[llvm] r319354 - [WebAssembly] Fix fptoui lowering bounds

Dan Gohman via llvm-commits llvm-commits at lists.llvm.org
Wed Nov 29 12:20:11 PST 2017


Author: djg
Date: Wed Nov 29 12:20:11 2017
New Revision: 319354

URL: http://llvm.org/viewvc/llvm-project?rev=319354&view=rev
Log:
[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.

Modified:
    llvm/trunk/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
    llvm/trunk/lib/Target/WebAssembly/WebAssemblyLowerBrUnless.cpp
    llvm/trunk/test/CodeGen/WebAssembly/conv-trap.ll

Modified: llvm/trunk/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp?rev=319354&r1=319353&r2=319354&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp (original)
+++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp Wed Nov 29 12:20:11 2017
@@ -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>(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>(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;

Modified: llvm/trunk/lib/Target/WebAssembly/WebAssemblyLowerBrUnless.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/WebAssemblyLowerBrUnless.cpp?rev=319354&r1=319353&r2=319354&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/WebAssemblyLowerBrUnless.cpp (original)
+++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyLowerBrUnless.cpp Wed Nov 29 12:20:11 2017
@@ -99,6 +99,13 @@ bool WebAssemblyLowerBrUnless::runOnMach
         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;
         }
       }

Modified: llvm/trunk/test/CodeGen/WebAssembly/conv-trap.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/WebAssembly/conv-trap.ll?rev=319354&r1=319353&r2=319354&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/WebAssembly/conv-trap.ll (original)
+++ llvm/trunk/test/CodeGen/WebAssembly/conv-trap.ll Wed Nov 29 12:20:11 2017
@@ -13,14 +13,13 @@ target triple = "wasm32-unknown-unknown-
 ; 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




More information about the llvm-commits mailing list