ppc/svp64: allow predicate macro expansion
authorDmitry Selyutin <ghostmansd@gmail.com>
Sun, 28 May 2023 22:04:56 +0000 (01:04 +0300)
committerDmitry Selyutin <ghostmansd@gmail.com>
Tue, 14 Nov 2023 19:53:35 +0000 (22:53 +0300)
gas/config/tc-ppc-svp64.c
gas/config/tc-ppc.c
gas/config/tc-ppc.h

index 84512ff59325d7cae58d11c0003de843cbbd06a1..8f0cd06b67dc28f8de547162b2fbc4482da36494 100644 (file)
@@ -61,6 +61,33 @@ struct svp64_ctx {
 #define SVP64_RC1_ACTIVE (1U << 3U)
 #define SVP64_RC1_INVERT (SVP64_RC1_ACTIVE | (1U << 4U))
 
+enum svp64_predicate {
+  /* Integer */
+  SVP64_PREDICATE_1BIT_R3,
+  SVP64_PREDICATE_R3,
+  SVP64_PREDICATE_R3_INV,
+  SVP64_PREDICATE_R10,
+  SVP64_PREDICATE_R10_INV,
+  SVP64_PREDICATE_R30,
+  SVP64_PREDICATE_R30_INV,
+  /* CR */
+  SVP64_PREDICATE_LT,
+  SVP64_PREDICATE_NL,
+  SVP64_PREDICATE_GE = SVP64_PREDICATE_NL,
+  SVP64_PREDICATE_GT,
+  SVP64_PREDICATE_NG,
+  SVP64_PREDICATE_LE = SVP64_PREDICATE_NG,
+  SVP64_PREDICATE_EQ,
+  SVP64_PREDICATE_NE,
+  SVP64_PREDICATE_SO,
+  SVP64_PREDICATE_UN = SVP64_PREDICATE_SO,
+  SVP64_PREDICATE_NS,
+  SVP64_PREDICATE_NU = SVP64_PREDICATE_NS,
+  /* RC1 */
+  SVP64_PREDICATE_RC1,
+  SVP64_PREDICATE_RC1_INV,
+};
+
 static void
 svp64_operand (expressionS *exp)
 {
@@ -99,16 +126,33 @@ svp64_operand (expressionS *exp)
     *origin = '*';
 }
 
-static void
-svp64_parse_name (const char *name, expressionS *exp, enum expr_mode mode)
+static inline void
+svp64_optimize_cr_cond (expressionS *exp)
 {
-  ppc_parse_name_common (name, exp, mode, svp64_regs, svp64_num_regs);
+  size_t i;
+  static const enum svp64_predicate table[] = {
+    SVP64_PREDICATE_LT,
+    SVP64_PREDICATE_GT,
+    SVP64_PREDICATE_EQ,
+    SVP64_PREDICATE_SO,
+  };
+
+  for (i = 0; i < sizeof (table) / sizeof (table[0]); ++i)
+    {
+      if (exp->X_add_number == table[i])
+       {
+         exp->X_op = O_register;
+         exp->X_add_number = (offsetT)i;
+         exp->X_md = PPC_OPERAND_CR_BIT;
+         return;
+       }
+    }
 }
 
 static bool
 svp64_special_expr (expressionS *exp)
 {
-  return (exp->X_op == O_vector);
+  return ((exp->X_op == O_vector) || (exp->X_op == O_predicate));
 }
 
 static jmp_buf svp64_exception;
@@ -164,7 +208,6 @@ svp64_expression (char *str, expressionS *exp)
     *str++ = '\0';
   str_tail = str;
   old_sep = *str;
-  *str = '\0';
   str = str_head;
   input_line_pointer = str;
 
@@ -177,49 +220,37 @@ svp64_expression (char *str, expressionS *exp)
   return ((exp->X_op == O_absent) ? str_head : str_tail);
 }
 
-struct svp64_predicate_map {
+struct svp64_predicate_cr_map {
   const char *str;
   unsigned int len : 3;
-  unsigned int cr : 1;
-  unsigned int mask : 3 + 2; /* 3-bit plus RC1 */
+  unsigned int id : 5;
 };
-#define SVP64_PREDICATE_MAP(STR, MODE, MASK) \
-  { STR, (sizeof (STR) - 1), MODE, MASK }
+#define SVP64_PREDICATE_CR_MAP(STR, ID) \
+  { STR, (sizeof (STR) - 1), ID }
 
-static char *
-svp64_decode_predicate (char *str, bool *cr, unsigned int *mask)
+static bool
+svp64_parse_predicate_cr (const char *name, expressionS *exp)
 {
   size_t i;
-  static const struct svp64_predicate_map table[] = {
-    /* integer */
-    SVP64_PREDICATE_MAP ("1<<r3", 0, 1),
-    SVP64_PREDICATE_MAP ("r3"   , 0, 2),
-    SVP64_PREDICATE_MAP ("~r3"  , 0, 3),
-    SVP64_PREDICATE_MAP ("r10"  , 0, 4),
-    SVP64_PREDICATE_MAP ("~r10" , 0, 5),
-    SVP64_PREDICATE_MAP ("r30"  , 0, 6),
-    SVP64_PREDICATE_MAP ("~r30" , 0, 7),
-    /* CR */
-    SVP64_PREDICATE_MAP ("lt"   , 1, 0),
-    SVP64_PREDICATE_MAP ("nl"   , 1, 1),
-    SVP64_PREDICATE_MAP ("ge"   , 1, 1), /* same value as nl */
-    SVP64_PREDICATE_MAP ("gt"   , 1, 2),
-    SVP64_PREDICATE_MAP ("ng"   , 1, 3),
-    SVP64_PREDICATE_MAP ("le"   , 1, 3), /* same value as ng */
-    SVP64_PREDICATE_MAP ("eq"   , 1, 4),
-    SVP64_PREDICATE_MAP ("ne"   , 1, 5),
-    SVP64_PREDICATE_MAP ("so"   , 1, 6),
-    SVP64_PREDICATE_MAP ("un"   , 1, 6), /* same value as so */
-    SVP64_PREDICATE_MAP ("ns"   , 1, 7),
-    SVP64_PREDICATE_MAP ("nu"   , 1, 7), /* same value as ns */
-    /* RC1 */
-    SVP64_PREDICATE_MAP ("RC1"  , 0, SVP64_RC1_ACTIVE),
-    SVP64_PREDICATE_MAP ("~RC1" , 0, SVP64_RC1_INVERT),
+  const char *str = name;
+  static const struct svp64_predicate_cr_map table[] = {
+    SVP64_PREDICATE_CR_MAP ("lt", SVP64_PREDICATE_LT),
+    SVP64_PREDICATE_CR_MAP ("nl", SVP64_PREDICATE_NL),
+    SVP64_PREDICATE_CR_MAP ("ge", SVP64_PREDICATE_GE),
+    SVP64_PREDICATE_CR_MAP ("gt", SVP64_PREDICATE_GT),
+    SVP64_PREDICATE_CR_MAP ("ng", SVP64_PREDICATE_NG),
+    SVP64_PREDICATE_CR_MAP ("le", SVP64_PREDICATE_LE),
+    SVP64_PREDICATE_CR_MAP ("eq", SVP64_PREDICATE_EQ),
+    SVP64_PREDICATE_CR_MAP ("ne", SVP64_PREDICATE_NE),
+    SVP64_PREDICATE_CR_MAP ("so", SVP64_PREDICATE_SO),
+    SVP64_PREDICATE_CR_MAP ("un", SVP64_PREDICATE_UN),
+    SVP64_PREDICATE_CR_MAP ("ns", SVP64_PREDICATE_NS),
+    SVP64_PREDICATE_CR_MAP ("nu", SVP64_PREDICATE_NU),
   };
 
   for (i = 0; i < sizeof (table) / sizeof (table[0]); ++i)
     {
-      const struct svp64_predicate_map *entry = &table[i];
+      const struct svp64_predicate_cr_map *entry = &table[i];
 
       if (strncmp (str, entry->str, entry->len) != 0)
         continue;
@@ -231,10 +262,112 @@ svp64_decode_predicate (char *str, bool *cr, unsigned int *mask)
           continue;
         }
 
-      *mask = entry->mask;
-      *cr = entry->cr;
+      exp->X_op = O_predicate;
+      exp->X_add_number = entry->id;
+
+      return true;
+    }
+
+  return false;
+}
+
+static bool
+svp64_parse_predicate_RC1 (const char *name, expressionS *exp)
+{
+  if (strcmp (name, "RC1") == 0)
+    {
+      exp->X_op = O_predicate;
+      exp->X_add_number = SVP64_PREDICATE_RC1;
+      return true;
+    }
+  else
+    return false;
+}
+
+static void
+svp64_parse_name (const char *name, expressionS *exp, enum expr_mode mode)
+{
+  exp->X_op = O_absent;
+  exp->X_op_symbol = NULL;
+  exp->X_add_symbol = NULL;
+
+  if ((svp64_parse_predicate_cr (name, exp)
+      || svp64_parse_predicate_RC1 (name, exp)) == 0)
+    ppc_parse_name_common (name, exp, mode, svp64_regs, svp64_num_regs);
+}
+
+static char *
+svp64_decode_predicate (char *str, bool *cr, unsigned int *mask)
+{
+  char *origin;
+  expressionS exp;
+
+  origin = str;
+  str = svp64_expression (str, &exp);
+  if (str != origin)
+    {
+      expressionS *sym_exp = NULL;
+      static const struct {
+       unsigned int cr : 1;
+       unsigned int mask : 3 + 2; /* 3-bit plus RC1 */
+      } table[] = {
+       /* SVP64_PREDICATE_1BIT_R3 */ {0, 1},
+       /* SVP64_PREDICATE_R3 */      {0, 2},
+       /* SVP64_PREDICATE_R3_INV */  {0, 3},
+       /* SVP64_PREDICATE_R10 */     {0, 4},
+       /* SVP64_PREDICATE_R10_INV */ {0, 5},
+       /* SVP64_PREDICATE_R30 */     {0, 6},
+       /* SVP64_PREDICATE_R30_INV */ {0, 7},
+       /* SVP64_PREDICATE_LT */      {1, 0},
+       /* SVP64_PREDICATE_NL */      {1, 1},
+       /* SVP64_PREDICATE_GT */      {1, 2},
+       /* SVP64_PREDICATE_NG */      {1, 3},
+       /* SVP64_PREDICATE_EQ */      {1, 4},
+       /* SVP64_PREDICATE_NE */      {1, 5},
+       /* SVP64_PREDICATE_SO */      {1, 6},
+       /* SVP64_PREDICATE_NS */      {1, 7},
+       /* {SVP64_PREDICATE_RC1*/     {0, SVP64_RC1_ACTIVE},
+       /* SVP64_PREDICATE_RC1_INV */ {0, SVP64_RC1_INVERT},
+      };
+      enum svp64_predicate predicate;
+
+      if (exp.X_add_symbol)
+       sym_exp = symbol_get_value_expression (exp.X_add_symbol);
+
+      if ((exp.X_op == O_register) &&
+           ((exp.X_add_number == 3)
+           || (exp.X_add_number == 10)
+           || (exp.X_add_number == 30)))
+       {
+         exp.X_op = O_predicate;
+         if (exp.X_add_number == 3)
+           exp.X_add_number = SVP64_PREDICATE_R3;
+         else if (exp.X_add_number == 10)
+           exp.X_add_number = SVP64_PREDICATE_R10;
+         else if (exp.X_add_number == 30)
+           exp.X_add_number = SVP64_PREDICATE_R30;
+       }
+      else if ((exp.X_op == O_bit_not) && (sym_exp != NULL))
+       {
+         if (sym_exp->X_op == O_register)
+           {
+             if (sym_exp->X_add_number == 3)
+               exp.X_add_number = SVP64_PREDICATE_R3_INV;
+             else if (sym_exp->X_add_number == 10)
+               exp.X_add_number = SVP64_PREDICATE_R10_INV;
+             else if (sym_exp->X_add_number == 30)
+               exp.X_add_number = SVP64_PREDICATE_R30_INV;
+           }
+         else if ((sym_exp->X_op == O_predicate)
+               && (sym_exp->X_add_number == SVP64_PREDICATE_RC1))
+           exp.X_add_number = SVP64_PREDICATE_RC1_INV;
+       }
+      else if (exp.X_op != O_predicate)
+       return NULL;
 
-      *str++ = '\0';
+      predicate = (enum svp64_predicate)exp.X_add_number;
+      *cr = (table[predicate].cr ? true : false);
+      *mask = table[predicate].mask;
 
       return str;
     }
index a0da2f6db39e0016c8be6e9132e61e28f29a4bae..06aff47890d07d98a2ff3e1d2720e2033d7c94b2 100644 (file)
@@ -971,6 +971,9 @@ ppc_resolve_symbol (symbolS *sym ATTRIBUTE_UNUSED,
     case O_vector:
       *seg = reg_section;
       break;
+    case O_predicate:
+      *seg = absolute_section;
+      break;
     default:
       abort ();
     }
@@ -980,7 +983,6 @@ ppc_resolve_symbol (symbolS *sym ATTRIBUTE_UNUSED,
 
 /* Propagate X_md and check register expressions.  This is to support
    condition codes like 4*cr5+eq.  */
-
 int
 ppc_optimize_expr (expressionS *left, operatorT op, expressionS *right)
 {
@@ -1003,13 +1005,17 @@ ppc_optimize_expr (expressionS *left, operatorT op, expressionS *right)
 
   /* Accept the above plus <cr bit>, and <cr bit> plus the above.  */
   if (op == O_add
-      && left->X_op == O_register
-      && right->X_op == O_register
+      && ((left->X_op == O_register) || (left->X_op == O_predicate))
+      && ((right->X_op == O_register) || (right->X_op == O_predicate))
       && ((right->X_md == PPC_OPERAND_CR_BIT
           && left->X_md == (PPC_OPERAND_CR_REG | PPC_OPERAND_CR_BIT))
          || (right->X_md == (PPC_OPERAND_CR_REG | PPC_OPERAND_CR_BIT)
-             && left->X_md == PPC_OPERAND_CR_BIT)))
+             && (left->X_md == PPC_OPERAND_CR_BIT || left->X_op == O_predicate))))
     {
+      if (left->X_op == O_predicate)
+       svp64_optimize_cr_cond (left);
+      if (right->X_op == O_predicate)
+       svp64_optimize_cr_cond (right);
       left->X_md = PPC_OPERAND_CR_BIT;
       right->X_op = O_constant;
       return 0;
@@ -1025,6 +1031,16 @@ ppc_optimize_expr (expressionS *left, operatorT op, expressionS *right)
     {
       if (op == O_add && left->X_op == O_constant)
        left->X_md = right->X_md;
+      else if ((ppc_cpu & PPC_OPCODE_SVP64)
+         && (op == O_left_shift)
+         && (left->X_op == O_constant)
+         && (left->X_add_number == 1)
+         && (right->X_add_number == 3)) /* 1<<r3 */
+       {
+         left->X_op = O_predicate;
+         left->X_add_number = SVP64_PREDICATE_1BIT_R3;
+         return 1;
+       }
       else
        as_warn (_("invalid register expression"));
     }
index fce6c98e0bae0e3fe95b2c129daa7a053164b850..4587802091418b5503c5b8ef6b02009036afb598 100644 (file)
@@ -368,6 +368,9 @@ extern int tc_ppc_regname_to_dw2regnum (char *);
  */
 #define O_vector O_md1
 
+/* Operand is a predicate to s/dm/sm/ff/pr modes. */
+#define O_predicate O_md2
+
 extern bool ppc_resolve_symbol (symbolS *sym, valueT *val, segT *seg);
 #define md_resolve_symbol ppc_resolve_symbol