Add integer and floating comparison instructions that return CPU flags:
ifcmp, ifcmp_imm, and ffcmp.
Add conditional branch instructions that check CPU flags: brif, brff
Add instructions that check a condition in the CPU flags and return a
b1: trueif, trueff.
This is a verification pass that can be run after register allocation.
It verifies that value locations are consistent with constraints on
their uses, and that the register diversions are consistent.
Make it clear that register diversions are local to an EBB only. This
affects what branch relaxation is allowed to do.
The verify_locations() takes an optional Liveness parameter which is
used to check that no diverted values are live across CFG edges.
These are parallels to the existing regmove instruction, but the divert
the value to and from a stack slot.
Like regmove diversions, this is a temporary diversion that must be
local to the EBB.
The extend and reduce instructions have additional type constraints.
Stop inserting sextend instructions after ctz, clz, and popcnt when
translating from WebAssembly. The Cretonne instructions have the same
signature as the WebAssembly equivalents.
These formats are not used any longer after the heap_load and heap_store
instructions were replaced by heap_addr.
Also drop the Uoffset32 immediate operand type which isn't used either.
Add a settings::FlagsOrIsa struct which represents a flags reference and
optionally the ISA it belongs to. Use this for passing flags/isa
information to the verifier.
The verify_function() and verify_context() functions are now generic so
they accept either a &Flags or a &TargetISa argument.
Fix the return_at_end verifier tests which no longer require an ISA
specified. The signle "set return_at_end" flag setting now makes it to
the verifier even when no ISA is present to carry it.
* Make passes assert their dependencies consistently.
This avoids ambiguity about whose responsibility it is to run
to compute cfg, domtree, and loop_analysis data.
* Reset the `valid` flag in DominatorTree's `clear()`.
* Remove the redundant assert from DominatorTree::with_function.
* Remove the message strings from obvious asserts.
This avoids having them spill out into multiple lines.
* Refactor calls to `compute` on `Context` objects into helper functions.
The flag guarantees that the generated function does not have any
internal return instructions. If the function returns at all, the return
must be the last instruction.
For now just implement a verifier check for this property. When we get
CFG simplifiers and block layout optimizations, they will need to heed
the flag.
The legalizer can invalidate the dominator tree, but we don't actually
need a dominator tree during legalization, so defer the construction of
the domtree.
- Add an "invalid" state to the dominator tree along with clear() and
is_valid() methods to test it.
- Invalidate the dominator tree as part of legalization.
- Ensure that a valid dominator tree exists before the passes that need
it.
Together these features add up to a manual invalidation mechanism for
the dominator tree.
Add preamble syntax for declaring static and dynamic heaps, and update
the langref section on heaps. Add IR support for heap references.
Remove the heap_load and heap_store as discussed in #144. We will use
heap_addr along with native load and store instructions in their place.
Add the heap_addr instruction and document its bounds checking
semantics.
The new PrimaryMap replaces the primary EntityMap and the PrimaryEntityData
marker trait which was causing some confusion. We now have a clear
division between the two types of maps:
- PrimaryMap is used to assign entity numbers to the primary data for an
entity.
- EntityMap is a secondary mapping adding additional info.
The split also means that the secondary EntityMap can now behave as if
all keys have a default value. This means that we can get rid of the
annoying ensure() and get_or_default() methods ther were used everywhere
instead of indexing. Just use normal indexing now; non-existent keys
will return the default value.
See #144 for discussion.
- Add a new GlobalVar entity type both in Python and Rust.
- Define a UnaryGlobalVar instruction format containing a GlobalVar
reference.
- Add a globalvar.rs module defining the GlobalVarData with support for
'vmctx' and 'deref' global variable kinds.
Langref:
Add a section about global variables and the global_addr
instruction.
Parser:
Add support for the UnaryGlobalVar instruction format as well as
global variable declarations in the preamble.
Once a signature has been legalized, the arguments to any call using
that signature must be assigned to the proper stack locations. Outgoing
arguments that are passed on the stack must be assigned to matching
OutgoingArg stack slot locations.
Outgoing arguments that are passed in registers don't need to appear in
the correct registers until after register allocation.
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.
A fallthrough jump is actually represented as 0 bytes, so no encoding is
needed.
Also allow for unencoded instructions in the generated emit_inst
implementations. The verifier has stricter rules for when this is
allowed.
We allow ghost instructions to exist if they have no side effects.
Instructions that affect control flow or that have other side effects
must be encoded.
Teach the IL verifier to enforce this. Once any instruction has an
encoding, all instructions with side effects must have an encoding.
* Replace a single-character string literal with a character literal.
* Use is_some() instead of comparing with Some(_).
* Add code-quotes around type names in comments.
* Use !...is_empty() instead of len() != 0.
* Tidy up redundant returns.
* Remove redundant .clone() calls.
* Remove unnecessary explicit lifetime parameters.
* Tidy up unnecessary '&'s.
* Add parens to make operator precedence explicit.
* Use debug_assert_eq instead of debug_assert with ==.
* Replace a &Vec argument with a &[...].
* Replace `a = a op b` with `a op= b`.
* Avoid unnecessary closures.
* Avoid .iter() and .iter_mut() for iterating over containers.
* Remove unneeded qualification.
This means that we can verify the basics with verify_context before
moving on to verifying the liveness information.
Live ranges are now verified immediately after computing them and after
register allocation is complete.
The liveness verifier will check that the live ranges are consistent
with the function. It runs as part of the register allocation pipeline
when enable_verifier is set.
The initial implementation checks the live ranges, but not the
ISA-specific constraints and affinities.