Edit

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

Branch :

  • Show log

    Commit

  • Author : Jamie Madill
    Date : 2016-11-07 13:58:48
    Hash : 45bcc784
    Message : translator: Scope all classes with "sh". I was seeing an odd problem with our PoolAlloc conflicting with the glslang/Vulkan TIntermNode, so the fix was to move everything to a separate namespace. The bison grammars are also regenerated. No functional changes. BUG=angleproject:1576 Change-Id: I959c7afe4c092f0d458432c07b4dcee4d39513f3 Reviewed-on: https://chromium-review.googlesource.com/408267 Reviewed-by: Yuly Novikov <ynovikov@chromium.org> Commit-Queue: Jamie Madill <jmadill@chromium.org>

  • 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.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, TIntermTyped::CreateZero(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