1 //
2 // Copyright 2020 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
7 #include "compiler/translator/TranslatorMetalDirect/HoistConstants.h"
8 #include "compiler/translator/TranslatorMetalDirect/AstHelpers.h"
9 #include "compiler/translator/TranslatorMetalDirect/IntermRebuild.h"
10 #include "compiler/translator/TranslatorMetalDirect/Layout.h"
11 #include "compiler/translator/tree_util/FindFunction.h"
12 #include "compiler/translator/tree_util/ReplaceVariable.h"
13
14 using namespace sh;
15
16 ////////////////////////////////////////////////////////////////////////////////
17
18 namespace
19 {
20
21 class Rewriter : private TIntermRebuild
22 {
23 private:
24 const size_t mMinRequiredSize;
25 TIntermSequence mHoistedDeclNodes;
26
27 public:
Rewriter(TCompiler & compiler,size_t minRequiredSize)28 Rewriter(TCompiler &compiler, size_t minRequiredSize)
29 : TIntermRebuild(compiler, true, false), mMinRequiredSize(minRequiredSize)
30 {}
31
visitDeclarationPre(TIntermDeclaration & declNode)32 PreResult visitDeclarationPre(TIntermDeclaration &declNode) override
33 {
34 if (getParentFunction())
35 {
36 Declaration decl = ViewDeclaration(declNode);
37 const TType &type = decl.symbol.getType();
38 if (type.getQualifier() == TQualifier::EvqConst)
39 {
40 if (decl.initExpr && decl.initExpr->hasConstantValue())
41 {
42 const size_t size = MetalLayoutOf(type).sizeOf;
43 if (size >= mMinRequiredSize)
44 {
45 mHoistedDeclNodes.push_back(&declNode);
46 return nullptr;
47 }
48 }
49 }
50 }
51 return {declNode, VisitBits::Neither};
52 }
53
rewrite(TIntermBlock & root,IdGen & idGen)54 bool rewrite(TIntermBlock &root, IdGen &idGen)
55 {
56 if (!rebuildRoot(root))
57 {
58 return false;
59 }
60
61 if (mHoistedDeclNodes.empty())
62 {
63 return true;
64 }
65
66 root.insertChildNodes(FindFirstFunctionDefinitionIndex(&root), mHoistedDeclNodes);
67
68 for (TIntermNode *opaqueDeclNode : mHoistedDeclNodes)
69 {
70 TIntermDeclaration *declNode = opaqueDeclNode->getAsDeclarationNode();
71 ASSERT(declNode);
72 const TVariable &oldVar = ViewDeclaration(*declNode).symbol.variable();
73 const Name newName = idGen.createNewName(oldVar.name());
74 auto *newVar = new TVariable(&mSymbolTable, newName.rawName(), &oldVar.getType(),
75 newName.symbolType());
76 if (!ReplaceVariable(&mCompiler, &root, &oldVar, newVar))
77 {
78 return false;
79 }
80 }
81
82 return true;
83 }
84 };
85
86 } // anonymous namespace
87
88 ////////////////////////////////////////////////////////////////////////////////
89
HoistConstants(TCompiler & compiler,TIntermBlock & root,IdGen & idGen,size_t minRequiredSize)90 bool sh::HoistConstants(TCompiler &compiler,
91 TIntermBlock &root,
92 IdGen &idGen,
93 size_t minRequiredSize)
94 {
95 return Rewriter(compiler, minRequiredSize).rewrite(root, idGen);
96 }
97