Давайте рассмотрим пример функции IR LLVM @example_before()
.
define void @example_before(i32 %x, i32 %y) {
%a = and i32 %x, 65535
%b = lshr i32 %x, 16
%c = and i32 %y, 65535
%d = lshr i32 %y, 16
ret void
}
Используя LLVM C ++ API, цель состоит в том, чтобы вставить новую двоичную инструкцию сразу после обоих ее аргументов.Т.е. сразу после аргумента, который появляется в функции позже, чем другой аргумент.
В этом примере рассмотрим регистры %a
и %c
.Мы хотим вставить %z = mul i32 %a, %c
.Конечный результат должен выглядеть следующим образом: @example_after()
.
define void @example_after(i32 %x, i32 %y) {
%a = and i32 %x, 65535
%b = lshr i32 %x, 16
%c = and i32 %y, 65535
%z = mul i32 %a, %c
%d = lshr i32 %y, 16
ret void
}
Чтобы решить проблему, я получил вспомогательную функцию, которая находит инструкцию сразу после двух, представленных в качестве аргументов.Для этой функции также требуется DominatorTree
.
/// Finds the first instruction after both A and B.
/// A and B are assumed to be either Instruction or Argument.
Instruction *getInstructionAfter(Value *A, Value *B, DominatorTree &DT) {
Instruction *I = nullptr;
if (auto AI = dyn_cast<Instruction>(A))
I = AI->getNextNode();
else // If Argument use the first instruction in the entry block.
I = &cast<Argument>(A)->getParent()->front().front();
auto BI = dyn_cast<Instruction>(B);
if (BI && DT.dominates(I, BI))
I = BI->getNextNode(); // After B.
return I;
}
Выход getInstructionAfter()
может быть легко использован в качестве точки вставки новой инструкции.
IRBuilder<> Builder{getInstructionAfter(X, Y, DT)};
return Builder.CreateMul(X, Y);
Однако getInstructionAfter()
выглядит относительно сложным по сравнению с проблемой, которую он решает.Есть ли более простые решения для этого?