+ /* NIR hack to pass through
+ * TGSI_PROPERTY_FS_COLOR0_WRITES_ALL_CBUFS */
+ if (semantic_name == TGSI_SEMANTIC_COLOR &&
+ semantic_index == -1)
+ semantic_index = 0;
+
+ for (int i = 0; i < 4; i++) {
+ add_output(c,
+ loc + i,
+ semantic_name,
+ semantic_index,
+ i);
+ }
+
+ switch (semantic_name) {
+ case TGSI_SEMANTIC_POSITION:
+ c->output_position_index = loc;
+ break;
+ case TGSI_SEMANTIC_CLIPVERTEX:
+ c->output_clipvertex_index = loc;
+ break;
+ case TGSI_SEMANTIC_COLOR:
+ c->output_color_index = loc;
+ break;
+ case TGSI_SEMANTIC_PSIZE:
+ c->output_point_size_index = loc;
+ break;
+ }
+
+ }
+}
+
+static void
+ntq_setup_uniforms(struct vc4_compile *c)
+{
+ foreach_list_typed(nir_variable, var, node, &c->s->uniforms) {
+ unsigned array_len = MAX2(glsl_get_length(var->type), 1);
+ unsigned array_elem_size = 4 * sizeof(float);
+
+ declare_uniform_range(c, var->data.driver_location * array_elem_size,
+ array_len * array_elem_size);
+
+ }
+}
+
+/**
+ * Sets up the mapping from nir_register to struct qreg *.
+ *
+ * Each nir_register gets a struct qreg per 32-bit component being stored.
+ */
+static void
+ntq_setup_registers(struct vc4_compile *c, struct exec_list *list)
+{
+ foreach_list_typed(nir_register, nir_reg, node, list) {
+ unsigned array_len = MAX2(nir_reg->num_array_elems, 1);
+ struct qreg *qregs = ralloc_array(c->def_ht, struct qreg,
+ array_len *
+ nir_reg->num_components);
+
+ _mesa_hash_table_insert(c->def_ht, nir_reg, qregs);
+
+ for (int i = 0; i < array_len * nir_reg->num_components; i++)
+ qregs[i] = qir_uniform_ui(c, 0);
+ }
+}
+
+static void
+ntq_emit_load_const(struct vc4_compile *c, nir_load_const_instr *instr)
+{
+ struct qreg *qregs = ralloc_array(c->def_ht, struct qreg,
+ instr->def.num_components);
+ for (int i = 0; i < instr->def.num_components; i++)
+ qregs[i] = qir_uniform_ui(c, instr->value.u[i]);
+
+ _mesa_hash_table_insert(c->def_ht, &instr->def, qregs);
+}
+
+static void
+ntq_emit_intrinsic(struct vc4_compile *c, nir_intrinsic_instr *instr)
+{
+ const nir_intrinsic_info *info = &nir_intrinsic_infos[instr->intrinsic];
+ struct qreg *dest = NULL;
+
+ if (info->has_dest) {
+ dest = ntq_get_dest(c, instr->dest);
+ }
+
+ switch (instr->intrinsic) {
+ case nir_intrinsic_load_uniform:
+ for (int i = 0; i < instr->num_components; i++) {
+ dest[i] = qir_uniform(c, QUNIFORM_UNIFORM,
+ instr->const_index[0] * 4 + i);
+ }
+ break;
+
+ case nir_intrinsic_load_uniform_indirect:
+ for (int i = 0; i < instr->num_components; i++) {
+ dest[i] = indirect_uniform_load(c,
+ ntq_get_src(c, instr->src[0], 0),
+ (instr->const_index[0] *
+ 4 + i) * sizeof(float));
+ }
+
+ break;
+
+ case nir_intrinsic_load_input:
+ assert(instr->num_components == 1);
+ *dest = c->inputs[instr->const_index[0]];
+
+ break;
+
+ case nir_intrinsic_store_output:
+ assert(instr->num_components == 1);
+ c->outputs[instr->const_index[0]] =
+ qir_MOV(c, ntq_get_src(c, instr->src[0], 0));
+ c->num_outputs = MAX2(c->num_outputs, instr->const_index[0] + 1);
+ break;
+
+ case nir_intrinsic_discard:
+ c->discard = qir_uniform_ui(c, ~0);
+ break;
+
+ case nir_intrinsic_discard_if:
+ if (c->discard.file == QFILE_NULL)
+ c->discard = qir_uniform_ui(c, 0);
+ c->discard = qir_OR(c, c->discard,
+ ntq_get_src(c, instr->src[0], 0));
+ break;
+
+ default:
+ fprintf(stderr, "Unknown intrinsic: ");
+ nir_print_instr(&instr->instr, stderr);
+ fprintf(stderr, "\n");
+ break;
+ }
+}
+
+static void
+ntq_emit_if(struct vc4_compile *c, nir_if *if_stmt)
+{
+ fprintf(stderr, "general IF statements not handled.\n");
+}
+
+static void
+ntq_emit_instr(struct vc4_compile *c, nir_instr *instr)
+{
+ switch (instr->type) {
+ case nir_instr_type_alu:
+ ntq_emit_alu(c, nir_instr_as_alu(instr));
+ break;
+
+ case nir_instr_type_intrinsic:
+ ntq_emit_intrinsic(c, nir_instr_as_intrinsic(instr));
+ break;
+
+ case nir_instr_type_load_const:
+ ntq_emit_load_const(c, nir_instr_as_load_const(instr));
+ break;
+
+ case nir_instr_type_tex:
+ ntq_emit_tex(c, nir_instr_as_tex(instr));
+ break;
+
+ default:
+ fprintf(stderr, "Unknown NIR instr type: ");
+ nir_print_instr(instr, stderr);
+ fprintf(stderr, "\n");
+ abort();
+ }
+}
+
+static void
+ntq_emit_block(struct vc4_compile *c, nir_block *block)
+{
+ nir_foreach_instr(block, instr) {
+ ntq_emit_instr(c, instr);
+ }
+}
+
+static void
+ntq_emit_cf_list(struct vc4_compile *c, struct exec_list *list)
+{
+ foreach_list_typed(nir_cf_node, node, node, list) {
+ switch (node->type) {
+ /* case nir_cf_node_loop: */
+ case nir_cf_node_block:
+ ntq_emit_block(c, nir_cf_node_as_block(node));
+ break;
+
+ case nir_cf_node_if:
+ ntq_emit_if(c, nir_cf_node_as_if(node));
+ break;
+
+ default:
+ assert(0);
+ }
+ }
+}
+
+static void
+ntq_emit_impl(struct vc4_compile *c, nir_function_impl *impl)
+{
+ ntq_setup_registers(c, &impl->registers);
+ ntq_emit_cf_list(c, &impl->body);
+}
+
+static void
+nir_to_qir(struct vc4_compile *c)
+{
+ ntq_setup_inputs(c);
+ ntq_setup_outputs(c);
+ ntq_setup_uniforms(c);
+ ntq_setup_registers(c, &c->s->registers);
+
+ /* Find the main function and emit the body. */
+ nir_foreach_overload(c->s, overload) {
+ assert(strcmp(overload->function->name, "main") == 0);
+ assert(overload->impl);
+ ntq_emit_impl(c, overload->impl);
+ }
+}
+
+static const nir_shader_compiler_options nir_options = {
+ .lower_ffma = true,
+ .lower_flrp = true,
+ .lower_fpow = true,
+ .lower_fsat = true,
+ .lower_fsqrt = true,
+ .lower_negate = true,
+};
+
+static bool
+count_nir_instrs_in_block(nir_block *block, void *state)
+{
+ int *count = (int *) state;
+ nir_foreach_instr(block, instr) {
+ *count = *count + 1;
+ }
+ return true;
+}
+
+static int
+count_nir_instrs(nir_shader *nir)
+{
+ int count = 0;
+ nir_foreach_overload(nir, overload) {
+ if (!overload->impl)
+ continue;
+ nir_foreach_block(overload->impl, count_nir_instrs_in_block, &count);
+ }
+ return count;
+}
+
+static struct vc4_compile *
+vc4_shader_ntq(struct vc4_context *vc4, enum qstage stage,
+ struct vc4_key *key)
+{
+ struct vc4_compile *c = qir_compile_init();
+
+ c->stage = stage;
+ c->shader_state = &key->shader_state->base;
+ c->program_id = key->shader_state->program_id;
+ c->variant_id = key->shader_state->compiled_variant_count++;
+
+ c->key = key;
+ switch (stage) {
+ case QSTAGE_FRAG:
+ c->fs_key = (struct vc4_fs_key *)key;
+ if (c->fs_key->is_points) {
+ c->point_x = emit_fragment_varying(c, ~0, ~0, 0);
+ c->point_y = emit_fragment_varying(c, ~0, ~0, 0);
+ } else if (c->fs_key->is_lines) {
+ c->line_x = emit_fragment_varying(c, ~0, ~0, 0);
+ }
+ break;
+ case QSTAGE_VERT:
+ c->vs_key = (struct vc4_vs_key *)key;
+ break;
+ case QSTAGE_COORD:
+ c->vs_key = (struct vc4_vs_key *)key;
+ break;
+ }
+
+ const struct tgsi_token *tokens = key->shader_state->base.tokens;
+ if (c->fs_key && c->fs_key->light_twoside) {
+ if (!key->shader_state->twoside_tokens) {
+ const struct tgsi_lowering_config lowering_config = {
+ .color_two_side = true,
+ };
+ struct tgsi_shader_info info;
+ key->shader_state->twoside_tokens =
+ tgsi_transform_lowering(&lowering_config,
+ key->shader_state->base.tokens,
+ &info);
+
+ /* If no transformation occurred, then NULL is
+ * returned and we just use our original tokens.
+ */
+ if (!key->shader_state->twoside_tokens) {
+ key->shader_state->twoside_tokens =
+ key->shader_state->base.tokens;
+ }
+ }
+ tokens = key->shader_state->twoside_tokens;
+ }
+
+ if (vc4_debug & VC4_DEBUG_TGSI) {
+ fprintf(stderr, "%s prog %d/%d TGSI:\n",
+ qir_get_stage_name(c->stage),
+ c->program_id, c->variant_id);
+ tgsi_dump(tokens, 0);
+ }
+
+ c->s = tgsi_to_nir(tokens, &nir_options);
+ nir_opt_global_to_local(c->s);
+ nir_convert_to_ssa(c->s);
+ vc4_nir_lower_io(c);
+ nir_lower_idiv(c->s);
+
+ vc4_optimize_nir(c->s);
+
+ nir_remove_dead_variables(c->s);
+
+ nir_convert_from_ssa(c->s, false);