8cad74832a6d29a5886588063b3121e92696bc27
[mesa.git] / src / compiler / nir / nir_opcodes.py
1 #
2 # Copyright (C) 2014 Connor Abbott
3 #
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:
10 #
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
13 # Software.
14 #
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
21 # IN THE SOFTWARE.
22 #
23 # Authors:
24 # Connor Abbott (cwabbott0@gmail.com)
25
26
27 # Class that represents all the information we have about the opcode
28 # NOTE: this must be kept in sync with nir_op_info
29
30 class Opcode(object):
31 """Class that represents all the information we have about the opcode
32 NOTE: this must be kept in sync with nir_op_info
33 """
34 def __init__(self, name, output_size, output_type, input_sizes,
35 input_types, algebraic_properties, const_expr):
36 """Parameters:
37
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.
45
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.
55
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.
64 """
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:
77 assert 0 <= size <= 4
78 if output_size != 0:
79 assert size != 0
80 self.name = name
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
88
89 # helper variables for strings
90 tfloat = "float"
91 tint = "int"
92 tbool = "bool32"
93 tuint = "uint"
94 tfloat32 = "float32"
95 tint32 = "int32"
96 tuint32 = "uint32"
97 tint64 = "int64"
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, ("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, "bit_size == 64 ? fabs(src0) : fabsf(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)")
168 unop_convert("f2i", tint32, tfloat32, "src0") # Float-to-integer conversion.
169 unop_convert("f2u", tuint32, tfloat32, "src0") # Float-to-unsigned conversion
170 unop_convert("d2i", tint32, tfloat64, "src0") # Double-to-integer conversion.
171 unop_convert("d2u", tuint32, tfloat64, "src0") # Double-to-unsigned conversion.
172 unop_convert("i2f", tfloat32, tint32, "src0") # Integer-to-float conversion.
173 unop_convert("i2d", tfloat64, tint32, "src0") # Integer-to-double conversion.
174 unop_convert("i2i32", tint32, tint, "src0") # General int (int8_t, int64_t, etc.) to int32_t conversion
175 unop_convert("u2i32", tint32, tuint, "src0") # General uint (uint8_t, uint64_t, etc.) to int32_t conversion
176 unop_convert("i2u32", tuint32, tint, "src0") # General int (int8_t, int64_t, etc.) to uint32_t conversion
177 unop_convert("u2u32", tuint32, tuint, "src0") # General uint (uint8_t, uint64_t, etc.) to uint32_t conversion
178 unop_convert("i2i64", tint64, tint, "src0") # General int (int8_t, int32_t, etc.) to int64_t conversion
179 unop_convert("u2i64", tint64, tuint, "src0") # General uint (uint8_t, uint64_t, etc.) to int64_t conversion
180 unop_convert("f2i64", tint64, tfloat, "src0") # General float (float or double) to int64_t conversion
181 unop_convert("i2u64", tuint64, tint, "src0") # General int (int8_t, int64_t, etc.) to uint64_t conversion
182 unop_convert("u2u64", tuint64, tuint, "src0") # General uint (uint8_t, uint32_t, etc.) to uint64_t conversion
183 unop_convert("f2u64", tuint64, tfloat, "src0") # General float (float or double) to uint64_t conversion
184 unop_convert("i642f", tfloat32, tint64, "src0") # int64_t-to-float conversion.
185 unop_convert("i642b", tbool, tint64, "src0") # int64_t-to-bool conversion.
186 unop_convert("i642d", tfloat64, tint64, "src0") # int64_t-to-double conversion.
187 unop_convert("u642f", tfloat32, tuint64, "src0") # uint64_t-to-float conversion.
188 unop_convert("u642d", tfloat64, tuint64, "src0") # uint64_t-to-double conversion.
189
190 # Float-to-boolean conversion
191 unop_convert("f2b", tbool, tfloat32, "src0 != 0.0f")
192 unop_convert("d2b", tbool, tfloat64, "src0 != 0.0")
193 # Boolean-to-float conversion
194 unop_convert("b2f", tfloat32, tbool, "src0 ? 1.0f : 0.0f")
195 # Int-to-boolean conversion
196 unop_convert("i2b", tbool, tint, "src0 != 0")
197 unop_convert("b2i", tint32, tbool, "src0 ? 1 : 0") # Boolean-to-int conversion
198 unop_convert("b2i64", tint64, tbool, "src0 ? 1 : 0") # Boolean-to-int64_t conversion.
199 unop_convert("u2f", tfloat32, tuint32, "src0") # Unsigned-to-float conversion.
200 unop_convert("u2d", tfloat64, tuint32, "src0") # Unsigned-to-double conversion.
201 # double-to-float conversion
202 unop_convert("d2f", tfloat32, tfloat64, "src0") # Double to single precision
203 unop_convert("f2d", tfloat64, tfloat32, "src0") # Single to double precision
204
205 # Unary floating-point rounding operations.
206
207
208 unop("ftrunc", tfloat, "bit_size == 64 ? trunc(src0) : truncf(src0)")
209 unop("fceil", tfloat, "bit_size == 64 ? ceil(src0) : ceilf(src0)")
210 unop("ffloor", tfloat, "bit_size == 64 ? floor(src0) : floorf(src0)")
211 unop("ffract", tfloat, "src0 - (bit_size == 64 ? floor(src0) : floorf(src0))")
212 unop("fround_even", tfloat, "bit_size == 64 ? _mesa_roundeven(src0) : _mesa_roundevenf(src0)")
213
214 unop("fquantize2f16", tfloat, "(fabs(src0) < ldexpf(1.0, -14)) ? copysignf(0.0f, src0) : _mesa_half_to_float(_mesa_float_to_half(src0))")
215
216 # Trigonometric operations.
217
218
219 unop("fsin", tfloat, "bit_size == 64 ? sin(src0) : sinf(src0)")
220 unop("fcos", tfloat, "bit_size == 64 ? cos(src0) : cosf(src0)")
221
222
223 # Partial derivatives.
224
225
226 unop("fddx", tfloat, "0.0") # the derivative of a constant is 0.
227 unop("fddy", tfloat, "0.0")
228 unop("fddx_fine", tfloat, "0.0")
229 unop("fddy_fine", tfloat, "0.0")
230 unop("fddx_coarse", tfloat, "0.0")
231 unop("fddy_coarse", tfloat, "0.0")
232
233
234 # Floating point pack and unpack operations.
235
236 def pack_2x16(fmt):
237 unop_horiz("pack_" + fmt + "_2x16", 1, tuint32, 2, tfloat32, """
238 dst.x = (uint32_t) pack_fmt_1x16(src0.x);
239 dst.x |= ((uint32_t) pack_fmt_1x16(src0.y)) << 16;
240 """.replace("fmt", fmt))
241
242 def pack_4x8(fmt):
243 unop_horiz("pack_" + fmt + "_4x8", 1, tuint32, 4, tfloat32, """
244 dst.x = (uint32_t) pack_fmt_1x8(src0.x);
245 dst.x |= ((uint32_t) pack_fmt_1x8(src0.y)) << 8;
246 dst.x |= ((uint32_t) pack_fmt_1x8(src0.z)) << 16;
247 dst.x |= ((uint32_t) pack_fmt_1x8(src0.w)) << 24;
248 """.replace("fmt", fmt))
249
250 def unpack_2x16(fmt):
251 unop_horiz("unpack_" + fmt + "_2x16", 2, tfloat32, 1, tuint32, """
252 dst.x = unpack_fmt_1x16((uint16_t)(src0.x & 0xffff));
253 dst.y = unpack_fmt_1x16((uint16_t)(src0.x << 16));
254 """.replace("fmt", fmt))
255
256 def unpack_4x8(fmt):
257 unop_horiz("unpack_" + fmt + "_4x8", 4, tfloat32, 1, tuint32, """
258 dst.x = unpack_fmt_1x8((uint8_t)(src0.x & 0xff));
259 dst.y = unpack_fmt_1x8((uint8_t)((src0.x >> 8) & 0xff));
260 dst.z = unpack_fmt_1x8((uint8_t)((src0.x >> 16) & 0xff));
261 dst.w = unpack_fmt_1x8((uint8_t)(src0.x >> 24));
262 """.replace("fmt", fmt))
263
264
265 pack_2x16("snorm")
266 pack_4x8("snorm")
267 pack_2x16("unorm")
268 pack_4x8("unorm")
269 pack_2x16("half")
270 unpack_2x16("snorm")
271 unpack_4x8("snorm")
272 unpack_2x16("unorm")
273 unpack_4x8("unorm")
274 unpack_2x16("half")
275
276 unop_horiz("pack_uvec2_to_uint", 1, tuint32, 2, tuint32, """
277 dst.x = (src0.x & 0xffff) | (src0.y << 16);
278 """)
279
280 unop_horiz("pack_uvec4_to_uint", 1, tuint32, 4, tuint32, """
281 dst.x = (src0.x << 0) |
282 (src0.y << 8) |
283 (src0.z << 16) |
284 (src0.w << 24);
285 """)
286
287 unop_horiz("pack_64_2x32", 1, tuint64, 2, tuint32,
288 "dst.x = src0.x | ((uint64_t)src0.y << 32);")
289
290 unop_horiz("unpack_64_2x32", 2, tuint32, 1, tuint64,
291 "dst.x = src0.x; dst.y = src0.x >> 32;")
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_64_2x32_split_x", tuint32, tuint64, "src0")
302 unop_convert("unpack_64_2x32_split_y", tuint32, tuint64, "src0 >> 32")
303
304 # Bit operations, part of ARB_gpu_shader5.
305
306
307 unop("bitfield_reverse", tuint32, """
308 /* we're not winning any awards for speed here, but that's ok */
309 dst = 0;
310 for (unsigned bit = 0; bit < 32; bit++)
311 dst |= ((src0 >> bit) & 1) << (31 - bit);
312 """)
313 unop("bit_count", tuint32, """
314 dst = 0;
315 for (unsigned bit = 0; bit < 32; bit++) {
316 if ((src0 >> bit) & 1)
317 dst++;
318 }
319 """)
320
321 unop_convert("ufind_msb", tint32, tuint32, """
322 dst = -1;
323 for (int bit = 31; bit > 0; bit--) {
324 if ((src0 >> bit) & 1) {
325 dst = bit;
326 break;
327 }
328 }
329 """)
330
331 unop("ifind_msb", tint32, """
332 dst = -1;
333 for (int bit = 31; bit >= 0; bit--) {
334 /* If src0 < 0, we're looking for the first 0 bit.
335 * if src0 >= 0, we're looking for the first 1 bit.
336 */
337 if ((((src0 >> bit) & 1) && (src0 >= 0)) ||
338 (!((src0 >> bit) & 1) && (src0 < 0))) {
339 dst = bit;
340 break;
341 }
342 }
343 """)
344
345 unop("find_lsb", tint32, """
346 dst = -1;
347 for (unsigned bit = 0; bit < 32; bit++) {
348 if ((src0 >> bit) & 1) {
349 dst = bit;
350 break;
351 }
352 }
353 """)
354
355
356 for i in xrange(1, 5):
357 for j in xrange(1, 5):
358 unop_horiz("fnoise{0}_{1}".format(i, j), i, tfloat, j, tfloat, "0.0f")
359
360 def binop_convert(name, out_type, in_type, alg_props, const_expr):
361 opcode(name, 0, out_type, [0, 0], [in_type, in_type], alg_props, const_expr)
362
363 def binop(name, ty, alg_props, const_expr):
364 binop_convert(name, ty, ty, alg_props, const_expr)
365
366 def binop_compare(name, ty, alg_props, const_expr):
367 binop_convert(name, tbool, ty, alg_props, const_expr)
368
369 def binop_horiz(name, out_size, out_type, src1_size, src1_type, src2_size,
370 src2_type, const_expr):
371 opcode(name, out_size, out_type, [src1_size, src2_size], [src1_type, src2_type],
372 "", const_expr)
373
374 def binop_reduce(name, output_size, output_type, src_type, prereduce_expr,
375 reduce_expr, final_expr):
376 def final(src):
377 return final_expr.format(src= "(" + src + ")")
378 def reduce_(src0, src1):
379 return reduce_expr.format(src0=src0, src1=src1)
380 def prereduce(src0, src1):
381 return "(" + prereduce_expr.format(src0=src0, src1=src1) + ")"
382 src0 = prereduce("src0.x", "src1.x")
383 src1 = prereduce("src0.y", "src1.y")
384 src2 = prereduce("src0.z", "src1.z")
385 src3 = prereduce("src0.w", "src1.w")
386 opcode(name + "2", output_size, output_type,
387 [2, 2], [src_type, src_type], commutative,
388 final(reduce_(src0, src1)))
389 opcode(name + "3", output_size, output_type,
390 [3, 3], [src_type, src_type], commutative,
391 final(reduce_(reduce_(src0, src1), src2)))
392 opcode(name + "4", output_size, output_type,
393 [4, 4], [src_type, src_type], commutative,
394 final(reduce_(reduce_(src0, src1), reduce_(src2, src3))))
395
396 binop("fadd", tfloat, commutative + associative, "src0 + src1")
397 binop("iadd", tint, commutative + associative, "src0 + src1")
398 binop("fsub", tfloat, "", "src0 - src1")
399 binop("isub", tint, "", "src0 - src1")
400
401 binop("fmul", tfloat, commutative + associative, "src0 * src1")
402 # low 32-bits of signed/unsigned integer multiply
403 binop("imul", tint, commutative + associative, "src0 * src1")
404 # high 32-bits of signed integer multiply
405 binop("imul_high", tint32, commutative,
406 "(int32_t)(((int64_t) src0 * (int64_t) src1) >> 32)")
407 # high 32-bits of unsigned integer multiply
408 binop("umul_high", tuint32, commutative,
409 "(uint32_t)(((uint64_t) src0 * (uint64_t) src1) >> 32)")
410
411 binop("fdiv", tfloat, "", "src0 / src1")
412 binop("idiv", tint, "", "src0 / src1")
413 binop("udiv", tuint, "", "src0 / src1")
414
415 # returns a boolean representing the carry resulting from the addition of
416 # the two unsigned arguments.
417
418 binop_convert("uadd_carry", tuint, tuint, commutative, "src0 + src1 < src0")
419
420 # returns a boolean representing the borrow resulting from the subtraction
421 # of the two unsigned arguments.
422
423 binop_convert("usub_borrow", tuint, tuint, "", "src0 < src1")
424
425 binop("umod", tuint, "", "src1 == 0 ? 0 : src0 % src1")
426
427 # For signed integers, there are several different possible definitions of
428 # "modulus" or "remainder". We follow the conventions used by LLVM and
429 # SPIR-V. The irem opcode implements the standard C/C++ signed "%"
430 # operation while the imod opcode implements the more mathematical
431 # "modulus" operation. For details on the difference, see
432 #
433 # http://mathforum.org/library/drmath/view/52343.html
434
435 binop("irem", tint, "", "src1 == 0 ? 0 : src0 % src1")
436 binop("imod", tint, "",
437 "src1 == 0 ? 0 : ((src0 % src1 == 0 || (src0 >= 0) == (src1 >= 0)) ?"
438 " src0 % src1 : src0 % src1 + src1)")
439 binop("fmod", tfloat, "", "src0 - src1 * floorf(src0 / src1)")
440 binop("frem", tfloat, "", "src0 - src1 * truncf(src0 / src1)")
441
442 #
443 # Comparisons
444 #
445
446
447 # these integer-aware comparisons return a boolean (0 or ~0)
448
449 binop_compare("flt", tfloat, "", "src0 < src1")
450 binop_compare("fge", tfloat, "", "src0 >= src1")
451 binop_compare("feq", tfloat, commutative, "src0 == src1")
452 binop_compare("fne", tfloat, commutative, "src0 != src1")
453 binop_compare("ilt", tint, "", "src0 < src1")
454 binop_compare("ige", tint, "", "src0 >= src1")
455 binop_compare("ieq", tint, commutative, "src0 == src1")
456 binop_compare("ine", tint, commutative, "src0 != src1")
457 binop_compare("ult", tuint, "", "src0 < src1")
458 binop_compare("uge", tuint, "", "src0 >= src1")
459
460 # integer-aware GLSL-style comparisons that compare floats and ints
461
462 binop_reduce("ball_fequal", 1, tbool, tfloat, "{src0} == {src1}",
463 "{src0} && {src1}", "{src}")
464 binop_reduce("bany_fnequal", 1, tbool, tfloat, "{src0} != {src1}",
465 "{src0} || {src1}", "{src}")
466 binop_reduce("ball_iequal", 1, tbool, tint, "{src0} == {src1}",
467 "{src0} && {src1}", "{src}")
468 binop_reduce("bany_inequal", 1, tbool, tint, "{src0} != {src1}",
469 "{src0} || {src1}", "{src}")
470
471 # non-integer-aware GLSL-style comparisons that return 0.0 or 1.0
472
473 binop_reduce("fall_equal", 1, tfloat32, tfloat32, "{src0} == {src1}",
474 "{src0} && {src1}", "{src} ? 1.0f : 0.0f")
475 binop_reduce("fany_nequal", 1, tfloat32, tfloat32, "{src0} != {src1}",
476 "{src0} || {src1}", "{src} ? 1.0f : 0.0f")
477
478 # These comparisons for integer-less hardware return 1.0 and 0.0 for true
479 # and false respectively
480
481 binop("slt", tfloat32, "", "(src0 < src1) ? 1.0f : 0.0f") # Set on Less Than
482 binop("sge", tfloat32, "", "(src0 >= src1) ? 1.0f : 0.0f") # Set on Greater or Equal
483 binop("seq", tfloat32, commutative, "(src0 == src1) ? 1.0f : 0.0f") # Set on Equal
484 binop("sne", tfloat32, commutative, "(src0 != src1) ? 1.0f : 0.0f") # Set on Not Equal
485
486
487 opcode("ishl", 0, tint, [0, 0], [tint, tuint32], "", "src0 << src1")
488 opcode("ishr", 0, tint, [0, 0], [tint, tuint32], "", "src0 >> src1")
489 opcode("ushr", 0, tuint, [0, 0], [tuint, tuint32], "", "src0 >> src1")
490
491 # bitwise logic operators
492 #
493 # These are also used as boolean and, or, xor for hardware supporting
494 # integers.
495
496
497 binop("iand", tuint, commutative + associative, "src0 & src1")
498 binop("ior", tuint, commutative + associative, "src0 | src1")
499 binop("ixor", tuint, commutative + associative, "src0 ^ src1")
500
501
502 # floating point logic operators
503 #
504 # These use (src != 0.0) for testing the truth of the input, and output 1.0
505 # for true and 0.0 for false
506
507 binop("fand", tfloat32, commutative,
508 "((src0 != 0.0f) && (src1 != 0.0f)) ? 1.0f : 0.0f")
509 binop("for", tfloat32, commutative,
510 "((src0 != 0.0f) || (src1 != 0.0f)) ? 1.0f : 0.0f")
511 binop("fxor", tfloat32, commutative,
512 "(src0 != 0.0f && src1 == 0.0f) || (src0 == 0.0f && src1 != 0.0f) ? 1.0f : 0.0f")
513
514 binop_reduce("fdot", 1, tfloat, tfloat, "{src0} * {src1}", "{src0} + {src1}",
515 "{src}")
516
517 binop_reduce("fdot_replicated", 4, tfloat, tfloat,
518 "{src0} * {src1}", "{src0} + {src1}", "{src}")
519
520 opcode("fdph", 1, tfloat, [3, 4], [tfloat, tfloat], "",
521 "src0.x * src1.x + src0.y * src1.y + src0.z * src1.z + src1.w")
522 opcode("fdph_replicated", 4, tfloat, [3, 4], [tfloat, tfloat], "",
523 "src0.x * src1.x + src0.y * src1.y + src0.z * src1.z + src1.w")
524
525 binop("fmin", tfloat, "", "fminf(src0, src1)")
526 binop("imin", tint, commutative + associative, "src1 > src0 ? src0 : src1")
527 binop("umin", tuint, commutative + associative, "src1 > src0 ? src0 : src1")
528 binop("fmax", tfloat, "", "fmaxf(src0, src1)")
529 binop("imax", tint, commutative + associative, "src1 > src0 ? src1 : src0")
530 binop("umax", tuint, commutative + associative, "src1 > src0 ? src1 : src0")
531
532 # Saturated vector add for 4 8bit ints.
533 binop("usadd_4x8", tint32, commutative + associative, """
534 dst = 0;
535 for (int i = 0; i < 32; i += 8) {
536 dst |= MIN2(((src0 >> i) & 0xff) + ((src1 >> i) & 0xff), 0xff) << i;
537 }
538 """)
539
540 # Saturated vector subtract for 4 8bit ints.
541 binop("ussub_4x8", tint32, "", """
542 dst = 0;
543 for (int i = 0; i < 32; i += 8) {
544 int src0_chan = (src0 >> i) & 0xff;
545 int src1_chan = (src1 >> i) & 0xff;
546 if (src0_chan > src1_chan)
547 dst |= (src0_chan - src1_chan) << i;
548 }
549 """)
550
551 # vector min for 4 8bit ints.
552 binop("umin_4x8", tint32, commutative + associative, """
553 dst = 0;
554 for (int i = 0; i < 32; i += 8) {
555 dst |= MIN2((src0 >> i) & 0xff, (src1 >> i) & 0xff) << i;
556 }
557 """)
558
559 # vector max for 4 8bit ints.
560 binop("umax_4x8", tint32, commutative + associative, """
561 dst = 0;
562 for (int i = 0; i < 32; i += 8) {
563 dst |= MAX2((src0 >> i) & 0xff, (src1 >> i) & 0xff) << i;
564 }
565 """)
566
567 # unorm multiply: (a * b) / 255.
568 binop("umul_unorm_4x8", tint32, commutative + associative, """
569 dst = 0;
570 for (int i = 0; i < 32; i += 8) {
571 int src0_chan = (src0 >> i) & 0xff;
572 int src1_chan = (src1 >> i) & 0xff;
573 dst |= ((src0_chan * src1_chan) / 255) << i;
574 }
575 """)
576
577 binop("fpow", tfloat, "", "bit_size == 64 ? powf(src0, src1) : pow(src0, src1)")
578
579 binop_horiz("pack_half_2x16_split", 1, tuint32, 1, tfloat32, 1, tfloat32,
580 "pack_half_1x16(src0.x) | (pack_half_1x16(src1.x) << 16)")
581
582 binop_convert("pack_64_2x32_split", tuint64, tuint32, "",
583 "src0 | ((uint64_t)src1 << 32)")
584
585 # bfm implements the behavior of the first operation of the SM5 "bfi" assembly
586 # and that of the "bfi1" i965 instruction. That is, it has undefined behavior
587 # if either of its arguments are 32.
588 binop_convert("bfm", tuint32, tint32, "", """
589 int bits = src0, offset = src1;
590 if (offset < 0 || bits < 0 || offset > 31 || bits > 31 || offset + bits > 32)
591 dst = 0; /* undefined */
592 else
593 dst = ((1u << bits) - 1) << offset;
594 """)
595
596 opcode("ldexp", 0, tfloat, [0, 0], [tfloat, tint32], "", """
597 dst = (bit_size == 64) ? ldexp(src0, src1) : ldexpf(src0, src1);
598 /* flush denormals to zero. */
599 if (!isnormal(dst))
600 dst = copysignf(0.0f, src0);
601 """)
602
603 # Combines the first component of each input to make a 2-component vector.
604
605 binop_horiz("vec2", 2, tuint, 1, tuint, 1, tuint, """
606 dst.x = src0.x;
607 dst.y = src1.x;
608 """)
609
610 # Byte extraction
611 binop("extract_u8", tuint, "", "(uint8_t)(src0 >> (src1 * 8))")
612 binop("extract_i8", tint, "", "(int8_t)(src0 >> (src1 * 8))")
613
614 # Word extraction
615 binop("extract_u16", tuint, "", "(uint16_t)(src0 >> (src1 * 16))")
616 binop("extract_i16", tint, "", "(int16_t)(src0 >> (src1 * 16))")
617
618
619 def triop(name, ty, const_expr):
620 opcode(name, 0, ty, [0, 0, 0], [ty, ty, ty], "", const_expr)
621 def triop_horiz(name, output_size, src1_size, src2_size, src3_size, const_expr):
622 opcode(name, output_size, tuint,
623 [src1_size, src2_size, src3_size],
624 [tuint, tuint, tuint], "", const_expr)
625
626 triop("ffma", tfloat, "src0 * src1 + src2")
627
628 triop("flrp", tfloat, "src0 * (1 - src2) + src1 * src2")
629
630 # Conditional Select
631 #
632 # A vector conditional select instruction (like ?:, but operating per-
633 # component on vectors). There are two versions, one for floating point
634 # bools (0.0 vs 1.0) and one for integer bools (0 vs ~0).
635
636
637 triop("fcsel", tfloat32, "(src0 != 0.0f) ? src1 : src2")
638 opcode("bcsel", 0, tuint, [0, 0, 0],
639 [tbool, tuint, tuint], "", "src0 ? src1 : src2")
640
641 # SM5 bfi assembly
642 triop("bfi", tuint32, """
643 unsigned mask = src0, insert = src1, base = src2;
644 if (mask == 0) {
645 dst = base;
646 } else {
647 unsigned tmp = mask;
648 while (!(tmp & 1)) {
649 tmp >>= 1;
650 insert <<= 1;
651 }
652 dst = (base & ~mask) | (insert & mask);
653 }
654 """)
655
656 # SM5 ubfe/ibfe assembly
657 opcode("ubfe", 0, tuint32,
658 [0, 0, 0], [tuint32, tint32, tint32], "", """
659 unsigned base = src0;
660 int offset = src1, bits = src2;
661 if (bits == 0) {
662 dst = 0;
663 } else if (bits < 0 || offset < 0) {
664 dst = 0; /* undefined */
665 } else if (offset + bits < 32) {
666 dst = (base << (32 - bits - offset)) >> (32 - bits);
667 } else {
668 dst = base >> offset;
669 }
670 """)
671 opcode("ibfe", 0, tint32,
672 [0, 0, 0], [tint32, tint32, tint32], "", """
673 int base = src0;
674 int offset = src1, bits = src2;
675 if (bits == 0) {
676 dst = 0;
677 } else if (bits < 0 || offset < 0) {
678 dst = 0; /* undefined */
679 } else if (offset + bits < 32) {
680 dst = (base << (32 - bits - offset)) >> (32 - bits);
681 } else {
682 dst = base >> offset;
683 }
684 """)
685
686 # GLSL bitfieldExtract()
687 opcode("ubitfield_extract", 0, tuint32,
688 [0, 0, 0], [tuint32, tint32, tint32], "", """
689 unsigned base = src0;
690 int offset = src1, bits = src2;
691 if (bits == 0) {
692 dst = 0;
693 } else if (bits < 0 || offset < 0 || offset + bits > 32) {
694 dst = 0; /* undefined per the spec */
695 } else {
696 dst = (base >> offset) & ((1ull << bits) - 1);
697 }
698 """)
699 opcode("ibitfield_extract", 0, tint32,
700 [0, 0, 0], [tint32, tint32, tint32], "", """
701 int base = src0;
702 int offset = src1, bits = src2;
703 if (bits == 0) {
704 dst = 0;
705 } else if (offset < 0 || bits < 0 || offset + bits > 32) {
706 dst = 0;
707 } else {
708 dst = (base << (32 - offset - bits)) >> offset; /* use sign-extending shift */
709 }
710 """)
711
712 # Combines the first component of each input to make a 3-component vector.
713
714 triop_horiz("vec3", 3, 1, 1, 1, """
715 dst.x = src0.x;
716 dst.y = src1.x;
717 dst.z = src2.x;
718 """)
719
720 def quadop_horiz(name, output_size, src1_size, src2_size, src3_size,
721 src4_size, const_expr):
722 opcode(name, output_size, tuint,
723 [src1_size, src2_size, src3_size, src4_size],
724 [tuint, tuint, tuint, tuint],
725 "", const_expr)
726
727 opcode("bitfield_insert", 0, tuint32, [0, 0, 0, 0],
728 [tuint32, tuint32, tint32, tint32], "", """
729 unsigned base = src0, insert = src1;
730 int offset = src2, bits = src3;
731 if (bits == 0) {
732 dst = 0;
733 } else if (offset < 0 || bits < 0 || bits + offset > 32) {
734 dst = 0;
735 } else {
736 unsigned mask = ((1ull << bits) - 1) << offset;
737 dst = (base & ~mask) | ((insert << bits) & mask);
738 }
739 """)
740
741 quadop_horiz("vec4", 4, 1, 1, 1, 1, """
742 dst.x = src0.x;
743 dst.y = src1.x;
744 dst.z = src2.x;
745 dst.w = src3.x;
746 """)
747
748