Fix some 16- and 8-bit behavior in x64 backend related to rotates.

Uncovered by @bjorn3 (thanks!): 8- and 16-bit rotates were not working
properly in recent versions of Cranelift with part of the lowering
migrated to ISLE.

This PR fixes a few issues:

- 8- and 16-bit rotate-left needs to mask a constant amount, if any,
  because we use a 32-bit rotate instruction and so don't get the
  appropriate shift-amount masking for free from x86 semantics.

- `operand_size_from_type` was incorrect: it only handled 32- and 64-bit
  types and silently returned `OperandSize::Size32` for everything else.
  Now uses the `OperandSize::from_ty(ty)` helper as the pre-ISLE code
  did.

Our test coverage for narrow value types is not great; this PR adds some
runtests for rotl/rotr but more would always be better!
This commit is contained in:
Chris Fallin
2021-12-16 11:34:24 -08:00
parent d29b7c8a59
commit 1323ae417e
10 changed files with 352 additions and 229 deletions

View File

@@ -57,11 +57,7 @@ where
#[inline]
fn operand_size_of_type(&mut self, ty: Type) -> OperandSize {
if ty.bits() == 64 {
OperandSize::Size64
} else {
OperandSize::Size32
}
OperandSize::from_ty(ty)
}
fn put_in_reg_mem(&mut self, val: Value) -> RegMem {
@@ -125,6 +121,16 @@ where
Some(Imm8Reg::Imm8 { imm })
}
#[inline]
fn mask_imm8_const(&mut self, imm8: &Imm8Reg, mask: u64) -> Imm8Reg {
match imm8 {
&Imm8Reg::Reg { reg } => Imm8Reg::Reg { reg },
&Imm8Reg::Imm8 { imm } => Imm8Reg::Imm8 {
imm: imm & (mask as u8),
},
}
}
#[inline]
fn simm32_from_value(&mut self, val: Value) -> Option<RegMemImm> {
let inst = self.lower_ctx.dfg().value_def(val).inst()?;