ppc/svp64: support SVP64 vectors
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
gas/config/tc-ppc.c
gas/config/tc-ppc.h

index bf8c0c947b7165be05648127416a356da22315fa..b6dd549e7f166fbb32de59466047632115e48836 100644 (file)
@@ -60,6 +60,56 @@ struct svp64_ctx {
 #define SVP64_RC1_ACTIVE (1U << 3U)
 #define SVP64_RC1_INVERT (SVP64_RC1_ACTIVE | (1U << 4U))
 
+static void
+svp64_operand (expressionS *exp)
+{
+  bool vector = false;
+  bool compat = false;
+  char *origin = input_line_pointer;
+
+  if (input_line_pointer[0] == '*')
+    {
+      vector = true;
+      if (ISDIGIT (input_line_pointer[1]))
+       {
+         input_line_pointer[0] = 'r';
+         compat = true;
+       }
+      else
+       ++input_line_pointer;
+    }
+
+  if (!vector && !compat && !reg_names_p &&
+      (input_line_pointer[0] != '%' || !ISALPHA (input_line_pointer[1])))
+    return;
+
+  if (!compat && (*input_line_pointer == '%'))
+    ++input_line_pointer;
+
+  ppc_operand_common (exp, svp64_regs, svp64_num_regs);
+
+  if (exp->X_op == O_absent)
+    input_line_pointer = origin;
+  else if (vector &&
+      ((exp->X_op == O_register) || (exp->X_op == O_constant)))
+    exp->X_op = O_vector;
+
+  if (compat)
+    *origin = '*';
+}
+
+static void
+svp64_parse_name (const char *name, expressionS *exp, enum expr_mode mode)
+{
+  ppc_parse_name_common (name, exp, mode, svp64_regs, svp64_num_regs);
+}
+
+static bool
+svp64_special_expr (expressionS *exp)
+{
+  return (exp->X_op == O_vector);
+}
+
 static jmp_buf svp64_exception;
 
 #define svp64_raise(...)                \
index 8bf7e6bc25d47bd687e401fc9df1a5dd9ee15153..f6320dcca214ef47b62f4c1e30e2954cf65c3617 100644 (file)
 struct svp64_ctx;
 
 static void
-ppc_assemble (char *str, struct svp64_ctx *svp64 ATTRIBUTE_UNUSED);
+ppc_assemble (char *str, struct svp64_ctx *svp64);
+
+static bool reg_names_p;
+
+static void
+ppc_operand_common (expressionS *expressionP,
+    const struct powerpc_pd_reg *regs, size_t num);
+
+static void
+ppc_parse_name_common (const char *name,
+    expressionS *exp, enum expr_mode mode,
+    const struct powerpc_pd_reg *regs, size_t num);
 
 #include "tc-ppc-svp64.c"
 
@@ -824,13 +835,30 @@ reg_name_search (const struct powerpc_pd_reg *regs, int regcount, const char *na
 
 /* Called for a non-symbol, non-number operand.  Handles %reg.  */
 
-void
-md_operand (expressionS *expressionP)
+static void
+ppc_operand_common (expressionS *expressionP,
+    const struct powerpc_pd_reg *regs, size_t num)
 {
-  const struct powerpc_pd_reg *reg;
+  char endc;
   char *name;
+  const struct powerpc_pd_reg *reg;
+
+  endc = get_symbol_name (&name);
+  reg = reg_name_search (regs, num, name);
+  restore_line_pointer (endc);
+
+  if (reg != NULL)
+    {
+      expressionP->X_op = O_register;
+      expressionP->X_add_number = reg->value;
+      expressionP->X_md = reg->flags;
+    }
+}
+
+static void
+ppc_operand_default (expressionS *exp)
+{
   char *start;
-  char c;
 
   if (input_line_pointer[0] != '%' || !ISALPHA (input_line_pointer[1]))
     return;
@@ -838,21 +866,17 @@ md_operand (expressionS *expressionP)
   start = input_line_pointer;
   ++input_line_pointer;
 
-  c = get_symbol_name (&name);
-  reg = reg_name_search (pre_defined_registers,
-                        ARRAY_SIZE (pre_defined_registers), name);
-  *input_line_pointer = c;
+  ppc_operand_common (exp,
+    pre_defined_registers,
+    ARRAY_SIZE (pre_defined_registers));
 
-  if (reg != NULL)
-    {
-      expressionP->X_op = O_register;
-      expressionP->X_add_number = reg->value;
-      expressionP->X_md = reg->flags;
-    }
-  else
+  if (exp->X_op == O_absent)
     input_line_pointer = start;
 }
 
+void
+(*ppc_operand) (expressionS *expressionP) = ppc_operand_default;
+
 /* Whether to do the special parsing.  */
 static bool cr_operand;
 
@@ -871,16 +895,17 @@ static const struct powerpc_pd_reg cr_cond[] =
    to use for condition codes, and recognises other registers when
    -mregnames.  */
 
-void
-ppc_parse_name (const char *name, expressionS *exp, enum expr_mode mode)
+static void
+ppc_parse_name_common (const char *name,
+    expressionS *exp, enum expr_mode mode,
+    const struct powerpc_pd_reg *regs, size_t num)
 {
   const struct powerpc_pd_reg *reg = NULL;
 
   if (cr_operand)
     reg = reg_name_search (cr_cond, ARRAY_SIZE (cr_cond), name);
   if (reg == NULL && (cr_operand || reg_names_p))
-    reg = reg_name_search (pre_defined_registers,
-                          ARRAY_SIZE (pre_defined_registers), name);
+    reg = reg_name_search (regs, num, name);
   if (reg != NULL)
     {
       exp->X_op = O_register;
@@ -904,11 +929,15 @@ ppc_parse_name (const char *name, expressionS *exp, enum expr_mode mode)
   if (mode != expr_defer
       && !S_FORCE_RELOC (sym, 0))
     {
-      segT segment = S_GET_SEGMENT (sym);
-      if (segment == absolute_section || segment == reg_section)
+      segT sym_seg = S_GET_SEGMENT (sym);
+      expressionS *sym_exp = symbol_get_value_expression (sym);
+
+      if ((sym_seg == absolute_section)
+         || (sym_seg == reg_section)
+         || (((ppc_cpu & PPC_OPCODE_SVP64) != 0) && svp64_special_expr (sym_exp)))
        {
          resolve_symbol_value (sym);
-         *exp = *symbol_get_value_expression (sym);
+         *exp = *sym_exp;
          done = true;
        }
     }
@@ -920,6 +949,32 @@ ppc_parse_name (const char *name, expressionS *exp, enum expr_mode mode)
     }
 }
 
+static void
+ppc_parse_name_default (const char *name, expressionS *exp, enum expr_mode mode)
+{
+  ppc_parse_name_common (name, exp, mode,
+    pre_defined_registers, ARRAY_SIZE (pre_defined_registers));
+}
+
+void
+(*ppc_parse_name) (const char *name, expressionS *exp, enum expr_mode mode) = ppc_parse_name_default;
+
+bool
+ppc_resolve_symbol (symbolS *sym ATTRIBUTE_UNUSED,
+    valueT *val ATTRIBUTE_UNUSED, segT *seg)
+{
+  switch (symbol_get_value_expression (sym)->X_op)
+    {
+    case O_vector:
+      *seg = reg_section;
+      break;
+    default:
+      abort ();
+    }
+
+  return true;
+}
+
 /* Propagate X_md and check register expressions.  This is to support
    condition codes like 4*cr5+eq.  */
 
@@ -1892,6 +1947,11 @@ md_begin (void)
 
   ppc_cie_data_alignment = ppc_obj64 ? -8 : -4;
   ppc_dwarf2_line_min_insn_length = (ppc_cpu & PPC_OPCODE_VLE) ? 2 : 4;
+  if (ppc_cpu & PPC_OPCODE_SVP64)
+    {
+      ppc_parse_name = svp64_parse_name;
+      ppc_operand = svp64_operand;
+    }
 
 #ifdef OBJ_ELF
   /* Set the ELF flags if desired.  */
@@ -3320,7 +3380,7 @@ is_svp64_insn (char *str)
 /* This routine is called for each instruction to be assembled.  */
 
 static void
-ppc_assemble (char *str, struct svp64_ctx *svp64 ATTRIBUTE_UNUSED)
+ppc_assemble (char *str, struct svp64_ctx *svp64)
 {
   char *s;
   const struct powerpc_opcode *opcode;
@@ -3407,6 +3467,7 @@ ppc_assemble (char *str, struct svp64_ctx *svp64 ATTRIBUTE_UNUSED)
   fc = 0;
   for (opindex_ptr = opcode->operands; *opindex_ptr != 0; opindex_ptr++)
     {
+      bool vector;
       const struct powerpc_operand *operand;
       const char *errmsg;
       char *hold;
@@ -3490,6 +3551,7 @@ ppc_assemble (char *str, struct svp64_ctx *svp64 ATTRIBUTE_UNUSED)
       input_line_pointer = str;
       cr_operand = ((operand->flags & PPC_OPERAND_CR_BIT) != 0
                    || (operand->flags & PPC_OPERAND_CR_REG) != 0);
+      memset (&ex, 0, sizeof (ex));
       expression (&ex);
       cr_operand = false;
       str = input_line_pointer;
@@ -3497,6 +3559,15 @@ ppc_assemble (char *str, struct svp64_ctx *svp64 ATTRIBUTE_UNUSED)
 
       resolve_register (&ex);
 
+      vector = false;
+      if (ex.X_op == O_vector)
+       {
+         if (!svp64)
+           as_bad (_("vector operand not supported"));
+         ex.X_op = O_register;
+         vector = true;
+       }
+
       if (ex.X_op == O_illegal)
        as_bad (_("illegal operand"));
       else if (ex.X_op == O_absent)
@@ -3509,9 +3580,9 @@ ppc_assemble (char *str, struct svp64_ctx *svp64 ATTRIBUTE_UNUSED)
                  | PPC_OPERAND_VSR | PPC_OPERAND_CR_BIT | PPC_OPERAND_CR_REG
                  | PPC_OPERAND_SPR | PPC_OPERAND_GQR | PPC_OPERAND_ACC
                  | PPC_OPERAND_DMR)) != 0
-             && !((ex.X_md & PPC_OPERAND_GPR) != 0
+             && !(vector || ((ex.X_md & PPC_OPERAND_GPR) != 0
                   && ex.X_add_number != 0
-                  && (operand->flags & PPC_OPERAND_GPR_0) != 0))
+                  && (operand->flags & PPC_OPERAND_GPR_0) != 0)))
            as_warn (_("invalid register expression"));
          insn = ppc_insert_operand (insn, operand, ex.X_add_number,
                                     ppc_cpu, (char *) NULL, 0);
index 4d71c9ff1f161d66508894dbccc9341141b88b89..9474d9adc9ea592e3ede3ca34ba67681bc88cebf 100644 (file)
@@ -322,9 +322,12 @@ extern void ppc_frob_label (symbolS *);
 /* call md_pcrel_from_section, not md_pcrel_from */
 #define MD_PCREL_FROM_SECTION(FIX, SEC) md_pcrel_from_section(FIX, SEC)
 
+#define md_operand(EXP) ppc_operand (EXP)
+extern void (*ppc_operand) (expressionS *exp);
+
 #define md_parse_name(name, exp, mode, c) \
-  (ppc_parse_name (name, exp, mode), true)
-extern void ppc_parse_name (const char *, struct expressionS *, enum expr_mode);
+  ((*ppc_parse_name) (name, exp, mode), true)
+extern void (*ppc_parse_name) (const char *, struct expressionS *, enum expr_mode);
 
 #define md_optimize_expr(left, op, right) ppc_optimize_expr (left, op, right)
 extern int ppc_optimize_expr (expressionS *, operatorT, expressionS *);
@@ -359,6 +362,15 @@ extern void ppc_cfi_frame_initial_instructions (void);
 #define tc_regname_to_dw2regnum tc_ppc_regname_to_dw2regnum
 extern int tc_ppc_regname_to_dw2regnum (char *);
 
+/*
+ * A hint that the operand refers to a vector, like *%r102 or *%f.15.
+ * Such operand is converted to a usual O_register after it's remapped.
+ */
+#define O_vector O_md1
+
+extern bool ppc_resolve_symbol (symbolS *sym, valueT *val, segT *seg);
+#define md_resolve_symbol ppc_resolve_symbol
+
 extern int ppc_cie_data_alignment;
 
 extern int ppc_dwarf2_line_min_insn_length;