From patchwork Sun Nov 12 12:08:17 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lehua Ding X-Patchwork-Id: 164251 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:b909:0:b0:403:3b70:6f57 with SMTP id t9csp660238vqg; Sun, 12 Nov 2023 04:10:57 -0800 (PST) X-Google-Smtp-Source: AGHT+IHemO9qed9bDeUTz3lXeII46Dyb3K1/IMu7zXmPYPK7gZU0G8MpMh323qTuR5W/sMSBmkS9 X-Received: by 2002:a05:6870:2424:b0:1ef:aba1:1995 with SMTP id n36-20020a056870242400b001efaba11995mr5300429oap.59.1699791057447; Sun, 12 Nov 2023 04:10:57 -0800 (PST) ARC-Seal: i=2; a=rsa-sha256; t=1699791057; cv=pass; d=google.com; s=arc-20160816; b=0RNJZzEsIT3SdB7KtKvBMexkAzoNKcn/mjegZUpA/eXVxTV//+lfL7DvvuDcRGaHHg qN318GDV70nYXNQzYP6Tmv23rKNDANRcoBDuhVI+2F6bImk+ryFMnWjwrFuVneOFU1N3 RsPC87xAoUg5+umr5LWFnq6jiSkMntEcHUFBpVxPuh3LkDzTybQQRW5F8duyDqv4AVAA g/5BYHG/mJa409cQufHJMCy57nIuFKf18BORnCz7JbcHALvxlLPSE8cT0rAD6SrzkqWU CZxTVT0SScCVDusmz28+vmcelYhs+dylpN1dx5imydotR7tgScerHvJOi3cJuSmwmmQM pgjg== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=errors-to:list-subscribe:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:feedback-id :content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:arc-filter:dmarc-filter :delivered-to; bh=viwnp7foIOfy+VU8zUP68Chx+HH0VVG3vPIyl7KoIRw=; fh=9Ok8HNl3eD0lUFF4nhUPZJmQfyAUbHnIPw/rSVNIfK0=; b=w2uNq9vDvdkP9Slkn3d+MzYHgpy3BmXjJT5xjHhORR6XJ46X0nLPOx33J67SWowrBO eaO9RcumqmpRTbuOTxZ/7unReripMwolr1XCbBDMLdY+DhOO5M0URZ2YwvN7yYrVWOLB 2Y4Vl3Y5lAsntDgoxRjK90Ne3EZBfzwosUQ8ET9/fM9Mjq/V8lnCYp9iUAL0bVdUwEqk /C00bL5Oxyk7FqMeKHanVIhACWabz7SUSj63rdRKq6YeqNtN8FzHxGRjLWY3tGuhmSuV PDdx22noQpWFc7Ps0FRF1+kYrWEpnR0N8SJSxPBT6zO0UsSPhQPcNA24Bj3td9Zg6rsI fawQ== ARC-Authentication-Results: i=2; mx.google.com; arc=pass (i=1); spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 8.43.85.97 as permitted sender) smtp.mailfrom="gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org" Received: from server2.sourceware.org (server2.sourceware.org. [8.43.85.97]) by mx.google.com with ESMTPS id l18-20020a05622a051200b00403be2ad0besi2773669qtx.11.2023.11.12.04.10.57 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 12 Nov 2023 04:10:57 -0800 (PST) Received-SPF: pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 8.43.85.97 as permitted sender) client-ip=8.43.85.97; Authentication-Results: mx.google.com; arc=pass (i=1); spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 8.43.85.97 as permitted sender) smtp.mailfrom="gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org" Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 2DEEE3858D37 for ; Sun, 12 Nov 2023 12:10:57 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from smtpbguseast1.qq.com (smtpbguseast1.qq.com [54.204.34.129]) by sourceware.org (Postfix) with ESMTPS id CD8B93858028 for ; Sun, 12 Nov 2023 12:08:49 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org CD8B93858028 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=rivai.ai Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=rivai.ai ARC-Filter: OpenARC Filter v1.0.0 sourceware.org CD8B93858028 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=54.204.34.129 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1699790935; cv=none; b=gx0LdakkrxI1w8uWw2BsIUIhmlsXx6KFFA+WCKryBQ8ErK6kV1MHNcFNcvyV1hB8l5/7jiHQj7bIIlnkUB+Wfj9YPU2bvvaRvStIDDRTceK0v/iyy1UgWeDj1tF2cn7zfwH8sa93iW5roGsmW1eLJLTIFO155gNFbHlor35P5R4= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1699790935; c=relaxed/simple; bh=pikDaNVnhaUuEwHpU12Zq79oUSz8HqKIm17PBR9EzUI=; h=From:To:Subject:Date:Message-Id:MIME-Version; b=qJgJt7KewO+FNMgDwXQEDV3wvgrBwokt6Ab9y6CnNre1d8SVh+DBDvo//MFXPxRqamXpD/ETTI6rxRh2QaegiYWwHfmGYcMBUn+ShUoH0hnWnYKZgpSD07IN1YYvs58z+xJfXt+SXREgg7AT9UwedOg6P3iN8Wdgo9kVFb0isyU= ARC-Authentication-Results: i=1; server2.sourceware.org X-QQ-mid: bizesmtp67t1699790923tun14vrq Received: from rios-cad121.hadoop.rioslab.org ( [58.60.1.9]) by bizesmtp.qq.com (ESMTP) with id ; Sun, 12 Nov 2023 20:08:42 +0800 (CST) X-QQ-SSF: 01400000000000C0F000000A0000000 X-QQ-FEAT: +ynUkgUhZJn1Mg+n5EqnxXtvSxHuKDSXt3Re/YbaM2vTfCcDaO15ZrC79t4D2 kvcsIFJVyoBORVvKqimoVk4SkF2TMBhCVOTHZUG+797o0gJ7WT4BLfbV2urkQWch1AclDhQ zUWFA9LZM+Wc06mmhHJout4jktL5V2J7AJ/sefjTrvAZ4/9FQmTpk2QrctVAap1tWAwriaK F6HETGfOfWQGMBHoQrDaUpFYARDO3Ld6LrghETbjHTqko/08+DapliCeKqGlQjJvadmTdLZ KCPMOD755nlirDpCPlwVTdpbMRkkjXjCcV7uCnhJZpXXQt9tsyEbXkP8AfkEOFRqodlxsBg viRVNJspGuEyk3miDD6qJ4ypQfFMWD/4J1o36nv3WGOAyq3gSEOERB9g13qJ//K3jcTLQu1 R+PYLyNC9lQ= X-QQ-GoodBg: 2 X-BIZMAIL-ID: 6025235424158987513 From: Lehua Ding To: gcc-patches@gcc.gnu.org Cc: vmakarov@redhat.com, richard.sandiford@arm.com, juzhe.zhong@rivai.ai, lehua.ding@rivai.ai Subject: [PATCH V3 7/7] lra: Support subreg live range track and conflict detect Date: Sun, 12 Nov 2023 20:08:17 +0800 Message-Id: <20231112120817.2635864-8-lehua.ding@rivai.ai> X-Mailer: git-send-email 2.36.3 In-Reply-To: <20231112120817.2635864-1-lehua.ding@rivai.ai> References: <20231112120817.2635864-1-lehua.ding@rivai.ai> MIME-Version: 1.0 X-QQ-SENDSIZE: 520 Feedback-ID: bizesmtp:rivai.ai:qybglogicsvrgz:qybglogicsvrgz6a-0 X-Spam-Status: No, score=-11.6 required=5.0 tests=BAYES_00, GIT_PATCH_0, KAM_DMARC_STATUS, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2, SPF_HELO_PASS, SPF_PASS, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1782360108149919563 X-GMAIL-MSGID: 1782360108149919563 This patch supports tracking the liveness of a subreg in a lra pass, with the goal of getting it to agree with ira's register allocation scheme. There is some duplication, maybe in the future this part of the code logic can be harmonized. gcc/ChangeLog: * ira-build.cc (setup_pseudos_has_subreg_object): Collect new data for lra to use. (ira_build): Ditto. * lra-assigns.cc (set_offset_conflicts): New function. (setup_live_pseudos_and_spill_after_risky_transforms): Adjust. (lra_assign): Ditto. * lra-constraints.cc (process_alt_operands): Ditto. * lra-int.h (GCC_LRA_INT_H): Ditto. (struct lra_live_range): Ditto. (struct lra_insn_reg): Ditto. (get_range_hard_regs): New. (get_nregs): New. (has_subreg_object_p): New. * lra-lives.cc (INCLUDE_VECTOR): Adjust. (lra_live_range_pool): Ditto. (create_live_range): Ditto. (lra_merge_live_ranges): Ditto. (update_pseudo_point): Ditto. (mark_regno_live): Ditto. (mark_regno_dead): Ditto. (process_bb_lives): Ditto. (remove_some_program_points_and_update_live_ranges): Ditto. (lra_print_live_range_list): Ditto. (class subreg_live_item): New. (create_subregs_live_ranges): New. (lra_create_live_ranges_1): Ditto. * lra.cc (get_range_blocks): Ditto. (get_range_hard_regs): Ditto. (new_insn_reg): Ditto. (collect_non_operand_hard_regs): Ditto. (initialize_lra_reg_info_element): Ditto. (reg_same_range_p): New. (add_regs_to_insn_regno_info): Adjust. --- gcc/ira-build.cc | 31 ++++ gcc/lra-assigns.cc | 111 ++++++++++++-- gcc/lra-constraints.cc | 18 ++- gcc/lra-int.h | 31 ++++ gcc/lra-lives.cc | 340 ++++++++++++++++++++++++++++++++++------- gcc/lra.cc | 139 +++++++++++++++-- 6 files changed, 585 insertions(+), 85 deletions(-) diff --git a/gcc/ira-build.cc b/gcc/ira-build.cc index f88aeeeeaef..bb29627d375 100644 --- a/gcc/ira-build.cc +++ b/gcc/ira-build.cc @@ -95,6 +95,9 @@ int ira_copies_num; basic block. */ static int last_basic_block_before_change; +/* Record these pseudos which has subreg object. Used by LRA pass. */ +bitmap_head pseudos_has_subreg_object; + /* Initialize some members in loop tree node NODE. Use LOOP_NUM for the member loop_num. */ static void @@ -3711,6 +3714,33 @@ update_conflict_hard_reg_costs (void) } } +/* Setup speudos_has_subreg_object. */ +static void +setup_pseudos_has_subreg_object () +{ + bitmap_initialize (&pseudos_has_subreg_object, ®_obstack); + ira_allocno_t a; + ira_allocno_iterator ai; + FOR_EACH_ALLOCNO (a, ai) + if (has_subreg_object_p (a)) + { + bitmap_set_bit (&pseudos_has_subreg_object, ALLOCNO_REGNO (a)); + if (ira_dump_file != NULL) + { + fprintf (ira_dump_file, + " a%d(r%d, nregs: %d) has subreg objects:\n", + ALLOCNO_NUM (a), ALLOCNO_REGNO (a), ALLOCNO_NREGS (a)); + ira_allocno_object_iterator oi; + ira_object_t obj; + FOR_EACH_ALLOCNO_OBJECT (a, obj, oi) + fprintf (ira_dump_file, " object %d: start: %d, nregs: %d\n", + OBJECT_INDEX (obj), OBJECT_START (obj), + OBJECT_NREGS (obj)); + fprintf (ira_dump_file, "\n"); + } + } +} + /* Create a internal representation (IR) for IRA (allocnos, copies, loop tree nodes). The function returns TRUE if we generate loop structure (besides nodes representing all function and the basic @@ -3731,6 +3761,7 @@ ira_build (void) create_allocnos (); ira_costs (); create_allocno_objects (); + setup_pseudos_has_subreg_object (); ira_create_allocno_live_ranges (); remove_unnecessary_regions (false); ira_compress_allocno_live_ranges (); diff --git a/gcc/lra-assigns.cc b/gcc/lra-assigns.cc index d2ebcfd5056..6588a740162 100644 --- a/gcc/lra-assigns.cc +++ b/gcc/lra-assigns.cc @@ -1131,6 +1131,52 @@ assign_hard_regno (int hard_regno, int regno) /* Array used for sorting different pseudos. */ static int *sorted_pseudos; +/* The detail conflict offsets If two live ranges conflict. Use to record + partail conflict. */ +static bitmap_head live_range_conflicts; + +/* Set the conflict offset of the two registers REGNO1 and REGNO2. Use the + regno with bigger nregs as the base. */ +static void +set_offset_conflicts (int regno1, int regno2) +{ + gcc_assert (reg_renumber[regno1] >= 0 && reg_renumber[regno2] >= 0); + int nregs1 = get_nregs (regno1); + int nregs2 = get_nregs (regno2); + if (nregs1 < nregs2) + { + std::swap (nregs1, nregs2); + std::swap (regno1, regno2); + } + + lra_live_range_t r1 = lra_reg_info[regno1].live_ranges; + lra_live_range_t r2 = lra_reg_info[regno2].live_ranges; + int total = nregs1; + + bitmap_clear (&live_range_conflicts); + while (r1 != NULL && r2 != NULL) + { + if (r1->start > r2->finish) + r1 = r1->next; + else if (r2->start > r1->finish) + r2 = r2->next; + else + { + for (const subreg_range &range1 : r1->subreg.ranges) + for (const subreg_range &range2 : r2->subreg.ranges) + /* Record all overlap offset. */ + for (int i = range1.start - (range2.end - range2.start) + 1; + i < range1.end; i++) + if (i >= 0 && i < total) + bitmap_set_bit (&live_range_conflicts, i); + if (r1->finish < r2->finish) + r1 = r1->next; + else + r2 = r2->next; + } + } +} + /* The constraints pass is allowed to create equivalences between pseudos that make the current allocation "incorrect" (in the sense that pseudos are assigned to hard registers from their own conflict @@ -1226,19 +1272,56 @@ setup_live_pseudos_and_spill_after_risky_transforms (bitmap the same hard register. */ || hard_regno != reg_renumber[conflict_regno]) { - int conflict_hard_regno = reg_renumber[conflict_regno]; - - biggest_mode = lra_reg_info[conflict_regno].biggest_mode; - biggest_nregs = hard_regno_nregs (conflict_hard_regno, - biggest_mode); - nregs_diff - = (biggest_nregs - - hard_regno_nregs (conflict_hard_regno, - PSEUDO_REGNO_MODE (conflict_regno))); - add_to_hard_reg_set (&conflict_set, - biggest_mode, - conflict_hard_regno - - (WORDS_BIG_ENDIAN ? nregs_diff : 0)); + if (hard_regno >= 0 && reg_renumber[conflict_regno] >= 0 + && (has_subreg_object_p (regno) + || has_subreg_object_p (conflict_regno))) + { + int nregs1 = get_nregs (regno); + int nregs2 = get_nregs (conflict_regno); + /* Quick check it is no overlap at all between them. */ + if (hard_regno + nregs1 <= reg_renumber[conflict_regno] + || reg_renumber[conflict_regno] + nregs2 <= hard_regno) + continue; + + /* Check the overlap is ok if them have partial overlap. */ + set_offset_conflicts (regno, conflict_regno); + if (nregs1 >= nregs2) + EXECUTE_IF_SET_IN_BITMAP (&live_range_conflicts, 0, k, bi) + { + int start_regno + = WORDS_BIG_ENDIAN + ? reg_renumber[conflict_regno] + nregs2 + k - nregs1 + : reg_renumber[conflict_regno] - k; + if (start_regno >= 0 && hard_regno == start_regno) + SET_HARD_REG_BIT (conflict_set, start_regno); + } + else + EXECUTE_IF_SET_IN_BITMAP (&live_range_conflicts, 0, k, bi) + { + int start_regno + = WORDS_BIG_ENDIAN + ? reg_renumber[conflict_regno] + nregs2 - k - nregs1 + : reg_renumber[conflict_regno] + k; + if (start_regno < FIRST_PSEUDO_REGISTER + && hard_regno == start_regno) + SET_HARD_REG_BIT (conflict_set, start_regno); + } + } + else + { + int conflict_hard_regno = reg_renumber[conflict_regno]; + + biggest_mode = lra_reg_info[conflict_regno].biggest_mode; + biggest_nregs + = hard_regno_nregs (conflict_hard_regno, biggest_mode); + nregs_diff + = (biggest_nregs + - hard_regno_nregs (conflict_hard_regno, + PSEUDO_REGNO_MODE (conflict_regno))); + add_to_hard_reg_set (&conflict_set, biggest_mode, + conflict_hard_regno + - (WORDS_BIG_ENDIAN ? nregs_diff : 0)); + } } if (! overlaps_hard_reg_set_p (conflict_set, mode, hard_regno)) { @@ -1637,7 +1720,9 @@ lra_assign (bool &fails_p) init_regno_assign_info (); bitmap_initialize (&all_spilled_pseudos, ®_obstack); create_live_range_start_chains (); + bitmap_initialize (&live_range_conflicts, ®_obstack); setup_live_pseudos_and_spill_after_risky_transforms (&all_spilled_pseudos); + bitmap_clear (&live_range_conflicts); if (! lra_hard_reg_split_p && ! lra_asm_error_p && flag_checking) /* Check correctness of allocation but only when there are no hard reg splits and asm errors as in the case of errors explicit insns involving diff --git a/gcc/lra-constraints.cc b/gcc/lra-constraints.cc index c3ad846b97b..912d0c3feec 100644 --- a/gcc/lra-constraints.cc +++ b/gcc/lra-constraints.cc @@ -2363,13 +2363,19 @@ process_alt_operands (int only_alternative) { /* We should reject matching of an early clobber operand if the matching operand is - not dying in the insn. */ - if (!TEST_BIT (curr_static_id->operand[m] - .early_clobber_alts, nalt) + not dying in the insn. But for subreg of pseudo which + has subreg live be tracked in ira, the REG_DEAD note + doesn't have. that case we think them the matching is + ok. */ + if (!TEST_BIT ( + curr_static_id->operand[m].early_clobber_alts, + nalt) || operand_reg[nop] == NULL_RTX - || (find_regno_note (curr_insn, REG_DEAD, - REGNO (op)) - || REGNO (op) == REGNO (operand_reg[m]))) + || find_regno_note (curr_insn, REG_DEAD, REGNO (op)) + || (read_modify_subreg_p ( + *curr_id->operand_loc[nop]) + && has_subreg_object_p (REGNO (op))) + || REGNO (op) == REGNO (operand_reg[m])) match_p = true; } if (match_p) diff --git a/gcc/lra-int.h b/gcc/lra-int.h index 678377d9ec6..5a97bd61475 100644 --- a/gcc/lra-int.h +++ b/gcc/lra-int.h @@ -21,6 +21,7 @@ along with GCC; see the file COPYING3. If not see #ifndef GCC_LRA_INT_H #define GCC_LRA_INT_H +#include "lra.h" #include "subreg-live-range.h" #define lra_assert(c) gcc_checking_assert (c) @@ -48,6 +49,8 @@ struct lra_live_range lra_live_range_t next; /* Pointer to structures with the same start. */ lra_live_range_t start_next; + /* Object whose live range is described by given structure. */ + subreg_ranges subreg; }; typedef struct lra_copy *lra_copy_t; @@ -110,6 +113,8 @@ public: /* The biggest size mode in which each pseudo reg is referred in whole function (possibly via subreg). */ machine_mode biggest_mode; + /* The real reg MODE. */ + machine_mode reg_mode; /* Live ranges of the pseudo. */ lra_live_range_t live_ranges; /* This member is set up in lra-lives.cc for subsequent @@ -161,6 +166,12 @@ struct lra_insn_reg unsigned int subreg_p : 1; /* The corresponding regno of the register. */ int regno; + /* The start and end of current ref of blocks, remember the use/def can be + a normal subreg. */ + int start, end; + /* The start and end of current ref of hard regs, remember the use/def can be + a normal subreg. */ + int start_reg, end_reg; /* Next reg info of the same insn. */ struct lra_insn_reg *next; }; @@ -332,6 +343,8 @@ extern struct lra_insn_reg *lra_get_insn_regs (int); extern void lra_free_copies (void); extern void lra_create_copy (int, int, int); extern lra_copy_t lra_get_copy (int); +extern subreg_range +get_range_hard_regs (int regno, const subreg_range &r); extern int lra_new_regno_start; extern int lra_constraint_new_regno_start; @@ -533,4 +546,22 @@ lra_assign_reg_val (int from, int to) lra_reg_info[to].offset = lra_reg_info[from].offset; } +/* Return the number regs of REGNO. */ +inline int +get_nregs (int regno) +{ + enum reg_class aclass = lra_get_allocno_class (regno); + gcc_assert (aclass != NO_REGS); + int nregs = ira_reg_class_max_nregs[aclass][lra_reg_info[regno].reg_mode]; + return nregs; +} + +extern bitmap_head pseudos_has_subreg_object; +/* Return true if pseudo REGNO has subreg live range. */ +inline bool +has_subreg_object_p (int regno) +{ + return bitmap_bit_p (&pseudos_has_subreg_object, regno); +} + #endif /* GCC_LRA_INT_H */ diff --git a/gcc/lra-lives.cc b/gcc/lra-lives.cc index d93921ad302..8a7c653fb09 100644 --- a/gcc/lra-lives.cc +++ b/gcc/lra-lives.cc @@ -26,6 +26,7 @@ along with GCC; see the file COPYING3. If not see stack memory slots to spilled pseudos. */ #include "config.h" +#define INCLUDE_VECTOR #include "system.h" #include "coretypes.h" #include "backend.h" @@ -97,6 +98,9 @@ static bitmap_head temp_bitmap; /* Pool for pseudo live ranges. */ static object_allocator lra_live_range_pool ("live ranges"); +/* Store def/use point of has_subreg_object_p register. */ +static class subregs_live_points *live_points; + /* Free live range list LR. */ static void free_live_range_list (lra_live_range_t lr) @@ -113,16 +117,26 @@ free_live_range_list (lra_live_range_t lr) /* Create and return pseudo live range with given attributes. */ static lra_live_range_t -create_live_range (int regno, int start, int finish, lra_live_range_t next) +create_live_range (int regno, const subreg_ranges &sr, int start, int finish, + lra_live_range_t next) { lra_live_range_t p = lra_live_range_pool.allocate (); p->regno = regno; p->start = start; p->finish = finish; p->next = next; + p->subreg = sr; return p; } +static lra_live_range_t +create_live_range (int regno, int start, int finish, lra_live_range_t next) +{ + subreg_ranges sr = subreg_ranges (1); + sr.add_range (1, subreg_range (0, 1)); + return create_live_range (regno, sr, start, finish, next); +} + /* Copy live range R and return the result. */ static lra_live_range_t copy_live_range (lra_live_range_t r) @@ -164,7 +178,8 @@ lra_merge_live_ranges (lra_live_range_t r1, lra_live_range_t r2) if (r1->start < r2->start) std::swap (r1, r2); - if (r1->start == r2->finish + 1) + if (r1->start == r2->finish + 1 + && (r1->regno != r2->regno || r1->subreg.same_p (r2->subreg))) { /* Joint ranges: merge r1 and r2 into r1. */ r1->start = r2->start; @@ -174,7 +189,8 @@ lra_merge_live_ranges (lra_live_range_t r1, lra_live_range_t r2) } else { - gcc_assert (r2->finish + 1 < r1->start); + gcc_assert (r2->finish + 1 < r1->start + || !r1->subreg.same_p (r2->subreg)); /* Add r1 to the result. */ if (first == NULL) first = last = r1; @@ -237,6 +253,10 @@ sparseset_contains_pseudos_p (sparseset a) return false; } +static void +update_pseudo_point (int regno, const subreg_range &range, int point, + enum point_type type); + /* Mark pseudo REGNO as living or dying at program point POINT, depending on whether TYPE is a definition or a use. If this is the first reference to REGNO that we've encountered, then create a new live range for it. */ @@ -249,27 +269,78 @@ update_pseudo_point (int regno, int point, enum point_type type) /* Don't compute points for hard registers. */ if (HARD_REGISTER_NUM_P (regno)) return; + if (!complete_info_p && lra_get_regno_hard_regno (regno) >= 0) + return; - if (complete_info_p || lra_get_regno_hard_regno (regno) < 0) + if (has_subreg_object_p (regno)) { - if (type == DEF_POINT) - { - if (sparseset_bit_p (pseudos_live, regno)) - { - p = lra_reg_info[regno].live_ranges; - lra_assert (p != NULL); - p->finish = point; - } - } - else /* USE_POINT */ + update_pseudo_point (regno, subreg_range (0, get_nregs (regno)), point, + type); + return; + } + + if (type == DEF_POINT) + { + if (sparseset_bit_p (pseudos_live, regno)) { - if (!sparseset_bit_p (pseudos_live, regno) - && ((p = lra_reg_info[regno].live_ranges) == NULL - || (p->finish != point && p->finish + 1 != point))) - lra_reg_info[regno].live_ranges - = create_live_range (regno, point, -1, p); + p = lra_reg_info[regno].live_ranges; + lra_assert (p != NULL); + p->finish = point; } } + else /* USE_POINT */ + { + if (!sparseset_bit_p (pseudos_live, regno) + && ((p = lra_reg_info[regno].live_ranges) == NULL + || (p->finish != point && p->finish + 1 != point))) + lra_reg_info[regno].live_ranges + = create_live_range (regno, point, -1, p); + } +} + +/* Like the above mark_regno_dead but for has_subreg_object_p REGNO. */ +static void +update_pseudo_point (int regno, const subreg_range &range, int point, + enum point_type type) +{ + /* Don't compute points for hard registers. */ + if (HARD_REGISTER_NUM_P (regno)) + return; + + if (!complete_info_p && lra_get_regno_hard_regno (regno) >= 0) + { + if (has_subreg_object_p (regno)) + live_points->add_range (regno, get_nregs (regno), range, + type == DEF_POINT); + return; + } + + if (!has_subreg_object_p (regno)) + { + update_pseudo_point (regno, point, type); + return; + } + + if (lra_dump_file != NULL) + { + fprintf (lra_dump_file, " %s r%d", + type == DEF_POINT ? "def" : "use", regno); + fprintf (lra_dump_file, "[subreg: start %d, nregs: %d]", range.start, + range.end - range.start); + fprintf (lra_dump_file, " at point %d\n", point); + } + + live_points->add_point (regno, get_nregs (regno), range, type == DEF_POINT, + point); +} + +/* Update each range in SR. */ +static void +update_pseudo_point (int regno, const subreg_ranges sr, int point, + enum point_type type) +{ + for (const subreg_range &range : sr.ranges) + update_pseudo_point (regno, range, point, type); } /* Structure describing local BB data used for pseudo @@ -354,12 +425,18 @@ mark_pseudo_dead (int regno) if (!sparseset_bit_p (pseudos_live, regno)) return; + /* Just return if regno have partial subreg live for subreg access. */ + if (has_subreg_object_p (regno) && !live_points->empty_live_p (regno)) + return; + sparseset_clear_bit (pseudos_live, regno); sparseset_set_bit (start_dying, regno); } +static void +mark_regno_live (int regno, const subreg_range &range, machine_mode mode); /* Mark register REGNO (pseudo or hard register) in MODE as being live - and update BB_GEN_PSEUDOS. */ + and update CURR_BB_INFO. */ static void mark_regno_live (int regno, machine_mode mode) { @@ -370,6 +447,11 @@ mark_regno_live (int regno, machine_mode mode) for (last = end_hard_regno (mode, regno); regno < last; regno++) make_hard_regno_live (regno); } + else if (has_subreg_object_p (regno)) + { + machine_mode mode = lra_reg_info[regno].reg_mode; + mark_regno_live (regno, subreg_range (0, get_nregs (regno)), mode); + } else { mark_pseudo_live (regno); @@ -379,9 +461,26 @@ mark_regno_live (int regno, machine_mode mode) } } +/* Like the above mark_regno_dead but for has_subreg_object_p REGNO. */ +static void +mark_regno_live (int regno, const subreg_range &range, machine_mode mode) +{ + if (HARD_REGISTER_NUM_P (regno) || !has_subreg_object_p (regno)) + mark_regno_live (regno, mode); + else + { + mark_pseudo_live (regno); + machine_mode mode = lra_reg_info[regno].reg_mode; + if (!range.full_p (get_nregs (regno))) + has_subreg_live_p = true; + add_subreg_range (curr_bb_info, regno, mode, range, false); + } +} +static void +mark_regno_dead (int regno, const subreg_range &range, machine_mode mode); /* Mark register REGNO (pseudo or hard register) in MODE as being dead - and update BB_GEN_PSEUDOS and BB_KILLED_PSEUDOS. */ + and update CURR_BB_INFO. */ static void mark_regno_dead (int regno, machine_mode mode) { @@ -392,6 +491,12 @@ mark_regno_dead (int regno, machine_mode mode) for (last = end_hard_regno (mode, regno); regno < last; regno++) make_hard_regno_dead (regno); } + else if (has_subreg_object_p (regno)) + { + machine_mode mode = lra_reg_info[regno].reg_mode; + subreg_range range = subreg_range (0, get_nregs (regno)); + mark_regno_dead (regno, range, mode); + } else { mark_pseudo_dead (regno); @@ -402,7 +507,22 @@ mark_regno_dead (int regno, machine_mode mode) } } - +/* Like the above mark_regno_dead but for has_subreg_object_p REGNO. */ +static void +mark_regno_dead (int regno, const subreg_range &range, machine_mode mode) +{ + if (HARD_REGISTER_NUM_P (regno) || !has_subreg_object_p (regno)) + mark_regno_dead (regno, mode); + else + { + mark_pseudo_dead (regno); + machine_mode mode = lra_reg_info[regno].reg_mode; + if (!range.full_p (get_nregs (regno))) + has_subreg_live_p = true; + remove_subreg_range (curr_bb_info, regno, mode, range); + add_subreg_range (curr_bb_info, regno, mode, range, true); + } +} /* This page contains code for making global live analysis of pseudos. The code works only when pseudo live info is changed on a BB @@ -823,6 +943,8 @@ process_bb_lives (basic_block bb, int &curr_point, bool dead_insn_p) function_abi last_call_abi = default_function_abi; reg_live_out = DF_LIVE_SUBREG_OUT (bb); + bitmap reg_live_partial_out = DF_LIVE_SUBREG_PARTIAL_OUT (bb); + subregs_live *range_out = DF_LIVE_SUBREG_RANGE_OUT (bb); sparseset_clear (pseudos_live); sparseset_clear (pseudos_live_through_calls); sparseset_clear (pseudos_live_through_setjumps); @@ -830,7 +952,12 @@ process_bb_lives (basic_block bb, int &curr_point, bool dead_insn_p) hard_regs_live &= ~eliminable_regset; EXECUTE_IF_SET_IN_BITMAP (reg_live_out, FIRST_PSEUDO_REGISTER, j, bi) { - update_pseudo_point (j, curr_point, USE_POINT); + if (bitmap_bit_p (reg_live_partial_out, j) && has_subreg_object_p (j)) + for (const subreg_range &r : range_out->lives.at (j).ranges) + update_pseudo_point (j, get_range_hard_regs (j, r), curr_point, + USE_POINT); + else + update_pseudo_point (j, curr_point, USE_POINT); mark_pseudo_live (j); } @@ -1023,8 +1150,11 @@ process_bb_lives (basic_block bb, int &curr_point, bool dead_insn_p) for (reg = curr_id->regs; reg != NULL; reg = reg->next) if (reg->type != OP_IN) { - update_pseudo_point (reg->regno, curr_point, USE_POINT); - mark_regno_live (reg->regno, reg->biggest_mode); + const subreg_range &range = subreg_range (reg->start, reg->end); + update_pseudo_point (reg->regno, + get_range_hard_regs (reg->regno, range), + curr_point, USE_POINT); + mark_regno_live (reg->regno, range, reg->biggest_mode); /* ??? Should be a no-op for unused registers. */ check_pseudos_live_through_calls (reg->regno, last_call_abi); } @@ -1045,17 +1175,20 @@ process_bb_lives (basic_block bb, int &curr_point, bool dead_insn_p) /* See which defined values die here. */ for (reg = curr_id->regs; reg != NULL; reg = reg->next) - if (reg->type != OP_IN - && ! reg_early_clobber_p (reg, n_alt) && ! reg->subreg_p) + if (reg->type != OP_IN && !reg_early_clobber_p (reg, n_alt) + && (!reg->subreg_p || has_subreg_object_p (reg->regno))) { + const subreg_range &range = subreg_range (reg->start, reg->end); if (reg->type == OP_OUT) - update_pseudo_point (reg->regno, curr_point, DEF_POINT); - mark_regno_dead (reg->regno, reg->biggest_mode); + update_pseudo_point (reg->regno, + get_range_hard_regs (reg->regno, range), + curr_point, DEF_POINT); + mark_regno_dead (reg->regno, range, reg->biggest_mode); } for (reg = curr_static_id->hard_regs; reg != NULL; reg = reg->next) - if (reg->type != OP_IN - && ! reg_early_clobber_p (reg, n_alt) && ! reg->subreg_p) + if (reg->type != OP_IN && !reg_early_clobber_p (reg, n_alt) + && !reg->subreg_p) make_hard_regno_dead (reg->regno); if (curr_id->arg_hard_regs != NULL) @@ -1086,7 +1219,7 @@ process_bb_lives (basic_block bb, int &curr_point, bool dead_insn_p) /* Increment the current program point if we must. */ if (sparseset_contains_pseudos_p (unused_set) - || sparseset_contains_pseudos_p (start_dying)) + || sparseset_contains_pseudos_p (start_dying) || has_subreg_live_p) next_program_point (curr_point, freq); /* If we removed the source reg from a simple register copy from the @@ -1107,9 +1240,12 @@ process_bb_lives (basic_block bb, int &curr_point, bool dead_insn_p) for (reg = curr_id->regs; reg != NULL; reg = reg->next) if (reg->type != OP_OUT) { + const subreg_range &range = subreg_range (reg->start, reg->end); if (reg->type == OP_IN) - update_pseudo_point (reg->regno, curr_point, USE_POINT); - mark_regno_live (reg->regno, reg->biggest_mode); + update_pseudo_point (reg->regno, + get_range_hard_regs (reg->regno, range), + curr_point, USE_POINT); + mark_regno_live (reg->regno, range, reg->biggest_mode); check_pseudos_live_through_calls (reg->regno, last_call_abi); } @@ -1129,22 +1265,25 @@ process_bb_lives (basic_block bb, int &curr_point, bool dead_insn_p) /* Mark early clobber outputs dead. */ for (reg = curr_id->regs; reg != NULL; reg = reg->next) - if (reg->type != OP_IN - && reg_early_clobber_p (reg, n_alt) && ! reg->subreg_p) + if (reg->type != OP_IN && reg_early_clobber_p (reg, n_alt) + && (!reg->subreg_p || has_subreg_object_p (reg->regno))) { + const subreg_range &range = subreg_range (reg->start, reg->end); if (reg->type == OP_OUT) - update_pseudo_point (reg->regno, curr_point, DEF_POINT); - mark_regno_dead (reg->regno, reg->biggest_mode); + update_pseudo_point (reg->regno, + get_range_hard_regs (reg->regno, range), + curr_point, DEF_POINT); + mark_regno_dead (reg->regno, range, reg->biggest_mode); /* We're done processing inputs, so make sure early clobber operands that are both inputs and outputs are still live. */ if (reg->type == OP_INOUT) - mark_regno_live (reg->regno, reg->biggest_mode); + mark_regno_live (reg->regno, range, reg->biggest_mode); } for (reg = curr_static_id->hard_regs; reg != NULL; reg = reg->next) - if (reg->type != OP_IN - && reg_early_clobber_p (reg, n_alt) && ! reg->subreg_p) + if (reg->type != OP_IN && reg_early_clobber_p (reg, n_alt) + && !reg->subreg_p) { struct lra_insn_reg *reg2; @@ -1160,7 +1299,7 @@ process_bb_lives (basic_block bb, int &curr_point, bool dead_insn_p) /* Increment the current program point if we must. */ if (sparseset_contains_pseudos_p (dead_set) - || sparseset_contains_pseudos_p (start_dying)) + || sparseset_contains_pseudos_p (start_dying) || has_subreg_live_p) next_program_point (curr_point, freq); /* Update notes. */ @@ -1293,13 +1432,17 @@ process_bb_lives (basic_block bb, int &curr_point, bool dead_insn_p) EXECUTE_IF_SET_IN_SPARSESET (pseudos_live, i) { - update_pseudo_point (i, curr_point, DEF_POINT); + if (has_subreg_object_p (i)) + update_pseudo_point (i, live_points->subreg_live_ranges.at (i), + curr_point, DEF_POINT); + else + update_pseudo_point (i, curr_point, DEF_POINT); mark_pseudo_dead (i); } - EXECUTE_IF_SET_IN_BITMAP (DF_LIVE_SUBREG_IN (bb), FIRST_PSEUDO_REGISTER, j, - bi) - { + EXECUTE_IF_SET_IN_BITMAP (DF_LIVE_SUBREG_IN (bb), FIRST_PSEUDO_REGISTER, j, + bi) + { if (sparseset_cardinality (pseudos_live_through_calls) == 0) break; if (sparseset_bit_p (pseudos_live_through_calls, j)) @@ -1400,7 +1543,8 @@ remove_some_program_points_and_update_live_ranges (void) next_r = r->next; r->start = map[r->start]; r->finish = map[r->finish]; - if (prev_r == NULL || prev_r->start > r->finish + 1) + if (prev_r == NULL || prev_r->start > r->finish + 1 + || !prev_r->subreg.same_p (r->subreg)) { prev_r = r; continue; @@ -1418,8 +1562,18 @@ remove_some_program_points_and_update_live_ranges (void) void lra_print_live_range_list (FILE *f, lra_live_range_t r) { - for (; r != NULL; r = r->next) - fprintf (f, " [%d..%d]", r->start, r->finish); + if (r != NULL && has_subreg_object_p (r->regno)) + { + for (; r != NULL; r = r->next) + { + fprintf (f, " [%d..%d]{", r->start, r->finish); + r->subreg.dump (f); + fprintf (f, "}"); + } + } + else + for (; r != NULL; r = r->next) + fprintf (f, " [%d..%d]", r->start, r->finish); fprintf (f, "\n"); } @@ -1492,7 +1646,84 @@ compress_live_ranges (void) } } - +/* Use to temp record subregs live range in create_subregs_live_ranges function. + */ +class subreg_live_item +{ +public: + subreg_ranges subreg; + int start, finish; +}; + +/* Create subreg live ranges from objects def/use point info. */ +static void +create_subregs_live_ranges () +{ + for (const auto &subreg_point_it : live_points->subreg_points) + { + unsigned int regno = subreg_point_it.first; + const class live_points &points = subreg_point_it.second; + class lra_reg *reg_info = &lra_reg_info[regno]; + std::vector temps; + gcc_assert (has_subreg_object_p (regno)); + for (const auto &point_it : points.points) + { + int point = point_it.first; + const live_point ®s = point_it.second; + gcc_assert (temps.empty () || temps.back ().finish <= point); + if (!regs.use_reg.empty_p ()) + { + if (temps.empty ()) + temps.push_back ({regs.use_reg, point, -1}); + else if (temps.back ().finish == -1) + { + if (!temps.back ().subreg.same_p (regs.use_reg)) + { + if (temps.back ().start == point) + temps.back ().subreg.add_ranges (regs.use_reg); + else + { + temps.back ().finish = point - 1; + + subreg_ranges temp = regs.use_reg; + temp.add_ranges (temps.back ().subreg); + temps.push_back ({temp, point, -1}); + } + } + } + else if (temps.back ().subreg.same_p (regs.use_reg) + && (temps.back ().finish == point + || temps.back ().finish + 1 == point)) + temps.back ().finish = -1; + else + temps.push_back ({regs.use_reg, point, -1}); + } + if (!regs.def_reg.empty_p ()) + { + gcc_assert (!temps.empty ()); + if (regs.def_reg.include_ranges_p (temps.back ().subreg)) + temps.back ().finish = point; + else if (temps.back ().subreg.include_ranges_p (regs.def_reg)) + { + temps.back ().finish = point; + + subreg_ranges diff = temps.back ().subreg; + diff.remove_ranges (regs.def_reg); + temps.push_back ({diff, point + 1, -1}); + } + else + gcc_unreachable (); + } + } + + gcc_assert (reg_info->live_ranges == NULL); + + for (const subreg_live_item &item : temps) + reg_info->live_ranges + = create_live_range (regno, item.subreg, item.start, item.finish, + reg_info->live_ranges); + } +} /* The number of the current live range pass. */ int lra_live_range_iter; @@ -1573,6 +1804,8 @@ lra_create_live_ranges_1 (bool all_p, bool dead_insn_p) int n = inverted_rev_post_order_compute (cfun, rpo); lra_assert (n == n_basic_blocks_for_fn (cfun)); bb_live_change_p = false; + has_subreg_live_p = false; + live_points = new subregs_live_points (); for (i = 0; i < n; ++i) { bb = BASIC_BLOCK_FOR_FN (cfun, rpo[i]); @@ -1655,9 +1888,14 @@ lra_create_live_ranges_1 (bool all_p, bool dead_insn_p) } } lra_live_max_point = curr_point; + create_subregs_live_ranges (); if (lra_dump_file != NULL) - print_live_ranges (lra_dump_file); + { + live_points->dump (lra_dump_file); + print_live_ranges (lra_dump_file); + } /* Clean up. */ + delete live_points; sparseset_free (unused_set); sparseset_free (dead_set); sparseset_free (start_dying); diff --git a/gcc/lra.cc b/gcc/lra.cc index bcc00ff7d6b..23fc0daf1ed 100644 --- a/gcc/lra.cc +++ b/gcc/lra.cc @@ -566,6 +566,54 @@ lra_asm_insn_error (rtx_insn *insn) /* Pools for insn reg info. */ object_allocator lra_insn_reg_pool ("insn regs"); +/* Return the subreg range of rtx SUBREG in blocks. */ +static subreg_range +get_range_blocks (int regno, bool subreg_p, machine_mode reg_mode, + poly_int64 offset, poly_int64 size) +{ + gcc_assert (has_subreg_object_p (regno)); + int nblocks = get_nblocks (reg_mode); + if (!subreg_p) + return subreg_range (0, nblocks); + + poly_int64 unit_size = REGMODE_NATURAL_SIZE (reg_mode); + poly_int64 left = offset + size; + + int subreg_start = -1; + int subreg_nregs = -1; + for (int i = 0; i < nblocks; i += 1) + { + poly_int64 right = unit_size * (i + 1); + if (subreg_start < 0 && maybe_lt (offset, right)) + subreg_start = i; + if (subreg_nregs < 0 && maybe_le (left, right)) + { + subreg_nregs = i + 1 - subreg_start; + break; + } + } + gcc_assert (subreg_start >= 0 && subreg_nregs > 0); + return subreg_range (subreg_start, subreg_start + subreg_nregs); +} + +/* Return the subreg range of rtx SUBREG in hard regs. */ +subreg_range +get_range_hard_regs (int regno, const subreg_range &r) +{ + if (!has_subreg_object_p (regno) || lra_reg_info[regno].reg_mode == VOIDmode) + return subreg_range (0, 1); + enum reg_class aclass = lra_get_allocno_class (regno); + gcc_assert (aclass != NO_REGS); + int nregs = ira_reg_class_max_nregs[aclass][lra_reg_info[regno].reg_mode]; + int nblocks = get_nblocks (lra_reg_info[regno].reg_mode); + int times = nblocks / nregs; + gcc_assert (nblocks >= nregs && times * nregs == nblocks); + int start = r.start / times; + int end = CEIL (r.end, times); + + return subreg_range (start, end); +} + /* Create LRA insn related info about a reference to REGNO in INSN with TYPE (in/out/inout), biggest reference mode MODE, flag that it is reference through subreg (SUBREG_P), and reference to the next @@ -573,21 +621,49 @@ object_allocator lra_insn_reg_pool ("insn regs"); alternatives in which it can be early clobbered are given by EARLY_CLOBBER_ALTS. */ static struct lra_insn_reg * -new_insn_reg (rtx_insn *insn, int regno, enum op_type type, - machine_mode mode, bool subreg_p, - alternative_mask early_clobber_alts, +new_insn_reg (rtx_insn *insn, int regno, enum op_type type, poly_int64 size, + poly_int64 offset, machine_mode mode, machine_mode reg_mode, + bool subreg_p, alternative_mask early_clobber_alts, struct lra_insn_reg *next) { lra_insn_reg *ir = lra_insn_reg_pool.allocate (); ir->type = type; ir->biggest_mode = mode; - if (NONDEBUG_INSN_P (insn) - && partial_subreg_p (lra_reg_info[regno].biggest_mode, mode)) - lra_reg_info[regno].biggest_mode = mode; + if (NONDEBUG_INSN_P (insn)) + { + if (partial_subreg_p (lra_reg_info[regno].biggest_mode, mode)) + { + lra_reg_info[regno].biggest_mode = mode; + } + + if (regno >= FIRST_PSEUDO_REGISTER) + { + if (lra_reg_info[regno].reg_mode == VOIDmode) + lra_reg_info[regno].reg_mode = reg_mode; + else + gcc_assert (maybe_eq (GET_MODE_SIZE (lra_reg_info[regno].reg_mode), + GET_MODE_SIZE (reg_mode))); + } + } ir->subreg_p = subreg_p; ir->early_clobber_alts = early_clobber_alts; ir->regno = regno; ir->next = next; + if (has_subreg_object_p (regno)) + { + const subreg_range &r + = get_range_blocks (regno, subreg_p, reg_mode, offset, size); + ir->start = r.start; + ir->end = r.end; + const subreg_range &r_hard = get_range_hard_regs (regno, r); + ir->start_reg = r_hard.start; + ir->end_reg = r_hard.end; + } + else + { + ir->start = 0; + ir->end = 1; + } return ir; } @@ -887,11 +963,18 @@ collect_non_operand_hard_regs (rtx_insn *insn, rtx *x, return list; mode = GET_MODE (op); subreg_p = false; + poly_int64 size = GET_MODE_SIZE (mode); + poly_int64 offset = 0; if (code == SUBREG) { mode = wider_subreg_mode (op); if (read_modify_subreg_p (op)) - subreg_p = true; + { + offset = SUBREG_BYTE (op); + subreg_p = true; + } + else + size = GET_MODE_SIZE (GET_MODE (SUBREG_REG (op))); op = SUBREG_REG (op); code = GET_CODE (op); } @@ -925,7 +1008,8 @@ collect_non_operand_hard_regs (rtx_insn *insn, rtx *x, && ! (FIRST_STACK_REG <= regno && regno <= LAST_STACK_REG)); #endif - list = new_insn_reg (data->insn, regno, type, mode, subreg_p, + list = new_insn_reg (data->insn, regno, type, size, offset, mode, + GET_MODE (op), subreg_p, early_clobber ? ALL_ALTERNATIVES : 0, list); } } @@ -1354,6 +1438,7 @@ initialize_lra_reg_info_element (int i) lra_reg_info[i].preferred_hard_regno_profit1 = 0; lra_reg_info[i].preferred_hard_regno_profit2 = 0; lra_reg_info[i].biggest_mode = VOIDmode; + lra_reg_info[i].reg_mode = VOIDmode; lra_reg_info[i].live_ranges = NULL; lra_reg_info[i].nrefs = lra_reg_info[i].freq = 0; lra_reg_info[i].last_reload = 0; @@ -1459,7 +1544,21 @@ lra_get_copy (int n) return copy_vec[n]; } - +/* Return true if REG occupied the same blocks as OFFSET + SIZE subreg. */ +static bool +reg_same_range_p (lra_insn_reg *reg, poly_int64 offset, poly_int64 size, + bool subreg_p) +{ + if (has_subreg_object_p (reg->regno)) + { + const subreg_range &r + = get_range_blocks (reg->regno, subreg_p, + lra_reg_info[reg->regno].reg_mode, offset, size); + return r.start == reg->start && r.end == reg->end; + } + else + return true; +} /* This page contains code dealing with info about registers in insns. */ @@ -1483,11 +1582,18 @@ add_regs_to_insn_regno_info (lra_insn_recog_data_t data, rtx x, code = GET_CODE (x); mode = GET_MODE (x); subreg_p = false; + poly_int64 size = GET_MODE_SIZE (mode); + poly_int64 offset = 0; if (GET_CODE (x) == SUBREG) { mode = wider_subreg_mode (x); if (read_modify_subreg_p (x)) - subreg_p = true; + { + offset = SUBREG_BYTE (x); + subreg_p = true; + } + else + size = GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))); x = SUBREG_REG (x); code = GET_CODE (x); } @@ -1499,7 +1605,8 @@ add_regs_to_insn_regno_info (lra_insn_recog_data_t data, rtx x, expand_reg_info (); if (bitmap_set_bit (&lra_reg_info[regno].insn_bitmap, INSN_UID (insn))) { - data->regs = new_insn_reg (data->insn, regno, type, mode, subreg_p, + data->regs = new_insn_reg (data->insn, regno, type, size, offset, + mode, GET_MODE (x), subreg_p, early_clobber_alts, data->regs); return; } @@ -1508,12 +1615,14 @@ add_regs_to_insn_regno_info (lra_insn_recog_data_t data, rtx x, for (curr = data->regs; curr != NULL; curr = curr->next) if (curr->regno == regno) { - if (curr->subreg_p != subreg_p || curr->biggest_mode != mode) + if (!reg_same_range_p (curr, offset, size, subreg_p) + || curr->biggest_mode != mode) /* The info cannot be integrated into the found structure. */ - data->regs = new_insn_reg (data->insn, regno, type, mode, - subreg_p, early_clobber_alts, - data->regs); + data->regs + = new_insn_reg (data->insn, regno, type, size, offset, mode, + GET_MODE (x), subreg_p, early_clobber_alts, + data->regs); else { if (curr->type != type)