[Mesa-dev] [PATCH] tgsi: Add a conditional move inststruction

Zack Rusin zackr at vmware.com
Wed Apr 3 18:45:16 PDT 2013


It's part of SM4 (http://goo.gl/4IpeK). It's also fairly
painful to emulate without branching. Most hardware
supports it natively and even llvm has a 'select' opcode
which can handle it without too much hassle.

Signed-off-by: Zack Rusin <zackr at vmware.com>
---
 src/gallium/auxiliary/gallivm/lp_bld_tgsi_action.c  |   19 ++++++++++++++++++-
 src/gallium/auxiliary/tgsi/tgsi_exec.c              |   17 +++++++++++++++++
 src/gallium/auxiliary/tgsi/tgsi_info.c              |    1 +
 src/gallium/auxiliary/tgsi/tgsi_opcode_tmp.h        |    2 +-
 src/gallium/docs/source/tgsi.rst                    |   11 +++++++++++
 src/gallium/drivers/r600/r600_shader.c              |    3 +++
 src/gallium/include/pipe/p_shader_tokens.h          |    4 +++-
 src/gallium/tests/graw/fragment-shader/frag-movc.sh |   11 +++++++++++
 8 files changed, 65 insertions(+), 3 deletions(-)
 create mode 100644 src/gallium/tests/graw/fragment-shader/frag-movc.sh

diff --git a/src/gallium/auxiliary/gallivm/lp_bld_tgsi_action.c b/src/gallium/auxiliary/gallivm/lp_bld_tgsi_action.c
index dfe581d..3a06542 100644
--- a/src/gallium/auxiliary/gallivm/lp_bld_tgsi_action.c
+++ b/src/gallium/auxiliary/gallivm/lp_bld_tgsi_action.c
@@ -563,7 +563,6 @@ mad_emit(
 }
 
 /* TGSI_OPCODE_MOV */
-
 static void
 mov_emit(
    const struct lp_build_tgsi_action * action,
@@ -573,6 +572,23 @@ mov_emit(
    emit_data->output[emit_data->chan] = emit_data->args[0];
 }
 
+/* TGSI_OPCODE_MOVC */
+static void
+movc_emit(
+   const struct lp_build_tgsi_action * action,
+   struct lp_build_tgsi_context * bld_base,
+   struct lp_build_emit_data * emit_data)
+{
+   LLVMBuilderRef builder = bld_base->base.gallivm->builder;
+   emit_data->output[emit_data->chan] =
+      LLVMBuildSelect(builder,
+                      LLVMBuildFCmp(builder, LLVMRealUNE,
+                                    emit_data->args[0],
+                                    bld_base->base.zero, ""),
+                      emit_data->args[1], emit_data->args[2], "");
+}
+
+
 /* TGSI_OPCODE_MUL */
 static void
 mul_emit(
@@ -882,6 +898,7 @@ lp_set_default_actions(struct lp_build_tgsi_context * bld_base)
    bld_base->op_actions[TGSI_OPCODE_LRP].emit = lrp_emit;
    bld_base->op_actions[TGSI_OPCODE_MAD].emit = mad_emit;
    bld_base->op_actions[TGSI_OPCODE_MOV].emit = mov_emit;
+   bld_base->op_actions[TGSI_OPCODE_MOVC].emit = movc_emit;
    bld_base->op_actions[TGSI_OPCODE_MUL].emit = mul_emit;
    bld_base->op_actions[TGSI_OPCODE_DIV].emit = fdiv_emit;
    bld_base->op_actions[TGSI_OPCODE_RCP].emit = rcp_emit;
diff --git a/src/gallium/auxiliary/tgsi/tgsi_exec.c b/src/gallium/auxiliary/tgsi/tgsi_exec.c
index 8579d8a..b1ab021 100644
--- a/src/gallium/auxiliary/tgsi/tgsi_exec.c
+++ b/src/gallium/auxiliary/tgsi/tgsi_exec.c
@@ -303,6 +303,19 @@ micro_mov(union tgsi_exec_channel *dst,
    dst->u[3] = src->u[3];
 }
 
+
+static void
+micro_movc(union tgsi_exec_channel *dst,
+           const union tgsi_exec_channel *src0,
+           const union tgsi_exec_channel *src1,
+           const union tgsi_exec_channel *src2)
+{
+   dst->u[0] = src0->u[0] ? src1->u[0] : src2->u[0];
+   dst->u[1] = src0->u[1] ? src1->u[1] : src2->u[1];
+   dst->u[2] = src0->u[2] ? src1->u[2] : src2->u[2];
+   dst->u[3] = src0->u[3] ? src1->u[3] : src2->u[3];
+}
+
 static void
 micro_rcp(union tgsi_exec_channel *dst,
           const union tgsi_exec_channel *src)
@@ -4385,6 +4398,10 @@ exec_instruction(
       /* src[2] = sampler unit */
       exec_tex(mach, inst, TEX_MODIFIER_EXPLICIT_LOD, 2);
       break;
+
+   case TGSI_OPCODE_MOVC:
+      exec_vector_trinary(mach, inst, micro_movc, TGSI_EXEC_DATA_UINT, TGSI_EXEC_DATA_FLOAT);
+      break;
    default:
       assert( 0 );
    }
diff --git a/src/gallium/auxiliary/tgsi/tgsi_info.c b/src/gallium/auxiliary/tgsi/tgsi_info.c
index 8ae5523..f7b2dc0 100644
--- a/src/gallium/auxiliary/tgsi/tgsi_info.c
+++ b/src/gallium/auxiliary/tgsi/tgsi_info.c
@@ -219,6 +219,7 @@ static const struct tgsi_opcode_info opcode_info[TGSI_OPCODE_LAST] =
    { 1, 3, 1, 0, 0, 0, OTHR, "TEX2", TGSI_OPCODE_TEX2 },
    { 1, 3, 1, 0, 0, 0, OTHR, "TXB2", TGSI_OPCODE_TXB2 },
    { 1, 3, 1, 0, 0, 0, OTHR, "TXL2", TGSI_OPCODE_TXL2 },
+   { 1, 3, 0, 0, 0, 0, COMP, "MOVC", TGSI_OPCODE_MOVC },
 };
 
 const struct tgsi_opcode_info *
diff --git a/src/gallium/auxiliary/tgsi/tgsi_opcode_tmp.h b/src/gallium/auxiliary/tgsi/tgsi_opcode_tmp.h
index fa30352..7caf15e 100644
--- a/src/gallium/auxiliary/tgsi/tgsi_opcode_tmp.h
+++ b/src/gallium/auxiliary/tgsi/tgsi_opcode_tmp.h
@@ -197,7 +197,7 @@ OP13_SAMPLE(GATHER4)
 OP12(SVIEWINFO)
 OP13(SAMPLE_POS)
 OP12(SAMPLE_INFO)
-
+OP13(MOVC)
 
 #undef OP00
 #undef OP01
diff --git a/src/gallium/docs/source/tgsi.rst b/src/gallium/docs/source/tgsi.rst
index 28308cb..6c5a02b 100644
--- a/src/gallium/docs/source/tgsi.rst
+++ b/src/gallium/docs/source/tgsi.rst
@@ -72,6 +72,17 @@ used.
 
   dst.w = src.w
 
+.. opcode:: MOVC - Conditional move
+
+.. math::
+
+  dst.x = src0.x ? src1.x : src2.x
+
+  dst.y = src0.y ? src1.y : src2.y
+
+  dst.z = src0.z ? src1.z : src2.z
+
+  dst.w = src0.w ? src1.w : src2.w
 
 .. opcode:: LIT - Light Coefficients
 
diff --git a/src/gallium/drivers/r600/r600_shader.c b/src/gallium/drivers/r600/r600_shader.c
index d24d8e7..5aff3d0 100644
--- a/src/gallium/drivers/r600/r600_shader.c
+++ b/src/gallium/drivers/r600/r600_shader.c
@@ -6080,6 +6080,7 @@ static struct r600_shader_tgsi_instruction r600_shader_tgsi_instruction[] = {
 	{TGSI_OPCODE_TEX2,	0, FETCH_OP_SAMPLE, tgsi_tex},
 	{TGSI_OPCODE_TXB2,	0, FETCH_OP_SAMPLE_LB, tgsi_tex},
 	{TGSI_OPCODE_TXL2,	0, FETCH_OP_SAMPLE_L, tgsi_tex},
+	{TGSI_OPCODE_MOVC,	0, ALU_OP0_NOP, tgsi_unsupported},
 	{TGSI_OPCODE_LAST,	0, ALU_OP0_NOP, tgsi_unsupported},
 };
 
@@ -6273,6 +6274,7 @@ static struct r600_shader_tgsi_instruction eg_shader_tgsi_instruction[] = {
 	{TGSI_OPCODE_TEX2,	0, FETCH_OP_SAMPLE, tgsi_tex},
 	{TGSI_OPCODE_TXB2,	0, FETCH_OP_SAMPLE_LB, tgsi_tex},
 	{TGSI_OPCODE_TXL2,	0, FETCH_OP_SAMPLE_L, tgsi_tex},
+	{TGSI_OPCODE_MOVC,	0, ALU_OP0_NOP, tgsi_unsupported},
 	{TGSI_OPCODE_LAST,	0, ALU_OP0_NOP, tgsi_unsupported},
 };
 
@@ -6466,5 +6468,6 @@ static struct r600_shader_tgsi_instruction cm_shader_tgsi_instruction[] = {
 	{TGSI_OPCODE_TEX2,	0, FETCH_OP_SAMPLE, tgsi_tex},
 	{TGSI_OPCODE_TXB2,	0, FETCH_OP_SAMPLE_LB, tgsi_tex},
 	{TGSI_OPCODE_TXL2,	0, FETCH_OP_SAMPLE_L, tgsi_tex},
+	{TGSI_OPCODE_MOVC,	0, ALU_OP0_NOP, tgsi_unsupported},
 	{TGSI_OPCODE_LAST,	0, ALU_OP0_NOP, tgsi_unsupported},
 };
diff --git a/src/gallium/include/pipe/p_shader_tokens.h b/src/gallium/include/pipe/p_shader_tokens.h
index 478ce25..d2405d7 100644
--- a/src/gallium/include/pipe/p_shader_tokens.h
+++ b/src/gallium/include/pipe/p_shader_tokens.h
@@ -442,7 +442,9 @@ struct tgsi_property_data {
 #define TGSI_OPCODE_TXB2                178
 #define TGSI_OPCODE_TXL2                179
 
-#define TGSI_OPCODE_LAST                180
+#define TGSI_OPCODE_MOVC                180
+
+#define TGSI_OPCODE_LAST                181
 
 #define TGSI_SAT_NONE            0  /* do not saturate */
 #define TGSI_SAT_ZERO_ONE        1  /* clamp to [0,1] */
diff --git a/src/gallium/tests/graw/fragment-shader/frag-movc.sh b/src/gallium/tests/graw/fragment-shader/frag-movc.sh
new file mode 100644
index 0000000..f6bc7b0
--- /dev/null
+++ b/src/gallium/tests/graw/fragment-shader/frag-movc.sh
@@ -0,0 +1,11 @@
+FRAG
+DCL IN[0], COLOR, LINEAR
+DCL OUT[0], COLOR
+DCL TEMP[0]
+IMM[0] FLT32 {   10.0000,     1.0000,     0.0000,     0.0000}
+IMM[1] UINT32 {1, 0, 0, 0}
+0: MUL TEMP[0].x, IN[0].xxxx, IMM[0].xxxx
+1: F2U TEMP[0].x, TEMP[0].xxxx
+2: AND TEMP[0].x, TEMP[0].xxxx, IMM[1].xxxx
+3: MOVC OUT[0], TEMP[0].xxxx, IMM[0].yzzz, IMM[0].yyyz
+4: END
-- 
1.7.10.4



More information about the mesa-dev mailing list