From: Thomas Lively Date: Fri, 13 Sep 2019 22:54:41 +0000 (+0000) Subject: [WebAssembly] Narrowing and widening SIMD ops X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=f308fdbdc638a9a7b905fa13118093c029b85c87;p=llvm [WebAssembly] Narrowing and widening SIMD ops Summary: Implements target-specific LLVM intrinsics and clang builtins for these new SIMD operations, as described at https://github.com/WebAssembly/simd/blob/master/proposals/simd/SIMD.md#integer-to-integer-narrowing. Reviewers: aheejin Subscribers: dschuff, sbc100, jgravelle-google, hiraditya, sunfish, cfe-commits, llvm-commits Tags: #clang, #llvm Differential Revision: https://reviews.llvm.org/D67425 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@371906 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/llvm/IR/IntrinsicsWebAssembly.td b/include/llvm/IR/IntrinsicsWebAssembly.td index 73d190b0b55..6b5d0cbf799 100644 --- a/include/llvm/IR/IntrinsicsWebAssembly.td +++ b/include/llvm/IR/IntrinsicsWebAssembly.td @@ -117,6 +117,31 @@ def int_wasm_qfms : Intrinsic<[llvm_anyvector_ty], [LLVMMatchType<0>, LLVMMatchType<0>, LLVMMatchType<0>], [IntrNoMem, IntrSpeculatable]>; +def int_wasm_narrow_signed : + Intrinsic<[llvm_anyvector_ty], + [llvm_anyvector_ty, LLVMMatchType<1>], + [IntrNoMem, IntrSpeculatable]>; +def int_wasm_narrow_unsigned : + Intrinsic<[llvm_anyvector_ty], + [llvm_anyvector_ty, LLVMMatchType<1>], + [IntrNoMem, IntrSpeculatable]>; +def int_wasm_widen_low_signed : + Intrinsic<[llvm_anyvector_ty], + [llvm_anyvector_ty], + [IntrNoMem, IntrSpeculatable]>; +def int_wasm_widen_high_signed : + Intrinsic<[llvm_anyvector_ty], + [llvm_anyvector_ty], + [IntrNoMem, IntrSpeculatable]>; +def int_wasm_widen_low_unsigned : + Intrinsic<[llvm_anyvector_ty], + [llvm_anyvector_ty], + [IntrNoMem, IntrSpeculatable]>; +def int_wasm_widen_high_unsigned : + Intrinsic<[llvm_anyvector_ty], + [llvm_anyvector_ty], + [IntrNoMem, IntrSpeculatable]>; + //===----------------------------------------------------------------------===// // Bulk memory intrinsics diff --git a/lib/Target/WebAssembly/WebAssemblyInstrSIMD.td b/lib/Target/WebAssembly/WebAssemblyInstrSIMD.td index ff031675959..64fb77136cd 100644 --- a/lib/Target/WebAssembly/WebAssemblyInstrSIMD.td +++ b/lib/Target/WebAssembly/WebAssemblyInstrSIMD.td @@ -712,6 +712,42 @@ defm "" : SIMDConvert; defm "" : SIMDConvert; defm "" : SIMDConvert; +// Widening operations +multiclass SIMDWiden baseInst> { + defm "" : SIMDConvert; + defm "" : SIMDConvert; + defm "" : SIMDConvert; + defm "" : SIMDConvert; +} + +defm "" : SIMDWiden; +defm "" : SIMDWiden; + +// Narrowing operations +multiclass SIMDNarrow baseInst> { + defm NARROW_S_#vec_t : + SIMD_I<(outs V128:$dst), (ins V128:$low, V128:$high), (outs), (ins), + [(set (vec_t V128:$dst), (vec_t (int_wasm_narrow_signed + (arg_t V128:$low), (arg_t V128:$high))))], + vec#".narrow_"#arg#"_s\t$dst, $low, $high", vec#".narrow_"#arg#"_s", + baseInst>; + defm NARROW_U_#vec_t : + SIMD_I<(outs V128:$dst), (ins V128:$low, V128:$high), (outs), (ins), + [(set (vec_t V128:$dst), (vec_t (int_wasm_narrow_unsigned + (arg_t V128:$low), (arg_t V128:$high))))], + vec#".narrow_"#arg#"_u\t$dst, $low, $high", vec#".narrow_"#arg#"_u", + !add(baseInst, 1)>; +} + +defm "" : SIMDNarrow; +defm "" : SIMDNarrow; + // Lower llvm.wasm.trunc.saturate.* to saturating instructions def : Pat<(v4i32 (int_wasm_trunc_saturate_signed (v4f32 V128:$src))), (fp_to_sint_v4i32_v4f32 (v4f32 V128:$src))>; diff --git a/test/CodeGen/WebAssembly/simd-intrinsics.ll b/test/CodeGen/WebAssembly/simd-intrinsics.ll index 2077cf8c70e..f88b8b45426 100644 --- a/test/CodeGen/WebAssembly/simd-intrinsics.ll +++ b/test/CodeGen/WebAssembly/simd-intrinsics.ll @@ -87,6 +87,30 @@ define <16 x i8> @bitselect_v16i8(<16 x i8> %v1, <16 x i8> %v2, <16 x i8> %c) { ret <16 x i8> %a } +; CHECK-LABEL: narrow_signed_v16i8: +; SIMD128-NEXT: .functype narrow_signed_v16i8 (v128, v128) -> (v128){{$}} +; SIMD128-NEXT: i8x16.narrow_i16x8_s $push[[R:[0-9]+]]=, $0, $1{{$}} +; SIMD128-NEXT: return $pop[[R]]{{$}} +declare <16 x i8> @llvm.wasm.narrow.signed.v16i8.v8i16(<8 x i16>, <8 x i16>) +define <16 x i8> @narrow_signed_v16i8(<8 x i16> %low, <8 x i16> %high) { + %a = call <16 x i8> @llvm.wasm.narrow.signed.v16i8.v8i16( + <8 x i16> %low, <8 x i16> %high + ) + ret <16 x i8> %a +} + +; CHECK-LABEL: narrow_unsigned_v16i8: +; SIMD128-NEXT: .functype narrow_unsigned_v16i8 (v128, v128) -> (v128){{$}} +; SIMD128-NEXT: i8x16.narrow_i16x8_u $push[[R:[0-9]+]]=, $0, $1{{$}} +; SIMD128-NEXT: return $pop[[R]]{{$}} +declare <16 x i8> @llvm.wasm.narrow.unsigned.v16i8.v8i16(<8 x i16>, <8 x i16>) +define <16 x i8> @narrow_unsigned_v16i8(<8 x i16> %low, <8 x i16> %high) { + %a = call <16 x i8> @llvm.wasm.narrow.unsigned.v16i8.v8i16( + <8 x i16> %low, <8 x i16> %high + ) + ret <16 x i8> %a +} + ; ============================================================================== ; 8 x i16 ; ============================================================================== @@ -166,6 +190,70 @@ define <8 x i16> @bitselect_v8i16(<8 x i16> %v1, <8 x i16> %v2, <8 x i16> %c) { ret <8 x i16> %a } +; CHECK-LABEL: narrow_signed_v8i16: +; SIMD128-NEXT: .functype narrow_signed_v8i16 (v128, v128) -> (v128){{$}} +; SIMD128-NEXT: i16x8.narrow_i32x4_s $push[[R:[0-9]+]]=, $0, $1{{$}} +; SIMD128-NEXT: return $pop[[R]]{{$}} +declare <8 x i16> @llvm.wasm.narrow.signed.v8i16.v4i32(<4 x i32>, <4 x i32>) +define <8 x i16> @narrow_signed_v8i16(<4 x i32> %low, <4 x i32> %high) { + %a = call <8 x i16> @llvm.wasm.narrow.signed.v8i16.v4i32( + <4 x i32> %low, <4 x i32> %high + ) + ret <8 x i16> %a +} + +; CHECK-LABEL: narrow_unsigned_v8i16: +; SIMD128-NEXT: .functype narrow_unsigned_v8i16 (v128, v128) -> (v128){{$}} +; SIMD128-NEXT: i16x8.narrow_i32x4_u $push[[R:[0-9]+]]=, $0, $1{{$}} +; SIMD128-NEXT: return $pop[[R]]{{$}} +declare <8 x i16> @llvm.wasm.narrow.unsigned.v8i16.v4i32(<4 x i32>, <4 x i32>) +define <8 x i16> @narrow_unsigned_v8i16(<4 x i32> %low, <4 x i32> %high) { + %a = call <8 x i16> @llvm.wasm.narrow.unsigned.v8i16.v4i32( + <4 x i32> %low, <4 x i32> %high + ) + ret <8 x i16> %a +} + +; CHECK-LABEL: widen_low_signed_v8i16: +; SIMD128-NEXT: .functype widen_low_signed_v8i16 (v128) -> (v128){{$}} +; SIMD128-NEXT: i16x8.widen_low_i8x16_s $push[[R:[0-9]+]]=, $0{{$}} +; SIMD128-NEXT: return $pop[[R]]{{$}} +declare <8 x i16> @llvm.wasm.widen.low.signed.v8i16.v16i8(<16 x i8>) +define <8 x i16> @widen_low_signed_v8i16(<16 x i8> %v) { + %a = call <8 x i16> @llvm.wasm.widen.low.signed.v8i16.v16i8(<16 x i8> %v) + ret <8 x i16> %a +} + +; CHECK-LABEL: widen_high_signed_v8i16: +; SIMD128-NEXT: .functype widen_high_signed_v8i16 (v128) -> (v128){{$}} +; SIMD128-NEXT: i16x8.widen_high_i8x16_s $push[[R:[0-9]+]]=, $0{{$}} +; SIMD128-NEXT: return $pop[[R]]{{$}} +declare <8 x i16> @llvm.wasm.widen.high.signed.v8i16.v16i8(<16 x i8>) +define <8 x i16> @widen_high_signed_v8i16(<16 x i8> %v) { + %a = call <8 x i16> @llvm.wasm.widen.high.signed.v8i16.v16i8(<16 x i8> %v) + ret <8 x i16> %a +} + +; CHECK-LABEL: widen_low_unsigned_v8i16: +; SIMD128-NEXT: .functype widen_low_unsigned_v8i16 (v128) -> (v128){{$}} +; SIMD128-NEXT: i16x8.widen_low_i8x16_u $push[[R:[0-9]+]]=, $0{{$}} +; SIMD128-NEXT: return $pop[[R]]{{$}} +declare <8 x i16> @llvm.wasm.widen.low.unsigned.v8i16.v16i8(<16 x i8>) +define <8 x i16> @widen_low_unsigned_v8i16(<16 x i8> %v) { + %a = call <8 x i16> @llvm.wasm.widen.low.unsigned.v8i16.v16i8(<16 x i8> %v) + ret <8 x i16> %a +} + +; CHECK-LABEL: widen_high_unsigned_v8i16: +; SIMD128-NEXT: .functype widen_high_unsigned_v8i16 (v128) -> (v128){{$}} +; SIMD128-NEXT: i16x8.widen_high_i8x16_u $push[[R:[0-9]+]]=, $0{{$}} +; SIMD128-NEXT: return $pop[[R]]{{$}} +declare <8 x i16> @llvm.wasm.widen.high.unsigned.v8i16.v16i8(<16 x i8>) +define <8 x i16> @widen_high_unsigned_v8i16(<16 x i8> %v) { + %a = call <8 x i16> @llvm.wasm.widen.high.unsigned.v8i16.v16i8(<16 x i8> %v) + ret <8 x i16> %a +} + ; ============================================================================== ; 4 x i32 ; ============================================================================== @@ -223,6 +311,46 @@ define <4 x i32> @trunc_sat_u_v4i32(<4 x float> %x) { ret <4 x i32> %a } +; CHECK-LABEL: widen_low_signed_v4i32: +; SIMD128-NEXT: .functype widen_low_signed_v4i32 (v128) -> (v128){{$}} +; SIMD128-NEXT: i32x4.widen_low_i16x8_s $push[[R:[0-9]+]]=, $0{{$}} +; SIMD128-NEXT: return $pop[[R]]{{$}} +declare <4 x i32> @llvm.wasm.widen.low.signed.v4i32.v8i16(<8 x i16>) +define <4 x i32> @widen_low_signed_v4i32(<8 x i16> %v) { + %a = call <4 x i32> @llvm.wasm.widen.low.signed.v4i32.v8i16(<8 x i16> %v) + ret <4 x i32> %a +} + +; CHECK-LABEL: widen_high_signed_v4i32: +; SIMD128-NEXT: .functype widen_high_signed_v4i32 (v128) -> (v128){{$}} +; SIMD128-NEXT: i32x4.widen_high_i16x8_s $push[[R:[0-9]+]]=, $0{{$}} +; SIMD128-NEXT: return $pop[[R]]{{$}} +declare <4 x i32> @llvm.wasm.widen.high.signed.v4i32.v8i16(<8 x i16>) +define <4 x i32> @widen_high_signed_v4i32(<8 x i16> %v) { + %a = call <4 x i32> @llvm.wasm.widen.high.signed.v4i32.v8i16(<8 x i16> %v) + ret <4 x i32> %a +} + +; CHECK-LABEL: widen_low_unsigned_v4i32: +; SIMD128-NEXT: .functype widen_low_unsigned_v4i32 (v128) -> (v128){{$}} +; SIMD128-NEXT: i32x4.widen_low_i16x8_u $push[[R:[0-9]+]]=, $0{{$}} +; SIMD128-NEXT: return $pop[[R]]{{$}} +declare <4 x i32> @llvm.wasm.widen.low.unsigned.v4i32.v8i16(<8 x i16>) +define <4 x i32> @widen_low_unsigned_v4i32(<8 x i16> %v) { + %a = call <4 x i32> @llvm.wasm.widen.low.unsigned.v4i32.v8i16(<8 x i16> %v) + ret <4 x i32> %a +} + +; CHECK-LABEL: widen_high_unsigned_v4i32: +; SIMD128-NEXT: .functype widen_high_unsigned_v4i32 (v128) -> (v128){{$}} +; SIMD128-NEXT: i32x4.widen_high_i16x8_u $push[[R:[0-9]+]]=, $0{{$}} +; SIMD128-NEXT: return $pop[[R]]{{$}} +declare <4 x i32> @llvm.wasm.widen.high.unsigned.v4i32.v8i16(<8 x i16>) +define <4 x i32> @widen_high_unsigned_v4i32(<8 x i16> %v) { + %a = call <4 x i32> @llvm.wasm.widen.high.unsigned.v4i32.v8i16(<8 x i16> %v) + ret <4 x i32> %a +} + ; ============================================================================== ; 2 x i64 ; ============================================================================== diff --git a/test/MC/WebAssembly/simd-encodings.s b/test/MC/WebAssembly/simd-encodings.s index 491b4844d7f..c1c5243a6ca 100644 --- a/test/MC/WebAssembly/simd-encodings.s +++ b/test/MC/WebAssembly/simd-encodings.s @@ -463,4 +463,40 @@ main: # CHECK: f64x2.convert_i64x2_u # encoding: [0xfd,0xb2,0x01] f64x2.convert_i64x2_u + # CHECK: i8x16.narrow_i16x8_s # encoding: [0xfd,0xc6,0x01] + i8x16.narrow_i16x8_s + + # CHECK: i8x16.narrow_i16x8_u # encoding: [0xfd,0xc7,0x01] + i8x16.narrow_i16x8_u + + # CHECK: i16x8.narrow_i32x4_s # encoding: [0xfd,0xc8,0x01] + i16x8.narrow_i32x4_s + + # CHECK: i16x8.narrow_i32x4_u # encoding: [0xfd,0xc9,0x01] + i16x8.narrow_i32x4_u + + # CHECK: i16x8.widen_low_i8x16_s # encoding: [0xfd,0xca,0x01] + i16x8.widen_low_i8x16_s + + # CHECK: i16x8.widen_high_i8x16_s # encoding: [0xfd,0xcb,0x01] + i16x8.widen_high_i8x16_s + + # CHECK: i16x8.widen_low_i8x16_u # encoding: [0xfd,0xcc,0x01] + i16x8.widen_low_i8x16_u + + # CHECK: i16x8.widen_high_i8x16_u # encoding: [0xfd,0xcd,0x01] + i16x8.widen_high_i8x16_u + + # CHECK: i32x4.widen_low_i16x8_s # encoding: [0xfd,0xce,0x01] + i32x4.widen_low_i16x8_s + + # CHECK: i32x4.widen_high_i16x8_s # encoding: [0xfd,0xcf,0x01] + i32x4.widen_high_i16x8_s + + # CHECK: i32x4.widen_low_i16x8_u # encoding: [0xfd,0xd0,0x01] + i32x4.widen_low_i16x8_u + + # CHECK: i32x4.widen_high_i16x8_u # encoding: [0xfd,0xd1,0x01] + i32x4.widen_high_i16x8_u + end_function