This bug drove me nuts for several hours until I figured out what was
going on.
The assignment sub-tree is being generated, then lost. It works for
simple assignments because a = b = c -> (= a (= b c)), but for complex
assignments (those that require move or memset), a = b = c -> (b = c) (a
= c) but nothing points to (b = c). The cause is using binary
expressions to store assignments.
It's not possible to take the address of constants (at this stage) and
trying to use a move instruction with .zero as source would result in
the VM complaining about null pointer access when bounds checking is on.
Thus, don't convert a nil source expression until it is known to be
safe, and use memset when it is not.
This fixes the problem of using the return value of a function as an
element in a compound initializer. The cause of the problem is that
compound initializers were represented by block expressions, but
function calls are contained within block expressions, so def
initialization saw the block expression and thought it was a nested
compound initializer.
Technically, it was a bug in the nested element parsing code in that it
wasn't checking the result value of the block expression, but using a
whole new expression type makes things much cleaner and the work done
paves the way for labeled initializers and compound assignments.
Not that it really makes any difference for labels since they're
guaranteed unique, but it does remove the question of "why nva instead
of save_string?". Looking at history, save_string came after I changed
it from strdup (va()) to nva(), and then either didn't think to look for
nva or thought it wasn't worth changing.
Multi-line calls (especially messages) got rather confusing to read as
the lines jumped back and forth. Now the binding is better but the dags
code is reordering the parameters sometimes.
The server code is not yet ready for doubles, especially in its varargs
builtins: they expect only floats. When float promotion is enabled
(default for advanced code, disabled for traditional or v6only),
"@float_promoted@" is written to the prog's strings.
That was a fair bit trickier than I thought, but now .return and .paramN
are handled correctly, too, especially taking call instructions into
account (they can "kill" all 9 defs).
This reverts commit a2f203c840.
There is indeed a world of difference between "any" and "only", and it
helps if I read the rest of the docs AND the code :P.
As expected, this does not fix the mangled pointer problem in
struct-init-param.r, but it does improve the ud-chains. There's still a
problem with .return, but it's handling in flow_analyze_statement is a
bit "special" :P.
Doing the same thing at the end of two branches of an if/else seems off.
And doing an associative(?) set operation every time through a loop is
wasteful.
This fixes the ICE when attempting to compile address-cast without
optimization (just realized why, too: the assignment was optimized out
of existence).
This the fixes the incorrect flow analysis caused by the def being seen
to have the wrong size (structure field of structure def seen through a
constant pointer). Fixes the ICE, but the pointer constant is broken
somewhere in dags, presumably.