3 # Copyright (C) 2014 Connor Abbott
5 # Permission is hereby granted, free of charge, to any person obtaining a
6 # copy of this software and associated documentation files (the "Software"),
7 # to deal in the Software without restriction, including without limitation
8 # the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 # and/or sell copies of the Software, and to permit persons to whom the
10 # Software is furnished to do so, subject to the following conditions:
12 # The above copyright notice and this permission notice (including the next
13 # paragraph) shall be included in all copies or substantial portions of the
16 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
25 # Connor Abbott (cwabbott0@gmail.com)
28 # Class that represents all the information we have about the opcode
29 # NOTE: this must be kept in sync with nir_op_info
32 """Class that represents all the information we have about the opcode
33 NOTE: this must be kept in sync with nir_op_info
35 def __init__(self
, name
, output_size
, output_type
, input_sizes
,
36 input_types
, algebraic_properties
, const_expr
):
39 - name is the name of the opcode (prepend nir_op_ for the enum name)
40 - all types are strings that get nir_type_ prepended to them
41 - input_types is a list of types
42 - algebraic_properties is a space-seperated string, where nir_op_is_ is
43 prepended before each entry
44 - const_expr is an expression or series of statements that computes the
45 constant value of the opcode given the constant values of its inputs.
47 Constant expressions are formed from the variables src0, src1, ...,
48 src(N-1), where N is the number of arguments. The output of the
49 expression should be stored in the dst variable. Per-component input
50 and output variables will be scalars and non-per-component input and
51 output variables will be a struct with fields named x, y, z, and w
52 all of the correct type. Input and output variables can be assumed
53 to already be of the correct type and need no conversion. In
54 particular, the conversion from the C bool type to/from NIR_TRUE and
55 NIR_FALSE happens automatically.
57 For per-component instructions, the entire expression will be
58 executed once for each component. For non-per-component
59 instructions, the expression is expected to store the correct values
60 in dst.x, dst.y, etc. If "dst" does not exist anywhere in the
61 constant expression, an assignment to dst will happen automatically
62 and the result will be equivalent to "dst = <expression>" for
63 per-component instructions and "dst.x = dst.y = ... = <expression>"
64 for non-per-component instructions.
66 assert isinstance(name
, str)
67 assert isinstance(output_size
, int)
68 assert isinstance(output_type
, str)
69 assert isinstance(input_sizes
, list)
70 assert isinstance(input_sizes
[0], int)
71 assert isinstance(input_types
, list)
72 assert isinstance(input_types
[0], str)
73 assert isinstance(algebraic_properties
, str)
74 assert isinstance(const_expr
, str)
75 assert len(input_sizes
) == len(input_types
)
76 assert 0 <= output_size
<= 4
77 for size
in input_sizes
:
82 self
.num_inputs
= len(input_sizes
)
83 self
.output_size
= output_size
84 self
.output_type
= output_type
85 self
.input_sizes
= input_sizes
86 self
.input_types
= input_types
87 self
.algebraic_properties
= algebraic_properties
88 self
.const_expr
= const_expr
90 # helper variables for strings
101 commutative
= "commutative "
102 associative
= "associative "
104 # global dictionary of opcodes
107 def opcode(name
, output_size
, output_type
, input_sizes
, input_types
,
108 algebraic_properties
, const_expr
):
109 assert name
not in opcodes
110 opcodes
[name
] = Opcode(name
, output_size
, output_type
, input_sizes
,
111 input_types
, algebraic_properties
, const_expr
)
113 def unop_convert(name
, out_type
, in_type
, const_expr
):
114 opcode(name
, 0, out_type
, [0], [in_type
], "", const_expr
)
116 def unop(name
, ty
, const_expr
):
117 opcode(name
, 0, ty
, [0], [ty
], "", const_expr
)
119 def unop_horiz(name
, output_size
, output_type
, input_size
, input_type
,
121 opcode(name
, output_size
, output_type
, [input_size
], [input_type
], "",
124 def unop_reduce(name
, output_size
, output_type
, input_type
, prereduce_expr
,
125 reduce_expr
, final_expr
):
127 return "(" + prereduce_expr
.format(src
=src
) + ")"
129 return final_expr
.format(src
="(" + src
+ ")")
130 def reduce_(src0
, src1
):
131 return reduce_expr
.format(src0
=src0
, src1
=src1
)
132 src0
= prereduce("src0.x")
133 src1
= prereduce("src0.y")
134 src2
= prereduce("src0.z")
135 src3
= prereduce("src0.w")
136 unop_horiz(name
+ "2", output_size
, output_type
, 2, input_type
,
137 final(reduce_(src0
, src1
)))
138 unop_horiz(name
+ "3", output_size
, output_type
, 3, input_type
,
139 final(reduce_(reduce_(src0
, src1
), src2
)))
140 unop_horiz(name
+ "4", output_size
, output_type
, 4, input_type
,
141 final(reduce_(reduce_(src0
, src1
), reduce_(src2
, src3
))))
144 # These two move instructions differ in what modifiers they support and what
145 # the negate modifier means. Otherwise, they are identical.
146 unop("fmov", tfloat
, "src0")
147 unop("imov", tint
, "src0")
149 unop("ineg", tint
, "-src0")
150 unop("fneg", tfloat
, "-src0")
151 unop("inot", tint
, "~src0") # invert every bit of the integer
152 unop("fnot", tfloat
, "(src0 == 0.0f) ? 1.0f : 0.0f")
153 unop("fsign", tfloat
, "(src0 == 0.0f) ? 0.0f : ((src0 > 0.0f) ? 1.0f : -1.0f)")
154 unop("isign", tint
, "(src0 == 0) ? 0 : ((src0 > 0) ? 1 : -1)")
155 unop("iabs", tint
, "(src0 < 0) ? -src0 : src0")
156 unop("fabs", tfloat
, "fabsf(src0)")
157 unop("fsat", tfloat
, "(src0 > 1.0f) ? 1.0f : ((src0 <= 0.0f) ? 0.0f : src0)")
158 unop("frcp", tfloat
, "1.0f / src0")
159 unop("frsq", tfloat
, "1.0f / sqrtf(src0)")
160 unop("fsqrt", tfloat
, "sqrtf(src0)")
161 unop("fexp2", tfloat
, "exp2f(src0)")
162 unop("flog2", tfloat
, "log2f(src0)")
163 unop_convert("f2i", tint32
, tfloat32
, "src0") # Float-to-integer conversion.
164 unop_convert("f2u", tuint32
, tfloat32
, "src0") # Float-to-unsigned conversion
165 unop_convert("d2i", tint32
, tfloat64
, "src0") # Double-to-integer conversion.
166 unop_convert("d2u", tuint32
, tfloat64
, "src0") # Double-to-unsigned conversion.
167 unop_convert("i2f", tfloat32
, tint32
, "src0") # Integer-to-float conversion.
168 unop_convert("i2d", tfloat64
, tint32
, "src0") # Integer-to-double conversion.
169 # Float-to-boolean conversion
170 unop_convert("f2b", tbool
, tfloat32
, "src0 != 0.0f")
171 unop_convert("d2b", tbool
, tfloat64
, "src0 != 0.0")
172 # Boolean-to-float conversion
173 unop_convert("b2f", tfloat32
, tbool
, "src0 ? 1.0f : 0.0f")
174 # Int-to-boolean conversion
175 unop_convert("i2b", tbool
, tint32
, "src0 != 0")
176 unop_convert("b2i", tint32
, tbool
, "src0 ? 1 : 0") # Boolean-to-int conversion
177 unop_convert("u2f", tfloat32
, tuint32
, "src0") # Unsigned-to-float conversion.
178 unop_convert("u2d", tfloat64
, tuint32
, "src0") # Unsigned-to-double conversion.
179 # double-to-float conversion
180 unop_convert("d2f", tfloat32
, tfloat64
, "src0") # Single to double precision
181 unop_convert("f2d", tfloat64
, tfloat32
, "src0") # Double to single precision
183 # Unary floating-point rounding operations.
186 unop("ftrunc", tfloat
, "bit_size == 64 ? trunc(src0) : truncf(src0)")
187 unop("fceil", tfloat
, "bit_size == 64 ? ceil(src0) : ceilf(src0)")
188 unop("ffloor", tfloat
, "bit_size == 64 ? floor(src0) : floorf(src0)")
189 unop("ffract", tfloat
, "src0 - (bit_size == 64 ? floor(src0) : floorf(src0))")
190 unop("fround_even", tfloat
, "bit_size == 64 ? _mesa_roundeven(src0) : _mesa_roundevenf(src0)")
192 unop("fquantize2f16", tfloat
, "(fabs(src0) < ldexpf(1.0, -14)) ? copysignf(0.0f, src0) : _mesa_half_to_float(_mesa_float_to_half(src0))")
194 # Trigonometric operations.
197 unop("fsin", tfloat
, "bit_size == 64 ? sin(src0) : sinf(src0)")
198 unop("fcos", tfloat
, "bit_size == 64 ? cos(src0) : cosf(src0)")
201 # Partial derivatives.
204 unop("fddx", tfloat
, "0.0") # the derivative of a constant is 0.
205 unop("fddy", tfloat
, "0.0")
206 unop("fddx_fine", tfloat
, "0.0")
207 unop("fddy_fine", tfloat
, "0.0")
208 unop("fddx_coarse", tfloat
, "0.0")
209 unop("fddy_coarse", tfloat
, "0.0")
212 # Floating point pack and unpack operations.
215 unop_horiz("pack_" + fmt
+ "_2x16", 1, tuint32
, 2, tfloat32
, """
216 dst.x = (uint32_t) pack_fmt_1x16(src0.x);
217 dst.x |= ((uint32_t) pack_fmt_1x16(src0.y)) << 16;
218 """.replace("fmt", fmt
))
221 unop_horiz("pack_" + fmt
+ "_4x8", 1, tuint32
, 4, tfloat32
, """
222 dst.x = (uint32_t) pack_fmt_1x8(src0.x);
223 dst.x |= ((uint32_t) pack_fmt_1x8(src0.y)) << 8;
224 dst.x |= ((uint32_t) pack_fmt_1x8(src0.z)) << 16;
225 dst.x |= ((uint32_t) pack_fmt_1x8(src0.w)) << 24;
226 """.replace("fmt", fmt
))
228 def unpack_2x16(fmt
):
229 unop_horiz("unpack_" + fmt
+ "_2x16", 2, tfloat32
, 1, tuint32
, """
230 dst.x = unpack_fmt_1x16((uint16_t)(src0.x & 0xffff));
231 dst.y = unpack_fmt_1x16((uint16_t)(src0.x << 16));
232 """.replace("fmt", fmt
))
235 unop_horiz("unpack_" + fmt
+ "_4x8", 4, tfloat32
, 1, tuint32
, """
236 dst.x = unpack_fmt_1x8((uint8_t)(src0.x & 0xff));
237 dst.y = unpack_fmt_1x8((uint8_t)((src0.x >> 8) & 0xff));
238 dst.z = unpack_fmt_1x8((uint8_t)((src0.x >> 16) & 0xff));
239 dst.w = unpack_fmt_1x8((uint8_t)(src0.x >> 24));
240 """.replace("fmt", fmt
))
254 unop_horiz("pack_uvec2_to_uint", 1, tuint32
, 2, tuint32
, """
255 dst.x = (src0.x & 0xffff) | (src0.y >> 16);
258 unop_horiz("pack_uvec4_to_uint", 1, tuint32
, 4, tuint32
, """
259 dst.x = (src0.x << 0) |
265 unop_horiz("pack_double_2x32", 1, tuint64
, 2, tuint32
, """
279 unop_horiz("unpack_double_2x32", 2, tuint32
, 1, tuint64
, """
293 # Lowered floating point unpacking operations.
296 unop_horiz("unpack_half_2x16_split_x", 1, tfloat32
, 1, tuint32
,
297 "unpack_half_1x16((uint16_t)(src0.x & 0xffff))")
298 unop_horiz("unpack_half_2x16_split_y", 1, tfloat32
, 1, tuint32
,
299 "unpack_half_1x16((uint16_t)(src0.x >> 16))")
301 unop_convert("unpack_double_2x32_split_x", tuint32
, tuint64
, """
313 unop_convert("unpack_double_2x32_split_y", tuint32
, tuint64
, """
325 # Bit operations, part of ARB_gpu_shader5.
328 unop("bitfield_reverse", tuint32
, """
329 /* we're not winning any awards for speed here, but that's ok */
331 for (unsigned bit = 0; bit < 32; bit++)
332 dst |= ((src0 >> bit) & 1) << (31 - bit);
334 unop("bit_count", tuint32
, """
336 for (unsigned bit = 0; bit < 32; bit++) {
337 if ((src0 >> bit) & 1)
342 unop_convert("ufind_msb", tint32
, tuint32
, """
344 for (int bit = 31; bit > 0; bit--) {
345 if ((src0 >> bit) & 1) {
352 unop("ifind_msb", tint32
, """
354 for (int bit = 31; bit >= 0; bit--) {
355 /* If src0 < 0, we're looking for the first 0 bit.
356 * if src0 >= 0, we're looking for the first 1 bit.
358 if ((((src0 >> bit) & 1) && (src0 >= 0)) ||
359 (!((src0 >> bit) & 1) && (src0 < 0))) {
366 unop("find_lsb", tint32
, """
368 for (unsigned bit = 0; bit < 32; bit++) {
369 if ((src0 >> bit) & 1) {
377 for i
in xrange(1, 5):
378 for j
in xrange(1, 5):
379 unop_horiz("fnoise{0}_{1}".format(i
, j
), i
, tfloat
, j
, tfloat
, "0.0f")
381 def binop_convert(name
, out_type
, in_type
, alg_props
, const_expr
):
382 opcode(name
, 0, out_type
, [0, 0], [in_type
, in_type
], alg_props
, const_expr
)
384 def binop(name
, ty
, alg_props
, const_expr
):
385 binop_convert(name
, ty
, ty
, alg_props
, const_expr
)
387 def binop_compare(name
, ty
, alg_props
, const_expr
):
388 binop_convert(name
, tbool
, ty
, alg_props
, const_expr
)
390 def binop_horiz(name
, out_size
, out_type
, src1_size
, src1_type
, src2_size
,
391 src2_type
, const_expr
):
392 opcode(name
, out_size
, out_type
, [src1_size
, src2_size
], [src1_type
, src2_type
],
395 def binop_reduce(name
, output_size
, output_type
, src_type
, prereduce_expr
,
396 reduce_expr
, final_expr
):
398 return final_expr
.format(src
= "(" + src
+ ")")
399 def reduce_(src0
, src1
):
400 return reduce_expr
.format(src0
=src0
, src1
=src1
)
401 def prereduce(src0
, src1
):
402 return "(" + prereduce_expr
.format(src0
=src0
, src1
=src1
) + ")"
403 src0
= prereduce("src0.x", "src1.x")
404 src1
= prereduce("src0.y", "src1.y")
405 src2
= prereduce("src0.z", "src1.z")
406 src3
= prereduce("src0.w", "src1.w")
407 opcode(name
+ "2", output_size
, output_type
,
408 [2, 2], [src_type
, src_type
], commutative
,
409 final(reduce_(src0
, src1
)))
410 opcode(name
+ "3", output_size
, output_type
,
411 [3, 3], [src_type
, src_type
], commutative
,
412 final(reduce_(reduce_(src0
, src1
), src2
)))
413 opcode(name
+ "4", output_size
, output_type
,
414 [4, 4], [src_type
, src_type
], commutative
,
415 final(reduce_(reduce_(src0
, src1
), reduce_(src2
, src3
))))
417 binop("fadd", tfloat
, commutative
+ associative
, "src0 + src1")
418 binop("iadd", tint
, commutative
+ associative
, "src0 + src1")
419 binop("fsub", tfloat
, "", "src0 - src1")
420 binop("isub", tint
, "", "src0 - src1")
422 binop("fmul", tfloat
, commutative
+ associative
, "src0 * src1")
423 # low 32-bits of signed/unsigned integer multiply
424 binop("imul", tint
, commutative
+ associative
, "src0 * src1")
425 # high 32-bits of signed integer multiply
426 binop("imul_high", tint32
, commutative
,
427 "(int32_t)(((int64_t) src0 * (int64_t) src1) >> 32)")
428 # high 32-bits of unsigned integer multiply
429 binop("umul_high", tuint32
, commutative
,
430 "(uint32_t)(((uint64_t) src0 * (uint64_t) src1) >> 32)")
432 binop("fdiv", tfloat
, "", "src0 / src1")
433 binop("idiv", tint
, "", "src0 / src1")
434 binop("udiv", tuint
, "", "src0 / src1")
436 # returns a boolean representing the carry resulting from the addition of
437 # the two unsigned arguments.
439 binop_convert("uadd_carry", tuint
, tuint
, commutative
, "src0 + src1 < src0")
441 # returns a boolean representing the borrow resulting from the subtraction
442 # of the two unsigned arguments.
444 binop_convert("usub_borrow", tuint
, tuint
, "", "src0 < src1")
446 binop("fmod", tfloat
, "", "src0 - src1 * floorf(src0 / src1)")
447 binop("umod", tuint
, "", "src1 == 0 ? 0 : src0 % src1")
454 # these integer-aware comparisons return a boolean (0 or ~0)
456 binop_compare("flt", tfloat
, "", "src0 < src1")
457 binop_compare("fge", tfloat
, "", "src0 >= src1")
458 binop_compare("feq", tfloat
, commutative
, "src0 == src1")
459 binop_compare("fne", tfloat
, commutative
, "src0 != src1")
460 binop_compare("ilt", tint
, "", "src0 < src1")
461 binop_compare("ige", tint
, "", "src0 >= src1")
462 binop_compare("ieq", tint
, commutative
, "src0 == src1")
463 binop_compare("ine", tint
, commutative
, "src0 != src1")
464 binop_compare("ult", tuint
, "", "src0 < src1")
465 binop_compare("uge", tuint
, "", "src0 >= src1")
467 # integer-aware GLSL-style comparisons that compare floats and ints
469 binop_reduce("ball_fequal", 1, tbool
, tfloat
, "{src0} == {src1}",
470 "{src0} && {src1}", "{src}")
471 binop_reduce("bany_fnequal", 1, tbool
, tfloat
, "{src0} != {src1}",
472 "{src0} || {src1}", "{src}")
473 binop_reduce("ball_iequal", 1, tbool
, tint
, "{src0} == {src1}",
474 "{src0} && {src1}", "{src}")
475 binop_reduce("bany_inequal", 1, tbool
, tint
, "{src0} != {src1}",
476 "{src0} || {src1}", "{src}")
478 # non-integer-aware GLSL-style comparisons that return 0.0 or 1.0
480 binop_reduce("fall_equal", 1, tfloat32
, tfloat32
, "{src0} == {src1}",
481 "{src0} && {src1}", "{src} ? 1.0f : 0.0f")
482 binop_reduce("fany_nequal", 1, tfloat32
, tfloat32
, "{src0} != {src1}",
483 "{src0} || {src1}", "{src} ? 1.0f : 0.0f")
485 # These comparisons for integer-less hardware return 1.0 and 0.0 for true
486 # and false respectively
488 binop("slt", tfloat32
, "", "(src0 < src1) ? 1.0f : 0.0f") # Set on Less Than
489 binop("sge", tfloat32
, "", "(src0 >= src1) ? 1.0f : 0.0f") # Set on Greater or Equal
490 binop("seq", tfloat32
, commutative
, "(src0 == src1) ? 1.0f : 0.0f") # Set on Equal
491 binop("sne", tfloat32
, commutative
, "(src0 != src1) ? 1.0f : 0.0f") # Set on Not Equal
494 binop("ishl", tint
, "", "src0 << src1")
495 binop("ishr", tint
, "", "src0 >> src1")
496 binop("ushr", tuint
, "", "src0 >> src1")
498 # bitwise logic operators
500 # These are also used as boolean and, or, xor for hardware supporting
504 binop("iand", tuint
, commutative
+ associative
, "src0 & src1")
505 binop("ior", tuint
, commutative
+ associative
, "src0 | src1")
506 binop("ixor", tuint
, commutative
+ associative
, "src0 ^ src1")
509 # floating point logic operators
511 # These use (src != 0.0) for testing the truth of the input, and output 1.0
512 # for true and 0.0 for false
514 binop("fand", tfloat32
, commutative
,
515 "((src0 != 0.0f) && (src1 != 0.0f)) ? 1.0f : 0.0f")
516 binop("for", tfloat32
, commutative
,
517 "((src0 != 0.0f) || (src1 != 0.0f)) ? 1.0f : 0.0f")
518 binop("fxor", tfloat32
, commutative
,
519 "(src0 != 0.0f && src1 == 0.0f) || (src0 == 0.0f && src1 != 0.0f) ? 1.0f : 0.0f")
521 binop_reduce("fdot", 1, tfloat
, tfloat
, "{src0} * {src1}", "{src0} + {src1}",
524 binop_reduce("fdot_replicated", 4, tfloat
, tfloat
,
525 "{src0} * {src1}", "{src0} + {src1}", "{src}")
527 opcode("fdph", 1, tfloat
, [3, 4], [tfloat
, tfloat
], "",
528 "src0.x * src1.x + src0.y * src1.y + src0.z * src1.z + src1.w")
529 opcode("fdph_replicated", 4, tfloat
, [3, 4], [tfloat
, tfloat
], "",
530 "src0.x * src1.x + src0.y * src1.y + src0.z * src1.z + src1.w")
532 binop("fmin", tfloat
, "", "fminf(src0, src1)")
533 binop("imin", tint
, commutative
+ associative
, "src1 > src0 ? src0 : src1")
534 binop("umin", tuint
, commutative
+ associative
, "src1 > src0 ? src0 : src1")
535 binop("fmax", tfloat
, "", "fmaxf(src0, src1)")
536 binop("imax", tint
, commutative
+ associative
, "src1 > src0 ? src1 : src0")
537 binop("umax", tuint
, commutative
+ associative
, "src1 > src0 ? src1 : src0")
539 # Saturated vector add for 4 8bit ints.
540 binop("usadd_4x8", tint32
, commutative
+ associative
, """
542 for (int i = 0; i < 32; i += 8) {
543 dst |= MIN2(((src0 >> i) & 0xff) + ((src1 >> i) & 0xff), 0xff) << i;
547 # Saturated vector subtract for 4 8bit ints.
548 binop("ussub_4x8", tint32
, "", """
550 for (int i = 0; i < 32; i += 8) {
551 int src0_chan = (src0 >> i) & 0xff;
552 int src1_chan = (src1 >> i) & 0xff;
553 if (src0_chan > src1_chan)
554 dst |= (src0_chan - src1_chan) << i;
558 # vector min for 4 8bit ints.
559 binop("umin_4x8", tint32
, commutative
+ associative
, """
561 for (int i = 0; i < 32; i += 8) {
562 dst |= MIN2((src0 >> i) & 0xff, (src1 >> i) & 0xff) << i;
566 # vector max for 4 8bit ints.
567 binop("umax_4x8", tint32
, commutative
+ associative
, """
569 for (int i = 0; i < 32; i += 8) {
570 dst |= MAX2((src0 >> i) & 0xff, (src1 >> i) & 0xff) << i;
574 # unorm multiply: (a * b) / 255.
575 binop("umul_unorm_4x8", tint32
, commutative
+ associative
, """
577 for (int i = 0; i < 32; i += 8) {
578 int src0_chan = (src0 >> i) & 0xff;
579 int src1_chan = (src1 >> i) & 0xff;
580 dst |= ((src0_chan * src1_chan) / 255) << i;
584 binop("fpow", tfloat
, "", "bit_size == 64 ? powf(src0, src1) : pow(src0, src1)")
586 binop_horiz("pack_half_2x16_split", 1, tuint32
, 1, tfloat32
, 1, tfloat32
,
587 "pack_half_1x16(src0.x) | (pack_half_1x16(src1.x) << 16)")
589 binop_convert("pack_double_2x32_split", tuint64
, tuint32
, "", """
602 # bfm implements the behavior of the first operation of the SM5 "bfi" assembly
603 # and that of the "bfi1" i965 instruction. That is, it has undefined behavior
604 # if either of its arguments are 32.
605 binop_convert("bfm", tuint32
, tint32
, "", """
606 int bits = src0, offset = src1;
607 if (offset < 0 || bits < 0 || offset > 31 || bits > 31 || offset + bits > 32)
608 dst = 0; /* undefined */
610 dst = ((1u << bits) - 1) << offset;
613 opcode("ldexp", 0, tfloat
, [0, 0], [tfloat
, tint
], "", """
614 dst = (bit_size == 64) ? ldexp(src0, src1) : ldexpf(src0, src1);
615 /* flush denormals to zero. */
617 dst = copysignf(0.0f, src0);
620 # Combines the first component of each input to make a 2-component vector.
622 binop_horiz("vec2", 2, tuint
, 1, tuint
, 1, tuint
, """
628 binop("extract_u8", tuint
, "", "(uint8_t)(src0 >> (src1 * 8))")
629 binop("extract_i8", tint
, "", "(int8_t)(src0 >> (src1 * 8))")
632 binop("extract_u16", tuint
, "", "(uint16_t)(src0 >> (src1 * 16))")
633 binop("extract_i16", tint
, "", "(int16_t)(src0 >> (src1 * 16))")
636 def triop(name
, ty
, const_expr
):
637 opcode(name
, 0, ty
, [0, 0, 0], [ty
, ty
, ty
], "", const_expr
)
638 def triop_horiz(name
, output_size
, src1_size
, src2_size
, src3_size
, const_expr
):
639 opcode(name
, output_size
, tuint
,
640 [src1_size
, src2_size
, src3_size
],
641 [tuint
, tuint
, tuint
], "", const_expr
)
643 triop("ffma", tfloat
, "src0 * src1 + src2")
645 triop("flrp", tfloat
, "src0 * (1 - src2) + src1 * src2")
649 # A vector conditional select instruction (like ?:, but operating per-
650 # component on vectors). There are two versions, one for floating point
651 # bools (0.0 vs 1.0) and one for integer bools (0 vs ~0).
654 triop("fcsel", tfloat32
, "(src0 != 0.0f) ? src1 : src2")
655 opcode("bcsel", 0, tuint
, [0, 0, 0],
656 [tbool
, tuint
, tuint
], "", "src0 ? src1 : src2")
659 triop("bfi", tuint32
, """
660 unsigned mask = src0, insert = src1, base = src2;
669 dst = (base & ~mask) | (insert & mask);
673 # SM5 ubfe/ibfe assembly
674 opcode("ubfe", 0, tuint32
,
675 [0, 0, 0], [tuint32
, tint32
, tint32
], "", """
676 unsigned base = src0;
677 int offset = src1, bits = src2;
680 } else if (bits < 0 || offset < 0) {
681 dst = 0; /* undefined */
682 } else if (offset + bits < 32) {
683 dst = (base << (32 - bits - offset)) >> (32 - bits);
685 dst = base >> offset;
688 opcode("ibfe", 0, tint32
,
689 [0, 0, 0], [tint32
, tint32
, tint32
], "", """
691 int offset = src1, bits = src2;
694 } else if (bits < 0 || offset < 0) {
695 dst = 0; /* undefined */
696 } else if (offset + bits < 32) {
697 dst = (base << (32 - bits - offset)) >> (32 - bits);
699 dst = base >> offset;
703 # GLSL bitfieldExtract()
704 opcode("ubitfield_extract", 0, tuint32
,
705 [0, 0, 0], [tuint32
, tint32
, tint32
], "", """
706 unsigned base = src0;
707 int offset = src1, bits = src2;
710 } else if (bits < 0 || offset < 0 || offset + bits > 32) {
711 dst = 0; /* undefined per the spec */
713 dst = (base >> offset) & ((1ull << bits) - 1);
716 opcode("ibitfield_extract", 0, tint32
,
717 [0, 0, 0], [tint32
, tint32
, tint32
], "", """
719 int offset = src1, bits = src2;
722 } else if (offset < 0 || bits < 0 || offset + bits > 32) {
725 dst = (base << (32 - offset - bits)) >> offset; /* use sign-extending shift */
729 # Combines the first component of each input to make a 3-component vector.
731 triop_horiz("vec3", 3, 1, 1, 1, """
737 def quadop_horiz(name
, output_size
, src1_size
, src2_size
, src3_size
,
738 src4_size
, const_expr
):
739 opcode(name
, output_size
, tuint
,
740 [src1_size
, src2_size
, src3_size
, src4_size
],
741 [tuint
, tuint
, tuint
, tuint
],
744 opcode("bitfield_insert", 0, tuint32
, [0, 0, 0, 0],
745 [tuint32
, tuint32
, tint32
, tint32
], "", """
746 unsigned base = src0, insert = src1;
747 int offset = src2, bits = src3;
750 } else if (offset < 0 || bits < 0 || bits + offset > 32) {
753 unsigned mask = ((1ull << bits) - 1) << offset;
754 dst = (base & ~mask) | ((insert << bits) & mask);
758 quadop_horiz("vec4", 4, 1, 1, 1, 1, """