Use a simple quadratically probed, open addressed hash table. We could use a parfect hash function, but it would take longer to compute in Python, and this is not in the critical path performancewise.
63 lines
2.1 KiB
Python
63 lines
2.1 KiB
Python
"""
|
|
Generate sources with instruction info.
|
|
"""
|
|
|
|
import srcgen
|
|
import constant_hash
|
|
|
|
def collect_instr_groups(targets):
|
|
seen = set()
|
|
groups = []
|
|
for t in targets:
|
|
for g in t.instruction_groups:
|
|
if g not in seen:
|
|
groups.append(g)
|
|
seen.add(g)
|
|
return groups
|
|
|
|
def gen_opcodes(groups, out_dir):
|
|
"""Generate opcode enumerations."""
|
|
fmt = srcgen.Formatter()
|
|
|
|
fmt.doc_comment('An instruction opcode.')
|
|
fmt.doc_comment('')
|
|
fmt.doc_comment('All instructions from all supported targets are present.')
|
|
fmt.line('#[derive(Copy, Clone, PartialEq, Eq, Debug)]')
|
|
instrs = []
|
|
with fmt.indented('pub enum Opcode {', '}'):
|
|
fmt.line('NotAnOpcode,')
|
|
for g in groups:
|
|
for i in g.instructions:
|
|
instrs.append(i)
|
|
# Build a doc comment.
|
|
prefix = ', '.join(o.name for o in i.outs)
|
|
if prefix:
|
|
prefix = prefix + ' = '
|
|
suffix = ', '.join(o.name for o in i.ins)
|
|
fmt.doc_comment('`{}{} {}`.'.format(prefix, i.name, suffix))
|
|
# Enum variant itself.
|
|
fmt.line(i.camel_name + ',')
|
|
|
|
# Generate a private opcode_name function.
|
|
with fmt.indented('fn opcode_name(opc: Opcode) -> &\'static str {', '}'):
|
|
with fmt.indented('match opc {', '}'):
|
|
fmt.line('Opcode::NotAnOpcode => "<not an opcode>",')
|
|
for i in instrs:
|
|
fmt.format('Opcode::{} => "{}",', i.camel_name, i.name)
|
|
|
|
# Generate an opcode hash table for looking up opcodes by name.
|
|
hash_table = constant_hash.compute_quadratic(instrs,
|
|
lambda i: constant_hash.simple_hash(i.name))
|
|
with fmt.indented('const OPCODE_HASH_TABLE: [Opcode; {}] = ['.format(len(hash_table)), '];'):
|
|
for i in hash_table:
|
|
if i is None:
|
|
fmt.line('Opcode::NotAnOpcode,')
|
|
else:
|
|
fmt.format('Opcode::{},', i.camel_name)
|
|
|
|
fmt.update_file('opcodes.rs', out_dir)
|
|
|
|
def generate(targets, out_dir):
|
|
groups = collect_instr_groups(targets)
|
|
gen_opcodes(groups, out_dir)
|