Now convert_nil only assigns the nil expression a type, and nil makes
its way down to the statement emission code (where it belongs, really).
Breaks even more things :)
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.
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.
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.
While expression symbols worked for what they are, they weren't so good
for ivar access because every ivar of a class (and its super classes)
would be accessed at method scope creation, generating spurious access
errors if any were private. That is, when the access checks worked at
all.
This is for adding methods to classes and protocols via their interface,
not for adding methods by adding protocols (they still get copied).
Slightly more memory efficient.
Unlike gcc, qfcc requires foo to be defined, not just declared (I
suspect this is a bug in gcc, or even the ObjC spec), because allowing
forward declarations causes an empty (no methods) protocol to be
emitted, and then when the protocol is actually defined, one with
methods, resulting in two different versions of the same protocol, which
comments in the gnu objc runtime specifically state is a problem but is
not checked because it "never happens in practice" (found while
investigating gcc's behavior with @protocol and just what some of the
comments about static instance lists meant).
It proved to be too fragile in its current implementation. It broke
pointers to incomplete structs and switch enum checking, and getting it
to work for other things was overly invasive. I still want the encoding,
but need to come up with something more robust.a
Such declarations were being lost, thus in the following, the id field
never got added:
typedef struct qwaq_mevent_s {
int id;
int x, y, z;
int buttons;
} qwaq_mevent_t;
The addition of xdef data has made qfo_to_progs unusable in qfprogs,
resulting in various invalid memory accesses. It always was an ugly hack
anyway, so this is the first step to proper qfo support in qfprogs.
I was originally going to put it in the debug syms file, but I realized
that the data persistence code would need access to both def type and
certainly correct def offsets for defs in far data.
This far better reflects the actual meaning. It is very likely that
ty_none is a holdover from long before there was full type encoding and
it meant that the union in qfcc's type_t had no data. This is still
true for basic types, but only if not a function, field or pointer type.
If the type was function, field or pointer, it was not true, so it was
misnamed pretty much from the start.
The encoding is 3:5 giving 3 bits for alignment (log2) and 5 bits for
size, with alignment in the 3 most significant bits. This keeps the
format backwards compatible as until doubles were added, all types were
aligned to 1 word which gets encoded as 0, and the size is unaffected.
This fixed the uninitialized temp warning in HUD.r. The problem was
caused by the flow analyzer not being able to detect that the struct
temp was being initialized by the move statement due to the address of
the temp being in a pointer temp. While it would be good to use a
constant pointer for the address of the struct temp or improving the
flow analyzer to track actual data, avoiding the temp in the first place
results in nicer code as it removes a move statement.
Only as scalars, I still need to think about what to do for vectors and
quaternions due to param size issues. Also, doubles are not yet
guaranteed to be correctly aligned.
I don't remember what the goal was (stopped working on it eight months
ago), but some possibilities include:
- better handling of nil (have trouble with assigning into struts)
- automatic forward declarations ala C# and jai (I was watching vids
about jai at the time)
- something for pascal
- simply that the default symbol type should not be var (in which case,
goal accomplished)
Currently, they can represent either vectors or quaternions, and the
quaternions can be in either [s, v] form or [w, x, y, z] form.
Many things will not actual work yet as the vector expression needs to be
converted into the appropriate form for assigning the elements to the
components of the "vector" type.
This is a nice feature found in fteqcc (also a bit of a challenge from
Spike). Getting bison to accept the new expression required rewriting the
state expression grammar, so this is mostly for the state expression. A
test to ensure the state expression doesn't break is included.
This goes towards complementing the "if not" logic extension. I need to
check if fteqcc supports "not" with "while" (the version I have access to
at the moment does not), and also whether it would be good to support
"not" with "for", and if so, what form the syntax should take.
It is syntactic sugar for if (!(foo)), but is useful for avoiding
inconsistencies between such things as if (string) and if (!string), even
though qcc can't parse if not (string). It also makes for easier to read
code when the logic in the condition is complex.
Dead nodes are those that generate unused values (unassigned leaf nodes,
expressions or destinationless move(p) nodes). The revoval is done by the
flow analysis code (via the dags code) so that any pre and post removal
flow analysis and manipulation may be done (eg, available expressions).
qfcc now does local common subexpression elimination. It seems to work, but
is optional (default off): use -O to enable. Also, uninitialized variable
detection is finally back :)
The progs engine now has very basic valgrind-like functionality for
checking pointer accesses. Enable with pr_boundscheck 2
When an alais def (or aliased def) is used, any overlapping aliases that
have previously been assigned need to be marked as live, and edges to the
aliases added to the new node. However, when assigned to, live-forcing
needs to be turned off.
This fixes the lost assignments to .super.
When the naive uninitialized variable detection finds a node with possible
uses of uninitialized variables, the statements in the node are scanned one
at a time checking each usage and removing uninitialized definitions as
appropriate. vectest.r now compiles without warnings. As an added bonus,
accurate line number information is reported for uninitialized variables.
Unfortunately, there is still a problem with uninitialized temps in
switch.r, but that might just be poor handling of temp op aliases.
The dummy nodes are for detectining uninitialized variables (entry dummy)
and making globals live at function exit (exit dummy). The reaching defs
and live vars code currently seg because neither node has had its sets
initialized.
Also move the ALLOC/FREE macros from qfcc.h to QF/alloc.h (needed to for
set.c).
Both modules are more generally useful than just for qfcc (eg, set
builtins for ruamoko).
Set of everything is implemented by inverting the meaning of bits in the
bitmap: 1 becomes non-member, 0 member. This means that set_size and
set_first/set_next become inverted and represent non-members as counting
members becomes impossible :)
With the need to handle aliasing in the optimizer, it has become apparent
that having the flow data attached to symbols is not nearly as useful as
having it attached to defs (which are views of the actual variables).
This also involves a bit of a cleanup of operand types: op_pointer and
op_alias are gone (this seems to greatly simplify the optimizer)
There is a bit of a problem with enums in switch statements, but this might
actually be a sign that something is not quite right in the switch code
(other than enums not being recognized as ints for jump table
optimization).
Simply "backed" and "virutal". Backed spaces have memory allocated to them
while virtual spaces do not. Virtual spaces are intended for local
variables and entity fields.
With this, alias defs become singletons based on the def they alias and the
type and offset of the alias. Thus, the removal of the free_def call in
emit.c.
alias_def now always creates an offset def (though the usual case has an
offset of 0). The if the alias escapes the bounds of the base def, an
internal error will be generated.
It really doesn't seem wise to allow the compiler to do so as it would
overwrite unrelated defs. The only time such a thing is valid is the return
statement (silly vm design), and that's read-only.