anv: Move the physical device dispatch table to anv_instance
[mesa.git] / src / freedreno / ir3 / ir3.c
index 23b12a6fc5f2d064060f1fdb63eda0fe9fa848a3..18c2936caa720b9fc733d2a98d8f0f69d3c7b2e0 100644 (file)
@@ -45,17 +45,12 @@ void * ir3_alloc(struct ir3 *shader, int sz)
        return rzalloc_size(shader, sz); /* TODO: don't use rzalloc */
 }
 
-struct ir3 * ir3_create(struct ir3_compiler *compiler,
-               unsigned nin, unsigned nout)
+struct ir3 * ir3_create(struct ir3_compiler *compiler, gl_shader_stage type)
 {
-       struct ir3 *shader = rzalloc(compiler, struct ir3);
+       struct ir3 *shader = rzalloc(NULL, struct ir3);
 
        shader->compiler = compiler;
-       shader->ninputs = nin;
-       shader->inputs = ir3_alloc(shader, sizeof(shader->inputs[0]) * nin);
-
-       shader->noutputs = nout;
-       shader->outputs = ir3_alloc(shader, sizeof(shader->outputs[0]) * nout);
+       shader->type = type;
 
        list_inithead(&shader->block_list);
        list_inithead(&shader->array_list);
@@ -103,28 +98,28 @@ static uint32_t reg(struct ir3_register *reg, struct ir3_info *info,
                if (reg->flags & IR3_REG_RELATIV) {
                        components = reg->size;
                        val.idummy10 = reg->array.offset;
-                       max = (reg->array.offset + repeat + components - 1) >> 2;
+                       max = (reg->array.offset + repeat + components - 1);
                } else {
                        components = util_last_bit(reg->wrmask);
                        val.comp = reg->num & 0x3;
                        val.num  = reg->num >> 2;
-                       max = (reg->num + repeat + components - 1) >> 2;
+                       max = (reg->num + repeat + components - 1);
                }
 
                if (reg->flags & IR3_REG_CONST) {
-                       info->max_const = MAX2(info->max_const, max);
+                       info->max_const = MAX2(info->max_const, max >> 2);
                } else if (val.num == 63) {
                        /* ignore writes to dummy register r63.x */
-               } else if (max < 48) {
+               } else if (max < regid(48, 0)) {
                        if (reg->flags & IR3_REG_HALF) {
                                if (info->gpu_id >= 600) {
                                        /* starting w/ a6xx, half regs conflict with full regs: */
-                                       info->max_reg = MAX2(info->max_reg, (max+1)/2);
+                                       info->max_reg = MAX2(info->max_reg, max >> 3);
                                } else {
-                                       info->max_half_reg = MAX2(info->max_half_reg, max);
+                                       info->max_half_reg = MAX2(info->max_half_reg, max >> 2);
                                }
                        } else {
-                               info->max_reg = MAX2(info->max_reg, max);
+                               info->max_reg = MAX2(info->max_reg, max >> 2);
                        }
                }
        }
@@ -153,6 +148,16 @@ static int emit_cat0(struct ir3_instruction *instr, void *ptr,
        cat0->sync     = !!(instr->flags & IR3_INSTR_SY);
        cat0->opc_cat  = 0;
 
+       switch (instr->opc) {
+       case OPC_IF:
+       case OPC_ELSE:
+       case OPC_ENDIF:
+               cat0->dummy4 = 16;
+               break;
+       default:
+               break;
+       }
+
        return 0;
 }
 
@@ -234,7 +239,8 @@ static int emit_cat2(struct ir3_instruction *instr, void *ptr,
        } else if (src1->flags & IR3_REG_CONST) {
                iassert(src1->num < (1 << 12));
                cat2->c1.src1   = reg(src1, info, instr->repeat,
-                               IR3_REG_CONST | IR3_REG_R | IR3_REG_HALF);
+                               IR3_REG_CONST | IR3_REG_R | IR3_REG_HALF |
+                               absneg);
                cat2->c1.src1_c = 1;
        } else {
                iassert(src1->num < (1 << 11));
@@ -260,7 +266,8 @@ static int emit_cat2(struct ir3_instruction *instr, void *ptr,
                } else if (src2->flags & IR3_REG_CONST) {
                        iassert(src2->num < (1 << 12));
                        cat2->c2.src2   = reg(src2, info, instr->repeat,
-                                       IR3_REG_CONST | IR3_REG_R | IR3_REG_HALF);
+                                       IR3_REG_CONST | IR3_REG_R | IR3_REG_HALF |
+                                       absneg);
                        cat2->c2.src2_c = 1;
                } else {
                        iassert(src2->num < (1 << 11));
@@ -344,7 +351,7 @@ static int emit_cat3(struct ir3_instruction *instr, void *ptr,
        } else if (src1->flags & IR3_REG_CONST) {
                iassert(src1->num < (1 << 12));
                cat3->c1.src1   = reg(src1, info, instr->repeat,
-                               IR3_REG_CONST | IR3_REG_R | IR3_REG_HALF);
+                               IR3_REG_CONST | IR3_REG_R | IR3_REG_HALF | absneg);
                cat3->c1.src1_c = 1;
        } else {
                iassert(src1->num < (1 << 11));
@@ -369,7 +376,7 @@ static int emit_cat3(struct ir3_instruction *instr, void *ptr,
        } else if (src3->flags & IR3_REG_CONST) {
                iassert(src3->num < (1 << 12));
                cat3->c2.src3   = reg(src3, info, instr->repeat,
-                               IR3_REG_CONST | IR3_REG_R | IR3_REG_HALF);
+                               IR3_REG_CONST | IR3_REG_R | IR3_REG_HALF | absneg);
                cat3->c2.src3_c = 1;
        } else {
                iassert(src3->num < (1 << 11));
@@ -451,11 +458,29 @@ static int emit_cat5(struct ir3_instruction *instr, void *ptr,
         * than tex/sampler idx, we use the first src reg in the ir to hold
         * samp_tex hvec2:
         */
-       struct ir3_register *src1 = instr->regs[2];
-       struct ir3_register *src2 = instr->regs[3];
+       struct ir3_register *src1;
+       struct ir3_register *src2;
        instr_cat5_t *cat5 = ptr;
 
-       iassert_type(dst, type_size(instr->cat5.type) == 32)
+       iassert((instr->regs_count == 2) ||
+                       (instr->regs_count == 3) || (instr->regs_count == 4));
+
+       switch (instr->opc) {
+       case OPC_DSX:
+       case OPC_DSXPP_1:
+       case OPC_DSY:
+       case OPC_DSYPP_1:
+       case OPC_RGETPOS:
+       case OPC_RGETINFO:
+               iassert((instr->flags & IR3_INSTR_S2EN) == 0);
+               src1 = instr->regs[1];
+               src2 = instr->regs_count > 2 ? instr->regs[2] : NULL;
+               break;
+       default:
+               src1 = instr->regs[2];
+               src2 = instr->regs_count > 3 ? instr->regs[3] : NULL;
+               break;
+       }
 
        assume(src1 || !src2);
 
@@ -774,18 +799,30 @@ static int emit_cat6(struct ir3_instruction *instr, void *ptr,
 
                return 0;
        } else if (instr->cat6.src_offset || (instr->opc == OPC_LDG) ||
-                       (instr->opc == OPC_LDL)) {
+                       (instr->opc == OPC_LDL) || (instr->opc == OPC_LDLW)) {
+               struct ir3_register *src3 = instr->regs[3];
                instr_cat6a_t *cat6a = ptr;
 
                cat6->src_off = true;
 
-               cat6a->src1 = reg(src1, info, instr->repeat, IR3_REG_IMMED);
-               cat6a->src1_im = !!(src1->flags & IR3_REG_IMMED);
-               if (src2) {
-                       cat6a->src2 = reg(src2, info, instr->repeat, IR3_REG_IMMED);
-                       cat6a->src2_im = !!(src2->flags & IR3_REG_IMMED);
+               if (instr->opc == OPC_LDG) {
+                       /* For LDG src1 can not be immediate, so src1_imm is redundant and
+                        * instead used to signal whether (when true) 'off' is a 32 bit
+                        * register or an immediate offset.
+                        */
+                       cat6a->src1 = reg(src1, info, instr->repeat, 0);
+                       cat6a->src1_im = !(src3->flags & IR3_REG_IMMED);
+                       cat6a->off = reg(src3, info, instr->repeat, IR3_REG_IMMED);
+               } else {
+                       cat6a->src1 = reg(src1, info, instr->repeat, IR3_REG_IMMED);
+                       cat6a->src1_im = !!(src1->flags & IR3_REG_IMMED);
+                       cat6a->off = reg(src3, info, instr->repeat, IR3_REG_IMMED);
+                       iassert(src3->flags & IR3_REG_IMMED);
                }
-               cat6a->off = instr->cat6.src_offset;
+
+               /* Num components */
+               cat6a->src2 = reg(src2, info, instr->repeat, IR3_REG_IMMED);
+               cat6a->src2_im = true;
        } else {
                instr_cat6b_t *cat6b = ptr;
 
@@ -800,11 +837,22 @@ static int emit_cat6(struct ir3_instruction *instr, void *ptr,
        }
 
        if (instr->cat6.dst_offset || (instr->opc == OPC_STG) ||
-                       (instr->opc == OPC_STL)) {
+                       (instr->opc == OPC_STL) || (instr->opc == OPC_STLW)) {
                instr_cat6c_t *cat6c = ptr;
                cat6->dst_off = true;
                cat6c->dst = reg(dst, info, instr->repeat, IR3_REG_R | IR3_REG_HALF);
-               cat6c->off = instr->cat6.dst_offset;
+
+               if (instr->flags & IR3_INSTR_G) {
+                       struct ir3_register *src3 = instr->regs[4];
+                       cat6c->off = reg(src3, info, instr->repeat, IR3_REG_R | IR3_REG_HALF);
+                       if (src3->flags & IR3_REG_IMMED) {
+                               /* Immediate offsets are in bytes... */
+                               cat6->g = false;
+                               cat6c->off *= 4;
+                       }
+               } else {
+                       cat6c->off = instr->cat6.dst_offset;
+               }
        } else {
                instr_cat6d_t *cat6d = ptr;
                cat6->dst_off = false;
@@ -851,8 +899,8 @@ void * ir3_assemble(struct ir3 *shader, struct ir3_info *info,
        info->sizedwords    = 0;
        info->ss = info->sy = 0;
 
-       list_for_each_entry (struct ir3_block, block, &shader->block_list, node) {
-               list_for_each_entry (struct ir3_instruction, instr, &block->instr_list, node) {
+       foreach_block (block, &shader->block_list) {
+               foreach_instr (instr, &block->instr_list) {
                        info->sizedwords += 2;
                }
        }
@@ -869,12 +917,19 @@ void * ir3_assemble(struct ir3 *shader, struct ir3_info *info,
 
        ptr = dwords = calloc(4, info->sizedwords);
 
-       list_for_each_entry (struct ir3_block, block, &shader->block_list, node) {
-               list_for_each_entry (struct ir3_instruction, instr, &block->instr_list, node) {
+       foreach_block (block, &shader->block_list) {
+               foreach_instr (instr, &block->instr_list) {
                        int ret = emit[opc_cat(instr->opc)](instr, dwords, info);
                        if (ret)
                                goto fail;
+
+                       if ((instr->opc == OPC_BARY_F) && (instr->regs[0]->flags & IR3_REG_EI))
+                               info->last_baryf = info->instrs_count;
+
                        info->instrs_count += 1 + instr->repeat + instr->nop;
+                       info->nops_count += instr->nop;
+                       if (instr->opc == OPC_NOP)
+                               info->nops_count += 1 + instr->repeat;
                        dwords += 2;
 
                        if (instr->flags & IR3_INSTR_SS)
@@ -1022,6 +1077,10 @@ ir3_instr_set_address(struct ir3_instruction *instr,
 {
        if (instr->address != addr) {
                struct ir3 *ir = instr->block->shader;
+
+               debug_assert(!instr->address);
+               debug_assert(instr->block == addr->block);
+
                instr->address = addr;
                array_insert(ir, ir->indirects, instr);
        }
@@ -1030,14 +1089,14 @@ ir3_instr_set_address(struct ir3_instruction *instr,
 void
 ir3_block_clear_mark(struct ir3_block *block)
 {
-       list_for_each_entry (struct ir3_instruction, instr, &block->instr_list, node)
+       foreach_instr (instr, &block->instr_list)
                instr->flags &= ~IR3_INSTR_MARK;
 }
 
 void
 ir3_clear_mark(struct ir3 *ir)
 {
-       list_for_each_entry (struct ir3_block, block, &ir->block_list, node) {
+       foreach_block (block, &ir->block_list) {
                ir3_block_clear_mark(block);
        }
 }
@@ -1047,12 +1106,13 @@ unsigned
 ir3_count_instructions(struct ir3 *ir)
 {
        unsigned cnt = 0;
-       list_for_each_entry (struct ir3_block, block, &ir->block_list, node) {
-               list_for_each_entry (struct ir3_instruction, instr, &block->instr_list, node) {
+       foreach_block (block, &ir->block_list) {
+               block->start_ip = cnt;
+               block->end_ip = cnt;
+               foreach_instr (instr, &block->instr_list) {
                        instr->ip = cnt++;
+                       block->end_ip = instr->ip;
                }
-               block->start_ip = list_first_entry(&block->instr_list, struct ir3_instruction, node)->ip;
-               block->end_ip = list_last_entry(&block->instr_list, struct ir3_instruction, node)->ip;
        }
        return cnt;
 }
@@ -1060,7 +1120,7 @@ ir3_count_instructions(struct ir3 *ir)
 struct ir3_array *
 ir3_lookup_array(struct ir3 *ir, unsigned id)
 {
-       list_for_each_entry (struct ir3_array, arr, &ir->array_list, node)
+       foreach_array (arr, &ir->array_list)
                if (arr->id == id)
                        return arr;
        return NULL;