From patchwork Wed Nov 8 03:47:40 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lehua Ding X-Patchwork-Id: 79366 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 77223385700D for ; Wed, 8 Nov 2023 03:49:06 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from smtpbgbr1.qq.com (smtpbgbr1.qq.com [54.207.19.206]) by sourceware.org (Postfix) with ESMTPS id 20B49385843A for ; Wed, 8 Nov 2023 03:48:31 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 20B49385843A 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 20B49385843A Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=54.207.19.206 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1699415318; cv=none; b=mfb5PdHHUW2h+EnCSs4y6D240/szkAm0P7lDWB7j01KkCNDIrIH9d5ot/t7/bUr38+4OYigpupEAyAHJhpiYEGKnHVhWKZ06BO0P2qWlrRTR5+tvHv1s6hxi55CinUWWwFO0esq6JDFaeuZ9hWqP2lT+bKuH+/H6Eih+bXNAdXw= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1699415318; c=relaxed/simple; bh=oIrhcxt6k9/WL+1QtmxuEyZn/YFoC/IMv6hk2Aeno5U=; h=From:To:Subject:Date:Message-Id:MIME-Version; b=oDPdACtZ8F9UAegEXzaWeMUPYULYf+KXFcb3x78dTFVmNqXjvLkGclvfBSruMSQ3hgiSYxrKWE69KLrFwHYlQ6Re3td/hvg1KuE1Q6QnPPe+yKugOw1InEDYIB4otaVH+hkocv4ytWUDyDyWo5/sR0fM/0c2NY4BF0IUJZRSZYg= ARC-Authentication-Results: i=1; server2.sourceware.org X-QQ-mid: bizesmtp81t1699415285tnv77siz Received: from rios-cad121.hadoop.rioslab.org ( [58.60.1.9]) by bizesmtp.qq.com (ESMTP) with id ; Wed, 08 Nov 2023 11:48:04 +0800 (CST) X-QQ-SSF: 01400000000000C0F000000A0000000 X-QQ-FEAT: 1aHTM9ylpVxqg9GvzHHMpF2YkJiCySa/kPpPLBaW86by7m3bnWIhqcCtMe2ka cZQmoLMeJspOZfrPcHkd5+iKzUFf8WJjyZhzDjgk0ok5jn4/l+erOk20RgY2OVSMu/Dn44n EyM1g4BHNtI8tMYhcc1c5I0WlqONyNYuViBOe6+6gLPg6mjS+bWsKpbGUMg4P7gEzk3r2v3 BC8UqcTvJJrfEP3IYBx38Qn9TbpvQhtXZdSxT3gXvjj0ORIYu76Qpojyh/YucLclxt7Dxjc 4G8weEeUJSRXzYwxlARcmzwK1GN+TZu5iNip+/B4d5EuwDriglt3kjSsSldA/8inhU7mR2c 4FVuwaAQ7c7I1FA0F+bWedmLTdogMEU2ELkJsFGlzbLe3BKAYQ+x4AKYYeWdiaMwiFhulC0 X-QQ-GoodBg: 2 X-BIZMAIL-ID: 11019565537794461922 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 7/7] lra: Support subreg live range track and conflict detect Date: Wed, 8 Nov 2023 11:47:40 +0800 Message-Id: <20231108034740.834590-8-lehua.ding@rivai.ai> X-Mailer: git-send-email 2.36.3 In-Reply-To: <20231108034740.834590-1-lehua.ding@rivai.ai> References: <20231108034740.834590-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_H3, RCVD_IN_MSPIKE_WL, 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+patchwork=sourceware.org@gcc.gnu.org This patch implements tracking of the live range of subregs and synchronously modifies conflict detection. gcc/ChangeLog: * ira-build.cc (print_copy): Adjust print. (setup_pseudos_has_subreg_object): New. (ira_build): collect subreg object allocno. * lra-assigns.cc (set_offset_conflicts): New. (setup_live_pseudos_and_spill_after_risky_transforms): Adjust. (lra_assign): Adjust. * lra-constraints.cc (process_alt_operands): Relax. * lra-int.h (GCC_LRA_INT_H): New include. (struct lra_live_range): New field subreg. (struct lra_insn_reg): New fields. (get_range_hard_regs): Exported. (get_nregs): New. (has_subreg_object_p): New. * lra-lives.cc (INCLUDE_VECTOR): New. (lra_live_range_pool): New. (create_live_range): Adjust. (lra_merge_live_ranges): Adjust. (update_pseudo_point): Adjust. (class bb_data_pseudos): New. (mark_regno_live): Adjust. (mark_regno_dead): Adjust. (process_bb_lives): Adjust. (remove_some_program_points_and_update_live_ranges): Adjust. (lra_print_live_range_list): Adjust print. (class subreg_live_item): New class. (create_subregs_live_ranges): New. (lra_create_live_ranges_1): Add subreg live ranges. * lra.cc (get_range_blocks): New. (get_range_hard_regs): New. (new_insn_reg): Adjust. (collect_non_operand_hard_regs): Adjust. (initialize_lra_reg_info_element): Adjust. (reg_same_range_p): New. (add_regs_to_insn_regno_info): Adjust. * subreg-live-range.h: New constructor. --- gcc/ira-build.cc | 40 ++++- gcc/lra-assigns.cc | 111 ++++++++++-- gcc/lra-constraints.cc | 18 +- gcc/lra-int.h | 33 ++++ gcc/lra-lives.cc | 361 ++++++++++++++++++++++++++++++++++------ gcc/lra.cc | 139 ++++++++++++++-- gcc/subreg-live-range.h | 1 + 7 files changed, 614 insertions(+), 89 deletions(-) diff --git a/gcc/ira-build.cc b/gcc/ira-build.cc index 379f877ca67..cba38d5fecb 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 @@ -1688,8 +1691,13 @@ print_copy (FILE *f, ira_copy_t cp) { ira_allocno_t a1 = OBJECT_ALLOCNO (cp->first); ira_allocno_t a2 = OBJECT_ALLOCNO (cp->second); - fprintf (f, " cp%d:a%d(r%d)<->a%d(r%d)@%d:%s\n", cp->num, ALLOCNO_NUM (a1), - ALLOCNO_REGNO (a1), ALLOCNO_NUM (a2), ALLOCNO_REGNO (a2), cp->freq, + fprintf (f, " cp%d:a%d(r%d", cp->num, ALLOCNO_NUM (a1), ALLOCNO_REGNO (a1)); + if (ALLOCNO_NREGS (a1) != OBJECT_NREGS (cp->first)) + fprintf (f, "_obj%d", OBJECT_INDEX (cp->first)); + fprintf (f, ")<->a%d(r%d", ALLOCNO_NUM (a2), ALLOCNO_REGNO (a2)); + if (ALLOCNO_NREGS (a2) != OBJECT_NREGS (cp->second)) + fprintf (f, "_obj%d", OBJECT_INDEX (cp->second)); + fprintf (f, ")@%d:%s\n", cp->freq, cp->insn != NULL ? "move" : cp->constraint_p ? "constraint" : "shuffle"); @@ -3706,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 @@ -3726,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 d0752c2ae50..5a97bd61475 100644 --- a/gcc/lra-int.h +++ b/gcc/lra-int.h @@ -21,6 +21,9 @@ 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) /* The parameter used to prevent infinite reloading for an insn. Each @@ -46,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; @@ -108,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 @@ -159,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; }; @@ -330,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; @@ -531,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 477b82786cf..814b3960541 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" @@ -44,6 +45,7 @@ along with GCC; see the file COPYING3. If not see #include "lra-int.h" #include "target.h" #include "function-abi.h" +#include "subreg-live-range.h" /* Program points are enumerated by numbers from range 0..LRA_LIVE_MAX_POINT-1. There are approximately two times more @@ -97,6 +99,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 +118,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 +179,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 +190,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 +254,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,31 +270,100 @@ 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); + } } -/* The corresponding bitmaps of BB currently being processed. */ -static bitmap bb_killed_pseudos, bb_gen_pseudos; +/* 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 + live-analysis. */ +class bb_data_pseudos : public basic_block_subreg_live_info +{ +public: + /* Basic block about which the below data are. */ + basic_block bb; +}; + +/* Array for all BB data. Indexed by the corresponding BB index. */ +typedef class bb_data_pseudos *bb_data_t; + +/* All basic block data are referred through the following array. */ +static bb_data_t bb_data; + +/* The corresponding basic block info of BB currently being processed. */ +static bb_data_t curr_bb_info; + +/* Flag mean curr function has subreg ref need be tracked. */ +static bool has_subreg_live_p; /* Record hard register REGNO as now being live. It updates living hard regs and START_LIVING. */ @@ -336,12 +426,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) { @@ -352,6 +448,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); @@ -361,9 +462,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) { @@ -374,6 +492,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); @@ -384,7 +508,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 @@ -814,7 +953,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); } @@ -1007,8 +1151,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); } @@ -1029,17 +1176,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) @@ -1070,7 +1220,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 @@ -1091,9 +1241,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); } @@ -1113,22 +1266,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; @@ -1144,7 +1300,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. */ @@ -1277,13 +1433,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)) @@ -1384,7 +1544,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; @@ -1402,8 +1563,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"); } @@ -1476,7 +1647,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; @@ -1557,6 +1805,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]); @@ -1639,9 +1889,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..47d378b371e 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)) + 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) diff --git a/gcc/subreg-live-range.h b/gcc/subreg-live-range.h index bee97708a52..b703b9642f2 100644 --- a/gcc/subreg-live-range.h +++ b/gcc/subreg-live-range.h @@ -76,6 +76,7 @@ public: int max; std::set ranges; + subreg_ranges () : max (1) {} subreg_ranges (int max) : max (max) { gcc_assert (maybe_ge (max, 1)); } /* Modify ranges. */