├── .gitignore ├── README.md ├── part1 ├── Makefile ├── hello.c └── src │ └── tutorial01.ml ├── part2 ├── Makefile ├── hello.c └── src │ └── tutorial02.ml ├── part3 ├── Makefile └── src │ └── tutorial03.ml └── part4 ├── Makefile └── src └── tutorial04.ml /.gitignore: -------------------------------------------------------------------------------- 1 | .*.swp 2 | build 3 | hello.bc 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ocaml-llvm-tutorial 2 | -------------------------------------------------------------------------------- /part1/Makefile: -------------------------------------------------------------------------------- 1 | SRC_DIR:=src 2 | 3 | TOOLS:=tutorial01 4 | 5 | #TARGET:=native 6 | TARGET:=byte 7 | 8 | LLVM_VERSION := 3.8 9 | CLANG := clang-$(LLVM_VERSION) 10 | 11 | OCAMLBUILDFLAGS:=-classic-display -j 0 -cflags -w,@a-4 12 | 13 | export OCAMLPATH=/usr/lib/ocaml/llvm-$(LLVM_VERSION) 14 | 15 | tutorial01_OCAMLBUILDFLAGS:=-use-ocamlfind -pkgs llvm,llvm.bitreader -lflags -ccopt,-L/usr/lib/llvm-$(LLVM_VERSION)/lib 16 | 17 | 18 | 19 | 20 | ################ 21 | OCAMLBUILD:=ocamlbuild 22 | 23 | 24 | 25 | CLEAN_RULES:=$(patsubst %,%-clean,$(TOOLS)) 26 | 27 | 28 | 29 | .PHONY: $(TOOLS) clean $(CLEAN_RULES) default run 30 | 31 | default: $(TOOLS) 32 | 33 | $(TOOLS): 34 | $(OCAMLBUILD) $(OCAMLBUILDFLAGS) $($@_OCAMLBUILDFLAGS) $($@_OCAMLBUILDFLAGS_$(TARGET)) -I $(SRC_DIR) -build-dir build/$@ $@.$(TARGET) 35 | 36 | run: $(TOOLS) hello.bc 37 | CAML_LD_LIBRARY_PATH=/usr/lib/ocaml/llvm-$(LLVM_VERSION) ./build/tutorial01/src/tutorial01.byte hello.bc 38 | 39 | clean: $(CLEAN_RULES) 40 | -rm -f hello.bc 41 | 42 | $(CLEAN_RULES): 43 | $(OCAMLBUILD) $(OCAMLBUILDFLAGS) -I $(SRC_DIR) -build-dir build/$(patsubst %-clean,%,$@) -clean $(patsubst %-clean,%,$@).$(TARGET) 44 | 45 | hello.bc: hello.c 46 | $(CLANG) -c -emit-llvm $< 47 | -------------------------------------------------------------------------------- /part1/hello.c: -------------------------------------------------------------------------------- 1 | /* compile with: clang -emit-llvm -c hello.c -o hello.bc */ 2 | #include 3 | 4 | int main(void) 5 | { 6 | printf("hello, world\n"); 7 | 8 | return 0; 9 | } 10 | -------------------------------------------------------------------------------- /part1/src/tutorial01.ml: -------------------------------------------------------------------------------- 1 | let _ = 2 | let llctx = Llvm.global_context () in 3 | let llmem = Llvm.MemoryBuffer.of_file Sys.argv.(1) in 4 | let llm = Llvm_bitreader.parse_bitcode llctx llmem in 5 | Llvm.dump_module llm ; 6 | () 7 | -------------------------------------------------------------------------------- /part2/Makefile: -------------------------------------------------------------------------------- 1 | SRC_DIR:=src 2 | 3 | TOOLS:=tutorial02 4 | 5 | #TARGET:=native 6 | TARGET:=byte 7 | 8 | LLVM_VERSION := 3.8 9 | CLANG := clang-$(LLVM_VERSION) 10 | 11 | OCAMLBUILDFLAGS:=-classic-display -j 0 -cflags -w,@a-4 12 | 13 | export OCAMLPATH=/usr/lib/ocaml/llvm-$(LLVM_VERSION) 14 | 15 | tutorial02_OCAMLBUILDFLAGS:=-use-ocamlfind -pkgs llvm,llvm.bitreader -lflags -ccopt,-L/usr/lib/llvm-$(LLVM_VERSION)/lib 16 | 17 | 18 | 19 | 20 | ################ 21 | OCAMLBUILD:=ocamlbuild 22 | 23 | 24 | 25 | CLEAN_RULES:=$(patsubst %,%-clean,$(TOOLS)) 26 | 27 | 28 | 29 | .PHONY: $(TOOLS) clean $(CLEAN_RULES) default run 30 | 31 | default: $(TOOLS) 32 | 33 | $(TOOLS): 34 | $(OCAMLBUILD) $(OCAMLBUILDFLAGS) $($@_OCAMLBUILDFLAGS) $($@_OCAMLBUILDFLAGS_$(TARGET)) -I $(SRC_DIR) -build-dir build/$@ $@.$(TARGET) 35 | 36 | run: $(TOOLS) hello.bc 37 | CAML_LD_LIBRARY_PATH=/usr/lib/ocaml/llvm-$(LLVM_VERSION) ./build/tutorial02/src/tutorial02.byte hello.bc 38 | 39 | clean: $(CLEAN_RULES) 40 | -rm -f hello.bc 41 | 42 | $(CLEAN_RULES): 43 | $(OCAMLBUILD) $(OCAMLBUILDFLAGS) -I $(SRC_DIR) -build-dir build/$(patsubst %-clean,%,$@) -clean $(patsubst %-clean,%,$@).$(TARGET) 44 | 45 | hello.bc: hello.c 46 | $(CLANG) -c -emit-llvm $< 47 | -------------------------------------------------------------------------------- /part2/hello.c: -------------------------------------------------------------------------------- 1 | /* compile with: clang -emit-llvm -c hello.c -o hello.bc */ 2 | #include 3 | 4 | int main(void) 5 | { 6 | printf("hello, world\n"); 7 | 8 | return 0; 9 | } 10 | -------------------------------------------------------------------------------- /part2/src/tutorial02.ml: -------------------------------------------------------------------------------- 1 | let rec print_type llty = 2 | let ty = Llvm.classify_type llty in 3 | match ty with 4 | | Llvm.TypeKind.Integer -> Printf.printf " integer\n" 5 | | Llvm.TypeKind.Function -> Printf.printf " function\n" 6 | | Llvm.TypeKind.Array -> Printf.printf " array of" ; print_type (Llvm.element_type llty) 7 | | Llvm.TypeKind.Pointer -> Printf.printf " pointer to" ; print_type (Llvm.element_type llty) 8 | | Llvm.TypeKind.Vector -> Printf.printf " vector of" ; print_type (Llvm.element_type llty) 9 | | _ -> Printf.printf " other type\n" 10 | 11 | let print_val lv = 12 | Printf.printf "Value\n" ; 13 | Printf.printf " name %s\n" (Llvm.value_name lv) ; 14 | let llty = Llvm.type_of lv in 15 | Printf.printf " type %s\n" (Llvm.string_of_lltype llty) ; 16 | print_type llty ; 17 | () 18 | 19 | let print_fun lv = 20 | Llvm.iter_blocks 21 | (fun llbb -> 22 | Printf.printf " bb: %s\n" (Llvm.value_name (Llvm.value_of_block (llbb))) ; 23 | Llvm.iter_instrs 24 | (fun lli -> 25 | Printf.printf " instr: %s\n" (Llvm.string_of_llvalue lli) 26 | ) 27 | llbb 28 | ) 29 | lv 30 | 31 | let _ = 32 | let llctx = Llvm.global_context () in 33 | let llmem = Llvm.MemoryBuffer.of_file Sys.argv.(1) in 34 | let llm = Llvm_bitreader.parse_bitcode llctx llmem in 35 | (*Llvm.dump_module llm ;*) 36 | 37 | Printf.printf "*** lookup_function ***\n" ; 38 | let opt_lv = Llvm.lookup_function "main" llm in 39 | begin 40 | match opt_lv with 41 | | Some lv -> print_val lv 42 | | None -> Printf.printf "'main' function not found\n" 43 | end ; 44 | 45 | Printf.printf "*** iter_functions ***\n" ; 46 | Llvm.iter_functions print_val llm ; 47 | 48 | Printf.printf "*** fold_left_functions ***\n" ; 49 | let count = 50 | Llvm.fold_left_functions 51 | (fun acc lv -> 52 | print_val lv ; 53 | acc + 1 54 | ) 55 | 0 56 | llm 57 | in 58 | Printf.printf "Functions count: %d\n" count ; 59 | 60 | Printf.printf "*** basic blocks/instructions ***\n" ; 61 | Llvm.iter_functions print_fun llm ; 62 | 63 | Printf.printf "*** iter_globals ***\n" ; 64 | Llvm.iter_globals print_val llm ; 65 | 66 | () 67 | -------------------------------------------------------------------------------- /part3/Makefile: -------------------------------------------------------------------------------- 1 | SRC_DIR:=src 2 | 3 | TOOLS:=tutorial03 4 | 5 | #TARGET:=native 6 | TARGET:=byte 7 | 8 | LLVM_VERSION := 3.8 9 | CLANG := clang-$(LLVM_VERSION) 10 | LLC := llc-$(LLVM_VERSION) 11 | 12 | OCAMLBUILDFLAGS:=-classic-display -j 0 -cflags -w,@a-4 13 | 14 | export OCAMLPATH=/usr/lib/ocaml/llvm-$(LLVM_VERSION) 15 | 16 | tutorial03_OCAMLBUILDFLAGS:=-use-ocamlfind -pkgs llvm,llvm.bitreader -lflags -ccopt,-L/usr/lib/llvm-$(LLVM_VERSION)/lib 17 | 18 | 19 | 20 | 21 | ################ 22 | OCAMLBUILD:=ocamlbuild 23 | 24 | 25 | 26 | CLEAN_RULES:=$(patsubst %,%-clean,$(TOOLS)) 27 | 28 | 29 | 30 | .PHONY: $(TOOLS) clean $(CLEAN_RULES) default run 31 | 32 | default: $(TOOLS) 33 | 34 | $(TOOLS): 35 | $(OCAMLBUILD) $(OCAMLBUILDFLAGS) $($@_OCAMLBUILDFLAGS) $($@_OCAMLBUILDFLAGS_$(TARGET)) -I $(SRC_DIR) -build-dir build/$@ $@.$(TARGET) 36 | 37 | clean: $(CLEAN_RULES) 38 | -rm -f hello hello.o hello.s hello.ll 39 | 40 | $(CLEAN_RULES): 41 | $(OCAMLBUILD) $(OCAMLBUILDFLAGS) -I $(SRC_DIR) -build-dir build/$(patsubst %-clean,%,$@) -clean $(patsubst %-clean,%,$@).$(TARGET) 42 | 43 | run: $(TOOLS) hello 44 | ./hello 45 | 46 | hello: hello.o 47 | $(CLANG) -o $@ $< 48 | 49 | hello.o: hello.s 50 | $(CLANG) -c hello.s 51 | 52 | hello.s: hello.ll 53 | $(LLC) $< 54 | 55 | hello.ll: $(TOOLS) 56 | CAML_LD_LIBRARY_PATH=/usr/lib/ocaml/llvm-$(LLVM_VERSION) ./build/tutorial03/src/tutorial03.byte $@ 57 | -------------------------------------------------------------------------------- /part3/src/tutorial03.ml: -------------------------------------------------------------------------------- 1 | open Llvm 2 | 3 | let _ = 4 | let llctx = global_context () in 5 | let llm = create_module llctx "mymodule" in 6 | 7 | let i32_t = i32_type llctx in 8 | let fty = function_type i32_t [| |] in 9 | 10 | let f = define_function "main" fty llm in 11 | let llbuilder = builder_at_end llctx (entry_block f) in 12 | 13 | let _ = build_ret (const_int i32_t 0) llbuilder in 14 | 15 | if Array.length Sys.argv > 1 16 | then print_module Sys.argv.(1) llm 17 | else dump_module llm ; 18 | () 19 | -------------------------------------------------------------------------------- /part4/Makefile: -------------------------------------------------------------------------------- 1 | SRC_DIR:=src 2 | 3 | TOOLS:=tutorial04 4 | 5 | #TARGET:=native 6 | TARGET:=byte 7 | 8 | LLVM_VERSION := 3.8 9 | CLANG := clang-$(LLVM_VERSION) 10 | LLC := llc-$(LLVM_VERSION) 11 | 12 | OCAMLBUILDFLAGS:=-classic-display -j 0 -cflags -w,@a-4 13 | 14 | export OCAMLPATH=/usr/lib/ocaml/llvm-$(LLVM_VERSION) 15 | 16 | tutorial04_OCAMLBUILDFLAGS:=-use-ocamlfind -pkgs llvm,llvm.analysis,llvm.bitwriter,llvm.target,llvm_X86 -lflags -ccopt,-L/usr/lib/llvm-$(LLVM_VERSION)/lib 17 | 18 | 19 | 20 | 21 | ################ 22 | OCAMLBUILD:=ocamlbuild 23 | 24 | 25 | 26 | CLEAN_RULES:=$(patsubst %,%-clean,$(TOOLS)) 27 | 28 | 29 | 30 | .PHONY: $(TOOLS) clean $(CLEAN_RULES) default run 31 | 32 | default: $(TOOLS) 33 | 34 | $(TOOLS): 35 | $(OCAMLBUILD) $(OCAMLBUILDFLAGS) $($@_OCAMLBUILDFLAGS) $($@_OCAMLBUILDFLAGS_$(TARGET)) -I $(SRC_DIR) -build-dir build/$@ $@.$(TARGET) 36 | 37 | clean: $(CLEAN_RULES) 38 | -rm -f hello hello.o hello.s hello.bc 39 | 40 | $(CLEAN_RULES): 41 | $(OCAMLBUILD) $(OCAMLBUILDFLAGS) -I $(SRC_DIR) -build-dir build/$(patsubst %-clean,%,$@) -clean $(patsubst %-clean,%,$@).$(TARGET) 42 | 43 | run: $(TOOLS) hello 44 | ./hello 45 | 46 | hello: hello.o 47 | $(CLANG) -o $@ $< 48 | 49 | hello.o: hello.s 50 | $(CLANG) -c hello.s 51 | 52 | hello.s: hello.bc 53 | $(LLC) $< 54 | 55 | hello.bc: $(TOOLS) 56 | CAML_LD_LIBRARY_PATH=/usr/lib/ocaml/llvm-$(LLVM_VERSION) ./build/tutorial04/src/tutorial04.byte $@ 57 | -------------------------------------------------------------------------------- /part4/src/tutorial04.ml: -------------------------------------------------------------------------------- 1 | open Llvm 2 | 3 | let add_target_triple triple llm = 4 | Llvm_X86.initialize (); 5 | let lltarget = Llvm_target.Target.by_triple triple in 6 | let llmachine = Llvm_target.TargetMachine.create ~triple:triple lltarget in 7 | let lldly = Llvm_target.TargetMachine.data_layout llmachine in 8 | 9 | set_target_triple (Llvm_target.TargetMachine.triple llmachine) llm ; 10 | set_data_layout (Llvm_target.DataLayout.as_string lldly) llm ; 11 | () 12 | 13 | 14 | let _ = 15 | let llctx = global_context () in 16 | let llm = create_module llctx "mymodule" in 17 | 18 | add_target_triple "x86_64" llm ; 19 | let i8_t = i8_type llctx in 20 | let i32_t = i32_type llctx in 21 | let fty = function_type i32_t [| |] in 22 | 23 | let f = define_function "main" fty llm in 24 | let llbuilder = builder_at_end llctx (entry_block f) in 25 | 26 | let printf_ty = var_arg_function_type i32_t [| pointer_type i8_t |] in 27 | let printf = declare_function "printf" printf_ty llm in 28 | add_function_attr printf Attribute.Nounwind ; 29 | add_param_attr (param printf 0) Attribute.Nocapture ; 30 | 31 | let s = build_global_stringptr "Hello, world!\n" "" llbuilder in 32 | (* try commenting these two lines and compare the result *) 33 | let zero = const_int i32_t 0 in 34 | let s = build_in_bounds_gep s [| zero |] "" llbuilder in 35 | 36 | let _ = build_call printf [| s |] "" llbuilder in 37 | 38 | let _ = build_ret (const_int i32_t 0) llbuilder in 39 | 40 | Llvm_analysis.assert_valid_module llm ; 41 | let _ = 42 | if Array.length Sys.argv > 1 43 | then Llvm_bitwriter.write_bitcode_file llm Sys.argv.(1) |> ignore 44 | else dump_module llm 45 | in 46 | () 47 | --------------------------------------------------------------------------------