Return a function pointer from TargetIsa::encode().

Replace the isa::Legalize enumeration with a function pointer. This
allows an ISA to define its own specific legalization actions instead of
relying on the default two.

Generate a LEGALIZE_ACTIONS table for each ISA which contains
legalization function pointers indexed by the legalization codes that
are already in the encoding tables. Include this table in
isa/*/enc_tables.rs.

Give the `Encodings` iterator a reference to the action table and change
its `legalize()` method to return a function pointer instead of an
ISA-specific code.

The Result<> returned from TargetIsa::encode() no longer implements
Debug, so eliminate uses of unwrap and expect on that type.
This commit is contained in:
Jakob Stoklund Olesen
2017-07-27 14:46:56 -07:00
parent 1bbc06e2d6
commit b04a2c30d2
19 changed files with 140 additions and 102 deletions

View File

@@ -10,6 +10,7 @@ try:
from typing import Union, Iterator, Sequence, Iterable, List, Dict # noqa
from typing import Optional, Set # noqa
from .ast import Expr, VarMap # noqa
from .isa import TargetISA # noqa
from .ti import TypeConstraint # noqa
from .typevar import TypeVar # noqa
DefApply = Union[Def, Apply]
@@ -282,17 +283,37 @@ class XForm(object):
class XFormGroup(object):
"""
A group of related transformations.
:param isa: A target ISA whose instructions are allowed.
:param chain: A next level group to try if this one doesn't match.
"""
def __init__(self, name, doc):
# type: (str, str) -> None
def __init__(self, name, doc, isa=None, chain=None):
# type: (str, str, TargetISA, XFormGroup) -> None
self.xforms = list() # type: List[XForm]
self.name = name
self.__doc__ = doc
self.isa = isa
self.chain = chain
def __str__(self):
# type: () -> str
return self.name
if self.isa:
return '{}.{}'.format(self.isa.name, self.name)
else:
return self.name
def rust_name(self):
# type: () -> str
"""
Get the Rust name of this function implementing this transform.
"""
if self.isa:
# This is a function in the same module as the LEGALIZE_ACTION
# table referring to it.
return self.name
else:
return '::legalizer::{}'.format(self.name)
def legalize(self, src, dst):
# type: (Union[Def, Apply], Rtl) -> None

View File

@@ -875,7 +875,7 @@ def gen_isa(isa, fmt):
emit_recipe_sizing(isa, fmt)
# Finally, tie it all together in an `EncInfo`.
with fmt.indented('pub static INFO: EncInfo = EncInfo {', '};'):
with fmt.indented('pub static INFO: isa::EncInfo = isa::EncInfo {', '};'):
fmt.line('constraints: &RECIPE_CONSTRAINTS,')
fmt.line('sizing: &RECIPE_SIZING,')
fmt.line('names: &RECIPE_NAMES,')

View File

@@ -345,6 +345,8 @@ def gen_typesets_table(fmt, type_sets):
"""
Generate the table of ValueTypeSets described by type_sets.
"""
if len(type_sets.table) == 0:
return
fmt.comment('Table of value type sets.')
assert len(type_sets.table) <= typeset_limit, "Too many type sets"
with fmt.indented(

View File

@@ -9,7 +9,7 @@ the input instruction.
"""
from __future__ import absolute_import
from srcgen import Formatter
from base import legalize, instructions
from base import instructions
from cdsl.ast import Var
from cdsl.ti import ti_rtl, TypeEnv, get_type_env, TypesEqual,\
InTypeset, WiderOrEq
@@ -18,7 +18,7 @@ from gen_instr import gen_typesets_table
from cdsl.typevar import TypeVar
try:
from typing import Sequence, List, Dict # noqa
from typing import Sequence, List, Dict, Set # noqa
from cdsl.isa import TargetISA # noqa
from cdsl.ast import Def # noqa
from cdsl.xform import XForm, XFormGroup # noqa
@@ -167,7 +167,7 @@ def unwrap_inst(iref, node, fmt):
# The tuple of locals we're extracting is `expr.args`.
with fmt.indented(
'let ({}) = if let InstructionData::{} {{'
'let ({}) = if let ir::InstructionData::{} {{'
.format(', '.join(map(str, expr.args)), iform.name), '};'):
# Fields are encoded directly.
for f in iform.imm_fields:
@@ -348,9 +348,11 @@ def gen_xform_group(xgrp, fmt, type_sets):
fmt.doc_comment("Legalize the instruction pointed to by `pos`.")
fmt.line('#[allow(unused_variables,unused_assignments)]')
with fmt.indented(
'fn {}(dfg: &mut DataFlowGraph, '
'cfg: &mut ControlFlowGraph, pos: &mut Cursor) -> '
'pub fn {}(dfg: &mut ir::DataFlowGraph, '
'cfg: &mut ::flowgraph::ControlFlowGraph, '
'pos: &mut ir::Cursor) -> '
'bool {{'.format(xgrp.name), '}'):
fmt.line('use ir::InstBuilder;')
# Gen the instruction to be legalized. The cursor we're passed must be
# pointing at an instruction.
@@ -360,21 +362,55 @@ def gen_xform_group(xgrp, fmt, type_sets):
for xform in xgrp.xforms:
inst = xform.src.rtl[0].expr.inst
with fmt.indented(
'Opcode::{} => {{'.format(inst.camel_name), '}'):
'ir::Opcode::{} => {{'.format(inst.camel_name), '}'):
gen_xform(xform, fmt, type_sets)
# We'll assume there are uncovered opcodes.
fmt.line('_ => return false,')
if xgrp.chain:
fmt.format('_ => return {}(dfg, cfg, pos),',
xgrp.chain.rust_name())
else:
fmt.line('_ => return false,')
fmt.line('true')
def gen_isa(isa, fmt, shared_groups):
# type: (TargetISA, Formatter, Set[XFormGroup]) -> None
"""
Generate legalization functions for `isa` and add any shared `XFormGroup`s
encountered to `shared_groups`.
Generate `TYPE_SETS` and `LEGALIZE_ACTION` tables.
"""
type_sets = UniqueTable()
for xgrp in isa.legalize_codes.keys():
if xgrp.isa is None:
shared_groups.add(xgrp)
else:
assert xgrp.isa == isa
gen_xform_group(xgrp, fmt, type_sets)
gen_typesets_table(fmt, type_sets)
with fmt.indented(
'pub static LEGALIZE_ACTIONS: [isa::Legalize; {}] = ['
.format(len(isa.legalize_codes)), '];'):
for xgrp in isa.legalize_codes.keys():
fmt.format('{},', xgrp.rust_name())
def generate(isas, out_dir):
# type: (Sequence[TargetISA], str) -> None
shared_groups = set() # type: Set[XFormGroup]
for isa in isas:
fmt = Formatter()
gen_isa(isa, fmt, shared_groups)
fmt.update_file('legalize-{}.rs'.format(isa.name), out_dir)
# Shared xform groups.
fmt = Formatter()
# Table of TypeSet instances
type_sets = UniqueTable()
gen_xform_group(legalize.narrow, fmt, type_sets)
gen_xform_group(legalize.expand, fmt, type_sets)
for xgrp in sorted(shared_groups, key=lambda g: g.name):
gen_xform_group(xgrp, fmt, type_sets)
gen_typesets_table(fmt, type_sets)
fmt.update_file('legalizer.rs', out_dir)