Line data Source code
1 : //
2 : // Copyright (c) 2002-2015 The ANGLE Project Authors. All rights reserved.
3 : // Use of this source code is governed by a BSD-style license that can be
4 : // found in the LICENSE file.
5 : //
6 : // The PruneEmptyDeclarations function prunes unnecessary empty declarations and declarators from the AST.
7 :
8 : #include "compiler/translator/PruneEmptyDeclarations.h"
9 :
10 : #include "compiler/translator/IntermNode.h"
11 :
12 : namespace sh
13 : {
14 :
15 : namespace
16 : {
17 :
18 0 : class PruneEmptyDeclarationsTraverser : private TIntermTraverser
19 : {
20 : public:
21 : static void apply(TIntermNode *root);
22 : private:
23 : PruneEmptyDeclarationsTraverser();
24 : bool visitDeclaration(Visit, TIntermDeclaration *node) override;
25 : };
26 :
27 0 : void PruneEmptyDeclarationsTraverser::apply(TIntermNode *root)
28 : {
29 0 : PruneEmptyDeclarationsTraverser prune;
30 0 : root->traverse(&prune);
31 0 : prune.updateTree();
32 0 : }
33 :
34 0 : PruneEmptyDeclarationsTraverser::PruneEmptyDeclarationsTraverser()
35 0 : : TIntermTraverser(true, false, false)
36 : {
37 0 : }
38 :
39 0 : bool PruneEmptyDeclarationsTraverser::visitDeclaration(Visit, TIntermDeclaration *node)
40 : {
41 0 : TIntermSequence *sequence = node->getSequence();
42 0 : if (sequence->size() >= 1)
43 : {
44 0 : TIntermSymbol *sym = sequence->front()->getAsSymbolNode();
45 : // Prune declarations without a variable name, unless it's an interface block declaration.
46 0 : if (sym != nullptr && sym->getSymbol() == "" && !sym->isInterfaceBlock())
47 : {
48 0 : if (sequence->size() > 1)
49 : {
50 : // Generate a replacement that will remove the empty declarator in the beginning of
51 : // a declarator list. Example of a declaration that will be changed:
52 : // float, a;
53 : // will be changed to
54 : // float a;
55 : // This applies also to struct declarations.
56 0 : TIntermSequence emptyReplacement;
57 0 : mMultiReplacements.push_back(
58 0 : NodeReplaceWithMultipleEntry(node, sym, emptyReplacement));
59 : }
60 0 : else if (sym->getBasicType() != EbtStruct)
61 : {
62 : // Single struct declarations may just declare the struct type and no variables, so
63 : // they should not be pruned. All other single empty declarations can be pruned
64 : // entirely. Example of an empty declaration that will be pruned:
65 : // float;
66 0 : TIntermSequence emptyReplacement;
67 0 : TIntermBlock *parentAsBlock = getParentNode()->getAsBlock();
68 : // The declaration may be inside a block or in a loop init expression.
69 0 : ASSERT(parentAsBlock != nullptr || getParentNode()->getAsLoopNode() != nullptr);
70 0 : if (parentAsBlock)
71 : {
72 0 : mMultiReplacements.push_back(
73 0 : NodeReplaceWithMultipleEntry(parentAsBlock, node, emptyReplacement));
74 : }
75 : else
76 : {
77 0 : queueReplacement(node, nullptr, OriginalNode::IS_DROPPED);
78 : }
79 : }
80 0 : else if (sym->getType().getQualifier() != EvqGlobal &&
81 0 : sym->getType().getQualifier() != EvqTemporary)
82 : {
83 : // We've hit an empty struct declaration with a qualifier, for example like
84 : // this:
85 : // const struct a { int i; };
86 : // NVIDIA GL driver version 367.27 doesn't accept this kind of declarations, so
87 : // we convert the declaration to a regular struct declaration. This is okay,
88 : // since ESSL 1.00 spec section 4.1.8 says about structs that "The optional
89 : // qualifiers only apply to any declarators, and are not part of the type being
90 : // defined for name."
91 :
92 0 : if (mInGlobalScope)
93 : {
94 0 : sym->getTypePointer()->setQualifier(EvqGlobal);
95 : }
96 : else
97 : {
98 0 : sym->getTypePointer()->setQualifier(EvqTemporary);
99 : }
100 : }
101 : }
102 : }
103 0 : return false;
104 : }
105 :
106 : } // namespace
107 :
108 0 : void PruneEmptyDeclarations(TIntermNode *root)
109 : {
110 0 : PruneEmptyDeclarationsTraverser::apply(root);
111 0 : }
112 :
113 : } // namespace sh
|