This is an archive of the discontinued LLVM Phabricator instance.

[RegisterScavenger][RISCV] Don't search for FrameSetup instrs if we were searching from Non-FrameSetup instrs
ClosedPublic

Authored by StephenFan on Oct 11 2022, 9:44 AM.

Details

Summary

Otherwise, the spill position may point to position where before
FrameSetup instructions. In which case, the spill instruction may store
to caller's frame since the stack pointer has not been adjustted.

Fixes https://github.com/llvm/llvm-project/issues/58286

Diff Detail

Event Timeline

StephenFan created this revision.Oct 11 2022, 9:44 AM
Herald added a project: Restricted Project. · View Herald TranscriptOct 11 2022, 9:44 AM
StephenFan requested review of this revision.Oct 11 2022, 9:44 AM
craig.topper added inline comments.Oct 11 2022, 9:56 AM
llvm/lib/CodeGen/RegisterScavenging.cpp
378

I think "to where" should be removed from this sentence.

380

Use MI.getFlag?

If I understand correctly, the use of a vreg in the frame-setup allowed findSurvivorBackward to trigger this code

// Keep searching when we find a vreg since the spilled register will
// be usefull for this other vreg as well later.
bool FoundVReg = false;
for (const MachineOperand &MO : MI.operands()) {
  if (MO.isReg() && Register::isVirtualRegister(MO.getReg())) {
    FoundVReg = true;
    break;
  }
}
if (FoundVReg) {
  InstrCountDown = InstrLimit;
  Pos = I;
}

which caused the search to stop above the frame-setup. So another option might be to use T1 as the scratch register in frame-setup as was once proposed in an earlier revision of https://reviews.llvm.org/D61884

If I understand correctly, the use of a vreg in the frame-setup allowed findSurvivorBackward to trigger this code

// Keep searching when we find a vreg since the spilled register will
// be usefull for this other vreg as well later.
bool FoundVReg = false;
for (const MachineOperand &MO : MI.operands()) {
  if (MO.isReg() && Register::isVirtualRegister(MO.getReg())) {
    FoundVReg = true;
    break;
  }
}
if (FoundVReg) {
  InstrCountDown = InstrLimit;
  Pos = I;
}

which caused the search to stop above the frame-setup. So another option might be to use T1 as the scratch register in frame-setup as was once proposed in an earlier revision of https://reviews.llvm.org/D61884

But we can't use T1 with shrink wrapping and I've confirmed the same bug exists with shrink wrapping.

If I understand correctly, the use of a vreg in the frame-setup allowed findSurvivorBackward to trigger this code

// Keep searching when we find a vreg since the spilled register will
// be usefull for this other vreg as well later.
bool FoundVReg = false;
for (const MachineOperand &MO : MI.operands()) {
  if (MO.isReg() && Register::isVirtualRegister(MO.getReg())) {
    FoundVReg = true;
    break;
  }
}
if (FoundVReg) {
  InstrCountDown = InstrLimit;
  Pos = I;
}

which caused the search to stop above the frame-setup. So another option might be to use T1 as the scratch register in frame-setup as was once proposed in an earlier revision of https://reviews.llvm.org/D61884

But we can't use T1 with shrink wrapping and I've confirmed the same bug exists with shrink wrapping.

Thanks for looking into shrink-wrapping! Do you mind sharing your shrink-wrapping test cases? So that I can pick them as CodeGen/RISCV test cases.

  1. Remove "to where" in comment.
  2. Use MI. instead of I->
  3. Update failed tests.
StephenFan added inline comments.Oct 11 2022, 8:08 PM
llvm/test/CodeGen/RISCV/out-of-reach-emergency-slot.mir
27

The code here seems incorrect. Here a1 is stored to 0(sp) before sub sp, sp, a1 but restored after sub sp, sp, a1.

llvm/test/CodeGen/RISCV/rvv/large-rvv-stack-size.mir
20

See the comment above.

craig.topper added inline comments.Oct 11 2022, 9:20 PM
llvm/test/CodeGen/RISCV/out-of-reach-emergency-slot.mir
37

This doens't look correct either.

If I understand correctly, the use of a vreg in the frame-setup allowed findSurvivorBackward to trigger this code

// Keep searching when we find a vreg since the spilled register will
// be usefull for this other vreg as well later.
bool FoundVReg = false;
for (const MachineOperand &MO : MI.operands()) {
  if (MO.isReg() && Register::isVirtualRegister(MO.getReg())) {
    FoundVReg = true;
    break;
  }
}
if (FoundVReg) {
  InstrCountDown = InstrLimit;
  Pos = I;
}

which caused the search to stop above the frame-setup. So another option might be to use T1 as the scratch register in frame-setup as was once proposed in an earlier revision of https://reviews.llvm.org/D61884

But we can't use T1 with shrink wrapping and I've confirmed the same bug exists with shrink wrapping.

Thanks for looking into shrink-wrapping! Do you mind sharing your shrink-wrapping test cases? So that I can pick them as CodeGen/RISCV test cases.

This was my shrink wrap case

@var = external global i32                                                       
                                                                                 
define void @func(i1 %c) {                                                       
  %space = alloca i32, align 4                                                   
  %stackspace = alloca[1024 x i32], align 4                                      
  br i1 %c, label %foo, label %bar                                               
                                                                                 
bar:                                                                             
                                                                                 
  ;; Load values to increase register pressure.                                  
  %v0 = load volatile i32, i32* @var                                             
  %v1 = load volatile i32, i32* @var                                             
  %v2 = load volatile i32, i32* @var                                             
  %v3 = load volatile i32, i32* @var                                             
  %v4 = load volatile i32, i32* @var                                             
  %v5 = load volatile i32, i32* @var                                             
  %v6 = load volatile i32, i32* @var                                             
  %v7 = load volatile i32, i32* @var                                             
  %v8 = load volatile i32, i32* @var                                             
  %v9 = load volatile i32, i32* @var                                             
  %v10 = load volatile i32, i32* @var                                            
  %v11 = load volatile i32, i32* @var                                            
  %v12 = load volatile i32, i32* @var                                            
  %v13 = load volatile i32, i32* @var                                            
                                                                                 
  store volatile i32 %v0, i32* %space                                            
                                                                                 
  ;; store values so they are used.                                              
  store volatile i32 %v0, i32* @var                                              
  store volatile i32 %v1, i32* @var                                              
  store volatile i32 %v2, i32* @var                                              
  store volatile i32 %v3, i32* @var                                              
  store volatile i32 %v4, i32* @var                                              
  store volatile i32 %v5, i32* @var                                              
  store volatile i32 %v6, i32* @var                                              
  store volatile i32 %v7, i32* @var                                              
  store volatile i32 %v8, i32* @var                                              
  store volatile i32 %v9, i32* @var                                              
  store volatile i32 %v10, i32* @var                                             
  store volatile i32 %v11, i32* @var                                             
  store volatile i32 %v12, i32* @var                                             
  store volatile i32 %v13, i32* @var                                             
  br label %foo                                                                  
                                                                                 
foo:                                                                             
  ret void                                                                       
}
StephenFan added inline comments.Oct 12 2022, 7:42 AM
llvm/test/CodeGen/RISCV/out-of-reach-emergency-slot.mir
37

This test case is tricky and rare. We may need to implement the target hook saveScavengerRegister to fix it. So I left a FIXME.

If I understand correctly, the use of a vreg in the frame-setup allowed findSurvivorBackward to trigger this code

// Keep searching when we find a vreg since the spilled register will
// be usefull for this other vreg as well later.
bool FoundVReg = false;
for (const MachineOperand &MO : MI.operands()) {
  if (MO.isReg() && Register::isVirtualRegister(MO.getReg())) {
    FoundVReg = true;
    break;
  }
}
if (FoundVReg) {
  InstrCountDown = InstrLimit;
  Pos = I;
}

which caused the search to stop above the frame-setup. So another option might be to use T1 as the scratch register in frame-setup as was once proposed in an earlier revision of https://reviews.llvm.org/D61884

But we can't use T1 with shrink wrapping and I've confirmed the same bug exists with shrink wrapping.

Thanks for looking into shrink-wrapping! Do you mind sharing your shrink-wrapping test cases? So that I can pick them as CodeGen/RISCV test cases.

This was my shrink wrap case

@var = external global i32                                                       
                                                                                 
define void @func(i1 %c) {                                                       
  %space = alloca i32, align 4                                                   
  %stackspace = alloca[1024 x i32], align 4                                      
  br i1 %c, label %foo, label %bar                                               
                                                                                 
bar:                                                                             
                                                                                 
  ;; Load values to increase register pressure.                                  
  %v0 = load volatile i32, i32* @var                                             
  %v1 = load volatile i32, i32* @var                                             
  %v2 = load volatile i32, i32* @var                                             
  %v3 = load volatile i32, i32* @var                                             
  %v4 = load volatile i32, i32* @var                                             
  %v5 = load volatile i32, i32* @var                                             
  %v6 = load volatile i32, i32* @var                                             
  %v7 = load volatile i32, i32* @var                                             
  %v8 = load volatile i32, i32* @var                                             
  %v9 = load volatile i32, i32* @var                                             
  %v10 = load volatile i32, i32* @var                                            
  %v11 = load volatile i32, i32* @var                                            
  %v12 = load volatile i32, i32* @var                                            
  %v13 = load volatile i32, i32* @var                                            
                                                                                 
  store volatile i32 %v0, i32* %space                                            
                                                                                 
  ;; store values so they are used.                                              
  store volatile i32 %v0, i32* @var                                              
  store volatile i32 %v1, i32* @var                                              
  store volatile i32 %v2, i32* @var                                              
  store volatile i32 %v3, i32* @var                                              
  store volatile i32 %v4, i32* @var                                              
  store volatile i32 %v5, i32* @var                                              
  store volatile i32 %v6, i32* @var                                              
  store volatile i32 %v7, i32* @var                                              
  store volatile i32 %v8, i32* @var                                              
  store volatile i32 %v9, i32* @var                                              
  store volatile i32 %v10, i32* @var                                             
  store volatile i32 %v11, i32* @var                                             
  store volatile i32 %v12, i32* @var                                             
  store volatile i32 %v13, i32* @var                                             
  br label %foo                                                                  
                                                                                 
foo:                                                                             
  ret void                                                                       
}

Thanks!

StephenFan retitled this revision from [WIP][RegisterScavenger][RISCV] Don't search for FrameSetup instrs if we were searching from Non-FrameSetup instrs to [RegisterScavenger][RISCV] Don't search for FrameSetup instrs if we were searching from Non-FrameSetup instrs.

Add test case.

craig.topper added inline comments.Oct 18 2022, 8:31 PM
llvm/lib/CodeGen/RegisterScavenging.cpp
376

Can this be done in the FoundTo path? Does this matter before we find To?

Do check in FoundTo path.

StephenFan added inline comments.Oct 25 2022, 11:55 PM
llvm/lib/CodeGen/RegisterScavenging.cpp
376

You are right. It doesn't matter before we find To.

This revision is now accepted and ready to land.Nov 16 2022, 9:39 PM