nir: add support for (un)pack_double_2x32
[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
302 # Bit operations, part of ARB_gpu_shader5.
303
304
305 unop("bitfield_reverse", tuint32, """
306 /* we're not winning any awards for speed here, but that's ok */
307 dst = 0;
308 for (unsigned bit = 0; bit < 32; bit++)
309 dst |= ((src0 >> bit) & 1) << (31 - bit);
310 """)
311 unop("bit_count", tuint32, """
312 dst = 0;
313 for (unsigned bit = 0; bit < 32; bit++) {
314 if ((src0 >> bit) & 1)
315 dst++;
316 }
317 """)
318
319 unop_convert("ufind_msb", tint32, tuint32, """
320 dst = -1;
321 for (int bit = 31; bit > 0; bit--) {
322 if ((src0 >> bit) & 1) {
323 dst = bit;
324 break;
325 }
326 }
327 """)
328
329 unop("ifind_msb", tint32, """
330 dst = -1;
331 for (int bit = 31; bit >= 0; bit--) {
332 /* If src0 < 0, we're looking for the first 0 bit.
333 * if src0 >= 0, we're looking for the first 1 bit.
334 */
335 if ((((src0 >> bit) & 1) && (src0 >= 0)) ||
336 (!((src0 >> bit) & 1) && (src0 < 0))) {
337 dst = bit;
338 break;
339 }
340 }
341 """)
342
343 unop("find_lsb", tint32, """
344 dst = -1;
345 for (unsigned bit = 0; bit < 32; bit++) {
346 if ((src0 >> bit) & 1) {
347 dst = bit;
348 break;
349 }
350 }
351 """)
352
353
354 for i in xrange(1, 5):
355 for j in xrange(1, 5):
356 unop_horiz("fnoise{0}_{1}".format(i, j), i, tfloat, j, tfloat, "0.0f")
357
358 def binop_convert(name, out_type, in_type, alg_props, const_expr):
359 opcode(name, 0, out_type, [0, 0], [in_type, in_type], alg_props, const_expr)
360
361 def binop(name, ty, alg_props, const_expr):
362 binop_convert(name, ty, ty, alg_props, const_expr)
363
364 def binop_compare(name, ty, alg_props, const_expr):
365 binop_convert(name, tbool, ty, alg_props, const_expr)
366
367 def binop_horiz(name, out_size, out_type, src1_size, src1_type, src2_size,
368 src2_type, const_expr):
369 opcode(name, out_size, out_type, [src1_size, src2_size], [src1_type, src2_type],
370 "", const_expr)
371
372 def binop_reduce(name, output_size, output_type, src_type, prereduce_expr,
373 reduce_expr, final_expr):
374 def final(src):
375 return final_expr.format(src= "(" + src + ")")
376 def reduce_(src0, src1):
377 return reduce_expr.format(src0=src0, src1=src1)
378 def prereduce(src0, src1):
379 return "(" + prereduce_expr.format(src0=src0, src1=src1) + ")"
380 src0 = prereduce("src0.x", "src1.x")
381 src1 = prereduce("src0.y", "src1.y")
382 src2 = prereduce("src0.z", "src1.z")
383 src3 = prereduce("src0.w", "src1.w")
384 opcode(name + "2", output_size, output_type,
385 [2, 2], [src_type, src_type], commutative,
386 final(reduce_(src0, src1)))
387 opcode(name + "3", output_size, output_type,
388 [3, 3], [src_type, src_type], commutative,
389 final(reduce_(reduce_(src0, src1), src2)))
390 opcode(name + "4", output_size, output_type,
391 [4, 4], [src_type, src_type], commutative,
392 final(reduce_(reduce_(src0, src1), reduce_(src2, src3))))
393
394 binop("fadd", tfloat, commutative + associative, "src0 + src1")
395 binop("iadd", tint, commutative + associative, "src0 + src1")
396 binop("fsub", tfloat, "", "src0 - src1")
397 binop("isub", tint, "", "src0 - src1")
398
399 binop("fmul", tfloat, commutative + associative, "src0 * src1")
400 # low 32-bits of signed/unsigned integer multiply
401 binop("imul", tint, commutative + associative, "src0 * src1")
402 # high 32-bits of signed integer multiply
403 binop("imul_high", tint32, commutative,
404 "(int32_t)(((int64_t) src0 * (int64_t) src1) >> 32)")
405 # high 32-bits of unsigned integer multiply
406 binop("umul_high", tuint32, commutative,
407 "(uint32_t)(((uint64_t) src0 * (uint64_t) src1) >> 32)")
408
409 binop("fdiv", tfloat, "", "src0 / src1")
410 binop("idiv", tint, "", "src0 / src1")
411 binop("udiv", tuint, "", "src0 / src1")
412
413 # returns a boolean representing the carry resulting from the addition of
414 # the two unsigned arguments.
415
416 binop_convert("uadd_carry", tuint, tuint, commutative, "src0 + src1 < src0")
417
418 # returns a boolean representing the borrow resulting from the subtraction
419 # of the two unsigned arguments.
420
421 binop_convert("usub_borrow", tuint, tuint, "", "src0 < src1")
422
423 binop("fmod", tfloat, "", "src0 - src1 * floorf(src0 / src1)")
424 binop("umod", tuint, "", "src1 == 0 ? 0 : src0 % src1")
425
426 #
427 # Comparisons
428 #
429
430
431 # these integer-aware comparisons return a boolean (0 or ~0)
432
433 binop_compare("flt", tfloat, "", "src0 < src1")
434 binop_compare("fge", tfloat, "", "src0 >= src1")
435 binop_compare("feq", tfloat, commutative, "src0 == src1")
436 binop_compare("fne", tfloat, commutative, "src0 != src1")
437 binop_compare("ilt", tint, "", "src0 < src1")
438 binop_compare("ige", tint, "", "src0 >= src1")
439 binop_compare("ieq", tint, commutative, "src0 == src1")
440 binop_compare("ine", tint, commutative, "src0 != src1")
441 binop_compare("ult", tuint, "", "src0 < src1")
442 binop_compare("uge", tuint, "", "src0 >= src1")
443
444 # integer-aware GLSL-style comparisons that compare floats and ints
445
446 binop_reduce("ball_fequal", 1, tbool, tfloat, "{src0} == {src1}",
447 "{src0} && {src1}", "{src}")
448 binop_reduce("bany_fnequal", 1, tbool, tfloat, "{src0} != {src1}",
449 "{src0} || {src1}", "{src}")
450 binop_reduce("ball_iequal", 1, tbool, tint, "{src0} == {src1}",
451 "{src0} && {src1}", "{src}")
452 binop_reduce("bany_inequal", 1, tbool, tint, "{src0} != {src1}",
453 "{src0} || {src1}", "{src}")
454
455 # non-integer-aware GLSL-style comparisons that return 0.0 or 1.0
456
457 binop_reduce("fall_equal", 1, tfloat32, tfloat32, "{src0} == {src1}",
458 "{src0} && {src1}", "{src} ? 1.0f : 0.0f")
459 binop_reduce("fany_nequal", 1, tfloat32, tfloat32, "{src0} != {src1}",
460 "{src0} || {src1}", "{src} ? 1.0f : 0.0f")
461
462 # These comparisons for integer-less hardware return 1.0 and 0.0 for true
463 # and false respectively
464
465 binop("slt", tfloat32, "", "(src0 < src1) ? 1.0f : 0.0f") # Set on Less Than
466 binop("sge", tfloat32, "", "(src0 >= src1) ? 1.0f : 0.0f") # Set on Greater or Equal
467 binop("seq", tfloat32, commutative, "(src0 == src1) ? 1.0f : 0.0f") # Set on Equal
468 binop("sne", tfloat32, commutative, "(src0 != src1) ? 1.0f : 0.0f") # Set on Not Equal
469
470
471 binop("ishl", tint, "", "src0 << src1")
472 binop("ishr", tint, "", "src0 >> src1")
473 binop("ushr", tuint, "", "src0 >> src1")
474
475 # bitwise logic operators
476 #
477 # These are also used as boolean and, or, xor for hardware supporting
478 # integers.
479
480
481 binop("iand", tuint, commutative + associative, "src0 & src1")
482 binop("ior", tuint, commutative + associative, "src0 | src1")
483 binop("ixor", tuint, commutative + associative, "src0 ^ src1")
484
485
486 # floating point logic operators
487 #
488 # These use (src != 0.0) for testing the truth of the input, and output 1.0
489 # for true and 0.0 for false
490
491 binop("fand", tfloat32, commutative,
492 "((src0 != 0.0f) && (src1 != 0.0f)) ? 1.0f : 0.0f")
493 binop("for", tfloat32, commutative,
494 "((src0 != 0.0f) || (src1 != 0.0f)) ? 1.0f : 0.0f")
495 binop("fxor", tfloat32, commutative,
496 "(src0 != 0.0f && src1 == 0.0f) || (src0 == 0.0f && src1 != 0.0f) ? 1.0f : 0.0f")
497
498 binop_reduce("fdot", 1, tfloat, tfloat, "{src0} * {src1}", "{src0} + {src1}",
499 "{src}")
500
501 binop_reduce("fdot_replicated", 4, tfloat, tfloat,
502 "{src0} * {src1}", "{src0} + {src1}", "{src}")
503
504 opcode("fdph", 1, tfloat, [3, 4], [tfloat, tfloat], "",
505 "src0.x * src1.x + src0.y * src1.y + src0.z * src1.z + src1.w")
506 opcode("fdph_replicated", 4, tfloat, [3, 4], [tfloat, tfloat], "",
507 "src0.x * src1.x + src0.y * src1.y + src0.z * src1.z + src1.w")
508
509 binop("fmin", tfloat, "", "fminf(src0, src1)")
510 binop("imin", tint, commutative + associative, "src1 > src0 ? src0 : src1")
511 binop("umin", tuint, commutative + associative, "src1 > src0 ? src0 : src1")
512 binop("fmax", tfloat, "", "fmaxf(src0, src1)")
513 binop("imax", tint, commutative + associative, "src1 > src0 ? src1 : src0")
514 binop("umax", tuint, commutative + associative, "src1 > src0 ? src1 : src0")
515
516 # Saturated vector add for 4 8bit ints.
517 binop("usadd_4x8", tint32, commutative + associative, """
518 dst = 0;
519 for (int i = 0; i < 32; i += 8) {
520 dst |= MIN2(((src0 >> i) & 0xff) + ((src1 >> i) & 0xff), 0xff) << i;
521 }
522 """)
523
524 # Saturated vector subtract for 4 8bit ints.
525 binop("ussub_4x8", tint32, "", """
526 dst = 0;
527 for (int i = 0; i < 32; i += 8) {
528 int src0_chan = (src0 >> i) & 0xff;
529 int src1_chan = (src1 >> i) & 0xff;
530 if (src0_chan > src1_chan)
531 dst |= (src0_chan - src1_chan) << i;
532 }
533 """)
534
535 # vector min for 4 8bit ints.
536 binop("umin_4x8", tint32, commutative + associative, """
537 dst = 0;
538 for (int i = 0; i < 32; i += 8) {
539 dst |= MIN2((src0 >> i) & 0xff, (src1 >> i) & 0xff) << i;
540 }
541 """)
542
543 # vector max for 4 8bit ints.
544 binop("umax_4x8", tint32, commutative + associative, """
545 dst = 0;
546 for (int i = 0; i < 32; i += 8) {
547 dst |= MAX2((src0 >> i) & 0xff, (src1 >> i) & 0xff) << i;
548 }
549 """)
550
551 # unorm multiply: (a * b) / 255.
552 binop("umul_unorm_4x8", tint32, commutative + associative, """
553 dst = 0;
554 for (int i = 0; i < 32; i += 8) {
555 int src0_chan = (src0 >> i) & 0xff;
556 int src1_chan = (src1 >> i) & 0xff;
557 dst |= ((src0_chan * src1_chan) / 255) << i;
558 }
559 """)
560
561 binop("fpow", tfloat, "", "bit_size == 64 ? powf(src0, src1) : pow(src0, src1)")
562
563 binop_horiz("pack_half_2x16_split", 1, tuint32, 1, tfloat32, 1, tfloat32,
564 "pack_half_1x16(src0.x) | (pack_half_1x16(src1.x) << 16)")
565
566 # bfm implements the behavior of the first operation of the SM5 "bfi" assembly
567 # and that of the "bfi1" i965 instruction. That is, it has undefined behavior
568 # if either of its arguments are 32.
569 binop_convert("bfm", tuint32, tint32, "", """
570 int bits = src0, offset = src1;
571 if (offset < 0 || bits < 0 || offset > 31 || bits > 31 || offset + bits > 32)
572 dst = 0; /* undefined */
573 else
574 dst = ((1u << bits) - 1) << offset;
575 """)
576
577 opcode("ldexp", 0, tfloat, [0, 0], [tfloat, tint], "", """
578 dst = (bit_size == 64) ? ldexp(src0, src1) : ldexpf(src0, src1);
579 /* flush denormals to zero. */
580 if (!isnormal(dst))
581 dst = copysignf(0.0f, src0);
582 """)
583
584 # Combines the first component of each input to make a 2-component vector.
585
586 binop_horiz("vec2", 2, tuint, 1, tuint, 1, tuint, """
587 dst.x = src0.x;
588 dst.y = src1.x;
589 """)
590
591 # Byte extraction
592 binop("extract_u8", tuint, "", "(uint8_t)(src0 >> (src1 * 8))")
593 binop("extract_i8", tint, "", "(int8_t)(src0 >> (src1 * 8))")
594
595 # Word extraction
596 binop("extract_u16", tuint, "", "(uint16_t)(src0 >> (src1 * 16))")
597 binop("extract_i16", tint, "", "(int16_t)(src0 >> (src1 * 16))")
598
599
600 def triop(name, ty, const_expr):
601 opcode(name, 0, ty, [0, 0, 0], [ty, ty, ty], "", const_expr)
602 def triop_horiz(name, output_size, src1_size, src2_size, src3_size, const_expr):
603 opcode(name, output_size, tuint,
604 [src1_size, src2_size, src3_size],
605 [tuint, tuint, tuint], "", const_expr)
606
607 triop("ffma", tfloat, "src0 * src1 + src2")
608
609 triop("flrp", tfloat, "src0 * (1 - src2) + src1 * src2")
610
611 # Conditional Select
612 #
613 # A vector conditional select instruction (like ?:, but operating per-
614 # component on vectors). There are two versions, one for floating point
615 # bools (0.0 vs 1.0) and one for integer bools (0 vs ~0).
616
617
618 triop("fcsel", tfloat32, "(src0 != 0.0f) ? src1 : src2")
619 opcode("bcsel", 0, tuint, [0, 0, 0],
620 [tbool, tuint, tuint], "", "src0 ? src1 : src2")
621
622 # SM5 bfi assembly
623 triop("bfi", tuint32, """
624 unsigned mask = src0, insert = src1, base = src2;
625 if (mask == 0) {
626 dst = base;
627 } else {
628 unsigned tmp = mask;
629 while (!(tmp & 1)) {
630 tmp >>= 1;
631 insert <<= 1;
632 }
633 dst = (base & ~mask) | (insert & mask);
634 }
635 """)
636
637 # SM5 ubfe/ibfe assembly
638 opcode("ubfe", 0, tuint32,
639 [0, 0, 0], [tuint32, tint32, tint32], "", """
640 unsigned base = src0;
641 int offset = src1, bits = src2;
642 if (bits == 0) {
643 dst = 0;
644 } else if (bits < 0 || offset < 0) {
645 dst = 0; /* undefined */
646 } else if (offset + bits < 32) {
647 dst = (base << (32 - bits - offset)) >> (32 - bits);
648 } else {
649 dst = base >> offset;
650 }
651 """)
652 opcode("ibfe", 0, tint32,
653 [0, 0, 0], [tint32, tint32, tint32], "", """
654 int base = src0;
655 int offset = src1, bits = src2;
656 if (bits == 0) {
657 dst = 0;
658 } else if (bits < 0 || offset < 0) {
659 dst = 0; /* undefined */
660 } else if (offset + bits < 32) {
661 dst = (base << (32 - bits - offset)) >> (32 - bits);
662 } else {
663 dst = base >> offset;
664 }
665 """)
666
667 # GLSL bitfieldExtract()
668 opcode("ubitfield_extract", 0, tuint32,
669 [0, 0, 0], [tuint32, tint32, tint32], "", """
670 unsigned base = src0;
671 int offset = src1, bits = src2;
672 if (bits == 0) {
673 dst = 0;
674 } else if (bits < 0 || offset < 0 || offset + bits > 32) {
675 dst = 0; /* undefined per the spec */
676 } else {
677 dst = (base >> offset) & ((1ull << bits) - 1);
678 }
679 """)
680 opcode("ibitfield_extract", 0, tint32,
681 [0, 0, 0], [tint32, tint32, tint32], "", """
682 int base = src0;
683 int offset = src1, bits = src2;
684 if (bits == 0) {
685 dst = 0;
686 } else if (offset < 0 || bits < 0 || offset + bits > 32) {
687 dst = 0;
688 } else {
689 dst = (base << (32 - offset - bits)) >> offset; /* use sign-extending shift */
690 }
691 """)
692
693 # Combines the first component of each input to make a 3-component vector.
694
695 triop_horiz("vec3", 3, 1, 1, 1, """
696 dst.x = src0.x;
697 dst.y = src1.x;
698 dst.z = src2.x;
699 """)
700
701 def quadop_horiz(name, output_size, src1_size, src2_size, src3_size,
702 src4_size, const_expr):
703 opcode(name, output_size, tuint,
704 [src1_size, src2_size, src3_size, src4_size],
705 [tuint, tuint, tuint, tuint],
706 "", const_expr)
707
708 opcode("bitfield_insert", 0, tuint32, [0, 0, 0, 0],
709 [tuint32, tuint32, tint32, tint32], "", """
710 unsigned base = src0, insert = src1;
711 int offset = src2, bits = src3;
712 if (bits == 0) {
713 dst = 0;
714 } else if (offset < 0 || bits < 0 || bits + offset > 32) {
715 dst = 0;
716 } else {
717 unsigned mask = ((1ull << bits) - 1) << offset;
718 dst = (base & ~mask) | ((insert << bits) & mask);
719 }
720 """)
721
722 quadop_horiz("vec4", 4, 1, 1, 1, 1, """
723 dst.x = src0.x;
724 dst.y = src1.x;
725 dst.z = src2.x;
726 dst.w = src3.x;
727 """)
728
729