Mercurial > hg > CbC > CbC_gcc
diff gcc/ira-lives.c @ 145:1830386684a0
gcc-9.2.0
author | anatofuz |
---|---|
date | Thu, 13 Feb 2020 11:34:05 +0900 |
parents | 84e7813d76e9 |
children |
line wrap: on
line diff
--- a/gcc/ira-lives.c Thu Oct 25 07:37:49 2018 +0900 +++ b/gcc/ira-lives.c Thu Feb 13 11:34:05 2020 +0900 @@ -1,5 +1,5 @@ /* IRA processing allocno lives to build allocno live ranges. - Copyright (C) 2006-2018 Free Software Foundation, Inc. + Copyright (C) 2006-2020 Free Software Foundation, Inc. Contributed by Vladimir Makarov <vmakarov@redhat.com>. This file is part of GCC. @@ -33,6 +33,7 @@ #include "ira.h" #include "ira-int.h" #include "sparseset.h" +#include "function-abi.h" /* The code in this file is similar to one in global but the code works on the allocno basis and creates live ranges instead of @@ -80,8 +81,9 @@ /* The number of last call at which given allocno was saved. */ static int *allocno_saved_at_call; -/* The value of get_preferred_alternatives for the current instruction, - supplemental to recog_data. */ +/* The value returned by ira_setup_alts for the current instruction; + i.e. the set of alternatives that we should consider to be likely + candidates during reloading. */ static alternative_mask preferred_alternatives; /* If non-NULL, the source operand of a register to register copy for which @@ -163,7 +165,9 @@ make_object_dead (ira_object_t obj) { live_range_t lr; + int regno; int ignore_regno = -1; + int ignore_total_regno = -1; int end_regno = -1; sparseset_clear_bit (objects_live, OBJECT_CONFLICT_ID (obj)); @@ -174,26 +178,26 @@ && 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); + ignore_regno = ignore_total_regno = REGNO (ignore_reg_for_conflicts); - while (src_regno < end_regno) + for (regno = ignore_regno; regno < end_regno; regno++) { - if (TEST_HARD_REG_BIT (OBJECT_CONFLICT_HARD_REGS (obj), src_regno)) - { - ignore_regno = end_regno = -1; - break; - } - src_regno++; + if (TEST_HARD_REG_BIT (OBJECT_CONFLICT_HARD_REGS (obj), regno)) + ignore_regno = end_regno; + if (TEST_HARD_REG_BIT (OBJECT_TOTAL_CONFLICT_HARD_REGS (obj), regno)) + ignore_total_regno = end_regno; } } - IOR_HARD_REG_SET (OBJECT_CONFLICT_HARD_REGS (obj), hard_regs_live); - IOR_HARD_REG_SET (OBJECT_TOTAL_CONFLICT_HARD_REGS (obj), hard_regs_live); + OBJECT_CONFLICT_HARD_REGS (obj) |= hard_regs_live; + OBJECT_TOTAL_CONFLICT_HARD_REGS (obj) |= hard_regs_live; /* If IGNORE_REG_FOR_CONFLICTS did not already conflict with OBJ, make sure it still doesn't. */ - for (; ignore_regno < end_regno; ignore_regno++) - CLEAR_HARD_REG_BIT (OBJECT_CONFLICT_HARD_REGS (obj), ignore_regno); + for (regno = ignore_regno; regno < end_regno; regno++) + CLEAR_HARD_REG_BIT (OBJECT_CONFLICT_HARD_REGS (obj), regno); + for (regno = ignore_total_regno; regno < end_regno; regno++) + CLEAR_HARD_REG_BIT (OBJECT_TOTAL_CONFLICT_HARD_REGS (obj), regno); lr = OBJECT_LIVE_RANGES (obj); ira_assert (lr != NULL); @@ -629,9 +633,28 @@ /* Check and make if necessary conflicts for definition DEF of class DEF_CL of the current insn with input operands. Process only - constraints of alternative ALT. */ + constraints of alternative ALT. + + One of three things is true when this function is called: + + (1) DEF is an earlyclobber for alternative ALT. Input operands then + conflict with DEF in ALT unless they explicitly match DEF via 0-9 + constraints. + + (2) DEF matches (via 0-9 constraints) an operand that is an + earlyclobber for alternative ALT. Other input operands then + conflict with DEF in ALT. + + (3) [FOR_TIE_P] Some input operand X matches DEF for alternative ALT. + Input operands with a different value from X then conflict with + DEF in ALT. + + However, there's still a judgement call to make when deciding + whether a conflict in ALT is important enough to be reflected + in the pan-alternative allocno conflict set. */ static void -check_and_make_def_conflict (int alt, int def, enum reg_class def_cl) +check_and_make_def_conflict (int alt, int def, enum reg_class def_cl, + bool for_tie_p) { int use, use_match; ira_allocno_t a; @@ -665,14 +688,40 @@ if (use == def || recog_data.operand_type[use] == OP_OUT) continue; + /* An earlyclobber on DEF doesn't apply to an input operand X if X + explicitly matches DEF, but it applies to other input operands + even if they happen to be the same value as X. + + In contrast, if an input operand X is tied to a non-earlyclobber + DEF, there's no conflict with other input operands that have the + same value as X. */ + if (op_alt[use].matches == def + || (for_tie_p + && rtx_equal_p (recog_data.operand[use], + recog_data.operand[op_alt[def].matched]))) + continue; + if (op_alt[use].anything_ok) use_cl = ALL_REGS; else use_cl = op_alt[use].cl; + if (use_cl == NO_REGS) + continue; + + /* If DEF is simply a tied operand, ignore cases in which this + alternative requires USE to have a likely-spilled class. + Adding a conflict would just constrain USE further if DEF + happens to be allocated first. */ + if (for_tie_p && targetm.class_likely_spilled_p (use_cl)) + continue; /* If there's any alternative that allows USE to match DEF, do not record a conflict. If that causes us to create an invalid - instruction due to the earlyclobber, reload must fix it up. */ + instruction due to the earlyclobber, reload must fix it up. + + Likewise, if we're treating a tied DEF like a partial earlyclobber, + do not record a conflict if there's another alternative in which + DEF is neither tied nor earlyclobber. */ for (alt1 = 0; alt1 < recog_data.n_alternatives; alt1++) { if (!TEST_BIT (preferred_alternatives, alt1)) @@ -687,6 +736,12 @@ && recog_data.constraints[use - 1][0] == '%' && op_alt1[use - 1].matches == def)) break; + if (for_tie_p + && !op_alt1[def].earlyclobber + && op_alt1[def].matched < 0 + && alternative_class (op_alt1, def) != NO_REGS + && alternative_class (op_alt1, use) != NO_REGS) + break; } if (alt1 < recog_data.n_alternatives) @@ -697,8 +752,7 @@ if ((use_match = op_alt[use].matches) >= 0) { - if (use_match == def) - continue; + gcc_checking_assert (use_match != def); if (op_alt[use_match].anything_ok) use_cl = ALL_REGS; @@ -713,7 +767,11 @@ /* Make conflicts of early clobber pseudo registers of the current insn with its inputs. Avoid introducing unnecessary conflicts by checking classes of the constraints and pseudos because otherwise - significant code degradation is possible for some targets. */ + significant code degradation is possible for some targets. + + For these purposes, tying an input to an output makes that output act + like an earlyclobber for inputs with a different value, since the output + register then has a predetermined purpose on input to the instruction. */ static void make_early_clobber_and_input_conflicts (void) { @@ -728,15 +786,19 @@ if (TEST_BIT (preferred_alternatives, alt)) for (def = 0; def < n_operands; def++) { - def_cl = NO_REGS; - if (op_alt[def].earlyclobber) + if (op_alt[def].anything_ok) + def_cl = ALL_REGS; + else + def_cl = op_alt[def].cl; + if (def_cl != NO_REGS) { - if (op_alt[def].anything_ok) - def_cl = ALL_REGS; - else - def_cl = op_alt[def].cl; - check_and_make_def_conflict (alt, def, def_cl); + if (op_alt[def].earlyclobber) + check_and_make_def_conflict (alt, def, def_cl, false); + else if (op_alt[def].matched >= 0 + && !targetm.class_likely_spilled_p (def_cl)) + check_and_make_def_conflict (alt, def, def_cl, true); } + if ((def_match = op_alt[def].matches) >= 0 && (op_alt[def_match].earlyclobber || op_alt[def].earlyclobber)) @@ -745,7 +807,7 @@ def_cl = ALL_REGS; else def_cl = op_alt[def_match].cl; - check_and_make_def_conflict (alt, def, def_cl); + check_and_make_def_conflict (alt, def, def_cl, false); } } } @@ -987,10 +1049,8 @@ /* We could increase costs of A instead of making it conflicting with the hard register. But it works worse because it will be spilled in reload in anyway. */ - IOR_HARD_REG_SET (OBJECT_CONFLICT_HARD_REGS (obj), - reg_class_contents[cl]); - IOR_HARD_REG_SET (OBJECT_TOTAL_CONFLICT_HARD_REGS (obj), - reg_class_contents[cl]); + OBJECT_CONFLICT_HARD_REGS (obj) |= reg_class_contents[cl]; + OBJECT_TOTAL_CONFLICT_HARD_REGS (obj) |= reg_class_contents[cl]; } } } @@ -1083,17 +1143,67 @@ int src_regno = REGNO (SET_SRC (set)); machine_mode mode = GET_MODE (SET_DEST (set)); + /* By definition, a register does not conflict with itself, therefore we + do not have to handle it specially. Returning NULL_RTX now, helps + simplify the callers of this function. */ + if (dst_regno == src_regno) + return NULL_RTX; + /* Computing conflicts for register pairs is difficult to get right, so for now, disallow it. */ - if ((dst_regno < FIRST_PSEUDO_REGISTER + if ((HARD_REGISTER_NUM_P (dst_regno) && hard_regno_nregs (dst_regno, mode) != 1) - || (src_regno < FIRST_PSEUDO_REGISTER + || (HARD_REGISTER_NUM_P (src_regno) && hard_regno_nregs (src_regno, mode) != 1)) return NULL_RTX; return SET_SRC (set); } +#ifdef EH_RETURN_DATA_REGNO + +/* Add EH return hard registers as conflict hard registers to allocnos + living at end of BB. For most allocnos it is already done in + process_bb_node_lives when we processing input edges but it does + not work when and EH edge is edge out of the current region. This + function covers such out of region edges. */ +static void +process_out_of_region_eh_regs (basic_block bb) +{ + edge e; + edge_iterator ei; + unsigned int i; + bitmap_iterator bi; + bool eh_p = false; + + FOR_EACH_EDGE (e, ei, bb->succs) + if ((e->flags & EDGE_EH) + && IRA_BB_NODE (e->dest)->parent != IRA_BB_NODE (bb)->parent) + eh_p = true; + + if (! eh_p) + return; + + EXECUTE_IF_SET_IN_BITMAP (df_get_live_out (bb), FIRST_PSEUDO_REGISTER, i, bi) + { + ira_allocno_t a = ira_curr_regno_allocno_map[i]; + for (int n = ALLOCNO_NUM_OBJECTS (a) - 1; n >= 0; n--) + { + ira_object_t obj = ALLOCNO_OBJECT (a, n); + for (int k = 0; ; k++) + { + unsigned int regno = EH_RETURN_DATA_REGNO (k); + if (regno == INVALID_REGNUM) + break; + SET_HARD_REG_BIT (OBJECT_CONFLICT_HARD_REGS (obj), regno); + SET_HARD_REG_BIT (OBJECT_TOTAL_CONFLICT_HARD_REGS (obj), regno); + } + } + } +} + +#endif + /* Process insns of the basic block given by its LOOP_TREE_NODE to update allocno live ranges, allocno hard register conflicts, intersected calls, and register pressure info for allocnos for the @@ -1122,8 +1232,7 @@ reg_live_out = df_get_live_out (bb); sparseset_clear (objects_live); REG_SET_TO_HARD_REG_SET (hard_regs_live, reg_live_out); - AND_COMPL_HARD_REG_SET (hard_regs_live, eliminable_regset); - AND_COMPL_HARD_REG_SET (hard_regs_live, ira_no_alloc_regs); + hard_regs_live &= ~(eliminable_regset | ira_no_alloc_regs); for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) if (TEST_HARD_REG_BIT (hard_regs_live, i)) { @@ -1148,6 +1257,10 @@ EXECUTE_IF_SET_IN_BITMAP (reg_live_out, FIRST_PSEUDO_REGISTER, j, bi) mark_pseudo_regno_live (j); +#ifdef EH_RETURN_DATA_REGNO + process_out_of_region_eh_regs (bb); +#endif + freq = REG_FREQ_FROM_BB (bb); if (freq == 0) freq = 1; @@ -1228,16 +1341,9 @@ } } - extract_insn (insn); - preferred_alternatives = get_preferred_alternatives (insn); - preprocess_constraints (insn); + preferred_alternatives = ira_setup_alts (insn); process_single_reg_class_operands (false, freq); - /* See which defined values die here. */ - FOR_EACH_INSN_DEF (def, insn) - if (!call_p || !DF_REF_FLAGS_IS_SET (def, DF_REF_MAY_CLOBBER)) - mark_ref_dead (def); - if (call_p) { /* Try to find a SET in the CALL_INSN_FUNCTION_USAGE, and from @@ -1255,10 +1361,7 @@ ira_object_t obj = ira_object_id_map[i]; a = OBJECT_ALLOCNO (obj); int num = ALLOCNO_NUM (a); - HARD_REG_SET this_call_used_reg_set; - - get_call_reg_set_usage (insn, &this_call_used_reg_set, - call_used_reg_set); + function_abi callee_abi = insn_callee_abi (insn); /* Don't allocate allocnos that cross setjmps or any call, if this function receives a nonlocal @@ -1273,10 +1376,10 @@ } if (can_throw_internal (insn)) { - IOR_HARD_REG_SET (OBJECT_CONFLICT_HARD_REGS (obj), - this_call_used_reg_set); - IOR_HARD_REG_SET (OBJECT_TOTAL_CONFLICT_HARD_REGS (obj), - this_call_used_reg_set); + OBJECT_CONFLICT_HARD_REGS (obj) + |= callee_abi.mode_clobbers (ALLOCNO_MODE (a)); + OBJECT_TOTAL_CONFLICT_HARD_REGS (obj) + |= callee_abi.mode_clobbers (ALLOCNO_MODE (a)); } if (sparseset_bit_p (allocnos_processed, num)) @@ -1293,14 +1396,26 @@ /* Mark it as saved at the next call. */ allocno_saved_at_call[num] = last_call_num + 1; ALLOCNO_CALLS_CROSSED_NUM (a)++; - IOR_HARD_REG_SET (ALLOCNO_CROSSED_CALLS_CLOBBERED_REGS (a), - this_call_used_reg_set); + ALLOCNO_CROSSED_CALLS_ABIS (a) |= 1 << callee_abi.id (); + ALLOCNO_CROSSED_CALLS_CLOBBERED_REGS (a) + |= callee_abi.full_and_partial_reg_clobbers (); if (cheap_reg != NULL_RTX && ALLOCNO_REGNO (a) == (int) REGNO (cheap_reg)) ALLOCNO_CHEAP_CALLS_CROSSED_NUM (a)++; } } + /* See which defined values die here. Note that we include + the call insn in the lifetimes of these values, so we don't + mistakenly consider, for e.g. an addressing mode with a + side-effect like a post-increment fetching the address, + that the use happens before the call, and the def to happen + after the call: we believe both to happen before the actual + call. (We don't handle return-values here.) */ + FOR_EACH_INSN_DEF (def, insn) + if (!call_p || !DF_REF_FLAGS_IS_SET (def, DF_REF_MAY_CLOBBER)) + mark_ref_dead (def); + make_early_clobber_and_input_conflicts (); curr_point++; @@ -1347,10 +1462,11 @@ } /* Allocnos can't go in stack regs at the start of a basic block - that is reached by an abnormal edge. Likewise for call - clobbered regs, because caller-save, fixup_abnormal_edges and - possibly the table driven EH machinery are not quite ready to - handle such allocnos live across such edges. */ + that is reached by an abnormal edge. Likewise for registers + that are at least partly call clobbered, because caller-save, + fixup_abnormal_edges and possibly the table driven EH machinery + are not quite ready to handle such allocnos live across such + edges. */ if (bb_has_abnormal_pred (bb)) { #ifdef STACK_REGS @@ -1370,12 +1486,12 @@ if (!cfun->has_nonlocal_label && has_abnormal_call_or_eh_pred_edge_p (bb)) for (px = 0; px < FIRST_PSEUDO_REGISTER; px++) - if (call_used_regs[px] + if (eh_edge_abi.clobbers_at_least_part_of_reg_p (px) #ifdef REAL_PIC_OFFSET_TABLE_REGNUM /* We should create a conflict of PIC pseudo with PIC hard reg as PIC hard reg can have a wrong value after jump described by the abnormal edge. - In this case we can not allocate PIC hard reg to + In this case we cannot allocate PIC hard reg to PIC pseudo as PIC pseudo will also have a wrong value. This code is not critical as LRA can fix it but it is better to have the right allocation