It turns out that most encoding predicates are expressed as recipe
predicates. This means that the encoding tables can be more compact
since we can check the recipe predicate separately from individual
instruction predicates, and the recipe number is already present in the
table.
- Don't combine recipe and encoding-specific predicates when creating an
Encoding. Keep them separate.
- Generate a table of recipe predicates with function pointers. Many of
these are null.
- Check any recipe predicate before accepting a recipe+bits pair.
This has the effect of making almost all instruction predicates
CODE_ALWAYS.
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.
Generate code to:
- Unwrap the instruction and generate an error if the instruction format
doesn't match the recipe.
- Look up the value locations of register and stack arguments.
The recipe_* functions in the ISA binemit modules now take these
unwrapped items as arguments.
Also add an optional `emit` argument to the EncRecipe constructor which
makes it possible to provide inline Rust code snippets for code
emission. This requires a lot less boilerplate than recipe_* functions.
Add a Stack() class for specifying operand constraints for values on the
stack.
Add encoding recipes for RISC-V spill and fill instructions. Don't
implement the encoding recipe functions yet since we don't have the
stack slot layout yet.
Avoid spreading u32 as a bitmask of register classes throughout the
code.
Enforce the limit of 32 register classes total. This could easily be
raised if needed.
The MAX_TOPRCS constant is the highest possible number of top-level
register classes in an ISA. The RegClassData.toprc field is always
smaller than this limit.
A top-level register class is one that has no sub-classes. It is
possible to have multiple top-level register classes in the same
register bank. For example, ARM's FPR bank has both D and Q top-level
register classes.
Number register classes such that all top-level register classes appear
as a contiguous sequence starting from 0. This will be used by the
register allocator when counting used registers per top-level register
class.
The register constraint for an output operand can be specified as an
integer indicating the input operand number to tie. The tied operands
must use the same register.
Generate operand constraints using ConstraintKind::Tied(n) for both the
tied operands. The n index refers to the opposite array. The input
operand refers to the outs array and vice versa.
Two new pieces of information are available for all encoding recipes:
- The size in bytes of an encoded instruction, and
- The range of a branch encoded with the recipe, if any.
In the meta language, EncRecipe takes two new constructor arguments. The
size is required for all encodings and branch_range is required for all
recipes used to encode branches.
When defining an instruction encoding, allow part of the instruction
predicate to be provided as operands on the instruction opcode:
icmp.i32(intcc.ult, x, y)
This generates an instruction predicate that checks
IntCompare.cond == IntCC::UnsignedLessThan
The List and Dict types are no longer implicitly available. They must be
imported from typing.
Type annotations must appear before the doc comment in a function. Also
fix type errors in these functions that weren't detected before.
Ensure that the set of register classes is closed under intersection.
Provide a RegClass::intersect() method which finds the register class
representing the intersection of two classes.
Generate a bit-mask of subclasses for each register class to be used by
the intersect() method.
Ensure that register classes are sorted topologically. This is also used
by the intersect() method.
Every encoding recipe must specify register constraints on input and
output values.
Generate recipe constraint tables along with the other encoding tables.
Add a RegBank class for describing CPU register banks.
Define register banks for all the ISA stubs. The ARM32 floating point
bank in particular requires attention.