如何在llvm中更改Callinst中的操作数类型?

如何在llvm中更改Callinst中的操作数类型?,llvm,Llvm,我正在尝试实现CallInst的转换,并执行以下操作: 更改函数调用参数的类型 更改返回值的类型 例如,我想更改以下IR: %call = call double @add(double %0, double %1) define double @add(double %x, double %y) #0 { entry: %x.addr = alloca double, align 8 %y.addr = alloca double, align

我正在尝试实现CallInst的转换,并执行以下操作:

  • 更改函数调用参数的类型

  • 更改返回值的类型

  • 例如,我想更改以下IR:

        %call = call double @add(double %0, double %1)
    
        define double @add(double %x, double %y) #0 {
        entry:
          %x.addr = alloca double, align 8
          %y.addr = alloca double, align 8
          store double %x, double* %x.addr, align 8
          store double %y, double* %y.addr, align 8
          %0 = load double, double* %x.addr, align 8
          %1 = load double, double* %x.addr, align 8
          %add = fadd double %0, %1
          ret double %add
        }
    
    要更新,请执行以下操作:

        %call = call x86_fp80 @new_add(x86_fp80 %0, x86_fp80 %1)
    
        define x86_fp80 @new_add(x86_fp80 %x, x86_fp80 %y) #0 {
        entry:
          %x.addr = alloca x86_fp80, align 16
          %y.addr = alloca x86_fp80, align 16
          store x86_fp80 %x, x86_fp80* %x.addr, align 16
          store x86_fp80 %y, x86_fp80* %y.addr, align 16
          %0 = load x86_fp80, x86_fp80* %x.addr, align 16
          %1 = load x86_fp80, x86_fp80* %x.addr, align 16
          %add = fadd x86_fp80 %0, %1
          ret x86_fp80 %add
        }
    
    我已经完成了AllocaInst、StoreInst、LoadInst、BinaryOperator和ReturnInst的类型更改

    我现在很困惑如何对付卡林斯特

    我最初的想法是迭代所有指令时,如果我找到一个CallInst

       if (CallInst *call = dyn_cast<CallInst>(it)){
    
    使用

  • 使用从步骤2中获得的新函数构造一个新的CallInst

    CallInst *new_call = CallInst::Create(new_fun, *arrayRefOperands, "newCall", call);
    new_call->takeName(call);
    }
    
  • 然而,通过这种方式,我得到了以下IR,而不是我想要的新IR:

       %call = call x86_fp80 (x86_fp80, x86_fp80, ...) @0(x86_fp80 %5, x86_fp80 %7)
    
       declare x86_fp80 @new_add(x86_fp80, x86_fp80, ...)
    
    已构造被调用函数的新定义(声明x86_fp80@new_add(x86_fp80,x86_fp80,…),但此新函数的主体为空。我很困惑如何添加身体和得到新的我想要的。我天真的想法是:

       for (Instruction i : called function(add in the example)){
           create new_i with type x86_fp80;
           insert new_i in the new function constructed(new_add in the example);
         }   
    
    这是实现我目标的好方法吗


    任何建议都将不胜感激:)

    如果您不再在其他地方使用原始函数,您可以使用llvm::Value::mutateType(llvm::Ty)将double type Value更改为x86_fp80。 使用CallInst->getCalledFunction()转到函数定义,并迭代所有值,然后将双精度类型变为x86_fp80


    参考:非常感谢您的回答。然而,据说直接突变基因型是非常危险的。因此,在我的代码中,我用我想要的新类型创建了一个新函数。这不管用吗?我认为我的问题在于如何创建新函数的主体,对吗?如果有一个优雅的方法可以做到这一点,你能给我一些建议吗?非常感谢:)您还可以使用llvm::CloneFunction(const llvm::Function,ValueToValueMapTy*)这不会将函数添加到当前模块中,您可以使用clone->setname(string)设置返回函数名称,然后使用module->getFunctionList()->push_bask(clone)将其添加到当前模块函数列表中,此处ValueToValueMapTy用于引用,以指定在克隆函数中更改的映射。有关更多信息,请参阅(参考:)CloneFunction的其他变体。您可以根据需要使用它们。我在答案中尝试了您的方法,但它会导致返回类型和操作数类型的运行时错误不容易匹配。例如,将函数foo double foo(double x){double y=x;return y;}的类型变异有两个步骤,1)使用mutateType()将foo的声明变异为long double(long double x);2)将函数体中的返回指令变异为long double无论我先执行步骤1)还是步骤2),首先都会出现核心转储错误。因为两个步骤必须在一个语句中完成,才能使类型匹配。非常感谢您的耐心。我对克隆函数法有一个疑问。你是说我需要在克隆函数上进行类型变异吗?顺便问一下,你认为我在文章末尾的想法是什么?非常感谢:)
    CallInst *new_call = CallInst::Create(new_fun, *arrayRefOperands, "newCall", call);
    new_call->takeName(call);
    }
    
       %call = call x86_fp80 (x86_fp80, x86_fp80, ...) @0(x86_fp80 %5, x86_fp80 %7)
    
       declare x86_fp80 @new_add(x86_fp80, x86_fp80, ...)
    
       for (Instruction i : called function(add in the example)){
           create new_i with type x86_fp80;
           insert new_i in the new function constructed(new_add in the example);
         }