r600g/sb: initial commit of the optimizing shader backend
[mesa.git] / src / gallium / drivers / r600 / r600_shader.c
index 82885d1370e84497a4eed551f9a9eb45d732b347..f0d3be405d23ae089f1317cb120261c807fa3eb6 100644 (file)
@@ -271,14 +271,16 @@ int r600_compute_shader_create(struct pipe_context * ctx,
        unsigned char * bytes;
        unsigned byte_count;
        struct r600_shader_ctx shader_ctx;
+       boolean use_kill = false;
        bool dump = (r600_ctx->screen->debug_flags & DBG_CS) != 0;
 
-       r600_llvm_compile(mod, &bytes, &byte_count, r600_ctx->family , dump);
        shader_ctx.bc = bytecode;
        r600_bytecode_init(shader_ctx.bc, r600_ctx->chip_class, r600_ctx->family,
                           r600_ctx->screen->msaa_texture_support);
        shader_ctx.bc->type = TGSI_PROCESSOR_COMPUTE;
        shader_ctx.bc->isa = r600_ctx->isa;
+       r600_llvm_compile(mod, &bytes, &byte_count, r600_ctx->family,
+                               shader_ctx.bc, &use_kill, dump);
        r600_bytecode_from_byte_stream(&shader_ctx, bytes, byte_count);
        if (shader_ctx.bc->chip_class == CAYMAN) {
                cm_bytecode_add_cf_end(shader_ctx.bc);
@@ -399,12 +401,7 @@ static unsigned r600_alu_from_byte_stream(struct r600_shader_ctx *ctx,
                return bytes_read;
        }
 
-       if (alu.execute_mask) {
-               alu.pred_sel = 0;
-               r600_bytecode_add_alu_type(ctx->bc, &alu, CF_OP_ALU_PUSH_BEFORE);
-       } else {
-               r600_bytecode_add_alu(ctx->bc, &alu);
-       }
+       r600_bytecode_add_alu_type(ctx->bc, &alu, ctx->bc->cf_last->op);
 
        /* XXX: Handle other KILL instructions */
        if (alu_op->flags & AF_KILL) {
@@ -516,6 +513,9 @@ static unsigned r600_tex_from_byte_stream(struct r600_shader_ctx *ctx,
        tex.src_sel_y = G_SQ_TEX_WORD2_SRC_SEL_Y(word2);
        tex.src_sel_z = G_SQ_TEX_WORD2_SRC_SEL_Z(word2);
        tex.src_sel_w = G_SQ_TEX_WORD2_SRC_SEL_W(word2);
+       tex.offset_x <<= 1;
+       tex.offset_y <<= 1;
+       tex.offset_z <<= 1;
 
        tex.inst_mod = 0;
 
@@ -592,7 +592,6 @@ static void r600_bytecode_from_byte_stream(struct r600_shader_ctx *ctx,
                                unsigned char * bytes,  unsigned num_bytes)
 {
        unsigned bytes_read = 0;
-       ctx->bc->nstack = bytes[bytes_read++];
        unsigned i, byte;
        while (bytes_read < num_bytes) {
                char inst_type = bytes[bytes_read++];
@@ -632,7 +631,7 @@ static void r600_bytecode_from_byte_stream(struct r600_shader_ctx *ctx,
                        int32_t word1 = i32_from_byte_stream(bytes, &bytes_read);
 
                        r600_bytecode_add_cf(ctx->bc);
-                       ctx->bc->cf_last->op = r600_isa_cf_by_opcode(ctx->bc->isa, 8/* CF_ALU*/, 1);
+                       ctx->bc->cf_last->op = r600_isa_cf_by_opcode(ctx->bc->isa, G_SQ_CF_ALU_WORD1_CF_INST(word1), 1);
                        ctx->bc->cf_last->kcache[0].bank = G_SQ_CF_ALU_WORD0_KCACHE_BANK0(word0);
                        ctx->bc->cf_last->kcache[0].addr = G_SQ_CF_ALU_WORD1_KCACHE_ADDR0(word1);
                        ctx->bc->cf_last->kcache[0].mode = G_SQ_CF_ALU_WORD0_KCACHE_MODE0(word0);
@@ -1447,6 +1446,7 @@ static int r600_shader_from_tgsi(struct r600_screen *rscreen,
                struct radeon_llvm_context radeon_llvm_ctx;
                LLVMModuleRef mod;
                bool dump = r600_can_dump_shader(rscreen, ctx.type);
+               boolean use_kill = false;
 
                memset(&radeon_llvm_ctx, 0, sizeof(radeon_llvm_ctx));
                radeon_llvm_ctx.type = ctx.type;
@@ -1463,7 +1463,7 @@ static int r600_shader_from_tgsi(struct r600_screen *rscreen,
                mod = r600_tgsi_llvm(&radeon_llvm_ctx, tokens);
 
                if (r600_llvm_compile(mod, &inst_bytes, &inst_byte_count,
-                                     rscreen->family, dump)) {
+                                     rscreen->family, ctx.bc, &use_kill, dump)) {
                        FREE(inst_bytes);
                        radeon_llvm_dispose(&radeon_llvm_ctx);
                        use_llvm = 0;
@@ -1473,6 +1473,8 @@ static int r600_shader_from_tgsi(struct r600_screen *rscreen,
                        ctx.file_offset[TGSI_FILE_OUTPUT] =
                                        ctx.file_offset[TGSI_FILE_INPUT];
                }
+               if (use_kill)
+                       ctx.shader->uses_kill = use_kill;
                radeon_llvm_dispose(&radeon_llvm_ctx);
        }
 #endif
@@ -1900,7 +1902,7 @@ static int r600_shader_from_tgsi(struct r600_screen *rscreen,
                }
        }
        /* add program end */
-       if (ctx.bc->chip_class == CAYMAN)
+       if (!use_llvm && ctx.bc->chip_class == CAYMAN)
                cm_bytecode_add_cf_end(ctx.bc);
 
        /* check GPR limit - we have 124 = 128 - 4
@@ -4506,7 +4508,7 @@ static int tgsi_tex(struct r600_shader_ctx *ctx)
         * Then fetch the texel with src.
         */
        if (read_compressed_msaa) {
-               unsigned sample_chan = inst->Texture.Texture == TGSI_TEXTURE_2D_MSAA ? 3 : 4;
+               unsigned sample_chan = 3;
                unsigned temp = r600_get_temp(ctx);
                assert(src_loaded);
 
@@ -4537,7 +4539,7 @@ static int tgsi_tex(struct r600_shader_ctx *ctx)
                if (ctx->bc->chip_class == CAYMAN) {
                        for (i = 0 ; i < 4; i++) {
                                memset(&alu, 0, sizeof(struct r600_bytecode_alu));
-                               alu.op = ctx->inst_info->op;
+                               alu.op = ALU_OP2_MULLO_INT;
                                alu.src[0].sel = src_gpr;
                                alu.src[0].chan = sample_chan;
                                alu.src[1].sel = V_SQ_ALU_SRC_LITERAL;
@@ -4741,6 +4743,26 @@ static int tgsi_tex(struct r600_shader_ctx *ctx)
                /* the array index is read from Z */
                tex.coord_type_z = 0;
 
+       /* mask unused source components */
+       if (opcode == FETCH_OP_SAMPLE) {
+               switch (inst->Texture.Texture) {
+               case TGSI_TEXTURE_2D:
+               case TGSI_TEXTURE_RECT:
+                       tex.src_sel_z = 7;
+                       tex.src_sel_w = 7;
+                       break;
+               case TGSI_TEXTURE_1D_ARRAY:
+                       tex.src_sel_y = 7;
+                       tex.src_sel_w = 7;
+                       break;
+               case TGSI_TEXTURE_1D:
+                       tex.src_sel_y = 7;
+                       tex.src_sel_z = 7;
+                       tex.src_sel_w = 7;
+                       break;
+               }
+       }
+
        r = r600_bytecode_add_tex(ctx->bc, &tex);
        if (r)
                return r;
@@ -5492,7 +5514,7 @@ static int tgsi_opdst(struct r600_shader_ctx *ctx)
        return 0;
 }
 
-static int emit_logic_pred(struct r600_shader_ctx *ctx, int opcode)
+static int emit_logic_pred(struct r600_shader_ctx *ctx, int opcode, int alu_type)
 {
        struct r600_bytecode_alu alu;
        int r;
@@ -5512,7 +5534,7 @@ static int emit_logic_pred(struct r600_shader_ctx *ctx, int opcode)
 
        alu.last = 1;
 
-       r = r600_bytecode_add_alu_type(ctx->bc, &alu, CF_OP_ALU_PUSH_BEFORE);
+       r = r600_bytecode_add_alu_type(ctx->bc, &alu, alu_type);
        if (r)
                return r;
        return 0;
@@ -5730,9 +5752,21 @@ static void break_loop_on_flag(struct r600_shader_ctx *ctx, unsigned fc_sp)
 }
 #endif
 
-static int tgsi_if(struct r600_shader_ctx *ctx)
+static int emit_if(struct r600_shader_ctx *ctx, int opcode)
 {
-       emit_logic_pred(ctx, ALU_OP2_PRED_SETNE_INT);
+       int alu_type = CF_OP_ALU_PUSH_BEFORE;
+
+       /* There is a hardware bug on Cayman where a BREAK/CONTINUE followed by
+        * LOOP_STARTxxx for nested loops may put the branch stack into a state
+        * such that ALU_PUSH_BEFORE doesn't work as expected. Workaround this
+        * by replacing the ALU_PUSH_BEFORE with a PUSH + ALU */
+       if (ctx->bc->chip_class == CAYMAN && ctx->bc->stack.loop > 1) {
+               r600_bytecode_add_cfinst(ctx->bc, CF_OP_PUSH);
+               ctx->bc->cf_last->cf_addr = ctx->bc->cf_last->id + 2;
+               alu_type = CF_OP_ALU;
+       }
+
+       emit_logic_pred(ctx, opcode, alu_type);
 
        r600_bytecode_add_cfinst(ctx->bc, CF_OP_JUMP);
 
@@ -5742,6 +5776,16 @@ static int tgsi_if(struct r600_shader_ctx *ctx)
        return 0;
 }
 
+static int tgsi_if(struct r600_shader_ctx *ctx)
+{
+       return emit_if(ctx, ALU_OP2_PRED_SETNE);
+}
+
+static int tgsi_uif(struct r600_shader_ctx *ctx)
+{
+       return emit_if(ctx, ALU_OP2_PRED_SETNE_INT);
+}
+
 static int tgsi_else(struct r600_shader_ctx *ctx)
 {
        r600_bytecode_add_cfinst(ctx->bc, CF_OP_ELSE);
@@ -5840,7 +5884,7 @@ static int tgsi_umad(struct r600_shader_ctx *ctx)
 {
        struct tgsi_full_instruction *inst = &ctx->parse.FullToken.FullInstruction;
        struct r600_bytecode_alu alu;
-       int i, j, r;
+       int i, j, k, r;
        int lasti = tgsi_last_instruction(inst->Dst[0].Register.WriteMask);
 
        /* src0 * src1 */
@@ -5848,21 +5892,40 @@ static int tgsi_umad(struct r600_shader_ctx *ctx)
                if (!(inst->Dst[0].Register.WriteMask & (1 << i)))
                        continue;
 
-               memset(&alu, 0, sizeof(struct r600_bytecode_alu));
+               if (ctx->bc->chip_class == CAYMAN) {
+                       for (j = 0 ; j < 4; j++) {
+                               memset(&alu, 0, sizeof(struct r600_bytecode_alu));
 
-               alu.dst.chan = i;
-               alu.dst.sel = ctx->temp_reg;
-               alu.dst.write = 1;
+                               alu.op = ALU_OP2_MULLO_UINT;
+                               for (k = 0; k < inst->Instruction.NumSrcRegs; k++) {
+                                       r600_bytecode_src(&alu.src[k], &ctx->src[k], i);
+                               }
+                               tgsi_dst(ctx, &inst->Dst[0], j, &alu.dst);
+                               alu.dst.sel = ctx->temp_reg;
+                               alu.dst.write = (j == i);
+                               if (j == 3)
+                                       alu.last = 1;
+                               r = r600_bytecode_add_alu(ctx->bc, &alu);
+                               if (r)
+                                       return r;
+                       }
+               } else {
+                       memset(&alu, 0, sizeof(struct r600_bytecode_alu));
 
-               alu.op = ALU_OP2_MULLO_UINT;
-               for (j = 0; j < 2; j++) {
-                       r600_bytecode_src(&alu.src[j], &ctx->src[j], i);
-               }
+                       alu.dst.chan = i;
+                       alu.dst.sel = ctx->temp_reg;
+                       alu.dst.write = 1;
 
-               alu.last = 1;
-               r = r600_bytecode_add_alu(ctx->bc, &alu);
-               if (r)
-                       return r;
+                       alu.op = ALU_OP2_MULLO_UINT;
+                       for (j = 0; j < 2; j++) {
+                               r600_bytecode_src(&alu.src[j], &ctx->src[j], i);
+                       }
+
+                       alu.last = 1;
+                       r = r600_bytecode_add_alu(ctx->bc, &alu);
+                       if (r)
+                               return r;
+               }
        }
 
 
@@ -5974,8 +6037,7 @@ static struct r600_shader_tgsi_instruction r600_shader_tgsi_instruction[] = {
        {TGSI_OPCODE_TXL,       0, FETCH_OP_SAMPLE_L, tgsi_tex},
        {TGSI_OPCODE_BRK,       0, CF_OP_LOOP_BREAK, tgsi_loop_brk_cont},
        {TGSI_OPCODE_IF,        0, ALU_OP0_NOP, tgsi_if},
-       /* gap */
-       {75,                    0, ALU_OP0_NOP, tgsi_unsupported},
+       {TGSI_OPCODE_UIF,       0, ALU_OP0_NOP, tgsi_uif},
        {76,                    0, ALU_OP0_NOP, tgsi_unsupported},
        {TGSI_OPCODE_ELSE,      0, ALU_OP0_NOP, tgsi_else},
        {TGSI_OPCODE_ENDIF,     0, ALU_OP0_NOP, tgsi_endif},
@@ -6018,7 +6080,8 @@ static struct r600_shader_tgsi_instruction r600_shader_tgsi_instruction[] = {
        {111,                   0, ALU_OP0_NOP, tgsi_unsupported},
        {TGSI_OPCODE_NRM4,      0, ALU_OP0_NOP, tgsi_unsupported},
        {TGSI_OPCODE_CALLNZ,    0, ALU_OP0_NOP, tgsi_unsupported},
-       {TGSI_OPCODE_IFC,       0, ALU_OP0_NOP, tgsi_unsupported},
+       /* gap */
+       {114,                   0, ALU_OP0_NOP, tgsi_unsupported},
        {TGSI_OPCODE_BREAKC,    0, ALU_OP0_NOP, tgsi_unsupported},
        {TGSI_OPCODE_KIL,       0, ALU_OP2_KILLGT, tgsi_kill},  /* conditional kill */
        {TGSI_OPCODE_END,       0, ALU_OP0_NOP, tgsi_end},  /* aka HALT */
@@ -6167,8 +6230,7 @@ static struct r600_shader_tgsi_instruction eg_shader_tgsi_instruction[] = {
        {TGSI_OPCODE_TXL,       0, FETCH_OP_SAMPLE_L, tgsi_tex},
        {TGSI_OPCODE_BRK,       0, CF_OP_LOOP_BREAK, tgsi_loop_brk_cont},
        {TGSI_OPCODE_IF,        0, ALU_OP0_NOP, tgsi_if},
-       /* gap */
-       {75,                    0, ALU_OP0_NOP, tgsi_unsupported},
+       {TGSI_OPCODE_UIF,       0, ALU_OP0_NOP, tgsi_uif},
        {76,                    0, ALU_OP0_NOP, tgsi_unsupported},
        {TGSI_OPCODE_ELSE,      0, ALU_OP0_NOP, tgsi_else},
        {TGSI_OPCODE_ENDIF,     0, ALU_OP0_NOP, tgsi_endif},
@@ -6211,7 +6273,8 @@ static struct r600_shader_tgsi_instruction eg_shader_tgsi_instruction[] = {
        {111,                   0, ALU_OP0_NOP, tgsi_unsupported},
        {TGSI_OPCODE_NRM4,      0, ALU_OP0_NOP, tgsi_unsupported},
        {TGSI_OPCODE_CALLNZ,    0, ALU_OP0_NOP, tgsi_unsupported},
-       {TGSI_OPCODE_IFC,       0, ALU_OP0_NOP, tgsi_unsupported},
+       /* gap */
+       {114,                   0, ALU_OP0_NOP, tgsi_unsupported},
        {TGSI_OPCODE_BREAKC,    0, ALU_OP0_NOP, tgsi_unsupported},
        {TGSI_OPCODE_KIL,       0, ALU_OP2_KILLGT, tgsi_kill},  /* conditional kill */
        {TGSI_OPCODE_END,       0, ALU_OP0_NOP, tgsi_end},  /* aka HALT */
@@ -6360,8 +6423,7 @@ static struct r600_shader_tgsi_instruction cm_shader_tgsi_instruction[] = {
        {TGSI_OPCODE_TXL,       0, FETCH_OP_SAMPLE_L, tgsi_tex},
        {TGSI_OPCODE_BRK,       0, CF_OP_LOOP_BREAK, tgsi_loop_brk_cont},
        {TGSI_OPCODE_IF,        0, ALU_OP0_NOP, tgsi_if},
-       /* gap */
-       {75,                    0, ALU_OP0_NOP, tgsi_unsupported},
+       {TGSI_OPCODE_UIF,       0, ALU_OP0_NOP, tgsi_uif},
        {76,                    0, ALU_OP0_NOP, tgsi_unsupported},
        {TGSI_OPCODE_ELSE,      0, ALU_OP0_NOP, tgsi_else},
        {TGSI_OPCODE_ENDIF,     0, ALU_OP0_NOP, tgsi_endif},
@@ -6404,7 +6466,8 @@ static struct r600_shader_tgsi_instruction cm_shader_tgsi_instruction[] = {
        {111,                   0, ALU_OP0_NOP, tgsi_unsupported},
        {TGSI_OPCODE_NRM4,      0, ALU_OP0_NOP, tgsi_unsupported},
        {TGSI_OPCODE_CALLNZ,    0, ALU_OP0_NOP, tgsi_unsupported},
-       {TGSI_OPCODE_IFC,       0, ALU_OP0_NOP, tgsi_unsupported},
+       /* gap */
+       {114,                   0, ALU_OP0_NOP, tgsi_unsupported},
        {TGSI_OPCODE_BREAKC,    0, ALU_OP0_NOP, tgsi_unsupported},
        {TGSI_OPCODE_KIL,       0, ALU_OP2_KILLGT, tgsi_kill},  /* conditional kill */
        {TGSI_OPCODE_END,       0, ALU_OP0_NOP, tgsi_end},  /* aka HALT */