Emit ISA predicates in the encoding tables.

Use the new ISA predicate numbering to emit ISA predicate instructions in the
encoding tables.

Properly decode the ISA predicate number in RISC-V and add tests for RV32M iwth
and without 'supports_m' enabled.
This commit is contained in:
Jakob Stoklund Olesen
2016-08-31 10:29:53 -07:00
parent f305f50829
commit 116b898da3
2 changed files with 84 additions and 17 deletions

View File

@@ -55,6 +55,7 @@ from constant_hash import compute_quadratic
from unique_table import UniqueSeqTable from unique_table import UniqueSeqTable
from collections import OrderedDict, defaultdict from collections import OrderedDict, defaultdict
import math import math
import itertools
def emit_instp(instp, fmt): def emit_instp(instp, fmt):
@@ -168,7 +169,26 @@ class EncList(object):
name += ' ({})'.format(self.encodings[0].cpumode) name += ' ({})'.format(self.encodings[0].cpumode)
return name return name
def encode(self, seq_table, doc_table): def by_isap(self):
"""
Group the encodings by ISA predicate without reordering them.
Yield a sequence of `(isap, (encs...))` tuples where `isap` is the ISA
predicate or `None`, and `(encs...)` is a tuple of encodings that all
have the same ISA predicate.
"""
maxlen = CODE_FAIL >> PRED_BITS
for isap, group in itertools.groupby(
self.encodings, lambda enc: enc.isap):
group = tuple(group)
# This probably never happens, but we can't express more than
# maxlen encodings per isap.
while len(group) > maxlen:
yield (isap, group[0..maxlen])
group = group[maxlen:]
yield (isap, group)
def encode(self, seq_table, doc_table, isa):
""" """
Encode this list as a sequence of u16 numbers. Encode this list as a sequence of u16 numbers.
@@ -180,10 +200,22 @@ class EncList(object):
words = list() words = list()
docs = list() docs = list()
for idx, enc in enumerate(self.encodings): # Group our encodings by isap.
for isap, group in self.by_isap():
if isap:
# We have an ISA predicate covering `glen` encodings.
pnum = isa.settings.predicate_number[isap]
glen = len(group)
doc = 'skip {}x3 unless {}'.format(glen, isap)
docs.append((len(words), doc))
words.append((glen << PRED_BITS) | pnum)
for enc in group:
seq, doc = seq_doc(enc) seq, doc = seq_doc(enc)
docs.append((len(words), doc)) docs.append((len(words), doc))
words.extend(seq) words.extend(seq)
# Terminate the list.
words.append(CODE_FAIL) words.append(CODE_FAIL)
self.offset = seq_table.add(words) self.offset = seq_table.add(words)
@@ -269,13 +301,13 @@ def make_tables(cpumode):
return table return table
def encode_enclists(level1, seq_table, doc_table): def encode_enclists(level1, seq_table, doc_table, isa):
""" """
Compute encodings and doc comments for encoding lists in `level1`. Compute encodings and doc comments for encoding lists in `level1`.
""" """
for level2 in level1: for level2 in level1:
for enclist in level2: for enclist in level2:
enclist.encode(seq_table, doc_table) enclist.encode(seq_table, doc_table, isa)
def emit_enclists(seq_table, doc_table, fmt): def emit_enclists(seq_table, doc_table, fmt):
@@ -397,7 +429,7 @@ def gen_isa(isa, fmt):
level2_doc[len(level2_hashtables)].append(cpumode.name) level2_doc[len(level2_hashtables)].append(cpumode.name)
level1 = make_tables(cpumode) level1 = make_tables(cpumode)
level1_tables[cpumode] = level1 level1_tables[cpumode] = level1
encode_enclists(level1, seq_table, doc_table) encode_enclists(level1, seq_table, doc_table, isa)
encode_level2_hashtables(level1, level2_hashtables, level2_doc) encode_level2_hashtables(level1, level2_hashtables, level2_doc)
# Level 1 table encodes offsets into the level 2 table. # Level 1 table encodes offsets into the level 2 table.

View File

@@ -40,16 +40,16 @@ fn isa_constructor(shared_flags: shared_settings::Flags,
impl TargetIsa for Isa { impl TargetIsa for Isa {
fn encode(&self, _: &DataFlowGraph, inst: &InstructionData) -> Option<Encoding> { fn encode(&self, _: &DataFlowGraph, inst: &InstructionData) -> Option<Encoding> {
shared_encoding::lookup_enclist(inst.first_type(), use isa::encoding::{lookup_enclist, general_encoding};
lookup_enclist(inst.first_type(),
inst.opcode(), inst.opcode(),
self.cpumode, self.cpumode,
&encoding::LEVEL2[..]) &encoding::LEVEL2[..])
.and_then(|enclist_offset| { .and_then(|enclist_offset| {
shared_encoding::general_encoding(enclist_offset, general_encoding(enclist_offset,
&encoding::ENCLISTS[..], &encoding::ENCLISTS[..],
|instp| encoding::check_instp(inst, instp), |instp| encoding::check_instp(inst, instp),
// TODO: Implement ISA predicates properly. |isap| self.isa_flags.numbered_predicate(isap as usize))
|isap| isap != 17)
}) })
} }
@@ -160,5 +160,40 @@ mod tests {
// ADDI is I/0b00100 // ADDI is I/0b00100
assert_eq!(encstr(&*isa, isa.encode(&dfg, &inst32).unwrap()), "I/04"); assert_eq!(encstr(&*isa, isa.encode(&dfg, &inst32).unwrap()), "I/04");
// Create an imul.i32 which is encodable in RV32, but only when use_m is true.
let mul32 = InstructionData::Binary {
opcode: Opcode::Imul,
ty: types::I32,
args: [arg32, arg32],
};
assert_eq!(isa.encode(&dfg, &mul32), None);
}
#[test]
fn test_rv32m() {
let mut shared_builder = settings::builder();
shared_builder.set_bool("is_64bit", false).unwrap();
let shared_flags = settings::Flags::new(shared_builder);
// Set the supports_m stting which in turn enables the use_m predicate that unlocks
// encodings for imul.
let mut isa_builder = isa::lookup("riscv").unwrap();
isa_builder.set_bool("supports_m", true).unwrap();
let isa = isa_builder.finish(shared_flags);
let mut dfg = DataFlowGraph::new();
let ebb = dfg.make_ebb();
let arg32 = dfg.append_ebb_arg(ebb, types::I32);
// Create an imul.i32 which is encodable in RV32M.
let mul32 = InstructionData::Binary {
opcode: Opcode::Imul,
ty: types::I32,
args: [arg32, arg32],
};
assert_eq!(encstr(&*isa, isa.encode(&dfg, &mul32).unwrap()), "R/10c");
} }
} }