Age | Commit message (Collapse) | Author |
|
parseref() has code to reuse address constants, but this is not
done in other passes such as fold or isel. Introduce a new function
newcon() which takes a Con and returns a Ref for that constant, and
use this whenever creating address constants.
This is necessary to fix folding of address constants when one
operand is already folded. For example, in
%a =l add $x, 1
%b =l add %a, 2
%c =w loadw %b
%a and %b were folded to $x+1 and $x+3 respectively, but then the
second add is visited again since it uses %a. This gets folded to
$x+3 as well, but as a new distinct constant. This results in %b
getting labeled as bottom instead of either constant, disabling the
replacement of %b by a constant in subsequent instructions (such
as the loadw).
|
|
|
|
Some abis, like the riscv one, treat
arguments differently depending on
whether they are variadic or not.
To prepare for the upcomming riscv
target, we change the variadic call
syntax and give meaning to the
location of the '...' marker.
# new syntax
%ret =w call $f(w %regular, ..., w %variadic)
By nature of their abis, the change
is backwards compatible for existing
targets.
|
|
Reported by Alessandro Mantovani.
These addresses are likely bogus, but
they triggered an unwarranted assertion
failure. We now raise a civilized error.
|
|
This now only limits the number of arguments when parsing the input SSA,
which is usually a small fixed size (depending on the frontend).
|
|
|
|
|
|
Slots are stored as `int` in Fn, so use the same type in Tmp.
Rearrange the fields in Tmp slightly so that sizeof(Tmp) stays the same
(at least on 64-bit systems).
|
|
Michael Forney needs this to run his
compiler on interesting programs.
|
|
Previously, we would skip ssa construction when
a temporary has a single definition. This is
only part of the ssa invariant: we must also
check that all uses are dominated by the single
definition. The new code does this.
In fact, qbe does not store all the dominators
for a block, so instead of walking the idom
linked list we use a rough heuristic and declare
conservatively that B0 dominates B1 when one of
the two conditions is true:
a. B0 is the start block
b. B0 is B1
Some measurements on a big file from Michael
Forney show that the code is still as fast as
before this patch.
|
|
|
|
They are now linear and can be
safely used with arguments that
have side-effects. This patch
also introduces an iscall()
macro and uses it to fix a
missing check for Ovacall in
liveness analysis.
|
|
The arm64 might have the same problem but it
is currently unable to handle them even in
instruction selection.
Thanks to Jean Dao for reporting the bug.
|
|
The stashing of constants in gas.c was also
changed to support 16-bytes constants.
|
|
|
|
Symbols in the source file are still limited in
length because the rest of the code assumes that
strings always fit in NString bytes.
Regardless, there is already a benefit because
comparing/copying symbol names does not require
using strcmp()/strcpy() anymore.
|
|
The previous heuristics were ad hoc and it was
hard to understand why they worked at all.
This patch can be summarized in three points:
1. When a register is freed (an instruction
assigns it), we try to find if a temporary
would like to be in it, and if we find one,
we move it in the newly freed register.
I call this an "eager move".
2. Temporaries now remember in what register
they were last allocated; this information
is stored in the field Tmp.visit, and
prevails on the field Tmp.hint when it is
set. (This makes having the same hint for
interfering temporaries not so disastrous.)
3. Blocks are now allocated in "onion" order,
from the innermost loop to the outermost.
This is the change I am the least sure
about; it should be evaluated thorougly.
|
|
Ori needs this. It should not cost much more memory at runtime,
only a minimal amount of address space.
|
|
The previous code was buggy. It would put a stack
pointer on the heap when handling "add $foo, 42".
The new code is more straightforward and hopefully
more correct. Only temporaries with a "stack"
alias class will have a slot pointer.
|
|
With the default toolchain, it looks like we have to
make sure all symbols are loaded using rip-relative
addressing.
|
|
The arm64 ABI needs to know precisely what
floating point types are being used, so we
need to store that information.
I also made typ[] a dynamic array.
|
|
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).
|
|
Notably, this adds a new pass to get rid of
jumps on jumps.
|
|
|
|
|
|
When a temporary marked local is escaping,
the whole slot must be marked as such. To
solve this, Alias now holds a pointer to
the alias information of the slot. For
simplicity of the code, this pointer is
always valid and fetching ->type out of it
is meaningful.
|
|
|
|
Compiling languages with closures often requires passing
an extra environment parameter to the called function.
One solution is to use a convention, and reserve, say,
the first argument for that purpose. However, that
makes binding to C a little less smooth.
Alternatively, QBE now provides a way to remain fully
ABI compatible with C by having a "hidden" environment
argument (marked with the keyword 'env'). Calling a
function expecting an environment from C will make the
contents of the environment undefined, but the normal
arguments will be passed without alteration. Conversely,
calling a C function like it is a closure by passing
it an environemnt will work smoothly.
|
|
|
|
This change is backward compatible, calls to
"variadic" functions (like printf) must now be
annotated (with ...).
|
|
|
|
When an edge is deleted, the phis and predecessors of the
destination block have to be updated. This is what blkdel()
was doing, but at a level too coarse. The new function
edgedel() allows to remove a single edge (and takes care of
multiple edges).
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
The type sizes are important to get right because
the ABI relies on them when it emits memory blits
to pass/return structs.
|
|
|
|
|
|
|
|
|
|
|