blob: bca93385e2d133745e8ca1a5f97431b552900246 [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
28namespace
29{
30
31class AliasingBreaker : public TIntermTraverser
32{
33 public:
34 AliasingBreaker() : TIntermTraverser(true, false, true) {}
35
36 protected:
37 bool visitBinary(Visit visit, TIntermBinary *binary)
38 {
39 if (visit != PreVisit)
40 {
41 return false;
42 }
43
44 if (mLoopLevel < 2 || !binary->isAssignment())
45 {
46 return true;
47 }
48
49 TIntermTyped *B = binary->getRight();
50 TType type = B->getType();
51
52 if (!type.isScalar() && !type.isVector() && !type.isMatrix())
53 {
54 return true;
55 }
56
57 if (type.isArray() || IsSampler(type.getBasicType()))
58 {
59 return true;
60 }
61
62 // We have a scalar / vector / matrix assignment with loop depth 2.
63 // Transform it from
64 // A = B
65 // to
66 // A = (B + typeof<B>(0));
67
68 TIntermBinary *bPlusZero = new TIntermBinary(EOpAdd, B, TIntermTyped::CreateZero(type));
69 bPlusZero->setLine(B->getLine());
70
71 binary->setRight(bPlusZero);
72
73 return true;
74 }
75
76 bool visitLoop(Visit visit, TIntermLoop *loop)
77 {
78 if (visit == PreVisit)
79 {
80 mLoopLevel++;
81 }
82 else
83 {
84 ASSERT(mLoopLevel > 0);
85 mLoopLevel--;
86 }
87
88 return true;
89 }
90
91 private:
92 int mLoopLevel = 0;
93};
94
95} // anonymous namespace
96
97namespace sh
98{
99
100void BreakVariableAliasingInInnerLoops(TIntermNode *root)
101{
102 AliasingBreaker breaker;
103 root->traverse(&breaker);
104}
105
106} // namespace sh