xref: /aosp_15_r20/external/angle/src/tests/compiler_tests/ConstantFolding_test.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1 //
2 // Copyright 2015 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 // ConstantFolding_test.cpp:
7 //   Tests for constant folding
8 //
9 
10 #include "tests/test_utils/ConstantFoldingTest.h"
11 
12 using namespace sh;
13 
14 // Test that zero, true or false are not found in AST when they are not expected. This is to make
15 // sure that the subsequent tests run correctly.
TEST_F(ConstantFoldingExpressionTest,FoldFloatTestCheck)16 TEST_F(ConstantFoldingExpressionTest, FoldFloatTestCheck)
17 {
18     const std::string &floatString = "1.0";
19     evaluateFloat(floatString);
20     ASSERT_FALSE(constantFoundInAST(0.0f));
21     ASSERT_FALSE(constantFoundInAST(true));
22     ASSERT_FALSE(constantFoundInAST(false));
23 }
24 
TEST_F(ConstantFoldingTest,FoldIntegerAdd)25 TEST_F(ConstantFoldingTest, FoldIntegerAdd)
26 {
27     const std::string &shaderString =
28         "#version 300 es\n"
29         "precision mediump float;\n"
30         "out int my_Int;\n"
31         "void main() {\n"
32         "   const int i = 1124 + 5;\n"
33         "   my_Int = i;\n"
34         "}\n";
35     compileAssumeSuccess(shaderString);
36     ASSERT_FALSE(constantFoundInAST(1124));
37     ASSERT_FALSE(constantFoundInAST(5));
38     ASSERT_TRUE(constantFoundInAST(1129));
39 }
40 
TEST_F(ConstantFoldingTest,FoldIntegerSub)41 TEST_F(ConstantFoldingTest, FoldIntegerSub)
42 {
43     const std::string &shaderString =
44         "#version 300 es\n"
45         "precision mediump float;\n"
46         "out int my_Int;\n"
47         "void main() {\n"
48         "   const int i = 1124 - 5;\n"
49         "   my_Int = i;\n"
50         "}\n";
51     compileAssumeSuccess(shaderString);
52     ASSERT_FALSE(constantFoundInAST(1124));
53     ASSERT_FALSE(constantFoundInAST(5));
54     ASSERT_TRUE(constantFoundInAST(1119));
55 }
56 
TEST_F(ConstantFoldingTest,FoldIntegerMul)57 TEST_F(ConstantFoldingTest, FoldIntegerMul)
58 {
59     const std::string &shaderString =
60         "#version 300 es\n"
61         "precision mediump float;\n"
62         "out int my_Int;\n"
63         "void main() {\n"
64         "   const int i = 1124 * 5;\n"
65         "   my_Int = i;\n"
66         "}\n";
67     compileAssumeSuccess(shaderString);
68     ASSERT_FALSE(constantFoundInAST(1124));
69     ASSERT_FALSE(constantFoundInAST(5));
70     ASSERT_TRUE(constantFoundInAST(5620));
71 }
72 
TEST_F(ConstantFoldingTest,FoldIntegerDiv)73 TEST_F(ConstantFoldingTest, FoldIntegerDiv)
74 {
75     const std::string &shaderString =
76         "#version 300 es\n"
77         "precision mediump float;\n"
78         "out int my_Int;\n"
79         "void main() {\n"
80         "   const int i = 1124 / 5;\n"
81         "   my_Int = i;\n"
82         "}\n";
83     compileAssumeSuccess(shaderString);
84     ASSERT_FALSE(constantFoundInAST(1124));
85     ASSERT_FALSE(constantFoundInAST(5));
86     // Rounding mode of division is undefined in the spec but ANGLE can be expected to round down.
87     ASSERT_TRUE(constantFoundInAST(224));
88 }
89 
TEST_F(ConstantFoldingTest,FoldIntegerModulus)90 TEST_F(ConstantFoldingTest, FoldIntegerModulus)
91 {
92     const std::string &shaderString =
93         "#version 300 es\n"
94         "precision mediump float;\n"
95         "out int my_Int;\n"
96         "void main() {\n"
97         "   const int i = 1124 % 5;\n"
98         "   my_Int = i;\n"
99         "}\n";
100     compileAssumeSuccess(shaderString);
101     ASSERT_FALSE(constantFoundInAST(1124));
102     ASSERT_FALSE(constantFoundInAST(5));
103     ASSERT_TRUE(constantFoundInAST(4));
104 }
105 
TEST_F(ConstantFoldingTest,FoldVectorCrossProduct)106 TEST_F(ConstantFoldingTest, FoldVectorCrossProduct)
107 {
108     const std::string &shaderString =
109         "#version 300 es\n"
110         "precision mediump float;\n"
111         "out vec3 my_Vec3;"
112         "void main() {\n"
113         "   const vec3 v3 = cross(vec3(1.0f, 1.0f, 1.0f), vec3(1.0f, -1.0f, 1.0f));\n"
114         "   my_Vec3 = v3;\n"
115         "}\n";
116     compileAssumeSuccess(shaderString);
117     std::vector<float> input1(3, 1.0f);
118     ASSERT_FALSE(constantVectorFoundInAST(input1));
119     std::vector<float> input2;
120     input2.push_back(1.0f);
121     input2.push_back(-1.0f);
122     input2.push_back(1.0f);
123     ASSERT_FALSE(constantVectorFoundInAST(input2));
124     std::vector<float> result;
125     result.push_back(2.0f);
126     result.push_back(0.0f);
127     result.push_back(-2.0f);
128     ASSERT_TRUE(constantVectorFoundInAST(result));
129 }
130 
131 // FoldMxNMatrixInverse tests check if the matrix 'inverse' operation
132 // on MxN matrix is constant folded when argument is constant expression and also
133 // checks the correctness of the result returned by the constant folding operation.
134 // All the matrices including matrices in the shader code are in column-major order.
TEST_F(ConstantFoldingTest,Fold2x2MatrixInverse)135 TEST_F(ConstantFoldingTest, Fold2x2MatrixInverse)
136 {
137     const std::string &shaderString =
138         "#version 300 es\n"
139         "precision mediump float;\n"
140         "in float i;\n"
141         "out vec2 my_Vec;\n"
142         "void main() {\n"
143         "   const mat2 m2 = inverse(mat2(2.0f, 3.0f,\n"
144         "                                5.0f, 7.0f));\n"
145         "   mat2 m = m2 * mat2(i);\n"
146         "   my_Vec = m[0];\n"
147         "}\n";
148     compileAssumeSuccess(shaderString);
149     float inputElements[] = {2.0f, 3.0f, 5.0f, 7.0f};
150     std::vector<float> input(inputElements, inputElements + 4);
151     ASSERT_FALSE(constantColumnMajorMatrixFoundInAST(input));
152     float outputElements[] = {-7.0f, 3.0f, 5.0f, -2.0f};
153     std::vector<float> result(outputElements, outputElements + 4);
154     ASSERT_TRUE(constantColumnMajorMatrixFoundInAST(result));
155 }
156 
157 // Check if the matrix 'inverse' operation on 3x3 matrix is constant folded.
TEST_F(ConstantFoldingTest,Fold3x3MatrixInverse)158 TEST_F(ConstantFoldingTest, Fold3x3MatrixInverse)
159 {
160     const std::string &shaderString =
161         "#version 300 es\n"
162         "precision mediump float;\n"
163         "in float i;\n"
164         "out vec3 my_Vec;\n"
165         "void main() {\n"
166         "   const mat3 m3 = inverse(mat3(11.0f, 13.0f, 19.0f,\n"
167         "                                23.0f, 29.0f, 31.0f,\n"
168         "                                37.0f, 41.0f, 43.0f));\n"
169         "   mat3 m = m3 * mat3(i);\n"
170         "   my_Vec = m[0];\n"
171         "}\n";
172     compileAssumeSuccess(shaderString);
173     float inputElements[] = {11.0f, 13.0f, 19.0f, 23.0f, 29.0f, 31.0f, 37.0f, 41.0f, 43.0f};
174     std::vector<float> input(inputElements, inputElements + 9);
175     ASSERT_FALSE(constantVectorFoundInAST(input));
176     float outputElements[] = {3.0f / 85.0f,    -11.0f / 34.0f, 37.0f / 170.0f,
177                               -79.0f / 340.0f, 23.0f / 68.0f,  -12.0f / 85.0f,
178                               13.0f / 68.0f,   -3.0f / 68.0f,  -1.0f / 34.0f};
179     std::vector<float> result(outputElements, outputElements + 9);
180     const float floatFaultTolerance = 0.000001f;
181     ASSERT_TRUE(constantVectorNearFoundInAST(result, floatFaultTolerance));
182 }
183 
184 // Check if the matrix 'inverse' operation on 4x4 matrix is constant folded.
TEST_F(ConstantFoldingTest,Fold4x4MatrixInverse)185 TEST_F(ConstantFoldingTest, Fold4x4MatrixInverse)
186 {
187     const std::string &shaderString =
188         "#version 300 es\n"
189         "precision mediump float;\n"
190         "in float i;\n"
191         "out vec4 my_Vec;\n"
192         "void main() {\n"
193         "   const mat4 m4 = inverse(mat4(29.0f, 31.0f, 37.0f, 41.0f,\n"
194         "                                43.0f, 47.0f, 53.0f, 59.0f,\n"
195         "                                61.0f, 67.0f, 71.0f, 73.0f,\n"
196         "                                79.0f, 83.0f, 89.0f, 97.0f));\n"
197         "   mat4 m = m4 * mat4(i);\n"
198         "   my_Vec = m[0];\n"
199         "}\n";
200     compileAssumeSuccess(shaderString);
201     float inputElements[] = {29.0f, 31.0f, 37.0f, 41.0f, 43.0f, 47.0f, 53.0f, 59.0f,
202                              61.0f, 67.0f, 71.0f, 73.0f, 79.0f, 83.0f, 89.0f, 97.0f};
203     std::vector<float> input(inputElements, inputElements + 16);
204     ASSERT_FALSE(constantVectorFoundInAST(input));
205     float outputElements[] = {43.0f / 126.0f, -11.0f / 21.0f, -2.0f / 21.0f,  31.0f / 126.0f,
206                               -5.0f / 7.0f,   9.0f / 14.0f,   1.0f / 14.0f,   -1.0f / 7.0f,
207                               85.0f / 126.0f, -11.0f / 21.0f, 43.0f / 210.0f, -38.0f / 315.0f,
208                               -2.0f / 7.0f,   5.0f / 14.0f,   -6.0f / 35.0f,  3.0f / 70.0f};
209     std::vector<float> result(outputElements, outputElements + 16);
210     const float floatFaultTolerance = 0.00001f;
211     ASSERT_TRUE(constantVectorNearFoundInAST(result, floatFaultTolerance));
212 }
213 
214 // FoldMxNMatrixDeterminant tests check if the matrix 'determinant' operation
215 // on MxN matrix is constant folded when argument is constant expression and also
216 // checks the correctness of the result returned by the constant folding operation.
217 // All the matrices including matrices in the shader code are in column-major order.
TEST_F(ConstantFoldingTest,Fold2x2MatrixDeterminant)218 TEST_F(ConstantFoldingTest, Fold2x2MatrixDeterminant)
219 {
220     const std::string &shaderString =
221         "#version 300 es\n"
222         "precision mediump float;\n"
223         "out float my_Float;"
224         "void main() {\n"
225         "   const float f = determinant(mat2(2.0f, 3.0f,\n"
226         "                                    5.0f, 7.0f));\n"
227         "   my_Float = f;\n"
228         "}\n";
229     compileAssumeSuccess(shaderString);
230     float inputElements[] = {2.0f, 3.0f, 5.0f, 7.0f};
231     std::vector<float> input(inputElements, inputElements + 4);
232     ASSERT_FALSE(constantColumnMajorMatrixFoundInAST(input));
233     ASSERT_TRUE(constantFoundInAST(-1.0f));
234 }
235 
236 // Check if the matrix 'determinant' operation on 3x3 matrix is constant folded.
TEST_F(ConstantFoldingTest,Fold3x3MatrixDeterminant)237 TEST_F(ConstantFoldingTest, Fold3x3MatrixDeterminant)
238 {
239     const std::string &shaderString =
240         "#version 300 es\n"
241         "precision mediump float;\n"
242         "out float my_Float;"
243         "void main() {\n"
244         "   const float f = determinant(mat3(11.0f, 13.0f, 19.0f,\n"
245         "                               23.0f, 29.0f, 31.0f,\n"
246         "                                    37.0f, 41.0f, 43.0f));\n"
247         "   my_Float = f;\n"
248         "}\n";
249     compileAssumeSuccess(shaderString);
250     float inputElements[] = {11.0f, 13.0f, 19.0f, 23.0f, 29.0f, 31.0f, 37.0f, 41.0f, 43.0f};
251     std::vector<float> input(inputElements, inputElements + 9);
252     ASSERT_FALSE(constantColumnMajorMatrixFoundInAST(input));
253     ASSERT_TRUE(constantFoundInAST(-680.0f));
254 }
255 
256 // Check if the matrix 'determinant' operation on 4x4 matrix is constant folded.
TEST_F(ConstantFoldingTest,Fold4x4MatrixDeterminant)257 TEST_F(ConstantFoldingTest, Fold4x4MatrixDeterminant)
258 {
259     const std::string &shaderString =
260         "#version 300 es\n"
261         "precision mediump float;\n"
262         "out float my_Float;"
263         "void main() {\n"
264         "   const float f = determinant(mat4(29.0f, 31.0f, 37.0f, 41.0f,\n"
265         "                                    43.0f, 47.0f, 53.0f, 59.0f,\n"
266         "                                    61.0f, 67.0f, 71.0f, 73.0f,\n"
267         "                                    79.0f, 83.0f, 89.0f, 97.0f));\n"
268         "   my_Float = f;\n"
269         "}\n";
270     compileAssumeSuccess(shaderString);
271     float inputElements[] = {29.0f, 31.0f, 37.0f, 41.0f, 43.0f, 47.0f, 53.0f, 59.0f,
272                              61.0f, 67.0f, 71.0f, 73.0f, 79.0f, 83.0f, 89.0f, 97.0f};
273     std::vector<float> input(inputElements, inputElements + 16);
274     ASSERT_FALSE(constantColumnMajorMatrixFoundInAST(input));
275     ASSERT_TRUE(constantFoundInAST(-2520.0f));
276 }
277 
278 // Check if the matrix 'transpose' operation on 3x3 matrix is constant folded.
279 // All the matrices including matrices in the shader code are in column-major order.
TEST_F(ConstantFoldingTest,Fold3x3MatrixTranspose)280 TEST_F(ConstantFoldingTest, Fold3x3MatrixTranspose)
281 {
282     const std::string &shaderString =
283         "#version 300 es\n"
284         "precision mediump float;\n"
285         "in float i;\n"
286         "out vec3 my_Vec;\n"
287         "void main() {\n"
288         "   const mat3 m3 = transpose(mat3(11.0f, 13.0f, 19.0f,\n"
289         "                                  23.0f, 29.0f, 31.0f,\n"
290         "                                  37.0f, 41.0f, 43.0f));\n"
291         "   mat3 m = m3 * mat3(i);\n"
292         "   my_Vec = m[0];\n"
293         "}\n";
294     compileAssumeSuccess(shaderString);
295     float inputElements[] = {11.0f, 13.0f, 19.0f, 23.0f, 29.0f, 31.0f, 37.0f, 41.0f, 43.0f};
296     std::vector<float> input(inputElements, inputElements + 9);
297     ASSERT_FALSE(constantColumnMajorMatrixFoundInAST(input));
298     float outputElements[] = {11.0f, 23.0f, 37.0f, 13.0f, 29.0f, 41.0f, 19.0f, 31.0f, 43.0f};
299     std::vector<float> result(outputElements, outputElements + 9);
300     ASSERT_TRUE(constantColumnMajorMatrixFoundInAST(result));
301 }
302 
303 // Test that 0xFFFFFFFF wraps to -1 when parsed as integer.
304 // This is featured in the examples of ESSL3 section 4.1.3. ESSL3 section 12.42
305 // means that any 32-bit unsigned integer value is a valid literal.
TEST_F(ConstantFoldingTest,ParseWrappedHexIntLiteral)306 TEST_F(ConstantFoldingTest, ParseWrappedHexIntLiteral)
307 {
308     const std::string &shaderString =
309         "#version 300 es\n"
310         "precision mediump float;\n"
311         "precision highp int;\n"
312         "uniform int inInt;\n"
313         "out vec4 my_Vec;\n"
314         "void main() {\n"
315         "   const int i = 0xFFFFFFFF;\n"
316         "   my_Vec = vec4(i * inInt);\n"
317         "}\n";
318     compileAssumeSuccess(shaderString);
319     ASSERT_TRUE(constantFoundInAST(-1));
320 }
321 
322 // Test that 3000000000 wraps to -1294967296 when parsed as integer.
323 // This is featured in the examples of GLSL 4.5, and ESSL behavior should match
324 // desktop GLSL when it comes to integer parsing.
TEST_F(ConstantFoldingTest,ParseWrappedDecimalIntLiteral)325 TEST_F(ConstantFoldingTest, ParseWrappedDecimalIntLiteral)
326 {
327     const std::string &shaderString =
328         "#version 300 es\n"
329         "precision mediump float;\n"
330         "precision highp int;\n"
331         "uniform int inInt;\n"
332         "out vec4 my_Vec;\n"
333         "void main() {\n"
334         "   const int i = 3000000000;\n"
335         "   my_Vec = vec4(i * inInt);\n"
336         "}\n";
337     compileAssumeSuccess(shaderString);
338     ASSERT_TRUE(constantFoundInAST(-1294967296));
339 }
340 
341 // Test that 0xFFFFFFFFu is parsed correctly as an unsigned integer literal.
342 // This is featured in the examples of ESSL3 section 4.1.3. ESSL3 section 12.42
343 // means that any 32-bit unsigned integer value is a valid literal.
TEST_F(ConstantFoldingTest,ParseMaxUintLiteral)344 TEST_F(ConstantFoldingTest, ParseMaxUintLiteral)
345 {
346     const std::string &shaderString =
347         "#version 300 es\n"
348         "precision mediump float;\n"
349         "precision highp int;\n"
350         "uniform uint inInt;\n"
351         "out vec4 my_Vec;\n"
352         "void main() {\n"
353         "   const uint i = 0xFFFFFFFFu;\n"
354         "   my_Vec = vec4(i * inInt);\n"
355         "}\n";
356     compileAssumeSuccess(shaderString);
357     ASSERT_TRUE(constantFoundInAST(0xFFFFFFFFu));
358 }
359 
360 // Test that unary minus applied to unsigned int is constant folded correctly.
361 // This is featured in the examples of ESSL3 section 4.1.3. ESSL3 section 12.42
362 // means that any 32-bit unsigned integer value is a valid literal.
TEST_F(ConstantFoldingTest,FoldUnaryMinusOnUintLiteral)363 TEST_F(ConstantFoldingTest, FoldUnaryMinusOnUintLiteral)
364 {
365     const std::string &shaderString =
366         "#version 300 es\n"
367         "precision mediump float;\n"
368         "precision highp int;\n"
369         "uniform uint inInt;\n"
370         "out vec4 my_Vec;\n"
371         "void main() {\n"
372         "   const uint i = -1u;\n"
373         "   my_Vec = vec4(i * inInt);\n"
374         "}\n";
375     compileAssumeSuccess(shaderString);
376     ASSERT_TRUE(constantFoundInAST(0xFFFFFFFFu));
377 }
378 
379 // Test that constant mat2 initialization with a mat2 parameter works correctly.
TEST_F(ConstantFoldingTest,FoldMat2ConstructorTakingMat2)380 TEST_F(ConstantFoldingTest, FoldMat2ConstructorTakingMat2)
381 {
382     const std::string &shaderString =
383         "precision mediump float;\n"
384         "uniform float mult;\n"
385         "void main() {\n"
386         "   const mat2 cm = mat2(mat2(0.0, 1.0, 2.0, 3.0));\n"
387         "   mat2 m = cm * mult;\n"
388         "   gl_FragColor = vec4(m[0], m[1]);\n"
389         "}\n";
390     compileAssumeSuccess(shaderString);
391     float outputElements[] = {0.0f, 1.0f, 2.0f, 3.0f};
392     std::vector<float> result(outputElements, outputElements + 4);
393     ASSERT_TRUE(constantColumnMajorMatrixFoundInAST(result));
394 }
395 
396 // Test that constant mat2 initialization with an int parameter works correctly.
TEST_F(ConstantFoldingTest,FoldMat2ConstructorTakingScalar)397 TEST_F(ConstantFoldingTest, FoldMat2ConstructorTakingScalar)
398 {
399     const std::string &shaderString =
400         "precision mediump float;\n"
401         "uniform float mult;\n"
402         "void main() {\n"
403         "   const mat2 cm = mat2(3);\n"
404         "   mat2 m = cm * mult;\n"
405         "   gl_FragColor = vec4(m[0], m[1]);\n"
406         "}\n";
407     compileAssumeSuccess(shaderString);
408     float outputElements[] = {3.0f, 0.0f, 0.0f, 3.0f};
409     std::vector<float> result(outputElements, outputElements + 4);
410     ASSERT_TRUE(constantColumnMajorMatrixFoundInAST(result));
411 }
412 
413 // Test that constant mat2 initialization with a mix of parameters works correctly.
TEST_F(ConstantFoldingTest,FoldMat2ConstructorTakingMix)414 TEST_F(ConstantFoldingTest, FoldMat2ConstructorTakingMix)
415 {
416     const std::string &shaderString =
417         "precision mediump float;\n"
418         "uniform float mult;\n"
419         "void main() {\n"
420         "   const mat2 cm = mat2(-1, vec2(0.0, 1.0), vec4(2.0));\n"
421         "   mat2 m = cm * mult;\n"
422         "   gl_FragColor = vec4(m[0], m[1]);\n"
423         "}\n";
424     compileAssumeSuccess(shaderString);
425     float outputElements[] = {-1.0, 0.0f, 1.0f, 2.0f};
426     std::vector<float> result(outputElements, outputElements + 4);
427     ASSERT_TRUE(constantColumnMajorMatrixFoundInAST(result));
428 }
429 
430 // Test that constant mat2 initialization with a mat3 parameter works correctly.
TEST_F(ConstantFoldingTest,FoldMat2ConstructorTakingMat3)431 TEST_F(ConstantFoldingTest, FoldMat2ConstructorTakingMat3)
432 {
433     const std::string &shaderString =
434         "precision mediump float;\n"
435         "uniform float mult;\n"
436         "void main() {\n"
437         "   const mat2 cm = mat2(mat3(0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0));\n"
438         "   mat2 m = cm * mult;\n"
439         "   gl_FragColor = vec4(m[0], m[1]);\n"
440         "}\n";
441     compileAssumeSuccess(shaderString);
442     float outputElements[] = {0.0f, 1.0f, 3.0f, 4.0f};
443     std::vector<float> result(outputElements, outputElements + 4);
444     ASSERT_TRUE(constantColumnMajorMatrixFoundInAST(result));
445 }
446 
447 // Test that constant mat4x3 initialization with a mat3x2 parameter works correctly.
TEST_F(ConstantFoldingTest,FoldMat4x3ConstructorTakingMat3x2)448 TEST_F(ConstantFoldingTest, FoldMat4x3ConstructorTakingMat3x2)
449 {
450     const std::string &shaderString =
451         "#version 300 es\n"
452         "precision mediump float;\n"
453         "uniform float mult;\n"
454         "out vec4 my_FragColor;\n"
455         "void main() {\n"
456         "   const mat4x3 cm = mat4x3(mat3x2(1.0, 2.0,\n"
457         "                                   3.0, 4.0,\n"
458         "                                   5.0, 6.0));\n"
459         "   mat4x3 m = cm * mult;\n"
460         "   my_FragColor = vec4(m[0], m[1][0]);\n"
461         "}\n";
462     compileAssumeSuccess(shaderString);
463     float outputElements[] = {1.0f, 2.0f, 0.0f, 3.0f, 4.0f, 0.0f,
464                               5.0f, 6.0f, 1.0f, 0.0f, 0.0f, 0.0f};
465     std::vector<float> result(outputElements, outputElements + 12);
466     ASSERT_TRUE(constantColumnMajorMatrixFoundInAST(result));
467 }
468 
469 // Test that constant mat2 initialization with a vec4 parameter works correctly.
TEST_F(ConstantFoldingTest,FoldMat2ConstructorTakingVec4)470 TEST_F(ConstantFoldingTest, FoldMat2ConstructorTakingVec4)
471 {
472     const std::string &shaderString =
473         "precision mediump float;\n"
474         "uniform float mult;\n"
475         "void main() {\n"
476         "   const mat2 cm = mat2(vec4(0.0, 1.0, 2.0, 3.0));\n"
477         "   mat2 m = cm * mult;\n"
478         "   gl_FragColor = vec4(m[0], m[1]);\n"
479         "}\n";
480     compileAssumeSuccess(shaderString);
481     float outputElements[] = {0.0f, 1.0f, 2.0f, 3.0f};
482     std::vector<float> result(outputElements, outputElements + 4);
483     ASSERT_TRUE(constantColumnMajorMatrixFoundInAST(result));
484 }
485 
486 // Test that equality comparison of two different structs with a nested struct inside returns false.
TEST_F(ConstantFoldingTest,FoldNestedDifferentStructEqualityComparison)487 TEST_F(ConstantFoldingTest, FoldNestedDifferentStructEqualityComparison)
488 {
489     const std::string &shaderString =
490         "precision mediump float;\n"
491         "struct nested {\n"
492         "    float f\n;"
493         "};\n"
494         "struct S {\n"
495         "    nested a;\n"
496         "    float f;\n"
497         "};\n"
498         "uniform vec4 mult;\n"
499         "void main()\n"
500         "{\n"
501         "    const S s1 = S(nested(0.0), 2.0);\n"
502         "    const S s2 = S(nested(0.0), 3.0);\n"
503         "    gl_FragColor = (s1 == s2 ? 1.0 : 0.5) * mult;\n"
504         "}\n";
505     compileAssumeSuccess(shaderString);
506     ASSERT_TRUE(constantFoundInAST(0.5f));
507 }
508 
509 // Test that equality comparison of two identical structs with a nested struct inside returns true.
TEST_F(ConstantFoldingTest,FoldNestedIdenticalStructEqualityComparison)510 TEST_F(ConstantFoldingTest, FoldNestedIdenticalStructEqualityComparison)
511 {
512     const std::string &shaderString =
513         "precision mediump float;\n"
514         "struct nested {\n"
515         "    float f\n;"
516         "};\n"
517         "struct S {\n"
518         "    nested a;\n"
519         "    float f;\n"
520         "    int i;\n"
521         "};\n"
522         "uniform vec4 mult;\n"
523         "void main()\n"
524         "{\n"
525         "    const S s1 = S(nested(0.0), 2.0, 3);\n"
526         "    const S s2 = S(nested(0.0), 2.0, 3);\n"
527         "    gl_FragColor = (s1 == s2 ? 1.0 : 0.5) * mult;\n"
528         "}\n";
529     compileAssumeSuccess(shaderString);
530     ASSERT_TRUE(constantFoundInAST(1.0f));
531 }
532 
533 // Test that right elements are chosen from non-square matrix
TEST_F(ConstantFoldingTest,FoldNonSquareMatrixIndexing)534 TEST_F(ConstantFoldingTest, FoldNonSquareMatrixIndexing)
535 {
536     const std::string &shaderString =
537         "#version 300 es\n"
538         "precision mediump float;\n"
539         "out vec4 my_FragColor;\n"
540         "void main()\n"
541         "{\n"
542         "    my_FragColor = mat3x4(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11)[1];\n"
543         "}\n";
544     compileAssumeSuccess(shaderString);
545     float outputElements[] = {4.0f, 5.0f, 6.0f, 7.0f};
546     std::vector<float> result(outputElements, outputElements + 4);
547     ASSERT_TRUE(constantVectorFoundInAST(result));
548 }
549 
550 // Test that folding outer product of vectors with non-matching lengths works.
TEST_F(ConstantFoldingTest,FoldNonSquareOuterProduct)551 TEST_F(ConstantFoldingTest, FoldNonSquareOuterProduct)
552 {
553     const std::string &shaderString =
554         "#version 300 es\n"
555         "precision mediump float;\n"
556         "out vec4 my_FragColor;\n"
557         "void main()\n"
558         "{\n"
559         "    mat3x2 prod = outerProduct(vec2(2.0, 3.0), vec3(5.0, 7.0, 11.0));\n"
560         "    my_FragColor = vec4(prod[0].x);\n"
561         "}\n";
562     compileAssumeSuccess(shaderString);
563     // clang-format off
564     float outputElements[] =
565     {
566         10.0f, 15.0f,
567         14.0f, 21.0f,
568         22.0f, 33.0f
569     };
570     // clang-format on
571     std::vector<float> result(outputElements, outputElements + 6);
572     ASSERT_TRUE(constantColumnMajorMatrixFoundInAST(result));
573 }
574 
575 // Test that folding bit shift left with non-matching signedness works.
TEST_F(ConstantFoldingTest,FoldBitShiftLeftDifferentSignedness)576 TEST_F(ConstantFoldingTest, FoldBitShiftLeftDifferentSignedness)
577 {
578     const std::string &shaderString =
579         "#version 300 es\n"
580         "precision mediump float;\n"
581         "out vec4 my_FragColor;\n"
582         "void main()\n"
583         "{\n"
584         "    uint u = 0xffffffffu << 31;\n"
585         "    my_FragColor = vec4(u);\n"
586         "}\n";
587     compileAssumeSuccess(shaderString);
588     ASSERT_TRUE(constantFoundInAST(0x80000000u));
589 }
590 
591 // Test that folding bit shift right with non-matching signedness works.
TEST_F(ConstantFoldingTest,FoldBitShiftRightDifferentSignedness)592 TEST_F(ConstantFoldingTest, FoldBitShiftRightDifferentSignedness)
593 {
594     const std::string &shaderString =
595         "#version 300 es\n"
596         "precision mediump float;\n"
597         "out vec4 my_FragColor;\n"
598         "void main()\n"
599         "{\n"
600         "    uint u = 0xffffffffu >> 30;\n"
601         "    my_FragColor = vec4(u);\n"
602         "}\n";
603     compileAssumeSuccess(shaderString);
604     ASSERT_TRUE(constantFoundInAST(0x3u));
605 }
606 
607 // Test that folding signed bit shift right extends the sign bit.
608 // ESSL 3.00.6 section 5.9 Expressions.
TEST_F(ConstantFoldingTest,FoldBitShiftRightExtendSignBit)609 TEST_F(ConstantFoldingTest, FoldBitShiftRightExtendSignBit)
610 {
611     const std::string &shaderString =
612         "#version 300 es\n"
613         "precision mediump float;\n"
614         "out vec4 my_FragColor;\n"
615         "void main()\n"
616         "{\n"
617         "    const int i = 0x8fffe000 >> 6;\n"
618         "    uint u = uint(i);"
619         "    my_FragColor = vec4(u);\n"
620         "}\n";
621     compileAssumeSuccess(shaderString);
622     // The bits of the operand are 0x8fffe000 = 1000 1111 1111 1111 1110 0000 0000 0000
623     // After shifting, they become              1111 1110 0011 1111 1111 1111 1000 0000 = 0xfe3fff80
624     ASSERT_TRUE(constantFoundInAST(0xfe3fff80u));
625 }
626 
627 // Signed bit shift left should interpret its operand as a bit pattern. As a consequence a number
628 // may turn from positive to negative when shifted left.
629 // ESSL 3.00.6 section 5.9 Expressions.
TEST_F(ConstantFoldingTest,FoldBitShiftLeftInterpretedAsBitPattern)630 TEST_F(ConstantFoldingTest, FoldBitShiftLeftInterpretedAsBitPattern)
631 {
632     const std::string &shaderString =
633         "#version 300 es\n"
634         "precision mediump float;\n"
635         "out vec4 my_FragColor;\n"
636         "void main()\n"
637         "{\n"
638         "    const int i = 0x1fffffff << 3;\n"
639         "    uint u = uint(i);"
640         "    my_FragColor = vec4(u);\n"
641         "}\n";
642     compileAssumeSuccess(shaderString);
643     ASSERT_TRUE(constantFoundInAST(0xfffffff8u));
644 }
645 
646 // Test that dividing the minimum signed integer by -1 works.
647 // ESSL 3.00.6 section 4.1.3 Integers:
648 // "However, for the case where the minimum representable value is divided by -1, it is allowed to
649 // return either the minimum representable value or the maximum representable value."
TEST_F(ConstantFoldingTest,FoldDivideMinimumIntegerByMinusOne)650 TEST_F(ConstantFoldingTest, FoldDivideMinimumIntegerByMinusOne)
651 {
652     const std::string &shaderString =
653         "#version 300 es\n"
654         "precision mediump float;\n"
655         "out vec4 my_FragColor;\n"
656         "void main()\n"
657         "{\n"
658         "    int i = 0x80000000 / (-1);\n"
659         "    my_FragColor = vec4(i);\n"
660         "}\n";
661     compileAssumeSuccess(shaderString);
662     ASSERT_TRUE(constantFoundInAST(0x7fffffff) || constantFoundInAST(-0x7fffffff - 1));
663 }
664 
665 // Test that folding an unsigned integer addition that overflows works.
666 // ESSL 3.00.6 section 4.1.3 Integers:
667 // "For all precisions, operations resulting in overflow or underflow will not cause any exception,
668 // nor will they saturate, rather they will 'wrap' to yield the low-order n bits of the result where
669 // n is the size in bits of the integer."
TEST_F(ConstantFoldingTest,FoldUnsignedIntegerAddOverflow)670 TEST_F(ConstantFoldingTest, FoldUnsignedIntegerAddOverflow)
671 {
672     const std::string &shaderString =
673         "#version 300 es\n"
674         "precision mediump float;\n"
675         "out vec4 my_FragColor;\n"
676         "void main()\n"
677         "{\n"
678         "    uint u = 0xffffffffu + 43u;\n"
679         "    my_FragColor = vec4(u);\n"
680         "}\n";
681     compileAssumeSuccess(shaderString);
682     ASSERT_TRUE(constantFoundInAST(42u));
683 }
684 
685 // Test that folding a signed integer addition that overflows works.
686 // ESSL 3.00.6 section 4.1.3 Integers:
687 // "For all precisions, operations resulting in overflow or underflow will not cause any exception,
688 // nor will they saturate, rather they will 'wrap' to yield the low-order n bits of the result where
689 // n is the size in bits of the integer."
TEST_F(ConstantFoldingTest,FoldSignedIntegerAddOverflow)690 TEST_F(ConstantFoldingTest, FoldSignedIntegerAddOverflow)
691 {
692     const std::string &shaderString =
693         "#version 300 es\n"
694         "precision mediump float;\n"
695         "out vec4 my_FragColor;\n"
696         "void main()\n"
697         "{\n"
698         "    int i = 0x7fffffff + 4;\n"
699         "    my_FragColor = vec4(i);\n"
700         "}\n";
701     compileAssumeSuccess(shaderString);
702     ASSERT_TRUE(constantFoundInAST(-0x7ffffffd));
703 }
704 
705 // Test that folding an unsigned integer subtraction that overflows works.
706 // ESSL 3.00.6 section 4.1.3 Integers:
707 // "For all precisions, operations resulting in overflow or underflow will not cause any exception,
708 // nor will they saturate, rather they will 'wrap' to yield the low-order n bits of the result where
709 // n is the size in bits of the integer."
TEST_F(ConstantFoldingTest,FoldUnsignedIntegerDiffOverflow)710 TEST_F(ConstantFoldingTest, FoldUnsignedIntegerDiffOverflow)
711 {
712     const std::string &shaderString =
713         "#version 300 es\n"
714         "precision mediump float;\n"
715         "out vec4 my_FragColor;\n"
716         "void main()\n"
717         "{\n"
718         "    uint u = 0u - 5u;\n"
719         "    my_FragColor = vec4(u);\n"
720         "}\n";
721     compileAssumeSuccess(shaderString);
722     ASSERT_TRUE(constantFoundInAST(0xfffffffbu));
723 }
724 
725 // Test that folding a signed integer subtraction that overflows works.
726 // ESSL 3.00.6 section 4.1.3 Integers:
727 // "For all precisions, operations resulting in overflow or underflow will not cause any exception,
728 // nor will they saturate, rather they will 'wrap' to yield the low-order n bits of the result where
729 // n is the size in bits of the integer."
TEST_F(ConstantFoldingTest,FoldSignedIntegerDiffOverflow)730 TEST_F(ConstantFoldingTest, FoldSignedIntegerDiffOverflow)
731 {
732     const std::string &shaderString =
733         "#version 300 es\n"
734         "precision mediump float;\n"
735         "out vec4 my_FragColor;\n"
736         "void main()\n"
737         "{\n"
738         "    int i = -0x7fffffff - 7;\n"
739         "    my_FragColor = vec4(i);\n"
740         "}\n";
741     compileAssumeSuccess(shaderString);
742     ASSERT_TRUE(constantFoundInAST(0x7ffffffa));
743 }
744 
745 // Test that folding an unsigned integer multiplication that overflows works.
746 // ESSL 3.00.6 section 4.1.3 Integers:
747 // "For all precisions, operations resulting in overflow or underflow will not cause any exception,
748 // nor will they saturate, rather they will 'wrap' to yield the low-order n bits of the result where
749 // n is the size in bits of the integer."
TEST_F(ConstantFoldingTest,FoldUnsignedIntegerMultiplyOverflow)750 TEST_F(ConstantFoldingTest, FoldUnsignedIntegerMultiplyOverflow)
751 {
752     const std::string &shaderString =
753         "#version 300 es\n"
754         "precision mediump float;\n"
755         "out vec4 my_FragColor;\n"
756         "void main()\n"
757         "{\n"
758         "    uint u = 0xffffffffu * 10u;\n"
759         "    my_FragColor = vec4(u);\n"
760         "}\n";
761     compileAssumeSuccess(shaderString);
762     ASSERT_TRUE(constantFoundInAST(0xfffffff6u));
763 }
764 
765 // Test that folding a signed integer multiplication that overflows works.
766 // ESSL 3.00.6 section 4.1.3 Integers:
767 // "For all precisions, operations resulting in overflow or underflow will not cause any exception,
768 // nor will they saturate, rather they will 'wrap' to yield the low-order n bits of the result where
769 // n is the size in bits of the integer."
TEST_F(ConstantFoldingTest,FoldSignedIntegerMultiplyOverflow)770 TEST_F(ConstantFoldingTest, FoldSignedIntegerMultiplyOverflow)
771 {
772     const std::string &shaderString =
773         "#version 300 es\n"
774         "precision mediump float;\n"
775         "out vec4 my_FragColor;\n"
776         "void main()\n"
777         "{\n"
778         "    int i = 0x7fffffff * 42;\n"
779         "    my_FragColor = vec4(i);\n"
780         "}\n";
781     compileAssumeSuccess(shaderString);
782     ASSERT_TRUE(constantFoundInAST(-42));
783 }
784 
785 // Test that folding of negating the minimum representable integer works. Note that in the test
786 // "0x80000000" is a negative literal, and the minus sign before it is the negation operator.
787 // ESSL 3.00.6 section 4.1.3 Integers:
788 // "For all precisions, operations resulting in overflow or underflow will not cause any exception,
789 // nor will they saturate, rather they will 'wrap' to yield the low-order n bits of the result where
790 // n is the size in bits of the integer."
TEST_F(ConstantFoldingTest,FoldMinimumSignedIntegerNegation)791 TEST_F(ConstantFoldingTest, FoldMinimumSignedIntegerNegation)
792 {
793     const std::string &shaderString =
794         "#version 300 es\n"
795         "precision mediump float;\n"
796         "out vec4 my_FragColor;\n"
797         "void main()\n"
798         "{\n"
799         "    int i = -0x80000000;\n"
800         "    my_FragColor = vec4(i);\n"
801         "}\n";
802     compileAssumeSuccess(shaderString);
803     // Negating the minimum signed integer overflows the positive range, so it wraps back to itself.
804     ASSERT_TRUE(constantFoundInAST(-0x7fffffff - 1));
805 }
806 
807 // Test that folding of shifting the minimum representable integer works.
TEST_F(ConstantFoldingTest,FoldMinimumSignedIntegerRightShift)808 TEST_F(ConstantFoldingTest, FoldMinimumSignedIntegerRightShift)
809 {
810     const std::string &shaderString =
811         "#version 300 es\n"
812         "precision mediump float;\n"
813         "out vec4 my_FragColor;\n"
814         "void main()\n"
815         "{\n"
816         "    int i = (0x80000000 >> 1);\n"
817         "    int j = (0x80000000 >> 7);\n"
818         "    my_FragColor = vec4(i, j, i, j);\n"
819         "}\n";
820     compileAssumeSuccess(shaderString);
821     ASSERT_TRUE(constantFoundInAST(-0x40000000));
822     ASSERT_TRUE(constantFoundInAST(-0x01000000));
823 }
824 
825 // Test that folding of shifting by 0 works.
TEST_F(ConstantFoldingTest,FoldShiftByZero)826 TEST_F(ConstantFoldingTest, FoldShiftByZero)
827 {
828     const std::string &shaderString =
829         "#version 300 es\n"
830         "precision mediump float;\n"
831         "out vec4 my_FragColor;\n"
832         "void main()\n"
833         "{\n"
834         "    int i = (3 >> 0);\n"
835         "    int j = (73 << 0);\n"
836         "    my_FragColor = vec4(i, j, i, j);\n"
837         "}\n";
838     compileAssumeSuccess(shaderString);
839     ASSERT_TRUE(constantFoundInAST(3));
840     ASSERT_TRUE(constantFoundInAST(73));
841 }
842 
843 // Test that folding IsInf results in true when the parameter is an out-of-range float literal.
844 // ESSL 3.00.6 section 4.1.4 Floats:
845 // "If the value of the floating point number is too large (small) to be stored as a single
846 // precision value, it is converted to positive (negative) infinity."
847 // ESSL 3.00.6 section 12.4:
848 // "Mandate support for signed infinities."
TEST_F(ConstantFoldingTest,FoldIsInfOutOfRangeFloatLiteral)849 TEST_F(ConstantFoldingTest, FoldIsInfOutOfRangeFloatLiteral)
850 {
851     const std::string &shaderString =
852         "#version 300 es\n"
853         "precision mediump float;\n"
854         "out vec4 my_FragColor;\n"
855         "void main()\n"
856         "{\n"
857         "    bool b = isinf(1.0e2048);\n"
858         "    my_FragColor = vec4(b);\n"
859         "}\n";
860     compileAssumeSuccess(shaderString);
861     ASSERT_TRUE(constantFoundInAST(true));
862 }
863 
864 // Regression test case of unary + constant folding of a void struct member.
TEST_F(ConstantFoldingTest,VoidStructMember)865 TEST_F(ConstantFoldingTest, VoidStructMember)
866 {
867     constexpr const char *kShaderString = "struct U{void t;}n(){+U().t";
868     ASSERT_FALSE(compile(kShaderString));
869 }
870 
871 // Test that floats that are too small to be represented get flushed to zero.
872 // ESSL 3.00.6 section 4.1.4 Floats:
873 // "A value with a magnitude too small to be represented as a mantissa and exponent is converted to
874 // zero."
TEST_F(ConstantFoldingExpressionTest,FoldTooSmallFloat)875 TEST_F(ConstantFoldingExpressionTest, FoldTooSmallFloat)
876 {
877     const std::string &floatString = "1.0e-2048";
878     evaluateFloat(floatString);
879     ASSERT_TRUE(constantFoundInAST(0.0f));
880 }
881 
882 // IEEE 754 dictates that behavior of infinity is derived from limiting cases of real arithmetic.
883 // lim radians(x) x -> inf = inf
884 // ESSL 3.00.6 section 4.5.1: "Infinities and zeroes are generated as dictated by IEEE".
TEST_F(ConstantFoldingExpressionTest,FoldRadiansInfinity)885 TEST_F(ConstantFoldingExpressionTest, FoldRadiansInfinity)
886 {
887     const std::string &floatString = "radians(1.0e2048)";
888     evaluateFloat(floatString);
889     ASSERT_TRUE(constantFoundInAST(std::numeric_limits<float>::infinity()));
890 }
891 
892 // IEEE 754 dictates that behavior of infinity is derived from limiting cases of real arithmetic.
893 // lim degrees(x) x -> inf = inf
894 // ESSL 3.00.6 section 4.5.1: "Infinities and zeroes are generated as dictated by IEEE".
TEST_F(ConstantFoldingExpressionTest,FoldDegreesInfinity)895 TEST_F(ConstantFoldingExpressionTest, FoldDegreesInfinity)
896 {
897     const std::string &floatString = "degrees(1.0e2048)";
898     evaluateFloat(floatString);
899     ASSERT_TRUE(constantFoundInAST(std::numeric_limits<float>::infinity()));
900 }
901 
902 // IEEE 754 dictates that sinh(inf) = inf.
903 // ESSL 3.00.6 section 4.5.1: "Infinities and zeroes are generated as dictated by IEEE".
TEST_F(ConstantFoldingExpressionTest,FoldSinhInfinity)904 TEST_F(ConstantFoldingExpressionTest, FoldSinhInfinity)
905 {
906     const std::string &floatString = "sinh(1.0e2048)";
907     evaluateFloat(floatString);
908     ASSERT_TRUE(constantFoundInAST(std::numeric_limits<float>::infinity()));
909 }
910 
911 // IEEE 754 dictates that sinh(-inf) = -inf.
912 // ESSL 3.00.6 section 4.5.1: "Infinities and zeroes are generated as dictated by IEEE".
TEST_F(ConstantFoldingExpressionTest,FoldSinhNegativeInfinity)913 TEST_F(ConstantFoldingExpressionTest, FoldSinhNegativeInfinity)
914 {
915     const std::string &floatString = "sinh(-1.0e2048)";
916     evaluateFloat(floatString);
917     ASSERT_TRUE(constantFoundInAST(-std::numeric_limits<float>::infinity()));
918 }
919 
920 // IEEE 754 dictates that cosh(inf) = inf.
921 // ESSL 3.00.6 section 4.5.1: "Infinities and zeroes are generated as dictated by IEEE".
TEST_F(ConstantFoldingExpressionTest,FoldCoshInfinity)922 TEST_F(ConstantFoldingExpressionTest, FoldCoshInfinity)
923 {
924     const std::string &floatString = "cosh(1.0e2048)";
925     evaluateFloat(floatString);
926     ASSERT_TRUE(constantFoundInAST(std::numeric_limits<float>::infinity()));
927 }
928 
929 // IEEE 754 dictates that cosh(-inf) = inf.
930 // ESSL 3.00.6 section 4.5.1: "Infinities and zeroes are generated as dictated by IEEE".
TEST_F(ConstantFoldingExpressionTest,FoldCoshNegativeInfinity)931 TEST_F(ConstantFoldingExpressionTest, FoldCoshNegativeInfinity)
932 {
933     const std::string &floatString = "cosh(-1.0e2048)";
934     evaluateFloat(floatString);
935     ASSERT_TRUE(constantFoundInAST(std::numeric_limits<float>::infinity()));
936 }
937 
938 // IEEE 754 dictates that asinh(inf) = inf.
939 // ESSL 3.00.6 section 4.5.1: "Infinities and zeroes are generated as dictated by IEEE".
TEST_F(ConstantFoldingExpressionTest,FoldAsinhInfinity)940 TEST_F(ConstantFoldingExpressionTest, FoldAsinhInfinity)
941 {
942     const std::string &floatString = "asinh(1.0e2048)";
943     evaluateFloat(floatString);
944     ASSERT_TRUE(constantFoundInAST(std::numeric_limits<float>::infinity()));
945 }
946 
947 // IEEE 754 dictates that asinh(-inf) = -inf.
948 // ESSL 3.00.6 section 4.5.1: "Infinities and zeroes are generated as dictated by IEEE".
TEST_F(ConstantFoldingExpressionTest,FoldAsinhNegativeInfinity)949 TEST_F(ConstantFoldingExpressionTest, FoldAsinhNegativeInfinity)
950 {
951     const std::string &floatString = "asinh(-1.0e2048)";
952     evaluateFloat(floatString);
953     ASSERT_TRUE(constantFoundInAST(-std::numeric_limits<float>::infinity()));
954 }
955 
956 // IEEE 754 dictates that acosh(inf) = inf.
957 // ESSL 3.00.6 section 4.5.1: "Infinities and zeroes are generated as dictated by IEEE".
TEST_F(ConstantFoldingExpressionTest,FoldAcoshInfinity)958 TEST_F(ConstantFoldingExpressionTest, FoldAcoshInfinity)
959 {
960     const std::string &floatString = "acosh(1.0e2048)";
961     evaluateFloat(floatString);
962     ASSERT_TRUE(constantFoundInAST(std::numeric_limits<float>::infinity()));
963 }
964 
965 // IEEE 754 dictates that pow or powr(0, inf) = 0.
966 // ESSL 3.00.6 section 4.5.1: "Infinities and zeroes are generated as dictated by IEEE".
TEST_F(ConstantFoldingExpressionTest,FoldPowInfinity)967 TEST_F(ConstantFoldingExpressionTest, FoldPowInfinity)
968 {
969     const std::string &floatString = "pow(0.0, 1.0e2048)";
970     evaluateFloat(floatString);
971     ASSERT_TRUE(constantFoundInAST(0.0f));
972 }
973 
974 // IEEE 754 dictates that exp(inf) = inf.
975 // ESSL 3.00.6 section 4.5.1: "Infinities and zeroes are generated as dictated by IEEE".
TEST_F(ConstantFoldingExpressionTest,FoldExpInfinity)976 TEST_F(ConstantFoldingExpressionTest, FoldExpInfinity)
977 {
978     const std::string &floatString = "exp(1.0e2048)";
979     evaluateFloat(floatString);
980     ASSERT_TRUE(constantFoundInAST(std::numeric_limits<float>::infinity()));
981 }
982 
983 // IEEE 754 dictates that exp(-inf) = 0.
984 // ESSL 3.00.6 section 4.5.1: "Infinities and zeroes are generated as dictated by IEEE".
TEST_F(ConstantFoldingExpressionTest,FoldExpNegativeInfinity)985 TEST_F(ConstantFoldingExpressionTest, FoldExpNegativeInfinity)
986 {
987     const std::string &floatString = "exp(-1.0e2048)";
988     evaluateFloat(floatString);
989     ASSERT_TRUE(constantFoundInAST(0.0f));
990 }
991 
992 // IEEE 754 dictates that log(inf) = inf.
993 // ESSL 3.00.6 section 4.5.1: "Infinities and zeroes are generated as dictated by IEEE".
TEST_F(ConstantFoldingExpressionTest,FoldLogInfinity)994 TEST_F(ConstantFoldingExpressionTest, FoldLogInfinity)
995 {
996     const std::string &floatString = "log(1.0e2048)";
997     evaluateFloat(floatString);
998     ASSERT_TRUE(constantFoundInAST(std::numeric_limits<float>::infinity()));
999 }
1000 
1001 // IEEE 754 dictates that exp2(inf) = inf.
1002 // ESSL 3.00.6 section 4.5.1: "Infinities and zeroes are generated as dictated by IEEE".
TEST_F(ConstantFoldingExpressionTest,FoldExp2Infinity)1003 TEST_F(ConstantFoldingExpressionTest, FoldExp2Infinity)
1004 {
1005     const std::string &floatString = "exp2(1.0e2048)";
1006     evaluateFloat(floatString);
1007     ASSERT_TRUE(constantFoundInAST(std::numeric_limits<float>::infinity()));
1008 }
1009 
1010 // IEEE 754 dictates that exp2(-inf) = 0.
1011 // ESSL 3.00.6 section 4.5.1: "Infinities and zeroes are generated as dictated by IEEE".
TEST_F(ConstantFoldingExpressionTest,FoldExp2NegativeInfinity)1012 TEST_F(ConstantFoldingExpressionTest, FoldExp2NegativeInfinity)
1013 {
1014     const std::string &floatString = "exp2(-1.0e2048)";
1015     evaluateFloat(floatString);
1016     ASSERT_TRUE(constantFoundInAST(0.0f));
1017 }
1018 
1019 // IEEE 754 dictates that log2(inf) = inf.
1020 // ESSL 3.00.6 section 4.5.1: "Infinities and zeroes are generated as dictated by IEEE".
TEST_F(ConstantFoldingExpressionTest,FoldLog2Infinity)1021 TEST_F(ConstantFoldingExpressionTest, FoldLog2Infinity)
1022 {
1023     const std::string &floatString = "log2(1.0e2048)";
1024     evaluateFloat(floatString);
1025     ASSERT_TRUE(constantFoundInAST(std::numeric_limits<float>::infinity()));
1026 }
1027 
1028 // IEEE 754 dictates that behavior of infinity is derived from limiting cases of real arithmetic.
1029 // lim sqrt(x) x -> inf = inf
1030 // ESSL 3.00.6 section 4.5.1: "Infinities and zeroes are generated as dictated by IEEE".
TEST_F(ConstantFoldingExpressionTest,FoldSqrtInfinity)1031 TEST_F(ConstantFoldingExpressionTest, FoldSqrtInfinity)
1032 {
1033     const std::string &floatString = "sqrt(1.0e2048)";
1034     evaluateFloat(floatString);
1035     ASSERT_TRUE(constantFoundInAST(std::numeric_limits<float>::infinity()));
1036 }
1037 
1038 // IEEE 754 dictates that rSqrt(inf) = 0
1039 // ESSL 3.00.6 section 4.5.1: "Infinities and zeroes are generated as dictated by IEEE".
TEST_F(ConstantFoldingExpressionTest,FoldInversesqrtInfinity)1040 TEST_F(ConstantFoldingExpressionTest, FoldInversesqrtInfinity)
1041 {
1042     const std::string &floatString = "inversesqrt(1.0e2048)";
1043     evaluateFloat(floatString);
1044     ASSERT_TRUE(constantFoundInAST(0.0f));
1045 }
1046 
1047 // IEEE 754 dictates that behavior of infinity is derived from limiting cases of real arithmetic.
1048 // lim length(x) x -> inf = inf
1049 // ESSL 3.00.6 section 4.5.1: "Infinities and zeroes are generated as dictated by IEEE".
TEST_F(ConstantFoldingExpressionTest,FoldLengthInfinity)1050 TEST_F(ConstantFoldingExpressionTest, FoldLengthInfinity)
1051 {
1052     const std::string &floatString = "length(1.0e2048)";
1053     evaluateFloat(floatString);
1054     ASSERT_TRUE(constantFoundInAST(std::numeric_limits<float>::infinity()));
1055 }
1056 
1057 // IEEE 754 dictates that behavior of infinity is derived from limiting cases of real arithmetic.
1058 // lim dot(x, y) x -> inf, y > 0 = inf
1059 // ESSL 3.00.6 section 4.5.1: "Infinities and zeroes are generated as dictated by IEEE".
TEST_F(ConstantFoldingExpressionTest,FoldDotInfinity)1060 TEST_F(ConstantFoldingExpressionTest, FoldDotInfinity)
1061 {
1062     const std::string &floatString = "dot(1.0e2048, 1.0)";
1063     evaluateFloat(floatString);
1064     ASSERT_TRUE(constantFoundInAST(std::numeric_limits<float>::infinity()));
1065 }
1066 
1067 // IEEE 754 dictates that behavior of infinity is derived from limiting cases of real arithmetic.
1068 // lim dot(vec2(x, y), vec2(z)) x -> inf, finite y, z > 0 = inf
1069 // ESSL 3.00.6 section 4.5.1: "Infinities and zeroes are generated as dictated by IEEE".
TEST_F(ConstantFoldingExpressionTest,FoldDotInfinity2)1070 TEST_F(ConstantFoldingExpressionTest, FoldDotInfinity2)
1071 {
1072     const std::string &floatString = "dot(vec2(1.0e2048, -1.0), vec2(1.0))";
1073     evaluateFloat(floatString);
1074     ASSERT_TRUE(constantFoundInAST(std::numeric_limits<float>::infinity()));
1075 }
1076 
1077 // Faceforward behavior with infinity as a parameter can be derived from dot().
1078 // ESSL 3.00.6 section 4.5.1: "Infinities and zeroes are generated as dictated by IEEE".
TEST_F(ConstantFoldingExpressionTest,FoldFaceForwardInfinity)1079 TEST_F(ConstantFoldingExpressionTest, FoldFaceForwardInfinity)
1080 {
1081     const std::string &floatString = "faceforward(4.0, 1.0e2048, 1.0)";
1082     evaluateFloat(floatString);
1083     ASSERT_TRUE(constantFoundInAST(-4.0f));
1084 }
1085 
1086 // Faceforward behavior with infinity as a parameter can be derived from dot().
1087 // ESSL 3.00.6 section 4.5.1: "Infinities and zeroes are generated as dictated by IEEE".
TEST_F(ConstantFoldingExpressionTest,FoldFaceForwardInfinity2)1088 TEST_F(ConstantFoldingExpressionTest, FoldFaceForwardInfinity2)
1089 {
1090     const std::string &floatString = "faceforward(vec2(4.0), vec2(1.0e2048, -1.0), vec2(1.0)).x";
1091     evaluateFloat(floatString);
1092     ASSERT_TRUE(constantFoundInAST(-4.0f));
1093 }
1094 
1095 // Test that infinity - finite value evaluates to infinity.
1096 // ESSL 3.00.6 section 4.5.1: "Infinities and zeroes are generated as dictated by IEEE".
TEST_F(ConstantFoldingExpressionTest,FoldInfinityMinusFinite)1097 TEST_F(ConstantFoldingExpressionTest, FoldInfinityMinusFinite)
1098 {
1099     const std::string &floatString = "1.0e2048 - 1.0e20";
1100     evaluateFloat(floatString);
1101     ASSERT_TRUE(constantFoundInAST(std::numeric_limits<float>::infinity()));
1102 }
1103 
1104 // Test that -infinity + finite value evaluates to -infinity.
1105 // ESSL 3.00.6 section 4.5.1: "Infinities and zeroes are generated as dictated by IEEE".
TEST_F(ConstantFoldingExpressionTest,FoldMinusInfinityPlusFinite)1106 TEST_F(ConstantFoldingExpressionTest, FoldMinusInfinityPlusFinite)
1107 {
1108     const std::string &floatString = "(-1.0e2048) + 1.0e20";
1109     evaluateFloat(floatString);
1110     ASSERT_TRUE(constantFoundInAST(-std::numeric_limits<float>::infinity()));
1111 }
1112 
1113 // Test that infinity * finite value evaluates to infinity.
1114 // ESSL 3.00.6 section 4.5.1: "Infinities and zeroes are generated as dictated by IEEE".
TEST_F(ConstantFoldingExpressionTest,FoldInfinityMultipliedByFinite)1115 TEST_F(ConstantFoldingExpressionTest, FoldInfinityMultipliedByFinite)
1116 {
1117     const std::string &floatString = "1.0e2048 * 1.0e-20";
1118     evaluateFloat(floatString);
1119     ASSERT_TRUE(constantFoundInAST(std::numeric_limits<float>::infinity()));
1120 }
1121 
1122 // Test that infinity * infinity evaluates to infinity.
1123 // ESSL 3.00.6 section 4.5.1: "Infinities and zeroes are generated as dictated by IEEE".
TEST_F(ConstantFoldingExpressionTest,FoldInfinityMultipliedByInfinity)1124 TEST_F(ConstantFoldingExpressionTest, FoldInfinityMultipliedByInfinity)
1125 {
1126     const std::string &floatString = "1.0e2048 * 1.0e2048";
1127     evaluateFloat(floatString);
1128     ASSERT_TRUE(constantFoundInAST(std::numeric_limits<float>::infinity()));
1129 }
1130 
1131 // Test that infinity * negative infinity evaluates to negative infinity.
1132 // ESSL 3.00.6 section 4.5.1: "Infinities and zeroes are generated as dictated by IEEE".
TEST_F(ConstantFoldingExpressionTest,FoldInfinityMultipliedByNegativeInfinity)1133 TEST_F(ConstantFoldingExpressionTest, FoldInfinityMultipliedByNegativeInfinity)
1134 {
1135     const std::string &floatString = "1.0e2048 * (-1.0e2048)";
1136     evaluateFloat(floatString);
1137     ASSERT_TRUE(constantFoundInAST(-std::numeric_limits<float>::infinity()));
1138 }
1139 
1140 // Test that dividing by minus zero results in the appropriately signed infinity.
1141 // ESSL 3.00.6 section 4.5.1: "Infinities and zeroes are generated as dictated by IEEE".
1142 // "If both positive and negative zeros are implemented, the correctly signed Inf will be
1143 // generated".
TEST_F(ConstantFoldingExpressionTest,FoldDivideByNegativeZero)1144 TEST_F(ConstantFoldingExpressionTest, FoldDivideByNegativeZero)
1145 {
1146     const std::string &floatString = "1.0 / (-0.0)";
1147     evaluateFloat(floatString);
1148     ASSERT_TRUE(constantFoundInAST(-std::numeric_limits<float>::infinity()));
1149     ASSERT_TRUE(hasWarning());
1150 }
1151 
1152 // Test that infinity divided by zero evaluates to infinity.
1153 // ESSL 3.00.6 section 4.5.1: "Infinities and zeroes are generated as dictated by IEEE".
TEST_F(ConstantFoldingExpressionTest,FoldInfinityDividedByZero)1154 TEST_F(ConstantFoldingExpressionTest, FoldInfinityDividedByZero)
1155 {
1156     const std::string &floatString = "1.0e2048 / 0.0";
1157     evaluateFloat(floatString);
1158     ASSERT_TRUE(constantFoundInAST(std::numeric_limits<float>::infinity()));
1159     ASSERT_TRUE(hasWarning());
1160 }
1161 
1162 // Test that negative infinity divided by zero evaluates to negative infinity.
1163 // ESSL 3.00.6 section 4.5.1: "Infinities and zeroes are generated as dictated by IEEE".
TEST_F(ConstantFoldingExpressionTest,FoldMinusInfinityDividedByZero)1164 TEST_F(ConstantFoldingExpressionTest, FoldMinusInfinityDividedByZero)
1165 {
1166     const std::string &floatString = "(-1.0e2048) / 0.0";
1167     evaluateFloat(floatString);
1168     ASSERT_TRUE(constantFoundInAST(-std::numeric_limits<float>::infinity()));
1169     ASSERT_TRUE(hasWarning());
1170 }
1171 
1172 // Test that dividing a finite number by infinity results in zero.
1173 // ESSL 3.00.6 section 4.5.1: "Infinities and zeroes are generated as dictated by IEEE".
TEST_F(ConstantFoldingExpressionTest,FoldDivideByInfinity)1174 TEST_F(ConstantFoldingExpressionTest, FoldDivideByInfinity)
1175 {
1176     const std::string &floatString = "1.0e30 / 1.0e2048";
1177     evaluateFloat(floatString);
1178     ASSERT_TRUE(constantFoundInAST(0.0f));
1179 }
1180 
1181 // Test that unsigned bitfieldExtract is folded correctly.
TEST_F(ConstantFoldingExpressionTest,FoldUnsignedBitfieldExtract)1182 TEST_F(ConstantFoldingExpressionTest, FoldUnsignedBitfieldExtract)
1183 {
1184     const std::string &uintString = "bitfieldExtract(0x00110000u, 16, 5)";
1185     evaluateUint(uintString);
1186     ASSERT_TRUE(constantFoundInAST(0x11u));
1187 }
1188 
1189 // Test that unsigned bitfieldExtract to extract 32 bits is folded correctly.
TEST_F(ConstantFoldingExpressionTest,FoldUnsignedBitfieldExtract32Bits)1190 TEST_F(ConstantFoldingExpressionTest, FoldUnsignedBitfieldExtract32Bits)
1191 {
1192     const std::string &uintString = "bitfieldExtract(0xff0000ffu, 0, 32)";
1193     evaluateUint(uintString);
1194     ASSERT_TRUE(constantFoundInAST(0xff0000ffu));
1195 }
1196 
1197 // Test that signed bitfieldExtract is folded correctly. The higher bits should be set to 1 if the
1198 // most significant bit of the extracted value is 1.
TEST_F(ConstantFoldingExpressionTest,FoldSignedBitfieldExtract)1199 TEST_F(ConstantFoldingExpressionTest, FoldSignedBitfieldExtract)
1200 {
1201     const std::string &intString = "bitfieldExtract(0x00110000, 16, 5)";
1202     evaluateInt(intString);
1203     // 0xfffffff1 == -15
1204     ASSERT_TRUE(constantFoundInAST(-15));
1205 }
1206 
1207 // Test that bitfieldInsert is folded correctly.
TEST_F(ConstantFoldingExpressionTest,FoldBitfieldInsert)1208 TEST_F(ConstantFoldingExpressionTest, FoldBitfieldInsert)
1209 {
1210     const std::string &uintString = "bitfieldInsert(0x04501701u, 0x11u, 8, 5)";
1211     evaluateUint(uintString);
1212     ASSERT_TRUE(constantFoundInAST(0x04501101u));
1213 }
1214 
1215 // Test that bitfieldInsert to insert 32 bits is folded correctly.
TEST_F(ConstantFoldingExpressionTest,FoldBitfieldInsert32Bits)1216 TEST_F(ConstantFoldingExpressionTest, FoldBitfieldInsert32Bits)
1217 {
1218     const std::string &uintString = "bitfieldInsert(0xff0000ffu, 0x11u, 0, 32)";
1219     evaluateUint(uintString);
1220     ASSERT_TRUE(constantFoundInAST(0x11u));
1221 }
1222 
1223 // Test that bitfieldReverse is folded correctly.
TEST_F(ConstantFoldingExpressionTest,FoldBitfieldReverse)1224 TEST_F(ConstantFoldingExpressionTest, FoldBitfieldReverse)
1225 {
1226     const std::string &uintString = "bitfieldReverse((1u << 4u) | (1u << 7u))";
1227     evaluateUint(uintString);
1228     uint32_t flag1 = 1u << (31u - 4u);
1229     uint32_t flag2 = 1u << (31u - 7u);
1230     ASSERT_TRUE(constantFoundInAST(flag1 | flag2));
1231 }
1232 
1233 // Test that bitCount is folded correctly.
TEST_F(ConstantFoldingExpressionTest,FoldBitCount)1234 TEST_F(ConstantFoldingExpressionTest, FoldBitCount)
1235 {
1236     const std::string &intString = "bitCount(0x17103121u)";
1237     evaluateInt(intString);
1238     ASSERT_TRUE(constantFoundInAST(10));
1239 }
1240 
1241 // Test that findLSB is folded correctly.
TEST_F(ConstantFoldingExpressionTest,FoldFindLSB)1242 TEST_F(ConstantFoldingExpressionTest, FoldFindLSB)
1243 {
1244     const std::string &intString = "findLSB(0x80010000u)";
1245     evaluateInt(intString);
1246     ASSERT_TRUE(constantFoundInAST(16));
1247 }
1248 
1249 // Test that findLSB is folded correctly when the operand is zero.
TEST_F(ConstantFoldingExpressionTest,FoldFindLSBZero)1250 TEST_F(ConstantFoldingExpressionTest, FoldFindLSBZero)
1251 {
1252     const std::string &intString = "findLSB(0u)";
1253     evaluateInt(intString);
1254     ASSERT_TRUE(constantFoundInAST(-1));
1255 }
1256 
1257 // Test that findMSB is folded correctly.
TEST_F(ConstantFoldingExpressionTest,FoldFindMSB)1258 TEST_F(ConstantFoldingExpressionTest, FoldFindMSB)
1259 {
1260     const std::string &intString = "findMSB(0x01000008u)";
1261     evaluateInt(intString);
1262     ASSERT_TRUE(constantFoundInAST(24));
1263 }
1264 
1265 // Test that findMSB is folded correctly when the operand is zero.
TEST_F(ConstantFoldingExpressionTest,FoldFindMSBZero)1266 TEST_F(ConstantFoldingExpressionTest, FoldFindMSBZero)
1267 {
1268     const std::string &intString = "findMSB(0u)";
1269     evaluateInt(intString);
1270     ASSERT_TRUE(constantFoundInAST(-1));
1271 }
1272 
1273 // Test that findMSB is folded correctly for a negative integer.
1274 // It is supposed to return the index of the most significant bit set to 0.
TEST_F(ConstantFoldingExpressionTest,FoldFindMSBNegativeInt)1275 TEST_F(ConstantFoldingExpressionTest, FoldFindMSBNegativeInt)
1276 {
1277     const std::string &intString = "findMSB(-8)";
1278     evaluateInt(intString);
1279     ASSERT_TRUE(constantFoundInAST(2));
1280 }
1281 
1282 // Test that findMSB is folded correctly for -1.
TEST_F(ConstantFoldingExpressionTest,FoldFindMSBMinusOne)1283 TEST_F(ConstantFoldingExpressionTest, FoldFindMSBMinusOne)
1284 {
1285     const std::string &intString = "findMSB(-1)";
1286     evaluateInt(intString);
1287     ASSERT_TRUE(constantFoundInAST(-1));
1288 }
1289 
1290 // Test that packUnorm4x8 is folded correctly for a vector of zeroes.
TEST_F(ConstantFoldingExpressionTest,FoldPackUnorm4x8Zero)1291 TEST_F(ConstantFoldingExpressionTest, FoldPackUnorm4x8Zero)
1292 {
1293     const std::string &intString = "packUnorm4x8(vec4(0.0))";
1294     evaluateUint(intString);
1295     ASSERT_TRUE(constantFoundInAST(0u));
1296 }
1297 
1298 // Test that packUnorm4x8 is folded correctly for a vector of ones.
TEST_F(ConstantFoldingExpressionTest,FoldPackUnorm4x8One)1299 TEST_F(ConstantFoldingExpressionTest, FoldPackUnorm4x8One)
1300 {
1301     const std::string &intString = "packUnorm4x8(vec4(1.0))";
1302     evaluateUint(intString);
1303     ASSERT_TRUE(constantFoundInAST(0xffffffffu));
1304 }
1305 
1306 // Test that packSnorm4x8 is folded correctly for a vector of zeroes.
TEST_F(ConstantFoldingExpressionTest,FoldPackSnorm4x8Zero)1307 TEST_F(ConstantFoldingExpressionTest, FoldPackSnorm4x8Zero)
1308 {
1309     const std::string &intString = "packSnorm4x8(vec4(0.0))";
1310     evaluateUint(intString);
1311     ASSERT_TRUE(constantFoundInAST(0u));
1312 }
1313 
1314 // Test that packSnorm4x8 is folded correctly for a vector of ones.
TEST_F(ConstantFoldingExpressionTest,FoldPackSnorm4x8One)1315 TEST_F(ConstantFoldingExpressionTest, FoldPackSnorm4x8One)
1316 {
1317     const std::string &intString = "packSnorm4x8(vec4(1.0))";
1318     evaluateUint(intString);
1319     ASSERT_TRUE(constantFoundInAST(0x7f7f7f7fu));
1320 }
1321 
1322 // Test that packSnorm4x8 is folded correctly for a vector of minus ones.
TEST_F(ConstantFoldingExpressionTest,FoldPackSnorm4x8MinusOne)1323 TEST_F(ConstantFoldingExpressionTest, FoldPackSnorm4x8MinusOne)
1324 {
1325     const std::string &intString = "packSnorm4x8(vec4(-1.0))";
1326     evaluateUint(intString);
1327     ASSERT_TRUE(constantFoundInAST(0x81818181u));
1328 }
1329 
1330 // Test that unpackSnorm4x8 is folded correctly when it needs to clamp the result.
TEST_F(ConstantFoldingExpressionTest,FoldUnpackSnorm4x8Clamp)1331 TEST_F(ConstantFoldingExpressionTest, FoldUnpackSnorm4x8Clamp)
1332 {
1333     const std::string &floatString = "unpackSnorm4x8(0x00000080u).x";
1334     evaluateFloat(floatString);
1335     ASSERT_TRUE(constantFoundInAST(-1.0f));
1336 }
1337 
1338 // Test that unpackUnorm4x8 is folded correctly.
TEST_F(ConstantFoldingExpressionTest,FoldUnpackUnorm4x8)1339 TEST_F(ConstantFoldingExpressionTest, FoldUnpackUnorm4x8)
1340 {
1341     const std::string &floatString = "unpackUnorm4x8(0x007bbeefu).z";
1342     evaluateFloat(floatString);
1343     ASSERT_TRUE(constantFoundInAST(123.0f / 255.0f));
1344 }
1345 
1346 // Test that ldexp is folded correctly.
TEST_F(ConstantFoldingExpressionTest,FoldLdexp)1347 TEST_F(ConstantFoldingExpressionTest, FoldLdexp)
1348 {
1349     const std::string &floatString = "ldexp(0.625, 1)";
1350     evaluateFloat(floatString);
1351     ASSERT_TRUE(constantFoundInAST(1.25f));
1352 }
1353 
1354 // Fold a ternary operator.
TEST_F(ConstantFoldingTest,FoldTernary)1355 TEST_F(ConstantFoldingTest, FoldTernary)
1356 {
1357     const std::string &shaderString =
1358         R"(#version 300 es
1359         precision highp int;
1360         uniform int u;
1361         out int my_FragColor;
1362         void main()
1363         {
1364             my_FragColor = (true ? 1 : u);
1365         })";
1366     compileAssumeSuccess(shaderString);
1367     ASSERT_TRUE(constantFoundInAST(1));
1368     ASSERT_FALSE(symbolFoundInMain("u"));
1369 }
1370 
1371 // Fold a ternary operator inside a consuming expression.
TEST_F(ConstantFoldingTest,FoldTernaryInsideExpression)1372 TEST_F(ConstantFoldingTest, FoldTernaryInsideExpression)
1373 {
1374     const std::string &shaderString =
1375         R"(#version 300 es
1376         precision highp int;
1377         uniform int u;
1378         out int my_FragColor;
1379         void main()
1380         {
1381             my_FragColor = ivec2((true ? 1 : u) + 2, 4).x;
1382         })";
1383     compileAssumeSuccess(shaderString);
1384     ASSERT_TRUE(constantFoundInAST(3));
1385     ASSERT_FALSE(symbolFoundInMain("u"));
1386 }
1387 
1388 // Fold indexing into an array constructor.
TEST_F(ConstantFoldingExpressionTest,FoldArrayConstructorIndexing)1389 TEST_F(ConstantFoldingExpressionTest, FoldArrayConstructorIndexing)
1390 {
1391     const std::string &floatString = "(float[3](-1.0, 1.0, 2.0))[2]";
1392     evaluateFloat(floatString);
1393     ASSERT_FALSE(constantFoundInAST(-1.0f));
1394     ASSERT_FALSE(constantFoundInAST(1.0f));
1395     ASSERT_TRUE(constantFoundInAST(2.0f));
1396 }
1397 
1398 // Fold indexing into an array of arrays constructor.
TEST_F(ConstantFoldingExpressionTest,FoldArrayOfArraysConstructorIndexing)1399 TEST_F(ConstantFoldingExpressionTest, FoldArrayOfArraysConstructorIndexing)
1400 {
1401     const std::string &floatString = "(float[2][2](float[2](-1.0, 1.0), float[2](2.0, 3.0)))[1][0]";
1402     evaluateFloat(floatString);
1403     ASSERT_FALSE(constantFoundInAST(-1.0f));
1404     ASSERT_FALSE(constantFoundInAST(1.0f));
1405     ASSERT_FALSE(constantFoundInAST(3.0f));
1406     ASSERT_TRUE(constantFoundInAST(2.0f));
1407 }
1408 
1409 // Fold indexing into a named constant array.
TEST_F(ConstantFoldingTest,FoldNamedArrayIndexing)1410 TEST_F(ConstantFoldingTest, FoldNamedArrayIndexing)
1411 {
1412     const std::string &shaderString =
1413         R"(#version 300 es
1414         precision highp float;
1415         const float[3] arr = float[3](-1.0, 1.0, 2.0);
1416         out float my_FragColor;
1417         void main()
1418         {
1419             my_FragColor = arr[1];
1420         })";
1421     compileAssumeSuccess(shaderString);
1422     ASSERT_FALSE(constantFoundInAST(-1.0f));
1423     ASSERT_FALSE(constantFoundInAST(2.0f));
1424     ASSERT_TRUE(constantFoundInAST(1.0f));
1425     // The variable should be pruned out since after folding the indexing, there are no more
1426     // references to it.
1427     ASSERT_FALSE(symbolFoundInAST("arr"));
1428 }
1429 
1430 // Fold indexing into a named constant array of arrays.
TEST_F(ConstantFoldingTest,FoldNamedArrayOfArraysIndexing)1431 TEST_F(ConstantFoldingTest, FoldNamedArrayOfArraysIndexing)
1432 {
1433     const std::string &shaderString =
1434         R"(#version 310 es
1435         precision highp float;
1436         const float[2][2] arr = float[2][2](float[2](-1.0, 1.0), float[2](2.0, 3.0));
1437         out float my_FragColor;
1438         void main()
1439         {
1440             my_FragColor = arr[0][1];
1441         })";
1442     compileAssumeSuccess(shaderString);
1443     ASSERT_FALSE(constantFoundInAST(-1.0f));
1444     ASSERT_FALSE(constantFoundInAST(2.0f));
1445     ASSERT_FALSE(constantFoundInAST(3.0f));
1446     ASSERT_TRUE(constantFoundInAST(1.0f));
1447     // The variable should be pruned out since after folding the indexing, there are no more
1448     // references to it.
1449     ASSERT_FALSE(symbolFoundInAST("arr"));
1450 }
1451 
1452 // Fold indexing into an array constructor where some of the arguments are constant and others are
1453 // non-constant but without side effects.
TEST_F(ConstantFoldingTest,FoldArrayConstructorIndexingWithMixedArguments)1454 TEST_F(ConstantFoldingTest, FoldArrayConstructorIndexingWithMixedArguments)
1455 {
1456     const std::string &shaderString =
1457         R"(#version 300 es
1458         precision highp float;
1459         uniform float u;
1460         out float my_FragColor;
1461         void main()
1462         {
1463             my_FragColor = float[2](u, 1.0)[1];
1464         })";
1465     compileAssumeSuccess(shaderString);
1466     ASSERT_TRUE(constantFoundInAST(1.0f));
1467     ASSERT_FALSE(constantFoundInAST(1));
1468     ASSERT_FALSE(symbolFoundInMain("u"));
1469 }
1470 
1471 // Indexing into an array constructor where some of the arguments have side effects can't be folded.
TEST_F(ConstantFoldingTest,CantFoldArrayConstructorIndexingWithSideEffects)1472 TEST_F(ConstantFoldingTest, CantFoldArrayConstructorIndexingWithSideEffects)
1473 {
1474     const std::string &shaderString =
1475         R"(#version 300 es
1476         precision highp float;
1477         out float my_FragColor;
1478         void main()
1479         {
1480             float sideEffectTarget = 0.0;
1481             float f = float[3](sideEffectTarget = 1.0, 1.0, 2.0)[1];
1482             my_FragColor = f + sideEffectTarget;
1483         })";
1484     compileAssumeSuccess(shaderString);
1485     // All of the array constructor arguments should be present in the final AST.
1486     ASSERT_TRUE(constantFoundInAST(1.0f));
1487     ASSERT_TRUE(constantFoundInAST(2.0f));
1488 }
1489 
1490 // Fold comparing two array constructors.
TEST_F(ConstantFoldingTest,FoldArrayConstructorEquality)1491 TEST_F(ConstantFoldingTest, FoldArrayConstructorEquality)
1492 {
1493     const std::string &shaderString =
1494         R"(#version 300 es
1495         precision highp float;
1496         out float my_FragColor;
1497         void main()
1498         {
1499             const bool b = (float[3](2.0, 1.0, -1.0) == float[3](2.0, 1.0, -1.0));
1500             my_FragColor = b ? 3.0 : 4.0;
1501         })";
1502     compileAssumeSuccess(shaderString);
1503     ASSERT_TRUE(constantFoundInAST(3.0f));
1504     ASSERT_FALSE(constantFoundInAST(4.0f));
1505 }
1506 
1507 // Fold comparing two named constant arrays.
TEST_F(ConstantFoldingExpressionTest,FoldNamedArrayEquality)1508 TEST_F(ConstantFoldingExpressionTest, FoldNamedArrayEquality)
1509 {
1510     const std::string &shaderString =
1511         R"(#version 300 es
1512         precision highp float;
1513         const float[3] arrA = float[3](-1.0, 1.0, 2.0);
1514         const float[3] arrB = float[3](-1.0, 1.0, 2.0);
1515         out float my_FragColor;
1516         void main()
1517         {
1518             const bool b = (arrA == arrB);
1519             my_FragColor = b ? 3.0 : 4.0;
1520         })";
1521     compileAssumeSuccess(shaderString);
1522     ASSERT_TRUE(constantFoundInAST(3.0f));
1523     ASSERT_FALSE(constantFoundInAST(4.0f));
1524 }
1525 
1526 // Fold comparing two array of arrays constructors.
TEST_F(ConstantFoldingTest,FoldArrayOfArraysConstructorEquality)1527 TEST_F(ConstantFoldingTest, FoldArrayOfArraysConstructorEquality)
1528 {
1529     const std::string &shaderString =
1530         R"(#version 310 es
1531         precision highp float;
1532         out float my_FragColor;
1533         void main()
1534         {
1535             const bool b = (float[2][2](float[2](-1.0, 1.0), float[2](2.0, 3.0)) ==
1536                             float[2][2](float[2](-1.0, 1.0), float[2](2.0, 1000.0)));
1537             my_FragColor = b ? 4.0 : 5.0;
1538         })";
1539     compileAssumeSuccess(shaderString);
1540     ASSERT_TRUE(constantFoundInAST(5.0f));
1541     ASSERT_FALSE(constantFoundInAST(4.0f));
1542 }
1543 
1544 // Test that casting a negative float to uint results in a warning. ESSL 3.00.6 section 5.4.1
1545 // specifies this as an undefined conversion.
TEST_F(ConstantFoldingExpressionTest,FoldNegativeFloatToUint)1546 TEST_F(ConstantFoldingExpressionTest, FoldNegativeFloatToUint)
1547 {
1548     const std::string &uintString = "uint(-1.0)";
1549     evaluateUint(uintString);
1550     ASSERT_TRUE(constantFoundInAST(std::numeric_limits<unsigned int>::max()));
1551     ASSERT_TRUE(hasWarning());
1552 }
1553 
1554 // Test that casting a negative float to uint inside a uvec constructor results in a warning. ESSL
1555 // 3.00.6 section 5.4.1 specifies this as an undefined conversion.
TEST_F(ConstantFoldingExpressionTest,FoldNegativeFloatToUvec)1556 TEST_F(ConstantFoldingExpressionTest, FoldNegativeFloatToUvec)
1557 {
1558     const std::string &uintString = "uvec4(2.0, 1.0, vec2(0.0, -1.0)).w";
1559     evaluateUint(uintString);
1560     ASSERT_TRUE(constantFoundInAST(std::numeric_limits<unsigned int>::max()));
1561     ASSERT_TRUE(hasWarning());
1562 }
1563 
1564 // Test that a negative float doesn't result in a warning when it is inside a constructor but isn't
1565 // actually converted.
TEST_F(ConstantFoldingExpressionTest,NegativeFloatInsideUvecConstructorButOutOfRange)1566 TEST_F(ConstantFoldingExpressionTest, NegativeFloatInsideUvecConstructorButOutOfRange)
1567 {
1568     const std::string &uintString = "uvec2(1.0, vec2(0.0, -1.0)).x";
1569     evaluateUint(uintString);
1570     ASSERT_FALSE(hasWarning());
1571 }
1572 
1573 // Test that a large float (above max int32_t) is converted to unsigned integer correctly.
TEST_F(ConstantFoldingExpressionTest,LargeFloatToUint)1574 TEST_F(ConstantFoldingExpressionTest, LargeFloatToUint)
1575 {
1576     const std::string &uintString = "uint(3221225472.0)";
1577     evaluateUint(uintString);
1578     ASSERT_TRUE(constantFoundInAST(3221225472u));
1579     ASSERT_FALSE(hasWarning());
1580 }
1581 
1582 // Test that folding % with a negative dividend generates a warning.
TEST_F(ConstantFoldingExpressionTest,IntegerModulusNegativeDividend)1583 TEST_F(ConstantFoldingExpressionTest, IntegerModulusNegativeDividend)
1584 {
1585     const std::string &intString = "(-5) % 3";
1586     evaluateInt(intString);
1587     ASSERT_TRUE(hasWarning());
1588 }
1589 
1590 // Test that folding % with a negative divisor generates a warning.
TEST_F(ConstantFoldingExpressionTest,IntegerModulusNegativeDivisor)1591 TEST_F(ConstantFoldingExpressionTest, IntegerModulusNegativeDivisor)
1592 {
1593     const std::string &intString = "5 % (-3)";
1594     evaluateInt(intString);
1595     ASSERT_TRUE(hasWarning());
1596 }
1597 
TEST_F(ConstantFoldingExpressionTest,IsnanDifferentComponents)1598 TEST_F(ConstantFoldingExpressionTest, IsnanDifferentComponents)
1599 {
1600     const std::string &ivec4String =
1601         "ivec4(mix(ivec2(2), ivec2(3), isnan(vec2(1.0, 0.0 / 0.0))), 4, 5)";
1602     evaluateIvec4(ivec4String);
1603     int outputElements[] = {2, 3, 4, 5};
1604     std::vector<int> result(outputElements, outputElements + 4);
1605     ASSERT_TRUE(constantVectorFoundInAST(result));
1606 }
1607 
TEST_F(ConstantFoldingExpressionTest,IsinfDifferentComponents)1608 TEST_F(ConstantFoldingExpressionTest, IsinfDifferentComponents)
1609 {
1610     const std::string &ivec4String =
1611         "ivec4(mix(ivec2(2), ivec2(3), isinf(vec2(0.0, 1.0e2048))), 4, 5)";
1612     evaluateIvec4(ivec4String);
1613     int outputElements[] = {2, 3, 4, 5};
1614     std::vector<int> result(outputElements, outputElements + 4);
1615     ASSERT_TRUE(constantVectorFoundInAST(result));
1616 }
1617 
TEST_F(ConstantFoldingExpressionTest,FloatBitsToIntDifferentComponents)1618 TEST_F(ConstantFoldingExpressionTest, FloatBitsToIntDifferentComponents)
1619 {
1620     const std::string &ivec4String = "ivec4(floatBitsToInt(vec2(0.0, 1.0)), 4, 5)";
1621     evaluateIvec4(ivec4String);
1622     int outputElements[] = {0, 0x3f800000, 4, 5};
1623     std::vector<int> result(outputElements, outputElements + 4);
1624     ASSERT_TRUE(constantVectorFoundInAST(result));
1625 }
1626 
TEST_F(ConstantFoldingExpressionTest,FloatBitsToUintDifferentComponents)1627 TEST_F(ConstantFoldingExpressionTest, FloatBitsToUintDifferentComponents)
1628 {
1629     const std::string &ivec4String = "ivec4(floatBitsToUint(vec2(0.0, 1.0)), 4, 5)";
1630     evaluateIvec4(ivec4String);
1631     int outputElements[] = {0, 0x3f800000, 4, 5};
1632     std::vector<int> result(outputElements, outputElements + 4);
1633     ASSERT_TRUE(constantVectorFoundInAST(result));
1634 }
1635 
TEST_F(ConstantFoldingExpressionTest,IntBitsToFloatDifferentComponents)1636 TEST_F(ConstantFoldingExpressionTest, IntBitsToFloatDifferentComponents)
1637 {
1638     const std::string &vec4String = "vec4(intBitsToFloat(ivec2(0, 0x3f800000)), 0.25, 0.5)";
1639     evaluateVec4(vec4String);
1640     float outputElements[] = {0.0, 1.0, 0.25, 0.5};
1641     std::vector<float> result(outputElements, outputElements + 4);
1642     ASSERT_TRUE(constantVectorFoundInAST(result));
1643 }
1644 
TEST_F(ConstantFoldingExpressionTest,UintBitsToFloatDifferentComponents)1645 TEST_F(ConstantFoldingExpressionTest, UintBitsToFloatDifferentComponents)
1646 {
1647     const std::string &vec4String = "vec4(uintBitsToFloat(uvec2(0U, 0x3f800000U)), 0.25, 0.5)";
1648     evaluateVec4(vec4String);
1649     float outputElements[] = {0.0, 1.0, 0.25, 0.5};
1650     std::vector<float> result(outputElements, outputElements + 4);
1651     ASSERT_TRUE(constantVectorFoundInAST(result));
1652 }
1653