• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright (C) 2016 LunarG, Inc.
3 //
4 // All rights reserved.
5 //
6 // Redistribution and use in source and binary forms, with or without
7 // modification, are permitted provided that the following conditions
8 // are met:
9 //
10 //    Redistributions of source code must retain the above copyright
11 //    notice, this list of conditions and the following disclaimer.
12 //
13 //    Redistributions in binary form must reproduce the above
14 //    copyright notice, this list of conditions and the following
15 //    disclaimer in the documentation and/or other materials provided
16 //    with the distribution.
17 //
18 //    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
19 //    contributors may be used to endorse or promote products derived
20 //    from this software without specific prior written permission.
21 //
22 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25 // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26 // COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28 // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32 // ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 // POSSIBILITY OF SUCH DAMAGE.
34 //
35 
36 #pragma once
37 
38 #include "../Include/Common.h"
39 #include "reflection.h"
40 #include "localintermediate.h"
41 
42 #include "gl_types.h"
43 
44 #include <list>
45 #include <unordered_set>
46 
47 namespace glslang {
48 
49 //
50 // The traverser: mostly pass through, except
51 //  - processing function-call nodes to push live functions onto the stack of functions to process
52 //  - processing selection nodes to trim semantically dead code
53 //
54 // This is in the glslang namespace directly so it can be a friend of TReflection.
55 // This can be derived from to implement reflection database traversers or
56 // binding mappers: anything that wants to traverse the live subset of the tree.
57 //
58 
59 class TLiveTraverser : public TIntermTraverser {
60 public:
61     TLiveTraverser(const TIntermediate& i, bool traverseAll = false,
62                    bool preVisit = true, bool inVisit = false, bool postVisit = false) :
TIntermTraverser(preVisit,inVisit,postVisit)63         TIntermTraverser(preVisit, inVisit, postVisit),
64         intermediate(i), traverseAll(traverseAll)
65     { }
66 
67     //
68     // Given a function name, find its subroot in the tree, and push it onto the stack of
69     // functions left to process.
70     //
pushFunction(const TString & name)71     void pushFunction(const TString& name)
72     {
73         TIntermSequence& globals = intermediate.getTreeRoot()->getAsAggregate()->getSequence();
74         for (unsigned int f = 0; f < globals.size(); ++f) {
75             TIntermAggregate* candidate = globals[f]->getAsAggregate();
76             if (candidate && candidate->getOp() == EOpFunction && candidate->getName() == name) {
77                 functions.push_back(candidate);
78                 break;
79             }
80         }
81     }
82 
83     typedef std::list<TIntermAggregate*> TFunctionStack;
84     TFunctionStack functions;
85 
86 protected:
87     // To catch which function calls are not dead, and hence which functions must be visited.
visitAggregate(TVisit,TIntermAggregate * node)88     virtual bool visitAggregate(TVisit, TIntermAggregate* node)
89     {
90         if (!traverseAll)
91             if (node->getOp() == EOpFunctionCall)
92                 addFunctionCall(node);
93 
94         return true; // traverse this subtree
95     }
96 
97     // To prune semantically dead paths.
visitSelection(TVisit,TIntermSelection * node)98     virtual bool visitSelection(TVisit /* visit */,  TIntermSelection* node)
99     {
100         if (traverseAll)
101             return true; // traverse all code
102 
103         TIntermConstantUnion* constant = node->getCondition()->getAsConstantUnion();
104         if (constant) {
105             // cull the path that is dead
106             if (constant->getConstArray()[0].getBConst() == true && node->getTrueBlock())
107                 node->getTrueBlock()->traverse(this);
108             if (constant->getConstArray()[0].getBConst() == false && node->getFalseBlock())
109                 node->getFalseBlock()->traverse(this);
110 
111             return false; // don't traverse any more, we did it all above
112         } else
113             return true; // traverse the whole subtree
114     }
115 
116     // Track live functions as well as uniforms, so that we don't visit dead functions
117     // and only visit each function once.
addFunctionCall(TIntermAggregate * call)118     void addFunctionCall(TIntermAggregate* call)
119     {
120         // // just use the map to ensure we process each function at most once
121         if (liveFunctions.find(call->getName()) == liveFunctions.end()) {
122             liveFunctions.insert(call->getName());
123             pushFunction(call->getName());
124         }
125     }
126 
127     const TIntermediate& intermediate;
128     typedef std::unordered_set<TString> TLiveFunctions;
129     TLiveFunctions liveFunctions;
130     bool traverseAll;
131 
132 private:
133     // prevent copy & copy construct
134     TLiveTraverser(TLiveTraverser&);
135     TLiveTraverser& operator=(TLiveTraverser&);
136 };
137 
138 } // namespace glslang
139