r600: double multiply can handle only one multiply at a time
[mesa.git] / src / gallium / drivers / r600 / r600_shader.c
index f7b8495df08d5d79932567dc816f16ae8fda477d..7d1452add343bb88d473c9ebe0b5ba7c891eaa54 100644 (file)
@@ -137,7 +137,7 @@ static int store_shader(struct pipe_context *ctx,
 
        if (shader->bo == NULL) {
                shader->bo = (struct r600_resource*)
-                       pipe_buffer_create(ctx->screen, PIPE_BIND_CUSTOM, PIPE_USAGE_IMMUTABLE, shader->shader.bc.ndw * 4);
+                       pipe_buffer_create(ctx->screen, 0, PIPE_USAGE_IMMUTABLE, shader->shader.bc.ndw * 4);
                if (shader->bo == NULL) {
                        return -ENOMEM;
                }
@@ -3804,9 +3804,6 @@ static int tgsi_op2_64_params(struct r600_shader_ctx *ctx, bool singledest, bool
                /* handle some special cases */
                if (i == 1 || i == 3) {
                        switch (ctx->parse.FullToken.FullInstruction.Instruction.Opcode) {
-                       case TGSI_OPCODE_SUB:
-                               r600_bytecode_src_toggle_neg(&alu.src[1]);
-                               break;
                        case TGSI_OPCODE_DABS:
                                r600_bytecode_src_set_abs(&alu.src[0]);
                                break;
@@ -3931,17 +3928,6 @@ static int tgsi_op2_s(struct r600_shader_ctx *ctx, int swap, int trans_only)
                        r600_bytecode_src(&alu.src[0], &ctx->src[1], i);
                        r600_bytecode_src(&alu.src[1], &ctx->src[0], i);
                }
-               /* handle some special cases */
-               switch (inst->Instruction.Opcode) {
-               case TGSI_OPCODE_SUB:
-                       r600_bytecode_src_toggle_neg(&alu.src[1]);
-                       break;
-               case TGSI_OPCODE_ABS:
-                       r600_bytecode_src_set_abs(&alu.src[0]);
-                       break;
-               default:
-                       break;
-               }
                if (i == lasti || trans_only) {
                        alu.last = 1;
                }
@@ -4340,25 +4326,27 @@ static int cayman_mul_double_instr(struct r600_shader_ctx *ctx)
        int lasti = tgsi_last_instruction(inst->Dst[0].Register.WriteMask);
        int t1 = ctx->temp_reg;
 
-       for (k = 0; k < 2; k++) {
-               if (!(inst->Dst[0].Register.WriteMask & (0x3 << (k * 2))))
-                       continue;
+       /* t1 would get overwritten below if we actually tried to
+        * multiply two pairs of doubles at a time. */
+       assert(inst->Dst[0].Register.WriteMask == TGSI_WRITEMASK_XY ||
+              inst->Dst[0].Register.WriteMask == TGSI_WRITEMASK_ZW);
 
-               for (i = 0; i < 4; i++) {
-                       memset(&alu, 0, sizeof(struct r600_bytecode_alu));
-                       alu.op = ctx->inst_info->op;
-                       for (j = 0; j < inst->Instruction.NumSrcRegs; j++) {
-                               r600_bytecode_src(&alu.src[j], &ctx->src[j], k * 2 + ((i == 3) ? 0 : 1));
-                       }
-                       alu.dst.sel = t1;
-                       alu.dst.chan = i;
-                       alu.dst.write = 1;
-                       if (i == 3)
-                               alu.last = 1;
-                       r = r600_bytecode_add_alu(ctx->bc, &alu);
-                       if (r)
-                               return r;
+       k = inst->Dst[0].Register.WriteMask == TGSI_WRITEMASK_XY ? 0 : 1;
+
+       for (i = 0; i < 4; i++) {
+               memset(&alu, 0, sizeof(struct r600_bytecode_alu));
+               alu.op = ctx->inst_info->op;
+               for (j = 0; j < inst->Instruction.NumSrcRegs; j++) {
+                       r600_bytecode_src(&alu.src[j], &ctx->src[j], k * 2 + ((i == 3) ? 0 : 1));
                }
+               alu.dst.sel = t1;
+               alu.dst.chan = i;
+               alu.dst.write = 1;
+               if (i == 3)
+                       alu.last = 1;
+               r = r600_bytecode_add_alu(ctx->bc, &alu);
+               if (r)
+                       return r;
        }
 
        for (i = 0; i <= lasti; i++) {
@@ -8886,6 +8874,105 @@ static int tgsi_umad(struct r600_shader_ctx *ctx)
        return 0;
 }
 
+static int tgsi_pk2h(struct r600_shader_ctx *ctx)
+{
+       struct tgsi_full_instruction *inst = &ctx->parse.FullToken.FullInstruction;
+       struct r600_bytecode_alu alu;
+       int r, i;
+       int lasti = tgsi_last_instruction(inst->Dst[0].Register.WriteMask);
+
+       /* temp.xy = f32_to_f16(src) */
+       memset(&alu, 0, sizeof(struct r600_bytecode_alu));
+       alu.op = ALU_OP1_FLT32_TO_FLT16;
+       alu.dst.chan = 0;
+       alu.dst.sel = ctx->temp_reg;
+       alu.dst.write = 1;
+       r600_bytecode_src(&alu.src[0], &ctx->src[0], 0);
+       r = r600_bytecode_add_alu(ctx->bc, &alu);
+       if (r)
+               return r;
+       alu.dst.chan = 1;
+       r600_bytecode_src(&alu.src[0], &ctx->src[0], 1);
+       alu.last = 1;
+       r = r600_bytecode_add_alu(ctx->bc, &alu);
+       if (r)
+               return r;
+
+       /* dst.x = temp.y * 0x10000 + temp.x */
+       for (i = 0; i < lasti + 1; i++) {
+               if (!(inst->Dst[0].Register.WriteMask & (1 << i)))
+                       continue;
+
+               memset(&alu, 0, sizeof(struct r600_bytecode_alu));
+               alu.op = ALU_OP3_MULADD_UINT24;
+               alu.is_op3 = 1;
+               tgsi_dst(ctx, &inst->Dst[0], i, &alu.dst);
+               alu.last = i == lasti;
+               alu.src[0].sel = ctx->temp_reg;
+               alu.src[0].chan = 1;
+               alu.src[1].sel = V_SQ_ALU_SRC_LITERAL;
+               alu.src[1].value = 0x10000;
+               alu.src[2].sel = ctx->temp_reg;
+               alu.src[2].chan = 0;
+               r = r600_bytecode_add_alu(ctx->bc, &alu);
+               if (r)
+                       return r;
+       }
+
+       return 0;
+}
+
+static int tgsi_up2h(struct r600_shader_ctx *ctx)
+{
+       struct tgsi_full_instruction *inst = &ctx->parse.FullToken.FullInstruction;
+       struct r600_bytecode_alu alu;
+       int r, i;
+       int lasti = tgsi_last_instruction(inst->Dst[0].Register.WriteMask);
+
+       /* temp.x = src.x */
+       /* note: no need to mask out the high bits */
+       memset(&alu, 0, sizeof(struct r600_bytecode_alu));
+       alu.op = ALU_OP1_MOV;
+       alu.dst.chan = 0;
+       alu.dst.sel = ctx->temp_reg;
+       alu.dst.write = 1;
+       r600_bytecode_src(&alu.src[0], &ctx->src[0], 0);
+       r = r600_bytecode_add_alu(ctx->bc, &alu);
+       if (r)
+               return r;
+
+       /* temp.y = src.x >> 16 */
+       memset(&alu, 0, sizeof(struct r600_bytecode_alu));
+       alu.op = ALU_OP2_LSHR_INT;
+       alu.dst.chan = 1;
+       alu.dst.sel = ctx->temp_reg;
+       alu.dst.write = 1;
+       r600_bytecode_src(&alu.src[0], &ctx->src[0], 0);
+       alu.src[1].sel = V_SQ_ALU_SRC_LITERAL;
+       alu.src[1].value = 16;
+       alu.last = 1;
+       r = r600_bytecode_add_alu(ctx->bc, &alu);
+       if (r)
+               return r;
+
+       /* dst.wz = dst.xy = f16_to_f32(temp.xy) */
+       for (i = 0; i < lasti + 1; i++) {
+               if (!(inst->Dst[0].Register.WriteMask & (1 << i)))
+                       continue;
+               memset(&alu, 0, sizeof(struct r600_bytecode_alu));
+               tgsi_dst(ctx, &inst->Dst[0], i, &alu.dst);
+               alu.op = ALU_OP1_FLT16_TO_FLT32;
+               alu.src[0].sel = ctx->temp_reg;
+               alu.src[0].chan = i % 2;
+               alu.last = i == lasti;
+               r = r600_bytecode_add_alu(ctx->bc, &alu);
+               if (r)
+                       return r;
+       }
+
+       return 0;
+}
+
 static const struct r600_shader_tgsi_instruction r600_shader_tgsi_instruction[] = {
        [TGSI_OPCODE_ARL]       = { ALU_OP0_NOP, tgsi_r600_arl},
        [TGSI_OPCODE_MOV]       = { ALU_OP1_MOV, tgsi_op2},
@@ -8910,7 +8997,6 @@ static const struct r600_shader_tgsi_instruction r600_shader_tgsi_instruction[]
        [TGSI_OPCODE_SLT]       = { ALU_OP2_SETGT, tgsi_op2_swap},
        [TGSI_OPCODE_SGE]       = { ALU_OP2_SETGE, tgsi_op2},
        [TGSI_OPCODE_MAD]       = { ALU_OP3_MULADD, tgsi_op3},
-       [TGSI_OPCODE_SUB]       = { ALU_OP2_ADD, tgsi_op2},
        [TGSI_OPCODE_LRP]       = { ALU_OP0_NOP, tgsi_lrp},
        [TGSI_OPCODE_FMA]       = { ALU_OP0_NOP, tgsi_unsupported},
        [TGSI_OPCODE_SQRT]      = { ALU_OP1_SQRT_IEEE, tgsi_trans_srcx_replicate},
@@ -8926,7 +9012,7 @@ static const struct r600_shader_tgsi_instruction r600_shader_tgsi_instruction[]
        [TGSI_OPCODE_POW]       = { ALU_OP0_NOP, tgsi_pow},
        [TGSI_OPCODE_XPD]       = { ALU_OP0_NOP, tgsi_xpd},
        [32]                    = { ALU_OP0_NOP, tgsi_unsupported},
-       [TGSI_OPCODE_ABS]       = { ALU_OP1_MOV, tgsi_op2},
+       [33]                    = { ALU_OP0_NOP, tgsi_unsupported},
        [34]                    = { ALU_OP0_NOP, tgsi_unsupported},
        [TGSI_OPCODE_DPH]       = { ALU_OP2_DOT4, tgsi_dp},
        [TGSI_OPCODE_COS]       = { ALU_OP1_COS, tgsi_trig},
@@ -9109,7 +9195,6 @@ static const struct r600_shader_tgsi_instruction eg_shader_tgsi_instruction[] =
        [TGSI_OPCODE_SLT]       = { ALU_OP2_SETGT, tgsi_op2_swap},
        [TGSI_OPCODE_SGE]       = { ALU_OP2_SETGE, tgsi_op2},
        [TGSI_OPCODE_MAD]       = { ALU_OP3_MULADD, tgsi_op3},
-       [TGSI_OPCODE_SUB]       = { ALU_OP2_ADD, tgsi_op2},
        [TGSI_OPCODE_LRP]       = { ALU_OP0_NOP, tgsi_lrp},
        [TGSI_OPCODE_FMA]       = { ALU_OP3_FMA, tgsi_op3},
        [TGSI_OPCODE_SQRT]      = { ALU_OP1_SQRT_IEEE, tgsi_trans_srcx_replicate},
@@ -9125,14 +9210,14 @@ static const struct r600_shader_tgsi_instruction eg_shader_tgsi_instruction[] =
        [TGSI_OPCODE_POW]       = { ALU_OP0_NOP, tgsi_pow},
        [TGSI_OPCODE_XPD]       = { ALU_OP0_NOP, tgsi_xpd},
        [32]                    = { ALU_OP0_NOP, tgsi_unsupported},
-       [TGSI_OPCODE_ABS]       = { ALU_OP1_MOV, tgsi_op2},
+       [33]                    = { ALU_OP0_NOP, tgsi_unsupported},
        [34]                    = { ALU_OP0_NOP, tgsi_unsupported},
        [TGSI_OPCODE_DPH]       = { ALU_OP2_DOT4, tgsi_dp},
        [TGSI_OPCODE_COS]       = { ALU_OP1_COS, tgsi_trig},
        [TGSI_OPCODE_DDX]       = { FETCH_OP_GET_GRADIENTS_H, tgsi_tex},
        [TGSI_OPCODE_DDY]       = { FETCH_OP_GET_GRADIENTS_V, tgsi_tex},
        [TGSI_OPCODE_KILL]      = { ALU_OP2_KILLGT, tgsi_kill},  /* unconditional kill */
-       [TGSI_OPCODE_PK2H]      = { ALU_OP0_NOP, tgsi_unsupported},
+       [TGSI_OPCODE_PK2H]      = { ALU_OP0_NOP, tgsi_pk2h},
        [TGSI_OPCODE_PK2US]     = { ALU_OP0_NOP, tgsi_unsupported},
        [TGSI_OPCODE_PK4B]      = { ALU_OP0_NOP, tgsi_unsupported},
        [TGSI_OPCODE_PK4UB]     = { ALU_OP0_NOP, tgsi_unsupported},
@@ -9147,7 +9232,7 @@ static const struct r600_shader_tgsi_instruction eg_shader_tgsi_instruction[] =
        [TGSI_OPCODE_TEX]       = { FETCH_OP_SAMPLE, tgsi_tex},
        [TGSI_OPCODE_TXD]       = { FETCH_OP_SAMPLE_G, tgsi_tex},
        [TGSI_OPCODE_TXP]       = { FETCH_OP_SAMPLE, tgsi_tex},
-       [TGSI_OPCODE_UP2H]      = { ALU_OP0_NOP, tgsi_unsupported},
+       [TGSI_OPCODE_UP2H]      = { ALU_OP0_NOP, tgsi_up2h},
        [TGSI_OPCODE_UP2US]     = { ALU_OP0_NOP, tgsi_unsupported},
        [TGSI_OPCODE_UP4B]      = { ALU_OP0_NOP, tgsi_unsupported},
        [TGSI_OPCODE_UP4UB]     = { ALU_OP0_NOP, tgsi_unsupported},
@@ -9332,7 +9417,6 @@ static const struct r600_shader_tgsi_instruction cm_shader_tgsi_instruction[] =
        [TGSI_OPCODE_SLT]       = { ALU_OP2_SETGT, tgsi_op2_swap},
        [TGSI_OPCODE_SGE]       = { ALU_OP2_SETGE, tgsi_op2},
        [TGSI_OPCODE_MAD]       = { ALU_OP3_MULADD, tgsi_op3},
-       [TGSI_OPCODE_SUB]       = { ALU_OP2_ADD, tgsi_op2},
        [TGSI_OPCODE_LRP]       = { ALU_OP0_NOP, tgsi_lrp},
        [TGSI_OPCODE_FMA]       = { ALU_OP3_FMA, tgsi_op3},
        [TGSI_OPCODE_SQRT]      = { ALU_OP1_SQRT_IEEE, cayman_emit_float_instr},
@@ -9348,14 +9432,14 @@ static const struct r600_shader_tgsi_instruction cm_shader_tgsi_instruction[] =
        [TGSI_OPCODE_POW]       = { ALU_OP0_NOP, cayman_pow},
        [TGSI_OPCODE_XPD]       = { ALU_OP0_NOP, tgsi_xpd},
        [32]                    = { ALU_OP0_NOP, tgsi_unsupported},
-       [TGSI_OPCODE_ABS]       = { ALU_OP1_MOV, tgsi_op2},
+       [33]                    = { ALU_OP0_NOP, tgsi_unsupported},
        [34]                    = { ALU_OP0_NOP, tgsi_unsupported},
        [TGSI_OPCODE_DPH]       = { ALU_OP2_DOT4, tgsi_dp},
        [TGSI_OPCODE_COS]       = { ALU_OP1_COS, cayman_trig},
        [TGSI_OPCODE_DDX]       = { FETCH_OP_GET_GRADIENTS_H, tgsi_tex},
        [TGSI_OPCODE_DDY]       = { FETCH_OP_GET_GRADIENTS_V, tgsi_tex},
        [TGSI_OPCODE_KILL]      = { ALU_OP2_KILLGT, tgsi_kill},  /* unconditional kill */
-       [TGSI_OPCODE_PK2H]      = { ALU_OP0_NOP, tgsi_unsupported},
+       [TGSI_OPCODE_PK2H]      = { ALU_OP0_NOP, tgsi_pk2h},
        [TGSI_OPCODE_PK2US]     = { ALU_OP0_NOP, tgsi_unsupported},
        [TGSI_OPCODE_PK4B]      = { ALU_OP0_NOP, tgsi_unsupported},
        [TGSI_OPCODE_PK4UB]     = { ALU_OP0_NOP, tgsi_unsupported},
@@ -9370,7 +9454,7 @@ static const struct r600_shader_tgsi_instruction cm_shader_tgsi_instruction[] =
        [TGSI_OPCODE_TEX]       = { FETCH_OP_SAMPLE, tgsi_tex},
        [TGSI_OPCODE_TXD]       = { FETCH_OP_SAMPLE_G, tgsi_tex},
        [TGSI_OPCODE_TXP]       = { FETCH_OP_SAMPLE, tgsi_tex},
-       [TGSI_OPCODE_UP2H]      = { ALU_OP0_NOP, tgsi_unsupported},
+       [TGSI_OPCODE_UP2H]      = { ALU_OP0_NOP, tgsi_up2h},
        [TGSI_OPCODE_UP2US]     = { ALU_OP0_NOP, tgsi_unsupported},
        [TGSI_OPCODE_UP4B]      = { ALU_OP0_NOP, tgsi_unsupported},
        [TGSI_OPCODE_UP4UB]     = { ALU_OP0_NOP, tgsi_unsupported},