I realized that spir-v pointers are essentially references (the way
they're used) since OpVariable requires a pointer type rather than the
base type. Thus, under the hood, references are just pointers with
automatic dereferencing. However, nothing uses references yet, and I
expect to run into issues with is_pointer vs is_reference vs is_ptr
(high-level pointer, reference, low-level pointer, respectively).
Since begin_function creates the parameter and locals scopes, there's no
need for another scope for the function body. This fixes the detection
of shadowed parameters for Ruamoko and QuakeC.
It's currently passing for Ruamoko, but glsl doesn't catch shadowed
params. There's a bit of a conflict and I want to make sure I don't lose
the checking.
I'd gotten tired of all the convoluted progs version checks, and with
the addition of spirv, they're not even always relevant, and adding C
(when I get to it) will make things even worse. However, for now the
first victim is just the parameter/return value size check.
Now declarations can be deferred too, thus things like generic/template
and inline functions should be possible. However, the most important
thing is this is a step towards a cleaner middle layer for compilation,
separating front-end language from back-end code-gen.
I don't remember why I thought it was a good idea at the time, but I
decided that having the union was a bit iffy and making the list
"official" would be a good idea. In the end, it removed a nice chunk of
code (redundant list manipulations).
And they even pass validation (though it turns out there's a bug in
glslangValidator regarding specialization constants with expressions (or
possibly spirv-val, but it seems to be the former as my bug report shows
signs of activity in that direction)).
https://github.com/KhronosGroup/glslang/issues/3748
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.
So far, this affects only glsl (because only glsl marks expressions as
constexpr), but it does get specialization constant initializers for
global variables working.
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.
Including anti-commutativity. I hadn't set them before because I was
uncertain and got conflicting answers, but when I took a look again, it
seems IEEE 754 does guarantee commutativity for multiplication and
addition, so long as NaN isn't involved (and then it seems to be because
`a==a` is always false when a is a NaN).
Both for geometric algebra and in general (since it's just in
unary_expr). However, it doesn't quite work for float stuff (eg,
`vector × vector`, but that's only because the anti-commutative flag
isn't set.
Really, I need to look into getting the optimizations more general, but
`a × ⋆a` is now just a single cross product instead off cross, add and
divide.
Maybe there's a different trick to making gcc see that the dimension was
already check, but this works nicely size if the two calculations
differ, there are bigger problems.
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'm not sure what's up (I doubt it's actually ub, it's just that it took
enabling ubsan *and* link-time-optimizations to see the warning), and
the warning is technically correct, though going from -1 (int) to
0xfffffff400000000 has me stumped, but ensuring width is 2-4 does take
care of it. All because I got a weird test failure that I wound up being
unable to reproduce after rebuilding qfcc (thus the ubsan pass, but no
other sniffles).
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.
A few more types and function parameters are set up more or less
correctly (however, the pointer storage class is hard-coded for now:
need to add attributes to everything).
It was a bit of a surprise seeing a test case fail and then succeed
after making a minor edit to help find the bug, but valgrind to the
rescue. I'm surprised nothing showed up earlier.
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.
They can have a variety (min int and long) of backing types, so
requiring ev_invalid (which is used for struct and union).
Also, ensure is_int etc fail for handle types.
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.