initial version of regalloc
This commit is contained in:
parent
b8108acb2e
commit
40eb2ce96f
584
boot.c
584
boot.c
@ -429,8 +429,8 @@ int parse_type() {
|
||||
int epilog_label;
|
||||
|
||||
int local_table[4096]; // id -> local id
|
||||
int next_local_id = 2;
|
||||
int max_local_id = 2;
|
||||
int next_local_id = 12;
|
||||
int max_local_id = 12;
|
||||
|
||||
const int MARKER_TEMP = 0;
|
||||
const int MARKER_SCALAR = 1;
|
||||
@ -441,47 +441,137 @@ int local_marker[4096];
|
||||
int global_marker[4096];
|
||||
int local_type[4096];
|
||||
int global_type[4096];
|
||||
|
||||
int reg_type[4096];
|
||||
int next_reg_id = 18;
|
||||
int max_reg_id = 18;
|
||||
int indirection[4096];
|
||||
int overflow[4096];
|
||||
|
||||
const int REG_ZERO = 0;
|
||||
const int REG_RA = 1;
|
||||
const int REG_SP = 2;
|
||||
const int REG_GP = 3;
|
||||
const int REG_TP = 4;
|
||||
const int REG_T0 = 5;
|
||||
const int REG_T1 = 6;
|
||||
const int REG_T2 = 7;
|
||||
const int REG_FP = 8;
|
||||
const int REG_S1 = 9;
|
||||
const int REG_A0 = 10;
|
||||
const int REG_A1 = 11;
|
||||
const int REG_A2 = 12;
|
||||
const int REG_A3 = 13;
|
||||
const int REG_A4 = 14;
|
||||
const int REG_A5 = 15;
|
||||
const int REG_A6 = 16;
|
||||
const int REG_A7 = 17;
|
||||
const int REG_S2 = 18;
|
||||
const int REG_S3 = 19;
|
||||
const int REG_S4 = 20;
|
||||
const int REG_S5 = 21;
|
||||
const int REG_S6 = 22;
|
||||
const int REG_S7 = 23;
|
||||
const int REG_S8 = 24;
|
||||
const int REG_S9 = 25;
|
||||
const int REG_S10 = 26;
|
||||
const int REG_S11 = 27;
|
||||
const int REG_T3 = 28;
|
||||
const int REG_T4 = 29;
|
||||
const int REG_T5 = 30;
|
||||
const int REG_T6 = 31;
|
||||
|
||||
void reset_reg() {
|
||||
next_reg_id = REG_S2;
|
||||
for (int i = 0; i < 4096; ++i) {
|
||||
reg_type[i] = TYPE_VOID;
|
||||
indirection[i] = 0;
|
||||
overflow[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
const char* reg_name(int reg) {
|
||||
if (reg == 0) return "zero";
|
||||
if (reg == 1) return "ra";
|
||||
if (reg == 2) return "sp";
|
||||
if (reg == 3) return "gp";
|
||||
if (reg == 4) return "tp";
|
||||
if (reg == 5) return "t0";
|
||||
if (reg == 6) return "t1";
|
||||
if (reg == 7) return "t2";
|
||||
if (reg == 8) return "fp";
|
||||
// reserved begin
|
||||
if (reg == 9) return "s1";
|
||||
if (reg == 10) return "a0";
|
||||
if (reg == 11) return "a1";
|
||||
if (reg == 12) return "a2";
|
||||
if (reg == 13) return "a3";
|
||||
if (reg == 14) return "a4";
|
||||
if (reg == 15) return "a5";
|
||||
if (reg == 16) return "a6";
|
||||
if (reg == 17) return "a7";
|
||||
// allocation begin
|
||||
if (reg == 18) return "s2";
|
||||
if (reg == 19) return "s3";
|
||||
if (reg == 20) return "s4";
|
||||
if (reg == 21) return "s5";
|
||||
if (reg == 22) return "s6";
|
||||
if (reg == 23) return "s7";
|
||||
if (reg == 24) return "s8";
|
||||
if (reg == 25) return "s9";
|
||||
if (reg == 26) return "s10";
|
||||
if (reg == 27) return "s11";
|
||||
// overflow begin
|
||||
if (reg == 28) return "t3";
|
||||
if (reg == 29) return "t4";
|
||||
if (reg == 30) return "t5";
|
||||
if (reg == 31) return "t6";
|
||||
return 0;
|
||||
}
|
||||
|
||||
int is_overflow(int reg) {
|
||||
return reg > REG_S11;
|
||||
}
|
||||
|
||||
void reset_local() {
|
||||
next_local_id = 2;
|
||||
max_local_id = 2;
|
||||
next_local_id = 12;
|
||||
max_local_id = 12;
|
||||
for (int i = 0; i < 4096; ++i) {
|
||||
local_table[i] = 0;
|
||||
local_marker[i] = MARKER_TEMP;
|
||||
local_type[i] = TYPE_VOID;
|
||||
indirection[i] = 0;
|
||||
}
|
||||
reset_reg();
|
||||
}
|
||||
|
||||
void reset_temp() {
|
||||
while (next_local_id > 2 && local_marker[next_local_id - 1] == MARKER_TEMP) {
|
||||
while (next_local_id > 12 && local_marker[next_local_id - 1] == MARKER_TEMP) {
|
||||
--next_local_id;
|
||||
}
|
||||
reset_reg();
|
||||
}
|
||||
|
||||
int next_reg(int type) {
|
||||
int reg = next_local_id++;
|
||||
local_type[reg] = type;
|
||||
indirection[reg] = 0;
|
||||
int next_local_slot(int type) {
|
||||
int slot = next_local_id++;
|
||||
local_type[slot] = type;
|
||||
if (next_local_id > max_local_id) {
|
||||
max_local_id = next_local_id;
|
||||
}
|
||||
return reg;
|
||||
return slot;
|
||||
}
|
||||
|
||||
int declare_local(int id, int type) {
|
||||
if (local_table[id] != 0) return local_table[id];
|
||||
int reg = next_reg(type);
|
||||
local_marker[reg] = MARKER_SCALAR;
|
||||
return local_table[id] = reg;
|
||||
int slot = next_local_slot(type);
|
||||
local_marker[slot] = MARKER_SCALAR;
|
||||
return local_table[id] = slot;
|
||||
}
|
||||
|
||||
int declare_local_array(int id, int type, int size) {
|
||||
if (local_table[id] != 0) return local_table[id];
|
||||
int reg;
|
||||
for (int i = 0; i < size; ++i) local_marker[reg = next_reg(type)] = MARKER_ARRAY;
|
||||
return local_table[id] = reg;
|
||||
int slot;
|
||||
for (int i = 0; i < size; ++i) local_marker[slot = next_local_slot(type)] = MARKER_ARRAY;
|
||||
return local_table[id] = slot;
|
||||
}
|
||||
|
||||
void declare_global(int id, int marker, int type) {
|
||||
@ -489,6 +579,23 @@ void declare_global(int id, int marker, int type) {
|
||||
global_type[id] = type;
|
||||
}
|
||||
|
||||
int next_reg(int type) {
|
||||
int reg = next_reg_id++;
|
||||
if (is_overflow(reg)) {
|
||||
int slot = next_local_slot(type);
|
||||
local_marker[slot] = MARKER_TEMP;
|
||||
overflow[reg] = slot;
|
||||
}
|
||||
reg_type[reg] = type;
|
||||
if (next_reg_id > max_reg_id) {
|
||||
max_reg_id = next_reg_id;
|
||||
}
|
||||
return reg;
|
||||
}
|
||||
|
||||
|
||||
// prolog & epilog helpers
|
||||
|
||||
int check_itype_immediate(int value) {
|
||||
return value >= -2048 && value <= 2047;
|
||||
}
|
||||
@ -522,74 +629,176 @@ void asm_addi(const char* rd, const char* rs, int imm) {
|
||||
}
|
||||
}
|
||||
|
||||
void load_address(int rd, int id) {
|
||||
if (id == -1) {
|
||||
eprintf("void cannot be arithmetically operated\n");
|
||||
exit(1);
|
||||
}
|
||||
int offset = -id * 8 - 8;
|
||||
if (indirection[id]) {
|
||||
// assembly helpers
|
||||
|
||||
// address loaders
|
||||
// rd must be one of 0, 1, 2
|
||||
void load_local_address(int rd, int slot_id) {
|
||||
// TODO use sp instead
|
||||
int offset = -slot_id * 8 - 8;
|
||||
const char* rd_name = reg_name(rd);
|
||||
if (check_itype_immediate(offset)) {
|
||||
printf(" ld t%d, %d(fp) # indirection\n", rd, offset);
|
||||
printf(" addi %s, fp, %d\n", rd_name, offset);
|
||||
} else {
|
||||
printf(" li t%d, %d\n", rd, offset);
|
||||
printf(" add t%d, fp, t%d\n", rd, rd);
|
||||
printf(" ld t%d, 0(t%d) # indirection\n", rd, rd);
|
||||
}
|
||||
} else {
|
||||
if (check_itype_immediate(offset)) {
|
||||
printf(" addi t%d, fp, %d\n", rd, offset);
|
||||
} else {
|
||||
printf(" li t%d, %d\n", rd, offset);
|
||||
printf(" add t%d, fp, t%d\n", rd, rd);
|
||||
}
|
||||
printf(" li %s, %d\n", rd_name, offset);
|
||||
printf(" add %s, fp, %s\n", rd_name, rd_name);
|
||||
}
|
||||
}
|
||||
|
||||
void load(int rd, int id) {
|
||||
load_address(rd, id);
|
||||
int type = local_type[id];
|
||||
const char* op = "lw"; // int
|
||||
if (type == TYPE_CHAR) {
|
||||
op = "lb";
|
||||
} else if (type & TYPE_PTR_MASK) {
|
||||
op = "ld";
|
||||
const char* load_op(int reg) {
|
||||
int type = reg_type[reg];
|
||||
if (type & TYPE_PTR_MASK) {
|
||||
return "ld";
|
||||
} else if (type == TYPE_CHAR) {
|
||||
return "lb";
|
||||
} else { // int
|
||||
return "lw";
|
||||
}
|
||||
printf(" %s t%d, 0(t%d) # id: type %d\n", op, rd, rd, type);
|
||||
}
|
||||
|
||||
void store_t0(int id) {
|
||||
load_address(1, id);
|
||||
int type = local_type[id];
|
||||
const char* op = "sw"; // int
|
||||
if (type == TYPE_CHAR) {
|
||||
op = "sb";
|
||||
} else if (type & TYPE_PTR_MASK) {
|
||||
op = "sd";
|
||||
const char* store_op_of_type(int type) {
|
||||
if (type & TYPE_PTR_MASK) {
|
||||
return "sd";
|
||||
} else if (type == TYPE_CHAR) {
|
||||
return "sb";
|
||||
} else { // int
|
||||
return "sw";
|
||||
}
|
||||
printf(" %s t0, 0(t1) # id: type %d\n", op, type);
|
||||
}
|
||||
|
||||
const char* store_op(int reg) {
|
||||
return store_op_of_type(reg_type[reg]);
|
||||
}
|
||||
|
||||
// load a non-trivial register into t0, t1 or t2
|
||||
// rd must be one of t0, t1, t2
|
||||
void load(int rd, int reg) {
|
||||
const char* op = load_op(reg);
|
||||
const char* rd_name = reg_name(rd);
|
||||
if (is_overflow(reg)) {
|
||||
load_local_address(rd, overflow[reg]);
|
||||
if (indirection[reg]) {
|
||||
printf(" ld %s, 0(%s)\n", rd_name, rd_name);
|
||||
}
|
||||
reg = rd;
|
||||
}
|
||||
printf(" %s %s, 0(%s) # load non-trivial register\n", op, rd_name, reg_name(reg));
|
||||
}
|
||||
|
||||
// store t0 into a non-trivial register
|
||||
void store_t0(int reg) {
|
||||
const char* op = store_op(reg);
|
||||
if (is_overflow(reg)) {
|
||||
load_local_address(REG_T2, overflow[reg]);
|
||||
if (indirection[reg]) {
|
||||
printf(" ld t2, 0(t2)\n");
|
||||
}
|
||||
reg = REG_T2;
|
||||
}
|
||||
printf(" %s t0, 0(%s) # store non-trivial register\n", op, reg_name(reg));
|
||||
}
|
||||
|
||||
int is_nontrivial(int reg) {
|
||||
return is_overflow(reg) || indirection[reg];
|
||||
}
|
||||
|
||||
void _asm_r(const char* op, int rd, int rs1) {
|
||||
const char* rd_name = reg_name(rd);
|
||||
const char* rs1_name = reg_name(rs1);
|
||||
if (is_nontrivial(rd)) rd_name = "t0";
|
||||
if (is_nontrivial(rs1)) {
|
||||
rs1_name = "t0";
|
||||
load(REG_T0, rs1);
|
||||
}
|
||||
printf(" %s %s, %s\n", op, rd_name, rs1_name);
|
||||
if (is_nontrivial(rd)) {
|
||||
store_t0(rd);
|
||||
}
|
||||
}
|
||||
|
||||
void _asm_rr(const char* op, int rd, int rs1, int rs2) {
|
||||
const char* rd_name = reg_name(rd);
|
||||
const char* rs1_name = reg_name(rs1);
|
||||
const char* rs2_name = reg_name(rs2);
|
||||
if (is_nontrivial(rd)) rd_name = "t0";
|
||||
if (is_nontrivial(rs1)) {
|
||||
rs1_name = "t0";
|
||||
load(REG_T0, rs1);
|
||||
}
|
||||
if (is_nontrivial(rs2)) {
|
||||
rs2_name = "t1";
|
||||
load(REG_T1, rs2);
|
||||
}
|
||||
printf(" %s %s, %s, %s\n", op, rd_name, rs1_name, rs2_name);
|
||||
if (is_nontrivial(rd)) {
|
||||
store_t0(rd);
|
||||
}
|
||||
}
|
||||
|
||||
void _asm_ri(const char* op, int rd, int rs1, int imm) {
|
||||
const char* rd_name = reg_name(rd);
|
||||
const char* rs1_name = reg_name(rs1);
|
||||
if (is_nontrivial(rd)) rd_name = "t0";
|
||||
if (is_nontrivial(rs1)) {
|
||||
rs1_name = "t0";
|
||||
load(REG_T0, rs1);
|
||||
}
|
||||
printf(" %s %s, %s, %d\n", op, rd_name, rs1_name, imm);
|
||||
if (is_nontrivial(rd)) {
|
||||
store_t0(rd);
|
||||
}
|
||||
}
|
||||
|
||||
void _asm_branch(const char* op, int rs1, int label) {
|
||||
const char* rs1_name = reg_name(rs1);
|
||||
if (is_nontrivial(rs1)) {
|
||||
rs1_name = "t0";
|
||||
load(REG_T0, rs1);
|
||||
}
|
||||
printf(" %s %s, L%d\n", op, rs1_name, label);
|
||||
}
|
||||
|
||||
int asm_r(int type, const char* op, int rs1) {
|
||||
int rd = next_reg(type);
|
||||
_asm_r(op, rd, rs1);
|
||||
return rd;
|
||||
}
|
||||
|
||||
int asm_rr(int type, const char* op, int rs1, int rs2) {
|
||||
int rd = next_reg(type);
|
||||
_asm_rr(op, rd, rs1, rs2);
|
||||
return rd;
|
||||
}
|
||||
|
||||
void asm_mv(int rd, int rs1) {
|
||||
_asm_r("mv", rd, rs1);
|
||||
}
|
||||
|
||||
int materialize_t0(int type) {
|
||||
int reg = next_reg(type);
|
||||
store_t0(reg);
|
||||
return reg;
|
||||
int rd = next_reg(type);
|
||||
asm_mv(rd, REG_T0);
|
||||
return rd;
|
||||
}
|
||||
|
||||
int dereference(int reg) {
|
||||
local_type[reg] = local_type[reg] & ~TYPE_PTR_MASK;
|
||||
indirection[reg] = 1;
|
||||
return reg;
|
||||
int materialize_address(int type, int marker) {
|
||||
if (marker == MARKER_ARRAY) {
|
||||
type = type | TYPE_PTR_MASK;
|
||||
}
|
||||
int rd = materialize_t0(TYPE_VOID_PTR);
|
||||
reg_type[rd] = type;
|
||||
indirection[rd] = marker == MARKER_SCALAR;
|
||||
return rd;
|
||||
}
|
||||
|
||||
int lookup_from_slot(int slot) {
|
||||
load_local_address(REG_T0, slot);
|
||||
return materialize_address(local_type[slot], local_marker[slot]);
|
||||
}
|
||||
|
||||
int lookup(int id) {
|
||||
int local = local_table[id];
|
||||
if (local) {
|
||||
if (local_marker[local] == MARKER_ARRAY) {
|
||||
load_address(0, local);
|
||||
return materialize_t0(local_type[local] | TYPE_PTR_MASK);
|
||||
}
|
||||
return local;
|
||||
int slot = local_table[id];
|
||||
if (slot) {
|
||||
return lookup_from_slot(slot);
|
||||
}
|
||||
const char* name = id_table + id_lut[id];
|
||||
if (global_marker[id]) {
|
||||
@ -598,11 +807,7 @@ int lookup(int id) {
|
||||
exit(1);
|
||||
}
|
||||
printf(" la t0, %s # id: %d\n", name, id);
|
||||
int reg = materialize_t0(global_type[id] | TYPE_PTR_MASK);
|
||||
if (global_marker[id] == MARKER_SCALAR) {
|
||||
reg = dereference(reg);
|
||||
}
|
||||
return reg;
|
||||
return materialize_address(global_type[id], global_marker[id]);
|
||||
}
|
||||
eprintf("unresolved identifier: %s\n", name);
|
||||
exit(1);
|
||||
@ -619,65 +824,33 @@ int asm_label(int label) {
|
||||
return label;
|
||||
}
|
||||
|
||||
int is_not_reusable(int rs1, int expected_type) {
|
||||
return indirection[rs1] || local_marker[rs1] != MARKER_TEMP || local_type[rs1] != expected_type;
|
||||
}
|
||||
|
||||
int asm_r(const char* op, int rs1) {
|
||||
load(0, rs1);
|
||||
printf(" %s t0, t0\n", op);
|
||||
int rd = rs1;
|
||||
if (is_not_reusable(rs1, TYPE_INT)) {
|
||||
rd = next_reg(TYPE_INT);
|
||||
}
|
||||
store_t0(rd);
|
||||
return rd;
|
||||
}
|
||||
|
||||
int asm_r_arith(const char* op, int rs1) {
|
||||
if (local_type[rs1] & TYPE_PTR_MASK) {
|
||||
if (reg_type[rs1] & TYPE_PTR_MASK) {
|
||||
eprintf("pointer cannot be arithmetically operated by %s\n", op);
|
||||
exit(1);
|
||||
}
|
||||
return asm_r(op, rs1);
|
||||
}
|
||||
|
||||
int asm_rr(const char* op, int rs1, int rs2) {
|
||||
load(0, rs1);
|
||||
load(1, rs2);
|
||||
printf(" %s t0, t0, t1\n", op);
|
||||
int rd = rs1;
|
||||
if (is_not_reusable(rd, TYPE_INT)) {
|
||||
rd = rs2;
|
||||
if (is_not_reusable(rd, TYPE_INT)) {
|
||||
rd = next_reg(TYPE_INT);
|
||||
}
|
||||
}
|
||||
store_t0(rd);
|
||||
return rd;
|
||||
return asm_r(TYPE_INT, op, rs1);
|
||||
}
|
||||
|
||||
int asm_rr_arith(const char* op, int rs1, int rs2) {
|
||||
if (local_type[rs1] & TYPE_PTR_MASK || local_type[rs2] & TYPE_PTR_MASK) {
|
||||
if (reg_type[rs1] & TYPE_PTR_MASK || reg_type[rs2] & TYPE_PTR_MASK) {
|
||||
eprintf("pointer cannot be arithmetically operated by %s\n", op);
|
||||
exit(1);
|
||||
}
|
||||
return asm_rr(op, rs1, rs2);
|
||||
return asm_rr(TYPE_INT, op, rs1, rs2);
|
||||
}
|
||||
|
||||
int asm_rr_cmp(const char* op, int rs1, int rs2) {
|
||||
// since NULL is virtually 0, it is considered valid example of a pointer comparing with an integer
|
||||
return asm_rr(op, rs1, rs2);
|
||||
// since NULL is virtually 0, it is considered a valid example of a pointer comparing with an integer
|
||||
return asm_rr(TYPE_INT, op, rs1, rs2);
|
||||
}
|
||||
|
||||
void asm_beqz(int rs1, int label) {
|
||||
load(0, rs1);
|
||||
printf(" beqz t0, L%d\n", label);
|
||||
_asm_branch("beqz", rs1, label);
|
||||
}
|
||||
|
||||
void asm_bnez(int rs1, int label) {
|
||||
load(0, rs1);
|
||||
printf(" bnez t0, L%d\n", label);
|
||||
_asm_branch("bnez", rs1, label);
|
||||
}
|
||||
|
||||
void asm_j(int label) {
|
||||
@ -714,15 +887,9 @@ int step_of(int type) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
void asm_shift_t0(const char* op, int type) {
|
||||
if (type == TYPE_INT_PTR) {
|
||||
printf(" %s t0, t0, 2\n", op);
|
||||
}
|
||||
}
|
||||
|
||||
int asm_add(int lhs, int rhs) {
|
||||
int type1 = local_type[lhs] & TYPE_PTR_MASK;
|
||||
int type2 = local_type[rhs] & TYPE_PTR_MASK;
|
||||
int type1 = reg_type[lhs] & TYPE_PTR_MASK;
|
||||
int type2 = reg_type[rhs] & TYPE_PTR_MASK;
|
||||
if (type1 != type2) {
|
||||
int ptr;
|
||||
int idx;
|
||||
@ -733,27 +900,26 @@ int asm_add(int lhs, int rhs) {
|
||||
ptr = rhs;
|
||||
idx = lhs;
|
||||
}
|
||||
int ptr_type = local_type[ptr];
|
||||
int ptr_type = reg_type[ptr];
|
||||
if (ptr_type == TYPE_VOID_PTR) {
|
||||
eprintf("void pointer cannot be arithmetically operated\n");
|
||||
exit(1);
|
||||
}
|
||||
load(0, idx);
|
||||
load(1, ptr);
|
||||
asm_shift_t0("slli", ptr_type);
|
||||
printf(" add t0, t0, t1\n");
|
||||
return materialize_t0(ptr_type);
|
||||
int offset = next_reg(TYPE_INT);
|
||||
int shift = 2 * (ptr_type == TYPE_INT_PTR);
|
||||
_asm_ri("slli", offset, idx, shift);
|
||||
return asm_rr(ptr_type, "add", ptr, offset);
|
||||
}
|
||||
if (type1 && type2) {
|
||||
eprintf("operands of addition cannot be both pointers\n");
|
||||
exit(1);
|
||||
}
|
||||
return asm_rr("add", lhs, rhs);
|
||||
return asm_rr(TYPE_INT, "add", lhs, rhs);
|
||||
}
|
||||
|
||||
int asm_sub(int lhs, int rhs) {
|
||||
int lhs_type = local_type[lhs];
|
||||
int rhs_type = local_type[rhs];
|
||||
int lhs_type = reg_type[lhs];
|
||||
int rhs_type = reg_type[rhs];
|
||||
int type1 = lhs_type & TYPE_PTR_MASK;
|
||||
int type2 = rhs_type & TYPE_PTR_MASK;
|
||||
if (type1 && type2) {
|
||||
@ -765,17 +931,36 @@ int asm_sub(int lhs, int rhs) {
|
||||
eprintf("void pointer cannot be arithmetically operated\n");
|
||||
exit(1);
|
||||
}
|
||||
load(0, lhs);
|
||||
load(1, rhs);
|
||||
printf(" sub t0, t0, t1\n");
|
||||
asm_shift_t0("srai", lhs_type);
|
||||
int difference = asm_rr(TYPE_INT, "sub", lhs, rhs);
|
||||
int shift = 2 * (lhs_type == TYPE_INT_PTR);
|
||||
_asm_ri("slli", REG_T0, difference, shift);
|
||||
return materialize_t0(TYPE_INT);
|
||||
}
|
||||
if (type1) {
|
||||
int neg = asm_r_arith("neg", rhs);
|
||||
return asm_add(lhs, neg);
|
||||
}
|
||||
return asm_rr("sub", lhs, rhs);
|
||||
return asm_rr_arith("sub", lhs, rhs);
|
||||
}
|
||||
|
||||
int dereference(int reg) {
|
||||
if (indirection[reg]) {
|
||||
load(reg, reg);
|
||||
} else {
|
||||
indirection[reg] = 1;
|
||||
}
|
||||
reg_type[reg] = reg_type[reg] & ~TYPE_PTR_MASK;
|
||||
return reg;
|
||||
}
|
||||
|
||||
int addressof(int reg) {
|
||||
if (indirection[reg] && !(reg_type[reg] & TYPE_PTR_MASK)) {
|
||||
reg_type[reg] = reg_type[reg] | TYPE_PTR_MASK;
|
||||
indirection[reg] = 0;
|
||||
} else {
|
||||
printf("cannot take address of this expression");
|
||||
}
|
||||
return reg;
|
||||
}
|
||||
|
||||
// parser
|
||||
@ -811,10 +996,11 @@ int parse_function_call(int id) {
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < arg; ++i) {
|
||||
load(0, args[i]);
|
||||
printf(" mv a%d, t0\n", i);
|
||||
asm_mv(i + REG_A0, args[i]);
|
||||
}
|
||||
// TODO saved by caller
|
||||
printf(" call %s\n", name);
|
||||
// TODO saved by caller
|
||||
int type = global_type[id];
|
||||
if (type != TYPE_VOID) {
|
||||
printf(" mv t0, a0\n");
|
||||
@ -855,20 +1041,16 @@ int parse_postfix_expr() {
|
||||
while (1) {
|
||||
next_token();
|
||||
if (token_type == TOKEN_INC) {
|
||||
int type = local_type[lhs];
|
||||
int type = reg_type[lhs];
|
||||
int reg = next_reg(type);
|
||||
load(0, lhs);
|
||||
store_t0(reg);
|
||||
printf(" addi t0, t0, %d\n", step_of(type));
|
||||
store_t0(lhs);
|
||||
asm_mv(reg, lhs);
|
||||
_asm_ri("addi", lhs, lhs, step_of(type));
|
||||
lhs = reg;
|
||||
} else if (token_type == TOKEN_DEC) {
|
||||
int type = local_type[lhs];
|
||||
int type = reg_type[lhs];
|
||||
int reg = next_reg(type);
|
||||
load(0, lhs);
|
||||
store_t0(reg);
|
||||
printf(" addi t0, t0, -%d\n", step_of(type));
|
||||
store_t0(lhs);
|
||||
asm_mv(reg, lhs);
|
||||
_asm_ri("addi", lhs, lhs, -step_of(type));
|
||||
lhs = reg;
|
||||
} else if (token_type == TOKEN_BRACKET_LEFT) {
|
||||
int rhs = parse_expr();
|
||||
@ -886,16 +1068,15 @@ int parse_prefix_expr() {
|
||||
next_token();
|
||||
if (token_type == TOKEN_AND) {
|
||||
int reg = parse_postfix_expr();
|
||||
int type = local_type[reg];
|
||||
int type = reg_type[reg];
|
||||
if (type & TYPE_PTR_MASK) {
|
||||
eprintf("cannot take address of a pointer\n");
|
||||
exit(1);
|
||||
}
|
||||
load_address(0, reg);
|
||||
return materialize_t0(type | TYPE_PTR_MASK);
|
||||
return addressof(reg);
|
||||
} else if (token_type == TOKEN_STAR) {
|
||||
int reg = parse_postfix_expr();
|
||||
int type = local_type[reg];
|
||||
int type = reg_type[reg];
|
||||
if (!(type & TYPE_PTR_MASK)) {
|
||||
eprintf("cannot dereference a non-pointer\n");
|
||||
exit(1);
|
||||
@ -904,8 +1085,7 @@ int parse_prefix_expr() {
|
||||
eprintf("cannot dereference void pointer\n");
|
||||
exit(1);
|
||||
}
|
||||
load(0, reg);
|
||||
return dereference(materialize_t0(type));
|
||||
return dereference(reg);
|
||||
} else if (token_type == TOKEN_MINUS) {
|
||||
int reg = parse_postfix_expr();
|
||||
return asm_r_arith("neg", reg);
|
||||
@ -914,18 +1094,14 @@ int parse_prefix_expr() {
|
||||
return asm_r_arith("not", reg);
|
||||
} else if (token_type == TOKEN_NOT) {
|
||||
int reg = parse_postfix_expr();
|
||||
return asm_r("seqz", reg);
|
||||
return asm_r(TYPE_INT, "seqz", reg);
|
||||
} else if (token_type == TOKEN_INC) {
|
||||
int reg = parse_postfix_expr();
|
||||
load(0, reg);
|
||||
printf(" addi t0, t0, %d\n", step_of(local_type[reg]));
|
||||
store_t0(reg);
|
||||
_asm_ri("addi", reg, reg, step_of(reg_type[reg]));
|
||||
return reg;
|
||||
} else if (token_type == TOKEN_DEC) {
|
||||
int reg = parse_postfix_expr();
|
||||
load(0, reg);
|
||||
printf(" addi t0, t0, -%d\n", step_of(local_type[reg]));
|
||||
store_t0(reg);
|
||||
_asm_ri("addi", reg, reg, -step_of(reg_type[reg]));
|
||||
return reg;
|
||||
} else {
|
||||
unget_token();
|
||||
@ -1003,11 +1179,11 @@ int parse_cmp_expr() {
|
||||
} else if (token_type == TOKEN_LE) {
|
||||
int rhs = parse_shift_expr();
|
||||
int sgt = asm_rr_cmp("sgt", lhs, rhs);
|
||||
lhs = asm_r("seqz", sgt);
|
||||
lhs = asm_r(TYPE_INT, "seqz", sgt);
|
||||
} else if (token_type == TOKEN_GE) {
|
||||
int rhs = parse_shift_expr();
|
||||
int slt = asm_rr_cmp("slt", lhs, rhs);
|
||||
lhs = asm_r("seqz", slt);
|
||||
lhs = asm_r(TYPE_INT, "seqz", slt);
|
||||
} else {
|
||||
unget_token();
|
||||
break;
|
||||
@ -1023,11 +1199,11 @@ int parse_eq_expr() {
|
||||
if (token_type == TOKEN_EQ) {
|
||||
int rhs = parse_cmp_expr();
|
||||
int xor0 = asm_rr_cmp("xor", lhs, rhs);
|
||||
lhs = asm_r("seqz", xor0);
|
||||
lhs = asm_r(TYPE_INT, "seqz", xor0);
|
||||
} else if (token_type == TOKEN_NE) {
|
||||
int rhs = parse_cmp_expr();
|
||||
int xor0 = asm_rr_cmp("xor", lhs, rhs);
|
||||
lhs = asm_r("snez", xor0);
|
||||
lhs = asm_r(TYPE_INT, "snez", xor0);
|
||||
} else {
|
||||
unget_token();
|
||||
break;
|
||||
@ -1084,48 +1260,58 @@ int parse_bitwise_or_expr() {
|
||||
|
||||
int parse_logical_and_expr() {
|
||||
int lhs = parse_bitwise_or_expr();
|
||||
int label = next_label();
|
||||
int label_used = 0;
|
||||
int logical = 0;
|
||||
int label;
|
||||
int result;
|
||||
while (1) {
|
||||
next_token();
|
||||
if (token_type == TOKEN_LAND) {
|
||||
lhs = asm_r("snez", lhs);
|
||||
asm_beqz(lhs, label);
|
||||
if (!logical) {
|
||||
logical = 1;
|
||||
label = next_label();
|
||||
result = next_reg(TYPE_INT);
|
||||
_asm_r("snez", result, lhs);
|
||||
}
|
||||
asm_beqz(result, label);
|
||||
int rhs = parse_bitwise_or_expr();
|
||||
rhs = asm_r("snez", rhs);
|
||||
lhs = asm_rr("and", lhs, rhs);
|
||||
label_used = 1;
|
||||
_asm_r("snez", result, rhs);
|
||||
} else {
|
||||
unget_token();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (label_used) {
|
||||
if (logical) {
|
||||
asm_label(label);
|
||||
return result;
|
||||
}
|
||||
return lhs;
|
||||
}
|
||||
|
||||
int parse_logical_or_expr() {
|
||||
int lhs = parse_logical_and_expr();
|
||||
int label = next_label();
|
||||
int label_used = 0;
|
||||
int logical = 0;
|
||||
int label;
|
||||
int result;
|
||||
while (1) {
|
||||
next_token();
|
||||
if (token_type == TOKEN_LOR) {
|
||||
lhs = asm_r("snez", lhs);
|
||||
asm_bnez(lhs, label);
|
||||
if (!logical) {
|
||||
logical = 1;
|
||||
label = next_label();
|
||||
result = next_reg(TYPE_INT);
|
||||
_asm_r("snez", result, lhs);
|
||||
}
|
||||
asm_bnez(result, label);
|
||||
int rhs = parse_logical_and_expr();
|
||||
rhs = asm_r("snez", rhs);
|
||||
lhs = asm_rr("or", lhs, rhs);
|
||||
label_used = 1;
|
||||
_asm_r("snez", result, rhs);
|
||||
} else {
|
||||
unget_token();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (label_used) {
|
||||
if (logical) {
|
||||
asm_label(label);
|
||||
return result;
|
||||
}
|
||||
return lhs;
|
||||
}
|
||||
@ -1135,8 +1321,7 @@ int parse_assign_expr() {
|
||||
next_token();
|
||||
if (token_type == TOKEN_ASSIGN) {
|
||||
int rhs = parse_assign_expr();
|
||||
load(0, rhs);
|
||||
store_t0(lhs);
|
||||
asm_mv(lhs, rhs);
|
||||
return lhs;
|
||||
} else {
|
||||
unget_token();
|
||||
@ -1165,10 +1350,9 @@ void parse_local_variable(int type) {
|
||||
int size = token_data;
|
||||
expect_token(TOKEN_BRACKET_RIGHT);
|
||||
declare_local_array(id, type, size);
|
||||
next_token();
|
||||
} else {
|
||||
declare_local(id, type);
|
||||
return;
|
||||
}
|
||||
int slot = declare_local(id, type);
|
||||
if (token_type == TOKEN_SEMICOLON) {
|
||||
unget_token();
|
||||
return;
|
||||
@ -1176,8 +1360,13 @@ void parse_local_variable(int type) {
|
||||
unget_token();
|
||||
expect_token(TOKEN_ASSIGN);
|
||||
int reg = parse_expr();
|
||||
load(0, reg);
|
||||
store_t0(local_table[id]);
|
||||
if (type != reg_type[reg]) {
|
||||
eprintf("type mismatch in assignment\n");
|
||||
exit(1);
|
||||
}
|
||||
asm_mv(REG_T0, reg);
|
||||
load_local_address(REG_T2, slot);
|
||||
printf(" %s t0, 0(t2)\n", store_op_of_type(type));
|
||||
}
|
||||
|
||||
void parse_stmt();
|
||||
@ -1290,9 +1479,8 @@ void parse_stmt() {
|
||||
return;
|
||||
}
|
||||
unget_token();
|
||||
int reg = parse_expr();
|
||||
load(0, reg);
|
||||
printf(" mv a0, t0\n");
|
||||
int rs1 = parse_expr();
|
||||
asm_mv(REG_A0, rs1);
|
||||
asm_j(epilog_label);
|
||||
} else if (token_type == TOKEN_BREAK) {
|
||||
int label = asm_get_break_label();
|
||||
@ -1335,7 +1523,7 @@ void parse_function(const char* name) {
|
||||
}
|
||||
int arg_type = parse_type();
|
||||
if (arg_type < 0 || arg_type == TYPE_VOID) {
|
||||
eprintf("unexpected a non-void argument type");
|
||||
eprintf("unexpected a non-void argument type: %d\n", arg_type);
|
||||
exit(1);
|
||||
}
|
||||
expect_token(TOKEN_ID);
|
||||
@ -1392,16 +1580,23 @@ void parse_function(const char* name) {
|
||||
asm_addi("sp", "sp", -frame_size);
|
||||
asm_sd("ra", frame_size - 8, "sp");
|
||||
asm_sd("fp", frame_size - 16, "sp");
|
||||
for (int reg = REG_S2; reg <= REG_S11; ++reg) {
|
||||
asm_sd(reg_name(reg), frame_size - reg * 8 + 15 * 8, "sp");
|
||||
}
|
||||
asm_addi("fp", "sp", frame_size);
|
||||
for (int i = 0; i < arg; ++i) {
|
||||
printf(" mv t0, a%d\n", i);
|
||||
store_t0(args[i]);
|
||||
int slot = args[i];
|
||||
load_local_address(REG_T2, slot);
|
||||
printf(" %s a%d, 0(t2)\n", store_op_of_type(local_type[slot]), i);
|
||||
}
|
||||
asm_j(label);
|
||||
// epilog
|
||||
asm_label(epilog_label);
|
||||
asm_ld("fp", frame_size - 16, "sp");
|
||||
asm_ld("ra", frame_size - 8, "sp");
|
||||
asm_ld("fp", frame_size - 16, "sp");
|
||||
for (int reg = REG_S2; reg <= REG_S11; ++reg) {
|
||||
asm_ld(reg_name(reg), frame_size - reg * 8 + 15 * 8, "sp");
|
||||
}
|
||||
asm_addi("sp", "sp", frame_size);
|
||||
printf(" ret\n");
|
||||
}
|
||||
@ -1496,6 +1691,7 @@ void dump_string_table() {
|
||||
}
|
||||
|
||||
int main() {
|
||||
eprintf("start compiling...\n");
|
||||
parse_top_level();
|
||||
dump_string_table();
|
||||
return 0;
|
||||
|
2
boot.sh
2
boot.sh
@ -5,7 +5,7 @@ gcc ../boot.c ../boot-lib.c -o gcc.out &&
|
||||
riscv64-linux-gnu-gcc-12 -static boot1.s ../boot-lib.c -o boot1.out &&
|
||||
qemu-riscv64 boot1.out < boot-all.c > boot2.s &&
|
||||
riscv64-linux-gnu-gcc-12 -static boot2.s ../boot-lib.c -o boot2.out &&
|
||||
qemu-riscv64 boot2.out < boot-all.c > boot3.s &&
|
||||
qemu-riscv64 boot2.out < boot-all.c > boot3.s
|
||||
cmp --silent boot1.s boot2.s && echo "boot1.s == boot2.s" || echo "boot1.s != boot2.s"
|
||||
cmp --silent boot2.s boot3.s && echo "boot2.s == boot3.s" || echo "boot2.s != boot3.s"
|
||||
cmp --silent boot1.s boot3.s && echo "boot1.s == boot3.s" || echo "boot1.s != boot3.s"
|
||||
|
Loading…
Reference in New Issue
Block a user