aarch64: Migrate {s,u}{div,rem} to ISLE (#3572)
* aarch64: Migrate {s,u}{div,rem} to ISLE
This commit migrates four different instructions at once to ISLE:
* `sdiv`
* `udiv`
* `srem`
* `urem`
These all share similar codegen and center around the `div` instruction
to use internally. The main feature of these was to model the manual
traps since the `div` instruction doesn't trap on overflow, instead
requiring manual checks to adhere to the semantics of the instruction
itself.
While I was here I went ahead and implemented an optimization for these
instructions when the right-hand-side is a constant with a known value.
For `udiv`, `srem`, and `urem` if the right-hand-side is a nonzero
constant then the checks for traps can be skipped entirely. For `sdiv`
if the constant is not 0 and not -1 then additionally all checks can be
elided. Finally if the right-hand-side of `sdiv` is -1 the zero-check is
elided, but it still needs a check for `i64::MIN` on the left-hand-side
and currently there's a TODO where `-1` is still checked too.
* Rebasing and review conflicts
This commit is contained in:
@@ -1307,6 +1307,12 @@
|
||||
(decl imm12_from_u64 (Imm12) u64)
|
||||
(extern extractor imm12_from_u64 imm12_from_u64)
|
||||
|
||||
(decl u8_into_uimm5 (u8) UImm5)
|
||||
(extern constructor u8_into_uimm5 u8_into_uimm5)
|
||||
|
||||
(decl u8_into_imm12 (u8) Imm12)
|
||||
(extern constructor u8_into_imm12 u8_into_imm12)
|
||||
|
||||
(decl imm12_from_negated_u64 (Imm12) u64)
|
||||
(extern extractor imm12_from_negated_u64 imm12_from_negated_u64)
|
||||
|
||||
@@ -1339,6 +1345,15 @@
|
||||
(decl get_extended_op (ExtendedValue) ExtendOp)
|
||||
(extern constructor get_extended_op get_extended_op)
|
||||
|
||||
(decl nzcv (bool bool bool bool) NZCV)
|
||||
(extern constructor nzcv nzcv)
|
||||
|
||||
(decl cond_br_zero (Reg) CondBrKind)
|
||||
(extern constructor cond_br_zero cond_br_zero)
|
||||
|
||||
(decl cond_br_cond (Cond) CondBrKind)
|
||||
(extern constructor cond_br_cond cond_br_cond)
|
||||
|
||||
;; Instruction creation helpers ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
;; Emit an instruction.
|
||||
@@ -1352,6 +1367,9 @@
|
||||
(decl zero_reg () Reg)
|
||||
(extern constructor zero_reg zero_reg)
|
||||
|
||||
(decl writable_zero_reg () WritableReg)
|
||||
(extern constructor writable_zero_reg writable_zero_reg)
|
||||
|
||||
;; Helper for emitting `MInst.MovZ` instructions.
|
||||
(decl movz (MoveWideConst OperandSize) Reg)
|
||||
(rule (movz imm size)
|
||||
@@ -1543,3 +1561,41 @@
|
||||
|
||||
;; 64-bit passthrough.
|
||||
(rule (put_in_reg_zext64 val @ (value_type $I64)) (put_in_reg val))
|
||||
|
||||
;; Misc instruction helpers ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(decl trap_if_zero_divisor (Reg) Reg)
|
||||
(rule (trap_if_zero_divisor reg)
|
||||
(let ((_ Unit (emit (MInst.TrapIf (cond_br_zero reg) (trap_code_division_by_zero)))))
|
||||
reg))
|
||||
|
||||
(decl size_from_ty (Type) OperandSize)
|
||||
(rule (size_from_ty (fits_in_32 _ty)) (OperandSize.Size32))
|
||||
(rule (size_from_ty $I64) (OperandSize.Size64))
|
||||
|
||||
;; Check for signed overflow. The only case is min_value / -1.
|
||||
;; The following checks must be done in 32-bit or 64-bit, depending
|
||||
;; on the input type.
|
||||
(decl trap_if_div_overflow (Type Reg Reg) Reg)
|
||||
(rule (trap_if_div_overflow ty x y)
|
||||
(let (
|
||||
;; Check RHS is -1.
|
||||
(_1 Unit (emit (MInst.AluRRImm12 (adds_op ty) (writable_zero_reg) y (u8_into_imm12 1))))
|
||||
|
||||
;; Check LHS is min_value, by subtracting 1 and branching if
|
||||
;; there is overflow.
|
||||
(_2 Unit (emit (MInst.CCmpImm (size_from_ty ty)
|
||||
x
|
||||
(u8_into_uimm5 1)
|
||||
(nzcv $false $false $false $false)
|
||||
(Cond.Eq))))
|
||||
(_3 Unit (emit (MInst.TrapIf (cond_br_cond (Cond.Vs))
|
||||
(trap_code_integer_overflow))))
|
||||
)
|
||||
x))
|
||||
|
||||
;; Helper to use either a 32 or 64-bit adds depending on the input type.
|
||||
(decl adds_op (Type) ALUOp)
|
||||
(rule (adds_op (fits_in_32 _ty)) (ALUOp.AddS32))
|
||||
(rule (adds_op $I64) (ALUOp.AddS64))
|
||||
|
||||
|
||||
Reference in New Issue
Block a user