r600g: add initial bank swizzle support.
authorDave Airlie <airlied@redhat.com>
Wed, 8 Sep 2010 04:09:40 +0000 (14:09 +1000)
committerDave Airlie <airlied@redhat.com>
Wed, 8 Sep 2010 04:12:21 +0000 (14:12 +1000)
this is ported from r600c mostly, bank swizzling is real messy and I don't think
I got enough sleep last night to fully understand it.

src/gallium/drivers/r600/r600_asm.c
src/gallium/drivers/r600/r600_asm.h
src/gallium/drivers/r600/r600_sq.h
src/gallium/drivers/r600/r700_asm.c

index 13a44c8d0e390c7d09a77183631d5abfbc6a9e35..0ed177c66bdf09fbf6c5dc23801068348417c142 100644 (file)
 #include <stdio.h>
 #include <errno.h>
 
+static inline unsigned int r600_bc_get_num_operands(struct r600_bc_alu *alu)
+{
+       if(alu->is_op3)
+               return 3;
+
+       switch (alu->inst) {
+       case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP:
+               return 0;
+       case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_ADD:
+       case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_KILLE:
+       case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_KILLGT:
+       case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_KILLGE:
+       case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_KILLNE:
+       case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MUL: 
+       case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MAX:
+       case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MIN:
+       case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_SETE: 
+       case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_SETNE:
+       case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_SETGT:
+       case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_SETGE:
+       case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_PRED_SETE:
+       case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_PRED_SETGT:
+       case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_PRED_SETGE:
+       case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_PRED_SETNE:
+       case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_DOT4:
+       case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_DOT4_IEEE:
+       case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_CUBE:
+               return 2;  
+               
+       case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MOV: 
+       case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MOVA_FLOOR:
+       case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_FRACT:
+       case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_FLOOR:
+       case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_TRUNC:
+       case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_EXP_IEEE:
+       case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_LOG_CLAMPED:
+       case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_LOG_IEEE:
+       case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_RECIP_IEEE:
+       case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_RECIPSQRT_IEEE:
+       case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_FLT_TO_INT:
+       case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_SIN:
+       case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_COS:
+               return 1;
+        
+       default: R600_ERR(
+               "Need instruction operand number for 0x%x.\n", alu->inst); 
+       };
+       
+       return 3;
+}
+
 int r700_bc_alu_build(struct r600_bc *bc, struct r600_bc_alu *alu, unsigned id);
 
 static struct r600_bc_cf *r600_bc_cf(void)
@@ -50,6 +101,7 @@ static struct r600_bc_alu *r600_bc_alu(void)
        if (alu == NULL)
                return NULL;
        LIST_INITHEAD(&alu->list);
+       LIST_INITHEAD(&alu->bs_list);
        return alu;
 }
 
@@ -129,10 +181,219 @@ int r600_bc_add_output(struct r600_bc *bc, const struct r600_bc_output *output)
        return 0;
 }
 
+const unsigned bank_swizzle_vec[8] = {SQ_ALU_VEC_210,  //000
+                                     SQ_ALU_VEC_120,  //001
+                                     SQ_ALU_VEC_102,  //010
+
+                                     SQ_ALU_VEC_201,  //011
+                                     SQ_ALU_VEC_012,  //100
+                                     SQ_ALU_VEC_021,  //101
+
+                                     SQ_ALU_VEC_012,  //110
+                                     SQ_ALU_VEC_012}; //111
+
+const unsigned bank_swizzle_scl[8] = {SQ_ALU_SCL_210,  //000
+                                     SQ_ALU_SCL_122,  //001 
+                                     SQ_ALU_SCL_122,  //010
+                                     
+                                     SQ_ALU_SCL_221,  //011
+                                     SQ_ALU_SCL_212,  //100
+                                     SQ_ALU_SCL_122,  //101
+
+                                     SQ_ALU_SCL_122,  //110
+                                     SQ_ALU_SCL_122}; //111
+
+static int init_gpr(struct r600_bc_alu *alu)
+{
+       int cycle, component;
+       /* set up gpr use */
+       for (cycle = 0; cycle < NUM_OF_CYCLES; cycle++)
+               for (component = 0; component < NUM_OF_COMPONENTS; component++)
+                        alu->hw_gpr[cycle][component] = -1;
+       return 0;
+}
+
+static int reserve_gpr(struct r600_bc_alu *alu, unsigned sel, unsigned chan, unsigned cycle)
+{
+       if (alu->hw_gpr[cycle][chan] < 0)
+               alu->hw_gpr[cycle][chan] = sel;
+       else if (alu->hw_gpr[cycle][chan] != (int)sel) {
+               R600_ERR("Another scalar operation has already used GPR read port for channel\n");
+               return -1;
+       }
+       return 0;
+}
+
+static int cycle_for_scalar_bank_swizzle(const int swiz, const int sel, unsigned *p_cycle)
+{
+       int table[3];
+       int ret = 0;
+       switch (swiz) {
+       case SQ_ALU_SCL_210:
+               table[0] = 2; table[1] = 1; table[2] = 0;
+                *p_cycle = table[sel];
+                break;
+       case SQ_ALU_SCL_122:
+               table[0] = 1; table[1] = 2; table[2] = 2;
+                *p_cycle = table[sel];
+                break;
+       case SQ_ALU_SCL_212:
+               table[0] = 2; table[1] = 1; table[2] = 2;
+                *p_cycle = table[sel];
+                break;
+       case SQ_ALU_SCL_221:
+               table[0] = 2; table[1] = 2; table[2] = 1;
+               *p_cycle = table[sel];
+                break;
+               break;
+       default:
+               R600_ERR("bad scalar bank swizzle value\n");
+               ret = -1;
+               break;
+       }
+       return ret;
+}
+
+static int cycle_for_vector_bank_swizzle(const int swiz, const int sel, unsigned *p_cycle)
+{
+       int table[3];
+       int ret;
+
+       switch (swiz) {
+       case SQ_ALU_VEC_012:
+               table[0] = 0; table[1] = 1; table[2] = 2;
+                *p_cycle = table[sel];
+                break;
+       case SQ_ALU_VEC_021:
+               table[0] = 0; table[1] = 2; table[2] = 1;
+                *p_cycle = table[sel];
+                break;
+       case SQ_ALU_VEC_120:
+               table[0] = 1; table[1] = 2; table[2] = 0;
+                *p_cycle = table[sel];
+                break;
+       case SQ_ALU_VEC_102:
+               table[0] = 1; table[1] = 0; table[2] = 2;
+                *p_cycle = table[sel];
+                break;
+       case SQ_ALU_VEC_201:
+               table[0] = 2; table[1] = 0; table[2] = 1;
+                *p_cycle = table[sel];
+                break;
+       case SQ_ALU_VEC_210:
+               table[0] = 2; table[1] = 1; table[2] = 0;
+                *p_cycle = table[sel];
+                break;
+       default:
+               R600_ERR("bad vector bank swizzle value\n");
+               ret = -1;
+               break;
+       }
+       return ret;
+}
+
+static int is_const(int sel)
+{
+       if (sel > 255 && sel < 512)
+               return 1;
+       if (sel >= V_SQ_ALU_SRC_0 && sel <= V_SQ_ALU_SRC_LITERAL)
+               return 1;
+       return 0;
+}
+
+static void update_chan_counter(struct r600_bc_alu *alu, int *chan_counter)
+{
+       int num_src;
+       int i;
+       int channel_swizzle;
+
+       num_src = r600_bc_get_num_operands(alu);
+
+       for (i = 0; i < num_src; i++) {
+               channel_swizzle = alu->src[i].chan;
+               if ((alu->src[i].sel > 0 && alu->src[i].sel < 128) && channel_swizzle <= 3)
+                       chan_counter[channel_swizzle]++;
+       }
+}
+
+#if 0
+/* we need something like this I think - but this is bogus */
+int check_read_slots(struct r600_bc *bc, struct r600_bc_alu *alu_first)
+{
+       struct r600_bc_alu *alu;
+       int chan_counter[4]  = { 0 };
+
+       update_chan_counter(alu_first, chan_counter);
+
+       LIST_FOR_EACH_ENTRY(alu, &alu_first->bs_list, bs_list) {
+               update_chan_counter(alu, chan_counter);
+       }
+
+       if (chan_counter[0] > 3 ||
+           chan_counter[1] > 3 ||
+           chan_counter[2] > 3 ||
+           chan_counter[3] > 3) {
+               R600_ERR("needed to split instruction for input ran out of banks %x %d %d %d %d\n",
+                        alu_first->inst, chan_counter[0], chan_counter[1], chan_counter[2], chan_counter[3]);
+               return -1;
+       }
+       return 0;
+}
+#endif
+
+static int check_scalar(struct r600_bc *bc, struct r600_bc_alu *alu)
+{
+       unsigned swizzle_key;
+
+       swizzle_key = (is_const(alu->src[0].sel) ? 4 : 0 ) + 
+               (is_const(alu->src[1].sel) ? 2 : 0 ) + 
+               (is_const(alu->src[2].sel) ? 1 : 0 );
+
+       alu->bank_swizzle = bank_swizzle_scl[swizzle_key];
+       return 0;
+}
+
+static int check_vector(struct r600_bc *bc, struct r600_bc_alu *alu)
+{
+       unsigned swizzle_key;
+
+       swizzle_key = (is_const(alu->src[0].sel) ? 4 : 0 ) + 
+               (is_const(alu->src[1].sel) ? 2 : 0 ) + 
+               (is_const(alu->src[2].sel) ? 1 : 0 );
+
+       alu->bank_swizzle = bank_swizzle_vec[swizzle_key];
+       return 0;
+}
+
+static int check_and_set_bank_swizzle(struct r600_bc *bc, struct r600_bc_alu *alu_first)
+{
+       struct r600_bc_alu *alu;
+       int num_instr = 1;
+
+       init_gpr(alu_first);
+
+       LIST_FOR_EACH_ENTRY(alu, &alu_first->bs_list, bs_list) {
+               num_instr++;
+       }
+
+       if (num_instr == 1) {
+               check_scalar(bc, alu_first);
+               
+       } else {
+/*             check_read_slots(bc, bc->cf_last->curr_bs_head);*/
+               check_vector(bc, alu_first);
+               LIST_FOR_EACH_ENTRY(alu, &alu_first->bs_list, bs_list) {
+                       check_vector(bc, alu);
+               }
+       }
+       return 0;
+}
+
 int r600_bc_add_alu_type(struct r600_bc *bc, const struct r600_bc_alu *alu, int type)
 {
        struct r600_bc_alu *nalu = r600_bc_alu();
        struct r600_bc_alu *lalu;
+       struct r600_bc_alu *curr_bs_head;
        int i, r;
 
        if (nalu == NULL)
@@ -151,6 +412,12 @@ int r600_bc_add_alu_type(struct r600_bc *bc, const struct r600_bc_alu *alu, int
                }
                bc->cf_last->inst = (type << 3);
        }
+       if (!bc->cf_last->curr_bs_head) {
+               bc->cf_last->curr_bs_head = nalu;
+               LIST_INITHEAD(&nalu->bs_list);
+       } else {
+               LIST_ADDTAIL(&nalu->bs_list, &bc->cf_last->curr_bs_head->bs_list);
+       }
        if (alu->last && (bc->cf_last->ndw >> 1) >= 124) {
                bc->force_add_cf = 1;
        }
@@ -185,6 +452,11 @@ int r600_bc_add_alu_type(struct r600_bc *bc, const struct r600_bc_alu *alu, int
        if (bc->use_mem_constant)
                bc->cf_last->kcache0_mode = 2;
 
+       /* process cur ALU instructions for bank swizzle */
+       if (alu->last) {
+               check_and_set_bank_swizzle(bc, bc->cf_last->curr_bs_head);
+               bc->cf_last->curr_bs_head = NULL;
+       }
        return 0;
 }
 
@@ -365,7 +637,7 @@ static int r600_bc_alu_build(struct r600_bc *bc, struct r600_bc_alu *alu, unsign
                                        S_SQ_ALU_WORD1_OP3_SRC2_CHAN(alu->src[2].chan) |
                                        S_SQ_ALU_WORD1_OP3_SRC2_NEG(alu->src[2].neg) |
                                        S_SQ_ALU_WORD1_OP3_ALU_INST(alu->inst) |
-                                       S_SQ_ALU_WORD1_BANK_SWIZZLE(0);
+                                       S_SQ_ALU_WORD1_BANK_SWIZZLE(alu->bank_swizzle);
        } else {
                bc->bytecode[id++] = S_SQ_ALU_WORD1_DST_GPR(alu->dst.sel) |
                                        S_SQ_ALU_WORD1_DST_CHAN(alu->dst.chan) |
@@ -375,7 +647,7 @@ static int r600_bc_alu_build(struct r600_bc *bc, struct r600_bc_alu *alu, unsign
                                        S_SQ_ALU_WORD1_OP2_SRC1_ABS(alu->src[1].abs) |
                                        S_SQ_ALU_WORD1_OP2_WRITE_MASK(alu->dst.write) |
                                        S_SQ_ALU_WORD1_OP2_ALU_INST(alu->inst) |
-                                       S_SQ_ALU_WORD1_BANK_SWIZZLE(0) |
+                                       S_SQ_ALU_WORD1_BANK_SWIZZLE(alu->bank_swizzle) |
                                        S_SQ_ALU_WORD1_OP2_UPDATE_EXECUTE_MASK(alu->predicate) |
                                        S_SQ_ALU_WORD1_OP2_UPDATE_PRED(alu->predicate);
        }
index 0d75d99310e3b40ba1ff20e4e467eae087684d3e..d4b3463af59ccdceb4b64d71b5e2a4eac96f2808 100644 (file)
@@ -26,6 +26,9 @@
 #include "radeon.h"
 #include "util/u_double_list.h"
 
+#define NUM_OF_CYCLES 3
+#define NUM_OF_COMPONENTS 4
+
 struct r600_bc_alu_src {
        unsigned                        sel;
        unsigned                        chan;
@@ -44,6 +47,7 @@ struct r600_bc_alu_dst {
 
 struct r600_bc_alu {
        struct list_head                list;
+       struct list_head                bs_list; /* bank swizzle list */
        struct r600_bc_alu_src          src[3];
        struct r600_bc_alu_dst          dst;
        unsigned                        inst;
@@ -52,7 +56,9 @@ struct r600_bc_alu {
        unsigned                        predicate;
        unsigned                        nliteral;
        unsigned                        literal_added;
+       unsigned                        bank_swizzle;
        u32                             value[4];
+       int hw_gpr[NUM_OF_CYCLES][NUM_OF_COMPONENTS];
 };
 
 struct r600_bc_tex {
@@ -125,6 +131,7 @@ struct r600_bc_cf {
        struct list_head                tex;
        struct list_head                vtx;
        struct r600_bc_output           output;
+       struct r600_bc_alu *curr_bs_head;
 };
 
 #define FC_NONE 0
index 1542059c039e70cc5d934e43687ea10da093bf81..d0f5726d25180eb9a4ff9d64d6e0bf7b7d992969 100644 (file)
 
 #define V_SQ_REL_ABSOLUTE 0
 #define V_SQ_REL_RELATIVE 1
+
+#define SQ_ALU_VEC_012                                0x00
+#define SQ_ALU_VEC_021                                0x01
+#define SQ_ALU_VEC_120                                0x02
+#define SQ_ALU_VEC_102                                0x03
+#define SQ_ALU_VEC_201                                0x04
+#define SQ_ALU_VEC_210                                0x05
+
+#define SQ_ALU_SCL_210                           0x00000000
+#define SQ_ALU_SCL_122                           0x00000001
+#define SQ_ALU_SCL_212                           0x00000002
+#define SQ_ALU_SCL_221                           0x00000003
 #endif
index aaeaff596360ba99b94d03dec9c863cf3bb736a5..7f7ce5a4bacfe231c9201c678008c99cc79c2cf1 100644 (file)
@@ -51,7 +51,7 @@ int r700_bc_alu_build(struct r600_bc *bc, struct r600_bc_alu *alu, unsigned id)
                                        S_SQ_ALU_WORD1_OP3_SRC2_CHAN(alu->src[2].chan) |
                                        S_SQ_ALU_WORD1_OP3_SRC2_NEG(alu->src[2].neg) |
                                        S_SQ_ALU_WORD1_OP3_ALU_INST(alu->inst) |
-                                       S_SQ_ALU_WORD1_BANK_SWIZZLE(0);
+                                       S_SQ_ALU_WORD1_BANK_SWIZZLE(alu->bank_swizzle);
        } else {
                bc->bytecode[id++] = S_SQ_ALU_WORD1_DST_GPR(alu->dst.sel) |
                                        S_SQ_ALU_WORD1_DST_CHAN(alu->dst.chan) |
@@ -61,7 +61,7 @@ int r700_bc_alu_build(struct r600_bc *bc, struct r600_bc_alu *alu, unsigned id)
                                        S_SQ_ALU_WORD1_OP2_SRC1_ABS(alu->src[1].abs) |
                                        S_SQ_ALU_WORD1_OP2_WRITE_MASK(alu->dst.write) |
                                        S_SQ_ALU_WORD1_OP2_ALU_INST(alu->inst) |
-                                       S_SQ_ALU_WORD1_BANK_SWIZZLE(0) |
+                                       S_SQ_ALU_WORD1_BANK_SWIZZLE(alu->bank_swizzle) |
                                        S_SQ_ALU_WORD1_OP2_UPDATE_EXECUTE_MASK(alu->predicate) |
                                        S_SQ_ALU_WORD1_OP2_UPDATE_PRED(alu->predicate);
        }