From patchwork Sat Mar 30 17:11:35 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tom de Vries X-Patchwork-Id: 232538 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 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client CN "localhost", Issuer "www.qmailtoaster.com" (not verified)) by ozlabs.org (Postfix) with ESMTPS id 6417E2C007A for ; Sun, 31 Mar 2013 04:13:00 +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:from :to:cc:in-reply-to:subject:content-type:mime-version:message-id :date; q=dns; s=default; b=WFIhQvigCM8LkWUnA33HpeJaFsN7CMIRQLM3F m87mzsCVTtVX7shHd6NZHQ/DhWnwjgp3ztmbNGicHPQYx8OJYR9BgRXWTKJ0cEyQ kKuxuggcHIvKK9CPDVyK0lIfnqhR2QIaFzUb82jki4TJ386xIRaSfFjMuvgTNmht AXCKAY= 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:from :to:cc:in-reply-to:subject:content-type:mime-version:message-id :date; s=default; bh=MHKiOfnVlQmjHtsUfy76w5Iv6go=; b=YNR4HtHNqLZ BDJ20qmuX5Hxbhe1Yy9j0uKbTEnPmxhBJxhiZJUZcllUAq5r8dI3tPt8R9PPcy0p YLXEXOsFmb3OMG9qKB6fqCm49bW90WRjhEno9DkOGVOMozCcNldmDN7MQ8V3aU4N eNQGJunnBcI+AYInwqDnNY3Q+JzmcMgc= Received: (qmail 8749 invoked by alias); 30 Mar 2013 17:11:47 -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 8296 invoked by uid 89); 30 Mar 2013 17:11:40 -0000 X-Spam-SWARE-Status: No, score=-0.2 required=5.0 tests=AWL, BAYES_50, KAM_STOCKTIP, KHOP_RCVD_UNTRUST, KHOP_THREADED, RCVD_IN_HOSTKARMA_W, RCVD_IN_HOSTKARMA_WL, TW_FN autolearn=no version=3.3.1 Received: from relay1.mentorg.com (HELO relay1.mentorg.com) (192.94.38.131) by sourceware.org (qpsmtpd/0.84/v0.84-167-ge50287c) with ESMTP; Sat, 30 Mar 2013 17:11:38 +0000 Received: from svr-orw-exc-10.mgc.mentorg.com ([147.34.98.58]) by relay1.mentorg.com with esmtp id 1ULzJY-000385-9X from Tom_deVries@mentor.com ; Sat, 30 Mar 2013 10:11:36 -0700 Received: from SVR-ORW-FEM-03.mgc.mentorg.com ([147.34.97.39]) by SVR-ORW-EXC-10.mgc.mentorg.com with Microsoft SMTPSVC(6.0.3790.4675); Sat, 30 Mar 2013 10:11:36 -0700 Received: from build1-lucid-cs (147.34.91.1) by svr-orw-fem-03.mgc.mentorg.com (147.34.97.39) with Microsoft SMTP Server id 14.1.289.1; Sat, 30 Mar 2013 10:11:35 -0700 Received: by build1-lucid-cs (Postfix, from userid 49877) id 7AB32421213; Sat, 30 Mar 2013 10:11:35 -0700 (PDT) From: Tom de Vries To: Vladimir Makarov CC: gcc-patches In-Reply-To: <51558EF4.1030106@mentor.com> Subject: [PATCH][06/10] -fuse-caller-save - Collect register usage information MIME-Version: 1.0 Message-ID: <20130330171135.7AB32421213@build1-lucid-cs> Date: Sat, 30 Mar 2013 10:11:35 -0700 X-Virus-Found: No Vladimir, This patch adds analysis in pass_final to track which hard registers are set or clobbered by the function body, and stores that information in a struct cgraph_node. Thanks, -Tom 2013-03-30 Radovan Obradovic Tom de Vries * cgraph.h (struct cgraph_node): Add function_used_regs, function_used_regs_initialized and function_used_regs_valid fields. * final.c: Move include of hard-reg-set.h to before rtl.h to declare find_all_hard_reg_sets. (collect_fn_hard_reg_usage, get_call_fndecl, get_call_cgraph_node) (get_call_reg_set_usage): New function. (rest_of_handle_final): Use collect_fn_hard_reg_usage. diff --git a/gcc/cgraph.h b/gcc/cgraph.h index 8ab7ae1..2132d91 100644 --- a/gcc/cgraph.h +++ b/gcc/cgraph.h @@ -251,6 +251,15 @@ struct GTY(()) cgraph_node { /* Unique id of the node. */ int uid; + /* Call unsaved hard registers really used by the corresponding + function (including ones used by functions called by the + function). */ + HARD_REG_SET function_used_regs; + /* Set if function_used_regs is initialized. */ + unsigned function_used_regs_initialized: 1; + /* Set if function_used_regs is valid. */ + unsigned function_used_regs_valid: 1; + /* Set when decl is an abstract function pointed to by the ABSTRACT_DECL_ORIGIN of a reachable function. */ unsigned abstract_and_needed : 1; diff --git a/gcc/final.c b/gcc/final.c index d25b8e0..4e0fd01 100644 --- a/gcc/final.c +++ b/gcc/final.c @@ -48,6 +48,7 @@ along with GCC; see the file COPYING3. If not see #include "tm.h" #include "tree.h" +#include "hard-reg-set.h" #include "rtl.h" #include "tm_p.h" #include "regs.h" @@ -56,7 +57,6 @@ along with GCC; see the file COPYING3. If not see #include "recog.h" #include "conditions.h" #include "flags.h" -#include "hard-reg-set.h" #include "output.h" #include "except.h" #include "function.h" @@ -222,6 +222,7 @@ static int alter_cond (rtx); static int final_addr_vec_align (rtx); #endif static int align_fuzz (rtx, rtx, int, unsigned); +static void collect_fn_hard_reg_usage (void); /* Initialize data in final at the beginning of a compilation. */ @@ -4328,6 +4329,8 @@ rest_of_handle_final (void) rtx x; const char *fnname; + collect_fn_hard_reg_usage (); + /* Get the function's name, as described by its RTL. This may be different from the DECL_NAME name used in the source file. */ @@ -4584,3 +4587,121 @@ struct rtl_opt_pass pass_clean_state = 0 /* todo_flags_finish */ } }; + +/* Collect hard register usage for the current function. */ + +static void +collect_fn_hard_reg_usage (void) +{ + rtx insn; + int i; + struct cgraph_node *node; + struct hard_reg_set_container other_usage; + + if (!flag_use_caller_save) + return; + + node = cgraph_get_node (current_function_decl); + gcc_assert (node != NULL); + + gcc_assert (!node->function_used_regs_initialized); + node->function_used_regs_initialized = 1; + + for (insn = get_insns (); insn != NULL_RTX; insn = next_insn (insn)) + { + HARD_REG_SET insn_used_regs; + + if (!NONDEBUG_INSN_P (insn)) + continue; + + find_all_hard_reg_sets (insn, &insn_used_regs, false); + + if (CALL_P (insn) + && !get_call_reg_set_usage (insn, &insn_used_regs, call_used_reg_set)) + { + CLEAR_HARD_REG_SET (node->function_used_regs); + return; + } + + IOR_HARD_REG_SET (node->function_used_regs, insn_used_regs); + } + + /* Be conservative - mark fixed and global registers as used. */ + IOR_HARD_REG_SET (node->function_used_regs, fixed_reg_set); + for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) + if (global_regs[i]) + SET_HARD_REG_BIT (node->function_used_regs, i); + +#ifdef STACK_REGS + /* Handle STACK_REGS conservatively, since the df-framework does not + provide accurate information for them. */ + + for (i = FIRST_STACK_REG; i <= LAST_STACK_REG; i++) + SET_HARD_REG_BIT (node->function_used_regs, i); +#endif + + CLEAR_HARD_REG_SET (other_usage.set); + targetm.fn_other_hard_reg_usage (&other_usage); + IOR_HARD_REG_SET (node->function_used_regs, other_usage.set); + + node->function_used_regs_valid = 1; +} + +/* Get the declaration of the function called by INSN. */ + +static tree +get_call_fndecl (rtx insn) +{ + rtx note, datum; + + if (!flag_use_caller_save) + return NULL_TREE; + + note = find_reg_note (insn, REG_CALL_DECL, NULL_RTX); + if (note == NULL_RTX) + return NULL_TREE; + + datum = XEXP (note, 0); + if (datum != NULL_RTX) + return SYMBOL_REF_DECL (datum); + + return NULL_TREE; +} + +static struct cgraph_node * +get_call_cgraph_node (rtx insn) +{ + tree fndecl; + + if (insn == NULL_RTX) + return NULL; + + fndecl = get_call_fndecl (insn); + if (fndecl == NULL_TREE + || !targetm.binds_local_p (fndecl)) + return NULL; + + return cgraph_get_node (fndecl); +} + +/* Find hard registers used by function call instruction INSN, and return them + in REG_SET. Return DEFAULT_SET in REG_SET if not found. */ + +bool +get_call_reg_set_usage (rtx insn, HARD_REG_SET *reg_set, + HARD_REG_SET default_set) +{ + struct cgraph_node *node = get_call_cgraph_node (insn); + if (node != NULL + && node->function_used_regs_valid) + { + COPY_HARD_REG_SET (*reg_set, node->function_used_regs); + AND_HARD_REG_SET (*reg_set, default_set); + return true; + } + else + { + COPY_HARD_REG_SET (*reg_set, default_set); + return false; + } +} diff --git a/gcc/regs.h b/gcc/regs.h index 090d6b6..ec71ad4 100644 --- a/gcc/regs.h +++ b/gcc/regs.h @@ -421,4 +421,8 @@ range_in_hard_reg_set_p (const HARD_REG_SET set, unsigned regno, int nregs) return true; } +/* Get registers used by given function call instruction. */ +extern bool get_call_reg_set_usage (rtx insn, HARD_REG_SET *reg_set, + HARD_REG_SET default_set); + #endif /* GCC_REGS_H */