From bcd5bc559c14aae60c5e025d76a1599909b876ed Mon Sep 17 00:00:00 2001 From: Jakob Stoklund Olesen Date: Tue, 25 Oct 2016 16:52:15 -0700 Subject: [PATCH] Begin generating code for the legalizer. This is a work in progress. The 'legalizer.rs' file generated by gen_legalizer.py is not used for anything yet. Add PEP 484 type annotations to a bunch of Python code. --- lib/cretonne/meta/build.py | 2 + lib/cretonne/meta/gen_legalizer.py | 121 +++++++++++++++++++++++++++++ lib/cretonne/src/ir/layout.rs | 9 +++ 3 files changed, 132 insertions(+) create mode 100644 lib/cretonne/meta/gen_legalizer.py diff --git a/lib/cretonne/meta/build.py b/lib/cretonne/meta/build.py index 1554b6a54c..51f8e7c056 100644 --- a/lib/cretonne/meta/build.py +++ b/lib/cretonne/meta/build.py @@ -10,6 +10,7 @@ import gen_instr import gen_settings import gen_build_deps import gen_encoding +import gen_legalizer parser = argparse.ArgumentParser(description='Generate sources for Cretonne.') parser.add_argument('--out-dir', help='set output directory') @@ -23,4 +24,5 @@ gen_types.generate(out_dir) gen_instr.generate(isas, out_dir) gen_settings.generate(isas, out_dir) gen_encoding.generate(isas, out_dir) +gen_legalizer.generate(isas, out_dir) gen_build_deps.generate() diff --git a/lib/cretonne/meta/gen_legalizer.py b/lib/cretonne/meta/gen_legalizer.py new file mode 100644 index 0000000000..0fdfc921af --- /dev/null +++ b/lib/cretonne/meta/gen_legalizer.py @@ -0,0 +1,121 @@ +""" +Generate legalizer transformations. + +The transformations defined in the `cretonne.legalize` module are all of the +macro-expansion form where the input pattern is a single instruction. We +generate a Rust function for each `XFormGroup` which takes a `Cursor` pointing +at the instruction to be legalized. The expanded destination pattern replaces +the input instruction. +""" +from __future__ import absolute_import +from srcgen import Formatter +import cretonne.legalize as legalize +from cretonne.ast import Def, Apply # noqa +from cretonne.xform import XForm, XFormGroup # noqa + +try: + from typing import Union # noqa + DefApply = Union[Def, Apply] +except ImportError: + pass + + +def unwrap_inst(iref, node, fmt): + # type: (str, DefApply, Formatter) -> None + """ + Given a `Def` or `Apply` node, emit code that extracts all the instruction + fields from `dfg[iref]`. + + Create local variables named after the `Var` instances in `node`. + + :param iref: Name of the `Inst` reference to unwrap. + :param node: `Def` or `Apply` node providing variable names. + + """ + fmt.comment('Unwrap {}'.format(node)) + defs, expr = node.defs_expr() + iform = expr.inst.format + nvops = len(iform.value_operands) + + # The tuple of locals we're extracting is `expr.args`. + with fmt.indented( + 'let ({}) = if let InstructionData::{} {{' + .format(', '.join(map(str, expr.args)), iform.name), '};'): + if iform.boxed_storage: + # This format indirects to a largish `data` struct. + fmt.line('ref data,') + else: + # Fields are encoded directly. + for m in iform.members: + if m: + fmt.line('{},'.format(m)) + if nvops == 1: + fmt.line('arg,') + elif nvops > 1: + fmt.line('args,') + fmt.line('..') + fmt.outdented_line('} = dfg[inst] {') + # Generate the values for the tuple. + outs = list() + prefix = 'data.' if iform.boxed_storage else '' + for i, m in enumerate(iform.members): + if m: + outs.append(prefix + m) + else: + # This is a value operand. + if nvops == 1: + outs.append(prefix + 'arg') + else: + outs.append( + '{}args[{}]'.format( + prefix, iform.value_operands.index(i))) + fmt.line('({})'.format(', '.join(outs))) + fmt.outdented_line('} else {') + fmt.line('unimplemented!("bad instruction format")') + + +def gen_xform(xform, fmt): + # type: (XForm, Formatter) -> None + """ + Emit code for `xform`, assuming the the opcode of xform's root instruction + has already been matched. + + `inst: Inst` is the variable to be replaced. It is pointed to by `pos: + Cursor`. + `dfg: DataFlowGraph` is available and mutable. + """ + unwrap_inst('inst', xform.src.rtl[0], fmt) + + +def gen_xform_group(xgrp, fmt): + # type: (XFormGroup, Formatter) -> None + fmt.doc_comment(""" + Legalize the instruction pointed to by `pos`. + + Return the first instruction in the expansion, and leave `pos` pointing + at the last instruction in the expansion. + """) + with fmt.indented( + 'fn ' + xgrp.name + + '(pos: &mut Cursor, dfg: &mut DataFlowGraph) -> ' + + 'Option {{', + '}'): + # Gen the instruction to be legalized. The cursor we're passed must be + # pointing at an instruction. + fmt.line('let inst = pos.current_inst().expect("need instruction");') + + with fmt.indented('match dfg[inst].opcode() {', '}'): + for xform in xgrp.xforms: + inst = xform.src.rtl[0].root_inst() + with fmt.indented( + 'Opcode::{} => {{'.format(inst.camel_name), '}'): + gen_xform(xform, fmt) + # We'll assume there are uncovered opcodes. + fmt.line('_ => None,') + + +def generate(isas, out_dir): + fmt = Formatter() + gen_xform_group(legalize.narrow, fmt) + gen_xform_group(legalize.expand, fmt) + fmt.update_file('legalizer.rs', out_dir) diff --git a/lib/cretonne/src/ir/layout.rs b/lib/cretonne/src/ir/layout.rs index 864420c4f5..fdd2305747 100644 --- a/lib/cretonne/src/ir/layout.rs +++ b/lib/cretonne/src/ir/layout.rs @@ -391,6 +391,15 @@ impl<'f> Cursor<'f> { } } + /// Get the instruction corresponding to the current position, if any. + pub fn current_inst(&self) -> Option { + use self::CursorPosition::*; + match self.pos { + At(inst) => Some(inst), + _ => None, + } + } + /// Go to a specific instruction which must be inserted in the layout. /// New instructions will be inserted before `inst`. pub fn goto_inst(&mut self, inst: Inst) {