Handle srem properly when avoid_div_traps is false.
The codegen for div/rem ops has two modes, depending on the `avoid_div_traps` flag: it can either do all checks for trapping conditions explicitly, and use explicit trap instructions, then use a hardware divide instruction that will not trap (`avoid_div_traps == true`); or it can run in a mode where a hardware FP fault on the divide instruction implies a Wasm trap (`avoid_div_traps == false`). Wasmtime uses the former while Lucet (for example) uses the latter. It turns out that because we run all our spec tests run under Wasmtime, we missed a spec corner case that fails in the latter: INT_MIN % -1 == 0 per the spec, but causes a trap with the x86 signed divide/remainder instruction. Hence, in Lucet, this specific remainder computation would incorrectly result in a Wasm trap. This PR fixes the issue by just forcing use of the explicit-checks implementation for `srem` even when `avoid_div_traps` is false.
This commit is contained in:
@@ -887,7 +887,6 @@ pub(crate) fn emit(
|
||||
// idiv %divisor
|
||||
//
|
||||
// $done:
|
||||
debug_assert!(info.flags().avoid_div_traps());
|
||||
|
||||
// Check if the divisor is zero, first.
|
||||
let inst = Inst::cmp_rmi_r(*size, RegMemImm::imm(0), divisor.to_reg());
|
||||
|
||||
@@ -5181,7 +5181,8 @@ fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
|
||||
input_ty,
|
||||
));
|
||||
|
||||
if flags.avoid_div_traps() {
|
||||
// Always do explicit checks for `srem`: otherwise, INT_MIN % -1 is not handled properly.
|
||||
if flags.avoid_div_traps() || op == Opcode::Srem {
|
||||
// A vcode meta-instruction is used to lower the inline checks, since they embed
|
||||
// pc-relative offsets that must not change, thus requiring regalloc to not
|
||||
// interfere by introducing spills and reloads.
|
||||
|
||||
Reference in New Issue
Block a user