x64: port select to ISLE (#3682)
* x64: port `select` using an FP comparison to ISLE This change includes quite a few interlocking parts, required mainly by the current x64 conventions in ISLE: - it adds a way to emit a `cmove` with multiple OR-ing conditions; because x64 ISLE cannot currently safely emit a comparison followed by several jumps, this adds `MachInst::CmoveOr` and `MachInst::XmmCmoveOr` macro instructions. Unfortunately, these macro instructions hide the multi-instruction sequence in `lower.isle` - to properly keep track of what instructions consume and produce flags, @cfallin added a way to pass around variants of `ConsumesFlags` and `ProducesFlags`--these changes affect all backends - then, to lower the `fcmp + select` CLIF, this change adds several `cmove*_from_values` helpers that perform all of the awkward conversions between `Value`, `ValueReg`, `Reg`, and `Gpr/Xmm`; one upside is that now these lowerings have much-improved documentation explaining why the various `FloatCC` and `CC` choices are made the the way they are. Co-authored-by: Chris Fallin <chris@cfallin.org>
This commit is contained in:
@@ -324,47 +324,79 @@
|
||||
|
||||
;; Newtype wrapper around `MInst` for instructions that are used for their
|
||||
;; effect on flags.
|
||||
(type ProducesFlags (enum (ProducesFlags (inst MInst) (result Reg))))
|
||||
;;
|
||||
;; Variant determines how result is given when combined with a
|
||||
;; ConsumesFlags. See `with_flags` below for more.
|
||||
(type ProducesFlags (enum
|
||||
(ProducesFlagsSideEffect (inst MInst))
|
||||
;; Not directly combinable with a ConsumesFlags;
|
||||
;; used in s390x and unwrapped directly by `trapif`.
|
||||
(ProducesFlagsReturnsReg (inst MInst) (result Reg))
|
||||
(ProducesFlagsReturnsResultWithConsumer (inst MInst) (result Reg))))
|
||||
|
||||
;; Newtype wrapper around `MInst` for instructions that consume flags.
|
||||
(type ConsumesFlags (enum (ConsumesFlags (inst MInst) (result Reg))))
|
||||
;;
|
||||
;; Variant determines how result is given when combined with a
|
||||
;; ProducesFlags. See `with_flags` below for more.
|
||||
(type ConsumesFlags (enum
|
||||
(ConsumesFlagsReturnsResultWithProducer (inst MInst) (result Reg))
|
||||
(ConsumesFlagsReturnsReg (inst MInst) (result Reg))
|
||||
(ConsumesFlagsTwiceReturnsValueRegs (inst1 MInst)
|
||||
(inst2 MInst)
|
||||
(result ValueRegs))))
|
||||
|
||||
|
||||
;; Helper for combining two flags-consumer instructions that return a
|
||||
;; single Reg, giving a ConsumesFlags that returns both values in a
|
||||
;; ValueRegs.
|
||||
(decl consumes_flags_concat (ConsumesFlags ConsumesFlags) ConsumesFlags)
|
||||
(rule (consumes_flags_concat (ConsumesFlags.ConsumesFlagsReturnsReg inst1 reg1)
|
||||
(ConsumesFlags.ConsumesFlagsReturnsReg inst2 reg2))
|
||||
(ConsumesFlags.ConsumesFlagsTwiceReturnsValueRegs
|
||||
inst1
|
||||
inst2
|
||||
(value_regs reg1 reg2)))
|
||||
|
||||
;; Combine flags-producing and -consuming instructions together, ensuring that
|
||||
;; they are emitted back-to-back and no other instructions can be emitted
|
||||
;; between them and potentially clobber the flags.
|
||||
;;
|
||||
;; Returns a `ValueRegs` where the first register is the result of the
|
||||
;; `ProducesFlags` instruction and the second is the result of the
|
||||
;; `ConsumesFlags` instruction.
|
||||
;; Returns a `ValueRegs` according to the specific combination of ProducesFlags and ConsumesFlags modes:
|
||||
;; - SideEffect + ReturnsReg --> ValueReg with one Reg from consumer
|
||||
;; - SideEffect + ReturnsValueRegs --> ValueReg as given from consumer
|
||||
;; - ReturnsResultWithProducer + ReturnsResultWithConsumer --> ValueReg with low part from producer, high part from consumer
|
||||
;;
|
||||
;; See `with_flags_reg` below for a variant that extracts out just the lower Reg.
|
||||
(decl with_flags (ProducesFlags ConsumesFlags) ValueRegs)
|
||||
(rule (with_flags (ProducesFlags.ProducesFlags producer_inst producer_result)
|
||||
(ConsumesFlags.ConsumesFlags consumer_inst consumer_result))
|
||||
|
||||
(rule (with_flags (ProducesFlags.ProducesFlagsReturnsResultWithConsumer producer_inst producer_result)
|
||||
(ConsumesFlags.ConsumesFlagsReturnsResultWithProducer consumer_inst consumer_result))
|
||||
(let ((_x Unit (emit producer_inst))
|
||||
(_y Unit (emit consumer_inst)))
|
||||
(value_regs producer_result consumer_result)))
|
||||
|
||||
;; Like `with_flags` but returns only the result of the consumer operation.
|
||||
(decl with_flags_1 (ProducesFlags ConsumesFlags) Reg)
|
||||
(rule (with_flags_1 (ProducesFlags.ProducesFlags producer_inst _producer_result)
|
||||
(ConsumesFlags.ConsumesFlags consumer_inst consumer_result))
|
||||
(rule (with_flags (ProducesFlags.ProducesFlagsSideEffect producer_inst)
|
||||
(ConsumesFlags.ConsumesFlagsReturnsReg consumer_inst consumer_result))
|
||||
(let ((_x Unit (emit producer_inst))
|
||||
(_y Unit (emit consumer_inst)))
|
||||
consumer_result))
|
||||
(value_reg consumer_result)))
|
||||
|
||||
;; Like `with_flags` but allows two consumers of the same flags. The result is a
|
||||
;; `ValueRegs` containing the first consumer's result and then the second
|
||||
;; consumer's result.
|
||||
(decl with_flags_2 (ProducesFlags ConsumesFlags ConsumesFlags) ValueRegs)
|
||||
(rule (with_flags_2 (ProducesFlags.ProducesFlags producer_inst _producer_result)
|
||||
(ConsumesFlags.ConsumesFlags consumer_inst_1 consumer_result_1)
|
||||
(ConsumesFlags.ConsumesFlags consumer_inst_2 consumer_result_2))
|
||||
(rule (with_flags (ProducesFlags.ProducesFlagsSideEffect producer_inst)
|
||||
(ConsumesFlags.ConsumesFlagsTwiceReturnsValueRegs consumer_inst_1
|
||||
consumer_inst_2
|
||||
consumer_result))
|
||||
(let ((_x Unit (emit producer_inst))
|
||||
;; Note that the order of emission here is swapped, as this seems
|
||||
;; to generate better register allocation for now with fewer
|
||||
;; `mov` instructions.
|
||||
(_y Unit (emit consumer_inst_2))
|
||||
(_z Unit (emit consumer_inst_1)))
|
||||
(value_regs consumer_result_1 consumer_result_2)))
|
||||
consumer_result))
|
||||
|
||||
(decl with_flags_reg (ProducesFlags ConsumesFlags) Reg)
|
||||
(rule (with_flags_reg p c)
|
||||
(let ((v ValueRegs (with_flags p c)))
|
||||
(value_regs_get v 0)))
|
||||
|
||||
;;;; Helpers for Working with TrapCode ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user