---
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)