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.