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