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:
@@ -633,15 +633,26 @@
|
||||
|
||||
;;;; Rules for `rotl` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
;; `i64` and smaller.
|
||||
;; `i16` and `i8`: we need to extend the shift amount, or mask the
|
||||
;; constant.
|
||||
|
||||
(rule (lower (has_type (fits_in_64 ty) (rotl src amt)))
|
||||
(rule (lower (has_type (ty_8_or_16 ty) (rotl src amt)))
|
||||
(let ((amt_ Reg (extend_to_reg amt $I32 (ExtendKind.Zero))))
|
||||
(value_reg (m_rotl ty (put_in_reg src) (Imm8Reg.Reg amt_)))))
|
||||
|
||||
(rule (lower (has_type (ty_8_or_16 ty) (rotl src (imm8_from_value amt))))
|
||||
(value_reg (m_rotl ty (put_in_reg src) (mask_imm8_const amt (ty_bits_mask ty)))))
|
||||
|
||||
;; `i64` and `i32`: we can rely on x86's rotate-amount masking since
|
||||
;; we operate on the whole register.
|
||||
|
||||
(rule (lower (has_type (ty_32_or_64 ty) (rotl src amt)))
|
||||
;; NB: Only the low bits of `amt` matter since we logically mask the
|
||||
;; shift amount to the value's bit width.
|
||||
(let ((amt_ Reg (lo_reg amt)))
|
||||
(value_reg (m_rotl ty (put_in_reg src) (Imm8Reg.Reg amt_)))))
|
||||
|
||||
(rule (lower (has_type (fits_in_64 ty) (rotl src (imm8_from_value amt))))
|
||||
(rule (lower (has_type (ty_32_or_64 ty) (rotl src (imm8_from_value amt))))
|
||||
(value_reg (m_rotl ty (put_in_reg src) amt)))
|
||||
|
||||
;; `i128`.
|
||||
|
||||
Reference in New Issue
Block a user