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//
21class TConstTraverser : public TIntermTraverser {
22public:
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
38protected:
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
68void TConstTraverser::visitSymbol(TIntermSymbol* node)
69{
70 infoSink.info.message(EPrefixInternalError, "Symbol Node found in constant constructor", node->getLine());
71 return;
72}
73
74bool 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
92bool 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
102bool 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
150bool 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
157void 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
220bool 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
227bool 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//
239bool 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