tor-browser

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

BreakVariableAliasingInInnerLoops.cpp (3263B)


      1 //
      2 // Copyright 2016 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 // BreakVariableAliasingInInnerLoops.h: To optimize simple assignments, the HLSL compiler frontend
      8 //      may record a variable as aliasing another. Sometimes the alias information gets garbled
      9 //      so we work around this issue by breaking the aliasing chain in inner loops.
     10 
     11 #include "compiler/translator/tree_ops/d3d/BreakVariableAliasingInInnerLoops.h"
     12 
     13 #include "compiler/translator/Compiler.h"
     14 #include "compiler/translator/tree_util/IntermNode_util.h"
     15 #include "compiler/translator/tree_util/IntermTraverse.h"
     16 
     17 // A HLSL compiler developer gave us more details on the root cause and the workaround needed:
     18 //     The root problem is that if the HLSL compiler is applying aliasing information even on
     19 //     incomplete simulations (in this case, a single pass). The bug is triggered by an assignment
     20 //     that comes from a series of assignments, possibly with swizzled or ternary operators with
     21 //     known conditionals, where the source is before the loop.
     22 //     So, a workaround is to add a +0 term to variables the first time they are assigned to in
     23 //     an inner loop (if they are declared in an outside scope, otherwise there is no need).
     24 //     This will break the aliasing chain.
     25 
     26 // For simplicity here we add a +0 to any assignment that is in at least two nested loops. Because
     27 // the bug only shows up with swizzles, and ternary assignment, whole array or whole structure
     28 // assignment don't need a workaround.
     29 
     30 namespace sh
     31 {
     32 
     33 namespace
     34 {
     35 
     36 class AliasingBreaker : public TIntermTraverser
     37 {
     38  public:
     39    AliasingBreaker() : TIntermTraverser(true, false, true) {}
     40 
     41  protected:
     42    bool visitBinary(Visit visit, TIntermBinary *binary) override
     43    {
     44        if (visit != PreVisit)
     45        {
     46            return false;
     47        }
     48 
     49        if (mLoopLevel < 2 || !binary->isAssignment())
     50        {
     51            return true;
     52        }
     53 
     54        TIntermTyped *B = binary->getRight();
     55        TType type      = B->getType();
     56 
     57        if (!type.isScalar() && !type.isVector() && !type.isMatrix())
     58        {
     59            return true;
     60        }
     61 
     62        if (type.isArray() || IsSampler(type.getBasicType()))
     63        {
     64            return true;
     65        }
     66 
     67        // We have a scalar / vector / matrix assignment with loop depth 2.
     68        // Transform it from
     69        //    A = B
     70        // to
     71        //    A = (B + typeof<B>(0));
     72 
     73        TIntermBinary *bPlusZero = new TIntermBinary(EOpAdd, B, CreateZeroNode(type));
     74        bPlusZero->setLine(B->getLine());
     75 
     76        binary->replaceChildNode(B, bPlusZero);
     77 
     78        return true;
     79    }
     80 
     81    bool visitLoop(Visit visit, TIntermLoop *loop) override
     82    {
     83        if (visit == PreVisit)
     84        {
     85            mLoopLevel++;
     86        }
     87        else
     88        {
     89            ASSERT(mLoopLevel > 0);
     90            mLoopLevel--;
     91        }
     92 
     93        return true;
     94    }
     95 
     96  private:
     97    int mLoopLevel = 0;
     98 };
     99 
    100 }  // anonymous namespace
    101 
    102 bool BreakVariableAliasingInInnerLoops(TCompiler *compiler, TIntermNode *root)
    103 {
    104    AliasingBreaker breaker;
    105    root->traverse(&breaker);
    106 
    107    return compiler->validateAST(root);
    108 }
    109 
    110 }  // namespace sh