ppc/svp64: validate and fix modes
authorDmitry Selyutin <ghostmansd@gmail.com>
Sun, 19 Jun 2022 17:59:19 +0000 (20:59 +0300)
committerDmitry Selyutin <ghostmansd@gmail.com>
Fri, 23 Sep 2022 17:11:54 +0000 (20:11 +0300)
gas/config/tc-ppc-svp64.c

index 0f7db8c474abcb8f20f487dda16f1d9f5dcd4113..b9a07c2f594de9c4f00856953b6d086e86a82daf 100644 (file)
@@ -45,7 +45,6 @@ struct svp64_ctx {
   unsigned int mr : 1;
   unsigned int rg : 1;
   unsigned int crm : 1;
-  unsigned int svm : 1;
   unsigned int type : 2;
   unsigned int rc : 1;
   unsigned int mode : 5;
@@ -533,20 +532,6 @@ svp64_decode_crm (char *str, struct svp64_ctx *svp64)
   return str;
 }
 
-static char *
-svp64_decode_svm (char *str, struct svp64_ctx *svp64)
-{
-  str += (sizeof ("svm") - 1);
-  if ( ! ISSPACE (*str) && *str != SVP64_SEP && *str != '\0')
-    return NULL;
-
-  svp64->svm = 1;
-
-  *str++ = '\0';
-
-  return str;
-}
-
 static char *
 svp64_decode_mode (char *str, struct svp64_ctx *svp64)
 {
@@ -571,7 +556,6 @@ svp64_decode_mode (char *str, struct svp64_ctx *svp64)
     SVP64_DECODER ("mr"  , svp64_decode_mr),
     SVP64_DECODER ("mrr" , svp64_decode_mrr),
     SVP64_DECODER ("crm" , svp64_decode_crm),
-    SVP64_DECODER ("svm" , svp64_decode_svm),
   };
 
   for (i = 0; i < sizeof (table) / sizeof (table[0]); ++i)
@@ -768,7 +752,189 @@ svp64_decode (char *str, struct svp64_ctx *svp64)
 }
 
 static void
-svp64_validate (struct svp64_ctx *svp64)
+svp64_validate_and_fix_mode_bc (struct svp64_ctx *svp64)
+{
+  /*
+   * Create mode and (overridden) src/dst widths.
+   * TODO: sanity-check BC modes.
+   */
+  svp64->sv_mode = ((svp64->bc_svstep << SVP64_MODE_MOD2_MSB) |
+                    (svp64->bc_vlset << SVP64_MODE_MOD2_LSB) |
+                    (svp64->bc_snz << SVP64_MODE_BC_SNZ));
+  svp64->srcwid = ((svp64->bc_vsb << 1) | svp64->bc_lru);
+  svp64->destwid = ((svp64->bc_lru << 1) | svp64->bc_all);
+}
+
+static void
+svp64_validate_and_fix_mode_mr (struct svp64_ctx *svp64)
+{
+  svp64->mode |= (1U << SVP64_MODE_REDUCE);
+  svp64_raise_if (svp64->dst_zero,
+    "dest-zero not allowed in mr mode");
+
+  if (svp64->rg)
+    svp64->mode |= (1U << SVP64_MODE_RG);
+
+  if (svp64->crm)
+    {
+      svp64->mode |= (1U << SVP64_MODE_CRM);
+      svp64_raise_if (!svp64->rc, "CRM only allowed when Rc=1");
+    }
+
+  /*
+   * Bit of weird encoding to jam zero-pred or SVM mode in.
+   * SVM mode can be enabled only when SUBVL=2/3/4 (vec2/3/4)
+   */
+  if (svp64->subvl == 0)
+    svp64->mode |= (svp64->dst_zero << SVP64_MODE_DZ);
+}
+
+static void
+svp64_validate_and_fix_mode_ff(struct svp64_ctx *svp64)
+{
+  svp64_raise_if (svp64->src_zero,
+    "dest-zero not allowed in ff mode");
+
+  if (svp64->ff & SVP64_RC1_ACTIVE)
+    {
+      svp64->mode |= (1U << SVP64_MODE_RC1);
+      svp64->mode |= (svp64->dst_zero << SVP64_MODE_DZ);
+      svp64_raise_if (svp64->rc,
+        "ffirst RC1/~RC1 only possible when Rc=0");
+      if (svp64->ff & SVP64_RC1_INVERT)
+        svp64->mode |= (1U << SVP64_MODE_INV);
+    }
+  else
+    {
+      svp64_raise_if (svp64->dst_zero,
+        "dst-zero not allowed in ffirst BO");
+      svp64_raise_if (!svp64->rc,
+        "ffirst BO only possible when Rc=1");
+      svp64->mode |= (svp64->ff << SVP64_MODE_BO_LSB);
+    }
+}
+
+static void
+svp64_validate_and_fix_mode_sat(struct svp64_ctx *svp64)
+{
+  svp64->mode |= (svp64->src_zero << SVP64_MODE_SZ);
+  svp64->mode |= (svp64->dst_zero << SVP64_MODE_DZ);
+  svp64->mode |= (svp64->sat << SVP64_MODE_N);
+}
+
+static void
+svp64_validate_and_fix_mode_pr(struct svp64_ctx *svp64)
+{
+  svp64_raise_if (svp64->src_zero,
+    "dest-zero not allowed in pr mode");
+
+  if (svp64->pr & SVP64_RC1_ACTIVE)
+    {
+      svp64->mode |= (1U << SVP64_MODE_RC1);
+      svp64->mode |= (svp64->dst_zero << SVP64_MODE_DZ);
+      svp64_raise_if (svp64->rc,
+        "pr-mode RC1/~RC1 only possible when Rc=0");
+      if (svp64->pr & SVP64_RC1_INVERT)
+        svp64->mode |= (1U << SVP64_MODE_INV);
+    }
+  else
+    {
+      svp64_raise_if (svp64->dst_zero,
+        "dst-zero not allowed in pr-mode BO");
+      svp64_raise_if (!svp64->rc,
+        "pr-mode BO only possible when Rc=1");
+      svp64->mode |= (svp64->pr << SVP64_MODE_BO_LSB);
+    }
+}
+
+static void
+svp64_validate_and_fix_mode_explicit(struct svp64_ctx *svp64)
+{
+  static void (*const table[])(struct svp64_ctx *svp64) = {
+    svp64_validate_and_fix_mode_mr,
+    svp64_validate_and_fix_mode_ff,
+    svp64_validate_and_fix_mode_sat,
+    svp64_validate_and_fix_mode_pr,
+  };
+
+  return table[svp64->sv_mode] (svp64);
+}
+
+static void
+svp64_validate_and_fix_mode_normal (struct svp64_ctx *svp64)
+{
+  svp64->mode |= (svp64->src_zero << SVP64_MODE_SZ);
+  svp64->mode |= (svp64->dst_zero << SVP64_MODE_DZ);
+  if ((svp64->type == SVP64_TYPE_LD) ||
+      (svp64->type == SVP64_TYPE_ST))
+    {
+      /* TODO: for now, LD/ST-indexed is ignored. */
+      svp64->mode |= (svp64->ldst_elstride << SVP64_MODE_ELS_NORMAL);
+    }
+  else
+    {
+      /*
+       * TODO: reduce and subvector mode.
+       * 00  1   dz CRM  reduce mode (mr), SUBVL=1
+       * 00  1   SVM CRM subvector reduce mode, SUBVL>1
+       */
+    }
+  svp64->sv_mode = 0;
+}
+
+/*
+ * There are 4 different modes, here, which will be partly-merged-in:
+ * is_ldst is merged in with "normal", but is_bc is so different it's
+ * done separately. Likewise is_cr (when it is done).
+ *
+ * "normal" arithmetic: https://libre-soc.org/openpower/sv/normal
+ * | 0-1 |  2  |  3   4  |  description                              |
+ * | --- | --- |---------|------------------------------------------ |
+ * | 00  |   0 |  dz  sz | normal mode                               |
+ * | 00  |   1 |   0  RG | scalar reduce mode (mr), SUBVL=1          |
+ * | 00  |   1 |   1  /  | parallel reduce mode (mr), SUBVL=1        |
+ * | 00  |   1 | SVM  RG | subvector reduce mode, SUBVL>1            |
+ * | 01  | inv | CR-bit  | Rc=1: ffirst CR sel                       |
+ * | 01  | inv | VLi RC1 | Rc=0: ffirst z/nonz                       |
+ * | 10  |   N | dz   sz | sat mode: N=0/1 u/s                       |
+ * | 11  | inv | CR-bit  | Rc=1: pred-result CR sel                  |
+ * | 11  | inv | dz  RC1 | Rc=0: pred-result z/nonz                  |
+ *
+ * LD/ST-immediate: https://libre-soc.org/openpower/sv/ldst
+ * | 0-1 |  2  |  3   4  |  description                              |
+ * | --- | --- |---------|------------------------------------------ |
+ * | 00  | 0   |  dz els | normal mode                               |
+ * | 00  | 1   |  dz shf | shift mode                                |
+ * | 01  | inv | CR-bit  | Rc=1: ffirst CR sel                       |
+ * | 01  | inv | els RC1 | Rc=0: ffirst z/nonz                       |
+ * | 10  |   N | dz  els | sat mode: N=0/1 u/s                       |
+ * | 11  | inv | CR-bit  | Rc=1: pred-result CR sel                  |
+ * | 11  | inv | els RC1 | Rc=0: pred-result z/nonz                  |
+ *
+ * LD/ST-indexed (RA+RB): https://libre-soc.org/openpower/sv/ldst
+ * | 0-1 |  2  |  3   4  |  description                              |
+ * | --- | --- |---------|------------------------------------------ |
+ * | 00  | SEA |  dz  sz | normal mode                               |
+ * | 01  | SEA |  dz  sz | Strided (scalar only source)              |
+ * | 10  |   N |  dz  sz |  sat mode: N=0/1 u/s                      |
+ * | 11  | inv | CR-bit  |  Rc=1: pred-result CR sel                 |
+ * | 11  | inv | dz  RC1 |  Rc=0: pred-result z/nonz                 |
+ *
+ * ...and branches/cr_ops are still in development.
+ */
+static void
+svp64_validate_and_fix_mode (struct svp64_ctx *svp64)
+{
+  if (svp64->type == SVP64_TYPE_BC)
+    svp64_validate_and_fix_mode_bc (svp64);
+  else if (svp64->sv_mode_explicit)
+    svp64_validate_and_fix_mode_explicit (svp64);
+  else
+    svp64_validate_and_fix_mode_normal (svp64);
+}
+
+static void
+svp64_validate_and_fix (struct svp64_ctx *svp64)
 {
   if (svp64->desc->ptype == SVP64_PTYPE_P2)
     {
@@ -816,14 +982,6 @@ svp64_validate (struct svp64_ctx *svp64)
         }
     }
 
-  if (svp64->svm)
-    {
-      svp64_raise_if (svp64->sv_mode != 0,
-        "sub-vector mode in mapreduce only");
-      svp64_raise_if (svp64->subvl == 0,
-        "sub-vector mode not possible on SUBVL!=0");
-    }
-
   if (svp64->src_zero)
     {
       svp64_raise_if (!svp64->has_smask && !svp64->mask_m_specified,
@@ -834,6 +992,8 @@ svp64_validate (struct svp64_ctx *svp64)
       svp64_raise_if (!svp64->has_pmask && !svp64->mask_m_specified,
         "dest zeroing requires a dest predicate");
     }
+
+  svp64_validate_and_fix_mode (svp64);
 }
 
 static void
@@ -847,7 +1007,7 @@ svp64_assemble (char *str)
   memset (&svp64, 0, sizeof (svp64));
 
   svp64_decode (str, &svp64);
-  svp64_validate (&svp64);
+  svp64_validate_and_fix (&svp64);
 
   as_warn (_("opcode ignored (desc=%p)"), svp64.desc);
   memcpy (str, "nop", sizeof ("nop"));