From f643e7e752cfccee2f2b9c55fa4169013b9eb151 Mon Sep 17 00:00:00 2001 From: Jakob Stoklund Olesen Date: Mon, 24 Jul 2017 14:13:35 -0700 Subject: [PATCH] Generate an INST_PREDICATES table for each ISA. Instead of generating a single `check_instp()` function, create an array of individual function pointers for checking instruction predicates. This makes explicit the jump table in the old check_instp() method and it gives us a way of determining the number of instruction predicates that exists. --- lib/cretonne/meta/gen_encoding.py | 43 ++++++++++-------------- lib/cretonne/src/isa/arm32/enc_tables.rs | 1 - lib/cretonne/src/isa/arm32/mod.rs | 2 +- lib/cretonne/src/isa/arm64/enc_tables.rs | 1 - lib/cretonne/src/isa/arm64/mod.rs | 2 +- lib/cretonne/src/isa/enc_tables.rs | 18 +++++++--- lib/cretonne/src/isa/intel/mod.rs | 2 +- lib/cretonne/src/isa/riscv/mod.rs | 2 +- 8 files changed, 35 insertions(+), 36 deletions(-) diff --git a/lib/cretonne/meta/gen_encoding.py b/lib/cretonne/meta/gen_encoding.py index 5f49cb42c6..43f02d6416 100644 --- a/lib/cretonne/meta/gen_encoding.py +++ b/lib/cretonne/meta/gen_encoding.py @@ -101,36 +101,27 @@ def emit_instp(instp, fmt): fmt.line('return {};'.format(instp.rust_predicate(0))) -def emit_instps(instps, fmt): +def emit_inst_predicates(instps, fmt): # type: (Sequence[PredNode], srcgen.Formatter) -> None """ - Emit a function for matching instruction predicates. + Emit private functions for matching instruction predicates as well as a + static `INST_PREDICATES` array indexed by predicate number. """ - - if not instps: - # If the ISA has no predicates, just emit a stub. + for instp in instps: + name = 'inst_predicate_{}'.format(instp.number) with fmt.indented( - 'pub fn check_instp(_: &InstructionData, _: u16) ' + - '-> bool {', '}'): - fmt.line('unimplemented!()') - return + 'fn {}(inst: &InstructionData) -> bool {{' + .format(name), + '}'): + emit_instp(instp, fmt) + fmt.line('unreachable!();') + # Generate the static table. with fmt.indented( - 'pub fn check_instp(inst: &InstructionData, instp_idx: u16) ' + - '-> bool {', '}'): - # The matches emitted by `emit_instp` need this. - fmt.line('use ir::instructions::InstructionFormat;') - with fmt.indented('match instp_idx {', '}'): - for instp in instps: - with fmt.indented('{} => {{'.format(instp.number), '}'): - emit_instp(instp, fmt) - fmt.line('_ => panic!("Invalid instruction predicate")') - - # The match cases will fall through if the instruction format is wrong. - fmt.line('panic!("Bad format {:?}/{} for instp {}",') - fmt.line(' InstructionFormat::from(inst),') - fmt.line(' inst.opcode(),') - fmt.line(' instp_idx);') + 'pub static INST_PREDICATES: [InstPredicate; {}] = [' + .format(len(instps)), '];'): + for instp in instps: + fmt.format('inst_predicate_{},', instp.number) def emit_recipe_predicates(recipes, fmt): @@ -658,8 +649,8 @@ def gen_isa(isa, fmt): # Make the `RECIPE_PREDICATES` table. emit_recipe_predicates(isa.all_recipes, fmt) - # Generate the check_instp() function.. - emit_instps(isa.all_instps, fmt) + # Make the `INST_PREDICATES` table. + emit_inst_predicates(isa.all_instps, fmt) # Level1 tables, one per CPU mode level1_tables = dict() diff --git a/lib/cretonne/src/isa/arm32/enc_tables.rs b/lib/cretonne/src/isa/arm32/enc_tables.rs index e33d47f12d..adcc2fd915 100644 --- a/lib/cretonne/src/isa/arm32/enc_tables.rs +++ b/lib/cretonne/src/isa/arm32/enc_tables.rs @@ -1,6 +1,5 @@ //! Encoding tables for ARM32 ISA. -use ir::InstructionData; use ir::types; use isa::EncInfo; use isa::constraints::*; diff --git a/lib/cretonne/src/isa/arm32/mod.rs b/lib/cretonne/src/isa/arm32/mod.rs index 06852e4ad2..1e5cde38db 100644 --- a/lib/cretonne/src/isa/arm32/mod.rs +++ b/lib/cretonne/src/isa/arm32/mod.rs @@ -74,8 +74,8 @@ impl TargetIsa for Isa { Ok(Encodings::new(enclist_offset, &enc_tables::ENCLISTS[..], &enc_tables::RECIPE_PREDICATES[..], + &enc_tables::INST_PREDICATES[..], inst, - enc_tables::check_instp, self.isa_flags.predicate_view())) }) } diff --git a/lib/cretonne/src/isa/arm64/enc_tables.rs b/lib/cretonne/src/isa/arm64/enc_tables.rs index 889a5a7dbe..e57f3cc98c 100644 --- a/lib/cretonne/src/isa/arm64/enc_tables.rs +++ b/lib/cretonne/src/isa/arm64/enc_tables.rs @@ -1,6 +1,5 @@ //! Encoding tables for ARM64 ISA. -use ir::InstructionData; use ir::types; use isa::EncInfo; use isa::constraints::*; diff --git a/lib/cretonne/src/isa/arm64/mod.rs b/lib/cretonne/src/isa/arm64/mod.rs index 26e4ea9dfe..4dd873e17b 100644 --- a/lib/cretonne/src/isa/arm64/mod.rs +++ b/lib/cretonne/src/isa/arm64/mod.rs @@ -67,8 +67,8 @@ impl TargetIsa for Isa { Ok(Encodings::new(enclist_offset, &enc_tables::ENCLISTS[..], &enc_tables::RECIPE_PREDICATES[..], + &enc_tables::INST_PREDICATES[..], inst, - enc_tables::check_instp, self.isa_flags.predicate_view())) }) } diff --git a/lib/cretonne/src/isa/enc_tables.rs b/lib/cretonne/src/isa/enc_tables.rs index 843cbf6a1d..d040dd9ca4 100644 --- a/lib/cretonne/src/isa/enc_tables.rs +++ b/lib/cretonne/src/isa/enc_tables.rs @@ -16,6 +16,12 @@ use std::ops::Range; /// A None predicate is always satisfied. pub type RecipePredicate = Option bool>; +/// An instruction predicate. +/// +/// This is a predicate function that needs to be tested in addition to the recipe predicate. It +/// can't depend on ISA settings. +pub type InstPredicate = fn(&InstructionData) -> bool; + /// Legalization action to perform when no encoding can be found for an instruction. /// /// This is an index into an ISA-specific table of legalization actions. @@ -152,9 +158,9 @@ pub struct Encodings<'a> { offset: usize, enclist: &'static [EncListEntry], inst: &'a InstructionData, - instp: fn(&InstructionData, EncListEntry) -> bool, isa_predicates: PredicateView<'a>, recipe_predicates: &'static [RecipePredicate], + inst_predicates: &'static [InstPredicate], } impl<'a> Encodings<'a> { @@ -176,17 +182,17 @@ impl<'a> Encodings<'a> { pub fn new(offset: usize, enclist: &'static [EncListEntry], recipe_predicates: &'static [RecipePredicate], + inst_predicates: &'static [InstPredicate], inst: &'a InstructionData, - instp: fn(&InstructionData, EncListEntry) -> bool, isa_predicates: PredicateView<'a>) -> Self { Encodings { offset, enclist, inst, - instp, isa_predicates, recipe_predicates, + inst_predicates, } } @@ -208,7 +214,11 @@ impl<'a> Iterator for Encodings<'a> { if pred <= CODE_ALWAYS { // This is an instruction predicate followed by recipe and encbits entries. self.offset += 3; - if pred == CODE_ALWAYS || (self.instp)(self.inst, pred) { + let satisfied = match self.inst_predicates.get(pred as usize) { + Some(p) => p(self.inst), + None => true, + }; + if satisfied { let recipe = self.enclist[self.offset - 2]; if self.check_recipe(recipe) { let encoding = Encoding::new(recipe, self.enclist[self.offset - 1]); diff --git a/lib/cretonne/src/isa/intel/mod.rs b/lib/cretonne/src/isa/intel/mod.rs index c459b49bd7..85445ac701 100644 --- a/lib/cretonne/src/isa/intel/mod.rs +++ b/lib/cretonne/src/isa/intel/mod.rs @@ -74,8 +74,8 @@ impl TargetIsa for Isa { Ok(Encodings::new(enclist_offset, &enc_tables::ENCLISTS[..], &enc_tables::RECIPE_PREDICATES[..], + &enc_tables::INST_PREDICATES[..], inst, - enc_tables::check_instp, self.isa_flags.predicate_view())) }) } diff --git a/lib/cretonne/src/isa/riscv/mod.rs b/lib/cretonne/src/isa/riscv/mod.rs index d09bfbd028..3fe675b7a4 100644 --- a/lib/cretonne/src/isa/riscv/mod.rs +++ b/lib/cretonne/src/isa/riscv/mod.rs @@ -74,8 +74,8 @@ impl TargetIsa for Isa { Ok(Encodings::new(enclist_offset, &enc_tables::ENCLISTS[..], &enc_tables::RECIPE_PREDICATES[..], + &enc_tables::INST_PREDICATES[..], inst, - enc_tables::check_instp, self.isa_flags.predicate_view())) }) }