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 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.
|
||||||
|
|||||||
@@ -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");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user