stable 重构文件结构
抽象出Machine Code
This commit is contained in:
30
src/ccompiler/backend/Makefile
Normal file
30
src/ccompiler/backend/Makefile
Normal file
@ -0,0 +1,30 @@
|
||||
# 编译器设置
|
||||
CC = gcc
|
||||
AR = ar
|
||||
CFLAGS = -g -Wall -I../..
|
||||
|
||||
RISCV32_DIR = ./riscv32
|
||||
|
||||
# 源文件列表
|
||||
SRCS = \
|
||||
backend.c \
|
||||
$(RISCV32_DIR)/riscv32.c
|
||||
|
||||
# 生成目标文件列表
|
||||
OBJS = $(SRCS:.c=.o)
|
||||
|
||||
# 最终目标
|
||||
TARGET = libbackend.a
|
||||
|
||||
all: $(TARGET)
|
||||
|
||||
$(TARGET): $(OBJS)
|
||||
$(AR) rcs $@ $^
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
|
||||
clean:
|
||||
rm -f $(OBJS) $(TARGET)
|
||||
|
||||
.PHONY: all clean
|
23
src/ccompiler/backend/backend.c
Normal file
23
src/ccompiler/backend/backend.c
Normal file
@ -0,0 +1,23 @@
|
||||
#include "backend.h"
|
||||
|
||||
int gen_asm_from_ir(ir_prog_t* ir, cc_arch_t arch, asm_prog_t* out_asm) {
|
||||
switch (arch) {
|
||||
case CC_ARCH_RISCV32:
|
||||
// TODO using maroc to choice
|
||||
init_rv32_prog(&(out_asm->rv32), NULL);
|
||||
gen_rv32_from_ir(ir, &(out_asm->rv32));
|
||||
break;
|
||||
case CC_ARCH_X86_32:
|
||||
default:
|
||||
Panic("Unsupported arch");
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
asm_prog_t* cc_backend(ir_prog_t* ir, cc_backend_conf_t* conf) {
|
||||
// TODO
|
||||
asm_prog_t* bin = (asm_prog_t*)salloc_alloc(sizeof(asm_prog_t));
|
||||
gen_asm_from_ir(ir, conf->arch, bin);
|
||||
return bin;
|
||||
}
|
30
src/ccompiler/backend/backend.h
Normal file
30
src/ccompiler/backend/backend.h
Normal file
@ -0,0 +1,30 @@
|
||||
#ifndef __SMCC_CC_BACKEND_H__
|
||||
#define __SMCC_CC_BACKEND_H__
|
||||
|
||||
// TODO Use Maroc to choice architecture
|
||||
#ifndef __SMCC_CC_NO_RISCV32__
|
||||
#include "riscv32/riscv32.h"
|
||||
#endif
|
||||
|
||||
// #ifndef __SMCC_CC_NO_X86_32__
|
||||
// #include "x86_32/x86_32.h"
|
||||
// #endif
|
||||
|
||||
// TODO 统一 汇编器 接口
|
||||
#include <src/assembler/assembler.h>
|
||||
#include "../middleend/ir/ir.h"
|
||||
typedef enum cc_arch {
|
||||
CC_ARCH_RISCV32,
|
||||
CC_ARCH_X86_32
|
||||
} cc_arch_t;
|
||||
|
||||
typedef union asm_prog asm_prog_t;
|
||||
int gen_asm_from_ir(ir_prog_t* ir, cc_arch_t arch, asm_prog_t* asm_prog);
|
||||
|
||||
typedef struct cc_backend_conf {
|
||||
cc_arch_t arch;
|
||||
} cc_backend_conf_t;
|
||||
|
||||
asm_prog_t* cc_backend(ir_prog_t* ir, cc_backend_conf_t* conf);
|
||||
|
||||
#endif
|
41
src/ccompiler/backend/riscv32/README.md
Normal file
41
src/ccompiler/backend/riscv32/README.md
Normal file
@ -0,0 +1,41 @@
|
||||
# 后端代码生成
|
||||
|
||||
## riscv32i
|
||||
|
||||
> 仿照ripes的syscall,实现了rv32-vm
|
||||
|
||||
### syscall ecall 系统调用
|
||||
|
||||
```c
|
||||
// ecall 系统调用函数实现
|
||||
#define ECALL_PNT_INT(num) \
|
||||
ADDI(REG_A0, REG_X0, num), \
|
||||
ADDI(REG_A7, REG_X0, 0x1), \
|
||||
ECALL(),
|
||||
|
||||
#define ECALL_PNT_STR(str) \
|
||||
ADDI(REG_A0, REG_X0, str), \
|
||||
ADDI(REG_A7, REG_X0, 0x4), \
|
||||
ECALL(),
|
||||
|
||||
#define ECALL_EXIT(errno) \
|
||||
ADDI(REG_A0, REG_X0, errno), \
|
||||
ADDI(REG_A7, REG_X0, 10), \
|
||||
ECALL(),
|
||||
|
||||
#define ECALL_SCAN_INT(int) \
|
||||
ADDI(REG_A7, (1025 + 4)), \
|
||||
ECALL(),
|
||||
|
||||
#define ECALL_SCAN_STR(str) \
|
||||
ADDI(REG_A0, REG_X0, str), \
|
||||
ADDI(REG_A7, REG_X0, (1025 + 5)), \
|
||||
ECALL(),
|
||||
|
||||
// 函数声明
|
||||
void ecall_pnt_int(int num);
|
||||
void ecall_pnt_str(char *str);
|
||||
void ecall_exit(int errno);
|
||||
int ecall_scani();
|
||||
void ecall_scans(char *str);
|
||||
```
|
302
src/ccompiler/backend/riscv32/riscv32.c
Normal file
302
src/ccompiler/backend/riscv32/riscv32.c
Normal file
@ -0,0 +1,302 @@
|
||||
#include "riscv32.h"
|
||||
#include <src/mcode/riscv32/riscv32_instr.h>
|
||||
|
||||
typedef struct {
|
||||
ir_func_t* func;
|
||||
int stack_offset;
|
||||
int stack_base;
|
||||
int func_idx;
|
||||
int block_idx;
|
||||
} gen_ctx_t;
|
||||
|
||||
static inline int stack_pos(ir_node_t* ptr, gen_ctx_t *ctx) {
|
||||
// ir_func_t *func, int stack_base, int stack_offset
|
||||
int offset = ctx->stack_base;
|
||||
for (int i = 0; i < ctx->func->bblocks.size; i ++) {
|
||||
ir_bblock_t* block = vector_at(ctx->func->bblocks, i);
|
||||
for (int i = 0; i < block->instrs.size; i++) {
|
||||
if (vector_at(block->instrs, i) == ptr) {
|
||||
offset += i * 4;
|
||||
Assert(offset >= 0 && offset < ctx->stack_offset);
|
||||
return offset;
|
||||
}
|
||||
}
|
||||
offset += block->instrs.size * 4;
|
||||
}
|
||||
Panic("stack pos got error");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int system_func(const char* name) {
|
||||
static struct {
|
||||
const char* name;
|
||||
int ecall_num;
|
||||
} defined_func[] = {
|
||||
{"ecall_pnt_int", 1},
|
||||
{"ecall_pnt_char", 11},
|
||||
{"ecall_scan_int", 1025 + 4},
|
||||
};
|
||||
|
||||
for (int i = 0; i < sizeof(defined_func)/sizeof(defined_func[0]); i++) {
|
||||
if (rt_strcmp(name, defined_func[i].name) == 0) {
|
||||
return defined_func[i].ecall_num;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int get_node_val(mcode_rv32_t* out_asm, gen_ctx_t* ctx, ir_node_t* ptr, int reg) {
|
||||
int len = 0;
|
||||
switch (ptr->tag) {
|
||||
case IR_NODE_CONST_INT: {
|
||||
// TODO
|
||||
rv32_li(out_asm, reg, ptr->data.const_int.val);
|
||||
// emit_rv32_instr(out_asm, RV_ADDI, reg, reg, 0, ptr->data.const_int.val);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
int offset = stack_pos(ptr, ctx);
|
||||
rv32_lw(out_asm, reg, REG_SP, offset);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
static int gen_instr(rv32_prog_t* _out_asm, gen_ctx_t* ctx, ir_node_t* instr) {
|
||||
mcode_rv32_t* out_asm = &_out_asm->mcode;
|
||||
int idx = 0;
|
||||
int offset;
|
||||
char buf[1024];
|
||||
symasm_entry_t label;
|
||||
|
||||
switch (instr->tag) {
|
||||
case IR_NODE_ALLOC: {
|
||||
// TODO
|
||||
break;
|
||||
}
|
||||
case IR_NODE_LOAD: {
|
||||
offset = stack_pos(instr->data.load.target, ctx);
|
||||
// t0 = M[sp + offset]
|
||||
rv32_lw(out_asm, REG_T0, REG_SP, offset);
|
||||
break;
|
||||
}
|
||||
case IR_NODE_STORE: {
|
||||
idx += get_node_val(out_asm, ctx, instr->data.store.value, REG_T0);
|
||||
offset = stack_pos(instr->data.store.target, ctx);
|
||||
// M[sp + offset] = t0
|
||||
rv32_sw(out_asm, REG_T0, REG_SP, offset);
|
||||
break;
|
||||
}
|
||||
case IR_NODE_RET: {
|
||||
// A0 = S0
|
||||
if (instr->data.ret.ret_val != NULL) {
|
||||
idx += get_node_val(out_asm, ctx, instr->data.ret.ret_val, REG_A0);
|
||||
}
|
||||
// ra = M[sp + 0]
|
||||
rv32_lw(out_asm, REG_RA, REG_SP, 0);
|
||||
// sp = sp + stack_offset
|
||||
rv32_addi(out_asm, REG_SP, REG_SP, ctx->stack_offset);
|
||||
// ret == JALR(REG_X0, REG_RA, 0)
|
||||
rv32_ret(out_asm);
|
||||
break;
|
||||
}
|
||||
case IR_NODE_OP: {
|
||||
idx += get_node_val(out_asm, ctx, instr->data.op.lhs, REG_T1);
|
||||
idx += get_node_val(out_asm, ctx, instr->data.op.rhs, REG_T2);
|
||||
|
||||
rv32_instr_t _instr = {
|
||||
.rd = REG_T0,
|
||||
.rs1 = REG_T1,
|
||||
.rs2 = REG_T2,
|
||||
.imm = 0
|
||||
};
|
||||
#define GEN_BIN_OP(type) _instr.instr_type = type, \
|
||||
emit_rv32_instr(out_asm, &_instr, EMIT_PUSH_BACK, NULL)
|
||||
switch (instr->data.op.op) {
|
||||
case IR_OP_ADD:
|
||||
GEN_BIN_OP(RV_ADD);
|
||||
break;
|
||||
case IR_OP_SUB:
|
||||
GEN_BIN_OP(RV_SUB);
|
||||
break;
|
||||
case IR_OP_MUL:
|
||||
GEN_BIN_OP(RV_MUL);
|
||||
break;
|
||||
case IR_OP_DIV:
|
||||
GEN_BIN_OP(RV_DIV);
|
||||
break;
|
||||
case IR_OP_MOD:
|
||||
GEN_BIN_OP(RV_REM);
|
||||
break;
|
||||
case IR_OP_EQ:
|
||||
GEN_BIN_OP(RV_XOR);
|
||||
rv32_seqz(out_asm, REG_T0, REG_T0);
|
||||
break;
|
||||
case IR_OP_GE:
|
||||
GEN_BIN_OP(RV_SLT);
|
||||
rv32_seqz(out_asm, REG_T0, REG_T0);
|
||||
break;
|
||||
case IR_OP_GT:
|
||||
// SGT(rd, rs1, rs2) SLT(rd, rs2, rs1)
|
||||
// GENCODE(SGT(REG_T0, REG_T1, REG_T2));
|
||||
rv32_slt(out_asm, REG_T0, REG_T2, REG_T1);
|
||||
break;
|
||||
case IR_OP_LE:
|
||||
// GENCODE(SGT(REG_T0, REG_T1, REG_T2));
|
||||
rv32_slt(out_asm, REG_T0, REG_T2, REG_T1);
|
||||
rv32_seqz(out_asm, REG_T0, REG_T0);
|
||||
break;
|
||||
case IR_OP_LT:
|
||||
rv32_slt(out_asm, REG_T0, REG_T1, REG_T2);
|
||||
break;
|
||||
case IR_OP_NEQ:
|
||||
GEN_BIN_OP(RV_XOR);
|
||||
break;
|
||||
default:
|
||||
LOG_ERROR("ERROR gen_instr op in riscv");
|
||||
break;
|
||||
}
|
||||
offset = stack_pos(instr, ctx);
|
||||
rv32_sw(out_asm, REG_T0, REG_SP, offset);
|
||||
break;
|
||||
}
|
||||
case IR_NODE_BRANCH: {
|
||||
get_node_val(out_asm, ctx, instr->data.branch.cond, REG_T0);
|
||||
|
||||
rt.snprintf(buf, sizeof(buf), "L%s%p", instr->data.branch.true_bblock->label, instr->data.branch.true_bblock);
|
||||
label.name = strpool_intern(_out_asm->strpool, buf);
|
||||
label.attr = LOCAL;
|
||||
rv32_bne_l(out_asm, REG_T0, REG_X0, &label);
|
||||
|
||||
rt.snprintf(buf, sizeof(buf), "L%s%p", instr->data.branch.false_bblock->label, instr->data.branch.false_bblock);
|
||||
label.name = strpool_intern(_out_asm->strpool, buf);
|
||||
label.attr = LOCAL;
|
||||
rv32_jal_l(out_asm, REG_X0, &label);
|
||||
break;
|
||||
}
|
||||
case IR_NODE_JUMP: {
|
||||
// TODO
|
||||
rt.snprintf(buf, sizeof(buf), "L%s%p", instr->data.jump.target_bblock->label, instr->data.jump.target_bblock);
|
||||
label.name = strpool_intern(_out_asm->strpool, buf);
|
||||
label.attr = LOCAL;
|
||||
rv32_jal_l(out_asm, REG_X0, &label);
|
||||
break;
|
||||
}
|
||||
case IR_NODE_CALL: {
|
||||
if (instr->data.call.args.size > 8) {
|
||||
LOG_ERROR("can't add so much params");
|
||||
}
|
||||
int param_regs[8] = {
|
||||
REG_A0, REG_A1, REG_A2, REG_A3,
|
||||
REG_A4, REG_A5, REG_A6, REG_A7
|
||||
};
|
||||
for (int i = 0; i < instr->data.call.args.size; i++) {
|
||||
ir_node_t* param = vector_at(instr->data.call.args, i);
|
||||
idx += get_node_val(out_asm, ctx, param, param_regs[i]);
|
||||
}
|
||||
|
||||
int system_func_idx = system_func(instr->data.call.callee->name);
|
||||
if (system_func_idx != -1) {
|
||||
rv32_li(out_asm, REG_A7, system_func_idx);
|
||||
rv32_ecall(out_asm);
|
||||
goto CALL_END;
|
||||
}
|
||||
|
||||
/*
|
||||
// GENCODES(CALL(0));
|
||||
// AUIPC(REG_X1, REG_X0), \
|
||||
// JALR(REG_X1, REG_X1, offset)
|
||||
*/
|
||||
// TODO CALL
|
||||
label.name = strpool_intern(_out_asm->strpool, instr->data.call.callee->name);
|
||||
label.attr = GLOBAL;
|
||||
rv32_call_l(out_asm, &label);
|
||||
CALL_END:
|
||||
offset = stack_pos(instr, ctx);
|
||||
rv32_sw(out_asm, REG_A0, REG_SP, offset);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
LOG_ERROR("ERROR gen_instr in riscv");
|
||||
}
|
||||
return idx;
|
||||
}
|
||||
|
||||
static int gen_block(rv32_prog_t* out_asm, gen_ctx_t* ctx, ir_bblock_t* block) {
|
||||
symasm_entry_t label;
|
||||
char buf[1024];
|
||||
rt.snprintf(buf, sizeof(buf), "L%s%p", block->label, block);
|
||||
label.name = strpool_intern(out_asm->strpool, buf);
|
||||
label.attr = LOCAL;
|
||||
symtab_asm_put(&out_asm->symtab, &label, out_asm->mcode.code.size);
|
||||
|
||||
for (int i = 0; i < block->instrs.size; i ++) {
|
||||
gen_instr(out_asm, ctx, vector_at(block->instrs, i));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gen_func(rv32_prog_t* out_asm, ir_func_t* func) {
|
||||
gen_ctx_t ctx;
|
||||
|
||||
symasm_entry_t label = {
|
||||
.name = strpool_intern(out_asm->strpool, func->name),
|
||||
.attr = GLOBAL,
|
||||
};
|
||||
symtab_asm_put(&out_asm->symtab, &label, out_asm->mcode.code.size);
|
||||
|
||||
int stack_base = 4;
|
||||
int stack_offset = stack_base;
|
||||
for (int i = 0; i < func->bblocks.size; i++) {
|
||||
// TODO every instr push ret val to stack
|
||||
stack_offset += 4 * (*vector_at(func->bblocks, i)).instrs.size;
|
||||
}
|
||||
ctx.func = func;
|
||||
ctx.stack_base = stack_base;
|
||||
ctx.stack_offset = stack_offset;
|
||||
ctx.func_idx = 0;
|
||||
ctx.block_idx = 0;
|
||||
// TODO Alignment by 16
|
||||
|
||||
// sp = sp - stack_offset;
|
||||
rv32_addi(&out_asm->mcode, REG_SP, REG_SP, -stack_offset);
|
||||
// M[sp] = ra;
|
||||
rv32_sw(&out_asm->mcode, REG_RA, REG_SP, 0);
|
||||
|
||||
int param_regs[8] = {
|
||||
REG_A0, REG_A1, REG_A2, REG_A3,
|
||||
REG_A4, REG_A5, REG_A6, REG_A7
|
||||
};
|
||||
if (func->params.size > 8) {
|
||||
LOG_ERROR("can't add so much params");
|
||||
}
|
||||
for (int i = 0; i < func->params.size; i++) {
|
||||
int offset = stack_pos(vector_at(func->params, i), &ctx);
|
||||
// M[sp + offset] = param[idx];
|
||||
rv32_sw(&out_asm->mcode, param_regs[i], REG_SP, offset);
|
||||
}
|
||||
|
||||
for(int i = 0; i < func->bblocks.size; i ++) {
|
||||
gen_block(out_asm, &ctx ,vector_at(func->bblocks, i));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int gen_rv32_from_ir(ir_prog_t* ir, rv32_prog_t* out_asm) {
|
||||
init_rv32_prog(out_asm, NULL);
|
||||
|
||||
for(int i = 0; i < ir->funcs.size; i ++) {
|
||||
gen_func(out_asm, vector_at(ir->funcs, i));
|
||||
}
|
||||
return 0;
|
||||
|
||||
// // Got Main pos;
|
||||
// for (int i = 0; i < prog->funcs.size; i++) {
|
||||
// if (strcmp(vector_at(prog->funcs, i)->name, "main") == 0) {
|
||||
// return jmp_cache[i];
|
||||
// }
|
||||
// }
|
||||
// LOG_ERROR("main not found");
|
||||
}
|
9
src/ccompiler/backend/riscv32/riscv32.h
Normal file
9
src/ccompiler/backend/riscv32/riscv32.h
Normal file
@ -0,0 +1,9 @@
|
||||
#ifndef __SMCC_CC_RISCV32_H__
|
||||
#define __SMCC_CC_RISCV32_H__
|
||||
|
||||
#include <src/assembler/assembler.h>
|
||||
#include "../../middleend/ir/ir.h"
|
||||
|
||||
int gen_rv32_from_ir(ir_prog_t* ir, rv32_prog_t* out_asm);
|
||||
|
||||
#endif
|
Reference in New Issue
Block a user