Rename the ArgumentType type to AbiParam since it describes the ABI
characteristics of a parameter or return value, not just the value type.
In Signature, rename members argument_types and return_types to "params"
and "returns". Again, they are not just types.
Fix a couple lingering references to "EBB arguments".
Add EBB parameter and EBB argument to the langref glossary to clarify
the distinction between formal EBB parameter values and arguments passed
to branches.
- Replace "ebb_arg" with "ebb_param" in function names that deal with
EBB parameters.
- Rename the ValueDef variants to Result and Param.
- A bunch of other small langref fixes.
No functional changes intended.
On some ISAs like Intel's, all arithmetic instructions set all or some
of the CPU flags, so flag values can't be live across these
instructions. On ISAs like ARM's Aarch32, flags are clobbered by compact
16-bit encodings but not necessarily by 32-bit encodings of the same
instruction.
The "clobbers_flags" bit on the encoding recipe is used to indicate if
CPU flag values can be live across an instruction, or conversely whether
the encoding can be used where flag values are live.
The arm32 ISA technically has separate floating point and integer flags,
but the only useful thing you can do with the floating point flags is to
copy them ti the integer flags, so there is not need to model them.
The arm64 ISA fixes this and the fcmp instruction writes the integer
nzcv flags directly.
RISC-V does not have CPU flags.
This makes it possible to define register banks that opt out of register
pressure tracking. This will be used to define banks for special-purpose
registers like the CPU flags.
The pressure tracker does not need to use resources for a top-level
register class in a non-tracked bank. The constant MAX_TOPRCS is renamed
to MAX_TRACKED_TOPRCS to indicate that there may be top-level register
classes with higher numbers, but they won't require pressure tracking.
We won't be tracking register pressure for CPU flags since only one
value is allowed to be live at a time.
The word "scalar" is a bit vague and tends to mean "non-vector". Since
we are about to add new CPU flag value types that can't appear as vector
lanes, make the distinction clear: LaneType represents value types that
can appear as a vector lane.
Also replace the Type::is_scalar() method with an is_vector() method.
When solver variables represent operands on the current instruction,
they need to be constrained as required by the instructions, but
variables that are simply moved out of the way should only be
constrained to their top-level register class. The live range affinity
is just a hint, not a requirement.
When "binemit" tests encode instructions, keep track of the current set
of register diversions, and use the diverted locations to check operand
constraints.
This matches how constraints are applied during a real binemit phase.
The register constraint solver schedules a set of move instructions to
execute before the instruction getting colored. In extreme cases, this
is not possible because there are no available registers to break cycles
in the register assignments that must be scheduled.
When that happens, we spill one register to an emergency slot so it
becomes available for implementing the assignment cycle. Then the
original register is restored.
The coloring pass can't yet understand the spill and fill move types.
This will be implemented next.
This makes it possible to materialize new RegClass references without
requiring a RegInfo reference to be passed around.
- Move the RegInfo::toprc() method to RegClassData.
- Rename RegClassData::intersect() to intersect_index() and provide a
new intersect() which returns a register class.
- Remove some &RegInfo parameters that are no longer needed.
It can happen that the currently live registers are blocking a smaller
register class completely, so the only way of solving the allocation
problem is to turn some of the live-through registers into solver
variables.
When the quick_solve attempt fails, try to free up registers in the
critical register class by turning live-through values into solver
variables.
The x86_divmodx traps on integer overflow, but the srem instruction is
not supposed to trap with a -1 divisor.
Generate a legalization expansion for srem that special-cases the -1
divisor to simply return 0.
An f64 can represent multiple values in the range INT_MIN-1 < x <=
INT_MIN which all truncate to INT_MIN, so comparing the input value
against INT_MIN is not good enough.
Instead, detect overflow on x <= INT_MIN-1 when INT_MIN-1 is an exact
floating point value.
Also make sure we generate type checks for the controlling type variable
in legalization patterns. This is not needed for encodings since the
encoding tables are already keyed on the controlling type variable.
In 32-bit mode, all function arguments are passed on the stack, not in
registers.
This ABI support is not complete or properly tested, but at least it
doesn't try to pass arguments in r8.
The native x86_fmin and x86_fmax instructions don't behave correctly for
NaN inputs and when comparing +0.0 to -0.0, so we need separate branches
for those cases.
To begin with, these are catch-all encodings with a SIB byte and a
32-bit displacement, so they can access any stack slot via both the
stack pointer and the frame pointer.
In the future, we will add encodings for 8-bit displacements as well as
EBP-relative references without a SIB byte.
This contains encoding details for a stack reference: The base register
and offset to use in the specific instruction encoding.
Generate StackRef objects called in_stk0 etc for the binemit recipe
code. All binemit recipes need to compute base pointer offsets for stack
references, so have the automatically generated code do it.
This makes the details of the spiderwasm prologue configurable so it is
easier to modify SpiderMonkey without having to change Cretonne.
Create a stack object representing the SpiderMonkey prologue words
before calculating the stack layout so they won't be overwritten by
Cretonne's stack objects.
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.
* Added Intel x86-64 encodings for 64bit loads and store instructions
* Using GPR registers instead of ABCD for istore8 with REX prefix
Fixed testing of 64bit intel encoding
* Emit REX and REX-less encodings for optional REX prefix
Value renumbering in binary64.cton
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 encoding tables are keyed by the controlling type variable only. We
need to distinguish different encodings for instructions with multiple
type variables.
Add a TypePredicate instruction predicate which can check the type of an
instruction value operand. Combine type checks into the instruction
predicate for instructions with more than one type variable.
Add Intel encodings for fcvt_from_sint.f32.i64 which can now be
distinguished from fcvt_from_sint.f32.i32.
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.
Encodings has a 16-bit "recipe" field, but even Intel only has 57
recipes currently, so it is unlikely that we will ever need to full
range. Use this to represent encoding lists more compactly.
Change the encoding list to a format that:
- Doesn't need a predicate entry before every encoding entry.
- Doesn't need a terminator after the list for each instruction.
- Supports multiple "stop codes" for configurable guidance of the
legalizer.
The encoding scheme has these limits:
- 2*NR + NS <= 0x1000
- INSTP + ISAP <= 0x1000
Where:
- NR is the number of recipes in an ISA,
- NS is the number of stop codes (legalization actions).
- INSTP is the number of instruction predicates.
- ISAP is the number of discrete ISA predicates.
Instead of generating a single `check_instp()` function, create an array
of individual function pointers for checking instruction predicates.
This makes explicit the jump table in the old check_instp() method and
it gives us a way of determining the number of instruction predicates
that exists.
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.
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.