- 添加 scc_ast2ir_mir_module 内联函数统一访问模块 - 替换所有直接访问 ctx->builder.cprog->module 的地方 - 移除重复的 scc_hir_type_size 函数实现 - 添加 scc_hir_module_type_size 函数到模块接口 - 更新所有类型大小计算调用使用新函数 feat(hir): 增强构建器安全性和全局变量处理 - 为 scc_hir_builder_integer 添加空指针检查断言 - 修复 scc_hir_builder_global_alloca 中全局变量类型设置 - 改进 scc_hir_builder_get_elem_ptr 处理空指针索引情况 - 重构字符串常量生成使用 get_elem_ptr 构建器函数 refactor(lir): 简化地址表达式表示并增强内置函数支持 - 移除复杂地址结构体 scc_lir_addr_t - 简化 scc_lir_instr 结构体中的地址表示 - 移除 STORE_ADDR 操作码 - 添加 memcpy 和 memset 内置函数操作码 - 在符号元数据中使用联合体替代嵌套结构体 feat(hir2lir): 完善 HIR 到 LIR 转换中的内置函数处理 - 添加 ensure_vreg 辅助函数确保虚拟寄存器操作数 - 正确处理全局变量地址符号引用 - 优化 GET_ELEM_PTR 转换使用类型大小计算 - 完整实现所有内置函数(BUILTIN)的 LIR 转换 - 包括 memcpy、memset、va_start、va_arg、va_end、va_copy 等
460 lines
14 KiB
C
460 lines
14 KiB
C
/**
|
|
* @file scc_lir_dump.c
|
|
* @brief LIR 文本 dump 实现
|
|
*/
|
|
|
|
#include "scc_lir_dump.h"
|
|
#include <scc_core.h>
|
|
|
|
static const char *op_to_string(scc_lir_op_t op) {
|
|
switch (op) {
|
|
case SCC_LIR_MOV:
|
|
return "mov";
|
|
case SCC_LIR_LOAD:
|
|
return "load";
|
|
case SCC_LIR_LOAD_ADDR:
|
|
return "load.addr";
|
|
case SCC_LIR_STORE:
|
|
return "store";
|
|
// case SCC_LIR_STORE_ADDR:
|
|
// return "store.addr";
|
|
case SCC_LIR_ADD:
|
|
return "add";
|
|
case SCC_LIR_SUB:
|
|
return "sub";
|
|
case SCC_LIR_MUL:
|
|
return "mul";
|
|
case SCC_LIR_DIV_S:
|
|
return "div.s";
|
|
case SCC_LIR_DIV_U:
|
|
return "div.u";
|
|
case SCC_LIR_REM_S:
|
|
return "rem.s";
|
|
case SCC_LIR_REM_U:
|
|
return "rem.u";
|
|
case SCC_LIR_AND:
|
|
return "and";
|
|
case SCC_LIR_OR:
|
|
return "or";
|
|
case SCC_LIR_XOR:
|
|
return "xor";
|
|
case SCC_LIR_SHL:
|
|
return "shl";
|
|
case SCC_LIR_SHR:
|
|
return "shr";
|
|
case SCC_LIR_SAR:
|
|
return "sar";
|
|
case SCC_LIR_NEG:
|
|
return "neg";
|
|
case SCC_LIR_NOT:
|
|
return "not";
|
|
case SCC_LIR_FADD:
|
|
return "fadd";
|
|
case SCC_LIR_FSUB:
|
|
return "fsub";
|
|
case SCC_LIR_FMUL:
|
|
return "fmul";
|
|
case SCC_LIR_FDIV:
|
|
return "fdiv";
|
|
case SCC_LIR_FNEG:
|
|
return "fneg";
|
|
case SCC_LIR_FCVT:
|
|
return "fcvt";
|
|
case SCC_LIR_CMP:
|
|
return "cmp";
|
|
case SCC_LIR_BR:
|
|
return "br";
|
|
case SCC_LIR_JMP:
|
|
return "jmp";
|
|
case SCC_LIR_JMP_INDIRECT:
|
|
return "jmp.indirect";
|
|
case SCC_LIR_CALL:
|
|
return "call";
|
|
case SCC_LIR_CALL_INDIRECT:
|
|
return "call.indirect";
|
|
case SCC_LIR_RET:
|
|
return "ret";
|
|
case SCC_LIR_PARALLEL_COPY:
|
|
return "parallel_copy";
|
|
case SCC_LIR_VA_START:
|
|
return "va_start";
|
|
case SCC_LIR_VA_ARG:
|
|
return "va_arg";
|
|
case SCC_LIR_VA_END:
|
|
return "va_end";
|
|
case SCC_LIR_VA_COPY:
|
|
return "va_copy";
|
|
case SCC_LIR_ALLOCA:
|
|
return "alloca";
|
|
|
|
case SCC_LIR_MEMCPY:
|
|
return "memcpy";
|
|
case SCC_LIR_MEMSET:
|
|
return "memset";
|
|
case SCC_LIR_NOP:
|
|
return "nop";
|
|
default:
|
|
return "???";
|
|
}
|
|
}
|
|
|
|
static const char *cond_to_string(scc_lir_cond_t cond) {
|
|
switch (cond) {
|
|
case SCC_LIR_COND_EQ:
|
|
return "eq";
|
|
case SCC_LIR_COND_NE:
|
|
return "ne";
|
|
case SCC_LIR_COND_SLT:
|
|
return "slt";
|
|
case SCC_LIR_COND_SLE:
|
|
return "sle";
|
|
case SCC_LIR_COND_SGT:
|
|
return "sgt";
|
|
case SCC_LIR_COND_SGE:
|
|
return "sge";
|
|
case SCC_LIR_COND_ULT:
|
|
return "ult";
|
|
case SCC_LIR_COND_ULE:
|
|
return "ule";
|
|
case SCC_LIR_COND_UGT:
|
|
return "ugt";
|
|
case SCC_LIR_COND_UGE:
|
|
return "uge";
|
|
case SCC_LIR_COND_FEQ:
|
|
return "feq";
|
|
case SCC_LIR_COND_FNE:
|
|
return "fne";
|
|
case SCC_LIR_COND_FLT:
|
|
return "flt";
|
|
case SCC_LIR_COND_FLE:
|
|
return "fle";
|
|
case SCC_LIR_COND_FGT:
|
|
return "fgt";
|
|
case SCC_LIR_COND_FGE:
|
|
return "fge";
|
|
default:
|
|
return "???";
|
|
}
|
|
}
|
|
|
|
static void dump_operand(scc_lir_dump_ctx_t *ctx, const scc_lir_val_t *op) {
|
|
scc_tree_dump_t *td = ctx->dump_ctx;
|
|
|
|
switch (op->kind) {
|
|
case SCC_LIR_INSTR_KIND_NONE:
|
|
scc_tree_dump_append(td, "_");
|
|
break;
|
|
case SCC_LIR_INSTR_KIND_ARG:
|
|
scc_tree_dump_append_fmt(td, "arg[%u]", op->data.arg);
|
|
break;
|
|
case SCC_LIR_INSTR_KIND_VREG:
|
|
scc_tree_dump_append_fmt(td, "%%%u", op->data.reg);
|
|
break;
|
|
// case SCC_LIR_INSTR_KIND_PREG:
|
|
// scc_tree_dump_append_fmt(td, "Phy%u", op->data.reg);
|
|
// break;
|
|
case SCC_LIR_INSTR_KIND_IMM:
|
|
// TODO hack ap
|
|
scc_tree_dump_append_fmt(td, "%lld", op->data.imm.data.digit);
|
|
break;
|
|
case SCC_LIR_INSTR_KIND_FIMM:
|
|
TODO();
|
|
scc_tree_dump_append_fmt(td, "%lf", op->data.fimm);
|
|
break;
|
|
case SCC_LIR_INSTR_KIND_SYMBOL:
|
|
scc_tree_dump_append_fmt(td, "@%s",
|
|
op->data.symbol ? op->data.symbol : "<null>");
|
|
break;
|
|
default:
|
|
scc_tree_dump_append(td, "<?>");
|
|
}
|
|
}
|
|
|
|
static void dump_size_ext(scc_lir_dump_ctx_t *ctx, u8 size, scc_lir_ext_t ext) {
|
|
scc_tree_dump_t *td = ctx->dump_ctx;
|
|
const char *size_str = "";
|
|
if (size == SCC_LIR_SIZE_8)
|
|
size_str = "8";
|
|
else if (size == SCC_LIR_SIZE_16)
|
|
size_str = "16";
|
|
else if (size == SCC_LIR_SIZE_32)
|
|
size_str = "32";
|
|
else if (size == SCC_LIR_SIZE_64)
|
|
size_str = "64";
|
|
else
|
|
size_str = "sz(?)";
|
|
|
|
const char *ext_str = "";
|
|
if (ext == SCC_LIR_EXT_SEXT)
|
|
ext_str = ".s";
|
|
else if (ext == SCC_LIR_EXT_ZEXT)
|
|
ext_str = ".u";
|
|
else if (ext == SCC_LIR_EXT_FLOAT)
|
|
ext_str = ".f";
|
|
|
|
if (size_str[0] || ext_str[0]) {
|
|
scc_tree_dump_append_fmt(td, ".%s%s", size_str, ext_str);
|
|
}
|
|
}
|
|
|
|
void scc_lir_dump_ins(scc_lir_dump_ctx_t *ctx, const scc_lir_instr_t *ins) {
|
|
Assert(ctx != nullptr && ins != nullptr);
|
|
scc_tree_dump_t *td = ctx->dump_ctx;
|
|
|
|
scc_tree_dump_begin_line(td);
|
|
scc_tree_dump_append(td, " ");
|
|
// 输出操作码(带节点颜色)
|
|
scc_tree_dump_node(td, "%s", op_to_string(ins->op));
|
|
|
|
// 输出宽度和扩展标志
|
|
dump_size_ext(ctx, ins->size, ins->ext);
|
|
scc_tree_dump_append(td, " ");
|
|
|
|
switch (ins->op) {
|
|
case SCC_LIR_MOV:
|
|
case SCC_LIR_LOAD:
|
|
dump_operand(ctx, &ins->to);
|
|
scc_tree_dump_append(td, " <- ");
|
|
dump_operand(ctx, &ins->arg0);
|
|
break;
|
|
case SCC_LIR_LOAD_ADDR:
|
|
// base + index * scale + offset
|
|
dump_operand(ctx, &ins->to);
|
|
scc_tree_dump_append(td, " <- (");
|
|
dump_operand(ctx, &ins->arg0); // base
|
|
scc_tree_dump_append(td, " + ");
|
|
dump_operand(ctx, &ins->arg1); // index
|
|
scc_tree_dump_append_fmt(td, " * %d + %lld)", ins->metadata.addr.scale,
|
|
ins->metadata.addr.offset);
|
|
break;
|
|
case SCC_LIR_NEG:
|
|
case SCC_LIR_NOT:
|
|
case SCC_LIR_FNEG:
|
|
case SCC_LIR_FCVT:
|
|
dump_operand(ctx, &ins->to);
|
|
scc_tree_dump_append(td, ", ");
|
|
dump_operand(ctx, &ins->arg0);
|
|
break;
|
|
case SCC_LIR_ALLOCA:
|
|
scc_tree_dump_append_fmt(td, "(sz=%zd,al=%zd) => ",
|
|
ins->metadata.alloca.size_bytes,
|
|
ins->metadata.alloca.align_bytes);
|
|
dump_operand(ctx, &ins->to);
|
|
break;
|
|
// case SCC_LIR_STORE_ADDR:
|
|
case SCC_LIR_STORE:
|
|
dump_operand(ctx, &ins->arg0);
|
|
scc_tree_dump_append(td, " -> ");
|
|
dump_operand(ctx, &ins->arg1);
|
|
break;
|
|
case SCC_LIR_ADD:
|
|
case SCC_LIR_SUB:
|
|
case SCC_LIR_MUL:
|
|
case SCC_LIR_DIV_S:
|
|
case SCC_LIR_DIV_U:
|
|
case SCC_LIR_REM_S:
|
|
case SCC_LIR_REM_U:
|
|
case SCC_LIR_AND:
|
|
case SCC_LIR_OR:
|
|
case SCC_LIR_XOR:
|
|
case SCC_LIR_SHL:
|
|
case SCC_LIR_SHR:
|
|
case SCC_LIR_SAR:
|
|
case SCC_LIR_FADD:
|
|
case SCC_LIR_FSUB:
|
|
case SCC_LIR_FMUL:
|
|
case SCC_LIR_FDIV:
|
|
dump_operand(ctx, &ins->to);
|
|
scc_tree_dump_append(td, ", ");
|
|
dump_operand(ctx, &ins->arg0);
|
|
scc_tree_dump_append(td, ", ");
|
|
dump_operand(ctx, &ins->arg1);
|
|
break;
|
|
case SCC_LIR_CMP:
|
|
dump_operand(ctx, &ins->to);
|
|
scc_tree_dump_append_fmt(td, ", %s, ",
|
|
cond_to_string(ins->metadata.cond));
|
|
dump_operand(ctx, &ins->arg0);
|
|
scc_tree_dump_append(td, ", ");
|
|
dump_operand(ctx, &ins->arg1);
|
|
break;
|
|
case SCC_LIR_BR:
|
|
dump_operand(ctx, &ins->arg0);
|
|
scc_tree_dump_append_fmt(td, ", BB#%zu, BB#%zu",
|
|
ins->metadata.br.true_target,
|
|
ins->metadata.br.false_target);
|
|
break;
|
|
case SCC_LIR_JMP:
|
|
scc_tree_dump_append_fmt(td, "#BB%d", ins->metadata.jmp_target);
|
|
break;
|
|
case SCC_LIR_JMP_INDIRECT:
|
|
dump_operand(ctx, &ins->arg0);
|
|
break;
|
|
case SCC_LIR_CALL: {
|
|
const struct scc_lir_call *c = &ins->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 = &ins->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 (ins->metadata.ret_val.kind != SCC_LIR_INSTR_KIND_NONE) {
|
|
dump_operand(ctx, &ins->metadata.ret_val);
|
|
}
|
|
break;
|
|
case SCC_LIR_PARALLEL_COPY: {
|
|
const struct scc_lir_parallel_copy *pc = &ins->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, &ins->metadata.va_start.ap);
|
|
scc_tree_dump_append(td, ", ");
|
|
dump_operand(ctx, &ins->metadata.va_start.last);
|
|
break;
|
|
case SCC_LIR_VA_ARG:
|
|
dump_operand(ctx, &ins->metadata.va_arg.to);
|
|
scc_tree_dump_append(td, " = va_arg ");
|
|
dump_operand(ctx, &ins->metadata.va_arg.ap);
|
|
scc_tree_dump_append_fmt(
|
|
td, ", size=%u, align=%u, float=%d", ins->metadata.va_arg.type_size,
|
|
ins->metadata.va_arg.type_align, ins->metadata.va_arg.is_float);
|
|
break;
|
|
case SCC_LIR_VA_END:
|
|
dump_operand(ctx, &ins->metadata.va_end.ap);
|
|
break;
|
|
case SCC_LIR_VA_COPY:
|
|
dump_operand(ctx, &ins->metadata.va_copy.dest);
|
|
scc_tree_dump_append(td, ", ");
|
|
dump_operand(ctx, &ins->metadata.va_copy.src);
|
|
break;
|
|
case SCC_LIR_MEMCPY:
|
|
dump_operand(ctx, &ins->metadata.memcpy.dest);
|
|
scc_tree_dump_append(td, ", ");
|
|
dump_operand(ctx, &ins->metadata.memcpy.src);
|
|
scc_tree_dump_append(td, ", ");
|
|
dump_operand(ctx, &ins->metadata.memcpy.size);
|
|
break;
|
|
case SCC_LIR_MEMSET:
|
|
dump_operand(ctx, &ins->metadata.memset.dest);
|
|
scc_tree_dump_append(td, ", ");
|
|
dump_operand(ctx, &ins->metadata.memset.value);
|
|
scc_tree_dump_append(td, ", ");
|
|
dump_operand(ctx, &ins->metadata.memset.size);
|
|
break;
|
|
case SCC_LIR_NOP:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void scc_lir_dump_bblock(scc_lir_dump_ctx_t *ctx, const scc_lir_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_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);
|
|
scc_lir_dump_ins(ctx, ins);
|
|
}
|
|
}
|
|
|
|
void scc_lir_dump_func(scc_lir_dump_ctx_t *ctx, const scc_lir_func_t *func) {
|
|
Assert(ctx != nullptr && func != nullptr);
|
|
scc_tree_dump_t *td = ctx->dump_ctx;
|
|
|
|
scc_lir_func_meta_t *meta = SCC_LIR_FUNC_META(func);
|
|
// 函数头部
|
|
scc_tree_dump_begin_line(td);
|
|
scc_tree_dump_node(td, "func @%s%s", func->name ? func->name : "<anon>",
|
|
meta->is_va_arg ? "(...)" : "()");
|
|
scc_tree_dump_append_fmt(td, " (vregs: %u, frame: %d)", meta->vregs_count,
|
|
meta->frame_size);
|
|
if (meta->attr != SCC_LIR_ATTR_NONE) {
|
|
scc_tree_dump_append(td, " [attr:");
|
|
if (meta->attr & SCC_LIR_ATTR_STATIC)
|
|
scc_tree_dump_append(td, " static");
|
|
if (meta->attr & SCC_LIR_ATTR_WEAK)
|
|
scc_tree_dump_append(td, " weak");
|
|
scc_tree_dump_append(td, " ]");
|
|
}
|
|
scc_tree_dump_append(td, " {");
|
|
|
|
// 输出所有基本块
|
|
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->lir_module->cfg_module, id);
|
|
scc_lir_dump_bblock(ctx, bb);
|
|
}
|
|
|
|
scc_tree_dump_begin_line(td);
|
|
scc_tree_dump_append(td, "}");
|
|
}
|
|
|
|
void scc_lir_dump_module(scc_lir_dump_ctx_t *ctx) {
|
|
scc_vec_foreach(ctx->lir_module->cfg_module.symbols, i) {
|
|
// FIXME 0 is null
|
|
if (i == 0)
|
|
continue;
|
|
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_node(ctx->dump_ctx, "symbol");
|
|
scc_lir_symbol_meta_t *meta = SCC_LIR_SYMBOL_META(sym);
|
|
scc_tree_dump_append_fmt(ctx->dump_ctx, " %s", sym->name);
|
|
if (sym->kind == SCC_CFG_SYMBOL_KIND_DATA) {
|
|
scc_tree_dump_append_fmt(ctx->dump_ctx, "(size=%zu)",
|
|
meta->data.size);
|
|
}
|
|
}
|
|
scc_vec_foreach(ctx->lir_module->cfg_module.funcs, i) {
|
|
if (i == 0)
|
|
continue;
|
|
scc_lir_dump_func(ctx,
|
|
&scc_vec_at(ctx->lir_module->cfg_module.funcs, i));
|
|
}
|
|
}
|