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 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
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 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
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) % (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
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