Merge remote-tracking branch 'public/master' into vulkan
[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 tfloat64 = "float64"
99
100 commutative = "commutative "
101 associative = "associative "
102
103 # global dictionary of opcodes
104 opcodes = {}
105
106 def opcode(name, output_size, output_type, input_sizes, input_types,
107 algebraic_properties, const_expr):
108 assert name not in opcodes
109 opcodes[name] = Opcode(name, output_size, output_type, input_sizes,
110 input_types, algebraic_properties, const_expr)
111
112 def unop_convert(name, out_type, in_type, const_expr):
113 opcode(name, 0, out_type, [0], [in_type], "", const_expr)
114
115 def unop(name, ty, const_expr):
116 opcode(name, 0, ty, [0], [ty], "", const_expr)
117
118 def unop_horiz(name, output_size, output_type, input_size, input_type,
119 const_expr):
120 opcode(name, output_size, output_type, [input_size], [input_type], "",
121 const_expr)
122
123 def unop_reduce(name, output_size, output_type, input_type, prereduce_expr,
124 reduce_expr, final_expr):
125 def prereduce(src):
126 return "(" + prereduce_expr.format(src=src) + ")"
127 def final(src):
128 return final_expr.format(src="(" + src + ")")
129 def reduce_(src0, src1):
130 return reduce_expr.format(src0=src0, src1=src1)
131 src0 = prereduce("src0.x")
132 src1 = prereduce("src0.y")
133 src2 = prereduce("src0.z")
134 src3 = prereduce("src0.w")
135 unop_horiz(name + "2", output_size, output_type, 2, input_type,
136 final(reduce_(src0, src1)))
137 unop_horiz(name + "3", output_size, output_type, 3, input_type,
138 final(reduce_(reduce_(src0, src1), src2)))
139 unop_horiz(name + "4", output_size, output_type, 4, input_type,
140 final(reduce_(reduce_(src0, src1), reduce_(src2, src3))))
141
142
143 # These two move instructions differ in what modifiers they support and what
144 # the negate modifier means. Otherwise, they are identical.
145 unop("fmov", tfloat, "src0")
146 unop("imov", tint, "src0")
147
148 unop("ineg", tint, "-src0")
149 unop("fneg", tfloat, "-src0")
150 unop("inot", tint, "~src0") # invert every bit of the integer
151 unop("fnot", tfloat, "(src0 == 0.0f) ? 1.0f : 0.0f")
152 unop("fsign", tfloat, "(src0 == 0.0f) ? 0.0f : ((src0 > 0.0f) ? 1.0f : -1.0f)")
153 unop("isign", tint, "(src0 == 0) ? 0 : ((src0 > 0) ? 1 : -1)")
154 unop("iabs", tint, "(src0 < 0) ? -src0 : src0")
155 unop("fabs", tfloat, "fabsf(src0)")
156 unop("fsat", tfloat, "(src0 > 1.0f) ? 1.0f : ((src0 <= 0.0f) ? 0.0f : src0)")
157 unop("frcp", tfloat, "1.0f / src0")
158 unop("frsq", tfloat, "1.0f / sqrtf(src0)")
159 unop("fsqrt", tfloat, "sqrtf(src0)")
160 unop("fexp2", tfloat, "exp2f(src0)")
161 unop("flog2", tfloat, "log2f(src0)")
162 unop_convert("f2i", tint32, tfloat32, "src0") # Float-to-integer conversion.
163 unop_convert("f2u", tuint32, tfloat32, "src0") # Float-to-unsigned conversion
164 unop_convert("i2f", tfloat32, tint32, "src0") # Integer-to-float conversion.
165 # Float-to-boolean conversion
166 unop_convert("f2b", tbool, tfloat32, "src0 != 0.0f")
167 # Boolean-to-float conversion
168 unop_convert("b2f", tfloat32, tbool, "src0 ? 1.0f : 0.0f")
169 # Int-to-boolean conversion
170 unop_convert("i2b", tbool, tint32, "src0 != 0")
171 unop_convert("b2i", tint32, tbool, "src0 ? 1 : 0") # Boolean-to-int conversion
172 unop_convert("u2f", tfloat32, tuint32, "src0") # Unsigned-to-float conversion.
173
174 # Unary floating-point rounding operations.
175
176
177 unop("ftrunc", tfloat, "bit_size == 64 ? trunc(src0) : truncf(src0)")
178 unop("fceil", tfloat, "bit_size == 64 ? ceil(src0) : ceilf(src0)")
179 unop("ffloor", tfloat, "bit_size == 64 ? floor(src0) : floorf(src0)")
180 unop("ffract", tfloat, "src0 - (bit_size == 64 ? floor(src0) : floorf(src0))")
181 unop("fround_even", tfloat, "bit_size == 64 ? _mesa_roundeven(src0) : _mesa_roundevenf(src0)")
182
183 unop("fquantize2f16", tfloat, "(fabs(src0) < ldexpf(1.0, -14)) ? copysignf(0.0f, src0) : _mesa_half_to_float(_mesa_float_to_half(src0))")
184
185 # Trigonometric operations.
186
187
188 unop("fsin", tfloat, "bit_size == 64 ? sin(src0) : sinf(src0)")
189 unop("fcos", tfloat, "bit_size == 64 ? cos(src0) : cosf(src0)")
190
191
192 # Partial derivatives.
193
194
195 unop("fddx", tfloat, "0.0") # the derivative of a constant is 0.
196 unop("fddy", tfloat, "0.0")
197 unop("fddx_fine", tfloat, "0.0")
198 unop("fddy_fine", tfloat, "0.0")
199 unop("fddx_coarse", tfloat, "0.0")
200 unop("fddy_coarse", tfloat, "0.0")
201
202
203 # Floating point pack and unpack operations.
204
205 def pack_2x16(fmt):
206 unop_horiz("pack_" + fmt + "_2x16", 1, tuint32, 2, tfloat32, """
207 dst.x = (uint32_t) pack_fmt_1x16(src0.x);
208 dst.x |= ((uint32_t) pack_fmt_1x16(src0.y)) << 16;
209 """.replace("fmt", fmt))
210
211 def pack_4x8(fmt):
212 unop_horiz("pack_" + fmt + "_4x8", 1, tuint32, 4, tfloat32, """
213 dst.x = (uint32_t) pack_fmt_1x8(src0.x);
214 dst.x |= ((uint32_t) pack_fmt_1x8(src0.y)) << 8;
215 dst.x |= ((uint32_t) pack_fmt_1x8(src0.z)) << 16;
216 dst.x |= ((uint32_t) pack_fmt_1x8(src0.w)) << 24;
217 """.replace("fmt", fmt))
218
219 def unpack_2x16(fmt):
220 unop_horiz("unpack_" + fmt + "_2x16", 2, tfloat32, 1, tuint32, """
221 dst.x = unpack_fmt_1x16((uint16_t)(src0.x & 0xffff));
222 dst.y = unpack_fmt_1x16((uint16_t)(src0.x << 16));
223 """.replace("fmt", fmt))
224
225 def unpack_4x8(fmt):
226 unop_horiz("unpack_" + fmt + "_4x8", 4, tfloat32, 1, tuint32, """
227 dst.x = unpack_fmt_1x8((uint8_t)(src0.x & 0xff));
228 dst.y = unpack_fmt_1x8((uint8_t)((src0.x >> 8) & 0xff));
229 dst.z = unpack_fmt_1x8((uint8_t)((src0.x >> 16) & 0xff));
230 dst.w = unpack_fmt_1x8((uint8_t)(src0.x >> 24));
231 """.replace("fmt", fmt))
232
233
234 pack_2x16("snorm")
235 pack_4x8("snorm")
236 pack_2x16("unorm")
237 pack_4x8("unorm")
238 pack_2x16("half")
239 unpack_2x16("snorm")
240 unpack_4x8("snorm")
241 unpack_2x16("unorm")
242 unpack_4x8("unorm")
243 unpack_2x16("half")
244
245 unop_horiz("pack_uvec2_to_uint", 1, tuint32, 2, tuint32, """
246 dst.x = (src0.x & 0xffff) | (src0.y >> 16);
247 """)
248
249 unop_horiz("pack_uvec4_to_uint", 1, tuint32, 4, tuint32, """
250 dst.x = (src0.x << 0) |
251 (src0.y << 8) |
252 (src0.z << 16) |
253 (src0.w << 24);
254 """)
255
256 # Lowered floating point unpacking operations.
257
258
259 unop_horiz("unpack_half_2x16_split_x", 1, tfloat32, 1, tuint32,
260 "unpack_half_1x16((uint16_t)(src0.x & 0xffff))")
261 unop_horiz("unpack_half_2x16_split_y", 1, tfloat32, 1, tuint32,
262 "unpack_half_1x16((uint16_t)(src0.x >> 16))")
263
264
265 # Bit operations, part of ARB_gpu_shader5.
266
267
268 unop("bitfield_reverse", tuint32, """
269 /* we're not winning any awards for speed here, but that's ok */
270 dst = 0;
271 for (unsigned bit = 0; bit < 32; bit++)
272 dst |= ((src0 >> bit) & 1) << (31 - bit);
273 """)
274 unop("bit_count", tuint32, """
275 dst = 0;
276 for (unsigned bit = 0; bit < 32; bit++) {
277 if ((src0 >> bit) & 1)
278 dst++;
279 }
280 """)
281
282 unop_convert("ufind_msb", tint32, tuint32, """
283 dst = -1;
284 for (int bit = 31; bit > 0; bit--) {
285 if ((src0 >> bit) & 1) {
286 dst = bit;
287 break;
288 }
289 }
290 """)
291
292 unop("ifind_msb", tint32, """
293 dst = -1;
294 for (int bit = 31; bit >= 0; bit--) {
295 /* If src0 < 0, we're looking for the first 0 bit.
296 * if src0 >= 0, we're looking for the first 1 bit.
297 */
298 if ((((src0 >> bit) & 1) && (src0 >= 0)) ||
299 (!((src0 >> bit) & 1) && (src0 < 0))) {
300 dst = bit;
301 break;
302 }
303 }
304 """)
305
306 unop("find_lsb", tint32, """
307 dst = -1;
308 for (unsigned bit = 0; bit < 32; bit++) {
309 if ((src0 >> bit) & 1) {
310 dst = bit;
311 break;
312 }
313 }
314 """)
315
316
317 for i in xrange(1, 5):
318 for j in xrange(1, 5):
319 unop_horiz("fnoise{0}_{1}".format(i, j), i, tfloat, j, tfloat, "0.0f")
320
321 def binop_convert(name, out_type, in_type, alg_props, const_expr):
322 opcode(name, 0, out_type, [0, 0], [in_type, in_type], alg_props, const_expr)
323
324 def binop(name, ty, alg_props, const_expr):
325 binop_convert(name, ty, ty, alg_props, const_expr)
326
327 def binop_compare(name, ty, alg_props, const_expr):
328 binop_convert(name, tbool, ty, alg_props, const_expr)
329
330 def binop_horiz(name, out_size, out_type, src1_size, src1_type, src2_size,
331 src2_type, const_expr):
332 opcode(name, out_size, out_type, [src1_size, src2_size], [src1_type, src2_type],
333 "", const_expr)
334
335 def binop_reduce(name, output_size, output_type, src_type, prereduce_expr,
336 reduce_expr, final_expr):
337 def final(src):
338 return final_expr.format(src= "(" + src + ")")
339 def reduce_(src0, src1):
340 return reduce_expr.format(src0=src0, src1=src1)
341 def prereduce(src0, src1):
342 return "(" + prereduce_expr.format(src0=src0, src1=src1) + ")"
343 src0 = prereduce("src0.x", "src1.x")
344 src1 = prereduce("src0.y", "src1.y")
345 src2 = prereduce("src0.z", "src1.z")
346 src3 = prereduce("src0.w", "src1.w")
347 opcode(name + "2", output_size, output_type,
348 [2, 2], [src_type, src_type], commutative,
349 final(reduce_(src0, src1)))
350 opcode(name + "3", output_size, output_type,
351 [3, 3], [src_type, src_type], commutative,
352 final(reduce_(reduce_(src0, src1), src2)))
353 opcode(name + "4", output_size, output_type,
354 [4, 4], [src_type, src_type], commutative,
355 final(reduce_(reduce_(src0, src1), reduce_(src2, src3))))
356
357 binop("fadd", tfloat, commutative + associative, "src0 + src1")
358 binop("iadd", tint, commutative + associative, "src0 + src1")
359 binop("fsub", tfloat, "", "src0 - src1")
360 binop("isub", tint, "", "src0 - src1")
361
362 binop("fmul", tfloat, commutative + associative, "src0 * src1")
363 # low 32-bits of signed/unsigned integer multiply
364 binop("imul", tint, commutative + associative, "src0 * src1")
365 # high 32-bits of signed integer multiply
366 binop("imul_high", tint32, commutative,
367 "(int32_t)(((int64_t) src0 * (int64_t) src1) >> 32)")
368 # high 32-bits of unsigned integer multiply
369 binop("umul_high", tuint32, commutative,
370 "(uint32_t)(((uint64_t) src0 * (uint64_t) src1) >> 32)")
371
372 binop("fdiv", tfloat, "", "src0 / src1")
373 binop("idiv", tint, "", "src0 / src1")
374 binop("udiv", tuint, "", "src0 / src1")
375
376 # returns a boolean representing the carry resulting from the addition of
377 # the two unsigned arguments.
378
379 binop_convert("uadd_carry", tuint, tuint, commutative, "src0 + src1 < src0")
380
381 # returns a boolean representing the borrow resulting from the subtraction
382 # of the two unsigned arguments.
383
384 binop_convert("usub_borrow", tuint, tuint, "", "src0 < src1")
385
386 binop("umod", tuint, "", "src1 == 0 ? 0 : src0 % src1")
387
388 # For signed integers, there are several different possible definitions of
389 # "modulus" or "remainder". We follow the conventions used by LLVM and
390 # SPIR-V. The irem opcode implements the standard C/C++ signed "%"
391 # operation while the imod opcode implements the more mathematical
392 # "modulus" operation. For details on the difference, see
393 #
394 # http://mathforum.org/library/drmath/view/52343.html
395
396 binop("irem", tint, "", "src1 == 0 ? 0 : src0 % src1")
397 binop("imod", tint, "",
398 "src1 == 0 ? 0 : ((src0 % src1 == 0 || (src0 >= 0) == (src1 >= 0)) ?"
399 " src0 % src1 : src0 % src1 + src1)")
400 binop("fmod", tfloat, "", "src0 - src1 * floorf(src0 / src1)")
401 binop("frem", tfloat, "", "src0 - src1 * truncf(src0 / src1)")
402
403 #
404 # Comparisons
405 #
406
407
408 # these integer-aware comparisons return a boolean (0 or ~0)
409
410 binop_compare("flt", tfloat, "", "src0 < src1")
411 binop_compare("fge", tfloat, "", "src0 >= src1")
412 binop_compare("feq", tfloat, commutative, "src0 == src1")
413 binop_compare("fne", tfloat, commutative, "src0 != src1")
414 binop_compare("ilt", tint, "", "src0 < src1")
415 binop_compare("ige", tint, "", "src0 >= src1")
416 binop_compare("ieq", tint, commutative, "src0 == src1")
417 binop_compare("ine", tint, commutative, "src0 != src1")
418 binop_compare("ult", tuint, "", "src0 < src1")
419 binop_compare("uge", tuint, "", "src0 >= src1")
420
421 # integer-aware GLSL-style comparisons that compare floats and ints
422
423 binop_reduce("ball_fequal", 1, tbool, tfloat, "{src0} == {src1}",
424 "{src0} && {src1}", "{src}")
425 binop_reduce("bany_fnequal", 1, tbool, tfloat, "{src0} != {src1}",
426 "{src0} || {src1}", "{src}")
427 binop_reduce("ball_iequal", 1, tbool, tint, "{src0} == {src1}",
428 "{src0} && {src1}", "{src}")
429 binop_reduce("bany_inequal", 1, tbool, tint, "{src0} != {src1}",
430 "{src0} || {src1}", "{src}")
431
432 # non-integer-aware GLSL-style comparisons that return 0.0 or 1.0
433
434 binop_reduce("fall_equal", 1, tfloat32, tfloat32, "{src0} == {src1}",
435 "{src0} && {src1}", "{src} ? 1.0f : 0.0f")
436 binop_reduce("fany_nequal", 1, tfloat32, tfloat32, "{src0} != {src1}",
437 "{src0} || {src1}", "{src} ? 1.0f : 0.0f")
438
439 # These comparisons for integer-less hardware return 1.0 and 0.0 for true
440 # and false respectively
441
442 binop("slt", tfloat32, "", "(src0 < src1) ? 1.0f : 0.0f") # Set on Less Than
443 binop("sge", tfloat32, "", "(src0 >= src1) ? 1.0f : 0.0f") # Set on Greater or Equal
444 binop("seq", tfloat32, commutative, "(src0 == src1) ? 1.0f : 0.0f") # Set on Equal
445 binop("sne", tfloat32, commutative, "(src0 != src1) ? 1.0f : 0.0f") # Set on Not Equal
446
447
448 binop("ishl", tint, "", "src0 << src1")
449 binop("ishr", tint, "", "src0 >> src1")
450 binop("ushr", tuint, "", "src0 >> src1")
451
452 # bitwise logic operators
453 #
454 # These are also used as boolean and, or, xor for hardware supporting
455 # integers.
456
457
458 binop("iand", tuint, commutative + associative, "src0 & src1")
459 binop("ior", tuint, commutative + associative, "src0 | src1")
460 binop("ixor", tuint, commutative + associative, "src0 ^ src1")
461
462
463 # floating point logic operators
464 #
465 # These use (src != 0.0) for testing the truth of the input, and output 1.0
466 # for true and 0.0 for false
467
468 binop("fand", tfloat32, commutative,
469 "((src0 != 0.0f) && (src1 != 0.0f)) ? 1.0f : 0.0f")
470 binop("for", tfloat32, commutative,
471 "((src0 != 0.0f) || (src1 != 0.0f)) ? 1.0f : 0.0f")
472 binop("fxor", tfloat32, commutative,
473 "(src0 != 0.0f && src1 == 0.0f) || (src0 == 0.0f && src1 != 0.0f) ? 1.0f : 0.0f")
474
475 binop_reduce("fdot", 1, tfloat, tfloat, "{src0} * {src1}", "{src0} + {src1}",
476 "{src}")
477
478 binop_reduce("fdot_replicated", 4, tfloat, tfloat,
479 "{src0} * {src1}", "{src0} + {src1}", "{src}")
480
481 opcode("fdph", 1, tfloat, [3, 4], [tfloat, tfloat], "",
482 "src0.x * src1.x + src0.y * src1.y + src0.z * src1.z + src1.w")
483 opcode("fdph_replicated", 4, tfloat, [3, 4], [tfloat, tfloat], "",
484 "src0.x * src1.x + src0.y * src1.y + src0.z * src1.z + src1.w")
485
486 binop("fmin", tfloat, "", "fminf(src0, src1)")
487 binop("imin", tint, commutative + associative, "src1 > src0 ? src0 : src1")
488 binop("umin", tuint, commutative + associative, "src1 > src0 ? src0 : src1")
489 binop("fmax", tfloat, "", "fmaxf(src0, src1)")
490 binop("imax", tint, commutative + associative, "src1 > src0 ? src1 : src0")
491 binop("umax", tuint, commutative + associative, "src1 > src0 ? src1 : src0")
492
493 # Saturated vector add for 4 8bit ints.
494 binop("usadd_4x8", tint32, commutative + associative, """
495 dst = 0;
496 for (int i = 0; i < 32; i += 8) {
497 dst |= MIN2(((src0 >> i) & 0xff) + ((src1 >> i) & 0xff), 0xff) << i;
498 }
499 """)
500
501 # Saturated vector subtract for 4 8bit ints.
502 binop("ussub_4x8", tint32, "", """
503 dst = 0;
504 for (int i = 0; i < 32; i += 8) {
505 int src0_chan = (src0 >> i) & 0xff;
506 int src1_chan = (src1 >> i) & 0xff;
507 if (src0_chan > src1_chan)
508 dst |= (src0_chan - src1_chan) << i;
509 }
510 """)
511
512 # vector min for 4 8bit ints.
513 binop("umin_4x8", tint32, commutative + associative, """
514 dst = 0;
515 for (int i = 0; i < 32; i += 8) {
516 dst |= MIN2((src0 >> i) & 0xff, (src1 >> i) & 0xff) << i;
517 }
518 """)
519
520 # vector max for 4 8bit ints.
521 binop("umax_4x8", tint32, commutative + associative, """
522 dst = 0;
523 for (int i = 0; i < 32; i += 8) {
524 dst |= MAX2((src0 >> i) & 0xff, (src1 >> i) & 0xff) << i;
525 }
526 """)
527
528 # unorm multiply: (a * b) / 255.
529 binop("umul_unorm_4x8", tint32, commutative + associative, """
530 dst = 0;
531 for (int i = 0; i < 32; i += 8) {
532 int src0_chan = (src0 >> i) & 0xff;
533 int src1_chan = (src1 >> i) & 0xff;
534 dst |= ((src0_chan * src1_chan) / 255) << i;
535 }
536 """)
537
538 binop("fpow", tfloat, "", "bit_size == 64 ? powf(src0, src1) : pow(src0, src1)")
539
540 binop_horiz("pack_half_2x16_split", 1, tuint32, 1, tfloat32, 1, tfloat32,
541 "pack_half_1x16(src0.x) | (pack_half_1x16(src1.x) << 16)")
542
543 # bfm implements the behavior of the first operation of the SM5 "bfi" assembly
544 # and that of the "bfi1" i965 instruction. That is, it has undefined behavior
545 # if either of its arguments are 32.
546 binop_convert("bfm", tuint32, tint32, "", """
547 int bits = src0, offset = src1;
548 if (offset < 0 || bits < 0 || offset > 31 || bits > 31 || offset + bits > 32)
549 dst = 0; /* undefined */
550 else
551 dst = ((1u << bits) - 1) << offset;
552 """)
553
554 opcode("ldexp", 0, tfloat, [0, 0], [tfloat, tint], "", """
555 dst = (bit_size == 64) ? ldexp(src0, src1) : ldexpf(src0, src1);
556 /* flush denormals to zero. */
557 if (!isnormal(dst))
558 dst = copysignf(0.0f, src0);
559 """)
560
561 # Combines the first component of each input to make a 2-component vector.
562
563 binop_horiz("vec2", 2, tuint, 1, tuint, 1, tuint, """
564 dst.x = src0.x;
565 dst.y = src1.x;
566 """)
567
568 # Byte extraction
569 binop("extract_u8", tuint, "", "(uint8_t)(src0 >> (src1 * 8))")
570 binop("extract_i8", tint, "", "(int8_t)(src0 >> (src1 * 8))")
571
572 # Word extraction
573 binop("extract_u16", tuint, "", "(uint16_t)(src0 >> (src1 * 16))")
574 binop("extract_i16", tint, "", "(int16_t)(src0 >> (src1 * 16))")
575
576
577 def triop(name, ty, const_expr):
578 opcode(name, 0, ty, [0, 0, 0], [ty, ty, ty], "", const_expr)
579 def triop_horiz(name, output_size, src1_size, src2_size, src3_size, const_expr):
580 opcode(name, output_size, tuint,
581 [src1_size, src2_size, src3_size],
582 [tuint, tuint, tuint], "", const_expr)
583
584 triop("ffma", tfloat, "src0 * src1 + src2")
585
586 triop("flrp", tfloat, "src0 * (1 - src2) + src1 * src2")
587
588 # Conditional Select
589 #
590 # A vector conditional select instruction (like ?:, but operating per-
591 # component on vectors). There are two versions, one for floating point
592 # bools (0.0 vs 1.0) and one for integer bools (0 vs ~0).
593
594
595 triop("fcsel", tfloat32, "(src0 != 0.0f) ? src1 : src2")
596 opcode("bcsel", 0, tuint, [0, 0, 0],
597 [tbool, tuint, tuint], "", "src0 ? src1 : src2")
598
599 # SM5 bfi assembly
600 triop("bfi", tuint32, """
601 unsigned mask = src0, insert = src1, base = src2;
602 if (mask == 0) {
603 dst = base;
604 } else {
605 unsigned tmp = mask;
606 while (!(tmp & 1)) {
607 tmp >>= 1;
608 insert <<= 1;
609 }
610 dst = (base & ~mask) | (insert & mask);
611 }
612 """)
613
614 # SM5 ubfe/ibfe assembly
615 opcode("ubfe", 0, tuint32,
616 [0, 0, 0], [tuint32, tint32, tint32], "", """
617 unsigned base = src0;
618 int offset = src1, bits = src2;
619 if (bits == 0) {
620 dst = 0;
621 } else if (bits < 0 || offset < 0) {
622 dst = 0; /* undefined */
623 } else if (offset + bits < 32) {
624 dst = (base << (32 - bits - offset)) >> (32 - bits);
625 } else {
626 dst = base >> offset;
627 }
628 """)
629 opcode("ibfe", 0, tint32,
630 [0, 0, 0], [tint32, tint32, tint32], "", """
631 int base = src0;
632 int offset = src1, bits = src2;
633 if (bits == 0) {
634 dst = 0;
635 } else if (bits < 0 || offset < 0) {
636 dst = 0; /* undefined */
637 } else if (offset + bits < 32) {
638 dst = (base << (32 - bits - offset)) >> (32 - bits);
639 } else {
640 dst = base >> offset;
641 }
642 """)
643
644 # GLSL bitfieldExtract()
645 opcode("ubitfield_extract", 0, tuint32,
646 [0, 0, 0], [tuint32, tint32, tint32], "", """
647 unsigned base = src0;
648 int offset = src1, bits = src2;
649 if (bits == 0) {
650 dst = 0;
651 } else if (bits < 0 || offset < 0 || offset + bits > 32) {
652 dst = 0; /* undefined per the spec */
653 } else {
654 dst = (base >> offset) & ((1ull << bits) - 1);
655 }
656 """)
657 opcode("ibitfield_extract", 0, tint32,
658 [0, 0, 0], [tint32, tint32, tint32], "", """
659 int base = src0;
660 int offset = src1, bits = src2;
661 if (bits == 0) {
662 dst = 0;
663 } else if (offset < 0 || bits < 0 || offset + bits > 32) {
664 dst = 0;
665 } else {
666 dst = (base << (32 - offset - bits)) >> offset; /* use sign-extending shift */
667 }
668 """)
669
670 # Combines the first component of each input to make a 3-component vector.
671
672 triop_horiz("vec3", 3, 1, 1, 1, """
673 dst.x = src0.x;
674 dst.y = src1.x;
675 dst.z = src2.x;
676 """)
677
678 def quadop_horiz(name, output_size, src1_size, src2_size, src3_size,
679 src4_size, const_expr):
680 opcode(name, output_size, tuint,
681 [src1_size, src2_size, src3_size, src4_size],
682 [tuint, tuint, tuint, tuint],
683 "", const_expr)
684
685 opcode("bitfield_insert", 0, tuint32, [0, 0, 0, 0],
686 [tuint32, tuint32, tint32, tint32], "", """
687 unsigned base = src0, insert = src1;
688 int offset = src2, bits = src3;
689 if (bits == 0) {
690 dst = 0;
691 } else if (offset < 0 || bits < 0 || bits + offset > 32) {
692 dst = 0;
693 } else {
694 unsigned mask = ((1ull << bits) - 1) << offset;
695 dst = (base & ~mask) | ((insert << bits) & mask);
696 }
697 """)
698
699 quadop_horiz("vec4", 4, 1, 1, 1, 1, """
700 dst.x = src0.x;
701 dst.y = src1.x;
702 dst.z = src2.x;
703 dst.w = src3.x;
704 """)
705
706