【问题标题】:How to insert a basic block between two block in LLVM如何在 LLVM 中的两个块之间插入一个基本块
【发布时间】:2020-06-16 05:55:45
【问题描述】:

这与Inserting a block between two blocks in LLVM 类似,但我不清楚解决方案描述 - 或者更好 - 我尝试按照描述的方式进行操作,但它不起作用(对我而言)。

我想做什么: 无论一个基本块有多于一个后继者,我都想插入一个基本块。 所以如果基本块A有条件跳转到B或C,我想在A和B之间以及A和C之间插入一个基本块。如果有跳转表,它也应该工作。

所以我要做的是:

while (...) {
  // get next basic block and ensure it has at least 2 successors:
  BasicBlock *origBB = getNextBB();
  Instruction *TI = origBB->getTerminator()
  if (!TI || TI->getNumSuccessors() < 2)
    continue;

  // collect successors:
  std::vector<BasicBlock *> Successors;
  for (succ_iterator SI = succ_begin(origBB), SE = succ_end(origBB); SI != SE; ++SI) {
     BasicBlock *succ = *SI;
     Successors.push_back(succ);
  }

  // now for each successor:
  for (uint32_t i = 0; i < Successors.size(); i++) {
    // Create a new basic block
    BasicBlock *BB = BasicBlock::Create(C, "", &F, nullptr);
    // F.getBasicBlockList().push_back(BB); <= this did not work, seem to result in endless loop
    IRBuilder<> IRB(BB);
    // put instructions into BB
    ... // omitted
    // then add the terminator:
    IRB.CreateBr(Successors[i]);

    // Now we have to fix the original BB to our new basic block:
    TI->setSuccessor(i, BB);
  }
}

当我运行这个 LLVM 通道时,我收到以下错误: PHI node entries do not match predecessors!

好的,所以我想我必须从后继者中删除相应的前任,并在 setSuccessor() 之后添加以下代码:

origBB->replaceSuccessorsPhiUsesWith(Successors[j], BB);
BasicBlock *S = Successors[i];
S->removePredecessor(origBB);

然后我得到错误Instruction does not dominate all uses!

我确信解决方案非常简单 - 但我找不到它:-(

非常感谢任何帮助或指点!

【问题讨论】:

  • Phi 节点问题可以通过查看 SI 中的 phi 节点来解决,如果有引用 origBB,则让它们引用 BB。或者您可以使用llvm::splitBlock(succ),它会为您处理几乎所有事情。
  • 如何查看后继节点的 phi 节点?以及如何纠正它们?我需要一个指向函数调用的指针:)。我不能使用 splitBlock(我认为),因为它不是拆分块,而是将块插入到不同的边缘。
  • 您可以在 splitBlock() 中查看如何更正 phi 节点的示例。

标签: llvm llvm-ir


【解决方案1】:

好的,我在这里回答我自己的问题。

建议 a) 使用 splitBlock() 的评论进入了错误的方向,因为它是关于插入边缘,所以结果是错误的。 b) 更新 phi 实际上可以解决问题。然而,这是非常复杂的,因为不能使用简单的replacePhiUsesWith - A->B 和 A 是循环头而 B 是循环尾的情况(所以回到 B)将导致编译错误,所以所有 phi必须仔细评估。

所以解决方法其实很简单,浏览llvm的源码发现:SplitEdge()。它完全符合我的要求,在两个基本块的边缘之间插入一个基本块!

由于该函数没有记录在 doxygen 类列表中,因此并不明显,因此除了通过浏览源和包含之外找不到它。

那么这里如何使用它:

#include "llvm/Transforms/Utils/BasicBlockUtils.h"

void inYourFunction() {

   ...
   // Insert the new block into the edge between thisBB and a successorBB
   BasicBlock *insertedBB = SplitEdge(thisBB, successorBB);
   if (!insertedBB) {
     // SplitEdge can fail, e.g. if the successor is a landing pad
     return;
   }
   // Then put instructions into the new BB
   BasicBlock::iterator IP = newBB->getFirstInsertionPt();
   IRBuilder<>          IRB(&(*IP));
   // and then work with IRB
   // You need not to take care of the branch to successorBB - it is already there
   ...

}

就是这样,就这么简单。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-25
    • 1970-01-01
    • 2020-04-24
    相关资源
    最近更新 更多