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

F9feb45c0a049cccc3e2563f1fe2f869?s=47 sonson
August 29, 2020

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

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

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

F9feb45c0a049cccc3e2563f1fe2f869?s=128

sonson

August 29, 2020
Tweet

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

  3. • sonson • @sonson_twit • github.com/sonsongithub • iOS͸͍ͩͿݹࢀͷ͓ͬ͞ΜͰ͢ • ຊ৬

    • DENSO IT Laboratory, Inc. • Research Engineer • ը૾ೝࣝɼը૾ݕࡧɼػցֶशɾɾɾͳͲ ࣗݾ঺հ https://github.com/sonsongithub/zipr SwiftͰॻ͍ͯΔ zipͰਬ͖ग़ͨ͠ը૾ϑΝΠϧϏϡʔΞ
  4. ࠓ೔ͷιʔείʔυͳͲ llvm.orgͷ೔ຊޠ༁Λ΍ͬͯΈͨϦϙδτϦ ࠓ೔঺հ͢Δίʔυશൠ https://github.com/sonsongithub/llvm-tutorial https://github.com/sonsongithub/llvm_jit_compile

  5. LLVM

  6. LLVM • ίϯύΠϥج൫ • ίϯύΠϥΛ࡞ΔͨΊͷ࢓༷΍ιϑτ΢ΣΞ܈ • C++, Python, GoͷΠϯλϑΣʔε͕ఏڙ͞Ε͍ͯΔ •

    ੲ͸ɼLow Level Virtual MachineͷུͩͬͨΒ͍͕͠ɼࠓ͸LLVM • ͨ͘͞Μͷιϑτ΢ΣΞ͕LLVMΛར༻͍ͯ͠Δ • Swift, Rust, Halide, Julia, clang, lldb…
  7. LLVMͰԿ͔࡞Δͱ͖ͷΠϝʔδʙΦϨΦϨݴޠ ΦϨΦϨݴޠ ιʔείʔυ --7.*3 1BTT όΠφϦ ίϯύΠϥ LLVMΛAPIΛ࢖ͬͯɼLLVM IRʹม׵͢Δ ΦϨΦϨݴޠͷύʔα͸ࣗ෼Ͱ࡞Δ

    C++, Go, PythonͰॻ͚Δ ৭ʑ༻ҙ͞Ε͍ͯΔ͠ ࣗ෼Ͱ΋࡞ΕΔ x86ͷPassΛ࢖͑͹ɼx86ʹରԠͰ͖Δ armͷPassΛ࢖͑͹ɼar̼ʹରԠͰ͖Δ 1BTT 1BTT
  8. Swiftͷ৔߹ 4XJGU ιʔείʔυ 4*- ந৅ߏจ໦ ࠷దԽ --7.*3 όΠφϦ ɾɾɾɾɾ 4XJGU*OUFSNFEJBUF-BOHVBHF

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

  10. LLVM IR

  11. LLVM IR • LLVMͷத֩ͱͳΔɼதؒදݱ • ΞηϯϒϦݴޠͬΆ͍ײ͡ͷදݱ • ʢ໋ྩʣʢಡΈग़͠ݩʣʢಡΈग़͠ݩʣʢॻ͖ࠐΈઌʣ • ແݶͷϨδελ͕͋Γɼܕ෇͚ݴޠɼSSA(Static

    Single Assignment) • ̏छྨͷ࢖͍ํ͕͋Δ • ςΩετܗࣜɾɾɾclangͱ͔Ͱग़ྗͰ͖Δ΍ͭɽhuman readable • ΠϯϝϞϦܗࣜɾɾɾɾࠓճͷΑ͏ͳϓϩάϥϜ্Ͱදݱ͞ΕΔ΋ͷ • bit codeܗࣜɾɾɾɾόΠφϦͰอ࣋ͯ͠ίϯύΫτͳ΍ͭ
  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 }
  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 }
  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 }
  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 }
  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 }
  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 }
  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 }
  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 }
  20. ܭࢉάϥϑ

  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); ී௨ʹ࣮૷ ܭࢉάϥϑͬΆ࣮͘૷
  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 ࣮ߦ࣌ʹ೚ҙͷม਺Ͱඍ෼ͨ͠Γɼґଘؔ܎Λ೺Ѳͨ͠ΓͰ͖Δ
  23. ྫɿHalide - ࠷దԽ C++ͷΈͰSIMDʹରԠ HalideͳΒɼ͜ΕͰSIMD/εϨου/GPUʹରԠ ܭࢉάϥϑͰදݱ͢Δ͜ͱͰɼґଘؔ܎౳͕໌֬ʹͳΔ Halide͸ɼͦΕΛ༻͍ͯɼϋʔυ΢ΣΞʹಈతʹ࠷దԽͨ͠όΠφϦΛLLVMܦ༝Ͱు͚Δ

  24. ࠓ೔ͷ໨ඪɿܭࢉάϥϑΛJITίϯύΠϧ͢Δ • LLVMͱLLVM IRΛͪΐͬͱཧղ͢Δ • C++ͰܭࢉάϥϑΛ࣮૷͢Δ • ܭࢉάϥϑ͔Βந৅ߏจ໦Λ࡞Δ • ந৅ߏจ໦ΛɼLLVMʹҾ͖౉͠ɼLLVM

    IRʹม׵͢Δ • ϞδϡʔϧΛίϯύΠϧ͠ɼؔ਺ϙΠϯλΛಘΔ • ܭࢉάϥϑ͔Βੜ੒ͨؔ͠਺Λ࣮ߦ͢Δ ※ͪͳΈʹܭࢉάϥϑࣗମ͸JITͰͳͯ͘΋࣮ݱͰ͖·͢
  25. ࠓ೔ͷίʔυͷ౔୆ HalideͷαΠτ ܭࢉάϥϑͳͲ͸ɼ͜ͷιʔεͰษڧ llvm.org - Tutorial Kaleidoscope C++ͰΦϨΦϨݴޠΛ࡞ΔνϡʔτϦΞϧ https://llvm.org/docs/tutorial/MyFirstLanguageFrontend/index.html https://halide-lang.org

  26. LLVM API

  27. LLVMͷΠϯετʔϧ • macOS - brew, ιʔε͔ΒϏϧυ • Xcode͸಺แͷ΋ͷ͸͓͢͢Ί͠ͳ͍ɹྫɿllvm-config͕ͳ͍ • Linux

    - ύοέʔδϚωʔδϟͰ͍ΕΕ͹͍͍ • ubuntuͰ͸aptͰ͍Ε·ͨ͠ • Windows - ஌Βͳ͍ɾɾɾɾ • ͢Μ·ͤΜ
  28. LLVMͰؔ਺Λ࡞ΔΠϝʔδ ܭࢉάϥϑΞϓϦ --7.*3 --7. ந৅ߏจ໦ ܭࢉάϥϑ όΠφϦ

  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
  30. γϯϓϧͳؔ਺ΛLLVMͰ࣮૷ͯ͠ΈΔ • ࣮૷͢Δؔ਺ a + b double func(double a, double

    b) { return a + b; }
  31. LLVMͰϓϩάϥϛϯά͢ΔΠϝʔδ

  32. ී௨ͷCͩͱ Ҿ਺ͳͲΛఆٛ͢Δ ؔ਺Λ࡞Δ ԋࢉ͢Δ ໭Γ஋Λఆٛ͢Δ ίϯύΠϧ͢Δ ࣮ߦ͢Δ (double a, double

    b)... double hoge (double a, double b)... a + b return a + b; clang hoge.cpp -o hoge hoge
  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())
  34. ४උɾɾɾɾ͓·͡ͳ͍ --7.͕؅ཧ͢Δ$POUFYU static llvm::LLVMContext TheContext; InitializeNativeTarget(); InitializeNativeTargetAsmPrinter();

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

    new module std::unique_ptr<Module> module(new llvm::Module("originalModule", TheContext)); .PEVMF
  36. LLVM IRͷϏϧμΛ࡞Δ --7.͕؅ཧ͢Δ$POUFYU .PEVMF static llvm::LLVMContext TheContext; InitializeNativeTarget(); InitializeNativeTargetAsmPrinter(); //

    Create a new module std::unique_ptr<Module> module(new llvm::Module("originalModule", TheContext)); // LLVM IR builder static IRBuilder<> builder(TheContext); ͜ͷΦϒδΣΫτʹ଍͠ࢉͷ໋ྩͳͲΛ౉ͯ͠ ϓϩάϥϛϯά͍ͯ͘͠
  37. ࢦఆͨ͠ܕΛ࣋ͭؔ਺Λ࡞Δ --7.͕؅ཧ͢Δ$POUFYU .PEVMF 'VODUJPO Ҿ਺ɾ໭Γ஋ ໊લ static llvm::LLVMContext TheContext; InitializeNativeTarget();

    InitializeNativeTargetAsmPrinter(); // Create a new module std::unique_ptr<Module> 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<Type *> 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()); ໭Γ஋΍Ҿ਺ͷܕΛࢦఆͯ͠ ؔ਺ͷܕΛ࡞Δ Ϟδϡʔϧɼ໊લɼܕΛࢦఆͯ͠ ؔ਺Λ࡞Δ
  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
  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<std::string> 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<std::string, Value*> dict; for (auto &arg : function->args()) { dict[arg.getName()] = &arg; } #MPDL FOUSZ ॲཧ ͜ͷؔ਺ͷҾ਺ͱͳΔMMWN7BMVFΛ MMWN'VODUJPO͔Βྻڍ͠ɼ ໊લΛηοτ͢Δ TUENBQʹม਺Λอଘ͓ͯ͘͠ ޙ͔Βݺͼग़͢ͱ͖ʹศར
  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<std::string> 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<std::string, Value*> 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Ͱฦͬͯ͘Δ
  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<std::string> 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<std::string, Value*> 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);
  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 }
  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<double(*)(double, double)>( executionEngine->getFunctionAddress(function->getName().str()) ); f(1.0, 2.0); ࠓճͷ࣮૷͸ɼ&YFDVUJPO&OHJOFΫϥεΛ࢖ͬͯ+*5ίϯύΠϧ .$+*5ͱ͍͏ͷΛ࢖͍ͬͯͯݱࡏEFQSFDBUFE ϗϯτ͸ɼ03$+*5Λ࢖͏΂͖Β͍͠
  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<double(*)(double, double)>( executionEngine->getFunctionAddress(function->getName().str()) ); f(1.0, 2.0); $$ ͸ؔ਺ͷϙΠϯλͷܕΛϥϯλΠϜ࣌ʹಈతʹม͑ΒΕͳ͍ɾɾɾ ํ๏͋Γ·͢ɾɾɾʁ
  45. Մม௕Ҿ਺ΛLLVM IRͰ࢖͏ • ରࡦҊɿҾ਺ΛϙΠϯλͰ౉͠ɼ໌ࣔతʹݺͼग़͞ͳ͍ ݺͼग़͠ଆͷΫϥε΍είʔϓ --7.Ͱ+*5ͨؔ͠਺ EPVCMF EPVCMF ɹݺͼग़͠ଆͷΫϥε΍είʔϓ --7.Ͱ+*5ͨؔ͠਺

    EPVCMF EPVCMF ୈೋҊ͸ɼՄม௕Ҿ਺ͷC/C++ͷؔ਺ϙΠϯλͰ࣮ݱ͢Δɾɾɾɾʁ
  46. ܭࢉάϥϑͷ࣮૷

  47. ܭࢉάϥϑΛC++Ͱ࡞Δ • ந৅ߏจ໦ΛΘ͔Γ΍͘͢͢ΔͨΊ • ؆୯ͷͨΊʹ+ͷΈͷೋͭͷ୯७ܭࢉάϥϑͷΈΛߟ͑Δ • ܕ͸͢΂ͯdouble • ܭࢉ͸ɼԋࢉࢠͷΦʔόʔϩʔυͰ࣮૷͢Δ •

    ܭࢉάϥϑ͔Βந৅ߏจ໦Λ࡞Γɼ͔ͦ͜ΒLLVM IRΛు͖ग़͢ • ੿࡞ͷαϯϓϧ͸ɼVISITORύλʔϯͰ࣮૷ͯ͠Έͨ
  48. • ந৅ߏจ໦ͷϊʔυΛϥοϓͨ͠ม਺Λ࢖͏ • ໦ߏ଄ͷϊʔυͱɼܭࢉʹݱΕΔม਺ͱ݁ՌΛ෼͚Δ • ԋࢉࢠͷΦʔόʔϩʔυ͕࣮૷͠΍͍͢ • Halideͷड͚ചΓ ந৅ߏจ໦ΛC++ͷΦʔόʔϩʔυͰ࣮૷͢Δ

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

    + b; f.realise();
  50. ·ͣ͸ม਺એݴɹม਺ͷఆٛͷϊʔυΛ಺แ 7BSB 7BS&YQS"45 WBMVF 7BSC 7BS&YQS"45 WBMVF Func f; Var

    a, b; f(a, b) = a + b; f.realise(); 7BSΫϥε͸҉໧ͷܕม׵Ͱ &YQSΫϥεͱͯ΋ԋࢉࢠΛΦʔόʔϩʔυ͢Δ ͳͷͰ7BSಉ࢜Λ଍ͤΔ ͞Βʹ--7.*3Ͱ࢖ΘΕΔ໊લ͕7BS͕࡞ΒΕͨλΠϛϯάͰ ࣗಈੜ੒͞ΕΔʢϚϧνεϨουඇରԠʣ
  51. ࿨ΛऔΔϊʔυΛߏ੒͢Δʔࢠϊʔυ͕ೋͭ &YQS 7BS&YQS"45 WBMVF &YQS 7BS&YQS"45 WBMVF B C &YQS#JOBSZ"45

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

    DIBSPQ &YQS"45 MIT &YQS"45 SIT &YQS Func f; Var a, b; f(a, b) = a + b; f.realise(); ͞Βʹ'VODʹ಺แ͞ΕΔ ͜͏͓͔ͯ͠ͳ͍ͱ ԋࢉࢠͷΦʔόʔϩʔυͷ࣮૷͕େม
  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); }
  54. ϊʔυΛḷͬͯLLVM IRΛ૊Έཱ͍ͯͯ͘ &YQS 7BS&YQS"45 WBMVF &YQS 7BS&YQS"45 WBMVF Func f;

    Var a, b; f(a, b) = a + b; f.realise(); &YQS#JOBSZ"45 DIBSPQ &YQS"45 MIT &YQS"45 SIT &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"); }
  55. ϊʔυΛḷͬͯLLVM IRΛ૊Έཱ͍ͯͯ͘ &YQS 7BS&YQS"45 WBMVF &YQS 7BS&YQS"45 WBMVF Func f;

    Var a, b; f(a, b) = a + b; f.realise(); &YQS#JOBSZ"45 DIBSPQ &YQS"45 MIT &YQS"45 SIT &YQS llvm::Value* VarExprAST::accept(IRVisitor* visitor) { // Ϟδϡʔϧʹొ࿥͞Εͨม਺Λฦ͢ auto p = visitor->name2Value[name]; return p; }
  56. &YQS &YQS#JOBSZ"45 ͜ͷ࢓૊ΈΛߏ଄తʹ࡞͍͚ͬͯ͹Α͍ f(a, b, c) = a + b

    * c * c; 7BSB &YQS"45 WBMVF DIBSPQ &YQS"45 MIT &YQS"45 SIT 7BSC &YQS"45 WBMVF 7BSD &YQS"45 WBMVF &YQS &YQS#JOBSZ"45 DIBSPQ &YQS"45 MIT &YQS"45 SIT &YQS &YQS#JOBSZ"45 DIBSPQ &YQS"45 MIT &YQS"45 SIT
  57. Further more… • ఆ਺͸ɼcreateValueؔ਺Ͱఆ਺Λ࡞੒Ͱ͖Δ • C/C++Ͱݺ΂Δ֎෦ؔ਺ͷݺͼग़͠ɾɾɾ໊લͰొ࿥͢Δ͚ͩ • C͸؆୯͕ͩɼC++͸mangling͕ೖΔͷͰେมʢmangling͕ॲཧܥʹґଘ͢ΔͨΊʣ • double

    hoge_cpp(double a) → _Z8hoge_cppd • ৚݅෼ذ • blockΛ׆༻࣮ͯ͠૷͢Δ • ϝϞϦ֬อɾɾɾSSA͔Βͷղ์ • allocaͰ֬อ͠ɼSSA͡Όͳ͍ม਺Λ࡞ΕΔɽ͜ΕͰforจͱ͔΋؆୯ʹ࡞ΕΔ
  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; }
  59. ·ͱΊ • LLVMͷ׆༻ɼܭࢉάϥϑͷԠ༻ • LLVM IRͷجຊ • ܭࢉάϥϑˠந৅ߏจ໦ͷ࡞Γํͷ͸͡ΊͷҰา • ͓͢͢Ίڭࡐ

    • LLVM IR → llvm.orgͷTutorial Kaleidoscope Language • ந৅ߏจ໦ͱJIT → Halideͷιʔείʔυ