--- tags: MIR --- # mir API 介紹 TODO - [ ] 整理入門到中階的範例傳到 github,不然這篇不好懂。 ## 初始化 MIR 初始化跟結束分別為 `MIR_init()` / `MIR_finish (MIR_context_t ctx)` 當建立好 mir 的物件,可以將要實作的功能包裝成模組(module),mir 會用內建的雙向 linked list 將模組連接在一起,而模組包含了下面這些項目(item) * Function * Import * Export * Foward declaration * Prototype * Data * Reference data * Expression Data * Memory segment 模組的初始化跟結束分別為 `MIR_new_module` / `MIR_finish_module` ## c2mir 將 C 程式碼當作輸入的話要透過 c2mir 的 API 來達成,其中 `c2mir_compile` 的 `get_func` 會用來讀取程式碼,而 `jit_ptr` 會當作參數傳入 `get_func`,讀取完畢會回傳 EOF。 ```c typedef struct jit_item { char *code; size_t code_size; size_t curr; } jit_item_t; int get_func(void *data) { jit_item_t *item = data; return item->curr >= item->code_size ? EOF : item->code[item->curr++]; } jit_item_t *jit_ptr = (jit_item_t *)malloc(sizeof(jit_item_t *)); jit_ptr->curr = 0; jit_ptr->code = "int add(int a,int b) { \ int c = a + b; \ printf(\"%d + %d = %d\n\", a, b, c); \ return a + b; \ }\n "; jit_ptr->code_size = strlen(jit_ptr->code); if (!c2mir_compile(ctx, options, get_func, jit_ptr, name, NULL)) { perror("Compile failure"); exit(EXIT_FAILURE); } ``` 當 `c2mir_compile` 成功之後,會當作模組給 ctx 接上,所以如果今天是做直譯器的話,要呼叫編譯好的函數就要從 ctx 的模組的尾把取得編譯好的模組,再從模組裡面找編譯好的函數,透過 MIR-generator 產生機器碼就可以當作函式來呼叫了。 ```c MIR_module_t module = DLIST_TAIL(MIR_module_t, *MIR_get_module_list(ctx)); MIR_item_t func = DLIST_HEAD(MIR_item_t, module->items); size_t func_len = DLIST_LENGTH(MIR_item_t, module->items); int a = 10, b = 50; for (int i = 0; i < func_len; i++, func = DLIST_NEXT(MIR_item_t, func)) { if (func->item_type == MIR_func_item) { int (*arich)(int, int) = MIR_gen(ctx, 0, func); arich(a, b); printf("%d + %d = %d\n", a, b, c); break; } } ``` ## 連結 執行 mir 之前需要將模組載入跟連結 ```c MIR_load_module (MIR_context ctx, MIR_module_t m) MIR_link (MIR_context ctx, void (*set_interface) (MIR_item_t item), void * (*import_resolver) (const char *)) ``` `MIR_link` 的 set_interface 有3種 * `MIR_set_interp_interface`: 呼叫函數的時候將 MIR 的直譯 * `MIR_set_gen_interface`: MIR-generator 會將所有載入的函式產生機器碼,當呼叫函數就會執行機器碼 * `MIR_set_lazy_gen_interface`: MIR-generator 只會當函式第一次被呼叫的時候產生機器碼 import_solver 則是當 mir 的 context 裡面有未使用 MIR 定義的函式(e.g. printf) 就會傳入函式名稱當作 key 來查詢,如果有找到函式就會回傳函式的地址。 >未使用 MIR 定義的函式只會被呼叫不會被 MIR-generator 優化 >[color=#f24] ```c typedef struct { char *name; void (*func)(void); } func_obj_t; func_obj_t func_list[4] = { {"printf", printf}, {"puts", puts}, {"show_result", show_result}, {"show_item", show_item}, {NULL, NULL} }; void *import_resolver(const char *name) { size_t len = sizeof(func_list) / sizeof(func_obj_t); for (int i = 0; len; i++) if (!strcmp(func_list[i].name, name)) return func_list[i].func; return NULL; } MIR_link(ctx, MIR_set_gen_interface, import_resolver); ``` ## 執行 當模組都載入跟連結後就可以透過 MIR-generator 來產生機器碼了。 ```c void MIR_gen_init (MIR_context_t ctx, int gens_num); void MIR_gen_finish (MIR_context_t ctx); void MIR_gen_set_optimize_level (MIR_context_t ctx, int gen_num, unsigned int level); void *MIR_gen (MIR_context_t ctx, int gen_num, MIR_item_t func_item); ``` gens_num 表示要使用幾個 generator 來產生機器碼,每個 generator 都是不同的執行緒 MIR_gen 產生函式的機器碼,並回傳函式的地址,可以當作 C 函式來呼叫,呼叫後會執行產生的機器碼。 MIR_gen_set_optimize_level 設定優化的等級,一共有4級(0 ~ 3)可以選,等級愈高優化的愈激進,編譯時間也愈長,可以參考下圖的流程。 ![](https://i.imgur.com/i7EFYHU.png)