diff --git a/lib/cretonne/src/isa/arm32/mod.rs b/lib/cretonne/src/isa/arm32/mod.rs index 1e5cde38db..f9a44db258 100644 --- a/lib/cretonne/src/isa/arm32/mod.rs +++ b/lib/cretonne/src/isa/arm32/mod.rs @@ -10,7 +10,7 @@ use binemit::{CodeSink, MemoryCodeSink, emit_function}; use super::super::settings as shared_settings; use isa::enc_tables::{self as shared_enc_tables, lookup_enclist, Encodings}; use isa::Builder as IsaBuilder; -use isa::{TargetIsa, RegInfo, RegClass, EncInfo, Legalize}; +use isa::{TargetIsa, RegInfo, RegClass, EncInfo}; use ir; use regalloc; @@ -62,22 +62,19 @@ impl TargetIsa for Isa { } fn legal_encodings<'a>(&'a self, - _dfg: &'a ir::DataFlowGraph, + dfg: &'a ir::DataFlowGraph, inst: &'a ir::InstructionData, ctrl_typevar: ir::Type) - -> Result, Legalize> { + -> Encodings<'a> { lookup_enclist(ctrl_typevar, - inst.opcode(), + inst, + dfg, self.cpumode, - &enc_tables::LEVEL2[..]) - .and_then(|enclist_offset| { - Ok(Encodings::new(enclist_offset, - &enc_tables::ENCLISTS[..], - &enc_tables::RECIPE_PREDICATES[..], - &enc_tables::INST_PREDICATES[..], - inst, - self.isa_flags.predicate_view())) - }) + &enc_tables::LEVEL2[..], + &enc_tables::ENCLISTS[..], + &enc_tables::RECIPE_PREDICATES[..], + &enc_tables::INST_PREDICATES[..], + self.isa_flags.predicate_view()) } fn legalize_signature(&self, sig: &mut ir::Signature, current: bool) { diff --git a/lib/cretonne/src/isa/arm64/mod.rs b/lib/cretonne/src/isa/arm64/mod.rs index 4dd873e17b..f530d4b0b2 100644 --- a/lib/cretonne/src/isa/arm64/mod.rs +++ b/lib/cretonne/src/isa/arm64/mod.rs @@ -10,7 +10,7 @@ use binemit::{CodeSink, MemoryCodeSink, emit_function}; use super::super::settings as shared_settings; use isa::enc_tables::{lookup_enclist, Encodings}; use isa::Builder as IsaBuilder; -use isa::{TargetIsa, RegInfo, RegClass, EncInfo, Legalize}; +use isa::{TargetIsa, RegInfo, RegClass, EncInfo}; use ir; use regalloc; @@ -55,22 +55,19 @@ impl TargetIsa for Isa { } fn legal_encodings<'a>(&'a self, - _dfg: &'a ir::DataFlowGraph, + dfg: &'a ir::DataFlowGraph, inst: &'a ir::InstructionData, ctrl_typevar: ir::Type) - -> Result, Legalize> { + -> Encodings<'a> { lookup_enclist(ctrl_typevar, - inst.opcode(), + inst, + dfg, &enc_tables::LEVEL1_A64[..], - &enc_tables::LEVEL2[..]) - .and_then(|enclist_offset| { - Ok(Encodings::new(enclist_offset, - &enc_tables::ENCLISTS[..], - &enc_tables::RECIPE_PREDICATES[..], - &enc_tables::INST_PREDICATES[..], - inst, - self.isa_flags.predicate_view())) - }) + &enc_tables::LEVEL2[..], + &enc_tables::ENCLISTS[..], + &enc_tables::RECIPE_PREDICATES[..], + &enc_tables::INST_PREDICATES[..], + self.isa_flags.predicate_view()) } fn legalize_signature(&self, sig: &mut ir::Signature, current: bool) { diff --git a/lib/cretonne/src/isa/enc_tables.rs b/lib/cretonne/src/isa/enc_tables.rs index 95e79b2982..402bf8f06d 100644 --- a/lib/cretonne/src/isa/enc_tables.rs +++ b/lib/cretonne/src/isa/enc_tables.rs @@ -4,8 +4,8 @@ //! `lib/cretonne/meta/gen_encoding.py`. use constant_hash::{Table, probe}; -use ir::{Type, Opcode, InstructionData}; -use isa::{Encoding, Legalize}; +use ir::{Type, Opcode, DataFlowGraph, InstructionData}; +use isa::Encoding; use settings::PredicateView; use std::ops::Range; @@ -97,45 +97,59 @@ impl + Copy> Table for [Level2Entry] { } } -/// Two-level hash table lookup. +/// Two-level hash table lookup and iterator construction. /// /// Given the controlling type variable and instruction opcode, find the corresponding encoding /// list. /// -/// Returns an offset into the ISA's `ENCLIST` table, or `None` if the opcode/type combination is -/// not legal. -pub fn lookup_enclist(ctrl_typevar: Type, - opcode: Opcode, - level1_table: &[Level1Entry], - level2_table: &[Level2Entry]) - -> Result +/// Returns an iterator that produces legal encodings for `inst`. +pub fn lookup_enclist<'a, OffT1, OffT2>(ctrl_typevar: Type, + inst: &'a InstructionData, + _dfg: &'a DataFlowGraph, + level1_table: &'static [Level1Entry], + level2_table: &'static [Level2Entry], + enclist: &'static [EncListEntry], + recipe_preds: &'static [RecipePredicate], + inst_preds: &'static [InstPredicate], + isa_preds: PredicateView<'a>) + -> Encodings<'a> where OffT1: Into + Copy, OffT2: Into + Copy { - match probe(level1_table, ctrl_typevar, ctrl_typevar.index()) { + let (offset, legalize) = match probe(level1_table, ctrl_typevar, ctrl_typevar.index()) { Err(l1idx) => { // No level 1 entry found for the type. // We have a sentinel entry with the default legalization code. - let l1ent = &level1_table[l1idx]; - Err(l1ent.legalize.into()) + (!0, level1_table[l1idx].legalize) } Ok(l1idx) => { // We have a valid level 1 entry for this type. let l1ent = &level1_table[l1idx]; - match level2_table.get(l1ent.range()) { + let offset = match level2_table.get(l1ent.range()) { Some(l2tab) => { - probe(l2tab, opcode, opcode as usize) - .map(|l2idx| l2tab[l2idx].offset.into() as usize) - .map_err(|_| l1ent.legalize.into()) + let opcode = inst.opcode(); + match probe(l2tab, opcode, opcode as usize) { + Ok(l2idx) => l2tab[l2idx].offset.into() as usize, + Err(_) => !0, + } } - None => { - // The l1ent range is invalid. This means that we just have a customized - // legalization code for this type. The level 2 table is empty. - Err(l1ent.legalize.into()) - } - } + // The l1ent range is invalid. This means that we just have a customized + // legalization code for this type. The level 2 table is empty. + None => !0, + }; + (offset, l1ent.legalize) } - } + }; + + // Now we have an offset into `enclist` that is `!0` when no encoding list could be found. + // The default legalization code is always valid. + Encodings::new(offset, + legalize, + inst, + enclist, + recipe_preds, + inst_preds, + isa_preds) } /// Encoding list entry. @@ -153,11 +167,13 @@ const PRED_START: usize = 0x1000; pub struct Encodings<'a> { // Current offset into `enclist`, or out of bounds after we've reached the end. offset: usize, + // Legalization code to use of no encoding is found. + legalize: LegalizeCode, inst: &'a InstructionData, - isa_predicates: PredicateView<'a>, enclist: &'static [EncListEntry], - recipe_predicates: &'static [RecipePredicate], - inst_predicates: &'static [InstPredicate], + recipe_preds: &'static [RecipePredicate], + inst_preds: &'static [InstPredicate], + isa_preds: PredicateView<'a>, } impl<'a> Encodings<'a> { @@ -167,37 +183,49 @@ impl<'a> Encodings<'a> { /// encoding lists are laid out such that first call to `next` returns valid entry in the list /// or `None`. pub fn new(offset: usize, - enclist: &'static [EncListEntry], - recipe_predicates: &'static [RecipePredicate], - inst_predicates: &'static [InstPredicate], + legalize: LegalizeCode, inst: &'a InstructionData, - isa_predicates: PredicateView<'a>) + enclist: &'static [EncListEntry], + recipe_preds: &'static [RecipePredicate], + inst_preds: &'static [InstPredicate], + isa_preds: PredicateView<'a>) -> Self { Encodings { offset, - enclist, inst, - isa_predicates, - recipe_predicates, - inst_predicates, + legalize, + isa_preds, + recipe_preds, + inst_preds, + enclist, } } + /// Get the legalization action that caused the enumeration of encodings to stop. + /// This can be the default legalization action for the type or a custom code for the + /// instruction. + /// + /// This method must only be called after the iterator returns `None`. + pub fn legalize(&self) -> LegalizeCode { + debug_assert_eq!(self.offset, !0, "Premature Encodings::legalize()"); + self.legalize + } + /// Check if the `rpred` recipe predicate s satisfied. fn check_recipe(&self, rpred: RecipePredicate) -> bool { match rpred { - Some(p) => p(self.isa_predicates, self.inst), + Some(p) => p(self.isa_preds, self.inst), None => true, } } /// Check an instruction or isa predicate. fn check_pred(&self, pred: usize) -> bool { - if let Some(&p) = self.inst_predicates.get(pred) { + if let Some(&p) = self.inst_preds.get(pred) { p(self.inst) } else { - let pred = pred - self.inst_predicates.len(); - self.isa_predicates.test(pred) + let pred = pred - self.inst_preds.len(); + self.isa_preds.test(pred) } } } @@ -211,7 +239,7 @@ impl<'a> Iterator for Encodings<'a> { // Check for "recipe+bits". let recipe = entry >> 1; - if let Some(&rpred) = self.recipe_predicates.get(recipe) { + if let Some(&rpred) = self.recipe_preds.get(recipe) { let bits = self.offset + 1; if entry & 1 == 0 { self.offset += 2; // Next entry. @@ -226,7 +254,9 @@ impl<'a> Iterator for Encodings<'a> { // Check for "stop with legalize". if entry < PRED_START { - unimplemented!(); + self.legalize = (entry - 2 * self.recipe_preds.len()) as LegalizeCode; + self.offset = !0; // Stop. + return None; } // Finally, this must be a predicate entry. @@ -237,7 +267,8 @@ impl<'a> Iterator for Encodings<'a> { if self.check_pred(pred) { self.offset += 1; } else if skip == 0 { - self.offset = !0 // This means stop. + self.offset = !0; // Stop. + return None; } else { self.offset += 1 + skip; } diff --git a/lib/cretonne/src/isa/intel/mod.rs b/lib/cretonne/src/isa/intel/mod.rs index 85445ac701..9d31727b14 100644 --- a/lib/cretonne/src/isa/intel/mod.rs +++ b/lib/cretonne/src/isa/intel/mod.rs @@ -10,7 +10,7 @@ use binemit::{CodeSink, MemoryCodeSink, emit_function}; use super::super::settings as shared_settings; use isa::enc_tables::{self as shared_enc_tables, lookup_enclist, Encodings}; use isa::Builder as IsaBuilder; -use isa::{TargetIsa, RegInfo, RegClass, EncInfo, Legalize}; +use isa::{TargetIsa, RegInfo, RegClass, EncInfo}; use ir; use regalloc; @@ -62,22 +62,19 @@ impl TargetIsa for Isa { } fn legal_encodings<'a>(&'a self, - _dfg: &'a ir::DataFlowGraph, + dfg: &'a ir::DataFlowGraph, inst: &'a ir::InstructionData, ctrl_typevar: ir::Type) - -> Result, Legalize> { + -> Encodings<'a> { lookup_enclist(ctrl_typevar, - inst.opcode(), + inst, + dfg, self.cpumode, - &enc_tables::LEVEL2[..]) - .and_then(|enclist_offset| { - Ok(Encodings::new(enclist_offset, - &enc_tables::ENCLISTS[..], - &enc_tables::RECIPE_PREDICATES[..], - &enc_tables::INST_PREDICATES[..], - inst, - self.isa_flags.predicate_view())) - }) + &enc_tables::LEVEL2[..], + &enc_tables::ENCLISTS[..], + &enc_tables::RECIPE_PREDICATES[..], + &enc_tables::INST_PREDICATES[..], + self.isa_flags.predicate_view()) } fn legalize_signature(&self, sig: &mut ir::Signature, current: bool) { diff --git a/lib/cretonne/src/isa/mod.rs b/lib/cretonne/src/isa/mod.rs index 7b25aec8ec..6c43040825 100644 --- a/lib/cretonne/src/isa/mod.rs +++ b/lib/cretonne/src/isa/mod.rs @@ -156,7 +156,7 @@ pub trait TargetIsa { dfg: &'a ir::DataFlowGraph, inst: &'a ir::InstructionData, ctrl_typevar: ir::Type) - -> Result, Legalize>; + -> Encodings<'a>; /// Encode an instruction after determining it is legal. /// @@ -169,8 +169,8 @@ pub trait TargetIsa { inst: &ir::InstructionData, ctrl_typevar: ir::Type) -> Result { - self.legal_encodings(dfg, inst, ctrl_typevar) - .and_then(|mut iter| iter.next().ok_or(Legalize::Expand)) + let mut iter = self.legal_encodings(dfg, inst, ctrl_typevar); + iter.next().ok_or(iter.legalize().into()) } /// Get a data structure describing the instruction encodings in this ISA. diff --git a/lib/cretonne/src/isa/riscv/mod.rs b/lib/cretonne/src/isa/riscv/mod.rs index 3fe675b7a4..18f0172f86 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, MemoryCodeSink, emit_function}; use isa::enc_tables::{self as shared_enc_tables, lookup_enclist, Encodings}; use isa::Builder as IsaBuilder; -use isa::{TargetIsa, RegInfo, RegClass, EncInfo, Legalize}; +use isa::{TargetIsa, RegInfo, RegClass, EncInfo}; use ir; use regalloc; @@ -62,22 +62,19 @@ impl TargetIsa for Isa { } fn legal_encodings<'a>(&'a self, - _dfg: &'a ir::DataFlowGraph, + dfg: &'a ir::DataFlowGraph, inst: &'a ir::InstructionData, ctrl_typevar: ir::Type) - -> Result, Legalize> { + -> Encodings<'a> { lookup_enclist(ctrl_typevar, - inst.opcode(), + inst, + dfg, self.cpumode, - &enc_tables::LEVEL2[..]) - .and_then(|enclist_offset| { - Ok(Encodings::new(enclist_offset, - &enc_tables::ENCLISTS[..], - &enc_tables::RECIPE_PREDICATES[..], - &enc_tables::INST_PREDICATES[..], - inst, - self.isa_flags.predicate_view())) - }) + &enc_tables::LEVEL2[..], + &enc_tables::ENCLISTS[..], + &enc_tables::RECIPE_PREDICATES[..], + &enc_tables::INST_PREDICATES[..], + self.isa_flags.predicate_view()) } fn legalize_signature(&self, sig: &mut ir::Signature, current: bool) {