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:
TConstTraverser(ConstantUnion * cUnion,bool singleConstParam,TOperator constructType,TInfoSink & sink,TType & t)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 		  matrixRows(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 matrixRows; // number of rows in 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 
visitSymbol(TIntermSymbol * node)68 void TConstTraverser::visitSymbol(TIntermSymbol* node)
69 {
70 	infoSink.info.message(EPrefixInternalError, "Symbol Node found in constant constructor", node->getLine());
71 	return;
72 }
73 
visitBinary(Visit visit,TIntermBinary * node)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 
visitUnary(Visit visit,TIntermUnary * node)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 
visitAggregate(Visit visit,TIntermAggregate * node)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 			matrixRows = node->getType().getSecondarySize();
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 		matrixRows = 0;
146 	}
147 	return false;
148 }
149 
visitSelection(Visit visit,TIntermSelection * node)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 
visitConstantUnion(TIntermConstantUnion * node)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) % (matrixRows + 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 
visitLoop(Visit visit,TIntermLoop * node)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 
visitBranch(Visit visit,TIntermBranch * node)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 //
parseConstTree(const TSourceLoc & line,TIntermNode * root,ConstantUnion * unionArray,TOperator constructorType,TType t,bool singleConstantParam)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