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 collections import OrderedDict, defaultdict
import math
import itertools
def emit_instp(instp, fmt):
@@ -168,7 +169,26 @@ class EncList(object):
name += ' ({})'.format(self.encodings[0].cpumode)
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.
@@ -180,10 +200,22 @@ class EncList(object):
words = list()
docs = list()
for idx, enc in enumerate(self.encodings):
seq, doc = seq_doc(enc)
docs.append((len(words), doc))
words.extend(seq)
# 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)
docs.append((len(words), doc))
words.extend(seq)
# Terminate the list.
words.append(CODE_FAIL)
self.offset = seq_table.add(words)
@@ -269,13 +301,13 @@ def make_tables(cpumode):
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`.
"""
for level2 in level1:
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):
@@ -397,7 +429,7 @@ def gen_isa(isa, fmt):
level2_doc[len(level2_hashtables)].append(cpumode.name)
level1 = make_tables(cpumode)
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)
# 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 {
fn encode(&self, _: &DataFlowGraph, inst: &InstructionData) -> Option<Encoding> {
shared_encoding::lookup_enclist(inst.first_type(),
inst.opcode(),
self.cpumode,
&encoding::LEVEL2[..])
use isa::encoding::{lookup_enclist, general_encoding};
lookup_enclist(inst.first_type(),
inst.opcode(),
self.cpumode,
&encoding::LEVEL2[..])
.and_then(|enclist_offset| {
shared_encoding::general_encoding(enclist_offset,
&encoding::ENCLISTS[..],
|instp| encoding::check_instp(inst, instp),
// TODO: Implement ISA predicates properly.
|isap| isap != 17)
general_encoding(enclist_offset,
&encoding::ENCLISTS[..],
|instp| encoding::check_instp(inst, instp),
|isap| self.isa_flags.numbered_predicate(isap as usize))
})
}
@@ -160,5 +160,40 @@ mod tests {
// ADDI is I/0b00100
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");
}
}