From 6ab35e54b89227e7f3fde7dc9c6ee1c371f9b500 Mon Sep 17 00:00:00 2001 From: Jakob Stoklund Olesen Date: Wed, 5 Apr 2017 10:07:19 -0700 Subject: [PATCH] Move encoding-related information into an EncInfo struct. The tables returned by recipe_names() and recipe_constraints() are now collected into an EncInfo struct that is available from TargetIsa::encoding_info(). This is equivalent to the register bank tables available fro TargetIsa::register_info(). This cleans of the TargetIsa interface and makes it easier to add encoding-related information. --- lib/cretonne/meta/gen_encoding.py | 9 ++++++-- lib/cretonne/src/isa/arm32/enc_tables.rs | 3 ++- lib/cretonne/src/isa/arm32/mod.rs | 14 +++++-------- lib/cretonne/src/isa/arm64/enc_tables.rs | 3 ++- lib/cretonne/src/isa/arm64/mod.rs | 14 +++++-------- lib/cretonne/src/isa/encoding.rs | 26 ++++++++++++++++++++++++ lib/cretonne/src/isa/intel/enc_tables.rs | 3 ++- lib/cretonne/src/isa/intel/mod.rs | 14 +++++-------- lib/cretonne/src/isa/mod.rs | 25 ++++------------------- lib/cretonne/src/isa/riscv/enc_tables.rs | 8 +++++--- lib/cretonne/src/isa/riscv/mod.rs | 16 ++++++--------- lib/cretonne/src/regalloc/coloring.rs | 11 ++++++---- lib/cretonne/src/regalloc/liveness.rs | 20 ++++++++---------- lib/cretonne/src/write.rs | 2 +- lib/reader/src/parser.rs | 3 ++- 15 files changed, 88 insertions(+), 83 deletions(-) diff --git a/lib/cretonne/meta/gen_encoding.py b/lib/cretonne/meta/gen_encoding.py index e4faa6410c..21b121487f 100644 --- a/lib/cretonne/meta/gen_encoding.py +++ b/lib/cretonne/meta/gen_encoding.py @@ -450,7 +450,7 @@ def emit_recipe_names(isa, fmt): This is used for pretty-printing encodings. """ with fmt.indented( - 'pub static RECIPE_NAMES: [&\'static str; {}] = [' + 'static RECIPE_NAMES: [&\'static str; {}] = [' .format(len(isa.all_recipes)), '];'): for r in isa.all_recipes: fmt.line('"{}",'.format(r.name)) @@ -465,7 +465,7 @@ def emit_recipe_constraints(isa, fmt): properly encoded. """ with fmt.indented( - 'pub static RECIPE_CONSTRAINTS: [RecipeConstraints; {}] = [' + 'static RECIPE_CONSTRAINTS: [RecipeConstraints; {}] = [' .format(len(isa.all_recipes)), '];'): for r in isa.all_recipes: fmt.comment(r.name) @@ -536,6 +536,11 @@ def gen_isa(isa, fmt): emit_recipe_names(isa, fmt) emit_recipe_constraints(isa, fmt) + # Finally, tie it all together in an `EncInfo`. + with fmt.indented('pub static INFO: EncInfo = EncInfo {', '};'): + fmt.line('constraints: &RECIPE_CONSTRAINTS,') + fmt.line('names: &RECIPE_NAMES,') + def generate(isas, out_dir): # type: (Sequence[TargetISA], str) -> None diff --git a/lib/cretonne/src/isa/arm32/enc_tables.rs b/lib/cretonne/src/isa/arm32/enc_tables.rs index c464d92f23..67cde87ed4 100644 --- a/lib/cretonne/src/isa/arm32/enc_tables.rs +++ b/lib/cretonne/src/isa/arm32/enc_tables.rs @@ -2,7 +2,8 @@ use ir::InstructionData; use ir::types; -use isa::enc_tables::{Level1Entry, Level2Entry}; +use isa::EncInfo; use isa::constraints::*; +use isa::enc_tables::{Level1Entry, Level2Entry}; include!(concat!(env!("OUT_DIR"), "/encoding-arm32.rs")); diff --git a/lib/cretonne/src/isa/arm32/mod.rs b/lib/cretonne/src/isa/arm32/mod.rs index df4f4c2570..c9c7f2af5c 100644 --- a/lib/cretonne/src/isa/arm32/mod.rs +++ b/lib/cretonne/src/isa/arm32/mod.rs @@ -9,7 +9,7 @@ use binemit::CodeSink; use super::super::settings as shared_settings; use isa::enc_tables::{self as shared_enc_tables, lookup_enclist, general_encoding}; use isa::Builder as IsaBuilder; -use isa::{TargetIsa, RegInfo, Encoding, Legalize, RecipeConstraints}; +use isa::{TargetIsa, RegInfo, EncInfo, Encoding, Legalize}; use ir; #[allow(dead_code)] @@ -55,6 +55,10 @@ impl TargetIsa for Isa { registers::INFO.clone() } + fn encoding_info(&self) -> EncInfo { + enc_tables::INFO.clone() + } + fn encode(&self, dfg: &ir::DataFlowGraph, inst: &ir::InstructionData) @@ -72,14 +76,6 @@ impl TargetIsa for Isa { }) } - fn recipe_names(&self) -> &'static [&'static str] { - &enc_tables::RECIPE_NAMES[..] - } - - fn recipe_constraints(&self) -> &'static [RecipeConstraints] { - &enc_tables::RECIPE_CONSTRAINTS - } - fn emit_inst(&self, func: &ir::Function, inst: ir::Inst, sink: &mut CodeSink) { binemit::emit_inst(func, inst, sink) } diff --git a/lib/cretonne/src/isa/arm64/enc_tables.rs b/lib/cretonne/src/isa/arm64/enc_tables.rs index 064a00f2e2..d092c0eb8f 100644 --- a/lib/cretonne/src/isa/arm64/enc_tables.rs +++ b/lib/cretonne/src/isa/arm64/enc_tables.rs @@ -2,7 +2,8 @@ use ir::InstructionData; use ir::types; -use isa::enc_tables::{Level1Entry, Level2Entry}; +use isa::EncInfo; use isa::constraints::*; +use isa::enc_tables::{Level1Entry, Level2Entry}; include!(concat!(env!("OUT_DIR"), "/encoding-arm64.rs")); diff --git a/lib/cretonne/src/isa/arm64/mod.rs b/lib/cretonne/src/isa/arm64/mod.rs index 2c11b450bb..a8cfe834b9 100644 --- a/lib/cretonne/src/isa/arm64/mod.rs +++ b/lib/cretonne/src/isa/arm64/mod.rs @@ -9,7 +9,7 @@ use binemit::CodeSink; use super::super::settings as shared_settings; use isa::enc_tables::{lookup_enclist, general_encoding}; use isa::Builder as IsaBuilder; -use isa::{TargetIsa, RegInfo, Encoding, Legalize, RecipeConstraints}; +use isa::{TargetIsa, RegInfo, EncInfo, Encoding, Legalize}; use ir; #[allow(dead_code)] @@ -48,6 +48,10 @@ impl TargetIsa for Isa { registers::INFO.clone() } + fn encoding_info(&self) -> EncInfo { + enc_tables::INFO.clone() + } + fn encode(&self, dfg: &ir::DataFlowGraph, inst: &ir::InstructionData) @@ -65,14 +69,6 @@ impl TargetIsa for Isa { }) } - fn recipe_names(&self) -> &'static [&'static str] { - &enc_tables::RECIPE_NAMES[..] - } - - fn recipe_constraints(&self) -> &'static [RecipeConstraints] { - &enc_tables::RECIPE_CONSTRAINTS - } - fn emit_inst(&self, func: &ir::Function, inst: ir::Inst, sink: &mut CodeSink) { binemit::emit_inst(func, inst, sink) } diff --git a/lib/cretonne/src/isa/encoding.rs b/lib/cretonne/src/isa/encoding.rs index 4c8e33a764..88040925ad 100644 --- a/lib/cretonne/src/isa/encoding.rs +++ b/lib/cretonne/src/isa/encoding.rs @@ -1,6 +1,7 @@ //! The `Encoding` struct. use std::fmt; +use isa::constraints::RecipeConstraints; /// Bits needed to encode an instruction as binary machine code. /// @@ -76,3 +77,28 @@ impl fmt::Display for DisplayEncoding { } } } + +/// Information about all the encodings in this ISA. +#[derive(Clone)] +pub struct EncInfo { + /// Constraints on value operands per recipe. + pub constraints: &'static [RecipeConstraints], + + /// Names of encoding recipes. + pub names: &'static [&'static str], +} + +impl EncInfo { + /// Get the value operand constraints for `enc` if it is a legal encoding. + pub fn operand_constraints(&self, enc: Encoding) -> Option<&RecipeConstraints> { + self.constraints.get(enc.recipe()) + } + + /// Create an object that can display an ISA-dependent encoding properly. + pub fn display(&self, enc: Encoding) -> DisplayEncoding { + DisplayEncoding { + encoding: enc, + recipe_names: self.names, + } + } +} diff --git a/lib/cretonne/src/isa/intel/enc_tables.rs b/lib/cretonne/src/isa/intel/enc_tables.rs index a29394a3a9..8abc8cd9d9 100644 --- a/lib/cretonne/src/isa/intel/enc_tables.rs +++ b/lib/cretonne/src/isa/intel/enc_tables.rs @@ -2,7 +2,8 @@ use ir::InstructionData; use ir::types; -use isa::enc_tables::{Level1Entry, Level2Entry}; +use isa::EncInfo; use isa::constraints::*; +use isa::enc_tables::{Level1Entry, Level2Entry}; include!(concat!(env!("OUT_DIR"), "/encoding-intel.rs")); diff --git a/lib/cretonne/src/isa/intel/mod.rs b/lib/cretonne/src/isa/intel/mod.rs index 46aa101ce0..b48a119632 100644 --- a/lib/cretonne/src/isa/intel/mod.rs +++ b/lib/cretonne/src/isa/intel/mod.rs @@ -9,7 +9,7 @@ use binemit::CodeSink; use super::super::settings as shared_settings; use isa::enc_tables::{self as shared_enc_tables, lookup_enclist, general_encoding}; use isa::Builder as IsaBuilder; -use isa::{TargetIsa, RegInfo, Encoding, Legalize, RecipeConstraints}; +use isa::{TargetIsa, RegInfo, EncInfo, Encoding, Legalize}; use ir; #[allow(dead_code)] @@ -55,6 +55,10 @@ impl TargetIsa for Isa { registers::INFO.clone() } + fn encoding_info(&self) -> EncInfo { + enc_tables::INFO.clone() + } + fn encode(&self, dfg: &ir::DataFlowGraph, inst: &ir::InstructionData) @@ -72,14 +76,6 @@ impl TargetIsa for Isa { }) } - fn recipe_names(&self) -> &'static [&'static str] { - &enc_tables::RECIPE_NAMES[..] - } - - fn recipe_constraints(&self) -> &'static [RecipeConstraints] { - &enc_tables::RECIPE_CONSTRAINTS - } - fn emit_inst(&self, func: &ir::Function, inst: ir::Inst, sink: &mut CodeSink) { binemit::emit_inst(func, inst, sink) } diff --git a/lib/cretonne/src/isa/mod.rs b/lib/cretonne/src/isa/mod.rs index 4eddae7b14..4fc08906ae 100644 --- a/lib/cretonne/src/isa/mod.rs +++ b/lib/cretonne/src/isa/mod.rs @@ -40,9 +40,9 @@ //! The configured target ISA trait object is a `Box` which can be used for multiple //! concurrent function compilations. -pub use isa::encoding::Encoding; -pub use isa::registers::{RegInfo, RegUnit, RegClass, RegClassIndex}; pub use isa::constraints::{RecipeConstraints, OperandConstraint, ConstraintKind}; +pub use isa::encoding::{Encoding, EncInfo}; +pub use isa::registers::{RegInfo, RegUnit, RegClass, RegClassIndex}; use binemit::CodeSink; use settings; @@ -143,25 +143,8 @@ pub trait TargetIsa { /// This is also the main entry point for determining if an instruction is legal. fn encode(&self, dfg: &DataFlowGraph, inst: &InstructionData) -> Result; - /// Get a static array of names associated with encoding recipes in this ISA. Encoding recipes - /// are numbered starting from 0, corresponding to indexes into the name array. - /// - /// This is just used for printing and parsing encodings in the textual IL format. - fn recipe_names(&self) -> &'static [&'static str]; - - /// Get a static array of value operand constraints associated with encoding recipes in this - /// ISA. - /// - /// The constraints describe which registers can be used with an encoding recipe. - fn recipe_constraints(&self) -> &'static [RecipeConstraints]; - - /// Create an object that can display an ISA-dependent encoding properly. - fn display_enc(&self, enc: Encoding) -> encoding::DisplayEncoding { - encoding::DisplayEncoding { - encoding: enc, - recipe_names: self.recipe_names(), - } - } + /// Get a data structure describing the instruction encodings in this ISA. + fn encoding_info(&self) -> EncInfo; /// Legalize a function signature. /// diff --git a/lib/cretonne/src/isa/riscv/enc_tables.rs b/lib/cretonne/src/isa/riscv/enc_tables.rs index 7940fce004..87c62bd63c 100644 --- a/lib/cretonne/src/isa/riscv/enc_tables.rs +++ b/lib/cretonne/src/isa/riscv/enc_tables.rs @@ -1,11 +1,12 @@ //! Encoding tables for RISC-V. use ir::condcodes::IntCC; -use ir::{Opcode, InstructionData}; use ir::types; -use predicates; -use isa::enc_tables::{Level1Entry, Level2Entry}; +use ir::{Opcode, InstructionData}; +use isa::EncInfo; use isa::constraints::*; +use isa::enc_tables::{Level1Entry, Level2Entry}; +use predicates; use super::registers::*; // Include the generated encoding tables: @@ -13,4 +14,5 @@ use super::registers::*; // - `LEVEL1_RV64` // - `LEVEL2` // - `ENCLIST` +// - `INFO` include!(concat!(env!("OUT_DIR"), "/encoding-riscv.rs")); diff --git a/lib/cretonne/src/isa/riscv/mod.rs b/lib/cretonne/src/isa/riscv/mod.rs index 348e1af32f..7658db392e 100644 --- a/lib/cretonne/src/isa/riscv/mod.rs +++ b/lib/cretonne/src/isa/riscv/mod.rs @@ -10,7 +10,7 @@ use super::super::settings as shared_settings; use binemit::CodeSink; use isa::enc_tables::{self as shared_enc_tables, lookup_enclist, general_encoding}; use isa::Builder as IsaBuilder; -use isa::{TargetIsa, RegInfo, Encoding, Legalize, RecipeConstraints}; +use isa::{TargetIsa, RegInfo, EncInfo, Encoding, Legalize}; use ir::{Function, Inst, InstructionData, DataFlowGraph, Signature}; #[allow(dead_code)] @@ -56,6 +56,10 @@ impl TargetIsa for Isa { registers::INFO.clone() } + fn encoding_info(&self) -> EncInfo { + enc_tables::INFO.clone() + } + fn encode(&self, dfg: &DataFlowGraph, inst: &InstructionData) -> Result { lookup_enclist(inst.ctrl_typevar(dfg), inst.opcode(), @@ -70,14 +74,6 @@ impl TargetIsa for Isa { }) } - fn recipe_names(&self) -> &'static [&'static str] { - &enc_tables::RECIPE_NAMES[..] - } - - fn recipe_constraints(&self) -> &'static [RecipeConstraints] { - &enc_tables::RECIPE_CONSTRAINTS - } - fn legalize_signature(&self, sig: &mut Signature) { // We can pass in `self.isa_flags` too, if we need it. abi::legalize_signature(sig, &self.shared_flags) @@ -100,7 +96,7 @@ mod tests { use ir::{types, immediates}; fn encstr(isa: &isa::TargetIsa, enc: isa::Encoding) -> String { - isa.display_enc(enc).to_string() + isa.encoding_info().display(enc).to_string() } #[test] diff --git a/lib/cretonne/src/regalloc/coloring.rs b/lib/cretonne/src/regalloc/coloring.rs index b8c08bd278..b9e5fe7148 100644 --- a/lib/cretonne/src/regalloc/coloring.rs +++ b/lib/cretonne/src/regalloc/coloring.rs @@ -38,7 +38,7 @@ use entity_map::EntityMap; use dominator_tree::DominatorTree; use ir::{Ebb, Inst, Value, Function, Cursor, ValueLoc, DataFlowGraph}; -use isa::{TargetIsa, RegInfo, Encoding, RecipeConstraints, ConstraintKind}; +use isa::{TargetIsa, RegInfo, Encoding, EncInfo, ConstraintKind}; use regalloc::affinity::Affinity; use regalloc::allocatable_set::AllocatableSet; use regalloc::live_value_tracker::{LiveValue, LiveValueTracker}; @@ -69,7 +69,7 @@ struct Context<'a> { // Cached ISA information. // We save it here to avoid frequent virtual function calls on the `TargetIsa` trait object. reginfo: RegInfo, - recipe_constraints: &'a [RecipeConstraints], + encinfo: EncInfo, // References to contextual data structures we need. domtree: &'a DominatorTree, @@ -98,7 +98,7 @@ impl Coloring { tracker: &mut LiveValueTracker) { let mut ctx = Context { reginfo: isa.register_info(), - recipe_constraints: isa.recipe_constraints(), + encinfo: isa.encoding_info(), domtree: domtree, liveness: liveness, // TODO: Ask the target ISA about reserved registers etc. @@ -259,7 +259,10 @@ impl<'a> Context<'a> { let (kills, defs) = tracker.process_inst(inst, dfg, self.liveness); // Get the operand constraints for `inst` that we are trying to satisfy. - let constraints = self.recipe_constraints[encoding.recipe()].clone(); + let constraints = self.encinfo + .operand_constraints(encoding) + .expect("Missing instruction encoding") + .clone(); // Get rid of the killed values. for lv in kills { diff --git a/lib/cretonne/src/regalloc/liveness.rs b/lib/cretonne/src/regalloc/liveness.rs index 3344c5b841..90b817a825 100644 --- a/lib/cretonne/src/regalloc/liveness.rs +++ b/lib/cretonne/src/regalloc/liveness.rs @@ -178,7 +178,7 @@ use flowgraph::ControlFlowGraph; use ir::dfg::ValueDef; use ir::{Function, Value, Inst, Ebb}; -use isa::{TargetIsa, RecipeConstraints}; +use isa::{TargetIsa, EncInfo}; use regalloc::affinity::Affinity; use regalloc::liverange::LiveRange; use sparse_map::SparseMap; @@ -191,7 +191,7 @@ type LiveRangeSet = SparseMap; fn get_or_create<'a>(lrset: &'a mut LiveRangeSet, value: Value, func: &Function, - recipe_constraints: &[RecipeConstraints]) + enc_info: &EncInfo) -> &'a mut LiveRange { // It would be better to use `get_mut()` here, but that leads to borrow checker fighting // which can probably only be resolved by non-lexical lifetimes. @@ -205,8 +205,8 @@ fn get_or_create<'a>(lrset: &'a mut LiveRangeSet, def = inst.into(); // Initialize the affinity from the defining instruction's result constraints. // Don't do this for call return values which are always tied to a single register. - affinity = recipe_constraints - .get(func.encodings[inst].recipe()) + affinity = enc_info + .operand_constraints(func.encodings[inst]) .and_then(|rc| rc.outs.get(rnum)) .map(Affinity::new) .unwrap_or_default(); @@ -296,7 +296,7 @@ impl Liveness { self.ranges.clear(); // Get ISA data structures used for computing live range affinities. - let recipe_constraints = isa.recipe_constraints(); + let enc_info = isa.encoding_info(); let reg_info = isa.register_info(); // The liveness computation needs to visit all uses, but the order doesn't matter. @@ -309,22 +309,20 @@ impl Liveness { // TODO: When we implement DCE, we can use the absence of a live range to indicate // an unused value. for def in func.dfg.inst_results(inst) { - get_or_create(&mut self.ranges, def, func, recipe_constraints); + get_or_create(&mut self.ranges, def, func, &enc_info); } - // The instruction encoding is used to compute affinities. - let recipe = func.encodings[inst].recipe(); // Iterator of constraints, one per value operand. // TODO: Should we fail here if the instruction doesn't have a valid encoding? - let mut operand_constraints = recipe_constraints - .get(recipe) + let mut operand_constraints = enc_info + .operand_constraints(func.encodings[inst]) .map(|c| c.ins) .unwrap_or(&[]) .iter(); for &arg in func.dfg.inst_args(inst) { // Get the live range, create it as a dead range if necessary. - let lr = get_or_create(&mut self.ranges, arg, func, recipe_constraints); + let lr = get_or_create(&mut self.ranges, arg, func, &enc_info); // Extend the live range to reach this use. extend_to_use(lr, ebb, inst, &mut self.worklist, func, cfg); diff --git a/lib/cretonne/src/write.rs b/lib/cretonne/src/write.rs index e2cd0fe3f5..7dfe743ead 100644 --- a/lib/cretonne/src/write.rs +++ b/lib/cretonne/src/write.rs @@ -184,7 +184,7 @@ fn write_instruction(w: &mut Write, if let Some(enc) = func.encodings.get(inst).cloned() { let mut s = String::with_capacity(16); if let Some(isa) = isa { - write!(s, "[{}", isa.display_enc(enc))?; + write!(s, "[{}", isa.encoding_info().display(enc))?; // Write value locations, if we have them. if !func.locations.is_empty() { let regs = isa.register_info(); diff --git a/lib/reader/src/parser.rs b/lib/reader/src/parser.rs index ca98bd98f2..1843c78776 100644 --- a/lib/reader/src/parser.rs +++ b/lib/reader/src/parser.rs @@ -108,7 +108,8 @@ impl<'a> Context<'a> { fn find_recipe_index(&self, recipe_name: &str) -> Option { if let Some(unique_isa) = self.unique_isa { unique_isa - .recipe_names() + .encoding_info() + .names .iter() .position(|&name| name == recipe_name) .map(|idx| idx as u16)