ãã¥ãŒããªã¢ã«ãLLVMã䜿çšããããã°ã©ãã³ã°èšèªã®äœæãã®ç¬¬3ç« ã«ããããã ãã®ç« ã§ã¯ã
第2ç« ã§äœæããASTïŒAbstract Syntax TreeïŒãLLVM IRã«å€æããæ¹æ³ã«ã€ããŠèª¬æããŸãã 圌女ã¯LLVMã®ããã€ãã®åŽé¢ã«ã€ããŠèª¬æãããŸããããããã«ç°¡åãã瀺ããŸãã LLVM IRã³ãŒããçŽæ¥äœæããããããåå¥è§£æãšæ§æè§£æã«å€ãã®äœæ¥ãå¿
èŠã§ããããšãããããŸãã
泚 ïŒãã®ç« ã®ã³ãŒãã«ã¯LLVM 2.2以éãå¿
èŠã§ãã LLVM 2.1ããŒãžã§ã³ãå«ããšããã®ã³ãŒãã¯æ©èœããŸããã LLVMãªãªãŒã¹ã«äžèŽãããã®ãã¥ãŒããªã¢ã«ã®ããŒãžã§ã³ã䜿çšããå¿
èŠãããããšã«ã泚æããŠãã ãããå
¬åŒãªãªãŒã¹ã«ä»å±ã®ããã¥ã¡ã³ãã䜿çšããã
ãllvm.orgã®ãªãªãŒã¹ããŒãžã«ã¢ã¯ã»ã¹ããŠ
ãã ãã ã
ã³ãŒãçæã®ããã«èª¿æŽãããŠããŸã
LLVM IRãçæããã«ã¯ãããã€ãã®ç°¡åãªã»ããã¢ãããå¿
èŠã§ãã ãŸããASTã¯ã©ã¹ããšã«ä»®æ³ã³ãŒãçæã¡ãœããïŒ
Codegen
ïŒãå®çŸ©ããŸãã
virtual Value *Codegen() = 0;
};
virtual Value *Codegen();
}; ...
Codegen()
ã¡ãœããã¯ãæå®ãããASTããŒãã®IRãšãã®ãã¹ãŠã®äŸåããŒããè¿ããããããã¹ãŠã
LLVM Value
ãªããžã§ã¯ããè¿ããŸãã
"Value"
ã¯ãLLVMã®ã
éçåäžå²ãåœãŠ ïŒ
SSA ïŒ
ã¬ãžã¹ã¿ ããŸãã¯ãSSAå€ãã衚ãããã«äœ¿çšãããã¯ã©ã¹ã§ãã SSAã§æãéèŠãªç¹ã¯ãå€ãé¢é£ããåœä»€ã®å®è¡ãšããŠèšç®ãããåœä»€ãåå®è¡ããããŸã§ïŒããã³ãã®å ŽåïŒæ°ããå€ãåãåãããšãã§ããªãããšã§ãã ã€ãŸããSSAå€ãã倿Žãããæ¹æ³ã¯ãããŸããã 詳现ã«ã€ããŠã¯ã
éçåäžå²ãåœãŠã«ã€ããŠã
èªã¿ãã ãã-ãããã®æŠå¿µã¯ã泚æãæããšããã«éåžžã«èªç¶ã«èŠããŸãã
ExprAST
ã¯ã©ã¹ã®éå±€ã«ä»®æ³ã¡ãœããã远å ãã代ããã«ã
Visitorãã¶ã€ã³ãã¿ãŒã³ãŸãã¯ä»ã®ã¡ãœããã䜿çšããã®ãçã«ããªã£ãŠããããšã«æ³šæããŠãã ããã ç¹°ãè¿ããŸããããã®ãã¥ãŒããªã¢ã«ã§ã¯ãåªãããœãããŠã§ã¢éçºæ¹æ³ã«ã€ããŠã¯èª¬æããŸãããç®æšã¯ã·ã³ãã«ã§ãããä»®æ³ã¡ãœããã远å ããããšã¯ç°¡åã§ãã
ãŸããããŒãµãŒã«äœ¿çšããããã®ãšåæ§ã®ãšã©ãŒãåŠçããæ¹æ³ãå¿
èŠã§ãã ã³ãŒãçæäžã«èŠã€ãã£ããšã©ãŒã¡ãã»ãŒãžã«ãã®ã¡ãœããã䜿çšããŸãïŒããšãã°ã宣èšãããŠããªããã©ã¡ãŒã¿ãŒã䜿çšããŸãïŒã
Value *ErrorV(const char *Str) { Error(Str); return 0; } static Module *TheModule; static IRBuilder<> Builder(getGlobalContext()); static std::map<std::string, Value*> NamedValues;
ãããã®éç倿°ã¯ãã³ãŒãçæäžã«äœ¿çšãããŸãã
TheModule
ã¯ããã¹ãŠã®é¢æ°ãšã°ããŒãã«å€æ°ãã³ãŒãã®äžéšã«å«ãLLVMã³ã³ã¹ãã©ã¯ãã§ãã ã»ãšãã©ã®å Žåããããã¯ãLLVM IRãå«ãŸããã³ãŒãã«äœ¿çšããæäžäœã®æ§é ã§ãã
Builder
ãªããžã§ã¯ãã¯ãLLVMåœä»€ãç°¡åã«çæã§ããããã«ãããã«ããŒãªããžã§ã¯ãã§ãã ã¯ã©ã¹ãã³ãã¬ãŒãã€ã³ã¹ã¿ã³ã¹
IRBuilder
IRBuilder
ã¯ãåœä»€ãæ¿å
¥ããããã®çŸåšã®å Žæã远跡ããæ°ããåœä»€ãäœæããããã®ã¡ãœãããå«ãã§ããŸãã
NamedValues
ããã
NamedValues
ãçŸåšã®ã¹ã³ãŒãã§å®çŸ©ãããŠããå€ãšãã®LLVM衚çŸ
NamedValues
远跡ããŸãã ïŒã€ãŸããããã¯ã³ãŒãã®æåããŒãã«ã§ãïŒã Kaleidoscopeã®çŸåšã®ãã©ãŒã ã§ã¯ãåç
§ã§ããã®ã¯é¢æ°ãã©ã¡ãŒã¿ãŒã®ã¿ã§ãã ãããã£ãŠããã®ãããã§ã¯ã颿°æ¬äœã®ã³ãŒããçæãããšãã«ããã®é¢æ°ã®ãã©ã¡ãŒã¿ãŒãé
眮ãããŸãã
ããããã¹ãŠãç¥ã£ãŠããã°ãåŒã®ã³ãŒãã®çæã«ã€ããŠè©±ãããšãã§ããŸãã ãäœã§ããã®ã³ãŒããçæããããã«ã
Builder
ããã§ã«äœæãããŠããããšãåæãšããŠããŸãã ãšãããããããã¯æ¢ã«è¡ãããŠãããšä»®å®ããããã䜿çšããŠã³ãŒããä¿åããŸãã
åŒã³ãŒãçæ
åŒããŒãã®LLVMã³ãŒãã®çæã¯éåžžã«ç°¡åã§ãã4ã€ã®åŒããŒãã¿ã€ããã¹ãŠã«ã€ããŠãã³ã¡ã³ãè¡ã45è¡æªæºã§ãã å§ããããã«ãæ°å€ãªãã©ã«ãèŠãŠã¿ãŸãããã
Value *NumberExprAST::Codegen() { return ConstantFP::get(getGlobalContext(), APFloat(Val)); }
LLVM IRã§ã¯ãæ°å€å®æ°ã¯
ConstantFP
ã¯ã©ã¹ã§è¡šãããŸãããã®ã¯ã©ã¹ã«ã¯ã
APFloat
ã®åœ¢åŒã®æ°å€ãå«ãŸããŸãïŒ
APFloat
ã¯ãå®å®æ°ãä»»æã®ç²ŸåºŠã®æ°å€ã«ãã£ã¹ãããæ©èœããããŸãïŒã ãã®ã³ãŒãã¯ã
ConstantFP
äœæããŠè¿ããŸãã LLVM IRã§ã¯ããã¹ãŠã®å®æ°ã¯äžæïŒäžæïŒããã³å
±æïŒå
±æïŒã§ããããšã«æ³šæããŠãã ããã ãã®ãããAPIã¯
"new foo(..)"
ã
"foo::Create(..)"
ã§ã¯ãªããã€ãã£ãªã
"foo::get(...)"
䜿çšã
"foo::Create(..)"
ã
Value *VariableExprAST::Codegen() {
LLVMã䜿çšããå Žåã倿°åç
§ãéåžžã«ç°¡åã§ãã Kaleidoscopeã®åçŽãªããŒãžã§ã³ã§ã¯ã倿°ãæ¢ã«ã©ããã«èšå®ãããŠããããã®å€ãå©çšå¯èœã§ãããšæ³å®ããŠããŸãã å®éã«ã¯ãNamedValuesãããã®å€ã¯é¢æ°ã®åŒæ°ã®ã¿ã«ãªããŸãã ãã®ã³ãŒãã¯ãæå®ãããååããããäžã§å®çŸ©ãããŠããããšã確èªãïŒå®çŸ©ãããŠããªãå Žåãããã¯äžæãªå€æ°ãžã®ãªã³ã¯ã§ãïŒããã®å€ãè¿ããŸãã åŸç¶ã®ç« ã§ã¯ãããŒã«ã«å€æ°ãšã«ãŒãã«ãŠã³ã¿ãŒå€æ°ã®ãµããŒãã远å ããŸãã
Value *BinaryExprAST::Codegen() { Value *L = LHS->Codegen(); Value *R = RHS->Codegen(); if (L == 0 || R == 0) return 0; switch (Op) { case '+': return Builder.CreateFAdd(L, R, "addtmp"); case '-': return Builder.CreateFSub(L, R, "subtmp"); case '*': return Builder.CreateFMul(L, R, "multmp"); case '<': L = Builder.CreateFCmpULT(L, R, "cmptmp");
äºé
æŒç®åã§ã楜ãã¿ãå§ãŸããŸãã ããã§ã®äž»ãªèãæ¹ã¯ãåŒã®å·ŠåŽã®ã³ãŒããååž°çã«çæããæ¬¡ã«å³åŽã®ã³ãŒããçæããŠããã€ããªåŒã®çµæãèšç®ããããšã§ãã ãã®ã³ãŒãã§ã¯ãLLVMã¹ããŒãã¡ã³ããäœæããããã®2é
æŒç®åã«é¢ããç°¡åãªã¹ã€ãããäœæããŸããã
äžèšã®äŸã§ã¯ãLLVM
Builder
ã¯ã©ã¹ãæçµçã«ãã®å€ã瀺ããŠããŸãã
IRBuilder
ã¯ãæ°ããäœæãããåœä»€ãæ¿å
¥ããå ŽæãèªèããŠãããäœæããåœä»€ïŒ
"CreateFAdd"
ïŒã䜿çšãããªãã©ã³ãïŒãã®å Žåã¯LãšRïŒãããã³å¿
èŠã«å¿ããŠäœ¿çšããåœä»€ãæå®ããã ãã§ããçæãããåœä»€ã®ååã
LLVMã®ãã1ã€ã®åªããæ©èœã¯ãååã®å²ãåœãŠã§ãã ããšãã°ãäžèšã§
"addtmp"
倿°ãæ°å䜿çšãããšãLLVMã¯æ¯åèªåçã«äžæã®æ°å€ãµãã£ãã¯ã¹ãå²ãåœãŠãŸãã æç€ºã®ããŒã«ã«å€åã¯ãªãã·ã§ã³ã§ãããIRãã³ããèªã¿ãããããŸãã
LLVMåœä»€ã¯å³å¯ãªã«ãŒã«ã«ãã£ãŠå¶éãããŸããããšãã°ã
å ç®åœä»€ã®å·Šå³ã®ãªãã©ã³ãã¯åãåã§ããå¿
èŠããããå ç®çµæã®åã¯ãªãã©ã³ãã®åã«å¯Ÿå¿ããŸãã Kaleidoscopeã®ãã¹ãŠã®å€ã¯å®æ°ã§ãããããå ç®ãæžç®ãä¹ç®ã®éåžžã«åçŽãªã³ãŒããååŸããŸãã
äžæ¹ãLLVMã®ä»æ§ã§ã¯
ã fcmp
åœä»€ã¯åžžã«å€ãi1ãïŒåäžãããæŽæ°ïŒãè¿ããŸãã åé¡ã¯ãKaleidoscopeã§ã¯0.0ãŸãã¯1.0ã®å€ãå¿
èŠãªããšã§ãã ãããè¡ãã«ã¯ã
fcmp
ã
fcmp
ãšçµã¿åãããŸãã ãã®åœä»€ã¯ã笊å·ãªãæŽæ°ã宿µ®åå°æ°ç¹ã«å€æããŸãã 察ç
§çã«ã
sitofp
ã䜿çšã
ãå Žåãã<ãæŒç®åã¯å
¥åå€ã«å¿ããŠ0.0ãš-1.0ãè¿ããŸãã
Value *CallExprAST::Codegen() {
LLVMã³ãŒããçæããŠé¢æ°ãåŒã³åºãã®ã¯éåžžã«ç°¡åã§ãã äžèšã®ã³ãŒãã¯ãæåã«LLVMã¢ãžã¥ãŒã«ã®ã·ã³ãã«ããŒãã«ã§é¢æ°åãæ€çŽ¢ããŸãã LLVMã¢ãžã¥ãŒã«ã¯ãJITã³ã³ãã€ã«ã«äœ¿çšã§ãããã¹ãŠã®æ©èœãå«ãã³ã³ãããŒã§ããããšãæãåºããŠãã ããã å颿°ã«ååãä»ãããšãLLVMã·ã³ãã«ããŒãã«ã䜿çšããŠé¢æ°åãæ€çŽ¢ã§ããŸãã
åŒã³åºã颿°ãåãåã£ãåŸãæž¡ãããååŒæ°ã®ã³ãŒããååž°çã«çæããLLVMåŒã³åºãåœä»€ãäœæããŸãã LLVMã¯ããã©ã«ãã§Cã®ãããªé¢æ°åŒã³åºãèŠåã䜿çšããããšã«æ³šæããŠãã ãããããã«ããã
"sin"
ã
"cos"
ãªã©ã®æšæºã©ã€ãã©ãªé¢æ°ã«ãããã®åŒã³åºãã远å ã®åŽåãªãã§äœ¿çšã§ããŸãã
ããã§ã4ã€ã®äž»èŠãªã¿ã€ãã®KaleidoscopeèšèªåŒããŒãã®åŠçãå®äºããŸããã ããã«é²ãã§ãããã«ããã€ãã®ãã¥ãŒã远å ã§ããŸãã ããšãã°ãLLVMèšèªãåç
§ãããšãæ¢åã®éçºãžã®æ¥ç¶ãéåžžã«ç°¡åãªä»ã®è峿·±ãæç€ºãããã€ãèŠã€ãããŸãã
æ©èœã³ãŒãçæ
ãããã¿ã€ããšé¢æ°ã®ã³ãŒãçæã§ã¯ãã³ãŒãåŒãçæãããããã³ãŒããçŸããããªãå€ãã®è©³çްãåŠçããå¿
èŠããããŸãããããã€ãã®éèŠãªãã€ã³ãã説æã§ããŸãã ãŸãããããã¿ã€ãã®ã³ãŒãçæã«ã€ããŠèª¬æããŸããããããã¯ã颿°ã®æ¬äœãšå€éšé¢æ°ã®å®£èšã®äž¡æ¹ã«äœ¿çšãããŸãã ã³ãŒãã¯æ¬¡ã§å§ãŸããŸãïŒ
Function *PrototypeAST::Codegen() {
æ°è¡ã®ãã®ã³ãŒãã¯å®éã«å®åã瀺ããŠããŸãã ãŸãããã®é¢æ°ã¯
"Value*"
ã§ã¯ãªã
"Function*"
è¿ãããšã«æ³šæããŠãã ããã ããããã¿ã€ããã¯å®éã«ã¯ïŒèšç®åŒã§ã¯ãªãïŒé¢æ°ã®å€éšã€ã³ã¿ãŒãã§ã€ã¹ãæãããã颿°ã«å¯ŸããŠçæãããã³ãŒãã«å¯Ÿå¿ããLLVM颿°ãè¿ãããšã¯çã«ããªã£ãŠããŸãã
"FunctionType::get"
ãåŒã³åºããšããã®ãããã¿ã€ãã«äœ¿çšãããFunctionTypeãäœæãããŸãã Kaleidoscopeã®ãã¹ãŠã®é¢æ°åŒæ°ã¯å®æ°ã§ãããããæåã®è¡ã¯ãNãåã®å®æ°ããLLVMãã¯ãã«ãäœæããŸãã æ¬¡ã«ã
FunctionType::get
ã¡ãœããã䜿çšããŠããNãåã®æå¹ãªåŒæ°ãåããçµæãšããŠ1ã€ã®æå¹ãªåŒæ°ãè¿ã颿°åãäœæããŸãã LLVMã®åã¯å®æ°ãšããŠäžæã§ããããã
"new"
ã§ã¯ãªã
"get"
ãå¿
èŠã§ããããšã«æ³šæããŠãã ããïŒå
ã®èšèã§ã¯ãã...ã ãã
"
äœæ
"
ã§ã¯ãªãã
"
get
"
ãïŒã ã
æåŸã®è¡ã¯ãå®éã«ãããã¿ã€ãã«äžèŽãã颿°ãäœæããŸãã 䜿çšããã¿ã€ããé¢ä¿ãååãããã³æ¿å
¥ããã¢ãžã¥ãŒã«ã瀺ããŸãã ã
å€éšãªã³ã±ãŒãž ãã¯ãçŸåšã®ã¢ãžã¥ãŒã«ã®å€éšã§é¢æ°ãå®çŸ©ã§ããããšãããã³/ãŸãã¯ã¢ãžã¥ãŒã«ã®å€éšã§åŒã³åºãããšãã§ããããšãæå³ããŸãã
"Name"
ã¯ãŠãŒã¶ãŒãæå®ããååãå®çŸ©ãã
"TheModule"
ã¯ãã®ååã
"TheModule"
æåããŒãã«ã«ç»é²ãããŠããããšã瀺ããŸãã
ååã®ç«¶åã«é¢ããŠã¯ãã¢ãžã¥ãŒã«ã®ã·ã³ãã«ããŒãã«ã¯ã·ã³ãã«ããŒãã«ã®æ©èœãšåãããã«æ©èœããŸãã以åã«ã·ã³ãã«ããŒãã«ã«è¿œå ãããååã§æ°ãã颿°ãäœæãããå Žåãã¢ãžã¥ãŒã«ã«è¿œå ããããšæé»çã«ååã倿ŽãããŸãã äžèšã®ã³ãŒãã¯ãã®äºå®ã䜿çšããŠãåã颿°ã以åã«å®£èšããããã©ããã倿ããŸãã
Kaleidoscopeã§ã¯ã颿°ã®åå®çŸ©ã¯2ã€ã®å ŽåããããŸãã ãŸãããããã¿ã€ããäžèŽããéãã颿°ã®
extern
å®çŸ©ãè€æ°å䜿çšããå ŽåïŒãã¹ãŠã®åŒæ°ãåãåã§ãããããåŒæ°ã®æ°ãäžèŽãããã©ããã確èªããã ãã§ãïŒã 第äºã«ã颿°ã®
extern
å®çŸ©ã䜿çšãããå Žåã¯ã
extern
å®çŸ©ã䜿çšããŸãã ããã¯ãçžäºã«ååž°çãªé¢æ°ãå®çŸ©ãããšãã«å¿
èŠã§ãã
ãããå®è£
ããããã«ãäžèšã®ã³ãŒãã¯æåã«é¢æ°åã®ç«¶åããããã©ããã確èªããŸãã ååšããå Žåã¯ãäœæãã颿°ãåé€ãïŒ
"getFunction"
ãåŒã³åºããŠïŒã次ã«
"getFunction"
ãåŒã³åºããŠãæå®ããååã®æ¢åã®é¢æ°ãååŸããŸãã LLVMã®å€ãã®APIã«ã¯
"erase"
圢åŒãš
"remove"
圢åŒã®äž¡æ¹ãããããšã«æ³šæããŠãã ããã
"remove"
ã¡ãœããã¯ã芪ãªããžã§ã¯ãïŒããšãã°ãã¢ãžã¥ãŒã«ã®é¢æ°ïŒãããªããžã§ã¯ããåãé¢ãïŒãªã³ã¯è§£é€ãïŒããããè¿ããŸãã
"erase"
ã¡ãœããã¯ããªããžã§ã¯ãããã¿ããïŒãªã³ã¯è§£é€ïŒããŠããåé€ããŸãã
äžèšã®æšè«ã確èªããããã«ããŸããæ¢åã®ãæ©èœãã空ãã§ããããšã確èªããŸãã ãã®å Žåãvoidã¯ããŒã¹ãããã¯ãã€ãŸã颿°ã®æ¬äœãå«ãŸããŠããªãããšãæå³ããŸãã 颿°ã«ããã£ãããå Žåãããã¯ç¹°ãè¿ã宣èšã§ããããããã®å Žåãã³ãŒããæåŠããŸãã åã®é¢æ°ã
"extern"
颿°ã§ããå ŽåãåŒæ°ã®æ°ãçŸåšã®å®çŸ©ã®åŒæ°ã®æ°ãšåçŽã«æ¯èŒããŸãã ããããäžèŽããªãå Žåããšã©ãŒã衚瀺ãããŸãã
颿°ãããã¿ã€ããåŠçããããã®ã³ãŒãã®æåŸã®éšåã¯ã颿°ãžã®åŒæ°ã®ã«ãŒãã§ã
NamedValues
ãªããžã§ã¯ãåã察å¿ããåŒæ°ãæå®ãã
NamedValues
ãããã«åŒæ°ãç»é²ããŠããã®åŸ
VariableExprAST
ASTããŒãã§äœ¿çšããŸãã æ¬¡ã«ã颿°ãªããžã§ã¯ããè¿ããŸãã ç«¶åããåŒæ°åïŒããšãã°ã
"extern Foo (aba)"
ïŒããã§ãã¯ããªãããšã«æ³šæããŠãã ããã ããããããã¯äžèšã§äœ¿çšããæ¹æ³ã䜿çšããŠãéåžžã«ç°¡åãã€ç°¡åã«è¡ãããšãã§ããŸãã
Function *FunctionAST::Codegen() { NamedValues.clear(); Function *TheFunction = Proto->Codegen(); if (TheFunction == 0) return 0;
颿°ãå®çŸ©ããããã®ã³ãŒãçæã¯éåžžã«ç°¡åã«éå§ãããŸãããããã¿ã€ãã³ãŒãçæïŒ
Proto
ïŒãåŒã³åºãããã¹ãŠãæ£åžžã§ããããšã確èªããŸãã ãŸããNamedValuesã«ãŒããã¯ãªã¢ããŠãåŠçäžã®æåŸã®é¢æ°ãæ®ã£ãŠããªãããšã確èªããŸãã ãããã¿ã€ãã³ãŒããçæãããšãå
ã«é²ãããšãã§ããæ¢è£œã®LLVMæ©èœãªããžã§ã¯ãã確ä¿ãããŸãã
次ã«ãBuilderã§ã®äœæ¥ã«é²ã¿ãŸãã æåã®è¡ã¯ãæ°ãã
åºæ¬ããã㯠[
en ]ïŒ
"entry"
ãšåŒã°ããïŒãäœæãããããTheFunctionã«æ¿å
¥ãããŸãã 2è¡ç®ã¯ãæ°ããããŒã¹ãŠãããã®æåŸã«æ°ããåœä»€ãæ¿å
¥ãããããšããã«ããŒã«äŒããŸãã LLVMã®åºæ¬ãããã¯ã¯
ãå¶åŸ¡ãããŒã°ã©ããå®çŸ©
ããæ©èœã®éèŠãªéšåã§ãã å¶åŸ¡ãããŒããŸã ãªãããã颿°ã«ã¯1ã€ã®ãããã¯ã®ã¿ãå«ãŸããŸãã ãããã第5ç« ã§ä¿®æ£ããŸã:)ã
if (Value *RetVal = Body->Codegen()) {
æ¿å
¥ãã€ã³ããèšå®ããããšãã«ãŒã颿°åŒã«
CodeGen()
ã䜿çšããŠã³ãŒãçæã
CodeGen()
ãŸãã ãšã©ãŒãçºçããªãå Žåãå
¥åãããã¯ã«åŒèšç®ã³ãŒãã远å ããèšç®ãããå€ãè¿ããŸãã æ¬¡ã«ããšã©ãŒããªãå Žåã
LLVMåœä»€"ret"
ãäœæãã颿°ã宿ãããŸãã 颿°ãäœæãããåŸãLLVMã«çµã¿èŸŒãŸãã
"verifyFunction"
ããã·ãŒãžã£ãåŒã³åºããŸãã çæãããã³ãŒãã«å¯ŸããŠããŸããŸãªäžè²«æ§ãã§ãã¯ãå®è¡ããã³ã³ãã€ã©ããã¹ãŠãæ£ããè¡ã£ãŠããããšã倿ããŸãã ãã®æé ã䜿çšããããšã¯éåžžã«éèŠã§ããå€ãã®ãã°ãæ€åºã§ããŸãã 颿°ãçµäºããŠæ€èšŒããããããããè¿ããŸãã
ãã®å°ããªéšåã¯ãšã©ãŒåŠççšã§ãã ç°¡åã«ããããã«ã
eraseFromParent
ã¡ãœããã䜿çšããŠãäœæããã颿°ã®ãã®åçŽãªåé€ãåŠçããŸãã ããã«ããããŠãŒã¶ãŒã¯ä»¥åã«èª€ã£ãŠå
¥åããã颿°ããªãŒããŒã©ã€ãã§ããŸããåé€ããªãã£ãå Žåãã·ã³ãã«ããŒãã«ã«æ¬äœãå«ãŸããå°æ¥ã®ãªãŒããŒã©ã€ããçŠæ¢ãããŸãã
å®éããã®ã³ãŒãã«ã¯ãã°ããããŸãã
"PrototypeAST:: Codegen"
ã¯ãäºåã«å®çŸ©ãããäºå宣èšãè¿ãããšãã§ããŸããã³ãŒãã¯å®éã«ããããåé€ã§ããŸãã ãã®ãã°ãä¿®æ£ããã«ã¯ããã€ãã®æ¹æ³ããããŸãããäœãæãä»ãããšãã§ããããèããŠãã ããïŒ ããã«å°ããªãã¹ãã±ãŒã¹ããããŸãïŒ
extern foo(ab); # o, "foo". def foo(ab) c; # , 'c'. def bar() foo(1, 2); # , "foo"
ã¡ã€ã³ããã°ã©ã ã®å€æŽãšæçµçãªèã
å®éããããŸã§ã®ãšãããLLVMã³ãŒãçæã¯å°ãè峿·±ããã®ã§ããããè峿·±ãIRåŒã³åºããèŠãããšãã§ããŸãã ã³ãŒãã¯ã颿°ãHandleDefinitionãããHandleExternããªã©ã§Codegenã䜿çšããŠã³ãŒãçæãåŒã³åºããLLVM IRããã³ãããŸãã ããã«ãããLLVM IRã§ç°¡åãªæ©èœã確èªã§ããŸãã äŸïŒ
ready> 4 + 5;
ãããã¬ãã«ã®åŒãèªãïŒ
ããã«@ ""ïŒïŒãå®çŸ©ãã{
ãšã³ããªãŒïŒ
ret double 9.000000e + 00
}
ããŒãµãŒããããã¬ãã«ã®åŒãå¿å颿°ãšããŠè¿ãæ¹æ³ã«æ³šç®ããŠãã ããã ããã¯ã次ã®ç« ã§JITãµããŒãã远å ãããšãã«äŸ¿å©ã§ãã ãŸããã³ãŒãã¯ãéåžžã«æåéãããããŸã£ãããã«ç¿»èš³ããããšã«æ³šæããŠãã ãã
IRBuilder
ã«ãã£ãŠè¡ããã宿°ã®åçŽãªæãããã¿ãé€ããŠãæé©åã¯è¡ãã
IRBuilder
ã æ¬¡ã®ç« ã§æç€ºçã«æé©åã远å ããŸãã
ready> def fooïŒabïŒa * a + 2 * a * b + b * b;
颿°å®çŸ©ã®èªã¿åãïŒ
ããã«@fooãå®çŸ©ïŒdoubleïŒ
aãdoubleïŒ
bïŒ{
ãšã³ããªãŒïŒ
ïŒ
multmp = fmul doubleïŒ
aãïŒ
a
ïŒ
multmp1 = fmul double 2.000000e + 00ãïŒ
a
ïŒ
multmp2 = fmul doubleïŒ
multmp1ãïŒ
b
ïŒ
addtmp = fadd doubleïŒ
multmpãïŒ
multmp2
ïŒ
multmp3 = fmul doubleïŒ
bãïŒ
b
ïŒ
addtmp4 = fadd doubleïŒ
addtmpãïŒ
multmp3
ret doubleïŒ
addtmp4
}
以äžã«ããã€ãã®ç°¡åãªç®è¡æŒç®ã瀺ããŸãã åœä»€ãäœæããããã«äœ¿çšããLLVM
Builder'
åŒã³åºããšã®é¡èãªé¡äŒŒç¹ã«æ³šæããŠãã ããã
ready> def barïŒaïŒfooïŒaã4.0ïŒ+ barïŒ31337ïŒ;
颿°å®çŸ©ã®èªã¿åãïŒ
ããã«@barïŒdoubleïŒ
aïŒ{
ãšã³ããªãŒïŒ
ïŒ
calltmp = call double @fooïŒdoubleïŒ
aãdouble 4.000000e + 00ïŒ
ïŒ
calltmp1 =ããã«@barãåŒã³åºãïŒããã«3.133700e + 04ïŒ
ïŒ
addtmp = fadd doubleïŒ
calltmpãïŒ
calltmp1
ret doubleïŒ
addtmp
}
以äžã«ããã€ãã®é¢æ°åŒã³åºãã瀺ããŸãã ãã®é¢æ°ãåŒã³åºããšãé·æéå®è¡ãããããšã«æ³šæããŠãã ããã å°æ¥çã«ã¯ãæ¡ä»¶ä»ããããŒå¶åŸ¡ã远å ããŠãååž°ãæ¬åœã«äŸ¿å©ã«ããŸã:)ã
ready> extern cosïŒxïŒ;
externãèªãïŒ
double @cosïŒdoubleïŒã宣èšããŸã
ready> cosïŒ1.234ïŒ;ãããã¬ãã«ã®åŒãèªãïŒ
ããã«@ ""ïŒïŒãå®çŸ©ãã{
ãšã³ããªãŒïŒ
ïŒ
calltmp = call double @cosïŒdouble 1.234000e + 00ïŒ
ret doubleïŒ
calltmp
}
ããã«
extern
ããã®ã¯ãã©ã€ãã©ãªé¢æ°
"cos"
ãšãã®åŒã³åºãã®å€éšã§ãã
æºåå®äº> ^ D
; ModuleID = 'ç§ã®ã¯ãŒã«ãªjit'
ããã«@ ""ïŒïŒãå®çŸ©ãã{
ãšã³ããªãŒïŒ
ïŒ
addtmp = fadd double 4.000000e + 00ã5.000000e + 00
ret doubleïŒ
addtmp
}
ããã«@fooãå®çŸ©ïŒdoubleïŒ
aãdoubleïŒ
bïŒ{
ãšã³ããªãŒïŒ
ïŒ
multmp = fmul doubleïŒ
aãïŒ
a
ïŒ
multmp1 = fmul double 2.000000e + 00ãïŒ
a
ïŒ
multmp2 = fmul doubleïŒ
multmp1ãïŒ
b
ïŒ
addtmp = fadd doubleïŒ
multmpãïŒ
multmp2
ïŒ
multmp3 = fmul doubleïŒ
bãïŒ
b
ïŒ
addtmp4 = fadd doubleïŒ
addtmpãïŒ
multmp3
ret doubleïŒ
addtmp4
}
ããã«@barïŒdoubleïŒ
aïŒ{
ãšã³ããªãŒïŒ
ïŒ
calltmp = call double @fooïŒdoubleïŒ
aãdouble 4.000000e + 00ïŒ
ïŒ
calltmp1 =ããã«@barãåŒã³åºãïŒããã«3.133700e + 04ïŒ
ïŒ
addtmp = fadd doubleïŒ
calltmpãïŒ
calltmp1
ret doubleïŒ
addtmp
}
double @cosïŒdoubleïŒã宣èšããŸã
ããã«@ ""ïŒïŒãå®çŸ©ãã{
ãšã³ããªãŒïŒ
ïŒ
calltmp = call double @cosïŒdouble 1.234000e + 00ïŒ
ret doubleïŒ
calltmp
}
çŸåšã®ãã¢ãçµäºãããšãçæãããã¢ãžã¥ãŒã«å
šäœã®IRãã³ããè¿ãããŸãã
ããã§ã¯ããã¹ãŠã®æ©èœãçžäºã«åç
§ãåã£ãå
šäœåãèŠãããšãã§ããŸããããã§ãäžè¯é¡ãã¥ãŒããªã¢ã«ã®ç¬¬3ç« ã¯çµããã§ããæ¬¡ã®ç« ã§ã¯ãJITãµããŒããšãªããã£ãã€ã¶ãŒã远å ããŠãå®éã«ã³ãŒãã®å®è¡ãéå§ã§ããããã«ããŸãïŒå®å
šãªã³ãŒããªã¹ã
ããã«ãæ¡åŒµLLVMã³ãŒããžã§ãã¬ãŒã¿ãŒãªã©ãäœæ¥äŸã®å®å
šãªã³ãŒããªã¹ãã瀺ããŸããLLVMã©ã€ãã©ãªã䜿çšããŠãããããããããã³ãŒãã«ãªã³ã¯ããå¿
èŠããããŸãããããè¡ãã«ã¯ãllvm-configããŒã«ã次ã®ããã«äœ¿çšããŸãã#
g++ -g -O3 toy.cpp `llvm-config --cppflags --ldflags --libs core` -o toy
#
./toy
ãããŠæåŸã«ãã³ãŒãèªäœïŒ #include "llvm/DerivedTypes.h" #include "llvm/LLVMContext.h" #include "llvm/Module.h" #include "llvm/Analysis/Verifier.h" #include "llvm/Support/IRBuilder.h" #include <cstdio> #include <string> #include <map> #include <vector> using namespace llvm; //===----------------------------------------------------------------------===// // Lexer ( ) //===----------------------------------------------------------------------===// // [0-255], , // enum Token { tok_eof = -1, // ( ) tok_def = -2, tok_extern = -3, // ( : , ) tok_identifier = -4, tok_number = -5 }; static std::string IdentifierStr; // , tok_identifier static double NumVal; // , tok_number /// gettok - . static int gettok() { static int LastChar = ' '; // . while (isspace(LastChar)) LastChar = getchar(); if (isalpha(LastChar)) { // : [a-zA-Z][a-zA-Z0-9]* IdentifierStr = LastChar; while (isalnum((LastChar = getchar()))) IdentifierStr += LastChar; if (IdentifierStr == "def") return tok_def; if (IdentifierStr == "extern") return tok_extern; return tok_identifier; } if (isdigit(LastChar) || LastChar == '.') { // : [0-9.]+ std::string NumStr; do { NumStr += LastChar; LastChar = getchar(); } while (isdigit(LastChar) || LastChar == '.'); NumVal = strtod(NumStr.c_str(), 0); return tok_number; } if (LastChar == '#') { // do LastChar = getchar(); while (LastChar != EOF && LastChar != '\n' && LastChar != '\r'); if (LastChar != EOF) return gettok(); } // . if (LastChar == EOF) return tok_eof; // ASCII int ThisChar = LastChar; LastChar = getchar(); return ThisChar; } //===----------------------------------------------------------------------===// // Abstract Syntax Tree ( ) //===----------------------------------------------------------------------===// /// ExprAST - . class ExprAST { public: virtual ~ExprAST() {} virtual Value *Codegen() = 0; }; /// NumberExprAST - (, "1.0"). class NumberExprAST : public ExprAST { double Val; public: NumberExprAST(double val) : Val(val) {} virtual Value *Codegen(); }; /// VariableExprAST - (, "a"). class VariableExprAST : public ExprAST { std::string Name; public: VariableExprAST(const std::string &name) : Name(name) {} virtual Value *Codegen(); }; /// BinaryExprAST - . class BinaryExprAST : public ExprAST { char Op; ExprAST *LHS, *RHS; public: BinaryExprAST(char op, ExprAST *lhs, ExprAST *rhs) : Op(op), LHS(lhs), RHS(rhs) {} virtual Value *Codegen(); }; /// CallExprAST - . class CallExprAST : public ExprAST { std::string Callee; std::vector<ExprAST*> Args; public: CallExprAST(const std::string &callee, std::vector<ExprAST*> &args) : Callee(callee), Args(args) {} virtual Value *Codegen(); }; /// PrototypeAST - "" , /// (, , /// ). class PrototypeAST { std::string Name; std::vector<std::string> Args; public: PrototypeAST(const std::string &name, const std::vector<std::string> &args) : Name(name), Args(args) {} Function *Codegen(); }; /// FunctionAST - class FunctionAST { PrototypeAST *Proto; ExprAST *Body; public: FunctionAST(PrototypeAST *proto, ExprAST *body) : Proto(proto), Body(body) {} Function *Codegen(); }; //===----------------------------------------------------------------------===// // Parser ( ) //===----------------------------------------------------------------------===// /// CurTok/getNextToken - . CurTok - /// , . getNextToken /// CurTok. static int CurTok; static int getNextToken() { return CurTok = gettok(); } /// BinopPrecedence - static std::map<char, int> BinopPrecedence; /// GetTokPrecedence - . static int GetTokPrecedence() { if (!isascii(CurTok)) return -1; // , . int TokPrec = BinopPrecedence[CurTok]; if (TokPrec <= 0) return -1; return TokPrec; } /// Error* - . ExprAST *Error(const char *Str) { fprintf(stderr, "Error: %s\n", Str);return 0;} PrototypeAST *ErrorP(const char *Str) { Error(Str); return 0; } FunctionAST *ErrorF(const char *Str) { Error(Str); return 0; } static ExprAST *ParseExpression(); /// identifierexpr /// ::= identifier /// ::= identifier '(' expression* ')' static ExprAST *ParseIdentifierExpr() { std::string IdName = IdentifierStr; getNextToken(); // . if (CurTok != '(') // . return new VariableExprAST(IdName); // . getNextToken(); // ( std::vector<ExprAST*> Args; if (CurTok != ')') { while (1) { ExprAST *Arg = ParseExpression(); if (!Arg) return 0; Args.push_back(Arg); if (CurTok == ')') break; if (CurTok != ',') return Error("Expected ')' or ',' in argument list"); getNextToken(); } } // ')'. getNextToken(); return new CallExprAST(IdName, Args); } /// numberexpr ::= number static ExprAST *ParseNumberExpr() { ExprAST *Result = new NumberExprAST(NumVal); getNextToken(); // return Result; } /// parenexpr ::= '(' expression ')' static ExprAST *ParseParenExpr() { getNextToken(); // (. ExprAST *V = ParseExpression(); if (!V) return 0; if (CurTok != ')') return Error("expected ')'"); getNextToken(); // ). return V; } /// primary /// ::= identifierexpr /// ::= numberexpr /// ::= parenexpr static ExprAST *ParsePrimary() { switch (CurTok) { default: return Error("unknown token when expecting an expression"); case tok_identifier: return ParseIdentifierExpr(); case tok_number: return ParseNumberExpr(); case '(': return ParseParenExpr(); } } /// binoprhs /// ::= ('+' primary)* static ExprAST *ParseBinOpRHS(int ExprPrec, ExprAST *LHS) { // , while (1) { int TokPrec = GetTokPrecedence(); // , // , if (TokPrec < ExprPrec) return LHS; // , , . int BinOp = CurTok; getNextToken(); // // ExprAST *RHS = ParsePrimary(); if (!RHS) return 0; // BinOp RHS , RHS, // RHS LHS. int NextPrec = GetTokPrecedence(); if (TokPrec < NextPrec) { RHS = ParseBinOpRHS(TokPrec+1, RHS); if (RHS == 0) return 0; } // LHS/RHS. LHS = new BinaryExprAST(BinOp, LHS, RHS); } } /// expression /// ::= primary binoprhs /// static ExprAST *ParseExpression() { ExprAST *LHS = ParsePrimary(); if (!LHS) return 0; return ParseBinOpRHS(0, LHS); } /// prototype /// ::= id '(' id* ')' static PrototypeAST *ParsePrototype() { if (CurTok != tok_identifier) return ErrorP("Expected function name in prototype"); std::string FnName = IdentifierStr; getNextToken(); if (CurTok != '(') return ErrorP("Expected '(' in prototype"); // . std::vector<std::string> ArgNames; while (getNextToken() == tok_identifier) ArgNames.push_back(IdentifierStr); if (CurTok != ')') return ErrorP("Expected ')' in prototype"); // . getNextToken(); // ')'. return new PrototypeAST(FnName, ArgNames); } /// definition ::= 'def' prototype expression static FunctionAST *ParseDefinition() { getNextToken(); // def. PrototypeAST *Proto = ParsePrototype(); if (Proto == 0) return 0; if (ExprAST *E = ParseExpression()) return new FunctionAST(Proto, E); return 0; } /// toplevelexpr ::= expression static FunctionAST *ParseTopLevelExpr() { if (ExprAST *E = ParseExpression()) { // . PrototypeAST *Proto = new PrototypeAST("", std::vector<std::string>()); return new FunctionAST(Proto, E); } return 0; } /// external ::= 'extern' prototype static PrototypeAST *ParseExtern() { getNextToken(); // extern. return ParsePrototype(); } //===----------------------------------------------------------------------===// // Code Generation () //===----------------------------------------------------------------------===// static Module *TheModule; static IRBuilder<> Builder(getGlobalContext()); static std::map<std::string, Value*> NamedValues; Value *ErrorV(const char *Str) { Error(Str); return 0; } Value *NumberExprAST::Codegen() { return ConstantFP::get(getGlobalContext(), APFloat(Val)); } Value *VariableExprAST::Codegen() { // . Value *V = NamedValues[Name]; return V ? V : ErrorV("Unknown variable name"); } Value *BinaryExprAST::Codegen() { Value *L = LHS->Codegen(); Value *R = RHS->Codegen(); if (L == 0 || R == 0) return 0; switch (Op) { case '+': return Builder.CreateFAdd(L, R, "addtmp"); case '-': return Builder.CreateFSub(L, R, "subtmp"); case '*': return Builder.CreateFMul(L, R, "multmp"); case '<': L = Builder.CreateFCmpULT(L, R, "cmptmp"); // 0 1 0.0 1.0 return Builder.CreateUIToFP(L, Type::getDoubleTy(getGlobalContext()), "booltmp"); default: return ErrorV("invalid binary operator"); } } Value *CallExprAST::Codegen() { // . Function *CalleeF = TheModule->getFunction(Callee); if (CalleeF == 0) return ErrorV("Unknown function referenced"); // . 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() == 0) return 0; } return Builder.CreateCall(CalleeF, ArgsV.begin(), ArgsV.end(), "calltmp"); } Function *PrototypeAST::Codegen() { // : double(double,double) .. std::vector<const Type*> Doubles(Args.size(), Type::getDoubleTy(getGlobalContext())); FunctionType *FT = FunctionType::get(Type::getDoubleTy(getGlobalContext()), Doubles, false); Function *F = Function::Create(FT, Function::ExternalLinkage, Name, TheModule); // (F) , 'Name'. // , . if (F->getName() != Name) { // , . F->eraseFromParent(); F = TheModule->getFunction(Name); // (F) , . if (!F->empty()) { ErrorF("redefinition of function"); return 0; } // (F) , . if (F->arg_size() != Args.size()) { ErrorF("redefinition of function with different # args"); return 0; } } // . unsigned Idx = 0; for (Function::arg_iterator AI = F->arg_begin(); Idx != Args.size(); ++AI, ++Idx) { AI->setName(Args[Idx]); // . NamedValues[Args[Idx]] = AI; } return F; } Function *FunctionAST::Codegen() { NamedValues.clear(); Function *TheFunction = Proto->Codegen(); if (TheFunction == 0) return 0; // . BasicBlock *BB = BasicBlock::Create(getGlobalContext(), "entry", TheFunction); Builder.SetInsertPoint(BB); if (Value *RetVal = Body->Codegen()) { // . Builder.CreateRet(RetVal); // , (). verifyFunction(*TheFunction); return TheFunction; } // , . TheFunction->eraseFromParent(); return 0; } //===----------------------------------------------------------------------===// // Top-Level parsing ( ) JIT //===----------------------------------------------------------------------===// static void HandleDefinition() { if (FunctionAST *F = ParseDefinition()) { if (Function *LF = F->Codegen()) { fprintf(stderr, "Read function definition:"); LF->dump(); } } else { // . getNextToken(); } } static void HandleExtern() { if (PrototypeAST *P = ParseExtern()) { if (Function *F = P->Codegen()) { fprintf(stderr, "Read extern: "); F->dump(); } } else { // . getNextToken(); } } static void HandleTopLevelExpression() { // Evaluate a top-level expression into an anonymous function. if (FunctionAST *F = ParseTopLevelExpr()) { if (Function *LF = F->Codegen()) { fprintf(stderr, "Read top-level expression:"); LF->dump(); } } else { // . getNextToken(); } } /// top ::= definition | external | expression | ';' static void MainLoop() { while (1) { fprintf(stderr, "ready> "); switch (CurTok) { case tok_eof: return; case ';': getNextToken(); break; // . case tok_def: HandleDefinition(); break; case tok_extern: HandleExtern(); break; default: HandleTopLevelExpression(); break; } } } //===----------------------------------------------------------------------===// // "" , // ("extern") . //===----------------------------------------------------------------------===// /// putchard - 0. extern "C" double putchard(double X) { putchar((char)X); return 0; } //===----------------------------------------------------------------------===// // Main driver code ( ) //===----------------------------------------------------------------------===// int main() { LLVMContext &Context = getGlobalContext(); // . // 1 - . BinopPrecedence['<'] = 10; BinopPrecedence['+'] = 20; BinopPrecedence['-'] = 20; BinopPrecedence['*'] = 40; // . fprintf(stderr, "ready> "); getNextToken(); // , . TheModule = new Module("my cool jit", Context); // " ". MainLoop(); // . TheModule->dump(); return 0; }