mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-10-19 19:12:56 +02:00
[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. llvm-svn: 319354
This commit is contained in:
parent
d69529fdff
commit
881766b860
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user