We don't want to distinguish between single-result and multiple-result
instructions any longer.
- Merge the simple_instruction() and complex_instruction() builder
methods into a single build() that can handle all cases.
- All format constructors now take a ctrl_type argument. Previously,
some would take a result_type argument.
- Instruction constructors no longer attempt to compute a single result
type. Just pass a ctrl_type and let the backend decide.
Fix one format constructor call in legalizer/split.rs which now takes a
ctrl_type instead of a result type.
Now we can access instruction results and arguments as well as EBB
arguments as slices.
Delete the Values iterator which was traversing the linked lists of
values. It is no longer needed.
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.
This instruction behaves like icmp fused with brnz, and it can be used
to represent fused compare+branch instruction on Intel when optimizing
for macro-op fusion.
RISC-V provides compare-and-branch instructions directly, and it is
needed there too.
Compare a scalar integer to an immediate constant. Both Intel and RISC-V
ISAs have this operation.
This requires the addition of a new IntCompareImm instruction format.
When defining an instruction encoding, allow part of the instruction
predicate to be provided as operands on the instruction opcode:
icmp.i32(intcc.ult, x, y)
This generates an instruction predicate that checks
IntCompare.cond == IntCC::UnsignedLessThan
Compute an instruction predicate from any constant values given as
arguments for the immediate operands in an instruction pattern.
Allows for patterns like icmp.i32(intcc.ugt, x, y) or iadd_imm.i32(x, 1)
Trap these predicates in the legalizer code generator since we can't
actually handle them yet.
Consolidate the imm_members and imm_kinds into this list so the
FormatField is the single definition of these properties.
This makes it easier to access the precomputed FormatFields
parametrically, avoiding going through getattr().
This is better for type checking too.
The meta language patterns sometimes need to refer to specific values of
enumerated immediate operands. The dot syntax provides a namespaced,
typed way of doing that: icmp(intcc.ult, a, x).
Add an ast.Enumerator class for representing this kind of AST leaf node.
Add value definitions for the intcc and floatcc immediate operand kinds.
These two instructions make sense for vector types by simply performing
the same operation on each lane, like most other vector operations.
Problem found by @angusholder's verifier.
The carry and borrow values are boolean, so we have to convert them to
an integer type with bint(c) before we can add them to the result.
Also tweak the default legalizer action for unsupported types: Only
attempt a narrowing pattern for lane types > 32 bits.
This was found by @angusholder's new type checks in the verifier.
* Verify that a recomputed dominator tree is identical to the existing one.
* The verifier now typechecks instruction results and arguments.
* The verifier now typechecks instruction results and arguments.
* The verifier now typechecks instruction results and arguments.
* Added `inst_{fixed,variable}_args` accessor functions.
* Improved error messages in verifier.
* Type check return statements against the function signature.
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.
When the legalizer splits a value into halves, it would previously stop
if the value was an EBB argument. With this change, we also split EBB
arguments and iteratively split arguments on branches to the EBB.
The iterative splitting stops when we hit the entry block arguments or
an instruction that isn't one of the concatenation instructions.
Legalizing some instructions may require modifications to the control
flow graph, and some operations need to use the CFG analysis.
The CFG reference is threaded through all the legalization functions to
reach the generated expansion functions as well as the legalizer::split
module where it will be used first.
The legalizer often splits values into parts with the vsplit and
isplit_lohi instructions. Avoid doing that for values that are already
defined by the corresponding concatenation instructions.
This reduces the number of instructions created during legalization, and
it simplifies later optimizations. A number of dead concatenation
instructions are left behind. They can be trivially cleaned up by a dead
code elimination pass.
Instead, just return the first of the detached values, and provide a
next_secondary_result() method for traversing the list.
This is equivalent to how detach_ebb_args() works, and it allows the
data flow graph to be modified while traversing the list of results.
Now that some instruction formats put all of their value arguments in a
value list, we need to know how many value are fixed and how many are
variable_args.
CC @angusholder who may need this information in the verifier.
Any code that needs to manipulate a variable argument list on an
instruction will need to remove the instruction's value list first,
change the list, and then put it back on the instruction. This is
required to avoid fighting the borrow checker over mutable locks on the
DataFlowGraph and its value list pool.
Add a generated InstructionData::take_value_list() method which lifts
out and existing value list and returns it, levaing an empty list in its
place, like Option::take() does it.
Add a generated InstructionData::put_value_list() which puts it back,
verifying that no existing value list is overwritten.
The value_list flag can be inferred from the presence of VARIABLE_ARGS
in the operand list.
The boxed_storage flag is obsolete. We don't need boxed storage anywhere
no that we have value lists instead.
Allow some flexibility in the signature matching for instruction
formats. In particular, look for a value list format as a second chance
option.
The Return, ReturnReg, and TernaryOverflow formats all fit the single
MultiAry catch-all format for instructions without immediate operands.
No instruction sets actually have single instructions for materializing
vector constants. You always need to use a constant pool.
Cretonne doesn't have constant pools yet, but it will in the future, and
that is how vector constants should be represented.
Instruction formats are now identified by a signature that doesn't
include the ordering of value operands relative to immediate operands.
This means that the BinaryRev instruction format becomes redundant, so
delete it. The isub_imm instruction was the only one using that format.
Rename it to irsub_imm to make it clear what it does now that it is
printed as 'irsub_imm v2, 45'.