OCaml 㧠LLVM -- äºå§ã
ãã®è¨äºã¯ LLVM-2.8 ã¨ãã® OCaml binding ã使ã£ã LLVM ããã°ã©ãã³ã°ã®å§ãæ¹ã«ã¤ãã¦ãè¯ãå¤ããªãã¨ãã声ãèããã®ã§ãçå±ã¯ã¨ããããã©ããã£ã¦å§ãããã主ç¼ã«æ¸ããç©ã§ããOCaml ã Makefile ãå ¨ãæ¸ããäºãç¡ããç¥ããããç¡ããã§ã LLVM ã使ãããã¨ããæ¹ã«ã¯ã¡ãã£ã¨ç¡çãªå 容ã«ãªã£ã¦ãã¾ã
clang ã¨ã LLVM ã¨ããã®é ããèãã¾ããããApple ã製åã«çµæ§ä½¿ã£ã¦ããã¨ãã話ã§ãããæ°ã«ãªã£ã¦ãã人ãããã§ããããç§ã LLVMãæ°ã«ãªãã¾ãããè¦ããã«ãããã°ã©ã å 㧠Cã¿ãããªè¨èª(èªå¼ãããã¾ãã)ã®æ§æããªã¼ãåçã«çæãã¦ãããããã¯ããé¡ã㨠LLVM ã®ã¨ã³ã¸ã³ã«æããã¨ã¢ã¼ã©ä¸æè°ãåã¢ã¼ããã¯ãã£ç¨ã«ããæã㧠JIT ã³ã³ãã¤ã«ãã¦ããã¦ã¹ã¤ã¹ã¤åããã¨ããéæ³ã®ãããªè©±ã§ãã
ãã·ã³èªã¯ Z80 ã§æ¢ã¾ã£ã¦ãããããã C9(=RET) ä½ããè¦ãã¦ãªããªã¸ãµã³ã§ããªãã ãã³ã³ãã¤ã©ã®ä¸ã®æ¹ãæ¸ããããããªæ°ã«ãã¦ããããã¨ãã訳ãã©ã¤ãã©ãªèªä½ã¯ C++ ã§æ¸ããã¦ãã¦ãã¦ãã§ãã¨æãã¾ããã(å®éã¯ãããªã²ã©ãã³ã¼ããããªãããã§ã)ããªã㨠OCaml binding ãä»ãã¦ãããé£ã³ã¤ããªãããã«ã¯ããã¾ããã ãªã®ã§æ©é使ã£ã¦ã¿ã¾ããã!
ãã¼ã£ã¨ã clang ã®äºã¯æ°ã«ãªãã¾ããã ããããªããã
Haskell ã§ããããã§ãã£ã¦ï¼ ã³ã¯ãâ¦
ãã£ãå㯠Haskell ã好ãã ãã Haskell ã§ããã¾ãã£ã¦ï¼ ããã大ãã«çµæ§ã
ã§ã LLVM-2.8 + llvm-0.9.0.1 ã¯ãã«ãã¯åºæ¥ããã©ãå ¨ç¶ä½¿ãã¾ããããLLVM-2.8 ã§ã¯ add 㨠fadd ã使ãåããå¿ è¦ããããã§ããããããå ¨ãèããã«ããã ã³ã³ãã¤ã«ã§ããããã«ãã¦ããã ãããã¹ããå ¨ãããã«ãªãªã¼ã¹ãã¦ãã ä»ä¿ºãä½æ ãããããæ¸ãã¯ãã«ãªã£ã¡ãã£ã¦ããã ãã©â¦ã¾ãã誰ããä½è ãããã使ã£ã¦ãªãã£ã¦ãã¨ãã
ã¾ããä¸çªä¸ã®ããFFIã£ã½ã.hscã¬ã¤ã¤ãªã大å¤ã§ããã©ä½¿ãã¾ãããé å¼µã£ã¦ãã ãããã¾ã C ã®ã¤ã³ã¿ã¼ãã§ã¼ã¹ãã®ã¾ã¾æã£ã¦ãã¦ããã使ããã®å½ããåã§ããã©ãâ¦
LLVM-2.6 + LLVM-0.7.1.2 ã ã¨ãããªãã«åãã¿ãããã§ãã
ã¤ã³ã¹ãã¼ã«
OCaml ã® LLVM binding 㯠LLVM ã®ã½ã¼ã¹ã«ãã£ã¤ãã¦ãã¾ããã ããã OCaml ãã¤ã³ã¹ãã¼ã«ããä¸ã§ã LLVM ããã«ããã¤ã³ã¹ãã¼ã«ãã¦ããã°ããã®ã¾ã¾ OCaml LLVM binding ã使ããããã«ãªãã¾ãã楽åã§ããã
ãï¼ãã«ããé¢åã ã£ã¦ï¼ ãæ é·(ãã«)ã¸å¸°ãï¼ http://migzou.blog84.fc2.com/blog-entry-84.html ã
OCamlFind ã¨ä¸ç·ã«ä½¿ãã¾ããã
ããã¤ã³ã¹ãã¼ã«ãããããã£ããã ããã俺㯠OCaml 㧠LLVM ã使ã£ã¦ã¿ãããï¼
ããã¡ãã£ã¨å¾ ã£ã¦ä¸ãããå¤åãã®ã¾ã¾ã§ã¯ãªã³ã¯ããæ大å¤ã§ãããMakefile ã«ãã©ãã°ãä¸ã æ¸ããªãããããªãã§ãããã
OCamlFind ã使ãã¾ãããã OCamlFind ã® META ãã¡ã¤ã«ã«å¿
è¦ãªãã©ãã°ã llvm ããã±ã¼ã¸ã¨ãã¦ç»é²ãã¦ããã°ãå¾ã¯ -package llvm ã¨ããã° ocamlfind ãåæã«å¿
è¦ãªãªãã·ã§ã³ãæèã«å¿ãã¦ä½¿ã£ã¦ããã¾ããã¨ã£ã¦ã楽ã
https://bitbucket.org/camlspotter/ocaml-llvm-phantom/src/4f9dbe9a87ba/llvm-ocamlfind/ ã«ãããã¡ã¤ã«ãä¸ã¤åã£ã¦ãã¦(ocaml-llvm-phantom èªä½ã clone ãã¦ãããã§ããã©)ã./install-META.sh ã¨ããã¨åæã«ããé©å½ã« llvm ã®çºã® META ãã¡ã¤ã«ãä½ã£ã¦ãããªãã«ãªãã®äºè§£ãåããã«ã次ã®ãããªãã¡ã¤ã«ã llvm ocamlfind ããã±ã¼ã¸ã¨ãã¦ã¤ã³ã¹ãã¼ã«ãã¾ã:
requires = "" version = "[llvm 2.8]" description = "LLVM 2.8" directory = "^" browse_interfaces = " Llvm Llvm_analysis Llvm_bitreader Llvm_bitwriter Llvm_executionengine Llvm_scalar_opts Llvm_target " archive(byte) = "llvm.cma llvm_analysis.cma llvm_executionengine.cma llvm_bitreader.cma llvm_bitwriter.cma llvm_scalar_opts.cma llvm_target.cma" archive(native) = "llvm.cmxa llvm_analysis.cmxa llvm_executionengine.cmxa llvm_bitreader.cmxa llvm_bitwriter.cmxa llvm_scalar_opts.cmxa llvm_target.cmxa" linkopts = "-cc g++ -cclib -L/home/jfuruse/.share/prefix/lib -cclib -lpthread -cclib -ldl -cclib -lm -cclib -lLLVMpic16passes -cclib -lLLVMMCDisassembler -cclib -lLLVMXCoreCodeGen -cclib -lLLVMXCoreAsmPrinter -cclib -lLLVMXCoreInfo -cclib -lLLVMSystemZCodeGen -cclib -lLLVMSystemZAsmPrinter -cclib -lLLVMSystemZInfo -cclib -lLLVMSparcCodeGen -cclib -lLLVMSparcAsmPrinter -cclib -lLLVMSparcInfo -cclib -lLLVMPowerPCCodeGen -cclib -lLLVMPowerPCAsmPrinter -cclib -lLLVMPowerPCInfo -cclib -lLLVMPIC16AsmPrinter -cclib -lLLVMPIC16CodeGen -cclib -lLLVMPIC16Info -cclib -lLLVMMipsAsmPrinter -cclib -lLLVMMipsCodeGen -cclib -lLLVMMipsInfo -cclib -lLLVMMSP430CodeGen -cclib -lLLVMMSP430AsmPrinter -cclib -lLLVMMSP430Info -cclib -lLLVMMBlazeAsmPrinter -cclib -lLLVMMBlazeCodeGen -cclib -lLLVMMBlazeInfo -cclib -lLLVMLinker -cclib -lLLVMipo -cclib -lLLVMInterpreter -cclib -lLLVMInstrumentation -cclib -lLLVMJIT -cclib -lLLVMExecutionEngine -cclib -lLLVMCppBackend -cclib -lLLVMCppBackendInfo -cclib -lLLVMCellSPUCodeGen -cclib -lLLVMCellSPUAsmPrinter -cclib -lLLVMCellSPUInfo -cclib -lLLVMCBackend -cclib -lLLVMCBackendInfo -cclib -lLLVMBlackfinCodeGen -cclib -lLLVMBlackfinAsmPrinter -cclib -lLLVMBlackfinInfo -cclib -lLLVMBitWriter -cclib -lLLVMX86Disassembler -cclib -lLLVMX86AsmParser -cclib -lLLVMX86CodeGen -cclib -lLLVMX86AsmPrinter -cclib -lLLVMX86Info -cclib -lLLVMAsmParser -cclib -lLLVMARMDisassembler -cclib -lLLVMARMAsmParser -cclib -lLLVMARMCodeGen -cclib -lLLVMARMAsmPrinter -cclib -lLLVMARMInfo -cclib -lLLVMArchive -cclib -lLLVMBitReader -cclib -lLLVMAlphaCodeGen -cclib -lLLVMSelectionDAG -cclib -lLLVMAlphaAsmPrinter -cclib -lLLVMAsmPrinter -cclib -lLLVMMCParser -cclib -lLLVMCodeGen -cclib -lLLVMScalarOpts -cclib -lLLVMInstCombine -cclib -lLLVMTransformUtils -cclib -lLLVMipa -cclib -lLLVMAnalysis -cclib -lLLVMTarget -cclib -lLLVMMC -cclib -lLLVMCore -cclib -lLLVMAlphaInfo -cclib -lLLVMSupport -cclib -lLLVMSystem "
ãããé·ããï¼ ã§ãéã«è¨ãã¨ããã®ãã¡ã¤ã«ãä½ã£ã¨ããªãã¨ä¸ã Makefile ã«ãããæã¡è¾¼ã¾ãªãããããªã訳ã§ãã¦â¦ æªããã¨ã¯è¨ããªãããä½ã£ã¦ããã¾ããã!
Makefile/OMakefile ãã
ãããã Makefile ããå§ãã¾ãããã test.ml ã£ã¦ãã¡ã¤ã«ãæ¸ãã¦ã test ã£ã¦ããå®è¡ãã¡ã¤ã«ãä½ããã¨ã«ãã¾ã:
# TAB ãæ½°ãã¦ããã®ã§èªåã§ç´ãã¦ã!! test: test.cmx ocamlfind ocamlopt -package llvm -o $@ $< %.cmo: %.ml ocamlfind ocamlc -package llvm -c $< %.cmx: %.ml ocamlfind ocamlopt -package llvm -c $< .PHONY: clean clean: rm -f *.cm* *.o test
è¶ ãããã«ã«ã¯ãããªæãã§ããããã ocamlfind ã§åOCamlã³ãã³ããã©ãããã¦ã -package llvm ãä»ãããããã ããããããã¨ä¸ã® META ãã¡ã¤ã«ã«æ¸ãã¦ãããªãã·ã§ã³ãé©å®ä»ãå ãã¦ã³ã³ãã¤ã©ãèµ·åãã¦ããããã½ã¼ã¹ãä¸ãã¡ã¤ã«ãããªãããç°¡åã§ããã
OMake http://omake.metaprl.org/ ã好ãã¨ããæ¹ã®çºã«ã OMakefile ãªãã©ãæ¸ãããæ¸ãã¨ãã¾ããã:
# OMakeroot ã¯èªåã§ä½ã£ã¦ããã USE_OCAMLFIND=true OCAMLPACKS[]= llvm FILES[] = test .DEFAULT: test OCamlProgram(test, $(FILES)) .PHONY: clean clean: rm -f $(filter-proper-targets $(ls R, .))
ã½ã¼ã¹ãä¸ãã¡ã¤ã«ãããªã㨠Makefile ã OMakefile ãé·ãã¯ãã¾ãå¤ããã¾ããããããããããªã£ã¦ãã㨠OMake ã®æ¹ãåã§ããã¾ãã Makefile ã§éãã§ãããã¡ã«åéã¤ããªããªã£ãã OMake ã«ç§»è¡ãã¦ã¿ãã®ãæ¤è¨ãã¦ã¿ã¦ãã ããã
åãã¦ã® LLVM ã使ã£ãã³ã¼ããæ¸ãã
ãã¦ãããããèå¿ã®ã½ã¼ã¹ã³ã¼ãã test.ml ãæ¸ãã¾ããã!
ç®æ¨ã¯ã ä¸ãããã 32bit ã®æ´æ°ãäºåã«ãã¦è¿ãé¢æ° double ã LLVM ã§å®ç¾©ãã³ã³ãã¤ã«ãã¦ãå®è¡ããã
ã§ãã ç°¡åããã¾ããï¼ ãããããã¾ããã¾ãã¯ç°¡åããããã®ããå§ããã»ããããã§ããã
ã¾ãã¯æºå: ã¨ã³ã¸ã³ãã³ã³ãã¯ã¹ããã¢ã¸ã¥ã¼ã«ããã«ã
open Llvm module E = Llvm_executionengine let _ = E.initialize_native_target () let context = global_context () let module_ = create_module context "mymodule" let builder = builder context
ã¾ãã¯æºåã§ãã ãã®è¾ºã¯ã¾ããåªæã®ãããªãã®ã§ãã
- Llvm_executionengine ã¨ããã¨ã«ããã¢ã¸ã¥ã¼ã«åãé·ãã®ã§ã E ã¨ããç縮åãã¤ãã¾ããã
- E.initialize_native_target () ããªã㨠JIT ã³ã³ãã¤ã«ãã¦ãããããã ã®ã¤ã³ã¿ããªã¿ã«ãªãã¾ããã¤ã³ã¿ããªã¿ã§ãåããã©é ãã!
- context ã¨ãããªããããããããªããã®ãè³ãã¨ããã§å¿ è¦ã§ããæ®é㯠global_context () ãã使ãã¾ããã
- é¢æ°ã¯ã¢ã¸ã¥ã¼ã«ã«å®ç¾©ãã¾ãã "mymodule" ã¨ããååã®ã¢ã¸ã¥ã¼ã«ãä½ãã¾ãããã
- ãã«ã builder ãä½ã£ã¦ããã¾ããããã¯ç¾å¨ä½æ¥ãã¦ããå ´æã示ãã«ã¼ã½ã«ããã¤ã³ã¿ã¿ãããªãã®ã§ãã
build_hogehoge å¼æ° builder ã¨ããé¢æ°ãããåºã¦ãã¾ãããããã¯ç¾å¨ builder ãå·®ãã¦ããæã«
hogehoge ã¨ããã¤ã³ã¹ãã©ã¯ã·ã§ã³ãä»ãå ãã¦ãã£ã¦æå³ã§ãã
ããï¼ãã«ãã§ããªãï¼ã¡ããã¨ä¸ã®æºåããã¾ãããï¼ ocamlfind ã® META ã¨ããã£ã¦ãªãï¼ãããªäººã®äºã¯ç¥ãã¾ããã
åãå®ç¾©
ãã¦ããã使ãåãããã§å®ç¾©ãã¦ããã¾ããããã test.ml ã®ç¶ãã§ã(ããããã test.ml ã«è¶³ãã¦ããã¾ã):
let i32_t = i32_type context
ä¸ã®ã³ã¼ã㯠context ä¸ã§ 32bit ã®æ´æ°åã i32_t ã¨ãã¦å®ç¾©ãã¾ãããããªé¢¨ã« OCaml LLVM binding ã§ã¯ä½ãåºæ¬åãä½ãã¨ãã«ãã context ãè¦æ±ããã®ã§ãããé¢åã§ããããªã®ã§ãåãã£ã¦ãããã£ã¦å®ç¾©ãã¦ããã®ãããã§ãããã
ã㦠double é¢æ°ãå®ç¾©!
é¢æ°ãå®ç¾©ããã«ã¯ãã¾ãé¢æ°ã®åãä½ã£ã¦ãããããé¢æ°ããããã¨å®£è¨ããªããã°ããã¾ãããC ã®é¢æ°ãããã¿ã¤ã宣è¨ã®ãããªãã®ã§ã:
let double_type = function_type i32_t [| i32_t |] let double = declare_function "double" double_type module_
double_type 㧠i32_t ãä¸ã¤åãåã i32_t ãè¿ãé¢æ°ã®åãå®ç¾©ãã¦ãmodule_ ã§ã¯ "double" ã¨ããååã®é¢æ°ããã®åãæã¡ã¾ããã¼ãã¨å®£è¨ãã¦ãã¾ãã
ãã¦ãèå¿ã®é¢æ°ã®å®ç¾©ã«ç§»ãããã¨æã¾ããããã®åã«:
let bb = append_block context "entry" double let () = position_at_end bb builder
LLVM ã§ã¯ã³ã¼ãã¯é¢æ°å ã®ãã¼ã·ãã¯ãããã¯ã«æ¸ããªãã¦ã¯ããã¾ããããã¼ã·ãã¯ãããã¯å ã®ã³ã¼ãã¯é ã«å®è¡ããã¾ããæ¡ä»¶åå²ãã«ã¼ãã¯ãã¼ã·ãã¯ãããã¯ãè¤æ°ä½ãããããããã©ã³ãå½ä»¤ã§ç¹ããäºã§å®ç¾ãã¾ãããä»åã¯ãã¹ãã¾ããããã§ã¯ "entry" ã¨ããååã®ãã¼ã·ãã¯ãããã¯ã double é¢æ°ã«ä»ãå ãããã«ãããã®ãããã¯ã®æå¾ï¼ã¨ãã£ã¦ãã¾ã ã³ã¼ããä½ãç¡ãã®ã§å é ã§ãï¼ã«ç§»åãã¾ãã
double é¢æ°ã¯å¼æ°ãäºåãã¦è¿ãé¢æ°ã§ããããå¼æ°ã使ããªãã¨ä½ã«ããªãã¾ãããã¾ãã¯å¼æ°ãåãåºãã¾ããã:
let param = match params double with | [| param |] -> param | _ -> assert false
params é¢æ°ã§ double ã®å¼æ°é åãåå¾ã§ãã¾ããä¸å¼æ°ãããªãã¯ãã§ãããã¦ããã㧠param ã¯å¼æ°ãæã示ã llvalue ã¨ããåãæã¤å¤ã§ãããllvalue ã¯ä½ãå ·ä½çãªå¤ãæå³ããã®ã§ã¯ãªãäºã«æ³¨æãã¦ãã ãããValue ã¨ããããã«ã¯ä½ãå¤ãåãåºããããªæ°ããã¾ãããããã§ã¯ããã¾ããã大éæã«è¨ãã¨ãä½ãããã®è¨ç®çµæãå ¥ã£ãå¤æ°ãæã示ããã®ã ã¨æãã°ããã§ããããä¾ãã°ããã®å ´åã¯é¢æ°ãå®è¡æã«æ¸¡ãããå¼æ°ã«ãªãã¾ããã
llvalue ã«ã¯ååãä»ãããã¨ãã§ãã¾ãããã£ãããªã®ã§å¼æ°ã« "param" ã¨ããååãä»ãã¦ã¿ã¾ã:
let () = set_value_name "param" param
ãã¦ããã® param ãäºåããã³ã¼ããçæãã¾ããã:
let doubled = build_mul param (const_int i32_t 2) "doubled" builder
build_mul x y name builder 㯠x 㨠y ã¨ãã llvalue ã®å 容ãæãã¦ã name ã¨ããååã® llvalue ã«çµæãæ ¼ç´ããã³ã¼ãã builder ãæã示ãã¦ããå ´æã«å ãã¾ãããã㧠const_int i32_t 2 㯠32bit æ´æ°ã® 2 ãçæãã¦ãã¾ããçµæã® llvalue 㯠doubled ã¨ããå¤æ°ã«æç¸ããã¾ãããã®çµæã build_ret ã使ã£ã¦é¢æ°ã®è¿ãå¤ã«ããã°åºæ¥ä¸ããã§ã:
let () = ignore (build_ret doubled builder)
ãã³ãããããæ´åæ§ããã§ãã¯
ãªãã ãè¯ãããã£ãæ§ãªãããããæ§ãªï¼ï¼ï¼ ããã§ãã®å®ç¾©ãããé¢æ°ããã³ããã¦ã¿ã¾ããã:
let () = dump_value double
ããããã¨ãããªã®ã表示ãããã¯ãã§ã:
// ãã£ã¨ã³ã¬ã¯ OCaml ã®ã½ã¼ã¹ãããªããã define i32 @double(i32 %param) { entry: %doubled = mul i32 %param, 2 ret i32 %doubled }
ã©ãã§ãããã Cã£ã½ãææ³ã§ãä»ã¾ã§æ§ç¯ãã¦ããåãã³ã¼ãã double é¢æ°ã®å®ç¾©ã«çµåãã£ã¦ããã®ããããã§ãããããi32 ã¨ããåã® %param ãåãåã£ã¦ã%param 㨠2 ãæãã¦ããã®çµæ i32 ã® %doubled ãè¿ãããããªé¢¨ã«èªããã¯ãã§ãã
ãããæ¬å½ã«ãã®ã³ã¼ãã§æ£ããã®ã§ããããããããªå¿é çã®ããªãã®ããã«ãLLVM ã§ã¯ã³ã¼ãã«è´å½çãªééãããªãããã§ãã¯ãã Llvm_analysis.assert_valid_function é¢æ°ãããã¾ã:
let () = Llvm_analysis.assert_valid_function double
ãã double é¢æ°ã®å é¨ã®åãééã£ã¦ããããå¦ãªãã¨ããã¦ããã¨ãããã§ã¨ã©ã¼ãåãã¾ãããã®ã¨ã©ã¼ã¡ãã»ã¼ã¸ã¯æ £ããªãã¨è¯ãæå³ãå¤ããªãã®ã§ãããããã§ã assert_valid_function ã¯æ¯éå¼åºãã¹ãã§ããããã§èããªãã¨å¾ã§ãã£ã¨æå³ã®ããããªãã¨ã©ã¼ã«æ©ã¾ããããã¨ã«ãªãã¾ãããããã¡ããããã®ã¨ã©ã¼ãã§ãã¯ã§æ¤æ»ã§ããã®ã¯åã®æ´åæ§ã ã¨ããSSAå½¢å¼ã«ãªã£ã¦ããã ã¨ã (SSAãç¥ããªã人ã¯åããããã»ã£ã¨ãã¦ããã§ã)ããããããã¨ã ãã§ãå ¨ã¦ã®åé¡ãæ¤åºã§ããããã§ã¯ããã¾ããããããã§ãæçã§ãã(Haskell ã® LLVM ã¯ãã®ãã§ãã¯ããµãã£ã¦ããã®ã§ããã°ãç´ãã«ãããã¨...å´é£¯ç©ã§ã)
ããå®è¡!
ãã¦ãããããå®è¡ã§ãã dump ã§è¦ãã³ã¼ããå®éã« LLVM ã®ã¨ã³ã¸ã³ã«æ¸¡ããã³ã³ãã¤ã«ããä¸ã§ãå¼æ°ãä¸ãã¦å®è¡ãã¦ã¿ã¾ããã:
let engine = E.ExecutionEngine.create module_ let res = E.ExecutionEngine.run_function double [| E.GenericValue.of_int i32_t 21 |] engine let res_int = E.GenericValue.as_int res let () = Printf.eprintf "double(21)=%d\n" res_int
ã¾ã㯠ExecutionEngine.create ã§å®è¡ã¨ã³ã¸ã³ engine ãä½ããExecutionEngine.run_function 㧠double é¢æ°ã engine ä¸ã§ JIT ã³ã³ãã¤ã«ããããã«å¼æ°ãä¸ãã¦èµ°ããã¾ãããã®éã®å¼æ°ã¯ E.GenericValue.t ã¨ããåãæã£ã¦ãã¦ã llvalue ã¨éã£ã¦æ¬å½ã®å¤ã§ããããã§ã¯ E.GenericValue.of_int i32_t 21 㧠32bit æ´æ°åã®å¤ 21 ãä½ã£ã¦ãã¾ããçµæ res ã E.GenericValue.t ã§ããããå®éã«å¤ãåãåºãã¾ããããã OCaml ã®æ´æ°ã« as_int ã§å¤æãã¦ããªã³ãã¢ã¦ããã¦çµäºãã¡ããã¨ä¸æããã£ã¦ããã°çµæã 42 ã«ãªã£ã¦ããã¯ã...ã§ãã
LLVM ã使ã£ãããã°ã©ãã³ã°ã£ã¦ãããªæã
ã©ãã§ããããåãç°¡å㪠LLVM ã®é¢æ°ã OCaml binding ã使ã£ã¦å®ç¾©ããå®éã« JIT ã使ã£ã¦ã³ã³ãã¤ã«ããèµ°ããã¦ã¿ã¾ãããæé ã¯ãããªæã:
- é¢æ°ã®åï¼ãããã¿ã¤ãï¼å®£è¨ããã
- ãã¼ã·ãã¯ãããã¯ãé¢æ°ã«ãã£ã¤ãã
- ãã«ããã³ã¼ãã足ãããã¹ã¼ã·ãã¯ãããã¯ã«ç§»å
- ã³ã¼ãã build_hogehoge å½ä»¤ã§ä»ãå ãã¦ãã
- è¤æ°ã®ãã¼ã·ãã¯ãããã¯ãæãã°ããã¯ããããã©ã³ãå½ä»¤ã§ç¹ããããã(ä»åã¯ãã¹)
- build_ret ã§è¿å¤ããªã¿ã¼ã³
- assert_valid_function ã§å®ç¾©ããã§ãã¯
- ã¨ã³ã¸ã³ä¸ã§ JIT ã³ã³ãã¤ã«ï¼å®è¡
ä¸æ¹ã LLVM ã® C++ API ã OCaml binding ã¯åãæéããããã¾ããã§ããã®åãåçã«ãã¹ãè¨èª(C++ ã OCaml)ãã LLVM ã®ã³ã¼ãæ¨ãçæãããã®ã³ã¼ãã JIT ã³ã³ãã¤ã«+å®è¡ããããã®çµæããã¹ãè¨èªã§ã¾ã使ããã¨ãã£ãé¢ç½ãäºãåºæ¥ãããã«ãªãã®ã§ããããã¯çµæ§æ¥½ããã§ããã
ä¾ãã°èªåã®ããã°ã©ãã³ã°è¨èªå¦çç³»ã OCaml ã§æ¸ãã¦ããã¤ãã£ãã³ã¼ãã«ã³ã³ãã¤ã«ãå®è¡ããé¨åã LLVM ã§ãããã¨ãããã¼ã¹ãåæ¤æ»ã¯è¨èªå¦çã«åããé¢æ°åè¨èªã§ãã£ã¦ãå®è¡ã¯ã¤ã³ã¿ããªã¿ã ã¨ä»æãã»ã§ãé ããããã·ã³èªã«å¤æããããã§ããç°¡åã«ãªã¬ãªã¬è¨èªã® REPL ãä½ãã¡ããã¾ããï¼çããã試ãã¦ã¿ã¦ãï¼
LLVMãããããã©ãããã
ãã¦ã
ãªã¬ã¯ããããã®ã¼ãã¯ãããã°ããã ãããª
ãã®ã¯ã¦ããªãé ã LLVM åãã...
æªå®
â èå·ä»ç¾©
ããã§ãããä¾ãã° LLVM ã®ãã¼ã¸ã«ãã Kaleidoscope ã¨ãããªã¢ãã£è¨èªã® OCaml ç http://llvm.org/docs/tutorial/OCamlLangImpl1.html ã試ãã¦ã¿ããã©ãã§ããããCamlP4 ã使ã£ããã¼ãµé¨åã®å®è£ ããå ¥ã£ã¦ããã®ã§ãè¨èªå¦çç³»å é¨ãããã£ããã¨ã®ç¡ã人ã«ã¯è¯ãããããã¾ãããéã«ããã®è¾ºç¥ã£ã¦ã人ã¯ãã¼ãµé¨åã¯ãã£é£ã°ãã¦èªåã®å¥½ã㪠lex+yacc ãªã parsec ãªãã§æ¸ãã°ããããã
ãã ããã®ãã¥ã¼ããªã¢ã«ãã¡ãã£ã¨å¤ãã®ã§ããä¾ãã° double ã®è¶³ãç®ã add å½ä»¤ã§ãã£ã¦ããã®ã§ããããã㯠fadd ã使ããªã㨠LLVM 2.8 ã§ã¯ã¨ã©ã¼ã«ãªã£ã¡ããããã®è¾ºããã¤ã¾ã¥ããã¤ã³ããããã¾ãã...ã¾ããä¸è¨ã§ããã¨ã
LLVMåã¯åºæ¬å°é·å
ã¨ããäºã§ãããããã¥ã¡ã³ããã¡ãã£ã¨å¤ããã¨ããåã®ãã¼ã¸ã§ã³ã ã¨åãã¦ããã®ã«ãç¾ãã¼ã¸ã§ã³ã ã¨æåãããããã¨ããçµæ§ããã¾ãã ããã§ã¡ã²ã«ãããªãã
æåãã LLVM ããã°ã©ãã³ã°ãªã©æãåºããªãã»ããè¯ã
ã®ã§ãããããããªããããã
Phi ã¨ã SSA ã¨ãã
ä»åã®åç´ãªä¾ã§ã¯æ¡ä»¶åå²ãå ¨ããªãã£ã訳ã§ãããæ¡ä»¶åå²ãããã³ã¼ãã LLVM ã§æ¸ãããå ´åã«ã¯ãSSAå½¢å¼ã¨ããPhié¢æ°ã¨ããå®å®ãããã¯äººé¡æå¾ã®ããã³ãã£ã¢ãã¨ããåå¼·ããã»ããè¯ãããããã¾ããã§ãããããã¦ããèªèº«ãªã«ãè¦ãã¦ããã¾ãããããã»ã»ã»ã(æãåºãã¾ããããããã³ã¹ããã³ãã¢ã§ãããhttp://en.wikipedia.org/wiki/Dominator_(graph_theory) )
OCaml binding ã¡ã³ãã¤
OCaml binding 㧠LLVM æ¸ãã¦ãã¨ãæ°æéå¾ã«ã
- ãªãã§ä¸ã context ã£ã¦æ¸ããªããããã
- ãªãã§ä¸ã builder ã£ã¦æ¸ããªããããã
- ãªãã§ä½ã§ãããã§ã llvalue ãããã ããããã
assert_valid_function ã§å®ç¾©ãã§ãã¯ããã¾ã§åã¨ã©ã¼ããããããªãã - ãªãã§å¤ãª gep ä½ã£ãã segfault ã§è½ã¡ããã
- ãªãã§ä»¥ä¸ç¥
ãããã¨ãä½ã¨ããããã¨ããããé å¼µã£ã¦ããã¨ããã§ããã楽ãã¿ã«ã
ç²ãã
ãããããåªããå£èª¿ã§æ¸ãã¦ã¿ããç²ãããâ¦
test.ml ã®å ¨ä½ã ãã
open Llvm module E = Llvm_executionengine (* Llvm_executionengine ã£ã¦ä¸ã æ¸ãã¦ãããªããã E ã£ã¦ååãã¤ãã¾ã *) let _ = E.initialize_native_target () (* ãããããªã㨠JIT ãæå¹ã«ãªããããã ã®ã¤ã³ã¿ã¼ããªã¿ã«ãªã£ã¡ãã£ã¦é ããªãã *) let context = global_context () (* ãã®ã³ã³ãã¯ã¹ãã£ã¦ã®ãããããªãã®ãè¦æ±ãã¾ããé¢åã ã *) let module_ = create_module context "mymodule" (* ã¢ã¸ã¥ã¼ã«ãä½ãã¾ããã *) let builder = builder context (* ãã«ããä½ãã¾ãããã build_hogehoge å¼æ° builder ããã¨ã hogehoge ã¨ããå½ä»¤ã builder ãæãã¦ããæã«ä½ã£ã¦ãããã ã«ã¼ã½ã«ã¿ãããªãã®ã§ãã *) let i32_t = i32_type context (* 32bit æ´æ°ã®åãä½åº¦ã i32_type context ã£ã¦æ¸ãã®é¢åã ããå®ç¾©ãã¨ãã *) (* æºåçµããï¼ double é¢æ°ãå®ç¾©ãã¦ããã¾ããã!! *) let double_type = function_type i32_t [| i32_t |] (* double é¢æ°ã®åã i32_t ãä¸ã¤åãåã£ã¦ i32_t ãè¿ã *) let double = declare_function "double" double_type module_ (* "double" ã¨ããé¢æ°ã double_type ãæã¤ã¨å®£è¨ãã¾ãã *) let bb = append_block context "entry" double (* double é¢æ°ã« "entry" ã¨ããååã® basic block ãä»ãå ãã¾ãã *) let () = position_at_end bb builder (* ãã«ãã bb ãæãããã«ãã¦ã build_hogehoge ã double é¢æ°ã®ã³ã¼ããçæããããã«ãã¾ã *) let param = match params double with | [| param |] -> param | _ -> assert false (* double é¢æ°ã®å¼æ°ãæã llvalue ãå¾ã¾ããä¸å¼æ°ã ãããä¸ã¤ãã帰ã£ã¦ããªãã¯ã *) let () = set_value_name "param" param (* å¼æ°ã«ååã¯ã¤ããªãã¦ããããã©ããã£ããã ãã俺㯠"param" ã£ã¦ååãããã¶ãã *) let doubled = build_mul param (const_int i32_t 2) "doubled" builder (* param ã 2 åããã³ã¼ããçæãã¾ããçµæãå©ç¨ããã«ã¯ doubled ã使ã *) let () = ignore (build_ret doubled builder) (* doubled ãé¢æ°ã®æ»ãå¤ã«ããã *) (* double é¢æ°ã¯å®ç¾©ã§ãã!! *) let () = dump_value double (* 念ã®ããã double ããã³ããã¦ã¿ããã³ã¼ããããªã³ãã¢ã¦ããããããããã¨ãªãäºåãã¦ãã£ã½ãã§ããï¼ *) let () = Llvm_analysis.assert_valid_function double (* æè§ã ããã LLVM æ§ã«ä¿ºã®ã³ã¼ããæ£ãããèãã¦ã¿ãããï¼ ã¨ãããããé¡ãã§ãããå¿ ãèãã¦ãã ãããããã§èããªãã¨å¾ã§å¾æãã¾ãã ããããã§ã¨ã©ã¼ãåºãã¨ããããè¨ããã¾ããã¯ããã¯æå³ããããã¾ããããããã¦ã¯ããã¾ããã ãã§ãã¯ãããã«å¾ã§æå¥ãè¨ãããå ´åããã£ã¨ãããããããªããªãã¾ãã *) (* double é¢æ°ã¯ãã§ãã¯ã§ãããï¼ ããã LLVM æ§ã«ã³ã³ãã¤ã«ãã¦ãããã! *) let engine = E.ExecutionEngine.create module_ (* LLVM engine ãä½ãã! *) let res = E.ExecutionEngine.run_function double [| E.GenericValue.of_int i32_t 21 |] engine (* Engine ã« double é¢æ°ãã³ã³ãã¤ã«ãã¦ããã®ä¸ 21 ãé©ç¨ãã¦çµæããããã¾ã *) let res_int = E.GenericValue.as_int res (* çµæã OCaml ã®æ´æ°ã«å¤æããã *) let () = Printf.eprintf "double(21)=%d\n" res_int (* ã¡ãã㨠42 ã«ãªã£ã¦ãã¾ãããï¼ *)