cranelift: Fix urem/srem in interpreter (#4532)
This commit is contained in:
@@ -1013,4 +1013,26 @@ mod tests {
|
||||
|
||||
assert_eq!(result, vec![DataValue::B(true)])
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn srem_trap() {
|
||||
let code = "function %test() -> i64 {
|
||||
block0:
|
||||
v0 = iconst.i64 0x8000_0000_0000_0000
|
||||
v1 = iconst.i64 -1
|
||||
v2 = srem.i64 v0, v1
|
||||
return v2
|
||||
}";
|
||||
|
||||
let func = parse_functions(code).unwrap().into_iter().next().unwrap();
|
||||
let mut env = FunctionStore::default();
|
||||
env.add(func.name.to_string(), &func);
|
||||
let state = InterpreterState::default().with_function_store(env);
|
||||
let trap = Interpreter::new(state)
|
||||
.call_by_name("%test", &[])
|
||||
.unwrap()
|
||||
.unwrap_trap();
|
||||
|
||||
assert_eq!(trap, CraneliftTrap::User(TrapCode::IntegerOverflow));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -597,9 +597,9 @@ where
|
||||
Opcode::Srem => binary_can_trap(Value::rem, arg(0)?, arg(1)?)?,
|
||||
Opcode::IaddImm => binary(Value::add, arg(0)?, imm_as_ctrl_ty()?)?,
|
||||
Opcode::ImulImm => binary(Value::mul, arg(0)?, imm_as_ctrl_ty()?)?,
|
||||
Opcode::UdivImm => binary_unsigned_can_trap(Value::div, arg(0)?, imm())?,
|
||||
Opcode::UdivImm => binary_unsigned_can_trap(Value::div, arg(0)?, imm_as_ctrl_ty()?)?,
|
||||
Opcode::SdivImm => binary_can_trap(Value::div, arg(0)?, imm_as_ctrl_ty()?)?,
|
||||
Opcode::UremImm => binary_unsigned_can_trap(Value::rem, arg(0)?, imm())?,
|
||||
Opcode::UremImm => binary_unsigned_can_trap(Value::rem, arg(0)?, imm_as_ctrl_ty()?)?,
|
||||
Opcode::SremImm => binary_can_trap(Value::rem, arg(0)?, imm_as_ctrl_ty()?)?,
|
||||
Opcode::IrsubImm => binary(Value::sub, imm_as_ctrl_ty()?, arg(0)?)?,
|
||||
Opcode::IaddCin => choose(
|
||||
|
||||
@@ -529,15 +529,23 @@ impl Value for DataValue {
|
||||
return Err(ValueError::IntegerDivisionByZero);
|
||||
}
|
||||
|
||||
binary_match!(/(&self, &other); [I8, I16, I32, I64, U8, U16, U32, U64])
|
||||
binary_match!(/(&self, &other); [I8, I16, I32, I64, I128, U8, U16, U32, U64, U128])
|
||||
}
|
||||
|
||||
fn rem(self, other: Self) -> ValueResult<Self> {
|
||||
if other.clone().into_int()? == 0 {
|
||||
let denominator = other.clone().into_int()?;
|
||||
|
||||
// Check if we are dividing INT_MIN / -1. This causes an integer overflow trap.
|
||||
let min = Value::int(1i128 << (self.ty().bits() - 1), self.ty())?;
|
||||
if self == min && denominator == -1 {
|
||||
return Err(ValueError::IntegerOverflow);
|
||||
}
|
||||
|
||||
if denominator == 0 {
|
||||
return Err(ValueError::IntegerDivisionByZero);
|
||||
}
|
||||
|
||||
binary_match!(%(&self, &other); [I8, I16, I32, I64])
|
||||
binary_match!(%(&self, &other); [I8, I16, I32, I64, I128, U8, U16, U32, U64, U128])
|
||||
}
|
||||
|
||||
fn sqrt(self) -> ValueResult<Self> {
|
||||
|
||||
Reference in New Issue
Block a user