compiler

Unnamed Compiled Systems Language Project
git clone http://frotz.net/git/compiler.git
Log | Files | Refs

commit a4fff190317e510032e697fc074c209d882993ae
parent e660e0c77e0b9b89bbde39585605dd806e5d79d7
Author: Brian Swetland <swetland@frotz.net>
Date:   Fri, 13 Mar 2020 20:56:08 -0700

compiler: pointers-to-structs

- gen_deref_ptr() and gen_get_ptr() for "." and "&" ops
- add a tracing facility to gen_*() (-v option to compiler) to
  make diagnosing code generation mishaps a bit easier
- gen_load() and gen_load_reg() handle iRegInd items correctly now
- gen_store() releases registers for the address item as welll now
  (since now the address may be in a temporary)
- flag an internal error if our register allocator shows registers
  still in use when we go to generate the epilogue
- generic print_item() and print_type() debug functions
- tidy: tnames[ctx.tok & 0x7f] -> tnames[ctx.tok] in a few places
  now that we no longer play weird tricks with these values
- updated test/1040-structs

Diffstat:
Msrc/compiler.c | 184+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------
Mtest/1040-structs.log | 2++
Mtest/1040-structs.src | 13+++++++++++++
3 files changed, 186 insertions(+), 13 deletions(-)

diff --git a/src/compiler.c b/src/compiler.c @@ -13,6 +13,8 @@ #include <unistd.h> #include <sys/stat.h> +#include "risc5.h" + #define FNMAXARGS 8 #define nil 0 @@ -215,6 +217,7 @@ const char* type_id_tab[] = { "void", "byte", "bool", "int32", "nil", "*", "[]", "[]", "struct", "func", "undef", }; +void print_type(Type t); // ------------------------------------------------------------------ @@ -236,6 +239,9 @@ enum { // r a b iFunc, }; +const char* item_id_tab[] = { "Const", "Reg", "RegInd", "Comp", "Func" }; +void print_item(Item x); + // Item Flags #define ifReadOnly 1 @@ -293,6 +299,11 @@ struct CtxRec { CtxRec ctx; +bool TRACE_CODEGEN = false; + +void gen_trace(const char* fn, Item x, Item y); +void gen_trace_n(const char* fn, u32 n, Item x, Item y); +void gen_trace_code(const char* msg, u32 pc); // initialize x as appropriate for obj // (which must be a local or global variable or function) @@ -316,6 +327,12 @@ void gen_unary_op(u32 op, Item x); // stores val into var, consuming both void gen_store(Item val, Item var); +// consume ptr item, transforming into thing-pointed-at +void gen_deref_ptr(Item x); + +// consume a memory-based item, transforming into an address (ptr) +void gen_get_ptr(Item x); + // release any registers or other resources held by this item void gen_discard(Item val); @@ -783,17 +800,17 @@ void print() { case tIDN: printf("@%s ", ctx.tmp); break; case tEOL: printf("\n"); break; case tSTR: printstr(ctx.tmp); break; - default: printf("%s ", tnames[ctx.tok & 0x7F]); break; + default: printf("%s ", tnames[ctx.tok]); break; } } void expected(const char* what) { - error("expected %s, found %s", what, tnames[ctx.tok & 0x7F]); + error("expected %s, found %s", what, tnames[ctx.tok]); } void expect(token_t tok) { if (ctx.tok != tok) { - error("expected %s, found %s", tnames[tok], tnames[ctx.tok & 0x7F]); + error("expected %s, found %s", tnames[tok], tnames[ctx.tok]); } } @@ -894,7 +911,7 @@ void parse_expr(Item x); String parse_name(const char* what) { if (ctx.tok != tIDN) { - error("expected %s, found %s", what, tnames[ctx.tok & 0x7F]); + error("expected %s, found %s", what, tnames[ctx.tok]); } String str = make_string(ctx.tmp, strlen(ctx.tmp)); next(); @@ -975,8 +992,15 @@ void parse_primary_expr(Item x) { } else if (ctx.tok == tDOT) { next(); String name = parse_name("field name"); - dereference(x, name); - //error("<TODO> field deref"); + if (x->type->kind == tRecord) { + dereference(x, name); + } else if ((x->type->kind == tPointer) && + (x->type->base->kind == tRecord)) { + gen_deref_ptr(x); + dereference(x, name); + } else { + error("can only use '.' with struct or pointer-to-struct"); + } } else if (ctx.tok == tOBRACK) { next(); require(tCBRACK); @@ -1002,7 +1026,8 @@ void parse_unary_expr(Item x) { } } else if (ctx.tok == tAMP) { next(); - error("<TODO> get pointer"); + parse_unary_expr(x); + gen_get_ptr(x); } else { parse_primary_expr(x); } @@ -1653,6 +1678,10 @@ void parse_program() { #define tmp_reg_first 8 #define tmp_reg_last 11 +bool is_tmp_reg(u32 n) { + return (n >= tmp_reg_first) && (n <= tmp_reg_last); +} + u32 get_reg_tmp() { u32 n = tmp_reg_first; while (n <= tmp_reg_last) { @@ -1680,6 +1709,7 @@ void put_reg(u32 r) { void emit(u32 ins) { ctx.code[ctx.pc / 4] = ins; + gen_trace_code("", ctx.pc); ctx.pc = ctx.pc + 4; } @@ -1792,6 +1822,7 @@ void gen_item_from_obj(Item x, Object obj) { } else { error("unsupported identifier"); } + gen_trace("item_from_obj<<<", x, nil); } @@ -1809,11 +1840,13 @@ bool patch_last_load(u32 oldr, u32 newr) { return false; } ctx.code[(ctx.pc - 4) / 4] = (ins & 0xF0FFFFFF) | (newr << 24); + gen_trace_code("patch_last_load()", (ctx.pc - 4)); return true; } // load the value of an item into a specific register void gen_load_reg(Item x, u32 r) { + gen_trace_n("load_reg", r, x, nil); if (x->kind == iReg) { if (x->r != r) { if (patch_last_load(x->r, r)) { @@ -1827,14 +1860,19 @@ void gen_load_reg(Item x, u32 r) { emit_mov(r, x->a); } else if (x->kind == iRegInd) { emit_mem(LDW, r, x->r, x->a); + if (x->r != r) { + put_reg(x->r); + } } else { error("gen_load failed (kind %u)", x->kind); } x->kind = iReg; x->r = r; + gen_trace("load_reg<<<", x, nil); } void gen_discard(Item x) { + gen_trace("discard", x, nil); if (x->kind == iReg) { put_reg(x->r); } @@ -1843,22 +1881,54 @@ void gen_discard(Item x) { // convert an item to value-in-register format // if it's not already in that format void gen_load(Item x) { - if (x->kind != iReg) { + if ((x->kind == iRegInd) && is_tmp_reg(x->r)) { + gen_load_reg(x, x->r); + } else if (x->kind != iReg) { gen_load_reg(x, get_reg_tmp()); } } -void gen_store(Item val, Item var) { +void gen_store(Item val, Item adr) { + gen_trace("gen_store", val, adr); gen_load(val); - if (var->kind == iRegInd) { - emit_mem(STW, val->r, var->r, var->a); + if (adr->kind == iRegInd) { + emit_mem(STW, val->r, adr->r, adr->a); put_reg(val->r); + put_reg(adr->r); } else { error("gen_store: invalid target"); } } +void gen_deref_ptr(Item x) { + gen_trace("deref_ptr", x, nil); + gen_load(x); + if (x->kind != iReg) { + error("internal - ptr deref failed"); + } + x->type = x->type->base; + x->kind = iRegInd; + x->a = 0; + gen_trace("deref_ptr<<<", x, nil); +} + +void gen_get_ptr(Item x) { + gen_trace("get_ptr", x, nil); + if (x->kind != iRegInd) { + error("internal - get ptr failed"); + } + x->kind = iReg; + if (x->a != 0) { + emit_opi_n(ADD, x->r, x->r, x->a); + x->a = 0; + } + // TODO: can we cache these or be sure to recycle them later? + x->type = make_type(tPointer, x->type, nil, nil, 0, 4); + gen_trace("get_ptr<<<", x, nil); +} + u32 gen_branch_cond(Item x, bool sense) { + gen_trace_n("branch_cond", sense, x, nil); u32 cc; if (x->kind == iComp) { if (sense == false) { @@ -1885,15 +1955,18 @@ u32 gen_branch_cond(Item x, bool sense) { } u32 gen_branch_fwd() { + gen_trace("branch_fwd", nil, nil); emit_bi(AL, 0); return ctx.pc - 4; } void gen_branch_back(u32 addr) { + gen_trace_n("branch_back", addr, nil, nil); emit_bi(AL, (addr - ctx.pc - 4) >> 2); } void gen_return(Item x) { + gen_trace("return", x, nil); if (x->type != ctx.type_void) { gen_load_reg(x, R0); } @@ -1902,6 +1975,7 @@ void gen_return(Item x) { } void gen_param(u32 n, Item val) { + gen_trace_n("param", n, val, nil); if (n > 7) { error("gen_param - too many parameters"); } @@ -1909,6 +1983,7 @@ void gen_param(u32 n, Item val) { } void gen_builtin(u32 id) { + gen_trace_n("builtin", id, nil, nil); if (id == biPrintHex32) { emit_mov(1, 0xFFFF0000); // MOV R1, IOBASE emit_mem(STW, 0, 1, 0x104); // SW R0, [R1, 0x104] @@ -1918,6 +1993,7 @@ void gen_builtin(u32 id) { } void gen_save_regs() { + gen_trace("save_regs", nil, nil); u32 n = tmp_reg_first; u32 off = ctx.spill_stack; while (n <= tmp_reg_last) { @@ -1930,6 +2006,7 @@ void gen_save_regs() { } void gen_restore_regs() { + gen_trace("restore_regs", nil, nil); u32 n = tmp_reg_first; u32 off = ctx.spill_stack; while (n <= tmp_reg_last) { @@ -1942,6 +2019,7 @@ void gen_restore_regs() { } void gen_call(Item x) { + gen_trace("call", x, nil); gen_save_regs(); if (x->type->obj->flags & ofBuiltin) { // OPT: not all builtins will require save/restore regs @@ -1971,6 +2049,7 @@ void gen_call(Item x) { } void gen_add_op(u32 op, Item x, Item y) { + gen_trace_n("add_op", op, x, y); op = add_op_to_ins(op); if ((x->kind == iConst) && (y->kind == iConst)) { // XC = XC op YC @@ -2000,6 +2079,7 @@ void gen_add_op(u32 op, Item x, Item y) { } void gen_mul_op(u32 op, Item x, Item y) { + gen_trace_n("mul_op", op, x, y); op = mul_op_to_ins(op); if ((x->kind == iConst) && (y->kind == iConst)) { // XC = XC op YC @@ -2050,6 +2130,7 @@ void gen_mul_op(u32 op, Item x, Item y) { } void gen_rel_op(u32 op, Item x, Item y) { + gen_trace_n("rel_op", op, x, y); gen_load(x); gen_load(y); @@ -2061,6 +2142,7 @@ void gen_rel_op(u32 op, Item x, Item y) { } void gen_unary_op(u32 op, Item x) { + gen_trace_n("unary_op", op, x, nil); if (x->kind == iConst) { if (op == tMINUS) { x->a = - x->a; @@ -2099,6 +2181,7 @@ void fixup_branch_fwd(u32 addr) { u32 off = (ctx.pc - addr - 4) >> 2; u32 ins = ctx.code[addr >> 2] & 0xFF000000; ctx.code[addr >> 2] = ins | (off & 0x00FFFFFF); + gen_trace_code("fixup_branch_fwd()", addr); } // note that we have forward branches to this pc @@ -2115,6 +2198,7 @@ void fixup_branches_fwd(Fixup fixup) { } void gen_prologue(Object fn) { + gen_trace("prologue", nil, nil); fn->value = ctx.pc; emit_opi(SUB, SP, SP, 4 + fn->type->len * 4); emit_mem(STW, LR, SP, 0); @@ -2136,6 +2220,18 @@ void gen_prologue(Object fn) { } void gen_epilogue(Object fn) { + gen_trace("epilogue", nil, nil); + if (ctx.regbits) { + u32 n = tmp_reg_first; + while (n <= tmp_reg_last) { + if (ctx.regbits & (1 << n)) { + fprintf(stderr, "R%u ", n); + } + n++; + } + fprintf(stderr,"\n"); + error("internal - registers reserved in epilogue"); + } if (ctx.local_stack > 0xFFFF) { error("using too much stack"); } @@ -2143,6 +2239,7 @@ void gen_epilogue(Object fn) { // patch prologue u32 ins = ctx.code[fn->value / 4]; ctx.code[fn->value / 4] = (ins & 0xFFFF0000) | ctx.local_stack; + gen_trace_code("patch_prologue()", fn->value); // emit epilogue emit_mem(LDW, LR, SP, 0); @@ -2152,11 +2249,13 @@ void gen_epilogue(Object fn) { void gen_start() { + gen_trace("start", nil, nil); emit_mov(SB, 0); // placeholder SB load emit_bi(AL, 0); // placeholder branch to init } void gen_end() { + gen_trace("end", nil, nil); String str = make_string("start", 5); Object obj = find(str); while (obj != nil) { @@ -2199,8 +2298,6 @@ void gen_write(const char* outname) { close(fd); } -#include "risc5.h" - void gen_listing(const char* listfn, const char* srcfn) { FILE* fin = fopen(srcfn, "r"); if (fin == NULL) { @@ -2286,6 +2383,65 @@ void dump_context() { } } +void print_type(Type type) { + if (type->kind == tArray) { + fprintf(stderr, "[%u]", type->len); + print_type(type->base); + } else if (type->kind == tPointer) { + fprintf(stderr, "*"); + print_type(type->base); + } else if (type->kind == tRecord) { + if (type->obj != nil) { + fprintf(stderr, "{}%s", type->obj->name->text); + } else { + fprintf(stderr, "{}\n"); + } + } else { + fprintf(stderr, "%s", type_id_tab[type->kind]); + } +} + +void print_item(Item x) { + fprintf(stderr, "<%s: r=%d,a=%d,b=%d,t=", + item_id_tab[x->kind], x->r, x->a, x->b); + print_type(x->type); + fprintf(stderr, ">"); +} + +void gen_trace(const char* fn, Item x, Item y) { + if (TRACE_CODEGEN) { + fprintf(stderr, "gen_%-17s", fn); + if (x != nil) { + print_item(x); + } + if (y != nil) { + fprintf(stderr, ", "); + print_item(y); + } + fprintf(stderr, "\n"); + } +} +void gen_trace_n(const char* fn, u32 n, Item x, Item y) { + if (TRACE_CODEGEN) { + fprintf(stderr, "gen_%-17s0x%x, ", fn, n); + if (x != nil) { + print_item(x); + } + if (y != nil) { + fprintf(stderr, ", "); + print_item(y); + } + fprintf(stderr, "\n"); + } +} +void gen_trace_code(const char* msg, u32 pc) { + if (TRACE_CODEGEN) { + u32 ins = ctx.code[pc >> 2]; + char buf[64]; + risc5dis(pc, ins, buf); + fprintf(stderr, "gen_code '%08x: %08x %s' %s\n", pc, ins, buf, msg); + } +} // ================================================================ int main(int argc, char **argv) { @@ -2314,6 +2470,8 @@ int main(int argc, char **argv) { argv++; } else if (!strcmp(argv[1], "-p")) { dump = true; + } else if (!strcmp(argv[1], "-v")) { + TRACE_CODEGEN = true; } else if (!strcmp(argv[1], "-A")) { ctx.flags |= cfAbortOnError; } else if (argv[1][0] == '-') { diff --git a/test/1040-structs.log b/test/1040-structs.log @@ -2,4 +2,6 @@ D 0000002d D 00000011 D 0000007b D 000001c8 +D 00000080 +D 000001cb X 00000000 diff --git a/test/1040-structs.src b/test/1040-structs.src @@ -9,7 +9,18 @@ type Line struct { end Point, }; +func add(a *Point, b *Point) { + a.x = a.x + b.x; + a.y = a.y + b.y; +} + +func print(p *Point) { + _hexout_(p.x); + _hexout_(p.y); +} + var p0 Point = { x: 45, y: 17 }; +var p1 Point = { x: 5, y: 3 }; func start() i32 { _hexout_(p0.x); @@ -18,5 +29,7 @@ func start() i32 { p0.y = 456; _hexout_(p0.x); _hexout_(p0.y); + add(&p1, &p0); + print(&p1); return 0; }