Misc. constant-folding fixes: Check % for 0, mat(mat) constructor, index range checki...
[platform/upstream/glslang.git] / glslang / MachineIndependent / parseConst.cpp
1 //
2 //Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
3 //All rights reserved.
4 //
5 //Redistribution and use in source and binary forms, with or without
6 //modification, are permitted provided that the following conditions
7 //are met:
8 //
9 //    Redistributions of source code must retain the above copyright
10 //    notice, this list of conditions and the following disclaimer.
11 //
12 //    Redistributions in binary form must reproduce the above
13 //    copyright notice, this list of conditions and the following
14 //    disclaimer in the documentation and/or other materials provided
15 //    with the distribution.
16 //
17 //    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
18 //    contributors may be used to endorse or promote products derived
19 //    from this software without specific prior written permission.
20 //
21 //THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 //"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 //LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 //FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 //COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 //INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 //BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 //LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 //CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 //LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 //ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 //POSSIBILITY OF SUCH DAMAGE.
33 //
34
35 //
36 // Travarse a tree of constants to create a single folded constant.
37 // It should only be used when the whole tree is known to be constant.
38 //
39
40 #include "ParseHelper.h"
41
42 namespace glslang {
43
44 class TConstTraverser : public TIntermTraverser {
45 public:
46     TConstTraverser(const TConstUnionArray& cUnion, bool singleConstParam, TOperator constructType, const TType& t) : unionArray(cUnion), type(t),
47         constructorType(constructType), singleConstantParam(singleConstParam), error(false), isMatrix(false), 
48         matrixCols(0), matrixRows(0) {  index = 0; tOp = EOpNull; }
49     int index;
50     TConstUnionArray unionArray;
51     TOperator tOp;
52     const TType& type;
53     TOperator constructorType;
54     bool singleConstantParam;
55     bool error;
56     int size; // size of the constructor ( 4 for vec4)
57     bool isMatrix;
58     int matrixCols;
59     int matrixRows;
60 };
61
62 bool ParseAggregate(bool /* preVisit */, TIntermAggregate* node, TIntermTraverser* it)
63 {
64     TConstTraverser* oit = static_cast<TConstTraverser*>(it);
65
66     if (! node->isConstructor() && node->getOp() != EOpComma) {
67         oit->error = true;
68
69         return false;  
70     }
71
72     if (node->getSequence().size() == 0) {
73         oit->error = true;
74
75         return false;
76     }
77
78     bool flag = node->getSequence().size() == 1 && node->getSequence()[0]->getAsTyped()->getAsConstantUnion();
79     if (flag) {
80         oit->singleConstantParam = true; 
81         oit->constructorType = node->getOp();
82         oit->size = node->getType().getObjectSize();
83
84         if (node->getType().isMatrix()) {
85             oit->isMatrix = true;
86             oit->matrixCols = node->getType().getMatrixCols();
87             oit->matrixRows = node->getType().getMatrixRows();
88         }
89     }       
90
91     for (TIntermSequence::iterator p = node->getSequence().begin(); 
92                                    p != node->getSequence().end(); p++) {
93
94         if (node->getOp() == EOpComma)
95             oit->index = 0;           
96
97         (*p)->traverse(oit);
98     }   
99     if (flag) 
100     {
101         oit->singleConstantParam = false;   
102         oit->constructorType = EOpNull;
103         oit->size = 0;
104         oit->isMatrix = false;
105         oit->matrixCols = 0;
106         oit->matrixRows = 0;
107     }
108
109     return false;
110 }
111
112 void ParseConstantUnion(TIntermConstantUnion* node, TIntermTraverser* it)
113 {
114     TConstTraverser* oit = static_cast<TConstTraverser*>(it);
115     TConstUnionArray leftUnionArray(oit->unionArray);
116     int instanceSize = oit->type.getObjectSize();
117
118     if (oit->index >= instanceSize)
119         return;
120
121     if (! oit->singleConstantParam) {
122         int size = node->getType().getObjectSize();
123     
124         const TConstUnionArray& rightUnionArray = node->getConstArray();
125         for (int i = 0; i < size; i++) {
126             if (oit->index >= instanceSize)
127                 return;
128             leftUnionArray[oit->index] = rightUnionArray[i];
129
130             oit->index++;
131         }
132     } else {
133         int endIndex = oit->index + oit->size;
134         const TConstUnionArray& rightUnionArray = node->getConstArray();
135         if (! oit->isMatrix) {
136             int count = 0;
137             for (int i = oit->index; i < endIndex; i++) {
138                 if (i >= instanceSize)
139                     return;
140
141                 leftUnionArray[i] = rightUnionArray[count];
142
143                 (oit->index)++;
144                 
145                 if (node->getType().getObjectSize() > 1)
146                     count++;
147             }
148         } else {
149             // constructing a matrix, but from what?
150             if (node->isMatrix()) {
151                 // Matrix from a matrix; oit has the outer matrix, node is the argument matrix.
152                 // Traverse the outer, potentially bigger matrix, fill in missing pieces with the
153                 // identity matrix.
154                 for (int c = 0; c < oit->matrixCols; ++c) {
155                     for (int r = 0; r < oit->matrixRows; ++r) {
156                         int targetOffset = oit->index + c * oit->matrixRows + r;
157                         if (r < node->getType().getMatrixRows() && c < node->getType().getMatrixCols()) {
158                             int srcOffset = c * node->getType().getMatrixRows() + r;
159                             leftUnionArray[targetOffset] = rightUnionArray[srcOffset];
160                         } else if (r == c)
161                             leftUnionArray[targetOffset].setDConst(1.0);
162                         else
163                             leftUnionArray[targetOffset].setDConst(0.0);
164                     }
165                 }
166             } else {
167                 // matrix from vector
168                 int count = 0;
169                 int index = oit->index;
170                 for (int i = index; i < endIndex; i++) {
171                     if (i >= instanceSize)
172                         return;
173                     if (i == index || (i - index) % (oit->matrixRows + 1) == 0 )
174                         leftUnionArray[i] = rightUnionArray[count];
175                     else 
176                         leftUnionArray[i].setDConst(0.0);
177
178                     oit->index++;
179
180                     if (node->getType().getObjectSize() > 1)
181                         count++;                
182                 }
183             }
184         }
185     }
186 }
187
188 bool TIntermediate::parseConstTree(TIntermNode* root, TConstUnionArray unionArray, TOperator constructorType, const TType& t, bool singleConstantParam)
189 {
190     if (root == 0)
191         return false;
192
193     TConstTraverser it(unionArray, singleConstantParam, constructorType, t);
194     
195     it.visitAggregate = ParseAggregate;
196     it.visitConstantUnion = ParseConstantUnion;
197
198     root->traverse(&it);
199     if (it.error)
200         return true;
201     else
202         return false;
203 }
204
205 } // end namespace glslang