summaryrefslogtreecommitdiff
path: root/src/jit/hwintrinsiccodegenxarch.cpp
diff options
context:
space:
mode:
authorFei Peng <fei.peng@intel.com>2018-01-19 00:01:21 -0800
committerFei Peng <fei.peng@intel.com>2018-01-19 00:01:21 -0800
commit654a8d5ff0cf1a7e0968c68a4b84aecf03ed9c1c (patch)
tree2cebb82cd42b3cec6de0ca3e0d50b6954db6263b /src/jit/hwintrinsiccodegenxarch.cpp
parentfffd34540b50cee2ae5a3e1215e525f029eec124 (diff)
downloadcoreclr-654a8d5ff0cf1a7e0968c68a4b84aecf03ed9c1c.tar.gz
coreclr-654a8d5ff0cf1a7e0968c68a4b84aecf03ed9c1c.tar.bz2
coreclr-654a8d5ff0cf1a7e0968c68a4b84aecf03ed9c1c.zip
Merge SSE intrinsics into the table-driven framework
Diffstat (limited to 'src/jit/hwintrinsiccodegenxarch.cpp')
-rw-r--r--src/jit/hwintrinsiccodegenxarch.cpp216
1 files changed, 60 insertions, 156 deletions
diff --git a/src/jit/hwintrinsiccodegenxarch.cpp b/src/jit/hwintrinsiccodegenxarch.cpp
index 6ea0de7e23..69b3cf54ba 100644
--- a/src/jit/hwintrinsiccodegenxarch.cpp
+++ b/src/jit/hwintrinsiccodegenxarch.cpp
@@ -33,12 +33,14 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
// Return Value:
// returns true if this category can be table-driven in CodeGen
//
-static bool genIsTableDrivenHWIntrinsic(HWIntrinsicCategory category)
+static bool genIsTableDrivenHWIntrinsic(HWIntrinsicCategory category, HWIntrinsicFlag flags)
{
// TODO - make more categories to the table-driven framework
- const bool tableDrivenIntrinsic = category == HW_Category_SimpleSIMD;
- const bool nonTableDrivenIntrinsic = category == HW_Category_Special;
- return tableDrivenIntrinsic && !nonTableDrivenIntrinsic;
+ // HW_Category_Helper and HW_Flag_MultiIns usually need manual codegen
+ const bool tableDrivenCategory =
+ category == HW_Category_SimpleSIMD || category == HW_Category_MemoryLoad || category == HW_Category_SIMDScalar;
+ const bool tableDrivenFlag = (flags & HW_Flag_MultiIns) == 0;
+ return tableDrivenCategory && tableDrivenFlag;
}
void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node)
@@ -46,12 +48,13 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node)
NamedIntrinsic intrinsicID = node->gtHWIntrinsicId;
InstructionSet isa = Compiler::isaOfHWIntrinsic(intrinsicID);
HWIntrinsicCategory category = Compiler::categoryOfHWIntrinsic(intrinsicID);
- HWIntrinsicFlag flag = Compiler::flagOfHWIntrinsic(intrinsicID);
+ HWIntrinsicFlag flags = Compiler::flagsOfHWIntrinsic(intrinsicID);
+ int ival = Compiler::ivalOfHWIntrinsic(intrinsicID);
int numArgs = Compiler::numArgsOfHWIntrinsic(intrinsicID);
- assert((flag & HW_Flag_NoCodeGen) == 0);
+ assert((flags & HW_Flag_NoCodeGen) == 0);
- if (genIsTableDrivenHWIntrinsic(category))
+ if (genIsTableDrivenHWIntrinsic(category, flags))
{
GenTree* op1 = node->gtGetOp1();
GenTree* op2 = node->gtGetOp2();
@@ -74,10 +77,35 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node)
case 1:
genConsumeOperands(node);
op1Reg = op1->gtRegNum;
- emit->emitIns_R_R(ins, simdSize, targetReg, op1Reg);
+ if (category == HW_Category_MemoryLoad)
+ {
+ emit->emitIns_R_AR(ins, simdSize, targetReg, op1Reg, 0);
+ }
+ else if (category == HW_Category_SIMDScalar && (flags & HW_Flag_CopyUpperBits) != 0)
+ {
+ emit->emitIns_SIMD_R_R_R(ins, simdSize, targetReg, op1Reg, op1Reg);
+ }
+ else
+ {
+
+ emit->emitIns_R_R(ins, simdSize, targetReg, op1Reg);
+ }
break;
+
case 2:
- genHWIntrinsic_R_R_RM(node, ins);
+ genConsumeOperands(node);
+ if (ival != -1)
+ {
+ genHWIntrinsic_R_R_RM_I(node, ins);
+ }
+ else if (category == HW_Category_MemoryLoad)
+ {
+ emit->emitIns_SIMD_R_R_AR(ins, emitTypeSize(TYP_SIMD16), targetReg, op1->gtRegNum, op2->gtRegNum);
+ }
+ else
+ {
+ genHWIntrinsic_R_R_RM(node, ins);
+ }
break;
case 3:
{
@@ -329,14 +357,14 @@ void CodeGen::genHWIntrinsic_R_R_RM_I(GenTreeHWIntrinsic* node, instruction ins)
case GT_CLS_VAR_ADDR:
{
- emit->emitIns_SIMD_R_R_C_I(ins, targetReg, op1Reg, memBase->gtClsVar.gtClsVarHnd, 0, ival,
- targetType);
+ emit->emitIns_SIMD_R_R_C_I(ins, emitTypeSize(targetType), targetReg, op1Reg,
+ memBase->gtClsVar.gtClsVarHnd, 0, ival);
return;
}
default:
{
- emit->emitIns_SIMD_R_R_A_I(ins, targetReg, op1Reg, memIndir, ival, targetType);
+ emit->emitIns_SIMD_R_R_A_I(ins, emitTypeSize(targetType), targetReg, op1Reg, memIndir, ival);
return;
}
}
@@ -374,11 +402,11 @@ void CodeGen::genHWIntrinsic_R_R_RM_I(GenTreeHWIntrinsic* node, instruction ins)
assert((varNum != BAD_VAR_NUM) || (tmpDsc != nullptr));
assert(offset != (unsigned)-1);
- emit->emitIns_SIMD_R_R_S_I(ins, targetReg, op1Reg, varNum, offset, ival, targetType);
+ emit->emitIns_SIMD_R_R_S_I(ins, emitTypeSize(targetType), targetReg, op1Reg, varNum, offset, ival);
}
else
{
- emit->emitIns_SIMD_R_R_R_I(ins, targetReg, op1Reg, op2->gtRegNum, ival, targetType);
+ emit->emitIns_SIMD_R_R_R_I(ins, emitTypeSize(targetType), targetReg, op1Reg, op2->gtRegNum, ival);
}
}
@@ -392,7 +420,7 @@ void CodeGen::genSSEIntrinsic(GenTreeHWIntrinsic* node)
regNumber targetReg = node->gtRegNum;
var_types targetType = node->TypeGet();
var_types baseType = node->gtSIMDBaseType;
- instruction ins = INS_invalid;
+ instruction ins = Compiler::insOfHWIntrinsic(intrinsicID, node->gtSIMDBaseType);
regNumber op1Reg = REG_NA;
regNumber op2Reg = REG_NA;
@@ -408,28 +436,7 @@ void CodeGen::genSSEIntrinsic(GenTreeHWIntrinsic* node)
switch (intrinsicID)
{
- case NI_SSE_Add:
- case NI_SSE_AddScalar:
- case NI_SSE_And:
- case NI_SSE_AndNot:
case NI_SSE_ConvertToVector128SingleScalar:
- case NI_SSE_Divide:
- case NI_SSE_DivideScalar:
- case NI_SSE_Max:
- case NI_SSE_MaxScalar:
- case NI_SSE_Min:
- case NI_SSE_MinScalar:
- case NI_SSE_MoveHighToLow:
- case NI_SSE_MoveLowToHigh:
- case NI_SSE_MoveScalar:
- case NI_SSE_Multiply:
- case NI_SSE_MultiplyScalar:
- case NI_SSE_Or:
- case NI_SSE_Subtract:
- case NI_SSE_SubtractScalar:
- case NI_SSE_UnpackHigh:
- case NI_SSE_UnpackLow:
- case NI_SSE_Xor:
{
assert(node->TypeGet() == TYP_SIMD16);
assert(node->gtSIMDBaseType == TYP_FLOAT);
@@ -439,51 +446,14 @@ void CodeGen::genSSEIntrinsic(GenTreeHWIntrinsic* node)
genHWIntrinsic_R_R_RM(node, ins);
break;
}
-
- case NI_SSE_CompareEqual:
- case NI_SSE_CompareEqualScalar:
- case NI_SSE_CompareGreaterThan:
- case NI_SSE_CompareGreaterThanScalar:
- case NI_SSE_CompareGreaterThanOrEqual:
- case NI_SSE_CompareGreaterThanOrEqualScalar:
- case NI_SSE_CompareLessThan:
- case NI_SSE_CompareLessThanScalar:
- case NI_SSE_CompareLessThanOrEqual:
- case NI_SSE_CompareLessThanOrEqualScalar:
- case NI_SSE_CompareNotEqual:
- case NI_SSE_CompareNotEqualScalar:
- case NI_SSE_CompareNotGreaterThan:
- case NI_SSE_CompareNotGreaterThanScalar:
- case NI_SSE_CompareNotGreaterThanOrEqual:
- case NI_SSE_CompareNotGreaterThanOrEqualScalar:
- case NI_SSE_CompareNotLessThan:
- case NI_SSE_CompareNotLessThanScalar:
- case NI_SSE_CompareNotLessThanOrEqual:
- case NI_SSE_CompareNotLessThanOrEqualScalar:
- case NI_SSE_CompareOrdered:
- case NI_SSE_CompareOrderedScalar:
- case NI_SSE_CompareUnordered:
- case NI_SSE_CompareUnorderedScalar:
- {
- assert(node->TypeGet() == TYP_SIMD16);
- assert(node->gtSIMDBaseType == TYP_FLOAT);
- assert(Compiler::ivalOfHWIntrinsic(intrinsicID) != -1);
-
- instruction ins = Compiler::insOfHWIntrinsic(intrinsicID, node->gtSIMDBaseType);
- genHWIntrinsic_R_R_RM_I(node, ins);
- break;
- }
-
case NI_SSE_CompareEqualOrderedScalar:
case NI_SSE_CompareEqualUnorderedScalar:
{
assert(baseType == TYP_FLOAT);
- op2Reg = op2->gtRegNum;
-
- regNumber tmpReg = node->GetSingleTempReg();
- instruction ins = Compiler::insOfHWIntrinsic(intrinsicID, node->gtSIMDBaseType);
+ op2Reg = op2->gtRegNum;
+ regNumber tmpReg = node->GetSingleTempReg();
- emit->emitIns_SIMD_R_R(ins, op1Reg, op2Reg, TYP_SIMD16);
+ 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);
@@ -498,8 +468,7 @@ void CodeGen::genSSEIntrinsic(GenTreeHWIntrinsic* node)
assert(baseType == TYP_FLOAT);
op2Reg = op2->gtRegNum;
- instruction ins = Compiler::insOfHWIntrinsic(intrinsicID, node->gtSIMDBaseType);
- emit->emitIns_SIMD_R_R(ins, op1Reg, op2Reg, TYP_SIMD16);
+ 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;
@@ -511,8 +480,7 @@ void CodeGen::genSSEIntrinsic(GenTreeHWIntrinsic* node)
assert(baseType == TYP_FLOAT);
op2Reg = op2->gtRegNum;
- instruction ins = Compiler::insOfHWIntrinsic(intrinsicID, node->gtSIMDBaseType);
- emit->emitIns_SIMD_R_R(ins, op1Reg, op2Reg, TYP_SIMD16);
+ 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;
@@ -524,8 +492,7 @@ void CodeGen::genSSEIntrinsic(GenTreeHWIntrinsic* node)
assert(baseType == TYP_FLOAT);
op2Reg = op2->gtRegNum;
- instruction ins = Compiler::insOfHWIntrinsic(intrinsicID, node->gtSIMDBaseType);
- emit->emitIns_SIMD_R_R(ins, op2Reg, op1Reg, TYP_SIMD16);
+ 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;
@@ -537,8 +504,7 @@ void CodeGen::genSSEIntrinsic(GenTreeHWIntrinsic* node)
assert(baseType == TYP_FLOAT);
op2Reg = op2->gtRegNum;
- instruction ins = Compiler::insOfHWIntrinsic(intrinsicID, node->gtSIMDBaseType);
- emit->emitIns_SIMD_R_R(ins, op2Reg, op1Reg, TYP_SIMD16);
+ 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;
@@ -550,10 +516,9 @@ void CodeGen::genSSEIntrinsic(GenTreeHWIntrinsic* node)
assert(baseType == TYP_FLOAT);
op2Reg = op2->gtRegNum;
- regNumber tmpReg = node->GetSingleTempReg();
- instruction ins = Compiler::insOfHWIntrinsic(intrinsicID, node->gtSIMDBaseType);
+ regNumber tmpReg = node->GetSingleTempReg();
- emit->emitIns_SIMD_R_R(ins, op1Reg, op2Reg, TYP_SIMD16);
+ 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);
@@ -562,84 +527,23 @@ void CodeGen::genSSEIntrinsic(GenTreeHWIntrinsic* node)
break;
}
- case NI_SSE_ConvertToInt32:
- case NI_SSE_ConvertToInt32WithTruncation:
- case NI_SSE_ConvertToInt64:
- case NI_SSE_ConvertToInt64WithTruncation:
- case NI_SSE_Reciprocal:
- case NI_SSE_ReciprocalSqrt:
- case NI_SSE_Sqrt:
- {
- assert(baseType == TYP_FLOAT);
- assert(op2 == nullptr);
-
- instruction ins = Compiler::insOfHWIntrinsic(intrinsicID, node->gtSIMDBaseType);
- emit->emitIns_SIMD_R_R(ins, targetReg, op1Reg, TYP_SIMD16);
- break;
- }
-
case NI_SSE_ConvertToSingle:
case NI_SSE_StaticCast:
{
assert(op2 == nullptr);
if (op1Reg != targetReg)
{
- instruction ins = Compiler::insOfHWIntrinsic(intrinsicID, node->gtSIMDBaseType);
- emit->emitIns_SIMD_R_R(ins, targetReg, op1Reg, TYP_SIMD16);
+ emit->emitIns_R_R(ins, emitTypeSize(TYP_SIMD16), targetReg, op1Reg);
}
break;
}
- case NI_SSE_LoadAlignedVector128:
- case NI_SSE_LoadScalar:
- case NI_SSE_LoadVector128:
- {
- assert(baseType == TYP_FLOAT);
- assert(op2 == nullptr);
-
- instruction ins = Compiler::insOfHWIntrinsic(intrinsicID, node->gtSIMDBaseType);
- emit->emitIns_R_AR(ins, emitTypeSize(TYP_SIMD16), targetReg, op1Reg, 0);
- break;
- }
-
- case NI_SSE_LoadHigh:
- case NI_SSE_LoadLow:
- {
- assert(baseType == TYP_FLOAT);
- op2Reg = op2->gtRegNum;
-
- instruction ins = Compiler::insOfHWIntrinsic(intrinsicID, node->gtSIMDBaseType);
- emit->emitIns_SIMD_R_R_AR(ins, targetReg, op1Reg, op2Reg, TYP_SIMD16);
- break;
- }
-
case NI_SSE_MoveMask:
{
assert(baseType == TYP_FLOAT);
assert(op2 == nullptr);
- instruction ins = Compiler::insOfHWIntrinsic(intrinsicID, node->gtSIMDBaseType);
- emit->emitIns_SIMD_R_R(ins, targetReg, op1Reg, TYP_INT);
- break;
- }
-
- case NI_SSE_ReciprocalScalar:
- case NI_SSE_ReciprocalSqrtScalar:
- case NI_SSE_SqrtScalar:
- {
- assert(baseType == TYP_FLOAT);
- assert(op2 == nullptr);
-
- instruction ins = Compiler::insOfHWIntrinsic(intrinsicID, node->gtSIMDBaseType);
- emit->emitIns_SIMD_R_R_R(ins, targetReg, op1Reg, op1Reg, TYP_SIMD16);
- break;
- }
-
- case NI_SSE_SetAllVector128:
- {
- assert(baseType == TYP_FLOAT);
- assert(op2 == nullptr);
- emit->emitIns_SIMD_R_R_R_I(INS_shufps, targetReg, op1Reg, op1Reg, 0, TYP_SIMD16);
+ emit->emitIns_R_R(ins, emitTypeSize(TYP_INT), targetReg, op1Reg);
break;
}
@@ -651,12 +555,12 @@ void CodeGen::genSSEIntrinsic(GenTreeHWIntrinsic* node)
if (op1Reg == targetReg)
{
regNumber tmpReg = node->GetSingleTempReg();
- emit->emitIns_SIMD_R_R(INS_movaps, tmpReg, op1Reg, TYP_SIMD16);
+ emit->emitIns_R_R(INS_movaps, emitTypeSize(TYP_SIMD16), tmpReg, op1Reg);
op1Reg = tmpReg;
}
- emit->emitIns_SIMD_R_R_R(INS_xorps, targetReg, targetReg, targetReg, TYP_SIMD16);
- emit->emitIns_SIMD_R_R_R(INS_movss, targetReg, targetReg, op1Reg, TYP_SIMD16);
+ emit->emitIns_SIMD_R_R_R(INS_xorps, emitTypeSize(TYP_SIMD16), targetReg, targetReg, targetReg);
+ emit->emitIns_SIMD_R_R_R(INS_movss, emitTypeSize(TYP_SIMD16), targetReg, targetReg, op1Reg);
break;
}
@@ -665,7 +569,7 @@ void CodeGen::genSSEIntrinsic(GenTreeHWIntrinsic* node)
assert(baseType == TYP_FLOAT);
assert(op1 == nullptr);
assert(op2 == nullptr);
- emit->emitIns_SIMD_R_R_R(INS_xorps, targetReg, targetReg, targetReg, TYP_SIMD16);
+ emit->emitIns_SIMD_R_R_R(INS_xorps, emitTypeSize(TYP_SIMD16), targetReg, targetReg, targetReg);
break;
}
@@ -699,7 +603,7 @@ void CodeGen::genSSEIntrinsic(GenTreeHWIntrinsic* node)
if (op3->IsCnsIntOrI())
{
ssize_t ival = op3->AsIntConCommon()->IconValue();
- emit->emitIns_SIMD_R_R_R_I(INS_shufps, targetReg, op1Reg, op2Reg, (int)ival, TYP_SIMD16);
+ emit->emitIns_SIMD_R_R_R_I(INS_shufps, emitTypeSize(TYP_SIMD16), targetReg, op1Reg, op2Reg, (int)ival);
}
else
{
@@ -749,7 +653,7 @@ void CodeGen::genSSEIntrinsic(GenTreeHWIntrinsic* node)
for (unsigned i = 0; i < jmpCount; i++)
{
genDefineTempLabel(jmpTable[i]);
- emit->emitIns_SIMD_R_R_R_I(INS_shufps, targetReg, op1Reg, op2Reg, i, TYP_SIMD16);
+ emit->emitIns_SIMD_R_R_R_I(INS_shufps, emitTypeSize(TYP_SIMD16), targetReg, op1Reg, op2Reg, i);
emit->emitIns_J(INS_jmp, switchTableEnd);
}