Power10 bignum operands
authorAlan Modra <amodra@gmail.com>
Sun, 11 Apr 2021 23:32:46 +0000 (09:02 +0930)
committerAlan Modra <amodra@gmail.com>
Mon, 12 Apr 2021 02:27:03 +0000 (11:57 +0930)
When built on a 32-bit host without --enable-64-bit-bfd, powerpc-linux
and other 32-bit powerpc targeted binutils fail to assemble some
power10 prefixed instructions with 34-bit fields.  A typical error
seen when running the testsuite is
.../gas/testsuite/gas/ppc/prefix-pcrel.s:10: Error: bignum invalid
In practice this doesn't matter for addresses:  32-bit programs don't
need or use the top 2 bits of a d34 field when calculating addresses.
However it may matter when loading or adding 64-bit constants with
paddi.  A power10 processor in 32-bit mode still has 64-bit wide GPRs.
So this patch enables limited support for O_big PowerPC operands, and
corrects sign extension of 32-bit constants using X_extrabit.

* config/tc-ppc.c (insn_validate): Use uint64_t for operand values.
(md_assemble): Likewise.  Handle bignum operands.
(ppc_elf_suffix): Handle O_big.  Remove unnecessary input_line_pointer
check.
* expr.c: Delete unnecessary forward declarations.
(generic_bignum_to_int32): Return uint32_t.
(generic_bignum_to_int64): Return uint64_t.  Compile always.
(operand): Twiddle X_extrabit for unary '~'.  Set X_unsigned and
clear X_extrabit for unary '!'.
* expr.h (generic_bignum_to_int32): Declare.
(generic_bignum_to_int64): Declare.
* testsuite/gas/ppc/prefix-pcrel.s,
* testsuite/gas/ppc/prefix-pcrel.d: Add more instructions.

gas/ChangeLog
gas/config/tc-ppc.c
gas/expr.c
gas/expr.h
gas/testsuite/gas/ppc/prefix-pcrel.d
gas/testsuite/gas/ppc/prefix-pcrel.s

index 15e4c071929c00b4ad210da5acb5fa1007ec4988..1b1dafe92d4f500d26da46ff5eeb9bb8d8ae09fd 100644 (file)
@@ -1,3 +1,21 @@
+2021-04-12  Alan Modra  <amodra@gmail.com>
+
+       * config/tc-ppc.c (insn_validate): Use uint64_t for operand values.
+       (md_assemble): Likewise.  Handle bignum operands.
+       (ppc_elf_suffix): Handle O_big.  Remove unnecessary input_line_pointer
+       check.
+       * expr.c: Delete unnecessary forward declarations.
+       (generic_bignum_to_int32): Return uint32_t.
+       (generic_bignum_to_int64): Return uint64_t.  Compile always.
+       (operand): Twiddle X_extrabit for unary '~'.  Set X_unsigned and
+       clear X_extrabit for unary '!'.
+       * expr.h (generic_bignum_to_int32): Declare.
+       (generic_bignum_to_int64): Declare.
+       * testsuite/gas/ppc/prefix-pcrel.s,
+       * testsuite/gas/ppc/prefix-pcrel.d: Add more instructions.
+
+2021-04-09  Tejas Belagod  <tejas.belagod@arm.com>
+
 2021-04-12  Nelson Chu  <nelson.chu@sifive.com>
 
        * testsuite/gas/riscv/march-fail-order-x-std.d: Renamed from
 
 2021-04-09  Tejas Belagod  <tejas.belagod@arm.com>
 
-       * config/tc-aarch64.c (warn_unpredictable_ldst): Clean-up diagnostic messages
-       for LD/ST Exclusive instructions.
+       * config/tc-aarch64.c (warn_unpredictable_ldst): Clean-up
+       diagnostic messages for LD/ST Exclusive instructions.
        * testsuite/gas/aarch64/diagnostic.s: Add a diagnostic test for STLXP.
-       * testsuite/gas/aarch64/diagnostic.l: Fix-up test after message clean-up.
+       * testsuite/gas/aarch64/diagnostic.l: Fix-up test after message
+       clean-up.
 
 2021-04-09  Alan Modra  <amodra@gmail.com>
 
        well as Intel syntax tests.
        * testsuite/gas/i386/invlpgb.d, testsuite/gas/i386/snp.d: Adjust
        expectations.
-       * testsuite/gas/i386/invlpgb64.d, testsuite/gas/i386/snp64.d: 
+       * testsuite/gas/i386/invlpgb64.d, testsuite/gas/i386/snp64.d:
        Likewise. Drop passing --def-sym to as.
 
 2021-03-25  Jan Beulich  <jbeulich@suse.com>
 2021-02-12  Nick Clifton  <nickc@redhat.com>
 
        * testsuite/gas/mach-o/sections-1.d: Stop automatic debug link
-        following.
+       following.
        * testsuite/gas/xgate/insns-dwarf2.d: Likewise.
 
 2021-02-12  Alan Modra  <amodra@gmail.com>
index 5511e722108ba07995af3fcf40c2367e5bc069e6..c719b408b0eb59357f6d7e7022a9d041e181c318 100644 (file)
@@ -1574,7 +1574,7 @@ insn_validate (const struct powerpc_opcode *op)
          if (operand->shift == (int) PPC_OPSHIFT_INV)
            {
              const char *errmsg;
-             int64_t val;
+             uint64_t val;
 
              errmsg = NULL;
              val = -1;
@@ -2197,7 +2197,7 @@ ppc_elf_suffix (char **str_p, expressionS *exp_p)
       {
        int reloc = ptr->reloc;
 
-       if (!ppc_obj64 && exp_p->X_add_number != 0)
+       if (!ppc_obj64 && (exp_p->X_op == O_big || exp_p->X_add_number != 0))
          {
            switch (reloc)
              {
@@ -2238,14 +2238,12 @@ ppc_elf_suffix (char **str_p, expressionS *exp_p)
 
            input_line_pointer = str;
            expression (&new_exp);
-           if (new_exp.X_op == O_constant)
+           if (new_exp.X_op == O_constant && exp_p->X_op != O_big)
              {
                exp_p->X_add_number += new_exp.X_add_number;
                str = input_line_pointer;
              }
-
-           if (&input_line_pointer != str_p)
-             input_line_pointer = orig_line;
+           input_line_pointer = orig_line;
          }
        *str_p = str;
 
@@ -3397,8 +3395,8 @@ md_assemble (char *str)
            }
          if (--num_optional_provided < 0)
            {
-             int64_t val = ppc_optional_operand_value (operand, insn, ppc_cpu,
-                                                       num_optional_provided);
+             uint64_t val = ppc_optional_operand_value (operand, insn, ppc_cpu,
+                                                        num_optional_provided);
              if (operand->insert)
                {
                  insn = (*operand->insert) (insn, val, ppc_cpu, &errmsg);
@@ -3459,14 +3457,32 @@ md_assemble (char *str)
          insn = ppc_insert_operand (insn, operand, ex.X_add_number,
                                     ppc_cpu, (char *) NULL, 0);
        }
-      else if (ex.X_op == O_constant)
+      else if (ex.X_op == O_constant
+              || (ex.X_op == O_big && ex.X_add_number > 0))
        {
+         uint64_t val;
+         if (ex.X_op == O_constant)
+           {
+             val = ex.X_add_number;
+             if (sizeof (ex.X_add_number) < sizeof (val)
+                 && (ex.X_add_number < 0) != ex.X_extrabit)
+               val = val ^ ((addressT) -1 ^ (uint64_t) -1);
+           }
+         else
+           val = generic_bignum_to_int64 ();
 #ifdef OBJ_ELF
          /* Allow @HA, @L, @H on constants.  */
-         bfd_reloc_code_real_type reloc;
          char *orig_str = str;
+         bfd_reloc_code_real_type reloc = ppc_elf_suffix (&str, &ex);
 
-         if ((reloc = ppc_elf_suffix (&str, &ex)) != BFD_RELOC_NONE)
+         if (ex.X_op == O_constant)
+           {
+             val = ex.X_add_number;
+             if (sizeof (ex.X_add_number) < sizeof (val)
+                 && (ex.X_add_number < 0) != ex.X_extrabit)
+               val = val ^ ((addressT) -1 ^ (uint64_t) -1);
+           }
+         if (reloc != BFD_RELOC_NONE)
            switch (reloc)
              {
              default:
@@ -3474,81 +3490,77 @@ md_assemble (char *str)
                break;
 
              case BFD_RELOC_LO16:
-               ex.X_add_number &= 0xffff;
+               val &= 0xffff;
                if ((operand->flags & PPC_OPERAND_SIGNED) != 0)
-                 ex.X_add_number = SEX16 (ex.X_add_number);
+                 val = SEX16 (val);
                break;
 
              case BFD_RELOC_HI16:
                if (REPORT_OVERFLOW_HI && ppc_obj64)
                  {
                    /* PowerPC64 @h is tested for overflow.  */
-                   ex.X_add_number = (addressT) ex.X_add_number >> 16;
+                   val = val >> 16;
                    if ((operand->flags & PPC_OPERAND_SIGNED) != 0)
                      {
-                       addressT sign = (((addressT) -1 >> 16) + 1) >> 1;
-                       ex.X_add_number
-                         = ((addressT) ex.X_add_number ^ sign) - sign;
+                       uint64_t sign = (((uint64_t) -1 >> 16) + 1) >> 1;
+                       val = (val ^ sign) - sign;
                      }
                    break;
                  }
                /* Fallthru */
 
              case BFD_RELOC_PPC64_ADDR16_HIGH:
-               ex.X_add_number = PPC_HI (ex.X_add_number);
+               val = PPC_HI (val);
                if ((operand->flags & PPC_OPERAND_SIGNED) != 0)
-                 ex.X_add_number = SEX16 (ex.X_add_number);
+                 val = SEX16 (val);
                break;
 
              case BFD_RELOC_HI16_S:
                if (REPORT_OVERFLOW_HI && ppc_obj64)
                  {
                    /* PowerPC64 @ha is tested for overflow.  */
-                   ex.X_add_number
-                     = ((addressT) ex.X_add_number + 0x8000) >> 16;
+                   val = (val + 0x8000) >> 16;
                    if ((operand->flags & PPC_OPERAND_SIGNED) != 0)
                      {
-                       addressT sign = (((addressT) -1 >> 16) + 1) >> 1;
-                       ex.X_add_number
-                         = ((addressT) ex.X_add_number ^ sign) - sign;
+                       uint64_t sign = (((uint64_t) -1 >> 16) + 1) >> 1;
+                       val = (val ^ sign) - sign;
                      }
                    break;
                  }
                /* Fallthru */
 
              case BFD_RELOC_PPC64_ADDR16_HIGHA:
-               ex.X_add_number = PPC_HA (ex.X_add_number);
+               val = PPC_HA (val);
                if ((operand->flags & PPC_OPERAND_SIGNED) != 0)
-                 ex.X_add_number = SEX16 (ex.X_add_number);
+                 val = SEX16 (val);
                break;
 
              case BFD_RELOC_PPC64_HIGHER:
-               ex.X_add_number = PPC_HIGHER (ex.X_add_number);
+               val = PPC_HIGHER (val);
                if ((operand->flags & PPC_OPERAND_SIGNED) != 0)
-                 ex.X_add_number = SEX16 (ex.X_add_number);
+                 val = SEX16 (val);
                break;
 
              case BFD_RELOC_PPC64_HIGHER_S:
-               ex.X_add_number = PPC_HIGHERA (ex.X_add_number);
+               val = PPC_HIGHERA (val);
                if ((operand->flags & PPC_OPERAND_SIGNED) != 0)
-                 ex.X_add_number = SEX16 (ex.X_add_number);
+                 val = SEX16 (val);
                break;
 
              case BFD_RELOC_PPC64_HIGHEST:
-               ex.X_add_number = PPC_HIGHEST (ex.X_add_number);
+               val = PPC_HIGHEST (val);
                if ((operand->flags & PPC_OPERAND_SIGNED) != 0)
-                 ex.X_add_number = SEX16 (ex.X_add_number);
+                 val = SEX16 (val);
                break;
 
              case BFD_RELOC_PPC64_HIGHEST_S:
-               ex.X_add_number = PPC_HIGHESTA (ex.X_add_number);
+               val = PPC_HIGHESTA (val);
                if ((operand->flags & PPC_OPERAND_SIGNED) != 0)
-                 ex.X_add_number = SEX16 (ex.X_add_number);
+                 val = SEX16 (val);
                break;
              }
 #endif /* OBJ_ELF */
-         insn = ppc_insert_operand (insn, operand, ex.X_add_number,
-                                    ppc_cpu, (char *) NULL, 0);
+         insn = ppc_insert_operand (insn, operand, val, ppc_cpu, NULL, 0);
        }
       else
        {
index aabd33c84f9c4ac1c9e82dffd4b969faeaf2cd0b..afd065c23be3a4c0f6dcc3e712acdb5abbce60b6 100644 (file)
 
 bool literal_prefix_dollar_hex = false;
 
-static void floating_constant (expressionS * expressionP);
-static valueT generic_bignum_to_int32 (void);
-#ifdef BFD64
-static valueT generic_bignum_to_int64 (void);
-#endif
-static void integer_constant (int radix, expressionS * expressionP);
-static void mri_char_constant (expressionS *);
 static void clean_up_expression (expressionS * expressionP);
-static segT operand (expressionS *, enum expr_mode);
-static operatorT operatorf (int *);
 
 /* We keep a mapping of expression symbols to file positions, so that
    we can provide better error messages.  */
@@ -218,31 +209,25 @@ floating_constant (expressionS *expressionP)
   expressionP->X_add_number = -1;
 }
 
-static valueT
+uint32_t
 generic_bignum_to_int32 (void)
 {
-  valueT number =
-    ((((valueT) generic_bignum[1] & LITTLENUM_MASK) << LITTLENUM_NUMBER_OF_BITS)
-     | ((valueT) generic_bignum[0] & LITTLENUM_MASK));
-  number &= 0xffffffff;
-  return number;
+  return ((((uint32_t) generic_bignum[1] & LITTLENUM_MASK)
+          << LITTLENUM_NUMBER_OF_BITS)
+         | ((uint32_t) generic_bignum[0] & LITTLENUM_MASK));
 }
 
-#ifdef BFD64
-static valueT
+uint64_t
 generic_bignum_to_int64 (void)
 {
-  valueT number =
-    ((((((((valueT) generic_bignum[3] & LITTLENUM_MASK)
-         << LITTLENUM_NUMBER_OF_BITS)
-        | ((valueT) generic_bignum[2] & LITTLENUM_MASK))
-       << LITTLENUM_NUMBER_OF_BITS)
-       | ((valueT) generic_bignum[1] & LITTLENUM_MASK))
-      << LITTLENUM_NUMBER_OF_BITS)
-     | ((valueT) generic_bignum[0] & LITTLENUM_MASK));
-  return number;
+  return ((((((((uint64_t) generic_bignum[3] & LITTLENUM_MASK)
+              << LITTLENUM_NUMBER_OF_BITS)
+             | ((uint64_t) generic_bignum[2] & LITTLENUM_MASK))
+            << LITTLENUM_NUMBER_OF_BITS)
+           | ((uint64_t) generic_bignum[1] & LITTLENUM_MASK))
+          << LITTLENUM_NUMBER_OF_BITS)
+         | ((uint64_t) generic_bignum[0] & LITTLENUM_MASK));
 }
-#endif
 
 static void
 integer_constant (int radix, expressionS *expressionP)
@@ -1031,9 +1016,16 @@ operand (expressionS *expressionP, enum expr_mode mode)
                  expressionP->X_extrabit ^= 1;
              }
            else if (c == '~' || c == '"')
-             expressionP->X_add_number = ~ expressionP->X_add_number;
+             {
+               expressionP->X_add_number = ~ expressionP->X_add_number;
+               expressionP->X_extrabit ^= 1;
+             }
            else if (c == '!')
-             expressionP->X_add_number = ! expressionP->X_add_number;
+             {
+               expressionP->X_add_number = ! expressionP->X_add_number;
+               expressionP->X_unsigned = 1;
+               expressionP->X_extrabit = 0;
+             }
          }
        else if (expressionP->X_op == O_big
                 && expressionP->X_add_number <= 0
index 5537039edd626894dc42acb97af67133eb00aa5f..e8707127362e65f31a856d39bcdf09c5307c16f7 100644 (file)
@@ -185,6 +185,8 @@ extern void current_location (expressionS *);
 
 extern symbolS *expr_build_uconstant (offsetT);
 extern symbolS *expr_build_dot (void);
+extern uint32_t generic_bignum_to_int32 (void);
+extern uint64_t generic_bignum_to_int64 (void);
 
 int resolve_expression (expressionS *);
 
index 0d10424ea544e660b6bedf585566252f188bbb80..6807d3b2ba64747935fe9faf028b683c7e5f5581 100644 (file)
@@ -232,4 +232,22 @@ Disassembly of section \.text:
 .*:    (df eb 00 60|60 00 eb df) 
 .*:    (04 10 00 00|00 00 10 04)       pstxv   vs63,96 # 3d8
 .*:    (df e0 00 60|60 00 e0 df) 
+.*:    (06 00 7f ff|ff 7f 00 06)       pli     r1,2147483647
+.*:    (38 20 ff ff|ff ff 20 38) 
+.*:    (06 00 80 00|00 80 00 06)       pli     r2,2147483648
+.*:    (38 40 00 00|00 00 40 38) 
+.*:    (06 00 ff ff|ff ff 00 06)       pli     r3,4294967295
+.*:    (38 60 ff ff|ff ff 60 38) 
+.*:    (06 00 00 00|00 00 00 06)       pli     r4,0
+.*:    (38 80 00 00|00 00 80 38) 
+.*:    (06 03 ff ff|ff ff 03 06)       pli     r5,-1
+.*:    (38 a0 ff ff|ff ff a0 38) 
+.*:    (06 03 80 00|00 80 03 06)       pli     r6,-2147483647
+.*:    (38 c0 00 01|01 00 c0 38) 
+.*:    (06 03 80 00|00 80 03 06)       pli     r7,-2147483648
+.*:    (38 e0 00 00|00 00 e0 38) 
+.*:    (06 03 80 00|00 80 03 06)       pli     r8,-2147483648
+.*:    (39 00 00 00|00 00 00 39) 
+.*:    (06 03 7f ff|ff 7f 03 06)       pli     r9,-2147483649
+.*:    (39 20 ff ff|ff ff 20 39) 
 #pass
index c3831d8a2c350afee7939d262da9fa30676bc8e7..32f04b109c2b29163e9d439e7ebd0971d01b54fa 100644 (file)
@@ -119,3 +119,14 @@ prefix:
        pstxv   13,96(0),1
        pstxv   63,96(11),0
        pstxv   63,96(0),1
+
+# test d34 values of interest when bfd_vma is 32-bit
+       pli     1,0x7fffffff
+       pli     2,0x80000000
+       pli     3,0xffffffff
+       pli     4,0
+       pli     5,-1
+       pli     6,-0x7fffffff
+       pli     7,-0x80000000
+       pli     8,~0x7fffffff
+       pli     9,~0x80000000