feat(ir): 添加MIR中间表示层并重构LIR相关代码
- 新增mir库模块,包含scc_mir、scc_mir_module、scc_mir_dump等组件 - 添加LIR到MIR的转换接口scc_lir2mir - 定义MIR操作数类型和指令结构,支持虚拟寄存器、物理寄存器、立即数等 - 实现x86_64指令选择器,将LIR指令转换为MIR指令 - 重构LIR模块中函数参数命名,统一使用lir_module参数名 - 移除LIR中物理寄存器相关的代码和注释 - 更新cbuild.toml依赖配置,添加mir模块依赖
This commit is contained in:
@@ -11,6 +11,7 @@ dependencies = [
|
|||||||
{ name = "ast2ir", path = "./libs/ast2ir" },
|
{ name = "ast2ir", path = "./libs/ast2ir" },
|
||||||
{ name = "hir", path = "./libs/ir/hir" },
|
{ name = "hir", path = "./libs/ir/hir" },
|
||||||
{ name = "lir", path = "./libs/ir/lir" },
|
{ name = "lir", path = "./libs/ir/lir" },
|
||||||
|
{ name = "mir", path = "./libs/ir/mir" },
|
||||||
|
|
||||||
# { name = "ir2mcode", path = "./libs/ir2mcode" },
|
# { name = "ir2mcode", path = "./libs/ir2mcode" },
|
||||||
# { name = "sccf2target", path = "./libs/target/sccf2target" },
|
# { name = "sccf2target", path = "./libs/target/sccf2target" },
|
||||||
|
|||||||
@@ -31,9 +31,9 @@ typedef enum scc_lir_attr {
|
|||||||
} scc_lir_attr_t;
|
} scc_lir_attr_t;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
SCC_LIR_INSTR_KIND_NONE, // 无操作数
|
SCC_LIR_INSTR_KIND_NONE, // 无操作数
|
||||||
SCC_LIR_INSTR_KIND_VREG, // 虚拟寄存器
|
SCC_LIR_INSTR_KIND_VREG, // 虚拟寄存器
|
||||||
SCC_LIR_INSTR_KIND_PREG, // 物理寄存器 (后端定义编号)
|
// SCC_LIR_INSTR_KIND_PREG, // 物理寄存器 (后端定义编号)
|
||||||
SCC_LIR_INSTR_KIND_IMM, // 整数立即数
|
SCC_LIR_INSTR_KIND_IMM, // 整数立即数
|
||||||
SCC_LIR_INSTR_KIND_FIMM, // 浮点立即数
|
SCC_LIR_INSTR_KIND_FIMM, // 浮点立即数
|
||||||
SCC_LIR_INSTR_KIND_SYMBOL, // 全局符号 (函数名、全局变量、字符串常量)
|
SCC_LIR_INSTR_KIND_SYMBOL, // 全局符号 (函数名、全局变量、字符串常量)
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
scc_tree_dump_t *dump_ctx;
|
scc_tree_dump_t *dump_ctx;
|
||||||
scc_lir_module_t *module;
|
scc_lir_module_t *lir_module;
|
||||||
} scc_lir_dump_ctx_t;
|
} scc_lir_dump_ctx_t;
|
||||||
|
|
||||||
static inline void scc_lir_dump_init(scc_lir_dump_ctx_t *ctx,
|
static inline void scc_lir_dump_init(scc_lir_dump_ctx_t *ctx,
|
||||||
@@ -15,7 +15,7 @@ static inline void scc_lir_dump_init(scc_lir_dump_ctx_t *ctx,
|
|||||||
scc_lir_module_t *module) {
|
scc_lir_module_t *module) {
|
||||||
Assert(ctx != nullptr && dump_ctx != nullptr && module != nullptr);
|
Assert(ctx != nullptr && dump_ctx != nullptr && module != nullptr);
|
||||||
ctx->dump_ctx = dump_ctx;
|
ctx->dump_ctx = dump_ctx;
|
||||||
ctx->module = module;
|
ctx->lir_module = module;
|
||||||
}
|
}
|
||||||
void scc_lir_dump_ins(scc_lir_dump_ctx_t *ctx, const scc_lir_instr_t *ins);
|
void scc_lir_dump_ins(scc_lir_dump_ctx_t *ctx, const scc_lir_instr_t *ins);
|
||||||
void scc_lir_dump_bblock(scc_lir_dump_ctx_t *ctx, const scc_lir_bblock_t *bb);
|
void scc_lir_dump_bblock(scc_lir_dump_ctx_t *ctx, const scc_lir_bblock_t *bb);
|
||||||
|
|||||||
@@ -22,12 +22,12 @@ typedef struct scc_lir_module {
|
|||||||
/**
|
/**
|
||||||
* @brief 初始化 LIR 模块
|
* @brief 初始化 LIR 模块
|
||||||
*/
|
*/
|
||||||
void scc_lir_module_init(scc_lir_module_t *module);
|
void scc_lir_module_init(scc_lir_module_t *lir_module);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 销毁 LIR 模块,释放所有函数和符号资源
|
* @brief 销毁 LIR 模块,释放所有函数和符号资源
|
||||||
*/
|
*/
|
||||||
void scc_lir_module_drop(scc_lir_module_t *module);
|
void scc_lir_module_drop(scc_lir_module_t *lir_module);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 添加一个函数声明(外部或未定义)
|
* @brief 添加一个函数声明(外部或未定义)
|
||||||
@@ -36,7 +36,7 @@ void scc_lir_module_drop(scc_lir_module_t *module);
|
|||||||
* @param attr 属性
|
* @param attr 属性
|
||||||
* @return 符号指针
|
* @return 符号指针
|
||||||
*/
|
*/
|
||||||
scc_lir_symbol_id_t scc_lir_module_add_func_decl(scc_lir_module_t *module,
|
scc_lir_symbol_id_t scc_lir_module_add_func_decl(scc_lir_module_t *lir_module,
|
||||||
const char *name);
|
const char *name);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -50,7 +50,7 @@ scc_lir_symbol_id_t scc_lir_module_add_func_decl(scc_lir_module_t *module,
|
|||||||
* @param attr 属性
|
* @param attr 属性
|
||||||
* @return 符号指针
|
* @return 符号指针
|
||||||
*/
|
*/
|
||||||
scc_lir_symbol_id_t scc_lir_module_add_data(scc_lir_module_t *module,
|
scc_lir_symbol_id_t scc_lir_module_add_data(scc_lir_module_t *lir_module,
|
||||||
const char *name,
|
const char *name,
|
||||||
scc_cfg_symbol_kind_t kind,
|
scc_cfg_symbol_kind_t kind,
|
||||||
const u8 *init_data, usize size,
|
const u8 *init_data, usize size,
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ typedef struct {
|
|||||||
scc_lir_func_t *current_func;
|
scc_lir_func_t *current_func;
|
||||||
scc_lir_instr_vec_t instrs;
|
scc_lir_instr_vec_t instrs;
|
||||||
|
|
||||||
scc_hashtable_t bb_map; // ir_bblock_ref_t -> scc_lir_bblock_id_t
|
|
||||||
scc_hashtable_t value_to_vreg; // ir_value_ref_t -> unsigned int vreg
|
scc_hashtable_t value_to_vreg; // ir_value_ref_t -> unsigned int vreg
|
||||||
scc_hashtable_t func_decl_map; // ir_func_ref_t -> const char* (用于调用)
|
scc_hashtable_t func_decl_map; // ir_func_ref_t -> const char* (用于调用)
|
||||||
} ir2lir_ctx_t;
|
} ir2lir_ctx_t;
|
||||||
@@ -23,13 +22,11 @@ static void ir2lir_ctx_init(ir2lir_ctx_t *ctx, scc_lir_module_t *lir_module,
|
|||||||
scc_hir_module_t *hir_module) {
|
scc_hir_module_t *hir_module) {
|
||||||
ctx->hir_module = hir_module;
|
ctx->hir_module = hir_module;
|
||||||
ctx->lir_module = lir_module;
|
ctx->lir_module = lir_module;
|
||||||
scc_hashtable_usize_init(&ctx->bb_map);
|
|
||||||
scc_hashtable_usize_init(&ctx->value_to_vreg);
|
scc_hashtable_usize_init(&ctx->value_to_vreg);
|
||||||
scc_hashtable_usize_init(&ctx->func_decl_map);
|
scc_hashtable_usize_init(&ctx->func_decl_map);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ir2lir_ctx_drop(ir2lir_ctx_t *ctx) {
|
static void ir2lir_ctx_drop(ir2lir_ctx_t *ctx) {
|
||||||
scc_hashtable_drop(&ctx->bb_map);
|
|
||||||
scc_hashtable_drop(&ctx->value_to_vreg);
|
scc_hashtable_drop(&ctx->value_to_vreg);
|
||||||
scc_hashtable_drop(&ctx->func_decl_map);
|
scc_hashtable_drop(&ctx->func_decl_map);
|
||||||
}
|
}
|
||||||
@@ -107,7 +104,8 @@ static int get_vreg_for_value(ir2lir_ctx_t *ctx, scc_hir_value_ref_t val_ref) {
|
|||||||
if (found)
|
if (found)
|
||||||
return (int)(usize)found;
|
return (int)(usize)found;
|
||||||
|
|
||||||
int vreg = SCC_LIR_FUNC_META(ctx->current_func)->vregs_count++;
|
int vreg = ++(SCC_LIR_FUNC_META(ctx->current_func)->vregs_count);
|
||||||
|
Assert(vreg != 0);
|
||||||
scc_hashtable_set(&ctx->value_to_vreg, (void *)(usize)val_ref,
|
scc_hashtable_set(&ctx->value_to_vreg, (void *)(usize)val_ref,
|
||||||
(void *)(usize)vreg);
|
(void *)(usize)vreg);
|
||||||
return vreg;
|
return vreg;
|
||||||
@@ -386,25 +384,18 @@ static void translate_hir_value(ir2lir_ctx_t *ctx, scc_hir_value_t *value,
|
|||||||
case SCC_HIR_VALUE_TAG_BRANCH: {
|
case SCC_HIR_VALUE_TAG_BRANCH: {
|
||||||
scc_lir_val_t cond =
|
scc_lir_val_t cond =
|
||||||
ir_value_to_lir_operand(ctx, value->data.branch.cond);
|
ir_value_to_lir_operand(ctx, value->data.branch.cond);
|
||||||
scc_lir_bblock_id_t true_bb =
|
|
||||||
(scc_lir_bblock_id_t)(uintptr_t)scc_hashtable_get(
|
|
||||||
&ctx->bb_map,
|
|
||||||
(void *)(uintptr_t)value->data.branch.true_bblock);
|
|
||||||
scc_lir_bblock_id_t false_bb =
|
|
||||||
(scc_lir_bblock_id_t)(uintptr_t)scc_hashtable_get(
|
|
||||||
&ctx->bb_map,
|
|
||||||
(void *)(uintptr_t)value->data.branch.false_bblock);
|
|
||||||
scc_lir_instr_t instr = {
|
scc_lir_instr_t instr = {
|
||||||
.op = SCC_LIR_BR, .arg0 = cond, .metadata.br = {true_bb, false_bb}};
|
.op = SCC_LIR_BR,
|
||||||
|
.arg0 = cond,
|
||||||
|
.metadata.br = {value->data.branch.true_bblock,
|
||||||
|
value->data.branch.false_bblock}};
|
||||||
scc_lir_builder_add_instr(ctx, &instr);
|
scc_lir_builder_add_instr(ctx, &instr);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SCC_HIR_VALUE_TAG_JUMP: {
|
case SCC_HIR_VALUE_TAG_JUMP: {
|
||||||
scc_lir_bblock_id_t target =
|
|
||||||
(scc_lir_bblock_id_t)(usize)scc_hashtable_get(
|
|
||||||
&ctx->bb_map, (void *)(usize)value->data.jump.target_bblock);
|
|
||||||
scc_lir_instr_t instr = {.op = SCC_LIR_JMP,
|
scc_lir_instr_t instr = {.op = SCC_LIR_JMP,
|
||||||
.metadata.jmp_target = target};
|
.metadata.jmp_target =
|
||||||
|
value->data.jump.target_bblock};
|
||||||
scc_lir_builder_add_instr(ctx, &instr);
|
scc_lir_builder_add_instr(ctx, &instr);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -487,7 +478,6 @@ static void translate_func(ir2lir_ctx_t *ctx, scc_hir_func_t *ir_func) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 清理本次函数翻译的临时映射
|
// 清理本次函数翻译的临时映射
|
||||||
scc_hashtable_drop(&ctx->bb_map);
|
|
||||||
scc_hashtable_drop(&ctx->value_to_vreg);
|
scc_hashtable_drop(&ctx->value_to_vreg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -144,9 +144,9 @@ static void dump_operand(scc_lir_dump_ctx_t *ctx, const scc_lir_val_t *op) {
|
|||||||
case SCC_LIR_INSTR_KIND_VREG:
|
case SCC_LIR_INSTR_KIND_VREG:
|
||||||
scc_tree_dump_append_fmt(td, "%%%u", op->data.reg);
|
scc_tree_dump_append_fmt(td, "%%%u", op->data.reg);
|
||||||
break;
|
break;
|
||||||
case SCC_LIR_INSTR_KIND_PREG:
|
// case SCC_LIR_INSTR_KIND_PREG:
|
||||||
scc_tree_dump_append_fmt(td, "Phy%u", op->data.reg);
|
// scc_tree_dump_append_fmt(td, "Phy%u", op->data.reg);
|
||||||
break;
|
// break;
|
||||||
case SCC_LIR_INSTR_KIND_IMM:
|
case SCC_LIR_INSTR_KIND_IMM:
|
||||||
// TODO hack ap
|
// TODO hack ap
|
||||||
scc_tree_dump_append_fmt(td, "%lld", op->data.imm.data.digit);
|
scc_tree_dump_append_fmt(td, "%lld", op->data.imm.data.digit);
|
||||||
@@ -295,7 +295,7 @@ void scc_lir_dump_ins(scc_lir_dump_ctx_t *ctx, const scc_lir_instr_t *ins) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case SCC_LIR_JMP:
|
case SCC_LIR_JMP:
|
||||||
scc_tree_dump_append_fmt(td, "BB#%zu", ins->metadata.jmp_target);
|
scc_tree_dump_append_fmt(td, "#BB%d", ins->metadata.jmp_target);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SCC_LIR_JMP_INDIRECT:
|
case SCC_LIR_JMP_INDIRECT:
|
||||||
@@ -395,7 +395,7 @@ void scc_lir_dump_bblock(scc_lir_dump_ctx_t *ctx, const scc_lir_bblock_t *bb) {
|
|||||||
|
|
||||||
// 基本块头部
|
// 基本块头部
|
||||||
scc_tree_dump_begin_line(td);
|
scc_tree_dump_begin_line(td);
|
||||||
scc_tree_dump_node(td, "BB%zu", bb->id);
|
scc_tree_dump_node(td, "#BB%zu", bb->id);
|
||||||
if (bb->name) {
|
if (bb->name) {
|
||||||
scc_tree_dump_append_fmt(td, " (%s)", bb->name);
|
scc_tree_dump_append_fmt(td, " (%s)", bb->name);
|
||||||
}
|
}
|
||||||
@@ -430,10 +430,10 @@ void scc_lir_dump_func(scc_lir_dump_ctx_t *ctx, const scc_lir_func_t *func) {
|
|||||||
scc_tree_dump_append(td, " {");
|
scc_tree_dump_append(td, " {");
|
||||||
|
|
||||||
// 输出所有基本块
|
// 输出所有基本块
|
||||||
for (usize i = 0; i < scc_vec_size(func->bblocks); ++i) {
|
scc_vec_foreach(func->bblocks, i) {
|
||||||
scc_cfg_bblock_id_t id = scc_vec_at(func->bblocks, i);
|
scc_cfg_bblock_id_t id = scc_vec_at(func->bblocks, i);
|
||||||
const scc_cfg_bblock_t *bb =
|
const scc_cfg_bblock_t *bb =
|
||||||
scc_cfg_module_unsafe_get_bblock(&ctx->module->cfg_module, id);
|
scc_cfg_module_unsafe_get_bblock(&ctx->lir_module->cfg_module, id);
|
||||||
scc_lir_dump_bblock(ctx, bb);
|
scc_lir_dump_bblock(ctx, bb);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -442,18 +442,20 @@ void scc_lir_dump_func(scc_lir_dump_ctx_t *ctx, const scc_lir_func_t *func) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void scc_lir_dump_module(scc_lir_dump_ctx_t *ctx) {
|
void scc_lir_dump_module(scc_lir_dump_ctx_t *ctx) {
|
||||||
scc_vec_foreach(ctx->module->cfg_module.symbols, i) {
|
scc_vec_foreach(ctx->lir_module->cfg_module.symbols, i) {
|
||||||
// FIXME 0 is null
|
// FIXME 0 is null
|
||||||
if (i == 0)
|
if (i == 0)
|
||||||
continue;
|
continue;
|
||||||
scc_lir_symbol_t *sym = &scc_vec_at(ctx->module->cfg_module.symbols, i);
|
scc_lir_symbol_t *sym =
|
||||||
|
&scc_vec_at(ctx->lir_module->cfg_module.symbols, i);
|
||||||
scc_tree_dump_begin_line(ctx->dump_ctx);
|
scc_tree_dump_begin_line(ctx->dump_ctx);
|
||||||
scc_tree_dump_node(ctx->dump_ctx, "symbol");
|
scc_tree_dump_node(ctx->dump_ctx, "symbol");
|
||||||
scc_tree_dump_append_fmt(ctx->dump_ctx, " %s", sym->name);
|
scc_tree_dump_append_fmt(ctx->dump_ctx, " %s", sym->name);
|
||||||
}
|
}
|
||||||
scc_vec_foreach(ctx->module->cfg_module.funcs, i) {
|
scc_vec_foreach(ctx->lir_module->cfg_module.funcs, i) {
|
||||||
if (i == 0)
|
if (i == 0)
|
||||||
continue;
|
continue;
|
||||||
scc_lir_dump_func(ctx, &scc_vec_at(ctx->module->cfg_module.funcs, i));
|
scc_lir_dump_func(ctx,
|
||||||
|
&scc_vec_at(ctx->lir_module->cfg_module.funcs, i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +1,22 @@
|
|||||||
#include <scc_lir_module.h>
|
#include <scc_lir_module.h>
|
||||||
|
|
||||||
void scc_lir_module_init(scc_lir_module_t *module) {
|
void scc_lir_module_init(scc_lir_module_t *lir_module) {
|
||||||
// FIXME
|
// FIXME
|
||||||
// module->module
|
// lir_module->lir_module
|
||||||
|
|
||||||
scc_vec_init(module->func_metas);
|
scc_vec_init(lir_module->func_metas);
|
||||||
scc_vec_init(module->symbol_metas);
|
scc_vec_init(lir_module->symbol_metas);
|
||||||
}
|
}
|
||||||
|
|
||||||
void scc_lir_module_drop(scc_lir_module_t *module) {
|
void scc_lir_module_drop(scc_lir_module_t *lir_module) {
|
||||||
scc_vec_free(module->func_metas);
|
// FIXME memory leak
|
||||||
scc_vec_free(module->symbol_metas);
|
scc_vec_free(lir_module->func_metas);
|
||||||
|
scc_vec_free(lir_module->symbol_metas);
|
||||||
}
|
}
|
||||||
|
|
||||||
scc_lir_symbol_id_t scc_lir_module_add_func_decl(scc_lir_module_t *module,
|
scc_lir_symbol_id_t scc_lir_module_add_func_decl(scc_lir_module_t *lir_module,
|
||||||
const char *name) {
|
const char *name) {
|
||||||
if (!module || !name)
|
if (!lir_module || !name)
|
||||||
return SCC_CFG_ID_nullptr;
|
return SCC_CFG_ID_nullptr;
|
||||||
|
|
||||||
scc_lir_symbol_meta_t *meta = scc_malloc(sizeof(scc_lir_symbol_meta_t));
|
scc_lir_symbol_meta_t *meta = scc_malloc(sizeof(scc_lir_symbol_meta_t));
|
||||||
@@ -26,21 +27,21 @@ scc_lir_symbol_id_t scc_lir_module_add_func_decl(scc_lir_module_t *module,
|
|||||||
.meta = meta};
|
.meta = meta};
|
||||||
meta->func.func = nullptr;
|
meta->func.func = nullptr;
|
||||||
|
|
||||||
scc_vec_push(module->symbol_metas, meta);
|
scc_vec_push(lir_module->symbol_metas, meta);
|
||||||
scc_cfg_symbol_id_t id =
|
scc_cfg_symbol_id_t id =
|
||||||
scc_cfg_module_add_symbol(&module->cfg_module, &sym);
|
scc_cfg_module_add_symbol(&lir_module->cfg_module, &sym);
|
||||||
if (id == SCC_CFG_ID_nullptr) {
|
if (id == SCC_CFG_ID_nullptr) {
|
||||||
Panic("scc_lir: add func decl '%s' failed", name);
|
Panic("scc_lir: add func decl '%s' failed", name);
|
||||||
}
|
}
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
scc_lir_symbol_id_t scc_lir_module_add_data(scc_lir_module_t *module,
|
scc_lir_symbol_id_t scc_lir_module_add_data(scc_lir_module_t *lir_module,
|
||||||
const char *name,
|
const char *name,
|
||||||
scc_cfg_symbol_kind_t kind,
|
scc_cfg_symbol_kind_t kind,
|
||||||
const u8 *init_data, usize size,
|
const u8 *init_data, usize size,
|
||||||
u32 align) {
|
u32 align) {
|
||||||
if (!module || !name)
|
if (!lir_module || !name)
|
||||||
return SCC_CFG_ID_nullptr;
|
return SCC_CFG_ID_nullptr;
|
||||||
if (kind != SCC_CFG_SYMBOL_KIND_DATA && kind != SCC_CFG_SYMBOL_KIND_EXTERN)
|
if (kind != SCC_CFG_SYMBOL_KIND_DATA && kind != SCC_CFG_SYMBOL_KIND_EXTERN)
|
||||||
return SCC_CFG_ID_nullptr;
|
return SCC_CFG_ID_nullptr;
|
||||||
@@ -67,9 +68,9 @@ scc_lir_symbol_id_t scc_lir_module_add_data(scc_lir_module_t *module,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
scc_vec_push(module->symbol_metas, meta);
|
scc_vec_push(lir_module->symbol_metas, meta);
|
||||||
scc_cfg_symbol_id_t id =
|
scc_cfg_symbol_id_t id =
|
||||||
scc_cfg_module_add_symbol(&module->cfg_module, &sym);
|
scc_cfg_module_add_symbol(&lir_module->cfg_module, &sym);
|
||||||
if (id = SCC_CFG_ID_nullptr) {
|
if (id = SCC_CFG_ID_nullptr) {
|
||||||
/* 冲突时释放已分配的数据 */
|
/* 冲突时释放已分配的数据 */
|
||||||
scc_free(meta->data.init_data);
|
scc_free(meta->data.init_data);
|
||||||
|
|||||||
15
libs/ir/mir/cbuild.toml
Normal file
15
libs/ir/mir/cbuild.toml
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
[package]
|
||||||
|
name = "scc_mir"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = []
|
||||||
|
description = ""
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
{ name = "scc_cfg", path = "../cfg" },
|
||||||
|
{ name = "scc_lir", path = "../lir" },
|
||||||
|
{ name = "scc_utils", path = "../../../runtime/scc_utils" },
|
||||||
|
{ name = "tree_dump", path = "../../tree_dump" },
|
||||||
|
{ name = "scc_mcode", path = "../../mcode" },
|
||||||
|
]
|
||||||
|
# features = {}
|
||||||
|
# default_features = []
|
||||||
10
libs/ir/mir/include/scc_lir2mir.h
Normal file
10
libs/ir/mir/include/scc_lir2mir.h
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
#ifndef __SCC_LIR2MIR_H__
|
||||||
|
#define __SCC_LIR2MIR_H__
|
||||||
|
|
||||||
|
#include "scc_mir_module.h"
|
||||||
|
#include <scc_lir_module.h>
|
||||||
|
|
||||||
|
void scc_lir2mir(scc_mir_module_t *mir_module,
|
||||||
|
const scc_lir_module_t *lir_module);
|
||||||
|
|
||||||
|
#endif /* __SCC_LIR2MIR_H__ */
|
||||||
60
libs/ir/mir/include/scc_mir.h
Normal file
60
libs/ir/mir/include/scc_mir.h
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
// scc_mir.h (示意)
|
||||||
|
|
||||||
|
#ifndef __SCC_MIR_H__
|
||||||
|
#define __SCC_MIR_H__
|
||||||
|
|
||||||
|
#include <scc_lir.h> // 复用 VREG 概念和一些基础类型
|
||||||
|
// #include "scc_target_desc.h" // 目标架构描述(寄存器文件、指令编码)
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
SCC_MIR_OP_NONE,
|
||||||
|
SCC_MIR_OP_MEM, // 内存访问
|
||||||
|
SCC_MIR_OP_VREG, // 虚拟寄存器
|
||||||
|
SCC_MIR_OP_PREG, // 物理寄存器
|
||||||
|
SCC_MIR_OP_IMM, // 立即数
|
||||||
|
SCC_MIR_OP_SYMBOL, // 符号地址(用于重定位)
|
||||||
|
SCC_MIR_OP_BLOCK // 基本块引用(label)
|
||||||
|
} scc_mir_op_kind_t;
|
||||||
|
|
||||||
|
typedef struct scc_mir_operand {
|
||||||
|
scc_mir_op_kind_t kind;
|
||||||
|
union {
|
||||||
|
int vreg; // 虚拟寄存器索引
|
||||||
|
int preg; // 物理寄存器
|
||||||
|
i64 imm; // 立即数
|
||||||
|
const char *symbol; // 符号名
|
||||||
|
int stack_slot; // 栈槽 ID (由 FrameLayout 分配)
|
||||||
|
scc_lir_bblock_id_t block_id; // 目标基本块
|
||||||
|
};
|
||||||
|
} scc_mir_operand_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
SCC_MIR_PSUEDO_ALLOCA = -1,
|
||||||
|
} scc_mir_psuedo_op_t;
|
||||||
|
|
||||||
|
typedef struct scc_mir_instr {
|
||||||
|
int opcode; // 目标特定的指令编码 (如 X86::ADD32rr)
|
||||||
|
int num_operands; // 实际使用的操作数个数
|
||||||
|
scc_mir_operand_t
|
||||||
|
operands[8]; // 固定小数组,RISC 风格指令通常不超过 4 操作数
|
||||||
|
scc_pos_t src_loc; // 调试信息 (继承自 LIR)
|
||||||
|
} scc_mir_instr_t;
|
||||||
|
typedef SCC_VEC(scc_mir_instr_t) scc_mir_instr_vec_t;
|
||||||
|
|
||||||
|
typedef scc_cfg_bblock_t scc_mir_bblock_t;
|
||||||
|
typedef struct scc_mir_bblock_meta {
|
||||||
|
} scc_mir_bblock_meta_t;
|
||||||
|
#define SCC_MIR_BBLOCK_VALUES(bblock) \
|
||||||
|
((scc_mir_instr_vec_t *)&((bblock)->values))
|
||||||
|
|
||||||
|
typedef scc_cfg_func_t scc_mir_func_t;
|
||||||
|
typedef struct scc_mir_func_meta {
|
||||||
|
// 栈帧信息 (由 FrameLayout Pass 填充)
|
||||||
|
int frame_size;
|
||||||
|
int stack_alignment;
|
||||||
|
// 寄存器分配信息
|
||||||
|
SCC_VEC(int) vreg_alloc; // vreg -> phys reg 映射
|
||||||
|
} scc_mir_func_meta_t;
|
||||||
|
#define SCC_MIR_FUNC_META(func) ((scc_mir_func_meta_t *)(func)->meta)
|
||||||
|
|
||||||
|
#endif /* __SCC_MIR_H__ */
|
||||||
22
libs/ir/mir/include/scc_mir_dump.h
Normal file
22
libs/ir/mir/include/scc_mir_dump.h
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
#ifndef __SCC_MIR_DUMP_H__
|
||||||
|
#define __SCC_MIR_DUMP_H__
|
||||||
|
|
||||||
|
#include "scc_mir.h"
|
||||||
|
#include "scc_mir_module.h"
|
||||||
|
#include <scc_tree_dump.h>
|
||||||
|
typedef struct {
|
||||||
|
scc_tree_dump_t *dump_ctx;
|
||||||
|
scc_mir_module_t *mir_module;
|
||||||
|
} scc_mir_dump_ctx_t;
|
||||||
|
|
||||||
|
static inline void scc_mir_dump_init(scc_mir_dump_ctx_t *ctx,
|
||||||
|
scc_tree_dump_t *dump_ctx,
|
||||||
|
scc_mir_module_t *module) {
|
||||||
|
Assert(ctx != nullptr && dump_ctx != nullptr && module != nullptr);
|
||||||
|
ctx->dump_ctx = dump_ctx;
|
||||||
|
ctx->mir_module = module;
|
||||||
|
}
|
||||||
|
|
||||||
|
void scc_mir_dump_module(scc_mir_dump_ctx_t *ctx);
|
||||||
|
|
||||||
|
#endif /* __SCC_MIR_DUMP_H__*/
|
||||||
18
libs/ir/mir/include/scc_mir_module.h
Normal file
18
libs/ir/mir/include/scc_mir_module.h
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
#ifndef __SCC_MIR_MODULE_H__
|
||||||
|
#define __SCC_MIR_MODULE_H__
|
||||||
|
|
||||||
|
#include "scc_mir.h"
|
||||||
|
#include <scc_lir_module.h>
|
||||||
|
|
||||||
|
typedef scc_lir_symbol_meta_vec_t scc_mir_symbol_meta_vec_t;
|
||||||
|
typedef SCC_VEC(scc_mir_func_meta_t *) scc_mir_func_meta_vec_t;
|
||||||
|
typedef struct scc_mir_module {
|
||||||
|
scc_cfg_module_t cfg_module;
|
||||||
|
scc_mir_func_meta_vec_t func_metas;
|
||||||
|
scc_mir_symbol_meta_vec_t symbol_metas;
|
||||||
|
} scc_mir_module_t;
|
||||||
|
|
||||||
|
void scc_mir_module_init(scc_mir_module_t *mir_module);
|
||||||
|
void scc_mir_module_drop(scc_mir_module_t *mir_module);
|
||||||
|
|
||||||
|
#endif /* __SCC_MIR_MODULE_H__ */
|
||||||
131
libs/ir/mir/include/scc_mir_pass.h
Normal file
131
libs/ir/mir/include/scc_mir_pass.h
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
#ifndef __SCC_MIR_PASS_H__
|
||||||
|
#define __SCC_MIR_PASS_H__
|
||||||
|
|
||||||
|
#include "scc_mir.h"
|
||||||
|
|
||||||
|
/** Pass 的唯一标识符 (枚举) */
|
||||||
|
typedef enum {
|
||||||
|
SCC_MIR_PASS_ABI_LOWERING, // ABI 物理化 (核心)
|
||||||
|
SCC_MIR_PASS_REG_ALLOC, // 寄存器分配 (核心)
|
||||||
|
SCC_MIR_PASS_FRAME_LAYOUT, // 栈帧布局 (核心)
|
||||||
|
SCC_MIR_PASS_PROLOGUE_EPILOGUE, // 序言/尾声插入 (核心)
|
||||||
|
SCC_MIR_PASS_DEAD_CODE_ELIM, // 死代码消除 (优化)
|
||||||
|
SCC_MIR_PASS_CONST_PROP, // 常量传播 (优化)
|
||||||
|
SCC_MIR_PASS_PEEPHOLE, // 窥孔优化 (优化)
|
||||||
|
SCC_MIR_PASS_CFG_SIMPLIFY, // CFG 简化 (优化)
|
||||||
|
SCC_MIR_PASS_COPY_PROP, // 复制传播 (优化)
|
||||||
|
SCC_MIR_PASS_COUNT
|
||||||
|
} scc_mir_pass_id_t;
|
||||||
|
|
||||||
|
/** Pass 运行阶段 (用于自动排序) */
|
||||||
|
typedef enum {
|
||||||
|
SCC_MIR_STAGE_ANY, // 无特殊阶段要求
|
||||||
|
SCC_MIR_STAGE_PRE_REGALLOC, // 寄存器分配前
|
||||||
|
SCC_MIR_STAGE_REGALLOC, // 寄存器分配本身
|
||||||
|
SCC_MIR_STAGE_POST_REGALLOC // 寄存器分配后
|
||||||
|
} scc_mir_pass_stage_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Pass 执行函数原型
|
||||||
|
* @param func 输入的 MIR 函数 (Pass 可修改或替换)
|
||||||
|
* @param ctx 可选的上下文指针 (如目标机器信息、调试标志)
|
||||||
|
* @return 执行后的 MIR 函数指针 (若未修改可返回原指针,若需替换可返回新指针)
|
||||||
|
* @warning Pass 应负责释放不再使用的旧函数资源
|
||||||
|
*/
|
||||||
|
typedef scc_mir_func_t *(*scc_mir_pass_fn_t)(scc_mir_func_t *func, void *ctx);
|
||||||
|
|
||||||
|
typedef struct scc_lir_pass_desc {
|
||||||
|
scc_mir_pass_id_t id; // 唯一标识
|
||||||
|
const char *name; // 可读名称
|
||||||
|
scc_mir_pass_stage_t stage; // 所属阶段
|
||||||
|
scc_mir_pass_id_t *deps; // 依赖的 Pass ID 数组 (可为 NULL)
|
||||||
|
usize num_deps; // 依赖数量
|
||||||
|
scc_mir_pass_fn_t run; // 执行函数
|
||||||
|
cbool required; // 是否为核心必需 Pass
|
||||||
|
} scc_mir_pass_desc_t;
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------
|
||||||
|
* Pass 管理器
|
||||||
|
* -------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
typedef struct scc_lir_pass_manager {
|
||||||
|
SCC_VEC(scc_mir_pass_desc_t) passes; // 所有已注册 Pass
|
||||||
|
SCC_VEC(scc_mir_pass_id_t) pipeline; // 当前流水线顺序
|
||||||
|
void *ctx; // 传递给每个 Pass 的上下文
|
||||||
|
} scc_mir_pass_manager_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 初始化 Pass 管理器
|
||||||
|
* @param pm 管理器指针
|
||||||
|
* @param ctx 全局上下文 (如 scc_target_t*)
|
||||||
|
*/
|
||||||
|
void scc_mir_pass_manager_init(scc_mir_pass_manager_t *pm, void *ctx);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 销毁 Pass 管理器,释放资源
|
||||||
|
*/
|
||||||
|
void scc_mir_pass_manager_drop(scc_mir_pass_manager_t *pm);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 注册一个 Pass (通常在编译器初始化时调用)
|
||||||
|
* @param pm 管理器
|
||||||
|
* @param desc Pass 描述符
|
||||||
|
*/
|
||||||
|
void scc_mir_pass_register(scc_mir_pass_manager_t *pm,
|
||||||
|
const scc_mir_pass_desc_t *desc);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 构建默认的核心流水线 (仅包含 required=true 的 Pass)
|
||||||
|
* @param pm 管理器
|
||||||
|
*
|
||||||
|
* 自动按阶段排序并解析依赖。
|
||||||
|
*/
|
||||||
|
void scc_mir_pass_build_core_pipeline(scc_mir_pass_manager_t *pm);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 向流水线追加一个可选 Pass
|
||||||
|
* @param pm 管理器
|
||||||
|
* @param id 要添加的 Pass ID
|
||||||
|
* @return 成功返回 true,若依赖不满足或 ID 无效返回 false
|
||||||
|
*/
|
||||||
|
cbool scc_mir_pass_add_to_pipeline(scc_mir_pass_manager_t *pm,
|
||||||
|
scc_mir_pass_id_t id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 对指定函数运行当前流水线中的所有 Pass
|
||||||
|
* @param pm 管理器
|
||||||
|
* @param func 要处理的 LIR 函数
|
||||||
|
* @return 最终处理后的函数指针
|
||||||
|
*/
|
||||||
|
scc_lir_func_t *scc_mir_pass_run_pipeline(scc_mir_pass_manager_t *pm,
|
||||||
|
scc_lir_func_t *func);
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------
|
||||||
|
* 便捷宏:声明并注册一个 Pass
|
||||||
|
* -------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 在模块内部声明并注册一个 Pass
|
||||||
|
* @param pm 管理器指针
|
||||||
|
* @param id Pass ID 枚举值
|
||||||
|
* @param name_str Pass 名称字符串
|
||||||
|
* @param stage 运行阶段
|
||||||
|
* @param deps_arr 依赖数组 (可为 NULL)
|
||||||
|
* @param num_deps 依赖数量
|
||||||
|
* @param fn 执行函数
|
||||||
|
* @param req 是否必需
|
||||||
|
*/
|
||||||
|
#define SCC_MIR_REGISTER_PASS(pm, id, name_str, stage, deps_arr, num_deps, fn, \
|
||||||
|
req) \
|
||||||
|
do { \
|
||||||
|
scc_mir_pass_desc_t desc = {.id = (id), \
|
||||||
|
.name = (name_str), \
|
||||||
|
.stage = (stage), \
|
||||||
|
.deps = (deps_arr), \
|
||||||
|
.num_deps = (num_deps), \
|
||||||
|
.run = (fn), \
|
||||||
|
.required = (req)}; \
|
||||||
|
scc_mir_pass_register((pm), &desc); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#endif /* __SCC_LIR_PASS_H__ */
|
||||||
393
libs/ir/mir/src/mir_x86.c
Normal file
393
libs/ir/mir/src/mir_x86.c
Normal file
@@ -0,0 +1,393 @@
|
|||||||
|
#include <scc_lir_module.h>
|
||||||
|
#include <scc_mir_module.h>
|
||||||
|
#include <scc_tree_dump.h>
|
||||||
|
|
||||||
|
#include <x86/scc_x86_iform.c>
|
||||||
|
#include <x86/scc_x86_reg.c>
|
||||||
|
|
||||||
|
static const char *preg_name(int preg_id) {
|
||||||
|
if (preg_id < 1 || preg_id >= SCC_X86_REG_COUNT)
|
||||||
|
return "???";
|
||||||
|
return scc_x86_reg_table[preg_id].name;
|
||||||
|
}
|
||||||
|
|
||||||
|
void scc_x86_instr_dump(scc_tree_dump_t *td, const scc_mir_instr_t *instr) {
|
||||||
|
scc_x86_iform_t iform = instr->opcode;
|
||||||
|
const scc_x86_iform_info_t *info = &scc_x86_iform_table[iform];
|
||||||
|
scc_tree_dump_append_fmt(td, " %s", info->iform_name);
|
||||||
|
// Assert(instr->num_operands == info->num_ops);
|
||||||
|
for (int i = 0; i < instr->num_operands; i += 1) {
|
||||||
|
if (i == 0)
|
||||||
|
scc_tree_dump_append(td, " ");
|
||||||
|
else
|
||||||
|
scc_tree_dump_append_fmt(td, ", ");
|
||||||
|
scc_mir_operand_t *op = &instr->operands[i];
|
||||||
|
switch (op->kind) {
|
||||||
|
case SCC_MIR_OP_VREG:
|
||||||
|
scc_tree_dump_append_fmt(td, "$%d", op->vreg);
|
||||||
|
break;
|
||||||
|
case SCC_MIR_OP_PREG:
|
||||||
|
scc_tree_dump_append_fmt(td, "$%s", preg_name(op->preg));
|
||||||
|
break;
|
||||||
|
case SCC_MIR_OP_IMM:
|
||||||
|
scc_tree_dump_append_fmt(td, "%ld", op->imm);
|
||||||
|
break;
|
||||||
|
case SCC_MIR_OP_BLOCK:
|
||||||
|
scc_tree_dump_append_fmt(td, "#BB%d", op->block_id);
|
||||||
|
break;
|
||||||
|
case SCC_MIR_OP_SYMBOL:
|
||||||
|
scc_tree_dump_append_fmt(td, "@%s", op->symbol);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct x86_isel {
|
||||||
|
scc_mir_instr_vec_t instrs;
|
||||||
|
} x86_isel_t;
|
||||||
|
|
||||||
|
static void add_instr(x86_isel_t *isel, const scc_mir_instr_t *instr) {
|
||||||
|
scc_vec_push(isel->instrs, *instr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void add_instr_0(x86_isel_t *isel, scc_x86_iform_t opcode) {
|
||||||
|
scc_mir_instr_t out = {.opcode = opcode, .num_operands = 0};
|
||||||
|
add_instr(isel, &out);
|
||||||
|
}
|
||||||
|
static inline void add_instr_1(x86_isel_t *isel, scc_x86_iform_t opcode,
|
||||||
|
scc_mir_operand_t op1) {
|
||||||
|
scc_mir_instr_t out = {.opcode = opcode, .num_operands = 1};
|
||||||
|
out.operands[0] = op1;
|
||||||
|
add_instr(isel, &out);
|
||||||
|
}
|
||||||
|
static inline void add_instr_2(x86_isel_t *isel, scc_x86_iform_t opcode,
|
||||||
|
scc_mir_operand_t op1, scc_mir_operand_t op2) {
|
||||||
|
scc_mir_instr_t out = {.opcode = opcode, .num_operands = 2};
|
||||||
|
out.operands[0] = op1;
|
||||||
|
out.operands[1] = op2;
|
||||||
|
add_instr(isel, &out);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将 LIR 值转换为 MIR 操作数
|
||||||
|
static scc_mir_operand_t lir_val_to_mir_op(const scc_lir_val_t *val) {
|
||||||
|
scc_mir_operand_t op = {0};
|
||||||
|
switch (val->kind) {
|
||||||
|
case SCC_LIR_INSTR_KIND_NONE:
|
||||||
|
op.kind = SCC_MIR_OP_NONE;
|
||||||
|
break;
|
||||||
|
case SCC_LIR_INSTR_KIND_VREG:
|
||||||
|
op.kind = SCC_MIR_OP_VREG;
|
||||||
|
op.vreg = val->data.reg;
|
||||||
|
break;
|
||||||
|
case SCC_LIR_INSTR_KIND_IMM:
|
||||||
|
op.kind = SCC_MIR_OP_IMM;
|
||||||
|
// FIXME hack ap
|
||||||
|
op.imm = val->data.imm.data.digit;
|
||||||
|
break;
|
||||||
|
case SCC_LIR_INSTR_KIND_FIMM:
|
||||||
|
// 浮点立即数暂时作为普通立即数处理(后端需特殊处理)
|
||||||
|
op.kind = SCC_MIR_OP_IMM;
|
||||||
|
op.imm = *(i64 *)&val->data.fimm;
|
||||||
|
break;
|
||||||
|
case SCC_LIR_INSTR_KIND_SYMBOL:
|
||||||
|
op.kind = SCC_MIR_OP_SYMBOL;
|
||||||
|
op.symbol = val->data.symbol;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
return op;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sel_mir(x86_isel_t *isel, const scc_lir_instr_t *instr) {
|
||||||
|
switch (instr->op) {
|
||||||
|
case SCC_LIR_MOV: {
|
||||||
|
add_instr_2(isel, SCC_X86_IFORM_MOV_GPRV_GPRV_89,
|
||||||
|
lir_val_to_mir_op(&instr->to),
|
||||||
|
lir_val_to_mir_op(&instr->arg0));
|
||||||
|
} break;
|
||||||
|
case SCC_LIR_LOAD: {
|
||||||
|
add_instr_2(isel, SCC_X86_IFORM_MOV_GPRV_MEMV,
|
||||||
|
lir_val_to_mir_op(&instr->to),
|
||||||
|
lir_val_to_mir_op(&instr->arg0));
|
||||||
|
} break;
|
||||||
|
case SCC_LIR_LOAD_ADDR: {
|
||||||
|
add_instr_2(isel, SCC_X86_IFORM_LEA_GPRV_AGEN,
|
||||||
|
lir_val_to_mir_op(&instr->to),
|
||||||
|
lir_val_to_mir_op(&instr->arg0));
|
||||||
|
} break;
|
||||||
|
case SCC_LIR_STORE:
|
||||||
|
case SCC_LIR_STORE_ADDR: {
|
||||||
|
add_instr_2(isel, SCC_X86_IFORM_MOV_MEMV_GPRV,
|
||||||
|
lir_val_to_mir_op(&instr->arg1),
|
||||||
|
lir_val_to_mir_op(&instr->arg0));
|
||||||
|
} break;
|
||||||
|
// case SCC_LIR_LEA:
|
||||||
|
// case SCC_LIR_NEG:
|
||||||
|
// case SCC_LIR_NOT:
|
||||||
|
// case SCC_LIR_FNEG:
|
||||||
|
// case SCC_LIR_FCVT:
|
||||||
|
case SCC_LIR_ALLOCA: {
|
||||||
|
add_instr_2(isel, SCC_MIR_PSUEDO_ALLOCA, lir_val_to_mir_op(&instr->to),
|
||||||
|
(scc_mir_operand_t){
|
||||||
|
.kind = SCC_MIR_OP_IMM,
|
||||||
|
.imm = instr->size,
|
||||||
|
});
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case SCC_LIR_ADD:
|
||||||
|
case SCC_LIR_SUB:
|
||||||
|
case SCC_LIR_MUL:
|
||||||
|
case SCC_LIR_AND:
|
||||||
|
case SCC_LIR_OR:
|
||||||
|
case SCC_LIR_XOR:
|
||||||
|
case SCC_LIR_SHL:
|
||||||
|
case SCC_LIR_SHR:
|
||||||
|
case SCC_LIR_SAR: {
|
||||||
|
int base;
|
||||||
|
bool is_commutative =
|
||||||
|
(instr->op != SCC_LIR_SUB && instr->op != SCC_LIR_SHL &&
|
||||||
|
instr->op != SCC_LIR_SHR && instr->op != SCC_LIR_SAR);
|
||||||
|
switch (instr->op) {
|
||||||
|
case SCC_LIR_ADD:
|
||||||
|
base = SCC_X86_IFORM_ADD_GPRV_GPRV_01;
|
||||||
|
break;
|
||||||
|
case SCC_LIR_SUB:
|
||||||
|
base = SCC_X86_IFORM_SUB_GPRV_GPRV_29;
|
||||||
|
break;
|
||||||
|
case SCC_LIR_AND:
|
||||||
|
base = SCC_X86_IFORM_AND_GPRV_GPRV_21;
|
||||||
|
break;
|
||||||
|
case SCC_LIR_OR:
|
||||||
|
base = SCC_X86_IFORM_OR_GPRV_GPRV_09;
|
||||||
|
break;
|
||||||
|
case SCC_LIR_XOR:
|
||||||
|
base = SCC_X86_IFORM_XOR_GPRV_GPRV_31;
|
||||||
|
break;
|
||||||
|
case SCC_LIR_MUL:
|
||||||
|
base = SCC_X86_IFORM_IMUL_GPRV_GPRV;
|
||||||
|
break;
|
||||||
|
case SCC_LIR_SHL:
|
||||||
|
base = SCC_X86_IFORM_SHR_GPRV_IMMB;
|
||||||
|
break; // 简化,实际应处理 CL 移位
|
||||||
|
case SCC_LIR_SHR:
|
||||||
|
base = SCC_X86_IFORM_SHR_GPRV_IMMB;
|
||||||
|
break;
|
||||||
|
case SCC_LIR_SAR:
|
||||||
|
base = SCC_X86_IFORM_SAR_GPRV_IMMB;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (instr->arg0.kind == SCC_LIR_INSTR_KIND_IMM) {
|
||||||
|
add_instr_2(isel, SCC_X86_IFORM_MOV_GPRV_IMMV,
|
||||||
|
lir_val_to_mir_op(&instr->to),
|
||||||
|
lir_val_to_mir_op(&instr->arg0));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 三地址转两地址:若 to != arg0,需先 mov to, arg0
|
||||||
|
if (instr->to.kind == SCC_LIR_INSTR_KIND_VREG &&
|
||||||
|
instr->arg0.kind == SCC_LIR_INSTR_KIND_VREG &&
|
||||||
|
instr->to.data.reg != instr->arg0.data.reg) {
|
||||||
|
add_instr_2(isel, SCC_X86_IFORM_MOV_GPRV_GPRV_89,
|
||||||
|
lir_val_to_mir_op(&instr->to),
|
||||||
|
lir_val_to_mir_op(&instr->arg0));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果是立即数,使用 RI 变体
|
||||||
|
if (instr->arg1.kind == SCC_LIR_INSTR_KIND_IMM) {
|
||||||
|
// 需要根据立即数大小选择 RI8/RI32
|
||||||
|
add_instr_2(isel, base, lir_val_to_mir_op(&instr->to),
|
||||||
|
lir_val_to_mir_op(&instr->arg1));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成两地址运算指令
|
||||||
|
add_instr_2(isel, base, lir_val_to_mir_op(&instr->to),
|
||||||
|
lir_val_to_mir_op(&instr->arg1));
|
||||||
|
} break;
|
||||||
|
// case SCC_LIR_DIV_S:
|
||||||
|
// case SCC_LIR_DIV_U:
|
||||||
|
// case SCC_LIR_REM_S:
|
||||||
|
// case SCC_LIR_REM_U:
|
||||||
|
// case SCC_LIR_FADD:
|
||||||
|
// case SCC_LIR_FSUB:
|
||||||
|
// case SCC_LIR_FMUL:
|
||||||
|
// case SCC_LIR_FDIV:
|
||||||
|
// dump_operand(ctx, &instr->to);
|
||||||
|
// scc_tree_dump_append(td, ", ");
|
||||||
|
// dump_operand(ctx, &instr->arg0);
|
||||||
|
// scc_tree_dump_append(td, ", ");
|
||||||
|
// dump_operand(ctx, &instr->arg1);
|
||||||
|
// break;
|
||||||
|
|
||||||
|
// case SCC_LIR_CMP:
|
||||||
|
// dump_operand(ctx, &instr->to);
|
||||||
|
// scc_tree_dump_append_fmt(td, ", %s, ",
|
||||||
|
// cond_to_string(instr->metadata.cond));
|
||||||
|
// dump_operand(ctx, &instr->arg0);
|
||||||
|
// scc_tree_dump_append(td, ", ");
|
||||||
|
// dump_operand(ctx, &instr->arg1);
|
||||||
|
// break;
|
||||||
|
|
||||||
|
// case SCC_LIR_BR:
|
||||||
|
// dump_operand(ctx, &instr->arg0);
|
||||||
|
// scc_tree_dump_append_fmt(td, ", BB#%zu, BB#%zu",
|
||||||
|
// instr->metadata.br.true_target,
|
||||||
|
// instr->metadata.br.false_target);
|
||||||
|
// break;
|
||||||
|
|
||||||
|
case SCC_LIR_JMP: {
|
||||||
|
add_instr_1(isel, SCC_X86_IFORM_JMP_GPRV,
|
||||||
|
(scc_mir_operand_t){
|
||||||
|
.kind = SCC_MIR_OP_BLOCK,
|
||||||
|
.block_id = instr->metadata.jmp_target,
|
||||||
|
});
|
||||||
|
} break;
|
||||||
|
|
||||||
|
// case SCC_LIR_JMP_INDIRECT:
|
||||||
|
// dump_operand(ctx, &instr->arg0);
|
||||||
|
// break;
|
||||||
|
|
||||||
|
case SCC_LIR_CALL: {
|
||||||
|
const struct scc_lir_call *c = &instr->metadata.call;
|
||||||
|
Assert(c->callee != nullptr);
|
||||||
|
add_instr_1(isel, SCC_X86_IFORM_CALL_NEAR_GPRV,
|
||||||
|
(scc_mir_operand_t){
|
||||||
|
.kind = SCC_MIR_OP_SYMBOL,
|
||||||
|
.symbol = c->callee,
|
||||||
|
});
|
||||||
|
} break;
|
||||||
|
// case SCC_LIR_CALL: {
|
||||||
|
// const struct scc_lir_call *c = &instr->metadata.call;
|
||||||
|
// if (c->ret_vreg.kind != SCC_LIR_INSTR_KIND_NONE) {
|
||||||
|
// dump_operand(ctx, &c->ret_vreg);
|
||||||
|
// scc_tree_dump_append(td, " = ");
|
||||||
|
// }
|
||||||
|
// scc_tree_dump_append_fmt(td, "call @%s(",
|
||||||
|
// c->callee ? c->callee : "<null>");
|
||||||
|
// for (u8 i = 0; i < c->arg_count; i++) {
|
||||||
|
// if (i > 0)
|
||||||
|
// scc_tree_dump_append(td, ", ");
|
||||||
|
// dump_operand(ctx, &c->args[i]);
|
||||||
|
// }
|
||||||
|
// scc_tree_dump_append_fmt(td, ") clobber=0x%llx",
|
||||||
|
// (unsigned long long)c->clobber_mask);
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// case SCC_LIR_CALL_INDIRECT: {
|
||||||
|
// const struct scc_lir_call_indirect *c =
|
||||||
|
// &instr->metadata.call_indirect; if (c->ret_vreg.kind !=
|
||||||
|
// SCC_LIR_INSTR_KIND_NONE) {
|
||||||
|
// dump_operand(ctx, &c->ret_vreg);
|
||||||
|
// scc_tree_dump_append(td, " = ");
|
||||||
|
// }
|
||||||
|
// scc_tree_dump_append(td, "call ");
|
||||||
|
// dump_operand(ctx, &c->target);
|
||||||
|
// scc_tree_dump_append(td, "(");
|
||||||
|
// for (u8 i = 0; i < c->arg_count; i++) {
|
||||||
|
// if (i > 0)
|
||||||
|
// scc_tree_dump_append(td, ", ");
|
||||||
|
// dump_operand(ctx, &c->args[i]);
|
||||||
|
// }
|
||||||
|
// scc_tree_dump_append_fmt(td, ") clobber=0x%llx",
|
||||||
|
// (unsigned long long)c->clobber_mask);
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
|
||||||
|
case SCC_LIR_RET: {
|
||||||
|
if (instr->metadata.ret_val.kind != SCC_LIR_INSTR_KIND_NONE) {
|
||||||
|
// FIXME target ABI
|
||||||
|
add_instr_2(isel, SCC_X86_IFORM_MOV_GPRV_GPRV_89,
|
||||||
|
(scc_mir_operand_t){
|
||||||
|
.kind = SCC_MIR_OP_PREG,
|
||||||
|
.preg = SCC_X86_REG_RAX,
|
||||||
|
},
|
||||||
|
lir_val_to_mir_op(&instr->metadata.ret_val));
|
||||||
|
}
|
||||||
|
|
||||||
|
add_instr_0(isel, SCC_X86_IFORM_RET_FAR);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
// case SCC_LIR_PARALLEL_COPY: {
|
||||||
|
// const struct scc_lir_parallel_copy *pc =
|
||||||
|
// &instr->metadata.parallel_copy; scc_tree_dump_append(td, "[");
|
||||||
|
// for (u8 i = 0; i < pc->num_copies; i++) {
|
||||||
|
// if (i > 0)
|
||||||
|
// scc_tree_dump_append(td, ", ");
|
||||||
|
// dump_operand(ctx, &pc->dests[i]);
|
||||||
|
// scc_tree_dump_append(td, " <- ");
|
||||||
|
// dump_operand(ctx, &pc->srcs[i]);
|
||||||
|
// }
|
||||||
|
// scc_tree_dump_append(td, "]");
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// case SCC_LIR_VA_START:
|
||||||
|
// dump_operand(ctx, &instr->metadata.va_start.ap);
|
||||||
|
// scc_tree_dump_append(td, ", ");
|
||||||
|
// dump_operand(ctx, &instr->metadata.va_start.last);
|
||||||
|
// break;
|
||||||
|
|
||||||
|
// case SCC_LIR_VA_ARG:
|
||||||
|
// dump_operand(ctx, &instr->metadata.va_arg.to);
|
||||||
|
// scc_tree_dump_append(td, " = va_arg ");
|
||||||
|
// dump_operand(ctx, &instr->metadata.va_arg.ap);
|
||||||
|
// scc_tree_dump_append_fmt(td, ", size=%u, align=%u, float=%d",
|
||||||
|
// instr->metadata.va_arg.type_size,
|
||||||
|
// instr->metadata.va_arg.type_align,
|
||||||
|
// instr->metadata.va_arg.is_float);
|
||||||
|
// break;
|
||||||
|
|
||||||
|
// case SCC_LIR_VA_END:
|
||||||
|
// dump_operand(ctx, &instr->metadata.va_end.ap);
|
||||||
|
// break;
|
||||||
|
|
||||||
|
// case SCC_LIR_VA_COPY:
|
||||||
|
// dump_operand(ctx, &instr->metadata.va_copy.dest);
|
||||||
|
// scc_tree_dump_append(td, ", ");
|
||||||
|
// dump_operand(ctx, &instr->metadata.va_copy.src);
|
||||||
|
// break;
|
||||||
|
|
||||||
|
// case SCC_LIR_NOP:
|
||||||
|
// break;
|
||||||
|
//
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
UNREACHABLE();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static void sel_func(scc_lir_module_t *lir_module, const scc_lir_func_t *func) {
|
||||||
|
x86_isel_t isel;
|
||||||
|
|
||||||
|
scc_vec_foreach(func->bblocks, i) {
|
||||||
|
scc_vec_init(isel.instrs);
|
||||||
|
|
||||||
|
scc_cfg_bblock_id_t id = scc_vec_at(func->bblocks, i);
|
||||||
|
scc_cfg_bblock_t *bb =
|
||||||
|
scc_cfg_module_unsafe_get_bblock(&lir_module->cfg_module, id);
|
||||||
|
scc_lir_instr_vec_t *instrs = SCC_LIR_BBLOCK_VALUES(bb);
|
||||||
|
scc_vec_foreach(*instrs, i) {
|
||||||
|
const scc_lir_instr_t *ins = &scc_vec_at(*instrs, i);
|
||||||
|
sel_mir(&isel, ins);
|
||||||
|
}
|
||||||
|
|
||||||
|
bb->values = *(scc_cfg_value_vec_t *)&isel.instrs;
|
||||||
|
scc_vec_init(isel.instrs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void scc_isel_x86_64(scc_mir_module_t *mir_module,
|
||||||
|
scc_lir_module_t *lir_module) {
|
||||||
|
scc_vec_foreach(lir_module->cfg_module.funcs, i) {
|
||||||
|
if (i == 0)
|
||||||
|
continue;
|
||||||
|
scc_lir_func_t *func = &scc_vec_at(lir_module->cfg_module.funcs, i);
|
||||||
|
sel_func(lir_module, func);
|
||||||
|
}
|
||||||
|
}
|
||||||
12
libs/ir/mir/src/scc_lir2mir.c
Normal file
12
libs/ir/mir/src/scc_lir2mir.c
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
#include <scc_lir2mir.h>
|
||||||
|
|
||||||
|
extern void scc_isel_x86_64(scc_mir_module_t *mir_module,
|
||||||
|
scc_lir_module_t *lir_module);
|
||||||
|
|
||||||
|
void scc_lir2mir(scc_mir_module_t *mir_module,
|
||||||
|
const scc_lir_module_t *lir_module) {
|
||||||
|
// FIXME hack cfg module
|
||||||
|
mir_module->cfg_module = lir_module->cfg_module;
|
||||||
|
// TODO using target ABI choice it
|
||||||
|
scc_isel_x86_64(mir_module, lir_module);
|
||||||
|
}
|
||||||
0
libs/ir/mir/src/scc_mir.c
Normal file
0
libs/ir/mir/src/scc_mir.c
Normal file
80
libs/ir/mir/src/scc_mir_dump.c
Normal file
80
libs/ir/mir/src/scc_mir_dump.c
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
#include <scc_mir_dump.h>
|
||||||
|
|
||||||
|
void scc_x86_instr_dump(scc_tree_dump_t *dump, const scc_mir_instr_t *instr);
|
||||||
|
|
||||||
|
void scc_mir_dump_instr(scc_mir_dump_ctx_t *ctx, const scc_mir_instr_t *ins) {
|
||||||
|
scc_tree_dump_t *td = ctx->dump_ctx;
|
||||||
|
scc_tree_dump_begin_line(td);
|
||||||
|
if (ins->opcode >= 0) {
|
||||||
|
scc_x86_instr_dump(td, ins);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (ins->opcode) {
|
||||||
|
case SCC_MIR_PSUEDO_ALLOCA:
|
||||||
|
scc_tree_dump_node(td, " @alloca");
|
||||||
|
scc_tree_dump_append_fmt(td, "(%d)", ins->operands[1].imm);
|
||||||
|
Assert(ins->operands[0].kind == SCC_MIR_OP_VREG);
|
||||||
|
scc_tree_dump_append_fmt(td, " %%%d", ins->operands[0].vreg);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void scc_mir_dump_bblock(scc_mir_dump_ctx_t *ctx, const scc_mir_bblock_t *bb) {
|
||||||
|
Assert(ctx != nullptr && bb != nullptr);
|
||||||
|
scc_tree_dump_t *td = ctx->dump_ctx;
|
||||||
|
|
||||||
|
// 基本块头部
|
||||||
|
scc_tree_dump_begin_line(td);
|
||||||
|
scc_tree_dump_node(td, "#BB%zu", bb->id);
|
||||||
|
if (bb->name) {
|
||||||
|
scc_tree_dump_append_fmt(td, " (%s)", bb->name);
|
||||||
|
}
|
||||||
|
scc_tree_dump_append(td, ":");
|
||||||
|
|
||||||
|
// 输出每条指令
|
||||||
|
scc_mir_instr_vec_t *instrs = SCC_MIR_BBLOCK_VALUES(bb);
|
||||||
|
scc_vec_foreach(*instrs, i) {
|
||||||
|
const scc_mir_instr_t *ins = &scc_vec_at(*instrs, i);
|
||||||
|
scc_mir_dump_instr(ctx, ins);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void scc_mir_dump_func(scc_mir_dump_ctx_t *ctx, const scc_mir_func_t *func) {
|
||||||
|
Assert(ctx != nullptr && func != nullptr);
|
||||||
|
scc_tree_dump_t *td = ctx->dump_ctx;
|
||||||
|
|
||||||
|
scc_mir_func_meta_t *meta = SCC_MIR_FUNC_META(func);
|
||||||
|
// 函数头部
|
||||||
|
scc_tree_dump_begin_line(td);
|
||||||
|
scc_tree_dump_node(td, "func @%s", func->name ? func->name : "<anon>");
|
||||||
|
|
||||||
|
// 输出所有基本块
|
||||||
|
scc_vec_foreach(func->bblocks, i) {
|
||||||
|
scc_cfg_bblock_id_t id = scc_vec_at(func->bblocks, i);
|
||||||
|
const scc_cfg_bblock_t *bb =
|
||||||
|
scc_cfg_module_unsafe_get_bblock(&ctx->mir_module->cfg_module, id);
|
||||||
|
scc_mir_dump_bblock(ctx, bb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void scc_mir_dump_module(scc_mir_dump_ctx_t *ctx) {
|
||||||
|
scc_vec_foreach(ctx->mir_module->cfg_module.symbols, i) {
|
||||||
|
// FIXME 0 is null
|
||||||
|
if (i == 0)
|
||||||
|
continue;
|
||||||
|
scc_cfg_symbol_t *sym =
|
||||||
|
&scc_vec_at(ctx->mir_module->cfg_module.symbols, i);
|
||||||
|
scc_tree_dump_begin_line(ctx->dump_ctx);
|
||||||
|
scc_tree_dump_node(ctx->dump_ctx, "symbol");
|
||||||
|
scc_tree_dump_append_fmt(ctx->dump_ctx, " %s", sym->name);
|
||||||
|
}
|
||||||
|
scc_vec_foreach(ctx->mir_module->cfg_module.funcs, i) {
|
||||||
|
if (i == 0)
|
||||||
|
continue;
|
||||||
|
scc_mir_dump_func(ctx,
|
||||||
|
&scc_vec_at(ctx->mir_module->cfg_module.funcs, i));
|
||||||
|
}
|
||||||
|
}
|
||||||
12
libs/ir/mir/src/scc_mir_module.c
Normal file
12
libs/ir/mir/src/scc_mir_module.c
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
#include "scc_mir_module.h"
|
||||||
|
|
||||||
|
void scc_mir_module_init(scc_mir_module_t *mir_module) {
|
||||||
|
scc_vec_init(mir_module->func_metas);
|
||||||
|
scc_vec_init(mir_module->symbol_metas);
|
||||||
|
}
|
||||||
|
|
||||||
|
void scc_mir_module_drop(scc_mir_module_t *mir_module) {
|
||||||
|
// FIXME memory leak
|
||||||
|
scc_vec_free(mir_module->func_metas);
|
||||||
|
scc_vec_free(mir_module->symbol_metas);
|
||||||
|
}
|
||||||
0
libs/ir/mir/src/scc_mir_pass.c
Normal file
0
libs/ir/mir/src/scc_mir_pass.c
Normal file
@@ -16,6 +16,7 @@ typedef struct {
|
|||||||
cbool emit_ast;
|
cbool emit_ast;
|
||||||
cbool emit_hir;
|
cbool emit_hir;
|
||||||
cbool emit_lir;
|
cbool emit_lir;
|
||||||
|
cbool emit_mir;
|
||||||
} scc_config_t;
|
} scc_config_t;
|
||||||
|
|
||||||
static void setup_argparse(scc_argparse_t *argparse, scc_config_t *config,
|
static void setup_argparse(scc_argparse_t *argparse, scc_config_t *config,
|
||||||
@@ -183,6 +184,13 @@ static void setup_argparse(scc_argparse_t *argparse, scc_config_t *config,
|
|||||||
scc_hints[SCC_HINT_EMIT_LIR]);
|
scc_hints[SCC_HINT_EMIT_LIR]);
|
||||||
scc_argparse_spec_setup_bool(&opt_lir.spec, &(config->emit_lir));
|
scc_argparse_spec_setup_bool(&opt_lir.spec, &(config->emit_lir));
|
||||||
scc_argparse_cmd_add_opt(root, &opt_lir);
|
scc_argparse_cmd_add_opt(root, &opt_lir);
|
||||||
|
|
||||||
|
// -M, --emit-mir
|
||||||
|
scc_argparse_opt_t opt_mir;
|
||||||
|
scc_argparse_opt_init(&opt_mir, 'M', "emit-mir",
|
||||||
|
scc_hints[SCC_HINT_EMIT_MIR]);
|
||||||
|
scc_argparse_spec_setup_bool(&opt_mir.spec, &(config->emit_mir));
|
||||||
|
scc_argparse_cmd_add_opt(root, &opt_mir);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* __SCC_CONFIG_H___ */
|
#endif /* __SCC_CONFIG_H___ */
|
||||||
|
|||||||
23
src/main.c
23
src/main.c
@@ -7,8 +7,9 @@
|
|||||||
#include <scc_ast_dump.h>
|
#include <scc_ast_dump.h>
|
||||||
#include <scc_hir2lir.h>
|
#include <scc_hir2lir.h>
|
||||||
#include <scc_hir_dump.h>
|
#include <scc_hir_dump.h>
|
||||||
|
#include <scc_lir2mir.h>
|
||||||
#include <scc_lir_dump.h>
|
#include <scc_lir_dump.h>
|
||||||
|
#include <scc_mir_dump.h>
|
||||||
// #include <scc_ir2mcode.h>
|
// #include <scc_ir2mcode.h>
|
||||||
// #include <sccf2pe.h>
|
// #include <sccf2pe.h>
|
||||||
|
|
||||||
@@ -262,6 +263,26 @@ sstream_drop:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
scc_mir_module_t mir_module;
|
||||||
|
scc_mir_module_init(&mir_module);
|
||||||
|
scc_lir2mir(&mir_module, &lir_module);
|
||||||
|
if (config.emit_mir) {
|
||||||
|
scc_mir_dump_ctx_t mir_dump_ctx;
|
||||||
|
scc_tree_dump_t tree_dump;
|
||||||
|
if (fp == nullptr) {
|
||||||
|
scc_tree_dump_init(&tree_dump, true);
|
||||||
|
} else {
|
||||||
|
scc_tree_dump_init(&tree_dump, false);
|
||||||
|
}
|
||||||
|
scc_mir_dump_init(&mir_dump_ctx, &tree_dump, &mir_module);
|
||||||
|
scc_mir_dump_module(&mir_dump_ctx);
|
||||||
|
|
||||||
|
scc_tree_dump_flush(&tree_dump, tree_dump_output,
|
||||||
|
fp == nullptr ? scc_stdout : fp);
|
||||||
|
scc_tree_dump_drop(&tree_dump);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
// scc_ir2mcode_ctx_t ir2mcode_ctx;
|
// scc_ir2mcode_ctx_t ir2mcode_ctx;
|
||||||
// sccf_builder_t sccf_builder;
|
// sccf_builder_t sccf_builder;
|
||||||
// scc_ir2mcode_init(&ir2mcode_ctx, &cprog, &sccf_builder,
|
// scc_ir2mcode_init(&ir2mcode_ctx, &cprog, &sccf_builder,
|
||||||
|
|||||||
Reference in New Issue
Block a user