From 930d3c76312ea949b494617465fabae4749df260 Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Thu, 2 Jul 2026 21:14:11 -0700 Subject: [PATCH 1/6] Fixup the wasm hwintrinsiclist to have all the right instruction entries --- src/coreclr/jit/hwintrinsiclistwasm.h | 34 +++++++++++++-------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/coreclr/jit/hwintrinsiclistwasm.h b/src/coreclr/jit/hwintrinsiclistwasm.h index d728e7da3f8e00..cd34f686b1398d 100644 --- a/src/coreclr/jit/hwintrinsiclistwasm.h +++ b/src/coreclr/jit/hwintrinsiclistwasm.h @@ -29,11 +29,10 @@ HARDWARE_INTRINSIC(PackedSimd, Bitmask, 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, -1, -1, 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, -1, -1, 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, -1, -1, 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. 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, -1, -1, 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, -1, -1, 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, -1, -1, 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, -1, -1, HW_Category_Helper, HW_Flag_InvalidNodeId) +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, -1, -1, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_SpecialCodeGen|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, -1, -1, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_SpecialCodeGen|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, -1, -1, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_SpecialCodeGen|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, -1, -1, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_SpecialCodeGen|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, -1, -1, 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, -1, -1, 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, -1, -1, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) @@ -43,13 +42,13 @@ HARDWARE_INTRINSIC(PackedSimd, ConvertToSingle, 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, -1, -1, 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, -1, -1, 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, -1, -1, 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, -1, -1, HW_Category_Helper, HW_Flag_InvalidNodeId) +HARDWARE_INTRINSIC(PackedSimd, ExtractScalar, 16, 2, INS_i8x16_extract_lane_s, INS_i8x16_extract_lane_u, INS_i16x8_extract_lane_s, INS_i16x8_extract_lane_u, INS_i32x4_extract_lane, INS_i32x4_extract_lane, INS_i64x2_extract_lane, INS_i64x2_extract_lane, INS_f32x4_extract_lane, INS_f64x2_extract_lane, -1, -1, HW_Category_IMM, 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, -1, -1, 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, -1, -1, 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, -1, -1, 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, -1, -1, HW_Category_Helper, HW_Flag_InvalidNodeId) +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, -1, -1, HW_Category_Helper, HW_Flag_InvalidNodeId|HW_Flag_SpecialImport) +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, -1, -1, HW_Category_Helper, HW_Flag_InvalidNodeId|HW_Flag_SpecialImport) +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, -1, -1, HW_Category_Helper, HW_Flag_InvalidNodeId|HW_Flag_SpecialImport) 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, -1, -1, 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, -1, -1, HW_Category_Helper, HW_Flag_InvalidNodeId) +HARDWARE_INTRINSIC(PackedSimd, LoadWideningVector128, 16, 1, INS_v128_load8x8_s, INS_v128_load8x8_u, INS_v128_load16x4_s, INS_v128_load16x4_u, INS_v128_load32x2_s, INS_v128_load32x2_u, INS_invalid, INS_invalid, INS_invalid, INS_invalid, -1, -1, HW_Category_MemoryLoad, HW_Flag_SpecialImport) 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, -1, -1, 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, -1, -1, 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, -1, -1, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_Commutative) @@ -62,17 +61,18 @@ HARDWARE_INTRINSIC(PackedSimd, Or, 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, -1, -1, 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, -1, -1, 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, -1, -1, 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, -1, -1, HW_Category_Helper, HW_Flag_InvalidNodeId) +HARDWARE_INTRINSIC(PackedSimd, ReplaceScalar, 16, 3, INS_i8x16_replace_lane, INS_i8x16_replace_lane, INS_i16x8_replace_lane, INS_i16x8_replace_lane, INS_i32x4_replace_lane, INS_i32x4_replace_lane, INS_i64x2_replace_lane, INS_i64x2_replace_lane, INS_f32x4_replace_lane, INS_f64x2_replace_lane, -1, -1, HW_Category_IMM, 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, -1, -1, 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, -1, -1, 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, -1, -1, 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, -1, -1, HW_Category_Helper, HW_Flag_InvalidNodeId) +HARDWARE_INTRINSIC(PackedSimd, ShiftLeft, 16, 2, INS_i8x16_shl, INS_i8x16_shl, INS_i16x8_shl, INS_i16x8_shl, INS_i32x4_shl, INS_i32x4_shl, INS_i64x2_shl, INS_i64x2_shl, INS_invalid, INS_invalid, -1, -1, HW_Category_IMM, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(PackedSimd, ShiftRightArithmetic, 16, 2, INS_i8x16_shr_s, INS_i8x16_shr_s, INS_i16x8_shr_s, INS_i16x8_shr_s, INS_i32x4_shr_s, INS_i32x4_shr_s, INS_i64x2_shr_s, INS_i64x2_shr_s, INS_invalid, INS_invalid, -1, -1, HW_Category_IMM, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(PackedSimd, ShiftRightLogical, 16, 2, INS_i8x16_shr_u, INS_i8x16_shr_u, INS_i16x8_shr_u, INS_i16x8_shr_u, INS_i32x4_shr_u, INS_i32x4_shr_u, INS_i64x2_shr_u, INS_i64x2_shr_u, INS_invalid, INS_invalid, -1, -1, HW_Category_IMM, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(PackedSimd, Shuffle, 16, 2, INS_i8x16_shuffle, INS_i8x16_shuffle, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, -1, -1, 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, -1, -1, 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, -1, -1, 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, -1, -1, HW_Category_Helper, HW_Flag_InvalidNodeId) +HARDWARE_INTRINSIC(PackedSimd, Splat, 16, 1, INS_i8x16_splat, INS_i8x16_splat, INS_i16x8_splat, INS_i16x8_splat, INS_i32x4_splat, INS_i32x4_splat, INS_i64x2_splat, INS_i64x2_splat, INS_f32x4_splat, INS_f64x2_splat, -1, -1, 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, -1, -1, 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, -1, -1, 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, -1, -1, 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, -1, -1, HW_Category_Helper, 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, -1, -1, HW_Category_Helper, HW_Flag_InvalidNodeId|HW_Flag_SpecialImport|HW_Flag_BaseTypeFromSecondArg) 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, -1, -1, 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, -1, -1, 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, -1, -1, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) From f3e49314e2192cbe8573064e78c6692ac6c9c4a1 Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Thu, 2 Jul 2026 22:37:34 -0700 Subject: [PATCH 2/6] Add base lightup support for most of the WASM intrinsics --- src/coreclr/jit/assertionprop.cpp | 2 + src/coreclr/jit/gentree.cpp | 210 ++++++++++++++------- src/coreclr/jit/hwintrinsic.cpp | 240 ++++++++++++++++++------ src/coreclr/jit/hwintrinsic.h | 1 - src/coreclr/jit/hwintrinsiclist.h | 2 +- src/coreclr/jit/hwintrinsiclistwasm.h | 10 +- src/coreclr/jit/hwintrinsicwasm.cpp | 36 ++-- src/coreclr/jit/lowerwasm.cpp | 256 +++++++++++++++++++++++++- src/coreclr/jit/valuenum.cpp | 2 + 9 files changed, 612 insertions(+), 147 deletions(-) diff --git a/src/coreclr/jit/assertionprop.cpp b/src/coreclr/jit/assertionprop.cpp index 29043e95b67844..25386d153f5ea0 100644 --- a/src/coreclr/jit/assertionprop.cpp +++ b/src/coreclr/jit/assertionprop.cpp @@ -344,6 +344,8 @@ static Range GetRange(Compiler* comp, GenTree* tree, BasicBlock* block, ASSERT_V case NI_AVX_MoveMask: case NI_AVX2_MoveMask: case NI_AVX512_MoveMask: +#elif defined(TARGET_WASM) + case NI_PackedSimd_Bitmask: #endif case NI_Vector_ExtractMostSignificantBits: { diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index 34c7e81e06e870..e28ee657a05081 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -23582,11 +23582,8 @@ GenTree* Compiler::gtNewSimdCvtNode( { return gtNewSimdCvtNativeNode(type, fixupVal, simdTargetBaseType, simdSourceBaseType, simdSize); } -#elif defined(TARGET_ARM64) +#elif defined(TARGET_ARM64) || defined(TARGET_WASM) return gtNewSimdCvtNativeNode(type, op1, simdTargetBaseType, simdSourceBaseType, simdSize); -#elif defined(TARGET_WASM) - NYI_WASM_SIMD("gtNewSimdCvtNode"); - return nullptr; #else #error Unsupported platform #endif @@ -23801,7 +23798,39 @@ GenTree* Compiler::gtNewSimdCvtNativeNode( unreached(); } #elif defined(TARGET_WASM) - NYI_WASM_SIMD("gtNewSimdCvtNativeNode"); + NamedIntrinsic intrinsic = NI_Illegal; + + switch (simdTargetBaseType) + { + case TYP_INT: + { + assert(simdSourceBaseType == TYP_FLOAT); + intrinsic = NI_PackedSimd_ConvertToInt32Saturate; + break; + } + + case TYP_UINT: + { + assert(simdSourceBaseType == TYP_FLOAT); + intrinsic = NI_PackedSimd_ConvertToUInt32Saturate; + break; + } + + case TYP_LONG: + case TYP_ULONG: + { + NYI_WASM_SIMD("gtNewSimdCvtNativeNode"); + return nullptr; + } + + default: + { + unreached(); + } + } + + assert(intrinsic != NI_Illegal); + return gtNewSimdHWIntrinsicNode(type, op1, intrinsic, simdSourceBaseType, simdSize); #else #error Unsupported platform #endif @@ -24386,6 +24415,11 @@ GenTree* Compiler::gtNewSimdCreateScalarNode(var_types type, GenTree* op1, var_t } #endif // TARGET_ARM64 +#if defined(TARGET_WASM) + // TODO-WASM-SIMD: Implement NI_Vector_CreateScalar + return nullptr; +#endif + return gtNewSimdHWIntrinsicNode(type, op1, hwIntrinsicID, simdBaseType, simdSize); } @@ -24509,6 +24543,11 @@ GenTree* Compiler::gtNewSimdCreateScalarUnsafeNode(var_types type, } #endif // TARGET_ARM64 +#if defined(TARGET_WASM) + // TODO-WASM-SIMD: Implement NI_Vector_CreateScalarUnsafe + return nullptr; +#endif + return gtNewSimdHWIntrinsicNode(type, op1, hwIntrinsicID, simdBaseType, simdSize); } @@ -26151,9 +26190,13 @@ GenTree* Compiler::gtNewSimdMinMaxNode(var_types type, op2 = gtNewSimdCreateScalarUnsafeNode(type, op2, simdBaseType, simdSize); } #elif defined(TARGET_WASM) - NYI_WASM_SIMD("gtNewSimdMinMaxNode"); + if (!isMagnitude && !isNumber) + { + intrinsic = isMax ? NI_PackedSimd_Max : NI_PackedSimd_Min; + retNode = gtNewSimdHWIntrinsicNode(type, op1, op2, intrinsic, simdBaseType, simdSize); + } #else - assert(!isScalar); +#error Unsupported platform #endif if (retNode == nullptr) @@ -26422,7 +26465,14 @@ GenTree* Compiler::gtNewSimdMinMaxNativeNode( } } #elif defined(TARGET_WASM) - NYI_WASM_SIMD("gtNewSimdMinMaxNode"); + if (varTypeIsFloating(simdBaseType)) + { + intrinsic = isMax ? NI_PackedSimd_PseudoMax : NI_PackedSimd_PseudoMin; + } + else + { + intrinsic = isMax ? NI_PackedSimd_Max : NI_PackedSimd_Min; + } #else #error Unsupported platform #endif // !TARGET_XARCH && !TARGET_ARM64 @@ -29377,37 +29427,7 @@ GenTree* Compiler::gtNewSimdUnOpNode( #if defined(TARGET_ARM64) if (op == GT_NEG) { - switch (simdBaseType) - { - case TYP_UBYTE: - { - simdBaseType = TYP_BYTE; - break; - } - - case TYP_USHORT: - { - simdBaseType = TYP_SHORT; - break; - } - - case TYP_UINT: - { - simdBaseType = TYP_INT; - break; - } - - case TYP_ULONG: - { - simdBaseType = TYP_LONG; - break; - } - - default: - { - break; - } - } + simdBaseType = varTypeToSigned(simdBaseType); } #endif // TARGET_ARM64 @@ -29466,12 +29486,10 @@ GenTree* Compiler::gtNewSimdWidenLowerNode(var_types type, GenTree* op1, var_typ NamedIntrinsic intrinsic = NI_Illegal; - GenTree* tmp1; - #if defined(TARGET_XARCH) if (simdSize == 64) { - tmp1 = gtNewSimdGetLowerNode(TYP_SIMD32, op1, simdBaseType, simdSize); + GenTree* tmp1 = gtNewSimdGetLowerNode(TYP_SIMD32, op1, simdBaseType, simdSize); switch (simdBaseType) { @@ -29530,7 +29548,7 @@ GenTree* Compiler::gtNewSimdWidenLowerNode(var_types type, GenTree* op1, var_typ { assert(!varTypeIsIntegral(simdBaseType) || compIsaSupportedDebugOnly(InstructionSet_AVX2)); - tmp1 = gtNewSimdGetLowerNode(TYP_SIMD16, op1, simdBaseType, simdSize); + GenTree* tmp1 = gtNewSimdGetLowerNode(TYP_SIMD16, op1, simdBaseType, simdSize); switch (simdBaseType) { @@ -29611,6 +29629,8 @@ GenTree* Compiler::gtNewSimdWidenLowerNode(var_types type, GenTree* op1, var_typ return gtNewSimdHWIntrinsicNode(type, op1, intrinsic, simdBaseType, simdSize); } #elif defined(TARGET_ARM64) + GenTree* tmp1; + if (simdSize == 16) { tmp1 = gtNewSimdGetLowerNode(TYP_SIMD8, op1, simdBaseType, simdSize); @@ -29645,9 +29665,22 @@ GenTree* Compiler::gtNewSimdWidenLowerNode(var_types type, GenTree* op1, var_typ return tmp1; #elif defined(TARGET_WASM) - tmp1 = nullptr; - NYI_WASM_SIMD("gtNewSimdWidenLowerNode"); - return nullptr; + if (varTypeIsFloating(simdBaseType)) + { + assert(simdBaseType == TYP_FLOAT); + intrinsic = NI_PackedSimd_ConvertToDoubleLower; + } + else if (varTypeIsSigned(simdBaseType)) + { + intrinsic = NI_PackedSimd_SignExtendWideningLower; + } + else + { + intrinsic = NI_PackedSimd_ZeroExtendWideningLower; + } + + assert(intrinsic != NI_Illegal); + return gtNewSimdHWIntrinsicNode(TYP_SIMD16, op1, intrinsic, simdBaseType, 8); #else #error Unsupported platform #endif // !TARGET_XARCH && !TARGET_ARM64 @@ -29665,12 +29698,10 @@ GenTree* Compiler::gtNewSimdWidenUpperNode(var_types type, GenTree* op1, var_typ NamedIntrinsic intrinsic = NI_Illegal; - GenTree* tmp1; - #if defined(TARGET_XARCH) if (simdSize == 64) { - tmp1 = gtNewSimdGetUpperNode(TYP_SIMD32, op1, simdBaseType, simdSize); + GenTree* tmp1 = gtNewSimdGetUpperNode(TYP_SIMD32, op1, simdBaseType, simdSize); switch (simdBaseType) { @@ -29729,7 +29760,7 @@ GenTree* Compiler::gtNewSimdWidenUpperNode(var_types type, GenTree* op1, var_typ { assert(!varTypeIsIntegral(simdBaseType) || compIsaSupportedDebugOnly(InstructionSet_AVX2)); - tmp1 = gtNewSimdGetUpperNode(TYP_SIMD16, op1, simdBaseType, simdSize); + GenTree* tmp1 = gtNewSimdGetUpperNode(TYP_SIMD16, op1, simdBaseType, simdSize); switch (simdBaseType) { @@ -29775,13 +29806,13 @@ GenTree* Compiler::gtNewSimdWidenUpperNode(var_types type, GenTree* op1, var_typ GenTree* op1Dup = fgMakeMultiUse(&op1); - tmp1 = gtNewSimdHWIntrinsicNode(type, op1, op1Dup, NI_X86Base_MoveHighToLow, simdBaseType, simdSize); + GenTree* tmp1 = gtNewSimdHWIntrinsicNode(type, op1, op1Dup, NI_X86Base_MoveHighToLow, simdBaseType, simdSize); return gtNewSimdHWIntrinsicNode(type, tmp1, NI_X86Base_ConvertToVector128Double, simdBaseType, simdSize); } else { - tmp1 = gtNewSimdHWIntrinsicNode(type, op1, gtNewIconNode(8), NI_X86Base_ShiftRightLogical128BitLane, - simdBaseType, simdSize); + GenTree* tmp1 = gtNewSimdHWIntrinsicNode(type, op1, gtNewIconNode(8), NI_X86Base_ShiftRightLogical128BitLane, + simdBaseType, simdSize); switch (simdBaseType) { @@ -29856,13 +29887,26 @@ GenTree* Compiler::gtNewSimdWidenUpperNode(var_types type, GenTree* op1, var_typ assert(intrinsic != NI_Illegal); - tmp1 = gtNewSimdHWIntrinsicNode(TYP_SIMD16, op1, intrinsic, simdBaseType, simdSize); + GenTree* tmp1 = gtNewSimdHWIntrinsicNode(TYP_SIMD16, op1, intrinsic, simdBaseType, simdSize); return gtNewSimdGetUpperNode(TYP_SIMD8, tmp1, simdBaseType, 16); } #elif defined(TARGET_WASM) - tmp1 = nullptr; - NYI_WASM_SIMD("gtNewSimdWidenUpperNode"); - return nullptr; + if (varTypeIsFloating(simdBaseType)) + { + NYI_WASM_SIMD("gtNewSimdWidenUpperNode"); + return nullptr; + } + else if (varTypeIsSigned(simdBaseType)) + { + intrinsic = NI_PackedSimd_SignExtendWideningUpper; + } + else + { + intrinsic = NI_PackedSimd_ZeroExtendWideningUpper; + } + + assert(intrinsic != NI_Illegal); + return gtNewSimdHWIntrinsicNode(TYP_SIMD16, op1, intrinsic, simdBaseType, 8); #else #error Unsupported platform #endif // !TARGET_XARCH && !TARGET_ARM64 @@ -31614,7 +31658,11 @@ NamedIntrinsic GenTreeHWIntrinsic::GetHWIntrinsicIdForUnOp( { id = NI_AdvSimd_Negate; } -#endif // TARGET_ARM64 +#elif defined(TARGET_WASM) + id = NI_PackedSimd_Negate; +#elif !defined(TARGET_XARCH) +#error Unsupported platform +#endif break; } @@ -31624,7 +31672,11 @@ NamedIntrinsic GenTreeHWIntrinsic::GetHWIntrinsicIdForUnOp( #if defined(TARGET_ARM64) id = NI_AdvSimd_Not; -#endif // TARGET_ARM64 +#elif defined(TARGET_WASM) + id = NI_PackedSimd_Not; +#elif !defined(TARGET_XARCH) +#error Unsupported platform +#endif break; } @@ -32377,7 +32429,11 @@ NamedIntrinsic GenTreeHWIntrinsic::GetHWIntrinsicIdForCmpOp(Compiler* comp, { id = NI_AdvSimd_CompareEqual; } -#endif // !TARGET_XARCH && !TARGET_ARM64 +#elif defined(TARGET_WASM) + id = NI_PackedSimd_CompareEqual; +#else +#error Unsupported platform +#endif break; } @@ -32417,7 +32473,11 @@ NamedIntrinsic GenTreeHWIntrinsic::GetHWIntrinsicIdForCmpOp(Compiler* comp, { id = NI_AdvSimd_CompareGreaterThanOrEqual; } -#endif // !TARGET_XARCH && !TARGET_ARM64 +#elif defined(TARGET_WASM) + id = NI_PackedSimd_CompareGreaterThanOrEqual; +#else +#error Unsupported platform +#endif break; } @@ -32471,7 +32531,11 @@ NamedIntrinsic GenTreeHWIntrinsic::GetHWIntrinsicIdForCmpOp(Compiler* comp, { id = NI_AdvSimd_CompareGreaterThan; } -#endif // !TARGET_XARCH && !TARGET_ARM64 +#elif defined(TARGET_WASM) + id = NI_PackedSimd_CompareGreaterThan; +#else +#error Unsupported platform +#endif break; } @@ -32511,7 +32575,11 @@ NamedIntrinsic GenTreeHWIntrinsic::GetHWIntrinsicIdForCmpOp(Compiler* comp, { id = NI_AdvSimd_CompareLessThanOrEqual; } -#endif // !TARGET_XARCH && !TARGET_ARM64 +#elif defined(TARGET_WASM) + id = NI_PackedSimd_CompareLessThanOrEqual; +#else +#error Unsupported platform +#endif break; } @@ -32567,7 +32635,11 @@ NamedIntrinsic GenTreeHWIntrinsic::GetHWIntrinsicIdForCmpOp(Compiler* comp, { id = NI_AdvSimd_CompareLessThan; } -#endif // !TARGET_XARCH && !TARGET_ARM64 +#elif defined(TARGET_WASM) + id = NI_PackedSimd_CompareLessThan; +#else +#error Unsupported platform +#endif break; } @@ -32593,7 +32665,13 @@ NamedIntrinsic GenTreeHWIntrinsic::GetHWIntrinsicIdForCmpOp(Compiler* comp, { id = isScalar ? NI_X86Base_CompareScalarNotEqual : NI_X86Base_CompareNotEqual; } -#endif // TARGET_XARCH +#elif defined(TARGET_ARM64) + id = NI_Illegal; +#elif defined(TARGET_WASM) + id = NI_PackedSimd_CompareNotEqual; +#else +#error Unsupported platform +#endif break; } @@ -34292,6 +34370,8 @@ GenTree* Compiler::gtFoldExprHWIntrinsic(GenTreeHWIntrinsic* tree) case NI_X86Base_MoveMask: case NI_AVX_MoveMask: case NI_AVX2_MoveMask: +#elif defined(TARGET_WASM) + case NI_PackedSimd_Bitmask: #endif { simdmask_t simdMaskVal; diff --git a/src/coreclr/jit/hwintrinsic.cpp b/src/coreclr/jit/hwintrinsic.cpp index c4b66fb3761bec..f43e496fbc7edc 100644 --- a/src/coreclr/jit/hwintrinsic.cpp +++ b/src/coreclr/jit/hwintrinsic.cpp @@ -2911,12 +2911,6 @@ GenTree* Compiler::impXplatIntrinsic(NamedIntrinsic intrinsic, return nullptr; } } -#elif defined(TARGET_WASM) - if (intrinsic != NI_Vector_Create) - { - // TODO-WASM-SIMD: Finish adding xplat intrinsic lightup - return nullptr; - } #endif if (simdSize != 0) @@ -2963,9 +2957,19 @@ GenTree* Compiler::impXplatIntrinsic(NamedIntrinsic intrinsic, } else { -#if defined(TARGET_XARCH) +#if defined(TARGET_ARM64) + intrinsic = NI_AdvSimd_AddSaturate; + + if ((simdSize == 8) && varTypeIsLong(simdBaseType)) + { + intrinsic = NI_AdvSimd_AddSaturateScalar; + } + + retNode = gtNewSimdHWIntrinsicNode(retType, op1, op2, intrinsic, simdBaseType, simdSize); +#elif defined(TARGET_XARCH) || defined(TARGET_WASM) if (varTypeIsSmall(simdBaseType)) { +#if defined(TARGET_XARCH) if (simdSize == 64) { intrinsic = NI_AVX512_AddSaturate; @@ -2979,7 +2983,11 @@ GenTree* Compiler::impXplatIntrinsic(NamedIntrinsic intrinsic, assert(simdSize == 16); intrinsic = NI_X86Base_AddSaturate; } - +#elif defined(TARGET_WASM) + intrinsic = NI_PackedSimd_AddSaturate; +#else +#error Unsupported platform +#endif retNode = gtNewSimdHWIntrinsicNode(retType, op1, op2, intrinsic, simdBaseType, simdSize); } else if (varTypeIsUnsigned(simdBaseType)) @@ -3006,13 +3014,6 @@ GenTree* Compiler::impXplatIntrinsic(NamedIntrinsic intrinsic, switch (simdBaseType) { - case TYP_SHORT: - { - minCns->EvaluateBroadcastInPlace(INT16_MIN); - maxCns->EvaluateBroadcastInPlace(INT16_MAX); - break; - } - case TYP_INT: { minCns->EvaluateBroadcastInPlace(INT32_MIN); @@ -3046,6 +3047,7 @@ GenTree* Compiler::impXplatIntrinsic(NamedIntrinsic intrinsic, // The mask we need is ((a ^ b) & ~(b ^ c)) < 0 +#if defined(TARGET_XARCH) if (compOpportunisticallyDependsOn(InstructionSet_AVX512)) { // tmpDup1 = a: 0xF0 @@ -3058,6 +3060,7 @@ GenTree* Compiler::impXplatIntrinsic(NamedIntrinsic intrinsic, simdBaseType, simdSize); } else +#endif { GenTree* op1Dup2 = gtCloneExpr(op1Dup1); @@ -3070,20 +3073,6 @@ GenTree* Compiler::impXplatIntrinsic(NamedIntrinsic intrinsic, msk = gtNewSimdIsNegativeNode(retType, msk, simdBaseType, simdSize); retNode = gtNewSimdCndSelNode(retType, msk, ovf, tmpDup2, simdBaseType, simdSize); } -#elif defined(TARGET_ARM64) - intrinsic = NI_AdvSimd_AddSaturate; - - if ((simdSize == 8) && varTypeIsLong(simdBaseType)) - { - intrinsic = NI_AdvSimd_AddSaturateScalar; - } - - retNode = gtNewSimdHWIntrinsicNode(retType, op1, op2, intrinsic, simdBaseType, simdSize); -#elif defined(TARGET_WASM) - // TODO-WASM-SIMD: Implement NI_Vector_AddSaturate - return nullptr; -#else - unreached(); #endif } break; @@ -3275,6 +3264,11 @@ GenTree* Compiler::impXplatIntrinsic(NamedIntrinsic intrinsic, { assert(simdBaseType == TYP_FLOAT); +#if defined(TARGET_WASM) + // TODO-WASM-SIMD: Implement NI_Vector_AsVector128(Vector2) - Need WithElement + return nullptr; +#endif + op1 = impSIMDPopStack(); if (op1->IsCnsVec()) @@ -3309,6 +3303,11 @@ GenTree* Compiler::impXplatIntrinsic(NamedIntrinsic intrinsic, { assert(simdBaseType == TYP_FLOAT); +#if defined(TARGET_WASM) + // TODO-WASM-SIMD: Implement NI_Vector_AsVector128(Vector3) - Need WithElement + return nullptr; +#endif + op1 = impSIMDPopStack(); if (op1->IsCnsVec()) @@ -3369,6 +3368,11 @@ GenTree* Compiler::impXplatIntrinsic(NamedIntrinsic intrinsic, assert(simdBaseType == TYP_FLOAT); assert((simdSize == 8) || (simdSize == 12)); +#if defined(TARGET_WASM) + // TODO-WASM-SIMD: Implement NI_Vector_AsVector128Unsafe + return nullptr; +#endif + op1 = impSIMDPopStack(); retNode = gtNewSimdHWIntrinsicNode(retType, op1, NI_Vector_AsVector128Unsafe, simdBaseType, simdSize); break; @@ -3380,6 +3384,11 @@ GenTree* Compiler::impXplatIntrinsic(NamedIntrinsic intrinsic, assert((simdSize == 16) && (simdBaseType == TYP_FLOAT)); assert((retType == TYP_SIMD8) || (retType == TYP_SIMD12)); +#if defined(TARGET_WASM) + // TODO-WASM-SIMD: Implement NI_Vector_AsVector2/3 + return nullptr; +#endif + assert(sig->numArgs == 1); op1 = impSIMDPopStack(); @@ -3533,6 +3542,11 @@ GenTree* Compiler::impXplatIntrinsic(NamedIntrinsic intrinsic, } #endif +#if defined(TARGET_WASM) + // TODO-WASM-SIMD: Implement NI_Vector_ConvertToInt64 + return nullptr; +#endif + op1 = impSIMDPopStack(); retNode = gtNewSimdCvtNode(retType, op1, TYP_LONG, simdBaseType, simdSize); break; @@ -3555,6 +3569,11 @@ GenTree* Compiler::impXplatIntrinsic(NamedIntrinsic intrinsic, } #endif +#if defined(TARGET_WASM) + // TODO-WASM-SIMD: Implement NI_Vector_ConvertToInt64Native + return nullptr; +#endif + op1 = impSIMDPopStack(); retNode = gtNewSimdCvtNativeNode(retType, op1, TYP_LONG, simdBaseType, simdSize); break; @@ -3605,8 +3624,7 @@ GenTree* Compiler::impXplatIntrinsic(NamedIntrinsic intrinsic, #elif defined(TARGET_ARM64) intrinsic = NI_AdvSimd_ConvertToSingle; #elif defined(TARGET_WASM) - // TODO-WASM-SIMD: Implement NI_Vector_ConvertToSingle - return nullptr; + intrinsic = NI_PackedSimd_ConvertToSingle; #else unreached(); #endif @@ -3667,6 +3685,11 @@ GenTree* Compiler::impXplatIntrinsic(NamedIntrinsic intrinsic, } #endif +#if defined(TARGET_WASM) + // TODO-WASM-SIMD: Implement NI_Vector_ConvertToUInt64 + return nullptr; +#endif + op1 = impSIMDPopStack(); retNode = gtNewSimdCvtNode(retType, op1, TYP_ULONG, simdBaseType, simdSize); break; @@ -3689,6 +3712,11 @@ GenTree* Compiler::impXplatIntrinsic(NamedIntrinsic intrinsic, } #endif +#if defined(TARGET_WASM) + // TODO-WASM-SIMD: Implement NI_Vector_ConvertToUInt64Native + return nullptr; +#endif + op1 = impSIMDPopStack(); retNode = gtNewSimdCvtNativeNode(retType, op1, TYP_ULONG, simdBaseType, simdSize); break; @@ -3707,6 +3735,14 @@ GenTree* Compiler::impXplatIntrinsic(NamedIntrinsic intrinsic, impSpillSideEffect(true, stackState.esStackDepth - 2 DEBUGARG("Spilling op1 side effects for vector CreateAlternatingSequence")); +#if defined(TARGET_WASM) + if (!impStackTop(0).val->OperIsConst() || !impStackTop(1).val->OperIsConst()) + { + // TODO-WASM-SIMD: Implement NI_Vector_CreateAlternatingSequence - Need Shuffle + return nullptr; + } +#endif + op2 = impPopStack().val; op1 = impPopStack().val; @@ -3759,7 +3795,6 @@ GenTree* Compiler::impXplatIntrinsic(NamedIntrinsic intrinsic, case NI_Vector_CreateScalar: { assert(sig->numArgs == 1); - op1 = impPopStack().val; retNode = gtNewSimdCreateScalarNode(retType, op1, simdBaseType, simdSize); break; @@ -3800,6 +3835,11 @@ GenTree* Compiler::impXplatIntrinsic(NamedIntrinsic intrinsic, { assert(sig->numArgs == 2); +#if defined(TARGET_WASM) + // TODO-WASM-SIMD: Implement NI_Vector_Dot - Need Shuffle + return nullptr; +#endif + #if defined(TARGET_ARM64) if (varTypeIsLong(simdBaseType)) { @@ -3907,6 +3947,21 @@ GenTree* Compiler::impXplatIntrinsic(NamedIntrinsic intrinsic, unreached(); } } +#elif defined(TARGET_WASM) + if (simdBaseType == TYP_FLOAT) + { + simdBaseType = TYP_INT; + } + else if (simdBaseType == TYP_DOUBLE) + { + simdBaseType = TYP_LONG; + } + else + { + assert(varTypeIsIntegral(simdBaseType)); + } + + intrinsic = NI_PackedSimd_Bitmask; #endif retNode = gtNewSimdHWIntrinsicNode(retType, op1, intrinsic, simdBaseType, simdSize); @@ -3944,6 +3999,9 @@ GenTree* Compiler::impXplatIntrinsic(NamedIntrinsic intrinsic, impSpillSideEffect(true, stackState.esStackDepth - 2 DEBUGARG("Spilling op2 side effects for FusedMultiplyAdd")); +#elif defined(TARGET_WASM) + // TODO-WASM-SIMD: Implement NI_Vector_FusedMultiplyAdd + return nullptr; #endif op3 = impSIMDPopStack(); @@ -3958,6 +4016,11 @@ GenTree* Compiler::impXplatIntrinsic(NamedIntrinsic intrinsic, { assert(sig->numArgs == 2); +#if defined(TARGET_WASM) + // TODO-WASM-SIMD: Implement NI_Vector_GetElement + return nullptr; +#endif + op2 = impPopStack().val; op1 = impSIMDPopStack(); @@ -4567,6 +4630,8 @@ GenTree* Compiler::impXplatIntrinsic(NamedIntrinsic intrinsic, { isFmaSupported = compExactlyDependsOn(InstructionSet_AVX2); } +#elif defined(TARGET_WASM) + isFmaSupported = false; #endif if (isFmaSupported) @@ -4585,6 +4650,11 @@ GenTree* Compiler::impXplatIntrinsic(NamedIntrinsic intrinsic, { assert(sig->numArgs == 2); +#if defined(TARGET_WASM) + // TODO-WASM-SIMD: Implement NI_Vector_Narrow + return nullptr; +#endif + op2 = impSIMDPopStack(); op1 = impSIMDPopStack(); @@ -4845,6 +4915,11 @@ GenTree* Compiler::impXplatIntrinsic(NamedIntrinsic intrinsic, { assert(sig->numArgs == 1); +#if defined(TARGET_WASM) + // TODO-WASM-SIMD: Implement NI_Vector_Reverse - Need Shuffle + return nullptr; +#endif + #if defined(TARGET_XARCH) if ((simdSize == 64) && varTypeIsByte(simdBaseType)) { @@ -4936,6 +5011,11 @@ GenTree* Compiler::impXplatIntrinsic(NamedIntrinsic intrinsic, { assert((sig->numArgs == 2) || (sig->numArgs == 3)); +#if defined(TARGET_WASM) + // TODO-WASM-SIMD: Implement NI_Vector_Shuffle + return nullptr; +#endif + bool isShuffleNative = (intrinsic != NI_Vector_Shuffle); bool isNonDeterministic = isShuffleNative; @@ -5127,9 +5207,19 @@ GenTree* Compiler::impXplatIntrinsic(NamedIntrinsic intrinsic, } else { -#if defined(TARGET_XARCH) +#if defined(TARGET_ARM64) + intrinsic = NI_AdvSimd_SubtractSaturate; + + if ((simdSize == 8) && varTypeIsLong(simdBaseType)) + { + intrinsic = NI_AdvSimd_SubtractSaturateScalar; + } + + retNode = gtNewSimdHWIntrinsicNode(retType, op1, op2, intrinsic, simdBaseType, simdSize); +#elif defined(TARGET_XARCH) || defined(TARGET_WASM) if (varTypeIsSmall(simdBaseType)) { +#if defined(TARGET_XARCH) if (simdSize == 64) { intrinsic = NI_AVX512_SubtractSaturate; @@ -5143,6 +5233,11 @@ GenTree* Compiler::impXplatIntrinsic(NamedIntrinsic intrinsic, assert(simdSize == 16); intrinsic = NI_X86Base_SubtractSaturate; } +#elif defined(TARGET_WASM) + intrinsic = NI_PackedSimd_SubtractSaturate; +#else +#error Unsupported platform +#endif retNode = gtNewSimdHWIntrinsicNode(retType, op1, op2, intrinsic, simdBaseType, simdSize); } @@ -5170,13 +5265,6 @@ GenTree* Compiler::impXplatIntrinsic(NamedIntrinsic intrinsic, switch (simdBaseType) { - case TYP_SHORT: - { - minCns->EvaluateBroadcastInPlace(INT16_MIN); - maxCns->EvaluateBroadcastInPlace(INT16_MAX); - break; - } - case TYP_INT: { minCns->EvaluateBroadcastInPlace(INT32_MIN); @@ -5210,6 +5298,7 @@ GenTree* Compiler::impXplatIntrinsic(NamedIntrinsic intrinsic, // The mask we need is ((a ^ b) & (b ^ c)) < 0 +#if defined(TARGET_XARCH) if (compOpportunisticallyDependsOn(InstructionSet_AVX512)) { // tmpDup1 = a: 0xF0 @@ -5222,6 +5311,7 @@ GenTree* Compiler::impXplatIntrinsic(NamedIntrinsic intrinsic, simdBaseType, simdSize); } else +#endif { GenTree* op1Dup2 = gtCloneExpr(op1Dup1); @@ -5234,20 +5324,6 @@ GenTree* Compiler::impXplatIntrinsic(NamedIntrinsic intrinsic, msk = gtNewSimdIsNegativeNode(retType, msk, simdBaseType, simdSize); retNode = gtNewSimdCndSelNode(retType, msk, ovf, tmpDup2, simdBaseType, simdSize); } -#elif defined(TARGET_ARM64) - intrinsic = NI_AdvSimd_SubtractSaturate; - - if ((simdSize == 8) && varTypeIsLong(simdBaseType)) - { - intrinsic = NI_AdvSimd_SubtractSaturateScalar; - } - - retNode = gtNewSimdHWIntrinsicNode(retType, op1, op2, intrinsic, simdBaseType, simdSize); -#elif defined(TARGET_WASM) - // TODO-WASM-SIMD: Implement NI_Vector_SubtractSaturate - return nullptr; -#else - unreached(); #endif } break; @@ -5256,6 +5332,12 @@ GenTree* Compiler::impXplatIntrinsic(NamedIntrinsic intrinsic, case NI_Vector_Sum: { assert(sig->numArgs == 1); + +#if defined(TARGET_WASM) + // TODO-WASM-SIMD: Implement NI_Vector_Sum - Need Shuffle + return nullptr; +#endif + op1 = impSIMDPopStack(); retNode = gtNewSimdSumNode(retType, op1, simdBaseType, simdSize); break; @@ -5264,6 +5346,12 @@ GenTree* Compiler::impXplatIntrinsic(NamedIntrinsic intrinsic, case NI_Vector_ToScalar: { assert(sig->numArgs == 1); + +#if defined(TARGET_WASM) + // TODO-WASM-SIMD: Implement NI_Vector_ToScalar - Need GetElement + return nullptr; +#endif + op1 = impSIMDPopStack(); retNode = gtNewSimdToScalarNode(retType, op1, simdBaseType, simdSize); break; @@ -5289,6 +5377,11 @@ GenTree* Compiler::impXplatIntrinsic(NamedIntrinsic intrinsic, { assert(sig->numArgs == 2); +#if defined(TARGET_WASM) + // TODO-WASM-SIMD: Implement NI_Vector_Unzip - Need Shuffle + return nullptr; +#endif + #if defined(TARGET_XARCH) if (simdSize == 16) { @@ -5320,6 +5413,15 @@ GenTree* Compiler::impXplatIntrinsic(NamedIntrinsic intrinsic, case NI_Vector_WidenUpper: { assert(sig->numArgs == 1); + +#if defined(TARGET_WASM) + if (simdBaseType == TYP_FLOAT) + { + // TODO-WASM-SIMD - Implement NI_Vector_WidenUpper(float) - Need Shuffle + return nullptr; + } +#endif + op1 = impSIMDPopStack(); retNode = gtNewSimdWidenUpperNode(retType, op1, simdBaseType, simdSize); break; @@ -5329,6 +5431,11 @@ GenTree* Compiler::impXplatIntrinsic(NamedIntrinsic intrinsic, { assert(sig->numArgs == 3); +#if defined(TARGET_WASM) + // TODO-WASM-SIMD: Implement NI_Vector_WithElement + return nullptr; +#endif + #if defined(TARGET_X86) if (varTypeIsLong(simdBaseType)) { @@ -5421,6 +5528,11 @@ GenTree* Compiler::impXplatIntrinsic(NamedIntrinsic intrinsic, { assert(sig->numArgs == 2); +#if defined(TARGET_WASM) + // TODO-WASM-SIMD: Implement NI_Vector_Zip - Need Shuffle + return nullptr; +#endif + op2 = impSIMDPopStack(); op1 = impSIMDPopStack(); @@ -5722,6 +5834,11 @@ GenTree* Compiler::impXplatIntrinsic(NamedIntrinsic intrinsic, { assert(sig->numArgs == 2); +#if defined(TARGET_WASM) + // TODO-WASM-SIMD: Implement NI_Vector_op_LeftShift + return nullptr; +#endif + #if defined(TARGET_XARCH) if ((simdSize == 32) && !compOpportunisticallyDependsOn(InstructionSet_AVX2)) { @@ -5767,6 +5884,11 @@ GenTree* Compiler::impXplatIntrinsic(NamedIntrinsic intrinsic, { assert(sig->numArgs == 2); +#if defined(TARGET_WASM) + // TODO-WASM-SIMD: Implement NI_Vector_op_RightShift + return nullptr; +#endif + #if defined(TARGET_XARCH) if ((simdSize == 32) && !compOpportunisticallyDependsOn(InstructionSet_AVX2)) { @@ -5813,6 +5935,11 @@ GenTree* Compiler::impXplatIntrinsic(NamedIntrinsic intrinsic, { assert(sig->numArgs == 2); +#if defined(TARGET_WASM) + // TODO-WASM-SIMD: Implement NI_Vector_op_UnsignedRightShift + return nullptr; +#endif + #if defined(TARGET_XARCH) if ((simdSize == 32) && !compOpportunisticallyDependsOn(InstructionSet_AVX2)) { @@ -5862,6 +5989,11 @@ GenTree* Compiler::impXplatIntrinsic(NamedIntrinsic intrinsic, assert(sig->numArgs == 2); assert(retNode == nullptr); +#if defined(TARGET_WASM) + // TODO-WASM-SIMD: Implement NI_Vector_Concat - Need Shuffle + return nullptr; +#endif + op2 = impSIMDPopStack(); op1 = impSIMDPopStack(); diff --git a/src/coreclr/jit/hwintrinsic.h b/src/coreclr/jit/hwintrinsic.h index cb89bdc1dd10d6..7effb01b75f84b 100644 --- a/src/coreclr/jit/hwintrinsic.h +++ b/src/coreclr/jit/hwintrinsic.h @@ -264,7 +264,6 @@ enum HWIntrinsicFlag : uint64_t // The intrinsic supports some sort of containment analysis HW_Flag_SupportsContainment = 0x400, HW_Flag_ReturnsPerElementMask = 0x800, - // TODO-WASM: Add WASM-specific flags as needed. #else #error Unsupported platform #endif diff --git a/src/coreclr/jit/hwintrinsiclist.h b/src/coreclr/jit/hwintrinsiclist.h index a4ea290b3ef96d..487ed00d7d92c9 100644 --- a/src/coreclr/jit/hwintrinsiclist.h +++ b/src/coreclr/jit/hwintrinsiclist.h @@ -107,7 +107,7 @@ HARDWARE_INTRINSIC(Vector, CreateScalar, HARDWARE_INTRINSIC(Vector, CreateScalarUnsafe, -1, 1, INS_ins, INS_ins, INS_ins, INS_ins, INS_ins, INS_ins, INS_ins, INS_ins, INS_fmov, INS_fmov, -1, -1, HW_Category_SIMD, HW_Flag_SpecialImport|HW_Flag_SpecialCodeGen|HW_Flag_SupportsContainment) #else HARDWARE_INTRINSIC(Vector, CreateScalar, -1, 1, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, -1, -1, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) -HARDWARE_INTRINSIC(Vector, CreateScalarUnsafe, -1, 1, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, -1, -1, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) +HARDWARE_INTRINSIC(Vector, CreateScalarUnsafe, -1, 1, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, -1, -1, HW_Category_SIMD, HW_Flag_SpecialImport|HW_Flag_SpecialCodeGen) #endif HARDWARE_INTRINSIC(Vector, CreateSequence, -1, 2, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, -1, -1, HW_Category_Helper, HW_Flag_InvalidNodeId|HW_Flag_AvxOnlyCompatible) diff --git a/src/coreclr/jit/hwintrinsiclistwasm.h b/src/coreclr/jit/hwintrinsiclistwasm.h index cd34f686b1398d..42b3c1211196d0 100644 --- a/src/coreclr/jit/hwintrinsiclistwasm.h +++ b/src/coreclr/jit/hwintrinsiclistwasm.h @@ -42,7 +42,7 @@ HARDWARE_INTRINSIC(PackedSimd, ConvertToSingle, 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, -1, -1, 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, -1, -1, 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, -1, -1, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(PackedSimd, ExtractScalar, 16, 2, INS_i8x16_extract_lane_s, INS_i8x16_extract_lane_u, INS_i16x8_extract_lane_s, INS_i16x8_extract_lane_u, INS_i32x4_extract_lane, INS_i32x4_extract_lane, INS_i64x2_extract_lane, INS_i64x2_extract_lane, INS_f32x4_extract_lane, INS_f64x2_extract_lane, -1, -1, HW_Category_IMM, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(PackedSimd, ExtractScalar, 16, 2, INS_i8x16_extract_lane_s, INS_i8x16_extract_lane_u, INS_i16x8_extract_lane_s, INS_i16x8_extract_lane_u, INS_i32x4_extract_lane, INS_i32x4_extract_lane, INS_i64x2_extract_lane, INS_i64x2_extract_lane, INS_f32x4_extract_lane, INS_f64x2_extract_lane, -1, -1, HW_Category_IMM, HW_Flag_BaseTypeFromFirstArg|HW_Flag_SpecialImport) 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, -1, -1, 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, -1, -1, HW_Category_Helper, HW_Flag_InvalidNodeId|HW_Flag_SpecialImport) 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, -1, -1, HW_Category_Helper, HW_Flag_InvalidNodeId|HW_Flag_SpecialImport) @@ -61,11 +61,11 @@ HARDWARE_INTRINSIC(PackedSimd, Or, 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, -1, -1, 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, -1, -1, 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, -1, -1, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(PackedSimd, ReplaceScalar, 16, 3, INS_i8x16_replace_lane, INS_i8x16_replace_lane, INS_i16x8_replace_lane, INS_i16x8_replace_lane, INS_i32x4_replace_lane, INS_i32x4_replace_lane, INS_i64x2_replace_lane, INS_i64x2_replace_lane, INS_f32x4_replace_lane, INS_f64x2_replace_lane, -1, -1, HW_Category_IMM, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(PackedSimd, ReplaceScalar, 16, 3, INS_i8x16_replace_lane, INS_i8x16_replace_lane, INS_i16x8_replace_lane, INS_i16x8_replace_lane, INS_i32x4_replace_lane, INS_i32x4_replace_lane, INS_i64x2_replace_lane, INS_i64x2_replace_lane, INS_f32x4_replace_lane, INS_f64x2_replace_lane, -1, -1, HW_Category_IMM, HW_Flag_BaseTypeFromFirstArg|HW_Flag_SpecialImport) 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, -1, -1, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(PackedSimd, ShiftLeft, 16, 2, INS_i8x16_shl, INS_i8x16_shl, INS_i16x8_shl, INS_i16x8_shl, INS_i32x4_shl, INS_i32x4_shl, INS_i64x2_shl, INS_i64x2_shl, INS_invalid, INS_invalid, -1, -1, HW_Category_IMM, HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(PackedSimd, ShiftRightArithmetic, 16, 2, INS_i8x16_shr_s, INS_i8x16_shr_s, INS_i16x8_shr_s, INS_i16x8_shr_s, INS_i32x4_shr_s, INS_i32x4_shr_s, INS_i64x2_shr_s, INS_i64x2_shr_s, INS_invalid, INS_invalid, -1, -1, HW_Category_IMM, HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(PackedSimd, ShiftRightLogical, 16, 2, INS_i8x16_shr_u, INS_i8x16_shr_u, INS_i16x8_shr_u, INS_i16x8_shr_u, INS_i32x4_shr_u, INS_i32x4_shr_u, INS_i64x2_shr_u, INS_i64x2_shr_u, INS_invalid, INS_invalid, -1, -1, HW_Category_IMM, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(PackedSimd, ShiftLeft, 16, 2, INS_i8x16_shl, INS_i8x16_shl, INS_i16x8_shl, INS_i16x8_shl, INS_i32x4_shl, INS_i32x4_shl, INS_i64x2_shl, INS_i64x2_shl, INS_invalid, INS_invalid, -1, -1, HW_Category_IMM, HW_Flag_BaseTypeFromFirstArg|HW_Flag_SpecialImport) +HARDWARE_INTRINSIC(PackedSimd, ShiftRightArithmetic, 16, 2, INS_i8x16_shr_s, INS_i8x16_shr_s, INS_i16x8_shr_s, INS_i16x8_shr_s, INS_i32x4_shr_s, INS_i32x4_shr_s, INS_i64x2_shr_s, INS_i64x2_shr_s, INS_invalid, INS_invalid, -1, -1, HW_Category_IMM, HW_Flag_BaseTypeFromFirstArg|HW_Flag_SpecialImport) +HARDWARE_INTRINSIC(PackedSimd, ShiftRightLogical, 16, 2, INS_i8x16_shr_u, INS_i8x16_shr_u, INS_i16x8_shr_u, INS_i16x8_shr_u, INS_i32x4_shr_u, INS_i32x4_shr_u, INS_i64x2_shr_u, INS_i64x2_shr_u, INS_invalid, INS_invalid, -1, -1, HW_Category_IMM, HW_Flag_BaseTypeFromFirstArg|HW_Flag_SpecialImport) HARDWARE_INTRINSIC(PackedSimd, Shuffle, 16, 2, INS_i8x16_shuffle, INS_i8x16_shuffle, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, -1, -1, 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, -1, -1, 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, -1, -1, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) diff --git a/src/coreclr/jit/hwintrinsicwasm.cpp b/src/coreclr/jit/hwintrinsicwasm.cpp index 25ab03cdb2f9b0..1915586de284ed 100644 --- a/src/coreclr/jit/hwintrinsicwasm.cpp +++ b/src/coreclr/jit/hwintrinsicwasm.cpp @@ -94,29 +94,28 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, { // 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: - break; - case NI_PackedSimd_ExtractScalar: + { break; + } case NI_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); } @@ -124,12 +123,22 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, case NI_PackedSimd_LoadScalarAndSplatVector128: case NI_PackedSimd_LoadScalarAndInsert: case NI_PackedSimd_LoadWideningVector128: + { + break; + } + + case NI_PackedSimd_ShiftLeft: + case NI_PackedSimd_ShiftRightArithmetic: + case NI_PackedSimd_ShiftRightLogical: + { break; + } case NI_PackedSimd_Store: { assert(sig->numArgs == 2); assert(simdSize == 16); + op2 = impPopStack().val; op1 = impPopStack().val; @@ -138,24 +147,17 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, // 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: + { break; - - case NI_PackedSimd_ShiftLeft: - case NI_PackedSimd_ShiftRightArithmetic: - case NI_PackedSimd_ShiftRightLogical: - break; - - case NI_PackedSimd_Splat: - break; + } default: { - break; + unreached(); } } diff --git a/src/coreclr/jit/lowerwasm.cpp b/src/coreclr/jit/lowerwasm.cpp index 7c6ddf4c701955..7527e5066efd37 100644 --- a/src/coreclr/jit/lowerwasm.cpp +++ b/src/coreclr/jit/lowerwasm.cpp @@ -825,19 +825,267 @@ void Lowering::AfterLowerArgsForCall(GenTreeCall* call) // GenTree* Lowering::LowerHWIntrinsic(GenTreeHWIntrinsic* node) { - HWIntrinsicCategory category = HWIntrinsicInfo::lookupCategory(node->GetHWIntrinsicId()); - switch (category) + NamedIntrinsic intrinsic = node->GetHWIntrinsicId(); + HWIntrinsicCategory category = HWIntrinsicInfo::lookupCategory(intrinsic); + + switch (intrinsic) { - case HWIntrinsicCategory::HW_Category_SIMD: + case NI_Vector_Create: + case NI_Vector_CreateScalar: + { + return LowerHWIntrinsicCreate(node); + } + + case NI_Vector_op_Equality: + { + assert(category == HW_Category_Helper); + return LowerHWIntrinsicCmpOp(node, GT_EQ); + } + + case NI_Vector_op_Inequality: + { + assert(category == HW_Category_Helper); + return LowerHWIntrinsicCmpOp(node, GT_NE); + } + + case NI_PackedSimd_CompareGreaterThan: + case NI_PackedSimd_CompareGreaterThanOrEqual: + case NI_PackedSimd_CompareLessThan: + case NI_PackedSimd_CompareLessThanOrEqual: { + assert(category == HW_Category_SIMD); + + if (node->GetSimdBaseType() == TYP_ULONG) + { + var_types simdType = node->TypeGet(); + unsigned simdSize = node->GetSimdSize(); + + GenTree* op1 = node->Op(1); + GenTree* op2 = node->Op(2); + + GenTreeVecCon* vecCon1 = m_compiler->gtNewVconNode(simdType); + vecCon1->EvaluateBroadcastInPlace(INT64_MIN); + BlockRange().InsertAfter(op1, vecCon1); + LowerNode(vecCon1); + + op1 = m_compiler->gtNewSimdBinOpNode(GT_SUB, simdType, op1, vecCon1, TYP_ULONG, simdSize); + BlockRange().InsertAfter(vecCon1, op1); + LowerNode(op1); + + GenTreeVecCon* vecCon2 = m_compiler->gtNewVconNode(simdType); + vecCon2->EvaluateBroadcastInPlace(INT64_MIN); + BlockRange().InsertAfter(op2, vecCon2); + LowerNode(vecCon2); + + op2 = m_compiler->gtNewSimdBinOpNode(GT_SUB, simdType, op2, vecCon2, TYP_ULONG, simdSize); + BlockRange().InsertAfter(vecCon2, op2); + LowerNode(op2); + + node->SetSimdBaseType(TYP_LONG); + node->Op(1) = op1; + node->Op(2) = op2; + } break; } + default: - NYI_WASM_SIMD("Lowering::LowerHWIntrinsic"); + { + assert(category == HW_Category_SIMD); + break; + } } return node->gtNext; } +//---------------------------------------------------------------------------------------------- +// Lowering::LowerHWIntrinsicCmpOp: Lowers a Vector128 comparison intrinsic +// +// Arguments: +// node - The hardware intrinsic node. +// cmpOp - The comparison operation, currently must be GT_EQ or GT_NE +// +GenTree* Lowering::LowerHWIntrinsicCmpOp(GenTreeHWIntrinsic* node, genTreeOps cmpOp) +{ + NamedIntrinsic intrinsicId = node->GetHWIntrinsicId(); + var_types simdBaseType = node->GetSimdBaseType(); + unsigned simdSize = node->GetSimdSize(); + var_types simdType = Compiler::getSIMDTypeForSize(simdSize); + + assert((intrinsicId == NI_Vector_op_Equality) || (intrinsicId == NI_Vector_op_Inequality)); + + assert(varTypeIsSIMD(simdType)); + assert(varTypeIsArithmetic(simdBaseType)); + assert(simdSize != 0); + assert(node->TypeIs(TYP_INT)); + assert((cmpOp == GT_EQ) || (cmpOp == GT_NE)); + + GenTree* op1 = node->Op(1); + GenTree* op2 = node->Op(2); + + NamedIntrinsic compareIntrinsic = NI_PackedSimd_CompareEqual; + NamedIntrinsic reduceIntrinsic = NI_PackedSimd_AllTrue; + + if (intrinsicId == NI_Vector_op_Inequality) + { + compareIntrinsic = NI_PackedSimd_CompareNotEqual; + reduceIntrinsic = NI_PackedSimd_AnyTrue; + } + + GenTree* cmp = m_compiler->gtNewSimdHWIntrinsicNode(simdType, op1, op2, compareIntrinsic, simdBaseType, simdSize); + BlockRange().InsertBefore(node, cmp); + LowerNode(cmp); + + node->gtType = TYP_INT; + node->ResetHWIntrinsicId(reduceIntrinsic, m_compiler, cmp); + + if (simdBaseType == TYP_FLOAT) + { + node->SetSimdBaseType(TYP_INT); + } + else if (simdBaseType == TYP_DOUBLE) + { + node->SetSimdBaseType(TYP_LONG); + } + else + { + assert(varTypeIsIntegral(simdBaseType)); + } + + LowerNode(node); + return node->gtNext; +} + +//---------------------------------------------------------------------------------------------- +// Lowering::LowerHWIntrinsicCreate: Lowers a Vector128 Create call +// +// Arguments: +// node - The hardware intrinsic node. +// +GenTree* Lowering::LowerHWIntrinsicCreate(GenTreeHWIntrinsic* node) +{ + NamedIntrinsic intrinsicId = node->GetHWIntrinsicId(); + var_types simdType = node->TypeGet(); + var_types simdBaseType = node->GetSimdBaseType(); + unsigned simdSize = node->GetSimdSize(); + simd_t simdVal = {}; + + assert(varTypeIsSIMD(simdType)); + assert(varTypeIsArithmetic(simdBaseType)); + assert(simdSize != 0); + + bool isConstant = GenTreeVecCon::IsHWIntrinsicCreateConstant(node, simdVal); + bool isCreateScalar = HWIntrinsicInfo::IsVectorCreateScalar(intrinsicId); + size_t argCnt = node->GetOperandCount(); + + if (isConstant) + { + for (GenTree* arg : node->Operands()) + { + BlockRange().Remove(arg); + } + + GenTreeVecCon* vecCon = m_compiler->gtNewVconNode(simdType); + + vecCon->gtSimdVal = simdVal; + BlockRange().InsertBefore(node, vecCon); + + LIR::Use use; + if (BlockRange().TryGetUse(node, &use)) + { + use.ReplaceWith(vecCon); + } + else + { + vecCon->SetUnusedValue(); + } + + BlockRange().Remove(node); + + return LowerNode(vecCon); + } + else if (argCnt == 1) + { + if (isCreateScalar) + { + GenTree* op1 = node->Op(1); + + GenTree* tmp = m_compiler->gtNewZeroConNode(simdType); + BlockRange().InsertBefore(op1, tmp); + LowerNode(tmp); + + GenTree* idx = m_compiler->gtNewIconNode(0); + BlockRange().InsertAfter(tmp, idx); + LowerNode(idx); + + node->ResetHWIntrinsicId(NI_PackedSimd_ReplaceScalar, m_compiler, tmp, idx, op1); + return LowerNode(node); + } + + node->ChangeHWIntrinsicId(NI_PackedSimd_Splat); + return LowerNode(node); + } + + // We have the following (where simd is simd8 or simd16): + // /--* op1 T + // +--* ... T + // +--* opN T + // node = * HWINTRINSIC simd T Create + + // We will be constructing the following parts: + // /--* op1 T + // tmp1 = * HWINTRINSIC simd16 T CreateScalarUnsafe + // ... + + // This is roughly the following managed code: + // var tmp1 = Vector128.CreateScalarUnsafe(op1); + // ... + + GenTree* tmp1 = InsertNewSimdCreateScalarUnsafeNode(simdType, node->Op(1), simdBaseType, simdSize); + LowerNode(tmp1); + + // We will be constructing the following parts: + // ... + // idx = CNS_INT int N + // /--* tmp1 simd + // +--* idx int + // +--* opN T + // tmp1 = * HWINTRINSIC simd T Insert + // ... + + // This is roughly the following managed code: + // ... + // tmp1 = PackedSimd.ReplaceScalar(tmp1, N, opN); + // ... + + unsigned N = 0; + GenTree* opN = nullptr; + GenTree* idx = nullptr; + + for (N = 1; N < argCnt - 1; N++) + { + opN = node->Op(N + 1); + + // Place the insert as early as possible to avoid creating a lot of long lifetimes. + GenTree* insertionPoint = LIR::LastNode(tmp1, opN); + idx = m_compiler->gtNewIconNode(N); + tmp1 = m_compiler->gtNewSimdHWIntrinsicNode(simdType, tmp1, idx, opN, NI_PackedSimd_ReplaceScalar, simdBaseType, + simdSize); + BlockRange().InsertAfter(insertionPoint, idx, tmp1); + LowerNode(tmp1); + } + + assert(N == (argCnt - 1)); + + // For the last insert, we will reuse the existing node and so handle it here, outside the loop. + opN = node->Op(argCnt); + idx = m_compiler->gtNewIconNode(N); + BlockRange().InsertBefore(opN, idx); + + node->ResetHWIntrinsicId(NI_PackedSimd_ReplaceScalar, m_compiler, tmp1, idx, opN); + + return LowerNode(node); +} + //---------------------------------------------------------------------------------------------- // ContainCheckHWIntrinsic: Perform containment analysis for a hardware intrinsic node. // diff --git a/src/coreclr/jit/valuenum.cpp b/src/coreclr/jit/valuenum.cpp index 769e7170e6bb66..cff6a6e66e85f1 100644 --- a/src/coreclr/jit/valuenum.cpp +++ b/src/coreclr/jit/valuenum.cpp @@ -8291,6 +8291,8 @@ ValueNum ValueNumStore::EvalHWIntrinsicFunUnary(GenTreeHWIntrinsic* tree, case NI_X86Base_MoveMask: case NI_AVX_MoveMask: case NI_AVX2_MoveMask: +#elif defined(TARGET_WASM) + case NI_PackedSimd_Bitmask: #endif { From 03b489a355b83e2a0491d06b07cbd99491c2c283 Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Fri, 3 Jul 2026 09:13:10 -0700 Subject: [PATCH 3/6] Various fixes to get crossgen build to succeed --- src/coreclr/jit/gentree.cpp | 57 +++++++++-------- src/coreclr/jit/hwintrinsic.cpp | 40 +++++++++--- src/coreclr/jit/hwintrinsiclistwasm.h | 8 +-- src/coreclr/jit/hwintrinsicwasm.cpp | 56 ++++++++++++++++- src/coreclr/jit/importercalls.cpp | 10 +++ src/coreclr/jit/lclmorph.cpp | 5 ++ src/coreclr/jit/lowerwasm.cpp | 90 +++++++++++++++------------ 7 files changed, 185 insertions(+), 81 deletions(-) diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index e28ee657a05081..b759bba544ca2f 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -23909,7 +23909,9 @@ GenTree* Compiler::gtNewSimdCmpOpNode( assert(varTypeIsIntegral(simdBaseType)); assert(!canUseEvexEncodingDebugOnly()); assert((simdSize == 16) || ((simdSize == 32) && compOpportunisticallyDependsOn(InstructionSet_AVX2))); -#endif // TARGET_XARCH +#elif defined(TARGET_WASM) + assert(simdBaseType == TYP_ULONG); +#endif switch (op) { @@ -23965,7 +23967,13 @@ GenTree* Compiler::gtNewSimdCmpOpNode( return gtNewSimdBinOpNode(GT_OR, type, op1, op2, simdBaseType, simdSize); } +#endif // TARGET_XARCH +#if defined(TARGET_XARCH) || defined(TARGET_WASM) +#if defined(TARGET_WASM) + case GT_GE: + case GT_LE: +#endif case GT_GT: case GT_LT: { @@ -24034,7 +24042,7 @@ GenTree* Compiler::gtNewSimdCmpOpNode( return gtNewSimdCmpOpNode(op, type, op1, op2, simdBaseType, simdSize); } -#endif // TARGET_XARCH +#endif // TARGET_XARCH || TARGET_WASM case GT_NE: { @@ -24215,12 +24223,10 @@ GenTree* Compiler::gtNewSimdCndSelNode( NamedIntrinsic intrinsic = NI_Illegal; -#if defined(TARGET_XARCH) +#if defined(TARGET_XARCH) || defined(TARGET_WASM) return gtNewSimdHWIntrinsicNode(type, op1, op2, op3, NI_Vector_ConditionalSelect, simdBaseType, simdSize); #elif defined(TARGET_ARM64) return gtNewSimdHWIntrinsicNode(type, op1, op2, op3, NI_AdvSimd_BitwiseSelect, simdBaseType, simdSize); -#elif defined(TARGET_WASM) - return gtNewSimdHWIntrinsicNode(type, op2, op3, op1, NI_PackedSimd_BitwiseSelect, simdBaseType, simdSize); #else #error Unsupported platform #endif // !TARGET_XARCH && !TARGET_ARM64 @@ -24415,11 +24421,6 @@ GenTree* Compiler::gtNewSimdCreateScalarNode(var_types type, GenTree* op1, var_t } #endif // TARGET_ARM64 -#if defined(TARGET_WASM) - // TODO-WASM-SIMD: Implement NI_Vector_CreateScalar - return nullptr; -#endif - return gtNewSimdHWIntrinsicNode(type, op1, hwIntrinsicID, simdBaseType, simdSize); } @@ -24543,11 +24544,6 @@ GenTree* Compiler::gtNewSimdCreateScalarUnsafeNode(var_types type, } #endif // TARGET_ARM64 -#if defined(TARGET_WASM) - // TODO-WASM-SIMD: Implement NI_Vector_CreateScalarUnsafe - return nullptr; -#endif - return gtNewSimdHWIntrinsicNode(type, op1, hwIntrinsicID, simdBaseType, simdSize); } @@ -26297,7 +26293,7 @@ GenTree* Compiler::gtNewSimdMinMaxNode(var_types type, assert(!isScalar); - if (isMagnitude) + if (isMagnitude && !varTypeIsUnsigned(simdBaseType)) { GenTree* op1Dup = fgMakeMultiUse(&op1); GenTree* op2Dup = fgMakeMultiUse(&op2); @@ -26309,7 +26305,7 @@ GenTree* Compiler::gtNewSimdMinMaxNode(var_types type, GenTree* absOp2Dup = fgMakeMultiUse(&absOp2); GenTree* equalsMask = gtNewSimdCmpOpNode(GT_EQ, type, absOp1, absOp2, simdBaseType, simdSize); - ; + GenTree* signMask1 = nullptr; GenTree* signMask2 = nullptr; GenTree* signMask3 = nullptr; @@ -26469,7 +26465,7 @@ GenTree* Compiler::gtNewSimdMinMaxNativeNode( { intrinsic = isMax ? NI_PackedSimd_PseudoMax : NI_PackedSimd_PseudoMin; } - else + else if (!varTypeIsLong(simdBaseType)) { intrinsic = isMax ? NI_PackedSimd_Max : NI_PackedSimd_Min; } @@ -32065,10 +32061,7 @@ NamedIntrinsic GenTreeHWIntrinsic::GetHWIntrinsicIdForBinOp(Compiler* comp, #elif defined(TARGET_ARM64) id = NI_AdvSimd_Or; #elif defined(TARGET_WASM) - if (!varTypeIsByte(simdBaseType)) - { - id = NI_PackedSimd_Or; - } + id = NI_PackedSimd_Or; #else #error Unsupported platform #endif @@ -32474,7 +32467,10 @@ NamedIntrinsic GenTreeHWIntrinsic::GetHWIntrinsicIdForCmpOp(Compiler* comp, id = NI_AdvSimd_CompareGreaterThanOrEqual; } #elif defined(TARGET_WASM) - id = NI_PackedSimd_CompareGreaterThanOrEqual; + if (simdBaseType != TYP_ULONG) + { + id = NI_PackedSimd_CompareGreaterThanOrEqual; + } #else #error Unsupported platform #endif @@ -32532,7 +32528,10 @@ NamedIntrinsic GenTreeHWIntrinsic::GetHWIntrinsicIdForCmpOp(Compiler* comp, id = NI_AdvSimd_CompareGreaterThan; } #elif defined(TARGET_WASM) - id = NI_PackedSimd_CompareGreaterThan; + if (simdBaseType != TYP_ULONG) + { + id = NI_PackedSimd_CompareGreaterThan; + } #else #error Unsupported platform #endif @@ -32576,7 +32575,10 @@ NamedIntrinsic GenTreeHWIntrinsic::GetHWIntrinsicIdForCmpOp(Compiler* comp, id = NI_AdvSimd_CompareLessThanOrEqual; } #elif defined(TARGET_WASM) - id = NI_PackedSimd_CompareLessThanOrEqual; + if (simdBaseType != TYP_ULONG) + { + id = NI_PackedSimd_CompareLessThanOrEqual; + } #else #error Unsupported platform #endif @@ -32636,7 +32638,10 @@ NamedIntrinsic GenTreeHWIntrinsic::GetHWIntrinsicIdForCmpOp(Compiler* comp, id = NI_AdvSimd_CompareLessThan; } #elif defined(TARGET_WASM) - id = NI_PackedSimd_CompareLessThan; + if (simdBaseType != TYP_ULONG) + { + id = NI_PackedSimd_CompareLessThan; + } #else #error Unsupported platform #endif diff --git a/src/coreclr/jit/hwintrinsic.cpp b/src/coreclr/jit/hwintrinsic.cpp index f43e496fbc7edc..8c5b32ae951fec 100644 --- a/src/coreclr/jit/hwintrinsic.cpp +++ b/src/coreclr/jit/hwintrinsic.cpp @@ -3109,7 +3109,7 @@ GenTree* Compiler::impXplatIntrinsic(NamedIntrinsic intrinsic, case NI_Vector_AsUInt32: case NI_Vector_AsUInt64: case NI_Vector_AsVector4: -#if defined(TARGET_ARM64) +#if defined(TARGET_ARM64) || defined(TARGET_WASM) case NI_Vector_AsVector: #endif { @@ -3795,6 +3795,15 @@ GenTree* Compiler::impXplatIntrinsic(NamedIntrinsic intrinsic, case NI_Vector_CreateScalar: { assert(sig->numArgs == 1); + +#if defined(TARGET_WASM) + if (!impStackTop(0).val->OperIsConst()) + { + // TODO-WASM-SIMD: Implement NI_Vector_CreateScalar + break; + } +#endif + op1 = impPopStack().val; retNode = gtNewSimdCreateScalarNode(retType, op1, simdBaseType, simdSize); break; @@ -3804,6 +3813,14 @@ GenTree* Compiler::impXplatIntrinsic(NamedIntrinsic intrinsic, { assert(sig->numArgs == 1); +#if defined(TARGET_WASM) + if (!impStackTop(0).val->OperIsConst()) + { + // TODO-WASM-SIMD: Implement NI_Vector_CreateScalarUnsafe + break; + } +#endif + op1 = impPopStack().val; retNode = gtNewSimdCreateScalarUnsafeNode(retType, op1, simdBaseType, simdSize); break; @@ -4446,10 +4463,10 @@ GenTree* Compiler::impXplatIntrinsic(NamedIntrinsic intrinsic, { assert(sig->numArgs == 1); -#if defined(TARGET_ARM64) +#if defined(TARGET_ARM64) || defined(TARGET_WASM) if (opts.OptimizationDisabled()) { - // ARM64 doesn't have aligned loads, but aligned loads are only validated to be + // ARM64/WASM doesn't have aligned loads, but aligned loads are only validated to be // aligned when optimizations are disable, so only skip the intrinsic handling // if optimizations are enabled break; @@ -4472,10 +4489,10 @@ GenTree* Compiler::impXplatIntrinsic(NamedIntrinsic intrinsic, { assert(sig->numArgs == 1); -#if defined(TARGET_ARM64) +#if defined(TARGET_ARM64) || defined(TARGET_WASM) if (opts.OptimizationDisabled()) { - // ARM64 doesn't have aligned loads, but aligned loads are only validated to be + // ARM64/WASM doesn't have aligned loads, but aligned loads are only validated to be // aligned when optimizations are disable, so only skip the intrinsic handling // if optimizations are enabled break; @@ -4964,6 +4981,11 @@ GenTree* Compiler::impXplatIntrinsic(NamedIntrinsic intrinsic, break; } +#if defined(TARGET_WASM) + // TODO-WASM-SIMD: Implement NI_Vector_ShiftLeft + return nullptr; +#endif + #if defined(TARGET_XARCH) if ((simdSize == 16) && !compOpportunisticallyDependsOn(InstructionSet_AVX2)) { @@ -5097,10 +5119,10 @@ GenTree* Compiler::impXplatIntrinsic(NamedIntrinsic intrinsic, assert(sig->numArgs == 2); assert(retType == TYP_VOID); -#if defined(TARGET_ARM64) +#if defined(TARGET_ARM64) || defined(TARGET_WASM) if (opts.OptimizationDisabled()) { - // ARM64 doesn't have aligned stores, but aligned stores are only validated to be + // ARM64/WASM doesn't have aligned stores, but aligned stores are only validated to be // aligned when optimizations are disable, so only skip the intrinsic handling // if optimizations are enabled break; @@ -5128,10 +5150,10 @@ GenTree* Compiler::impXplatIntrinsic(NamedIntrinsic intrinsic, assert(sig->numArgs == 2); assert(retType == TYP_VOID); -#if defined(TARGET_ARM64) +#if defined(TARGET_ARM64) || defined(TARGET_WASM) if (opts.OptimizationDisabled()) { - // ARM64 doesn't have aligned stores, but aligned stores are only validated to be + // ARM64/WASM doesn't have aligned stores, but aligned stores are only validated to be // aligned when optimizations are disable, so only skip the intrinsic handling // if optimizations are enabled break; diff --git a/src/coreclr/jit/hwintrinsiclistwasm.h b/src/coreclr/jit/hwintrinsiclistwasm.h index 42b3c1211196d0..3fc99f95260725 100644 --- a/src/coreclr/jit/hwintrinsiclistwasm.h +++ b/src/coreclr/jit/hwintrinsiclistwasm.h @@ -29,10 +29,10 @@ HARDWARE_INTRINSIC(PackedSimd, Bitmask, 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, -1, -1, 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, -1, -1, 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, -1, -1, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_Commutative|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, -1, -1, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_SpecialCodeGen|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, -1, -1, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_SpecialCodeGen|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, -1, -1, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_SpecialCodeGen|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, -1, -1, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_SpecialCodeGen|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, -1, -1, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_SpecialImport|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, -1, -1, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_SpecialImport|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, -1, -1, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_SpecialImport|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, -1, -1, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_SpecialImport|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, -1, -1, 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, -1, -1, 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, -1, -1, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) diff --git a/src/coreclr/jit/hwintrinsicwasm.cpp b/src/coreclr/jit/hwintrinsicwasm.cpp index 1915586de284ed..05d20b8f5f37ee 100644 --- a/src/coreclr/jit/hwintrinsicwasm.cpp +++ b/src/coreclr/jit/hwintrinsicwasm.cpp @@ -92,6 +92,54 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, switch (intrinsic) { + case NI_PackedSimd_CompareGreaterThan: + { + assert(sig->numArgs == 2); + assert(simdSize == 16); + + op2 = impSIMDPopStack(); + op1 = impSIMDPopStack(); + + retNode = gtNewSimdCmpOpNode(GT_GT, retType, op1, op2, simdBaseType, simdSize); + break; + } + + case NI_PackedSimd_CompareGreaterThanOrEqual: + { + assert(sig->numArgs == 2); + assert(simdSize == 16); + + op2 = impSIMDPopStack(); + op1 = impSIMDPopStack(); + + retNode = gtNewSimdCmpOpNode(GT_GE, retType, op1, op2, simdBaseType, simdSize); + break; + } + + case NI_PackedSimd_CompareLessThan: + { + assert(sig->numArgs == 2); + assert(simdSize == 16); + + op2 = impSIMDPopStack(); + op1 = impSIMDPopStack(); + + retNode = gtNewSimdCmpOpNode(GT_LT, retType, op1, op2, simdBaseType, simdSize); + break; + } + + case NI_PackedSimd_CompareLessThanOrEqual: + { + assert(sig->numArgs == 2); + assert(simdSize == 16); + + op2 = impSIMDPopStack(); + op1 = impSIMDPopStack(); + + retNode = gtNewSimdCmpOpNode(GT_LE, retType, op1, op2, simdBaseType, simdSize); + break; + } + // 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_ExtractScalar: @@ -116,7 +164,9 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, // 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); + + retNode = gtNewSimdLoadNode(retType, op1, simdBaseType, simdSize); + break; } case NI_PackedSimd_LoadScalarVector128: @@ -147,7 +197,9 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, // 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); + + retNode = gtNewSimdStoreNode(op1, op2, simdBaseType, simdSize); + break; } case NI_PackedSimd_StoreSelectedScalar: diff --git a/src/coreclr/jit/importercalls.cpp b/src/coreclr/jit/importercalls.cpp index 086673dd4e2ca9..2bd177d6be78ad 100644 --- a/src/coreclr/jit/importercalls.cpp +++ b/src/coreclr/jit/importercalls.cpp @@ -5276,19 +5276,29 @@ GenTree* Compiler::impIntrinsic(CORINFO_CLASS_HANDLE clsHnd, else if (!isNative || !BlockNonDeterministicIntrinsics(mustExpand)) { #if defined(FEATURE_HW_INTRINSICS) +#if !defined(TARGET_WASM) GenTree* op2 = impImplicitR4orR8Cast(impPopStack().val, callType); GenTree* op1 = impImplicitR4orR8Cast(impPopStack().val, callType); +#endif if (isNative) { assert(!isMagnitude && !isNumber); +#if defined(TARGET_WASM) + // TODO-WASM-SIMD: Implement NI_Vector_MinMax - Need GetElement +#else retNode = gtNewSimdMinMaxNativeNode(callType, op1, op2, JitType2PreciseVarType(callJitType), 0, isMax); +#endif } else { +#if defined(TARGET_WASM) + // TODO-WASM-SIMD: Implement NI_Vector_MinMax - Need GetElement +#else retNode = gtNewSimdMinMaxNode(callType, op1, op2, JitType2PreciseVarType(callJitType), 0, isMax, isMagnitude, isNumber); +#endif } #endif // FEATURE_HW_INTRINSICS diff --git a/src/coreclr/jit/lclmorph.cpp b/src/coreclr/jit/lclmorph.cpp index 426a284166868d..0a7e8e85e17115 100644 --- a/src/coreclr/jit/lclmorph.cpp +++ b/src/coreclr/jit/lclmorph.cpp @@ -1960,6 +1960,11 @@ class LocalAddressVisitor final : public GenTreeVisitor return IndirTransform::LclFld; } +#if defined(TARGET_WASM) + // TODO-WASM-SIMD: Handle once GetElement and WithElement are supported + return IndirTransform::LclFld; +#endif + #ifdef FEATURE_HW_INTRINSICS if (varTypeIsSIMD(varDsc)) { diff --git a/src/coreclr/jit/lowerwasm.cpp b/src/coreclr/jit/lowerwasm.cpp index 7527e5066efd37..ca638ec90b8941 100644 --- a/src/coreclr/jit/lowerwasm.cpp +++ b/src/coreclr/jit/lowerwasm.cpp @@ -830,6 +830,11 @@ GenTree* Lowering::LowerHWIntrinsic(GenTreeHWIntrinsic* node) switch (intrinsic) { + case NI_Vector_ConditionalSelect: + { + return LowerHWIntrinsicCndSel(node); + } + case NI_Vector_Create: case NI_Vector_CreateScalar: { @@ -848,46 +853,6 @@ GenTree* Lowering::LowerHWIntrinsic(GenTreeHWIntrinsic* node) return LowerHWIntrinsicCmpOp(node, GT_NE); } - case NI_PackedSimd_CompareGreaterThan: - case NI_PackedSimd_CompareGreaterThanOrEqual: - case NI_PackedSimd_CompareLessThan: - case NI_PackedSimd_CompareLessThanOrEqual: - { - assert(category == HW_Category_SIMD); - - if (node->GetSimdBaseType() == TYP_ULONG) - { - var_types simdType = node->TypeGet(); - unsigned simdSize = node->GetSimdSize(); - - GenTree* op1 = node->Op(1); - GenTree* op2 = node->Op(2); - - GenTreeVecCon* vecCon1 = m_compiler->gtNewVconNode(simdType); - vecCon1->EvaluateBroadcastInPlace(INT64_MIN); - BlockRange().InsertAfter(op1, vecCon1); - LowerNode(vecCon1); - - op1 = m_compiler->gtNewSimdBinOpNode(GT_SUB, simdType, op1, vecCon1, TYP_ULONG, simdSize); - BlockRange().InsertAfter(vecCon1, op1); - LowerNode(op1); - - GenTreeVecCon* vecCon2 = m_compiler->gtNewVconNode(simdType); - vecCon2->EvaluateBroadcastInPlace(INT64_MIN); - BlockRange().InsertAfter(op2, vecCon2); - LowerNode(vecCon2); - - op2 = m_compiler->gtNewSimdBinOpNode(GT_SUB, simdType, op2, vecCon2, TYP_ULONG, simdSize); - BlockRange().InsertAfter(vecCon2, op2); - LowerNode(op2); - - node->SetSimdBaseType(TYP_LONG); - node->Op(1) = op1; - node->Op(2) = op2; - } - break; - } - default: { assert(category == HW_Category_SIMD); @@ -955,6 +920,51 @@ GenTree* Lowering::LowerHWIntrinsicCmpOp(GenTreeHWIntrinsic* node, genTreeOps cm return node->gtNext; } +//---------------------------------------------------------------------------------------------- +// Lowering::LowerHWIntrinsicCndSel: Lowers a Vector128 ConditionalSelect call +// +// Arguments: +// node - The hardware intrinsic node. +// +GenTree* Lowering::LowerHWIntrinsicCndSel(GenTreeHWIntrinsic* node) +{ + var_types simdType = node->gtType; + var_types simdBaseType = node->GetSimdBaseType(); + unsigned simdSize = node->GetSimdSize(); + + assert(varTypeIsSIMD(simdType)); + assert(varTypeIsArithmetic(simdBaseType)); + assert(simdSize != 0); + + // Get the three arguments to ConditionalSelect we stored in node + // op1: the condition vector + // op2: the left vector + // op3: the right vector + + GenTree* op1 = node->Op(1); + GenTree* op2 = node->Op(2); + GenTree* op3 = node->Op(3); + + if (op3->IsVectorZero()) + { + // The operation is (op2 & op1) | (zero & ~op1), so we can drop the second half + BlockRange().Remove(op3); + node->ResetHWIntrinsicId(NI_PackedSimd_And, m_compiler, op1, op2); + } + else if (op2->IsVectorZero()) + { + // The operation is (zero & op1) | (op3 & ~op1), so we can drop the first half + BlockRange().Remove(op2); + node->ResetHWIntrinsicId(NI_PackedSimd_AndNot, m_compiler, op3, op1); + } + else + { + // PackedSimd.BitwiseSelect is (left, right, condition) + node->ResetHWIntrinsicId(NI_PackedSimd_BitwiseSelect, m_compiler, op2, op3, op1); + } + return LowerNode(node); +} + //---------------------------------------------------------------------------------------------- // Lowering::LowerHWIntrinsicCreate: Lowers a Vector128 Create call // From 485471e36157fa0a1384ff393872d4f25849cd26 Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Fri, 3 Jul 2026 11:26:53 -0700 Subject: [PATCH 4/6] Ensure we use simdSize=16 --- src/coreclr/jit/gentree.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index b759bba544ca2f..f0ade18c043f98 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -29676,7 +29676,7 @@ GenTree* Compiler::gtNewSimdWidenLowerNode(var_types type, GenTree* op1, var_typ } assert(intrinsic != NI_Illegal); - return gtNewSimdHWIntrinsicNode(TYP_SIMD16, op1, intrinsic, simdBaseType, 8); + return gtNewSimdHWIntrinsicNode(TYP_SIMD16, op1, intrinsic, simdBaseType, simdSize); #else #error Unsupported platform #endif // !TARGET_XARCH && !TARGET_ARM64 @@ -29902,7 +29902,7 @@ GenTree* Compiler::gtNewSimdWidenUpperNode(var_types type, GenTree* op1, var_typ } assert(intrinsic != NI_Illegal); - return gtNewSimdHWIntrinsicNode(TYP_SIMD16, op1, intrinsic, simdBaseType, 8); + return gtNewSimdHWIntrinsicNode(TYP_SIMD16, op1, intrinsic, simdBaseType, simdSize); #else #error Unsupported platform #endif // !TARGET_XARCH && !TARGET_ARM64 From 6403a9bdf41463a27dfc5ae78d03a0536c7d8412 Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Tue, 7 Jul 2026 09:29:23 -0700 Subject: [PATCH 5/6] Resolve a table conflict after merging in main --- src/coreclr/jit/hwintrinsiclistwasm.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/jit/hwintrinsiclistwasm.h b/src/coreclr/jit/hwintrinsiclistwasm.h index 3fc99f95260725..ae0eb686c75edd 100644 --- a/src/coreclr/jit/hwintrinsiclistwasm.h +++ b/src/coreclr/jit/hwintrinsiclistwasm.h @@ -66,7 +66,7 @@ HARDWARE_INTRINSIC(PackedSimd, RoundToNearest, HARDWARE_INTRINSIC(PackedSimd, ShiftLeft, 16, 2, INS_i8x16_shl, INS_i8x16_shl, INS_i16x8_shl, INS_i16x8_shl, INS_i32x4_shl, INS_i32x4_shl, INS_i64x2_shl, INS_i64x2_shl, INS_invalid, INS_invalid, -1, -1, HW_Category_IMM, HW_Flag_BaseTypeFromFirstArg|HW_Flag_SpecialImport) HARDWARE_INTRINSIC(PackedSimd, ShiftRightArithmetic, 16, 2, INS_i8x16_shr_s, INS_i8x16_shr_s, INS_i16x8_shr_s, INS_i16x8_shr_s, INS_i32x4_shr_s, INS_i32x4_shr_s, INS_i64x2_shr_s, INS_i64x2_shr_s, INS_invalid, INS_invalid, -1, -1, HW_Category_IMM, HW_Flag_BaseTypeFromFirstArg|HW_Flag_SpecialImport) HARDWARE_INTRINSIC(PackedSimd, ShiftRightLogical, 16, 2, INS_i8x16_shr_u, INS_i8x16_shr_u, INS_i16x8_shr_u, INS_i16x8_shr_u, INS_i32x4_shr_u, INS_i32x4_shr_u, INS_i64x2_shr_u, INS_i64x2_shr_u, INS_invalid, INS_invalid, -1, -1, HW_Category_IMM, HW_Flag_BaseTypeFromFirstArg|HW_Flag_SpecialImport) -HARDWARE_INTRINSIC(PackedSimd, Shuffle, 16, 2, INS_i8x16_shuffle, INS_i8x16_shuffle, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, -1, -1, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(PackedSimd, Shuffle, 16, 3, INS_i8x16_shuffle, INS_i8x16_shuffle, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, -1, -1, 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, -1, -1, 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, -1, -1, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(PackedSimd, Splat, 16, 1, INS_i8x16_splat, INS_i8x16_splat, INS_i16x8_splat, INS_i16x8_splat, INS_i32x4_splat, INS_i32x4_splat, INS_i64x2_splat, INS_i64x2_splat, INS_f32x4_splat, INS_f64x2_splat, -1, -1, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg) From 812eed0ffc48fcbea26bc5c146b9d2c7845213d8 Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Tue, 7 Jul 2026 14:01:47 -0700 Subject: [PATCH 6/6] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- src/coreclr/jit/lowerwasm.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/coreclr/jit/lowerwasm.cpp b/src/coreclr/jit/lowerwasm.cpp index ca638ec90b8941..124a233e37cb3f 100644 --- a/src/coreclr/jit/lowerwasm.cpp +++ b/src/coreclr/jit/lowerwasm.cpp @@ -916,8 +916,7 @@ GenTree* Lowering::LowerHWIntrinsicCmpOp(GenTreeHWIntrinsic* node, genTreeOps cm assert(varTypeIsIntegral(simdBaseType)); } - LowerNode(node); - return node->gtNext; + return LowerNode(node); } //----------------------------------------------------------------------------------------------