From patchwork Mon Nov 11 14:43:41 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ulrich Weigand X-Patchwork-Id: 290339 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 1BAD62C008A for ; Tue, 12 Nov 2013 01:54:01 +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=OCb70kePPwf381yJ ReqO90l5+jKRq5NvEtN5gy/qqH/gVNFgKefYQhVtO1/sbhMmVdgU3uEvqqRew3xG n3iKs1xE4tDvY6s5Uo7F28m77gOPR0uBEfOOLDacbsTNw9amwHdN7OPy/JkaSIoo aUt7Jq5O93Id22luPcczfzu8tB8= 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=z/UY0hnYDRrwu97L9HcLmm lfqcE=; b=A8nEKImahCRiicGaFJ33/8Zv5CzTpxmRQF11qQOAFVRMhWwyfzFUG4 LxYU1s+V6p0dmCjmBdVEh2ysxicpk1sK9NHF0bVTdkIefA/YNsaPzSdVySXMVscq vJK75yP/Gx6QuQiI7ue59CLgJmD7T+rL0UuxuOKb/sCng1iKspz6k= Received: (qmail 15952 invoked by alias); 11 Nov 2013 14:46:31 -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 15916 invoked by uid 89); 11 Nov 2013 14:46:30 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-0.0 required=5.0 tests=AWL, BAYES_50, MSGID_FROM_MTA_HEADER, RDNS_NONE, SPF_PASS, URIBL_BLOCKED autolearn=no version=3.3.2 X-HELO: e06smtp16.uk.ibm.com Received: from Unknown (HELO e06smtp16.uk.ibm.com) (195.75.94.112) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES256-SHA encrypted) ESMTPS; Mon, 11 Nov 2013 14:45:10 +0000 Received: from /spool/local by e06smtp16.uk.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Mon, 11 Nov 2013 14:45:01 -0000 Received: from d06dlp01.portsmouth.uk.ibm.com (9.149.20.13) by e06smtp16.uk.ibm.com (192.168.101.146) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; Mon, 11 Nov 2013 14:44:59 -0000 Received: from b06cxnps4076.portsmouth.uk.ibm.com (d06relay13.portsmouth.uk.ibm.com [9.149.109.198]) by d06dlp01.portsmouth.uk.ibm.com (Postfix) with ESMTP id EDF8F17D8067 for ; Mon, 11 Nov 2013 14:44:38 +0000 (GMT) Received: from d06av02.portsmouth.uk.ibm.com (d06av02.portsmouth.uk.ibm.com [9.149.37.228]) by b06cxnps4076.portsmouth.uk.ibm.com (8.13.8/8.13.8/NCO v10.0) with ESMTP id rABEhVMH54198474 for ; Mon, 11 Nov 2013 14:43:31 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 rABEhhru012513 for ; Mon, 11 Nov 2013 07:43:43 -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 rABEhg2e012422 for ; Mon, 11 Nov 2013 07:43:42 -0700 Message-Id: <201311111443.rABEhg2e012422@d06av02.portsmouth.uk.ibm.com> Received: by tuxmaker.boeblingen.de.ibm.com (sSMTP sendmail emulation); Mon, 11 Nov 2013 15:43:41 +0100 Subject: [PATCH, rs6000] ELFv2 ABI 6/8: Eliminate register save area in some cases To: gcc-patches@gcc.gnu.org Date: Mon, 11 Nov 2013 15:43:41 +0100 (CET) From: "Ulrich Weigand" MIME-Version: 1.0 X-TM-AS-MML: disable X-Content-Scanned: Fidelis XPS MAILER x-cbid: 13111114-3548-0000-0000-0000071B40F7 Hello, the final area of changes implemented by the ELFv2 ABI is stack space consumption. Reducing the miminum stack size requirements is important for environments where stack space is restricted, e.g. Linux kernel code, or where we have a large number of stacks (e.g. heavily multi-threaded applications). One reason for the large stack space requirement of the current ABI is that every caller must provide an argument save area of 64 bytes to its caller. This is actually useful in one specific case: if the called function uses variable arguments and constructs a va_list. Because of the way the ABI is designed, the callee can in this case simply store the 8 GPRs (potentially) carrying arguments into that save area, and is then guaranteed to have all function arguments in a linear arrangement on the stack, which makes a trivial va_arg implementation possible. If the callee is not vararg, this wouldn't really be necessary. However, if we were to skip that area then, vararg and non-vararg routines would have incompatible ABIs, which would make it impossible to generate code for a function call if the caller does not have a prototype of the called function. Therefore the old ABI requires the save area to be present always. With the new ABI, we wanted to retain the possibility of using a trivial va_arg implementation, and also the possibility of calling non-prototyped routines safely. However, even so, there is a set of cases where it is still not necessary to provide a save area: when calling a function we have a prototype for and know that it is neither vararg nor uses on-stack arguments. This patch implement this change by having REG_PARM_STACK_SPACE return a different value depending on whether the called routine requires on-stack arguments (and we have a prototype). There was one problem exposed by this change: rs6000_function_arg contained this piece of code: if (mode == BLKmode) mode = Pmode; which marked the mode of a GPR holding an incoming struct argument as Pmode. This is now causing a problem. When REG_PARM_STACK_SPACE returns 0, function.c must allocate a stack slot within the callee's frame to serve as DECL_RTL for the parameter. This is done in assign_parm_setup_block. This routine attempts to use the mode of the incoming register as the mode of that stack slot, if the sizes match. This means that the DECL_RTL for an argument of struct type may now have mode Pmode, even if that type cannot reliably be operated on in Pmode, which causes ICEs in several test cases for me. Note that when REG_PARM_STACK_SPACE is non-zero, this problem does not occur, because in this case, function.c allocates the stack slot for the parameter's DECL_RTL in the register save area, using a different function assign_parm_find_stack_rtl. *That* function will keep the mode as BLKmode even if the incoming register is in another mode. Removing the above two lines from rs6000_function_arg fixes this problem, and does not appear to introduce any problem for the ELFv1 ABI case either (full bootstrap / regtest still passes). Looking back at the ChangeLog, those two lines where added by Alan Modra back in 2004: http://gcc.gnu.org/ml/gcc/2004-11/msg00617.html to fix ICEs after a change by Richard Henderson: http://gcc.gnu.org/ml/gcc/2004-11/msg00569.html but Richard shortly afterwards reverted that change again since it caused problems elsewhere too: http://gcc.gnu.org/ml/gcc/2004-11/msg00751.html So all in all, it seems this change by Alan was simply not necessary and can be reverted. Bye, Ulrich ChangeLog: 2013-11-11 Ulrich Weigand Alan Modra * config/rs6000/rs6000-protos.h (rs6000_reg_parm_stack_space): Add prototype. * config/rs6000/rs6000.h (RS6000_REG_SAVE): Remove. (REG_PARM_STACK_SPACE): Call rs6000_reg_parm_stack_space. * config/rs6000/rs6000.c (rs6000_parm_needs_stack): New function. (rs6000_function_parms_need_stack): Likewise. (rs6000_reg_parm_stack_space): Likewise. (rs6000_function_arg): Do not replace BLKmode by Pmode when returning a register argument. Index: gcc/gcc/config/rs6000/rs6000-protos.h =================================================================== --- gcc.orig/gcc/config/rs6000/rs6000-protos.h +++ gcc/gcc/config/rs6000/rs6000-protos.h @@ -158,6 +158,7 @@ extern tree altivec_resolve_overloaded_b extern rtx rs6000_libcall_value (enum machine_mode); extern rtx rs6000_va_arg (tree, tree); extern int function_ok_for_sibcall (tree); +extern int rs6000_reg_parm_stack_space (tree); extern void rs6000_elf_declare_function_name (FILE *, const char *, tree); extern bool rs6000_elf_in_small_data_p (const_tree); #ifdef ARGS_SIZE_RTX Index: gcc/gcc/config/rs6000/rs6000.h =================================================================== --- gcc.orig/gcc/config/rs6000/rs6000.h +++ gcc/gcc/config/rs6000/rs6000.h @@ -1527,10 +1527,6 @@ extern enum reg_class rs6000_constraints #define FRAME_GROWS_DOWNWARD (flag_stack_protect != 0 \ || (flag_sanitize & SANITIZE_ADDRESS) != 0) -/* Size of the outgoing register save area */ -#define RS6000_REG_SAVE \ - ((DEFAULT_ABI == ABI_V4 ? 0 : 32) << (TARGET_64BIT ? 1 : 0)) - /* Size of the fixed area on the stack */ #define RS6000_SAVE_AREA \ ((DEFAULT_ABI == ABI_V4 ? 8 : 24) << (TARGET_64BIT ? 1 : 0)) @@ -1588,7 +1584,7 @@ extern enum reg_class rs6000_constraints /* Define this if stack space is still allocated for a parameter passed in a register. The value is the number of bytes allocated to this area. */ -#define REG_PARM_STACK_SPACE(FNDECL) RS6000_REG_SAVE +#define REG_PARM_STACK_SPACE(FNDECL) rs6000_reg_parm_stack_space((FNDECL)) /* Define this if the above stack space is to be considered part of the space allocated by the caller. */ Index: gcc/gcc/config/rs6000/rs6000.c =================================================================== --- gcc.orig/gcc/config/rs6000/rs6000.c +++ gcc/gcc/config/rs6000/rs6000.c @@ -10093,9 +10093,6 @@ rs6000_function_arg (cumulative_args_t c if (TARGET_32BIT && TARGET_POWERPC64) return rs6000_mixed_function_arg (mode, type, align_words); - if (mode == BLKmode) - mode = Pmode; - return gen_rtx_REG (mode, GP_ARG_MIN_REG + align_words); } else @@ -10250,6 +10247,139 @@ rs6000_pass_by_reference (cumulative_arg return 0; } +/* Process parameter of type TYPE after ARGS_SO_FAR parameters were + already processes. Return true if the parameter must be passed + (fully or partially) on the stack. */ + +static bool +rs6000_parm_needs_stack (cumulative_args_t args_so_far, tree type) +{ + enum machine_mode mode; + int unsignedp; + rtx entry_parm; + + /* Catch errors. */ + if (type == NULL || type == error_mark_node) + return true; + + /* Handle types with no storage requirement. */ + if (TYPE_MODE (type) == VOIDmode) + return false; + + /* Handle complex types. */ + if (TREE_CODE (type) == COMPLEX_TYPE) + return (rs6000_parm_needs_stack (args_so_far, TREE_TYPE (type)) + || rs6000_parm_needs_stack (args_so_far, TREE_TYPE (type))); + + /* Handle transparent aggregates. */ + if ((TREE_CODE (type) == UNION_TYPE || TREE_CODE (type) == RECORD_TYPE) + && TYPE_TRANSPARENT_AGGR (type)) + type = TREE_TYPE (first_field (type)); + + /* See if this arg was passed by invisible reference. */ + if (pass_by_reference (get_cumulative_args (args_so_far), + TYPE_MODE (type), type, true)) + type = build_pointer_type (type); + + /* Find mode as it is passed by the ABI. */ + unsignedp = TYPE_UNSIGNED (type); + mode = promote_mode (type, TYPE_MODE (type), &unsignedp); + + /* If we must pass in stack, we need a stack. */ + if (rs6000_must_pass_in_stack (mode, type)) + return true; + + /* If there is no incoming register, we need a stack. */ + entry_parm = rs6000_function_arg (args_so_far, mode, type, true); + if (entry_parm == NULL) + return true; + + /* Likewise if we need to pass both in registers and on the stack. */ + if (GET_CODE (entry_parm) == PARALLEL + && XEXP (XVECEXP (entry_parm, 0, 0), 0) == NULL_RTX) + return true; + + /* Also true if we're partially in registers and partially not. */ + if (rs6000_arg_partial_bytes (args_so_far, mode, type, true) != 0) + return true; + + /* Update info on where next arg arrives in registers. */ + rs6000_function_arg_advance (args_so_far, mode, type, true); + return false; +} + +/* Return true if FUN has no prototype, has a variable argument + list, or passes any parameter in memory. */ + +static bool +rs6000_function_parms_need_stack (tree fun) +{ + function_args_iterator args_iter; + tree arg_type; + CUMULATIVE_ARGS args_so_far_v; + cumulative_args_t args_so_far; + + if (!fun) + /* Must be a libcall, all of which only use reg parms. */ + return false; + if (!TYPE_P (fun)) + fun = TREE_TYPE (fun); + + /* Varargs functions need the parameter save area. */ + if (!prototype_p (fun) || stdarg_p (fun)) + return true; + + INIT_CUMULATIVE_INCOMING_ARGS (args_so_far_v, fun, NULL_RTX); + args_so_far = pack_cumulative_args (&args_so_far_v); + + if (aggregate_value_p (TREE_TYPE (fun), fun)) + { + tree type = build_pointer_type (TREE_TYPE (fun)); + rs6000_parm_needs_stack (args_so_far, type); + } + + FOREACH_FUNCTION_ARGS (fun, arg_type, args_iter) + if (rs6000_parm_needs_stack (args_so_far, arg_type)) + return true; + + return false; +} + +/* Return the size of the REG_PARM_STACK_SPACE are for FUN. This is + usually a constant depending on the ABI. However, in the ELFv2 ABI + the register parameter area is optional when calling a function that + has a prototype is scope, has no variable argument list, and passes + all parameters in registers. */ + +int +rs6000_reg_parm_stack_space (tree fun) +{ + int reg_parm_stack_space; + + switch (DEFAULT_ABI) + { + default: + reg_parm_stack_space = 0; + break; + + case ABI_AIX: + case ABI_DARWIN: + reg_parm_stack_space = TARGET_64BIT ? 64 : 32; + break; + + case ABI_ELFv2: + /* ??? Recomputing this every time is a bit expensive. Is there + a place to cache this information? */ + if (rs6000_function_parms_need_stack (fun)) + reg_parm_stack_space = TARGET_64BIT ? 64 : 32; + else + reg_parm_stack_space = 0; + break; + } + + return reg_parm_stack_space; +} + static void rs6000_move_block_from_reg (int regno, rtx x, int nregs) {