├── .gitignore
├── LICENSE
├── Makefile
├── README.rst
├── basic_self_jit_x64.c
├── call_c_from_jit.c
├── call_puts_from_jit.c
├── gcd.c
└── gcd_iter.c
/.gitignore:
--------------------------------------------------------------------------------
1 | # Object files
2 | *.o
3 | *.ko
4 |
5 | # Libraries
6 | *.lib
7 | *.a
8 |
9 | # Shared objects (inc. Windows DLLs)
10 | *.dll
11 | *.so
12 | *.so.*
13 | *.dylib
14 |
15 | # Executables
16 | *.exe
17 | *.out
18 | *.app
19 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | This is free and unencumbered software released into the public domain.
2 |
3 | Anyone is free to copy, modify, publish, use, compile, sell, or
4 | distribute this software, either in source code form or as a compiled
5 | binary, for any purpose, commercial or non-commercial, and by any
6 | means.
7 |
8 | In jurisdictions that recognize copyright laws, the author or authors
9 | of this software dedicate any and all copyright interest in the
10 | software to the public domain. We make this dedication for the benefit
11 | of the public at large and to the detriment of our heirs and
12 | successors. We intend this dedication to be an overt act of
13 | relinquishment in perpetuity of all present and future rights to this
14 | software under copyright law.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 | OTHER DEALINGS IN THE SOFTWARE.
23 |
24 | For more information, please refer to
25 |
26 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | #-------------------------------------------------------------------------------
2 | # Makefile for building the code samples. Read inline comments for
3 | # documentation.
4 | #
5 | # Eli Bendersky (eliben@gmail.com)
6 | # This code is in the public domain
7 | #-------------------------------------------------------------------------------
8 |
9 | LIBJIT_PATH = $$HOME/test/libjit
10 | LIBJIT_INCLUDE_PATH = $(LIBJIT_PATH)/include
11 | LIBJIT_LIB_PATH = $(LIBJIT_PATH)/jit/.libs
12 | LIBJIT_AR = $(LIBJIT_LIB_PATH)/libjit.a
13 |
14 | CC = gcc
15 | LD = gcc
16 | CCOPT = -g -O0
17 | CCFLAGS = -c $(CCOPT)
18 | LDFLAGS = -lpthread -lm -ldl -lrt
19 |
20 | all: gcd gcd_iter call_c_from_jit call_puts_from_jit \
21 | basic_self_jit_x64
22 |
23 | gcd: gcd.o
24 | $(LD) $^ $(LIBJIT_AR) $(LDFLAGS) -o $@
25 |
26 | gcd.o: gcd.c
27 | $(CC) -I$(LIBJIT_INCLUDE_PATH) -I. $(CCFLAGS) $^ -o $@
28 |
29 | gcd_iter: gcd_iter.o
30 | $(LD) $^ $(LIBJIT_AR) $(LDFLAGS) -o $@
31 |
32 | gcd_iter.o: gcd_iter.c
33 | $(CC) -I$(LIBJIT_INCLUDE_PATH) -I. $(CCFLAGS) $^ -o $@
34 |
35 | call_c_from_jit: call_c_from_jit.o
36 | $(LD) $^ $(LIBJIT_AR) $(LDFLAGS) -o $@
37 |
38 | call_c_from_jit.o: call_c_from_jit.c
39 | $(CC) -I$(LIBJIT_INCLUDE_PATH) -I. $(CCFLAGS) $^ -o $@
40 |
41 | call_puts_from_jit: call_puts_from_jit.o
42 | $(LD) $^ $(LIBJIT_AR) $(LDFLAGS) -o $@
43 |
44 | call_puts_from_jit.o: call_puts_from_jit.c
45 | $(CC) -I$(LIBJIT_INCLUDE_PATH) -I. $(CCFLAGS) $^ -o $@
46 |
47 | basic_self_jit_x64: basic_self_jit_x64.c
48 | $(CC) $(CCOPT) $^ -o $@
49 |
50 | clean:
51 | rm -rf *.o gcd gcd_iter call_c_from_jit call_puts_from_jit \
52 | basic_self_jit_x64
53 |
54 |
55 |
--------------------------------------------------------------------------------
/README.rst:
--------------------------------------------------------------------------------
1 | libjit-samples
2 | ==============
3 |
4 | Code samples for using libjit and related APIs.
5 |
6 |
--------------------------------------------------------------------------------
/basic_self_jit_x64.c:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | // Simple JITing of code into memory.
3 | //
4 | // This example doesn't actually use libjit - it's much more basic.
5 | //
6 | // Eli Bendersky (eliben@gmail.com)
7 | // This code is in the public domain
8 | //------------------------------------------------------------------------------
9 | #include
10 | #include
11 | #include
12 | #include
13 |
14 |
15 | // Allocates RWX memory of given size and returns a pointer to it. On failure,
16 | // prints out the error and returns NULL.
17 | void* alloc_executable_memory(size_t size) {
18 | void* ptr = mmap(0, size,
19 | PROT_READ | PROT_WRITE | PROT_EXEC,
20 | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
21 | if (ptr == (void*)-1) {
22 | perror("mmap");
23 | return NULL;
24 | }
25 | return ptr;
26 | }
27 |
28 | // Allocates RW memory of given size and returns a pointer to it. On failure,
29 | // prints out the error and returns NULL. mmap is used to allocate, so
30 | // deallocation has to be done with munmap, and the memory is allocated
31 | // on a page boundary so it's suitable for calling mprotect.
32 | void* alloc_writable_memory(size_t size) {
33 | void* ptr = mmap(0, size,
34 | PROT_READ | PROT_WRITE,
35 | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
36 | if (ptr == (void*)-1) {
37 | perror("mmap");
38 | return NULL;
39 | }
40 | return ptr;
41 | }
42 |
43 | // Sets a RX permission on the given memory, which must be page-aligned. Returns
44 | // 0 on success. On failure, prints out the error and returns -1.
45 | int make_memory_executable(void* m, size_t size) {
46 | if (mprotect(m, size, PROT_READ | PROT_EXEC) == -1) {
47 | perror("mprotect");
48 | return -1;
49 | }
50 | return 0;
51 | }
52 |
53 | // Emits code into the given memory, assuming enough was allocated. Returns the
54 | // number of bytes emitted.
55 | size_t emit_code_into_memory(unsigned char* m) {
56 | unsigned char code[] = {
57 | 0x48, 0x89, 0xf8, // mov %rdi, %rax
58 | 0x48, 0x83, 0xc0, 0x04, // add $4, %rax
59 | 0xc3 // ret
60 | };
61 | memcpy(m, code, sizeof(code));
62 | return sizeof(code);
63 | }
64 |
65 | const size_t SIZE = 1024;
66 | typedef long (*JittedFunc)(long);
67 |
68 | // Allocates RWX memory directly.
69 | void run_from_rwx() {
70 | void* m = alloc_executable_memory(SIZE);
71 | size_t n = emit_code_into_memory(m);
72 |
73 | const char* filename = "/tmp/jitout.bin";
74 | FILE* outfile = fopen(filename, "wb");
75 | if (outfile) {
76 | if (fwrite(m, 1, n, outfile) == n) {
77 | printf("Successfully emitted binary to %s\n", filename);
78 | }
79 | fclose(outfile);
80 | }
81 |
82 | JittedFunc func = m;
83 | int result = func(2);
84 | printf("result = %d\n", result);
85 | }
86 |
87 | // Allocates RW memory, emits the code into it and sets it to RX before
88 | // executing.
89 | void emit_to_rw_run_from_rx() {
90 | void* m = alloc_writable_memory(SIZE);
91 | emit_code_into_memory(m);
92 | make_memory_executable(m, SIZE);
93 |
94 | JittedFunc func = m;
95 | int result = func(2);
96 | printf("result = %d\n", result);
97 | }
98 |
99 | int main(int argc, char** argv) {
100 | run_from_rwx();
101 | emit_to_rw_run_from_rx();
102 |
103 | return 0;
104 | }
105 |
--------------------------------------------------------------------------------
/call_c_from_jit.c:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | // call_c_from_jit libjit sample.
3 | //
4 | // Eli Bendersky (eliben@gmail.com)
5 | // This code is in the public domain
6 | //------------------------------------------------------------------------------
7 | #include
8 | #include
9 | #include
10 |
11 |
12 | int native_mult(int a, int b) {
13 | return a * b;
14 | }
15 |
16 | // Builds this function, and returns an uncompiled jit_function_t:
17 | //
18 | // int jit_adder(int x, y) {
19 | // return x + y;
20 | // }
21 | jit_function_t build_jit_adder(jit_context_t context) {
22 | jit_context_build_start(context);
23 |
24 | // Create function signature and object. int (*)(int, int)
25 | jit_type_t params[2] = {jit_type_int, jit_type_int};
26 | jit_type_t signature = jit_type_create_signature(
27 | jit_abi_cdecl, jit_type_int, params, 2, 1);
28 | jit_function_t F = jit_function_create(context, signature);
29 |
30 | // x, y are the parameters; sum is a temporary
31 | jit_value_t x = jit_value_get_param(F, 0);
32 | jit_value_t y = jit_value_get_param(F, 1);
33 | jit_value_t sum = jit_value_create(F, jit_type_int);
34 |
35 | // sum = x + y
36 | jit_value_t temp_sum = jit_insn_add(F, x, y);
37 | jit_insn_store(F, sum, temp_sum);
38 |
39 | // return sum
40 | jit_insn_return(F, sum);
41 | jit_context_build_end(context);
42 | return F;
43 | }
44 |
45 | // Builds this function:
46 | //
47 | // void foo(int x, int y, int* result) {
48 | // int t = jit_adder(x, y);
49 | // *result = native_mult(t, y);
50 | // }
51 | //
52 | // Returns an uncompiled jit_function_t
53 | // Note that jit_adder is a jit_function_t that's passed into this builder.
54 | jit_function_t build_foo(jit_context_t context, jit_function_t jit_adder) {
55 | jit_context_build_start(context);
56 |
57 | // Create function signature and object. void (*)(int, int, void*)
58 | // libjit treats all native pointers as void*.
59 | jit_type_t params[] = {jit_type_int, jit_type_int, jit_type_void_ptr};
60 | jit_type_t signature = jit_type_create_signature(
61 | jit_abi_cdecl, jit_type_void, params, 3, 1);
62 | jit_function_t F = jit_function_create(context, signature);
63 |
64 | // x, y, result are the parameters; t is a temporary
65 | jit_value_t x = jit_value_get_param(F, 0);
66 | jit_value_t y = jit_value_get_param(F, 1);
67 | jit_value_t result = jit_value_get_param(F, 2);
68 | jit_value_t t = jit_value_create(F, jit_type_int);
69 |
70 | // t = jit_adder(x, y)
71 | jit_value_t adder_args[] = {x, y};
72 | jit_value_t call_temp = jit_insn_call(
73 | F, "jit_adder", jit_adder, 0, adder_args, 2, 0);
74 |
75 | jit_insn_store(F, t, call_temp);
76 |
77 | // Prepare calling native_mult: create its signature
78 | jit_type_t mult_params[] = {jit_type_int, jit_type_int};
79 | jit_type_t mult_signature = jit_type_create_signature(
80 | jit_abi_cdecl, jit_type_int, params, 2, 1);
81 |
82 | // x = native_mult(t, y)
83 | jit_value_t mult_args[] = {t, y};
84 | jit_value_t res = jit_insn_call_native(
85 | F, "native_mult", native_mult, mult_signature,
86 | mult_args, sizeof(mult_args) / sizeof(jit_value_t), JIT_CALL_NOTHROW);
87 | jit_insn_store(F, x, res);
88 |
89 | // *result = x
90 | // Note that this creates a store of a value libjit considers to be a
91 | // jit_type_int, so the pointer must point to at least that size.
92 | jit_insn_store_relative(F, result, 0, x);
93 |
94 | jit_context_build_end(context);
95 | return F;
96 | }
97 |
98 |
99 | // Run foo with arguments and return its result
100 | int run_foo(jit_function_t jit_foo, int x, int y) {
101 | int result, *presult = &result;
102 | void* args[] = {&x, &y, &presult};
103 |
104 | jit_function_apply(jit_foo, args, NULL);
105 | return result;
106 | }
107 |
108 |
109 | int main(int argc, char** argv) {
110 | jit_init();
111 | jit_context_t context = jit_context_create();
112 | jit_function_t jit_adder = build_jit_adder(context);
113 | jit_function_t foo = build_foo(context, jit_adder);
114 |
115 | // This will dump the uncompiled function, showing libjit opcodes
116 | jit_dump_function(stdout, jit_adder, "jit_adder [uncompiled]");
117 | jit_dump_function(stdout, foo, "foo [uncompiled]");
118 |
119 | // Compile (JIT) the functions to machine code
120 | jit_context_build_start(context);
121 | jit_function_compile(jit_adder);
122 | jit_function_compile(foo);
123 | jit_context_build_end(context);
124 |
125 | // This will dump the disassembly of the machine code for the function
126 | jit_dump_function(stdout, jit_adder, "jit_adder [compiled]");
127 | jit_dump_function(stdout, foo, "foo [compiled]");
128 |
129 | // Run the function on argv input
130 | if (argc > 2) {
131 | int u = atoi(argv[1]);
132 | int v = atoi(argv[2]);
133 | printf("foo(%d, %d) --> %d\n", u, v, run_foo(foo, u, v));
134 | }
135 |
136 | jit_context_destroy(context);
137 | return 0;
138 | }
139 |
140 |
141 |
--------------------------------------------------------------------------------
/call_puts_from_jit.c:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | // call_puts_from_jit libjit sample.
3 | //
4 | // Eli Bendersky (eliben@gmail.com)
5 | // This code is in the public domain
6 | //------------------------------------------------------------------------------
7 | #include
8 | #include
9 | #include
10 |
11 |
12 | int main(int argc, char** argv) {
13 | jit_init();
14 | jit_context_t context = jit_context_create();
15 |
16 | // void foo()
17 | jit_function_t F = jit_function_create(context,
18 | jit_type_create_signature(jit_abi_cdecl, jit_type_void, NULL, 0, 1));
19 |
20 | // Approach #1: allocate the string buffer on stack inside the jit-ed
21 | // function and store the desired characters into it.
22 |
23 | // char* bufptr
24 | #define CONST_BYTE(v) (jit_value_create_nint_constant(F, jit_type_ubyte, v))
25 | jit_type_t type_cstring = jit_type_create_pointer(jit_type_sys_char, 1);
26 | jit_value_t bufptr = jit_value_create(F, type_cstring);
27 |
28 | // Make bufptr point to a 4-byte buffer allocated on the stack
29 | jit_insn_store(F, bufptr, jit_insn_alloca(F, CONST_BYTE(4)));
30 |
31 | // Store "abc" (with explicit terminating zero) into bufptr
32 | jit_insn_store_relative(F, bufptr, 0, CONST_BYTE('a'));
33 | jit_insn_store_relative(F, bufptr, 1, CONST_BYTE('b'));
34 | jit_insn_store_relative(F, bufptr, 2, CONST_BYTE('c'));
35 | jit_insn_store_relative(F, bufptr, 3, CONST_BYTE('\x00'));
36 |
37 | // Create the signature of puts: int (*)(char*)
38 | jit_type_t puts_signature = jit_type_create_signature(
39 | jit_abi_cdecl, jit_type_int, &type_cstring, 1, 1);
40 |
41 | // puts(bufptr);
42 | jit_insn_call_native(
43 | F, "puts", puts, puts_signature, &bufptr, 1, JIT_CALL_NOTHROW);
44 |
45 | // Approach #2: use the address of a string literal in the host code directly,
46 | // storing it into a constant. Note that this has to explicitly specify that
47 | // host pointers are 64-bit.
48 |
49 | jit_value_t hostmemptr = jit_value_create_long_constant(
50 | F, type_cstring, (long)"foobar");
51 |
52 | jit_insn_call_native(
53 | F, "puts", puts, puts_signature, &hostmemptr, 1, JIT_CALL_NOTHROW);
54 |
55 | jit_dump_function(stdout, F, "F [uncompiled]");
56 | jit_function_compile(F);
57 | jit_dump_function(stdout, F, "F [compiled]");
58 |
59 | // Run
60 | jit_function_apply(F, NULL, NULL);
61 |
62 | jit_context_destroy(context);
63 | return 0;
64 | }
65 |
66 |
67 |
--------------------------------------------------------------------------------
/gcd.c:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | // gcd.c Taken from the libjit tutorial, part 2.
3 | //
4 | // The libjit license applies to this file.
5 | //------------------------------------------------------------------------------
6 | /*
7 | * JITs this gcd function:
8 | * unsigned int gcd(unsigned int x, unsigned int y) {
9 | * if (x == y)
10 | * return x;
11 | * else if (x < y)
12 | * return gcd(x, y - x);
13 | * else
14 | * return gcd(x - y, y);
15 | * }
16 | */
17 |
18 | #include
19 | #include
20 |
21 | int main(int argc, char **argv) {
22 | jit_context_t context;
23 | jit_type_t params[2];
24 | jit_type_t signature;
25 | jit_function_t function;
26 | jit_value_t x, y;
27 | jit_value_t temp1, temp2;
28 | jit_value_t temp3, temp4;
29 | jit_value_t temp_args[2];
30 | jit_label_t label1 = jit_label_undefined;
31 | jit_label_t label2 = jit_label_undefined;
32 | jit_uint arg1, arg2;
33 | void *args[2];
34 | jit_uint result;
35 |
36 | /* Create a context to hold the JIT's primary state */
37 | context = jit_context_create();
38 |
39 | /* Lock the context while we build and compile the function */
40 | jit_context_build_start(context);
41 |
42 | /* Build the function signature */
43 | params[0] = jit_type_uint;
44 | params[1] = jit_type_uint;
45 | signature = jit_type_create_signature
46 | (jit_abi_cdecl, jit_type_uint, params, 2, 1);
47 |
48 | /* Create the function object */
49 | function = jit_function_create(context, signature);
50 | jit_type_free(signature);
51 |
52 | /* Check the condition "if(x == y)" */
53 | x = jit_value_get_param(function, 0);
54 | y = jit_value_get_param(function, 1);
55 | temp1 = jit_insn_eq(function, x, y);
56 | jit_insn_branch_if_not(function, temp1, &label1);
57 |
58 | /* Implement "return x" */
59 | jit_insn_return(function, x);
60 |
61 | /* Set "label1" at this position */
62 | jit_insn_label(function, &label1);
63 |
64 | /* Check the condition "if(x < y)" */
65 | temp2 = jit_insn_lt(function, x, y);
66 | jit_insn_branch_if_not(function, temp2, &label2);
67 |
68 | /* Implement "return gcd(x, y - x)" */
69 | temp_args[0] = x;
70 | temp_args[1] = jit_insn_sub(function, y, x);
71 | temp3 = jit_insn_call
72 | (function, "gcd", function, 0, temp_args, 2, 0);
73 | jit_insn_return(function, temp3);
74 |
75 | /* Set "label2" at this position */
76 | jit_insn_label(function, &label2);
77 |
78 | /* Implement "return gcd(x - y, y)" */
79 | temp_args[0] = jit_insn_sub(function, x, y);
80 | temp_args[1] = y;
81 | temp4 = jit_insn_call
82 | (function, "gcd", function, 0, temp_args, 2, 0);
83 | jit_insn_return(function, temp4);
84 |
85 | /* Compile the function */
86 | jit_function_compile(function);
87 |
88 | /* Unlock the context */
89 | jit_context_build_end(context);
90 |
91 | /* Execute the function and print the result */
92 | arg1 = 27;
93 | arg2 = 14;
94 | args[0] = &arg1;
95 | args[1] = &arg2;
96 | jit_function_apply(function, args, &result);
97 | printf("gcd(27, 14) = %u\n", (unsigned int)result);
98 |
99 | /* Clean up */
100 | jit_context_destroy(context);
101 |
102 | /* Finished */
103 | return 0;
104 | }
105 |
--------------------------------------------------------------------------------
/gcd_iter.c:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | // gcd_iter libjit sample. Iterative version of gcd.c
3 | //
4 | // Eli Bendersky (eliben@gmail.com)
5 | // This code is in the public domain
6 | //------------------------------------------------------------------------------
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 |
13 | // Native version for benchmarking
14 | int __attribute__ ((noinline)) gcd_iter_native(int u, int v) {
15 | int t;
16 | while (v) {
17 | t = u;
18 | u = v;
19 | v = t % v;
20 | }
21 | return u < 0 ? -u : u; /* abs(u) */
22 | }
23 |
24 | // Compute difference between two timespecs, as a timespec.
25 | struct timespec timespec_diff(struct timespec start, struct timespec end) {
26 | const long SEC = 1000 * 1000 * 1000; // 1 sec in ns
27 | struct timespec diff;
28 | if (end.tv_nsec < start.tv_nsec) {
29 | diff.tv_sec = end.tv_sec - start.tv_sec - 1;
30 | diff.tv_nsec = SEC + end.tv_nsec - start.tv_nsec;
31 | } else {
32 | diff.tv_sec = end.tv_sec - start.tv_sec;
33 | diff.tv_nsec = end.tv_nsec - start.tv_nsec;
34 | }
35 |
36 | return diff;
37 | }
38 |
39 | void print_diff(struct timespec start, struct timespec end) {
40 | struct timespec diff = timespec_diff(start, end);
41 | printf("Elapsed %ld . %ld\n", diff.tv_sec, diff.tv_nsec);
42 | }
43 |
44 | // Run a benchmark
45 | void benchmark(jit_function_t jit_f) {
46 | int n1 = 49979687;
47 | int n2 = 982451653;
48 | const int N = 5 * 1000 * 1000;
49 | struct timespec t1, t2, d;
50 | typedef int (*FF)(int, int);
51 | int i, g;
52 |
53 | // Arguments for the JIT invocation
54 | void* args[] = {&n1, &n2};
55 | jit_int result;
56 |
57 | printf("Native\n");
58 | clock_gettime(CLOCK_REALTIME, &t1);
59 | for (i = 0; i < N; ++i) {
60 | g = gcd_iter_native(n1, n2);
61 | }
62 | clock_gettime(CLOCK_REALTIME, &t2);
63 | print_diff(t1, t2);
64 |
65 | printf("\nJIT apply\n");
66 | clock_gettime(CLOCK_REALTIME, &t1);
67 | for (i = 0; i < N; ++i) {
68 | jit_function_apply(jit_f, args, &result);
69 | }
70 | clock_gettime(CLOCK_REALTIME, &t2);
71 | print_diff(t1, t2);
72 |
73 | printf("\nJIT closure\n");
74 | FF clos = jit_function_to_closure(jit_f);
75 | clock_gettime(CLOCK_REALTIME, &t1);
76 | for (i = 0; i < N; ++i) {
77 | g = clos(n1, n2);
78 | }
79 | clock_gettime(CLOCK_REALTIME, &t2);
80 | print_diff(t1, t2);
81 | }
82 |
83 |
84 | // Builds a function that performs the iterative GCD computation, implementing
85 | // the following C code:
86 | //
87 | // int gcd_iter(int u, int v) {
88 | // int t;
89 | // while (v) {
90 | // t = u;
91 | // u = v;
92 | // v = t % v;
93 | // }
94 | // return u < 0 ? -u : u; /* abs(u) */
95 | // }
96 | //
97 | // Returns an uncompiled jit_function_t.
98 | jit_function_t build_gcd_func(jit_context_t context) {
99 | jit_context_build_start(context);
100 |
101 | // Create function signature and object. int (*)(int, int)
102 | jit_type_t params[2] = {jit_type_int, jit_type_int};
103 | jit_type_t signature = jit_type_create_signature(
104 | jit_abi_cdecl, jit_type_int, params, 2, 1);
105 | jit_function_t F = jit_function_create(context, signature);
106 |
107 | // u, v are function parameters; t is a temporary value.
108 | jit_value_t u, v, t;
109 | u = jit_value_get_param(F, 0);
110 | v = jit_value_get_param(F, 1);
111 | t = jit_value_create(F, jit_type_int);
112 |
113 | // Create the while (v) condition with a label that allows to loop back.
114 | //
115 | // label_while:
116 | // if (v == 0) goto label_after_while
117 | // .. contents of while loop
118 | //
119 | // label_after_while is created as undefined at this point, so that
120 | // instructions can have forward references to it. It will be placed later.
121 | jit_label_t label_while = jit_label_undefined;
122 | jit_label_t label_after_while = jit_label_undefined;
123 | jit_value_t const0 = jit_value_create_nint_constant(F, jit_type_int, 0);
124 |
125 | jit_insn_label(F, &label_while);
126 | jit_value_t cmp_v_0 = jit_insn_eq(F, v, const0);
127 | jit_insn_branch_if(F, cmp_v_0, &label_after_while);
128 |
129 | // t = u
130 | jit_insn_store(F, t, u);
131 | // u = v
132 | jit_insn_store(F, u, v);
133 |
134 | // v = t % v
135 | jit_value_t rem = jit_insn_rem(F, t, v);
136 | jit_insn_store(F, v, rem);
137 |
138 | // goto label_while
139 | // label_after_while:
140 | // ...
141 | jit_insn_branch(F, &label_while);
142 | jit_insn_label(F, &label_after_while);
143 |
144 | // if (u >= 0) goto label_positive
145 | // return -u
146 | // label_pos:
147 | // return u
148 | jit_label_t label_positive = jit_label_undefined;
149 | jit_value_t cmp_u_0 = jit_insn_ge(F, u, const0);
150 | jit_insn_branch_if(F, cmp_u_0, &label_positive);
151 |
152 | jit_value_t minus_u = jit_insn_neg(F, u);
153 | jit_insn_return(F, minus_u);
154 | jit_insn_label(F, &label_positive);
155 | jit_insn_return(F, u);
156 |
157 | jit_context_build_end(context);
158 | return F;
159 | }
160 |
161 |
162 | int main(int argc, char** argv) {
163 | jit_init();
164 | jit_context_t context = jit_context_create();
165 | jit_function_t gcd = build_gcd_func(context);
166 |
167 | // This will dump the uncompiled function, showing libjit opcodes
168 | jit_dump_function(stdout, gcd, "gcd [uncompiled]");
169 |
170 | printf("Optimization level: %u\n", jit_function_get_optimization_level(gcd));
171 | // Compile (JIT) the function to machine code
172 | jit_context_build_start(context);
173 | jit_function_compile(gcd);
174 | jit_context_build_end(context);
175 |
176 | // This will dump the disassembly of the machine code for the function
177 | jit_dump_function(stdout, gcd, "gcd [compiled]");
178 |
179 | // Run the function on argv input
180 | if (argc > 2) {
181 | int u = atoi(argv[1]);
182 | int v = atoi(argv[2]);
183 | void* args[2] = {&u, &v};
184 |
185 | printf("gcd(%d, %d) --> ", u, v);
186 | jit_int result;
187 | jit_function_apply(gcd, args, &result);
188 | /*typedef int (*FF)(int, int);*/
189 | /*FF gcd_f = jit_function_to_closure(gcd);*/
190 | /*int result = gcd_f(u, v);*/
191 | printf("%d\n", (int)result);
192 | }
193 |
194 | /*benchmark(gcd);*/
195 |
196 | jit_context_destroy(context);
197 | return 0;
198 | }
199 |
200 |
--------------------------------------------------------------------------------