Skip to content

Commit 73ceff9

Browse files
committed
黒魔術は濫用してなんぼ
1 parent 6da5876 commit 73ceff9

15 files changed

Lines changed: 7401 additions & 1175 deletions

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
.cache/
22
build/
3+
build-x86/
4+
build-aarch64/
35
build-test/
6+
refs/
47
.DS_Store
58
Thumbs.db

CMakeLists.txt

Lines changed: 4 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -8,64 +8,24 @@ set(CMAKE_C_EXTENSIONS OFF)
88

99
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
1010

11-
find_program(LLVM_CONFIG_EXECUTABLE NAMES llvm-config-22 llvm-config REQUIRED)
12-
13-
function(bfjit_query_llvm_config output_variable option)
14-
execute_process(
15-
COMMAND "${LLVM_CONFIG_EXECUTABLE}" "${option}"
16-
OUTPUT_VARIABLE query_output
17-
OUTPUT_STRIP_TRAILING_WHITESPACE
18-
RESULT_VARIABLE query_status
19-
)
20-
21-
if(NOT query_status EQUAL 0)
22-
message(FATAL_ERROR "Failed to query LLVM using ${LLVM_CONFIG_EXECUTABLE} ${option}")
23-
endif()
24-
25-
set(${output_variable} "${query_output}" PARENT_SCOPE)
26-
endfunction()
27-
28-
bfjit_query_llvm_config(LLVM_VERSION --version)
29-
30-
if(NOT LLVM_VERSION MATCHES "^22\\.")
31-
message(FATAL_ERROR "LLVM 22 is required, but ${LLVM_VERSION} was found")
32-
endif()
33-
34-
bfjit_query_llvm_config(LLVM_INCLUDE_DIR --includedir)
35-
bfjit_query_llvm_config(LLVM_SHARED_MODE --shared-mode)
36-
bfjit_query_llvm_config(LLVM_LIBFILES_RAW --libfiles)
37-
38-
if(NOT LLVM_SHARED_MODE STREQUAL "shared")
39-
message(FATAL_ERROR "LLVM must provide shared libraries, but llvm-config --shared-mode returned ${LLVM_SHARED_MODE}")
40-
endif()
41-
42-
string(REPLACE "\n" ";" LLVM_SHARED_LIBRARIES "${LLVM_LIBFILES_RAW}")
43-
list(FILTER LLVM_SHARED_LIBRARIES EXCLUDE REGEX "^$")
44-
45-
if(NOT LLVM_SHARED_LIBRARIES)
46-
message(FATAL_ERROR "No LLVM shared libraries were reported by llvm-config --libfiles")
47-
endif()
48-
49-
add_library(llvm-shared INTERFACE)
50-
target_include_directories(llvm-shared INTERFACE "${LLVM_INCLUDE_DIR}")
51-
target_link_libraries(llvm-shared INTERFACE ${LLVM_SHARED_LIBRARIES})
52-
5311
add_library(libbfjit STATIC
5412
include/bfjit.h
5513
include/bfjit_internal.h
5614
include/bflexer.h
5715
include/bfopt.h
5816
include/bfparser.h
5917
src/bfjit.c
60-
src/bfjit_codegen.c
18+
src/bfjit_backend.c
19+
src/bfjit_backend_shared.c
20+
src/bfjit_backend_x86_64.c
21+
src/bfjit_backend_aarch64.c
6122
src/bfjit_runtime.c
6223
src/bflexer.c
6324
src/bfopt.c
6425
src/bfparser.c
6526
)
6627

6728
target_include_directories(libbfjit PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include")
68-
target_link_libraries(libbfjit PUBLIC llvm-shared)
6929
set_target_properties(libbfjit PROPERTIES OUTPUT_NAME bfjit)
7030

7131
add_executable(bfjit src/main.c)

include/bfjit.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,7 @@ typedef struct bf_jit_err {
1414

1515
bool bf_jit_execute_program(const bf_program *program, uint8_t *tape,
1616
size_t tape_size, bf_jit_err *err);
17+
bool bf_jit_dump_program_code(const bf_program *program,
18+
const char *output_path, bf_jit_err *err);
1719

1820
#endif // BFJIT_H

include/bfjit_internal.h

Lines changed: 266 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,276 @@
33

44
#include "bfjit.h"
55

6-
#include <llvm-c/Core.h>
7-
#include <llvm-c/Error.h>
8-
#include <llvm-c/LLJIT.h>
9-
#include <llvm-c/Orc.h>
6+
typedef int (*bf_jit_entry_fn)(uint8_t *tape, size_t tape_size);
7+
typedef int (*bf_runtime_entry_fn)(uint8_t *tape, size_t tape_size,
8+
const bf_program *program);
9+
10+
typedef struct bf_jit_state {
11+
uint8_t *tape;
12+
size_t tape_size;
13+
size_t pointer;
14+
} bf_jit_state;
15+
16+
typedef struct bf_jit_compiled_program {
17+
bf_jit_entry_fn entry;
18+
void *code;
19+
size_t code_size;
20+
size_t mapping_size;
21+
} bf_jit_compiled_program;
22+
23+
typedef struct bf_runtime_profile {
24+
size_t total_node_executions;
25+
size_t node_counts[BF_IR_NONNULL_MULTIPLY_LOOP + 1];
26+
size_t scan_step1_count;
27+
size_t scan_step4_count;
28+
size_t scan_other_count;
29+
size_t scan_other_positive_count;
30+
size_t scan_other_negative_count;
31+
size_t scan_step1_distance_total;
32+
size_t scan_step4_distance_total;
33+
size_t scan_other_distance_total;
34+
size_t scan_other_positive_distance_total;
35+
size_t scan_other_negative_distance_total;
36+
size_t scan_pending_offset_nonzero_count;
37+
size_t scan_pending_offset_abs_total;
38+
size_t scan_pending_offset_max_abs;
39+
struct bf_runtime_scan_context_entry *scan_context_entries;
40+
size_t scan_context_entry_count;
41+
size_t scan_context_entry_capacity;
42+
size_t multiply_loop_term_total;
43+
size_t simple_segment_executions;
44+
size_t simple_segment_total_nodes;
45+
size_t simple_segment_max_nodes;
46+
struct bf_runtime_simple_segment_entry *simple_segment_entries;
47+
size_t simple_segment_entry_count;
48+
size_t simple_segment_entry_capacity;
49+
} bf_runtime_profile;
50+
51+
typedef struct bf_runtime_simple_segment_entry {
52+
char *signature;
53+
const bf_ir_node *context_node;
54+
char *context_signature;
55+
bf_ir_kind context_kind;
56+
size_t executions;
57+
} bf_runtime_simple_segment_entry;
58+
59+
typedef struct bf_runtime_scan_context_entry {
60+
int pending_offset;
61+
int step;
62+
size_t executions;
63+
} bf_runtime_scan_context_entry;
64+
65+
typedef enum bf_jit_patch_kind {
66+
BF_JIT_PATCH_BRANCH,
67+
BF_JIT_PATCH_COND,
68+
BF_JIT_PATCH_CBZ,
69+
BF_JIT_PATCH_CBNZ
70+
} bf_jit_patch_kind;
71+
72+
typedef struct bf_jit_patch {
73+
size_t offset;
74+
bf_jit_patch_kind kind;
75+
} bf_jit_patch;
76+
77+
typedef struct bf_jit_label {
78+
size_t position;
79+
bf_jit_patch *patches;
80+
size_t patch_count;
81+
size_t patch_capacity;
82+
} bf_jit_label;
83+
84+
typedef enum bf_jit_simple_effect_kind {
85+
BF_JIT_SIMPLE_EFFECT_NONE = 0,
86+
BF_JIT_SIMPLE_EFFECT_ADD = 1,
87+
BF_JIT_SIMPLE_EFFECT_SET = 2
88+
} bf_jit_simple_effect_kind;
89+
90+
typedef struct bf_jit_simple_effect {
91+
int effective_offset;
92+
bf_jit_simple_effect_kind kind;
93+
uint8_t value;
94+
} bf_jit_simple_effect;
95+
96+
typedef struct bf_jit_two_simple_effects {
97+
size_t count;
98+
bf_jit_simple_effect effects[2];
99+
} bf_jit_two_simple_effects;
100+
101+
typedef struct bf_jit_simple_run_info {
102+
size_t next_index;
103+
int pending_offset_after;
104+
int min_offset;
105+
int max_offset;
106+
bool has_simple;
107+
size_t first_simple_index;
108+
int first_simple_pending_offset;
109+
size_t second_simple_index;
110+
int second_simple_pending_offset;
111+
size_t simple_count;
112+
} bf_jit_simple_run_info;
113+
114+
typedef struct bf_jit_pending_offset_ops {
115+
int (*emit_simple_run)(void *context, const bf_ir_block *block,
116+
size_t start_index, size_t *next_index,
117+
int *pending_offset);
118+
int (*emit_control_with_pending_offset)(void *context,
119+
const bf_ir_node *node,
120+
int pending_offset);
121+
int (*emit_input_at_offset)(void *context, int offset);
122+
int (*emit_output_at_offset)(void *context, int offset);
123+
int (*emit_add_ptr)(void *context, int delta);
124+
int (*emit_scan_with_pending_offset)(void *context, const bf_ir_node *node,
125+
int pending_offset);
126+
int (*emit_multiply_with_pending_offset)(void *context,
127+
const bf_ir_node *node,
128+
int pending_offset);
129+
int (*emit_node)(void *context, const bf_ir_node *node);
130+
} bf_jit_pending_offset_ops;
131+
132+
typedef enum bf_jit_control_flow_plan_kind {
133+
BF_JIT_CONTROL_FLOW_PLAN_NONE = 0,
134+
BF_JIT_CONTROL_FLOW_PLAN_LOOP_WITH_PENDING_OFFSET,
135+
BF_JIT_CONTROL_FLOW_PLAN_IF_WITH_PENDING_OFFSET,
136+
} bf_jit_control_flow_plan_kind;
137+
138+
typedef struct bf_jit_control_flow_plan {
139+
bf_jit_control_flow_plan_kind kind;
140+
} bf_jit_control_flow_plan;
141+
142+
typedef enum bf_jit_scan_plan_kind {
143+
BF_JIT_SCAN_PLAN_ERROR = 0,
144+
BF_JIT_SCAN_PLAN_STEP1,
145+
BF_JIT_SCAN_PLAN_STRIDE4,
146+
BF_JIT_SCAN_PLAN_GENERIC,
147+
} bf_jit_scan_plan_kind;
148+
149+
typedef struct bf_jit_scan_plan {
150+
bf_jit_scan_plan_kind kind;
151+
int step;
152+
} bf_jit_scan_plan;
153+
154+
typedef struct bf_jit_scan_ops {
155+
void (*label_init)(bf_jit_label *label);
156+
void (*label_dispose)(bf_jit_label *label);
157+
int (*bind_label)(void *context, bf_jit_label *label);
158+
int (*emit_jump)(void *context, bf_jit_label *label);
159+
int (*emit_invalid_step)(void *context);
160+
int (*emit_load_state)(void *context);
161+
int (*emit_store_pointer)(void *context);
162+
int (*emit_prepare_upper_bound)(void *context);
163+
int (*emit_branch_current_zero)(void *context, bf_jit_label *label);
164+
int (*emit_branch_current_nonzero)(void *context, bf_jit_label *label);
165+
int (*emit_branch_disp_zero)(void *context, int offset,
166+
bf_jit_label *label);
167+
int (*emit_branch_if_current_oob)(void *context);
168+
int (*emit_branch_if_advance_oob)(void *context, int delta,
169+
bf_jit_label *label);
170+
int (*emit_branch_if_backward_oob)(void *context, int delta);
171+
int (*emit_advance)(void *context, int delta);
172+
} bf_jit_scan_ops;
173+
174+
typedef struct bf_jit_multi_zero_plan {
175+
bool is_noop;
176+
int min_offset;
177+
int max_offset;
178+
} bf_jit_multi_zero_plan;
179+
180+
typedef struct bf_jit_multiply_loop_plan {
181+
bool zero_current_only;
182+
bool has_terms;
183+
bool has_small_term_count;
184+
int min_offset;
185+
int max_offset;
186+
} bf_jit_multiply_loop_plan;
187+
188+
typedef enum bf_jit_multiply_term_plan_kind {
189+
BF_JIT_MULTIPLY_TERM_PLAN_ADD_SOURCE = 0,
190+
BF_JIT_MULTIPLY_TERM_PLAN_SUB_SOURCE,
191+
BF_JIT_MULTIPLY_TERM_PLAN_GENERAL,
192+
} bf_jit_multiply_term_plan_kind;
193+
194+
typedef struct bf_jit_multiply_term_plan {
195+
bf_jit_multiply_term_plan_kind kind;
196+
int offset;
197+
int factor;
198+
} bf_jit_multiply_term_plan;
199+
200+
typedef struct bf_jit_multiply_term_ops {
201+
int (*emit_term)(void *context, const bf_jit_multiply_term_plan *plan);
202+
} bf_jit_multiply_term_ops;
203+
204+
typedef struct bf_jit_size_hint_ops {
205+
size_t (*node_size_hint)(const bf_ir_node *node, void *context);
206+
void *context;
207+
} bf_jit_size_hint_ops;
10208

11209
void bf_jit_err_reset(bf_jit_err *err);
12210
void bf_set_jit_err(bf_jit_err *err, const char *msg);
13-
void bf_set_jit_err_from_llvm(bf_jit_err *err, LLVMErrorRef llvm_err);
14211

15-
LLVMModuleRef bf_build_module(LLVMContextRef ctx, const bf_program *program,
16-
bf_jit_err *err);
17-
int bf_opt_llvm_module(LLVMModuleRef mod, bf_jit_err *err);
212+
bool bf_jit_backend_compile(const bf_program *program,
213+
bf_jit_compiled_program *compiled, bf_jit_err *err);
214+
void bf_jit_backend_dispose(bf_jit_compiled_program *compiled);
215+
216+
size_t bf_jit_arch_code_size(const bf_program *program);
217+
bool bf_jit_arch_emit_program(uint8_t *code, size_t code_size,
218+
const bf_program *program, bf_jit_err *err,
219+
size_t *emitted_size);
220+
221+
bool bf_jit_node_is_simple(const bf_ir_node *node);
222+
int bf_jit_simple_node_effective_offset(const bf_ir_node *node,
223+
int pending_offset);
224+
bf_jit_simple_effect_kind
225+
bf_jit_simple_node_effect_kind(const bf_ir_node *node);
226+
uint8_t bf_jit_simple_node_effect_value(const bf_ir_node *node);
227+
void bf_jit_merge_simple_effect(bf_jit_simple_effect_kind *effect_kind,
228+
uint8_t *effect_value,
229+
bf_jit_simple_effect_kind next_kind,
230+
uint8_t next_value);
231+
void bf_jit_collect_simple_run_info(const bf_ir_block *block,
232+
size_t start_index, int pending_offset,
233+
bf_jit_simple_run_info *info);
234+
bool bf_jit_if_has_nonnull_multiply_simple_tail(
235+
const bf_ir_node *node, bf_jit_simple_run_info *tail_info);
236+
void bf_jit_build_two_simple_effects(const bf_ir_node *first_node,
237+
int first_pending_offset,
238+
const bf_ir_node *second_node,
239+
int second_pending_offset,
240+
bf_jit_two_simple_effects *effects);
241+
bool bf_jit_block_is_offset_safe_zero_delta(const bf_ir_block *block);
242+
void bf_jit_build_control_flow_plan(const bf_ir_node *node, int pending_offset,
243+
bf_jit_control_flow_plan *plan);
244+
void bf_jit_build_scan_plan(int step, bf_jit_scan_plan *plan);
245+
int bf_jit_emit_scan_shared(int step, const bf_jit_scan_ops *ops,
246+
void *context);
247+
void bf_jit_build_multi_zero_plan(const bf_ir_node *node,
248+
bf_jit_multi_zero_plan *plan);
249+
void bf_jit_build_multiply_loop_plan(const bf_ir_node *node,
250+
bf_jit_multiply_loop_plan *plan);
251+
void bf_jit_build_multiply_term_plan(const bf_multiply_term *term,
252+
bf_jit_multiply_term_plan *plan);
253+
int bf_jit_emit_multiply_terms_shared(const bf_ir_node *node,
254+
const bf_jit_multiply_term_ops *ops,
255+
void *context);
256+
size_t bf_jit_block_size_hint_shared(const bf_ir_block *block,
257+
const bf_jit_size_hint_ops *ops);
258+
int bf_jit_emit_block_with_pending_offset_shared(
259+
const bf_ir_block *block, int *pending_offset, int flush_pending_offset,
260+
const bf_jit_pending_offset_ops *ops, void *context);
18261

19-
LLVMOrcMaterializationUnitRef bf_create_io_symbols(LLVMOrcLLJITRef jit);
262+
int bf_runtime_execute(const bf_program *program, uint8_t *tape,
263+
size_t tape_size);
264+
int bf_runtime_execute_profiled(const bf_program *program, uint8_t *tape,
265+
size_t tape_size, bf_runtime_profile *profile);
266+
void bf_runtime_profile_dispose(bf_runtime_profile *profile);
267+
int bf_runtime_read_byte(void);
268+
void bf_runtime_write_byte(uint8_t value);
269+
int bf_runtime_execute_scan(bf_jit_state *state, int step);
270+
int bf_runtime_execute_multi_zero(bf_jit_state *state, const bf_ir_node *node);
271+
int bf_runtime_execute_multiply_loop(bf_jit_state *state,
272+
const bf_ir_node *node);
273+
size_t bf_runtime_scan_index(const uint8_t *tape, size_t tape_size,
274+
size_t start_index, int64_t step);
275+
size_t bf_runtime_scan_index_step4(const uint8_t *tape, size_t tape_size,
276+
size_t start_index);
20277

21278
#endif

include/bfparser.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,18 @@
99
typedef enum bf_ir_kind {
1010
BF_IR_ADD_PTR = 0,
1111
BF_IR_ADD_DATA,
12+
BF_IR_ADD_DATA_OFFSET,
1213
BF_IR_INPUT,
1314
BF_IR_OUTPUT,
1415
BF_IR_LOOP,
16+
BF_IR_IF,
1517
BF_IR_SET_ZERO,
1618
BF_IR_SET_CONST,
19+
BF_IR_SET_CONST_OFFSET,
1720
BF_IR_MULTI_ZERO,
1821
BF_IR_SCAN,
19-
BF_IR_MULTIPLY_LOOP
22+
BF_IR_MULTIPLY_LOOP,
23+
BF_IR_NONNULL_MULTIPLY_LOOP
2024
} bf_ir_kind;
2125

2226
typedef struct bf_multiply_term {
@@ -36,6 +40,7 @@ struct bf_ir_node {
3640
bf_ir_kind kind;
3741
bf_src_loc loc;
3842
int arg;
43+
int offset;
3944
bf_ir_block body;
4045
bf_multiply_term *terms;
4146
size_t term_count;

0 commit comments

Comments
 (0)