Make legalization actions configurable.
When an instruction doesn't have a valid encoding for the target ISA, it needs to be legalized. Different legalization strategies can be expressed as separate XFormGroup objects. Make the choice of XFormGroup configurable per CPU mode, rather than depending on a hard-coded default. Add a CPUMode.legalize_type() method which assigns an XFormGroup to controlling type variables and lets you set a default. Add a `legalize` field to Level1Entry so the first-level hash table lookup gives us the configured default legalization action for the instruction's controlling type variable.
This commit is contained in:
@@ -27,6 +27,13 @@ narrow = XFormGroup('narrow', """
|
|||||||
operations are expressed in terms of smaller integer types.
|
operations are expressed in terms of smaller integer types.
|
||||||
""")
|
""")
|
||||||
|
|
||||||
|
widen = XFormGroup('widen', """
|
||||||
|
Legalize instructions by widening.
|
||||||
|
|
||||||
|
The transformations in the 'widen' group work by expressing
|
||||||
|
instructions in terms of larger types.
|
||||||
|
""")
|
||||||
|
|
||||||
expand = XFormGroup('expand', """
|
expand = XFormGroup('expand', """
|
||||||
Legalize instructions by expansion.
|
Legalize instructions by expansion.
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
"""Defining instruction set architectures."""
|
"""Defining instruction set architectures."""
|
||||||
from __future__ import absolute_import
|
from __future__ import absolute_import
|
||||||
|
from collections import OrderedDict
|
||||||
from .predicates import And
|
from .predicates import And
|
||||||
from .registers import RegClass, Register, Stack
|
from .registers import RegClass, Register, Stack
|
||||||
from .ast import Apply
|
from .ast import Apply
|
||||||
|
from .types import ValueType
|
||||||
|
|
||||||
# The typing module is only required by mypy, and we don't use these imports
|
# The typing module is only required by mypy, and we don't use these imports
|
||||||
# outside type comments.
|
# outside type comments.
|
||||||
@@ -12,8 +14,8 @@ try:
|
|||||||
from .instructions import MaybeBoundInst, InstructionGroup, InstructionFormat # noqa
|
from .instructions import MaybeBoundInst, InstructionGroup, InstructionFormat # noqa
|
||||||
from .predicates import PredNode # noqa
|
from .predicates import PredNode # noqa
|
||||||
from .settings import SettingGroup # noqa
|
from .settings import SettingGroup # noqa
|
||||||
from .types import ValueType # noqa
|
|
||||||
from .registers import RegBank # noqa
|
from .registers import RegBank # noqa
|
||||||
|
from .xform import XFormGroup # noqa
|
||||||
OperandConstraint = Union[RegClass, Register, int, Stack]
|
OperandConstraint = Union[RegClass, Register, int, Stack]
|
||||||
ConstraintSeq = Union[OperandConstraint, Tuple[OperandConstraint, ...]]
|
ConstraintSeq = Union[OperandConstraint, Tuple[OperandConstraint, ...]]
|
||||||
# Instruction specification for encodings. Allows for predicated
|
# Instruction specification for encodings. Allows for predicated
|
||||||
@@ -43,6 +45,11 @@ class TargetISA(object):
|
|||||||
self.cpumodes = list() # type: List[CPUMode]
|
self.cpumodes = list() # type: List[CPUMode]
|
||||||
self.regbanks = list() # type: List[RegBank]
|
self.regbanks = list() # type: List[RegBank]
|
||||||
self.regclasses = list() # type: List[RegClass]
|
self.regclasses = list() # type: List[RegClass]
|
||||||
|
self.legalize_codes = OrderedDict() # type: OrderedDict[XFormGroup, int] # noqa
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
# type: () -> str
|
||||||
|
return self.name
|
||||||
|
|
||||||
def finish(self):
|
def finish(self):
|
||||||
# type: () -> TargetISA
|
# type: () -> TargetISA
|
||||||
@@ -138,6 +145,25 @@ class TargetISA(object):
|
|||||||
# `isa/registers.rs`.
|
# `isa/registers.rs`.
|
||||||
assert len(self.regclasses) <= 32, "Too many register classes"
|
assert len(self.regclasses) <= 32, "Too many register classes"
|
||||||
|
|
||||||
|
def legalize_code(self, xgrp):
|
||||||
|
# type: (XFormGroup) -> int
|
||||||
|
"""
|
||||||
|
Get the legalization code for the transform group `xgrp`. Assign one if
|
||||||
|
necessary.
|
||||||
|
|
||||||
|
Each target ISA has its own list of legalization actions with
|
||||||
|
associated legalize codes that appear in the encoding tables.
|
||||||
|
|
||||||
|
This method is used to maintain the registry of legalization actions
|
||||||
|
and their table codes.
|
||||||
|
"""
|
||||||
|
if xgrp in self.legalize_codes:
|
||||||
|
code = self.legalize_codes[xgrp]
|
||||||
|
else:
|
||||||
|
code = len(self.legalize_codes)
|
||||||
|
self.legalize_codes[xgrp] = code
|
||||||
|
return code
|
||||||
|
|
||||||
|
|
||||||
class CPUMode(object):
|
class CPUMode(object):
|
||||||
"""
|
"""
|
||||||
@@ -157,6 +183,11 @@ class CPUMode(object):
|
|||||||
self.encodings = [] # type: List[Encoding]
|
self.encodings = [] # type: List[Encoding]
|
||||||
isa.cpumodes.append(self)
|
isa.cpumodes.append(self)
|
||||||
|
|
||||||
|
# Tables for configuring legalization actions when no valid encoding
|
||||||
|
# exists for an instruction.
|
||||||
|
self.default_legalize = None # type: XFormGroup
|
||||||
|
self.type_legalize = dict() # type: Dict[ValueType, XFormGroup]
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
# type: () -> str
|
# type: () -> str
|
||||||
return self.name
|
return self.name
|
||||||
@@ -171,6 +202,36 @@ class CPUMode(object):
|
|||||||
"""
|
"""
|
||||||
self.encodings.append(Encoding(self, *args, **kwargs))
|
self.encodings.append(Encoding(self, *args, **kwargs))
|
||||||
|
|
||||||
|
def legalize_type(self, default=None, **kwargs):
|
||||||
|
# type: (XFormGroup, **XFormGroup) -> None
|
||||||
|
"""
|
||||||
|
Configure the legalization action per controlling type variable.
|
||||||
|
|
||||||
|
Instructions that have a controlling type variable mentioned in one of
|
||||||
|
the arguments will be legalized according to the action specified here
|
||||||
|
instead of using the `legalize_default` action.
|
||||||
|
|
||||||
|
The keyword arguments are value type names:
|
||||||
|
|
||||||
|
mode.legalize_type(i8=widen, i16=widen, i32=expand)
|
||||||
|
|
||||||
|
The `default` argument specifies the action to take for controlling
|
||||||
|
type variables that don't have an explicitly configured action.
|
||||||
|
"""
|
||||||
|
if default is not None:
|
||||||
|
self.default_legalize = default
|
||||||
|
|
||||||
|
for name, xgrp in kwargs.items():
|
||||||
|
ty = ValueType.by_name(name)
|
||||||
|
self.type_legalize[ty] = xgrp
|
||||||
|
|
||||||
|
def get_legalize_action(self, ty):
|
||||||
|
# type: (ValueType) -> XFormGroup
|
||||||
|
"""
|
||||||
|
Get the legalization action to use for `ty`.
|
||||||
|
"""
|
||||||
|
return self.type_legalize.get(ty, self.default_legalize)
|
||||||
|
|
||||||
|
|
||||||
class EncRecipe(object):
|
class EncRecipe(object):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -241,6 +241,10 @@ class XFormGroup(object):
|
|||||||
self.name = name
|
self.name = name
|
||||||
self.__doc__ = doc
|
self.__doc__ = doc
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
# type: () -> str
|
||||||
|
return self.name
|
||||||
|
|
||||||
def legalize(self, src, dst):
|
def legalize(self, src, dst):
|
||||||
# type: (Union[Def, Apply], Rtl) -> None
|
# type: (Union[Def, Apply], Rtl) -> None
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ try:
|
|||||||
from cdsl.predicates import PredNode, PredLeaf # noqa
|
from cdsl.predicates import PredNode, PredLeaf # noqa
|
||||||
from cdsl.types import ValueType # noqa
|
from cdsl.types import ValueType # noqa
|
||||||
from cdsl.instructions import Instruction # noqa
|
from cdsl.instructions import Instruction # noqa
|
||||||
|
from cdsl.xform import XFormGroup # noqa
|
||||||
except ImportError:
|
except ImportError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -261,12 +262,17 @@ class Level2Table(object):
|
|||||||
"""
|
"""
|
||||||
Level 2 table mapping instruction opcodes to `EncList` objects.
|
Level 2 table mapping instruction opcodes to `EncList` objects.
|
||||||
|
|
||||||
|
A level 2 table can be completely empty if it only holds a custom
|
||||||
|
legalization action for `ty`.
|
||||||
|
|
||||||
:param ty: Controlling type variable of all entries, or `None`.
|
:param ty: Controlling type variable of all entries, or `None`.
|
||||||
|
:param legalize: Default legalize action for `ty`.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, ty):
|
def __init__(self, ty, legalize):
|
||||||
# type: (ValueType) -> None
|
# type: (ValueType, XFormGroup) -> None
|
||||||
self.ty = ty
|
self.ty = ty
|
||||||
|
self.legalize = legalize
|
||||||
# Maps inst -> EncList
|
# Maps inst -> EncList
|
||||||
self.lists = OrderedDict() # type: OrderedDict[Instruction, EncList]
|
self.lists = OrderedDict() # type: OrderedDict[Instruction, EncList]
|
||||||
|
|
||||||
@@ -278,6 +284,16 @@ class Level2Table(object):
|
|||||||
self.lists[inst] = ls
|
self.lists[inst] = ls
|
||||||
return ls
|
return ls
|
||||||
|
|
||||||
|
def is_empty(self):
|
||||||
|
# type: () -> bool
|
||||||
|
"""
|
||||||
|
Check if this level 2 table is completely empty.
|
||||||
|
|
||||||
|
This can happen if the associated type simply has an overridden
|
||||||
|
legalize action.
|
||||||
|
"""
|
||||||
|
return len(self.lists) == 0
|
||||||
|
|
||||||
def enclists(self):
|
def enclists(self):
|
||||||
# type: () -> Iterable[EncList]
|
# type: () -> Iterable[EncList]
|
||||||
return iter(self.lists.values())
|
return iter(self.lists.values())
|
||||||
@@ -310,21 +326,32 @@ class Level1Table(object):
|
|||||||
Level 1 table mapping types to `Level2` objects.
|
Level 1 table mapping types to `Level2` objects.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self, cpumode):
|
||||||
# type: () -> None
|
# type: (CPUMode) -> None
|
||||||
|
self.cpumode = cpumode
|
||||||
self.tables = OrderedDict() # type: OrderedDict[ValueType, Level2Table] # noqa
|
self.tables = OrderedDict() # type: OrderedDict[ValueType, Level2Table] # noqa
|
||||||
|
|
||||||
|
if cpumode.default_legalize is None:
|
||||||
|
raise AssertionError(
|
||||||
|
'CPU mode {}.{} needs a default legalize action'
|
||||||
|
.format(cpumode.isa, cpumode))
|
||||||
|
self.legalize_code = cpumode.isa.legalize_code(
|
||||||
|
cpumode.default_legalize)
|
||||||
|
|
||||||
def __getitem__(self, ty):
|
def __getitem__(self, ty):
|
||||||
# type: (ValueType) -> Level2Table
|
# type: (ValueType) -> Level2Table
|
||||||
tbl = self.tables.get(ty)
|
tbl = self.tables.get(ty)
|
||||||
if not tbl:
|
if not tbl:
|
||||||
tbl = Level2Table(ty)
|
legalize = self.cpumode.get_legalize_action(ty)
|
||||||
|
# Allocate a legalization code in a predictable order.
|
||||||
|
self.cpumode.isa.legalize_code(legalize)
|
||||||
|
tbl = Level2Table(ty, legalize)
|
||||||
self.tables[ty] = tbl
|
self.tables[ty] = tbl
|
||||||
return tbl
|
return tbl
|
||||||
|
|
||||||
def l2tables(self):
|
def l2tables(self):
|
||||||
# type: () -> Iterable[Level2Table]
|
# type: () -> Iterable[Level2Table]
|
||||||
return iter(self.tables.values())
|
return (l2 for l2 in self.tables.values() if not l2.is_empty())
|
||||||
|
|
||||||
|
|
||||||
def make_tables(cpumode):
|
def make_tables(cpumode):
|
||||||
@@ -332,11 +359,17 @@ def make_tables(cpumode):
|
|||||||
"""
|
"""
|
||||||
Generate tables for `cpumode` as described above.
|
Generate tables for `cpumode` as described above.
|
||||||
"""
|
"""
|
||||||
table = Level1Table()
|
table = Level1Table(cpumode)
|
||||||
for enc in cpumode.encodings:
|
for enc in cpumode.encodings:
|
||||||
ty = enc.ctrl_typevar()
|
ty = enc.ctrl_typevar()
|
||||||
inst = enc.inst
|
inst = enc.inst
|
||||||
table[ty][inst].encodings.append(enc)
|
table[ty][inst].encodings.append(enc)
|
||||||
|
|
||||||
|
# Ensure there are level 1 table entries for all types with a custom
|
||||||
|
# legalize action. Try to be stable relative to dict ordering.
|
||||||
|
for ty in sorted(cpumode.type_legalize.keys(), key=str):
|
||||||
|
table[ty]
|
||||||
|
|
||||||
return table
|
return table
|
||||||
|
|
||||||
|
|
||||||
@@ -412,22 +445,42 @@ def emit_level1_hashtable(cpumode, level1, offt, fmt):
|
|||||||
'pub static LEVEL1_{}: [Level1Entry<{}>; {}] = ['
|
'pub static LEVEL1_{}: [Level1Entry<{}>; {}] = ['
|
||||||
.format(cpumode.name.upper(), offt, len(hash_table)), '];'):
|
.format(cpumode.name.upper(), offt, len(hash_table)), '];'):
|
||||||
for level2 in hash_table:
|
for level2 in hash_table:
|
||||||
if level2:
|
# Empty hash table entry. Include the default legalization action.
|
||||||
l2l = int(math.log(level2.hash_table_len, 2))
|
if not level2:
|
||||||
assert l2l > 0, "Hash table too small"
|
fmt.format(
|
||||||
tyname = level2.ty.name if level2.ty is not None else 'void'
|
'Level1Entry {{ ty: types::VOID, log2len: !0, '
|
||||||
fmt.line(
|
'offset: 0, legalize: {} }},',
|
||||||
'Level1Entry ' +
|
level1.legalize_code)
|
||||||
'{{ ty: types::{}, log2len: {}, offset: {:#08x} }},'
|
continue
|
||||||
.format(
|
|
||||||
tyname.upper(),
|
if level2.ty is not None:
|
||||||
l2l,
|
tyname = level2.ty.rust_name()
|
||||||
level2.hash_table_offset))
|
|
||||||
else:
|
else:
|
||||||
# Empty entry.
|
tyname = 'types::VOID'
|
||||||
fmt.line(
|
|
||||||
'Level1Entry ' +
|
lcode = cpumode.isa.legalize_code(level2.legalize)
|
||||||
'{ ty: types::VOID, log2len: 0, offset: 0 },')
|
|
||||||
|
# Empty level 2 table: Only a specialized legalization action, no
|
||||||
|
# actual table.
|
||||||
|
# Set an offset that is out of bounds, but make sure it doesn't
|
||||||
|
# overflow its type when adding `1<<log2len`.
|
||||||
|
if level2.is_empty():
|
||||||
|
fmt.format(
|
||||||
|
'Level1Entry {{ '
|
||||||
|
'ty: {}, log2len: 0, offset: !0 - 1, '
|
||||||
|
'legalize: {} }}, // {}',
|
||||||
|
tyname, lcode, level2.legalize)
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Proper level 2 hash table.
|
||||||
|
l2l = int(math.log(level2.hash_table_len, 2))
|
||||||
|
assert l2l > 0, "Level2 hash table too small"
|
||||||
|
fmt.format(
|
||||||
|
'Level1Entry {{ '
|
||||||
|
'ty: {}, log2len: {}, offset: {:#08x}, '
|
||||||
|
'legalize: {} }}, // {}',
|
||||||
|
tyname, l2l, level2.hash_table_offset,
|
||||||
|
lcode, level2.legalize)
|
||||||
|
|
||||||
|
|
||||||
def offset_type(length):
|
def offset_type(length):
|
||||||
|
|||||||
@@ -6,9 +6,14 @@ Commonly used definitions.
|
|||||||
from __future__ import absolute_import
|
from __future__ import absolute_import
|
||||||
from cdsl.isa import TargetISA, CPUMode
|
from cdsl.isa import TargetISA, CPUMode
|
||||||
import base.instructions
|
import base.instructions
|
||||||
|
from base.legalize import narrow
|
||||||
|
|
||||||
ISA = TargetISA('arm32', [base.instructions.GROUP])
|
ISA = TargetISA('arm32', [base.instructions.GROUP])
|
||||||
|
|
||||||
# CPU modes for 32-bit ARM and Thumb2.
|
# CPU modes for 32-bit ARM and Thumb2.
|
||||||
A32 = CPUMode('A32', ISA)
|
A32 = CPUMode('A32', ISA)
|
||||||
T32 = CPUMode('T32', ISA)
|
T32 = CPUMode('T32', ISA)
|
||||||
|
|
||||||
|
# TODO: Refine these.
|
||||||
|
A32.legalize_type(narrow)
|
||||||
|
T32.legalize_type(narrow)
|
||||||
|
|||||||
@@ -6,6 +6,10 @@ Commonly used definitions.
|
|||||||
from __future__ import absolute_import
|
from __future__ import absolute_import
|
||||||
from cdsl.isa import TargetISA, CPUMode
|
from cdsl.isa import TargetISA, CPUMode
|
||||||
import base.instructions
|
import base.instructions
|
||||||
|
from base.legalize import narrow
|
||||||
|
|
||||||
ISA = TargetISA('arm64', [base.instructions.GROUP])
|
ISA = TargetISA('arm64', [base.instructions.GROUP])
|
||||||
A64 = CPUMode('A64', ISA)
|
A64 = CPUMode('A64', ISA)
|
||||||
|
|
||||||
|
# TODO: Refine these
|
||||||
|
A64.legalize_type(narrow)
|
||||||
|
|||||||
@@ -9,6 +9,20 @@ from .defs import I32, I64
|
|||||||
from . import recipes as r
|
from . import recipes as r
|
||||||
from . import settings as cfg
|
from . import settings as cfg
|
||||||
from . import instructions as x86
|
from . import instructions as x86
|
||||||
|
from base.legalize import narrow, expand
|
||||||
|
|
||||||
|
I32.legalize_type(
|
||||||
|
default=narrow,
|
||||||
|
i32=expand,
|
||||||
|
f32=expand,
|
||||||
|
f64=expand)
|
||||||
|
|
||||||
|
I64.legalize_type(
|
||||||
|
default=narrow,
|
||||||
|
i32=expand,
|
||||||
|
i64=expand,
|
||||||
|
f32=expand,
|
||||||
|
f64=expand)
|
||||||
|
|
||||||
for inst, opc in [
|
for inst, opc in [
|
||||||
(base.iadd, 0x01),
|
(base.iadd, 0x01),
|
||||||
|
|||||||
@@ -11,6 +11,20 @@ from .recipes import R, Rshamt, Ricmp, I, Iz, Iicmp, Iret, Icall, Icopy
|
|||||||
from .recipes import U, UJ, UJcall, SB, SBzero, GPsp, GPfi, Irmov
|
from .recipes import U, UJ, UJcall, SB, SBzero, GPsp, GPfi, Irmov
|
||||||
from .settings import use_m
|
from .settings import use_m
|
||||||
from cdsl.ast import Var
|
from cdsl.ast import Var
|
||||||
|
from base.legalize import narrow, expand
|
||||||
|
|
||||||
|
RV32.legalize_type(
|
||||||
|
default=narrow,
|
||||||
|
i32=expand,
|
||||||
|
f32=expand,
|
||||||
|
f64=expand)
|
||||||
|
|
||||||
|
RV64.legalize_type(
|
||||||
|
default=narrow,
|
||||||
|
i32=expand,
|
||||||
|
i64=expand,
|
||||||
|
f32=expand,
|
||||||
|
f64=expand)
|
||||||
|
|
||||||
# Dummies for instruction predicates.
|
# Dummies for instruction predicates.
|
||||||
x = Var('x')
|
x = Var('x')
|
||||||
|
|||||||
@@ -9,6 +9,11 @@ use isa::{Encoding, Legalize};
|
|||||||
use settings::PredicateView;
|
use settings::PredicateView;
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
|
|
||||||
|
/// Legalization action to perform when no encoding can be found for an instruction.
|
||||||
|
///
|
||||||
|
/// This is an index into an ISA-specific table of legalization actions.
|
||||||
|
pub type LegalizeCode = u8;
|
||||||
|
|
||||||
/// Level 1 hash table entry.
|
/// Level 1 hash table entry.
|
||||||
///
|
///
|
||||||
/// One level 1 hash table is generated per CPU mode. This table is keyed by the controlling type
|
/// One level 1 hash table is generated per CPU mode. This table is keyed by the controlling type
|
||||||
@@ -19,14 +24,15 @@ use std::ops::Range;
|
|||||||
/// have a power-of-two size.
|
/// have a power-of-two size.
|
||||||
///
|
///
|
||||||
/// Entries are generic over the offset type. It will typically be `u32` or `u16`, depending on the
|
/// Entries are generic over the offset type. It will typically be `u32` or `u16`, depending on the
|
||||||
/// size of the `LEVEL2` table. A `u16` offset allows entries to shrink to 32 bits each, but some
|
/// size of the `LEVEL2` table.
|
||||||
/// ISAs may have tables so large that `u32` offsets are needed.
|
|
||||||
///
|
///
|
||||||
/// Empty entries are encoded with a 0 `log2len`. This is on the assumption that no level 2 tables
|
/// Empty entries are encoded with a `!0` value for `log2len` which will always be out of range.
|
||||||
/// have only a single entry.
|
/// Entries that have a `legalize` value but no level 2 table have an `offset` field that is out f
|
||||||
|
/// bounds.
|
||||||
pub struct Level1Entry<OffT: Into<u32> + Copy> {
|
pub struct Level1Entry<OffT: Into<u32> + Copy> {
|
||||||
pub ty: Type,
|
pub ty: Type,
|
||||||
pub log2len: u8,
|
pub log2len: u8,
|
||||||
|
pub legalize: LegalizeCode,
|
||||||
pub offset: OffT,
|
pub offset: OffT,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,7 +50,7 @@ impl<OffT: Into<u32> + Copy> Table<Type> for [Level1Entry<OffT>] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn key(&self, idx: usize) -> Option<Type> {
|
fn key(&self, idx: usize) -> Option<Type> {
|
||||||
if self[idx].log2len != 0 {
|
if self[idx].log2len != !0 {
|
||||||
Some(self[idx].ty)
|
Some(self[idx].ty)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
@@ -55,7 +61,7 @@ impl<OffT: Into<u32> + Copy> Table<Type> for [Level1Entry<OffT>] {
|
|||||||
/// Level 2 hash table entry.
|
/// Level 2 hash table entry.
|
||||||
///
|
///
|
||||||
/// The second level hash tables are keyed by `Opcode`, and contain an offset into the `ENCLISTS`
|
/// The second level hash tables are keyed by `Opcode`, and contain an offset into the `ENCLISTS`
|
||||||
/// table where the encoding recipes for the instrution are stored.
|
/// table where the encoding recipes for the instruction are stored.
|
||||||
///
|
///
|
||||||
/// Entries are generic over the offset type which depends on the size of `ENCLISTS`. A `u16`
|
/// Entries are generic over the offset type which depends on the size of `ENCLISTS`. A `u16`
|
||||||
/// offset allows the entries to be only 32 bits each. There is no benefit to dropping down to `u8`
|
/// offset allows the entries to be only 32 bits each. There is no benefit to dropping down to `u8`
|
||||||
@@ -93,22 +99,28 @@ pub fn lookup_enclist<OffT1, OffT2>(ctrl_typevar: Type,
|
|||||||
where OffT1: Into<u32> + Copy,
|
where OffT1: Into<u32> + Copy,
|
||||||
OffT2: Into<u32> + Copy
|
OffT2: Into<u32> + Copy
|
||||||
{
|
{
|
||||||
// TODO: The choice of legalization actions here is naive. This needs to be configurable.
|
|
||||||
match probe(level1_table, ctrl_typevar, ctrl_typevar.index()) {
|
match probe(level1_table, ctrl_typevar, ctrl_typevar.index()) {
|
||||||
Err(_) => {
|
Err(l1idx) => {
|
||||||
// No level 1 entry for the type.
|
// No level 1 entry found for the type.
|
||||||
Err(if ctrl_typevar.lane_type().bits() > 32 {
|
// We have a sentinel entry with the default legalization code.
|
||||||
Legalize::Narrow
|
let l1ent = &level1_table[l1idx];
|
||||||
} else {
|
Err(l1ent.legalize.into())
|
||||||
Legalize::Expand
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
Ok(l1idx) => {
|
Ok(l1idx) => {
|
||||||
|
// We have a valid level 1 entry for this type.
|
||||||
let l1ent = &level1_table[l1idx];
|
let l1ent = &level1_table[l1idx];
|
||||||
let l2tab = &level2_table[l1ent.range()];
|
match level2_table.get(l1ent.range()) {
|
||||||
|
Some(l2tab) => {
|
||||||
probe(l2tab, opcode, opcode as usize)
|
probe(l2tab, opcode, opcode as usize)
|
||||||
.map(|l2idx| l2tab[l2idx].offset.into() as usize)
|
.map(|l2idx| l2tab[l2idx].offset.into() as usize)
|
||||||
.map_err(|_| Legalize::Expand)
|
.map_err(|_| l1ent.legalize.into())
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
// The l1ent range is invalid. This means that we just have a customized
|
||||||
|
// legalization code for this type. The level 2 table is empty.
|
||||||
|
Err(l1ent.legalize.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -126,6 +126,20 @@ pub enum Legalize {
|
|||||||
Expand,
|
Expand,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Translate a legalization code into a `Legalize` enum.
|
||||||
|
///
|
||||||
|
/// This mapping is going away soon. It depends on matching the `TargetISA.legalize_code()`
|
||||||
|
/// mapping.
|
||||||
|
impl From<u8> for Legalize {
|
||||||
|
fn from(x: u8) -> Legalize {
|
||||||
|
match x {
|
||||||
|
0 => Legalize::Narrow,
|
||||||
|
1 => Legalize::Expand,
|
||||||
|
_ => panic!("Unknown legalization code {}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Methods that are specialized to a target ISA.
|
/// Methods that are specialized to a target ISA.
|
||||||
pub trait TargetIsa {
|
pub trait TargetIsa {
|
||||||
/// Get the name of this ISA.
|
/// Get the name of this ISA.
|
||||||
|
|||||||
Reference in New Issue
Block a user