Skip to content

Commit 15717ae

Browse files
committed
Chapter 4: Optimizer Support
Note: http://old.nabble.com/Linking-with-C-Library-td28133460.html explains how to get extern functions to actually link
1 parent 1c3f870 commit 15717ae

File tree

6 files changed

+65
-9
lines changed

6 files changed

+65
-9
lines changed

_tags

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1-
"+llvm-2.8": include
21
<{lexer,parser}.ml>: use_camlp4, pp(camlp4of)
32
<*.{byte,native}>: g++, use_llvm, use_llvm_analysis
3+
<*.{byte,native}>: use_llvm_executionengine, use_llvm_target
4+
<*.{byte,native}>: use_llvm_scalar_opts, use_bindings

bindings.c

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#include <stdio.h>
2+
3+
/* putchard - putchar that takes a double and returns 0. */
4+
extern double putchard(double X) {
5+
putchar((char)X);
6+
return 0;
7+
}

codegen.ml

+5-2
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ let rec codegen_expr = function
2424
match op with
2525
| '+' -> build_fadd lhs_val rhs_val "addtmp" builder
2626
| '-' -> build_fsub lhs_val rhs_val "subtmp" builder
27-
| '/' -> build_fsub lhs_val rhs_val "divtmp" builder
27+
| '/' -> build_fdiv lhs_val rhs_val "divtmp" builder
2828
| '*' -> build_fmul lhs_val rhs_val "multmp" builder
2929
| '<' ->
3030
(* Convert bool 0/1 to double 0.0 or 1.0 *)
@@ -77,7 +77,7 @@ let codegen_proto = function
7777
) (params f);
7878
f
7979

80-
let codegen_func = function
80+
let codegen_func the_fpm = function
8181
| Ast.Function (proto, body) ->
8282
Hashtbl.clear named_values;
8383
let the_function = codegen_proto proto in
@@ -95,6 +95,9 @@ let codegen_func = function
9595
(* Validate the generated code, checking for consistency. *)
9696
Llvm_analysis.assert_valid_function the_function;
9797

98+
(* Optimize the function. *)
99+
let _ = PassManager.run_function the_function the_fpm in
100+
98101
the_function
99102
with e ->
100103
delete_function the_function;

myocamlbuild.ml

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
open Ocamlbuild_plugin;;
2+
3+
ocaml_lib ~extern:true "llvm";;
4+
ocaml_lib ~extern:true "llvm_analysis";;
5+
ocaml_lib ~extern:true "llvm_executionengine";;
6+
ocaml_lib ~extern:true "llvm_target";;
7+
ocaml_lib ~extern:true "llvm_scalar_opts";;
8+
9+
flag ["link"; "ocaml"; "g++"] (S[A"-cc"; A"g++"; A"-cclib"; A"-rdynamic"]);
10+
dep ["link"; "ocaml"; "use_bindings"] ["bindings.o"];;

toplevel.ml

+15-5
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,25 @@
33
*===----------------------------------------------------------------------===*)
44

55
open Llvm
6+
open Llvm_executionengine
67

78
(* top ::= definition | external | expression | ';' *)
8-
let rec main_loop stream =
9+
let rec main_loop the_fpm the_execution_engine stream =
910
match Stream.peek stream with
1011
| None -> ()
1112

1213
(* ignore top-level semicolons. *)
1314
| Some (Token.Kwd ';') ->
1415
Stream.junk stream;
15-
main_loop stream
16+
main_loop the_fpm the_execution_engine stream
1617

1718
| Some token ->
1819
begin
1920
try match token with
2021
| Token.Def ->
2122
let e = Parser.parse_definition stream in
2223
print_endline "parsed a function definition.";
23-
dump_value (Codegen.codegen_func e);
24+
dump_value (Codegen.codegen_func the_fpm e);
2425
| Token.Extern ->
2526
let e = Parser.parse_extern stream in
2627
print_endline "parsed an extern.";
@@ -29,11 +30,20 @@ let rec main_loop stream =
2930
(* Evaluate a top-level expression into an anonymous function. *)
3031
let e = Parser.parse_toplevel stream in
3132
print_endline "parsed a top-level expr";
32-
dump_value (Codegen.codegen_func e);
33+
let the_function = Codegen.codegen_func the_fpm e in
34+
dump_value the_function;
35+
36+
(* JIT the function, returning a function pointer. *)
37+
let result = ExecutionEngine.run_function the_function [||]
38+
the_execution_engine in
39+
40+
print_string "Evaluated to ";
41+
print_float (GenericValue.as_float Codegen.double_type result);
42+
print_newline ();
3343
with Stream.Error s | Codegen.Error s ->
3444
(* Skip token for error recovery. *)
3545
Stream.junk stream;
3646
print_endline s;
3747
end;
3848
print_string "ready> "; flush stdout;
39-
main_loop stream
49+
main_loop the_fpm the_execution_engine stream

toy.ml

+26-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
*===----------------------------------------------------------------------===*)
55

66
open Llvm
7+
open Llvm_executionengine
8+
open Llvm_target
9+
open Llvm_scalar_opts
710

811
let main () =
912
(* Install standard binary operators.
@@ -18,8 +21,30 @@ let main () =
1821
print_string "ready> "; flush stdout;
1922
let stream = Lexer.lex (Stream.of_channel stdin) in
2023

24+
(* Create the JIT. *)
25+
let the_execution_engine = ExecutionEngine.create Codegen.the_module in
26+
let the_fpm = PassManager.create_function Codegen.the_module in
27+
28+
(* Set up the optimizer pipeline. Start with registering info about how the
29+
* target lays out data structures. *)
30+
TargetData.add (ExecutionEngine.target_data the_execution_engine) the_fpm;
31+
32+
(* Do simple "peephole" optimizations and bit-twiddling optzn. *)
33+
add_instruction_combination the_fpm;
34+
35+
(* reassociate expressions. *)
36+
add_reassociation the_fpm;
37+
38+
(* Eliminate Common SubExpressions. *)
39+
add_gvn the_fpm;
40+
41+
(* Simplify the control flow graph (deleting unreachable blocks, etc). *)
42+
add_cfg_simplification the_fpm;
43+
44+
ignore (PassManager.initialize the_fpm);
45+
2146
(* Run the main "interpreter loop" now. *)
22-
Toplevel.main_loop stream;
47+
Toplevel.main_loop the_fpm the_execution_engine stream;
2348

2449
(* Print out all the generated code. *)
2550
dump_module Codegen.the_module

0 commit comments

Comments
 (0)