From fdbda73fc7222a5e0c58c3f77e15b95513d58df1 Mon Sep 17 00:00:00 2001 From: Vladimir Makarov Date: Mon, 12 Jul 2004 18:01:44 +0000 Subject: [PATCH] re PR rtl-optimization/15921 (gcc.c-torture/compile/920501-4.c fails on powerpc-*) 2004-07-12 Vladimir Makarov PR rtl-optimization/15921 * Makefile.in (global.o): Add recog.h. * global.c (recog.h): Add the include-clause. (bb_info): New member earlyclobber. (allocate_bb_info, free_bb_info): Initialize/finish the new member. (earlyclobber_regclass, earlyclobber_regclass_length): The new global variables. (check_earlyclobber, regclass_intersect, mark_reg_use_for_earlyclobber, mark_reg_use_for_earlyclobber_1): New functions. (calculate_local_reg_bb_info): Calculate value of earlyclobber. (make_accurate_live_analysis): Modify pavin. From-SVN: r84569 --- gcc/ChangeLog | 17 ++++++ gcc/Makefile.in | 6 +-- gcc/global.c | 162 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 181 insertions(+), 4 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 9580f3d..577cb62 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,20 @@ +2004-07-12 Vladimir Makarov + + PR rtl-optimization/15921 + * Makefile.in (global.o): Add recog.h. + + * global.c (recog.h): Add the include-clause. + (bb_info): New member earlyclobber. + (allocate_bb_info, free_bb_info): Initialize/finish the new + member. + (earlyclobber_regclass, earlyclobber_regclass_length): The new + global variables. + (check_earlyclobber, regclass_intersect, + mark_reg_use_for_earlyclobber, mark_reg_use_for_earlyclobber_1): + New functions. + (calculate_local_reg_bb_info): Calculate value of earlyclobber. + (make_accurate_live_analysis): Modify pavin. + 2004-07-12 Diego Novillo * tree-cfg.c (find_taken_edge): Statically compute the truth diff --git a/gcc/Makefile.in b/gcc/Makefile.in index f1446ed..6d55e06 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -2006,9 +2006,9 @@ local-alloc.o : local-alloc.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_ bitmap.o : bitmap.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(GTM_H) $(RTL_H) $(FLAGS_H) \ $(BASIC_BLOCK_H) $(REGS_H) $(GGC_H) $(CC) -c $(ALL_CFLAGS) -DGENERATOR_FILE $(ALL_CPPFLAGS) $(INCLUDES) $< $(OUTPUT_OPTION) -global.o : global.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(FLAGS_H) \ - reload.h function.h $(BASIC_BLOCK_H) $(REGS_H) hard-reg-set.h insn-config.h output.h \ - toplev.h $(TM_P_H) +global.o : global.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) flags.h \ + reload.h function.h $(RECOG_H) $(BASIC_BLOCK_H) $(REGS_H) hard-reg-set.h\ + insn-config.h output.h toplev.h $(TM_P_H) varray.o : varray.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) varray.h $(GGC_H) errors.h \ $(HASHTAB_H) vec.o : vec.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) coretypes.h vec.h $(GGC_H) errors.h diff --git a/gcc/global.c b/gcc/global.c index 24149d3..ab50844 100644 --- a/gcc/global.c +++ b/gcc/global.c @@ -34,6 +34,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "regs.h" #include "function.h" #include "insn-config.h" +#include "recog.h" #include "reload.h" #include "output.h" #include "toplev.h" @@ -309,6 +310,10 @@ static void reg_dies (int, enum machine_mode, struct insn_chain *); static void allocate_bb_info (void); static void free_bb_info (void); +static void check_earlyclobber (rtx); +static bool regclass_intersect (enum reg_class, enum reg_class); +static void mark_reg_use_for_earlyclobber_1 (rtx *, void *); +static int mark_reg_use_for_earlyclobber (rtx *, void *); static void calculate_local_reg_bb_info (void); static void set_up_bb_rts_numbers (void); static int rpost_cmp (const void *, const void *); @@ -2000,6 +2005,9 @@ struct bb_info { /* The basic block reverse post-order number. */ int rts_number; + /* Registers used uninitialized in an insn in which there is an + early clobbered register might get the same hard register. */ + bitmap earlyclobber; /* Registers correspondingly killed (clobbered) and defined but not killed afterward in the basic block. */ bitmap killed, avloc; @@ -2032,6 +2040,7 @@ allocate_bb_info (void) FOR_EACH_BB (bb) { bb_info = bb->aux; + bb_info->earlyclobber = BITMAP_XMALLOC (); bb_info->avloc = BITMAP_XMALLOC (); bb_info->killed = BITMAP_XMALLOC (); bb_info->pavin = BITMAP_XMALLOC (); @@ -2057,6 +2066,7 @@ free_bb_info (void) BITMAP_XFREE (bb_info->pavin); BITMAP_XFREE (bb_info->killed); BITMAP_XFREE (bb_info->avloc); + BITMAP_XFREE (bb_info->earlyclobber); } free_aux_for_blocks (); } @@ -2086,6 +2096,144 @@ mark_reg_change (rtx reg, rtx setter, void *data) bitmap_clear_bit (bb_info->avloc, regno); } +/* Classes of registers which could be early clobbered in the current + insn. */ + +static varray_type earlyclobber_regclass; + +/* The function stores classes of registers which could be early + clobbered in INSN. */ + +static void +check_earlyclobber (rtx insn) +{ + int opno; + + extract_insn (insn); + + VARRAY_POP_ALL (earlyclobber_regclass); + for (opno = 0; opno < recog_data.n_operands; opno++) + { + char c; + bool amp_p; + int i; + enum reg_class class; + const char *p = recog_data.constraints[opno]; + + class = NO_REGS; + amp_p = false; + for (;;) + { + c = *p; + switch (c) + { + case '=': case '+': case '?': + case '#': case '!': + case '*': case '%': + case 'm': case '<': case '>': case 'V': case 'o': + case 'E': case 'F': case 'G': case 'H': + case 's': case 'i': case 'n': + case 'I': case 'J': case 'K': case 'L': + case 'M': case 'N': case 'O': case 'P': + case 'X': + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + /* These don't say anything we care about. */ + break; + + case '&': + amp_p = true; + break; + case '\0': + case ',': + if (amp_p && class != NO_REGS) + { + for (i = VARRAY_ACTIVE_SIZE (earlyclobber_regclass) - 1; + i >= 0; i--) + if (VARRAY_INT (earlyclobber_regclass, i) == (int) class) + break; + if (i < 0) + VARRAY_PUSH_INT (earlyclobber_regclass, (int) class); + } + + amp_p = false; + class = NO_REGS; + break; + + case 'r': + class = GENERAL_REGS; + break; + + default: + class = REG_CLASS_FROM_CONSTRAINT (c, p); + break; + } + if (c == '\0') + break; + p += CONSTRAINT_LEN (c, p); + } + } +} + +/* The function returns true if register classes C1 and C2 inetrsect. */ + +static bool +regclass_intersect (enum reg_class c1, enum reg_class c2) +{ + HARD_REG_SET rs, zero; + + CLEAR_HARD_REG_SET (zero); + COPY_HARD_REG_SET(rs, reg_class_contents [c1]); + AND_HARD_REG_SET (rs, reg_class_contents [c2]); + GO_IF_HARD_REG_EQUAL (zero, rs, yes); + return true; + yes: + return false; +} + +/* The function checks that pseudo-register *X has a class + intersecting with the class of pseudo-register could be early + clobbered in the same insn. */ + +static int +mark_reg_use_for_earlyclobber (rtx *x, void *data ATTRIBUTE_UNUSED) +{ + enum reg_class pref_class, alt_class; + int i, regno; + basic_block bb = data; + struct bb_info *bb_info = BB_INFO (bb); + + if (GET_CODE (*x) == REG && REGNO (*x) >= FIRST_PSEUDO_REGISTER) + { + regno = REGNO (*x); + if (bitmap_bit_p (bb_info->killed, regno) + || bitmap_bit_p (bb_info->avloc, regno)) + return 0; + pref_class = reg_preferred_class (regno); + alt_class = reg_alternate_class (regno); + for (i = VARRAY_ACTIVE_SIZE (earlyclobber_regclass) - 1; i >= 0; i--) + if (regclass_intersect (VARRAY_INT (earlyclobber_regclass, i), + pref_class) + || (VARRAY_INT (earlyclobber_regclass, i) != NO_REGS + && regclass_intersect (VARRAY_INT (earlyclobber_regclass, i), + alt_class))) + { + bitmap_set_bit (bb_info->earlyclobber, regno); + break; + } + } + return 0; +} + +/* The function processes all pseudo-registers in *X with the aid of + previous function. */ + +static void +mark_reg_use_for_earlyclobber_1 (rtx *x, void *data) +{ + for_each_rtx (x, mark_reg_use_for_earlyclobber, data); +} + /* The function calculates local info for each basic block. */ static void @@ -2094,12 +2242,18 @@ calculate_local_reg_bb_info (void) basic_block bb; rtx insn, bound; + VARRAY_INT_INIT (earlyclobber_regclass, 20, + "classes of registers early clobbered in an insn"); FOR_EACH_BB (bb) { bound = NEXT_INSN (BB_END (bb)); for (insn = BB_HEAD (bb); insn != bound; insn = NEXT_INSN (insn)) if (INSN_P (insn)) - note_stores (PATTERN (insn), mark_reg_change, bb); + { + note_stores (PATTERN (insn), mark_reg_change, bb); + check_earlyclobber (insn); + note_uses (&PATTERN (insn), mark_reg_use_for_earlyclobber_1, bb); + } } } @@ -2229,6 +2383,12 @@ make_accurate_live_analysis (void) { bb_info = BB_INFO (bb); + /* Reload can assign the same hard register to uninitialized + pseudo-register and early clobbered pseudo-register in an + insn if the pseudo-register is used first time in given BB + and not lived at the BB start. To prevent this we don't + change life information for such pseudo-registers. */ + bitmap_a_or_b (bb_info->pavin, bb_info->pavin, bb_info->earlyclobber); bitmap_a_and_b (bb->global_live_at_start, bb->global_live_at_start, bb_info->pavin); bitmap_a_and_b (bb->global_live_at_end, bb->global_live_at_end, -- 2.7.4