When targeting Vulkan semantics, we should emit code that is actually
readable.
Also, make sure to use plain F{Min,Max,Clamp} on HLSL. HLSL has
NaN-aware semantics by default.
The implementation assumed that BDA to struct would always result in a
Block-like type, but that is not necessarily the case. Treat non-Block
structs as POD types as well.
Work around missing feature from GLSL. Normally we can emit a global
invariant gl_Position; and call it a day, but it does not work for mesh
shaders it seems. Declaring invariance inside an explicit IO block works
fine on the other hand ...
Handling native array types is not really feasible since we need to fuse
the variable declaration with the type declaration.
This is feasible in something like variable_decl, but for plain SSA
pointers, this breaks down.
Similar concern as access chains. Objects that we cannot lower to
temporaries must implicitly access all expression dependencies when they
are themselves accessed.
GLSL and RelaxedPrecision are quite different in what they affect.
RelaxedPrecision affects operations, while this is merely implied in
GLSL based on inputs.
This leads to situations where we have to promote mediump inputs to
highp, and the simplest approach is to force highp temporaries for
inputs which are consumed in a highp context. For completeness, we also
demote RelaxedPrecision inputs to mediump variables.
PHI is handled by copying the PHI into a temporary.
We have to be very careful with hoisted temporaries, since the child
temporary will not be analyzed up-front. We inherit the hoisted-ness
state and emit the hoisted child temporary as necessary. When faking the
temporaries with OpCopyObject, we make sure to block any variable
hoisting.
Hoisting children of PHI variables is fine, since PHIs are not hoisted with
the same framework as other temporaries.
Just like we try to fixup struct names for block types, inner structs
can be "anonymous" structs. HLSL codegen from DXC tends to emit this,
and emitting dummy struct names tends to break GL linkage on some
drivers.
Makes codegen from typical D3D emulation SPIR-V more readable.
Also makes cross compilation with NotEqual more sensible.
It's very rare to actually need the strict NaN-checks in practice.
Also, glslang now emits UnordNotEqual by default it seems, so give up
trying to assume OrdNotEqual. Harmonize for UnordNotEqual as the sane
default.
Introduces an idea of a recompilation making forward progress.
There are some extreme edge cases where we need more than 3 loops, but
only allow this in specific circumstances where we can reason about
forward progress being made.
This is somewhat awkward to support, but the best effort we can do here
is to analyze various Load/Store opcodes and deduce the ideal overall
alignment based on this. This is not a 100% perfect solution, but should
be correct for any reasonable use case.
Also fix various nitpicks with BDA support while I'm at it.
Apparently, it's legal to use a selection construct where both paths
branch to same location, but a different merge point is used.
This breaks many assumptions the variable scope analyzer makes.
The only logical way to generate code for this scenario is to treat the
selection construct as a trivial switch construct with only a default
case.