Module: Mesa
Branch: main
Commit: e74aaa347b671587c875b00d5a5cd1e89375aaa8
URL:    
http://cgit.freedesktop.org/mesa/mesa/commit/?id=e74aaa347b671587c875b00d5a5cd1e89375aaa8

Author: Simon Perretta <[email protected]>
Date:   Wed Jan 18 15:41:23 2023 +0000

pvr: Support dual-destination ALU instructions

Signed-off-by: Simon Perretta <[email protected]>
Acked-by: Frank Binns <[email protected]>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/20430>

---

 src/imagination/rogue/passes/rogue_copy_prop.c     |  20 ++--
 src/imagination/rogue/passes/rogue_dce.c           |   2 +-
 .../rogue/passes/rogue_lower_pseudo_ops.c          |  14 +--
 .../rogue/passes/rogue_schedule_instr_groups.c     |  15 ++-
 src/imagination/rogue/rogue.c                      |  42 ++++----
 src/imagination/rogue/rogue.h                      |  25 +++--
 src/imagination/rogue/rogue_alu_instrs.def         |  58 +++++-----
 src/imagination/rogue/rogue_builder.c              | 120 +++++++++++++--------
 src/imagination/rogue/rogue_builder.h              |  21 ++--
 src/imagination/rogue/rogue_info.c                 |  46 ++++----
 src/imagination/rogue/rogue_print.c                |  15 ++-
 src/imagination/rogue/rogue_validate.c             |   5 +-
 12 files changed, 235 insertions(+), 148 deletions(-)

diff --git a/src/imagination/rogue/passes/rogue_copy_prop.c 
b/src/imagination/rogue/passes/rogue_copy_prop.c
index a1102aeb9eb..bd58c128c3a 100644
--- a/src/imagination/rogue/passes/rogue_copy_prop.c
+++ b/src/imagination/rogue/passes/rogue_copy_prop.c
@@ -37,7 +37,8 @@ static bool can_back_prop(rogue_alu_instr *mov)
 {
    /* TODO: Check for src/dst modifiers when support is added for them. */
 
-   if (!rogue_ref_is_reg(&mov->src[0].ref) || !rogue_ref_is_reg(&mov->dst.ref))
+   if (!rogue_ref_is_reg(&mov->src[0].ref) ||
+       !rogue_ref_is_reg(&mov->dst[0].ref))
       return false;
 
    if (mov->src[0].ref.reg->regarray)
@@ -45,7 +46,7 @@ static bool can_back_prop(rogue_alu_instr *mov)
 
    /* Vertex outputs require uvsw.write; only back-propagate if the parent
     * instruction is also a mov. */
-   if (mov->dst.ref.reg->class == ROGUE_REG_CLASS_VTXOUT) {
+   if (mov->dst[0].ref.reg->class == ROGUE_REG_CLASS_VTXOUT) {
       rogue_reg_write *write =
          list_first_entry(&mov->src[0].ref.reg->writes, rogue_reg_write, link);
 
@@ -62,7 +63,7 @@ static bool can_back_prop(rogue_alu_instr *mov)
       return false;
 
    /* Is this the only instruction that writes to this register? */
-   if (!list_is_singular(&mov->dst.ref.reg->writes))
+   if (!list_is_singular(&mov->dst[0].ref.reg->writes))
       return false;
 
    return true;
@@ -72,13 +73,14 @@ static bool can_forward_prop(rogue_alu_instr *mov)
 {
    /* TODO: Check for src/dst modifiers when support is added for them. */
 
-   if (!rogue_ref_is_reg(&mov->src[0].ref) || !rogue_ref_is_reg(&mov->dst.ref))
+   if (!rogue_ref_is_reg(&mov->src[0].ref) ||
+       !rogue_ref_is_reg(&mov->dst[0].ref))
       return false;
 
-   if (mov->dst.ref.reg->regarray)
+   if (mov->dst[0].ref.reg->regarray)
       return false;
 
-   if (mov->dst.ref.reg->class != ROGUE_REG_CLASS_SSA)
+   if (mov->dst[0].ref.reg->class != ROGUE_REG_CLASS_SSA)
       return false;
 
    /* Is the source register written to more than once (driver-supplied regs 
can
@@ -87,7 +89,7 @@ static bool can_forward_prop(rogue_alu_instr *mov)
       return false;
 
    /* Is this the only instruction that writes to this register? */
-   if (!list_is_singular(&mov->dst.ref.reg->writes))
+   if (!list_is_singular(&mov->dst[0].ref.reg->writes))
       return false;
 
    return true;
@@ -96,7 +98,7 @@ static bool can_forward_prop(rogue_alu_instr *mov)
 static bool rogue_back_prop(rogue_alu_instr *mov)
 {
    rogue_reg *mov_src = mov->src[0].ref.reg;
-   rogue_reg *mov_dst = mov->dst.ref.reg;
+   rogue_reg *mov_dst = mov->dst[0].ref.reg;
 
    rogue_reg_write *write =
       list_first_entry(&mov_src->writes, rogue_reg_write, link);
@@ -114,7 +116,7 @@ static bool rogue_forward_prop(rogue_alu_instr *mov)
    bool success = true;
 
    rogue_reg *mov_src = mov->src[0].ref.reg;
-   rogue_reg *mov_dst = mov->dst.ref.reg;
+   rogue_reg *mov_dst = mov->dst[0].ref.reg;
 
    rogue_foreach_reg_use_safe (use, mov_dst)
       if (rogue_can_replace_reg_use(use, mov_src))
diff --git a/src/imagination/rogue/passes/rogue_dce.c 
b/src/imagination/rogue/passes/rogue_dce.c
index 6acbdd20fcb..75c0b7d03a2 100644
--- a/src/imagination/rogue/passes/rogue_dce.c
+++ b/src/imagination/rogue/passes/rogue_dce.c
@@ -47,7 +47,7 @@ static bool rogue_dce_alu_instr(rogue_alu_instr *alu)
    switch (alu->op) {
    case ROGUE_ALU_OP_MOV:
    case ROGUE_ALU_OP_MBYP:
-      if (!alu->mod && rogue_alu_dst_src_equal(&alu->dst, &alu->src[0])) {
+      if (!alu->mod && rogue_alu_dst_src_equal(&alu->dst[0], &alu->src[0])) {
          rogue_instr_delete(&alu->instr);
          progress = true;
       }
diff --git a/src/imagination/rogue/passes/rogue_lower_pseudo_ops.c 
b/src/imagination/rogue/passes/rogue_lower_pseudo_ops.c
index 26a1ed26619..b89905d2c87 100644
--- a/src/imagination/rogue/passes/rogue_lower_pseudo_ops.c
+++ b/src/imagination/rogue/passes/rogue_lower_pseudo_ops.c
@@ -35,7 +35,7 @@
 
 static inline bool rogue_lower_FABS(rogue_builder *b, rogue_alu_instr *fabs)
 {
-   rogue_alu_instr *mbyp = rogue_MBYP(b, fabs->dst.ref, fabs->src[0].ref);
+   rogue_alu_instr *mbyp = rogue_MBYP(b, fabs->dst[0].ref, fabs->src[0].ref);
    rogue_merge_instr_comment(&mbyp->instr, &fabs->instr, "fabs");
    rogue_set_alu_src_mod(mbyp, 0, ROGUE_ALU_SRC_MOD_ABS);
    rogue_instr_delete(&fabs->instr);
@@ -45,7 +45,7 @@ static inline bool rogue_lower_FABS(rogue_builder *b, 
rogue_alu_instr *fabs)
 
 static inline bool rogue_lower_FNEG(rogue_builder *b, rogue_alu_instr *fneg)
 {
-   rogue_alu_instr *mbyp = rogue_MBYP(b, fneg->dst.ref, fneg->src[0].ref);
+   rogue_alu_instr *mbyp = rogue_MBYP(b, fneg->dst[0].ref, fneg->src[0].ref);
    rogue_merge_instr_comment(&mbyp->instr, &fneg->instr, "fneg");
    rogue_set_alu_src_mod(mbyp, 0, ROGUE_ALU_SRC_MOD_NEG);
    rogue_instr_delete(&fneg->instr);
@@ -55,7 +55,7 @@ static inline bool rogue_lower_FNEG(rogue_builder *b, 
rogue_alu_instr *fneg)
 
 static inline bool rogue_lower_FNABS(rogue_builder *b, rogue_alu_instr *fnabs)
 {
-   rogue_alu_instr *mbyp = rogue_MBYP(b, fnabs->dst.ref, fnabs->src[0].ref);
+   rogue_alu_instr *mbyp = rogue_MBYP(b, fnabs->dst[0].ref, fnabs->src[0].ref);
    rogue_merge_instr_comment(&mbyp->instr, &fnabs->instr, "fnabs");
    rogue_set_alu_src_mod(mbyp, 0, ROGUE_ALU_SRC_MOD_ABS);
    rogue_set_alu_src_mod(mbyp, 0, ROGUE_ALU_SRC_MOD_NEG);
@@ -70,11 +70,11 @@ static inline bool rogue_lower_MOV(rogue_builder *b, 
rogue_alu_instr *mov)
 
    /* If we're writing to a vertex output register, we need to use uvsw.write.
     */
-   if (rogue_ref_is_reg(&mov->dst.ref) &&
-       mov->dst.ref.reg->class == ROGUE_REG_CLASS_VTXOUT) {
-      instr = &rogue_UVSW_WRITE(b, mov->dst.ref, mov->src[0].ref)->instr;
+   if (rogue_ref_is_reg(&mov->dst[0].ref) &&
+       mov->dst[0].ref.reg->class == ROGUE_REG_CLASS_VTXOUT) {
+      instr = &rogue_UVSW_WRITE(b, mov->dst[0].ref, mov->src[0].ref)->instr;
    } else {
-      instr = &rogue_MBYP(b, mov->dst.ref, mov->src[0].ref)->instr;
+      instr = &rogue_MBYP(b, mov->dst[0].ref, mov->src[0].ref)->instr;
    }
 
    rogue_merge_instr_comment(instr, &mov->instr, "mov");
diff --git a/src/imagination/rogue/passes/rogue_schedule_instr_groups.c 
b/src/imagination/rogue/passes/rogue_schedule_instr_groups.c
index 271ba8b83a6..cb288fefa5b 100644
--- a/src/imagination/rogue/passes/rogue_schedule_instr_groups.c
+++ b/src/imagination/rogue/passes/rogue_schedule_instr_groups.c
@@ -72,11 +72,16 @@ static void rogue_lower_alu_io(rogue_alu_instr *alu, 
rogue_instr_group *group)
    const rogue_alu_op_info *info = &rogue_alu_op_infos[alu->op];
    enum rogue_instr_phase phase = alu->instr.index;
 
-   rogue_set_io_sel(&group->io_sel,
-                    info->phase_io[phase].dst,
-                    &alu->dst.ref,
-                    true);
-   alu->dst.ref = rogue_ref_io(info->phase_io[phase].dst);
+   for (unsigned u = 0; u < info->num_dsts; ++u) {
+      if (info->phase_io[phase].dst[u] == ROGUE_IO_INVALID)
+         continue;
+
+      rogue_set_io_sel(&group->io_sel,
+                       info->phase_io[phase].dst[u],
+                       &alu->dst[u].ref,
+                       true);
+      alu->dst[u].ref = rogue_ref_io(info->phase_io[phase].dst[u]);
+   }
 
    for (unsigned u = 0; u < info->num_srcs; ++u) {
       if (info->phase_io[phase].src[u] == ROGUE_IO_INVALID)
diff --git a/src/imagination/rogue/rogue.c b/src/imagination/rogue/rogue.c
index 8bd10225534..3ba5aec62ae 100644
--- a/src/imagination/rogue/rogue.c
+++ b/src/imagination/rogue/rogue.c
@@ -646,17 +646,20 @@ void rogue_link_instr_write(rogue_instr *instr)
    switch (instr->type) {
    case ROGUE_INSTR_TYPE_ALU: {
       rogue_alu_instr *alu = rogue_instr_as_alu(instr);
+      const unsigned num_dsts = rogue_alu_op_infos[alu->op].num_dsts;
 
-      if (rogue_ref_is_reg(&alu->dst.ref)) {
-         rogue_reg_write *write = &alu->dst_write.reg;
-         rogue_reg *reg = alu->dst.ref.reg;
-         rogue_link_instr_write_reg(instr, write, reg, 0);
-      } else if (rogue_ref_is_regarray(&alu->dst.ref)) {
-         struct util_dynarray **writearray = &alu->dst_write.regarray;
-         rogue_regarray *regarray = alu->dst.ref.regarray;
-         rogue_link_instr_write_regarray(instr, writearray, regarray, 0);
-      } else {
-         unreachable("Invalid destination reference type.");
+      for (unsigned i = 0; i < num_dsts; ++i) {
+         if (rogue_ref_is_reg(&alu->dst[i].ref)) {
+            rogue_reg_write *write = &alu->dst_write[i].reg;
+            rogue_reg *reg = alu->dst[i].ref.reg;
+            rogue_link_instr_write_reg(instr, write, reg, 0);
+         } else if (rogue_ref_is_regarray(&alu->dst[i].ref)) {
+            struct util_dynarray **writearray = &alu->dst_write[i].regarray;
+            rogue_regarray *regarray = alu->dst[i].ref.regarray;
+            rogue_link_instr_write_regarray(instr, writearray, regarray, 0);
+         } else {
+            unreachable("Invalid destination reference type.");
+         }
       }
 
       break;
@@ -815,15 +818,18 @@ void rogue_unlink_instr_write(rogue_instr *instr)
    switch (instr->type) {
    case ROGUE_INSTR_TYPE_ALU: {
       rogue_alu_instr *alu = rogue_instr_as_alu(instr);
+      const unsigned num_dsts = rogue_alu_op_infos[alu->op].num_dsts;
 
-      if (rogue_ref_is_reg(&alu->dst.ref)) {
-         rogue_reg_write *write = &alu->dst_write.reg;
-         rogue_unlink_instr_write_reg(instr, write);
-      } else if (rogue_ref_is_regarray(&alu->dst.ref)) {
-         struct util_dynarray **writearray = &alu->dst_write.regarray;
-         rogue_unlink_instr_write_regarray(instr, writearray);
-      } else {
-         unreachable("Invalid destination reference type.");
+      for (unsigned i = 0; i < num_dsts; ++i) {
+         if (rogue_ref_is_reg(&alu->dst[i].ref)) {
+            rogue_reg_write *write = &alu->dst_write[i].reg;
+            rogue_unlink_instr_write_reg(instr, write);
+         } else if (rogue_ref_is_regarray(&alu->dst[i].ref)) {
+            struct util_dynarray **writearray = &alu->dst_write[i].regarray;
+            rogue_unlink_instr_write_regarray(instr, writearray);
+         } else {
+            unreachable("Invalid destination reference type.");
+         }
       }
 
       break;
diff --git a/src/imagination/rogue/rogue.h b/src/imagination/rogue/rogue.h
index cd78bacde8e..f331a3814ca 100644
--- a/src/imagination/rogue/rogue.h
+++ b/src/imagination/rogue/rogue.h
@@ -864,6 +864,7 @@ static inline bool rogue_refs_equal(rogue_ref *a, rogue_ref 
*b)
 typedef struct rogue_alu_dst {
    rogue_ref ref;
    uint64_t mod;
+   unsigned index;
 } rogue_alu_dst;
 
 typedef struct rogue_alu_src {
@@ -1066,9 +1067,10 @@ static inline bool rogue_ctrl_op_has_dsts(enum 
rogue_ctrl_op op)
 
 /* ALU instructions have at most 3 sources. */
 #define ROGUE_ALU_OP_MAX_SRCS 3
+#define ROGUE_ALU_OP_MAX_DSTS 2
 
 typedef struct rogue_alu_io_info {
-   enum rogue_io dst;
+   enum rogue_io dst[ROGUE_ALU_OP_MAX_DSTS];
    enum rogue_io src[ROGUE_ALU_OP_MAX_SRCS];
 } rogue_alu_io_info;
 
@@ -1076,17 +1078,18 @@ typedef struct rogue_alu_io_info {
 typedef struct rogue_alu_op_info {
    const char *str;
 
+   unsigned num_dsts;
    unsigned num_srcs;
 
    uint64_t supported_phases;
    rogue_alu_io_info phase_io[ROGUE_INSTR_PHASE_COUNT];
 
    uint64_t supported_op_mods;
-   uint64_t supported_dst_mods;
+   uint64_t supported_dst_mods[ROGUE_ALU_OP_MAX_DSTS];
    uint64_t supported_src_mods[ROGUE_ALU_OP_MAX_SRCS];
 
    /* TODO NEXT: Do the same for other instruction types. */
-   uint64_t supported_dst_types;
+   uint64_t supported_dst_types[ROGUE_ALU_OP_MAX_DSTS];
    uint64_t supported_src_types[ROGUE_ALU_OP_MAX_SRCS];
 } rogue_alu_op_info;
 
@@ -1143,12 +1146,12 @@ typedef struct rogue_alu_instr {
 
    uint64_t mod;
 
-   rogue_alu_dst dst;
+   rogue_alu_dst dst[ROGUE_ALU_OP_MAX_DSTS];
 
    union {
       rogue_reg_write reg;
       struct util_dynarray *regarray;
-   } dst_write;
+   } dst_write[ROGUE_ALU_OP_MAX_DSTS];
 
    rogue_alu_src src[ROGUE_ALU_OP_MAX_SRCS];
 
@@ -1171,9 +1174,17 @@ static inline bool rogue_alu_op_mod_is_set(const 
rogue_alu_instr *alu,
 }
 
 static inline void rogue_set_alu_dst_mod(rogue_alu_instr *alu,
+                                         unsigned dst_index,
                                          enum rogue_alu_dst_mod mod)
 {
-   alu->dst.mod |= BITFIELD64_BIT(mod);
+   alu->dst[dst_index].mod |= BITFIELD64_BIT(mod);
+}
+
+static inline bool rogue_alu_dst_mod_is_set(const rogue_alu_instr *alu,
+                                            unsigned dst_index,
+                                            enum rogue_alu_dst_mod mod)
+{
+   return !!(alu->dst[dst_index].mod & BITFIELD64_BIT(mod));
 }
 
 static inline void rogue_set_alu_src_mod(rogue_alu_instr *alu,
@@ -2082,7 +2093,7 @@ static inline bool rogue_dst_reg_replace(rogue_reg_write 
*write,
 
    switch (instr->type) {
    case ROGUE_INSTR_TYPE_ALU:
-      ref = &rogue_instr_as_alu(instr)->dst.ref;
+      ref = &rogue_instr_as_alu(instr)->dst[dst_index].ref;
       break;
 
    case ROGUE_INSTR_TYPE_BACKEND:
diff --git a/src/imagination/rogue/rogue_alu_instrs.def 
b/src/imagination/rogue/rogue_alu_instrs.def
index 371017c9e52..6f903865eea 100644
--- a/src/imagination/rogue/rogue_alu_instrs.def
+++ b/src/imagination/rogue/rogue_alu_instrs.def
@@ -28,40 +28,48 @@
  */
 
 /*
- * ROGUE_BUILDER_DEFINE_ALUs
+ * ROGUE_BUILDER_DEFINE_ALUds
+ *    d: Number of destinations.
  *    s: Number of sources.
  */
 
-#ifndef ROGUE_BUILDER_DEFINE_ALU1
-#define ROGUE_BUILDER_DEFINE_ALU1(...)
-#endif /* ROGUE_BUILDER_DEFINE_ALU1 */
+#ifndef ROGUE_BUILDER_DEFINE_ALU11
+#define ROGUE_BUILDER_DEFINE_ALU11(...)
+#endif /* ROGUE_BUILDER_DEFINE_ALU11 */
 
-#ifndef ROGUE_BUILDER_DEFINE_ALU2
-#define ROGUE_BUILDER_DEFINE_ALU2(...)
-#endif /* ROGUE_BUILDER_DEFINE_ALU2 */
+#ifndef ROGUE_BUILDER_DEFINE_ALU12
+#define ROGUE_BUILDER_DEFINE_ALU12(...)
+#endif /* ROGUE_BUILDER_DEFINE_ALU12 */
 
-#ifndef ROGUE_BUILDER_DEFINE_ALU3
-#define ROGUE_BUILDER_DEFINE_ALU3(...)
-#endif /* ROGUE_BUILDER_DEFINE_ALU3 */
+#ifndef ROGUE_BUILDER_DEFINE_ALU13
+#define ROGUE_BUILDER_DEFINE_ALU13(...)
+#endif /* ROGUE_BUILDER_DEFINE_ALU13 */
 
-ROGUE_BUILDER_DEFINE_ALU1(MOV)
-ROGUE_BUILDER_DEFINE_ALU1(MBYP)
+#ifndef ROGUE_BUILDER_DEFINE_ALU22
+#define ROGUE_BUILDER_DEFINE_ALU22(...)
+#endif /* ROGUE_BUILDER_DEFINE_ALU22 */
 
-ROGUE_BUILDER_DEFINE_ALU1(FABS)
-ROGUE_BUILDER_DEFINE_ALU1(FNEG)
-ROGUE_BUILDER_DEFINE_ALU1(FNABS)
+ROGUE_BUILDER_DEFINE_ALU11(MOV)
+ROGUE_BUILDER_DEFINE_ALU11(MBYP)
 
-ROGUE_BUILDER_DEFINE_ALU1(PCK_U8888)
+ROGUE_BUILDER_DEFINE_ALU11(FABS)
+ROGUE_BUILDER_DEFINE_ALU11(FNEG)
+ROGUE_BUILDER_DEFINE_ALU11(FNABS)
 
-ROGUE_BUILDER_DEFINE_ALU2(FADD)
-ROGUE_BUILDER_DEFINE_ALU2(FMUL)
+ROGUE_BUILDER_DEFINE_ALU11(PCK_U8888)
 
-ROGUE_BUILDER_DEFINE_ALU2(FMAX)
-ROGUE_BUILDER_DEFINE_ALU2(FMIN)
+ROGUE_BUILDER_DEFINE_ALU12(FADD)
+ROGUE_BUILDER_DEFINE_ALU12(FMUL)
 
-ROGUE_BUILDER_DEFINE_ALU3(SEL)
-ROGUE_BUILDER_DEFINE_ALU3(FMAD)
+ROGUE_BUILDER_DEFINE_ALU12(FMAX)
+ROGUE_BUILDER_DEFINE_ALU12(FMIN)
 
-#undef ROGUE_BUILDER_DEFINE_ALU3
-#undef ROGUE_BUILDER_DEFINE_ALU2
-#undef ROGUE_BUILDER_DEFINE_ALU1
+ROGUE_BUILDER_DEFINE_ALU13(FMAD)
+ROGUE_BUILDER_DEFINE_ALU13(SEL)
+
+ROGUE_BUILDER_DEFINE_ALU22(TST)
+
+#undef ROGUE_BUILDER_DEFINE_ALU22
+#undef ROGUE_BUILDER_DEFINE_ALU13
+#undef ROGUE_BUILDER_DEFINE_ALU12
+#undef ROGUE_BUILDER_DEFINE_ALU11
diff --git a/src/imagination/rogue/rogue_builder.c 
b/src/imagination/rogue/rogue_builder.c
index 87d9ae8809e..8454c78d542 100644
--- a/src/imagination/rogue/rogue_builder.c
+++ b/src/imagination/rogue/rogue_builder.c
@@ -48,14 +48,19 @@ static inline void rogue_builder_insert_instr(rogue_builder 
*b,
 
 static inline rogue_alu_instr *rogue_build_alu(rogue_builder *b,
                                                enum rogue_alu_op op,
-                                               rogue_ref dst,
+                                               unsigned num_dsts,
+                                               rogue_ref dsts[num_dsts],
                                                unsigned num_srcs,
                                                rogue_ref srcs[num_srcs])
 {
    rogue_alu_instr *alu =
       rogue_alu_instr_create(rogue_cursor_block(b->cursor), op);
 
-   alu->dst.ref = dst;
+   for (unsigned i = 0; i < num_dsts; ++i) {
+      alu->dst[i].ref = dsts[i];
+      alu->dst[i].index = i;
+   }
+
    for (unsigned i = 0; i < num_srcs; ++i) {
       alu->src[i].ref = srcs[i];
       alu->src[i].index = i;
@@ -65,68 +70,99 @@ static inline rogue_alu_instr 
*rogue_build_alu(rogue_builder *b,
    return alu;
 }
 
-static inline rogue_alu_instr *rogue_build_alu1(rogue_builder *b,
-                                                enum rogue_alu_op op,
-                                                rogue_ref dst,
-                                                rogue_ref src0)
+static inline rogue_alu_instr *rogue_build_alu11(rogue_builder *b,
+                                                 enum rogue_alu_op op,
+                                                 rogue_ref dst0,
+                                                 rogue_ref src0)
 {
+   rogue_ref dsts[] = { dst0 };
    rogue_ref srcs[] = { src0 };
-   return rogue_build_alu(b, op, dst, 1, srcs);
+   return rogue_build_alu(b, op, 1, dsts, 1, srcs);
 }
 
-static inline rogue_alu_instr *rogue_build_alu2(rogue_builder *b,
-                                                enum rogue_alu_op op,
-                                                rogue_ref dst,
-                                                rogue_ref src0,
-                                                rogue_ref src1)
+static inline rogue_alu_instr *rogue_build_alu12(rogue_builder *b,
+                                                 enum rogue_alu_op op,
+                                                 rogue_ref dst0,
+                                                 rogue_ref src0,
+                                                 rogue_ref src1)
 {
+   rogue_ref dsts[] = { dst0 };
    rogue_ref srcs[] = { src0, src1 };
-   return rogue_build_alu(b, op, dst, 2, srcs);
+   return rogue_build_alu(b, op, 1, dsts, 2, srcs);
 }
 
-static inline rogue_alu_instr *rogue_build_alu3(rogue_builder *b,
-                                                enum rogue_alu_op op,
-                                                rogue_ref dst,
-                                                rogue_ref src0,
-                                                rogue_ref src1,
-                                                rogue_ref src2)
+static inline rogue_alu_instr *rogue_build_alu13(rogue_builder *b,
+                                                 enum rogue_alu_op op,
+                                                 rogue_ref dst0,
+                                                 rogue_ref src0,
+                                                 rogue_ref src1,
+                                                 rogue_ref src2)
 {
+   rogue_ref dsts[] = { dst0 };
    rogue_ref srcs[] = { src0, src1, src2 };
-   return rogue_build_alu(b, op, dst, 3, srcs);
+   return rogue_build_alu(b, op, 1, dsts, 3, srcs);
+}
+
+static inline rogue_alu_instr *rogue_build_alu22(rogue_builder *b,
+                                                 enum rogue_alu_op op,
+                                                 rogue_ref dst0,
+                                                 rogue_ref dst1,
+                                                 rogue_ref src0,
+                                                 rogue_ref src1)
+{
+   rogue_ref dsts[] = { dst0, dst1 };
+   rogue_ref srcs[] = { src0, src1 };
+   return rogue_build_alu(b, op, 2, dsts, 2, srcs);
 }
 
 /* TODO: Static inline in rogue.h? */
-#define ROGUE_BUILDER_DEFINE_ALU1(op)                              \
+#define ROGUE_BUILDER_DEFINE_ALU11(op)                             \
    PUBLIC                                                          \
    rogue_alu_instr *rogue_##op(rogue_builder *b,                   \
-                               rogue_ref dst,                      \
+                               rogue_ref dst0,                     \
                                rogue_ref src0)                     \
    {                                                               \
+      assert(rogue_alu_op_infos[ROGUE_ALU_OP_##op].num_dsts == 1); \
       assert(rogue_alu_op_infos[ROGUE_ALU_OP_##op].num_srcs == 1); \
-      return rogue_build_alu1(b, ROGUE_ALU_OP_##op, dst, src0);    \
+      return rogue_build_alu11(b, ROGUE_ALU_OP_##op, dst0, src0);  \
    }
 
-#define ROGUE_BUILDER_DEFINE_ALU2(op)                                 \
-   PUBLIC                                                             \
-   rogue_alu_instr *rogue_##op(rogue_builder *b,                      \
-                               rogue_ref dst,                         \
-                               rogue_ref src0,                        \
-                               rogue_ref src1)                        \
-   {                                                                  \
-      assert(rogue_alu_op_infos[ROGUE_ALU_OP_##op].num_srcs == 2);    \
-      return rogue_build_alu2(b, ROGUE_ALU_OP_##op, dst, src0, src1); \
+#define ROGUE_BUILDER_DEFINE_ALU12(op)                                  \
+   PUBLIC                                                               \
+   rogue_alu_instr *rogue_##op(rogue_builder *b,                        \
+                               rogue_ref dst0,                          \
+                               rogue_ref src0,                          \
+                               rogue_ref src1)                          \
+   {                                                                    \
+      assert(rogue_alu_op_infos[ROGUE_ALU_OP_##op].num_dsts == 1);      \
+      assert(rogue_alu_op_infos[ROGUE_ALU_OP_##op].num_srcs == 2);      \
+      return rogue_build_alu12(b, ROGUE_ALU_OP_##op, dst0, src0, src1); \
+   }
+
+#define ROGUE_BUILDER_DEFINE_ALU13(op)                                        \
+   PUBLIC                                                                     \
+   rogue_alu_instr *rogue_##op(rogue_builder *b,                              \
+                               rogue_ref dst0,                                \
+                               rogue_ref src0,                                \
+                               rogue_ref src1,                                \
+                               rogue_ref src2)                                \
+   {                                                                          \
+      assert(rogue_alu_op_infos[ROGUE_ALU_OP_##op].num_dsts == 1);            \
+      assert(rogue_alu_op_infos[ROGUE_ALU_OP_##op].num_srcs == 3);            \
+      return rogue_build_alu13(b, ROGUE_ALU_OP_##op, dst0, src0, src1, src2); \
    }
 
-#define ROGUE_BUILDER_DEFINE_ALU3(op)                                       \
-   PUBLIC                                                                   \
-   rogue_alu_instr *rogue_##op(rogue_builder *b,                            \
-                               rogue_ref dst,                               \
-                               rogue_ref src0,                              \
-                               rogue_ref src1,                              \
-                               rogue_ref src2)                              \
-   {                                                                        \
-      assert(rogue_alu_op_infos[ROGUE_ALU_OP_##op].num_srcs == 3);          \
-      return rogue_build_alu3(b, ROGUE_ALU_OP_##op, dst, src0, src1, src2); \
+#define ROGUE_BUILDER_DEFINE_ALU22(op)                                        \
+   PUBLIC                                                                     \
+   rogue_alu_instr *rogue_##op(rogue_builder *b,                              \
+                               rogue_ref dst0,                                \
+                               rogue_ref dst1,                                \
+                               rogue_ref src0,                                \
+                               rogue_ref src1)                                \
+   {                                                                          \
+      assert(rogue_alu_op_infos[ROGUE_ALU_OP_##op].num_dsts == 2);            \
+      assert(rogue_alu_op_infos[ROGUE_ALU_OP_##op].num_srcs == 2);            \
+      return rogue_build_alu22(b, ROGUE_ALU_OP_##op, dst0, dst1, src0, src1); \
    }
 
 #include "rogue_alu_instrs.def"
diff --git a/src/imagination/rogue/rogue_builder.h 
b/src/imagination/rogue/rogue_builder.h
index b3061541d3d..02540bed25d 100644
--- a/src/imagination/rogue/rogue_builder.h
+++ b/src/imagination/rogue/rogue_builder.h
@@ -91,22 +91,31 @@ static inline rogue_block *rogue_push_block(rogue_builder 
*b)
 }
 
 /* ALU instructions. */
-#define ROGUE_BUILDER_DEFINE_ALU1(op) \
-   rogue_alu_instr *rogue_##op(rogue_builder *b, rogue_ref dst, rogue_ref 
src0);
+#define ROGUE_BUILDER_DEFINE_ALU11(op)           \
+   rogue_alu_instr *rogue_##op(rogue_builder *b, \
+                               rogue_ref dst0,   \
+                               rogue_ref src0);
 
-#define ROGUE_BUILDER_DEFINE_ALU2(op)            \
+#define ROGUE_BUILDER_DEFINE_ALU12(op)           \
    rogue_alu_instr *rogue_##op(rogue_builder *b, \
-                               rogue_ref dst,    \
+                               rogue_ref dst0,   \
                                rogue_ref src0,   \
                                rogue_ref src1);
 
-#define ROGUE_BUILDER_DEFINE_ALU3(op)            \
+#define ROGUE_BUILDER_DEFINE_ALU13(op)           \
    rogue_alu_instr *rogue_##op(rogue_builder *b, \
-                               rogue_ref dst,    \
+                               rogue_ref dst0,   \
                                rogue_ref src0,   \
                                rogue_ref src1,   \
                                rogue_ref src2);
 
+#define ROGUE_BUILDER_DEFINE_ALU22(op)           \
+   rogue_alu_instr *rogue_##op(rogue_builder *b, \
+                               rogue_ref dst0,   \
+                               rogue_ref dst1,   \
+                               rogue_ref src0,   \
+                               rogue_ref src1);
+
 #include "rogue_alu_instrs.def"
 
 /* Backend instructions. */
diff --git a/src/imagination/rogue/rogue_info.c 
b/src/imagination/rogue/rogue_info.c
index 8ee93d9a4c2..55ed81e99a5 100644
--- a/src/imagination/rogue/rogue_info.c
+++ b/src/imagination/rogue/rogue_info.c
@@ -300,50 +300,50 @@ const rogue_io_info rogue_io_infos[ROGUE_IO_COUNT] = {
 #define T(type) BITFIELD64_BIT(ROGUE_REF_TYPE_##type - 1)
 const rogue_alu_op_info rogue_alu_op_infos[ROGUE_ALU_OP_COUNT] = {
    [ROGUE_ALU_OP_INVALID] = { .str = "!INVALID!", },
-   [ROGUE_ALU_OP_MBYP] = { .str = "mbyp", .num_srcs = 1,
+   [ROGUE_ALU_OP_MBYP] = { .str = "mbyp", .num_dsts = 1, .num_srcs = 1,
       .supported_phases = P(0),
-      .phase_io[PH(0)] = { .dst = IO(FT0), .src[0] = IO(S0), },
+      .phase_io[PH(0)] = { .dst[0] = IO(FT0), .src[0] = IO(S0), },
       .supported_src_mods = {
          [0] = SM(ABS) | SM(NEG),
       },
-      .supported_dst_types = T(REG),
+      .supported_dst_types = { [0] = T(REG), },
       .supported_src_types = {
          [0] = T(REG),
       },
    },
-   [ROGUE_ALU_OP_FADD] = { .str = "fadd", .num_srcs = 2,
+   [ROGUE_ALU_OP_FADD] = { .str = "fadd", .num_dsts = 1, .num_srcs = 2,
       .supported_phases = P(0),
-      .phase_io[PH(0)] = { .dst = IO(FT0), .src[0] = IO(S0), .src[1] = IO(S1), 
},
+      .phase_io[PH(0)] = { .dst[0] = IO(FT0), .src[0] = IO(S0), .src[1] = 
IO(S1), },
       .supported_op_mods = OM(LP) | OM(SAT),
       .supported_src_mods = {
          [0] = SM(FLR) | SM(ABS) | SM(NEG),
          [1] = SM(ABS),
       },
    },
-   [ROGUE_ALU_OP_FMUL] = { .str = "fmul", .num_srcs = 2,
+   [ROGUE_ALU_OP_FMUL] = { .str = "fmul", .num_dsts = 1, .num_srcs = 2,
       .supported_phases = P(0),
-      .phase_io[PH(0)] = { .dst = IO(FT0), .src[0] = IO(S0), .src[1] = IO(S1), 
},
+      .phase_io[PH(0)] = { .dst[0] = IO(FT0), .src[0] = IO(S0), .src[1] = 
IO(S1), },
       .supported_op_mods = OM(LP) | OM(SAT),
       .supported_src_mods = {
          [0] = SM(FLR) | SM(ABS) | SM(NEG),
          [1] = SM(ABS),
       },
-      .supported_dst_types = T(REG),
+      .supported_dst_types = { [0] = T(REG), },
       .supported_src_types = {
          [0] = T(REG),
          [1] = T(REG),
       },
    },
-   [ROGUE_ALU_OP_FMAD] = { .str = "fmad", .num_srcs = 3,
+   [ROGUE_ALU_OP_FMAD] = { .str = "fmad", .num_dsts = 1, .num_srcs = 3,
       .supported_phases = P(0),
-      .phase_io[PH(0)] = { .dst = IO(FT0), .src[0] = IO(S0), .src[1] = IO(S1), 
.src[2] = IO(S2), },
+      .phase_io[PH(0)] = { .dst[0] = IO(FT0), .src[0] = IO(S0), .src[1] = 
IO(S1), .src[2] = IO(S2), },
       .supported_op_mods = OM(LP) | OM(SAT),
       .supported_src_mods = {
          [0] = SM(ABS) | SM(NEG),
          [1] = SM(ABS) | SM(NEG),
          [2] = SM(FLR) | SM(ABS) | SM(NEG),
       },
-      .supported_dst_types = T(REG),
+      .supported_dst_types = { [0] = T(REG), },
       .supported_src_types = {
          [0] = T(REG),
          [1] = T(REG),
@@ -351,30 +351,30 @@ const rogue_alu_op_info 
rogue_alu_op_infos[ROGUE_ALU_OP_COUNT] = {
       },
    },
    /* TODO: Implement */
-   [ROGUE_ALU_OP_TST] = { .str = "tst", .num_srcs = 2, },
-   [ROGUE_ALU_OP_PCK_U8888] = { .str = "pck.u8888", .num_srcs = 1,
+   [ROGUE_ALU_OP_TST] = { .str = "tst", .num_dsts = 2, .num_srcs = 2, },
+   [ROGUE_ALU_OP_PCK_U8888] = { .str = "pck.u8888", .num_dsts = 1, .num_srcs = 
1,
       .supported_phases = P(2_PCK),
-      .phase_io[PH(2_PCK)] = { .dst = IO(FT2), .src[0] = IO(IS3), },
+      .phase_io[PH(2_PCK)] = { .dst[0] = IO(FT2), .src[0] = IO(IS3), },
       .supported_op_mods = OM(SCALE) | OM(ROUNDZERO),
-      .supported_dst_types = T(REG),
+      .supported_dst_types = { [0] = T(REG), },
       .supported_src_types = {
          [0] = T(REGARRAY),
       },
    },
    /* This mov is "fake" since it can be lowered to a MBYP, make a new 
instruction for real mov (call it MOVD?). */
-   [ROGUE_ALU_OP_MOV] = { .str = "mov", .num_srcs = 1,
-      .supported_dst_types = T(REG),
+   [ROGUE_ALU_OP_MOV] = { .str = "mov", .num_dsts = 1, .num_srcs = 1,
+      .supported_dst_types = { [0] = T(REG), },
       .supported_src_types = {
          [0] = T(REG) | T(IMM),
       },
    },
-   [ROGUE_ALU_OP_FABS] = { .str = "fabs", .num_srcs = 1, },
-   [ROGUE_ALU_OP_FNEG] = { .str = "fneg", .num_srcs = 1, },
-   [ROGUE_ALU_OP_FNABS] = { .str = "fnabs", .num_srcs = 1, },
+   [ROGUE_ALU_OP_FABS] = { .str = "fabs", .num_dsts = 1, .num_srcs = 1, },
+   [ROGUE_ALU_OP_FNEG] = { .str = "fneg", .num_dsts = 1, .num_srcs = 1, },
+   [ROGUE_ALU_OP_FNABS] = { .str = "fnabs", .num_dsts = 1, .num_srcs = 1, },
 
-   [ROGUE_ALU_OP_FMAX] = { .str = "fmax", .num_srcs = 2, }, /* TODO */
-   [ROGUE_ALU_OP_FMIN] = { .str = "fmin", .num_srcs = 2, }, /* TODO */
-   [ROGUE_ALU_OP_SEL] = { .str = "sel", .num_srcs = 3, }, /* TODO */
+   [ROGUE_ALU_OP_FMAX] = { .str = "fmax", .num_dsts = 1, .num_srcs = 2, }, /* 
TODO */
+   [ROGUE_ALU_OP_FMIN] = { .str = "fmin", .num_dsts = 1, .num_srcs = 2, }, /* 
TODO */
+   [ROGUE_ALU_OP_SEL] = { .str = "sel", .num_dsts = 1, .num_srcs = 3, }, /* 
TODO */
 };
 #undef T
 #undef IO
diff --git a/src/imagination/rogue/rogue_print.c 
b/src/imagination/rogue/rogue_print.c
index b185869668b..94442170843 100644
--- a/src/imagination/rogue/rogue_print.c
+++ b/src/imagination/rogue/rogue_print.c
@@ -256,12 +256,21 @@ static inline void rogue_print_alu_instr(FILE *fp, const 
rogue_alu_instr *alu)
 
    rogue_print_alu_mods(fp, alu);
 
-   fputs(" ", fp);
+   for (unsigned i = 0; i < info->num_dsts; ++i) {
+      if (i > 0)
+         fputs(",", fp);
+
+      fputs(" ", fp);
 
-   rogue_print_alu_dst(fp, &alu->dst);
+      rogue_print_alu_dst(fp, &alu->dst[i]);
+   }
 
    for (unsigned i = 0; i < info->num_srcs; ++i) {
-      fputs(", ", fp);
+      if (i == 0 && !info->num_dsts)
+         fputs(" ", fp);
+      else
+         fputs(", ", fp);
+
       rogue_print_alu_src(fp, &alu->src[i]);
    }
 }
diff --git a/src/imagination/rogue/rogue_validate.c 
b/src/imagination/rogue/rogue_validate.c
index 76ce80640ec..c4f4110015d 100644
--- a/src/imagination/rogue/rogue_validate.c
+++ b/src/imagination/rogue/rogue_validate.c
@@ -194,8 +194,9 @@ static void validate_alu_instr(rogue_validation_state 
*state,
    if (!rogue_mods_supported(alu->mod, info->supported_op_mods))
       validate_log(state, "Unsupported ALU op modifiers.");
 
-   /* Validate destination and sources. */
-   validate_alu_dst(state, &alu->dst, info->supported_dst_types);
+   /* Validate destinations and sources. */
+   for (unsigned i = 0; i < info->num_dsts; ++i)
+      validate_alu_dst(state, &alu->dst[i], info->supported_dst_types[i]);
 
    for (unsigned i = 0; i < info->num_srcs; ++i)
       validate_alu_src(state, &alu->src[i], info->supported_src_types[i]);

Reply via email to