From patchwork Mon Nov 11 14:35:42 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ulrich Weigand X-Patchwork-Id: 290318 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]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 9389C2C00AA for ; Tue, 12 Nov 2013 01:39:26 +1100 (EST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :message-id:subject:to:date:from:mime-version:content-type :content-transfer-encoding; q=dns; s=default; b=gaoP4pzhSDJy3uPh Uzg9e2fI+2iNOkAy5NQAcc6DQYPPERVPh6fZ+X9lG2MHrDtmEse2QBdaAWOHlAqD f47LdO4laVK/UQdhw1VyTfbiTMSpSsBRH0E3BYPo6zpIQejDLw7xgUlHcrSTnYiN 72MAhpDJRYhgJm+e0JLWvdITQik= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :message-id:subject:to:date:from:mime-version:content-type :content-transfer-encoding; s=default; bh=DcgIXpt6QnxYFJXYEPhMby aHrl0=; b=RAbJGe+IhDl+Lxl0LVwXDhRyOoEu8KW1dNCPexmqJHlQ6jR0KYzPKS INXuhYOlhRXXyMPVuulZbHa2fTvhTADWPYvIEOJ7pV1oRAShlROLiwZBy9aLENNj dmILyy6khjz1/DJxbI3hVslpAoRwd7MoT98wldsEPOsg0AD2wbJYU= Received: (qmail 25351 invoked by alias); 11 Nov 2013 14:37:13 -0000 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 Received: (qmail 25325 invoked by uid 89); 11 Nov 2013 14:37:12 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=0.7 required=5.0 tests=AWL, BAYES_50, KAM_STOCKGEN, MSGID_FROM_MTA_HEADER, RDNS_NONE, SPF_PASS, URIBL_BLOCKED autolearn=no version=3.3.2 X-HELO: e06smtp10.uk.ibm.com Received: from Unknown (HELO e06smtp10.uk.ibm.com) (195.75.94.106) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES256-SHA encrypted) ESMTPS; Mon, 11 Nov 2013 14:37:10 +0000 Received: from /spool/local by e06smtp10.uk.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Mon, 11 Nov 2013 14:37:00 -0000 Received: from d06dlp01.portsmouth.uk.ibm.com (9.149.20.13) by e06smtp10.uk.ibm.com (192.168.101.140) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; Mon, 11 Nov 2013 14:36:59 -0000 Received: from b06cxnps3074.portsmouth.uk.ibm.com (d06relay09.portsmouth.uk.ibm.com [9.149.109.194]) by d06dlp01.portsmouth.uk.ibm.com (Postfix) with ESMTP id 24C9A17D8067 for ; Mon, 11 Nov 2013 14:36:39 +0000 (GMT) Received: from d06av02.portsmouth.uk.ibm.com (d06av02.portsmouth.uk.ibm.com [9.149.37.228]) by b06cxnps3074.portsmouth.uk.ibm.com (8.13.8/8.13.8/NCO v10.0) with ESMTP id rABEZW0U53608636 for ; Mon, 11 Nov 2013 14:35:32 GMT Received: from d06av02.portsmouth.uk.ibm.com (localhost [127.0.0.1]) by d06av02.portsmouth.uk.ibm.com (8.14.4/8.14.4/NCO v10.0 AVout) with ESMTP id rABEZioq023270 for ; Mon, 11 Nov 2013 07:35:44 -0700 Received: from tuxmaker.boeblingen.de.ibm.com (tuxmaker.boeblingen.de.ibm.com [9.152.85.9]) by d06av02.portsmouth.uk.ibm.com (8.14.4/8.14.4/NCO v10.0 AVin) with SMTP id rABEZgh4023245 for ; Mon, 11 Nov 2013 07:35:42 -0700 Message-Id: <201311111435.rABEZgh4023245@d06av02.portsmouth.uk.ibm.com> Received: by tuxmaker.boeblingen.de.ibm.com (sSMTP sendmail emulation); Mon, 11 Nov 2013 15:35:42 +0100 Subject: [PATCH, rs6000] ELFv2 ABI preparation: Refactor call expanders To: gcc-patches@gcc.gnu.org Date: Mon, 11 Nov 2013 15:35:42 +0100 (CET) From: "Ulrich Weigand" MIME-Version: 1.0 X-TM-AS-MML: disable X-Content-Scanned: Fidelis XPS MAILER x-cbid: 13111114-4966-0000-0000-00000776FA37 Hello, this patch refactors code to expand calls in preparation for adding support for the new little-endian ABI. Currently, the call expanders always generate the same RTX pattern, which is matched by different insns patterns depending on circumstances (ABI, local vs. global calls, ...). This makes it difficult if in some of these circumstances, we'd really need a different RTX pattern, e.g. becuase the call uses certain special registers, or because the call must perform extra actions like saving or restoring the TOC pointer. There is one exception to this logic already in place: when expanding an indirect call on ABI_AIX, the expander calls a routine in rs6000.c. This patch expands on that by handling *all* calls (including sibling calls) on ABI_AIX via a routine in rs6000.c. This should be fully transparent to generated code, although generated RTL is a bit different: we use CALL_INSN_FUNCTION_USAGE to track uses of ABI-defined registers by the call, which has a couple of other advantages: - we can remove some patterns that were duplicated solely to track whether or not a call uses r11; - we can simply the sibcall patterns so they no longer explicitly refer to LR_REGNO; - we can precisely track which calls use r2 to ensure we have correct data flow for the register (this doesn't actually matter for the current code, but will become necessary with the new ABI). Tested on powerpc64-linux and powerpc64le-linux. OK for mainline? Bye, Ulrich ChangeLog: 2013-11-11 Ulrich Weigand * config/rs6000/rs6000.c (rs6000_call_indirect_aix): Rename to ... (rs6000_call_aix): ... this. Handle both direct and indirect calls. Create call insn directly instead of via various gen_... routines. Mention special registers used by the call in CALL_INSN_FUNCTION_USAGE. (rs6000_sibcall_aix): New function. * config/rs6000/rs6000.md (TOC_SAVE_OFFSET_32BIT): Remove. (TOC_SAVE_OFFSET_64BIT): Likewise. (AIX_FUNC_DESC_TOC_32BIT): Likewise. (AIX_FUNC_DESC_TOC_64BIT): Likewise. (AIX_FUNC_DESC_SC_32BIT): Likewise. (AIX_FUNC_DESC_SC_64BIT): Likewise. ("call" expander): Call rs6000_call_aix. ("call_value" expander): Likewise. ("call_indirect_aix"): Replace this pattern ... ("call_indirect_aix_nor11"): ... and this pattern ... ("*call_indirect_aix"): ... by this insn pattern. ("call_value_indirect_aix"): Replace this pattern ... ("call_value_indirect_aix_nor11"): ... and this pattern ... ("*call_value_indirect_aix"): ... by this insn pattern. ("*call_nonlocal_aix32", "*call_nonlocal_aix64"): Replace by ... ("*call_nonlocal_aix"): ... this pattern. ("*call_value_nonlocal_aix32", "*call_value_nonlocal_aix64"): Replace ("*call_value_nonlocal_aix"): ... by this pattern. ("*call_local_aix"): New insn pattern. ("*call_value_local_aix"): Likewise. ("sibcall" expander): Call rs6000_sibcall_aix. ("sibcall_value" expander): Likewise. Move earlier in file. ("*sibcall_nonlocal_aix"): Replace by ... ("*sibcall_aix"): ... this pattern. ("*sibcall_value_nonlocal_aix"): Replace by ... ("*sibcall_value_aix"): ... this pattern. * config/rs6000/rs6000-protos.h (rs6000_call_indirect_aix): Remove. (rs6000_call_aix): Add prototype. (rs6000_sibcall_aix): Likewise. Index: gcc/gcc/config/rs6000/rs6000.c =================================================================== --- gcc.orig/gcc/config/rs6000/rs6000.c +++ gcc/gcc/config/rs6000/rs6000.c @@ -30599,118 +30599,138 @@ rs6000_legitimate_constant_p (enum machi } -/* A function pointer under AIX is a pointer to a data area whose first word - contains the actual address of the function, whose second word contains a - pointer to its TOC, and whose third word contains a value to place in the - static chain register (r11). Note that if we load the static chain, our - "trampoline" need not have any executable code. */ + +/* Expand code to perform a call under the AIX ABI. */ void -rs6000_call_indirect_aix (rtx value, rtx func_desc, rtx flag) +rs6000_call_aix (rtx value, rtx func_desc, rtx flag, rtx cookie) { + rtx toc_reg = gen_rtx_REG (Pmode, TOC_REGNUM); + rtx toc_load = NULL_RTX; + rtx toc_restore = NULL_RTX; rtx func_addr; - rtx toc_reg; - rtx sc_reg; - rtx stack_ptr; - rtx stack_toc_offset; - rtx stack_toc_mem; - rtx func_toc_offset; - rtx func_toc_mem; - rtx func_sc_offset; - rtx func_sc_mem; + rtx abi_reg = NULL_RTX; + rtx call[4]; + int n_call; rtx insn; - rtx (*call_func) (rtx, rtx, rtx, rtx); - rtx (*call_value_func) (rtx, rtx, rtx, rtx, rtx); - - stack_ptr = gen_rtx_REG (Pmode, STACK_POINTER_REGNUM); - toc_reg = gen_rtx_REG (Pmode, TOC_REGNUM); - /* Load up address of the actual function. */ - func_desc = force_reg (Pmode, func_desc); - func_addr = gen_reg_rtx (Pmode); - emit_move_insn (func_addr, gen_rtx_MEM (Pmode, func_desc)); + /* Handle longcall attributes. */ + if (INTVAL (cookie) & CALL_LONG) + func_desc = rs6000_longcall_ref (func_desc); + + /* Handle indirect calls. */ + if (GET_CODE (func_desc) != SYMBOL_REF + || !SYMBOL_REF_FUNCTION_P (func_desc)) + { + /* Save the TOC into its reserved slot before the call, + and prepare to restore it after the call. */ + rtx stack_ptr = gen_rtx_REG (Pmode, STACK_POINTER_REGNUM); + rtx stack_toc_offset = GEN_INT (5 * GET_MODE_SIZE (Pmode)); + rtx stack_toc_mem = gen_frame_mem (Pmode, + gen_rtx_PLUS (Pmode, stack_ptr, + stack_toc_offset)); + toc_restore = gen_rtx_SET (VOIDmode, toc_reg, stack_toc_mem); + + /* Can we optimize saving the TOC in the prologue or + do we need to do it at every call? */ + if (TARGET_SAVE_TOC_INDIRECT && !cfun->calls_alloca) + cfun->machine->save_toc_in_prologue = true; + else + { + MEM_VOLATILE_P (stack_toc_mem) = 1; + emit_move_insn (stack_toc_mem, toc_reg); + } - if (TARGET_32BIT) - { + /* A function pointer under AIX is a pointer to a data area whose + first word contains the actual address of the function, whose + second word contains a pointer to its TOC, and whose third word + contains a value to place in the static chain register (r11). + Note that if we load the static chain, our "trampoline" need + not have any executable code. */ + + /* Load up address of the actual function. */ + func_desc = force_reg (Pmode, func_desc); + func_addr = gen_reg_rtx (Pmode); + emit_move_insn (func_addr, gen_rtx_MEM (Pmode, func_desc)); + + /* Prepare to load the TOC of the called function. Note that the + TOC load must happen immediately before the actual call so + that unwinding the TOC registers works correctly. See the + comment in frob_update_context. */ + rtx func_toc_offset = GEN_INT (GET_MODE_SIZE (Pmode)); + rtx func_toc_mem = gen_rtx_MEM (Pmode, + gen_rtx_PLUS (Pmode, func_desc, + func_toc_offset)); + toc_load = gen_rtx_USE (VOIDmode, func_toc_mem); - stack_toc_offset = GEN_INT (TOC_SAVE_OFFSET_32BIT); - func_toc_offset = GEN_INT (AIX_FUNC_DESC_TOC_32BIT); - func_sc_offset = GEN_INT (AIX_FUNC_DESC_SC_32BIT); + /* If we have a static chain, load it up. */ if (TARGET_POINTERS_TO_NESTED_FUNCTIONS) { - call_func = gen_call_indirect_aix32bit; - call_value_func = gen_call_value_indirect_aix32bit; - } - else - { - call_func = gen_call_indirect_aix32bit_nor11; - call_value_func = gen_call_value_indirect_aix32bit_nor11; + rtx sc_reg = gen_rtx_REG (Pmode, STATIC_CHAIN_REGNUM); + rtx func_sc_offset = GEN_INT (2 * GET_MODE_SIZE (Pmode)); + rtx func_sc_mem = gen_rtx_MEM (Pmode, + gen_rtx_PLUS (Pmode, func_desc, + func_sc_offset)); + emit_move_insn (sc_reg, func_sc_mem); + abi_reg = sc_reg; } } else { - stack_toc_offset = GEN_INT (TOC_SAVE_OFFSET_64BIT); - func_toc_offset = GEN_INT (AIX_FUNC_DESC_TOC_64BIT); - func_sc_offset = GEN_INT (AIX_FUNC_DESC_SC_64BIT); - if (TARGET_POINTERS_TO_NESTED_FUNCTIONS) - { - call_func = gen_call_indirect_aix64bit; - call_value_func = gen_call_value_indirect_aix64bit; - } - else - { - call_func = gen_call_indirect_aix64bit_nor11; - call_value_func = gen_call_value_indirect_aix64bit_nor11; - } + /* Direct calls use the TOC: for local calls, the callee will + assume the TOC register is set; for non-local calls, the + PLT stub needs the TOC register. */ + abi_reg = toc_reg; + func_addr = func_desc; } - /* Reserved spot to store the TOC. */ - stack_toc_mem = gen_frame_mem (Pmode, - gen_rtx_PLUS (Pmode, - stack_ptr, - stack_toc_offset)); + /* Create the call. */ + call[0] = gen_rtx_CALL (VOIDmode, gen_rtx_MEM (SImode, func_addr), flag); + if (value != NULL_RTX) + call[0] = gen_rtx_SET (VOIDmode, value, call[0]); + n_call = 1; - gcc_assert (cfun); - gcc_assert (cfun->machine); + if (toc_load) + call[n_call++] = toc_load; + if (toc_restore) + call[n_call++] = toc_restore; - /* Can we optimize saving the TOC in the prologue or do we need to do it at - every call? */ - if (TARGET_SAVE_TOC_INDIRECT && !cfun->calls_alloca) - cfun->machine->save_toc_in_prologue = true; + call[n_call++] = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (Pmode, LR_REGNO)); - else - { - MEM_VOLATILE_P (stack_toc_mem) = 1; - emit_move_insn (stack_toc_mem, toc_reg); - } + insn = gen_rtx_PARALLEL (VOIDmode, gen_rtvec_v (n_call, call)); + insn = emit_call_insn (insn); - /* Calculate the address to load the TOC of the called function. We don't - actually load this until the split after reload. */ - func_toc_mem = gen_rtx_MEM (Pmode, - gen_rtx_PLUS (Pmode, - func_desc, - func_toc_offset)); - - /* If we have a static chain, load it up. */ - if (TARGET_POINTERS_TO_NESTED_FUNCTIONS) - { - func_sc_mem = gen_rtx_MEM (Pmode, - gen_rtx_PLUS (Pmode, - func_desc, - func_sc_offset)); + /* Mention all registers defined by the ABI to hold information + as uses in CALL_INSN_FUNCTION_USAGE. */ + if (abi_reg) + use_reg (&CALL_INSN_FUNCTION_USAGE (insn), abi_reg); +} - sc_reg = gen_rtx_REG (Pmode, STATIC_CHAIN_REGNUM); - emit_move_insn (sc_reg, func_sc_mem); - } +/* Expand code to perform a sibling call under the AIX ABI. */ - /* Create the call. */ - if (value) - insn = call_value_func (value, func_addr, flag, func_toc_mem, - stack_toc_mem); - else - insn = call_func (func_addr, flag, func_toc_mem, stack_toc_mem); +void +rs6000_sibcall_aix (rtx value, rtx func_desc, rtx flag, rtx cookie) +{ + rtx call[2]; + rtx insn; + + gcc_assert (INTVAL (cookie) == 0); - emit_call_insn (insn); + /* Create the call. */ + call[0] = gen_rtx_CALL (VOIDmode, gen_rtx_MEM (SImode, func_desc), flag); + if (value != NULL_RTX) + call[0] = gen_rtx_SET (VOIDmode, value, call[0]); + + call[1] = simple_return_rtx; + + insn = gen_rtx_PARALLEL (VOIDmode, gen_rtvec_v (2, call)); + insn = emit_call_insn (insn); + + /* Note use of the TOC register. */ + use_reg (&CALL_INSN_FUNCTION_USAGE (insn), gen_rtx_REG (Pmode, TOC_REGNUM)); + /* We need to also mark a use of the link register since the function we + sibling-call to will use it to return to our caller. */ + use_reg (&CALL_INSN_FUNCTION_USAGE (insn), gen_rtx_REG (Pmode, LR_REGNO)); } /* Return whether we need to always update the saved TOC pointer when we update Index: gcc/gcc/config/rs6000/rs6000.md =================================================================== --- gcc.orig/gcc/config/rs6000/rs6000.md +++ gcc/gcc/config/rs6000/rs6000.md @@ -56,18 +56,6 @@ (TFHAR_REGNO 114) (TFIAR_REGNO 115) (TEXASR_REGNO 116) - - ; ABI defined stack offsets for storing the TOC pointer with AIX calls. - (TOC_SAVE_OFFSET_32BIT 20) - (TOC_SAVE_OFFSET_64BIT 40) - - ; Function TOC offset in the AIX function descriptor. - (AIX_FUNC_DESC_TOC_32BIT 4) - (AIX_FUNC_DESC_TOC_64BIT 8) - - ; Static chain offset in the AIX function descriptor. - (AIX_FUNC_DESC_SC_32BIT 8) - (AIX_FUNC_DESC_SC_64BIT 16) ]) ;; @@ -12109,8 +12097,13 @@ operands[0] = XEXP (operands[0], 0); + if (DEFAULT_ABI == ABI_AIX) + { + rs6000_call_aix (NULL_RTX, operands[0], operands[1], operands[2]); + DONE; + } + if (GET_CODE (operands[0]) != SYMBOL_REF - || (DEFAULT_ABI == ABI_AIX && !SYMBOL_REF_FUNCTION_P (operands[0])) || (DEFAULT_ABI != ABI_DARWIN && (INTVAL (operands[2]) & CALL_LONG) != 0)) { if (INTVAL (operands[2]) & CALL_LONG) @@ -12123,12 +12116,6 @@ operands[0] = force_reg (Pmode, operands[0]); break; - case ABI_AIX: - /* AIX function pointers are really pointers to a three word - area. */ - rs6000_call_indirect_aix (NULL_RTX, operands[0], operands[1]); - DONE; - default: gcc_unreachable (); } @@ -12154,8 +12141,13 @@ operands[1] = XEXP (operands[1], 0); + if (DEFAULT_ABI == ABI_AIX) + { + rs6000_call_aix (operands[0], operands[1], operands[2], operands[3]); + DONE; + } + if (GET_CODE (operands[1]) != SYMBOL_REF - || (DEFAULT_ABI == ABI_AIX && !SYMBOL_REF_FUNCTION_P (operands[1])) || (DEFAULT_ABI != ABI_DARWIN && (INTVAL (operands[3]) & CALL_LONG) != 0)) { if (INTVAL (operands[3]) & CALL_LONG) @@ -12168,12 +12160,6 @@ operands[1] = force_reg (Pmode, operands[1]); break; - case ABI_AIX: - /* AIX function pointers are really pointers to a three word - area. */ - rs6000_call_indirect_aix (operands[0], operands[1], operands[2]); - DONE; - default: gcc_unreachable (); } @@ -12265,135 +12251,6 @@ [(set_attr "type" "branch") (set_attr "length" "4,8")]) -;; Call to indirect functions with the AIX abi using a 3 word descriptor. -;; Operand0 is the addresss of the function to call -;; Operand1 is the flag for System V.4 for unprototyped or FP registers -;; Operand2 is the location in the function descriptor to load r2 from -;; Operand3 is the stack location to hold the current TOC pointer - -(define_insn "call_indirect_aix" - [(call (mem:SI (match_operand:P 0 "register_operand" "c,*l")) - (match_operand 1 "" "g,g")) - (use (match_operand:P 2 "memory_operand" ",")) - (set (reg:P TOC_REGNUM) (match_operand:P 3 "memory_operand" ",")) - (use (reg:P STATIC_CHAIN_REGNUM)) - (clobber (reg:P LR_REGNO))] - "DEFAULT_ABI == ABI_AIX && TARGET_POINTERS_TO_NESTED_FUNCTIONS" - " 2,%2\;b%T0l\; 2,%3" - [(set_attr "type" "jmpreg") - (set_attr "length" "12")]) - -;; Like call_indirect_aix, but no use of the static chain -;; Operand0 is the addresss of the function to call -;; Operand1 is the flag for System V.4 for unprototyped or FP registers -;; Operand2 is the location in the function descriptor to load r2 from -;; Operand3 is the stack location to hold the current TOC pointer - -(define_insn "call_indirect_aix_nor11" - [(call (mem:SI (match_operand:P 0 "register_operand" "c,*l")) - (match_operand 1 "" "g,g")) - (use (match_operand:P 2 "memory_operand" ",")) - (set (reg:P TOC_REGNUM) (match_operand:P 3 "memory_operand" ",")) - (clobber (reg:P LR_REGNO))] - "DEFAULT_ABI == ABI_AIX && !TARGET_POINTERS_TO_NESTED_FUNCTIONS" - " 2,%2\;b%T0l\; 2,%3" - [(set_attr "type" "jmpreg") - (set_attr "length" "12")]) - -;; Operand0 is the return result of the function -;; Operand1 is the addresss of the function to call -;; Operand2 is the flag for System V.4 for unprototyped or FP registers -;; Operand3 is the location in the function descriptor to load r2 from -;; Operand4 is the stack location to hold the current TOC pointer - -(define_insn "call_value_indirect_aix" - [(set (match_operand 0 "" "") - (call (mem:SI (match_operand:P 1 "register_operand" "c,*l")) - (match_operand 2 "" "g,g"))) - (use (match_operand:P 3 "memory_operand" ",")) - (set (reg:P TOC_REGNUM) (match_operand:P 4 "memory_operand" ",")) - (use (reg:P STATIC_CHAIN_REGNUM)) - (clobber (reg:P LR_REGNO))] - "DEFAULT_ABI == ABI_AIX && TARGET_POINTERS_TO_NESTED_FUNCTIONS" - " 2,%3\;b%T1l\; 2,%4" - [(set_attr "type" "jmpreg") - (set_attr "length" "12")]) - -;; Like call_value_indirect_aix, but no use of the static chain -;; Operand0 is the return result of the function -;; Operand1 is the addresss of the function to call -;; Operand2 is the flag for System V.4 for unprototyped or FP registers -;; Operand3 is the location in the function descriptor to load r2 from -;; Operand4 is the stack location to hold the current TOC pointer - -(define_insn "call_value_indirect_aix_nor11" - [(set (match_operand 0 "" "") - (call (mem:SI (match_operand:P 1 "register_operand" "c,*l")) - (match_operand 2 "" "g,g"))) - (use (match_operand:P 3 "memory_operand" ",")) - (set (reg:P TOC_REGNUM) (match_operand:P 4 "memory_operand" ",")) - (clobber (reg:P LR_REGNO))] - "DEFAULT_ABI == ABI_AIX && !TARGET_POINTERS_TO_NESTED_FUNCTIONS" - " 2,%3\;b%T1l\; 2,%4" - [(set_attr "type" "jmpreg") - (set_attr "length" "12")]) - -;; Call to function which may be in another module. Restore the TOC -;; pointer (r2) after the call unless this is System V. -;; Operand2 is nonzero if we are using the V.4 calling sequence and -;; either the function was not prototyped, or it was prototyped as a -;; variable argument function. It is > 0 if FP registers were passed -;; and < 0 if they were not. - -(define_insn "*call_nonlocal_aix32" - [(call (mem:SI (match_operand:SI 0 "symbol_ref_operand" "s")) - (match_operand 1 "" "g")) - (use (match_operand:SI 2 "immediate_operand" "O")) - (clobber (reg:SI LR_REGNO))] - "TARGET_32BIT - && DEFAULT_ABI == ABI_AIX - && (INTVAL (operands[2]) & CALL_LONG) == 0" - "bl %z0\;nop" - [(set_attr "type" "branch") - (set_attr "length" "8")]) - -(define_insn "*call_nonlocal_aix64" - [(call (mem:SI (match_operand:DI 0 "symbol_ref_operand" "s")) - (match_operand 1 "" "g")) - (use (match_operand:SI 2 "immediate_operand" "O")) - (clobber (reg:SI LR_REGNO))] - "TARGET_64BIT - && DEFAULT_ABI == ABI_AIX - && (INTVAL (operands[2]) & CALL_LONG) == 0" - "bl %z0\;nop" - [(set_attr "type" "branch") - (set_attr "length" "8")]) - -(define_insn "*call_value_nonlocal_aix32" - [(set (match_operand 0 "" "") - (call (mem:SI (match_operand:SI 1 "symbol_ref_operand" "s")) - (match_operand 2 "" "g"))) - (use (match_operand:SI 3 "immediate_operand" "O")) - (clobber (reg:SI LR_REGNO))] - "TARGET_32BIT - && DEFAULT_ABI == ABI_AIX - && (INTVAL (operands[3]) & CALL_LONG) == 0" - "bl %z1\;nop" - [(set_attr "type" "branch") - (set_attr "length" "8")]) - -(define_insn "*call_value_nonlocal_aix64" - [(set (match_operand 0 "" "") - (call (mem:SI (match_operand:DI 1 "symbol_ref_operand" "s")) - (match_operand 2 "" "g"))) - (use (match_operand:SI 3 "immediate_operand" "O")) - (clobber (reg:SI LR_REGNO))] - "TARGET_64BIT - && DEFAULT_ABI == ABI_AIX - && (INTVAL (operands[3]) & CALL_LONG) == 0" - "bl %z1\;nop" - [(set_attr "type" "branch") - (set_attr "length" "8")]) ;; A function pointer under System V is just a normal pointer ;; operands[0] is the function pointer @@ -12576,6 +12433,79 @@ [(set_attr "type" "branch,branch") (set_attr "length" "4,8")]) + +;; Call to AIX abi function in the same module. + +(define_insn "*call_local_aix" + [(call (mem:SI (match_operand:P 0 "current_file_function_operand" "s")) + (match_operand 1 "" "g")) + (clobber (reg:P LR_REGNO))] + "DEFAULT_ABI == ABI_AIX" + "bl %z0" + [(set_attr "type" "branch") + (set_attr "length" "4")]) + +(define_insn "*call_value_local_aix" + [(set (match_operand 0 "" "") + (call (mem:SI (match_operand:P 1 "current_file_function_operand" "s")) + (match_operand 2 "" "g"))) + (clobber (reg:P LR_REGNO))] + "DEFAULT_ABI == ABI_AIX" + "bl %z1" + [(set_attr "type" "branch") + (set_attr "length" "4")]) + +;; Call to AIX abi function which may be in another module. +;; Restore the TOC pointer (r2) after the call. + +(define_insn "*call_nonlocal_aix" + [(call (mem:SI (match_operand:P 0 "symbol_ref_operand" "s")) + (match_operand 1 "" "g")) + (clobber (reg:P LR_REGNO))] + "DEFAULT_ABI == ABI_AIX" + "bl %z0\;nop" + [(set_attr "type" "branch") + (set_attr "length" "8")]) + +(define_insn "*call_value_nonlocal_aix" + [(set (match_operand 0 "" "") + (call (mem:SI (match_operand:P 1 "symbol_ref_operand" "s")) + (match_operand 2 "" "g"))) + (clobber (reg:P LR_REGNO))] + "DEFAULT_ABI == ABI_AIX" + "bl %z1\;nop" + [(set_attr "type" "branch") + (set_attr "length" "8")]) + +;; Call to indirect functions with the AIX abi using a 3 word descriptor. +;; Operand0 is the addresss of the function to call +;; Operand2 is the location in the function descriptor to load r2 from +;; Operand3 is the stack location to hold the current TOC pointer + +(define_insn "*call_indirect_aix" + [(call (mem:SI (match_operand:P 0 "register_operand" "c,*l")) + (match_operand 1 "" "g,g")) + (use (match_operand:P 2 "memory_operand" ",")) + (set (reg:P TOC_REGNUM) (match_operand:P 3 "memory_operand" ",")) + (clobber (reg:P LR_REGNO))] + "DEFAULT_ABI == ABI_AIX" + " 2,%2\;b%T0l\; 2,%3" + [(set_attr "type" "jmpreg") + (set_attr "length" "12")]) + +(define_insn "*call_value_indirect_aix" + [(set (match_operand 0 "" "") + (call (mem:SI (match_operand:P 1 "register_operand" "c,*l")) + (match_operand 2 "" "g,g"))) + (use (match_operand:P 3 "memory_operand" ",")) + (set (reg:P TOC_REGNUM) (match_operand:P 4 "memory_operand" ",")) + (clobber (reg:P LR_REGNO))] + "DEFAULT_ABI == ABI_AIX" + " 2,%3\;b%T1l\; 2,%4" + [(set_attr "type" "jmpreg") + (set_attr "length" "12")]) + + ;; Call subroutine returning any type. (define_expand "untyped_call" [(parallel [(call (match_operand 0 "" "") @@ -12623,6 +12553,39 @@ gcc_assert (GET_CODE (operands[1]) == CONST_INT); operands[0] = XEXP (operands[0], 0); + + if (DEFAULT_ABI == ABI_AIX) + { + rs6000_sibcall_aix (NULL_RTX, operands[0], operands[1], operands[2]); + DONE; + } +}") + +(define_expand "sibcall_value" + [(parallel [(set (match_operand 0 "register_operand" "") + (call (mem:SI (match_operand 1 "address_operand" "")) + (match_operand 2 "" ""))) + (use (match_operand 3 "" "")) + (use (reg:SI LR_REGNO)) + (simple_return)])] + "" + " +{ +#if TARGET_MACHO + if (MACHOPIC_INDIRECT) + operands[1] = machopic_indirect_call_target (operands[1]); +#endif + + gcc_assert (GET_CODE (operands[1]) == MEM); + gcc_assert (GET_CODE (operands[2]) == CONST_INT); + + operands[1] = XEXP (operands[1], 0); + + if (DEFAULT_ABI == ABI_AIX) + { + rs6000_sibcall_aix (operands[0], operands[1], operands[2], operands[3]); + DONE; + } }") ;; this and similar patterns must be marked as using LR, otherwise @@ -12690,7 +12653,6 @@ [(set_attr "type" "branch") (set_attr "length" "4,8")]) - (define_insn "*sibcall_value_local64" [(set (match_operand 0 "" "") (call (mem:SI (match_operand:DI 1 "current_file_function_operand" "s,s")) @@ -12712,35 +12674,6 @@ [(set_attr "type" "branch") (set_attr "length" "4,8")]) -(define_insn "*sibcall_nonlocal_aix" - [(call (mem:SI (match_operand:P 0 "call_operand" "s,c")) - (match_operand 1 "" "g,g")) - (use (match_operand:SI 2 "immediate_operand" "O,O")) - (use (reg:SI LR_REGNO)) - (simple_return)] - "DEFAULT_ABI == ABI_AIX - && (INTVAL (operands[2]) & CALL_LONG) == 0" - "@ - b %z0 - b%T0" - [(set_attr "type" "branch") - (set_attr "length" "4")]) - -(define_insn "*sibcall_value_nonlocal_aix" - [(set (match_operand 0 "" "") - (call (mem:SI (match_operand:P 1 "call_operand" "s,c")) - (match_operand 2 "" "g,g"))) - (use (match_operand:SI 3 "immediate_operand" "O,O")) - (use (reg:SI LR_REGNO)) - (simple_return)] - "DEFAULT_ABI == ABI_AIX - && (INTVAL (operands[3]) & CALL_LONG) == 0" - "@ - b %z1 - b%T1" - [(set_attr "type" "branch") - (set_attr "length" "4")]) - (define_insn "*sibcall_nonlocal_sysv" [(call (mem:SI (match_operand:P 0 "call_operand" "s,s,c,c")) (match_operand 1 "" "")) @@ -12771,27 +12704,6 @@ [(set_attr "type" "branch") (set_attr "length" "4,8,4,8")]) -(define_expand "sibcall_value" - [(parallel [(set (match_operand 0 "register_operand" "") - (call (mem:SI (match_operand 1 "address_operand" "")) - (match_operand 2 "" ""))) - (use (match_operand 3 "" "")) - (use (reg:SI LR_REGNO)) - (simple_return)])] - "" - " -{ -#if TARGET_MACHO - if (MACHOPIC_INDIRECT) - operands[1] = machopic_indirect_call_target (operands[1]); -#endif - - gcc_assert (GET_CODE (operands[1]) == MEM); - gcc_assert (GET_CODE (operands[2]) == CONST_INT); - - operands[1] = XEXP (operands[1], 0); -}") - (define_insn "*sibcall_value_nonlocal_sysv" [(set (match_operand 0 "" "") (call (mem:SI (match_operand:P 1 "call_operand" "s,s,c,c")) @@ -12823,6 +12735,31 @@ [(set_attr "type" "branch") (set_attr "length" "4,8,4,8")]) +;; AIX ABI sibling call patterns. + +(define_insn "*sibcall_aix" + [(call (mem:SI (match_operand:P 0 "call_operand" "s,c")) + (match_operand 1 "" "g,g")) + (simple_return)] + "DEFAULT_ABI == ABI_AIX" + "@ + b %z0 + b%T0" + [(set_attr "type" "branch") + (set_attr "length" "4")]) + +(define_insn "*sibcall_value_aix" + [(set (match_operand 0 "" "") + (call (mem:SI (match_operand:P 1 "call_operand" "s,c")) + (match_operand 2 "" "g,g"))) + (simple_return)] + "DEFAULT_ABI == ABI_AIX" + "@ + b %z1 + b%T1" + [(set_attr "type" "branch") + (set_attr "length" "4")]) + (define_expand "sibcall_epilogue" [(use (const_int 0))] "" Index: gcc/gcc/config/rs6000/rs6000-protos.h =================================================================== --- gcc.orig/gcc/config/rs6000/rs6000-protos.h +++ gcc/gcc/config/rs6000/rs6000-protos.h @@ -182,7 +182,8 @@ extern unsigned int rs6000_dbx_register_ extern void rs6000_emit_epilogue (int); extern void rs6000_emit_eh_reg_restore (rtx, rtx); extern const char * output_isel (rtx *); -extern void rs6000_call_indirect_aix (rtx, rtx, rtx); +extern void rs6000_call_aix (rtx, rtx, rtx, rtx); +extern void rs6000_sibcall_aix (rtx, rtx, rtx, rtx); extern void rs6000_aix_asm_output_dwarf_table_ref (char *); extern void get_ppc476_thunk_name (char name[32]); extern bool rs6000_overloaded_builtin_p (enum rs6000_builtins);