blob: 26af4086f8cc40c8753de591f2a8e660cab28da8 [file] [log] [blame]
Nicolas Capens0bac2852016-05-07 06:09:58 -04001// Copyright 2016 The SwiftShader Authors. All Rights Reserved.
John Bauman89401822014-05-06 15:04:28 -04002//
Nicolas Capens0bac2852016-05-07 06:09:58 -04003// 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
John Bauman89401822014-05-06 15:04:28 -04006//
Nicolas Capens0bac2852016-05-07 06:09:58 -04007// 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.
John Bauman89401822014-05-06 15:04:28 -040014
Nicolas Capenscc863da2015-01-21 15:50:55 -050015#include "ParseHelper.h"
John Bauman89401822014-05-06 15:04:28 -040016
17//
Nicolas Capens0bac2852016-05-07 06:09:58 -040018// Use this class to carry along data from node to node in
John Bauman89401822014-05-06 15:04:28 -040019// the traversal
20//
21class TConstTraverser : public TIntermTraverser {
22public:
Nicolas Capens0bac2852016-05-07 06:09:58 -040023 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),
Chris Forbesd46e9f62018-09-21 11:30:15 -070033 matrixRows(0) {
Nicolas Capens0bac2852016-05-07 06:09:58 -040034 }
John Bauman89401822014-05-06 15:04:28 -040035
Nicolas Capens0bac2852016-05-07 06:09:58 -040036 bool error;
John Bauman89401822014-05-06 15:04:28 -040037
38protected:
Nicolas Capens0bac2852016-05-07 06:09:58 -040039 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*);
John Bauman89401822014-05-06 15:04:28 -040047
Nicolas Capens0bac2852016-05-07 06:09:58 -040048 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;
Chris Forbesd46e9f62018-09-21 11:30:15 -070056 int matrixRows; // number of rows in the matrix (nominal size and not the instance size)
John Bauman89401822014-05-06 15:04:28 -040057};
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{
Nicolas Capens0bac2852016-05-07 06:09:58 -040070 infoSink.info.message(EPrefixInternalError, "Symbol Node found in constant constructor", node->getLine());
71 return;
John Bauman89401822014-05-06 15:04:28 -040072}
73
74bool TConstTraverser::visitBinary(Visit visit, TIntermBinary* node)
75{
Nicolas Capens0bac2852016-05-07 06:09:58 -040076 TQualifier qualifier = node->getType().getQualifier();
Nicolas Capensc3bfb402014-06-12 11:45:17 -040077
Nicolas Capens0bac2852016-05-07 06:09:58 -040078 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 }
John Bauman89401822014-05-06 15:04:28 -040086
Nicolas Capens0bac2852016-05-07 06:09:58 -040087 infoSink.info.message(EPrefixInternalError, "Binary Node found in constant constructor", node->getLine());
Nicolas Capensc3bfb402014-06-12 11:45:17 -040088
Nicolas Capens0bac2852016-05-07 06:09:58 -040089 return false;
John Bauman89401822014-05-06 15:04:28 -040090}
91
92bool TConstTraverser::visitUnary(Visit visit, TIntermUnary* node)
93{
Nicolas Capens0bac2852016-05-07 06:09:58 -040094 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;
John Bauman89401822014-05-06 15:04:28 -0400100}
101
102bool TConstTraverser::visitAggregate(Visit visit, TIntermAggregate* node)
103{
Nicolas Capens0bac2852016-05-07 06:09:58 -0400104 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 }
John Bauman89401822014-05-06 15:04:28 -0400112
Nicolas Capens0bac2852016-05-07 06:09:58 -0400113 if (node->getSequence().size() == 0) {
114 error = true;
115 return false;
116 }
John Bauman89401822014-05-06 15:04:28 -0400117
Nicolas Capens0bac2852016-05-07 06:09:58 -0400118 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();
John Bauman89401822014-05-06 15:04:28 -0400124
Nicolas Capens0bac2852016-05-07 06:09:58 -0400125 if (node->getType().isMatrix()) {
126 isMatrix = true;
Chris Forbesd46e9f62018-09-21 11:30:15 -0700127 matrixRows = node->getType().getSecondarySize();
Nicolas Capens0bac2852016-05-07 06:09:58 -0400128 }
129 }
John Bauman89401822014-05-06 15:04:28 -0400130
Nicolas Capens0bac2852016-05-07 06:09:58 -0400131 for (TIntermSequence::iterator p = node->getSequence().begin();
132 p != node->getSequence().end(); p++) {
John Bauman89401822014-05-06 15:04:28 -0400133
Nicolas Capens0bac2852016-05-07 06:09:58 -0400134 if (node->getOp() == EOpComma)
135 index = 0;
John Bauman89401822014-05-06 15:04:28 -0400136
Nicolas Capens0bac2852016-05-07 06:09:58 -0400137 (*p)->traverse(this);
138 }
139 if (flag)
140 {
141 singleConstantParam = false;
142 constructorType = EOpNull;
143 size = 0;
144 isMatrix = false;
Chris Forbesd46e9f62018-09-21 11:30:15 -0700145 matrixRows = 0;
Nicolas Capens0bac2852016-05-07 06:09:58 -0400146 }
147 return false;
John Bauman89401822014-05-06 15:04:28 -0400148}
149
150bool TConstTraverser::visitSelection(Visit visit, TIntermSelection* node)
151{
Nicolas Capens0bac2852016-05-07 06:09:58 -0400152 infoSink.info.message(EPrefixInternalError, "Selection Node found in constant constructor", node->getLine());
153 error = true;
154 return false;
John Bauman89401822014-05-06 15:04:28 -0400155}
156
157void TConstTraverser::visitConstantUnion(TIntermConstantUnion* node)
158{
Nicolas Capens0bac2852016-05-07 06:09:58 -0400159 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 }
Nicolas Capens2e2ba8d2015-02-10 13:55:57 -0500165
Nicolas Capens0bac2852016-05-07 06:09:58 -0400166 ConstantUnion* leftUnionArray = unionArray;
167 size_t instanceSize = type.getObjectSize();
168 TBasicType basicType = type.getBasicType();
John Bauman89401822014-05-06 15:04:28 -0400169
Nicolas Capens0bac2852016-05-07 06:09:58 -0400170 if (index >= instanceSize)
171 return;
John Bauman89401822014-05-06 15:04:28 -0400172
Nicolas Capens0bac2852016-05-07 06:09:58 -0400173 if (!singleConstantParam) {
174 size_t size = node->getType().getObjectSize();
Nicolas Capensc3bfb402014-06-12 11:45:17 -0400175
Nicolas Capens0bac2852016-05-07 06:09:58 -0400176 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]);
John Bauman89401822014-05-06 15:04:28 -0400181
Nicolas Capens0bac2852016-05-07 06:09:58 -0400182 (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;
John Bauman89401822014-05-06 15:04:28 -0400192
Nicolas Capens0bac2852016-05-07 06:09:58 -0400193 leftUnionArray[i].cast(basicType, rightUnionArray[count]);
John Bauman89401822014-05-06 15:04:28 -0400194
Nicolas Capens0bac2852016-05-07 06:09:58 -0400195 (index)++;
Nicolas Capensc3bfb402014-06-12 11:45:17 -0400196
Nicolas Capens0bac2852016-05-07 06:09:58 -0400197 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;
Chris Forbesd46e9f62018-09-21 11:30:15 -0700206 if (element - i == 0 || (i - element) % (matrixRows + 1) == 0 )
Nicolas Capens0bac2852016-05-07 06:09:58 -0400207 leftUnionArray[i].cast(basicType, rightUnionArray[0]);
208 else
209 leftUnionArray[i].setFConst(0.0f);
John Bauman89401822014-05-06 15:04:28 -0400210
Nicolas Capens0bac2852016-05-07 06:09:58 -0400211 (index)++;
John Bauman89401822014-05-06 15:04:28 -0400212
Nicolas Capens0bac2852016-05-07 06:09:58 -0400213 if (node->getType().getObjectSize() > 1)
214 count++;
215 }
216 }
217 }
John Bauman89401822014-05-06 15:04:28 -0400218}
219
220bool TConstTraverser::visitLoop(Visit visit, TIntermLoop* node)
221{
Nicolas Capens0bac2852016-05-07 06:09:58 -0400222 infoSink.info.message(EPrefixInternalError, "Loop Node found in constant constructor", node->getLine());
223 error = true;
224 return false;
John Bauman89401822014-05-06 15:04:28 -0400225}
226
227bool TConstTraverser::visitBranch(Visit visit, TIntermBranch* node)
228{
Nicolas Capens0bac2852016-05-07 06:09:58 -0400229 infoSink.info.message(EPrefixInternalError, "Branch Node found in constant constructor", node->getLine());
230 error = true;
231 return false;
John Bauman89401822014-05-06 15:04:28 -0400232}
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//
Alexis Hetu253fdd12015-07-07 15:12:46 -0400239bool TIntermediate::parseConstTree(const TSourceLoc& line, TIntermNode* root, ConstantUnion* unionArray, TOperator constructorType, TType t, bool singleConstantParam)
John Bauman89401822014-05-06 15:04:28 -0400240{
Nicolas Capens0bac2852016-05-07 06:09:58 -0400241 if (root == 0)
242 return false;
John Bauman89401822014-05-06 15:04:28 -0400243
Nicolas Capens0bac2852016-05-07 06:09:58 -0400244 TConstTraverser it(unionArray, singleConstantParam, constructorType, infoSink, t);
John Bauman89401822014-05-06 15:04:28 -0400245
Nicolas Capens0bac2852016-05-07 06:09:58 -0400246 root->traverse(&it);
247 if (it.error)
248 return true;
249 else
250 return false;
John Bauman89401822014-05-06 15:04:28 -0400251}