diff options
| author | Dan Gohman <dan433584@gmail.com> | 2017-11-28 01:13:40 +0000 |
|---|---|---|
| committer | Dan Gohman <dan433584@gmail.com> | 2017-11-28 01:13:40 +0000 |
| commit | cdd48b8a6b08a1feb6acbc407b5735ed7e7dfead (patch) | |
| tree | 97d0addeb2e51638441aca7ff7b3d4045d31ea68 /llvm/test | |
| parent | 9e3381e8dc447c936834cf291162a52cace2a517 (diff) | |
| download | bcm5719-llvm-cdd48b8a6b08a1feb6acbc407b5735ed7e7dfead.tar.gz bcm5719-llvm-cdd48b8a6b08a1feb6acbc407b5735ed7e7dfead.zip | |
[WebAssembly] Fix trapping behavior in fptosi/fptoui.
This adds code to protect WebAssembly's `trunc_s` family of opcodes
from values outside their domain. Even though such conversions have
full undefined behavior in C/C++, LLVM IR's `fptosi` and `fptoui` do
not, and only return undef.
This also implements the proposed non-trapping float-to-int conversion
feature and uses that instead when available.
llvm-svn: 319128
Diffstat (limited to 'llvm/test')
| -rw-r--r-- | llvm/test/CodeGen/WebAssembly/conv-trap.ll | 163 | ||||
| -rw-r--r-- | llvm/test/CodeGen/WebAssembly/conv.ll | 18 |
2 files changed, 172 insertions, 9 deletions
diff --git a/llvm/test/CodeGen/WebAssembly/conv-trap.ll b/llvm/test/CodeGen/WebAssembly/conv-trap.ll new file mode 100644 index 00000000000..160d893d74c --- /dev/null +++ b/llvm/test/CodeGen/WebAssembly/conv-trap.ll @@ -0,0 +1,163 @@ +; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -disable-wasm-explicit-locals -mattr=-nontrapping-fptoint | FileCheck %s + +; Test that basic conversion operations assemble as expected using +; the trapping opcodes and explicit code to suppress the trapping. + +target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" +target triple = "wasm32-unknown-unknown-wasm" + +; CHECK-LABEL: i32_trunc_s_f32: +; CHECK-NEXT: .param f32{{$}} +; CHECK-NEXT: .result i32{{$}} +; CHECK-NEXT: block +; CHECK-NEXT: f32.abs $push[[ABS:[0-9]+]]=, $0{{$}} +; CHECK-NEXT: f32.const $push[[LIMIT:[0-9]+]]=, 0x1p31{{$}} +; CHECK-NEXT: f32.lt $push[[LT:[0-9]+]]=, $pop[[ABS]], $pop[[LIMIT]]{{$}} +; CHECK-NEXT: i32.eqz $push[[EQZ:[0-9]+]]=, $pop[[LT]]{{$}} +; CHECK-NEXT: br_if 0, $pop[[EQZ]]{{$}} +; CHECK-NEXT: i32.trunc_s/f32 $push[[NUM:[0-9]+]]=, $0{{$}} +; CHECK-NEXT: return $pop[[NUM]]{{$}} +; CHECK-NEXT: BB +; CHECK-NEXT: end_block +; CHECK-NEXT: i32.const $push[[ALT:[0-9]+]]=, -2147483648{{$}} +; CHECK-NEXT: return $pop[[ALT]]{{$}} +define i32 @i32_trunc_s_f32(float %x) { + %a = fptosi float %x to i32 + ret i32 %a +} + +; CHECK-LABEL: i32_trunc_u_f32: +; CHECK-NEXT: .param f32{{$}} +; CHECK-NEXT: .result i32{{$}} +; CHECK-NEXT: block +; CHECK-NEXT: f32.const $push[[LIMIT:[0-9]+]]=, 0x1p32{{$}} +; CHECK-NEXT: f32.lt $push[[LT:[0-9]+]]=, $0, $pop[[LIMIT]]{{$}} +; CHECK-NEXT: i32.eqz $push[[EQZ:[0-9]+]]=, $pop[[LT]]{{$}} +; CHECK-NEXT: br_if 0, $pop[[EQZ]]{{$}} +; CHECK-NEXT: i32.trunc_u/f32 $push[[NUM:[0-9]+]]=, $0{{$}} +; CHECK-NEXT: return $pop[[NUM]]{{$}} +; CHECK-NEXT: BB +; CHECK-NEXT: end_block +; CHECK-NEXT: i32.const $push[[ALT:[0-9]+]]=, 0{{$}} +; CHECK-NEXT: return $pop[[ALT]]{{$}} +define i32 @i32_trunc_u_f32(float %x) { + %a = fptoui float %x to i32 + ret i32 %a +} + +; CHECK-LABEL: i32_trunc_s_f64: +; CHECK-NEXT: .param f64{{$}} +; CHECK-NEXT: .result i32{{$}} +; CHECK-NEXT: block +; CHECK-NEXT: f64.abs $push[[ABS:[0-9]+]]=, $0{{$}} +; CHECK-NEXT: f64.const $push[[LIMIT:[0-9]+]]=, 0x1p31{{$}} +; CHECK-NEXT: f64.lt $push[[LT:[0-9]+]]=, $pop[[ABS]], $pop[[LIMIT]]{{$}} +; CHECK-NEXT: i32.eqz $push[[EQZ:[0-9]+]]=, $pop[[LT]]{{$}} +; CHECK-NEXT: br_if 0, $pop[[EQZ]]{{$}} +; CHECK-NEXT: i32.trunc_s/f64 $push[[NUM:[0-9]+]]=, $0{{$}} +; CHECK-NEXT: return $pop[[NUM]]{{$}} +; CHECK-NEXT: BB +; CHECK-NEXT: end_block +; CHECK-NEXT: i32.const $push[[ALT:[0-9]+]]=, -2147483648{{$}} +; CHECK-NEXT: return $pop[[ALT]]{{$}} +define i32 @i32_trunc_s_f64(double %x) { + %a = fptosi double %x to i32 + ret i32 %a +} + +; CHECK-LABEL: i32_trunc_u_f64: +; CHECK-NEXT: .param f64{{$}} +; CHECK-NEXT: .result i32{{$}} +; CHECK-NEXT: block +; CHECK-NEXT: f64.const $push[[LIMIT:[0-9]+]]=, 0x1p32{{$}} +; CHECK-NEXT: f64.lt $push[[LT:[0-9]+]]=, $0, $pop[[LIMIT]]{{$}} +; CHECK-NEXT: i32.eqz $push[[EQZ:[0-9]+]]=, $pop[[LT]]{{$}} +; CHECK-NEXT: br_if 0, $pop[[EQZ]]{{$}} +; CHECK-NEXT: i32.trunc_u/f64 $push[[NUM:[0-9]+]]=, $0{{$}} +; CHECK-NEXT: return $pop[[NUM]]{{$}} +; CHECK-NEXT: BB +; CHECK-NEXT: end_block +; CHECK-NEXT: i32.const $push[[ALT:[0-9]+]]=, 0{{$}} +; CHECK-NEXT: return $pop[[ALT]]{{$}} +define i32 @i32_trunc_u_f64(double %x) { + %a = fptoui double %x to i32 + ret i32 %a +} + +; CHECK-LABEL: i64_trunc_s_f32: +; CHECK-NEXT: .param f32{{$}} +; CHECK-NEXT: .result i64{{$}} +; CHECK-NEXT: block +; CHECK-NEXT: f32.abs $push[[ABS:[0-9]+]]=, $0{{$}} +; CHECK-NEXT: f32.const $push[[LIMIT:[0-9]+]]=, 0x1p63{{$}} +; CHECK-NEXT: f32.lt $push[[LT:[0-9]+]]=, $pop[[ABS]], $pop[[LIMIT]]{{$}} +; CHECK-NEXT: i32.eqz $push[[EQZ:[0-9]+]]=, $pop[[LT]]{{$}} +; CHECK-NEXT: br_if 0, $pop[[EQZ]]{{$}} +; CHECK-NEXT: i64.trunc_s/f32 $push[[NUM:[0-9]+]]=, $0{{$}} +; CHECK-NEXT: return $pop[[NUM]]{{$}} +; CHECK-NEXT: BB +; CHECK-NEXT: end_block +; CHECK-NEXT: i64.const $push[[ALT:[0-9]+]]=, -9223372036854775808{{$}} +; CHECK-NEXT: return $pop[[ALT]]{{$}} +define i64 @i64_trunc_s_f32(float %x) { + %a = fptosi float %x to i64 + ret i64 %a +} + +; CHECK-LABEL: i64_trunc_u_f32: +; CHECK-NEXT: .param f32{{$}} +; CHECK-NEXT: .result i64{{$}} +; CHECK-NEXT: block +; CHECK-NEXT: f32.const $push[[LIMIT:[0-9]+]]=, 0x1p64{{$}} +; CHECK-NEXT: f32.lt $push[[LT:[0-9]+]]=, $0, $pop[[LIMIT]]{{$}} +; CHECK-NEXT: i32.eqz $push[[EQZ:[0-9]+]]=, $pop[[LT]]{{$}} +; CHECK-NEXT: br_if 0, $pop[[EQZ]]{{$}} +; CHECK-NEXT: i64.trunc_u/f32 $push[[NUM:[0-9]+]]=, $0{{$}} +; CHECK-NEXT: return $pop[[NUM]]{{$}} +; CHECK-NEXT: BB +; CHECK-NEXT: end_block +; CHECK-NEXT: i64.const $push[[ALT:[0-9]+]]=, 0{{$}} +; CHECK-NEXT: return $pop[[ALT]]{{$}} +define i64 @i64_trunc_u_f32(float %x) { + %a = fptoui float %x to i64 + ret i64 %a +} + +; CHECK-LABEL: i64_trunc_s_f64: +; CHECK-NEXT: .param f64{{$}} +; CHECK-NEXT: .result i64{{$}} +; CHECK-NEXT: block +; CHECK-NEXT: f64.abs $push[[ABS:[0-9]+]]=, $0{{$}} +; CHECK-NEXT: f64.const $push[[LIMIT:[0-9]+]]=, 0x1p63{{$}} +; CHECK-NEXT: f64.lt $push[[LT:[0-9]+]]=, $pop[[ABS]], $pop[[LIMIT]]{{$}} +; CHECK-NEXT: i32.eqz $push[[EQZ:[0-9]+]]=, $pop[[LT]]{{$}} +; CHECK-NEXT: br_if 0, $pop[[EQZ]]{{$}} +; CHECK-NEXT: i64.trunc_s/f64 $push[[NUM:[0-9]+]]=, $0{{$}} +; CHECK-NEXT: return $pop[[NUM]]{{$}} +; CHECK-NEXT: BB +; CHECK-NEXT: end_block +; CHECK-NEXT: i64.const $push[[ALT:[0-9]+]]=, -9223372036854775808{{$}} +; CHECK-NEXT: return $pop[[ALT]]{{$}} +define i64 @i64_trunc_s_f64(double %x) { + %a = fptosi double %x to i64 + ret i64 %a +} + +; CHECK-LABEL: i64_trunc_u_f64: +; CHECK-NEXT: .param f64{{$}} +; CHECK-NEXT: .result i64{{$}} +; CHECK-NEXT: block +; CHECK-NEXT: f64.const $push[[LIMIT:[0-9]+]]=, 0x1p64{{$}} +; CHECK-NEXT: f64.lt $push[[LT:[0-9]+]]=, $0, $pop[[LIMIT]]{{$}} +; CHECK-NEXT: i32.eqz $push[[EQZ:[0-9]+]]=, $pop[[LT]]{{$}} +; CHECK-NEXT: br_if 0, $pop[[EQZ]]{{$}} +; CHECK-NEXT: i64.trunc_u/f64 $push[[NUM:[0-9]+]]=, $0{{$}} +; CHECK-NEXT: return $pop[[NUM]]{{$}} +; CHECK-NEXT: BB +; CHECK-NEXT: end_block +; CHECK-NEXT: i64.const $push[[ALT:[0-9]+]]=, 0{{$}} +; CHECK-NEXT: return $pop[[ALT]]{{$}} +define i64 @i64_trunc_u_f64(double %x) { + %a = fptoui double %x to i64 + ret i64 %a +} diff --git a/llvm/test/CodeGen/WebAssembly/conv.ll b/llvm/test/CodeGen/WebAssembly/conv.ll index 913c4b0b19e..7633f9703c7 100644 --- a/llvm/test/CodeGen/WebAssembly/conv.ll +++ b/llvm/test/CodeGen/WebAssembly/conv.ll @@ -1,4 +1,4 @@ -; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -disable-wasm-explicit-locals | FileCheck %s +; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -disable-wasm-explicit-locals -mattr=+nontrapping-fptoint | FileCheck %s ; Test that basic conversion operations assemble as expected. @@ -38,7 +38,7 @@ define i64 @i64_extend_u_i32(i32 %x) { ; CHECK-LABEL: i32_trunc_s_f32: ; CHECK-NEXT: .param f32{{$}} ; CHECK-NEXT: .result i32{{$}} -; CHECK-NEXT: i32.trunc_s/f32 $push[[NUM:[0-9]+]]=, $0{{$}} +; CHECK-NEXT: i32.trunc_s:sat/f32 $push[[NUM:[0-9]+]]=, $0{{$}} ; CHECK-NEXT: return $pop[[NUM]]{{$}} define i32 @i32_trunc_s_f32(float %x) { %a = fptosi float %x to i32 @@ -48,7 +48,7 @@ define i32 @i32_trunc_s_f32(float %x) { ; CHECK-LABEL: i32_trunc_u_f32: ; CHECK-NEXT: .param f32{{$}} ; CHECK-NEXT: .result i32{{$}} -; CHECK-NEXT: i32.trunc_u/f32 $push[[NUM:[0-9]+]]=, $0{{$}} +; CHECK-NEXT: i32.trunc_u:sat/f32 $push[[NUM:[0-9]+]]=, $0{{$}} ; CHECK-NEXT: return $pop[[NUM]]{{$}} define i32 @i32_trunc_u_f32(float %x) { %a = fptoui float %x to i32 @@ -58,7 +58,7 @@ define i32 @i32_trunc_u_f32(float %x) { ; CHECK-LABEL: i32_trunc_s_f64: ; CHECK-NEXT: .param f64{{$}} ; CHECK-NEXT: .result i32{{$}} -; CHECK-NEXT: i32.trunc_s/f64 $push[[NUM:[0-9]+]]=, $0{{$}} +; CHECK-NEXT: i32.trunc_s:sat/f64 $push[[NUM:[0-9]+]]=, $0{{$}} ; CHECK-NEXT: return $pop[[NUM]]{{$}} define i32 @i32_trunc_s_f64(double %x) { %a = fptosi double %x to i32 @@ -68,7 +68,7 @@ define i32 @i32_trunc_s_f64(double %x) { ; CHECK-LABEL: i32_trunc_u_f64: ; CHECK-NEXT: .param f64{{$}} ; CHECK-NEXT: .result i32{{$}} -; CHECK-NEXT: i32.trunc_u/f64 $push[[NUM:[0-9]+]]=, $0{{$}} +; CHECK-NEXT: i32.trunc_u:sat/f64 $push[[NUM:[0-9]+]]=, $0{{$}} ; CHECK-NEXT: return $pop[[NUM]]{{$}} define i32 @i32_trunc_u_f64(double %x) { %a = fptoui double %x to i32 @@ -78,7 +78,7 @@ define i32 @i32_trunc_u_f64(double %x) { ; CHECK-LABEL: i64_trunc_s_f32: ; CHECK-NEXT: .param f32{{$}} ; CHECK-NEXT: .result i64{{$}} -; CHECK-NEXT: i64.trunc_s/f32 $push[[NUM:[0-9]+]]=, $0{{$}} +; CHECK-NEXT: i64.trunc_s:sat/f32 $push[[NUM:[0-9]+]]=, $0{{$}} ; CHECK-NEXT: return $pop[[NUM]]{{$}} define i64 @i64_trunc_s_f32(float %x) { %a = fptosi float %x to i64 @@ -88,7 +88,7 @@ define i64 @i64_trunc_s_f32(float %x) { ; CHECK-LABEL: i64_trunc_u_f32: ; CHECK-NEXT: .param f32{{$}} ; CHECK-NEXT: .result i64{{$}} -; CHECK-NEXT: i64.trunc_u/f32 $push[[NUM:[0-9]+]]=, $0{{$}} +; CHECK-NEXT: i64.trunc_u:sat/f32 $push[[NUM:[0-9]+]]=, $0{{$}} ; CHECK-NEXT: return $pop[[NUM]]{{$}} define i64 @i64_trunc_u_f32(float %x) { %a = fptoui float %x to i64 @@ -98,7 +98,7 @@ define i64 @i64_trunc_u_f32(float %x) { ; CHECK-LABEL: i64_trunc_s_f64: ; CHECK-NEXT: .param f64{{$}} ; CHECK-NEXT: .result i64{{$}} -; CHECK-NEXT: i64.trunc_s/f64 $push[[NUM:[0-9]+]]=, $0{{$}} +; CHECK-NEXT: i64.trunc_s:sat/f64 $push[[NUM:[0-9]+]]=, $0{{$}} ; CHECK-NEXT: return $pop[[NUM]]{{$}} define i64 @i64_trunc_s_f64(double %x) { %a = fptosi double %x to i64 @@ -108,7 +108,7 @@ define i64 @i64_trunc_s_f64(double %x) { ; CHECK-LABEL: i64_trunc_u_f64: ; CHECK-NEXT: .param f64{{$}} ; CHECK-NEXT: .result i64{{$}} -; CHECK-NEXT: i64.trunc_u/f64 $push[[NUM:[0-9]+]]=, $0{{$}} +; CHECK-NEXT: i64.trunc_u:sat/f64 $push[[NUM:[0-9]+]]=, $0{{$}} ; CHECK-NEXT: return $pop[[NUM]]{{$}} define i64 @i64_trunc_u_f64(double %x) { %a = fptoui double %x to i64 |

