From patchwork Mon Sep 5 15:41:26 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alan Modra X-Patchwork-Id: 113386 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) by ozlabs.org (Postfix) with SMTP id 10956B6F7C for ; Tue, 6 Sep 2011 01:42:04 +1000 (EST) Received: (qmail 2093 invoked by alias); 5 Sep 2011 15:42:00 -0000 Received: (qmail 2066 invoked by uid 22791); 5 Sep 2011 15:41:56 -0000 X-SWARE-Spam-Status: No, hits=-0.9 required=5.0 tests=AWL, BAYES_40, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, FREEMAIL_FROM, KAM_STOCKGEN, RCVD_IN_DNSWL_LOW, T_TO_NO_BRKTS_FREEMAIL X-Spam-Check-By: sourceware.org Received: from mail-yw0-f47.google.com (HELO mail-yw0-f47.google.com) (209.85.213.47) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Mon, 05 Sep 2011 15:41:36 +0000 Received: by ywa12 with SMTP id 12so3414243ywa.20 for ; Mon, 05 Sep 2011 08:41:35 -0700 (PDT) Received: by 10.90.169.9 with SMTP id r9mr2510506age.189.1315237295438; Mon, 05 Sep 2011 08:41:35 -0700 (PDT) Received: from bubble.grove.modra.org ([115.187.252.19]) by mx.google.com with ESMTPS id c13sm9881063anm.6.2011.09.05.08.41.31 (version=TLSv1/SSLv3 cipher=OTHER); Mon, 05 Sep 2011 08:41:34 -0700 (PDT) Received: by bubble.grove.modra.org (Postfix, from userid 1000) id F141E170C2BC; Tue, 6 Sep 2011 01:11:26 +0930 (CST) Date: Tue, 6 Sep 2011 01:11:26 +0930 From: Alan Modra To: gcc-patches@gcc.gnu.org Cc: David Edelsohn Subject: rs6000 toc reference rtl Message-ID: <20110905154126.GS18554@bubble.grove.modra.org> Mail-Followup-To: gcc-patches@gcc.gnu.org, David Edelsohn MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.5.20 (2009-06-14) X-IsSubscribed: yes Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org This patch changes the rtl used by rs6000 for a TOC reference address. The old rtl for -mcmodel=small is: (plus (reg tocreg) (const (unspec [(symbol_ref sym)] UNSPEC_TOCREL))) while the old rtl for -mcmodel=medium/large is: (set (reg rn) (const (plus (reg r2) (high (const (unspec [(symbol_ref sym)] UNSPEC_TOCREL)))))) (lo_sum (reg rn) (const (unspec [(symbol_ref sym)] UNSPEC_TOCREL))) These change to (unspec [(symbol_ref sym) (reg tocreg)] UNSPEC_TOCREL) and (set (reg rn) (high (unspec [(symbol_ref sym) (reg r2)] UNSPEC_TOCREL))) (lo_sum (reg rn) (unspec [(symbol_ref sym) (reg r2)] UNSPEC_TOCREL)) respectively. Why do I want to do this, apart from simplifying the rtl? Well, df-scan.c and other parts of gcc don't look inside a CONST for regs (arguably a bug), so we don't see r2 as being live for the high part of a large-toc sequence. Consequently, Mike's change to split rtl for indirect calls sometimes sees the scheduler moving the r2 load in the indirect call sequence before a toc reference. While I could have tackled the CONST problem, I reckon doing so would be more likely to destabilize other targets than the changes to cselib.c and cprop.c below. Bootstrapped and regression tested powerpc-linux and powerpc64-linux, and also with a -mcmodel=small default. OK for mainline? Further comments/explanation interspersed with changelog. * cselib.c (preserve_only_constants): Remove HIGH rtx containing value references. * cprop.c (cprop_constant_p): Return false for HIGH rtx containing value references. Regs inside a HIGH cause value refs to appear. * config/rs6000/predicates.md (input_operand): Match unspec. Remove redundant tests. legitimate_constant_pool_address_p true now implies toc_relative_expr_p is true. * rs6000-protos.h (toc_relative_expr_p): Update prototype. * const/rs6000/rs6000.c (tocrel_base, tocrel_offset): Make const. const_rtx is a pain. mode_dependent_address forces a const_rtx down to here, but we need to pass this on to output_addr_const. (legitimate_constant_pool_address_p): Move TARGET_TOC test and register checks to.. (toc_relative_expr_p): ..here. Add "strict" param. Match new rtl generated by create_TOC_reference. toc_relative_expr_p is needed in input_operand for 'R' constraint, but we can't allow medium/large toc to match without ensuring reload actually gives us a reg. (rs6000_delegitimize_address): Handle new rtl for toc refs. Simpler checks here should fix 50191 as a side-effect. (rs6000_cannot_force_const_mem, rs6000_find_base_term): Likewise. (use_toc_relative_ref): New function, split out from.. (rs6000_emit_move): ..here. Remove redundant tests. (rs6000_legitimize_reload_address): Formatting. Remove redundant code. Use use_toc_relative_ref. The existing lo_sum/high case handles new toc refs. (print_operand): Formatting, style. Adjust for toc changes. (print_operand_address): Likewise. (rs6000_output_addr_const_extra): Likewise. (create_TOC_reference): Put TOC_REGISTER in UNSPEC_TOCREL rather than a PLUS. Use this formulation for both high and low part of -mcmodel=medium/large toc reference too. Making the low-part depend on r2 is deliberate and necessary in the face of ld editing code to nop out the high part. * config/rs6000/rs6000.md (tls_gd, tls_gd_high): Similarly avoid a PLUS in high part of addresses here. (tls_ld, tls_ld_high, tls_got_dtprel, tls_got_dtprel_high): Likewise. (tls_got_tprel, tls_got_tprel_high, largetoc_high): Likewise. (largetoc_high, largetoc_low): Move earlier. Cope when no base reg available. Index: gcc/cselib.c =================================================================== --- gcc/cselib.c (revision 178035) +++ gcc/cselib.c (working copy) @@ -325,8 +325,9 @@ preserve_only_constants (void **x, void && v->locs->next == NULL) { if (CONSTANT_P (v->locs->loc) - && (GET_CODE (v->locs->loc) != CONST - || !references_value_p (v->locs->loc, 0))) + && !((GET_CODE (v->locs->loc) == CONST + || GET_CODE (v->locs->loc) == HIGH) + && references_value_p (v->locs->loc, 0))) return 1; if (cfa_base_preserved_val) { Index: gcc/cprop.c =================================================================== --- gcc/cprop.c (revision 178035) +++ gcc/cprop.c (working copy) @@ -253,7 +253,13 @@ insert_set_in_table (rtx dest, rtx src, static bool cprop_constant_p (const_rtx x) { - return CONSTANT_P (x) && (GET_CODE (x) != CONST || shared_const_p (x)); + if (!CONSTANT_P (x)) + return false; + if (GET_CODE (x) == CONST) + return shared_const_p (x); + if (GET_CODE (x) == HIGH) + return !references_value_p (x, false); + return true; } /* Scan pattern PAT of INSN and add an entry to the hash TABLE (set or Index: gcc/config/rs6000/predicates.md =================================================================== --- gcc/config/rs6000/predicates.md (revision 178035) +++ gcc/config/rs6000/predicates.md (working copy) @@ -815,7 +815,7 @@ (define_predicate "current_file_function ;; Return 1 if this operand is a valid input for a move insn. (define_predicate "input_operand" (match_code "label_ref,symbol_ref,const,high,reg,subreg,mem, - const_double,const_vector,const_int,plus") + const_double,const_vector,const_int,plus,unspec") { /* Memory is always valid. */ if (memory_operand (op, mode)) @@ -823,7 +823,6 @@ (define_predicate "input_operand" /* For floating-point, easy constants are valid. */ if (SCALAR_FLOAT_MODE_P (mode) - && CONSTANT_P (op) && easy_fp_constant (op, mode)) return 1; @@ -857,11 +856,7 @@ (define_predicate "input_operand" return 1; /* A SYMBOL_REF referring to the TOC is valid. */ - if (legitimate_constant_pool_address_p (op, mode, false)) - return 1; - - /* A constant pool expression (relative to the TOC) is valid */ - if (toc_relative_expr_p (op)) + if (toc_relative_expr_p (op, false)) return 1; /* V.4 allows SYMBOL_REFs and CONSTs that are in the small data region Index: gcc/config/rs6000/rs6000-protos.h =================================================================== --- gcc/config/rs6000/rs6000-protos.h (revision 178035) +++ gcc/config/rs6000/rs6000-protos.h (working copy) @@ -38,7 +38,7 @@ extern bool macho_lo_sum_memory_operand extern int num_insns_constant (rtx, enum machine_mode); extern int num_insns_constant_wide (HOST_WIDE_INT); extern int small_data_operand (rtx, enum machine_mode); -extern bool toc_relative_expr_p (rtx); +extern bool toc_relative_expr_p (const_rtx, bool); extern bool invalid_e500_subreg (rtx, enum machine_mode); extern void validate_condition_mode (enum rtx_code, enum machine_mode); extern bool legitimate_constant_pool_address_p (const_rtx, enum machine_mode, Index: gcc/config/rs6000/rs6000.c =================================================================== --- gcc/config/rs6000/rs6000.c (revision 178035) +++ gcc/config/rs6000/rs6000.c (working copy) @@ -5271,15 +5271,32 @@ constant_pool_expr_p (rtx op) && ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (get_pool_constant (base), Pmode)); } -static rtx tocrel_base, tocrel_offset; +static const_rtx tocrel_base, tocrel_offset; bool -toc_relative_expr_p (rtx op) +toc_relative_expr_p (const_rtx op, bool strict) { - if (GET_CODE (op) != CONST) + if (!TARGET_TOC) return false; - split_const (op, &tocrel_base, &tocrel_offset); + if (TARGET_CMODEL != CMODEL_SMALL) + { + /* Only match the low part. */ + if (GET_CODE (op) != LO_SUM + || GET_CODE (XEXP (op, 0)) != REG + || !INT_REG_OK_FOR_BASE_P (XEXP (op, 0), strict)) + return false; + op = XEXP (op, 1); + } + + tocrel_base = op; + tocrel_offset = const0_rtx; + if (GET_CODE (op) == PLUS && CONST_INT_P (XEXP (op, 1))) + { + tocrel_base = XEXP (op, 0); + tocrel_offset = XEXP (op, 1); + } + return (GET_CODE (tocrel_base) == UNSPEC && XINT (tocrel_base, 1) == UNSPEC_TOCREL); } @@ -5291,14 +5308,7 @@ bool legitimate_constant_pool_address_p (const_rtx x, enum machine_mode mode, bool strict) { - return (TARGET_TOC - && (GET_CODE (x) == PLUS || GET_CODE (x) == LO_SUM) - && GET_CODE (XEXP (x, 0)) == REG - && (REGNO (XEXP (x, 0)) == TOC_REGISTER - || ((TARGET_MINIMAL_TOC - || TARGET_CMODEL != CMODEL_SMALL) - && INT_REG_OK_FOR_BASE_P (XEXP (x, 0), strict))) - && toc_relative_expr_p (XEXP (x, 1)) + return (toc_relative_expr_p (x, strict) && (TARGET_CMODEL != CMODEL_MEDIUM || constant_pool_expr_p (XVECEXP (tocrel_base, 0, 0)) || mode == QImode @@ -5764,49 +5774,37 @@ rs6000_output_dwarf_dtprel (FILE *file, static rtx rs6000_delegitimize_address (rtx orig_x) { - rtx x, y; + rtx x, y, offset; orig_x = delegitimize_mem_from_attrs (orig_x); x = orig_x; if (MEM_P (x)) x = XEXP (x, 0); - if (GET_CODE (x) == (TARGET_CMODEL != CMODEL_SMALL ? LO_SUM : PLUS) - && GET_CODE (XEXP (x, 1)) == CONST) + y = x; + if (TARGET_CMODEL != CMODEL_SMALL + && GET_CODE (y) == LO_SUM) + y = XEXP (y, 1); + + offset = NULL_RTX; + if (GET_CODE (y) == PLUS + && GET_MODE (y) == Pmode + && CONST_INT_P (XEXP (y, 1))) { - rtx offset = NULL_RTX; + offset = XEXP (y, 1); + y = XEXP (y, 0); + } - y = XEXP (XEXP (x, 1), 0); - if (GET_CODE (y) == PLUS - && GET_MODE (y) == Pmode - && CONST_INT_P (XEXP (y, 1))) - { - offset = XEXP (y, 1); - y = XEXP (y, 0); - } - if (GET_CODE (y) == UNSPEC - && XINT (y, 1) == UNSPEC_TOCREL - && ((GET_CODE (XEXP (x, 0)) == REG - && (REGNO (XEXP (x, 0)) == TOC_REGISTER - || TARGET_MINIMAL_TOC - || TARGET_CMODEL != CMODEL_SMALL)) - || (TARGET_CMODEL != CMODEL_SMALL - && GET_CODE (XEXP (x, 0)) == CONST - && GET_CODE (XEXP (XEXP (x, 0), 0)) == PLUS - && GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 0)) == REG - && REGNO (XEXP (XEXP (XEXP (x, 0), 0), 0)) == TOC_REGISTER - && GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 1)) == HIGH - && rtx_equal_p (XEXP (x, 1), - XEXP (XEXP (XEXP (XEXP (x, 0), 0), 1), 0))))) - { - y = XVECEXP (y, 0, 0); - if (offset != NULL_RTX) - y = gen_rtx_PLUS (Pmode, y, offset); - if (!MEM_P (orig_x)) - return y; - else - return replace_equiv_address_nv (orig_x, y); - } + if (GET_CODE (y) == UNSPEC + && XINT (y, 1) == UNSPEC_TOCREL) + { + y = XVECEXP (y, 0, 0); + if (offset != NULL_RTX) + y = gen_rtx_PLUS (Pmode, y, offset); + if (!MEM_P (orig_x)) + return y; + else + return replace_equiv_address_nv (orig_x, y); } if (TARGET_MACHO @@ -6047,9 +6045,8 @@ rs6000_tls_referenced_p (rtx x) static bool rs6000_cannot_force_const_mem (enum machine_mode mode ATTRIBUTE_UNUSED, rtx x) { - if (GET_CODE (x) == CONST - && GET_CODE (XEXP (x, 0)) == PLUS - && GET_CODE (XEXP (XEXP (x, 0), 1)) == HIGH) + if (GET_CODE (x) == HIGH + && GET_CODE (XEXP (x, 0)) == UNSPEC) return true; return rs6000_tls_referenced_p (x); @@ -6064,6 +6061,21 @@ rs6000_tls_symbol_ref_1 (rtx *x, void *d return RS6000_SYMBOL_REF_TLS_P (*x); } +/* Return true iff the given SYMBOL_REF refers to a constant pool entry + that we have put in the TOC, or for cmodel=medium, if the SYMBOL_REF + can be addressed relative to the toc pointer. */ + +static bool +use_toc_relative_ref (rtx sym) +{ + return ((constant_pool_expr_p (sym) + && ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (get_pool_constant (sym), + get_pool_mode (sym))) + || (TARGET_CMODEL == CMODEL_MEDIUM + && !CONSTANT_POOL_ADDRESS_P (sym) + && SYMBOL_REF_LOCAL_P (sym))); +} + /* Our implementation of LEGITIMIZE_RELOAD_ADDRESS. Returns a value to replace the input X, or the original X if no replacement is called for. The output parameter *WIN is 1 if the calling macro should goto WIN, @@ -6101,7 +6113,7 @@ rs6000_legitimize_reload_address (rtx x, { push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL, BASE_REG_CLASS, GET_MODE (x), VOIDmode, 0, 0, - opnum, (enum reload_type)type); + opnum, (enum reload_type) type); *win = 1; return x; } @@ -6112,7 +6124,7 @@ rs6000_legitimize_reload_address (rtx x, { push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL, BASE_REG_CLASS, Pmode, VOIDmode, 0, 0, - opnum, (enum reload_type)type); + opnum, (enum reload_type) type); *win = 1; return x; } @@ -6130,30 +6142,11 @@ rs6000_legitimize_reload_address (rtx x, floating point constant. */ push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL, BASE_REG_CLASS, Pmode, VOIDmode, 0, 0, - opnum, (enum reload_type)type); - *win = 1; - return x; - } -#endif - - if (TARGET_CMODEL != CMODEL_SMALL - && GET_CODE (x) == LO_SUM - && GET_CODE (XEXP (x, 0)) == PLUS - && GET_CODE (XEXP (XEXP (x, 0), 0)) == REG - && REGNO (XEXP (XEXP (x, 0), 0)) == TOC_REGISTER - && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST - && GET_CODE (XEXP (XEXP (XEXP (x, 0), 1), 0)) == HIGH - && GET_CODE (XEXP (x, 1)) == CONST - && GET_CODE (XEXP (XEXP (x, 1), 0)) == UNSPEC - && XINT (XEXP (XEXP (x, 1), 0), 1) == UNSPEC_TOCREL - && rtx_equal_p (XEXP (XEXP (XEXP (XEXP (x, 0), 1), 0), 0), XEXP (x, 1))) - { - push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL, - BASE_REG_CLASS, Pmode, VOIDmode, 0, 0, opnum, (enum reload_type) type); *win = 1; return x; } +#endif /* Force ld/std non-word aligned offset into base register by wrapping in offset 0. */ @@ -6210,7 +6203,7 @@ rs6000_legitimize_reload_address (rtx x, push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL, BASE_REG_CLASS, GET_MODE (x), VOIDmode, 0, 0, - opnum, (enum reload_type)type); + opnum, (enum reload_type) type); *win = 1; return x; } @@ -6250,7 +6243,7 @@ rs6000_legitimize_reload_address (rtx x, push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL, BASE_REG_CLASS, Pmode, VOIDmode, 0, 0, - opnum, (enum reload_type)type); + opnum, (enum reload_type) type); *win = 1; return x; } @@ -6277,8 +6270,7 @@ rs6000_legitimize_reload_address (rtx x, if (TARGET_TOC && reg_offset_p && GET_CODE (x) == SYMBOL_REF - && constant_pool_expr_p (x) - && ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (get_pool_constant (x), mode)) + && use_toc_relative_ref (x)) { x = create_TOC_reference (x, NULL_RTX); if (TARGET_CMODEL != CMODEL_SMALL) @@ -6513,9 +6505,13 @@ rs6000_debug_mode_dependent_address (con rtx rs6000_find_base_term (rtx op) { - rtx base, offset; + rtx base; - split_const (op, &base, &offset); + base = op; + if (GET_CODE (base) == CONST) + base = XEXP (base, 0); + if (GET_CODE (base) == PLUS) + base = XEXP (base, 0); if (GET_CODE (base) == UNSPEC) switch (XINT (base, 1)) { @@ -7170,15 +7163,9 @@ rs6000_emit_move (rtx dest, rtx source, /* If this is a SYMBOL_REF that refers to a constant pool entry, and we have put it in the TOC, we just need to make a TOC-relative reference to it. */ - if ((TARGET_TOC - && GET_CODE (operands[1]) == SYMBOL_REF - && constant_pool_expr_p (operands[1]) - && ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (get_pool_constant (operands[1]), - get_pool_mode (operands[1]))) - || (TARGET_CMODEL == CMODEL_MEDIUM - && GET_CODE (operands[1]) == SYMBOL_REF - && !CONSTANT_POOL_ADDRESS_P (operands[1]) - && SYMBOL_REF_LOCAL_P (operands[1]))) + if (TARGET_TOC + && GET_CODE (operands[1]) == SYMBOL_REF + && use_toc_relative_ref (operands[1])) { rtx reg = NULL_RTX; if (TARGET_CMODEL != CMODEL_SMALL) @@ -7193,10 +7180,6 @@ rs6000_emit_move (rtx dest, rtx source, else if (mode == Pmode && CONSTANT_P (operands[1]) && GET_CODE (operands[1]) != HIGH - && !(TARGET_CMODEL != CMODEL_SMALL - && GET_CODE (operands[1]) == CONST - && GET_CODE (XEXP (operands[1], 0)) == PLUS - && GET_CODE (XEXP (XEXP (operands[1], 0), 1)) == HIGH) && ((GET_CODE (operands[1]) != CONST_INT && ! easy_fp_constant (operands[1], mode)) || (GET_CODE (operands[1]) == CONST_INT @@ -7204,9 +7187,7 @@ rs6000_emit_move (rtx dest, rtx source, > (TARGET_CMODEL != CMODEL_SMALL ? 3 : 2))) || (GET_CODE (operands[0]) == REG && FP_REGNO_P (REGNO (operands[0])))) - && ! legitimate_constant_pool_address_p (operands[1], mode, - false) - && ! toc_relative_expr_p (operands[1]) + && !toc_relative_expr_p (operands[1], false) && (TARGET_CMODEL == CMODEL_SMALL || can_create_pseudo_p () || (REG_P (operands[0]) @@ -15310,7 +15330,7 @@ print_operand (FILE *file, rtx x, int co case 'D': /* Like 'J' but get to the GT bit only. */ - gcc_assert (GET_CODE (x) == REG); + gcc_assert (REG_P (x)); /* Bit 1 is GT bit. */ i = 4 * (REGNO (x) - CR0_REGNO) + 1; @@ -15430,9 +15450,9 @@ print_operand (FILE *file, rtx x, int co case 'L': /* Write second word of DImode or DFmode reference. Works on register or non-indexed memory only. */ - if (GET_CODE (x) == REG) + if (REG_P (x)) fputs (reg_names[REGNO (x) + 1], file); - else if (GET_CODE (x) == MEM) + else if (MEM_P (x)) { /* Handle possible auto-increment. Since it is pre-increment and we have already done it, we can just use an offset of word. */ @@ -15601,7 +15622,7 @@ print_operand (FILE *file, rtx x, int co case 't': /* Like 'J' but get to the OVERFLOW/UNORDERED bit. */ - gcc_assert (GET_CODE (x) == REG && GET_MODE (x) == CCmode); + gcc_assert (REG_P (x) && GET_MODE (x) == CCmode); /* Bit 3 is OV bit. */ i = 4 * (REGNO (x) - CR0_REGNO) + 3; @@ -15641,7 +15662,7 @@ print_operand (FILE *file, rtx x, int co case 'U': /* Print `u' if this has an auto-increment or auto-decrement. */ - if (GET_CODE (x) == MEM + if (MEM_P (x) && (GET_CODE (XEXP (x, 0)) == PRE_INC || GET_CODE (XEXP (x, 0)) == PRE_DEC || GET_CODE (XEXP (x, 0)) == PRE_MODIFY)) @@ -15750,7 +15771,7 @@ print_operand (FILE *file, rtx x, int co return; case 'X': - if (GET_CODE (x) == MEM + if (MEM_P (x) && (legitimate_indexed_address_p (XEXP (x, 0), 0) || (GET_CODE (XEXP (x, 0)) == PRE_MODIFY && legitimate_indexed_address_p (XEXP (XEXP (x, 0), 1), 0)))) @@ -15759,9 +15780,9 @@ print_operand (FILE *file, rtx x, int co case 'Y': /* Like 'L', for third word of TImode */ - if (GET_CODE (x) == REG) + if (REG_P (x)) fputs (reg_names[REGNO (x) + 2], file); - else if (GET_CODE (x) == MEM) + else if (MEM_P (x)) { if (GET_CODE (XEXP (x, 0)) == PRE_INC || GET_CODE (XEXP (x, 0)) == PRE_DEC) @@ -15809,9 +15831,9 @@ print_operand (FILE *file, rtx x, int co case 'Z': /* Like 'L', for last word of TImode. */ - if (GET_CODE (x) == REG) + if (REG_P (x)) fputs (reg_names[REGNO (x) + 3], file); - else if (GET_CODE (x) == MEM) + else if (MEM_P (x)) { if (GET_CODE (XEXP (x, 0)) == PRE_INC || GET_CODE (XEXP (x, 0)) == PRE_DEC) @@ -15831,7 +15854,7 @@ print_operand (FILE *file, rtx x, int co { rtx tmp; - gcc_assert (GET_CODE (x) == MEM); + gcc_assert (MEM_P (x)); tmp = XEXP (x, 0); @@ -15842,7 +15865,7 @@ print_operand (FILE *file, rtx x, int co || GET_MODE (x) == TImode)) { /* Handle [reg]. */ - if (GET_CODE (tmp) == REG) + if (REG_P (tmp)) { fprintf (file, "0(%s)", reg_names[REGNO (tmp)]); break; @@ -15853,7 +15876,7 @@ print_operand (FILE *file, rtx x, int co { int x; - gcc_assert (GET_CODE (XEXP (tmp, 0)) == REG); + gcc_assert (REG_P (XEXP (tmp, 0))); x = INTVAL (XEXP (tmp, 1)); fprintf (file, "%d(%s)", x, reg_names[REGNO (XEXP (tmp, 0))]); @@ -15870,7 +15893,7 @@ print_operand (FILE *file, rtx x, int co else if (VECTOR_MEM_VSX_P (GET_MODE (x)) && GET_CODE (tmp) == PRE_MODIFY) tmp = XEXP (tmp, 1); - if (GET_CODE (tmp) == REG) + if (REG_P (tmp)) fprintf (file, "0,%s", reg_names[REGNO (tmp)]); else { @@ -15893,9 +15916,9 @@ print_operand (FILE *file, rtx x, int co } case 0: - if (GET_CODE (x) == REG) + if (REG_P (x)) fprintf (file, "%s", reg_names[REGNO (x)]); - else if (GET_CODE (x) == MEM) + else if (MEM_P (x)) { /* We need to handle PRE_INC and PRE_DEC here, since we need to know the width from the mode. */ @@ -15909,14 +15932,14 @@ print_operand (FILE *file, rtx x, int co } else { - if (toc_relative_expr_p (x)) + if (toc_relative_expr_p (x, false)) /* This hack along with a corresponding hack in rs6000_output_addr_const_extra arranges to output addends where the assembler expects to find them. eg. - (const (plus (unspec [symbol_ref ("x") tocrel]) 4)) + (plus (unspec [(symbol_ref ("x")) (reg 2)] tocrel) 4) without this hack would be output as "x@toc+4". We want "x+4@toc". */ - output_addr_const (file, tocrel_base); + output_addr_const (file, CONST_CAST_RTX (tocrel_base)); else output_addr_const (file, x); } @@ -15939,7 +15968,7 @@ print_operand (FILE *file, rtx x, int co void print_operand_address (FILE *file, rtx x) { - if (GET_CODE (x) == REG) + if (REG_P (x)) fprintf (file, "0(%s)", reg_names[ REGNO (x) ]); else if (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == CONST || GET_CODE (x) == LABEL_REF) @@ -15951,9 +15980,9 @@ print_operand_address (FILE *file, rtx x else gcc_assert (!TARGET_TOC); } - else if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == REG) + else if (GET_CODE (x) == PLUS && REG_P (XEXP (x, 0)) + && REG_P (XEXP (x, 1))) { - gcc_assert (REG_P (XEXP (x, 0))); if (REGNO (XEXP (x, 0)) == 0) fprintf (file, "%s,%s", reg_names[ REGNO (XEXP (x, 1)) ], reg_names[ REGNO (XEXP (x, 0)) ]); @@ -15961,11 +15990,12 @@ print_operand_address (FILE *file, rtx x fprintf (file, "%s,%s", reg_names[ REGNO (XEXP (x, 0)) ], reg_names[ REGNO (XEXP (x, 1)) ]); } - else if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == CONST_INT) + else if (GET_CODE (x) == PLUS && REG_P (XEXP (x, 0)) + && GET_CODE (XEXP (x, 1)) == CONST_INT) fprintf (file, HOST_WIDE_INT_PRINT_DEC "(%s)", INTVAL (XEXP (x, 1)), reg_names[ REGNO (XEXP (x, 0)) ]); #if TARGET_MACHO - else if (GET_CODE (x) == LO_SUM && GET_CODE (XEXP (x, 0)) == REG + else if (GET_CODE (x) == LO_SUM && REG_P (XEXP (x, 0)) && CONSTANT_P (XEXP (x, 1))) { fprintf (file, "lo16("); @@ -15973,29 +16003,29 @@ print_operand_address (FILE *file, rtx x fprintf (file, ")(%s)", reg_names[ REGNO (XEXP (x, 0)) ]); } #endif - else if (legitimate_constant_pool_address_p (x, QImode, true)) +#if TARGET_ELF + else if (GET_CODE (x) == LO_SUM && REG_P (XEXP (x, 0)) + && CONSTANT_P (XEXP (x, 1))) + { + output_addr_const (file, XEXP (x, 1)); + fprintf (file, "@l(%s)", reg_names[ REGNO (XEXP (x, 0)) ]); + } +#endif + else if (toc_relative_expr_p (x, false)) { /* This hack along with a corresponding hack in rs6000_output_addr_const_extra arranges to output addends where the assembler expects to find them. eg. (lo_sum (reg 9) - . (const (plus (unspec [symbol_ref ("x") tocrel]) 8))) + . (plus (unspec [(symbol_ref ("x")) (reg 2)] tocrel) 8)) without this hack would be output as "x@toc+8@l(9)". We want "x+8@toc@l(9)". */ - output_addr_const (file, tocrel_base); + output_addr_const (file, CONST_CAST_RTX (tocrel_base)); if (GET_CODE (x) == LO_SUM) - fprintf (file, "@l(%s)", reg_names[ REGNO (XEXP (x, 0)) ]); + fprintf (file, "@l(%s)", reg_names[REGNO (XEXP (x, 0))]); else - fprintf (file, "(%s)", reg_names[REGNO (XEXP (x, 0))]); - } -#if TARGET_ELF - else if (GET_CODE (x) == LO_SUM && GET_CODE (XEXP (x, 0)) == REG - && CONSTANT_P (XEXP (x, 1))) - { - output_addr_const (file, XEXP (x, 1)); - fprintf (file, "@l(%s)", reg_names[ REGNO (XEXP (x, 0)) ]); + fprintf (file, "(%s)", reg_names[REGNO (XVECEXP (tocrel_base, 0, 1))]); } -#endif else gcc_unreachable (); } @@ -16009,13 +16039,15 @@ rs6000_output_addr_const_extra (FILE *fi switch (XINT (x, 1)) { case UNSPEC_TOCREL: - gcc_assert (GET_CODE (XVECEXP (x, 0, 0)) == SYMBOL_REF); + gcc_checking_assert (GET_CODE (XVECEXP (x, 0, 0)) == SYMBOL_REF + && REG_P (XVECEXP (x, 0, 1)) + && REGNO (XVECEXP (x, 0, 1)) == TOC_REGISTER); output_addr_const (file, XVECEXP (x, 0, 0)); if (x == tocrel_base && tocrel_offset != const0_rtx) { if (INTVAL (tocrel_offset) >= 0) fprintf (file, "+"); - output_addr_const (file, tocrel_offset); + output_addr_const (file, CONST_CAST_RTX (tocrel_offset)); } if (!TARGET_AIX || (TARGET_ELF && TARGET_MINIMAL_TOC)) { @@ -19033,7 +19065,7 @@ uses_TOC (void) rtx create_TOC_reference (rtx symbol, rtx largetoc_reg) { - rtx tocrel, tocreg; + rtx tocrel, tocreg, hi; if (TARGET_DEBUG_ADDR) { @@ -19051,24 +19083,18 @@ create_TOC_reference (rtx symbol, rtx la if (!can_create_pseudo_p ()) df_set_regs_ever_live (TOC_REGISTER, true); - tocrel = gen_rtx_CONST (Pmode, - gen_rtx_UNSPEC (Pmode, gen_rtvec (1, symbol), - UNSPEC_TOCREL)); tocreg = gen_rtx_REG (Pmode, TOC_REGISTER); - if (TARGET_CMODEL != CMODEL_SMALL) + tocrel = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, symbol, tocreg), UNSPEC_TOCREL); + if (TARGET_CMODEL == CMODEL_SMALL) + return tocrel; + + hi = gen_rtx_HIGH (Pmode, copy_rtx (tocrel)); + if (largetoc_reg != NULL) { - rtx hi = gen_rtx_CONST (Pmode, - gen_rtx_PLUS (Pmode, tocreg, - gen_rtx_HIGH (Pmode, tocrel))); - if (largetoc_reg != NULL) - { - emit_move_insn (largetoc_reg, hi); - hi = largetoc_reg; - } - return gen_rtx_LO_SUM (Pmode, hi, copy_rtx (tocrel)); + emit_move_insn (largetoc_reg, hi); + hi = largetoc_reg; } - else - return gen_rtx_PLUS (Pmode, tocreg, tocrel); + return gen_rtx_LO_SUM (Pmode, hi, tocrel); } /* Issue assembly directives that create a reference to the given DWARF Index: gcc/config/rs6000/rs6000.md =================================================================== --- gcc/config/rs6000/rs6000.md (revision 178035) +++ gcc/config/rs6000/rs6000.md (working copy) @@ -11543,10 +11544,8 @@ (define_insn_and_split "*tls_gd" [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b") - (const:TLSmode - (plus:TLSmode (match_operand:TLSmode 1 "gpc_reg_operand" "b") - (high:TLSmode - (unspec:TLSmode [(match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")] - UNSPEC_TLSGD)))))] + (high:TLSmode + (unspec:TLSmode [(match_operand:TLSmode 1 "gpc_reg_operand" "b") + (match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")] + UNSPEC_TLSGD)))] "HAVE_AS_TLS && TARGET_TLS_MARKERS && TARGET_CMODEL != CMODEL_SMALL" "addis %0,%1,%2@got@tlsgd@ha" [(set_attr "length" "4")]) @@ -11680,10 +11678,8 @@ (define_insn_and_split "*tls_ld" [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b") - (const:TLSmode - (plus:TLSmode (match_operand:TLSmode 1 "gpc_reg_operand" "b") - (high:TLSmode - (unspec:TLSmode [(const_int 0)] UNSPEC_TLSLD)))))] + (high:TLSmode + (unspec:TLSmode [(const_int 0) + (match_operand:TLSmode 1 "gpc_reg_operand" "b")] + UNSPEC_TLSLD)))] "HAVE_AS_TLS && TARGET_TLS_MARKERS && TARGET_CMODEL != CMODEL_SMALL" "addis %0,%1,%&@got@tlsld@ha" [(set_attr "length" "4")]) @@ -11777,10 +11773,8 @@ (define_insn_and_split "tls_got_dtprel_< "l %0,%2@got@dtprel(%1)" "&& TARGET_CMODEL != CMODEL_SMALL" [(set (match_dup 3) - (const:TLSmode - (plus:TLSmode (match_dup 1) - (high:TLSmode - (unspec:TLSmode [(match_dup 2)] UNSPEC_TLSGOTDTPREL))))) + (high:TLSmode + (unspec:TLSmode [(match_dup 1) (match_dup 2)] UNSPEC_TLSGOTDTPREL))) (set (match_dup 0) (lo_sum:TLSmode (match_dup 3) (unspec:TLSmode [(match_dup 2)] UNSPEC_TLSGOTDTPREL)))] @@ -11795,11 +11789,10 @@ (define_insn_and_split "tls_got_dtprel_< (define_insn "*tls_got_dtprel_high" [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b") - (const:TLSmode - (plus:TLSmode (match_operand:TLSmode 1 "gpc_reg_operand" "b") - (high:TLSmode - (unspec:TLSmode [(match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")] - UNSPEC_TLSGOTDTPREL)))))] + (high:TLSmode + (unspec:TLSmode [(match_operand:TLSmode 1 "gpc_reg_operand" "b") + (match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")] + UNSPEC_TLSGOTDTPREL)))] "HAVE_AS_TLS && TARGET_CMODEL != CMODEL_SMALL" "addis %0,%1,%2@got@dtprel@ha" [(set_attr "length" "4")]) @@ -11849,10 +11842,8 @@ (define_insn_and_split "tls_got_tprel_ %0,%2@got@tprel(%1)" "&& TARGET_CMODEL != CMODEL_SMALL" [(set (match_dup 3) - (const:TLSmode - (plus:TLSmode (match_dup 1) - (high:TLSmode - (unspec:TLSmode [(match_dup 2)] UNSPEC_TLSGOTTPREL))))) + (high:TLSmode + (unspec:TLSmode [(match_dup 1) (match_dup 2)] UNSPEC_TLSGOTTPREL))) (set (match_dup 0) (lo_sum:TLSmode (match_dup 3) (unspec:TLSmode [(match_dup 2)] UNSPEC_TLSGOTTPREL)))] @@ -11867,11 +11858,10 @@ (define_insn_and_split "tls_got_tprel_" [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b") - (const:TLSmode - (plus:TLSmode (match_operand:TLSmode 1 "gpc_reg_operand" "b") - (high:TLSmode - (unspec:TLSmode [(match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")] - UNSPEC_TLSGOTTPREL)))))] + (high:TLSmode + (unspec:TLSmode [(match_operand:TLSmode 1 "gpc_reg_operand" "b") + (match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")] + UNSPEC_TLSGOTTPREL)))] "HAVE_AS_TLS && TARGET_CMODEL != CMODEL_SMALL" "addis %0,%1,%2@got@tprel@ha" [(set_attr "length" "4")]) @@ -12163,6 +12153,25 @@ (define_expand "builtin_setjmp_receiver" DONE; }") +;; Largetoc support +(define_insn "largetoc_high" + [(set (match_operand:DI 0 "gpc_reg_operand" "=b*r") + (high:DI + (unspec [(match_operand:DI 1 "" "") + (match_operand:DI 2 "gpc_reg_operand" "b")] + UNSPEC_TOCREL)))] + "TARGET_ELF && TARGET_CMODEL != CMODEL_SMALL" + "{cau|addis} %0,%2,%1@toc@ha") + +(define_insn "largetoc_low" + [(set (match_operand:DI 0 "gpc_reg_operand" "=r,r") + (lo_sum:DI (match_operand:DI 1 "gpc_reg_operand" "b,!*r") + (match_operand:DI 2 "" "")))] + "TARGET_ELF && TARGET_CMODEL != CMODEL_SMALL" + "@ + {cal %0,%2@l(%1)|addi %0,%1,%2@l} + {ai|addic} %0,%1,%2@l") + ;; Elf specific ways of loading addresses for non-PIC code. ;; The output of this could be r0, but we make a very strong ;; preference for a base register because it will usually @@ -12181,22 +12190,6 @@ (define_insn "elf_low" "@ {cal|la} %0,%2@l(%1) {ai|addic} %0,%1,%K2") - -;; Largetoc support -(define_insn "largetoc_high" - [(set (match_operand:DI 0 "gpc_reg_operand" "=b") - (const:DI - (plus:DI (match_operand:DI 1 "gpc_reg_operand" "b") - (high:DI (match_operand:DI 2 "" "")))))] - "TARGET_ELF && TARGET_CMODEL != CMODEL_SMALL" - "{cau|addis} %0,%1,%2@ha") - -(define_insn "largetoc_low" - [(set (match_operand:DI 0 "gpc_reg_operand" "=r") - (lo_sum:DI (match_operand:DI 1 "gpc_reg_operand" "b") - (match_operand:DI 2 "" "")))] - "TARGET_ELF && TARGET_CMODEL != CMODEL_SMALL" - "{cal %0,%2@l(%1)|addi %0,%1,%2@l}") ;; Call and call_value insns (define_expand "call"