When extern was added, the rv64 code switched regular globals from
using la (a pseudo-instruction that uses pc-relative addressing
with auipc + addi) to lui + addi (absolute addressing). Presumably,
this was done to match gcc's output with -fPIC and -fno-PIC
respectively. However, the key difference here is actually the
directive `%option pic` vs `%option nopic`, which determines whether
la uses the GOT or not.
This broke linking as PIE (for instance in compilers with
--enable-default-pie), even when there are no global references
outside the executable. The other architectures always use pc-relative
addressing, so rv64 should do the same.
It turns out there are more specific pseudo-instructions lla and
lga we can use instead. lla uses auipc+addi, and lga uses auipc+ld
from the GOT.
lga does not allow an offset. If you try to use one, it will assemble
without error, but fail at link time with
(.text+0x10): dangerous relocation: The addend isn't allowed for R_RISCV_GOT_HI20
For now, just add a check for this. A proper fix involves some
changes to rv64/isel like is done for amd64.
The parser now uses a vector to get tokens into, similar to how quoted strings
are handled. This buffer is PFn-scoped, so function and data parsing can use
it. Type parsing has to copy its names to the global heap.
While this avoids the "identifier too long" error, it of course calls malloc
more often, so could potentially have a small negative performance impact on
parsing.
Floating point comparisons are subtle due to
unordered operands (i.e., when one or two of
the operands are nans).
In amd64 we arrange post isel to make sure we
only have comparisons that will return false
on unordered operands and for which we have a
negated version (returning true on unordered
operands). I made this situation a bit more
explicit by marking unexpected comparisons
with "?" in amd64/emit.c.
In arm64, the instruction set is rich enough
to have a negated version for all operators
that returns true on unordered inputs. So we
build a backend specific table.
I made sure to remove cmpneg() from utils.c;
it is a footgun as it does not work well for
floating point ops because of the 'unordered'
edge case.
I found the ARM docs about condition codes
pretty bad; the following C program is a
good substitute:
#include <stdio.h>
int
flags(float a, float b)
{
int z, c, n, v, le;
__asm__(
"fcmpe %s5, %s6\n"
"\tcset %0, eq\n"
"\tcset %1, mi\n"
"\tcset %2, cs\n"
"\tcset %3, vs\n"
"\tcset %4, le\n"
: "=r"(z),"=r"(n),"=r"(c),"=r"(v),"=r"(le)
: "x"(a), "x"(b)
: "cc");
printf(
"cmp(%g,%g): z=%d n=%d c=%d v=%d le=%d\n",
a, b, z, n, c, v, le);
}
int
main()
{
flags(1.0, 1.0);
flags(0.0, 1.0);
flags(1.0, 0.0);
flags(0.0, 0.0/0.0);
flags(0.0/0.0, 0.0);
}
Compile & run with:
aarch64-linux-gnu-gcc -static -no-pie flags.c
qemu-aarch64 ./a.out
ABI lowering for winabi was incorrectly using a Kl cls when emitting
Ostorel, which in turn was causing isel to fail to lower large constants
in to temporaries ( https://c9x.me/git/qbe.git/tree/amd64/isel.c#n107 )
when necessary.
(This should be applied on the 'winabi' branch.)
In the presence of the hidden arg for return-by-value, the
registers used for natural arguments were incorrect.
(This should be applied on the 'winabi' branch.)
This is an implementation of the Windows ABI. It supports most features
(struct passing/returning, varargs, env). TLS is not yet supported.
This patch does not actually port QBE to Windows, it only allows QBE to
generate correct asm to target Windows. As a result, testing is
accomplished on a Linux host, by using a cross-compiling toolchain, and
running the resulting binaries by using wine. See:
TARGET=amd64_win tools/test.sh all
A few cross-platform tests were changed from 'long' to 'long long' in
driver code because long in C does not match the size of a QBE 'l' on
Windows.
On x86_64, direct calls are always PC-relative. This means that
in order to call an absolute address, the call must be indirect.
To accomplish this, update fixarg to introduce a temporary before
emitting.
It is possible that GVN removes
some dead blocks, this could lead
to odd - but probably harmless -
phi args appearing in the IL.
This patch cleans things up during
fillcfg().
Useful for ifopt to match more
often. Empty blocks are fused
and conditional jumps on empty
blocks with the same successor
(and no phis in the successor)
are collapsed.
Replacement of tiny conditional jump graphlets with
conditional move instructions.
Currently enabled only for x86. Arm64 support using cselXX
will be essentially identical.
Adds (internal) frontend sel0/sel1 ops with flag-specific
backend xselXX following jnz implementation pattern.
Testing: standard QBE, cproc, harec, hare, roland
In case we need to spill to accomodate
for the jump argument, piggyback the
reloads from slots to regalloc so that
they can be correctly inserted on edges.
If $bin is set in the environment, use it instead of using `qbe` from
the source tree. The same for $binref. This supports the following use
cases:
- I have a qbe package installed, and I want to test my local changes
with the installed packages as a reference:
$ binref=/usr/bin/qbe ./tools/test.sh all
- I want to test the installed qbe against new tests that I have
written, to reproduce a bug:
$ bin=/usr/bin/qbe ./tools/test.sh test/newtest.ssa
In Debian, we also run tests against the installed package when
dependencies change, etc. We will also run on several architectures
where the necessary cross compilers might not be available. So make
tests that cannot be run because of a missing compiler exit with 77,
signaling to Debian's autopkgtest that the test is skipped.
On Apple platforms x18 is not guaranteed
to be preserved across context switches.
So we now use IP1 as scratch register.
En passant, one dubious use of IP0 in
arm64/emit.c fixarg() was transitioned
to IP1. I believe the previous code could
clobber a user value if IP0 was live.
- Many stylistic nits.
- Removed blkmerge().
- Some minor bug fixes.
- GCM reassoc is now "sink"; a pass that
moves trivial ops in their target block
with the same goal of reducing register
pressure, but starting from instructions
that benefit from having their inputs
close.