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