• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © 2023 Google LLC
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21  * IN THE SOFTWARE.
22  */
23 
24 #include <gtest/gtest.h>
25 #include <gtest/gtest-spi.h>
26 
27 #include "main/mtypes.h"
28 #include "standalone_scaffolding.h"
29 #include "ir.h"
30 #include "ir_optimization.h"
31 #include "nir.h"
32 #include "builtin_functions.h"
33 #include "nir.h"
34 #include "gl_nir.h"
35 #include "gl_nir_linker.h"
36 #include "glsl_parser_extras.h"
37 #include "glsl_to_nir.h"
38 #include "linker_util.h"
39 #include "nir_builder.h"
40 
41 /* The printed-GLSL-IR tests use fmemopen so we can do stdio to memory (or you'd
42  * need equivalent tempfiles that you manage).  Just disable this test on those
43  * platforms (aka Windows).
44  */
45 #ifdef HAVE_FMEMOPEN
46 
47 namespace
48 {
49    class gl_nir_lower_mediump_test : public ::testing::Test
50    {
51    protected:
52       gl_nir_lower_mediump_test();
53       ~gl_nir_lower_mediump_test();
54 
55       struct gl_shader *compile_shader(GLenum type, const char *source);
56       void compile(const char *source);
57 
58       struct gl_context local_ctx;
59       struct gl_context *ctx;
60 
find_op(nir_op op)61       nir_alu_instr *find_op(nir_op op)
62       {
63          if (!nir)
64             return NULL;
65 
66          nir_foreach_function_impl(impl, nir)
67          {
68             nir_foreach_block(block, impl)
69             {
70                nir_foreach_instr(instr, block)
71                {
72                   if (instr->type == nir_instr_type_alu)
73                   {
74                      nir_alu_instr *alu = nir_instr_as_alu(instr);
75                      if (alu->op == op)
76                         return alu;
77                   }
78                }
79             }
80          }
81          return NULL;
82       }
83 
op_dest_bits(nir_op op)84       uint32_t op_dest_bits(nir_op op)
85       {
86          nir_alu_instr *alu = find_op(op);
87          EXPECT_TRUE(alu != NULL);
88          return alu->def.bit_size;
89       }
90 
91       /* Returns the common bit size of all src operands (failing if not matching). */
op_src_bits(nir_op op)92       uint32_t op_src_bits(nir_op op)
93       {
94          nir_alu_instr *alu = find_op(op);
95          EXPECT_TRUE(alu != NULL);
96 
97          for (int i = 0; i < nir_op_infos[op].num_inputs; i++) {
98             EXPECT_EQ(alu->src[i].src.ssa->bit_size, alu->src[0].src.ssa->bit_size);
99          }
100          return alu->src[0].src.ssa->bit_size;
101       }
102 
103       nir_shader *nir;
104       struct gl_shader_program *whole_program;
105       const char *source;
106       char *fs_ir;
107    };
108 
gl_nir_lower_mediump_test()109    gl_nir_lower_mediump_test::gl_nir_lower_mediump_test()
110        : nir(NULL), source(NULL), fs_ir(NULL)
111    {
112       glsl_type_singleton_init_or_ref();
113    }
114 
~gl_nir_lower_mediump_test()115    gl_nir_lower_mediump_test::~gl_nir_lower_mediump_test()
116    {
117       if (HasFailure())
118       {
119          if (source)
120             printf("\nSource for the failed test:\n%s\n", source);
121          if (fs_ir) {
122             printf("\nGLSL IR from the failed test:\n\n");
123             printf("%s", fs_ir);
124 
125          }
126          if (nir) {
127             printf("\nNIR from the failed test:\n\n");
128             nir_print_shader(nir, stdout);
129          }
130       }
131 
132       standalone_destroy_shader_program(whole_program);
133 
134       free(fs_ir);
135 
136       glsl_type_singleton_decref();
137    }
138 
139    struct gl_shader *
compile_shader(GLenum type,const char * source)140    gl_nir_lower_mediump_test::compile_shader(GLenum type, const char *source)
141    {
142       struct gl_shader *shader = standalone_add_shader_source(ctx, whole_program, type, source);
143 
144       /* Save off the GLSL IR, since the compile frees it. */
145       char temp[4096];
146       FILE *ftemp = NULL;
147       if (type == GL_FRAGMENT_SHADER)
148          ftemp = fmemopen(temp, sizeof(temp), "w");
149 
150       _mesa_glsl_compile_shader(ctx, shader, ftemp, false, false, true);
151 
152       if (type == GL_FRAGMENT_SHADER) {
153          fclose(ftemp);
154          fs_ir = strdup(temp);
155       }
156 
157       return shader;
158    }
159 
160    void
compile(const char * source)161    gl_nir_lower_mediump_test::compile(const char *source)
162    {
163       ctx = &local_ctx;
164 
165       static const struct nir_shader_compiler_options compiler_options = {
166           .support_16bit_alu = true,
167       };
168 
169       /* Get better variable names from GLSL IR for debugging. */
170       ir_variable::temporaries_allocate_names = true;
171 
172       initialize_context_to_defaults(ctx, API_OPENGLES2);
173       ctx->Version = 31;
174       for (int i = 0; i < MESA_SHADER_STAGES; i++) {
175          ctx->Const.ShaderCompilerOptions[i].LowerPrecisionFloat16 = true;
176          ctx->Const.ShaderCompilerOptions[i].LowerPrecisionInt16 = true;
177          ctx->Const.ShaderCompilerOptions[i].NirOptions = &compiler_options;
178       }
179 
180       /* GL_ARB_explicit_uniform_location, GL_MAX_UNIFORM_LOCATIONS */
181       ctx->Const.MaxUserAssignableUniformLocations =
182          4 * MESA_SHADER_STAGES * MAX_UNIFORMS;
183 
184       ctx->Const.Program[MESA_SHADER_VERTEX].MaxCombinedUniformComponents = 128 * 4;
185       ctx->Const.Program[MESA_SHADER_FRAGMENT].MaxCombinedUniformComponents = 16 * 4;
186 
187       _mesa_glsl_builtin_functions_init_or_ref();
188 
189       whole_program = standalone_create_shader_program();
190       whole_program->IsES = true;
191 
192       const char *vs_source = R"(#version 310 es
193       void main() {
194          gl_Position = vec4(0.0);
195       })";
196       compile_shader(GL_VERTEX_SHADER, vs_source);
197 
198       compile_shader(GL_FRAGMENT_SHADER, source);
199 
200       for (unsigned i = 0; i < whole_program->NumShaders; i++)
201       {
202          struct gl_shader *shader = whole_program->Shaders[i];
203          if (shader->CompileStatus != COMPILE_SUCCESS)
204             fprintf(stderr, "Compiler error: %s", shader->InfoLog);
205          ASSERT_EQ(shader->CompileStatus, COMPILE_SUCCESS);
206       }
207 
208       link_shaders_init(ctx, whole_program);
209       gl_nir_link_glsl(ctx, whole_program);
210       if (whole_program->data->LinkStatus != LINKING_SUCCESS)
211          fprintf(stderr, "Linker error: %s", whole_program->data->InfoLog);
212       EXPECT_EQ(whole_program->data->LinkStatus, LINKING_SUCCESS);
213 
214       nir = whole_program->_LinkedShaders[MESA_SHADER_FRAGMENT]->Program->nir;
215 
216       /* Store the source for printing from later assertions. */
217       this->source = source;
218    }
219 
220    // A predicate-formatter for asserting that two integers are mutually prime.
glsl_ir_contains(const char * glsl_ir_expr,const char * needle_expr,const char * glsl_ir,const char * needle)221    testing::AssertionResult glsl_ir_contains(const char *glsl_ir_expr,
222                                              const char *needle_expr,
223                                              const char *glsl_ir,
224                                              const char *needle)
225    {
226       /* If we didn't HAVE_FMEMOPEN, we won't have GLSL IR to look at.  Just
227        * skip those parts of the tests on such platforms.
228        */
229       if (!glsl_ir)
230          return testing::AssertionSuccess();
231 
232       if (strstr(glsl_ir, needle))
233          return testing::AssertionSuccess();
234 
235       return testing::AssertionFailure() << " " << needle_expr << " not found in GLSL IR";
236    }
237 } // namespace
238 
TEST_F(gl_nir_lower_mediump_test,float_simple_mul)239 TEST_F(gl_nir_lower_mediump_test, float_simple_mul)
240 {
241    ASSERT_NO_FATAL_FAILURE(compile(
242        R"(#version 310 es
243          uniform mediump float a, b;
244          out mediump float result;
245 
246          void main()
247          {
248             result = a * b;
249          }
250     )"));
251 
252    EXPECT_EQ(op_dest_bits(nir_op_fmul), 16);
253 }
254 
TEST_F(gl_nir_lower_mediump_test,int_simple_mul)255 TEST_F(gl_nir_lower_mediump_test, int_simple_mul)
256 {
257    ASSERT_NO_FATAL_FAILURE(compile(
258        R"(#version 310 es
259          precision highp float;
260          precision mediump int;
261          uniform mediump int a, b;
262          out mediump int result;
263 
264          void main()
265          {
266             result = a * b;
267          }
268     )"));
269 
270    EXPECT_EQ(op_dest_bits(nir_op_imul), 16);
271 }
272 
TEST_F(gl_nir_lower_mediump_test,int_default_precision_med)273 TEST_F(gl_nir_lower_mediump_test, int_default_precision_med)
274 {
275    ASSERT_NO_FATAL_FAILURE(compile(
276        R"(#version 310 es
277          precision highp float;
278          precision mediump int;
279          uniform int a, b;
280          out int result;
281 
282          void main()
283          {
284             result = a * b;
285          }
286     )"));
287 
288    EXPECT_EQ(op_dest_bits(nir_op_imul), 16);
289 }
290 
TEST_F(gl_nir_lower_mediump_test,int_default_precision_high)291 TEST_F(gl_nir_lower_mediump_test, int_default_precision_high)
292 {
293    ASSERT_NO_FATAL_FAILURE(compile(
294        R"(#version 310 es
295          precision mediump float;
296          precision highp int;
297          uniform int a, b;
298          out int result;
299 
300          void main()
301          {
302             result = a * b;
303          }
304     )"));
305 
306    EXPECT_EQ(op_dest_bits(nir_op_imul), 32);
307 }
308 
309 /* Test that a builtin with mediump args does mediump computation. */
TEST_F(gl_nir_lower_mediump_test,dot_builtin)310 TEST_F(gl_nir_lower_mediump_test, dot_builtin)
311 {
312    ASSERT_NO_FATAL_FAILURE(compile(
313        R"(#version 310 es
314          precision highp float;
315          precision highp int;
316          uniform mediump vec4 a, b;
317          out float result;
318 
319          void main()
320          {
321             result = dot(a, b);
322          }
323     )"));
324 
325    EXPECT_EQ(op_dest_bits(nir_op_fdot4), 16);
326 }
327 
328 /* Test that a constant-index array deref is mediump */
TEST_F(gl_nir_lower_mediump_test,array_const_index)329 TEST_F(gl_nir_lower_mediump_test, array_const_index)
330 {
331    ASSERT_NO_FATAL_FAILURE(compile(
332        R"(#version 310 es
333          precision highp float;
334          precision highp int;
335          uniform mediump float a, b[2];
336          out float result;
337 
338          void main()
339          {
340             result = a * b[1];
341          }
342     )"));
343 
344    EXPECT_EQ(op_dest_bits(nir_op_fmul), 16);
345 }
346 
347 /* Test that a variable-index array deref is mediump, even if the array index is highp */
TEST_F(gl_nir_lower_mediump_test,array_uniform_index)348 TEST_F(gl_nir_lower_mediump_test, array_uniform_index)
349 {
350    ASSERT_NO_FATAL_FAILURE(compile(
351        R"(#version 310 es
352          precision highp float;
353          uniform mediump float a, b[2];
354          uniform highp int i;
355          out float result;
356 
357          void main()
358          {
359             result = a * b[i];
360          }
361     )"));
362 
363    EXPECT_EQ(op_dest_bits(nir_op_fmul), 16);
364 }
365 
366 /* Test that a variable-index array deref is highp, even if the array index is mediump */
TEST_F(gl_nir_lower_mediump_test,array_mediump_index)367 TEST_F(gl_nir_lower_mediump_test, array_mediump_index)
368 {
369    ASSERT_NO_FATAL_FAILURE(compile(
370        R"(#version 310 es
371          precision highp float;
372          uniform highp int b[2];
373          uniform mediump int a, i;
374          out highp int result;
375 
376          void main()
377          {
378             result = a * b[i];
379          }
380     )"));
381 
382    EXPECT_PRED_FORMAT2(glsl_ir_contains, fs_ir, "expression int * ");
383 
384    EXPECT_EQ(op_dest_bits(nir_op_imul), 32);
385 }
386 
TEST_F(gl_nir_lower_mediump_test,func_return)387 TEST_F(gl_nir_lower_mediump_test, func_return)
388 {
389    ASSERT_NO_FATAL_FAILURE(compile(
390        R"(#version 310 es
391          precision highp float; /* Make sure that default highp temps in function handling don't break our mediump return. */
392          uniform mediump float a;
393          uniform highp float b;
394          out float result;
395 
396          mediump float func()
397          {
398             return b; /* Returning highp b here, but it should be the mediump return value qualifier that matters */
399          }
400 
401          void main()
402          {
403             /* "If a function returns a value, then a call to that function may
404              *  be used as an expression, whose type will be the type that was
405              *  used to declare or define the function."
406              */
407             result = a * func();
408          }
409     )"));
410 
411    EXPECT_PRED_FORMAT2(glsl_ir_contains, fs_ir, "expression float16_t * ");
412 
413    EXPECT_EQ(op_dest_bits(nir_op_fmul), 16);
414 }
415 
TEST_F(gl_nir_lower_mediump_test,func_args_in_mediump)416 TEST_F(gl_nir_lower_mediump_test, func_args_in_mediump)
417 {
418    ASSERT_NO_FATAL_FAILURE(compile(
419        R"(#version 310 es
420          precision highp float; /* Make sure that default highp temps in function handling don't break our mediump return. */
421          uniform highp float a, b;
422          out highp float result;
423 
424          highp float func(mediump float x, mediump float y)
425          {
426             return x * y; /* should be mediump due to x and y, but propagating qualifiers from a,b by inlining could trick it. */
427          }
428 
429          void main()
430          {
431             result = func(a, b);
432          }
433     )"));
434 
435    EXPECT_PRED_FORMAT2(glsl_ir_contains, fs_ir, "expression float f162f (expression float16_t * (expression float16_t f2fmp (var_ref x) ) (expression float16_t f2fmp (var_ref y) ) )");
436 
437    EXPECT_EQ(op_dest_bits(nir_op_fmul), 16);
438 }
439 
TEST_F(gl_nir_lower_mediump_test,func_args_inout_mediump)440 TEST_F(gl_nir_lower_mediump_test, func_args_inout_mediump)
441 {
442    ASSERT_NO_FATAL_FAILURE(compile(
443        R"(#version 310 es
444          precision highp float; /* Make sure that default highp temps in function handling don't break our mediump inout. */
445          uniform highp float a, b;
446          out float result;
447 
448          void func(inout mediump float x, mediump float y)
449          {
450             x = x * y; /* should be mediump due to x and y, but propagating qualifiers from a,b by inlining could trick it. */
451          }
452 
453          void main()
454          {
455             /* The spec says "function input and output is done through copies,
456              * and therefore qualifiers do not have to match."  So we use a
457              * highp here for our mediump inout.
458              */
459             highp float x = a;
460             func(x, b);
461             result = x;
462          }
463     )"));
464 
465    EXPECT_PRED_FORMAT2(glsl_ir_contains, fs_ir, "expression float16_t * ");
466 
467    EXPECT_EQ(op_dest_bits(nir_op_fmul), 16);
468 }
469 
TEST_F(gl_nir_lower_mediump_test,func_args_in_out_mediump)470 TEST_F(gl_nir_lower_mediump_test, func_args_in_out_mediump)
471 {
472    ASSERT_NO_FATAL_FAILURE(compile(
473        R"(#version 310 es
474          precision highp float; /* Make sure that default highp temps in function handling don't break our mediump inout. */
475          uniform highp float a, b;
476          out float result;
477 
478          void func(mediump float x, mediump float y, out mediump float w)
479          {
480             w = x * y; /* should be mediump due to x and y, but propagating qualifiers from a,b by inlining could trick it. */
481          }
482 
483          void main()
484          {
485             /* The spec says "function input and output is done through copies,
486              * and therefore qualifiers do not have to match."  So we use a
487              * highp here for our mediump out.
488              */
489             highp float x;
490             func(a, b, x);
491             result = x;
492          }
493     )"));
494 
495    EXPECT_PRED_FORMAT2(glsl_ir_contains, fs_ir, "expression float16_t * ");
496 
497    EXPECT_EQ(op_dest_bits(nir_op_fmul), 16);
498 }
499 
TEST_F(gl_nir_lower_mediump_test,func_args_inout_highp)500 TEST_F(gl_nir_lower_mediump_test, func_args_inout_highp)
501 {
502    ASSERT_NO_FATAL_FAILURE(compile(
503        R"(#version 310 es
504          precision mediump float; /* Make sure that default mediump temps in function handling don't break our highp inout. */
505          uniform mediump float a, b;
506          out float result;
507 
508          void func(inout highp float x, highp float y)
509          {
510             x = x * y; /* should be highp due to x and y, but propagating qualifiers from a,b by inlining could trick it. */
511          }
512 
513          void main()
514          {
515             mediump float x = a;
516             func(x, b);
517             result = x;
518          }
519     )"));
520 
521    EXPECT_PRED_FORMAT2(glsl_ir_contains, fs_ir, "expression float * ");
522 
523    EXPECT_EQ(op_dest_bits(nir_op_fmul), 32);
524 }
525 
TEST_F(gl_nir_lower_mediump_test,if_mediump)526 TEST_F(gl_nir_lower_mediump_test, if_mediump)
527 {
528    ASSERT_NO_FATAL_FAILURE(compile(
529        R"(#version 310 es
530          precision highp float;
531          uniform mediump float a, b, c;
532          out float result;
533 
534          void main()
535          {
536             if (a * b < c)
537                result = 1.0;
538             else
539                result = 0.0;
540          }
541     )"));
542 
543    EXPECT_EQ(op_dest_bits(nir_op_fmul), 16);
544    EXPECT_EQ(op_src_bits(nir_op_flt), 16);
545 }
546 
TEST_F(gl_nir_lower_mediump_test,mat_mul_mediump)547 TEST_F(gl_nir_lower_mediump_test, mat_mul_mediump)
548 {
549    ASSERT_NO_FATAL_FAILURE(compile(
550        R"(#version 310 es
551          precision highp float;
552          uniform mediump mat2 a;
553          uniform mediump vec2 b;
554          out highp vec2 result;
555 
556          void main()
557          {
558             result = a * b;
559          }
560     )"));
561 
562    EXPECT_EQ(op_dest_bits(nir_op_fmul), 16);
563 }
564 
TEST_F(gl_nir_lower_mediump_test,struct_default_precision_lvalue)565 TEST_F(gl_nir_lower_mediump_test, struct_default_precision_lvalue)
566 {
567    ASSERT_NO_FATAL_FAILURE(compile(
568        R"(#version 310 es
569          precision highp float;
570          precision mediump int;
571          struct S {
572             float x, y;
573             int z, w;
574          };
575          uniform S a;
576          out mediump vec2 result;
577 
578          void main()
579          {
580             /* I believe that structure members don't have a precision
581              * qualifier, so we expect the precision of these operations to come
582              * from the lvalue (which is higher precedence than the default
583              * precision).
584              */
585             mediump float resultf = a.x * a.y;
586             highp int resulti = a.z * a.w;
587             result = vec2(resultf, float(resulti));
588          }
589     )"));
590 
591    /* GLSL fails to implement this correctly. */
592    EXPECT_NONFATAL_FAILURE(
593        EXPECT_PRED_FORMAT2(glsl_ir_contains, fs_ir,
594                            "expression float16_t * (record_ref (var_ref a)  x) (record_ref (var_ref a)  y) "),
595        "not found in GLSL IR");
596    EXPECT_NONFATAL_FAILURE(
597        EXPECT_PRED_FORMAT2(glsl_ir_contains, fs_ir,
598                            "expression int * (record_ref (var_ref a)  z) (record_ref (var_ref a)  w) "),
599        "not found in GLSL IR");
600 
601    // Enable these checks once we fix the GLSL.
602    //EXPECT_EQ(op_dest_bits(nir_op_fmul), 16);
603    //EXPECT_EQ(op_dest_bits(nir_op_imul), 32);
604 }
605 
TEST_F(gl_nir_lower_mediump_test,float_constructor)606 TEST_F(gl_nir_lower_mediump_test, float_constructor)
607 {
608    ASSERT_NO_FATAL_FAILURE(compile(
609        R"(#version 310 es
610          precision mediump float;
611          uniform highp uint a;
612          uniform mediump float b;
613          out mediump float result;
614 
615          void main()
616          {
617             /* It's tricky to reconcile these two bits of spec: "Literal
618              * constants do not have precision qualifiers. Neither do Boolean
619              * variables. Neither do constructors."
620              *
621              * and
622              *
623              * "For this paragraph, “operationincludes operators, built-in
624              * functions, and constructors, andoperandincludes function
625              * arguments and constructor arguments."
626              *
627              * I take this to mean that the language doesn't let you put a
628              * precision qualifier on a constructor (or literal), but the
629              * constructor operation gets precision qualification inference
630              * based on its args like normal.
631              */
632             result = float(a) * b;
633          }
634     )"));
635 
636    EXPECT_EQ(op_dest_bits(nir_op_fmul), 32);
637 }
638 
TEST_F(gl_nir_lower_mediump_test,vec2_constructor)639 TEST_F(gl_nir_lower_mediump_test, vec2_constructor)
640 {
641    ASSERT_NO_FATAL_FAILURE(compile(
642        R"(#version 310 es
643          precision mediump float;
644          uniform highp float a, b;
645          uniform mediump float c;
646          out mediump vec2 result;
647 
648          void main()
649          {
650             result = c * vec2(a, b);
651          }
652     )"));
653 
654    EXPECT_EQ(op_dest_bits(nir_op_fmul), 32);
655 }
TEST_F(gl_nir_lower_mediump_test,vec4_of_float_constructor)656 TEST_F(gl_nir_lower_mediump_test, vec4_of_float_constructor)
657 {
658    ASSERT_NO_FATAL_FAILURE(compile(
659        R"(#version 310 es
660          precision mediump float;
661          uniform highp float a;
662          uniform mediump float b;
663          out mediump vec4 result;
664 
665          void main()
666          {
667             result = b * vec4(a);
668          }
669     )"));
670 
671    EXPECT_EQ(op_dest_bits(nir_op_fmul), 32);
672 }
673 
TEST_F(gl_nir_lower_mediump_test,vec4_of_vec2_constructor)674 TEST_F(gl_nir_lower_mediump_test, vec4_of_vec2_constructor)
675 {
676    ASSERT_NO_FATAL_FAILURE(compile(
677        R"(#version 310 es
678          precision mediump float;
679          uniform highp vec2 a, b;
680          uniform mediump vec4 c;
681          out mediump vec4 result;
682 
683          void main()
684          {
685             /* GLSL IR has to either have a temp for a*b, or clone the
686              * expression and let it get CSEed later.  If it chooses temp, that
687              * may confuse us.
688              */
689             result = c + vec4(a * b, 0.0, 0.0);
690          }
691     )"));
692 
693    EXPECT_EQ(op_dest_bits(nir_op_fmul), 32);
694    EXPECT_EQ(op_dest_bits(nir_op_fadd), 32);
695 }
696 
TEST_F(gl_nir_lower_mediump_test,float_literal_mediump)697 TEST_F(gl_nir_lower_mediump_test, float_literal_mediump)
698 {
699    ASSERT_NO_FATAL_FAILURE(compile(
700        R"(#version 310 es
701          precision highp float;
702          uniform mediump float a;
703          out highp float result;
704 
705          void main()
706          {
707             /* The literal is unqualified, so it shouldn't promote the expression to highp. */
708             result = a * 2.0;
709          }
710     )"));
711 
712    EXPECT_EQ(op_dest_bits(nir_op_fmul), 16);
713 }
714 
TEST_F(gl_nir_lower_mediump_test,float_const_highp)715 TEST_F(gl_nir_lower_mediump_test, float_const_highp)
716 {
717    ASSERT_NO_FATAL_FAILURE(compile(
718        R"(#version 310 es
719          precision highp float;
720          uniform mediump float a;
721          out highp float result;
722 
723          void main()
724          {
725             highp float two = 2.0;
726             /* The constant is highp, so even with constant propagation the expression should be highp. */
727             result = a * two;
728          }
729     )"));
730 
731    EXPECT_EQ(op_dest_bits(nir_op_fmul), 32);
732 }
733 
TEST_F(gl_nir_lower_mediump_test,float_const_expr_mediump)734 TEST_F(gl_nir_lower_mediump_test, float_const_expr_mediump)
735 {
736    ASSERT_NO_FATAL_FAILURE(compile(
737        R"(#version 310 es
738          precision highp float;
739          uniform mediump float a;
740          out highp float result;
741 
742          void main()
743          {
744             /* "Where the precision of a constant integral or constant floating
745              * point expression is not specified, evaluation is performed at
746              * highp. This rule does not affect the precision qualification of the
747              * expression."
748              * So the 5.0 is calculated at highp, but a * 5.0 is calculated at mediump.
749              */
750             result = a * (2.0 + 3.0);
751          }
752     )"));
753 
754    EXPECT_EQ(op_dest_bits(nir_op_fmul), 16);
755 }
756 
TEST_F(gl_nir_lower_mediump_test,unpackUnorm4x8)757 TEST_F(gl_nir_lower_mediump_test, unpackUnorm4x8)
758 {
759    ASSERT_NO_FATAL_FAILURE(compile(
760        R"(#version 310 es
761          precision highp float;
762          uniform highp uint a;
763          uniform mediump float b;
764          out highp float result;
765 
766          void main()
767          {
768             result = unpackUnorm4x8(a).x * b;
769          }
770     )"));
771 
772    /* XXX: GLSL doesn't lower this one correctly, currently.  It returns highp despite the prototype being mediump. */
773    EXPECT_NONFATAL_FAILURE(
774       EXPECT_PRED_FORMAT2(glsl_ir_contains, fs_ir, "expression f16vec4 unpackUnorm4x8 (var_ref a"),
775       "not found in GLSL IR");
776    EXPECT_PRED_FORMAT2(glsl_ir_contains, fs_ir, "expression float16_t *");
777 
778    /* XXX: NIR insists that nir_op_unpack_unorm_4x8 returns 32 bits per channel, too. */
779    EXPECT_NONFATAL_FAILURE(
780       EXPECT_EQ(op_dest_bits(nir_op_unpack_unorm_4x8), 16),
781       "op_dest_bits");
782    EXPECT_EQ(op_dest_bits(nir_op_fmul), 16);
783 }
784 
TEST_F(gl_nir_lower_mediump_test,packUnorm4x8)785 TEST_F(gl_nir_lower_mediump_test, packUnorm4x8)
786 {
787    ASSERT_NO_FATAL_FAILURE(compile(
788        R"(#version 310 es
789          precision highp float;
790          uniform mediump vec4 a;
791          uniform mediump uint b;
792          out highp uint result;
793 
794          void main()
795          {
796             result = packUnorm4x8(a) & b;
797          }
798     )"));
799 
800    /* Test both the GLSL IR return value and an op using it with a mediump
801     * value, so we can be sure it's not just that we're assigning to highp.
802     */
803    EXPECT_PRED_FORMAT2(glsl_ir_contains, fs_ir, "expression uint packUnorm4x8 (var_ref a)");
804    EXPECT_PRED_FORMAT2(glsl_ir_contains, fs_ir, "expression uint &");
805 
806    EXPECT_EQ(op_dest_bits(nir_op_pack_unorm_4x8), 32);
807 }
808 
809 /* XXX: Add unit tests getting at precision of temporaries inside builtin function impls. */
810 /* XXX: Add unit tests getting at precision of any other temps internally generated by the compiler */
811 /* XXX: Add unit tests checking for default precision on user-declared function temps*/
812 
813 #endif /* HAVE_FMEMOPEN */
814