Chaos mode MVP: Skip branch optimization in MachBuffer (#6039)
* fuzz: Add chaos mode control plane Co-authored-by: Falk Zwimpfer <24669719+FalkZ@users.noreply.github.com> Co-authored-by: Moritz Waser <mzrw.dev@pm.me> * fuzz: Skip branch optimization with chaos mode Co-authored-by: Falk Zwimpfer <24669719+FalkZ@users.noreply.github.com> Co-authored-by: Moritz Waser <mzrw.dev@pm.me> * fuzz: Rename chaos engine -> control plane Co-authored-by: Falk Zwimpfer <24669719+FalkZ@users.noreply.github.com> Co-authored-by: Moritz Waser <mzrw.dev@pm.me> * chaos mode: refactoring ControlPlane to be passed through the call stack by reference Co-authored-by: Falk Zwimpfer <24669719+FalkZ@users.noreply.github.com> Co-authored-by: Remo Senekowitsch <contact@remsle.dev> * fuzz: annotate chaos todos Co-authored-by: Falk Zwimpfer <24669719+FalkZ@users.noreply.github.com> Co-authored-by: Moritz Waser <mzrw.dev@pm.me> * fuzz: cleanup control plane Co-authored-by: Falk Zwimpfer <24669719+FalkZ@users.noreply.github.com> Co-authored-by: Moritz Waser <mzrw.dev@pm.me> * fuzz: remove control plane from compiler context Co-authored-by: Falk Zwimpfer <24669719+FalkZ@users.noreply.github.com> Co-authored-by: Moritz Waser <mzrw.dev@pm.me> * fuzz: move control plane into emit state Co-authored-by: Falk Zwimpfer <24669719+FalkZ@users.noreply.github.com> Co-authored-by: Moritz Waser <mzrw.dev@pm.me> * fuzz: fix remaining compiler errors Co-authored-by: Falk Zwimpfer <24669719+FalkZ@users.noreply.github.com> Co-authored-by: Moritz Waser <mzrw.dev@pm.me> * fix tests * refactor emission state ctrl plane accessors Co-authored-by: Falk Zwimpfer <24669719+FalkZ@users.noreply.github.com> Co-authored-by: Moritz Waser <mzrw.dev@pm.me> * centralize conditional compilation of chaos mode Also cleanup a few straggling dependencies on cranelift-control that aren't needed anymore. Co-authored-by: Falk Zwimpfer <24669719+FalkZ@users.noreply.github.com> Co-authored-by: Moritz Waser <mzrw.dev@pm.me> * add cranelift-control to published crates prtest:full Co-authored-by: Falk Zwimpfer <24669719+FalkZ@users.noreply.github.com> Co-authored-by: Moritz Waser <mzrw.dev@pm.me> * add cranelift-control to public crates Co-authored-by: Falk Zwimpfer <24669719+FalkZ@users.noreply.github.com> Co-authored-by: Moritz Waser <mzrw.dev@pm.me> --------- Co-authored-by: Falk Zwimpfer <24669719+FalkZ@users.noreply.github.com> Co-authored-by: Moritz Waser <mzrw.dev@pm.me> Co-authored-by: Remo Senekowitsch <contact@remsle.dev>
This commit is contained in:
committed by
GitHub
parent
064968b01d
commit
7eb8914090
@@ -148,6 +148,7 @@ use crate::machinst::{
|
||||
};
|
||||
use crate::timing;
|
||||
use crate::trace;
|
||||
use cranelift_control::ControlPlane;
|
||||
use cranelift_entity::{entity_impl, SecondaryMap};
|
||||
use smallvec::SmallVec;
|
||||
use std::convert::TryFrom;
|
||||
@@ -523,7 +524,7 @@ impl<I: VCodeInst> MachBuffer<I> {
|
||||
}
|
||||
|
||||
/// Bind a label to the current offset. A label can only be bound once.
|
||||
pub fn bind_label(&mut self, label: MachLabel) {
|
||||
pub fn bind_label(&mut self, label: MachLabel, ctrl_plane: &mut ControlPlane) {
|
||||
trace!(
|
||||
"MachBuffer: bind label {:?} at offset {}",
|
||||
label,
|
||||
@@ -542,7 +543,7 @@ impl<I: VCodeInst> MachBuffer<I> {
|
||||
// offset and added it to the list (which contains all labels at the
|
||||
// current offset).
|
||||
|
||||
self.optimize_branches();
|
||||
self.optimize_branches(ctrl_plane);
|
||||
|
||||
// Post-invariant: by `optimize_branches()` (see argument there).
|
||||
}
|
||||
@@ -773,7 +774,11 @@ impl<I: VCodeInst> MachBuffer<I> {
|
||||
// fixup record referring to that last branch is removed.
|
||||
}
|
||||
|
||||
fn optimize_branches(&mut self) {
|
||||
fn optimize_branches(&mut self, ctrl_plane: &mut ControlPlane) {
|
||||
if ctrl_plane.get_decision() {
|
||||
return;
|
||||
}
|
||||
|
||||
self.lazily_clear_labels_at_tail();
|
||||
// Invariants valid at this point.
|
||||
|
||||
@@ -1141,13 +1146,18 @@ impl<I: VCodeInst> MachBuffer<I> {
|
||||
/// Should only be called if `island_needed()` returns true, i.e., if we
|
||||
/// actually reach a deadline. It's not necessarily a problem to do so
|
||||
/// otherwise but it may result in unnecessary work during emission.
|
||||
pub fn emit_island(&mut self, distance: CodeOffset) {
|
||||
self.emit_island_maybe_forced(false, distance);
|
||||
pub fn emit_island(&mut self, distance: CodeOffset, ctrl_plane: &mut ControlPlane) {
|
||||
self.emit_island_maybe_forced(false, distance, ctrl_plane);
|
||||
}
|
||||
|
||||
/// Same as `emit_island`, but an internal API with a `force_veneers`
|
||||
/// argument to force all veneers to always get emitted for debugging.
|
||||
fn emit_island_maybe_forced(&mut self, force_veneers: bool, distance: CodeOffset) {
|
||||
fn emit_island_maybe_forced(
|
||||
&mut self,
|
||||
force_veneers: bool,
|
||||
distance: CodeOffset,
|
||||
ctrl_plane: &mut ControlPlane,
|
||||
) {
|
||||
// We're going to purge fixups, so no latest-branch editing can happen
|
||||
// anymore.
|
||||
self.latest_branches.clear();
|
||||
@@ -1190,7 +1200,7 @@ impl<I: VCodeInst> MachBuffer<I> {
|
||||
self.start_srcloc(loc);
|
||||
}
|
||||
self.align_to(I::LabelUse::ALIGN);
|
||||
self.bind_label(label);
|
||||
self.bind_label(label, ctrl_plane);
|
||||
self.add_trap(code);
|
||||
if let Some(map) = stack_map {
|
||||
let extent = StackMapExtent::UpcomingBytes(I::TRAP_OPCODE.len() as u32);
|
||||
@@ -1204,7 +1214,7 @@ impl<I: VCodeInst> MachBuffer<I> {
|
||||
|
||||
for MachLabelConstant { label, align, data } in mem::take(&mut self.pending_constants) {
|
||||
self.align_to(align);
|
||||
self.bind_label(label);
|
||||
self.bind_label(label, ctrl_plane);
|
||||
self.put_data(&data[..]);
|
||||
}
|
||||
|
||||
@@ -1328,7 +1338,11 @@ impl<I: VCodeInst> MachBuffer<I> {
|
||||
self.use_label_at_offset(veneer_fixup_off, label, veneer_label_use);
|
||||
}
|
||||
|
||||
fn finish_emission_maybe_forcing_veneers(&mut self, force_veneers: bool) {
|
||||
fn finish_emission_maybe_forcing_veneers(
|
||||
&mut self,
|
||||
force_veneers: bool,
|
||||
ctrl_plane: &mut ControlPlane,
|
||||
) {
|
||||
while !self.pending_constants.is_empty()
|
||||
|| !self.pending_traps.is_empty()
|
||||
|| !self.fixup_records.is_empty()
|
||||
@@ -1336,7 +1350,7 @@ impl<I: VCodeInst> MachBuffer<I> {
|
||||
// `emit_island()` will emit any pending veneers and constants, and
|
||||
// as a side-effect, will also take care of any fixups with resolved
|
||||
// labels eagerly.
|
||||
self.emit_island_maybe_forced(force_veneers, u32::MAX);
|
||||
self.emit_island_maybe_forced(force_veneers, u32::MAX, ctrl_plane);
|
||||
}
|
||||
|
||||
// Ensure that all labels have been fixed up after the last island is emitted. This is a
|
||||
@@ -1346,14 +1360,14 @@ impl<I: VCodeInst> MachBuffer<I> {
|
||||
}
|
||||
|
||||
/// Finish any deferred emissions and/or fixups.
|
||||
pub fn finish(mut self) -> MachBufferFinalized<Stencil> {
|
||||
pub fn finish(mut self, ctrl_plane: &mut ControlPlane) -> MachBufferFinalized<Stencil> {
|
||||
let _tt = timing::vcode_emit_finish();
|
||||
|
||||
// Do any optimizations on branches at tail of buffer, as if we
|
||||
// had bound one last label.
|
||||
self.optimize_branches();
|
||||
self.optimize_branches(ctrl_plane);
|
||||
|
||||
self.finish_emission_maybe_forcing_veneers(false);
|
||||
self.finish_emission_maybe_forcing_veneers(false, ctrl_plane);
|
||||
|
||||
let mut srclocs = self.srclocs;
|
||||
srclocs.sort_by_key(|entry| entry.start);
|
||||
@@ -1713,19 +1727,28 @@ impl<I: VCodeInst> MachTextSectionBuilder<I> {
|
||||
}
|
||||
|
||||
impl<I: VCodeInst> TextSectionBuilder for MachTextSectionBuilder<I> {
|
||||
fn append(&mut self, labeled: bool, func: &[u8], align: u32) -> u64 {
|
||||
fn append(
|
||||
&mut self,
|
||||
labeled: bool,
|
||||
func: &[u8],
|
||||
align: u32,
|
||||
ctrl_plane: &mut ControlPlane,
|
||||
) -> u64 {
|
||||
// Conditionally emit an island if it's necessary to resolve jumps
|
||||
// between functions which are too far away.
|
||||
let size = func.len() as u32;
|
||||
if self.force_veneers || self.buf.island_needed(size) {
|
||||
self.buf.emit_island_maybe_forced(self.force_veneers, size);
|
||||
self.buf
|
||||
.emit_island_maybe_forced(self.force_veneers, size, ctrl_plane);
|
||||
}
|
||||
|
||||
self.buf.align_to(align);
|
||||
let pos = self.buf.cur_offset();
|
||||
if labeled {
|
||||
self.buf
|
||||
.bind_label(MachLabel::from_block(BlockIndex::new(self.next_func)));
|
||||
self.buf.bind_label(
|
||||
MachLabel::from_block(BlockIndex::new(self.next_func)),
|
||||
ctrl_plane,
|
||||
);
|
||||
self.next_func += 1;
|
||||
}
|
||||
self.buf.put_data(func);
|
||||
@@ -1748,13 +1771,13 @@ impl<I: VCodeInst> TextSectionBuilder for MachTextSectionBuilder<I> {
|
||||
self.force_veneers = true;
|
||||
}
|
||||
|
||||
fn finish(&mut self) -> Vec<u8> {
|
||||
fn finish(&mut self, ctrl_plane: &mut ControlPlane) -> Vec<u8> {
|
||||
// Double-check all functions were pushed.
|
||||
assert_eq!(self.next_func, self.buf.label_offsets.len());
|
||||
|
||||
// Finish up any veneers, if necessary.
|
||||
self.buf
|
||||
.finish_emission_maybe_forcing_veneers(self.force_veneers);
|
||||
.finish_emission_maybe_forcing_veneers(self.force_veneers, ctrl_plane);
|
||||
|
||||
// We don't need the data any more, so return it to the caller.
|
||||
mem::take(&mut self.buf.data).into_vec()
|
||||
@@ -1770,7 +1793,7 @@ mod test {
|
||||
use crate::ir::UserExternalNameRef;
|
||||
use crate::isa::aarch64::inst::xreg;
|
||||
use crate::isa::aarch64::inst::{BranchTarget, CondBrKind, EmitInfo, Inst};
|
||||
use crate::machinst::MachInstEmit;
|
||||
use crate::machinst::{MachInstEmit, MachInstEmitState};
|
||||
use crate::settings;
|
||||
use std::default::Default;
|
||||
use std::vec::Vec;
|
||||
@@ -1786,14 +1809,14 @@ mod test {
|
||||
fn test_elide_jump_to_next() {
|
||||
let info = EmitInfo::new(settings::Flags::new(settings::builder()));
|
||||
let mut buf = MachBuffer::new();
|
||||
let mut state = Default::default();
|
||||
let mut state = <Inst as MachInstEmit>::State::default();
|
||||
|
||||
buf.reserve_labels_for_blocks(2);
|
||||
buf.bind_label(label(0));
|
||||
buf.bind_label(label(0), state.ctrl_plane_mut());
|
||||
let inst = Inst::Jump { dest: target(1) };
|
||||
inst.emit(&[], &mut buf, &info, &mut state);
|
||||
buf.bind_label(label(1));
|
||||
let buf = buf.finish();
|
||||
buf.bind_label(label(1), state.ctrl_plane_mut());
|
||||
let buf = buf.finish(state.ctrl_plane_mut());
|
||||
assert_eq!(0, buf.total_size());
|
||||
}
|
||||
|
||||
@@ -1801,11 +1824,11 @@ mod test {
|
||||
fn test_elide_trivial_jump_blocks() {
|
||||
let info = EmitInfo::new(settings::Flags::new(settings::builder()));
|
||||
let mut buf = MachBuffer::new();
|
||||
let mut state = Default::default();
|
||||
let mut state = <Inst as MachInstEmit>::State::default();
|
||||
|
||||
buf.reserve_labels_for_blocks(4);
|
||||
|
||||
buf.bind_label(label(0));
|
||||
buf.bind_label(label(0), state.ctrl_plane_mut());
|
||||
let inst = Inst::CondBr {
|
||||
kind: CondBrKind::NotZero(xreg(0)),
|
||||
taken: target(1),
|
||||
@@ -1813,17 +1836,17 @@ mod test {
|
||||
};
|
||||
inst.emit(&[], &mut buf, &info, &mut state);
|
||||
|
||||
buf.bind_label(label(1));
|
||||
buf.bind_label(label(1), state.ctrl_plane_mut());
|
||||
let inst = Inst::Jump { dest: target(3) };
|
||||
inst.emit(&[], &mut buf, &info, &mut state);
|
||||
|
||||
buf.bind_label(label(2));
|
||||
buf.bind_label(label(2), state.ctrl_plane_mut());
|
||||
let inst = Inst::Jump { dest: target(3) };
|
||||
inst.emit(&[], &mut buf, &info, &mut state);
|
||||
|
||||
buf.bind_label(label(3));
|
||||
buf.bind_label(label(3), state.ctrl_plane_mut());
|
||||
|
||||
let buf = buf.finish();
|
||||
let buf = buf.finish(state.ctrl_plane_mut());
|
||||
assert_eq!(0, buf.total_size());
|
||||
}
|
||||
|
||||
@@ -1831,11 +1854,11 @@ mod test {
|
||||
fn test_flip_cond() {
|
||||
let info = EmitInfo::new(settings::Flags::new(settings::builder()));
|
||||
let mut buf = MachBuffer::new();
|
||||
let mut state = Default::default();
|
||||
let mut state = <Inst as MachInstEmit>::State::default();
|
||||
|
||||
buf.reserve_labels_for_blocks(4);
|
||||
|
||||
buf.bind_label(label(0));
|
||||
buf.bind_label(label(0), state.ctrl_plane_mut());
|
||||
let inst = Inst::CondBr {
|
||||
kind: CondBrKind::Zero(xreg(0)),
|
||||
taken: target(1),
|
||||
@@ -1843,19 +1866,19 @@ mod test {
|
||||
};
|
||||
inst.emit(&[], &mut buf, &info, &mut state);
|
||||
|
||||
buf.bind_label(label(1));
|
||||
buf.bind_label(label(1), state.ctrl_plane_mut());
|
||||
let inst = Inst::Nop4;
|
||||
inst.emit(&[], &mut buf, &info, &mut state);
|
||||
|
||||
buf.bind_label(label(2));
|
||||
buf.bind_label(label(2), state.ctrl_plane_mut());
|
||||
let inst = Inst::Udf {
|
||||
trap_code: TrapCode::Interrupt,
|
||||
};
|
||||
inst.emit(&[], &mut buf, &info, &mut state);
|
||||
|
||||
buf.bind_label(label(3));
|
||||
buf.bind_label(label(3), state.ctrl_plane_mut());
|
||||
|
||||
let buf = buf.finish();
|
||||
let buf = buf.finish(state.ctrl_plane_mut());
|
||||
|
||||
let mut buf2 = MachBuffer::new();
|
||||
let mut state = Default::default();
|
||||
@@ -1867,7 +1890,7 @@ mod test {
|
||||
let inst = Inst::Nop4;
|
||||
inst.emit(&[], &mut buf2, &info, &mut state);
|
||||
|
||||
let buf2 = buf2.finish();
|
||||
let buf2 = buf2.finish(state.ctrl_plane_mut());
|
||||
|
||||
assert_eq!(buf.data, buf2.data);
|
||||
}
|
||||
@@ -1876,11 +1899,11 @@ mod test {
|
||||
fn test_island() {
|
||||
let info = EmitInfo::new(settings::Flags::new(settings::builder()));
|
||||
let mut buf = MachBuffer::new();
|
||||
let mut state = Default::default();
|
||||
let mut state = <Inst as MachInstEmit>::State::default();
|
||||
|
||||
buf.reserve_labels_for_blocks(4);
|
||||
|
||||
buf.bind_label(label(0));
|
||||
buf.bind_label(label(0), state.ctrl_plane_mut());
|
||||
let inst = Inst::CondBr {
|
||||
kind: CondBrKind::NotZero(xreg(0)),
|
||||
taken: target(2),
|
||||
@@ -1888,24 +1911,24 @@ mod test {
|
||||
};
|
||||
inst.emit(&[], &mut buf, &info, &mut state);
|
||||
|
||||
buf.bind_label(label(1));
|
||||
buf.bind_label(label(1), state.ctrl_plane_mut());
|
||||
while buf.cur_offset() < 2000000 {
|
||||
if buf.island_needed(0) {
|
||||
buf.emit_island(0);
|
||||
buf.emit_island(0, state.ctrl_plane_mut());
|
||||
}
|
||||
let inst = Inst::Nop4;
|
||||
inst.emit(&[], &mut buf, &info, &mut state);
|
||||
}
|
||||
|
||||
buf.bind_label(label(2));
|
||||
buf.bind_label(label(2), state.ctrl_plane_mut());
|
||||
let inst = Inst::Nop4;
|
||||
inst.emit(&[], &mut buf, &info, &mut state);
|
||||
|
||||
buf.bind_label(label(3));
|
||||
buf.bind_label(label(3), state.ctrl_plane_mut());
|
||||
let inst = Inst::Nop4;
|
||||
inst.emit(&[], &mut buf, &info, &mut state);
|
||||
|
||||
let buf = buf.finish();
|
||||
let buf = buf.finish(state.ctrl_plane_mut());
|
||||
|
||||
assert_eq!(2000000 + 8, buf.total_size());
|
||||
|
||||
@@ -1934,7 +1957,7 @@ mod test {
|
||||
};
|
||||
inst.emit(&[], &mut buf2, &info, &mut state);
|
||||
|
||||
let buf2 = buf2.finish();
|
||||
let buf2 = buf2.finish(state.ctrl_plane_mut());
|
||||
|
||||
assert_eq!(&buf.data[0..8], &buf2.data[..]);
|
||||
}
|
||||
@@ -1943,25 +1966,25 @@ mod test {
|
||||
fn test_island_backward() {
|
||||
let info = EmitInfo::new(settings::Flags::new(settings::builder()));
|
||||
let mut buf = MachBuffer::new();
|
||||
let mut state = Default::default();
|
||||
let mut state = <Inst as MachInstEmit>::State::default();
|
||||
|
||||
buf.reserve_labels_for_blocks(4);
|
||||
|
||||
buf.bind_label(label(0));
|
||||
buf.bind_label(label(0), state.ctrl_plane_mut());
|
||||
let inst = Inst::Nop4;
|
||||
inst.emit(&[], &mut buf, &info, &mut state);
|
||||
|
||||
buf.bind_label(label(1));
|
||||
buf.bind_label(label(1), state.ctrl_plane_mut());
|
||||
let inst = Inst::Nop4;
|
||||
inst.emit(&[], &mut buf, &info, &mut state);
|
||||
|
||||
buf.bind_label(label(2));
|
||||
buf.bind_label(label(2), state.ctrl_plane_mut());
|
||||
while buf.cur_offset() < 2000000 {
|
||||
let inst = Inst::Nop4;
|
||||
inst.emit(&[], &mut buf, &info, &mut state);
|
||||
}
|
||||
|
||||
buf.bind_label(label(3));
|
||||
buf.bind_label(label(3), state.ctrl_plane_mut());
|
||||
let inst = Inst::CondBr {
|
||||
kind: CondBrKind::NotZero(xreg(0)),
|
||||
taken: target(0),
|
||||
@@ -1969,7 +1992,7 @@ mod test {
|
||||
};
|
||||
inst.emit(&[], &mut buf, &info, &mut state);
|
||||
|
||||
let buf = buf.finish();
|
||||
let buf = buf.finish(state.ctrl_plane_mut());
|
||||
|
||||
assert_eq!(2000000 + 12, buf.total_size());
|
||||
|
||||
@@ -1986,7 +2009,7 @@ mod test {
|
||||
};
|
||||
inst.emit(&[], &mut buf2, &info, &mut state);
|
||||
|
||||
let buf2 = buf2.finish();
|
||||
let buf2 = buf2.finish(state.ctrl_plane_mut());
|
||||
|
||||
assert_eq!(&buf.data[2000000..], &buf2.data[..]);
|
||||
}
|
||||
@@ -2028,11 +2051,11 @@ mod test {
|
||||
|
||||
let info = EmitInfo::new(settings::Flags::new(settings::builder()));
|
||||
let mut buf = MachBuffer::new();
|
||||
let mut state = Default::default();
|
||||
let mut state = <Inst as MachInstEmit>::State::default();
|
||||
|
||||
buf.reserve_labels_for_blocks(8);
|
||||
|
||||
buf.bind_label(label(0));
|
||||
buf.bind_label(label(0), state.ctrl_plane_mut());
|
||||
let inst = Inst::CondBr {
|
||||
kind: CondBrKind::Zero(xreg(0)),
|
||||
taken: target(1),
|
||||
@@ -2040,38 +2063,38 @@ mod test {
|
||||
};
|
||||
inst.emit(&[], &mut buf, &info, &mut state);
|
||||
|
||||
buf.bind_label(label(1));
|
||||
buf.bind_label(label(1), state.ctrl_plane_mut());
|
||||
let inst = Inst::Jump { dest: target(3) };
|
||||
inst.emit(&[], &mut buf, &info, &mut state);
|
||||
|
||||
buf.bind_label(label(2));
|
||||
buf.bind_label(label(2), state.ctrl_plane_mut());
|
||||
let inst = Inst::Nop4;
|
||||
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, &info, &mut state);
|
||||
|
||||
buf.bind_label(label(3));
|
||||
buf.bind_label(label(3), state.ctrl_plane_mut());
|
||||
let inst = Inst::Jump { dest: target(4) };
|
||||
inst.emit(&[], &mut buf, &info, &mut state);
|
||||
|
||||
buf.bind_label(label(4));
|
||||
buf.bind_label(label(4), state.ctrl_plane_mut());
|
||||
let inst = Inst::Jump { dest: target(5) };
|
||||
inst.emit(&[], &mut buf, &info, &mut state);
|
||||
|
||||
buf.bind_label(label(5));
|
||||
buf.bind_label(label(5), state.ctrl_plane_mut());
|
||||
let inst = Inst::Jump { dest: target(7) };
|
||||
inst.emit(&[], &mut buf, &info, &mut state);
|
||||
|
||||
buf.bind_label(label(6));
|
||||
buf.bind_label(label(6), state.ctrl_plane_mut());
|
||||
let inst = Inst::Nop4;
|
||||
inst.emit(&[], &mut buf, &info, &mut state);
|
||||
|
||||
buf.bind_label(label(7));
|
||||
buf.bind_label(label(7), state.ctrl_plane_mut());
|
||||
let inst = Inst::Ret { rets: vec![] };
|
||||
inst.emit(&[], &mut buf, &info, &mut state);
|
||||
|
||||
let buf = buf.finish();
|
||||
let buf = buf.finish(state.ctrl_plane_mut());
|
||||
|
||||
let golden_data = vec![
|
||||
0xa0, 0x00, 0x00, 0xb4, // cbz x0, 0x14
|
||||
@@ -2104,31 +2127,31 @@ mod test {
|
||||
// b label0
|
||||
let info = EmitInfo::new(settings::Flags::new(settings::builder()));
|
||||
let mut buf = MachBuffer::new();
|
||||
let mut state = Default::default();
|
||||
let mut state = <Inst as MachInstEmit>::State::default();
|
||||
|
||||
buf.reserve_labels_for_blocks(5);
|
||||
|
||||
buf.bind_label(label(0));
|
||||
buf.bind_label(label(0), state.ctrl_plane_mut());
|
||||
let inst = Inst::Jump { dest: target(1) };
|
||||
inst.emit(&[], &mut buf, &info, &mut state);
|
||||
|
||||
buf.bind_label(label(1));
|
||||
buf.bind_label(label(1), state.ctrl_plane_mut());
|
||||
let inst = Inst::Jump { dest: target(2) };
|
||||
inst.emit(&[], &mut buf, &info, &mut state);
|
||||
|
||||
buf.bind_label(label(2));
|
||||
buf.bind_label(label(2), state.ctrl_plane_mut());
|
||||
let inst = Inst::Jump { dest: target(3) };
|
||||
inst.emit(&[], &mut buf, &info, &mut state);
|
||||
|
||||
buf.bind_label(label(3));
|
||||
buf.bind_label(label(3), state.ctrl_plane_mut());
|
||||
let inst = Inst::Jump { dest: target(4) };
|
||||
inst.emit(&[], &mut buf, &info, &mut state);
|
||||
|
||||
buf.bind_label(label(4));
|
||||
buf.bind_label(label(4), state.ctrl_plane_mut());
|
||||
let inst = Inst::Jump { dest: target(1) };
|
||||
inst.emit(&[], &mut buf, &info, &mut state);
|
||||
|
||||
let buf = buf.finish();
|
||||
let buf = buf.finish(state.ctrl_plane_mut());
|
||||
|
||||
let golden_data = vec![
|
||||
0x00, 0x00, 0x00, 0x14, // b 0
|
||||
@@ -2140,10 +2163,11 @@ mod test {
|
||||
#[test]
|
||||
fn metadata_records() {
|
||||
let mut buf = MachBuffer::<Inst>::new();
|
||||
let ctrl_plane = &mut Default::default();
|
||||
|
||||
buf.reserve_labels_for_blocks(1);
|
||||
|
||||
buf.bind_label(label(0));
|
||||
buf.bind_label(label(0), ctrl_plane);
|
||||
buf.put1(1);
|
||||
buf.add_trap(TrapCode::HeapOutOfBounds);
|
||||
buf.put1(2);
|
||||
@@ -2163,7 +2187,7 @@ mod test {
|
||||
);
|
||||
buf.put1(4);
|
||||
|
||||
let buf = buf.finish();
|
||||
let buf = buf.finish(ctrl_plane);
|
||||
|
||||
assert_eq!(buf.data(), &[1, 2, 3, 4]);
|
||||
assert_eq!(
|
||||
|
||||
@@ -52,6 +52,7 @@ use crate::settings::Flags;
|
||||
use crate::value_label::ValueLabelsRanges;
|
||||
use alloc::vec::Vec;
|
||||
use core::fmt::Debug;
|
||||
use cranelift_control::ControlPlane;
|
||||
use cranelift_entity::PrimaryMap;
|
||||
use regalloc2::{Allocation, VReg};
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
@@ -272,13 +273,21 @@ pub trait MachInstEmit: MachInst {
|
||||
/// emitting a function body.
|
||||
pub trait MachInstEmitState<I: VCodeInst>: Default + Clone + Debug {
|
||||
/// Create a new emission state given the ABI object.
|
||||
fn new(abi: &Callee<I::ABIMachineSpec>) -> Self;
|
||||
fn new(abi: &Callee<I::ABIMachineSpec>, ctrl_plane: ControlPlane) -> Self;
|
||||
/// Update the emission state before emitting an instruction that is a
|
||||
/// safepoint.
|
||||
fn pre_safepoint(&mut self, _stack_map: StackMap) {}
|
||||
/// Update the emission state to indicate instructions are associated with a
|
||||
/// particular RelSourceLoc.
|
||||
fn pre_sourceloc(&mut self, _srcloc: RelSourceLoc) {}
|
||||
/// The emission state holds ownership of a control plane, so it doesn't
|
||||
/// have to be passed around explicitly too much. `ctrl_plane_mut` may
|
||||
/// be used if temporary access to the control plane is needed by some
|
||||
/// other function that doesn't have access to the emission state.
|
||||
fn ctrl_plane_mut(&mut self) -> &mut ControlPlane;
|
||||
/// Used to continue using a control plane after the emission state is
|
||||
/// not needed anymore.
|
||||
fn take_ctrl_plane(self) -> ControlPlane;
|
||||
}
|
||||
|
||||
/// The result of a `MachBackend::compile_function()` call. Contains machine
|
||||
@@ -474,7 +483,13 @@ pub trait TextSectionBuilder {
|
||||
///
|
||||
/// This function returns the offset at which the data was placed in the
|
||||
/// text section.
|
||||
fn append(&mut self, labeled: bool, data: &[u8], align: u32) -> u64;
|
||||
fn append(
|
||||
&mut self,
|
||||
labeled: bool,
|
||||
data: &[u8],
|
||||
align: u32,
|
||||
ctrl_plane: &mut ControlPlane,
|
||||
) -> u64;
|
||||
|
||||
/// Attempts to resolve a relocation for this function.
|
||||
///
|
||||
@@ -497,7 +512,7 @@ pub trait TextSectionBuilder {
|
||||
|
||||
/// Completes this text section, filling out any final details, and returns
|
||||
/// the bytes of the text section.
|
||||
fn finish(&mut self) -> Vec<u8>;
|
||||
fn finish(&mut self, ctrl_plane: &mut ControlPlane) -> Vec<u8>;
|
||||
}
|
||||
|
||||
/// Expected unwind info type.
|
||||
|
||||
@@ -26,6 +26,7 @@ use crate::timing;
|
||||
use crate::trace;
|
||||
use crate::CodegenError;
|
||||
use crate::ValueLocRange;
|
||||
use cranelift_control::ControlPlane;
|
||||
use regalloc2::{
|
||||
Edit, Function as RegallocFunction, InstOrEdit, InstRange, Operand, OperandKind, PRegSet,
|
||||
RegClass, VReg,
|
||||
@@ -763,6 +764,7 @@ impl<I: VCodeInst> VCode<I> {
|
||||
regalloc: ®alloc2::Output,
|
||||
want_disasm: bool,
|
||||
want_metadata: bool,
|
||||
ctrl_plane: &mut ControlPlane,
|
||||
) -> EmitResult<I>
|
||||
where
|
||||
I: VCodeInst,
|
||||
@@ -813,7 +815,7 @@ impl<I: VCodeInst> VCode<I> {
|
||||
let mut cur_srcloc = None;
|
||||
let mut last_offset = None;
|
||||
let mut inst_offsets = vec![];
|
||||
let mut state = I::State::new(&self.abi);
|
||||
let mut state = I::State::new(&self.abi, std::mem::take(ctrl_plane));
|
||||
|
||||
let mut disasm = String::new();
|
||||
|
||||
@@ -874,7 +876,7 @@ impl<I: VCodeInst> VCode<I> {
|
||||
|
||||
// Now emit the regular block body.
|
||||
|
||||
buffer.bind_label(MachLabel::from_block(block));
|
||||
buffer.bind_label(MachLabel::from_block(block), state.ctrl_plane_mut());
|
||||
|
||||
if want_disasm {
|
||||
writeln!(&mut disasm, "block{}:", block.index()).unwrap();
|
||||
@@ -1054,11 +1056,14 @@ impl<I: VCodeInst> VCode<I> {
|
||||
let worst_case_next_bb =
|
||||
I::worst_case_size() * (next_block_size + next_block_ra_insertions);
|
||||
if buffer.island_needed(worst_case_next_bb) {
|
||||
buffer.emit_island(worst_case_next_bb);
|
||||
buffer.emit_island(worst_case_next_bb, ctrl_plane);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// emission state is not needed anymore, move control plane back out
|
||||
*ctrl_plane = state.take_ctrl_plane();
|
||||
|
||||
// Emit the constants used by the function.
|
||||
let mut alignment = 1;
|
||||
for (constant, data) in self.constants.iter() {
|
||||
|
||||
Reference in New Issue
Block a user