yutopp's blog

サンドバッグになりたい

LLVM3.3 と VS11 で遊んでみた

リンカが完成していなくても話題のLLVMで遊びたいってワケ

環境: Windows 7(x64),VS Express 2012 for Desktop,LLVM3.3

LLVMをビルドし,C++から呼んでIRを吐かせるまでの記事.自分用メモ.
サクサクとやりたいので自分でやってみた方法を書きます.ほとんどドキュメント通りです.

VSでインストールするまでのドキュメント
http://llvm.org/docs/GettingStartedVS.html

1. LLVM3.3をダウンロード
http://llvm.org/releases/download.html#3.3
LLVM source code というやつ
自分はD:に展開した.ので,D:\llvm-3.3.src に LLVM が配置されている.

2. CMakeする
http://www.cmake.org/cmake/resources/software.html
より最新の CMake を持ってくる.
GUI の CMake を開き,ソースコードとバイナリの出力先を LLVM の配置パス(D:\llvm-3.3.src)にする.
で,Configure."Visual Studio 11" と "Use default native compilers" を選択.で Finish.
(makeにPythonが使われているが,この際に Python3.3 が選ばれるとconfigureに失敗する.
http://stackoverflow.com/questions/13772617/building-llvm-fails-with-empty-error-message
ので,自分はインストールしていた Python3.3 をアンインストールして,Python 2.7.5 を入れた.つらい.)
終わったら Generate し,LLVM が配置されたディレクトリに移動.

3. ビルドする
LLVM が配置されたディレクトリに LLVM.sln というファイルが出来ているので開く.で,開いたそのままの状態でビルドを始める.今回は,Win32 の Debug ビルド.
すこし時間がかかるので,その間にツイッターをしましょう.

特にトラブルも起きなかったので無事ビルドは終わり.


使ってみるゾ
適当なプロジェクトを作り,
インクルードパスは,D:\llvm-3.3.src\include
ライブラリパスは,D:\llvm-3.3.src\lib\Debug
に通す.このプロジェクトも,Win32 の Debug でビルドする.

サンプルプログラム
http://www.ibm.com/developerworks/jp/opensource/library/os-createcompilerllvm1/
を参考(丸パクリ)にした.LLVM の IR をダンプする.
MSVC(v110)でコンパイルエラーが発生するので,プロジェクトのプロパティ -> C/C++ -> コマンドライン に -D_SCL_SECURE_NO_WARNINGS を追加しちゃって下さい.

#include <vector>
#include <string>
#include <iostream>

#include "llvm/ADT/ArrayRef.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/IRBuilder.h"


int main()
{
    llvm::LLVMContext& context = llvm::getGlobalContext();
    std::shared_ptr<llvm::Module> const module = std::make_shared<llvm::Module>( "Bunchou", context );
    llvm::IRBuilder<> builder( context );

    llvm::FunctionType* const func_type = llvm::FunctionType::get( builder.getVoidTy(), false );
    llvm::Function* const main_func =
        llvm::Function::Create( func_type, llvm::Function::ExternalLinkage, "main", module.get() );
    llvm::BasicBlock* const entry = llvm::BasicBlock::Create( context, "entrypoint", main_func );
    builder.SetInsertPoint( entry );

    llvm::Value* const sintyoku_doudesuka = builder.CreateGlobalStringPtr( "進捗どうですか?\n" );

    std::vector<llvm::Type*> puts_args;
    puts_args.push_back( builder.getInt8Ty()->getPointerTo() );
    llvm::ArrayRef<llvm::Type*> args_ref( puts_args );

    llvm::FunctionType* const puts_type =
        llvm::FunctionType::get( builder.getInt32Ty(), args_ref, false );
    llvm::Constant* const puts_func = module->getOrInsertFunction( "puts", puts_type );

    builder.CreateCall( puts_func, sintyoku_doudesuka );
    builder.CreateRetVoid();

    module->dump();

    // wait
    { char c; std::cin >> c; }
}


//
//
#pragma comment( lib, "LLVMXCoreCodeGen.lib" )
#pragma comment( lib, "LLVMTableGen.lib" )
#pragma comment( lib, "LLVMSystemZCodeGen.lib" )
#pragma comment( lib, "LLVMSparcCodeGen.lib" )
//#pragma comment( lib, "LLVMPTXCodeGen.lib" )
#pragma comment( lib, "LLVMPowerPCCodeGen.lib" )
#pragma comment( lib, "LLVMMSP430CodeGen.lib" )
#pragma comment( lib, "LLVMMipsCodeGen.lib" )
#pragma comment( lib, "LLVMMCJIT.lib" )
#pragma comment( lib, "LLVMRuntimeDyld.lib" )
#pragma comment( lib, "LLVMObject.lib" )
#pragma comment( lib, "LLVMMCDisassembler.lib" )
#pragma comment( lib, "LLVMXCoreDesc.lib" )
#pragma comment( lib, "LLVMXCoreInfo.lib" )
#pragma comment( lib, "LLVMSystemZDesc.lib" )
#pragma comment( lib, "LLVMSystemZInfo.lib" )
#pragma comment( lib, "LLVMSparcDesc.lib" )
#pragma comment( lib, "LLVMSparcInfo.lib" )
#pragma comment( lib, "LLVMPowerPCDesc.lib" )
#pragma comment( lib, "LLVMPowerPCInfo.lib" )
#pragma comment( lib, "LLVMPowerPCAsmPrinter.lib" )
//#pragma comment( lib, "LLVMPTXDesc.lib" )
//#pragma comment( lib, "LLVMPTXInfo.lib" )
//#pragma comment( lib, "LLVMPTXAsmPrinter.lib" )
#pragma comment( lib, "LLVMMipsDesc.lib" )
#pragma comment( lib, "LLVMMipsInfo.lib" )
#pragma comment( lib, "LLVMMipsAsmPrinter.lib" )
#pragma comment( lib, "LLVMMSP430Desc.lib" )
#pragma comment( lib, "LLVMMSP430Info.lib" )
#pragma comment( lib, "LLVMMSP430AsmPrinter.lib" )
#pragma comment( lib, "LLVMMBlazeDisassembler.lib" )
#pragma comment( lib, "LLVMMBlazeAsmParser.lib" )
#pragma comment( lib, "LLVMMBlazeCodeGen.lib" )
#pragma comment( lib, "LLVMMBlazeDesc.lib" )
#pragma comment( lib, "LLVMMBlazeAsmPrinter.lib" )
#pragma comment( lib, "LLVMMBlazeInfo.lib" )
#pragma comment( lib, "LLVMLinker.lib" )
#pragma comment( lib, "LLVMipo.lib" )
#pragma comment( lib, "LLVMInterpreter.lib" )
#pragma comment( lib, "LLVMInstrumentation.lib" )
#pragma comment( lib, "LLVMJIT.lib" )
#pragma comment( lib, "LLVMExecutionEngine.lib" )
#pragma comment( lib, "LLVMDebugInfo.lib" )
//#pragma comment( lib, "LLVMCppBackend.lib" )
//#pragma comment( lib, "LLVMCppBackendInfo.lib" )
//#pragma comment( lib, "LLVMCellSPUCodeGen.lib" )
//#pragma comment( lib, "LLVMCellSPUDesc.lib" )
//#pragma comment( lib, "LLVMCellSPUInfo.lib" )
//#pragma comment( lib, "LLVMCBackend.lib" )
//#pragma comment( lib, "LLVMCBackendInfo.lib" )
//#pragma comment( lib, "LLVMBlackfinCodeGen.lib" )
//#pragma comment( lib, "LLVMBlackfinDesc.lib" )
//#pragma comment( lib, "LLVMBlackfinInfo.lib" )
#pragma comment( lib, "LLVMBitWriter.lib" )
#pragma comment( lib, "LLVMX86Disassembler.lib" )
#pragma comment( lib, "LLVMX86AsmParser.lib" )
#pragma comment( lib, "LLVMX86CodeGen.lib" )
#pragma comment( lib, "LLVMX86Desc.lib" )
#pragma comment( lib, "LLVMX86AsmPrinter.lib" )
#pragma comment( lib, "LLVMX86Utils.lib" )
#pragma comment( lib, "LLVMX86Info.lib" )
#pragma comment( lib, "LLVMAsmParser.lib" )
#pragma comment( lib, "LLVMARMDisassembler.lib" )
#pragma comment( lib, "LLVMARMAsmParser.lib" )
#pragma comment( lib, "LLVMARMCodeGen.lib" )
#pragma comment( lib, "LLVMARMDesc.lib" )
#pragma comment( lib, "LLVMARMAsmPrinter.lib" )
#pragma comment( lib, "LLVMARMInfo.lib" )
#pragma comment( lib, "LLVMArchive.lib" )
#pragma comment( lib, "LLVMBitReader.lib" )
//#pragma comment( lib, "LLVMAlphaCodeGen.lib" )
#pragma comment( lib, "LLVMSelectionDAG.lib" )
#pragma comment( lib, "LLVMAsmPrinter.lib" )
#pragma comment( lib, "LLVMMCParser.lib" )
#pragma comment( lib, "LLVMCodeGen.lib" )
#pragma comment( lib, "LLVMScalarOpts.lib" )
#pragma comment( lib, "LLVMInstCombine.lib" )
#pragma comment( lib, "LLVMTransformUtils.lib" )
#pragma comment( lib, "LLVMipa.lib" )
#pragma comment( lib, "LLVMAnalysis.lib" )
#pragma comment( lib, "LLVMTarget.lib" )
#pragma comment( lib, "LLVMCore.lib" )
//#pragma comment( lib, "LLVMAlphaDesc.lib" )
//#pragma comment( lib, "LLVMAlphaInfo.lib" )
#pragma comment( lib, "LLVMMC.lib" )
#pragma comment( lib, "LLVMSupport.lib" )

実行すると,以下のようなIRが生成されます.

; ModuleID = 'Bunchou'

@0 = private unnamed_addr constant [18 x i8] c"\90i\92\BB\82\C7\82\A4\82\C5\82\B7\82\A9\81H\0A\00"

define void @main() {
entrypoint:
  %0 = call i32 @puts(i8* getelementptr inbounds ([18 x i8]* @0, i32 0, i32 0))
  ret void
}

declare i32 @puts(i8*)

ではでは,実行してみます.
LLVM を展開したディレクトリ(D:\llvm-3.3.src)の bin\Debug に lli.exe という物がある.これに生成したIRを食わせると実行してくれるようなのでやってみましょう.


f:id:yutopp:20130910001113p:plain

ヤッター,動きました!進捗ありました!


IRから実行形式にするには
http://stackoverflow.com/questions/13928250/how-to-save-ir-to-a-file-and-build-it-to-an-executable-file


さあ文鳥言語に組み込もうっと.