How to properly insert a function call in an MachineFunction Pass

Hi all,

I want to know what is the proper way to insert a function call (particulary, RISCV PseudoCALL) in an MachineFunction Pass. I have tried instrumenting in the IR layer, using a FunctionPass, and it works well, because in the IR the function call is built using the class FuctionType.

Unfortunately, I want to insert function calls before certain assembly depending on its encoding. Therefore, I tried BuildMI and append an ExternalSymbol Operand to the created MI, and the ExternalSymbol is initialized with the function name to be call.

MachineInstrBuilder call = BuildMI(MBB,MI,MI->getDebugLoc(),ST.getInstrInfo()->get(RISCV::PseudoCALL));
ExternalSymbol Sym = MachineOperand::CreateES("my_function");

llc geneates seem-to-be-fine assembly file, but cannnot generate linkable file(.o). And the error was

unsupported relocation type

I browse about the llvm-mc and guess the issue is caused by a missing “fixup”?
When printing out the IR after instr selection, I have also notice the difference between the “normal” PseudoCALL generated from IR and the call that I have inserted by a pass.

; normal call generated from IR
PseudoCALL target-flags{riscv-call} @normal_call, <regmask $x1 $x3 $x4 ... $x27 $f8_f ... $f27_f $f9_h ... $f21_h and 6 more>, implicit def dead $x1, $implicit $x10, $implicit def $x2
; my inserted call, seems to use a same syntax as inline asm, so that is absolutely wrong
PseudoCALL &my_function , implicit def $x1

I have also tried add the function name as an MCSymbol, but still no luck.
Could you show me how to do this in the LLVM framework with the correct API?

Best Zhao

I am not sure I understand you perfectly, but I will show you what I have done.

  FunctionCallee getLogFunc(LLVMContext &Ctx, Function &F, Type *stateType, std::string rtFuncName)
    // 函数参数:
    std::vector<Type *> paramTypes = {
        Type::getInt8PtrTy(Ctx), // filename
        Type::getInt32Ty(Ctx),   // line
        Type::getInt8PtrTy(Ctx), // name
        Type::getInt32Ty(Ctx),   // type
        Type::getInt32Ty(Ctx),   // int value
        Type::getInt32Ty(Ctx)   // int value
    // 函数返回值:
    Type *retType = Type::getVoidTy(Ctx);
    // 函数类型:
    FunctionType *logFuncType = FunctionType::get(retType, paramTypes, false);
    // 根据函数的名字获取该函数:
    FunctionCallee logFunc = F.getParent()->getOrInsertFunction(rtFuncName, logFuncType);
    return logFunc;

  void log_int_load(std::string filename, std::string varname, int type, LoadInst *inst,
                    BasicBlock &B, LLVMContext &Ctx)
    IRBuilder<> builder(inst);
    builder.SetInsertPoint(&B, ++builder.GetInsertPoint());

    Value *argfilename = builder.CreateGlobalString(filename);
    Value *argstr = builder.CreateGlobalString(varname);
    Value *argtype = ConstantInt::get(Type::getInt32Ty(Ctx), type);
    Value *argvalue = dyn_cast_or_null<Value>(inst); // state
    Value *argline = getLine(inst, Ctx);             //
    Value *argold = dyn_cast_or_null<Value>(inst);   // old state

    Value *args[] = {argfilename, argline, argstr, argtype, argvalue, argold};
    FunctionCallee logFunc = getLogFunc(Ctx, F, Type::getInt32Ty(Ctx), "logint");
    builder.CreateCall(logFunc, args);

and logint is defined in a .cpp file:

extern "C" void logint(char* filename, int line, char* name, int type, int state, int old_state) {
  // sth.