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.")
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 {', '}'):

View File

@@ -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<Encoding, Legalize> {
fn legal_encodings<'a, 'b>(&'a self,
_dfg: &'b ir::DataFlowGraph,
inst: &'b ir::InstructionData,
ctrl_typevar: ir::Type)
-> Result<Encodings<'a, 'b>, 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) {

View File

@@ -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<Encoding, Legalize> {
fn legal_encodings<'a, 'b>(&'a self,
_dfg: &'b ir::DataFlowGraph,
inst: &'b ir::InstructionData,
ctrl_typevar: ir::Type)
-> Result<Encodings<'a, 'b>, 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) {

View File

@@ -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<InstP, IsaP>(offset: usize,
enclist: &[EncListEntry],
instp: InstP,
isap: IsaP)
-> Option<Encoding>
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<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
}
}

View File

@@ -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<Encoding, Legalize> {
fn legal_encodings<'a, 'b>(&'a self,
_dfg: &'b ir::DataFlowGraph,
inst: &'b ir::InstructionData,
ctrl_typevar: ir::Type)
-> Result<Encodings<'a, 'b>, 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) {

View File

@@ -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<Encodings<'a, 'b>, 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<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.
fn encoding_info(&self) -> EncInfo;

View File

@@ -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<Encoding, Legalize> {
fn legal_encodings<'a, 'b>(&'a self,
_dfg: &'b ir::DataFlowGraph,
inst: &'b ir::InstructionData,
ctrl_typevar: ir::Type)
-> Result<Encodings<'a, 'b>, 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) {