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

Author: Simon Perretta <[email protected]>
Date:   Sun Feb 12 15:26:06 2023 +0000

pvr: Add support for validating modifier combos

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

---

 src/imagination/.clang-format          |  1 +
 src/imagination/rogue/rogue.h          | 60 +++++++++++++++--------
 src/imagination/rogue/rogue_encode.c   |  4 +-
 src/imagination/rogue/rogue_info.c     | 80 ++++++++++++++++++++++++-------
 src/imagination/rogue/rogue_validate.c | 88 ++++++++++++++++++++++++++++++++--
 5 files changed, 191 insertions(+), 42 deletions(-)

diff --git a/src/imagination/.clang-format b/src/imagination/.clang-format
index abb446037e2..2021ccfb223 100644
--- a/src/imagination/.clang-format
+++ b/src/imagination/.clang-format
@@ -251,6 +251,7 @@ ForEachMacros: [
   'rogue_foreach_instr_in_shader_safe',
   'rogue_foreach_instr_in_shader_rev',
   'rogue_foreach_instr_in_shader_safe_rev',
+  'rogue_foreach_mod_in_set',
   'rogue_foreach_reg',
   'rogue_foreach_reg_safe',
   'rogue_foreach_reg_use',
diff --git a/src/imagination/rogue/rogue.h b/src/imagination/rogue/rogue.h
index 4ff55bfbcc8..36a61805c41 100644
--- a/src/imagination/rogue/rogue.h
+++ b/src/imagination/rogue/rogue.h
@@ -348,15 +348,16 @@ enum rogue_instr_phase {
    ROGUE_INSTR_PHASE_INVALID = ~0,
 };
 
-#define rogue_foreach_phase_in_set(p, phases)  \
-   for (uint64_t __phases = (phases), p;       \
-        ((p) = ffsll(__phases) - 1, __phases); \
-        __phases &= ~(1ull << (p)))
+/* TODO: put into bitscan.h */
+#define u_foreach_bit64_rev(b, dword)                  \
+   for (uint64_t __dword = (dword), b;                 \
+        ((b) = util_last_bit64(__dword) - 1, __dword); \
+        __dword &= ~(1ull << (b)))
 
-#define rogue_foreach_phase_in_set_rev(p, phases)        \
-   for (uint64_t __phases = (phases), p;                 \
-        ((p) = util_last_bit64(__phases) - 1, __phases); \
-        __phases &= ~(1ull << (p)))
+#define rogue_foreach_phase_in_set(p, phases) u_foreach_bit64(p, phases)
+#define rogue_foreach_phase_in_set_rev(p, phases) u_foreach_bit64_rev(p, 
phases)
+
+#define rogue_foreach_mod_in_set(m, mods) u_foreach_bit64(m, mods)
 
 /** Rogue basic block. */
 typedef struct rogue_block {
@@ -1046,6 +1047,8 @@ enum rogue_alu_op_mod {
 
 typedef struct rogue_alu_op_mod_info {
    const char *str;
+   uint64_t exclude; /* Can't use this op mod with any of these. */
+   uint64_t require; /* Required op mods for this to be used (OR). */
 } rogue_alu_op_mod_info;
 
 extern const rogue_alu_op_mod_info
@@ -1113,6 +1116,8 @@ enum rogue_ctrl_op_mod {
 
 typedef struct rogue_ctrl_op_mod_info {
    const char *str;
+   uint64_t exclude; /* Can't use this op mod with any of these. */
+   uint64_t require; /* Required op mods for this to be used (OR). */
 } rogue_ctrl_op_mod_info;
 
 extern const rogue_ctrl_op_mod_info
@@ -1383,7 +1388,6 @@ typedef struct rogue_backend_op_info {
 extern const rogue_backend_op_info
    rogue_backend_op_infos[ROGUE_BACKEND_OP_COUNT];
 
-/* TODO: Some of these may not be used together; express that in op mod info. 
*/
 enum rogue_backend_op_mod {
    /* In order of priority */
    ROGUE_BACKEND_OP_MOD_PROJ, /* Projection (send T co-ordinate). */
@@ -1440,6 +1444,8 @@ enum rogue_backend_op_mod {
 
 typedef struct rogue_backend_op_mod_info {
    const char *str;
+   uint64_t exclude; /* Can't use this op mod with any of these. */
+   uint64_t require; /* Required op mods for this to be used (OR). */
 } rogue_backend_op_mod_info;
 
 extern const rogue_backend_op_mod_info
@@ -1531,6 +1537,25 @@ enum rogue_bitwise_op {
    ROGUE_BITWISE_OP_COUNT,
 };
 
+enum rogue_bitwise_op_mod {
+   /* In order of priority */
+   ROGUE_BITWISE_OP_MOD_TWB, /* Top word break. */
+   ROGUE_BITWISE_OP_MOD_PWB, /* Partial word break. */
+   ROGUE_BITWISE_OP_MOD_MTB, /* Mask top break. */
+   ROGUE_BITWISE_OP_MOD_FTB, /* Find top break. */
+
+   ROGUE_BITWISE_OP_MOD_COUNT,
+};
+
+typedef struct rogue_bitwise_op_mod_info {
+   const char *str;
+   uint64_t exclude; /* Can't use this op mod with any of these. */
+   uint64_t require; /* Required op mods for this to be used (OR). */
+} rogue_bitwise_op_mod_info;
+
+extern const rogue_bitwise_op_mod_info
+   rogue_bitwise_op_mod_infos[ROGUE_BITWISE_OP_MOD_COUNT];
+
 #define ROGUE_BITWISE_OP_MAX_SRCS 7
 #define ROGUE_BITWISE_OP_MAX_DSTS 2
 
@@ -1586,21 +1611,18 @@ typedef struct rogue_bitwise_instr {
    rogue_src_use src_use[ROGUE_BITWISE_OP_MAX_SRCS];
 } rogue_bitwise_instr;
 
-#if 0
-static inline
-void
-rogue_set_bitwise_op_mod(rogue_bitwise_instr *bitwise, enum 
rogue_bitwise_op_mod mod)
+static inline void rogue_set_bitwise_op_mod(rogue_bitwise_instr *bitwise,
+                                            enum rogue_bitwise_op_mod mod)
 {
-       bitwise->mod |= BITFIELD64_BIT(mod);
+   bitwise->mod |= BITFIELD64_BIT(mod);
 }
 
-static inline
-bool
-rogue_bitwise_op_mod_is_set(const rogue_bitwise_instr *bitwise, enum 
rogue_bitwise_op_mod mod)
+static inline bool
+rogue_bitwise_op_mod_is_set(const rogue_bitwise_instr *bitwise,
+                            enum rogue_bitwise_op_mod mod)
 {
-       return !!(bitwise->mod & BITFIELD64_BIT(mod));
+   return !!(bitwise->mod & BITFIELD64_BIT(mod));
 }
-#endif
 
 /**
  * \brief Allocates and initializes a new bitwise instruction.
diff --git a/src/imagination/rogue/rogue_encode.c 
b/src/imagination/rogue/rogue_encode.c
index 598edac709e..e4a3cbdce95 100644
--- a/src/imagination/rogue/rogue_encode.c
+++ b/src/imagination/rogue/rogue_encode.c
@@ -289,7 +289,7 @@ static void rogue_encode_alu_instr(const rogue_alu_instr 
*alu,
 #undef DM
 #undef SM
 
-#define OM(op_mod) BITFIELD64_BIT(ROGUE_BACKEND_OP_MOD_##op_mod)
+#define OM(op_mod) ROGUE_BACKEND_OP_MOD_##op_mod
 static void rogue_encode_backend_instr(const rogue_backend_instr *backend,
                                        unsigned instr_size,
                                        rogue_instr_encoding *instr_encoding)
@@ -471,7 +471,7 @@ static void rogue_encode_backend_instr(const 
rogue_backend_instr *backend,
             rogue_backend_op_mod_is_set(backend, OM(PPLOD));
       }
 
-      if (instr_size >= 3) {
+      if (instr_size > 3) {
          instr_encoding->backend.dma.smp.extb = 1;
 
          instr_encoding->backend.dma.smp.w =
diff --git a/src/imagination/rogue/rogue_info.c 
b/src/imagination/rogue/rogue_info.c
index 6d0212fcb2f..80ea1e1d1f6 100644
--- a/src/imagination/rogue/rogue_info.c
+++ b/src/imagination/rogue/rogue_info.c
@@ -282,8 +282,11 @@ const rogue_backend_op_info 
rogue_backend_op_infos[ROGUE_BACKEND_OP_COUNT] = {
          [1] = T(REGARRAY),
          [2] = T(VAL),
       },
+      .dst_stride = {
+         [0] = ~0U,
+      },
       .src_stride = {
-         [1] = 3,
+         [1] = ~0U,
       },
    },
        [ROGUE_BACKEND_OP_FITRP_PIXEL] = { .str = "fitrp.pixel", .num_dsts = 1, 
.num_srcs = 4,
@@ -318,6 +321,15 @@ const rogue_backend_op_info 
rogue_backend_op_infos[ROGUE_BACKEND_OP_COUNT] = {
          [4] = T(REG) | T(IO),
          [5] = T(VAL),
       },
+      /* TODO: This may depend on the other options set. */
+      .src_stride = {
+         [1] = 3,
+         [2] = ~0U,
+         [3] = 3,
+      },
+      .dst_stride = {
+         [0] = ~0U,
+      },
    },
        [ROGUE_BACKEND_OP_SMP2D] = { .str = "smp2d", .num_dsts = 1, .num_srcs = 
6,
       .phase_io = { .dst[0] = IO(S4), .src[1] = IO(S0), .src[2] = IO(S1), 
.src[3] = IO(S2), },
@@ -336,6 +348,15 @@ const rogue_backend_op_info 
rogue_backend_op_infos[ROGUE_BACKEND_OP_COUNT] = {
          [4] = T(REG) | T(IO),
          [5] = T(VAL),
       },
+      /* TODO: This may depend on the other options set. */
+      .src_stride = {
+         [1] = 3,
+         [2] = ~0U,
+         [3] = 3,
+      },
+      .dst_stride = {
+         [0] = ~0U,
+      },
    },
        [ROGUE_BACKEND_OP_SMP3D] = { .str = "smp3d", .num_dsts = 1, .num_srcs = 
6,
       .phase_io = { .dst[0] = IO(S4), .src[1] = IO(S0), .src[2] = IO(S1), 
.src[3] = IO(S2), },
@@ -354,6 +375,15 @@ const rogue_backend_op_info 
rogue_backend_op_infos[ROGUE_BACKEND_OP_COUNT] = {
          [4] = T(REG) | T(IO),
          [5] = T(VAL),
       },
+      /* TODO: This may depend on the other options set. */
+      .src_stride = {
+         [1] = 3,
+         [2] = ~0U,
+         [3] = 3,
+      },
+      .dst_stride = {
+         [0] = ~0U,
+      },
    },
 };
 #undef B
@@ -361,36 +391,37 @@ const rogue_backend_op_info 
rogue_backend_op_infos[ROGUE_BACKEND_OP_COUNT] = {
 #undef OM
 #undef IO
 
+#define OM(op_mod) BITFIELD64_BIT(ROGUE_BACKEND_OP_MOD_##op_mod)
 const rogue_backend_op_mod_info 
rogue_backend_op_mod_infos[ROGUE_BACKEND_OP_MOD_COUNT] = {
    [ROGUE_BACKEND_OP_MOD_PROJ]  = { .str = "proj", },
    [ROGUE_BACKEND_OP_MOD_FCNORM]  = { .str = "fcnorm", },
    [ROGUE_BACKEND_OP_MOD_NNCOORDS]  = { .str = "nncoords", },
 
-   [ROGUE_BACKEND_OP_MOD_BIAS]  = { .str = "bias", },
-   [ROGUE_BACKEND_OP_MOD_REPLACE]  = { .str = "replace", },
-   [ROGUE_BACKEND_OP_MOD_GRADIENT]  = { .str = "gradient", },
+   [ROGUE_BACKEND_OP_MOD_BIAS]  = { .str = "bias", .exclude = OM(REPLACE) | 
OM(GRADIENT) },
+   [ROGUE_BACKEND_OP_MOD_REPLACE]  = { .str = "replace", .exclude = OM(BIAS) | 
OM(GRADIENT) },
+   [ROGUE_BACKEND_OP_MOD_GRADIENT]  = { .str = "gradient", .exclude = OM(BIAS) 
| OM(REPLACE) },
 
-   [ROGUE_BACKEND_OP_MOD_PPLOD]  = { .str = "pplod", },
+   [ROGUE_BACKEND_OP_MOD_PPLOD]  = { .str = "pplod", .require = OM(BIAS) | 
OM(REPLACE) },
    [ROGUE_BACKEND_OP_MOD_TAO]  = { .str = "tao", },
    [ROGUE_BACKEND_OP_MOD_SOO]  = { .str = "soo", },
    [ROGUE_BACKEND_OP_MOD_SNO]  = { .str = "sno", },
    [ROGUE_BACKEND_OP_MOD_WRT]  = { .str = "wrt", },
 
-   [ROGUE_BACKEND_OP_MOD_DATA]  = { .str = "data", },
-   [ROGUE_BACKEND_OP_MOD_INFO]  = { .str = "info", },
-   [ROGUE_BACKEND_OP_MOD_BOTH]  = { .str = "both", },
+   [ROGUE_BACKEND_OP_MOD_DATA]  = { .str = "data", .exclude = OM(INFO) | 
OM(BOTH) },
+   [ROGUE_BACKEND_OP_MOD_INFO]  = { .str = "info", .exclude = OM(DATA) | 
OM(BOTH) },
+   [ROGUE_BACKEND_OP_MOD_BOTH]  = { .str = "both", .exclude = OM(DATA) | 
OM(INFO) },
 
-   [ROGUE_BACKEND_OP_MOD_BYPASS]  = { .str = "bypass", },
-   [ROGUE_BACKEND_OP_MOD_FORCELINEFILL]  = { .str = "forcelinefill", },
+   [ROGUE_BACKEND_OP_MOD_BYPASS]  = { .str = "bypass", .exclude = 
OM(FORCELINEFILL) | OM(WRITETHROUGH) | OM(WRITEBACK) | OM(LAZYWRITEBACK) },
+   [ROGUE_BACKEND_OP_MOD_FORCELINEFILL]  = { .str = "forcelinefill", .exclude 
= OM(BYPASS) | OM(WRITETHROUGH) | OM(WRITEBACK) | OM(LAZYWRITEBACK) },
 
-   [ROGUE_BACKEND_OP_MOD_WRITETHROUGH]  = { .str = "writethrough", },
-   [ROGUE_BACKEND_OP_MOD_WRITEBACK]  = { .str = "writeback", },
-   [ROGUE_BACKEND_OP_MOD_LAZYWRITEBACK]  = { .str = "lazywriteback", },
+   [ROGUE_BACKEND_OP_MOD_WRITETHROUGH]  = { .str = "writethrough", .exclude = 
OM(BYPASS) | OM(FORCELINEFILL) | OM(WRITEBACK) | OM(LAZYWRITEBACK) },
+   [ROGUE_BACKEND_OP_MOD_WRITEBACK]  = { .str = "writeback", .exclude = 
OM(BYPASS) | OM(FORCELINEFILL) | OM(WRITETHROUGH) | OM(LAZYWRITEBACK) },
+   [ROGUE_BACKEND_OP_MOD_LAZYWRITEBACK]  = { .str = "lazywriteback", .exclude 
= OM(BYPASS) | OM(FORCELINEFILL) | OM(WRITETHROUGH) | OM(WRITEBACK) },
 
-   [ROGUE_BACKEND_OP_MOD_SLCBYPASS]  = { .str = "slcbypass", },
-   [ROGUE_BACKEND_OP_MOD_SLCWRITEBACK]  = { .str = "slcwriteback", },
-   [ROGUE_BACKEND_OP_MOD_SLCWRITETHROUGH]  = { .str = "slcwritethrough", },
-   [ROGUE_BACKEND_OP_MOD_SLCNOALLOC]  = { .str = "slcnoalloc", },
+   [ROGUE_BACKEND_OP_MOD_SLCBYPASS]  = { .str = "slcbypass", .exclude = 
OM(SLCWRITEBACK) | OM(SLCWRITETHROUGH) | OM(SLCNOALLOC) },
+   [ROGUE_BACKEND_OP_MOD_SLCWRITEBACK]  = { .str = "slcwriteback", .exclude = 
OM(SLCBYPASS) | OM(SLCWRITETHROUGH) | OM(SLCNOALLOC) },
+   [ROGUE_BACKEND_OP_MOD_SLCWRITETHROUGH]  = { .str = "slcwritethrough", 
.exclude = OM(SLCBYPASS) | OM(SLCWRITEBACK) | OM(SLCNOALLOC) },
+   [ROGUE_BACKEND_OP_MOD_SLCNOALLOC]  = { .str = "slcnoalloc", .exclude = 
OM(SLCBYPASS) | OM(SLCWRITEBACK) | OM(SLCWRITETHROUGH) },
 
    [ROGUE_BACKEND_OP_MOD_ARRAY]  = { .str = "array", },
    [ROGUE_BACKEND_OP_MOD_INTEGER]  = { .str = "integer", },
@@ -400,6 +431,21 @@ const rogue_backend_op_mod_info 
rogue_backend_op_mod_infos[ROGUE_BACKEND_OP_MOD_
 
    [ROGUE_BACKEND_OP_MOD_SAT]  = { .str = "sat", },
 };
+#undef OM
+
+#define OM(op_mod) BITFIELD64_BIT(ROGUE_BITWISE_OP_MOD_##op_mod)
+const rogue_bitwise_op_mod_info
+   rogue_bitwise_op_mod_infos[ROGUE_BITWISE_OP_MOD_COUNT] = {
+      [ROGUE_BITWISE_OP_MOD_TWB] = { .str = "twb",
+                                     .exclude = OM(PWB) | OM(MTB) | OM(FTB) },
+      [ROGUE_BITWISE_OP_MOD_PWB] = { .str = "pwb",
+                                     .exclude = OM(TWB) | OM(MTB) | OM(FTB) },
+      [ROGUE_BITWISE_OP_MOD_MTB] = { .str = "mtb",
+                                     .exclude = OM(TWB) | OM(PWB) | OM(FTB) },
+      [ROGUE_BITWISE_OP_MOD_FTB] = { .str = "ftb",
+                                     .exclude = OM(TWB) | OM(PWB) | OM(MTB) },
+   };
+#undef OM
 
 #define P(type) BITFIELD64_BIT(ROGUE_INSTR_PHASE_##type)
 #define PH(type) ROGUE_INSTR_PHASE_##type
diff --git a/src/imagination/rogue/rogue_validate.c 
b/src/imagination/rogue/rogue_validate.c
index a0c351b9e60..e8f9d7b4caa 100644
--- a/src/imagination/rogue/rogue_validate.c
+++ b/src/imagination/rogue/rogue_validate.c
@@ -224,6 +224,23 @@ static void validate_src(rogue_validation_state *state,
    state->ctx.ref = NULL;
 }
 
+static bool validate_alu_op_mod_combo(uint64_t mods)
+{
+   rogue_foreach_mod_in_set (mod, mods) {
+      const rogue_alu_op_mod_info *info = &rogue_alu_op_mod_infos[mod];
+
+      /* Check if any excluded op mods have been included. */
+      if (info->exclude & mods)
+         return false;
+
+      /* Check if any required op mods have been missed. */
+      if (info->require && !(info->require & mods))
+         return false;
+   }
+
+   return true;
+}
+
 static void validate_alu_instr(rogue_validation_state *state,
                                const rogue_alu_instr *alu)
 {
@@ -238,10 +255,13 @@ static void validate_alu_instr(rogue_validation_state 
*state,
    if (rogue_alu_comp_is_none(alu) && alu->op == ROGUE_ALU_OP_TST)
       validate_log(state, "ALU comparison not set for test op.");
 
-   /* Initial check if instruction modifiers are valid. */
+   /* Check if instruction modifiers are valid. */
    if (!rogue_mods_supported(alu->mod, info->supported_op_mods))
       validate_log(state, "Unsupported ALU op modifiers.");
 
+   if (!validate_alu_op_mod_combo(alu->mod))
+      validate_log(state, "Unsupported ALU op modifier combination.");
+
    /* Instruction repeat checks. */
    if (alu->instr.repeat > 1 && !info->dst_repeat_mask &&
        !info->src_repeat_mask) {
@@ -270,6 +290,23 @@ static void validate_alu_instr(rogue_validation_state 
*state,
    }
 }
 
+static bool validate_backend_op_mod_combo(uint64_t mods)
+{
+   rogue_foreach_mod_in_set (mod, mods) {
+      const rogue_backend_op_mod_info *info = &rogue_backend_op_mod_infos[mod];
+
+      /* Check if any excluded op mods have been included. */
+      if (info->exclude & mods)
+         return false;
+
+      /* Check if any required op mods have been missed. */
+      if (info->require && !(info->require & mods))
+         return false;
+   }
+
+   return true;
+}
+
 static void validate_backend_instr(rogue_validation_state *state,
                                    const rogue_backend_instr *backend)
 {
@@ -279,10 +316,13 @@ static void validate_backend_instr(rogue_validation_state 
*state,
 
    const rogue_backend_op_info *info = &rogue_backend_op_infos[backend->op];
 
-   /* Initial check if instruction modifiers are valid. */
+   /* Check if instruction modifiers are valid. */
    if (!rogue_mods_supported(backend->mod, info->supported_op_mods))
       validate_log(state, "Unsupported backend op modifiers.");
 
+   if (!validate_backend_op_mod_combo(backend->mod))
+      validate_log(state, "Unsupported backend op modifier combination.");
+
    /* Instruction repeat checks. */
    if (backend->instr.repeat > 1 && !info->dst_repeat_mask &&
        !info->src_repeat_mask) {
@@ -311,6 +351,23 @@ static void validate_backend_instr(rogue_validation_state 
*state,
    }
 }
 
+static bool validate_ctrl_op_mod_combo(uint64_t mods)
+{
+   rogue_foreach_mod_in_set (mod, mods) {
+      const rogue_ctrl_op_mod_info *info = &rogue_ctrl_op_mod_infos[mod];
+
+      /* Check if any excluded op mods have been included. */
+      if (info->exclude & mods)
+         return false;
+
+      /* Check if any required op mods have been missed. */
+      if (info->require && !(info->require & mods))
+         return false;
+   }
+
+   return true;
+}
+
 /* Returns true if instruction can end block. */
 static bool validate_ctrl_instr(rogue_validation_state *state,
                                 const rogue_ctrl_instr *ctrl)
@@ -327,10 +384,13 @@ static bool validate_ctrl_instr(rogue_validation_state 
*state,
       validate_log(state,
                    "Ctrl op did not expect target block, but one provided.");
 
-   /* Initial check if instruction modifiers are valid. */
+   /* Check if instruction modifiers are valid. */
    if (!rogue_mods_supported(ctrl->mod, info->supported_op_mods))
       validate_log(state, "Unsupported CTRL op modifiers.");
 
+   if (!validate_ctrl_op_mod_combo(ctrl->mod))
+      validate_log(state, "Unsupported CTRL op modifier combination.");
+
    /* Instruction repeat checks. */
    if (ctrl->instr.repeat > 1 && !info->dst_repeat_mask &&
        !info->src_repeat_mask) {
@@ -369,6 +429,23 @@ static bool validate_ctrl_instr(rogue_validation_state 
*state,
    return info->ends_block;
 }
 
+static bool validate_bitwise_op_mod_combo(uint64_t mods)
+{
+   rogue_foreach_mod_in_set (mod, mods) {
+      const rogue_bitwise_op_mod_info *info = &rogue_bitwise_op_mod_infos[mod];
+
+      /* Check if any excluded op mods have been included. */
+      if (info->exclude & mods)
+         return false;
+
+      /* Check if any required op mods have been missed. */
+      if (info->require && !(info->require & mods))
+         return false;
+   }
+
+   return true;
+}
+
 static void validate_bitwise_instr(rogue_validation_state *state,
                                    const rogue_bitwise_instr *bitwise)
 {
@@ -378,10 +455,13 @@ static void validate_bitwise_instr(rogue_validation_state 
*state,
 
    const rogue_bitwise_op_info *info = &rogue_bitwise_op_infos[bitwise->op];
 
-   /* Initial check if instruction modifiers are valid. */
+   /* Check if instruction modifiers are valid. */
    if (!rogue_mods_supported(bitwise->mod, info->supported_op_mods))
       validate_log(state, "Unsupported bitwise op modifiers.");
 
+   if (!validate_bitwise_op_mod_combo(bitwise->mod))
+      validate_log(state, "Unsupported bitwise op modifier combination.");
+
    /* Instruction repeat checks. */
    if (bitwise->instr.repeat > 1 && !info->dst_repeat_mask &&
        !info->src_repeat_mask) {

Reply via email to