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:
@@ -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):
|
||||
# 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.
|
||||
|
||||
@@ -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(),
|
||||
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,
|
||||
general_encoding(enclist_offset,
|
||||
&encoding::ENCLISTS[..],
|
||||
|instp| encoding::check_instp(inst, instp),
|
||||
// TODO: Implement ISA predicates properly.
|
||||
|isap| isap != 17)
|
||||
|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");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user