Age | Commit message (Collapse) | Author |
|
|
|
Some arm64 abi tests have been failing
for some time now. This fixes them by
being a bit more careful with liveset
management in spill.c.
A late bsclr() call in spill.c may drop
legitimately live registers in e.g.,
R12 =w add R12, 1
While it hurts for regs, it does not
matter for ssa temps because those cannot
be both in the arguments & return (by the
ssa invariant). I added a check before
bsclr() to make sure we are clearing
only ssa temps.
One might be surprised that any ssa temp
may be live at this point. The reason why
this is the case is the special handling
of dead return values earlier in spill().
I think that it is the only case where
the return value can be (awkwardly) live
at the same time as the arguments, and I
think this never happens with registers
(i.e., we never have dead register-
assigning instructions). I added an
assert to check the latter invariant.
Finally, there was a simple bug in the
arm64 abi which I fixed: In case the return
happens via a pointer, x8 needs to be marked
live at the beginning of the function. This
was caught by test/abi4.ssa.
|
|
|
|
|
|
|
|
The heuristic was bogus for at least
two reasons (see below), and, looking
at some generated code, it looks like
some other issues are more pressing.
1. A stack slot of 4 bytes could be
used for a temporary of 8 bytes.
2. Should 2 arguments of an operation
end up spilled, the same slot
could be allocated to both!
|
|
If an instruction does not have a result, the
variable `s` is not set. This could lead to a
bogus slot assignment.
|
|
On test/spill1.ssa, the stack frame of
the function f() goes from 56 bytes to
40 bytes. That's a reduction of close
to 30%.
This patch also opens the door to
folding operations on spill slots.
For example
movl $15, %r15d
addl -X(%rbp), %r15d
movl %r15d, -X(%rbp)
should become
add $15, -X(%rbp)
when %r15d is not used afterwards.
|
|
|
|
Instead of systematically spilling any
temp live in an exit branch but not in
the part of the loop already processed,
only spill when it is already known to
have been spilled.
|
|
If a variable is spilled in a loop, the
spiller now tries to keep it spilled over
the whole loop.
Thanks to Michael Forney for sharing a test
case exhibiting a pathological reload.
|
|
Compiler warned about comparison between signed and unsigned values.
|
|
I now take the view that a phi is "used" at the
end of all the predecessors. (Think that copies
are made to phis at the end of all predecessors.)
|
|
This big diff does multiple changes to allow
the addition of new targets to qbe. The
changes are listed below in decreasing order
of impact.
1. Add a new Target structure.
To add support for a given target, one has to
implement all the members of the Target
structure. All the source files where changed
to use this interface where needed.
2. Single out amd64-specific code.
In this commit, the amd64 target T_amd64_sysv
is the only target available, it is implemented
in the amd64/ directory. All the non-static
items in this directory are prefixed with either
amd64_ or amd64_sysv (for items that are
specific to the System V ABI).
3. Centralize Ops information.
There is now a file 'ops.h' that must be used to
store all the available operations together with
their metadata. The various targets will only
select what they need; but it is beneficial that
there is only *one* place to change to add a new
instruction.
One good side effect of this change is that any
operation 'xyz' in the IL now as a corresponding
'Oxyz' in the code.
4. Misc fixes.
One notable change is that instruction selection
now generates generic comparison operations and
the lowering to the target's comparisons is done
in the emitter.
GAS directives for data are the same for many
targets, so data emission was extracted in a
file 'gas.c'.
5. Modularize the Makefile.
The Makefile now has a list of C files that
are target-independent (SRC), and one list
of C files per target. Each target can also
use its own 'all.h' header (for example to
define registers).
|
|
The register allocation now has stricter assertions
about global registers. The stricter assertions
required changes in the spiller: We now correctly
indicate to the register allocator what registers
are used by "ret" instructions.
|
|
|
|
|
|
|
|
|
|
Inside the main instruction-processing loop, it is
taken care of by limit. However at block boundaries
we are doing fancy bitset operations without calling
limit.
|
|
|
|
|
|
|
|
|
|
int is used all over the place for temporaries,
maybe this should be changed, I don't know.
Another thing to consider is that temporaries
are currently on 12 bits (and will be on 29
or 30 bits in the future), so int will always be
safe to store them. We just loose the free
invariant of non-negativity.
|
|
|
|
|