Add a Context::compile() function which runs all compiler passes.
This is the main entry point to the code generator. It returns the computed size of the functions code. Also add a 'test compile' command which runs the whole code generation pipeline.
This commit is contained in:
@@ -31,11 +31,12 @@ use binemit::CodeOffset;
|
||||
use ir::{Function, DataFlowGraph, Cursor, InstructionData, Opcode, InstEncodings};
|
||||
use isa::{TargetIsa, EncInfo};
|
||||
use iterators::IteratorExtras;
|
||||
use result::CtonError;
|
||||
|
||||
/// Relax branches and compute the final layout of EBB headers in `func`.
|
||||
///
|
||||
/// Fill in the `func.offsets` table so the function is ready for binary emission.
|
||||
pub fn relax_branches(func: &mut Function, isa: &TargetIsa) {
|
||||
pub fn relax_branches(func: &mut Function, isa: &TargetIsa) -> Result<CodeOffset, CtonError> {
|
||||
let encinfo = isa.encoding_info();
|
||||
|
||||
// Clear all offsets so we can recognize EBBs that haven't been visited yet.
|
||||
@@ -45,13 +46,15 @@ pub fn relax_branches(func: &mut Function, isa: &TargetIsa) {
|
||||
// Start by inserting fall through instructions.
|
||||
fallthroughs(func);
|
||||
|
||||
let mut offset = 0;
|
||||
|
||||
// The relaxation algorithm iterates to convergence.
|
||||
let mut go_again = true;
|
||||
while go_again {
|
||||
go_again = false;
|
||||
offset = 0;
|
||||
|
||||
// Visit all instructions in layout order
|
||||
let mut offset = 0;
|
||||
let mut pos = Cursor::new(&mut func.layout);
|
||||
while let Some(ebb) = pos.next_ebb() {
|
||||
// Record the offset for `ebb` and make sure we iterate until offsets are stable.
|
||||
@@ -90,6 +93,8 @@ pub fn relax_branches(func: &mut Function, isa: &TargetIsa) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(offset)
|
||||
}
|
||||
|
||||
/// Convert `jump` instructions to `fallthrough` instructions where possible and verify that any
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
//! contexts concurrently. Typically, you would have one context per compilation thread and only a
|
||||
//! single ISA instance.
|
||||
|
||||
use binemit::{CodeOffset, relax_branches};
|
||||
use dominator_tree::DominatorTree;
|
||||
use flowgraph::ControlFlowGraph;
|
||||
use ir::Function;
|
||||
@@ -16,7 +17,7 @@ use loop_analysis::LoopAnalysis;
|
||||
use isa::TargetIsa;
|
||||
use legalize_function;
|
||||
use regalloc;
|
||||
use result::CtonResult;
|
||||
use result::{CtonError, CtonResult};
|
||||
use verifier;
|
||||
use simple_gvn::do_simple_gvn;
|
||||
use licm::do_licm;
|
||||
@@ -54,6 +55,22 @@ impl Context {
|
||||
}
|
||||
}
|
||||
|
||||
/// Compile the function.
|
||||
///
|
||||
/// Run the function through all the passes necessary to generate code for the target ISA
|
||||
/// represented by `isa`. This does not include the final step of emitting machine code into a
|
||||
/// code sink.
|
||||
///
|
||||
/// Returns the size of the function's code.
|
||||
pub fn compile(&mut self, isa: &TargetIsa) -> Result<CodeOffset, CtonError> {
|
||||
self.flowgraph();
|
||||
self.verify_if(isa)?;
|
||||
|
||||
self.legalize(isa)?;
|
||||
self.regalloc(isa)?;
|
||||
self.relax_branches(isa)
|
||||
}
|
||||
|
||||
/// Run the verifier on the function.
|
||||
///
|
||||
/// Also check that the dominator tree and control flow graph are consistent with the function.
|
||||
@@ -107,4 +124,12 @@ impl Context {
|
||||
self.regalloc
|
||||
.run(isa, &mut self.func, &self.cfg, &self.domtree)
|
||||
}
|
||||
|
||||
/// Run the branch relaxation pass and return the final code size.
|
||||
pub fn relax_branches(&mut self, isa: &TargetIsa) -> Result<CodeOffset, CtonError> {
|
||||
let code_size = relax_branches(&mut self.func, isa)?;
|
||||
self.verify_if(isa)?;
|
||||
|
||||
Ok(code_size)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user