SeparateDeclarations.cpp (7628B)
1 // 2 // Copyright 2002 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 SeparateDeclarations function processes declarations, so that in the end each declaration 7 // contains only one declarator. 8 // This is useful as an intermediate step when initialization needs to be separated from 9 // declaration, or when things need to be unfolded out of the initializer. 10 // Example: 11 // int a[1] = int[1](1), b[1] = int[1](2); 12 // gets transformed when run through this class into the AST equivalent of: 13 // int a[1] = int[1](1); 14 // int b[1] = int[1](2); 15 16 #include "compiler/translator/tree_ops/SeparateDeclarations.h" 17 18 #include "compiler/translator/SymbolTable.h" 19 #include "compiler/translator/tree_util/IntermTraverse.h" 20 #include "compiler/translator/tree_util/ReplaceVariable.h" 21 22 namespace sh 23 { 24 25 namespace 26 { 27 28 class SeparateDeclarationsTraverser : private TIntermTraverser 29 { 30 public: 31 [[nodiscard]] static bool apply(TCompiler *compiler, 32 TIntermNode *root, 33 TSymbolTable *symbolTable); 34 35 private: 36 SeparateDeclarationsTraverser(TSymbolTable *symbolTable); 37 bool visitDeclaration(Visit, TIntermDeclaration *node) override; 38 void visitSymbol(TIntermSymbol *symbol) override; 39 40 void separateDeclarator(TIntermSequence *sequence, 41 size_t index, 42 TIntermSequence *replacementDeclarations, 43 const TStructure **replacementStructure); 44 45 VariableReplacementMap mVariableMap; 46 }; 47 48 bool SeparateDeclarationsTraverser::apply(TCompiler *compiler, 49 TIntermNode *root, 50 TSymbolTable *symbolTable) 51 { 52 SeparateDeclarationsTraverser separateDecl(symbolTable); 53 root->traverse(&separateDecl); 54 return separateDecl.updateTree(compiler, root); 55 } 56 57 SeparateDeclarationsTraverser::SeparateDeclarationsTraverser(TSymbolTable *symbolTable) 58 : TIntermTraverser(true, false, false, symbolTable) 59 {} 60 61 bool SeparateDeclarationsTraverser::visitDeclaration(Visit, TIntermDeclaration *node) 62 { 63 TIntermSequence *sequence = node->getSequence(); 64 if (sequence->size() <= 1) 65 { 66 return true; 67 } 68 69 TIntermBlock *parentBlock = getParentNode()->getAsBlock(); 70 ASSERT(parentBlock != nullptr); 71 72 TIntermSequence replacementDeclarations; 73 const TStructure *replacementStructure = nullptr; 74 for (size_t ii = 0; ii < sequence->size(); ++ii) 75 { 76 separateDeclarator(sequence, ii, &replacementDeclarations, &replacementStructure); 77 } 78 79 mMultiReplacements.emplace_back(parentBlock, node, std::move(replacementDeclarations)); 80 return false; 81 } 82 83 void SeparateDeclarationsTraverser::visitSymbol(TIntermSymbol *symbol) 84 { 85 const TVariable *variable = &symbol->variable(); 86 if (mVariableMap.count(variable) > 0) 87 { 88 queueAccessChainReplacement(mVariableMap[variable]->deepCopy()); 89 } 90 } 91 92 void SeparateDeclarationsTraverser::separateDeclarator(TIntermSequence *sequence, 93 size_t index, 94 TIntermSequence *replacementDeclarations, 95 const TStructure **replacementStructure) 96 { 97 TIntermTyped *declarator = sequence->at(index)->getAsTyped(); 98 const TType &declaratorType = declarator->getType(); 99 100 // If the declaration is not simultaneously declaring a struct, can use the same declarator. 101 // Otherwise, the first declarator is taken as-is if the struct has a name. 102 const TStructure *structure = declaratorType.getStruct(); 103 const bool isStructSpecifier = declaratorType.isStructSpecifier(); 104 if (!isStructSpecifier || (index == 0 && structure->symbolType() != SymbolType::Empty)) 105 { 106 TIntermDeclaration *replacementDeclaration = new TIntermDeclaration; 107 108 // Make sure to update the declarator's initializers if any. 109 declarator->traverse(this); 110 111 replacementDeclaration->appendDeclarator(declarator); 112 replacementDeclaration->setLine(declarator->getLine()); 113 replacementDeclarations->push_back(replacementDeclaration); 114 return; 115 } 116 117 // If the struct is nameless, split it out first. 118 if (structure->symbolType() == SymbolType::Empty) 119 { 120 if (*replacementStructure == nullptr) 121 { 122 TStructure *newStructure = 123 new TStructure(mSymbolTable, kEmptyImmutableString, &structure->fields(), 124 SymbolType::AngleInternal); 125 newStructure->setAtGlobalScope(structure->atGlobalScope()); 126 *replacementStructure = structure = newStructure; 127 128 TType *namedType = new TType(structure, true); 129 namedType->setQualifier(EvqGlobal); 130 131 TVariable *structVariable = 132 new TVariable(mSymbolTable, kEmptyImmutableString, namedType, SymbolType::Empty); 133 134 TIntermDeclaration *structDeclaration = new TIntermDeclaration; 135 structDeclaration->appendDeclarator(new TIntermSymbol(structVariable)); 136 structDeclaration->setLine(declarator->getLine()); 137 replacementDeclarations->push_back(structDeclaration); 138 } 139 else 140 { 141 structure = *replacementStructure; 142 } 143 } 144 145 // Redeclare the declarator but not as a struct specifier. 146 TIntermSymbol *asSymbol = declarator->getAsSymbolNode(); 147 TIntermTyped *initializer = nullptr; 148 if (asSymbol == nullptr) 149 { 150 TIntermBinary *asBinary = declarator->getAsBinaryNode(); 151 ASSERT(asBinary->getOp() == EOpInitialize); 152 asSymbol = asBinary->getLeft()->getAsSymbolNode(); 153 initializer = asBinary->getRight(); 154 155 // Make sure the initializer itself has its variables replaced if necessary. 156 if (initializer->getAsSymbolNode()) 157 { 158 const TVariable *initializerVariable = &initializer->getAsSymbolNode()->variable(); 159 if (mVariableMap.count(initializerVariable) > 0) 160 { 161 initializer = mVariableMap[initializerVariable]->deepCopy(); 162 } 163 } 164 else 165 { 166 initializer->traverse(this); 167 } 168 } 169 170 ASSERT(asSymbol && asSymbol->variable().symbolType() != SymbolType::Empty); 171 172 TType *newType = new TType(structure, false); 173 newType->setQualifier(asSymbol->getType().getQualifier()); 174 newType->makeArrays(asSymbol->getType().getArraySizes()); 175 176 TVariable *replacementVar = new TVariable(mSymbolTable, asSymbol->getName(), newType, 177 asSymbol->variable().symbolType()); 178 TIntermSymbol *replacementSymbol = new TIntermSymbol(replacementVar); 179 TIntermTyped *replacement = replacementSymbol; 180 if (initializer) 181 { 182 replacement = new TIntermBinary(EOpInitialize, replacement, initializer); 183 } 184 185 TIntermDeclaration *replacementDeclaration = new TIntermDeclaration; 186 replacementDeclaration->appendDeclarator(replacement); 187 replacementDeclaration->setLine(declarator->getLine()); 188 replacementDeclarations->push_back(replacementDeclaration); 189 190 mVariableMap[&asSymbol->variable()] = replacementSymbol; 191 } 192 } // namespace 193 194 bool SeparateDeclarations(TCompiler *compiler, TIntermNode *root, TSymbolTable *symbolTable) 195 { 196 return SeparateDeclarationsTraverser::apply(compiler, root, symbolTable); 197 } 198 199 } // namespace sh