LLVM:如何将内存调用替换为通过堆栈传递参数的函数调用?

时间:2017-12-01 16:49:57

标签: c++ llvm llvm-ir

这是我的初始代码,它不按我想要的方式工作,但我有点遇到障碍,不知道如何继续进行。 所以,基本上我想用内存操作数捕获一个尾调用,然后创建一个新函数“__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推送到堆栈?

提前致谢。

0 个答案:

没有答案