+static void debug_function(void *private_data,
+ enum nir_spirv_debug_level level, size_t spirv_offset,
+ const char *message)
+{
+ assert(private_data);
+ auto r_log = reinterpret_cast<std::string *>(private_data);
+ *r_log += message;
+}
+
+struct clover_lower_nir_state {
+ std::vector<module::argument> &args;
+ uint32_t global_dims;
+ nir_variable *offset_vars[3];
+};
+
+static bool
+clover_lower_nir_filter(const nir_instr *instr, const void *)
+{
+ return instr->type == nir_instr_type_intrinsic;
+}
+
+static nir_ssa_def *
+clover_lower_nir_instr(nir_builder *b, nir_instr *instr, void *_state)
+{
+ clover_lower_nir_state *state = reinterpret_cast<clover_lower_nir_state*>(_state);
+ nir_intrinsic_instr *intrinsic = nir_instr_as_intrinsic(instr);
+
+ switch (intrinsic->intrinsic) {
+ case nir_intrinsic_load_base_global_invocation_id: {
+ nir_ssa_def *loads[3];
+
+ /* create variables if we didn't do so alrady */
+ if (!state->offset_vars[0]) {
+ /* TODO: fix for 64 bit */
+ /* Even though we only place one scalar argument, clover will bind up to
+ * three 32 bit values
+ */
+ state->args.emplace_back(module::argument::scalar, 4, 4, 4,
+ module::argument::zero_ext,
+ module::argument::grid_offset);
+
+ const glsl_type *type = glsl_uint_type();
+ for (uint32_t i = 0; i < 3; i++) {
+ state->offset_vars[i] =
+ nir_variable_create(b->shader, nir_var_uniform, type,
+ "global_invocation_id_offsets");
+ state->offset_vars[i]->data.location = b->shader->num_uniforms++;
+ }
+ }
+
+ for (int i = 0; i < 3; i++) {
+ nir_variable *var = state->offset_vars[i];
+ loads[i] = var ? nir_load_var(b, var) : nir_imm_int(b, 0);
+ }
+
+ return nir_u2u(b, nir_vec(b, loads, state->global_dims),
+ nir_dest_bit_size(intrinsic->dest));
+ }
+ default:
+ return NULL;
+ }
+}
+
+static bool
+clover_lower_nir(nir_shader *nir, std::vector<module::argument> &args, uint32_t dims)
+{
+ clover_lower_nir_state state = { args, dims };
+ return nir_shader_lower_instructions(nir,
+ clover_lower_nir_filter, clover_lower_nir_instr, &state);
+}
+