diff --git a/boot.c b/boot.c index 5fbab63..3dbf328 100644 --- a/boot.c +++ b/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]) { - if (check_itype_immediate(offset)) { - printf(" ld t%d, %d(fp) # indirection\n", rd, 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); - } +// 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(" addi %s, fp, %d\n", rd_name, offset); } 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); + } +} + +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"; + } +} + +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"; + } +} + +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 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"; +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); } - 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"; +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 t0, 0(t1) # id: type %d\n", op, type); + 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; diff --git a/boot.sh b/boot.sh index 91909ec..c4a4ecb 100644 --- a/boot.sh +++ b/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"