Adds support for transforming integer division and remainder by constants
into sequences that do not involve division instructions.
* div/rem by constant powers of two are turned into right shifts, plus some
fixups for the signed cases.
* div/rem by constant non-powers of two are turned into double length
multiplies by a magic constant, plus some fixups involving shifts,
addition and subtraction, that depends on the constant, the word size and
the signedness involved.
* The following cases are transformed: div and rem, signed or unsigned, 32
or 64 bit. The only un-transformed cases are: unsigned div and rem by
zero, signed div and rem by zero or -1.
* This is all incorporated within a new transformation pass, "preopt", in
lib/cretonne/src/preopt.rs.
* In preopt.rs, fn do_preopt() is the main driver. It is designed to be
extensible to transformations of other kinds of instructions. Currently
it merely uses a helper to identify div/rem transformation candidates and
another helper to perform the transformation.
* In preopt.rs, fn get_div_info() pattern matches to find candidates, both
cases where the second arg is an immediate, and cases where the second
arg is an identifier bound to an immediate at its definition point.
* In preopt.rs, fn do_divrem_transformation() does the heavy lifting of the
transformation proper. It in turn uses magic{S,U}{32,64} to calculate the
magic numbers required for the transformations.
* There are many test cases for the transformation proper:
filetests/preopt/div_by_const_non_power_of_2.cton
filetests/preopt/div_by_const_power_of_2.cton
filetests/preopt/rem_by_const_non_power_of_2.cton
filetests/preopt/rem_by_const_power_of_2.cton
filetests/preopt/div_by_const_indirect.cton
preopt.rs also contains a set of tests for magic number generation.
* The main (non-power-of-2) transformation requires instructions that return
the high word of a double-length multiply. For this, instructions umulhi
and smulhi have been added to the core instruction set. These will map
directly to single instructions on most non-intel targets.
* intel does not have an instruction exactly like that. For intel,
instructions x86_umulx and x86_smulx have been added. These map to real
instructions and return both result words. The intel legaliser will
rewrite {s,u}mulhi into x86_{s,u}mulx uses that throw away the lower half
word. Tests:
filetests/isa/intel/legalize-mulhi.cton (new file)
filetests/isa/intel/binary64.cton (added x86_{s,u}mulx encoding tests)
This is the floating point equivalent of trapif: Trap when a given
condition is in the floating-point flags.
Define Intel encodings comparable to the trapif encodings.
This enables code generation that never causes a SIGFPE signal to be
raised from a division instruction. Instead, division and remainder
calculations are protected by explicit traps.
This instruction loads a stack limit from a global variable and compares
it to the stack pointer, trapping if the stack has grown beyond the
limit.
Also add a expand_flags transform group containing legalization patterns
for ISAs with CPU flags.
Fixes#234.
The instruction set has variants with 8-bit and 32-bit signed immediate
operands.
Add a TODO to use a TEST instruction for the special case ifcmp_imm x, 0.
Changes:
* Adds a new generic instruction, SELECTIF, that does value selection (a la
conditional move) similarly to existing SELECT, except that it is
controlled by condition code input and flags-register inputs.
* Adds a new Intel x86_64 variant, 'baseline', that supports SSE2 and
nothing else.
* Adds new Intel x86_64 instructions BSR and BSF.
* Implements generic CLZ, CTZ and POPCOUNT on x86_64 'baseline' targets
using the new BSR, BSF and SELECTIF instructions.
* Implements SELECTIF on x86_64 targets using conditional-moves.
* new test filetests/isa/intel/baseline_clz_ctz_popcount.cton
(for legalization)
* new test filetests/isa/intel/baseline_clz_ctz_popcount_encoding.cton
(for encoding)
* Allow lib/cretonne/meta/gen_legalizer.py to generate non-snake-caseified
Rust without rustc complaining.
Fixes#238.
* Switch RegClass to a bitmap implementation.
* Add special RegClass to remove r13 from 'ld' recipe.
* Use MASK_LEN constant instead of magic number.
* Enforce that RegClass slicing is only valid on contiguous classes.
* Use Optional[int] for RegClass optional bitmask parameter.
* Add comment explaining use of Intel ISA's GPR_NORIP register class.
Add an addend field to reloc_external, and use it to move the
responsibility for accounting for the difference between the end of an
instruction (where the PC is considered to be in PC-relative on intel)
and the beginning of the immediate field into the encoding code.
Specifically, this makes IntelGOTPCRel4 directly correspond to
R_X86_64_GOTPCREL, instead of also carrying an implicit `- 4`.
* Use imm64 rather than offset32
* Add predicate to enforce signed 32-bit limit to imm
* Remove AdjustSpImm format
* Add encoding tests for adjust_sp_imm
* Adjust use of adjust_sp_imm in Intel prologue_epilogue to match
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.
The register allocator can't handle branches with constrained register
operands, and the brz.b1/brnz.b1 instructions only have the t8jccd_abcd
in 32-bit mode where no REX prefixes are possible.
This adds a worst case encoding for those cases where a b1 value lives
in a non-ABCD register.
These spills and fills use 32-bit writes, knowing that the spill slot is
minimum 4 bytes which makes it safe.
Also simplify the definition of load/store encodings a bit by
introducing loops.
Most recipes with an ABCD constraint can handle the full GPR register
class when a REX prefix is applied, but not all. The "icscc" macro
recipe always generates a setCC instruction with no REX prefix, so it
can only write the ABCD registers, even in its REX form.
Don't automatically rewrite ABCD constraints to GPR constraints when
applying a REX prefix to a tail recipe. Instead, allow individual ABCD
recipes to specify a "when_prefixed" alternative recipe to use. This
also eliminates the spurious Rex*abcd recipe names which didn't have an
ABCD constraint.
Also allow recipes to specify that a REX prefix is required by setting
the prefix_required flag. This is used by recipes like t8jccb which
explicitly accesses an 8-bit register with a GPR constraint which is
only valid with a prefix.
Some REX-less encodings require an ABCD input because they are looking
at 8-bit registers. This constraint doesn't apply with a REX prefix
where the low 8 bits of all registers are addressable.
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 brz and brnz instructions get support for 32-bit jump displacements
for long range branches.
Also change the way branch ranges are specified on tail recipes for the
Intel instructions. All branch displacements are relative to the end of
the instruction, so just compute the branch range origin as the
instruction size instead of trying to specify it in the tail recipe
definitions.
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.