diff --git a/cranelift/codegen/src/context.rs b/cranelift/codegen/src/context.rs index 5cc50f5c54..fb7b8bb37d 100644 --- a/cranelift/codegen/src/context.rs +++ b/cranelift/codegen/src/context.rs @@ -10,7 +10,6 @@ //! single ISA instance. use crate::alias_analysis::AliasAnalysis; -use crate::binemit::CodeInfo; use crate::dce::do_dce; use crate::dominator_tree::DominatorTree; use crate::flowgraph::ControlFlowGraph; @@ -19,16 +18,16 @@ use crate::isa::TargetIsa; use crate::legalizer::simple_legalize; use crate::licm::do_licm; use crate::loop_analysis::LoopAnalysis; -use crate::machinst::MachCompileResult; +use crate::machinst::CompiledCode; use crate::nan_canonicalization::do_nan_canonicalization; use crate::remove_constant_phis::do_remove_constant_phis; -use crate::result::CodegenResult; +use crate::result::{CodegenResult, CompileResult}; use crate::settings::{FlagsOrIsa, OptLevel}; use crate::simple_gvn::do_simple_gvn; use crate::simple_preopt::do_preopt; -use crate::timing; use crate::unreachable_code::eliminate_unreachable_code; use crate::verifier::{verify_context, VerifierErrors, VerifierResult}; +use crate::{timing, CompileError}; #[cfg(feature = "souper-harvest")] use alloc::string::String; use alloc::vec::Vec; @@ -51,9 +50,9 @@ pub struct Context { pub loop_analysis: LoopAnalysis, /// Result of MachBackend compilation, if computed. - pub mach_compile_result: Option, + compiled_code: Option, - /// Flag: do we want a disassembly with the MachCompileResult? + /// Flag: do we want a disassembly with the CompiledCode? pub want_disasm: bool, } @@ -76,7 +75,7 @@ impl Context { cfg: ControlFlowGraph::new(), domtree: DominatorTree::new(), loop_analysis: LoopAnalysis::new(), - mach_compile_result: None, + compiled_code: None, want_disasm: false, } } @@ -87,10 +86,16 @@ impl Context { self.cfg.clear(); self.domtree.clear(); self.loop_analysis.clear(); - self.mach_compile_result = None; + self.compiled_code = None; self.want_disasm = false; } + /// Returns the compilation result for this function, available after any `compile` function + /// has been called. + pub fn compiled_code(&self) -> Option<&CompiledCode> { + self.compiled_code.as_ref() + } + /// Set the flag to request a disassembly when compiling with a /// `MachBackend` backend. pub fn set_disasm(&mut self, val: bool) { @@ -102,7 +107,7 @@ impl Context { /// Run the function through all the passes necessary to generate code for the target ISA /// represented by `isa`, as well as the final step of emitting machine code into a /// `Vec`. The machine code is not relocated. Instead, any relocations can be obtained - /// from `mach_compile_result`. + /// from `compiled_code()`. /// /// This function calls `compile` and `emit_to_memory`, taking care to resize `mem` as /// needed, so it provides a safe interface. @@ -112,13 +117,13 @@ impl Context { &mut self, isa: &dyn TargetIsa, mem: &mut Vec, - ) -> CodegenResult<()> { - let info = self.compile(isa)?; + ) -> CompileResult<&CompiledCode> { + let compiled_code = self.compile(isa)?; + let code_info = compiled_code.code_info(); let old_len = mem.len(); - mem.resize(old_len + info.total_size as usize, 0); - let new_info = unsafe { self.emit_to_memory(mem.as_mut_ptr().add(old_len)) }; - debug_assert!(new_info == info); - Ok(()) + mem.resize(old_len + code_info.total_size as usize, 0); + mem[old_len..].copy_from_slice(compiled_code.code_buffer()); + Ok(compiled_code) } /// Compile the function. @@ -128,86 +133,66 @@ impl Context { /// code sink. /// /// Returns information about the function's code and read-only data. - pub fn compile(&mut self, isa: &dyn TargetIsa) -> CodegenResult { + pub fn compile(&mut self, isa: &dyn TargetIsa) -> CompileResult<&CompiledCode> { let _tt = timing::compile(); - self.verify_if(isa)?; - let opt_level = isa.flags().opt_level(); - log::trace!( - "Compiling (opt level {:?}):\n{}", - opt_level, - self.func.display() - ); + let mut inner = || { + self.verify_if(isa)?; - self.compute_cfg(); - if opt_level != OptLevel::None { - self.preopt(isa)?; - } - if isa.flags().enable_nan_canonicalization() { - self.canonicalize_nans(isa)?; - } + let opt_level = isa.flags().opt_level(); + log::trace!( + "Compiling (opt level {:?}):\n{}", + opt_level, + self.func.display() + ); + + self.compute_cfg(); + if opt_level != OptLevel::None { + self.preopt(isa)?; + } + if isa.flags().enable_nan_canonicalization() { + self.canonicalize_nans(isa)?; + } + + self.legalize(isa)?; + if opt_level != OptLevel::None { + self.compute_domtree(); + self.compute_loop_analysis(); + self.licm(isa)?; + self.simple_gvn(isa)?; + } - self.legalize(isa)?; - if opt_level != OptLevel::None { self.compute_domtree(); - self.compute_loop_analysis(); - self.licm(isa)?; - self.simple_gvn(isa)?; - } + self.eliminate_unreachable_code(isa)?; + if opt_level != OptLevel::None { + self.dce(isa)?; + } - self.compute_domtree(); - self.eliminate_unreachable_code(isa)?; - if opt_level != OptLevel::None { - self.dce(isa)?; - } + self.remove_constant_phis(isa)?; - self.remove_constant_phis(isa)?; + if opt_level != OptLevel::None && isa.flags().enable_alias_analysis() { + self.replace_redundant_loads()?; + self.simple_gvn(isa)?; + } - if opt_level != OptLevel::None && isa.flags().enable_alias_analysis() { - self.replace_redundant_loads()?; - self.simple_gvn(isa)?; - } + let result = isa.compile_function(&self.func, self.want_disasm)?; + self.compiled_code = Some(result); + Ok(()) + }; - let result = isa.compile_function(&self.func, self.want_disasm)?; - let info = result.code_info(); - self.mach_compile_result = Some(result); - Ok(info) - } - - /// Emit machine code directly into raw memory. - /// - /// Write all of the function's machine code to the memory at `mem`. The size of the machine - /// code is returned by `compile` above. - /// - /// The machine code is not relocated. - /// Instead, any relocations can be obtained from `mach_compile_result`. - /// - /// # Safety - /// - /// This function is unsafe since it does not perform bounds checking on the memory buffer, - /// and it can't guarantee that the `mem` pointer is valid. - /// - /// Returns information about the emitted code and data. - #[deny(unsafe_op_in_unsafe_fn)] - pub unsafe fn emit_to_memory(&self, mem: *mut u8) -> CodeInfo { - let _tt = timing::binemit(); - let result = self - .mach_compile_result - .as_ref() - .expect("only using mach backend now"); - let info = result.code_info(); - - let mem = unsafe { std::slice::from_raw_parts_mut(mem, info.total_size as usize) }; - mem.copy_from_slice(result.buffer.data()); - - info + inner() + .map(|_| self.compiled_code.as_ref().unwrap()) + .map_err(|error| CompileError { + inner: error, + func: &self.func, + }) } /// If available, return information about the code layout in the /// final machine code: the offsets (in bytes) of each basic-block /// start, and all basic-block edges. pub fn get_code_bb_layout(&self) -> Option<(Vec, Vec<(usize, usize)>)> { - if let Some(result) = self.mach_compile_result.as_ref() { + if let Some(result) = self.compiled_code.as_ref() { Some(( result.bb_starts.iter().map(|&off| off as usize).collect(), result @@ -230,7 +215,7 @@ impl Context { isa: &dyn TargetIsa, ) -> CodegenResult> { let unwind_info_kind = isa.unwind_info_kind(); - let result = self.mach_compile_result.as_ref().unwrap(); + let result = self.compiled_code.as_ref().unwrap(); isa.emit_unwind_info(result, unwind_info_kind) } diff --git a/cranelift/codegen/src/isa/aarch64/mod.rs b/cranelift/codegen/src/isa/aarch64/mod.rs index 702b7d2977..90ca986205 100644 --- a/cranelift/codegen/src/isa/aarch64/mod.rs +++ b/cranelift/codegen/src/isa/aarch64/mod.rs @@ -7,7 +7,7 @@ use crate::isa::aarch64::settings as aarch64_settings; use crate::isa::unwind::systemv; use crate::isa::{Builder as IsaBuilder, TargetIsa}; use crate::machinst::{ - compile, MachCompileResult, MachTextSectionBuilder, Reg, TextSectionBuilder, VCode, + compile, CompiledCode, MachTextSectionBuilder, Reg, TextSectionBuilder, VCode, }; use crate::result::CodegenResult; use crate::settings as shared_settings; @@ -65,11 +65,7 @@ impl AArch64Backend { } impl TargetIsa for AArch64Backend { - fn compile_function( - &self, - func: &Function, - want_disasm: bool, - ) -> CodegenResult { + fn compile_function(&self, func: &Function, want_disasm: bool) -> CodegenResult { let flags = self.flags(); let (vcode, regalloc_result) = self.compile_vcode(func, flags.clone())?; @@ -84,7 +80,7 @@ impl TargetIsa for AArch64Backend { log::debug!("disassembly:\n{}", disasm); } - Ok(MachCompileResult { + Ok(CompiledCode { buffer, frame_size, disasm: emit_result.disasm, @@ -125,7 +121,7 @@ impl TargetIsa for AArch64Backend { #[cfg(feature = "unwind")] fn emit_unwind_info( &self, - result: &MachCompileResult, + result: &CompiledCode, kind: crate::machinst::UnwindInfoKind, ) -> CodegenResult> { use crate::isa::unwind::UnwindInfo; diff --git a/cranelift/codegen/src/isa/mod.rs b/cranelift/codegen/src/isa/mod.rs index 3d556d4935..5904f51b20 100644 --- a/cranelift/codegen/src/isa/mod.rs +++ b/cranelift/codegen/src/isa/mod.rs @@ -49,7 +49,7 @@ use crate::flowgraph; use crate::ir::{self, Function}; #[cfg(feature = "unwind")] use crate::isa::unwind::systemv::RegisterMappingError; -use crate::machinst::{MachCompileResult, TextSectionBuilder, UnwindInfoKind}; +use crate::machinst::{CompiledCode, TextSectionBuilder, UnwindInfoKind}; use crate::settings; use crate::settings::SetResult; use crate::CodegenResult; @@ -230,11 +230,7 @@ pub trait TargetIsa: fmt::Display + Send + Sync { fn dynamic_vector_bytes(&self, dynamic_ty: ir::Type) -> u32; /// Compile the given function. - fn compile_function( - &self, - func: &Function, - want_disasm: bool, - ) -> CodegenResult; + fn compile_function(&self, func: &Function, want_disasm: bool) -> CodegenResult; #[cfg(feature = "unwind")] /// Map a regalloc::Reg to its corresponding DWARF register. @@ -254,7 +250,7 @@ pub trait TargetIsa: fmt::Display + Send + Sync { #[cfg(feature = "unwind")] fn emit_unwind_info( &self, - result: &MachCompileResult, + result: &CompiledCode, kind: UnwindInfoKind, ) -> CodegenResult>; diff --git a/cranelift/codegen/src/isa/s390x/mod.rs b/cranelift/codegen/src/isa/s390x/mod.rs index 83e2ebdcf2..3ecb85886b 100644 --- a/cranelift/codegen/src/isa/s390x/mod.rs +++ b/cranelift/codegen/src/isa/s390x/mod.rs @@ -7,7 +7,7 @@ use crate::isa::s390x::settings as s390x_settings; use crate::isa::unwind::systemv::RegisterMappingError; use crate::isa::{Builder as IsaBuilder, TargetIsa}; use crate::machinst::{ - compile, MachCompileResult, MachTextSectionBuilder, Reg, TextSectionBuilder, VCode, + compile, CompiledCode, MachTextSectionBuilder, Reg, TextSectionBuilder, VCode, }; use crate::result::CodegenResult; use crate::settings as shared_settings; @@ -64,11 +64,7 @@ impl S390xBackend { } impl TargetIsa for S390xBackend { - fn compile_function( - &self, - func: &Function, - want_disasm: bool, - ) -> CodegenResult { + fn compile_function(&self, func: &Function, want_disasm: bool) -> CodegenResult { let flags = self.flags(); let (vcode, regalloc_result) = self.compile_vcode(func, flags.clone())?; @@ -83,7 +79,7 @@ impl TargetIsa for S390xBackend { log::debug!("disassembly:\n{}", disasm); } - Ok(MachCompileResult { + Ok(CompiledCode { buffer, frame_size, disasm: emit_result.disasm, @@ -127,7 +123,7 @@ impl TargetIsa for S390xBackend { #[cfg(feature = "unwind")] fn emit_unwind_info( &self, - result: &MachCompileResult, + result: &CompiledCode, kind: crate::machinst::UnwindInfoKind, ) -> CodegenResult> { use crate::isa::unwind::UnwindInfo; diff --git a/cranelift/codegen/src/isa/x64/mod.rs b/cranelift/codegen/src/isa/x64/mod.rs index 8f93c5b640..73bab65286 100644 --- a/cranelift/codegen/src/isa/x64/mod.rs +++ b/cranelift/codegen/src/isa/x64/mod.rs @@ -9,9 +9,7 @@ use crate::isa::unwind::systemv; use crate::isa::x64::{inst::regs::create_reg_env_systemv, settings as x64_settings}; use crate::isa::Builder as IsaBuilder; use crate::machinst::Reg; -use crate::machinst::{ - compile, MachCompileResult, MachTextSectionBuilder, TextSectionBuilder, VCode, -}; +use crate::machinst::{compile, CompiledCode, MachTextSectionBuilder, TextSectionBuilder, VCode}; use crate::result::{CodegenError, CodegenResult}; use crate::settings::{self as shared_settings, Flags}; use alloc::{boxed::Box, vec::Vec}; @@ -59,11 +57,7 @@ impl X64Backend { } impl TargetIsa for X64Backend { - fn compile_function( - &self, - func: &Function, - want_disasm: bool, - ) -> CodegenResult { + fn compile_function(&self, func: &Function, want_disasm: bool) -> CodegenResult { let flags = self.flags(); let (vcode, regalloc_result) = self.compile_vcode(func, flags.clone())?; @@ -78,7 +72,7 @@ impl TargetIsa for X64Backend { log::trace!("disassembly:\n{}", disasm); } - Ok(MachCompileResult { + Ok(CompiledCode { buffer, frame_size, disasm: emit_result.disasm, @@ -119,7 +113,7 @@ impl TargetIsa for X64Backend { #[cfg(feature = "unwind")] fn emit_unwind_info( &self, - result: &MachCompileResult, + result: &CompiledCode, kind: crate::machinst::UnwindInfoKind, ) -> CodegenResult> { use crate::isa::unwind::UnwindInfo; diff --git a/cranelift/codegen/src/lib.rs b/cranelift/codegen/src/lib.rs index 25ed7e17ae..593a8fc1e9 100644 --- a/cranelift/codegen/src/lib.rs +++ b/cranelift/codegen/src/lib.rs @@ -114,7 +114,7 @@ mod value_label; #[cfg(feature = "souper-harvest")] mod souper_harvest; -pub use crate::result::{CodegenError, CodegenResult}; +pub use crate::result::{CodegenError, CodegenResult, CompileError}; /// Even when trace logging is disabled, the trace macro has a significant performance cost so we /// disable it by default. diff --git a/cranelift/codegen/src/machinst/mod.rs b/cranelift/codegen/src/machinst/mod.rs index a47f4a2a95..953aa83ea8 100644 --- a/cranelift/codegen/src/machinst/mod.rs +++ b/cranelift/codegen/src/machinst/mod.rs @@ -272,7 +272,7 @@ pub trait MachInstEmitState: Default + Clone + Debug { /// The result of a `MachBackend::compile_function()` call. Contains machine /// code (as bytes) and a disassembly, if requested. -pub struct MachCompileResult { +pub struct CompiledCode { /// Machine code. pub buffer: MachBufferFinalized, /// Size of stack frame, in bytes. @@ -299,13 +299,18 @@ pub struct MachCompileResult { pub bb_edges: Vec<(CodeOffset, CodeOffset)>, } -impl MachCompileResult { +impl CompiledCode { /// Get a `CodeInfo` describing section sizes from this compilation result. pub fn code_info(&self) -> CodeInfo { CodeInfo { total_size: self.buffer.total_size(), } } + + /// Returns a reference to the machine code generated for this function compilation. + pub fn code_buffer(&self) -> &[u8] { + self.buffer.data() + } } /// An object that can be used to create the text section of an executable. diff --git a/cranelift/codegen/src/result.rs b/cranelift/codegen/src/result.rs index d8b7320c54..d14049c0b6 100644 --- a/cranelift/codegen/src/result.rs +++ b/cranelift/codegen/src/result.rs @@ -2,7 +2,7 @@ use regalloc2::checker::CheckerErrors; -use crate::verifier::VerifierErrors; +use crate::{ir::Function, verifier::VerifierErrors}; use std::string::String; /// A compilation error. @@ -81,3 +81,22 @@ impl From for CodegenError { CodegenError::Verifier { 0: source } } } + +/// Compilation error, with the accompanying function to help printing it. +pub struct CompileError<'a> { + /// Underlying `CodegenError` that triggered the error. + pub inner: CodegenError, + /// Function we tried to compile, for display purposes. + pub func: &'a Function, +} + +// By default, have `CompileError` be displayed as the internal error, and let consumers care if +// they want to use the func field for adding details. +impl<'a> core::fmt::Debug for CompileError<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + self.inner.fmt(f) + } +} + +/// A convenient alias for a `Result` that uses `CompileError` as the error type. +pub type CompileResult<'a, T> = Result>; diff --git a/cranelift/codegen/src/timing.rs b/cranelift/codegen/src/timing.rs index e4bfe4001e..f21a68fa33 100644 --- a/cranelift/codegen/src/timing.rs +++ b/cranelift/codegen/src/timing.rs @@ -68,7 +68,6 @@ define_passes! { regalloc: "Register allocation", regalloc_checker: "Register allocation symbolic verification", - binemit: "Binary machine code emission", layout_renumber: "Layout full renumbering", canonicalize_nans: "Canonicalization of NaNs", diff --git a/cranelift/filetests/src/function_runner.rs b/cranelift/filetests/src/function_runner.rs index 5400711603..62efa83024 100644 --- a/cranelift/filetests/src/function_runner.rs +++ b/cranelift/filetests/src/function_runner.rs @@ -241,12 +241,10 @@ fn compile(function: Function, isa: &dyn TargetIsa) -> Result From> for ModuleError { + fn from(err: CompileError<'a>) -> Self { + Self::Compilation(err.inner) + } +} + // This is manually implementing Error and Display instead of using thiserror to reduce the amount // of dependencies used by Cranelift. impl std::error::Error for ModuleError { diff --git a/cranelift/object/src/backend.rs b/cranelift/object/src/backend.rs index 0998d829ee..803c60832c 100644 --- a/cranelift/object/src/backend.rs +++ b/cranelift/object/src/backend.rs @@ -313,11 +313,7 @@ impl Module for ObjectModule { ctx.compile_and_emit(self.isa(), &mut code)?; - self.define_function_bytes( - func_id, - &code, - ctx.mach_compile_result.as_ref().unwrap().buffer.relocs(), - ) + self.define_function_bytes(func_id, &code, ctx.compiled_code().unwrap().buffer.relocs()) } fn define_function_bytes( diff --git a/cranelift/src/compile.rs b/cranelift/src/compile.rs index 603f193afd..af03d8a4fe 100644 --- a/cranelift/src/compile.rs +++ b/cranelift/src/compile.rs @@ -68,17 +68,17 @@ fn handle_module(options: &Options, path: &Path, name: &str, fisa: FlagsOrIsa) - let mut mem = vec![]; // Compile and encode the result to machine code. - context + let compiled_code = context .compile_and_emit(isa, &mut mem) - .map_err(|err| anyhow::anyhow!("{}", pretty_error(&context.func, err)))?; - let result = context.mach_compile_result.as_ref().unwrap(); - let code_info = result.code_info(); + .map_err(|err| anyhow::anyhow!("{}", pretty_error(&err.func, err.inner)))?; + let code_info = compiled_code.code_info(); if options.print { println!("{}", context.func.display()); } if options.disasm { + let result = context.compiled_code().unwrap(); print_all( isa, &mem, diff --git a/cranelift/src/wasm.rs b/cranelift/src/wasm.rs index e02d80862d..f35f62b043 100644 --- a/cranelift/src/wasm.rs +++ b/cranelift/src/wasm.rs @@ -257,11 +257,10 @@ fn handle_module(options: &Options, path: &Path, name: &str, fisa: FlagsOrIsa) - } (vec![], vec![], vec![]) } else { - context + let compiled_code = context .compile_and_emit(isa, &mut mem) - .map_err(|err| anyhow::anyhow!("{}", pretty_error(&context.func, err)))?; - let result = context.mach_compile_result.as_ref().unwrap(); - let code_info = result.code_info(); + .map_err(|err| anyhow::anyhow!("{}", pretty_error(&err.func, err.inner)))?; + let code_info = compiled_code.code_info(); if options.print_size { println!( @@ -280,9 +279,9 @@ fn handle_module(options: &Options, path: &Path, name: &str, fisa: FlagsOrIsa) - saved_size = Some(code_info.total_size); } ( - result.buffer.relocs().to_vec(), - result.buffer.traps().to_vec(), - result.buffer.stack_maps().to_vec(), + compiled_code.buffer.relocs().to_vec(), + compiled_code.buffer.traps().to_vec(), + compiled_code.buffer.stack_maps().to_vec(), ) }; @@ -299,14 +298,7 @@ fn handle_module(options: &Options, path: &Path, name: &str, fisa: FlagsOrIsa) - println!("; Exported as \"{}\"", export_name); } let value_ranges = if options.value_ranges { - Some( - context - .mach_compile_result - .as_ref() - .unwrap() - .value_labels_ranges - .clone(), - ) + Some(context.compiled_code().unwrap().value_labels_ranges.clone()) } else { None }; diff --git a/crates/cranelift/src/compiler.rs b/crates/cranelift/src/compiler.rs index d993041342..99d125b619 100644 --- a/crates/cranelift/src/compiler.rs +++ b/crates/cranelift/src/compiler.rs @@ -98,14 +98,13 @@ impl Compiler { let start_srcloc = FilePos::new(offset as u32); let end_srcloc = FilePos::new((offset + len) as u32); - // New-style backend: we have a `MachCompileResult` that will give us `MachSrcLoc` mapping + // New-style backend: we have a `CompiledCode` that will give us `MachSrcLoc` mapping // tuples. let instructions = if tunables.generate_address_map { collect_address_maps( body_len, context - .mach_compile_result - .as_ref() + .compiled_code() .unwrap() .buffer .get_srclocs_sorted() @@ -212,27 +211,25 @@ impl wasmtime_environ::Compiler for Compiler { )?; let mut code_buf: Vec = Vec::new(); - context + let compiled_code = context .compile_and_emit(isa, &mut code_buf) - .map_err(|error| CompileError::Codegen(pretty_error(&context.func, error)))?; + .map_err(|error| CompileError::Codegen(pretty_error(&error.func, error.inner)))?; - let result = context.mach_compile_result.as_ref().unwrap(); - - let func_relocs = result + let func_relocs = compiled_code .buffer .relocs() .into_iter() .map(mach_reloc_to_reloc) .collect::>(); - let traps = result + let traps = compiled_code .buffer .traps() .into_iter() .map(mach_trap_to_trap) .collect::>(); - let stack_maps = mach_stack_maps_to_stack_maps(result.buffer.stack_maps()); + let stack_maps = mach_stack_maps_to_stack_maps(compiled_code.buffer.stack_maps()); let unwind_info = if isa.flags().unwind_info() { context @@ -246,14 +243,7 @@ impl wasmtime_environ::Compiler for Compiler { self.get_function_address_map(&context, &input, code_buf.len() as u32, tunables); let ranges = if tunables.generate_native_debuginfo { - Some( - context - .mach_compile_result - .as_ref() - .unwrap() - .value_labels_ranges - .clone(), - ) + Some(context.compiled_code().unwrap().value_labels_ranges.clone()) } else { None }; @@ -681,19 +671,18 @@ impl Compiler { isa: &dyn TargetIsa, ) -> Result { let mut code_buf = Vec::new(); - context + let compiled_code = context .compile_and_emit(isa, &mut code_buf) - .map_err(|error| CompileError::Codegen(pretty_error(&context.func, error)))?; - let result = context.mach_compile_result.as_ref().unwrap(); + .map_err(|error| CompileError::Codegen(pretty_error(&error.func, error.inner)))?; // Processing relocations isn't the hardest thing in the world here but // no trampoline should currently generate a relocation, so assert that // they're all empty and if this ever trips in the future then handling // will need to be added here to ensure they make their way into the // `CompiledFunction` below. - assert!(result.buffer.relocs().is_empty()); + assert!(compiled_code.buffer.relocs().is_empty()); - let traps = result + let traps = compiled_code .buffer .traps() .into_iter()