diff options
38 files changed, 1196 insertions, 38 deletions
diff --git a/src/inc/corinfo.h b/src/inc/corinfo.h index dc3d22fa9f..ccd44a61ab 100644 --- a/src/inc/corinfo.h +++ b/src/inc/corinfo.h @@ -213,11 +213,11 @@ TODO: Talk about initializing strutures before use #define SELECTANY extern __declspec(selectany) #endif -SELECTANY const GUID JITEEVersionIdentifier = { /* 8f51c68e-d515-425c-9e04-97e4a8148b07 */ - 0x8f51c68e, - 0xd515, - 0x425c, - {0x9e, 0x04, 0x97, 0xe4, 0xa8, 0x14, 0x8b, 0x07} +SELECTANY const GUID JITEEVersionIdentifier = { /* 860df660-2919-440a-ad6d-865f014e5360 */ + 0x860df660, + 0x2919, + 0x440a, + { 0xad, 0x6d, 0x86, 0x5f, 0x01, 0x4e, 0x53, 0x60 } }; ////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -642,6 +642,7 @@ enum CorInfoHelpFunc CORINFO_HELP_THROW_ARGUMENTEXCEPTION, // throw ArgumentException CORINFO_HELP_THROW_ARGUMENTOUTOFRANGEEXCEPTION, // throw ArgumentOutOfRangeException + CORINFO_HELP_THROW_PLATFORM_NOT_SUPPORTED, // throw PlatformNotSupportedException CORINFO_HELP_JIT_PINVOKE_BEGIN, // Transition to preemptive mode before a P/Invoke, frame is the first argument CORINFO_HELP_JIT_PINVOKE_END, // Transition to cooperative mode after a P/Invoke, frame is the first argument diff --git a/src/inc/jithelpers.h b/src/inc/jithelpers.h index 43b75293ae..1419cda2de 100644 --- a/src/inc/jithelpers.h +++ b/src/inc/jithelpers.h @@ -344,8 +344,9 @@ JITHELPER(CORINFO_HELP_LOOP_CLONE_CHOICE_ADDR, JIT_LoopCloneChoiceAddr, CORINFO_HELP_SIG_REG_ONLY) JITHELPER(CORINFO_HELP_DEBUG_LOG_LOOP_CLONING, JIT_DebugLogLoopCloning, CORINFO_HELP_SIG_REG_ONLY) - JITHELPER(CORINFO_HELP_THROW_ARGUMENTEXCEPTION, JIT_ThrowArgumentException, CORINFO_HELP_SIG_REG_ONLY) - JITHELPER(CORINFO_HELP_THROW_ARGUMENTOUTOFRANGEEXCEPTION, JIT_ThrowArgumentOutOfRangeException, CORINFO_HELP_SIG_REG_ONLY) + JITHELPER(CORINFO_HELP_THROW_ARGUMENTEXCEPTION, JIT_ThrowArgumentException, CORINFO_HELP_SIG_REG_ONLY) + JITHELPER(CORINFO_HELP_THROW_ARGUMENTOUTOFRANGEEXCEPTION, JIT_ThrowArgumentOutOfRangeException, CORINFO_HELP_SIG_REG_ONLY) + JITHELPER(CORINFO_HELP_THROW_PLATFORM_NOT_SUPPORTED, JIT_ThrowPlatformNotSupportedException, CORINFO_HELP_SIG_REG_ONLY) JITHELPER(CORINFO_HELP_JIT_PINVOKE_BEGIN, NULL, CORINFO_HELP_SIG_UNDEF) JITHELPER(CORINFO_HELP_JIT_PINVOKE_END, NULL, CORINFO_HELP_SIG_UNDEF) diff --git a/src/jit/CMakeLists.txt b/src/jit/CMakeLists.txt index 5b92329a38..32c6065c52 100644 --- a/src/jit/CMakeLists.txt +++ b/src/jit/CMakeLists.txt @@ -6,6 +6,7 @@ include_directories("../inc") if (CLR_CMAKE_TARGET_ARCH_AMD64 OR (CLR_CMAKE_TARGET_ARCH_I386 AND NOT CLR_CMAKE_PLATFORM_UNIX)) add_definitions(-DFEATURE_SIMD) + add_definitions(-DFEATURE_HW_INTRINSICS) endif () # JIT_BUILD disables certain PAL_TRY debugging features @@ -100,6 +101,7 @@ set( JIT_AMD64_SOURCES targetamd64.cpp unwindamd64.cpp hwintrinsicxarch.cpp + hwintrinsiccodegenxarch.cpp ) set( JIT_ARM_SOURCES @@ -128,6 +130,7 @@ set( JIT_I386_SOURCES targetx86.cpp unwindx86.cpp hwintrinsicxarch.cpp + hwintrinsiccodegenxarch.cpp ) set( JIT_ARM64_SOURCES diff --git a/src/jit/armelnonjit/CMakeLists.txt b/src/jit/armelnonjit/CMakeLists.txt index 20a124a4b7..9ee4b8ffc0 100644 --- a/src/jit/armelnonjit/CMakeLists.txt +++ b/src/jit/armelnonjit/CMakeLists.txt @@ -6,6 +6,7 @@ add_definitions(-DSELF_NO_HOST) remove_definitions(-DFEATURE_MERGE_JIT_AND_ENGINE) remove_definitions(-DFEATURE_SIMD) +remove_definitions(-DFEATURE_HW_INTRINSICS) if(FEATURE_READYTORUN) add_definitions(-DFEATURE_READYTORUN_COMPILER) diff --git a/src/jit/codegenlinear.h b/src/jit/codegenlinear.h index 2cee11dcdb..571c5fe481 100644 --- a/src/jit/codegenlinear.h +++ b/src/jit/codegenlinear.h @@ -113,6 +113,25 @@ void genPutArgStkSIMD12(GenTree* treeNode); #endif // _TARGET_X86_ #endif // FEATURE_SIMD +#if FEATURE_HW_INTRINSICS +void genHWIntrinsic(GenTreeHWIntrinsic* node); +void genSSEIntrinsic(GenTreeHWIntrinsic* node); +void genSSE2Intrinsic(GenTreeHWIntrinsic* node); +void genSSE3Intrinsic(GenTreeHWIntrinsic* node); +void genSSSE3Intrinsic(GenTreeHWIntrinsic* node); +void genSSE41Intrinsic(GenTreeHWIntrinsic* node); +void genSSE42Intrinsic(GenTreeHWIntrinsic* node); +void genAVXIntrinsic(GenTreeHWIntrinsic* node); +void genAVX2Intrinsic(GenTreeHWIntrinsic* node); +void genAESIntrinsic(GenTreeHWIntrinsic* node); +void genBMI1Intrinsic(GenTreeHWIntrinsic* node); +void genBMI2Intrinsic(GenTreeHWIntrinsic* node); +void genFMAIntrinsic(GenTreeHWIntrinsic* node); +void genLZCNTIntrinsic(GenTreeHWIntrinsic* node); +void genPCLMULQDQIntrinsic(GenTreeHWIntrinsic* node); +void genPOPCNTIntrinsic(GenTreeHWIntrinsic* node); +#endif // FEATURE_HW_INTRINSICS + #if !defined(_TARGET_64BIT_) // CodeGen for Long Ints diff --git a/src/jit/codegenxarch.cpp b/src/jit/codegenxarch.cpp index 529dafced1..aef6033ea9 100644 --- a/src/jit/codegenxarch.cpp +++ b/src/jit/codegenxarch.cpp @@ -1869,6 +1869,12 @@ void CodeGen::genCodeForTreeNode(GenTreePtr treeNode) break; #endif // FEATURE_SIMD +#if FEATURE_HW_INTRINSICS + case GT_HWIntrinsic: + genHWIntrinsic(treeNode->AsHWIntrinsic()); + break; +#endif // FEATURE_HW_INTRINSICS + case GT_CKFINITE: genCkfinite(treeNode); break; diff --git a/src/jit/compiler.h b/src/jit/compiler.h index d05b894c58..1e85a7b012 100644 --- a/src/jit/compiler.h +++ b/src/jit/compiler.h @@ -2081,6 +2081,19 @@ public: void SetOpLclRelatedToSIMDIntrinsic(GenTreePtr op); #endif +#if FEATURE_HW_INTRINSICS + GenTreeHWIntrinsic* gtNewSimdHWIntrinsicNode( + var_types type, GenTree* op1, NamedIntrinsic hwIntrinsicID, var_types baseType, unsigned size); + GenTreeHWIntrinsic* gtNewSimdHWIntrinsicNode( + var_types type, GenTree* op1, GenTree* op2, NamedIntrinsic hwIntrinsicID, var_types baseType, unsigned size); + GenTreeHWIntrinsic* gtNewScalarHWIntrinsicNode(var_types type, GenTree* op1, NamedIntrinsic hwIntrinsicID); + GenTreeHWIntrinsic* gtNewScalarHWIntrinsicNode(var_types type, + GenTree* op1, + GenTree* op2, + NamedIntrinsic hwIntrinsicID); + GenTree* gtNewMustThrowException(unsigned helper, var_types type); +#endif // FEATURE_HW_INTRINSICS + GenTreePtr gtNewLclLNode(unsigned lnum, var_types type, IL_OFFSETX ILoffs = BAD_IL_OFFSET); GenTreeLclFld* gtNewLclFldNode(unsigned lnum, var_types type, unsigned offset); GenTreePtr gtNewInlineCandidateReturnExpr(GenTreePtr inlineCandidate, var_types type); @@ -3030,7 +3043,7 @@ protected: bool tailCall); NamedIntrinsic lookupNamedIntrinsic(CORINFO_METHOD_HANDLE method); -#ifdef _TARGET_XARCH_ +#if FEATURE_HW_INTRINSICS InstructionSet lookupHWIntrinsicISA(const char* className); NamedIntrinsic lookupHWIntrinsic(const char* methodName, InstructionSet isa); InstructionSet isaOfHWIntrinsic(NamedIntrinsic intrinsic); @@ -3050,7 +3063,7 @@ protected: GenTree* impLZCNTIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig); GenTree* impPCLMULQDQIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig); GenTree* impPOPCNTIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig); -#endif +#endif // FEATURE_HW_INTRINSICS GenTreePtr impArrayAccessIntrinsic(CORINFO_CLASS_HANDLE clsHnd, CORINFO_SIG_INFO* sig, int memberRef, diff --git a/src/jit/emitxarch.cpp b/src/jit/emitxarch.cpp index 09fdb1bd08..de0b4a5b68 100644 --- a/src/jit/emitxarch.cpp +++ b/src/jit/emitxarch.cpp @@ -7076,6 +7076,12 @@ void emitter::emitDispIns( // INS_bt operands are reversed. Display them in the normal order. printf("%s, %s", emitRegName(id->idReg2(), attr), emitRegName(id->idReg1(), attr)); } +#if FEATURE_HW_INTRINSICS + else if (ins == INS_crc32 && attr != EA_8BYTE) + { + printf("%s, %s", emitRegName(id->idReg1(), EA_4BYTE), emitRegName(id->idReg2(), attr)); + } +#endif // FEATURE_HW_INTRINSICS else { printf("%s, %s", emitRegName(id->idReg1(), attr), emitRegName(id->idReg2(), attr)); @@ -9185,6 +9191,26 @@ BYTE* emitter::emitOutputRR(BYTE* dst, instrDesc* id) #endif // _TARGET_AMD64_ } +#if FEATURE_HW_INTRINSICS + else if ((ins == INS_crc32) || (ins == INS_lzcnt) || (ins == INS_popcnt)) + { + code = insEncodeRMreg(ins, code); + if ((ins == INS_crc32) && (size > EA_1BYTE)) + { + code |= 0x0100; + } + + if (size == EA_2BYTE) + { + assert(ins == INS_crc32); + dst += emitOutputByte(dst, 0x66); + } + else if (size == EA_8BYTE) + { + code = AddRexWPrefix(ins, code); + } + } +#endif // FEATURE_HW_INTRINSICS else { code = insEncodeMRreg(ins, insCodeMR(ins)); diff --git a/src/jit/flowgraph.cpp b/src/jit/flowgraph.cpp index e5247ae53d..58b461c519 100644 --- a/src/jit/flowgraph.cpp +++ b/src/jit/flowgraph.cpp @@ -6827,7 +6827,8 @@ bool Compiler::fgIsThrow(GenTreePtr tree) (tree->gtCall.gtCallMethHnd == eeFindHelper(CORINFO_HELP_THROWDIVZERO)) || (tree->gtCall.gtCallMethHnd == eeFindHelper(CORINFO_HELP_THROWNULLREF)) || (tree->gtCall.gtCallMethHnd == eeFindHelper(CORINFO_HELP_THROW)) || - (tree->gtCall.gtCallMethHnd == eeFindHelper(CORINFO_HELP_RETHROW))) + (tree->gtCall.gtCallMethHnd == eeFindHelper(CORINFO_HELP_RETHROW)) || + (tree->gtCall.gtCallMethHnd == eeFindHelper(CORINFO_HELP_THROW_PLATFORM_NOT_SUPPORTED))) { noway_assert(tree->gtFlags & GTF_CALL); noway_assert(tree->gtFlags & GTF_EXCEPT); diff --git a/src/jit/gentree.cpp b/src/jit/gentree.cpp index c199a29772..8ca9cda030 100644 --- a/src/jit/gentree.cpp +++ b/src/jit/gentree.cpp @@ -2024,6 +2024,13 @@ AGAIN: break; #endif // FEATURE_SIMD +#if FEATURE_HW_INTRINSICS + case GT_HWIntrinsic: + hash += tree->gtHWIntrinsic.gtHWIntrinsicId; + hash += tree->gtHWIntrinsic.gtSIMDBaseType; + break; +#endif // FEATURE_HW_INTRINSICS + default: assert(!"unexpected binary ExOp operator"); } @@ -10982,6 +10989,10 @@ extern const char* const simdIntrinsicNames[] = { }; #endif // FEATURE_SIMD +#if FEATURE_HW_INTRINSICS +extern const char* getHWIntrinsicName(NamedIntrinsic intrinsic); +#endif // FEATURE_HW_INTRINSICS + /*****************************************************************************/ void Compiler::gtDispTree(GenTreePtr tree, @@ -11304,6 +11315,16 @@ void Compiler::gtDispTree(GenTreePtr tree, } #endif // FEATURE_SIMD +#if FEATURE_HW_INTRINSICS + if (tree->gtOper == GT_HWIntrinsic) + { + printf(" %s %s", + tree->gtHWIntrinsic.gtSIMDBaseType == TYP_UNKNOWN ? "" + : varTypeName(tree->gtHWIntrinsic.gtSIMDBaseType), + getHWIntrinsicName(tree->gtHWIntrinsic.gtHWIntrinsicId)); + } +#endif // FEATURE_HW_INTRINSICS + gtDispRegVal(tree); gtDispVN(tree); printf("\n"); @@ -17538,6 +17559,59 @@ bool GenTree::isCommutativeSIMDIntrinsic() } #endif // FEATURE_SIMD +#if FEATURE_HW_INTRINSICS +GenTreeHWIntrinsic* Compiler::gtNewSimdHWIntrinsicNode( + var_types type, GenTree* op1, NamedIntrinsic hwIntrinsicID, var_types baseType, unsigned size) +{ + return new (this, GT_HWIntrinsic) GenTreeHWIntrinsic(type, op1, hwIntrinsicID, baseType, size); +} + +GenTreeHWIntrinsic* Compiler::gtNewSimdHWIntrinsicNode( + var_types type, GenTree* op1, GenTree* op2, NamedIntrinsic hwIntrinsicID, var_types baseType, unsigned size) +{ + return new (this, GT_HWIntrinsic) GenTreeHWIntrinsic(type, op1, op2, hwIntrinsicID, baseType, size); +} + +GenTreeHWIntrinsic* Compiler::gtNewScalarHWIntrinsicNode(var_types type, GenTree* op1, NamedIntrinsic hwIntrinsicID) +{ + return new (this, GT_HWIntrinsic) GenTreeHWIntrinsic(type, op1, hwIntrinsicID, TYP_UNKNOWN, 0); +} + +GenTreeHWIntrinsic* Compiler::gtNewScalarHWIntrinsicNode(var_types type, + GenTree* op1, + GenTree* op2, + NamedIntrinsic hwIntrinsicID) +{ + return new (this, GT_HWIntrinsic) GenTreeHWIntrinsic(type, op1, op2, hwIntrinsicID, TYP_UNKNOWN, 0); +} + +//--------------------------------------------------------------------------------------- +// gtNewMustThrowException: +// create a throw node (calling into JIT helper) that must be thrown. +// The result would be a comma node: COMMA(jithelperthrow(void), x) where x's type should be specified. +// +// Arguments +// helper - JIT helper ID +// type - return type of the node +// +// Return Value +// pointer to the throw node +// +GenTree* Compiler::gtNewMustThrowException(unsigned helper, var_types type) +{ + GenTreeCall* node = gtNewHelperCallNode(helper, TYP_VOID); + node->gtCallMoreFlags |= GTF_CALL_M_DOES_NOT_RETURN; + if (type != TYP_VOID) + { + unsigned dummyTemp = lvaGrabTemp(true DEBUGARG("dummy temp of must thrown exception")); + lvaTable[dummyTemp].lvType = type; + GenTree* dummyNode = gtNewLclvNode(dummyTemp, type); + return gtNewOperNode(GT_COMMA, type, node, dummyNode); + } + return node; +} +#endif // FEATURE_HW_INTRINSICS + //--------------------------------------------------------------------------------------- // InitializeStructReturnType: // Initialize the Return Type Descriptor for a method that returns a struct type diff --git a/src/jit/gentree.h b/src/jit/gentree.h index 6c915ce429..c8117c5dba 100644 --- a/src/jit/gentree.h +++ b/src/jit/gentree.h @@ -27,6 +27,7 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX #include "simplerhash.h" #include "nodeinfo.h" #include "simd.h" +#include "namedintrinsiclist.h" // Debugging GenTree is much easier if we add a magic virtual function to make the debugger able to figure out what type // it's got. This is enabled by default in DEBUG. To enable it in RET builds (temporarily!), you need to change the @@ -1713,6 +1714,11 @@ public: #ifdef FEATURE_SIMD case GT_SIMD: #endif // !FEATURE_SIMD + +#if FEATURE_HW_INTRINSICS + case GT_HWIntrinsic: +#endif // FEATURE_HW_INTRINSICS + #if !defined(LEGACY_BACKEND) && defined(_TARGET_ARM_) case GT_PUTARG_REG: #endif // !defined(LEGACY_BACKEND) && defined(_TARGET_ARM_) @@ -4196,20 +4202,38 @@ struct GenTreeIntrinsic : public GenTreeOp #endif }; +struct GenTreeJitIntrinsic : public GenTreeOp +{ + var_types gtSIMDBaseType; // SIMD vector base type + unsigned gtSIMDSize; // SIMD vector size in bytes, use 0 for scalar intrinsics + + GenTreeJitIntrinsic( + genTreeOps oper, var_types type, GenTreePtr op1, GenTreePtr op2, var_types baseType, unsigned size) + : GenTreeOp(oper, type, op1, op2), gtSIMDBaseType(baseType), gtSIMDSize(size) + { + } + + bool isSIMD() + { + return gtSIMDSize != 0; + } + +#if DEBUGGABLE_GENTREE + GenTreeJitIntrinsic() : GenTreeOp() + { + } +#endif +}; + #ifdef FEATURE_SIMD /* gtSIMD -- SIMD intrinsic (possibly-binary op [NULL op2 is allowed] with additional fields) */ -struct GenTreeSIMD : public GenTreeOp +struct GenTreeSIMD : public GenTreeJitIntrinsic { SIMDIntrinsicID gtSIMDIntrinsicID; // operation Id - var_types gtSIMDBaseType; // SIMD vector base type - unsigned gtSIMDSize; // SIMD vector size in bytes GenTreeSIMD(var_types type, GenTreePtr op1, SIMDIntrinsicID simdIntrinsicID, var_types baseType, unsigned size) - : GenTreeOp(GT_SIMD, type, op1, nullptr) - , gtSIMDIntrinsicID(simdIntrinsicID) - , gtSIMDBaseType(baseType) - , gtSIMDSize(size) + : GenTreeJitIntrinsic(GT_SIMD, type, op1, nullptr, baseType, size), gtSIMDIntrinsicID(simdIntrinsicID) { } @@ -4219,21 +4243,42 @@ struct GenTreeSIMD : public GenTreeOp SIMDIntrinsicID simdIntrinsicID, var_types baseType, unsigned size) - : GenTreeOp(GT_SIMD, type, op1, op2) - , gtSIMDIntrinsicID(simdIntrinsicID) - , gtSIMDBaseType(baseType) - , gtSIMDSize(size) + : GenTreeJitIntrinsic(GT_SIMD, type, op1, op2, baseType, size), gtSIMDIntrinsicID(simdIntrinsicID) { } #if DEBUGGABLE_GENTREE - GenTreeSIMD() : GenTreeOp() + GenTreeSIMD() : GenTreeJitIntrinsic() { } #endif }; #endif // FEATURE_SIMD +#if FEATURE_HW_INTRINSICS +struct GenTreeHWIntrinsic : public GenTreeJitIntrinsic +{ + NamedIntrinsic gtHWIntrinsicId; + + GenTreeHWIntrinsic(var_types type, GenTree* op1, NamedIntrinsic hwIntrinsicID, var_types baseType, unsigned size) + : GenTreeJitIntrinsic(GT_HWIntrinsic, type, op1, nullptr, baseType, size), gtHWIntrinsicId(hwIntrinsicID) + { + } + + GenTreeHWIntrinsic( + var_types type, GenTree* op1, GenTree* op2, NamedIntrinsic hwIntrinsicID, var_types baseType, unsigned size) + : GenTreeJitIntrinsic(GT_HWIntrinsic, type, op1, op2, baseType, size), gtHWIntrinsicId(hwIntrinsicID) + { + } + +#if DEBUGGABLE_GENTREE + GenTreeHWIntrinsic() : GenTreeJitIntrinsic() + { + } +#endif +}; +#endif // FEATURE_HW_INTRINSICS + /* gtIndex -- array access */ struct GenTreeIndex : public GenTreeOp diff --git a/src/jit/gtlist.h b/src/jit/gtlist.h index e731b32620..e249a75de7 100644 --- a/src/jit/gtlist.h +++ b/src/jit/gtlist.h @@ -224,6 +224,10 @@ GTNODE(RSH_LO , GenTreeOp ,0,GTK_BINOP) GTNODE(SIMD , GenTreeSIMD ,0,GTK_BINOP|GTK_EXOP) // SIMD functions/operators/intrinsics #endif // FEATURE_SIMD +#if FEATURE_HW_INTRINSICS +GTNODE(HWIntrinsic , GenTreeHWIntrinsic ,0,GTK_BINOP|GTK_EXOP) // hardware intrinsics +#endif // FEATURE_HW_INTRINSICS + //----------------------------------------------------------------------------- // LIR specific compare and conditional branch/set nodes: //----------------------------------------------------------------------------- diff --git a/src/jit/gtstructs.h b/src/jit/gtstructs.h index ab0ae43027..1277ac5b0d 100644 --- a/src/jit/gtstructs.h +++ b/src/jit/gtstructs.h @@ -104,6 +104,9 @@ GTSTRUCT_1(PhysReg , GT_PHYSREG) #ifdef FEATURE_SIMD GTSTRUCT_1(SIMD , GT_SIMD) #endif // FEATURE_SIMD +#if FEATURE_HW_INTRINSICS +GTSTRUCT_1(HWIntrinsic , GT_HWIntrinsic) +#endif // FEATURE_HW_INTRINSICS GTSTRUCT_1(AllocObj , GT_ALLOCOBJ) GTSTRUCT_1(RuntimeLookup, GT_RUNTIMELOOKUP) GTSTRUCT_2(CC , GT_JCC, GT_SETCC) diff --git a/src/jit/hwintrinsiccodegenxarch.cpp b/src/jit/hwintrinsiccodegenxarch.cpp new file mode 100644 index 0000000000..763647e7bf --- /dev/null +++ b/src/jit/hwintrinsiccodegenxarch.cpp @@ -0,0 +1,220 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +XX XX +XX Intel hardware intrinsic Code Generator XX +XX XX +XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +*/ +#include "jitpch.h" +#ifdef _MSC_VER +#pragma hdrstop +#endif + +#if FEATURE_HW_INTRINSICS + +#include "emit.h" +#include "codegen.h" +#include "sideeffects.h" +#include "lower.h" +#include "gcinfo.h" +#include "gcinfoencoder.h" + +void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node) +{ + NamedIntrinsic intrinsicID = node->gtHWIntrinsicId; + InstructionSet isa = compiler->isaOfHWIntrinsic(intrinsicID); + switch (isa) + { + case InstructionSet_SSE: + genSSEIntrinsic(node); + break; + case InstructionSet_SSE2: + genSSE2Intrinsic(node); + break; + case InstructionSet_SSE3: + genSSE3Intrinsic(node); + break; + case InstructionSet_SSSE3: + genSSSE3Intrinsic(node); + break; + case InstructionSet_SSE41: + genSSE41Intrinsic(node); + break; + case InstructionSet_SSE42: + genSSE42Intrinsic(node); + break; + case InstructionSet_AVX: + genAVXIntrinsic(node); + break; + case InstructionSet_AVX2: + genAVX2Intrinsic(node); + break; + case InstructionSet_AES: + genAESIntrinsic(node); + break; + case InstructionSet_BMI1: + genBMI1Intrinsic(node); + break; + case InstructionSet_BMI2: + genBMI2Intrinsic(node); + break; + case InstructionSet_FMA: + genFMAIntrinsic(node); + break; + case InstructionSet_LZCNT: + genLZCNTIntrinsic(node); + break; + case InstructionSet_PCLMULQDQ: + genPCLMULQDQIntrinsic(node); + break; + case InstructionSet_POPCNT: + genPOPCNTIntrinsic(node); + break; + default: + unreached(); + break; + } +} + +void CodeGen::genSSEIntrinsic(GenTreeHWIntrinsic* node) +{ + NYI("Implement SSE intrinsic code generation"); +} + +void CodeGen::genSSE2Intrinsic(GenTreeHWIntrinsic* node) +{ + NYI("Implement SSE2 intrinsic code generation"); +} + +void CodeGen::genSSE3Intrinsic(GenTreeHWIntrinsic* node) +{ + NYI("Implement SSE3 intrinsic code generation"); +} + +void CodeGen::genSSSE3Intrinsic(GenTreeHWIntrinsic* node) +{ + NYI("Implement SSSE3 intrinsic code generation"); +} + +void CodeGen::genSSE41Intrinsic(GenTreeHWIntrinsic* node) +{ + NYI("Implement SSE41 intrinsic code generation"); +} + +void CodeGen::genSSE42Intrinsic(GenTreeHWIntrinsic* node) +{ + NamedIntrinsic intrinsicID = node->gtHWIntrinsicId; + GenTree* op1 = node->gtGetOp1(); + GenTree* op2 = node->gtGetOp2(); + regNumber targetReg = node->gtRegNum; + assert(targetReg != REG_NA); + var_types targetType = node->TypeGet(); + var_types baseType = node->gtSIMDBaseType; + + regNumber op1Reg = op1->gtRegNum; + regNumber op2Reg = op2->gtRegNum; + genConsumeOperands(node); + + switch (intrinsicID) + { + case NI_SSE42_Crc32: + if (op1Reg != targetReg) + { + inst_RV_RV(INS_mov, targetReg, op1Reg, targetType, emitTypeSize(targetType)); + } + + if (baseType == TYP_UBYTE || baseType == TYP_CHAR) // baseType is the type of the second argument + { + assert(targetType == TYP_INT); + inst_RV_RV(INS_crc32, targetReg, op2Reg, baseType, emitTypeSize(baseType)); + } + else + { + assert(op1->TypeGet() == op2->TypeGet()); + assert(targetType == TYP_INT || targetType == TYP_LONG); + inst_RV_RV(INS_crc32, targetReg, op2Reg, targetType, emitTypeSize(targetType)); + } + + break; + default: + unreached(); + break; + } + genProduceReg(node); +} + +void CodeGen::genAVXIntrinsic(GenTreeHWIntrinsic* node) +{ + NYI("Implement AVX intrinsic code generation"); +} + +void CodeGen::genAVX2Intrinsic(GenTreeHWIntrinsic* node) +{ + NYI("Implement AVX2 intrinsic code generation"); +} + +void CodeGen::genAESIntrinsic(GenTreeHWIntrinsic* node) +{ + NYI("Implement AES intrinsic code generation"); +} + +void CodeGen::genBMI1Intrinsic(GenTreeHWIntrinsic* node) +{ + NYI("Implement BMI1 intrinsic code generation"); +} + +void CodeGen::genBMI2Intrinsic(GenTreeHWIntrinsic* node) +{ + NYI("Implement BMI2 intrinsic code generation"); +} + +void CodeGen::genFMAIntrinsic(GenTreeHWIntrinsic* node) +{ + NYI("Implement FMA intrinsic code generation"); +} + +void CodeGen::genLZCNTIntrinsic(GenTreeHWIntrinsic* node) +{ + NamedIntrinsic intrinsicID = node->gtHWIntrinsicId; + GenTree* op1 = node->gtGetOp1(); + regNumber targetReg = node->gtRegNum; + assert(targetReg != REG_NA); + var_types targetType = node->TypeGet(); + regNumber op1Reg = op1->gtRegNum; + genConsumeOperands(node); + + assert(intrinsicID == NI_LZCNT_LeadingZeroCount); + + inst_RV_RV(INS_lzcnt, targetReg, op1Reg, targetType, emitTypeSize(targetType)); + + genProduceReg(node); +} + +void CodeGen::genPCLMULQDQIntrinsic(GenTreeHWIntrinsic* node) +{ + NYI("Implement PCLMULQDQ intrinsic code generation"); +} + +void CodeGen::genPOPCNTIntrinsic(GenTreeHWIntrinsic* node) +{ + NamedIntrinsic intrinsicID = node->gtHWIntrinsicId; + GenTree* op1 = node->gtGetOp1(); + regNumber targetReg = node->gtRegNum; + assert(targetReg != REG_NA); + var_types targetType = node->TypeGet(); + regNumber op1Reg = op1->gtRegNum; + genConsumeOperands(node); + + assert(intrinsicID == NI_POPCNT_PopCount); + + inst_RV_RV(INS_popcnt, targetReg, op1Reg, targetType, emitTypeSize(targetType)); + + genProduceReg(node); +} + +#endif // FEATURE_HW_INTRINSICS diff --git a/src/jit/hwintrinsiclistxarch.h b/src/jit/hwintrinsiclistxarch.h index d066d10289..7db3e5c78f 100644 --- a/src/jit/hwintrinsiclistxarch.h +++ b/src/jit/hwintrinsiclistxarch.h @@ -10,7 +10,7 @@ // clang-format off -#ifdef _TARGET_XARCH_ +#if FEATURE_HW_INTRINSICS // Intrinsic ID Function name ISA // SSE Intrinsics HARDWARE_INTRINSIC(SSE_IsSupported, "get_IsSupported", SSE) @@ -29,6 +29,7 @@ HARDWARE_INTRINSIC(SSE41_IsSupported, "get_IsSupported", // SSE42 Intrinsics HARDWARE_INTRINSIC(SSE42_IsSupported, "get_IsSupported", SSE42) +HARDWARE_INTRINSIC(SSE42_Crc32, "Crc32", SSE42) // AVX Intrinsics HARDWARE_INTRINSIC(AVX_IsSupported, "get_IsSupported", AVX) @@ -50,13 +51,15 @@ HARDWARE_INTRINSIC(FMA_IsSupported, "get_IsSupported", // LZCNT Intrinsics HARDWARE_INTRINSIC(LZCNT_IsSupported, "get_IsSupported", LZCNT) +HARDWARE_INTRINSIC(LZCNT_LeadingZeroCount, "LeadingZeroCount", LZCNT) // PCLMULQDQ Intrinsics HARDWARE_INTRINSIC(PCLMULQDQ_IsSupported, "get_IsSupported", PCLMULQDQ) // POPCNT Intrinsics HARDWARE_INTRINSIC(POPCNT_IsSupported, "get_IsSupported", POPCNT) -#endif +HARDWARE_INTRINSIC(POPCNT_PopCount, "PopCount", POPCNT) +#endif // FEATURE_HW_INTRINSICS #undef HARDWARE_INTRINSIC diff --git a/src/jit/hwintrinsicxarch.cpp b/src/jit/hwintrinsicxarch.cpp index 45ee468174..d27e784fe5 100644 --- a/src/jit/hwintrinsicxarch.cpp +++ b/src/jit/hwintrinsicxarch.cpp @@ -4,7 +4,7 @@ #include "jitpch.h" -#ifdef _TARGET_XARCH_ +#if FEATURE_HW_INTRINSICS struct HWIntrinsicInfo { @@ -18,6 +18,11 @@ static const hwIntrinsicInfoArray[] = { #include "hwintrinsiclistxarch.h" }; +extern const char* getHWIntrinsicName(NamedIntrinsic intrinsic) +{ + return hwIntrinsicInfoArray[intrinsic - NI_HW_INTRINSIC_START - 1].intrinsicName; +} + //------------------------------------------------------------------------ // lookupHWIntrinsicISA: map class name to InstructionSet value // @@ -162,6 +167,14 @@ InstructionSet Compiler::isaOfHWIntrinsic(NamedIntrinsic intrinsic) GenTree* Compiler::impX86HWIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig) { InstructionSet isa = isaOfHWIntrinsic(intrinsic); + if (!compSupports(isa) && strcmp("get_IsSupported", getHWIntrinsicName(intrinsic)) != 0) + { + for (unsigned i = 0; i < sig->numArgs; i++) + { + impPopStack(); + } + return gtNewMustThrowException(CORINFO_HELP_THROW_PLATFORM_NOT_SUPPORTED, JITtype2varType(sig->retType)); + } switch (isa) { case InstructionSet_SSE: @@ -262,14 +275,45 @@ GenTree* Compiler::impSSE41Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HA GenTree* Compiler::impSSE42Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig) { + GenTree* retNode = nullptr; + GenTree* op1 = nullptr; + GenTree* op2 = nullptr; + var_types callType = JITtype2varType(sig->retType); + + CORINFO_ARG_LIST_HANDLE argLst = sig->args; + CORINFO_CLASS_HANDLE argClass; + CorInfoType corType; switch (intrinsic) { case NI_SSE42_IsSupported: - return gtNewIconNode(compSupports(InstructionSet_SSE42)); + retNode = gtNewIconNode(compSupports(InstructionSet_SSE42)); + break; + + case NI_SSE42_Crc32: + assert(sig->numArgs == 2); + op2 = impPopStack().val; + op1 = impPopStack().val; +#ifdef _TARGET_X86_ + if (varTypeIsLong(callType)) + { + return gtNewMustThrowException(CORINFO_HELP_THROW_PLATFORM_NOT_SUPPORTED, callType); + } +#endif + argLst = info.compCompHnd->getArgNext(argLst); // the second argument + corType = strip(info.compCompHnd->getArgType(sig, argLst, &argClass)); // type of the secnod argument + + retNode = gtNewScalarHWIntrinsicNode(callType, op1, op2, NI_SSE42_Crc32); + + // TODO - currently we use the BaseType to bring the type of the secnod argument + // to the code generator. May encode the overload info in other way. + retNode->gtHWIntrinsic.gtSIMDBaseType = JITtype2varType(corType); + break; default: - return nullptr; + JITDUMP("Not implemented hardware intrinsic"); + break; } + return retNode; } GenTree* Compiler::impAVXIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig) @@ -346,14 +390,33 @@ GenTree* Compiler::impFMAIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HAND GenTree* Compiler::impLZCNTIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig) { + GenTree* retNode = nullptr; + GenTree* op1 = nullptr; + var_types callType = JITtype2varType(sig->retType); + switch (intrinsic) { case NI_LZCNT_IsSupported: - return gtNewIconNode(compSupports(InstructionSet_LZCNT)); + retNode = gtNewIconNode(compSupports(InstructionSet_LZCNT)); + break; + + case NI_LZCNT_LeadingZeroCount: + assert(sig->numArgs == 1); + op1 = impPopStack().val; +#ifdef _TARGET_X86_ + if (varTypeIsLong(callType)) + { + return gtNewMustThrowException(CORINFO_HELP_THROW_PLATFORM_NOT_SUPPORTED, callType); + } +#endif + retNode = gtNewScalarHWIntrinsicNode(callType, op1, NI_LZCNT_LeadingZeroCount); + break; default: - return nullptr; + JITDUMP("Not implemented hardware intrinsic"); + break; } + return retNode; } GenTree* Compiler::impPCLMULQDQIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig) @@ -370,14 +433,33 @@ GenTree* Compiler::impPCLMULQDQIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHO GenTree* Compiler::impPOPCNTIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig) { + GenTree* retNode = nullptr; + GenTree* op1 = nullptr; + var_types callType = JITtype2varType(sig->retType); + switch (intrinsic) { case NI_POPCNT_IsSupported: - return gtNewIconNode(compSupports(InstructionSet_POPCNT)); + retNode = gtNewIconNode(compSupports(InstructionSet_POPCNT)); + break; + + case NI_POPCNT_PopCount: + assert(sig->numArgs == 1); + op1 = impPopStack().val; +#ifdef _TARGET_X86_ + if (varTypeIsLong(callType)) + { + return gtNewMustThrowException(CORINFO_HELP_THROW_PLATFORM_NOT_SUPPORTED, callType); + } +#endif + retNode = gtNewScalarHWIntrinsicNode(callType, op1, NI_POPCNT_PopCount); + break; default: - return nullptr; + JITDUMP("Not implemented hardware intrinsic"); + break; } + return retNode; } -#endif // _TARGET_XARCH_
\ No newline at end of file +#endif // FEATURE_HW_INTRINSICS diff --git a/src/jit/importer.cpp b/src/jit/importer.cpp index 6429978a10..06661c0576 100644 --- a/src/jit/importer.cpp +++ b/src/jit/importer.cpp @@ -3853,12 +3853,12 @@ GenTree* Compiler::impIntrinsic(GenTree* newobjThis, { assert(retNode == nullptr); const NamedIntrinsic ni = lookupNamedIntrinsic(method); -#if defined(_TARGET_XARCH_) && !defined(LEGACY_BACKEND) +#if FEATURE_HW_INTRINSICS if (ni > NI_HW_INTRINSIC_START && ni < NI_HW_INTRINSIC_END) { - retNode = impX86HWIntrinsic(ni, method, sig); + return impX86HWIntrinsic(ni, method, sig); } -#endif +#endif // FEATURE_HW_INTRINSICS switch (ni) { case NI_System_Enum_HasFlag: @@ -4081,13 +4081,13 @@ NamedIntrinsic Compiler::lookupNamedIntrinsic(CORINFO_METHOD_HANDLE method) } } -#if defined(_TARGET_XARCH_) && !defined(LEGACY_BACKEND) +#if FEATURE_HW_INTRINSICS if ((namespaceName != nullptr) && strcmp(namespaceName, "System.Runtime.Intrinsics.X86") == 0) { InstructionSet isa = lookupHWIntrinsicISA(className); result = lookupHWIntrinsic(methodName, isa); } -#endif +#endif // FEATURE_HW_INTRINSICS return result; } diff --git a/src/jit/instrsxarch.h b/src/jit/instrsxarch.h index 225539ae39..8d6dd6a3e8 100644 --- a/src/jit/instrsxarch.h +++ b/src/jit/instrsxarch.h @@ -382,6 +382,15 @@ INST3( vzeroupper, "zeroupper" , 0, IUM_WR, 0, 0, 0xC577F8, BAD_CODE, BA INST3( vperm2i128, "perm2i128" , 0, IUM_WR, 0, 0, BAD_CODE, BAD_CODE, SSE3A(0x46)) // Permute 128-bit halves of input register INST3( vpermq, "permq" , 0, IUM_WR, 0, 0, BAD_CODE, BAD_CODE, SSE3A(0x00)) // Permute 64-bit of input register INST3(LAST_AVX_INSTRUCTION, "LAST_AVX_INSTRUCTION", 0, IUM_WR, 0, 0, BAD_CODE, BAD_CODE, BAD_CODE) + +// Scalar instructions in SSE4.2 +INST3( crc32, "crc32" , 0, IUM_WR, 0, 0, BAD_CODE, BAD_CODE, PACK4(0xF2, 0x0F, 0x38, 0xF0)) + +// LZCNT +INST3( lzcnt, "lzcnt" , 0, IUM_WR, 0, 0, BAD_CODE, BAD_CODE, SSEFLT(0xBD)) + +// POPCNT +INST3( popcnt, "popcnt" , 0, IUM_WR, 0, 0, BAD_CODE, BAD_CODE, SSEFLT(0xB8)) #endif // !LEGACY_BACKEND // enum name FP updmode rf wf R/M,R/M[reg] R/M,icon diff --git a/src/jit/jit.settings.targets b/src/jit/jit.settings.targets index ee1df74c62..2d2cc71c2f 100644 --- a/src/jit/jit.settings.targets +++ b/src/jit/jit.settings.targets @@ -104,6 +104,7 @@ <CppCompile Condition="'$(ClDefines.Contains(`LEGACY_BACKEND`))'=='False'" Include="..\SIMD.cpp" /> <CppCompile Condition="'$(ClDefines.Contains(`LEGACY_BACKEND`))'=='False'" Include="..\SIMDCodeGenXArch.cpp" /> <CppCompile Condition="'$(ClDefines.Contains(`LEGACY_BACKEND`))'=='False'" Include="..\hwintrinsicxarch.cpp" /> + <CppCompile Condition="'$(ClDefines.Contains(`LEGACY_BACKEND`))'=='False'" Include="..\hwintrinsiccodegenxarch.cpp" /> </ItemGroup> <ItemGroup Condition="'$(TargetArch)'=='amd64'"> <!-- AMD64 target is always RyuJIT backend --> @@ -116,6 +117,7 @@ <CppCompile Include="..\SIMDCodeGenXArch.cpp" /> <CppCompile Include="..\unwindAmd64.cpp" /> <CppCompile Include="..\hwintrinsicxarch.cpp" /> + <CppCompile Include="..\hwintrinsiccodegenxarch.cpp" /> </ItemGroup> <ItemGroup Condition="'$(TargetArch)'=='arm'"> <CppCompile Include="..\emitarm.cpp" /> diff --git a/src/jit/legacyjit/CMakeLists.txt b/src/jit/legacyjit/CMakeLists.txt index 6aa95f4ca1..4a14d0f15b 100644 --- a/src/jit/legacyjit/CMakeLists.txt +++ b/src/jit/legacyjit/CMakeLists.txt @@ -10,6 +10,9 @@ remove_definitions(-DFEATURE_MERGE_JIT_AND_ENGINE) # No SIMD in legacy back-end. remove_definitions(-DFEATURE_SIMD) +# No hardware intrinsic in legacy back-end. +remove_definitions(-DFEATURE_HW_INTRINSICS) + if(WIN32) add_definitions(-DFX_VER_INTERNALNAME_STR=legacyjit.dll) endif(WIN32) diff --git a/src/jit/legacynonjit/CMakeLists.txt b/src/jit/legacynonjit/CMakeLists.txt index 4b7ef21235..b36800d329 100644 --- a/src/jit/legacynonjit/CMakeLists.txt +++ b/src/jit/legacynonjit/CMakeLists.txt @@ -7,6 +7,8 @@ remove_definitions(-DFEATURE_MERGE_JIT_AND_ENGINE) remove_definitions(-DFEATURE_SIMD) +remove_definitions(-DFEATURE_HW_INTRINSICS) + add_definitions(-DLEGACY_BACKEND) remove_definitions(-D_TARGET_X86_=1) diff --git a/src/jit/linuxnonjit/CMakeLists.txt b/src/jit/linuxnonjit/CMakeLists.txt index 23a66cbcf5..feec36b8af 100644 --- a/src/jit/linuxnonjit/CMakeLists.txt +++ b/src/jit/linuxnonjit/CMakeLists.txt @@ -11,6 +11,7 @@ endif(FEATURE_READYTORUN) if (CLR_CMAKE_PLATFORM_ARCH_I386) remove_definitions(-DFEATURE_SIMD) + remove_definitions(-DFEATURE_HW_INTRINSICS) add_definitions(-DUNIX_X86_ABI) set(JIT_ARCH_ALTJIT_SOURCES ${JIT_I386_SOURCES}) elseif(CLR_CMAKE_PLATFORM_ARCH_AMD64) diff --git a/src/jit/lsra.h b/src/jit/lsra.h index fed5d6ea86..1a21ff2919 100644 --- a/src/jit/lsra.h +++ b/src/jit/lsra.h @@ -1258,6 +1258,10 @@ private: void TreeNodeInfoInitSIMD(GenTreeSIMD* tree); #endif // FEATURE_SIMD +#if FEATURE_HW_INTRINSICS + void TreeNodeInfoInitHWIntrinsic(GenTreeHWIntrinsic* intrinsicTree); +#endif // FEATURE_HW_INTRINSICS + void TreeNodeInfoInitPutArgStk(GenTreePutArgStk* argNode); #ifdef _TARGET_ARM_ void TreeNodeInfoInitPutArgSplit(GenTreePutArgSplit* tree); diff --git a/src/jit/lsraxarch.cpp b/src/jit/lsraxarch.cpp index 53aebe00bf..86184150ba 100644 --- a/src/jit/lsraxarch.cpp +++ b/src/jit/lsraxarch.cpp @@ -373,6 +373,12 @@ void LinearScan::TreeNodeInfoInit(GenTree* tree) break; #endif // FEATURE_SIMD +#if FEATURE_HW_INTRINSICS + case GT_HWIntrinsic: + TreeNodeInfoInitHWIntrinsic(tree->AsHWIntrinsic()); + break; +#endif // FEATURE_HW_INTRINSICS + case GT_CAST: TreeNodeInfoInitCast(tree); break; @@ -2416,6 +2422,27 @@ void LinearScan::TreeNodeInfoInitSIMD(GenTreeSIMD* simdTree) } #endif // FEATURE_SIMD +#if FEATURE_HW_INTRINSICS +//------------------------------------------------------------------------ +// TreeNodeInfoInitHWIntrinsic: Set the NodeInfo for a GT_HWIntrinsic tree. +// +// Arguments: +// tree - The GT_HWIntrinsic node of interest +// +// Return Value: +// None. + +void LinearScan::TreeNodeInfoInitHWIntrinsic(GenTreeHWIntrinsic* intrinsicTree) +{ + TreeNodeInfo* info = &(intrinsicTree->gtLsraInfo); + if (intrinsicTree->gtGetOp2IfPresent() != nullptr) + { + info->srcCount += GetOperandSourceCount(intrinsicTree->gtOp.gtOp2); + } + info->srcCount += GetOperandSourceCount(intrinsicTree->gtOp.gtOp1); +} +#endif + //------------------------------------------------------------------------ // TreeNodeInfoInitCast: Set the NodeInfo for a GT_CAST. // diff --git a/src/jit/namedintrinsiclist.h b/src/jit/namedintrinsiclist.h index 42786a0c9e..1144df6ad2 100644 --- a/src/jit/namedintrinsiclist.h +++ b/src/jit/namedintrinsiclist.h @@ -14,7 +14,7 @@ enum NamedIntrinsic : unsigned int NI_MathF_Round = 2, NI_Math_Round = 3, NI_System_Collections_Generic_EqualityComparer_get_Default = 4, -#ifdef _TARGET_XARCH_ +#if FEATURE_HW_INTRINSICS NI_HW_INTRINSIC_START, #define HARDWARE_INTRINSIC(id, name, isa) NI_##id, #include "hwintrinsiclistxarch.h" diff --git a/src/jit/protononjit/CMakeLists.txt b/src/jit/protononjit/CMakeLists.txt index b8b1567960..33916c3cae 100644 --- a/src/jit/protononjit/CMakeLists.txt +++ b/src/jit/protononjit/CMakeLists.txt @@ -7,6 +7,8 @@ remove_definitions(-DFEATURE_MERGE_JIT_AND_ENGINE) remove_definitions(-DFEATURE_SIMD) +remove_definitions(-DFEATURE_HW_INTRINSICS) + if(FEATURE_READYTORUN) add_definitions(-DFEATURE_READYTORUN_COMPILER) endif(FEATURE_READYTORUN) diff --git a/src/jit/utils.cpp b/src/jit/utils.cpp index 4e061fa15e..71974a85fc 100644 --- a/src/jit/utils.cpp +++ b/src/jit/utils.cpp @@ -1476,6 +1476,7 @@ void HelperCallProperties::init() case CORINFO_HELP_RETHROW: case CORINFO_HELP_THROW_ARGUMENTEXCEPTION: case CORINFO_HELP_THROW_ARGUMENTOUTOFRANGEEXCEPTION: + case CORINFO_HELP_THROW_PLATFORM_NOT_SUPPORTED: break; diff --git a/src/jit/valuenum.cpp b/src/jit/valuenum.cpp index f11430a9cc..105623227c 100644 --- a/src/jit/valuenum.cpp +++ b/src/jit/valuenum.cpp @@ -5603,6 +5603,15 @@ void Compiler::fgValueNumberTree(GenTreePtr tree, bool evalAsgLhsInd) } #endif +#if FEATURE_HW_INTRINSICS + if (oper == GT_HWIntrinsic) + { + // TODO-CQ: For now hardware intrinsics are not handled by value numbering to be amenable for CSE'ing. + tree->gtVNPair.SetBoth(vnStore->VNForExpr(compCurBB, TYP_UNKNOWN)); + return; + } +#endif // FEATURE_HW_INTRINSICS + var_types typ = tree->TypeGet(); if (GenTree::OperIsConst(oper)) { diff --git a/src/vm/jithelpers.cpp b/src/vm/jithelpers.cpp index 8cff03ae60..1611d585a5 100644 --- a/src/vm/jithelpers.cpp +++ b/src/vm/jithelpers.cpp @@ -5110,6 +5110,24 @@ HCIMPL0(void, JIT_ThrowArgumentOutOfRangeException) HCIMPLEND /*********************************************************************/ +HCIMPL0(void, JIT_ThrowPlatformNotSupportedException) +{ + FCALL_CONTRACT; + + /* Make no assumptions about the current machine state */ + ResetCurrentContext(); + + FC_GC_POLL_NOT_NEEDED(); // throws always open up for GC + + HELPER_METHOD_FRAME_BEGIN_ATTRIB_NOPOLL(Frame::FRAME_ATTR_EXCEPTION); // Set up a frame + + COMPlusThrow(kPlatformNotSupportedException); + + HELPER_METHOD_FRAME_END(); +} +HCIMPLEND + +/*********************************************************************/ HCIMPL0(void, JIT_Overflow) { FCALL_CONTRACT; diff --git a/tests/src/JIT/HardwareIntrinsics/Crc32.cs b/tests/src/JIT/HardwareIntrinsics/Crc32.cs new file mode 100644 index 0000000000..27ea5a9bbf --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/Crc32.cs @@ -0,0 +1,180 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +// + +using System; +using System.Runtime.Intrinsics.X86; + +namespace IntelHardwareIntrinsicTest +{ + class Program + { + const int Pass = 100; + const int Fail = 0; + + static int Main(string[] args) + { + ulong s1l = 0, s2l = 0, resl; + int testResult = Pass; + + if (!Sse42.IsSupported || !Environment.Is64BitProcess) + { + try + { + resl = Sse42.Crc32(s1l, s2l); + Console.WriteLine("Intrinsic Sse42.Crc32 is called on non-supported hardware."); + Console.WriteLine("Sse42.IsSupported " + Sse42.IsSupported); + Console.WriteLine("Environment.Is64BitProcess " + Environment.Is64BitProcess); + return Fail; + } + catch (PlatformNotSupportedException) + { + testResult = Pass; + } + } + + + if (Sse42.IsSupported) + { + if (Environment.Is64BitProcess) + { + for (int i = 0; i < longCrcTable.Length; i++) + { + s1l = longCrcTable[i].s1; + s2l = longCrcTable[i].s2; + resl = Sse42.Crc32(s1l, s2l); + if (resl != longCrcTable[i].res) + { + Console.WriteLine("{0}: Inputs: 0x{1,16:x}, 0x{2,16:x} Expected: 0x{3,16:x} actual: 0x{4,16:x}", + i, s1l, s2l, longCrcTable[i].res, resl); + testResult = Fail; + } + } + } + + uint s1i, s2i, resi; + for (int i = 0; i < intCrcTable.Length; i++) + { + s1i = intCrcTable[i].s1; + s2i = intCrcTable[i].s2; + resi = Sse42.Crc32(s1i, s2i); + if (resi != intCrcTable[i].res) + { + Console.WriteLine("{0}: Inputs: 0x{1,8:x}, 0x{2,8:x} Expected: 0x{3,8:x} actual: 0x{4,8:x}", + i, s1i, s2i, intCrcTable[i].res, resi); + testResult = Fail; + } + } + + ushort s2s; + for (int i = 0; i < shortCrcTable.Length; i++) + { + s1i = shortCrcTable[i].s1; + s2s = shortCrcTable[i].s2; + resi = Sse42.Crc32(s1i, s2s); + if (resi != shortCrcTable[i].res) + { + Console.WriteLine("{0}: Inputs: 0x{1,8:x}, 0x{2,8:x} Expected: 0x{3,8:x} actual: 0x{4,8:x}", + i, s1i, s2s, shortCrcTable[i].res, resi); + testResult = Fail; + } + } + + byte s2b; + for (int i = 0; i < byteCrcTable.Length; i++) + { + s1i = byteCrcTable[i].s1; + s2b = byteCrcTable[i].s2; + resi = Sse42.Crc32(s1i, s2b); + if (resi != byteCrcTable[i].res) + { + Console.WriteLine("{0}: Inputs: 0x{1,8:x}, 0x{2,8:x} Expected: 0x{3,8:x} actual: 0x{4,8:x}", + i, s1i, s2b, byteCrcTable[i].res, resi); + testResult = Fail; + } + } + } + + return testResult; + } + + public struct Crc<T, U> where T : struct where U : struct + { + public T s1; + public U s2; + public T res; + public Crc(T a, U b, T c) + { + this.s1 = a; + this.s2 = b; + this.res = c; + } + } + + public static Crc<ulong, ulong>[] longCrcTable = { + new Crc<ulong, ulong>(0x0000000000000000UL, 0x0000000000000000UL, 0x0000000000000000UL), + new Crc<ulong, ulong>(0x0000000000000000UL, 0x0000000000000001UL, 0x00000000493c7d27UL), + new Crc<ulong, ulong>(0x0000000000000001UL, 0x0000000000000000UL, 0x00000000493c7d27UL), + new Crc<ulong, ulong>(0x0000000000000001UL, 0x0000000000000001UL, 0x0000000000000000UL), + new Crc<ulong, ulong>(0x0000000000000000UL, 0xffffffffffffffffUL, 0x00000000c44ff94dUL), + new Crc<ulong, ulong>(0xffffffffffffffffUL, 0x0000000000000000UL, 0x0000000073d74d75UL), + new Crc<ulong, ulong>(0xffffffffffffffffUL, 0xffffffffffffffffUL, 0x00000000b798b438UL), + new Crc<ulong, ulong>(0x0000000000000001UL, 0xffffffffffffffffUL, 0x000000008d73846aUL), + new Crc<ulong, ulong>(0xffffffffffffffffUL, 0x0000000000000001UL, 0x000000003aeb3052UL), + new Crc<ulong, ulong>(0xfffffffffffe1f0dUL, 0x00000000f5c1ddb3UL, 0x000000000504c066UL), + new Crc<ulong, ulong>(0x0000000000000005UL, 0x000000bce1263cffUL, 0x000000004ab954daUL), + new Crc<ulong, ulong>(0x0000000000000463UL, 0xffffffffff840d0dUL, 0x00000000797d59f3UL), + new Crc<ulong, ulong>(0x00000000000f423fUL, 0x000000000001e0f3UL, 0x000000005c6b8093UL) + }; + + public static Crc<uint, uint>[] intCrcTable = { + new Crc<uint, uint>(0x00000000U, 0x00000000U, 0x00000000U), + new Crc<uint, uint>(0x00000000U, 0x00000001U, 0xdd45aab8U), + new Crc<uint, uint>(0x00000001U, 0x00000000U, 0xdd45aab8U), + new Crc<uint, uint>(0x00000001U, 0x00000001U, 0x00000000U), + new Crc<uint, uint>(0x00000000U, 0xffffffffU, 0xb798b438U), + new Crc<uint, uint>(0xffffffffU, 0x00000000U, 0xb798b438U), + new Crc<uint, uint>(0xffffffffU, 0xffffffffU, 0x00000000U), + new Crc<uint, uint>(0x00000001U, 0xffffffffU, 0x6add1e80U), + new Crc<uint, uint>(0xffffffffU, 0x00000001U, 0x6add1e80U), + new Crc<uint, uint>(0xfffe1f0dU, 0xf5c1ddb3U, 0x911888ccU), + new Crc<uint, uint>(0x00000005U, 0xe1263cffU, 0xbe12f661U), + new Crc<uint, uint>(0x00000463U, 0xff840d0dU, 0xcba65e37U), + new Crc<uint, uint>(0x000f423fU, 0x0001e0f3U, 0xa5b7881dU) + }; + + public static Crc<uint, ushort>[] shortCrcTable = { + new Crc<uint, ushort>(0x00000000U, 0x0000, 0x00000000U), + new Crc<uint, ushort>(0x00000000U, 0x0001, 0x13a29877U), + new Crc<uint, ushort>(0x00000001U, 0x0000, 0x13a29877U), + new Crc<uint, ushort>(0x00000001U, 0x0001, 0x00000000U), + new Crc<uint, ushort>(0x00000000U, 0xffff, 0xe9e77d2U), + new Crc<uint, ushort>(0xffffffffU, 0x0000, 0xe9e882dU), + new Crc<uint, ushort>(0xffffffffU, 0xffff, 0x0000ffffU), + new Crc<uint, ushort>(0x00000001U, 0xffff, 0x1d3cefa5U), + new Crc<uint, ushort>(0xffffffffU, 0x0001, 0x1d3c105aU), + new Crc<uint, ushort>(0xfffe1f0dU, 0xddb3, 0x6de0d33dU), + new Crc<uint, ushort>(0x00000005U, 0x3cff, 0x836b5b49U), + new Crc<uint, ushort>(0x00000463U, 0x0d0d, 0x0cf56c40U), + new Crc<uint, ushort>(0x000f423fU, 0xe0f3, 0x943a5bc7U) + }; + + public static Crc<uint, byte>[] byteCrcTable = { + new Crc<uint, byte>(0x00000000U, 0x00, 0x00000000U), + new Crc<uint, byte>(0x00000000U, 0x01, 0xf26b8303U), + new Crc<uint, byte>(0x00000001U, 0x00, 0xf26b8303U), + new Crc<uint, byte>(0x00000001U, 0x01, 0x00000000U), + new Crc<uint, byte>(0x00000000U, 0xff, 0xad7d5351U), + new Crc<uint, byte>(0xffffffffU, 0x00, 0xad82acaeU), + new Crc<uint, byte>(0xffffffffU, 0xff, 0x00ffffffU), + new Crc<uint, byte>(0x00000001U, 0xff, 0x5f16d052U), + new Crc<uint, byte>(0xffffffffU, 0x01, 0x5fe92fadU), + new Crc<uint, byte>(0xfffe1f0dU, 0xb3, 0x1e9233f1U), + new Crc<uint, byte>(0x00000005U, 0xff, 0x988c474dU), + new Crc<uint, byte>(0x00000463U, 0x0d, 0xcdbe2c41U), + new Crc<uint, byte>(0x000f423fU, 0xf3, 0x8ecee656U) + }; + + } +}
\ No newline at end of file diff --git a/tests/src/JIT/HardwareIntrinsics/Crc32_r.csproj b/tests/src/JIT/HardwareIntrinsics/Crc32_r.csproj new file mode 100644 index 0000000000..e42eeb4f93 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/Crc32_r.csproj @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{95DFC527-4DC1-495E-97D7-E94EE1F7140D}</ProjectGuid> + <OutputType>Exe</OutputType> + <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> + <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> + </PropertyGroup> + <!-- Default configurations to help VS understand the configurations --> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "></PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " /> + <ItemGroup> + <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> + <Visible>False</Visible> + </CodeAnalysisDependentAssemblyPaths> + </ItemGroup> + <PropertyGroup> + <DebugType>None</DebugType> + <Optimize></Optimize> + </PropertyGroup> + <ItemGroup> + <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> + </ItemGroup> + <ItemGroup> + <Compile Include="Crc32.cs" /> + </ItemGroup> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> + <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "></PropertyGroup> +</Project>
\ No newline at end of file diff --git a/tests/src/JIT/HardwareIntrinsics/Crc32_ro.csproj b/tests/src/JIT/HardwareIntrinsics/Crc32_ro.csproj new file mode 100644 index 0000000000..0dfe5e0930 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/Crc32_ro.csproj @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{95DFC527-4DC1-495E-97D7-E94EE1F7140D}</ProjectGuid> + <OutputType>Exe</OutputType> + <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> + <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> + </PropertyGroup> + <!-- Default configurations to help VS understand the configurations --> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "></PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " /> + <ItemGroup> + <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> + <Visible>False</Visible> + </CodeAnalysisDependentAssemblyPaths> + </ItemGroup> + <PropertyGroup> + <DebugType>None</DebugType> + <Optimize>True</Optimize> + </PropertyGroup> + <ItemGroup> + <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> + </ItemGroup> + <ItemGroup> + <Compile Include="Crc32.cs" /> + </ItemGroup> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> + <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "></PropertyGroup> +</Project>
\ No newline at end of file diff --git a/tests/src/JIT/HardwareIntrinsics/Lzcnt.cs b/tests/src/JIT/HardwareIntrinsics/Lzcnt.cs new file mode 100644 index 0000000000..9d40c08c54 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/Lzcnt.cs @@ -0,0 +1,99 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +// + +using System; +using System.Runtime.Intrinsics.X86; + +namespace IntelHardwareIntrinsicTest +{ + class Program + { + const int Pass = 100; + const int Fail = 0; + + static int Main(string[] args) + { + ulong sl = 0, resl; + int testResult = Pass; + + if (!Lzcnt.IsSupported || !Environment.Is64BitProcess) + { + try + { + resl = Lzcnt.LeadingZeroCount(sl); + Console.WriteLine("Intrinsic Lzcnt.LeadingZeroCount is called on non-supported hardware."); + Console.WriteLine("Lzcnt.IsSupported " + Lzcnt.IsSupported); + Console.WriteLine("Environment.Is64BitProcess " + Environment.Is64BitProcess); + return Fail; + } + catch (PlatformNotSupportedException) + { + testResult = Pass; + } + } + + + if (Lzcnt.IsSupported) + { + if (Environment.Is64BitProcess) + { + for (int i = 0; i < longLzcntTable.Length; i++) + { + sl = longLzcntTable[i].s; + resl = Lzcnt.LeadingZeroCount(sl); + if (resl != longLzcntTable[i].res) + { + Console.WriteLine("{0}: Inputs: 0x{1,16:x} Expected: 0x{3,16:x} actual: 0x{4,16:x}", + i, sl, longLzcntTable[i].res, resl); + testResult = Fail; + } + } + } + + uint si, resi; + for (int i = 0; i < intLzcntTable.Length; i++) + { + si = intLzcntTable[i].s; + resi = Lzcnt.LeadingZeroCount(si); + if (resi != intLzcntTable[i].res) + { + Console.WriteLine("{0}: Inputs: 0x{1,16:x} Expected: 0x{3,16:x} actual: 0x{4,16:x}", + i, si, intLzcntTable[i].res, resi); + testResult = Fail; + } + } + } + + return testResult; + } + + public struct LZCNT<T> where T : struct + { + public T s; + public T res; + public LZCNT(T a, T r) + { + this.s = a; + this.res = r; + } + } + + public static LZCNT<ulong>[] longLzcntTable = { + new LZCNT<ulong>(0x0000000000000000UL, 64), + new LZCNT<ulong>(0x0000000000000001UL, 63), + new LZCNT<ulong>(0xffffffffffffffffUL, 0), + new LZCNT<ulong>(0xf000000000000000UL, 0), + new LZCNT<ulong>(0x00050000000f423fUL, 13) + }; + + public static LZCNT<uint>[] intLzcntTable = { + new LZCNT<uint>(0x00000000U, 32), + new LZCNT<uint>(0x00000001U, 31), + new LZCNT<uint>(0xffffffffU, 0), + new LZCNT<uint>(0xf0000000U, 0), + new LZCNT<uint>(0x0005423fU, 13) + }; + } +}
\ No newline at end of file diff --git a/tests/src/JIT/HardwareIntrinsics/Lzcnt_r.csproj b/tests/src/JIT/HardwareIntrinsics/Lzcnt_r.csproj new file mode 100644 index 0000000000..cc76545fcc --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/Lzcnt_r.csproj @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{95DFC527-4DC1-495E-97D7-E94EE1F7140D}</ProjectGuid> + <OutputType>Exe</OutputType> + <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> + <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> + </PropertyGroup> + <!-- Default configurations to help VS understand the configurations --> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "></PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " /> + <ItemGroup> + <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> + <Visible>False</Visible> + </CodeAnalysisDependentAssemblyPaths> + </ItemGroup> + <PropertyGroup> + <DebugType>None</DebugType> + <Optimize></Optimize> + </PropertyGroup> + <ItemGroup> + <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> + </ItemGroup> + <ItemGroup> + <Compile Include="Lzcnt.cs" /> + </ItemGroup> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> + <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "></PropertyGroup> +</Project>
\ No newline at end of file diff --git a/tests/src/JIT/HardwareIntrinsics/Lzcnt_ro.csproj b/tests/src/JIT/HardwareIntrinsics/Lzcnt_ro.csproj new file mode 100644 index 0000000000..9bc71c3767 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/Lzcnt_ro.csproj @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{95DFC527-4DC1-495E-97D7-E94EE1F7140D}</ProjectGuid> + <OutputType>Exe</OutputType> + <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> + <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> + </PropertyGroup> + <!-- Default configurations to help VS understand the configurations --> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "></PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " /> + <ItemGroup> + <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> + <Visible>False</Visible> + </CodeAnalysisDependentAssemblyPaths> + </ItemGroup> + <PropertyGroup> + <DebugType>None</DebugType> + <Optimize>True</Optimize> + </PropertyGroup> + <ItemGroup> + <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> + </ItemGroup> + <ItemGroup> + <Compile Include="Lzcnt.cs" /> + </ItemGroup> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> + <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "></PropertyGroup> +</Project>
\ No newline at end of file diff --git a/tests/src/JIT/HardwareIntrinsics/Popcnt.cs b/tests/src/JIT/HardwareIntrinsics/Popcnt.cs new file mode 100644 index 0000000000..20c443ba53 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/Popcnt.cs @@ -0,0 +1,101 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +// + +using System; +using System.Runtime.Intrinsics.X86; + +namespace IntelHardwareIntrinsicTest +{ + class Program + { + const int Pass = 100; + const int Fail = 0; + + static int Main(string[] args) + { + ulong sl = 0; + long resl; + int testResult = Pass; + + if (!Popcnt.IsSupported || !Environment.Is64BitProcess) + { + try + { + resl = Popcnt.PopCount(sl); + Console.WriteLine("Intrinsic Popcnt.PopCount is called on non-supported hardware"); + Console.WriteLine("Popcnt.IsSupported " + Popcnt.IsSupported); + Console.WriteLine("Environment.Is64BitProcess " + Environment.Is64BitProcess); + return Fail; + } + catch (PlatformNotSupportedException) + { + testResult = Pass; + } + } + + + if (Popcnt.IsSupported) + { + if (Environment.Is64BitProcess) + { + for (int i = 0; i < longPopcntTable.Length; i++) + { + sl = longPopcntTable[i].s; + resl = Popcnt.PopCount(sl); + if (resl != longPopcntTable[i].res) + { + Console.WriteLine("{0}: Inputs: 0x{1,16:x} Expected: 0x{3,16:x} actual: 0x{4,16:x}", + i, sl, longPopcntTable[i].res, resl); + testResult = Fail; + } + } + } + + uint si; + int resi; + for (int i = 0; i < intPopcntTable.Length; i++) + { + si = intPopcntTable[i].s; + resi = Popcnt.PopCount(si); + if (resi != intPopcntTable[i].res) + { + Console.WriteLine("{0}: Inputs: 0x{1,16:x} Expected: 0x{3,16:x} actual: 0x{4,16:x}", + i, si, intPopcntTable[i].res, resi); + testResult = Fail; + } + } + } + + return testResult; + } + + public struct POPCNT<T, U> where T : struct where U : struct + { + public T s; + public U res; + public POPCNT(T a, U r) + { + this.s = a; + this.res = r; + } + } + + public static POPCNT<ulong,long>[] longPopcntTable = { + new POPCNT<ulong,long>(0x0000000000000000UL, 0), + new POPCNT<ulong,long>(0x0000000000000001UL, 1), + new POPCNT<ulong,long>(0xffffffffffffffffUL, 64), + new POPCNT<ulong,long>(0x8000000000000000UL, 1), + new POPCNT<ulong,long>(0x00050000000f423fUL, 14) + }; + + public static POPCNT<uint,int>[] intPopcntTable = { + new POPCNT<uint,int>(0x00000000U, 0), + new POPCNT<uint,int>(0x00000001U, 1), + new POPCNT<uint,int>(0xffffffffU, 32), + new POPCNT<uint,int>(0x80000000U, 1), + new POPCNT<uint,int>(0x0005423fU, 10) + }; + } +}
\ No newline at end of file diff --git a/tests/src/JIT/HardwareIntrinsics/Popcnt_r.csproj b/tests/src/JIT/HardwareIntrinsics/Popcnt_r.csproj new file mode 100644 index 0000000000..2a0e814c3e --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/Popcnt_r.csproj @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{95DFC527-4DC1-495E-97D7-E94EE1F7140D}</ProjectGuid> + <OutputType>Exe</OutputType> + <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> + <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> + </PropertyGroup> + <!-- Default configurations to help VS understand the configurations --> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "></PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " /> + <ItemGroup> + <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> + <Visible>False</Visible> + </CodeAnalysisDependentAssemblyPaths> + </ItemGroup> + <PropertyGroup> + <DebugType>None</DebugType> + <Optimize></Optimize> + </PropertyGroup> + <ItemGroup> + <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> + </ItemGroup> + <ItemGroup> + <Compile Include="Popcnt.cs" /> + </ItemGroup> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> + <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "></PropertyGroup> +</Project>
\ No newline at end of file diff --git a/tests/src/JIT/HardwareIntrinsics/Popcnt_ro.csproj b/tests/src/JIT/HardwareIntrinsics/Popcnt_ro.csproj new file mode 100644 index 0000000000..1a1414aecf --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/Popcnt_ro.csproj @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{95DFC527-4DC1-495E-97D7-E94EE1F7140D}</ProjectGuid> + <OutputType>Exe</OutputType> + <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> + <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> + </PropertyGroup> + <!-- Default configurations to help VS understand the configurations --> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "></PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " /> + <ItemGroup> + <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> + <Visible>False</Visible> + </CodeAnalysisDependentAssemblyPaths> + </ItemGroup> + <PropertyGroup> + <DebugType>None</DebugType> + <Optimize>True</Optimize> + </PropertyGroup> + <ItemGroup> + <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> + </ItemGroup> + <ItemGroup> + <Compile Include="Popcnt.cs" /> + </ItemGroup> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> + <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "></PropertyGroup> +</Project>
\ No newline at end of file |