我正在关注自己的简单编程语言“Kaleidoscope”的llvm教程,并且我的语言中有一个明显的功能,本教程似乎没有涵盖这些功能。我只想将任何双倍打印到标准输出,就像C ++一样:
std::cout << 5.0;
我的语言会像
那样print(5.0);
Third chapter of llvm's tutorial涵盖函数调用。他们使用的代码是:
Value *CallExprAST::codegen() {
// Look up the name in the global module table.
Function *CalleeF = TheModule->getFunction(Callee);
if (!CalleeF)
return ErrorV("Unknown function referenced");
// If argument mismatch error.
if (CalleeF->arg_size() != Args.size())
return ErrorV("Incorrect # arguments passed");
std::vector<Value *> ArgsV;
for (unsigned i = 0, e = Args.size(); i != e; ++i) {
ArgsV.push_back(Args[i]->codegen());
if (!ArgsV.back())
return nullptr;
}
return Builder.CreateCall(CalleeF, ArgsV, "calltmp");
}
如何为特定函数调用codegen()
实现print(any fp number)
方法?
答案 0 :(得分:3)
下面是为printf生成的llvm ir代码(“%f”,a);用clang。 printf签名是int printf(const char *,...);
@.str = private unnamed_addr constant [3 x i8] c"%f\00", align 1
; Function Attrs: nounwind uwtable
define i32 @main() #0 {
%a = alloca double, align 8
%1 = load double* %a, align 8
%2 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([3 x i8]* @.str, i32 0, i32 0), double %1)
ret i32 0
}
declare i32 @printf(i8*, ...) #1
要在codegen中实现,首先需要检查函数是否已经存在于模块中。如果没有那么你需要添加声明,你可以在一个电话中同时进行。
Function *CalleeF = TheModule->getOrInsertFunction("printf",
FunctionType::get(IntegerType::getInt32Ty(Context), PointerType::get(Type::getInt8Ty(Context), 0), true /* this is var arg func type*/)
);
上面的将获取或添加函数声明的句柄
declare i32 @printf(i8*, ...) #1
然后你可以通过匹配参数来调用函数。
std::vector<Value *> ArgsV;
for (unsigned i = 0, e = Args.size(); i != e; ++i)
ArgsV.push_back(Args[i]->codegen());
return Builder.CreateCall(CalleeF, ArgsV, "printfCall");
答案 1 :(得分:2)
您首先检查Callee == "print"
是否然后插入所需的任何说明。
LLVM IR没有“打印”概念,因为它不是真正的语言考虑因素 - 它是操作系统提供的工具。对您而言,最简单的选择可能是将来电转换为对printf
的调用,例如print(5.0)
变为printf("%f\n", 5.0)
。
您链接的教程确实显示了外部函数调用的工作原理 - 您必须使用正确的签名插入printf
的声明,然后构建对该函数的调用。