Edit

kc3-lang/angle/src/compiler/translator/BreakVariableAliasingInInnerLoops.cpp

Branch :

  • Show log

    Commit

  • Author : Olli Etuaho
    Date : 2017-07-05 17:02:55
    Hash : 3ec75686
    Message : Collect AST transform utilities to a separate file Collect static functions that are used to create nodes in AST transformations into a single file. BUG=angleproject:1490 TEST=angle_unittests Change-Id: I6f87422988fa088f2f4b48986e378a2909705cb7

  • src/compiler/translator/BreakVariableAliasingInInnerLoops.cpp
  • //
    // Copyright (c) 2016 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.
    //
    
    // BreakVariableAliasingInInnerLoops.h: To optimize simple assignments, the HLSL compiler frontend
    //      may record a variable as aliasing another. Sometimes the alias information gets garbled
    //      so we work around this issue by breaking the aliasing chain in inner loops.
    
    #include "BreakVariableAliasingInInnerLoops.h"
    
    #include "compiler/translator/IntermNode_util.h"
    #include "compiler/translator/IntermTraverse.h"
    
    // A HLSL compiler developer gave us more details on the root cause and the workaround needed:
    //     The root problem is that if the HLSL compiler is applying aliasing information even on
    //     incomplete simulations (in this case, a single pass). The bug is triggered by an assignment
    //     that comes from a series of assignments, possibly with swizzled or ternary operators with
    //     known conditionals, where the source is before the loop.
    //     So, a workaround is to add a +0 term to variables the first time they are assigned to in
    //     an inner loop (if they are declared in an outside scope, otherwise there is no need).
    //     This will break the aliasing chain.
    
    // For simplicity here we add a +0 to any assignment that is in at least two nested loops. Because
    // the bug only shows up with swizzles, and ternary assignment, whole array or whole structure
    // assignment don't need a workaround.
    
    namespace sh
    {
    
    namespace
    {
    
    class AliasingBreaker : public TIntermTraverser
    {
      public:
        AliasingBreaker() : TIntermTraverser(true, false, true) {}
    
      protected:
        bool visitBinary(Visit visit, TIntermBinary *binary)
        {
            if (visit != PreVisit)
            {
                return false;
            }
    
            if (mLoopLevel < 2 || !binary->isAssignment())
            {
                return true;
            }
    
            TIntermTyped *B = binary->getRight();
            TType type      = B->getType();
    
            if (!type.isScalar() && !type.isVector() && !type.isMatrix())
            {
                return true;
            }
    
            if (type.isArray() || IsSampler(type.getBasicType()))
            {
                return true;
            }
    
            // We have a scalar / vector / matrix assignment with loop depth 2.
            // Transform it from
            //    A = B
            // to
            //    A = (B + typeof<B>(0));
    
            TIntermBinary *bPlusZero = new TIntermBinary(EOpAdd, B, CreateZeroNode(type));
            bPlusZero->setLine(B->getLine());
    
            binary->replaceChildNode(B, bPlusZero);
    
            return true;
        }
    
        bool visitLoop(Visit visit, TIntermLoop *loop)
        {
            if (visit == PreVisit)
            {
                mLoopLevel++;
            }
            else
            {
                ASSERT(mLoopLevel > 0);
                mLoopLevel--;
            }
    
            return true;
        }
    
      private:
        int mLoopLevel = 0;
    };
    
    }  // anonymous namespace
    
    void BreakVariableAliasingInInnerLoops(TIntermNode *root)
    {
        AliasingBreaker breaker;
        root->traverse(&breaker);
    }
    
    }  // namespace sh