2 # Copyright (C) 2014 Connor Abbott
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:
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
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
24 # Connor Abbott (cwabbott0@gmail.com)
27 # Class that represents all the information we have about the opcode
28 # NOTE: this must be kept in sync with nir_op_info
31 """Class that represents all the information we have about the opcode
32 NOTE: this must be kept in sync with nir_op_info
34 def __init__(self
, name
, output_size
, output_type
, input_sizes
,
35 input_types
, algebraic_properties
, const_expr
):
38 - name is the name of the opcode (prepend nir_op_ for the enum name)
39 - all types are strings that get nir_type_ prepended to them
40 - input_types is a list of types
41 - algebraic_properties is a space-seperated string, where nir_op_is_ is
42 prepended before each entry
43 - const_expr is an expression or series of statements that computes the
44 constant value of the opcode given the constant values of its inputs.
46 Constant expressions are formed from the variables src0, src1, ...,
47 src(N-1), where N is the number of arguments. The output of the
48 expression should be stored in the dst variable. Per-component input
49 and output variables will be scalars and non-per-component input and
50 output variables will be a struct with fields named x, y, z, and w
51 all of the correct type. Input and output variables can be assumed
52 to already be of the correct type and need no conversion. In
53 particular, the conversion from the C bool type to/from NIR_TRUE and
54 NIR_FALSE happens automatically.
56 For per-component instructions, the entire expression will be
57 executed once for each component. For non-per-component
58 instructions, the expression is expected to store the correct values
59 in dst.x, dst.y, etc. If "dst" does not exist anywhere in the
60 constant expression, an assignment to dst will happen automatically
61 and the result will be equivalent to "dst = <expression>" for
62 per-component instructions and "dst.x = dst.y = ... = <expression>"
63 for non-per-component instructions.
65 assert isinstance(name
, str)
66 assert isinstance(output_size
, int)
67 assert isinstance(output_type
, str)
68 assert isinstance(input_sizes
, list)
69 assert isinstance(input_sizes
[0], int)
70 assert isinstance(input_types
, list)
71 assert isinstance(input_types
[0], str)
72 assert isinstance(algebraic_properties
, str)
73 assert isinstance(const_expr
, str)
74 assert len(input_sizes
) == len(input_types
)
75 assert 0 <= output_size
<= 4
76 for size
in input_sizes
:
81 self
.num_inputs
= len(input_sizes
)
82 self
.output_size
= output_size
83 self
.output_type
= output_type
84 self
.input_sizes
= input_sizes
85 self
.input_types
= input_types
86 self
.algebraic_properties
= algebraic_properties
87 self
.const_expr
= const_expr
89 # 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
, ("bit_size == 64 ? ((src0 == 0.0) ? 1.0 : 0.0f) : " +
153 "((src0 == 0.0f) ? 1.0f : 0.0f)"))
154 unop("fsign", tfloat
, ("bit_size == 64 ? " +
155 "((src0 == 0.0) ? 0.0 : ((src0 > 0.0) ? 1.0 : -1.0)) : " +
156 "((src0 == 0.0f) ? 0.0f : ((src0 > 0.0f) ? 1.0f : -1.0f))"))
157 unop("isign", tint
, "(src0 == 0) ? 0 : ((src0 > 0) ? 1 : -1)")
158 unop("iabs", tint
, "(src0 < 0) ? -src0 : src0")
159 unop("fabs", tfloat
, "fabs(src0)")
160 unop("fsat", tfloat
, ("bit_size == 64 ? " +
161 "((src0 > 1.0) ? 1.0 : ((src0 <= 0.0) ? 0.0 : src0)) : " +
162 "((src0 > 1.0f) ? 1.0f : ((src0 <= 0.0f) ? 0.0f : src0))"))
163 unop("frcp", tfloat
, "bit_size == 64 ? 1.0 / src0 : 1.0f / src0")
164 unop("frsq", tfloat
, "bit_size == 64 ? 1.0 / sqrt(src0) : 1.0f / sqrtf(src0)")
165 unop("fsqrt", tfloat
, "bit_size == 64 ? sqrt(src0) : sqrtf(src0)")
166 unop("fexp2", tfloat
, "exp2f(src0)")
167 unop("flog2", tfloat
, "log2f(src0)")
169 # Generate all of the numeric conversion opcodes
170 for src_t
in [tint
, tuint
, tfloat
]:
171 if src_t
in (tint
, tuint
):
172 dst_types
= [tfloat
, src_t
]
173 elif src_t
== tfloat
:
174 dst_types
= [tint
, tuint
, tfloat
]
176 for dst_t
in dst_types
:
178 bit_sizes
= [16, 32, 64]
180 bit_sizes
= [8, 16, 32, 64]
181 for bit_size
in bit_sizes
:
182 if bit_size
== 16 and dst_t
== tfloat
and src_t
== tfloat
:
183 rnd_modes
= ['rtne', 'rtz', 'undef']
184 for rnd_mode
in rnd_modes
:
185 unop_convert("{0}2{1}{2}_{3}".format(src_t
[0], dst_t
[0],
187 dst_t
+ str(bit_size
), src_t
, "src0")
189 unop_convert("{0}2{1}{2}".format(src_t
[0], dst_t
[0], bit_size
),
190 dst_t
+ str(bit_size
), src_t
, "src0")
192 # We'll hand-code the to/from bool conversion opcodes. Because bool doesn't
193 # have multiple bit-sizes, we can always infer the size from the other type.
194 unop_convert("f2b", tbool
, tfloat
, "src0 != 0.0")
195 unop_convert("i2b", tbool
, tint
, "src0 != 0")
196 unop_convert("b2f", tfloat
, tbool
, "src0 ? 1.0 : 0.0")
197 unop_convert("b2i", tint
, tbool
, "src0 ? 1 : 0")
200 # Unary floating-point rounding operations.
203 unop("ftrunc", tfloat
, "bit_size == 64 ? trunc(src0) : truncf(src0)")
204 unop("fceil", tfloat
, "bit_size == 64 ? ceil(src0) : ceilf(src0)")
205 unop("ffloor", tfloat
, "bit_size == 64 ? floor(src0) : floorf(src0)")
206 unop("ffract", tfloat
, "src0 - (bit_size == 64 ? floor(src0) : floorf(src0))")
207 unop("fround_even", tfloat
, "bit_size == 64 ? _mesa_roundeven(src0) : _mesa_roundevenf(src0)")
209 unop("fquantize2f16", tfloat
, "(fabs(src0) < ldexpf(1.0, -14)) ? copysignf(0.0f, src0) : _mesa_half_to_float(_mesa_float_to_half(src0))")
211 # Trigonometric operations.
214 unop("fsin", tfloat
, "bit_size == 64 ? sin(src0) : sinf(src0)")
215 unop("fcos", tfloat
, "bit_size == 64 ? cos(src0) : cosf(src0)")
218 # Partial derivatives.
221 unop("fddx", tfloat
, "0.0") # the derivative of a constant is 0.
222 unop("fddy", tfloat
, "0.0")
223 unop("fddx_fine", tfloat
, "0.0")
224 unop("fddy_fine", tfloat
, "0.0")
225 unop("fddx_coarse", tfloat
, "0.0")
226 unop("fddy_coarse", tfloat
, "0.0")
229 # Floating point pack and unpack operations.
232 unop_horiz("pack_" + fmt
+ "_2x16", 1, tuint32
, 2, tfloat32
, """
233 dst.x = (uint32_t) pack_fmt_1x16(src0.x);
234 dst.x |= ((uint32_t) pack_fmt_1x16(src0.y)) << 16;
235 """.replace("fmt", fmt
))
238 unop_horiz("pack_" + fmt
+ "_4x8", 1, tuint32
, 4, tfloat32
, """
239 dst.x = (uint32_t) pack_fmt_1x8(src0.x);
240 dst.x |= ((uint32_t) pack_fmt_1x8(src0.y)) << 8;
241 dst.x |= ((uint32_t) pack_fmt_1x8(src0.z)) << 16;
242 dst.x |= ((uint32_t) pack_fmt_1x8(src0.w)) << 24;
243 """.replace("fmt", fmt
))
245 def unpack_2x16(fmt
):
246 unop_horiz("unpack_" + fmt
+ "_2x16", 2, tfloat32
, 1, tuint32
, """
247 dst.x = unpack_fmt_1x16((uint16_t)(src0.x & 0xffff));
248 dst.y = unpack_fmt_1x16((uint16_t)(src0.x << 16));
249 """.replace("fmt", fmt
))
252 unop_horiz("unpack_" + fmt
+ "_4x8", 4, tfloat32
, 1, tuint32
, """
253 dst.x = unpack_fmt_1x8((uint8_t)(src0.x & 0xff));
254 dst.y = unpack_fmt_1x8((uint8_t)((src0.x >> 8) & 0xff));
255 dst.z = unpack_fmt_1x8((uint8_t)((src0.x >> 16) & 0xff));
256 dst.w = unpack_fmt_1x8((uint8_t)(src0.x >> 24));
257 """.replace("fmt", fmt
))
271 unop_horiz("pack_uvec2_to_uint", 1, tuint32
, 2, tuint32
, """
272 dst.x = (src0.x & 0xffff) | (src0.y << 16);
275 unop_horiz("pack_uvec4_to_uint", 1, tuint32
, 4, tuint32
, """
276 dst.x = (src0.x << 0) |
282 unop_horiz("pack_64_2x32", 1, tuint64
, 2, tuint32
,
283 "dst.x = src0.x | ((uint64_t)src0.y << 32);")
285 unop_horiz("unpack_64_2x32", 2, tuint32
, 1, tuint64
,
286 "dst.x = src0.x; dst.y = src0.x >> 32;")
288 # Lowered floating point unpacking operations.
291 unop_horiz("unpack_half_2x16_split_x", 1, tfloat32
, 1, tuint32
,
292 "unpack_half_1x16((uint16_t)(src0.x & 0xffff))")
293 unop_horiz("unpack_half_2x16_split_y", 1, tfloat32
, 1, tuint32
,
294 "unpack_half_1x16((uint16_t)(src0.x >> 16))")
296 unop_convert("unpack_64_2x32_split_x", tuint32
, tuint64
, "src0")
297 unop_convert("unpack_64_2x32_split_y", tuint32
, tuint64
, "src0 >> 32")
299 # Bit operations, part of ARB_gpu_shader5.
302 unop("bitfield_reverse", tuint32
, """
303 /* we're not winning any awards for speed here, but that's ok */
305 for (unsigned bit = 0; bit < 32; bit++)
306 dst |= ((src0 >> bit) & 1) << (31 - bit);
308 unop("bit_count", tuint32
, """
310 for (unsigned bit = 0; bit < 32; bit++) {
311 if ((src0 >> bit) & 1)
316 unop_convert("ufind_msb", tint32
, tuint32
, """
318 for (int bit = 31; bit >= 0; bit--) {
319 if ((src0 >> bit) & 1) {
326 unop("ifind_msb", tint32
, """
328 for (int bit = 31; bit >= 0; bit--) {
329 /* If src0 < 0, we're looking for the first 0 bit.
330 * if src0 >= 0, we're looking for the first 1 bit.
332 if ((((src0 >> bit) & 1) && (src0 >= 0)) ||
333 (!((src0 >> bit) & 1) && (src0 < 0))) {
340 unop("find_lsb", tint32
, """
342 for (unsigned bit = 0; bit < 32; bit++) {
343 if ((src0 >> bit) & 1) {
351 for i
in xrange(1, 5):
352 for j
in xrange(1, 5):
353 unop_horiz("fnoise{0}_{1}".format(i
, j
), i
, tfloat
, j
, tfloat
, "0.0f")
356 # AMD_gcn_shader extended instructions
357 unop_horiz("cube_face_coord", 2, tfloat32
, 3, tfloat32
, """
359 float absX = fabs(src0.x);
360 float absY = fabs(src0.y);
361 float absZ = fabs(src0.z);
362 if (src0.x >= 0 && absX >= absY && absX >= absZ) { dst.x = -src0.y; dst.y = -src0.z; }
363 if (src0.x < 0 && absX >= absY && absX >= absZ) { dst.x = -src0.y; dst.y = src0.z; }
364 if (src0.y >= 0 && absY >= absX && absY >= absZ) { dst.x = src0.z; dst.y = src0.x; }
365 if (src0.y < 0 && absY >= absX && absY >= absZ) { dst.x = -src0.z; dst.y = src0.x; }
366 if (src0.z >= 0 && absZ >= absX && absZ >= absY) { dst.x = -src0.y; dst.y = src0.x; }
367 if (src0.z < 0 && absZ >= absX && absZ >= absY) { dst.x = -src0.y; dst.y = -src0.x; }
370 unop_horiz("cube_face_index", 1, tfloat32
, 3, tfloat32
, """
371 float absX = fabs(src0.x);
372 float absY = fabs(src0.y);
373 float absZ = fabs(src0.z);
374 if (src0.x >= 0 && absX >= absY && absX >= absZ) dst.x = 0;
375 if (src0.x < 0 && absX >= absY && absX >= absZ) dst.x = 1;
376 if (src0.y >= 0 && absY >= absX && absY >= absZ) dst.x = 2;
377 if (src0.y < 0 && absY >= absX && absY >= absZ) dst.x = 3;
378 if (src0.z >= 0 && absZ >= absX && absZ >= absY) dst.x = 4;
379 if (src0.z < 0 && absZ >= absX && absZ >= absY) dst.x = 5;
383 def binop_convert(name
, out_type
, in_type
, alg_props
, const_expr
):
384 opcode(name
, 0, out_type
, [0, 0], [in_type
, in_type
], alg_props
, const_expr
)
386 def binop(name
, ty
, alg_props
, const_expr
):
387 binop_convert(name
, ty
, ty
, alg_props
, const_expr
)
389 def binop_compare(name
, ty
, alg_props
, const_expr
):
390 binop_convert(name
, tbool
, ty
, alg_props
, const_expr
)
392 def binop_horiz(name
, out_size
, out_type
, src1_size
, src1_type
, src2_size
,
393 src2_type
, const_expr
):
394 opcode(name
, out_size
, out_type
, [src1_size
, src2_size
], [src1_type
, src2_type
],
397 def binop_reduce(name
, output_size
, output_type
, src_type
, prereduce_expr
,
398 reduce_expr
, final_expr
):
400 return final_expr
.format(src
= "(" + src
+ ")")
401 def reduce_(src0
, src1
):
402 return reduce_expr
.format(src0
=src0
, src1
=src1
)
403 def prereduce(src0
, src1
):
404 return "(" + prereduce_expr
.format(src0
=src0
, src1
=src1
) + ")"
405 src0
= prereduce("src0.x", "src1.x")
406 src1
= prereduce("src0.y", "src1.y")
407 src2
= prereduce("src0.z", "src1.z")
408 src3
= prereduce("src0.w", "src1.w")
409 opcode(name
+ "2", output_size
, output_type
,
410 [2, 2], [src_type
, src_type
], commutative
,
411 final(reduce_(src0
, src1
)))
412 opcode(name
+ "3", output_size
, output_type
,
413 [3, 3], [src_type
, src_type
], commutative
,
414 final(reduce_(reduce_(src0
, src1
), src2
)))
415 opcode(name
+ "4", output_size
, output_type
,
416 [4, 4], [src_type
, src_type
], commutative
,
417 final(reduce_(reduce_(src0
, src1
), reduce_(src2
, src3
))))
419 binop("fadd", tfloat
, commutative
+ associative
, "src0 + src1")
420 binop("iadd", tint
, commutative
+ associative
, "src0 + src1")
421 binop("fsub", tfloat
, "", "src0 - src1")
422 binop("isub", tint
, "", "src0 - src1")
424 binop("fmul", tfloat
, commutative
+ associative
, "src0 * src1")
425 # low 32-bits of signed/unsigned integer multiply
426 binop("imul", tint
, commutative
+ associative
, "src0 * src1")
427 # high 32-bits of signed integer multiply
428 binop("imul_high", tint32
, commutative
,
429 "(int32_t)(((int64_t) src0 * (int64_t) src1) >> 32)")
430 # high 32-bits of unsigned integer multiply
431 binop("umul_high", tuint32
, commutative
,
432 "(uint32_t)(((uint64_t) src0 * (uint64_t) src1) >> 32)")
434 binop("fdiv", tfloat
, "", "src0 / src1")
435 binop("idiv", tint
, "", "src1 == 0 ? 0 : (src0 / src1)")
436 binop("udiv", tuint
, "", "src1 == 0 ? 0 : (src0 / src1)")
438 # returns a boolean representing the carry resulting from the addition of
439 # the two unsigned arguments.
441 binop_convert("uadd_carry", tuint
, tuint
, commutative
, "src0 + src1 < src0")
443 # returns a boolean representing the borrow resulting from the subtraction
444 # of the two unsigned arguments.
446 binop_convert("usub_borrow", tuint
, tuint
, "", "src0 < src1")
448 binop("umod", tuint
, "", "src1 == 0 ? 0 : src0 % src1")
450 # For signed integers, there are several different possible definitions of
451 # "modulus" or "remainder". We follow the conventions used by LLVM and
452 # SPIR-V. The irem opcode implements the standard C/C++ signed "%"
453 # operation while the imod opcode implements the more mathematical
454 # "modulus" operation. For details on the difference, see
456 # http://mathforum.org/library/drmath/view/52343.html
458 binop("irem", tint
, "", "src1 == 0 ? 0 : src0 % src1")
459 binop("imod", tint
, "",
460 "src1 == 0 ? 0 : ((src0 % src1 == 0 || (src0 >= 0) == (src1 >= 0)) ?"
461 " src0 % src1 : src0 % src1 + src1)")
462 binop("fmod", tfloat
, "", "src0 - src1 * floorf(src0 / src1)")
463 binop("frem", tfloat
, "", "src0 - src1 * truncf(src0 / src1)")
470 # these integer-aware comparisons return a boolean (0 or ~0)
472 binop_compare("flt", tfloat
, "", "src0 < src1")
473 binop_compare("fge", tfloat
, "", "src0 >= src1")
474 binop_compare("feq", tfloat
, commutative
, "src0 == src1")
475 binop_compare("fne", tfloat
, commutative
, "src0 != src1")
476 binop_compare("ilt", tint
, "", "src0 < src1")
477 binop_compare("ige", tint
, "", "src0 >= src1")
478 binop_compare("ieq", tint
, commutative
, "src0 == src1")
479 binop_compare("ine", tint
, commutative
, "src0 != src1")
480 binop_compare("ult", tuint
, "", "src0 < src1")
481 binop_compare("uge", tuint
, "", "src0 >= src1")
483 # integer-aware GLSL-style comparisons that compare floats and ints
485 binop_reduce("ball_fequal", 1, tbool
, tfloat
, "{src0} == {src1}",
486 "{src0} && {src1}", "{src}")
487 binop_reduce("bany_fnequal", 1, tbool
, tfloat
, "{src0} != {src1}",
488 "{src0} || {src1}", "{src}")
489 binop_reduce("ball_iequal", 1, tbool
, tint
, "{src0} == {src1}",
490 "{src0} && {src1}", "{src}")
491 binop_reduce("bany_inequal", 1, tbool
, tint
, "{src0} != {src1}",
492 "{src0} || {src1}", "{src}")
494 # non-integer-aware GLSL-style comparisons that return 0.0 or 1.0
496 binop_reduce("fall_equal", 1, tfloat32
, tfloat32
, "{src0} == {src1}",
497 "{src0} && {src1}", "{src} ? 1.0f : 0.0f")
498 binop_reduce("fany_nequal", 1, tfloat32
, tfloat32
, "{src0} != {src1}",
499 "{src0} || {src1}", "{src} ? 1.0f : 0.0f")
501 # These comparisons for integer-less hardware return 1.0 and 0.0 for true
502 # and false respectively
504 binop("slt", tfloat32
, "", "(src0 < src1) ? 1.0f : 0.0f") # Set on Less Than
505 binop("sge", tfloat
, "", "(src0 >= src1) ? 1.0f : 0.0f") # Set on Greater or Equal
506 binop("seq", tfloat32
, commutative
, "(src0 == src1) ? 1.0f : 0.0f") # Set on Equal
507 binop("sne", tfloat32
, commutative
, "(src0 != src1) ? 1.0f : 0.0f") # Set on Not Equal
510 opcode("ishl", 0, tint
, [0, 0], [tint
, tuint32
], "", "src0 << src1")
511 opcode("ishr", 0, tint
, [0, 0], [tint
, tuint32
], "", "src0 >> src1")
512 opcode("ushr", 0, tuint
, [0, 0], [tuint
, tuint32
], "", "src0 >> src1")
514 # bitwise logic operators
516 # These are also used as boolean and, or, xor for hardware supporting
520 binop("iand", tuint
, commutative
+ associative
, "src0 & src1")
521 binop("ior", tuint
, commutative
+ associative
, "src0 | src1")
522 binop("ixor", tuint
, commutative
+ associative
, "src0 ^ src1")
525 # floating point logic operators
527 # These use (src != 0.0) for testing the truth of the input, and output 1.0
528 # for true and 0.0 for false
530 binop("fand", tfloat32
, commutative
,
531 "((src0 != 0.0f) && (src1 != 0.0f)) ? 1.0f : 0.0f")
532 binop("for", tfloat32
, commutative
,
533 "((src0 != 0.0f) || (src1 != 0.0f)) ? 1.0f : 0.0f")
534 binop("fxor", tfloat32
, commutative
,
535 "(src0 != 0.0f && src1 == 0.0f) || (src0 == 0.0f && src1 != 0.0f) ? 1.0f : 0.0f")
537 binop_reduce("fdot", 1, tfloat
, tfloat
, "{src0} * {src1}", "{src0} + {src1}",
540 binop_reduce("fdot_replicated", 4, tfloat
, tfloat
,
541 "{src0} * {src1}", "{src0} + {src1}", "{src}")
543 opcode("fdph", 1, tfloat
, [3, 4], [tfloat
, tfloat
], "",
544 "src0.x * src1.x + src0.y * src1.y + src0.z * src1.z + src1.w")
545 opcode("fdph_replicated", 4, tfloat
, [3, 4], [tfloat
, tfloat
], "",
546 "src0.x * src1.x + src0.y * src1.y + src0.z * src1.z + src1.w")
548 binop("fmin", tfloat
, "", "fminf(src0, src1)")
549 binop("imin", tint
, commutative
+ associative
, "src1 > src0 ? src0 : src1")
550 binop("umin", tuint
, commutative
+ associative
, "src1 > src0 ? src0 : src1")
551 binop("fmax", tfloat
, "", "fmaxf(src0, src1)")
552 binop("imax", tint
, commutative
+ associative
, "src1 > src0 ? src1 : src0")
553 binop("umax", tuint
, commutative
+ associative
, "src1 > src0 ? src1 : src0")
555 # Saturated vector add for 4 8bit ints.
556 binop("usadd_4x8", tint32
, commutative
+ associative
, """
558 for (int i = 0; i < 32; i += 8) {
559 dst |= MIN2(((src0 >> i) & 0xff) + ((src1 >> i) & 0xff), 0xff) << i;
563 # Saturated vector subtract for 4 8bit ints.
564 binop("ussub_4x8", tint32
, "", """
566 for (int i = 0; i < 32; i += 8) {
567 int src0_chan = (src0 >> i) & 0xff;
568 int src1_chan = (src1 >> i) & 0xff;
569 if (src0_chan > src1_chan)
570 dst |= (src0_chan - src1_chan) << i;
574 # vector min for 4 8bit ints.
575 binop("umin_4x8", tint32
, commutative
+ associative
, """
577 for (int i = 0; i < 32; i += 8) {
578 dst |= MIN2((src0 >> i) & 0xff, (src1 >> i) & 0xff) << i;
582 # vector max for 4 8bit ints.
583 binop("umax_4x8", tint32
, commutative
+ associative
, """
585 for (int i = 0; i < 32; i += 8) {
586 dst |= MAX2((src0 >> i) & 0xff, (src1 >> i) & 0xff) << i;
590 # unorm multiply: (a * b) / 255.
591 binop("umul_unorm_4x8", tint32
, commutative
+ associative
, """
593 for (int i = 0; i < 32; i += 8) {
594 int src0_chan = (src0 >> i) & 0xff;
595 int src1_chan = (src1 >> i) & 0xff;
596 dst |= ((src0_chan * src1_chan) / 255) << i;
600 binop("fpow", tfloat
, "", "bit_size == 64 ? powf(src0, src1) : pow(src0, src1)")
602 binop_horiz("pack_half_2x16_split", 1, tuint32
, 1, tfloat32
, 1, tfloat32
,
603 "pack_half_1x16(src0.x) | (pack_half_1x16(src1.x) << 16)")
605 binop_convert("pack_64_2x32_split", tuint64
, tuint32
, "",
606 "src0 | ((uint64_t)src1 << 32)")
608 # bfm implements the behavior of the first operation of the SM5 "bfi" assembly
609 # and that of the "bfi1" i965 instruction. That is, it has undefined behavior
610 # if either of its arguments are 32.
611 binop_convert("bfm", tuint32
, tint32
, "", """
612 int bits = src0, offset = src1;
613 if (offset < 0 || bits < 0 || offset > 31 || bits > 31 || offset + bits > 32)
614 dst = 0; /* undefined */
616 dst = ((1u << bits) - 1) << offset;
619 opcode("ldexp", 0, tfloat
, [0, 0], [tfloat
, tint32
], "", """
620 dst = (bit_size == 64) ? ldexp(src0, src1) : ldexpf(src0, src1);
621 /* flush denormals to zero. */
623 dst = copysignf(0.0f, src0);
626 # Combines the first component of each input to make a 2-component vector.
628 binop_horiz("vec2", 2, tuint
, 1, tuint
, 1, tuint
, """
634 binop("extract_u8", tuint
, "", "(uint8_t)(src0 >> (src1 * 8))")
635 binop("extract_i8", tint
, "", "(int8_t)(src0 >> (src1 * 8))")
638 binop("extract_u16", tuint
, "", "(uint16_t)(src0 >> (src1 * 16))")
639 binop("extract_i16", tint
, "", "(int16_t)(src0 >> (src1 * 16))")
642 def triop(name
, ty
, const_expr
):
643 opcode(name
, 0, ty
, [0, 0, 0], [ty
, ty
, ty
], "", const_expr
)
644 def triop_horiz(name
, output_size
, src1_size
, src2_size
, src3_size
, const_expr
):
645 opcode(name
, output_size
, tuint
,
646 [src1_size
, src2_size
, src3_size
],
647 [tuint
, tuint
, tuint
], "", const_expr
)
649 triop("ffma", tfloat
, "src0 * src1 + src2")
651 triop("flrp", tfloat
, "src0 * (1 - src2) + src1 * src2")
655 # A vector conditional select instruction (like ?:, but operating per-
656 # component on vectors). There are two versions, one for floating point
657 # bools (0.0 vs 1.0) and one for integer bools (0 vs ~0).
660 triop("fcsel", tfloat32
, "(src0 != 0.0f) ? src1 : src2")
661 opcode("bcsel", 0, tuint
, [0, 0, 0],
662 [tbool
, tuint
, tuint
], "", "src0 ? src1 : src2")
665 triop("bfi", tuint32
, """
666 unsigned mask = src0, insert = src1, base = src2;
675 dst = (base & ~mask) | (insert & mask);
679 # SM5 ubfe/ibfe assembly
680 opcode("ubfe", 0, tuint32
,
681 [0, 0, 0], [tuint32
, tint32
, tint32
], "", """
682 unsigned base = src0;
683 int offset = src1, bits = src2;
686 } else if (bits < 0 || offset < 0) {
687 dst = 0; /* undefined */
688 } else if (offset + bits < 32) {
689 dst = (base << (32 - bits - offset)) >> (32 - bits);
691 dst = base >> offset;
694 opcode("ibfe", 0, tint32
,
695 [0, 0, 0], [tint32
, tint32
, tint32
], "", """
697 int offset = src1, bits = src2;
700 } else if (bits < 0 || offset < 0) {
701 dst = 0; /* undefined */
702 } else if (offset + bits < 32) {
703 dst = (base << (32 - bits - offset)) >> (32 - bits);
705 dst = base >> offset;
709 # GLSL bitfieldExtract()
710 opcode("ubitfield_extract", 0, tuint32
,
711 [0, 0, 0], [tuint32
, tint32
, tint32
], "", """
712 unsigned base = src0;
713 int offset = src1, bits = src2;
716 } else if (bits < 0 || offset < 0 || offset + bits > 32) {
717 dst = 0; /* undefined per the spec */
719 dst = (base >> offset) & ((1ull << bits) - 1);
722 opcode("ibitfield_extract", 0, tint32
,
723 [0, 0, 0], [tint32
, tint32
, tint32
], "", """
725 int offset = src1, bits = src2;
728 } else if (offset < 0 || bits < 0 || offset + bits > 32) {
731 dst = (base << (32 - offset - bits)) >> offset; /* use sign-extending shift */
735 # Combines the first component of each input to make a 3-component vector.
737 triop_horiz("vec3", 3, 1, 1, 1, """
743 def quadop_horiz(name
, output_size
, src1_size
, src2_size
, src3_size
,
744 src4_size
, const_expr
):
745 opcode(name
, output_size
, tuint
,
746 [src1_size
, src2_size
, src3_size
, src4_size
],
747 [tuint
, tuint
, tuint
, tuint
],
750 opcode("bitfield_insert", 0, tuint32
, [0, 0, 0, 0],
751 [tuint32
, tuint32
, tint32
, tint32
], "", """
752 unsigned base = src0, insert = src1;
753 int offset = src2, bits = src3;
756 } else if (offset < 0 || bits < 0 || bits + offset > 32) {
759 unsigned mask = ((1ull << bits) - 1) << offset;
760 dst = (base & ~mask) | ((insert << offset) & mask);
764 quadop_horiz("vec4", 4, 1, 1, 1, 1, """