ppc/svp64: validate and fix modes
authorDmitry Selyutin <ghostmansd@gmail.com>
Sun, 28 May 2023 22:04:56 +0000 (01:04 +0300)
committerDmitry Selyutin <ghostmansd@gmail.com>
Wed, 9 Aug 2023 16:52:09 +0000 (19:52 +0300)
gas/config/tc-ppc-svp64.c

index cbaaaf5fbd9a457819604a8c9504ee9eaf832219..91977b9d45a59aebac8f13bda15e1ac288c4451a 100644 (file)
@@ -47,6 +47,14 @@ struct svp64_ctx {
   unsigned int mr : 1;
   unsigned int RG : 1;
   unsigned int crm : 1;
+  unsigned int bc_all : 1;
+  unsigned int bc_lru : 1;
+  unsigned int bc_brc : 1;
+  unsigned int bc_svstep : 1;
+  unsigned int bc_vsb : 1;
+  unsigned int bc_vlset : 1;
+  unsigned int bc_vli : 1;
+  unsigned int bc_snz : 1;
 };
 
 #define SVP64_RC1_ACTIVE (1U << 3U)
@@ -609,7 +617,177 @@ 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->dz,
+    "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->desc->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->dz << SVP64_MODE_DZ);
+}
+
+static void
+svp64_validate_and_fix_mode_ff(struct svp64_ctx *svp64)
+{
+  svp64_raise_if (svp64->sz,
+    "dest-zero not allowed in ff mode");
+
+  if (svp64->ff & SVP64_RC1_ACTIVE)
+    {
+      svp64->mode |= (1U << SVP64_MODE_RC1);
+      svp64->mode |= (svp64->dz << SVP64_MODE_DZ);
+      svp64_raise_if (svp64->desc->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->dz,
+        "dst-zero not allowed in ffirst BO");
+      svp64_raise_if (!svp64->desc->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->sz << SVP64_MODE_SZ);
+  svp64->mode |= (svp64->dz << SVP64_MODE_DZ);
+  svp64->mode |= (svp64->sat << SVP64_MODE_N);
+}
+
+static void
+svp64_validate_and_fix_mode_strided(struct svp64_ctx *svp64)
+{
+  svp64->mode |= (svp64->dz << SVP64_MODE_DZ);
+  svp64->mode |= (svp64->sz << SVP64_MODE_SZ);
+  svp64->mode |= (svp64->sea << SVP64_MODE_SEA);
+}
+
+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,
+  };
+
+  if ((svp64->sv_mode == 0b01) && (svp64->desc->mode == SVP64_MODE_LDST_IDX))
+    return svp64_validate_and_fix_mode_strided (svp64);
+
+  return (*table[svp64->sv_mode]) (svp64);
+}
+
+static void
+svp64_validate_and_fix_mode_normal (struct svp64_ctx *svp64)
+{
+  svp64->mode |= (svp64->sz << SVP64_MODE_SZ);
+  svp64->mode |= (svp64->dz << SVP64_MODE_DZ);
+  if ((svp64->desc->mode == SVP64_MODE_LDST_IMM) ||
+      (svp64->desc->mode == SVP64_MODE_LDST_IDX))
+    {
+      /* TODO: for now, LD/ST-indexed is ignored. */
+      svp64->mode |= (svp64->els << 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->desc->mode == SVP64_MODE_BRANCH)
+    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);
+
+  svp64->mode |= (((svp64->sv_mode >> 0) & 0x1) << SVP64_MODE_MOD2_LSB);
+  svp64->mode |= (((svp64->sv_mode >> 1) & 0x1) << SVP64_MODE_MOD2_MSB);
+}
+
+static void
+svp64_validate_and_fix (struct svp64_ctx *svp64)
 {
   if (svp64->desc->ptype == SVP64_PTYPE_P2)
     {
@@ -667,6 +845,8 @@ svp64_validate (struct svp64_ctx *svp64)
       svp64_raise_if (!svp64->has_smask && !svp64->mask_m_specified,
         "src zeroing requires a source predicate");
     }
+
+  svp64_validate_and_fix_mode (svp64);
 }
 
 static void
@@ -680,7 +860,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"));