llvm.org GIT mirror llvm / 685c102
[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 Dan Gohman 2 years ago
3 changed file(s) with 99 addition(s) and 62 deletion(s). Raw diff Collapse all Expand all
206206 unsigned Abs = Float64 ? WebAssembly::ABS_F64 : WebAssembly::ABS_F32;
207207 unsigned FConst = Float64 ? WebAssembly::CONST_F64 : WebAssembly::CONST_F32;
208208 unsigned LT = Float64 ? WebAssembly::LT_F64 : WebAssembly::LT_F32;
209 unsigned GE = Float64 ? WebAssembly::GE_F64 : WebAssembly::GE_F32;
209210 unsigned IConst = Int64 ? WebAssembly::CONST_I64 : WebAssembly::CONST_I32;
211 unsigned Eqz = WebAssembly::EQZ_I32;
212 unsigned And = WebAssembly::AND_I32;
210213 int64_t Limit = Int64 ? INT64_MIN : INT32_MIN;
211214 int64_t Substitute = IsUnsigned ? 0 : Limit;
212215 double CmpVal = IsUnsigned ? -(double)Limit * 2.0 : -(double)Limit;
235238 TrueMBB->addSuccessor(DoneMBB);
236239 FalseMBB->addSuccessor(DoneMBB);
237240
238 unsigned Tmp0, Tmp1, Tmp2, Tmp3, Tmp4;
241 unsigned Tmp0, Tmp1, CmpReg, EqzReg, FalseReg, TrueReg;
239242 Tmp0 = MRI.createVirtualRegister(MRI.getRegClass(InReg));
240243 Tmp1 = MRI.createVirtualRegister(MRI.getRegClass(InReg));
241 Tmp2 = MRI.createVirtualRegister(&WebAssembly::I32RegClass);
242 Tmp3 = MRI.createVirtualRegister(MRI.getRegClass(OutReg));
243 Tmp4 = MRI.createVirtualRegister(MRI.getRegClass(OutReg));
244 CmpReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass);
245 EqzReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass);
246 FalseReg = MRI.createVirtualRegister(MRI.getRegClass(OutReg));
247 TrueReg = MRI.createVirtualRegister(MRI.getRegClass(OutReg));
244248
245249 MI.eraseFromParent();
250 // For signed numbers, we can do a single comparison to determine whether
251 // fabs(x) is within range.
246252 if (IsUnsigned) {
247253 Tmp0 = InReg;
248254 } else {
251257 }
252258 BuildMI(BB, DL, TII.get(FConst), Tmp1)
253259 .addFPImm(cast(ConstantFP::get(Ty, CmpVal)));
254 BuildMI(BB, DL, TII.get(LT), Tmp2)
260 BuildMI(BB, DL, TII.get(LT), CmpReg)
255261 .addReg(Tmp0)
256262 .addReg(Tmp1);
263
264 // For unsigned numbers, we have to do a separate comparison with zero.
265 if (IsUnsigned) {
266 Tmp1 = MRI.createVirtualRegister(MRI.getRegClass(InReg));
267 unsigned SecondCmpReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass);
268 unsigned AndReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass);
269 BuildMI(BB, DL, TII.get(FConst), Tmp1)
270 .addFPImm(cast(ConstantFP::get(Ty, 0.0)));
271 BuildMI(BB, DL, TII.get(GE), SecondCmpReg)
272 .addReg(Tmp0)
273 .addReg(Tmp1);
274 BuildMI(BB, DL, TII.get(And), AndReg)
275 .addReg(CmpReg)
276 .addReg(SecondCmpReg);
277 CmpReg = AndReg;
278 }
279
280 BuildMI(BB, DL, TII.get(Eqz), EqzReg)
281 .addReg(CmpReg);
282
283 // Create the CFG diamond to select between doing the conversion or using
284 // the substitute value.
257285 BuildMI(BB, DL, TII.get(WebAssembly::BR_IF))
258286 .addMBB(TrueMBB)
259 .addReg(Tmp2);
260
261 BuildMI(FalseMBB, DL, TII.get(IConst), Tmp3)
262 .addImm(Substitute);
287 .addReg(EqzReg);
288 BuildMI(FalseMBB, DL, TII.get(LoweredOpcode), FalseReg)
289 .addReg(InReg);
263290 BuildMI(FalseMBB, DL, TII.get(WebAssembly::BR))
264291 .addMBB(DoneMBB);
265 BuildMI(TrueMBB, DL, TII.get(LoweredOpcode), Tmp4)
266 .addReg(InReg);
267
292 BuildMI(TrueMBB, DL, TII.get(IConst), TrueReg)
293 .addImm(Substitute);
268294 BuildMI(*DoneMBB, DoneMBB->begin(), DL, TII.get(TargetOpcode::PHI), OutReg)
269 .addReg(Tmp3)
295 .addReg(FalseReg)
270296 .addMBB(FalseMBB)
271 .addReg(Tmp4)
297 .addReg(TrueReg)
272298 .addMBB(TrueMBB);
273299
274300 return DoneMBB;
9898 case NE_F32: Def->setDesc(TII.get(EQ_F32)); Inverted = true; break;
9999 case EQ_F64: Def->setDesc(TII.get(NE_F64)); Inverted = true; break;
100100 case NE_F64: Def->setDesc(TII.get(EQ_F64)); Inverted = true; break;
101 case EQZ_I32: {
102 // Invert an eqz by replacing it with its operand.
103 Cond = Def->getOperand(1).getReg();
104 Def->eraseFromParent();
105 Inverted = true;
106 break;
107 }
101108 default: break;
102109 }
103110 }
1212 ; CHECK-NEXT: f32.abs $push[[ABS:[0-9]+]]=, $0{{$}}
1313 ; CHECK-NEXT: f32.const $push[[LIMIT:[0-9]+]]=, 0x1p31{{$}}
1414 ; CHECK-NEXT: f32.lt $push[[LT:[0-9]+]]=, $pop[[ABS]], $pop[[LIMIT]]{{$}}
15 ; CHECK-NEXT: i32.eqz $push[[EQZ:[0-9]+]]=, $pop[[LT]]{{$}}
16 ; CHECK-NEXT: br_if 0, $pop[[EQZ]]{{$}}
15 ; CHECK-NEXT: br_if 0, $pop[[LT]]{{$}}
16 ; CHECK-NEXT: i32.const $push[[ALT:[0-9]+]]=, -2147483648{{$}}
17 ; CHECK-NEXT: return $pop[[ALT]]{{$}}
18 ; CHECK-NEXT: BB
19 ; CHECK-NEXT: end_block
1720 ; CHECK-NEXT: i32.trunc_s/f32 $push[[NUM:[0-9]+]]=, $0{{$}}
1821 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
19 ; CHECK-NEXT: BB
20 ; CHECK-NEXT: end_block
21 ; CHECK-NEXT: i32.const $push[[ALT:[0-9]+]]=, -2147483648{{$}}
22 ; CHECK-NEXT: return $pop[[ALT]]{{$}}
2322 define i32 @i32_trunc_s_f32(float %x) {
2423 %a = fptosi float %x to i32
2524 ret i32 %a
3130 ; CHECK-NEXT: block
3231 ; CHECK-NEXT: f32.const $push[[LIMIT:[0-9]+]]=, 0x1p32{{$}}
3332 ; CHECK-NEXT: f32.lt $push[[LT:[0-9]+]]=, $0, $pop[[LIMIT]]{{$}}
34 ; CHECK-NEXT: i32.eqz $push[[EQZ:[0-9]+]]=, $pop[[LT]]{{$}}
35 ; CHECK-NEXT: br_if 0, $pop[[EQZ]]{{$}}
33 ; CHECK-NEXT: f32.const $push[[ZERO:[0-9]+]]=, 0x0p0{{$}}
34 ; CHECK-NEXT: f32.ge $push[[GE:[0-9]+]]=, $0, $pop[[ZERO]]{{$}}
35 ; CHECK-NEXT: i32.and $push[[AND:[0-9]+]]=, $pop[[LT]], $pop[[GE]]{{$}}
36 ; CHECK-NEXT: br_if 0, $pop[[AND]]{{$}}
37 ; CHECK-NEXT: i32.const $push[[ALT:[0-9]+]]=, 0{{$}}
38 ; CHECK-NEXT: return $pop[[ALT]]{{$}}
39 ; CHECK-NEXT: BB
40 ; CHECK-NEXT: end_block
3641 ; CHECK-NEXT: i32.trunc_u/f32 $push[[NUM:[0-9]+]]=, $0{{$}}
3742 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
38 ; CHECK-NEXT: BB
39 ; CHECK-NEXT: end_block
40 ; CHECK-NEXT: i32.const $push[[ALT:[0-9]+]]=, 0{{$}}
41 ; CHECK-NEXT: return $pop[[ALT]]{{$}}
4243 define i32 @i32_trunc_u_f32(float %x) {
4344 %a = fptoui float %x to i32
4445 ret i32 %a
5152 ; CHECK-NEXT: f64.abs $push[[ABS:[0-9]+]]=, $0{{$}}
5253 ; CHECK-NEXT: f64.const $push[[LIMIT:[0-9]+]]=, 0x1p31{{$}}
5354 ; CHECK-NEXT: f64.lt $push[[LT:[0-9]+]]=, $pop[[ABS]], $pop[[LIMIT]]{{$}}
54 ; CHECK-NEXT: i32.eqz $push[[EQZ:[0-9]+]]=, $pop[[LT]]{{$}}
55 ; CHECK-NEXT: br_if 0, $pop[[EQZ]]{{$}}
55 ; CHECK-NEXT: br_if 0, $pop[[LT]]{{$}}
56 ; CHECK-NEXT: i32.const $push[[ALT:[0-9]+]]=, -2147483648{{$}}
57 ; CHECK-NEXT: return $pop[[ALT]]{{$}}
58 ; CHECK-NEXT: BB
59 ; CHECK-NEXT: end_block
5660 ; CHECK-NEXT: i32.trunc_s/f64 $push[[NUM:[0-9]+]]=, $0{{$}}
5761 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
58 ; CHECK-NEXT: BB
59 ; CHECK-NEXT: end_block
60 ; CHECK-NEXT: i32.const $push[[ALT:[0-9]+]]=, -2147483648{{$}}
61 ; CHECK-NEXT: return $pop[[ALT]]{{$}}
6262 define i32 @i32_trunc_s_f64(double %x) {
6363 %a = fptosi double %x to i32
6464 ret i32 %a
7070 ; CHECK-NEXT: block
7171 ; CHECK-NEXT: f64.const $push[[LIMIT:[0-9]+]]=, 0x1p32{{$}}
7272 ; CHECK-NEXT: f64.lt $push[[LT:[0-9]+]]=, $0, $pop[[LIMIT]]{{$}}
73 ; CHECK-NEXT: i32.eqz $push[[EQZ:[0-9]+]]=, $pop[[LT]]{{$}}
74 ; CHECK-NEXT: br_if 0, $pop[[EQZ]]{{$}}
73 ; CHECK-NEXT: f64.const $push[[ZERO:[0-9]+]]=, 0x0p0{{$}}
74 ; CHECK-NEXT: f64.ge $push[[GE:[0-9]+]]=, $0, $pop[[ZERO]]{{$}}
75 ; CHECK-NEXT: i32.and $push[[AND:[0-9]+]]=, $pop[[LT]], $pop[[GE]]{{$}}
76 ; CHECK-NEXT: br_if 0, $pop[[AND]]{{$}}
77 ; CHECK-NEXT: i32.const $push[[ALT:[0-9]+]]=, 0{{$}}
78 ; CHECK-NEXT: return $pop[[ALT]]{{$}}
79 ; CHECK-NEXT: BB
80 ; CHECK-NEXT: end_block
7581 ; CHECK-NEXT: i32.trunc_u/f64 $push[[NUM:[0-9]+]]=, $0{{$}}
7682 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
77 ; CHECK-NEXT: BB
78 ; CHECK-NEXT: end_block
79 ; CHECK-NEXT: i32.const $push[[ALT:[0-9]+]]=, 0{{$}}
80 ; CHECK-NEXT: return $pop[[ALT]]{{$}}
8183 define i32 @i32_trunc_u_f64(double %x) {
8284 %a = fptoui double %x to i32
8385 ret i32 %a
9092 ; CHECK-NEXT: f32.abs $push[[ABS:[0-9]+]]=, $0{{$}}
9193 ; CHECK-NEXT: f32.const $push[[LIMIT:[0-9]+]]=, 0x1p63{{$}}
9294 ; CHECK-NEXT: f32.lt $push[[LT:[0-9]+]]=, $pop[[ABS]], $pop[[LIMIT]]{{$}}
93 ; CHECK-NEXT: i32.eqz $push[[EQZ:[0-9]+]]=, $pop[[LT]]{{$}}
94 ; CHECK-NEXT: br_if 0, $pop[[EQZ]]{{$}}
95 ; CHECK-NEXT: br_if 0, $pop[[LT]]{{$}}
96 ; CHECK-NEXT: i64.const $push[[ALT:[0-9]+]]=, -9223372036854775808{{$}}
97 ; CHECK-NEXT: return $pop[[ALT]]{{$}}
98 ; CHECK-NEXT: BB
99 ; CHECK-NEXT: end_block
95100 ; CHECK-NEXT: i64.trunc_s/f32 $push[[NUM:[0-9]+]]=, $0{{$}}
96101 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
97 ; CHECK-NEXT: BB
98 ; CHECK-NEXT: end_block
99 ; CHECK-NEXT: i64.const $push[[ALT:[0-9]+]]=, -9223372036854775808{{$}}
100 ; CHECK-NEXT: return $pop[[ALT]]{{$}}
101102 define i64 @i64_trunc_s_f32(float %x) {
102103 %a = fptosi float %x to i64
103104 ret i64 %a
109110 ; CHECK-NEXT: block
110111 ; CHECK-NEXT: f32.const $push[[LIMIT:[0-9]+]]=, 0x1p64{{$}}
111112 ; CHECK-NEXT: f32.lt $push[[LT:[0-9]+]]=, $0, $pop[[LIMIT]]{{$}}
112 ; CHECK-NEXT: i32.eqz $push[[EQZ:[0-9]+]]=, $pop[[LT]]{{$}}
113 ; CHECK-NEXT: br_if 0, $pop[[EQZ]]{{$}}
113 ; CHECK-NEXT: f32.const $push[[ZERO:[0-9]+]]=, 0x0p0{{$}}
114 ; CHECK-NEXT: f32.ge $push[[GE:[0-9]+]]=, $0, $pop[[ZERO]]{{$}}
115 ; CHECK-NEXT: i32.and $push[[AND:[0-9]+]]=, $pop[[LT]], $pop[[GE]]{{$}}
116 ; CHECK-NEXT: br_if 0, $pop[[AND]]{{$}}
117 ; CHECK-NEXT: i64.const $push[[ALT:[0-9]+]]=, 0{{$}}
118 ; CHECK-NEXT: return $pop[[ALT]]{{$}}
119 ; CHECK-NEXT: BB
120 ; CHECK-NEXT: end_block
114121 ; CHECK-NEXT: i64.trunc_u/f32 $push[[NUM:[0-9]+]]=, $0{{$}}
115122 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
116 ; CHECK-NEXT: BB
117 ; CHECK-NEXT: end_block
118 ; CHECK-NEXT: i64.const $push[[ALT:[0-9]+]]=, 0{{$}}
119 ; CHECK-NEXT: return $pop[[ALT]]{{$}}
120123 define i64 @i64_trunc_u_f32(float %x) {
121124 %a = fptoui float %x to i64
122125 ret i64 %a
129132 ; CHECK-NEXT: f64.abs $push[[ABS:[0-9]+]]=, $0{{$}}
130133 ; CHECK-NEXT: f64.const $push[[LIMIT:[0-9]+]]=, 0x1p63{{$}}
131134 ; CHECK-NEXT: f64.lt $push[[LT:[0-9]+]]=, $pop[[ABS]], $pop[[LIMIT]]{{$}}
132 ; CHECK-NEXT: i32.eqz $push[[EQZ:[0-9]+]]=, $pop[[LT]]{{$}}
133 ; CHECK-NEXT: br_if 0, $pop[[EQZ]]{{$}}
135 ; CHECK-NEXT: br_if 0, $pop[[LT]]{{$}}
136 ; CHECK-NEXT: i64.const $push[[ALT:[0-9]+]]=, -9223372036854775808{{$}}
137 ; CHECK-NEXT: return $pop[[ALT]]{{$}}
138 ; CHECK-NEXT: BB
139 ; CHECK-NEXT: end_block
134140 ; CHECK-NEXT: i64.trunc_s/f64 $push[[NUM:[0-9]+]]=, $0{{$}}
135141 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
136 ; CHECK-NEXT: BB
137 ; CHECK-NEXT: end_block
138 ; CHECK-NEXT: i64.const $push[[ALT:[0-9]+]]=, -9223372036854775808{{$}}
139 ; CHECK-NEXT: return $pop[[ALT]]{{$}}
140142 define i64 @i64_trunc_s_f64(double %x) {
141143 %a = fptosi double %x to i64
142144 ret i64 %a
148150 ; CHECK-NEXT: block
149151 ; CHECK-NEXT: f64.const $push[[LIMIT:[0-9]+]]=, 0x1p64{{$}}
150152 ; CHECK-NEXT: f64.lt $push[[LT:[0-9]+]]=, $0, $pop[[LIMIT]]{{$}}
151 ; CHECK-NEXT: i32.eqz $push[[EQZ:[0-9]+]]=, $pop[[LT]]{{$}}
152 ; CHECK-NEXT: br_if 0, $pop[[EQZ]]{{$}}
153 ; CHECK-NEXT: f64.const $push[[ZERO:[0-9]+]]=, 0x0p0{{$}}
154 ; CHECK-NEXT: f64.ge $push[[GE:[0-9]+]]=, $0, $pop[[ZERO]]{{$}}
155 ; CHECK-NEXT: i32.and $push[[AND:[0-9]+]]=, $pop[[LT]], $pop[[GE]]{{$}}
156 ; CHECK-NEXT: br_if 0, $pop[[AND]]{{$}}
157 ; CHECK-NEXT: i64.const $push[[ALT:[0-9]+]]=, 0{{$}}
158 ; CHECK-NEXT: return $pop[[ALT]]{{$}}
159 ; CHECK-NEXT: BB
160 ; CHECK-NEXT: end_block
153161 ; CHECK-NEXT: i64.trunc_u/f64 $push[[NUM:[0-9]+]]=, $0{{$}}
154162 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
155 ; CHECK-NEXT: BB
156 ; CHECK-NEXT: end_block
157 ; CHECK-NEXT: i64.const $push[[ALT:[0-9]+]]=, 0{{$}}
158 ; CHECK-NEXT: return $pop[[ALT]]{{$}}
159163 define i64 @i64_trunc_u_f64(double %x) {
160164 %a = fptoui double %x to i64
161165 ret i64 %a