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