llvm - 如何用我的语言实现打印功能?
llvm - How to implement print function in my language?
我正在关注 llvm 的教程,了解他们自己的简单编程语言 "Kaleidoscope",并且在我的语言中有一个明显的功能,本教程似乎没有涵盖。我只是想像 C++ 那样将任何 double 打印到标准输出:
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)
?
您首先检查是否 Callee == "print"
然后插入任何您想要的指令。
LLVM IR 没有 "printing" 的概念,因为这不是真正的语言考虑——它是由 OS 提供的工具。对您来说,最简单的选择可能是将调用转换为对 printf
的调用,例如print(5.0)
变成 printf("%f\n", 5.0)
.
您链接的教程确实展示了外部函数调用的工作原理——您必须使用正确的签名为 printf
插入一个声明,然后构建一个调用。
下面是为 printf("%f", a) 生成的 llvm ir 代码;使用铿锵声。 printf 签名是 int printf(const char*, ...);
@.str = private unnamed_addr constant [3 x i8] c"%f[=10=]", 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");
我正在关注 llvm 的教程,了解他们自己的简单编程语言 "Kaleidoscope",并且在我的语言中有一个明显的功能,本教程似乎没有涵盖。我只是想像 C++ 那样将任何 double 打印到标准输出:
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)
?
您首先检查是否 Callee == "print"
然后插入任何您想要的指令。
LLVM IR 没有 "printing" 的概念,因为这不是真正的语言考虑——它是由 OS 提供的工具。对您来说,最简单的选择可能是将调用转换为对 printf
的调用,例如print(5.0)
变成 printf("%f\n", 5.0)
.
您链接的教程确实展示了外部函数调用的工作原理——您必须使用正确的签名为 printf
插入一个声明,然后构建一个调用。
下面是为 printf("%f", a) 生成的 llvm ir 代码;使用铿锵声。 printf 签名是 int printf(const char*, ...);
@.str = private unnamed_addr constant [3 x i8] c"%f[=10=]", 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");