[llvm] r344204 - [WebAssembly] Saturating float to int intrinsics

Thomas Lively via llvm-commits llvm-commits at lists.llvm.org
Wed Oct 10 17:01:25 PDT 2018


Author: tlively
Date: Wed Oct 10 17:01:25 2018
New Revision: 344204

URL: http://llvm.org/viewvc/llvm-project?rev=344204&view=rev
Log:
[WebAssembly] Saturating float to int intrinsics

Summary:
Although the saturating float to int instructions are already
emitted from normal IR, the fpto{s,u}i instructions produce poison
values if the argument cannot fit in the result type. These intrinsics
are therefore necessary to get guaranteed defined saturating behavior.

Reviewers: aheejin, dschuff

Subscribers: sbc100, jgravelle-google, sunfish, llvm-commits

Differential Revision: https://reviews.llvm.org/D53004

Modified:
    llvm/trunk/include/llvm/IR/IntrinsicsWebAssembly.td
    llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrConv.td
    llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrSIMD.td
    llvm/trunk/test/CodeGen/WebAssembly/conv.ll
    llvm/trunk/test/CodeGen/WebAssembly/simd-intrinsics.ll

Modified: llvm/trunk/include/llvm/IR/IntrinsicsWebAssembly.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/IR/IntrinsicsWebAssembly.td?rev=344204&r1=344203&r2=344204&view=diff
==============================================================================
--- llvm/trunk/include/llvm/IR/IntrinsicsWebAssembly.td (original)
+++ llvm/trunk/include/llvm/IR/IntrinsicsWebAssembly.td Wed Oct 10 17:01:25 2018
@@ -37,6 +37,17 @@ def int_wasm_current_memory : Intrinsic<
 def int_wasm_grow_memory : Intrinsic<[llvm_anyint_ty], [LLVMMatchType<0>], []>;
 
 //===----------------------------------------------------------------------===//
+// Saturating float-to-int conversions
+//===----------------------------------------------------------------------===//
+
+def int_wasm_trunc_saturate_signed : Intrinsic<[llvm_anyint_ty],
+                                               [llvm_anyfloat_ty],
+                                               [IntrNoMem, IntrSpeculatable]>;
+def int_wasm_trunc_saturate_unsigned : Intrinsic<[llvm_anyint_ty],
+                                                 [llvm_anyfloat_ty],
+                                                 [IntrNoMem, IntrSpeculatable]>;
+
+//===----------------------------------------------------------------------===//
 // Exception handling intrinsics
 //===----------------------------------------------------------------------===//
 

Modified: llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrConv.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrConv.td?rev=344204&r1=344203&r2=344204&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrConv.td (original)
+++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrConv.td Wed Oct 10 17:01:25 2018
@@ -97,6 +97,24 @@ defm I64_TRUNC_U_SAT_F64 : I<(outs I64:$
                              "i64.trunc_u:sat/f64", 0xfc07>,
                              Requires<[HasNontrappingFPToInt]>;
 
+// Lower llvm.wasm.trunc.saturate.* to saturating instructions
+def : Pat<(int_wasm_trunc_saturate_signed F32:$src),
+          (I32_TRUNC_S_SAT_F32 F32:$src)>;
+def : Pat<(int_wasm_trunc_saturate_unsigned F32:$src),
+          (I32_TRUNC_U_SAT_F32 F32:$src)>;
+def : Pat<(int_wasm_trunc_saturate_signed F64:$src),
+          (I32_TRUNC_S_SAT_F64 F64:$src)>;
+def : Pat<(int_wasm_trunc_saturate_unsigned F64:$src),
+          (I32_TRUNC_U_SAT_F64 F64:$src)>;
+def : Pat<(int_wasm_trunc_saturate_signed F32:$src),
+          (I64_TRUNC_S_SAT_F32 F32:$src)>;
+def : Pat<(int_wasm_trunc_saturate_unsigned F32:$src),
+          (I64_TRUNC_U_SAT_F32 F32:$src)>;
+def : Pat<(int_wasm_trunc_saturate_signed F64:$src),
+          (I64_TRUNC_S_SAT_F64 F64:$src)>;
+def : Pat<(int_wasm_trunc_saturate_unsigned F64:$src),
+          (I64_TRUNC_U_SAT_F64 F64:$src)>;
+
 // Conversion from floating point to integer pseudo-instructions which don't
 // trap on overflow or invalid.
 let usesCustomInserter = 1, isCodeGenOnly = 1 in {

Modified: llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrSIMD.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrSIMD.td?rev=344204&r1=344203&r2=344204&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrSIMD.td (original)
+++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrSIMD.td Wed Oct 10 17:01:25 2018
@@ -782,6 +782,16 @@ defm "" : SIMDConvert<v4i32, v4f32, fp_t
 defm "" : SIMDConvert<v2i64, v2f64, fp_to_sint, "i64x2.trunc_sat_s/f64x2", 149>;
 defm "" : SIMDConvert<v2i64, v2f64, fp_to_uint, "i64x2.trunc_sat_u/f64x2", 150>;
 
+// 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))>;
+def : Pat<(v4i32 (int_wasm_trunc_saturate_unsigned (v4f32 V128:$src))),
+          (fp_to_uint_v4i32_v4f32 (v4f32 V128:$src))>;
+def : Pat<(v2i64 (int_wasm_trunc_saturate_signed (v2f64 V128:$src))),
+          (fp_to_sint_v2i64_v2f64 (v2f64 V128:$src))>;
+def : Pat<(v2i64 (int_wasm_trunc_saturate_unsigned (v2f64 V128:$src))),
+          (fp_to_uint_v2i64_v2f64 (v2f64 V128:$src))>;
+
 // Bitcasts are nops
 // Matching bitcast t1 to t1 causes strange errors, so avoid repeating types
 foreach t1 = [v16i8, v8i16, v4i32, v2i64, v4f32, v2f64] in

Modified: llvm/trunk/test/CodeGen/WebAssembly/conv.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/WebAssembly/conv.ll?rev=344204&r1=344203&r2=344204&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/WebAssembly/conv.ll (original)
+++ llvm/trunk/test/CodeGen/WebAssembly/conv.ll Wed Oct 10 17:01:25 2018
@@ -45,6 +45,17 @@ define i32 @i32_trunc_s_f32(float %x) {
   ret i32 %a
 }
 
+; CHECK-LABEL: i32_trunc_sat_s_f32:
+; CHECK-NEXT: .param f32{{$}}
+; CHECK-NEXT: .result i32{{$}}
+; CHECK-NEXT: i32.trunc_s:sat/f32 $push[[NUM:[0-9]+]]=, $0{{$}}
+; CHECK-NEXT: return $pop[[NUM]]{{$}}
+declare i32 @llvm.wasm.trunc.saturate.signed.i32.f32(float)
+define i32 @i32_trunc_sat_s_f32(float %x) {
+  %a = call i32 @llvm.wasm.trunc.saturate.signed.i32.f32(float %x)
+  ret i32 %a
+}
+
 ; CHECK-LABEL: i32_trunc_u_f32:
 ; CHECK-NEXT: .param f32{{$}}
 ; CHECK-NEXT: .result i32{{$}}
@@ -55,6 +66,17 @@ define i32 @i32_trunc_u_f32(float %x) {
   ret i32 %a
 }
 
+; CHECK-LABEL: i32_trunc_sat_u_f32:
+; CHECK-NEXT: .param f32{{$}}
+; CHECK-NEXT: .result i32{{$}}
+; CHECK-NEXT: i32.trunc_u:sat/f32 $push[[NUM:[0-9]+]]=, $0{{$}}
+; CHECK-NEXT: return $pop[[NUM]]{{$}}
+declare i32 @llvm.wasm.trunc.saturate.unsigned.i32.f32(float)
+define i32 @i32_trunc_sat_u_f32(float %x) {
+  %a = call i32 @llvm.wasm.trunc.saturate.unsigned.i32.f32(float %x)
+  ret i32 %a
+}
+
 ; CHECK-LABEL: i32_trunc_s_f64:
 ; CHECK-NEXT: .param f64{{$}}
 ; CHECK-NEXT: .result i32{{$}}
@@ -65,6 +87,17 @@ define i32 @i32_trunc_s_f64(double %x) {
   ret i32 %a
 }
 
+; CHECK-LABEL: i32_trunc_sat_s_f64:
+; CHECK-NEXT: .param f64{{$}}
+; CHECK-NEXT: .result i32{{$}}
+; CHECK-NEXT: i32.trunc_s:sat/f64 $push[[NUM:[0-9]+]]=, $0{{$}}
+; CHECK-NEXT: return $pop[[NUM]]{{$}}
+declare i32 @llvm.wasm.trunc.saturate.signed.i32.f64(double)
+define i32 @i32_trunc_sat_s_f64(double %x) {
+  %a = call i32 @llvm.wasm.trunc.saturate.signed.i32.f64(double %x)
+  ret i32 %a
+}
+
 ; CHECK-LABEL: i32_trunc_u_f64:
 ; CHECK-NEXT: .param f64{{$}}
 ; CHECK-NEXT: .result i32{{$}}
@@ -75,6 +108,17 @@ define i32 @i32_trunc_u_f64(double %x) {
   ret i32 %a
 }
 
+; CHECK-LABEL: i32_trunc_sat_u_f64:
+; CHECK-NEXT: .param f64{{$}}
+; CHECK-NEXT: .result i32{{$}}
+; CHECK-NEXT: i32.trunc_u:sat/f64 $push[[NUM:[0-9]+]]=, $0{{$}}
+; CHECK-NEXT: return $pop[[NUM]]{{$}}
+declare i32 @llvm.wasm.trunc.saturate.unsigned.i32.f64(double)
+define i32 @i32_trunc_sat_u_f64(double %x) {
+  %a = call i32 @llvm.wasm.trunc.saturate.unsigned.i32.f64(double %x)
+  ret i32 %a
+}
+
 ; CHECK-LABEL: i64_trunc_s_f32:
 ; CHECK-NEXT: .param f32{{$}}
 ; CHECK-NEXT: .result i64{{$}}
@@ -85,6 +129,17 @@ define i64 @i64_trunc_s_f32(float %x) {
   ret i64 %a
 }
 
+; CHECK-LABEL: i64_trunc_sat_s_f32:
+; CHECK-NEXT: .param f32{{$}}
+; CHECK-NEXT: .result i64{{$}}
+; CHECK-NEXT: i64.trunc_s:sat/f32 $push[[NUM:[0-9]+]]=, $0{{$}}
+; CHECK-NEXT: return $pop[[NUM]]{{$}}
+declare i64 @llvm.wasm.trunc.saturate.signed.i64.f32(float)
+define i64 @i64_trunc_sat_s_f32(float %x) {
+  %a = call i64 @llvm.wasm.trunc.saturate.signed.i64.f32(float %x)
+  ret i64 %a
+}
+
 ; CHECK-LABEL: i64_trunc_u_f32:
 ; CHECK-NEXT: .param f32{{$}}
 ; CHECK-NEXT: .result i64{{$}}
@@ -95,6 +150,17 @@ define i64 @i64_trunc_u_f32(float %x) {
   ret i64 %a
 }
 
+; CHECK-LABEL: i64_trunc_sat_u_f32:
+; CHECK-NEXT: .param f32{{$}}
+; CHECK-NEXT: .result i64{{$}}
+; CHECK-NEXT: i64.trunc_u:sat/f32 $push[[NUM:[0-9]+]]=, $0{{$}}
+; CHECK-NEXT: return $pop[[NUM]]{{$}}
+declare i64 @llvm.wasm.trunc.saturate.unsigned.i64.f32(float)
+define i64 @i64_trunc_sat_u_f32(float %x) {
+  %a = call i64 @llvm.wasm.trunc.saturate.unsigned.i64.f32(float %x)
+  ret i64 %a
+}
+
 ; CHECK-LABEL: i64_trunc_s_f64:
 ; CHECK-NEXT: .param f64{{$}}
 ; CHECK-NEXT: .result i64{{$}}
@@ -105,6 +171,17 @@ define i64 @i64_trunc_s_f64(double %x) {
   ret i64 %a
 }
 
+; CHECK-LABEL: i64_trunc_sat_s_f64:
+; CHECK-NEXT: .param f64{{$}}
+; CHECK-NEXT: .result i64{{$}}
+; CHECK-NEXT: i64.trunc_s:sat/f64 $push[[NUM:[0-9]+]]=, $0{{$}}
+; CHECK-NEXT: return $pop[[NUM]]{{$}}
+declare i64 @llvm.wasm.trunc.saturate.signed.i64.f64(double)
+define i64 @i64_trunc_sat_s_f64(double %x) {
+  %a = call i64 @llvm.wasm.trunc.saturate.signed.i64.f64(double %x)
+  ret i64 %a
+}
+
 ; CHECK-LABEL: i64_trunc_u_f64:
 ; CHECK-NEXT: .param f64{{$}}
 ; CHECK-NEXT: .result i64{{$}}
@@ -115,6 +192,17 @@ define i64 @i64_trunc_u_f64(double %x) {
   ret i64 %a
 }
 
+; CHECK-LABEL: i64_trunc_sat_u_f64:
+; CHECK-NEXT: .param f64{{$}}
+; CHECK-NEXT: .result i64{{$}}
+; CHECK-NEXT: i64.trunc_u:sat/f64 $push[[NUM:[0-9]+]]=, $0{{$}}
+; CHECK-NEXT: return $pop[[NUM]]{{$}}
+declare i64 @llvm.wasm.trunc.saturate.unsigned.i64.f64(double)
+define i64 @i64_trunc_sat_u_f64(double %x) {
+  %a = call i64 @llvm.wasm.trunc.saturate.unsigned.i64.f64(double %x)
+  ret i64 %a
+}
+
 ; CHECK-LABEL: f32_convert_s_i32:
 ; CHECK-NEXT: .param i32{{$}}
 ; CHECK-NEXT: .result f32{{$}}

Modified: llvm/trunk/test/CodeGen/WebAssembly/simd-intrinsics.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/WebAssembly/simd-intrinsics.ll?rev=344204&r1=344203&r2=344204&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/WebAssembly/simd-intrinsics.ll (original)
+++ llvm/trunk/test/CodeGen/WebAssembly/simd-intrinsics.ll Wed Oct 10 17:01:25 2018
@@ -226,6 +226,30 @@ define <4 x i32> @bitselect_v4i32(<4 x i
   ret <4 x i32> %a
 }
 
+; CHECK-LABEL: trunc_sat_s_v4i32:
+; NO-SIMD128-NOT: f32x4
+; SIMD128-NEXT: .param v128{{$}}
+; SIMD128-NEXT: .result v128{{$}}
+; SIMD128-NEXT: i32x4.trunc_sat_s/f32x4 $push[[R:[0-9]+]]=, $0
+; SIMD128-NEXT: return $pop[[R]]
+declare <4 x i32> @llvm.wasm.trunc.saturate.signed.v4i32.v4f32(<4 x float>)
+define <4 x i32> @trunc_sat_s_v4i32(<4 x float> %x) {
+  %a = call <4 x i32> @llvm.wasm.trunc.saturate.signed.v4i32.v4f32(<4 x float> %x)
+  ret <4 x i32> %a
+}
+
+; CHECK-LABEL: trunc_sat_u_v4i32:
+; NO-SIMD128-NOT: f32x4
+; SIMD128-NEXT: .param v128{{$}}
+; SIMD128-NEXT: .result v128{{$}}
+; SIMD128-NEXT: i32x4.trunc_sat_u/f32x4 $push[[R:[0-9]+]]=, $0
+; SIMD128-NEXT: return $pop[[R]]
+declare <4 x i32> @llvm.wasm.trunc.saturate.unsigned.v4i32.v4f32(<4 x float>)
+define <4 x i32> @trunc_sat_u_v4i32(<4 x float> %x) {
+  %a = call <4 x i32> @llvm.wasm.trunc.saturate.unsigned.v4i32.v4f32(<4 x float> %x)
+  ret <4 x i32> %a
+}
+
 ; ==============================================================================
 ; 2 x i64
 ; ==============================================================================
@@ -264,6 +288,30 @@ define <2 x i64> @bitselect_v2i64(<2 x i
   ret <2 x i64> %a
 }
 
+; CHECK-LABEL: trunc_sat_s_v2i64:
+; NO-SIMD128-NOT: f32x4
+; SIMD128-NEXT: .param v128{{$}}
+; SIMD128-NEXT: .result v128{{$}}
+; SIMD128-NEXT: i64x2.trunc_sat_s/f64x2 $push[[R:[0-9]+]]=, $0
+; SIMD128-NEXT: return $pop[[R]]
+declare <2 x i64> @llvm.wasm.trunc.saturate.signed.v2i64.v2f64(<2 x double>)
+define <2 x i64> @trunc_sat_s_v2i64(<2 x double> %x) {
+  %a = call <2 x i64> @llvm.wasm.trunc.saturate.signed.v2i64.v2f64(<2 x double> %x)
+  ret <2 x i64> %a
+}
+
+; CHECK-LABEL: trunc_sat_u_v2i64:
+; NO-SIMD128-NOT: f32x4
+; SIMD128-NEXT: .param v128{{$}}
+; SIMD128-NEXT: .result v128{{$}}
+; SIMD128-NEXT: i64x2.trunc_sat_u/f64x2 $push[[R:[0-9]+]]=, $0
+; SIMD128-NEXT: return $pop[[R]]
+declare <2 x i64> @llvm.wasm.trunc.saturate.unsigned.v2i64.v2f64(<2 x double>)
+define <2 x i64> @trunc_sat_u_v2i64(<2 x double> %x) {
+  %a = call <2 x i64> @llvm.wasm.trunc.saturate.unsigned.v2i64.v2f64(<2 x double> %x)
+  ret <2 x i64> %a
+}
+
 ; ==============================================================================
 ; 4 x f32
 ; ==============================================================================




More information about the llvm-commits mailing list