blob: 133130d206e7c5f9b67ebc394d2ebe5614fa7f50 [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();
Olli Etuaho13389b62016-10-16 11:48:18 +010021 bool visitDeclaration(Visit, TIntermDeclaration *node) override;
Olli Etuahoc6833112015-04-22 15:15:54 +030022};
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
Olli Etuaho13389b62016-10-16 11:48:18 +010036bool PruneEmptyDeclarationsTraverser::visitDeclaration(Visit, TIntermDeclaration *node)
Olli Etuahoc6833112015-04-22 15:15:54 +030037{
Olli Etuaho13389b62016-10-16 11:48:18 +010038 TIntermSequence *sequence = node->getSequence();
39 if (sequence->size() >= 1)
Olli Etuahoc6833112015-04-22 15:15:54 +030040 {
Olli Etuaho13389b62016-10-16 11:48:18 +010041 TIntermSymbol *sym = sequence->front()->getAsSymbolNode();
42 // Prune declarations without a variable name, unless it's an interface block declaration.
43 if (sym != nullptr && sym->getSymbol() == "" && !sym->isInterfaceBlock())
Olli Etuahoc6833112015-04-22 15:15:54 +030044 {
Olli Etuaho13389b62016-10-16 11:48:18 +010045 if (sequence->size() > 1)
Olli Etuahoc6833112015-04-22 15:15:54 +030046 {
Olli Etuaho13389b62016-10-16 11:48:18 +010047 // Generate a replacement that will remove the empty declarator in the beginning of
48 // a declarator list. Example of a declaration that will be changed:
49 // float, a;
50 // will be changed to
51 // float a;
52 // This applies also to struct declarations.
53 TIntermSequence emptyReplacement;
54 mMultiReplacements.push_back(
55 NodeReplaceWithMultipleEntry(node, sym, emptyReplacement));
56 }
57 else if (sym->getBasicType() != EbtStruct)
58 {
59 // Single struct declarations may just declare the struct type and no variables, so
60 // they should not be pruned. All other single empty declarations can be pruned
61 // entirely. Example of an empty declaration that will be pruned:
62 // float;
63 TIntermSequence emptyReplacement;
64 TIntermBlock *parentAsBlock = getParentNode()->getAsBlock();
65 // The declaration may be inside a block or in a loop init expression.
66 ASSERT(parentAsBlock != nullptr || getParentNode()->getAsLoopNode() != nullptr);
67 if (parentAsBlock)
Olli Etuahoc6833112015-04-22 15:15:54 +030068 {
Olli Etuaho13389b62016-10-16 11:48:18 +010069 mMultiReplacements.push_back(
70 NodeReplaceWithMultipleEntry(parentAsBlock, node, emptyReplacement));
Olli Etuahoc6833112015-04-22 15:15:54 +030071 }
Olli Etuaho13389b62016-10-16 11:48:18 +010072 else
Olli Etuahoc6833112015-04-22 15:15:54 +030073 {
Olli Etuaho13389b62016-10-16 11:48:18 +010074 queueReplacement(node, nullptr, OriginalNode::IS_DROPPED);
Olli Etuahoc6833112015-04-22 15:15:54 +030075 }
Olli Etuaho13389b62016-10-16 11:48:18 +010076 }
77 else if (sym->getType().getQualifier() != EvqGlobal &&
78 sym->getType().getQualifier() != EvqTemporary)
79 {
80 // We've hit an empty struct declaration with a qualifier, for example like
81 // this:
82 // const struct a { int i; };
83 // NVIDIA GL driver version 367.27 doesn't accept this kind of declarations, so
84 // we convert the declaration to a regular struct declaration. This is okay,
85 // since ESSL 1.00 spec section 4.1.8 says about structs that "The optional
86 // qualifiers only apply to any declarators, and are not part of the type being
87 // defined for name."
Olli Etuaho474a08c02016-06-28 10:49:46 +030088
Olli Etuaho13389b62016-10-16 11:48:18 +010089 if (mInGlobalScope)
90 {
91 sym->getTypePointer()->setQualifier(EvqGlobal);
92 }
93 else
94 {
95 sym->getTypePointer()->setQualifier(EvqTemporary);
Olli Etuaho474a08c02016-06-28 10:49:46 +030096 }
Olli Etuahoc6833112015-04-22 15:15:54 +030097 }
98 }
Olli Etuahoc6833112015-04-22 15:15:54 +030099 }
Olli Etuaho13389b62016-10-16 11:48:18 +0100100 return false;
Olli Etuahoc6833112015-04-22 15:15:54 +0300101}
102
103} // namespace
104
105void PruneEmptyDeclarations(TIntermNode *root)
106{
107 PruneEmptyDeclarationsTraverser::apply(root);
108}