From 1a480a257836e96b8ee2adcd9e335466b5cd7913 Mon Sep 17 00:00:00 2001 From: Aleksey Kuznetsov Date: Mon, 19 Jun 2017 20:52:19 +0500 Subject: [PATCH] Implement an iterator over encodings (#96) * Implement an iterator over encodings * Implement TargetIsa::legal_encodings * Exclude non-boolean settings of isa flags bytes * Address flake8 long line error --- lib/cretonne/meta/gen_settings.py | 4 ++ lib/cretonne/src/isa/arm32/mod.rs | 26 +++---- lib/cretonne/src/isa/arm64/mod.rs | 26 +++---- lib/cretonne/src/isa/enc_tables.rs | 108 +++++++++++++++++++---------- lib/cretonne/src/isa/intel/mod.rs | 26 +++---- lib/cretonne/src/isa/mod.rs | 15 +++- lib/cretonne/src/isa/riscv/mod.rs | 26 +++---- 7 files changed, 139 insertions(+), 92 deletions(-) diff --git a/lib/cretonne/meta/gen_settings.py b/lib/cretonne/meta/gen_settings.py index 23e9a5c7a9..ae16b337c0 100644 --- a/lib/cretonne/meta/gen_settings.py +++ b/lib/cretonne/meta/gen_settings.py @@ -87,6 +87,10 @@ def gen_getters(sgrp, fmt): """ fmt.doc_comment("User-defined settings.") with fmt.indented('impl Flags {', '}'): + fmt.doc_comment('Returns inner slice of bytes.') + fmt.doc_comment('The byte-sized settings are not included.') + with fmt.indented('pub fn predicate_bytes(&self) -> &[u8] {', '}'): + fmt.line('&self.bytes[{}..]'.format(sgrp.boolean_offset)) fmt.doc_comment('Dynamic numbered predicate getter.') with fmt.indented( 'pub fn numbered_predicate(&self, p: usize) -> bool {', '}'): diff --git a/lib/cretonne/src/isa/arm32/mod.rs b/lib/cretonne/src/isa/arm32/mod.rs index 5657c7523b..d986b9e0e2 100644 --- a/lib/cretonne/src/isa/arm32/mod.rs +++ b/lib/cretonne/src/isa/arm32/mod.rs @@ -8,9 +8,9 @@ mod registers; 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::enc_tables::{self as shared_enc_tables, lookup_enclist, Encodings}; use isa::Builder as IsaBuilder; -use isa::{TargetIsa, RegInfo, RegClass, EncInfo, Encoding, Legalize}; +use isa::{TargetIsa, RegInfo, RegClass, EncInfo, Legalize}; use ir; use regalloc; @@ -61,22 +61,22 @@ impl TargetIsa for Isa { enc_tables::INFO.clone() } - fn encode(&self, - _dfg: &ir::DataFlowGraph, - inst: &ir::InstructionData, - ctrl_typevar: ir::Type) - -> Result { + fn legal_encodings<'a, 'b>(&'a self, + _dfg: &'b ir::DataFlowGraph, + inst: &'b ir::InstructionData, + ctrl_typevar: ir::Type) + -> Result, Legalize> { lookup_enclist(ctrl_typevar, inst.opcode(), self.cpumode, &enc_tables::LEVEL2[..]) .and_then(|enclist_offset| { - general_encoding(enclist_offset, - &enc_tables::ENCLISTS[..], - |instp| enc_tables::check_instp(inst, instp), - |isap| self.isa_flags.numbered_predicate(isap as usize)) - .ok_or(Legalize::Expand) - }) + Ok(Encodings::new(enclist_offset, + &enc_tables::ENCLISTS[..], + inst, + enc_tables::check_instp, + self.isa_flags.predicate_bytes())) + }) } 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 fe81ea8c09..c8c2de3cf8 100644 --- a/lib/cretonne/src/isa/arm64/mod.rs +++ b/lib/cretonne/src/isa/arm64/mod.rs @@ -8,9 +8,9 @@ mod registers; use binemit::CodeSink; use super::super::settings as shared_settings; -use isa::enc_tables::{lookup_enclist, general_encoding}; +use isa::enc_tables::{lookup_enclist, Encodings}; use isa::Builder as IsaBuilder; -use isa::{TargetIsa, RegInfo, RegClass, EncInfo, Encoding, Legalize}; +use isa::{TargetIsa, RegInfo, RegClass, EncInfo, Legalize}; use ir; use regalloc; @@ -54,22 +54,22 @@ impl TargetIsa for Isa { enc_tables::INFO.clone() } - fn encode(&self, - _dfg: &ir::DataFlowGraph, - inst: &ir::InstructionData, - ctrl_typevar: ir::Type) - -> Result { + fn legal_encodings<'a, 'b>(&'a self, + _dfg: &'b ir::DataFlowGraph, + inst: &'b ir::InstructionData, + ctrl_typevar: ir::Type) + -> Result, Legalize> { lookup_enclist(ctrl_typevar, inst.opcode(), &enc_tables::LEVEL1_A64[..], &enc_tables::LEVEL2[..]) .and_then(|enclist_offset| { - general_encoding(enclist_offset, - &enc_tables::ENCLISTS[..], - |instp| enc_tables::check_instp(inst, instp), - |isap| self.isa_flags.numbered_predicate(isap as usize)) - .ok_or(Legalize::Expand) - }) + Ok(Encodings::new(enclist_offset, + &enc_tables::ENCLISTS[..], + inst, + enc_tables::check_instp, + self.isa_flags.predicate_bytes())) + }) } 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 d7dde71eed..3467a2bdfd 100644 --- a/lib/cretonne/src/isa/enc_tables.rs +++ b/lib/cretonne/src/isa/enc_tables.rs @@ -2,7 +2,7 @@ //! //! This module contains types and functions for working with the encoding tables generated by //! `lib/cretonne/meta/gen_encoding.py`. -use ir::{Type, Opcode}; +use ir::{Type, Opcode, InstructionData}; use isa::{Encoding, Legalize}; use constant_hash::{Table, probe}; @@ -114,43 +114,75 @@ const CODE_ALWAYS: EncListEntry = PRED_MASK; /// The encoding list terminator. const CODE_FAIL: EncListEntry = 0xffff; -/// Find the first applicable general encoding of `inst`. -/// -/// Given an encoding list offset as returned by `lookup_enclist` above, search the encoding list -/// for the most first encoding that applies to `inst`. The encoding lists are laid out such that -/// this is the first valid entry in the list. -/// -/// This function takes two closures that are used to evaluate predicates: -/// - `instp` is passed an instruction predicate number to be evaluated on the current instruction. -/// - `isap` is passed an ISA predicate number to evaluate. -/// -/// Returns the corresponding encoding, or `None` if no list entries are satisfied by `inst`. -pub fn general_encoding(offset: usize, - enclist: &[EncListEntry], - instp: InstP, - isap: IsaP) - -> Option - where InstP: Fn(EncListEntry) -> bool, - IsaP: Fn(EncListEntry) -> bool -{ - let mut pos = offset; - while enclist[pos] != CODE_FAIL { - let pred = enclist[pos]; - if pred <= CODE_ALWAYS { - // This is an instruction predicate followed by recipe and encbits entries. - if pred == CODE_ALWAYS || instp(pred) { - return Some(Encoding::new(enclist[pos + 1], enclist[pos + 2])); - } - pos += 3; - } else { - // This is an ISA predicate entry. - pos += 1; - if !isap(pred & PRED_MASK) { - // ISA predicate failed, skip the next N entries. - pos += 3 * (pred >> PRED_BITS) as usize; - } +/// An iterator over legal encodings for the instruction. +pub struct Encodings<'a, 'b> { + offset: usize, + enclist: &'b [EncListEntry], + inst: &'b InstructionData, + instp: fn(&InstructionData, EncListEntry) -> bool, + isa_predicate_bytes: &'a [u8], +} + +impl<'a, 'b> Encodings<'a, 'b> { + /// Creates a new instance of `Encodings`. + /// + /// # Parameters + /// + /// - `offset` an offset into encoding list returned by `lookup_enclist` function. + /// - `inst` the current instruction. + /// - `enclist` a list of encoding entries. + /// - `instp` an instruction predicate number to be evaluated on the current instruction. + /// - `isa_predicate_bytes` an ISA flags as a slice of bytes to evaluate an ISA predicate number + /// on the current instruction. + /// + /// This iterator provides search for encodings that applies to the given instruction. The + /// 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: &'b [EncListEntry], + inst: &'b InstructionData, + instp: fn(&InstructionData, EncListEntry) -> bool, + isa_predicate_bytes: &'a [u8]) + -> Self { + Encodings { + offset, + enclist, + inst, + instp, + isa_predicate_bytes, } } - - None +} + +impl<'a, 'b> Iterator for Encodings<'a, 'b> { + type Item = Encoding; + + fn next(&mut self) -> Option { + fn numbered_predicate(bytes: &[u8], p: usize) -> bool { + bytes[p / 8] & (1 << (p % 8)) != 0 + } + + while self.enclist[self.offset] != CODE_FAIL { + let pred = self.enclist[self.offset]; + if pred <= CODE_ALWAYS { + // This is an instruction predicate followed by recipe and encbits entries. + if pred == CODE_ALWAYS || (self.instp)(self.inst, pred) { + let encoding = Encoding::new(self.enclist[self.offset + 1], + self.enclist[self.offset + 2]); + self.offset += 3; + return Some(encoding); + } else { + self.offset += 3; + } + } else { + // This is an ISA predicate entry. + self.offset += 1; + if !numbered_predicate(self.isa_predicate_bytes, (pred & PRED_MASK) as usize) { + // ISA predicate failed, skip the next N entries. + self.offset += 3 * (pred >> PRED_BITS) as usize; + } + } + } + None + } } diff --git a/lib/cretonne/src/isa/intel/mod.rs b/lib/cretonne/src/isa/intel/mod.rs index 1711be3166..6cfd0b4b85 100644 --- a/lib/cretonne/src/isa/intel/mod.rs +++ b/lib/cretonne/src/isa/intel/mod.rs @@ -8,9 +8,9 @@ mod registers; 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::enc_tables::{self as shared_enc_tables, lookup_enclist, Encodings}; use isa::Builder as IsaBuilder; -use isa::{TargetIsa, RegInfo, RegClass, EncInfo, Encoding, Legalize}; +use isa::{TargetIsa, RegInfo, RegClass, EncInfo, Legalize}; use ir; use regalloc; @@ -61,22 +61,22 @@ impl TargetIsa for Isa { enc_tables::INFO.clone() } - fn encode(&self, - _dfg: &ir::DataFlowGraph, - inst: &ir::InstructionData, - ctrl_typevar: ir::Type) - -> Result { + fn legal_encodings<'a, 'b>(&'a self, + _dfg: &'b ir::DataFlowGraph, + inst: &'b ir::InstructionData, + ctrl_typevar: ir::Type) + -> Result, Legalize> { lookup_enclist(ctrl_typevar, inst.opcode(), self.cpumode, &enc_tables::LEVEL2[..]) .and_then(|enclist_offset| { - general_encoding(enclist_offset, - &enc_tables::ENCLISTS[..], - |instp| enc_tables::check_instp(inst, instp), - |isap| self.isa_flags.numbered_predicate(isap as usize)) - .ok_or(Legalize::Expand) - }) + Ok(Encodings::new(enclist_offset, + &enc_tables::ENCLISTS[..], + inst, + enc_tables::check_instp, + self.isa_flags.predicate_bytes())) + }) } 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 edc0034217..1ec80e790c 100644 --- a/lib/cretonne/src/isa/mod.rs +++ b/lib/cretonne/src/isa/mod.rs @@ -48,6 +48,7 @@ use binemit::CodeSink; use settings; use ir; use regalloc; +use isa::enc_tables::Encodings; pub mod riscv; pub mod intel; @@ -136,17 +137,27 @@ pub trait TargetIsa { /// Get a data structure describing the registers in this ISA. fn register_info(&self) -> RegInfo; + /// Returns an iterartor over legal encodings for the instruction. + fn legal_encodings<'a, 'b>(&'a self, + dfg: &'b ir::DataFlowGraph, + inst: &'b ir::InstructionData, + ctrl_typevar: ir::Type) + -> Result, Legalize>; + /// Encode an instruction after determining it is legal. /// /// If `inst` can legally be encoded in this ISA, produce the corresponding `Encoding` object. - /// Otherwise, return `None`. + /// Otherwise, return `Legalize` action. /// /// This is also the main entry point for determining if an instruction is legal. fn encode(&self, dfg: &ir::DataFlowGraph, inst: &ir::InstructionData, ctrl_typevar: ir::Type) - -> Result; + -> Result { + self.legal_encodings(dfg, inst, ctrl_typevar) + .and_then(|mut iter| iter.next().ok_or(Legalize::Expand)) + } /// Get a data structure describing the instruction encodings in this ISA. fn encoding_info(&self) -> EncInfo; diff --git a/lib/cretonne/src/isa/riscv/mod.rs b/lib/cretonne/src/isa/riscv/mod.rs index ad64e4fd29..5f9cd771a2 100644 --- a/lib/cretonne/src/isa/riscv/mod.rs +++ b/lib/cretonne/src/isa/riscv/mod.rs @@ -8,9 +8,9 @@ mod registers; 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::enc_tables::{self as shared_enc_tables, lookup_enclist, Encodings}; use isa::Builder as IsaBuilder; -use isa::{TargetIsa, RegInfo, RegClass, EncInfo, Encoding, Legalize}; +use isa::{TargetIsa, RegInfo, RegClass, EncInfo, Legalize}; use ir; use regalloc; @@ -61,22 +61,22 @@ impl TargetIsa for Isa { enc_tables::INFO.clone() } - fn encode(&self, - _dfg: &ir::DataFlowGraph, - inst: &ir::InstructionData, - ctrl_typevar: ir::Type) - -> Result { + fn legal_encodings<'a, 'b>(&'a self, + _dfg: &'b ir::DataFlowGraph, + inst: &'b ir::InstructionData, + ctrl_typevar: ir::Type) + -> Result, Legalize> { lookup_enclist(ctrl_typevar, inst.opcode(), self.cpumode, &enc_tables::LEVEL2[..]) .and_then(|enclist_offset| { - general_encoding(enclist_offset, - &enc_tables::ENCLISTS[..], - |instp| enc_tables::check_instp(inst, instp), - |isap| self.isa_flags.numbered_predicate(isap as usize)) - .ok_or(Legalize::Expand) - }) + Ok(Encodings::new(enclist_offset, + &enc_tables::ENCLISTS[..], + inst, + enc_tables::check_instp, + self.isa_flags.predicate_bytes())) + }) } fn legalize_signature(&self, sig: &mut ir::Signature, current: bool) {