diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 18fce48d72b344..66d53992b70759 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -3319,6 +3319,7 @@ class Compiler unsigned simdSize, bool isSimdAsHWIntrinsic); + GenTreeHWIntrinsic* gtNewScalarHWIntrinsicNode(var_types type, NamedIntrinsic hwIntrinsicID); GenTreeHWIntrinsic* gtNewScalarHWIntrinsicNode(var_types type, GenTree* op1, NamedIntrinsic hwIntrinsicID); GenTreeHWIntrinsic* gtNewScalarHWIntrinsicNode(var_types type, GenTree* op1, diff --git a/src/coreclr/jit/emit.h b/src/coreclr/jit/emit.h index 3f6607a9966a52..22e9cfd6c79e09 100644 --- a/src/coreclr/jit/emit.h +++ b/src/coreclr/jit/emit.h @@ -1240,21 +1240,22 @@ class emitter #define PERFSCORE_THROUGHPUT_1C 1.0f // Single Issue -#define PERFSCORE_THROUGHPUT_2C 2.0f // slower - 2 cycles -#define PERFSCORE_THROUGHPUT_3C 3.0f // slower - 3 cycles -#define PERFSCORE_THROUGHPUT_4C 4.0f // slower - 4 cycles -#define PERFSCORE_THROUGHPUT_5C 5.0f // slower - 5 cycles -#define PERFSCORE_THROUGHPUT_6C 6.0f // slower - 6 cycles -#define PERFSCORE_THROUGHPUT_7C 7.0f // slower - 7 cycles -#define PERFSCORE_THROUGHPUT_8C 8.0f // slower - 8 cycles -#define PERFSCORE_THROUGHPUT_9C 9.0f // slower - 9 cycles -#define PERFSCORE_THROUGHPUT_10C 10.0f // slower - 10 cycles -#define PERFSCORE_THROUGHPUT_13C 13.0f // slower - 13 cycles -#define PERFSCORE_THROUGHPUT_19C 19.0f // slower - 19 cycles -#define PERFSCORE_THROUGHPUT_25C 25.0f // slower - 25 cycles -#define PERFSCORE_THROUGHPUT_33C 33.0f // slower - 33 cycles -#define PERFSCORE_THROUGHPUT_52C 52.0f // slower - 52 cycles -#define PERFSCORE_THROUGHPUT_57C 57.0f // slower - 57 cycles +#define PERFSCORE_THROUGHPUT_2C 2.0f // slower - 2 cycles +#define PERFSCORE_THROUGHPUT_3C 3.0f // slower - 3 cycles +#define PERFSCORE_THROUGHPUT_4C 4.0f // slower - 4 cycles +#define PERFSCORE_THROUGHPUT_5C 5.0f // slower - 5 cycles +#define PERFSCORE_THROUGHPUT_6C 6.0f // slower - 6 cycles +#define PERFSCORE_THROUGHPUT_7C 7.0f // slower - 7 cycles +#define PERFSCORE_THROUGHPUT_8C 8.0f // slower - 8 cycles +#define PERFSCORE_THROUGHPUT_9C 9.0f // slower - 9 cycles +#define PERFSCORE_THROUGHPUT_10C 10.0f // slower - 10 cycles +#define PERFSCORE_THROUGHPUT_13C 13.0f // slower - 13 cycles +#define PERFSCORE_THROUGHPUT_19C 19.0f // slower - 19 cycles +#define PERFSCORE_THROUGHPUT_25C 25.0f // slower - 25 cycles +#define PERFSCORE_THROUGHPUT_33C 33.0f // slower - 33 cycles +#define PERFSCORE_THROUGHPUT_52C 52.0f // slower - 52 cycles +#define PERFSCORE_THROUGHPUT_57C 57.0f // slower - 57 cycles +#define PERFSCORE_THROUGHPUT_140C 140.0f // slower - 140 cycles #define PERFSCORE_LATENCY_ILLEGAL -1024.0f @@ -1281,6 +1282,7 @@ class emitter #define PERFSCORE_LATENCY_26C 26.0f #define PERFSCORE_LATENCY_62C 62.0f #define PERFSCORE_LATENCY_69C 69.0f +#define PERFSCORE_LATENCY_140C 140.0f #define PERFSCORE_LATENCY_400C 400.0f // Intel microcode issue with these instuctions #define PERFSCORE_LATENCY_BRANCH_DIRECT 1.0f // cost of an unconditional branch diff --git a/src/coreclr/jit/emitarm64.cpp b/src/coreclr/jit/emitarm64.cpp index 0e9da02b60cd4e..1ae7aa873a0aef 100644 --- a/src/coreclr/jit/emitarm64.cpp +++ b/src/coreclr/jit/emitarm64.cpp @@ -14588,6 +14588,12 @@ emitter::insExecutionCharacteristics emitter::getInsExecutionCharacteristics(ins result.insThroughput = PERFSCORE_THROUGHPUT_ZERO; result.insLatency = PERFSCORE_LATENCY_ZERO; } + else if (ins == INS_yield) + { + // @ToDo - find out the actual latency, match x86/x64 for now + result.insThroughput = PERFSCORE_THROUGHPUT_140C; + result.insLatency = PERFSCORE_LATENCY_140C; + } else { result.insThroughput = PERFSCORE_THROUGHPUT_2X; diff --git a/src/coreclr/jit/emitxarch.cpp b/src/coreclr/jit/emitxarch.cpp index fa6d44cda0f4bc..00c403d08768d9 100644 --- a/src/coreclr/jit/emitxarch.cpp +++ b/src/coreclr/jit/emitxarch.cpp @@ -2898,7 +2898,8 @@ void emitter::emitIns(instruction ins) ins == INS_r_movsp || ins == INS_r_stosb || ins == INS_r_stosd || ins == INS_r_stosp || ins == INS_ret || ins == INS_sahf || ins == INS_stosb || ins == INS_stosd || ins == INS_stosp // These instructions take zero operands - || ins == INS_vzeroupper || ins == INS_lfence || ins == INS_mfence || ins == INS_sfence); + || ins == INS_vzeroupper || ins == INS_lfence || ins == INS_mfence || ins == INS_sfence || + ins == INS_pause); assert(assertCond); } @@ -12333,8 +12334,8 @@ BYTE* emitter::emitOutputRR(BYTE* dst, instrDesc* id) // Due to elided register moves, we can't have the following assert. // For example, consider: // t85 = LCL_VAR byref V01 arg1 rdx (last use) REG rdx - // /--* t85 byref - // * STORE_LCL_VAR byref V40 tmp31 rdx REG rdx + // /--* t85 byref + // * STORE_LCL_VAR byref V40 tmp31 rdx REG rdx // Here, V01 is type `long` on entry, then is stored as a byref. But because // the register allocator assigned the same register, no instruction was // generated, and we only (currently) make gcref/byref changes in emitter GC info @@ -16104,6 +16105,13 @@ emitter::insExecutionCharacteristics emitter::getInsExecutionCharacteristics(ins result.insThroughput = PERFSCORE_THROUGHPUT_2X; break; + case INS_pause: + { + result.insLatency = PERFSCORE_LATENCY_140C; + result.insThroughput = PERFSCORE_THROUGHPUT_140C; + break; + } + default: // unhandled instruction insFmt combination perfScoreUnhandledInstruction(id, &result); diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index e7aded8d92c927..867e2ae9e72c6e 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -21948,6 +21948,12 @@ GenTree* Compiler::gtNewSimdZeroNode(var_types type, return gtNewSimdHWIntrinsicNode(type, intrinsic, simdBaseJitType, simdSize, isSimdAsHWIntrinsic); } +GenTreeHWIntrinsic* Compiler::gtNewScalarHWIntrinsicNode(var_types type, NamedIntrinsic hwIntrinsicID) +{ + return new (this, GT_HWINTRINSIC) + GenTreeHWIntrinsic(type, hwIntrinsicID, CORINFO_TYPE_UNDEF, 0, /* isSimdAsHWIntrinsic */ false); +} + GenTreeHWIntrinsic* Compiler::gtNewScalarHWIntrinsicNode(var_types type, GenTree* op1, NamedIntrinsic hwIntrinsicID) { SetOpLclRelatedToSIMDIntrinsic(op1); diff --git a/src/coreclr/jit/hwintrinsic.h b/src/coreclr/jit/hwintrinsic.h index 0b35ca719b6e2f..186b64463d820f 100644 --- a/src/coreclr/jit/hwintrinsic.h +++ b/src/coreclr/jit/hwintrinsic.h @@ -804,7 +804,7 @@ struct HWIntrinsic final if (baseType == TYP_UNKNOWN) { - assert(category == HW_Category_Scalar); + assert((category == HW_Category_Scalar) || (category == HW_Category_Special)); if (HWIntrinsicInfo::BaseTypeFromFirstArg(id)) { diff --git a/src/coreclr/jit/hwintrinsicarm64.cpp b/src/coreclr/jit/hwintrinsicarm64.cpp index 8f4d0f0ebf96fd..f72fbaf1df7e1e 100644 --- a/src/coreclr/jit/hwintrinsicarm64.cpp +++ b/src/coreclr/jit/hwintrinsicarm64.cpp @@ -308,9 +308,8 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, var_types retType, unsigned simdSize) { - HWIntrinsicCategory category = HWIntrinsicInfo::lookupCategory(intrinsic); - int numArgs = sig->numArgs; - var_types simdBaseType = JitType2PreciseVarType(simdBaseJitType); + HWIntrinsicCategory category = HWIntrinsicInfo::lookupCategory(intrinsic); + int numArgs = sig->numArgs; if (!featureSIMD || !IsBaselineSimdIsaSupported()) { @@ -318,7 +317,14 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, } assert(numArgs >= 0); - assert(varTypeIsArithmetic(simdBaseType)); + + var_types simdBaseType = TYP_UNKNOWN; + + if (intrinsic != NI_ArmBase_Yield) + { + simdBaseType = JitType2PreciseVarType(simdBaseJitType); + assert(varTypeIsArithmetic(simdBaseType)); + } GenTree* retNode = nullptr; GenTree* op1 = nullptr; @@ -327,6 +333,16 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, switch (intrinsic) { + case NI_ArmBase_Yield: + { + assert(sig->numArgs == 0); + assert(JITtype2varType(sig->retType) == TYP_VOID); + assert(simdSize == 0); + + retNode = gtNewScalarHWIntrinsicNode(TYP_VOID, intrinsic); + break; + } + case NI_Vector64_Abs: case NI_Vector128_Abs: { diff --git a/src/coreclr/jit/hwintrinsiccodegenarm64.cpp b/src/coreclr/jit/hwintrinsiccodegenarm64.cpp index 3352c9ba595710..8604d0db811d2d 100644 --- a/src/coreclr/jit/hwintrinsiccodegenarm64.cpp +++ b/src/coreclr/jit/hwintrinsiccodegenarm64.cpp @@ -255,6 +255,13 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node) emitSize = emitActualTypeSize(intrin.baseType); opt = INS_OPTS_NONE; } + else if (intrin.category == HW_Category_Special) + { + assert(intrin.id == NI_ArmBase_Yield); + + emitSize = EA_UNKNOWN; + opt = INS_OPTS_NONE; + } else { emitSize = emitActualTypeSize(Compiler::getSIMDTypeForSize(node->GetSimdSize())); @@ -443,6 +450,12 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node) } break; + case NI_ArmBase_Yield: + { + ins = INS_yield; + break; + } + default: ins = HWIntrinsicInfo::lookupIns(intrin.id, intrin.baseType); break; @@ -735,6 +748,12 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node) } break; + case NI_ArmBase_Yield: + { + GetEmitter()->emitIns(ins); + break; + } + // mvni doesn't support the range of element types, so hard code the 'opts' value. case NI_Vector64_get_Zero: case NI_Vector64_get_AllBitsSet: diff --git a/src/coreclr/jit/hwintrinsiccodegenxarch.cpp b/src/coreclr/jit/hwintrinsiccodegenxarch.cpp index 8523b529cbec42..0dc565d65575a7 100644 --- a/src/coreclr/jit/hwintrinsiccodegenxarch.cpp +++ b/src/coreclr/jit/hwintrinsiccodegenxarch.cpp @@ -1447,6 +1447,8 @@ void CodeGen::genX86BaseIntrinsic(GenTreeHWIntrinsic* node) { NamedIntrinsic intrinsicId = node->gtHWIntrinsicId; + genConsumeOperands(node); + switch (intrinsicId) { case NI_X86Base_BitScanForward: @@ -1459,9 +1461,16 @@ void CodeGen::genX86BaseIntrinsic(GenTreeHWIntrinsic* node) var_types targetType = node->TypeGet(); instruction ins = HWIntrinsicInfo::lookupIns(intrinsicId, targetType); - genConsumeOperands(node); genHWIntrinsic_R_RM(node, ins, emitTypeSize(targetType), targetReg, op1); - genProduceReg(node); + break; + } + + case NI_X86Base_Pause: + { + assert(node->GetSimdBaseType() == TYP_UNKNOWN); + assert(node->gtGetOp1() == nullptr); + assert(node->gtGetOp2() == nullptr); + GetEmitter()->emitIns(INS_pause); break; } @@ -1469,6 +1478,8 @@ void CodeGen::genX86BaseIntrinsic(GenTreeHWIntrinsic* node) unreached(); break; } + + genProduceReg(node); } //------------------------------------------------------------------------ @@ -1532,7 +1543,7 @@ void CodeGen::genSSEIntrinsic(GenTreeHWIntrinsic* node) case NI_SSE_StoreFence: { - assert(baseType == TYP_VOID); + assert(baseType == TYP_UNKNOWN); assert(op1 == nullptr); assert(op2 == nullptr); emit->emitIns(INS_sfence); @@ -1617,7 +1628,7 @@ void CodeGen::genSSE2Intrinsic(GenTreeHWIntrinsic* node) case NI_SSE2_LoadFence: { - assert(baseType == TYP_VOID); + assert(baseType == TYP_UNKNOWN); assert(op1 == nullptr); assert(op2 == nullptr); emit->emitIns(INS_lfence); @@ -1626,7 +1637,7 @@ void CodeGen::genSSE2Intrinsic(GenTreeHWIntrinsic* node) case NI_SSE2_MemoryFence: { - assert(baseType == TYP_VOID); + assert(baseType == TYP_UNKNOWN); assert(op1 == nullptr); assert(op2 == nullptr); emit->emitIns(INS_mfence); diff --git a/src/coreclr/jit/hwintrinsiclistarm64.h b/src/coreclr/jit/hwintrinsiclistarm64.h index 3f6c90a1315f87..c7e49b91a05be8 100644 --- a/src/coreclr/jit/hwintrinsiclistarm64.h +++ b/src/coreclr/jit/hwintrinsiclistarm64.h @@ -627,6 +627,7 @@ HARDWARE_INTRINSIC(Aes, PolynomialMultiplyWideningUpper, // Base Intrinsics HARDWARE_INTRINSIC(ArmBase, LeadingZeroCount, 0, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_clz, INS_clz, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoFloatingPointUsed) HARDWARE_INTRINSIC(ArmBase, ReverseElementBits, 0, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_rbit, INS_rbit, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed) +HARDWARE_INTRINSIC(ArmBase, Yield, 0, 0, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Special, HW_Flag_SpecialCodeGen|HW_Flag_SpecialImport) // *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** // ISA Function name SIMD size Number of arguments Instructions Category Flags diff --git a/src/coreclr/jit/hwintrinsiclistxarch.h b/src/coreclr/jit/hwintrinsiclistxarch.h index 7179e9854b382f..ce66b6e6906040 100644 --- a/src/coreclr/jit/hwintrinsiclistxarch.h +++ b/src/coreclr/jit/hwintrinsiclistxarch.h @@ -199,6 +199,7 @@ HARDWARE_INTRINSIC(Vector256, Xor, // X86Base Intrinsics HARDWARE_INTRINSIC(X86Base, BitScanForward, 0, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_bsf, INS_bsf, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(X86Base, BitScanReverse, 0, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_bsr, INS_bsr, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(X86Base, Pause, 0, 0, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Special, HW_Flag_NoContainment|HW_Flag_NoRMWSemantics) // *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** // ISA Function name SIMD size NumArg Instructions Category Flags diff --git a/src/coreclr/jit/hwintrinsicxarch.cpp b/src/coreclr/jit/hwintrinsicxarch.cpp index c0ed9a4de197f4..a565d7b3855447 100644 --- a/src/coreclr/jit/hwintrinsicxarch.cpp +++ b/src/coreclr/jit/hwintrinsicxarch.cpp @@ -491,6 +491,7 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, { case InstructionSet_Vector256: case InstructionSet_Vector128: + case InstructionSet_X86Base: return impBaseIntrinsic(intrinsic, clsHnd, method, sig, simdBaseJitType, retType, simdSize); case InstructionSet_SSE: return impSSEIntrinsic(intrinsic, method, sig); @@ -548,8 +549,13 @@ GenTree* Compiler::impBaseIntrinsic(NamedIntrinsic intrinsic, return nullptr; } - var_types simdBaseType = JitType2PreciseVarType(simdBaseJitType); - assert(varTypeIsArithmetic(simdBaseType)); + var_types simdBaseType = TYP_UNKNOWN; + + if (intrinsic != NI_X86Base_Pause) + { + simdBaseType = JitType2PreciseVarType(simdBaseJitType); + assert(varTypeIsArithmetic(simdBaseType)); + } switch (intrinsic) { @@ -1532,6 +1538,16 @@ GenTree* Compiler::impBaseIntrinsic(NamedIntrinsic intrinsic, break; } + case NI_X86Base_Pause: + { + assert(sig->numArgs == 0); + assert(JITtype2varType(sig->retType) == TYP_VOID); + assert(simdSize == 0); + + retNode = gtNewScalarHWIntrinsicNode(TYP_VOID, intrinsic); + break; + } + default: { return nullptr; @@ -1604,7 +1620,7 @@ GenTree* Compiler::impSSEIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HAND case NI_SSE_StoreFence: assert(sig->numArgs == 0); assert(JITtype2varType(sig->retType) == TYP_VOID); - retNode = gtNewSimdHWIntrinsicNode(TYP_VOID, intrinsic, CORINFO_TYPE_VOID, 0); + retNode = gtNewScalarHWIntrinsicNode(TYP_VOID, intrinsic); break; default: @@ -1667,7 +1683,7 @@ GenTree* Compiler::impSSE2Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HAN assert(JITtype2varType(sig->retType) == TYP_VOID); assert(simdSize == 0); - retNode = gtNewSimdHWIntrinsicNode(TYP_VOID, intrinsic, CORINFO_TYPE_VOID, simdSize); + retNode = gtNewScalarHWIntrinsicNode(TYP_VOID, intrinsic); break; } diff --git a/src/coreclr/jit/instrsarm64.h b/src/coreclr/jit/instrsarm64.h index 548c13f339469f..fbd74c1030522c 100644 --- a/src/coreclr/jit/instrsarm64.h +++ b/src/coreclr/jit/instrsarm64.h @@ -1563,6 +1563,9 @@ INST1(uxth, "uxth", 0, IF_DR_2H, 0x53003C00) INST1(nop, "nop", 0, IF_SN_0A, 0xD503201F) // nop SN_0A 1101010100000011 0010000000011111 D503 201F +INST1(yield, "yield", 0, IF_SN_0A, 0xD503203F) + // yield SN_0A 1101010100000011 0010000000111111 D503 203F + INST1(bkpt, "bkpt", 0, IF_SN_0A, 0xD43E0000) // brpt SN_0A 1101010000111110 0000000000000000 D43E 0000 0xF000 diff --git a/src/coreclr/jit/instrsxarch.h b/src/coreclr/jit/instrsxarch.h index 4dc1fffd098d51..17b94fc81d779e 100644 --- a/src/coreclr/jit/instrsxarch.h +++ b/src/coreclr/jit/instrsxarch.h @@ -640,11 +640,11 @@ INST2(rcl, "rcl", IUM_RW, 0x0010D2, BAD_CODE, INST2(rcl_1, "rcl", IUM_RW, 0x0010D0, 0x0010D0, Writes_OF | Writes_CF | Reads_CF ) INST2(rcl_N, "rcl", IUM_RW, 0x0010C0, 0x0010C0, Undefined_OF | Writes_CF - | Reads_CF ) + | Reads_CF ) INST2(rcr, "rcr", IUM_RW, 0x0018D2, BAD_CODE, Undefined_OF | Writes_CF | Reads_CF ) INST2(rcr_1, "rcr", IUM_RW, 0x0018D0, 0x0018D0, Writes_OF | Writes_CF - | Reads_CF ) + | Reads_CF ) INST2(rcr_N, "rcr", IUM_RW, 0x0018C0, 0x0018C0, Undefined_OF | Writes_CF | Reads_CF ) INST2(shl, "shl", IUM_RW, 0x0020D2, BAD_CODE, Undefined_OF | Writes_SF | Writes_ZF | Undefined_AF | Writes_PF | Writes_CF ) @@ -683,6 +683,7 @@ INST1(stosq, "stosq", IUM_RD, 0x00AB48, INST1(int3, "int3", IUM_RD, 0x0000CC, INS_FLAGS_None ) INST1(nop, "nop", IUM_RD, 0x000090, INS_FLAGS_None ) +INST1(pause, "pause", IUM_RD, 0x0090F3, INS_FLAGS_None ) INST1(lock, "lock", IUM_RD, 0x0000F0, INS_FLAGS_None ) INST1(leave, "leave", IUM_RD, 0x0000C9, INS_FLAGS_None ) diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/ArmBase.PlatformNotSupported.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/ArmBase.PlatformNotSupported.cs index af23cef761ad92..aab444638fda17 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/ArmBase.PlatformNotSupported.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/ArmBase.PlatformNotSupported.cs @@ -91,5 +91,11 @@ internal Arm64() { } /// A64: RBIT Wd, Wn /// public static uint ReverseElementBits(uint value) { throw new PlatformNotSupportedException(); } + + /// + /// A32: YIELD + /// A64: YIELD + /// + public static void Yield() { throw new PlatformNotSupportedException(); } } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/ArmBase.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/ArmBase.cs index 4900e618cf2dc3..dd378377f5c506 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/ArmBase.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/ArmBase.cs @@ -87,5 +87,11 @@ internal Arm64() { } /// A64: RBIT Wd, Wn /// public static uint ReverseElementBits(uint value) => ReverseElementBits(value); + + /// + /// A32: YIELD + /// A64: YIELD + /// + public static void Yield() => Yield(); } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/X86/X86Base.PlatformNotSupported.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/X86/X86Base.PlatformNotSupported.cs index 261ac82076ecb4..9ca497a5b8990b 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/X86/X86Base.PlatformNotSupported.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/X86/X86Base.PlatformNotSupported.cs @@ -67,9 +67,15 @@ internal X64() { } internal static uint BitScanReverse(uint value) { throw new PlatformNotSupportedException(); } /// - /// void __cpuidex(int cpuInfo[4], int function_id, int subfunction_id); + /// void __cpuidex (int cpuInfo[4], int function_id, int subfunction_id); /// CPUID /// public static (int Eax, int Ebx, int Ecx, int Edx) CpuId(int functionId, int subFunctionId) { throw new PlatformNotSupportedException(); } + + /// + /// void _mm_pause (void); + /// PAUSE + /// + public static void Pause() { throw new PlatformNotSupportedException(); } } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/X86/X86Base.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/X86/X86Base.cs index 7f7576be50ad25..c8b230b86166bc 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/X86/X86Base.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/X86/X86Base.cs @@ -69,7 +69,7 @@ internal X64() { } internal static uint BitScanReverse(uint value) => BitScanReverse(value); /// - /// void __cpuidex(int cpuInfo[4], int function_id, int subfunction_id); + /// void __cpuidex (int cpuInfo[4], int function_id, int subfunction_id); /// CPUID /// public static unsafe (int Eax, int Ebx, int Ecx, int Edx) CpuId(int functionId, int subFunctionId) @@ -78,5 +78,11 @@ public static unsafe (int Eax, int Ebx, int Ecx, int Edx) CpuId(int functionId, __cpuidex(cpuInfo, functionId, subFunctionId); return (cpuInfo[0], cpuInfo[1], cpuInfo[2], cpuInfo[3]); } + + /// + /// void _mm_pause (void); + /// PAUSE + /// + public static void Pause() => Pause(); } } diff --git a/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs b/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs index d4bb25487ad490..c71ed7d1fd624c 100644 --- a/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs +++ b/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs @@ -2840,6 +2840,7 @@ internal ArmBase() { } public static int LeadingZeroCount(uint value) { throw null; } public static int ReverseElementBits(int value) { throw null; } public static uint ReverseElementBits(uint value) { throw null; } + public static void Yield() { throw null; } public abstract partial class Arm64 { internal Arm64() { } @@ -3653,7 +3654,6 @@ internal X64() { } public static new bool IsSupported { get { throw null; } } } } - [System.CLSCompliantAttribute(false)] [System.Runtime.Versioning.RequiresPreviewFeaturesAttribute("AvxVnni is in preview.")] public abstract class AvxVnni : System.Runtime.Intrinsics.X86.Avx2 @@ -3674,7 +3674,6 @@ internal X64() { } public static new bool IsSupported { get { throw null; } } } } - [System.CLSCompliantAttribute(false)] public abstract partial class Bmi1 : System.Runtime.Intrinsics.X86.X86Base { @@ -4497,6 +4496,7 @@ public abstract partial class X86Base internal X86Base() { } public static bool IsSupported { get { throw null; } } public static (int Eax, int Ebx, int Ecx, int Edx) CpuId(int functionId, int subFunctionId) { throw null; } + public static void Pause() { throw null; } public abstract partial class X64 { internal X64() { } diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/ArmBase/Yield.cs b/src/tests/JIT/HardwareIntrinsics/Arm/ArmBase/Yield.cs new file mode 100644 index 00000000000000..51f0ded9d94536 --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/Arm/ArmBase/Yield.cs @@ -0,0 +1,34 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + class Program + { + const int Pass = 100; + const int Fail = 0; + + static unsafe int Main(string[] args) + { + int testResult = ArmBase.IsSupported ? Pass : Fail; + + try + { + ArmBase.Yield(); + } + catch (Exception e) + { + testResult = (ArmBase.IsSupported || (e is not PlatformNotSupportedException)) ? Fail : Pass; + } + + return testResult; + } + } +} diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/ArmBase/Yield_r.csproj b/src/tests/JIT/HardwareIntrinsics/Arm/ArmBase/Yield_r.csproj new file mode 100644 index 00000000000000..168f77656f101b --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/Arm/ArmBase/Yield_r.csproj @@ -0,0 +1,13 @@ + + + Exe + true + + + Embedded + + + + + + diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/ArmBase/Yield_ro.csproj b/src/tests/JIT/HardwareIntrinsics/Arm/ArmBase/Yield_ro.csproj new file mode 100644 index 00000000000000..ac75e1bac6ed05 --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/Arm/ArmBase/Yield_ro.csproj @@ -0,0 +1,13 @@ + + + Exe + true + + + Embedded + True + + + + + diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/Pause.cs b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/Pause.cs new file mode 100644 index 00000000000000..54223b04e66e89 --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/Pause.cs @@ -0,0 +1,34 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; + +namespace IntelHardwareIntrinsicTest +{ + class Program + { + const int Pass = 100; + const int Fail = 0; + + static unsafe int Main(string[] args) + { + int testResult = X86Base.IsSupported ? Pass : Fail; + + try + { + X86Base.Pause(); + } + catch (Exception e) + { + testResult = (X86Base.IsSupported || (e is not PlatformNotSupportedException)) ? Fail : Pass; + } + + return testResult; + } + } +} diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/Pause_r.csproj b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/Pause_r.csproj new file mode 100644 index 00000000000000..9b005d1608375e --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/Pause_r.csproj @@ -0,0 +1,13 @@ + + + Exe + true + + + Embedded + + + + + + diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/Pause_ro.csproj b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/Pause_ro.csproj new file mode 100644 index 00000000000000..8943a9d7d3ebac --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/Pause_ro.csproj @@ -0,0 +1,13 @@ + + + Exe + true + + + Embedded + True + + + + +