Commit Graph

100 Commits

Author SHA1 Message Date
Denis Merigoux
07e1f682d0 Added Intel x86-64 encodings for 64bit loads and store instructions (#127)
* 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
2017-07-31 14:52:39 -07:00
Jakob Stoklund Olesen
54534e2147 Add Intel legalization for division and multiplication.
These operations need custom legalization in order to use Intel's div
and idiv instructions.
2017-07-28 16:41:59 -07:00
Jakob Stoklund Olesen
99d34cbbd7 Try to depend only on the ir module being in scope.
Generated code should used qualified names assuming that `ir` is in
scope, not everything else.
2017-07-28 16:33:02 -07:00
Jakob Stoklund Olesen
2aca35a9aa Return a function pointer from TargetIsa::encode().
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.
2017-07-27 17:08:00 -07:00
Denis Merigoux
b547b78683 Bugfix: encode function wasn't calling legalize function properly 2017-07-27 16:49:09 -07:00
Jakob Stoklund Olesen
84aeb3eb56 Generate type check predicates for secondary type variables.
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.
2017-07-26 08:19:44 -07:00
Jakob Stoklund Olesen
637966dc7f Add support for legalization codes in the encoding tables.
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.
2017-07-25 16:45:36 -07:00
Jakob Stoklund Olesen
2ccb261e8d Use a more compact encoding list representation.
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.
2017-07-25 15:38:55 -07:00
Jakob Stoklund Olesen
776af93ef2 Generate an INST_PREDICATES table for each ISA.
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.
2017-07-24 14:19:17 -07:00
Jakob Stoklund Olesen
f39d75fa58 Generate a RECIPE_PREDICATES table for each ISA.
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.
2017-07-24 14:19:17 -07:00
Jakob Stoklund Olesen
716cd26fbf Make legalization actions configurable.
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.
2017-07-24 12:49:06 -07:00
Jakob Stoklund Olesen
f651ec4f78 Add a PredicateView type to abstract the predicate bit vector a bit.
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.
2017-07-24 09:10:58 -07:00
Jakob Stoklund Olesen
4142a9ca9c Return a Result from constant_hash::probe.
When a hash table probe fails, return the index of the failed entry.
This can be used to store default values in the sentinel entries.
2017-07-21 21:10:32 -07:00
Jakob Stoklund Olesen
efdbf0d735 Add Intel encodings for jump and branch instructions.
Just implement jump, brz, and brnz as needed for WebAssembly.
2017-07-19 09:15:19 -07:00
Jakob Stoklund Olesen
53d9232d39 Track regmove instruction during binemit.
Register locations can change throughout an EBB. Make sure the
emit_inst() function considers this when encoding instructions and
update the register diversion tracker.
2017-07-18 12:52:53 -07:00
Jakob Stoklund Olesen
cf876e492a Add Intel encodings for imul. 2017-07-18 09:27:36 -07:00
Jakob Stoklund Olesen
2f7057b96f Add a Context::emit_to_memory function.
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.
2017-07-18 08:03:53 -07:00
Jakob Stoklund Olesen
f91d747bda Add support for setting presets.
Fixes #11.

Presets are groups of settings and values applied at once. This is used
as a shorthand in test files, so for example "isa intel nehalem" enables
all of the CPUID bits that the Nehalem micro-architecture provides.
2017-07-14 13:57:44 -07:00
Jakob Stoklund Olesen
435a15b88d Add Intel encodings for popcnt.
Change the result type for the bit-counting instructions from a fixed i8
to the iB type variable which is the type of the input. This matches the
convention in WebAssembly, and at least Intel's instructions will set a
full register's worth of count result, even if it is always < 64.

Duplicate the Intel 'ur' encoding recipe into 'umr' and 'urm' variants
corresponding to the RM and MR encoding variants. The difference is
which register is encoded as 'reg' and which is 'r/m' in the ModR/M
byte. A 'mov' register copy uses the MR variant, a unary popcnt uses the
RM variant.
2017-07-12 14:17:16 -07:00
Jakob Stoklund Olesen
a4a8c83aab Start adding Intel 64-bit encodings.
Add a TailRecipe.rex() method which creates an encoding recipe with a
REX prefix.

Define I64 encodings with REX.W for i64 operations and with/without REX
for i32 ops. Only test the with-REX encodings for now. We don't yet have
an instruction shrinking pass that can select the non-REX encodings.
2017-07-11 11:05:27 -07:00
Jakob Stoklund Olesen
fb227cb389 Move Intel recipe_* bodies into intel/recipes.py.
Use a PUT_OP macro in the TailRecipe Python class to replace the code
snippet that emits the prefixes + opcode part of the instruction encoding.

Prepare for the addition of REX prefixes by giving the PUT_OP functions
a third argument representing the REX prefix. For the non-REX encodings,
verify that no REX bits wold be needed.
2017-07-11 11:05:27 -07:00
Jakob Stoklund Olesen
528e6ff3f5 Generate instruction unwrapping code for binemit recipes.
Generate code to:

- Unwrap the instruction and generate an error if the instruction format
  doesn't match the recipe.
- Look up the value locations of register and stack arguments.

The recipe_* functions in the ISA binemit modules now take these
unwrapped items as arguments.

Also add an optional `emit` argument to the EncRecipe constructor which
makes it possible to provide inline Rust code snippets for code
emission. This requires a lot less boilerplate than recipe_* functions.
2017-07-07 15:10:17 -07:00
Jakob Stoklund Olesen
9662f102e5 Intel 32-bit encodings for copy.i32. 2017-07-05 15:48:06 -07:00
Jakob Stoklund Olesen
811c1059fc Add Intel call/return encodings. 2017-06-30 12:21:36 -07:00
Jakob Stoklund Olesen
c592d3174f Add Intel iconst.i32 encoding. 2017-06-30 11:41:06 -07:00
Jakob Stoklund Olesen
7bc2e82b16 Implement the basics of the x86-64 ABI.
This is just a rough sketch to get us started. There are bound to be
some issues.

This also legalizes signatures for x86-32, but probably not correctly.
It's basically implementing the x86-64 ABI for 32-bit.
2017-06-30 10:41:26 -07:00
Jakob Stoklund Olesen
05cf44a156 Add an offset to StackSlotData.
The offset is relative to the stack pointer in the calling function, so
it excludes the return address pushed by the call instruction itself on
Intel ISAs.

Change the ArgumentLoc::Stack offset to an i32, so it matches the stack
slot offsets.
2017-06-28 14:38:13 -07:00
Jakob Stoklund Olesen
e15c332471 Encode iconst.i32 for RISC-V.
For large constants with the low 12 bits clear, we already have the
"lui" encoding. Add "addi %x0" encodings for signed 12-bit constants.
2017-06-22 12:13:37 -07:00
Jakob Stoklund Olesen
b6cff6a98a Move EntityRef and entity_impl! into a new module.
The EntityRef trait is used by more than just the EntityMap now, so it
should live in its own module.

Also move the entity_impl! macro into the new module so it can be used
for defining new entity references anywhere.
2017-06-20 10:16:27 -07:00
Dan Gohman
0c7316ae28 Lint fixes (#99)
* 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.
2017-06-19 16:24:10 -07:00
Aleksey Kuznetsov
3693735874 Implement an iterator over encodings (#96)
* Implement an iterator over encodings

* Implement TargetIsa::legal_encodings

* Exclude non-boolean settings of isa flags bytes

* Address flake8 long line error
2017-06-19 08:52:19 -07:00
Jakob Stoklund Olesen
4503306f0e Add RISC-V encodings for call_indirect. 2017-06-14 16:14:16 -07:00
Jakob Stoklund Olesen
3e1e2b6e5e Add RISC-V encodings for copy instructions. 2017-06-14 15:36:25 -07:00
Jakob Stoklund Olesen
5336bbd4cc Add RISC-V encodings for spill and fill.
Add a Stack() class for specifying operand constraints for values on the
stack.

Add encoding recipes for RISC-V spill and fill instructions. Don't
implement the encoding recipe functions yet since we don't have the
stack slot layout yet.
2017-06-13 13:39:52 -07:00
Jakob Stoklund Olesen
6787a4ea5c Add a RegClassMask typedef and a MAX_TOPRCS constant.
Avoid spreading u32 as a bitmask of register classes throughout the
code.

Enforce the limit of 32 register classes total. This could easily be
raised if needed.

The MAX_TOPRCS constant is the highest possible number of top-level
register classes in an ISA. The RegClassData.toprc field is always
smaller than this limit.
2017-05-15 16:22:22 -07:00
Jakob Stoklund Olesen
71bb7483b7 Compute top-level register classes for each register bank.
A top-level register class is one that has no sub-classes. It is
possible to have multiple top-level register classes in the same
register bank. For example, ARM's FPR bank has both D and Q top-level
register classes.

Number register classes such that all top-level register classes appear
as a contiguous sequence starting from 0. This will be used by the
register allocator when counting used registers per top-level register
class.
2017-05-15 15:19:49 -07:00
Jakob Stoklund Olesen
621f3a2f50 Add a register bank index to RegClassData.
This makes it possible to find the register bank that contains a
register class.
2017-05-15 15:17:58 -07:00
Benjamin Bouvier
29dc723e25 Update rustfmt to 0.8.4; (#81) 2017-05-15 15:10:47 -07:00
Jakob Stoklund Olesen
bd8230411a Encodings for load/store instructions.
We don't support the full set of Intel addressing modes yet. So far we
have:

- Register indirect, no displacement.
- Register indirect, 8-bit signed displacement.
- Register indirect, 32-bit signed displacement.

The SIB addressing modes will need new Cretonne instruction formats to
represent.
2017-05-12 16:49:39 -07:00
Jakob Stoklund Olesen
f4929825ca Add subtract and logical instruction encodings to Intel-32.
Also add versions with 8-bit and 32-bit immediate operands.
2017-05-12 15:37:12 -07:00
Jakob Stoklund Olesen
31b7330b8d Return the first applicable encoding from general_encoding().
We'll arrange encoding lists such that the first suitable encoding is
the best choice for the legalizer. This is the most intuitive way of
generating the encodings.

After register allocation, we may choose a different encoding, but that
will require looking at the whole list.
2017-05-12 15:31:08 -07:00
Jakob Stoklund Olesen
6fd95c1158 Implement reloc_names() for all targets.
This gets rid of the last TargetIsa method with a default
implementation.
2017-05-11 17:58:11 -07:00
Jakob Stoklund Olesen
9be262e878 Implement a move resolver for the register constraint solver.
After finding a register solution, it need to be executed as a sequence
of regmove instructions. This often requires a topological ordering of
the moves so they don't conflict.

When the solution contains cycles, try to grab an available scratch
register to implement the copies. Panic if that fails (later, we'll
implement emergency spilling in this case).

Make sure we handle odd aliasing in the arm32 floating point register
bank. Not everything is a simple cycle in that case, so make sure we
don't assume so.
2017-05-11 11:54:02 -07:00
Jakob Stoklund Olesen
6b4c28d554 Use a constraint solver for register coloring.
Most of the time, register coloring is almost trivial: just pick
available registers for the values defined by the current instruction.
However, some instructions have register operand constraints, and it may
be necessary to move live registers around to satisfy the constraints.
Sometimes the instruction's own operands can interfere with each other
in a way that you can't just pick a register assignment for each output
in order.

This is complicated enough that it is worthwhile to represent as a
constraint satisfaction problem in a separate solver module. The
representation is chosen to be very fast in the common case where the
constraints are trivial to solve.

The current implementation is still incomplete, but as functional as the
code it's replacing. Missing features:

- Handle tied operand constraints.
- Handle ABI constraints on calls and return instructions.
- Execute a constraint solution by emitting regmove instructions.
- Handling register diversions before leaving the EBB.
2017-05-09 14:48:45 -07:00
Jakob Stoklund Olesen
a0085434af Add encodings for Intel dynamic shift instructions.
These instructions have a fixed register constraint; the shift amount is
passed in CL.

Add meta language syntax so a fixed register can be specified as
"GPR.rcx".
2017-05-09 13:11:50 -07:00
Jakob Stoklund Olesen
041fda63ac Add the very basics of Intel 32-bit instruction encodings.
Tabulate the Intel opcode representations and implement an OP() function
which computes the encoding bits.

Implement the single-byte opcode with a reg-reg ModR/M byte.
2017-05-08 16:57:38 -07:00
Jakob Stoklund Olesen
39e69ff565 Add constraint summaries to RecipeConstraints.
Most instructions don't have any fixed register constraints. Add boolean
summaries that can be used to check if it is worthwhile to scan the
constraint lists when looking for a fixed register constraint.

Also add a tied_ops summary bool which indicates that the instruction
has tied operand constraints.
2017-05-08 16:41:24 -07:00
Jakob Stoklund Olesen
0f41cbdee2 Add support for tied operand constraints.
The register constraint for an output operand can be specified as an
integer indicating the input operand number to tie. The tied operands
must use the same register.

Generate operand constraints using ConstraintKind::Tied(n) for both the
tied operands. The n index refers to the opposite array. The input
operand refers to the outs array and vice versa.
2017-05-08 16:31:47 -07:00
Jakob Stoklund Olesen
f8a3a01f96 Add a few register utilities. 2017-05-08 13:39:26 -07:00
Jakob Stoklund Olesen
aaa70a677d Add a regs_overlap function to the isa module.
Test it with the arm32 register banks which have the most interesting
properties. Most other registers have a single register unit.
2017-05-08 13:36:27 -07:00