$30 off During Our Annual Pro Sale. View Details »

計算グラフのJITコンパイラをLLVM on C++で作ろう

sonson
August 29, 2020

計算グラフのJITコンパイラをLLVM on C++で作ろう

iOSのメイン開発言語として盤石になってきたSwift.
そのSwiftを支える最も重要なコンポーネントがコンパイラ開発基盤LLVMです.
また,LLVMは,Swiftだけでなく,多くのソフトウェアにとって欠かすことができないソフトウェアとなってきました.
このトークでは,計算グラフをC++上で実装し,LLVMによるJITコンパイルで,動的にバイナリを生成し,内部的にそれを実行するソースをベースにLLVMの中身を解説します.
ほとんど解説書がなく,とっつきにくいLLVMではありますが,実際にコードを書いていくと,その技術のおもしろさが随所に感じられてきます.
LLVMを学び始めて,半年の初心者ならではの視点で,LLVMのおもしろさをお伝えできればと考えています.

みなさんも,LLVMにレッツトライ!

sonson

August 29, 2020
Tweet

More Decks by sonson

Other Decks in Programming

Transcript

  1. © 2020 Yuichi Yoshida. All rights reserved. Redistribution or public display not permitted without written permission from Yuichi Yoshida.
    ܭࢉάϥϑͷJITίϯύΠϥΛLLVM on C++Ͱ࡞Ζ͏
    #iOSDC2020
    Yuichi Yoshida
    Senior Researcher, DENSO IT Laboratory, Inc.

    View Slide

  2. ਺ΧॴͰQRίʔυͱURLͰϦϯΫΛషΓ·͢
    SpeakerDeck͔Β࠷৽ͷPDFΛμ΢ϯϩʔυͰ͖·͢ɽ
    ֤ιʔείʔυ΁ͷϦϯΫ͕Կ౓͔ग़͖ͯ·͕͢ɼPDFͳΒQRίʔυΛΫϦοΫͯ͠ඈ΂·͢ɽ
    ࠓ೔ͷࢿྉ
    https://speakerdeck.com/sonsongithub/ji-suan-gurahufalsejitkonpairawollvm-on-c-plus-plus-dezuo-rou

    View Slide

  3. • sonson
    • @sonson_twit
    • github.com/sonsongithub
    • iOS͸͍ͩͿݹࢀͷ͓ͬ͞ΜͰ͢
    • ຊ৬
    • DENSO IT Laboratory, Inc.
    • Research Engineer
    • ը૾ೝࣝɼը૾ݕࡧɼػցֶशɾɾɾͳͲ
    ࣗݾ঺հ
    https://github.com/sonsongithub/zipr
    SwiftͰॻ͍ͯΔ
    zipͰਬ͖ग़ͨ͠ը૾ϑΝΠϧϏϡʔΞ

    View Slide

  4. ࠓ೔ͷιʔείʔυͳͲ
    llvm.orgͷ೔ຊޠ༁Λ΍ͬͯΈͨϦϙδτϦ ࠓ೔঺հ͢Δίʔυશൠ
    https://github.com/sonsongithub/llvm-tutorial https://github.com/sonsongithub/llvm_jit_compile

    View Slide

  5. LLVM

    View Slide

  6. LLVM
    • ίϯύΠϥج൫
    • ίϯύΠϥΛ࡞ΔͨΊͷ࢓༷΍ιϑτ΢ΣΞ܈
    • C++, Python, GoͷΠϯλϑΣʔε͕ఏڙ͞Ε͍ͯΔ
    • ੲ͸ɼLow Level Virtual MachineͷུͩͬͨΒ͍͕͠ɼࠓ͸LLVM
    • ͨ͘͞Μͷιϑτ΢ΣΞ͕LLVMΛར༻͍ͯ͠Δ
    • Swift, Rust, Halide, Julia, clang, lldb…

    View Slide

  7. LLVMͰԿ͔࡞Δͱ͖ͷΠϝʔδʙΦϨΦϨݴޠ
    ΦϨΦϨݴޠ
    ιʔείʔυ
    --7.*3 1BTT όΠφϦ
    ίϯύΠϥ
    LLVMΛAPIΛ࢖ͬͯɼLLVM IRʹม׵͢Δ
    ΦϨΦϨݴޠͷύʔα͸ࣗ෼Ͱ࡞Δ
    C++, Go, PythonͰॻ͚Δ
    ৭ʑ༻ҙ͞Ε͍ͯΔ͠
    ࣗ෼Ͱ΋࡞ΕΔ
    x86ͷPassΛ࢖͑͹ɼx86ʹରԠͰ͖Δ
    armͷPassΛ࢖͑͹ɼar̼ʹରԠͰ͖Δ
    1BTT 1BTT

    View Slide

  8. Swiftͷ৔߹
    4XJGU
    ιʔείʔυ
    4*-
    ந৅ߏจ໦ ࠷దԽ --7.*3 όΠφϦ
    ɾɾɾɾɾ
    4XJGU*OUFSNFEJBUF-BOHVBHF

    View Slide

  9. LLVMͰԿ͔࡞Δͱ͖ͷΠϝʔδʙࠓճͷ৔߹
    ܭࢉάϥϑΞϓϦ
    --7.*3
    --7.
    ந৅ߏจ໦
    ܭࢉάϥϑ όΠφϦ

    View Slide

  10. LLVM IR

    View Slide

  11. LLVM IR
    • LLVMͷத֩ͱͳΔɼதؒදݱ
    • ΞηϯϒϦݴޠͬΆ͍ײ͡ͷදݱ
    • ʢ໋ྩʣʢಡΈग़͠ݩʣʢಡΈग़͠ݩʣʢॻ͖ࠐΈઌʣ
    • ແݶͷϨδελ͕͋Γɼܕ෇͚ݴޠɼSSA(Static Single Assignment)
    • ̏छྨͷ࢖͍ํ͕͋Δ
    • ςΩετܗࣜɾɾɾclangͱ͔Ͱग़ྗͰ͖Δ΍ͭɽhuman readable
    • ΠϯϝϞϦܗࣜɾɾɾɾࠓճͷΑ͏ͳϓϩάϥϜ্Ͱදݱ͞ΕΔ΋ͷ
    • bit codeܗࣜɾɾɾɾόΠφϦͰอ࣋ͯ͠ίϯύΫτͳ΍ͭ

    View Slide

  12. LLVM IRͷྫ
    double func2(double a, double b, double *p) {
    return a + b - *p;
    }
    define double @func2(double, double, double*) #0 {
    %4 = alloca double, align 8
    %5 = alloca double, align 8
    %6 = alloca double*, align 8
    store double %0, double* %4, align 8
    store double %1, double* %5, align 8
    store double* %2, double** %6, align 8
    %7 = load double, double* %4, align 8
    %8 = load double, double* %5, align 8
    %9 = fadd double %7, %8
    %10 = load double*, double** %6, align 8
    %11 = load double, double* %10, align 8
    %12 = fsub double %9, %11
    ret double %12
    }

    View Slide

  13. LLVM IRͷྫ
    double func2(double a, double b, double *p) {
    return a + b - *p;
    }
    define double @func2(double, double, double*) #0 {
    %4 = alloca double, align 8
    %5 = alloca double, align 8
    %6 = alloca double*, align 8
    store double %0, double* %4, align 8
    store double %1, double* %5, align 8
    store double* %2, double** %6, align 8
    %7 = load double, double* %4, align 8
    %8 = load double, double* %5, align 8
    %9 = fadd double %7, %8
    %10 = load double*, double** %6, align 8
    %11 = load double, double* %10, align 8
    %12 = fsub double %9, %11
    ret double %12
    }

    View Slide

  14. LLVM IRͷྫ
    double func2(double a, double b, double *p) {
    return a + b - *p;
    }
    define double @func2(double, double, double*) #0 {
    %4 = alloca double, align 8
    %5 = alloca double, align 8
    %6 = alloca double*, align 8
    store double %0, double* %4, align 8
    store double %1, double* %5, align 8
    store double* %2, double** %6, align 8
    %7 = load double, double* %4, align 8
    %8 = load double, double* %5, align 8
    %9 = fadd double %7, %8
    %10 = load double*, double** %6, align 8
    %11 = load double, double* %10, align 8
    %12 = fsub double %9, %11
    ret double %12
    }

    View Slide

  15. LLVM IRͷྫ
    double func2(double a, double b, double *p) {
    return a + b - *p;
    }
    define double @func2(double, double, double*) #0 {
    %4 = alloca double, align 8
    %5 = alloca double, align 8
    %6 = alloca double*, align 8
    store double %0, double* %4, align 8
    store double %1, double* %5, align 8
    store double* %2, double** %6, align 8
    %7 = load double, double* %4, align 8
    %8 = load double, double* %5, align 8
    %9 = fadd double %7, %8
    %10 = load double*, double** %6, align 8
    %11 = load double, double* %10, align 8
    %12 = fsub double %9, %11
    ret double %12
    }

    View Slide

  16. LLVM IRͷྫ
    double func2(double a, double b, double *p) {
    return a + b - *p;
    }
    define double @func2(double, double, double*) #0 {
    %4 = alloca double, align 8
    %5 = alloca double, align 8
    %6 = alloca double*, align 8
    store double %0, double* %4, align 8
    store double %1, double* %5, align 8
    store double* %2, double** %6, align 8
    %7 = load double, double* %4, align 8
    %8 = load double, double* %5, align 8
    %9 = fadd double %7, %8
    %10 = load double*, double** %6, align 8
    %11 = load double, double* %10, align 8
    %12 = fsub double %9, %11
    ret double %12
    }

    View Slide

  17. LLVM IRͷྫ
    double func2(double a, double b, double *p) {
    return a + b - *p;
    }
    define double @func2(double, double, double*) #0 {
    %4 = alloca double, align 8
    %5 = alloca double, align 8
    %6 = alloca double*, align 8
    store double %0, double* %4, align 8
    store double %1, double* %5, align 8
    store double* %2, double** %6, align 8
    %7 = load double, double* %4, align 8
    %8 = load double, double* %5, align 8
    %9 = fadd double %7, %8
    %10 = load double*, double** %6, align 8
    %11 = load double, double* %10, align 8
    %12 = fsub double %9, %11
    ret double %12
    }

    View Slide

  18. LLVM IRͷྫ
    double func2(double a, double b, double *p) {
    return a + b - *p;
    }
    define double @func2(double, double, double*) #0 {
    %4 = alloca double, align 8
    %5 = alloca double, align 8
    %6 = alloca double*, align 8
    store double %0, double* %4, align 8
    store double %1, double* %5, align 8
    store double* %2, double** %6, align 8
    %7 = load double, double* %4, align 8
    %8 = load double, double* %5, align 8
    %9 = fadd double %7, %8
    %10 = load double*, double** %6, align 8
    %11 = load double, double* %10, align 8
    %12 = fsub double %9, %11
    ret double %12
    }

    View Slide

  19. LLVM IRͷྫ
    double func2(double a, double b, double *p) {
    return a + b - *p;
    }
    define double @func2(double, double, double*) #0 {
    %4 = alloca double, align 8
    %5 = alloca double, align 8
    %6 = alloca double*, align 8
    store double %0, double* %4, align 8
    store double %1, double* %5, align 8
    store double* %2, double** %6, align 8
    %7 = load double, double* %4, align 8
    %8 = load double, double* %5, align 8
    %9 = fadd double %7, %8
    %10 = load double*, double** %6, align 8
    %11 = load double, double* %10, align 8
    %12 = fsub double %9, %11
    ret double %12
    }

    View Slide

  20. ܭࢉάϥϑ

    View Slide

  21. ܭࢉάϥϑɾɾɾ f(x, y, z) = sin(x) + y * log(z)
    double x = pi;
    double y = 1.0;
    double z = 0.1;
    float y = sin(x) + y * log(z);
    Var x, y, z;
    Func f;
    f(x, y, z) = sin(x) + y * log(z);
    double r = f(10, 1, 2);
    ී௨ʹ࣮૷ ܭࢉάϥϑͬΆ࣮͘૷

    View Slide

  22. ܭࢉάϥϑ
    Var x, y, z;
    Func f;
    f(x, y, z) = sin(x) + y * log(z);
    double r = f(10, 1, 2);
    ม਺ͱؔ਺Λͭͳ͍Ͱ
    ؔ਺Λ࡞Δײ͡
    Y
    Z
    [
    TJO
    MPH
    NVMUJQMZ
    BEE
    ࣮ߦ࣌ʹґଘؔ܎͕Θ͔Δ
    G
    ࣮ߦ࣌ʹ೚ҙͷม਺Ͱඍ෼ͨ͠Γɼґଘؔ܎Λ೺Ѳͨ͠ΓͰ͖Δ

    View Slide

  23. ྫɿHalide - ࠷దԽ
    C++ͷΈͰSIMDʹରԠ HalideͳΒɼ͜ΕͰSIMD/εϨου/GPUʹରԠ
    ܭࢉάϥϑͰදݱ͢Δ͜ͱͰɼґଘؔ܎౳͕໌֬ʹͳΔ
    Halide͸ɼͦΕΛ༻͍ͯɼϋʔυ΢ΣΞʹಈతʹ࠷దԽͨ͠όΠφϦΛLLVMܦ༝Ͱు͚Δ

    View Slide

  24. ࠓ೔ͷ໨ඪɿܭࢉάϥϑΛJITίϯύΠϧ͢Δ
    • LLVMͱLLVM IRΛͪΐͬͱཧղ͢Δ
    • C++ͰܭࢉάϥϑΛ࣮૷͢Δ
    • ܭࢉάϥϑ͔Βந৅ߏจ໦Λ࡞Δ
    • ந৅ߏจ໦ΛɼLLVMʹҾ͖౉͠ɼLLVM IRʹม׵͢Δ
    • ϞδϡʔϧΛίϯύΠϧ͠ɼؔ਺ϙΠϯλΛಘΔ
    • ܭࢉάϥϑ͔Βੜ੒ͨؔ͠਺Λ࣮ߦ͢Δ
    ※ͪͳΈʹܭࢉάϥϑࣗମ͸JITͰͳͯ͘΋࣮ݱͰ͖·͢

    View Slide

  25. ࠓ೔ͷίʔυͷ౔୆
    HalideͷαΠτ
    ܭࢉάϥϑͳͲ͸ɼ͜ͷιʔεͰษڧ
    llvm.org - Tutorial Kaleidoscope
    C++ͰΦϨΦϨݴޠΛ࡞ΔνϡʔτϦΞϧ
    https://llvm.org/docs/tutorial/MyFirstLanguageFrontend/index.html https://halide-lang.org

    View Slide

  26. LLVM API

    View Slide

  27. LLVMͷΠϯετʔϧ
    • macOS - brew, ιʔε͔ΒϏϧυ
    • Xcode͸಺แͷ΋ͷ͸͓͢͢Ί͠ͳ͍ɹྫɿllvm-config͕ͳ͍
    • Linux - ύοέʔδϚωʔδϟͰ͍ΕΕ͹͍͍
    • ubuntuͰ͸aptͰ͍Ε·ͨ͠
    • Windows - ஌Βͳ͍ɾɾɾɾ
    • ͢Μ·ͤΜ

    View Slide

  28. LLVMͰؔ਺Λ࡞ΔΠϝʔδ
    ܭࢉάϥϑΞϓϦ
    --7.*3
    --7.
    ந৅ߏจ໦
    ܭࢉάϥϑ όΠφϦ

    View Slide

  29. LLVMͰؔ਺Λ࡞ΔΠϝʔδ
    ܭࢉάϥϑΞϓϦ
    --7.*3ʢΠϯϝϞϦʣ
    --7.
    ந৅ߏจ໦
    ܭࢉάϥϑ όΠφϦ
    --7."1*
    ม਺ఆٛɼԋࢉɼ໭Γ஋ɾɾɾɾ
    ; ModuleID = 'originalModule'
    source_filename = "originalModule"
    define double @func(double %a, double %b) {
    entry:
    %addtmp = fadd double %a, %b
    ret double %addtmp
    }
    όΠφϦ
    ʢΦϒδΣΫτϑΝΠϧʁʣ
    llcͳͲͷπʔϧ
    ςΩετܗࣜͷLLVM IR

    View Slide

  30. γϯϓϧͳؔ਺ΛLLVMͰ࣮૷ͯ͠ΈΔ
    • ࣮૷͢Δؔ਺ a + b
    double func(double a, double b) {
    return a + b;
    }

    View Slide

  31. LLVMͰϓϩάϥϛϯά͢ΔΠϝʔδ

    View Slide

  32. ී௨ͷCͩͱ
    Ҿ਺ͳͲΛఆٛ͢Δ
    ؔ਺Λ࡞Δ
    ԋࢉ͢Δ
    ໭Γ஋Λఆٛ͢Δ
    ίϯύΠϧ͢Δ
    ࣮ߦ͢Δ
    (double a, double b)...
    double hoge (double a, double b)...
    a + b
    return a + b;
    clang hoge.cpp -o hoge
    hoge

    View Slide

  33. $ͷίʔυ
    LLVM APIͰؔ਺Λ࡞Δ
    Ҿ਺ͳͲΛఆٛ͢Δ
    ؔ਺Λ࡞Δ
    ԋࢉ͢Δ
    ໭Γ஋Λఆٛ͢Δ
    ίϯύΠϧ͢Δ
    ࣮ߦ͢Δ
    llvm::FunctionType::get(Type::getDoubleTy(TheContext)…
    llvm::Function::Create(functionType, Function::ExternalLinkage...
    auto result = builder.CreateFAdd(dict["a"], dict["b"], “addtmp");
    builder.CreateRet(result);
    ExecutionEngine *executionEngine = EngineBuilder(std::move(module))...
    executionEngine->getFunctionAddress(function->getName().str())

    View Slide

  34. ४උɾɾɾɾ͓·͡ͳ͍
    --7.͕؅ཧ͢Δ$POUFYU
    static llvm::LLVMContext TheContext;
    InitializeNativeTarget();
    InitializeNativeTargetAsmPrinter();

    View Slide

  35. ࣮૷ͷཁɼϞδϡʔϧΛ࡞Δ
    --7.͕؅ཧ͢Δ$POUFYU
    static llvm::LLVMContext TheContext;
    InitializeNativeTarget();
    InitializeNativeTargetAsmPrinter();
    // Create a new module
    std::unique_ptr module(new llvm::Module("originalModule", TheContext));
    .PEVMF

    View Slide

  36. LLVM IRͷϏϧμΛ࡞Δ
    --7.͕؅ཧ͢Δ$POUFYU
    .PEVMF
    static llvm::LLVMContext TheContext;
    InitializeNativeTarget();
    InitializeNativeTargetAsmPrinter();
    // Create a new module
    std::unique_ptr module(new llvm::Module("originalModule", TheContext));
    // LLVM IR builder
    static IRBuilder<> builder(TheContext);
    ͜ͷΦϒδΣΫτʹ଍͠ࢉͷ໋ྩͳͲΛ౉ͯ͠
    ϓϩάϥϛϯά͍ͯ͘͠

    View Slide

  37. ࢦఆͨ͠ܕΛ࣋ͭؔ਺Λ࡞Δ
    --7.͕؅ཧ͢Δ$POUFYU
    .PEVMF
    'VODUJPO
    Ҿ਺ɾ໭Γ஋
    ໊લ
    static llvm::LLVMContext TheContext;
    InitializeNativeTarget();
    InitializeNativeTargetAsmPrinter();
    // Create a new module
    std::unique_ptr module(new llvm::Module("originalModule", TheContext));
    // LLVM IR builder
    static IRBuilder<> builder(TheContext);
    // define function
    // argument name list
    auto functionName = "originalFunction";
    // argument type list
    std::vector Doubles(2, Type::getDoubleTy(TheContext));
    // create function type
    FunctionType *functionType = FunctionType::get(Type::getDoubleTy(TheContext), Doubles, false);
    // create function in the module.
    Function *function = Function::Create(functionType, Function::ExternalLinkage, functionName, module.get());
    ໭Γ஋΍Ҿ਺ͷܕΛࢦఆͯ͠
    ؔ਺ͷܕΛ࡞Δ
    Ϟδϡʔϧɼ໊લɼܕΛࢦఆͯ͠
    ؔ਺Λ࡞Δ

    View Slide

  38. ॲཧͷϒϩοΫΛ࡞Δ
    --7.͕؅ཧ͢Δ$POUFYU
    .PEVMF
    'VODUJPO
    Ҿ਺ɾ໭Γ஋
    ໊લ
    // Create a new basic block to start insertion into.
    BasicBlock *basicBlock = BasicBlock::Create(TheContext, "entry", function);
    builder.SetInsertPoint(basicBlock);
    #MPDL FOUSZ

    View Slide

  39. FunctionΫϥε͔ΒҾ਺ͷϦετΛ΋Β͏
    --7.͕؅ཧ͢Δ$POUFYU
    .PEVMF
    'VODUJPO
    Ҿ਺ɾ໭Γ஋
    ໊લ
    // Create a new basic block to start insertion into.
    BasicBlock *basicBlock = BasicBlock::Create(TheContext, "entry", function);
    builder.SetInsertPoint(basicBlock);
    std::vector argNames{"a", “b"};
    // Set names for all arguments.
    // I'd like to use "zip" function, here.....
    unsigned idx = 0;
    for (auto &arg : function->args()) {
    arg.setName(argNames[idx++]);
    }
    // Create argument table for LLVM::Value type.
    static std::map dict;
    for (auto &arg : function->args()) {
    dict[arg.getName()] = &arg;
    }
    #MPDL FOUSZ

    ॲཧ
    ͜ͷؔ਺ͷҾ਺ͱͳΔMMWN7BMVFΛ
    MMWN'VODUJPO͔Βྻڍ͠ɼ
    ໊લΛηοτ͢Δ
    TUENBQʹม਺Λอଘ͓ͯ͘͠
    ޙ͔Βݺͼग़͢ͱ͖ʹศར

    View Slide

  40. ԋࢉ͢Δʢࠓճ͸଍͠ࢉʣ
    --7.͕؅ཧ͢Δ$POUFYU
    .PEVMF
    'VODUJPO
    Ҿ਺ɾ໭Γ஋
    ໊લ
    // Create a new basic block to start insertion into.
    BasicBlock *basicBlock = BasicBlock::Create(TheContext, "entry", function);
    builder.SetInsertPoint(basicBlock);
    std::vector argNames{"a", “b"};
    // Set names for all arguments.
    // I'd like to use "zip" function, here.....
    unsigned idx = 0;
    for (auto &arg : function->args()) {
    arg.setName(argNames[idx++]);
    }
    // Create argument table for LLVM::Value type.
    static std::map dict;
    for (auto &arg : function->args()) {
    dict[arg.getName()] = &arg;
    }
    // calculate "add"
    auto result = builder.CreateFAdd(dict["a"], dict["b"], “addtmp");
    #MPDL FOUSZ

    ॲཧ
    ೋͭͷม਺ͷ࿨
    ஋͸ɼMMWN7BMVFͰࢦఆ͢Δ
    "EEͷ݁Ռ΋MMWN7BMVFͰฦͬͯ͘Δ

    View Slide

  41. ໭Γ஋ͱͯ͠ܭࢉ݁ՌΛηοτ͢Δ
    --7.͕؅ཧ͢Δ$POUFYU
    .PEVMF
    'VODUJPO
    Ҿ਺ɾ໭Γ஋
    ໊લ
    #MPDL FOUSZ

    ॲཧ
    SFUVSO
    // Create a new basic block to start insertion into.
    BasicBlock *basicBlock = BasicBlock::Create(TheContext, "entry", function);
    builder.SetInsertPoint(basicBlock);
    std::vector argNames{"a", “b"};
    // Set names for all arguments.
    // I'd like to use "zip" function, here.....
    unsigned idx = 0;
    for (auto &arg : function->args()) {
    arg.setName(argNames[idx++]);
    }
    // Create argument table for LLVM::Value type.
    static std::map dict;
    for (auto &arg : function->args()) {
    dict[arg.getName()] = &arg;
    }
    // calculate "add"
    auto result = builder.CreateFAdd(dict["a"], dict["b"], “addtmp");
    // set return
    builder.CreateRet(result);

    View Slide

  42. ςΩετܗࣜͰ֬ೝ
    // confirm LLVM IR
    module->print(llvm::outs(), nullptr);
    ; ModuleID = 'originalModule'
    source_filename = "originalModule"
    define double @originalFunction(double, double) {
    entry:
    %addtmp = fadd double %0, %1
    ret double %addtmp
    }

    View Slide

  43. ࣮ߦ
    // confirm LLVM IR
    module->print(llvm::outs(), nullptr);
    // Builder JIT
    ExecutionEngine *executionEngine = EngineBuilder(std::move(module))
    .setEngineKind(EngineKind::JIT)
    .create();
    // Get pointer to a function which is built by EngineBuilder.
    auto f = reinterpret_cast(
    executionEngine->getFunctionAddress(function->getName().str())
    );
    f(1.0, 2.0);
    ࠓճͷ࣮૷͸ɼ&YFDVUJPO&OHJOFΫϥεΛ࢖ͬͯ+*5ίϯύΠϧ
    .$+*5ͱ͍͏ͷΛ࢖͍ͬͯͯݱࡏEFQSFDBUFE
    ϗϯτ͸ɼ03$+*5Λ࢖͏΂͖Β͍͠

    View Slide

  44. ࣮ߦ
    // confirm LLVM IR
    module->print(llvm::outs(), nullptr);
    // Builder JIT
    ExecutionEngine *executionEngine = EngineBuilder(std::move(module))
    .setEngineKind(EngineKind::JIT)
    .create();
    // Get pointer to a function which is built by EngineBuilder.
    auto f = reinterpret_cast(
    executionEngine->getFunctionAddress(function->getName().str())
    );
    f(1.0, 2.0);
    $$͸ؔ਺ͷϙΠϯλͷܕΛϥϯλΠϜ࣌ʹಈతʹม͑ΒΕͳ͍ɾɾɾ
    ํ๏͋Γ·͢ɾɾɾʁ

    View Slide

  45. Մม௕Ҿ਺ΛLLVM IRͰ࢖͏
    • ରࡦҊɿҾ਺ΛϙΠϯλͰ౉͠ɼ໌ࣔతʹݺͼग़͞ͳ͍
    ݺͼग़͠ଆͷΫϥε΍είʔϓ --7.Ͱ+*5ͨؔ͠਺
    EPVCMF
    EPVCMF
    ɹݺͼग़͠ଆͷΫϥε΍είʔϓ --7.Ͱ+*5ͨؔ͠਺
    EPVCMF
    EPVCMF
    ୈೋҊ͸ɼՄม௕Ҿ਺ͷC/C++ͷؔ਺ϙΠϯλͰ࣮ݱ͢Δɾɾɾɾʁ

    View Slide

  46. ܭࢉάϥϑͷ࣮૷

    View Slide

  47. ܭࢉάϥϑΛC++Ͱ࡞Δ
    • ந৅ߏจ໦ΛΘ͔Γ΍͘͢͢ΔͨΊ
    • ؆୯ͷͨΊʹ+ͷΈͷೋͭͷ୯७ܭࢉάϥϑͷΈΛߟ͑Δ
    • ܕ͸͢΂ͯdouble
    • ܭࢉ͸ɼԋࢉࢠͷΦʔόʔϩʔυͰ࣮૷͢Δ
    • ܭࢉάϥϑ͔Βந৅ߏจ໦Λ࡞Γɼ͔ͦ͜ΒLLVM IRΛు͖ग़͢
    • ੿࡞ͷαϯϓϧ͸ɼVISITORύλʔϯͰ࣮૷ͯ͠Έͨ

    View Slide

  48. • ந৅ߏจ໦ͷϊʔυΛϥοϓͨ͠ม਺Λ࢖͏
    • ໦ߏ଄ͷϊʔυͱɼܭࢉʹݱΕΔม਺ͱ݁ՌΛ෼͚Δ
    • ԋࢉࢠͷΦʔόʔϩʔυ͕࣮૷͠΍͍͢
    • Halideͷड͚ചΓ
    ந৅ߏจ໦ΛC++ͷΦʔόʔϩʔυͰ࣮૷͢Δ

    View Slide

  49. ܭࢉάϥϑΛC++Ͱॻ͘
    Func f;
    Var a, b;
    f(a, b) = a + b;
    f.realise();

    View Slide

  50. ·ͣ͸ม਺એݴɹม਺ͷఆٛͷϊʔυΛ಺แ
    7BSB
    7BS&YQS"45WBMVF
    7BSC
    7BS&YQS"45WBMVF
    Func f;
    Var a, b;
    f(a, b) = a + b;
    f.realise();
    7BSΫϥε͸҉໧ͷܕม׵Ͱ
    &YQSΫϥεͱͯ΋ԋࢉࢠΛΦʔόʔϩʔυ͢Δ
    ͳͷͰ7BSಉ࢜Λ଍ͤΔ
    ͞Βʹ--7.*3Ͱ࢖ΘΕΔ໊લ͕7BS͕࡞ΒΕͨλΠϛϯάͰ
    ࣗಈੜ੒͞ΕΔʢϚϧνεϨουඇରԠʣ

    View Slide

  51. ࿨ΛऔΔϊʔυΛߏ੒͢Δʔࢠϊʔυ͕ೋͭ
    &YQS
    7BS&YQS"45WBMVF
    &YQS
    7BS&YQS"45WBMVF
    B
    C

    &YQS#JOBSZ"45
    DIBSPQ
    &YQS"45MIT
    &YQS"45SIT
    Func f;
    Var a, b;
    f(a, b) = a + b;
    f.realise();
    &YQΫϥεͰ಺แ͢Δ
    &YQSΫϥεͷԋࢉࢠΛΦʔόʔϩʔυͯ͠
    7BSͷΦϒδΣΫτ΍ܭࢉ݁ՌΛ
    ίʔυͰͦͷ··ॻ͚ΔΑ͏ʹ͢Δ

    View Slide

  52. ݁ՌΛExprͰแΉ
    &YQS
    7BS&YQS"45WBMVF
    &YQS
    7BS&YQS"45WBMVF
    B
    C

    &YQS#JOBSZ"45
    DIBSPQ
    &YQS"45MIT
    &YQS"45SIT
    &YQS
    Func f;
    Var a, b;
    f(a, b) = a + b;
    f.realise();
    ͞Βʹ'VODʹ಺แ͞ΕΔ
    ͜͏͓͔ͯ͠ͳ͍ͱ
    ԋࢉࢠͷΦʔόʔϩʔυͷ࣮૷͕େม

    View Slide

  53. ݁ՌΛExprͰแΉ
    Func f;
    Var a, b;
    f(a, b) = a + b;
    f.realise();
    ͜ͷࠨล஋͸ɼ'VODͷϓϩύςΟͷ&YQSͷࢀরΛฦ͢
    ͜ͷࠨล஋ͷதͰɼBͱCΛؔ਺ͷҾ਺ͱͯ͠ηοτ͢Δ
    // Set names for all arguments.
    unsigned idx = 0;
    for (auto &arg : callee->args()) {
    arg.setName(argumentPlacefolders[idx++].name);
    }

    View Slide

  54. ϊʔυΛḷͬͯLLVM IRΛ૊Έཱ͍ͯͯ͘
    &YQS
    7BS&YQS"45WBMVF
    &YQS
    7BS&YQS"45WBMVF
    Func f;
    Var a, b;
    f(a, b) = a + b;
    f.realise();
    &YQS#JOBSZ"45
    DIBSPQ
    &YQS"45MIT
    &YQS"45SIT
    &YQS
    llvm::Value* BinaryExprAST::accept(IRVisitor* visitor) {
    std::cout << "accept - BinaryExprAST" << std::endl;
    llvm::Value* left = visitor->visit(lhs);
    llvm::Value* right = visitor->visit(rhs);
    auto p = visitor->builder;
    return p->CreateFAdd(left, right, "addtmp");
    }

    View Slide

  55. ϊʔυΛḷͬͯLLVM IRΛ૊Έཱ͍ͯͯ͘
    &YQS
    7BS&YQS"45WBMVF
    &YQS
    7BS&YQS"45WBMVF
    Func f;
    Var a, b;
    f(a, b) = a + b;
    f.realise();
    &YQS#JOBSZ"45
    DIBSPQ
    &YQS"45MIT
    &YQS"45SIT
    &YQS
    llvm::Value* VarExprAST::accept(IRVisitor* visitor) {
    // Ϟδϡʔϧʹొ࿥͞Εͨม਺Λฦ͢
    auto p = visitor->name2Value[name];
    return p;
    }

    View Slide

  56. &YQS
    &YQS#JOBSZ"45
    ͜ͷ࢓૊ΈΛߏ଄తʹ࡞͍͚ͬͯ͹Α͍
    f(a, b, c) = a + b * c * c; 7BSB
    &YQS"45WBMVF
    DIBSPQ
    &YQS"45MIT
    &YQS"45SIT
    7BSC
    &YQS"45WBMVF
    7BSD
    &YQS"45WBMVF
    &YQS
    &YQS#JOBSZ"45
    DIBSPQ
    &YQS"45MIT
    &YQS"45SIT
    &YQS
    &YQS#JOBSZ"45
    DIBSPQ
    &YQS"45MIT
    &YQS"45SIT

    View Slide

  57. Further more…
    • ఆ਺͸ɼcreateValueؔ਺Ͱఆ਺Λ࡞੒Ͱ͖Δ
    • C/C++Ͱݺ΂Δ֎෦ؔ਺ͷݺͼग़͠ɾɾɾ໊લͰొ࿥͢Δ͚ͩ
    • C͸؆୯͕ͩɼC++͸mangling͕ೖΔͷͰେมʢmangling͕ॲཧܥʹґଘ͢ΔͨΊʣ
    • double hoge_cpp(double a) → _Z8hoge_cppd
    • ৚݅෼ذ
    • blockΛ׆༻࣮ͯ͠૷͢Δ
    • ϝϞϦ֬อɾɾɾSSA͔Βͷղ์
    • allocaͰ֬อ͠ɼSSA͡Όͳ͍ม਺Λ࡞ΕΔɽ͜ΕͰforจͱ͔΋؆୯ʹ࡞ΕΔ

    View Slide

  58. ࠷ऴతʹɾɾɾɾɾ
    int main() {
    Func f;
    Var a, b, c;
    f(a, b, c) = F::sin(a * 1.2) + F::sin(b * F::pow(a, b));
    f.realise();
    std::cout << f(10.0, 2.0, 3.0) << std::endl;
    return 0;
    }

    View Slide

  59. ·ͱΊ
    • LLVMͷ׆༻ɼܭࢉάϥϑͷԠ༻
    • LLVM IRͷجຊ
    • ܭࢉάϥϑˠந৅ߏจ໦ͷ࡞Γํͷ͸͡ΊͷҰา
    • ͓͢͢Ίڭࡐ
    • LLVM IR → llvm.orgͷTutorial Kaleidoscope Language
    • ந৅ߏจ໦ͱJIT → Halideͷιʔείʔυ

    View Slide