ppc/svp64: remap operands and build instructions
authorDmitry Selyutin <ghostmansd@gmail.com>
Tue, 5 Jul 2022 19:30:40 +0000 (22:30 +0300)
committerDmitry Selyutin <ghostmansd@gmail.com>
Fri, 23 Sep 2022 17:11:54 +0000 (20:11 +0300)
gas/config/tc-ppc-svp64.c
gas/config/tc-ppc.c

index 158f1efa01d07fada5623241656e7506bcafb271..f22ba455a638e194e6b626dc597e55cd11515c4c 100644 (file)
@@ -23,6 +23,7 @@
 
 struct svp64_ctx {
   const struct svp64_desc *desc;
+  struct svp64_insn insn;
   unsigned int pmmode : 1;
   unsigned int pmask : 3;
   unsigned int smmode : 1;
@@ -1060,6 +1061,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)
 {
@@ -1073,5 +1242,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 9f688b6e9a5b7b9275d66a44bac0362dd0a496cf..585128d8235398116ff25d936d39cac52133eba7 100644 (file)
@@ -3550,6 +3550,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
@@ -3559,7 +3561,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
@@ -3665,6 +3670,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
@@ -4129,12 +4136,18 @@ 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))
     insn_length = 2;
-  else if ((opcode->flags & PPC_OPCODE_POWER10) != 0
-          && PPC_PREFIX_P (insn))
+  else if ((svp64 || ((opcode->flags & PPC_OPCODE_POWER10) != 0)) && PPC_PREFIX_P (insn))
     {
       struct insn_label_list *l;