Home | History | Annotate | Download | only in compiler
      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:
     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 
     47 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 
     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 
     87 void TOutputTraverser::visitSymbol(TIntermSymbol* node)
     88 {
     89 	OutputTreeText(sink, node, mDepth);
     90 
     91 	sink << "'" << node->getSymbol() << "' ";
     92 	sink << "(" << node->getCompleteString() << ")\n";
     93 }
     94 
     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 
    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 
    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 
    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 
    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 
    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 
    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 //
    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