The Builder provides a convenient interface for inserting instructions
into an extended basic block.
The bulk of the builder methods are generated automatically from the
meta language instruction descriptions.
Still TODO: Keep track of an insertion position.
The Rust type is usually the camel-cased name of the operand kind, but
there are variations, so allow an explicit rust_type='IntCC' when
defining operand kinds.
These refer to external functions and function signatures declared in
the preamble. Since we're already using the type names 'Signature' and
'Function', these entity references don't folow the usual EntityData /
Entity naming convention.
Entity references in instruction format operands also have member names
in the InstructionData struct. Track them the same way we track immediate operand member names.
Value operands still go in the arg / args members.
Enable syntax: iadd(x, y) which creates an Apply node.
Enable syntax: z << iadd(x, y) which creates a Def node.
Add an XForm class which represents source and destination patterns as
RTL lists.
The isplit_lohi instruction breaks an integer into two halves. This will
typically be used to get the two halves of an `i64` value on 32-bit
CPUs.
The iconcat_lohi is the reverse operation. It reconstructs the `i64`
from the low and high bits.
The # is a more conventional prefix for hexadecimal, and when ISA
information is not available, there may be a decimal number in front
which would be confusing.
So prefer [1#10c] for the ISA-less encoding format. Here '1' is decimal
and '#10c' is hexadecimal.
Move all the byte-sized settings to the front of the byte-vector, and add a
mechanism for assigning numbers to predicates that have no name as well as
predicates from the parent settings group.
This way, all the boolean predicates that are used by a target ISA appear as a
contiguous bit-vector that is a suffix of the settings byte-vector. This
bit-vector can then be indexed linearly when resolving ISA predicates on
encodings.
Add a numbered_predicate() method to the generated Flags structs that can read
a predicate by number dynamically.
Three predicates affect each extension:
- supports_m determines whether the target CPU supports the instruction set.
- enable_m determines if the instructions should be used, assuming they're
available.
- use_m is the predicate used to actually use the instructions.
Compute the u16 representation of encoding lists and emit a big table
concatenating all of them. Use the UniqueSeqTable to share some table space
between CPU modes.
We need to generate hash tables keyed by types, so the Python scripts need to
know the index used to represent types in Rust code.
To enforce this, add a new gen_types.py script which generates constant
definitions for the ir/types module.
Also generate constants for common SIMD vector sizes.
When generating Rust code for an instruction predicate, call the corresponding
function in the predicates module, using a qualified name.
We don't have methods corresponding to the predicates.
This collects all of the leaf predicates that go into a compound predicate.
Current leaf predicates are:
- Settings for ISA predicates, and
- FieldPredicates for instruction predicates.
Add new instruction predicates to support the 'I' encoding recipe: IsSignedInt,
IsUnsignedInt used to test that an immediate operand is in the allowed range.
Each InstructionFormat instance gets data members corresponding to its immediate
operands, so the can be referred to as BinaryImm.imm, for example.
This will be used to construct instruction predicates.
Usually an instruction firmat has only a single immediate operand called 'imm',
or 'cond' if it is one of the condigtion codes. Add a 'default_member' field to
ImmediateKind to keep track of this default member name in the InstructionData
struct.
Predcates are boolean functions. There will be ISA predicates and instruction
predicates.
The ISA predicates will be turned into member functions on the generated Flags
structs.
Clarify terminology by always referring to a 'Target ISA' instead of just
'Target'. Use 'isa' as a module name instead of 'target' both in Rust and Python
code.
This is only to clarify terminology and not at all because Cargo insists on
using the 'target' sub-directory for build products. Oh, no. Not at all.
The shift instructions have two type variables since the shift amount can be a
differently sized integer. Fix the RISC-V shift encodings to reflect this, and
allow i64 registers to be shifted by an i32 amount.
Move the CPUMode reference from EncRecipe to the Encoding itself, allowing
EncRecipes to be shared between CPU modes. At least RISC-V should be able to
share some recipes between RV32 and RV64 modes.
It is possible to return multiple values from a function, so ReturnData contains
a VariableArgs instance.
We don't want return instructions to appear as 'return (v1)', so tweak the
printing of VariableArgs so the parantheses are added externally.