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;
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 {
}
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;
; 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
; 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
; 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
; 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
; 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
; 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
; 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
; 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