We can't just pass the value, SPIRV expects to be able to write to the
parameter if it's not const.
This does not yet do the right thing for for out variables. They are not
copied back to the caller.
For assignable expressions, we can always use an access chain to query
the value. Access chains are not just faster, they also contain lots of
optimizations for merging swizzles and whatnot.
A single swizzle can be reduced to an access chain lookup. This is
especially useful during assignments, because it means we don't need to
load the whole vector and OpVectorShuffle it.
This allows transitioning variables to different types. Which in the end
makes it possible to write different load/store code for parameters,
global variables or potentially GL builtins.
Represents a function, its argument types and whether they are
in/out/const arguments.
For now, this is just used to not duplicate function types in SPV files.
And use it to implement assignments.
And because I rock, this is all assignments, including member variables
swizzles and *= assignments. So this works:
foo.member.rgba.rgb *= vec3(0);
Store quantifier and real type in GskSlVariable instead.
Make gsk_spv_writer_get_id_for_pointer_type() take type and storage
class.
And generate writer opcodes using 2 arguments: Type and storage class.
This represents a block of code. For now it's only used for if
statements (which are now enabled again), but in future commits
writing of function blocks will use it, too.
Autogenerate the headers for SPIR-V from the JSON file provided by the
spec (and now included here).
This provides a way more readable and on top of that type-safe way to
emit bytecodes when generating code.
As a result of this, the whole bytecode emission was rewritten, so there
are probably lots of different bugs in it now.
Note: If statement SPV generation was disabled. Code generation needs
some more support for control flow before I can reenable if statements.
Returns the matching basic type for a different scalar type, ie returns
bvec3 for boolean vec3 or dmat3x4 for double mat3x4.
If the function is called when no matching type exists, it will explode
in your face.
and gsk_spv_writer_get_id_for_one(). Those are functions that return the
id for the value 0 or 1 in the given scalar. Note that they can be used
for FALSE/TRUE.
Instead of NaN, print "(0.0 / 0.0)" and instead of INF, print "(1.0 /
0.0)".
Both of that is not spec-conformant, but the best we can do if we
encounter constant expressions that evaluate to these numbers.
This includes the new function gsk_spv_writer_add_conversion() which
does the daunting task of doing a conversion for all types that can
convert, so it's the equivalent to gsk_sl_value_new_convert().
They don't obey the laws that govern constructors (argument promotion,
constant amount of predefined types of arguments and so on).
So we turn constructor calls into their own expression type.
This also dimplifies function call validation because we don't have to
do two-in-one with constructors in there.
And while doing that, also fix up the rules that govern constructor
arguments: Matrixes aren't allowed as arguments for matrixes unless
they're the first and only argument.
And if scalars are the first and only argument, they behave differently
than they would otherwise.
A type has components, if it is essentially an array of tighly packed
scalar values. In this case, a GskSlValue's data is essentially
ScalarType data[n_components];
This required a lot of reorganization because we have to track if we're
at the start of the document.
On the plus side, we now parse the #version tag and if it's correctly
used, we emit a warning that we don't support it.
Aren't we awesome?
This is basically the source format we use to represent source code.
It can be created either from a file or from a GBytes, so we can use it
to hold all data that can be provided by user input (#defines) or by
actual files.
And when we encounter any strings in the preprocessor, we promptly emit
an error and skip them. But we do that after the preprocessor runs, so
we can access strings inside the preprocessor.
This is the 3rd time at least that I've rewritten it. This time, I've
added a GskSlQualifier struct that contains all the information relevant
to qualifiers. It replaces the previous GskSlDecorationList.
This queries where a statement jumps to after it is done. The enum is
sorted by importance, larger values jump further.
We use this to do 3 things:
1. Error out if the function body statement does not return a value from
a non-void function.
2. Make sure to emit a Return as last instruction in a function body
3. Print a warning about dead code when statements follow a jump.