This is an archive of the discontinued LLVM Phabricator instance.

[ARM] Only update the successor edges for immediate predecessors of PrologueMBB.
ClosedPublic

Authored by ZhiyaoMa98 on Apr 1 2022, 7:51 PM.

Details

Summary

When adjusting the function prologue for segmented stacks, only update the successor edges of the immediate predecessors of the original prologue.

I encountered a segmentation fault in LLVM while compiling the Rust core targeting armv7em with segmented stack enabled. Below is my attempt to fix it. I am not very certain about the correctness of my patch, because I do not fully understand the code.

Looking at the do-while loop

SmallPtrSet<MachineBasicBlock *, 8> BeforePrologueRegion;
SmallVector<MachineBasicBlock *, 2> WalkList;
WalkList.push_back(&PrologueMBB);

do {
  MachineBasicBlock *CurMBB = WalkList.pop_back_val();
  for (MachineBasicBlock *PredBB : CurMBB->predecessors()) {
    if (BeforePrologueRegion.insert(PredBB).second)
      WalkList.push_back(PredBB);
  }
} while (!WalkList.empty());

it seems BeforePrologueRegion contains non-immediate predecessors of PrologueMBB .

However, in the following while loop, ReplaceUsesOfBlockWith assumes that MBB is an immediate predecessor of PrologueMBB.

for (MachineBasicBlock *MBB : BeforePrologueRegion) {
  // Make sure the LiveIns are still sorted and unique.
  MBB->sortUniqueLiveIns();
  // Replace the edges to PrologueMBB by edges to the sequences
  // we are about to add.
  MBB->ReplaceUsesOfBlockWith(&PrologueMBB, AddedBlocks[0]);
}

The assumption comes from the function call chain

MBB->ReplaceUsesOfBlockWith(&PrologueMBB, AddedBlocks[0]);
--> replaceSuccessor(Old, New);
----> Old->removePredecessor(this);
------> assert(I != Predecessors.end()); Predecessors.erase(I);

I ran into this problem when I was compiling Rust core in release mode targeting armv7em with segmented stack enabled. The Predecessors.erase(I); line led to a segmentation fault.

I fixed the problem by adding the if-continue statement. It still passed all of the tests.

Diff Detail

Event Timeline

ZhiyaoMa98 created this revision.Apr 1 2022, 7:51 PM
ZhiyaoMa98 requested review of this revision.Apr 1 2022, 7:51 PM
Herald added a project: Restricted Project. · View Herald TranscriptApr 1 2022, 7:51 PM

I don't know much about this specific bit of code, but a comment in ReplaceUsesOfBlockWith mentions that it's expected that 'Old' is a successor of 'this' so the fix looks reasonable. However, could you also add a test for this?

llvm/lib/Target/ARM/ARMFrameLowering.cpp
2564–2569

I think this would be a bit clearer if rewritten as

if (MBB->isSuccessor(&PrologueMBB))
  MBB->ReplaceUsesOfBlockWith(&PrologueMBB, AddedBlocks[0]);

i.e. the test and action are both MBB->thing(&PrologueMBB).

I would like to add a test, but I do not know how. My understanding is that I will need to create an example that PrologueMBB has non-immediate predecessors. Is there any example I can follow? Thanks!

I would like to add a test, but I do not know how. My understanding is that I will need to create an example that PrologueMBB has non-immediate predecessors. Is there any example I can follow? Thanks!

It may be easiest to start with the original file they you saw the segfault. Adding "--emit llvm-ir" to the rustc command-line will cause a .ll file to be produced, then doing "bugpoint -run-llc file.ll" should hopefully reduce that down to a simple test case.

ZhiyaoMa98 added a comment.EditedApr 29 2022, 9:33 AM

I successfully reproduced the segfault by llc -relocation-model=ropi-rwpi large_llvm_ir.ll
I need to pass the -relocation-model=ropi-rwpi flag to bugpoint, any hint on this?

Edit: it seems to be --tool-args, trying this now.

Added tests. Before fix it segfaults on the new tests. After fix it just runs through.

ZhiyaoMa98 marked an inline comment as done.

Addressed inline comment to make the code more readable.

I don't have commit access. Please credit me as follows if everything looks good. Thanks.
Name: Zhiyao Ma
Email: zhiyao.ma.98@gmail.com

john.brawn accepted this revision.May 3 2022, 4:36 AM

Looks good, I'll commit this for you.

This revision is now accepted and ready to land.May 3 2022, 4:36 AM
This revision was landed with ongoing or failed builds.May 3 2022, 4:42 AM
This revision was automatically updated to reflect the committed changes.