I want to use new_field_expr for specialized field expressions instead.
However, I don't particularly like new_deffield_expr as a name, but I
can't think of anything better just yet.
Now, ctor expressions are collected and emitted after all other code,
and the ctor function being created outside of class_finish_module means
it's no longer limited to just class related initialization.
I plan to do this eventually for Ruamoko, but I need it to keep working
for now; it's rather nice having multiple languages. I expect this will
open up a lot of options for inlining, generic/template function
instantiation, etc. Right now, it's helping with specialization
constants in glsl.
They're currently wrong since they're meant to be for specialization
constants (and that whole system is currently broken anyway) but are
instead raw code expressions, but progress is progress.
Result type and constant handling is now table-driven, resulting in the
removal of seven switch statements (and thus a lot less hassle when
extending types or expressions). Also, (u)long and (u)short are fully
implemented.
In addition, other than result type handing for boolean results, any
back-end specific implementation is now in the back-end.
It's nowhere near complete, but unary and binary expressions that are
marked as constant will not be subject to constant folding. This is
necessary for proper support of specialization constants.
The imports need their result id recorded somewhere (and the hard-coding
in qc-parse.y removed), but that's a little bit of progress getting
spir-v working.
I don't know why I thought it was a good idea to make sy_var context
dependent. Renaming sy_var to sy_def makes it a little easier to know to
use the def field, too.
While I'm not happy with the module "creation" (at least it's limited to
two places), setting it up with spir-v capabilities and memory model
seems quite nice and should play nicely with being set up from within
source code, though using uint constant expressions might be overkill.
Thare are still many const casts, but this does get rid of one set. I
had tried to replace the paren flag with a () unary expression, but that
brought out a whole pile of places that had problems (especially
anything to do with boolean expressions).
It seems it was needed for dealing with the result expression for block
expressions, but it turns out (possibly thanks to dags), that it's easy
to check for the result value and using the appropriate call to emit the
code thus avoiding the non-executable code warning.
Fortunately, there was a reserved spot that could be used for the name
thus no need for a version update. The name isn't used yet but will be
for glsl support.
Each interface type (in, out, uniform etc) gets its own namespace, and
non-instanced blocks get a namespace (their block name) within the
interface namespace.
The defs for the block members are currently "allocated" to be at offset
-1, but the idea is to allow layout qualifiers to know if the member has
already been located.
I'm not sure I got all the checks right, but bsp_gbuf.geom passes the
validity (but failes due to not having implemented the application of
the qualifiers).
Attributes seem appropriate as GLSL's qualifiers affect variables rather
than types (since there's no typedef).
Not much is done with the attributes yet other than some basic error
checking (duplicates of non-layout attributes) and debug output, but
most (if not all) declarations get to the declaration code with
attributes intact.
I don't yet know whether the generated code is correct, but the little
functions that compute a generic type gets stored in the function's
params/return type.
Allows the parsing of the return type in the following:
@generic(vec=[vec2,vec3,vec4]) {
@vector(bool,@width(vec)) lessThan(vec x, vec y);
}
Unfortunately, can't use math in int value parameters just yet, the
processing of expressions needs to be delayed (it's currently done
immediately so type-checking happens to early).
It's not connected up yet, but does produce what looks like the correct
code.
It turned out that for v6 progs (due to lack of double or long) weren't
getting correctly parsed vector literals: incorrect "implicit" flag and
then a lot of brittleness around constant value conversions.
Now parameters can be declared `const`, `@in`, `@out`, `@inout`. `@in`
is redundant as it's the default, but I guess it's nice for
self-documenting code. `const` marks the parameter as read-only in the
function, `@out` and `@inout` allow the parameter to pass the value back
out (by copy), but `@out` does not initialize the parameter before
calling and returning without setting an `@out` parameter is an error
(but unfortunately, currently detected only when optimizing).
Unfortunately, it seems to have broken (only!) v6 progs when optimizing
as the second parameter gets optimized out.
The version directive really does only some error checking, and
only GL_EXT_multiview and GL_GOOGLE_include_directive are supported for
extensions, but enable/disable work (but not yet warn for multiview).
Using set_line_file sort of worked with its stack, but line directives
embedded in the source (which glsl's initialization code uses) messed up
the start path for quoted include searches.
There's no direct support for namespaces in Ruamoko yet, nor even in
qfcc, but glsl's blocks bring in a bit of foundation for them, even the
concept of "using" (for blocks with no instance name).
The members don't get locations allocated to them yet, but
fstrianglest.vert compiles and links correctly otherwise.
Also, there's no error checking yet.
Other than contructors (and problems with the `out` block) qfcc can
compile fstrianglest.vert to what looks like working ruamoko code.
There's still a lot of work to do, though.
Using a struct with function pointers instead of switching on an enum
makes it much easier to add languages and, more importantly,
sub-languages like glsl's shader stage variants.
I never did like overloaded_function_t as a name, and with the
introduction of generic functions (or templates, I guess?) meta-function
makes more sense to me.
Most of them were noise from the type const correctness pass, but the
qc field function handling was always dubious (though in practice safe
due to how the type was built, but...). The remaining casts outside of
type.c need some thought.
With this, genFType and genDType functions are now treated separately
and expanding to all components (single row or column matrices are not
supported (at this stage, anyway) for generic parameters).
That is, `@generic(...) { ... };`, which is handy for bulk declarations
(such as for glsl). This proved to be a lot harder than expected, I
suspect handling of specifiers needs a lot of work.
It doesn't properly differentiate between (treats genDType as being the
same as genFType):
@generic(genFType=@vector(float)) genFType radians(genFType degrees);
@generic(genDType=@vector(double)) genDType radians(genDType degrees);
but this is due to problems with how the type is built from
@vector(float) and @vector(double). However, I thought it was about time
I got some of this into git.
Also, `@generic(...) { ... };` blocks don't work properly (they lose the
generic info): need to get a little smarter about handling generic scope
in `external_def_list`.
While they might be ok, I expect them to cause some issues when doing
compile-time evaluations of type expressions, so use of dags seems to be
a premature optimization. However, as the "no dags" flag is propagated
to parent expression nodes, it may prove useful in other contexts.
The expression grammar has been tidied up and some basic checks are made
of parameters to the type functions. Also, type parameters are looked up
so parsing now works properly. However, the type parameters are not used
correctly, so function generation doesn't work.
The semantics are only partially implemented (generic types not yet
generated), but the generic scope for function declarations seems to be
working as intended in that it gets inserted in the scope chain and
removed at the end of the declaration.
The end goal is to allow generic and/or template functions, but this
allows types to be specified parametrically, eg vectors of specific type
and width, with widths of one becoming scalars.
Matrices are currently completely broken as I haven't decided on how to
represent the columns (rows is represented by width (column-major
storage)), and bools are only partially supported (need to sort out
32-bit vs 64-bit bools).
No semantics yet, but qfcc can parse some of QF's shaders. The grammar
mostly follows that in the OpenGL Shading Language, Version 4.60.7 spec,
but with a few less tokens.
This gets the types such that either there is only one definition, or C
sees the same name for what is essentially the same type despite there
being multiple local definitions.
The syntax is not at all correct at this stage (really, just a copy of
Ruamoko), but the keyword table exists (in the wrong place) and the
additional basic types (bool, bvecN and (d)matNxM) have been added.
Boolean base type is currently just int, and matrices have 0 width while
I think about what to use, but finally some progress after several
months' hiatus.
This allows the dags code to optimize the return values, and when I make
the node killing by function calls less aggressive, should make for many
more potential CSE optimizations.
The fix in bdafdad0d5 for
`while (count--)` never did appeal to me. I think I understood the core
problem at the time, but I hadn't figured out how to use a var's
use/define sets to detect the write-before-read. Using them allows the
special handling for flow control to be removed, making things more
robust. The function call handling has been superfluous since the
Ruamoko instruction set required the auxiliary operands on the call
statements.
Two birds with one stone: eliminates most of the problems with going
const-correct with expr_t, and it make dealing with internally generated
expressions at random locations much easier as the set source location
affects all new expressions created within that scope, to any depth.
Debug output is much easier to read now.
There were a few places where some const-casts were needed, but they're
localized to code that's supposed to manipulate types (but I do want to
come up with something to clean that up).
I'm not sure the regressive product is right (overall sign), but that's
actually partly a problem in the math itself (duals and the regressive
product still get poked at, so it may be just a matter of
interpretation).
The switch to using expression dags instead of trees meant that the
statement generator could traverse sub-expressions multiple times. This
is inefficient but usually ok if there are no side effects. However,
side effects and branches (usually from ?:, due to labels) break: side
effects happen more than once, and labels get emitted multiple times
resulting in orphaned statement blocks (and, in the end, uninitialized
temporaries).
This makes a slight improvement to the commutator product in that it
removes the expand statement, but there's still the problem of (a+a)/2.
However, at least now the product is correct and slightly less abysmal.
There's no guarantee the source file is in a writable directory (in
fact, it is very definitely in a read-only directory when running
`make distcheck`). However, it is reasonable to assume the output file
is being written to a writable directory thus default the object file
directory to that of the output file, but still use the source file's
name for the object file name.
Fixes#51
It just feels cleaner than unnecessarily copying token chains. It turns
out that the core problem was just order of operations in next_token:
moving the pending_macro code to after arg/macro detection seems to be
correct (even bare `G LPAREN() 0)` is *not* expanding `G`, as expected).
I got tired of the way the separate token types for macro expansion and
the rest of the preprocessor parser were handled. This makes them a
little more unified. Macro expansion seems to be slightly broken again
in that min/max/bound mess up badly, and __VA_OPT__ does things in the
wrong order, but I wanted to get this in as a checkpoint.
__VA_ARGS__ seems to be working but __VA_OPT__ still needs a lot of work
for dealing with its expansions, but basic error checking and simple
expansions seem to work.
Macros now store their arguments and have a cursor pointing to the next
token to take from their expansion list. While not checked yet, this
will make avoiding recursive macro invocations much easier. More
importantly, it's a step closer to correct argument expansion (though
token pasting is currently broken).
-D options weren't counting correctly so build_cpp_args was writing past
the end of the array allocated for command line arguments
parse_cpp_name had an out-by-one resulting in reading past the end of
the string.
The qfcc system include path was being set in the wrong place (not sure
why I thought that was right), and not respecting no_default_paths.
-M was generating preprocessor output when it should not have been,
resulting in corrupted dependency files.
Or at least mostly so. The __QFCC__ define isn't visible, and it seems
undef might not be working properly (ruamoko/lib/types.r doesn't
compile). Of course, there's still the issue of whether it's compiling
correctly.
In addition to cleaning up the old flex line rules, this improves
handling of the '# num "file" flags' from cpp to at least parse the
additional flags (support for the system header flag might come later,
but I doubt the extern-c flag will have much meaning).
QuakePascal has lost its line directive handling (no errors, but dead
rules) for now. Eventually the lexers will be merged.
Really, function-type macros expand too, but incorrectly as the
parameters are not parsed and thus not expanded, but this gets the basic
handling implemented, including # and ## processing.
This will be used for unifying preprocessing and parsing, the idea being
that the tokens will be recorded for later expansion via macros, without
the need to retokenize.
It's now meant only for ALLOC. Interestingly, when DEBUG_QF_MEMORY is
defined in expr.c, something breaks badly with vkgen (no sniffles out of
valgrind, though), but everything is fine with it not defined. It seems
there may be some unpleasant UB going on somewhere.
This fixes the motor test :) It turns out that every lead I had
previously was due to the disabling of that feature "breaking" dags
(such that expressions wouldn't be found) and it was the dagged
multi-vector components getting linked by expr->next that made a mess of
things.
Or at least mostly so (there are a few casts). This doesn't fix the
motor bug, but I've wanted to do this for over twenty years and at least
I know what's not causing the bug. However, disabling fold_constants in
expr_algebra.c does "fix" things, so it's still a good place to look.
They don't have much effect that I've noticed, but the expression dags
code does check for commutative expressions. The algebra code uses the
anticommutative flag for cross, wedge and subtract (unconditional at
this stage). Integer ops that are commutative are always commutative (or
anticommutative). Floating point ops can be controlled (default to non),
but no way to set the options currently.
Especially binary expressions. That expressions can now be reused is
what caused the need to make expression lists non-invasive: the reuse
resulted in loops in the lists. This doesn't directly affect code
generation at this stage but it will help with optimizing algebraic
expressions.
The dags are per sequence point (as per my reading of the C spec).
Finally, that little e. is cleaned up. convert_name was a bit of a pain
(in that it relied on modifying the expression rather than returning a
new one, or more that such behavior was relied on).
That is, passing int constants through ... in Ruamoko progs is no longer
a warning (still is for v6p and v6 progs). I got tired of getting the
warning for sizeof expressions when int through ... hasn't been a
problem for even most v6p progs, and was intended to not be a problem
for Ruamoko progs.