aarch64: Migrate uextend/sextend to ISLE
This commit migrates the sign/zero extension instructions from
`lower_inst.rs` to ISLE. There's actually a fair amount going on in this
migration since a few other pieces needed touching up along the way as
well:
* First is the actual migration of `uextend` and `sextend`. These
instructions are relatively simple but end up having a number of special
cases. I've attempted to replicate all the cases here but
double-checks would be good.
* This commit actually fixes a few issues where if the result of a vector
extraction is sign/zero-extended into i128 that actually results in
panics in the current backend.
* This commit adds exhaustive testing for
extension-of-a-vector-extraction is a noop wrt extraction.
* A bugfix around ISLE glue was required to get this commit working,
notably the case where the `RegMapper` implementation was trying to
map an input to an output (meaning ISLE was passing through an input
unmodified to the output) wasn't working. This requires a `mov`
instruction to be generated and this commit updates the glue to do
this. At the same time this commit updates the ISLE glue to share more
infrastructure between x64 and aarch64 so both backends get this fix
instead of just aarch64.
Overall I think that the translation to ISLE was a net benefit for these
instructions. It's relatively obvious what all the cases are now unlike
before where it took a few reads of the code and some boolean switches
to figure out which path was taken for each flavor of input. I think
there's still possible improvements here where, for example, the
`put_in_reg_{s,z}ext64` helper doesn't use this logic so technically
those helpers could also pattern match the "well atomic loads and vector
extractions automatically do this for us" but that's a possible future
improvement for later (and shouldn't be too too hard with some ISLE
refactoring).
This commit is contained in:
@@ -1515,6 +1515,34 @@
|
||||
(_ Unit (emit (MInst.VecRRLong op dst src high_half))))
|
||||
(writable_reg_to_reg dst)))
|
||||
|
||||
;; Helper for emitting `MInst.MovFromVec` instructions.
|
||||
(decl mov_from_vec (Reg u8 VectorSize) Reg)
|
||||
(rule (mov_from_vec rn idx size)
|
||||
(let ((dst WritableReg (temp_writable_reg $I64))
|
||||
(_ Unit (emit (MInst.MovFromVec dst rn idx size))))
|
||||
(writable_reg_to_reg dst)))
|
||||
|
||||
;; Helper for emitting `MInst.MovFromVecSigned` instructions.
|
||||
(decl mov_from_vec_signed (Reg u8 VectorSize OperandSize) Reg)
|
||||
(rule (mov_from_vec_signed rn idx size scalar_size)
|
||||
(let ((dst WritableReg (temp_writable_reg $I64))
|
||||
(_ Unit (emit (MInst.MovFromVecSigned dst rn idx size scalar_size))))
|
||||
(writable_reg_to_reg dst)))
|
||||
|
||||
;; Helper for emitting `MInst.Extend` instructions.
|
||||
(decl extend (Reg bool u8 u8) Reg)
|
||||
(rule (extend rn signed from_bits to_bits)
|
||||
(let ((dst WritableReg (temp_writable_reg $I64))
|
||||
(_ Unit (emit (MInst.Extend dst rn signed from_bits to_bits))))
|
||||
(writable_reg_to_reg dst)))
|
||||
|
||||
;; Helper for emitting `MInst.LoadAcquire` instructions.
|
||||
(decl load_acquire (Type Reg) Reg)
|
||||
(rule (load_acquire ty addr)
|
||||
(let ((dst WritableReg (temp_writable_reg $I64))
|
||||
(_ Unit (emit (MInst.LoadAcquire ty dst addr))))
|
||||
(writable_reg_to_reg dst)))
|
||||
|
||||
;; Immediate value helpers ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(decl imm (Type u64) Reg)
|
||||
@@ -1543,10 +1571,7 @@
|
||||
;; Place a `Value` into a register, sign extending it to 64-bits
|
||||
(decl put_in_reg_sext64 (Value) Reg)
|
||||
(rule (put_in_reg_sext64 val @ (value_type (fits_in_32 ty)))
|
||||
(let ((dst WritableReg (temp_writable_reg $I32))
|
||||
(src Reg (put_in_reg val))
|
||||
(_ Unit (emit (MInst.Extend dst src $true (ty_bits ty) 64))))
|
||||
(writable_reg_to_reg dst)))
|
||||
(extend (put_in_reg val) $true (ty_bits ty) 64))
|
||||
|
||||
;; 64-bit passthrough.
|
||||
(rule (put_in_reg_sext64 val @ (value_type $I64)) (put_in_reg val))
|
||||
@@ -1554,10 +1579,7 @@
|
||||
;; Place a `Value` into a register, zero extending it to 64-bits
|
||||
(decl put_in_reg_zext64 (Value) Reg)
|
||||
(rule (put_in_reg_zext64 val @ (value_type (fits_in_32 ty)))
|
||||
(let ((dst WritableReg (temp_writable_reg $I32))
|
||||
(src Reg (put_in_reg val))
|
||||
(_ Unit (emit (MInst.Extend dst src $false (ty_bits ty) 64))))
|
||||
(writable_reg_to_reg dst)))
|
||||
(extend (put_in_reg val) $false (ty_bits ty) 64))
|
||||
|
||||
;; 64-bit passthrough.
|
||||
(rule (put_in_reg_zext64 val @ (value_type $I64)) (put_in_reg val))
|
||||
@@ -1599,3 +1621,18 @@
|
||||
(rule (adds_op (fits_in_32 _ty)) (ALUOp.AddS32))
|
||||
(rule (adds_op $I64) (ALUOp.AddS64))
|
||||
|
||||
;; An atomic load that can be sunk into another operation.
|
||||
(type SinkableAtomicLoad extern (enum))
|
||||
|
||||
;; Extract a `SinkableAtomicLoad` that works with `Reg` from a value
|
||||
;; operand.
|
||||
(decl sinkable_atomic_load (SinkableAtomicLoad) Value)
|
||||
(extern extractor sinkable_atomic_load sinkable_atomic_load)
|
||||
|
||||
;; Sink a `SinkableLoad` into a `Reg`.
|
||||
;;
|
||||
;; This is a side-effectful operation that notifies the context that the
|
||||
;; instruction that produced the `SinkableAtomicLoad` has been sunk into another
|
||||
;; instruction, and no longer needs to be lowered.
|
||||
(decl sink_atomic_load (SinkableAtomicLoad) Reg)
|
||||
(extern constructor sink_atomic_load sink_atomic_load)
|
||||
|
||||
Reference in New Issue
Block a user