aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlan Modra <amodra@gmail.com>2021-04-12 09:02:46 +0930
committerAlan Modra <amodra@gmail.com>2021-04-12 11:57:03 +0930
commit32d715691aa037f2838b41fa257c2e239d67c134 (patch)
tree15950d786cf30650203914068f191717acacae46
parentfc304b889106f6d1bd720e969b95615992bf1961 (diff)
downloadfsf-binutils-gdb-32d715691aa037f2838b41fa257c2e239d67c134.zip
fsf-binutils-gdb-32d715691aa037f2838b41fa257c2e239d67c134.tar.gz
fsf-binutils-gdb-32d715691aa037f2838b41fa257c2e239d67c134.tar.bz2
Power10 bignum operands
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.
-rw-r--r--gas/ChangeLog29
-rw-r--r--gas/config/tc-ppc.c84
-rw-r--r--gas/expr.c50
-rw-r--r--gas/expr.h2
-rw-r--r--gas/testsuite/gas/ppc/prefix-pcrel.d18
-rw-r--r--gas/testsuite/gas/ppc/prefix-pcrel.s11
6 files changed, 124 insertions, 70 deletions
diff --git a/gas/ChangeLog b/gas/ChangeLog
index 15e4c07..1b1dafe 100644
--- a/gas/ChangeLog
+++ b/gas/ChangeLog
@@ -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
@@ -28,10 +46,11 @@
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>
@@ -522,7 +541,7 @@
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>
@@ -885,7 +904,7 @@
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>
diff --git a/gas/config/tc-ppc.c b/gas/config/tc-ppc.c
index 5511e72..c719b40 100644
--- a/gas/config/tc-ppc.c
+++ b/gas/config/tc-ppc.c
@@ -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
{
diff --git a/gas/expr.c b/gas/expr.c
index aabd33c..afd065c 100644
--- a/gas/expr.c
+++ b/gas/expr.c
@@ -35,16 +35,7 @@
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
diff --git a/gas/expr.h b/gas/expr.h
index 5537039..e870712 100644
--- a/gas/expr.h
+++ b/gas/expr.h
@@ -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 *);
diff --git a/gas/testsuite/gas/ppc/prefix-pcrel.d b/gas/testsuite/gas/ppc/prefix-pcrel.d
index 0d10424..6807d3b 100644
--- a/gas/testsuite/gas/ppc/prefix-pcrel.d
+++ b/gas/testsuite/gas/ppc/prefix-pcrel.d
@@ -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
diff --git a/gas/testsuite/gas/ppc/prefix-pcrel.s b/gas/testsuite/gas/ppc/prefix-pcrel.s
index c3831d8..32f04b1 100644
--- a/gas/testsuite/gas/ppc/prefix-pcrel.s
+++ b/gas/testsuite/gas/ppc/prefix-pcrel.s
@@ -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