diff --git a/RELEASES.md b/RELEASES.md index 486497a5fec..4ac1ebf9928 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -13,6 +13,14 @@ Released 2022-06-27. including Wasmtime. [regalloc2#60](https://github.com/bytecodealliance/regalloc2/pull/60) +* A bug in the 8-bit lowering of integer division on x86-64 was fixed in + Cranelift that could cause a register allocator panic due to an undefined + value in a register. (The divide instruction does not take a register `rdx` + as a source when 8 bits but the metadata incorrectly claimed it did.) No + impact on Wasm/Wasmtime users, and impact on direct Cranelift embedders + limited to compilation panics. + [#4332](https://github.com/bytecodealliance/wasmtime/pull/4332) + -------------------------------------------------------------------------------- ## 0.38.0 diff --git a/cranelift/codegen/src/isa/x64/inst/emit.rs b/cranelift/codegen/src/isa/x64/inst/emit.rs index 42f08cd669d..2c610adea20 100644 --- a/cranelift/codegen/src/isa/x64/inst/emit.rs +++ b/cranelift/codegen/src/isa/x64/inst/emit.rs @@ -385,13 +385,15 @@ pub(crate) fn emit( dst_remainder, } => { let dividend_lo = allocs.next(dividend_lo.to_reg()); - let dividend_hi = allocs.next(dividend_hi.to_reg()); let dst_quotient = allocs.next(dst_quotient.to_reg().to_reg()); let dst_remainder = allocs.next(dst_remainder.to_reg().to_reg()); debug_assert_eq!(dividend_lo, regs::rax()); - debug_assert_eq!(dividend_hi, regs::rdx()); debug_assert_eq!(dst_quotient, regs::rax()); debug_assert_eq!(dst_remainder, regs::rdx()); + if size.to_bits() > 8 { + let dividend_hi = allocs.next(dividend_hi.to_reg()); + debug_assert_eq!(dividend_hi, regs::rdx()); + } let (opcode, prefix) = match size { OperandSize::Size8 => (0xF6, LegacyPrefixes::None), diff --git a/cranelift/codegen/src/isa/x64/inst/emit_tests.rs b/cranelift/codegen/src/isa/x64/inst/emit_tests.rs index d1e2929c1d7..0cd67bf2c13 100644 --- a/cranelift/codegen/src/isa/x64/inst/emit_tests.rs +++ b/cranelift/codegen/src/isa/x64/inst/emit_tests.rs @@ -1750,12 +1750,12 @@ fn test_x64_emit() { insns.push(( Inst::div(OperandSize::Size8, false, RegMem::reg(regs::rax())), "F6F0", - "div %al, %dl, %al, %al, %dl", + "div %al, (none), %al, %al, %dl", )); insns.push(( Inst::div(OperandSize::Size8, false, RegMem::reg(regs::rsi())), "40F6F6", - "div %al, %dl, %sil, %al, %dl", + "div %al, (none), %sil, %al, %dl", )); // ======================================================== diff --git a/cranelift/codegen/src/isa/x64/inst/mod.rs b/cranelift/codegen/src/isa/x64/inst/mod.rs index a64ad4449d6..78c94f6f065 100644 --- a/cranelift/codegen/src/isa/x64/inst/mod.rs +++ b/cranelift/codegen/src/isa/x64/inst/mod.rs @@ -966,11 +966,15 @@ impl PrettyPrint for Inst { dst_remainder, } => { let dividend_lo = pretty_print_reg(dividend_lo.to_reg(), size.to_bytes(), allocs); - let dividend_hi = pretty_print_reg(dividend_hi.to_reg(), size.to_bytes(), allocs); let dst_quotient = pretty_print_reg(dst_quotient.to_reg().to_reg(), size.to_bytes(), allocs); let dst_remainder = pretty_print_reg(dst_remainder.to_reg().to_reg(), size.to_bytes(), allocs); + let dividend_hi = if size.to_bits() > 8 { + pretty_print_reg(dividend_hi.to_reg(), size.to_bytes(), allocs) + } else { + "(none)".to_string() + }; let divisor = divisor.pretty_print(size.to_bytes(), allocs); format!( "{} {}, {}, {}, {}, {}", @@ -1718,12 +1722,15 @@ fn x64_get_operands VReg>(inst: &Inst, collector: &mut OperandCol dividend_hi, dst_quotient, dst_remainder, + size, .. } => { collector.reg_fixed_use(dividend_lo.to_reg(), regs::rax()); - collector.reg_fixed_use(dividend_hi.to_reg(), regs::rdx()); collector.reg_fixed_def(dst_quotient.to_writable_reg(), regs::rax()); collector.reg_fixed_def(dst_remainder.to_writable_reg(), regs::rdx()); + if size.to_bits() > 8 { + collector.reg_fixed_use(dividend_hi.to_reg(), regs::rdx()); + } divisor.get_operands(collector); } Inst::MulHi {