Stop passing Cursor references to legalizer functions. Give them the
whole &mut Function instead. Given the whole Function reference, these
functions can create their own cursors.
This lets legalizer actions access other Function data structures like
the global variables.
This will compute the stack frame layout as appropriate for the
function's calling convention and insert prologue and epilogue code.
The default implementation is not useful, each target ISA will need to
override this function.
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.
The new encoding format allows entries that mean "stop with this
legalization code" which makes it possible to configure legalization
actions per instruction, instead of only per controlling type variable.
This patch adds the Rust side of the legalization codes:
- Add an `Encodings::legalize()` method on the encoding iterator which
can be called after the iterator has returned `None`. The returned
code is either the default legalization action for the type, or a
specific code encountered in the encoding list.
- Change `lookup_enclist` to return a full iterator instead of just an
offset. The two-phase lookup can bail at multiple points, each time
with a default legalization code from the level 1 table. This default
legalization code is stored in the returned iterator.
- Change all the implementations of legal_encodings() in the ISA
implementations.
This change means that we don't need to return a Result any longer. The
`Encodings` iterator can be empty with an associated legalization code.
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.
The encoding tables contain references to numbered ISA predicates.
- Give the ISA Flags types a predicate_view() method which returns a
PredicateView.
- Delete the old predicate_bytes() method which returned a raw &[u8].
- Use a 'static lifetime for the encoding list slice in the Encodings
iterator, and a single 'a lifetime for everything else.
Register locations can change throughout an EBB. Make sure the
emit_inst() function considers this when encoding instructions and
update the register diversion tracker.
This function will emit the binary machine code into contiguous raw
memory while sending relocations to a RelocSink.
Add a MemoryCodeSink for generating machine code directly into memory
efficiently. Allow the TargetIsa to provide emit_function
implementations that are specialized to the MemoryCodeSink type to avoid
needless small virtual callbacks to put1() et etc.
Fixes#11.
Presets are groups of settings and values applied at once. This is used
as a shorthand in test files, so for example "isa intel nehalem" enables
all of the CPUID bits that the Nehalem micro-architecture provides.
* Implement an iterator over encodings
* Implement TargetIsa::legal_encodings
* Exclude non-boolean settings of isa flags bytes
* Address flake8 long line error
The legalize_signature() function will return ArgumentLoc::Reg arguments
that contain a register unit. However, the register also needs to be
able to associate a register class with the argument values to fully
track the used registers.
When values are defined by instructions, the register class is part for
the operand constraints for the instruction. For values defined on ABI
boundaries like function arguments and return values from a call, the
register class is provided by the new regclass_for_abi_type() function.
Provide implementations of this function in abi modules of all the
targets, even those that don't have a legalize_signature()
implementation yet.
Since we're adding abi modules to all targets, move the
legalize_signature() stubs in there and make the function mandatory in
TargetIsa. All targets will eventually need this function.
These special-purpose arguments and return values are only relevant for
the function being compiled, so add a `current` flag to
legalize_signature().
- Add the necessary argument values to the entry block to represent
the special-purpose arguments.
- Propagate the link and sret arguments to return instructions if the
legalized signature asks for it.
Soon, InstructionData won't have sufficient information to compute this.
Give TargetIsa::encode() an explicit ctrl_typevar argument. This
function does not require the instruction to be inserted in the DFG
tables.
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.
The tables returned by recipe_names() and recipe_constraints() are now
collected into an EncInfo struct that is available from
TargetIsa::encoding_info(). This is equivalent to the register bank
tables available fro TargetIsa::register_info().
This cleans of the TargetIsa interface and makes it easier to add
encoding-related information.
Not all br_icmp opcodes are present in the ISA. The missing ones can be
reached by commuting operands.
Don't attempt to encode EBB offsets yet. For now just emit an EBB
relocation for the branch instruction.
Use the meta language encoding recipes to generate an emit_inst()
function for each ISA. The generated calls into recipe_*() functions
that must be implemented by hand.
Implement recipe_*() functions for the RISC-V recipes.
Add the TargetIsa::emit_inst() entry point which emits an instruction to
a CodeSink trait object.
This entry point will be used for controlling ABI conventions when
legalizing.
Provide an empty implementation for RISC-V and let the other ISAs crash
in legalization.
This is just the scaffolding. We still need to:
- Rewrite the entry block arguments to match the legalized signature.
- Rewrite call and return instructions.
- Implement the legalize_signature() function for all ISAs.
- Add shared generic types to help with the legalize_signature()
functions.
An SSA value is usually biased towards a specific register class or a
stack slot, depending on the constraints of the instructions using it.
Represent this bias as an Affinity enum, and implement a merging
algorithm for updating an affinity to satisfy a new constraint.
Affinities will be computed as part of the liveness analysis. This is
not implemented yet.
Every encoding recipe must specify register constraints on input and
output values.
Generate recipe constraint tables along with the other encoding tables.
This set of available register units also manages register aliasing in
an efficient way.
Detect if the units in a register straddles mask words. The algorithm
for allocating multi-unit registers expect the whole register to be
inside a single mask word. We could handle this if necessary, but so far
no ISAs need it.
The intel, arm32, and arm32 targets were only defined in the meta
language previously. Add Rust implementations too.
This is mostly boilerplate, except for the unit tests in the
registers.rs files.
Give these crates each a more standard directory layout with sources in
a 'src' sub-sirectory and Cargo.toml in the top lib/foo directory.
Add license and description fields to each.
The build script for the cretonne crate now lives in
'lib/cretonne/build.rs' separating it from the normal library sources
under 'lib/cretonne/src'.