Age | Commit message (Collapse) | Author |
|
The riscv test abi8.ssa caught a bug
in the arm backend. It turns out we
were using the wrong class when loading
pointers to aggregates from the stack.
The fix is simple and mirrors what is
done in the riscv abi.
|
|
|
|
Many things got fixed, but the most
notable change is the proper support
of floating point types in aggregates.
Minor fixes:
- selpar() did not deal correctly
with Cfpint
- typclass() was reading out of
bounds in the gp/fp arrays
- support for env calls
|
|
They are meant to exercise the
hardware floating-point calling
convention of the risc-v target.
|
|
|
|
The risc-v abi needs to know if a
type is defined as a union or not.
We cannot use nunion to obtain this
information because the risc-v abi
made the unfortunate decision of
treating
union { int i; }
differently from
int i;
So, instead, I introduce a single
bit flag 'isunion'.
|
|
|
|
This enables the example to be compiled and run as-is, without any
additional modification.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
It is mostly complete, but still has a few ABI bugs when passing
floats in structs, or when structs are passed partly in register,
and partly on stack.
|
|
|
|
This condition should match any jump with two successors. This is
needed on riscv64, where there is no flags register, so Jjnz is
used all the way to emit().
|
|
This reverts commit 028534d9897079bf64559dca0402bc59a956ce46.
riscv64 will have jump arguments with type RTmp.
|
|
|
|
|
|
This allows frontends to use BSS generically, without knowledge of
platform-dependent details.
|
|
|
|
|
|
|
|
Signed-off-by: Detlef Riekenberg <wine.dev@web.de>
|
|
|
|
|
|
|
|
amd64 lacks instruction for this so it has to be implemented with
float -> signed casts. The approach is borrowed from llvm.
|
|
amd64 lacks an instruction for this so it has to be implemented with
signed -> float casts:
- Word casting is done by zero-extending the word to a long and then doing
a regular signed cast.
- Long casting is done by dividing by two with correct rounding if the
highest bit is set and casting that to float, then adding
1 to mantissa with integer addition
|
|
|
|
|
|
|
|
Necessary for floating-point negation, because
`%result = sub 0, %operand` doesn't give the correct sign for 0/-0.
|
|
When slots are used with a large offset,
the emitter generates invalid assembly
code. That is caught later on by the
assembler, but it prevents compilation
of programs with large stack frames.
When a slot offset is too large to be
expressed as a constant offset to x29
(the frame pointer), emitins() inserts
a late Oaddr instruction to x16 and
replaces the large slot reference with
x16.
This change also gave me the opportunity
to refactor the save/restore logic for
callee-save registers.
This fixes the following Hare issue:
https://todo.sr.ht/~sircmpwn/hare/387
|
|
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).
|
|
|
|
|
|
This may happen in a branch QBE doesn't realize is unreachable,
for example (simplified from real code found in ncurses)
data $str = { b "abcdef", b 0 }
function l $f(w %x) {
@start
%.1 =w ceqw %x, 0
jnz %.1, @logic_join, @logic_right
@logic_right
%p =l call $strchr(l $str, w %x)
%.2 =w ceql %p, 0
@logic_join
%.3 =w phi @start %.1, @logic_right %.2
jnz %.3, @fail, @return
@fail
ret 0
@return
%.4 =l sub %p, $str
ret %.4
}
|
|
If the size of the struct is not a multiple of 8, the actual struct
size may be different from the size reserved on the stack.
This fixes the case where the struct is passed in memory, but we
still may over-read a struct passed in registers. A TODO is added
for now.
|
|
Michael found a bug where some copies
from registers to memory in the arm64
abi clobber the stack. The test case
is:
type :T = { w }
function w $f() {
@start
%p =:T call $g()
%x =w loadw %p
ret %x
}
qbe will write 4 bytes out of bounds
when pulling the result struct from
its register. The same bug can be
observed if :T's definition is {w 3};
in this case qbe writes 16 bytes in
a slot of 12 bytes.
This patch changes stkblob() to use
the rounded argument size if it is
going to be restored from registers.
Relatedly, mem->reg loads for structs
with size < 16 and != 8, are treated
a bit sloppily both in the arm64 and
in the sysv abis. That is much less
harmful than the present bug.
|
|
|
|
This make it easier to understand the differences.
|
|
|
|
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.
|
|
Tested-by: Thomas Bracht Laumann Jespersen <t@laumann.xyz>
Fixes: https://todo.sr.ht/~sircmpwn/hare/312
|
|
Fixes #467. It assumes that the stack won't need to grow beyond 2^32 bytes.
If that were to happen, we'd need another or at most two more `movk` instructions.
Signed-off-by: Sudipto Mallick <smlckz@disroot.org>
|
|
If registers spill onto the stack, we may end up with SSA like
S320 =l copy 0
after rega(). Handle this case in arm64 emit().
|