Ver código fonte

LiveTraverser no longer traverses switch cases that are statically not accessed

Zackery Mason-Blaug 4 meses atrás
pai
commit
0b3e8560fe

+ 327 - 0
Test/baseResults/liveTraverser.switch.vert.out

@@ -0,0 +1,327 @@
+liveTraverser.switch.vert
+Shader version: 460
+0:? Sequence
+0:25  Function Definition: main( ( global void)
+0:25    Function Parameters: 
+0:27    Sequence
+0:27      switch
+0:27      condition
+0:27        Constant:
+0:27          2 (const int)
+0:27      body
+0:27        Sequence
+0:28          case:  with expression
+0:28            Constant:
+0:28              2 (const int)
+0:?           Sequence
+0:28            Branch: Break
+0:29          case:  with expression
+0:29            Constant:
+0:29              1 (const int)
+0:?           Sequence
+0:30            move second child to first child ( temp highp 4-component vector of float)
+0:30              gl_Position: direct index for structure ( gl_Position highp 4-component vector of float Position)
+0:30                'anon@0' ( out block{ gl_Position 4-component vector of float Position gl_Position,  gl_PointSize float PointSize gl_PointSize,  out unsized 1-element array of float ClipDistance gl_ClipDistance,  out unsized 1-element array of float CullDistance gl_CullDistance})
+0:30                Constant:
+0:30                  0 (const uint)
+0:30              'n0' (layout( location=11) in highp 4-component vector of float)
+0:34      switch
+0:34      condition
+0:34        Constant:
+0:34          3 (const int)
+0:34      body
+0:34        Sequence
+0:35          default: 
+0:?           Sequence
+0:35            Branch: Break
+0:36          case:  with expression
+0:36            Constant:
+0:36              1 (const int)
+0:?           Sequence
+0:37            move second child to first child ( temp highp 4-component vector of float)
+0:37              gl_Position: direct index for structure ( gl_Position highp 4-component vector of float Position)
+0:37                'anon@0' ( out block{ gl_Position 4-component vector of float Position gl_Position,  gl_PointSize float PointSize gl_PointSize,  out unsized 1-element array of float ClipDistance gl_ClipDistance,  out unsized 1-element array of float CullDistance gl_CullDistance})
+0:37                Constant:
+0:37                  0 (const uint)
+0:37              'n1' (layout( location=12) in highp 4-component vector of float)
+0:41      switch
+0:41      condition
+0:41        Constant:
+0:41          3 (const int)
+0:41      body
+0:41        Sequence
+0:42          case:  with expression
+0:42            Constant:
+0:42              2 (const int)
+0:43          case:  with expression
+0:43            Constant:
+0:43              1 (const int)
+0:?           Sequence
+0:44            move second child to first child ( temp highp 4-component vector of float)
+0:44              gl_Position: direct index for structure ( gl_Position highp 4-component vector of float Position)
+0:44                'anon@0' ( out block{ gl_Position 4-component vector of float Position gl_Position,  gl_PointSize float PointSize gl_PointSize,  out unsized 1-element array of float ClipDistance gl_ClipDistance,  out unsized 1-element array of float CullDistance gl_CullDistance})
+0:44                Constant:
+0:44                  0 (const uint)
+0:44              'n2' (layout( location=13) in highp 4-component vector of float)
+0:48      switch
+0:48      condition
+0:48        Constant:
+0:48          1 (const int)
+0:48      body
+0:48        Sequence
+0:49          case:  with expression
+0:49            Constant:
+0:49              -1 (const int)
+0:?           Sequence
+0:50            move second child to first child ( temp highp 4-component vector of float)
+0:50              gl_Position: direct index for structure ( gl_Position highp 4-component vector of float Position)
+0:50                'anon@0' ( out block{ gl_Position 4-component vector of float Position gl_Position,  gl_PointSize float PointSize gl_PointSize,  out unsized 1-element array of float ClipDistance gl_ClipDistance,  out unsized 1-element array of float CullDistance gl_CullDistance})
+0:50                Constant:
+0:50                  0 (const uint)
+0:50              'n3' (layout( location=14) in highp 4-component vector of float)
+0:51            Branch: Break
+0:52          case:  with expression
+0:52            Constant:
+0:52              1 (const int)
+0:?           Sequence
+0:53            move second child to first child ( temp highp 4-component vector of float)
+0:53              gl_Position: direct index for structure ( gl_Position highp 4-component vector of float Position)
+0:53                'anon@0' ( out block{ gl_Position 4-component vector of float Position gl_Position,  gl_PointSize float PointSize gl_PointSize,  out unsized 1-element array of float ClipDistance gl_ClipDistance,  out unsized 1-element array of float CullDistance gl_CullDistance})
+0:53                Constant:
+0:53                  0 (const uint)
+0:53              'a0' (layout( location=0) in highp 4-component vector of float)
+0:54            Branch: Break
+0:55            move second child to first child ( temp highp 4-component vector of float)
+0:55              gl_Position: direct index for structure ( gl_Position highp 4-component vector of float Position)
+0:55                'anon@0' ( out block{ gl_Position 4-component vector of float Position gl_Position,  gl_PointSize float PointSize gl_PointSize,  out unsized 1-element array of float ClipDistance gl_ClipDistance,  out unsized 1-element array of float CullDistance gl_CullDistance})
+0:55                Constant:
+0:55                  0 (const uint)
+0:55              'n4' (layout( location=15) in highp 4-component vector of float)
+0:56          case:  with expression
+0:56            Constant:
+0:56              0 (const int)
+0:?           Sequence
+0:57            move second child to first child ( temp highp 4-component vector of float)
+0:57              gl_Position: direct index for structure ( gl_Position highp 4-component vector of float Position)
+0:57                'anon@0' ( out block{ gl_Position 4-component vector of float Position gl_Position,  gl_PointSize float PointSize gl_PointSize,  out unsized 1-element array of float ClipDistance gl_ClipDistance,  out unsized 1-element array of float CullDistance gl_CullDistance})
+0:57                Constant:
+0:57                  0 (const uint)
+0:57              'n5' (layout( location=16) in highp 4-component vector of float)
+0:63      switch
+0:63      condition
+0:63        Constant:
+0:63          1 (const int)
+0:63      body
+0:63        Sequence
+0:64          case:  with expression
+0:64            Constant:
+0:64              1 (const uint)
+0:?           Sequence
+0:65            move second child to first child ( temp highp 4-component vector of float)
+0:65              gl_Position: direct index for structure ( gl_Position highp 4-component vector of float Position)
+0:65                'anon@0' ( out block{ gl_Position 4-component vector of float Position gl_Position,  gl_PointSize float PointSize gl_PointSize,  out unsized 1-element array of float ClipDistance gl_ClipDistance,  out unsized 1-element array of float CullDistance gl_CullDistance})
+0:65                Constant:
+0:65                  0 (const uint)
+0:65              'a1' (layout( location=1) in highp 4-component vector of float)
+0:69      switch
+0:69      condition
+0:69        Constant:
+0:69          -1 (const int)
+0:69      body
+0:69        Sequence
+0:70          case:  with expression
+0:70            Constant:
+0:70              4294967295 (const uint)
+0:?           Sequence
+0:71            move second child to first child ( temp highp 4-component vector of float)
+0:71              gl_Position: direct index for structure ( gl_Position highp 4-component vector of float Position)
+0:71                'anon@0' ( out block{ gl_Position 4-component vector of float Position gl_Position,  gl_PointSize float PointSize gl_PointSize,  out unsized 1-element array of float ClipDistance gl_ClipDistance,  out unsized 1-element array of float CullDistance gl_CullDistance})
+0:71                Constant:
+0:71                  0 (const uint)
+0:71              'a2' (layout( location=2) in highp 4-component vector of float)
+0:75      switch
+0:75      condition
+0:75        Constant:
+0:75          1 (const int)
+0:75      body
+0:75        Sequence
+0:76          case:  with expression
+0:76            Constant:
+0:76              1 (const int)
+0:?           Sequence
+0:77            move second child to first child ( temp highp 4-component vector of float)
+0:77              gl_Position: direct index for structure ( gl_Position highp 4-component vector of float Position)
+0:77                'anon@0' ( out block{ gl_Position 4-component vector of float Position gl_Position,  gl_PointSize float PointSize gl_PointSize,  out unsized 1-element array of float ClipDistance gl_ClipDistance,  out unsized 1-element array of float CullDistance gl_CullDistance})
+0:77                Constant:
+0:77                  0 (const uint)
+0:77              'a3' (layout( location=3) in highp 4-component vector of float)
+0:78            Branch: Break
+0:79          case:  with expression
+0:79            Constant:
+0:79              -1 (const int)
+0:?           Sequence
+0:80            move second child to first child ( temp highp 4-component vector of float)
+0:80              gl_Position: direct index for structure ( gl_Position highp 4-component vector of float Position)
+0:80                'anon@0' ( out block{ gl_Position 4-component vector of float Position gl_Position,  gl_PointSize float PointSize gl_PointSize,  out unsized 1-element array of float ClipDistance gl_ClipDistance,  out unsized 1-element array of float CullDistance gl_CullDistance})
+0:80                Constant:
+0:80                  0 (const uint)
+0:80              'n6' (layout( location=17) in highp 4-component vector of float)
+0:84      switch
+0:84      condition
+0:84        Constant:
+0:84          1 (const int)
+0:84      body
+0:84        Sequence
+0:85          default: 
+0:86          case:  with expression
+0:86            Constant:
+0:86              2 (const int)
+0:?           Sequence
+0:87            move second child to first child ( temp highp 4-component vector of float)
+0:87              gl_Position: direct index for structure ( gl_Position highp 4-component vector of float Position)
+0:87                'anon@0' ( out block{ gl_Position 4-component vector of float Position gl_Position,  gl_PointSize float PointSize gl_PointSize,  out unsized 1-element array of float ClipDistance gl_ClipDistance,  out unsized 1-element array of float CullDistance gl_CullDistance})
+0:87                Constant:
+0:87                  0 (const uint)
+0:87              'a4' (layout( location=4) in highp 4-component vector of float)
+0:91      switch
+0:91      condition
+0:91        Constant:
+0:91          1 (const int)
+0:91      body
+0:91        Sequence
+0:92          case:  with expression
+0:92            Constant:
+0:92              1 (const int)
+0:?           Sequence
+0:93            move second child to first child ( temp highp 4-component vector of float)
+0:93              gl_Position: direct index for structure ( gl_Position highp 4-component vector of float Position)
+0:93                'anon@0' ( out block{ gl_Position 4-component vector of float Position gl_Position,  gl_PointSize float PointSize gl_PointSize,  out unsized 1-element array of float ClipDistance gl_ClipDistance,  out unsized 1-element array of float CullDistance gl_CullDistance})
+0:93                Constant:
+0:93                  0 (const uint)
+0:93              'a5' (layout( location=5) in highp 4-component vector of float)
+0:94            Branch: Break
+0:95          case:  with expression
+0:95            Constant:
+0:95              2 (const int)
+0:?           Sequence
+0:96            move second child to first child ( temp highp 4-component vector of float)
+0:96              gl_Position: direct index for structure ( gl_Position highp 4-component vector of float Position)
+0:96                'anon@0' ( out block{ gl_Position 4-component vector of float Position gl_Position,  gl_PointSize float PointSize gl_PointSize,  out unsized 1-element array of float ClipDistance gl_ClipDistance,  out unsized 1-element array of float CullDistance gl_CullDistance})
+0:96                Constant:
+0:96                  0 (const uint)
+0:96              'n7' (layout( location=18) in highp 4-component vector of float)
+0:100      switch
+0:100      condition
+0:100        Constant:
+0:100          8 (const int)
+0:100      body
+0:100        Sequence
+0:101          case:  with expression
+0:101            Constant:
+0:101              8 (const int)
+0:?           Sequence
+0:102            move second child to first child ( temp highp 4-component vector of float)
+0:102              gl_Position: direct index for structure ( gl_Position highp 4-component vector of float Position)
+0:102                'anon@0' ( out block{ gl_Position 4-component vector of float Position gl_Position,  gl_PointSize float PointSize gl_PointSize,  out unsized 1-element array of float ClipDistance gl_ClipDistance,  out unsized 1-element array of float CullDistance gl_CullDistance})
+0:102                Constant:
+0:102                  0 (const uint)
+0:102              'a6' (layout( location=6) in highp 4-component vector of float)
+0:103            Branch: Break
+0:104          case:  with expression
+0:104            Constant:
+0:104              7 (const int)
+0:?           Sequence
+0:105            move second child to first child ( temp highp 4-component vector of float)
+0:105              gl_Position: direct index for structure ( gl_Position highp 4-component vector of float Position)
+0:105                'anon@0' ( out block{ gl_Position 4-component vector of float Position gl_Position,  gl_PointSize float PointSize gl_PointSize,  out unsized 1-element array of float ClipDistance gl_ClipDistance,  out unsized 1-element array of float CullDistance gl_CullDistance})
+0:105                Constant:
+0:105                  0 (const uint)
+0:105              'n8' (layout( location=19) in highp 4-component vector of float)
+0:106            Branch: Break
+0:109      Sequence
+0:109        move second child to first child ( temp highp int)
+0:109          'x' ( temp highp int)
+0:109          Constant:
+0:109            2 (const int)
+0:112      switch
+0:112      condition
+0:112        'x' ( temp highp int)
+0:112      body
+0:112        Sequence
+0:113          case:  with expression
+0:113            Constant:
+0:113              1 (const int)
+0:?           Sequence
+0:114            move second child to first child ( temp highp 4-component vector of float)
+0:114              gl_Position: direct index for structure ( gl_Position highp 4-component vector of float Position)
+0:114                'anon@0' ( out block{ gl_Position 4-component vector of float Position gl_Position,  gl_PointSize float PointSize gl_PointSize,  out unsized 1-element array of float ClipDistance gl_ClipDistance,  out unsized 1-element array of float CullDistance gl_CullDistance})
+0:114                Constant:
+0:114                  0 (const uint)
+0:114              'a7' (layout( location=7) in highp 4-component vector of float)
+0:115            Branch: Break
+0:116          case:  with expression
+0:116            Constant:
+0:116              2 (const int)
+0:?           Sequence
+0:117            move second child to first child ( temp highp 4-component vector of float)
+0:117              gl_Position: direct index for structure ( gl_Position highp 4-component vector of float Position)
+0:117                'anon@0' ( out block{ gl_Position 4-component vector of float Position gl_Position,  gl_PointSize float PointSize gl_PointSize,  out unsized 1-element array of float ClipDistance gl_ClipDistance,  out unsized 1-element array of float CullDistance gl_CullDistance})
+0:117                Constant:
+0:117                  0 (const uint)
+0:117              'a8' (layout( location=8) in highp 4-component vector of float)
+0:118            Branch: Break
+0:122      switch
+0:122      condition
+0:122        add ( temp highp int)
+0:122          Constant:
+0:122            1 (const int)
+0:122          'x' ( temp highp int)
+0:122      body
+0:122        Sequence
+0:123          case:  with expression
+0:123            Constant:
+0:123              1 (const int)
+0:?           Sequence
+0:124            move second child to first child ( temp highp 4-component vector of float)
+0:124              gl_Position: direct index for structure ( gl_Position highp 4-component vector of float Position)
+0:124                'anon@0' ( out block{ gl_Position 4-component vector of float Position gl_Position,  gl_PointSize float PointSize gl_PointSize,  out unsized 1-element array of float ClipDistance gl_ClipDistance,  out unsized 1-element array of float CullDistance gl_CullDistance})
+0:124                Constant:
+0:124                  0 (const uint)
+0:124              'a9' (layout( location=9) in highp 4-component vector of float)
+0:125            Branch: Break
+0:126          case:  with expression
+0:126            Constant:
+0:126              3 (const int)
+0:?           Sequence
+0:127            move second child to first child ( temp highp 4-component vector of float)
+0:127              gl_Position: direct index for structure ( gl_Position highp 4-component vector of float Position)
+0:127                'anon@0' ( out block{ gl_Position 4-component vector of float Position gl_Position,  gl_PointSize float PointSize gl_PointSize,  out unsized 1-element array of float ClipDistance gl_ClipDistance,  out unsized 1-element array of float CullDistance gl_CullDistance})
+0:127                Constant:
+0:127                  0 (const uint)
+0:127              'a10' (layout( location=10) in highp 4-component vector of float)
+0:128            Branch: Break
+0:?   Linker Objects
+0:?     'a0' (layout( location=0) in highp 4-component vector of float)
+0:?     'a1' (layout( location=1) in highp 4-component vector of float)
+0:?     'a2' (layout( location=2) in highp 4-component vector of float)
+0:?     'a3' (layout( location=3) in highp 4-component vector of float)
+0:?     'a4' (layout( location=4) in highp 4-component vector of float)
+0:?     'a5' (layout( location=5) in highp 4-component vector of float)
+0:?     'a6' (layout( location=6) in highp 4-component vector of float)
+0:?     'a7' (layout( location=7) in highp 4-component vector of float)
+0:?     'a8' (layout( location=8) in highp 4-component vector of float)
+0:?     'a9' (layout( location=9) in highp 4-component vector of float)
+0:?     'a10' (layout( location=10) in highp 4-component vector of float)
+0:?     'n0' (layout( location=11) in highp 4-component vector of float)
+0:?     'n1' (layout( location=12) in highp 4-component vector of float)
+0:?     'n2' (layout( location=13) in highp 4-component vector of float)
+0:?     'n3' (layout( location=14) in highp 4-component vector of float)
+0:?     'n4' (layout( location=15) in highp 4-component vector of float)
+0:?     'n5' (layout( location=16) in highp 4-component vector of float)
+0:?     'n6' (layout( location=17) in highp 4-component vector of float)
+0:?     'n7' (layout( location=18) in highp 4-component vector of float)
+0:?     'n8' (layout( location=19) in highp 4-component vector of float)
+0:?     'n9' (layout( location=20) in highp 4-component vector of float)
+0:?     'anon@0' ( out block{ gl_Position 4-component vector of float Position gl_Position,  gl_PointSize float PointSize gl_PointSize,  out unsized 1-element array of float ClipDistance gl_ClipDistance,  out unsized 1-element array of float CullDistance gl_CullDistance})
+
+SPIR-V is not generated for failed compile or link

+ 130 - 0
Test/liveTraverser.switch.vert

@@ -0,0 +1,130 @@
+#version 460
+
+layout(location = 0) in vec4 a0; // accessed
+layout(location = 1) in vec4 a1; // accessed
+layout(location = 2) in vec4 a2; // accessed
+layout(location = 3) in vec4 a3; // accessed
+layout(location = 4) in vec4 a4; // accessed
+layout(location = 5) in vec4 a5; // accessed
+layout(location = 6) in vec4 a6; // accessed
+layout(location = 7) in vec4 a7; // accessed
+layout(location = 8) in vec4 a8; // accessed
+layout(location = 9) in vec4 a9; // accessed
+layout(location = 10) in vec4 a10; // accessed
+layout(location = 11) in vec4 n0; // not accessed
+layout(location = 12) in vec4 n1; // not accessed
+layout(location = 13) in vec4 n2; // not accessed
+layout(location = 14) in vec4 n3; // not accessed
+layout(location = 15) in vec4 n4; // not accessed
+layout(location = 16) in vec4 n5; // not accessed
+layout(location = 17) in vec4 n6; // not accessed
+layout(location = 18) in vec4 n7; // not accessed
+layout(location = 19) in vec4 n8; // not accessed
+layout(location = 20) in vec4 n9; // not accessed
+
+void main() {
+    // empty case is live
+    switch (2) {
+    case 2: break;
+    case 1:
+        gl_Position = n0;
+    }
+
+    // empty default case is live
+    switch (3) {
+    default: break;
+    case 1:
+        gl_Position = n1;
+    }
+
+    // no live case
+    switch (3) {
+    case 2: // fallthrough
+    case 1:
+        gl_Position = n2;
+    }
+
+    // ensure break is handled correctly
+    switch (1) {
+    case -1:
+        gl_Position = n3;
+        break;
+    case 1:
+        gl_Position = a0;
+        break;
+        gl_Position = n4;
+    case 0:
+        gl_Position = n5;
+    }
+
+    const int cx = 1;
+
+    // signed/unsigned mismatch
+    switch (cx) {
+    case uint(1):
+        gl_Position = a1;
+    }
+
+    // signed/unsigned conversion
+    switch (-1) {
+    case ~uint(0):
+        gl_Position = a2;
+    }
+
+    // const variable case
+    switch (1) {
+    case cx:
+        gl_Position = a3;
+        break;
+    case -1:
+        gl_Position = n6;
+    }
+
+    // fallthrough with const variable
+    switch (cx) {
+    default: // fallthrough
+    case 2:
+        gl_Position = a4;
+    }
+
+    // non-trivial constant expression
+    switch (((cx + 1) * 2) - 3) {
+    case 1:
+        gl_Position = a5;
+        break;
+    case 2:
+        gl_Position = n7;
+    }
+
+    // expression as case
+    switch (5 + 3) {
+    case 6 + 2:
+        gl_Position = a6;
+        break;
+    case 5 + 2:
+        gl_Position = n8;
+        break;
+    }
+
+    int x = 2;
+
+    // liveness of non-const variables cannot be deduced
+    switch (x) {
+    case 1:
+        gl_Position = a7;
+        break;
+    case 2:
+        gl_Position = a8;
+        break;
+    }
+
+    // const and non-const expression
+    switch (cx + x) {
+    case 1:
+        gl_Position = a9;
+        break;
+    case 3:
+        gl_Position = a10;
+        break;
+    }
+}

+ 5 - 0
glslang/Include/PoolAlloc.h

@@ -61,6 +61,8 @@
 // class as the allocator (second) template argument.
 //
 
+#include "visibility.h"
+
 #include <cstddef>
 #include <cstring>
 #include <vector>
@@ -179,6 +181,7 @@ public:
     // Call allocate() to actually acquire memory.  Returns nullptr if no memory
     // available, otherwise a properly aligned pointer to 'numBytes' of memory.
     //
+    GLSLANG_EXPORT_FOR_TESTS
     void* allocate(size_t numBytes);
 
     //
@@ -255,6 +258,7 @@ private:
 // different times.  But a simple use is to have a global pop
 // with everyone using the same global allocator.
 //
+GLSLANG_EXPORT_FOR_TESTS
 extern TPoolAllocator& GetThreadPoolAllocator();
 void SetThreadPoolAllocator(TPoolAllocator* poolAllocator);
 
@@ -289,6 +293,7 @@ public:
     template<class Other>
         pool_allocator(const pool_allocator<Other>& p) : allocator(p.getAllocator()) { }
 
+    GLSLANG_EXPORT_FOR_TESTS
     pointer allocate(size_type n) {
         return reinterpret_cast<pointer>(getAllocator().allocate(n * sizeof(T))); }
     pointer allocate(size_type n, const void*) {

+ 41 - 0
glslang/MachineIndependent/LiveTraverser.h

@@ -132,6 +132,47 @@ protected:
             return true; // traverse the whole subtree
     }
 
+    // To prune semantically dead paths in switch statements with constant expressions.
+    virtual bool visitSwitch(TVisit /* visit */, TIntermSwitch* node)
+    {
+        if (traverseAll)
+            return true; // traverse all code
+
+        TIntermConstantUnion* constant = node->getCondition()->getAsConstantUnion();
+        if (constant) {
+            TConstUnion switchValue = constant->getConstArray()[0];
+            int liveBranch = -1;
+            const auto& body = node->getBody()->getSequence();
+            for (unsigned int i = 0; i < body.size(); ++i) {
+                if (body[i]->getAsBranchNode()) {
+                    if (body[i]->getAsBranchNode()->getFlowOp() == glslang::EOpCase) {
+                        TConstUnion caseValue =
+                            body[i]->getAsBranchNode()->getExpression()->getAsConstantUnion()->getConstArray()[0];
+                        if (switchValue == caseValue.getIConst()) {
+                            liveBranch = (int)i;
+                            break;
+                        }
+                    } else if (body[i]->getAsBranchNode()->getFlowOp() == glslang::EOpDefault) {
+                        liveBranch = (int)i;
+                    }
+                }
+            }
+            if (liveBranch != -1) {
+                for (int i = liveBranch; i < (int)body.size(); ++i) {
+                    if (body[i]->getAsAggregate()) {
+                        for (auto* inst : body[i]->getAsAggregate()->getSequence()) {
+                            if (inst->getAsBranchNode() && (inst->getAsBranchNode()->getFlowOp() == glslang::EOpBreak))
+                                return false; // found and traversed the live case(s)
+                            inst->traverse(this);
+                        }
+                    }
+                }
+            }
+            return false; // finished traversing all cases
+        } else
+            return true; // traverse the whole subtree
+    }
+
     // Track live functions as well as uniforms, so that we don't visit dead functions
     // and only visit each function once.
     void addFunctionCall(TIntermAggregate* call)

+ 1 - 0
gtests/CMakeLists.txt

@@ -53,6 +53,7 @@ if(GLSLANG_TESTS)
             ${CMAKE_CURRENT_SOURCE_DIR}/Hlsl.FromFile.cpp
             ${CMAKE_CURRENT_SOURCE_DIR}/Link.FromFile.cpp
             ${CMAKE_CURRENT_SOURCE_DIR}/Link.FromFile.Vk.cpp
+            ${CMAKE_CURRENT_SOURCE_DIR}/LiveTraverser.FromFile.cpp
             ${CMAKE_CURRENT_SOURCE_DIR}/Pp.FromFile.cpp
             ${CMAKE_CURRENT_SOURCE_DIR}/Spv.FromFile.cpp
             ${CMAKE_CURRENT_SOURCE_DIR}/VkRelaxed.FromFile.cpp

+ 111 - 0
gtests/LiveTraverser.FromFile.cpp

@@ -0,0 +1,111 @@
+// Copyright (c) 2025 The Khronos Group Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <gtest/gtest.h>
+
+#include "TestFixture.h"
+
+#include "glslang/MachineIndependent/LiveTraverser.h"
+
+namespace glslangtest {
+namespace {
+
+struct LiveTraverserTestParams {
+    std::string fileName;
+    std::vector<std::string> liveVars;
+};
+
+using LiveTraverserTest = GlslangTest<::testing::TestWithParam<LiveTraverserTestParams>>;
+
+TEST_P(LiveTraverserTest, FromFile)
+{
+    const auto& fileName = GetParam().fileName;
+    const auto& expectedLiveVars = GetParam().liveVars;
+    const EShMessages controls = DeriveOptions(Source::GLSL, Semantics::Vulkan, Target::AST);
+    GlslangResult result;
+    result.validationResult = true;
+
+    std::string contents;
+    tryLoadFile(GlobalTestSettings.testRoot + "/" + fileName, "input", &contents);
+    std::unique_ptr<glslang::TShader> shader = std::make_unique<glslang::TShader>(GetShaderStage(GetSuffix(fileName)));
+
+    bool success = compile(shader.get(), contents, "", controls);
+    result.shaderResults.push_back({fileName, shader->getInfoLog(), shader->getInfoDebugLog()});
+
+    std::ostringstream stream;
+    outputResultToStream(&stream, result, controls);
+
+    class TLiveSymbolTraverser : public glslang::TLiveTraverser {
+    public:
+        TLiveSymbolTraverser(const glslang::TIntermediate& i, std::vector<std::string>& liveVars)
+            : glslang::TLiveTraverser(i), liveVars(liveVars)
+        {
+        }
+
+        virtual void visitSymbol(glslang::TIntermSymbol* symbol)
+        {
+            if (symbol->getAsSymbolNode()->getAccessName().compare(0, 3, "gl_") == 0)
+                return;
+
+            if (symbol->getQualifier().storage == glslang::TStorageQualifier::EvqVaryingIn ||
+                symbol->getQualifier().storage == glslang::TStorageQualifier::EvqVaryingOut ||
+                symbol->getQualifier().storage == glslang::TStorageQualifier::EvqUniform ||
+                symbol->getQualifier().storage == glslang::TStorageQualifier::EvqBuffer) {
+                liveVars.push_back(symbol->getAccessName().c_str());
+            }
+        }
+
+    private:
+        std::vector<std::string>& liveVars;
+    };
+
+    if (success) {
+        std::vector<std::string> actualLiveVars;
+        TLiveSymbolTraverser liveTraverser(*shader->getIntermediate(), actualLiveVars);
+        liveTraverser.pushFunction(shader->getIntermediate()->getEntryPointMangledName().c_str());
+        while (!liveTraverser.destinations.empty()) {
+            TIntermNode* destination = liveTraverser.destinations.back();
+            liveTraverser.destinations.pop_back();
+            destination->traverse(&liveTraverser);
+        }
+
+        for (const auto& expectedVar : expectedLiveVars) {
+            auto it = std::find(actualLiveVars.begin(), actualLiveVars.end(), expectedVar);
+            EXPECT_NE(it, actualLiveVars.end());
+            if (it != actualLiveVars.end())
+                actualLiveVars.erase(it);
+        }
+        EXPECT_TRUE(actualLiveVars.empty());
+    }
+
+    // Check with expected results.
+    const std::string expectedOutputFname = GlobalTestSettings.testRoot + "/baseResults/" + fileName + ".out";
+    std::string expectedOutput;
+    tryLoadFile(expectedOutputFname, "expected output", &expectedOutput);
+
+    checkEqAndUpdateIfRequested(expectedOutput, stream.str(), expectedOutputFname, result.spirvWarningsErrors);
+}
+
+// clang-format off
+INSTANTIATE_TEST_SUITE_P(
+    Glsl, LiveTraverserTest,
+    ::testing::ValuesIn(std::vector<LiveTraverserTestParams>({
+        {"liveTraverser.switch.vert", {"a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7", "a8", "a9", "a10"}},
+        // TODO: implement test for if statements
+    }))
+);
+// clang-format on
+
+} // anonymous namespace
+} // namespace glslangtest