On Fri, Nov 4, 2011 at 9:38 PM, Jakub Jelinek <ja...@redhat.com> wrote:
> Hi!
>
> As has been suggested by Alexandre in the PR, this patch allows merging
> basic blocks which couldn't be merged before because of user (non-forced)
> labels at the beginning of the second basic blocks.
> With this patch the user label is thrown away (for -g0 or -g 
> -fno-var-tracking-assignments)
> or turned into a debug bind stmt which contains the label.
> BB duplication is then taught not to duplicate these (both at GIMPLE
> and RTL level) so that we don't end up with multiple labels, and
> finally during var-tracking when DEBUG_INSNs are deleted this is
> turned into a special note.  Initially I used NOTE_INSN_DELETED_LABEL,
> but that has a few problems - as NOTE_INSN_DELETED_LABEL notes use the same
> file-wide numbers with CODE_LABELs, if we end up creating extra such labels
> only in -g build and not in -g0 build, that results in -fcompare-debug
> differences, even if we ignore all NOTE_INSN_DELETED_LABELs in the dump
> suddenly the CODE_LABEL_NUMBERs will differ in the next function.
> Furthermore, darwin is doing some terrible hacks to insert nops because
> it can't have labels at the end of function or what, which would result
> into code differences between -g and -g0.
> So this patch introduces a new note kind, NOTE_INSN_DELETED_DEBUG_LABEL
> which uses a different label namespace / numbering and which the darwin
> hacks can disable if needed.
>
> With this patch we can now vectorize the very obfuscated testcase from the
> PR.
>
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

Looks good to me.

Thanks,
Richard.

> 2011-11-04  Jakub Jelinek  <ja...@redhat.com>
>
>        PR tree-optimization/50693
>        * tree-cfg.c (gimple_can_merge_blocks_p): Allow merging with
>        non-forced user labels.
>        (gimple_merge_blocks): Turn non-forced user labels into
>        debug bind stmt with the label as first operand and reset value.
>        (gimple_duplicate_bb): Don't duplicate label debug stmts.
>        * dwarf2out.c (gen_label_die): Handle NOTE_INSN_DELETED_DEBUG_LABEL.
>        * final.c (final_scan_insn): Likewise.
>        (rest_of_clean_state): Don't dump NOTE_INSN_DELETED_DEBUG_LABEL.
>        * var-tracking.c (debug_label_num): New variable.
>        (delete_debug_insns): Don't delete DEBUG_INSNs for LABEL_DECLs,
>        instead turn them into NOTE_INSN_DELETED_DEBUG_LABEL notes.
>        * cfglayout.c (skip_insns_after_block, duplicate_insn_chain): Handle
>        NOTE_INSN_DELETED_DEBUG_LABEL.
>        (duplicate_insn_chain): Don't duplicate LABEL_DECL DEBUG_INSNs.
>        * insn-notes.def (DELETED_DEBUG_LABEL): New note kind.
>        * print-rtl.c (print_rtx): Handle NOTE_INSN_DELETED_DEBUG_LABEL.
>        * gengtype.c (adjust_field_rtx_def): Likewise.
>        * config/i386/i386.c (ix86_output_function_epilogue): For MachO
>        clear CODE_LABEL_NUMBER of NOTE_INSN_DELETED_DEBUG_LABEL
>        if their are at the end of function and nop hasn't been emitted.
>        * config/rs6000/rs6000.c (rs6000_output_function_epilogue): Likewise.
>
> --- gcc/tree-cfg.c.jj   2011-10-31 20:44:14.000000000 +0100
> +++ gcc/tree-cfg.c      2011-11-04 18:01:25.000000000 +0100
> @@ -1454,8 +1454,8 @@ gimple_can_merge_blocks_p (basic_block a
>        break;
>       lab = gimple_label_label (stmt);
>
> -      /* Do not remove user labels.  */
> -      if (!DECL_ARTIFICIAL (lab))
> +      /* Do not remove user forced labels.  */
> +      if (!DECL_ARTIFICIAL (lab) && FORCED_LABEL (lab))
>        return false;
>     }
>
> @@ -1701,6 +1701,15 @@ gimple_merge_blocks (basic_block a, basi
>              gimple_stmt_iterator dest_gsi = gsi_start_bb (a);
>              gsi_insert_before (&dest_gsi, stmt, GSI_NEW_STMT);
>            }
> +         /* Other user labels keep around in a form of a debug stmt.  */
> +         else if (!DECL_ARTIFICIAL (label) && MAY_HAVE_DEBUG_STMTS)
> +           {
> +             gimple dbg = gimple_build_debug_bind (label,
> +                                                   integer_zero_node,
> +                                                   stmt);
> +             gimple_debug_bind_reset_value (dbg);
> +             gsi_insert_before (&gsi, dbg, GSI_SAME_STMT);
> +           }
>
>          lp_nr = EH_LANDING_PAD_NR (label);
>          if (lp_nr)
> @@ -5207,6 +5216,12 @@ gimple_duplicate_bb (basic_block bb)
>       if (gimple_code (stmt) == GIMPLE_LABEL)
>        continue;
>
> +      /* Don't duplicate label debug stmts.  */
> +      if (gimple_debug_bind_p (stmt)
> +         && TREE_CODE (gimple_debug_bind_get_var (stmt))
> +            == LABEL_DECL)
> +       continue;
> +
>       /* Create a new copy of STMT and duplicate STMT's virtual
>         operands.  */
>       copy = gimple_copy (stmt);
> --- gcc/dwarf2out.c.jj  2011-11-01 09:04:37.000000000 +0100
> +++ gcc/dwarf2out.c     2011-11-04 17:41:25.000000000 +0100
> @@ -18020,6 +18020,14 @@ gen_label_die (tree decl, dw_die_ref con
>          ASM_GENERATE_INTERNAL_LABEL (label, "L", CODE_LABEL_NUMBER (insn));
>          add_AT_lbl_id (lbl_die, DW_AT_low_pc, label);
>        }
> +      else if (insn
> +              && NOTE_P (insn)
> +              && NOTE_KIND (insn) == NOTE_INSN_DELETED_DEBUG_LABEL
> +              && CODE_LABEL_NUMBER (insn) != -1)
> +       {
> +         ASM_GENERATE_INTERNAL_LABEL (label, "LDL", CODE_LABEL_NUMBER 
> (insn));
> +         add_AT_lbl_id (lbl_die, DW_AT_low_pc, label);
> +       }
>     }
>  }
>
> --- gcc/final.c.jj      2011-09-21 13:04:06.000000000 +0200
> +++ gcc/final.c 2011-11-04 17:38:17.000000000 +0100
> @@ -2080,6 +2080,12 @@ final_scan_insn (rtx insn, FILE *file, i
>          ASM_OUTPUT_DEBUG_LABEL (file, "L", CODE_LABEL_NUMBER (insn));
>          break;
>
> +       case NOTE_INSN_DELETED_DEBUG_LABEL:
> +         /* Similarly, but need to use different namespace for it.  */
> +         if (CODE_LABEL_NUMBER (insn) != -1)
> +           ASM_OUTPUT_DEBUG_LABEL (file, "LDL", CODE_LABEL_NUMBER (insn));
> +         break;
> +
>        case NOTE_INSN_VAR_LOCATION:
>        case NOTE_INSN_CALL_ARG_LOCATION:
>          if (!DECL_IGNORED_P (current_function_decl))
> @@ -4369,7 +4375,8 @@ rest_of_clean_state (void)
>              (NOTE_KIND (insn) != NOTE_INSN_VAR_LOCATION
>               && NOTE_KIND (insn) != NOTE_INSN_CALL_ARG_LOCATION
>               && NOTE_KIND (insn) != NOTE_INSN_BLOCK_BEG
> -              && NOTE_KIND (insn) != NOTE_INSN_BLOCK_END)))
> +              && NOTE_KIND (insn) != NOTE_INSN_BLOCK_END
> +              && NOTE_KIND (insn) != NOTE_INSN_DELETED_DEBUG_LABEL)))
>        print_rtl_single (final_output, insn);
>     }
>
> --- gcc/var-tracking.c.jj       2011-11-01 09:04:37.000000000 +0100
> +++ gcc/var-tracking.c  2011-11-04 17:45:22.000000000 +0100
> @@ -9517,6 +9517,12 @@ vt_initialize (void)
>   return true;
>  }
>
> +/* This is *not* reset after each function.  It gives each
> +   NOTE_INSN_DELETED_DEBUG_LABEL in the entire compilation
> +   a unique label number.  */
> +
> +static int debug_label_num = 1;
> +
>  /* Get rid of all debug insns from the insn stream.  */
>
>  static void
> @@ -9532,7 +9538,22 @@ delete_debug_insns (void)
>     {
>       FOR_BB_INSNS_SAFE (bb, insn, next)
>        if (DEBUG_INSN_P (insn))
> -         delete_insn (insn);
> +         {
> +           tree decl = INSN_VAR_LOCATION_DECL (insn);
> +           if (TREE_CODE (decl) == LABEL_DECL
> +               && DECL_NAME (decl)
> +               && !DECL_RTL_SET_P (decl))
> +             {
> +               PUT_CODE (insn, NOTE);
> +               NOTE_KIND (insn) = NOTE_INSN_DELETED_DEBUG_LABEL;
> +               NOTE_DELETED_LABEL_NAME (insn)
> +                 = IDENTIFIER_POINTER (DECL_NAME (decl));
> +               SET_DECL_RTL (decl, insn);
> +               CODE_LABEL_NUMBER (insn) = debug_label_num++;
> +             }
> +           else
> +             delete_insn (insn);
> +         }
>     }
>  }
>
> --- gcc/cfglayout.c.jj  2011-08-28 12:36:57.000000000 +0200
> +++ gcc/cfglayout.c     2011-11-04 17:42:35.000000000 +0100
> @@ -149,6 +149,7 @@ skip_insns_after_block (basic_block bb)
>            break;
>          case NOTE_INSN_DELETED:
>          case NOTE_INSN_DELETED_LABEL:
> +         case NOTE_INSN_DELETED_DEBUG_LABEL:
>            continue;
>          default:
>            reorder_insns (insn, insn, last_insn);
> @@ -1174,6 +1175,10 @@ duplicate_insn_chain (rtx from, rtx to)
>       switch (GET_CODE (insn))
>        {
>        case DEBUG_INSN:
> +         /* Don't duplicate label debug insns.  */
> +         if (TREE_CODE (INSN_VAR_LOCATION_DECL (insn)) == LABEL_DECL)
> +           break;
> +         /* FALLTHRU */
>        case INSN:
>        case CALL_INSN:
>        case JUMP_INSN:
> @@ -1219,6 +1224,7 @@ duplicate_insn_chain (rtx from, rtx to)
>
>            case NOTE_INSN_DELETED:
>            case NOTE_INSN_DELETED_LABEL:
> +           case NOTE_INSN_DELETED_DEBUG_LABEL:
>              /* No problem to strip these.  */
>            case NOTE_INSN_FUNCTION_BEG:
>              /* There is always just single entry to function.  */
> --- gcc/insn-notes.def.jj       2011-07-27 23:25:36.000000000 +0200
> +++ gcc/insn-notes.def  2011-11-04 17:31:08.000000000 +0100
> @@ -36,6 +36,10 @@ INSN_NOTE (DELETED)
>
>  /* Generated in place of user-declared labels when they are deleted.  */
>  INSN_NOTE (DELETED_LABEL)
> +/* Similarly, but for labels that have been present in debug stmts
> +   earlier and thus will only appear with -g.  These must use different
> +   label namespace.  */
> +INSN_NOTE (DELETED_DEBUG_LABEL)
>
>  /* These are used to mark the beginning and end of a lexical block.
>    See NOTE_BLOCK and reorder_blocks.  */
> --- gcc/print-rtl.c.jj  2011-08-28 12:36:57.000000000 +0200
> +++ gcc/print-rtl.c     2011-11-04 17:33:40.000000000 +0100
> @@ -283,6 +283,7 @@ print_rtx (const_rtx in_rtx)
>                }
>
>              case NOTE_INSN_DELETED_LABEL:
> +             case NOTE_INSN_DELETED_DEBUG_LABEL:
>                {
>                  const char *label = NOTE_DELETED_LABEL_NAME (in_rtx);
>                  if (label)
> @@ -442,7 +443,8 @@ print_rtx (const_rtx in_rtx)
>          {
>            /* This field is only used for NOTE_INSN_DELETED_LABEL, and
>               other times often contains garbage from INSN->NOTE death.  */
> -           if (NOTE_KIND (in_rtx) == NOTE_INSN_DELETED_LABEL)
> +           if (NOTE_KIND (in_rtx) == NOTE_INSN_DELETED_LABEL
> +               || NOTE_KIND (in_rtx) == NOTE_INSN_DELETED_DEBUG_LABEL)
>              fprintf (outfile, " %d",  XINT (in_rtx, i));
>          }
>  #if !defined(GENERATOR_FILE) && NUM_UNSPECV_VALUES > 0
> --- gcc/gengtype.c.jj   2011-10-17 09:20:38.000000000 +0200
> +++ gcc/gengtype.c      2011-11-04 17:34:55.000000000 +0100
> @@ -1015,6 +1015,7 @@ adjust_field_rtx_def (type_p t, options_
>          {
>          case NOTE_INSN_MAX:
>          case NOTE_INSN_DELETED_LABEL:
> +         case NOTE_INSN_DELETED_DEBUG_LABEL:
>            note_flds = create_field (note_flds, &string_type, "rt_str");
>            break;
>
> --- gcc/config/i386/i386.c.jj   2011-11-04 12:48:16.000000000 +0100
> +++ gcc/config/i386/i386.c      2011-11-04 17:51:41.000000000 +0100
> @@ -10879,15 +10879,28 @@ ix86_output_function_epilogue (FILE *fil
>      it looks like we might want one, insert a NOP.  */
>   {
>     rtx insn = get_last_insn ();
> +    rtx deleted_debug_label = NULL_RTX;
>     while (insn
>           && NOTE_P (insn)
>           && NOTE_KIND (insn) != NOTE_INSN_DELETED_LABEL)
> -      insn = PREV_INSN (insn);
> +      {
> +       /* Don't insert a nop for NOTE_INSN_DELETED_DEBUG_LABEL
> +          notes only, instead set their CODE_LABEL_NUMBER to -1,
> +          otherwise there would be code generation differences
> +          in between -g and -g0.  */
> +       if (NOTE_P (insn) && NOTE_KIND (insn) == 
> NOTE_INSN_DELETED_DEBUG_LABEL)
> +         deleted_debug_label = insn;
> +       insn = PREV_INSN (insn);
> +      }
>     if (insn
>        && (LABEL_P (insn)
>            || (NOTE_P (insn)
>                && NOTE_KIND (insn) == NOTE_INSN_DELETED_LABEL)))
>       fputs ("\tnop\n", file);
> +    else if (deleted_debug_label)
> +      for (insn = deleted_debug_label; insn; insn = NEXT_INSN (insn))
> +       if (NOTE_KIND (insn) == NOTE_INSN_DELETED_DEBUG_LABEL)
> +         CODE_LABEL_NUMBER (insn) = -1;
>   }
>  #endif
>
> --- gcc/config/rs6000/rs6000.c.jj       2011-11-04 07:49:43.000000000 +0100
> +++ gcc/config/rs6000/rs6000.c  2011-11-04 17:52:14.000000000 +0100
> @@ -21461,15 +21461,28 @@ rs6000_output_function_epilogue (FILE *f
>      it looks like we might want one, insert a NOP.  */
>   {
>     rtx insn = get_last_insn ();
> +    rtx deleted_debug_label = NULL_RTX;
>     while (insn
>           && NOTE_P (insn)
>           && NOTE_KIND (insn) != NOTE_INSN_DELETED_LABEL)
> -      insn = PREV_INSN (insn);
> +      {
> +       /* Don't insert a nop for NOTE_INSN_DELETED_DEBUG_LABEL
> +          notes only, instead set their CODE_LABEL_NUMBER to -1,
> +          otherwise there would be code generation differences
> +          in between -g and -g0.  */
> +       if (NOTE_P (insn) && NOTE_KIND (insn) == 
> NOTE_INSN_DELETED_DEBUG_LABEL)
> +         deleted_debug_label = insn;
> +       insn = PREV_INSN (insn);
> +      }
>     if (insn
>        && (LABEL_P (insn)
>            || (NOTE_P (insn)
>                && NOTE_KIND (insn) == NOTE_INSN_DELETED_LABEL)))
>       fputs ("\tnop\n", file);
> +    else if (deleted_debug_label)
> +      for (insn = deleted_debug_label; insn; insn = NEXT_INSN (insn))
> +       if (NOTE_KIND (insn) == NOTE_INSN_DELETED_DEBUG_LABEL)
> +         CODE_LABEL_NUMBER (insn) = -1;
>   }
>  #endif
>
>
>        Jakub
>

Reply via email to