https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86069

            Bug ID: 86069
           Summary: MIPS out-of-range branch expansion can break with
                    -fpic and shrink wrapping
           Product: gcc
           Version: 7.3.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: target
          Assignee: unassigned at gcc dot gnu.org
          Reporter: mpf at gcc dot gnu.org
  Target Milestone: ---

Created attachment 44241
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=44241&action=edit
test case

MIPS determines whether a branch is out of range quite late on and replaces an
out of range branch with either a direct or indirect jump. When compiling PIC
code then the only option for a long branch is to perform an indirect jump as
direct jumps are not PC-relative (at least not in the obvious way). The label
to jump to has to be obtained from the GOT as there is no way to calculate a
PC-relative offset directly either. The last-minute expansion of this code has
to grab the GOT pointer from the stack and then load the destination. The
expansion looks like this:

        beq     $4,$2,.L4

into

        bne     $4,$2,.L7
        .set    noat
        lw      $1,16($sp)
        lw      $1,%got(.L4)($1)
        addiu   $1,$1,%lo(.L4)
        jr      $1
        .set    at
.L7:

With shrink-wrapping it is possible for the compiler to move the prologue (that
sets up the GOT pointer and stashes it on the stack) to be moved after a
potentially out-of-range branch. The branch instructions do not acknowledge the
potential for them to be expanded into a GOT dependent sequence so there is no
way for the shrink-wrap code to do the right thing.

The obvious/simple solution may well be to mark all conditional branches as
using the GOT pointer for PIC code but this will effectively disable shrink
wrapping. To do anything smarter would require handling out-of-range branches
much earlier which is also unlikely to be a good idea.

Test case attached in dejagnu format. It fails at O1 and above. The original
failure was found as part of building LLVM with GCC and has been simplified to
this test case by Simon Dardis.

Reply via email to