• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2016 The SwiftShader Authors. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //    http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "localintermediate.h"
16 #include "SymbolTable.h"
17 
18 //
19 // Two purposes:
20 // 1.  Show an example of how to iterate tree.  Functions can
21 //     also directly call Traverse() on children themselves to
22 //     have finer grained control over the process than shown here.
23 //     See the last function for how to get started.
24 // 2.  Print out a text based description of the tree.
25 //
26 
27 //
28 // Use this class to carry along data from node to node in
29 // the traversal
30 //
31 class TOutputTraverser : public TIntermTraverser {
32 public:
TOutputTraverser(TInfoSinkBase & i)33 	TOutputTraverser(TInfoSinkBase& i) : sink(i) { }
34 	TInfoSinkBase& sink;
35 
36 protected:
37 	void visitSymbol(TIntermSymbol*);
38 	void visitConstantUnion(TIntermConstantUnion*);
39 	bool visitBinary(Visit visit, TIntermBinary*);
40 	bool visitUnary(Visit visit, TIntermUnary*);
41 	bool visitSelection(Visit visit, TIntermSelection*);
42 	bool visitAggregate(Visit visit, TIntermAggregate*);
43 	bool visitLoop(Visit visit, TIntermLoop*);
44 	bool visitBranch(Visit visit, TIntermBranch*);
45 };
46 
getCompleteString() const47 TString TType::getCompleteString() const
48 {
49 	TStringStream stream;
50 
51 	if (qualifier != EvqTemporary && qualifier != EvqGlobal)
52 		stream << getQualifierString() << " " << getPrecisionString() << " ";
53 	if (array)
54 		stream << "array of ";
55 	if (isMatrix())
56 		stream << static_cast<int>(primarySize) << "X" << static_cast<int>(secondarySize) << " matrix of ";
57 	else if(primarySize > 1)
58 		stream << static_cast<int>(primarySize) << "-component vector of ";
59 
60 	stream << getBasicString();
61 	return stream.str();
62 }
63 
64 //
65 // Helper functions for printing, not part of traversing.
66 //
67 
OutputTreeText(TInfoSinkBase & sink,TIntermNode * node,const int depth)68 void OutputTreeText(TInfoSinkBase& sink, TIntermNode* node, const int depth)
69 {
70 	int i;
71 
72 	sink.location(node->getLine());
73 
74 	for (i = 0; i < depth; ++i)
75 		sink << "  ";
76 }
77 
78 //
79 // The rest of the file are the traversal functions.  The last one
80 // is the one that starts the traversal.
81 //
82 // Return true from interior nodes to have the external traversal
83 // continue on to children.  If you process children yourself,
84 // return false.
85 //
86 
visitSymbol(TIntermSymbol * node)87 void TOutputTraverser::visitSymbol(TIntermSymbol* node)
88 {
89 	OutputTreeText(sink, node, mDepth);
90 
91 	sink << "'" << node->getSymbol() << "' ";
92 	sink << "(" << node->getCompleteString() << ")\n";
93 }
94 
visitBinary(Visit visit,TIntermBinary * node)95 bool TOutputTraverser::visitBinary(Visit visit, TIntermBinary* node)
96 {
97 	TInfoSinkBase& out = sink;
98 
99 	OutputTreeText(out, node, mDepth);
100 
101 	switch (node->getOp()) {
102 	case EOpAssign:                   out << "move second child to first child";           break;
103 	case EOpInitialize:               out << "initialize first child with second child";   break;
104 	case EOpAddAssign:                out << "add second child into first child";          break;
105 	case EOpSubAssign:                out << "subtract second child into first child";     break;
106 	case EOpMulAssign:                out << "multiply second child into first child";     break;
107 	case EOpVectorTimesMatrixAssign:  out << "matrix mult second child into first child";  break;
108 	case EOpVectorTimesScalarAssign:  out << "vector scale second child into first child"; break;
109 	case EOpMatrixTimesScalarAssign:  out << "matrix scale second child into first child"; break;
110 	case EOpMatrixTimesMatrixAssign:  out << "matrix mult second child into first child";  break;
111 	case EOpDivAssign:                out << "divide second child into first child";       break;
112 	case EOpIModAssign:               out << "modulo second child into first child";       break;
113 	case EOpBitShiftLeftAssign:       out << "bit-wise shift first child left by second child";  break;
114 	case EOpBitShiftRightAssign:      out << "bit-wise shift first child right by second child"; break;
115 	case EOpBitwiseAndAssign:         out << "bit-wise and second child into first child"; break;
116 	case EOpBitwiseXorAssign:         out << "bit-wise xor second child into first child"; break;
117 	case EOpBitwiseOrAssign:          out << "bit-wise or second child into first child";  break;
118 	case EOpIndexDirect:   out << "direct index";   break;
119 	case EOpIndexIndirect: out << "indirect index"; break;
120 	case EOpIndexDirectStruct:   out << "direct index for structure";   break;
121 	case EOpVectorSwizzle: out << "vector swizzle"; break;
122 
123 	case EOpAdd:    out << "add";                     break;
124 	case EOpSub:    out << "subtract";                break;
125 	case EOpMul:    out << "component-wise multiply"; break;
126 	case EOpDiv:    out << "divide";                  break;
127 	case EOpIMod:   out << "modulo";                  break;
128 	case EOpBitShiftLeft:     out << "bit-wise shift left";           break;
129 	case EOpBitShiftRight:    out << "bit-wise shift right";          break;
130 	case EOpBitwiseAnd:       out << "bit-wise and";                  break;
131 	case EOpBitwiseXor:       out << "bit-wise xor";                  break;
132 	case EOpBitwiseOr:        out << "bit-wise or";                   break;
133 	case EOpEqual:            out << "Compare Equal";                 break;
134 	case EOpNotEqual:         out << "Compare Not Equal";             break;
135 	case EOpLessThan:         out << "Compare Less Than";             break;
136 	case EOpGreaterThan:      out << "Compare Greater Than";          break;
137 	case EOpLessThanEqual:    out << "Compare Less Than or Equal";    break;
138 	case EOpGreaterThanEqual: out << "Compare Greater Than or Equal"; break;
139 
140 	case EOpVectorTimesScalar: out << "vector-scale";          break;
141 	case EOpVectorTimesMatrix: out << "vector-times-matrix";   break;
142 	case EOpMatrixTimesVector: out << "matrix-times-vector";   break;
143 	case EOpMatrixTimesScalar: out << "matrix-scale";          break;
144 	case EOpMatrixTimesMatrix: out << "matrix-multiply";       break;
145 
146 	case EOpLogicalOr:  out << "logical-or";   break;
147 	case EOpLogicalXor: out << "logical-xor"; break;
148 	case EOpLogicalAnd: out << "logical-and"; break;
149 	default: out << "<unknown op>";
150 	}
151 
152 	out << " (" << node->getCompleteString() << ")";
153 
154 	out << "\n";
155 
156 	return true;
157 }
158 
visitUnary(Visit visit,TIntermUnary * node)159 bool TOutputTraverser::visitUnary(Visit visit, TIntermUnary* node)
160 {
161 	TInfoSinkBase& out = sink;
162 
163 	OutputTreeText(out, node, mDepth);
164 
165 	switch (node->getOp()) {
166 	case EOpNegative:       out << "Negate value";         break;
167 	case EOpVectorLogicalNot:
168 	case EOpLogicalNot:     out << "Negate conditional";   break;
169 	case EOpBitwiseNot:     out << "bit-wise not";         break;
170 
171 	case EOpPostIncrement:  out << "Post-Increment";       break;
172 	case EOpPostDecrement:  out << "Post-Decrement";       break;
173 	case EOpPreIncrement:   out << "Pre-Increment";        break;
174 	case EOpPreDecrement:   out << "Pre-Decrement";        break;
175 
176 	case EOpRadians:        out << "radians";              break;
177 	case EOpDegrees:        out << "degrees";              break;
178 	case EOpSin:            out << "sine";                 break;
179 	case EOpCos:            out << "cosine";               break;
180 	case EOpTan:            out << "tangent";              break;
181 	case EOpAsin:           out << "arc sine";             break;
182 	case EOpAcos:           out << "arc cosine";           break;
183 	case EOpAtan:           out << "arc tangent";          break;
184 	case EOpSinh:           out << "hyperbolic sine";        break;
185 	case EOpCosh:           out << "hyperbolic cosine";      break;
186 	case EOpTanh:           out << "hyperbolic tangent";     break;
187 	case EOpAsinh:          out << "arc hyperbolic sine";    break;
188 	case EOpAcosh:          out << "arc hyperbolic cosine";  break;
189 	case EOpAtanh:          out << "arc hyperbolic tangent"; break;
190 
191 	case EOpExp:            out << "exp";                  break;
192 	case EOpLog:            out << "log";                  break;
193 	case EOpExp2:           out << "exp2";                 break;
194 	case EOpLog2:           out << "log2";                 break;
195 	case EOpSqrt:           out << "sqrt";                 break;
196 	case EOpInverseSqrt:    out << "inverse sqrt";         break;
197 
198 	case EOpAbs:            out << "Absolute value";       break;
199 	case EOpSign:           out << "Sign";                 break;
200 	case EOpFloor:          out << "Floor";                break;
201 	case EOpTrunc:          out << "Trunc";                break;
202 	case EOpRound:          out << "Round";                break;
203 	case EOpRoundEven:      out << "RoundEven";            break;
204 	case EOpCeil:           out << "Ceiling";              break;
205 	case EOpFract:          out << "Fraction";             break;
206 	case EOpIsNan:          out << "Is not a number";      break;
207 	case EOpIsInf:          out << "Is infinity";          break;
208 
209 	case EOpFloatBitsToInt: out << "float bits to int";    break;
210 	case EOpFloatBitsToUint: out << "float bits to uint";  break;
211 	case EOpIntBitsToFloat: out << "int bits to float";    break;
212 	case EOpUintBitsToFloat: out << "uint bits to float";  break;
213 
214 	case EOpPackSnorm2x16:  out << "pack Snorm 2x16";      break;
215 	case EOpPackUnorm2x16:  out << "pack Unorm 2x16";      break;
216 	case EOpPackHalf2x16:   out << "pack half 2x16";       break;
217 
218 	case EOpUnpackSnorm2x16: out << "unpack Snorm 2x16";   break;
219 	case EOpUnpackUnorm2x16: out << "unpack Unorm 2x16";   break;
220 	case EOpUnpackHalf2x16:  out << "unpack half 2x16";    break;
221 
222 	case EOpLength:         out << "length";               break;
223 	case EOpNormalize:      out << "normalize";            break;
224 		//	case EOpDPdx:           out << "dPdx";                 break;
225 		//	case EOpDPdy:           out << "dPdy";                 break;
226 		//	case EOpFwidth:         out << "fwidth";               break;
227 
228 	case EOpDeterminant:    out << "determinant";          break;
229 	case EOpTranspose:      out << "transpose";            break;
230 	case EOpInverse:        out << "inverse";              break;
231 
232 	case EOpAny:            out << "any";                  break;
233 	case EOpAll:            out << "all";                  break;
234 
235 	default: out.message(EPrefixError, "Bad unary op");
236 	}
237 
238 	out << " (" << node->getCompleteString() << ")";
239 
240 	out << "\n";
241 
242 	return true;
243 }
244 
visitAggregate(Visit visit,TIntermAggregate * node)245 bool TOutputTraverser::visitAggregate(Visit visit, TIntermAggregate* node)
246 {
247 	TInfoSinkBase& out = sink;
248 
249 	if (node->getOp() == EOpNull) {
250 		out.message(EPrefixError, "node is still EOpNull!");
251 		return true;
252 	}
253 
254 	OutputTreeText(out, node, mDepth);
255 
256 	switch (node->getOp()) {
257 	case EOpSequence:      out << "Sequence\n"; return true;
258 	case EOpComma:         out << "Comma\n"; return true;
259 	case EOpFunction:      out << "Function Definition: " << node->getName(); break;
260 	case EOpFunctionCall:  out << "Function Call: " << node->getName(); break;
261 	case EOpParameters:    out << "Function Parameters: ";              break;
262 
263 	case EOpConstructFloat: out << "Construct float"; break;
264 	case EOpConstructVec2:  out << "Construct vec2";  break;
265 	case EOpConstructVec3:  out << "Construct vec3";  break;
266 	case EOpConstructVec4:  out << "Construct vec4";  break;
267 	case EOpConstructBool:  out << "Construct bool";  break;
268 	case EOpConstructBVec2: out << "Construct bvec2"; break;
269 	case EOpConstructBVec3: out << "Construct bvec3"; break;
270 	case EOpConstructBVec4: out << "Construct bvec4"; break;
271 	case EOpConstructInt:   out << "Construct int";   break;
272 	case EOpConstructIVec2: out << "Construct ivec2"; break;
273 	case EOpConstructIVec3: out << "Construct ivec3"; break;
274 	case EOpConstructIVec4: out << "Construct ivec4"; break;
275 	case EOpConstructUInt:  out << "Construct uint";  break;
276 	case EOpConstructUVec2: out << "Construct uvec2"; break;
277 	case EOpConstructUVec3: out << "Construct uvec3"; break;
278 	case EOpConstructUVec4: out << "Construct uvec4"; break;
279 	case EOpConstructMat2:  out << "Construct mat2";  break;
280 	case EOpConstructMat2x3:  out << "Construct mat2x3";  break;
281 	case EOpConstructMat2x4:  out << "Construct mat2x4";  break;
282 	case EOpConstructMat3x2:  out << "Construct mat3x2";  break;
283 	case EOpConstructMat3:  out << "Construct mat3";  break;
284 	case EOpConstructMat3x4:  out << "Construct mat3x4";  break;
285 	case EOpConstructMat4x2:  out << "Construct mat4x2";  break;
286 	case EOpConstructMat4x3:  out << "Construct mat4x3";  break;
287 	case EOpConstructMat4:  out << "Construct mat4";  break;
288 	case EOpConstructStruct:  out << "Construct structure";  break;
289 
290 	case EOpLessThan:         out << "Compare Less Than";             break;
291 	case EOpGreaterThan:      out << "Compare Greater Than";          break;
292 	case EOpLessThanEqual:    out << "Compare Less Than or Equal";    break;
293 	case EOpGreaterThanEqual: out << "Compare Greater Than or Equal"; break;
294 	case EOpVectorEqual:      out << "Equal";                         break;
295 	case EOpVectorNotEqual:   out << "NotEqual";                      break;
296 
297 	case EOpMod:           out << "mod";         break;
298 	case EOpModf:          out << "modf";        break;
299 	case EOpPow:           out << "pow";         break;
300 
301 	case EOpAtan:          out << "arc tangent"; break;
302 
303 	case EOpMin:           out << "min";         break;
304 	case EOpMax:           out << "max";         break;
305 	case EOpClamp:         out << "clamp";       break;
306 	case EOpMix:           out << "mix";         break;
307 	case EOpStep:          out << "step";        break;
308 	case EOpSmoothStep:    out << "smoothstep";  break;
309 
310 	case EOpFloatBitsToInt:  out << "floatBitsToInt";  break;
311 	case EOpFloatBitsToUint: out << "floatBitsToUint"; break;
312 	case EOpIntBitsToFloat:  out << "intBitsToFloat";  break;
313 	case EOpUintBitsToFloat: out << "uintBitsToFloat"; break;
314 
315 	case EOpDistance:      out << "distance";                break;
316 	case EOpDot:           out << "dot-product";             break;
317 	case EOpCross:         out << "cross-product";           break;
318 	case EOpFaceForward:   out << "face-forward";            break;
319 	case EOpReflect:       out << "reflect";                 break;
320 	case EOpRefract:       out << "refract";                 break;
321 	case EOpMul:           out << "component-wise multiply"; break;
322 	case EOpOuterProduct:  out << "outer product";           break;
323 
324 	default: out.message(EPrefixError, "Bad aggregation op");
325 	}
326 
327 	if (node->getOp() != EOpSequence && node->getOp() != EOpParameters)
328 		out << " (" << node->getCompleteString() << ")";
329 
330 	out << "\n";
331 
332 	return true;
333 }
334 
visitSelection(Visit visit,TIntermSelection * node)335 bool TOutputTraverser::visitSelection(Visit visit, TIntermSelection* node)
336 {
337 	TInfoSinkBase& out = sink;
338 
339 	OutputTreeText(out, node, mDepth);
340 
341 	out << "Test condition and select";
342 	out << " (" << node->getCompleteString() << ")\n";
343 
344 	++mDepth;
345 
346 	OutputTreeText(sink, node, mDepth);
347 	out << "Condition\n";
348 	node->getCondition()->traverse(this);
349 
350 	OutputTreeText(sink, node, mDepth);
351 	if (node->getTrueBlock()) {
352 		out << "true case\n";
353 		node->getTrueBlock()->traverse(this);
354 	} else
355 		out << "true case is null\n";
356 
357 	if (node->getFalseBlock()) {
358 		OutputTreeText(sink, node, mDepth);
359 		out << "false case\n";
360 		node->getFalseBlock()->traverse(this);
361 	}
362 
363 	--mDepth;
364 
365 	return false;
366 }
367 
visitConstantUnion(TIntermConstantUnion * node)368 void TOutputTraverser::visitConstantUnion(TIntermConstantUnion* node)
369 {
370 	TInfoSinkBase& out = sink;
371 
372 	size_t size = node->getType().getObjectSize();
373 
374 	for(size_t i = 0; i < size; i++) {
375 		OutputTreeText(out, node, mDepth);
376 		switch (node->getUnionArrayPointer()[i].getType()) {
377 		case EbtBool:
378 			if (node->getUnionArrayPointer()[i].getBConst())
379 				out << "true";
380 			else
381 				out << "false";
382 
383 			out << " (" << "const bool" << ")";
384 			out << "\n";
385 			break;
386 		case EbtFloat:
387 			out << node->getUnionArrayPointer()[i].getFConst();
388 			out << " (const float)\n";
389 			break;
390 		case EbtInt:
391 			out << node->getUnionArrayPointer()[i].getIConst();
392 			out << " (const int)\n";
393 			break;
394 		case EbtUInt:
395 			out << node->getUnionArrayPointer()[i].getUConst();
396 			out << " (const uint)\n";
397 			break;
398 		default:
399 			out.message(EPrefixInternalError, "Unknown constant", node->getLine());
400 			break;
401 		}
402 	}
403 }
404 
visitLoop(Visit visit,TIntermLoop * node)405 bool TOutputTraverser::visitLoop(Visit visit, TIntermLoop* node)
406 {
407 	TInfoSinkBase& out = sink;
408 
409 	OutputTreeText(out, node, mDepth);
410 
411 	out << "Loop with condition ";
412 	if (node->getType() == ELoopDoWhile)
413 		out << "not ";
414 	out << "tested first\n";
415 
416 	++mDepth;
417 
418 	OutputTreeText(sink, node, mDepth);
419 	if (node->getCondition()) {
420 		out << "Loop Condition\n";
421 		node->getCondition()->traverse(this);
422 	} else
423 		out << "No loop condition\n";
424 
425 	OutputTreeText(sink, node, mDepth);
426 	if (node->getBody()) {
427 		out << "Loop Body\n";
428 		node->getBody()->traverse(this);
429 	} else
430 		out << "No loop body\n";
431 
432 	if (node->getExpression()) {
433 		OutputTreeText(sink, node, mDepth);
434 		out << "Loop Terminal Expression\n";
435 		node->getExpression()->traverse(this);
436 	}
437 
438 	--mDepth;
439 
440 	return false;
441 }
442 
visitBranch(Visit visit,TIntermBranch * node)443 bool TOutputTraverser::visitBranch(Visit visit, TIntermBranch* node)
444 {
445 	TInfoSinkBase& out = sink;
446 
447 	OutputTreeText(out, node, mDepth);
448 
449 	switch (node->getFlowOp()) {
450 	case EOpKill:      out << "Branch: Kill";           break;
451 	case EOpBreak:     out << "Branch: Break";          break;
452 	case EOpContinue:  out << "Branch: Continue";       break;
453 	case EOpReturn:    out << "Branch: Return";         break;
454 	default:           out << "Branch: Unknown Branch"; break;
455 	}
456 
457 	if (node->getExpression()) {
458 		out << " with expression\n";
459 		++mDepth;
460 		node->getExpression()->traverse(this);
461 		--mDepth;
462 	} else
463 		out << "\n";
464 
465 	return false;
466 }
467 
468 //
469 // This function is the one to call externally to start the traversal.
470 // Individual functions can be initialized to 0 to skip processing of that
471 // type of node.  It's children will still be processed.
472 //
outputTree(TIntermNode * root)473 void TIntermediate::outputTree(TIntermNode* root)
474 {
475 	if (root == 0)
476 		return;
477 
478 	TOutputTraverser it(infoSink.info);
479 
480 	root->traverse(&it);
481 }
482