machinst: allow passing constant information to the instruction emitter;
A new associated type Info is added to MachInstEmit, which is the immutable counterpart to State. It can't easily be constructed from an ABICallee, since it would require adding an associated type to the latter, and making so leaks the associated type in a lot of places in the code base and makes the code harder to read. Instead, the EmitInfo state can simply be passed to the `Vcode::emit` function directly.
This commit is contained in:
@@ -1421,7 +1421,7 @@ impl MachBranch {
|
||||
mod test {
|
||||
use super::*;
|
||||
use crate::isa::aarch64::inst::xreg;
|
||||
use crate::isa::aarch64::inst::{BranchTarget, CondBrKind, Inst};
|
||||
use crate::isa::aarch64::inst::{BranchTarget, CondBrKind, EmitInfo, Inst};
|
||||
use crate::machinst::MachInstEmit;
|
||||
use crate::settings;
|
||||
use std::default::Default;
|
||||
@@ -1435,14 +1435,14 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_elide_jump_to_next() {
|
||||
let flags = settings::Flags::new(settings::builder());
|
||||
let info = EmitInfo::new(settings::Flags::new(settings::builder()));
|
||||
let mut buf = MachBuffer::new();
|
||||
let mut state = Default::default();
|
||||
|
||||
buf.reserve_labels_for_blocks(2);
|
||||
buf.bind_label(label(0));
|
||||
let inst = Inst::Jump { dest: target(1) };
|
||||
inst.emit(&mut buf, &flags, &mut state);
|
||||
inst.emit(&mut buf, &info, &mut state);
|
||||
buf.bind_label(label(1));
|
||||
let buf = buf.finish();
|
||||
assert_eq!(0, buf.total_size());
|
||||
@@ -1450,7 +1450,7 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_elide_trivial_jump_blocks() {
|
||||
let flags = settings::Flags::new(settings::builder());
|
||||
let info = EmitInfo::new(settings::Flags::new(settings::builder()));
|
||||
let mut buf = MachBuffer::new();
|
||||
let mut state = Default::default();
|
||||
|
||||
@@ -1462,15 +1462,15 @@ mod test {
|
||||
taken: target(1),
|
||||
not_taken: target(2),
|
||||
};
|
||||
inst.emit(&mut buf, &flags, &mut state);
|
||||
inst.emit(&mut buf, &info, &mut state);
|
||||
|
||||
buf.bind_label(label(1));
|
||||
let inst = Inst::Jump { dest: target(3) };
|
||||
inst.emit(&mut buf, &flags, &mut state);
|
||||
inst.emit(&mut buf, &info, &mut state);
|
||||
|
||||
buf.bind_label(label(2));
|
||||
let inst = Inst::Jump { dest: target(3) };
|
||||
inst.emit(&mut buf, &flags, &mut state);
|
||||
inst.emit(&mut buf, &info, &mut state);
|
||||
|
||||
buf.bind_label(label(3));
|
||||
|
||||
@@ -1480,7 +1480,7 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_flip_cond() {
|
||||
let flags = settings::Flags::new(settings::builder());
|
||||
let info = EmitInfo::new(settings::Flags::new(settings::builder()));
|
||||
let mut buf = MachBuffer::new();
|
||||
let mut state = Default::default();
|
||||
|
||||
@@ -1492,17 +1492,17 @@ mod test {
|
||||
taken: target(1),
|
||||
not_taken: target(2),
|
||||
};
|
||||
inst.emit(&mut buf, &flags, &mut state);
|
||||
inst.emit(&mut buf, &info, &mut state);
|
||||
|
||||
buf.bind_label(label(1));
|
||||
let inst = Inst::Udf {
|
||||
trap_info: (SourceLoc::default(), TrapCode::Interrupt),
|
||||
};
|
||||
inst.emit(&mut buf, &flags, &mut state);
|
||||
inst.emit(&mut buf, &info, &mut state);
|
||||
|
||||
buf.bind_label(label(2));
|
||||
let inst = Inst::Nop4;
|
||||
inst.emit(&mut buf, &flags, &mut state);
|
||||
inst.emit(&mut buf, &info, &mut state);
|
||||
|
||||
buf.bind_label(label(3));
|
||||
|
||||
@@ -1514,9 +1514,9 @@ mod test {
|
||||
kind: CondBrKind::NotZero(xreg(0)),
|
||||
trap_info: (SourceLoc::default(), TrapCode::Interrupt),
|
||||
};
|
||||
inst.emit(&mut buf2, &flags, &mut state);
|
||||
inst.emit(&mut buf2, &info, &mut state);
|
||||
let inst = Inst::Nop4;
|
||||
inst.emit(&mut buf2, &flags, &mut state);
|
||||
inst.emit(&mut buf2, &info, &mut state);
|
||||
|
||||
let buf2 = buf2.finish();
|
||||
|
||||
@@ -1525,7 +1525,7 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_island() {
|
||||
let flags = settings::Flags::new(settings::builder());
|
||||
let info = EmitInfo::new(settings::Flags::new(settings::builder()));
|
||||
let mut buf = MachBuffer::new();
|
||||
let mut state = Default::default();
|
||||
|
||||
@@ -1537,7 +1537,7 @@ mod test {
|
||||
taken: target(2),
|
||||
not_taken: target(3),
|
||||
};
|
||||
inst.emit(&mut buf, &flags, &mut state);
|
||||
inst.emit(&mut buf, &info, &mut state);
|
||||
|
||||
buf.bind_label(label(1));
|
||||
while buf.cur_offset() < 2000000 {
|
||||
@@ -1545,16 +1545,16 @@ mod test {
|
||||
buf.emit_island();
|
||||
}
|
||||
let inst = Inst::Nop4;
|
||||
inst.emit(&mut buf, &flags, &mut state);
|
||||
inst.emit(&mut buf, &info, &mut state);
|
||||
}
|
||||
|
||||
buf.bind_label(label(2));
|
||||
let inst = Inst::Nop4;
|
||||
inst.emit(&mut buf, &flags, &mut state);
|
||||
inst.emit(&mut buf, &info, &mut state);
|
||||
|
||||
buf.bind_label(label(3));
|
||||
let inst = Inst::Nop4;
|
||||
inst.emit(&mut buf, &flags, &mut state);
|
||||
inst.emit(&mut buf, &info, &mut state);
|
||||
|
||||
let buf = buf.finish();
|
||||
|
||||
@@ -1567,7 +1567,7 @@ mod test {
|
||||
taken: BranchTarget::ResolvedOffset(1048576 - 4),
|
||||
not_taken: BranchTarget::ResolvedOffset(2000000 + 4 - 4),
|
||||
};
|
||||
inst.emit(&mut buf2, &flags, &mut state);
|
||||
inst.emit(&mut buf2, &info, &mut state);
|
||||
|
||||
let buf2 = buf2.finish();
|
||||
|
||||
@@ -1576,7 +1576,7 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_island_backward() {
|
||||
let flags = settings::Flags::new(settings::builder());
|
||||
let info = EmitInfo::new(settings::Flags::new(settings::builder()));
|
||||
let mut buf = MachBuffer::new();
|
||||
let mut state = Default::default();
|
||||
|
||||
@@ -1584,16 +1584,16 @@ mod test {
|
||||
|
||||
buf.bind_label(label(0));
|
||||
let inst = Inst::Nop4;
|
||||
inst.emit(&mut buf, &flags, &mut state);
|
||||
inst.emit(&mut buf, &info, &mut state);
|
||||
|
||||
buf.bind_label(label(1));
|
||||
let inst = Inst::Nop4;
|
||||
inst.emit(&mut buf, &flags, &mut state);
|
||||
inst.emit(&mut buf, &info, &mut state);
|
||||
|
||||
buf.bind_label(label(2));
|
||||
while buf.cur_offset() < 2000000 {
|
||||
let inst = Inst::Nop4;
|
||||
inst.emit(&mut buf, &flags, &mut state);
|
||||
inst.emit(&mut buf, &info, &mut state);
|
||||
}
|
||||
|
||||
buf.bind_label(label(3));
|
||||
@@ -1602,7 +1602,7 @@ mod test {
|
||||
taken: target(0),
|
||||
not_taken: target(1),
|
||||
};
|
||||
inst.emit(&mut buf, &flags, &mut state);
|
||||
inst.emit(&mut buf, &info, &mut state);
|
||||
|
||||
let buf = buf.finish();
|
||||
|
||||
@@ -1615,11 +1615,11 @@ mod test {
|
||||
taken: BranchTarget::ResolvedOffset(8),
|
||||
not_taken: BranchTarget::ResolvedOffset(4 - (2000000 + 4)),
|
||||
};
|
||||
inst.emit(&mut buf2, &flags, &mut state);
|
||||
inst.emit(&mut buf2, &info, &mut state);
|
||||
let inst = Inst::Jump {
|
||||
dest: BranchTarget::ResolvedOffset(-(2000000 + 8)),
|
||||
};
|
||||
inst.emit(&mut buf2, &flags, &mut state);
|
||||
inst.emit(&mut buf2, &info, &mut state);
|
||||
|
||||
let buf2 = buf2.finish();
|
||||
|
||||
@@ -1661,7 +1661,7 @@ mod test {
|
||||
// label7:
|
||||
// ret
|
||||
|
||||
let flags = settings::Flags::new(settings::builder());
|
||||
let info = EmitInfo::new(settings::Flags::new(settings::builder()));
|
||||
let mut buf = MachBuffer::new();
|
||||
let mut state = Default::default();
|
||||
|
||||
@@ -1673,38 +1673,38 @@ mod test {
|
||||
taken: target(1),
|
||||
not_taken: target(2),
|
||||
};
|
||||
inst.emit(&mut buf, &flags, &mut state);
|
||||
inst.emit(&mut buf, &info, &mut state);
|
||||
|
||||
buf.bind_label(label(1));
|
||||
let inst = Inst::Jump { dest: target(3) };
|
||||
inst.emit(&mut buf, &flags, &mut state);
|
||||
inst.emit(&mut buf, &info, &mut state);
|
||||
|
||||
buf.bind_label(label(2));
|
||||
let inst = Inst::Nop4;
|
||||
inst.emit(&mut buf, &flags, &mut state);
|
||||
inst.emit(&mut buf, &flags, &mut state);
|
||||
inst.emit(&mut buf, &info, &mut state);
|
||||
inst.emit(&mut buf, &info, &mut state);
|
||||
let inst = Inst::Jump { dest: target(0) };
|
||||
inst.emit(&mut buf, &flags, &mut state);
|
||||
inst.emit(&mut buf, &info, &mut state);
|
||||
|
||||
buf.bind_label(label(3));
|
||||
let inst = Inst::Jump { dest: target(4) };
|
||||
inst.emit(&mut buf, &flags, &mut state);
|
||||
inst.emit(&mut buf, &info, &mut state);
|
||||
|
||||
buf.bind_label(label(4));
|
||||
let inst = Inst::Jump { dest: target(5) };
|
||||
inst.emit(&mut buf, &flags, &mut state);
|
||||
inst.emit(&mut buf, &info, &mut state);
|
||||
|
||||
buf.bind_label(label(5));
|
||||
let inst = Inst::Jump { dest: target(7) };
|
||||
inst.emit(&mut buf, &flags, &mut state);
|
||||
inst.emit(&mut buf, &info, &mut state);
|
||||
|
||||
buf.bind_label(label(6));
|
||||
let inst = Inst::Nop4;
|
||||
inst.emit(&mut buf, &flags, &mut state);
|
||||
inst.emit(&mut buf, &info, &mut state);
|
||||
|
||||
buf.bind_label(label(7));
|
||||
let inst = Inst::Ret;
|
||||
inst.emit(&mut buf, &flags, &mut state);
|
||||
inst.emit(&mut buf, &info, &mut state);
|
||||
|
||||
let buf = buf.finish();
|
||||
|
||||
@@ -1737,7 +1737,7 @@ mod test {
|
||||
//
|
||||
// label0, label1, ..., label4:
|
||||
// b label0
|
||||
let flags = settings::Flags::new(settings::builder());
|
||||
let info = EmitInfo::new(settings::Flags::new(settings::builder()));
|
||||
let mut buf = MachBuffer::new();
|
||||
let mut state = Default::default();
|
||||
|
||||
@@ -1745,23 +1745,23 @@ mod test {
|
||||
|
||||
buf.bind_label(label(0));
|
||||
let inst = Inst::Jump { dest: target(1) };
|
||||
inst.emit(&mut buf, &flags, &mut state);
|
||||
inst.emit(&mut buf, &info, &mut state);
|
||||
|
||||
buf.bind_label(label(1));
|
||||
let inst = Inst::Jump { dest: target(2) };
|
||||
inst.emit(&mut buf, &flags, &mut state);
|
||||
inst.emit(&mut buf, &info, &mut state);
|
||||
|
||||
buf.bind_label(label(2));
|
||||
let inst = Inst::Jump { dest: target(3) };
|
||||
inst.emit(&mut buf, &flags, &mut state);
|
||||
inst.emit(&mut buf, &info, &mut state);
|
||||
|
||||
buf.bind_label(label(3));
|
||||
let inst = Inst::Jump { dest: target(4) };
|
||||
inst.emit(&mut buf, &flags, &mut state);
|
||||
inst.emit(&mut buf, &info, &mut state);
|
||||
|
||||
buf.bind_label(label(4));
|
||||
let inst = Inst::Jump { dest: target(1) };
|
||||
inst.emit(&mut buf, &flags, &mut state);
|
||||
inst.emit(&mut buf, &info, &mut state);
|
||||
|
||||
let buf = buf.finish();
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ pub fn compile<B: LowerBackend + MachBackend>(
|
||||
f: &Function,
|
||||
b: &B,
|
||||
abi: Box<dyn ABICallee<I = B::MInst>>,
|
||||
emit_info: <B::MInst as MachInstEmit>::Info,
|
||||
) -> CodegenResult<VCode<B::MInst>>
|
||||
where
|
||||
B::MInst: PrettyPrint,
|
||||
@@ -21,7 +22,7 @@ where
|
||||
// Compute lowered block order.
|
||||
let block_order = BlockLoweringOrder::new(f);
|
||||
// Build the lowering context.
|
||||
let lower = Lower::new(f, abi, block_order)?;
|
||||
let lower = Lower::new(f, abi, emit_info, block_order)?;
|
||||
// Lower the IR.
|
||||
let (mut vcode, stack_map_request_info) = {
|
||||
let _tt = timing::vcode_lower();
|
||||
|
||||
@@ -315,9 +315,10 @@ impl<'func, I: VCodeInst> Lower<'func, I> {
|
||||
pub fn new(
|
||||
f: &'func Function,
|
||||
abi: Box<dyn ABICallee<I = I>>,
|
||||
emit_info: I::Info,
|
||||
block_order: BlockLoweringOrder,
|
||||
) -> CodegenResult<Lower<'func, I>> {
|
||||
let mut vcode = VCodeBuilder::new(abi, block_order);
|
||||
let mut vcode = VCodeBuilder::new(abi, emit_info, block_order);
|
||||
|
||||
let mut next_vreg: u32 = 0;
|
||||
|
||||
|
||||
@@ -275,12 +275,21 @@ pub enum MachTerminator<'a> {
|
||||
pub trait MachInstEmit: MachInst {
|
||||
/// Persistent state carried across `emit` invocations.
|
||||
type State: MachInstEmitState<Self>;
|
||||
/// Constant information used in `emit` invocations.
|
||||
type Info: MachInstEmitInfo;
|
||||
/// Emit the instruction.
|
||||
fn emit(&self, code: &mut MachBuffer<Self>, flags: &Flags, state: &mut Self::State);
|
||||
fn emit(&self, code: &mut MachBuffer<Self>, info: &Self::Info, state: &mut Self::State);
|
||||
/// Pretty-print the instruction.
|
||||
fn pretty_print(&self, mb_rru: Option<&RealRegUniverse>, state: &mut Self::State) -> String;
|
||||
}
|
||||
|
||||
/// Constant information used to emit an instruction.
|
||||
pub trait MachInstEmitInfo {
|
||||
/// Return the target-independent settings used for the compilation of this
|
||||
/// particular function.
|
||||
fn flags(&self) -> &Flags;
|
||||
}
|
||||
|
||||
/// A trait describing the emission state carried between MachInsts when
|
||||
/// emitting a function body.
|
||||
pub trait MachInstEmitState<I: MachInst>: Default + Clone + Debug {
|
||||
|
||||
@@ -88,6 +88,10 @@ pub struct VCode<I: VCodeInst> {
|
||||
/// ABI object.
|
||||
abi: Box<dyn ABICallee<I = I>>,
|
||||
|
||||
/// Constant information used during code emission. This should be
|
||||
/// immutable across function compilations within the same module.
|
||||
emit_info: I::Info,
|
||||
|
||||
/// Safepoint instruction indices. Filled in post-regalloc. (Prior to
|
||||
/// regalloc, the safepoint instructions are listed in the separate
|
||||
/// `StackmapRequestInfo` held separate from the `VCode`.)
|
||||
@@ -132,9 +136,13 @@ pub struct VCodeBuilder<I: VCodeInst> {
|
||||
|
||||
impl<I: VCodeInst> VCodeBuilder<I> {
|
||||
/// Create a new VCodeBuilder.
|
||||
pub fn new(abi: Box<dyn ABICallee<I = I>>, block_order: BlockLoweringOrder) -> VCodeBuilder<I> {
|
||||
pub fn new(
|
||||
abi: Box<dyn ABICallee<I = I>>,
|
||||
emit_info: I::Info,
|
||||
block_order: BlockLoweringOrder,
|
||||
) -> VCodeBuilder<I> {
|
||||
let reftype_class = I::ref_type_regclass(abi.flags());
|
||||
let vcode = VCode::new(abi, block_order);
|
||||
let vcode = VCode::new(abi, emit_info, block_order);
|
||||
let stack_map_info = StackmapRequestInfo {
|
||||
reftype_class,
|
||||
reftyped_vregs: vec![],
|
||||
@@ -263,7 +271,11 @@ fn is_reftype(ty: Type) -> bool {
|
||||
|
||||
impl<I: VCodeInst> VCode<I> {
|
||||
/// New empty VCode.
|
||||
fn new(abi: Box<dyn ABICallee<I = I>>, block_order: BlockLoweringOrder) -> VCode<I> {
|
||||
fn new(
|
||||
abi: Box<dyn ABICallee<I = I>>,
|
||||
emit_info: I::Info,
|
||||
block_order: BlockLoweringOrder,
|
||||
) -> VCode<I> {
|
||||
VCode {
|
||||
liveins: abi.liveins(),
|
||||
liveouts: abi.liveouts(),
|
||||
@@ -277,6 +289,7 @@ impl<I: VCodeInst> VCode<I> {
|
||||
block_succs: vec![],
|
||||
block_order,
|
||||
abi,
|
||||
emit_info,
|
||||
safepoint_insns: vec![],
|
||||
safepoint_slots: vec![],
|
||||
}
|
||||
@@ -431,7 +444,6 @@ impl<I: VCodeInst> VCode<I> {
|
||||
|
||||
buffer.reserve_labels_for_blocks(self.num_blocks() as BlockIndex); // first N MachLabels are simply block indices.
|
||||
|
||||
let flags = self.abi.flags();
|
||||
let mut safepoint_idx = 0;
|
||||
let mut cur_srcloc = None;
|
||||
for block in 0..self.num_blocks() {
|
||||
@@ -440,7 +452,7 @@ impl<I: VCodeInst> VCode<I> {
|
||||
while new_offset > buffer.cur_offset() {
|
||||
// Pad with NOPs up to the aligned block offset.
|
||||
let nop = I::gen_nop((new_offset - buffer.cur_offset()) as usize);
|
||||
nop.emit(&mut buffer, flags, &mut Default::default());
|
||||
nop.emit(&mut buffer, &self.emit_info, &mut Default::default());
|
||||
}
|
||||
assert_eq!(buffer.cur_offset(), new_offset);
|
||||
|
||||
@@ -469,7 +481,7 @@ impl<I: VCodeInst> VCode<I> {
|
||||
safepoint_idx += 1;
|
||||
}
|
||||
|
||||
self.insts[iix as usize].emit(&mut buffer, flags, &mut state);
|
||||
self.insts[iix as usize].emit(&mut buffer, &self.emit_info, &mut state);
|
||||
}
|
||||
|
||||
if cur_srcloc.is_some() {
|
||||
|
||||
Reference in New Issue
Block a user