Tutorial 続き
Tutorial の例には main が無いため、せっかく生成した llvm のコードの断片を実行できない。
main を足した版。※私のC++ 知識は入門以下レベルなので、決して真似しないこと。
コンパイルして実行ファイル tut2 を作り、
c++ -g tut2.cpp `/usr/local/bin/llvm-config --cxxflags --ldflags --libs core` -o tut2
実行すると llvm ir を出力する。以下は tut2 10 3 7 を実行したもの。llvm の関数 mul_add に 10, 3, 7 を渡し、結果を返す。この例では 10 * 3 + 7 = 37 を返す。パイプで llvm-as, lli をつなぐとステータスとして 37 が確認できる。
./tut2 10 3 7 | llvm-as | lli echo $? 37
tut2 が出力するllvm のコード。
; ModuleID = 'tut2'
define i32 @mul_add(i32 %x, i32 %y, i32 %z) {
entry:
%tmp = mul i32 %x, %y ;[#uses=1]
%tmp2 = add i32 %tmp, %z ;[#uses=1]
ret i32 %tmp2
}define i32 @main() {
entry:
%tmp = call i32 @mul_add(i32 10, i32 3, i32 7) ;[#uses=1]
ret i32 %tmp
}
ちょっとllvm を思い出すために脱線。llvm の最適化(opt)を掛けて disassemble する(llvm-dis)とこのくらいの簡単なコードは完全に定数になってしまうのだった。
./tut2 10 3 7 | llvm-as | opt -std-compile-opts | llvm-dis
; ModuleID = '<stdin>' define i32 @mul_add(i32 %x, i32 %y, i32 %z) nounwind readnone { entry: %tmp = mul i32 %y, %x ; <i32> [#uses=1] %tmp2 = add i32 %tmp, %z ; <i32> [#uses=1] ret i32 %tmp2 } define i32 @main() nounwind readnone { entry: ret i32 37 }
恐らくこの最適化も、わざわざ llvm ir を出力せず、tut2.cpp の内部で実行できるはず。
tut2.cpp
#include "llvm/Module.h" #include "llvm/Function.h" #include "llvm/PassManager.h" #include "llvm/CallingConv.h" #include "llvm/Analysis/Verifier.h" #include "llvm/Assembly/PrintModulePass.h" #include "llvm/Support/IRBuilder.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; Module* makeLLVMModule(); void addMain(Module* mod, int x, int y, int z); int main(int argc, char**argv) { Module* Mod = makeLLVMModule(); if (argc != 4) { cerr << "Usage: tut2 x y z\n"; return 1; } addMain(Mod, atoi(argv[1]), atoi(argv[2]), atoi(argv[3])); verifyModule(*Mod, PrintMessageAction); PassManager PM; PM.add(createPrintModulePass(&outs())); PM.run(*Mod); delete Mod; return 0; } void addMain(Module* mod, int x, int y, int z) { Constant* cmain = mod->getOrInsertFunction("main", IntegerType::get(32), NULL); Function* main = cast<Function>(cmain); main->setCallingConv(CallingConv::C); BasicBlock* block = BasicBlock::Create("entry", main); IRBuilder<> builder(block); std::vector<Value*> args1; args1.push_back(ConstantInt::get(Type::Int32Ty, x)); args1.push_back(ConstantInt::get(Type::Int32Ty, y)); args1.push_back(ConstantInt::get(Type::Int32Ty, z)); // get mul_add fuction Constant* c = mod->getOrInsertFunction("mul_add", IntegerType::get(32), IntegerType::get(32), IntegerType::get(32), IntegerType::get(32), NULL); Function* mul_add = cast<Function>(c); Value* ret = builder.CreateCall(mul_add, args1.begin(), args1.end(), "tmp"); builder.CreateRet(ret); } Module* makeLLVMModule() { Module* mod = new Module("tut2"); Constant* c = mod->getOrInsertFunction("mul_add", /*ret type*/ IntegerType::get(32), /*args*/ IntegerType::get(32), IntegerType::get(32), IntegerType::get(32), /*varargs terminated with null*/ NULL); Function* mul_add = cast<Function>(c); mul_add->setCallingConv(CallingConv::C); Function::arg_iterator args = mul_add->arg_begin(); Value* x = args++; x->setName("x"); Value* y = args++; y->setName("y"); Value* z = args++; z->setName("z"); BasicBlock* block = BasicBlock::Create("entry", mul_add); IRBuilder<> builder(block); Value* tmp = builder.CreateBinOp(Instruction::Mul, x, y, "tmp"); Value* tmp2 = builder.CreateBinOp(Instruction::Add, tmp, z, "tmp2"); builder.CreateRet(tmp2); return mod; }