From patchwork Thu Sep 17 14:38:07 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Robert Suchanek X-Patchwork-Id: 518891 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)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 64FD4141404 for ; Fri, 18 Sep 2015 00:38:41 +1000 (AEST) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b=bRSDmGDi; dkim-atps=neutral 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:subject:date:message-id:content-type :content-transfer-encoding:mime-version; q=dns; s=default; b=XbE cgUiMUjYPxRNNXheXxaXonXwbMJ0O/uQD0w6Yy1jDCyoIrsy1BNM7ITW/auUcb0W Cmbxkh5eLBXcdgAslgv+i/foD6Sg7AC4fODZIsz+TtwjTYh9BYiBbgh5tufP5zji vRz7MnSpGI6slW90GMcfB1M+Susp+o2unT2M2bHk= 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:subject:date:message-id:content-type :content-transfer-encoding:mime-version; s=default; bh=pjK+alEWD O8JdWeT/2RHfZ0MBXs=; b=bRSDmGDi++Wk9RoQkGdf+glp9FTuY7D03S3uVBxuy A+377P49hTUdLq9EUmAtr5+0Ueqq01jsh3zM0tvmvTwOM1+i9ItyHoPHk57EqYWE eKiDSuKKg3ybs3X9sceCHVucd/i3RSGGSoOUtBCuwk8qkzNGNu4MFYLG6o2mPXzf yc= Received: (qmail 41012 invoked by alias); 17 Sep 2015 14:38: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 41001 invoked by uid 89); 17 Sep 2015 14:38:30 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-2.3 required=5.0 tests=AWL, BAYES_00, RCVD_IN_DNSWL_LOW, SPF_PASS, T_RP_MATCHES_RCVD autolearn=ham version=3.3.2 X-HELO: mailapp01.imgtec.com Received: from mailapp01.imgtec.com (HELO mailapp01.imgtec.com) (195.59.15.196) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Thu, 17 Sep 2015 14:38:29 +0000 Received: from KLMAIL01.kl.imgtec.org (unknown [192.168.5.35]) by Websense Email Security Gateway with ESMTPS id 8523AE077A37 for ; Thu, 17 Sep 2015 15:38:23 +0100 (IST) Received: from hhmail02.hh.imgtec.org (10.100.10.20) by KLMAIL01.kl.imgtec.org (192.168.5.35) with Microsoft SMTP Server (TLS) id 14.3.195.1; Thu, 17 Sep 2015 15:38:25 +0100 Received: from hhmail02.hh.imgtec.org ([::1]) by hhmail02.hh.imgtec.org ([::1]) with mapi id 14.03.0235.001; Thu, 17 Sep 2015 15:38:25 +0100 From: Robert Suchanek To: "gcc-patches@gcc.gnu.org" Subject: [RFC][PATCH] Preferred rename register in regrename pass Date: Thu, 17 Sep 2015 14:38:07 +0000 Message-ID: MIME-Version: 1.0 X-IsSubscribed: yes Hi, We came across a situation for MIPS64 where moves for sign-extension were not converted into a nop because of IRA spilled some of the allocnos and assigned different hard register for the output operand in the move. LRA is not fixing this up as most likely the move was not introduced by the LRA itself. I found it hard to fix this in LRA and looked at an alternative solution where regrename pass appeared to be the best candidate. The patch below introduces a notion of a preferred rename register and attempts to use the output register for an input register iff the input register dies in an instruction. The preferred register is validated and in the case it fails to be validated, it falls back to the old technique of finding the best rename register. Of course, it has slightly limited scope of use as it's not enabled be default, however, when targeting performance one is likely to enable it via -funroll-loops or -fpeel-loops. I did some experiments with -funroll-loops on x86_64-unknown-linux-gnu and the code size improved almost 0.4% on average case. I haven't done an extensive performance testing but it appeared SPEC2006 had some minor improvement on average, which could be real improvement or just noise. On MIPS64 with -funroll-loops, there were a number of cases where the unnecessary moves turned into a nop in CSiBE. MIPS32 also marginally improved but to a lower degree. The patch successfully passed x86_64-unknown-linux-gnu, mips-mti-linux-gnu and mips-img-linux-gnu. I'm not sure if this is something that should be enabled by default for everyone or a target hook should be added. Any other comments/suggestions? Regards, Robert gcc/ * regrename.c (find_preferred_rename_reg): New function. (record_operand_use): Remove assertion. Allocate or resize heads and chains vectors, if necessary. (find_best_rename_reg): Use the new function and validate chosen register. (build_def_use): Don't allocate and initialize space of size 0. (regrename_finish): Free heads and chains vectors. (regrename_optimize): Pass true to initializing function. * regrename.h (struct operand_rr_info): Replace arrays of heads and chains with vectors. --- gcc/regrename.c | 86 +++++++++++++++++++++++++++++++++++++++++++++++++++++---- gcc/regrename.h | 4 +-- 2 files changed, 82 insertions(+), 8 deletions(-) diff --git a/gcc/regrename.c b/gcc/regrename.c index c328c1b..90fee98 100644 --- a/gcc/regrename.c +++ b/gcc/regrename.c @@ -174,6 +174,51 @@ dump_def_use_chain (int from) } } +/* Return a preferred rename register for HEAD. */ + +static int +find_preferred_rename_reg (du_head_p head) +{ + struct du_chain *this_du; + int preferred_reg = -1; + + for (this_du = head->first; this_du; this_du = this_du->next_use) + { + rtx note; + insn_rr_info *p; + + /* The preferred rename register is an output register iff an input + register dies in an instruction but the candidate must be validated by + check_new_reg_p. */ + for (note = REG_NOTES (this_du->insn); note; note = XEXP (note, 1)) + if (insn_rr.exists() + && REG_NOTE_KIND (note) == REG_DEAD + && REGNO (XEXP (note, 0)) == head->regno + && (p = &insn_rr[INSN_UID (this_du->insn)]) + && p->op_info) + { + int i; + for (i = 0; i < p->op_info->n_chains; i++) + { + struct du_head *next_head = p->op_info->heads[i]; + if (head != next_head) + { + preferred_reg = next_head->regno; + if (dump_file) + fprintf (dump_file, + "Chain %s (%d) has preferred rename register" + " %s for insn %d [%s]\n", + reg_names[head->regno], head->id, + reg_names[preferred_reg], + INSN_UID (this_du->insn), + reg_class_names[this_du->cl]); + } + } + } + } + return preferred_reg; +} + static void free_chain_data (void) { @@ -206,7 +251,16 @@ record_operand_use (struct du_head *head, struct du_chain *this_du) { if (cur_operand == NULL) return; - gcc_assert (cur_operand->n_chains < MAX_REGS_PER_ADDRESS); + + if (!cur_operand->heads.exists ()) + cur_operand->heads.create (0); + if (!cur_operand->chains.exists ()) + cur_operand->chains.create (0); + if (cur_operand->heads.length () <= (unsigned) cur_operand->n_chains) + cur_operand->heads.safe_grow_cleared (cur_operand->n_chains + 1); + if (cur_operand->chains.length () <= (unsigned) cur_operand->n_chains) + cur_operand->chains.safe_grow_cleared (cur_operand->n_chains + 1); + cur_operand->heads[cur_operand->n_chains] = head; cur_operand->chains[cur_operand->n_chains++] = this_du; } @@ -355,6 +409,7 @@ find_rename_reg (du_head_p this_head, enum reg_class super_class, enum reg_class preferred_class; int pass; int best_new_reg = old_reg; + int preferred_reg = -1; /* Further narrow the set of registers we can use for renaming. If the chain needs a call-saved register, mark the call-used @@ -370,6 +425,11 @@ find_rename_reg (du_head_p this_head, enum reg_class super_class, preferred_class = (enum reg_class) targetm.preferred_rename_class (super_class); + /* Try to find a preferred rename register for THIS_HEAD. */ + if ((preferred_reg = find_preferred_rename_reg (this_head)) != -1 + && check_new_reg_p (old_reg, preferred_reg, this_head, *unavailable)) + return preferred_reg; + /* If PREFERRED_CLASS is not NO_REGS, we iterate in the first pass over registers that belong to PREFERRED_CLASS and try to find the best register within the class. If that failed, we iterate in @@ -1588,10 +1648,14 @@ build_def_use (basic_block bb) if (insn_rr.exists ()) { insn_info = &insn_rr[INSN_UID (insn)]; - insn_info->op_info = XOBNEWVEC (&rename_obstack, operand_rr_info, - recog_data.n_operands); - memset (insn_info->op_info, 0, - sizeof (operand_rr_info) * recog_data.n_operands); + if (recog_data.n_operands > 0) + { + insn_info->op_info = XOBNEWVEC (&rename_obstack, + operand_rr_info, + recog_data.n_operands); + memset (insn_info->op_info, 0, + sizeof (operand_rr_info) * recog_data.n_operands); + } } /* Simplify the code below by promoting OP_OUT to OP_INOUT in @@ -1811,6 +1875,16 @@ regrename_init (bool insn_info) void regrename_finish (void) { + int i; + struct insn_rr_info *item; + + FOR_EACH_VEC_ELT (insn_rr, i, item) + if (item->op_info) + { + item->op_info->heads.release (); + item->op_info->chains.release (); + } + insn_rr.release (); free_chain_data (); obstack_free (&rename_obstack, NULL); @@ -1826,7 +1900,7 @@ regrename_optimize (void) df_analyze (); df_set_flags (DF_DEFER_INSN_RESCAN); - regrename_init (false); + regrename_init (true); regrename_analyze (NULL); diff --git a/gcc/regrename.h b/gcc/regrename.h index bbe156d..2e3bc20 100644 --- a/gcc/regrename.h +++ b/gcc/regrename.h @@ -71,8 +71,8 @@ struct operand_rr_info int n_chains; /* Holds either the chain for the operand itself, or for the registers in a memory operand. */ - struct du_chain *chains[MAX_REGS_PER_ADDRESS]; - struct du_head *heads[MAX_REGS_PER_ADDRESS]; + vec chains; + vec heads; }; /* A struct to hold a vector of operand_rr_info structures describing the