From 0c8f251beebba7c497a18372f30e034635e6c5b5 Mon Sep 17 00:00:00 2001 From: Jakob Stoklund Olesen Date: Fri, 26 Aug 2016 14:44:03 -0700 Subject: [PATCH] Emit encoding lists (WIP). Compute the u16 representation of encoding lists and emit a big table concatenating all of them. Use the UniqueSeqTable to share some table space between CPU modes. --- meta/cretonne/__init__.py | 3 + meta/gen_encoding.py | 112 +++++++++++++++++++++++++++++++++++--- 2 files changed, 106 insertions(+), 9 deletions(-) diff --git a/meta/cretonne/__init__.py b/meta/cretonne/__init__.py index 2e316982c0..b44a238ffd 100644 --- a/meta/cretonne/__init__.py +++ b/meta/cretonne/__init__.py @@ -1030,6 +1030,9 @@ class CPUMode(object): self.encodings = [] isa.cpumodes.append(self) + def __str__(self): + return self.name + def enc(self, *args, **kwargs): """ Add a new encoding to this CPU mode. diff --git a/meta/gen_encoding.py b/meta/gen_encoding.py index c10a4f8a06..278ed66da5 100644 --- a/meta/gen_encoding.py +++ b/meta/gen_encoding.py @@ -51,7 +51,8 @@ instructions with different types for secondary type variables. """ from __future__ import absolute_import import srcgen -from collections import OrderedDict +from unique_table import UniqueSeqTable +from collections import OrderedDict, defaultdict def emit_instp(instp, fmt): @@ -102,6 +103,43 @@ def emit_instps(instps, fmt): fmt.line(' instp_idx);') +# Encoding lists are represented as u16 arrays. +CODE_BITS = 16 +PRED_BITS = 12 +PRED_MASK = (1 << PRED_BITS) - 1 + +# 0..CODE_ALWAYS means: Check instruction predicate and use the next two +# entries as a (recipe, encbits) pair if true. CODE_ALWAYS is the always-true +# predicate, smaller numbers refer to instruction predicates. +CODE_ALWAYS = PRED_MASK + +# Codes above CODE_ALWAYS indicate an ISA predicate to be tested. +# `x & PRED_MASK` is the ISA predicate number to test. +# `(x >> PRED_BITS)*3` is the number of u16 table entries to skip if the ISA +# predicate is false. (The factor of three corresponds to the (inst-pred, +# recipe, encbits) triples. +# +# Finally, CODE_FAIL indicates the end of the list. +CODE_FAIL = (1 << CODE_BITS) - 1 + + +def seq_doc(enc): + """ + Return a tuple containing u16 representations of the instruction predicate + an recipe / encbits. + + Also return a doc string. + """ + if enc.instp: + p = enc.instp.number + doc = '--> {} when {}'.format(enc, enc.instp) + else: + p = CODE_ALWAYS + doc = '--> {}'.format(enc) + assert p <= CODE_ALWAYS + return ((p, enc.recipe.number, enc.encbits), doc) + + class EncList(object): """ List of instructions for encoding a given type + opcode pair. @@ -121,10 +159,38 @@ class EncList(object): self.encodings = [] def name(self): + name = self.inst.name if self.ty: - return '{}.{}'.format(self.inst.name, self.ty.name) - else: - return self.inst.name + name = '{}.{}'.format(name, self.ty.name) + if self.encodings: + name += ' ({})'.format(self.encodings[0].cpumode) + return name + + def encode(self, seq_table, doc_table): + """ + Encode this list as a sequence of u16 numbers. + + Adds the sequence to `seq_table` and records the returned offset as + `self.offset`. + + Adds comment lines to `doc_table` keyed by seq_table offsets. + """ + words = list() + docs = list() + + for idx, enc in enumerate(self.encodings): + seq, doc = seq_doc(enc) + docs.append((len(words), doc)) + words.extend(seq) + words.append(CODE_FAIL) + + self.offset = seq_table.add(words) + + # Add doc comments. + doc_table[self.offset].append( + '{:06x}: {}'.format(self.offset, self.name())) + for pos, doc in docs: + doc_table[self.offset + pos].append(doc) class Level2Table(object): @@ -181,18 +247,46 @@ def make_tables(cpumode): return table +def encode_enclists(level1, seq_table, doc_table): + """ + Compute encodings and doc comments for encoding lists in `level1`. + """ + for level2 in level1: + for enclist in level2: + enclist.encode(seq_table, doc_table) + + +def emit_enclists(seq_table, doc_table, fmt): + with fmt.indented( + 'const ENCLISTS: [u16; {}] = ['.format(len(seq_table.table)), + '];'): + line = '' + for idx, entry in enumerate(seq_table.table): + if idx in doc_table: + if line: + fmt.line(line) + line = '' + for doc in doc_table[idx]: + fmt.comment(doc) + line += '{:#06x}, '.format(entry) + if line: + fmt.line(line) + + def gen_isa(isa, fmt): # First assign numbers to relevant instruction predicates and generate the # check_instp() function.. emit_instps(isa.all_instps, fmt) + # Tables for enclists with comments. + seq_table = UniqueSeqTable() + doc_table = defaultdict(list) + for cpumode in isa.cpumodes: level1 = make_tables(cpumode) - for level2 in level1: - for enclist in level2: - fmt.comment(enclist.name()) - for enc in enclist.encodings: - fmt.comment('{} when {}'.format(enc, enc.instp)) + encode_enclists(level1, seq_table, doc_table) + + emit_enclists(seq_table, doc_table, fmt) def generate(isas, out_dir):