Skip to content
This repository was archived by the owner on Feb 5, 2019. It is now read-only.

Commit be7c9e5

Browse files
Dan Gohmanalexcrichton
authored andcommitted
[WebAssembly] Fix fptoui lowering bounds
To fully avoid trapping on wasm, fptoui needs a second check to ensure that the operand isn't below the supported range. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@319354 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent d597d74 commit be7c9e5

File tree

3 files changed

+99
-62
lines changed

3 files changed

+99
-62
lines changed

lib/Target/WebAssembly/WebAssemblyISelLowering.cpp

Lines changed: 40 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,10 @@ LowerFPToInt(
196196
unsigned Abs = Float64 ? WebAssembly::ABS_F64 : WebAssembly::ABS_F32;
197197
unsigned FConst = Float64 ? WebAssembly::CONST_F64 : WebAssembly::CONST_F32;
198198
unsigned LT = Float64 ? WebAssembly::LT_F64 : WebAssembly::LT_F32;
199+
unsigned GE = Float64 ? WebAssembly::GE_F64 : WebAssembly::GE_F32;
199200
unsigned IConst = Int64 ? WebAssembly::CONST_I64 : WebAssembly::CONST_I32;
201+
unsigned Eqz = WebAssembly::EQZ_I32;
202+
unsigned And = WebAssembly::AND_I32;
200203
int64_t Limit = Int64 ? INT64_MIN : INT32_MIN;
201204
int64_t Substitute = IsUnsigned ? 0 : Limit;
202205
double CmpVal = IsUnsigned ? -(double)Limit * 2.0 : -(double)Limit;
@@ -225,14 +228,17 @@ LowerFPToInt(
225228
TrueMBB->addSuccessor(DoneMBB);
226229
FalseMBB->addSuccessor(DoneMBB);
227230

228-
unsigned Tmp0, Tmp1, Tmp2, Tmp3, Tmp4;
231+
unsigned Tmp0, Tmp1, CmpReg, EqzReg, FalseReg, TrueReg;
229232
Tmp0 = MRI.createVirtualRegister(MRI.getRegClass(InReg));
230233
Tmp1 = MRI.createVirtualRegister(MRI.getRegClass(InReg));
231-
Tmp2 = MRI.createVirtualRegister(&WebAssembly::I32RegClass);
232-
Tmp3 = MRI.createVirtualRegister(MRI.getRegClass(OutReg));
233-
Tmp4 = MRI.createVirtualRegister(MRI.getRegClass(OutReg));
234+
CmpReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass);
235+
EqzReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass);
236+
FalseReg = MRI.createVirtualRegister(MRI.getRegClass(OutReg));
237+
TrueReg = MRI.createVirtualRegister(MRI.getRegClass(OutReg));
234238

235239
MI.eraseFromParent();
240+
// For signed numbers, we can do a single comparison to determine whether
241+
// fabs(x) is within range.
236242
if (IsUnsigned) {
237243
Tmp0 = InReg;
238244
} else {
@@ -241,24 +247,44 @@ LowerFPToInt(
241247
}
242248
BuildMI(BB, DL, TII.get(FConst), Tmp1)
243249
.addFPImm(cast<ConstantFP>(ConstantFP::get(Ty, CmpVal)));
244-
BuildMI(BB, DL, TII.get(LT), Tmp2)
250+
BuildMI(BB, DL, TII.get(LT), CmpReg)
245251
.addReg(Tmp0)
246252
.addReg(Tmp1);
253+
254+
// For unsigned numbers, we have to do a separate comparison with zero.
255+
if (IsUnsigned) {
256+
Tmp1 = MRI.createVirtualRegister(MRI.getRegClass(InReg));
257+
unsigned SecondCmpReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass);
258+
unsigned AndReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass);
259+
BuildMI(BB, DL, TII.get(FConst), Tmp1)
260+
.addFPImm(cast<ConstantFP>(ConstantFP::get(Ty, 0.0)));
261+
BuildMI(BB, DL, TII.get(GE), SecondCmpReg)
262+
.addReg(Tmp0)
263+
.addReg(Tmp1);
264+
BuildMI(BB, DL, TII.get(And), AndReg)
265+
.addReg(CmpReg)
266+
.addReg(SecondCmpReg);
267+
CmpReg = AndReg;
268+
}
269+
270+
BuildMI(BB, DL, TII.get(Eqz), EqzReg)
271+
.addReg(CmpReg);
272+
273+
// Create the CFG diamond to select between doing the conversion or using
274+
// the substitute value.
247275
BuildMI(BB, DL, TII.get(WebAssembly::BR_IF))
248276
.addMBB(TrueMBB)
249-
.addReg(Tmp2);
250-
251-
BuildMI(FalseMBB, DL, TII.get(IConst), Tmp3)
252-
.addImm(Substitute);
277+
.addReg(EqzReg);
278+
BuildMI(FalseMBB, DL, TII.get(LoweredOpcode), FalseReg)
279+
.addReg(InReg);
253280
BuildMI(FalseMBB, DL, TII.get(WebAssembly::BR))
254281
.addMBB(DoneMBB);
255-
BuildMI(TrueMBB, DL, TII.get(LoweredOpcode), Tmp4)
256-
.addReg(InReg);
257-
282+
BuildMI(TrueMBB, DL, TII.get(IConst), TrueReg)
283+
.addImm(Substitute);
258284
BuildMI(*DoneMBB, DoneMBB->begin(), DL, TII.get(TargetOpcode::PHI), OutReg)
259-
.addReg(Tmp3)
285+
.addReg(FalseReg)
260286
.addMBB(FalseMBB)
261-
.addReg(Tmp4)
287+
.addReg(TrueReg)
262288
.addMBB(TrueMBB);
263289

264290
return DoneMBB;

lib/Target/WebAssembly/WebAssemblyLowerBrUnless.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,13 @@ bool WebAssemblyLowerBrUnless::runOnMachineFunction(MachineFunction &MF) {
9999
case NE_F32: Def->setDesc(TII.get(EQ_F32)); Inverted = true; break;
100100
case EQ_F64: Def->setDesc(TII.get(NE_F64)); Inverted = true; break;
101101
case NE_F64: Def->setDesc(TII.get(EQ_F64)); Inverted = true; break;
102+
case EQZ_I32: {
103+
// Invert an eqz by replacing it with its operand.
104+
Cond = Def->getOperand(1).getReg();
105+
Def->eraseFromParent();
106+
Inverted = true;
107+
break;
108+
}
102109
default: break;
103110
}
104111
}

test/CodeGen/WebAssembly/conv-trap.ll

Lines changed: 52 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,13 @@ target triple = "wasm32-unknown-unknown-wasm"
1313
; CHECK-NEXT: f32.abs $push[[ABS:[0-9]+]]=, $0{{$}}
1414
; CHECK-NEXT: f32.const $push[[LIMIT:[0-9]+]]=, 0x1p31{{$}}
1515
; CHECK-NEXT: f32.lt $push[[LT:[0-9]+]]=, $pop[[ABS]], $pop[[LIMIT]]{{$}}
16-
; CHECK-NEXT: i32.eqz $push[[EQZ:[0-9]+]]=, $pop[[LT]]{{$}}
17-
; CHECK-NEXT: br_if 0, $pop[[EQZ]]{{$}}
18-
; CHECK-NEXT: i32.trunc_s/f32 $push[[NUM:[0-9]+]]=, $0{{$}}
19-
; CHECK-NEXT: return $pop[[NUM]]{{$}}
20-
; CHECK-NEXT: BB
21-
; CHECK-NEXT: end_block
16+
; CHECK-NEXT: br_if 0, $pop[[LT]]{{$}}
2217
; CHECK-NEXT: i32.const $push[[ALT:[0-9]+]]=, -2147483648{{$}}
2318
; CHECK-NEXT: return $pop[[ALT]]{{$}}
19+
; CHECK-NEXT: BB
20+
; CHECK-NEXT: end_block
21+
; CHECK-NEXT: i32.trunc_s/f32 $push[[NUM:[0-9]+]]=, $0{{$}}
22+
; CHECK-NEXT: return $pop[[NUM]]{{$}}
2423
define i32 @i32_trunc_s_f32(float %x) {
2524
%a = fptosi float %x to i32
2625
ret i32 %a
@@ -32,14 +31,16 @@ define i32 @i32_trunc_s_f32(float %x) {
3231
; CHECK-NEXT: block
3332
; CHECK-NEXT: f32.const $push[[LIMIT:[0-9]+]]=, 0x1p32{{$}}
3433
; CHECK-NEXT: f32.lt $push[[LT:[0-9]+]]=, $0, $pop[[LIMIT]]{{$}}
35-
; CHECK-NEXT: i32.eqz $push[[EQZ:[0-9]+]]=, $pop[[LT]]{{$}}
36-
; CHECK-NEXT: br_if 0, $pop[[EQZ]]{{$}}
37-
; CHECK-NEXT: i32.trunc_u/f32 $push[[NUM:[0-9]+]]=, $0{{$}}
38-
; CHECK-NEXT: return $pop[[NUM]]{{$}}
39-
; CHECK-NEXT: BB
40-
; CHECK-NEXT: end_block
34+
; CHECK-NEXT: f32.const $push[[ZERO:[0-9]+]]=, 0x0p0{{$}}
35+
; CHECK-NEXT: f32.ge $push[[GE:[0-9]+]]=, $0, $pop[[ZERO]]{{$}}
36+
; CHECK-NEXT: i32.and $push[[AND:[0-9]+]]=, $pop[[LT]], $pop[[GE]]{{$}}
37+
; CHECK-NEXT: br_if 0, $pop[[AND]]{{$}}
4138
; CHECK-NEXT: i32.const $push[[ALT:[0-9]+]]=, 0{{$}}
4239
; CHECK-NEXT: return $pop[[ALT]]{{$}}
40+
; CHECK-NEXT: BB
41+
; CHECK-NEXT: end_block
42+
; CHECK-NEXT: i32.trunc_u/f32 $push[[NUM:[0-9]+]]=, $0{{$}}
43+
; CHECK-NEXT: return $pop[[NUM]]{{$}}
4344
define i32 @i32_trunc_u_f32(float %x) {
4445
%a = fptoui float %x to i32
4546
ret i32 %a
@@ -52,14 +53,13 @@ define i32 @i32_trunc_u_f32(float %x) {
5253
; CHECK-NEXT: f64.abs $push[[ABS:[0-9]+]]=, $0{{$}}
5354
; CHECK-NEXT: f64.const $push[[LIMIT:[0-9]+]]=, 0x1p31{{$}}
5455
; CHECK-NEXT: f64.lt $push[[LT:[0-9]+]]=, $pop[[ABS]], $pop[[LIMIT]]{{$}}
55-
; CHECK-NEXT: i32.eqz $push[[EQZ:[0-9]+]]=, $pop[[LT]]{{$}}
56-
; CHECK-NEXT: br_if 0, $pop[[EQZ]]{{$}}
57-
; CHECK-NEXT: i32.trunc_s/f64 $push[[NUM:[0-9]+]]=, $0{{$}}
58-
; CHECK-NEXT: return $pop[[NUM]]{{$}}
59-
; CHECK-NEXT: BB
60-
; CHECK-NEXT: end_block
56+
; CHECK-NEXT: br_if 0, $pop[[LT]]{{$}}
6157
; CHECK-NEXT: i32.const $push[[ALT:[0-9]+]]=, -2147483648{{$}}
6258
; CHECK-NEXT: return $pop[[ALT]]{{$}}
59+
; CHECK-NEXT: BB
60+
; CHECK-NEXT: end_block
61+
; CHECK-NEXT: i32.trunc_s/f64 $push[[NUM:[0-9]+]]=, $0{{$}}
62+
; CHECK-NEXT: return $pop[[NUM]]{{$}}
6363
define i32 @i32_trunc_s_f64(double %x) {
6464
%a = fptosi double %x to i32
6565
ret i32 %a
@@ -71,14 +71,16 @@ define i32 @i32_trunc_s_f64(double %x) {
7171
; CHECK-NEXT: block
7272
; CHECK-NEXT: f64.const $push[[LIMIT:[0-9]+]]=, 0x1p32{{$}}
7373
; CHECK-NEXT: f64.lt $push[[LT:[0-9]+]]=, $0, $pop[[LIMIT]]{{$}}
74-
; CHECK-NEXT: i32.eqz $push[[EQZ:[0-9]+]]=, $pop[[LT]]{{$}}
75-
; CHECK-NEXT: br_if 0, $pop[[EQZ]]{{$}}
76-
; CHECK-NEXT: i32.trunc_u/f64 $push[[NUM:[0-9]+]]=, $0{{$}}
77-
; CHECK-NEXT: return $pop[[NUM]]{{$}}
78-
; CHECK-NEXT: BB
79-
; CHECK-NEXT: end_block
74+
; CHECK-NEXT: f64.const $push[[ZERO:[0-9]+]]=, 0x0p0{{$}}
75+
; CHECK-NEXT: f64.ge $push[[GE:[0-9]+]]=, $0, $pop[[ZERO]]{{$}}
76+
; CHECK-NEXT: i32.and $push[[AND:[0-9]+]]=, $pop[[LT]], $pop[[GE]]{{$}}
77+
; CHECK-NEXT: br_if 0, $pop[[AND]]{{$}}
8078
; CHECK-NEXT: i32.const $push[[ALT:[0-9]+]]=, 0{{$}}
8179
; CHECK-NEXT: return $pop[[ALT]]{{$}}
80+
; CHECK-NEXT: BB
81+
; CHECK-NEXT: end_block
82+
; CHECK-NEXT: i32.trunc_u/f64 $push[[NUM:[0-9]+]]=, $0{{$}}
83+
; CHECK-NEXT: return $pop[[NUM]]{{$}}
8284
define i32 @i32_trunc_u_f64(double %x) {
8385
%a = fptoui double %x to i32
8486
ret i32 %a
@@ -91,14 +93,13 @@ define i32 @i32_trunc_u_f64(double %x) {
9193
; CHECK-NEXT: f32.abs $push[[ABS:[0-9]+]]=, $0{{$}}
9294
; CHECK-NEXT: f32.const $push[[LIMIT:[0-9]+]]=, 0x1p63{{$}}
9395
; CHECK-NEXT: f32.lt $push[[LT:[0-9]+]]=, $pop[[ABS]], $pop[[LIMIT]]{{$}}
94-
; CHECK-NEXT: i32.eqz $push[[EQZ:[0-9]+]]=, $pop[[LT]]{{$}}
95-
; CHECK-NEXT: br_if 0, $pop[[EQZ]]{{$}}
96-
; CHECK-NEXT: i64.trunc_s/f32 $push[[NUM:[0-9]+]]=, $0{{$}}
97-
; CHECK-NEXT: return $pop[[NUM]]{{$}}
98-
; CHECK-NEXT: BB
99-
; CHECK-NEXT: end_block
96+
; CHECK-NEXT: br_if 0, $pop[[LT]]{{$}}
10097
; CHECK-NEXT: i64.const $push[[ALT:[0-9]+]]=, -9223372036854775808{{$}}
10198
; CHECK-NEXT: return $pop[[ALT]]{{$}}
99+
; CHECK-NEXT: BB
100+
; CHECK-NEXT: end_block
101+
; CHECK-NEXT: i64.trunc_s/f32 $push[[NUM:[0-9]+]]=, $0{{$}}
102+
; CHECK-NEXT: return $pop[[NUM]]{{$}}
102103
define i64 @i64_trunc_s_f32(float %x) {
103104
%a = fptosi float %x to i64
104105
ret i64 %a
@@ -110,14 +111,16 @@ define i64 @i64_trunc_s_f32(float %x) {
110111
; CHECK-NEXT: block
111112
; CHECK-NEXT: f32.const $push[[LIMIT:[0-9]+]]=, 0x1p64{{$}}
112113
; CHECK-NEXT: f32.lt $push[[LT:[0-9]+]]=, $0, $pop[[LIMIT]]{{$}}
113-
; CHECK-NEXT: i32.eqz $push[[EQZ:[0-9]+]]=, $pop[[LT]]{{$}}
114-
; CHECK-NEXT: br_if 0, $pop[[EQZ]]{{$}}
115-
; CHECK-NEXT: i64.trunc_u/f32 $push[[NUM:[0-9]+]]=, $0{{$}}
116-
; CHECK-NEXT: return $pop[[NUM]]{{$}}
117-
; CHECK-NEXT: BB
118-
; CHECK-NEXT: end_block
114+
; CHECK-NEXT: f32.const $push[[ZERO:[0-9]+]]=, 0x0p0{{$}}
115+
; CHECK-NEXT: f32.ge $push[[GE:[0-9]+]]=, $0, $pop[[ZERO]]{{$}}
116+
; CHECK-NEXT: i32.and $push[[AND:[0-9]+]]=, $pop[[LT]], $pop[[GE]]{{$}}
117+
; CHECK-NEXT: br_if 0, $pop[[AND]]{{$}}
119118
; CHECK-NEXT: i64.const $push[[ALT:[0-9]+]]=, 0{{$}}
120119
; CHECK-NEXT: return $pop[[ALT]]{{$}}
120+
; CHECK-NEXT: BB
121+
; CHECK-NEXT: end_block
122+
; CHECK-NEXT: i64.trunc_u/f32 $push[[NUM:[0-9]+]]=, $0{{$}}
123+
; CHECK-NEXT: return $pop[[NUM]]{{$}}
121124
define i64 @i64_trunc_u_f32(float %x) {
122125
%a = fptoui float %x to i64
123126
ret i64 %a
@@ -130,14 +133,13 @@ define i64 @i64_trunc_u_f32(float %x) {
130133
; CHECK-NEXT: f64.abs $push[[ABS:[0-9]+]]=, $0{{$}}
131134
; CHECK-NEXT: f64.const $push[[LIMIT:[0-9]+]]=, 0x1p63{{$}}
132135
; CHECK-NEXT: f64.lt $push[[LT:[0-9]+]]=, $pop[[ABS]], $pop[[LIMIT]]{{$}}
133-
; CHECK-NEXT: i32.eqz $push[[EQZ:[0-9]+]]=, $pop[[LT]]{{$}}
134-
; CHECK-NEXT: br_if 0, $pop[[EQZ]]{{$}}
135-
; CHECK-NEXT: i64.trunc_s/f64 $push[[NUM:[0-9]+]]=, $0{{$}}
136-
; CHECK-NEXT: return $pop[[NUM]]{{$}}
137-
; CHECK-NEXT: BB
138-
; CHECK-NEXT: end_block
136+
; CHECK-NEXT: br_if 0, $pop[[LT]]{{$}}
139137
; CHECK-NEXT: i64.const $push[[ALT:[0-9]+]]=, -9223372036854775808{{$}}
140138
; CHECK-NEXT: return $pop[[ALT]]{{$}}
139+
; CHECK-NEXT: BB
140+
; CHECK-NEXT: end_block
141+
; CHECK-NEXT: i64.trunc_s/f64 $push[[NUM:[0-9]+]]=, $0{{$}}
142+
; CHECK-NEXT: return $pop[[NUM]]{{$}}
141143
define i64 @i64_trunc_s_f64(double %x) {
142144
%a = fptosi double %x to i64
143145
ret i64 %a
@@ -149,14 +151,16 @@ define i64 @i64_trunc_s_f64(double %x) {
149151
; CHECK-NEXT: block
150152
; CHECK-NEXT: f64.const $push[[LIMIT:[0-9]+]]=, 0x1p64{{$}}
151153
; CHECK-NEXT: f64.lt $push[[LT:[0-9]+]]=, $0, $pop[[LIMIT]]{{$}}
152-
; CHECK-NEXT: i32.eqz $push[[EQZ:[0-9]+]]=, $pop[[LT]]{{$}}
153-
; CHECK-NEXT: br_if 0, $pop[[EQZ]]{{$}}
154-
; CHECK-NEXT: i64.trunc_u/f64 $push[[NUM:[0-9]+]]=, $0{{$}}
155-
; CHECK-NEXT: return $pop[[NUM]]{{$}}
156-
; CHECK-NEXT: BB
157-
; CHECK-NEXT: end_block
154+
; CHECK-NEXT: f64.const $push[[ZERO:[0-9]+]]=, 0x0p0{{$}}
155+
; CHECK-NEXT: f64.ge $push[[GE:[0-9]+]]=, $0, $pop[[ZERO]]{{$}}
156+
; CHECK-NEXT: i32.and $push[[AND:[0-9]+]]=, $pop[[LT]], $pop[[GE]]{{$}}
157+
; CHECK-NEXT: br_if 0, $pop[[AND]]{{$}}
158158
; CHECK-NEXT: i64.const $push[[ALT:[0-9]+]]=, 0{{$}}
159159
; CHECK-NEXT: return $pop[[ALT]]{{$}}
160+
; CHECK-NEXT: BB
161+
; CHECK-NEXT: end_block
162+
; CHECK-NEXT: i64.trunc_u/f64 $push[[NUM:[0-9]+]]=, $0{{$}}
163+
; CHECK-NEXT: return $pop[[NUM]]{{$}}
160164
define i64 @i64_trunc_u_f64(double %x) {
161165
%a = fptoui double %x to i64
162166
ret i64 %a

0 commit comments

Comments
 (0)