feat(mir): 添加栈偏移操作数类型并重构内存访问表示
- 将 MIR 中的 SCC_MIR_OP_MEM 替换为更精确的 SCC_MIR_OP_STACK_SLOT 和 SCC_MIR_OP_STACK_OFFSET 类型 - 在 x86_64 指令选择中更新相应的内存操作数处理逻辑 - 修改寄存器分配器中的栈槽操作数类型检查 - 更新 IR 转机器码过程中的内存操作数转换 refactor(hir): 使用 tree_dump_node 输出函数节点 - 将 hir_dump 中的函数名输出从 append 改为 node 类型 refactor(frame-layout): 重构栈帧布局传递实现结构 - 引入函数指针实现方式替代直接函数实现 - 将栈帧分配功能集成到 MIR 传递流程中 - 移除独立的 frame_layout 实现文件 refactor(prolog-epilog): 添加函数序言/尾声传递框架 - 为 Windows x64 平台初始化序言/尾声生成器 - 在 MIR 传递阶段添加序言/尾声处理步骤 refactor(win64): 更新 Windows x64 目标平台接口 - 重命名寄存器分配填充函数为 scc_win_pc_x64_reg_alloc_fill - 添加栈帧分配和序言/尾声初始化函数 - 修正参数传递中的栈槽操作数类型 refactor(dump): 改进 MIR 输出格式 - 将基本块显示改为分支节点类型 - 更新操作数类型的显示处理 chore: 添加 x86 编码相关数据结构定义 - 新增 scc_x86_encode.h 头文件包含内存操作数和指令编码接口定义
This commit is contained in:
@@ -658,7 +658,7 @@ void scc_hir_dump_func_linear(scc_hir_dump_t *ctx, scc_hir_func_ref_t func_ref,
|
|||||||
scc_tree_dump_append(ctx->dump_ctx, "<invalid function>");
|
scc_tree_dump_append(ctx->dump_ctx, "<invalid function>");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
scc_tree_dump_append_fmt(ctx->dump_ctx, "func @%s",
|
scc_tree_dump_node(ctx->dump_ctx, "func @%s",
|
||||||
(func->name && func->name[0]) ? func->name
|
(func->name && func->name[0]) ? func->name
|
||||||
: "<unnamed>");
|
: "<unnamed>");
|
||||||
|
|
||||||
|
|||||||
@@ -3,10 +3,15 @@
|
|||||||
|
|
||||||
#include "../scc_mir_module.h"
|
#include "../scc_mir_module.h"
|
||||||
|
|
||||||
typedef struct scc_frame_layout {
|
struct scc_frame_layout;
|
||||||
scc_mir_func_t *func;
|
typedef struct scc_frame_layout scc_frame_layout_t;
|
||||||
} scc_frame_layout_t;
|
typedef void (*scc_frame_layout_impl_fn)(scc_frame_layout_t *ctx,
|
||||||
|
scc_mir_module_t *mir_module,
|
||||||
|
scc_mir_func_t *mir_func);
|
||||||
|
|
||||||
void scc_frame_layout(scc_frame_layout_t *ctx, scc_mir_module_t *module);
|
struct scc_frame_layout {
|
||||||
|
scc_frame_layout_impl_fn impl_fn;
|
||||||
|
int offset;
|
||||||
|
};
|
||||||
|
|
||||||
#endif /* __SCC_FRAME_LAYOUT_H__ */
|
#endif /* __SCC_FRAME_LAYOUT_H__ */
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
#ifndef __SCC_PROLOG_EPILOG_H__
|
#ifndef __SCC_PROLOG_EPILOG_H__
|
||||||
#define __SCC_PROLOG_EPILOG_H__
|
#define __SCC_PROLOG_EPILOG_H__
|
||||||
|
|
||||||
|
#include "../scc_mir_module.h"
|
||||||
#include <scc_lir_module.h>
|
#include <scc_lir_module.h>
|
||||||
#include <scc_mir_module.h>
|
|
||||||
typedef void (*scc_prolog_epilog_fn)(void *userdata,
|
typedef void (*scc_prolog_epilog_fn)(void *userdata,
|
||||||
const scc_mir_func_t *func);
|
const scc_mir_func_t *func);
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,8 @@
|
|||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
SCC_MIR_OP_NONE,
|
SCC_MIR_OP_NONE,
|
||||||
SCC_MIR_OP_MEM, // 内存访问
|
SCC_MIR_OP_STACK_OFFSET, // 已分配的内存
|
||||||
|
SCC_MIR_OP_STACK_SLOT, // 栈空间
|
||||||
SCC_MIR_OP_VREG, // 虚拟寄存器
|
SCC_MIR_OP_VREG, // 虚拟寄存器
|
||||||
SCC_MIR_OP_PREG, // 物理寄存器
|
SCC_MIR_OP_PREG, // 物理寄存器
|
||||||
SCC_MIR_OP_IMM, // 立即数
|
SCC_MIR_OP_IMM, // 立即数
|
||||||
@@ -23,6 +24,7 @@ typedef struct scc_mir_operand {
|
|||||||
i64 imm; // 立即数
|
i64 imm; // 立即数
|
||||||
const char *symbol; // 符号名
|
const char *symbol; // 符号名
|
||||||
int stack_slot; // 栈槽 ID (由 FrameLayout 分配)
|
int stack_slot; // 栈槽 ID (由 FrameLayout 分配)
|
||||||
|
int stack_offset; // 栈偏移
|
||||||
scc_lir_bblock_id_t block_id; // 目标基本块
|
scc_lir_bblock_id_t block_id; // 目标基本块
|
||||||
};
|
};
|
||||||
} scc_mir_operand_t;
|
} scc_mir_operand_t;
|
||||||
@@ -78,5 +80,10 @@ void scc_mir_vreg_op(const scc_mir_func_t *func, int vreg,
|
|||||||
|
|
||||||
void scc_mir_vreg_map2preg(scc_mir_func_t *func, int vreg, int preg);
|
void scc_mir_vreg_map2preg(scc_mir_func_t *func, int vreg, int preg);
|
||||||
int scc_mir_vreg_map2slot(scc_mir_func_t *func, int vreg, int size, int align);
|
int scc_mir_vreg_map2slot(scc_mir_func_t *func, int vreg, int size, int align);
|
||||||
|
static inline scc_mir_stack_slot_t *
|
||||||
|
scc_mir_unsafe_slot(const scc_mir_func_t *func, int slot) {
|
||||||
|
Assert(slot > 0);
|
||||||
|
return &scc_vec_at(SCC_MIR_FUNC_META(func)->stack_slots, slot);
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* __SCC_MIR_H__ */
|
#endif /* __SCC_MIR_H__ */
|
||||||
|
|||||||
@@ -2,8 +2,13 @@
|
|||||||
#define __SCC_WIN64_H__
|
#define __SCC_WIN64_H__
|
||||||
|
|
||||||
#include "../arch/x86_64_isel.h"
|
#include "../arch/x86_64_isel.h"
|
||||||
|
#include "../core_pass/scc_frame_layout.h"
|
||||||
|
#include "../core_pass/scc_prolog_epilog.h"
|
||||||
#include "../core_pass/scc_reg_alloc.h"
|
#include "../core_pass/scc_reg_alloc.h"
|
||||||
|
|
||||||
void scc_win_pc_x64_abi_lowering(scc_abi_lowering_t *abi_lowering);
|
void scc_win_pc_x64_abi_lowering(scc_abi_lowering_t *abi_lowering);
|
||||||
void scc_reg_alloc_fill_win_x64(scc_reg_alloc_op_t *ops);
|
void scc_win_pc_x64_reg_alloc_fill(scc_reg_alloc_op_t *ops);
|
||||||
|
void scc_win_pc_x64_frame_alloc_init(scc_frame_layout_t *ctx);
|
||||||
|
void scc_win_pc_x64_prolog_epilog_init(scc_prolog_epilog_t *ctx);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -36,9 +36,11 @@ void scc_x86_instr_dump(scc_tree_dump_t *td, const scc_mir_instr_t *instr) {
|
|||||||
case SCC_MIR_OP_SYMBOL:
|
case SCC_MIR_OP_SYMBOL:
|
||||||
scc_tree_dump_append_fmt(td, "@%s", op->symbol);
|
scc_tree_dump_append_fmt(td, "@%s", op->symbol);
|
||||||
break;
|
break;
|
||||||
case SCC_MIR_OP_MEM:
|
case SCC_MIR_OP_STACK_SLOT:
|
||||||
scc_tree_dump_append_fmt(td, "[%d]", op->stack_slot);
|
scc_tree_dump_append_fmt(td, "[%d]", op->stack_slot);
|
||||||
break;
|
break;
|
||||||
|
case SCC_MIR_OP_STACK_OFFSET:
|
||||||
|
scc_tree_dump_append_fmt(td, "[sp, %d]", op->stack_offset);
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -99,12 +101,12 @@ void scc_x86_emit_move(scc_x86_64_isel_t *isel, scc_mir_operand_t dst,
|
|||||||
dst, src);
|
dst, src);
|
||||||
} else if (src.kind == SCC_MIR_OP_SYMBOL) {
|
} else if (src.kind == SCC_MIR_OP_SYMBOL) {
|
||||||
add_instr_2(isel, SCC_X86_IFORM_MOV_GPRV_IMMZ, dst, src);
|
add_instr_2(isel, SCC_X86_IFORM_MOV_GPRV_IMMZ, dst, src);
|
||||||
} else if (src.kind == SCC_MIR_OP_MEM) {
|
} else if (src.kind == SCC_MIR_OP_STACK_SLOT) {
|
||||||
add_instr_2(isel, SCC_X86_IFORM_MOV_GPRV_MEMV, dst, src);
|
add_instr_2(isel, SCC_X86_IFORM_MOV_GPRV_MEMV, dst, src);
|
||||||
} else {
|
} else {
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
} else if (dst.kind == SCC_MIR_OP_MEM) {
|
} else if (dst.kind == SCC_MIR_OP_STACK_SLOT) {
|
||||||
if (src.kind == SCC_MIR_OP_VREG || src.kind == SCC_MIR_OP_PREG) {
|
if (src.kind == SCC_MIR_OP_VREG || src.kind == SCC_MIR_OP_PREG) {
|
||||||
add_instr_2(isel, SCC_X86_IFORM_MOV_MEMV_GPRV, dst, src);
|
add_instr_2(isel, SCC_X86_IFORM_MOV_MEMV_GPRV, dst, src);
|
||||||
} else if (src.kind == SCC_MIR_OP_IMM) {
|
} else if (src.kind == SCC_MIR_OP_IMM) {
|
||||||
@@ -113,7 +115,7 @@ void scc_x86_emit_move(scc_x86_64_isel_t *isel, scc_mir_operand_t dst,
|
|||||||
scc_mir_operand_t temp = new_vreg_temp(isel);
|
scc_mir_operand_t temp = new_vreg_temp(isel);
|
||||||
add_instr_2(isel, SCC_X86_IFORM_MOV_GPRV_IMMZ, temp, src);
|
add_instr_2(isel, SCC_X86_IFORM_MOV_GPRV_IMMZ, temp, src);
|
||||||
add_instr_2(isel, SCC_X86_IFORM_MOV_MEMV_GPRV, dst, temp);
|
add_instr_2(isel, SCC_X86_IFORM_MOV_MEMV_GPRV, dst, temp);
|
||||||
} else if (src.kind == SCC_MIR_OP_MEM) {
|
} else if (src.kind == SCC_MIR_OP_STACK_SLOT) {
|
||||||
scc_mir_operand_t temp = new_vreg_temp(isel);
|
scc_mir_operand_t temp = new_vreg_temp(isel);
|
||||||
scc_x86_emit_move(isel, temp, src, size);
|
scc_x86_emit_move(isel, temp, src, size);
|
||||||
scc_x86_emit_move(isel, dst, temp, size);
|
scc_x86_emit_move(isel, dst, temp, size);
|
||||||
@@ -209,7 +211,8 @@ static void emit_binary_op(scc_x86_64_isel_t *isel, scc_lir_op_t op,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static scc_mir_operand_t stack_slot_op(int offset) {
|
static scc_mir_operand_t stack_slot_op(int offset) {
|
||||||
return (scc_mir_operand_t){.kind = SCC_MIR_OP_MEM, .stack_slot = offset};
|
return (scc_mir_operand_t){.kind = SCC_MIR_OP_STACK_SLOT,
|
||||||
|
.stack_slot = offset};
|
||||||
}
|
}
|
||||||
|
|
||||||
static void emit_spill_load(scc_x86_64_isel_t *isel, int vreg, int offset) {
|
static void emit_spill_load(scc_x86_64_isel_t *isel, int vreg, int offset) {
|
||||||
@@ -281,6 +284,11 @@ static void sel_mir(scc_x86_64_isel_t *isel, const scc_lir_instr_t *instr) {
|
|||||||
case SCC_LIR_MUL:
|
case SCC_LIR_MUL:
|
||||||
// imul dst, src0, src1 → 需要 mov + imul
|
// imul dst, src0, src1 → 需要 mov + imul
|
||||||
emit_copy_if_needed(isel, dst, src0, size);
|
emit_copy_if_needed(isel, dst, src0, size);
|
||||||
|
if (src1.kind == SCC_MIR_OP_IMM) {
|
||||||
|
scc_mir_operand_t op = new_vreg_temp(isel);
|
||||||
|
scc_x86_emit_move(isel, op, src1, size);
|
||||||
|
src1 = op;
|
||||||
|
}
|
||||||
add_instr_2(isel, SCC_X86_IFORM_IMUL_GPRV_GPRV, dst, src1);
|
add_instr_2(isel, SCC_X86_IFORM_IMUL_GPRV_GPRV, dst, src1);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -421,6 +429,8 @@ static void sel_mir(scc_x86_64_isel_t *isel, const scc_lir_instr_t *instr) {
|
|||||||
.imm = instr->size,
|
.imm = instr->size,
|
||||||
});
|
});
|
||||||
Assert(op.kind == SCC_MIR_OP_VREG);
|
Assert(op.kind == SCC_MIR_OP_VREG);
|
||||||
|
// FIXME
|
||||||
|
scc_mir_vreg_map2slot(isel->func, op.vreg, instr->size, 8);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* ---- 其他(占位) ---- */
|
/* ---- 其他(占位) ---- */
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ static void x86_emit_spill(scc_mir_instr_vec_t *ctx, int preg, int slot) {
|
|||||||
scc_mir_instr_t ins = {
|
scc_mir_instr_t ins = {
|
||||||
.opcode = SCC_X86_IFORM_MOV_MEMV_GPRV,
|
.opcode = SCC_X86_IFORM_MOV_MEMV_GPRV,
|
||||||
.num_operands = 2,
|
.num_operands = 2,
|
||||||
.operands = {{.kind = SCC_MIR_OP_MEM, .stack_slot = slot},
|
.operands = {{.kind = SCC_MIR_OP_STACK_SLOT, .stack_slot = slot},
|
||||||
{.kind = SCC_MIR_OP_PREG, .preg = preg}}};
|
{.kind = SCC_MIR_OP_PREG, .preg = preg}}};
|
||||||
scc_vec_push(*ctx, ins);
|
scc_vec_push(*ctx, ins);
|
||||||
}
|
}
|
||||||
@@ -15,7 +15,7 @@ static void x86_emit_reload(scc_mir_instr_vec_t *ctx, int preg, int slot) {
|
|||||||
.opcode = SCC_X86_IFORM_MOV_GPRV_MEMV,
|
.opcode = SCC_X86_IFORM_MOV_GPRV_MEMV,
|
||||||
.num_operands = 2,
|
.num_operands = 2,
|
||||||
.operands = {{.kind = SCC_MIR_OP_PREG, .preg = preg},
|
.operands = {{.kind = SCC_MIR_OP_PREG, .preg = preg},
|
||||||
{.kind = SCC_MIR_OP_MEM, .stack_slot = slot}}};
|
{.kind = SCC_MIR_OP_STACK_SLOT, .stack_slot = slot}}};
|
||||||
scc_vec_push(*ctx, ins);
|
scc_vec_push(*ctx, ins);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
#include <core_pass/scc_frame_layout.h>
|
|
||||||
|
|
||||||
void scc_frame_layout(scc_frame_layout_t *ctx, scc_mir_module_t *module) {}
|
|
||||||
@@ -118,7 +118,7 @@ static void alloc_instr(scc_reg_alloc_ctx_t *ctx,
|
|||||||
slot = scc_mir_vreg_map2slot(ctx->func, vreg, 8, 8);
|
slot = scc_mir_vreg_map2slot(ctx->func, vreg, 8, 8);
|
||||||
} else {
|
} else {
|
||||||
// 已经是 MEM,直接用它的 slot
|
// 已经是 MEM,直接用它的 slot
|
||||||
Assert(op->kind == SCC_MIR_OP_MEM);
|
Assert(op->kind == SCC_MIR_OP_STACK_SLOT);
|
||||||
slot = op->stack_slot;
|
slot = op->stack_slot;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -192,6 +192,11 @@ static void alloc_bb(scc_reg_alloc_ctx_t *ctx, scc_mir_module_t *module,
|
|||||||
|
|
||||||
scc_vec_foreach(*old_instrs, i) {
|
scc_vec_foreach(*old_instrs, i) {
|
||||||
scc_mir_instr_t ins = scc_vec_at(*old_instrs, i);
|
scc_mir_instr_t ins = scc_vec_at(*old_instrs, i);
|
||||||
|
if (ins.opcode == SCC_MIR_PSUEDO_ALLOCA) {
|
||||||
|
scc_mir_vreg_op(ctx->func, ins.operands[0].vreg, &ins.operands[0]);
|
||||||
|
scc_vec_push(new_instrs, ins);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
alloc_instr(ctx, &new_instrs, &ins);
|
alloc_instr(ctx, &new_instrs, &ins);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ void scc_mir_vreg_op(const scc_mir_func_t *func, int vreg,
|
|||||||
out->kind = SCC_MIR_OP_PREG;
|
out->kind = SCC_MIR_OP_PREG;
|
||||||
out->preg = (int)-idx;
|
out->preg = (int)-idx;
|
||||||
} else {
|
} else {
|
||||||
out->kind = SCC_MIR_OP_MEM;
|
out->kind = SCC_MIR_OP_STACK_SLOT;
|
||||||
Assert(idx < scc_vec_size(meta->stack_slots));
|
Assert(idx < scc_vec_size(meta->stack_slots));
|
||||||
out->stack_slot = (int)(usize)idx;
|
out->stack_slot = (int)(usize)idx;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ void scc_mir_dump_instr(scc_mir_dump_ctx_t *ctx, const scc_mir_instr_t *ins) {
|
|||||||
scc_tree_dump_append_fmt(td, "(%d)", ins->operands[1].imm);
|
scc_tree_dump_append_fmt(td, "(%d)", ins->operands[1].imm);
|
||||||
if (ins->operands[0].kind == SCC_MIR_OP_VREG) {
|
if (ins->operands[0].kind == SCC_MIR_OP_VREG) {
|
||||||
scc_tree_dump_append_fmt(td, " %%%d", ins->operands[0].vreg);
|
scc_tree_dump_append_fmt(td, " %%%d", ins->operands[0].vreg);
|
||||||
} else if (ins->operands[0].kind == SCC_MIR_OP_MEM) {
|
} else if (ins->operands[0].kind == SCC_MIR_OP_STACK_SLOT) {
|
||||||
scc_tree_dump_append_fmt(td, " [%d]", ins->operands[0].stack_slot);
|
scc_tree_dump_append_fmt(td, " [%d]", ins->operands[0].stack_slot);
|
||||||
} else {
|
} else {
|
||||||
scc_tree_dump_append(td, "<alloced>");
|
scc_tree_dump_append(td, "<alloced>");
|
||||||
@@ -33,7 +33,7 @@ void scc_mir_dump_bblock(scc_mir_dump_ctx_t *ctx, const scc_mir_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_branch(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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,27 +1,78 @@
|
|||||||
#include <arch/x86_64_reg_alloc.h>
|
#include <arch/x86_64_reg_alloc.h>
|
||||||
#include <target/scc_win64.h>
|
#include <target/scc_win64.h>
|
||||||
|
|
||||||
#include <core_pass/scc_frame_layout.h>
|
// #include <core_pass/scc_frame_layout.h>
|
||||||
#include <core_pass/scc_reg_alloc.h>
|
// #include <core_pass/scc_prolog_epilog.h>
|
||||||
|
// #include <core_pass/scc_reg_alloc.h>
|
||||||
|
|
||||||
#include <scc_mir_module.h>
|
#include <scc_mir_module.h>
|
||||||
#include <scc_mir_pass.h>
|
#include <scc_mir_pass.h>
|
||||||
|
|
||||||
|
void scc_frame_layout(scc_frame_layout_t *ctx, scc_mir_module_t *module) {
|
||||||
|
Assert(ctx && ctx->impl_fn && module);
|
||||||
|
scc_vec_foreach(module->cfg_module.funcs, i) {
|
||||||
|
if (i == 0)
|
||||||
|
continue;
|
||||||
|
ctx->impl_fn(ctx, module, &scc_vec_at(module->cfg_module.funcs, i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void scc_prolog_epilog(scc_prolog_epilog_t *ctx, scc_mir_module_t *module) {
|
||||||
|
Assert(ctx && ctx->epilog && ctx->prolog && module);
|
||||||
|
scc_vec_foreach(module->cfg_module.funcs, i) {
|
||||||
|
if (i == 0)
|
||||||
|
continue;
|
||||||
|
scc_mir_func_t *func = &scc_vec_at(module->cfg_module.funcs, i);
|
||||||
|
scc_vec_foreach(func->bblocks, i) {
|
||||||
|
scc_cfg_bblock_id_t bb_id = scc_vec_at(func->bblocks, i);
|
||||||
|
scc_cfg_bblock_t *bb =
|
||||||
|
scc_cfg_module_unsafe_get_bblock(&module->cfg_module, bb_id);
|
||||||
|
Assert(bb != nullptr);
|
||||||
|
scc_mir_instr_vec_t *old_instrs = SCC_MIR_BBLOCK_VALUES(bb);
|
||||||
|
scc_mir_instr_vec_t new_instrs;
|
||||||
|
scc_vec_init(new_instrs);
|
||||||
|
|
||||||
|
if (i == 0) {
|
||||||
|
|
||||||
|
} else if (i == scc_vec_size(func->bblocks) - 1) {
|
||||||
|
// FIXME epilog it maybe used in ret instr
|
||||||
|
}
|
||||||
|
|
||||||
|
scc_vec_foreach(*old_instrs, i) {
|
||||||
|
scc_mir_instr_t ins = scc_vec_at(*old_instrs, i);
|
||||||
|
if (ins.opcode == SCC_MIR_PSUEDO_ALLOCA) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
scc_vec_push(new_instrs, ins);
|
||||||
|
}
|
||||||
|
|
||||||
|
scc_vec_free(*old_instrs);
|
||||||
|
*old_instrs = new_instrs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void scc_mir_pass(scc_mir_module_t *mir_module, scc_mir_pass_stage_t stage) {
|
void scc_mir_pass(scc_mir_module_t *mir_module, scc_mir_pass_stage_t stage) {
|
||||||
scc_reg_alloc_ctx_t reg_alloc_ctx = {
|
scc_reg_alloc_ctx_t reg_alloc_ctx = {
|
||||||
.func = nullptr, .instrs = nullptr, .ops = {0}};
|
.func = nullptr, .instrs = nullptr, .ops = {0}};
|
||||||
scc_reg_alloc_fill_arch_x86(®_alloc_ctx.ops);
|
scc_reg_alloc_fill_arch_x86(®_alloc_ctx.ops);
|
||||||
scc_reg_alloc_fill_win_x64(®_alloc_ctx.ops);
|
scc_win_pc_x64_reg_alloc_fill(®_alloc_ctx.ops);
|
||||||
|
|
||||||
scc_reg_alloc(®_alloc_ctx, mir_module);
|
scc_reg_alloc(®_alloc_ctx, mir_module);
|
||||||
if (stage == SCC_MIR_STAGE_REGALLOC) {
|
if (stage == SCC_MIR_STAGE_REGALLOC) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
scc_frame_layout_t frame_layout_ctx = {0};
|
||||||
|
scc_win_pc_x64_frame_alloc_init(&frame_layout_ctx);
|
||||||
|
scc_frame_layout(&frame_layout_ctx, mir_module);
|
||||||
if (stage == SCC_MIR_STAGE_FRAME_LAYOUT) {
|
if (stage == SCC_MIR_STAGE_FRAME_LAYOUT) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
scc_prolog_epilog_t prolog_epilog_ctx = {0};
|
||||||
|
scc_win_pc_x64_prolog_epilog_init(&prolog_epilog_ctx);
|
||||||
|
scc_prolog_epilog(&prolog_epilog_ctx, mir_module);
|
||||||
if (stage == SCC_MIR_STAGE_PROLOGUE_EPILOGUE) {
|
if (stage == SCC_MIR_STAGE_PROLOGUE_EPILOGUE) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,30 +2,23 @@
|
|||||||
#include <x86/scc_x86_iform.h>
|
#include <x86/scc_x86_iform.h>
|
||||||
|
|
||||||
#include <arch/x86_64_isel.h>
|
#include <arch/x86_64_isel.h>
|
||||||
#include <core_pass/scc_abi_lowering.h>
|
|
||||||
#include <core_pass/scc_prolog_epilog.h>
|
#include <core_pass/scc_prolog_epilog.h>
|
||||||
#include <target/scc_win64.h>
|
#include <target/scc_win64.h>
|
||||||
|
|
||||||
static const int WIN64_DEFAULT_ALIGN = 8;
|
static const int WIN64_DEFAULT_ALIGN = 8;
|
||||||
static const int WIN64_STACK_ALIGN = 16;
|
static const int WIN64_STACK_ALIGN = 16;
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
scc_hashtable_t *vreg2slot;
|
|
||||||
int offset;
|
|
||||||
} frame_layout_ctx_t;
|
|
||||||
|
|
||||||
static void transit_vreg(scc_mir_func_meta_t *func, scc_mir_operand_t *op) {
|
static void transit_vreg(scc_mir_func_meta_t *func, scc_mir_operand_t *op) {
|
||||||
Assert(op->kind == SCC_MIR_OP_VREG);
|
Assert(op->kind == SCC_MIR_OP_VREG);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void frame_alloc_impl(frame_layout_ctx_t *ctx,
|
static void frame_alloc_impl(scc_frame_layout_t *ctx,
|
||||||
scc_mir_module_t *mir_module,
|
scc_mir_module_t *mir_module,
|
||||||
scc_mir_func_t *mir_func) {
|
scc_mir_func_t *mir_func) {
|
||||||
/*
|
/*
|
||||||
WIN ABI
|
WIN ABI
|
||||||
*/
|
*/
|
||||||
ctx->offset = 8; // called ret address
|
ctx->offset = 8;
|
||||||
|
|
||||||
scc_mir_func_meta_t *func_meta = SCC_MIR_FUNC_META(mir_func);
|
scc_mir_func_meta_t *func_meta = SCC_MIR_FUNC_META(mir_func);
|
||||||
scc_vec_foreach(mir_func->bblocks, i) {
|
scc_vec_foreach(mir_func->bblocks, i) {
|
||||||
scc_cfg_bblock_id_t id = scc_vec_at(mir_func->bblocks, i);
|
scc_cfg_bblock_id_t id = scc_vec_at(mir_func->bblocks, i);
|
||||||
@@ -35,8 +28,19 @@ static void frame_alloc_impl(frame_layout_ctx_t *ctx,
|
|||||||
scc_vec_foreach(*instrs, j) {
|
scc_vec_foreach(*instrs, j) {
|
||||||
scc_mir_instr_t *ins = &scc_vec_at(*instrs, j);
|
scc_mir_instr_t *ins = &scc_vec_at(*instrs, j);
|
||||||
for (int k = 0; k < ins->num_operands; k += 1) {
|
for (int k = 0; k < ins->num_operands; k += 1) {
|
||||||
if (ins->operands[k].kind == SCC_MIR_OP_VREG) {
|
scc_mir_operand_t *op = &ins->operands[k];
|
||||||
transit_vreg(func_meta, &ins->operands[k]);
|
if (op->kind == SCC_MIR_OP_VREG) {
|
||||||
|
Panic("vreg not supported in frame layout");
|
||||||
|
} else if (op->kind == SCC_MIR_OP_STACK_SLOT) {
|
||||||
|
scc_mir_stack_slot_t *slot =
|
||||||
|
scc_mir_unsafe_slot(mir_func, op->stack_slot);
|
||||||
|
op->kind = SCC_MIR_OP_STACK_OFFSET;
|
||||||
|
if (slot->offset == 0) {
|
||||||
|
// FIXME align
|
||||||
|
ctx->offset += slot->size;
|
||||||
|
slot->offset = ctx->offset;
|
||||||
|
}
|
||||||
|
op->stack_offset = slot->offset;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -47,6 +51,11 @@ static void frame_alloc_impl(frame_layout_ctx_t *ctx,
|
|||||||
// 16 字节栈对齐
|
// 16 字节栈对齐
|
||||||
ctx->offset =
|
ctx->offset =
|
||||||
(total_size + WIN64_STACK_ALIGN - 1) & ~(WIN64_STACK_ALIGN - 1);
|
(total_size + WIN64_STACK_ALIGN - 1) & ~(WIN64_STACK_ALIGN - 1);
|
||||||
|
func_meta->frame_size = ctx->offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
void scc_win_pc_x64_frame_alloc_init(scc_frame_layout_t *ctx) {
|
||||||
|
ctx->impl_fn = frame_alloc_impl;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -99,6 +108,11 @@ static void epilogue(void *userdata, const scc_mir_func_t *func) {
|
|||||||
add_instr_1(isel, SCC_X86_IFORM_POP_GPRV_58, reg_operand(SCC_X86_REG_RBP));
|
add_instr_1(isel, SCC_X86_IFORM_POP_GPRV_58, reg_operand(SCC_X86_REG_RBP));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void scc_win_pc_x64_prolog_epilog_init(scc_prolog_epilog_t *ctx) {
|
||||||
|
ctx->prolog = prologue;
|
||||||
|
ctx->epilog = epilogue;
|
||||||
|
}
|
||||||
|
|
||||||
static void lower_call(void *userdata, const scc_lir_instr_t *instr) {
|
static void lower_call(void *userdata, const scc_lir_instr_t *instr) {
|
||||||
scc_x86_64_isel_t *isel = userdata;
|
scc_x86_64_isel_t *isel = userdata;
|
||||||
/*
|
/*
|
||||||
@@ -174,7 +188,7 @@ static scc_mir_operand_t lower_param(void *userdata, const scc_lir_val_t *val) {
|
|||||||
case 3:
|
case 3:
|
||||||
return reg_operand(SCC_X86_REG_R9);
|
return reg_operand(SCC_X86_REG_R9);
|
||||||
default:
|
default:
|
||||||
return (scc_mir_operand_t){.kind = SCC_MIR_OP_MEM,
|
return (scc_mir_operand_t){.kind = SCC_MIR_OP_STACK_SLOT,
|
||||||
.stack_slot = -val->data.arg};
|
.stack_slot = -val->data.arg};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -231,14 +245,9 @@ static void mark_reg_used(void *ctx, int preg) {
|
|||||||
}
|
}
|
||||||
static void clean_mark_regs(void *ctx) { reg_mask = 0; }
|
static void clean_mark_regs(void *ctx) { reg_mask = 0; }
|
||||||
|
|
||||||
void scc_reg_alloc_fill_win_x64(scc_reg_alloc_op_t *ops) {
|
void scc_win_pc_x64_reg_alloc_fill(scc_reg_alloc_op_t *ops) {
|
||||||
ops->acquire_reg = acquire_reg;
|
ops->acquire_reg = acquire_reg;
|
||||||
ops->release_reg = release_reg;
|
ops->release_reg = release_reg;
|
||||||
ops->mark_reg_used = mark_reg_used;
|
ops->mark_reg_used = mark_reg_used;
|
||||||
ops->clean_mark_regs = clean_mark_regs;
|
ops->clean_mark_regs = clean_mark_regs;
|
||||||
}
|
}
|
||||||
|
|
||||||
void scc_win_pc_x64_prolog_epilog(scc_prolog_epilog_t *prolog_epilog) {
|
|
||||||
prolog_epilog->prolog = prologue;
|
|
||||||
prolog_epilog->epilog = epilogue;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -17,9 +17,17 @@ void mir_x86_to_mcode(scc_mcode_t *mcode, const scc_mir_instr_t *ins) {
|
|||||||
ops[i].kind = SCC_X86_OPR_REG;
|
ops[i].kind = SCC_X86_OPR_REG;
|
||||||
ops[i].reg = ins->operands[i].preg;
|
ops[i].reg = ins->operands[i].preg;
|
||||||
break;
|
break;
|
||||||
case SCC_MIR_OP_MEM:
|
case SCC_MIR_OP_STACK_SLOT:
|
||||||
Panic("can't convert mem to mcode");
|
Panic("can't convert mem to mcode");
|
||||||
break;
|
break;
|
||||||
|
case SCC_MIR_OP_STACK_OFFSET:
|
||||||
|
// TODO
|
||||||
|
ops[i].kind = SCC_X86_OPR_MEM;
|
||||||
|
ops[i].mem.base = SCC_X86_REG_RSP;
|
||||||
|
ops[i].mem.index = SCC_X86_REG_INVALID;
|
||||||
|
ops[i].mem.scale = 1;
|
||||||
|
ops[i].mem.disp = -ins->operands[i].stack_offset; // 注意符号
|
||||||
|
break;
|
||||||
case SCC_MIR_OP_IMM:
|
case SCC_MIR_OP_IMM:
|
||||||
ops[i].kind = SCC_X86_OPR_IMM;
|
ops[i].kind = SCC_X86_OPR_IMM;
|
||||||
ops[i].imm = ins->operands[i].imm;
|
ops[i].imm = ins->operands[i].imm;
|
||||||
|
|||||||
@@ -5,12 +5,15 @@ static inline void scc_ir_sym_to_sccf_sym(const scc_cfg_symbol_t *symbol,
|
|||||||
switch (symbol->kind) {
|
switch (symbol->kind) {
|
||||||
case SCC_CFG_SYMBOL_KIND_DATA:
|
case SCC_CFG_SYMBOL_KIND_DATA:
|
||||||
sym->sccf_sym_type = SCCF_SYM_TYPE_DATA;
|
sym->sccf_sym_type = SCCF_SYM_TYPE_DATA;
|
||||||
|
sym->sccf_sect_type = SCCF_SECT_DATA;
|
||||||
break;
|
break;
|
||||||
case SCC_CFG_SYMBOL_KIND_FUNC:
|
case SCC_CFG_SYMBOL_KIND_FUNC:
|
||||||
sym->sccf_sym_type = SCCF_SYM_TYPE_FUNC;
|
sym->sccf_sym_type = SCCF_SYM_TYPE_FUNC;
|
||||||
|
sym->sccf_sect_type = SCCF_SECT_CODE;
|
||||||
break;
|
break;
|
||||||
case SCC_CFG_SYMBOL_KIND_EXTERN:
|
case SCC_CFG_SYMBOL_KIND_EXTERN:
|
||||||
sym->sccf_sym_type = SCCF_SYM_TYPE_EXTERN;
|
sym->sccf_sym_type = SCCF_SYM_TYPE_EXTERN;
|
||||||
|
sym->sccf_sect_type = SCCF_SECT_NONE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,6 +45,11 @@ void scc_ir2sccf(sccf_builder_t *builder, scc_mir_module_t *mir_module) {
|
|||||||
scc_vec_init(sect_data);
|
scc_vec_init(sect_data);
|
||||||
|
|
||||||
scc_vec_foreach(mir_module->cfg_module.symbols, i) {
|
scc_vec_foreach(mir_module->cfg_module.symbols, i) {
|
||||||
|
if (i == 0) {
|
||||||
|
// FIXME
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
scc_cfg_symbol_t *symbol =
|
scc_cfg_symbol_t *symbol =
|
||||||
&scc_vec_at(mir_module->cfg_module.symbols, i);
|
&scc_vec_at(mir_module->cfg_module.symbols, i);
|
||||||
|
|
||||||
|
|||||||
28
libs/mcode/include/x86/scc_x86_encode.h
Normal file
28
libs/mcode/include/x86/scc_x86_encode.h
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
#ifndef __SCC_X86_ENCODE_H__
|
||||||
|
#define __SCC_X86_ENCODE_H__
|
||||||
|
|
||||||
|
#include "../scc_mcode.h"
|
||||||
|
#include "scc_x86_iform.h"
|
||||||
|
#include "scc_x86_reg.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
scc_x86_reg_t base;
|
||||||
|
scc_x86_reg_t index;
|
||||||
|
u8 scale; /* 1,2,4,8 */
|
||||||
|
i32 disp;
|
||||||
|
} scc_x86_mem_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
scc_x86_operand_kind_t kind;
|
||||||
|
union {
|
||||||
|
scc_x86_reg_t reg;
|
||||||
|
i64 imm;
|
||||||
|
scc_x86_mem_t mem;
|
||||||
|
};
|
||||||
|
} scc_x86_operand_value_t;
|
||||||
|
|
||||||
|
/* 按 iform 发射一条指令,ops 数组长度需与 iform 定义的操作数数目一致 */
|
||||||
|
int scc_x86_encode_inst(scc_mcode_t *mcode, scc_x86_iform_t iform,
|
||||||
|
const scc_x86_operand_value_t *ops);
|
||||||
|
|
||||||
|
#endif /* __SCC_X86_ENCODE_H__ */
|
||||||
449
libs/mcode/src/scc_x86_encode.c
Normal file
449
libs/mcode/src/scc_x86_encode.c
Normal file
@@ -0,0 +1,449 @@
|
|||||||
|
#include <assert.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <x86/scc_x86_encode.h>
|
||||||
|
#include <x86/scc_x86_iform.h>
|
||||||
|
#include <x86/scc_x86_reg.h>
|
||||||
|
|
||||||
|
/* ---------- 内部辅助 ---------- */
|
||||||
|
static inline void emit_u8(scc_mcode_t *m, uint8_t v) {
|
||||||
|
scc_mcode_add_u8(m, v);
|
||||||
|
}
|
||||||
|
static inline void emit_u16(scc_mcode_t *m, uint16_t v) {
|
||||||
|
scc_mcode_add_u16(m, v);
|
||||||
|
}
|
||||||
|
static inline void emit_u32(scc_mcode_t *m, uint32_t v) {
|
||||||
|
scc_mcode_add_u32(m, v);
|
||||||
|
}
|
||||||
|
static inline void emit_u64(scc_mcode_t *m, uint64_t v) {
|
||||||
|
scc_mcode_add_u64(m, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------- 寄存器查询 ---------- */
|
||||||
|
static inline uint16_t scc_reg_width(scc_x86_reg_t reg) {
|
||||||
|
if (reg >= SCC_X86_REG_COUNT || reg == SCC_X86_REG_INVALID)
|
||||||
|
return 0;
|
||||||
|
return scc_x86_reg_table[reg].width;
|
||||||
|
}
|
||||||
|
static inline int scc_reg_ordinal(scc_x86_reg_t reg) {
|
||||||
|
if (reg >= SCC_X86_REG_COUNT || reg == SCC_X86_REG_INVALID)
|
||||||
|
return 0;
|
||||||
|
return scc_x86_reg_table[reg].ordinal;
|
||||||
|
}
|
||||||
|
static int reg_low3(scc_x86_reg_t reg) {
|
||||||
|
if (reg == SCC_X86_REG_INVALID)
|
||||||
|
return 0;
|
||||||
|
return scc_reg_ordinal(reg) & 7;
|
||||||
|
}
|
||||||
|
static int reg_rex_bit(scc_x86_reg_t reg) {
|
||||||
|
if (reg == SCC_X86_REG_INVALID)
|
||||||
|
return 0;
|
||||||
|
if (reg >= SCC_X86_REG_AH && reg <= SCC_X86_REG_DH)
|
||||||
|
return 0;
|
||||||
|
return (scc_reg_ordinal(reg) >= 8) ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------- 操作数宽度推导 ---------- */
|
||||||
|
static int infer_operand_width(const scc_x86_iform_info_t *info,
|
||||||
|
const scc_x86_operand_value_t ops[]) {
|
||||||
|
for (int i = 0; i < info->num_explicit_ops; i++) {
|
||||||
|
if (ops[i].kind == SCC_X86_OPR_REG && !info->ops[i].is_implicit) {
|
||||||
|
uint16_t w = scc_reg_width(ops[i].reg);
|
||||||
|
if (w > 0)
|
||||||
|
return w;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const char *eosz = info->encode.eosz;
|
||||||
|
int default_64 = info->encode.default_64b;
|
||||||
|
if (!strcmp(eosz, "o16"))
|
||||||
|
return 16;
|
||||||
|
if (!strcmp(eosz, "o32"))
|
||||||
|
return 32;
|
||||||
|
if (!strcmp(eosz, "o64"))
|
||||||
|
return 64;
|
||||||
|
if (!strcmp(eosz, "oszall") || !strcmp(eosz, "osznot16"))
|
||||||
|
return default_64 ? 64 : 32;
|
||||||
|
return 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------- 前缀决策 ---------- */
|
||||||
|
static int need_rexw(const scc_x86_encoding_t *enc, scc_x86_reg_t reg_op,
|
||||||
|
scc_x86_reg_t rm_op, scc_x86_reg_t base,
|
||||||
|
scc_x86_reg_t idx) {
|
||||||
|
/* 强制要求 / 明确禁止 优先级最高 */
|
||||||
|
if (enc->rex_w == 1)
|
||||||
|
return 1;
|
||||||
|
if (enc->rex_w == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* 指令已隐含 64 位语义(如 PUSH/POP),但仍可能被 64 位操作数需要 W?例如
|
||||||
|
* PUSH r64 不需要 W,但 PUSH r/m64 也不需要。总之 default_64b
|
||||||
|
* 时一般无需额外 W,但若操作数明确是 64 位且模板没有禁止,我们仍加上以兼容
|
||||||
|
* movabs 等 */
|
||||||
|
int has_64bit_op = 0;
|
||||||
|
if (reg_op != SCC_X86_REG_INVALID && scc_reg_width(reg_op) == 64)
|
||||||
|
has_64bit_op = 1;
|
||||||
|
if (rm_op != SCC_X86_REG_INVALID && scc_reg_width(rm_op) == 64)
|
||||||
|
has_64bit_op = 1;
|
||||||
|
if (base != SCC_X86_REG_INVALID && scc_reg_width(base) == 64)
|
||||||
|
has_64bit_op = 1;
|
||||||
|
if (idx != SCC_X86_REG_INVALID && scc_reg_width(idx) == 64)
|
||||||
|
has_64bit_op = 1;
|
||||||
|
|
||||||
|
if (enc->default_64b) {
|
||||||
|
/* 对于默认 64 位的指令(如 CALL, JMP),有些仍需要 REX.W
|
||||||
|
* 访问扩展寄存器,但若 reg/rm 本身是 64 位且需要 REX.B/R 则一并设置 W
|
||||||
|
* 来保证编码正确?这里简单处理:只要访问扩展寄存器就加 W */
|
||||||
|
return (reg_op != SCC_X86_REG_INVALID && reg_rex_bit(reg_op)) ||
|
||||||
|
(rm_op != SCC_X86_REG_INVALID && reg_rex_bit(rm_op)) ||
|
||||||
|
(base != SCC_X86_REG_INVALID && reg_rex_bit(base)) ||
|
||||||
|
(idx != SCC_X86_REG_INVALID && reg_rex_bit(idx))
|
||||||
|
? 1
|
||||||
|
: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 普通指令:有 64 位操作数即加 W */
|
||||||
|
return has_64bit_op;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int need_66_prefix(const scc_x86_encoding_t *enc, scc_x86_reg_t reg_op,
|
||||||
|
scc_x86_reg_t rm_op) {
|
||||||
|
if (enc->osz_required)
|
||||||
|
return 1;
|
||||||
|
// 如果强制指定了操作大小,不自动加66
|
||||||
|
if (!strcmp(enc->eosz, "o32") || !strcmp(enc->eosz, "o64"))
|
||||||
|
return 0;
|
||||||
|
if (reg_op != SCC_X86_REG_INVALID && scc_reg_width(reg_op) == 16)
|
||||||
|
return 1;
|
||||||
|
if (rm_op != SCC_X86_REG_INVALID && scc_reg_width(rm_op) == 16)
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
static int need_67_prefix(const scc_x86_encoding_t *enc, scc_x86_reg_t base,
|
||||||
|
scc_x86_reg_t idx) {
|
||||||
|
(void)enc;
|
||||||
|
(void)base;
|
||||||
|
(void)idx;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void emit_legacy_prefixes(scc_mcode_t *m, const scc_x86_encoding_t *enc,
|
||||||
|
scc_x86_reg_t reg_op, scc_x86_reg_t rm_op,
|
||||||
|
scc_x86_reg_t base, scc_x86_reg_t idx) {
|
||||||
|
if (enc->has_lock)
|
||||||
|
emit_u8(m, 0xF0);
|
||||||
|
if (enc->f2_required)
|
||||||
|
emit_u8(m, 0xF2);
|
||||||
|
if (enc->f3_required)
|
||||||
|
emit_u8(m, 0xF3);
|
||||||
|
if (need_66_prefix(enc, reg_op, rm_op))
|
||||||
|
emit_u8(m, 0x66);
|
||||||
|
if (need_67_prefix(enc, base, idx))
|
||||||
|
emit_u8(m, 0x67);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void emit_rex(scc_mcode_t *m, const scc_x86_encoding_t *enc,
|
||||||
|
scc_x86_reg_t reg_op, scc_x86_reg_t rm_op,
|
||||||
|
scc_x86_reg_t base, scc_x86_reg_t idx) {
|
||||||
|
int rex = 0x40;
|
||||||
|
if (need_rexw(enc, reg_op, rm_op, base, idx))
|
||||||
|
rex |= 8;
|
||||||
|
if (reg_op != SCC_X86_REG_INVALID && reg_rex_bit(reg_op))
|
||||||
|
rex |= 4;
|
||||||
|
if (idx != SCC_X86_REG_INVALID && reg_rex_bit(idx))
|
||||||
|
rex |= 2;
|
||||||
|
scc_x86_reg_t b = (rm_op != SCC_X86_REG_INVALID) ? rm_op : base;
|
||||||
|
if (b != SCC_X86_REG_INVALID && reg_rex_bit(b))
|
||||||
|
rex |= 1;
|
||||||
|
if (rex != 0x40) {
|
||||||
|
LOG_INFO("[REX] emit 0x%02x", (uint8_t)rex);
|
||||||
|
emit_u8(m, (uint8_t)rex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void emit_escape_map(scc_mcode_t *m, const scc_x86_encoding_t *enc) {
|
||||||
|
if (enc->map == 1) {
|
||||||
|
emit_u8(m, 0x0F);
|
||||||
|
} else if (enc->map == 2) {
|
||||||
|
emit_u8(m, 0x0F);
|
||||||
|
emit_u8(m, 0x38);
|
||||||
|
} else if (enc->map == 3) {
|
||||||
|
emit_u8(m, 0x0F);
|
||||||
|
emit_u8(m, 0x3A);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void emit_opcode(scc_mcode_t *m, const scc_x86_encoding_t *enc,
|
||||||
|
scc_x86_reg_t rm_reg, scc_x86_reg_t base_reg) {
|
||||||
|
for (int i = 0; i < enc->opcode_len; i++) {
|
||||||
|
uint8_t byte = enc->opcode[i];
|
||||||
|
if (enc->partial_opcode && i == enc->opcode_len - 1) {
|
||||||
|
scc_x86_reg_t target =
|
||||||
|
(rm_reg != SCC_X86_REG_INVALID) ? rm_reg : base_reg;
|
||||||
|
if (target != SCC_X86_REG_INVALID)
|
||||||
|
byte |= (reg_low3(target) & 7);
|
||||||
|
}
|
||||||
|
emit_u8(m, byte);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int scale_to_enc(uint8_t scale) {
|
||||||
|
switch (scale) {
|
||||||
|
case 1:
|
||||||
|
return 0;
|
||||||
|
case 2:
|
||||||
|
return 1;
|
||||||
|
case 4:
|
||||||
|
return 2;
|
||||||
|
case 8:
|
||||||
|
return 3;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int disp_size(int32_t disp, scc_x86_reg_t base) {
|
||||||
|
if (disp == 0 && base != SCC_X86_REG_RBP && base != SCC_X86_REG_R13)
|
||||||
|
return 0;
|
||||||
|
if (disp >= -128 && disp <= 127)
|
||||||
|
return 8;
|
||||||
|
return 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------- 立即数发射(独立函数) ---------- */
|
||||||
|
static void emit_immediate(scc_mcode_t *m, const scc_x86_encoding_t *enc,
|
||||||
|
const scc_x86_operand_t *tmpl, int imm_idx,
|
||||||
|
int64_t imm_val, int op_width) {
|
||||||
|
const char *oc2 = tmpl[imm_idx].oc2;
|
||||||
|
int imm_size = enc->imm_size;
|
||||||
|
if (!strcmp(oc2, "b"))
|
||||||
|
imm_size = 1;
|
||||||
|
else if (!strcmp(oc2, "w"))
|
||||||
|
imm_size = 2;
|
||||||
|
else if (!strcmp(oc2, "z"))
|
||||||
|
imm_size = (op_width <= 16) ? op_width / 8 : (op_width <= 32 ? 4 : 4);
|
||||||
|
else if (!strcmp(oc2, "v"))
|
||||||
|
imm_size = op_width / 8;
|
||||||
|
else if (!strcmp(oc2, "d") || !strcmp(oc2, "ss"))
|
||||||
|
imm_size = 4;
|
||||||
|
else if (!strcmp(oc2, "q"))
|
||||||
|
imm_size = 8;
|
||||||
|
|
||||||
|
LOG_INFO("[IMM] val=%lld size=%d", imm_val, imm_size);
|
||||||
|
switch (imm_size) {
|
||||||
|
case 1:
|
||||||
|
emit_u8(m, (uint8_t)imm_val);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
emit_u16(m, (uint16_t)imm_val);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
emit_u32(m, (uint32_t)imm_val);
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
emit_u64(m, (uint64_t)imm_val);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------- ModR/M + SIB + 位移 + 立即数 ---------- */
|
||||||
|
static void emit_modrm_sib_disp(scc_mcode_t *m,
|
||||||
|
const scc_x86_iform_info_t *info,
|
||||||
|
const scc_x86_operand_value_t ops[],
|
||||||
|
int op_width) {
|
||||||
|
const scc_x86_encoding_t *enc = &info->encode;
|
||||||
|
const scc_x86_operand_t *tmpl = info->ops;
|
||||||
|
int num_ops = info->num_explicit_ops;
|
||||||
|
|
||||||
|
scc_x86_reg_t reg_r = SCC_X86_REG_INVALID;
|
||||||
|
scc_x86_reg_t reg_b = SCC_X86_REG_INVALID;
|
||||||
|
int has_mem = 0;
|
||||||
|
scc_x86_mem_t memdesc = {0};
|
||||||
|
int64_t imm_val = 0;
|
||||||
|
int imm_idx = -1;
|
||||||
|
|
||||||
|
for (int i = 0; i < num_ops; i++) {
|
||||||
|
const char *tname = tmpl[i].name;
|
||||||
|
if (ops[i].kind == SCC_X86_OPR_REG) {
|
||||||
|
LOG_INFO("[OPD] %d: REG kind, name=\"%s\" reg=%d", i, tname,
|
||||||
|
ops[i].reg);
|
||||||
|
if (strncmp(tname, "REG0", 4) == 0)
|
||||||
|
reg_r = ops[i].reg;
|
||||||
|
else if (strncmp(tname, "REG1", 4) == 0)
|
||||||
|
reg_b = ops[i].reg;
|
||||||
|
else {
|
||||||
|
if (reg_r == SCC_X86_REG_INVALID)
|
||||||
|
reg_r = ops[i].reg;
|
||||||
|
else if (reg_b == SCC_X86_REG_INVALID)
|
||||||
|
reg_b = ops[i].reg;
|
||||||
|
}
|
||||||
|
} else if (ops[i].kind == SCC_X86_OPR_MEM) {
|
||||||
|
has_mem = 1;
|
||||||
|
memdesc = ops[i].mem;
|
||||||
|
} else if (ops[i].kind == SCC_X86_OPR_IMM) {
|
||||||
|
imm_val = ops[i].imm;
|
||||||
|
imm_idx = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LOG_INFO("[MODRM] reg_r=%d (ord=%d) reg_b=%d (ord=%d)", reg_r,
|
||||||
|
scc_reg_ordinal(reg_r), reg_b, scc_reg_ordinal(reg_b));
|
||||||
|
|
||||||
|
uint8_t modrm = 0;
|
||||||
|
if (has_mem) {
|
||||||
|
if (reg_r != SCC_X86_REG_INVALID)
|
||||||
|
modrm |= (reg_low3(reg_r) & 7) << 3;
|
||||||
|
else if (enc->modrm_reg_fix >= 0)
|
||||||
|
modrm |= (enc->modrm_reg_fix & 7) << 3;
|
||||||
|
|
||||||
|
int32_t disp = memdesc.disp;
|
||||||
|
int dsize = disp_size(disp, memdesc.base);
|
||||||
|
modrm |= (dsize == 0) ? 0 : (dsize == 8) ? 0x40 : 0x80;
|
||||||
|
|
||||||
|
if (memdesc.index != SCC_X86_REG_INVALID) {
|
||||||
|
modrm |= 4;
|
||||||
|
int idx_ord = scc_reg_ordinal(memdesc.index);
|
||||||
|
int base_ord = scc_reg_ordinal(memdesc.base);
|
||||||
|
int scale_enc = scale_to_enc(memdesc.scale);
|
||||||
|
if (scale_enc < 0)
|
||||||
|
return;
|
||||||
|
uint8_t sib = (uint8_t)((scale_enc << 6) | ((idx_ord & 7) << 3) |
|
||||||
|
(base_ord & 7));
|
||||||
|
emit_u8(m, modrm);
|
||||||
|
emit_u8(m, sib);
|
||||||
|
if (dsize == 8)
|
||||||
|
emit_u8(m, (uint8_t)disp);
|
||||||
|
else if (dsize == 32)
|
||||||
|
emit_u32(m, (uint32_t)disp);
|
||||||
|
} else if (memdesc.base == SCC_X86_REG_INVALID) {
|
||||||
|
modrm |= 5;
|
||||||
|
emit_u8(m, modrm);
|
||||||
|
emit_u32(m, (uint32_t)disp);
|
||||||
|
} else {
|
||||||
|
int base_ord = scc_reg_ordinal(memdesc.base);
|
||||||
|
if (memdesc.base == SCC_X86_REG_RSP ||
|
||||||
|
memdesc.base == SCC_X86_REG_R12) {
|
||||||
|
modrm |= 4;
|
||||||
|
uint8_t sib = (uint8_t)((base_ord & 7) | (4 << 3));
|
||||||
|
emit_u8(m, modrm);
|
||||||
|
emit_u8(m, sib);
|
||||||
|
if (dsize == 8)
|
||||||
|
emit_u8(m, (uint8_t)disp);
|
||||||
|
else if (dsize == 32)
|
||||||
|
emit_u32(m, (uint32_t)disp);
|
||||||
|
} else {
|
||||||
|
modrm |= (base_ord & 7);
|
||||||
|
emit_u8(m, modrm);
|
||||||
|
if (dsize == 8)
|
||||||
|
emit_u8(m, (uint8_t)disp);
|
||||||
|
else if (dsize == 32)
|
||||||
|
emit_u32(m, (uint32_t)disp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
modrm = 0xC0;
|
||||||
|
if (enc->modrm_reg_fix >= 0)
|
||||||
|
modrm |= (enc->modrm_reg_fix & 7) << 3;
|
||||||
|
else if (reg_r != SCC_X86_REG_INVALID)
|
||||||
|
modrm |= (reg_low3(reg_r) & 7) << 3;
|
||||||
|
|
||||||
|
if (enc->modrm_rm_fix >= 0) {
|
||||||
|
modrm |= enc->modrm_rm_fix & 7;
|
||||||
|
} else if (reg_b != SCC_X86_REG_INVALID) {
|
||||||
|
modrm |= reg_low3(reg_b) & 7;
|
||||||
|
} else if (enc->modrm_reg_fix >= 0 && reg_r != SCC_X86_REG_INVALID) {
|
||||||
|
modrm |= reg_low3(reg_r) & 7;
|
||||||
|
} else if (reg_r != SCC_X86_REG_INVALID) {
|
||||||
|
modrm |= reg_low3(reg_r) & 7;
|
||||||
|
}
|
||||||
|
emit_u8(m, modrm);
|
||||||
|
}
|
||||||
|
LOG_INFO("[MODRM] emit byte 0x%02x", modrm);
|
||||||
|
|
||||||
|
/* 立即数在 ModRM 后发射 */
|
||||||
|
if (imm_idx >= 0) {
|
||||||
|
emit_immediate(m, enc, tmpl, imm_idx, imm_val, op_width);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------- 主编码入口 ---------- */
|
||||||
|
int scc_x86_encode_inst(scc_mcode_t *mcode, scc_x86_iform_t iform,
|
||||||
|
const scc_x86_operand_value_t *ops) {
|
||||||
|
if (!mcode || !ops)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (iform >= SCC_X86_IFORM_COUNT || iform < 0)
|
||||||
|
Panic("invalid iform %d", iform);
|
||||||
|
|
||||||
|
const scc_x86_iform_info_t *info = &scc_x86_iform_table[iform];
|
||||||
|
const scc_x86_encoding_t *enc = &info->encode;
|
||||||
|
const scc_x86_operand_t *tmpl = info->ops;
|
||||||
|
int num_ops = info->num_explicit_ops;
|
||||||
|
|
||||||
|
LOG_INFO("[IFORM] %s, explicit_ops=%d (total=%d)", info->iform_name,
|
||||||
|
num_ops, info->num_ops);
|
||||||
|
|
||||||
|
scc_x86_reg_t reg_field = SCC_X86_REG_INVALID;
|
||||||
|
scc_x86_reg_t rm_field = SCC_X86_REG_INVALID;
|
||||||
|
scc_x86_reg_t base_reg = SCC_X86_REG_INVALID;
|
||||||
|
scc_x86_reg_t idx_reg = SCC_X86_REG_INVALID;
|
||||||
|
|
||||||
|
/* ---------- 收集立即数信息(用于无 ModRM 指令) ---------- */
|
||||||
|
int64_t imm_val = 0;
|
||||||
|
int imm_idx = -1;
|
||||||
|
for (int i = 0; i < num_ops; i++) {
|
||||||
|
const char *tname = tmpl[i].name;
|
||||||
|
if (ops[i].kind == SCC_X86_OPR_REG) {
|
||||||
|
if (strncmp(tname, "REG0", 4) == 0) {
|
||||||
|
if (enc->modrm_reg_fix >= 0)
|
||||||
|
rm_field = ops[i].reg; // reg固定 → REG0为rm
|
||||||
|
else
|
||||||
|
reg_field = ops[i].reg; // 否则为reg
|
||||||
|
} else if (strncmp(tname, "REG1", 4) == 0) {
|
||||||
|
if (enc->modrm_rm_fix >= 0)
|
||||||
|
reg_field = ops[i].reg; // rm固定 → REG1为reg
|
||||||
|
else
|
||||||
|
rm_field = ops[i].reg; // 否则为rm
|
||||||
|
} else {
|
||||||
|
// 未命名的寄存器,按先 reg 后 rm 填充
|
||||||
|
if (reg_field == SCC_X86_REG_INVALID)
|
||||||
|
reg_field = ops[i].reg;
|
||||||
|
else if (rm_field == SCC_X86_REG_INVALID)
|
||||||
|
rm_field = ops[i].reg;
|
||||||
|
}
|
||||||
|
} else if (ops[i].kind == SCC_X86_OPR_MEM) {
|
||||||
|
base_reg = ops[i].mem.base;
|
||||||
|
idx_reg = ops[i].mem.index;
|
||||||
|
} else if (ops[i].kind == SCC_X86_OPR_IMM ||
|
||||||
|
ops[i].kind == SCC_X86_OPR_RELBR) {
|
||||||
|
imm_val = ops[i].imm;
|
||||||
|
imm_idx = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int op_width = infer_operand_width(info, ops);
|
||||||
|
LOG_INFO("[OPWIDTH] %d bits", op_width);
|
||||||
|
|
||||||
|
// +++ 新增:无 ModRM 时,寄存器用 REX.B 扩展 +++
|
||||||
|
if (!enc->has_modrm) {
|
||||||
|
rm_field = reg_field;
|
||||||
|
reg_field = SCC_X86_REG_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
emit_legacy_prefixes(mcode, enc, reg_field, rm_field, base_reg, idx_reg);
|
||||||
|
emit_rex(mcode, enc, reg_field, rm_field, base_reg, idx_reg);
|
||||||
|
emit_escape_map(mcode, enc);
|
||||||
|
|
||||||
|
if (enc->has_modrm) {
|
||||||
|
emit_opcode(mcode, enc, rm_field, base_reg);
|
||||||
|
emit_modrm_sib_disp(mcode, info, ops, op_width);
|
||||||
|
} else {
|
||||||
|
// 无 ModRM:opcode 中的寄存器来自 rm_field
|
||||||
|
emit_opcode(mcode, enc, rm_field, base_reg);
|
||||||
|
if (imm_idx >= 0) {
|
||||||
|
emit_immediate(mcode, enc, tmpl, imm_idx, imm_val, op_width);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -71,20 +71,17 @@ void scc_tree_dump_append(scc_tree_dump_t *td, const char *s);
|
|||||||
*/
|
*/
|
||||||
void scc_tree_dump_append_fmt(scc_tree_dump_t *td, const char *fmt, ...);
|
void scc_tree_dump_append_fmt(scc_tree_dump_t *td, const char *fmt, ...);
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 追加带节点颜色的文本
|
|
||||||
*/
|
|
||||||
#define scc_tree_dump_node(td, fmt, ...) \
|
#define scc_tree_dump_node(td, fmt, ...) \
|
||||||
scc_tree_dump_append_fmt(td, "%s" fmt "%s", (td)->node_color, \
|
scc_tree_dump_append_fmt(td, "%s" fmt "%s", (td)->node_color, \
|
||||||
##__VA_ARGS__, (td)->reset_color)
|
##__VA_ARGS__, (td)->reset_color)
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 追加带值颜色的格式化文本
|
|
||||||
*/
|
|
||||||
#define scc_tree_dump_value(td, fmt, ...) \
|
#define scc_tree_dump_value(td, fmt, ...) \
|
||||||
scc_tree_dump_append_fmt(td, "%s" fmt "%s", (td)->value_color, \
|
scc_tree_dump_append_fmt(td, "%s" fmt "%s", (td)->value_color, \
|
||||||
##__VA_ARGS__, (td)->reset_color)
|
##__VA_ARGS__, (td)->reset_color)
|
||||||
|
|
||||||
|
#define scc_tree_dump_branch(td, fmt, ...) \
|
||||||
|
scc_tree_dump_append_fmt(td, "%s" fmt "%s", (td)->branch_color, \
|
||||||
|
##__VA_ARGS__, (td)->reset_color)
|
||||||
/**
|
/**
|
||||||
* @brief 推入新层级
|
* @brief 推入新层级
|
||||||
* @param is_last 该层级是否是父节点的最后一个子节点
|
* @param is_last 该层级是否是父节点的最后一个子节点
|
||||||
|
|||||||
@@ -4,10 +4,10 @@
|
|||||||
#define DEFAULT_BRANCH "|-"
|
#define DEFAULT_BRANCH "|-"
|
||||||
#define DEFAULT_LAST_BRANCH "`-"
|
#define DEFAULT_LAST_BRANCH "`-"
|
||||||
#define DEFAULT_SPACE " "
|
#define DEFAULT_SPACE " "
|
||||||
#define NODE_COLOR "\033[34m"
|
#define NODE_COLOR ANSI_FG_GREEN
|
||||||
#define VALUE_COLOR "\033[32m"
|
#define VALUE_COLOR ANSI_FG_YELLOW
|
||||||
#define BRANCH_COLOR "\033[33m"
|
#define BRANCH_COLOR ANSI_FG_CYAN
|
||||||
#define RESET_COLOR "\033[0m"
|
#define RESET_COLOR ANSI_NONE
|
||||||
|
|
||||||
void scc_tree_dump_init(scc_tree_dump_t *td, cbool use_color) {
|
void scc_tree_dump_init(scc_tree_dump_t *td, cbool use_color) {
|
||||||
scc_str_init(&td->buf);
|
scc_str_init(&td->buf);
|
||||||
|
|||||||
45
src/main.c
45
src/main.c
@@ -18,6 +18,8 @@
|
|||||||
#include <sccf2pe.h>
|
#include <sccf2pe.h>
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
void init_platform(void);
|
||||||
|
#define GET_VALID_FP(fp) (fp == nullptr ? scc_stdout : fp)
|
||||||
|
|
||||||
static void print_ring(scc_lexer_tok_ring_t *ring, int verbose) {
|
static void print_ring(scc_lexer_tok_ring_t *ring, int verbose) {
|
||||||
scc_lexer_tok_t tok = {0};
|
scc_lexer_tok_t tok = {0};
|
||||||
@@ -66,10 +68,21 @@ static void print_file(scc_lexer_tok_ring_t *ring, scc_file_t fp) {
|
|||||||
static void tree_dump_output(const char *str, usize len, void *user) {
|
static void tree_dump_output(const char *str, usize len, void *user) {
|
||||||
scc_fprintf(user, "%.*s", (int)len, str);
|
scc_fprintf(user, "%.*s", (int)len, str);
|
||||||
}
|
}
|
||||||
|
static inline int mir_dump(scc_file_t fp, scc_mir_module_t *mir_module) {
|
||||||
|
scc_tree_dump_t tree_dump;
|
||||||
|
scc_mir_dump_ctx_t mir_dump_ctx;
|
||||||
|
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);
|
||||||
|
|
||||||
void init_platform(void);
|
scc_tree_dump_flush(&tree_dump, tree_dump_output, GET_VALID_FP(fp));
|
||||||
|
scc_tree_dump_drop(&tree_dump);
|
||||||
#define GET_VALID_FP(fp) (fp == nullptr ? scc_stdout : fp)
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, const char **argv, const char **envp) {
|
int main(int argc, const char **argv, const char **envp) {
|
||||||
init_platform();
|
init_platform();
|
||||||
@@ -276,36 +289,20 @@ sstream_drop:
|
|||||||
|
|
||||||
switch (config.emit_stage) {
|
switch (config.emit_stage) {
|
||||||
case SCC_EMIT_STAGE_MIR:
|
case SCC_EMIT_STAGE_MIR:
|
||||||
goto mir_dump;
|
return mir_dump(fp, &mir_module);
|
||||||
case SCC_EMIT_STAGE_MIR_PASS_REG_ALLOC:
|
case SCC_EMIT_STAGE_MIR_PASS_REG_ALLOC:
|
||||||
scc_mir_pass(&mir_module, SCC_MIR_STAGE_REGALLOC);
|
scc_mir_pass(&mir_module, SCC_MIR_STAGE_REGALLOC);
|
||||||
goto mir_dump;
|
return mir_dump(fp, &mir_module);
|
||||||
case SCC_EMIT_STAGE_MIR_PASS_FLAME_LAYOUT:
|
case SCC_EMIT_STAGE_MIR_PASS_FLAME_LAYOUT:
|
||||||
scc_mir_pass(&mir_module, SCC_MIR_STAGE_FRAME_LAYOUT);
|
scc_mir_pass(&mir_module, SCC_MIR_STAGE_FRAME_LAYOUT);
|
||||||
goto mir_dump;
|
return mir_dump(fp, &mir_module);
|
||||||
case SCC_EMIT_STAGE_MIR_PASS_PROLOG_EPILOG:
|
case SCC_EMIT_STAGE_MIR_PASS_PROLOG_EPILOG:
|
||||||
scc_mir_pass(&mir_module, SCC_MIR_STAGE_PROLOGUE_EPILOGUE);
|
scc_mir_pass(&mir_module, SCC_MIR_STAGE_PROLOGUE_EPILOGUE);
|
||||||
goto mir_dump;
|
return mir_dump(fp, &mir_module);
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
|
scc_mir_pass(&mir_module, SCC_MIR_STAGE_ANY);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
do {
|
|
||||||
mir_dump:
|
|
||||||
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, GET_VALID_FP(fp));
|
|
||||||
scc_tree_dump_drop(&tree_dump);
|
|
||||||
return 0;
|
|
||||||
} while (0);
|
|
||||||
|
|
||||||
if (config.emit_stage == SCC_EMIT_STAGE_FLATBIN) {
|
if (config.emit_stage == SCC_EMIT_STAGE_FLATBIN) {
|
||||||
scc_mcode_t mcode = {0};
|
scc_mcode_t mcode = {0};
|
||||||
|
|||||||
Reference in New Issue
Block a user