cranelift: Add a conditional branch instruction with two targets (#5446)
Add a conditional branch instruction with two targets: brif. This instruction will eventually replace brz and brnz, as it encompasses the behavior of both. This PR also changes the InstructionData layout for instruction formats that hold BlockCall values, taking the same approach we use for Value arguments. This allows branch_destination to return a slice to the BlockCall values held in the instruction, rather than requiring that we pattern match on InstructionData to fetch the then/else blocks. Function generation for fuzzing has been updated to generate uses of brif, and I've run the cranelift-fuzzgen target locally for hours without triggering any new failures.
This commit is contained in:
@@ -2461,6 +2461,52 @@
|
||||
(rule (lower (fvpromote_low val))
|
||||
(vec_rr_long (VecRRLongOp.Fcvtl32) val $false))
|
||||
|
||||
;;; Rules for `brif` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
;; `brif` following `icmp`
|
||||
(rule (lower_branch (brif (maybe_uextend (icmp cc x @ (value_type ty) y)) _ _) targets)
|
||||
(let ((comparison FlagsAndCC (lower_icmp_into_flags cc x y ty))
|
||||
(cond Cond (cond_code (flags_and_cc_cc comparison)))
|
||||
(taken BranchTarget (branch_target targets 0))
|
||||
(not_taken BranchTarget (branch_target targets 1)))
|
||||
(emit_side_effect
|
||||
(with_flags_side_effect (flags_and_cc_flags comparison)
|
||||
(cond_br taken
|
||||
not_taken
|
||||
(cond_br_cond cond))))))
|
||||
|
||||
;; `brif` following `fcmp`
|
||||
(rule (lower_branch (brif (maybe_uextend (fcmp cc x @ (value_type (ty_scalar_float ty)) y)) _ _) targets)
|
||||
(let ((cond Cond (fp_cond_code cc))
|
||||
(taken BranchTarget (branch_target targets 0))
|
||||
(not_taken BranchTarget (branch_target targets 1)))
|
||||
(emit_side_effect
|
||||
(with_flags_side_effect (fpu_cmp (scalar_size ty) x y)
|
||||
(cond_br taken not_taken
|
||||
(cond_br_cond cond))))))
|
||||
|
||||
;; standard `brif`
|
||||
(rule -1 (lower_branch (brif c @ (value_type $I128) _ _) targets)
|
||||
(let ((flags ProducesFlags (flags_to_producesflags c))
|
||||
(c ValueRegs (put_in_regs c))
|
||||
(c_lo Reg (value_regs_get c 0))
|
||||
(c_hi Reg (value_regs_get c 1))
|
||||
(rt Reg (orr $I64 c_lo c_hi))
|
||||
(taken BranchTarget (branch_target targets 0))
|
||||
(not_taken BranchTarget (branch_target targets 1)))
|
||||
(emit_side_effect
|
||||
(with_flags_side_effect flags
|
||||
(cond_br taken not_taken (cond_br_not_zero rt))))))
|
||||
(rule -2 (lower_branch (brif c @ (value_type ty) _ _) targets)
|
||||
(if (ty_int_ref_scalar_64 ty))
|
||||
(let ((flags ProducesFlags (flags_to_producesflags c))
|
||||
(rt Reg (put_in_reg_zext64 c))
|
||||
(taken BranchTarget (branch_target targets 0))
|
||||
(not_taken BranchTarget (branch_target targets 1)))
|
||||
(emit_side_effect
|
||||
(with_flags_side_effect flags
|
||||
(cond_br taken not_taken (cond_br_not_zero rt))))))
|
||||
|
||||
;;; Rules for `brz`/`brnz` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
;; `brz` following `icmp`
|
||||
|
||||
@@ -24,8 +24,8 @@ use crate::machinst::{isle::*, InputSourceInst};
|
||||
use crate::{
|
||||
binemit::CodeOffset,
|
||||
ir::{
|
||||
immediates::*, types::*, AtomicRmwOp, ExternalName, Inst, InstructionData, MemFlags,
|
||||
TrapCode, Value, ValueList,
|
||||
immediates::*, types::*, AtomicRmwOp, BlockCall, ExternalName, Inst, InstructionData,
|
||||
MemFlags, TrapCode, Value, ValueList,
|
||||
},
|
||||
isa::aarch64::abi::AArch64Caller,
|
||||
isa::aarch64::inst::args::{ShiftOp, ShiftOpShiftImm},
|
||||
|
||||
@@ -1898,6 +1898,30 @@
|
||||
(hi Reg (value_regs_get regs 1)))
|
||||
(alu_rrr (AluOPRRR.Or) lo hi)))
|
||||
|
||||
;; Default behavior for branching based on an input value.
|
||||
(rule
|
||||
(lower_branch (brif v @ (value_type ty) _ _) targets)
|
||||
(lower_brz_or_nz (IntCC.NotEqual) (normalize_cmp_value ty v) targets ty))
|
||||
|
||||
;; Special case for SI128 to reify the comparison value and branch on it.
|
||||
(rule 2
|
||||
(lower_branch (brif v @ (value_type $I128) _ _) targets)
|
||||
(let ((zero ValueRegs (value_regs (zero_reg) (zero_reg)))
|
||||
(cmp Reg (gen_icmp (IntCC.NotEqual) v zero $I128)))
|
||||
(lower_brz_or_nz (IntCC.NotEqual) cmp targets $I64)))
|
||||
|
||||
;; Branching on the result of an icmp
|
||||
(rule 1
|
||||
(lower_branch (brif (icmp cc a @ (value_type ty) b) _ _) targets)
|
||||
(lower_br_icmp cc a b targets ty))
|
||||
|
||||
;; Branching on the result of an fcmp
|
||||
(rule 1
|
||||
(lower_branch (brif (fcmp cc a @ (value_type ty) b) _ _) targets)
|
||||
(let ((then BranchTarget (label_to_br_target (vec_label_get targets 0)))
|
||||
(else BranchTarget (label_to_br_target (vec_label_get targets 1))))
|
||||
(emit_side_effect (cond_br (emit_fcmp cc ty a b) then else))))
|
||||
|
||||
;;;;;
|
||||
(rule
|
||||
(lower_branch (brz v @ (value_type ty) _) targets)
|
||||
|
||||
@@ -14,8 +14,8 @@ use crate::machinst::{isle::*, MachInst, SmallInstVec};
|
||||
use crate::machinst::{VCodeConstant, VCodeConstantData};
|
||||
use crate::{
|
||||
ir::{
|
||||
immediates::*, types::*, AtomicRmwOp, ExternalName, Inst, InstructionData, MemFlags,
|
||||
StackSlot, TrapCode, Value, ValueList,
|
||||
immediates::*, types::*, AtomicRmwOp, BlockCall, ExternalName, Inst, InstructionData,
|
||||
MemFlags, StackSlot, TrapCode, Value, ValueList,
|
||||
},
|
||||
isa::riscv64::inst::*,
|
||||
machinst::{ArgPair, InstOutput, Lower},
|
||||
|
||||
@@ -3750,6 +3750,17 @@
|
||||
(emit_side_effect (jt_sequence (lshl_imm $I64 idx 2) targets))))
|
||||
|
||||
|
||||
;;;; Rules for `brif` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
;; 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 (brif val_cond _ _) targets)
|
||||
(emit_side_effect (cond_br_bool (value_nonzero val_cond)
|
||||
(vec_element targets 0)
|
||||
(vec_element targets 1))))
|
||||
|
||||
|
||||
;;;; Rules for `brz` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
;; Two-way conditional branch on zero. `targets` contains:
|
||||
|
||||
@@ -16,8 +16,8 @@ use crate::machinst::isle::*;
|
||||
use crate::machinst::{MachLabel, Reg};
|
||||
use crate::{
|
||||
ir::{
|
||||
condcodes::*, immediates::*, types::*, ArgumentPurpose, AtomicRmwOp, Endianness, Inst,
|
||||
InstructionData, KnownSymbol, LibCall, MemFlags, Opcode, TrapCode, Value, ValueList,
|
||||
condcodes::*, immediates::*, types::*, ArgumentPurpose, AtomicRmwOp, BlockCall, Endianness,
|
||||
Inst, InstructionData, KnownSymbol, LibCall, MemFlags, Opcode, TrapCode, Value, ValueList,
|
||||
},
|
||||
isa::unwind::UnwindInst,
|
||||
isa::CallConv,
|
||||
|
||||
@@ -2885,6 +2885,25 @@
|
||||
(rule (lower_branch (jump _) (single_target target))
|
||||
(emit_side_effect (jmp_known target)))
|
||||
|
||||
;; Rules for `brif` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(rule 2 (lower_branch (brif (maybe_uextend (icmp cc a b)) _ _) (two_targets then else))
|
||||
(emit_side_effect (jmp_cond_icmp (emit_cmp cc a b) then else)))
|
||||
|
||||
(rule 2 (lower_branch (brif (maybe_uextend (fcmp cc a b)) _ _) (two_targets then else))
|
||||
(emit_side_effect (jmp_cond_fcmp (emit_fcmp cc a b) then else)))
|
||||
|
||||
(rule 1 (lower_branch (brif val @ (value_type $I128) _ _)
|
||||
(two_targets then else))
|
||||
(emit_side_effect (jmp_cond_icmp (cmp_zero_i128 (CC.Z) val) then else)))
|
||||
|
||||
(rule (lower_branch (brif val @ (value_type (ty_int_bool_or_ref)) _ _)
|
||||
(two_targets then else))
|
||||
(emit_side_effect (with_flags_side_effect
|
||||
(cmp_zero_int_bool_ref val)
|
||||
(jmp_cond (CC.NZ) then else))))
|
||||
|
||||
|
||||
;; Rules for `brz` and `brnz` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(rule 2 (lower_branch (brz (maybe_uextend (icmp cc a b)) _) (two_targets taken not_taken))
|
||||
|
||||
@@ -20,7 +20,7 @@ use crate::{
|
||||
condcodes::{CondCode, FloatCC, IntCC},
|
||||
immediates::*,
|
||||
types::*,
|
||||
Inst, InstructionData, MemFlags, Opcode, TrapCode, Value, ValueList,
|
||||
BlockCall, Inst, InstructionData, MemFlags, Opcode, TrapCode, Value, ValueList,
|
||||
},
|
||||
isa::{
|
||||
unwind::UnwindInst,
|
||||
|
||||
Reference in New Issue
Block a user