The testing for returnBB was flipped which may cause ARM ld/st opt pass uses callee saved regs in returnBB when shrink-wrap is used.
Details
Diff Detail
- Repository
- rL LLVM
Event Timeline
E.g.: Before LD/ST opt: BB1: ... %SP<def,tied1> = t2LDMIA_UPD %SP<tied0>, pred:14, pred:%noreg, %R4<def>, %R5<def>, %R7<def>, %LR<def> Successors according to CFG: BB#3 BB#3: derived from LLVM BB %if.end Live Ins: %R0 %R1 %R2 %R3 %R12 %LR %R7 %R5 %R4 t2STRi12 %R2<kill>, %R1, 20, pred:14, pred:%noreg; t2STRi12 %R3<kill>, %R1, 24, pred:14, pred:%noreg; mem:ST4[%22] t2STRi12 %R12<kill>, %R1, 28, pred:14, pred:%noreg; mem:ST4[%23] tBX_RET pred:14, pred:%noreg After LD/ST opt: BB#3: derived from LLVM BB %if.end Live Ins: %R0 %R1 %R2 %R3 %R12 %LR %R7 %R5 %R4 %LR<def> = t2ADDri %R1, 20, pred:14, pred:%noreg, opt:%noreg t2STMIA %LR<kill>, pred:14, pred:%noreg, %R2<kill>, %R3<kill>, %R12<kill> tBX_RET pred:14, pred:%noreg
Looks like a typo.
lib/Target/ARM/ARMLoadStoreOptimizer.cpp | ||
---|---|---|
575 | Same test on both sides of '||' ? |
lib/Target/ARM/ARMLoadStoreOptimizer.cpp | ||
---|---|---|
575 | yes, it's typo. Thanks! |
Unfortunately, it's hard to reduce to a simple test case because
- The reproduce the issue, we need to make sure certain regs are used at that time
- The problem is exposed using a modified reg alloc policy which is not available on community now.
This patch looks like fixing a symptom rather than the root cause. Shouldn't BX_RET simply have an implicit use operand for LR? So this would rather need fixing where BX_RET is constructed.
Yes, I tried to add a use in td file like:
let isReturn = 1, isTerminator = 1, isBarrier = 1, Uses = [LR] in {
def tBX_RET : tPseudoExpand<(outs), (ins pred:$p), 2, IIC_Br, [(ARMretflag)], (tBX LR, pred:$p)>, Sched<[WriteBr]>;
Then I got an error like "use of undefined register LR". Any suggestions?
Thanks
I assume you removed LR from the callee saved register set, in that case it probably has to go into the live-in list in the start block.
At first, I thought LR was just a corner case that ld/st opt didn't handled correctly.
Then, I find another case where R4 is used in exiting BB and not restored.
Before ld/st opt pass:
BB#3: derived from LLVM BB %if.end
Live Ins: %R0 %R1 %R2 %R3 %R12 %LR %R7 %R5 %R4 Predecessors according to CFG: BB#2 BB#1
t2STRi12 %R2<kill>, %R1, 20, pred:14, pred:%noreg; mem:ST4[%21]
t2STRi12 %R3<kill>, %R1, 24, pred:14, pred:%noreg; mem:ST4[%22]
t2STRi12 %R12<kill>, %R1, 28, pred:14, pred:%noreg; mem:ST4[%23]
t2STRi12 %R0<kill>, %R1<kill>, 32, pred:14, pred:%noreg; mem:ST4[%24]
tBX_RET pred:14, pred:%noreg
After ld/st opt pass:
BB#3: derived from LLVM BB %if.end
Live Ins: %R0 %R1 %R2 %R3 %R12 %LR %R7 %R5 %R4 Predecessors according to CFG: BB#2 BB#1
%R4<def> = t2ADDri %R1, 20, pred:14, pred:%noreg, opt:%noreg
t2STMIA %R4<kill>, pred:14, pred:%noreg, %R2<kill>, %R3<kill>, %R12<kill> ==> R4 is clobbed
t2STRi12 %R0<kill>, %R1<kill>, 32, pred:14, pred:%noreg; mem:ST4[%24]
tBX_RET pred:14, pred:%noreg
But LivePhysRegs::addLiveOuts should add all the callee saves! Does maybe MBB->isReturnBlock() return false somehow in your case?
Oh. currently in addLiveOuts:
if (!MBB->isReturnBlock()) { // The return block has no successors whose live-ins we could merge // below. So instead we add the callee saved registers manually. for (const MCPhysReg *I = TRI->getCalleeSavedRegs(&MF); *I; ++I) addReg(*I);
Looks we should flip the condition to
if (!MBB->isReturnBlock())
I think originally the problem was covered because epilogue will do the job. Now with shrink-wrap, it is exposed.
Same test on both sides of '||' ?