From 05bba13ff70d60ac583e462ef3a516d00bbae33c Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Wed, 24 Oct 2007 17:54:40 +0000 Subject: [PATCH] re PR target/33755 (Gcc 4.2.2 broken for mips linux kernel builds) gcc/ PR target/33755 * config/mips/mips.c (override_options): Always move flag_delayed_branch to mips_flag_delayed_branch. (mips_lo_sum_offset): New structure. (mips_hash_base, mips_lo_sum_offset_hash, mips_lo_sum_offset_eq) (mips_lo_sum_offset_lookup, mips_record_lo_sum) (mips_orphaned_high_part_p: New functions. (mips_avoid_hazard): Don't check INSN_P here. (mips_avoid_hazards): Rename to... (mips_reorg_process_insns): ...this. Cope with !TARGET_EXPLICIT_RELOCS. Delete orphaned high-part relocations, or turn them into nops. (mips_reorg): Remove TARGET_EXPLICIT_RELOCS check from calls to dbr_schedule and mips_avoid_hazards/mips_reorg_process_insns. gcc/testsuite/ PR target/33755 * gcc.target/mips/pr33755.c: New test. From-SVN: r129607 --- gcc/ChangeLog | 17 ++ gcc/config/mips/mips.c | 224 ++++++++++++++++++++---- gcc/testsuite/ChangeLog | 5 + gcc/testsuite/gcc.target/mips/pr33755.c | 30 ++++ 4 files changed, 238 insertions(+), 38 deletions(-) create mode 100644 gcc/testsuite/gcc.target/mips/pr33755.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 4ba559540e5e..1f54d60baaa4 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,20 @@ +2007-10-24 Richard Sandiford + + PR target/33755 + * config/mips/mips.c (override_options): Always move + flag_delayed_branch to mips_flag_delayed_branch. + (mips_lo_sum_offset): New structure. + (mips_hash_base, mips_lo_sum_offset_hash, mips_lo_sum_offset_eq) + (mips_lo_sum_offset_lookup, mips_record_lo_sum) + (mips_orphaned_high_part_p: New functions. + (mips_avoid_hazard): Don't check INSN_P here. + (mips_avoid_hazards): Rename to... + (mips_reorg_process_insns): ...this. Cope with + !TARGET_EXPLICIT_RELOCS. Delete orphaned high-part relocations, + or turn them into nops. + (mips_reorg): Remove TARGET_EXPLICIT_RELOCS check from calls to + dbr_schedule and mips_avoid_hazards/mips_reorg_process_insns. + 2007-10-23 Eric Botcazou * doc/rtl.texi (Flags): Fix MEM_SCALAR_P entry. diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c index 40d14799ab0a..da2fb255b8aa 100644 --- a/gcc/config/mips/mips.c +++ b/gcc/config/mips/mips.c @@ -361,7 +361,6 @@ static void mips_sim_finish_insn (struct mips_sim *, rtx); static void vr4130_avoid_branch_rt_conflict (rtx); static void vr4130_align_insns (void); static void mips_avoid_hazard (rtx, rtx, int *, rtx *, rtx); -static void mips_avoid_hazards (void); static void mips_reorg (void); static bool mips_strict_matching_cpu_name_p (const char *, const char *); static bool mips_matching_cpu_name_p (const char *, const char *); @@ -4949,13 +4948,9 @@ override_options (void) target_flags &= ~MASK_EXPLICIT_RELOCS; } - /* When using explicit relocs, we call dbr_schedule from within - mips_reorg. */ - if (TARGET_EXPLICIT_RELOCS) - { - mips_flag_delayed_branch = flag_delayed_branch; - flag_delayed_branch = 0; - } + /* We call dbr_schedule from within mips_reorg. */ + mips_flag_delayed_branch = flag_delayed_branch; + flag_delayed_branch = 0; #ifdef MIPS_TFMODE_FORMAT REAL_MODE_FORMAT (TFmode) = &MIPS_TFMODE_FORMAT; @@ -8973,8 +8968,122 @@ vr4130_align_insns (void) dfa_finish (); } -/* Subroutine of mips_reorg. If there is a hazard between INSN - and a previous instruction, avoid it by inserting nops after +/* This structure records that the current function has a LO_SUM + involving SYMBOL_REF or LABEL_REF BASE and that MAX_OFFSET is + the largest offset applied to BASE by all such LO_SUMs. */ +struct mips_lo_sum_offset { + rtx base; + HOST_WIDE_INT offset; +}; + +/* Return a hash value for SYMBOL_REF or LABEL_REF BASE. */ + +static hashval_t +mips_hash_base (rtx base) +{ + int do_not_record_p; + + return hash_rtx (base, GET_MODE (base), &do_not_record_p, NULL, false); +} + +/* Hash-table callbacks for mips_lo_sum_offsets. */ + +static hashval_t +mips_lo_sum_offset_hash (const void *entry) +{ + return mips_hash_base (((const struct mips_lo_sum_offset *) entry)->base); +} + +static int +mips_lo_sum_offset_eq (const void *entry, const void *value) +{ + return rtx_equal_p (((const struct mips_lo_sum_offset *) entry)->base, + (rtx) value); +} + +/* Look up symbolic constant X in HTAB, which is a hash table of + mips_lo_sum_offsets. If OPTION is NO_INSERT, return true if X can be + paired with a recorded LO_SUM, otherwise record X in the table. */ + +static bool +mips_lo_sum_offset_lookup (htab_t htab, rtx x, enum insert_option option) +{ + rtx base; + HOST_WIDE_INT offset; + void **slot; + struct mips_lo_sum_offset *entry; + + /* Split X into a base and offset. */ + mips_split_const (x, &base, &offset); + if (UNSPEC_ADDRESS_P (base)) + base = UNSPEC_ADDRESS (base); + + /* Look up the base in the hash table. */ + slot = htab_find_slot_with_hash (htab, base, mips_hash_base (base), option); + if (slot == NULL) + return false; + + entry = (struct mips_lo_sum_offset *) *slot; + if (option == INSERT) + { + if (entry == NULL) + { + entry = XNEW (struct mips_lo_sum_offset); + entry->base = base; + entry->offset = offset; + *slot = entry; + } + else + { + if (offset > entry->offset) + entry->offset = offset; + } + } + return offset <= entry->offset; +} + +/* A for_each_rtx callback for which DATA is a mips_lo_sum_offset hash table. + Record every LO_SUM in *LOC. */ + +static int +mips_record_lo_sum (rtx *loc, void *data) +{ + if (GET_CODE (*loc) == LO_SUM) + mips_lo_sum_offset_lookup ((htab_t) data, XEXP (*loc, 1), INSERT); + return 0; +} + +/* Return true if INSN is a SET of an orphaned high-part relocation. + HTAB is a hash table of mips_lo_sum_offsets that describes all the + LO_SUMs in the current function. */ + +static bool +mips_orphaned_high_part_p (htab_t htab, rtx insn) +{ + enum mips_symbol_type type; + rtx x, set; + + set = single_set (insn); + if (set) + { + /* Check for %his. */ + x = SET_SRC (set); + if (GET_CODE (x) == HIGH + && general_symbolic_operand (XEXP (x, 0), VOIDmode)) + return !mips_lo_sum_offset_lookup (htab, XEXP (x, 0), NO_INSERT); + + /* Check for local %gots (and %got_pages, which is redundant but OK). */ + if (GET_CODE (x) == UNSPEC + && XINT (x, 1) == UNSPEC_LOAD_GOT + && mips_symbolic_constant_p (XVECEXP (x, 0, 1), &type) + && type == SYMBOL_GOTOFF_PAGE) + return !mips_lo_sum_offset_lookup (htab, XVECEXP (x, 0, 1), NO_INSERT); + } + return false; +} + +/* Subroutine of mips_reorg_process_insns. If there is a hazard between + INSN and a previous instruction, avoid it by inserting nops after instruction AFTER. *DELAYED_REG and *HILO_DELAY describe the hazards that apply at @@ -8995,9 +9104,6 @@ mips_avoid_hazard (rtx after, rtx insn, int *hilo_delay, rtx pattern, set; int nops, ninsns, hazard_set; - if (!INSN_P (insn)) - return; - pattern = PATTERN (insn); /* Do not put the whole function in .set noreorder if it contains @@ -9058,14 +9164,16 @@ mips_avoid_hazard (rtx after, rtx insn, int *hilo_delay, /* Go through the instruction stream and insert nops where necessary. - See if the whole function can then be put into .set noreorder & - .set nomacro. */ + Also delete any high-part relocations whose partnering low parts + are now all dead. See if the whole function can then be put into + .set noreorder and .set nomacro. */ static void -mips_avoid_hazards (void) +mips_reorg_process_insns (void) { - rtx insn, last_insn, lo_reg, delayed_reg; - int hilo_delay, i; + rtx insn, last_insn, subinsn, next_insn, lo_reg, delayed_reg; + int hilo_delay; + htab_t htab; /* Force all instructions to be split into their final form. */ split_all_insns_noflow (); @@ -9076,6 +9184,10 @@ mips_avoid_hazards (void) cfun->machine->all_noreorder_p = true; + /* Code that doesn't use explicit relocs can't be ".set nomacro". */ + if (!TARGET_EXPLICIT_RELOCS) + cfun->machine->all_noreorder_p = false; + /* Profiled functions can't be all noreorder because the profiler support uses assembler macros. */ if (current_function_profile) @@ -9093,24 +9205,63 @@ mips_avoid_hazards (void) if (TARGET_FIX_VR4130 && !ISA_HAS_MACCHI) cfun->machine->all_noreorder_p = false; + htab = htab_create (37, mips_lo_sum_offset_hash, + mips_lo_sum_offset_eq, free); + + /* Make a first pass over the instructions, recording all the LO_SUMs. */ + for (insn = get_insns (); insn != 0; insn = NEXT_INSN (insn)) + FOR_EACH_SUBINSN (subinsn, insn) + if (INSN_P (subinsn)) + for_each_rtx (&PATTERN (subinsn), mips_record_lo_sum, htab); + last_insn = 0; hilo_delay = 2; delayed_reg = 0; lo_reg = gen_rtx_REG (SImode, LO_REGNUM); - for (insn = get_insns (); insn != 0; insn = NEXT_INSN (insn)) - if (INSN_P (insn)) - { - if (GET_CODE (PATTERN (insn)) == SEQUENCE) - for (i = 0; i < XVECLEN (PATTERN (insn), 0); i++) - mips_avoid_hazard (last_insn, XVECEXP (PATTERN (insn), 0, i), - &hilo_delay, &delayed_reg, lo_reg); - else - mips_avoid_hazard (last_insn, insn, &hilo_delay, - &delayed_reg, lo_reg); + /* Make a second pass over the instructions. Delete orphaned + high-part relocations or turn them into NOPs. Avoid hazards + by inserting NOPs. */ + for (insn = get_insns (); insn != 0; insn = next_insn) + { + next_insn = NEXT_INSN (insn); + if (INSN_P (insn)) + { + if (GET_CODE (PATTERN (insn)) == SEQUENCE) + { + /* If we find an orphaned high-part relocation in a delay + slot, it's easier to turn that instruction into a nop than + to delete it. The delay slot will be a nop either way. */ + FOR_EACH_SUBINSN (subinsn, insn) + if (INSN_P (subinsn)) + { + if (mips_orphaned_high_part_p (htab, subinsn)) + { + PATTERN (subinsn) = gen_nop (); + INSN_CODE (subinsn) = CODE_FOR_nop; + } + mips_avoid_hazard (last_insn, subinsn, &hilo_delay, + &delayed_reg, lo_reg); + } + last_insn = insn; + } + else + { + /* INSN is a single instruction. Delete it if it's an + orphaned high-part relocation. */ + if (mips_orphaned_high_part_p (htab, insn)) + delete_insn (insn); + else + { + mips_avoid_hazard (last_insn, insn, &hilo_delay, + &delayed_reg, lo_reg); + last_insn = insn; + } + } + } + } - last_insn = insn; - } + htab_delete (htab); } @@ -9121,14 +9272,11 @@ mips_reorg (void) { if (TARGET_MIPS16) mips16_lay_out_constants (); - else if (TARGET_EXPLICIT_RELOCS) - { - if (mips_flag_delayed_branch) - dbr_schedule (get_insns ()); - mips_avoid_hazards (); - if (TUNE_MIPS4130 && TARGET_VR4130_ALIGN) - vr4130_align_insns (); - } + if (mips_flag_delayed_branch) + dbr_schedule (get_insns ()); + mips_reorg_process_insns (); + if (TARGET_EXPLICIT_RELOCS && TUNE_MIPS4130 && TARGET_VR4130_ALIGN) + vr4130_align_insns (); } /* This function does three things: diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 45f21cacf0ab..f16acd53ee60 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2007-10-24 Richard Sandiford + + PR target/33755 + * gcc.target/mips/pr33755.c: New test. + 2007-10-22 David S. Miller * gcc.dg/globalreg-1.c: New test. diff --git a/gcc/testsuite/gcc.target/mips/pr33755.c b/gcc/testsuite/gcc.target/mips/pr33755.c new file mode 100644 index 000000000000..a550480ddd7e --- /dev/null +++ b/gcc/testsuite/gcc.target/mips/pr33755.c @@ -0,0 +1,30 @@ +/* { dg-do link } */ +/* { dg-mips-options "-O2" } */ + +volatile int gv; +const char *ptrs[2]; + +void +foo (volatile int *v, const char **ptrs) +{ + switch (*v & 1) + { + case 0: + ptrs[0] = 0; + break; + case 1: + break; + default: + ptrs[1] = "Some text"; + break; + } + while (*v > 0) + *v -= 1; +} + +int +main (void) +{ + foo (&gv, ptrs); + return 0; +} -- 2.47.2