#include #include #include #define GET_MODULE(ctx) (&(ctx->cprog->module)) static const char *get_node_type_str(scc_hir_value_tag_t tag) { static const char *node_types[] = { [SCC_HIR_VALUE_TAG_NULLPTR] = "NullPtr", [SCC_HIR_VALUE_TAG_BUILTIN] = "Builtin", [SCC_HIR_VALUE_TAG_INTEGER] = "ConstInt", [SCC_HIR_VALUE_TAG_DECIMAL] = "ConstFloat", [SCC_HIR_VALUE_TAG_ARRAY] = "ConstArray", [SCC_HIR_VALUE_TAG_AGGREGATE] = "Aggregate", [SCC_HIR_VALUE_TAG_CONV] = "Convert", [SCC_HIR_VALUE_TAG_FUNC_ARG_REF] = "FuncArgRef", [SCC_HIR_VALUE_TAG_BLOCK_ARG_REF] = "BlockArgRef", [SCC_HIR_VALUE_TAG_ALLOC] = "Alloc", [SCC_HIR_VALUE_TAG_GLOBAL_ALLOC] = "GlobalAlloc", [SCC_HIR_VALUE_TAG_LOAD] = "Load", [SCC_HIR_VALUE_TAG_STORE] = "Store", [SCC_HIR_VALUE_TAG_GET_ELEM_PTR] = "GetElemPtr", [SCC_HIR_VALUE_TAG_OP] = "Op", [SCC_HIR_VALUE_TAG_BRANCH] = "Branch", [SCC_HIR_VALUE_TAG_JUMP] = "Jump", [SCC_HIR_VALUE_TAG_CALL] = "Call", [SCC_HIR_VALUE_TAG_RET] = "Ret", }; if (tag >= 0 && (usize)tag < sizeof(node_types) / sizeof(node_types[0]) && node_types[tag]) return node_types[tag]; return "UnknownIRNode"; } static const char *get_op_str(scc_hir_op_type_t op) { static const char *ops[] = { [SCC_HIR_OP_EMPTY] = "empty", [SCC_HIR_OP_NEQ] = "!=", [SCC_HIR_OP_EQ] = "==", [SCC_HIR_OP_GT] = ">", [SCC_HIR_OP_LT] = "<", [SCC_HIR_OP_GE] = ">=", [SCC_HIR_OP_LE] = "<=", [SCC_HIR_OP_ADD] = "+", [SCC_HIR_OP_SUB] = "-", [SCC_HIR_OP_MUL] = "*", [SCC_HIR_OP_DIV] = "/", [SCC_HIR_OP_MOD] = "%", [SCC_HIR_OP_AND] = "&", [SCC_HIR_OP_OR] = "|", [SCC_HIR_OP_XOR] = "^", [SCC_HIR_OP_NOT] = "~", [SCC_HIR_OP_SHL] = "<<", [SCC_HIR_OP_SHR] = ">>", [SCC_HIR_OP_SAR] = ">>a", }; if (op >= 0 && (usize)op < sizeof(ops) / sizeof(ops[0]) && ops[op]) return ops[op]; return ""; } static const char *get_type_tag_str(scc_hir_type_tag_t tag) { static const char *type_tags[] = { [SCC_HIR_TYPE_void] = "void", [SCC_HIR_TYPE_u8] = "u8", [SCC_HIR_TYPE_u16] = "u16", [SCC_HIR_TYPE_u32] = "u32", [SCC_HIR_TYPE_u64] = "u64", [SCC_HIR_TYPE_u128] = "u128", [SCC_HIR_TYPE_i8] = "i8", [SCC_HIR_TYPE_i16] = "i16", [SCC_HIR_TYPE_i32] = "i32", [SCC_HIR_TYPE_i64] = "i64", [SCC_HIR_TYPE_i128] = "i128", [SCC_HIR_TYPE_f16] = "f16", [SCC_HIR_TYPE_f32] = "f32", [SCC_HIR_TYPE_f64] = "f64", [SCC_HIR_TYPE_f128] = "f128", [SCC_HIR_TYPE_PTR] = "ptr", [SCC_HIR_TYPE_ARRAY] = "array", [SCC_HIR_TYPE_FUNC] = "func", [SCC_HIR_TYPE_STRUCT] = "struct", [SCC_HIR_TYPE_VECTOR] = "vector", }; if (tag >= 0 && (usize)tag < sizeof(type_tags) / sizeof(type_tags[0]) && type_tags[tag]) return type_tags[tag]; return ""; } static inline void dump_child_node_ref(scc_hir_dump_t *ctx, scc_hir_value_ref_t child, cbool is_last) { if (!child) return; scc_tree_dump_push(ctx->dump_ctx, is_last); scc_hir_dump_value(ctx, child); scc_tree_dump_pop(ctx->dump_ctx); } static void dump_integer_node(scc_hir_dump_t *ctx, const scc_hir_value_t *value) { scc_tree_dump_push(ctx->dump_ctx, true); scc_tree_dump_begin_line(ctx->dump_ctx); // FIXME hack it scc_tree_dump_value(ctx->dump_ctx, "%d", value->data.integer.data.digit); scc_tree_dump_pop(ctx->dump_ctx); } static void dump_op_node(scc_hir_dump_t *ctx, const scc_hir_value_t *value) { scc_tree_dump_push(ctx->dump_ctx, false); scc_tree_dump_begin_line(ctx->dump_ctx); scc_tree_dump_node(ctx->dump_ctx, "op: "); scc_tree_dump_value(ctx->dump_ctx, "%s", get_op_str(value->data.op.op)); scc_tree_dump_pop(ctx->dump_ctx); if (value->data.op.lhs) dump_child_node_ref(ctx, value->data.op.lhs, value->data.op.rhs ? false : true); if (value->data.op.rhs) dump_child_node_ref(ctx, value->data.op.rhs, true); } static void dump_load_node(scc_hir_dump_t *ctx, const scc_hir_value_t *value) { if (value->data.load.target) dump_child_node_ref(ctx, value->data.load.target, true); } static void dump_store_node(scc_hir_dump_t *ctx, const scc_hir_value_t *value) { if (value->data.store.target) dump_child_node_ref(ctx, value->data.store.target, false); if (value->data.store.value) dump_child_node_ref(ctx, value->data.store.value, true); } static void dump_get_elem_ptr_node(scc_hir_dump_t *ctx, const scc_hir_value_t *value) { if (value->data.get_elem_ptr.src_addr) dump_child_node_ref(ctx, value->data.get_elem_ptr.src_addr, false); if (value->data.get_elem_ptr.index) dump_child_node_ref(ctx, value->data.get_elem_ptr.index, true); } static void dump_branch_node(scc_hir_dump_t *ctx, const scc_hir_value_t *value) { if (value->data.branch.cond) dump_child_node_ref(ctx, value->data.branch.cond, false); if (value->data.branch.true_bblock) { scc_hir_bblock_t *true_bblock = scc_hir_module_get_bblock( GET_MODULE(ctx), value->data.branch.true_bblock); if (true_bblock) { scc_tree_dump_begin_line(ctx->dump_ctx); scc_tree_dump_node(ctx->dump_ctx, "TrueBlock: "); scc_tree_dump_value(ctx->dump_ctx, "'%s'", true_bblock->name ? true_bblock->name : ""); } } if (value->data.branch.false_bblock) { scc_hir_bblock_t *false_bblock = scc_hir_module_get_bblock( GET_MODULE(ctx), value->data.branch.false_bblock); if (false_bblock) { scc_tree_dump_begin_line(ctx->dump_ctx); scc_tree_dump_node(ctx->dump_ctx, "FalseBlock: "); scc_tree_dump_value(ctx->dump_ctx, "'%s'", false_bblock->name ? false_bblock->name : ""); } } } static void dump_jump_node(scc_hir_dump_t *ctx, const scc_hir_value_t *value) { scc_tree_dump_begin_line(ctx->dump_ctx); if (value->data.jump.target_bblock) { scc_hir_bblock_t *target = scc_hir_module_get_bblock( GET_MODULE(ctx), value->data.jump.target_bblock); if (target) scc_tree_dump_value(ctx->dump_ctx, "to '%s'", target->name ? target->name : ""); else scc_tree_dump_value(ctx->dump_ctx, "to invalid block"); } else { scc_tree_dump_value(ctx->dump_ctx, "to nullptr"); } } static void dump_call_node(scc_hir_dump_t *ctx, const scc_hir_value_t *value) { scc_tree_dump_begin_line(ctx->dump_ctx); if (value->data.call.callee) { scc_hir_func_t *callee = scc_hir_module_get_func(GET_MODULE(ctx), value->data.call.callee); scc_tree_dump_value(ctx->dump_ctx, "func='%s'", callee ? (callee->name ? callee->name : "") : ""); } else { scc_tree_dump_value(ctx->dump_ctx, "func=nullptr"); } for (usize i = 0; i < scc_vec_size(value->data.call.args); i++) { cbool is_last = (i + 1 == scc_vec_size(value->data.call.args)); scc_tree_dump_push(ctx->dump_ctx, is_last); scc_hir_value_ref_t arg = scc_vec_at(value->data.call.args, i); dump_child_node_ref(ctx, arg, is_last); scc_tree_dump_pop(ctx->dump_ctx); } } static void dump_ret_node(scc_hir_dump_t *ctx, const scc_hir_value_t *value) { if (value->data.ret.ret_val) dump_child_node_ref(ctx, value->data.ret.ret_val, true); } void scc_hir_dump_ctx_init(scc_hir_dump_t *ctx, scc_tree_dump_t *td, scc_hir_cprog_t *cprog) { ctx->cprog = cprog; ctx->dump_ctx = td; } void scc_hir_dump_value(scc_hir_dump_t *ctx, scc_hir_value_ref_t value_ref) { scc_hir_value_t *value = scc_hir_module_get_value(GET_MODULE(ctx), value_ref); if (!value) { LOG_ERROR("Invalid value ref"); return; } scc_tree_dump_begin_line(ctx->dump_ctx); scc_tree_dump_node(ctx->dump_ctx, "%s", get_node_type_str(value->tag)); if (value->name && value->name[0]) scc_tree_dump_value(ctx->dump_ctx, " [%s]", value->name); if (value->type) { scc_hir_type_t *type = scc_hir_module_get_type(GET_MODULE(ctx), value->type); if (type) { scc_tree_dump_append(ctx->dump_ctx, " : "); scc_tree_dump_value(ctx->dump_ctx, "%s", get_type_tag_str(type->tag)); } } switch (value->tag) { case SCC_HIR_VALUE_TAG_INTEGER: dump_integer_node(ctx, value); break; case SCC_HIR_VALUE_TAG_ALLOC: break; case SCC_HIR_VALUE_TAG_LOAD: dump_load_node(ctx, value); break; case SCC_HIR_VALUE_TAG_STORE: dump_store_node(ctx, value); break; case SCC_HIR_VALUE_TAG_GET_ELEM_PTR: dump_get_elem_ptr_node(ctx, value); break; case SCC_HIR_VALUE_TAG_OP: dump_op_node(ctx, value); break; case SCC_HIR_VALUE_TAG_BRANCH: dump_branch_node(ctx, value); break; case SCC_HIR_VALUE_TAG_JUMP: dump_jump_node(ctx, value); break; case SCC_HIR_VALUE_TAG_CALL: dump_call_node(ctx, value); break; case SCC_HIR_VALUE_TAG_RET: dump_ret_node(ctx, value); break; default: scc_tree_dump_value(ctx->dump_ctx, "unknown"); scc_tree_dump_append_fmt(ctx->dump_ctx, " tag(%d)", value->tag); break; } } void scc_hir_dump_type(scc_hir_dump_t *ctx, scc_hir_type_ref_t type_ref) { if (!ctx || !type_ref) { LOG_ERROR("invalid parameter"); return; } scc_hir_type_t *type = scc_hir_module_get_type(GET_MODULE(ctx), type_ref); if (!type) { LOG_ERROR("invalid type ref"); return; } scc_tree_dump_begin_line(ctx->dump_ctx); scc_tree_dump_node(ctx->dump_ctx, "Type: "); scc_tree_dump_value(ctx->dump_ctx, "%s", get_type_tag_str(type->tag)); switch (type->tag) { case SCC_HIR_TYPE_PTR: if (type->data.pointer.base) { scc_tree_dump_push(ctx->dump_ctx, true); scc_hir_dump_type(ctx, type->data.pointer.base); scc_tree_dump_pop(ctx->dump_ctx); } break; case SCC_HIR_TYPE_ARRAY: if (type->data.array.len > 0) { scc_tree_dump_begin_line(ctx->dump_ctx); scc_tree_dump_node(ctx->dump_ctx, "Array Length: "); scc_tree_dump_value(ctx->dump_ctx, "%zu", type->data.array.len); scc_tree_dump_append(ctx->dump_ctx, "\n"); } if (type->data.array.base) { scc_tree_dump_push(ctx->dump_ctx, true); scc_hir_dump_type(ctx, type->data.array.base); scc_tree_dump_pop(ctx->dump_ctx); } break; case SCC_HIR_TYPE_FUNC: for (usize i = 0; i < scc_vec_size(type->data.function.params); i++) { cbool is_last = (i + 1 == scc_vec_size(type->data.function.params)); scc_tree_dump_push(ctx->dump_ctx, is_last); scc_hir_dump_type(ctx, scc_vec_at(type->data.function.params, i)); scc_tree_dump_pop(ctx->dump_ctx); } if (type->data.function.ret_type) { scc_tree_dump_push(ctx->dump_ctx, true); scc_hir_dump_type(ctx, type->data.function.ret_type); scc_tree_dump_pop(ctx->dump_ctx); } break; default: break; } } void scc_hir_dump_bblock(scc_hir_dump_t *ctx, scc_hir_bblock_ref_t bblock_ref) { if (!ctx || !bblock_ref) { LOG_ERROR("invalid parameter"); return; } scc_hir_bblock_t *bblock = scc_hir_module_get_bblock(GET_MODULE(ctx), bblock_ref); if (!bblock) { LOG_ERROR("invalid bblock ref"); return; } scc_tree_dump_begin_line(ctx->dump_ctx); scc_tree_dump_node(ctx->dump_ctx, "BasicBlock: "); scc_tree_dump_value(ctx->dump_ctx, "'%s'", bblock->name ? bblock->name : ""); scc_tree_dump_append(ctx->dump_ctx, "\n"); for (usize i = 0; i < scc_vec_size(SCC_HIR_BBLOCK_VALUES(*bblock)); i++) { cbool is_last = (i + 1 == scc_vec_size(SCC_HIR_BBLOCK_VALUES(*bblock))); scc_tree_dump_push(ctx->dump_ctx, is_last); scc_hir_dump_value(ctx, scc_vec_at(SCC_HIR_BBLOCK_VALUES(*bblock), i)); scc_tree_dump_pop(ctx->dump_ctx); } } void scc_hir_dump_func(scc_hir_dump_t *ctx, scc_hir_func_ref_t func_ref) { scc_hir_func_t *func = scc_hir_module_get_func(GET_MODULE(ctx), func_ref); if (!ctx || !func) { LOG_ERROR("invalid parameter"); return; } scc_tree_dump_begin_line(ctx->dump_ctx); scc_tree_dump_node(ctx->dump_ctx, "Function: "); scc_tree_dump_value(ctx->dump_ctx, "'%s'", func->name ? func->name : ""); scc_tree_dump_append(ctx->dump_ctx, "\n"); if (SCC_HIR_FUNC_META(*func)->type) { scc_tree_dump_push(ctx->dump_ctx, false); scc_hir_dump_type(ctx, SCC_HIR_FUNC_META(*func)->type); scc_tree_dump_pop(ctx->dump_ctx); } for (usize i = 0; i < scc_vec_size(SCC_HIR_FUNC_META(*func)->params); i++) { cbool is_last = (i + 1 == scc_vec_size(SCC_HIR_FUNC_META(*func)->params)); scc_tree_dump_push(ctx->dump_ctx, is_last); scc_hir_dump_value(ctx, scc_vec_at(SCC_HIR_FUNC_META(*func)->params, i)); scc_tree_dump_pop(ctx->dump_ctx); } for (usize i = 0; i < scc_vec_size(func->bblocks); i++) { cbool is_last = (i + 1 == scc_vec_size(func->bblocks)); scc_tree_dump_push(ctx->dump_ctx, is_last); scc_hir_dump_bblock(ctx, scc_vec_at(func->bblocks, i)); scc_tree_dump_pop(ctx->dump_ctx); } } void scc_hir_dump_cprog(scc_hir_dump_t *ctx) { scc_tree_dump_node(ctx->dump_ctx, "Func defs:\n"); scc_vec_foreach(ctx->cprog->func_defs, i) { cbool is_last = (i + 1 == scc_vec_size(ctx->cprog->func_defs)); scc_tree_dump_push(ctx->dump_ctx, is_last); scc_hir_dump_func(ctx, scc_vec_at(ctx->cprog->func_defs, i)); scc_tree_dump_pop(ctx->dump_ctx); } } // ----- 线性输出(保留原逻辑,改用新 API)----- void scc_hir_dump_type_linear(scc_hir_dump_t *ctx, scc_hir_type_ref_t type_ref) { scc_hir_type_t *type = scc_hir_module_get_type(GET_MODULE(ctx), type_ref); if (!ctx || !type) { LOG_ERROR("invalid parameter"); return; } switch (type->tag) { case SCC_HIR_TYPE_unknown: case SCC_HIR_TYPE_void: case SCC_HIR_TYPE_i8: case SCC_HIR_TYPE_i16: case SCC_HIR_TYPE_i32: case SCC_HIR_TYPE_i64: case SCC_HIR_TYPE_i128: case SCC_HIR_TYPE_u8: case SCC_HIR_TYPE_u16: case SCC_HIR_TYPE_u32: case SCC_HIR_TYPE_u64: case SCC_HIR_TYPE_u128: case SCC_HIR_TYPE_f16: case SCC_HIR_TYPE_f32: case SCC_HIR_TYPE_f64: case SCC_HIR_TYPE_f128: scc_tree_dump_value(ctx->dump_ctx, "%s", get_type_tag_str(type->tag)); break; case SCC_HIR_TYPE_ARRAY: scc_tree_dump_append(ctx->dump_ctx, "["); scc_hir_dump_type_linear(ctx, type->data.array.base); scc_tree_dump_append_fmt(ctx->dump_ctx, ", %zu]", type->data.array.len); break; case SCC_HIR_TYPE_PTR: scc_tree_dump_append(ctx->dump_ctx, "*"); scc_hir_dump_type_linear(ctx, type->data.pointer.base); break; case SCC_HIR_TYPE_FUNC: scc_tree_dump_append(ctx->dump_ctx, "("); for (usize i = 0; i < scc_vec_size(type->data.function.params); i++) { if (i > 0) scc_tree_dump_append(ctx->dump_ctx, ", "); scc_hir_dump_type_linear(ctx, scc_vec_at(type->data.function.params, i)); } if (type->data.function.ret_type) { scc_tree_dump_append(ctx->dump_ctx, ") -> "); scc_hir_dump_type_linear(ctx, type->data.function.ret_type); } else { scc_tree_dump_append(ctx->dump_ctx, ")"); } break; default: LOG_ERROR("invalid type tag"); break; } } static void format_ref_or_value(scc_hir_dump_t *ctx, scc_hir_value_ref_t value_ref) { scc_hir_value_t *value = scc_hir_module_get_value(GET_MODULE(ctx), value_ref); if (!value) { scc_tree_dump_append_fmt(ctx->dump_ctx, "%%%u", value_ref); return; } // FIXME // if (value->tag == SCC_HIR_VALUE_TAG_INTEGER) { // scc_tree_dump_append_fmt(ctx->dump_ctx, "%d", // value->data.const_int.int32); // return; // } if (value->name && value->name[0] != '\0') { scc_tree_dump_node(ctx->dump_ctx, "%%%u[%s]", value_ref, value->name); } else { scc_tree_dump_node(ctx->dump_ctx, "%%%u", value_ref); } if (value->type != SCC_HIR_REF_nullptr) { scc_tree_dump_append(ctx->dump_ctx, ":"); scc_hir_dump_type_linear(ctx, value->type); } } void scc_hir_dump_value_linear(scc_hir_dump_t *ctx, scc_hir_value_ref_t value_ref) { scc_hir_value_t *value = scc_hir_module_get_value(GET_MODULE(ctx), value_ref); if (!value) { scc_tree_dump_append(ctx->dump_ctx, "\n"); return; } cbool needs_equals = (value->tag != SCC_HIR_VALUE_TAG_BRANCH && value->tag != SCC_HIR_VALUE_TAG_JUMP && value->tag != SCC_HIR_VALUE_TAG_RET && value->tag != SCC_HIR_VALUE_TAG_STORE); if (needs_equals) { format_ref_or_value(ctx, value_ref); scc_tree_dump_append(ctx->dump_ctx, " = "); } switch (value->tag) { case SCC_HIR_VALUE_TAG_BUILTIN: { scc_tree_dump_append(ctx->dump_ctx, "@scc::"); switch (value->data.builtin.tag) { case SCC_HIR_BUILTIN_TAG_MEMCPY: scc_tree_dump_append(ctx->dump_ctx, "memcpy"); scc_tree_dump_append(ctx->dump_ctx, "("); format_ref_or_value(ctx, value->data.builtin.func.memcpy.dest); scc_tree_dump_append(ctx->dump_ctx, ", "); format_ref_or_value(ctx, value->data.builtin.func.memcpy.src); scc_tree_dump_append(ctx->dump_ctx, ", "); format_ref_or_value(ctx, value->data.builtin.func.memcpy.size); scc_tree_dump_append(ctx->dump_ctx, ")"); break; case SCC_HIR_BUILTIN_TAG_MEMSET: scc_tree_dump_append(ctx->dump_ctx, "memset"); break; case SCC_HIR_BUILTIN_TAG_VA_ARG: scc_tree_dump_append(ctx->dump_ctx, "va_arg"); break; case SCC_HIR_BUILTIN_TAG_VA_END: scc_tree_dump_append(ctx->dump_ctx, "va_end"); break; case SCC_HIR_BUILTIN_TAG_VA_COPY: scc_tree_dump_append(ctx->dump_ctx, "va_copy"); break; case SCC_HIR_BUILTIN_TAG_VA_START: scc_tree_dump_append(ctx->dump_ctx, "va_start"); break; default: Panic("Unknown builtin tag"); break; } break; } case SCC_HIR_VALUE_TAG_INTEGER: // 值已经在 format 中输出,这里不需要再做 break; case SCC_HIR_VALUE_TAG_AGGREGATE: // 聚合类型:递归输出每个元素(每个占一行) scc_vec_foreach(value->data.aggregate.fields, i) { scc_hir_dump_value_linear( ctx, scc_vec_at(value->data.aggregate.fields, i)); scc_tree_dump_append(ctx->dump_ctx, "\n"); } return; case SCC_HIR_VALUE_TAG_ALLOC: scc_tree_dump_append(ctx->dump_ctx, "alloc"); break; case SCC_HIR_VALUE_TAG_LOAD: scc_tree_dump_append(ctx->dump_ctx, "load "); format_ref_or_value(ctx, value->data.load.target); break; case SCC_HIR_VALUE_TAG_STORE: scc_tree_dump_append(ctx->dump_ctx, "store "); format_ref_or_value(ctx, value->data.store.value); scc_tree_dump_append(ctx->dump_ctx, " -> "); format_ref_or_value(ctx, value->data.store.target); break; case SCC_HIR_VALUE_TAG_GET_ELEM_PTR: scc_tree_dump_append(ctx->dump_ctx, "getelemptr "); format_ref_or_value(ctx, value->data.get_elem_ptr.src_addr); scc_tree_dump_append(ctx->dump_ctx, ", "); format_ref_or_value(ctx, value->data.get_elem_ptr.index); break; case SCC_HIR_VALUE_TAG_OP: format_ref_or_value(ctx, value->data.op.lhs); scc_tree_dump_append_fmt(ctx->dump_ctx, " %s ", get_op_str(value->data.op.op)); format_ref_or_value(ctx, value->data.op.rhs); break; case SCC_HIR_VALUE_TAG_BRANCH: if (value->data.branch.cond) { scc_tree_dump_append(ctx->dump_ctx, "br "); format_ref_or_value(ctx, value->data.branch.cond); scc_tree_dump_append_fmt(ctx->dump_ctx, ", label %%L%u, label %%L%u", value->data.branch.true_bblock, value->data.branch.false_bblock); } else { scc_tree_dump_append_fmt(ctx->dump_ctx, "br label %%L%u", value->data.branch.true_bblock); } break; case SCC_HIR_VALUE_TAG_JUMP: scc_tree_dump_append_fmt(ctx->dump_ctx, "jmp label %%L%u", value->data.jump.target_bblock); break; case SCC_HIR_VALUE_TAG_CALL: { scc_hir_func_t *func = scc_hir_module_get_func(GET_MODULE(ctx), value->data.call.callee); scc_tree_dump_append_fmt(ctx->dump_ctx, "call @%s(", func ? (func->name ? func->name : "") : ""); for (usize i = 0; i < scc_vec_size(value->data.call.args); i++) { if (i > 0) scc_tree_dump_append(ctx->dump_ctx, ", "); format_ref_or_value(ctx, scc_vec_at(value->data.call.args, i)); } scc_tree_dump_append(ctx->dump_ctx, ")"); break; } case SCC_HIR_VALUE_TAG_RET: if (value->data.ret.ret_val != 0) { scc_tree_dump_append(ctx->dump_ctx, "ret "); format_ref_or_value(ctx, value->data.ret.ret_val); } else { scc_tree_dump_append(ctx->dump_ctx, "ret void"); } break; case SCC_HIR_VALUE_TAG_FUNC_ARG_REF: scc_tree_dump_append_fmt(ctx->dump_ctx, "arg[%zu]", value->data.arg_ref.idx); break; case SCC_HIR_VALUE_TAG_GLOBAL_ALLOC: scc_tree_dump_append_fmt(ctx->dump_ctx, "global %s", value->name); scc_tree_dump_begin_line(ctx->dump_ctx); scc_hir_dump_value_linear(ctx, value->data.global_alloc.value); return; case SCC_HIR_VALUE_TAG_ARRAY: scc_tree_dump_append(ctx->dump_ctx, "const_array "); scc_hir_dump_type_linear(ctx, value->data.const_array.base_type); scc_tree_dump_append(ctx->dump_ctx, " ["); scc_vec_foreach(value->data.const_array.fields, i) { u8 ch = scc_vec_at(value->data.const_array.fields, i); scc_tree_dump_append_fmt(ctx->dump_ctx, " `%c`, ", ch ? ch : ' '); } scc_tree_dump_append(ctx->dump_ctx, " ]"); break; default: scc_tree_dump_append_fmt(ctx->dump_ctx, "<%s value %u>", get_node_type_str(value->tag), value_ref); break; } } void scc_hir_dump_bblock_linear(scc_hir_dump_t *ctx, scc_hir_bblock_ref_t bblock_ref) { scc_tree_dump_begin_line(ctx->dump_ctx); scc_hir_bblock_t *bblock = scc_hir_module_get_bblock(GET_MODULE(ctx), bblock_ref); if (!bblock) { scc_tree_dump_append(ctx->dump_ctx, ""); return; } if (bblock->name && bblock->name[0] != '\0') scc_tree_dump_append_fmt(ctx->dump_ctx, "%%L%d %s:", bblock_ref, bblock->name); else scc_tree_dump_append_fmt(ctx->dump_ctx, "%%L%d :", bblock_ref); for (usize i = 0; i < scc_vec_size(SCC_HIR_BBLOCK_VALUES(*bblock)); i++) { scc_tree_dump_begin_line(ctx->dump_ctx); scc_tree_dump_append(ctx->dump_ctx, " "); scc_hir_dump_value_linear( ctx, scc_vec_at(SCC_HIR_BBLOCK_VALUES(*bblock), i)); } } void scc_hir_dump_func_linear(scc_hir_dump_t *ctx, scc_hir_func_ref_t func_ref, int is_decl) { scc_hir_func_t *func = scc_hir_module_get_func(GET_MODULE(ctx), func_ref); scc_tree_dump_begin_line(ctx->dump_ctx); if (!func) { scc_tree_dump_append(ctx->dump_ctx, ""); return; } scc_tree_dump_append_fmt(ctx->dump_ctx, "func @%s", (func->name && func->name[0]) ? func->name : ""); if (scc_vec_size(SCC_HIR_FUNC_META(*func)->params) > 0) { scc_tree_dump_append(ctx->dump_ctx, "("); for (usize i = 0; i < scc_vec_size(SCC_HIR_FUNC_META(*func)->params); i++) { if (i > 0) scc_tree_dump_append(ctx->dump_ctx, ", "); scc_hir_value_ref_t param_ref = scc_vec_at(SCC_HIR_FUNC_META(*func)->params, i); scc_hir_value_t *param_node = scc_hir_module_get_value(GET_MODULE(ctx), param_ref); scc_tree_dump_append(ctx->dump_ctx, "%"); if (param_node && param_node->name && param_node->name[0] != '\0') scc_tree_dump_append_fmt(ctx->dump_ctx, "%u[%s]", param_ref, param_node->name); else scc_tree_dump_append_fmt(ctx->dump_ctx, "%u", param_ref); } scc_tree_dump_append(ctx->dump_ctx, ")"); } else { scc_tree_dump_append(ctx->dump_ctx, "()"); } scc_tree_dump_append(ctx->dump_ctx, ": "); scc_hir_dump_type_linear(ctx, SCC_HIR_FUNC_META(*func)->type); if (is_decl) { scc_tree_dump_append(ctx->dump_ctx, ";"); return; } scc_tree_dump_append(ctx->dump_ctx, " {"); for (usize i = 0; i < scc_vec_size(func->bblocks); i++) { scc_hir_dump_bblock_linear(ctx, scc_vec_at(func->bblocks, i)); scc_tree_dump_append(ctx->dump_ctx, ""); } scc_tree_dump_begin_line(ctx->dump_ctx); scc_tree_dump_append(ctx->dump_ctx, "}"); } void scc_hir_dump_cprog_linear(scc_hir_dump_t *ctx) { for (usize i = 0; i < scc_vec_size(ctx->cprog->global_vals); i++) { scc_tree_dump_begin_line(ctx->dump_ctx); scc_hir_dump_value_linear(ctx, scc_vec_at(ctx->cprog->global_vals, i)); } for (usize i = 0; i < scc_vec_size(ctx->cprog->func_decls); i++) { scc_hir_func_ref_t func_decl = scc_vec_at(ctx->cprog->func_decls, i); scc_hir_func_t *func = scc_hir_module_get_func(GET_MODULE(ctx), func_decl); if (func && scc_vec_size(func->bblocks) == 0) scc_hir_dump_func_linear(ctx, func_decl, 1); } for (usize i = 0; i < scc_vec_size(ctx->cprog->func_defs); i++) { scc_hir_dump_func_linear(ctx, scc_vec_at(ctx->cprog->func_defs, i), 0); } }