s390x: Migrate branches and traps to ISLE
In order to migrate branches to ISLE, we define a second entry point `lower_branch` which gets the list of branch targets as additional argument. This requires a small change to `lower_common`: the `isle_lower` callback argument is changed from a function pointer to a closure. This allows passing the extra argument via a closure. Traps make use of the recently added facility to emit safepoints from ISLE, but are otherwise straightforward.
This commit is contained in:
@@ -4,6 +4,11 @@
|
||||
;; register(s) within which the lowered instruction's result values live.
|
||||
(decl lower (Inst) ValueRegs)
|
||||
|
||||
;; A variant of the main lowering constructor term, used for branches.
|
||||
;; The only difference is that it gets an extra argument holding a vector
|
||||
;; of branch targets to be used.
|
||||
(decl lower_branch (Inst VecMachLabel) ValueRegs)
|
||||
|
||||
|
||||
;;;; Rules for `iconst` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
@@ -1778,3 +1783,151 @@
|
||||
(value_reg (select_bool_reg ty (icmp_val $false int_cc x y)
|
||||
(put_in_reg val_true) (put_in_reg val_false))))
|
||||
|
||||
|
||||
;;;; Rules for `jump` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
;; Unconditional branch. The target is found as first (and only) element in
|
||||
;; the list of the current block's branch targets passed as `targets`.
|
||||
(rule (lower_branch (jump _ _) targets)
|
||||
(value_regs_none (jump_impl (vec_element targets 0))))
|
||||
|
||||
|
||||
;;;; Rules for `br_table` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
;; Jump table. `targets` contains the default target followed by the
|
||||
;; list of branch targets per index value.
|
||||
(rule (lower_branch (br_table val_idx _ _) targets)
|
||||
(let ((idx Reg (put_in_reg_zext64 val_idx))
|
||||
;; Bounds-check the index and branch to default.
|
||||
;; This is an internal branch that is not a terminator insn.
|
||||
;; Instead, the default target is listed a potential target
|
||||
;; in the final JTSequence, which is the block terminator.
|
||||
(cond ProducesBool
|
||||
(bool (icmpu_uimm32 $I64 idx (vec_length_minus1 targets))
|
||||
(intcc_as_cond (IntCC.UnsignedGreaterThanOrEqual))))
|
||||
(_ ValueRegs (value_regs_none (oneway_cond_br_bool cond
|
||||
(vec_element targets 0)))))
|
||||
;; Scale the index by the element size, and then emit the
|
||||
;; compound instruction that does:
|
||||
;;
|
||||
;; larl %r1, <jt-base>
|
||||
;; agf %r1, 0(%r1, %rScaledIndex)
|
||||
;; br %r1
|
||||
;; [jt entries]
|
||||
;;
|
||||
;; This must be *one* instruction in the vcode because
|
||||
;; we cannot allow regalloc to insert any spills/fills
|
||||
;; in the middle of the sequence; otherwise, the LARL's
|
||||
;; PC-rel offset to the jumptable would be incorrect.
|
||||
;; (The alternative is to introduce a relocation pass
|
||||
;; for inlined jumptables, which is much worse, IMHO.)
|
||||
(value_regs_none (jt_sequence (lshl_imm $I64 idx 2) targets))))
|
||||
|
||||
|
||||
;;;; Rules for `brz` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
;; Two-way conditional branch on zero. `targets` contains:
|
||||
;; - element 0: target if the condition is true (i.e. value is zero)
|
||||
;; - element 1: target if the condition is false (i.e. value is nonzero)
|
||||
(rule (lower_branch (brz val_cond _ _) targets)
|
||||
(value_regs_none (cond_br_bool (invert_bool (value_nonzero val_cond))
|
||||
(vec_element targets 0)
|
||||
(vec_element targets 1))))
|
||||
|
||||
|
||||
;;;; Rules for `brnz` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
;; Two-way conditional branch on nonzero. `targets` contains:
|
||||
;; - element 0: target if the condition is true (i.e. value is nonzero)
|
||||
;; - element 1: target if the condition is false (i.e. value is zero)
|
||||
(rule (lower_branch (brnz val_cond _ _) targets)
|
||||
(value_regs_none (cond_br_bool (value_nonzero val_cond)
|
||||
(vec_element targets 0)
|
||||
(vec_element targets 1))))
|
||||
|
||||
|
||||
;;;; Rules for `brif` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
;; Similarly to `selectif_spectre_guard`, we only recognize specific patterns
|
||||
;; generated by common code here. Others will fail to lower.
|
||||
|
||||
(rule (lower_branch (brif int_cc (def_inst (ifcmp x y)) _ _) targets)
|
||||
(value_regs_none (cond_br_bool (icmp_val $false int_cc x y)
|
||||
(vec_element targets 0)
|
||||
(vec_element targets 1))))
|
||||
|
||||
|
||||
;;;; Rules for `trap` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(rule (lower (trap trap_code))
|
||||
(safepoint (trap_impl trap_code)))
|
||||
|
||||
|
||||
;;;; Rules for `resumable_trap` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(rule (lower (resumable_trap trap_code))
|
||||
(safepoint (trap_impl trap_code)))
|
||||
|
||||
|
||||
;;;; Rules for `trapz` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(rule (lower (trapz val trap_code))
|
||||
(safepoint (trap_if_bool (invert_bool (value_nonzero val)) trap_code)))
|
||||
|
||||
|
||||
;;;; Rules for `trapnz` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(rule (lower (trapnz val trap_code))
|
||||
(safepoint (trap_if_bool (value_nonzero val) trap_code)))
|
||||
|
||||
|
||||
;;;; Rules for `resumable_trapnz` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(rule (lower (resumable_trapnz val trap_code))
|
||||
(safepoint (trap_if_bool (value_nonzero val) trap_code)))
|
||||
|
||||
|
||||
;;;; Rules for `debugtrap` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(rule (lower (debugtrap))
|
||||
(value_regs_none (debugtrap_impl)))
|
||||
|
||||
|
||||
;;;; Rules for `trapif` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
;; Similarly to `selectif_spectre_guard`, we only recognize specific patterns
|
||||
;; generated by common code here. Others will fail to lower.
|
||||
|
||||
;; Recognize the case of `ifcmp` feeding into `trapif`. Directly generate
|
||||
;; the desired comparison here; there is no separate `ifcmp` lowering.
|
||||
|
||||
(rule (lower (trapif int_cc (def_inst (ifcmp x y)) trap_code))
|
||||
(safepoint (trap_if_bool (icmp_val $false int_cc x y) trap_code)))
|
||||
|
||||
;; Recognize the case of `iadd_ifcout` feeding into `trapif`. Note that
|
||||
;; in the case, the `iadd_ifcout` is generated by a separate lowering
|
||||
;; (in order to properly handle the register output of that instruction.)
|
||||
;;
|
||||
;; The flags must not have been clobbered by any other instruction between the
|
||||
;; iadd_ifcout and this instruction, as verified by the CLIF validator; so we
|
||||
;; can simply rely on the condition code here.
|
||||
;;
|
||||
;; IaddIfcout is implemented via a ADD LOGICAL instruction, which sets the
|
||||
;; the condition code as follows:
|
||||
;; 0 Result zero; no carry
|
||||
;; 1 Result not zero; no carry
|
||||
;; 2 Result zero; carry
|
||||
;; 3 Result not zero; carry
|
||||
;; This means "carry" corresponds to condition code 2 or 3, i.e.
|
||||
;; a condition mask of 2 | 1.
|
||||
;;
|
||||
;; As this does not match any of the encodings used with a normal integer
|
||||
;; comparsion, this cannot be represented by any IntCC value. We need to
|
||||
;; remap the IntCC::UnsignedGreaterThan value that we have here as result
|
||||
;; of the unsigned_add_overflow_condition call to the correct mask.
|
||||
|
||||
(rule (lower (trapif (IntCC.UnsignedGreaterThan)
|
||||
(def_inst (iadd_ifcout x y)) trap_code))
|
||||
(value_regs_none (trap_if_impl (mask_as_cond 3) trap_code)))
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user