blob: 4763dd6ededdfd5a55f8121967981f8918fca8ca [file] [log] [blame]
Olli Etuahoc6833112015-04-22 15:15:54 +03001//
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
12namespace
13{
14
15class PruneEmptyDeclarationsTraverser : private TIntermTraverser
16{
17 public:
18 static void apply(TIntermNode *root);
19 private:
20 PruneEmptyDeclarationsTraverser();
21 bool visitAggregate(Visit, TIntermAggregate *node) override;
22};
23
24void PruneEmptyDeclarationsTraverser::apply(TIntermNode *root)
25{
26 PruneEmptyDeclarationsTraverser prune;
27 root->traverse(&prune);
28 prune.updateTree();
29}
30
31PruneEmptyDeclarationsTraverser::PruneEmptyDeclarationsTraverser()
32 : TIntermTraverser(true, false, false)
33{
34}
35
36bool PruneEmptyDeclarationsTraverser::visitAggregate(Visit, TIntermAggregate *node)
37{
38 if (node->getOp() == EOpDeclaration)
39 {
40 TIntermSequence *sequence = node->getSequence();
41 if (sequence->size() >= 1)
42 {
43 TIntermSymbol *sym = sequence->front()->getAsSymbolNode();
44 // Prune declarations without a variable name, unless it's an interface block declaration.
45 if (sym != nullptr && sym->getSymbol() == "" && !sym->isInterfaceBlock())
46 {
47 if (sequence->size() > 1)
48 {
49 // Generate a replacement that will remove the empty declarator in the beginning of a declarator
50 // list. Example of a declaration that will be changed:
51 // float, a;
52 // will be changed to
53 // float a;
54 // This applies also to struct declarations.
55 TIntermSequence emptyReplacement;
56 mMultiReplacements.push_back(NodeReplaceWithMultipleEntry(node, sym, emptyReplacement));
57 }
58 else if (sym->getBasicType() != EbtStruct)
59 {
60 // Single struct declarations may just declare the struct type and no variables, so they should
61 // not be pruned. All other single empty declarations can be pruned entirely. Example of an empty
62 // declaration that will be pruned:
63 // float;
64 TIntermSequence emptyReplacement;
Olli Etuaho6d40bbd2016-09-30 13:49:38 +010065 TIntermBlock *parentAsBlock = getParentNode()->getAsBlock();
Olli Etuaho635671d2016-10-20 07:57:36 -070066 // The declaration may be inside a block or in a loop init expression.
67 ASSERT(parentAsBlock != nullptr || getParentNode()->getAsLoopNode() != nullptr);
68 if (parentAsBlock)
69 {
70 mMultiReplacements.push_back(
71 NodeReplaceWithMultipleEntry(parentAsBlock, node, emptyReplacement));
72 }
73 else
74 {
75 queueReplacement(node, nullptr, OriginalNode::IS_DROPPED);
76 }
Olli Etuahoc6833112015-04-22 15:15:54 +030077 }
Olli Etuaho474a08c02016-06-28 10:49:46 +030078 else if (sym->getType().getQualifier() != EvqGlobal &&
79 sym->getType().getQualifier() != EvqTemporary)
80 {
81 // We've hit an empty struct declaration with a qualifier, for example like
82 // this:
83 // const struct a { int i; };
84 // NVIDIA GL driver version 367.27 doesn't accept this kind of declarations, so
85 // we convert the declaration to a regular struct declaration. This is okay,
86 // since ESSL 1.00 spec section 4.1.8 says about structs that "The optional
87 // qualifiers only apply to any declarators, and are not part of the type being
88 // defined for name."
89
90 if (mInGlobalScope)
91 {
92 sym->getTypePointer()->setQualifier(EvqGlobal);
93 }
94 else
95 {
96 sym->getTypePointer()->setQualifier(EvqTemporary);
97 }
98 }
Olli Etuahoc6833112015-04-22 15:15:54 +030099 }
100 }
101 return false;
102 }
103 return true;
104}
105
106} // namespace
107
108void PruneEmptyDeclarations(TIntermNode *root)
109{
110 PruneEmptyDeclarationsTraverser::apply(root);
111}