• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1import re
2from nir_opcodes import opcodes
3from nir_opcodes import type_has_size, type_size, type_sizes, type_base_type
4
5def type_add_size(type_, size):
6    if type_has_size(type_):
7        return type_
8    return type_ + str(size)
9
10def op_bit_sizes(op):
11    sizes = None
12    if not type_has_size(op.output_type):
13        sizes = set(type_sizes(op.output_type))
14
15    for input_type in op.input_types:
16        if not type_has_size(input_type):
17            if sizes is None:
18                sizes = set(type_sizes(input_type))
19            else:
20                sizes = sizes.intersection(set(type_sizes(input_type)))
21
22    return sorted(list(sizes)) if sizes is not None else None
23
24def get_const_field(type_):
25    if type_size(type_) == 1:
26        return 'b'
27    elif type_base_type(type_) == 'bool':
28        return 'i' + str(type_size(type_))
29    elif type_ == "float16":
30        return "u16"
31    else:
32        return type_base_type(type_)[0] + str(type_size(type_))
33
34template = """\
35/*
36 * Copyright (C) 2014 Intel Corporation
37 *
38 * Permission is hereby granted, free of charge, to any person obtaining a
39 * copy of this software and associated documentation files (the "Software"),
40 * to deal in the Software without restriction, including without limitation
41 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
42 * and/or sell copies of the Software, and to permit persons to whom the
43 * Software is furnished to do so, subject to the following conditions:
44 *
45 * The above copyright notice and this permission notice (including the next
46 * paragraph) shall be included in all copies or substantial portions of the
47 * Software.
48 *
49 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
50 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
51 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
52 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
53 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
54 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
55 * IN THE SOFTWARE.
56 *
57 * Authors:
58 *    Jason Ekstrand (jason@jlekstrand.net)
59 */
60
61#include <math.h>
62#include "util/rounding.h" /* for _mesa_roundeven */
63#include "util/half_float.h"
64#include "util/double.h"
65#include "util/softfloat.h"
66#include "util/bigmath.h"
67#include "nir_constant_expressions.h"
68
69/**
70 * \brief Checks if the provided value is a denorm and flushes it to zero.
71 */
72static void
73constant_denorm_flush_to_zero(nir_const_value *value, unsigned bit_size)
74{
75    switch(bit_size) {
76    case 64:
77        if (0 == (value->u64 & 0x7ff0000000000000))
78            value->u64 &= 0x8000000000000000;
79        break;
80    case 32:
81        if (0 == (value->u32 & 0x7f800000))
82            value->u32 &= 0x80000000;
83        break;
84    case 16:
85        if (0 == (value->u16 & 0x7c00))
86            value->u16 &= 0x8000;
87    }
88}
89
90/**
91 * Evaluate one component of packSnorm4x8.
92 */
93static uint8_t
94pack_snorm_1x8(float x)
95{
96    /* From section 8.4 of the GLSL 4.30 spec:
97     *
98     *    packSnorm4x8
99     *    ------------
100     *    The conversion for component c of v to fixed point is done as
101     *    follows:
102     *
103     *      packSnorm4x8: round(clamp(c, -1, +1) * 127.0)
104     *
105     * We must first cast the float to an int, because casting a negative
106     * float to a uint is undefined.
107     */
108   return (uint8_t) (int)
109          _mesa_roundevenf(CLAMP(x, -1.0f, +1.0f) * 127.0f);
110}
111
112/**
113 * Evaluate one component of packSnorm2x16.
114 */
115static uint16_t
116pack_snorm_1x16(float x)
117{
118    /* From section 8.4 of the GLSL ES 3.00 spec:
119     *
120     *    packSnorm2x16
121     *    -------------
122     *    The conversion for component c of v to fixed point is done as
123     *    follows:
124     *
125     *      packSnorm2x16: round(clamp(c, -1, +1) * 32767.0)
126     *
127     * We must first cast the float to an int, because casting a negative
128     * float to a uint is undefined.
129     */
130   return (uint16_t) (int)
131          _mesa_roundevenf(CLAMP(x, -1.0f, +1.0f) * 32767.0f);
132}
133
134/**
135 * Evaluate one component of unpackSnorm4x8.
136 */
137static float
138unpack_snorm_1x8(uint8_t u)
139{
140    /* From section 8.4 of the GLSL 4.30 spec:
141     *
142     *    unpackSnorm4x8
143     *    --------------
144     *    The conversion for unpacked fixed-point value f to floating point is
145     *    done as follows:
146     *
147     *       unpackSnorm4x8: clamp(f / 127.0, -1, +1)
148     */
149   return CLAMP((int8_t) u / 127.0f, -1.0f, +1.0f);
150}
151
152/**
153 * Evaluate one component of unpackSnorm2x16.
154 */
155static float
156unpack_snorm_1x16(uint16_t u)
157{
158    /* From section 8.4 of the GLSL ES 3.00 spec:
159     *
160     *    unpackSnorm2x16
161     *    ---------------
162     *    The conversion for unpacked fixed-point value f to floating point is
163     *    done as follows:
164     *
165     *       unpackSnorm2x16: clamp(f / 32767.0, -1, +1)
166     */
167   return CLAMP((int16_t) u / 32767.0f, -1.0f, +1.0f);
168}
169
170/**
171 * Evaluate one component packUnorm4x8.
172 */
173static uint8_t
174pack_unorm_1x8(float x)
175{
176    /* From section 8.4 of the GLSL 4.30 spec:
177     *
178     *    packUnorm4x8
179     *    ------------
180     *    The conversion for component c of v to fixed point is done as
181     *    follows:
182     *
183     *       packUnorm4x8: round(clamp(c, 0, +1) * 255.0)
184     */
185   return (uint8_t) (int)
186          _mesa_roundevenf(CLAMP(x, 0.0f, 1.0f) * 255.0f);
187}
188
189/**
190 * Evaluate one component packUnorm2x16.
191 */
192static uint16_t
193pack_unorm_1x16(float x)
194{
195    /* From section 8.4 of the GLSL ES 3.00 spec:
196     *
197     *    packUnorm2x16
198     *    -------------
199     *    The conversion for component c of v to fixed point is done as
200     *    follows:
201     *
202     *       packUnorm2x16: round(clamp(c, 0, +1) * 65535.0)
203     */
204   return (uint16_t) (int)
205          _mesa_roundevenf(CLAMP(x, 0.0f, 1.0f) * 65535.0f);
206}
207
208/**
209 * Evaluate one component of unpackUnorm4x8.
210 */
211static float
212unpack_unorm_1x8(uint8_t u)
213{
214    /* From section 8.4 of the GLSL 4.30 spec:
215     *
216     *    unpackUnorm4x8
217     *    --------------
218     *    The conversion for unpacked fixed-point value f to floating point is
219     *    done as follows:
220     *
221     *       unpackUnorm4x8: f / 255.0
222     */
223   return (float) u / 255.0f;
224}
225
226/**
227 * Evaluate one component of unpackUnorm2x16.
228 */
229static float
230unpack_unorm_1x16(uint16_t u)
231{
232    /* From section 8.4 of the GLSL ES 3.00 spec:
233     *
234     *    unpackUnorm2x16
235     *    ---------------
236     *    The conversion for unpacked fixed-point value f to floating point is
237     *    done as follows:
238     *
239     *       unpackUnorm2x16: f / 65535.0
240     */
241   return (float) u / 65535.0f;
242}
243
244/**
245 * Evaluate one component of packHalf2x16.
246 */
247static uint16_t
248pack_half_1x16(float x)
249{
250   return _mesa_float_to_half(x);
251}
252
253/**
254 * Evaluate one component of unpackHalf2x16.
255 */
256static float
257unpack_half_1x16_flush_to_zero(uint16_t u)
258{
259   if (0 == (u & 0x7c00))
260      u &= 0x8000;
261   return _mesa_half_to_float(u);
262}
263
264/**
265 * Evaluate one component of unpackHalf2x16.
266 */
267static float
268unpack_half_1x16(uint16_t u)
269{
270   return _mesa_half_to_float(u);
271}
272
273/* Some typed vector structures to make things like src0.y work */
274typedef int8_t int1_t;
275typedef uint8_t uint1_t;
276typedef float float16_t;
277typedef float float32_t;
278typedef double float64_t;
279typedef bool bool1_t;
280typedef bool bool8_t;
281typedef bool bool16_t;
282typedef bool bool32_t;
283typedef bool bool64_t;
284% for type in ["float", "int", "uint", "bool"]:
285% for width in type_sizes(type):
286struct ${type}${width}_vec {
287   ${type}${width}_t x;
288   ${type}${width}_t y;
289   ${type}${width}_t z;
290   ${type}${width}_t w;
291   ${type}${width}_t e;
292   ${type}${width}_t f;
293   ${type}${width}_t g;
294   ${type}${width}_t h;
295   ${type}${width}_t i;
296   ${type}${width}_t j;
297   ${type}${width}_t k;
298   ${type}${width}_t l;
299   ${type}${width}_t m;
300   ${type}${width}_t n;
301   ${type}${width}_t o;
302   ${type}${width}_t p;
303};
304% endfor
305% endfor
306
307<%def name="evaluate_op(op, bit_size, execution_mode)">
308   <%
309   output_type = type_add_size(op.output_type, bit_size)
310   input_types = [type_add_size(type_, bit_size) for type_ in op.input_types]
311   %>
312
313   ## For each non-per-component input, create a variable srcN that
314   ## contains x, y, z, and w elements which are filled in with the
315   ## appropriately-typed values.
316   % for j in range(op.num_inputs):
317      % if op.input_sizes[j] == 0:
318         <% continue %>
319      % elif "src" + str(j) not in op.const_expr:
320         ## Avoid unused variable warnings
321         <% continue %>
322      %endif
323
324      const struct ${input_types[j]}_vec src${j} = {
325      % for k in range(op.input_sizes[j]):
326         % if input_types[j] == "int1":
327             /* 1-bit integers use a 0/-1 convention */
328             -(int1_t)_src[${j}][${k}].b,
329         % elif input_types[j] == "float16":
330            _mesa_half_to_float(_src[${j}][${k}].u16),
331         % else:
332            _src[${j}][${k}].${get_const_field(input_types[j])},
333         % endif
334      % endfor
335      % for k in range(op.input_sizes[j], 16):
336         0,
337      % endfor
338      };
339   % endfor
340
341   % if op.output_size == 0:
342      ## For per-component instructions, we need to iterate over the
343      ## components and apply the constant expression one component
344      ## at a time.
345      for (unsigned _i = 0; _i < num_components; _i++) {
346         ## For each per-component input, create a variable srcN that
347         ## contains the value of the current (_i'th) component.
348         % for j in range(op.num_inputs):
349            % if op.input_sizes[j] != 0:
350               <% continue %>
351            % elif "src" + str(j) not in op.const_expr:
352               ## Avoid unused variable warnings
353               <% continue %>
354            % elif input_types[j] == "int1":
355               /* 1-bit integers use a 0/-1 convention */
356               const int1_t src${j} = -(int1_t)_src[${j}][_i].b;
357            % elif input_types[j] == "float16":
358               const float src${j} =
359                  _mesa_half_to_float(_src[${j}][_i].u16);
360            % else:
361               const ${input_types[j]}_t src${j} =
362                  _src[${j}][_i].${get_const_field(input_types[j])};
363            % endif
364         % endfor
365
366         ## Create an appropriately-typed variable dst and assign the
367         ## result of the const_expr to it.  If const_expr already contains
368         ## writes to dst, just include const_expr directly.
369         % if "dst" in op.const_expr:
370            ${output_type}_t dst;
371
372            ${op.const_expr}
373         % else:
374            ${output_type}_t dst = ${op.const_expr};
375         % endif
376
377         ## Store the current component of the actual destination to the
378         ## value of dst.
379         % if output_type == "int1" or output_type == "uint1":
380            /* 1-bit integers get truncated */
381            _dst_val[_i].b = dst & 1;
382         % elif output_type.startswith("bool"):
383            ## Sanitize the C value to a proper NIR 0/-1 bool
384            _dst_val[_i].${get_const_field(output_type)} = -(int)dst;
385         % elif output_type == "float16":
386            if (nir_is_rounding_mode_rtz(execution_mode, 16)) {
387               _dst_val[_i].u16 = _mesa_float_to_float16_rtz(dst);
388            } else {
389               _dst_val[_i].u16 = _mesa_float_to_float16_rtne(dst);
390            }
391         % else:
392            _dst_val[_i].${get_const_field(output_type)} = dst;
393         % endif
394
395         % if op.name != "fquantize2f16" and type_base_type(output_type) == "float":
396            % if type_has_size(output_type):
397               if (nir_is_denorm_flush_to_zero(execution_mode, ${type_size(output_type)})) {
398                  constant_denorm_flush_to_zero(&_dst_val[_i], ${type_size(output_type)});
399               }
400            % else:
401               if (nir_is_denorm_flush_to_zero(execution_mode, ${bit_size})) {
402                  constant_denorm_flush_to_zero(&_dst_val[i], bit_size);
403               }
404            %endif
405         % endif
406      }
407   % else:
408      ## In the non-per-component case, create a struct dst with
409      ## appropriately-typed elements x, y, z, and w and assign the result
410      ## of the const_expr to all components of dst, or include the
411      ## const_expr directly if it writes to dst already.
412      struct ${output_type}_vec dst;
413
414      % if "dst" in op.const_expr:
415         ${op.const_expr}
416      % else:
417         ## Splat the value to all components.  This way expressions which
418         ## write the same value to all components don't need to explicitly
419         ## write to dest.
420         dst.x = dst.y = dst.z = dst.w = ${op.const_expr};
421      % endif
422
423      ## For each component in the destination, copy the value of dst to
424      ## the actual destination.
425      % for k in range(op.output_size):
426         % if output_type == "int1" or output_type == "uint1":
427            /* 1-bit integers get truncated */
428            _dst_val[${k}].b = dst.${"xyzwefghijklmnop"[k]} & 1;
429         % elif output_type.startswith("bool"):
430            ## Sanitize the C value to a proper NIR 0/-1 bool
431            _dst_val[${k}].${get_const_field(output_type)} = -(int)dst.${"xyzwefghijklmnop"[k]};
432         % elif output_type == "float16":
433            if (nir_is_rounding_mode_rtz(execution_mode, 16)) {
434               _dst_val[${k}].u16 = _mesa_float_to_float16_rtz(dst.${"xyzwefghijklmnop"[k]});
435            } else {
436               _dst_val[${k}].u16 = _mesa_float_to_float16_rtne(dst.${"xyzwefghijklmnop"[k]});
437            }
438         % else:
439            _dst_val[${k}].${get_const_field(output_type)} = dst.${"xyzwefghijklmnop"[k]};
440         % endif
441
442         % if op.name != "fquantize2f16" and type_base_type(output_type) == "float":
443            % if type_has_size(output_type):
444               if (nir_is_denorm_flush_to_zero(execution_mode, ${type_size(output_type)})) {
445                  constant_denorm_flush_to_zero(&_dst_val[${k}], ${type_size(output_type)});
446               }
447            % else:
448               if (nir_is_denorm_flush_to_zero(execution_mode, ${bit_size})) {
449                  constant_denorm_flush_to_zero(&_dst_val[${k}], bit_size);
450               }
451            % endif
452         % endif
453      % endfor
454   % endif
455</%def>
456
457% for name, op in sorted(opcodes.items()):
458% if op.name == "fsat":
459#if defined(_MSC_VER) && (defined(_M_ARM64) || defined(_M_ARM64EC))
460#pragma optimize("", off) /* Temporary work-around for MSVC compiler bug, present in VS2019 16.9.2 */
461#endif
462% endif
463static void
464evaluate_${name}(nir_const_value *_dst_val,
465                 UNUSED unsigned num_components,
466                 ${"UNUSED" if op_bit_sizes(op) is None else ""} unsigned bit_size,
467                 UNUSED nir_const_value **_src,
468                 UNUSED unsigned execution_mode)
469{
470   % if op_bit_sizes(op) is not None:
471      switch (bit_size) {
472      % for bit_size in op_bit_sizes(op):
473      case ${bit_size}: {
474         ${evaluate_op(op, bit_size, execution_mode)}
475         break;
476      }
477      % endfor
478
479      default:
480         unreachable("unknown bit width");
481      }
482   % else:
483      ${evaluate_op(op, 0, execution_mode)}
484   % endif
485}
486% if op.name == "fsat":
487#if defined(_MSC_VER) && (defined(_M_ARM64) || defined(_M_ARM64EC))
488#pragma optimize("", on) /* Temporary work-around for MSVC compiler bug, present in VS2019 16.9.2 */
489#endif
490% endif
491% endfor
492
493void
494nir_eval_const_opcode(nir_op op, nir_const_value *dest,
495                      unsigned num_components, unsigned bit_width,
496                      nir_const_value **src,
497                      unsigned float_controls_execution_mode)
498{
499   switch (op) {
500% for name in sorted(opcodes.keys()):
501   case nir_op_${name}:
502      evaluate_${name}(dest, num_components, bit_width, src, float_controls_execution_mode);
503      return;
504% endfor
505   default:
506      unreachable("shouldn't get here");
507   }
508}"""
509
510from mako.template import Template
511
512print(Template(template).render(opcodes=opcodes, type_sizes=type_sizes,
513                                type_base_type=type_base_type,
514                                type_size=type_size,
515                                type_has_size=type_has_size,
516                                type_add_size=type_add_size,
517                                op_bit_sizes=op_bit_sizes,
518                                get_const_field=get_const_field))
519