------- Comment #31 from jakub at gcc dot gnu dot org 2008-05-09 14:18 ------- Alternate patch to #c12 that doesn't touch at all rs6000_legitimate_address, just changes print_operand_address:
--- gcc/config/rs6000/rs6000.c.jj 2008-04-24 18:30:39.000000000 +0200 +++ gcc/config/rs6000/rs6000.c 2008-05-09 16:10:24.000000000 +0200 @@ -723,6 +723,7 @@ static unsigned rs6000_hash_constant (rt static unsigned toc_hash_function (const void *); static int toc_hash_eq (const void *, const void *); static int constant_pool_expr_1 (rtx, int *, int *); +static int find_constant_pool_expr (rtx *, rtx **, rtx **); static bool constant_pool_expr_p (rtx); static bool legitimate_small_data_p (enum machine_mode, rtx); static bool legitimate_lo_sum_address_p (enum machine_mode, rtx, int); @@ -3335,6 +3336,44 @@ constant_pool_expr_1 (rtx op, int *have_ } } +static int +find_constant_pool_expr (rtx *op, rtx **sym, rtx **toc) +{ + switch (GET_CODE (*op)) + { + case SYMBOL_REF: + if (RS6000_SYMBOL_REF_TLS_P (*op)) + return 0; + else if (CONSTANT_POOL_ADDRESS_P (*op)) + { + if (ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (get_pool_constant (*op), Pmode)) + { + *sym = op; + return 1; + } + else + return 0; + } + else if (! strcmp (XSTR (*op, 0), toc_label_name)) + { + *toc = op; + return 1; + } + else + return 0; + case PLUS: + case MINUS: + return (find_constant_pool_expr (&XEXP (*op, 0), sym, toc) + && find_constant_pool_expr (&XEXP (*op, 1), sym, toc)); + case CONST: + return find_constant_pool_expr (&XEXP (*op, 0), sym, toc); + case CONST_INT: + return 1; + default: + return 0; + } +} + static bool constant_pool_expr_p (rtx op) { @@ -12268,32 +12307,36 @@ print_operand_address (FILE *file, rtx x { if (TARGET_AIX && (!TARGET_ELF || !TARGET_MINIMAL_TOC)) { - rtx contains_minus = XEXP (x, 1); - rtx minus, symref; + rtx *symref = NULL, *tocref = NULL, toc = NULL, addr; const char *name; - /* Find the (minus (sym) (toc)) buried in X, and temporarily - turn it into (sym) for output_addr_const. */ - while (GET_CODE (XEXP (contains_minus, 0)) != MINUS) - contains_minus = XEXP (contains_minus, 0); - - minus = XEXP (contains_minus, 0); - symref = XEXP (minus, 0); - XEXP (contains_minus, 0) = symref; + find_constant_pool_expr (&XEXP (x, 1), &symref, &tocref); + if (tocref) + { + toc = *tocref; + *tocref = const0_rtx; + } if (TARGET_ELF) { char *newname; - name = XSTR (symref, 0); + name = XSTR (*symref, 0); newname = alloca (strlen (name) + sizeof ("@toc")); strcpy (newname, name); strcat (newname, "@toc"); - XSTR (symref, 0) = newname; + XSTR (*symref, 0) = newname; } - output_addr_const (file, XEXP (x, 1)); + addr = XEXP (x, 1); + if (GET_CODE (addr) == CONST) + addr = XEXP (addr, 0); + addr = simplify_rtx (addr); + if (!addr) + addr = XEXP (x, 1); + output_addr_const (file, addr); if (TARGET_ELF) - XSTR (symref, 0) = name; - XEXP (contains_minus, 0) = minus; + XSTR (*symref, 0) = name; + if (tocref) + *tocref = toc; } else output_addr_const (file, XEXP (x, 1)); The differences from #c12: 1) it doesn't reuse the same routine for finding the addresses. The disadvantage of this is that whenever making changes to constant_pool_expr_1 the other should be adjusted too. 2) it will silently miscompile things if more than one sym or more than one toc is in the address (unlikely to be ever generated, true) 3) similarly, it doesn't check that toc is subtracted from sym, so in some pathological case we could have .LC1 + .LCTOC1 or -.LC1 - .LCTOC1. No testing done on the patch except for testing that it fixes the testcase. -- http://gcc.gnu.org/bugzilla/show_bug.cgi?id=36090