From patchwork Mon Nov 12 04:34:32 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter Bergner X-Patchwork-Id: 996265 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-489688-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=linux.ibm.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="jdnBY7ov"; dkim-atps=neutral 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 42tdG71fbYz9s5c for ; Mon, 12 Nov 2018 15:34:55 +1100 (AEDT) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:to:cc :from:subject:date:mime-version:content-type :content-transfer-encoding:message-id; q=dns; s=default; b=DGZqq swPFo7zUeuvfcO8rD1ybeTLG1dYYFm/R/ftKvYF8yjDPHkD7jVdov1eizlvFzcnM YAxvK94imyhy3+xXePQhAhewoY8uXP5x1q/vfAeGZH/CGZC8qBfhsJfGAeR8sDj3 F4lufLBzu/6ZWsS1fpqWigMigdI/TIHW8teT+0= 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:to:cc :from:subject:date:mime-version:content-type :content-transfer-encoding:message-id; s=default; bh=oKy4tJ69aiQ /NjtmmkS4FVnV2mY=; b=jdnBY7ovu3P4feYo23xArKDC0P+JTeWKt4S1DcRdbPo /hTMOI1WQiO8ZhGjqnfdAhVB9rPYBUSTG9uSDDftrPTpt/ZzWBr4tEU+NI9BIfmt dvvubR/bDSaIOk+EWiFRqWLSrOfT0Fi1aFAPkXcQFF8hHQl39PL81EfJwRhaNiCg = Received: (qmail 109405 invoked by alias); 12 Nov 2018 04:34:47 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 109393 invoked by uid 89); 12 Nov 2018 04:34:46 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-11.7 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_2, GIT_PATCH_3, RCVD_IN_DNSWL_LOW, SPF_PASS autolearn=ham version=3.3.2 spammy=Bonus, sk:hard_re, sk:HARD_RE, r2040 X-HELO: mx0a-001b2d01.pphosted.com Received: from mx0b-001b2d01.pphosted.com (HELO mx0a-001b2d01.pphosted.com) (148.163.158.5) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Mon, 12 Nov 2018 04:34:42 +0000 Received: from pps.filterd (m0098421.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.0.22/8.16.0.22) with SMTP id wAC4XwTi054055 for ; Sun, 11 Nov 2018 23:34:40 -0500 Received: from e31.co.us.ibm.com (e31.co.us.ibm.com [32.97.110.149]) by mx0a-001b2d01.pphosted.com with ESMTP id 2nq2a7rhny-1 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=NOT) for ; Sun, 11 Nov 2018 23:34:39 -0500 Received: from localhost by e31.co.us.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Mon, 12 Nov 2018 04:34:38 -0000 Received: from b03cxnp07029.gho.boulder.ibm.com (9.17.130.16) by e31.co.us.ibm.com (192.168.1.131) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; (version=TLSv1/SSLv3 cipher=AES256-GCM-SHA384 bits=256/256) Mon, 12 Nov 2018 04:34:35 -0000 Received: from b03ledav006.gho.boulder.ibm.com (b03ledav006.gho.boulder.ibm.com [9.17.130.237]) by b03cxnp07029.gho.boulder.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id wAC4YYZM20775122 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Mon, 12 Nov 2018 04:34:34 GMT Received: from b03ledav006.gho.boulder.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 4A037C605A; Mon, 12 Nov 2018 04:34:34 +0000 (GMT) Received: from b03ledav006.gho.boulder.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id D0D70C6055; Mon, 12 Nov 2018 04:34:32 +0000 (GMT) Received: from otta.local (unknown [9.85.156.246]) by b03ledav006.gho.boulder.ibm.com (Postfix) with ESMTP; Mon, 12 Nov 2018 04:34:32 +0000 (GMT) To: Renlin Li , Jeff Law , Vladimir N Makarov Cc: GCC Patches , Christophe Lyon , Ramana Radhakrishnan , Kyrylo Tkachov , Wilco Dijkstra From: Peter Bergner Subject: [PATCH][LRA] Fix PR87899: r264897 cause mis-compiled native arm-linux-gnueabihf toolchain Date: Sun, 11 Nov 2018 22:34:32 -0600 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:52.0) Gecko/20100101 Thunderbird/52.9.1 MIME-Version: 1.0 x-cbid: 18111204-8235-0000-0000-00000E25DD7E X-IBM-SpamModules-Scores: X-IBM-SpamModules-Versions: BY=3.00010030; HX=3.00000242; KW=3.00000007; PH=3.00000004; SC=3.00000270; SDB=6.01116187; UDB=6.00578839; IPR=6.00896296; MB=3.00024117; MTD=3.00000008; XFM=3.00000015; UTC=2018-11-12 04:34:37 X-IBM-AV-DETECTION: SAVI=unused REMOTE=unused XFE=unused x-cbparentid: 18111204-8236-0000-0000-000043535CF7 Message-Id: <04a0c117-8d96-3963-fdcd-fdd0467fa9f7@linux.ibm.com> X-IsSubscribed: yes Renlin, Jeff and Vlad: requests and questions for you below... PR87899 shows another latent LRA bug exposed by my r264897 commit. In the bugzilla report, we have the following rtl in LRA: (insn 1 (set (reg:SI 1 r1) (reg/f:SI 2040))) ... (insn 2 (set (mem/f/c:SI (pre_modify:SI (reg:SI 1 r1) (plus:SI (reg:SI 1 r1) (const_int 12)))) (reg:SI 1048)) (expr_list:REG_INC (reg:SI 1 r1))) ... My earlier patch now sees the reg copy in insn "1" and correctly skips adding a conflict between r1 and r2040 due to the copy. However, insn "2" updates r1 and r2040 is live across that update and so we should create a conflict between them, but we currently do not and that leads to us assigning r1 to one of r2040's reload pseudos which gets clobbered by the r1 update in insn "2". The reason a conflict was never added between r1 and r2040 is that LRA skips INOUT operands when computing conflicts and so misses the definition of r1 in insn "2" and so never adds conflicts for it. The reason the code skips the INOUT operands is that LRA doesn't want to create new program points for INOUT operands, since unnecessary program points can slow down remove_some_program_points_and_update_live_ranges. This was all fine before when we had conservative conflict info, but now we cannot ignore INOUT operands. The heart of the problem is that the {make,mark}_*_{live,dead} routines update the liveness, conflict and program point information for operands. My solution to the problem was to pull out the updating of the program point info from {make,mark}_*_{live,dead} and have them only update liveness and conflict information. I then created a separate function that is used for updating an operand's program points. This allowed me to modify the insn operand scanning to handle all operand types (IN, OUT and INOUT) and always call the {make,mark}_*_{live,dead} functions for all operand types, while only calling the new program point update function for IN and OUT operands. This change then allowed me to remove the hacky handling of conflicts for reg copies and instead use the more common method of removing the src reg of a copy from the live set before handling the copy's definition, thereby skipping the unwanted conflict. Bonus! :-) This passes bootstrap and regtesting on powerpc64le-linux with no regressions. Renlin, can you please verify that this patch fixes the issue you ran into? Jeff, could you please throw this on your test builders to see whether it exposes any problems with the patch I didn't see? Otherwise, Vlad and Jeff, what do you think of this solution? I'll note that I have compiled quite a few largish test cases and so far I am seeing the same exact program points being used in the LRA rtl dump before and after my patch. I'm continuing to do that with more tests to make sure I have everything working correctly. I'll also note I took the opportunity to convert lra-lives.c over to using the HARD_REGISTER_P and HARD_REGISTER_NUM_P convenience macros. Peter gcc/ PR rtl-optimization/87899 * lra-lives.c (start_living): Update white space in comment. (enum point_type): New. (sparseset_contains_pseudos_p): New function. (update_pseudo_point): Likewise. (make_hard_regno_live): Use HARD_REGISTER_NUM_P macro. (make_hard_regno_dead): Likewise. Remove ignore_reg_for_conflicts handling. Move early exit after adding conflicts. (mark_pseudo_live): Use HARD_REGISTER_NUM_P macro. Add early exit if regno is already live. Remove all handling of program points. (mark_pseudo_dead): Use HARD_REGISTER_NUM_P macro. Add early exit after adding conflicts. Remove all handling of program points and ignore_reg_for_conflicts. (mark_regno_live): Use HARD_REGISTER_NUM_P macro. Remove return value and do not guard call to mark_pseudo_live. (mark_regno_dead): Use HARD_REGISTER_NUM_P macro. Remove return value and do not guard call to mark_pseudo_dead. (check_pseudos_live_through_calls): Use HARD_REGISTER_NUM_P macro. (process_bb_lives): Use HARD_REGISTER_NUM_P and HARD_REGISTER_P macros. Use new function update_pseudo_point. Handle register copies by removing the source register from the live set. Handle INOUT operands. Update to the next program point using the unused_set, dead_set and start_dying sets. (lra_create_live_ranges_1): Use HARD_REGISTER_NUM_P macro. Index: gcc/lra-lives.c =================================================================== --- gcc/lra-lives.c (revision 265971) +++ gcc/lra-lives.c (working copy) @@ -83,7 +83,7 @@ static HARD_REG_SET hard_regs_live; /* Set of pseudos and hard registers start living/dying in the current insn. These sets are used to update REG_DEAD and REG_UNUSED notes - in the insn. */ + in the insn. */ static sparseset start_living, start_dying; /* Set of pseudos and hard regs dead and unused in the current @@ -96,10 +96,6 @@ static bitmap_head temp_bitmap; /* Pool for pseudo live ranges. */ static object_allocator lra_live_range_pool ("live ranges"); -/* If non-NULL, the source operand of a register to register copy for which - we should not add a conflict with the copy's destination operand. */ -static rtx ignore_reg_for_conflicts; - /* Free live range list LR. */ static void free_live_range_list (lra_live_range_t lr) @@ -224,6 +220,57 @@ lra_intersected_live_ranges_p (lra_live_ return false; } +enum point_type { + DEF_POINT, + USE_POINT +}; + +/* Return TRUE if set A contains a pseudo register, otherwise, return FALSE. */ +static bool +sparseset_contains_pseudos_p (sparseset a) +{ + int regno; + EXECUTE_IF_SET_IN_SPARSESET (a, regno) + if (!HARD_REGISTER_NUM_P (regno)) + return true; + return false; +} + +/* 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. */ + +static void +update_pseudo_point (int regno, int point, enum point_type type) +{ + lra_live_range_t p; + + /* 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 (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 */ + { + 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; @@ -232,7 +279,7 @@ static bitmap bb_killed_pseudos, bb_gen_ static void make_hard_regno_live (int regno) { - lra_assert (regno < FIRST_PSEUDO_REGISTER); + lra_assert (HARD_REGISTER_NUM_P (regno)); if (TEST_HARD_REG_BIT (hard_regs_live, regno)) return; SET_HARD_REG_BIT (hard_regs_live, regno); @@ -247,19 +294,15 @@ make_hard_regno_live (int regno) static void make_hard_regno_dead (int regno) { - lra_assert (regno < FIRST_PSEUDO_REGISTER); - if (! TEST_HARD_REG_BIT (hard_regs_live, regno)) - return; - sparseset_set_bit (start_dying, regno); + lra_assert (HARD_REGISTER_NUM_P (regno)); unsigned int i; EXECUTE_IF_SET_IN_SPARSESET (pseudos_live, i) - { - if (ignore_reg_for_conflicts != NULL_RTX - && REGNO (ignore_reg_for_conflicts) == i) - continue; - SET_HARD_REG_BIT (lra_reg_info[i].conflict_hard_regs, regno); - } + SET_HARD_REG_BIT (lra_reg_info[i].conflict_hard_regs, regno); + + if (! TEST_HARD_REG_BIT (hard_regs_live, regno)) + return; CLEAR_HARD_REG_BIT (hard_regs_live, regno); + sparseset_set_bit (start_dying, regno); if (fixed_regs[regno] || TEST_HARD_REG_BIT (hard_regs_spilled_into, regno)) { bitmap_clear_bit (bb_gen_pseudos, regno); @@ -267,130 +310,69 @@ make_hard_regno_dead (int regno) } } -/* Mark pseudo REGNO as living at program point POINT, update START_LIVING - and start a new live range for the pseudo corresponding to REGNO if it - is necessary. */ +/* Mark pseudo REGNO as now being live and update START_LIVING. */ static void -mark_pseudo_live (int regno, int point) +mark_pseudo_live (int regno) { - lra_live_range_t p; + lra_assert (!HARD_REGISTER_NUM_P (regno)); + if (sparseset_bit_p (pseudos_live, regno)) + return; - lra_assert (regno >= FIRST_PSEUDO_REGISTER); - lra_assert (! sparseset_bit_p (pseudos_live, regno)); sparseset_set_bit (pseudos_live, regno); - - if ((complete_info_p || lra_get_regno_hard_regno (regno) < 0) - && ((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); sparseset_set_bit (start_living, regno); } -/* Mark pseudo REGNO as not living at program point POINT and update - START_DYING. - This finishes the current live range for the pseudo corresponding - to REGNO. */ +/* Mark pseudo REGNO as now being dead and update START_DYING. */ static void -mark_pseudo_dead (int regno, int point) +mark_pseudo_dead (int regno) { - lra_live_range_t p; - int ignore_regno = -1; - int end_regno = -1; + lra_assert (!HARD_REGISTER_NUM_P (regno)); + IOR_HARD_REG_SET (lra_reg_info[regno].conflict_hard_regs, hard_regs_live); + if (!sparseset_bit_p (pseudos_live, regno)) + return; - lra_assert (regno >= FIRST_PSEUDO_REGISTER); - lra_assert (sparseset_bit_p (pseudos_live, regno)); sparseset_clear_bit (pseudos_live, regno); sparseset_set_bit (start_dying, regno); - - /* Check whether any part of IGNORE_REG_FOR_CONFLICTS already conflicts - with REGNO. */ - if (ignore_reg_for_conflicts != NULL_RTX - && REGNO (ignore_reg_for_conflicts) < FIRST_PSEUDO_REGISTER) - { - end_regno = END_REGNO (ignore_reg_for_conflicts); - int src_regno = ignore_regno = REGNO (ignore_reg_for_conflicts); - - while (src_regno < end_regno) - { - if (TEST_HARD_REG_BIT (lra_reg_info[regno].conflict_hard_regs, - src_regno)) - { - ignore_regno = end_regno = -1; - break; - } - src_regno++; - } - } - - IOR_HARD_REG_SET (lra_reg_info[regno].conflict_hard_regs, hard_regs_live); - - /* If IGNORE_REG_FOR_CONFLICTS did not already conflict with REGNO, make - sure it still doesn't. */ - for (; ignore_regno < end_regno; ignore_regno++) - CLEAR_HARD_REG_BIT (lra_reg_info[regno].conflict_hard_regs, ignore_regno); - - if (complete_info_p || lra_get_regno_hard_regno (regno) < 0) - { - p = lra_reg_info[regno].live_ranges; - lra_assert (p != NULL); - p->finish = point; - } } -/* Mark register REGNO (pseudo or hard register) in MODE as live at - program point POINT. Update BB_GEN_PSEUDOS. - Return TRUE if the liveness tracking sets were modified, or FALSE - if nothing changed. */ -static bool -mark_regno_live (int regno, machine_mode mode, int point) +/* Mark register REGNO (pseudo or hard register) in MODE as being live + and update BB_GEN_PSEUDOS. */ +static void +mark_regno_live (int regno, machine_mode mode) { int last; - bool changed = false; - if (regno < FIRST_PSEUDO_REGISTER) + if (HARD_REGISTER_NUM_P (regno)) { for (last = end_hard_regno (mode, regno); regno < last; regno++) make_hard_regno_live (regno); } else { - if (! sparseset_bit_p (pseudos_live, regno)) - { - mark_pseudo_live (regno, point); - changed = true; - } + mark_pseudo_live (regno); bitmap_set_bit (bb_gen_pseudos, regno); } - return changed; } -/* Mark register REGNO in MODE as dead at program point POINT. Update - BB_GEN_PSEUDOS and BB_KILLED_PSEUDOS. Return TRUE if the liveness - tracking sets were modified, or FALSE if nothing changed. */ -static bool -mark_regno_dead (int regno, machine_mode mode, int point) +/* Mark register REGNO (pseudo or hard register) in MODE as being dead + and update BB_GEN_PSEUDOS and BB_KILLED_PSEUDOS. */ +static void +mark_regno_dead (int regno, machine_mode mode) { int last; - bool changed = false; - if (regno < FIRST_PSEUDO_REGISTER) + if (HARD_REGISTER_NUM_P (regno)) { for (last = end_hard_regno (mode, regno); regno < last; regno++) make_hard_regno_dead (regno); } else { - if (sparseset_bit_p (pseudos_live, regno)) - { - mark_pseudo_dead (regno, point); - changed = true; - } + mark_pseudo_dead (regno); bitmap_clear_bit (bb_gen_pseudos, regno); bitmap_set_bit (bb_killed_pseudos, regno); } - return changed; } @@ -607,7 +589,7 @@ check_pseudos_live_through_calls (int re IOR_HARD_REG_SET (lra_reg_info[regno].conflict_hard_regs, last_call_used_reg_set); - for (hr = 0; hr < FIRST_PSEUDO_REGISTER; hr++) + for (hr = 0; HARD_REGISTER_NUM_P (hr); hr++) if (targetm.hard_regno_call_part_clobbered (hr, PSEUDO_REGNO_MODE (regno))) add_to_hard_reg_set (&lra_reg_info[regno].conflict_hard_regs, @@ -653,7 +635,7 @@ process_bb_lives (basic_block bb, int &c rtx link, *link_loc; bool need_curr_point_incr; HARD_REG_SET last_call_used_reg_set; - + reg_live_out = df_get_live_out (bb); sparseset_clear (pseudos_live); sparseset_clear (pseudos_live_through_calls); @@ -662,7 +644,10 @@ process_bb_lives (basic_block bb, int &c REG_SET_TO_HARD_REG_SET (hard_regs_live, reg_live_out); AND_COMPL_HARD_REG_SET (hard_regs_live, eliminable_regset); EXECUTE_IF_SET_IN_BITMAP (reg_live_out, FIRST_PSEUDO_REGISTER, j, bi) - mark_pseudo_live (j, curr_point); + { + update_pseudo_point (j, curr_point, USE_POINT); + mark_pseudo_live (j); + } bb_gen_pseudos = &get_bb_data (bb)->gen_pseudos; bb_killed_pseudos = &get_bb_data (bb)->killed_pseudos; @@ -702,7 +687,7 @@ process_bb_lives (basic_block bb, int &c set = single_set (curr_insn); if (dead_insn_p && set != NULL_RTX - && REG_P (SET_DEST (set)) && REGNO (SET_DEST (set)) >= FIRST_PSEUDO_REGISTER + && REG_P (SET_DEST (set)) && !HARD_REGISTER_P (SET_DEST (set)) && find_reg_note (curr_insn, REG_EH_REGION, NULL_RTX) == NULL_RTX && ! may_trap_p (PATTERN (curr_insn)) /* Don't do premature remove of pic offset pseudo as we can @@ -759,7 +744,7 @@ process_bb_lives (basic_block bb, int &c if (partial_subreg_p (lra_reg_info[regno].biggest_mode, reg->biggest_mode)) lra_reg_info[regno].biggest_mode = reg->biggest_mode; - if (regno < FIRST_PSEUDO_REGISTER) + if (HARD_REGISTER_NUM_P (regno)) { lra_hard_reg_usage[regno] += freq; /* A hard register explicitly can be used in small mode, @@ -775,7 +760,26 @@ process_bb_lives (basic_block bb, int &c } call_p = CALL_P (curr_insn); - ignore_reg_for_conflicts = non_conflicting_reg_copy_p (curr_insn); + + /* If we have a simple register copy and the source reg is live after + this instruction, then remove the source reg from the live set so + that it will not conflict with the destination reg. */ + rtx ignore_reg = non_conflicting_reg_copy_p (curr_insn); + if (ignore_reg != NULL_RTX) + { + int ignore_regno = REGNO (ignore_reg); + if (HARD_REGISTER_NUM_P (ignore_regno) + && TEST_HARD_REG_BIT (hard_regs_live, ignore_regno)) + CLEAR_HARD_REG_BIT (hard_regs_live, ignore_regno); + else if (!HARD_REGISTER_NUM_P (ignore_regno) + && sparseset_bit_p (pseudos_live, ignore_regno)) + sparseset_clear_bit (pseudos_live, ignore_regno); + else + /* We don't need any special handling of the source reg if + it is dead after this instruction. */ + ignore_reg = NULL_RTX; + } + src_regno = (set != NULL_RTX && REG_P (SET_SRC (set)) ? REGNO (SET_SRC (set)) : -1); dst_regno = (set != NULL_RTX && REG_P (SET_DEST (set)) @@ -785,13 +789,13 @@ process_bb_lives (basic_block bb, int &c /* Check that source regno does not conflict with destination regno to exclude most impossible preferences. */ - && (((src_regno >= FIRST_PSEUDO_REGISTER + && (((!HARD_REGISTER_NUM_P (src_regno) && (! sparseset_bit_p (pseudos_live, src_regno) - || (dst_regno >= FIRST_PSEUDO_REGISTER + || (!HARD_REGISTER_NUM_P (dst_regno) && lra_reg_val_equal_p (src_regno, lra_reg_info[dst_regno].val, lra_reg_info[dst_regno].offset)))) - || (src_regno < FIRST_PSEUDO_REGISTER + || (HARD_REGISTER_NUM_P (src_regno) && ! TEST_HARD_REG_BIT (hard_regs_live, src_regno))) /* It might be 'inheritance pseudo <- reload pseudo'. */ || (src_regno >= lra_constraint_new_regno_start @@ -816,13 +820,13 @@ process_bb_lives (basic_block bb, int &c } else if (dst_regno >= lra_constraint_new_regno_start) { - if ((hard_regno = src_regno) >= FIRST_PSEUDO_REGISTER) + if (!HARD_REGISTER_NUM_P (hard_regno = src_regno)) hard_regno = reg_renumber[src_regno]; regno = dst_regno; } else if (src_regno >= lra_constraint_new_regno_start) { - if ((hard_regno = dst_regno) >= FIRST_PSEUDO_REGISTER) + if (!HARD_REGISTER_NUM_P (hard_regno = dst_regno)) hard_regno = reg_renumber[dst_regno]; regno = src_regno; } @@ -833,12 +837,6 @@ process_bb_lives (basic_block bb, int &c sparseset_clear (start_living); - /* Try to avoid unnecessary program point increments, this saves - a lot of time in remove_some_program_points_and_update_live_ranges. - We only need an increment if something becomes live or dies at this - program point. */ - need_curr_point_incr = false; - /* Mark each defined value as live. We need to do this for unused values because they still conflict with quantities that are live at the time of the definition. */ @@ -846,14 +844,13 @@ process_bb_lives (basic_block bb, int &c { if (reg->type != OP_IN) { - need_curr_point_incr - |= mark_regno_live (reg->regno, reg->biggest_mode, - curr_point); + update_pseudo_point (reg->regno, curr_point, USE_POINT); + mark_regno_live (reg->regno, reg->biggest_mode); check_pseudos_live_through_calls (reg->regno, last_call_used_reg_set); } - if (reg->regno >= FIRST_PSEUDO_REGISTER) + if (!HARD_REGISTER_NUM_P (reg->regno)) for (hr = curr_static_id->hard_regs; hr != NULL; hr = hr->next) if (hr->clobber_high && maybe_gt (GET_MODE_SIZE (PSEUDO_REGNO_MODE (reg->regno)), @@ -868,7 +865,7 @@ process_bb_lives (basic_block bb, int &c if (curr_id->arg_hard_regs != NULL) for (i = 0; (regno = curr_id->arg_hard_regs[i]) >= 0; i++) - if (regno >= FIRST_PSEUDO_REGISTER) + if (!HARD_REGISTER_NUM_P (regno)) /* It is a clobber. */ make_hard_regno_live (regno - FIRST_PSEUDO_REGISTER); @@ -878,20 +875,22 @@ process_bb_lives (basic_block bb, int &c /* See which defined values die here. */ for (reg = curr_id->regs; reg != NULL; reg = reg->next) - if (reg->type == OP_OUT + if (reg->type != OP_IN && ! reg_early_clobber_p (reg, n_alt) && ! reg->subreg_p) - need_curr_point_incr - |= mark_regno_dead (reg->regno, reg->biggest_mode, - curr_point); + { + if (reg->type == OP_OUT) + update_pseudo_point (reg->regno, curr_point, DEF_POINT); + mark_regno_dead (reg->regno, reg->biggest_mode); + } for (reg = curr_static_id->hard_regs; reg != NULL; reg = reg->next) - if (reg->type == OP_OUT + 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) for (i = 0; (regno = curr_id->arg_hard_regs[i]) >= 0; i++) - if (regno >= FIRST_PSEUDO_REGISTER) + if (!HARD_REGISTER_NUM_P (regno)) /* It is a clobber. */ make_hard_regno_dead (regno - FIRST_PSEUDO_REGISTER); @@ -931,50 +930,63 @@ process_bb_lives (basic_block bb, int &c } /* Increment the current program point if we must. */ - if (need_curr_point_incr) + if (sparseset_contains_pseudos_p (unused_set) + || sparseset_contains_pseudos_p (start_dying)) next_program_point (curr_point, freq); sparseset_clear (start_living); - need_curr_point_incr = false; - /* Mark each used value as live. */ for (reg = curr_id->regs; reg != NULL; reg = reg->next) - if (reg->type == OP_IN) + if (reg->type != OP_OUT) { - need_curr_point_incr - |= mark_regno_live (reg->regno, reg->biggest_mode, - curr_point); + if (reg->type == OP_IN) + update_pseudo_point (reg->regno, curr_point, USE_POINT); + mark_regno_live (reg->regno, reg->biggest_mode); check_pseudos_live_through_calls (reg->regno, last_call_used_reg_set); } for (reg = curr_static_id->hard_regs; reg != NULL; reg = reg->next) - if (reg->type == OP_IN) + if (reg->type != OP_OUT) make_hard_regno_live (reg->regno); if (curr_id->arg_hard_regs != NULL) /* Make argument hard registers live. */ for (i = 0; (regno = curr_id->arg_hard_regs[i]) >= 0; i++) - if (regno < FIRST_PSEUDO_REGISTER) + if (HARD_REGISTER_NUM_P (regno)) make_hard_regno_live (regno); sparseset_and_compl (dead_set, start_living, start_dying); + /* If we removed the source reg from a simple register copy from the + live set, then it will appear to be dead, but it really isn't. */ + if (ignore_reg != NULL_RTX) + sparseset_clear_bit (dead_set, REGNO (ignore_reg)); + + sparseset_clear (start_dying); + /* Mark early clobber outputs dead. */ for (reg = curr_id->regs; reg != NULL; reg = reg->next) - if (reg->type == OP_OUT + if (reg->type != OP_IN && reg_early_clobber_p (reg, n_alt) && ! reg->subreg_p) - need_curr_point_incr - |= mark_regno_dead (reg->regno, reg->biggest_mode, - curr_point); + { + if (reg->type == OP_OUT) + update_pseudo_point (reg->regno, curr_point, DEF_POINT); + mark_regno_dead (reg->regno, 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); + } for (reg = curr_static_id->hard_regs; reg != NULL; reg = reg->next) - if (reg->type == OP_OUT + if (reg->type != OP_IN && reg_early_clobber_p (reg, n_alt) && ! reg->subreg_p) { struct lra_insn_reg *reg2; - + /* We can have early clobbered non-operand hard reg and the same hard reg as an insn input. Don't make hard reg dead before the insns. */ @@ -985,7 +997,9 @@ process_bb_lives (basic_block bb, int &c make_hard_regno_dead (reg->regno); } - if (need_curr_point_incr) + /* Increment the current program point if we must. */ + if (sparseset_contains_pseudos_p (dead_set) + || sparseset_contains_pseudos_p (start_dying)) next_program_point (curr_point, freq); /* Update notes. */ @@ -1017,7 +1031,6 @@ process_bb_lives (basic_block bb, int &c EXECUTE_IF_SET_IN_SPARSESET (unused_set, j) add_reg_note (curr_insn, REG_UNUSED, regno_reg_rtx[j]); } - ignore_reg_for_conflicts = NULL_RTX; if (bb_has_eh_pred (bb)) for (j = 0; ; ++j) @@ -1047,7 +1060,7 @@ process_bb_lives (basic_block bb, int &c allocate such regs in this case. */ if (!cfun->has_nonlocal_label && has_abnormal_call_or_eh_pred_edge_p (bb)) - for (px = 0; px < FIRST_PSEUDO_REGISTER; px++) + for (px = 0; HARD_REGISTER_NUM_P (px); px++) if (call_used_regs[px] #ifdef REAL_PIC_OFFSET_TABLE_REGNUM /* We should create a conflict of PIC pseudo with PIC @@ -1057,7 +1070,7 @@ process_bb_lives (basic_block bb, int &c pseudo will also have a wrong value. */ || (px == REAL_PIC_OFFSET_TABLE_REGNUM && pic_offset_table_rtx != NULL_RTX - && REGNO (pic_offset_table_rtx) >= FIRST_PSEUDO_REGISTER) + && !HARD_REGISTER_P (pic_offset_table_rtx)) #endif ) make_hard_regno_live (px); @@ -1095,7 +1108,10 @@ process_bb_lives (basic_block bb, int &c need_curr_point_incr = (sparseset_cardinality (pseudos_live) > 0); EXECUTE_IF_SET_IN_SPARSESET (pseudos_live, i) - mark_pseudo_dead (i, curr_point); + { + update_pseudo_point (i, curr_point, DEF_POINT); + mark_pseudo_dead (i); + } EXECUTE_IF_SET_IN_BITMAP (df_get_live_in (bb), FIRST_PSEUDO_REGISTER, j, bi) { @@ -1105,7 +1121,7 @@ process_bb_lives (basic_block bb, int &c check_pseudos_live_through_calls (j, last_call_used_reg_set); } - for (i = 0; i < FIRST_PSEUDO_REGISTER; ++i) + for (i = 0; HARD_REGISTER_NUM_P (i); ++i) { if (!TEST_HARD_REG_BIT (hard_regs_live, i)) continue; @@ -1332,12 +1348,12 @@ lra_create_live_ranges_1 (bool all_p, bo conservative because of recent transformation. Here in this file we recalculate it again as it costs practically nothing. */ - if (i >= FIRST_PSEUDO_REGISTER && regno_reg_rtx[i] != NULL_RTX) + if (!HARD_REGISTER_NUM_P (i) && regno_reg_rtx[i] != NULL_RTX) lra_reg_info[i].biggest_mode = GET_MODE (regno_reg_rtx[i]); else lra_reg_info[i].biggest_mode = VOIDmode; lra_reg_info[i].call_p = false; - if (i >= FIRST_PSEUDO_REGISTER + if (!HARD_REGISTER_NUM_P (i) && lra_reg_info[i].nrefs != 0) { if ((hard_regno = reg_renumber[i]) >= 0) @@ -1394,7 +1410,7 @@ lra_create_live_ranges_1 (bool all_p, bo } /* As we did not change CFG since LRA start we can use DF-infrastructure solver to solve live data flow problem. */ - for (int i = 0; i < FIRST_PSEUDO_REGISTER; ++i) + for (int i = 0; HARD_REGISTER_NUM_P (i); ++i) { if (TEST_HARD_REG_BIT (hard_regs_spilled_into, i)) bitmap_clear_bit (&all_hard_regs_bitmap, i);