This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

RFA: rtl-optimization/16643: cleanup_cfg() & register liveness


The following testcase:

    void foo (int a, int b, int c, int d, int e, int *f)
    {
      if (a == 0)
        if (b == 0)
          if (c == 0)
            if (d == 0)
              {
                *f = e;
                return;
              }
      *f = e;
      return;
    }

ICEs at -O2 on mips targets.  This happens both on mainline and
3.4 branch, but not 3.3.

As expected, crossjumping unifies the duplicate "*f = e" blocks,
leaving rtl like:

    if d == 0 then goto LABEL
    ;; end of block B1

    ;; start of block B2
    ;; end of block B2

    ;; start of block B3
    LABEL:

cleanup_cfg() (specifically try_simplify_condjump()) then deletes
the "if d == 0" branch, giving us:

    ;; start of block B1
    ;; end of block B1

    ;; start of block B3
    LABEL:

Now it looks like cleanup_cfg() is supposed to iterate until all such
jumps have been simplified, but it doesn't.  This is because it uses
a cache (the bb aux field) to detect forwarder blocks, and this cache
is not updated after B1 has been simplified.  Thus we only eliminate
one such branch for each call to cleanup_cfg().

The first patch below fixes that, and cures the ICE.  But to finish the
story... the task of cleaning up the final "a == 0" branch is left to:

    cleanup_cfg (CLEANUP_CFGLAYOUT);

called from cfg_layout_initialize(), itself called from
reorder_basic_blocks().  Now this call doesn't update the liveness
information, so "a" is still marked as live after all uses have been
deleted.  This causes the usual verify_local_live_at_start failure
during scheduling.

CLEANUP_CFGLAYOUT is clearly capable of deleting register uses, so I
assume that we should use CLEANUP_UPDATE_LIFE when liveness information
needs to be kept up to date.  That's what the second patch does, and it
also fixes the ICE (independently of the first).

The second patch has to touch other users of cfglayout as well:

   1) tracer:
        - called once before flow1, where CLEANUP_UPDATE_LIFE isn't needed
        - called once during bbro, where C_U_L is needed.

   2) reorder_basic_blocks
        - called once during bbro, where C_U_L is needed.
        - called once during stack, where C_U_L isn't needed.

   3) partition_hot_and_cold_blocks
        - called after flow1, but liveness info is recomputed immedately
          afterwards, so I don't think C_U_L is needed.

   4) thread_prologue_and_epilogue_insns
        - called between reload and flow2, C_U_L isn't needed.

   5) loop2:
        - before flow1, C_U_L isn't needed.

Slightly different patches are needed for mainline and branch.
The mainline versions have been bootstrapped & regression tested on
i686-pc-linux-gnu.  I'm testing the 3.4 patches on mips*-linux-gnu
targets now.

Assuming the 3.4 tests pass, are both patches OK for mainline and
branch?  Or would it be better to just apply the first patch to branch?

Richard

Attachment: 16643-1-mainline.diff
Description: Text document

Attachment: 16643-1-branch.diff
Description: Text document

Attachment: 16643-2-mainline.diff
Description: Text document

Attachment: 16643-2-branch.diff
Description: Text document

/* PR rtl-optimization/16643 */
void foo (int a, int b, int c, int d, int e, int *f)
{
  if (a == 0)
    if (b == 0)
      if (c == 0)
	if (d == 0)
	  {
	    *f = e;
	    return;
	  }
  *f = e;
  return;
}

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]