r600g: implement replacing gpr with pv and ps
[mesa.git] / src / gallium / drivers / r600 / r600_asm.c
index c22628423bd883d03232c2908c7ec39360e95ddc..c0501f5018d8a8965bc4f1a9ce1d136f497103fe 100644 (file)
  */
 #include <stdio.h>
 #include <errno.h>
+#include "util/u_format.h"
 #include "util/u_memory.h"
+#include "pipe/p_shader_tokens.h"
 #include "r600_pipe.h"
 #include "r600_sq.h"
 #include "r600_opcodes.h"
 #include "r600_asm.h"
+#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)
 {
@@ -55,8 +62,8 @@ static inline unsigned int r600_bc_get_num_operands(struct r600_bc_alu *alu)
        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;  
-               
+               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:
@@ -74,7 +81,7 @@ static inline unsigned int r600_bc_get_num_operands(struct r600_bc_alu *alu)
        default: R600_ERR(
                "Need instruction operand number for 0x%x.\n", alu->inst); 
        };
-       
+
        return 3;
 }
 
@@ -100,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;
 }
 
@@ -137,20 +143,21 @@ int r600_bc_init(struct r600_bc *bc, enum radeon_family family)
        case CHIP_RV635:
        case CHIP_RS780:
        case CHIP_RS880:
-               bc->chiprev = 0;
+               bc->chiprev = CHIPREV_R600;
                break;
        case CHIP_RV770:
        case CHIP_RV730:
        case CHIP_RV710:
        case CHIP_RV740:
-               bc->chiprev = 1;
+               bc->chiprev = CHIPREV_R700;
                break;
        case CHIP_CEDAR:
        case CHIP_REDWOOD:
        case CHIP_JUNIPER:
        case CHIP_CYPRESS:
        case CHIP_HEMLOCK:
-               bc->chiprev = 2;
+       case CHIP_PALM:
+               bc->chiprev = CHIPREV_EVERGREEN;
                break;
        default:
                R600_ERR("unknown family %d\n", bc->family);
@@ -187,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
-                                     
-                                     SQ_ALU_SCL_221,  //011
-                                     SQ_ALU_SCL_212,  //100
-                                     SQ_ALU_SCL_122,  //101
+/* 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_122,  //110
-                                     SQ_ALU_SCL_122}; //111
+/* 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;
+               }
+
+               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)
-{
-       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;
+static int reserve_cfile(struct alu_bank_swizzle *bs, unsigned sel, unsigned chan)
+{
+       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;
-}
-
-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;
+       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 ret;
+       return 0;       
 }
 
+static int is_gpr(unsigned sel)
+{
+       return (sel >= 0 && sel <= 127);
+}
 
+static int is_cfile(unsigned sel)
+{
+       return (sel > 255 && sel < 512);
+}
 
-static void update_chan_counter(struct r600_bc_alu *alu, int *chan_counter)
+static int is_const(int sel)
 {
-       int num_src;
-       int i;
-       int channel_swizzle;
+       return is_cfile(sel) ||
+               (sel >= V_SQ_ALU_SRC_0 && 
+               sel <= V_SQ_ALU_SRC_LITERAL);
+}
 
-       num_src = r600_bc_get_num_operands(alu);
+static int check_vector(struct r600_bc_alu *alu, struct alu_bank_swizzle *bs, int bank_swizzle)
+{
+       int r, src, num_src, sel, elem, cycle;
 
-       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]++;
+       num_src = r600_bc_get_num_operands(alu);
+       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 };
+       int r, src, num_src, const_count, sel, elem, cycle;
 
-       update_chan_counter(alu_first, chan_counter);
-
-       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;
 }
 
@@ -416,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 */
@@ -469,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;
@@ -502,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);
@@ -543,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;
 }
@@ -572,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;
 }
@@ -592,10 +811,34 @@ int r600_bc_add_cfinst(struct r600_bc *bc, int inst)
 /* common to all 3 families */
 static int r600_bc_vtx_build(struct r600_bc *bc, struct r600_bc_vtx *vtx, unsigned id)
 {
-       bc->bytecode[id++] = S_SQ_VTX_WORD0_BUFFER_ID(vtx->buffer_id) |
-                               S_SQ_VTX_WORD0_SRC_GPR(vtx->src_gpr) |
-                               S_SQ_VTX_WORD0_SRC_SEL_X(vtx->src_sel_x) |
-                               S_SQ_VTX_WORD0_MEGA_FETCH_COUNT(vtx->mega_fetch_count);
+       unsigned fetch_resource_start = 0;
+
+       /* check if we are fetch shader */
+                       /* fetch shader can also access vertex resource,
+                        * first fetch shader resource is at 160
+                        */
+       if (bc->type == -1) {
+               switch (bc->chiprev) {
+               /* r600 */
+               case CHIPREV_R600:
+               /* r700 */
+               case CHIPREV_R700:
+                       fetch_resource_start = 160;
+                       break;
+               /* evergreen */
+               case CHIPREV_EVERGREEN:
+                       fetch_resource_start = 0;
+                       break;
+               default:
+                       fprintf(stderr,  "%s:%s:%d unknown chiprev %d\n",
+                               __FILE__, __func__, __LINE__, bc->chiprev);
+                       break;
+               }
+       }
+       bc->bytecode[id++] = S_SQ_VTX_WORD0_BUFFER_ID(vtx->buffer_id + fetch_resource_start) |
+                       S_SQ_VTX_WORD0_SRC_GPR(vtx->src_gpr) |
+                       S_SQ_VTX_WORD0_SRC_SEL_X(vtx->src_sel_x) |
+                       S_SQ_VTX_WORD0_MEGA_FETCH_COUNT(vtx->mega_fetch_count);
        bc->bytecode[id++] = S_SQ_VTX_WORD1_DST_SEL_X(vtx->dst_sel_x) |
                                S_SQ_VTX_WORD1_DST_SEL_Y(vtx->dst_sel_y) |
                                S_SQ_VTX_WORD1_DST_SEL_Z(vtx->dst_sel_z) |
@@ -676,10 +919,11 @@ 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) |
-                                       S_SQ_ALU_WORD1_OP2_UPDATE_PRED(alu->predicate);
+                                       S_SQ_ALU_WORD1_OP2_UPDATE_EXECUTE_MASK(alu->predicate) |
+                                       S_SQ_ALU_WORD1_OP2_UPDATE_PRED(alu->predicate);
        }
        if (alu->last) {
                if (alu->nliteral && !alu->literal_added) {
@@ -699,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) |
@@ -710,7 +956,7 @@ static int r600_bc_cf_build(struct r600_bc *bc, struct r600_bc_cf *cf)
                        S_SQ_CF_ALU_WORD1_KCACHE_ADDR0(cf->kcache0_addr) |
                        S_SQ_CF_ALU_WORD1_KCACHE_ADDR1(cf->kcache1_addr) |
                                        S_SQ_CF_ALU_WORD1_BARRIER(1) |
-                                       S_SQ_CF_ALU_WORD1_USES_WATERFALL(bc->chiprev == 0 ? cf->r6xx_uses_waterfall : 0) |
+                                       S_SQ_CF_ALU_WORD1_USES_WATERFALL(bc->chiprev == CHIPREV_R600 ? cf->r6xx_uses_waterfall : 0) |
                                        S_SQ_CF_ALU_WORD1_COUNT((cf->ndw / 2) - 1);
                break;
        case V_SQ_CF_WORD1_SQ_CF_INST_TEX:
@@ -742,6 +988,8 @@ static int r600_bc_cf_build(struct r600_bc *bc, struct r600_bc_cf *cf)
        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:
                bc->bytecode[id++] = S_SQ_CF_WORD0_ADDR(cf->cf_addr >> 1);
                bc->bytecode[id++] = S_SQ_CF_WORD1_CF_INST(cf->inst) |
                                        S_SQ_CF_WORD1_BARRIER(1) |
@@ -766,7 +1014,10 @@ int r600_bc_build(struct r600_bc *bc)
        int r;
 
        if (bc->callstack[0].max > 0)
-           bc->nstack = ((bc->callstack[0].max + 3) >> 2) + 2;
+               bc->nstack = ((bc->callstack[0].max + 3) >> 2) + 2;
+       if (bc->type == TGSI_PROCESSOR_VERTEX && !bc->nstack) {
+               bc->nstack = 1;
+       }
 
        /* first path compute addr of each CF block */
        /* addr start after all the CF instructions */
@@ -774,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:
@@ -795,6 +1048,8 @@ int r600_bc_build(struct r600_bc *bc)
                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:
                        break;
                default:
                        R600_ERR("unsupported CF instruction (0x%X)\n", cf->inst);
@@ -810,7 +1065,7 @@ int r600_bc_build(struct r600_bc *bc)
                return -ENOMEM;
        LIST_FOR_EACH_ENTRY(cf, &bc->cf, list) {
                addr = cf->addr;
-               if (bc->chiprev == 2)
+               if (bc->chiprev == CHIPREV_EVERGREEN)
                        r = eg_bc_cf_build(bc, cf);
                else
                        r = r600_bc_cf_build(bc, cf);
@@ -818,14 +1073,16 @@ 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) {
-                               case 0:
+                               case CHIPREV_R600:
                                        r = r600_bc_alu_build(bc, alu, addr);
                                        break;
-                               case 1:
-                               case 2: /* eg alu is same encoding as r700 */
+                               case CHIPREV_R700:
+                               case CHIPREV_EVERGREEN: /* eg alu is same encoding as r700 */
                                        r = r700_bc_alu_build(bc, alu, addr);
                                        break;
                                default:
@@ -868,6 +1125,8 @@ int r600_bc_build(struct r600_bc *bc)
                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_CALL_FS:
+               case V_SQ_CF_WORD1_SQ_CF_INST_RETURN:
                        break;
                default:
                        R600_ERR("unsupported CF instruction (0x%X)\n", cf->inst);
@@ -879,15 +1138,15 @@ int r600_bc_build(struct r600_bc *bc)
 
 void r600_bc_clear(struct r600_bc *bc)
 {
-       struct r600_bc_cf *cf, *next_cf;
+       struct r600_bc_cf *cf = NULL, *next_cf;
 
        free(bc->bytecode);
        bc->bytecode = NULL;
 
        LIST_FOR_EACH_ENTRY_SAFE(cf, next_cf, &bc->cf, list) {
-               struct r600_bc_alu *alu, *next_alu;
-               struct r600_bc_tex *tex, *next_tex;
-               struct r600_bc_tex *vtx, *next_vtx;
+               struct r600_bc_alu *alu = NULL, *next_alu;
+               struct r600_bc_tex *tex = NULL, *next_tex;
+               struct r600_bc_tex *vtx = NULL, *next_vtx;
 
                LIST_FOR_EACH_ENTRY_SAFE(alu, next_alu, &cf->alu, list) {
                        free(alu);
@@ -912,3 +1171,440 @@ void r600_bc_clear(struct r600_bc *bc)
 
        LIST_INITHEAD(&cf->list);
 }
+
+void r600_bc_dump(struct r600_bc *bc)
+{
+       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) {
+       case 1:
+               chip = '7';
+               break;
+       case 2:
+               chip = 'E';
+               break;
+       case 0:
+       default:
+               chip = '6';
+               break;
+       }
+       fprintf(stderr, "bytecode %d dw -----------------------\n", bc->ndw);
+       fprintf(stderr, "     %c\n", chip);
+
+       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");
+}
+
+void r600_cf_vtx(struct r600_vertex_element *ve, u32 *bytecode, unsigned count)
+{
+       struct r600_pipe_state *rstate;
+       unsigned i = 0;
+
+       if (count > 8) {
+               bytecode[i++] = S_SQ_CF_WORD0_ADDR(8 >> 1);
+               bytecode[i++] = S_SQ_CF_WORD1_CF_INST(V_SQ_CF_WORD1_SQ_CF_INST_VTX) |
+                                               S_SQ_CF_WORD1_BARRIER(1) |
+                                               S_SQ_CF_WORD1_COUNT(8 - 1);
+               bytecode[i++] = S_SQ_CF_WORD0_ADDR(40 >> 1);
+               bytecode[i++] = S_SQ_CF_WORD1_CF_INST(V_SQ_CF_WORD1_SQ_CF_INST_VTX) |
+                                               S_SQ_CF_WORD1_BARRIER(1) |
+                                               S_SQ_CF_WORD1_COUNT(count - 8 - 1);
+       } else {
+               bytecode[i++] = S_SQ_CF_WORD0_ADDR(8 >> 1);
+               bytecode[i++] = S_SQ_CF_WORD1_CF_INST(V_SQ_CF_WORD1_SQ_CF_INST_VTX) |
+                                               S_SQ_CF_WORD1_BARRIER(1) |
+                                               S_SQ_CF_WORD1_COUNT(count - 1);
+       }
+       bytecode[i++] = S_SQ_CF_WORD0_ADDR(0);
+       bytecode[i++] = S_SQ_CF_WORD1_CF_INST(V_SQ_CF_WORD1_SQ_CF_INST_RETURN) |
+                       S_SQ_CF_WORD1_BARRIER(1);
+
+       rstate = &ve->rstate;
+       rstate->id = R600_PIPE_STATE_FETCH_SHADER;
+       rstate->nregs = 0;
+       r600_pipe_state_add_reg(rstate, R_0288A4_SQ_PGM_RESOURCES_FS,
+                               0x00000000, 0xFFFFFFFF, NULL);
+       r600_pipe_state_add_reg(rstate, R_0288DC_SQ_PGM_CF_OFFSET_FS,
+                               0x00000000, 0xFFFFFFFF, NULL);
+       r600_pipe_state_add_reg(rstate, R_028894_SQ_PGM_START_FS,
+                               r600_bo_offset(ve->fetch_shader) >> 8,
+                               0xFFFFFFFF, ve->fetch_shader);
+}
+
+void r600_cf_vtx_tc(struct r600_vertex_element *ve, u32 *bytecode, unsigned count)
+{
+       struct r600_pipe_state *rstate;
+       unsigned i = 0;
+
+       if (count > 8) {
+               bytecode[i++] = S_SQ_CF_WORD0_ADDR(8 >> 1);
+               bytecode[i++] = S_SQ_CF_WORD1_CF_INST(V_SQ_CF_WORD1_SQ_CF_INST_VTX_TC) |
+                                               S_SQ_CF_WORD1_BARRIER(1) |
+                                               S_SQ_CF_WORD1_COUNT(8 - 1);
+               bytecode[i++] = S_SQ_CF_WORD0_ADDR(40 >> 1);
+               bytecode[i++] = S_SQ_CF_WORD1_CF_INST(V_SQ_CF_WORD1_SQ_CF_INST_VTX_TC) |
+                                               S_SQ_CF_WORD1_BARRIER(1) |
+                                               S_SQ_CF_WORD1_COUNT((count - 8) - 1);
+       } else {
+               bytecode[i++] = S_SQ_CF_WORD0_ADDR(8 >> 1);
+               bytecode[i++] = S_SQ_CF_WORD1_CF_INST(V_SQ_CF_WORD1_SQ_CF_INST_VTX_TC) |
+                                               S_SQ_CF_WORD1_BARRIER(1) |
+                                               S_SQ_CF_WORD1_COUNT(count - 1);
+       }
+       bytecode[i++] = S_SQ_CF_WORD0_ADDR(0);
+       bytecode[i++] = S_SQ_CF_WORD1_CF_INST(V_SQ_CF_WORD1_SQ_CF_INST_RETURN) |
+                       S_SQ_CF_WORD1_BARRIER(1);
+
+       rstate = &ve->rstate;
+       rstate->id = R600_PIPE_STATE_FETCH_SHADER;
+       rstate->nregs = 0;
+       r600_pipe_state_add_reg(rstate, R_0288A4_SQ_PGM_RESOURCES_FS,
+                               0x00000000, 0xFFFFFFFF, NULL);
+       r600_pipe_state_add_reg(rstate, R_0288DC_SQ_PGM_CF_OFFSET_FS,
+                               0x00000000, 0xFFFFFFFF, NULL);
+       r600_pipe_state_add_reg(rstate, R_028894_SQ_PGM_START_FS,
+                               r600_bo_offset(ve->fetch_shader) >> 8,
+                               0xFFFFFFFF, ve->fetch_shader);
+}
+
+static void r600_vertex_data_type(enum pipe_format pformat, unsigned *format,
+                               unsigned *num_format, unsigned *format_comp)
+{
+       const struct util_format_description *desc;
+       unsigned i;
+
+       *format = 0;
+       *num_format = 0;
+       *format_comp = 0;
+
+       desc = util_format_description(pformat);
+       if (desc->layout != UTIL_FORMAT_LAYOUT_PLAIN) {
+               goto out_unknown;
+       }
+
+       /* Find the first non-VOID channel. */
+       for (i = 0; i < 4; i++) {
+               if (desc->channel[i].type != UTIL_FORMAT_TYPE_VOID) {
+                       break;
+               }
+       }
+
+       switch (desc->channel[i].type) {
+               /* Half-floats, floats, doubles */
+       case UTIL_FORMAT_TYPE_FLOAT:
+               switch (desc->channel[i].size) {
+               case 16:
+                       switch (desc->nr_channels) {
+                       case 1:
+                               *format = FMT_16_FLOAT;
+                               break;
+                       case 2:
+                               *format = FMT_16_16_FLOAT;
+                               break;
+                       case 3:
+                               *format = FMT_16_16_16_FLOAT;
+                               break;
+                       case 4:
+                               *format = FMT_16_16_16_16_FLOAT;
+                               break;
+                       }
+                       break;
+               case 32:
+                       switch (desc->nr_channels) {
+                       case 1:
+                               *format = FMT_32_FLOAT;
+                               break;
+                       case 2:
+                               *format = FMT_32_32_FLOAT;
+                               break;
+                       case 3:
+                               *format = FMT_32_32_32_FLOAT;
+                               break;
+                       case 4:
+                               *format = FMT_32_32_32_32_FLOAT;
+                               break;
+                       }
+                       break;
+               default:
+                       goto out_unknown;
+               }
+               break;
+               /* Unsigned ints */
+       case UTIL_FORMAT_TYPE_UNSIGNED:
+               /* Signed ints */
+       case UTIL_FORMAT_TYPE_SIGNED:
+               switch (desc->channel[i].size) {
+               case 8:
+                       switch (desc->nr_channels) {
+                       case 1:
+                               *format = FMT_8;
+                               break;
+                       case 2:
+                               *format = FMT_8_8;
+                               break;
+                       case 3:
+                       //      *format = FMT_8_8_8; /* fails piglit draw-vertices test */
+                       //      break;
+                       case 4:
+                               *format = FMT_8_8_8_8;
+                               break;
+                       }
+                       break;
+               case 16:
+                       switch (desc->nr_channels) {
+                       case 1:
+                               *format = FMT_16;
+                               break;
+                       case 2:
+                               *format = FMT_16_16;
+                               break;
+                       case 3:
+                       //      *format = FMT_16_16_16; /* fails piglit draw-vertices test */
+                       //      break;
+                       case 4:
+                               *format = FMT_16_16_16_16;
+                               break;
+                       }
+                       break;
+               case 32:
+                       switch (desc->nr_channels) {
+                       case 1:
+                               *format = FMT_32;
+                               break;
+                       case 2:
+                               *format = FMT_32_32;
+                               break;
+                       case 3:
+                               *format = FMT_32_32_32;
+                               break;
+                       case 4:
+                               *format = FMT_32_32_32_32;
+                               break;
+                       }
+                       break;
+               default:
+                       goto out_unknown;
+               }
+               break;
+       default:
+               goto out_unknown;
+       }
+
+       if (desc->channel[i].type == UTIL_FORMAT_TYPE_SIGNED) {
+               *format_comp = 1;
+       }
+       if (desc->channel[i].normalized) {
+               *num_format = 0;
+       } else {
+               *num_format = 2;
+       }
+       return;
+out_unknown:
+       R600_ERR("unsupported vertex format %s\n", util_format_name(pformat));
+}
+
+int r600_vertex_elements_build_fetch_shader(struct r600_pipe_context *rctx, struct r600_vertex_element *ve)
+{
+       unsigned ndw, i;
+       u32 *bytecode;
+       unsigned fetch_resource_start = 0, format, num_format, format_comp;
+       struct pipe_vertex_element *elements = ve->elements;
+       const struct util_format_description *desc;
+
+       /* 2 dwords for cf aligned to 4 + 4 dwords per input */
+       ndw = 8 + ve->count * 4;
+       ve->fs_size = ndw * 4;
+
+       /* use PIPE_BIND_VERTEX_BUFFER so we use the cache buffer manager */
+       ve->fetch_shader = r600_bo(rctx->radeon, ndw*4, 256, PIPE_BIND_VERTEX_BUFFER, 0);
+       if (ve->fetch_shader == NULL) {
+               return -ENOMEM;
+       }
+
+       bytecode = r600_bo_map(rctx->radeon, ve->fetch_shader, 0, NULL);
+       if (bytecode == NULL) {
+               r600_bo_reference(rctx->radeon, &ve->fetch_shader, NULL);
+               return -ENOMEM;
+       }
+
+       if (rctx->family >= CHIP_CEDAR) {
+               eg_cf_vtx(ve, &bytecode[0], (ndw - 8) / 4);
+       } else {
+               r600_cf_vtx(ve, &bytecode[0], (ndw - 8) / 4);
+               fetch_resource_start = 160;
+       }
+
+       /* vertex elements offset need special handling, if offset is bigger
+        * than what we can put in fetch instruction then we need to alterate
+        * the vertex resource offset. In such case in order to simplify code
+        * we will bound one resource per elements. It's a worst case scenario.
+        */
+       for (i = 0; i < ve->count; i++) {
+               ve->vbuffer_offset[i] = C_SQ_VTX_WORD2_OFFSET & elements[i].src_offset;
+               if (ve->vbuffer_offset[i]) {
+                       ve->vbuffer_need_offset = 1;
+               }
+       }
+
+       for (i = 0; i < ve->count; i++) {
+               unsigned vbuffer_index;
+               r600_vertex_data_type(ve->hw_format[i], &format, &num_format, &format_comp);
+               desc = util_format_description(ve->hw_format[i]);
+               if (desc == NULL) {
+                       R600_ERR("unknown format %d\n", ve->hw_format[i]);
+                       r600_bo_reference(rctx->radeon, &ve->fetch_shader, NULL);
+                       return -EINVAL;
+               }
+
+               /* see above for vbuffer_need_offset explanation */
+               vbuffer_index = elements[i].vertex_buffer_index;
+               if (ve->vbuffer_need_offset) {
+                       bytecode[8 + i * 4 + 0] = S_SQ_VTX_WORD0_BUFFER_ID(i + fetch_resource_start);
+               } else {
+                       bytecode[8 + i * 4 + 0] = S_SQ_VTX_WORD0_BUFFER_ID(vbuffer_index + fetch_resource_start);
+               }
+               bytecode[8 + i * 4 + 0] |= S_SQ_VTX_WORD0_SRC_GPR(0) |
+                                       S_SQ_VTX_WORD0_SRC_SEL_X(0) |
+                                       S_SQ_VTX_WORD0_MEGA_FETCH_COUNT(0x1F);
+               bytecode[8 + i * 4 + 1] = S_SQ_VTX_WORD1_DST_SEL_X(desc->swizzle[0]) |
+                                       S_SQ_VTX_WORD1_DST_SEL_Y(desc->swizzle[1]) |
+                                       S_SQ_VTX_WORD1_DST_SEL_Z(desc->swizzle[2]) |
+                                       S_SQ_VTX_WORD1_DST_SEL_W(desc->swizzle[3]) |
+                                       S_SQ_VTX_WORD1_USE_CONST_FIELDS(0) |
+                                       S_SQ_VTX_WORD1_DATA_FORMAT(format) |
+                                       S_SQ_VTX_WORD1_NUM_FORMAT_ALL(num_format) |
+                                       S_SQ_VTX_WORD1_FORMAT_COMP_ALL(format_comp) |
+                                       S_SQ_VTX_WORD1_SRF_MODE_ALL(1) |
+                                       S_SQ_VTX_WORD1_GPR_DST_GPR(i + 1);
+               bytecode[8 + i * 4 + 2] = S_SQ_VTX_WORD2_OFFSET(elements[i].src_offset) |
+                                       S_SQ_VTX_WORD2_MEGA_FETCH(1);
+               bytecode[8 + i * 4 + 3] = 0;
+       }
+       r600_bo_unmap(rctx->radeon, ve->fetch_shader);
+       return 0;
+}