Fixes#147.
The Solver::reassign_in() method would previously not record fixed
register assignments for values that are already in the correct
register. The register would simply be marked as unavailable for the
solver.
This did have the effect of tripping up the sanity checks in
Solver::add_var() when that method was called with such a "reassigned"
value. The function can be called for a value that already has a fixed
assignment, but the sanity checks want to make sure the variable
constraints are compatible with the existing fixed assignment. When no
such assignment could be found, the method panicked.
To fix this, make sure that even identity reassignments are recorded
in the assignments vector. Instead, filter the identity assignments out
before scheduling a move sequence for the assignments.
Also add some debug tracing to the regalloc solver.
It's not necessary to explicitly track whether the last instruction is a
return; if the builder for the last block isn't filled by the time we reach
the end, it needs a return to fill it.
The phantom unreachable stack is only used when the real unreachable stack is
active, so it's sufficient to check whether the real unreachable stack is empty.
Use these encodings to test trapz.b1 and trapnz.b1.
When a b1 value is stored in a register, only the low 8 bits are valid.
This is so we can use the various setCC instructions to generate the b1
registers.
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.
Future legalization patterns will have the ability to mutate the
flowgraph, so the domtree's list of RPO blocks is not a good guide for
iteration. Use the layout order instead. This will pick up any new EBBs
inserted.
The expansion of a heap_addr instruction depends on the type of heap and
its configuration, so this is handled by custom code.
Add a couple examples of heap access code to the language reference
manual.
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.
The code to compute the address of a global variable depends on the kind
of variable, so custom legalization is required.
- Add a legalizer::globalvar module which exposes an
expand_global_addr() function. This module is likely to grow as we add
more types of global variables.
- Add a ArgumentPurpose::VMContext enumerator. This is used to represent
special 'vmctx' arguments that are used as base pointers for vmctx
globals.
The custom_legalize() method on XFormGroup can be used to call a
custom function to legalize specific opcodes.
This will be used shortly to expand global_addr which has an expansion
that depends on the details of the global variable being referenced.
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.
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.