From 116b898da36cbbda01687663168473543e1d123c Mon Sep 17 00:00:00 2001 From: Jakob Stoklund Olesen Date: Wed, 31 Aug 2016 10:29:53 -0700 Subject: [PATCH] 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. --- meta/gen_encoding.py | 48 ++++++++++++++++++++++++----- src/libcretonne/isa/riscv/mod.rs | 53 ++++++++++++++++++++++++++------ 2 files changed, 84 insertions(+), 17 deletions(-) diff --git a/meta/gen_encoding.py b/meta/gen_encoding.py index e54d15f7fb..e404fb79ec 100644 --- a/meta/gen_encoding.py +++ b/meta/gen_encoding.py @@ -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. diff --git a/src/libcretonne/isa/riscv/mod.rs b/src/libcretonne/isa/riscv/mod.rs index ef87ade3f6..a4c1ce9885 100644 --- a/src/libcretonne/isa/riscv/mod.rs +++ b/src/libcretonne/isa/riscv/mod.rs @@ -40,16 +40,16 @@ fn isa_constructor(shared_flags: shared_settings::Flags, impl TargetIsa for Isa { fn encode(&self, _: &DataFlowGraph, inst: &InstructionData) -> Option { - 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"); } }