r600g: implement replacing gpr with pv and ps
[mesa.git] / src / gallium / drivers / r600 / r600_asm.c
index 1f41269534a381cb496c8c5a67b36e594bfb559f..c0501f5018d8a8965bc4f1a9ce1d136f497103fe 100644 (file)
@@ -32,6 +32,9 @@
 #include "r600_formats.h"
 #include "r600d.h"
 
+#define NUM_OF_CYCLES 3
+#define NUM_OF_COMPONENTS 4
+
 static inline unsigned int r600_bc_get_num_operands(struct r600_bc_alu *alu)
 {
        if(alu->is_op3)
@@ -104,7 +107,6 @@ 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;
 }
 
@@ -192,221 +194,416 @@ 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
+/* alu instructions that can ony exits once per group */
+static int is_alu_once_inst(struct r600_bc_alu *alu)
+{
+       return !alu->is_op3 && (
+               alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_KILLE ||
+               alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_KILLGT ||
+               alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_KILLGE ||
+               alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_KILLNE ||
+               alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_KILLGT_UINT ||
+               alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_KILLGE_UINT ||
+               alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_KILLE_INT ||
+               alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_KILLGT_INT ||
+               alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_KILLGE_INT ||
+               alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_KILLNE_INT ||
+               alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_PRED_SETGT_UINT ||
+               alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_PRED_SETGE_UINT ||
+               alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_PRED_SETE ||
+               alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_PRED_SETGT ||
+               alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_PRED_SETGE ||
+               alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_PRED_SETNE ||
+               alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_PRED_SET_INV ||
+               alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_PRED_SET_POP ||
+               alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_PRED_SET_CLR ||
+               alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_PRED_SET_RESTORE ||
+               alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_PRED_SETE_PUSH ||
+               alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_PRED_SETGT_PUSH ||
+               alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_PRED_SETGE_PUSH ||
+               alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_PRED_SETNE_PUSH ||
+               alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_PRED_SETE_INT ||
+               alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_PRED_SETGT_INT ||
+               alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_PRED_SETGE_INT ||
+               alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_PRED_SETNE_INT ||
+               alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_PRED_SETE_PUSH_INT ||
+               alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_PRED_SETGT_PUSH_INT ||
+               alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_PRED_SETGE_PUSH_INT ||
+               alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_PRED_SETNE_PUSH_INT ||
+               alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_PRED_SETLT_PUSH_INT ||
+               alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_PRED_SETLE_PUSH_INT);
+}
 
-                                     SQ_ALU_VEC_201,  //011
-                                     SQ_ALU_VEC_012,  //100
-                                     SQ_ALU_VEC_021,  //101
+static int is_alu_reduction_inst(struct r600_bc_alu *alu)
+{
+       return !alu->is_op3 && (
+               alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_CUBE ||
+               alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_DOT4 ||
+               alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_DOT4_IEEE ||
+               alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MAX4);
+}
 
-                                     SQ_ALU_VEC_012,  //110
-                                     SQ_ALU_VEC_012}; //111
+static int is_alu_mova_inst(struct r600_bc_alu *alu)
+{
+       return !alu->is_op3 && (
+               alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MOVA ||
+               alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MOVA_FLOOR ||
+               alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MOVA_INT);
+}
 
-const unsigned bank_swizzle_scl[8] = {SQ_ALU_SCL_210,  //000
-                                     SQ_ALU_SCL_122,  //001
-                                     SQ_ALU_SCL_122,  //010
+/* alu instructions that can only execute on the vector unit */
+static int is_alu_vec_unit_inst(struct r600_bc_alu *alu)
+{
+       return is_alu_reduction_inst(alu) ||
+               is_alu_mova_inst(alu);
+}
 
-                                     SQ_ALU_SCL_221,  //011
-                                     SQ_ALU_SCL_212,  //100
-                                     SQ_ALU_SCL_122,  //101
+/* alu instructions that can only execute on the trans unit */
+static int is_alu_trans_unit_inst(struct r600_bc_alu *alu)
+{
+       if(!alu->is_op3)
+               return alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_ASHR_INT ||
+                       alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_FLT_TO_INT ||
+                       alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_INT_TO_FLT ||
+                       alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_LSHL_INT ||
+                       alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_LSHR_INT ||
+                       alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MULHI_INT ||
+                       alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MULHI_UINT ||
+                       alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MULLO_INT ||
+                       alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MULLO_UINT ||
+                       alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_RECIP_INT ||
+                       alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_RECIP_UINT ||
+                       alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_UINT_TO_FLT ||
+                       alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_COS ||
+                       alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_EXP_IEEE ||
+                       alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_LOG_CLAMPED ||
+                       alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_LOG_IEEE ||
+                       alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_RECIP_CLAMPED ||
+                       alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_RECIP_FF ||
+                       alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_RECIP_IEEE ||
+                       alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_RECIPSQRT_CLAMPED ||
+                       alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_RECIPSQRT_FF ||
+                       alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_RECIPSQRT_IEEE ||
+                       alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_SIN ||
+                       alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_SQRT_IEEE;
+       else
+               return alu->inst == V_SQ_ALU_WORD1_OP3_SQ_OP3_INST_MUL_LIT ||
+                       alu->inst == V_SQ_ALU_WORD1_OP3_SQ_OP3_INST_MUL_LIT_D2 ||
+                       alu->inst == V_SQ_ALU_WORD1_OP3_SQ_OP3_INST_MUL_LIT_M2 ||
+                       alu->inst == V_SQ_ALU_WORD1_OP3_SQ_OP3_INST_MUL_LIT_M4;
+}
+
+/* alu instructions that can execute on any unit */
+static int is_alu_any_unit_inst(struct r600_bc_alu *alu)
+{
+       return !is_alu_vec_unit_inst(alu) &&
+               !is_alu_trans_unit_inst(alu);
+}
+
+static int assign_alu_units(struct r600_bc_alu *alu_first, struct r600_bc_alu *assignment[5])
+{
+       struct r600_bc_alu *alu;
+       unsigned i, chan, trans;
+
+       for (i = 0; i < 5; i++)
+               assignment[i] = NULL;
+
+       for (alu = alu_first; alu; alu = container_of(alu->list.next, alu, list)) {
+               chan = alu->dst.chan;
+               if (is_alu_trans_unit_inst(alu))
+                       trans = 1;
+               else if (is_alu_vec_unit_inst(alu))
+                       trans = 0;
+               else if (assignment[chan])
+                       trans = 1; // assume ALU_INST_PREFER_VECTOR
+               else
+                       trans = 0;
+
+               if (trans) {
+                       if (assignment[4]) {
+                               assert(0); //ALU.Trans has already been allocated
+                               return -1;
+                       }
+                       assignment[4] = alu;
+               } else {
+                       if (assignment[chan]) {
+                               assert(0); //ALU.chan has already been allocated
+                               return -1;
+                       }
+                       assignment[chan] = alu;
+               }
 
-                                     SQ_ALU_SCL_122,  //110
-                                     SQ_ALU_SCL_122}; //111
+               if (alu->last)
+                       break;
+       }
+       return 0;
+}
 
-static int init_gpr(struct r600_bc_alu *alu)
+struct alu_bank_swizzle {
+       int     hw_gpr[NUM_OF_CYCLES][NUM_OF_COMPONENTS];
+       int     hw_cfile_addr[4];
+       int     hw_cfile_elem[4];
+};
+
+const unsigned cycle_for_bank_swizzle_vec[][3] = {
+       [SQ_ALU_VEC_012] = { 0, 1, 2 },
+       [SQ_ALU_VEC_021] = { 0, 2, 1 },
+       [SQ_ALU_VEC_120] = { 1, 2, 0 },
+       [SQ_ALU_VEC_102] = { 1, 0, 2 },
+       [SQ_ALU_VEC_201] = { 2, 0, 1 },
+       [SQ_ALU_VEC_210] = { 2, 1, 0 }
+};
+
+const unsigned cycle_for_bank_swizzle_scl[][3] = {
+       [SQ_ALU_SCL_210] = { 2, 1, 0 },
+       [SQ_ALU_SCL_122] = { 1, 2, 2 },
+       [SQ_ALU_SCL_212] = { 2, 1, 2 },
+       [SQ_ALU_SCL_221] = { 2, 2, 1 }
+};
+
+static void init_bank_swizzle(struct alu_bank_swizzle *bs)
 {
-       int cycle, component;
+       int i, 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;
+                        bs->hw_gpr[cycle][component] = -1;
+       for (i = 0; i < 4; i++)
+               bs->hw_cfile_addr[i] = -1;
+       for (i = 0; i < 4; i++)
+               bs->hw_cfile_elem[i] = -1;
 }
 
-#if 0
-static int reserve_gpr(struct r600_bc_alu *alu, unsigned sel, unsigned chan, unsigned cycle)
+static int reserve_gpr(struct alu_bank_swizzle *bs, 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");
+       if (bs->hw_gpr[cycle][chan] == -1)
+               bs->hw_gpr[cycle][chan] = sel;
+       else if (bs->hw_gpr[cycle][chan] != (int)sel) {
+               // Another scalar operation has already used GPR read port for channel
                return -1;
        }
        return 0;
 }
 
-static int cycle_for_scalar_bank_swizzle(const int swiz, const int sel, unsigned *p_cycle)
+static int reserve_cfile(struct alu_bank_swizzle *bs, unsigned sel, unsigned chan)
 {
-       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;
+       int res, resmatch = -1, resempty = -1;
+       for (res = 3; res >= 0; --res) {
+               if (bs->hw_cfile_addr[res] == -1)
+                       resempty = res;
+               else if (bs->hw_cfile_addr[res] == sel &&
+                       bs->hw_cfile_elem[res] == chan)
+                       resmatch = res;
        }
-       return ret;
+       if (resmatch != -1)
+               return 0; // Read for this scalar element already reserved, nothing to do here.
+       else if (resempty != -1) {
+               bs->hw_cfile_addr[resempty] = sel;
+               bs->hw_cfile_elem[resempty] = chan;
+       } else {
+               // All cfile read ports are used, cannot reference vector element
+               return -1;
+       }
+       return 0;       
 }
 
-static int cycle_for_vector_bank_swizzle(const int swiz, const int sel, unsigned *p_cycle)
+static int is_gpr(unsigned sel)
 {
-       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;
+       return (sel >= 0 && sel <= 127);
 }
 
+static int is_cfile(unsigned sel)
+{
+       return (sel > 255 && sel < 512);
+}
 
+static int is_const(int sel)
+{
+       return is_cfile(sel) ||
+               (sel >= V_SQ_ALU_SRC_0 && 
+               sel <= V_SQ_ALU_SRC_LITERAL);
+}
 
-static void update_chan_counter(struct r600_bc_alu *alu, int *chan_counter)
+static int check_vector(struct r600_bc_alu *alu, struct alu_bank_swizzle *bs, int bank_swizzle)
 {
-       int num_src;
-       int i;
-       int channel_swizzle;
+       int r, src, num_src, sel, elem, cycle;
 
        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]++;
+       for (src = 0; src < num_src; src++) {
+               sel = alu->src[src].sel;
+               elem = alu->src[src].chan;
+               if (is_gpr(sel)) {
+                       cycle = cycle_for_bank_swizzle_vec[bank_swizzle][src];
+                       if (src == 1 && sel == alu->src[0].sel && elem == alu->src[0].chan)
+                               // Nothing to do; special-case optimization, 
+                               // second source uses first source’s reservation
+                               continue;
+                       else {
+                               r = reserve_gpr(bs, sel, elem, cycle);
+                               if (r)
+                                       return r;
+                       }
+               } else if (is_cfile(sel)) {
+                       r = reserve_cfile(bs, sel, elem);
+                       if (r)
+                               return r;
+               }
+               // No restrictions on PV, PS, literal or special constants
        }
+       return 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)
+static int check_scalar(struct r600_bc_alu *alu, struct alu_bank_swizzle *bs, int bank_swizzle)
 {
-       struct r600_bc_alu *alu;
-       int chan_counter[4]  = { 0 };
-
-       update_chan_counter(alu_first, chan_counter);
+       int r, src, num_src, const_count, sel, elem, cycle;
 
-       LIST_FOR_EACH_ENTRY(alu, &alu_first->bs_list, bs_list) {
-               update_chan_counter(alu, chan_counter);
+       num_src = r600_bc_get_num_operands(alu);
+       for (const_count = 0, src = 0; src < num_src; ++src) {
+               sel = alu->src[src].sel;
+               elem = alu->src[src].chan;
+               if (is_const(sel)) { // Any constant, including literal and inline constants
+                       if (const_count >= 2)
+                               // More than two references to a constant in
+                               // transcendental operation.
+                               return -1; 
+                       else
+                               const_count++;
+               }
+               if (is_cfile(sel)) {
+                       r = reserve_cfile(bs, sel, elem);
+                       if (r)
+                               return r;
+               }
        }
-
-       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;
+       for (src = 0; src < num_src; ++src) {
+               sel = alu->src[src].sel;
+               elem = alu->src[src].chan;
+               if (is_gpr(sel)) {
+                       cycle = cycle_for_bank_swizzle_scl[bank_swizzle][src];
+                       if (cycle < const_count)
+                               // Cycle for GPR load conflicts with
+                               // constant load in transcendental operation.
+                               return -1;
+                       r = reserve_gpr(bs, sel, elem, cycle);
+                       if (r)
+                               return r;
+               }
+               // Constants already processed
+               // No restrictions on PV, PS
        }
        return 0;
 }
-#endif
 
-static int is_const(int sel)
+static int check_and_set_bank_swizzle(struct r600_bc *bc, struct r600_bc_alu *alu_first)
 {
-       if (sel > 255 && sel < 512)
-               return 1;
-       if (sel >= V_SQ_ALU_SRC_0 && sel <= V_SQ_ALU_SRC_LITERAL)
-               return 1;
-       return 0;
-}
+       struct r600_bc_alu *assignment[5];
+       struct alu_bank_swizzle bs;
+       int bank_swizzle[5];
+       int i, r;
 
-static int check_scalar(struct r600_bc *bc, struct r600_bc_alu *alu)
-{
-       unsigned swizzle_key;
+       r = assign_alu_units(alu_first, assignment);
+       if (r)
+               return r;
 
-       if (alu->bank_swizzle_force) {
-               alu->bank_swizzle = alu->bank_swizzle_force;
+       if(alu_first->bank_swizzle_force) {
+               for (i = 0; i < 5; i++)
+                       if (assignment[i])
+                               assignment[i]->bank_swizzle = assignment[i]->bank_swizzle_force;
                return 0;
        }
-       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;
+       // just check every possible combination of bank swizzle
+       // not very efficent, but works on the first try in most of the cases
+       for (i = 0; i < 4; i++)
+               bank_swizzle[i] = SQ_ALU_VEC_012;
+       bank_swizzle[4] = SQ_ALU_SCL_210;
+       while(bank_swizzle[4] <= SQ_ALU_SCL_221) {
+               init_bank_swizzle(&bs);
+               for (i = 0; i < 4; i++) {
+                       if (assignment[i]) {
+                               r = check_vector(assignment[i], &bs, bank_swizzle[i]);
+                               if (r)
+                                       break;
+                       }
+               }
+               if (!r && assignment[4]) {
+                       r = check_scalar(assignment[4], &bs, bank_swizzle[4]);
+               }
+               if (!r) {
+                       for (i = 0; i < 5; i++) {
+                               if (assignment[i])
+                                       assignment[i]->bank_swizzle = bank_swizzle[i];
+                       }
+                       return 0;
+               }
 
-       if (alu->bank_swizzle_force) {
-               alu->bank_swizzle = alu->bank_swizzle_force;
-               return 0;
+               for (i = 0; i < 5; i++) {
+                       bank_swizzle[i]++;
+                       if (bank_swizzle[i] <= SQ_ALU_VEC_210)
+                               break;
+                       else
+                               bank_swizzle[i] = SQ_ALU_VEC_012;
+               }
        }
-       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;
+       // couldn't find a working swizzle
+       return -1;
 }
 
-static int check_and_set_bank_swizzle(struct r600_bc *bc, struct r600_bc_alu *alu_first)
+static int replace_gpr_with_pv_ps(struct r600_bc_alu *alu_first, struct r600_bc_alu *alu_prev)
 {
-       struct r600_bc_alu *alu = NULL;
-       int num_instr = 1;
-
-       init_gpr(alu_first);
+       struct r600_bc_alu *slots[5];
+       int gpr[5], chan[5];
+       int i, j, r, src, num_src;
+       
+       r = assign_alu_units(alu_prev, slots);
+       if (r)
+               return r;
 
-       LIST_FOR_EACH_ENTRY(alu, &alu_first->bs_list, bs_list) {
-               num_instr++;
+       for (i = 0; i < 5; ++i) {
+               if(slots[i] && slots[i]->dst.write && !slots[i]->dst.rel) {
+                       gpr[i] = slots[i]->dst.sel;
+                       if (is_alu_reduction_inst(slots[i]))
+                               chan[i] = 0;
+                       else
+                               chan[i] = slots[i]->dst.chan;
+               } else
+                       gpr[i] = -1;
+               
        }
 
-       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);
+       r = assign_alu_units(alu_first, slots);
+       if (r)
+               return r;
+
+       for (i = 0; i < 5; ++i) {
+               struct r600_bc_alu *alu = slots[i];
+               if(!alu)
+                       continue;
+
+               num_src = r600_bc_get_num_operands(alu);
+               for (src = 0; src < num_src; ++src) {
+                       if (!is_gpr(alu->src[src].sel) || alu->src[src].rel)
+                               continue;
+
+                       if (alu->src[src].sel == gpr[4] &&
+                               alu->src[src].chan == chan[4]) {
+                               alu->src[src].sel = V_SQ_ALU_SRC_PS;
+                               alu->src[src].chan = 0;
+                               continue;
+                       }
+
+                       for (j = 0; j < 4; ++j) {
+                               if (alu->src[src].sel == gpr[j] &&
+                                       alu->src[src].chan == j) {
+                                       alu->src[src].sel = V_SQ_ALU_SRC_PV;
+                                       alu->src[src].chan = chan[j];
+                                       break;
+                               }
+                       }
                }
        }
+
        return 0;
 }
 
@@ -421,21 +618,31 @@ int r600_bc_add_alu_type(struct r600_bc *bc, const struct r600_bc_alu *alu, int
        memcpy(nalu, alu, sizeof(struct r600_bc_alu));
        nalu->nliteral = 0;
 
+       if (bc->cf_last != NULL && bc->cf_last->inst != (type << 3)) {
+               /* check if we could add it anyway */
+               if (bc->cf_last->inst == (V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU << 3) &&
+                       type == V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU_PUSH_BEFORE) {
+                       LIST_FOR_EACH_ENTRY(alu, &bc->cf_last->alu, list) {
+                               if (alu->predicate) {
+                                       bc->force_add_cf = 1;
+                                       break;
+                               }
+                       }
+               } else
+                       bc->force_add_cf = 1;
+       }
+
        /* cf can contains only alu or only vtx or only tex */
-       if (bc->cf_last == NULL || bc->cf_last->inst != (type << 3) ||
-               bc->force_add_cf) {
+       if (bc->cf_last == NULL || bc->force_add_cf) {
                r = r600_bc_add_cf(bc);
                if (r) {
                        free(nalu);
                        return r;
                }
-               bc->cf_last->inst = (type << 3);
        }
+       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);
        }
        /* at most 128 slots, one add alu can add 4 slots + 4 constants(2 slots)
         * worst case */
@@ -474,7 +681,12 @@ int r600_bc_add_alu_type(struct r600_bc *bc, const struct r600_bc_alu *alu, int
 
        /* process cur ALU instructions for bank swizzle */
        if (alu->last) {
-               check_and_set_bank_swizzle(bc, bc->cf_last->curr_bs_head);
+               if (bc->cf_last->prev_bs_head)
+                       replace_gpr_with_pv_ps(bc->cf_last->curr_bs_head, bc->cf_last->prev_bs_head);
+               r = check_and_set_bank_swizzle(bc, bc->cf_last->curr_bs_head);
+               if (r)
+                       return r;
+               bc->cf_last->prev_bs_head = bc->cf_last->curr_bs_head;
                bc->cf_last->curr_bs_head = NULL;
        }
        return 0;
@@ -507,6 +719,8 @@ int r600_bc_add_literal(struct r600_bc *bc, const u32 *value)
        }
        /* same on EG */
        if (((bc->cf_last->inst != (V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU << 3)) &&
+            (bc->cf_last->inst != (V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU_POP_AFTER << 3)) &&
+            (bc->cf_last->inst != (V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU_POP2_AFTER << 3)) &&
             (bc->cf_last->inst != (V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU_PUSH_BEFORE << 3))) ||
                LIST_IS_EMPTY(&bc->cf_last->alu)) {
                R600_ERR("last CF is not ALU (%p)\n", bc->cf_last);
@@ -548,7 +762,7 @@ int r600_bc_add_vtx(struct r600_bc *bc, const struct r600_bc_vtx *vtx)
        /* each fetch use 4 dwords */
        bc->cf_last->ndw += 4;
        bc->ndw += 4;
-       if ((bc->ndw / 4) > 7)
+       if ((bc->cf_last->ndw / 4) > 7)
                bc->force_add_cf = 1;
        return 0;
 }
@@ -577,7 +791,7 @@ int r600_bc_add_tex(struct r600_bc *bc, const struct r600_bc_tex *tex)
        /* each texture fetch use 4 dwords */
        bc->cf_last->ndw += 4;
        bc->ndw += 4;
-       if ((bc->ndw / 4) > 7)
+       if ((bc->cf_last->ndw / 4) > 7)
                bc->force_add_cf = 1;
        return 0;
 }
@@ -705,6 +919,7 @@ static int r600_bc_alu_build(struct r600_bc *bc, struct r600_bc_alu *alu, unsign
                                        S_SQ_ALU_WORD1_OP2_SRC0_ABS(alu->src[0].abs) |
                                        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_OMOD(alu->omod) |
                                        S_SQ_ALU_WORD1_OP2_ALU_INST(alu->inst) |
                                        S_SQ_ALU_WORD1_BANK_SWIZZLE(alu->bank_swizzle) |
                                        S_SQ_ALU_WORD1_OP2_UPDATE_EXECUTE_MASK(alu->predicate) |
@@ -728,6 +943,8 @@ static int r600_bc_cf_build(struct r600_bc *bc, struct r600_bc_cf *cf)
 
        switch (cf->inst) {
        case (V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU << 3):
+       case (V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU_POP_AFTER << 3):
+       case (V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU_POP2_AFTER << 3):
        case (V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU_PUSH_BEFORE << 3):
                bc->bytecode[id++] = S_SQ_CF_ALU_WORD0_ADDR(cf->addr >> 1) |
                        S_SQ_CF_ALU_WORD0_KCACHE_MODE0(cf->kcache0_mode) |
@@ -808,6 +1025,8 @@ int r600_bc_build(struct r600_bc *bc)
        LIST_FOR_EACH_ENTRY(cf, &bc->cf, list) {
                switch (cf->inst) {
                case (V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU << 3):
+               case (V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU_POP_AFTER << 3):
+               case (V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU_POP2_AFTER << 3):
                case (V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU_PUSH_BEFORE << 3):
                        break;
                case V_SQ_CF_WORD1_SQ_CF_INST_TEX:
@@ -854,6 +1073,8 @@ int r600_bc_build(struct r600_bc *bc)
                        return r;
                switch (cf->inst) {
                case (V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU << 3):
+               case (V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU_POP_AFTER << 3):
+               case (V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU_POP2_AFTER << 3):
                case (V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU_PUSH_BEFORE << 3):
                        LIST_FOR_EACH_ENTRY(alu, &cf->alu, list) {
                                switch(bc->chiprev) {
@@ -953,7 +1174,12 @@ void r600_bc_clear(struct r600_bc *bc)
 
 void r600_bc_dump(struct r600_bc *bc)
 {
-       unsigned i;
+       struct r600_bc_cf *cf;
+       struct r600_bc_alu *alu;
+       struct r600_bc_vtx *vtx;
+       struct r600_bc_tex *tex;
+
+       unsigned i, id;
        char chip = '6';
 
        switch (bc->chiprev) {
@@ -970,9 +1196,127 @@ void r600_bc_dump(struct r600_bc *bc)
        }
        fprintf(stderr, "bytecode %d dw -----------------------\n", bc->ndw);
        fprintf(stderr, "     %c\n", chip);
-       for (i = 0; i < bc->ndw; i++) {
-               fprintf(stderr, "0x%08X\n", bc->bytecode[i]);
+
+       LIST_FOR_EACH_ENTRY(cf, &bc->cf, list) {
+               id = cf->id;
+
+               switch (cf->inst) {
+               case (V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU << 3):
+               case (V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU_POP_AFTER << 3):
+               case (V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU_POP2_AFTER << 3):
+               case (V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU_PUSH_BEFORE << 3):
+                       fprintf(stderr, "%04d %08X ALU ", id, bc->bytecode[id]);
+                       fprintf(stderr, "ADDR:%d ", cf->addr);
+                       fprintf(stderr, "KCACHE_MODE0:%X ", cf->kcache0_mode);
+                       fprintf(stderr, "KCACHE_BANK0:%X ", cf->kcache0_bank);
+                       fprintf(stderr, "KCACHE_BANK1:%X\n", cf->kcache1_bank);
+                       id++;
+                       fprintf(stderr, "%04d %08X ALU ", id, bc->bytecode[id]);
+                       fprintf(stderr, "INST:%d ", cf->inst);
+                       fprintf(stderr, "KCACHE_MODE1:%X ", cf->kcache1_mode);
+                       fprintf(stderr, "KCACHE_ADDR0:%X ", cf->kcache0_addr);
+                       fprintf(stderr, "KCACHE_ADDR1:%X ", cf->kcache1_addr);
+                       fprintf(stderr, "COUNT:%d\n", cf->ndw / 2);
+                       break;
+               case V_SQ_CF_WORD1_SQ_CF_INST_TEX:
+               case V_SQ_CF_WORD1_SQ_CF_INST_VTX:
+               case V_SQ_CF_WORD1_SQ_CF_INST_VTX_TC:
+                       fprintf(stderr, "%04d %08X TEX/VTX ", id, bc->bytecode[id]);
+                       fprintf(stderr, "ADDR:%d\n", cf->addr);
+                       id++;
+                       fprintf(stderr, "%04d %08X TEX/VTX ", id, bc->bytecode[id]);
+                       fprintf(stderr, "INST:%d ", cf->inst);
+                       fprintf(stderr, "COUNT:%d\n", cf->ndw / 4);
+                       break;
+               case V_SQ_CF_ALLOC_EXPORT_WORD1_SQ_CF_INST_EXPORT:
+               case V_SQ_CF_ALLOC_EXPORT_WORD1_SQ_CF_INST_EXPORT_DONE:
+                       fprintf(stderr, "%04d %08X EXPORT ", id, bc->bytecode[id]);
+                       fprintf(stderr, "GPR:%X ", cf->output.gpr);
+                       fprintf(stderr, "ELEM_SIZE:%X ", cf->output.elem_size);
+                       fprintf(stderr, "ARRAY_BASE:%X ", cf->output.array_base);
+                       fprintf(stderr, "TYPE:%X\n", cf->output.type);
+                       id++;
+                       fprintf(stderr, "%04d %08X EXPORT ", id, bc->bytecode[id]);
+                       fprintf(stderr, "SWIZ_X:%X ", cf->output.swizzle_x);
+                       fprintf(stderr, "SWIZ_Y:%X ", cf->output.swizzle_y);
+                       fprintf(stderr, "SWIZ_Z:%X ", cf->output.swizzle_z);
+                       fprintf(stderr, "SWIZ_W:%X ", cf->output.swizzle_w);
+                       fprintf(stderr, "SWIZ_W:%X ", cf->output.swizzle_w);
+                       fprintf(stderr, "BARRIER:%X ", cf->output.barrier);
+                       fprintf(stderr, "INST:%d ", cf->output.inst);
+                       fprintf(stderr, "EOP:%X\n", cf->output.end_of_program);
+                       break;
+               case V_SQ_CF_WORD1_SQ_CF_INST_JUMP:
+               case V_SQ_CF_WORD1_SQ_CF_INST_ELSE:
+               case V_SQ_CF_WORD1_SQ_CF_INST_POP:
+               case V_SQ_CF_WORD1_SQ_CF_INST_LOOP_START_NO_AL:
+               case V_SQ_CF_WORD1_SQ_CF_INST_LOOP_END:
+               case V_SQ_CF_WORD1_SQ_CF_INST_LOOP_CONTINUE:
+               case V_SQ_CF_WORD1_SQ_CF_INST_LOOP_BREAK:
+               case V_SQ_CF_WORD1_SQ_CF_INST_CALL_FS:
+               case V_SQ_CF_WORD1_SQ_CF_INST_RETURN:
+                       fprintf(stderr, "%04d %08X CF ", id, bc->bytecode[id]);
+                       fprintf(stderr, "ADDR:%d\n", cf->cf_addr);
+                       id++;
+                       fprintf(stderr, "%04d %08X CF ", id, bc->bytecode[id]);
+                       fprintf(stderr, "INST:%d ", cf->inst);
+                       fprintf(stderr, "COND:%X ", cf->cond);
+                       fprintf(stderr, "POP_COUNT:%X\n", cf->pop_count);
+                       break;
+               }
+
+               id = cf->addr;
+               LIST_FOR_EACH_ENTRY(alu, &cf->alu, list) {
+                       fprintf(stderr, "%04d %08X   ", id, bc->bytecode[id]);
+                       fprintf(stderr, "SRC0(SEL:%d ", alu->src[0].sel);
+                       fprintf(stderr, "REL:%d ", alu->src[0].rel);
+                       fprintf(stderr, "CHAN:%d ", alu->src[0].chan);
+                       fprintf(stderr, "NEG:%d) ", alu->src[0].neg);
+                       fprintf(stderr, "SRC1(SEL:%d ", alu->src[1].sel);
+                       fprintf(stderr, "REL:%d ", alu->src[1].rel);
+                       fprintf(stderr, "CHAN:%d ", alu->src[1].chan);
+                       fprintf(stderr, "NEG:%d) ", alu->src[1].neg);
+                       fprintf(stderr, "LAST:%d)\n", alu->last);
+                       id++;
+                       fprintf(stderr, "%04d %08X %c ", id, bc->bytecode[id], alu->last ? '*' : ' ');
+                       fprintf(stderr, "INST:%d ", alu->inst);
+                       fprintf(stderr, "DST(SEL:%d ", alu->dst.sel);
+                       fprintf(stderr, "CHAN:%d ", alu->dst.chan);
+                       fprintf(stderr, "REL:%d ", alu->dst.rel);
+                       fprintf(stderr, "CLAMP:%d) ", alu->dst.clamp);
+                       fprintf(stderr, "BANK_SWIZZLE:%d ", alu->bank_swizzle);
+                       if (alu->is_op3) {
+                               fprintf(stderr, "SRC2(SEL:%d ", alu->src[2].sel);
+                               fprintf(stderr, "REL:%d ", alu->src[2].rel);
+                               fprintf(stderr, "CHAN:%d ", alu->src[2].chan);
+                               fprintf(stderr, "NEG:%d)\n", alu->src[2].neg);
+                       } else {
+                               fprintf(stderr, "SRC0_ABS:%d ", alu->src[0].abs);
+                               fprintf(stderr, "SRC1_ABS:%d ", alu->src[1].abs);
+                               fprintf(stderr, "WRITE_MASK:%d ", alu->dst.write);
+                               fprintf(stderr, "OMOD:%d ", alu->omod);
+                               fprintf(stderr, "EXECUTE_MASK:%d ", alu->predicate);
+                               fprintf(stderr, "UPDATE_PRED:%d\n", alu->predicate);
+                       }
+
+                       id++;
+                       if (alu->last) {
+                               for (i = 0; i < alu->nliteral; i++, id++) {
+                                       float *f = (float*)(bc->bytecode + id);
+                                       fprintf(stderr, "%04d %08X   %f\n", id, bc->bytecode[id], *f);
+                               }
+                       }
+               }
+
+               LIST_FOR_EACH_ENTRY(tex, &cf->tex, list) {
+                       //TODO
+               }
+
+               LIST_FOR_EACH_ENTRY(vtx, &cf->vtx, list) {
+                       //TODO
+               }
        }
+
        fprintf(stderr, "--------------------------------------\n");
 }
 
@@ -1184,31 +1528,6 @@ out_unknown:
        R600_ERR("unsupported vertex format %s\n", util_format_name(pformat));
 }
 
-static void r600_bc(unsigned ndw, unsigned chiprev, u32 *bytecode)
-{
-       unsigned i;
-       char chip = '6';
-
-       switch (chiprev) {
-       case 1:
-               chip = '7';
-               break;
-       case 2:
-               chip = 'E';
-               break;
-       case 0:
-       default:
-               chip = '6';
-               break;
-       }
-       fprintf(stderr, "bytecode %d dw -----------------------\n", ndw);
-       fprintf(stderr, "    %c\n", chip);
-       for (i = 0; i < ndw; i++) {
-               fprintf(stderr, "0x%08X\n", bytecode[i]);
-       }
-       fprintf(stderr, "--------------------------------------\n");
-}
-
 int r600_vertex_elements_build_fetch_shader(struct r600_pipe_context *rctx, struct r600_vertex_element *ve)
 {
        unsigned ndw, i;