Age | Commit message (Collapse) | Author |
|
|
|
|
|
|
|
|
|
|
|
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().
|
|
|
|
|
|
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.
|
|
|
|
Env calls were disfunctional from the
start. This fixes them on amd64, but
they remain to do on arm64. A new
test shows how to use them.
|
|
|
|
|
|
|
|
|
|
The documentation states that loadw is syntactic sugar for loadsw,
but it actually got parsed as Oload. If the result is an l temporary,
Oload behaves like Oloadl, not Oloadsw.
To fix this, parse Tloadw as Oloadsw explicitly.
|
|
|