diff options
author | Alan Modra <amodra@gmail.com> | 2021-04-12 09:02:46 +0930 |
---|---|---|
committer | Alan Modra <amodra@gmail.com> | 2021-04-12 11:57:03 +0930 |
commit | 32d715691aa037f2838b41fa257c2e239d67c134 (patch) | |
tree | 15950d786cf30650203914068f191717acacae46 | |
parent | fc304b889106f6d1bd720e969b95615992bf1961 (diff) | |
download | fsf-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/ChangeLog | 29 | ||||
-rw-r--r-- | gas/config/tc-ppc.c | 84 | ||||
-rw-r--r-- | gas/expr.c | 50 | ||||
-rw-r--r-- | gas/expr.h | 2 | ||||
-rw-r--r-- | gas/testsuite/gas/ppc/prefix-pcrel.d | 18 | ||||
-rw-r--r-- | gas/testsuite/gas/ppc/prefix-pcrel.s | 11 |
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 { @@ -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 @@ -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 |