Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/jit/emitxarch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,7 @@ bool emitter::IsDstSrcSrcAVXInstruction(instruction ins)
case INS_movhps:
case INS_movlpd:
case INS_movlps:
case INS_movsdsse2:
case INS_movss:
case INS_rcpss:
case INS_roundsd:
Expand Down Expand Up @@ -267,7 +268,7 @@ bool emitter::Is4ByteSSE4Instruction(instruction ins)
bool emitter::TakesVexPrefix(instruction ins)
{
// special case vzeroupper as it requires 2-byte VEX prefix
// special case (l|m|s)fence and the prefetch instructions as they never take a VEX prefix
// special case the fencing and the prefetch instructions as they never take a VEX prefix
switch (ins)
{
case INS_lfence:
Expand Down
160 changes: 153 additions & 7 deletions src/jit/hwintrinsiccodegenxarch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -744,7 +744,6 @@ void CodeGen::genSSE2Intrinsic(GenTreeHWIntrinsic* node)
regNumber targetReg = node->gtRegNum;
var_types targetType = node->TypeGet();
var_types baseType = node->gtSIMDBaseType;
instruction ins = INS_invalid;
regNumber op1Reg = REG_NA;
regNumber op2Reg = REG_NA;
emitter* emit = getEmitter();
Expand All @@ -764,15 +763,161 @@ void CodeGen::genSSE2Intrinsic(GenTreeHWIntrinsic* node)
assert(op1 != nullptr);
assert(op2 != nullptr);
assert(baseType == TYP_DOUBLE);

ins = Compiler::insOfHWIntrinsic(intrinsicID, baseType);
op2Reg = op2->gtRegNum;
ival = Compiler::ivalOfHWIntrinsic(intrinsicID);
instruction ins = Compiler::insOfHWIntrinsic(intrinsicID, baseType);
op2Reg = op2->gtRegNum;
ival = Compiler::ivalOfHWIntrinsic(intrinsicID);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should assert that ival != -1

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

assert(ival != -1);
emit->emitIns_SIMD_R_R_R_I(ins, emitTypeSize(TYP_SIMD16), targetReg, op1Reg, op2Reg, ival);

break;
}

case NI_SSE2_CompareEqualOrderedScalar:
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be good to have an explicit bug that tracks merging this with the SSE implementation.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The issue #16330 tracks this work item. Could you assign it to me within hardware intrinsics project?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

case NI_SSE2_CompareEqualUnorderedScalar:
{
assert(baseType == TYP_DOUBLE);
op2Reg = op2->gtRegNum;
regNumber tmpReg = node->GetSingleTempReg();
instruction ins = Compiler::insOfHWIntrinsic(intrinsicID, baseType);

emit->emitIns_R_R(ins, emitTypeSize(TYP_SIMD16), op1Reg, op2Reg);
emit->emitIns_R(INS_setpo, EA_1BYTE, targetReg);
emit->emitIns_R(INS_sete, EA_1BYTE, tmpReg);
emit->emitIns_R_R(INS_and, EA_1BYTE, tmpReg, targetReg);
emit->emitIns_R(INS_setne, EA_1BYTE, targetReg);
emit->emitIns_R_R(INS_movzx, EA_1BYTE, targetReg, targetReg);
break;
}

case NI_SSE2_CompareGreaterThanOrderedScalar:
case NI_SSE2_CompareGreaterThanUnorderedScalar:
{
assert(baseType == TYP_DOUBLE);
op2Reg = op2->gtRegNum;
instruction ins = Compiler::insOfHWIntrinsic(intrinsicID, baseType);

emit->emitIns_R_R(ins, emitTypeSize(TYP_SIMD16), op1Reg, op2Reg);
emit->emitIns_R(INS_seta, EA_1BYTE, targetReg);
emit->emitIns_R_R(INS_movzx, EA_1BYTE, targetReg, targetReg);
break;
}

case NI_SSE2_CompareGreaterThanOrEqualOrderedScalar:
case NI_SSE2_CompareGreaterThanOrEqualUnorderedScalar:
{
assert(baseType == TYP_DOUBLE);
op2Reg = op2->gtRegNum;
instruction ins = Compiler::insOfHWIntrinsic(intrinsicID, baseType);

emit->emitIns_R_R(ins, emitTypeSize(TYP_SIMD16), op1Reg, op2Reg);
emit->emitIns_R(INS_setae, EA_1BYTE, targetReg);
emit->emitIns_R_R(INS_movzx, EA_1BYTE, targetReg, targetReg);
break;
}

case NI_SSE2_CompareLessThanOrderedScalar:
case NI_SSE2_CompareLessThanUnorderedScalar:
{
assert(baseType == TYP_DOUBLE);
op2Reg = op2->gtRegNum;
instruction ins = Compiler::insOfHWIntrinsic(intrinsicID, baseType);

emit->emitIns_R_R(ins, emitTypeSize(TYP_SIMD16), op2Reg, op1Reg);
emit->emitIns_R(INS_seta, EA_1BYTE, targetReg);
emit->emitIns_R_R(INS_movzx, EA_1BYTE, targetReg, targetReg);
break;
}

case NI_SSE2_CompareLessThanOrEqualOrderedScalar:
case NI_SSE2_CompareLessThanOrEqualUnorderedScalar:
{
assert(baseType == TYP_DOUBLE);
op2Reg = op2->gtRegNum;
instruction ins = Compiler::insOfHWIntrinsic(intrinsicID, baseType);

emit->emitIns_R_R(ins, emitTypeSize(TYP_SIMD16), op2Reg, op1Reg);
emit->emitIns_R(INS_setae, EA_1BYTE, targetReg);
emit->emitIns_R_R(INS_movzx, EA_1BYTE, targetReg, targetReg);
break;
}

case NI_SSE2_CompareNotEqualOrderedScalar:
case NI_SSE2_CompareNotEqualUnorderedScalar:
{
assert(baseType == TYP_DOUBLE);
op2Reg = op2->gtRegNum;
instruction ins = Compiler::insOfHWIntrinsic(intrinsicID, baseType);
regNumber tmpReg = node->GetSingleTempReg();

emit->emitIns_R_R(ins, emitTypeSize(TYP_SIMD16), op1Reg, op2Reg);
emit->emitIns_R(INS_setpe, EA_1BYTE, targetReg);
emit->emitIns_R(INS_setne, EA_1BYTE, tmpReg);
emit->emitIns_R_R(INS_or, EA_1BYTE, tmpReg, targetReg);
emit->emitIns_R(INS_setne, EA_1BYTE, targetReg);
emit->emitIns_R_R(INS_movzx, EA_1BYTE, targetReg, targetReg);
break;
}

case NI_SSE2_ConvertScalarToVector128Double:
case NI_SSE2_ConvertScalarToVector128Single:
{
assert(baseType == TYP_INT || baseType == TYP_LONG || baseType == TYP_FLOAT || baseType == TYP_DOUBLE);
assert(op1 != nullptr);
assert(op2 != nullptr);
instruction ins = Compiler::insOfHWIntrinsic(intrinsicID, baseType);
genHWIntrinsic_R_R_RM(node, ins);
break;
}

case NI_SSE2_ConvertScalarToVector128Int64:
case NI_SSE2_ConvertScalarToVector128UInt64:
{
assert(baseType == TYP_LONG || baseType == TYP_ULONG);
assert(op1 != nullptr);
assert(op2 == nullptr);
instruction ins = Compiler::insOfHWIntrinsic(intrinsicID, baseType);
// TODO-XArch-CQ -> use of type size of TYP_SIMD16 leads to
// instruction register encoding errors for SSE legacy encoding
emit->emitIns_R_R(ins, emitTypeSize(baseType), targetReg, op1Reg);
break;
}

case NI_SSE2_ConvertToDouble:
{
assert(op2 == nullptr);
if (op1Reg != targetReg)
{
instruction ins = Compiler::insOfHWIntrinsic(intrinsicID, baseType);
emit->emitIns_R_R(ins, emitTypeSize(targetType), targetReg, op1Reg);
}
break;
}

case NI_SSE2_ConvertToInt32:
case NI_SSE2_ConvertToInt64:
case NI_SSE2_ConvertToUInt32:
case NI_SSE2_ConvertToUInt64:
{
assert(op2 == nullptr);
assert(baseType == TYP_DOUBLE || baseType == TYP_FLOAT || baseType == TYP_INT || baseType == TYP_UINT ||
baseType == TYP_LONG || baseType == TYP_ULONG);
if (op1Reg != targetReg)
{
instruction ins = Compiler::insOfHWIntrinsic(intrinsicID, baseType);
if (baseType == TYP_DOUBLE || baseType == TYP_FLOAT)
{
emit->emitIns_R_R(ins, emitTypeSize(targetType), targetReg, op1Reg);
}
else
{
// TODO-XArch-Bug https://github.com/dotnet/coreclr/issues/16329
// using hardcoded instruction as workaround for inexact type conversions
emit->emitIns_R_R(INS_mov_xmm2i, emitActualTypeSize(baseType), op1Reg, targetReg);
}
}
break;
}

case NI_SSE2_LoadFence:
{
assert(baseType == TYP_VOID);
Expand All @@ -781,6 +926,7 @@ void CodeGen::genSSE2Intrinsic(GenTreeHWIntrinsic* node)
emit->emitIns(INS_lfence);
break;
}

case NI_SSE2_MemoryFence:
{
assert(baseType == TYP_VOID);
Expand All @@ -795,7 +941,7 @@ void CodeGen::genSSE2Intrinsic(GenTreeHWIntrinsic* node)
assert(op2 == nullptr);
assert(baseType == TYP_BYTE || baseType == TYP_UBYTE || baseType == TYP_DOUBLE);

ins = Compiler::insOfHWIntrinsic(intrinsicID, baseType);
instruction ins = Compiler::insOfHWIntrinsic(intrinsicID, baseType);
emit->emitIns_R_R(ins, emitTypeSize(TYP_INT), targetReg, op1Reg);
break;
}
Expand All @@ -807,7 +953,7 @@ void CodeGen::genSSE2Intrinsic(GenTreeHWIntrinsic* node)
assert(op1 == nullptr);
assert(op2 == nullptr);

ins = Compiler::insOfHWIntrinsic(intrinsicID, baseType);
instruction ins = Compiler::insOfHWIntrinsic(intrinsicID, baseType);
emit->emitIns_SIMD_R_R_R(ins, emitTypeSize(TYP_SIMD16), targetReg, targetReg, targetReg);
break;
}
Expand Down
Loading