feat(ir2mcode): 添加IR到机器码转换模块并更新依赖配置
- 新增ir2mcode库用于将IR转换为机器码 - 添加sccf2target依赖以支持目标平台转换 - 在ast库中添加scc_pos依赖支持位置信息 - 更新cbuild.toml配置文件添加新库依赖 - 实现AMD64架构代码生成功能 - 添加寄存器分配器实现栈和寄存器位置管理 - 支持基本的算术运算和内存访问操作 - 添加PE格式目标文件生成支持
This commit is contained in:
232
libs/ir2mcode/src/ir2amd64.c
Normal file
232
libs/ir2mcode/src/ir2amd64.c
Normal file
@@ -0,0 +1,232 @@
|
||||
#include <amd64/scc_amd64.h>
|
||||
#include <amd64/scc_amd64_abi.h>
|
||||
#include <reg_alloc.h>
|
||||
#include <scc_ir2mcode.h>
|
||||
|
||||
static scc_reg_loc_t *parse_location(scc_ir2mcode_ctx_t *ctx,
|
||||
scc_ir_bblock_ref_t node_ref) {
|
||||
scc_ir_node_t *node = scc_ir_ctx_get_node(ctx->ir_ctx, node_ref);
|
||||
if (node == null) {
|
||||
LOG_FATAL("invalid node ref");
|
||||
return null;
|
||||
}
|
||||
usize idx = 0;
|
||||
switch (node->tag) {
|
||||
case SCC_IR_NODE_CONST_INT:
|
||||
scc_ir_type_t *type = scc_ir_ctx_get_type(ctx->ir_ctx, node->type);
|
||||
Assert(type != 0);
|
||||
Assert(type->tag == SCC_IR_TYPE_U32 || type->tag == SCC_IR_TYPE_I32);
|
||||
scc_reg_loc_t loc = {.kind = SCC_REG_KIND_IMM,
|
||||
.idx = (usize)node->data.const_int.int32};
|
||||
scc_vec_push(ctx->reg_alloc.reg_loc_vec, loc);
|
||||
idx = scc_vec_size(ctx->reg_alloc.reg_loc_vec);
|
||||
break;
|
||||
case SCC_IR_NODE_CONST_UINT:
|
||||
case SCC_IR_NODE_CONST_FLOAT:
|
||||
TODO();
|
||||
break;
|
||||
default:
|
||||
idx = (usize)scc_hashtable_get(ctx->noderef2regloc,
|
||||
(void *)(usize)node_ref);
|
||||
break;
|
||||
}
|
||||
|
||||
Assert(idx > 0 && idx <= scc_vec_size(ctx->reg_alloc.reg_loc_vec));
|
||||
return &scc_vec_at(ctx->reg_alloc.reg_loc_vec, idx - 1);
|
||||
}
|
||||
|
||||
static void load_value_to_reg(scc_mcode_t *mcode, scc_reg_loc_t *loc, int reg) {
|
||||
switch (loc->kind) {
|
||||
case SCC_REG_KIND_GPR:
|
||||
if (loc->idx != reg) {
|
||||
scc_mcode_amd64_mov_r64_r64(mcode, reg, loc->idx);
|
||||
} else {
|
||||
TODO();
|
||||
}
|
||||
break;
|
||||
case SCC_REG_KIND_STACK:
|
||||
scc_mcode_amd64_mov_r64_m64_disp32(mcode, reg, SCC_AMD64_RBP,
|
||||
-loc->idx);
|
||||
break;
|
||||
case SCC_REG_KIND_IMM:
|
||||
scc_mcode_amd64_mov_r64_imm64(mcode, reg, loc->idx); // 或 imm32
|
||||
break;
|
||||
default:
|
||||
LOG_FATAL("unsupported location");
|
||||
}
|
||||
}
|
||||
|
||||
static void store_value_from_reg(scc_mcode_t *mcode, scc_reg_loc_t *loc,
|
||||
int reg) {
|
||||
switch (loc->kind) {
|
||||
case SCC_REG_KIND_GPR:
|
||||
if (loc->idx != reg) {
|
||||
scc_mcode_amd64_mov_r64_r64(mcode, loc->idx, reg);
|
||||
}
|
||||
case SCC_REG_KIND_STACK:
|
||||
scc_mcode_amd64_mov_m64_disp32_r64(mcode, SCC_AMD64_RBP, -loc->idx,
|
||||
reg);
|
||||
break;
|
||||
case SCC_REG_KIND_IMM:
|
||||
LOG_FATAL("cannot store to immediate");
|
||||
break;
|
||||
default:
|
||||
LOG_FATAL("unsupported location");
|
||||
}
|
||||
}
|
||||
|
||||
static void parse_node(scc_ir2mcode_ctx_t *ctx, scc_ir_bblock_ref_t node_ref,
|
||||
int idx) {
|
||||
scc_ir_node_t *node = scc_ir_ctx_get_node(ctx->ir_ctx, node_ref);
|
||||
if (node == null) {
|
||||
LOG_ERROR("invalid node ref");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (node->tag) {
|
||||
case SCC_IR_NODE_CONV: ///< 类型转换
|
||||
case SCC_IR_NODE_FUNC_ARG_REF: ///< 函数参数引用
|
||||
case SCC_IR_NODE_BLOCK_ARG_REF: ///< 基本块参数引用
|
||||
LOG_ERROR("Unsupported node type: %d", node->tag);
|
||||
break;
|
||||
case SCC_IR_NODE_ALLOC: ///< 分配内存(stack)
|
||||
case SCC_IR_NODE_GLOBAL_ALLOC: ///< 全局分配(bss)
|
||||
break;
|
||||
case SCC_IR_NODE_LOAD: ///< 加载数据
|
||||
{
|
||||
// node->data.load.target
|
||||
scc_reg_loc_t *from = parse_location(ctx, node->data.load.target);
|
||||
scc_reg_loc_t *to = parse_location(ctx, node_ref);
|
||||
load_value_to_reg(&ctx->mcode, from, SCC_AMD64_RAX);
|
||||
store_value_from_reg(&ctx->mcode, to, SCC_AMD64_RAX);
|
||||
break;
|
||||
}
|
||||
case SCC_IR_NODE_STORE: ///< 存储数据
|
||||
{
|
||||
scc_reg_loc_t *from = parse_location(ctx, node->data.store.value);
|
||||
scc_reg_loc_t *to = parse_location(ctx, node->data.store.target);
|
||||
load_value_to_reg(&ctx->mcode, from, SCC_AMD64_RAX);
|
||||
store_value_from_reg(&ctx->mcode, to, SCC_AMD64_RAX);
|
||||
break;
|
||||
}
|
||||
case SCC_IR_NODE_GET_PTR: ///< 获取指针
|
||||
case SCC_IR_NODE_GET_ELEM_PTR: ///< 获取元素指针(used by array)
|
||||
TODO();
|
||||
case SCC_IR_NODE_OP: ///< 二元运算
|
||||
scc_reg_loc_t *loc_lhs = parse_location(ctx, node->data.op.lhs);
|
||||
scc_reg_loc_t *loc_rhs = parse_location(ctx, node->data.op.rhs);
|
||||
scc_reg_loc_t *loc_res = parse_location(ctx, node_ref);
|
||||
|
||||
// 将左操作数加载到 RAX(临时结果寄存器)
|
||||
load_value_to_reg(&ctx->mcode, loc_lhs, SCC_AMD64_RAX);
|
||||
// 将右操作数加载到 RCX
|
||||
load_value_to_reg(&ctx->mcode, loc_rhs, SCC_AMD64_RCX);
|
||||
switch (node->data.op.op) {
|
||||
case SCC_IR_OP_ADD:
|
||||
scc_mcode_amd64_add_r64_r64(&ctx->mcode, SCC_AMD64_RAX,
|
||||
SCC_AMD64_RCX);
|
||||
break;
|
||||
case SCC_IR_OP_SUB:
|
||||
scc_mcode_amd64_sub_r64_r64(&ctx->mcode, SCC_AMD64_RAX,
|
||||
SCC_AMD64_RCX);
|
||||
break;
|
||||
case SCC_IR_OP_MUL:
|
||||
scc_mcode_amd64_mul_r64(&ctx->mcode, SCC_AMD64_RCX);
|
||||
break;
|
||||
default:
|
||||
LOG_FATAL("unknown op: %d", node->data.op.op);
|
||||
break;
|
||||
}
|
||||
// 将 RAX 中的结果存储到 res 位置
|
||||
store_value_from_reg(&ctx->mcode, loc_res, SCC_AMD64_RAX);
|
||||
// [SCC_IR_OP_EMPTY] = "empty", [SCC_IR_OP_NEQ] = "!=",
|
||||
// [SCC_IR_OP_EQ] = "==", [SCC_IR_OP_GT] = ">",
|
||||
// [SCC_IR_OP_LT] = "<", [SCC_IR_OP_GE] = ">=",
|
||||
// [SCC_IR_OP_LE] = "<=", [SCC_IR_OP_ADD] = "+",
|
||||
// [SCC_IR_OP_SUB] = "-", [SCC_IR_OP_MUL] = "*",
|
||||
// [SCC_IR_OP_DIV] = "/", [SCC_IR_OP_MOD] = "%",
|
||||
// [SCC_IR_OP_AND] = "&", [SCC_IR_OP_OR] = "|",
|
||||
// [SCC_IR_OP_XOR] = "^", [SCC_IR_OP_NOT] = "~",
|
||||
// [SCC_IR_OP_SHL] = "<<", [SCC_IR_OP_SHR] = ">>",
|
||||
// [SCC_IR_OP_SAR] = ">>a", // Arithmetic shift right
|
||||
break;
|
||||
case SCC_IR_NODE_BRANCH: ///< 有条件分支
|
||||
case SCC_IR_NODE_JUMP: ///< 无条件跳转
|
||||
case SCC_IR_NODE_CALL: ///< 调用函数
|
||||
LOG_ERROR("Unsupported node type: %d", node->tag);
|
||||
break;
|
||||
case SCC_IR_NODE_RET: ///< 函数返回
|
||||
scc_mcode_amd64_mov_r64_r64(&ctx->mcode, SCC_AMD64_RSP, SCC_AMD64_RBP);
|
||||
scc_mcode_amd64_pop_r64(&ctx->mcode, SCC_AMD64_RBP);
|
||||
scc_mcode_amd64_ret(&ctx->mcode);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void parse_bblock(scc_ir2mcode_ctx_t *ctx, scc_ir_bblock_t *bblock) {
|
||||
|
||||
// 打印基本块中的每条指令
|
||||
for (usize i = 0; i < scc_vec_size(bblock->instrs); i++) {
|
||||
scc_ir_node_ref_t node_ref = scc_vec_at(bblock->instrs, i);
|
||||
parse_node(ctx, node_ref, i);
|
||||
}
|
||||
}
|
||||
|
||||
static void parse_function(scc_ir2mcode_ctx_t *ctx, scc_ir_func_t *func) {
|
||||
scc_hashtable_t bblock2offset;
|
||||
|
||||
ctx->noderef2regloc = scc_reg_alloc(&ctx->reg_alloc, func);
|
||||
// 对齐到 16 字节
|
||||
usize stack_size = (ctx->reg_alloc.alloc_stack_size + 15) & ~15;
|
||||
|
||||
scc_mcode_amd64_push_r64(&ctx->mcode, SCC_AMD64_RBP);
|
||||
scc_mcode_amd64_mov_r64_r64(&ctx->mcode, SCC_AMD64_RBP, SCC_AMD64_RSP);
|
||||
scc_mcode_amd64_sub_rsp_imm32(&ctx->mcode, stack_size);
|
||||
|
||||
for (usize i = 0; i < scc_vec_size(func->bblocks); i++) {
|
||||
scc_ir_bblock_ref_t bblock_ref = scc_vec_at(func->bblocks, i);
|
||||
scc_ir_bblock_t *bblock =
|
||||
scc_ir_ctx_get_bblock(ctx->ir_ctx, bblock_ref);
|
||||
|
||||
if (bblock == null) {
|
||||
LOG_FATAL("<invalid block>\n");
|
||||
return;
|
||||
}
|
||||
parse_bblock(ctx, bblock);
|
||||
}
|
||||
}
|
||||
|
||||
void scc_ir2amd64(scc_ir2mcode_ctx_t *ctx) {
|
||||
scc_reg_alloc_init(&ctx->reg_alloc, scc_reg_alloc_with_stack, ctx->ir_ctx);
|
||||
|
||||
scc_vec_foreach(ctx->cprog->func_defs, i) {
|
||||
scc_ir_node_ref_t func_ref = scc_vec_at(ctx->cprog->func_defs, i);
|
||||
scc_ir_func_t *func = scc_ir_ctx_get_func(ctx->ir_ctx, func_ref);
|
||||
if (!func) {
|
||||
LOG_ERROR("invalid function reference");
|
||||
return;
|
||||
}
|
||||
sccf_sym_t sym = {
|
||||
.sccf_sect_offset = scc_vec_size(ctx->mcode.mcode),
|
||||
.sccf_sect_type = SCCF_SECT_CODE,
|
||||
.sccf_sym_bind = SCCF_SYM_BIND_GLOBAL,
|
||||
.sccf_sym_size = 0,
|
||||
.sccf_sym_type = SCCF_SYM_TYPE_FUNC,
|
||||
.sccf_sym_vis = SCCF_SYM_VIS_DEFAULT,
|
||||
};
|
||||
sccf_builder_add_symbol(&ctx->builder, func->name, &sym);
|
||||
|
||||
parse_function(ctx, func);
|
||||
}
|
||||
sccf_sect_data_t text_section;
|
||||
scc_vec_unsafe_from_buffer(text_section,
|
||||
scc_vec_unsafe_get_data(ctx->mcode.mcode),
|
||||
scc_vec_size(ctx->mcode.mcode));
|
||||
sccf_builder_add_text_section(&ctx->builder, &text_section);
|
||||
sccf_sect_data_t data_section;
|
||||
scc_vec_init(data_section);
|
||||
sccf_builder_add_data_section(&ctx->builder, &data_section);
|
||||
}
|
||||
Reference in New Issue
Block a user