summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/inc/corinfo.h11
-rw-r--r--src/inc/jithelpers.h5
-rw-r--r--src/jit/CMakeLists.txt3
-rw-r--r--src/jit/armelnonjit/CMakeLists.txt1
-rw-r--r--src/jit/codegenlinear.h19
-rw-r--r--src/jit/codegenxarch.cpp6
-rw-r--r--src/jit/compiler.h17
-rw-r--r--src/jit/emitxarch.cpp26
-rw-r--r--src/jit/flowgraph.cpp3
-rw-r--r--src/jit/gentree.cpp74
-rw-r--r--src/jit/gentree.h69
-rw-r--r--src/jit/gtlist.h4
-rw-r--r--src/jit/gtstructs.h3
-rw-r--r--src/jit/hwintrinsiccodegenxarch.cpp220
-rw-r--r--src/jit/hwintrinsiclistxarch.h7
-rw-r--r--src/jit/hwintrinsicxarch.cpp98
-rw-r--r--src/jit/importer.cpp10
-rw-r--r--src/jit/instrsxarch.h9
-rw-r--r--src/jit/jit.settings.targets2
-rw-r--r--src/jit/legacyjit/CMakeLists.txt3
-rw-r--r--src/jit/legacynonjit/CMakeLists.txt2
-rw-r--r--src/jit/linuxnonjit/CMakeLists.txt1
-rw-r--r--src/jit/lsra.h4
-rw-r--r--src/jit/lsraxarch.cpp27
-rw-r--r--src/jit/namedintrinsiclist.h2
-rw-r--r--src/jit/protononjit/CMakeLists.txt2
-rw-r--r--src/jit/utils.cpp1
-rw-r--r--src/jit/valuenum.cpp9
-rw-r--r--src/vm/jithelpers.cpp18
-rw-r--r--tests/src/JIT/HardwareIntrinsics/Crc32.cs180
-rw-r--r--tests/src/JIT/HardwareIntrinsics/Crc32_r.csproj33
-rw-r--r--tests/src/JIT/HardwareIntrinsics/Crc32_ro.csproj33
-rw-r--r--tests/src/JIT/HardwareIntrinsics/Lzcnt.cs99
-rw-r--r--tests/src/JIT/HardwareIntrinsics/Lzcnt_r.csproj33
-rw-r--r--tests/src/JIT/HardwareIntrinsics/Lzcnt_ro.csproj33
-rw-r--r--tests/src/JIT/HardwareIntrinsics/Popcnt.cs101
-rw-r--r--tests/src/JIT/HardwareIntrinsics/Popcnt_r.csproj33
-rw-r--r--tests/src/JIT/HardwareIntrinsics/Popcnt_ro.csproj33
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