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
This commit is contained in:
Aleksey Kuznetsov
2017-06-19 20:52:19 +05:00
committed by Jakob Stoklund Olesen
parent 342121aba0
commit 1a480a2578
7 changed files with 139 additions and 92 deletions

View File

@@ -87,6 +87,10 @@ def gen_getters(sgrp, fmt):
""" """
fmt.doc_comment("User-defined settings.") fmt.doc_comment("User-defined settings.")
with fmt.indented('impl Flags {', '}'): 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.') fmt.doc_comment('Dynamic numbered predicate getter.')
with fmt.indented( with fmt.indented(
'pub fn numbered_predicate(&self, p: usize) -> bool {', '}'): 'pub fn numbered_predicate(&self, p: usize) -> bool {', '}'):

View File

@@ -8,9 +8,9 @@ mod registers;
use binemit::CodeSink; use binemit::CodeSink;
use super::super::settings as shared_settings; 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::Builder as IsaBuilder;
use isa::{TargetIsa, RegInfo, RegClass, EncInfo, Encoding, Legalize}; use isa::{TargetIsa, RegInfo, RegClass, EncInfo, Legalize};
use ir; use ir;
use regalloc; use regalloc;
@@ -61,21 +61,21 @@ impl TargetIsa for Isa {
enc_tables::INFO.clone() enc_tables::INFO.clone()
} }
fn encode(&self, fn legal_encodings<'a, 'b>(&'a self,
_dfg: &ir::DataFlowGraph, _dfg: &'b ir::DataFlowGraph,
inst: &ir::InstructionData, inst: &'b ir::InstructionData,
ctrl_typevar: ir::Type) ctrl_typevar: ir::Type)
-> Result<Encoding, Legalize> { -> Result<Encodings<'a, 'b>, Legalize> {
lookup_enclist(ctrl_typevar, lookup_enclist(ctrl_typevar,
inst.opcode(), inst.opcode(),
self.cpumode, self.cpumode,
&enc_tables::LEVEL2[..]) &enc_tables::LEVEL2[..])
.and_then(|enclist_offset| { .and_then(|enclist_offset| {
general_encoding(enclist_offset, Ok(Encodings::new(enclist_offset,
&enc_tables::ENCLISTS[..], &enc_tables::ENCLISTS[..],
|instp| enc_tables::check_instp(inst, instp), inst,
|isap| self.isa_flags.numbered_predicate(isap as usize)) enc_tables::check_instp,
.ok_or(Legalize::Expand) self.isa_flags.predicate_bytes()))
}) })
} }

View File

@@ -8,9 +8,9 @@ mod registers;
use binemit::CodeSink; use binemit::CodeSink;
use super::super::settings as shared_settings; 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::Builder as IsaBuilder;
use isa::{TargetIsa, RegInfo, RegClass, EncInfo, Encoding, Legalize}; use isa::{TargetIsa, RegInfo, RegClass, EncInfo, Legalize};
use ir; use ir;
use regalloc; use regalloc;
@@ -54,21 +54,21 @@ impl TargetIsa for Isa {
enc_tables::INFO.clone() enc_tables::INFO.clone()
} }
fn encode(&self, fn legal_encodings<'a, 'b>(&'a self,
_dfg: &ir::DataFlowGraph, _dfg: &'b ir::DataFlowGraph,
inst: &ir::InstructionData, inst: &'b ir::InstructionData,
ctrl_typevar: ir::Type) ctrl_typevar: ir::Type)
-> Result<Encoding, Legalize> { -> Result<Encodings<'a, 'b>, Legalize> {
lookup_enclist(ctrl_typevar, lookup_enclist(ctrl_typevar,
inst.opcode(), inst.opcode(),
&enc_tables::LEVEL1_A64[..], &enc_tables::LEVEL1_A64[..],
&enc_tables::LEVEL2[..]) &enc_tables::LEVEL2[..])
.and_then(|enclist_offset| { .and_then(|enclist_offset| {
general_encoding(enclist_offset, Ok(Encodings::new(enclist_offset,
&enc_tables::ENCLISTS[..], &enc_tables::ENCLISTS[..],
|instp| enc_tables::check_instp(inst, instp), inst,
|isap| self.isa_flags.numbered_predicate(isap as usize)) enc_tables::check_instp,
.ok_or(Legalize::Expand) self.isa_flags.predicate_bytes()))
}) })
} }

View File

@@ -2,7 +2,7 @@
//! //!
//! This module contains types and functions for working with the encoding tables generated by //! This module contains types and functions for working with the encoding tables generated by
//! `lib/cretonne/meta/gen_encoding.py`. //! `lib/cretonne/meta/gen_encoding.py`.
use ir::{Type, Opcode}; use ir::{Type, Opcode, InstructionData};
use isa::{Encoding, Legalize}; use isa::{Encoding, Legalize};
use constant_hash::{Table, probe}; use constant_hash::{Table, probe};
@@ -114,43 +114,75 @@ const CODE_ALWAYS: EncListEntry = PRED_MASK;
/// The encoding list terminator. /// The encoding list terminator.
const CODE_FAIL: EncListEntry = 0xffff; const CODE_FAIL: EncListEntry = 0xffff;
/// Find the first applicable general encoding of `inst`. /// An iterator over legal encodings for the instruction.
/// pub struct Encodings<'a, 'b> {
/// Given an encoding list offset as returned by `lookup_enclist` above, search the encoding list offset: usize,
/// for the most first encoding that applies to `inst`. The encoding lists are laid out such that enclist: &'b [EncListEntry],
/// this is the first valid entry in the list. inst: &'b InstructionData,
/// instp: fn(&InstructionData, EncListEntry) -> bool,
/// This function takes two closures that are used to evaluate predicates: isa_predicate_bytes: &'a [u8],
/// - `instp` is passed an instruction predicate number to be evaluated on the current instruction. }
/// - `isap` is passed an ISA predicate number to evaluate.
/// impl<'a, 'b> Encodings<'a, 'b> {
/// Returns the corresponding encoding, or `None` if no list entries are satisfied by `inst`. /// Creates a new instance of `Encodings`.
pub fn general_encoding<InstP, IsaP>(offset: usize, ///
enclist: &[EncListEntry], /// # Parameters
instp: InstP, ///
isap: IsaP) /// - `offset` an offset into encoding list returned by `lookup_enclist` function.
-> Option<Encoding> /// - `inst` the current instruction.
where InstP: Fn(EncListEntry) -> bool, /// - `enclist` a list of encoding entries.
IsaP: Fn(EncListEntry) -> bool /// - `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
let mut pos = offset; /// on the current instruction.
while enclist[pos] != CODE_FAIL { ///
let pred = enclist[pos]; /// This iterator provides search for encodings that applies to the given instruction. The
if pred <= CODE_ALWAYS { /// encoding lists are laid out such that first call to `next` returns valid entry in the list
// This is an instruction predicate followed by recipe and encbits entries. /// or `None`.
if pred == CODE_ALWAYS || instp(pred) { pub fn new(offset: usize,
return Some(Encoding::new(enclist[pos + 1], enclist[pos + 2])); enclist: &'b [EncListEntry],
} inst: &'b InstructionData,
pos += 3; instp: fn(&InstructionData, EncListEntry) -> bool,
} else { isa_predicate_bytes: &'a [u8])
// This is an ISA predicate entry. -> Self {
pos += 1; Encodings {
if !isap(pred & PRED_MASK) { offset,
// ISA predicate failed, skip the next N entries. enclist,
pos += 3 * (pred >> PRED_BITS) as usize; inst,
instp,
isa_predicate_bytes,
} }
} }
}
impl<'a, 'b> Iterator for Encodings<'a, 'b> {
type Item = Encoding;
fn next(&mut self) -> Option<Encoding> {
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 None
}
} }

View File

@@ -8,9 +8,9 @@ mod registers;
use binemit::CodeSink; use binemit::CodeSink;
use super::super::settings as shared_settings; 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::Builder as IsaBuilder;
use isa::{TargetIsa, RegInfo, RegClass, EncInfo, Encoding, Legalize}; use isa::{TargetIsa, RegInfo, RegClass, EncInfo, Legalize};
use ir; use ir;
use regalloc; use regalloc;
@@ -61,21 +61,21 @@ impl TargetIsa for Isa {
enc_tables::INFO.clone() enc_tables::INFO.clone()
} }
fn encode(&self, fn legal_encodings<'a, 'b>(&'a self,
_dfg: &ir::DataFlowGraph, _dfg: &'b ir::DataFlowGraph,
inst: &ir::InstructionData, inst: &'b ir::InstructionData,
ctrl_typevar: ir::Type) ctrl_typevar: ir::Type)
-> Result<Encoding, Legalize> { -> Result<Encodings<'a, 'b>, Legalize> {
lookup_enclist(ctrl_typevar, lookup_enclist(ctrl_typevar,
inst.opcode(), inst.opcode(),
self.cpumode, self.cpumode,
&enc_tables::LEVEL2[..]) &enc_tables::LEVEL2[..])
.and_then(|enclist_offset| { .and_then(|enclist_offset| {
general_encoding(enclist_offset, Ok(Encodings::new(enclist_offset,
&enc_tables::ENCLISTS[..], &enc_tables::ENCLISTS[..],
|instp| enc_tables::check_instp(inst, instp), inst,
|isap| self.isa_flags.numbered_predicate(isap as usize)) enc_tables::check_instp,
.ok_or(Legalize::Expand) self.isa_flags.predicate_bytes()))
}) })
} }

View File

@@ -48,6 +48,7 @@ use binemit::CodeSink;
use settings; use settings;
use ir; use ir;
use regalloc; use regalloc;
use isa::enc_tables::Encodings;
pub mod riscv; pub mod riscv;
pub mod intel; pub mod intel;
@@ -136,17 +137,27 @@ pub trait TargetIsa {
/// Get a data structure describing the registers in this ISA. /// Get a data structure describing the registers in this ISA.
fn register_info(&self) -> RegInfo; 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<Encodings<'a, 'b>, Legalize>;
/// Encode an instruction after determining it is legal. /// Encode an instruction after determining it is legal.
/// ///
/// If `inst` can legally be encoded in this ISA, produce the corresponding `Encoding` object. /// 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. /// This is also the main entry point for determining if an instruction is legal.
fn encode(&self, fn encode(&self,
dfg: &ir::DataFlowGraph, dfg: &ir::DataFlowGraph,
inst: &ir::InstructionData, inst: &ir::InstructionData,
ctrl_typevar: ir::Type) ctrl_typevar: ir::Type)
-> Result<Encoding, Legalize>; -> Result<Encoding, Legalize> {
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. /// Get a data structure describing the instruction encodings in this ISA.
fn encoding_info(&self) -> EncInfo; fn encoding_info(&self) -> EncInfo;

View File

@@ -8,9 +8,9 @@ mod registers;
use super::super::settings as shared_settings; use super::super::settings as shared_settings;
use binemit::CodeSink; 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::Builder as IsaBuilder;
use isa::{TargetIsa, RegInfo, RegClass, EncInfo, Encoding, Legalize}; use isa::{TargetIsa, RegInfo, RegClass, EncInfo, Legalize};
use ir; use ir;
use regalloc; use regalloc;
@@ -61,21 +61,21 @@ impl TargetIsa for Isa {
enc_tables::INFO.clone() enc_tables::INFO.clone()
} }
fn encode(&self, fn legal_encodings<'a, 'b>(&'a self,
_dfg: &ir::DataFlowGraph, _dfg: &'b ir::DataFlowGraph,
inst: &ir::InstructionData, inst: &'b ir::InstructionData,
ctrl_typevar: ir::Type) ctrl_typevar: ir::Type)
-> Result<Encoding, Legalize> { -> Result<Encodings<'a, 'b>, Legalize> {
lookup_enclist(ctrl_typevar, lookup_enclist(ctrl_typevar,
inst.opcode(), inst.opcode(),
self.cpumode, self.cpumode,
&enc_tables::LEVEL2[..]) &enc_tables::LEVEL2[..])
.and_then(|enclist_offset| { .and_then(|enclist_offset| {
general_encoding(enclist_offset, Ok(Encodings::new(enclist_offset,
&enc_tables::ENCLISTS[..], &enc_tables::ENCLISTS[..],
|instp| enc_tables::check_instp(inst, instp), inst,
|isap| self.isa_flags.numbered_predicate(isap as usize)) enc_tables::check_instp,
.ok_or(Legalize::Expand) self.isa_flags.predicate_bytes()))
}) })
} }