1 //
2 // Copyright 2015 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 // IntermNode_test.cpp:
7 // Unit tests for the AST node classes.
8 //
9
10 #include "compiler/translator/IntermNode.h"
11 #include "angle_gl.h"
12 #include "compiler/translator/InfoSink.h"
13 #include "compiler/translator/PoolAlloc.h"
14 #include "compiler/translator/StaticType.h"
15 #include "compiler/translator/SymbolTable.h"
16 #include "gtest/gtest.h"
17
18 using namespace sh;
19
20 class IntermNodeTest : public testing::Test
21 {
22 public:
IntermNodeTest()23 IntermNodeTest() : mUniqueIndex(0) {}
24
25 protected:
SetUp()26 void SetUp() override
27 {
28 allocator.push();
29 SetGlobalPoolAllocator(&allocator);
30 }
31
TearDown()32 void TearDown() override
33 {
34 SetGlobalPoolAllocator(nullptr);
35 allocator.pop();
36 }
37
createTestSymbol(const TType & type)38 TIntermSymbol *createTestSymbol(const TType &type)
39 {
40 std::stringstream symbolNameOut;
41 symbolNameOut << "test" << mUniqueIndex;
42 ImmutableString symbolName(symbolNameOut.str());
43 ++mUniqueIndex;
44
45 // We're using a mock symbol table here, don't need to assign proper symbol ids to these
46 // nodes.
47 TSymbolTable symbolTable;
48 TType *variableType = new TType(type);
49 variableType->setQualifier(EvqTemporary);
50 TVariable *variable =
51 new TVariable(&symbolTable, symbolName, variableType, SymbolType::AngleInternal);
52 TIntermSymbol *node = new TIntermSymbol(variable);
53 node->setLine(createUniqueSourceLoc());
54 return node;
55 }
56
createTestSymbol()57 TIntermSymbol *createTestSymbol()
58 {
59 TType type(EbtFloat, EbpHigh);
60 return createTestSymbol(type);
61 }
62
createTestFunction(const TType & returnType,const TIntermSequence & args)63 TFunction *createTestFunction(const TType &returnType, const TIntermSequence &args)
64 {
65 // We're using a mock symbol table similarly as for creating symbol nodes.
66 const ImmutableString name("testFunc");
67 TSymbolTable symbolTable;
68 TFunction *func = new TFunction(&symbolTable, name, SymbolType::UserDefined,
69 new TType(returnType), false);
70 for (TIntermNode *arg : args)
71 {
72 const TType *type = new TType(arg->getAsTyped()->getType());
73 func->addParameter(new TVariable(&symbolTable, ImmutableString("param"), type,
74 SymbolType::UserDefined));
75 }
76 return func;
77 }
78
checkTypeEqualWithQualifiers(const TType & original,const TType & copy)79 void checkTypeEqualWithQualifiers(const TType &original, const TType ©)
80 {
81 ASSERT_EQ(original, copy);
82 ASSERT_EQ(original.getPrecision(), copy.getPrecision());
83 ASSERT_EQ(original.getQualifier(), copy.getQualifier());
84 }
85
checkSymbolCopy(TIntermNode * aOriginal,TIntermNode * aCopy)86 void checkSymbolCopy(TIntermNode *aOriginal, TIntermNode *aCopy)
87 {
88 ASSERT_NE(aOriginal, aCopy);
89 TIntermSymbol *copy = aCopy->getAsSymbolNode();
90 TIntermSymbol *original = aOriginal->getAsSymbolNode();
91 ASSERT_NE(nullptr, copy);
92 ASSERT_NE(nullptr, original);
93 ASSERT_NE(original, copy);
94 ASSERT_EQ(&original->variable(), ©->variable());
95 ASSERT_EQ(original->uniqueId(), copy->uniqueId());
96 ASSERT_EQ(original->getName(), copy->getName());
97 checkTypeEqualWithQualifiers(original->getType(), copy->getType());
98 ASSERT_EQ(original->getLine().first_file, copy->getLine().first_file);
99 ASSERT_EQ(original->getLine().first_line, copy->getLine().first_line);
100 ASSERT_EQ(original->getLine().last_file, copy->getLine().last_file);
101 ASSERT_EQ(original->getLine().last_line, copy->getLine().last_line);
102 }
103
createUniqueSourceLoc()104 TSourceLoc createUniqueSourceLoc()
105 {
106 TSourceLoc loc;
107 loc.first_file = mUniqueIndex;
108 loc.first_line = mUniqueIndex + 1;
109 loc.last_file = mUniqueIndex + 2;
110 loc.last_line = mUniqueIndex + 3;
111 ++mUniqueIndex;
112 return loc;
113 }
114
getTestSourceLoc()115 static TSourceLoc getTestSourceLoc()
116 {
117 TSourceLoc loc;
118 loc.first_file = 1;
119 loc.first_line = 2;
120 loc.last_file = 3;
121 loc.last_line = 4;
122 return loc;
123 }
124
checkTestSourceLoc(const TSourceLoc & loc)125 static void checkTestSourceLoc(const TSourceLoc &loc)
126 {
127 ASSERT_EQ(1, loc.first_file);
128 ASSERT_EQ(2, loc.first_line);
129 ASSERT_EQ(3, loc.last_file);
130 ASSERT_EQ(4, loc.last_line);
131 }
132
133 private:
134 angle::PoolAllocator allocator;
135 int mUniqueIndex;
136 };
137
138 // Check that the deep copy of a symbol node is an actual copy with the same attributes as the
139 // original.
TEST_F(IntermNodeTest,DeepCopySymbolNode)140 TEST_F(IntermNodeTest, DeepCopySymbolNode)
141 {
142 const TType *type = StaticType::Get<EbtInt, EbpHigh, EvqTemporary, 1, 1>();
143
144 // We're using a mock symbol table here, don't need to assign proper symbol ids to these nodes.
145 TSymbolTable symbolTable;
146
147 TVariable *variable =
148 new TVariable(&symbolTable, ImmutableString("name"), type, SymbolType::AngleInternal);
149 TIntermSymbol *original = new TIntermSymbol(variable);
150 original->setLine(getTestSourceLoc());
151 TIntermTyped *copy = original->deepCopy();
152 checkSymbolCopy(original, copy);
153 checkTestSourceLoc(copy->getLine());
154 }
155
156 // Check that the deep copy of a constant union node is an actual copy with the same attributes as
157 // the original.
TEST_F(IntermNodeTest,DeepCopyConstantUnionNode)158 TEST_F(IntermNodeTest, DeepCopyConstantUnionNode)
159 {
160 TType type(EbtInt, EbpHigh);
161 TConstantUnion *constValue = new TConstantUnion[1];
162 constValue[0].setIConst(101);
163 TIntermConstantUnion *original = new TIntermConstantUnion(constValue, type);
164 original->setLine(getTestSourceLoc());
165 TIntermTyped *copyTyped = original->deepCopy();
166 TIntermConstantUnion *copy = copyTyped->getAsConstantUnion();
167 ASSERT_NE(nullptr, copy);
168 ASSERT_NE(original, copy);
169 checkTestSourceLoc(copy->getLine());
170 checkTypeEqualWithQualifiers(original->getType(), copy->getType());
171 ASSERT_EQ(101, copy->getIConst(0));
172 }
173
174 // Check that the deep copy of a binary node is an actual copy with the same attributes as the
175 // original. Child nodes also need to be copies with the same attributes as the original children.
TEST_F(IntermNodeTest,DeepCopyBinaryNode)176 TEST_F(IntermNodeTest, DeepCopyBinaryNode)
177 {
178 TType type(EbtFloat, EbpHigh);
179
180 TIntermBinary *original = new TIntermBinary(EOpAdd, createTestSymbol(), createTestSymbol());
181 original->setLine(getTestSourceLoc());
182 TIntermTyped *copyTyped = original->deepCopy();
183 TIntermBinary *copy = copyTyped->getAsBinaryNode();
184 ASSERT_NE(nullptr, copy);
185 ASSERT_NE(original, copy);
186 checkTestSourceLoc(copy->getLine());
187 checkTypeEqualWithQualifiers(original->getType(), copy->getType());
188
189 checkSymbolCopy(original->getLeft(), copy->getLeft());
190 checkSymbolCopy(original->getRight(), copy->getRight());
191 }
192
193 // Check that the deep copy of a unary node is an actual copy with the same attributes as the
194 // original. The child node also needs to be a copy with the same attributes as the original child.
TEST_F(IntermNodeTest,DeepCopyUnaryNode)195 TEST_F(IntermNodeTest, DeepCopyUnaryNode)
196 {
197 TType type(EbtFloat, EbpHigh);
198
199 TIntermUnary *original = new TIntermUnary(EOpPreIncrement, createTestSymbol(), nullptr);
200 original->setLine(getTestSourceLoc());
201 TIntermTyped *copyTyped = original->deepCopy();
202 TIntermUnary *copy = copyTyped->getAsUnaryNode();
203 ASSERT_NE(nullptr, copy);
204 ASSERT_NE(original, copy);
205 checkTestSourceLoc(copy->getLine());
206 checkTypeEqualWithQualifiers(original->getType(), copy->getType());
207
208 checkSymbolCopy(original->getOperand(), copy->getOperand());
209 }
210
211 // Check that the deep copy of an aggregate node is an actual copy with the same attributes as the
212 // original. Child nodes also need to be copies with the same attributes as the original children.
TEST_F(IntermNodeTest,DeepCopyAggregateNode)213 TEST_F(IntermNodeTest, DeepCopyAggregateNode)
214 {
215 TIntermSequence *originalSeq = new TIntermSequence();
216 originalSeq->push_back(createTestSymbol());
217 originalSeq->push_back(createTestSymbol());
218 originalSeq->push_back(createTestSymbol());
219
220 TFunction *testFunc =
221 createTestFunction(originalSeq->back()->getAsTyped()->getType(), *originalSeq);
222
223 TIntermAggregate *original = TIntermAggregate::CreateFunctionCall(*testFunc, originalSeq);
224 original->setLine(getTestSourceLoc());
225
226 TIntermTyped *copyTyped = original->deepCopy();
227 TIntermAggregate *copy = copyTyped->getAsAggregate();
228 ASSERT_NE(nullptr, copy);
229 ASSERT_NE(original, copy);
230 checkTestSourceLoc(copy->getLine());
231 checkTypeEqualWithQualifiers(original->getType(), copy->getType());
232
233 ASSERT_EQ(original->getSequence()->size(), copy->getSequence()->size());
234 TIntermSequence::size_type i = 0;
235 for (auto *copyChild : *copy->getSequence())
236 {
237 TIntermNode *originalChild = original->getSequence()->at(i);
238 checkSymbolCopy(originalChild, copyChild);
239 ++i;
240 }
241 }
242
243 // Check that the deep copy of a ternary node is an actual copy with the same attributes as the
244 // original. Child nodes also need to be copies with the same attributes as the original children.
TEST_F(IntermNodeTest,DeepCopyTernaryNode)245 TEST_F(IntermNodeTest, DeepCopyTernaryNode)
246 {
247 TType type(EbtFloat, EbpHigh);
248
249 TIntermTernary *original = new TIntermTernary(createTestSymbol(TType(EbtBool, EbpUndefined)),
250 createTestSymbol(), createTestSymbol());
251 original->setLine(getTestSourceLoc());
252 TIntermTyped *copyTyped = original->deepCopy();
253 TIntermTernary *copy = copyTyped->getAsTernaryNode();
254 ASSERT_NE(nullptr, copy);
255 ASSERT_NE(original, copy);
256 checkTestSourceLoc(copy->getLine());
257 checkTypeEqualWithQualifiers(original->getType(), copy->getType());
258
259 checkSymbolCopy(original->getCondition(), copy->getCondition());
260 checkSymbolCopy(original->getTrueExpression(), copy->getTrueExpression());
261 checkSymbolCopy(original->getFalseExpression(), copy->getFalseExpression());
262 }
263