Simplify LowerBackend interface (#5432)
* Refactor lower_branch to have Unit result Branches cannot have any output, so it is more straightforward to have the ISLE term return Unit instead of InstOutput. Also provide a new `emit_side_effect` term to simplify implementation of `lower_branch` rules with Unit result. * Simplify LowerBackend interface Move all remaining asserts from the LowerBackend::lower and ::lower_branch_group into the common call site. Change return value of ::lower to Option<InstOutput>, and return value of ::lower_branch_group to Option<()> to match ISLE term signature. Only pass the first branch into ::lower_branch_group and rename it to ::lower_branch. As a result of all those changes, LowerBackend routines now consists solely to calls to the corresponding ISLE routines.
This commit is contained in:
@@ -3748,15 +3748,15 @@
|
|||||||
(MInst.EmitIsland needed_space)))
|
(MInst.EmitIsland needed_space)))
|
||||||
|
|
||||||
;; Helper for emitting `br_table` sequences.
|
;; Helper for emitting `br_table` sequences.
|
||||||
(decl br_table_impl (u64 Reg VecMachLabel) InstOutput)
|
(decl br_table_impl (u64 Reg VecMachLabel) Unit)
|
||||||
(rule (br_table_impl (imm12_from_u64 jt_size) ridx targets)
|
(rule (br_table_impl (imm12_from_u64 jt_size) ridx targets)
|
||||||
(let ((jt_info BoxJTSequenceInfo (targets_jt_info targets)))
|
(let ((jt_info BoxJTSequenceInfo (targets_jt_info targets)))
|
||||||
(side_effect (with_flags_side_effect
|
(emit_side_effect (with_flags_side_effect
|
||||||
(cmp_imm (OperandSize.Size32) ridx jt_size)
|
(cmp_imm (OperandSize.Size32) ridx jt_size)
|
||||||
(jt_sequence ridx jt_info)))))
|
(jt_sequence ridx jt_info)))))
|
||||||
(rule -1 (br_table_impl jt_size ridx targets)
|
(rule -1 (br_table_impl jt_size ridx targets)
|
||||||
(let ((jt_size Reg (imm $I64 (ImmExtend.Zero) jt_size))
|
(let ((jt_size Reg (imm $I64 (ImmExtend.Zero) jt_size))
|
||||||
(jt_info BoxJTSequenceInfo (targets_jt_info targets)))
|
(jt_info BoxJTSequenceInfo (targets_jt_info targets)))
|
||||||
(side_effect (with_flags_side_effect
|
(emit_side_effect (with_flags_side_effect
|
||||||
(cmp (OperandSize.Size32) ridx jt_size)
|
(cmp (OperandSize.Size32) ridx jt_size)
|
||||||
(jt_sequence ridx jt_info)))))
|
(jt_sequence ridx jt_info)))))
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
;; blocks while we lower, the fallthrough in the new order is not (necessarily)
|
;; blocks while we lower, the fallthrough in the new order is not (necessarily)
|
||||||
;; the same as the fallthrough in CLIF. So, we use the explicitly-provided
|
;; the same as the fallthrough in CLIF. So, we use the explicitly-provided
|
||||||
;; target.
|
;; target.
|
||||||
(decl partial lower_branch (Inst VecMachLabel) InstOutput)
|
(decl partial lower_branch (Inst VecMachLabel) Unit)
|
||||||
|
|
||||||
;;;; Rules for `iconst` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;; Rules for `iconst` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
@@ -2422,7 +2422,7 @@
|
|||||||
(cond Cond (invert_cond (cond_code (flags_and_cc_cc comparison))))
|
(cond Cond (invert_cond (cond_code (flags_and_cc_cc comparison))))
|
||||||
(taken BranchTarget (branch_target targets 0))
|
(taken BranchTarget (branch_target targets 0))
|
||||||
(not_taken BranchTarget (branch_target targets 1)))
|
(not_taken BranchTarget (branch_target targets 1)))
|
||||||
(side_effect
|
(emit_side_effect
|
||||||
(with_flags_side_effect (flags_and_cc_flags comparison)
|
(with_flags_side_effect (flags_and_cc_flags comparison)
|
||||||
(cond_br taken
|
(cond_br taken
|
||||||
not_taken
|
not_taken
|
||||||
@@ -2433,7 +2433,7 @@
|
|||||||
(cond Cond (cond_code (flags_and_cc_cc comparison)))
|
(cond Cond (cond_code (flags_and_cc_cc comparison)))
|
||||||
(taken BranchTarget (branch_target targets 0))
|
(taken BranchTarget (branch_target targets 0))
|
||||||
(not_taken BranchTarget (branch_target targets 1)))
|
(not_taken BranchTarget (branch_target targets 1)))
|
||||||
(side_effect
|
(emit_side_effect
|
||||||
(with_flags_side_effect (flags_and_cc_flags comparison)
|
(with_flags_side_effect (flags_and_cc_flags comparison)
|
||||||
(cond_br taken
|
(cond_br taken
|
||||||
not_taken
|
not_taken
|
||||||
@@ -2444,7 +2444,7 @@
|
|||||||
(cond Cond (invert_cond cond)) ;; negate for `brz`
|
(cond Cond (invert_cond cond)) ;; negate for `brz`
|
||||||
(taken BranchTarget (branch_target targets 0))
|
(taken BranchTarget (branch_target targets 0))
|
||||||
(not_taken BranchTarget (branch_target targets 1)))
|
(not_taken BranchTarget (branch_target targets 1)))
|
||||||
(side_effect
|
(emit_side_effect
|
||||||
(with_flags_side_effect (fpu_cmp (scalar_size ty) x y)
|
(with_flags_side_effect (fpu_cmp (scalar_size ty) x y)
|
||||||
(cond_br taken not_taken
|
(cond_br taken not_taken
|
||||||
(cond_br_cond cond))))))
|
(cond_br_cond cond))))))
|
||||||
@@ -2453,7 +2453,7 @@
|
|||||||
(let ((cond Cond (fp_cond_code cc))
|
(let ((cond Cond (fp_cond_code cc))
|
||||||
(taken BranchTarget (branch_target targets 0))
|
(taken BranchTarget (branch_target targets 0))
|
||||||
(not_taken BranchTarget (branch_target targets 1)))
|
(not_taken BranchTarget (branch_target targets 1)))
|
||||||
(side_effect
|
(emit_side_effect
|
||||||
(with_flags_side_effect (fpu_cmp (scalar_size ty) x y)
|
(with_flags_side_effect (fpu_cmp (scalar_size ty) x y)
|
||||||
(cond_br taken not_taken
|
(cond_br taken not_taken
|
||||||
(cond_br_cond cond))))))
|
(cond_br_cond cond))))))
|
||||||
@@ -2466,7 +2466,7 @@
|
|||||||
(rt Reg (orr $I64 c_lo c_hi))
|
(rt Reg (orr $I64 c_lo c_hi))
|
||||||
(taken BranchTarget (branch_target targets 0))
|
(taken BranchTarget (branch_target targets 0))
|
||||||
(not_taken BranchTarget (branch_target targets 1)))
|
(not_taken BranchTarget (branch_target targets 1)))
|
||||||
(side_effect
|
(emit_side_effect
|
||||||
(with_flags_side_effect flags
|
(with_flags_side_effect flags
|
||||||
(cond_br taken not_taken (cond_br_zero rt))))))
|
(cond_br taken not_taken (cond_br_zero rt))))))
|
||||||
(rule -2 (lower_branch (brz c @ (value_type ty) _ _) targets)
|
(rule -2 (lower_branch (brz c @ (value_type ty) _ _) targets)
|
||||||
@@ -2475,7 +2475,7 @@
|
|||||||
(rt Reg (put_in_reg_zext64 c))
|
(rt Reg (put_in_reg_zext64 c))
|
||||||
(taken BranchTarget (branch_target targets 0))
|
(taken BranchTarget (branch_target targets 0))
|
||||||
(not_taken BranchTarget (branch_target targets 1)))
|
(not_taken BranchTarget (branch_target targets 1)))
|
||||||
(side_effect
|
(emit_side_effect
|
||||||
(with_flags_side_effect flags
|
(with_flags_side_effect flags
|
||||||
(cond_br taken not_taken (cond_br_zero rt))))))
|
(cond_br taken not_taken (cond_br_zero rt))))))
|
||||||
;; standard `brnz`
|
;; standard `brnz`
|
||||||
@@ -2487,7 +2487,7 @@
|
|||||||
(rt Reg (orr $I64 c_lo c_hi))
|
(rt Reg (orr $I64 c_lo c_hi))
|
||||||
(taken BranchTarget (branch_target targets 0))
|
(taken BranchTarget (branch_target targets 0))
|
||||||
(not_taken BranchTarget (branch_target targets 1)))
|
(not_taken BranchTarget (branch_target targets 1)))
|
||||||
(side_effect
|
(emit_side_effect
|
||||||
(with_flags_side_effect flags
|
(with_flags_side_effect flags
|
||||||
(cond_br taken not_taken (cond_br_not_zero rt))))))
|
(cond_br taken not_taken (cond_br_not_zero rt))))))
|
||||||
(rule -2 (lower_branch (brnz c @ (value_type ty) _ _) targets)
|
(rule -2 (lower_branch (brnz c @ (value_type ty) _ _) targets)
|
||||||
@@ -2496,14 +2496,14 @@
|
|||||||
(rt Reg (put_in_reg_zext64 c))
|
(rt Reg (put_in_reg_zext64 c))
|
||||||
(taken BranchTarget (branch_target targets 0))
|
(taken BranchTarget (branch_target targets 0))
|
||||||
(not_taken BranchTarget (branch_target targets 1)))
|
(not_taken BranchTarget (branch_target targets 1)))
|
||||||
(side_effect
|
(emit_side_effect
|
||||||
(with_flags_side_effect flags
|
(with_flags_side_effect flags
|
||||||
(cond_br taken not_taken (cond_br_not_zero rt))))))
|
(cond_br taken not_taken (cond_br_not_zero rt))))))
|
||||||
|
|
||||||
;;; Rules for `jump` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;; Rules for `jump` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
(rule (lower_branch (jump _ _) targets)
|
(rule (lower_branch (jump _ _) targets)
|
||||||
(side_effect (aarch64_jump (branch_target targets 0))))
|
(emit_side_effect (aarch64_jump (branch_target targets 0))))
|
||||||
|
|
||||||
;;; Rules for `br_table` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;; Rules for `br_table` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ use crate::isa::aarch64::inst::*;
|
|||||||
use crate::isa::aarch64::AArch64Backend;
|
use crate::isa::aarch64::AArch64Backend;
|
||||||
use crate::machinst::lower::*;
|
use crate::machinst::lower::*;
|
||||||
use crate::machinst::{Reg, Writable};
|
use crate::machinst::{Reg, Writable};
|
||||||
use crate::CodegenResult;
|
|
||||||
use crate::{machinst::*, trace};
|
use crate::{machinst::*, trace};
|
||||||
use smallvec::{smallvec, SmallVec};
|
use smallvec::{smallvec, SmallVec};
|
||||||
|
|
||||||
@@ -745,51 +744,17 @@ pub(crate) fn maybe_value_multi(
|
|||||||
impl LowerBackend for AArch64Backend {
|
impl LowerBackend for AArch64Backend {
|
||||||
type MInst = Inst;
|
type MInst = Inst;
|
||||||
|
|
||||||
fn lower(&self, ctx: &mut Lower<Inst>, ir_inst: IRInst) -> CodegenResult<InstOutput> {
|
fn lower(&self, ctx: &mut Lower<Inst>, ir_inst: IRInst) -> Option<InstOutput> {
|
||||||
if let Some(temp_regs) = super::lower::isle::lower(ctx, self, ir_inst) {
|
isle::lower(ctx, self, ir_inst)
|
||||||
return Ok(temp_regs);
|
|
||||||
}
|
|
||||||
|
|
||||||
let ty = if ctx.num_outputs(ir_inst) > 0 {
|
|
||||||
Some(ctx.output_ty(ir_inst, 0))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
unreachable!(
|
|
||||||
"not implemented in ISLE: inst = `{}`, type = `{:?}`",
|
|
||||||
ctx.dfg().display_inst(ir_inst),
|
|
||||||
ty
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lower_branch_group(
|
fn lower_branch(
|
||||||
&self,
|
&self,
|
||||||
ctx: &mut Lower<Inst>,
|
ctx: &mut Lower<Inst>,
|
||||||
branches: &[IRInst],
|
ir_inst: IRInst,
|
||||||
targets: &[MachLabel],
|
targets: &[MachLabel],
|
||||||
) -> CodegenResult<()> {
|
) -> Option<()> {
|
||||||
// A block should end with at most two branches. The first may be a
|
isle::lower_branch(ctx, self, ir_inst, targets)
|
||||||
// conditional branch; a conditional branch can be followed only by an
|
|
||||||
// unconditional branch or fallthrough. Otherwise, if only one branch,
|
|
||||||
// it may be an unconditional branch, a fallthrough, a return, or a
|
|
||||||
// trap. These conditions are verified by `is_ebb_basic()` during the
|
|
||||||
// verifier pass.
|
|
||||||
assert!(branches.len() <= 2);
|
|
||||||
if branches.len() == 2 {
|
|
||||||
let op1 = ctx.data(branches[1]).opcode();
|
|
||||||
assert!(op1 == Opcode::Jump);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(temp_regs) = super::lower::isle::lower_branch(ctx, self, branches[0], targets) {
|
|
||||||
assert!(temp_regs.len() == 0);
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
|
|
||||||
unreachable!(
|
|
||||||
"not implemented in ISLE: branch = `{}`",
|
|
||||||
ctx.dfg().display_inst(branches[0]),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn maybe_pinned_reg(&self) -> Option<Reg> {
|
fn maybe_pinned_reg(&self) -> Option<Reg> {
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ pub(crate) fn lower_branch(
|
|||||||
backend: &AArch64Backend,
|
backend: &AArch64Backend,
|
||||||
branch: Inst,
|
branch: Inst,
|
||||||
targets: &[MachLabel],
|
targets: &[MachLabel],
|
||||||
) -> Option<InstOutput> {
|
) -> Option<()> {
|
||||||
// TODO: reuse the ISLE context across lowerings so we can reuse its
|
// TODO: reuse the ISLE context across lowerings so we can reuse its
|
||||||
// internal heap allocations.
|
// internal heap allocations.
|
||||||
let mut isle_ctx = IsleContext { lower_ctx, backend };
|
let mut isle_ctx = IsleContext { lower_ctx, backend };
|
||||||
|
|||||||
@@ -1865,22 +1865,22 @@
|
|||||||
(decl vec_label_get (VecMachLabel u8) MachLabel )
|
(decl vec_label_get (VecMachLabel u8) MachLabel )
|
||||||
(extern constructor vec_label_get vec_label_get)
|
(extern constructor vec_label_get vec_label_get)
|
||||||
|
|
||||||
(decl partial lower_branch (Inst VecMachLabel) InstOutput)
|
(decl partial lower_branch (Inst VecMachLabel) Unit)
|
||||||
(rule (lower_branch (jump _ _) targets )
|
(rule (lower_branch (jump _ _) targets )
|
||||||
(side_effect (SideEffectNoResult.Inst (gen_jump (vec_label_get targets 0)))))
|
(emit_side_effect (SideEffectNoResult.Inst (gen_jump (vec_label_get targets 0)))))
|
||||||
|
|
||||||
;;; cc a b targets Type
|
;;; cc a b targets Type
|
||||||
(decl lower_br_icmp (IntCC ValueRegs ValueRegs VecMachLabel Type) InstOutput)
|
(decl lower_br_icmp (IntCC ValueRegs ValueRegs VecMachLabel Type) Unit)
|
||||||
(extern constructor lower_br_icmp lower_br_icmp)
|
(extern constructor lower_br_icmp lower_br_icmp)
|
||||||
|
|
||||||
(decl lower_br_fcmp (FloatCC Reg Reg VecMachLabel Type) InstOutput)
|
(decl lower_br_fcmp (FloatCC Reg Reg VecMachLabel Type) Unit)
|
||||||
(extern constructor lower_br_fcmp lower_br_fcmp)
|
(extern constructor lower_br_fcmp lower_br_fcmp)
|
||||||
|
|
||||||
;; int scalar zero regs.
|
;; int scalar zero regs.
|
||||||
(decl int_zero_reg (Type) ValueRegs)
|
(decl int_zero_reg (Type) ValueRegs)
|
||||||
(extern constructor int_zero_reg int_zero_reg)
|
(extern constructor int_zero_reg int_zero_reg)
|
||||||
|
|
||||||
(decl lower_brz_or_nz (IntCC ValueRegs VecMachLabel Type) InstOutput)
|
(decl lower_brz_or_nz (IntCC ValueRegs VecMachLabel Type) Unit)
|
||||||
(extern constructor lower_brz_or_nz lower_brz_or_nz)
|
(extern constructor lower_brz_or_nz lower_brz_or_nz)
|
||||||
|
|
||||||
;; Normalize a value for comparision.
|
;; Normalize a value for comparision.
|
||||||
@@ -1940,7 +1940,7 @@
|
|||||||
(lower_br_fcmp cc a b targets ty))
|
(lower_br_fcmp cc a b targets ty))
|
||||||
|
|
||||||
;;;
|
;;;
|
||||||
(decl lower_br_table (Reg VecMachLabel) InstOutput)
|
(decl lower_br_table (Reg VecMachLabel) Unit)
|
||||||
(extern constructor lower_br_table lower_br_table)
|
(extern constructor lower_br_table lower_br_table)
|
||||||
|
|
||||||
(rule
|
(rule
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ use crate::isa::riscv64::inst::*;
|
|||||||
use crate::isa::riscv64::Riscv64Backend;
|
use crate::isa::riscv64::Riscv64Backend;
|
||||||
use crate::machinst::lower::*;
|
use crate::machinst::lower::*;
|
||||||
use crate::machinst::*;
|
use crate::machinst::*;
|
||||||
use crate::CodegenResult;
|
|
||||||
pub mod isle;
|
pub mod isle;
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
@@ -13,53 +12,17 @@ pub mod isle;
|
|||||||
impl LowerBackend for Riscv64Backend {
|
impl LowerBackend for Riscv64Backend {
|
||||||
type MInst = Inst;
|
type MInst = Inst;
|
||||||
|
|
||||||
fn lower(&self, ctx: &mut Lower<Inst>, ir_inst: IRInst) -> CodegenResult<InstOutput> {
|
fn lower(&self, ctx: &mut Lower<Inst>, ir_inst: IRInst) -> Option<InstOutput> {
|
||||||
if let Some(temp_regs) = super::lower::isle::lower(ctx, self, ir_inst) {
|
isle::lower(ctx, self, ir_inst)
|
||||||
return Ok(temp_regs);
|
|
||||||
}
|
|
||||||
|
|
||||||
let ty = if ctx.num_outputs(ir_inst) > 0 {
|
|
||||||
Some(ctx.output_ty(ir_inst, 0))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
unreachable!(
|
|
||||||
"not implemented in ISLE: inst = `{}`, type = `{:?}`",
|
|
||||||
ctx.dfg().display_inst(ir_inst),
|
|
||||||
ty
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lower_branch_group(
|
fn lower_branch(
|
||||||
&self,
|
&self,
|
||||||
ctx: &mut Lower<Inst>,
|
ctx: &mut Lower<Inst>,
|
||||||
branches: &[IRInst],
|
ir_inst: IRInst,
|
||||||
targets: &[MachLabel],
|
targets: &[MachLabel],
|
||||||
) -> CodegenResult<()> {
|
) -> Option<()> {
|
||||||
// A block should end with at most two branches. The first may be a
|
isle::lower_branch(ctx, self, ir_inst, targets)
|
||||||
// conditional branch; a conditional branch can be followed only by an
|
|
||||||
// unconditional branch or fallthrough. Otherwise, if only one branch,
|
|
||||||
// it may be an unconditional branch, a fallthrough, a return, or a
|
|
||||||
// trap. These conditions are verified by `is_ebb_basic()` during the
|
|
||||||
// verifier pass.
|
|
||||||
assert!(branches.len() <= 2);
|
|
||||||
if branches.len() == 2 {
|
|
||||||
let op1 = ctx.data(branches[1]).opcode();
|
|
||||||
assert!(op1 == Opcode::Jump);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Lower the first branch in ISLE. This will automatically handle
|
|
||||||
// the second branch (if any) by emitting a two-way conditional branch.
|
|
||||||
if let Some(temp_regs) = super::lower::isle::lower_branch(ctx, self, branches[0], targets) {
|
|
||||||
assert!(temp_regs.len() == 0);
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
|
|
||||||
unreachable!(
|
|
||||||
"not implemented in ISLE: branch = `{}`",
|
|
||||||
ctx.dfg().display_inst(branches[0]),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn maybe_pinned_reg(&self) -> Option<Reg> {
|
fn maybe_pinned_reg(&self) -> Option<Reg> {
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ impl generated_code::Context for IsleContext<'_, '_, MInst, Riscv64Backend> {
|
|||||||
b: Reg,
|
b: Reg,
|
||||||
targets: &VecMachLabel,
|
targets: &VecMachLabel,
|
||||||
ty: Type,
|
ty: Type,
|
||||||
) -> InstOutput {
|
) -> Unit {
|
||||||
let tmp = self.temp_writable_reg(I64);
|
let tmp = self.temp_writable_reg(I64);
|
||||||
MInst::lower_br_fcmp(
|
MInst::lower_br_fcmp(
|
||||||
*cc,
|
*cc,
|
||||||
@@ -81,7 +81,6 @@ impl generated_code::Context for IsleContext<'_, '_, MInst, Riscv64Backend> {
|
|||||||
)
|
)
|
||||||
.iter()
|
.iter()
|
||||||
.for_each(|i| self.emit(i));
|
.for_each(|i| self.emit(i));
|
||||||
InstOutput::default()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lower_brz_or_nz(
|
fn lower_brz_or_nz(
|
||||||
@@ -90,7 +89,7 @@ impl generated_code::Context for IsleContext<'_, '_, MInst, Riscv64Backend> {
|
|||||||
a: ValueRegs,
|
a: ValueRegs,
|
||||||
targets: &VecMachLabel,
|
targets: &VecMachLabel,
|
||||||
ty: Type,
|
ty: Type,
|
||||||
) -> InstOutput {
|
) -> Unit {
|
||||||
MInst::lower_br_icmp(
|
MInst::lower_br_icmp(
|
||||||
*cc,
|
*cc,
|
||||||
a,
|
a,
|
||||||
@@ -101,7 +100,6 @@ impl generated_code::Context for IsleContext<'_, '_, MInst, Riscv64Backend> {
|
|||||||
)
|
)
|
||||||
.iter()
|
.iter()
|
||||||
.for_each(|i| self.emit(i));
|
.for_each(|i| self.emit(i));
|
||||||
InstOutput::default()
|
|
||||||
}
|
}
|
||||||
fn lower_br_icmp(
|
fn lower_br_icmp(
|
||||||
&mut self,
|
&mut self,
|
||||||
@@ -110,7 +108,7 @@ impl generated_code::Context for IsleContext<'_, '_, MInst, Riscv64Backend> {
|
|||||||
b: ValueRegs,
|
b: ValueRegs,
|
||||||
targets: &VecMachLabel,
|
targets: &VecMachLabel,
|
||||||
ty: Type,
|
ty: Type,
|
||||||
) -> InstOutput {
|
) -> Unit {
|
||||||
let test = generated_code::constructor_lower_icmp(self, cc, a, b, ty);
|
let test = generated_code::constructor_lower_icmp(self, cc, a, b, ty);
|
||||||
self.emit(&MInst::CondBr {
|
self.emit(&MInst::CondBr {
|
||||||
taken: BranchTarget::Label(targets[0]),
|
taken: BranchTarget::Label(targets[0]),
|
||||||
@@ -121,7 +119,6 @@ impl generated_code::Context for IsleContext<'_, '_, MInst, Riscv64Backend> {
|
|||||||
rs2: zero_reg(),
|
rs2: zero_reg(),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
InstOutput::default()
|
|
||||||
}
|
}
|
||||||
fn load_ra(&mut self) -> Reg {
|
fn load_ra(&mut self) -> Reg {
|
||||||
if self.backend.flags.preserve_frame_pointers() {
|
if self.backend.flags.preserve_frame_pointers() {
|
||||||
@@ -397,7 +394,7 @@ impl generated_code::Context for IsleContext<'_, '_, MInst, Riscv64Backend> {
|
|||||||
tmp.to_reg()
|
tmp.to_reg()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lower_br_table(&mut self, index: Reg, targets: &VecMachLabel) -> InstOutput {
|
fn lower_br_table(&mut self, index: Reg, targets: &VecMachLabel) -> Unit {
|
||||||
let tmp1 = self.temp_writable_reg(I64);
|
let tmp1 = self.temp_writable_reg(I64);
|
||||||
let targets: Vec<BranchTarget> = targets
|
let targets: Vec<BranchTarget> = targets
|
||||||
.into_iter()
|
.into_iter()
|
||||||
@@ -409,7 +406,6 @@ impl generated_code::Context for IsleContext<'_, '_, MInst, Riscv64Backend> {
|
|||||||
tmp1,
|
tmp1,
|
||||||
targets,
|
targets,
|
||||||
});
|
});
|
||||||
InstOutput::default()
|
|
||||||
}
|
}
|
||||||
fn x_reg(&mut self, x: u8) -> Reg {
|
fn x_reg(&mut self, x: u8) -> Reg {
|
||||||
x_reg(x as usize)
|
x_reg(x as usize)
|
||||||
@@ -446,7 +442,7 @@ pub(crate) fn lower_branch(
|
|||||||
backend: &Riscv64Backend,
|
backend: &Riscv64Backend,
|
||||||
branch: Inst,
|
branch: Inst,
|
||||||
targets: &[MachLabel],
|
targets: &[MachLabel],
|
||||||
) -> Option<InstOutput> {
|
) -> Option<()> {
|
||||||
// TODO: reuse the ISLE context across lowerings so we can reuse its
|
// TODO: reuse the ISLE context across lowerings so we can reuse its
|
||||||
// internal heap allocations.
|
// internal heap allocations.
|
||||||
let mut isle_ctx = IsleContext { lower_ctx, backend };
|
let mut isle_ctx = IsleContext { lower_ctx, backend };
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
;; A variant of the main lowering constructor term, used for branches.
|
;; A variant of the main lowering constructor term, used for branches.
|
||||||
;; The only difference is that it gets an extra argument holding a vector
|
;; The only difference is that it gets an extra argument holding a vector
|
||||||
;; of branch targets to be used.
|
;; of branch targets to be used.
|
||||||
(decl partial lower_branch (Inst VecMachLabel) InstOutput)
|
(decl partial lower_branch (Inst VecMachLabel) Unit)
|
||||||
|
|
||||||
|
|
||||||
;;;; Rules for `iconst` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;; Rules for `iconst` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
@@ -3715,7 +3715,7 @@
|
|||||||
;; Unconditional branch. The target is found as first (and only) element in
|
;; Unconditional branch. The target is found as first (and only) element in
|
||||||
;; the list of the current block's branch targets passed as `targets`.
|
;; the list of the current block's branch targets passed as `targets`.
|
||||||
(rule (lower_branch (jump _ _) targets)
|
(rule (lower_branch (jump _ _) targets)
|
||||||
(side_effect (jump_impl (vec_element targets 0))))
|
(emit_side_effect (jump_impl (vec_element targets 0))))
|
||||||
|
|
||||||
|
|
||||||
;;;; Rules for `br_table` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;; Rules for `br_table` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
@@ -3731,8 +3731,8 @@
|
|||||||
(cond ProducesBool
|
(cond ProducesBool
|
||||||
(bool (icmpu_uimm32 $I64 idx (vec_length_minus1 targets))
|
(bool (icmpu_uimm32 $I64 idx (vec_length_minus1 targets))
|
||||||
(intcc_as_cond (IntCC.UnsignedGreaterThanOrEqual))))
|
(intcc_as_cond (IntCC.UnsignedGreaterThanOrEqual))))
|
||||||
(_ InstOutput (side_effect (oneway_cond_br_bool cond
|
(_ Unit (emit_side_effect (oneway_cond_br_bool cond
|
||||||
(vec_element targets 0)))))
|
(vec_element targets 0)))))
|
||||||
;; Scale the index by the element size, and then emit the
|
;; Scale the index by the element size, and then emit the
|
||||||
;; compound instruction that does:
|
;; compound instruction that does:
|
||||||
;;
|
;;
|
||||||
@@ -3747,7 +3747,7 @@
|
|||||||
;; PC-rel offset to the jumptable would be incorrect.
|
;; PC-rel offset to the jumptable would be incorrect.
|
||||||
;; (The alternative is to introduce a relocation pass
|
;; (The alternative is to introduce a relocation pass
|
||||||
;; for inlined jumptables, which is much worse, IMHO.)
|
;; for inlined jumptables, which is much worse, IMHO.)
|
||||||
(side_effect (jt_sequence (lshl_imm $I64 idx 2) targets))))
|
(emit_side_effect (jt_sequence (lshl_imm $I64 idx 2) targets))))
|
||||||
|
|
||||||
|
|
||||||
;;;; Rules for `brz` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;; Rules for `brz` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
@@ -3756,9 +3756,9 @@
|
|||||||
;; - element 0: target if the condition is true (i.e. value is zero)
|
;; - 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)
|
;; - element 1: target if the condition is false (i.e. value is nonzero)
|
||||||
(rule (lower_branch (brz val_cond _ _) targets)
|
(rule (lower_branch (brz val_cond _ _) targets)
|
||||||
(side_effect (cond_br_bool (invert_bool (value_nonzero val_cond))
|
(emit_side_effect (cond_br_bool (invert_bool (value_nonzero val_cond))
|
||||||
(vec_element targets 0)
|
(vec_element targets 0)
|
||||||
(vec_element targets 1))))
|
(vec_element targets 1))))
|
||||||
|
|
||||||
|
|
||||||
;;;; Rules for `brnz` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;; Rules for `brnz` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
@@ -3767,9 +3767,9 @@
|
|||||||
;; - element 0: target if the condition is true (i.e. value is nonzero)
|
;; - 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)
|
;; - element 1: target if the condition is false (i.e. value is zero)
|
||||||
(rule (lower_branch (brnz val_cond _ _) targets)
|
(rule (lower_branch (brnz val_cond _ _) targets)
|
||||||
(side_effect (cond_br_bool (value_nonzero val_cond)
|
(emit_side_effect (cond_br_bool (value_nonzero val_cond)
|
||||||
(vec_element targets 0)
|
(vec_element targets 0)
|
||||||
(vec_element targets 1))))
|
(vec_element targets 1))))
|
||||||
|
|
||||||
|
|
||||||
;;;; Rules for `trap` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;; Rules for `trap` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
//! Lowering rules for S390x.
|
//! Lowering rules for S390x.
|
||||||
|
|
||||||
use crate::ir::Inst as IRInst;
|
use crate::ir::Inst as IRInst;
|
||||||
use crate::ir::Opcode;
|
|
||||||
use crate::isa::s390x::inst::Inst;
|
use crate::isa::s390x::inst::Inst;
|
||||||
use crate::isa::s390x::S390xBackend;
|
use crate::isa::s390x::S390xBackend;
|
||||||
use crate::machinst::{InstOutput, Lower, LowerBackend, MachLabel};
|
use crate::machinst::{InstOutput, Lower, LowerBackend, MachLabel};
|
||||||
use crate::CodegenResult;
|
|
||||||
|
|
||||||
pub mod isle;
|
pub mod isle;
|
||||||
|
|
||||||
@@ -15,52 +13,16 @@ pub mod isle;
|
|||||||
impl LowerBackend for S390xBackend {
|
impl LowerBackend for S390xBackend {
|
||||||
type MInst = Inst;
|
type MInst = Inst;
|
||||||
|
|
||||||
fn lower(&self, ctx: &mut Lower<Inst>, ir_inst: IRInst) -> CodegenResult<InstOutput> {
|
fn lower(&self, ctx: &mut Lower<Inst>, ir_inst: IRInst) -> Option<InstOutput> {
|
||||||
if let Some(temp_regs) = super::lower::isle::lower(ctx, self, ir_inst) {
|
isle::lower(ctx, self, ir_inst)
|
||||||
return Ok(temp_regs);
|
|
||||||
}
|
|
||||||
|
|
||||||
let ty = if ctx.num_outputs(ir_inst) > 0 {
|
|
||||||
Some(ctx.output_ty(ir_inst, 0))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
unreachable!(
|
|
||||||
"not implemented in ISLE: inst = `{}`, type = `{:?}`",
|
|
||||||
ctx.dfg().display_inst(ir_inst),
|
|
||||||
ty
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lower_branch_group(
|
fn lower_branch(
|
||||||
&self,
|
&self,
|
||||||
ctx: &mut Lower<Inst>,
|
ctx: &mut Lower<Inst>,
|
||||||
branches: &[IRInst],
|
ir_inst: IRInst,
|
||||||
targets: &[MachLabel],
|
targets: &[MachLabel],
|
||||||
) -> CodegenResult<()> {
|
) -> Option<()> {
|
||||||
// A block should end with at most two branches. The first may be a
|
isle::lower_branch(ctx, self, ir_inst, targets)
|
||||||
// conditional branch; a conditional branch can be followed only by an
|
|
||||||
// unconditional branch or fallthrough. Otherwise, if only one branch,
|
|
||||||
// it may be an unconditional branch, a fallthrough, a return, or a
|
|
||||||
// trap. These conditions are verified by `is_ebb_basic()` during the
|
|
||||||
// verifier pass.
|
|
||||||
assert!(branches.len() <= 2);
|
|
||||||
if branches.len() == 2 {
|
|
||||||
let op1 = ctx.data(branches[1]).opcode();
|
|
||||||
assert!(op1 == Opcode::Jump);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Lower the first branch in ISLE. This will automatically handle
|
|
||||||
// the second branch (if any) by emitting a two-way conditional branch.
|
|
||||||
if let Some(temp_regs) = super::lower::isle::lower_branch(ctx, self, branches[0], targets) {
|
|
||||||
assert!(temp_regs.len() == 0);
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
|
|
||||||
unreachable!(
|
|
||||||
"not implemented in ISLE: branch = `{}`",
|
|
||||||
ctx.dfg().display_inst(branches[0]),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ pub(crate) fn lower_branch(
|
|||||||
backend: &S390xBackend,
|
backend: &S390xBackend,
|
||||||
branch: Inst,
|
branch: Inst,
|
||||||
targets: &[MachLabel],
|
targets: &[MachLabel],
|
||||||
) -> Option<InstOutput> {
|
) -> Option<()> {
|
||||||
// TODO: reuse the ISLE context across lowerings so we can reuse its
|
// TODO: reuse the ISLE context across lowerings so we can reuse its
|
||||||
// internal heap allocations.
|
// internal heap allocations.
|
||||||
let mut isle_ctx = IsleContext { lower_ctx, backend };
|
let mut isle_ctx = IsleContext { lower_ctx, backend };
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
;; A variant of the main lowering constructor term, used for branches.
|
;; A variant of the main lowering constructor term, used for branches.
|
||||||
;; The only difference is that it gets an extra argument holding a vector
|
;; The only difference is that it gets an extra argument holding a vector
|
||||||
;; of branch targets to be used.
|
;; of branch targets to be used.
|
||||||
(decl partial lower_branch (Inst MachLabelSlice) InstOutput)
|
(decl partial lower_branch (Inst MachLabelSlice) Unit)
|
||||||
|
|
||||||
;;;; Rules for `iconst` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;; Rules for `iconst` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
@@ -2865,55 +2865,55 @@
|
|||||||
;; Rules for `jump` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;; Rules for `jump` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
(rule (lower_branch (jump _ _) (single_target target))
|
(rule (lower_branch (jump _ _) (single_target target))
|
||||||
(side_effect (jmp_known target)))
|
(emit_side_effect (jmp_known target)))
|
||||||
|
|
||||||
;; Rules for `brz` and `brnz` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;; Rules for `brz` and `brnz` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
(rule 2 (lower_branch (brz (icmp cc a b) _ _) (two_targets taken not_taken))
|
(rule 2 (lower_branch (brz (icmp cc a b) _ _) (two_targets taken not_taken))
|
||||||
(let ((cmp IcmpCondResult (invert_icmp_cond_result (emit_cmp cc a b))))
|
(let ((cmp IcmpCondResult (invert_icmp_cond_result (emit_cmp cc a b))))
|
||||||
(side_effect (jmp_cond_icmp cmp taken not_taken))))
|
(emit_side_effect (jmp_cond_icmp cmp taken not_taken))))
|
||||||
|
|
||||||
(rule 2 (lower_branch (brz (uextend (icmp cc a b)) _ _) (two_targets taken not_taken))
|
(rule 2 (lower_branch (brz (uextend (icmp cc a b)) _ _) (two_targets taken not_taken))
|
||||||
(let ((cmp IcmpCondResult (invert_icmp_cond_result (emit_cmp cc a b))))
|
(let ((cmp IcmpCondResult (invert_icmp_cond_result (emit_cmp cc a b))))
|
||||||
(side_effect (jmp_cond_icmp cmp taken not_taken))))
|
(emit_side_effect (jmp_cond_icmp cmp taken not_taken))))
|
||||||
|
|
||||||
|
|
||||||
(rule 2 (lower_branch (brz (fcmp cc a b) _ _) (two_targets taken not_taken))
|
(rule 2 (lower_branch (brz (fcmp cc a b) _ _) (two_targets taken not_taken))
|
||||||
(let ((cmp FcmpCondResult (emit_fcmp (floatcc_inverse cc) a b)))
|
(let ((cmp FcmpCondResult (emit_fcmp (floatcc_inverse cc) a b)))
|
||||||
(side_effect (jmp_cond_fcmp cmp taken not_taken))))
|
(emit_side_effect (jmp_cond_fcmp cmp taken not_taken))))
|
||||||
|
|
||||||
(rule 2 (lower_branch (brz (uextend (fcmp cc a b)) _ _) (two_targets taken not_taken))
|
(rule 2 (lower_branch (brz (uextend (fcmp cc a b)) _ _) (two_targets taken not_taken))
|
||||||
(let ((cmp FcmpCondResult (emit_fcmp (floatcc_inverse cc) a b)))
|
(let ((cmp FcmpCondResult (emit_fcmp (floatcc_inverse cc) a b)))
|
||||||
(side_effect (jmp_cond_fcmp cmp taken not_taken))))
|
(emit_side_effect (jmp_cond_fcmp cmp taken not_taken))))
|
||||||
|
|
||||||
(rule 1 (lower_branch (brz val @ (value_type $I128) _ _) (two_targets taken not_taken))
|
(rule 1 (lower_branch (brz val @ (value_type $I128) _ _) (two_targets taken not_taken))
|
||||||
(side_effect (jmp_cond_icmp (cmp_zero_i128 (CC.NZ) val) taken not_taken)))
|
(emit_side_effect (jmp_cond_icmp (cmp_zero_i128 (CC.NZ) val) taken not_taken)))
|
||||||
|
|
||||||
(rule 0 (lower_branch (brz val @ (value_type (ty_int_bool_or_ref)) _ _) (two_targets taken not_taken))
|
(rule 0 (lower_branch (brz val @ (value_type (ty_int_bool_or_ref)) _ _) (two_targets taken not_taken))
|
||||||
(side_effect
|
(emit_side_effect
|
||||||
(with_flags_side_effect (cmp_zero_int_bool_ref val)
|
(with_flags_side_effect (cmp_zero_int_bool_ref val)
|
||||||
(jmp_cond (CC.Z) taken not_taken))))
|
(jmp_cond (CC.Z) taken not_taken))))
|
||||||
|
|
||||||
|
|
||||||
(rule 2 (lower_branch (brnz (icmp cc a b) _ _) (two_targets taken not_taken))
|
(rule 2 (lower_branch (brnz (icmp cc a b) _ _) (two_targets taken not_taken))
|
||||||
(side_effect (jmp_cond_icmp (emit_cmp cc a b) taken not_taken)))
|
(emit_side_effect (jmp_cond_icmp (emit_cmp cc a b) taken not_taken)))
|
||||||
|
|
||||||
(rule 2 (lower_branch (brnz (fcmp cc a b) _ _) (two_targets taken not_taken))
|
(rule 2 (lower_branch (brnz (fcmp cc a b) _ _) (two_targets taken not_taken))
|
||||||
(let ((cmp FcmpCondResult (emit_fcmp cc a b)))
|
(let ((cmp FcmpCondResult (emit_fcmp cc a b)))
|
||||||
(side_effect (jmp_cond_fcmp cmp taken not_taken))))
|
(emit_side_effect (jmp_cond_fcmp cmp taken not_taken))))
|
||||||
|
|
||||||
(rule 2 (lower_branch (brnz (uextend (icmp cc a b)) _ _) (two_targets taken not_taken))
|
(rule 2 (lower_branch (brnz (uextend (icmp cc a b)) _ _) (two_targets taken not_taken))
|
||||||
(side_effect (jmp_cond_icmp (emit_cmp cc a b) taken not_taken)))
|
(emit_side_effect (jmp_cond_icmp (emit_cmp cc a b) taken not_taken)))
|
||||||
|
|
||||||
(rule 2 (lower_branch (brnz (uextend (fcmp cc a b)) _ _) (two_targets taken not_taken))
|
(rule 2 (lower_branch (brnz (uextend (fcmp cc a b)) _ _) (two_targets taken not_taken))
|
||||||
(let ((cmp FcmpCondResult (emit_fcmp cc a b)))
|
(let ((cmp FcmpCondResult (emit_fcmp cc a b)))
|
||||||
(side_effect (jmp_cond_fcmp cmp taken not_taken))))
|
(emit_side_effect (jmp_cond_fcmp cmp taken not_taken))))
|
||||||
|
|
||||||
(rule 1 (lower_branch (brnz val @ (value_type $I128) _ _) (two_targets taken not_taken))
|
(rule 1 (lower_branch (brnz val @ (value_type $I128) _ _) (two_targets taken not_taken))
|
||||||
(side_effect (jmp_cond_icmp (cmp_zero_i128 (CC.Z) val) taken not_taken)))
|
(emit_side_effect (jmp_cond_icmp (cmp_zero_i128 (CC.Z) val) taken not_taken)))
|
||||||
|
|
||||||
(rule 0 (lower_branch (brnz val @ (value_type (ty_int_bool_or_ref)) _ _) (two_targets taken not_taken))
|
(rule 0 (lower_branch (brnz val @ (value_type (ty_int_bool_or_ref)) _ _) (two_targets taken not_taken))
|
||||||
(side_effect
|
(emit_side_effect
|
||||||
(with_flags_side_effect (cmp_zero_int_bool_ref val)
|
(with_flags_side_effect (cmp_zero_int_bool_ref val)
|
||||||
(jmp_cond (CC.NZ) taken not_taken))))
|
(jmp_cond (CC.NZ) taken not_taken))))
|
||||||
|
|
||||||
@@ -2944,7 +2944,7 @@
|
|||||||
;; Rules for `br_table` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;; Rules for `br_table` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
(rule (lower_branch (br_table idx @ (value_type ty) _ _) (jump_table_targets default_target jt_targets))
|
(rule (lower_branch (br_table idx @ (value_type ty) _ _) (jump_table_targets default_target jt_targets))
|
||||||
(side_effect (jmp_table_seq ty idx default_target jt_targets)))
|
(emit_side_effect (jmp_table_seq ty idx default_target jt_targets)))
|
||||||
|
|
||||||
;; Rules for `select_spectre_guard` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;; Rules for `select_spectre_guard` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
|
|||||||
@@ -299,51 +299,17 @@ fn lower_to_amode(ctx: &mut Lower<Inst>, spec: InsnInput, offset: i32) -> Amode
|
|||||||
impl LowerBackend for X64Backend {
|
impl LowerBackend for X64Backend {
|
||||||
type MInst = Inst;
|
type MInst = Inst;
|
||||||
|
|
||||||
fn lower(&self, ctx: &mut Lower<Inst>, ir_inst: IRInst) -> CodegenResult<InstOutput> {
|
fn lower(&self, ctx: &mut Lower<Inst>, ir_inst: IRInst) -> Option<InstOutput> {
|
||||||
if let Some(temp_regs) = isle::lower(ctx, self, ir_inst) {
|
isle::lower(ctx, self, ir_inst)
|
||||||
return Ok(temp_regs);
|
|
||||||
}
|
|
||||||
|
|
||||||
let ty = if ctx.num_outputs(ir_inst) > 0 {
|
|
||||||
Some(ctx.output_ty(ir_inst, 0))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
unreachable!(
|
|
||||||
"not implemented in ISLE: inst = `{}`, type = `{:?}`",
|
|
||||||
ctx.dfg().display_inst(ir_inst),
|
|
||||||
ty
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lower_branch_group(
|
fn lower_branch(
|
||||||
&self,
|
&self,
|
||||||
ctx: &mut Lower<Inst>,
|
ctx: &mut Lower<Inst>,
|
||||||
branches: &[IRInst],
|
ir_inst: IRInst,
|
||||||
targets: &[MachLabel],
|
targets: &[MachLabel],
|
||||||
) -> CodegenResult<()> {
|
) -> Option<()> {
|
||||||
// A block should end with at most two branches. The first may be a
|
isle::lower_branch(ctx, self, ir_inst, targets)
|
||||||
// conditional branch; a conditional branch can be followed only by an
|
|
||||||
// unconditional branch or fallthrough. Otherwise, if only one branch,
|
|
||||||
// it may be an unconditional branch, a fallthrough, a return, or a
|
|
||||||
// trap. These conditions are verified by `is_ebb_basic()` during the
|
|
||||||
// verifier pass.
|
|
||||||
assert!(branches.len() <= 2);
|
|
||||||
if branches.len() == 2 {
|
|
||||||
let op1 = ctx.data(branches[1]).opcode();
|
|
||||||
assert!(op1 == Opcode::Jump);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(temp_regs) = isle::lower_branch(ctx, self, branches[0], targets) {
|
|
||||||
assert!(temp_regs.len() == 0);
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
|
|
||||||
unreachable!(
|
|
||||||
"not implemented in ISLE: branch = `{}`",
|
|
||||||
ctx.dfg().display_inst(branches[0]),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn maybe_pinned_reg(&self) -> Option<Reg> {
|
fn maybe_pinned_reg(&self) -> Option<Reg> {
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ pub(crate) fn lower_branch(
|
|||||||
backend: &X64Backend,
|
backend: &X64Backend,
|
||||||
branch: Inst,
|
branch: Inst,
|
||||||
targets: &[MachLabel],
|
targets: &[MachLabel],
|
||||||
) -> Option<InstOutput> {
|
) -> Option<()> {
|
||||||
// TODO: reuse the ISLE context across lowerings so we can reuse its
|
// TODO: reuse the ISLE context across lowerings so we can reuse its
|
||||||
// internal heap allocations.
|
// internal heap allocations.
|
||||||
let mut isle_ctx = IsleContext { lower_ctx, backend };
|
let mut isle_ctx = IsleContext { lower_ctx, backend };
|
||||||
|
|||||||
@@ -140,7 +140,7 @@ macro_rules! isle_lower_prelude_methods {
|
|||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
if let Some(insn) = insn {
|
if let Some(insn) = insn {
|
||||||
if let Ok(regs) = self.backend.lower(self.lower_ctx, insn) {
|
if let Some(regs) = self.backend.lower(self.lower_ctx, insn) {
|
||||||
assert!(regs.len() == 1);
|
assert!(regs.len() == 1);
|
||||||
return regs[0];
|
return regs[0];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -122,18 +122,22 @@ pub trait LowerBackend {
|
|||||||
/// For a branch, this function should not generate the actual branch
|
/// For a branch, this function should not generate the actual branch
|
||||||
/// instruction. However, it must force any values it needs for the branch
|
/// instruction. However, it must force any values it needs for the branch
|
||||||
/// edge (block-param actuals) into registers, because the actual branch
|
/// edge (block-param actuals) into registers, because the actual branch
|
||||||
/// generation (`lower_branch_group()`) happens *after* any possible merged
|
/// generation (`lower_branch()`) happens *after* any possible merged
|
||||||
/// out-edge.
|
/// out-edge.
|
||||||
fn lower(&self, ctx: &mut Lower<Self::MInst>, inst: Inst) -> CodegenResult<InstOutput>;
|
///
|
||||||
|
/// Returns `None` if no lowering for the instruction was found.
|
||||||
|
fn lower(&self, ctx: &mut Lower<Self::MInst>, inst: Inst) -> Option<InstOutput>;
|
||||||
|
|
||||||
/// Lower a block-terminating group of branches (which together can be seen
|
/// Lower a block-terminating group of branches (which together can be seen
|
||||||
/// as one N-way branch), given a vcode MachLabel for each target.
|
/// as one N-way branch), given a vcode MachLabel for each target.
|
||||||
fn lower_branch_group(
|
///
|
||||||
|
/// Returns `None` if no lowering for the branch was found.
|
||||||
|
fn lower_branch(
|
||||||
&self,
|
&self,
|
||||||
ctx: &mut Lower<Self::MInst>,
|
ctx: &mut Lower<Self::MInst>,
|
||||||
insts: &[Inst],
|
inst: Inst,
|
||||||
targets: &[MachLabel],
|
targets: &[MachLabel],
|
||||||
) -> CodegenResult<()>;
|
) -> Option<()>;
|
||||||
|
|
||||||
/// A bit of a hack: give a fixed register that always holds the result of a
|
/// A bit of a hack: give a fixed register that always holds the result of a
|
||||||
/// `get_pinned_reg` instruction, if known. This allows elision of moves
|
/// `get_pinned_reg` instruction, if known. This allows elision of moves
|
||||||
@@ -740,7 +744,18 @@ impl<'func, I: VCodeInst> Lower<'func, I> {
|
|||||||
// or any of its outputs its used.
|
// or any of its outputs its used.
|
||||||
if has_side_effect || value_needed {
|
if has_side_effect || value_needed {
|
||||||
trace!("lowering: inst {}: {:?}", inst, self.f.dfg[inst]);
|
trace!("lowering: inst {}: {:?}", inst, self.f.dfg[inst]);
|
||||||
let temp_regs = backend.lower(self, inst)?;
|
let temp_regs = backend.lower(self, inst).unwrap_or_else(|| {
|
||||||
|
let ty = if self.num_outputs(inst) > 0 {
|
||||||
|
Some(self.output_ty(inst, 0))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
panic!(
|
||||||
|
"should be implemented in ISLE: inst = `{}`, type = `{:?}`",
|
||||||
|
self.f.dfg.display_inst(inst),
|
||||||
|
ty
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
// The ISLE generated code emits its own registers to define the
|
// The ISLE generated code emits its own registers to define the
|
||||||
// instruction's lowered values in. However, other instructions
|
// instruction's lowered values in. However, other instructions
|
||||||
@@ -895,10 +910,29 @@ impl<'func, I: VCodeInst> Lower<'func, I> {
|
|||||||
branches,
|
branches,
|
||||||
targets,
|
targets,
|
||||||
);
|
);
|
||||||
|
// A block should end with at most two branches. The first may be a
|
||||||
|
// conditional branch; a conditional branch can be followed only by an
|
||||||
|
// unconditional branch or fallthrough. Otherwise, if only one branch,
|
||||||
|
// it may be an unconditional branch, a fallthrough, a return, or a
|
||||||
|
// trap. These conditions are verified by `is_ebb_basic()` during the
|
||||||
|
// verifier pass.
|
||||||
|
assert!(branches.len() <= 2);
|
||||||
|
if branches.len() == 2 {
|
||||||
|
assert!(self.data(branches[1]).opcode() == Opcode::Jump);
|
||||||
|
}
|
||||||
// When considering code-motion opportunities, consider the current
|
// When considering code-motion opportunities, consider the current
|
||||||
// program point to be the first branch.
|
// program point to be the first branch.
|
||||||
self.cur_inst = Some(branches[0]);
|
self.cur_inst = Some(branches[0]);
|
||||||
backend.lower_branch_group(self, branches, targets)?;
|
// Lower the first branch in ISLE. This will automatically handle
|
||||||
|
// the second branch (if any) by emitting a two-way conditional branch.
|
||||||
|
backend
|
||||||
|
.lower_branch(self, branches[0], targets)
|
||||||
|
.unwrap_or_else(|| {
|
||||||
|
panic!(
|
||||||
|
"should be implemented in ISLE: branch = `{}`",
|
||||||
|
self.f.dfg.display_inst(branches[0]),
|
||||||
|
)
|
||||||
|
});
|
||||||
let loc = self.srcloc(branches[0]);
|
let loc = self.srcloc(branches[0]);
|
||||||
self.finish_ir_inst(loc);
|
self.finish_ir_inst(loc);
|
||||||
// Add block param outputs for current block.
|
// Add block param outputs for current block.
|
||||||
|
|||||||
@@ -282,20 +282,23 @@
|
|||||||
(inst2 MInst)
|
(inst2 MInst)
|
||||||
(inst3 MInst))))
|
(inst3 MInst))))
|
||||||
|
|
||||||
|
;; Emit given side-effectful instruction.
|
||||||
|
(decl emit_side_effect (SideEffectNoResult) Unit)
|
||||||
|
(rule (emit_side_effect (SideEffectNoResult.Inst inst))
|
||||||
|
(emit inst))
|
||||||
|
(rule (emit_side_effect (SideEffectNoResult.Inst2 inst1 inst2))
|
||||||
|
(let ((_ Unit (emit inst1)))
|
||||||
|
(emit inst2)))
|
||||||
|
(rule (emit_side_effect (SideEffectNoResult.Inst3 inst1 inst2 inst3))
|
||||||
|
(let ((_ Unit (emit inst1))
|
||||||
|
(_ Unit (emit inst2)))
|
||||||
|
(emit inst3)))
|
||||||
|
|
||||||
;; Create an empty `InstOutput`, but do emit the given side-effectful
|
;; Create an empty `InstOutput`, but do emit the given side-effectful
|
||||||
;; instruction.
|
;; instruction.
|
||||||
(decl side_effect (SideEffectNoResult) InstOutput)
|
(decl side_effect (SideEffectNoResult) InstOutput)
|
||||||
(rule (side_effect (SideEffectNoResult.Inst inst))
|
(rule (side_effect inst)
|
||||||
(let ((_ Unit (emit inst)))
|
(let ((_ Unit (emit_side_effect inst)))
|
||||||
(output_none)))
|
|
||||||
(rule (side_effect (SideEffectNoResult.Inst2 inst1 inst2))
|
|
||||||
(let ((_ Unit (emit inst1))
|
|
||||||
(_ Unit (emit inst2)))
|
|
||||||
(output_none)))
|
|
||||||
(rule (side_effect (SideEffectNoResult.Inst3 inst1 inst2 inst3))
|
|
||||||
(let ((_ Unit (emit inst1))
|
|
||||||
(_ Unit (emit inst2))
|
|
||||||
(_ Unit (emit inst3)))
|
|
||||||
(output_none)))
|
(output_none)))
|
||||||
|
|
||||||
(decl side_effect_concat (SideEffectNoResult SideEffectNoResult) SideEffectNoResult)
|
(decl side_effect_concat (SideEffectNoResult SideEffectNoResult) SideEffectNoResult)
|
||||||
|
|||||||
Reference in New Issue
Block a user