Addresses issue #304 and issue #307 by replacing unmatched type OpStores with
per-member copies. Covers assignment statements and most argument passing, but
does not yet cover r-value-based argument passing.
Takes some pressure off of issue #304.
Structures don't inherit locations and then explicitly decorate
members with them, so removed this reason to have another instance
of a structure type.
Code using atEndOfFile was dead, instead do something useful with
the scanners atEndOfInput(). This allows a better error message
for early termination of cascading errors.
This also enables vecN -> vec1 shape conversions for all places doing shape
conversions.
For signature selection, makes shape changes worse than any other comparison
when deciding what conversions are better than others.
This is part of the change to have desktop shaders respect precision
qualifiers on Vulkan, but since the defaults are all highp, and that's
different from ES fragment shaders, detect likely cases and warn about
them (but being careful to not be too noisy if it's unlikely to be a
problem).
Sets highp defaults for the appropriate types, for all stages,
and turns on precision qualifiers for non-ES shaders. Required
fixing some qualifier orders for desktop built-in declarations
for pre-420 shaders.
Use the new function selector for #version 400 and above,
parameterized for the GLSL #version 400 selection rules.
This can be used for both GLSL and HLSL, and other languages
as well.
When preprocessing only, some tokens were emitted as <bad token>.
This fixes them to preserve their original content.
This supplants PR #182, with a correction and test results.
From the ES spec + Bugzilla 15931 and GL_KHR_vulkan_glsl:
- Update precision qualifiers for all built-in function prototypes.
- Implement the new algorithm used to distinguish built-in function
operation precisions from result precisions.
Also add tracking of separate result and operation precisions, and
use that in generating SPIR-V.
(SPIR-V cares about precision of operation, while the front-end
cares about precision of result, for propagation.)
The sequence
#define m()
int m"
creates a token of no length (a string of 0 size). Protect
against a string of 0 size as well as the existing protect
against a null string.
This would look ahead for a second #, for token pasting, and if not
found, backup one token. This is fine, unless at the end of line,
which would backup the #, rather than the look ahead.
Also, this allows turning on the error check for a failed assigment
when parsing.
This makes 39 HLSL tests have a working assignment that was previously
silently dropped, due to lack of this functionality.
Added -C option to request cascading errors. By default, will exit early,
to avoid all error-recovery-based crashes.
This works by simulating end-of-file in input on first error, so no
need for exception handling, or stack unwinding, or any complex error
checking/handling to get out of the stack.
This is used by OpenGL, but not Vulkan.
Includes:
- atomicCounter, atomicIncrement, atomicCounterDecrement
- atomic_uint layout-offset checking
- AtomicStorage capability
SPV doesn't allow gaps in the components of the texturing coordinate.
It also removes the shadow reference.
So, close up the components so all used components are together.
For opaque types such as samplers, images, and atomic counters, we want to
reference the actual object in the child function. For a long time, we
used a shadow variable and made a copy of the image/sampler. In 76d0ac1a,
this was changed to not shadow samplers. However, this didn't cover all
opaque types and it also didn't get the pointer storage classes right.
This commit fixes both of these issues.
Fixes#324
The compiler will mark struct members with those builtins, but won't
declare the capability until that member is accessed by some executable
instruction.
Test changes:
- spv.430.vert: was missing ClipDistance capability.
- spv.precise.tese: remove TessellationPointSize capability.
The grammar now accepts type casts, like "(int)x", but that
has to be disambiguated from "(a + b)", needed deeper lookahead
and backing up than what existed so far.
This checkin implements about half of the HLSL intrinsics for a subset of their
entire type support (but a useful subset). The uncommented lines in
TBuiltInParseablesHlsl::identifyBuiltIns shows which are connected.
The test result should only give one error about linking
ES and non-ES shading language compilation units:
- empty.frag: No version info, interpreted as 100, ES
- empty2.frag: No version info, interpreted as 100, ES
- empty3.frag: Version declared as 110, non-ES
Previously, because the new intermediate is always created
without version/profile information, there would be two
linker errors:
1.) When merging the new intermediate with empty.frag
2.) When merging (new intermediate + empty.frag + empty2.frag) with empty3.frag
Now, there is only one error; as the error with merging the
new intermediate with empty.frag has been removed.
Note: This required adding a new test mode to see the AST for vulkan tests.
This also required reworking some deeper parts of type creation, regarding
when storage qualification and constness is deduced bottom-up or dictated
top-down.
GLSL interpolation qualifiers and auxiliary storage qualifiers are not
mutually exclusive. So when they are translated to SPIR-V decorations, two
independent utility methods should be employed to do this job.
Spec for decorating the OpVariable:
"The remaining variables listed by OpEntryPoint with the Input or Output storage class form the user-defined variable interface. These variables must be identified with a Location decoration"
Spec for decorating struct type:
"The layout of a structure type used as an Input or Output depends on whether it is also a Block (i.e. has a Block decoration).
If it is a not a Block, then the structure type must have a Location decoration"
These capabalities were added on declaration of the members, but
that is considered too aggressive, as those members are automatically
declared in some shaders that don't use them. Now, actual access
is needed to make the capabalities be declared.
This change causes ES shaders to precision qualifiers for build-in functions as defined in ESSL spec. It especially mattersfor functions that are defined as highp or taking a highp.
Fixes vulkanCTS dEQP-VK.glsl.builtin.function.integer.bitfieldreverse.*, where bitfieldReverse() retval was wrongly marked as RelaxedPrecision.
Note: floatBitsToInt/floatBitsToUInt precision is also broken, but in different way - so it is not addressed here.
Reimplement the whole workflow to make that: precise'ness of struct
members won't spread to other non-precise members of the same struct
instance.
Approach:
1. Build the map from symbols to their defining nodes. And for each
object node (StructIndex, DirectIndex, Symbol nodes, etc), generates an
accesschain path. Different AST nodes that indicating a same object
should have the same accesschain path.
2. Along the building phase in step 1, collect the initial set of
'precise' (AST qualifier: 'noContraction') objects' accesschain paths.
3. Start with the initial set of 'precise' accesschain paths, use it as
a worklist, do as the following steps until the worklist is empty:
1) Pop an accesschain path from worklist.
2) Get the symbol part from the accesschain path.
3) Find the defining nodes of that symbol.
4) For each defining node, check whether it is defining a 'precise'
object, or its assignee has nested 'precise' object. Get the
incremental path from assignee to its nested 'precise' object (if
any).
5) Traverse the right side of the defining node, obtain the
accesschain paths of the corresponding involved 'precise' objects.
Update the worklist with those new objects' accesschain paths.
Label involved operations with 'noContraction'.
In each step, whenever we find the parent object of an nested object is
'precise' (has 'noContraction' qualifier), we let the nested object
inherit the 'precise'ness from its parent object.
This fixes some vulkanCTS tests that use struct arrays as a member of in/out interface blocks.
From Vulkan spec:
"If it is a not a Block, then the structure type must have a Location decoration. Its members are assigned consecutive locations in their declaration order, with the first member assigned to the location specified for the structure type. >>>>> The members, and their nested types, must not themselves have Location decorations <<<<"
From SPIR-V spec:
"When applied to structure-type members, the Decorations Noperspective, Flat, Patch, Centroid, and Sample can only be applied to the top-level members of the structure type. (Nested objects' types cannot be structures whose members are decorated with these decorations.)"
Note this requires test-based piecing together of the preamble string,
so it changed to being a std::string to make it easier to do.
This closes issue #254.
This is a replacement commit for pull request #238.
This is a design change, followed by implementation change that
A) fixes the changes caused by the design change, and
B) fixes some cases that were originally incorrect.
The design change is to not give built-in functions default precision qualification.
This is to allow the rule that the precision of some built-in functions adopt their
precision qualification from the calling arguments. This is A above.
A consequence of this design change is that all built-ins that are supposed to have
an explicit precision qualifier must now be declared that way. So, a lot more
built-in declarations now have precision qualifiers, just to keep things the same.
This is B above.
- Add new keyword int64_t/uint64_t/i64vec/u64vec.
- Support 64-bit integer literals (dec/hex/oct).
- Support built-in operators for 64-bit integer type.
- Add implicit and explicit type conversion for 64-bit integer type.
- Add new built-in functions defined in this extension.
The input scanner can be trapped in an infinite loop if the given input
file does not have EOF (and is not ended with a 'whitespace').
The problem is caused by unget(), which keeps rolling back the scanner
pointer without hitting an EOF at the end of the file. This makes getch()
function keep returning the last character of the file and never ends,
and the effect of advance() is always counteracted by unget().
Fix issue: #237
1. The code generated for matrix constructor should 1) build column
vectors first, 2) build matrix with the vectors.
2. When there is only one scalar type constituent in vector's
constructor, we should populate the constituent to fill all the slots in
the vector. As for matrix, the single constituent should be populated to
the diagonal positions (top-left to bottom-right diagonal).
remove createSpvConstantFromConstSubTree()
Bool -> uint/int with OpSpecConstantOp OpSelect instruction.
uint <-> int conversion with OpSpecConstantOp OpIAdd instruction.
Note, implicit conversion: `const uint = an_int_spec_constant` is not
supported. Explicit type casting is required: `const uint =
uint(an_int_spec_constant)`
This is according to the expected KHR_vulkan_glsl without floating point.
So, floating-point spec-const operations no longer work, and that's
reflected in the tests.
Move SpecConstantOpModeGuard from makeSpvConstantFromConstSubTree() to
visitbinary() and visitunary(). Checking if the visiting node is a spec
constants, if so, turn on the SpecConstantOpMode, otherwise, stay in the
normal mode.
The existing test harness is a homemade shell script. All the tests
and the expected results are written in plain text files. The harness
just reads in a test, invoke the glslangValidator binary on it, and
compare the result with the golden file. All tests are kinda
integration tests.
This patch add Google Test as an external project, which provides a
new harness for reading shader source files, compile to SPIR-V, and
then compare with the expected output.
Approach:
Add a flag in `Builder` to indicate 'spec constant mode' and 'normal
mode'. When the builder is in 'normal mode', nothing changed. When the
builder is in 'spec constant mode', binary, unary and other instruction
creation rountines will be redirected to `createSpecConstantOp()` to
create instrution at module level with `OpSpecConstantOp <original
opcode> <operands>`.
'spec constant mode' should be enabled if and only if we are creating
spec constants. So a flager setter/recover guard is added when handling
binary/unary nodes in `createSpvConstantsFromConstSubTree()`.
Note when handling spec constants which are represented as ConstantUnion
Node, we should not use `OpSpecConstantOp` to initialize the composite
constant, so builder is set to 'normal mode'.
Tests:
Tests are added in Test/spv.specConstantOperations.vert, including:
1) Arithmetic, shift opeations for both scalar and composite type spec constants.
2) Size conversion from/to float and double for both scalar and vector.
3) Bitwise and/or/xor for both scalar and vector.
4) Unary negate/not for both scalar and vector.
5) Vector swizzles.
6) Comparisons for scalars.
7) == and != for composite type spec constants
Issues:
1) To implement == and != for composite type spec constants, the Spec needs
to allow OpAll, OpAny, OpFOrdEqual, OpFUnordEqual, OpOrdNotEqual,
OpFUnordNotEqual. Currently none of them are allowed in the Spec.
Much about const or temp is mechanical, about actual declaration,
while much is semantic, about something higher level. This commit
checks every use everywhere, and for the high-level ones, substitutes
an encapsulated version instead.