ppc/svp64: remap operands and build instructions
authorDmitry Selyutin <ghostmansd@gmail.com>
Sun, 28 May 2023 22:04:56 +0000 (01:04 +0300)
committerDmitry Selyutin <ghostmansd@gmail.com>
Tue, 15 Aug 2023 19:21:58 +0000 (22:21 +0300)
gas/config/tc-ppc-svp64.c
gas/config/tc-ppc.c

index b6dd549e7f166fbb32de59466047632115e48836..f840da7b2fc51a40ebb75d3e650d715444df63c7 100644 (file)
@@ -24,6 +24,7 @@
 struct svp64_ctx {
   const char *name;
   const struct svp64_desc *desc;
+  struct svp64_insn insn;
   unsigned int sv_mode_explicit : 1;
   unsigned int sv_mode : 2;
   unsigned int mode : 5;
@@ -912,6 +913,174 @@ svp64_validate_and_fix (struct svp64_ctx *svp64)
   svp64_validate_and_fix_mode (svp64);
 }
 
+static void
+svp64_remap_extra (struct svp64_ctx *svp64,
+    ppc_opindex_t opindex, uint32_t value)
+{
+  const struct svp64_extra_desc *desc;
+
+  desc = svp64_extra_desc (svp64->desc, opindex);
+  svp64_raise_if ((desc == NULL), "cannot remap EXTRA");
+
+  return (*desc->set) (&svp64->insn, value);
+}
+
+static int64_t
+svp64_remap_reg (struct svp64_ctx *svp64, int64_t value,
+    ppc_opindex_t opindex, bool vector)
+{
+  uint32_t field;
+  uint32_t sv_extra;
+
+  svp64_raise_if (((value < 0) || (value > 127)),
+    "register does not fit the expected range 0..127");
+  field = (uint32_t)value;
+
+  if (vector)
+    {
+      /* cut into 5-bits 2-bits FFFFF SS */
+      sv_extra = (field & 0x3);
+      field >>= 2;
+    }
+  else
+    {
+      /* cut into 2-bits 5-bits SS FFFFF */
+      sv_extra = (field >> 5);
+      field &= 0x1F;
+    }
+
+  if (svp64->desc->etype == SVP64_ETYPE_EXTRA2)
+    {
+      if (vector)
+        {
+          /* range is r0-r127 in increments of 2 (r0 r2 ... r126) */
+          svp64_raise_if ( ((sv_extra & 1) != 0),
+            "vector register cannot fit into EXTRA2");
+          sv_extra = (0x2 | (sv_extra >> 1));
+        }
+      else
+        {
+          /* range is r0-r63 in increments of 1 */
+          svp64_raise_if ( ((sv_extra >> 1) != 0),
+            "scalar register cannot fit into EXTRA2");
+          sv_extra &= 0x1;
+        }
+    }
+  else if (vector)
+    {
+      /* EXTRA3 vector bit needs marking */
+      sv_extra |= 0x4;
+    }
+
+  svp64_remap_extra (svp64, opindex, sv_extra);
+
+  return field;
+}
+
+static int64_t
+svp64_remap_gpr (struct svp64_ctx *svp64, int64_t value,
+    ppc_opindex_t opindex, bool vector)
+{
+  return svp64_remap_reg (svp64, value, opindex, vector);
+}
+
+static int64_t
+svp64_remap_fpr (struct svp64_ctx *svp64, int64_t value,
+    ppc_opindex_t opindex, bool vector)
+{
+  return svp64_remap_reg (svp64, value, opindex, vector);
+}
+
+static int64_t
+svp64_remap_cr (struct svp64_ctx *svp64, int64_t value,
+    ppc_opindex_t opindex, bool vector, bool cr_bit)
+{
+  uint32_t field;
+  uint32_t subfield;
+  uint32_t sv_extra;
+
+  svp64_raise_if (((value < 0) || (value > 127)),
+    "register does not fit the expected range 0..127");
+  field = (uint32_t)value;
+
+  if (cr_bit)
+    {
+      subfield = (field & 0x3);
+      field >>= 2;
+    }
+
+  if (vector)
+    {
+      /* cut into 3-bits 4-bits FFF SSSS but will cut 2 zeros off later */
+      sv_extra = (field & 0xf);
+      field >>= 4;
+    }
+  else
+    {
+      /* cut into 2-bits 3-bits SS FFF */
+      sv_extra = (field >> 3);
+      field &= 0x7;
+    }
+
+  if (svp64->desc->etype == SVP64_ETYPE_EXTRA2)
+    {
+      if (vector)
+        {
+          svp64_raise_if (((sv_extra & 0x7) != 0),
+            "vector CR cannot fit into EXTRA2");
+          sv_extra = (0x2 | (sv_extra >> 3));
+        }
+      else
+        {
+          svp64_raise_if (((sv_extra >> 1) != 0),
+            "scalar CR cannot fit into EXTRA2");
+          sv_extra &= 0x1;
+        }
+    }
+  else
+    {
+      if (vector)
+        {
+          svp64_raise_if (((sv_extra & 0x3) != 0),
+            "vector CR cannot fit into EXTRA3");
+          sv_extra = (0x4 | (sv_extra >> 2));
+        }
+      else
+        {
+          svp64_raise_if (((sv_extra >> 2) != 0),
+            "scalar CR cannot fit into EXTRA3");
+          sv_extra &= 0x3;
+        }
+    }
+
+  if (cr_bit)
+    field = ((field << 2) | subfield);
+
+  svp64_remap_extra (svp64, opindex, sv_extra);
+
+  return field;
+}
+
+static int64_t
+svp64_remap (struct svp64_ctx *ctx, int64_t value,
+    const struct powerpc_operand *operand, bool vector)
+{
+  const ppc_opindex_t opindex = (ppc_opindex_t)(operand - powerpc_operands);
+
+  if ((operand->flags & (PPC_OPERAND_GPR | PPC_OPERAND_GPR_0)) != 0)
+    return svp64_remap_gpr (ctx, value, opindex, vector);
+  else if ((operand->flags & PPC_OPERAND_FPR) != 0)
+    return svp64_remap_fpr (ctx, value, opindex, vector);
+  else if ((operand->flags & (PPC_OPERAND_CR_BIT | PPC_OPERAND_CR_REG)) != 0)
+    {
+      bool cr_bit = ((operand->flags & PPC_OPERAND_CR_BIT) != 0);
+
+      return svp64_remap_cr (ctx, value, opindex, vector, cr_bit);
+    }
+
+  return value;
+}
+
 static void
 svp64_assemble (char *str)
 {
@@ -925,5 +1094,17 @@ svp64_assemble (char *str)
   svp64_decode (str, &svp64);
   svp64_validate_and_fix (&svp64);
 
+  svp64_insn_set_prefix_PO (&svp64.insn, 0x1);
+  svp64_insn_set_prefix_id (&svp64.insn, 0x3);
+
+  svp64_insn_set_prefix_rm_mode (&svp64.insn, svp64.mode);
+  if (svp64.desc->ptype == SVP64_PTYPE_P2)
+    svp64_insn_set_prefix_rm_smask (&svp64.insn, svp64.smask);
+  svp64_insn_set_prefix_rm_mmode (&svp64.insn, svp64.mmode);
+  svp64_insn_set_prefix_rm_mask (&svp64.insn, svp64.pmask);
+  svp64_insn_set_prefix_rm_subvl (&svp64.insn, svp64.subvl);
+  svp64_insn_set_prefix_rm_ewsrc (&svp64.insn, svp64.srcwid);
+  svp64_insn_set_prefix_rm_elwidth (&svp64.insn, svp64.destwid);
+
   ppc_assemble (str, &svp64);
 }
index f6320dcca214ef47b62f4c1e30e2954cf65c3617..1900029f5e681f051169845e4d3d77712e37e45f 100644 (file)
@@ -3574,6 +3574,8 @@ ppc_assemble (char *str, struct svp64_ctx *svp64)
        as_bad (_("missing operand"));
       else if (ex.X_op == O_register)
        {
+         int64_t val = ex.X_add_number;
+
          if ((ex.X_md
               & ~operand->flags
               & (PPC_OPERAND_GPR | PPC_OPERAND_FPR | PPC_OPERAND_VR
@@ -3584,7 +3586,10 @@ ppc_assemble (char *str, struct svp64_ctx *svp64)
                   && ex.X_add_number != 0
                   && (operand->flags & PPC_OPERAND_GPR_0) != 0)))
            as_warn (_("invalid register expression"));
-         insn = ppc_insert_operand (insn, operand, ex.X_add_number,
+
+         if (svp64)
+           val = svp64_remap (svp64, val, operand, vector);
+         insn = ppc_insert_operand (insn, operand, val,
                                     ppc_cpu, (char *) NULL, 0);
        }
       else if (ex.X_op == O_constant
@@ -3690,6 +3695,8 @@ ppc_assemble (char *str, struct svp64_ctx *svp64)
                break;
              }
 #endif /* OBJ_ELF */
+         if (svp64)
+           val = svp64_remap (svp64, val, operand, vector);
          insn = ppc_insert_operand (insn, operand, val, ppc_cpu, NULL, 0);
        }
       else
@@ -4154,6 +4161,13 @@ ppc_assemble (char *str, struct svp64_ctx *svp64)
   if ((frag_now_fix () & addr_mask) != 0)
     as_bad (_("instruction address is not a multiple of %d"), addr_mask + 1);
 
+  /* Take care of SVP64 instructions. */
+  if (svp64)
+    {
+      svp64_insn_set_suffix (&svp64->insn, insn);
+      insn = svp64_insn_get (&svp64->insn);
+    }
+
   /* Differentiate between two, four, and eight byte insns.  */
   insn_length = 4;
   if ((ppc_cpu & PPC_OPCODE_VLE) != 0 && PPC_OP_SE_VLE (insn))