tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

RunAtTheEndOfShader.cpp (4171B)


      1 //
      2 // Copyright 2017 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 // RunAtTheEndOfShader.cpp: Add code to be run at the end of the shader. In case main() contains a
      7 // return statement, this is done by replacing the main() function with another function that calls
      8 // the old main, like this:
      9 //
     10 // void main() { body }
     11 // =>
     12 // void main0() { body }
     13 // void main()
     14 // {
     15 //     main0();
     16 //     codeToRun
     17 // }
     18 //
     19 // This way the code will get run even if the return statement inside main is executed.
     20 //
     21 // This is done if main ends in an unconditional |discard| as well, to help with SPIR-V generation
     22 // that expects no dead-code to be present after branches in a block.  To avoid bugs when |discard|
     23 // is wrapped in unconditional blocks, any |discard| in main() is used as a signal to wrap it.
     24 //
     25 
     26 #include "compiler/translator/tree_util/RunAtTheEndOfShader.h"
     27 
     28 #include "compiler/translator/Compiler.h"
     29 #include "compiler/translator/IntermNode.h"
     30 #include "compiler/translator/StaticType.h"
     31 #include "compiler/translator/SymbolTable.h"
     32 #include "compiler/translator/tree_util/FindMain.h"
     33 #include "compiler/translator/tree_util/IntermNode_util.h"
     34 #include "compiler/translator/tree_util/IntermTraverse.h"
     35 
     36 namespace sh
     37 {
     38 
     39 namespace
     40 {
     41 
     42 constexpr const ImmutableString kMainString("main");
     43 
     44 class ContainsReturnOrDiscardTraverser : public TIntermTraverser
     45 {
     46  public:
     47    ContainsReturnOrDiscardTraverser()
     48        : TIntermTraverser(true, false, false), mContainsReturnOrDiscard(false)
     49    {}
     50 
     51    bool visitBranch(Visit visit, TIntermBranch *node) override
     52    {
     53        if (node->getFlowOp() == EOpReturn || node->getFlowOp() == EOpKill)
     54        {
     55            mContainsReturnOrDiscard = true;
     56        }
     57        return false;
     58    }
     59 
     60    bool containsReturnOrDiscard() { return mContainsReturnOrDiscard; }
     61 
     62  private:
     63    bool mContainsReturnOrDiscard;
     64 };
     65 
     66 bool ContainsReturnOrDiscard(TIntermNode *node)
     67 {
     68    ContainsReturnOrDiscardTraverser traverser;
     69    node->traverse(&traverser);
     70    return traverser.containsReturnOrDiscard();
     71 }
     72 
     73 void WrapMainAndAppend(TIntermBlock *root,
     74                       TIntermFunctionDefinition *main,
     75                       TIntermNode *codeToRun,
     76                       TSymbolTable *symbolTable)
     77 {
     78    // Replace main() with main0() with the same body.
     79    TFunction *oldMain =
     80        new TFunction(symbolTable, kEmptyImmutableString, SymbolType::AngleInternal,
     81                      StaticType::GetBasic<EbtVoid, EbpUndefined>(), false);
     82    TIntermFunctionDefinition *oldMainDefinition =
     83        CreateInternalFunctionDefinitionNode(*oldMain, main->getBody());
     84 
     85    bool replaced = root->replaceChildNode(main, oldMainDefinition);
     86    ASSERT(replaced);
     87 
     88    // void main()
     89    TFunction *newMain = new TFunction(symbolTable, kMainString, SymbolType::UserDefined,
     90                                       StaticType::GetBasic<EbtVoid, EbpUndefined>(), false);
     91    TIntermFunctionPrototype *newMainProto = new TIntermFunctionPrototype(newMain);
     92 
     93    // {
     94    //     main0();
     95    //     codeToRun
     96    // }
     97    TIntermBlock *newMainBody = new TIntermBlock();
     98    TIntermSequence emptySequence;
     99    TIntermAggregate *oldMainCall = TIntermAggregate::CreateFunctionCall(*oldMain, &emptySequence);
    100    newMainBody->appendStatement(oldMainCall);
    101    newMainBody->appendStatement(codeToRun);
    102 
    103    // Add the new main() to the root node.
    104    TIntermFunctionDefinition *newMainDefinition =
    105        new TIntermFunctionDefinition(newMainProto, newMainBody);
    106    root->appendStatement(newMainDefinition);
    107 }
    108 
    109 }  // anonymous namespace
    110 
    111 bool RunAtTheEndOfShader(TCompiler *compiler,
    112                         TIntermBlock *root,
    113                         TIntermNode *codeToRun,
    114                         TSymbolTable *symbolTable)
    115 {
    116    TIntermFunctionDefinition *main = FindMain(root);
    117    if (ContainsReturnOrDiscard(main))
    118    {
    119        WrapMainAndAppend(root, main, codeToRun, symbolTable);
    120    }
    121    else
    122    {
    123        main->getBody()->appendStatement(codeToRun);
    124    }
    125 
    126    return compiler->validateAST(root);
    127 }
    128 
    129 }  // namespace sh