Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Register scavenger seems to spill a live register #33034

Closed
llvmbot opened this issue Jul 4, 2017 · 5 comments
Closed

Register scavenger seems to spill a live register #33034

llvmbot opened this issue Jul 4, 2017 · 5 comments
Assignees
Labels
bugzilla Issues migrated from bugzilla

Comments

@llvmbot
Copy link
Collaborator

llvmbot commented Jul 4, 2017

Bugzilla Link 33687
Resolution FIXED
Resolved on Jul 06, 2017 20:03
Version trunk
OS Linux
Attachments Testcase from libcxx
Reporter LLVM Bugzilla Contributor
CC @DMG862,@MatzeB

Extended Description

This bug happens in Cortex-M0 after https://reviews.llvm.org/D21885 and none of the follow-ups seem to have fixed it.

The failing test case comes from the libcxx testsuite. Apologies for the big testcase but I didn't manage to
reduce it further using bugpoint without introducing unpleasant "undefs" everywhere.

clang -S -o test.s -mcpu=cortex-m0 --target=arm-arm-none-eabi iterator.pass.bad.ll

The issue is that, at the point the RegisterScavenger is run, we have a very big basic block, number 47.

In which the phyisical register %R2 has a very long live range as it is defined
very early in the function.

%R2<def> = tLDRpci <cp#0>, pred:14, pred:%noreg

Right before the Register scavenging there is this sequence if instructions in that same basic block #​47

%vreg42<def> = tLDRpci <cp#143>, pred:14, pred:%noreg; tGPR:%vreg42
%vreg42<def,tied1> = tADDhirr %vreg42<tied0>, %SP<kill>, pred:14, pred:%noreg; tGPR:%vreg42
tSTRi %R0, %vreg42<kill>, 0, pred:14, pred:%noreg; mem:ST4[%760] tGPR:%vreg42
%vreg43<def> = tLDRpci <cp#144>, pred:14, pred:%noreg; tGPR:%vreg43
%vreg43<def,tied1> = tADDhirr %vreg43<tied0>, %SP<kill>, pred:14, pred:%noreg; tGPR:%vreg43
tSTRi %R1, %vreg43<kill>, 0, pred:14, pred:%noreg; mem:ST4[%761](align=8) tGPR:%vreg43
%vreg44<def> = tLDRpci <cp#145>, pred:14, pred:%noreg; tGPR:%vreg44
%vreg44<def,tied1> = tADDhirr %vreg44<tied0>, %SP<kill>, pred:14, pred:%noreg; tGPR:%vreg44  <-- (B)
tSTRi %R2, %vreg44<kill>, 0, pred:14, pred:%noreg; mem:ST4[%761+4] tGPR:%vreg44   <-- (A)

After the register scavenger, though, R2 is spilled (R12 is a scratch register in ARM).

%R12<def> = tMOVr %R2<kill>, pred:14, pred:%noreg
%R2<def> = tLDRpci <cp#143>, pred:14, pred:%noreg
%R2<def,tied1> = tADDhirr %R2<tied0>, %SP<kill>, pred:14, pred:%noreg
tSTRi %R0, %R2<kill>, 0, pred:14, pred:%noreg; mem:ST4[%760]
%R2<def> = tLDRpci <cp#144>, pred:14, pred:%noreg
%R2<def,tied1> = tADDhirr %R2<tied0>, %SP<kill>, pred:14, pred:%noreg
tSTRi %R1, %R2<kill>, 0, pred:14, pred:%noreg; mem:ST4[%761](align=8)
%R2<def> = tLDRpci <cp#145>, pred:14, pred:%noreg
%R2<def,tied1> = tADDhirr %R2<tied0>, %SP<kill>, pred:14, pred:%noreg
tSTRi %R2<kill>, %R2<kill>, 0, pred:14, pred:%noreg; mem:ST4[%761+4]    <-- problem
%R2<def> = tMOVr %R12<kill>, pred:14, pred:%noreg

The value of R2 is still used however has been clobbered durng the spill.

What I see is that the current algorithm in scavengeFrameVirtualRegsInBlock
loops from the last to the first instruction, but if an instruction only reads
a virtual register and does not write it, then this instruction is handled in
the next iteration (so the iteration of the previous instruction).

static bool scavengeFrameVirtualRegsInBlock(MachineRegisterInfo &MRI,
RegScavenger &RS,
MachineBasicBlock &MBB) {
const TargetRegisterInfo &TRI = *MRI.getTargetRegisterInfo();
RS.enterBasicBlockEnd(MBB);

unsigned InitialNumVirtRegs = MRI.getNumVirtRegs();
bool NextInstructionReadsVReg = false;
for (MachineBasicBlock::iterator I = MBB.end(); I != MBB.begin(); ) {
--I;
// Move RegScavenger to the position between *I and *std::next(I).
RS.backward(I);

// Look for unassigned vregs in the uses of *std::next(I).
if (NextInstructionReadsVReg) {
  MachineBasicBlock::iterator N = std::next(I);
  const MachineInstr &NMI = *N;
  for (const MachineOperand &MO : NMI.operands()) {
    if (!MO.isReg())
      continue;
    unsigned Reg = MO.getReg();
    // We only care about virtual registers and ignore virtual registers
    // created by the target callbacks in the process (those will be handled
    // in a scavenging round).
    if (!TargetRegisterInfo::isVirtualRegister(Reg) ||
        TargetRegisterInfo::virtReg2Index(Reg) >= InitialNumVirtRegs)
      continue;
    if (!MO.readsReg())
      continue;

    unsigned SReg = scavengeVReg(MRI, RS, Reg, true); // <-- (C)
    N->addRegisterKilled(SReg, &TRI, false);
    RS.setRegUsed(SReg);
  }
}
... rest of the loop ...

}

So in my testcase when I == (A), given that it only reads a vreg but does not
write it, it is handled in the next iteration. This is, when I == (B) in which
case N == (A). Then because of RS.backward(I) at the beginning of the loop,
RS.MBBI points at (B) so scavengeVReg will start from (B) without
checking anything of (A).

I made a quick experiment replacing (C) with

RS.skipTo(N);
unsigned SReg = scavengeVReg(MRI, RS, Reg, true);

but I'm pretty sure this is wrong (and also makes other tests fail). So I'm a
bit puzzled at this point what is the reason why the RegScavenger thinks that
R2 is an eligible register at this point. It looks to me that not considering
(A) might be the cause but then this problem could have happened in other parts
of that basic block that expose similar patterns.

Kind regards.

@llvmbot
Copy link
Collaborator Author

llvmbot commented Jul 4, 2017

assigned to @MatzeB

@MatzeB
Copy link
Contributor

MatzeB commented Jul 5, 2017

The MI snippets given here look fine to me: %R2 is spilled and then reused for something else.

The actual problem may be that %R2 isn't restored early enough? I will need to look into the actual example to check that.

@MatzeB
Copy link
Contributor

MatzeB commented Jul 7, 2017

Hi,

I am trying to reproduce this. I added MF.dump() at the beginning of llvm::scavengeFrameVirtualRegs() to get a dump immediately before scavenging where the vregs to scavenge are still around.

I could not find any block in the dump that looks similar to the snippet you showed. BB#42 ends up being a short blocks that looks nothing like it and I couldn't find any similar code around. This was on todays llvm r307338 running llc without any additional flags on the file. Do I need additional flags is it just a different version?

@MatzeB
Copy link
Contributor

MatzeB commented Jul 7, 2017

Sorry, just realized you already had a clang commandline up there, I can reproduce the situation with that.

@MatzeB
Copy link
Contributor

MatzeB commented Jul 7, 2017

Thanks for the report! Fixed in r307352.

@llvmbot llvmbot transferred this issue from llvm/llvm-bugzilla-archive Dec 10, 2021
This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bugzilla Issues migrated from bugzilla
Projects
None yet
Development

No branches or pull requests

2 participants