2 //Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
5 //Redistribution and use in source and binary forms, with or without
6 //modification, are permitted provided that the following conditions
9 // Redistributions of source code must retain the above copyright
10 // notice, this list of conditions and the following disclaimer.
12 // Redistributions in binary form must reproduce the above
13 // copyright notice, this list of conditions and the following
14 // disclaimer in the documentation and/or other materials provided
15 // with the distribution.
17 // Neither the name of 3Dlabs Inc. Ltd. nor the names of its
18 // contributors may be used to endorse or promote products derived
19 // from this software without specific prior written permission.
21 //THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 //"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 //LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 //FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 //COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 //INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 //BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 //LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 //CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 //LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 //ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 //POSSIBILITY OF SUCH DAMAGE.
35 #include "localintermediate.h"
36 #include "../Include/ShHandle.h"
40 // 1. Show an example of how to iterate tree. Functions can
41 // also directly call Traverse() on children themselves to
42 // have finer grained control over the process than shown here.
43 // See the last function for how to get started.
44 // 2. Print out a text based description of the tree.
48 // Use this class to carry along data from node to node in
51 class TOutputTraverser
: public TIntermTraverser
{
53 TOutputTraverser(TInfoSink
& i
) : infoSink(i
) { }
57 TString
TType::getCompleteString() const
62 if (qualifier
!= EvqTemporary
&& qualifier
!= EvqGlobal
)
63 p
+= sprintf(p
, "%s ", getQualifierString());
65 p
+= sprintf(p
, "array of ");
67 p
+= sprintf(p
, "%dX%d matrix of ", size
, size
);
69 p
+= sprintf(p
, "%d-component vector of ", size
);
71 sprintf(p
, "%s", getBasicString());
77 // Helper functions for printing, not part of traversing.
80 void OutputTreeText(TInfoSink
& infoSink
, TIntermNode
* node
, const int depth
)
84 infoSink
.debug
<< FormatSourceLoc(node
->getLine());
86 for (i
= 0; i
< depth
; ++i
)
87 infoSink
.debug
<< " ";
91 // The rest of the file are the traversal functions. The last one
92 // is the one that starts the traversal.
94 // Return true from interior nodes to have the external traversal
95 // continue on to children. If you process children yourself,
99 void OutputSymbol(TIntermSymbol
* node
, TIntermTraverser
* it
)
101 TOutputTraverser
* oit
= static_cast<TOutputTraverser
*>(it
);
103 OutputTreeText(oit
->infoSink
, node
, oit
->depth
);
106 sprintf(buf
, "'%s' (%s)\n",
107 node
->getSymbol().c_str(),
108 node
->getCompleteString().c_str());
110 oit
->infoSink
.debug
<< buf
;
113 bool OutputBinary(bool /* preVisit */, TIntermBinary
* node
, TIntermTraverser
* it
)
115 TOutputTraverser
* oit
= static_cast<TOutputTraverser
*>(it
);
116 TInfoSink
& out
= oit
->infoSink
;
118 OutputTreeText(out
, node
, oit
->depth
);
120 switch (node
->getOp()) {
121 case EOpAssign
: out
.debug
<< "move second child to first child"; break;
122 case EOpAddAssign
: out
.debug
<< "add second child into first child"; break;
123 case EOpSubAssign
: out
.debug
<< "subtract second child into first child"; break;
124 case EOpMulAssign
: out
.debug
<< "multiply second child into first child"; break;
125 case EOpVectorTimesMatrixAssign
: out
.debug
<< "matrix mult second child into first child"; break;
126 case EOpVectorTimesScalarAssign
: out
.debug
<< "vector scale second child into first child"; break;
127 case EOpMatrixTimesScalarAssign
: out
.debug
<< "matrix scale second child into first child"; break;
128 case EOpMatrixTimesMatrixAssign
: out
.debug
<< "matrix mult second child into first child"; break;
129 case EOpDivAssign
: out
.debug
<< "divide second child into first child"; break;
130 case EOpModAssign
: out
.debug
<< "mod second child into first child"; break;
131 case EOpAndAssign
: out
.debug
<< "and second child into first child"; break;
132 case EOpInclusiveOrAssign
: out
.debug
<< "or second child into first child"; break;
133 case EOpExclusiveOrAssign
: out
.debug
<< "exclusive or second child into first child"; break;
134 case EOpLeftShiftAssign
: out
.debug
<< "left shift second child into first child"; break;
135 case EOpRightShiftAssign
: out
.debug
<< "right shift second child into first child"; break;
137 case EOpIndexDirect
: out
.debug
<< "direct index"; break;
138 case EOpIndexIndirect
: out
.debug
<< "indirect index"; break;
139 case EOpIndexDirectStruct
: out
.debug
<< "direct index for structure"; break;
140 case EOpVectorSwizzle
: out
.debug
<< "vector swizzle"; break;
142 case EOpAdd
: out
.debug
<< "add"; break;
143 case EOpSub
: out
.debug
<< "subtract"; break;
144 case EOpMul
: out
.debug
<< "component-wise multiply"; break;
145 case EOpDiv
: out
.debug
<< "divide"; break;
146 case EOpMod
: out
.debug
<< "mod"; break;
147 case EOpRightShift
: out
.debug
<< "right-shift"; break;
148 case EOpLeftShift
: out
.debug
<< "left-shift"; break;
149 case EOpAnd
: out
.debug
<< "bitwise and"; break;
150 case EOpInclusiveOr
: out
.debug
<< "inclusive-or"; break;
151 case EOpExclusiveOr
: out
.debug
<< "exclusive-or"; break;
152 case EOpEqual
: out
.debug
<< "Compare Equal"; break;
153 case EOpNotEqual
: out
.debug
<< "Compare Not Equal"; break;
154 case EOpLessThan
: out
.debug
<< "Compare Less Than"; break;
155 case EOpGreaterThan
: out
.debug
<< "Compare Greater Than"; break;
156 case EOpLessThanEqual
: out
.debug
<< "Compare Less Than or Equal"; break;
157 case EOpGreaterThanEqual
: out
.debug
<< "Compare Greater Than or Equal"; break;
159 case EOpVectorTimesScalar
: out
.debug
<< "vector-scale"; break;
160 case EOpVectorTimesMatrix
: out
.debug
<< "vector-times-matrix"; break;
161 case EOpMatrixTimesVector
: out
.debug
<< "matrix-times-vector"; break;
162 case EOpMatrixTimesScalar
: out
.debug
<< "matrix-scale"; break;
163 case EOpMatrixTimesMatrix
: out
.debug
<< "matrix-multiply"; break;
165 case EOpLogicalOr
: out
.debug
<< "logical-or"; break;
166 case EOpLogicalXor
: out
.debug
<< "logical-xor"; break;
167 case EOpLogicalAnd
: out
.debug
<< "logical-and"; break;
168 default: out
.debug
<< "<unknown op>";
171 out
.debug
<< " (" << node
->getCompleteString() << ")";
178 bool OutputUnary(bool /* preVisit */, TIntermUnary
* node
, TIntermTraverser
* it
)
180 TOutputTraverser
* oit
= static_cast<TOutputTraverser
*>(it
);
181 TInfoSink
& out
= oit
->infoSink
;
183 OutputTreeText(out
, node
, oit
->depth
);
185 switch (node
->getOp()) {
186 case EOpNegative
: out
.debug
<< "Negate value"; break;
187 case EOpVectorLogicalNot
:
188 case EOpLogicalNot
: out
.debug
<< "Negate conditional"; break;
189 case EOpBitwiseNot
: out
.debug
<< "Bitwise not"; break;
191 case EOpPostIncrement
: out
.debug
<< "Post-Increment"; break;
192 case EOpPostDecrement
: out
.debug
<< "Post-Decrement"; break;
193 case EOpPreIncrement
: out
.debug
<< "Pre-Increment"; break;
194 case EOpPreDecrement
: out
.debug
<< "Pre-Decrement"; break;
196 case EOpConvIntToBool
: out
.debug
<< "Convert int to bool"; break;
197 case EOpConvFloatToBool
:out
.debug
<< "Convert float to bool";break;
198 case EOpConvBoolToFloat
:out
.debug
<< "Convert bool to float";break;
199 case EOpConvIntToFloat
: out
.debug
<< "Convert int to float"; break;
200 case EOpConvFloatToInt
: out
.debug
<< "Convert float to int"; break;
201 case EOpConvBoolToInt
: out
.debug
<< "Convert bool to int"; break;
203 case EOpRadians
: out
.debug
<< "radians"; break;
204 case EOpDegrees
: out
.debug
<< "degrees"; break;
205 case EOpSin
: out
.debug
<< "sine"; break;
206 case EOpCos
: out
.debug
<< "cosine"; break;
207 case EOpTan
: out
.debug
<< "tangent"; break;
208 case EOpAsin
: out
.debug
<< "arc sine"; break;
209 case EOpAcos
: out
.debug
<< "arc cosine"; break;
210 case EOpAtan
: out
.debug
<< "arc tangent"; break;
212 case EOpExp
: out
.debug
<< "exp"; break;
213 case EOpLog
: out
.debug
<< "log"; break;
214 case EOpExp2
: out
.debug
<< "exp2"; break;
215 case EOpLog2
: out
.debug
<< "log2"; break;
216 case EOpSqrt
: out
.debug
<< "sqrt"; break;
217 case EOpInverseSqrt
: out
.debug
<< "inverse sqrt"; break;
219 case EOpAbs
: out
.debug
<< "Absolute value"; break;
220 case EOpSign
: out
.debug
<< "Sign"; break;
221 case EOpFloor
: out
.debug
<< "Floor"; break;
222 case EOpCeil
: out
.debug
<< "Ceiling"; break;
223 case EOpFract
: out
.debug
<< "Fraction"; break;
225 case EOpLength
: out
.debug
<< "length"; break;
226 case EOpNormalize
: out
.debug
<< "normalize"; break;
227 case EOpDPdx
: out
.debug
<< "dPdx"; break;
228 case EOpDPdy
: out
.debug
<< "dPdy"; break;
229 case EOpFwidth
: out
.debug
<< "fwidth"; break;
231 case EOpAny
: out
.debug
<< "any"; break;
232 case EOpAll
: out
.debug
<< "all"; break;
234 default: out
.debug
.message(EPrefixError
, "Bad unary op");
237 out
.debug
<< " (" << node
->getCompleteString() << ")";
244 bool OutputAggregate(bool /* preVisit */, TIntermAggregate
* node
, TIntermTraverser
* it
)
246 TOutputTraverser
* oit
= static_cast<TOutputTraverser
*>(it
);
247 TInfoSink
& out
= oit
->infoSink
;
249 if (node
->getOp() == EOpNull
) {
250 out
.debug
.message(EPrefixError
, "node is still EOpNull!");
254 OutputTreeText(out
, node
, oit
->depth
);
256 switch (node
->getOp()) {
257 case EOpSequence
: out
.debug
<< "Sequence\n"; return true;
258 case EOpComma
: out
.debug
<< "Comma\n"; return true;
259 case EOpFunction
: out
.debug
<< "Function Definition: " << node
->getName(); break;
260 case EOpFunctionCall
: out
.debug
<< "Function Call: " << node
->getName(); break;
261 case EOpParameters
: out
.debug
<< "Function Parameters: "; break;
263 case EOpConstructFloat
: out
.debug
<< "Construct float"; break;
264 case EOpConstructVec2
: out
.debug
<< "Construct vec2"; break;
265 case EOpConstructVec3
: out
.debug
<< "Construct vec3"; break;
266 case EOpConstructVec4
: out
.debug
<< "Construct vec4"; break;
267 case EOpConstructBool
: out
.debug
<< "Construct bool"; break;
268 case EOpConstructBVec2
: out
.debug
<< "Construct bvec2"; break;
269 case EOpConstructBVec3
: out
.debug
<< "Construct bvec3"; break;
270 case EOpConstructBVec4
: out
.debug
<< "Construct bvec4"; break;
271 case EOpConstructInt
: out
.debug
<< "Construct int"; break;
272 case EOpConstructIVec2
: out
.debug
<< "Construct ivec2"; break;
273 case EOpConstructIVec3
: out
.debug
<< "Construct ivec3"; break;
274 case EOpConstructIVec4
: out
.debug
<< "Construct ivec4"; break;
275 case EOpConstructMat2
: out
.debug
<< "Construct mat2"; break;
276 case EOpConstructMat3
: out
.debug
<< "Construct mat3"; break;
277 case EOpConstructMat4
: out
.debug
<< "Construct mat4"; break;
278 case EOpConstructStruct
: out
.debug
<< "Construct structure"; break;
280 case EOpLessThan
: out
.debug
<< "Compare Less Than"; break;
281 case EOpGreaterThan
: out
.debug
<< "Compare Greater Than"; break;
282 case EOpLessThanEqual
: out
.debug
<< "Compare Less Than or Equal"; break;
283 case EOpGreaterThanEqual
: out
.debug
<< "Compare Greater Than or Equal"; break;
284 case EOpVectorEqual
: out
.debug
<< "Equal"; break;
285 case EOpVectorNotEqual
: out
.debug
<< "NotEqual"; break;
287 case EOpMod
: out
.debug
<< "mod"; break;
288 case EOpPow
: out
.debug
<< "pow"; break;
290 case EOpAtan
: out
.debug
<< "arc tangent"; break;
292 case EOpMin
: out
.debug
<< "min"; break;
293 case EOpMax
: out
.debug
<< "max"; break;
294 case EOpClamp
: out
.debug
<< "clamp"; break;
295 case EOpMix
: out
.debug
<< "mix"; break;
296 case EOpStep
: out
.debug
<< "step"; break;
297 case EOpSmoothStep
: out
.debug
<< "smoothstep"; break;
299 case EOpDistance
: out
.debug
<< "distance"; break;
300 case EOpDot
: out
.debug
<< "dot-product"; break;
301 case EOpCross
: out
.debug
<< "cross-product"; break;
302 case EOpFaceForward
: out
.debug
<< "face-forward"; break;
303 case EOpReflect
: out
.debug
<< "reflect"; break;
304 case EOpRefract
: out
.debug
<< "refract"; break;
305 case EOpMul
: out
.debug
<< "component-wise multiply"; break;
307 case EOpItof
: out
.debug
<< "itof"; break;
308 case EOpFtoi
: out
.debug
<< "ftoi"; break;
309 case EOpSkipPixels
: out
.debug
<< "skipPixels"; break;
310 case EOpReadInput
: out
.debug
<< "readInput"; break;
311 case EOpWritePixel
: out
.debug
<< "writePixel"; break;
312 case EOpBitmapLsb
: out
.debug
<< "bitmapLSB"; break;
313 case EOpBitmapMsb
: out
.debug
<< "bitmapMSB"; break;
314 case EOpWriteOutput
: out
.debug
<< "writeOutput"; break;
315 case EOpReadPixel
: out
.debug
<< "readPixel"; break;
317 default: out
.debug
.message(EPrefixError
, "Bad aggregation op");
320 if (node
->getOp() != EOpSequence
&& node
->getOp() != EOpParameters
)
321 out
.debug
<< " (" << node
->getCompleteString() << ")";
328 bool OutputSelection(bool /* preVisit */, TIntermSelection
* node
, TIntermTraverser
* it
)
330 TOutputTraverser
* oit
= static_cast<TOutputTraverser
*>(it
);
331 TInfoSink
& out
= oit
->infoSink
;
333 OutputTreeText(out
, node
, oit
->depth
);
335 out
.debug
<< "Test condition and select";
336 out
.debug
<< " (" << node
->getCompleteString() << ")\n";
340 OutputTreeText(oit
->infoSink
, node
, oit
->depth
);
341 out
.debug
<< "Condition\n";
342 node
->getCondition()->traverse(it
);
344 OutputTreeText(oit
->infoSink
, node
, oit
->depth
);
345 if (node
->getTrueBlock()) {
346 out
.debug
<< "true case\n";
347 node
->getTrueBlock()->traverse(it
);
349 out
.debug
<< "true case is null\n";
351 if (node
->getFalseBlock()) {
352 OutputTreeText(oit
->infoSink
, node
, oit
->depth
);
353 out
.debug
<< "false case\n";
354 node
->getFalseBlock()->traverse(it
);
362 void OutputConstantUnion(TIntermConstantUnion
* node
, TIntermTraverser
* it
)
364 TOutputTraverser
* oit
= static_cast<TOutputTraverser
*>(it
);
365 TInfoSink
& out
= oit
->infoSink
;
368 if (node
->getType().getBasicType() == EbtStruct
)
369 size
= node
->getType().getStructSize();
371 size
= node
->getType().getInstanceSize();
373 for (int i
= 0; i
< size
; i
++) {
374 OutputTreeText(out
, node
, oit
->depth
);
375 switch (node
->getType().getBasicType()) {
377 if (node
->getUnionArrayPointer()[i
].bConst
)
380 out
.debug
<< "false";
382 out
.debug
<< " (" << "const bool" << ")";
389 sprintf(buf
, "%f (%s)", node
->getUnionArrayPointer()[i
].fConst
, "const float");
391 out
.debug
<< buf
<< "\n";
397 sprintf(buf
, "%d (%s)", node
->getUnionArrayPointer()[i
].iConst
, "const int");
399 out
.debug
<< buf
<< "\n";
403 out
.info
.message(EPrefixInternalError
, "Unknown constant", node
->getLine());
409 bool OutputLoop(bool /* preVisit */, TIntermLoop
* node
, TIntermTraverser
* it
)
411 TOutputTraverser
* oit
= static_cast<TOutputTraverser
*>(it
);
412 TInfoSink
& out
= oit
->infoSink
;
414 OutputTreeText(out
, node
, oit
->depth
);
416 out
.debug
<< "Loop with condition ";
417 if (! node
->testFirst())
419 out
.debug
<< "tested first\n";
423 OutputTreeText(oit
->infoSink
, node
, oit
->depth
);
424 if (node
->getTest()) {
425 out
.debug
<< "Loop Condition\n";
426 node
->getTest()->traverse(it
);
428 out
.debug
<< "No loop condition\n";
430 OutputTreeText(oit
->infoSink
, node
, oit
->depth
);
431 if (node
->getBody()) {
432 out
.debug
<< "Loop Body\n";
433 node
->getBody()->traverse(it
);
435 out
.debug
<< "No loop body\n";
437 if (node
->getTerminal()) {
438 OutputTreeText(oit
->infoSink
, node
, oit
->depth
);
439 out
.debug
<< "Loop Terminal Expression\n";
440 node
->getTerminal()->traverse(it
);
448 bool OutputBranch(bool /* previsit*/, TIntermBranch
* node
, TIntermTraverser
* it
)
450 TOutputTraverser
* oit
= static_cast<TOutputTraverser
*>(it
);
451 TInfoSink
& out
= oit
->infoSink
;
453 OutputTreeText(out
, node
, oit
->depth
);
455 switch (node
->getFlowOp()) {
456 case EOpKill
: out
.debug
<< "Branch: Kill"; break;
457 case EOpBreak
: out
.debug
<< "Branch: Break"; break;
458 case EOpContinue
: out
.debug
<< "Branch: Continue"; break;
459 case EOpReturn
: out
.debug
<< "Branch: Return"; break;
460 default: out
.debug
<< "Branch: Unknown Branch"; break;
463 if (node
->getExpression()) {
464 out
.debug
<< " with expression\n";
466 node
->getExpression()->traverse(it
);
475 // This function is the one to call externally to start the traversal.
476 // Individual functions can be initialized to 0 to skip processing of that
477 // type of node. It's children will still be processed.
479 void TIntermediate::outputTree(TIntermNode
* root
)
484 TOutputTraverser
it(infoSink
);
486 it
.visitAggregate
= OutputAggregate
;
487 it
.visitBinary
= OutputBinary
;
488 it
.visitConstantUnion
= OutputConstantUnion
;
489 it
.visitSelection
= OutputSelection
;
490 it
.visitSymbol
= OutputSymbol
;
491 it
.visitUnary
= OutputUnary
;
492 it
.visitLoop
= OutputLoop
;
493 it
.visitBranch
= OutputBranch
;