Как вставить блок basi c между двумя блоками в LLVM - PullRequest
1 голос
/ 03 марта 2020

Это похоже на Вставка блока между двумя блоками в LLVM , однако описание решения мне неясно - или лучше - я пытался сделать это, как описано, но это не работает (для меня).

Что я хочу сделать: где бы у блока basi c было более одного преемника, я хочу вставить блок basi c. Поэтому, если базовый c блок A выполняет условный переход к B или C, я хочу вставить базовый 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!

Я уверен, что решение очень простое - но я не могу его найти: - (

Большое спасибо за любую помощь или указатели!

1 Ответ

0 голосов
/ 04 марта 2020

ОК. Здесь я задаю свой вопрос.

Комментарий, предлагающий a) использование splitBlock (), идет в неправильном направлении, так как он касается вставки в ребро, поэтому результат будет неправильным. б) обновление фи на самом деле решит проблему. Однако это очень сложно, так как простой replacePhiUsesWith не может быть использован - случай, когда A-> B и A - это всего лишь oop голова, а B - хвост петли (возвращаясь к B), приведет к ошибке компиляции, поэтому все phis должны быть тщательно оценены.

Таким образом, решение на самом деле очень простое, которое я нашел, просматривая исходный код llvm: SplitEdge (). Он делает именно то, что мне нужно, вставляя блок c между ребром двух блоков c!

Это не очевидно, так как функция не задокументирована в списке классов 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
   ...

}

Вот так, это так просто.

...