[Mesa-dev] [PATCH 06/11] gallivm: add support for TGSI instructions with two outputs

Nicolai Hähnle nhaehnle at gmail.com
Sat Sep 16 11:23:48 UTC 2017


From: Nicolai Hähnle <nicolai.haehnle at amd.com>

---
 src/gallium/auxiliary/gallivm/lp_bld_tgsi.c        | 18 +++++++++++++++++-
 src/gallium/auxiliary/gallivm/lp_bld_tgsi_action.h |  5 +++++
 src/gallium/auxiliary/tgsi/tgsi_exec.h             |  9 +++++++++
 3 files changed, 31 insertions(+), 1 deletion(-)

diff --git a/src/gallium/auxiliary/gallivm/lp_bld_tgsi.c b/src/gallium/auxiliary/gallivm/lp_bld_tgsi.c
index 66f752989ab..b33976bb647 100644
--- a/src/gallium/auxiliary/gallivm/lp_bld_tgsi.c
+++ b/src/gallium/auxiliary/gallivm/lp_bld_tgsi.c
@@ -257,25 +257,31 @@ lp_build_tgsi_inst_llvm(
       break;
    }
 
    /* Check if the opcode has been implemented */
    if (!action->emit) {
       return FALSE;
    }
 
    memset(&emit_data, 0, sizeof(emit_data));
 
-   assert(info->num_dst <= 1);
+   assert(info->num_dst <= 2);
    if (info->num_dst) {
       TGSI_FOR_EACH_DST0_ENABLED_CHANNEL( inst, chan_index ) {
          emit_data.output[chan_index] = bld_base->base.undef;
       }
+
+      if (info->num_dst >= 2) {
+         TGSI_FOR_EACH_DST1_ENABLED_CHANNEL( inst, chan_index ) {
+            emit_data.output1[chan_index] = bld_base->base.undef;
+         }
+      }
    }
 
    emit_data.inst = inst;
    emit_data.info = info;
 
    /* Emit the instructions */
    if (info->output_mode == TGSI_OUTPUT_COMPONENTWISE && bld_base->soa) {
       TGSI_FOR_EACH_DST0_ENABLED_CHANNEL(inst, chan_index) {
          int src_index = get_src_chan_idx(inst->Instruction.Opcode, chan_index);
          /* ignore channels 1/3 in double dst */
@@ -302,25 +308,35 @@ lp_build_tgsi_inst_llvm(
       }
       action->emit(action, bld_base, &emit_data);
 
       /* Replicate the output values */
       if (info->output_mode == TGSI_OUTPUT_REPLICATE && bld_base->soa) {
          val = emit_data.output[0];
          memset(emit_data.output, 0, sizeof(emit_data.output));
          TGSI_FOR_EACH_DST0_ENABLED_CHANNEL(inst, chan_index) {
             emit_data.output[chan_index] = val;
          }
+
+         if (info->num_dst >= 2) {
+            val = emit_data.output1[0];
+            memset(emit_data.output1, 0, sizeof(emit_data.output1));
+            TGSI_FOR_EACH_DST1_ENABLED_CHANNEL(inst, chan_index) {
+               emit_data.output1[chan_index] = val;
+            }
+         }
       }
    }
 
    if (info->num_dst > 0 && info->opcode != TGSI_OPCODE_STORE) {
       bld_base->emit_store(bld_base, inst, info, 0, emit_data.output);
+      if (info->num_dst >= 2)
+         bld_base->emit_store(bld_base, inst, info, 1, emit_data.output1);
    }
    return TRUE;
 }
 
 
 LLVMValueRef
 lp_build_emit_fetch_src(
    struct lp_build_tgsi_context *bld_base,
    const struct tgsi_full_src_register *reg,
    enum tgsi_opcode_type stype,
diff --git a/src/gallium/auxiliary/gallivm/lp_bld_tgsi_action.h b/src/gallium/auxiliary/gallivm/lp_bld_tgsi_action.h
index 463d44eb450..c92517fee28 100644
--- a/src/gallium/auxiliary/gallivm/lp_bld_tgsi_action.h
+++ b/src/gallium/auxiliary/gallivm/lp_bld_tgsi_action.h
@@ -75,20 +75,25 @@ struct lp_build_emit_data {
     * This is used to specify the src channel to read from for doubles.
     */
    unsigned src_chan;
 
    /** The lp_build_tgsi_action::emit 'executes' the opcode and writes the
     * results to this array.
     */
    LLVMValueRef output[4];
 
    /**
+    * Secondary output for instruction that have a second destination register.
+    */
+   LLVMValueRef output1[4];
+
+   /**
     * The current instruction that is being 'executed'.
     */
    const struct tgsi_full_instruction * inst;
    const struct tgsi_opcode_info * info;
 };
 
 struct lp_build_tgsi_action
 {
 
    /**
diff --git a/src/gallium/auxiliary/tgsi/tgsi_exec.h b/src/gallium/auxiliary/tgsi/tgsi_exec.h
index 9d7e65f2c51..f656133400d 100644
--- a/src/gallium/auxiliary/tgsi/tgsi_exec.h
+++ b/src/gallium/auxiliary/tgsi/tgsi_exec.h
@@ -51,20 +51,29 @@ extern "C" {
 #define TGSI_IS_DST0_CHANNEL_ENABLED( INST, CHAN )\
    ((INST)->Dst[0].Register.WriteMask & (1 << (CHAN)))
 
 #define TGSI_IF_IS_DST0_CHANNEL_ENABLED( INST, CHAN )\
    if (TGSI_IS_DST0_CHANNEL_ENABLED( INST, CHAN ))
 
 #define TGSI_FOR_EACH_DST0_ENABLED_CHANNEL( INST, CHAN )\
    TGSI_FOR_EACH_CHANNEL( CHAN )\
       TGSI_IF_IS_DST0_CHANNEL_ENABLED( INST, CHAN )
 
+#define TGSI_IS_DST1_CHANNEL_ENABLED( INST, CHAN )\
+   ((INST)->Dst[1].Register.WriteMask & (1 << (CHAN)))
+
+#define TGSI_IF_IS_DST1_CHANNEL_ENABLED( INST, CHAN )\
+   if (TGSI_IS_DST1_CHANNEL_ENABLED( INST, CHAN ))
+
+#define TGSI_FOR_EACH_DST1_ENABLED_CHANNEL( INST, CHAN )\
+   TGSI_FOR_EACH_CHANNEL( CHAN )\
+      TGSI_IF_IS_DST1_CHANNEL_ENABLED( INST, CHAN )
 
 /**
   * Registers may be treated as float, signed int or unsigned int.
   */
 union tgsi_exec_channel
 {
    float    f[TGSI_QUAD_SIZE];
    int      i[TGSI_QUAD_SIZE];
    unsigned u[TGSI_QUAD_SIZE];
 };
-- 
2.11.0



More information about the mesa-dev mailing list