From a1cd1f8edecef19e397cafffc22ed96d03728f22 Mon Sep 17 00:00:00 2001 From: Adam Date: Wed, 17 Jun 2026 15:05:45 -0700 Subject: [PATCH 01/24] Implement Wasm codegen for Vector128.Create with const operands Enable Wasm SIMD ISA for use in the JIT --- src/coreclr/jit/codegen.h | 3 + src/coreclr/jit/codegenwasm.cpp | 19 +++ src/coreclr/jit/compiler.cpp | 7 + src/coreclr/jit/hwintrinsiclistwasm.h | 2 +- src/coreclr/jit/hwintrinsicwasm.cpp | 152 +++++++++++++++++- .../tools/Common/InstructionSetHelpers.cs | 5 + 6 files changed, 185 insertions(+), 3 deletions(-) diff --git a/src/coreclr/jit/codegen.h b/src/coreclr/jit/codegen.h index 24657a2232acc5..837ea325728b40 100644 --- a/src/coreclr/jit/codegen.h +++ b/src/coreclr/jit/codegen.h @@ -795,6 +795,9 @@ class CodeGen final : public CodeGenInterface #if defined(TARGET_WASM) void genCodeForConstant(GenTree* treeNode); +#if defined(FEATURE_SIMD) + void genCodeForVectorConstant(GenTree* treeNode); +#endif void genCatchArg(GenTree* treeNode); #endif diff --git a/src/coreclr/jit/codegenwasm.cpp b/src/coreclr/jit/codegenwasm.cpp index 40b7e5a41b1291..6883176dbc988c 100644 --- a/src/coreclr/jit/codegenwasm.cpp +++ b/src/coreclr/jit/codegenwasm.cpp @@ -922,6 +922,12 @@ void CodeGen::genCodeForTreeNode(GenTree* treeNode) genCkfinite(treeNode); break; +#if defined(FEATURE_SIMD) + case GT_CNS_VEC: + genCodeForVectorConstant(treeNode); + break; +#endif // FEATURE_SIMD + default: #ifdef DEBUG if (JitConfig.JitWasmNyiToR2RUnsupported()) @@ -1801,6 +1807,19 @@ void CodeGen::genCodeForConstant(GenTree* treeNode) WasmProduceReg(treeNode); } +#ifdef FEATURE_SIMD +void CodeGen::genCodeForVectorConstant(GenTree* treeNode) +{ + assert(treeNode->IsCnsVec()); + GenTreeVecCon* vecCon = treeNode->AsVecCon(); + + // There is only one type variant for v128.const, v128.const + // and the bytes are reinterpreted according to whichever operation consumes the value. + GetEmitter()->emitIns_V128Imm(INS_v128_const, vecCon->gtSimd16Val.u8); + WasmProduceReg(treeNode); +} +#endif + //------------------------------------------------------------------------ // genCodeForShift: Generate code for a shift or rotate operator // diff --git a/src/coreclr/jit/compiler.cpp b/src/coreclr/jit/compiler.cpp index f78d4d33e60457..640c5a94418320 100644 --- a/src/coreclr/jit/compiler.cpp +++ b/src/coreclr/jit/compiler.cpp @@ -2024,6 +2024,13 @@ void Compiler::compSetProcessor() // Add virtual vector ISAs. These are both supported as part of the required baseline. instructionSetFlags.AddInstructionSet(InstructionSet_Vector64); instructionSetFlags.AddInstructionSet(InstructionSet_Vector128); +#elif defined(TARGET_WASM) + // Ensure required baseline ISAs are supported in JIT code, even if not passed in by the VM. + instructionSetFlags.AddInstructionSet(InstructionSet_WasmBase); + instructionSetFlags.AddInstructionSet(InstructionSet_PackedSimd); + + // Add virtual vector ISA. Vector128 is part of the required Wasm SIMD baseline. + instructionSetFlags.AddInstructionSet(InstructionSet_Vector128); #endif // TARGET_ARM64 assert(instructionSetFlags.Equals(EnsureInstructionSetFlagsAreValid(instructionSetFlags))); diff --git a/src/coreclr/jit/hwintrinsiclistwasm.h b/src/coreclr/jit/hwintrinsiclistwasm.h index 872766bc39f685..ee62e4efadba16 100644 --- a/src/coreclr/jit/hwintrinsiclistwasm.h +++ b/src/coreclr/jit/hwintrinsiclistwasm.h @@ -34,7 +34,7 @@ HARDWARE_INTRINSIC(Vector128, AsVector128Unsafe, HARDWARE_INTRINSIC(Vector128, AsVector2, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector128, AsVector3, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMD, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector128, AsVector4, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) -HARDWARE_INTRINSIC(Vector128, Create, 16, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) +HARDWARE_INTRINSIC(Vector128, Create, 16, -1, {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_InvalidNodeId) HARDWARE_INTRINSIC(Vector128, CreateScalar, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector128, CreateScalarUnsafe, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector128, Dot, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) diff --git a/src/coreclr/jit/hwintrinsicwasm.cpp b/src/coreclr/jit/hwintrinsicwasm.cpp index bd6c38fdb9d984..02663de655100c 100644 --- a/src/coreclr/jit/hwintrinsicwasm.cpp +++ b/src/coreclr/jit/hwintrinsicwasm.cpp @@ -76,8 +76,156 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, unsigned simdSize, bool mustExpand) { - NYI_WASM_SIMD("impSpecialIntrinsic"); - return nullptr; + assert(varTypeIsArithmetic(simdBaseType)); + + GenTree* retNode = nullptr; + GenTree* op1 = nullptr; + + switch (intrinsic) + { + case NI_Vector128_Create: + { + // Vector128.Create(T) -> broadcast/"splat" one T value to all elements + // Vector128.Create(T, T, ..., T) -> pack N scalar T values + // + // For either form, if T is a const we can leverage a GenTreeVecCon and map directly to v128.const + if (sig->numArgs == 1) + { + op1 = impPopStack().val; + retNode = gtNewSimdCreateBroadcastNode(retType, op1, simdBaseType, simdSize); + break; + } + + uint32_t simdLength = getSIMDVectorLength(simdSize, simdBaseType); + assert(sig->numArgs == simdLength); + + bool isConstant = true; + + if (varTypeIsFloating(simdBaseType)) + { + for (uint32_t index = 0; index < sig->numArgs; index++) + { + if (!impStackTop(index).val->IsCnsFltOrDbl()) + { + isConstant = false; + break; + } + } + } + else + { + assert(varTypeIsIntegral(simdBaseType)); + + for (uint32_t index = 0; index < sig->numArgs; index++) + { + if (!impStackTop(index).val->IsIntegralConst()) + { + isConstant = false; + break; + } + } + } + + if (isConstant) + { + assert(simdSize == 16); + + GenTreeVecCon* vecCon = gtNewVconNode(retType); + + switch (simdBaseType) + { + case TYP_BYTE: + case TYP_UBYTE: + { + for (uint32_t index = 0; index < sig->numArgs; index++) + { + uint8_t cnsVal = static_cast(impPopStack().val->AsIntConCommon()->IntegralValue()); + vecCon->gtSimdVal.u8[simdLength - 1 - index] = cnsVal; + } + break; + } + + case TYP_SHORT: + case TYP_USHORT: + { + for (uint32_t index = 0; index < sig->numArgs; index++) + { + uint16_t cnsVal = + static_cast(impPopStack().val->AsIntConCommon()->IntegralValue()); + vecCon->gtSimdVal.u16[simdLength - 1 - index] = cnsVal; + } + break; + } + + case TYP_INT: + case TYP_UINT: + { + for (uint32_t index = 0; index < sig->numArgs; index++) + { + uint32_t cnsVal = + static_cast(impPopStack().val->AsIntConCommon()->IntegralValue()); + vecCon->gtSimdVal.u32[simdLength - 1 - index] = cnsVal; + } + break; + } + + case TYP_LONG: + case TYP_ULONG: + { + for (uint32_t index = 0; index < sig->numArgs; index++) + { + uint64_t cnsVal = + static_cast(impPopStack().val->AsIntConCommon()->IntegralValue()); + vecCon->gtSimdVal.u64[simdLength - 1 - index] = cnsVal; + } + break; + } + + case TYP_FLOAT: + { + for (uint32_t index = 0; index < sig->numArgs; index++) + { + float cnsVal = static_cast(impPopStack().val->AsDblCon()->DconValue()); + vecCon->gtSimdVal.f32[simdLength - 1 - index] = cnsVal; + } + break; + } + + case TYP_DOUBLE: + { + for (uint32_t index = 0; index < sig->numArgs; index++) + { + double cnsVal = static_cast(impPopStack().val->AsDblCon()->DconValue()); + vecCon->gtSimdVal.f64[simdLength - 1 - index] = cnsVal; + } + break; + } + + default: + { + unreached(); + } + } + + retNode = vecCon; + break; + } + + // TODO-WASM-SIMD: Build a GT_HWINTRINSIC node packing N non-constant operands + // (mirroring the arm64/xarch IntrinsicNodeBuilder path) once WASM SIMD lowering + // and codegen for Vector128.Create are implemented. + NYI_WASM_SIMD("Vector128.Create with non-constant operands"); + break; + } + + default: + { + NYI_WASM_SIMD("impSpecialIntrinsic"); + break; + } + } + + return retNode; } //------------------------------------------------------------------------ diff --git a/src/coreclr/tools/Common/InstructionSetHelpers.cs b/src/coreclr/tools/Common/InstructionSetHelpers.cs index b1ff24e8b804f7..106763c0828323 100644 --- a/src/coreclr/tools/Common/InstructionSetHelpers.cs +++ b/src/coreclr/tools/Common/InstructionSetHelpers.cs @@ -94,6 +94,11 @@ public static InstructionSetSupport ConfigureInstructionSetSupport(string instru } } } + else if (targetArchitecture == TargetArchitecture.Wasm32) + { + instructionSetSupportBuilder.AddSupportedInstructionSet("base"); + instructionSetSupportBuilder.AddSupportedInstructionSet("simd128"); + } bool throttleAvx512 = false; From f4fd2fe6ec05765b41283b9dcd6fb89204c1373a Mon Sep 17 00:00:00 2001 From: Adam Date: Thu, 18 Jun 2026 14:14:11 -0700 Subject: [PATCH 02/24] Fix categories and flags for some Vector128 Wasm hardware intrinsics --- src/coreclr/jit/hwintrinsiclistwasm.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/coreclr/jit/hwintrinsiclistwasm.h b/src/coreclr/jit/hwintrinsiclistwasm.h index ee62e4efadba16..edd58132cfcd55 100644 --- a/src/coreclr/jit/hwintrinsiclistwasm.h +++ b/src/coreclr/jit/hwintrinsiclistwasm.h @@ -39,12 +39,12 @@ HARDWARE_INTRINSIC(Vector128, CreateScalar, HARDWARE_INTRINSIC(Vector128, CreateScalarUnsafe, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector128, Dot, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector128, ExtractMostSignificantBits, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) -HARDWARE_INTRINSIC(Vector128, GetElement, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_InvalidNodeId) +HARDWARE_INTRINSIC(Vector128, GetElement, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector128, Shuffle, 16, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector128, ShuffleNative, 16, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector128, ShuffleNativeFallback, 16, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) -HARDWARE_INTRINSIC(Vector128, ToScalar, 16, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_InvalidNodeId) -HARDWARE_INTRINSIC(Vector128, WithElement, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) +HARDWARE_INTRINSIC(Vector128, ToScalar, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMD, HW_Flag_InvalidNodeId|HW_Flag_BaseTypeFromFirstArg|HW_Flag_ReturnsScalarT) +HARDWARE_INTRINSIC(Vector128, WithElement, 16, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector128, WithLower, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector128, WithUpper, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector128, get_AllBitsSet, 16, 0, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) From 48e0731e3d6d42f15e67431a5ae9d196d6db2580 Mon Sep 17 00:00:00 2001 From: Adam Date: Fri, 19 Jun 2026 15:07:57 -0700 Subject: [PATCH 03/24] Checkpoint: PackedSimd.Add now compiles as an intrinsic (with const vector operands) --- src/coreclr/jit/codegenwasm.cpp | 10 +- src/coreclr/jit/hwintrinsic.cpp | 6 +- src/coreclr/jit/hwintrinsic.h | 94 ++++++++++++++++++- src/coreclr/jit/hwintrinsiccodegenwasm.cpp | 34 ++++++- src/coreclr/jit/hwintrinsiclistwasm.h | 4 + src/coreclr/jit/instr.cpp | 6 ++ src/coreclr/jit/lowerwasm.cpp | 13 ++- .../System.Private.CoreLib.Shared.projitems | 1 + 8 files changed, 158 insertions(+), 10 deletions(-) diff --git a/src/coreclr/jit/codegenwasm.cpp b/src/coreclr/jit/codegenwasm.cpp index 680ce8740a9429..b5c76c3b966ce9 100644 --- a/src/coreclr/jit/codegenwasm.cpp +++ b/src/coreclr/jit/codegenwasm.cpp @@ -746,6 +746,12 @@ void CodeGen::genCodeForTreeNode(GenTree* treeNode) return; } + if (treeNode->OperIsHWIntrinsic()) + { + genHWIntrinsic(treeNode->AsHWIntrinsic()); + return; + } + switch (treeNode->OperGet()) { case GT_ADD: @@ -2490,10 +2496,6 @@ void CodeGen::genCodeForLclVar(GenTreeLclVar* tree) if (!varDsc->lvIsRegCandidate()) { var_types type = varDsc->GetRegisterType(tree); - if (type == TYP_SIMD16) - { - NYI_WASM_SIMD("SIMD16 local load"); - } GetEmitter()->emitIns_I(INS_local_get, EA_PTRSIZE, GetFramePointerRegIndex()); GetEmitter()->emitIns_S(ins_Load(type), emitTypeSize(type), tree->GetLclNum(), 0); diff --git a/src/coreclr/jit/hwintrinsic.cpp b/src/coreclr/jit/hwintrinsic.cpp index 9ac8e28620bf92..94919027de442d 100644 --- a/src/coreclr/jit/hwintrinsic.cpp +++ b/src/coreclr/jit/hwintrinsic.cpp @@ -1048,8 +1048,8 @@ static const HWIntrinsicIsaRange hwintrinsicIsaRangeArray[] = { { NI_Illegal, NI_Illegal }, // SveSm4_Arm64 #elif defined(TARGET_WASM) { NI_Illegal, NI_Illegal }, // WasmBase - { NI_Illegal, NI_Illegal }, // PackedSimd - { FIRST_NI_Vector128, LAST_NI_Vector128 }, // Vector128 + { FIRST_NI_PackedSimd, LAST_NI_PackedSimd }, // PackedSimd + { FIRST_NI_Vector128, LAST_NI_Vector128 }, // Vector128 // TODO-WASM: Add PackedSimd intrinsic ranges #else #error Unsupported platform @@ -2275,6 +2275,8 @@ GenTree* Compiler::impHWIntrinsic(NamedIntrinsic intrinsic, if ((simdSize != 8) && (simdSize != 16) && (simdSize != SIZE_UNKNOWN)) #elif defined(TARGET_XARCH) if ((simdSize != 16) && (simdSize != 32) && (simdSize != 64)) +#elif defined(TARGET_WASM) + if (simdSize != 16) #endif // TARGET_* { assert(!"Unexpected SIMD size"); diff --git a/src/coreclr/jit/hwintrinsic.h b/src/coreclr/jit/hwintrinsic.h index e993f91b3a3399..30a04b9da4873a 100644 --- a/src/coreclr/jit/hwintrinsic.h +++ b/src/coreclr/jit/hwintrinsic.h @@ -1463,8 +1463,100 @@ struct HWIntrinsic final } } }; +#else if defined(TARGET_WASM) +struct HWIntrinsic final +{ + HWIntrinsic(const GenTreeHWIntrinsic* node) + : op1(nullptr) + , op2(nullptr) + , op3(nullptr) + , numOperands(0) + , baseType(TYP_UNDEF) + { + assert(node != nullptr); -#endif // TARGET_ARM64 + id = node->GetHWIntrinsicId(); + category = HWIntrinsicInfo::lookupCategory(id); + + assert(HWIntrinsicInfo::RequiresCodegen(id)); + + InitializeOperands(node); + InitializeBaseType(node); + } + + bool codeGenIsTableDriven() const + { + bool isTableDrivenCategory = category != HW_Category_Helper; + bool isTableDrivenFlag = !HWIntrinsicInfo::HasSpecialCodegen(id); + + return isTableDrivenCategory && isTableDrivenFlag; + } + + NamedIntrinsic id; + HWIntrinsicCategory category; + GenTree* op1; + GenTree* op2; + GenTree* op3; + size_t numOperands; + var_types baseType; + +private: + void InitializeOperands(const GenTreeHWIntrinsic* node) + { + numOperands = node->GetOperandCount(); + + switch (numOperands) + { + case 3: + op3 = node->Op(3); + FALLTHROUGH; + case 2: + op2 = node->Op(2); + FALLTHROUGH; + case 1: + op1 = node->Op(1); + FALLTHROUGH; + case 0: + break; + + default: + unreached(); + } + } + + void InitializeBaseType(const GenTreeHWIntrinsic* node) + { + baseType = node->GetSimdBaseType(); + + if (baseType == TYP_UNKNOWN) + { + assert((category == HW_Category_Scalar) || (category == HW_Category_Special)); + + if (HWIntrinsicInfo::BaseTypeFromFirstArg(id)) + { + assert(op1 != nullptr); + baseType = op1->TypeGet(); + } + else if (HWIntrinsicInfo::BaseTypeFromSecondArg(id)) + { + // TODO-WASM: This case can likely be dropped + assert(op2 != nullptr); + baseType = op2->TypeGet(); + } + else + { + baseType = node->TypeGet(); + } + + if (category == HW_Category_Scalar) + { + baseType = genActualType(baseType); + } + } + } +}; + +#endif // TARGET_WASM #endif // FEATURE_HW_INTRINSICS diff --git a/src/coreclr/jit/hwintrinsiccodegenwasm.cpp b/src/coreclr/jit/hwintrinsiccodegenwasm.cpp index 245cf1f38c9c9a..f7c217396dae39 100644 --- a/src/coreclr/jit/hwintrinsiccodegenwasm.cpp +++ b/src/coreclr/jit/hwintrinsiccodegenwasm.cpp @@ -26,7 +26,39 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX // void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node) { - NYI_WASM_SIMD("genHWIntrinsic"); + // emitIns_v128_Imm + // emitIns_Lane + // emitIns_Memarg_Lane + + const HWIntrinsic info(node); + genConsumeMultiOpOperands(node); + + instruction ins; + emitAttr emitSize; + if (info.category == HW_Category_SIMD) + { + emitSize = emitTypeSize(info.baseType); + } + else + { + NYI_WASM_SIMD("genHWIntrinsic: non-SIMD category"); + } + + if (info.codeGenIsTableDriven()) + { + ins = HWIntrinsicInfo::lookupIns(info.id, info.baseType, m_compiler); + assert(ins != INS_invalid); + if (info.category == HW_Category_SIMD) + { + GetEmitter()->emitIns(ins); + } + else + { + NYI_WASM_SIMD("!HW_Category_SIMD"); + } + } + + WasmProduceReg(node); } #endif // FEATURE_HW_INTRINSICS diff --git a/src/coreclr/jit/hwintrinsiclistwasm.h b/src/coreclr/jit/hwintrinsiclistwasm.h index edd58132cfcd55..bcb978a353096c 100644 --- a/src/coreclr/jit/hwintrinsiclistwasm.h +++ b/src/coreclr/jit/hwintrinsiclistwasm.h @@ -64,6 +64,10 @@ HARDWARE_INTRINSIC(Vector128, op_Inequality, HARDWARE_INTRINSIC(Vector128, op_UnaryPlus, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) #define LAST_NI_Vector128 NI_Vector128_op_UnaryPlus + +#define FIRST_NI_PackedSimd NI_PackedSimd_Add +HARDWARE_INTRINSIC(PackedSimd, Add, 16, 2, {INS_i8x16_add, INS_i8x16_add, INS_i16x8_add, INS_i16x8_add, INS_i32x4_add, INS_i32x4_add, INS_i64x2_add, INS_i64x2_add, INS_f32x4_add, INS_f64x2_add}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_Commutative) +#define LAST_NI_PackedSimd NI_PackedSimd_Add #endif // FEATURE_HW_INTRINSICS #undef HARDWARE_INTRINSIC diff --git a/src/coreclr/jit/instr.cpp b/src/coreclr/jit/instr.cpp index 500e94832339cc..5dd0272329f865 100644 --- a/src/coreclr/jit/instr.cpp +++ b/src/coreclr/jit/instr.cpp @@ -2116,6 +2116,10 @@ instruction CodeGenInterface::ins_Load(var_types srcType, bool aligned /*=false* return INS_f32_load; case TYP_DOUBLE: return INS_f64_load; +#if FEATURE_SIMD + case TYP_SIMD16: + return INS_v128_load; +#endif default: NYI_WASM("ins_Load"); return INS_none; @@ -2525,6 +2529,8 @@ instruction CodeGenInterface::ins_Store(var_types dstType, bool aligned /*=false return INS_f32_store; case TYP_DOUBLE: return INS_f64_store; + case TYP_SIMD16: + return INS_v128_store; default: NYI_WASM("ins_Store"); return INS_none; diff --git a/src/coreclr/jit/lowerwasm.cpp b/src/coreclr/jit/lowerwasm.cpp index 78cda8482f64d6..61b4d5174bd407 100644 --- a/src/coreclr/jit/lowerwasm.cpp +++ b/src/coreclr/jit/lowerwasm.cpp @@ -820,8 +820,17 @@ void Lowering::AfterLowerArgsForCall(GenTreeCall* call) // GenTree* Lowering::LowerHWIntrinsic(GenTreeHWIntrinsic* node) { - NYI_WASM_SIMD("Lowering::LowerHWIntrinsic"); - return node; + HWIntrinsicCategory category = HWIntrinsicInfo::lookupCategory(node->GetHWIntrinsicId()); + switch (category) + { + case HWIntrinsicCategory::HW_Category_SIMD: + { + break; + } + default: + NYI_WASM_SIMD("Lowering::LowerHWIntrinsic"); + } + return node->gtNext; } //---------------------------------------------------------------------------------------------- diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems index 85fd4ebdca7aee..a067ae4b0b150f 100644 --- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems +++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems @@ -16,6 +16,7 @@ true true true + true false true false From 7bf550ba9e695a3855602b05f31651f3b912ca01 Mon Sep 17 00:00:00 2001 From: Adam Date: Fri, 19 Jun 2026 16:31:07 -0700 Subject: [PATCH 04/24] Add a few more PackedSimd intrinsics --- src/coreclr/jit/hwintrinsiclistwasm.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/coreclr/jit/hwintrinsiclistwasm.h b/src/coreclr/jit/hwintrinsiclistwasm.h index bcb978a353096c..53abb3fa8b16c3 100644 --- a/src/coreclr/jit/hwintrinsiclistwasm.h +++ b/src/coreclr/jit/hwintrinsiclistwasm.h @@ -66,8 +66,10 @@ HARDWARE_INTRINSIC(Vector128, op_UnaryPlus, #define LAST_NI_Vector128 NI_Vector128_op_UnaryPlus #define FIRST_NI_PackedSimd NI_PackedSimd_Add -HARDWARE_INTRINSIC(PackedSimd, Add, 16, 2, {INS_i8x16_add, INS_i8x16_add, INS_i16x8_add, INS_i16x8_add, INS_i32x4_add, INS_i32x4_add, INS_i64x2_add, INS_i64x2_add, INS_f32x4_add, INS_f64x2_add}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_Commutative) -#define LAST_NI_PackedSimd NI_PackedSimd_Add +HARDWARE_INTRINSIC(PackedSimd, Add, 16, 2, {INS_i8x16_add, INS_i8x16_add, INS_i16x8_add, INS_i16x8_add, INS_i32x4_add, INS_i32x4_add, INS_i64x2_add, INS_i64x2_add, INS_f32x4_add, INS_f64x2_add}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_Commutative) +HARDWARE_INTRINSIC(PackedSimd, Multiply, 16, 2, {INS_invalid, INS_invalid, INS_i16x8_mul, INS_i16x8_mul, INS_i32x4_mul, INS_i32x4_mul, INS_i64x2_mul, INS_i64x2_mul, INS_f32x4_mul, INS_f64x2_mul}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_Commutative) +HARDWARE_INTRINSIC(PackedSimd, Subtract, 16, 2, {INS_i8x16_sub, INS_i8x16_sub, INS_i16x8_sub, INS_i16x8_sub, INS_i32x4_sub, INS_i32x4_sub, INS_i64x2_sub, INS_i64x2_sub, INS_f32x4_sub, INS_f64x2_sub}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) +#define LAST_NI_PackedSimd NI_PackedSimd_Subtract #endif // FEATURE_HW_INTRINSICS #undef HARDWARE_INTRINSIC From 50f2359ba7b2c77bdb130806cad99f4231575a0f Mon Sep 17 00:00:00 2001 From: Adam Date: Sat, 20 Jun 2026 15:43:42 -0700 Subject: [PATCH 05/24] Add table-driven codegen entries for (simd), (simd, simd) and (simd, simd, simd) param type operations (no integer operands or immediates supported yet) --- src/coreclr/jit/hwintrinsiclistwasm.h | 58 ++++++++++++++++++++++++--- 1 file changed, 53 insertions(+), 5 deletions(-) diff --git a/src/coreclr/jit/hwintrinsiclistwasm.h b/src/coreclr/jit/hwintrinsiclistwasm.h index 53abb3fa8b16c3..e0bd01ff896f1f 100644 --- a/src/coreclr/jit/hwintrinsiclistwasm.h +++ b/src/coreclr/jit/hwintrinsiclistwasm.h @@ -65,11 +65,59 @@ HARDWARE_INTRINSIC(Vector128, op_UnaryPlus, #define LAST_NI_Vector128 NI_Vector128_op_UnaryPlus -#define FIRST_NI_PackedSimd NI_PackedSimd_Add -HARDWARE_INTRINSIC(PackedSimd, Add, 16, 2, {INS_i8x16_add, INS_i8x16_add, INS_i16x8_add, INS_i16x8_add, INS_i32x4_add, INS_i32x4_add, INS_i64x2_add, INS_i64x2_add, INS_f32x4_add, INS_f64x2_add}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_Commutative) -HARDWARE_INTRINSIC(PackedSimd, Multiply, 16, 2, {INS_invalid, INS_invalid, INS_i16x8_mul, INS_i16x8_mul, INS_i32x4_mul, INS_i32x4_mul, INS_i64x2_mul, INS_i64x2_mul, INS_f32x4_mul, INS_f64x2_mul}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_Commutative) -HARDWARE_INTRINSIC(PackedSimd, Subtract, 16, 2, {INS_i8x16_sub, INS_i8x16_sub, INS_i16x8_sub, INS_i16x8_sub, INS_i32x4_sub, INS_i32x4_sub, INS_i64x2_sub, INS_i64x2_sub, INS_f32x4_sub, INS_f64x2_sub}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) -#define LAST_NI_PackedSimd NI_PackedSimd_Subtract +#define FIRST_NI_PackedSimd NI_PackedSimd_Abs +HARDWARE_INTRINSIC(PackedSimd, Abs, 16, 1, {INS_i8x16_abs, INS_invalid, INS_i16x8_abs, INS_invalid, INS_i32x4_abs, INS_invalid, INS_i64x2_abs, INS_invalid, INS_f32x4_abs, INS_f64x2_abs}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(PackedSimd, Add, 16, 2, {INS_i8x16_add, INS_i8x16_add, INS_i16x8_add, INS_i16x8_add, INS_i32x4_add, INS_i32x4_add, INS_i64x2_add, INS_i64x2_add, INS_f32x4_add, INS_f64x2_add}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_Commutative) +HARDWARE_INTRINSIC(PackedSimd, AddPairwiseWidening, 16, 1, {INS_i16x8_extadd_pairwise_s_i8x16, INS_i16x8_extadd_pairwise_u_i8x16, INS_i32x4_extadd_pairwise_s_i16x8, INS_i32x4_extadd_pairwise_u_i16x8, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(PackedSimd, AddSaturate, 16, 2, {INS_i8x16_add_sat_s, INS_i8x16_add_sat_u, INS_i16x8_add_sat_s, INS_i16x8_add_sat_u, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_Commutative) +HARDWARE_INTRINSIC(PackedSimd, AllTrue, 16, 1, {INS_i8x16_all_true, INS_i8x16_all_true, INS_i16x8_all_true, INS_i16x8_all_true, INS_i32x4_all_true, INS_i32x4_all_true, INS_i64x2_all_true, INS_i64x2_all_true, INS_invalid, INS_invalid}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(PackedSimd, And, 16, 2, {INS_v128_and, INS_v128_and, INS_v128_and, INS_v128_and, INS_v128_and, INS_v128_and, INS_v128_and, INS_v128_and, INS_v128_and, INS_v128_and}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_Commutative) +HARDWARE_INTRINSIC(PackedSimd, AndNot, 16, 2, {INS_v128_andnot, INS_v128_andnot, INS_v128_andnot, INS_v128_andnot, INS_v128_andnot, INS_v128_andnot, INS_v128_andnot, INS_v128_andnot, INS_v128_andnot, INS_v128_andnot}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(PackedSimd, AnyTrue, 16, 1, {INS_v128_any_true, INS_v128_any_true, INS_v128_any_true, INS_v128_any_true, INS_v128_any_true, INS_v128_any_true, INS_v128_any_true, INS_v128_any_true, INS_v128_any_true, INS_v128_any_true}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(PackedSimd, AverageRounded, 16, 2, {INS_invalid, INS_i8x16_avgr_u, INS_invalid, INS_i16x8_avgr_u, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_Commutative) +HARDWARE_INTRINSIC(PackedSimd, Bitmask, 16, 1, {INS_i8x16_bitmask, INS_i8x16_bitmask, INS_i16x8_bitmask, INS_i16x8_bitmask, INS_i32x4_bitmask, INS_i32x4_bitmask, INS_i64x2_bitmask, INS_i64x2_bitmask, INS_invalid, INS_invalid}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(PackedSimd, BitwiseSelect, 16, 3, {INS_v128_bitselect, INS_v128_bitselect, INS_v128_bitselect, INS_v128_bitselect, INS_v128_bitselect, INS_v128_bitselect, INS_v128_bitselect, INS_v128_bitselect, INS_v128_bitselect, INS_v128_bitselect}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(PackedSimd, Ceiling, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_f32x4_ceil, INS_f64x2_ceil}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(PackedSimd, CompareEqual, 16, 2, {INS_i8x16_eq, INS_i8x16_eq, INS_i16x8_eq, INS_i16x8_eq, INS_i32x4_eq, INS_i32x4_eq, INS_i64x2_eq, INS_i64x2_eq, INS_f32x4_eq, INS_f64x2_eq}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_Commutative|HW_Flag_ReturnsPerElementMask) +// TODO-WASM-SIMD: ULONG slot below is INS_invalid because the WASM SIMD spec has no unsigned i64x2 compare (lt_u/le_u/gt_u/ge_u). Requires special codegen (e.g., XOR sign bit + signed compare) to support Vector128 ordered compares. Same applies to CompareGreaterThanOrEqual/CompareLessThan/CompareLessThanOrEqual below. +HARDWARE_INTRINSIC(PackedSimd, CompareGreaterThan, 16, 2, {INS_i8x16_gt_s, INS_i8x16_gt_u, INS_i16x8_gt_s, INS_i16x8_gt_u, INS_i32x4_gt_s, INS_i32x4_gt_u, INS_i64x2_gt_s, INS_invalid, INS_f32x4_gt, INS_f64x2_gt}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_ReturnsPerElementMask) +HARDWARE_INTRINSIC(PackedSimd, CompareGreaterThanOrEqual, 16, 2, {INS_i8x16_ge_s, INS_i8x16_ge_u, INS_i16x8_ge_s, INS_i16x8_ge_u, INS_i32x4_ge_s, INS_i32x4_ge_u, INS_i64x2_ge_s, INS_invalid, INS_f32x4_ge, INS_f64x2_ge}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_ReturnsPerElementMask) +HARDWARE_INTRINSIC(PackedSimd, CompareLessThan, 16, 2, {INS_i8x16_lt_s, INS_i8x16_lt_u, INS_i16x8_lt_s, INS_i16x8_lt_u, INS_i32x4_lt_s, INS_i32x4_lt_u, INS_i64x2_lt_s, INS_invalid, INS_f32x4_lt, INS_f64x2_lt}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_ReturnsPerElementMask) +HARDWARE_INTRINSIC(PackedSimd, CompareLessThanOrEqual, 16, 2, {INS_i8x16_le_s, INS_i8x16_le_u, INS_i16x8_le_s, INS_i16x8_le_u, INS_i32x4_le_s, INS_i32x4_le_u, INS_i64x2_le_s, INS_invalid, INS_f32x4_le, INS_f64x2_le}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_ReturnsPerElementMask) +HARDWARE_INTRINSIC(PackedSimd, CompareNotEqual, 16, 2, {INS_i8x16_ne, INS_i8x16_ne, INS_i16x8_ne, INS_i16x8_ne, INS_i32x4_ne, INS_i32x4_ne, INS_i64x2_ne, INS_i64x2_ne, INS_f32x4_ne, INS_f64x2_ne}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_Commutative|HW_Flag_ReturnsPerElementMask) +HARDWARE_INTRINSIC(PackedSimd, ConvertNarrowingSaturateSigned, 16, 2, {INS_invalid, INS_invalid, INS_i8x16_narrow_i16x8_s, INS_invalid, INS_i16x8_narrow_i32x4_s, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(PackedSimd, ConvertNarrowingSaturateUnsigned, 16, 2, {INS_invalid, INS_invalid, INS_i8x16_narrow_i16x8_u, INS_invalid, INS_i16x8_narrow_i32x4_u, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(PackedSimd, ConvertToDoubleLower, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_f64x2_convert_low_s_i32x4, INS_f64x2_convert_low_u_i32x4, INS_invalid, INS_invalid, INS_f64x2_promote_low_f32x4, INS_invalid}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(PackedSimd, ConvertToInt32Saturate, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_i32x4_trunc_sat_s_f32x4, INS_i32x4_trunc_sat_s_f64x2_zero}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(PackedSimd, ConvertToSingle, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_f32x4_convert_s_i32x4, INS_f32x4_convert_u_i32x4, INS_invalid, INS_invalid, INS_invalid, INS_f32x4_demote_f64x2_zero}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(PackedSimd, ConvertToUInt32Saturate, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_i32x4_trunc_sat_u_f32x4, INS_i32x4_trunc_sat_u_f64x2_zero}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(PackedSimd, Divide, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_f32x4_div, INS_f64x2_div}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(PackedSimd, Dot, 16, 2, {INS_invalid, INS_invalid, INS_i32x4_dot_i16x8_s, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(PackedSimd, Floor, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_f32x4_floor, INS_f64x2_floor}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(PackedSimd, Max, 16, 2, {INS_i8x16_max_s, INS_i8x16_max_u, INS_i16x8_max_s, INS_i16x8_max_u, INS_i32x4_max_s, INS_i32x4_max_u, INS_invalid, INS_invalid, INS_f32x4_max, INS_f64x2_max}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_Commutative) +HARDWARE_INTRINSIC(PackedSimd, Min, 16, 2, {INS_i8x16_min_s, INS_i8x16_min_u, INS_i16x8_min_s, INS_i16x8_min_u, INS_i32x4_min_s, INS_i32x4_min_u, INS_invalid, INS_invalid, INS_f32x4_min, INS_f64x2_min}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_Commutative) +HARDWARE_INTRINSIC(PackedSimd, Multiply, 16, 2, {INS_invalid, INS_invalid, INS_i16x8_mul, INS_i16x8_mul, INS_i32x4_mul, INS_i32x4_mul, INS_i64x2_mul, INS_i64x2_mul, INS_f32x4_mul, INS_f64x2_mul}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_Commutative) +HARDWARE_INTRINSIC(PackedSimd, MultiplyRoundedSaturateQ15, 16, 2, {INS_invalid, INS_invalid, INS_i16x8_q15mulr_sat_s, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_Commutative) +HARDWARE_INTRINSIC(PackedSimd, MultiplyWideningLower, 16, 2, {INS_i16x8_extmul_low_s_i8x16, INS_i16x8_extmul_low_u_i8x16, INS_i32x4_extmul_low_s_i16x8, INS_i32x4_extmul_low_u_i16x8, INS_i64x2_extmul_low_s_i32x4, INS_i64x2_extmul_low_u_i32x4, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(PackedSimd, MultiplyWideningUpper, 16, 2, {INS_i16x8_extmul_high_s_i8x16, INS_i16x8_extmul_high_u_i8x16, INS_i32x4_extmul_high_s_i16x8, INS_i32x4_extmul_high_u_i16x8, INS_i64x2_extmul_high_s_i32x4, INS_i64x2_extmul_high_u_i32x4, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(PackedSimd, Negate, 16, 1, {INS_i8x16_neg, INS_i8x16_neg, INS_i16x8_neg, INS_i16x8_neg, INS_i32x4_neg, INS_i32x4_neg, INS_i64x2_neg, INS_i64x2_neg, INS_f32x4_neg, INS_f64x2_neg}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(PackedSimd, Not, 16, 1, {INS_v128_not, INS_v128_not, INS_v128_not, INS_v128_not, INS_v128_not, INS_v128_not, INS_v128_not, INS_v128_not, INS_v128_not, INS_v128_not}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(PackedSimd, Or, 16, 2, {INS_v128_or, INS_v128_or, INS_v128_or, INS_v128_or, INS_v128_or, INS_v128_or, INS_v128_or, INS_v128_or, INS_v128_or, INS_v128_or}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_Commutative) +HARDWARE_INTRINSIC(PackedSimd, PopCount, 16, 1, {INS_invalid, INS_i8x16_popcnt, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(PackedSimd, PseudoMax, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_f32x4_pmax, INS_f64x2_pmax}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(PackedSimd, PseudoMin, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_f32x4_pmin, INS_f64x2_pmin}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(PackedSimd, RoundToNearest, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_f32x4_nearest, INS_f64x2_nearest}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(PackedSimd, SignExtendWideningLower, 16, 1, {INS_i16x8_extend_low_s_i8x16, INS_i16x8_extend_low_s_i8x16, INS_i32x4_extend_low_s_i16x8, INS_i32x4_extend_low_s_i16x8, INS_i64x2_extend_low_s_i32x4, INS_i64x2_extend_low_s_i32x4, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(PackedSimd, SignExtendWideningUpper, 16, 1, {INS_i16x8_extend_high_s_i8x16, INS_i16x8_extend_high_s_i8x16, INS_i32x4_extend_high_s_i16x8, INS_i32x4_extend_high_s_i16x8, INS_i64x2_extend_high_s_i32x4, INS_i64x2_extend_high_s_i32x4, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(PackedSimd, Sqrt, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_f32x4_sqrt, INS_f64x2_sqrt}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(PackedSimd, Subtract, 16, 2, {INS_i8x16_sub, INS_i8x16_sub, INS_i16x8_sub, INS_i16x8_sub, INS_i32x4_sub, INS_i32x4_sub, INS_i64x2_sub, INS_i64x2_sub, INS_f32x4_sub, INS_f64x2_sub}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(PackedSimd, SubtractSaturate, 16, 2, {INS_i8x16_sub_sat_s, INS_i8x16_sub_sat_u, INS_i16x8_sub_sat_s, INS_i16x8_sub_sat_u, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(PackedSimd, Swizzle, 16, 2, {INS_i8x16_swizzle, INS_i8x16_swizzle, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(PackedSimd, Truncate, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_f32x4_trunc, INS_f64x2_trunc}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(PackedSimd, Xor, 16, 2, {INS_v128_xor, INS_v128_xor, INS_v128_xor, INS_v128_xor, INS_v128_xor, INS_v128_xor, INS_v128_xor, INS_v128_xor, INS_v128_xor, INS_v128_xor}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_Commutative) +HARDWARE_INTRINSIC(PackedSimd, ZeroExtendWideningLower, 16, 1, {INS_i16x8_extend_low_u_i8x16, INS_i16x8_extend_low_u_i8x16, INS_i32x4_extend_low_u_i16x8, INS_i32x4_extend_low_u_i16x8, INS_i64x2_extend_low_u_i32x4, INS_i64x2_extend_low_u_i32x4, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(PackedSimd, ZeroExtendWideningUpper, 16, 1, {INS_i16x8_extend_high_u_i8x16, INS_i16x8_extend_high_u_i8x16, INS_i32x4_extend_high_u_i16x8, INS_i32x4_extend_high_u_i16x8, INS_i64x2_extend_high_u_i32x4, INS_i64x2_extend_high_u_i32x4, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) +#define LAST_NI_PackedSimd NI_PackedSimd_ZeroExtendWideningUpper #endif // FEATURE_HW_INTRINSICS #undef HARDWARE_INTRINSIC From 250aa5988027d1b65c7887457cb2f8e9f8709abc Mon Sep 17 00:00:00 2001 From: Adam Date: Mon, 22 Jun 2026 10:45:53 -0700 Subject: [PATCH 06/24] Add ifdefs and remove not fully implemented opcode --- src/coreclr/jit/hwintrinsiclistwasm.h | 11 ++++++----- src/coreclr/jit/lower.cpp | 4 ++++ 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/coreclr/jit/hwintrinsiclistwasm.h b/src/coreclr/jit/hwintrinsiclistwasm.h index e0bd01ff896f1f..11ac7cc6675213 100644 --- a/src/coreclr/jit/hwintrinsiclistwasm.h +++ b/src/coreclr/jit/hwintrinsiclistwasm.h @@ -32,7 +32,7 @@ HARDWARE_INTRINSIC(Vector128, AsUInt32, HARDWARE_INTRINSIC(Vector128, AsUInt64, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector128, AsVector128Unsafe, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMD, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector128, AsVector2, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) -HARDWARE_INTRINSIC(Vector128, AsVector3, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMD, HW_Flag_InvalidNodeId) +HARDWARE_INTRINSIC(Vector128, AsVector3, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector128, AsVector4, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector128, Create, 16, -1, {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_InvalidNodeId) HARDWARE_INTRINSIC(Vector128, CreateScalar, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) @@ -80,10 +80,11 @@ HARDWARE_INTRINSIC(PackedSimd, BitwiseSelect, 16, 3, HARDWARE_INTRINSIC(PackedSimd, Ceiling, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_f32x4_ceil, INS_f64x2_ceil}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(PackedSimd, CompareEqual, 16, 2, {INS_i8x16_eq, INS_i8x16_eq, INS_i16x8_eq, INS_i16x8_eq, INS_i32x4_eq, INS_i32x4_eq, INS_i64x2_eq, INS_i64x2_eq, INS_f32x4_eq, INS_f64x2_eq}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_Commutative|HW_Flag_ReturnsPerElementMask) // TODO-WASM-SIMD: ULONG slot below is INS_invalid because the WASM SIMD spec has no unsigned i64x2 compare (lt_u/le_u/gt_u/ge_u). Requires special codegen (e.g., XOR sign bit + signed compare) to support Vector128 ordered compares. Same applies to CompareGreaterThanOrEqual/CompareLessThan/CompareLessThanOrEqual below. -HARDWARE_INTRINSIC(PackedSimd, CompareGreaterThan, 16, 2, {INS_i8x16_gt_s, INS_i8x16_gt_u, INS_i16x8_gt_s, INS_i16x8_gt_u, INS_i32x4_gt_s, INS_i32x4_gt_u, INS_i64x2_gt_s, INS_invalid, INS_f32x4_gt, INS_f64x2_gt}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_ReturnsPerElementMask) -HARDWARE_INTRINSIC(PackedSimd, CompareGreaterThanOrEqual, 16, 2, {INS_i8x16_ge_s, INS_i8x16_ge_u, INS_i16x8_ge_s, INS_i16x8_ge_u, INS_i32x4_ge_s, INS_i32x4_ge_u, INS_i64x2_ge_s, INS_invalid, INS_f32x4_ge, INS_f64x2_ge}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_ReturnsPerElementMask) -HARDWARE_INTRINSIC(PackedSimd, CompareLessThan, 16, 2, {INS_i8x16_lt_s, INS_i8x16_lt_u, INS_i16x8_lt_s, INS_i16x8_lt_u, INS_i32x4_lt_s, INS_i32x4_lt_u, INS_i64x2_lt_s, INS_invalid, INS_f32x4_lt, INS_f64x2_lt}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_ReturnsPerElementMask) -HARDWARE_INTRINSIC(PackedSimd, CompareLessThanOrEqual, 16, 2, {INS_i8x16_le_s, INS_i8x16_le_u, INS_i16x8_le_s, INS_i16x8_le_u, INS_i32x4_le_s, INS_i32x4_le_u, INS_i64x2_le_s, INS_invalid, INS_f32x4_le, INS_f64x2_le}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_ReturnsPerElementMask) +//HARDWARE_INTRINSIC(PackedSimd, CompareGreaterThan, 16, 2, {INS_i8x16_gt_s, INS_i8x16_gt_u, INS_i16x8_gt_s, INS_i16x8_gt_u, INS_i32x4_gt_s, INS_i32x4_gt_u, INS_i64x2_gt_s, INS_invalid, INS_f32x4_gt, INS_f64x2_gt}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_ReturnsPerElementMask) +//HARDWARE_INTRINSIC(PackedSimd, CompareGreaterThanOrEqual, 16, 2, {INS_i8x16_ge_s, INS_i8x16_ge_u, INS_i16x8_ge_s, INS_i16x8_ge_u, INS_i32x4_ge_s, INS_i32x4_ge_u, INS_i64x2_ge_s, INS_invalid, INS_f32x4_ge, INS_f64x2_ge}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_ReturnsPerElementMask) +//HARDWARE_INTRINSIC(PackedSimd, CompareLessThan, 16, 2, {INS_i8x16_lt_s, INS_i8x16_lt_u, INS_i16x8_lt_s, INS_i16x8_lt_u, INS_i32x4_lt_s, INS_i32x4_lt_u, INS_i64x2_lt_s, INS_invalid, INS_f32x4_lt, INS_f64x2_lt}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_ReturnsPerElementMask) +//HARDWARE_INTRINSIC(PackedSimd, CompareLessThanOrEqual, 16, 2, {INS_i8x16_le_s, INS_i8x16_le_u, INS_i16x8_le_s, INS_i16x8_le_u, INS_i32x4_le_s, INS_i32x4_le_u, INS_i64x2_le_s, INS_invalid, INS_f32x4_le, INS_f64x2_le}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_ReturnsPerElementMask) + HARDWARE_INTRINSIC(PackedSimd, CompareNotEqual, 16, 2, {INS_i8x16_ne, INS_i8x16_ne, INS_i16x8_ne, INS_i16x8_ne, INS_i32x4_ne, INS_i32x4_ne, INS_i64x2_ne, INS_i64x2_ne, INS_f32x4_ne, INS_f64x2_ne}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_Commutative|HW_Flag_ReturnsPerElementMask) HARDWARE_INTRINSIC(PackedSimd, ConvertNarrowingSaturateSigned, 16, 2, {INS_invalid, INS_invalid, INS_i8x16_narrow_i16x8_s, INS_invalid, INS_i16x8_narrow_i32x4_s, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(PackedSimd, ConvertNarrowingSaturateUnsigned, 16, 2, {INS_invalid, INS_invalid, INS_i8x16_narrow_i16x8_u, INS_invalid, INS_i16x8_narrow_i32x4_u, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) diff --git a/src/coreclr/jit/lower.cpp b/src/coreclr/jit/lower.cpp index 84c0ccbce488f4..b55bda4b75c113 100644 --- a/src/coreclr/jit/lower.cpp +++ b/src/coreclr/jit/lower.cpp @@ -9466,7 +9466,11 @@ void Lowering::CheckNode(Compiler* compiler, GenTree* node) #ifdef FEATURE_SIMD case GT_HWINTRINSIC: + // TODO-WASM: SIMD12 is still maintained through lowering. + // Fix the below once we've determined our lowering path for SIMD12. +#ifndef TARGET_WASM assert(!node->TypeIs(TYP_SIMD12)); +#endif break; #endif // FEATURE_SIMD From 3766e1b2a22a159520792d37adda66205ecc1acc Mon Sep 17 00:00:00 2001 From: Adam Date: Mon, 22 Jun 2026 10:53:53 -0700 Subject: [PATCH 07/24] Cleanup (for now) unused code --- src/coreclr/jit/hwintrinsiccodegenwasm.cpp | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/src/coreclr/jit/hwintrinsiccodegenwasm.cpp b/src/coreclr/jit/hwintrinsiccodegenwasm.cpp index f7c217396dae39..310cb836db3ab3 100644 --- a/src/coreclr/jit/hwintrinsiccodegenwasm.cpp +++ b/src/coreclr/jit/hwintrinsiccodegenwasm.cpp @@ -33,20 +33,9 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node) const HWIntrinsic info(node); genConsumeMultiOpOperands(node); - instruction ins; - emitAttr emitSize; - if (info.category == HW_Category_SIMD) - { - emitSize = emitTypeSize(info.baseType); - } - else - { - NYI_WASM_SIMD("genHWIntrinsic: non-SIMD category"); - } - if (info.codeGenIsTableDriven()) { - ins = HWIntrinsicInfo::lookupIns(info.id, info.baseType, m_compiler); + instruction const ins = HWIntrinsicInfo::lookupIns(info.id, info.baseType, m_compiler); assert(ins != INS_invalid); if (info.category == HW_Category_SIMD) { @@ -57,6 +46,10 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node) NYI_WASM_SIMD("!HW_Category_SIMD"); } } + else + { + NYI_WASM_SIMD("!codeGenIsTableDriven"); + } WasmProduceReg(node); } From 46ae2441013913ab6e731473eda4b54c227ec2e9 Mon Sep 17 00:00:00 2001 From: Adam Date: Mon, 22 Jun 2026 11:05:43 -0700 Subject: [PATCH 08/24] Add #if FEATURE_SIMD --- src/coreclr/jit/instr.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/coreclr/jit/instr.cpp b/src/coreclr/jit/instr.cpp index 5dd0272329f865..f86d58ccd2e7aa 100644 --- a/src/coreclr/jit/instr.cpp +++ b/src/coreclr/jit/instr.cpp @@ -2529,8 +2529,10 @@ instruction CodeGenInterface::ins_Store(var_types dstType, bool aligned /*=false return INS_f32_store; case TYP_DOUBLE: return INS_f64_store; +#if FEATURE_SIMD case TYP_SIMD16: return INS_v128_store; +#endif default: NYI_WASM("ins_Store"); return INS_none; From cb5a7e959acec326cf58ae739493044c69ac8588 Mon Sep 17 00:00:00 2001 From: Adam Date: Mon, 22 Jun 2026 11:50:50 -0700 Subject: [PATCH 09/24] jit-format --- src/coreclr/jit/lower.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/coreclr/jit/lower.cpp b/src/coreclr/jit/lower.cpp index b55bda4b75c113..d73baaef62180e 100644 --- a/src/coreclr/jit/lower.cpp +++ b/src/coreclr/jit/lower.cpp @@ -9466,8 +9466,8 @@ void Lowering::CheckNode(Compiler* compiler, GenTree* node) #ifdef FEATURE_SIMD case GT_HWINTRINSIC: - // TODO-WASM: SIMD12 is still maintained through lowering. - // Fix the below once we've determined our lowering path for SIMD12. + // TODO-WASM: SIMD12 is still maintained through lowering. + // Fix the below once we've determined our lowering path for SIMD12. #ifndef TARGET_WASM assert(!node->TypeIs(TYP_SIMD12)); #endif From c0f347d6e7ad4ae576c4db2687671a3ccb77721f Mon Sep 17 00:00:00 2001 From: Adam Date: Mon, 22 Jun 2026 11:54:19 -0700 Subject: [PATCH 10/24] Fix ifdef condition syntax --- src/coreclr/jit/hwintrinsic.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/jit/hwintrinsic.h b/src/coreclr/jit/hwintrinsic.h index 30a04b9da4873a..27c17c2befd5ab 100644 --- a/src/coreclr/jit/hwintrinsic.h +++ b/src/coreclr/jit/hwintrinsic.h @@ -1463,7 +1463,7 @@ struct HWIntrinsic final } } }; -#else if defined(TARGET_WASM) +#elif defined(TARGET_WASM) struct HWIntrinsic final { HWIntrinsic(const GenTreeHWIntrinsic* node) From 3d4abae4a1b44715701313323488abe0d269a6c7 Mon Sep 17 00:00:00 2001 From: Adam Perlin Date: Mon, 22 Jun 2026 12:31:59 -0700 Subject: [PATCH 11/24] Apply suggestions from code review Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- src/coreclr/jit/codegenwasm.cpp | 2 ++ src/coreclr/jit/hwintrinsicwasm.cpp | 9 ++++++++- src/coreclr/jit/instr.cpp | 4 ++-- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/coreclr/jit/codegenwasm.cpp b/src/coreclr/jit/codegenwasm.cpp index b5c76c3b966ce9..1c560bb8d5926f 100644 --- a/src/coreclr/jit/codegenwasm.cpp +++ b/src/coreclr/jit/codegenwasm.cpp @@ -746,11 +746,13 @@ void CodeGen::genCodeForTreeNode(GenTree* treeNode) return; } +#ifdef FEATURE_HW_INTRINSICS if (treeNode->OperIsHWIntrinsic()) { genHWIntrinsic(treeNode->AsHWIntrinsic()); return; } +#endif // FEATURE_HW_INTRINSICS switch (treeNode->OperGet()) { diff --git a/src/coreclr/jit/hwintrinsicwasm.cpp b/src/coreclr/jit/hwintrinsicwasm.cpp index 02663de655100c..1f40e661bb354a 100644 --- a/src/coreclr/jit/hwintrinsicwasm.cpp +++ b/src/coreclr/jit/hwintrinsicwasm.cpp @@ -91,7 +91,14 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, // For either form, if T is a const we can leverage a GenTreeVecCon and map directly to v128.const if (sig->numArgs == 1) { - op1 = impPopStack().val; + op1 = impPopStack().val; + + if (!op1->IsIntegralConst() && !op1->IsCnsFltOrDbl()) + { + NYI_WASM_SIMD("Vector128.Create(T) with non-constant operand"); + break; + } + retNode = gtNewSimdCreateBroadcastNode(retType, op1, simdBaseType, simdSize); break; } diff --git a/src/coreclr/jit/instr.cpp b/src/coreclr/jit/instr.cpp index f86d58ccd2e7aa..e33d810f40fd70 100644 --- a/src/coreclr/jit/instr.cpp +++ b/src/coreclr/jit/instr.cpp @@ -2116,7 +2116,7 @@ instruction CodeGenInterface::ins_Load(var_types srcType, bool aligned /*=false* return INS_f32_load; case TYP_DOUBLE: return INS_f64_load; -#if FEATURE_SIMD +#if defined(FEATURE_SIMD) case TYP_SIMD16: return INS_v128_load; #endif @@ -2529,7 +2529,7 @@ instruction CodeGenInterface::ins_Store(var_types dstType, bool aligned /*=false return INS_f32_store; case TYP_DOUBLE: return INS_f64_store; -#if FEATURE_SIMD +#if defined(FEATURE_SIMD) case TYP_SIMD16: return INS_v128_store; #endif From 628c47ae1010a3dee7e2031950a04a4fceb2e97b Mon Sep 17 00:00:00 2001 From: Adam Date: Mon, 22 Jun 2026 16:05:28 -0700 Subject: [PATCH 12/24] Fix unconditional NYI_WASM_SIMD lower bailout, handle no disasm file case in SPMI (can happen if NYI_WASM_SIMD fires during import) --- src/coreclr/jit/lowerwasm.cpp | 2 +- src/coreclr/scripts/superpmi.py | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/coreclr/jit/lowerwasm.cpp b/src/coreclr/jit/lowerwasm.cpp index 61b4d5174bd407..b72d6ffc3fd7dd 100644 --- a/src/coreclr/jit/lowerwasm.cpp +++ b/src/coreclr/jit/lowerwasm.cpp @@ -841,5 +841,5 @@ GenTree* Lowering::LowerHWIntrinsic(GenTreeHWIntrinsic* node) // void Lowering::ContainCheckHWIntrinsic(GenTreeHWIntrinsic* node) { - NYI_WASM_SIMD("Lowering::ContainCheckHWIntrinsic"); + // TODO-WASM: implement containment for hardware intrinsics, currently a no-op } diff --git a/src/coreclr/scripts/superpmi.py b/src/coreclr/scripts/superpmi.py index 47aadbd45f8e30..fea95d6e2304ba 100644 --- a/src/coreclr/scripts/superpmi.py +++ b/src/coreclr/scripts/superpmi.py @@ -2405,6 +2405,13 @@ def create_exception(): # No miss/replay failure is expected in contexts that were reported as having diffs since then they succeeded during the diffs run. raise create_exception() + # A JIT may may exit successfully without writing any disassembly to DOTNET_JitStdOutFile. For example, the wasm JIT + # with JitWasmSimdNyiToR2RUnsupported=1 bails via + # implReadyToRunUnsupported() (CORJIT_R2R_UNSUPPORTED) for NYI_WASM_SIMD during import, so no code is produced. This is an expected behavior. + # TODO-WASM: This check can potentially be removed once we no longer have any NYI's in the import stage. + if not os.path.exists(item_path): + return "" + try: with open(item_path, 'r') as file_handle: return file_handle.read() From 4c056e33d84c90529a579ef42171e95534cfbf2e Mon Sep 17 00:00:00 2001 From: Adam Date: Mon, 22 Jun 2026 17:28:59 -0700 Subject: [PATCH 13/24] Remove TODO --- src/coreclr/jit/hwintrinsic.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/coreclr/jit/hwintrinsic.cpp b/src/coreclr/jit/hwintrinsic.cpp index 94919027de442d..6e301af5223f5e 100644 --- a/src/coreclr/jit/hwintrinsic.cpp +++ b/src/coreclr/jit/hwintrinsic.cpp @@ -1050,7 +1050,6 @@ static const HWIntrinsicIsaRange hwintrinsicIsaRangeArray[] = { { NI_Illegal, NI_Illegal }, // WasmBase { FIRST_NI_PackedSimd, LAST_NI_PackedSimd }, // PackedSimd { FIRST_NI_Vector128, LAST_NI_Vector128 }, // Vector128 - // TODO-WASM: Add PackedSimd intrinsic ranges #else #error Unsupported platform #endif From 10ff35cae39bbb17f90006d154555b601da40859 Mon Sep 17 00:00:00 2001 From: Adam Perlin Date: Tue, 23 Jun 2026 11:33:13 -0700 Subject: [PATCH 14/24] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- src/coreclr/scripts/superpmi.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/scripts/superpmi.py b/src/coreclr/scripts/superpmi.py index fea95d6e2304ba..898e3b8879320d 100644 --- a/src/coreclr/scripts/superpmi.py +++ b/src/coreclr/scripts/superpmi.py @@ -2405,7 +2405,7 @@ def create_exception(): # No miss/replay failure is expected in contexts that were reported as having diffs since then they succeeded during the diffs run. raise create_exception() - # A JIT may may exit successfully without writing any disassembly to DOTNET_JitStdOutFile. For example, the wasm JIT + # A JIT may exit successfully without writing any disassembly to DOTNET_JitStdOutFile. For example, the wasm JIT # with JitWasmSimdNyiToR2RUnsupported=1 bails via # implReadyToRunUnsupported() (CORJIT_R2R_UNSUPPORTED) for NYI_WASM_SIMD during import, so no code is produced. This is an expected behavior. # TODO-WASM: This check can potentially be removed once we no longer have any NYI's in the import stage. From 6ecc662e3209db84e40d5efbae35889f76675733 Mon Sep 17 00:00:00 2001 From: Adam Date: Tue, 23 Jun 2026 11:41:32 -0700 Subject: [PATCH 15/24] Copilot feedback: remove unconditional import NYI on non-constant vector elements --- src/coreclr/jit/hwintrinsicwasm.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/coreclr/jit/hwintrinsicwasm.cpp b/src/coreclr/jit/hwintrinsicwasm.cpp index 1f40e661bb354a..3f1114ab8eace9 100644 --- a/src/coreclr/jit/hwintrinsicwasm.cpp +++ b/src/coreclr/jit/hwintrinsicwasm.cpp @@ -91,14 +91,14 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, // For either form, if T is a const we can leverage a GenTreeVecCon and map directly to v128.const if (sig->numArgs == 1) { - op1 = impPopStack().val; - - if (!op1->IsIntegralConst() && !op1->IsCnsFltOrDbl()) + GenTree* const arg = impStackTop().val; + if (!arg->IsIntegralConst() && !arg->IsCnsFltOrDbl()) { - NYI_WASM_SIMD("Vector128.Create(T) with non-constant operand"); - break; + // Non-constant broadcast isn't supported yet on WASM; + return nullptr; } + op1 = impPopStack().val; retNode = gtNewSimdCreateBroadcastNode(retType, op1, simdBaseType, simdSize); break; } @@ -221,7 +221,7 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, // TODO-WASM-SIMD: Build a GT_HWINTRINSIC node packing N non-constant operands // (mirroring the arm64/xarch IntrinsicNodeBuilder path) once WASM SIMD lowering // and codegen for Vector128.Create are implemented. - NYI_WASM_SIMD("Vector128.Create with non-constant operands"); + retNode = nullptr; break; } From 292bcafd26e87dec3b3594b92979f49f7d05e6f5 Mon Sep 17 00:00:00 2001 From: Adam Date: Tue, 23 Jun 2026 12:09:09 -0700 Subject: [PATCH 16/24] Format hwintrinsiclistwasm.h --- src/coreclr/jit/hwintrinsiclistwasm.h | 100 +++++++++++++------------- 1 file changed, 50 insertions(+), 50 deletions(-) diff --git a/src/coreclr/jit/hwintrinsiclistwasm.h b/src/coreclr/jit/hwintrinsiclistwasm.h index 11ac7cc6675213..bde260a219dc50 100644 --- a/src/coreclr/jit/hwintrinsiclistwasm.h +++ b/src/coreclr/jit/hwintrinsiclistwasm.h @@ -66,58 +66,58 @@ HARDWARE_INTRINSIC(Vector128, op_UnaryPlus, #define LAST_NI_Vector128 NI_Vector128_op_UnaryPlus #define FIRST_NI_PackedSimd NI_PackedSimd_Abs -HARDWARE_INTRINSIC(PackedSimd, Abs, 16, 1, {INS_i8x16_abs, INS_invalid, INS_i16x8_abs, INS_invalid, INS_i32x4_abs, INS_invalid, INS_i64x2_abs, INS_invalid, INS_f32x4_abs, INS_f64x2_abs}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(PackedSimd, Add, 16, 2, {INS_i8x16_add, INS_i8x16_add, INS_i16x8_add, INS_i16x8_add, INS_i32x4_add, INS_i32x4_add, INS_i64x2_add, INS_i64x2_add, INS_f32x4_add, INS_f64x2_add}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_Commutative) -HARDWARE_INTRINSIC(PackedSimd, AddPairwiseWidening, 16, 1, {INS_i16x8_extadd_pairwise_s_i8x16, INS_i16x8_extadd_pairwise_u_i8x16, INS_i32x4_extadd_pairwise_s_i16x8, INS_i32x4_extadd_pairwise_u_i16x8, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(PackedSimd, AddSaturate, 16, 2, {INS_i8x16_add_sat_s, INS_i8x16_add_sat_u, INS_i16x8_add_sat_s, INS_i16x8_add_sat_u, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_Commutative) -HARDWARE_INTRINSIC(PackedSimd, AllTrue, 16, 1, {INS_i8x16_all_true, INS_i8x16_all_true, INS_i16x8_all_true, INS_i16x8_all_true, INS_i32x4_all_true, INS_i32x4_all_true, INS_i64x2_all_true, INS_i64x2_all_true, INS_invalid, INS_invalid}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(PackedSimd, And, 16, 2, {INS_v128_and, INS_v128_and, INS_v128_and, INS_v128_and, INS_v128_and, INS_v128_and, INS_v128_and, INS_v128_and, INS_v128_and, INS_v128_and}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_Commutative) -HARDWARE_INTRINSIC(PackedSimd, AndNot, 16, 2, {INS_v128_andnot, INS_v128_andnot, INS_v128_andnot, INS_v128_andnot, INS_v128_andnot, INS_v128_andnot, INS_v128_andnot, INS_v128_andnot, INS_v128_andnot, INS_v128_andnot}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(PackedSimd, AnyTrue, 16, 1, {INS_v128_any_true, INS_v128_any_true, INS_v128_any_true, INS_v128_any_true, INS_v128_any_true, INS_v128_any_true, INS_v128_any_true, INS_v128_any_true, INS_v128_any_true, INS_v128_any_true}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(PackedSimd, AverageRounded, 16, 2, {INS_invalid, INS_i8x16_avgr_u, INS_invalid, INS_i16x8_avgr_u, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_Commutative) -HARDWARE_INTRINSIC(PackedSimd, Bitmask, 16, 1, {INS_i8x16_bitmask, INS_i8x16_bitmask, INS_i16x8_bitmask, INS_i16x8_bitmask, INS_i32x4_bitmask, INS_i32x4_bitmask, INS_i64x2_bitmask, INS_i64x2_bitmask, INS_invalid, INS_invalid}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(PackedSimd, BitwiseSelect, 16, 3, {INS_v128_bitselect, INS_v128_bitselect, INS_v128_bitselect, INS_v128_bitselect, INS_v128_bitselect, INS_v128_bitselect, INS_v128_bitselect, INS_v128_bitselect, INS_v128_bitselect, INS_v128_bitselect}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(PackedSimd, Ceiling, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_f32x4_ceil, INS_f64x2_ceil}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(PackedSimd, CompareEqual, 16, 2, {INS_i8x16_eq, INS_i8x16_eq, INS_i16x8_eq, INS_i16x8_eq, INS_i32x4_eq, INS_i32x4_eq, INS_i64x2_eq, INS_i64x2_eq, INS_f32x4_eq, INS_f64x2_eq}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_Commutative|HW_Flag_ReturnsPerElementMask) +HARDWARE_INTRINSIC(PackedSimd, Abs, 16, 1, {INS_i8x16_abs, INS_invalid, INS_i16x8_abs, INS_invalid, INS_i32x4_abs, INS_invalid, INS_i64x2_abs, INS_invalid, INS_f32x4_abs, INS_f64x2_abs }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(PackedSimd, Add, 16, 2, {INS_i8x16_add, INS_i8x16_add, INS_i16x8_add, INS_i16x8_add, INS_i32x4_add, INS_i32x4_add, INS_i64x2_add, INS_i64x2_add, INS_f32x4_add, INS_f64x2_add }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_Commutative) +HARDWARE_INTRINSIC(PackedSimd, AddPairwiseWidening, 16, 1, {INS_i16x8_extadd_pairwise_s_i8x16, INS_i16x8_extadd_pairwise_u_i8x16, INS_i32x4_extadd_pairwise_s_i16x8, INS_i32x4_extadd_pairwise_u_i16x8, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(PackedSimd, AddSaturate, 16, 2, {INS_i8x16_add_sat_s, INS_i8x16_add_sat_u, INS_i16x8_add_sat_s, INS_i16x8_add_sat_u, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_Commutative) +HARDWARE_INTRINSIC(PackedSimd, AllTrue, 16, 1, {INS_i8x16_all_true, INS_i8x16_all_true, INS_i16x8_all_true, INS_i16x8_all_true, INS_i32x4_all_true, INS_i32x4_all_true, INS_i64x2_all_true, INS_i64x2_all_true, INS_invalid, INS_invalid }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(PackedSimd, And, 16, 2, {INS_v128_and, INS_v128_and, INS_v128_and, INS_v128_and, INS_v128_and, INS_v128_and, INS_v128_and, INS_v128_and, INS_v128_and, INS_v128_and }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_Commutative) +HARDWARE_INTRINSIC(PackedSimd, AndNot, 16, 2, {INS_v128_andnot, INS_v128_andnot, INS_v128_andnot, INS_v128_andnot, INS_v128_andnot, INS_v128_andnot, INS_v128_andnot, INS_v128_andnot, INS_v128_andnot, INS_v128_andnot }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(PackedSimd, AnyTrue, 16, 1, {INS_v128_any_true, INS_v128_any_true, INS_v128_any_true, INS_v128_any_true, INS_v128_any_true, INS_v128_any_true, INS_v128_any_true, INS_v128_any_true, INS_v128_any_true, INS_v128_any_true }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(PackedSimd, AverageRounded, 16, 2, {INS_invalid, INS_i8x16_avgr_u, INS_invalid, INS_i16x8_avgr_u, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_Commutative) +HARDWARE_INTRINSIC(PackedSimd, Bitmask, 16, 1, {INS_i8x16_bitmask, INS_i8x16_bitmask, INS_i16x8_bitmask, INS_i16x8_bitmask, INS_i32x4_bitmask, INS_i32x4_bitmask, INS_i64x2_bitmask, INS_i64x2_bitmask, INS_invalid, INS_invalid }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(PackedSimd, BitwiseSelect, 16, 3, {INS_v128_bitselect, INS_v128_bitselect, INS_v128_bitselect, INS_v128_bitselect, INS_v128_bitselect, INS_v128_bitselect, INS_v128_bitselect, INS_v128_bitselect, INS_v128_bitselect, INS_v128_bitselect }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(PackedSimd, Ceiling, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_f32x4_ceil, INS_f64x2_ceil }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(PackedSimd, CompareEqual, 16, 2, {INS_i8x16_eq, INS_i8x16_eq, INS_i16x8_eq, INS_i16x8_eq, INS_i32x4_eq, INS_i32x4_eq, INS_i64x2_eq, INS_i64x2_eq, INS_f32x4_eq, INS_f64x2_eq }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_Commutative|HW_Flag_ReturnsPerElementMask) // TODO-WASM-SIMD: ULONG slot below is INS_invalid because the WASM SIMD spec has no unsigned i64x2 compare (lt_u/le_u/gt_u/ge_u). Requires special codegen (e.g., XOR sign bit + signed compare) to support Vector128 ordered compares. Same applies to CompareGreaterThanOrEqual/CompareLessThan/CompareLessThanOrEqual below. -//HARDWARE_INTRINSIC(PackedSimd, CompareGreaterThan, 16, 2, {INS_i8x16_gt_s, INS_i8x16_gt_u, INS_i16x8_gt_s, INS_i16x8_gt_u, INS_i32x4_gt_s, INS_i32x4_gt_u, INS_i64x2_gt_s, INS_invalid, INS_f32x4_gt, INS_f64x2_gt}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_ReturnsPerElementMask) -//HARDWARE_INTRINSIC(PackedSimd, CompareGreaterThanOrEqual, 16, 2, {INS_i8x16_ge_s, INS_i8x16_ge_u, INS_i16x8_ge_s, INS_i16x8_ge_u, INS_i32x4_ge_s, INS_i32x4_ge_u, INS_i64x2_ge_s, INS_invalid, INS_f32x4_ge, INS_f64x2_ge}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_ReturnsPerElementMask) -//HARDWARE_INTRINSIC(PackedSimd, CompareLessThan, 16, 2, {INS_i8x16_lt_s, INS_i8x16_lt_u, INS_i16x8_lt_s, INS_i16x8_lt_u, INS_i32x4_lt_s, INS_i32x4_lt_u, INS_i64x2_lt_s, INS_invalid, INS_f32x4_lt, INS_f64x2_lt}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_ReturnsPerElementMask) -//HARDWARE_INTRINSIC(PackedSimd, CompareLessThanOrEqual, 16, 2, {INS_i8x16_le_s, INS_i8x16_le_u, INS_i16x8_le_s, INS_i16x8_le_u, INS_i32x4_le_s, INS_i32x4_le_u, INS_i64x2_le_s, INS_invalid, INS_f32x4_le, INS_f64x2_le}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_ReturnsPerElementMask) +//HARDWARE_INTRINSIC(PackedSimd, CompareGreaterThan, 16, 2, {INS_i8x16_gt_s, INS_i8x16_gt_u, INS_i16x8_gt_s, INS_i16x8_gt_u, INS_i32x4_gt_s, INS_i32x4_gt_u, INS_i64x2_gt_s, INS_invalid, INS_f32x4_gt, INS_f64x2_gt }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_ReturnsPerElementMask) +//HARDWARE_INTRINSIC(PackedSimd, CompareGreaterThanOrEqual, 16, 2, {INS_i8x16_ge_s, INS_i8x16_ge_u, INS_i16x8_ge_s, INS_i16x8_ge_u, INS_i32x4_ge_s, INS_i32x4_ge_u, INS_i64x2_ge_s, INS_invalid, INS_f32x4_ge, INS_f64x2_ge }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_ReturnsPerElementMask) +//HARDWARE_INTRINSIC(PackedSimd, CompareLessThan, 16, 2, {INS_i8x16_lt_s, INS_i8x16_lt_u, INS_i16x8_lt_s, INS_i16x8_lt_u, INS_i32x4_lt_s, INS_i32x4_lt_u, INS_i64x2_lt_s, INS_invalid, INS_f32x4_lt, INS_f64x2_lt }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_ReturnsPerElementMask) +//HARDWARE_INTRINSIC(PackedSimd, CompareLessThanOrEqual, 16, 2, {INS_i8x16_le_s, INS_i8x16_le_u, INS_i16x8_le_s, INS_i16x8_le_u, INS_i32x4_le_s, INS_i32x4_le_u, INS_i64x2_le_s, INS_invalid, INS_f32x4_le, INS_f64x2_le }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_ReturnsPerElementMask) -HARDWARE_INTRINSIC(PackedSimd, CompareNotEqual, 16, 2, {INS_i8x16_ne, INS_i8x16_ne, INS_i16x8_ne, INS_i16x8_ne, INS_i32x4_ne, INS_i32x4_ne, INS_i64x2_ne, INS_i64x2_ne, INS_f32x4_ne, INS_f64x2_ne}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_Commutative|HW_Flag_ReturnsPerElementMask) -HARDWARE_INTRINSIC(PackedSimd, ConvertNarrowingSaturateSigned, 16, 2, {INS_invalid, INS_invalid, INS_i8x16_narrow_i16x8_s, INS_invalid, INS_i16x8_narrow_i32x4_s, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(PackedSimd, ConvertNarrowingSaturateUnsigned, 16, 2, {INS_invalid, INS_invalid, INS_i8x16_narrow_i16x8_u, INS_invalid, INS_i16x8_narrow_i32x4_u, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(PackedSimd, ConvertToDoubleLower, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_f64x2_convert_low_s_i32x4, INS_f64x2_convert_low_u_i32x4, INS_invalid, INS_invalid, INS_f64x2_promote_low_f32x4, INS_invalid}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(PackedSimd, ConvertToInt32Saturate, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_i32x4_trunc_sat_s_f32x4, INS_i32x4_trunc_sat_s_f64x2_zero}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(PackedSimd, ConvertToSingle, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_f32x4_convert_s_i32x4, INS_f32x4_convert_u_i32x4, INS_invalid, INS_invalid, INS_invalid, INS_f32x4_demote_f64x2_zero}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(PackedSimd, ConvertToUInt32Saturate, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_i32x4_trunc_sat_u_f32x4, INS_i32x4_trunc_sat_u_f64x2_zero}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(PackedSimd, Divide, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_f32x4_div, INS_f64x2_div}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(PackedSimd, Dot, 16, 2, {INS_invalid, INS_invalid, INS_i32x4_dot_i16x8_s, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(PackedSimd, Floor, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_f32x4_floor, INS_f64x2_floor}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(PackedSimd, Max, 16, 2, {INS_i8x16_max_s, INS_i8x16_max_u, INS_i16x8_max_s, INS_i16x8_max_u, INS_i32x4_max_s, INS_i32x4_max_u, INS_invalid, INS_invalid, INS_f32x4_max, INS_f64x2_max}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_Commutative) -HARDWARE_INTRINSIC(PackedSimd, Min, 16, 2, {INS_i8x16_min_s, INS_i8x16_min_u, INS_i16x8_min_s, INS_i16x8_min_u, INS_i32x4_min_s, INS_i32x4_min_u, INS_invalid, INS_invalid, INS_f32x4_min, INS_f64x2_min}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_Commutative) -HARDWARE_INTRINSIC(PackedSimd, Multiply, 16, 2, {INS_invalid, INS_invalid, INS_i16x8_mul, INS_i16x8_mul, INS_i32x4_mul, INS_i32x4_mul, INS_i64x2_mul, INS_i64x2_mul, INS_f32x4_mul, INS_f64x2_mul}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_Commutative) -HARDWARE_INTRINSIC(PackedSimd, MultiplyRoundedSaturateQ15, 16, 2, {INS_invalid, INS_invalid, INS_i16x8_q15mulr_sat_s, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_Commutative) -HARDWARE_INTRINSIC(PackedSimd, MultiplyWideningLower, 16, 2, {INS_i16x8_extmul_low_s_i8x16, INS_i16x8_extmul_low_u_i8x16, INS_i32x4_extmul_low_s_i16x8, INS_i32x4_extmul_low_u_i16x8, INS_i64x2_extmul_low_s_i32x4, INS_i64x2_extmul_low_u_i32x4, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(PackedSimd, MultiplyWideningUpper, 16, 2, {INS_i16x8_extmul_high_s_i8x16, INS_i16x8_extmul_high_u_i8x16, INS_i32x4_extmul_high_s_i16x8, INS_i32x4_extmul_high_u_i16x8, INS_i64x2_extmul_high_s_i32x4, INS_i64x2_extmul_high_u_i32x4, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(PackedSimd, Negate, 16, 1, {INS_i8x16_neg, INS_i8x16_neg, INS_i16x8_neg, INS_i16x8_neg, INS_i32x4_neg, INS_i32x4_neg, INS_i64x2_neg, INS_i64x2_neg, INS_f32x4_neg, INS_f64x2_neg}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(PackedSimd, Not, 16, 1, {INS_v128_not, INS_v128_not, INS_v128_not, INS_v128_not, INS_v128_not, INS_v128_not, INS_v128_not, INS_v128_not, INS_v128_not, INS_v128_not}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(PackedSimd, Or, 16, 2, {INS_v128_or, INS_v128_or, INS_v128_or, INS_v128_or, INS_v128_or, INS_v128_or, INS_v128_or, INS_v128_or, INS_v128_or, INS_v128_or}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_Commutative) -HARDWARE_INTRINSIC(PackedSimd, PopCount, 16, 1, {INS_invalid, INS_i8x16_popcnt, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(PackedSimd, PseudoMax, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_f32x4_pmax, INS_f64x2_pmax}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(PackedSimd, PseudoMin, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_f32x4_pmin, INS_f64x2_pmin}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(PackedSimd, RoundToNearest, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_f32x4_nearest, INS_f64x2_nearest}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(PackedSimd, SignExtendWideningLower, 16, 1, {INS_i16x8_extend_low_s_i8x16, INS_i16x8_extend_low_s_i8x16, INS_i32x4_extend_low_s_i16x8, INS_i32x4_extend_low_s_i16x8, INS_i64x2_extend_low_s_i32x4, INS_i64x2_extend_low_s_i32x4, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(PackedSimd, SignExtendWideningUpper, 16, 1, {INS_i16x8_extend_high_s_i8x16, INS_i16x8_extend_high_s_i8x16, INS_i32x4_extend_high_s_i16x8, INS_i32x4_extend_high_s_i16x8, INS_i64x2_extend_high_s_i32x4, INS_i64x2_extend_high_s_i32x4, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(PackedSimd, Sqrt, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_f32x4_sqrt, INS_f64x2_sqrt}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(PackedSimd, Subtract, 16, 2, {INS_i8x16_sub, INS_i8x16_sub, INS_i16x8_sub, INS_i16x8_sub, INS_i32x4_sub, INS_i32x4_sub, INS_i64x2_sub, INS_i64x2_sub, INS_f32x4_sub, INS_f64x2_sub}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(PackedSimd, SubtractSaturate, 16, 2, {INS_i8x16_sub_sat_s, INS_i8x16_sub_sat_u, INS_i16x8_sub_sat_s, INS_i16x8_sub_sat_u, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(PackedSimd, Swizzle, 16, 2, {INS_i8x16_swizzle, INS_i8x16_swizzle, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(PackedSimd, Truncate, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_f32x4_trunc, INS_f64x2_trunc}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(PackedSimd, Xor, 16, 2, {INS_v128_xor, INS_v128_xor, INS_v128_xor, INS_v128_xor, INS_v128_xor, INS_v128_xor, INS_v128_xor, INS_v128_xor, INS_v128_xor, INS_v128_xor}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_Commutative) -HARDWARE_INTRINSIC(PackedSimd, ZeroExtendWideningLower, 16, 1, {INS_i16x8_extend_low_u_i8x16, INS_i16x8_extend_low_u_i8x16, INS_i32x4_extend_low_u_i16x8, INS_i32x4_extend_low_u_i16x8, INS_i64x2_extend_low_u_i32x4, INS_i64x2_extend_low_u_i32x4, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(PackedSimd, ZeroExtendWideningUpper, 16, 1, {INS_i16x8_extend_high_u_i8x16, INS_i16x8_extend_high_u_i8x16, INS_i32x4_extend_high_u_i16x8, INS_i32x4_extend_high_u_i16x8, INS_i64x2_extend_high_u_i32x4, INS_i64x2_extend_high_u_i32x4, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(PackedSimd, CompareNotEqual, 16, 2, {INS_i8x16_ne, INS_i8x16_ne, INS_i16x8_ne, INS_i16x8_ne, INS_i32x4_ne, INS_i32x4_ne, INS_i64x2_ne, INS_i64x2_ne, INS_f32x4_ne, INS_f64x2_ne }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_Commutative|HW_Flag_ReturnsPerElementMask) +HARDWARE_INTRINSIC(PackedSimd, ConvertNarrowingSaturateSigned, 16, 2, {INS_invalid, INS_invalid, INS_i8x16_narrow_i16x8_s, INS_invalid, INS_i16x8_narrow_i32x4_s, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(PackedSimd, ConvertNarrowingSaturateUnsigned, 16, 2, {INS_invalid, INS_invalid, INS_i8x16_narrow_i16x8_u, INS_invalid, INS_i16x8_narrow_i32x4_u, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(PackedSimd, ConvertToDoubleLower, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_f64x2_convert_low_s_i32x4, INS_f64x2_convert_low_u_i32x4, INS_invalid, INS_invalid, INS_f64x2_promote_low_f32x4, INS_invalid }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(PackedSimd, ConvertToInt32Saturate, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_i32x4_trunc_sat_s_f32x4, INS_i32x4_trunc_sat_s_f64x2_zero}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(PackedSimd, ConvertToSingle, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_f32x4_convert_s_i32x4, INS_f32x4_convert_u_i32x4, INS_invalid, INS_invalid, INS_invalid, INS_f32x4_demote_f64x2_zero }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(PackedSimd, ConvertToUInt32Saturate, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_i32x4_trunc_sat_u_f32x4, INS_i32x4_trunc_sat_u_f64x2_zero}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(PackedSimd, Divide, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_f32x4_div, INS_f64x2_div }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(PackedSimd, Dot, 16, 2, {INS_invalid, INS_invalid, INS_i32x4_dot_i16x8_s, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(PackedSimd, Floor, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_f32x4_floor, INS_f64x2_floor }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(PackedSimd, Max, 16, 2, {INS_i8x16_max_s, INS_i8x16_max_u, INS_i16x8_max_s, INS_i16x8_max_u, INS_i32x4_max_s, INS_i32x4_max_u, INS_invalid, INS_invalid, INS_f32x4_max, INS_f64x2_max }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_Commutative) +HARDWARE_INTRINSIC(PackedSimd, Min, 16, 2, {INS_i8x16_min_s, INS_i8x16_min_u, INS_i16x8_min_s, INS_i16x8_min_u, INS_i32x4_min_s, INS_i32x4_min_u, INS_invalid, INS_invalid, INS_f32x4_min, INS_f64x2_min }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_Commutative) +HARDWARE_INTRINSIC(PackedSimd, Multiply, 16, 2, {INS_invalid, INS_invalid, INS_i16x8_mul, INS_i16x8_mul, INS_i32x4_mul, INS_i32x4_mul, INS_i64x2_mul, INS_i64x2_mul, INS_f32x4_mul, INS_f64x2_mul }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_Commutative) +HARDWARE_INTRINSIC(PackedSimd, MultiplyRoundedSaturateQ15, 16, 2, {INS_invalid, INS_invalid, INS_i16x8_q15mulr_sat_s, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_Commutative) +HARDWARE_INTRINSIC(PackedSimd, MultiplyWideningLower, 16, 2, {INS_i16x8_extmul_low_s_i8x16, INS_i16x8_extmul_low_u_i8x16, INS_i32x4_extmul_low_s_i16x8, INS_i32x4_extmul_low_u_i16x8, INS_i64x2_extmul_low_s_i32x4, INS_i64x2_extmul_low_u_i32x4, INS_invalid, INS_invalid, INS_invalid, INS_invalid }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(PackedSimd, MultiplyWideningUpper, 16, 2, {INS_i16x8_extmul_high_s_i8x16, INS_i16x8_extmul_high_u_i8x16, INS_i32x4_extmul_high_s_i16x8, INS_i32x4_extmul_high_u_i16x8, INS_i64x2_extmul_high_s_i32x4, INS_i64x2_extmul_high_u_i32x4, INS_invalid, INS_invalid, INS_invalid, INS_invalid }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(PackedSimd, Negate, 16, 1, {INS_i8x16_neg, INS_i8x16_neg, INS_i16x8_neg, INS_i16x8_neg, INS_i32x4_neg, INS_i32x4_neg, INS_i64x2_neg, INS_i64x2_neg, INS_f32x4_neg, INS_f64x2_neg }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(PackedSimd, Not, 16, 1, {INS_v128_not, INS_v128_not, INS_v128_not, INS_v128_not, INS_v128_not, INS_v128_not, INS_v128_not, INS_v128_not, INS_v128_not, INS_v128_not }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(PackedSimd, Or, 16, 2, {INS_v128_or, INS_v128_or, INS_v128_or, INS_v128_or, INS_v128_or, INS_v128_or, INS_v128_or, INS_v128_or, INS_v128_or, INS_v128_or }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_Commutative) +HARDWARE_INTRINSIC(PackedSimd, PopCount, 16, 1, {INS_invalid, INS_i8x16_popcnt, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(PackedSimd, PseudoMax, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_f32x4_pmax, INS_f64x2_pmax }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(PackedSimd, PseudoMin, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_f32x4_pmin, INS_f64x2_pmin }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(PackedSimd, RoundToNearest, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_f32x4_nearest, INS_f64x2_nearest }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(PackedSimd, SignExtendWideningLower, 16, 1, {INS_i16x8_extend_low_s_i8x16, INS_i16x8_extend_low_s_i8x16, INS_i32x4_extend_low_s_i16x8, INS_i32x4_extend_low_s_i16x8, INS_i64x2_extend_low_s_i32x4, INS_i64x2_extend_low_s_i32x4, INS_invalid, INS_invalid, INS_invalid, INS_invalid }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(PackedSimd, SignExtendWideningUpper, 16, 1, {INS_i16x8_extend_high_s_i8x16, INS_i16x8_extend_high_s_i8x16, INS_i32x4_extend_high_s_i16x8, INS_i32x4_extend_high_s_i16x8, INS_i64x2_extend_high_s_i32x4, INS_i64x2_extend_high_s_i32x4, INS_invalid, INS_invalid, INS_invalid, INS_invalid }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(PackedSimd, Sqrt, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_f32x4_sqrt, INS_f64x2_sqrt }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(PackedSimd, Subtract, 16, 2, {INS_i8x16_sub, INS_i8x16_sub, INS_i16x8_sub, INS_i16x8_sub, INS_i32x4_sub, INS_i32x4_sub, INS_i64x2_sub, INS_i64x2_sub, INS_f32x4_sub, INS_f64x2_sub }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(PackedSimd, SubtractSaturate, 16, 2, {INS_i8x16_sub_sat_s, INS_i8x16_sub_sat_u, INS_i16x8_sub_sat_s, INS_i16x8_sub_sat_u, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(PackedSimd, Swizzle, 16, 2, {INS_i8x16_swizzle, INS_i8x16_swizzle, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(PackedSimd, Truncate, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_f32x4_trunc, INS_f64x2_trunc }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(PackedSimd, Xor, 16, 2, {INS_v128_xor, INS_v128_xor, INS_v128_xor, INS_v128_xor, INS_v128_xor, INS_v128_xor, INS_v128_xor, INS_v128_xor, INS_v128_xor, INS_v128_xor }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_Commutative) +HARDWARE_INTRINSIC(PackedSimd, ZeroExtendWideningLower, 16, 1, {INS_i16x8_extend_low_u_i8x16, INS_i16x8_extend_low_u_i8x16, INS_i32x4_extend_low_u_i16x8, INS_i32x4_extend_low_u_i16x8, INS_i64x2_extend_low_u_i32x4, INS_i64x2_extend_low_u_i32x4, INS_invalid, INS_invalid, INS_invalid, INS_invalid }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(PackedSimd, ZeroExtendWideningUpper, 16, 1, {INS_i16x8_extend_high_u_i8x16, INS_i16x8_extend_high_u_i8x16, INS_i32x4_extend_high_u_i16x8, INS_i32x4_extend_high_u_i16x8, INS_i64x2_extend_high_u_i32x4, INS_i64x2_extend_high_u_i32x4, INS_invalid, INS_invalid, INS_invalid, INS_invalid }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) #define LAST_NI_PackedSimd NI_PackedSimd_ZeroExtendWideningUpper #endif // FEATURE_HW_INTRINSICS From e7cef58bbde463e6a250f3fa4fe6f8f055c73f04 Mon Sep 17 00:00:00 2001 From: Adam Date: Tue, 23 Jun 2026 13:57:36 -0700 Subject: [PATCH 17/24] More copilot feedback --- src/coreclr/jit/hwintrinsiclistwasm.h | 2 +- src/coreclr/scripts/superpmi.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/coreclr/jit/hwintrinsiclistwasm.h b/src/coreclr/jit/hwintrinsiclistwasm.h index bde260a219dc50..f6f0df26b10154 100644 --- a/src/coreclr/jit/hwintrinsiclistwasm.h +++ b/src/coreclr/jit/hwintrinsiclistwasm.h @@ -73,7 +73,7 @@ HARDWARE_INTRINSIC(PackedSimd, AddSaturate, 1 HARDWARE_INTRINSIC(PackedSimd, AllTrue, 16, 1, {INS_i8x16_all_true, INS_i8x16_all_true, INS_i16x8_all_true, INS_i16x8_all_true, INS_i32x4_all_true, INS_i32x4_all_true, INS_i64x2_all_true, INS_i64x2_all_true, INS_invalid, INS_invalid }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(PackedSimd, And, 16, 2, {INS_v128_and, INS_v128_and, INS_v128_and, INS_v128_and, INS_v128_and, INS_v128_and, INS_v128_and, INS_v128_and, INS_v128_and, INS_v128_and }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_Commutative) HARDWARE_INTRINSIC(PackedSimd, AndNot, 16, 2, {INS_v128_andnot, INS_v128_andnot, INS_v128_andnot, INS_v128_andnot, INS_v128_andnot, INS_v128_andnot, INS_v128_andnot, INS_v128_andnot, INS_v128_andnot, INS_v128_andnot }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(PackedSimd, AnyTrue, 16, 1, {INS_v128_any_true, INS_v128_any_true, INS_v128_any_true, INS_v128_any_true, INS_v128_any_true, INS_v128_any_true, INS_v128_any_true, INS_v128_any_true, INS_v128_any_true, INS_v128_any_true }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(PackedSimd, AnyTrue, 16, 1, {INS_v128_any_true, INS_v128_any_true, INS_v128_any_true, INS_v128_any_true, INS_v128_any_true, INS_v128_any_true, INS_v128_any_true, INS_v128_any_true, INS_v128_any_true, INS_v128_any_true }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_ReturnsBoolean) HARDWARE_INTRINSIC(PackedSimd, AverageRounded, 16, 2, {INS_invalid, INS_i8x16_avgr_u, INS_invalid, INS_i16x8_avgr_u, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_Commutative) HARDWARE_INTRINSIC(PackedSimd, Bitmask, 16, 1, {INS_i8x16_bitmask, INS_i8x16_bitmask, INS_i16x8_bitmask, INS_i16x8_bitmask, INS_i32x4_bitmask, INS_i32x4_bitmask, INS_i64x2_bitmask, INS_i64x2_bitmask, INS_invalid, INS_invalid }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(PackedSimd, BitwiseSelect, 16, 3, {INS_v128_bitselect, INS_v128_bitselect, INS_v128_bitselect, INS_v128_bitselect, INS_v128_bitselect, INS_v128_bitselect, INS_v128_bitselect, INS_v128_bitselect, INS_v128_bitselect, INS_v128_bitselect }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) diff --git a/src/coreclr/scripts/superpmi.py b/src/coreclr/scripts/superpmi.py index 898e3b8879320d..3795bb9443cc3c 100644 --- a/src/coreclr/scripts/superpmi.py +++ b/src/coreclr/scripts/superpmi.py @@ -2405,11 +2405,11 @@ def create_exception(): # No miss/replay failure is expected in contexts that were reported as having diffs since then they succeeded during the diffs run. raise create_exception() - # A JIT may exit successfully without writing any disassembly to DOTNET_JitStdOutFile. For example, the wasm JIT - # with JitWasmSimdNyiToR2RUnsupported=1 bails via + # A Wasm JIT may exit successfully without writing any disassembly to DOTNET_JitStdOutFile. For example, the wasm JIT + # with JitWasmSimdNyiToR2RUnsupported=1 exits via # implReadyToRunUnsupported() (CORJIT_R2R_UNSUPPORTED) for NYI_WASM_SIMD during import, so no code is produced. This is an expected behavior. # TODO-WASM: This check can potentially be removed once we no longer have any NYI's in the import stage. - if not os.path.exists(item_path): + if not os.path.exists(item_path) and self.coreclr_args.target_arch == "wasm": return "" try: From 5a93f14cd19293d897e1d40b551d9a8f308437e0 Mon Sep 17 00:00:00 2001 From: Adam Perlin Date: Tue, 23 Jun 2026 15:05:10 -0700 Subject: [PATCH 18/24] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- src/coreclr/jit/codegenwasm.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/coreclr/jit/codegenwasm.cpp b/src/coreclr/jit/codegenwasm.cpp index 1c560bb8d5926f..b358d0c693dc59 100644 --- a/src/coreclr/jit/codegenwasm.cpp +++ b/src/coreclr/jit/codegenwasm.cpp @@ -1821,9 +1821,12 @@ void CodeGen::genCodeForVectorConstant(GenTree* treeNode) assert(treeNode->IsCnsVec()); GenTreeVecCon* vecCon = treeNode->AsVecCon(); + uint8_t bytes[16] = {}; + memcpy(bytes, &vecCon->gtSimdVal, genTypeSize(vecCon->TypeGet())); + // There is only one type variant for v128.const, v128.const // and the bytes are reinterpreted according to whichever operation consumes the value. - GetEmitter()->emitIns_V128Imm(INS_v128_const, vecCon->gtSimd16Val.u8); + GetEmitter()->emitIns_V128Imm(INS_v128_const, bytes); WasmProduceReg(treeNode); } #endif From 01e61c62469f1b47045a0c77b238daee5df04364 Mon Sep 17 00:00:00 2001 From: Adam Date: Wed, 24 Jun 2026 18:14:59 -0700 Subject: [PATCH 19/24] Address more review feedback: Ensure Vector128.GetElement can fall back to managed implementation, and implement HARDWARE_INTRINSIC() stubs for all packed simd opcodes to ensure NYI --- src/coreclr/jit/hwintrinsiclistwasm.h | 23 +++++++++--- src/coreclr/jit/hwintrinsicwasm.cpp | 51 +++++++++++++++++++++++++++ src/coreclr/scripts/superpmi.py | 8 +++++ 3 files changed, 77 insertions(+), 5 deletions(-) diff --git a/src/coreclr/jit/hwintrinsiclistwasm.h b/src/coreclr/jit/hwintrinsiclistwasm.h index f6f0df26b10154..7d6fe714a41cf7 100644 --- a/src/coreclr/jit/hwintrinsiclistwasm.h +++ b/src/coreclr/jit/hwintrinsiclistwasm.h @@ -79,11 +79,11 @@ HARDWARE_INTRINSIC(PackedSimd, Bitmask, 1 HARDWARE_INTRINSIC(PackedSimd, BitwiseSelect, 16, 3, {INS_v128_bitselect, INS_v128_bitselect, INS_v128_bitselect, INS_v128_bitselect, INS_v128_bitselect, INS_v128_bitselect, INS_v128_bitselect, INS_v128_bitselect, INS_v128_bitselect, INS_v128_bitselect }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(PackedSimd, Ceiling, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_f32x4_ceil, INS_f64x2_ceil }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(PackedSimd, CompareEqual, 16, 2, {INS_i8x16_eq, INS_i8x16_eq, INS_i16x8_eq, INS_i16x8_eq, INS_i32x4_eq, INS_i32x4_eq, INS_i64x2_eq, INS_i64x2_eq, INS_f32x4_eq, INS_f64x2_eq }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_Commutative|HW_Flag_ReturnsPerElementMask) -// TODO-WASM-SIMD: ULONG slot below is INS_invalid because the WASM SIMD spec has no unsigned i64x2 compare (lt_u/le_u/gt_u/ge_u). Requires special codegen (e.g., XOR sign bit + signed compare) to support Vector128 ordered compares. Same applies to CompareGreaterThanOrEqual/CompareLessThan/CompareLessThanOrEqual below. -//HARDWARE_INTRINSIC(PackedSimd, CompareGreaterThan, 16, 2, {INS_i8x16_gt_s, INS_i8x16_gt_u, INS_i16x8_gt_s, INS_i16x8_gt_u, INS_i32x4_gt_s, INS_i32x4_gt_u, INS_i64x2_gt_s, INS_invalid, INS_f32x4_gt, INS_f64x2_gt }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_ReturnsPerElementMask) -//HARDWARE_INTRINSIC(PackedSimd, CompareGreaterThanOrEqual, 16, 2, {INS_i8x16_ge_s, INS_i8x16_ge_u, INS_i16x8_ge_s, INS_i16x8_ge_u, INS_i32x4_ge_s, INS_i32x4_ge_u, INS_i64x2_ge_s, INS_invalid, INS_f32x4_ge, INS_f64x2_ge }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_ReturnsPerElementMask) -//HARDWARE_INTRINSIC(PackedSimd, CompareLessThan, 16, 2, {INS_i8x16_lt_s, INS_i8x16_lt_u, INS_i16x8_lt_s, INS_i16x8_lt_u, INS_i32x4_lt_s, INS_i32x4_lt_u, INS_i64x2_lt_s, INS_invalid, INS_f32x4_lt, INS_f64x2_lt }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_ReturnsPerElementMask) -//HARDWARE_INTRINSIC(PackedSimd, CompareLessThanOrEqual, 16, 2, {INS_i8x16_le_s, INS_i8x16_le_u, INS_i16x8_le_s, INS_i16x8_le_u, INS_i32x4_le_s, INS_i32x4_le_u, INS_i64x2_le_s, INS_invalid, INS_f32x4_le, INS_f64x2_le }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_ReturnsPerElementMask) +// TODO-WASM-SIMD: ULONG slot below is INS_invalid because the WASM SIMD spec has no unsigned i64x2 compare (lt_u/le_u/gt_u/ge_u). Requires special codegen (e.g., XOR sign bit + signed compare) to support Vector128 ordered compares. Until that lands, route through impSpecialIntrinsic via HW_Flag_InvalidNodeId so calls fail with a clear NYI instead of recursing into the self-referential managed bodies in PackedSimd.cs. +HARDWARE_INTRINSIC(PackedSimd, CompareGreaterThan, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid }, HW_Category_Helper, HW_Flag_InvalidNodeId) +HARDWARE_INTRINSIC(PackedSimd, CompareGreaterThanOrEqual, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid }, HW_Category_Helper, HW_Flag_InvalidNodeId) +HARDWARE_INTRINSIC(PackedSimd, CompareLessThan, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid }, HW_Category_Helper, HW_Flag_InvalidNodeId) +HARDWARE_INTRINSIC(PackedSimd, CompareLessThanOrEqual, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid }, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(PackedSimd, CompareNotEqual, 16, 2, {INS_i8x16_ne, INS_i8x16_ne, INS_i16x8_ne, INS_i16x8_ne, INS_i32x4_ne, INS_i32x4_ne, INS_i64x2_ne, INS_i64x2_ne, INS_f32x4_ne, INS_f64x2_ne }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_Commutative|HW_Flag_ReturnsPerElementMask) HARDWARE_INTRINSIC(PackedSimd, ConvertNarrowingSaturateSigned, 16, 2, {INS_invalid, INS_invalid, INS_i8x16_narrow_i16x8_s, INS_invalid, INS_i16x8_narrow_i32x4_s, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) @@ -94,7 +94,13 @@ HARDWARE_INTRINSIC(PackedSimd, ConvertToSingle, 1 HARDWARE_INTRINSIC(PackedSimd, ConvertToUInt32Saturate, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_i32x4_trunc_sat_u_f32x4, INS_i32x4_trunc_sat_u_f64x2_zero}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(PackedSimd, Divide, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_f32x4_div, INS_f64x2_div }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(PackedSimd, Dot, 16, 2, {INS_invalid, INS_invalid, INS_i32x4_dot_i16x8_s, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(PackedSimd, ExtractScalar, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid }, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(PackedSimd, Floor, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_f32x4_floor, INS_f64x2_floor }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(PackedSimd, LoadScalarAndInsert, 16, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid }, HW_Category_Helper, HW_Flag_InvalidNodeId) +HARDWARE_INTRINSIC(PackedSimd, LoadScalarAndSplatVector128, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid }, HW_Category_Helper, HW_Flag_InvalidNodeId) +HARDWARE_INTRINSIC(PackedSimd, LoadScalarVector128, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid }, HW_Category_Helper, HW_Flag_InvalidNodeId) +HARDWARE_INTRINSIC(PackedSimd, LoadVector128, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid }, HW_Category_Helper, HW_Flag_InvalidNodeId) +HARDWARE_INTRINSIC(PackedSimd, LoadWideningVector128, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid }, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(PackedSimd, Max, 16, 2, {INS_i8x16_max_s, INS_i8x16_max_u, INS_i16x8_max_s, INS_i16x8_max_u, INS_i32x4_max_s, INS_i32x4_max_u, INS_invalid, INS_invalid, INS_f32x4_max, INS_f64x2_max }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_Commutative) HARDWARE_INTRINSIC(PackedSimd, Min, 16, 2, {INS_i8x16_min_s, INS_i8x16_min_u, INS_i16x8_min_s, INS_i16x8_min_u, INS_i32x4_min_s, INS_i32x4_min_u, INS_invalid, INS_invalid, INS_f32x4_min, INS_f64x2_min }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_Commutative) HARDWARE_INTRINSIC(PackedSimd, Multiply, 16, 2, {INS_invalid, INS_invalid, INS_i16x8_mul, INS_i16x8_mul, INS_i32x4_mul, INS_i32x4_mul, INS_i64x2_mul, INS_i64x2_mul, INS_f32x4_mul, INS_f64x2_mul }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_Commutative) @@ -107,10 +113,17 @@ HARDWARE_INTRINSIC(PackedSimd, Or, 1 HARDWARE_INTRINSIC(PackedSimd, PopCount, 16, 1, {INS_invalid, INS_i8x16_popcnt, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(PackedSimd, PseudoMax, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_f32x4_pmax, INS_f64x2_pmax }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(PackedSimd, PseudoMin, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_f32x4_pmin, INS_f64x2_pmin }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(PackedSimd, ReplaceScalar, 16, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid }, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(PackedSimd, RoundToNearest, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_f32x4_nearest, INS_f64x2_nearest }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(PackedSimd, ShiftLeft, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid }, HW_Category_Helper, HW_Flag_InvalidNodeId) +HARDWARE_INTRINSIC(PackedSimd, ShiftRightArithmetic, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid }, HW_Category_Helper, HW_Flag_InvalidNodeId) +HARDWARE_INTRINSIC(PackedSimd, ShiftRightLogical, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid }, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(PackedSimd, SignExtendWideningLower, 16, 1, {INS_i16x8_extend_low_s_i8x16, INS_i16x8_extend_low_s_i8x16, INS_i32x4_extend_low_s_i16x8, INS_i32x4_extend_low_s_i16x8, INS_i64x2_extend_low_s_i32x4, INS_i64x2_extend_low_s_i32x4, INS_invalid, INS_invalid, INS_invalid, INS_invalid }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(PackedSimd, SignExtendWideningUpper, 16, 1, {INS_i16x8_extend_high_s_i8x16, INS_i16x8_extend_high_s_i8x16, INS_i32x4_extend_high_s_i16x8, INS_i32x4_extend_high_s_i16x8, INS_i64x2_extend_high_s_i32x4, INS_i64x2_extend_high_s_i32x4, INS_invalid, INS_invalid, INS_invalid, INS_invalid }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(PackedSimd, Splat, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid }, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(PackedSimd, Sqrt, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_f32x4_sqrt, INS_f64x2_sqrt }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(PackedSimd, Store, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid }, HW_Category_Helper, HW_Flag_InvalidNodeId) +HARDWARE_INTRINSIC(PackedSimd, StoreSelectedScalar, 16, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid }, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(PackedSimd, Subtract, 16, 2, {INS_i8x16_sub, INS_i8x16_sub, INS_i16x8_sub, INS_i16x8_sub, INS_i32x4_sub, INS_i32x4_sub, INS_i64x2_sub, INS_i64x2_sub, INS_f32x4_sub, INS_f64x2_sub }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(PackedSimd, SubtractSaturate, 16, 2, {INS_i8x16_sub_sat_s, INS_i8x16_sub_sat_u, INS_i16x8_sub_sat_s, INS_i16x8_sub_sat_u, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(PackedSimd, Swizzle, 16, 2, {INS_i8x16_swizzle, INS_i8x16_swizzle, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) diff --git a/src/coreclr/jit/hwintrinsicwasm.cpp b/src/coreclr/jit/hwintrinsicwasm.cpp index 3f1114ab8eace9..f8d06877f1a9cc 100644 --- a/src/coreclr/jit/hwintrinsicwasm.cpp +++ b/src/coreclr/jit/hwintrinsicwasm.cpp @@ -83,6 +83,57 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, switch (intrinsic) { + case NI_Vector128_GetElement: + case NI_Vector128_WithElement: + { + // Vector128.GetElement / WithElement have valid managed implementations in + // Vector128.cs. Return nullptr to let the importer fall back to those rather + // than asserting / NYI'ing in the JIT. + return nullptr; + } + + // The following PackedSimd intrinsics are not yet implemented on WASM. Because + // PackedSimd is decorated with a class-level [Intrinsic], the managed bodies in + // PackedSimd.cs are self-recursive stubs that would stack-overflow at runtime if + // the JIT didn't recognize them. Fail loudly with a descriptive NYI_WASM_SIMD + // instead until codegen lands. + case NI_PackedSimd_CompareGreaterThan: + case NI_PackedSimd_CompareGreaterThanOrEqual: + case NI_PackedSimd_CompareLessThan: + case NI_PackedSimd_CompareLessThanOrEqual: + NYI_WASM_SIMD("PackedSimd ordered compare (needs special codegen for Vector128)"); + break; + + case NI_PackedSimd_ExtractScalar: + NYI_WASM_SIMD("PackedSimd.ExtractScalar"); + break; + case NI_PackedSimd_ReplaceScalar: + NYI_WASM_SIMD("PackedSimd.ReplaceScalar"); + break; + + case NI_PackedSimd_LoadVector128: + case NI_PackedSimd_LoadScalarVector128: + case NI_PackedSimd_LoadScalarAndSplatVector128: + case NI_PackedSimd_LoadScalarAndInsert: + case NI_PackedSimd_LoadWideningVector128: + NYI_WASM_SIMD("PackedSimd load"); + break; + + case NI_PackedSimd_Store: + case NI_PackedSimd_StoreSelectedScalar: + NYI_WASM_SIMD("PackedSimd store"); + break; + + case NI_PackedSimd_ShiftLeft: + case NI_PackedSimd_ShiftRightArithmetic: + case NI_PackedSimd_ShiftRightLogical: + NYI_WASM_SIMD("PackedSimd shift"); + break; + + case NI_PackedSimd_Splat: + NYI_WASM_SIMD("PackedSimd.Splat"); + break; + case NI_Vector128_Create: { // Vector128.Create(T) -> broadcast/"splat" one T value to all elements diff --git a/src/coreclr/scripts/superpmi.py b/src/coreclr/scripts/superpmi.py index 3795bb9443cc3c..dc85979d1f3add 100644 --- a/src/coreclr/scripts/superpmi.py +++ b/src/coreclr/scripts/superpmi.py @@ -2410,6 +2410,14 @@ def create_exception(): # implReadyToRunUnsupported() (CORJIT_R2R_UNSUPPORTED) for NYI_WASM_SIMD during import, so no code is produced. This is an expected behavior. # TODO-WASM: This check can potentially be removed once we no longer have any NYI's in the import stage. if not os.path.exists(item_path) and self.coreclr_args.target_arch == "wasm": + # Log a warning so that unexpected misses (vs the expected JitWasmSimdNyiToR2RUnsupported path) remain diagnosable + # rather than being silently masked as empty diffs. + stderr_snippet = stderr.decode(errors='replace').strip().splitlines() + stderr_first_line = stderr_snippet[0] if stderr_snippet else "" + logging.warning( + "%sNo JitStdOutFile produced for wasm context %s at %s (exit=%d, stderr first line: %r). " + "Treating as empty diff; verify this is the expected JitWasmSimdNyiToR2RUnsupported path.", + print_prefix, context_index, item_path, proc.returncode, stderr_first_line) return "" try: From aff1238c17577bf8c6ff193dc2b5933921578d2e Mon Sep 17 00:00:00 2001 From: Adam Perlin Date: Thu, 25 Jun 2026 11:10:02 -0700 Subject: [PATCH 20/24] Update src/coreclr/jit/hwintrinsic.cpp Co-authored-by: Tanner Gooding --- src/coreclr/jit/hwintrinsic.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/coreclr/jit/hwintrinsic.cpp b/src/coreclr/jit/hwintrinsic.cpp index 6e301af5223f5e..220f2b82f11a37 100644 --- a/src/coreclr/jit/hwintrinsic.cpp +++ b/src/coreclr/jit/hwintrinsic.cpp @@ -1049,7 +1049,8 @@ static const HWIntrinsicIsaRange hwintrinsicIsaRangeArray[] = { #elif defined(TARGET_WASM) { NI_Illegal, NI_Illegal }, // WasmBase { FIRST_NI_PackedSimd, LAST_NI_PackedSimd }, // PackedSimd - { FIRST_NI_Vector128, LAST_NI_Vector128 }, // Vector128 + { FIRST_NI_PackedSimd, LAST_NI_PackedSimd }, // PackedSimd + { FIRST_NI_Vector128, LAST_NI_Vector128 }, // Vector128 #else #error Unsupported platform #endif From 79f9b4d3e776a933ad787cb079d0b4682976e8ba Mon Sep 17 00:00:00 2001 From: Adam Date: Thu, 25 Jun 2026 17:06:46 -0700 Subject: [PATCH 21/24] Additional review feedback: handle PackedSimd.LoadVector128, Store to impSpecialIntrinsic with gtNewSimd helpers, remove NYI_WASM_SIMD from impSpecialIntrinsic --- src/coreclr/jit/codegenwasm.cpp | 5 --- src/coreclr/jit/hwintrinsiclistwasm.h | 4 +-- src/coreclr/jit/hwintrinsicwasm.cpp | 46 +++++++++++++++++++-------- 3 files changed, 34 insertions(+), 21 deletions(-) diff --git a/src/coreclr/jit/codegenwasm.cpp b/src/coreclr/jit/codegenwasm.cpp index 76ccc784a43394..d9a0020d76d640 100644 --- a/src/coreclr/jit/codegenwasm.cpp +++ b/src/coreclr/jit/codegenwasm.cpp @@ -2669,11 +2669,6 @@ void CodeGen::genCodeForIndir(GenTreeIndir* tree) assert(tree->OperIs(GT_IND)); var_types type = tree->TypeGet(); - if (type == TYP_SIMD16) - { - NYI_WASM_SIMD("SIMD16 indirect load"); - } - instruction ins = ins_Load(type); genConsumeAddress(tree->Addr()); diff --git a/src/coreclr/jit/hwintrinsiclistwasm.h b/src/coreclr/jit/hwintrinsiclistwasm.h index 7d6fe714a41cf7..6e870dd13bc2b6 100644 --- a/src/coreclr/jit/hwintrinsiclistwasm.h +++ b/src/coreclr/jit/hwintrinsiclistwasm.h @@ -99,7 +99,7 @@ HARDWARE_INTRINSIC(PackedSimd, Floor, 1 HARDWARE_INTRINSIC(PackedSimd, LoadScalarAndInsert, 16, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid }, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(PackedSimd, LoadScalarAndSplatVector128, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid }, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(PackedSimd, LoadScalarVector128, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid }, HW_Category_Helper, HW_Flag_InvalidNodeId) -HARDWARE_INTRINSIC(PackedSimd, LoadVector128, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid }, HW_Category_Helper, HW_Flag_InvalidNodeId) +HARDWARE_INTRINSIC(PackedSimd, LoadVector128, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid }, HW_Category_Helper, HW_Flag_InvalidNodeId|HW_Flag_SpecialImport) HARDWARE_INTRINSIC(PackedSimd, LoadWideningVector128, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid }, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(PackedSimd, Max, 16, 2, {INS_i8x16_max_s, INS_i8x16_max_u, INS_i16x8_max_s, INS_i16x8_max_u, INS_i32x4_max_s, INS_i32x4_max_u, INS_invalid, INS_invalid, INS_f32x4_max, INS_f64x2_max }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_Commutative) HARDWARE_INTRINSIC(PackedSimd, Min, 16, 2, {INS_i8x16_min_s, INS_i8x16_min_u, INS_i16x8_min_s, INS_i16x8_min_u, INS_i32x4_min_s, INS_i32x4_min_u, INS_invalid, INS_invalid, INS_f32x4_min, INS_f64x2_min }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_Commutative) @@ -122,7 +122,7 @@ HARDWARE_INTRINSIC(PackedSimd, SignExtendWideningLower, 1 HARDWARE_INTRINSIC(PackedSimd, SignExtendWideningUpper, 16, 1, {INS_i16x8_extend_high_s_i8x16, INS_i16x8_extend_high_s_i8x16, INS_i32x4_extend_high_s_i16x8, INS_i32x4_extend_high_s_i16x8, INS_i64x2_extend_high_s_i32x4, INS_i64x2_extend_high_s_i32x4, INS_invalid, INS_invalid, INS_invalid, INS_invalid }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(PackedSimd, Splat, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid }, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(PackedSimd, Sqrt, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_f32x4_sqrt, INS_f64x2_sqrt }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(PackedSimd, Store, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid }, HW_Category_Helper, HW_Flag_InvalidNodeId) +HARDWARE_INTRINSIC(PackedSimd, Store, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid }, HW_Category_MemoryStore, HW_Flag_InvalidNodeId|HW_Flag_SpecialImport|HW_Flag_BaseTypeFromSecondArg) HARDWARE_INTRINSIC(PackedSimd, StoreSelectedScalar, 16, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid }, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(PackedSimd, Subtract, 16, 2, {INS_i8x16_sub, INS_i8x16_sub, INS_i16x8_sub, INS_i16x8_sub, INS_i32x4_sub, INS_i32x4_sub, INS_i64x2_sub, INS_i64x2_sub, INS_f32x4_sub, INS_f64x2_sub }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(PackedSimd, SubtractSaturate, 16, 2, {INS_i8x16_sub_sat_s, INS_i8x16_sub_sat_u, INS_i16x8_sub_sat_s, INS_i16x8_sub_sat_u, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid }, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) diff --git a/src/coreclr/jit/hwintrinsicwasm.cpp b/src/coreclr/jit/hwintrinsicwasm.cpp index f8d06877f1a9cc..94ecbf56819d0d 100644 --- a/src/coreclr/jit/hwintrinsicwasm.cpp +++ b/src/coreclr/jit/hwintrinsicwasm.cpp @@ -80,6 +80,7 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, GenTree* retNode = nullptr; GenTree* op1 = nullptr; + GenTree* op2 = nullptr; switch (intrinsic) { @@ -92,46 +93,65 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, return nullptr; } - // The following PackedSimd intrinsics are not yet implemented on WASM. Because - // PackedSimd is decorated with a class-level [Intrinsic], the managed bodies in - // PackedSimd.cs are self-recursive stubs that would stack-overflow at runtime if - // the JIT didn't recognize them. Fail loudly with a descriptive NYI_WASM_SIMD - // instead until codegen lands. + // The following PackedSimd intrinsics are not yet implemented on WASM. Because they are must-expand, + // when we return nullptr here the importer will insert a PlatformNotSupportedException throw. case NI_PackedSimd_CompareGreaterThan: case NI_PackedSimd_CompareGreaterThanOrEqual: case NI_PackedSimd_CompareLessThan: case NI_PackedSimd_CompareLessThanOrEqual: - NYI_WASM_SIMD("PackedSimd ordered compare (needs special codegen for Vector128)"); break; case NI_PackedSimd_ExtractScalar: - NYI_WASM_SIMD("PackedSimd.ExtractScalar"); break; + case NI_PackedSimd_ReplaceScalar: - NYI_WASM_SIMD("PackedSimd.ReplaceScalar"); break; case NI_PackedSimd_LoadVector128: + { + assert(sig->numArgs == 1); + assert(simdSize == 16); + op1 = impPopStack().val; + if (op1->OperIs(GT_CAST) && op1->gtGetOp1()->TypeIs(TYP_BYREF)) + { + // If what we have is a BYREF, that's what we really want, so throw away the cast. + op1 = op1->gtGetOp1(); + } + + return gtNewSimdLoadNode(retType, op1, simdBaseType, simdSize); + } + case NI_PackedSimd_LoadScalarVector128: case NI_PackedSimd_LoadScalarAndSplatVector128: case NI_PackedSimd_LoadScalarAndInsert: case NI_PackedSimd_LoadWideningVector128: - NYI_WASM_SIMD("PackedSimd load"); break; case NI_PackedSimd_Store: + { + assert(sig->numArgs == 2); + assert(simdSize == 16); + op2 = impPopStack().val; + op1 = impPopStack().val; + + if (op1->OperIs(GT_CAST) && op1->gtGetOp1()->TypeIs(TYP_BYREF)) + { + // If what we have is a BYREF, that's what we really want, so throw away the cast. + op1 = op1->gtGetOp1(); + } + + return gtNewSimdStoreNode(op1, op2, simdBaseType, simdSize); + } + case NI_PackedSimd_StoreSelectedScalar: - NYI_WASM_SIMD("PackedSimd store"); break; case NI_PackedSimd_ShiftLeft: case NI_PackedSimd_ShiftRightArithmetic: case NI_PackedSimd_ShiftRightLogical: - NYI_WASM_SIMD("PackedSimd shift"); break; case NI_PackedSimd_Splat: - NYI_WASM_SIMD("PackedSimd.Splat"); break; case NI_Vector128_Create: @@ -272,13 +292,11 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, // TODO-WASM-SIMD: Build a GT_HWINTRINSIC node packing N non-constant operands // (mirroring the arm64/xarch IntrinsicNodeBuilder path) once WASM SIMD lowering // and codegen for Vector128.Create are implemented. - retNode = nullptr; break; } default: { - NYI_WASM_SIMD("impSpecialIntrinsic"); break; } } From 132760afe7ba50a2900384fd20b9dc6c9616c84f Mon Sep 17 00:00:00 2001 From: Adam Date: Fri, 26 Jun 2026 10:39:00 -0700 Subject: [PATCH 22/24] Add impSimdCreate helper shared across targets --- src/coreclr/jit/codegenwasm.cpp | 4 +- src/coreclr/jit/compiler.h | 5 + src/coreclr/jit/hwintrinsic.cpp | 156 +++++++++++++++++++++++++++ src/coreclr/jit/hwintrinsicarm64.cpp | 146 +------------------------ src/coreclr/jit/hwintrinsicwasm.cpp | 137 +---------------------- src/coreclr/jit/hwintrinsicxarch.cpp | 143 +----------------------- 6 files changed, 166 insertions(+), 425 deletions(-) diff --git a/src/coreclr/jit/codegenwasm.cpp b/src/coreclr/jit/codegenwasm.cpp index d9a0020d76d640..690e90b0c0cea0 100644 --- a/src/coreclr/jit/codegenwasm.cpp +++ b/src/coreclr/jit/codegenwasm.cpp @@ -2668,8 +2668,8 @@ void CodeGen::genCodeForIndir(GenTreeIndir* tree) { assert(tree->OperIs(GT_IND)); - var_types type = tree->TypeGet(); - instruction ins = ins_Load(type); + var_types type = tree->TypeGet(); + instruction ins = ins_Load(type); genConsumeAddress(tree->Addr()); diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 15161eacd678d8..9c1ab063bddb6b 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -5152,6 +5152,11 @@ class Compiler GenTree* impImportLdvirtftn(GenTree* thisPtr, CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_CALL_INFO* pCallInfo); #if defined(FEATURE_HW_INTRINSICS) + GenTree* impSimdCreate(NamedIntrinsic intrinsic, + CORINFO_SIG_INFO* sig, + var_types simdBaseType, + var_types retType, + unsigned simdSize); GenTree* impSimdCreateScalarHalf(GenTree* op1); GenTree* impSimdToScalarHalf(GenTree* op1, CORINFO_CLASS_HANDLE halfClsHnd); #endif // FEATURE_HW_INTRINSICS diff --git a/src/coreclr/jit/hwintrinsic.cpp b/src/coreclr/jit/hwintrinsic.cpp index 6e301af5223f5e..9cd4d19e904f34 100644 --- a/src/coreclr/jit/hwintrinsic.cpp +++ b/src/coreclr/jit/hwintrinsic.cpp @@ -1604,6 +1604,162 @@ GenTree* Compiler::getArgForHWIntrinsic(var_types argType, CORINFO_CLASS_HANDLE return arg; } +//------------------------------------------------------------------------ +// impSimdCreate: Common importer logic for Vector{64,128,256,512}.Create intrinsics. +// +// Handles the shared pattern used across xarch, arm64, and wasm: +// * sig->numArgs == 1 -> emit a broadcast/splat node +// * sig->numArgs == simdLength, all const-> fold into a single GenTreeVecCon +// * otherwise -> pack operands into a GT_HWINTRINSIC +// via IntrinsicNodeBuilder +// +// Arguments: +// intrinsic -- the NI_Vector*_Create NamedIntrinsic being imported +// sig -- the call signature (used for numArgs) +// simdBaseType -- the base element type of the SIMD vector +// retType -- the SIMD return type +// simdSize -- size in bytes of the SIMD vector +// +// Return Value: +// The imported GenTree* representing the Create call. Operands are popped +// off the importer stack as part of this call. +// +GenTree* Compiler::impSimdCreate( + NamedIntrinsic intrinsic, CORINFO_SIG_INFO* sig, var_types simdBaseType, var_types retType, unsigned simdSize) +{ + if (sig->numArgs == 1) + { + GenTree* op1 = impPopStack().val; + return gtNewSimdCreateBroadcastNode(retType, op1, simdBaseType, simdSize); + } + + uint32_t simdLength = getSIMDVectorLength(simdSize, simdBaseType); + assert(sig->numArgs == simdLength); + + bool isConstant = true; + + if (varTypeIsFloating(simdBaseType)) + { + for (uint32_t index = 0; index < sig->numArgs; index++) + { + if (!impStackTop(index).val->IsCnsFltOrDbl()) + { + isConstant = false; + break; + } + } + } + else + { + assert(varTypeIsIntegral(simdBaseType)); + + for (uint32_t index = 0; index < sig->numArgs; index++) + { + if (!impStackTop(index).val->IsIntegralConst()) + { + isConstant = false; + break; + } + } + } + + if (isConstant) + { + GenTreeVecCon* vecCon = gtNewVconNode(retType); + + switch (simdBaseType) + { + case TYP_BYTE: + case TYP_UBYTE: + { + for (uint32_t index = 0; index < sig->numArgs; index++) + { + uint8_t cnsVal = static_cast(impPopStack().val->AsIntConCommon()->IntegralValue()); + vecCon->gtSimdVal.u8[simdLength - 1 - index] = cnsVal; + } + break; + } + + case TYP_SHORT: + case TYP_USHORT: + { + for (uint32_t index = 0; index < sig->numArgs; index++) + { + uint16_t cnsVal = static_cast(impPopStack().val->AsIntConCommon()->IntegralValue()); + vecCon->gtSimdVal.u16[simdLength - 1 - index] = cnsVal; + } + break; + } + + case TYP_INT: + case TYP_UINT: + { + for (uint32_t index = 0; index < sig->numArgs; index++) + { + uint32_t cnsVal = static_cast(impPopStack().val->AsIntConCommon()->IntegralValue()); + vecCon->gtSimdVal.u32[simdLength - 1 - index] = cnsVal; + } + break; + } + + case TYP_LONG: + case TYP_ULONG: + { + for (uint32_t index = 0; index < sig->numArgs; index++) + { + uint64_t cnsVal = static_cast(impPopStack().val->AsIntConCommon()->IntegralValue()); + vecCon->gtSimdVal.u64[simdLength - 1 - index] = cnsVal; + } + break; + } + + case TYP_FLOAT: + { + for (uint32_t index = 0; index < sig->numArgs; index++) + { + float cnsVal = static_cast(impPopStack().val->AsDblCon()->DconValue()); + vecCon->gtSimdVal.f32[simdLength - 1 - index] = cnsVal; + } + break; + } + + case TYP_DOUBLE: + { + for (uint32_t index = 0; index < sig->numArgs; index++) + { + double cnsVal = static_cast(impPopStack().val->AsDblCon()->DconValue()); + vecCon->gtSimdVal.f64[simdLength - 1 - index] = cnsVal; + } + break; + } + + default: + { + unreached(); + } + } + + return vecCon; + } +#ifdef TARGET_WASM + else + { + // non const Vector128.Create not yet implemented on Wasm + return nullptr; + } +#endif + + IntrinsicNodeBuilder nodeBuilder(getAllocator(CMK_ASTNode), sig->numArgs); + + for (int i = sig->numArgs - 1; i >= 0; i--) + { + GenTree* arg = impPopStack().val; + nodeBuilder.AddOperand(i, arg); + } + + return gtNewSimdHWIntrinsicNode(retType, std::move(nodeBuilder), intrinsic, simdBaseType, simdSize); +} + //------------------------------------------------------------------------ // addRangeCheckIfNeeded: add a GT_BOUNDS_CHECK node for non-full-range imm-intrinsic // diff --git a/src/coreclr/jit/hwintrinsicarm64.cpp b/src/coreclr/jit/hwintrinsicarm64.cpp index 2f8b9988c7810e..e21b4730c7eec9 100644 --- a/src/coreclr/jit/hwintrinsicarm64.cpp +++ b/src/coreclr/jit/hwintrinsicarm64.cpp @@ -1127,151 +1127,7 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, case NI_Vector64_Create: case NI_Vector128_Create: { - if (sig->numArgs == 1) - { - op1 = impPopStack().val; - retNode = gtNewSimdCreateBroadcastNode(retType, op1, simdBaseType, simdSize); - break; - } - - uint32_t simdLength = getSIMDVectorLength(simdSize, simdBaseType); - assert(sig->numArgs == simdLength); - - bool isConstant = true; - - if (varTypeIsFloating(simdBaseType)) - { - for (uint32_t index = 0; index < sig->numArgs; index++) - { - GenTree* arg = impStackTop(index).val; - - if (!arg->IsCnsFltOrDbl()) - { - isConstant = false; - break; - } - } - } - else - { - assert(varTypeIsIntegral(simdBaseType)); - - for (uint32_t index = 0; index < sig->numArgs; index++) - { - GenTree* arg = impStackTop(index).val; - - if (!arg->IsIntegralConst()) - { - isConstant = false; - break; - } - } - } - - if (isConstant) - { - // Some of the below code assumes 8 or 16 byte SIMD types - assert((simdSize == 8) || (simdSize == 16)); - - GenTreeVecCon* vecCon = gtNewVconNode(retType); - - switch (simdBaseType) - { - case TYP_BYTE: - case TYP_UBYTE: - { - uint8_t cnsVal = 0; - - for (uint32_t index = 0; index < sig->numArgs; index++) - { - cnsVal = static_cast(impPopStack().val->AsIntConCommon()->IntegralValue()); - vecCon->gtSimdVal.u8[simdLength - 1 - index] = cnsVal; - } - break; - } - - case TYP_SHORT: - case TYP_USHORT: - { - uint16_t cnsVal = 0; - - for (uint32_t index = 0; index < sig->numArgs; index++) - { - cnsVal = static_cast(impPopStack().val->AsIntConCommon()->IntegralValue()); - vecCon->gtSimdVal.u16[simdLength - 1 - index] = cnsVal; - } - break; - } - - case TYP_INT: - case TYP_UINT: - { - uint32_t cnsVal = 0; - - for (uint32_t index = 0; index < sig->numArgs; index++) - { - cnsVal = static_cast(impPopStack().val->AsIntConCommon()->IntegralValue()); - vecCon->gtSimdVal.u32[simdLength - 1 - index] = cnsVal; - } - break; - } - - case TYP_LONG: - case TYP_ULONG: - { - uint64_t cnsVal = 0; - - for (uint32_t index = 0; index < sig->numArgs; index++) - { - cnsVal = static_cast(impPopStack().val->AsIntConCommon()->IntegralValue()); - vecCon->gtSimdVal.u64[simdLength - 1 - index] = cnsVal; - } - break; - } - - case TYP_FLOAT: - { - float cnsVal = 0; - - for (uint32_t index = 0; index < sig->numArgs; index++) - { - cnsVal = static_cast(impPopStack().val->AsDblCon()->DconValue()); - vecCon->gtSimdVal.f32[simdLength - 1 - index] = cnsVal; - } - break; - } - - case TYP_DOUBLE: - { - double cnsVal = 0; - - for (uint32_t index = 0; index < sig->numArgs; index++) - { - cnsVal = static_cast(impPopStack().val->AsDblCon()->DconValue()); - vecCon->gtSimdVal.f64[simdLength - 1 - index] = cnsVal; - } - break; - } - - default: - { - unreached(); - } - } - - retNode = vecCon; - break; - } - - IntrinsicNodeBuilder nodeBuilder(getAllocator(CMK_ASTNode), sig->numArgs); - - for (int i = sig->numArgs - 1; i >= 0; i--) - { - GenTree* arg = impPopStack().val; - nodeBuilder.AddOperand(i, arg); - } - - retNode = gtNewSimdHWIntrinsicNode(retType, std::move(nodeBuilder), intrinsic, simdBaseType, simdSize); + retNode = impSimdCreate(intrinsic, sig, simdBaseType, retType, simdSize); break; } diff --git a/src/coreclr/jit/hwintrinsicwasm.cpp b/src/coreclr/jit/hwintrinsicwasm.cpp index 94ecbf56819d0d..2f25e4506e12ce 100644 --- a/src/coreclr/jit/hwintrinsicwasm.cpp +++ b/src/coreclr/jit/hwintrinsicwasm.cpp @@ -156,142 +156,7 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, case NI_Vector128_Create: { - // Vector128.Create(T) -> broadcast/"splat" one T value to all elements - // Vector128.Create(T, T, ..., T) -> pack N scalar T values - // - // For either form, if T is a const we can leverage a GenTreeVecCon and map directly to v128.const - if (sig->numArgs == 1) - { - GenTree* const arg = impStackTop().val; - if (!arg->IsIntegralConst() && !arg->IsCnsFltOrDbl()) - { - // Non-constant broadcast isn't supported yet on WASM; - return nullptr; - } - - op1 = impPopStack().val; - retNode = gtNewSimdCreateBroadcastNode(retType, op1, simdBaseType, simdSize); - break; - } - - uint32_t simdLength = getSIMDVectorLength(simdSize, simdBaseType); - assert(sig->numArgs == simdLength); - - bool isConstant = true; - - if (varTypeIsFloating(simdBaseType)) - { - for (uint32_t index = 0; index < sig->numArgs; index++) - { - if (!impStackTop(index).val->IsCnsFltOrDbl()) - { - isConstant = false; - break; - } - } - } - else - { - assert(varTypeIsIntegral(simdBaseType)); - - for (uint32_t index = 0; index < sig->numArgs; index++) - { - if (!impStackTop(index).val->IsIntegralConst()) - { - isConstant = false; - break; - } - } - } - - if (isConstant) - { - assert(simdSize == 16); - - GenTreeVecCon* vecCon = gtNewVconNode(retType); - - switch (simdBaseType) - { - case TYP_BYTE: - case TYP_UBYTE: - { - for (uint32_t index = 0; index < sig->numArgs; index++) - { - uint8_t cnsVal = static_cast(impPopStack().val->AsIntConCommon()->IntegralValue()); - vecCon->gtSimdVal.u8[simdLength - 1 - index] = cnsVal; - } - break; - } - - case TYP_SHORT: - case TYP_USHORT: - { - for (uint32_t index = 0; index < sig->numArgs; index++) - { - uint16_t cnsVal = - static_cast(impPopStack().val->AsIntConCommon()->IntegralValue()); - vecCon->gtSimdVal.u16[simdLength - 1 - index] = cnsVal; - } - break; - } - - case TYP_INT: - case TYP_UINT: - { - for (uint32_t index = 0; index < sig->numArgs; index++) - { - uint32_t cnsVal = - static_cast(impPopStack().val->AsIntConCommon()->IntegralValue()); - vecCon->gtSimdVal.u32[simdLength - 1 - index] = cnsVal; - } - break; - } - - case TYP_LONG: - case TYP_ULONG: - { - for (uint32_t index = 0; index < sig->numArgs; index++) - { - uint64_t cnsVal = - static_cast(impPopStack().val->AsIntConCommon()->IntegralValue()); - vecCon->gtSimdVal.u64[simdLength - 1 - index] = cnsVal; - } - break; - } - - case TYP_FLOAT: - { - for (uint32_t index = 0; index < sig->numArgs; index++) - { - float cnsVal = static_cast(impPopStack().val->AsDblCon()->DconValue()); - vecCon->gtSimdVal.f32[simdLength - 1 - index] = cnsVal; - } - break; - } - - case TYP_DOUBLE: - { - for (uint32_t index = 0; index < sig->numArgs; index++) - { - double cnsVal = static_cast(impPopStack().val->AsDblCon()->DconValue()); - vecCon->gtSimdVal.f64[simdLength - 1 - index] = cnsVal; - } - break; - } - - default: - { - unreached(); - } - } - - retNode = vecCon; - break; - } - - // TODO-WASM-SIMD: Build a GT_HWINTRINSIC node packing N non-constant operands - // (mirroring the arm64/xarch IntrinsicNodeBuilder path) once WASM SIMD lowering - // and codegen for Vector128.Create are implemented. + retNode = impSimdCreate(intrinsic, sig, simdBaseType, retType, simdSize); break; } diff --git a/src/coreclr/jit/hwintrinsicxarch.cpp b/src/coreclr/jit/hwintrinsicxarch.cpp index d4972a9fb3d5b7..784b1d7d6a1c6c 100644 --- a/src/coreclr/jit/hwintrinsicxarch.cpp +++ b/src/coreclr/jit/hwintrinsicxarch.cpp @@ -2031,148 +2031,7 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, case NI_Vector256_Create: case NI_Vector512_Create: { - if (sig->numArgs == 1) - { - op1 = impPopStack().val; - retNode = gtNewSimdCreateBroadcastNode(retType, op1, simdBaseType, simdSize); - break; - } - - uint32_t simdLength = getSIMDVectorLength(simdSize, simdBaseType); - assert(sig->numArgs == simdLength); - - bool isConstant = true; - - if (varTypeIsFloating(simdBaseType)) - { - for (uint32_t index = 0; index < sig->numArgs; index++) - { - GenTree* arg = impStackTop(index).val; - - if (!arg->IsCnsFltOrDbl()) - { - isConstant = false; - break; - } - } - } - else - { - assert(varTypeIsIntegral(simdBaseType)); - - for (uint32_t index = 0; index < sig->numArgs; index++) - { - GenTree* arg = impStackTop(index).val; - - if (!arg->IsIntegralConst()) - { - isConstant = false; - break; - } - } - } - - if (isConstant) - { - GenTreeVecCon* vecCon = gtNewVconNode(retType); - - switch (simdBaseType) - { - case TYP_BYTE: - case TYP_UBYTE: - { - uint8_t cnsVal = 0; - - for (uint32_t index = 0; index < sig->numArgs; index++) - { - cnsVal = static_cast(impPopStack().val->AsIntConCommon()->IntegralValue()); - vecCon->gtSimdVal.u8[simdLength - 1 - index] = cnsVal; - } - break; - } - - case TYP_SHORT: - case TYP_USHORT: - { - uint16_t cnsVal = 0; - - for (uint32_t index = 0; index < sig->numArgs; index++) - { - cnsVal = static_cast(impPopStack().val->AsIntConCommon()->IntegralValue()); - vecCon->gtSimdVal.u16[simdLength - 1 - index] = cnsVal; - } - break; - } - - case TYP_INT: - case TYP_UINT: - { - uint32_t cnsVal = 0; - - for (uint32_t index = 0; index < sig->numArgs; index++) - { - cnsVal = static_cast(impPopStack().val->AsIntConCommon()->IntegralValue()); - vecCon->gtSimdVal.u32[simdLength - 1 - index] = cnsVal; - } - break; - } - - case TYP_LONG: - case TYP_ULONG: - { - uint64_t cnsVal = 0; - - for (uint32_t index = 0; index < sig->numArgs; index++) - { - cnsVal = static_cast(impPopStack().val->AsIntConCommon()->IntegralValue()); - vecCon->gtSimdVal.u64[simdLength - 1 - index] = cnsVal; - } - break; - } - - case TYP_FLOAT: - { - float cnsVal = 0; - - for (uint32_t index = 0; index < sig->numArgs; index++) - { - cnsVal = static_cast(impPopStack().val->AsDblCon()->DconValue()); - vecCon->gtSimdVal.f32[simdLength - 1 - index] = cnsVal; - } - break; - } - - case TYP_DOUBLE: - { - double cnsVal = 0; - - for (uint32_t index = 0; index < sig->numArgs; index++) - { - double cnsVal = static_cast(impPopStack().val->AsDblCon()->DconValue()); - vecCon->gtSimdVal.f64[simdLength - 1 - index] = cnsVal; - } - break; - } - - default: - { - unreached(); - } - } - - retNode = vecCon; - break; - } - - IntrinsicNodeBuilder nodeBuilder(getAllocator(CMK_ASTNode), sig->numArgs); - - for (int i = sig->numArgs - 1; i >= 0; i--) - { - GenTree* arg = impPopStack().val; - nodeBuilder.AddOperand(i, arg); - } - - retNode = gtNewSimdHWIntrinsicNode(retType, std::move(nodeBuilder), intrinsic, simdBaseType, simdSize); + retNode = impSimdCreate(intrinsic, sig, simdBaseType, retType, simdSize); break; } From b868b5858250eb0b92c3f35e660ea9b480a17fc4 Mon Sep 17 00:00:00 2001 From: Adam Date: Fri, 26 Jun 2026 16:38:02 -0700 Subject: [PATCH 23/24] Fix op reversal assert --- src/coreclr/jit/gentree.cpp | 8 ++++++++ src/coreclr/jit/hwintrinsic.cpp | 1 - src/coreclr/jit/hwintrinsiclistwasm.h | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index 9adc0f618894bb..b5233482ee10f8 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -4777,6 +4777,13 @@ unsigned Compiler::gtSetMultiOpOrder(GenTreeMultiOp* multiOp) // We want the more complex tree to be evaluated first. if ((level < lvl2) && !multiOp->AsHWIntrinsic()->IsUserCall() && gtCanSwapOrder(op1, op2)) { +#if defined(TARGET_WASM) + // TODO-WASM-CQ: Wasm's stack-machine codegen requires operands to be evaluated in + // source order, so we cannot honor GTF_REVERSE_OPS here. For commutative HW + // intrinsics we could instead physically swap multiOp->Op(1)/Op(2) to retain the + // CQ benefit (mirroring the binary commutative path in gtSetEvalOrder). For now, + // just skip the swap to keep evaluation order intact. +#else if (multiOp->IsReverseOp()) { multiOp->ClearReverseOp(); @@ -4787,6 +4794,7 @@ unsigned Compiler::gtSetMultiOpOrder(GenTreeMultiOp* multiOp) } std::swap(level, lvl2); +#endif // TARGET_WASM } if (level < 1) diff --git a/src/coreclr/jit/hwintrinsic.cpp b/src/coreclr/jit/hwintrinsic.cpp index 598e4d24724a93..2e97cdf9d3715a 100644 --- a/src/coreclr/jit/hwintrinsic.cpp +++ b/src/coreclr/jit/hwintrinsic.cpp @@ -1048,7 +1048,6 @@ static const HWIntrinsicIsaRange hwintrinsicIsaRangeArray[] = { { NI_Illegal, NI_Illegal }, // SveSm4_Arm64 #elif defined(TARGET_WASM) { NI_Illegal, NI_Illegal }, // WasmBase - { FIRST_NI_PackedSimd, LAST_NI_PackedSimd }, // PackedSimd { FIRST_NI_PackedSimd, LAST_NI_PackedSimd }, // PackedSimd { FIRST_NI_Vector128, LAST_NI_Vector128 }, // Vector128 #else diff --git a/src/coreclr/jit/hwintrinsiclistwasm.h b/src/coreclr/jit/hwintrinsiclistwasm.h index 6e870dd13bc2b6..692835d03476fc 100644 --- a/src/coreclr/jit/hwintrinsiclistwasm.h +++ b/src/coreclr/jit/hwintrinsiclistwasm.h @@ -32,7 +32,7 @@ HARDWARE_INTRINSIC(Vector128, AsUInt32, HARDWARE_INTRINSIC(Vector128, AsUInt64, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector128, AsVector128Unsafe, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMD, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector128, AsVector2, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) -HARDWARE_INTRINSIC(Vector128, AsVector3, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) +HARDWARE_INTRINSIC(Vector128, AsVector3, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector128, AsVector4, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector128, Create, 16, -1, {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_InvalidNodeId) HARDWARE_INTRINSIC(Vector128, CreateScalar, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) From 3a54c5ae3159856a3f2c848730abac9f19c9430b Mon Sep 17 00:00:00 2001 From: Adam Perlin Date: Fri, 26 Jun 2026 18:55:27 -0700 Subject: [PATCH 24/24] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- src/coreclr/jit/hwintrinsic.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/coreclr/jit/hwintrinsic.cpp b/src/coreclr/jit/hwintrinsic.cpp index 2e97cdf9d3715a..60466cef97decd 100644 --- a/src/coreclr/jit/hwintrinsic.cpp +++ b/src/coreclr/jit/hwintrinsic.cpp @@ -1629,7 +1629,18 @@ GenTree* Compiler::impSimdCreate( { if (sig->numArgs == 1) { - GenTree* op1 = impPopStack().val; + GenTree* op1 = impStackTop().val; + +#ifdef TARGET_WASM + if (!(op1->IsIntegralConst() || op1->IsCnsFltOrDbl())) + { + // Vector*.Create(T) with a non-constant operand is not yet supported on Wasm. + // Returning nullptr lets the importer fall back to the managed implementation. + return nullptr; + } +#endif + + op1 = impPopStack().val; return gtNewSimdCreateBroadcastNode(retType, op1, simdBaseType, simdSize); }