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