From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 29665 invoked by alias); 10 Jan 2013 08:19:58 -0000 Received: (qmail 29653 invoked by uid 22791); 10 Jan 2013 08:19:57 -0000 X-SWARE-Spam-Status: No, hits=-1.3 required=5.0 tests=AWL,BAYES_00,KAM_STOCKGEN,RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from e06smtp14.uk.ibm.com (HELO e06smtp14.uk.ibm.com) (195.75.94.110) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Thu, 10 Jan 2013 08:19:47 +0000 Received: from /spool/local by e06smtp14.uk.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Thu, 10 Jan 2013 08:18:17 -0000 Received: from b06cxnps4074.portsmouth.uk.ibm.com (9.149.109.196) by e06smtp14.uk.ibm.com (192.168.101.144) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; Thu, 10 Jan 2013 08:18:16 -0000 Received: from d06av09.portsmouth.uk.ibm.com (d06av09.portsmouth.uk.ibm.com [9.149.37.250]) by b06cxnps4074.portsmouth.uk.ibm.com (8.13.8/8.13.8/NCO v10.0) with ESMTP id r0A8JYmJ63373544 for ; Thu, 10 Jan 2013 08:19:34 GMT Received: from d06av09.portsmouth.uk.ibm.com (loopback [127.0.0.1]) by d06av09.portsmouth.uk.ibm.com (8.14.4/8.13.1/NCO v10.0 AVout) with ESMTP id r0A8Jggf028553 for ; Thu, 10 Jan 2013 01:19:43 -0700 Received: from bart (dyn-9-152-212-144.boeblingen.de.ibm.com [9.152.212.144]) by d06av09.portsmouth.uk.ibm.com (8.14.4/8.13.1/NCO v10.0 AVin) with SMTP id r0A8JfbV028490 for ; Thu, 10 Jan 2013 01:19:41 -0700 Received: by bart (sSMTP sendmail emulation); Thu, 10 Jan 2013 09:19:41 +0100 Date: Thu, 10 Jan 2013 08:19:00 -0000 From: Andreas Krebbel To: gcc-patches@gcc.gnu.org Subject: [Committed] S/390: Fix PR55718: Handle GOTENT + constant for pic addresses Message-ID: <20130110081941.GA11578@bart> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.5.21 (2010-09-15) x-cbid: 13011008-1948-0000-0000-000003FC803A X-IsSubscribed: yes Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org X-SW-Source: 2013-01/txt/msg00518.txt.bz2 Hi, I've committed the attached patch which fixes PR 55718 by adding support for GOTENT + constant to legitimize_pic_address in the S/390 backend. The patch also does some rearrangements of the whole function in order to avoid some duplicate code. Bye, -Andreas- 2013-01-10 Andreas Krebbel PR target/55718 * config/s390/s390.c (s390_symref_operand_p) (s390_loadrelative_operand_p): Merge the two functions. (s390_check_qrst_address, print_operand_address): Add parameters to s390_loadrelative_operand_p invokation. (s390_check_symref_alignment): Use s390_loadrelative_operand_p. (s390_reload_larl_operand, s390_secondary_reload): Use s390_loadrelative_operand_p instead of s390_symref_operand_p. (legitimize_pic_address): Handle @GOTENT and @PLT + addend. --- gcc/config/s390/s390.c | 474 ++-!!!!!!!!!!!!!!!!!!!!!!!!!!!! gcc/testsuite/gcc.target/s390/pr55718.c | 29 + 2 files changed, 65 insertions(+), 10 deletions(-), 428 modifications(!) Index: gcc/config/s390/s390.c =================================================================== *** gcc/config/s390/s390.c.orig --- gcc/config/s390/s390.c *************** s390_legitimate_address_without_index_p *** 2148,2160 **** } ! /* Return true if ADDR is of kind symbol_ref or symbol_ref + const_int ! and return these parts in SYMREF and ADDEND. You can pass NULL in ! SYMREF and/or ADDEND if you are not interested in these values. ! Literal pool references are *not* considered symbol references. */ static bool ! s390_symref_operand_p (rtx addr, rtx *symref, HOST_WIDE_INT *addend) { HOST_WIDE_INT tmpaddend = 0; --- 2148,2164 ---- } ! /* Return TRUE if ADDR is an operand valid for a load/store relative ! instruction. Be aware that the alignment of the operand needs to ! be checked separately. ! Valid addresses are single references or a sum of a reference and a ! constant integer. Return these parts in SYMREF and ADDEND. You can ! pass NULL in REF and/or ADDEND if you are not interested in these ! values. Literal pool references are *not* considered symbol ! references. */ static bool ! s390_loadrelative_operand_p (rtx addr, rtx *symref, HOST_WIDE_INT *addend) { HOST_WIDE_INT tmpaddend = 0; *************** s390_symref_operand_p (rtx addr, rtx *sy *** 2163,2205 **** if (GET_CODE (addr) == PLUS) { ! if (GET_CODE (XEXP (addr, 0)) == SYMBOL_REF ! && !CONSTANT_POOL_ADDRESS_P (XEXP (addr, 0)) ! && CONST_INT_P (XEXP (addr, 1))) ! { ! tmpaddend = INTVAL (XEXP (addr, 1)); ! addr = XEXP (addr, 0); ! } ! else return false; - } - else - if (GET_CODE (addr) != SYMBOL_REF || CONSTANT_POOL_ADDRESS_P (addr)) - return false; - - if (symref) - *symref = addr; - if (addend) - *addend = tmpaddend; ! return true; ! } ! ! /* Return TRUE if ADDR is an operand valid for a load/store relative ! instructions. Be aware that the alignment of the operand needs to ! be checked separately. */ ! static bool ! s390_loadrelative_operand_p (rtx addr) ! { ! if (GET_CODE (addr) == CONST) ! addr = XEXP (addr, 0); ! /* Enable load relative for symbol@GOTENT. */ ! if (GET_CODE (addr) == UNSPEC ! && XINT (addr, 1) == UNSPEC_GOTENT) ! return true; ! return s390_symref_operand_p (addr, NULL, NULL); } /* Return true if the address in OP is valid for constraint letter C --- 2167,2192 ---- if (GET_CODE (addr) == PLUS) { ! if (!CONST_INT_P (XEXP (addr, 1))) return false; ! tmpaddend = INTVAL (XEXP (addr, 1)); ! addr = XEXP (addr, 0); ! } ! if ((GET_CODE (addr) == SYMBOL_REF && !CONSTANT_POOL_ADDRESS_P (addr)) ! || (GET_CODE (addr) == UNSPEC ! && (XINT (addr, 1) == UNSPEC_GOTENT ! || (TARGET_CPU_ZARCH && XINT (addr, 1) == UNSPEC_PLT)))) ! { ! if (symref) ! *symref = addr; ! if (addend) ! *addend = tmpaddend; ! return true; ! } ! return false; } /* Return true if the address in OP is valid for constraint letter C *************** s390_check_qrst_address (char c, rtx op, *** 2215,2221 **** /* This check makes sure that no symbolic address (except literal pool references) are accepted by the R or T constraints. */ ! if (s390_loadrelative_operand_p (op)) return 0; /* Ensure literal pool references are only accepted if LIT_POOL_OK. */ --- 2202,2208 ---- /* This check makes sure that no symbolic address (except literal pool references) are accepted by the R or T constraints. */ ! if (s390_loadrelative_operand_p (op, NULL, NULL)) return 0; /* Ensure literal pool references are only accepted if LIT_POOL_OK. */ *************** s390_check_symref_alignment (rtx addr, H *** 3022,3039 **** HOST_WIDE_INT addend; rtx symref; ! /* Accept symbol@GOTENT with pointer size alignment. */ ! if (GET_CODE (addr) == CONST ! && GET_CODE (XEXP (addr, 0)) == UNSPEC ! && XINT (XEXP (addr, 0), 1) == UNSPEC_GOTENT ! && alignment <= UNITS_PER_LONG) ! return true; ! if (!s390_symref_operand_p (addr, &symref, &addend)) return false; ! return (!SYMBOL_REF_NOT_NATURALLY_ALIGNED_P (symref) ! && !(addend & (alignment - 1))); } /* ADDR is moved into REG using larl. If ADDR isn't a valid larl --- 3009,3029 ---- HOST_WIDE_INT addend; rtx symref; ! if (!s390_loadrelative_operand_p (addr, &symref, &addend)) ! return false; ! if (addend & (alignment - 1)) return false; ! if (GET_CODE (symref) == SYMBOL_REF ! && !SYMBOL_REF_NOT_NATURALLY_ALIGNED_P (symref)) ! return true; ! ! if (GET_CODE (symref) == UNSPEC ! && alignment <= UNITS_PER_LONG) ! return true; ! ! return false; } /* ADDR is moved into REG using larl. If ADDR isn't a valid larl *************** s390_reload_larl_operand (rtx reg, rtx a *** 3046,3052 **** HOST_WIDE_INT addend; rtx symref; ! if (!s390_symref_operand_p (addr, &symref, &addend)) gcc_unreachable (); if (!(addend & 1)) --- 3036,3042 ---- HOST_WIDE_INT addend; rtx symref; ! if (!s390_loadrelative_operand_p (addr, &symref, &addend)) gcc_unreachable (); if (!(addend & 1)) *************** s390_secondary_reload (bool in_p, rtx x, *** 3132,3138 **** /* On z10 several optimizer steps may generate larl operands with an odd addend. */ if (in_p ! && s390_symref_operand_p (x, &symref, &offset) && mode == Pmode && !SYMBOL_REF_ALIGN1_P (symref) && (offset & 1) == 1) --- 3122,3128 ---- /* On z10 several optimizer steps may generate larl operands with an odd addend. */ if (in_p ! && s390_loadrelative_operand_p (x, &symref, &offset) && mode == Pmode && !SYMBOL_REF_ALIGN1_P (symref) && (offset & 1) == 1) *************** s390_secondary_reload (bool in_p, rtx x, *** 3144,3150 **** or if the symref addend of a SI or DI move is not aligned to the width of the access. */ if (MEM_P (x) ! && s390_symref_operand_p (XEXP (x, 0), NULL, NULL) && (mode == QImode || mode == TImode || FLOAT_MODE_P (mode) || (!TARGET_ZARCH && mode == DImode) || ((mode == HImode || mode == SImode || mode == DImode) --- 3134,3140 ---- or if the symref addend of a SI or DI move is not aligned to the width of the access. */ if (MEM_P (x) ! && s390_loadrelative_operand_p (XEXP (x, 0), NULL, NULL) && (mode == QImode || mode == TImode || FLOAT_MODE_P (mode) || (!TARGET_ZARCH && mode == DImode) || ((mode == HImode || mode == SImode || mode == DImode) *************** rtx *** 3419,3470 **** legitimize_pic_address (rtx orig, rtx reg) { rtx addr = orig; rtx new_rtx = orig; - rtx base; gcc_assert (!TLS_SYMBOLIC_CONST (addr)); ! if (GET_CODE (addr) == LABEL_REF ! || (GET_CODE (addr) == SYMBOL_REF && SYMBOL_REF_LOCAL_P (addr))) { ! /* This is a local symbol. */ ! if (TARGET_CPU_ZARCH && larl_operand (addr, VOIDmode)) ! { ! /* Access local symbols PC-relative via LARL. ! This is the same as in the non-PIC case, so it is ! handled automatically ... */ ! } else ! { ! /* Access local symbols relative to the GOT. */ ! rtx temp = reg? reg : gen_reg_rtx (Pmode); if (reload_in_progress || reload_completed) df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true); ! addr = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_GOTOFF); ! addr = gen_rtx_CONST (Pmode, addr); ! addr = force_const_mem (Pmode, addr); emit_move_insn (temp, addr); ! new_rtx = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, temp); ! if (reg != 0) ! { ! s390_load_address (reg, new_rtx); ! new_rtx = reg; ! } ! } } ! else if (GET_CODE (addr) == SYMBOL_REF) { if (reg == 0) reg = gen_reg_rtx (Pmode); ! if (flag_pic == 1) { ! /* Assume GOT offset < 4k. This is handled the same way ! in both 31- and 64-bit code (@GOT). */ if (reload_in_progress || reload_completed) df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true); --- 3409,3533 ---- legitimize_pic_address (rtx orig, rtx reg) { rtx addr = orig; + rtx addend = const0_rtx; rtx new_rtx = orig; gcc_assert (!TLS_SYMBOLIC_CONST (addr)); ! if (GET_CODE (addr) == CONST) ! addr = XEXP (addr, 0); ! ! if (GET_CODE (addr) == PLUS) { ! addend = XEXP (addr, 1); ! addr = XEXP (addr, 0); ! } ! ! if ((GET_CODE (addr) == LABEL_REF ! || (GET_CODE (addr) == SYMBOL_REF && SYMBOL_REF_LOCAL_P (addr)) ! || (GET_CODE (addr) == UNSPEC && ! (XINT (addr, 1) == UNSPEC_GOTENT ! || (TARGET_CPU_ZARCH && XINT (addr, 1) == UNSPEC_PLT)))) ! && GET_CODE (addend) == CONST_INT) ! { ! /* This can be locally addressed. */ ! ! /* larl_operand requires UNSPECs to be wrapped in a const rtx. */ ! rtx const_addr = (GET_CODE (addr) == UNSPEC ? ! gen_rtx_CONST (Pmode, addr) : addr); ! ! if (TARGET_CPU_ZARCH ! && larl_operand (const_addr, VOIDmode) ! && INTVAL (addend) < (HOST_WIDE_INT)1 << 31 ! && INTVAL (addend) >= -((HOST_WIDE_INT)1 << 31)) ! { ! if (INTVAL (addend) & 1) ! { ! /* LARL can't handle odd offsets, so emit a pair of LARL ! and LA. */ ! rtx temp = reg? reg : gen_reg_rtx (Pmode); ! ! if (!DISP_IN_RANGE (INTVAL (addend))) ! { ! HOST_WIDE_INT even = INTVAL (addend) - 1; ! addr = gen_rtx_PLUS (Pmode, addr, GEN_INT (even)); ! addr = gen_rtx_CONST (Pmode, addr); ! addend = const1_rtx; ! } ! ! emit_move_insn (temp, addr); ! new_rtx = gen_rtx_PLUS (Pmode, temp, addend); ! ! if (reg != 0) ! { ! s390_load_address (reg, new_rtx); ! new_rtx = reg; ! } ! } ! else ! { ! /* If the offset is even, we can just use LARL. This ! will happen automatically. */ ! } ! } else ! { ! /* No larl - Access local symbols relative to the GOT. */ ! rtx temp = reg? reg : gen_reg_rtx (Pmode); if (reload_in_progress || reload_completed) df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true); ! addr = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_GOTOFF); ! if (addend != const0_rtx) ! addr = gen_rtx_PLUS (Pmode, addr, addend); ! addr = gen_rtx_CONST (Pmode, addr); ! addr = force_const_mem (Pmode, addr); emit_move_insn (temp, addr); ! new_rtx = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, temp); ! if (reg != 0) ! { ! s390_load_address (reg, new_rtx); ! new_rtx = reg; ! } ! } } ! else if (GET_CODE (addr) == SYMBOL_REF && addend == const0_rtx) { + /* A non-local symbol reference without addend. + + The symbol ref is wrapped into an UNSPEC to make sure the + proper operand modifier (@GOT or @GOTENT) will be emitted. + This will tell the linker to put the symbol into the GOT. + + Additionally the code dereferencing the GOT slot is emitted here. + + An addend to the symref needs to be added afterwards. + legitimize_pic_address calls itself recursively to handle + that case. So no need to do it here. */ + if (reg == 0) reg = gen_reg_rtx (Pmode); ! if (TARGET_Z10) ! { ! /* Use load relative if possible. ! lgrl , sym@GOTENT */ ! new_rtx = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_GOTENT); ! new_rtx = gen_rtx_CONST (Pmode, new_rtx); ! new_rtx = gen_const_mem (GET_MODE (reg), new_rtx); ! ! emit_move_insn (reg, new_rtx); ! new_rtx = reg; ! } ! else if (flag_pic == 1) { ! /* Assume GOT offset is a valid displacement operand (< 4k ! or < 512k with z990). This is handled the same way in ! both 31- and 64-bit code (@GOT). ! lg , sym@GOT(r12) */ if (reload_in_progress || reload_completed) df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true); *************** legitimize_pic_address (rtx orig, rtx re *** 3479,3485 **** else if (TARGET_CPU_ZARCH) { /* If the GOT offset might be >= 4k, we determine the position ! of the GOT entry via a PC-relative LARL (@GOTENT). */ rtx temp = reg ? reg : gen_reg_rtx (Pmode); --- 3542,3550 ---- else if (TARGET_CPU_ZARCH) { /* If the GOT offset might be >= 4k, we determine the position ! of the GOT entry via a PC-relative LARL (@GOTENT). ! larl temp, sym@GOTENT ! lg , 0(temp) */ rtx temp = reg ? reg : gen_reg_rtx (Pmode); *************** legitimize_pic_address (rtx orig, rtx re *** 3488,3508 **** new_rtx = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_GOTENT); new_rtx = gen_rtx_CONST (Pmode, new_rtx); ! if (!TARGET_Z10) ! { ! emit_move_insn (temp, new_rtx); ! new_rtx = gen_const_mem (Pmode, temp); ! } ! else ! new_rtx = gen_const_mem (GET_MODE (reg), new_rtx); emit_move_insn (reg, new_rtx); new_rtx = reg; } else { /* If the GOT offset might be >= 4k, we have to load it ! from the literal pool (@GOT). */ rtx temp = reg ? reg : gen_reg_rtx (Pmode); --- 3553,3573 ---- new_rtx = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_GOTENT); new_rtx = gen_rtx_CONST (Pmode, new_rtx); + emit_move_insn (temp, new_rtx); ! new_rtx = gen_const_mem (Pmode, temp); emit_move_insn (reg, new_rtx); + new_rtx = reg; } else { /* If the GOT offset might be >= 4k, we have to load it ! from the literal pool (@GOT). ! ! lg temp, lit-litbase(r13) ! lg , 0(temp) ! lit: .long sym@GOT */ rtx temp = reg ? reg : gen_reg_rtx (Pmode); *************** legitimize_pic_address (rtx orig, rtx re *** 3523,3697 **** new_rtx = reg; } } ! else { ! if (GET_CODE (addr) == CONST) { ! addr = XEXP (addr, 0); ! if (GET_CODE (addr) == UNSPEC) ! { ! gcc_assert (XVECLEN (addr, 0) == 1); ! switch (XINT (addr, 1)) ! { ! /* If someone moved a GOT-relative UNSPEC ! out of the literal pool, force them back in. */ ! case UNSPEC_GOTOFF: ! case UNSPEC_PLTOFF: ! new_rtx = force_const_mem (Pmode, orig); ! break; ! ! /* @GOT is OK as is if small. */ ! case UNSPEC_GOT: ! if (flag_pic == 2) ! new_rtx = force_const_mem (Pmode, orig); ! break; ! ! /* @GOTENT is OK as is. */ ! case UNSPEC_GOTENT: ! break; ! ! /* @PLT is OK as is on 64-bit, must be converted to ! GOT-relative @PLTOFF on 31-bit. */ ! case UNSPEC_PLT: ! if (!TARGET_CPU_ZARCH) ! { ! rtx temp = reg? reg : gen_reg_rtx (Pmode); ! ! if (reload_in_progress || reload_completed) ! df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true); ! ! addr = XVECEXP (addr, 0, 0); ! addr = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), ! UNSPEC_PLTOFF); ! addr = gen_rtx_CONST (Pmode, addr); ! addr = force_const_mem (Pmode, addr); ! emit_move_insn (temp, addr); ! ! new_rtx = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, temp); ! if (reg != 0) ! { ! s390_load_address (reg, new_rtx); ! new_rtx = reg; ! } ! } ! break; ! ! /* Everything else cannot happen. */ ! default: ! gcc_unreachable (); ! } ! } ! else ! gcc_assert (GET_CODE (addr) == PLUS); ! } ! if (GET_CODE (addr) == PLUS) ! { ! rtx op0 = XEXP (addr, 0), op1 = XEXP (addr, 1); ! gcc_assert (!TLS_SYMBOLIC_CONST (op0)); ! gcc_assert (!TLS_SYMBOLIC_CONST (op1)); ! /* Check first to see if this is a constant offset ! from a local symbol reference. */ ! if ((GET_CODE (op0) == LABEL_REF ! || (GET_CODE (op0) == SYMBOL_REF && SYMBOL_REF_LOCAL_P (op0))) ! && GET_CODE (op1) == CONST_INT) ! { ! if (TARGET_CPU_ZARCH ! && larl_operand (op0, VOIDmode) ! && INTVAL (op1) < (HOST_WIDE_INT)1 << 31 ! && INTVAL (op1) >= -((HOST_WIDE_INT)1 << 31)) ! { ! if (INTVAL (op1) & 1) ! { ! /* LARL can't handle odd offsets, so emit a ! pair of LARL and LA. */ ! rtx temp = reg? reg : gen_reg_rtx (Pmode); ! ! if (!DISP_IN_RANGE (INTVAL (op1))) ! { ! HOST_WIDE_INT even = INTVAL (op1) - 1; ! op0 = gen_rtx_PLUS (Pmode, op0, GEN_INT (even)); ! op0 = gen_rtx_CONST (Pmode, op0); ! op1 = const1_rtx; ! } ! ! emit_move_insn (temp, op0); ! new_rtx = gen_rtx_PLUS (Pmode, temp, op1); ! ! if (reg != 0) ! { ! s390_load_address (reg, new_rtx); ! new_rtx = reg; ! } ! } ! else ! { ! /* If the offset is even, we can just use LARL. ! This will happen automatically. */ ! } ! } ! else ! { ! /* Access local symbols relative to the GOT. */ ! ! rtx temp = reg? reg : gen_reg_rtx (Pmode); ! ! if (reload_in_progress || reload_completed) ! df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true); ! ! addr = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, op0), ! UNSPEC_GOTOFF); ! addr = gen_rtx_PLUS (Pmode, addr, op1); ! addr = gen_rtx_CONST (Pmode, addr); ! addr = force_const_mem (Pmode, addr); ! emit_move_insn (temp, addr); ! ! new_rtx = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, temp); ! if (reg != 0) ! { ! s390_load_address (reg, new_rtx); ! new_rtx = reg; ! } ! } ! } ! ! /* Now, check whether it is a GOT relative symbol plus offset ! that was pulled out of the literal pool. Force it back in. */ ! ! else if (GET_CODE (op0) == UNSPEC ! && GET_CODE (op1) == CONST_INT ! && XINT (op0, 1) == UNSPEC_GOTOFF) ! { ! gcc_assert (XVECLEN (op0, 0) == 1); ! new_rtx = force_const_mem (Pmode, orig); ! } ! /* Otherwise, compute the sum. */ ! else ! { ! base = legitimize_pic_address (XEXP (addr, 0), reg); ! new_rtx = legitimize_pic_address (XEXP (addr, 1), ! base == reg ? NULL_RTX : reg); ! if (GET_CODE (new_rtx) == CONST_INT) ! new_rtx = plus_constant (Pmode, base, INTVAL (new_rtx)); ! else { ! if (GET_CODE (new_rtx) == PLUS && CONSTANT_P (XEXP (new_rtx, 1))) ! { ! base = gen_rtx_PLUS (Pmode, base, XEXP (new_rtx, 0)); ! new_rtx = XEXP (new_rtx, 1); ! } ! new_rtx = gen_rtx_PLUS (Pmode, base, new_rtx); } ! if (GET_CODE (new_rtx) == CONST) ! new_rtx = XEXP (new_rtx, 0); ! new_rtx = force_operand (new_rtx, 0); } } } return new_rtx; } --- 3588,3681 ---- new_rtx = reg; } } ! else if (GET_CODE (addr) == UNSPEC && GET_CODE (addend) == CONST_INT) { ! gcc_assert (XVECLEN (addr, 0) == 1); ! switch (XINT (addr, 1)) { ! /* These address symbols (or PLT slots) relative to the GOT ! (not GOT slots!). In general this will exceed the ! displacement range so these value belong into the literal ! pool. */ ! case UNSPEC_GOTOFF: ! case UNSPEC_PLTOFF: ! new_rtx = force_const_mem (Pmode, orig); ! break; ! /* For -fPIC the GOT size might exceed the displacement ! range so make sure the value is in the literal pool. */ ! case UNSPEC_GOT: ! if (flag_pic == 2) ! new_rtx = force_const_mem (Pmode, orig); ! break; ! /* For @GOTENT larl is used. This is handled like local ! symbol refs. */ ! case UNSPEC_GOTENT: ! gcc_unreachable (); ! break; ! /* @PLT is OK as is on 64-bit, must be converted to ! GOT-relative @PLTOFF on 31-bit. */ ! case UNSPEC_PLT: ! if (!TARGET_CPU_ZARCH) ! { ! rtx temp = reg? reg : gen_reg_rtx (Pmode); ! ! if (reload_in_progress || reload_completed) ! df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true); ! ! addr = XVECEXP (addr, 0, 0); ! addr = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), ! UNSPEC_PLTOFF); ! if (addend != const0_rtx) ! addr = gen_rtx_PLUS (Pmode, addr, addend); ! addr = gen_rtx_CONST (Pmode, addr); ! addr = force_const_mem (Pmode, addr); ! emit_move_insn (temp, addr); ! new_rtx = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, temp); ! if (reg != 0) { ! s390_load_address (reg, new_rtx); ! new_rtx = reg; } + } + else + /* On 64 bit larl can be used. This case is handled like + local symbol refs. */ + gcc_unreachable (); + break; + + /* Everything else cannot happen. */ + default: + gcc_unreachable (); + } + } + else if (addend != const0_rtx) + { + /* Otherwise, compute the sum. */ ! rtx base = legitimize_pic_address (addr, reg); ! new_rtx = legitimize_pic_address (addend, ! base == reg ? NULL_RTX : reg); ! if (GET_CODE (new_rtx) == CONST_INT) ! new_rtx = plus_constant (Pmode, base, INTVAL (new_rtx)); ! else ! { ! if (GET_CODE (new_rtx) == PLUS && CONSTANT_P (XEXP (new_rtx, 1))) ! { ! base = gen_rtx_PLUS (Pmode, base, XEXP (new_rtx, 0)); ! new_rtx = XEXP (new_rtx, 1); } + new_rtx = gen_rtx_PLUS (Pmode, base, new_rtx); } + + if (GET_CODE (new_rtx) == CONST) + new_rtx = XEXP (new_rtx, 0); + new_rtx = force_operand (new_rtx, 0); } + return new_rtx; } *************** print_operand_address (FILE *file, rtx a *** 5350,5356 **** { struct s390_address ad; ! if (s390_loadrelative_operand_p (addr)) { if (!TARGET_Z10) { --- 5334,5340 ---- { struct s390_address ad; ! if (s390_loadrelative_operand_p (addr, NULL, NULL)) { if (!TARGET_Z10) { Index: gcc/testsuite/gcc.target/s390/pr55718.c =================================================================== *** /dev/null --- gcc/testsuite/gcc.target/s390/pr55718.c *************** *** 0 **** --- 1,29 ---- + /* PR target/55717 */ + + /* { dg-do compile } */ + /* { dg-options "-O2 -march=z10 -fPIC" } */ + + extern char temp[]; + short ansi_value[256]; + void terminal_state(void) + { + static const char *puc[] = { "", "<", "=", ">", "?", 0}; + int i, j, k, l, modes_found; + char buf[256]; + k = (int) __builtin_strlen(temp); + for (j = l = 0; j < 255 && j - l < 50; j++) + { + __builtin_sprintf(temp, "\033[%s%d$p", puc[i], j); + if (ansi_value[1]) + { + l = j; + buf[k] = '\0'; + put_crlf(); + ptextln(buf); + buf[k++] = ' '; + k = (int) __builtin_strlen(temp); + } + } + for (i = j = 0; j < modes_found; j = ++i >> 1) + ; + }