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:
Remo Senekowitsch
2023-04-05 21:28:46 +02:00
committed by GitHub
parent 064968b01d
commit 7eb8914090
61 changed files with 815 additions and 245 deletions

15
Cargo.lock generated
View File

@@ -570,6 +570,7 @@ dependencies = [
"cranelift-bforest", "cranelift-bforest",
"cranelift-codegen-meta", "cranelift-codegen-meta",
"cranelift-codegen-shared", "cranelift-codegen-shared",
"cranelift-control",
"cranelift-entity", "cranelift-entity",
"cranelift-isle", "cranelift-isle",
"criterion", "criterion",
@@ -596,6 +597,13 @@ dependencies = [
name = "cranelift-codegen-shared" name = "cranelift-codegen-shared"
version = "0.96.0" version = "0.96.0"
[[package]]
name = "cranelift-control"
version = "0.96.0"
dependencies = [
"arbitrary",
]
[[package]] [[package]]
name = "cranelift-entity" name = "cranelift-entity"
version = "0.96.0" version = "0.96.0"
@@ -610,6 +618,7 @@ dependencies = [
"anyhow", "anyhow",
"cranelift", "cranelift",
"cranelift-codegen", "cranelift-codegen",
"cranelift-control",
"cranelift-frontend", "cranelift-frontend",
"cranelift-interpreter", "cranelift-interpreter",
"cranelift-jit", "cranelift-jit",
@@ -685,6 +694,7 @@ dependencies = [
"anyhow", "anyhow",
"cranelift", "cranelift",
"cranelift-codegen", "cranelift-codegen",
"cranelift-control",
"cranelift-entity", "cranelift-entity",
"cranelift-frontend", "cranelift-frontend",
"cranelift-module", "cranelift-module",
@@ -704,6 +714,7 @@ version = "0.96.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"cranelift-codegen", "cranelift-codegen",
"cranelift-control",
"hashbrown 0.13.1", "hashbrown 0.13.1",
] ]
@@ -722,6 +733,7 @@ version = "0.96.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"cranelift-codegen", "cranelift-codegen",
"cranelift-control",
"cranelift-entity", "cranelift-entity",
"cranelift-frontend", "cranelift-frontend",
"cranelift-module", "cranelift-module",
@@ -3585,6 +3597,7 @@ version = "9.0.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"cranelift-codegen", "cranelift-codegen",
"cranelift-control",
"cranelift-entity", "cranelift-entity",
"cranelift-frontend", "cranelift-frontend",
"cranelift-native", "cranelift-native",
@@ -3605,6 +3618,7 @@ version = "9.0.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"cranelift-codegen", "cranelift-codegen",
"cranelift-control",
"cranelift-native", "cranelift-native",
"gimli", "gimli",
"object", "object",
@@ -3684,6 +3698,7 @@ dependencies = [
"component-fuzz-util", "component-fuzz-util",
"component-test-util", "component-test-util",
"cranelift-codegen", "cranelift-codegen",
"cranelift-control",
"cranelift-filetests", "cranelift-filetests",
"cranelift-fuzzgen", "cranelift-fuzzgen",
"cranelift-interpreter", "cranelift-interpreter",

View File

@@ -162,6 +162,7 @@ cranelift-object = { path = "cranelift/object", version = "0.96.0" }
cranelift-jit = { path = "cranelift/jit", version = "0.96.0" } cranelift-jit = { path = "cranelift/jit", version = "0.96.0" }
cranelift-fuzzgen = { path = "cranelift/fuzzgen" } cranelift-fuzzgen = { path = "cranelift/fuzzgen" }
cranelift-bforest = { path = "cranelift/bforest", version = "0.96.0" } cranelift-bforest = { path = "cranelift/bforest", version = "0.96.0" }
cranelift-control = { path = "cranelift/control", version = "0.96.0" }
cranelift = { path = "cranelift/umbrella", version = "0.96.0" } cranelift = { path = "cranelift/umbrella", version = "0.96.0" }
winch-codegen = { path = "winch/codegen", version = "=0.7.0" } winch-codegen = { path = "winch/codegen", version = "=0.7.0" }

View File

@@ -19,6 +19,7 @@ capstone = { workspace = true, optional = true }
cranelift-codegen-shared = { path = "./shared", version = "0.96.0" } cranelift-codegen-shared = { path = "./shared", version = "0.96.0" }
cranelift-entity = { workspace = true } cranelift-entity = { workspace = true }
cranelift-bforest = { workspace = true } cranelift-bforest = { workspace = true }
cranelift-control = { workspace = true }
hashbrown = { workspace = true, features = ["raw"] } hashbrown = { workspace = true, features = ["raw"] }
target-lexicon = { workspace = true } target-lexicon = { workspace = true }
log = { workspace = true } log = { workspace = true }

View File

@@ -33,6 +33,7 @@ use crate::{timing, CompileError};
#[cfg(feature = "souper-harvest")] #[cfg(feature = "souper-harvest")]
use alloc::string::String; use alloc::string::String;
use alloc::vec::Vec; use alloc::vec::Vec;
use cranelift_control::ControlPlane;
#[cfg(feature = "souper-harvest")] #[cfg(feature = "souper-harvest")]
use crate::souper_harvest::do_souper_harvest; use crate::souper_harvest::do_souper_harvest;
@@ -124,8 +125,9 @@ impl Context {
&mut self, &mut self,
isa: &dyn TargetIsa, isa: &dyn TargetIsa,
mem: &mut Vec<u8>, mem: &mut Vec<u8>,
ctrl_plane: &mut ControlPlane,
) -> CompileResult<&CompiledCode> { ) -> CompileResult<&CompiledCode> {
let compiled_code = self.compile(isa)?; let compiled_code = self.compile(isa, ctrl_plane)?;
mem.extend_from_slice(compiled_code.code_buffer()); mem.extend_from_slice(compiled_code.code_buffer());
Ok(compiled_code) Ok(compiled_code)
} }
@@ -133,14 +135,18 @@ impl Context {
/// Internally compiles the function into a stencil. /// Internally compiles the function into a stencil.
/// ///
/// Public only for testing and fuzzing purposes. /// Public only for testing and fuzzing purposes.
pub fn compile_stencil(&mut self, isa: &dyn TargetIsa) -> CodegenResult<CompiledCodeStencil> { pub fn compile_stencil(
&mut self,
isa: &dyn TargetIsa,
ctrl_plane: &mut ControlPlane,
) -> CodegenResult<CompiledCodeStencil> {
let _tt = timing::compile(); let _tt = timing::compile();
self.verify_if(isa)?; self.verify_if(isa)?;
self.optimize(isa)?; self.optimize(isa)?;
isa.compile_function(&self.func, &self.domtree, self.want_disasm) isa.compile_function(&self.func, &self.domtree, self.want_disasm, ctrl_plane)
} }
/// Optimize the function, performing all compilation steps up to /// Optimize the function, performing all compilation steps up to
@@ -212,11 +218,17 @@ impl Context {
/// code sink. /// code sink.
/// ///
/// Returns information about the function's code and read-only data. /// Returns information about the function's code and read-only data.
pub fn compile(&mut self, isa: &dyn TargetIsa) -> CompileResult<&CompiledCode> { pub fn compile(
let stencil = self.compile_stencil(isa).map_err(|error| CompileError { &mut self,
inner: error, isa: &dyn TargetIsa,
func: &self.func, ctrl_plane: &mut ControlPlane,
})?; ) -> CompileResult<&CompiledCode> {
let stencil = self
.compile_stencil(isa, ctrl_plane)
.map_err(|error| CompileError {
inner: error,
func: &self.func,
})?;
Ok(self Ok(self
.compiled_code .compiled_code
.insert(stencil.apply_params(&self.func.params))) .insert(stencil.apply_params(&self.func.params)))

View File

@@ -32,6 +32,7 @@ use crate::{isa::TargetIsa, timing};
use crate::{trace, CompileError, Context}; use crate::{trace, CompileError, Context};
use alloc::borrow::{Cow, ToOwned as _}; use alloc::borrow::{Cow, ToOwned as _};
use alloc::string::ToString as _; use alloc::string::ToString as _;
use cranelift_control::ControlPlane;
impl Context { impl Context {
/// Compile the function, as in `compile`, but tries to reuse compiled artifacts from former /// Compile the function, as in `compile`, but tries to reuse compiled artifacts from former
@@ -40,6 +41,7 @@ impl Context {
&mut self, &mut self,
isa: &dyn TargetIsa, isa: &dyn TargetIsa,
cache_store: &mut dyn CacheKvStore, cache_store: &mut dyn CacheKvStore,
ctrl_plane: &mut ControlPlane,
) -> CompileResult<(&CompiledCode, bool)> { ) -> CompileResult<(&CompiledCode, bool)> {
let cache_key_hash = { let cache_key_hash = {
let _tt = timing::try_incremental_cache(); let _tt = timing::try_incremental_cache();
@@ -52,7 +54,7 @@ impl Context {
let info = compiled_code.code_info(); let info = compiled_code.code_info();
if isa.flags().enable_incremental_compilation_cache_checks() { if isa.flags().enable_incremental_compilation_cache_checks() {
let actual_result = self.compile(isa)?; let actual_result = self.compile(isa, ctrl_plane)?;
assert_eq!(*actual_result, compiled_code); assert_eq!(*actual_result, compiled_code);
assert_eq!(actual_result.code_info(), info); assert_eq!(actual_result.code_info(), info);
// no need to set `compiled_code` here, it's set by `compile()`. // no need to set `compiled_code` here, it's set by `compile()`.
@@ -71,10 +73,12 @@ impl Context {
cache_key_hash cache_key_hash
}; };
let stencil = self.compile_stencil(isa).map_err(|err| CompileError { let stencil = self
inner: err, .compile_stencil(isa, ctrl_plane)
func: &self.func, .map_err(|err| CompileError {
})?; inner: err,
func: &self.func,
})?;
let stencil = { let stencil = {
let _tt = timing::store_incremental_cache(); let _tt = timing::store_incremental_cache();

View File

@@ -1,5 +1,6 @@
//! AArch64 ISA: binary code emission. //! AArch64 ISA: binary code emission.
use cranelift_control::ControlPlane;
use regalloc2::Allocation; use regalloc2::Allocation;
use crate::binemit::{Reloc, StackMap}; use crate::binemit::{Reloc, StackMap};
@@ -638,15 +639,19 @@ pub struct EmitState {
stack_map: Option<StackMap>, stack_map: Option<StackMap>,
/// Current source-code location corresponding to instruction to be emitted. /// Current source-code location corresponding to instruction to be emitted.
cur_srcloc: RelSourceLoc, cur_srcloc: RelSourceLoc,
/// Only used during fuzz-testing. Otherwise, it is a zero-sized struct and
/// optimized away at compiletime. See [cranelift_control].
ctrl_plane: ControlPlane,
} }
impl MachInstEmitState<Inst> for EmitState { impl MachInstEmitState<Inst> for EmitState {
fn new(abi: &Callee<AArch64MachineDeps>) -> Self { fn new(abi: &Callee<AArch64MachineDeps>, ctrl_plane: ControlPlane) -> Self {
EmitState { EmitState {
virtual_sp_offset: 0, virtual_sp_offset: 0,
nominal_sp_to_fp: abi.frame_size() as i64, nominal_sp_to_fp: abi.frame_size() as i64,
stack_map: None, stack_map: None,
cur_srcloc: Default::default(), cur_srcloc: Default::default(),
ctrl_plane,
} }
} }
@@ -657,6 +662,14 @@ impl MachInstEmitState<Inst> for EmitState {
fn pre_sourceloc(&mut self, srcloc: RelSourceLoc) { fn pre_sourceloc(&mut self, srcloc: RelSourceLoc) {
self.cur_srcloc = srcloc; self.cur_srcloc = srcloc;
} }
fn ctrl_plane_mut(&mut self) -> &mut ControlPlane {
&mut self.ctrl_plane
}
fn take_ctrl_plane(self) -> ControlPlane {
self.ctrl_plane
}
} }
impl EmitState { impl EmitState {
@@ -1511,7 +1524,7 @@ impl MachInstEmit for Inst {
let again_label = sink.get_label(); let again_label = sink.get_label();
// again: // again:
sink.bind_label(again_label); sink.bind_label(again_label, &mut state.ctrl_plane);
let srcloc = state.cur_srcloc(); let srcloc = state.cur_srcloc();
if !srcloc.is_default() && !flags.notrap() { if !srcloc.is_default() && !flags.notrap() {
@@ -1713,7 +1726,7 @@ impl MachInstEmit for Inst {
let out_label = sink.get_label(); let out_label = sink.get_label();
// again: // again:
sink.bind_label(again_label); sink.bind_label(again_label, &mut state.ctrl_plane);
let srcloc = state.cur_srcloc(); let srcloc = state.cur_srcloc();
if !srcloc.is_default() && !flags.notrap() { if !srcloc.is_default() && !flags.notrap() {
@@ -1762,7 +1775,7 @@ impl MachInstEmit for Inst {
sink.use_label_at_offset(br_again_offset, again_label, LabelUse::Branch19); sink.use_label_at_offset(br_again_offset, again_label, LabelUse::Branch19);
// out: // out:
sink.bind_label(out_label); sink.bind_label(out_label, &mut state.ctrl_plane);
} }
&Inst::LoadAcquire { &Inst::LoadAcquire {
access_ty, access_ty,
@@ -3007,13 +3020,13 @@ impl MachInstEmit for Inst {
sink.put4(enc_jump26(0b000101, 0 /* will be fixed up later */)); sink.put4(enc_jump26(0b000101, 0 /* will be fixed up later */));
// else: // else:
sink.bind_label(else_label); sink.bind_label(else_label, &mut state.ctrl_plane);
// mov rd, rn // mov rd, rn
sink.put4(enc_vecmov(/* 16b = */ true, rd, rn)); sink.put4(enc_vecmov(/* 16b = */ true, rd, rn));
// out: // out:
sink.bind_label(out_label); sink.bind_label(out_label, &mut state.ctrl_plane);
} }
&Inst::MovToNZCV { rn } => { &Inst::MovToNZCV { rn } => {
let rn = allocs.next(rn); let rn = allocs.next(rn);
@@ -3464,8 +3477,8 @@ impl MachInstEmit for Inst {
dest: BranchTarget::Label(jump_around_label), dest: BranchTarget::Label(jump_around_label),
}; };
jmp.emit(&[], sink, emit_info, state); jmp.emit(&[], sink, emit_info, state);
sink.emit_island(needed_space + 4); sink.emit_island(needed_space + 4, &mut state.ctrl_plane);
sink.bind_label(jump_around_label); sink.bind_label(jump_around_label, &mut state.ctrl_plane);
} }
} }
@@ -3579,7 +3592,7 @@ impl MachInstEmit for Inst {
// out at this time. // out at this time.
let loop_start = sink.get_label(); let loop_start = sink.get_label();
sink.bind_label(loop_start); sink.bind_label(loop_start, &mut state.ctrl_plane);
Inst::AluRRImm12 { Inst::AluRRImm12 {
alu_op: ALUOp::Sub, alu_op: ALUOp::Sub,
@@ -3614,7 +3627,7 @@ impl MachInstEmit for Inst {
kind: CondBrKind::Cond(Cond::Gt), kind: CondBrKind::Cond(Cond::Gt),
} }
.emit(&[], sink, emit_info, state); .emit(&[], sink, emit_info, state);
sink.bind_label(loop_end); sink.bind_label(loop_end, &mut state.ctrl_plane);
} }
} }

View File

@@ -7811,7 +7811,7 @@ fn test_aarch64_binemit() {
let mut buffer = MachBuffer::new(); let mut buffer = MachBuffer::new();
insn.emit(&[], &mut buffer, &emit_info, &mut Default::default()); insn.emit(&[], &mut buffer, &emit_info, &mut Default::default());
let buffer = buffer.finish(); let buffer = buffer.finish(&mut Default::default());
let actual_encoding = &buffer.stringify_code_bytes(); let actual_encoding = &buffer.stringify_code_bytes();
assert_eq!(expected_encoding, actual_encoding); assert_eq!(expected_encoding, actual_encoding);
} }

View File

@@ -91,7 +91,9 @@ mod tests {
Some(StackSlotData::new(StackSlotKind::ExplicitSlot, 64)), Some(StackSlotData::new(StackSlotKind::ExplicitSlot, 64)),
)); ));
let code = context.compile(&*isa).expect("expected compilation"); let code = context
.compile(&*isa, &mut Default::default())
.expect("expected compilation");
let fde = match code let fde = match code
.create_unwind_info(isa.as_ref()) .create_unwind_info(isa.as_ref())
@@ -130,7 +132,9 @@ mod tests {
let mut context = Context::for_function(create_multi_return_function(CallConv::SystemV)); let mut context = Context::for_function(create_multi_return_function(CallConv::SystemV));
let code = context.compile(&*isa).expect("expected compilation"); let code = context
.compile(&*isa, &mut Default::default())
.expect("expected compilation");
let fde = match code let fde = match code
.create_unwind_info(isa.as_ref()) .create_unwind_info(isa.as_ref())

View File

@@ -15,6 +15,7 @@ use crate::result::CodegenResult;
use crate::settings as shared_settings; use crate::settings as shared_settings;
use alloc::{boxed::Box, vec::Vec}; use alloc::{boxed::Box, vec::Vec};
use core::fmt; use core::fmt;
use cranelift_control::ControlPlane;
use regalloc2::MachineEnv; use regalloc2::MachineEnv;
use target_lexicon::{Aarch64Architecture, Architecture, OperatingSystem, Triple}; use target_lexicon::{Aarch64Architecture, Architecture, OperatingSystem, Triple};
@@ -72,6 +73,7 @@ impl TargetIsa for AArch64Backend {
func: &Function, func: &Function,
domtree: &DominatorTree, domtree: &DominatorTree,
want_disasm: bool, want_disasm: bool,
ctrl_plane: &mut ControlPlane,
) -> CodegenResult<CompiledCodeStencil> { ) -> CodegenResult<CompiledCodeStencil> {
let (vcode, regalloc_result) = self.compile_vcode(func, domtree)?; let (vcode, regalloc_result) = self.compile_vcode(func, domtree)?;
@@ -79,10 +81,11 @@ impl TargetIsa for AArch64Backend {
&regalloc_result, &regalloc_result,
want_disasm, want_disasm,
self.flags.machine_code_cfg_info(), self.flags.machine_code_cfg_info(),
ctrl_plane,
); );
let frame_size = emit_result.frame_size; let frame_size = emit_result.frame_size;
let value_labels_ranges = emit_result.value_labels_ranges; let value_labels_ranges = emit_result.value_labels_ranges;
let buffer = emit_result.buffer.finish(); let buffer = emit_result.buffer.finish(ctrl_plane);
let sized_stackslot_offsets = emit_result.sized_stackslot_offsets; let sized_stackslot_offsets = emit_result.sized_stackslot_offsets;
let dynamic_stackslot_offsets = emit_result.dynamic_stackslot_offsets; let dynamic_stackslot_offsets = emit_result.dynamic_stackslot_offsets;

View File

@@ -57,6 +57,7 @@ use crate::CodegenResult;
use alloc::{boxed::Box, sync::Arc, vec::Vec}; use alloc::{boxed::Box, sync::Arc, vec::Vec};
use core::fmt; use core::fmt;
use core::fmt::{Debug, Formatter}; use core::fmt::{Debug, Formatter};
use cranelift_control::ControlPlane;
use target_lexicon::{triple, Architecture, PointerWidth, Triple}; use target_lexicon::{triple, Architecture, PointerWidth, Triple};
// This module is made public here for benchmarking purposes. No guarantees are // This module is made public here for benchmarking purposes. No guarantees are
@@ -273,6 +274,7 @@ pub trait TargetIsa: fmt::Display + Send + Sync {
func: &Function, func: &Function,
domtree: &DominatorTree, domtree: &DominatorTree,
want_disasm: bool, want_disasm: bool,
ctrl_plane: &mut ControlPlane,
) -> CodegenResult<CompiledCodeStencil>; ) -> CodegenResult<CompiledCodeStencil>;
#[cfg(feature = "unwind")] #[cfg(feature = "unwind")]

View File

@@ -6,6 +6,7 @@ use crate::ir::TrapCode;
use crate::isa::riscv64::inst::*; use crate::isa::riscv64::inst::*;
use crate::isa::riscv64::inst::{zero_reg, AluOPRRR}; use crate::isa::riscv64::inst::{zero_reg, AluOPRRR};
use crate::machinst::{AllocationConsumer, Reg, Writable}; use crate::machinst::{AllocationConsumer, Reg, Writable};
use cranelift_control::ControlPlane;
use regalloc2::Allocation; use regalloc2::Allocation;
pub struct EmitInfo { pub struct EmitInfo {
@@ -110,6 +111,9 @@ pub struct EmitState {
stack_map: Option<StackMap>, stack_map: Option<StackMap>,
/// Current source-code location corresponding to instruction to be emitted. /// Current source-code location corresponding to instruction to be emitted.
cur_srcloc: RelSourceLoc, cur_srcloc: RelSourceLoc,
/// Only used during fuzz-testing. Otherwise, it is a zero-sized struct and
/// optimized away at compiletime. See [cranelift_control].
ctrl_plane: ControlPlane,
} }
impl EmitState { impl EmitState {
@@ -127,12 +131,16 @@ impl EmitState {
} }
impl MachInstEmitState<Inst> for EmitState { impl MachInstEmitState<Inst> for EmitState {
fn new(abi: &Callee<crate::isa::riscv64::abi::Riscv64MachineDeps>) -> Self { fn new(
abi: &Callee<crate::isa::riscv64::abi::Riscv64MachineDeps>,
ctrl_plane: ControlPlane,
) -> Self {
EmitState { EmitState {
virtual_sp_offset: 0, virtual_sp_offset: 0,
nominal_sp_to_fp: abi.frame_size() as i64, nominal_sp_to_fp: abi.frame_size() as i64,
stack_map: None, stack_map: None,
cur_srcloc: RelSourceLoc::default(), cur_srcloc: RelSourceLoc::default(),
ctrl_plane,
} }
} }
@@ -143,6 +151,14 @@ impl MachInstEmitState<Inst> for EmitState {
fn pre_sourceloc(&mut self, srcloc: RelSourceLoc) { fn pre_sourceloc(&mut self, srcloc: RelSourceLoc) {
self.cur_srcloc = srcloc; self.cur_srcloc = srcloc;
} }
fn ctrl_plane_mut(&mut self) -> &mut ControlPlane {
&mut self.ctrl_plane
}
fn take_ctrl_plane(self) -> ControlPlane {
self.ctrl_plane
}
} }
impl Inst { impl Inst {
@@ -997,7 +1013,7 @@ impl MachInstEmit for Inst {
// we need to emit a jump table here to support that jump. // we need to emit a jump table here to support that jump.
let distance = (targets.len() * 2 * Inst::INSTRUCTION_SIZE as usize) as u32; let distance = (targets.len() * 2 * Inst::INSTRUCTION_SIZE as usize) as u32;
if sink.island_needed(distance) { if sink.island_needed(distance) {
sink.emit_island(distance); sink.emit_island(distance, &mut state.ctrl_plane);
} }
// Emit the jumps back to back // Emit the jumps back to back
@@ -1125,13 +1141,13 @@ impl MachInstEmit for Inst {
insts insts
.drain(..) .drain(..)
.for_each(|i: Inst| i.emit(&[], sink, emit_info, state)); .for_each(|i: Inst| i.emit(&[], sink, emit_info, state));
sink.bind_label(label_false); sink.bind_label(label_false, &mut state.ctrl_plane);
// select second value1 // select second value1
insts.extend(gen_moves(&dst[..], y.regs())); insts.extend(gen_moves(&dst[..], y.regs()));
insts insts
.into_iter() .into_iter()
.for_each(|i| i.emit(&[], sink, emit_info, state)); .for_each(|i| i.emit(&[], sink, emit_info, state));
sink.bind_label(label_jump_over); sink.bind_label(label_jump_over, &mut state.ctrl_plane);
} }
&Inst::Jalr { rd, base, offset } => { &Inst::Jalr { rd, base, offset } => {
let rd = allocs.next_writable(rd); let rd = allocs.next_writable(rd);
@@ -1167,13 +1183,13 @@ impl MachInstEmit for Inst {
.into_iter() .into_iter()
.for_each(|i| i.emit(&[], sink, emit_info, state)); .for_each(|i| i.emit(&[], sink, emit_info, state));
sink.bind_label(label_true); sink.bind_label(label_true, &mut state.ctrl_plane);
Inst::load_imm12(rd, Imm12::TRUE).emit(&[], sink, emit_info, state); Inst::load_imm12(rd, Imm12::TRUE).emit(&[], sink, emit_info, state);
Inst::Jal { Inst::Jal {
dest: BranchTarget::offset(Inst::INSTRUCTION_SIZE * 2), dest: BranchTarget::offset(Inst::INSTRUCTION_SIZE * 2),
} }
.emit(&[], sink, emit_info, state); .emit(&[], sink, emit_info, state);
sink.bind_label(label_false); sink.bind_label(label_false, &mut state.ctrl_plane);
Inst::load_imm12(rd, Imm12::FALSE).emit(&[], sink, emit_info, state); Inst::load_imm12(rd, Imm12::FALSE).emit(&[], sink, emit_info, state);
} }
&Inst::AtomicCas { &Inst::AtomicCas {
@@ -1204,7 +1220,7 @@ impl MachInstEmit for Inst {
// fail: // fail:
let fail_label = sink.get_label(); let fail_label = sink.get_label();
let cas_lebel = sink.get_label(); let cas_lebel = sink.get_label();
sink.bind_label(cas_lebel); sink.bind_label(cas_lebel, &mut state.ctrl_plane);
Inst::Atomic { Inst::Atomic {
op: AtomicOP::load_op(ty), op: AtomicOP::load_op(ty),
rd: dst, rd: dst,
@@ -1274,7 +1290,7 @@ impl MachInstEmit for Inst {
}, },
} }
.emit(&[], sink, emit_info, state); .emit(&[], sink, emit_info, state);
sink.bind_label(fail_label); sink.bind_label(fail_label, &mut state.ctrl_plane);
} }
&Inst::AtomicRmwLoop { &Inst::AtomicRmwLoop {
offset, offset,
@@ -1291,7 +1307,7 @@ impl MachInstEmit for Inst {
let t0 = allocs.next_writable(t0); let t0 = allocs.next_writable(t0);
let dst = allocs.next_writable(dst); let dst = allocs.next_writable(dst);
let retry = sink.get_label(); let retry = sink.get_label();
sink.bind_label(retry); sink.bind_label(retry, &mut state.ctrl_plane);
// load old value. // load old value.
Inst::Atomic { Inst::Atomic {
op: AtomicOP::load_op(ty), op: AtomicOP::load_op(ty),
@@ -1419,9 +1435,9 @@ impl MachInstEmit for Inst {
dest: BranchTarget::Label(label_select_done), dest: BranchTarget::Label(label_select_done),
} }
.emit(&[], sink, emit_info, state); .emit(&[], sink, emit_info, state);
sink.bind_label(label_select_dst); sink.bind_label(label_select_dst, &mut state.ctrl_plane);
Inst::gen_move(t0, dst.to_reg(), I64).emit(&[], sink, emit_info, state); Inst::gen_move(t0, dst.to_reg(), I64).emit(&[], sink, emit_info, state);
sink.bind_label(label_select_done); sink.bind_label(label_select_done, &mut state.ctrl_plane);
Inst::Atomic { Inst::Atomic {
op: AtomicOP::load_op(ty), op: AtomicOP::load_op(ty),
rd: writable_spilltmp_reg2(), rd: writable_spilltmp_reg2(),
@@ -1534,13 +1550,13 @@ impl MachInstEmit for Inst {
.for_each(|i| i.emit(&[], sink, emit_info, state)); .for_each(|i| i.emit(&[], sink, emit_info, state));
}; };
//here is true , use x. //here is true , use x.
sink.bind_label(label_true); sink.bind_label(label_true, &mut state.ctrl_plane);
gen_move(&dst, &x, sink, state); gen_move(&dst, &x, sink, state);
Inst::gen_jump(label_done).emit(&[], sink, emit_info, state); Inst::gen_jump(label_done).emit(&[], sink, emit_info, state);
// here is false use y // here is false use y
sink.bind_label(label_false); sink.bind_label(label_false, &mut state.ctrl_plane);
gen_move(&dst, &y, sink, state); gen_move(&dst, &y, sink, state);
sink.bind_label(label_done); sink.bind_label(label_done, &mut state.ctrl_plane);
} }
&Inst::Csr { &Inst::Csr {
csr_op, csr_op,
@@ -1585,9 +1601,9 @@ impl MachInstEmit for Inst {
} }
.emit(&[], sink, emit_info, state); .emit(&[], sink, emit_info, state);
// here condition is true , use rs1 // here condition is true , use rs1
sink.bind_label(label_true); sink.bind_label(label_true, &mut state.ctrl_plane);
Inst::gen_move(rd, rs1, I64).emit(&[], sink, emit_info, state); Inst::gen_move(rd, rs1, I64).emit(&[], sink, emit_info, state);
sink.bind_label(label_jump_over); sink.bind_label(label_jump_over, &mut state.ctrl_plane);
} }
&Inst::FcvtToInt { &Inst::FcvtToInt {
is_sat, is_sat,
@@ -1747,7 +1763,7 @@ impl MachInstEmit for Inst {
} }
.emit(&[], sink, emit_info, state); .emit(&[], sink, emit_info, state);
// here is nan , move 0 into rd register // here is nan , move 0 into rd register
sink.bind_label(label_nan); sink.bind_label(label_nan, &mut state.ctrl_plane);
if is_sat { if is_sat {
Inst::load_imm12(rd, Imm12::from_bits(0)).emit(&[], sink, emit_info, state); Inst::load_imm12(rd, Imm12::from_bits(0)).emit(&[], sink, emit_info, state);
} else { } else {
@@ -1758,7 +1774,7 @@ impl MachInstEmit for Inst {
.emit(&[], sink, emit_info, state); .emit(&[], sink, emit_info, state);
} }
// bind jump_over // bind jump_over
sink.bind_label(label_jump_over); sink.bind_label(label_jump_over, &mut state.ctrl_plane);
} }
&Inst::LoadExtName { &Inst::LoadExtName {
@@ -1812,12 +1828,12 @@ impl MachInstEmit for Inst {
} }
.emit(&[], sink, emit_info, state); .emit(&[], sink, emit_info, state);
// trap // trap
sink.bind_label(label_trap); sink.bind_label(label_trap, &mut state.ctrl_plane);
Inst::Udf { Inst::Udf {
trap_code: trap_code, trap_code: trap_code,
} }
.emit(&[], sink, emit_info, state); .emit(&[], sink, emit_info, state);
sink.bind_label(label_jump_over); sink.bind_label(label_jump_over, &mut state.ctrl_plane);
} }
&Inst::TrapIf { test, trap_code } => { &Inst::TrapIf { test, trap_code } => {
let test = allocs.next(test); let test = allocs.next(test);
@@ -1834,12 +1850,12 @@ impl MachInstEmit for Inst {
} }
.emit(&[], sink, emit_info, state); .emit(&[], sink, emit_info, state);
// trap // trap
sink.bind_label(label_trap); sink.bind_label(label_trap, &mut state.ctrl_plane);
Inst::Udf { Inst::Udf {
trap_code: trap_code, trap_code: trap_code,
} }
.emit(&[], sink, emit_info, state); .emit(&[], sink, emit_info, state);
sink.bind_label(label_jump_over); sink.bind_label(label_jump_over, &mut state.ctrl_plane);
} }
&Inst::Udf { trap_code } => { &Inst::Udf { trap_code } => {
sink.add_trap(trap_code); sink.add_trap(trap_code);
@@ -1874,7 +1890,7 @@ impl MachInstEmit for Inst {
.emit(&[], sink, emit_info, state); .emit(&[], sink, emit_info, state);
// here select x. // here select x.
sink.bind_label(label_select_x); sink.bind_label(label_select_x, &mut state.ctrl_plane);
gen_moves(&rd[..], x.regs()) gen_moves(&rd[..], x.regs())
.into_iter() .into_iter()
.for_each(|i| i.emit(&[], sink, emit_info, state)); .for_each(|i| i.emit(&[], sink, emit_info, state));
@@ -1884,11 +1900,11 @@ impl MachInstEmit for Inst {
} }
.emit(&[], sink, emit_info, state); .emit(&[], sink, emit_info, state);
// here select y. // here select y.
sink.bind_label(label_select_y); sink.bind_label(label_select_y, &mut state.ctrl_plane);
gen_moves(&rd[..], y.regs()) gen_moves(&rd[..], y.regs())
.into_iter() .into_iter()
.for_each(|i| i.emit(&[], sink, emit_info, state)); .for_each(|i| i.emit(&[], sink, emit_info, state));
sink.bind_label(label_jump_over); sink.bind_label(label_jump_over, &mut state.ctrl_plane);
} }
&Inst::AtomicLoad { rd, ty, p } => { &Inst::AtomicLoad { rd, ty, p } => {
let p = allocs.next(p); let p = allocs.next(p);
@@ -2049,7 +2065,7 @@ impl MachInstEmit for Inst {
} }
.emit(&[], sink, emit_info, state); .emit(&[], sink, emit_info, state);
// here is nan. // here is nan.
sink.bind_label(label_nan); sink.bind_label(label_nan, &mut state.ctrl_plane);
Inst::FpuRRR { Inst::FpuRRR {
alu_op: if ty == F32 { alu_op: if ty == F32 {
FpuOPRRR::FaddS FpuOPRRR::FaddS
@@ -2067,9 +2083,9 @@ impl MachInstEmit for Inst {
} }
.emit(&[], sink, emit_info, state); .emit(&[], sink, emit_info, state);
// here select origin x. // here select origin x.
sink.bind_label(label_x); sink.bind_label(label_x, &mut state.ctrl_plane);
Inst::gen_move(rd, rs, ty).emit(&[], sink, emit_info, state); Inst::gen_move(rd, rs, ty).emit(&[], sink, emit_info, state);
sink.bind_label(label_jump_over); sink.bind_label(label_jump_over, &mut state.ctrl_plane);
} }
&Inst::FloatSelectPseudo { &Inst::FloatSelectPseudo {
op, op,
@@ -2114,9 +2130,9 @@ impl MachInstEmit for Inst {
dest: BranchTarget::Label(label_jump_over), dest: BranchTarget::Label(label_jump_over),
} }
.emit(&[], sink, emit_info, state); .emit(&[], sink, emit_info, state);
sink.bind_label(label_rs2); sink.bind_label(label_rs2, &mut state.ctrl_plane);
Inst::gen_move(rd, rs2, ty).emit(&[], sink, emit_info, state); Inst::gen_move(rd, rs2, ty).emit(&[], sink, emit_info, state);
sink.bind_label(label_jump_over); sink.bind_label(label_jump_over, &mut state.ctrl_plane);
} }
&Inst::FloatSelect { &Inst::FloatSelect {
@@ -2224,7 +2240,7 @@ impl MachInstEmit for Inst {
} }
.emit(&[], sink, emit_info, state); .emit(&[], sink, emit_info, state);
// //
sink.bind_label(label_done); sink.bind_label(label_done, &mut state.ctrl_plane);
} }
// we have the reuslt,jump over. // we have the reuslt,jump over.
Inst::Jal { Inst::Jal {
@@ -2232,7 +2248,7 @@ impl MachInstEmit for Inst {
} }
.emit(&[], sink, emit_info, state); .emit(&[], sink, emit_info, state);
// here is nan. // here is nan.
sink.bind_label(label_nan); sink.bind_label(label_nan, &mut state.ctrl_plane);
op.snan_bits(tmp, ty) op.snan_bits(tmp, ty)
.into_iter() .into_iter()
.for_each(|i| i.emit(&[], sink, emit_info, state)); .for_each(|i| i.emit(&[], sink, emit_info, state));
@@ -2244,7 +2260,7 @@ impl MachInstEmit for Inst {
rs: tmp.to_reg(), rs: tmp.to_reg(),
} }
.emit(&[], sink, emit_info, state); .emit(&[], sink, emit_info, state);
sink.bind_label(label_jump_over); sink.bind_label(label_jump_over, &mut state.ctrl_plane);
} }
&Inst::Popcnt { &Inst::Popcnt {
sum, sum,
@@ -2277,7 +2293,7 @@ impl MachInstEmit for Inst {
.emit(&[], sink, emit_info, state); .emit(&[], sink, emit_info, state);
let label_done = sink.get_label(); let label_done = sink.get_label();
let label_loop = sink.get_label(); let label_loop = sink.get_label();
sink.bind_label(label_loop); sink.bind_label(label_loop, &mut state.ctrl_plane);
Inst::CondBr { Inst::CondBr {
taken: BranchTarget::Label(label_done), taken: BranchTarget::Label(label_done),
not_taken: BranchTarget::zero(), not_taken: BranchTarget::zero(),
@@ -2315,7 +2331,7 @@ impl MachInstEmit for Inst {
imm12: Imm12::from_bits(1), imm12: Imm12::from_bits(1),
} }
.emit(&[], sink, emit_info, state); .emit(&[], sink, emit_info, state);
sink.bind_label(label_over); sink.bind_label(label_over, &mut state.ctrl_plane);
} }
// set step and tmp. // set step and tmp.
{ {
@@ -2338,7 +2354,7 @@ impl MachInstEmit for Inst {
} }
.emit(&[], sink, emit_info, state); .emit(&[], sink, emit_info, state);
} }
sink.bind_label(label_done); sink.bind_label(label_done, &mut state.ctrl_plane);
} }
&Inst::Rev8 { rs, rd, tmp, step } => { &Inst::Rev8 { rs, rd, tmp, step } => {
let rs = allocs.next(rs); let rs = allocs.next(rs);
@@ -2352,7 +2368,7 @@ impl MachInstEmit for Inst {
Inst::load_imm12(step, Imm12::from_bits(56)).emit(&[], sink, emit_info, state); Inst::load_imm12(step, Imm12::from_bits(56)).emit(&[], sink, emit_info, state);
let label_done = sink.get_label(); let label_done = sink.get_label();
let label_loop = sink.get_label(); let label_loop = sink.get_label();
sink.bind_label(label_loop); sink.bind_label(label_loop, &mut state.ctrl_plane);
Inst::CondBr { Inst::CondBr {
taken: BranchTarget::Label(label_done), taken: BranchTarget::Label(label_done),
not_taken: BranchTarget::zero(), not_taken: BranchTarget::zero(),
@@ -2408,7 +2424,7 @@ impl MachInstEmit for Inst {
} }
} }
.emit(&[], sink, emit_info, state); .emit(&[], sink, emit_info, state);
sink.bind_label(label_done); sink.bind_label(label_done, &mut state.ctrl_plane);
} }
&Inst::Cltz { &Inst::Cltz {
sum, sum,
@@ -2444,7 +2460,7 @@ impl MachInstEmit for Inst {
} }
let label_done = sink.get_label(); let label_done = sink.get_label();
let label_loop = sink.get_label(); let label_loop = sink.get_label();
sink.bind_label(label_loop); sink.bind_label(label_loop, &mut state.ctrl_plane);
Inst::CondBr { Inst::CondBr {
taken: BranchTarget::Label(label_done), taken: BranchTarget::Label(label_done),
not_taken: BranchTarget::zero(), not_taken: BranchTarget::zero(),
@@ -2507,7 +2523,7 @@ impl MachInstEmit for Inst {
} }
.emit(&[], sink, emit_info, state); .emit(&[], sink, emit_info, state);
} }
sink.bind_label(label_done); sink.bind_label(label_done, &mut state.ctrl_plane);
} }
&Inst::Brev8 { &Inst::Brev8 {
rs, rs,
@@ -2549,7 +2565,7 @@ impl MachInstEmit for Inst {
let label_done = sink.get_label(); let label_done = sink.get_label();
let label_loop = sink.get_label(); let label_loop = sink.get_label();
sink.bind_label(label_loop); sink.bind_label(label_loop, &mut state.ctrl_plane);
Inst::CondBr { Inst::CondBr {
taken: BranchTarget::Label(label_done), taken: BranchTarget::Label(label_done),
not_taken: BranchTarget::zero(), not_taken: BranchTarget::zero(),
@@ -2587,7 +2603,7 @@ impl MachInstEmit for Inst {
rs2: tmp2.to_reg(), rs2: tmp2.to_reg(),
} }
.emit(&[], sink, emit_info, state); .emit(&[], sink, emit_info, state);
sink.bind_label(label_over); sink.bind_label(label_over, &mut state.ctrl_plane);
} }
// set step and tmp. // set step and tmp.
{ {
@@ -2645,7 +2661,7 @@ impl MachInstEmit for Inst {
dest: BranchTarget::Label(label_over), dest: BranchTarget::Label(label_over),
} }
.emit(&[], sink, emit_info, state); .emit(&[], sink, emit_info, state);
sink.bind_label(label_sll_1); sink.bind_label(label_sll_1, &mut state.ctrl_plane);
Inst::AluRRImm12 { Inst::AluRRImm12 {
alu_op: AluOPRRI::Slli, alu_op: AluOPRRI::Slli,
rd: tmp2, rd: tmp2,
@@ -2653,14 +2669,14 @@ impl MachInstEmit for Inst {
imm12: Imm12::from_bits(1), imm12: Imm12::from_bits(1),
} }
.emit(&[], sink, emit_info, state); .emit(&[], sink, emit_info, state);
sink.bind_label(label_over); sink.bind_label(label_over, &mut state.ctrl_plane);
} }
Inst::Jal { Inst::Jal {
dest: BranchTarget::Label(label_loop), dest: BranchTarget::Label(label_loop),
} }
.emit(&[], sink, emit_info, state); .emit(&[], sink, emit_info, state);
} }
sink.bind_label(label_done); sink.bind_label(label_done, &mut state.ctrl_plane);
} }
&Inst::StackProbeLoop { &Inst::StackProbeLoop {
guard_size, guard_size,
@@ -2681,7 +2697,7 @@ impl MachInstEmit for Inst {
let loop_start = sink.get_label(); let loop_start = sink.get_label();
let label_done = sink.get_label(); let label_done = sink.get_label();
sink.bind_label(loop_start); sink.bind_label(loop_start, &mut state.ctrl_plane);
Inst::CondBr { Inst::CondBr {
taken: BranchTarget::Label(label_done), taken: BranchTarget::Label(label_done),
not_taken: BranchTarget::zero(), not_taken: BranchTarget::zero(),
@@ -2719,7 +2735,7 @@ impl MachInstEmit for Inst {
dest: BranchTarget::Label(loop_start), dest: BranchTarget::Label(loop_start),
} }
.emit(&[], sink, emit_info, state); .emit(&[], sink, emit_info, state);
sink.bind_label(label_done); sink.bind_label(label_done, &mut state.ctrl_plane);
} }
}; };
let end_off = sink.cur_offset(); let end_off = sink.cur_offset();

View File

@@ -2077,7 +2077,7 @@ fn test_riscv64_binemit() {
let mut buffer = MachBuffer::new(); let mut buffer = MachBuffer::new();
unit.inst unit.inst
.emit(&[], &mut buffer, &emit_info, &mut Default::default()); .emit(&[], &mut buffer, &emit_info, &mut Default::default());
let buffer = buffer.finish(); let buffer = buffer.finish(&mut Default::default());
if buffer.data() != unit.code.to_le_bytes() { if buffer.data() != unit.code.to_le_bytes() {
{ {
let gnu = DebugRTypeInst::from_bs(&unit.code.to_le_bytes()); let gnu = DebugRTypeInst::from_bs(&unit.code.to_le_bytes());
@@ -2304,7 +2304,7 @@ fn riscv64_worst_case_instruction_size() {
for i in candidates { for i in candidates {
let mut buffer = MachBuffer::new(); let mut buffer = MachBuffer::new();
i.emit(&[], &mut buffer, &emit_info, &mut Default::default()); i.emit(&[], &mut buffer, &emit_info, &mut Default::default());
let buffer = buffer.finish(); let buffer = buffer.finish(&mut Default::default());
let length = buffer.data().len() as u32; let length = buffer.data().len() as u32;
if length > max.0 { if length > max.0 {
let length = buffer.data().len() as u32; let length = buffer.data().len() as u32;

View File

@@ -89,7 +89,9 @@ mod tests {
Some(StackSlotData::new(StackSlotKind::ExplicitSlot, 64)), Some(StackSlotData::new(StackSlotKind::ExplicitSlot, 64)),
)); ));
let code = context.compile(&*isa).expect("expected compilation"); let code = context
.compile(&*isa, &mut Default::default())
.expect("expected compilation");
let fde = match code let fde = match code
.create_unwind_info(isa.as_ref()) .create_unwind_info(isa.as_ref())
@@ -129,7 +131,9 @@ mod tests {
let mut context = Context::for_function(create_multi_return_function(CallConv::SystemV)); let mut context = Context::for_function(create_multi_return_function(CallConv::SystemV));
let code = context.compile(&*isa).expect("expected compilation"); let code = context
.compile(&*isa, &mut Default::default())
.expect("expected compilation");
let fde = match code let fde = match code
.create_unwind_info(isa.as_ref()) .create_unwind_info(isa.as_ref())

View File

@@ -15,6 +15,7 @@ use crate::result::CodegenResult;
use crate::settings as shared_settings; use crate::settings as shared_settings;
use alloc::{boxed::Box, vec::Vec}; use alloc::{boxed::Box, vec::Vec};
use core::fmt; use core::fmt;
use cranelift_control::ControlPlane;
use regalloc2::MachineEnv; use regalloc2::MachineEnv;
use target_lexicon::{Architecture, Triple}; use target_lexicon::{Architecture, Triple};
mod abi; mod abi;
@@ -72,6 +73,7 @@ impl TargetIsa for Riscv64Backend {
func: &Function, func: &Function,
domtree: &DominatorTree, domtree: &DominatorTree,
want_disasm: bool, want_disasm: bool,
ctrl_plane: &mut ControlPlane,
) -> CodegenResult<CompiledCodeStencil> { ) -> CodegenResult<CompiledCodeStencil> {
let (vcode, regalloc_result) = self.compile_vcode(func, domtree)?; let (vcode, regalloc_result) = self.compile_vcode(func, domtree)?;
@@ -80,10 +82,11 @@ impl TargetIsa for Riscv64Backend {
&regalloc_result, &regalloc_result,
want_disasm, want_disasm,
self.flags.machine_code_cfg_info(), self.flags.machine_code_cfg_info(),
ctrl_plane,
); );
let frame_size = emit_result.frame_size; let frame_size = emit_result.frame_size;
let value_labels_ranges = emit_result.value_labels_ranges; let value_labels_ranges = emit_result.value_labels_ranges;
let buffer = emit_result.buffer.finish(); let buffer = emit_result.buffer.finish(ctrl_plane);
let sized_stackslot_offsets = emit_result.sized_stackslot_offsets; let sized_stackslot_offsets = emit_result.sized_stackslot_offsets;
let dynamic_stackslot_offsets = emit_result.dynamic_stackslot_offsets; let dynamic_stackslot_offsets = emit_result.dynamic_stackslot_offsets;

View File

@@ -8,6 +8,7 @@ use crate::isa::s390x::settings as s390x_settings;
use crate::machinst::{Reg, RegClass}; use crate::machinst::{Reg, RegClass};
use crate::trace; use crate::trace;
use core::convert::TryFrom; use core::convert::TryFrom;
use cranelift_control::ControlPlane;
use regalloc2::Allocation; use regalloc2::Allocation;
/// Debug macro for testing that a regpair is valid: that the high register is even, and the low /// Debug macro for testing that a regpair is valid: that the high register is even, and the low
@@ -1347,15 +1348,19 @@ pub struct EmitState {
stack_map: Option<StackMap>, stack_map: Option<StackMap>,
/// Current source-code location corresponding to instruction to be emitted. /// Current source-code location corresponding to instruction to be emitted.
cur_srcloc: RelSourceLoc, cur_srcloc: RelSourceLoc,
/// Only used during fuzz-testing. Otherwise, it is a zero-sized struct and
/// optimized away at compiletime. See [cranelift_control].
ctrl_plane: ControlPlane,
} }
impl MachInstEmitState<Inst> for EmitState { impl MachInstEmitState<Inst> for EmitState {
fn new(abi: &Callee<S390xMachineDeps>) -> Self { fn new(abi: &Callee<S390xMachineDeps>, ctrl_plane: ControlPlane) -> Self {
EmitState { EmitState {
virtual_sp_offset: 0, virtual_sp_offset: 0,
initial_sp_offset: abi.frame_size() as i64, initial_sp_offset: abi.frame_size() as i64,
stack_map: None, stack_map: None,
cur_srcloc: Default::default(), cur_srcloc: Default::default(),
ctrl_plane,
} }
} }
@@ -1366,6 +1371,14 @@ impl MachInstEmitState<Inst> for EmitState {
fn pre_sourceloc(&mut self, srcloc: RelSourceLoc) { fn pre_sourceloc(&mut self, srcloc: RelSourceLoc) {
self.cur_srcloc = srcloc; self.cur_srcloc = srcloc;
} }
fn ctrl_plane_mut(&mut self) -> &mut ControlPlane {
&mut self.ctrl_plane
}
fn take_ctrl_plane(self) -> ControlPlane {
self.ctrl_plane
}
} }
impl EmitState { impl EmitState {
@@ -2137,7 +2150,7 @@ impl Inst {
let done_label = sink.get_label(); let done_label = sink.get_label();
// Emit label at the start of the loop. // Emit label at the start of the loop.
sink.bind_label(loop_label); sink.bind_label(loop_label, &mut state.ctrl_plane);
for inst in (&body).into_iter() { for inst in (&body).into_iter() {
match &inst { match &inst {
@@ -2160,7 +2173,7 @@ impl Inst {
inst.emit(&[], sink, emit_info, state); inst.emit(&[], sink, emit_info, state);
// Emit label at the end of the loop. // Emit label at the end of the loop.
sink.bind_label(done_label); sink.bind_label(done_label, &mut state.ctrl_plane);
} }
&Inst::CondBreak { .. } => unreachable!(), // Only valid inside a Loop. &Inst::CondBreak { .. } => unreachable!(), // Only valid inside a Loop.
&Inst::AtomicCas32 { &Inst::AtomicCas32 {
@@ -3646,7 +3659,7 @@ impl Inst {
// The first entry is the default target, which is not emitted // The first entry is the default target, which is not emitted
// into the jump table, so we skip it here. It is only in the // into the jump table, so we skip it here. It is only in the
// list so MachTerminator will see the potential target. // list so MachTerminator will see the potential target.
sink.bind_label(table_label); sink.bind_label(table_label, &mut state.ctrl_plane);
let jt_off = sink.cur_offset(); let jt_off = sink.cur_offset();
for &target in targets.iter().skip(1) { for &target in targets.iter().skip(1) {
let word_off = sink.cur_offset(); let word_off = sink.cur_offset();

View File

@@ -13363,6 +13363,7 @@ fn test_s390x_binemit() {
let mut isa_flag_builder = s390x_settings::builder(); let mut isa_flag_builder = s390x_settings::builder();
isa_flag_builder.enable("arch13").unwrap(); isa_flag_builder.enable("arch13").unwrap();
let isa_flags = s390x_settings::Flags::new(&flags, &isa_flag_builder); let isa_flags = s390x_settings::Flags::new(&flags, &isa_flag_builder);
let ctrl_plane = &mut Default::default();
let emit_info = EmitInfo::new(isa_flags); let emit_info = EmitInfo::new(isa_flags);
for (insn, expected_encoding, expected_printing) in insns { for (insn, expected_encoding, expected_printing) in insns {
@@ -13380,16 +13381,16 @@ fn test_s390x_binemit() {
// Label 0 before the instruction. // Label 0 before the instruction.
let label0 = buffer.get_label(); let label0 = buffer.get_label();
buffer.bind_label(label0); buffer.bind_label(label0, ctrl_plane);
// Emit the instruction. // Emit the instruction.
insn.emit(&[], &mut buffer, &emit_info, &mut Default::default()); insn.emit(&[], &mut buffer, &emit_info, &mut Default::default());
// Label 1 after the instruction. // Label 1 after the instruction.
let label1 = buffer.get_label(); let label1 = buffer.get_label();
buffer.bind_label(label1); buffer.bind_label(label1, ctrl_plane);
let buffer = buffer.finish(); let buffer = buffer.finish(ctrl_plane);
let actual_encoding = &buffer.stringify_code_bytes(); let actual_encoding = &buffer.stringify_code_bytes();
assert_eq!(expected_encoding, actual_encoding); assert_eq!(expected_encoding, actual_encoding);
} }

View File

@@ -122,7 +122,9 @@ mod tests {
Some(StackSlotData::new(StackSlotKind::ExplicitSlot, 64)), Some(StackSlotData::new(StackSlotKind::ExplicitSlot, 64)),
)); ));
let code = context.compile(&*isa).expect("expected compilation"); let code = context
.compile(&*isa, &mut Default::default())
.expect("expected compilation");
let fde = match code let fde = match code
.create_unwind_info(isa.as_ref()) .create_unwind_info(isa.as_ref())
@@ -164,7 +166,9 @@ mod tests {
Some(StackSlotData::new(StackSlotKind::ExplicitSlot, 64)), Some(StackSlotData::new(StackSlotKind::ExplicitSlot, 64)),
)); ));
let code = context.compile(&*isa).expect("expected compilation"); let code = context
.compile(&*isa, &mut Default::default())
.expect("expected compilation");
let fde = match code let fde = match code
.create_unwind_info(isa.as_ref()) .create_unwind_info(isa.as_ref())

View File

@@ -15,6 +15,7 @@ use crate::result::CodegenResult;
use crate::settings as shared_settings; use crate::settings as shared_settings;
use alloc::{boxed::Box, vec::Vec}; use alloc::{boxed::Box, vec::Vec};
use core::fmt; use core::fmt;
use cranelift_control::ControlPlane;
use regalloc2::MachineEnv; use regalloc2::MachineEnv;
use target_lexicon::{Architecture, Triple}; use target_lexicon::{Architecture, Triple};
@@ -72,14 +73,20 @@ impl TargetIsa for S390xBackend {
func: &Function, func: &Function,
domtree: &DominatorTree, domtree: &DominatorTree,
want_disasm: bool, want_disasm: bool,
ctrl_plane: &mut ControlPlane,
) -> CodegenResult<CompiledCodeStencil> { ) -> CodegenResult<CompiledCodeStencil> {
let flags = self.flags(); let flags = self.flags();
let (vcode, regalloc_result) = self.compile_vcode(func, domtree)?; let (vcode, regalloc_result) = self.compile_vcode(func, domtree)?;
let emit_result = vcode.emit(&regalloc_result, want_disasm, flags.machine_code_cfg_info()); let emit_result = vcode.emit(
&regalloc_result,
want_disasm,
flags.machine_code_cfg_info(),
ctrl_plane,
);
let frame_size = emit_result.frame_size; let frame_size = emit_result.frame_size;
let value_labels_ranges = emit_result.value_labels_ranges; let value_labels_ranges = emit_result.value_labels_ranges;
let buffer = emit_result.buffer.finish(); let buffer = emit_result.buffer.finish(ctrl_plane);
let sized_stackslot_offsets = emit_result.sized_stackslot_offsets; let sized_stackslot_offsets = emit_result.sized_stackslot_offsets;
let dynamic_stackslot_offsets = emit_result.dynamic_stackslot_offsets; let dynamic_stackslot_offsets = emit_result.dynamic_stackslot_offsets;

View File

@@ -357,7 +357,7 @@ mod tests {
.imm(0x17) .imm(0x17)
.encode(&mut sink); .encode(&mut sink);
let bytes = sink.finish().data; let bytes = sink.finish(&mut Default::default()).data;
assert_eq!(bytes.as_slice(), [0xc5, 0xf1, 0x73, 0xfa, 0x17]); assert_eq!(bytes.as_slice(), [0xc5, 0xf1, 0x73, 0xfa, 0x17]);
} }
@@ -385,7 +385,7 @@ mod tests {
.imm_reg(c) .imm_reg(c)
.encode(&mut sink); .encode(&mut sink);
let bytes = sink.finish().data; let bytes = sink.finish(&mut Default::default()).data;
assert_eq!(bytes.as_slice(), [0xc4, 0xe3, 0x69, 0x4b, 0xcb, 0x40]); assert_eq!(bytes.as_slice(), [0xc4, 0xe3, 0x69, 0x4b, 0xcb, 0x40]);
} }
@@ -410,7 +410,7 @@ mod tests {
.imm(4) .imm(4)
.encode(&mut sink); .encode(&mut sink);
let bytes = sink.finish().data; let bytes = sink.finish(&mut Default::default()).data;
assert_eq!(bytes.as_slice(), [0xc4, 0x41, 0x24, 0xc2, 0xd4, 0x04]); assert_eq!(bytes.as_slice(), [0xc4, 0x41, 0x24, 0xc2, 0xd4, 0x04]);
} }
@@ -434,7 +434,7 @@ mod tests {
.rm(src2) .rm(src2)
.encode(&mut sink); .encode(&mut sink);
let bytes = sink.finish().data; let bytes = sink.finish(&mut Default::default()).data;
assert_eq!(bytes.as_slice(), [0xc5, 0xf0, 0x55, 0xd0]); assert_eq!(bytes.as_slice(), [0xc5, 0xf0, 0x55, 0xd0]);
} }
@@ -462,7 +462,7 @@ mod tests {
.rm(src2) .rm(src2)
.encode(&mut sink); .encode(&mut sink);
let bytes = sink.finish().data; let bytes = sink.finish(&mut Default::default()).data;
assert_eq!(bytes.as_slice(), [0xc4, 0xc1, 0x70, 0x55, 0x55, 0x0a]); assert_eq!(bytes.as_slice(), [0xc4, 0xc1, 0x70, 0x55, 0x55, 0x0a]);
} }
@@ -492,7 +492,7 @@ mod tests {
.rm(src2) .rm(src2)
.encode(&mut sink); .encode(&mut sink);
let bytes = sink.finish().data; let bytes = sink.finish(&mut Default::default()).data;
assert_eq!(bytes.as_slice(), [0xc4, 0xa1, 0x70, 0x55, 0x54, 0xa8, 100]); assert_eq!(bytes.as_slice(), [0xc4, 0xa1, 0x70, 0x55, 0x54, 0xa8, 100]);
} }
} }

View File

@@ -620,7 +620,7 @@ pub(crate) fn emit(
// Here the `idiv` is executed, which is different depending on the // Here the `idiv` is executed, which is different depending on the
// size // size
sink.bind_label(do_op); sink.bind_label(do_op, &mut state.ctrl_plane);
let inst = match size { let inst = match size {
OperandSize::Size8 => Inst::div8( OperandSize::Size8 => Inst::div8(
DivSignedness::Signed, DivSignedness::Signed,
@@ -642,7 +642,7 @@ pub(crate) fn emit(
}; };
inst.emit(&[], sink, info, state); inst.emit(&[], sink, info, state);
sink.bind_label(done_label); sink.bind_label(done_label, &mut state.ctrl_plane);
} }
Inst::Imm { Inst::Imm {
@@ -1291,7 +1291,7 @@ pub(crate) fn emit(
let inst = Inst::xmm_unary_rm_r(op, consequent, Writable::from_reg(dst)); let inst = Inst::xmm_unary_rm_r(op, consequent, Writable::from_reg(dst));
inst.emit(&[], sink, info, state); inst.emit(&[], sink, info, state);
sink.bind_label(next); sink.bind_label(next, &mut state.ctrl_plane);
} }
Inst::Push64 { src } => { Inst::Push64 { src } => {
@@ -1395,7 +1395,7 @@ pub(crate) fn emit(
// Emit the main loop! // Emit the main loop!
let loop_start = sink.get_label(); let loop_start = sink.get_label();
sink.bind_label(loop_start); sink.bind_label(loop_start, &mut state.ctrl_plane);
// sub rsp, GUARD_SIZE // sub rsp, GUARD_SIZE
let inst = Inst::alu_rmi_r( let inst = Inst::alu_rmi_r(
@@ -1666,7 +1666,7 @@ pub(crate) fn emit(
inst.emit(&[], sink, info, state); inst.emit(&[], sink, info, state);
// Emit jump table (table of 32-bit offsets). // Emit jump table (table of 32-bit offsets).
sink.bind_label(start_of_jumptable); sink.bind_label(start_of_jumptable, &mut state.ctrl_plane);
let jt_off = sink.cur_offset(); let jt_off = sink.cur_offset();
for &target in targets.iter().chain(std::iter::once(default_target)) { for &target in targets.iter().chain(std::iter::once(default_target)) {
let word_off = sink.cur_offset(); let word_off = sink.cur_offset();
@@ -1698,7 +1698,7 @@ pub(crate) fn emit(
one_way_jmp(sink, cc1.invert(), else_label); one_way_jmp(sink, cc1.invert(), else_label);
one_way_jmp(sink, *cc2, trap_label); one_way_jmp(sink, *cc2, trap_label);
sink.bind_label(else_label); sink.bind_label(else_label, &mut state.ctrl_plane);
} }
Inst::TrapIfOr { Inst::TrapIfOr {
@@ -2750,18 +2750,18 @@ pub(crate) fn emit(
// x86's min/max are not symmetric; if either operand is a NaN, they return the // x86's min/max are not symmetric; if either operand is a NaN, they return the
// read-only operand: perform an addition between the two operands, which has the // read-only operand: perform an addition between the two operands, which has the
// desired NaN propagation effects. // desired NaN propagation effects.
sink.bind_label(propagate_nan); sink.bind_label(propagate_nan, &mut state.ctrl_plane);
let inst = Inst::xmm_rm_r(add_op, RegMem::reg(lhs), Writable::from_reg(dst)); let inst = Inst::xmm_rm_r(add_op, RegMem::reg(lhs), Writable::from_reg(dst));
inst.emit(&[], sink, info, state); inst.emit(&[], sink, info, state);
one_way_jmp(sink, CC::P, done); one_way_jmp(sink, CC::P, done);
sink.bind_label(do_min_max); sink.bind_label(do_min_max, &mut state.ctrl_plane);
let inst = Inst::xmm_rm_r(min_max_op, RegMem::reg(lhs), Writable::from_reg(dst)); let inst = Inst::xmm_rm_r(min_max_op, RegMem::reg(lhs), Writable::from_reg(dst));
inst.emit(&[], sink, info, state); inst.emit(&[], sink, info, state);
sink.bind_label(done); sink.bind_label(done, &mut state.ctrl_plane);
} }
Inst::XmmRmRImm { Inst::XmmRmRImm {
@@ -3028,7 +3028,7 @@ pub(crate) fn emit(
let inst = Inst::jmp_known(done); let inst = Inst::jmp_known(done);
inst.emit(&[], sink, info, state); inst.emit(&[], sink, info, state);
sink.bind_label(handle_negative); sink.bind_label(handle_negative, &mut state.ctrl_plane);
// Divide x by two to get it in range for the signed conversion, keep the LSB, and // Divide x by two to get it in range for the signed conversion, keep the LSB, and
// scale it back up on the FP side. // scale it back up on the FP side.
@@ -3081,7 +3081,7 @@ pub(crate) fn emit(
let inst = Inst::xmm_rm_r(add_op, RegMem::reg(dst), Writable::from_reg(dst)); let inst = Inst::xmm_rm_r(add_op, RegMem::reg(dst), Writable::from_reg(dst));
inst.emit(&[], sink, info, state); inst.emit(&[], sink, info, state);
sink.bind_label(done); sink.bind_label(done, &mut state.ctrl_plane);
} }
Inst::CvtFloatToSintSeq { Inst::CvtFloatToSintSeq {
@@ -3183,7 +3183,7 @@ pub(crate) fn emit(
let inst = Inst::jmp_known(done); let inst = Inst::jmp_known(done);
inst.emit(&[], sink, info, state); inst.emit(&[], sink, info, state);
sink.bind_label(not_nan); sink.bind_label(not_nan, &mut state.ctrl_plane);
// If the input was positive, saturate to INT_MAX. // If the input was positive, saturate to INT_MAX.
@@ -3281,7 +3281,7 @@ pub(crate) fn emit(
inst.emit(&[], sink, info, state); inst.emit(&[], sink, info, state);
} }
sink.bind_label(done); sink.bind_label(done, &mut state.ctrl_plane);
} }
Inst::CvtFloatToUintSeq { Inst::CvtFloatToUintSeq {
@@ -3391,7 +3391,7 @@ pub(crate) fn emit(
let inst = Inst::jmp_known(done); let inst = Inst::jmp_known(done);
inst.emit(&[], sink, info, state); inst.emit(&[], sink, info, state);
sink.bind_label(not_nan); sink.bind_label(not_nan, &mut state.ctrl_plane);
} else { } else {
// Trap. // Trap.
let inst = Inst::trap_if(CC::P, TrapCode::BadConversionToInteger); let inst = Inst::trap_if(CC::P, TrapCode::BadConversionToInteger);
@@ -3430,7 +3430,7 @@ pub(crate) fn emit(
// Now handle large inputs. // Now handle large inputs.
sink.bind_label(handle_large); sink.bind_label(handle_large, &mut state.ctrl_plane);
let inst = Inst::gen_move(Writable::from_reg(tmp_xmm2), src, types::F64); let inst = Inst::gen_move(Writable::from_reg(tmp_xmm2), src, types::F64);
inst.emit(&[], sink, info, state); inst.emit(&[], sink, info, state);
@@ -3463,7 +3463,7 @@ pub(crate) fn emit(
let inst = Inst::jmp_known(done); let inst = Inst::jmp_known(done);
inst.emit(&[], sink, info, state); inst.emit(&[], sink, info, state);
sink.bind_label(next_is_large); sink.bind_label(next_is_large, &mut state.ctrl_plane);
} else { } else {
let inst = Inst::trap_if(CC::L, TrapCode::IntegerOverflow); let inst = Inst::trap_if(CC::L, TrapCode::IntegerOverflow);
inst.emit(&[], sink, info, state); inst.emit(&[], sink, info, state);
@@ -3490,7 +3490,7 @@ pub(crate) fn emit(
inst.emit(&[], sink, info, state); inst.emit(&[], sink, info, state);
} }
sink.bind_label(done); sink.bind_label(done, &mut state.ctrl_plane);
} }
Inst::LoadExtName { dst, name, offset } => { Inst::LoadExtName { dst, name, offset } => {
@@ -3600,7 +3600,7 @@ pub(crate) fn emit(
i1.emit(&[], sink, info, state); i1.emit(&[], sink, info, state);
// again: // again:
sink.bind_label(again_label); sink.bind_label(again_label, &mut state.ctrl_plane);
// movq %rax, %r_temp // movq %rax, %r_temp
let i2 = Inst::mov_r_r(OperandSize::Size64, dst_old.to_reg(), temp); let i2 = Inst::mov_r_r(OperandSize::Size64, dst_old.to_reg(), temp);

View File

@@ -5098,6 +5098,7 @@ fn test_x64_emit() {
// ======================================================== // ========================================================
// Actually run the tests! // Actually run the tests!
let ctrl_plane = &mut Default::default();
let mut flag_builder = settings::builder(); let mut flag_builder = settings::builder();
flag_builder.enable("is_pic").unwrap(); flag_builder.enable("is_pic").unwrap();
let flags = settings::Flags::new(flag_builder); let flags = settings::Flags::new(flag_builder);
@@ -5126,9 +5127,9 @@ fn test_x64_emit() {
// Allow one label just after the instruction (so the offset is 0). // Allow one label just after the instruction (so the offset is 0).
let label = buffer.get_label(); let label = buffer.get_label();
buffer.bind_label(label); buffer.bind_label(label, ctrl_plane);
let buffer = buffer.finish(); let buffer = buffer.finish(ctrl_plane);
let actual_encoding = &buffer.stringify_code_bytes(); let actual_encoding = &buffer.stringify_code_bytes();
assert_eq!(expected_encoding, actual_encoding, "{}", expected_printing); assert_eq!(expected_encoding, actual_encoding, "{}", expected_printing);
} }

View File

@@ -10,6 +10,7 @@ use crate::{machinst::*, trace};
use crate::{settings, CodegenError, CodegenResult}; use crate::{settings, CodegenError, CodegenResult};
use alloc::boxed::Box; use alloc::boxed::Box;
use alloc::vec::Vec; use alloc::vec::Vec;
use cranelift_control::ControlPlane;
use regalloc2::{Allocation, PRegSet, VReg}; use regalloc2::{Allocation, PRegSet, VReg};
use smallvec::{smallvec, SmallVec}; use smallvec::{smallvec, SmallVec};
use std::fmt; use std::fmt;
@@ -2547,6 +2548,9 @@ pub struct EmitState {
stack_map: Option<StackMap>, stack_map: Option<StackMap>,
/// Current source location. /// Current source location.
cur_srcloc: RelSourceLoc, cur_srcloc: RelSourceLoc,
/// Only used during fuzz-testing. Otherwise, it is a zero-sized struct and
/// optimized away at compiletime. See [cranelift_control].
ctrl_plane: ControlPlane,
} }
/// Constant state used during emissions of a sequence of instructions. /// Constant state used during emissions of a sequence of instructions.
@@ -2583,12 +2587,13 @@ impl MachInstEmit for Inst {
} }
impl MachInstEmitState<Inst> for EmitState { impl MachInstEmitState<Inst> for EmitState {
fn new(abi: &Callee<X64ABIMachineSpec>) -> Self { fn new(abi: &Callee<X64ABIMachineSpec>, ctrl_plane: ControlPlane) -> Self {
EmitState { EmitState {
virtual_sp_offset: 0, virtual_sp_offset: 0,
nominal_sp_to_fp: abi.frame_size() as i64, nominal_sp_to_fp: abi.frame_size() as i64,
stack_map: None, stack_map: None,
cur_srcloc: Default::default(), cur_srcloc: Default::default(),
ctrl_plane,
} }
} }
@@ -2599,6 +2604,14 @@ impl MachInstEmitState<Inst> for EmitState {
fn pre_sourceloc(&mut self, srcloc: RelSourceLoc) { fn pre_sourceloc(&mut self, srcloc: RelSourceLoc) {
self.cur_srcloc = srcloc; self.cur_srcloc = srcloc;
} }
fn ctrl_plane_mut(&mut self) -> &mut ControlPlane {
&mut self.ctrl_plane
}
fn take_ctrl_plane(self) -> ControlPlane {
self.ctrl_plane
}
} }
impl EmitState { impl EmitState {

View File

@@ -118,7 +118,9 @@ mod tests {
Some(StackSlotData::new(StackSlotKind::ExplicitSlot, 64)), Some(StackSlotData::new(StackSlotKind::ExplicitSlot, 64)),
)); ));
let code = context.compile(&*isa).expect("expected compilation"); let code = context
.compile(&*isa, &mut Default::default())
.expect("expected compilation");
let fde = match code let fde = match code
.create_unwind_info(isa.as_ref()) .create_unwind_info(isa.as_ref())
@@ -157,7 +159,9 @@ mod tests {
let mut context = Context::for_function(create_multi_return_function(CallConv::SystemV)); let mut context = Context::for_function(create_multi_return_function(CallConv::SystemV));
let code = context.compile(&*isa).expect("expected compilation"); let code = context
.compile(&*isa, &mut Default::default())
.expect("expected compilation");
let fde = match code let fde = match code
.create_unwind_info(isa.as_ref()) .create_unwind_info(isa.as_ref())

View File

@@ -17,6 +17,7 @@ use crate::result::{CodegenError, CodegenResult};
use crate::settings::{self as shared_settings, Flags}; use crate::settings::{self as shared_settings, Flags};
use alloc::{boxed::Box, vec::Vec}; use alloc::{boxed::Box, vec::Vec};
use core::fmt; use core::fmt;
use cranelift_control::ControlPlane;
use regalloc2::MachineEnv; use regalloc2::MachineEnv;
use target_lexicon::Triple; use target_lexicon::Triple;
@@ -66,6 +67,7 @@ impl TargetIsa for X64Backend {
func: &Function, func: &Function,
domtree: &DominatorTree, domtree: &DominatorTree,
want_disasm: bool, want_disasm: bool,
ctrl_plane: &mut ControlPlane,
) -> CodegenResult<CompiledCodeStencil> { ) -> CodegenResult<CompiledCodeStencil> {
let (vcode, regalloc_result) = self.compile_vcode(func, domtree)?; let (vcode, regalloc_result) = self.compile_vcode(func, domtree)?;
@@ -73,10 +75,11 @@ impl TargetIsa for X64Backend {
&regalloc_result, &regalloc_result,
want_disasm, want_disasm,
self.flags.machine_code_cfg_info(), self.flags.machine_code_cfg_info(),
ctrl_plane,
); );
let frame_size = emit_result.frame_size; let frame_size = emit_result.frame_size;
let value_labels_ranges = emit_result.value_labels_ranges; let value_labels_ranges = emit_result.value_labels_ranges;
let buffer = emit_result.buffer.finish(); let buffer = emit_result.buffer.finish(ctrl_plane);
let sized_stackslot_offsets = emit_result.sized_stackslot_offsets; let sized_stackslot_offsets = emit_result.sized_stackslot_offsets;
let dynamic_stackslot_offsets = emit_result.dynamic_stackslot_offsets; let dynamic_stackslot_offsets = emit_result.dynamic_stackslot_offsets;

View File

@@ -92,8 +92,8 @@ pub use crate::machinst::buffer::{
MachCallSite, MachReloc, MachSrcLoc, MachStackMap, MachTextSectionBuilder, MachTrap, MachCallSite, MachReloc, MachSrcLoc, MachStackMap, MachTextSectionBuilder, MachTrap,
}; };
pub use crate::machinst::{ pub use crate::machinst::{
CompiledCode, Final, MachBuffer, MachBufferFinalized, MachInst, MachInstEmit, Reg, CompiledCode, Final, MachBuffer, MachBufferFinalized, MachInst, MachInstEmit,
TextSectionBuilder, Writable, MachInstEmitState, Reg, TextSectionBuilder, Writable,
}; };
mod alias_analysis; mod alias_analysis;

View File

@@ -148,6 +148,7 @@ use crate::machinst::{
}; };
use crate::timing; use crate::timing;
use crate::trace; use crate::trace;
use cranelift_control::ControlPlane;
use cranelift_entity::{entity_impl, SecondaryMap}; use cranelift_entity::{entity_impl, SecondaryMap};
use smallvec::SmallVec; use smallvec::SmallVec;
use std::convert::TryFrom; 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. /// 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!( trace!(
"MachBuffer: bind label {:?} at offset {}", "MachBuffer: bind label {:?} at offset {}",
label, label,
@@ -542,7 +543,7 @@ impl<I: VCodeInst> MachBuffer<I> {
// offset and added it to the list (which contains all labels at the // offset and added it to the list (which contains all labels at the
// current offset). // current offset).
self.optimize_branches(); self.optimize_branches(ctrl_plane);
// Post-invariant: by `optimize_branches()` (see argument there). // 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. // 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(); self.lazily_clear_labels_at_tail();
// Invariants valid at this point. // 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 /// 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 /// actually reach a deadline. It's not necessarily a problem to do so
/// otherwise but it may result in unnecessary work during emission. /// otherwise but it may result in unnecessary work during emission.
pub fn emit_island(&mut self, distance: CodeOffset) { pub fn emit_island(&mut self, distance: CodeOffset, ctrl_plane: &mut ControlPlane) {
self.emit_island_maybe_forced(false, distance); self.emit_island_maybe_forced(false, distance, ctrl_plane);
} }
/// Same as `emit_island`, but an internal API with a `force_veneers` /// Same as `emit_island`, but an internal API with a `force_veneers`
/// argument to force all veneers to always get emitted for debugging. /// 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 // We're going to purge fixups, so no latest-branch editing can happen
// anymore. // anymore.
self.latest_branches.clear(); self.latest_branches.clear();
@@ -1190,7 +1200,7 @@ impl<I: VCodeInst> MachBuffer<I> {
self.start_srcloc(loc); self.start_srcloc(loc);
} }
self.align_to(I::LabelUse::ALIGN); self.align_to(I::LabelUse::ALIGN);
self.bind_label(label); self.bind_label(label, ctrl_plane);
self.add_trap(code); self.add_trap(code);
if let Some(map) = stack_map { if let Some(map) = stack_map {
let extent = StackMapExtent::UpcomingBytes(I::TRAP_OPCODE.len() as u32); 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) { for MachLabelConstant { label, align, data } in mem::take(&mut self.pending_constants) {
self.align_to(align); self.align_to(align);
self.bind_label(label); self.bind_label(label, ctrl_plane);
self.put_data(&data[..]); 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); 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() while !self.pending_constants.is_empty()
|| !self.pending_traps.is_empty() || !self.pending_traps.is_empty()
|| !self.fixup_records.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 // `emit_island()` will emit any pending veneers and constants, and
// as a side-effect, will also take care of any fixups with resolved // as a side-effect, will also take care of any fixups with resolved
// labels eagerly. // 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 // 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. /// 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(); let _tt = timing::vcode_emit_finish();
// Do any optimizations on branches at tail of buffer, as if we // Do any optimizations on branches at tail of buffer, as if we
// had bound one last label. // 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; let mut srclocs = self.srclocs;
srclocs.sort_by_key(|entry| entry.start); srclocs.sort_by_key(|entry| entry.start);
@@ -1713,19 +1727,28 @@ impl<I: VCodeInst> MachTextSectionBuilder<I> {
} }
impl<I: VCodeInst> TextSectionBuilder for 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 // Conditionally emit an island if it's necessary to resolve jumps
// between functions which are too far away. // between functions which are too far away.
let size = func.len() as u32; let size = func.len() as u32;
if self.force_veneers || self.buf.island_needed(size) { 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); self.buf.align_to(align);
let pos = self.buf.cur_offset(); let pos = self.buf.cur_offset();
if labeled { if labeled {
self.buf self.buf.bind_label(
.bind_label(MachLabel::from_block(BlockIndex::new(self.next_func))); MachLabel::from_block(BlockIndex::new(self.next_func)),
ctrl_plane,
);
self.next_func += 1; self.next_func += 1;
} }
self.buf.put_data(func); self.buf.put_data(func);
@@ -1748,13 +1771,13 @@ impl<I: VCodeInst> TextSectionBuilder for MachTextSectionBuilder<I> {
self.force_veneers = true; 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. // Double-check all functions were pushed.
assert_eq!(self.next_func, self.buf.label_offsets.len()); assert_eq!(self.next_func, self.buf.label_offsets.len());
// Finish up any veneers, if necessary. // Finish up any veneers, if necessary.
self.buf 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. // We don't need the data any more, so return it to the caller.
mem::take(&mut self.buf.data).into_vec() mem::take(&mut self.buf.data).into_vec()
@@ -1770,7 +1793,7 @@ mod test {
use crate::ir::UserExternalNameRef; use crate::ir::UserExternalNameRef;
use crate::isa::aarch64::inst::xreg; use crate::isa::aarch64::inst::xreg;
use crate::isa::aarch64::inst::{BranchTarget, CondBrKind, EmitInfo, Inst}; use crate::isa::aarch64::inst::{BranchTarget, CondBrKind, EmitInfo, Inst};
use crate::machinst::MachInstEmit; use crate::machinst::{MachInstEmit, MachInstEmitState};
use crate::settings; use crate::settings;
use std::default::Default; use std::default::Default;
use std::vec::Vec; use std::vec::Vec;
@@ -1786,14 +1809,14 @@ mod test {
fn test_elide_jump_to_next() { fn test_elide_jump_to_next() {
let info = EmitInfo::new(settings::Flags::new(settings::builder())); let info = EmitInfo::new(settings::Flags::new(settings::builder()));
let mut buf = MachBuffer::new(); 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.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) }; let inst = Inst::Jump { dest: target(1) };
inst.emit(&[], &mut buf, &info, &mut state); inst.emit(&[], &mut buf, &info, &mut state);
buf.bind_label(label(1)); buf.bind_label(label(1), state.ctrl_plane_mut());
let buf = buf.finish(); let buf = buf.finish(state.ctrl_plane_mut());
assert_eq!(0, buf.total_size()); assert_eq!(0, buf.total_size());
} }
@@ -1801,11 +1824,11 @@ mod test {
fn test_elide_trivial_jump_blocks() { fn test_elide_trivial_jump_blocks() {
let info = EmitInfo::new(settings::Flags::new(settings::builder())); let info = EmitInfo::new(settings::Flags::new(settings::builder()));
let mut buf = MachBuffer::new(); 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.reserve_labels_for_blocks(4);
buf.bind_label(label(0)); buf.bind_label(label(0), state.ctrl_plane_mut());
let inst = Inst::CondBr { let inst = Inst::CondBr {
kind: CondBrKind::NotZero(xreg(0)), kind: CondBrKind::NotZero(xreg(0)),
taken: target(1), taken: target(1),
@@ -1813,17 +1836,17 @@ mod test {
}; };
inst.emit(&[], &mut buf, &info, &mut state); 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) }; let inst = Inst::Jump { dest: target(3) };
inst.emit(&[], &mut buf, &info, &mut state); 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) }; let inst = Inst::Jump { dest: target(3) };
inst.emit(&[], &mut buf, &info, &mut state); 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()); assert_eq!(0, buf.total_size());
} }
@@ -1831,11 +1854,11 @@ mod test {
fn test_flip_cond() { fn test_flip_cond() {
let info = EmitInfo::new(settings::Flags::new(settings::builder())); let info = EmitInfo::new(settings::Flags::new(settings::builder()));
let mut buf = MachBuffer::new(); 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.reserve_labels_for_blocks(4);
buf.bind_label(label(0)); buf.bind_label(label(0), state.ctrl_plane_mut());
let inst = Inst::CondBr { let inst = Inst::CondBr {
kind: CondBrKind::Zero(xreg(0)), kind: CondBrKind::Zero(xreg(0)),
taken: target(1), taken: target(1),
@@ -1843,19 +1866,19 @@ mod test {
}; };
inst.emit(&[], &mut buf, &info, &mut state); 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; let inst = Inst::Nop4;
inst.emit(&[], &mut buf, &info, &mut state); 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 { let inst = Inst::Udf {
trap_code: TrapCode::Interrupt, trap_code: TrapCode::Interrupt,
}; };
inst.emit(&[], &mut buf, &info, &mut state); 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 buf2 = MachBuffer::new();
let mut state = Default::default(); let mut state = Default::default();
@@ -1867,7 +1890,7 @@ mod test {
let inst = Inst::Nop4; let inst = Inst::Nop4;
inst.emit(&[], &mut buf2, &info, &mut state); 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); assert_eq!(buf.data, buf2.data);
} }
@@ -1876,11 +1899,11 @@ mod test {
fn test_island() { fn test_island() {
let info = EmitInfo::new(settings::Flags::new(settings::builder())); let info = EmitInfo::new(settings::Flags::new(settings::builder()));
let mut buf = MachBuffer::new(); 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.reserve_labels_for_blocks(4);
buf.bind_label(label(0)); buf.bind_label(label(0), state.ctrl_plane_mut());
let inst = Inst::CondBr { let inst = Inst::CondBr {
kind: CondBrKind::NotZero(xreg(0)), kind: CondBrKind::NotZero(xreg(0)),
taken: target(2), taken: target(2),
@@ -1888,24 +1911,24 @@ mod test {
}; };
inst.emit(&[], &mut buf, &info, &mut state); 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 { while buf.cur_offset() < 2000000 {
if buf.island_needed(0) { if buf.island_needed(0) {
buf.emit_island(0); buf.emit_island(0, state.ctrl_plane_mut());
} }
let inst = Inst::Nop4; let inst = Inst::Nop4;
inst.emit(&[], &mut buf, &info, &mut state); 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; let inst = Inst::Nop4;
inst.emit(&[], &mut buf, &info, &mut state); 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; let inst = Inst::Nop4;
inst.emit(&[], &mut buf, &info, &mut state); 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()); assert_eq!(2000000 + 8, buf.total_size());
@@ -1934,7 +1957,7 @@ mod test {
}; };
inst.emit(&[], &mut buf2, &info, &mut state); 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[..]); assert_eq!(&buf.data[0..8], &buf2.data[..]);
} }
@@ -1943,25 +1966,25 @@ mod test {
fn test_island_backward() { fn test_island_backward() {
let info = EmitInfo::new(settings::Flags::new(settings::builder())); let info = EmitInfo::new(settings::Flags::new(settings::builder()));
let mut buf = MachBuffer::new(); 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.reserve_labels_for_blocks(4);
buf.bind_label(label(0)); buf.bind_label(label(0), state.ctrl_plane_mut());
let inst = Inst::Nop4; let inst = Inst::Nop4;
inst.emit(&[], &mut buf, &info, &mut state); 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; let inst = Inst::Nop4;
inst.emit(&[], &mut buf, &info, &mut state); 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 { while buf.cur_offset() < 2000000 {
let inst = Inst::Nop4; let inst = Inst::Nop4;
inst.emit(&[], &mut buf, &info, &mut state); 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 { let inst = Inst::CondBr {
kind: CondBrKind::NotZero(xreg(0)), kind: CondBrKind::NotZero(xreg(0)),
taken: target(0), taken: target(0),
@@ -1969,7 +1992,7 @@ mod test {
}; };
inst.emit(&[], &mut buf, &info, &mut state); 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()); assert_eq!(2000000 + 12, buf.total_size());
@@ -1986,7 +2009,7 @@ mod test {
}; };
inst.emit(&[], &mut buf2, &info, &mut state); 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[..]); assert_eq!(&buf.data[2000000..], &buf2.data[..]);
} }
@@ -2028,11 +2051,11 @@ mod test {
let info = EmitInfo::new(settings::Flags::new(settings::builder())); let info = EmitInfo::new(settings::Flags::new(settings::builder()));
let mut buf = MachBuffer::new(); 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.reserve_labels_for_blocks(8);
buf.bind_label(label(0)); buf.bind_label(label(0), state.ctrl_plane_mut());
let inst = Inst::CondBr { let inst = Inst::CondBr {
kind: CondBrKind::Zero(xreg(0)), kind: CondBrKind::Zero(xreg(0)),
taken: target(1), taken: target(1),
@@ -2040,38 +2063,38 @@ mod test {
}; };
inst.emit(&[], &mut buf, &info, &mut state); 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) }; let inst = Inst::Jump { dest: target(3) };
inst.emit(&[], &mut buf, &info, &mut state); 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; let inst = Inst::Nop4;
inst.emit(&[], &mut buf, &info, &mut state); inst.emit(&[], &mut buf, &info, &mut state);
inst.emit(&[], &mut buf, &info, &mut state); inst.emit(&[], &mut buf, &info, &mut state);
let inst = Inst::Jump { dest: target(0) }; let inst = Inst::Jump { dest: target(0) };
inst.emit(&[], &mut buf, &info, &mut state); 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) }; let inst = Inst::Jump { dest: target(4) };
inst.emit(&[], &mut buf, &info, &mut state); 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) }; let inst = Inst::Jump { dest: target(5) };
inst.emit(&[], &mut buf, &info, &mut state); 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) }; let inst = Inst::Jump { dest: target(7) };
inst.emit(&[], &mut buf, &info, &mut state); 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; let inst = Inst::Nop4;
inst.emit(&[], &mut buf, &info, &mut state); 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![] }; let inst = Inst::Ret { rets: vec![] };
inst.emit(&[], &mut buf, &info, &mut state); inst.emit(&[], &mut buf, &info, &mut state);
let buf = buf.finish(); let buf = buf.finish(state.ctrl_plane_mut());
let golden_data = vec![ let golden_data = vec![
0xa0, 0x00, 0x00, 0xb4, // cbz x0, 0x14 0xa0, 0x00, 0x00, 0xb4, // cbz x0, 0x14
@@ -2104,31 +2127,31 @@ mod test {
// b label0 // b label0
let info = EmitInfo::new(settings::Flags::new(settings::builder())); let info = EmitInfo::new(settings::Flags::new(settings::builder()));
let mut buf = MachBuffer::new(); 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.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) }; let inst = Inst::Jump { dest: target(1) };
inst.emit(&[], &mut buf, &info, &mut state); 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) }; let inst = Inst::Jump { dest: target(2) };
inst.emit(&[], &mut buf, &info, &mut state); 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) }; let inst = Inst::Jump { dest: target(3) };
inst.emit(&[], &mut buf, &info, &mut state); 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) }; let inst = Inst::Jump { dest: target(4) };
inst.emit(&[], &mut buf, &info, &mut state); 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) }; let inst = Inst::Jump { dest: target(1) };
inst.emit(&[], &mut buf, &info, &mut state); inst.emit(&[], &mut buf, &info, &mut state);
let buf = buf.finish(); let buf = buf.finish(state.ctrl_plane_mut());
let golden_data = vec![ let golden_data = vec![
0x00, 0x00, 0x00, 0x14, // b 0 0x00, 0x00, 0x00, 0x14, // b 0
@@ -2140,10 +2163,11 @@ mod test {
#[test] #[test]
fn metadata_records() { fn metadata_records() {
let mut buf = MachBuffer::<Inst>::new(); let mut buf = MachBuffer::<Inst>::new();
let ctrl_plane = &mut Default::default();
buf.reserve_labels_for_blocks(1); buf.reserve_labels_for_blocks(1);
buf.bind_label(label(0)); buf.bind_label(label(0), ctrl_plane);
buf.put1(1); buf.put1(1);
buf.add_trap(TrapCode::HeapOutOfBounds); buf.add_trap(TrapCode::HeapOutOfBounds);
buf.put1(2); buf.put1(2);
@@ -2163,7 +2187,7 @@ mod test {
); );
buf.put1(4); buf.put1(4);
let buf = buf.finish(); let buf = buf.finish(ctrl_plane);
assert_eq!(buf.data(), &[1, 2, 3, 4]); assert_eq!(buf.data(), &[1, 2, 3, 4]);
assert_eq!( assert_eq!(

View File

@@ -52,6 +52,7 @@ use crate::settings::Flags;
use crate::value_label::ValueLabelsRanges; use crate::value_label::ValueLabelsRanges;
use alloc::vec::Vec; use alloc::vec::Vec;
use core::fmt::Debug; use core::fmt::Debug;
use cranelift_control::ControlPlane;
use cranelift_entity::PrimaryMap; use cranelift_entity::PrimaryMap;
use regalloc2::{Allocation, VReg}; use regalloc2::{Allocation, VReg};
use smallvec::{smallvec, SmallVec}; use smallvec::{smallvec, SmallVec};
@@ -272,13 +273,21 @@ pub trait MachInstEmit: MachInst {
/// emitting a function body. /// emitting a function body.
pub trait MachInstEmitState<I: VCodeInst>: Default + Clone + Debug { pub trait MachInstEmitState<I: VCodeInst>: Default + Clone + Debug {
/// Create a new emission state given the ABI object. /// 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 /// Update the emission state before emitting an instruction that is a
/// safepoint. /// safepoint.
fn pre_safepoint(&mut self, _stack_map: StackMap) {} fn pre_safepoint(&mut self, _stack_map: StackMap) {}
/// Update the emission state to indicate instructions are associated with a /// Update the emission state to indicate instructions are associated with a
/// particular RelSourceLoc. /// particular RelSourceLoc.
fn pre_sourceloc(&mut self, _srcloc: 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 /// 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 /// This function returns the offset at which the data was placed in the
/// text section. /// 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. /// 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 /// Completes this text section, filling out any final details, and returns
/// the bytes of the text section. /// 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. /// Expected unwind info type.

View File

@@ -26,6 +26,7 @@ use crate::timing;
use crate::trace; use crate::trace;
use crate::CodegenError; use crate::CodegenError;
use crate::ValueLocRange; use crate::ValueLocRange;
use cranelift_control::ControlPlane;
use regalloc2::{ use regalloc2::{
Edit, Function as RegallocFunction, InstOrEdit, InstRange, Operand, OperandKind, PRegSet, Edit, Function as RegallocFunction, InstOrEdit, InstRange, Operand, OperandKind, PRegSet,
RegClass, VReg, RegClass, VReg,
@@ -763,6 +764,7 @@ impl<I: VCodeInst> VCode<I> {
regalloc: &regalloc2::Output, regalloc: &regalloc2::Output,
want_disasm: bool, want_disasm: bool,
want_metadata: bool, want_metadata: bool,
ctrl_plane: &mut ControlPlane,
) -> EmitResult<I> ) -> EmitResult<I>
where where
I: VCodeInst, I: VCodeInst,
@@ -813,7 +815,7 @@ impl<I: VCodeInst> VCode<I> {
let mut cur_srcloc = None; let mut cur_srcloc = None;
let mut last_offset = None; let mut last_offset = None;
let mut inst_offsets = vec![]; 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(); let mut disasm = String::new();
@@ -874,7 +876,7 @@ impl<I: VCodeInst> VCode<I> {
// Now emit the regular block body. // 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 { if want_disasm {
writeln!(&mut disasm, "block{}:", block.index()).unwrap(); writeln!(&mut disasm, "block{}:", block.index()).unwrap();
@@ -1054,11 +1056,14 @@ impl<I: VCodeInst> VCode<I> {
let worst_case_next_bb = let worst_case_next_bb =
I::worst_case_size() * (next_block_size + next_block_ra_insertions); I::worst_case_size() * (next_block_size + next_block_ra_insertions);
if buffer.island_needed(worst_case_next_bb) { 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. // Emit the constants used by the function.
let mut alignment = 1; let mut alignment = 1;
for (constant, data) in self.constants.iter() { for (constant, data) in self.constants.iter() {

View File

@@ -0,0 +1,20 @@
[package]
authors = ["The Cranelift Project Developers"]
name = "cranelift-control"
version = "0.96.0"
description = "White-box fuzz testing framework"
license = "Apache-2.0 WITH LLVM-exception"
repository = "https://github.com/bytecodealliance/wasmtime"
readme = "README.md"
keywords = ["fuzz", "test"]
edition.workspace = true
[dependencies]
arbitrary = { version = "1.1.0" }
[features]
# Turn on chaos mode.
# Without this feature, a zero-sized dummy will be compiled
# for the control plane.
chaos = []

220
cranelift/control/LICENSE Normal file
View File

@@ -0,0 +1,220 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
--- LLVM Exceptions to the Apache 2.0 License ----
As an exception, if, as a result of your compiling your source code, portions
of this Software are embedded into an Object form of such source code, you
may redistribute such embedded portions in such Object form without complying
with the conditions of Sections 4(a), 4(b) and 4(d) of the License.
In addition, if you combine or link compiled forms of this Software with
software that is licensed under the GPLv2 ("Combined Software") and if a
court of competent jurisdiction determines that the patent provision (Section
3), the indemnity provision (Section 9) or other Section of the License
conflicts with the conditions of the GPLv2, you may retroactively and
prospectively choose to deem waived or otherwise exclude such Section(s) of
the License, but only in their entirety and only with respect to the Combined
Software.

View File

@@ -0,0 +1,4 @@
This crate contains the control plane for "chaos mode". It can be used to
inject pseudo-random perturbations into specific sections in the code while
fuzzing. Its compilation is feature-gated to prevent any performance
impact on release builds.

View File

@@ -0,0 +1,28 @@
use arbitrary::Arbitrary;
/// The control plane of chaos mode.
/// Please see the [crate-level documentation](crate).
#[derive(Debug, Clone, Default)]
pub struct ControlPlane {
data: Vec<bool>,
}
impl Arbitrary<'_> for ControlPlane {
fn arbitrary<'a>(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
Ok(Self {
data: u.arbitrary()?,
})
}
}
impl ControlPlane {
/// Returns a pseudo-random boolean if the control plane was constructed
/// with `arbitrary`.
///
/// The default value `false` will always be returned if the
/// pseudo-random data is exhausted or the control plane was constructed
/// with `default`.
pub fn get_decision(&mut self) -> bool {
self.data.pop().unwrap_or_default()
}
}

View File

@@ -0,0 +1,30 @@
//! # Cranelift Control
//!
//! This is the home of the control plane of chaos mode, a compilation feature
//! intended to be turned on for certain fuzz targets. When the feature is
//! turned off, as is normally the case, [ControlPlane] will be a zero-sized
//! type and optimized away.
//!
//! While the feature is turned on, the struct [ControlPlane]
//! provides functionality to tap into pseudo-randomness at specific locations
//! in the code. It may be used for targeted fuzzing of compiler internals,
//! e.g. manipulate heuristic optimizations, clobber undefined register bits
//! etc.
//!
//! There are two ways to acquire a [ControlPlane]:
//! - [arbitrary] for the real deal
//! - [default] for an "empty" control plane which always returns default
//! values
//!
//! [arbitrary]: ControlPlane#method.arbitrary
//! [default]: ControlPlane#method.default
#[cfg(not(feature = "chaos"))]
mod zero_sized;
#[cfg(not(feature = "chaos"))]
pub use zero_sized::*;
#[cfg(feature = "chaos")]
mod chaos;
#[cfg(feature = "chaos")]
pub use chaos::*;

View File

@@ -0,0 +1,28 @@
//! Shims for ControlPlane when chaos mode is disabled. Enables
//! unconditional use of the type and its methods throughout cranelift.
/// A shim for ControlPlane when chaos mode is disabled.
/// Please see the [crate-level documentation](crate).
#[derive(Debug, Clone, Default)]
pub struct ControlPlane {
/// prevent direct instantiation (use `default` instead)
_private: (),
}
/// A shim for ControlPlane's `Arbitrary` implementation when chaos mode is
/// disabled. It doesn't consume any bytes and always returns a default
/// control plane.
impl arbitrary::Arbitrary<'_> for ControlPlane {
fn arbitrary<'a>(_u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
Ok(Self::default())
}
}
impl ControlPlane {
/// Returns a pseudo-random boolean. This variant is used when chaos
/// mode is disabled. It always returns `false`.
#[inline]
pub fn get_decision(&mut self) -> bool {
false
}
}

View File

@@ -17,6 +17,7 @@ cranelift-native = { workspace = true }
cranelift-reader = { workspace = true } cranelift-reader = { workspace = true }
cranelift-jit = { workspace = true, features = ["selinux-fix"] } cranelift-jit = { workspace = true, features = ["selinux-fix"] }
cranelift-module = { workspace = true } cranelift-module = { workspace = true }
cranelift-control = { workspace = true }
file-per-thread-logger = "0.1.2" file-per-thread-logger = "0.1.2"
filecheck = "0.5.0" filecheck = "0.5.0"
gimli = { workspace = true } gimli = { workspace = true }

View File

@@ -7,6 +7,7 @@ use cranelift_codegen::ir::{
}; };
use cranelift_codegen::isa::{OwnedTargetIsa, TargetIsa}; use cranelift_codegen::isa::{OwnedTargetIsa, TargetIsa};
use cranelift_codegen::{ir, settings, CodegenError, Context}; use cranelift_codegen::{ir, settings, CodegenError, Context};
use cranelift_control::ControlPlane;
use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext}; use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext};
use cranelift_jit::{JITBuilder, JITModule}; use cranelift_jit::{JITBuilder, JITModule};
use cranelift_module::{FuncId, Linkage, Module, ModuleError}; use cranelift_module::{FuncId, Linkage, Module, ModuleError};
@@ -49,6 +50,7 @@ struct DefinedFunction {
/// "outside-of-function" functionality, see `cranelift_jit::backend::JITBackend`. /// "outside-of-function" functionality, see `cranelift_jit::backend::JITBackend`.
/// ///
/// ``` /// ```
/// # let ctrl_plane = &mut Default::default();
/// use cranelift_filetests::TestFileCompiler; /// use cranelift_filetests::TestFileCompiler;
/// use cranelift_reader::parse_functions; /// use cranelift_reader::parse_functions;
/// use cranelift_codegen::data_value::DataValue; /// use cranelift_codegen::data_value::DataValue;
@@ -57,8 +59,8 @@ struct DefinedFunction {
/// let func = parse_functions(code).unwrap().into_iter().nth(0).unwrap(); /// let func = parse_functions(code).unwrap().into_iter().nth(0).unwrap();
/// let mut compiler = TestFileCompiler::with_default_host_isa().unwrap(); /// let mut compiler = TestFileCompiler::with_default_host_isa().unwrap();
/// compiler.declare_function(&func).unwrap(); /// compiler.declare_function(&func).unwrap();
/// compiler.define_function(func.clone()).unwrap(); /// compiler.define_function(func.clone(), ctrl_plane).unwrap();
/// compiler.create_trampoline_for_function(&func).unwrap(); /// compiler.create_trampoline_for_function(&func, ctrl_plane).unwrap();
/// let compiled = compiler.compile().unwrap(); /// let compiled = compiler.compile().unwrap();
/// let trampoline = compiled.get_trampoline(&func).unwrap(); /// let trampoline = compiled.get_trampoline(&func).unwrap();
/// ///
@@ -116,16 +118,24 @@ impl TestFileCompiler {
/// Declares and compiles all functions in `functions`. Additionally creates a trampoline for /// Declares and compiles all functions in `functions`. Additionally creates a trampoline for
/// each one of them. /// each one of them.
pub fn add_functions(&mut self, functions: &[Function]) -> Result<()> { pub fn add_functions(
&mut self,
functions: &[Function],
ctrl_planes: Vec<ControlPlane>,
) -> Result<()> {
// Declare all functions in the file, so that they may refer to each other. // Declare all functions in the file, so that they may refer to each other.
for func in functions { for func in functions {
self.declare_function(func)?; self.declare_function(func)?;
} }
let ctrl_planes = ctrl_planes
.into_iter()
.chain(std::iter::repeat(ControlPlane::default()));
// Define all functions and trampolines // Define all functions and trampolines
for func in functions { for (func, ref mut ctrl_plane) in functions.iter().zip(ctrl_planes) {
self.define_function(func.clone())?; self.define_function(func.clone(), ctrl_plane)?;
self.create_trampoline_for_function(func)?; self.create_trampoline_for_function(func, ctrl_plane)?;
} }
Ok(()) Ok(())
@@ -141,7 +151,7 @@ impl TestFileCompiler {
.cloned() .cloned()
.collect::<Vec<_>>(); .collect::<Vec<_>>();
self.add_functions(&functions[..])?; self.add_functions(&functions[..], Vec::new())?;
Ok(()) Ok(())
} }
@@ -217,7 +227,7 @@ impl TestFileCompiler {
} }
/// Defines the body of a function /// Defines the body of a function
pub fn define_function(&mut self, func: Function) -> Result<()> { pub fn define_function(&mut self, func: Function, ctrl_plane: &mut ControlPlane) -> Result<()> {
let defined_func = self let defined_func = self
.defined_functions .defined_functions
.get(&func.name) .get(&func.name)
@@ -225,13 +235,17 @@ impl TestFileCompiler {
self.ctx.func = self.apply_func_rename(func, defined_func)?; self.ctx.func = self.apply_func_rename(func, defined_func)?;
self.module self.module
.define_function(defined_func.func_id, &mut self.ctx)?; .define_function(defined_func.func_id, &mut self.ctx, ctrl_plane)?;
self.module.clear_context(&mut self.ctx); self.module.clear_context(&mut self.ctx);
Ok(()) Ok(())
} }
/// Creates and registers a trampoline for a function if none exists. /// Creates and registers a trampoline for a function if none exists.
pub fn create_trampoline_for_function(&mut self, func: &Function) -> Result<()> { pub fn create_trampoline_for_function(
&mut self,
func: &Function,
ctrl_plane: &mut ControlPlane,
) -> Result<()> {
if !self.defined_functions.contains_key(&func.name) { if !self.defined_functions.contains_key(&func.name) {
anyhow::bail!("Undeclared function {} found!", &func.name); anyhow::bail!("Undeclared function {} found!", &func.name);
} }
@@ -246,7 +260,7 @@ impl TestFileCompiler {
let trampoline = make_trampoline(name.clone(), &func.signature, self.module.isa()); let trampoline = make_trampoline(name.clone(), &func.signature, self.module.isa());
self.declare_function(&trampoline)?; self.declare_function(&trampoline)?;
self.define_function(trampoline)?; self.define_function(trampoline, ctrl_plane)?;
self.trampolines.insert(func.signature.clone(), name); self.trampolines.insert(func.signature.clone(), name);
@@ -504,6 +518,7 @@ mod test {
return v1 return v1
}", }",
); );
let ctrl_plane = &mut ControlPlane::default();
// extract function // extract function
let test_file = parse_test(code.as_str(), ParseOptions::default()).unwrap(); let test_file = parse_test(code.as_str(), ParseOptions::default()).unwrap();
@@ -513,8 +528,12 @@ mod test {
// execute function // execute function
let mut compiler = TestFileCompiler::with_default_host_isa().unwrap(); let mut compiler = TestFileCompiler::with_default_host_isa().unwrap();
compiler.declare_function(&function).unwrap(); compiler.declare_function(&function).unwrap();
compiler.define_function(function.clone()).unwrap(); compiler
compiler.create_trampoline_for_function(&function).unwrap(); .define_function(function.clone(), ctrl_plane)
.unwrap();
compiler
.create_trampoline_for_function(&function, ctrl_plane)
.unwrap();
let compiled = compiler.compile().unwrap(); let compiled = compiler.compile().unwrap();
let trampoline = compiled.get_trampoline(&function).unwrap(); let trampoline = compiled.get_trampoline(&function).unwrap();
let returned = trampoline.call(&[]); let returned = trampoline.call(&[]);

View File

@@ -53,7 +53,7 @@ impl SubTest for TestCompile {
comp_ctx.set_disasm(true); comp_ctx.set_disasm(true);
let compiled_code = comp_ctx let compiled_code = comp_ctx
.compile(isa) .compile(isa, &mut Default::default())
.map_err(|e| crate::pretty_anyhow_error(&e.func, e.inner))?; .map_err(|e| crate::pretty_anyhow_error(&e.func, e.inner))?;
let total_size = compiled_code.code_info().total_size; let total_size = compiled_code.code_info().total_size;

View File

@@ -39,7 +39,9 @@ impl SubTest for TestUnwind {
let isa = context.isa.expect("unwind needs an ISA"); let isa = context.isa.expect("unwind needs an ISA");
let mut comp_ctx = cranelift_codegen::Context::for_function(func.into_owned()); let mut comp_ctx = cranelift_codegen::Context::for_function(func.into_owned());
let code = comp_ctx.compile(isa).expect("failed to compile function"); let code = comp_ctx
.compile(isa, &mut Default::default())
.expect("failed to compile function");
let mut text = String::new(); let mut text = String::new();
match code.create_unwind_info(isa).expect("unwind info") { match code.create_unwind_info(isa).expect("unwind info") {

View File

@@ -58,7 +58,7 @@ pub fn run(path: &Path, wat: &str) -> Result<()> {
let mut ctx = cranelift_codegen::Context::for_function(func.clone()); let mut ctx = cranelift_codegen::Context::for_function(func.clone());
ctx.set_disasm(true); ctx.set_disasm(true);
let code = ctx let code = ctx
.compile(isa) .compile(isa, &mut Default::default())
.map_err(|e| crate::pretty_anyhow_error(&e.func, e.inner))?; .map_err(|e| crate::pretty_anyhow_error(&e.func, e.inner))?;
writeln!(&mut actual, "function {}:", func.name).unwrap(); writeln!(&mut actual, "function {}:", func.name).unwrap();
writeln!(&mut actual, "{}", code.vcode.as_ref().unwrap()).unwrap(); writeln!(&mut actual, "{}", code.vcode.as_ref().unwrap()).unwrap();

View File

@@ -14,6 +14,7 @@ cranelift-module = { workspace = true }
cranelift-native = { workspace = true } cranelift-native = { workspace = true }
cranelift-codegen = { workspace = true, features = ["std"] } cranelift-codegen = { workspace = true, features = ["std"] }
cranelift-entity = { workspace = true } cranelift-entity = { workspace = true }
cranelift-control = { workspace = true }
anyhow = { workspace = true } anyhow = { workspace = true }
region = "2.2.0" region = "2.2.0"
libc = { version = "0.2.42" } libc = { version = "0.2.42" }

View File

@@ -51,7 +51,10 @@ fn main() {
bcx.seal_all_blocks(); bcx.seal_all_blocks();
bcx.finalize(); bcx.finalize();
} }
module.define_function(func_a, &mut ctx).unwrap(); let ctrl_plane = &mut Default::default();
module
.define_function(func_a, &mut ctx, ctrl_plane)
.unwrap();
module.clear_context(&mut ctx); module.clear_context(&mut ctx);
ctx.func.signature = sig_b; ctx.func.signature = sig_b;
@@ -74,7 +77,9 @@ fn main() {
bcx.seal_all_blocks(); bcx.seal_all_blocks();
bcx.finalize(); bcx.finalize();
} }
module.define_function(func_b, &mut ctx).unwrap(); module
.define_function(func_b, &mut ctx, ctrl_plane)
.unwrap();
module.clear_context(&mut ctx); module.clear_context(&mut ctx);
// Perform linking. // Perform linking.

View File

@@ -5,6 +5,7 @@ use cranelift_codegen::isa::{OwnedTargetIsa, TargetIsa};
use cranelift_codegen::settings::Configurable; use cranelift_codegen::settings::Configurable;
use cranelift_codegen::{self, ir, settings, MachReloc}; use cranelift_codegen::{self, ir, settings, MachReloc};
use cranelift_codegen::{binemit::Reloc, CodegenError}; use cranelift_codegen::{binemit::Reloc, CodegenError};
use cranelift_control::ControlPlane;
use cranelift_entity::SecondaryMap; use cranelift_entity::SecondaryMap;
use cranelift_module::{ use cranelift_module::{
DataContext, DataDescription, DataId, FuncId, Init, Linkage, Module, ModuleCompiledFunction, DataContext, DataDescription, DataId, FuncId, Init, Linkage, Module, ModuleCompiledFunction,
@@ -682,6 +683,7 @@ impl Module for JITModule {
&mut self, &mut self,
id: FuncId, id: FuncId,
ctx: &mut cranelift_codegen::Context, ctx: &mut cranelift_codegen::Context,
ctrl_plane: &mut ControlPlane,
) -> ModuleResult<ModuleCompiledFunction> { ) -> ModuleResult<ModuleCompiledFunction> {
info!("defining function {}: {}", id, ctx.func.display()); info!("defining function {}: {}", id, ctx.func.display());
let decl = self.declarations.get_function_decl(id); let decl = self.declarations.get_function_decl(id);
@@ -694,7 +696,7 @@ impl Module for JITModule {
} }
// work around borrow-checker to allow reuse of ctx below // work around borrow-checker to allow reuse of ctx below
let res = ctx.compile(self.isa())?; let res = ctx.compile(self.isa(), ctrl_plane)?;
let alignment = res.alignment as u64; let alignment = res.alignment as u64;
let compiled_code = ctx.compiled_code().unwrap(); let compiled_code = ctx.compiled_code().unwrap();

View File

@@ -57,7 +57,9 @@ fn define_simple_function(module: &mut JITModule) -> FuncId {
bcx.ins().return_(&[]); bcx.ins().return_(&[]);
} }
module.define_function(func_id, &mut ctx).unwrap(); module
.define_function(func_id, &mut ctx, &mut Default::default())
.unwrap();
func_id func_id
} }
@@ -207,7 +209,9 @@ fn libcall_function() {
bcx.ins().return_(&[]); bcx.ins().return_(&[]);
} }
module.define_function(func_id, &mut ctx).unwrap(); module
.define_function(func_id, &mut ctx, &mut Default::default())
.unwrap();
module.finalize_definitions().unwrap(); module.finalize_definitions().unwrap();
} }

View File

@@ -12,6 +12,7 @@ edition.workspace = true
[dependencies] [dependencies]
cranelift-codegen = { workspace = true } cranelift-codegen = { workspace = true }
cranelift-control = { workspace = true }
hashbrown = { workspace = true, optional = true } hashbrown = { workspace = true, optional = true }
anyhow = { workspace = true } anyhow = { workspace = true }

View File

@@ -14,6 +14,7 @@ use cranelift_codegen::ir::Function;
use cranelift_codegen::settings::SetError; use cranelift_codegen::settings::SetError;
use cranelift_codegen::{binemit, MachReloc}; use cranelift_codegen::{binemit, MachReloc};
use cranelift_codegen::{ir, isa, CodegenError, CompileError, Context}; use cranelift_codegen::{ir, isa, CodegenError, CompileError, Context};
use cranelift_control::ControlPlane;
use std::borrow::ToOwned; use std::borrow::ToOwned;
use std::string::String; use std::string::String;
@@ -658,6 +659,7 @@ pub trait Module {
&mut self, &mut self,
func: FuncId, func: FuncId,
ctx: &mut Context, ctx: &mut Context,
ctrl_plane: &mut ControlPlane,
) -> ModuleResult<ModuleCompiledFunction>; ) -> ModuleResult<ModuleCompiledFunction>;
/// Define a function, taking the function body from the given `bytes`. /// Define a function, taking the function body from the given `bytes`.
@@ -760,8 +762,9 @@ impl<M: Module> Module for &mut M {
&mut self, &mut self,
func: FuncId, func: FuncId,
ctx: &mut Context, ctx: &mut Context,
ctrl_plane: &mut ControlPlane,
) -> ModuleResult<ModuleCompiledFunction> { ) -> ModuleResult<ModuleCompiledFunction> {
(**self).define_function(func, ctx) (**self).define_function(func, ctx, ctrl_plane)
} }
fn define_function_bytes( fn define_function_bytes(

View File

@@ -12,6 +12,7 @@ edition.workspace = true
[dependencies] [dependencies]
cranelift-module = { workspace = true } cranelift-module = { workspace = true }
cranelift-codegen = { workspace = true, features = ["std"] } cranelift-codegen = { workspace = true, features = ["std"] }
cranelift-control = { workspace = true }
object = { workspace = true, features = ["write"] } object = { workspace = true, features = ["write"] }
target-lexicon = { workspace = true } target-lexicon = { workspace = true }
anyhow = { workspace = true } anyhow = { workspace = true }

View File

@@ -8,6 +8,7 @@ use cranelift_codegen::{
binemit::{Addend, CodeOffset, Reloc}, binemit::{Addend, CodeOffset, Reloc},
CodegenError, CodegenError,
}; };
use cranelift_control::ControlPlane;
use cranelift_module::{ use cranelift_module::{
DataContext, DataDescription, DataId, FuncId, Init, Linkage, Module, ModuleCompiledFunction, DataContext, DataDescription, DataId, FuncId, Init, Linkage, Module, ModuleCompiledFunction,
ModuleDeclarations, ModuleError, ModuleExtName, ModuleReloc, ModuleResult, ModuleDeclarations, ModuleError, ModuleExtName, ModuleReloc, ModuleResult,
@@ -319,11 +320,12 @@ impl Module for ObjectModule {
&mut self, &mut self,
func_id: FuncId, func_id: FuncId,
ctx: &mut cranelift_codegen::Context, ctx: &mut cranelift_codegen::Context,
ctrl_plane: &mut ControlPlane,
) -> ModuleResult<ModuleCompiledFunction> { ) -> ModuleResult<ModuleCompiledFunction> {
info!("defining function {}: {}", func_id, ctx.func.display()); info!("defining function {}: {}", func_id, ctx.func.display());
let mut code: Vec<u8> = Vec::new(); let mut code: Vec<u8> = Vec::new();
let res = ctx.compile_and_emit(self.isa(), &mut code)?; let res = ctx.compile_and_emit(self.isa(), &mut code, ctrl_plane)?;
let alignment = res.alignment as u64; let alignment = res.alignment as u64;
self.define_function_bytes( self.define_function_bytes(

View File

@@ -2,6 +2,7 @@ use cranelift_codegen::ir::*;
use cranelift_codegen::isa::CallConv; use cranelift_codegen::isa::CallConv;
use cranelift_codegen::settings; use cranelift_codegen::settings;
use cranelift_codegen::{ir::types::I16, Context}; use cranelift_codegen::{ir::types::I16, Context};
use cranelift_control::ControlPlane;
use cranelift_entity::EntityRef; use cranelift_entity::EntityRef;
use cranelift_frontend::*; use cranelift_frontend::*;
use cranelift_module::*; use cranelift_module::*;
@@ -31,7 +32,7 @@ fn error_on_incompatible_sig_in_declare_function() {
.unwrap(); // Make sure this is an error .unwrap(); // Make sure this is an error
} }
fn define_simple_function(module: &mut ObjectModule) -> FuncId { fn define_simple_function(module: &mut ObjectModule, ctrl_plane: &mut ControlPlane) -> FuncId {
let sig = Signature { let sig = Signature {
params: vec![], params: vec![],
returns: vec![], returns: vec![],
@@ -52,7 +53,9 @@ fn define_simple_function(module: &mut ObjectModule) -> FuncId {
bcx.ins().return_(&[]); bcx.ins().return_(&[]);
} }
module.define_function(func_id, &mut ctx).unwrap(); module
.define_function(func_id, &mut ctx, ctrl_plane)
.unwrap();
func_id func_id
} }
@@ -60,6 +63,7 @@ fn define_simple_function(module: &mut ObjectModule) -> FuncId {
#[test] #[test]
#[should_panic(expected = "Result::unwrap()` on an `Err` value: DuplicateDefinition(\"abc\")")] #[should_panic(expected = "Result::unwrap()` on an `Err` value: DuplicateDefinition(\"abc\")")]
fn panic_on_define_after_finalize() { fn panic_on_define_after_finalize() {
let ctrl_plane = &mut ControlPlane::default();
let flag_builder = settings::builder(); let flag_builder = settings::builder();
let isa_builder = cranelift_codegen::isa::lookup_by_name("x86_64-unknown-linux-gnu").unwrap(); let isa_builder = cranelift_codegen::isa::lookup_by_name("x86_64-unknown-linux-gnu").unwrap();
let isa = isa_builder let isa = isa_builder
@@ -68,8 +72,8 @@ fn panic_on_define_after_finalize() {
let mut module = let mut module =
ObjectModule::new(ObjectBuilder::new(isa, "foo", default_libcall_names()).unwrap()); ObjectModule::new(ObjectBuilder::new(isa, "foo", default_libcall_names()).unwrap());
define_simple_function(&mut module); define_simple_function(&mut module, ctrl_plane);
define_simple_function(&mut module); define_simple_function(&mut module, ctrl_plane);
} }
#[test] #[test]
@@ -192,7 +196,9 @@ fn libcall_function() {
bcx.ins().return_(&[]); bcx.ins().return_(&[]);
} }
module.define_function(func_id, &mut ctx).unwrap(); module
.define_function(func_id, &mut ctx, &mut ControlPlane::default())
.unwrap();
module.finish(); module.finish();
} }

View File

@@ -1041,9 +1041,11 @@ impl<'a> CrashCheckContext<'a> {
std::panic::set_hook(Box::new(|_| {})); // silence panics std::panic::set_hook(Box::new(|_| {})); // silence panics
let res = match std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| { let res = match std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
let _ = self let _ = self.context.compile_and_emit(
.context self.isa,
.compile_and_emit(self.isa, &mut self.code_memory); &mut self.code_memory,
&mut Default::default(),
);
})) { })) {
Ok(()) => CheckResult::Succeed, Ok(()) => CheckResult::Succeed,
Err(err) => CheckResult::Crash(get_panic_string(err)), Err(err) => CheckResult::Crash(get_panic_string(err)),

View File

@@ -102,7 +102,7 @@ fn handle_module(
// Compile and encode the result to machine code. // Compile and encode the result to machine code.
let compiled_code = context let compiled_code = context
.compile_and_emit(isa, &mut mem) .compile_and_emit(isa, &mut mem, &mut Default::default())
.map_err(|err| anyhow::anyhow!("{}", pretty_error(&err.func, err.inner)))?; .map_err(|err| anyhow::anyhow!("{}", pretty_error(&err.func, err.inner)))?;
let code_info = compiled_code.code_info(); let code_info = compiled_code.code_info();
@@ -113,7 +113,7 @@ fn handle_module(
cranelift_module::Linkage::Export, cranelift_module::Linkage::Export,
&context.func.signature, &context.func.signature,
)?; )?;
module.define_function(fid, &mut context)?; module.define_function(fid, &mut context, &mut Default::default())?;
} }
if options.print { if options.print {

View File

@@ -257,7 +257,7 @@ fn handle_module(options: &Options, path: &Path, name: &str, fisa: FlagsOrIsa) -
(vec![], vec![], vec![]) (vec![], vec![], vec![])
} else { } else {
let compiled_code = context let compiled_code = context
.compile_and_emit(isa, &mut mem) .compile_and_emit(isa, &mut mem, &mut Default::default())
.map_err(|err| anyhow::anyhow!("{}", pretty_error(&err.func, err.inner)))?; .map_err(|err| anyhow::anyhow!("{}", pretty_error(&err.func, err.inner)))?;
let code_info = compiled_code.code_info(); let code_info = compiled_code.code_info();

View File

@@ -12,6 +12,7 @@ edition.workspace = true
anyhow = { workspace = true } anyhow = { workspace = true }
wasmtime-environ = { workspace = true } wasmtime-environ = { workspace = true }
cranelift-codegen = { workspace = true } cranelift-codegen = { workspace = true }
cranelift-control = { workspace = true }
cranelift-native = { workspace = true } cranelift-native = { workspace = true }
target-lexicon = { workspace = true } target-lexicon = { workspace = true }
gimli = { workspace = true } gimli = { workspace = true }

View File

@@ -19,6 +19,7 @@ use cranelift_codegen::binemit::Reloc;
use cranelift_codegen::ir::LibCall; use cranelift_codegen::ir::LibCall;
use cranelift_codegen::isa::unwind::{systemv, UnwindInfo}; use cranelift_codegen::isa::unwind::{systemv, UnwindInfo};
use cranelift_codegen::TextSectionBuilder; use cranelift_codegen::TextSectionBuilder;
use cranelift_control::ControlPlane;
use gimli::write::{Address, EhFrame, EndianVec, FrameTable, Writer}; use gimli::write::{Address, EhFrame, EndianVec, FrameTable, Writer};
use gimli::RunTimeEndian; use gimli::RunTimeEndian;
use object::write::{Object, SectionId, StandardSegment, Symbol, SymbolId, SymbolSection}; use object::write::{Object, SectionId, StandardSegment, Symbol, SymbolId, SymbolSection};
@@ -59,6 +60,8 @@ pub struct ModuleTextBuilder<'a> {
/// Note that this isn't typically used. It's only used for SSE-disabled /// Note that this isn't typically used. It's only used for SSE-disabled
/// builds without SIMD on x86_64 right now. /// builds without SIMD on x86_64 right now.
libcall_symbols: HashMap<LibCall, SymbolId>, libcall_symbols: HashMap<LibCall, SymbolId>,
ctrl_plane: ControlPlane,
} }
impl<'a> ModuleTextBuilder<'a> { impl<'a> ModuleTextBuilder<'a> {
@@ -88,6 +91,7 @@ impl<'a> ModuleTextBuilder<'a> {
unwind_info: Default::default(), unwind_info: Default::default(),
text, text,
libcall_symbols: HashMap::default(), libcall_symbols: HashMap::default(),
ctrl_plane: ControlPlane::default(),
} }
} }
@@ -115,6 +119,7 @@ impl<'a> ModuleTextBuilder<'a> {
true, true,
&body, &body,
self.compiler.function_alignment().max(alignment), self.compiler.function_alignment().max(alignment),
&mut self.ctrl_plane,
); );
let symbol_id = self.obj.add_symbol(Symbol { let symbol_id = self.obj.add_symbol(Symbol {
@@ -227,7 +232,8 @@ impl<'a> ModuleTextBuilder<'a> {
if padding == 0 { if padding == 0 {
return; return;
} }
self.text.append(false, &vec![0; padding], 1); self.text
.append(false, &vec![0; padding], 1, &mut self.ctrl_plane);
} }
/// Indicates that the text section has been written completely and this /// Indicates that the text section has been written completely and this
@@ -237,7 +243,7 @@ impl<'a> ModuleTextBuilder<'a> {
/// necessary. /// necessary.
pub fn finish(mut self) { pub fn finish(mut self) {
// Finish up the text section now that we're done adding functions. // Finish up the text section now that we're done adding functions.
let text = self.text.finish(); let text = self.text.finish(&mut self.ctrl_plane);
self.obj self.obj
.section_mut(self.text_section) .section_mut(self.text_section)
.set_data(text, self.compiler.page_size_align()); .set_data(text, self.compiler.page_size_align());

View File

@@ -19,6 +19,7 @@ cranelift-codegen = { workspace = true }
cranelift-frontend = { workspace = true } cranelift-frontend = { workspace = true }
cranelift-entity = { workspace = true } cranelift-entity = { workspace = true }
cranelift-native = { workspace = true } cranelift-native = { workspace = true }
cranelift-control = { workspace = true }
wasmtime-cranelift-shared = { workspace = true } wasmtime-cranelift-shared = { workspace = true }
wasmparser = { workspace = true } wasmparser = { workspace = true }
target-lexicon = { workspace = true } target-lexicon = { workspace = true }

View File

@@ -612,7 +612,7 @@ fn compile_uncached<'a>(
) -> Result<(&'a CompiledCode, Vec<u8>), CompileError> { ) -> Result<(&'a CompiledCode, Vec<u8>), CompileError> {
let mut code_buf = Vec::new(); let mut code_buf = Vec::new();
let compiled_code = context let compiled_code = context
.compile_and_emit(isa, &mut code_buf) .compile_and_emit(isa, &mut code_buf, &mut Default::default())
.map_err(|error| CompileError::Codegen(pretty_error(&error.func, error.inner)))?; .map_err(|error| CompileError::Codegen(pretty_error(&error.func, error.inner)))?;
Ok((compiled_code, code_buf)) Ok((compiled_code, code_buf))
} }

View File

@@ -17,6 +17,7 @@ cranelift-filetests = { workspace = true }
cranelift-interpreter = { workspace = true } cranelift-interpreter = { workspace = true }
cranelift-fuzzgen = { workspace = true } cranelift-fuzzgen = { workspace = true }
cranelift-native = { workspace = true } cranelift-native = { workspace = true }
cranelift-control = { workspace = true }
libfuzzer-sys = { version = "0.4.0", features = ["arbitrary-derive"] } libfuzzer-sys = { version = "0.4.0", features = ["arbitrary-derive"] }
target-lexicon = { workspace = true } target-lexicon = { workspace = true }
smallvec = { workspace = true } smallvec = { workspace = true }
@@ -36,6 +37,7 @@ component-fuzz-util = { workspace = true }
[features] [features]
default = ['fuzz-spec-interpreter'] default = ['fuzz-spec-interpreter']
fuzz-spec-interpreter = ['wasmtime-fuzzing/fuzz-spec-interpreter'] fuzz-spec-interpreter = ['wasmtime-fuzzing/fuzz-spec-interpreter']
chaos = ["cranelift-control/chaos"]
[[bin]] [[bin]]
name = "compile" name = "compile"

View File

@@ -5,6 +5,7 @@ use cranelift_codegen::ir::Signature;
use cranelift_codegen::ir::UserExternalName; use cranelift_codegen::ir::UserExternalName;
use cranelift_codegen::ir::UserFuncName; use cranelift_codegen::ir::UserFuncName;
use cranelift_codegen::Context; use cranelift_codegen::Context;
use cranelift_control::ControlPlane;
use libfuzzer_sys::arbitrary; use libfuzzer_sys::arbitrary;
use libfuzzer_sys::arbitrary::Arbitrary; use libfuzzer_sys::arbitrary::Arbitrary;
use libfuzzer_sys::arbitrary::Unstructured; use libfuzzer_sys::arbitrary::Unstructured;
@@ -146,6 +147,9 @@ pub struct TestCase {
/// Functions under test /// Functions under test
/// By convention the first function is the main function. /// By convention the first function is the main function.
pub functions: Vec<Function>, pub functions: Vec<Function>,
/// Control planes for function compilation.
/// There should be an equal amount as functions to compile.
pub ctrl_planes: Vec<ControlPlane>,
/// Generate multiple test inputs for each test case. /// Generate multiple test inputs for each test case.
/// This allows us to get more coverage per compilation, which may be somewhat expensive. /// This allows us to get more coverage per compilation, which may be somewhat expensive.
pub inputs: Vec<TestCaseInput>, pub inputs: Vec<TestCaseInput>,
@@ -191,6 +195,7 @@ impl TestCase {
// the start. // the start.
let func_count = gen.u.int_in_range(gen.config.testcase_funcs.clone())?; let func_count = gen.u.int_in_range(gen.config.testcase_funcs.clone())?;
let mut functions: Vec<Function> = Vec::with_capacity(func_count); let mut functions: Vec<Function> = Vec::with_capacity(func_count);
let mut ctrl_planes: Vec<ControlPlane> = Vec::with_capacity(func_count);
for i in (0..func_count).rev() { for i in (0..func_count).rev() {
// Function name must be in a different namespace than TESTFILE_NAMESPACE (0) // Function name must be in a different namespace than TESTFILE_NAMESPACE (0)
let fname = UserFuncName::user(1, i as u32); let fname = UserFuncName::user(1, i as u32);
@@ -212,6 +217,8 @@ impl TestCase {
ALLOWED_LIBCALLS.to_vec(), ALLOWED_LIBCALLS.to_vec(),
)?; )?;
functions.push(func); functions.push(func);
ctrl_planes.push(ControlPlane::arbitrary(gen.u)?);
} }
// Now reverse the functions so that the main function is at the start. // Now reverse the functions so that the main function is at the start.
functions.reverse(); functions.reverse();
@@ -222,6 +229,7 @@ impl TestCase {
Ok(TestCase { Ok(TestCase {
isa, isa,
functions, functions,
ctrl_planes,
inputs, inputs,
compare_against_host, compare_against_host,
}) })
@@ -241,6 +249,7 @@ impl TestCase {
TestCase { TestCase {
isa: self.isa.clone(), isa: self.isa.clone(),
functions: optimized_functions, functions: optimized_functions,
ctrl_planes: self.ctrl_planes.clone(),
inputs: self.inputs.clone(), inputs: self.inputs.clone(),
compare_against_host: false, compare_against_host: false,
} }
@@ -368,7 +377,9 @@ fuzz_target!(|testcase: TestCase| {
}); });
} else { } else {
let mut compiler = TestFileCompiler::new(testcase.isa.clone()); let mut compiler = TestFileCompiler::new(testcase.isa.clone());
compiler.add_functions(&testcase.functions[..]).unwrap(); compiler
.add_functions(&testcase.functions[..], testcase.ctrl_planes.clone())
.unwrap();
let compiled = compiler.compile().unwrap(); let compiled = compiler.compile().unwrap();
let trampoline = compiled.get_trampoline(testcase.main()).unwrap(); let trampoline = compiled.get_trampoline(testcase.main()).unwrap();

View File

@@ -108,7 +108,7 @@ fuzz_target!(|func: FunctionWithIsa| {
let cache_key_hash = icache::compute_cache_key(&*isa, &func); let cache_key_hash = icache::compute_cache_key(&*isa, &func);
let mut context = Context::for_function(func.clone()); let mut context = Context::for_function(func.clone());
let prev_stencil = match context.compile_stencil(&*isa) { let prev_stencil = match context.compile_stencil(&*isa, &mut Default::default()) {
Ok(stencil) => stencil, Ok(stencil) => stencil,
Err(_) => return, Err(_) => return,
}; };
@@ -199,7 +199,7 @@ fuzz_target!(|func: FunctionWithIsa| {
context = Context::for_function(func.clone()); context = Context::for_function(func.clone());
let after_mutation_result = match context.compile(&*isa) { let after_mutation_result = match context.compile(&*isa, &mut Default::default()) {
Ok(info) => info, Ok(info) => info,
Err(_) => return, Err(_) => return,
}; };

View File

@@ -25,6 +25,7 @@ const CRATES_TO_PUBLISH: &[&str] = &[
"cranelift-codegen-shared", "cranelift-codegen-shared",
"cranelift-codegen-meta", "cranelift-codegen-meta",
"cranelift-egraph", "cranelift-egraph",
"cranelift-control",
"cranelift-codegen", "cranelift-codegen",
"cranelift-reader", "cranelift-reader",
"cranelift-serde", "cranelift-serde",
@@ -99,6 +100,7 @@ const PUBLIC_CRATES: &[&str] = &[
"cranelift-codegen-shared", "cranelift-codegen-shared",
"cranelift-codegen-meta", "cranelift-codegen-meta",
"cranelift-egraph", "cranelift-egraph",
"cranelift-control",
"cranelift-codegen", "cranelift-codegen",
"cranelift-reader", "cranelift-reader",
"cranelift-serde", "cranelift-serde",

View File

@@ -9,7 +9,7 @@ use cranelift_codegen::{
emit::{EmitInfo, EmitState}, emit::{EmitInfo, EmitState},
ALUOp, AMode, ExtendOp, Imm12, Inst, PairAMode, ALUOp, AMode, ExtendOp, Imm12, Inst, PairAMode,
}, },
settings, Final, MachBuffer, MachBufferFinalized, MachInstEmit, Writable, settings, Final, MachBuffer, MachBufferFinalized, MachInstEmit, MachInstEmitState, Writable,
}; };
/// An Aarch64 instruction operand. /// An Aarch64 instruction operand.
@@ -58,8 +58,8 @@ impl Assembler {
impl Assembler { impl Assembler {
/// Return the emitted code. /// Return the emitted code.
pub fn finalize(self) -> MachBufferFinalized<Final> { pub fn finalize(mut self) -> MachBufferFinalized<Final> {
let stencil = self.buffer.finish(); let stencil = self.buffer.finish(self.emit_state.ctrl_plane_mut());
stencil.apply_base_srcloc(Default::default()) stencil.apply_base_srcloc(Default::default())
} }

View File

@@ -15,7 +15,7 @@ use cranelift_codegen::{
}, },
settings as x64_settings, CallInfo, EmitInfo, EmitState, Inst, settings as x64_settings, CallInfo, EmitInfo, EmitState, Inst,
}, },
settings, Final, MachBuffer, MachBufferFinalized, MachInstEmit, Writable, settings, Final, MachBuffer, MachBufferFinalized, MachInstEmit, MachInstEmitState, Writable,
}; };
use super::{address::Address, regs}; use super::{address::Address, regs};
@@ -98,8 +98,8 @@ impl Assembler {
} }
/// Return the emitted code. /// Return the emitted code.
pub fn finalize(self) -> MachBufferFinalized<Final> { pub fn finalize(mut self) -> MachBufferFinalized<Final> {
let stencil = self.buffer.finish(); let stencil = self.buffer.finish(self.emit_state.ctrl_plane_mut());
stencil.apply_base_srcloc(Default::default()) stencil.apply_base_srcloc(Default::default())
} }