这是我的初始代码,它不按我想要的方式工作,但我有点遇到障碍,不知道如何继续进行。 所以,基本上我想用内存操作数捕获一个尾调用,然后创建一个新函数“__newfunc”,将内存操作数(它将在__newfunc中使用)放到堆栈中,并将初始调用替换为“__newfunc”调用。 / p>
for (auto &BB: F)
for (auto &I: BB) {
if(CallInst *CI = dyn_cast<CallInst>(&I))
// this check is not enough
if(CI->isTailCall()) {
LLVMContext &C = TheModule->getContext();
AttributeList A;
A = A.addAttribute(C, AttributeList::FunctionIndex,
Attribute::OptimizeNone);
A = A.addAttribute(C, AttributeList::FunctionIndex,
Attribute::NoInline);
A = A.addAttribute(C, AttributeList::FunctionIndex,
Attribute::NoUnwind);
SmallVector<Type *, 3> ParamTys;
for (unsigned i = 0; i < CI->getNumArgOperands(); i++)
ParamTys.push_back(CI->getArgOperand(i)->getType());
FunctionType* newFuncType =
FunctionType::get(CI->getType(), ParamTys, false);
Function *newFunc =
dyn_cast<Function>(TheModule->getOrInsertFunction(
"__newfunc", newFuncType, A));
BasicBlock *NewRetBlock = BasicBlock::Create(F.getContext(), "DDD", newFunc);
ReturnInst::Create(newFunc->getContext(), nullptr, NewRetBlock);
CI->setCalledFunction(newFunc);
}
}
}
在上面的代码中,我找到了一个尾调用(我还没有检查内存操作数,但现在不重要),然后使用初始调用具有的参数创建一个新函数并替换该调用。 (在新函数中创建“返回”是为了避免DCE删除新函数。) 以下是我在创建新函数后但在替换之前所拥有的内容。
; Function Attrs: nounwind uwtable
define void @foo(i64 %offset) local_unnamed_addr #0 {
entry:
%0 = load void (i64)*, void (i64)** @dispatch, align 8, !tbaa !2
tail call void %0(i64 %offset) #2
ret void
}
; Function Attrs: noinline nounwind optnone
define void @__newfunc(i64) #1 {
DDD:
ret void
}
替换后我有以下IR。看起来我丢失了load
。因此,它只生成对新函数的调用,但会丢失参数。
; Function Attrs: nounwind uwtable
define void @foo(i64 %offset) local_unnamed_addr #0 {
entry:
%0 = load void (i64)*, void (i64)** @dispatch, align 8, !tbaa !2
tail call void @__newfunc(i64 %offset) #2
ret void
}
...
所以我试图找到一种方法让它发挥作用。我假设我需要在__newfunc上设置特殊的调用约定,因为它应该只通过堆栈接受参数,但我不知道如何做到这一点。另外,如何在调用新指令之前将@dispatch推送到堆栈?
提前致谢。