ãã¥ãŒããªã¢ã«ãLLVMã䜿çšããããã°ã©ãã³ã°èšèªã®äœæãã®ç¬¬4ç« ã«ããããã åã®ç« ïŒ
1ã2ã3ïŒã§ã¯ãæãåçŽãªããã°ã©ãã³ã°èšèªã®å®è£
ãšãLLVM IRçæã®ãµããŒãã®è¿œå ã«ã€ããŠèª¬æããŸããã ãã®ç« ã§ã¯ããªããã£ãã€ã¶ãµããŒãã®è¿œå ãšJITã³ã³ãã€ã©ãµããŒãã®è¿œå ãšãã2ã€ã®æ°ããææ³ã«ã€ããŠèª¬æããŸãã ãããã®ã¢ããªã³ã¯ãKaleidoscopeããã°ã©ãã³ã°èšèªçšã®åªããå¹ççãªã³ãŒããååŸããæ¹æ³ã瀺ããŸãã
å®æ°ã®æãåçŽãªæãããã¿ïŒå®æ°ã®æãããã¿ïŒ
第3ç« ã®ãã¢ã¯ãšã¬ã¬ã³ãã§ç°¡åã«æ¡åŒµã§ããŸãã æ®å¿µãªãããå®ç§ãªã³ãŒããšã¯ã»ã©é ããã®ã§ãã ãã ããIRBuilderã¯ãåçŽãªã³ãŒããã³ã³ãã€ã«ããéã«æãããªæé©åãæäŸããŸãã
ready> def test(x) 1+2+x; Read function definition: define double @test(double %x) { entry: %addtmp = fadd double 3.000000e+00, %x ret double %addtmp }
ãã®ã³ãŒãã¯ãå
¥åã®è§£æã«ãã£ãŠæ§ç¯ãããASTã®æåéãã®è»¢åã§ã¯ãããŸããã ãã以å€ã®å Žåã次ã®ããã«ãªããŸãã
ready> def testïŒxïŒ1 + 2 + x;
é¢æ°å®çŸ©ã®èªã¿åãïŒ
äºé@testïŒdoubleïŒ
xïŒãå®çŸ©ãã{
ãšã³ããªãŒïŒ
ïŒ
addtmp = fadd double 2.000000e + 00ã1.000000e + 00
ïŒ
addtmp1 = fadd doubleïŒ
addtmpãïŒ
x
ret doubleïŒ
addtmp1
}
äžã§èŠãããã«ãå®æ°ã®
æãããã¿ã¯éåžžã«é »ç¹ã«äœ¿çšãããéåžžã«éèŠãªæé©åã§ããå€ãã®ããã°ã©ãã³ã°èšèªéçºè
ãASTã§å®æ°ã®æãããã¿ããµããŒãããã»ã©ã§ãã
LLVMã§ã¯ãLLVM IRããã«ããããã¹ãŠã®åŒã³åºãã
LLVM IR Builder
ãééãããããASTã§ãµããŒããå®è£
ããå¿
èŠã¯ãããŸãã
LLVM IR Builder
èªäœã¯ãå®æ°ãæããããããšãã§ãããã©ããããã§ãã¯ããŸãã åã«å®æ°ãæãããã¿ã代ããã«æ°ããå®æ°ãè¿ããŸãã æ瀺ãäœæããŸãã
ãŸããããã¯ç°¡åã§ãã:)ã å®éã«ã¯ãã³ãŒããçæãããšãã¯åžžã«
IRBuilder
ã䜿çšããããšããå§ãããŸãã 䜿çšæã«ãæ§æãªãŒããŒããããã¯ãããŸããïŒã©ãã§ãå®æ°ãã§ãã¯ã§ã³ã³ãã€ã©ãŒãæãªãå¿
èŠã¯ãããŸããïŒãå Žåã«ãã£ãŠã¯ãçæãããLLVM IRã®éã倧å¹
ã«æžããããšãã§ããŸãïŒç¹ã«ãã¯ãããã»ããµãåããèšèªãŸãã¯å€ãã®å®æ°ã䜿çšããèšèªã®å ŽåïŒã
äžæ¹ã
IRBuilder
ãã³ãŒãã®ãã¹ãŠã®åæãããã®ãŸãŸããã€ãŸãããã§ã«ãã«ããããã³ãŒãã§å®è¡ãããšããäºå®ã«ãã£ãŠå¶éãããŠããŸãã å°ãè€éãªäŸãåãäžãããšïŒ
ready> def testïŒxïŒïŒ1 + 2 + xïŒ*ïŒx +ïŒ1 + 2ïŒïŒ;
ready>é¢æ°å®çŸ©ã®èªã¿åãïŒ
äºé@testïŒdoubleïŒ
xïŒãå®çŸ©ãã{
ãšã³ããªãŒïŒ
ïŒ
addtmp = fadd double 3.000000e + 00ãïŒ
x
ïŒ
addtmp1 = fadd doubleïŒ
xã3.000000e + 00
ïŒ
multmp = fmul doubleïŒ
addtmpãïŒ
addtmp1
ret doubleïŒ
multmp
}
ãã®å Žåãäœåã®å·Šå³ã®éšåã¯åãå€ã§ãã ãtmp = x + 3; result = tmp * tmp;âããã«ã³ã³ãã¥ãŒãã£ã³ã°ã®ä»£ããã«â x + 3âã
æ®å¿µãªãããããŒã«ã«åæã§ã¯ãããæ€åºããŠä¿®æ£ããããšã¯ã§ããŸããã ããã«ã¯ã2ã€ã®å€æãå¿
èŠã§ããåŒã®åé¢é£ä»ãïŒåå¥ã®ã¢ã€ãã³ãã£ãã£ãè¿œå ããïŒãšãå
±éã®éšååŒã®åé€ïŒ
Common Subexpression EliminationãCSE ïŒã«ãããäœåãªè¿œå åœä»€ãåé€ãããŸãã 幞ããªããšã«ãLLVMã¯ããã»ãŒãžãšããŠäœ¿çšã§ããå¹
åºãæé©åãæäŸããŸãã
LLVMæé©åãã¹
LLVMã¯ãããŸããŸãªããšãå®è¡ããããŸããŸãªãã¬ãŒããªãã䌎ãæé©åãã¹ãå€æ°æäŸããŸãã ä»ã®ã·ã¹ãã ãšã¯ç°ãªããLLVMã«ã¯ã1çµã®æé©åããã¹ãŠã®èšèªã«é©åã§ãããããããå Žé¢ã«é©ããŠãããšãã誀ã£ãèããåãå
¥ããå ŽæããããŸããã LLVMã䜿çšãããšãã³ã³ãã€ã©ãŒããšã°ãŒãã¥ãŒã¿ãŒãšããŠäœ¿çšããŠã䜿çšããæé©åãé åºãç¶æ³ãå®å
šã«æ±ºå®ã§ããŸãã
LLVMã¯ããã¢ãžã¥ãŒã«ãééãããå®å
šãªãã¹ãšãæ®ããèæ
®ããã«1ã€ã®æ©èœã ãã§æ©èœãããæ©èœãééããããã¹ã®äž¡æ¹ããµããŒãããçµã¿èŸŒã¿ãŸãã ããã»ãŒãžãšãã®ä»çµã¿ã®è©³çŽ°ã«ã€ããŠã¯ãããã¥ã¡ã³ã
ããã¹ãš
LLVM ãã¹ ãªã¹ãã
èšè¿°ãã æ¹æ³ããåç
§ããŠãã ããã
Kaleidoscopeã®å ŽåãçŸåšããªã³ã¶ãã©ã€é¢æ°ãçæããŠããŸãããŠãŒã¶ãŒãå
¥åãããšãäžåºŠã«1ã€ãã€çæãããŸãã ç§ãã¡ã®ç®æšã¯ãçŸåšã®åœ¢åŒã§æé©åãæ倧éã«æŽ»çšããããšã§ã¯ãããŸããããããã«ãããããããç°¡åã§é«éãªã³ãŒããååŸããããšèããŠããŸãã ãããã£ãŠããŠãŒã¶ãŒãå
¥åãããæ©èœã«å¿ããŠãããã€ãã®æé©åãéžæããŸãã ãéçãªKaleidoscopeã³ã³ãã€ã©ããäœæããå Žåããã¡ã€ã«å
šäœã解æããããŸã§ãªããã£ãã€ã¶ãŒã®èµ·åãé
ãããããšãé€ããŠãã»ãŒåãã³ãŒãã䜿çšããŸãã
æ©èœçãªæé©åãåŸãããã«ãäœæããå¿
èŠããããŸã
FunctionPassManager
å®è¡ããLLVMæé©åãä¿åããã³æŽçãã
FunctionPassManager
ã 次ã«ãå®è¡ããæé©åã®ã»ãããè¿œå ã§ããŸãã ã³ãŒãã¯æ¬¡ã®ãšããã§ãã
FunctionPassManager OurFPM(TheModule);
ãã®ã³ãŒãã¯ã
"OurFPM"
ãšããååã®
FunctionPassManager
å®çŸ©ããŸãã äœæãããšãã¯ãã¢ãžã¥ãŒã«ã«ãã€ã³ã¿ãŒãæž¡ãå¿
èŠããããŸãã ãããå®äºããããäžé£ã®
"add"
åŒã³åºãã䜿çšããŠLLVMãã¹ãè¿œå ããŸãã ã»ãšãã©ã®å Žåãæåã®ãã¹ã¯å®åçãªãã®ã§ãããåŸç¶ã®æé©åã§ããã°ã©ã ã§äœ¿çšãããããŒã¿æ§é ããããããã«ããå¿
èŠããããŸãã å€æ°
"TheExecutionEngine"
ã¯ã次ã®ã»ã¯ã·ã§ã³ã§ååŸããJITã«é¢é£ä»ããããŠããŸãã
ãã®å Žåã4ã€ã®æé©åãã¹ãè¿œå ããããšã«ããŸããã éžæããããã»ãŒãžã¯ãåºç¯ãªã³ãŒãã«åœ¹ç«ã€ãã¯ãªãŒãã³ã°ãæé©åã®ããªãæšæºçãªã»ããã§ãã ç§ã¯åœŒããäœãããã®ããæ·±ãã¯è¿°ã¹ãŸããããç§ãä¿¡ããŠãã ããã圌ãã¯è¯ãåºçºç¹ã§ã:)
PassManager
ã»ããã¢ããã
PassManager
ã䜿çšããå¿
èŠããããŸãã ïŒ
FunctionAST::Codegen
ïŒæ°ããé¢æ°ãçæããåŸããŠãŒã¶ãŒã«æ»ãåã«å®è¡ããŸãã
if (Value *RetVal = Body->Codegen()) {
return TheFunction; }
ã芧ã®ãšãããããã¯éåžžã«ç°¡åã§ãã
FunctionPassManager
LLVM Function*
æé©åããããã«æŽæ°ããé¢æ°ã®æ¬äœãæ¹åããŸãïŒæ¬åœã«ããããããšãæã¿ãŸãïŒã ã³ãŒããããäžåºŠãã¹ãããŠã¿ãŠãã ããã
ready> def testïŒxïŒïŒ1 + 2 + xïŒ*ïŒx +ïŒ1 + 2ïŒïŒ;
ready>é¢æ°å®çŸ©ã®èªã¿åãïŒ
äºé@testïŒdoubleïŒ
xïŒãå®çŸ©ãã{
ãšã³ããªãŒïŒ
ïŒ
addtmp = fadd doubleïŒ
xã3.000000e + 00
ïŒ
multmp = fmul doubleïŒ
addtmpãïŒ
addtmp
ret doubleïŒ
multmp
}
äºæ³ã©ãããè¿œå çµæãšãã®åå©çšãä¿åããæé©åãããã³ãŒããäœæãããŸããã
LLVMã¯ãç¹å®ã®ç¶æ³ã§äœ¿çšã§ããå¹
åºãæé©åãæäŸããŸãã ããŸããŸãªéè·¯ã«é¢ãã
ããã€ãã®ããã¥ã¡ã³ããå©çšå¯èœã§ãããå®å
šã§ã¯ãããŸããã ã¢ã€ãã¢ã®ãã1ã€ã®è¯ãæ
å ±æºã¯ãllvm-gccãŸãã¯llvm-ldã䜿çšããããã»ãŒãžã調ã¹ãããšã§ãã optããŒã«ã䜿çšãããšãã³ãã³ãã©ã€ã³ããã»ãŒãžãè©ŠããŠããããã®æ©èœã確èªã§ããŸãã
ããã³ããšã³ãããããªãè¯ãã³ãŒããåŸãããã®ã§ããã®å®è£
ã«ã€ããŠè©±ããŸãããïŒ
JITã³ã³ãã€ã©ãŒã®è¿œå
LLVM IRã§å©çšå¯èœãªã³ãŒãã«ã¯ãããŸããŸãªããŒã«ãé©çšã§ããŸãã ããšãã°ãïŒäžèšã§è¡ã£ãããã«ïŒæé©åãå®è¡ããããããã¹ããŸãã¯ãã€ããªåœ¢åŒã§åºåãããããã©ãããã©ãŒã çšã«ã¢ã»ã³ãã©ãŒLLVMïŒ.sïŒãã¡ã€ã«ã§ã³ãŒããã³ã³ãã€ã«ããããJIT-ãé©çšãããã§ããŸããã³ã³ãã€ã«ã LLVM IRãã¥ãŒã®çŽ æŽããããšããã¯ãã³ã³ãã€ã©ã®ããŸããŸãªéšåã®éã§ãåäžãã§ããããšã§ãã
ãã®ã»ã¯ã·ã§ã³ã§ã¯ãã€ã³ã¿ãŒããªã¿ãŒçšã®JITã³ã³ãã€ã«ãµããŒããè¿œå ããŸãã Kaleidoscopeã®äž»ãªã¢ã€ãã¢ã¯ããŠãŒã¶ãŒãé¢æ°ãŸãã¯ãããã¬ãã«ã®åŒãå
¥åããŠãããã«çµæãååŸã§ããããšã§ãã ããšãã°ãã1 + 2;ããšå
¥åããå Žåã3ãèšç®ããŠåºåããå¿
èŠããããé¢æ°ãå®çŸ©ããå Žåãã³ãã³ãã©ã€ã³ããåŒã³åºãããšãã§ããŸãã
æåã«ãJITã宣èšããŠåæåããŸãã ããã¯ãã°ããŒãã«å€æ°ãè¿œå ããŠ
main
åŒã³åºãããšã§å®è¡ãããŸãã
static ExecutionEngine *TheExecutionEngine;
... int main() { ..
.. }
ããã«ãããæœè±¡çãª
"Execution Engine"
ãäœæãããŸããããã¯ãã³ã³ãã€ã©ãŒãŸãã¯LLVMã€ã³ã¿ãŒããªã¿ãŒã®ããããã§ãã LLVMã¯ããã©ãããã©ãŒã ã«JITã³ã³ãã€ã©ãååšããå Žåã¯èªåçã«éžæããŸããååšããªãå Žåã¯ãã€ã³ã¿ããªã¿ã«æ»ããŸãã
ExecutionEngine
äœæãããšãJITã䜿çšããæºåãæŽããŸãã ããŸããŸãªäŸ¿å©ãªAPIããããŸãããæãåçŽãªã®ã¯
"getPointerToFunction(F)"
ã¡ãœããã§ãã ãã®ã¡ãœããã¯ãæå®ãããLLVMé¢æ°ãJITã³ã³ãã€ã«ããçæããããã·ã³ã³ãŒããžã®é¢æ°ãã€ã³ã¿ãŒãè¿ããŸãã ãã®å Žåãããã¯ããããã¬ãã«ã®åŒã解æããã³ãŒãã次ã®ããã«å€æŽã§ããããšãæå³ããŸãã
static void HandleTopLevelExpression() {
}
ãããã¬ãã«ã®åŒã¯ãåŒæ°ãåããå®æ°ãè¿ãèªåŸçãªå¿åLLVMé¢æ°ãšããŠè¡šçŸããŠããããšãæãåºããŠãã ããã ãã€ãã£ããã©ãããã©ãŒã ã§LLVM JITã³ã³ãã€ã©ã䜿çšããŠãããããçµæãé¢æ°åã«ãã£ã¹ããããã®é¢æ°ãçŽæ¥åŒã³åºãããšãã§ããŸãã ããã¯ãJITã§ã³ã³ãã€ã«ãããã³ãŒããšãã¢ããªã±ãŒã·ã§ã³ã«éçã«ãªã³ã¯ãããŠãããã·ã³ã³ãŒãã®éã«éãããªãããšãæå³ããŸãã
ããã2ã€ã®å€æŽã«ãããã«ã¬ã€ãã¹ã³ãŒããæ©èœããããšãããããŸããïŒ
ready> 4 + 5;
ããã«@ ""ïŒïŒãå®çŸ©ãã{
ãšã³ããªãŒïŒ
ret double 9.000000e + 00
}
9.000000ã«è©äŸ¡
çŽ æŽããããããã¯åäœããããã«èŠããŸãã é¢æ°ã®ãã³ãã¯ããdoubleãè¿ãåŒæ°ãæããªãé¢æ°ãã瀺ããŠããŸããããã¯ãå
¥åãããåé«ã¬ãã«åŒã«å¯ŸããŠåæãããŸãã ããã¯åºæ¬çãªæ©èœã®ã¿ã®ãã¢ã³ã¹ãã¬ãŒã·ã§ã³ã§ãããããã«å€ãã®ããšãå®è¡ã§ããŸããïŒ
ready> def testfuncïŒxyïŒx + y * 2;
é¢æ°å®çŸ©ã®èªã¿åãïŒ
ããã«@testfuncïŒdoubleïŒ
xãdoubleïŒ
yïŒãå®çŸ©ãã{
ãšã³ããªãŒïŒ
ïŒ
multmp = fmul doubleïŒ
yã2.000000e + 00
ïŒ
addtmp = fadd doubleïŒ
multmpãïŒ
x
ret doubleïŒ
addtmp
}
ready> testfuncïŒ4ã10ïŒ;ããã«@ ""ïŒïŒãå®çŸ©ãã{
ãšã³ããªãŒïŒ
ïŒ
calltmp = call double @testfuncïŒdouble 4.000000e + 00ãdouble 1.000000e + 01ïŒ
ret doubleïŒ
calltmp
}
24.000000ã«è©äŸ¡
ããã¯ãã«ã¹ã¿ã ã³ãŒããå®è¡ã§ããããšã瀺ããŠããŸããã埮åŠãªç¹ã1ã€ãããŸãã
testfunc
ãåŒã³åºãå¿åé¢æ°ã§JITãåŒã³åºããŸãããtestfuncèªäœã§ã¯æ±ºããŠåŒã³åºããªãããšã«æ³šæããŠãã ããã å®éããã¹ãŠã®éå¿åé¢æ°ã®JITã¯ã
getPointerToFunction()
ããæ»ãåã«æšç§»çã«åŒã³åºãããå¿åé¢æ°ããã³ã³ãã€ã«ãããŸãã
JITã¯ããã·ã³ã«å²ãåœãŠãããã¡ã¢ãªã®è§£æŸãããããæŽæ°ããããã®é¢æ°ã®åã³ã³ãã€ã«ãªã©ã®ããã«ãä»ã®å€ãã®ããé«åºŠãªã€ã³ã¿ãŒãã§ãŒã¹ãæäŸããŸãã ãã ãããã®åçŽãªã³ãŒãã®å©ããåããŠããé©ãã»ã©åŒ·åãªæ©èœãåŸãããŸã-ãããæ€èšŒããŸãïŒã¢ã€ãã¢ãèŠããããã«å¿åé¢æ°ã®ãã³ããåé€ããŸãã:)ïŒ
ready> extern sinïŒxïŒ;
externãèªãïŒ
double @sinïŒdoubleïŒã宣èšããŸã
ready> extern cosïŒxïŒ; externãèªãïŒ
double @cosïŒdoubleïŒã宣èšããŸã
ready> sinïŒ1.0ïŒ; 0.841471ã«è©äŸ¡
ready> def fooïŒxïŒsinïŒxïŒ* sinïŒxïŒ+ cosïŒxïŒ* cosïŒxïŒ;é¢æ°å®çŸ©ã®èªã¿åãïŒ
ããã«@fooïŒdoubleïŒ
xïŒãå®çŸ©ãã{
ãšã³ããªãŒïŒ
ïŒ
calltmp = call double @sinïŒdoubleïŒ
xïŒ
ïŒ
multmp = fmul doubleïŒ
calltmpãïŒ
calltmp
ïŒ
calltmp2 =ããã«@cosãåŒã³åºãïŒdoubleïŒ
xïŒ
ïŒ
multmp4 = fmul doubleïŒ
calltmp2ãïŒ
calltmp2
ïŒ
addtmp = fadd doubleïŒ
multmpãïŒ
multmp4
ret doubleïŒ
addtmp
}
ready> fooïŒ4.0ïŒ; 1.000000ã«è©äŸ¡
ãããŒãJITã¯ã©ã®ããã«
sin
ãš
cos
ã«ã€ããŠåŠã³ãŸããã çãã¯é©ãã»ã©ç°¡åã§ãããã®äŸã§ã¯ãJITãé¢æ°ã®å®è¡ãéå§ããé¢æ°åŒã³åºãã«å°éããŸããã 圌ã¯ãé¢æ°ããŸã JITã«ãã£ãŠã³ã³ãã€ã«ãããŠããªãããšã«æ°ä»ããé¢æ°ãè©äŸ¡ããããã®æšæºçãªäžé£ã®æé ãåŒã³åºããŸããã ãã®å Žåããã®æ¬äœã¯é¢æ°ã«å¯ŸããŠå®çŸ©ãããŠããªããããJITã¯
"dlsym("sin")"
åŒã³åºãã§çµäºããŸãã
"sin"
JITã¢ãã¬ã¹ç©ºéã§å®çŸ©ãããŠãããããåã«ã©ã€ãã©ãªé¢æ°ãçŽæ¥åŒã³åºããŸãã
LLVM JITã¯ãæªå®çŸ©ã®é¢æ°ã®åŠçæ¹æ³ãå¶åŸ¡ããããã®å€æ°ã®ã€ã³ã¿ãŒãã§ãŒã¹ïŒ
ExecutionEngine.h
ãã¡ã€ã«ãåç
§ïŒãæäŸããŸãã ããã«ãããIRãªããžã§ã¯ããšã¢ãã¬ã¹ã®éã«æ瀺çãªãããã³ã°ã確ç«ã§ããé¢æ°ã®ååãåçã«åçã«è§£æ±ºã§ããé¢æ°ãæåã«äœ¿çšããããšãã«é¢æ°ã®é
延JITã³ã³ãã€ã«ãå¯èœã«ãªããŸãã
ãã®èå³æ·±ãã¢ããªã±ãŒã·ã§ã³ã®1ã€ã¯ãæäœçšã®ä»»æã®C ++ã³ãŒããèšè¿°ããããšã§èšèªãæ¡åŒµã§ããããšã§ãã ããšãã°ã次ãè¿œå ããå ŽåïŒ
次ã®ãããªã³ãŒãã䜿çšããŠãã³ã³ãœãŒã«ã«ç°¡åãªåºåãçæã§ããŸãã
"extern putchard(); putchard(120);"
ããã¯ãã³ã³ãœãŒã«ã«å°æåã®ãxããåºåããŸãïŒ120ã¯ãxãã®ASCIIã³ãŒãã§ãïŒã Kaleidoscopeã§åæ§ã®ã³ãŒãã䜿çšããŠããã¡ã€ã«I / Oãã³ã³ãœãŒã«å
¥åãããã³ä»ã®å€ãã®æ©èœãå®è£
ã§ããŸãã
ããã§ãJITãšãªããã£ãã€ã¶ãŒã«é¢ããç« ã¯çµããã§ãã çŸæç¹ã§ã¯ããã¥ãŒãªã³ã°å®å
šã§ã¯ãªããŠãŒã¶ãŒæåããã°ã©ãã³ã°èšèªã®ã³ãŒããJITã³ã³ãã€ã«ããã³æé©åã§ããŸãã 次ã«ãå¶åŸ¡ãããŒå¶åŸ¡ã䜿çšããŠèšèªãæ¡åŒµããéäžã§ããã€ãã®èå³æ·±ãLLVM IRåé¡ã«å¯ŸåŠããŸãã
å®å
šãªã³ãŒããªã¹ã
ãããŠä»ããã€ãã®ããã«ãç§ãã¡ã®äœåã®ã³ãŒãã®å®å
šãªãªã¹ãããããããã¯æ¬¡ã®ããã«ãã«ãã§ããŸãïŒ
#
g++ -g toy.cpp `llvm-config --cppflags --ldflags --libs core jit native` -O3 -o toy
#
./toy
Linuxã§ã³ã³ãã€ã«ããå Žåã-rdynamicãªãã·ã§ã³ãè¿œå ããŸãã ããã«ãããå®è¡æã®å€éšæ©èœãé©åã«æå¹ã«ãªããŸãã
ãããŠãã³ãŒãèªäœã¯æ¬¡ã®ãšããã§ãã
#include "llvm/DerivedTypes.h" #include "llvm/ExecutionEngine/ExecutionEngine.h" #include "llvm/ExecutionEngine/JIT.h" #include "llvm/LLVMContext.h" #include "llvm/Module.h" #include "llvm/PassManager.h" #include "llvm/Analysis/Verifier.h" #include "llvm/Analysis/Passes.h" #include "llvm/Target/TargetData.h" #include "llvm/Target/TargetSelect.h" #include "llvm/Transforms/Scalar.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(); // eat binop // 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; static FunctionPassManager *TheFPM; 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); // . TheFPM->run(*TheFunction); return TheFunction; } // , . TheFunction->eraseFromParent(); return 0; } //===----------------------------------------------------------------------===// // Top-Level parsing ( ) JIT //===----------------------------------------------------------------------===// static ExecutionEngine *TheExecutionEngine; 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()) { // JIT-, . void *FPtr = TheExecutionEngine->getPointerToFunction(LF); // ( , double), // . double (*FP)() = (double (*)())(intptr_t)FPtr; fprintf(stderr, "Evaluated to %f\n", FP()); } } 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() { InitializeNativeTarget(); LLVMContext &Context = getGlobalContext(); // . // 1 - . BinopPrecedence['<'] = 10; BinopPrecedence['+'] = 20; BinopPrecedence['-'] = 20; BinopPrecedence['*'] = 40; // . fprintf(stderr, "ready> "); getNextToken(); // , . TheModule = new Module("my cool jit", Context); // JIT. . std::string ErrStr; TheExecutionEngine = EngineBuilder(TheModule).setErrorStr(&ErrStr).create(); if (!TheExecutionEngine) { fprintf(stderr, "Could not create ExecutionEngine: %s\n", ErrStr.c_str()); exit(1); } FunctionPassManager OurFPM(TheModule); // . , // . OurFPM.add(new TargetData(*TheExecutionEngine->getTargetData())); // AliasAnalysis GVN. OurFPM.add(createBasicAliasAnalysisPass()); // "peephole" "bit-twiddling". OurFPM.add(createInstructionCombiningPass()); // . OurFPM.add(createReassociatePass()); // . OurFPM.add(createGVNPass()); // ( ..). OurFPM.add(createCFGSimplificationPass()); OurFPM.doInitialization(); // , . TheFPM = &OurFPM; // " ". MainLoop(); TheFPM = 0; // . TheModule->dump(); return 0; }
PS , :