From patchwork Tue Mar 29 13:22:25 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric Botcazou X-Patchwork-Id: 88768 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 EE52AB6EF7 for ; Wed, 30 Mar 2011 00:27:52 +1100 (EST) Received: (qmail 23851 invoked by alias); 29 Mar 2011 13:27:49 -0000 Received: (qmail 23513 invoked by uid 22791); 29 Mar 2011 13:27:43 -0000 X-SWARE-Spam-Status: No, hits=-1.9 required=5.0 tests=AWL,BAYES_00 X-Spam-Check-By: sourceware.org Received: from mel.act-europe.fr (HELO mel.act-europe.fr) (194.98.77.210) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Tue, 29 Mar 2011 13:27:35 +0000 Received: from localhost (localhost [127.0.0.1]) by filtered-smtp.eu.adacore.com (Postfix) with ESMTP id EBCC4CB0348 for ; Tue, 29 Mar 2011 15:27:33 +0200 (CEST) Received: from mel.act-europe.fr ([127.0.0.1]) by localhost (smtp.eu.adacore.com [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id jp+hcIvCFXKO for ; Tue, 29 Mar 2011 15:27:30 +0200 (CEST) Received: from [192.168.1.2] (bon31-9-83-155-120-49.fbx.proxad.net [83.155.120.49]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by mel.act-europe.fr (Postfix) with ESMTP id 7772DCB0349 for ; Tue, 29 Mar 2011 15:27:30 +0200 (CEST) From: Eric Botcazou To: gcc-patches@gcc.gnu.org Subject: [patch] Introduce -Wstack-usage Date: Tue, 29 Mar 2011 15:22:25 +0200 User-Agent: KMail/1.9.9 MIME-Version: 1.0 Message-Id: <201103291522.25419.ebotcazou@adacore.com> 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 Hi, in the wake of the -fstack-usage switch that was introduced in GCC 4.6, I'm proposing the associated -Wstack-usage warning. GCC already has had something related for quite some time: `-Wframe-larger-than=LEN' Warn if the size of a function frame is larger than LEN bytes. The computation done to determine the stack frame size is approximate and not conservative. The actual requirements may be somewhat greater than LEN even if you do not get a warning. In addition, any space allocated via `alloca', variable-length arrays, or related constructs is not included by the compiler when determining whether or not to issue a warning. but, as said above, the computation is approximate and doesn't take into account various constructs. On the contrary, since the implementation of -fstack-usage was designed to be conservative, implementing -Wstack-usage on top of it also yields conservative results. The warning messages are in keeping with the output of -fstack-usage. If the stack usage is fully static but exceeds the specified amount, it's: warning: stack usage is 1120 bytes [-Wstack-usage=] If the stack usage is (partly) dynamic but bounded, it's: warning: stack usage might be 1648 bytes [-Wstack-usage=] If the stack usage is (partly) dynamic and not bounded, it's: warning: stack usage might be unbounded [-Wstack-usage=] Tested on i586-suse-linux, OK for the mainline? 2011-03-29 Eric Botcazou * common.opt (flag_stack_usage_info): New variable. (-Wstack-usage): New option. * doc/invoke.texi (Warning options): Document -Wstack-usage. * opts.c (common_handle_option) : New case. : Likewise. * toplev.c (output_stack_usage): Deal with -Wstack-usage. * calls.c (expand_call): Test flag_stack_usage_info variable instead of flag_stack_usage. (emit_library_call_value_1): Likewise. * explow.c (allocate_dynamic_stack_space): Likewise. * function.c (instantiate_virtual_regs ): Likewise. (prepare_function_start): Likewise. (rest_of_handle_thread_prologue_and_epilogue): Likewise. * config/alpha/alpha.c (alpha_expand_prologue): Likewise. * config/arm/arm.c (arm_expand_prologue): Likewise. (thumb1_expand_prologue): Likewise. * config/avr/avr.c (expand_prologue): Likewise. * config/i386/i386.c (ix86_expand_prologue): Likewise. * config/ia64/ia64.c (ia64_expand_prologue): Likewise. * config/mips/mips.c (mips_expand_prologue): Likewise. * config/pa/pa.c (hppa_expand_prologue): Likewise. * config/rs6000/rs6000.c (rs6000_emit_prologue): Likewise. * config/s390/s390.c (s390_emit_prologue): Likewise. * config/sh/sh.c (sh_expand_prologue): Likewise. * config/sparc/sparc.c (sparc_expand_prologue): Likewise. * config/spu/spu.c (spu_expand_prologue): Likewise. 2011-03-29 Eric Botcazou * gcc.dg/stack-usage-2.c: New test. Index: doc/invoke.texi =================================================================== --- doc/invoke.texi (revision 171572) +++ doc/invoke.texi (working copy) @@ -260,7 +260,7 @@ Objective-C and Objective-C++ Dialects}. -Wredundant-decls @gol -Wreturn-type -Wsequence-point -Wshadow @gol -Wsign-compare -Wsign-conversion -Wstack-protector @gol --Wstrict-aliasing -Wstrict-aliasing=n @gol +-Wstack-usage=@var{len} -Wstrict-aliasing -Wstrict-aliasing=n @gol -Wstrict-overflow -Wstrict-overflow=@var{n} @gol -Wsuggest-attribute=@r{[}pure@r{|}const@r{|}noreturn@r{]} @gol -Wswitch -Wswitch-default -Wswitch-enum -Wsync-nand @gol @@ -3922,6 +3922,14 @@ via @code{alloca}, variable-length array is not included by the compiler when determining whether or not to issue a warning. +@item -Wstack-usage=@var{len} +@opindex Wstack-usage +Warn if the stack usage of a function might be larger than @var{len} bytes. +The computation done to determine the stack usage is conservative. +Any space allocated via @code{alloca}, variable-length arrays, or related +constructs is included by the compiler when determining whether or not to +issue a warning. + @item -Wunsafe-loop-optimizations @opindex Wunsafe-loop-optimizations @opindex Wno-unsafe-loop-optimizations Index: toplev.c =================================================================== --- toplev.c (revision 171572) +++ toplev.c (working copy) @@ -1048,14 +1048,12 @@ output_stack_usage (void) }; HOST_WIDE_INT stack_usage = current_function_static_stack_size; enum stack_usage_kind_type stack_usage_kind; - expanded_location loc; - const char *raw_id, *id; if (stack_usage < 0) { if (!warning_issued) { - warning (0, "-fstack-usage not supported for this target"); + warning (0, "stack usage computation not supported for this target"); warning_issued = true; } return; @@ -1082,24 +1080,44 @@ output_stack_usage (void) stack_usage += current_function_dynamic_stack_size; } - loc = expand_location (DECL_SOURCE_LOCATION (current_function_decl)); + if (flag_stack_usage) + { + expanded_location loc + = expand_location (DECL_SOURCE_LOCATION (current_function_decl)); + const char *raw_id, *id; + + /* Strip the scope prefix if any. */ + raw_id = lang_hooks.decl_printable_name (current_function_decl, 2); + id = strrchr (raw_id, '.'); + if (id) + id++; + else + id = raw_id; + + fprintf (stack_usage_file, + "%s:%d:%d:%s\t"HOST_WIDE_INT_PRINT_DEC"\t%s\n", + lbasename (loc.file), + loc.line, + loc.column, + id, + stack_usage, + stack_usage_kind_str[stack_usage_kind]); + } - /* Strip the scope prefix if any. */ - raw_id = lang_hooks.decl_printable_name (current_function_decl, 2); - id = strrchr (raw_id, '.'); - if (id) - id++; - else - id = raw_id; - - fprintf (stack_usage_file, - "%s:%d:%d:%s\t"HOST_WIDE_INT_PRINT_DEC"\t%s\n", - lbasename (loc.file), - loc.line, - loc.column, - id, - stack_usage, - stack_usage_kind_str[stack_usage_kind]); + if (warn_stack_usage >= 0) + { + if (stack_usage_kind == DYNAMIC) + warning (OPT_Wstack_usage_, "stack usage might be unbounded"); + else if (stack_usage > warn_stack_usage) + { + if (stack_usage_kind == DYNAMIC_BOUNDED) + warning (OPT_Wstack_usage_, "stack usage might be %wd bytes", + stack_usage); + else + warning (OPT_Wstack_usage_, "stack usage is %wd bytes", + stack_usage); + } + } } /* Open an auxiliary output file. */ Index: opts.c =================================================================== --- opts.c (revision 171572) +++ opts.c (working copy) @@ -1410,6 +1410,11 @@ common_handle_option (struct gcc_options opts->x_warn_frame_larger_than = value != -1; break; + case OPT_Wstack_usage_: + opts->x_warn_stack_usage = value; + opts->x_flag_stack_usage_info = value != -1; + break; + case OPT_Wstrict_aliasing: set_Wstrict_aliasing (opts, value); break; @@ -1631,6 +1636,11 @@ common_handle_option (struct gcc_options /* Deferred. */ break; + case OPT_fstack_usage: + opts->x_flag_stack_usage = value; + opts->x_flag_stack_usage_info = value != 0; + break; + case OPT_ftree_vectorizer_verbose_: vect_set_verbosity_level (opts, value); break; Index: function.c =================================================================== --- function.c (revision 171572) +++ function.c (working copy) @@ -1940,7 +1940,7 @@ instantiate_virtual_regs (void) /* See allocate_dynamic_stack_space for the rationale. */ #ifdef SETJMP_VIA_SAVE_AREA - if (flag_stack_usage && cfun->calls_setjmp) + if (flag_stack_usage_info && cfun->calls_setjmp) { int align = PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT; dynamic_offset = (dynamic_offset + align - 1) / align * align; @@ -4437,7 +4437,7 @@ prepare_function_start (void) init_expr (); default_rtl_profile (); - if (flag_stack_usage) + if (flag_stack_usage_info) { cfun->su = ggc_alloc_cleared_stack_usage (); cfun->su->static_stack_size = -1; @@ -5881,7 +5881,7 @@ rest_of_handle_thread_prologue_and_epilo thread_prologue_and_epilogue_insns (); /* The stack usage info is finalized during prologue expansion. */ - if (flag_stack_usage) + if (flag_stack_usage_info) output_stack_usage (); return 0; Index: calls.c =================================================================== --- calls.c (revision 171572) +++ calls.c (working copy) @@ -2505,7 +2505,7 @@ expand_call (tree exp, rtx target, int i stack_arg_under_construction = 0; } argblock = push_block (ARGS_SIZE_RTX (adjusted_args_size), 0, 0); - if (flag_stack_usage) + if (flag_stack_usage_info) current_function_has_unbounded_dynamic_stack_size = 1; } else @@ -2714,7 +2714,7 @@ expand_call (tree exp, rtx target, int i /* Record the maximum pushed stack space size. We need to delay doing it this far to take into account the optimization done by combine_pending_stack_adjustment_and_call. */ - if (flag_stack_usage + if (flag_stack_usage_info && !ACCUMULATE_OUTGOING_ARGS && pass && adjusted_args_size.var == 0) @@ -3579,7 +3579,7 @@ emit_library_call_value_1 (int retval, r if (args_size.constant > crtl->outgoing_args_size) crtl->outgoing_args_size = args_size.constant; - if (flag_stack_usage && !ACCUMULATE_OUTGOING_ARGS) + if (flag_stack_usage_info && !ACCUMULATE_OUTGOING_ARGS) { int pushed = args_size.constant + pending_stack_adjust; if (pushed > current_function_pushed_stack_size) Index: explow.c =================================================================== --- explow.c (revision 171572) +++ explow.c (working copy) @@ -1128,7 +1128,7 @@ allocate_dynamic_stack_space (rtx size, /* If stack usage info is requested, look into the size we are passed. We need to do so this early to avoid the obfuscation that may be introduced later by the various alignment operations. */ - if (flag_stack_usage) + if (flag_stack_usage_info) { if (CONST_INT_P (size)) stack_usage_size = INTVAL (size); @@ -1220,7 +1220,7 @@ allocate_dynamic_stack_space (rtx size, size = plus_constant (size, extra); size = force_operand (size, NULL_RTX); - if (flag_stack_usage) + if (flag_stack_usage_info) stack_usage_size += extra; if (extra && size_align > extra_align) @@ -1251,7 +1251,7 @@ allocate_dynamic_stack_space (rtx size, /* The above dynamic offset cannot be computed statically at this point, but it will be possible to do so after RTL expansion is done. Record how many times we will need to add it. */ - if (flag_stack_usage) + if (flag_stack_usage_info) current_function_dynamic_alloc_count++; /* ??? Can we infer a minimum of STACK_BOUNDARY here? */ @@ -1276,7 +1276,7 @@ allocate_dynamic_stack_space (rtx size, { size = round_push (size); - if (flag_stack_usage) + if (flag_stack_usage_info) { int align = crtl->preferred_stack_boundary / BITS_PER_UNIT; stack_usage_size = (stack_usage_size + align - 1) / align * align; @@ -1287,7 +1287,7 @@ allocate_dynamic_stack_space (rtx size, /* The size is supposed to be fully adjusted at this point so record it if stack usage info is requested. */ - if (flag_stack_usage) + if (flag_stack_usage_info) { current_function_dynamic_stack_size += stack_usage_size; Index: common.opt =================================================================== --- common.opt (revision 171572) +++ common.opt (working copy) @@ -138,6 +138,10 @@ enum vect_verbosity_levels user_vect_ver Variable enum stack_check_type flag_stack_check = NO_STACK_CHECK +; True if stack usage information needs to be computed. +Variable +bool flag_stack_usage_info = false + ; -dA causes debug commentary information to be produced in ; the generated assembly code (to make it more readable). This option ; is generally only of use to those who actually need to read the @@ -566,6 +570,10 @@ Wstack-protector Common Var(warn_stack_protect) Warning Warn when not issuing stack smashing protection for some reason +Wstack-usage= +Common Joined RejectNegative UInteger Var(warn_stack_usage) Init(-1) Warning +Warn if stack usage might be larger than specified amount + Wstrict-aliasing Common Warning Warn about code which might break strict aliasing rules Index: config/alpha/alpha.c =================================================================== --- config/alpha/alpha.c (revision 171572) +++ config/alpha/alpha.c (working copy) @@ -7531,7 +7531,7 @@ alpha_expand_prologue (void) sa_size = alpha_sa_size (); frame_size = compute_frame_size (get_frame_size (), sa_size); - if (flag_stack_usage) + if (flag_stack_usage_info) current_function_static_stack_size = frame_size; if (TARGET_ABI_OPEN_VMS) Index: config/s390/s390.c =================================================================== --- config/s390/s390.c (revision 171572) +++ config/s390/s390.c (working copy) @@ -8097,7 +8097,7 @@ s390_emit_prologue (void) if (!TARGET_PACKED_STACK) next_fpr = cfun_save_high_fprs_p ? 31 : 0; - if (flag_stack_usage) + if (flag_stack_usage_info) current_function_static_stack_size = cfun_frame_layout.frame_size; /* Decrement stack pointer. */ Index: config/spu/spu.c =================================================================== --- config/spu/spu.c (revision 171572) +++ config/spu/spu.c (working copy) @@ -2093,7 +2093,7 @@ spu_expand_prologue (void) } } - if (flag_stack_usage) + if (flag_stack_usage_info) current_function_static_stack_size = total_size; } Index: config/sparc/sparc.c =================================================================== --- config/sparc/sparc.c (revision 171572) +++ config/sparc/sparc.c (working copy) @@ -4562,7 +4562,7 @@ sparc_expand_prologue (void) /* Advertise that the data calculated just above are now valid. */ sparc_prologue_data_valid_p = true; - if (flag_stack_usage) + if (flag_stack_usage_info) current_function_static_stack_size = actual_fsize; if (flag_stack_check == STATIC_BUILTIN_STACK_CHECK && actual_fsize) Index: config/i386/i386.c =================================================================== --- config/i386/i386.c (revision 171572) +++ config/i386/i386.c (working copy) @@ -10540,7 +10540,7 @@ ix86_expand_prologue (void) allocate = frame.stack_pointer_offset - m->fs.sp_offset; - if (flag_stack_usage) + if (flag_stack_usage_info) { /* We start to count from ARG_POINTER. */ HOST_WIDE_INT stack_size = frame.stack_pointer_offset; Index: config/sh/sh.c =================================================================== --- config/sh/sh.c (revision 171572) +++ config/sh/sh.c (working copy) @@ -7345,7 +7345,7 @@ sh_expand_prologue (void) emit_insn (gen_shcompact_incoming_args ()); } - if (flag_stack_usage) + if (flag_stack_usage_info) current_function_static_stack_size = stack_usage; } Index: config/avr/avr.c =================================================================== --- config/avr/avr.c (revision 171572) +++ config/avr/avr.c (working copy) @@ -869,7 +869,7 @@ expand_prologue (void) } } - if (flag_stack_usage) + if (flag_stack_usage_info) current_function_static_stack_size = cfun->machine->stack_usage; } Index: config/ia64/ia64.c =================================================================== --- config/ia64/ia64.c (revision 171572) +++ config/ia64/ia64.c (working copy) @@ -3184,7 +3184,7 @@ ia64_expand_prologue (void) ia64_compute_frame_size (get_frame_size ()); last_scratch_gr_reg = 15; - if (flag_stack_usage) + if (flag_stack_usage_info) current_function_static_stack_size = current_frame_info.total_size; if (dump_file) Index: config/rs6000/rs6000.c =================================================================== --- config/rs6000/rs6000.c (revision 171572) +++ config/rs6000/rs6000.c (working copy) @@ -20451,7 +20451,7 @@ rs6000_emit_prologue (void) && call_used_regs[STATIC_CHAIN_REGNUM]); HOST_WIDE_INT sp_offset = 0; - if (flag_stack_usage) + if (flag_stack_usage_info) current_function_static_stack_size = info->total_size; if (flag_stack_check == STATIC_BUILTIN_STACK_CHECK && info->total_size) Index: config/arm/arm.c =================================================================== --- config/arm/arm.c (revision 171572) +++ config/arm/arm.c (working copy) @@ -15972,7 +15972,7 @@ arm_expand_prologue (void) } } - if (flag_stack_usage) + if (flag_stack_usage_info) current_function_static_stack_size = offsets->outgoing_args - offsets->saved_args; @@ -20788,7 +20788,7 @@ thumb1_expand_prologue (void) emit_move_insn (gen_rtx_REG (Pmode, ARM_HARD_FRAME_POINTER_REGNUM), stack_pointer_rtx); - if (flag_stack_usage) + if (flag_stack_usage_info) current_function_static_stack_size = offsets->outgoing_args - offsets->saved_args; Index: config/pa/pa.c =================================================================== --- config/pa/pa.c (revision 171572) +++ config/pa/pa.c (working copy) @@ -3845,7 +3845,7 @@ hppa_expand_prologue (void) local_fsize += STARTING_FRAME_OFFSET; actual_fsize = compute_frame_size (size, &save_fregs); - if (flag_stack_usage) + if (flag_stack_usage_info) current_function_static_stack_size = actual_fsize; /* Compute a few things we will use often. */ Index: config/mips/mips.c =================================================================== --- config/mips/mips.c (revision 171572) +++ config/mips/mips.c (working copy) @@ -10080,7 +10080,7 @@ mips_expand_prologue (void) frame = &cfun->machine->frame; size = frame->total_size; - if (flag_stack_usage) + if (flag_stack_usage_info) current_function_static_stack_size = size; /* Save the registers. Allocate up to MIPS_MAX_FIRST_STACK_STEP