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