nir: Add more modulus opcodes
[mesa.git] / src / compiler / nir / nir_opcodes.py
1 #! /usr/bin/env python
2 #
3 # Copyright (C) 2014 Connor Abbott
4 #
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:
11 #
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
14 # Software.
15 #
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
22 # IN THE SOFTWARE.
23 #
24 # Authors:
25 # Connor Abbott (cwabbott0@gmail.com)
26
27
28 # Class that represents all the information we have about the opcode
29 # NOTE: this must be kept in sync with nir_op_info
30
31 class Opcode(object):
32 """Class that represents all the information we have about the opcode
33 NOTE: this must be kept in sync with nir_op_info
34 """
35 def __init__(self, name, output_size, output_type, input_sizes,
36 input_types, algebraic_properties, const_expr):
37 """Parameters:
38
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.
46
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.
56
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.
65 """
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:
78 assert 0 <= size <= 4
79 if output_size != 0:
80 assert size != 0
81 self.name = name
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
89
90 # helper variables for strings
91 tfloat = "float"
92 tint = "int"
93 tbool = "bool32"
94 tuint = "uint"
95 tfloat32 = "float32"
96 tint32 = "int32"
97 tuint32 = "uint32"
98 tuint64 = "uint64"
99 tfloat64 = "float64"
100
101 commutative = "commutative "
102 associative = "associative "
103
104 # global dictionary of opcodes
105 opcodes = {}
106
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)
112
113 def unop_convert(name, out_type, in_type, const_expr):
114 opcode(name, 0, out_type, [0], [in_type], "", const_expr)
115
116 def unop(name, ty, const_expr):
117 opcode(name, 0, ty, [0], [ty], "", const_expr)
118
119 def unop_horiz(name, output_size, output_type, input_size, input_type,
120 const_expr):
121 opcode(name, output_size, output_type, [input_size], [input_type], "",
122 const_expr)
123
124 def unop_reduce(name, output_size, output_type, input_type, prereduce_expr,
125 reduce_expr, final_expr):
126 def prereduce(src):
127 return "(" + prereduce_expr.format(src=src) + ")"
128 def final(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))))
142
143
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")
148
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
182
183 # Unary floating-point rounding operations.
184
185
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)")
191
192 unop("fquantize2f16", tfloat, "(fabs(src0) < ldexpf(1.0, -14)) ? copysignf(0.0f, src0) : _mesa_half_to_float(_mesa_float_to_half(src0))")
193
194 # Trigonometric operations.
195
196
197 unop("fsin", tfloat, "bit_size == 64 ? sin(src0) : sinf(src0)")
198 unop("fcos", tfloat, "bit_size == 64 ? cos(src0) : cosf(src0)")
199
200
201 # Partial derivatives.
202
203
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")
210
211
212 # Floating point pack and unpack operations.
213
214 def pack_2x16(fmt):
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))
219
220 def pack_4x8(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))
227
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))
233
234 def unpack_4x8(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))
241
242
243 pack_2x16("snorm")
244 pack_4x8("snorm")
245 pack_2x16("unorm")
246 pack_4x8("unorm")
247 pack_2x16("half")
248 unpack_2x16("snorm")
249 unpack_4x8("snorm")
250 unpack_2x16("unorm")
251 unpack_4x8("unorm")
252 unpack_2x16("half")
253
254 unop_horiz("pack_uvec2_to_uint", 1, tuint32, 2, tuint32, """
255 dst.x = (src0.x & 0xffff) | (src0.y >> 16);
256 """)
257
258 unop_horiz("pack_uvec4_to_uint", 1, tuint32, 4, tuint32, """
259 dst.x = (src0.x << 0) |
260 (src0.y << 8) |
261 (src0.z << 16) |
262 (src0.w << 24);
263 """)
264
265 unop_horiz("pack_double_2x32", 1, tuint64, 2, tuint32, """
266 union {
267 uint64_t u64;
268 struct {
269 uint32_t i1;
270 uint32_t i2;
271 };
272 } di;
273
274 di.i1 = src0.x;
275 di.i2 = src0.y;
276 dst.x = di.u64;
277 """)
278
279 unop_horiz("unpack_double_2x32", 2, tuint32, 1, tuint64, """
280 union {
281 uint64_t u64;
282 struct {
283 uint32_t i1;
284 uint32_t i2;
285 };
286 } di;
287
288 di.u64 = src0.x;
289 dst.x = di.i1;
290 dst.y = di.i2;
291 """)
292
293 # Lowered floating point unpacking operations.
294
295
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))")
300
301 unop_convert("unpack_double_2x32_split_x", tuint32, tuint64, """
302 union {
303 uint64_t u64;
304 struct {
305 uint32_t x;
306 uint32_t y;
307 };
308 } di;
309 di.u64 = src0;
310 dst = di.x;
311 """)
312
313 unop_convert("unpack_double_2x32_split_y", tuint32, tuint64, """
314 union {
315 uint64_t u64;
316 struct {
317 uint32_t x;
318 uint32_t y;
319 };
320 } di;
321 di.u64 = src0;
322 dst = di.y;
323 """)
324
325 # Bit operations, part of ARB_gpu_shader5.
326
327
328 unop("bitfield_reverse", tuint32, """
329 /* we're not winning any awards for speed here, but that's ok */
330 dst = 0;
331 for (unsigned bit = 0; bit < 32; bit++)
332 dst |= ((src0 >> bit) & 1) << (31 - bit);
333 """)
334 unop("bit_count", tuint32, """
335 dst = 0;
336 for (unsigned bit = 0; bit < 32; bit++) {
337 if ((src0 >> bit) & 1)
338 dst++;
339 }
340 """)
341
342 unop_convert("ufind_msb", tint32, tuint32, """
343 dst = -1;
344 for (int bit = 31; bit > 0; bit--) {
345 if ((src0 >> bit) & 1) {
346 dst = bit;
347 break;
348 }
349 }
350 """)
351
352 unop("ifind_msb", tint32, """
353 dst = -1;
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.
357 */
358 if ((((src0 >> bit) & 1) && (src0 >= 0)) ||
359 (!((src0 >> bit) & 1) && (src0 < 0))) {
360 dst = bit;
361 break;
362 }
363 }
364 """)
365
366 unop("find_lsb", tint32, """
367 dst = -1;
368 for (unsigned bit = 0; bit < 32; bit++) {
369 if ((src0 >> bit) & 1) {
370 dst = bit;
371 break;
372 }
373 }
374 """)
375
376
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")
380
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)
383
384 def binop(name, ty, alg_props, const_expr):
385 binop_convert(name, ty, ty, alg_props, const_expr)
386
387 def binop_compare(name, ty, alg_props, const_expr):
388 binop_convert(name, tbool, ty, alg_props, const_expr)
389
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],
393 "", const_expr)
394
395 def binop_reduce(name, output_size, output_type, src_type, prereduce_expr,
396 reduce_expr, final_expr):
397 def final(src):
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))))
416
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")
421
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)")
431
432 binop("fdiv", tfloat, "", "src0 / src1")
433 binop("idiv", tint, "", "src0 / src1")
434 binop("udiv", tuint, "", "src0 / src1")
435
436 # returns a boolean representing the carry resulting from the addition of
437 # the two unsigned arguments.
438
439 binop_convert("uadd_carry", tuint, tuint, commutative, "src0 + src1 < src0")
440
441 # returns a boolean representing the borrow resulting from the subtraction
442 # of the two unsigned arguments.
443
444 binop_convert("usub_borrow", tuint, tuint, "", "src0 < src1")
445
446 binop("umod", tuint, "", "src1 == 0 ? 0 : src0 % src1")
447
448 # For signed integers, there are several different possible definitions of
449 # "modulus" or "remainder". We follow the conventions used by LLVM and
450 # SPIR-V. The irem opcode implements the standard C/C++ signed "%"
451 # operation while the imod opcode implements the more mathematical
452 # "modulus" operation. For details on the difference, see
453 #
454 # http://mathforum.org/library/drmath/view/52343.html
455
456 binop("irem", tint, "", "src1 == 0 ? 0 : src0 % src1")
457 binop("imod", tint, "",
458 "src1 == 0 ? 0 : ((src0 % src1 == 0 || (src0 >= 0) == (src1 >= 0)) ?"
459 " src0 % src1 : src0 % src1 + src1)")
460 binop("fmod", tfloat, "", "src0 - src1 * floorf(src0 / src1)")
461 binop("frem", tfloat, "", "src0 - src1 * truncf(src0 / src1)")
462
463 #
464 # Comparisons
465 #
466
467
468 # these integer-aware comparisons return a boolean (0 or ~0)
469
470 binop_compare("flt", tfloat, "", "src0 < src1")
471 binop_compare("fge", tfloat, "", "src0 >= src1")
472 binop_compare("feq", tfloat, commutative, "src0 == src1")
473 binop_compare("fne", tfloat, commutative, "src0 != src1")
474 binop_compare("ilt", tint, "", "src0 < src1")
475 binop_compare("ige", tint, "", "src0 >= src1")
476 binop_compare("ieq", tint, commutative, "src0 == src1")
477 binop_compare("ine", tint, commutative, "src0 != src1")
478 binop_compare("ult", tuint, "", "src0 < src1")
479 binop_compare("uge", tuint, "", "src0 >= src1")
480
481 # integer-aware GLSL-style comparisons that compare floats and ints
482
483 binop_reduce("ball_fequal", 1, tbool, tfloat, "{src0} == {src1}",
484 "{src0} && {src1}", "{src}")
485 binop_reduce("bany_fnequal", 1, tbool, tfloat, "{src0} != {src1}",
486 "{src0} || {src1}", "{src}")
487 binop_reduce("ball_iequal", 1, tbool, tint, "{src0} == {src1}",
488 "{src0} && {src1}", "{src}")
489 binop_reduce("bany_inequal", 1, tbool, tint, "{src0} != {src1}",
490 "{src0} || {src1}", "{src}")
491
492 # non-integer-aware GLSL-style comparisons that return 0.0 or 1.0
493
494 binop_reduce("fall_equal", 1, tfloat32, tfloat32, "{src0} == {src1}",
495 "{src0} && {src1}", "{src} ? 1.0f : 0.0f")
496 binop_reduce("fany_nequal", 1, tfloat32, tfloat32, "{src0} != {src1}",
497 "{src0} || {src1}", "{src} ? 1.0f : 0.0f")
498
499 # These comparisons for integer-less hardware return 1.0 and 0.0 for true
500 # and false respectively
501
502 binop("slt", tfloat32, "", "(src0 < src1) ? 1.0f : 0.0f") # Set on Less Than
503 binop("sge", tfloat32, "", "(src0 >= src1) ? 1.0f : 0.0f") # Set on Greater or Equal
504 binop("seq", tfloat32, commutative, "(src0 == src1) ? 1.0f : 0.0f") # Set on Equal
505 binop("sne", tfloat32, commutative, "(src0 != src1) ? 1.0f : 0.0f") # Set on Not Equal
506
507
508 binop("ishl", tint, "", "src0 << src1")
509 binop("ishr", tint, "", "src0 >> src1")
510 binop("ushr", tuint, "", "src0 >> src1")
511
512 # bitwise logic operators
513 #
514 # These are also used as boolean and, or, xor for hardware supporting
515 # integers.
516
517
518 binop("iand", tuint, commutative + associative, "src0 & src1")
519 binop("ior", tuint, commutative + associative, "src0 | src1")
520 binop("ixor", tuint, commutative + associative, "src0 ^ src1")
521
522
523 # floating point logic operators
524 #
525 # These use (src != 0.0) for testing the truth of the input, and output 1.0
526 # for true and 0.0 for false
527
528 binop("fand", tfloat32, commutative,
529 "((src0 != 0.0f) && (src1 != 0.0f)) ? 1.0f : 0.0f")
530 binop("for", tfloat32, commutative,
531 "((src0 != 0.0f) || (src1 != 0.0f)) ? 1.0f : 0.0f")
532 binop("fxor", tfloat32, commutative,
533 "(src0 != 0.0f && src1 == 0.0f) || (src0 == 0.0f && src1 != 0.0f) ? 1.0f : 0.0f")
534
535 binop_reduce("fdot", 1, tfloat, tfloat, "{src0} * {src1}", "{src0} + {src1}",
536 "{src}")
537
538 binop_reduce("fdot_replicated", 4, tfloat, tfloat,
539 "{src0} * {src1}", "{src0} + {src1}", "{src}")
540
541 opcode("fdph", 1, tfloat, [3, 4], [tfloat, tfloat], "",
542 "src0.x * src1.x + src0.y * src1.y + src0.z * src1.z + src1.w")
543 opcode("fdph_replicated", 4, tfloat, [3, 4], [tfloat, tfloat], "",
544 "src0.x * src1.x + src0.y * src1.y + src0.z * src1.z + src1.w")
545
546 binop("fmin", tfloat, "", "fminf(src0, src1)")
547 binop("imin", tint, commutative + associative, "src1 > src0 ? src0 : src1")
548 binop("umin", tuint, commutative + associative, "src1 > src0 ? src0 : src1")
549 binop("fmax", tfloat, "", "fmaxf(src0, src1)")
550 binop("imax", tint, commutative + associative, "src1 > src0 ? src1 : src0")
551 binop("umax", tuint, commutative + associative, "src1 > src0 ? src1 : src0")
552
553 # Saturated vector add for 4 8bit ints.
554 binop("usadd_4x8", tint32, commutative + associative, """
555 dst = 0;
556 for (int i = 0; i < 32; i += 8) {
557 dst |= MIN2(((src0 >> i) & 0xff) + ((src1 >> i) & 0xff), 0xff) << i;
558 }
559 """)
560
561 # Saturated vector subtract for 4 8bit ints.
562 binop("ussub_4x8", tint32, "", """
563 dst = 0;
564 for (int i = 0; i < 32; i += 8) {
565 int src0_chan = (src0 >> i) & 0xff;
566 int src1_chan = (src1 >> i) & 0xff;
567 if (src0_chan > src1_chan)
568 dst |= (src0_chan - src1_chan) << i;
569 }
570 """)
571
572 # vector min for 4 8bit ints.
573 binop("umin_4x8", tint32, commutative + associative, """
574 dst = 0;
575 for (int i = 0; i < 32; i += 8) {
576 dst |= MIN2((src0 >> i) & 0xff, (src1 >> i) & 0xff) << i;
577 }
578 """)
579
580 # vector max for 4 8bit ints.
581 binop("umax_4x8", tint32, commutative + associative, """
582 dst = 0;
583 for (int i = 0; i < 32; i += 8) {
584 dst |= MAX2((src0 >> i) & 0xff, (src1 >> i) & 0xff) << i;
585 }
586 """)
587
588 # unorm multiply: (a * b) / 255.
589 binop("umul_unorm_4x8", tint32, commutative + associative, """
590 dst = 0;
591 for (int i = 0; i < 32; i += 8) {
592 int src0_chan = (src0 >> i) & 0xff;
593 int src1_chan = (src1 >> i) & 0xff;
594 dst |= ((src0_chan * src1_chan) / 255) << i;
595 }
596 """)
597
598 binop("fpow", tfloat, "", "bit_size == 64 ? powf(src0, src1) : pow(src0, src1)")
599
600 binop_horiz("pack_half_2x16_split", 1, tuint32, 1, tfloat32, 1, tfloat32,
601 "pack_half_1x16(src0.x) | (pack_half_1x16(src1.x) << 16)")
602
603 binop_convert("pack_double_2x32_split", tuint64, tuint32, "", """
604 union {
605 uint64_t u64;
606 struct {
607 uint32_t x;
608 uint32_t y;
609 };
610 } di;
611 di.x = src0;
612 di.y = src1;
613 dst = di.u64;
614 """)
615
616 # bfm implements the behavior of the first operation of the SM5 "bfi" assembly
617 # and that of the "bfi1" i965 instruction. That is, it has undefined behavior
618 # if either of its arguments are 32.
619 binop_convert("bfm", tuint32, tint32, "", """
620 int bits = src0, offset = src1;
621 if (offset < 0 || bits < 0 || offset > 31 || bits > 31 || offset + bits > 32)
622 dst = 0; /* undefined */
623 else
624 dst = ((1u << bits) - 1) << offset;
625 """)
626
627 opcode("ldexp", 0, tfloat, [0, 0], [tfloat, tint], "", """
628 dst = (bit_size == 64) ? ldexp(src0, src1) : ldexpf(src0, src1);
629 /* flush denormals to zero. */
630 if (!isnormal(dst))
631 dst = copysignf(0.0f, src0);
632 """)
633
634 # Combines the first component of each input to make a 2-component vector.
635
636 binop_horiz("vec2", 2, tuint, 1, tuint, 1, tuint, """
637 dst.x = src0.x;
638 dst.y = src1.x;
639 """)
640
641 # Byte extraction
642 binop("extract_u8", tuint, "", "(uint8_t)(src0 >> (src1 * 8))")
643 binop("extract_i8", tint, "", "(int8_t)(src0 >> (src1 * 8))")
644
645 # Word extraction
646 binop("extract_u16", tuint, "", "(uint16_t)(src0 >> (src1 * 16))")
647 binop("extract_i16", tint, "", "(int16_t)(src0 >> (src1 * 16))")
648
649
650 def triop(name, ty, const_expr):
651 opcode(name, 0, ty, [0, 0, 0], [ty, ty, ty], "", const_expr)
652 def triop_horiz(name, output_size, src1_size, src2_size, src3_size, const_expr):
653 opcode(name, output_size, tuint,
654 [src1_size, src2_size, src3_size],
655 [tuint, tuint, tuint], "", const_expr)
656
657 triop("ffma", tfloat, "src0 * src1 + src2")
658
659 triop("flrp", tfloat, "src0 * (1 - src2) + src1 * src2")
660
661 # Conditional Select
662 #
663 # A vector conditional select instruction (like ?:, but operating per-
664 # component on vectors). There are two versions, one for floating point
665 # bools (0.0 vs 1.0) and one for integer bools (0 vs ~0).
666
667
668 triop("fcsel", tfloat32, "(src0 != 0.0f) ? src1 : src2")
669 opcode("bcsel", 0, tuint, [0, 0, 0],
670 [tbool, tuint, tuint], "", "src0 ? src1 : src2")
671
672 # SM5 bfi assembly
673 triop("bfi", tuint32, """
674 unsigned mask = src0, insert = src1, base = src2;
675 if (mask == 0) {
676 dst = base;
677 } else {
678 unsigned tmp = mask;
679 while (!(tmp & 1)) {
680 tmp >>= 1;
681 insert <<= 1;
682 }
683 dst = (base & ~mask) | (insert & mask);
684 }
685 """)
686
687 # SM5 ubfe/ibfe assembly
688 opcode("ubfe", 0, tuint32,
689 [0, 0, 0], [tuint32, tint32, tint32], "", """
690 unsigned base = src0;
691 int offset = src1, bits = src2;
692 if (bits == 0) {
693 dst = 0;
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);
698 } else {
699 dst = base >> offset;
700 }
701 """)
702 opcode("ibfe", 0, tint32,
703 [0, 0, 0], [tint32, tint32, tint32], "", """
704 int base = src0;
705 int offset = src1, bits = src2;
706 if (bits == 0) {
707 dst = 0;
708 } else if (bits < 0 || offset < 0) {
709 dst = 0; /* undefined */
710 } else if (offset + bits < 32) {
711 dst = (base << (32 - bits - offset)) >> (32 - bits);
712 } else {
713 dst = base >> offset;
714 }
715 """)
716
717 # GLSL bitfieldExtract()
718 opcode("ubitfield_extract", 0, tuint32,
719 [0, 0, 0], [tuint32, tint32, tint32], "", """
720 unsigned base = src0;
721 int offset = src1, bits = src2;
722 if (bits == 0) {
723 dst = 0;
724 } else if (bits < 0 || offset < 0 || offset + bits > 32) {
725 dst = 0; /* undefined per the spec */
726 } else {
727 dst = (base >> offset) & ((1ull << bits) - 1);
728 }
729 """)
730 opcode("ibitfield_extract", 0, tint32,
731 [0, 0, 0], [tint32, tint32, tint32], "", """
732 int base = src0;
733 int offset = src1, bits = src2;
734 if (bits == 0) {
735 dst = 0;
736 } else if (offset < 0 || bits < 0 || offset + bits > 32) {
737 dst = 0;
738 } else {
739 dst = (base << (32 - offset - bits)) >> offset; /* use sign-extending shift */
740 }
741 """)
742
743 # Combines the first component of each input to make a 3-component vector.
744
745 triop_horiz("vec3", 3, 1, 1, 1, """
746 dst.x = src0.x;
747 dst.y = src1.x;
748 dst.z = src2.x;
749 """)
750
751 def quadop_horiz(name, output_size, src1_size, src2_size, src3_size,
752 src4_size, const_expr):
753 opcode(name, output_size, tuint,
754 [src1_size, src2_size, src3_size, src4_size],
755 [tuint, tuint, tuint, tuint],
756 "", const_expr)
757
758 opcode("bitfield_insert", 0, tuint32, [0, 0, 0, 0],
759 [tuint32, tuint32, tint32, tint32], "", """
760 unsigned base = src0, insert = src1;
761 int offset = src2, bits = src3;
762 if (bits == 0) {
763 dst = 0;
764 } else if (offset < 0 || bits < 0 || bits + offset > 32) {
765 dst = 0;
766 } else {
767 unsigned mask = ((1ull << bits) - 1) << offset;
768 dst = (base & ~mask) | ((insert << bits) & mask);
769 }
770 """)
771
772 quadop_horiz("vec4", 4, 1, 1, 1, 1, """
773 dst.x = src0.x;
774 dst.y = src1.x;
775 dst.z = src2.x;
776 dst.w = src3.x;
777 """)
778
779