From: Dan Gohman Date: Wed, 29 Nov 2017 20:20:11 +0000 (+0000) Subject: [WebAssembly] Fix fptoui lowering bounds X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=685c102164544ca0d08ac37f049fef441ab64d07;p=llvm [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 --- diff --git a/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp b/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp index 79e5e14764e..c6f1a663a4f 100644 --- a/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp +++ b/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp @@ -207,7 +207,10 @@ LowerFPToInt( unsigned Abs = Float64 ? WebAssembly::ABS_F64 : WebAssembly::ABS_F32; unsigned FConst = Float64 ? WebAssembly::CONST_F64 : WebAssembly::CONST_F32; unsigned LT = Float64 ? WebAssembly::LT_F64 : WebAssembly::LT_F32; + unsigned GE = Float64 ? WebAssembly::GE_F64 : WebAssembly::GE_F32; unsigned IConst = Int64 ? WebAssembly::CONST_I64 : WebAssembly::CONST_I32; + unsigned Eqz = WebAssembly::EQZ_I32; + unsigned And = WebAssembly::AND_I32; int64_t Limit = Int64 ? INT64_MIN : INT32_MIN; int64_t Substitute = IsUnsigned ? 0 : Limit; double CmpVal = IsUnsigned ? -(double)Limit * 2.0 : -(double)Limit; @@ -236,14 +239,17 @@ LowerFPToInt( TrueMBB->addSuccessor(DoneMBB); FalseMBB->addSuccessor(DoneMBB); - unsigned Tmp0, Tmp1, Tmp2, Tmp3, Tmp4; + unsigned Tmp0, Tmp1, CmpReg, EqzReg, FalseReg, TrueReg; Tmp0 = MRI.createVirtualRegister(MRI.getRegClass(InReg)); Tmp1 = MRI.createVirtualRegister(MRI.getRegClass(InReg)); - Tmp2 = MRI.createVirtualRegister(&WebAssembly::I32RegClass); - Tmp3 = MRI.createVirtualRegister(MRI.getRegClass(OutReg)); - Tmp4 = MRI.createVirtualRegister(MRI.getRegClass(OutReg)); + CmpReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass); + EqzReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass); + FalseReg = MRI.createVirtualRegister(MRI.getRegClass(OutReg)); + TrueReg = MRI.createVirtualRegister(MRI.getRegClass(OutReg)); MI.eraseFromParent(); + // For signed numbers, we can do a single comparison to determine whether + // fabs(x) is within range. if (IsUnsigned) { Tmp0 = InReg; } else { @@ -252,24 +258,44 @@ LowerFPToInt( } BuildMI(BB, DL, TII.get(FConst), Tmp1) .addFPImm(cast(ConstantFP::get(Ty, CmpVal))); - BuildMI(BB, DL, TII.get(LT), Tmp2) + BuildMI(BB, DL, TII.get(LT), CmpReg) .addReg(Tmp0) .addReg(Tmp1); + + // For unsigned numbers, we have to do a separate comparison with zero. + if (IsUnsigned) { + Tmp1 = MRI.createVirtualRegister(MRI.getRegClass(InReg)); + unsigned SecondCmpReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass); + unsigned AndReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass); + BuildMI(BB, DL, TII.get(FConst), Tmp1) + .addFPImm(cast(ConstantFP::get(Ty, 0.0))); + BuildMI(BB, DL, TII.get(GE), SecondCmpReg) + .addReg(Tmp0) + .addReg(Tmp1); + BuildMI(BB, DL, TII.get(And), AndReg) + .addReg(CmpReg) + .addReg(SecondCmpReg); + CmpReg = AndReg; + } + + BuildMI(BB, DL, TII.get(Eqz), EqzReg) + .addReg(CmpReg); + + // Create the CFG diamond to select between doing the conversion or using + // the substitute value. BuildMI(BB, DL, TII.get(WebAssembly::BR_IF)) .addMBB(TrueMBB) - .addReg(Tmp2); - - BuildMI(FalseMBB, DL, TII.get(IConst), Tmp3) - .addImm(Substitute); + .addReg(EqzReg); + BuildMI(FalseMBB, DL, TII.get(LoweredOpcode), FalseReg) + .addReg(InReg); BuildMI(FalseMBB, DL, TII.get(WebAssembly::BR)) .addMBB(DoneMBB); - BuildMI(TrueMBB, DL, TII.get(LoweredOpcode), Tmp4) - .addReg(InReg); - + BuildMI(TrueMBB, DL, TII.get(IConst), TrueReg) + .addImm(Substitute); BuildMI(*DoneMBB, DoneMBB->begin(), DL, TII.get(TargetOpcode::PHI), OutReg) - .addReg(Tmp3) + .addReg(FalseReg) .addMBB(FalseMBB) - .addReg(Tmp4) + .addReg(TrueReg) .addMBB(TrueMBB); return DoneMBB; diff --git a/lib/Target/WebAssembly/WebAssemblyLowerBrUnless.cpp b/lib/Target/WebAssembly/WebAssemblyLowerBrUnless.cpp index 576b71dd796..5b867aa763a 100644 --- a/lib/Target/WebAssembly/WebAssemblyLowerBrUnless.cpp +++ b/lib/Target/WebAssembly/WebAssemblyLowerBrUnless.cpp @@ -99,6 +99,13 @@ bool WebAssemblyLowerBrUnless::runOnMachineFunction(MachineFunction &MF) { case NE_F32: Def->setDesc(TII.get(EQ_F32)); Inverted = true; break; case EQ_F64: Def->setDesc(TII.get(NE_F64)); Inverted = true; break; case NE_F64: Def->setDesc(TII.get(EQ_F64)); Inverted = true; break; + case EQZ_I32: { + // Invert an eqz by replacing it with its operand. + Cond = Def->getOperand(1).getReg(); + Def->eraseFromParent(); + Inverted = true; + break; + } default: break; } } diff --git a/test/CodeGen/WebAssembly/conv-trap.ll b/test/CodeGen/WebAssembly/conv-trap.ll index 160d893d74c..e20ed0a4527 100644 --- a/test/CodeGen/WebAssembly/conv-trap.ll +++ b/test/CodeGen/WebAssembly/conv-trap.ll @@ -13,14 +13,13 @@ target triple = "wasm32-unknown-unknown-wasm" ; 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: br_if 0, $pop[[LT]]{{$}} ; CHECK-NEXT: i32.const $push[[ALT:[0-9]+]]=, -2147483648{{$}} ; CHECK-NEXT: return $pop[[ALT]]{{$}} +; CHECK-NEXT: BB +; CHECK-NEXT: end_block +; CHECK-NEXT: i32.trunc_s/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 ret i32 %a @@ -32,14 +31,16 @@ define i32 @i32_trunc_s_f32(float %x) { ; 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: f32.const $push[[ZERO:[0-9]+]]=, 0x0p0{{$}} +; CHECK-NEXT: f32.ge $push[[GE:[0-9]+]]=, $0, $pop[[ZERO]]{{$}} +; CHECK-NEXT: i32.and $push[[AND:[0-9]+]]=, $pop[[LT]], $pop[[GE]]{{$}} +; CHECK-NEXT: br_if 0, $pop[[AND]]{{$}} ; CHECK-NEXT: i32.const $push[[ALT:[0-9]+]]=, 0{{$}} ; CHECK-NEXT: return $pop[[ALT]]{{$}} +; CHECK-NEXT: BB +; CHECK-NEXT: end_block +; CHECK-NEXT: i32.trunc_u/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 ret i32 %a @@ -52,14 +53,13 @@ define i32 @i32_trunc_u_f32(float %x) { ; 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: br_if 0, $pop[[LT]]{{$}} ; CHECK-NEXT: i32.const $push[[ALT:[0-9]+]]=, -2147483648{{$}} ; CHECK-NEXT: return $pop[[ALT]]{{$}} +; CHECK-NEXT: BB +; CHECK-NEXT: end_block +; CHECK-NEXT: i32.trunc_s/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 ret i32 %a @@ -71,14 +71,16 @@ define i32 @i32_trunc_s_f64(double %x) { ; 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: f64.const $push[[ZERO:[0-9]+]]=, 0x0p0{{$}} +; CHECK-NEXT: f64.ge $push[[GE:[0-9]+]]=, $0, $pop[[ZERO]]{{$}} +; CHECK-NEXT: i32.and $push[[AND:[0-9]+]]=, $pop[[LT]], $pop[[GE]]{{$}} +; CHECK-NEXT: br_if 0, $pop[[AND]]{{$}} ; CHECK-NEXT: i32.const $push[[ALT:[0-9]+]]=, 0{{$}} ; CHECK-NEXT: return $pop[[ALT]]{{$}} +; CHECK-NEXT: BB +; CHECK-NEXT: end_block +; CHECK-NEXT: i32.trunc_u/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 ret i32 %a @@ -91,14 +93,13 @@ define i32 @i32_trunc_u_f64(double %x) { ; 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: br_if 0, $pop[[LT]]{{$}} ; CHECK-NEXT: i64.const $push[[ALT:[0-9]+]]=, -9223372036854775808{{$}} ; CHECK-NEXT: return $pop[[ALT]]{{$}} +; CHECK-NEXT: BB +; CHECK-NEXT: end_block +; CHECK-NEXT: i64.trunc_s/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 ret i64 %a @@ -110,14 +111,16 @@ define i64 @i64_trunc_s_f32(float %x) { ; 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: f32.const $push[[ZERO:[0-9]+]]=, 0x0p0{{$}} +; CHECK-NEXT: f32.ge $push[[GE:[0-9]+]]=, $0, $pop[[ZERO]]{{$}} +; CHECK-NEXT: i32.and $push[[AND:[0-9]+]]=, $pop[[LT]], $pop[[GE]]{{$}} +; CHECK-NEXT: br_if 0, $pop[[AND]]{{$}} ; CHECK-NEXT: i64.const $push[[ALT:[0-9]+]]=, 0{{$}} ; CHECK-NEXT: return $pop[[ALT]]{{$}} +; CHECK-NEXT: BB +; CHECK-NEXT: end_block +; CHECK-NEXT: i64.trunc_u/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 ret i64 %a @@ -130,14 +133,13 @@ define i64 @i64_trunc_u_f32(float %x) { ; 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: br_if 0, $pop[[LT]]{{$}} ; CHECK-NEXT: i64.const $push[[ALT:[0-9]+]]=, -9223372036854775808{{$}} ; CHECK-NEXT: return $pop[[ALT]]{{$}} +; CHECK-NEXT: BB +; CHECK-NEXT: end_block +; CHECK-NEXT: i64.trunc_s/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 ret i64 %a @@ -149,14 +151,16 @@ define i64 @i64_trunc_s_f64(double %x) { ; 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: f64.const $push[[ZERO:[0-9]+]]=, 0x0p0{{$}} +; CHECK-NEXT: f64.ge $push[[GE:[0-9]+]]=, $0, $pop[[ZERO]]{{$}} +; CHECK-NEXT: i32.and $push[[AND:[0-9]+]]=, $pop[[LT]], $pop[[GE]]{{$}} +; CHECK-NEXT: br_if 0, $pop[[AND]]{{$}} ; CHECK-NEXT: i64.const $push[[ALT:[0-9]+]]=, 0{{$}} ; CHECK-NEXT: return $pop[[ALT]]{{$}} +; CHECK-NEXT: BB +; CHECK-NEXT: end_block +; CHECK-NEXT: i64.trunc_u/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 ret i64 %a