From 9220dbb078c0652028186b3aa2d1238f4bb8dfa1 Mon Sep 17 00:00:00 2001 From: qining Date: Wed, 4 May 2016 17:34:38 -0400 Subject: [PATCH 1/9] Precise and noContraction propagation 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. --- SPIRV/GlslangToSpv.cpp | 21 +- Test/baseResults/precise.tesc.out | 728 ++++++++++++ .../baseResults/precise_struct_block.vert.out | 1045 +++++++++++++++++ Test/baseResults/spv.precise.tesc.out | 122 ++ Test/baseResults/spv.precise.tese.out | 192 +++ Test/precise.tesc | 102 ++ Test/precise_struct_block.vert | 89 ++ Test/spv.precise.tesc | 24 + Test/spv.precise.tese | 36 + Test/test-spirv-list | 2 + Test/testlist | 2 + glslang/CMakeLists.txt | 2 + glslang/MachineIndependent/Intermediate.cpp | 4 + .../propagateNoContraction.cpp | 886 ++++++++++++++ .../propagateNoContraction.h | 53 + 15 files changed, 3307 insertions(+), 1 deletion(-) create mode 100644 Test/baseResults/precise.tesc.out create mode 100644 Test/baseResults/precise_struct_block.vert.out create mode 100644 Test/baseResults/spv.precise.tesc.out create mode 100644 Test/baseResults/spv.precise.tese.out create mode 100644 Test/precise.tesc create mode 100644 Test/precise_struct_block.vert create mode 100644 Test/spv.precise.tesc create mode 100644 Test/spv.precise.tese create mode 100644 glslang/MachineIndependent/propagateNoContraction.cpp create mode 100644 glslang/MachineIndependent/propagateNoContraction.h diff --git a/SPIRV/GlslangToSpv.cpp b/SPIRV/GlslangToSpv.cpp index 7aa62fbd..d160e36e 100755 --- a/SPIRV/GlslangToSpv.cpp +++ b/SPIRV/GlslangToSpv.cpp @@ -385,6 +385,15 @@ spv::Decoration TranslateInvariantDecoration(const glslang::TQualifier& qualifie return (spv::Decoration)spv::BadValue; } +// If glslang type is noContraction, return SPIR-V NoContraction decoration. +spv::Decoration TranslateNoContractionDecoration(const glslang::TQualifier& qualifier) +{ + if (qualifier.noContraction) + return spv::DecorationNoContraction; + else + return (spv::Decoration)spv::BadValue; +} + // Translate glslang built-in variable to SPIR-V built in decoration. spv::BuiltIn TGlslangToSpvTraverser::TranslateBuiltInDecoration(glslang::TBuiltInVariable builtIn) { @@ -612,7 +621,8 @@ bool HasNonLayoutQualifiers(const glslang::TQualifier& qualifier) // - struct members can inherit from a struct declaration // - effect decorations on the struct members (note smooth does not, and expecting something like volatile to effect the whole object) // - are not part of the offset/st430/etc or row/column-major layout - return qualifier.invariant || qualifier.nopersp || qualifier.flat || qualifier.centroid || qualifier.patch || qualifier.sample || qualifier.hasLocation(); + return qualifier.invariant || qualifier.nopersp || qualifier.flat || qualifier.centroid || qualifier.patch || qualifier.sample || qualifier.hasLocation() || + qualifier.noContraction; } // @@ -877,6 +887,9 @@ bool TGlslangToSpvTraverser::visitBinary(glslang::TVisit /* visit */, glslang::T convertGlslangToSpvType(node->getType()), leftRValue, rValue, node->getType().getBasicType()); + // Decorate this instruction, if this node has 'noContraction' qualifier. + addDecoration(rValue, TranslateNoContractionDecoration(node->getType().getQualifier())); + // these all need their counterparts in createBinaryOperation() assert(rValue != spv::NoResult); } @@ -1000,6 +1013,8 @@ bool TGlslangToSpvTraverser::visitBinary(glslang::TVisit /* visit */, glslang::T logger->missingFunctionality("unknown glslang binary operation"); return true; // pick up a child as the place-holder result } else { + // Decorate this instruction, if this node has 'noContraction' qualifier. + addDecoration(result, TranslateNoContractionDecoration(node->getType().getQualifier())); builder.setAccessChainRValue(result); return false; } @@ -1068,6 +1083,8 @@ bool TGlslangToSpvTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TI result = createUnaryOperation(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operand, node->getOperand()->getBasicType()); if (result) { + // Decorate this instruction, if this node has 'noContraction' qualifier. + addDecoration(result, TranslateNoContractionDecoration(node->getType().getQualifier())); builder.clearAccessChain(); builder.setAccessChainRValue(result); @@ -1100,6 +1117,8 @@ bool TGlslangToSpvTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TI convertGlslangToSpvType(node->getType()), operand, one, node->getType().getBasicType()); assert(result != spv::NoResult); + // Decorate this instruction, if this node has 'noContraction' qualifier. + addDecoration(result, TranslateNoContractionDecoration(node->getType().getQualifier())); // The result of operation is always stored, but conditionally the // consumed result. The consumed result is always an r-value. diff --git a/Test/baseResults/precise.tesc.out b/Test/baseResults/precise.tesc.out new file mode 100644 index 00000000..d14af90e --- /dev/null +++ b/Test/baseResults/precise.tesc.out @@ -0,0 +1,728 @@ +precise.tesc +Warning, version 450 is not yet complete; most version-specific features are present, but some are missing. + +Shader version: 450 +Requested GL_EXT_gpu_shader5 +Requested GL_EXT_shader_io_blocks +Requested GL_EXT_tessellation_shader +vertices = -1 +0:? Sequence +0:5 Function Definition: minimal( (global float) +0:5 Function Parameters: +0:6 Sequence +0:6 Sequence +0:6 move second child to first child (temp float) +0:6 'result' (noContraction temp float) +0:6 Constant: +0:6 5.000000 +0:7 Sequence +0:7 move second child to first child (temp float) +0:7 'a' (noContraction temp float) +0:7 Constant: +0:7 10.000000 +0:8 Sequence +0:8 move second child to first child (temp float) +0:8 'b' (noContraction temp float) +0:8 Constant: +0:8 20.000000 +0:9 Sequence +0:9 move second child to first child (temp float) +0:9 'c' (noContraction temp float) +0:9 Constant: +0:9 30.000000 +0:10 Sequence +0:10 move second child to first child (temp float) +0:10 'd' (noContraction temp float) +0:10 Constant: +0:10 40.000000 +0:11 move second child to first child (temp float) +0:11 'result' (noContraction temp float) +0:11 add (noContraction temp float) +0:11 component-wise multiply (noContraction temp float) +0:11 'a' (noContraction temp float) +0:11 'b' (noContraction temp float) +0:11 component-wise multiply (noContraction temp float) +0:11 'c' (noContraction temp float) +0:11 'd' (noContraction temp float) +0:12 Branch: Return with expression +0:12 'result' (noContraction temp float) +0:15 Function Definition: continuous_assignment( (global void) +0:15 Function Parameters: +0:16 Sequence +0:16 Sequence +0:16 move second child to first child (temp float) +0:16 'result' (noContraction temp float) +0:16 Constant: +0:16 5.000000 +0:17 Sequence +0:17 move second child to first child (temp int) +0:17 'a' (noContraction temp int) +0:17 Constant: +0:17 10 (const int) +0:18 Sequence +0:18 move second child to first child (temp int) +0:18 'b' (noContraction temp int) +0:18 Constant: +0:18 20 (const int) +0:19 move second child to first child (temp float) +0:19 'result' (noContraction temp float) +0:19 Convert int to float (temp float) +0:19 move second child to first child (temp int) +0:19 'a' (noContraction temp int) +0:19 add (noContraction temp int) +0:19 'b' (noContraction temp int) +0:19 Constant: +0:19 4 (const int) +0:22 Function Definition: convert( (global void) +0:22 Function Parameters: +0:? Sequence +0:24 Sequence +0:24 move second child to first child (temp int) +0:24 'a' (noContraction temp int) +0:24 Constant: +0:24 10 (const int) +0:25 Sequence +0:25 move second child to first child (temp int) +0:25 'b' (noContraction temp int) +0:25 Constant: +0:25 20 (const int) +0:26 move second child to first child (temp int) +0:26 'b' (noContraction temp int) +0:26 add (noContraction temp int) +0:26 'a' (noContraction temp int) +0:26 'b' (noContraction temp int) +0:27 move second child to first child (temp float) +0:27 'result' (noContraction temp float) +0:27 Convert int to float (temp float) +0:27 'b' (noContraction temp int) +0:30 Function Definition: loop_for( (global float) +0:30 Function Parameters: +0:31 Sequence +0:31 Sequence +0:31 move second child to first child (temp float) +0:31 'r1' (noContraction temp float) +0:31 Constant: +0:31 5.000000 +0:32 Sequence +0:32 move second child to first child (temp float) +0:32 'r2' (noContraction temp float) +0:32 Constant: +0:32 10.000000 +0:33 Sequence +0:33 move second child to first child (temp int) +0:33 'a' (temp int) +0:33 Constant: +0:33 10 (const int) +0:34 Sequence +0:34 move second child to first child (temp int) +0:34 'b' (noContraction temp int) +0:34 Constant: +0:34 20 (const int) +0:35 Sequence +0:35 move second child to first child (temp int) +0:35 'c' (noContraction temp int) +0:35 Constant: +0:35 30 (const int) +0:36 Sequence +0:36 Sequence +0:36 move second child to first child (temp int) +0:36 'i' (noContraction temp int) +0:36 Constant: +0:36 0 (const int) +0:36 Loop with condition tested first +0:36 Loop Condition +0:36 Compare Less Than (temp bool) +0:36 'i' (temp int) +0:36 'a' (temp int) +0:36 Loop Body +0:37 Sequence +0:37 add second child into first child (noContraction temp float) +0:37 'r1' (noContraction temp float) +0:37 add (noContraction temp float) +0:37 add (noContraction temp float) +0:37 Constant: +0:37 3.120000 +0:37 Convert int to float (temp float) +0:37 'b' (noContraction temp int) +0:37 Convert int to float (temp float) +0:37 'i' (noContraction temp int) +0:38 add second child into first child (noContraction temp int) +0:38 'c' (noContraction temp int) +0:38 Constant: +0:38 1 (const int) +0:36 Loop Terminal Expression +0:36 Post-Increment (noContraction temp int) +0:36 'i' (noContraction temp int) +0:40 add second child into first child (temp int) +0:40 'a' (temp int) +0:40 Constant: +0:40 1 (const int) +0:41 move second child to first child (temp float) +0:41 'r2' (noContraction temp float) +0:41 Convert int to float (temp float) +0:41 'c' (noContraction temp int) +0:42 Branch: Return with expression +0:42 Construct float (temp float) +0:42 add (temp float) +0:42 'r1' (noContraction temp float) +0:42 'r2' (noContraction temp float) +0:45 Function Definition: loop_array( (global void) +0:45 Function Parameters: +0:46 Sequence +0:46 Sequence +0:46 move second child to first child (temp int) +0:46 'result' (noContraction temp int) +0:46 Constant: +0:46 5 (const int) +0:48 Sequence +0:48 move second child to first child (temp int) +0:48 'x' (noContraction temp int) +0:48 Constant: +0:48 22 (const int) +0:49 Sequence +0:49 move second child to first child (temp int) +0:49 'y' (noContraction temp int) +0:49 Constant: +0:49 33 (const int) +0:52 add second child into first child (noContraction temp int) +0:52 'result' (noContraction temp int) +0:52 add (noContraction temp int) +0:52 'x' (noContraction temp int) +0:52 'y' (noContraction temp int) +0:54 Sequence +0:54 Sequence +0:54 move second child to first child (temp int) +0:54 'i' (temp int) +0:54 Constant: +0:54 0 (const int) +0:54 Loop with condition tested first +0:54 Loop Condition +0:54 Compare Less Than (temp bool) +0:54 'i' (temp int) +0:54 Constant: +0:54 3 (const int) +0:54 Loop Body +0:56 Sequence +0:56 add second child into first child (noContraction temp int) +0:56 'result' (noContraction temp int) +0:56 add (noContraction temp int) +0:56 indirect index (noContraction temp int) +0:56 'a0' (temp 3-element array of int) +0:56 'i' (temp int) +0:56 Constant: +0:56 2 (const int) +0:58 move second child to first child (temp int) +0:58 indirect index (noContraction temp int) +0:58 'a0' (noContraction temp 3-element array of int) +0:58 'i' (temp int) +0:58 subtract (noContraction temp int) +0:58 Constant: +0:58 3 (const int) +0:58 Post-Increment (noContraction temp int) +0:58 'result' (noContraction temp int) +0:54 Loop Terminal Expression +0:54 Pre-Increment (temp int) +0:54 'i' (temp int) +0:62 Function Definition: loop_while( (global void) +0:62 Function Parameters: +0:63 Sequence +0:63 Sequence +0:63 move second child to first child (temp float) +0:63 'result' (noContraction temp float) +0:63 Constant: +0:63 5.000000 +0:64 Sequence +0:64 move second child to first child (temp int) +0:64 'a' (noContraction temp int) +0:64 Constant: +0:64 10 (const int) +0:65 Sequence +0:65 move second child to first child (temp int) +0:65 'b' (noContraction temp int) +0:65 Constant: +0:65 20 (const int) +0:66 Loop with condition tested first +0:66 Loop Condition +0:66 Compare Less Than (temp bool) +0:66 'result' (noContraction temp float) +0:66 Constant: +0:66 10.000000 +0:66 Loop Body +0:67 Sequence +0:67 add second child into first child (noContraction temp float) +0:67 'result' (noContraction temp float) +0:67 add (noContraction temp float) +0:67 Constant: +0:67 3.120000 +0:67 Convert int to float (temp float) +0:67 'b' (noContraction temp int) +0:69 move second child to first child (temp float) +0:69 'result' (noContraction temp float) +0:69 Convert int to float (temp float) +0:69 add (noContraction temp int) +0:69 add (noContraction temp int) +0:69 'a' (noContraction temp int) +0:69 'b' (noContraction temp int) +0:69 Constant: +0:69 5 (const int) +0:70 move second child to first child (temp float) +0:70 'result' (noContraction temp float) +0:70 Constant: +0:70 11.100000 +0:73 Function Definition: fma_not_decorated( (global float) +0:73 Function Parameters: +0:? Sequence +0:75 Sequence +0:75 move second child to first child (temp float) +0:75 'a' (noContraction temp float) +0:75 Constant: +0:75 1.000000 +0:76 Sequence +0:76 move second child to first child (temp float) +0:76 'b' (noContraction temp float) +0:76 Constant: +0:76 2.000000 +0:77 Sequence +0:77 move second child to first child (temp float) +0:77 'c' (noContraction temp float) +0:77 Constant: +0:77 3.000000 +0:78 move second child to first child (temp float) +0:78 'b' (noContraction temp float) +0:78 add (noContraction temp float) +0:78 'b' (noContraction temp float) +0:78 'c' (noContraction temp float) +0:79 move second child to first child (temp float) +0:79 'result' (noContraction temp float) +0:79 fma (global float) +0:79 'a' (noContraction temp float) +0:79 'b' (noContraction temp float) +0:79 'c' (noContraction temp float) +0:80 Branch: Return with expression +0:80 'result' (noContraction temp float) +0:83 Function Definition: precise_return_exp_func( (noContraction temp float) +0:83 Function Parameters: +0:84 Sequence +0:84 Sequence +0:84 move second child to first child (temp float) +0:84 'a' (noContraction temp float) +0:84 Constant: +0:84 1.000000 +0:85 Sequence +0:85 move second child to first child (temp float) +0:85 'b' (noContraction temp float) +0:85 Constant: +0:85 2.000000 +0:86 Branch: Return with expression +0:86 add (noContraction temp float) +0:86 'a' (noContraction temp float) +0:86 'b' (noContraction temp float) +0:89 Function Definition: precise_return_val_func( (noContraction temp float) +0:89 Function Parameters: +0:90 Sequence +0:90 Sequence +0:90 move second child to first child (temp float) +0:90 'a' (noContraction temp float) +0:90 Constant: +0:90 1.000000 +0:91 Sequence +0:91 move second child to first child (temp float) +0:91 'b' (noContraction temp float) +0:91 Constant: +0:91 2.000000 +0:92 Sequence +0:92 move second child to first child (temp float) +0:92 'result' (noContraction temp float) +0:92 add (noContraction temp float) +0:92 'a' (noContraction temp float) +0:92 'b' (noContraction temp float) +0:93 Branch: Return with expression +0:93 'result' (noContraction temp float) +0:96 Function Definition: precise_func_parameter(f1;f1; (global float) +0:96 Function Parameters: +0:96 'b' (in float) +0:96 'c' (out float) +0:97 Sequence +0:97 Sequence +0:97 move second child to first child (temp float) +0:97 'a' (temp float) +0:97 Constant: +0:97 0.500000 +0:98 move second child to first child (temp float) +0:98 'c' (out float) +0:98 add (temp float) +0:98 'a' (temp float) +0:98 'b' (in float) +0:99 Branch: Return with expression +0:99 subtract (temp float) +0:99 'a' (temp float) +0:99 'b' (in float) +0:102 Function Definition: main( (global void) +0:102 Function Parameters: +0:? Linker Objects + + +Linked tessellation control stage: + +ERROR: Linking tessellation control stage: At least one shader must specify an output layout(vertices=...) + +Shader version: 450 +Requested GL_EXT_gpu_shader5 +Requested GL_EXT_shader_io_blocks +Requested GL_EXT_tessellation_shader +vertices = -1 +0:? Sequence +0:5 Function Definition: minimal( (global float) +0:5 Function Parameters: +0:6 Sequence +0:6 Sequence +0:6 move second child to first child (temp float) +0:6 'result' (noContraction temp float) +0:6 Constant: +0:6 5.000000 +0:7 Sequence +0:7 move second child to first child (temp float) +0:7 'a' (noContraction temp float) +0:7 Constant: +0:7 10.000000 +0:8 Sequence +0:8 move second child to first child (temp float) +0:8 'b' (noContraction temp float) +0:8 Constant: +0:8 20.000000 +0:9 Sequence +0:9 move second child to first child (temp float) +0:9 'c' (noContraction temp float) +0:9 Constant: +0:9 30.000000 +0:10 Sequence +0:10 move second child to first child (temp float) +0:10 'd' (noContraction temp float) +0:10 Constant: +0:10 40.000000 +0:11 move second child to first child (temp float) +0:11 'result' (noContraction temp float) +0:11 add (noContraction temp float) +0:11 component-wise multiply (noContraction temp float) +0:11 'a' (noContraction temp float) +0:11 'b' (noContraction temp float) +0:11 component-wise multiply (noContraction temp float) +0:11 'c' (noContraction temp float) +0:11 'd' (noContraction temp float) +0:12 Branch: Return with expression +0:12 'result' (noContraction temp float) +0:15 Function Definition: continuous_assignment( (global void) +0:15 Function Parameters: +0:16 Sequence +0:16 Sequence +0:16 move second child to first child (temp float) +0:16 'result' (noContraction temp float) +0:16 Constant: +0:16 5.000000 +0:17 Sequence +0:17 move second child to first child (temp int) +0:17 'a' (noContraction temp int) +0:17 Constant: +0:17 10 (const int) +0:18 Sequence +0:18 move second child to first child (temp int) +0:18 'b' (noContraction temp int) +0:18 Constant: +0:18 20 (const int) +0:19 move second child to first child (temp float) +0:19 'result' (noContraction temp float) +0:19 Convert int to float (temp float) +0:19 move second child to first child (temp int) +0:19 'a' (noContraction temp int) +0:19 add (noContraction temp int) +0:19 'b' (noContraction temp int) +0:19 Constant: +0:19 4 (const int) +0:22 Function Definition: convert( (global void) +0:22 Function Parameters: +0:? Sequence +0:24 Sequence +0:24 move second child to first child (temp int) +0:24 'a' (noContraction temp int) +0:24 Constant: +0:24 10 (const int) +0:25 Sequence +0:25 move second child to first child (temp int) +0:25 'b' (noContraction temp int) +0:25 Constant: +0:25 20 (const int) +0:26 move second child to first child (temp int) +0:26 'b' (noContraction temp int) +0:26 add (noContraction temp int) +0:26 'a' (noContraction temp int) +0:26 'b' (noContraction temp int) +0:27 move second child to first child (temp float) +0:27 'result' (noContraction temp float) +0:27 Convert int to float (temp float) +0:27 'b' (noContraction temp int) +0:30 Function Definition: loop_for( (global float) +0:30 Function Parameters: +0:31 Sequence +0:31 Sequence +0:31 move second child to first child (temp float) +0:31 'r1' (noContraction temp float) +0:31 Constant: +0:31 5.000000 +0:32 Sequence +0:32 move second child to first child (temp float) +0:32 'r2' (noContraction temp float) +0:32 Constant: +0:32 10.000000 +0:33 Sequence +0:33 move second child to first child (temp int) +0:33 'a' (temp int) +0:33 Constant: +0:33 10 (const int) +0:34 Sequence +0:34 move second child to first child (temp int) +0:34 'b' (noContraction temp int) +0:34 Constant: +0:34 20 (const int) +0:35 Sequence +0:35 move second child to first child (temp int) +0:35 'c' (noContraction temp int) +0:35 Constant: +0:35 30 (const int) +0:36 Sequence +0:36 Sequence +0:36 move second child to first child (temp int) +0:36 'i' (noContraction temp int) +0:36 Constant: +0:36 0 (const int) +0:36 Loop with condition tested first +0:36 Loop Condition +0:36 Compare Less Than (temp bool) +0:36 'i' (temp int) +0:36 'a' (temp int) +0:36 Loop Body +0:37 Sequence +0:37 add second child into first child (noContraction temp float) +0:37 'r1' (noContraction temp float) +0:37 add (noContraction temp float) +0:37 add (noContraction temp float) +0:37 Constant: +0:37 3.120000 +0:37 Convert int to float (temp float) +0:37 'b' (noContraction temp int) +0:37 Convert int to float (temp float) +0:37 'i' (noContraction temp int) +0:38 add second child into first child (noContraction temp int) +0:38 'c' (noContraction temp int) +0:38 Constant: +0:38 1 (const int) +0:36 Loop Terminal Expression +0:36 Post-Increment (noContraction temp int) +0:36 'i' (noContraction temp int) +0:40 add second child into first child (temp int) +0:40 'a' (temp int) +0:40 Constant: +0:40 1 (const int) +0:41 move second child to first child (temp float) +0:41 'r2' (noContraction temp float) +0:41 Convert int to float (temp float) +0:41 'c' (noContraction temp int) +0:42 Branch: Return with expression +0:42 Construct float (temp float) +0:42 add (temp float) +0:42 'r1' (noContraction temp float) +0:42 'r2' (noContraction temp float) +0:45 Function Definition: loop_array( (global void) +0:45 Function Parameters: +0:46 Sequence +0:46 Sequence +0:46 move second child to first child (temp int) +0:46 'result' (noContraction temp int) +0:46 Constant: +0:46 5 (const int) +0:48 Sequence +0:48 move second child to first child (temp int) +0:48 'x' (noContraction temp int) +0:48 Constant: +0:48 22 (const int) +0:49 Sequence +0:49 move second child to first child (temp int) +0:49 'y' (noContraction temp int) +0:49 Constant: +0:49 33 (const int) +0:52 add second child into first child (noContraction temp int) +0:52 'result' (noContraction temp int) +0:52 add (noContraction temp int) +0:52 'x' (noContraction temp int) +0:52 'y' (noContraction temp int) +0:54 Sequence +0:54 Sequence +0:54 move second child to first child (temp int) +0:54 'i' (temp int) +0:54 Constant: +0:54 0 (const int) +0:54 Loop with condition tested first +0:54 Loop Condition +0:54 Compare Less Than (temp bool) +0:54 'i' (temp int) +0:54 Constant: +0:54 3 (const int) +0:54 Loop Body +0:56 Sequence +0:56 add second child into first child (noContraction temp int) +0:56 'result' (noContraction temp int) +0:56 add (noContraction temp int) +0:56 indirect index (noContraction temp int) +0:56 'a0' (temp 3-element array of int) +0:56 'i' (temp int) +0:56 Constant: +0:56 2 (const int) +0:58 move second child to first child (temp int) +0:58 indirect index (noContraction temp int) +0:58 'a0' (noContraction temp 3-element array of int) +0:58 'i' (temp int) +0:58 subtract (noContraction temp int) +0:58 Constant: +0:58 3 (const int) +0:58 Post-Increment (noContraction temp int) +0:58 'result' (noContraction temp int) +0:54 Loop Terminal Expression +0:54 Pre-Increment (temp int) +0:54 'i' (temp int) +0:62 Function Definition: loop_while( (global void) +0:62 Function Parameters: +0:63 Sequence +0:63 Sequence +0:63 move second child to first child (temp float) +0:63 'result' (noContraction temp float) +0:63 Constant: +0:63 5.000000 +0:64 Sequence +0:64 move second child to first child (temp int) +0:64 'a' (noContraction temp int) +0:64 Constant: +0:64 10 (const int) +0:65 Sequence +0:65 move second child to first child (temp int) +0:65 'b' (noContraction temp int) +0:65 Constant: +0:65 20 (const int) +0:66 Loop with condition tested first +0:66 Loop Condition +0:66 Compare Less Than (temp bool) +0:66 'result' (noContraction temp float) +0:66 Constant: +0:66 10.000000 +0:66 Loop Body +0:67 Sequence +0:67 add second child into first child (noContraction temp float) +0:67 'result' (noContraction temp float) +0:67 add (noContraction temp float) +0:67 Constant: +0:67 3.120000 +0:67 Convert int to float (temp float) +0:67 'b' (noContraction temp int) +0:69 move second child to first child (temp float) +0:69 'result' (noContraction temp float) +0:69 Convert int to float (temp float) +0:69 add (noContraction temp int) +0:69 add (noContraction temp int) +0:69 'a' (noContraction temp int) +0:69 'b' (noContraction temp int) +0:69 Constant: +0:69 5 (const int) +0:70 move second child to first child (temp float) +0:70 'result' (noContraction temp float) +0:70 Constant: +0:70 11.100000 +0:73 Function Definition: fma_not_decorated( (global float) +0:73 Function Parameters: +0:? Sequence +0:75 Sequence +0:75 move second child to first child (temp float) +0:75 'a' (noContraction temp float) +0:75 Constant: +0:75 1.000000 +0:76 Sequence +0:76 move second child to first child (temp float) +0:76 'b' (noContraction temp float) +0:76 Constant: +0:76 2.000000 +0:77 Sequence +0:77 move second child to first child (temp float) +0:77 'c' (noContraction temp float) +0:77 Constant: +0:77 3.000000 +0:78 move second child to first child (temp float) +0:78 'b' (noContraction temp float) +0:78 add (noContraction temp float) +0:78 'b' (noContraction temp float) +0:78 'c' (noContraction temp float) +0:79 move second child to first child (temp float) +0:79 'result' (noContraction temp float) +0:79 fma (global float) +0:79 'a' (noContraction temp float) +0:79 'b' (noContraction temp float) +0:79 'c' (noContraction temp float) +0:80 Branch: Return with expression +0:80 'result' (noContraction temp float) +0:83 Function Definition: precise_return_exp_func( (noContraction temp float) +0:83 Function Parameters: +0:84 Sequence +0:84 Sequence +0:84 move second child to first child (temp float) +0:84 'a' (noContraction temp float) +0:84 Constant: +0:84 1.000000 +0:85 Sequence +0:85 move second child to first child (temp float) +0:85 'b' (noContraction temp float) +0:85 Constant: +0:85 2.000000 +0:86 Branch: Return with expression +0:86 add (noContraction temp float) +0:86 'a' (noContraction temp float) +0:86 'b' (noContraction temp float) +0:89 Function Definition: precise_return_val_func( (noContraction temp float) +0:89 Function Parameters: +0:90 Sequence +0:90 Sequence +0:90 move second child to first child (temp float) +0:90 'a' (noContraction temp float) +0:90 Constant: +0:90 1.000000 +0:91 Sequence +0:91 move second child to first child (temp float) +0:91 'b' (noContraction temp float) +0:91 Constant: +0:91 2.000000 +0:92 Sequence +0:92 move second child to first child (temp float) +0:92 'result' (noContraction temp float) +0:92 add (noContraction temp float) +0:92 'a' (noContraction temp float) +0:92 'b' (noContraction temp float) +0:93 Branch: Return with expression +0:93 'result' (noContraction temp float) +0:96 Function Definition: precise_func_parameter(f1;f1; (global float) +0:96 Function Parameters: +0:96 'b' (in float) +0:96 'c' (out float) +0:97 Sequence +0:97 Sequence +0:97 move second child to first child (temp float) +0:97 'a' (temp float) +0:97 Constant: +0:97 0.500000 +0:98 move second child to first child (temp float) +0:98 'c' (out float) +0:98 add (temp float) +0:98 'a' (temp float) +0:98 'b' (in float) +0:99 Branch: Return with expression +0:99 subtract (temp float) +0:99 'a' (temp float) +0:99 'b' (in float) +0:102 Function Definition: main( (global void) +0:102 Function Parameters: +0:? Linker Objects + diff --git a/Test/baseResults/precise_struct_block.vert.out b/Test/baseResults/precise_struct_block.vert.out new file mode 100644 index 00000000..7d783e55 --- /dev/null +++ b/Test/baseResults/precise_struct_block.vert.out @@ -0,0 +1,1045 @@ +precise_struct_block.vert +Warning, version 450 is not yet complete; most version-specific features are present, but some are missing. + +Shader version: 450 +0:? Sequence +0:11 Function Definition: struct_member( (global float) +0:11 Function Parameters: +0:12 Sequence +0:12 Sequence +0:12 move second child to first child (temp float) +0:12 'a' (noContraction temp float) +0:12 Constant: +0:12 1.000000 +0:13 Sequence +0:13 move second child to first child (temp float) +0:13 'b' (temp float) +0:13 Constant: +0:13 2.000000 +0:14 Sequence +0:14 move second child to first child (temp float) +0:14 'c' (temp float) +0:14 Constant: +0:14 3.000000 +0:15 Sequence +0:15 move second child to first child (temp float) +0:15 'd' (temp float) +0:15 Constant: +0:15 4.000000 +0:21 move second child to first child (temp float) +0:21 f1: direct index for structure (noContraction global float) +0:21 'S2' (temp structure{global float f1, global float f2}) +0:21 Constant: +0:21 0 (const int) +0:21 add (noContraction temp float) +0:21 'a' (noContraction temp float) +0:21 Constant: +0:21 0.200000 +0:22 move second child to first child (temp float) +0:22 f2: direct index for structure (global float) +0:22 'S2' (temp structure{global float f1, global float f2}) +0:22 Constant: +0:22 1 (const int) +0:22 add (temp float) +0:22 'b' (temp float) +0:22 Constant: +0:22 0.200000 +0:23 move second child to first child (temp float) +0:23 f1: direct index for structure (global float) +0:23 'S3' (temp structure{global float f1, global float f2}) +0:23 Constant: +0:23 0 (const int) +0:23 add (temp float) +0:23 'a' (temp float) +0:23 'b' (temp float) +0:24 move second child to first child (temp structure{global float f1, global float f2}) +0:24 'S' (temp structure{global float f1, global float f2}) +0:24 'S2' (temp structure{global float f1, global float f2}) +0:25 move second child to first child (temp float) +0:25 'result' (noContraction temp float) +0:25 add (noContraction temp float) +0:25 f1: direct index for structure (noContraction global float) +0:25 'S' (temp structure{global float f1, global float f2}) +0:25 Constant: +0:25 0 (const int) +0:25 Constant: +0:25 0.100000 +0:27 Branch: Return with expression +0:27 'result' (noContraction temp float) +0:30 Function Definition: complex_array_struct( (global float) +0:30 Function Parameters: +0:? Sequence +0:43 Sequence +0:43 Sequence +0:43 move second child to first child (temp int) +0:43 'i' (noContraction temp int) +0:43 Constant: +0:43 0 (const int) +0:43 Loop with condition tested first +0:43 Loop Condition +0:43 Compare Less Than (temp bool) +0:43 'i' (temp int) +0:43 Constant: +0:43 10 (const int) +0:43 Loop Body +0:44 Sequence +0:44 move second child to first child (temp float) +0:44 f: direct index for structure (temp float) +0:44 indirect index (temp structure{temp float f, temp structure{temp 5-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1a, temp 6-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1b, temp 7-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1c} t2, temp 4-component vector of float v, temp int p}) +0:44 't3' (temp 10-element array of structure{temp float f, temp structure{temp 5-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1a, temp 6-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1b, temp 7-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1c} t2, temp 4-component vector of float v, temp int p}) +0:44 'i' (temp int) +0:44 Constant: +0:44 0 (const int) +0:44 divide (temp float) +0:44 Convert int to float (temp float) +0:44 'i' (temp int) +0:44 Constant: +0:44 3.000000 +0:45 move second child to first child (temp 4-component vector of float) +0:45 v: direct index for structure (noContraction temp 4-component vector of float) +0:45 indirect index (temp structure{temp float f, temp structure{temp 5-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1a, temp 6-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1b, temp 7-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1c} t2, temp 4-component vector of float v, temp int p}) +0:45 't3' (temp 10-element array of structure{temp float f, temp structure{temp 5-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1a, temp 6-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1b, temp 7-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1c} t2, temp 4-component vector of float v, temp int p}) +0:45 'i' (temp int) +0:45 Constant: +0:45 2 (const int) +0:45 Construct vec4 (temp 4-component vector of float) +0:45 component-wise multiply (noContraction temp float) +0:45 Convert int to float (temp float) +0:45 'i' (noContraction temp int) +0:45 Constant: +0:45 1.500000 +0:46 move second child to first child (temp int) +0:46 p: direct index for structure (temp int) +0:46 indirect index (temp structure{temp float f, temp structure{temp 5-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1a, temp 6-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1b, temp 7-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1c} t2, temp 4-component vector of float v, temp int p}) +0:46 't3' (temp 10-element array of structure{temp float f, temp structure{temp 5-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1a, temp 6-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1b, temp 7-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1c} t2, temp 4-component vector of float v, temp int p}) +0:46 'i' (temp int) +0:46 Constant: +0:46 3 (const int) +0:46 add (temp int) +0:46 'i' (temp int) +0:46 Constant: +0:46 1 (const int) +0:47 Sequence +0:47 Sequence +0:47 move second child to first child (temp int) +0:47 'j' (temp int) +0:47 Constant: +0:47 0 (const int) +0:47 Loop with condition tested first +0:47 Loop Condition +0:47 Compare Less Than (temp bool) +0:47 'j' (temp int) +0:47 Constant: +0:47 5 (const int) +0:47 Loop Body +0:48 Sequence +0:48 Sequence +0:48 Sequence +0:48 move second child to first child (temp int) +0:48 'k' (temp int) +0:48 Constant: +0:48 0 (const int) +0:48 Loop with condition tested first +0:48 Loop Condition +0:48 Compare Less Than (temp bool) +0:48 'k' (temp int) +0:48 Constant: +0:48 3 (const int) +0:48 Loop Body +0:49 Sequence +0:49 move second child to first child (temp float) +0:49 indirect index (temp float) +0:49 t1_array: direct index for structure (temp 3-element array of float) +0:49 indirect index (temp structure{temp 3-element array of float t1_array, temp float t1_scalar}) +0:49 t1a: direct index for structure (temp 5-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar}) +0:49 t2: direct index for structure (temp structure{temp 5-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1a, temp 6-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1b, temp 7-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1c}) +0:49 indirect index (temp structure{temp float f, temp structure{temp 5-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1a, temp 6-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1b, temp 7-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1c} t2, temp 4-component vector of float v, temp int p}) +0:49 't3' (temp 10-element array of structure{temp float f, temp structure{temp 5-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1a, temp 6-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1b, temp 7-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1c} t2, temp 4-component vector of float v, temp int p}) +0:49 'i' (temp int) +0:49 Constant: +0:49 1 (const int) +0:49 Constant: +0:49 0 (const int) +0:49 'j' (temp int) +0:49 Constant: +0:49 0 (const int) +0:49 'k' (temp int) +0:49 Convert int to float (temp float) +0:49 add (temp int) +0:49 component-wise multiply (temp int) +0:49 'i' (temp int) +0:49 'j' (temp int) +0:49 'k' (temp int) +0:48 Loop Terminal Expression +0:48 Post-Increment (temp int) +0:48 'k' (temp int) +0:51 move second child to first child (temp float) +0:51 t1_scalar: direct index for structure (temp float) +0:51 indirect index (temp structure{temp 3-element array of float t1_array, temp float t1_scalar}) +0:51 t1a: direct index for structure (temp 5-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar}) +0:51 t2: direct index for structure (temp structure{temp 5-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1a, temp 6-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1b, temp 7-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1c}) +0:51 indirect index (temp structure{temp float f, temp structure{temp 5-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1a, temp 6-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1b, temp 7-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1c} t2, temp 4-component vector of float v, temp int p}) +0:51 't3' (temp 10-element array of structure{temp float f, temp structure{temp 5-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1a, temp 6-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1b, temp 7-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1c} t2, temp 4-component vector of float v, temp int p}) +0:51 'i' (temp int) +0:51 Constant: +0:51 1 (const int) +0:51 Constant: +0:51 0 (const int) +0:51 'j' (temp int) +0:51 Constant: +0:51 1 (const int) +0:51 divide (temp float) +0:51 component-wise multiply (temp float) +0:51 Convert int to float (temp float) +0:51 'j' (temp int) +0:51 Constant: +0:51 2.000000 +0:51 Convert int to float (temp float) +0:51 'i' (temp int) +0:47 Loop Terminal Expression +0:47 Post-Increment (temp int) +0:47 'j' (temp int) +0:54 Sequence +0:54 Sequence +0:54 move second child to first child (temp int) +0:54 'j' (noContraction temp int) +0:54 Constant: +0:54 0 (const int) +0:54 Loop with condition tested first +0:54 Loop Condition +0:54 Compare Less Than (temp bool) +0:54 'j' (temp int) +0:54 Constant: +0:54 6 (const int) +0:54 Loop Body +0:55 Sequence +0:55 Sequence +0:55 Sequence +0:55 move second child to first child (temp int) +0:55 'k' (temp int) +0:55 Constant: +0:55 0 (const int) +0:55 Loop with condition tested first +0:55 Loop Condition +0:55 Compare Less Than (temp bool) +0:55 'k' (temp int) +0:55 Constant: +0:55 3 (const int) +0:55 Loop Body +0:56 Sequence +0:56 move second child to first child (temp float) +0:56 indirect index (temp float) +0:56 t1_array: direct index for structure (temp 3-element array of float) +0:56 indirect index (temp structure{temp 3-element array of float t1_array, temp float t1_scalar}) +0:56 t1b: direct index for structure (temp 6-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar}) +0:56 t2: direct index for structure (temp structure{temp 5-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1a, temp 6-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1b, temp 7-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1c}) +0:56 indirect index (temp structure{temp float f, temp structure{temp 5-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1a, temp 6-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1b, temp 7-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1c} t2, temp 4-component vector of float v, temp int p}) +0:56 't3' (temp 10-element array of structure{temp float f, temp structure{temp 5-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1a, temp 6-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1b, temp 7-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1c} t2, temp 4-component vector of float v, temp int p}) +0:56 'i' (temp int) +0:56 Constant: +0:56 1 (const int) +0:56 Constant: +0:56 1 (const int) +0:56 'j' (temp int) +0:56 Constant: +0:56 0 (const int) +0:56 'k' (temp int) +0:56 Convert int to float (temp float) +0:56 add (temp int) +0:56 component-wise multiply (temp int) +0:56 'i' (temp int) +0:56 'j' (temp int) +0:56 'k' (temp int) +0:55 Loop Terminal Expression +0:55 Post-Increment (temp int) +0:55 'k' (temp int) +0:58 move second child to first child (temp float) +0:58 t1_scalar: direct index for structure (noContraction temp float) +0:58 indirect index (temp structure{temp 3-element array of float t1_array, temp float t1_scalar}) +0:58 t1b: direct index for structure (temp 6-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar}) +0:58 t2: direct index for structure (temp structure{temp 5-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1a, temp 6-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1b, temp 7-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1c}) +0:58 indirect index (temp structure{temp float f, temp structure{temp 5-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1a, temp 6-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1b, temp 7-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1c} t2, temp 4-component vector of float v, temp int p}) +0:58 't3' (temp 10-element array of structure{temp float f, temp structure{temp 5-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1a, temp 6-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1b, temp 7-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1c} t2, temp 4-component vector of float v, temp int p}) +0:58 'i' (temp int) +0:58 Constant: +0:58 1 (const int) +0:58 Constant: +0:58 1 (const int) +0:58 'j' (temp int) +0:58 Constant: +0:58 1 (const int) +0:58 divide (noContraction temp float) +0:58 component-wise multiply (noContraction temp float) +0:58 Convert int to float (temp float) +0:58 'j' (noContraction temp int) +0:58 Constant: +0:58 2.000000 +0:58 Convert int to float (temp float) +0:58 'i' (noContraction temp int) +0:54 Loop Terminal Expression +0:54 Post-Increment (noContraction temp int) +0:54 'j' (noContraction temp int) +0:61 Sequence +0:61 Sequence +0:61 move second child to first child (temp int) +0:61 'j' (noContraction temp int) +0:61 Constant: +0:61 0 (const int) +0:61 Loop with condition tested first +0:61 Loop Condition +0:61 Compare Less Than (temp bool) +0:61 'j' (temp int) +0:61 Constant: +0:61 6 (const int) +0:61 Loop Body +0:62 Sequence +0:62 Sequence +0:62 Sequence +0:62 move second child to first child (temp int) +0:62 'k' (noContraction temp int) +0:62 Constant: +0:62 0 (const int) +0:62 Loop with condition tested first +0:62 Loop Condition +0:62 Compare Less Than (temp bool) +0:62 'k' (temp int) +0:62 Constant: +0:62 3 (const int) +0:62 Loop Body +0:63 Sequence +0:63 move second child to first child (temp float) +0:63 indirect index (noContraction temp float) +0:63 t1_array: direct index for structure (noContraction temp 3-element array of float) +0:63 indirect index (temp structure{temp 3-element array of float t1_array, temp float t1_scalar}) +0:63 t1c: direct index for structure (temp 7-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar}) +0:63 t2: direct index for structure (temp structure{temp 5-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1a, temp 6-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1b, temp 7-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1c}) +0:63 indirect index (temp structure{temp float f, temp structure{temp 5-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1a, temp 6-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1b, temp 7-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1c} t2, temp 4-component vector of float v, temp int p}) +0:63 't3' (temp 10-element array of structure{temp float f, temp structure{temp 5-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1a, temp 6-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1b, temp 7-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1c} t2, temp 4-component vector of float v, temp int p}) +0:63 'i' (temp int) +0:63 Constant: +0:63 1 (const int) +0:63 Constant: +0:63 2 (const int) +0:63 'j' (temp int) +0:63 Constant: +0:63 0 (const int) +0:63 'k' (temp int) +0:63 Convert int to float (temp float) +0:63 add (noContraction temp int) +0:63 component-wise multiply (noContraction temp int) +0:63 'i' (noContraction temp int) +0:63 'j' (noContraction temp int) +0:63 'k' (noContraction temp int) +0:62 Loop Terminal Expression +0:62 Post-Increment (noContraction temp int) +0:62 'k' (noContraction temp int) +0:65 move second child to first child (temp float) +0:65 t1_scalar: direct index for structure (temp float) +0:65 indirect index (temp structure{temp 3-element array of float t1_array, temp float t1_scalar}) +0:65 t1c: direct index for structure (temp 7-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar}) +0:65 t2: direct index for structure (temp structure{temp 5-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1a, temp 6-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1b, temp 7-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1c}) +0:65 indirect index (temp structure{temp float f, temp structure{temp 5-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1a, temp 6-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1b, temp 7-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1c} t2, temp 4-component vector of float v, temp int p}) +0:65 't3' (temp 10-element array of structure{temp float f, temp structure{temp 5-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1a, temp 6-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1b, temp 7-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1c} t2, temp 4-component vector of float v, temp int p}) +0:65 'i' (temp int) +0:65 Constant: +0:65 1 (const int) +0:65 Constant: +0:65 2 (const int) +0:65 'j' (temp int) +0:65 Constant: +0:65 1 (const int) +0:65 divide (temp float) +0:65 component-wise multiply (temp float) +0:65 Convert int to float (temp float) +0:65 'j' (temp int) +0:65 Constant: +0:65 2.000000 +0:65 Convert int to float (temp float) +0:65 'i' (temp int) +0:61 Loop Terminal Expression +0:61 Post-Increment (noContraction temp int) +0:61 'j' (noContraction temp int) +0:43 Loop Terminal Expression +0:43 Post-Increment (noContraction temp int) +0:43 'i' (noContraction temp int) +0:68 Sequence +0:68 move second child to first child (temp int) +0:68 'i' (temp int) +0:68 Constant: +0:68 2 (const int) +0:69 move second child to first child (temp float) +0:69 'result' (noContraction temp float) +0:71 add (noContraction temp float) +0:70 add (noContraction temp float) +0:69 direct index (noContraction temp float) +0:69 t1_array: direct index for structure (temp 3-element array of float) +0:69 direct index (temp structure{temp 3-element array of float t1_array, temp float t1_scalar}) +0:69 t1c: direct index for structure (temp 7-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar}) +0:69 t2: direct index for structure (temp structure{temp 5-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1a, temp 6-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1b, temp 7-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1c}) +0:69 direct index (temp structure{temp float f, temp structure{temp 5-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1a, temp 6-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1b, temp 7-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1c} t2, temp 4-component vector of float v, temp int p}) +0:69 't3' (temp 10-element array of structure{temp float f, temp structure{temp 5-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1a, temp 6-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1b, temp 7-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1c} t2, temp 4-component vector of float v, temp int p}) +0:69 Constant: +0:69 5 (const int) +0:69 Constant: +0:69 1 (const int) +0:69 Constant: +0:69 2 (const int) +0:69 Constant: +0:69 6 (const int) +0:69 Constant: +0:69 0 (const int) +0:69 Constant: +0:69 1 (const int) +0:70 t1_scalar: direct index for structure (noContraction temp float) +0:70 direct index (temp structure{temp 3-element array of float t1_array, temp float t1_scalar}) +0:70 t1b: direct index for structure (temp 6-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar}) +0:70 t2: direct index for structure (temp structure{temp 5-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1a, temp 6-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1b, temp 7-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1c}) +0:70 direct index (temp structure{temp float f, temp structure{temp 5-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1a, temp 6-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1b, temp 7-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1c} t2, temp 4-component vector of float v, temp int p}) +0:70 't3' (temp 10-element array of structure{temp float f, temp structure{temp 5-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1a, temp 6-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1b, temp 7-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1c} t2, temp 4-component vector of float v, temp int p}) +0:70 Constant: +0:70 2 (const int) +0:70 Constant: +0:70 1 (const int) +0:70 Constant: +0:70 1 (const int) +0:70 Constant: +0:70 1 (const int) +0:70 Constant: +0:70 1 (const int) +0:71 direct index (noContraction temp float) +0:71 vector swizzle (temp 2-component vector of float) +0:71 v: direct index for structure (temp 4-component vector of float) +0:71 indirect index (temp structure{temp float f, temp structure{temp 5-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1a, temp 6-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1b, temp 7-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1c} t2, temp 4-component vector of float v, temp int p}) +0:71 't3' (temp 10-element array of structure{temp float f, temp structure{temp 5-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1a, temp 6-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1b, temp 7-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1c} t2, temp 4-component vector of float v, temp int p}) +0:71 subtract (temp int) +0:71 'i' (temp int) +0:71 Constant: +0:71 1 (const int) +0:71 Constant: +0:71 2 (const int) +0:71 Sequence +0:71 Constant: +0:71 0 (const int) +0:71 Constant: +0:71 1 (const int) +0:71 Constant: +0:71 0 (const int) +0:72 Branch: Return with expression +0:72 'result' (noContraction temp float) +0:75 Function Definition: out_block( (global float) +0:75 Function Parameters: +0:76 Sequence +0:76 Sequence +0:76 move second child to first child (temp float) +0:76 'a' (noContraction temp float) +0:76 Constant: +0:76 0.100000 +0:77 Sequence +0:77 move second child to first child (temp float) +0:77 'b' (noContraction temp float) +0:77 Constant: +0:77 0.200000 +0:78 move second child to first child (temp float) +0:78 f1: direct index for structure (noContraction global float) +0:78 s: direct index for structure (noContraction out structure{global float f1, global float f2}) +0:78 'partial_precise_block' (out block{noContraction out structure{global float f1, global float f2} s, out float x}) +0:78 Constant: +0:78 0 (const int) +0:78 Constant: +0:78 0 (const int) +0:78 add (noContraction temp float) +0:78 'a' (noContraction temp float) +0:78 'b' (noContraction temp float) +0:79 move second child to first child (temp float) +0:79 f2: direct index for structure (noContraction global float) +0:79 s: direct index for structure (noContraction out structure{global float f1, global float f2}) +0:79 'partial_precise_block' (out block{noContraction out structure{global float f1, global float f2} s, out float x}) +0:79 Constant: +0:79 0 (const int) +0:79 Constant: +0:79 1 (const int) +0:79 subtract (noContraction temp float) +0:79 'a' (noContraction temp float) +0:79 'b' (noContraction temp float) +0:80 move second child to first child (temp float) +0:80 x: direct index for structure (out float) +0:80 'partial_precise_block' (out block{noContraction out structure{global float f1, global float f2} s, out float x}) +0:80 Constant: +0:80 1 (const int) +0:80 component-wise multiply (temp float) +0:80 'a' (temp float) +0:80 'b' (temp float) +0:82 move second child to first child (temp float) +0:82 f1: direct index for structure (noContraction global float) +0:82 s: direct index for structure (noContraction out structure{global float f1, global float f2}) +0:82 'all_precise_block' (noContraction out block{out structure{global float f1, global float f2} s, out float x}) +0:82 Constant: +0:82 0 (const int) +0:82 Constant: +0:82 0 (const int) +0:82 add (noContraction temp float) +0:82 add (noContraction temp float) +0:82 'a' (noContraction temp float) +0:82 'b' (noContraction temp float) +0:82 Constant: +0:82 1.000000 +0:83 move second child to first child (temp float) +0:83 f2: direct index for structure (noContraction global float) +0:83 s: direct index for structure (noContraction out structure{global float f1, global float f2}) +0:83 'all_precise_block' (noContraction out block{out structure{global float f1, global float f2} s, out float x}) +0:83 Constant: +0:83 0 (const int) +0:83 Constant: +0:83 1 (const int) +0:83 subtract (noContraction temp float) +0:83 subtract (noContraction temp float) +0:83 'a' (noContraction temp float) +0:83 'b' (noContraction temp float) +0:83 Constant: +0:83 1.000000 +0:84 move second child to first child (temp float) +0:84 x: direct index for structure (noContraction out float) +0:84 'all_precise_block' (noContraction out block{out structure{global float f1, global float f2} s, out float x}) +0:84 Constant: +0:84 1 (const int) +0:84 component-wise multiply (noContraction temp float) +0:84 component-wise multiply (noContraction temp float) +0:84 'a' (noContraction temp float) +0:84 'b' (noContraction temp float) +0:84 Constant: +0:84 2.000000 +0:86 Branch: Return with expression +0:86 add (temp float) +0:86 'a' (temp float) +0:86 'b' (temp float) +0:89 Function Definition: main( (global void) +0:89 Function Parameters: +0:? Linker Objects +0:? 'partial_precise_block' (out block{noContraction out structure{global float f1, global float f2} s, out float x}) +0:? 'all_precise_block' (noContraction out block{out structure{global float f1, global float f2} s, out float x}) +0:? 'gl_VertexID' (gl_VertexId int VertexId) +0:? 'gl_InstanceID' (gl_InstanceId int InstanceId) + + +Linked vertex stage: + + +Shader version: 450 +0:? Sequence +0:11 Function Definition: struct_member( (global float) +0:11 Function Parameters: +0:12 Sequence +0:12 Sequence +0:12 move second child to first child (temp float) +0:12 'a' (noContraction temp float) +0:12 Constant: +0:12 1.000000 +0:13 Sequence +0:13 move second child to first child (temp float) +0:13 'b' (temp float) +0:13 Constant: +0:13 2.000000 +0:14 Sequence +0:14 move second child to first child (temp float) +0:14 'c' (temp float) +0:14 Constant: +0:14 3.000000 +0:15 Sequence +0:15 move second child to first child (temp float) +0:15 'd' (temp float) +0:15 Constant: +0:15 4.000000 +0:21 move second child to first child (temp float) +0:21 f1: direct index for structure (noContraction global float) +0:21 'S2' (temp structure{global float f1, global float f2}) +0:21 Constant: +0:21 0 (const int) +0:21 add (noContraction temp float) +0:21 'a' (noContraction temp float) +0:21 Constant: +0:21 0.200000 +0:22 move second child to first child (temp float) +0:22 f2: direct index for structure (global float) +0:22 'S2' (temp structure{global float f1, global float f2}) +0:22 Constant: +0:22 1 (const int) +0:22 add (temp float) +0:22 'b' (temp float) +0:22 Constant: +0:22 0.200000 +0:23 move second child to first child (temp float) +0:23 f1: direct index for structure (global float) +0:23 'S3' (temp structure{global float f1, global float f2}) +0:23 Constant: +0:23 0 (const int) +0:23 add (temp float) +0:23 'a' (temp float) +0:23 'b' (temp float) +0:24 move second child to first child (temp structure{global float f1, global float f2}) +0:24 'S' (temp structure{global float f1, global float f2}) +0:24 'S2' (temp structure{global float f1, global float f2}) +0:25 move second child to first child (temp float) +0:25 'result' (noContraction temp float) +0:25 add (noContraction temp float) +0:25 f1: direct index for structure (noContraction global float) +0:25 'S' (temp structure{global float f1, global float f2}) +0:25 Constant: +0:25 0 (const int) +0:25 Constant: +0:25 0.100000 +0:27 Branch: Return with expression +0:27 'result' (noContraction temp float) +0:30 Function Definition: complex_array_struct( (global float) +0:30 Function Parameters: +0:? Sequence +0:43 Sequence +0:43 Sequence +0:43 move second child to first child (temp int) +0:43 'i' (noContraction temp int) +0:43 Constant: +0:43 0 (const int) +0:43 Loop with condition tested first +0:43 Loop Condition +0:43 Compare Less Than (temp bool) +0:43 'i' (temp int) +0:43 Constant: +0:43 10 (const int) +0:43 Loop Body +0:44 Sequence +0:44 move second child to first child (temp float) +0:44 f: direct index for structure (temp float) +0:44 indirect index (temp structure{temp float f, temp structure{temp 5-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1a, temp 6-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1b, temp 7-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1c} t2, temp 4-component vector of float v, temp int p}) +0:44 't3' (temp 10-element array of structure{temp float f, temp structure{temp 5-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1a, temp 6-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1b, temp 7-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1c} t2, temp 4-component vector of float v, temp int p}) +0:44 'i' (temp int) +0:44 Constant: +0:44 0 (const int) +0:44 divide (temp float) +0:44 Convert int to float (temp float) +0:44 'i' (temp int) +0:44 Constant: +0:44 3.000000 +0:45 move second child to first child (temp 4-component vector of float) +0:45 v: direct index for structure (noContraction temp 4-component vector of float) +0:45 indirect index (temp structure{temp float f, temp structure{temp 5-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1a, temp 6-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1b, temp 7-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1c} t2, temp 4-component vector of float v, temp int p}) +0:45 't3' (temp 10-element array of structure{temp float f, temp structure{temp 5-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1a, temp 6-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1b, temp 7-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1c} t2, temp 4-component vector of float v, temp int p}) +0:45 'i' (temp int) +0:45 Constant: +0:45 2 (const int) +0:45 Construct vec4 (temp 4-component vector of float) +0:45 component-wise multiply (noContraction temp float) +0:45 Convert int to float (temp float) +0:45 'i' (noContraction temp int) +0:45 Constant: +0:45 1.500000 +0:46 move second child to first child (temp int) +0:46 p: direct index for structure (temp int) +0:46 indirect index (temp structure{temp float f, temp structure{temp 5-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1a, temp 6-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1b, temp 7-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1c} t2, temp 4-component vector of float v, temp int p}) +0:46 't3' (temp 10-element array of structure{temp float f, temp structure{temp 5-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1a, temp 6-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1b, temp 7-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1c} t2, temp 4-component vector of float v, temp int p}) +0:46 'i' (temp int) +0:46 Constant: +0:46 3 (const int) +0:46 add (temp int) +0:46 'i' (temp int) +0:46 Constant: +0:46 1 (const int) +0:47 Sequence +0:47 Sequence +0:47 move second child to first child (temp int) +0:47 'j' (temp int) +0:47 Constant: +0:47 0 (const int) +0:47 Loop with condition tested first +0:47 Loop Condition +0:47 Compare Less Than (temp bool) +0:47 'j' (temp int) +0:47 Constant: +0:47 5 (const int) +0:47 Loop Body +0:48 Sequence +0:48 Sequence +0:48 Sequence +0:48 move second child to first child (temp int) +0:48 'k' (temp int) +0:48 Constant: +0:48 0 (const int) +0:48 Loop with condition tested first +0:48 Loop Condition +0:48 Compare Less Than (temp bool) +0:48 'k' (temp int) +0:48 Constant: +0:48 3 (const int) +0:48 Loop Body +0:49 Sequence +0:49 move second child to first child (temp float) +0:49 indirect index (temp float) +0:49 t1_array: direct index for structure (temp 3-element array of float) +0:49 indirect index (temp structure{temp 3-element array of float t1_array, temp float t1_scalar}) +0:49 t1a: direct index for structure (temp 5-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar}) +0:49 t2: direct index for structure (temp structure{temp 5-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1a, temp 6-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1b, temp 7-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1c}) +0:49 indirect index (temp structure{temp float f, temp structure{temp 5-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1a, temp 6-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1b, temp 7-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1c} t2, temp 4-component vector of float v, temp int p}) +0:49 't3' (temp 10-element array of structure{temp float f, temp structure{temp 5-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1a, temp 6-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1b, temp 7-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1c} t2, temp 4-component vector of float v, temp int p}) +0:49 'i' (temp int) +0:49 Constant: +0:49 1 (const int) +0:49 Constant: +0:49 0 (const int) +0:49 'j' (temp int) +0:49 Constant: +0:49 0 (const int) +0:49 'k' (temp int) +0:49 Convert int to float (temp float) +0:49 add (temp int) +0:49 component-wise multiply (temp int) +0:49 'i' (temp int) +0:49 'j' (temp int) +0:49 'k' (temp int) +0:48 Loop Terminal Expression +0:48 Post-Increment (temp int) +0:48 'k' (temp int) +0:51 move second child to first child (temp float) +0:51 t1_scalar: direct index for structure (temp float) +0:51 indirect index (temp structure{temp 3-element array of float t1_array, temp float t1_scalar}) +0:51 t1a: direct index for structure (temp 5-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar}) +0:51 t2: direct index for structure (temp structure{temp 5-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1a, temp 6-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1b, temp 7-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1c}) +0:51 indirect index (temp structure{temp float f, temp structure{temp 5-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1a, temp 6-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1b, temp 7-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1c} t2, temp 4-component vector of float v, temp int p}) +0:51 't3' (temp 10-element array of structure{temp float f, temp structure{temp 5-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1a, temp 6-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1b, temp 7-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1c} t2, temp 4-component vector of float v, temp int p}) +0:51 'i' (temp int) +0:51 Constant: +0:51 1 (const int) +0:51 Constant: +0:51 0 (const int) +0:51 'j' (temp int) +0:51 Constant: +0:51 1 (const int) +0:51 divide (temp float) +0:51 component-wise multiply (temp float) +0:51 Convert int to float (temp float) +0:51 'j' (temp int) +0:51 Constant: +0:51 2.000000 +0:51 Convert int to float (temp float) +0:51 'i' (temp int) +0:47 Loop Terminal Expression +0:47 Post-Increment (temp int) +0:47 'j' (temp int) +0:54 Sequence +0:54 Sequence +0:54 move second child to first child (temp int) +0:54 'j' (noContraction temp int) +0:54 Constant: +0:54 0 (const int) +0:54 Loop with condition tested first +0:54 Loop Condition +0:54 Compare Less Than (temp bool) +0:54 'j' (temp int) +0:54 Constant: +0:54 6 (const int) +0:54 Loop Body +0:55 Sequence +0:55 Sequence +0:55 Sequence +0:55 move second child to first child (temp int) +0:55 'k' (temp int) +0:55 Constant: +0:55 0 (const int) +0:55 Loop with condition tested first +0:55 Loop Condition +0:55 Compare Less Than (temp bool) +0:55 'k' (temp int) +0:55 Constant: +0:55 3 (const int) +0:55 Loop Body +0:56 Sequence +0:56 move second child to first child (temp float) +0:56 indirect index (temp float) +0:56 t1_array: direct index for structure (temp 3-element array of float) +0:56 indirect index (temp structure{temp 3-element array of float t1_array, temp float t1_scalar}) +0:56 t1b: direct index for structure (temp 6-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar}) +0:56 t2: direct index for structure (temp structure{temp 5-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1a, temp 6-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1b, temp 7-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1c}) +0:56 indirect index (temp structure{temp float f, temp structure{temp 5-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1a, temp 6-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1b, temp 7-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1c} t2, temp 4-component vector of float v, temp int p}) +0:56 't3' (temp 10-element array of structure{temp float f, temp structure{temp 5-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1a, temp 6-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1b, temp 7-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1c} t2, temp 4-component vector of float v, temp int p}) +0:56 'i' (temp int) +0:56 Constant: +0:56 1 (const int) +0:56 Constant: +0:56 1 (const int) +0:56 'j' (temp int) +0:56 Constant: +0:56 0 (const int) +0:56 'k' (temp int) +0:56 Convert int to float (temp float) +0:56 add (temp int) +0:56 component-wise multiply (temp int) +0:56 'i' (temp int) +0:56 'j' (temp int) +0:56 'k' (temp int) +0:55 Loop Terminal Expression +0:55 Post-Increment (temp int) +0:55 'k' (temp int) +0:58 move second child to first child (temp float) +0:58 t1_scalar: direct index for structure (noContraction temp float) +0:58 indirect index (temp structure{temp 3-element array of float t1_array, temp float t1_scalar}) +0:58 t1b: direct index for structure (temp 6-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar}) +0:58 t2: direct index for structure (temp structure{temp 5-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1a, temp 6-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1b, temp 7-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1c}) +0:58 indirect index (temp structure{temp float f, temp structure{temp 5-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1a, temp 6-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1b, temp 7-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1c} t2, temp 4-component vector of float v, temp int p}) +0:58 't3' (temp 10-element array of structure{temp float f, temp structure{temp 5-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1a, temp 6-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1b, temp 7-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1c} t2, temp 4-component vector of float v, temp int p}) +0:58 'i' (temp int) +0:58 Constant: +0:58 1 (const int) +0:58 Constant: +0:58 1 (const int) +0:58 'j' (temp int) +0:58 Constant: +0:58 1 (const int) +0:58 divide (noContraction temp float) +0:58 component-wise multiply (noContraction temp float) +0:58 Convert int to float (temp float) +0:58 'j' (noContraction temp int) +0:58 Constant: +0:58 2.000000 +0:58 Convert int to float (temp float) +0:58 'i' (noContraction temp int) +0:54 Loop Terminal Expression +0:54 Post-Increment (noContraction temp int) +0:54 'j' (noContraction temp int) +0:61 Sequence +0:61 Sequence +0:61 move second child to first child (temp int) +0:61 'j' (noContraction temp int) +0:61 Constant: +0:61 0 (const int) +0:61 Loop with condition tested first +0:61 Loop Condition +0:61 Compare Less Than (temp bool) +0:61 'j' (temp int) +0:61 Constant: +0:61 6 (const int) +0:61 Loop Body +0:62 Sequence +0:62 Sequence +0:62 Sequence +0:62 move second child to first child (temp int) +0:62 'k' (noContraction temp int) +0:62 Constant: +0:62 0 (const int) +0:62 Loop with condition tested first +0:62 Loop Condition +0:62 Compare Less Than (temp bool) +0:62 'k' (temp int) +0:62 Constant: +0:62 3 (const int) +0:62 Loop Body +0:63 Sequence +0:63 move second child to first child (temp float) +0:63 indirect index (noContraction temp float) +0:63 t1_array: direct index for structure (noContraction temp 3-element array of float) +0:63 indirect index (temp structure{temp 3-element array of float t1_array, temp float t1_scalar}) +0:63 t1c: direct index for structure (temp 7-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar}) +0:63 t2: direct index for structure (temp structure{temp 5-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1a, temp 6-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1b, temp 7-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1c}) +0:63 indirect index (temp structure{temp float f, temp structure{temp 5-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1a, temp 6-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1b, temp 7-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1c} t2, temp 4-component vector of float v, temp int p}) +0:63 't3' (temp 10-element array of structure{temp float f, temp structure{temp 5-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1a, temp 6-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1b, temp 7-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1c} t2, temp 4-component vector of float v, temp int p}) +0:63 'i' (temp int) +0:63 Constant: +0:63 1 (const int) +0:63 Constant: +0:63 2 (const int) +0:63 'j' (temp int) +0:63 Constant: +0:63 0 (const int) +0:63 'k' (temp int) +0:63 Convert int to float (temp float) +0:63 add (noContraction temp int) +0:63 component-wise multiply (noContraction temp int) +0:63 'i' (noContraction temp int) +0:63 'j' (noContraction temp int) +0:63 'k' (noContraction temp int) +0:62 Loop Terminal Expression +0:62 Post-Increment (noContraction temp int) +0:62 'k' (noContraction temp int) +0:65 move second child to first child (temp float) +0:65 t1_scalar: direct index for structure (temp float) +0:65 indirect index (temp structure{temp 3-element array of float t1_array, temp float t1_scalar}) +0:65 t1c: direct index for structure (temp 7-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar}) +0:65 t2: direct index for structure (temp structure{temp 5-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1a, temp 6-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1b, temp 7-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1c}) +0:65 indirect index (temp structure{temp float f, temp structure{temp 5-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1a, temp 6-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1b, temp 7-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1c} t2, temp 4-component vector of float v, temp int p}) +0:65 't3' (temp 10-element array of structure{temp float f, temp structure{temp 5-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1a, temp 6-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1b, temp 7-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1c} t2, temp 4-component vector of float v, temp int p}) +0:65 'i' (temp int) +0:65 Constant: +0:65 1 (const int) +0:65 Constant: +0:65 2 (const int) +0:65 'j' (temp int) +0:65 Constant: +0:65 1 (const int) +0:65 divide (temp float) +0:65 component-wise multiply (temp float) +0:65 Convert int to float (temp float) +0:65 'j' (temp int) +0:65 Constant: +0:65 2.000000 +0:65 Convert int to float (temp float) +0:65 'i' (temp int) +0:61 Loop Terminal Expression +0:61 Post-Increment (noContraction temp int) +0:61 'j' (noContraction temp int) +0:43 Loop Terminal Expression +0:43 Post-Increment (noContraction temp int) +0:43 'i' (noContraction temp int) +0:68 Sequence +0:68 move second child to first child (temp int) +0:68 'i' (temp int) +0:68 Constant: +0:68 2 (const int) +0:69 move second child to first child (temp float) +0:69 'result' (noContraction temp float) +0:71 add (noContraction temp float) +0:70 add (noContraction temp float) +0:69 direct index (noContraction temp float) +0:69 t1_array: direct index for structure (temp 3-element array of float) +0:69 direct index (temp structure{temp 3-element array of float t1_array, temp float t1_scalar}) +0:69 t1c: direct index for structure (temp 7-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar}) +0:69 t2: direct index for structure (temp structure{temp 5-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1a, temp 6-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1b, temp 7-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1c}) +0:69 direct index (temp structure{temp float f, temp structure{temp 5-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1a, temp 6-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1b, temp 7-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1c} t2, temp 4-component vector of float v, temp int p}) +0:69 't3' (temp 10-element array of structure{temp float f, temp structure{temp 5-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1a, temp 6-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1b, temp 7-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1c} t2, temp 4-component vector of float v, temp int p}) +0:69 Constant: +0:69 5 (const int) +0:69 Constant: +0:69 1 (const int) +0:69 Constant: +0:69 2 (const int) +0:69 Constant: +0:69 6 (const int) +0:69 Constant: +0:69 0 (const int) +0:69 Constant: +0:69 1 (const int) +0:70 t1_scalar: direct index for structure (noContraction temp float) +0:70 direct index (temp structure{temp 3-element array of float t1_array, temp float t1_scalar}) +0:70 t1b: direct index for structure (temp 6-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar}) +0:70 t2: direct index for structure (temp structure{temp 5-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1a, temp 6-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1b, temp 7-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1c}) +0:70 direct index (temp structure{temp float f, temp structure{temp 5-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1a, temp 6-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1b, temp 7-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1c} t2, temp 4-component vector of float v, temp int p}) +0:70 't3' (temp 10-element array of structure{temp float f, temp structure{temp 5-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1a, temp 6-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1b, temp 7-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1c} t2, temp 4-component vector of float v, temp int p}) +0:70 Constant: +0:70 2 (const int) +0:70 Constant: +0:70 1 (const int) +0:70 Constant: +0:70 1 (const int) +0:70 Constant: +0:70 1 (const int) +0:70 Constant: +0:70 1 (const int) +0:71 direct index (noContraction temp float) +0:71 vector swizzle (temp 2-component vector of float) +0:71 v: direct index for structure (temp 4-component vector of float) +0:71 indirect index (temp structure{temp float f, temp structure{temp 5-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1a, temp 6-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1b, temp 7-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1c} t2, temp 4-component vector of float v, temp int p}) +0:71 't3' (temp 10-element array of structure{temp float f, temp structure{temp 5-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1a, temp 6-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1b, temp 7-element array of structure{temp 3-element array of float t1_array, temp float t1_scalar} t1c} t2, temp 4-component vector of float v, temp int p}) +0:71 subtract (temp int) +0:71 'i' (temp int) +0:71 Constant: +0:71 1 (const int) +0:71 Constant: +0:71 2 (const int) +0:71 Sequence +0:71 Constant: +0:71 0 (const int) +0:71 Constant: +0:71 1 (const int) +0:71 Constant: +0:71 0 (const int) +0:72 Branch: Return with expression +0:72 'result' (noContraction temp float) +0:75 Function Definition: out_block( (global float) +0:75 Function Parameters: +0:76 Sequence +0:76 Sequence +0:76 move second child to first child (temp float) +0:76 'a' (noContraction temp float) +0:76 Constant: +0:76 0.100000 +0:77 Sequence +0:77 move second child to first child (temp float) +0:77 'b' (noContraction temp float) +0:77 Constant: +0:77 0.200000 +0:78 move second child to first child (temp float) +0:78 f1: direct index for structure (noContraction global float) +0:78 s: direct index for structure (noContraction out structure{global float f1, global float f2}) +0:78 'partial_precise_block' (out block{noContraction out structure{global float f1, global float f2} s, out float x}) +0:78 Constant: +0:78 0 (const int) +0:78 Constant: +0:78 0 (const int) +0:78 add (noContraction temp float) +0:78 'a' (noContraction temp float) +0:78 'b' (noContraction temp float) +0:79 move second child to first child (temp float) +0:79 f2: direct index for structure (noContraction global float) +0:79 s: direct index for structure (noContraction out structure{global float f1, global float f2}) +0:79 'partial_precise_block' (out block{noContraction out structure{global float f1, global float f2} s, out float x}) +0:79 Constant: +0:79 0 (const int) +0:79 Constant: +0:79 1 (const int) +0:79 subtract (noContraction temp float) +0:79 'a' (noContraction temp float) +0:79 'b' (noContraction temp float) +0:80 move second child to first child (temp float) +0:80 x: direct index for structure (out float) +0:80 'partial_precise_block' (out block{noContraction out structure{global float f1, global float f2} s, out float x}) +0:80 Constant: +0:80 1 (const int) +0:80 component-wise multiply (temp float) +0:80 'a' (temp float) +0:80 'b' (temp float) +0:82 move second child to first child (temp float) +0:82 f1: direct index for structure (noContraction global float) +0:82 s: direct index for structure (noContraction out structure{global float f1, global float f2}) +0:82 'all_precise_block' (noContraction out block{out structure{global float f1, global float f2} s, out float x}) +0:82 Constant: +0:82 0 (const int) +0:82 Constant: +0:82 0 (const int) +0:82 add (noContraction temp float) +0:82 add (noContraction temp float) +0:82 'a' (noContraction temp float) +0:82 'b' (noContraction temp float) +0:82 Constant: +0:82 1.000000 +0:83 move second child to first child (temp float) +0:83 f2: direct index for structure (noContraction global float) +0:83 s: direct index for structure (noContraction out structure{global float f1, global float f2}) +0:83 'all_precise_block' (noContraction out block{out structure{global float f1, global float f2} s, out float x}) +0:83 Constant: +0:83 0 (const int) +0:83 Constant: +0:83 1 (const int) +0:83 subtract (noContraction temp float) +0:83 subtract (noContraction temp float) +0:83 'a' (noContraction temp float) +0:83 'b' (noContraction temp float) +0:83 Constant: +0:83 1.000000 +0:84 move second child to first child (temp float) +0:84 x: direct index for structure (noContraction out float) +0:84 'all_precise_block' (noContraction out block{out structure{global float f1, global float f2} s, out float x}) +0:84 Constant: +0:84 1 (const int) +0:84 component-wise multiply (noContraction temp float) +0:84 component-wise multiply (noContraction temp float) +0:84 'a' (noContraction temp float) +0:84 'b' (noContraction temp float) +0:84 Constant: +0:84 2.000000 +0:86 Branch: Return with expression +0:86 add (temp float) +0:86 'a' (temp float) +0:86 'b' (temp float) +0:89 Function Definition: main( (global void) +0:89 Function Parameters: +0:? Linker Objects +0:? 'partial_precise_block' (out block{noContraction out structure{global float f1, global float f2} s, out float x}) +0:? 'all_precise_block' (noContraction out block{out structure{global float f1, global float f2} s, out float x}) +0:? 'gl_VertexID' (gl_VertexId int VertexId) +0:? 'gl_InstanceID' (gl_InstanceId int InstanceId) + diff --git a/Test/baseResults/spv.precise.tesc.out b/Test/baseResults/spv.precise.tesc.out new file mode 100644 index 00000000..0331a14a --- /dev/null +++ b/Test/baseResults/spv.precise.tesc.out @@ -0,0 +1,122 @@ +spv.precise.tesc +Warning, version 310 is not yet complete; most version-specific features are present, but some are missing. + + +Linked tessellation control stage: + + +// Module Version 10000 +// Generated by (magic number): 80001 +// Id's are bound by 72 + + Capability Tessellation + 1: ExtInstImport "GLSL.std.450" + MemoryModel Logical GLSL450 + EntryPoint TessellationControl 4 "main" 12 15 20 30 40 45 + ExecutionMode 4 OutputVertices 3 + Source ESSL 310 + SourceExtension "GL_EXT_gpu_shader5" + SourceExtension "GL_EXT_shader_io_blocks" + SourceExtension "GL_EXT_tessellation_shader" + Name 4 "main" + Name 12 "in_te_position" + Name 15 "gl_InvocationID" + Name 20 "in_tc_position" + Name 30 "gl_TessLevelInner" + Name 40 "gl_TessLevelOuter" + Name 45 "in_tc_tessParam" + Decorate 12(in_te_position) Location 0 + Decorate 15(gl_InvocationID) BuiltIn InvocationId + Decorate 20(in_tc_position) Location 0 + Decorate 30(gl_TessLevelInner) Patch + Decorate 30(gl_TessLevelInner) BuiltIn TessLevelInner + Decorate 40(gl_TessLevelOuter) Patch + Decorate 40(gl_TessLevelOuter) BuiltIn TessLevelOuter + Decorate 45(in_tc_tessParam) Location 1 + Decorate 52 NoContraction + Decorate 53 NoContraction + Decorate 54 NoContraction + Decorate 60 NoContraction + Decorate 61 NoContraction + Decorate 62 NoContraction + Decorate 68 NoContraction + Decorate 69 NoContraction + Decorate 70 NoContraction + 2: TypeVoid + 3: TypeFunction 2 + 6: TypeFloat 32 + 7: TypeVector 6(float) 2 + 8: TypeInt 32 0 + 9: 8(int) Constant 3 + 10: TypeArray 7(fvec2) 9 + 11: TypePointer Output 10 +12(in_te_position): 11(ptr) Variable Output + 13: TypeInt 32 1 + 14: TypePointer Input 13(int) +15(gl_InvocationID): 14(ptr) Variable Input + 17: 8(int) Constant 32 + 18: TypeArray 7(fvec2) 17 + 19: TypePointer Input 18 +20(in_tc_position): 19(ptr) Variable Input + 22: TypePointer Input 7(fvec2) + 25: TypePointer Output 7(fvec2) + 27: 8(int) Constant 2 + 28: TypeArray 6(float) 27 + 29: TypePointer Output 28 +30(gl_TessLevelInner): 29(ptr) Variable Output + 31: 13(int) Constant 0 + 32: 6(float) Constant 1084227584 + 33: TypePointer Output 6(float) + 35: 13(int) Constant 1 + 37: 8(int) Constant 4 + 38: TypeArray 6(float) 37 + 39: TypePointer Output 38 +40(gl_TessLevelOuter): 39(ptr) Variable Output + 41: 6(float) Constant 1065353216 + 42: 6(float) Constant 1105985536 + 43: TypeArray 6(float) 17 + 44: TypePointer Input 43 +45(in_tc_tessParam): 44(ptr) Variable Input + 46: TypePointer Input 6(float) + 49: 13(int) Constant 2 + 4(main): 2 Function None 3 + 5: Label + 16: 13(int) Load 15(gl_InvocationID) + 21: 13(int) Load 15(gl_InvocationID) + 23: 22(ptr) AccessChain 20(in_tc_position) 21 + 24: 7(fvec2) Load 23 + 26: 25(ptr) AccessChain 12(in_te_position) 16 + Store 26 24 + 34: 33(ptr) AccessChain 30(gl_TessLevelInner) 31 + Store 34 32 + 36: 33(ptr) AccessChain 30(gl_TessLevelInner) 35 + Store 36 32 + 47: 46(ptr) AccessChain 45(in_tc_tessParam) 35 + 48: 6(float) Load 47 + 50: 46(ptr) AccessChain 45(in_tc_tessParam) 49 + 51: 6(float) Load 50 + 52: 6(float) FAdd 48 51 + 53: 6(float) FMul 42 52 + 54: 6(float) FAdd 41 53 + 55: 33(ptr) AccessChain 40(gl_TessLevelOuter) 31 + Store 55 54 + 56: 46(ptr) AccessChain 45(in_tc_tessParam) 49 + 57: 6(float) Load 56 + 58: 46(ptr) AccessChain 45(in_tc_tessParam) 31 + 59: 6(float) Load 58 + 60: 6(float) FAdd 57 59 + 61: 6(float) FMul 42 60 + 62: 6(float) FAdd 41 61 + 63: 33(ptr) AccessChain 40(gl_TessLevelOuter) 35 + Store 63 62 + 64: 46(ptr) AccessChain 45(in_tc_tessParam) 31 + 65: 6(float) Load 64 + 66: 46(ptr) AccessChain 45(in_tc_tessParam) 35 + 67: 6(float) Load 66 + 68: 6(float) FAdd 65 67 + 69: 6(float) FMul 42 68 + 70: 6(float) FAdd 41 69 + 71: 33(ptr) AccessChain 40(gl_TessLevelOuter) 49 + Store 71 70 + Return + FunctionEnd diff --git a/Test/baseResults/spv.precise.tese.out b/Test/baseResults/spv.precise.tese.out new file mode 100644 index 00000000..231ea333 --- /dev/null +++ b/Test/baseResults/spv.precise.tese.out @@ -0,0 +1,192 @@ +spv.precise.tese +Warning, version 310 is not yet complete; most version-specific features are present, but some are missing. + + +Linked tessellation evaluation stage: + + +// Module Version 10000 +// Generated by (magic number): 80001 +// Id's are bound by 119 + + Capability Tessellation + Capability TessellationPointSize + 1: ExtInstImport "GLSL.std.450" + MemoryModel Logical GLSL450 + EntryPoint TessellationEvaluation 4 "main" 12 21 62 112 + ExecutionMode 4 Triangles + ExecutionMode 4 SpacingEqual + ExecutionMode 4 VertexOrderCcw + Source ESSL 310 + SourceExtension "GL_EXT_gpu_shader5" + SourceExtension "GL_EXT_shader_io_blocks" + SourceExtension "GL_EXT_tessellation_shader" + Name 4 "main" + Name 9 "pos" + Name 12 "gl_TessCoord" + Name 21 "in_te_position" + Name 45 "f" + Name 62 "in_f_color" + Name 73 "bits" + Name 77 "numBits" + Name 78 "i" + Name 110 "gl_PerVertex" + MemberName 110(gl_PerVertex) 0 "gl_Position" + MemberName 110(gl_PerVertex) 1 "gl_PointSize" + Name 112 "" + Decorate 12(gl_TessCoord) BuiltIn TessCoord + Decorate 21(in_te_position) Location 0 + Decorate 27 NoContraction + Decorate 34 NoContraction + Decorate 35 NoContraction + Decorate 42 NoContraction + Decorate 43 NoContraction + Decorate 62(in_f_color) RelaxedPrecision + Decorate 62(in_f_color) Location 0 + Decorate 67 RelaxedPrecision + Decorate 68 RelaxedPrecision + Decorate 69 RelaxedPrecision + Decorate 70 RelaxedPrecision + Decorate 97 NoContraction + Decorate 99 NoContraction + Decorate 101 NoContraction + Decorate 106 NoContraction + Decorate 109 NoContraction + MemberDecorate 110(gl_PerVertex) 0 BuiltIn Position + MemberDecorate 110(gl_PerVertex) 1 BuiltIn PointSize + Decorate 110(gl_PerVertex) Block + 2: TypeVoid + 3: TypeFunction 2 + 6: TypeFloat 32 + 7: TypeVector 6(float) 2 + 8: TypePointer Function 7(fvec2) + 10: TypeVector 6(float) 3 + 11: TypePointer Input 10(fvec3) +12(gl_TessCoord): 11(ptr) Variable Input + 13: TypeInt 32 0 + 14: 13(int) Constant 0 + 15: TypePointer Input 6(float) + 18: 13(int) Constant 32 + 19: TypeArray 7(fvec2) 18 + 20: TypePointer Input 19 +21(in_te_position): 20(ptr) Variable Input + 22: TypeInt 32 1 + 23: 22(int) Constant 0 + 24: TypePointer Input 7(fvec2) + 28: 13(int) Constant 1 + 31: 22(int) Constant 1 + 36: 13(int) Constant 2 + 39: 22(int) Constant 2 + 44: TypePointer Function 6(float) + 46: 6(float) Constant 1077936128 + 57: 6(float) Constant 1056964608 + 60: TypeVector 6(float) 4 + 61: TypePointer Output 60(fvec4) + 62(in_f_color): 61(ptr) Variable Output + 66: 6(float) Constant 1065353216 + 71: TypeVector 13(int) 2 + 72: TypePointer Function 71(ivec2) + 76: TypePointer Function 13(int) + 85: TypeBool + 105: 6(float) Constant 1025758986 +110(gl_PerVertex): TypeStruct 60(fvec4) 6(float) + 111: TypePointer Output 110(gl_PerVertex) + 112: 111(ptr) Variable Output + 114: 6(float) Constant 0 + 4(main): 2 Function None 3 + 5: Label + 9(pos): 8(ptr) Variable Function + 45(f): 44(ptr) Variable Function + 73(bits): 72(ptr) Variable Function + 77(numBits): 76(ptr) Variable Function + 78(i): 76(ptr) Variable Function + 16: 15(ptr) AccessChain 12(gl_TessCoord) 14 + 17: 6(float) Load 16 + 25: 24(ptr) AccessChain 21(in_te_position) 23 + 26: 7(fvec2) Load 25 + 27: 7(fvec2) VectorTimesScalar 26 17 + 29: 15(ptr) AccessChain 12(gl_TessCoord) 28 + 30: 6(float) Load 29 + 32: 24(ptr) AccessChain 21(in_te_position) 31 + 33: 7(fvec2) Load 32 + 34: 7(fvec2) VectorTimesScalar 33 30 + 35: 7(fvec2) FAdd 27 34 + 37: 15(ptr) AccessChain 12(gl_TessCoord) 36 + 38: 6(float) Load 37 + 40: 24(ptr) AccessChain 21(in_te_position) 39 + 41: 7(fvec2) Load 40 + 42: 7(fvec2) VectorTimesScalar 41 38 + 43: 7(fvec2) FAdd 35 42 + Store 9(pos) 43 + 47: 15(ptr) AccessChain 12(gl_TessCoord) 14 + 48: 6(float) Load 47 + 49: 15(ptr) AccessChain 12(gl_TessCoord) 28 + 50: 6(float) Load 49 + 51: 15(ptr) AccessChain 12(gl_TessCoord) 36 + 52: 6(float) Load 51 + 53: 6(float) ExtInst 1(GLSL.std.450) 37(FMin) 50 52 + 54: 6(float) ExtInst 1(GLSL.std.450) 37(FMin) 48 53 + 55: 6(float) FMul 46 54 + 56: 6(float) ExtInst 1(GLSL.std.450) 31(Sqrt) 55 + 58: 6(float) FMul 56 57 + 59: 6(float) FAdd 58 57 + Store 45(f) 59 + 63: 10(fvec3) Load 12(gl_TessCoord) + 64: 6(float) Load 45(f) + 65: 10(fvec3) VectorTimesScalar 63 64 + 67: 6(float) CompositeExtract 65 0 + 68: 6(float) CompositeExtract 65 1 + 69: 6(float) CompositeExtract 65 2 + 70: 60(fvec4) CompositeConstruct 67 68 69 66 + Store 62(in_f_color) 70 + 74: 7(fvec2) Load 9(pos) + 75: 71(ivec2) Bitcast 74 + Store 73(bits) 75 + Store 77(numBits) 14 + Store 78(i) 14 + Branch 79 + 79: Label + LoopMerge 81 82 None + Branch 83 + 83: Label + 84: 13(int) Load 78(i) + 86: 85(bool) ULessThan 84 18 + BranchConditional 86 80 81 + 80: Label + 87: 76(ptr) AccessChain 73(bits) 14 + 88: 13(int) Load 87 + 89: 13(int) Load 78(i) + 90: 13(int) ShiftLeftLogical 88 89 + 91: 13(int) BitwiseAnd 90 28 + 92: 76(ptr) AccessChain 73(bits) 28 + 93: 13(int) Load 92 + 94: 13(int) Load 78(i) + 95: 13(int) ShiftLeftLogical 93 94 + 96: 13(int) BitwiseAnd 95 28 + 97: 13(int) IAdd 91 96 + 98: 13(int) Load 77(numBits) + 99: 13(int) IAdd 98 97 + Store 77(numBits) 99 + Branch 82 + 82: Label + 100: 13(int) Load 78(i) + 101: 13(int) IAdd 100 31 + Store 78(i) 101 + Branch 79 + 81: Label + 102: 13(int) Load 77(numBits) + 103: 13(int) BitwiseAnd 102 28 + 104: 6(float) ConvertUToF 103 + 106: 6(float) FMul 104 105 + 107: 7(fvec2) Load 9(pos) + 108: 7(fvec2) CompositeConstruct 106 106 + 109: 7(fvec2) FAdd 107 108 + Store 9(pos) 109 + 113: 7(fvec2) Load 9(pos) + 115: 6(float) CompositeExtract 113 0 + 116: 6(float) CompositeExtract 113 1 + 117: 60(fvec4) CompositeConstruct 115 116 114 66 + 118: 61(ptr) AccessChain 112 23 + Store 118 117 + Return + FunctionEnd diff --git a/Test/precise.tesc b/Test/precise.tesc new file mode 100644 index 00000000..71a71e48 --- /dev/null +++ b/Test/precise.tesc @@ -0,0 +1,102 @@ +#version 450 +#extension GL_EXT_tessellation_shader : require +#extension GL_EXT_gpu_shader5 : require + +float minimal() { + precise float result = 5.0; + float a = 10.0; + float b = 20.0; + float c = 30.0; + float d = 40.0; + result = a * b + c * d; // c * d, a * b and rvalue1 + rvalue2 should be 'noContraction'. + return result; +} + +void continuous_assignment() { + precise float result = 5.0; + int a = 10; + int b = 20; + result = a = b + 4; // b + 4 should be 'noContraction'. +} + +void convert() { + precise float result; + int a = 10; + int b = 20; + b = a + b; // a + b should be 'noContraction'. + result = float(b); // convert operation should not be 'noContraction'. +} + +float loop_for() { + precise float r1 = 5.0; + precise float r2 = 10.0; + int a = 10; + int b = 20; + int c = 30; + for (int i = 0; i < a; i++) { + r1 += 3.12 + b + i; // 'noContration', this make i++ also 'noContraction' + c += 1; // 'noContration' + } + a += 1; // a + 1 should not be 'noContraction'. + r2 = c; // The calculation of c should be 'noContration'. + return float(r1 + r2); // conversion should not be 'noContration'. +} + +void loop_array(void) { + precise int result = 5; + + int x = 22; + int y = 33; + + int a0[3]; + result += x + y; // x + y should be 'noContraction' also result + rvalue. + + for (int i = 0; i < 3; ++i) { + // a's dereference + 2 should be 'noContraction'. + result += a0[i] + 2; + // result + 1 and 3 - rvalue should be 'noContraction'. + a0[i] = 3 - result++; + } +} + +void loop_while() { + precise float result = 5.0; + int a = 10; + int b = 20; + while (result < 10) { + result += 3.12 + b; // result + 3.12 should be 'noContraction'. + } + result = a + b + 5; // b + 5 should be 'noCtraction' and also a + rvalue. + result = 11.1; +} + +float fma_not_decorated() { + precise float result; + float a = 1.0; + float b = 2.0; + float c = 3.0; + b = b + c; // b + c should be decorated with 'noContraction' + result = fma(a, b, c); // fma() should not be decorated with 'noContradtion' + return result; +} + +precise float precise_return_exp_func() { + float a = 1.0; + float b = 2.0; + return a + b; // the ADD operation should be 'noContraction' +} + +precise float precise_return_val_func() { + float a = 1.0; + float b = 2.0; + float result = a + b; // the ADD operation should be 'noContraction' + return result; +} + +float precise_func_parameter(float b, precise out float c) { + float a = 0.5; + c = a + b; // noContration + return a - b; // Not noContraction +} + +void main(){} diff --git a/Test/precise_struct_block.vert b/Test/precise_struct_block.vert new file mode 100644 index 00000000..a050ccd0 --- /dev/null +++ b/Test/precise_struct_block.vert @@ -0,0 +1,89 @@ +#version 450 + +struct T { + float f1; + float f2; +}; + +out B1 {precise T s; float x;} partial_precise_block; +precise out B2 {T s; float x;} all_precise_block; + +float struct_member() { + float a = 1.0; + float b = 2.0; + float c = 3.0; + float d = 4.0; + + precise float result; + + T S, S2, S3; + + S2.f1 = a + 0.2; // NoContraction + S2.f2 = b + 0.2; // NOT NoContraction + S3.f1 = a + b; // NOT NoContraction + S = S2; // "precise" propagated through parent object nodes + result = S.f1 + 0.1; // the ADD operation should be NoContraction + + return result; +} + +float complex_array_struct() { + precise float result; + struct T1 { + float t1_array[3]; + float t1_scalar; + }; + struct T2 { + T1 t1a[5]; + T1 t1b[6]; + T1 t1c[7]; + }; + struct T3 {float f; T2 t2; vec4 v; int p;}; + T3 t3[10]; + for(int i=0; i<10; i++) { + t3[i].f = i / 3.0; // Not NoContraction + t3[i].v = vec4(i * 1.5); // NoContraction + t3[i].p = i + 1; + for(int j=0; j<5; j++) { + for(int k = 0; k<3; k++) { + t3[i].t2.t1a[j].t1_array[k] = i * j + k; // Not NoContraction + } + t3[i].t2.t1a[j].t1_scalar = j * 2.0 / i; // Not NoContration + } + + for(int j=0; j<6; j++) { + for(int k = 0; k<3; k++) { + t3[i].t2.t1b[j].t1_array[k] = i * j + k; // Not NoContraction + } + t3[i].t2.t1b[j].t1_scalar = j * 2.0 / i; // NoContraction + } + + for(int j=0; j<6; j++) { + for(int k = 0; k<3; k++) { + t3[i].t2.t1c[j].t1_array[k] = i * j + k; // NoContraction + } + t3[i].t2.t1c[j].t1_scalar = j * 2.0 / i; // Not NoContraction + } + } + int i = 2; + result = t3[5].t2.t1c[6].t1_array[1] + + t3[2].t2.t1b[1].t1_scalar + + t3[i - 1].v.xy.x; // NoContraction + return result; +} + +float out_block() { + float a = 0.1; + float b = 0.2; + partial_precise_block.s.f1 = a + b; // NoContraction + partial_precise_block.s.f2 = a - b; // NoContraction + partial_precise_block.x = a * b; // Not NoContraction + + all_precise_block.s.f1 = a + b + 1.0; // NoContraction + all_precise_block.s.f2 = a - b - 1.0; // NoContraction + all_precise_block.x = a * b * 2.0; // Also NoContraction + + return a + b; // Not NoContraction +} + +void main(){} diff --git a/Test/spv.precise.tesc b/Test/spv.precise.tesc new file mode 100644 index 00000000..35de26b8 --- /dev/null +++ b/Test/spv.precise.tesc @@ -0,0 +1,24 @@ +#version 310 es +#extension GL_EXT_tessellation_shader : require +#extension GL_EXT_gpu_shader5 : require + +layout(vertices = 3) out; + +layout(location = 0) in highp vec2 in_tc_position[]; +layout(location = 1) in highp float in_tc_tessParam[]; + +layout(location = 0) out highp vec2 in_te_position[]; + +precise gl_TessLevelOuter; + +void main (void) +{ + in_te_position[gl_InvocationID] = in_tc_position[gl_InvocationID]; + + gl_TessLevelInner[0] = 5.0; + gl_TessLevelInner[1] = 5.0; + + gl_TessLevelOuter[0] = 1.0 + 59.0 * 0.5 * (in_tc_tessParam[1] + in_tc_tessParam[2]); + gl_TessLevelOuter[1] = 1.0 + 59.0 * 0.5 * (in_tc_tessParam[2] + in_tc_tessParam[0]); + gl_TessLevelOuter[2] = 1.0 + 59.0 * 0.5 * (in_tc_tessParam[0] + in_tc_tessParam[1]); +} diff --git a/Test/spv.precise.tese b/Test/spv.precise.tese new file mode 100644 index 00000000..874ea840 --- /dev/null +++ b/Test/spv.precise.tese @@ -0,0 +1,36 @@ +#version 310 es +#extension GL_EXT_tessellation_shader : require +#extension GL_EXT_gpu_shader5 : require + +layout(triangles, equal_spacing) in; + +layout(location = 0) in highp vec2 in_te_position[]; + +layout(location = 0) out mediump vec4 in_f_color; + +precise gl_Position; + +void main(void) { + highp vec2 pos = gl_TessCoord.x * in_te_position[0] + + gl_TessCoord.y * in_te_position[1] + + gl_TessCoord.z * in_te_position[2]; + + highp float f = + sqrt(3.0 * min(gl_TessCoord.x, min(gl_TessCoord.y, gl_TessCoord.z))) * + 0.5 + + 0.5; + in_f_color = vec4(gl_TessCoord * f, 1.0); + + // Offset the position slightly, based on the parity of the bits in the float + // representation. + // This is done to detect possible small differences in edge vertex positions + // between patches. + uvec2 bits = floatBitsToUint(pos); + uint numBits = 0u; + for (uint i = 0u; i < 32u; i++) + numBits += + ((bits[0] << i) & 1u) + ((bits[1] << i) & 1u); + pos += float(numBits & 1u) * 0.04; + + gl_Position = vec4(pos, 0.0, 1.0); +} diff --git a/Test/test-spirv-list b/Test/test-spirv-list index 703607da..03f4432e 100644 --- a/Test/test-spirv-list +++ b/Test/test-spirv-list @@ -107,6 +107,8 @@ spv.specConstant.vert spv.specConstant.comp spv.specConstantComposite.vert spv.specConstantOperations.vert +spv.precise.tese +spv.precise.tesc # GLSL-level semantics vulkan.frag vulkan.vert diff --git a/Test/testlist b/Test/testlist index d60fbca4..ecb99d1a 100644 --- a/Test/testlist +++ b/Test/testlist @@ -129,3 +129,5 @@ voidFunction.frag whileLoop.frag nonVulkan.frag spv.atomic.comp +precise.tesc +precise_struct_block.vert diff --git a/glslang/CMakeLists.txt b/glslang/CMakeLists.txt index 7015e304..f431cc11 100644 --- a/glslang/CMakeLists.txt +++ b/glslang/CMakeLists.txt @@ -33,6 +33,7 @@ set(SOURCES MachineIndependent/preprocessor/PpScanner.cpp MachineIndependent/preprocessor/PpSymbols.cpp MachineIndependent/preprocessor/PpTokens.cpp + MachineIndependent/propagateNoContraction.cpp GenericCodeGen/CodeGen.cpp GenericCodeGen/Link.cpp) @@ -62,6 +63,7 @@ set(HEADERS MachineIndependent/SymbolTable.h MachineIndependent/Versions.h MachineIndependent/parseVersions.h + MachineIndependent/propagateNoContraction.h MachineIndependent/preprocessor/PpContext.h MachineIndependent/preprocessor/PpTokens.h) diff --git a/glslang/MachineIndependent/Intermediate.cpp b/glslang/MachineIndependent/Intermediate.cpp index 47a93670..d3aa5853 100644 --- a/glslang/MachineIndependent/Intermediate.cpp +++ b/glslang/MachineIndependent/Intermediate.cpp @@ -42,6 +42,7 @@ #include "localintermediate.h" #include "RemoveTree.h" #include "SymbolTable.h" +#include "propagateNoContraction.h" #include @@ -1066,6 +1067,9 @@ bool TIntermediate::postProcess(TIntermNode* root, EShLanguage /*language*/) if (aggRoot && aggRoot->getOp() == EOpNull) aggRoot->setOperator(EOpSequence); + // Propagate 'noContraction' label in backward from 'precise' variables. + glslang::PropagateNoContraction(*this); + return true; } diff --git a/glslang/MachineIndependent/propagateNoContraction.cpp b/glslang/MachineIndependent/propagateNoContraction.cpp new file mode 100644 index 00000000..044ecbf3 --- /dev/null +++ b/glslang/MachineIndependent/propagateNoContraction.cpp @@ -0,0 +1,886 @@ +// +// Copyright (C) 2015-2016 Google, Inc. +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +// +// Visit the nodes in the glslang intermediate tree representation to +// propagate 'noContraction' qualifier. +// + +#include "propagateNoContraction.h" + +#include +#include +#include +#include + +#include "localintermediate.h" +namespace { + +// Use string to hold the accesschain information, as in most cases we the +// accesschain is short and may contain only one element, which is the symbol ID. +using ObjectAccessChain = std::string; +#ifndef StructAccessChainDelimiter +#define StructAccessChainDelimiter '/' +#endif + +// Mapping from Symbol IDs of symbol nodes, to their defining operation +// nodes. +using NodeMapping = std::unordered_multimap; +// Mapping from object nodes to their accesschain info string. +using AccessChainMapping = std::unordered_map; + +// Set of object IDs. +using ObjectAccesschainSet = std::unordered_set; +// Set of return branch nodes. +using ReturnBranchNodeSet = std::unordered_set; + +// A helper function to tell whether a node is 'noContraction'. Returns true if +// the node has 'noContraction' qualifier, otherwise false. +bool isPreciseObjectNode(glslang::TIntermTyped *node) +{ + return node->getType().getQualifier().noContraction; +} + +// Returns true if the opcode is a dereferencing one. +bool isDereferenceOperation(glslang::TOperator op) +{ + switch (op) { + case glslang::EOpIndexDirect: + case glslang::EOpIndexDirectStruct: + case glslang::EOpIndexIndirect: + case glslang::EOpVectorSwizzle: + return true; + default: + return false; + } +} + +// Returns true if the opcode leads to an assignment operation. +bool isAssignOperation(glslang::TOperator op) +{ + switch (op) { + case glslang::EOpAssign: + case glslang::EOpAddAssign: + case glslang::EOpSubAssign: + case glslang::EOpMulAssign: + case glslang::EOpVectorTimesMatrixAssign: + case glslang::EOpVectorTimesScalarAssign: + case glslang::EOpMatrixTimesScalarAssign: + case glslang::EOpMatrixTimesMatrixAssign: + case glslang::EOpDivAssign: + case glslang::EOpModAssign: + case glslang::EOpAndAssign: + case glslang::EOpLeftShiftAssign: + case glslang::EOpRightShiftAssign: + case glslang::EOpInclusiveOrAssign: + case glslang::EOpExclusiveOrAssign: + + case glslang::EOpPostIncrement: + case glslang::EOpPostDecrement: + case glslang::EOpPreIncrement: + case glslang::EOpPreDecrement: + return true; + default: + return false; + } +} + +// A helper function to get the unsigned int from a given constant union node. +// Note the node should only holds a uint scalar. +unsigned getStructIndexFromConstantUnion(glslang::TIntermTyped *node) +{ + assert(node->getAsConstantUnion() && node->getAsConstantUnion()->isScalar()); + unsigned struct_dereference_index = node->getAsConstantUnion()->getConstArray()[0].getUConst(); + return struct_dereference_index; +} + +// A helper function to generate symbol_label. +ObjectAccessChain generateSymbolLabel(glslang::TIntermSymbol *node) +{ + ObjectAccessChain symbol_id = std::to_string(node->getId()) + "(" + node->getName().c_str() + ")"; + return symbol_id; +} + +// Return true if the operation is an arithmetic operation and valid for +// 'NoContraction' decoration. +bool isArithmeticOperation(glslang::TOperator op) +{ + switch (op) { + case glslang::EOpAddAssign: + case glslang::EOpSubAssign: + case glslang::EOpMulAssign: + case glslang::EOpVectorTimesMatrixAssign: + case glslang::EOpVectorTimesScalarAssign: + case glslang::EOpMatrixTimesScalarAssign: + case glslang::EOpMatrixTimesMatrixAssign: + case glslang::EOpDivAssign: + case glslang::EOpModAssign: + + case glslang::EOpNegative: + + case glslang::EOpAdd: + case glslang::EOpSub: + case glslang::EOpMul: + case glslang::EOpDiv: + case glslang::EOpMod: + + case glslang::EOpVectorTimesScalar: + case glslang::EOpVectorTimesMatrix: + case glslang::EOpMatrixTimesVector: + case glslang::EOpMatrixTimesScalar: + + case glslang::EOpDot: + + case glslang::EOpAddCarry: + case glslang::EOpSubBorrow: + case glslang::EOpUMulExtended: + case glslang::EOpIMulExtended: + + case glslang::EOpPostIncrement: + case glslang::EOpPostDecrement: + case glslang::EOpPreIncrement: + case glslang::EOpPreDecrement: + return true; + default: + return false; + } +} + +// A helper class to help managing populating_initial_no_contraction_ flag. +template class StateSettingGuard { +public: + StateSettingGuard(T *state_ptr, T new_state_value) + : state_ptr_(state_ptr), previous_state_(*state_ptr) + { + *state_ptr = new_state_value; + } + StateSettingGuard(T *state_ptr) : state_ptr_(state_ptr), previous_state_(*state_ptr) {} + void setState(T new_state_value) + { + *state_ptr_ = new_state_value; + } + ~StateSettingGuard() { *state_ptr_ = previous_state_; } + +private: + T *state_ptr_; + T previous_state_; +}; + +// A helper function to get the front element from a given ObjectAccessChain +ObjectAccessChain getFrontElement(const ObjectAccessChain &chain) +{ + size_t pos_delimiter = chain.find(StructAccessChainDelimiter); + return pos_delimiter == std::string::npos ? chain : chain.substr(0, pos_delimiter); +} + +// A helper function to get the accesschain starting from the second element. +ObjectAccessChain subAccessChainFromSecondElement(const ObjectAccessChain& chain) +{ + size_t pos_delimiter = chain.find(StructAccessChainDelimiter); + return pos_delimiter == std::string::npos ? "" : chain.substr(pos_delimiter + 1); +} + +// +// A traverser which traverses the whole AST and populates: +// 1) A mapping from symbol nodes' IDs to their defining operation nodes. +// 2) A set of accesschains of the initial precise object nodes. +// +class TSymbolDefinitionCollectingTraverser : public glslang::TIntermTraverser { +public: + TSymbolDefinitionCollectingTraverser( + NodeMapping *symbol_definition_mapping, AccessChainMapping *accesschain_mapping, + ObjectAccesschainSet *precise_objects, + ReturnBranchNodeSet *precise_return_nodes); + + // bool visitAggregate(glslang::TVisit, glslang::TIntermAggregate *) override; + bool visitUnary(glslang::TVisit, glslang::TIntermUnary *) override; + bool visitBinary(glslang::TVisit, glslang::TIntermBinary *) override; + void visitSymbol(glslang::TIntermSymbol *) override; + bool visitAggregate(glslang::TVisit, glslang::TIntermAggregate *) override; + bool visitBranch(glslang::TVisit, glslang::TIntermBranch *) override; + +protected: + // The mapping from symbol node IDs to their defining nodes. This should be + // populated along traversing the AST. + NodeMapping &symbol_definition_mapping_; + // The set of symbol node IDs for precise symbol nodes, the ones marked as + // 'noContraction'. + ObjectAccesschainSet &precise_objects_; + // The set of precise return nodes. + ReturnBranchNodeSet &precise_return_nodes_; + // A temporary cache of the symbol node whose defining node is to be found + // currently along traversing the AST. + ObjectAccessChain object_to_be_defined_; + // A map from object node to its accesschain. This traverser stores + // the built accesschains into this map for each object node it has + // visited. + AccessChainMapping &accesschain_mapping_; + // The pointer to the Function Definition node, so we can get the + // precise'ness of the return expression from it when we traverse the + // return branch node. + glslang::TIntermAggregate* current_function_definition_node_; +}; + +TSymbolDefinitionCollectingTraverser::TSymbolDefinitionCollectingTraverser( + NodeMapping *symbol_definition_mapping, AccessChainMapping *accesschain_mapping, + ObjectAccesschainSet *precise_objects, + std::unordered_set *precise_return_nodes) + : TIntermTraverser(true, false, false), symbol_definition_mapping_(*symbol_definition_mapping), + precise_objects_(*precise_objects), object_to_be_defined_(), + accesschain_mapping_(*accesschain_mapping), current_function_definition_node_(nullptr), + precise_return_nodes_(*precise_return_nodes) {} + +// Visits a symbol node, set the object_to_be_defined_ to the +// current node symbol ID, and record a mapping from this node to the current +// object_to_be_defined_, which is the just obtained symbol +// ID. +void TSymbolDefinitionCollectingTraverser::visitSymbol(glslang::TIntermSymbol *node) +{ + object_to_be_defined_ = generateSymbolLabel(node); + accesschain_mapping_[node] = object_to_be_defined_; +} + +// Visits an aggregate node, traverses all of its children. +bool TSymbolDefinitionCollectingTraverser::visitAggregate(glslang::TVisit, + glslang::TIntermAggregate *node) +{ + // This aggreagate node might be a function definition node, in which case we need to + // cache this node, so we can get the precise'ness information of the return value + // of this function later. + StateSettingGuard current_function_definition_node_setting_guard( + ¤t_function_definition_node_); + if (node->getOp() == glslang::EOpFunction) { + // This is function definition node, we need to cache this node so that we can + // get the precise'ness of the return value later. + current_function_definition_node_setting_guard.setState(node); + } + // Traverse the items in the sequence. + glslang::TIntermSequence &seq = node->getSequence(); + for (int i = 0; i < (int)seq.size(); ++i) { + object_to_be_defined_.clear(); + seq[i]->traverse(this); + } + return false; +} + +bool TSymbolDefinitionCollectingTraverser::visitBranch(glslang::TVisit, + glslang::TIntermBranch *node) +{ + if (node->getFlowOp() == glslang::EOpReturn && node->getExpression() && + current_function_definition_node_ && + current_function_definition_node_->getType().getQualifier().noContraction) { + // This node is a return node with expression, and its function has + // precise return value. We need to find the involved objects in its + // expression and add them to the set of initial precise objects. + precise_return_nodes_.insert(node); + node->getExpression()->traverse(this); + } + return false; +} + +// Visits an unary node. This might be an implicit assignment like i++, i--. etc. +bool TSymbolDefinitionCollectingTraverser::visitUnary(glslang::TVisit /* visit */, + glslang::TIntermUnary *node) +{ + object_to_be_defined_.clear(); + node->getOperand()->traverse(this); + if (isAssignOperation(node->getOp())) { + // We should always be able to get an accesschain of the operand node. + // But we have some tests in which it is intented to have invalid operand + // nodes, so just return for now. + if (object_to_be_defined_.empty()) return false; + + // If the operand node object is 'precise', we collect its accesschain + // for the initial set of 'precise' objects. + if (isPreciseObjectNode(node->getOperand())) { + // The operand node is an 'precise' object node, add its + // accesschain to the set of 'precise' objects. This is to collect + // the initial set of 'precise' objects. + precise_objects_.insert(object_to_be_defined_); + } + // Gets the symbol ID from the object's accesschain. + ObjectAccessChain id_symbol = getFrontElement(object_to_be_defined_); + // Add a mapping from the symbol ID to this assignment operation node. + symbol_definition_mapping_.insert(std::make_pair(id_symbol, node)); + } + // Unary node is not a dereference node, so we clear the accesschain which + // is under construction. + object_to_be_defined_.clear(); + return false; +} + +// Visits a binary node and updates the mapping from symbol IDs to the definition +// nodes. Also collects the accesschains for the initial precise objects. +bool TSymbolDefinitionCollectingTraverser::visitBinary(glslang::TVisit /* visit */, + glslang::TIntermBinary *node) +{ + // Traverses the left node to build the accesschain info for the object. + object_to_be_defined_.clear(); + node->getLeft()->traverse(this); + + if (isAssignOperation(node->getOp())) { + // We should always be able to get an accesschain for the left node. + // But we have some tests in which it is intented to have invalid left + // nodes, so just return false in such cases for now. + if (object_to_be_defined_.empty()) return false; + + // If the left node object is 'precise', it is an initial precise object + // specified in the shader source. Adds it to the initial worklist to + // process later. + if (isPreciseObjectNode(node->getLeft())) { + // The left node is an 'precise' object node, add its accesschain to + // the set of 'precise' objects. This is to collect the initial set + // of 'precise' objects. + precise_objects_.insert(object_to_be_defined_); + } + // Gets the symbol ID from the object accesschain, which should be the + // first element recorded in the accesschain. + ObjectAccessChain id_symbol = getFrontElement(object_to_be_defined_); + // Adds a mapping from the symbol ID to this assignment operation node. + symbol_definition_mapping_.insert(std::make_pair(id_symbol, node)); + + // Traverses the right node, there may be other 'assignment' + // operatrions in the right. + object_to_be_defined_.clear(); + node->getRight()->traverse(this); + + return false; + } else if (isDereferenceOperation(node->getOp())) { + // If the left node is 'precise' object node, this node should also + // be 'precise' object node, and all the members of this node too. There + // is no need to append accesschain information into the object id. + if (isPreciseObjectNode(node->getLeft())) { + node->getWritableType().getQualifier().noContraction = true; + accesschain_mapping_[node] = object_to_be_defined_; + return false; + } + + // If the opcode is not EOpIndexDirectStruct, the left node is not be a + // struct type object, hence there is no need to append dereference + // indices. For other composite type objects, the precise'ness of + // members should always matches with the 'precise'ness of the + // composite type object. + if (node->getOp() != glslang::EOpIndexDirectStruct) { + accesschain_mapping_[node] = object_to_be_defined_; + return false; + } + + // The left node (parent node) is not 'precise' and it is a struct type + // object. We need to record the accesschain information of the current + // node into its object id. + unsigned struct_dereference_index = getStructIndexFromConstantUnion(node->getRight()); + object_to_be_defined_.push_back(StructAccessChainDelimiter); + object_to_be_defined_.append(std::to_string(struct_dereference_index)); + accesschain_mapping_[node] = object_to_be_defined_; + + // For dereference node, there is no need to traverse the right child + // node as the right node should always be an integer type object. + return false; + } else { + // For other binary nodes, still traverse the right node. + object_to_be_defined_.clear(); + node->getRight()->traverse(this); + return false; + } +} + +// Traverses the AST and returns a tuple of three members: +// 1) a mapping from symbol IDs to the definition nodes (aka. assignment nodes) of these symbols. +// 2) a mapping from object nodes in the AST to the accesschains of these objects. +// 3) a set of accesschains of precise objects. +std::tuple +getSymbolToDefinitionMappingAndPreciseSymbolIDs(const glslang::TIntermediate &intermediate) +{ + auto result_tuple = std::make_tuple(NodeMapping(), AccessChainMapping(), ObjectAccesschainSet(), ReturnBranchNodeSet()); + + TIntermNode *root = intermediate.getTreeRoot(); + if (root == 0) return result_tuple; + + NodeMapping &symbol_definition_mapping = std::get<0>(result_tuple); + AccessChainMapping &accesschain_mapping = std::get<1>(result_tuple); + ObjectAccesschainSet &precise_objects = std::get<2>(result_tuple); + ReturnBranchNodeSet &precise_return_nodes = std::get<3>(result_tuple); + + // Traverses the AST and populate the results. + TSymbolDefinitionCollectingTraverser collector(&symbol_definition_mapping, &accesschain_mapping, + &precise_objects, &precise_return_nodes); + root->traverse(&collector); + + return result_tuple; +} + +// +// A traverser that determine whether the left node (or operand node for unary +// node) of an assignment node is 'precise', containing 'precise' or not, +// according to the accesschain a given precise object which share the same +// symbol as the left node. +// +// Post-orderly traverses the left node subtree of an binary assignment node and: +// +// 1) Propagates the 'precise' from the left object nodes to this object node. +// +// 2) Builds object accesschain along the traversal, and also compares with +// the accesschain of the given 'precise' object along with the traversal to +// tell if the node to be defined is 'precise' or not. +// +class TNoContractionAssigneeCheckingTraverser : public glslang::TIntermTraverser { + + enum DecisionStatus { + // The object node to be assigned to may contain 'precise' objects and also not 'precise' objects. + Mixed = 0, + // The object node to be assigned to is either a 'precise' object or a struct objects whose members are all 'precise'. + Precise = 1, + // The object node to be assigned to is not a 'precise' object. + NotPreicse = 2, + }; + +public: + TNoContractionAssigneeCheckingTraverser() + : TIntermTraverser(true, false, false), accesschain_to_precise_object_(), decision_(Mixed) {} + + // Checks the precise'ness of a given assignment node with a precise object + // represented as accesschain. The precise object shares the same symbol + // with the assignee of the given assignment node. Return a tuple of two: + // + // 1) The precise'ness of the assignee node of this assignment node. True + // if the assignee contains 'precise' objects or is 'precise', false if + // the assignee is not 'precise' according to the accesschain of the given + // precise object. + // + // 2) The incremental accesschain from the assignee node to its nested + // 'precise' object, according to the accesschain of the given precise + // object. This incremental accesschain can be empty, which means the + // assignee is 'precise'. Otherwise it shows the path to the nested + // precise object. + std::tuple + getPrecisenessAndRemainedAccessChain(glslang::TIntermOperator* node, + const ObjectAccessChain &precise_object) + { + assert(isAssignOperation(node->getOp())); + accesschain_to_precise_object_ = precise_object; + decision_ = Mixed; + node->traverse(this); + return make_tuple(decision_ != NotPreicse, accesschain_to_precise_object_); + } + +protected: + bool visitBinary(glslang::TVisit, glslang::TIntermBinary *node) override; + bool visitUnary(glslang::TVisit, glslang::TIntermUnary *node) override; + void visitSymbol(glslang::TIntermSymbol *node) override; + + // The accesschain toward the given precise object. It will be iniailized + // with the accesschain of a given precise object, then trimmed along the + // traversal of the assignee subtree. The remained accesschain at the end + // of traversal shows the path from the assignee node to its nested + // 'precise' object. If the assignee node is 'precise' object object, this + // should be empty. + ObjectAccessChain accesschain_to_precise_object_; + // A state to tell the precise'ness of the assignee node according to the + // accesschain of the given precise object: + // + // 'Mixed': contains both 'precise' and 'non-precise' object + // (accesschain_to_precise_object_ is not empty), + // + // 'Precise': is precise object (accesschain_to_precise_object is empty), + // + // 'NotPrecise': is not precise object (mismatch in the struct dereference + // indices). + DecisionStatus decision_; +}; + +// Visit a binary node. As this traverser's job is to check the precise'ness of +// the assignee node in an assignment operation, it only needs to traverse the +// object nodes along the left branches. For struct type object nodes, it needs +// to obtain the struct dereference index from the right node to build the +// accesschain for this node. +bool TNoContractionAssigneeCheckingTraverser::visitBinary(glslang::TVisit, + glslang::TIntermBinary *node) +{ + node->getLeft()->traverse(this); + // For dereference operation nodes, we may need to check if the accesschain + // of the given precise object matches with the struct dereference indices + // of the assignee subtree. + if (isDereferenceOperation(node->getOp())) { + if (isPreciseObjectNode(node->getLeft())) { + // The left node is 'precise', which means the object node in the + // left contains the object represented in this node. If the left node + // is 'precise', this object node should also be 'precise' and no need + // to check the accesschain and struct deference indices anymore. + node->getWritableType().getQualifier().noContraction = true; + decision_ = Precise; + return false; + } + if (node->getOp() == glslang::EOpIndexDirectStruct && decision_ == Mixed) { + std::string struct_index = + std::to_string(getStructIndexFromConstantUnion(node->getRight())); + ObjectAccessChain precise_struct_index = getFrontElement(accesschain_to_precise_object_); + if (precise_struct_index == struct_index) { + // The struct dereference index matches with the record in the + // accesschain to the precise object. Pop the front access + // chain index from the precise object access chain. + accesschain_to_precise_object_ = + subAccessChainFromSecondElement(accesschain_to_precise_object_); + // If the given access chain to precise object is empty now, + // it means we've found the corresponding precise object in + // the assignee subtree. + if (accesschain_to_precise_object_.empty()) { + node->getWritableType().getQualifier().noContraction = true; + decision_ = Precise; + } + } else { + // The access chain index does not match with the record in the precise object id. + // This object should not be labelled as 'precise' here. + decision_ = NotPreicse; + } + } + } + return false; +} + +// Visits an unary node, traverses its operand. If the node is an assignment node, +// determines the precise'ness of the assignee directly based on the assignee node's +// precise'ness. +bool TNoContractionAssigneeCheckingTraverser::visitUnary(glslang::TVisit, + glslang::TIntermUnary *node) +{ + node->getOperand()->traverse(this); + if (isAssignOperation(node->getOp())) { + if (isPreciseObjectNode(node->getOperand())) { + decision_ = Precise; + // As the assignee node is 'precise', all (if any) the + // member objects the that node should also be 'precise'. This means + // we won't need to propagate extra access chain info. + accesschain_to_precise_object_.clear(); + } else { + decision_ = NotPreicse; + } + } + return false; +} + +// Visits a symbol node. The symbol ID of this node should match with the symbol ID, which is +// the front element, in the accesschain of the given 'precise' object. +void TNoContractionAssigneeCheckingTraverser::visitSymbol(glslang::TIntermSymbol *node) +{ + ObjectAccessChain symbol_id = generateSymbolLabel(node); + // The root symbol of the given access chain should be the same with the one represented by the symbol node here. + assert(symbol_id == getFrontElement(accesschain_to_precise_object_)); + // Pop the symbol node part from the front end of the accesschain string. + accesschain_to_precise_object_ = + subAccessChainFromSecondElement(accesschain_to_precise_object_); + if (accesschain_to_precise_object_.empty()) { + node->getWritableType().getQualifier().noContraction = true; + decision_ = Precise; + } + // If this symbol node is 'precise', all its members should be 'precise' so the assignee of the processing + // assignment operations is 'precise'. + if (isPreciseObjectNode(node)) { + decision_ = Precise; + } +} + +// +// A traverser that only traverses the right side of binary assignment nodes +// and the operand node of unary assignment nodes. +// +// 1) Marks arithmetic operations 'NoContraction'. +// +// 2) Find the object which should be marked as 'precise' in the right and +// update the 'precise' object worklist. +// +class TNoContractionPropagator : public glslang::TIntermTraverser { +public: + TNoContractionPropagator(ObjectAccesschainSet *precise_objects, + const AccessChainMapping &accesschain_mapping) + : TIntermTraverser(true, false, false), remained_accesschain_(), + precise_objects_(*precise_objects), + accesschain_mapping_(accesschain_mapping), added_precise_object_ids_() {} + + // Propagates 'precise' in the right nodes of a given assignment node with + // accesschain record from the assignee node to a 'precise' object it + // contains. + void + propagateNoContractionInOneExpression(glslang::TIntermTyped *defining_node, + const ObjectAccessChain &assignee_remained_accesschain) + { + remained_accesschain_ = assignee_remained_accesschain; + if (glslang::TIntermBinary *BN = defining_node->getAsBinaryNode()) { + assert(isAssignOperation(BN->getOp())); + BN->getRight()->traverse(this); + if (isArithmeticOperation(BN->getOp())) { + BN->getWritableType().getQualifier().noContraction = true; + } + } else if (glslang::TIntermUnary *UN = defining_node->getAsUnaryNode()) { + assert(isAssignOperation(UN->getOp())); + UN->getOperand()->traverse(this); + if (isArithmeticOperation(UN->getOp())) { + UN->getWritableType().getQualifier().noContraction = true; + } + } + } + + // Propagates 'precise' in a given precise return node. + void + propagateNoContractionInReturnNode(glslang::TIntermBranch *return_node) + { + remained_accesschain_ = ""; + assert(return_node->getFlowOp() == glslang::EOpReturn && return_node->getExpression()); + return_node->getExpression()->traverse(this); + } + +protected: + // Visit an aggregate node. The node can be a initializer list, in which + // case we need to find the 'precise' or 'precise' containing object node + // with the accesschain record. In other cases, just need to traverse all + // the children nodes. + bool visitAggregate(glslang::TVisit, glslang::TIntermAggregate *node) override + { + if (!remained_accesschain_.empty() && node->getOp() == glslang::EOpConstructStruct) { + // This is a struct initializer node, and the remained + // accesschain is not empty, we need to refer to the + // assignee_remained_access_chain_ to find the nested + // 'precise' object. And we don't need to visit other nodes in this + // aggreagate node. + + // Gets the struct dereference index that leads to 'precise' object. + ObjectAccessChain precise_accesschain_index_str = + getFrontElement(remained_accesschain_); + unsigned precise_accesschain_index = std::stoul(precise_accesschain_index_str); + // Gets the node pointed by the accesschain index extracted before. + glslang::TIntermTyped *potential_precise_node = + node->getSequence()[precise_accesschain_index]->getAsTyped(); + assert(potential_precise_node); + // Pop the front accesschain index from the path, and visit the nested node. + { + ObjectAccessChain next_level_accesschain = + subAccessChainFromSecondElement(remained_accesschain_); + StateSettingGuard setup_remained_accesschain_for_next_level( + &remained_accesschain_, next_level_accesschain); + potential_precise_node->traverse(this); + } + + } else { + // If this is not a struct constructor, just visit each nested node. + glslang::TIntermSequence &seq = node->getSequence(); + for (int i = 0; i < (int)seq.size(); ++i) { + seq[i]->traverse(this); + } + } + + return false; + } + + // Visit a binary node. A binary node can be an object node, e.g. a dereference node. + // As only the top object nodes in the right side of an assignment needs to be visited + // and added to 'precise' worklist, this traverser won't visit the children nodes of + // an object node. If the binary node does not represent an object node, it should + // go on to traverse its children nodes and if it is an arithmetic operation node, this + // operation should be marked as 'noContraction'. + bool visitBinary(glslang::TVisit, glslang::TIntermBinary *node) override + { + if (isDereferenceOperation(node->getOp())) { + // This binary node is an object node. Need to update the precise + // object set with the accesschain of this node + remained + // accesschain . + ObjectAccessChain new_precise_accesschain = accesschain_mapping_.at(node); + if (remained_accesschain_.empty()) { + node->getWritableType().getQualifier().noContraction = true; + } else { + new_precise_accesschain += + StructAccessChainDelimiter + remained_accesschain_; + } + // Cache the accesschain as added precise object, so we won't add the + // same object to the worklist again. + if (!added_precise_object_ids_.count(new_precise_accesschain)) { + precise_objects_.insert(new_precise_accesschain); + added_precise_object_ids_.insert(new_precise_accesschain); + } + // Only the upper-most object nodes should be visited, so do not + // visit children of this object node. + return false; + } + // If this is an arithmetic operation, marks this node as 'noContraction'. + if (isArithmeticOperation(node->getOp())) { + node->getWritableType().getQualifier().noContraction = true; + } + // As this node is not an object node, need to traverse the children nodes. + node->getLeft()->traverse(this); + node->getRight()->traverse(this); + return false; + } + + // Visits an unary node. An unary node can not be an object node. If the operation + // is an arithmetic operation, need to mark this node as 'noContraction'. + bool visitUnary(glslang::TVisit /* visit */, glslang::TIntermUnary *node) override + { + // If this is an arithmetic operation, marks this with 'noContraction' + if (isArithmeticOperation(node->getOp())) { + node->getWritableType().getQualifier().noContraction = true; + } + node->getOperand()->traverse(this); + return false; + } + + // Visits a symbol node. A symbol node is always an object node. So we + // should always be able to find its in our colected mapping from object + // nodes to accesschains. As an object node, a symbol node can be either + // 'precise' or containing 'precise' objects according to unused + // accesschain information we have when we visit this node. + void visitSymbol(glslang::TIntermSymbol *node) override + { + // Symbol nodes are object nodes and should always have an + // accesschain collected before matches with it. + assert(accesschain_mapping_.count(node)); + ObjectAccessChain new_precise_accesschain = accesschain_mapping_.at(node); + // If the unused accesschain is empty, this symbol node should be + // marked as 'precise'. Otherwise, the unused accesschain should be + // appended to the symbol ID to build a new accesschain which points to + // the nested 'precise' object in this symbol object. + if (remained_accesschain_.empty()) { + node->getWritableType().getQualifier().noContraction = true; + } else { + new_precise_accesschain += StructAccessChainDelimiter + remained_accesschain_; + } + // Add the new 'precise' accesschain to the worklist and make sure we + // don't visit it again. + if (!added_precise_object_ids_.count(new_precise_accesschain)) { + precise_objects_.insert(new_precise_accesschain); + added_precise_object_ids_.insert(new_precise_accesschain); + } + } + + // A set of precise objects, represented as accesschains. + ObjectAccesschainSet &precise_objects_; + // Visited symbol nodes, should not revisit these nodes. + ObjectAccesschainSet added_precise_object_ids_; + // The left node of an assignment operation might be an parent of 'precise' objects. + // This means the left node might not be an 'precise' object node, but it may contains + // 'precise' qualifier which should be propagated to the corresponding child node in + // the right. So we need the path from the left node to its nested 'precise' node to + // tell us how to find the corresponding 'precise' node in the right. + ObjectAccessChain remained_accesschain_; + // A map from node pointers to their accesschains. + const AccessChainMapping &accesschain_mapping_; +}; + +#undef StructAccessChainDelimiter +} + +namespace glslang { + +void PropagateNoContraction(const glslang::TIntermediate &intermediate) +{ + // First, traverses the AST, records symbols with their defining operations + // and collects the initial set of precise symbols (symbol nodes that marked + // as 'noContraction'). + auto mappings_and_precise_objects = + getSymbolToDefinitionMappingAndPreciseSymbolIDs(intermediate); + + // The mapping of symbol node IDs to their defining nodes. This enables us + // to get the defining node directly from a given symbol ID without + // traversing the tree again. + NodeMapping &symbol_definition_mapping = std::get<0>(mappings_and_precise_objects); + + // The mapping of object nodes to their accesschains recorded. + AccessChainMapping &accesschain_mapping = std::get<1>(mappings_and_precise_objects); + + // The initial set of 'precise' objects which are represented as the + // accesschain toward them. + ObjectAccesschainSet &precise_object_accesschains = + std::get<2>(mappings_and_precise_objects); + + // The set of 'precise' return nodes. + ReturnBranchNodeSet &precise_return_nodes = std::get<3>(mappings_and_precise_objects); + + // Second, uses the initial set of precise objects as a worklist, pops an + // accesschain, extract the symbol ID from it. Then: + // 1) Check the assignee object, see if it is 'precise' object node or + // contains 'precise' object. Obtain the incremental accesschain from the + // assignee node to its nested 'precise' node (if any). + // 2) If the assignee object node is 'precise' or it contains 'precise' + // objects, traverses the right side of the assignment operation + // expression to mark arithmetic operations as 'noContration' and update + // 'precise' accesschain worklist with new found object nodes. + // Repeat above steps until the worklist is empty. + TNoContractionAssigneeCheckingTraverser checker; + TNoContractionPropagator propagator(&precise_object_accesschains, + accesschain_mapping); + + // We have to initial precise worklist to handle: + // 1) precise return nodes + // 2) precise object accesschains + // We should process the precise return nodes first and the involved + // objects in the return expression should be added to the precise object + // accesschain set. + while (!precise_return_nodes.empty()) { + glslang::TIntermBranch* precise_return_node = *precise_return_nodes.begin(); + propagator.propagateNoContractionInReturnNode(precise_return_node); + precise_return_nodes.erase(precise_return_node); + } + + while (!precise_object_accesschains.empty()) { + // Get the accesschain of a precise object from the worklist. + ObjectAccessChain precise_object_accesschain = *precise_object_accesschains.begin(); + // Get the symbol id from the accesschain. + ObjectAccessChain symbol_id = getFrontElement(precise_object_accesschain); + // Get all the defining nodes of that symbol ID. + std::pair range = + symbol_definition_mapping.equal_range(symbol_id); + // Visit all the assignment nodes of that symbol ID and + // 1) Check if the assignee node is 'precise' or contains 'precise' + // objects. + // 2) Propagate the 'precise' to the top layer object ndoes + // in the right side of the assignment operation, update the 'precise' + // worklist with new accesschains representing the new 'precise' + // objects, and mark arithmetic operations as 'noContraction'. + for (NodeMapping::iterator defining_node_iter = range.first; + defining_node_iter != range.second; defining_node_iter++) { + TIntermOperator *defining_node = defining_node_iter->second; + // Check the assignee node. + auto checker_result = checker.getPrecisenessAndRemainedAccessChain( + defining_node, precise_object_accesschain); + bool &contain_precise = std::get<0>(checker_result); + ObjectAccessChain &remained_accesschain = std::get<1>(checker_result); + // If the assignee node is 'precise' or contains 'precise', propagate the + // 'precise' to the right. Otherwise just skip this assignment node. + if (contain_precise) { + propagator.propagateNoContractionInOneExpression(defining_node, + remained_accesschain); + } + } + // Remove the last processed 'precise' object from the worklist. + precise_object_accesschains.erase(precise_object_accesschain); + } +} +}; diff --git a/glslang/MachineIndependent/propagateNoContraction.h b/glslang/MachineIndependent/propagateNoContraction.h new file mode 100644 index 00000000..43c2116b --- /dev/null +++ b/glslang/MachineIndependent/propagateNoContraction.h @@ -0,0 +1,53 @@ +// +// Copyright (C) 2015-2016 Google, Inc. +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +// +// Visit the nodes in the glslang intermediate tree representation to +// propagate 'noContraction' qualifier. +// + +#include "../Include/intermediate.h" + +namespace glslang { + +// Propagates the 'precise' qualifier for objects (objects marked with +// 'noContraction' qualifier) from the shader source specified 'precise' +// variables to all the involved objects, and add 'noContraction' qualifier for +// the involved arithmetic operations. +// Note that the same qualifier: 'noContraction' is used in both object nodes +// and arithmetic operation nodes, but has different meaning. For object nodes, +// 'noContraction' means the object is 'precise'; and for arithmetic operation +// nodes, it means the operation should not be contracted. +void PropagateNoContraction(const glslang::TIntermediate& intermediate); +}; From 1a0d93f416361d11bffd562d092cb2ba53cd8e9c Mon Sep 17 00:00:00 2001 From: qining Date: Thu, 5 May 2016 17:47:27 -0400 Subject: [PATCH 2/9] Fix the test of precise output function parameter Rebase to 5cc344d8ce09a6d35ff88b9ea9f351062d779081 and update the expected test result. --- Test/baseResults/precise.tesc.out | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/Test/baseResults/precise.tesc.out b/Test/baseResults/precise.tesc.out index d14af90e..4976b9cb 100644 --- a/Test/baseResults/precise.tesc.out +++ b/Test/baseResults/precise.tesc.out @@ -341,18 +341,18 @@ vertices = -1 0:96 Function Definition: precise_func_parameter(f1;f1; (global float) 0:96 Function Parameters: 0:96 'b' (in float) -0:96 'c' (out float) +0:96 'c' (noContraction out float) 0:97 Sequence 0:97 Sequence 0:97 move second child to first child (temp float) -0:97 'a' (temp float) +0:97 'a' (noContraction temp float) 0:97 Constant: 0:97 0.500000 0:98 move second child to first child (temp float) -0:98 'c' (out float) -0:98 add (temp float) -0:98 'a' (temp float) -0:98 'b' (in float) +0:98 'c' (noContraction out float) +0:98 add (noContraction temp float) +0:98 'a' (noContraction temp float) +0:98 'b' (noContraction in float) 0:99 Branch: Return with expression 0:99 subtract (temp float) 0:99 'a' (temp float) @@ -706,18 +706,18 @@ vertices = -1 0:96 Function Definition: precise_func_parameter(f1;f1; (global float) 0:96 Function Parameters: 0:96 'b' (in float) -0:96 'c' (out float) +0:96 'c' (noContraction out float) 0:97 Sequence 0:97 Sequence 0:97 move second child to first child (temp float) -0:97 'a' (temp float) +0:97 'a' (noContraction temp float) 0:97 Constant: 0:97 0.500000 0:98 move second child to first child (temp float) -0:98 'c' (out float) -0:98 add (temp float) -0:98 'a' (temp float) -0:98 'b' (in float) +0:98 'c' (noContraction out float) +0:98 add (noContraction temp float) +0:98 'a' (noContraction temp float) +0:98 'b' (noContraction in float) 0:99 Branch: Return with expression 0:99 subtract (temp float) 0:99 'a' (temp float) From 015150e4b359ee7539ea5952fa86439c550602df Mon Sep 17 00:00:00 2001 From: qining Date: Thu, 5 May 2016 22:34:52 -0400 Subject: [PATCH 3/9] Removed the redundant functionalities in the assignee checking traverser --- .../propagateNoContraction.cpp | 211 +++++++++--------- 1 file changed, 111 insertions(+), 100 deletions(-) diff --git a/glslang/MachineIndependent/propagateNoContraction.cpp b/glslang/MachineIndependent/propagateNoContraction.cpp index 044ecbf3..fa2b62a9 100644 --- a/glslang/MachineIndependent/propagateNoContraction.cpp +++ b/glslang/MachineIndependent/propagateNoContraction.cpp @@ -211,6 +211,14 @@ ObjectAccessChain subAccessChainFromSecondElement(const ObjectAccessChain& chain return pos_delimiter == std::string::npos ? "" : chain.substr(pos_delimiter + 1); } +// A helper function to get the accesschain after removing a given prefix. +ObjectAccessChain getSubAccessChainAfterPrefix(const ObjectAccessChain &chain, const ObjectAccessChain &prefix) +{ + size_t pos = chain.find(prefix); + if (pos != 0) return chain; + return chain.substr(prefix.length() + sizeof(StructAccessChainDelimiter)); +} + // // A traverser which traverses the whole AST and populates: // 1) A mapping from symbol nodes' IDs to their defining operation nodes. @@ -466,8 +474,9 @@ class TNoContractionAssigneeCheckingTraverser : public glslang::TIntermTraverser }; public: - TNoContractionAssigneeCheckingTraverser() - : TIntermTraverser(true, false, false), accesschain_to_precise_object_(), decision_(Mixed) {} + TNoContractionAssigneeCheckingTraverser(const AccessChainMapping &accesschain_mapping) + : TIntermTraverser(true, false, false), accesschain_mapping_(accesschain_mapping), + precise_object_(nullptr) {} // Checks the precise'ness of a given assignment node with a precise object // represented as accesschain. The precise object shares the same symbol @@ -488,125 +497,127 @@ public: const ObjectAccessChain &precise_object) { assert(isAssignOperation(node->getOp())); - accesschain_to_precise_object_ = precise_object; - decision_ = Mixed; - node->traverse(this); - return make_tuple(decision_ != NotPreicse, accesschain_to_precise_object_); + precise_object_ = &precise_object; + ObjectAccessChain assignee_object; + if (glslang::TIntermBinary* BN = node->getAsBinaryNode()) { + // This is a binary assignment node, we need to check the + // precise'ness of the left node. + if (!accesschain_mapping_.count(BN->getLeft())) { + // If the left node is not an object node, it can not be + // 'precise'. + return make_tuple(false, ObjectAccessChain()); + } + // The left node (assignee node) is an object node, traverse the + // node to let the 'precise' of nesting objects being transfered to + // nested objects. + BN->getLeft()->traverse(this); + // After traversing the left node, if the left node is 'precise', + // we can conclude this assignment should propagate 'precise'. + if (isPreciseObjectNode(BN->getLeft())) { + return make_tuple(true, ObjectAccessChain()); + } + // If the precise'ness of the left node (assignee node) can not + // be determined by now, we need to compare the accesschain string + // of the assignee object with the given precise object. + assignee_object = accesschain_mapping_.at(BN->getLeft()); + + } else if (glslang::TIntermUnary* UN = node->getAsUnaryNode()) { + // This is a unary assignment node, we need to check the + // precise'ness of the operand node. For unary assignment node, the + // operand node should always be an object node. + if (!accesschain_mapping_.count(UN->getOperand())) { + // If the operand node is not an object node, it can not be + // 'precise'. + return make_tuple(false, ObjectAccessChain()); + } + // Traverse the operand node to let the 'precise' being propagated + // from lower nodes to upper nodes. + UN->getOperand()->traverse(this); + // After traversing the operand node, if the operand node is + // 'precise', this assignment should propagate 'precise'. + if (isPreciseObjectNode(UN->getOperand())) { + return make_tuple(true, ObjectAccessChain()); + } + // If the precise'ness of the operand node (assignee node) can not + // be determined by now, we need to compare the accesschain string + // of the assignee object with the given precise object. + assignee_object = accesschain_mapping_.at(UN->getOperand()); + } else { + // Not a binary or unary node, should not happen. + assert(false); + } + + // Compare the accesschain string of the assignee node with the given + // precise object to determine if this assignment should propagate + // 'precise'. + if (assignee_object.find(precise_object) == 0) { + // The accesschain string of the given precise object is a prefix + // of assignee's accesschain string. The assignee should be + // 'precise'. + return make_tuple(true, ObjectAccessChain()); + } else if (precise_object.find(assignee_object) == 0) { + // The assignee's accesschain string is a prefix of the given + // precise object, the assignee object contains 'precise' object, + // and we need to pass the remained accesschain to the object nodes + // in the right. + return make_tuple(true, getSubAccessChainAfterPrefix(precise_object, assignee_object)); + } else { + // The accesschain strings do not match, the assignee object can + // not be labelled as 'precise' according to the given precise + // object. + return make_tuple(false, ObjectAccessChain()); + } } protected: bool visitBinary(glslang::TVisit, glslang::TIntermBinary *node) override; - bool visitUnary(glslang::TVisit, glslang::TIntermUnary *node) override; void visitSymbol(glslang::TIntermSymbol *node) override; - // The accesschain toward the given precise object. It will be iniailized - // with the accesschain of a given precise object, then trimmed along the - // traversal of the assignee subtree. The remained accesschain at the end - // of traversal shows the path from the assignee node to its nested - // 'precise' object. If the assignee node is 'precise' object object, this - // should be empty. - ObjectAccessChain accesschain_to_precise_object_; - // A state to tell the precise'ness of the assignee node according to the - // accesschain of the given precise object: - // - // 'Mixed': contains both 'precise' and 'non-precise' object - // (accesschain_to_precise_object_ is not empty), - // - // 'Precise': is precise object (accesschain_to_precise_object is empty), - // - // 'NotPrecise': is not precise object (mismatch in the struct dereference - // indices). - DecisionStatus decision_; + // A map from object nodes to their accesschain string (used as object ID). + const AccessChainMapping &accesschain_mapping_; + // A given precise object, represented in it accesschain string. This + // precise object is used to be compared with the assignee node to tell if + // the assignee node is 'precise', contains 'precise' object or not + // 'precise'. + const ObjectAccessChain *precise_object_; }; -// Visit a binary node. As this traverser's job is to check the precise'ness of -// the assignee node in an assignment operation, it only needs to traverse the -// object nodes along the left branches. For struct type object nodes, it needs -// to obtain the struct dereference index from the right node to build the -// accesschain for this node. +// Visit a binary node. If the node is an object node, it must be a dereference +// node. In such cases, if the left node is 'precise', this node should also be +// 'precise'. bool TNoContractionAssigneeCheckingTraverser::visitBinary(glslang::TVisit, glslang::TIntermBinary *node) { + // Traverses the left so that we transfer the 'precise' from nesting object + // to its nested object. node->getLeft()->traverse(this); - // For dereference operation nodes, we may need to check if the accesschain - // of the given precise object matches with the struct dereference indices - // of the assignee subtree. - if (isDereferenceOperation(node->getOp())) { + // If this binary node is an object node, we should have it in the + // accesschain_mapping_. + if (accesschain_mapping_.count(node)) { + // A binary object node must be a dereference node. + assert(isDereferenceOperation(node->getOp())); + // If the left node is 'precise', this node should also be precise, + // otherwise, compare with the given precise_object_. If the + // accesschain of this node matches with the given precise_object_, + // this node should be marked as 'precise'. if (isPreciseObjectNode(node->getLeft())) { - // The left node is 'precise', which means the object node in the - // left contains the object represented in this node. If the left node - // is 'precise', this object node should also be 'precise' and no need - // to check the accesschain and struct deference indices anymore. node->getWritableType().getQualifier().noContraction = true; - decision_ = Precise; - return false; - } - if (node->getOp() == glslang::EOpIndexDirectStruct && decision_ == Mixed) { - std::string struct_index = - std::to_string(getStructIndexFromConstantUnion(node->getRight())); - ObjectAccessChain precise_struct_index = getFrontElement(accesschain_to_precise_object_); - if (precise_struct_index == struct_index) { - // The struct dereference index matches with the record in the - // accesschain to the precise object. Pop the front access - // chain index from the precise object access chain. - accesschain_to_precise_object_ = - subAccessChainFromSecondElement(accesschain_to_precise_object_); - // If the given access chain to precise object is empty now, - // it means we've found the corresponding precise object in - // the assignee subtree. - if (accesschain_to_precise_object_.empty()) { - node->getWritableType().getQualifier().noContraction = true; - decision_ = Precise; - } - } else { - // The access chain index does not match with the record in the precise object id. - // This object should not be labelled as 'precise' here. - decision_ = NotPreicse; - } + } else if (accesschain_mapping_.at(node) == *precise_object_){ + node->getWritableType().getQualifier().noContraction = true; } } return false; } -// Visits an unary node, traverses its operand. If the node is an assignment node, -// determines the precise'ness of the assignee directly based on the assignee node's -// precise'ness. -bool TNoContractionAssigneeCheckingTraverser::visitUnary(glslang::TVisit, - glslang::TIntermUnary *node) -{ - node->getOperand()->traverse(this); - if (isAssignOperation(node->getOp())) { - if (isPreciseObjectNode(node->getOperand())) { - decision_ = Precise; - // As the assignee node is 'precise', all (if any) the - // member objects the that node should also be 'precise'. This means - // we won't need to propagate extra access chain info. - accesschain_to_precise_object_.clear(); - } else { - decision_ = NotPreicse; - } - } - return false; -} - -// Visits a symbol node. The symbol ID of this node should match with the symbol ID, which is -// the front element, in the accesschain of the given 'precise' object. +// Visit a symbol node, if the symbol node ID (its accesschain string) matches +// with the given precise object, this node should be 'precise'. void TNoContractionAssigneeCheckingTraverser::visitSymbol(glslang::TIntermSymbol *node) { - ObjectAccessChain symbol_id = generateSymbolLabel(node); - // The root symbol of the given access chain should be the same with the one represented by the symbol node here. - assert(symbol_id == getFrontElement(accesschain_to_precise_object_)); - // Pop the symbol node part from the front end of the accesschain string. - accesschain_to_precise_object_ = - subAccessChainFromSecondElement(accesschain_to_precise_object_); - if (accesschain_to_precise_object_.empty()) { + // A symbol node should always be an object node, and should have been added + // to the map from object nodes to their accesschain strings. + assert(accesschain_mapping_.count(node)); + if (accesschain_mapping_.at(node) == *precise_object_) { node->getWritableType().getQualifier().noContraction = true; - decision_ = Precise; - } - // If this symbol node is 'precise', all its members should be 'precise' so the assignee of the processing - // assignment operations is 'precise'. - if (isPreciseObjectNode(node)) { - decision_ = Precise; } } @@ -833,7 +844,7 @@ void PropagateNoContraction(const glslang::TIntermediate &intermediate) // expression to mark arithmetic operations as 'noContration' and update // 'precise' accesschain worklist with new found object nodes. // Repeat above steps until the worklist is empty. - TNoContractionAssigneeCheckingTraverser checker; + TNoContractionAssigneeCheckingTraverser checker(accesschain_mapping); TNoContractionPropagator propagator(&precise_object_accesschains, accesschain_mapping); From 25262b3fd95da58de45197e9b06418bdcdeee57c Mon Sep 17 00:00:00 2001 From: qining Date: Fri, 6 May 2016 17:25:16 -0400 Subject: [PATCH 4/9] Resolve comments 1. Sink adding noContraction decoration to createBinaryOperation() and createUnaryOperation(). 2. Fix comments. 3. Remove the #define of my delimiter, use global constant char. --- SPIRV/GlslangToSpv.cpp | 108 +++++---- .../propagateNoContraction.cpp | 216 +++++++++--------- 2 files changed, 162 insertions(+), 162 deletions(-) diff --git a/SPIRV/GlslangToSpv.cpp b/SPIRV/GlslangToSpv.cpp index d160e36e..22575b5a 100755 --- a/SPIRV/GlslangToSpv.cpp +++ b/SPIRV/GlslangToSpv.cpp @@ -33,8 +33,6 @@ //ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE //POSSIBILITY OF SUCH DAMAGE. -// -// Author: John Kessenich, LunarG // // Visit the nodes in the glslang intermediate tree representation to // translate them to SPIR-V. @@ -135,10 +133,10 @@ protected: spv::Id createImageTextureFunctionCall(glslang::TIntermOperator* node); spv::Id handleUserFunctionCall(const glslang::TIntermAggregate*); - spv::Id createBinaryOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, spv::Id left, spv::Id right, glslang::TBasicType typeProxy, bool reduceComparison = true); - spv::Id createBinaryMatrixOperation(spv::Op, spv::Decoration precision, spv::Id typeId, spv::Id left, spv::Id right); - spv::Id createUnaryOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, spv::Id operand,glslang::TBasicType typeProxy); - spv::Id createUnaryMatrixOperation(spv::Op, spv::Decoration precision, spv::Id typeId, spv::Id operand,glslang::TBasicType typeProxy); + spv::Id createBinaryOperation(glslang::TOperator op, spv::Decoration precision, spv::Decoration noContraction, spv::Id typeId, spv::Id left, spv::Id right, glslang::TBasicType typeProxy, bool reduceComparison = true); + spv::Id createBinaryMatrixOperation(spv::Op, spv::Decoration precision, spv::Decoration noContraction, spv::Id typeId, spv::Id left, spv::Id right); + spv::Id createUnaryOperation(glslang::TOperator op, spv::Decoration precision, spv::Decoration noContraction, spv::Id typeId, spv::Id operand,glslang::TBasicType typeProxy); + spv::Id createUnaryMatrixOperation(spv::Op, spv::Decoration precision, spv::Decoration noContraction, spv::Id typeId, spv::Id operand,glslang::TBasicType typeProxy); spv::Id createConversion(glslang::TOperator op, spv::Decoration precision, spv::Id destTypeId, spv::Id operand); spv::Id makeSmearedConstant(spv::Id constant, int vectorSize); spv::Id createAtomicOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, std::vector& operands, glslang::TBasicType typeProxy); @@ -244,7 +242,7 @@ spv::StorageClass TranslateStorageClass(const glslang::TType& type) case glslang::EvqGlobal: return spv::StorageClassPrivate; case glslang::EvqConstReadOnly: return spv::StorageClassFunction; case glslang::EvqTemporary: return spv::StorageClassFunction; - default: + default: assert(0); return spv::StorageClassFunction; } @@ -567,7 +565,7 @@ spv::ImageFormat TGlslangToSpvTraverser::TranslateImageFormat(const glslang::TTy } } -// Return whether or not the given type is something that should be tied to a +// Return whether or not the given type is something that should be tied to a // descriptor set. bool IsDescriptorResource(const glslang::TType& type) { @@ -621,8 +619,7 @@ bool HasNonLayoutQualifiers(const glslang::TQualifier& qualifier) // - struct members can inherit from a struct declaration // - effect decorations on the struct members (note smooth does not, and expecting something like volatile to effect the whole object) // - are not part of the offset/st430/etc or row/column-major layout - return qualifier.invariant || qualifier.nopersp || qualifier.flat || qualifier.centroid || qualifier.patch || qualifier.sample || qualifier.hasLocation() || - qualifier.noContraction; + return qualifier.invariant || qualifier.nopersp || qualifier.flat || qualifier.centroid || qualifier.patch || qualifier.sample || qualifier.hasLocation(); } // @@ -792,7 +789,7 @@ TGlslangToSpvTraverser::~TGlslangToSpvTraverser() // // -// Symbols can turn into +// Symbols can turn into // - uniform/input reads // - output writes // - complex lvalue base setups: foo.bar[3].... , where we see foo and start up an access chain @@ -883,13 +880,11 @@ bool TGlslangToSpvTraverser::visitBinary(glslang::TVisit /* visit */, glslang::T spv::Id leftRValue = accessChainLoad(node->getLeft()->getType()); // do the operation - rValue = createBinaryOperation(node->getOp(), TranslatePrecisionDecoration(node->getType()), + rValue = createBinaryOperation(node->getOp(), TranslatePrecisionDecoration(node->getType()), + TranslateNoContractionDecoration(node->getType().getQualifier()), convertGlslangToSpvType(node->getType()), leftRValue, rValue, node->getType().getBasicType()); - // Decorate this instruction, if this node has 'noContraction' qualifier. - addDecoration(rValue, TranslateNoContractionDecoration(node->getType().getQualifier())); - // these all need their counterparts in createBinaryOperation() assert(rValue != spv::NoResult); } @@ -1005,6 +1000,7 @@ bool TGlslangToSpvTraverser::visitBinary(glslang::TVisit /* visit */, glslang::T // get result spv::Id result = createBinaryOperation(node->getOp(), TranslatePrecisionDecoration(node->getType()), + TranslateNoContractionDecoration(node->getType().getQualifier()), convertGlslangToSpvType(node->getType()), left, right, node->getLeft()->getType().getBasicType()); @@ -1013,8 +1009,6 @@ bool TGlslangToSpvTraverser::visitBinary(glslang::TVisit /* visit */, glslang::T logger->missingFunctionality("unknown glslang binary operation"); return true; // pick up a child as the place-holder result } else { - // Decorate this instruction, if this node has 'noContraction' qualifier. - addDecoration(result, TranslateNoContractionDecoration(node->getType().getQualifier())); builder.setAccessChainRValue(result); return false; } @@ -1073,6 +1067,7 @@ bool TGlslangToSpvTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TI operand = accessChainLoad(node->getOperand()->getType()); spv::Decoration precision = TranslatePrecisionDecoration(node->getType()); + spv::Decoration noContraction = TranslateNoContractionDecoration(node->getType().getQualifier()); // it could be a conversion if (! result) @@ -1080,11 +1075,9 @@ bool TGlslangToSpvTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TI // if not, then possibly an operation if (! result) - result = createUnaryOperation(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operand, node->getOperand()->getBasicType()); + result = createUnaryOperation(node->getOp(), precision, noContraction, convertGlslangToSpvType(node->getType()), operand, node->getOperand()->getBasicType()); if (result) { - // Decorate this instruction, if this node has 'noContraction' qualifier. - addDecoration(result, TranslateNoContractionDecoration(node->getType().getQualifier())); builder.clearAccessChain(); builder.setAccessChainRValue(result); @@ -1113,12 +1106,11 @@ bool TGlslangToSpvTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TI else op = glslang::EOpSub; - spv::Id result = createBinaryOperation(op, TranslatePrecisionDecoration(node->getType()), + spv::Id result = createBinaryOperation(op, TranslatePrecisionDecoration(node->getType()), + TranslateNoContractionDecoration(node->getType().getQualifier()), convertGlslangToSpvType(node->getType()), operand, one, node->getType().getBasicType()); assert(result != spv::NoResult); - // Decorate this instruction, if this node has 'noContraction' qualifier. - addDecoration(result, TranslateNoContractionDecoration(node->getType().getQualifier())); // The result of operation is always stored, but conditionally the // consumed result. The consumed result is always an r-value. @@ -1350,7 +1342,7 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt break; } case glslang::EOpMul: - // compontent-wise matrix multiply + // compontent-wise matrix multiply binOp = glslang::EOpMul; break; case glslang::EOpOuterProduct: @@ -1359,7 +1351,7 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt break; case glslang::EOpDot: { - // for scalar dot product, use multiply + // for scalar dot product, use multiply glslang::TIntermSequence& glslangOperands = node->getSequence(); if (! glslangOperands[0]->getAsTyped()->isVector()) binOp = glslang::EOpMul; @@ -1414,8 +1406,8 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt right->traverse(this); spv::Id rightId = accessChainLoad(right->getType()); - result = createBinaryOperation(binOp, precision, - convertGlslangToSpvType(node->getType()), leftId, rightId, + result = createBinaryOperation(binOp, precision, TranslateNoContractionDecoration(node->getType().getQualifier()), + convertGlslangToSpvType(node->getType()), leftId, rightId, left->getType().getBasicType(), reduceComparison); // code above should only make binOp that exists in createBinaryOperation @@ -1488,7 +1480,11 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt result = createNoArgOperation(node->getOp()); break; case 1: - result = createUnaryOperation(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operands.front(), glslangOperands[0]->getAsTyped()->getBasicType()); + result = createUnaryOperation( + node->getOp(), precision, + TranslateNoContractionDecoration(node->getType().getQualifier()), + convertGlslangToSpvType(node->getType()), operands.front(), + glslangOperands[0]->getAsTyped()->getBasicType()); break; default: result = createMiscOperation(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operands, node->getBasicType()); @@ -1579,7 +1575,7 @@ bool TGlslangToSpvTraverser::visitSwitch(glslang::TVisit /* visit */, glslang::T codeSegments.push_back(child); } - // handle the case where the last code segment is missing, due to no code + // handle the case where the last code segment is missing, due to no code // statements between the last case and the end of the switch statement if ((caseValues.size() && (int)codeSegments.size() == valueIndexToSegment[caseValues.size() - 1]) || (int)codeSegments.size() == defaultSegment) @@ -1714,7 +1710,7 @@ bool TGlslangToSpvTraverser::visitBranch(glslang::TVisit /* visit */, glslang::T spv::Id TGlslangToSpvTraverser::createSpvVariable(const glslang::TIntermSymbol* node) { - // First, steer off constants, which are not SPIR-V variables, but + // First, steer off constants, which are not SPIR-V variables, but // can still have a mapping to a SPIR-V Id. // This includes specialization constants. if (node->getQualifier().isConstant()) { @@ -2018,7 +2014,7 @@ spv::Id TGlslangToSpvTraverser::makeArraySizeId(const glslang::TArraySizes& arra specNode->traverse(this); return accessChainLoad(specNode->getAsTyped()->getType()); } - + // Otherwise, need a compile-time (front end) size, get it: int size = arraySizes.getDimSize(dim); assert(size > 0); @@ -2165,7 +2161,7 @@ void TGlslangToSpvTraverser::updateMemberOffset(const glslang::TType& /*structTy // Getting this far means we need explicit offsets if (currentOffset < 0) currentOffset = 0; - + // Now, currentOffset is valid (either 0, or from a previous nextOffset), // but possibly not yet correctly aligned. @@ -2195,7 +2191,7 @@ void TGlslangToSpvTraverser::makeFunctions(const glslang::TIntermSequence& glslF // so that it's available to call. // Translating the body will happen later. // - // Typically (except for a "const in" parameter), an address will be passed to the + // Typically (except for a "const in" parameter), an address will be passed to the // function. What it is an address of varies: // // - "in" parameters not marked as "const" can be written to without modifying the argument, @@ -2265,7 +2261,7 @@ void TGlslangToSpvTraverser::visitFunctions(const glslang::TIntermSequence& glsl void TGlslangToSpvTraverser::handleFunctionEntry(const glslang::TIntermAggregate* node) { - // SPIR-V functions should already be in the functionMap from the prepass + // SPIR-V functions should already be in the functionMap from the prepass // that called makeFunctions(). spv::Function* function = functionMap[node->getName().c_str()]; spv::Block* functionBlock = function->getEntryBlock(); @@ -2679,7 +2675,8 @@ spv::Id TGlslangToSpvTraverser::handleUserFunctionCall(const glslang::TIntermAgg } // Translate AST operation to SPV operation, already having SPV-based operands/types. -spv::Id TGlslangToSpvTraverser::createBinaryOperation(glslang::TOperator op, spv::Decoration precision, +spv::Id TGlslangToSpvTraverser::createBinaryOperation(glslang::TOperator op, spv::Decoration precision, + spv::Decoration noContraction, spv::Id typeId, spv::Id left, spv::Id right, glslang::TBasicType typeProxy, bool reduceComparison) { @@ -2816,13 +2813,15 @@ spv::Id TGlslangToSpvTraverser::createBinaryOperation(glslang::TOperator op, spv if (binOp != spv::OpNop) { assert(comparison == false); if (builder.isMatrix(left) || builder.isMatrix(right)) - return createBinaryMatrixOperation(binOp, precision, typeId, left, right); + return createBinaryMatrixOperation(binOp, precision, noContraction, typeId, left, right); // No matrix involved; make both operands be the same number of components, if needed if (needMatchingVectors) builder.promoteScalar(precision, left, right); - return builder.setPrecision(builder.createBinOp(binOp, typeId, left, right), precision); + spv::Id result = builder.createBinOp(binOp, typeId, left, right); + addDecoration(result, noContraction); + return builder.setPrecision(result, precision); } if (! comparison) @@ -2891,8 +2890,11 @@ spv::Id TGlslangToSpvTraverser::createBinaryOperation(glslang::TOperator op, spv break; } - if (binOp != spv::OpNop) - return builder.setPrecision(builder.createBinOp(binOp, typeId, left, right), precision); + if (binOp != spv::OpNop) { + spv::Id result = builder.createBinOp(binOp, typeId, left, right); + addDecoration(result, noContraction); + return builder.setPrecision(result, precision); + } return 0; } @@ -2911,7 +2913,7 @@ spv::Id TGlslangToSpvTraverser::createBinaryOperation(glslang::TOperator op, spv // matrix op scalar op in {+, -, /} // scalar op matrix op in {+, -, /} // -spv::Id TGlslangToSpvTraverser::createBinaryMatrixOperation(spv::Op op, spv::Decoration precision, spv::Id typeId, spv::Id left, spv::Id right) +spv::Id TGlslangToSpvTraverser::createBinaryMatrixOperation(spv::Op op, spv::Decoration precision, spv::Decoration noContraction, spv::Id typeId, spv::Id left, spv::Id right) { bool firstClass = true; @@ -2947,8 +2949,11 @@ spv::Id TGlslangToSpvTraverser::createBinaryMatrixOperation(spv::Op op, spv::Dec break; } - if (firstClass) - return builder.setPrecision(builder.createBinOp(op, typeId, left, right), precision); + if (firstClass) { + spv::Id result = builder.createBinOp(op, typeId, left, right); + addDecoration(result, noContraction); + return builder.setPrecision(result, precision); + } // Handle component-wise +, -, *, and / for all combinations of type. // The result type of all of them is the same type as the (a) matrix operand. @@ -2983,8 +2988,9 @@ spv::Id TGlslangToSpvTraverser::createBinaryMatrixOperation(spv::Op op, spv::Dec indexes.push_back(c); spv::Id leftVec = leftMat ? builder.createCompositeExtract( left, vecType, indexes) : smearVec; spv::Id rightVec = rightMat ? builder.createCompositeExtract(right, vecType, indexes) : smearVec; - results.push_back(builder.createBinOp(op, vecType, leftVec, rightVec)); - builder.setPrecision(results.back(), precision); + spv::Id result = builder.createBinOp(op, vecType, leftVec, rightVec); + addDecoration(result, noContraction); + results.push_back(builder.setPrecision(result, precision)); } // put the pieces together @@ -2996,7 +3002,7 @@ spv::Id TGlslangToSpvTraverser::createBinaryMatrixOperation(spv::Op op, spv::Dec } } -spv::Id TGlslangToSpvTraverser::createUnaryOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, spv::Id operand, glslang::TBasicType typeProxy) +spv::Id TGlslangToSpvTraverser::createUnaryOperation(glslang::TOperator op, spv::Decoration precision, spv::Decoration noContraction, spv::Id typeId, spv::Id operand, glslang::TBasicType typeProxy) { spv::Op unaryOp = spv::OpNop; int libCall = -1; @@ -3008,7 +3014,7 @@ spv::Id TGlslangToSpvTraverser::createUnaryOperation(glslang::TOperator op, spv: if (isFloat) { unaryOp = spv::OpFNegate; if (builder.isMatrixType(typeId)) - return createUnaryMatrixOperation(unaryOp, precision, typeId, operand, typeProxy); + return createUnaryMatrixOperation(unaryOp, precision, noContraction, typeId, operand, typeProxy); } else unaryOp = spv::OpSNegate; break; @@ -3290,11 +3296,12 @@ spv::Id TGlslangToSpvTraverser::createUnaryOperation(glslang::TOperator op, spv: id = builder.createUnaryOp(unaryOp, typeId, operand); } + addDecoration(id, noContraction); return builder.setPrecision(id, precision); } // Create a unary operation on a matrix -spv::Id TGlslangToSpvTraverser::createUnaryMatrixOperation(spv::Op op, spv::Decoration precision, spv::Id typeId, spv::Id operand, glslang::TBasicType /* typeProxy */) +spv::Id TGlslangToSpvTraverser::createUnaryMatrixOperation(spv::Op op, spv::Decoration precision, spv::Decoration noContraction, spv::Id typeId, spv::Id operand, glslang::TBasicType /* typeProxy */) { // Handle unary operations vector by vector. // The result type is the same type as the original type. @@ -3315,8 +3322,9 @@ spv::Id TGlslangToSpvTraverser::createUnaryMatrixOperation(spv::Op op, spv::Deco std::vector indexes; indexes.push_back(c); spv::Id vec = builder.createCompositeExtract(operand, vecType, indexes); - results.push_back(builder.createUnaryOp(op, vecType, vec)); - builder.setPrecision(results.back(), precision); + spv::Id vec_result = builder.createUnaryOp(op, vecType, vec); + addDecoration(vec_result, noContraction); + results.push_back(builder.setPrecision(vec_result, precision)); } // put the pieces together @@ -4144,7 +4152,7 @@ bool TGlslangToSpvTraverser::isTrivialLeaf(const glslang::TIntermTyped* node) default: return false; } -} +} // A node is trivial if it is a single operation with no side effects. // Error on the side of saying non-trivial. diff --git a/glslang/MachineIndependent/propagateNoContraction.cpp b/glslang/MachineIndependent/propagateNoContraction.cpp index fa2b62a9..f4b88d16 100644 --- a/glslang/MachineIndependent/propagateNoContraction.cpp +++ b/glslang/MachineIndependent/propagateNoContraction.cpp @@ -47,18 +47,27 @@ #include "localintermediate.h" namespace { -// Use string to hold the accesschain information, as in most cases we the -// accesschain is short and may contain only one element, which is the symbol ID. +// Use string to hold the accesschain information, as in most cases the +// accesschain is short and may contain only one element, which is the symbol +// ID. +// Example: struct {float a; float b;} s; +// Object s.a will be represented with: /0 +// Object s.b will be represented with: /1 +// Object s will be representend with: +// For members of vector, matrix and arrays, they will be represented with the +// same symbol ID of their container symbol objects. This is because their +// precise'ness is always the same as their container symbol objects. using ObjectAccessChain = std::string; -#ifndef StructAccessChainDelimiter -#define StructAccessChainDelimiter '/' -#endif + +// The delimiter used in the ObjectAccessChain string to separate symbol ID and +// different level of struct indices. +const char OBJECT_ACCESSCHAIN_DELIMITER = '/'; // Mapping from Symbol IDs of symbol nodes, to their defining operation // nodes. -using NodeMapping = std::unordered_multimap; +using NodeMapping = std::unordered_multimap; // Mapping from object nodes to their accesschain info string. -using AccessChainMapping = std::unordered_map; +using AccessChainMapping = std::unordered_map; // Set of object IDs. using ObjectAccesschainSet = std::unordered_set; @@ -67,7 +76,7 @@ using ReturnBranchNodeSet = std::unordered_set; // A helper function to tell whether a node is 'noContraction'. Returns true if // the node has 'noContraction' qualifier, otherwise false. -bool isPreciseObjectNode(glslang::TIntermTyped *node) +bool isPreciseObjectNode(glslang::TIntermTyped* node) { return node->getType().getQualifier().noContraction; } @@ -118,7 +127,7 @@ bool isAssignOperation(glslang::TOperator op) // A helper function to get the unsigned int from a given constant union node. // Note the node should only holds a uint scalar. -unsigned getStructIndexFromConstantUnion(glslang::TIntermTyped *node) +unsigned getStructIndexFromConstantUnion(glslang::TIntermTyped* node) { assert(node->getAsConstantUnion() && node->getAsConstantUnion()->isScalar()); unsigned struct_dereference_index = node->getAsConstantUnion()->getConstArray()[0].getUConst(); @@ -126,9 +135,10 @@ unsigned getStructIndexFromConstantUnion(glslang::TIntermTyped *node) } // A helper function to generate symbol_label. -ObjectAccessChain generateSymbolLabel(glslang::TIntermSymbol *node) +ObjectAccessChain generateSymbolLabel(glslang::TIntermSymbol* node) { - ObjectAccessChain symbol_id = std::to_string(node->getId()) + "(" + node->getName().c_str() + ")"; + ObjectAccessChain symbol_id = + std::to_string(node->getId()) + "(" + node->getName().c_str() + ")"; return symbol_id; } @@ -180,43 +190,41 @@ bool isArithmeticOperation(glslang::TOperator op) // A helper class to help managing populating_initial_no_contraction_ flag. template class StateSettingGuard { public: - StateSettingGuard(T *state_ptr, T new_state_value) + StateSettingGuard(T* state_ptr, T new_state_value) : state_ptr_(state_ptr), previous_state_(*state_ptr) { *state_ptr = new_state_value; } - StateSettingGuard(T *state_ptr) : state_ptr_(state_ptr), previous_state_(*state_ptr) {} - void setState(T new_state_value) - { - *state_ptr_ = new_state_value; - } + StateSettingGuard(T* state_ptr) : state_ptr_(state_ptr), previous_state_(*state_ptr) {} + void setState(T new_state_value) { *state_ptr_ = new_state_value; } ~StateSettingGuard() { *state_ptr_ = previous_state_; } private: - T *state_ptr_; + T* state_ptr_; T previous_state_; }; // A helper function to get the front element from a given ObjectAccessChain -ObjectAccessChain getFrontElement(const ObjectAccessChain &chain) +ObjectAccessChain getFrontElement(const ObjectAccessChain& chain) { - size_t pos_delimiter = chain.find(StructAccessChainDelimiter); + size_t pos_delimiter = chain.find(OBJECT_ACCESSCHAIN_DELIMITER); return pos_delimiter == std::string::npos ? chain : chain.substr(0, pos_delimiter); } // A helper function to get the accesschain starting from the second element. ObjectAccessChain subAccessChainFromSecondElement(const ObjectAccessChain& chain) { - size_t pos_delimiter = chain.find(StructAccessChainDelimiter); + size_t pos_delimiter = chain.find(OBJECT_ACCESSCHAIN_DELIMITER); return pos_delimiter == std::string::npos ? "" : chain.substr(pos_delimiter + 1); } // A helper function to get the accesschain after removing a given prefix. -ObjectAccessChain getSubAccessChainAfterPrefix(const ObjectAccessChain &chain, const ObjectAccessChain &prefix) +ObjectAccessChain getSubAccessChainAfterPrefix(const ObjectAccessChain& chain, + const ObjectAccessChain& prefix) { size_t pos = chain.find(prefix); if (pos != 0) return chain; - return chain.substr(prefix.length() + sizeof(StructAccessChainDelimiter)); + return chain.substr(prefix.length() + sizeof(OBJECT_ACCESSCHAIN_DELIMITER)); } // @@ -226,34 +234,33 @@ ObjectAccessChain getSubAccessChainAfterPrefix(const ObjectAccessChain &chain, c // class TSymbolDefinitionCollectingTraverser : public glslang::TIntermTraverser { public: - TSymbolDefinitionCollectingTraverser( - NodeMapping *symbol_definition_mapping, AccessChainMapping *accesschain_mapping, - ObjectAccesschainSet *precise_objects, - ReturnBranchNodeSet *precise_return_nodes); + TSymbolDefinitionCollectingTraverser(NodeMapping* symbol_definition_mapping, + AccessChainMapping* accesschain_mapping, + ObjectAccesschainSet* precise_objects, + ReturnBranchNodeSet* precise_return_nodes); - // bool visitAggregate(glslang::TVisit, glslang::TIntermAggregate *) override; - bool visitUnary(glslang::TVisit, glslang::TIntermUnary *) override; - bool visitBinary(glslang::TVisit, glslang::TIntermBinary *) override; - void visitSymbol(glslang::TIntermSymbol *) override; - bool visitAggregate(glslang::TVisit, glslang::TIntermAggregate *) override; - bool visitBranch(glslang::TVisit, glslang::TIntermBranch *) override; + bool visitUnary(glslang::TVisit, glslang::TIntermUnary*) override; + bool visitBinary(glslang::TVisit, glslang::TIntermBinary*) override; + void visitSymbol(glslang::TIntermSymbol*) override; + bool visitAggregate(glslang::TVisit, glslang::TIntermAggregate*) override; + bool visitBranch(glslang::TVisit, glslang::TIntermBranch*) override; protected: // The mapping from symbol node IDs to their defining nodes. This should be // populated along traversing the AST. - NodeMapping &symbol_definition_mapping_; + NodeMapping& symbol_definition_mapping_; // The set of symbol node IDs for precise symbol nodes, the ones marked as // 'noContraction'. - ObjectAccesschainSet &precise_objects_; + ObjectAccesschainSet& precise_objects_; // The set of precise return nodes. - ReturnBranchNodeSet &precise_return_nodes_; + ReturnBranchNodeSet& precise_return_nodes_; // A temporary cache of the symbol node whose defining node is to be found // currently along traversing the AST. ObjectAccessChain object_to_be_defined_; // A map from object node to its accesschain. This traverser stores // the built accesschains into this map for each object node it has // visited. - AccessChainMapping &accesschain_mapping_; + AccessChainMapping& accesschain_mapping_; // The pointer to the Function Definition node, so we can get the // precise'ness of the return expression from it when we traverse the // return branch node. @@ -261,9 +268,9 @@ protected: }; TSymbolDefinitionCollectingTraverser::TSymbolDefinitionCollectingTraverser( - NodeMapping *symbol_definition_mapping, AccessChainMapping *accesschain_mapping, - ObjectAccesschainSet *precise_objects, - std::unordered_set *precise_return_nodes) + NodeMapping* symbol_definition_mapping, AccessChainMapping* accesschain_mapping, + ObjectAccesschainSet* precise_objects, + std::unordered_set* precise_return_nodes) : TIntermTraverser(true, false, false), symbol_definition_mapping_(*symbol_definition_mapping), precise_objects_(*precise_objects), object_to_be_defined_(), accesschain_mapping_(*accesschain_mapping), current_function_definition_node_(nullptr), @@ -273,7 +280,7 @@ TSymbolDefinitionCollectingTraverser::TSymbolDefinitionCollectingTraverser( // current node symbol ID, and record a mapping from this node to the current // object_to_be_defined_, which is the just obtained symbol // ID. -void TSymbolDefinitionCollectingTraverser::visitSymbol(glslang::TIntermSymbol *node) +void TSymbolDefinitionCollectingTraverser::visitSymbol(glslang::TIntermSymbol* node) { object_to_be_defined_ = generateSymbolLabel(node); accesschain_mapping_[node] = object_to_be_defined_; @@ -281,12 +288,12 @@ void TSymbolDefinitionCollectingTraverser::visitSymbol(glslang::TIntermSymbol *n // Visits an aggregate node, traverses all of its children. bool TSymbolDefinitionCollectingTraverser::visitAggregate(glslang::TVisit, - glslang::TIntermAggregate *node) + glslang::TIntermAggregate* node) { // This aggreagate node might be a function definition node, in which case we need to // cache this node, so we can get the precise'ness information of the return value // of this function later. - StateSettingGuard current_function_definition_node_setting_guard( + StateSettingGuard current_function_definition_node_setting_guard( ¤t_function_definition_node_); if (node->getOp() == glslang::EOpFunction) { // This is function definition node, we need to cache this node so that we can @@ -294,7 +301,7 @@ bool TSymbolDefinitionCollectingTraverser::visitAggregate(glslang::TVisit, current_function_definition_node_setting_guard.setState(node); } // Traverse the items in the sequence. - glslang::TIntermSequence &seq = node->getSequence(); + glslang::TIntermSequence& seq = node->getSequence(); for (int i = 0; i < (int)seq.size(); ++i) { object_to_be_defined_.clear(); seq[i]->traverse(this); @@ -303,7 +310,7 @@ bool TSymbolDefinitionCollectingTraverser::visitAggregate(glslang::TVisit, } bool TSymbolDefinitionCollectingTraverser::visitBranch(glslang::TVisit, - glslang::TIntermBranch *node) + glslang::TIntermBranch* node) { if (node->getFlowOp() == glslang::EOpReturn && node->getExpression() && current_function_definition_node_ && @@ -319,7 +326,7 @@ bool TSymbolDefinitionCollectingTraverser::visitBranch(glslang::TVisit, // Visits an unary node. This might be an implicit assignment like i++, i--. etc. bool TSymbolDefinitionCollectingTraverser::visitUnary(glslang::TVisit /* visit */, - glslang::TIntermUnary *node) + glslang::TIntermUnary* node) { object_to_be_defined_.clear(); node->getOperand()->traverse(this); @@ -351,7 +358,7 @@ bool TSymbolDefinitionCollectingTraverser::visitUnary(glslang::TVisit /* visit * // Visits a binary node and updates the mapping from symbol IDs to the definition // nodes. Also collects the accesschains for the initial precise objects. bool TSymbolDefinitionCollectingTraverser::visitBinary(glslang::TVisit /* visit */, - glslang::TIntermBinary *node) + glslang::TIntermBinary* node) { // Traverses the left node to build the accesschain info for the object. object_to_be_defined_.clear(); @@ -408,7 +415,7 @@ bool TSymbolDefinitionCollectingTraverser::visitBinary(glslang::TVisit /* visit // object. We need to record the accesschain information of the current // node into its object id. unsigned struct_dereference_index = getStructIndexFromConstantUnion(node->getRight()); - object_to_be_defined_.push_back(StructAccessChainDelimiter); + object_to_be_defined_.push_back(OBJECT_ACCESSCHAIN_DELIMITER); object_to_be_defined_.append(std::to_string(struct_dereference_index)); accesschain_mapping_[node] = object_to_be_defined_; @@ -428,17 +435,18 @@ bool TSymbolDefinitionCollectingTraverser::visitBinary(glslang::TVisit /* visit // 2) a mapping from object nodes in the AST to the accesschains of these objects. // 3) a set of accesschains of precise objects. std::tuple -getSymbolToDefinitionMappingAndPreciseSymbolIDs(const glslang::TIntermediate &intermediate) +getSymbolToDefinitionMappingAndPreciseSymbolIDs(const glslang::TIntermediate& intermediate) { - auto result_tuple = std::make_tuple(NodeMapping(), AccessChainMapping(), ObjectAccesschainSet(), ReturnBranchNodeSet()); + auto result_tuple = std::make_tuple(NodeMapping(), AccessChainMapping(), ObjectAccesschainSet(), + ReturnBranchNodeSet()); - TIntermNode *root = intermediate.getTreeRoot(); + TIntermNode* root = intermediate.getTreeRoot(); if (root == 0) return result_tuple; - NodeMapping &symbol_definition_mapping = std::get<0>(result_tuple); - AccessChainMapping &accesschain_mapping = std::get<1>(result_tuple); - ObjectAccesschainSet &precise_objects = std::get<2>(result_tuple); - ReturnBranchNodeSet &precise_return_nodes = std::get<3>(result_tuple); + NodeMapping& symbol_definition_mapping = std::get<0>(result_tuple); + AccessChainMapping& accesschain_mapping = std::get<1>(result_tuple); + ObjectAccesschainSet& precise_objects = std::get<2>(result_tuple); + ReturnBranchNodeSet& precise_return_nodes = std::get<3>(result_tuple); // Traverses the AST and populate the results. TSymbolDefinitionCollectingTraverser collector(&symbol_definition_mapping, &accesschain_mapping, @@ -474,7 +482,7 @@ class TNoContractionAssigneeCheckingTraverser : public glslang::TIntermTraverser }; public: - TNoContractionAssigneeCheckingTraverser(const AccessChainMapping &accesschain_mapping) + TNoContractionAssigneeCheckingTraverser(const AccessChainMapping& accesschain_mapping) : TIntermTraverser(true, false, false), accesschain_mapping_(accesschain_mapping), precise_object_(nullptr) {} @@ -494,7 +502,7 @@ public: // precise object. std::tuple getPrecisenessAndRemainedAccessChain(glslang::TIntermOperator* node, - const ObjectAccessChain &precise_object) + const ObjectAccessChain& precise_object) { assert(isAssignOperation(node->getOp())); precise_object_ = &precise_object; @@ -570,23 +578,23 @@ public: } protected: - bool visitBinary(glslang::TVisit, glslang::TIntermBinary *node) override; - void visitSymbol(glslang::TIntermSymbol *node) override; + bool visitBinary(glslang::TVisit, glslang::TIntermBinary* node) override; + void visitSymbol(glslang::TIntermSymbol* node) override; // A map from object nodes to their accesschain string (used as object ID). - const AccessChainMapping &accesschain_mapping_; + const AccessChainMapping& accesschain_mapping_; // A given precise object, represented in it accesschain string. This // precise object is used to be compared with the assignee node to tell if // the assignee node is 'precise', contains 'precise' object or not // 'precise'. - const ObjectAccessChain *precise_object_; + const ObjectAccessChain* precise_object_; }; // Visit a binary node. If the node is an object node, it must be a dereference // node. In such cases, if the left node is 'precise', this node should also be // 'precise'. bool TNoContractionAssigneeCheckingTraverser::visitBinary(glslang::TVisit, - glslang::TIntermBinary *node) + glslang::TIntermBinary* node) { // Traverses the left so that we transfer the 'precise' from nesting object // to its nested object. @@ -602,7 +610,7 @@ bool TNoContractionAssigneeCheckingTraverser::visitBinary(glslang::TVisit, // this node should be marked as 'precise'. if (isPreciseObjectNode(node->getLeft())) { node->getWritableType().getQualifier().noContraction = true; - } else if (accesschain_mapping_.at(node) == *precise_object_){ + } else if (accesschain_mapping_.at(node) == *precise_object_) { node->getWritableType().getQualifier().noContraction = true; } } @@ -611,7 +619,7 @@ bool TNoContractionAssigneeCheckingTraverser::visitBinary(glslang::TVisit, // Visit a symbol node, if the symbol node ID (its accesschain string) matches // with the given precise object, this node should be 'precise'. -void TNoContractionAssigneeCheckingTraverser::visitSymbol(glslang::TIntermSymbol *node) +void TNoContractionAssigneeCheckingTraverser::visitSymbol(glslang::TIntermSymbol* node) { // A symbol node should always be an object node, and should have been added // to the map from object nodes to their accesschain strings. @@ -632,27 +640,27 @@ void TNoContractionAssigneeCheckingTraverser::visitSymbol(glslang::TIntermSymbol // class TNoContractionPropagator : public glslang::TIntermTraverser { public: - TNoContractionPropagator(ObjectAccesschainSet *precise_objects, - const AccessChainMapping &accesschain_mapping) + TNoContractionPropagator(ObjectAccesschainSet* precise_objects, + const AccessChainMapping& accesschain_mapping) : TIntermTraverser(true, false, false), remained_accesschain_(), - precise_objects_(*precise_objects), - accesschain_mapping_(accesschain_mapping), added_precise_object_ids_() {} + precise_objects_(*precise_objects), accesschain_mapping_(accesschain_mapping), + added_precise_object_ids_() {} // Propagates 'precise' in the right nodes of a given assignment node with // accesschain record from the assignee node to a 'precise' object it // contains. void - propagateNoContractionInOneExpression(glslang::TIntermTyped *defining_node, - const ObjectAccessChain &assignee_remained_accesschain) + propagateNoContractionInOneExpression(glslang::TIntermTyped* defining_node, + const ObjectAccessChain& assignee_remained_accesschain) { remained_accesschain_ = assignee_remained_accesschain; - if (glslang::TIntermBinary *BN = defining_node->getAsBinaryNode()) { + if (glslang::TIntermBinary* BN = defining_node->getAsBinaryNode()) { assert(isAssignOperation(BN->getOp())); BN->getRight()->traverse(this); if (isArithmeticOperation(BN->getOp())) { BN->getWritableType().getQualifier().noContraction = true; } - } else if (glslang::TIntermUnary *UN = defining_node->getAsUnaryNode()) { + } else if (glslang::TIntermUnary* UN = defining_node->getAsUnaryNode()) { assert(isAssignOperation(UN->getOp())); UN->getOperand()->traverse(this); if (isArithmeticOperation(UN->getOp())) { @@ -662,8 +670,7 @@ public: } // Propagates 'precise' in a given precise return node. - void - propagateNoContractionInReturnNode(glslang::TIntermBranch *return_node) + void propagateNoContractionInReturnNode(glslang::TIntermBranch* return_node) { remained_accesschain_ = ""; assert(return_node->getFlowOp() == glslang::EOpReturn && return_node->getExpression()); @@ -675,7 +682,7 @@ protected: // case we need to find the 'precise' or 'precise' containing object node // with the accesschain record. In other cases, just need to traverse all // the children nodes. - bool visitAggregate(glslang::TVisit, glslang::TIntermAggregate *node) override + bool visitAggregate(glslang::TVisit, glslang::TIntermAggregate* node) override { if (!remained_accesschain_.empty() && node->getOp() == glslang::EOpConstructStruct) { // This is a struct initializer node, and the remained @@ -689,7 +696,7 @@ protected: getFrontElement(remained_accesschain_); unsigned precise_accesschain_index = std::stoul(precise_accesschain_index_str); // Gets the node pointed by the accesschain index extracted before. - glslang::TIntermTyped *potential_precise_node = + glslang::TIntermTyped* potential_precise_node = node->getSequence()[precise_accesschain_index]->getAsTyped(); assert(potential_precise_node); // Pop the front accesschain index from the path, and visit the nested node. @@ -700,16 +707,9 @@ protected: &remained_accesschain_, next_level_accesschain); potential_precise_node->traverse(this); } - - } else { - // If this is not a struct constructor, just visit each nested node. - glslang::TIntermSequence &seq = node->getSequence(); - for (int i = 0; i < (int)seq.size(); ++i) { - seq[i]->traverse(this); - } + return false; } - - return false; + return true; } // Visit a binary node. A binary node can be an object node, e.g. a dereference node. @@ -718,7 +718,7 @@ protected: // an object node. If the binary node does not represent an object node, it should // go on to traverse its children nodes and if it is an arithmetic operation node, this // operation should be marked as 'noContraction'. - bool visitBinary(glslang::TVisit, glslang::TIntermBinary *node) override + bool visitBinary(glslang::TVisit, glslang::TIntermBinary* node) override { if (isDereferenceOperation(node->getOp())) { // This binary node is an object node. Need to update the precise @@ -728,8 +728,7 @@ protected: if (remained_accesschain_.empty()) { node->getWritableType().getQualifier().noContraction = true; } else { - new_precise_accesschain += - StructAccessChainDelimiter + remained_accesschain_; + new_precise_accesschain += OBJECT_ACCESSCHAIN_DELIMITER + remained_accesschain_; } // Cache the accesschain as added precise object, so we won't add the // same object to the worklist again. @@ -746,21 +745,18 @@ protected: node->getWritableType().getQualifier().noContraction = true; } // As this node is not an object node, need to traverse the children nodes. - node->getLeft()->traverse(this); - node->getRight()->traverse(this); - return false; + return true; } // Visits an unary node. An unary node can not be an object node. If the operation // is an arithmetic operation, need to mark this node as 'noContraction'. - bool visitUnary(glslang::TVisit /* visit */, glslang::TIntermUnary *node) override + bool visitUnary(glslang::TVisit /* visit */, glslang::TIntermUnary* node) override { // If this is an arithmetic operation, marks this with 'noContraction' if (isArithmeticOperation(node->getOp())) { node->getWritableType().getQualifier().noContraction = true; } - node->getOperand()->traverse(this); - return false; + return true; } // Visits a symbol node. A symbol node is always an object node. So we @@ -768,7 +764,7 @@ protected: // nodes to accesschains. As an object node, a symbol node can be either // 'precise' or containing 'precise' objects according to unused // accesschain information we have when we visit this node. - void visitSymbol(glslang::TIntermSymbol *node) override + void visitSymbol(glslang::TIntermSymbol* node) override { // Symbol nodes are object nodes and should always have an // accesschain collected before matches with it. @@ -781,7 +777,7 @@ protected: if (remained_accesschain_.empty()) { node->getWritableType().getQualifier().noContraction = true; } else { - new_precise_accesschain += StructAccessChainDelimiter + remained_accesschain_; + new_precise_accesschain += OBJECT_ACCESSCHAIN_DELIMITER + remained_accesschain_; } // Add the new 'precise' accesschain to the worklist and make sure we // don't visit it again. @@ -792,7 +788,7 @@ protected: } // A set of precise objects, represented as accesschains. - ObjectAccesschainSet &precise_objects_; + ObjectAccesschainSet& precise_objects_; // Visited symbol nodes, should not revisit these nodes. ObjectAccesschainSet added_precise_object_ids_; // The left node of an assignment operation might be an parent of 'precise' objects. @@ -802,15 +798,13 @@ protected: // tell us how to find the corresponding 'precise' node in the right. ObjectAccessChain remained_accesschain_; // A map from node pointers to their accesschains. - const AccessChainMapping &accesschain_mapping_; + const AccessChainMapping& accesschain_mapping_; }; - -#undef StructAccessChainDelimiter } namespace glslang { -void PropagateNoContraction(const glslang::TIntermediate &intermediate) +void PropagateNoContraction(const glslang::TIntermediate& intermediate) { // First, traverses the AST, records symbols with their defining operations // and collects the initial set of precise symbols (symbol nodes that marked @@ -821,18 +815,17 @@ void PropagateNoContraction(const glslang::TIntermediate &intermediate) // The mapping of symbol node IDs to their defining nodes. This enables us // to get the defining node directly from a given symbol ID without // traversing the tree again. - NodeMapping &symbol_definition_mapping = std::get<0>(mappings_and_precise_objects); + NodeMapping& symbol_definition_mapping = std::get<0>(mappings_and_precise_objects); // The mapping of object nodes to their accesschains recorded. - AccessChainMapping &accesschain_mapping = std::get<1>(mappings_and_precise_objects); + AccessChainMapping& accesschain_mapping = std::get<1>(mappings_and_precise_objects); // The initial set of 'precise' objects which are represented as the // accesschain toward them. - ObjectAccesschainSet &precise_object_accesschains = - std::get<2>(mappings_and_precise_objects); + ObjectAccesschainSet& precise_object_accesschains = std::get<2>(mappings_and_precise_objects); // The set of 'precise' return nodes. - ReturnBranchNodeSet &precise_return_nodes = std::get<3>(mappings_and_precise_objects); + ReturnBranchNodeSet& precise_return_nodes = std::get<3>(mappings_and_precise_objects); // Second, uses the initial set of precise objects as a worklist, pops an // accesschain, extract the symbol ID from it. Then: @@ -845,10 +838,9 @@ void PropagateNoContraction(const glslang::TIntermediate &intermediate) // 'precise' accesschain worklist with new found object nodes. // Repeat above steps until the worklist is empty. TNoContractionAssigneeCheckingTraverser checker(accesschain_mapping); - TNoContractionPropagator propagator(&precise_object_accesschains, - accesschain_mapping); + TNoContractionPropagator propagator(&precise_object_accesschains, accesschain_mapping); - // We have to initial precise worklist to handle: + // We have two initial precise worklists to handle: // 1) precise return nodes // 2) precise object accesschains // We should process the precise return nodes first and the involved @@ -877,12 +869,12 @@ void PropagateNoContraction(const glslang::TIntermediate &intermediate) // objects, and mark arithmetic operations as 'noContraction'. for (NodeMapping::iterator defining_node_iter = range.first; defining_node_iter != range.second; defining_node_iter++) { - TIntermOperator *defining_node = defining_node_iter->second; + TIntermOperator* defining_node = defining_node_iter->second; // Check the assignee node. auto checker_result = checker.getPrecisenessAndRemainedAccessChain( defining_node, precise_object_accesschain); - bool &contain_precise = std::get<0>(checker_result); - ObjectAccessChain &remained_accesschain = std::get<1>(checker_result); + bool& contain_precise = std::get<0>(checker_result); + ObjectAccessChain& remained_accesschain = std::get<1>(checker_result); // If the assignee node is 'precise' or contains 'precise', propagate the // 'precise' to the right. Otherwise just skip this assignment node. if (contain_precise) { From 0c96db5a4ca3b50655c7500a2e44c324da56f613 Mon Sep 17 00:00:00 2001 From: qining Date: Fri, 6 May 2016 18:56:33 -0400 Subject: [PATCH 5/9] add a test for matrix, fix a variable name --- Test/baseResults/precise.tesc.out | 52 ++++++++++++++++++- Test/precise.tesc | 7 +++ .../propagateNoContraction.cpp | 15 +++--- 3 files changed, 65 insertions(+), 9 deletions(-) diff --git a/Test/baseResults/precise.tesc.out b/Test/baseResults/precise.tesc.out index 4976b9cb..a6b10adf 100644 --- a/Test/baseResults/precise.tesc.out +++ b/Test/baseResults/precise.tesc.out @@ -357,8 +357,32 @@ vertices = -1 0:99 subtract (temp float) 0:99 'a' (temp float) 0:99 'b' (in float) -0:102 Function Definition: main( (global void) +0:102 Function Definition: matrix(mf23;mf32; (global 3X3 matrix of float) 0:102 Function Parameters: +0:102 'a' (in 2X3 matrix of float) +0:102 'b' (in 3X2 matrix of float) +0:103 Sequence +0:103 Sequence +0:103 move second child to first child (temp 2X3 matrix of float) +0:103 'c' (noContraction temp 2X3 matrix of float) +0:103 Constant: +0:103 1.000000 +0:103 2.000000 +0:103 3.000000 +0:103 4.000000 +0:103 5.000000 +0:103 6.000000 +0:105 move second child to first child (temp 3X3 matrix of float) +0:105 'result' (noContraction temp 3X3 matrix of float) +0:105 matrix-multiply (noContraction temp 3X3 matrix of float) +0:105 add (noContraction temp 2X3 matrix of float) +0:105 'a' (noContraction in 2X3 matrix of float) +0:105 'c' (noContraction temp 2X3 matrix of float) +0:105 'b' (noContraction in 3X2 matrix of float) +0:106 Branch: Return with expression +0:106 'result' (noContraction temp 3X3 matrix of float) +0:109 Function Definition: main( (global void) +0:109 Function Parameters: 0:? Linker Objects @@ -722,7 +746,31 @@ vertices = -1 0:99 subtract (temp float) 0:99 'a' (temp float) 0:99 'b' (in float) -0:102 Function Definition: main( (global void) +0:102 Function Definition: matrix(mf23;mf32; (global 3X3 matrix of float) 0:102 Function Parameters: +0:102 'a' (in 2X3 matrix of float) +0:102 'b' (in 3X2 matrix of float) +0:103 Sequence +0:103 Sequence +0:103 move second child to first child (temp 2X3 matrix of float) +0:103 'c' (noContraction temp 2X3 matrix of float) +0:103 Constant: +0:103 1.000000 +0:103 2.000000 +0:103 3.000000 +0:103 4.000000 +0:103 5.000000 +0:103 6.000000 +0:105 move second child to first child (temp 3X3 matrix of float) +0:105 'result' (noContraction temp 3X3 matrix of float) +0:105 matrix-multiply (noContraction temp 3X3 matrix of float) +0:105 add (noContraction temp 2X3 matrix of float) +0:105 'a' (noContraction in 2X3 matrix of float) +0:105 'c' (noContraction temp 2X3 matrix of float) +0:105 'b' (noContraction in 3X2 matrix of float) +0:106 Branch: Return with expression +0:106 'result' (noContraction temp 3X3 matrix of float) +0:109 Function Definition: main( (global void) +0:109 Function Parameters: 0:? Linker Objects diff --git a/Test/precise.tesc b/Test/precise.tesc index 71a71e48..b4ac5795 100644 --- a/Test/precise.tesc +++ b/Test/precise.tesc @@ -99,4 +99,11 @@ float precise_func_parameter(float b, precise out float c) { return a - b; // Not noContraction } +mat3 matrix (mat2x3 a, mat3x2 b) { + mat2x3 c = mat2x3(1.0, 2.0, 3.0, 4.0, 5.0, 6.0); + precise mat3 result; + result = (a + c) * b; // should be noContraction + return result; +} + void main(){} diff --git a/glslang/MachineIndependent/propagateNoContraction.cpp b/glslang/MachineIndependent/propagateNoContraction.cpp index f4b88d16..be53ea31 100644 --- a/glslang/MachineIndependent/propagateNoContraction.cpp +++ b/glslang/MachineIndependent/propagateNoContraction.cpp @@ -61,7 +61,7 @@ using ObjectAccessChain = std::string; // The delimiter used in the ObjectAccessChain string to separate symbol ID and // different level of struct indices. -const char OBJECT_ACCESSCHAIN_DELIMITER = '/'; +const char ObjectAccesschainDelimiter = '/'; // Mapping from Symbol IDs of symbol nodes, to their defining operation // nodes. @@ -169,6 +169,7 @@ bool isArithmeticOperation(glslang::TOperator op) case glslang::EOpVectorTimesMatrix: case glslang::EOpMatrixTimesVector: case glslang::EOpMatrixTimesScalar: + case glslang::EOpMatrixTimesMatrix: case glslang::EOpDot: @@ -207,14 +208,14 @@ private: // A helper function to get the front element from a given ObjectAccessChain ObjectAccessChain getFrontElement(const ObjectAccessChain& chain) { - size_t pos_delimiter = chain.find(OBJECT_ACCESSCHAIN_DELIMITER); + size_t pos_delimiter = chain.find(ObjectAccesschainDelimiter); return pos_delimiter == std::string::npos ? chain : chain.substr(0, pos_delimiter); } // A helper function to get the accesschain starting from the second element. ObjectAccessChain subAccessChainFromSecondElement(const ObjectAccessChain& chain) { - size_t pos_delimiter = chain.find(OBJECT_ACCESSCHAIN_DELIMITER); + size_t pos_delimiter = chain.find(ObjectAccesschainDelimiter); return pos_delimiter == std::string::npos ? "" : chain.substr(pos_delimiter + 1); } @@ -224,7 +225,7 @@ ObjectAccessChain getSubAccessChainAfterPrefix(const ObjectAccessChain& chain, { size_t pos = chain.find(prefix); if (pos != 0) return chain; - return chain.substr(prefix.length() + sizeof(OBJECT_ACCESSCHAIN_DELIMITER)); + return chain.substr(prefix.length() + sizeof(ObjectAccesschainDelimiter)); } // @@ -415,7 +416,7 @@ bool TSymbolDefinitionCollectingTraverser::visitBinary(glslang::TVisit /* visit // object. We need to record the accesschain information of the current // node into its object id. unsigned struct_dereference_index = getStructIndexFromConstantUnion(node->getRight()); - object_to_be_defined_.push_back(OBJECT_ACCESSCHAIN_DELIMITER); + object_to_be_defined_.push_back(ObjectAccesschainDelimiter); object_to_be_defined_.append(std::to_string(struct_dereference_index)); accesschain_mapping_[node] = object_to_be_defined_; @@ -728,7 +729,7 @@ protected: if (remained_accesschain_.empty()) { node->getWritableType().getQualifier().noContraction = true; } else { - new_precise_accesschain += OBJECT_ACCESSCHAIN_DELIMITER + remained_accesschain_; + new_precise_accesschain += ObjectAccesschainDelimiter + remained_accesschain_; } // Cache the accesschain as added precise object, so we won't add the // same object to the worklist again. @@ -777,7 +778,7 @@ protected: if (remained_accesschain_.empty()) { node->getWritableType().getQualifier().noContraction = true; } else { - new_precise_accesschain += OBJECT_ACCESSCHAIN_DELIMITER + remained_accesschain_; + new_precise_accesschain += ObjectAccesschainDelimiter + remained_accesschain_; } // Add the new 'precise' accesschain to the worklist and make sure we // don't visit it again. From 34d257184ad9d96b6e1dfe038b8baef3ff6e31bd Mon Sep 17 00:00:00 2001 From: qining Date: Fri, 6 May 2016 20:00:44 -0400 Subject: [PATCH 6/9] simplified the symbol definition collector code, add assert() --- .../propagateNoContraction.cpp | 56 +++++-------------- 1 file changed, 13 insertions(+), 43 deletions(-) diff --git a/glslang/MachineIndependent/propagateNoContraction.cpp b/glslang/MachineIndependent/propagateNoContraction.cpp index be53ea31..ae9cec0e 100644 --- a/glslang/MachineIndependent/propagateNoContraction.cpp +++ b/glslang/MachineIndependent/propagateNoContraction.cpp @@ -333,9 +333,7 @@ bool TSymbolDefinitionCollectingTraverser::visitUnary(glslang::TVisit /* visit * node->getOperand()->traverse(this); if (isAssignOperation(node->getOp())) { // We should always be able to get an accesschain of the operand node. - // But we have some tests in which it is intented to have invalid operand - // nodes, so just return for now. - if (object_to_be_defined_.empty()) return false; + assert(!object_to_be_defined_.empty()); // If the operand node object is 'precise', we collect its accesschain // for the initial set of 'precise' objects. @@ -367,9 +365,7 @@ bool TSymbolDefinitionCollectingTraverser::visitBinary(glslang::TVisit /* visit if (isAssignOperation(node->getOp())) { // We should always be able to get an accesschain for the left node. - // But we have some tests in which it is intented to have invalid left - // nodes, so just return false in such cases for now. - if (object_to_be_defined_.empty()) return false; + assert(!object_to_be_defined_.empty()); // If the left node object is 'precise', it is an initial precise object // specified in the shader source. Adds it to the initial worklist to @@ -391,44 +387,26 @@ bool TSymbolDefinitionCollectingTraverser::visitBinary(glslang::TVisit /* visit object_to_be_defined_.clear(); node->getRight()->traverse(this); - return false; } else if (isDereferenceOperation(node->getOp())) { - // If the left node is 'precise' object node, this node should also - // be 'precise' object node, and all the members of this node too. There - // is no need to append accesschain information into the object id. - if (isPreciseObjectNode(node->getLeft())) { - node->getWritableType().getQualifier().noContraction = true; - accesschain_mapping_[node] = object_to_be_defined_; - return false; + // The left node (parent node) is a struct type object. We need to + // record the accesschain information of the current node into its + // object id. + if (node->getOp() == glslang::EOpIndexDirectStruct) { + unsigned struct_dereference_index = getStructIndexFromConstantUnion(node->getRight()); + object_to_be_defined_.push_back(ObjectAccesschainDelimiter); + object_to_be_defined_.append(std::to_string(struct_dereference_index)); } - - // If the opcode is not EOpIndexDirectStruct, the left node is not be a - // struct type object, hence there is no need to append dereference - // indices. For other composite type objects, the precise'ness of - // members should always matches with the 'precise'ness of the - // composite type object. - if (node->getOp() != glslang::EOpIndexDirectStruct) { - accesschain_mapping_[node] = object_to_be_defined_; - return false; - } - - // The left node (parent node) is not 'precise' and it is a struct type - // object. We need to record the accesschain information of the current - // node into its object id. - unsigned struct_dereference_index = getStructIndexFromConstantUnion(node->getRight()); - object_to_be_defined_.push_back(ObjectAccesschainDelimiter); - object_to_be_defined_.append(std::to_string(struct_dereference_index)); accesschain_mapping_[node] = object_to_be_defined_; // For dereference node, there is no need to traverse the right child // node as the right node should always be an integer type object. - return false; + } else { // For other binary nodes, still traverse the right node. object_to_be_defined_.clear(); node->getRight()->traverse(this); - return false; } + return false; } // Traverses the AST and returns a tuple of three members: @@ -511,11 +489,7 @@ public: if (glslang::TIntermBinary* BN = node->getAsBinaryNode()) { // This is a binary assignment node, we need to check the // precise'ness of the left node. - if (!accesschain_mapping_.count(BN->getLeft())) { - // If the left node is not an object node, it can not be - // 'precise'. - return make_tuple(false, ObjectAccessChain()); - } + assert(accesschain_mapping_.count(BN->getLeft())); // The left node (assignee node) is an object node, traverse the // node to let the 'precise' of nesting objects being transfered to // nested objects. @@ -534,11 +508,7 @@ public: // This is a unary assignment node, we need to check the // precise'ness of the operand node. For unary assignment node, the // operand node should always be an object node. - if (!accesschain_mapping_.count(UN->getOperand())) { - // If the operand node is not an object node, it can not be - // 'precise'. - return make_tuple(false, ObjectAccessChain()); - } + assert(accesschain_mapping_.count(UN->getOperand())); // Traverse the operand node to let the 'precise' being propagated // from lower nodes to upper nodes. UN->getOperand()->traverse(this); From 5bec2b5619df65bba3a21412fb386bbdd505da80 Mon Sep 17 00:00:00 2001 From: qining Date: Fri, 6 May 2016 21:52:28 -0400 Subject: [PATCH 7/9] integer type operation should not be noContraction --- Test/baseResults/precise.tesc.out | 208 +++++++++--------- .../baseResults/precise_struct_block.vert.out | 8 +- Test/precise.tesc | 20 +- Test/precise_struct_block.vert | 2 +- .../propagateNoContraction.cpp | 2 +- 5 files changed, 116 insertions(+), 124 deletions(-) diff --git a/Test/baseResults/precise.tesc.out b/Test/baseResults/precise.tesc.out index a6b10adf..962a3c98 100644 --- a/Test/baseResults/precise.tesc.out +++ b/Test/baseResults/precise.tesc.out @@ -55,46 +55,45 @@ vertices = -1 0:16 Constant: 0:16 5.000000 0:17 Sequence -0:17 move second child to first child (temp int) -0:17 'a' (noContraction temp int) +0:17 move second child to first child (temp float) +0:17 'a' (noContraction temp float) 0:17 Constant: -0:17 10 (const int) +0:17 10.000000 0:18 Sequence -0:18 move second child to first child (temp int) -0:18 'b' (noContraction temp int) +0:18 move second child to first child (temp float) +0:18 'b' (noContraction temp float) 0:18 Constant: -0:18 20 (const int) +0:18 20.000000 0:19 move second child to first child (temp float) 0:19 'result' (noContraction temp float) -0:19 Convert int to float (temp float) -0:19 move second child to first child (temp int) -0:19 'a' (noContraction temp int) -0:19 add (noContraction temp int) -0:19 'b' (noContraction temp int) -0:19 Constant: -0:19 4 (const int) +0:19 move second child to first child (temp float) +0:19 'a' (noContraction temp float) +0:19 add (noContraction temp float) +0:19 'b' (noContraction temp float) +0:19 Constant: +0:19 4.000000 0:22 Function Definition: convert( (global void) 0:22 Function Parameters: 0:? Sequence 0:24 Sequence -0:24 move second child to first child (temp int) -0:24 'a' (noContraction temp int) +0:24 move second child to first child (temp float) +0:24 'a' (noContraction temp float) 0:24 Constant: -0:24 10 (const int) +0:24 10.000000 0:25 Sequence -0:25 move second child to first child (temp int) -0:25 'b' (noContraction temp int) +0:25 move second child to first child (temp float) +0:25 'b' (noContraction temp float) 0:25 Constant: -0:25 20 (const int) -0:26 move second child to first child (temp int) -0:26 'b' (noContraction temp int) -0:26 add (noContraction temp int) -0:26 'a' (noContraction temp int) -0:26 'b' (noContraction temp int) -0:27 move second child to first child (temp float) -0:27 'result' (noContraction temp float) -0:27 Convert int to float (temp float) -0:27 'b' (noContraction temp int) +0:25 20.000000 +0:26 move second child to first child (temp float) +0:26 'b' (noContraction temp float) +0:26 add (noContraction temp float) +0:26 'a' (noContraction temp float) +0:26 'b' (noContraction temp float) +0:27 move second child to first child (temp double) +0:27 'result' (noContraction temp double) +0:27 Convert float to double (temp double) +0:27 'b' (noContraction temp float) 0:30 Function Definition: loop_for( (global float) 0:30 Function Parameters: 0:31 Sequence @@ -168,12 +167,7 @@ vertices = -1 0:42 'r2' (noContraction temp float) 0:45 Function Definition: loop_array( (global void) 0:45 Function Parameters: -0:46 Sequence -0:46 Sequence -0:46 move second child to first child (temp int) -0:46 'result' (noContraction temp int) -0:46 Constant: -0:46 5 (const int) +0:? Sequence 0:48 Sequence 0:48 move second child to first child (temp int) 0:48 'x' (noContraction temp int) @@ -184,11 +178,13 @@ vertices = -1 0:49 'y' (noContraction temp int) 0:49 Constant: 0:49 33 (const int) -0:52 add second child into first child (noContraction temp int) -0:52 'result' (noContraction temp int) -0:52 add (noContraction temp int) -0:52 'x' (noContraction temp int) -0:52 'y' (noContraction temp int) +0:52 add second child into first child (noContraction temp float) +0:52 'result' (noContraction temp float) +0:52 add (noContraction temp float) +0:52 Convert int to float (temp float) +0:52 'x' (noContraction temp int) +0:52 Convert int to float (temp float) +0:52 'y' (noContraction temp int) 0:54 Sequence 0:54 Sequence 0:54 move second child to first child (temp int) @@ -203,23 +199,23 @@ vertices = -1 0:54 3 (const int) 0:54 Loop Body 0:56 Sequence -0:56 add second child into first child (noContraction temp int) -0:56 'result' (noContraction temp int) -0:56 add (noContraction temp int) -0:56 indirect index (noContraction temp int) -0:56 'a0' (temp 3-element array of int) +0:56 add second child into first child (noContraction temp float) +0:56 'result' (noContraction temp float) +0:56 add (noContraction temp float) +0:56 indirect index (noContraction temp float) +0:56 'a0' (temp 3-element array of float) 0:56 'i' (temp int) 0:56 Constant: -0:56 2 (const int) -0:58 move second child to first child (temp int) -0:58 indirect index (noContraction temp int) -0:58 'a0' (noContraction temp 3-element array of int) +0:56 2.000000 +0:58 move second child to first child (temp float) +0:58 indirect index (noContraction temp float) +0:58 'a0' (noContraction temp 3-element array of float) 0:58 'i' (temp int) -0:58 subtract (noContraction temp int) +0:58 subtract (noContraction temp float) 0:58 Constant: -0:58 3 (const int) -0:58 Post-Increment (noContraction temp int) -0:58 'result' (noContraction temp int) +0:58 3.000000 +0:58 Post-Increment (noContraction temp float) +0:58 'result' (noContraction temp float) 0:54 Loop Terminal Expression 0:54 Pre-Increment (temp int) 0:54 'i' (temp int) @@ -259,8 +255,8 @@ vertices = -1 0:69 move second child to first child (temp float) 0:69 'result' (noContraction temp float) 0:69 Convert int to float (temp float) -0:69 add (noContraction temp int) -0:69 add (noContraction temp int) +0:69 add (temp int) +0:69 add (temp int) 0:69 'a' (noContraction temp int) 0:69 'b' (noContraction temp int) 0:69 Constant: @@ -444,46 +440,45 @@ vertices = -1 0:16 Constant: 0:16 5.000000 0:17 Sequence -0:17 move second child to first child (temp int) -0:17 'a' (noContraction temp int) +0:17 move second child to first child (temp float) +0:17 'a' (noContraction temp float) 0:17 Constant: -0:17 10 (const int) +0:17 10.000000 0:18 Sequence -0:18 move second child to first child (temp int) -0:18 'b' (noContraction temp int) +0:18 move second child to first child (temp float) +0:18 'b' (noContraction temp float) 0:18 Constant: -0:18 20 (const int) +0:18 20.000000 0:19 move second child to first child (temp float) 0:19 'result' (noContraction temp float) -0:19 Convert int to float (temp float) -0:19 move second child to first child (temp int) -0:19 'a' (noContraction temp int) -0:19 add (noContraction temp int) -0:19 'b' (noContraction temp int) -0:19 Constant: -0:19 4 (const int) +0:19 move second child to first child (temp float) +0:19 'a' (noContraction temp float) +0:19 add (noContraction temp float) +0:19 'b' (noContraction temp float) +0:19 Constant: +0:19 4.000000 0:22 Function Definition: convert( (global void) 0:22 Function Parameters: 0:? Sequence 0:24 Sequence -0:24 move second child to first child (temp int) -0:24 'a' (noContraction temp int) +0:24 move second child to first child (temp float) +0:24 'a' (noContraction temp float) 0:24 Constant: -0:24 10 (const int) +0:24 10.000000 0:25 Sequence -0:25 move second child to first child (temp int) -0:25 'b' (noContraction temp int) +0:25 move second child to first child (temp float) +0:25 'b' (noContraction temp float) 0:25 Constant: -0:25 20 (const int) -0:26 move second child to first child (temp int) -0:26 'b' (noContraction temp int) -0:26 add (noContraction temp int) -0:26 'a' (noContraction temp int) -0:26 'b' (noContraction temp int) -0:27 move second child to first child (temp float) -0:27 'result' (noContraction temp float) -0:27 Convert int to float (temp float) -0:27 'b' (noContraction temp int) +0:25 20.000000 +0:26 move second child to first child (temp float) +0:26 'b' (noContraction temp float) +0:26 add (noContraction temp float) +0:26 'a' (noContraction temp float) +0:26 'b' (noContraction temp float) +0:27 move second child to first child (temp double) +0:27 'result' (noContraction temp double) +0:27 Convert float to double (temp double) +0:27 'b' (noContraction temp float) 0:30 Function Definition: loop_for( (global float) 0:30 Function Parameters: 0:31 Sequence @@ -557,12 +552,7 @@ vertices = -1 0:42 'r2' (noContraction temp float) 0:45 Function Definition: loop_array( (global void) 0:45 Function Parameters: -0:46 Sequence -0:46 Sequence -0:46 move second child to first child (temp int) -0:46 'result' (noContraction temp int) -0:46 Constant: -0:46 5 (const int) +0:? Sequence 0:48 Sequence 0:48 move second child to first child (temp int) 0:48 'x' (noContraction temp int) @@ -573,11 +563,13 @@ vertices = -1 0:49 'y' (noContraction temp int) 0:49 Constant: 0:49 33 (const int) -0:52 add second child into first child (noContraction temp int) -0:52 'result' (noContraction temp int) -0:52 add (noContraction temp int) -0:52 'x' (noContraction temp int) -0:52 'y' (noContraction temp int) +0:52 add second child into first child (noContraction temp float) +0:52 'result' (noContraction temp float) +0:52 add (noContraction temp float) +0:52 Convert int to float (temp float) +0:52 'x' (noContraction temp int) +0:52 Convert int to float (temp float) +0:52 'y' (noContraction temp int) 0:54 Sequence 0:54 Sequence 0:54 move second child to first child (temp int) @@ -592,23 +584,23 @@ vertices = -1 0:54 3 (const int) 0:54 Loop Body 0:56 Sequence -0:56 add second child into first child (noContraction temp int) -0:56 'result' (noContraction temp int) -0:56 add (noContraction temp int) -0:56 indirect index (noContraction temp int) -0:56 'a0' (temp 3-element array of int) +0:56 add second child into first child (noContraction temp float) +0:56 'result' (noContraction temp float) +0:56 add (noContraction temp float) +0:56 indirect index (noContraction temp float) +0:56 'a0' (temp 3-element array of float) 0:56 'i' (temp int) 0:56 Constant: -0:56 2 (const int) -0:58 move second child to first child (temp int) -0:58 indirect index (noContraction temp int) -0:58 'a0' (noContraction temp 3-element array of int) +0:56 2.000000 +0:58 move second child to first child (temp float) +0:58 indirect index (noContraction temp float) +0:58 'a0' (noContraction temp 3-element array of float) 0:58 'i' (temp int) -0:58 subtract (noContraction temp int) +0:58 subtract (noContraction temp float) 0:58 Constant: -0:58 3 (const int) -0:58 Post-Increment (noContraction temp int) -0:58 'result' (noContraction temp int) +0:58 3.000000 +0:58 Post-Increment (noContraction temp float) +0:58 'result' (noContraction temp float) 0:54 Loop Terminal Expression 0:54 Pre-Increment (temp int) 0:54 'i' (temp int) @@ -648,8 +640,8 @@ vertices = -1 0:69 move second child to first child (temp float) 0:69 'result' (noContraction temp float) 0:69 Convert int to float (temp float) -0:69 add (noContraction temp int) -0:69 add (noContraction temp int) +0:69 add (temp int) +0:69 add (temp int) 0:69 'a' (noContraction temp int) 0:69 'b' (noContraction temp int) 0:69 Constant: diff --git a/Test/baseResults/precise_struct_block.vert.out b/Test/baseResults/precise_struct_block.vert.out index 7d783e55..9d726d65 100644 --- a/Test/baseResults/precise_struct_block.vert.out +++ b/Test/baseResults/precise_struct_block.vert.out @@ -325,8 +325,8 @@ Shader version: 450 0:63 0 (const int) 0:63 'k' (temp int) 0:63 Convert int to float (temp float) -0:63 add (noContraction temp int) -0:63 component-wise multiply (noContraction temp int) +0:63 add (temp int) +0:63 component-wise multiply (temp int) 0:63 'i' (noContraction temp int) 0:63 'j' (noContraction temp int) 0:63 'k' (noContraction temp int) @@ -848,8 +848,8 @@ Shader version: 450 0:63 0 (const int) 0:63 'k' (temp int) 0:63 Convert int to float (temp float) -0:63 add (noContraction temp int) -0:63 component-wise multiply (noContraction temp int) +0:63 add (temp int) +0:63 component-wise multiply (temp int) 0:63 'i' (noContraction temp int) 0:63 'j' (noContraction temp int) 0:63 'k' (noContraction temp int) diff --git a/Test/precise.tesc b/Test/precise.tesc index b4ac5795..c541540c 100644 --- a/Test/precise.tesc +++ b/Test/precise.tesc @@ -14,17 +14,17 @@ float minimal() { void continuous_assignment() { precise float result = 5.0; - int a = 10; - int b = 20; + float a = 10.0; + float b = 20.0; result = a = b + 4; // b + 4 should be 'noContraction'. } void convert() { - precise float result; - int a = 10; - int b = 20; + precise double result; + float a = 10.0; + float b = 20.0; b = a + b; // a + b should be 'noContraction'. - result = float(b); // convert operation should not be 'noContraction'. + result = double(b); // convert operation should not be 'noContraction'. } float loop_for() { @@ -43,13 +43,13 @@ float loop_for() { } void loop_array(void) { - precise int result = 5; + precise float result; int x = 22; int y = 33; - int a0[3]; - result += x + y; // x + y should be 'noContraction' also result + rvalue. + float a0[3]; + result += float(x) + float(y); // x + y should be 'noContraction' also result + rvalue. for (int i = 0; i < 3; ++i) { // a's dereference + 2 should be 'noContraction'. @@ -66,7 +66,7 @@ void loop_while() { while (result < 10) { result += 3.12 + b; // result + 3.12 should be 'noContraction'. } - result = a + b + 5; // b + 5 should be 'noCtraction' and also a + rvalue. + result = a + b + 5; // b + 5 should not be 'noCtraction' because all operands are integers. result = 11.1; } diff --git a/Test/precise_struct_block.vert b/Test/precise_struct_block.vert index a050ccd0..279b4b09 100644 --- a/Test/precise_struct_block.vert +++ b/Test/precise_struct_block.vert @@ -60,7 +60,7 @@ float complex_array_struct() { for(int j=0; j<6; j++) { for(int k = 0; k<3; k++) { - t3[i].t2.t1c[j].t1_array[k] = i * j + k; // NoContraction + t3[i].t2.t1c[j].t1_array[k] = i * j + k; // Not NoContraction because all operands are integers } t3[i].t2.t1c[j].t1_scalar = j * 2.0 / i; // Not NoContraction } diff --git a/glslang/MachineIndependent/propagateNoContraction.cpp b/glslang/MachineIndependent/propagateNoContraction.cpp index ae9cec0e..da8dfaf8 100644 --- a/glslang/MachineIndependent/propagateNoContraction.cpp +++ b/glslang/MachineIndependent/propagateNoContraction.cpp @@ -712,7 +712,7 @@ protected: return false; } // If this is an arithmetic operation, marks this node as 'noContraction'. - if (isArithmeticOperation(node->getOp())) { + if (isArithmeticOperation(node->getOp()) && node->getBasicType() != glslang::EbtInt) { node->getWritableType().getQualifier().noContraction = true; } // As this node is not an object node, need to traverse the children nodes. From bb0ac5466047f8ef14dda37cb0b160682d20ee26 Mon Sep 17 00:00:00 2001 From: qining Date: Mon, 9 May 2016 21:18:33 -0400 Subject: [PATCH 8/9] Rebase to d3d3ce7160001846ede74978954e67f4f9fd84e4,update comments, rename a member variable name, fix format issue --- .../propagateNoContraction.cpp | 72 +++++++++---------- 1 file changed, 35 insertions(+), 37 deletions(-) diff --git a/glslang/MachineIndependent/propagateNoContraction.cpp b/glslang/MachineIndependent/propagateNoContraction.cpp index da8dfaf8..b859dde1 100644 --- a/glslang/MachineIndependent/propagateNoContraction.cpp +++ b/glslang/MachineIndependent/propagateNoContraction.cpp @@ -142,7 +142,7 @@ ObjectAccessChain generateSymbolLabel(glslang::TIntermSymbol* node) return symbol_id; } -// Return true if the operation is an arithmetic operation and valid for +// Returns true if the operation is an arithmetic operation and valid for // 'NoContraction' decoration. bool isArithmeticOperation(glslang::TOperator op) { @@ -173,11 +173,6 @@ bool isArithmeticOperation(glslang::TOperator op) case glslang::EOpDot: - case glslang::EOpAddCarry: - case glslang::EOpSubBorrow: - case glslang::EOpUMulExtended: - case glslang::EOpIMulExtended: - case glslang::EOpPostIncrement: case glslang::EOpPostDecrement: case glslang::EOpPreIncrement: @@ -224,7 +219,8 @@ ObjectAccessChain getSubAccessChainAfterPrefix(const ObjectAccessChain& chain, const ObjectAccessChain& prefix) { size_t pos = chain.find(prefix); - if (pos != 0) return chain; + if (pos != 0) + return chain; return chain.substr(prefix.length() + sizeof(ObjectAccesschainDelimiter)); } @@ -257,7 +253,7 @@ protected: ReturnBranchNodeSet& precise_return_nodes_; // A temporary cache of the symbol node whose defining node is to be found // currently along traversing the AST. - ObjectAccessChain object_to_be_defined_; + ObjectAccessChain current_object__; // A map from object node to its accesschain. This traverser stores // the built accesschains into this map for each object node it has // visited. @@ -273,18 +269,18 @@ TSymbolDefinitionCollectingTraverser::TSymbolDefinitionCollectingTraverser( ObjectAccesschainSet* precise_objects, std::unordered_set* precise_return_nodes) : TIntermTraverser(true, false, false), symbol_definition_mapping_(*symbol_definition_mapping), - precise_objects_(*precise_objects), object_to_be_defined_(), + precise_objects_(*precise_objects), current_object__(), accesschain_mapping_(*accesschain_mapping), current_function_definition_node_(nullptr), precise_return_nodes_(*precise_return_nodes) {} -// Visits a symbol node, set the object_to_be_defined_ to the +// Visits a symbol node, set the current_object__ to the // current node symbol ID, and record a mapping from this node to the current -// object_to_be_defined_, which is the just obtained symbol +// current_object__, which is the just obtained symbol // ID. void TSymbolDefinitionCollectingTraverser::visitSymbol(glslang::TIntermSymbol* node) { - object_to_be_defined_ = generateSymbolLabel(node); - accesschain_mapping_[node] = object_to_be_defined_; + current_object__ = generateSymbolLabel(node); + accesschain_mapping_[node] = current_object__; } // Visits an aggregate node, traverses all of its children. @@ -304,7 +300,7 @@ bool TSymbolDefinitionCollectingTraverser::visitAggregate(glslang::TVisit, // Traverse the items in the sequence. glslang::TIntermSequence& seq = node->getSequence(); for (int i = 0; i < (int)seq.size(); ++i) { - object_to_be_defined_.clear(); + current_object__.clear(); seq[i]->traverse(this); } return false; @@ -329,11 +325,11 @@ bool TSymbolDefinitionCollectingTraverser::visitBranch(glslang::TVisit, bool TSymbolDefinitionCollectingTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TIntermUnary* node) { - object_to_be_defined_.clear(); + current_object__.clear(); node->getOperand()->traverse(this); if (isAssignOperation(node->getOp())) { // We should always be able to get an accesschain of the operand node. - assert(!object_to_be_defined_.empty()); + assert(!current_object__.empty()); // If the operand node object is 'precise', we collect its accesschain // for the initial set of 'precise' objects. @@ -341,16 +337,16 @@ bool TSymbolDefinitionCollectingTraverser::visitUnary(glslang::TVisit /* visit * // The operand node is an 'precise' object node, add its // accesschain to the set of 'precise' objects. This is to collect // the initial set of 'precise' objects. - precise_objects_.insert(object_to_be_defined_); + precise_objects_.insert(current_object__); } // Gets the symbol ID from the object's accesschain. - ObjectAccessChain id_symbol = getFrontElement(object_to_be_defined_); + ObjectAccessChain id_symbol = getFrontElement(current_object__); // Add a mapping from the symbol ID to this assignment operation node. symbol_definition_mapping_.insert(std::make_pair(id_symbol, node)); } // Unary node is not a dereference node, so we clear the accesschain which // is under construction. - object_to_be_defined_.clear(); + current_object__.clear(); return false; } @@ -360,12 +356,12 @@ bool TSymbolDefinitionCollectingTraverser::visitBinary(glslang::TVisit /* visit glslang::TIntermBinary* node) { // Traverses the left node to build the accesschain info for the object. - object_to_be_defined_.clear(); + current_object__.clear(); node->getLeft()->traverse(this); if (isAssignOperation(node->getOp())) { // We should always be able to get an accesschain for the left node. - assert(!object_to_be_defined_.empty()); + assert(!current_object__.empty()); // If the left node object is 'precise', it is an initial precise object // specified in the shader source. Adds it to the initial worklist to @@ -374,17 +370,17 @@ bool TSymbolDefinitionCollectingTraverser::visitBinary(glslang::TVisit /* visit // The left node is an 'precise' object node, add its accesschain to // the set of 'precise' objects. This is to collect the initial set // of 'precise' objects. - precise_objects_.insert(object_to_be_defined_); + precise_objects_.insert(current_object__); } // Gets the symbol ID from the object accesschain, which should be the // first element recorded in the accesschain. - ObjectAccessChain id_symbol = getFrontElement(object_to_be_defined_); + ObjectAccessChain id_symbol = getFrontElement(current_object__); // Adds a mapping from the symbol ID to this assignment operation node. symbol_definition_mapping_.insert(std::make_pair(id_symbol, node)); // Traverses the right node, there may be other 'assignment' // operatrions in the right. - object_to_be_defined_.clear(); + current_object__.clear(); node->getRight()->traverse(this); } else if (isDereferenceOperation(node->getOp())) { @@ -393,26 +389,27 @@ bool TSymbolDefinitionCollectingTraverser::visitBinary(glslang::TVisit /* visit // object id. if (node->getOp() == glslang::EOpIndexDirectStruct) { unsigned struct_dereference_index = getStructIndexFromConstantUnion(node->getRight()); - object_to_be_defined_.push_back(ObjectAccesschainDelimiter); - object_to_be_defined_.append(std::to_string(struct_dereference_index)); + current_object__.push_back(ObjectAccesschainDelimiter); + current_object__.append(std::to_string(struct_dereference_index)); } - accesschain_mapping_[node] = object_to_be_defined_; + accesschain_mapping_[node] = current_object__; // For dereference node, there is no need to traverse the right child // node as the right node should always be an integer type object. } else { // For other binary nodes, still traverse the right node. - object_to_be_defined_.clear(); - node->getRight()->traverse(this); + current_object__.clear(); + return true; } return false; } -// Traverses the AST and returns a tuple of three members: +// Traverses the AST and returns a tuple of four members: // 1) a mapping from symbol IDs to the definition nodes (aka. assignment nodes) of these symbols. // 2) a mapping from object nodes in the AST to the accesschains of these objects. // 3) a set of accesschains of precise objects. +// 4) a set of return nodes with precise expressions. std::tuple getSymbolToDefinitionMappingAndPreciseSymbolIDs(const glslang::TIntermediate& intermediate) { @@ -420,7 +417,8 @@ getSymbolToDefinitionMappingAndPreciseSymbolIDs(const glslang::TIntermediate& in ReturnBranchNodeSet()); TIntermNode* root = intermediate.getTreeRoot(); - if (root == 0) return result_tuple; + if (root == 0) + return result_tuple; NodeMapping& symbol_definition_mapping = std::get<0>(result_tuple); AccessChainMapping& accesschain_mapping = std::get<1>(result_tuple); @@ -561,7 +559,7 @@ protected: const ObjectAccessChain* precise_object_; }; -// Visit a binary node. If the node is an object node, it must be a dereference +// Visits a binary node. If the node is an object node, it must be a dereference // node. In such cases, if the left node is 'precise', this node should also be // 'precise'. bool TNoContractionAssigneeCheckingTraverser::visitBinary(glslang::TVisit, @@ -588,7 +586,7 @@ bool TNoContractionAssigneeCheckingTraverser::visitBinary(glslang::TVisit, return false; } -// Visit a symbol node, if the symbol node ID (its accesschain string) matches +// Visits a symbol node, if the symbol node ID (its accesschain string) matches // with the given precise object, this node should be 'precise'. void TNoContractionAssigneeCheckingTraverser::visitSymbol(glslang::TIntermSymbol* node) { @@ -649,7 +647,7 @@ public: } protected: - // Visit an aggregate node. The node can be a initializer list, in which + // Visits an aggregate node. The node can be a initializer list, in which // case we need to find the 'precise' or 'precise' containing object node // with the accesschain record. In other cases, just need to traverse all // the children nodes. @@ -683,7 +681,7 @@ protected: return true; } - // Visit a binary node. A binary node can be an object node, e.g. a dereference node. + // Visits a binary node. A binary node can be an object node, e.g. a dereference node. // As only the top object nodes in the right side of an assignment needs to be visited // and added to 'precise' worklist, this traverser won't visit the children nodes of // an object node. If the binary node does not represent an object node, it should @@ -779,7 +777,7 @@ void PropagateNoContraction(const glslang::TIntermediate& intermediate) { // First, traverses the AST, records symbols with their defining operations // and collects the initial set of precise symbols (symbol nodes that marked - // as 'noContraction'). + // as 'noContraction') and precise return nodes. auto mappings_and_precise_objects = getSymbolToDefinitionMappingAndPreciseSymbolIDs(intermediate); @@ -831,7 +829,7 @@ void PropagateNoContraction(const glslang::TIntermediate& intermediate) // Get all the defining nodes of that symbol ID. std::pair range = symbol_definition_mapping.equal_range(symbol_id); - // Visit all the assignment nodes of that symbol ID and + // Visits all the assignment nodes of that symbol ID and // 1) Check if the assignee node is 'precise' or contains 'precise' // objects. // 2) Propagate the 'precise' to the top layer object ndoes From e543cc35e954a0385195e0b52045b9cea59700ea Mon Sep 17 00:00:00 2001 From: qining Date: Mon, 9 May 2016 21:38:42 -0400 Subject: [PATCH 9/9] remove double underscore --- .../propagateNoContraction.cpp | 42 +++++++++---------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/glslang/MachineIndependent/propagateNoContraction.cpp b/glslang/MachineIndependent/propagateNoContraction.cpp index b859dde1..ab00829b 100644 --- a/glslang/MachineIndependent/propagateNoContraction.cpp +++ b/glslang/MachineIndependent/propagateNoContraction.cpp @@ -253,7 +253,7 @@ protected: ReturnBranchNodeSet& precise_return_nodes_; // A temporary cache of the symbol node whose defining node is to be found // currently along traversing the AST. - ObjectAccessChain current_object__; + ObjectAccessChain current_object_; // A map from object node to its accesschain. This traverser stores // the built accesschains into this map for each object node it has // visited. @@ -269,18 +269,18 @@ TSymbolDefinitionCollectingTraverser::TSymbolDefinitionCollectingTraverser( ObjectAccesschainSet* precise_objects, std::unordered_set* precise_return_nodes) : TIntermTraverser(true, false, false), symbol_definition_mapping_(*symbol_definition_mapping), - precise_objects_(*precise_objects), current_object__(), + precise_objects_(*precise_objects), current_object_(), accesschain_mapping_(*accesschain_mapping), current_function_definition_node_(nullptr), precise_return_nodes_(*precise_return_nodes) {} -// Visits a symbol node, set the current_object__ to the +// Visits a symbol node, set the current_object_ to the // current node symbol ID, and record a mapping from this node to the current -// current_object__, which is the just obtained symbol +// current_object_, which is the just obtained symbol // ID. void TSymbolDefinitionCollectingTraverser::visitSymbol(glslang::TIntermSymbol* node) { - current_object__ = generateSymbolLabel(node); - accesschain_mapping_[node] = current_object__; + current_object_ = generateSymbolLabel(node); + accesschain_mapping_[node] = current_object_; } // Visits an aggregate node, traverses all of its children. @@ -300,7 +300,7 @@ bool TSymbolDefinitionCollectingTraverser::visitAggregate(glslang::TVisit, // Traverse the items in the sequence. glslang::TIntermSequence& seq = node->getSequence(); for (int i = 0; i < (int)seq.size(); ++i) { - current_object__.clear(); + current_object_.clear(); seq[i]->traverse(this); } return false; @@ -325,11 +325,11 @@ bool TSymbolDefinitionCollectingTraverser::visitBranch(glslang::TVisit, bool TSymbolDefinitionCollectingTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TIntermUnary* node) { - current_object__.clear(); + current_object_.clear(); node->getOperand()->traverse(this); if (isAssignOperation(node->getOp())) { // We should always be able to get an accesschain of the operand node. - assert(!current_object__.empty()); + assert(!current_object_.empty()); // If the operand node object is 'precise', we collect its accesschain // for the initial set of 'precise' objects. @@ -337,16 +337,16 @@ bool TSymbolDefinitionCollectingTraverser::visitUnary(glslang::TVisit /* visit * // The operand node is an 'precise' object node, add its // accesschain to the set of 'precise' objects. This is to collect // the initial set of 'precise' objects. - precise_objects_.insert(current_object__); + precise_objects_.insert(current_object_); } // Gets the symbol ID from the object's accesschain. - ObjectAccessChain id_symbol = getFrontElement(current_object__); + ObjectAccessChain id_symbol = getFrontElement(current_object_); // Add a mapping from the symbol ID to this assignment operation node. symbol_definition_mapping_.insert(std::make_pair(id_symbol, node)); } // Unary node is not a dereference node, so we clear the accesschain which // is under construction. - current_object__.clear(); + current_object_.clear(); return false; } @@ -356,12 +356,12 @@ bool TSymbolDefinitionCollectingTraverser::visitBinary(glslang::TVisit /* visit glslang::TIntermBinary* node) { // Traverses the left node to build the accesschain info for the object. - current_object__.clear(); + current_object_.clear(); node->getLeft()->traverse(this); if (isAssignOperation(node->getOp())) { // We should always be able to get an accesschain for the left node. - assert(!current_object__.empty()); + assert(!current_object_.empty()); // If the left node object is 'precise', it is an initial precise object // specified in the shader source. Adds it to the initial worklist to @@ -370,17 +370,17 @@ bool TSymbolDefinitionCollectingTraverser::visitBinary(glslang::TVisit /* visit // The left node is an 'precise' object node, add its accesschain to // the set of 'precise' objects. This is to collect the initial set // of 'precise' objects. - precise_objects_.insert(current_object__); + precise_objects_.insert(current_object_); } // Gets the symbol ID from the object accesschain, which should be the // first element recorded in the accesschain. - ObjectAccessChain id_symbol = getFrontElement(current_object__); + ObjectAccessChain id_symbol = getFrontElement(current_object_); // Adds a mapping from the symbol ID to this assignment operation node. symbol_definition_mapping_.insert(std::make_pair(id_symbol, node)); // Traverses the right node, there may be other 'assignment' // operatrions in the right. - current_object__.clear(); + current_object_.clear(); node->getRight()->traverse(this); } else if (isDereferenceOperation(node->getOp())) { @@ -389,17 +389,17 @@ bool TSymbolDefinitionCollectingTraverser::visitBinary(glslang::TVisit /* visit // object id. if (node->getOp() == glslang::EOpIndexDirectStruct) { unsigned struct_dereference_index = getStructIndexFromConstantUnion(node->getRight()); - current_object__.push_back(ObjectAccesschainDelimiter); - current_object__.append(std::to_string(struct_dereference_index)); + current_object_.push_back(ObjectAccesschainDelimiter); + current_object_.append(std::to_string(struct_dereference_index)); } - accesschain_mapping_[node] = current_object__; + accesschain_mapping_[node] = current_object_; // For dereference node, there is no need to traverse the right child // node as the right node should always be an integer type object. } else { // For other binary nodes, still traverse the right node. - current_object__.clear(); + current_object_.clear(); return true; } return false;