让我们以LLVM IR函数@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()
与其解决的问题相比,显得相对复杂。有没有更简单的解决方案?