diff --git a/docs/design/coreclr/jit/first-class-structs.md b/docs/design/coreclr/jit/first-class-structs.md index d72af35753dae..dc017aee75f2e 100644 --- a/docs/design/coreclr/jit/first-class-structs.md +++ b/docs/design/coreclr/jit/first-class-structs.md @@ -113,9 +113,9 @@ Structs only appear as rvalues in the following contexts: * As a call argument * In this context, it must be one of: `GT_OBJ`, `GT_LCL_VAR`, `GT_LCL_FLD` or `GT_FIELD_LIST`. -* As an operand to a hardware or SIMD intrinsic (for `TYP_SIMD*` only) +* As an operand to a hardware intrinsic (for `TYP_SIMD*` only) * In this case the struct handle is generally assumed to be unneeded, as it is captured (directly or - indirectly) in the `GT_SIMD` or `GT_HWINTRINSIC` node. + indirectly) in the `GT_HWINTRINSIC` node. * It would simplify both the recognition and optimization of these nodes if they carried a `ClassLayout`. After morph, a struct-typed value on the RHS of assignment is one of: @@ -124,7 +124,6 @@ After morph, a struct-typed value on the RHS of assignment is one of: * `GT_CALL` * `GT_LCL_VAR` * `GT_LCL_FLD` -* `GT_SIMD` * `GT_OBJ` nodes can also be used as rvalues when they are call arguments * Proposed: `GT_OBJ` nodes can be used in any context where a struct rvalue or lvalue might occur, except after morph when the struct is independently promoted. diff --git a/src/coreclr/jit/CMakeLists.txt b/src/coreclr/jit/CMakeLists.txt index 4e3640cdccfbd..b39a7316530d5 100644 --- a/src/coreclr/jit/CMakeLists.txt +++ b/src/coreclr/jit/CMakeLists.txt @@ -340,7 +340,6 @@ set( JIT_HEADERS sideeffects.h simd.h simdashwintrinsic.h - simdintrinsiclist.h sm.h smallhash.h smcommon.h diff --git a/src/coreclr/jit/clrjit.natvis b/src/coreclr/jit/clrjit.natvis index 5873fca508786..b44fd31bc85ac 100644 --- a/src/coreclr/jit/clrjit.natvis +++ b/src/coreclr/jit/clrjit.natvis @@ -59,7 +59,6 @@ Documentation for VS debugger format specifiers: https://docs.microsoft.com/en-u {gtTreeID, d}: [[{this->gtOp1,na}={this->gtOp2,na}] {gtTreeID, d}: [[{((GenTreeCast*)this)->gtCastType,en} <- {((GenTreeUnOp*)this)->gtOp1->gtType,en}] - {gtTreeID, d}: [[{((GenTreeSIMD*)this)->gtSIMDIntrinsicID,en}, {gtType,en}] {gtTreeID, d}: [[{((GenTreeHWIntrinsic*)this)->gtHWIntrinsicId,en}, {gtType,en}] {gtTreeID, d}: [[{gtOper,en}, {gtType,en}] diff --git a/src/coreclr/jit/codegen.h b/src/coreclr/jit/codegen.h index ef14cf55bbd4c..2cf76a5cbf6a4 100644 --- a/src/coreclr/jit/codegen.h +++ b/src/coreclr/jit/codegen.h @@ -1058,7 +1058,7 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX void genCodeForContainedCompareChain(GenTree* tree, bool* inchain, GenCondition* prevCond); #endif void genCodeForSelect(GenTreeOp* select); - void genIntrinsic(GenTree* treeNode); + void genIntrinsic(GenTreeIntrinsic* treeNode); void genPutArgStk(GenTreePutArgStk* treeNode); void genPutArgReg(GenTreeOp* tree); #if FEATURE_ARG_SPLIT @@ -1078,9 +1078,8 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX #ifdef TARGET_ARM64 insOpts genGetSimdInsOpt(emitAttr size, var_types elementType); #endif - void genSIMDIntrinsicUpperSave(GenTreeSIMD* simdNode); - void genSIMDIntrinsicUpperRestore(GenTreeSIMD* simdNode); - void genSIMDIntrinsic(GenTreeSIMD* simdNode); + void genSimdUpperSave(GenTreeIntrinsic* node); + void genSimdUpperRestore(GenTreeIntrinsic* node); // TYP_SIMD12 (i.e Vector3 of size 12 bytes) is not a hardware supported size and requires // two reads/writes on 64-bit targets. These routines abstract reading/writing of Vector3 diff --git a/src/coreclr/jit/codegenarm64.cpp b/src/coreclr/jit/codegenarm64.cpp index 0adfcc5484641..6a969c7e7cb4a 100644 --- a/src/coreclr/jit/codegenarm64.cpp +++ b/src/coreclr/jit/codegenarm64.cpp @@ -5018,46 +5018,6 @@ void CodeGen::genEmitHelperCall(unsigned helper, int argSize, emitAttr retSize, } #ifdef FEATURE_SIMD - -//------------------------------------------------------------------------ -// genSIMDIntrinsic: Generate code for a SIMD Intrinsic. This is the main -// routine which in turn calls appropriate genSIMDIntrinsicXXX() routine. -// -// Arguments: -// simdNode - The GT_SIMD node -// -// Return Value: -// None. -// -// Notes: -// Currently, we only recognize SIMDVector and SIMDVector, and -// a limited set of methods. -// -// TODO-CLEANUP Merge all versions of this function and move to new file simdcodegencommon.cpp. -void CodeGen::genSIMDIntrinsic(GenTreeSIMD* simdNode) -{ - // NYI for unsupported base types - if (!varTypeIsArithmetic(simdNode->GetSimdBaseType())) - { - noway_assert(!"SIMD intrinsic with unsupported base type."); - } - - switch (simdNode->GetSIMDIntrinsicId()) - { - case SIMDIntrinsicUpperSave: - genSIMDIntrinsicUpperSave(simdNode); - break; - - case SIMDIntrinsicUpperRestore: - genSIMDIntrinsicUpperRestore(simdNode); - break; - - default: - noway_assert(!"Unimplemented SIMD intrinsic."); - unreached(); - } -} - insOpts CodeGen::genGetSimdInsOpt(emitAttr size, var_types elementType) { assert((size == EA_16BYTE) || (size == EA_8BYTE)); @@ -5092,11 +5052,11 @@ insOpts CodeGen::genGetSimdInsOpt(emitAttr size, var_types elementType) } //----------------------------------------------------------------------------- -// genSIMDIntrinsicUpperSave: save the upper half of a TYP_SIMD16 vector to -// the given register, if any, or to memory. +// genSimdUpperSave: save the upper half of a TYP_SIMD16 vector to +// the given register, if any, or to memory. // // Arguments: -// simdNode - The GT_SIMD node +// node - The GT_INTRINSIC node // // Return Value: // None. @@ -5109,81 +5069,93 @@ insOpts CodeGen::genGetSimdInsOpt(emitAttr size, var_types elementType) // In that case, this node will be marked GTF_SPILL, which will cause this method to save // the upper half to the lclVar's home location. // -void CodeGen::genSIMDIntrinsicUpperSave(GenTreeSIMD* simdNode) +void CodeGen::genSimdUpperSave(GenTreeIntrinsic* node) { - assert(simdNode->GetSIMDIntrinsicId() == SIMDIntrinsicUpperSave); + assert(node->gtIntrinsicName == NI_SIMD_UpperSave); + + GenTree* op1 = node->gtGetOp1(); + assert(op1->IsLocal()); - GenTree* op1 = simdNode->Op(1); GenTreeLclVar* lclNode = op1->AsLclVar(); LclVarDsc* varDsc = compiler->lvaGetDesc(lclNode); assert(emitTypeSize(varDsc->GetRegisterType(lclNode)) == 16); - regNumber targetReg = simdNode->GetRegNum(); - regNumber op1Reg = genConsumeReg(op1); + regNumber tgtReg = node->GetRegNum(); + assert(tgtReg != REG_NA); + + regNumber op1Reg = genConsumeReg(op1); assert(op1Reg != REG_NA); - assert(targetReg != REG_NA); - GetEmitter()->emitIns_R_R_I_I(INS_mov, EA_8BYTE, targetReg, op1Reg, 0, 1); - if ((simdNode->gtFlags & GTF_SPILL) != 0) + GetEmitter()->emitIns_R_R_I_I(INS_mov, EA_8BYTE, tgtReg, op1Reg, 0, 1); + + if ((node->gtFlags & GTF_SPILL) != 0) { // This is not a normal spill; we'll spill it to the lclVar location. // The localVar must have a stack home. + unsigned varNum = lclNode->GetLclNum(); assert(varDsc->lvOnFrame); + // We want to store this to the upper 8 bytes of this localVar's home. int offset = 8; emitAttr attr = emitTypeSize(TYP_SIMD8); - GetEmitter()->emitIns_S_R(INS_str, attr, targetReg, varNum, offset); + GetEmitter()->emitIns_S_R(INS_str, attr, tgtReg, varNum, offset); } else { - genProduceReg(simdNode); + genProduceReg(node); } } //----------------------------------------------------------------------------- -// genSIMDIntrinsicUpperRestore: Restore the upper half of a TYP_SIMD16 vector to -// the given register, if any, or to memory. +// genSimdUpperRestore: Restore the upper half of a TYP_SIMD16 vector to +// the given register, if any, or to memory. // // Arguments: -// simdNode - The GT_SIMD node +// node - The GT_INTRINSIC node // // Return Value: // None. // // Notes: -// For consistency with genSIMDIntrinsicUpperSave, and to ensure that lclVar nodes always -// have their home register, this node has its targetReg on the lclVar child, and its source -// on the simdNode. -// Regarding spill, please see the note above on genSIMDIntrinsicUpperSave. If we have spilled +// For consistency with genSimdUpperSave, and to ensure that lclVar nodes always +// have their home register, this node has its tgtReg on the lclVar child, and its source +// on the node. +// Regarding spill, please see the note above on genSimdUpperSave. If we have spilled // an upper-half to the lclVar's home location, this node will be marked GTF_SPILLED. // -void CodeGen::genSIMDIntrinsicUpperRestore(GenTreeSIMD* simdNode) +void CodeGen::genSimdUpperRestore(GenTreeIntrinsic* node) { - assert(simdNode->GetSIMDIntrinsicId() == SIMDIntrinsicUpperRestore); + assert(node->gtIntrinsicName == NI_SIMD_UpperRestore); - GenTree* op1 = simdNode->Op(1); + GenTree* op1 = node->gtGetOp1(); assert(op1->IsLocal()); + GenTreeLclVar* lclNode = op1->AsLclVar(); LclVarDsc* varDsc = compiler->lvaGetDesc(lclNode); assert(emitTypeSize(varDsc->GetRegisterType(lclNode)) == 16); - regNumber srcReg = simdNode->GetRegNum(); + regNumber srcReg = node->GetRegNum(); + assert(srcReg != REG_NA); + regNumber lclVarReg = genConsumeReg(lclNode); - unsigned varNum = lclNode->GetLclNum(); assert(lclVarReg != REG_NA); - assert(srcReg != REG_NA); - if (simdNode->gtFlags & GTF_SPILLED) + + unsigned varNum = lclNode->GetLclNum(); + + if (node->gtFlags & GTF_SPILLED) { // The localVar must have a stack home. assert(varDsc->lvOnFrame); + // We will load this from the upper 8 bytes of this localVar's home. int offset = 8; emitAttr attr = emitTypeSize(TYP_SIMD8); GetEmitter()->emitIns_R_S(INS_ldr, attr, srcReg, varNum, offset); } + GetEmitter()->emitIns_R_R_I_I(INS_mov, EA_8BYTE, lclVarReg, srcReg, 1, 0); } diff --git a/src/coreclr/jit/codegenarmarch.cpp b/src/coreclr/jit/codegenarmarch.cpp index 9fa3560730719..3bf17cee35156 100644 --- a/src/coreclr/jit/codegenarmarch.cpp +++ b/src/coreclr/jit/codegenarmarch.cpp @@ -334,15 +334,9 @@ void CodeGen::genCodeForTreeNode(GenTree* treeNode) break; case GT_INTRINSIC: - genIntrinsic(treeNode); + genIntrinsic(treeNode->AsIntrinsic()); break; -#ifdef FEATURE_SIMD - case GT_SIMD: - genSIMDIntrinsic(treeNode->AsSIMD()); - break; -#endif // FEATURE_SIMD - #ifdef FEATURE_HW_INTRINSICS case GT_HWINTRINSIC: genHWIntrinsic(treeNode->AsHWIntrinsic()); @@ -662,18 +656,21 @@ void CodeGen::genEmitGSCookieCheck(bool pushReg) // Return value: // None // -void CodeGen::genIntrinsic(GenTree* treeNode) +void CodeGen::genIntrinsic(GenTreeIntrinsic* treeNode) { - assert(treeNode->OperIs(GT_INTRINSIC)); - // Both operand and its result must be of the same floating point type. - GenTree* srcNode = treeNode->AsOp()->gtOp1; - assert(varTypeIsFloating(srcNode)); - assert(srcNode->TypeGet() == treeNode->TypeGet()); + GenTree* srcNode = treeNode->gtGetOp1(); - // Only a subset of functions are treated as math intrinsics. - // - switch (treeNode->AsIntrinsic()->gtIntrinsicName) +#ifdef DEBUG + if ((treeNode->gtIntrinsicName > NI_SYSTEM_MATH_START) && (treeNode->gtIntrinsicName < NI_SYSTEM_MATH_END)) + { + assert(varTypeIsFloating(srcNode)); + assert(srcNode->TypeGet() == treeNode->TypeGet()); + } +#endif // DEBUG + + // Handle intrinsics that can be implemented by target-specific instructions + switch (treeNode->gtIntrinsicName) { case NI_System_Math_Abs: genConsumeOperands(treeNode->AsOp()); @@ -704,13 +701,13 @@ void CodeGen::genIntrinsic(GenTree* treeNode) case NI_System_Math_Max: genConsumeOperands(treeNode->AsOp()); GetEmitter()->emitIns_R_R_R(INS_fmax, emitActualTypeSize(treeNode), treeNode->GetRegNum(), - treeNode->gtGetOp1()->GetRegNum(), treeNode->gtGetOp2()->GetRegNum()); + srcNode->GetRegNum(), treeNode->gtGetOp2()->GetRegNum()); break; case NI_System_Math_Min: genConsumeOperands(treeNode->AsOp()); GetEmitter()->emitIns_R_R_R(INS_fmin, emitActualTypeSize(treeNode), treeNode->GetRegNum(), - treeNode->gtGetOp1()->GetRegNum(), treeNode->gtGetOp2()->GetRegNum()); + srcNode->GetRegNum(), treeNode->gtGetOp2()->GetRegNum()); break; #endif // TARGET_ARM64 @@ -719,6 +716,23 @@ void CodeGen::genIntrinsic(GenTree* treeNode) GetEmitter()->emitInsBinary(INS_SQRT, emitActualTypeSize(treeNode), treeNode, srcNode); break; +#if defined(FEATURE_SIMD) + // The handling is a bit more complex so genSimdUpperSave/Restore + // handles genConsumeOperands and genProduceReg + + case NI_SIMD_UpperRestore: + { + genSimdUpperRestore(treeNode); + return; + } + + case NI_SIMD_UpperSave: + { + genSimdUpperSave(treeNode); + return; + } +#endif // FEATURE_SIMD + default: assert(!"genIntrinsic: Unsupported intrinsic"); unreached(); diff --git a/src/coreclr/jit/codegenlinear.cpp b/src/coreclr/jit/codegenlinear.cpp index d7f3c66dbe6b2..dc5e7dffbe44a 100644 --- a/src/coreclr/jit/codegenlinear.cpp +++ b/src/coreclr/jit/codegenlinear.cpp @@ -1717,7 +1717,7 @@ void CodeGen::genConsumeOperands(GenTreeOp* tree) #if defined(FEATURE_SIMD) || defined(FEATURE_HW_INTRINSICS) //------------------------------------------------------------------------ // genConsumeOperands: Do liveness update for the operands of a multi-operand node, -// currently GT_SIMD or GT_HWINTRINSIC +// currently GT_HWINTRINSIC // // Arguments: // tree - the GenTreeMultiOp whose operands will have their liveness updated. diff --git a/src/coreclr/jit/codegenloongarch64.cpp b/src/coreclr/jit/codegenloongarch64.cpp index 298d17e9e4cbf..e17dd3d743377 100644 --- a/src/coreclr/jit/codegenloongarch64.cpp +++ b/src/coreclr/jit/codegenloongarch64.cpp @@ -4855,27 +4855,6 @@ void CodeGen::genEmitHelperCall(unsigned helper, int argSize, emitAttr retSize, } #ifdef FEATURE_SIMD - -//------------------------------------------------------------------------ -// genSIMDIntrinsic: Generate code for a SIMD Intrinsic. This is the main -// routine which in turn calls appropriate genSIMDIntrinsicXXX() routine. -// -// Arguments: -// simdNode - The GT_SIMD node -// -// Return Value: -// None. -// -// Notes: -// Currently, we only recognize SIMDVector and SIMDVector, and -// a limited set of methods. -// -// TODO-CLEANUP Merge all versions of this function and move to new file simdcodegencommon.cpp. -void CodeGen::genSIMDIntrinsic(GenTreeSIMD* simdNode) -{ - NYI("unimplemented on LOONGARCH64 yet"); -} - insOpts CodeGen::genGetSimdInsOpt(emitAttr size, var_types elementType) { NYI("unimplemented on LOONGARCH64 yet"); @@ -4883,11 +4862,11 @@ insOpts CodeGen::genGetSimdInsOpt(emitAttr size, var_types elementType) } //----------------------------------------------------------------------------- -// genSIMDIntrinsicUpperSave: save the upper half of a TYP_SIMD16 vector to -// the given register, if any, or to memory. +// genSimdUpperSave: save the upper half of a TYP_SIMD16 vector to +// the given register, if any, or to memory. // // Arguments: -// simdNode - The GT_SIMD node +// node - The GT_INTRINSIC node // // Return Value: // None. @@ -4900,29 +4879,29 @@ insOpts CodeGen::genGetSimdInsOpt(emitAttr size, var_types elementType) // In that case, this node will be marked GTF_SPILL, which will cause this method to save // the upper half to the lclVar's home location. // -void CodeGen::genSIMDIntrinsicUpperSave(GenTreeSIMD* simdNode) +void CodeGen::genSimdUpperSave(GenTreeIntrinsic* node) { NYI("unimplemented on LOONGARCH64 yet"); } //----------------------------------------------------------------------------- -// genSIMDIntrinsicUpperRestore: Restore the upper half of a TYP_SIMD16 vector to -// the given register, if any, or to memory. +// genSimdUpperRestore: Restore the upper half of a TYP_SIMD16 vector to +// the given register, if any, or to memory. // // Arguments: -// simdNode - The GT_SIMD node +// node - The GT_INTRINSIC node // // Return Value: // None. // // Notes: -// For consistency with genSIMDIntrinsicUpperSave, and to ensure that lclVar nodes always -// have their home register, this node has its targetReg on the lclVar child, and its source -// on the simdNode. -// Regarding spill, please see the note above on genSIMDIntrinsicUpperSave. If we have spilled +// For consistency with genSimdUpperSave, and to ensure that lclVar nodes always +// have their home register, this node has its tgtReg on the lclVar child, and its source +// on the node. +// Regarding spill, please see the note above on genSimdUpperSave. If we have spilled // an upper-half to the lclVar's home location, this node will be marked GTF_SPILLED. // -void CodeGen::genSIMDIntrinsicUpperRestore(GenTreeSIMD* simdNode) +void CodeGen::genSimdUpperRestore(GenTreeIntrinsic* node) { NYI("unimplemented on LOONGARCH64 yet"); } @@ -5299,12 +5278,6 @@ void CodeGen::genCodeForTreeNode(GenTree* treeNode) genIntrinsic(treeNode); break; -#ifdef FEATURE_SIMD - case GT_SIMD: - genSIMDIntrinsic(treeNode->AsSIMD()); - break; -#endif // FEATURE_SIMD - #ifdef FEATURE_HW_INTRINSICS case GT_HWINTRINSIC: genHWIntrinsic(treeNode->AsHWIntrinsic()); diff --git a/src/coreclr/jit/codegenxarch.cpp b/src/coreclr/jit/codegenxarch.cpp index b838a387440cc..6780ab666212a 100644 --- a/src/coreclr/jit/codegenxarch.cpp +++ b/src/coreclr/jit/codegenxarch.cpp @@ -1743,15 +1743,9 @@ void CodeGen::genCodeForTreeNode(GenTree* treeNode) break; case GT_INTRINSIC: - genIntrinsic(treeNode); + genIntrinsic(treeNode->AsIntrinsic()); break; -#ifdef FEATURE_SIMD - case GT_SIMD: - genSIMDIntrinsic(treeNode->AsSIMD()); - break; -#endif // FEATURE_SIMD - #ifdef FEATURE_HW_INTRINSICS case GT_HWINTRINSIC: genHWIntrinsic(treeNode->AsHWIntrinsic()); @@ -7657,10 +7651,10 @@ void CodeGen::genSSE41RoundOp(GenTreeOp* treeNode) // Return value: // None // -void CodeGen::genIntrinsic(GenTree* treeNode) +void CodeGen::genIntrinsic(GenTreeIntrinsic* treeNode) { // Handle intrinsics that can be implemented by target-specific instructions - switch (treeNode->AsIntrinsic()->gtIntrinsicName) + switch (treeNode->gtIntrinsicName) { case NI_System_Math_Abs: genSSE2BitwiseOp(treeNode); @@ -7676,7 +7670,7 @@ void CodeGen::genIntrinsic(GenTree* treeNode) case NI_System_Math_Sqrt: { // Both operand and its result must be of the same floating point type. - GenTree* srcNode = treeNode->AsOp()->gtOp1; + GenTree* srcNode = treeNode->gtGetOp1(); assert(varTypeIsFloating(srcNode)); assert(srcNode->TypeGet() == treeNode->TypeGet()); @@ -7687,6 +7681,23 @@ void CodeGen::genIntrinsic(GenTree* treeNode) break; } +#if defined(FEATURE_SIMD) + // The handling is a bit more complex so genSimdUpperSave/Restore + // handles genConsumeOperands and genProduceReg + + case NI_SIMD_UpperRestore: + { + genSimdUpperRestore(treeNode); + return; + } + + case NI_SIMD_UpperSave: + { + genSimdUpperSave(treeNode); + return; + } +#endif // FEATURE_SIMD + default: assert(!"genIntrinsic: Unsupported intrinsic"); unreached(); diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index b771b4ceba10c..69d29c74d1894 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -2390,14 +2390,6 @@ class Compiler genTreeOps oper, GenTree* cond, GenTree* op1, GenTree* op2, var_types type); #ifdef FEATURE_SIMD - GenTreeSIMD* gtNewSIMDNode( - var_types type, GenTree* op1, SIMDIntrinsicID simdIntrinsicID, CorInfoType simdBaseJitType, unsigned simdSize); - GenTreeSIMD* gtNewSIMDNode(var_types type, - GenTree* op1, - GenTree* op2, - SIMDIntrinsicID simdIntrinsicID, - CorInfoType simdBaseJitType, - unsigned simdSize); void SetOpLclRelatedToSIMDIntrinsic(GenTree* op); #endif @@ -4884,11 +4876,6 @@ class Compiler void fgValueNumberArrIndexAddr(GenTreeArrAddr* arrAddr); -#ifdef FEATURE_SIMD - // Does value-numbering for a GT_SIMD tree - void fgValueNumberSimd(GenTreeSIMD* tree); -#endif // FEATURE_SIMD - #ifdef FEATURE_HW_INTRINSICS // Does value-numbering for a GT_HWINTRINSIC tree void fgValueNumberHWIntrinsic(GenTreeHWIntrinsic* tree); @@ -8585,32 +8572,6 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX bool areArgumentsContiguous(GenTree* op1, GenTree* op2); GenTree* CreateAddressNodeForSimdHWIntrinsicCreate(GenTree* tree, var_types simdBaseType, unsigned simdSize); - // Whether SIMD vector occupies part of SIMD register. - // SSE2: vector2f/3f are considered sub register SIMD types. - // AVX: vector2f, 3f and 4f are all considered sub register SIMD types. - bool isSubRegisterSIMDType(GenTreeSIMD* simdNode) - { - unsigned vectorRegisterByteLength; -#if defined(TARGET_XARCH) - // Calling the getSIMDVectorRegisterByteLength api causes the size of Vector to be recorded - // with the AOT compiler, so that it cannot change from aot compilation time to runtime - // This api does not require such fixing as it merely pertains to the size of the simd type - // relative to the Vector size as used at compile time. (So detecting a vector length of 16 here - // does not preclude the code from being used on a machine with a larger vector length.) - if (getSIMDSupportLevel() < SIMD_AVX2_Supported) - { - vectorRegisterByteLength = 16; - } - else - { - vectorRegisterByteLength = 32; - } -#else - vectorRegisterByteLength = getSIMDVectorRegisterByteLength(); -#endif - return (simdNode->GetSimdSize() < vectorRegisterByteLength); - } - // Get the type for the hardware SIMD vector. // This is the maximum SIMD type supported for this target. var_types getSIMDVectorType() @@ -10973,13 +10934,8 @@ class GenTreeVisitor break; } -#if defined(FEATURE_SIMD) || defined(FEATURE_HW_INTRINSICS) -#if defined(FEATURE_SIMD) - case GT_SIMD: -#endif #if defined(FEATURE_HW_INTRINSICS) case GT_HWINTRINSIC: -#endif if (TVisitor::UseExecutionOrder && node->IsReverseOp()) { assert(node->AsMultiOp()->GetOperandCount() == 2); @@ -11007,7 +10963,7 @@ class GenTreeVisitor } } break; -#endif // defined(FEATURE_SIMD) || defined(FEATURE_HW_INTRINSICS) +#endif // defined(FEATURE_HW_INTRINSICS) case GT_SELECT: { diff --git a/src/coreclr/jit/compiler.hpp b/src/coreclr/jit/compiler.hpp index 946866d63c888..ea4a027400ecb 100644 --- a/src/coreclr/jit/compiler.hpp +++ b/src/coreclr/jit/compiler.hpp @@ -4125,13 +4125,8 @@ void GenTree::VisitOperands(TVisitor visitor) return; // Variadic nodes -#if defined(FEATURE_SIMD) || defined(FEATURE_HW_INTRINSICS) -#if defined(FEATURE_SIMD) - case GT_SIMD: -#endif #if defined(FEATURE_HW_INTRINSICS) case GT_HWINTRINSIC: -#endif for (GenTree* operand : this->AsMultiOp()->Operands()) { if (visitor(operand) == VisitResult::Abort) @@ -4140,7 +4135,7 @@ void GenTree::VisitOperands(TVisitor visitor) } } return; -#endif // defined(FEATURE_SIMD) || defined(FEATURE_HW_INTRINSICS) +#endif // defined(FEATURE_HW_INTRINSICS) // Special nodes case GT_PHI: diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index 2ffcd3ae2e0d4..a3a59a17927dd 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -351,10 +351,6 @@ void GenTree::InitNodeSize() #endif // FEATURE_ARG_SPLIT #endif // FEATURE_PUT_STRUCT_ARG_STK -#ifdef FEATURE_SIMD - static_assert_no_msg(sizeof(GenTreeSIMD) <= TREE_NODE_SZ_SMALL); -#endif // FEATURE_SIMD - #ifdef FEATURE_HW_INTRINSICS static_assert_no_msg(sizeof(GenTreeHWIntrinsic) <= TREE_NODE_SZ_SMALL); #endif // FEATURE_HW_INTRINSICS @@ -2659,11 +2655,6 @@ bool GenTree::Compare(GenTree* op1, GenTree* op2, bool swapOK) case GT_CALL: return GenTreeCall::Equals(op1->AsCall(), op2->AsCall()); -#ifdef FEATURE_SIMD - case GT_SIMD: - return GenTreeSIMD::Equals(op1->AsSIMD(), op2->AsSIMD()); -#endif // FEATURE_SIMD - #ifdef FEATURE_HW_INTRINSICS case GT_HWINTRINSIC: return GenTreeHWIntrinsic::Equals(op1->AsHWIntrinsic(), op2->AsHWIntrinsic()); @@ -3078,14 +3069,6 @@ unsigned Compiler::gtHashValue(GenTree* tree) case GT_INDEX_ADDR: break; -#ifdef FEATURE_SIMD - case GT_SIMD: - hash += tree->AsSIMD()->GetSIMDIntrinsicId(); - hash += tree->AsSIMD()->GetSimdBaseType(); - hash += tree->AsSIMD()->GetSimdSize(); - break; -#endif // FEATURE_SIMD - #ifdef FEATURE_HW_INTRINSICS case GT_HWINTRINSIC: hash += tree->AsHWIntrinsic()->GetHWIntrinsicId(); @@ -3181,20 +3164,15 @@ unsigned Compiler::gtHashValue(GenTree* tree) break; -#if defined(FEATURE_SIMD) || defined(FEATURE_HW_INTRINSICS) -#if defined(FEATURE_SIMD) - case GT_SIMD: -#endif #if defined(FEATURE_HW_INTRINSICS) case GT_HWINTRINSIC: -#endif // TODO-List: rewrite with a general visitor / iterator? for (GenTree* operand : tree->AsMultiOp()->Operands()) { hash = genTreeHashAdd(hash, gtHashValue(operand)); } break; -#endif // defined(FEATURE_SIMD) || defined(FEATURE_HW_INTRINSICS) +#endif // FEATURE_HW_INTRINSICS case GT_PHI: for (GenTreePhi::Use& use : tree->AsPhi()->Uses()) @@ -5001,6 +4979,20 @@ unsigned Compiler::gtSetEvalOrder(GenTree* tree) costEx = 36; costSz = 4; break; + +#if defined(FEATURE_SIMD) + case NI_SIMD_UpperRestore: + case NI_SIMD_UpperSave: + { + // TODO-CQ: 1 Ex/Sz isn't necessarily "accurate" but it is what the previous + // cost was computed as, in gtSetMultiOpOrder, when this was handled by the + // older SIMD intrinsic support. + + costEx = 1; + costSz = 1; + break; + } +#endif // FEATURE_SIMD } level++; break; @@ -5715,15 +5707,10 @@ unsigned Compiler::gtSetEvalOrder(GenTree* tree) costEx += 3 * IND_COST_EX; break; -#if defined(FEATURE_SIMD) || defined(FEATURE_HW_INTRINSICS) -#if defined(FEATURE_SIMD) - case GT_SIMD: -#endif #if defined(FEATURE_HW_INTRINSICS) case GT_HWINTRINSIC: -#endif return gtSetMultiOpOrder(tree->AsMultiOp()); -#endif // defined(FEATURE_SIMD) || defined(FEATURE_HW_INTRINSICS) +#endif // FEATURE_HW_INTRINSICS case GT_ARR_ELEM: { @@ -6084,13 +6071,8 @@ bool GenTree::TryGetUse(GenTree* operand, GenTree*** pUse) return false; #endif // FEATURE_ARG_SPLIT -#if defined(FEATURE_SIMD) || defined(FEATURE_HW_INTRINSICS) -#if defined(FEATURE_SIMD) - case GT_SIMD: -#endif #if defined(FEATURE_HW_INTRINSICS) case GT_HWINTRINSIC: -#endif for (GenTree** opUse : this->AsMultiOp()->UseEdges()) { if (*opUse == operand) @@ -6100,7 +6082,7 @@ bool GenTree::TryGetUse(GenTree* operand, GenTree*** pUse) } } return false; -#endif // defined(FEATURE_SIMD) || defined(FEATURE_HW_INTRINSICS) +#endif // FEATURE_HW_INTRINSICS // Special nodes case GT_PHI: @@ -8045,7 +8027,7 @@ GenTree* Compiler::gtNewBlkOpNode(GenTree* dst, GenTree* srcOrFillVal, bool isVo // should be labeled as simd intrinsic related struct. This is done so that // we do not promote the local, thus avoiding conflicting access methods // (fields vs. whole-register). - if (varTypeIsSIMD(srcOrFillVal) && srcOrFillVal->OperIsSimdOrHWintrinsic()) + if (varTypeIsSIMD(srcOrFillVal) && srcOrFillVal->OperIsHWIntrinsic()) { // TODO-Cleanup: similar logic already exists in "gtNewAssignNode", // however, it is not enabled for x86. Fix that and delete this code. @@ -8770,14 +8752,6 @@ GenTree* Compiler::gtCloneExpr( copy = gtCloneExprCallHelper(tree->AsCall(), addFlags, deepVarNum, deepVarVal); break; -#ifdef FEATURE_SIMD - case GT_SIMD: - copy = new (this, GT_SIMD) - GenTreeSIMD(tree->TypeGet(), IntrinsicNodeBuilder(getAllocator(CMK_ASTNode), tree->AsSIMD()), - tree->AsSIMD()->GetSIMDIntrinsicId(), tree->AsSIMD()->GetSimdBaseJitType(), - tree->AsSIMD()->GetSimdSize()); - goto CLONE_MULTIOP_OPERANDS; -#endif #ifdef FEATURE_HW_INTRINSICS case GT_HWINTRINSIC: copy = new (this, GT_HWINTRINSIC) @@ -9462,16 +9436,11 @@ GenTreeUseEdgeIterator::GenTreeUseEdgeIterator(GenTree* node) return; // Variadic nodes -#ifdef FEATURE_SIMD - case GT_SIMD: -#endif #ifdef FEATURE_HW_INTRINSICS case GT_HWINTRINSIC: -#endif -#if defined(FEATURE_SIMD) || defined(FEATURE_HW_INTRINSICS) SetEntryStateForMultiOp(); return; -#endif // defined(FEATURE_SIMD) || defined(FEATURE_HW_INTRINSICS) +#endif // FEATURE_HW_INTRINSICS // LEA, which may have no first operand case GT_LEA: @@ -9746,7 +9715,7 @@ void GenTreeUseEdgeIterator::SetEntryStateForBinOp() void GenTreeUseEdgeIterator::AdvanceMultiOp() { assert(m_node != nullptr); - assert(m_node->OperIs(GT_SIMD, GT_HWINTRINSIC)); + assert(m_node->OperIs(GT_HWINTRINSIC)); m_edge++; if (m_edge == m_statePtr) @@ -9765,7 +9734,7 @@ void GenTreeUseEdgeIterator::AdvanceMultiOp() void GenTreeUseEdgeIterator::AdvanceReversedMultiOp() { assert(m_node != nullptr); - assert(m_node->OperIs(GT_SIMD, GT_HWINTRINSIC)); + assert(m_node->OperIs(GT_HWINTRINSIC)); assert((m_node->AsMultiOp()->GetOperandCount() == 2) && m_node->IsReverseOp()); m_edge--; @@ -11681,14 +11650,6 @@ void Compiler::gtDispChild(GenTree* child, indentStack->Pop(); } -#ifdef FEATURE_SIMD -// Intrinsic Id to name map -extern const char* const simdIntrinsicNames[] = { -#define SIMD_INTRINSIC(mname, inst, id, name, r, ac, arg1, arg2, arg3, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10) name, -#include "simdintrinsiclist.h" -}; -#endif // FEATURE_SIMD - /*****************************************************************************/ void Compiler::gtDispTree(GenTree* tree, @@ -12138,22 +12099,8 @@ void Compiler::gtDispTree(GenTree* tree, } break; -#if defined(FEATURE_SIMD) || defined(FEATURE_HW_INTRINSICS) -#if defined(FEATURE_SIMD) - case GT_SIMD: -#endif #if defined(FEATURE_HW_INTRINSICS) case GT_HWINTRINSIC: -#endif - -#if defined(FEATURE_SIMD) - if (tree->OperIs(GT_SIMD)) - { - printf(" %s %s", varTypeName(tree->AsSIMD()->GetSimdBaseType()), - simdIntrinsicNames[tree->AsSIMD()->GetSIMDIntrinsicId()]); - } -#endif // defined(FEATURE_SIMD) -#if defined(FEATURE_HW_INTRINSICS) if (tree->OperIs(GT_HWINTRINSIC)) { printf(" %s %s", tree->AsHWIntrinsic()->GetSimdBaseType() == TYP_UNKNOWN @@ -12161,7 +12108,6 @@ void Compiler::gtDispTree(GenTree* tree, : varTypeName(tree->AsHWIntrinsic()->GetSimdBaseType()), HWIntrinsicInfo::lookupName(tree->AsHWIntrinsic()->GetHWIntrinsicId())); } -#endif // defined(FEATURE_HW_INTRINSICS) gtDispCommonEndLine(tree); @@ -12175,7 +12121,7 @@ void Compiler::gtDispTree(GenTree* tree, } } break; -#endif // defined(FEATURE_SIMD) || defined(FEATURE_HW_INTRINSICS) +#endif // defined(FEATURE_HW_INTRINSICS) case GT_ARR_ELEM: gtDispCommonEndLine(tree); @@ -14399,12 +14345,6 @@ GenTree* Compiler::gtFoldExprConst(GenTree* tree) return tree; } -#ifdef FEATURE_SIMD - if (tree->OperIs(GT_SIMD)) - { - return tree; - } -#endif // FEATURE_SIMD #ifdef FEATURE_HW_INTRINSICS if (tree->OperIs(GT_HWINTRINSIC)) { @@ -17613,9 +17553,6 @@ CORINFO_CLASS_HANDLE Compiler::gtGetStructHandleIfPresent(GenTree* tree) structHnd = gtGetCanonicalStructHandleForSIMD(tree->TypeGet()); } break; - case GT_SIMD: - structHnd = gtGetStructHandleForSIMD(tree->gtType, tree->AsSIMD()->GetSimdBaseJitType()); - break; case GT_CNS_VEC: structHnd = gtGetCanonicalStructHandleForSIMD(tree->TypeGet()); break; @@ -18599,33 +18536,6 @@ FieldSeq::FieldSeq(CORINFO_FIELD_HANDLE fieldHnd, ssize_t offset, FieldKind fiel } #ifdef FEATURE_SIMD -GenTreeSIMD* Compiler::gtNewSIMDNode( - var_types type, GenTree* op1, SIMDIntrinsicID simdIntrinsicID, CorInfoType simdBaseJitType, unsigned simdSize) -{ - assert(op1 != nullptr); - SetOpLclRelatedToSIMDIntrinsic(op1); - - GenTreeSIMD* simdNode = new (this, GT_SIMD) - GenTreeSIMD(type, getAllocator(CMK_ASTNode), op1, simdIntrinsicID, simdBaseJitType, simdSize); - return simdNode; -} - -GenTreeSIMD* Compiler::gtNewSIMDNode(var_types type, - GenTree* op1, - GenTree* op2, - SIMDIntrinsicID simdIntrinsicID, - CorInfoType simdBaseJitType, - unsigned simdSize) -{ - assert(op1 != nullptr); - SetOpLclRelatedToSIMDIntrinsic(op1); - SetOpLclRelatedToSIMDIntrinsic(op2); - - GenTreeSIMD* simdNode = new (this, GT_SIMD) - GenTreeSIMD(type, getAllocator(CMK_ASTNode), op1, op2, simdIntrinsicID, simdBaseJitType, simdSize); - return simdNode; -} - //------------------------------------------------------------------- // SetOpLclRelatedToSIMDIntrinsic: Determine if the tree has a local var that needs to be set // as used by a SIMD intrinsic, and if so, set that local var appropriately. @@ -18746,13 +18656,6 @@ var_types GenTreeJitIntrinsic::GetSimdBaseType() const } return JitType2PreciseVarType(simdBaseJitType); } - -/* static */ bool GenTreeSIMD::Equals(GenTreeSIMD* op1, GenTreeSIMD* op2) -{ - return (op1->TypeGet() == op2->TypeGet()) && (op1->GetSIMDIntrinsicId() == op2->GetSIMDIntrinsicId()) && - (op1->GetSimdBaseType() == op2->GetSimdBaseType()) && (op1->GetSimdSize() == op2->GetSimdSize()) && - OperandsAreEqual(op1, op2); -} #endif // FEATURE_SIMD #ifdef FEATURE_HW_INTRINSICS diff --git a/src/coreclr/jit/gentree.h b/src/coreclr/jit/gentree.h index a7cd6c5600ecb..780953c5c0cf7 100644 --- a/src/coreclr/jit/gentree.h +++ b/src/coreclr/jit/gentree.h @@ -1088,7 +1088,7 @@ struct GenTree if (gtType == TYP_VOID) { // These are the only operators which can produce either VOID or non-VOID results. - assert(OperIs(GT_NOP, GT_CALL, GT_COMMA) || OperIsCompare() || OperIsLong() || OperIsSimdOrHWintrinsic() || + assert(OperIs(GT_NOP, GT_CALL, GT_COMMA) || OperIsCompare() || OperIsLong() || OperIsHWIntrinsic() || IsCnsVec()); return false; } @@ -1642,7 +1642,7 @@ struct GenTree static bool OperIsMultiOp(genTreeOps gtOper) { - return OperIsSIMD(gtOper) || OperIsHWIntrinsic(gtOper); + return OperIsHWIntrinsic(gtOper); } bool OperIsMultiOp() const @@ -1655,21 +1655,6 @@ struct GenTree return OperIs(GT_ASG, GT_CALL); } - // This is here for cleaner FEATURE_SIMD #ifdefs. - static bool OperIsSIMD(genTreeOps gtOper) - { -#ifdef FEATURE_SIMD - return gtOper == GT_SIMD; -#else // !FEATURE_SIMD - return false; -#endif // !FEATURE_SIMD - } - - bool OperIsSIMD() const - { - return OperIsSIMD(gtOper); - } - static bool OperIsHWIntrinsic(genTreeOps gtOper) { #ifdef FEATURE_HW_INTRINSICS @@ -1684,11 +1669,6 @@ struct GenTree return OperIsHWIntrinsic(gtOper); } - bool OperIsSimdOrHWintrinsic() const - { - return OperIsSIMD() || OperIsHWIntrinsic(); - } - // This is here for cleaner GT_LONG #ifdefs. static bool OperIsLong(genTreeOps gtOper) { @@ -5587,7 +5567,7 @@ struct GenTreeCall final : public GenTree bool mayUseDispatcher = true; // Branch predictors on ARM64 generally do not handle the dispatcher as // well as on x64 hardware, so only use the validator by default. - bool shouldUseDispatcher = false; + bool shouldUseDispatcher = false; #else // Other platforms do not even support the dispatcher. bool mayUseDispatcher = false; @@ -6130,20 +6110,12 @@ struct GenTreeJitIntrinsic : public GenTreeMultiOp { protected: GenTree* gtInlineOperands[2]; - regNumberSmall gtOtherReg; // The second register for multi-reg intrinsics. - MultiRegSpillFlags gtSpillFlags; // Spill flags for multi-reg intrinsics. - unsigned char gtAuxiliaryJitType; // For intrinsics than need another type (e.g. Avx2.Gather* or SIMD (by element)) - unsigned char gtSimdBaseJitType; // SIMD vector base JIT type - unsigned char gtSimdSize; // SIMD vector size in bytes, use 0 for scalar intrinsics - -#if defined(FEATURE_SIMD) - union { - SIMDIntrinsicID gtSIMDIntrinsicID; // operation Id - NamedIntrinsic gtHWIntrinsicId; - }; -#else + regNumberSmall gtOtherReg; // The second register for multi-reg intrinsics. + MultiRegSpillFlags gtSpillFlags; // Spill flags for multi-reg intrinsics. + unsigned char gtAuxiliaryJitType; // For intrinsics than need another type (e.g. Avx2.Gather* or SIMD (by element)) + unsigned char gtSimdBaseJitType; // SIMD vector base JIT type + unsigned char gtSimdSize; // SIMD vector size in bytes, use 0 for scalar intrinsics NamedIntrinsic gtHWIntrinsicId; -#endif public: regNumber GetOtherReg() const @@ -6286,59 +6258,6 @@ struct GenTreeJitIntrinsic : public GenTreeMultiOp } }; -#ifdef FEATURE_SIMD - -/* gtSIMD -- SIMD intrinsic (possibly-binary op [NULL op2 is allowed] with additional fields) */ -struct GenTreeSIMD : public GenTreeJitIntrinsic -{ - GenTreeSIMD(var_types type, - IntrinsicNodeBuilder&& nodeBuilder, - SIMDIntrinsicID simdIntrinsicID, - CorInfoType simdBaseJitType, - unsigned simdSize) - : GenTreeJitIntrinsic(GT_SIMD, type, std::move(nodeBuilder), simdBaseJitType, simdSize) - { - gtSIMDIntrinsicID = simdIntrinsicID; - } - - GenTreeSIMD(var_types type, - CompAllocator allocator, - GenTree* op1, - SIMDIntrinsicID simdIntrinsicID, - CorInfoType simdBaseJitType, - unsigned simdSize) - : GenTreeJitIntrinsic(GT_SIMD, type, allocator, simdBaseJitType, simdSize, op1) - { - gtSIMDIntrinsicID = simdIntrinsicID; - } - - GenTreeSIMD(var_types type, - CompAllocator allocator, - GenTree* op1, - GenTree* op2, - SIMDIntrinsicID simdIntrinsicID, - CorInfoType simdBaseJitType, - unsigned simdSize) - : GenTreeJitIntrinsic(GT_SIMD, type, allocator, simdBaseJitType, simdSize, op1, op2) - { - gtSIMDIntrinsicID = simdIntrinsicID; - } - -#if DEBUGGABLE_GENTREE - GenTreeSIMD() : GenTreeJitIntrinsic() - { - } -#endif - - SIMDIntrinsicID GetSIMDIntrinsicId() const - { - return gtSIMDIntrinsicID; - } - - static bool Equals(GenTreeSIMD* op1, GenTreeSIMD* op2); -}; -#endif // FEATURE_SIMD - #ifdef FEATURE_HW_INTRINSICS struct GenTreeHWIntrinsic : public GenTreeJitIntrinsic { diff --git a/src/coreclr/jit/gtlist.h b/src/coreclr/jit/gtlist.h index cf6f508fd1277..a0650f1d0dc05 100644 --- a/src/coreclr/jit/gtlist.h +++ b/src/coreclr/jit/gtlist.h @@ -189,10 +189,6 @@ GTNODE(RSH_LO , GenTreeOp ,0,GTK_BINOP|DBK_NOTHIR) GTNODE(SELECT_HI , GenTreeOp ,0,GTK_BINOP|DBK_NOTHIR) #endif // !defined(TARGET_64BIT) -#ifdef FEATURE_SIMD -GTNODE(SIMD , GenTreeSIMD ,0,GTK_SPECIAL) // SIMD functions/operators/intrinsics -#endif // FEATURE_SIMD - #ifdef FEATURE_HW_INTRINSICS GTNODE(HWINTRINSIC , GenTreeHWIntrinsic ,0,GTK_SPECIAL) // hardware intrinsics #endif // FEATURE_HW_INTRINSICS diff --git a/src/coreclr/jit/gtstructs.h b/src/coreclr/jit/gtstructs.h index ae62bde014a5a..0321f51a95c00 100644 --- a/src/coreclr/jit/gtstructs.h +++ b/src/coreclr/jit/gtstructs.h @@ -73,11 +73,7 @@ GTSTRUCT_1(Colon , GT_COLON) GTSTRUCT_1(FptrVal , GT_FTN_ADDR) GTSTRUCT_1(Intrinsic , GT_INTRINSIC) GTSTRUCT_1(IndexAddr , GT_INDEX_ADDR) -#if defined(FEATURE_HW_INTRINSICS) && defined(FEATURE_SIMD) -GTSTRUCT_N(MultiOp , GT_SIMD, GT_HWINTRINSIC) -#elif defined(FEATURE_SIMD) -GTSTRUCT_N(MultiOp , GT_SIMD) -#elif defined(FEATURE_HW_INTRINSICS) +#if defined(FEATURE_HW_INTRINSICS) GTSTRUCT_N(MultiOp , GT_HWINTRINSIC) #endif GTSTRUCT_1(BoundsChk , GT_BOUNDS_CHECK) @@ -109,9 +105,6 @@ GTSTRUCT_1(PutArgSplit , GT_PUTARG_SPLIT) GTSTRUCT_1(PutArgStk , GT_PUTARG_STK) #endif // !FEATURE_ARG_SPLIT GTSTRUCT_1(PhysReg , GT_PHYSREG) -#ifdef FEATURE_SIMD -GTSTRUCT_1(SIMD , GT_SIMD) -#endif // FEATURE_SIMD #ifdef FEATURE_HW_INTRINSICS GTSTRUCT_1(HWIntrinsic , GT_HWINTRINSIC) #endif // FEATURE_HW_INTRINSICS diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index eda9ce179b639..d1af2c46f630b 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -1196,7 +1196,7 @@ GenTree* Compiler::impGetStructAddr(GenTree* structVal, genTreeOps oper = structVal->gtOper; if (oper == GT_CALL || oper == GT_RET_EXPR || (oper == GT_OBJ && !willDeref) || oper == GT_MKREFANY || - structVal->OperIsSimdOrHWintrinsic() || structVal->IsCnsVec()) + structVal->OperIsHWIntrinsic() || structVal->IsCnsVec()) { unsigned tmpNum = lvaGrabTemp(true DEBUGARG("struct address for call/obj")); @@ -1342,9 +1342,6 @@ GenTree* Compiler::impNormStructVal(GenTree* structVal, CORINFO_CLASS_HANDLE str case GT_BLK: case GT_FIELD: case GT_CNS_VEC: -#ifdef FEATURE_SIMD - case GT_SIMD: -#endif #ifdef FEATURE_HW_INTRINSICS case GT_HWINTRINSIC: #endif @@ -1355,7 +1352,7 @@ GenTree* Compiler::impNormStructVal(GenTree* structVal, CORINFO_CLASS_HANDLE str case GT_COMMA: { - // The second thing could either be a block node or a GT_FIELD or a GT_SIMD or a GT_COMMA node. + // The second thing could either be a block node or a GT_FIELD or a GT_COMMA node. GenTree* blockNode = structVal->AsOp()->gtOp2; assert(blockNode->gtType == structType); @@ -1373,7 +1370,7 @@ GenTree* Compiler::impNormStructVal(GenTree* structVal, CORINFO_CLASS_HANDLE str } #ifdef FEATURE_SIMD - if (blockNode->OperIsSimdOrHWintrinsic() || blockNode->IsCnsVec()) + if (blockNode->OperIsHWIntrinsic() || blockNode->IsCnsVec()) { parent->AsOp()->gtOp2 = impNormStructVal(blockNode, structHnd, curLevel); } diff --git a/src/coreclr/jit/lower.cpp b/src/coreclr/jit/lower.cpp index 9a2180983bc0a..b9cd308c66781 100644 --- a/src/coreclr/jit/lower.cpp +++ b/src/coreclr/jit/lower.cpp @@ -1344,7 +1344,7 @@ void Lowering::LowerArg(GenTreeCall* call, CallArg* callArg, bool late) const LclVarDsc* varDsc = comp->lvaGetDesc(arg->AsLclVarCommon()); type = varDsc->lvType; } - else if (arg->OperIs(GT_SIMD, GT_HWINTRINSIC)) + else if (arg->OperIs(GT_HWINTRINSIC)) { GenTreeJitIntrinsic* jitIntrinsic = reinterpret_cast(arg); @@ -6639,7 +6639,6 @@ void Lowering::CheckNode(Compiler* compiler, GenTree* node) break; #ifdef FEATURE_SIMD - case GT_SIMD: case GT_HWINTRINSIC: assert(node->TypeGet() != TYP_SIMD12); break; diff --git a/src/coreclr/jit/lsra.cpp b/src/coreclr/jit/lsra.cpp index 1203485793fa6..0e1cf0770a9df 100644 --- a/src/coreclr/jit/lsra.cpp +++ b/src/coreclr/jit/lsra.cpp @@ -6311,24 +6311,15 @@ void LinearScan::insertUpperVectorSave(GenTree* tree, saveLcl->SetRegNum(lclVarReg); SetLsraAdded(saveLcl); - GenTreeSIMD* simdNode = compiler->gtNewSIMDNode(LargeVectorSaveType, saveLcl, SIMDIntrinsicUpperSave, - varDsc->GetSimdBaseJitType(), genTypeSize(varDsc)); + GenTreeIntrinsic* simdUpperSave = + new (compiler, GT_INTRINSIC) GenTreeIntrinsic(LargeVectorSaveType, saveLcl, NI_SIMD_UpperSave, nullptr); - if (simdNode->GetSimdBaseJitType() == CORINFO_TYPE_UNDEF) - { - // There are a few scenarios where we can get a LCL_VAR which - // doesn't know the underlying baseType. In that scenario, we - // will just lie and say it is a float. Codegen doesn't actually - // care what the type is but this avoids an assert that would - // otherwise be fired from the more general checks that happen. - simdNode->SetSimdBaseJitType(CORINFO_TYPE_FLOAT); - } + SetLsraAdded(simdUpperSave); + simdUpperSave->SetRegNum(spillReg); - SetLsraAdded(simdNode); - simdNode->SetRegNum(spillReg); if (spillToMem) { - simdNode->gtFlags |= GTF_SPILL; + simdUpperSave->gtFlags |= GTF_SPILL; upperVectorInterval->physReg = REG_NA; } else @@ -6337,8 +6328,8 @@ void LinearScan::insertUpperVectorSave(GenTree* tree, upperVectorInterval->physReg = spillReg; } - blockRange.InsertBefore(tree, LIR::SeqTree(compiler, simdNode)); - DISPTREE(simdNode); + blockRange.InsertBefore(tree, LIR::SeqTree(compiler, simdUpperSave)); + DISPTREE(simdUpperSave); JITDUMP("\n"); } @@ -6377,21 +6368,11 @@ void LinearScan::insertUpperVectorRestore(GenTree* tree, restoreLcl->SetRegNum(lclVarReg); SetLsraAdded(restoreLcl); - GenTreeSIMD* simdNode = compiler->gtNewSIMDNode(varDsc->TypeGet(), restoreLcl, SIMDIntrinsicUpperRestore, - varDsc->GetSimdBaseJitType(), genTypeSize(varDsc->lvType)); - - if (simdNode->GetSimdBaseJitType() == CORINFO_TYPE_UNDEF) - { - // There are a few scenarios where we can get a LCL_VAR which - // doesn't know the underlying baseType. In that scenario, we - // will just lie and say it is a float. Codegen doesn't actually - // care what the type is but this avoids an assert that would - // otherwise be fired from the more general checks that happen. - simdNode->SetSimdBaseJitType(CORINFO_TYPE_FLOAT); - } + GenTreeIntrinsic* simdUpperRestore = + new (compiler, GT_INTRINSIC) GenTreeIntrinsic(varDsc->TypeGet(), restoreLcl, NI_SIMD_UpperRestore, nullptr); regNumber restoreReg = upperVectorInterval->physReg; - SetLsraAdded(simdNode); + SetLsraAdded(simdUpperRestore); if (restoreReg == REG_NA) { @@ -6399,14 +6380,14 @@ void LinearScan::insertUpperVectorRestore(GenTree* tree, assert(lclVarInterval->isSpilled); #ifdef TARGET_AMD64 assert(refPosition->assignedReg() == REG_NA); - simdNode->gtFlags |= GTF_NOREG_AT_USE; + simdUpperRestore->gtFlags |= GTF_NOREG_AT_USE; #else - simdNode->gtFlags |= GTF_SPILLED; + simdUpperRestore->gtFlags |= GTF_SPILLED; assert(refPosition->assignedReg() != REG_NA); restoreReg = refPosition->assignedReg(); #endif } - simdNode->SetRegNum(restoreReg); + simdUpperRestore->SetRegNum(restoreReg); LIR::Range& blockRange = LIR::AsRange(block); if (tree != nullptr) @@ -6416,7 +6397,7 @@ void LinearScan::insertUpperVectorRestore(GenTree* tree, bool foundUse = blockRange.TryGetUse(tree, &treeUse); assert(foundUse); // We need to insert the restore prior to the use, not (necessarily) immediately after the lclVar. - blockRange.InsertBefore(treeUse.User(), LIR::SeqTree(compiler, simdNode)); + blockRange.InsertBefore(treeUse.User(), LIR::SeqTree(compiler, simdUpperRestore)); } else { @@ -6429,15 +6410,15 @@ void LinearScan::insertUpperVectorRestore(GenTree* tree, assert(branch->OperIsConditionalJump() || branch->OperGet() == GT_SWITCH_TABLE || branch->OperGet() == GT_SWITCH); - blockRange.InsertBefore(branch, LIR::SeqTree(compiler, simdNode)); + blockRange.InsertBefore(branch, LIR::SeqTree(compiler, simdUpperRestore)); } else { assert(block->KindIs(BBJ_NONE, BBJ_ALWAYS)); - blockRange.InsertAtEnd(LIR::SeqTree(compiler, simdNode)); + blockRange.InsertAtEnd(LIR::SeqTree(compiler, simdUpperRestore)); } } - DISPTREE(simdNode); + DISPTREE(simdUpperRestore); JITDUMP("\n"); } #endif // FEATURE_PARTIAL_SIMD_CALLEE_SAVE diff --git a/src/coreclr/jit/morph.cpp b/src/coreclr/jit/morph.cpp index 14403a8c0f796..d2fd606accd11 100644 --- a/src/coreclr/jit/morph.cpp +++ b/src/coreclr/jit/morph.cpp @@ -12749,16 +12749,11 @@ GenTree* Compiler::fgMorphTree(GenTree* tree, MorphAddrContext* mac) tree = fgMorphCall(tree->AsCall()); break; -#if defined(FEATURE_SIMD) || defined(FEATURE_HW_INTRINSICS) -#if defined(FEATURE_SIMD) - case GT_SIMD: -#endif #if defined(FEATURE_HW_INTRINSICS) case GT_HWINTRINSIC: -#endif tree = fgMorphMultiOp(tree->AsMultiOp()); break; -#endif // defined(FEATURE_SIMD) || defined(FEATURE_HW_INTRINSICS) +#endif // FEATURE_HW_INTRINSICS case GT_ARR_ELEM: tree->AsArrElem()->gtArrObj = fgMorphTree(tree->AsArrElem()->gtArrObj); diff --git a/src/coreclr/jit/namedintrinsiclist.h b/src/coreclr/jit/namedintrinsiclist.h index 37af303c0ab68..dd58663b6505c 100644 --- a/src/coreclr/jit/namedintrinsiclist.h +++ b/src/coreclr/jit/namedintrinsiclist.h @@ -148,6 +148,11 @@ enum NamedIntrinsic : unsigned short NI_SIMD_AS_HWINTRINSIC_END, #endif // FEATURE_HW_INTRINSICS +#if defined(FEATURE_SIMD) + NI_SIMD_UpperRestore, + NI_SIMD_UpperSave, +#endif // FEATURE_SIMD + NI_SRCS_UNSAFE_START, NI_SRCS_UNSAFE_Add, diff --git a/src/coreclr/jit/optcse.cpp b/src/coreclr/jit/optcse.cpp index efd8ffb0f26b4..fa21ea5b8facd 100644 --- a/src/coreclr/jit/optcse.cpp +++ b/src/coreclr/jit/optcse.cpp @@ -3666,12 +3666,6 @@ bool Compiler::optIsCSEcandidate(GenTree* tree) case GT_GT: return true; // Allow the CSE of Comparison operators -#ifdef FEATURE_SIMD - case GT_SIMD: - return true; // allow SIMD intrinsics to be CSE-ed - -#endif // FEATURE_SIMD - #ifdef FEATURE_HW_INTRINSICS case GT_HWINTRINSIC: { diff --git a/src/coreclr/jit/simd.cpp b/src/coreclr/jit/simd.cpp index 8f18908134f51..d73d4d779e9e9 100644 --- a/src/coreclr/jit/simd.cpp +++ b/src/coreclr/jit/simd.cpp @@ -8,7 +8,7 @@ // // This implementation is preliminary, and may change dramatically. // -// New JIT types, TYP_SIMDxx, are introduced, and the SIMD intrinsics are created as GT_SIMD nodes. +// New JIT types, TYP_SIMDxx, are introduced, and the hwintrinsics are created as GT_HWINTRINSC nodes. // Nodes of SIMD types will be typed as TYP_SIMD* (e.g. TYP_SIMD8, TYP_SIMD16, etc.). // // Note that currently the "reference implementation" is the same as the runtime dll. As such, it is currently @@ -30,15 +30,6 @@ #endif #ifdef FEATURE_SIMD - -// Intrinsic Id to intrinsic info map -const SIMDIntrinsicInfo simdIntrinsicInfoArray[] = { -#define SIMD_INTRINSIC(mname, inst, id, name, retType, argCount, arg1, arg2, arg3, t1, t2, t3, t4, t5, t6, t7, t8, t9, \ - t10) \ - {SIMDIntrinsic##id, mname, inst, retType, argCount, arg1, arg2, arg3, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10}, -#include "simdintrinsiclist.h" -}; - //------------------------------------------------------------------------ // getSIMDVectorLength: Get the length (number of elements of base type) of // SIMD Vector given its size and base (element) type. diff --git a/src/coreclr/jit/simd.h b/src/coreclr/jit/simd.h index f59c09b72a7c0..be227acf2bcaf 100644 --- a/src/coreclr/jit/simd.h +++ b/src/coreclr/jit/simd.h @@ -144,28 +144,6 @@ struct simd32_t #ifdef FEATURE_SIMD -#ifdef DEBUG -extern const char* const simdIntrinsicNames[]; -#endif - -enum SIMDIntrinsicID : uint16_t -{ -#define SIMD_INTRINSIC(m, i, id, n, r, ac, arg1, arg2, arg3, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10) SIMDIntrinsic##id, -#include "simdintrinsiclist.h" -}; - -// Static info about a SIMD intrinsic -struct SIMDIntrinsicInfo -{ - SIMDIntrinsicID id; - const char* methodName; - bool isInstMethod; - var_types retType; - unsigned char argCount; - var_types argType[SIMD_INTRINSIC_MAX_MODELED_PARAM_COUNT]; - var_types supportedBaseTypes[SIMD_INTRINSIC_MAX_BASETYPE_COUNT]; -}; - #ifdef TARGET_XARCH // SSE2 Shuffle control byte to shuffle vector // These correspond to shuffle immediate byte in shufps SSE2 instruction. diff --git a/src/coreclr/jit/simdcodegenxarch.cpp b/src/coreclr/jit/simdcodegenxarch.cpp index a05e281fa54ef..68e7236101625 100644 --- a/src/coreclr/jit/simdcodegenxarch.cpp +++ b/src/coreclr/jit/simdcodegenxarch.cpp @@ -285,11 +285,11 @@ void CodeGen::genPutArgStkSIMD12(GenTree* treeNode) #endif // TARGET_X86 //----------------------------------------------------------------------------- -// genSIMDIntrinsicUpperSave: save the upper half of a TYP_SIMD32 vector to -// the given register, if any, or to memory. +// genSimdUpperSave: save the upper half of a TYP_SIMD32 vector to +// the given register, if any, or to memory. // // Arguments: -// simdNode - The GT_SIMD node +// node - The GT_INTRINSIC node // // Return Value: // None. @@ -303,26 +303,30 @@ void CodeGen::genPutArgStkSIMD12(GenTree* treeNode) // (Note that if there are no caller-save registers available, the entire 32 byte // value will be spilled to the stack.) // -void CodeGen::genSIMDIntrinsicUpperSave(GenTreeSIMD* simdNode) +void CodeGen::genSimdUpperSave(GenTreeIntrinsic* node) { - assert(simdNode->GetSIMDIntrinsicId() == SIMDIntrinsicUpperSave); + assert(node->gtIntrinsicName == NI_SIMD_UpperSave); - GenTree* op1 = simdNode->Op(1); - assert(op1->IsLocal() && op1->TypeGet() == TYP_SIMD32); - regNumber targetReg = simdNode->GetRegNum(); - regNumber op1Reg = genConsumeReg(op1); + GenTree* op1 = node->gtGetOp1(); + assert(op1->IsLocal() && (op1->TypeGet() == TYP_SIMD32)); + + regNumber tgtReg = node->GetRegNum(); + regNumber op1Reg = genConsumeReg(op1); assert(op1Reg != REG_NA); - if (targetReg != REG_NA) + + if (tgtReg != REG_NA) { - GetEmitter()->emitIns_R_R_I(INS_vextractf128, EA_32BYTE, targetReg, op1Reg, 0x01); - genProduceReg(simdNode); + GetEmitter()->emitIns_R_R_I(INS_vextractf128, EA_32BYTE, tgtReg, op1Reg, 0x01); + genProduceReg(node); } else { // The localVar must have a stack home. + unsigned varNum = op1->AsLclVarCommon()->GetLclNum(); LclVarDsc* varDsc = compiler->lvaGetDesc(varNum); assert(varDsc->lvOnFrame); + // We want to store this to the upper 16 bytes of this localVar's home. int offs = 16; @@ -331,29 +335,31 @@ void CodeGen::genSIMDIntrinsicUpperSave(GenTreeSIMD* simdNode) } //----------------------------------------------------------------------------- -// genSIMDIntrinsicUpperRestore: Restore the upper half of a TYP_SIMD32 vector to -// the given register, if any, or to memory. +// genSimdUpperRestore: Restore the upper half of a TYP_SIMD32 vector to +// the given register, if any, or to memory. // // Arguments: -// simdNode - The GT_SIMD node +// node - The GT_INTRINSIC node // // Return Value: // None. // // Notes: -// For consistency with genSIMDIntrinsicUpperSave, and to ensure that lclVar nodes always +// For consistency with genSimdUpperSave, and to ensure that lclVar nodes always // have their home register, this node has its targetReg on the lclVar child, and its source -// on the simdNode. +// on the node. // -void CodeGen::genSIMDIntrinsicUpperRestore(GenTreeSIMD* simdNode) +void CodeGen::genSimdUpperRestore(GenTreeIntrinsic* node) { - assert(simdNode->GetSIMDIntrinsicId() == SIMDIntrinsicUpperRestore); + assert(node->gtIntrinsicName == NI_SIMD_UpperRestore); - GenTree* op1 = simdNode->Op(1); + GenTree* op1 = node->gtGetOp1(); assert(op1->IsLocal() && op1->TypeGet() == TYP_SIMD32); - regNumber srcReg = simdNode->GetRegNum(); + + regNumber srcReg = node->GetRegNum(); regNumber lclVarReg = genConsumeReg(op1); assert(lclVarReg != REG_NA); + if (srcReg != REG_NA) { GetEmitter()->emitIns_R_R_R_I(INS_vinsertf128, EA_32BYTE, lclVarReg, lclVarReg, srcReg, 0x01); @@ -370,42 +376,5 @@ void CodeGen::genSIMDIntrinsicUpperRestore(GenTreeSIMD* simdNode) } } -//------------------------------------------------------------------------ -// genSIMDIntrinsic: Generate code for a SIMD Intrinsic. This is the main -// routine which in turn calls appropriate genSIMDIntrinsicXXX() routine. -// -// Arguments: -// simdNode - The GT_SIMD node -// -// Return Value: -// None. -// -// Notes: -// Currently, we only recognize SIMDVector and SIMDVector, and -// a limited set of methods. -// -void CodeGen::genSIMDIntrinsic(GenTreeSIMD* simdNode) -{ - // NYI for unsupported base types - if (!varTypeIsArithmetic(simdNode->GetSimdBaseType())) - { - noway_assert(!"SIMD intrinsic with unsupported base type."); - } - - switch (simdNode->GetSIMDIntrinsicId()) - { - case SIMDIntrinsicUpperSave: - genSIMDIntrinsicUpperSave(simdNode); - break; - case SIMDIntrinsicUpperRestore: - genSIMDIntrinsicUpperRestore(simdNode); - break; - - default: - noway_assert(!"Unimplemented SIMD intrinsic."); - unreached(); - } -} - #endif // FEATURE_SIMD #endif // TARGET_XARCH diff --git a/src/coreclr/jit/simdintrinsiclist.h b/src/coreclr/jit/simdintrinsiclist.h deleted file mode 100644 index 74beb2db3d8ca..0000000000000 --- a/src/coreclr/jit/simdintrinsiclist.h +++ /dev/null @@ -1,53 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -/*****************************************************************************/ -#ifndef SIMD_INTRINSIC -#error Define SIMD_INTRINSIC before including this file -#endif -/*****************************************************************************/ - -// clang-format off -#ifdef FEATURE_SIMD - - /* - Notes: - a) TYP_UNKNOWN means 'baseType' of SIMD vector which is not known apriori - b) Each method maps to a unique intrinsic Id - c) To facilitate argument types to be used as an array initializer, args are listed within "{}" braces. - d) Since comma is used as actual param separator in a macro, TYP_UNDEF entries are added to keep param count constant. - e) TODO-Cleanup: when we plumb TYP_SIMD through front-end, replace TYP_STRUCT with TYP_SIMD. - */ - -#if defined(TARGET_XARCH) || defined(TARGET_ARM64) - -// Max number of parameters that we model in the table for SIMD intrinsic methods. -#define SIMD_INTRINSIC_MAX_MODELED_PARAM_COUNT 3 - -// Actual maximum number of parameters for any SIMD intrinsic method. -// Constructors that take either N values, or a smaller Vector plus additional element values, -// actually have more arguments than the "modeled" count. -#define SIMD_INTRINSIC_MAX_PARAM_COUNT 5 - -// Max number of base types supported by an intrinsic -#define SIMD_INTRINSIC_MAX_BASETYPE_COUNT 10 - -/*************************************************************************************************************************************************************************************************************************** - Method Name, Is Instance Intrinsic Id, Display Name, return type, Arg count, Individual argument types Supported base types - Method (including implicit "this") - ***************************************************************************************************************************************************************************************************************************/ -SIMD_INTRINSIC(nullptr, false, None, "None", TYP_UNDEF, 0, {TYP_UNDEF, TYP_UNDEF, TYP_UNDEF}, {TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF}) - -// Internal intrinsics for saving & restoring the upper half of a vector register -SIMD_INTRINSIC("UpperSave", false, UpperSave, "UpperSave Internal", TYP_STRUCT, 2, {TYP_UNDEF, TYP_UNDEF, TYP_UNDEF}, {TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF}) -SIMD_INTRINSIC("UpperRestore", false, UpperRestore, "UpperRestore Internal", TYP_STRUCT, 2, {TYP_UNDEF, TYP_UNDEF, TYP_UNDEF}, {TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF}) - -SIMD_INTRINSIC(nullptr, false, Invalid, "Invalid", TYP_UNDEF, 0, {TYP_UNDEF, TYP_UNDEF, TYP_UNDEF}, {TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF}) -#undef SIMD_INTRINSIC -#else // !defined(TARGET_XARCH) && !defined(TARGET_ARM64) -#error SIMD intrinsics not defined for target arch -#endif // !defined(TARGET_XARCH) && !defined(TARGET_ARM64) - - -#endif //FEATURE_SIMD -// clang-format on diff --git a/src/coreclr/jit/valuenum.cpp b/src/coreclr/jit/valuenum.cpp index b6c74e5fcc679..1bc05151623d1 100644 --- a/src/coreclr/jit/valuenum.cpp +++ b/src/coreclr/jit/valuenum.cpp @@ -341,10 +341,6 @@ VNFunc GetVNFuncForNode(GenTree* node) } break; -#ifdef FEATURE_SIMD - case GT_SIMD: - return VNFunc(VNF_SIMD_FIRST + node->AsSIMD()->GetSIMDIntrinsicId()); -#endif // FEATURE_SIMD #ifdef FEATURE_HW_INTRINSICS case GT_HWINTRINSIC: return VNFunc(VNF_HWI_FIRST + (node->AsHWIntrinsic()->GetHWIntrinsicId() - NI_HW_INTRINSIC_START - 1)); @@ -9327,12 +9323,6 @@ void Compiler::fgValueNumberTree(GenTree* tree) fgValueNumberCall(tree->AsCall()); break; -#ifdef FEATURE_SIMD - case GT_SIMD: - fgValueNumberSimd(tree->AsSIMD()); - break; -#endif // FEATURE_SIMD - #ifdef FEATURE_HW_INTRINSICS case GT_HWINTRINSIC: fgValueNumberHWIntrinsic(tree->AsHWIntrinsic()); @@ -9561,68 +9551,6 @@ void Compiler::fgValueNumberArrIndexAddr(GenTreeArrAddr* arrAddr) arrAddr->gtVNPair = vnStore->VNPWithExc(arrAddrVNP, vnStore->VNPExceptionSet(arrAddr->Addr()->gtVNPair)); } -#ifdef FEATURE_SIMD -// Does value-numbering for a GT_SIMD node. -void Compiler::fgValueNumberSimd(GenTreeSIMD* tree) -{ - VNFunc simdFunc = GetVNFuncForNode(tree); - ValueNumPair excSetPair; - ValueNumPair normalPair; - - if ((tree->GetOperandCount() > 2) || ((JitConfig.JitDisableSimdVN() & 1) == 1)) - { - // We have a SIMD node with 3 or more args. To retain the - // previous behavior, we will generate a unique VN for this case. - excSetPair = ValueNumStore::VNPForEmptyExcSet(); - for (GenTree* operand : tree->Operands()) - { - excSetPair = vnStore->VNPUnionExcSet(operand->gtVNPair, excSetPair); - } - tree->gtVNPair = vnStore->VNPUniqueWithExc(tree->TypeGet(), excSetPair); - return; - } - - // There are some SIMD operations that have zero args, i.e. NI_Vector128_Zero - if (tree->GetOperandCount() == 0) - { - excSetPair = ValueNumStore::VNPForEmptyExcSet(); - normalPair = vnStore->VNPairForFunc(tree->TypeGet(), simdFunc); - } - else // SIMD unary or binary operator. - { - ValueNumPair resvnp = ValueNumPair(); - ValueNumPair op1vnp; - ValueNumPair op1Xvnp; - vnStore->VNPUnpackExc(tree->Op(1)->gtVNPair, &op1vnp, &op1Xvnp); - - ValueNum addrVN = ValueNumStore::NoVN; - - if (tree->GetOperandCount() == 1) - { - // A unary SIMD node. - excSetPair = op1Xvnp; - { - normalPair = vnStore->VNPairForFunc(tree->TypeGet(), simdFunc, op1vnp); - assert(vnStore->VNFuncArity(simdFunc) == 1); - } - } - else - { - ValueNumPair op2vnp; - ValueNumPair op2Xvnp; - vnStore->VNPUnpackExc(tree->Op(2)->gtVNPair, &op2vnp, &op2Xvnp); - - excSetPair = vnStore->VNPExcSetUnion(op1Xvnp, op2Xvnp); - { - normalPair = vnStore->VNPairForFunc(tree->TypeGet(), simdFunc, op1vnp, op2vnp); - assert(vnStore->VNFuncArity(simdFunc) == 2); - } - } - } - tree->gtVNPair = vnStore->VNPWithExc(normalPair, excSetPair); -} -#endif // FEATURE_SIMD - #ifdef FEATURE_HW_INTRINSICS void Compiler::fgValueNumberHWIntrinsic(GenTreeHWIntrinsic* tree) { diff --git a/src/coreclr/jit/valuenumfuncs.h b/src/coreclr/jit/valuenumfuncs.h index baaf1fc62a8f2..8dcb66c5f5669 100644 --- a/src/coreclr/jit/valuenumfuncs.h +++ b/src/coreclr/jit/valuenumfuncs.h @@ -168,11 +168,6 @@ ValueNumFuncDef(MUL_UN_OVF, 2, true, false, false) ValueNumFuncDef(SimdType, 2, false, false, false) // A value number function to compose a SIMD type #endif -#define SIMD_INTRINSIC(m, i, id, n, r, argCount, arg1, arg2, arg3, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10) \ -ValueNumFuncDef(SIMD_##id, argCount, false, false, false) // All of the SIMD intrinsic -#include "simdintrinsiclist.h" -#define VNF_SIMD_FIRST VNF_SIMD_None - #if defined(TARGET_XARCH) #define HARDWARE_INTRINSIC(isa, name, size, argCount, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, category, flag) \ ValueNumFuncDef(HWI_##isa##_##name, argCount, false, false, false) // All of the HARDWARE_INTRINSICS for x86/x64