blob: c763d2e0a0c5646b60a10d4d31472b6e7c82125c [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//
Jamie Madilld7b1ab52016-12-12 14:42:19 -05006// The PruneEmptyDeclarations function prunes unnecessary empty declarations and declarators from
7// the AST.
Olli Etuahoc6833112015-04-22 15:15:54 +03008
9#include "compiler/translator/PruneEmptyDeclarations.h"
10
Olli Etuahocccf2b02017-07-05 14:50:54 +030011#include "compiler/translator/IntermTraverse.h"
Olli Etuahoc6833112015-04-22 15:15:54 +030012
Jamie Madill45bcc782016-11-07 13:58:48 -050013namespace sh
14{
15
Olli Etuahoc6833112015-04-22 15:15:54 +030016namespace
17{
18
19class PruneEmptyDeclarationsTraverser : private TIntermTraverser
20{
21 public:
Olli Etuaho923ecef2017-10-11 12:01:38 +030022 static void apply(TIntermBlock *root);
Jamie Madilld7b1ab52016-12-12 14:42:19 -050023
Olli Etuahoc6833112015-04-22 15:15:54 +030024 private:
25 PruneEmptyDeclarationsTraverser();
Olli Etuaho13389b62016-10-16 11:48:18 +010026 bool visitDeclaration(Visit, TIntermDeclaration *node) override;
Olli Etuahoc6833112015-04-22 15:15:54 +030027};
28
Olli Etuaho923ecef2017-10-11 12:01:38 +030029void PruneEmptyDeclarationsTraverser::apply(TIntermBlock *root)
Olli Etuahoc6833112015-04-22 15:15:54 +030030{
31 PruneEmptyDeclarationsTraverser prune;
32 root->traverse(&prune);
33 prune.updateTree();
34}
35
36PruneEmptyDeclarationsTraverser::PruneEmptyDeclarationsTraverser()
37 : TIntermTraverser(true, false, false)
38{
39}
40
Olli Etuaho13389b62016-10-16 11:48:18 +010041bool PruneEmptyDeclarationsTraverser::visitDeclaration(Visit, TIntermDeclaration *node)
Olli Etuahoc6833112015-04-22 15:15:54 +030042{
Olli Etuaho13389b62016-10-16 11:48:18 +010043 TIntermSequence *sequence = node->getSequence();
44 if (sequence->size() >= 1)
Olli Etuahoc6833112015-04-22 15:15:54 +030045 {
Olli Etuaho13389b62016-10-16 11:48:18 +010046 TIntermSymbol *sym = sequence->front()->getAsSymbolNode();
47 // Prune declarations without a variable name, unless it's an interface block declaration.
48 if (sym != nullptr && sym->getSymbol() == "" && !sym->isInterfaceBlock())
Olli Etuahoc6833112015-04-22 15:15:54 +030049 {
Olli Etuaho13389b62016-10-16 11:48:18 +010050 if (sequence->size() > 1)
Olli Etuahoc6833112015-04-22 15:15:54 +030051 {
Olli Etuaho13389b62016-10-16 11:48:18 +010052 // Generate a replacement that will remove the empty declarator in the beginning of
53 // a declarator list. Example of a declaration that will be changed:
54 // float, a;
55 // will be changed to
56 // float a;
57 // This applies also to struct declarations.
58 TIntermSequence emptyReplacement;
59 mMultiReplacements.push_back(
60 NodeReplaceWithMultipleEntry(node, sym, emptyReplacement));
61 }
62 else if (sym->getBasicType() != EbtStruct)
63 {
64 // Single struct declarations may just declare the struct type and no variables, so
Olli Etuaho923ecef2017-10-11 12:01:38 +030065 // they should not be pruned. If there are entirely empty non-struct declarations,
66 // they result in TIntermDeclaration nodes without any children in the parsing
67 // stage. This will be handled further down in the code.
68 UNREACHABLE();
Olli Etuaho13389b62016-10-16 11:48:18 +010069 }
70 else if (sym->getType().getQualifier() != EvqGlobal &&
71 sym->getType().getQualifier() != EvqTemporary)
72 {
73 // We've hit an empty struct declaration with a qualifier, for example like
74 // this:
75 // const struct a { int i; };
76 // NVIDIA GL driver version 367.27 doesn't accept this kind of declarations, so
77 // we convert the declaration to a regular struct declaration. This is okay,
78 // since ESSL 1.00 spec section 4.1.8 says about structs that "The optional
79 // qualifiers only apply to any declarators, and are not part of the type being
80 // defined for name."
Olli Etuaho474a08c02016-06-28 10:49:46 +030081
Olli Etuaho13389b62016-10-16 11:48:18 +010082 if (mInGlobalScope)
83 {
84 sym->getTypePointer()->setQualifier(EvqGlobal);
85 }
86 else
87 {
88 sym->getTypePointer()->setQualifier(EvqTemporary);
Olli Etuaho474a08c02016-06-28 10:49:46 +030089 }
Olli Etuahoc6833112015-04-22 15:15:54 +030090 }
91 }
Olli Etuahoc6833112015-04-22 15:15:54 +030092 }
Olli Etuaho923ecef2017-10-11 12:01:38 +030093 else
94 {
95 // We have a declaration with no declarators.
96 // The declaration may be either inside a block or in a loop init expression.
97 TIntermBlock *parentAsBlock = getParentNode()->getAsBlock();
98 ASSERT(parentAsBlock != nullptr || getParentNode()->getAsLoopNode() != nullptr);
99 if (parentAsBlock)
100 {
101 TIntermSequence emptyReplacement;
102 mMultiReplacements.push_back(
103 NodeReplaceWithMultipleEntry(parentAsBlock, node, emptyReplacement));
104 }
105 else
106 {
107 queueReplacement(nullptr, OriginalNode::IS_DROPPED);
108 }
109 }
Olli Etuaho13389b62016-10-16 11:48:18 +0100110 return false;
Olli Etuahoc6833112015-04-22 15:15:54 +0300111}
112
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500113} // namespace
Olli Etuahoc6833112015-04-22 15:15:54 +0300114
Olli Etuaho923ecef2017-10-11 12:01:38 +0300115void PruneEmptyDeclarations(TIntermBlock *root)
Olli Etuahoc6833112015-04-22 15:15:54 +0300116{
117 PruneEmptyDeclarationsTraverser::apply(root);
118}
Jamie Madill45bcc782016-11-07 13:58:48 -0500119
120} // namespace sh