glsl: Add "built-in" function for 64-bit integer sign()
authorIan Romanick <ian.d.romanick@intel.com>
Mon, 17 Oct 2016 20:55:27 +0000 (13:55 -0700)
committerIan Romanick <ian.d.romanick@intel.com>
Fri, 20 Jan 2017 23:41:23 +0000 (15:41 -0800)
These functions are directly available in shaders.  A #define is added
to detect the presence.  This allows these functions to be tested using
piglit regardless of whether the driver uses them for lowering.  The
GLSL spec says that functions and macros beginning with __ are reserved
for use by the implementation... hey, that's us!

Signed-off-by: Ian Romanick <ian.d.romanick@intel.com>
Reviewed-by: Matt Turner <mattst88@gmail.com>
src/compiler/glsl/builtin_functions.cpp
src/compiler/glsl/builtin_functions.h
src/compiler/glsl/builtin_int64.h
src/compiler/glsl/glcpp/glcpp-parse.y
src/compiler/glsl/int64.glsl
src/compiler/glsl/udivmod64.h [new file with mode: 0644]

index a043c9d4dc87a88db63a047efac3de53f8f95a23..f64ab6a5f33c99cf3eab64aaeea0be7ed8857db3 100644 (file)
@@ -3099,6 +3099,10 @@ builtin_builder::create_builtins()
    add_function("allInvocationsARB", _vote(ir_unop_vote_all), NULL);
    add_function("allInvocationsEqualARB", _vote(ir_unop_vote_eq), NULL);
 
+   add_function("__builtin_sign64",
+                generate_ir::sign64(mem_ctx, integer_functions_supported),
+                NULL);
+
    add_function("__builtin_umul64",
                 generate_ir::umul64(mem_ctx, integer_functions_supported),
                 NULL);
index a79fb974fbee0a5267ad32b9c89a97fb8c34f5f0..c66f523f6927c5422615ea2f0832a7ba4ed4d05b 100644 (file)
@@ -48,6 +48,9 @@ namespace generate_ir {
 ir_function_signature *
 umul64(void *mem_ctx, builtin_available_predicate avail);
 
+ir_function_signature *
+sign64(void *mem_ctx, builtin_available_predicate avail);
+
 }
 
 #endif /* BULITIN_FUNCTIONS_H */
index 108da08ee4815476e7de1d56469d5fa9054a6ab4..c12565d14c78f3f2cce18d540610da319059eec4 100644 (file)
@@ -28,3 +28,29 @@ umul64(void *mem_ctx, builtin_available_predicate avail)
    sig->replace_parameters(&sig_parameters);
    return sig;
 }
+ir_function_signature *
+sign64(void *mem_ctx, builtin_available_predicate avail)
+{
+   ir_function_signature *const sig =
+      new(mem_ctx) ir_function_signature(glsl_type::ivec2_type, avail);
+   ir_factory body(&sig->body, mem_ctx);
+   sig->is_defined = true;
+
+   exec_list sig_parameters;
+
+   ir_variable *const r0007 = new(mem_ctx) ir_variable(glsl_type::ivec2_type, "a", ir_var_function_in);
+   sig_parameters.push_tail(r0007);
+   ir_variable *const r0008 = new(mem_ctx) ir_variable(glsl_type::ivec2_type, "result", ir_var_auto);
+   body.emit(r0008);
+   body.emit(assign(r0008, rshift(swizzle_y(r0007), body.constant(int(31))), 0x02));
+
+   ir_expression *const r0009 = bit_or(swizzle_x(r0007), swizzle_y(r0007));
+   ir_expression *const r000A = nequal(r0009, body.constant(int(0)));
+   ir_expression *const r000B = expr(ir_unop_b2i, r000A);
+   body.emit(assign(r0008, bit_or(swizzle_y(r0008), r000B), 0x01));
+
+   body.emit(ret(r0008));
+
+   sig->replace_parameters(&sig_parameters);
+   return sig;
+}
index ee553773670726c775e8a35dfc7021adbe528c3e..39a7a89258f90beeaa50c2b7e25296ad9e270d6e 100644 (file)
@@ -2343,6 +2343,7 @@ _glcpp_parser_handle_version_declaration(glcpp_parser_t *parser, intmax_t versio
        * those functions so that they can be tested.
        */
       if (parser->extension_list->MESA_shader_integer_functions) {
+         add_builtin_define(parser, "__have_builtin_builtin_sign64", 1);
          add_builtin_define(parser, "__have_builtin_builtin_umul64", 1);
       }
    }
index f5fb01013c76512c426e47bd4f31b547239df0f1..a2bec011e3e0771fd08afe11dc4a7999cf964342 100644 (file)
@@ -17,3 +17,14 @@ umul64(uvec2 a, uvec2 b)
 
    return result;
 }
+
+ivec2
+sign64(ivec2 a)
+{
+   ivec2 result;
+
+   result.y = a.y >> 31;
+   result.x = result.y | int((a.x | a.y) != 0);
+
+   return result;
+}
diff --git a/src/compiler/glsl/udivmod64.h b/src/compiler/glsl/udivmod64.h
new file mode 100644 (file)
index 0000000..b434e45
--- /dev/null
@@ -0,0 +1,206 @@
+ir_function_signature *
+udivmod64(void *mem_ctx, ir_factory &body)
+{
+   ir_function_signature *const sig =
+      new(mem_ctx) ir_function_signature(glsl_type::uvec4_type);
+   exec_list sig_parameters;
+
+   ir_variable *const r0001 = new(mem_ctx) ir_variable(glsl_type::uvec2_type, "numer", ir_var_function_in);
+   sig_parameters.push_tail(r0001);
+   ir_variable *const r0002 = new(mem_ctx) ir_variable(glsl_type::uvec2_type, "denom", ir_var_function_in);
+   sig_parameters.push_tail(r0002);
+   ir_variable *const r0003 = new(mem_ctx) ir_variable(glsl_type::int_type, "i", ir_var_auto);
+   body.emit(r0003);
+   ir_variable *const r0004 = new(mem_ctx) ir_variable(glsl_type::uint64_t_type, "n64", ir_var_auto);
+   body.emit(r0004);
+   ir_variable *const r0005 = new(mem_ctx) ir_variable(glsl_type::int_type, "log2_denom", ir_var_auto);
+   body.emit(r0005);
+   ir_variable *const r0006 = new(mem_ctx) ir_variable(glsl_type::uvec2_type, "quot", ir_var_auto);
+   body.emit(r0006);
+   body.emit(assign(r0006, ir_constant::zero(mem_ctx, glsl_type::uvec2_type), 0x03));
+
+   ir_expression *const r0007 = expr(ir_unop_find_msb, swizzle_y(r0002));
+   body.emit(assign(r0005, add(r0007, body.constant(int(32))), 0x01));
+
+   /* IF CONDITION */
+   ir_expression *const r0009 = equal(swizzle_y(r0002), body.constant(0u));
+   ir_expression *const r000A = nequal(swizzle_y(r0001), body.constant(0u));
+   ir_expression *const r000B = logic_and(r0009, r000A);
+   ir_if *f0008 = new(mem_ctx) ir_if(operand(r000B).val);
+   exec_list *const f0008_parent_instructions = body.instructions;
+
+      /* THEN INSTRUCTIONS */
+      body.instructions = &f0008->then_instructions;
+
+      ir_variable *const r000C = new(mem_ctx) ir_variable(glsl_type::int_type, "i", ir_var_auto);
+      body.emit(r000C);
+      ir_variable *const r000D = body.make_temp(glsl_type::int_type, "findMSB_retval");
+      body.emit(assign(r000D, expr(ir_unop_find_msb, swizzle_x(r0002)), 0x01));
+
+      body.emit(assign(r0005, r000D, 0x01));
+
+      body.emit(assign(r000C, sub(body.constant(int(31)), r000D), 0x01));
+
+      /* LOOP BEGIN */
+      ir_loop *f000E = new(mem_ctx) ir_loop();
+      exec_list *const f000E_parent_instructions = body.instructions;
+
+         body.instructions = &f000E->body_instructions;
+
+         /* IF CONDITION */
+         ir_expression *const r0010 = less(r000C, body.constant(int(1)));
+         ir_if *f000F = new(mem_ctx) ir_if(operand(r0010).val);
+         exec_list *const f000F_parent_instructions = body.instructions;
+
+            /* THEN INSTRUCTIONS */
+            body.instructions = &f000F->then_instructions;
+
+            body.emit(new(mem_ctx) ir_loop_jump(ir_loop_jump::jump_break));
+
+
+         body.instructions = f000F_parent_instructions;
+         body.emit(f000F);
+
+         /* END IF */
+
+         /* IF CONDITION */
+         ir_expression *const r0012 = lshift(swizzle_x(r0002), r000C);
+         ir_expression *const r0013 = lequal(r0012, swizzle_y(r0001));
+         ir_if *f0011 = new(mem_ctx) ir_if(operand(r0013).val);
+         exec_list *const f0011_parent_instructions = body.instructions;
+
+            /* THEN INSTRUCTIONS */
+            body.instructions = &f0011->then_instructions;
+
+            ir_expression *const r0014 = lshift(swizzle_x(r0002), r000C);
+            body.emit(assign(r0001, sub(swizzle_y(r0001), r0014), 0x02));
+
+            ir_expression *const r0015 = lshift(body.constant(1u), r000C);
+            body.emit(assign(r0006, bit_or(swizzle_y(r0006), r0015), 0x02));
+
+
+         body.instructions = f0011_parent_instructions;
+         body.emit(f0011);
+
+         /* END IF */
+
+         body.emit(assign(r000C, add(r000C, body.constant(int(-1))), 0x01));
+
+      /* LOOP END */
+
+      body.instructions = f000E_parent_instructions;
+      body.emit(f000E);
+
+      /* IF CONDITION */
+      ir_expression *const r0017 = lequal(swizzle_x(r0002), swizzle_y(r0001));
+      ir_if *f0016 = new(mem_ctx) ir_if(operand(r0017).val);
+      exec_list *const f0016_parent_instructions = body.instructions;
+
+         /* THEN INSTRUCTIONS */
+         body.instructions = &f0016->then_instructions;
+
+         body.emit(assign(r0001, sub(swizzle_y(r0001), swizzle_x(r0002)), 0x02));
+
+         body.emit(assign(r0006, bit_or(swizzle_y(r0006), body.constant(1u)), 0x02));
+
+
+      body.instructions = f0016_parent_instructions;
+      body.emit(f0016);
+
+      /* END IF */
+
+
+   body.instructions = f0008_parent_instructions;
+   body.emit(f0008);
+
+   /* END IF */
+
+   body.emit(assign(r0004, expr(ir_unop_pack_uint_2x32, r0001), 0x01));
+
+   ir_expression *const r0018 = sub(body.constant(int(63)), r0005);
+   body.emit(assign(r0003, expr(ir_binop_min, body.constant(int(31)), r0018), 0x01));
+
+   /* LOOP BEGIN */
+   ir_loop *f0019 = new(mem_ctx) ir_loop();
+   exec_list *const f0019_parent_instructions = body.instructions;
+
+      body.instructions = &f0019->body_instructions;
+
+      /* IF CONDITION */
+      ir_expression *const r001B = less(r0003, body.constant(int(1)));
+      ir_if *f001A = new(mem_ctx) ir_if(operand(r001B).val);
+      exec_list *const f001A_parent_instructions = body.instructions;
+
+         /* THEN INSTRUCTIONS */
+         body.instructions = &f001A->then_instructions;
+
+         body.emit(new(mem_ctx) ir_loop_jump(ir_loop_jump::jump_break));
+
+
+      body.instructions = f001A_parent_instructions;
+      body.emit(f001A);
+
+      /* END IF */
+
+      ir_variable *const r001C = body.make_temp(glsl_type::uint64_t_type, "assignment_tmp");
+      ir_expression *const r001D = expr(ir_unop_pack_uint_2x32, r0002);
+      body.emit(assign(r001C, lshift(r001D, r0003), 0x01));
+
+      /* IF CONDITION */
+      ir_expression *const r001F = lequal(r001C, r0004);
+      ir_if *f001E = new(mem_ctx) ir_if(operand(r001F).val);
+      exec_list *const f001E_parent_instructions = body.instructions;
+
+         /* THEN INSTRUCTIONS */
+         body.instructions = &f001E->then_instructions;
+
+         body.emit(assign(r0004, sub(r0004, r001C), 0x01));
+
+         ir_expression *const r0020 = lshift(body.constant(1u), r0003);
+         body.emit(assign(r0006, bit_or(swizzle_x(r0006), r0020), 0x01));
+
+
+      body.instructions = f001E_parent_instructions;
+      body.emit(f001E);
+
+      /* END IF */
+
+      body.emit(assign(r0003, add(r0003, body.constant(int(-1))), 0x01));
+
+   /* LOOP END */
+
+   body.instructions = f0019_parent_instructions;
+   body.emit(f0019);
+
+   ir_variable *const r0021 = body.make_temp(glsl_type::uint64_t_type, "packUint2x32_retval");
+   body.emit(assign(r0021, expr(ir_unop_pack_uint_2x32, r0002), 0x01));
+
+   /* IF CONDITION */
+   ir_expression *const r0023 = lequal(r0021, r0004);
+   ir_if *f0022 = new(mem_ctx) ir_if(operand(r0023).val);
+   exec_list *const f0022_parent_instructions = body.instructions;
+
+      /* THEN INSTRUCTIONS */
+      body.instructions = &f0022->then_instructions;
+
+      ir_expression *const r0024 = expr(ir_unop_pack_uint_2x32, r0002);
+      body.emit(assign(r0004, sub(r0004, r0024), 0x01));
+
+      body.emit(assign(r0006, bit_or(swizzle_x(r0006), body.constant(1u)), 0x01));
+
+
+   body.instructions = f0022_parent_instructions;
+   body.emit(f0022);
+
+   /* END IF */
+
+   ir_variable *const r0025 = body.make_temp(glsl_type::uvec4_type, "vec_ctor");
+   body.emit(assign(r0025, r0006, 0x03));
+
+   body.emit(assign(r0025, expr(ir_unop_unpack_uint_2x32, r0004), 0x0c));
+
+   body.emit(ret(r0025));
+
+   sig->replace_parameters(&sig_parameters);
+   return sig;
+}