// // Copyright 2020 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // #include #include "compiler/translator/TranslatorMetalDirect/AstHelpers.h" #include "compiler/translator/TranslatorMetalDirect/SeparateCompoundStructDeclarations.h" #include "compiler/translator/tree_ops/SeparateDeclarations.h" #include "compiler/translator/tree_util/IntermTraverse.h" using namespace sh; //////////////////////////////////////////////////////////////////////////////// namespace { class Separator : public TIntermTraverser { public: std::unordered_map replacementMap; Separator(TSymbolTable &symbolTable, IdGen &idGen) : TIntermTraverser(false, false, true, &symbolTable), mIdGen(idGen) {} IdGen &mIdGen; bool visitDeclaration(Visit, TIntermDeclaration *declNode) override { ASSERT(declNode->getChildCount() == 1); Declaration declaration = ViewDeclaration(*declNode); const TVariable &var = declaration.symbol.variable(); const TType &type = var.getType(); const SymbolType symbolType = var.symbolType(); if (type.isStructSpecifier() && symbolType != SymbolType::Empty) { const TStructure *structure = type.getStruct(); TVariable *structVar = nullptr; TType *instanceType = nullptr; // Name unnamed inline structs if (structure->symbolType() == SymbolType::Empty) { const TStructure *structDefn = new TStructure(mSymbolTable, mIdGen.createNewName().rawName(), &structure->fields(), SymbolType::AngleInternal); structVar = new TVariable(mSymbolTable, ImmutableString(""), new TType(structDefn, true), SymbolType::Empty); instanceType = new TType(structDefn, false); } else { structVar = new TVariable(mSymbolTable, ImmutableString(""), new TType(structure, true), SymbolType::Empty); instanceType = new TType(structure, false); } if (type.isArray()) { instanceType->makeArrays(type.getArraySizes()); } instanceType->setQualifier(type.getQualifier()); auto *instanceVar = new TVariable(mSymbolTable, var.name(), instanceType, symbolType, var.extensions()); TIntermSequence replacements; replacements.push_back(new TIntermDeclaration({structVar})); TIntermSymbol *instanceSymbol = new TIntermSymbol(instanceVar); TIntermDeclaration *instanceDecl = new TIntermDeclaration; if (declaration.initExpr) { instanceDecl->appendDeclarator(new TIntermBinary( TOperator::EOpInitialize, instanceSymbol, declaration.initExpr)); } else { instanceDecl->appendDeclarator(instanceSymbol); } replacements.push_back(instanceDecl); replacementMap[declaration.symbol.uniqueId().get()] = instanceSymbol; ASSERT(getParentNode() != nullptr); ASSERT(getParentNode()->getAsBlock() != nullptr); mMultiReplacements.push_back(NodeReplaceWithMultipleEntry( getParentNode()->getAsBlock(), declNode, std::move(replacements))); } return false; } void visitSymbol(TIntermSymbol *decl) override { auto symbol = replacementMap.find(decl->uniqueId().get()); if (symbol != replacementMap.end()) { queueReplacement(symbol->second->deepCopy(), OriginalNode::IS_DROPPED); } } }; } // anonymous namespace //////////////////////////////////////////////////////////////////////////////// bool sh::SeparateCompoundStructDeclarations(TCompiler &compiler, IdGen &idGen, TIntermBlock &root, TSymbolTable *symbolTable) { Separator separator(compiler.getSymbolTable(), idGen); root.traverse(&separator); if (!separator.updateTree(&compiler, &root)) { return false; } if (!SeparateDeclarations(&compiler, &root, symbolTable)) { return false; } return true; }