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 "ParseHelper.h"
     16 
     17 //
     18 // Use this class to carry along data from node to node in
     19 // the traversal
     20 //
     21 class TConstTraverser : public TIntermTraverser {
     22 public:
     23 	TConstTraverser(ConstantUnion* cUnion, bool singleConstParam, TOperator constructType, TInfoSink& sink, TType& t)
     24 		: error(false),
     25 		  index(0),
     26 		  unionArray(cUnion),
     27 		  type(t),
     28 		  constructorType(constructType),
     29 		  singleConstantParam(singleConstParam),
     30 		  infoSink(sink),
     31 		  size(0),
     32 		  isMatrix(false),
     33 		  matrixSize(0) {
     34 	}
     35 
     36 	bool error;
     37 
     38 protected:
     39 	void visitSymbol(TIntermSymbol*);
     40 	void visitConstantUnion(TIntermConstantUnion*);
     41 	bool visitBinary(Visit visit, TIntermBinary*);
     42 	bool visitUnary(Visit visit, TIntermUnary*);
     43 	bool visitSelection(Visit visit, TIntermSelection*);
     44 	bool visitAggregate(Visit visit, TIntermAggregate*);
     45 	bool visitLoop(Visit visit, TIntermLoop*);
     46 	bool visitBranch(Visit visit, TIntermBranch*);
     47 
     48 	size_t index;
     49 	ConstantUnion *unionArray;
     50 	TType type;
     51 	TOperator constructorType;
     52 	bool singleConstantParam;
     53 	TInfoSink& infoSink;
     54 	size_t size; // size of the constructor ( 4 for vec4)
     55 	bool isMatrix;
     56 	int matrixSize; // dimension of the matrix (nominal size and not the instance size)
     57 };
     58 
     59 //
     60 // The rest of the file are the traversal functions.  The last one
     61 // is the one that starts the traversal.
     62 //
     63 // Return true from interior nodes to have the external traversal
     64 // continue on to children.  If you process children yourself,
     65 // return false.
     66 //
     67 
     68 void TConstTraverser::visitSymbol(TIntermSymbol* node)
     69 {
     70 	infoSink.info.message(EPrefixInternalError, "Symbol Node found in constant constructor", node->getLine());
     71 	return;
     72 }
     73 
     74 bool TConstTraverser::visitBinary(Visit visit, TIntermBinary* node)
     75 {
     76 	TQualifier qualifier = node->getType().getQualifier();
     77 
     78 	if (qualifier != EvqConstExpr) {
     79 		TString buf;
     80 		buf.append("'constructor' : assigning non-constant to ");
     81 		buf.append(type.getCompleteString());
     82 		infoSink.info.message(EPrefixError, buf.c_str(), node->getLine());
     83 		error = true;
     84 		return false;
     85 	}
     86 
     87 	infoSink.info.message(EPrefixInternalError, "Binary Node found in constant constructor", node->getLine());
     88 
     89 	return false;
     90 }
     91 
     92 bool TConstTraverser::visitUnary(Visit visit, TIntermUnary* node)
     93 {
     94 	TString buf;
     95 	buf.append("'constructor' : assigning non-constant to ");
     96 	buf.append(type.getCompleteString());
     97 	infoSink.info.message(EPrefixError, buf.c_str(), node->getLine());
     98 	error = true;
     99 	return false;
    100 }
    101 
    102 bool TConstTraverser::visitAggregate(Visit visit, TIntermAggregate* node)
    103 {
    104 	if (!node->isConstructor() && node->getOp() != EOpComma) {
    105 		TString buf;
    106 		buf.append("'constructor' : assigning non-constant to ");
    107 		buf.append(type.getCompleteString());
    108 		infoSink.info.message(EPrefixError, buf.c_str(), node->getLine());
    109 		error = true;
    110 		return false;
    111 	}
    112 
    113 	if (node->getSequence().size() == 0) {
    114 		error = true;
    115 		return false;
    116 	}
    117 
    118 	bool flag = node->getSequence().size() == 1 && node->getSequence()[0]->getAsTyped()->getAsConstantUnion();
    119 	if (flag)
    120 	{
    121 		singleConstantParam = true;
    122 		constructorType = node->getOp();
    123 		size = node->getType().getObjectSize();
    124 
    125 		if (node->getType().isMatrix()) {
    126 			isMatrix = true;
    127 			matrixSize = node->getType().getNominalSize();
    128 		}
    129 	}
    130 
    131 	for (TIntermSequence::iterator p = node->getSequence().begin();
    132 	                               p != node->getSequence().end(); p++) {
    133 
    134 		if (node->getOp() == EOpComma)
    135 			index = 0;
    136 
    137 		(*p)->traverse(this);
    138 	}
    139 	if (flag)
    140 	{
    141 		singleConstantParam = false;
    142 		constructorType = EOpNull;
    143 		size = 0;
    144 		isMatrix = false;
    145 		matrixSize = 0;
    146 	}
    147 	return false;
    148 }
    149 
    150 bool TConstTraverser::visitSelection(Visit visit, TIntermSelection* node)
    151 {
    152 	infoSink.info.message(EPrefixInternalError, "Selection Node found in constant constructor", node->getLine());
    153 	error = true;
    154 	return false;
    155 }
    156 
    157 void TConstTraverser::visitConstantUnion(TIntermConstantUnion* node)
    158 {
    159 	if (!node->getUnionArrayPointer())
    160 	{
    161 		// The constant was not initialized, this should already have been logged
    162 		assert(infoSink.info.size() != 0);
    163 		return;
    164 	}
    165 
    166 	ConstantUnion* leftUnionArray = unionArray;
    167 	size_t instanceSize = type.getObjectSize();
    168 	TBasicType basicType = type.getBasicType();
    169 
    170 	if (index >= instanceSize)
    171 		return;
    172 
    173 	if (!singleConstantParam) {
    174 		size_t size = node->getType().getObjectSize();
    175 
    176 		ConstantUnion *rightUnionArray = node->getUnionArrayPointer();
    177 		for(size_t i = 0; i < size; i++) {
    178 			if (index >= instanceSize)
    179 				return;
    180 			leftUnionArray[index].cast(basicType, rightUnionArray[i]);
    181 
    182 			(index)++;
    183 		}
    184 	} else {
    185 		size_t totalSize = index + size;
    186 		ConstantUnion *rightUnionArray = node->getUnionArrayPointer();
    187 		if (!isMatrix) {
    188 			int count = 0;
    189 			for(size_t i = index; i < totalSize; i++) {
    190 				if (i >= instanceSize)
    191 					return;
    192 
    193 				leftUnionArray[i].cast(basicType, rightUnionArray[count]);
    194 
    195 				(index)++;
    196 
    197 				if (node->getType().getObjectSize() > 1)
    198 					count++;
    199 			}
    200 		} else {  // for matrix constructors
    201 			int count = 0;
    202 			int element = index;
    203 			for(size_t i = index; i < totalSize; i++) {
    204 				if (i >= instanceSize)
    205 					return;
    206 				if (element - i == 0 || (i - element) % (matrixSize + 1) == 0 )
    207 					leftUnionArray[i].cast(basicType, rightUnionArray[0]);
    208 				else
    209 					leftUnionArray[i].setFConst(0.0f);
    210 
    211 				(index)++;
    212 
    213 				if (node->getType().getObjectSize() > 1)
    214 					count++;
    215 			}
    216 		}
    217 	}
    218 }
    219 
    220 bool TConstTraverser::visitLoop(Visit visit, TIntermLoop* node)
    221 {
    222 	infoSink.info.message(EPrefixInternalError, "Loop Node found in constant constructor", node->getLine());
    223 	error = true;
    224 	return false;
    225 }
    226 
    227 bool TConstTraverser::visitBranch(Visit visit, TIntermBranch* node)
    228 {
    229 	infoSink.info.message(EPrefixInternalError, "Branch Node found in constant constructor", node->getLine());
    230 	error = true;
    231 	return false;
    232 }
    233 
    234 //
    235 // This function is the one to call externally to start the traversal.
    236 // Individual functions can be initialized to 0 to skip processing of that
    237 // type of node.  It's children will still be processed.
    238 //
    239 bool TIntermediate::parseConstTree(const TSourceLoc& line, TIntermNode* root, ConstantUnion* unionArray, TOperator constructorType, TType t, bool singleConstantParam)
    240 {
    241 	if (root == 0)
    242 		return false;
    243 
    244 	TConstTraverser it(unionArray, singleConstantParam, constructorType, infoSink, t);
    245 
    246 	root->traverse(&it);
    247 	if (it.error)
    248 		return true;
    249 	else
    250 		return false;
    251 }
    252