riscv64: Delete SelectIf instruction (#5888)
* riscv64: Delete `SelectIf` instruction * riscv64: Fix typo in comment Co-authored-by: Trevor Elliott <awesomelyawesome@gmail.com> * riscv64: Improve `bmask` codegen * riscv64: Use `lower_bmask` in `select_spectre_guard` * riscv64: Use `lower_bmask` to extend values in `select_spectre_guard` Co-authored-by: Trevor Elliott <awesomelyawesome@gmail.com> --------- Co-authored-by: Trevor Elliott <awesomelyawesome@gmail.com>
This commit is contained in:
@@ -257,12 +257,7 @@
|
||||
(is_signed bool)
|
||||
(in_type Type)
|
||||
(out_type Type))
|
||||
(SelectIf
|
||||
(if_spectre_guard bool)
|
||||
(rd VecWritableReg)
|
||||
(test Reg)
|
||||
(x ValueRegs)
|
||||
(y ValueRegs))
|
||||
|
||||
(RawData (data VecU8))
|
||||
|
||||
;; An unwind pseudo-instruction.
|
||||
@@ -872,6 +867,12 @@
|
||||
(rule (rv_sltu rs1 rs2)
|
||||
(alu_rrr (AluOPRRR.SltU) rs1 rs2))
|
||||
|
||||
;; Helper for emitting the `snez` instruction.
|
||||
;; This instruction is a mnemonic for `sltu rd, zero, rs`.
|
||||
(decl rv_snez (Reg) Reg)
|
||||
(rule (rv_snez rs1)
|
||||
(rv_sltu (zero_reg) rs1))
|
||||
|
||||
;; Helper for emiting the `sltiu` ("Set Less Than Immediate Unsigned") instruction.
|
||||
;; rd ← rs1 < imm
|
||||
(decl rv_sltiu (Reg Imm12) Reg)
|
||||
@@ -1371,15 +1372,35 @@
|
||||
(rule (select_addi (fits_in_64 ty)) (AluOPRRI.Addi))
|
||||
|
||||
|
||||
(decl bnot_128 (ValueRegs) ValueRegs)
|
||||
(rule
|
||||
(bnot_128 val)
|
||||
(let
|
||||
(;; low part.
|
||||
(low Reg (rv_not (value_regs_get val 0)))
|
||||
;; high part.
|
||||
(high Reg (rv_not (value_regs_get val 1))))
|
||||
(value_regs low high)))
|
||||
(decl gen_bnot (Type ValueRegs) ValueRegs)
|
||||
(rule 1 (gen_bnot $I128 x)
|
||||
(let ((lo Reg (rv_not (value_regs_get x 0)))
|
||||
(hi Reg (rv_not (value_regs_get x 1))))
|
||||
(value_regs lo hi)))
|
||||
|
||||
(rule 0 (gen_bnot (fits_in_64 _) x)
|
||||
(rv_not x))
|
||||
|
||||
|
||||
(decl gen_and (Type ValueRegs ValueRegs) ValueRegs)
|
||||
(rule 1 (gen_and $I128 x y)
|
||||
(value_regs
|
||||
(rv_and (value_regs_get x 0) (value_regs_get y 0))
|
||||
(rv_and (value_regs_get x 1) (value_regs_get y 1))))
|
||||
|
||||
(rule 0 (gen_and (fits_in_64 _) x y)
|
||||
(rv_and (value_regs_get x 0) (value_regs_get y 0)))
|
||||
|
||||
|
||||
(decl gen_or (Type ValueRegs ValueRegs) ValueRegs)
|
||||
(rule 1 (gen_or $I128 x y)
|
||||
(value_regs
|
||||
(rv_or (value_regs_get x 0) (value_regs_get y 0))
|
||||
(rv_or (value_regs_get x 1) (value_regs_get y 1))))
|
||||
|
||||
(rule 0 (gen_or (fits_in_64 _) x y)
|
||||
(rv_or (value_regs_get x 0) (value_regs_get y 0)))
|
||||
|
||||
|
||||
(decl lower_bit_reverse (Reg Type) Reg)
|
||||
|
||||
@@ -2511,9 +2532,8 @@
|
||||
0
|
||||
(lower_bmask (fits_in_64 _) (fits_in_64 in_ty) val)
|
||||
(let ((input Reg (normalize_cmp_value in_ty val (ExtendOp.Zero)))
|
||||
(zero Reg (zero_reg))
|
||||
(ones Reg (load_imm12 -1)))
|
||||
(value_reg (gen_select_reg (IntCC.Equal) zero input zero ones))))
|
||||
(non_zero Reg (rv_snez input)))
|
||||
(value_reg (rv_neg non_zero))))
|
||||
|
||||
;; Bitwise-or the two registers that make up the 128-bit value, then recurse as
|
||||
;; though it was a 64-bit value.
|
||||
|
||||
@@ -1864,48 +1864,6 @@ impl MachInstEmit for Inst {
|
||||
}
|
||||
sink.put_data(Inst::TRAP_OPCODE);
|
||||
}
|
||||
&Inst::SelectIf {
|
||||
if_spectre_guard: _if_spectre_guard, // _if_spectre_guard not use because it is used to not be removed by optimization pass and some other staff.
|
||||
ref rd,
|
||||
test,
|
||||
ref x,
|
||||
ref y,
|
||||
} => {
|
||||
let label_select_x = sink.get_label();
|
||||
let label_select_y = sink.get_label();
|
||||
let label_jump_over = sink.get_label();
|
||||
let test = allocs.next(test);
|
||||
let x = alloc_value_regs(x, &mut allocs);
|
||||
let y = alloc_value_regs(y, &mut allocs);
|
||||
let rd: Vec<_> = rd.iter().map(|r| allocs.next_writable(*r)).collect();
|
||||
Inst::CondBr {
|
||||
taken: BranchTarget::Label(label_select_x),
|
||||
not_taken: BranchTarget::Label(label_select_y),
|
||||
kind: IntegerCompare {
|
||||
kind: IntCC::NotEqual,
|
||||
rs1: test,
|
||||
rs2: zero_reg(),
|
||||
},
|
||||
}
|
||||
.emit(&[], sink, emit_info, state);
|
||||
|
||||
// here select x.
|
||||
sink.bind_label(label_select_x, &mut state.ctrl_plane);
|
||||
gen_moves(&rd[..], x.regs())
|
||||
.into_iter()
|
||||
.for_each(|i| i.emit(&[], sink, emit_info, state));
|
||||
// jump over
|
||||
Inst::Jal {
|
||||
dest: BranchTarget::Label(label_jump_over),
|
||||
}
|
||||
.emit(&[], sink, emit_info, state);
|
||||
// here select y.
|
||||
sink.bind_label(label_select_y, &mut state.ctrl_plane);
|
||||
gen_moves(&rd[..], y.regs())
|
||||
.into_iter()
|
||||
.for_each(|i| i.emit(&[], sink, emit_info, state));
|
||||
sink.bind_label(label_jump_over, &mut state.ctrl_plane);
|
||||
}
|
||||
&Inst::AtomicLoad { rd, ty, p } => {
|
||||
let p = allocs.next(p);
|
||||
let rd = allocs.next_writable(rd);
|
||||
|
||||
@@ -526,18 +526,6 @@ fn riscv64_get_operands<F: Fn(VReg) -> VReg>(inst: &Inst, collector: &mut Operan
|
||||
collector.reg_early_def(tmp);
|
||||
collector.reg_early_def(rd);
|
||||
}
|
||||
&Inst::SelectIf {
|
||||
ref rd,
|
||||
test,
|
||||
ref x,
|
||||
ref y,
|
||||
..
|
||||
} => {
|
||||
collector.reg_use(test);
|
||||
collector.reg_uses(x.regs());
|
||||
collector.reg_uses(y.regs());
|
||||
rd.iter().for_each(|r| collector.reg_early_def(*r));
|
||||
}
|
||||
&Inst::RawData { .. } => {}
|
||||
&Inst::AtomicStore { src, p, .. } => {
|
||||
collector.reg_use(src);
|
||||
@@ -1012,31 +1000,6 @@ impl Inst {
|
||||
rd, rs, tmp, tmp2, step, ty
|
||||
)
|
||||
}
|
||||
&Inst::SelectIf {
|
||||
if_spectre_guard,
|
||||
ref rd,
|
||||
test,
|
||||
ref x,
|
||||
ref y,
|
||||
} => {
|
||||
let test = format_reg(test, allocs);
|
||||
let x = format_regs(x.regs(), allocs);
|
||||
let y = format_regs(y.regs(), allocs);
|
||||
let rd: Vec<_> = rd.iter().map(|r| r.to_reg()).collect();
|
||||
let rd = format_regs(&rd[..], allocs);
|
||||
format!(
|
||||
"selectif{} {},{},{}##test={}",
|
||||
if if_spectre_guard {
|
||||
"_spectre_guard"
|
||||
} else {
|
||||
""
|
||||
},
|
||||
rd,
|
||||
x,
|
||||
y,
|
||||
test
|
||||
)
|
||||
}
|
||||
&Inst::Popcnt {
|
||||
sum,
|
||||
step,
|
||||
|
||||
@@ -230,8 +230,8 @@
|
||||
(rv_remu x y)))
|
||||
|
||||
;;;; Rules for `and` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
(rule -1 (lower (has_type (fits_in_64 (ty_int ty)) (band x y)))
|
||||
(rv_and x y))
|
||||
(rule -1 (lower (has_type (ty_int ty) (band x y)))
|
||||
(gen_and ty x y))
|
||||
|
||||
;; Special cases for when one operand is an immediate that fits in 12 bits.
|
||||
(rule 2 (lower (has_type (fits_in_64 (ty_int ty)) (band x (imm12_from_value y))))
|
||||
@@ -240,9 +240,6 @@
|
||||
(rule 1 (lower (has_type (fits_in_64 (ty_int ty)) (band (imm12_from_value x) y)))
|
||||
(rv_andi y x))
|
||||
|
||||
(rule (lower (has_type $I128 (band x y)))
|
||||
(lower_b128_binary (AluOPRRR.And) x y))
|
||||
|
||||
(rule (lower (has_type $F32 (band x y)))
|
||||
(lower_float_binary (AluOPRRR.And) x y $F32))
|
||||
|
||||
@@ -277,8 +274,8 @@
|
||||
|
||||
|
||||
;;;; Rules for `or` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
(rule -1 (lower (has_type (fits_in_64 (ty_int ty)) (bor x y)))
|
||||
(rv_or x y))
|
||||
(rule -1 (lower (has_type (ty_int ty) (bor x y)))
|
||||
(gen_or ty x y))
|
||||
|
||||
;; Special cases for when one operand is an immediate that fits in 12 bits.
|
||||
(rule 2 (lower (has_type (fits_in_64 (ty_int ty)) (bor x (imm12_from_value y))))
|
||||
@@ -287,9 +284,6 @@
|
||||
(rule 1 (lower (has_type (fits_in_64 (ty_int ty)) (bor (imm12_from_value x) y)))
|
||||
(rv_ori y x))
|
||||
|
||||
(rule (lower (has_type $I128 (bor x y)))
|
||||
(lower_b128_binary (AluOPRRR.Or) x y))
|
||||
|
||||
(rule (lower (has_type $F32 (bor x y)))
|
||||
(lower_float_binary (AluOPRRR.Or) x y $F32))
|
||||
|
||||
@@ -345,11 +339,8 @@
|
||||
|
||||
|
||||
;;;; Rules for `bnot` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
(rule -1 (lower (has_type (fits_in_64 (ty_int ty)) (bnot x)))
|
||||
(rv_xori x (imm_from_neg_bits -1)))
|
||||
|
||||
(rule (lower (has_type $I128 (bnot x)))
|
||||
(bnot_128 x))
|
||||
(rule -1 (lower (has_type (ty_int ty) (bnot x)))
|
||||
(gen_bnot ty x))
|
||||
|
||||
(rule
|
||||
(lower (has_type $F32 (bnot x)))
|
||||
@@ -927,17 +918,23 @@
|
||||
|
||||
|
||||
;;;;; Rules for `select_spectre_guard`;;;;;;;;;
|
||||
(rule
|
||||
(lower (has_type r_ty (select_spectre_guard (icmp cc ca @ (value_type cty) cb) a b)))
|
||||
(let
|
||||
((dst VecWritableReg (alloc_vec_writable r_ty))
|
||||
(r Reg (lower_icmp cc ca cb cty))
|
||||
(_ Unit (emit (MInst.SelectIf $true (vec_writable_clone dst) r a b))))
|
||||
(vec_writable_to_regs dst)))
|
||||
|
||||
(rule -1
|
||||
(lower (has_type ty (select_spectre_guard c @ (value_type cty) x y)))
|
||||
(gen_select ty (truthy_to_reg cty (normalize_cmp_value cty c (ExtendOp.Zero))) x y))
|
||||
;; SelectSpectreGuard is equivalent to Select, but we should not use a branch based
|
||||
;; lowering for it. Instead we use a conditional move based lowering.
|
||||
;;
|
||||
;; We don't have cmov's in RISC-V either, but we can emulate those using bitwise
|
||||
;; operations, which is what we do below.
|
||||
(rule (lower (has_type ty (select_spectre_guard cmp @ (value_type cmp_ty) x @ (value_type arg_ty) y)))
|
||||
(let (;; Build a mask that is 0 or -1 depending on the input comparision value.
|
||||
;; `lower_bmask` handles normalizing the input.
|
||||
(mask ValueRegs (lower_bmask arg_ty cmp_ty cmp))
|
||||
;; Using the mask above we can select either `x` or `y` by
|
||||
;; performing a bitwise `and` on both sides and then merging them
|
||||
;; together. We know that only the bits of one of the sides will be selected.
|
||||
;; TODO: We can use `andn` here if we have `Zbb`
|
||||
(lhs ValueRegs (gen_and arg_ty x mask))
|
||||
(rhs ValueRegs (gen_and arg_ty y (gen_bnot arg_ty mask))))
|
||||
(gen_or arg_ty lhs rhs)))
|
||||
|
||||
;;;;; Rules for `bmask`;;;;;;;;;
|
||||
(rule
|
||||
|
||||
Reference in New Issue
Block a user