From: Alan Modra Date: Sun, 11 Apr 2021 23:32:46 +0000 (+0930) Subject: Power10 bignum operands X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=32d715691aa037f2838b41fa257c2e239d67c134;p=binutils-gdb.git 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. --- diff --git a/gas/ChangeLog b/gas/ChangeLog index 15e4c071929..1b1dafe92d4 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,21 @@ +2021-04-12 Alan Modra + + * 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 + 2021-04-12 Nelson Chu * testsuite/gas/riscv/march-fail-order-x-std.d: Renamed from @@ -28,10 +46,11 @@ 2021-04-09 Tejas Belagod - * 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 @@ -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 @@ -885,7 +904,7 @@ 2021-02-12 Nick Clifton * 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 diff --git a/gas/config/tc-ppc.c b/gas/config/tc-ppc.c index 5511e722108..c719b408b0e 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 aabd33c84f9..afd065c23be 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 5537039edd6..e8707127362 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 0d10424ea54..6807d3b2ba6 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 c3831d8a2c3..32f04b109c2 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