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/RewriteCaseDeclarations.h"
8 #include "compiler/translator/TranslatorMetalDirect/AstHelpers.h"
9 #include "compiler/translator/TranslatorMetalDirect/IntermRebuild.h"
10 
11 using namespace sh;
12 
13 ////////////////////////////////////////////////////////////////////////////////
14 
15 namespace
16 {
17 
18 class Rewriter : public TIntermRebuild
19 {
20     std::vector<std::vector<const TVariable *>> mDeclaredVarStack;
21 
22   public:
Rewriter(TCompiler & compiler)23     Rewriter(TCompiler &compiler) : TIntermRebuild(compiler, true, true) {}
24 
~Rewriter()25     ~Rewriter() override { ASSERT(mDeclaredVarStack.empty()); }
26 
27   private:
visitSwitchPre(TIntermSwitch & node)28     PreResult visitSwitchPre(TIntermSwitch &node) override
29     {
30         mDeclaredVarStack.emplace_back();
31         return node;
32     }
33 
visitSwitchPost(TIntermSwitch & node)34     PostResult visitSwitchPost(TIntermSwitch &node) override
35     {
36         ASSERT(!mDeclaredVarStack.empty());
37         const auto vars = std::move(mDeclaredVarStack.back());
38         mDeclaredVarStack.pop_back();
39         if (!vars.empty())
40         {
41             auto &block = *new TIntermBlock();
42             for (const TVariable *var : vars)
43             {
44                 block.appendStatement(new TIntermDeclaration{var});
45             }
46             block.appendStatement(&node);
47             return block;
48         }
49         return node;
50     }
51 
visitDeclarationPre(TIntermDeclaration & node)52     PreResult visitDeclarationPre(TIntermDeclaration &node) override
53     {
54         if (!mDeclaredVarStack.empty())
55         {
56             TIntermNode *parent = getParentNode();
57             if (parent->getAsBlock())
58             {
59                 TIntermNode *grandparent = getParentNode(1);
60                 if (grandparent && grandparent->getAsSwitchNode())
61                 {
62                     Declaration decl = ViewDeclaration(node);
63                     mDeclaredVarStack.back().push_back(&decl.symbol.variable());
64                     if (decl.initExpr)
65                     {
66                         return *new TIntermBinary(TOperator::EOpAssign, &decl.symbol,
67                                                   decl.initExpr);
68                     }
69                     else
70                     {
71                         return nullptr;
72                     }
73                 }
74             }
75         }
76         return node;
77     }
78 };
79 
80 }  // anonymous namespace
81 
82 ////////////////////////////////////////////////////////////////////////////////
83 
RewriteCaseDeclarations(TCompiler & compiler,TIntermBlock & root)84 bool sh::RewriteCaseDeclarations(TCompiler &compiler, TIntermBlock &root)
85 {
86     if (!Rewriter(compiler).rebuildRoot(root))
87     {
88         return false;
89     }
90     return true;
91 }
92