From db08fcbd27eda7032cc9098e1a40638e424d0531 Mon Sep 17 00:00:00 2001 From: Mid <> Date: Thu, 17 Jul 2025 21:02:10 +0300 Subject: [PATCH] End of an Era --- Makefile | 6 +- README.md | 14 +- examples/Allocator.nct | 5 + {tests => examples}/Exporter.nct | 0 examples/FarPointer.nct | 8 + {tests => examples}/HTTPFileServer.nct | 0 {tests => examples}/Importer.nct | 0 {tests => examples}/IrregularAllocation.nct | 0 {tests => examples}/ListDLC.nct | 0 {tests => examples}/ListS.nct | 0 examples/ScalarReplacementOptimization.nct | 14 + {tests => examples}/UDPEcho.nct | 0 {tests => examples}/UserListDLC.nct | 3 +- {tests => examples}/arrays.nct | 0 {tests => examples}/bf.nct | 0 {tests => examples}/bit-rounding.nct | 0 {tests => examples}/cat.nct | 0 examples/countwords.nct | 48 +++ {tests => examples}/funcdefs.nct | 0 {tests => examples}/functions.nct | 0 {tests => examples}/if.nct | 0 {tests => examples}/loopregalloc.nct | 4 +- {tests => examples}/lvl1localrecord.nct | 0 {tests => examples}/lvl1symbolrecord.nct | 0 {tests => examples}/lvl2localrecord.nct | 0 {tests => examples}/lvl2symbolrecord.nct | 0 {tests => examples}/mandelbrot.b | 0 {tests => examples}/mbr.nct | 0 {tests => examples}/ops.nct | 0 examples/parsenum.nct | 23 ++ {tests => examples}/scoping.nct | 0 {tests => examples}/spill.nct | 0 {tests => examples}/stack.nct | 0 src/ast.c | 342 ++++++++++++++++---- src/ast.h | 5 + src/ntc.c | 1 + src/parse.c | 85 ++++- src/scope.h | 10 +- src/types.h | 5 + src/x86/arch.c | 22 +- src/x86/arch.h | 29 +- src/x86/cg.c | 116 ++++--- src/x86/dumberdowner.c | 20 +- 43 files changed, 588 insertions(+), 172 deletions(-) create mode 100644 examples/Allocator.nct rename {tests => examples}/Exporter.nct (100%) create mode 100644 examples/FarPointer.nct rename {tests => examples}/HTTPFileServer.nct (100%) rename {tests => examples}/Importer.nct (100%) rename {tests => examples}/IrregularAllocation.nct (100%) rename {tests => examples}/ListDLC.nct (100%) rename {tests => examples}/ListS.nct (100%) create mode 100644 examples/ScalarReplacementOptimization.nct rename {tests => examples}/UDPEcho.nct (100%) rename {tests => examples}/UserListDLC.nct (92%) rename {tests => examples}/arrays.nct (100%) rename {tests => examples}/bf.nct (100%) rename {tests => examples}/bit-rounding.nct (100%) rename {tests => examples}/cat.nct (100%) create mode 100644 examples/countwords.nct rename {tests => examples}/funcdefs.nct (100%) rename {tests => examples}/functions.nct (100%) rename {tests => examples}/if.nct (100%) rename {tests => examples}/loopregalloc.nct (82%) rename {tests => examples}/lvl1localrecord.nct (100%) rename {tests => examples}/lvl1symbolrecord.nct (100%) rename {tests => examples}/lvl2localrecord.nct (100%) rename {tests => examples}/lvl2symbolrecord.nct (100%) rename {tests => examples}/mandelbrot.b (100%) rename {tests => examples}/mbr.nct (100%) rename {tests => examples}/ops.nct (100%) create mode 100644 examples/parsenum.nct rename {tests => examples}/scoping.nct (100%) rename {tests => examples}/spill.nct (100%) rename {tests => examples}/stack.nct (100%) diff --git a/Makefile b/Makefile index 007224f..3b938dc 100644 --- a/Makefile +++ b/Makefile @@ -8,15 +8,15 @@ DEPS := $(patsubst build/%.o,build/%.d,$(OBJECTS)) PREFIX = /usr/local -CFLAGS = $(if $(DEBUGA),-DDEBUG=1,) -Wall $(if $(ASAN),-fsanitize=address,) -fno-PIE -no-pie -std=gnu11 $(if $(DEBUG),-O0 -g,-Os -s) -fms-extensions -Isrc -Wno-array-bounds -MMD -MP -flto +CFLAGS = $(if $(DEBUGA),-DDEBUG=1,) -Wall $(if $(ASAN),-fsanitize=address,) -fno-PIE -no-pie -std=gnu11 $(if $(DEBUG),-O0 -g,-Os -s) -fms-extensions -Isrc -Wno-array-bounds -MMD -MP -flto -Wno-format-zero-length .PHONY: install clean build/%.o: src/%.c - cc -c $(CFLAGS) -o $@ $< + $(CC) -c $(CFLAGS) -o $@ $< ntc: $(OBJECTS) - cc $(CFLAGS) -o ntc $(OBJECTS) + $(CC) $(CFLAGS) -o ntc $(OBJECTS) install: ntc cp ./ntc $(PREFIX)/bin diff --git a/README.md b/README.md index c7759a0..d7cc083 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,19 @@ This will be ported into a man page later: Unknown arguments are ignored. -# Example +# Example 1 + + $ ntc < tests/parsenum.nct > out.asm + $ nasm -f elf -o out.o out.asm + $ ld -dynamic-linker /lib/ld-linux.so.2 -m elf_i386 -o parsenum out.o -lc + $ printf "123" | ./parsenum + $ echo $? + 123 + $ printf "05" | ./parsenum + $ echo $? + 5 + +# Example 2 $ ntc < tests/bf.nct > out.asm $ nasm -f elf -o out.o out.asm diff --git a/examples/Allocator.nct b/examples/Allocator.nct new file mode 100644 index 0000000..ca5d2aa --- /dev/null +++ b/examples/Allocator.nct @@ -0,0 +1,5 @@ +record Allocator { + u8* userdata; + u8*(u8* userdata, u8* original, u32 size) realloc; +} + diff --git a/tests/Exporter.nct b/examples/Exporter.nct similarity index 100% rename from tests/Exporter.nct rename to examples/Exporter.nct diff --git a/examples/FarPointer.nct b/examples/FarPointer.nct new file mode 100644 index 0000000..1d027a7 --- /dev/null +++ b/examples/FarPointer.nct @@ -0,0 +1,8 @@ +u8 @far* x; +u8 @far* y; + +loop { + u8 v = *x; + *y = v; + x.offset = x.offset + 1; +} diff --git a/tests/HTTPFileServer.nct b/examples/HTTPFileServer.nct similarity index 100% rename from tests/HTTPFileServer.nct rename to examples/HTTPFileServer.nct diff --git a/tests/Importer.nct b/examples/Importer.nct similarity index 100% rename from tests/Importer.nct rename to examples/Importer.nct diff --git a/tests/IrregularAllocation.nct b/examples/IrregularAllocation.nct similarity index 100% rename from tests/IrregularAllocation.nct rename to examples/IrregularAllocation.nct diff --git a/tests/ListDLC.nct b/examples/ListDLC.nct similarity index 100% rename from tests/ListDLC.nct rename to examples/ListDLC.nct diff --git a/tests/ListS.nct b/examples/ListS.nct similarity index 100% rename from tests/ListS.nct rename to examples/ListS.nct diff --git a/examples/ScalarReplacementOptimization.nct b/examples/ScalarReplacementOptimization.nct new file mode 100644 index 0000000..8c7c629 --- /dev/null +++ b/examples/ScalarReplacementOptimization.nct @@ -0,0 +1,14 @@ +record X { + u32 a; + u32 b; +} + +main: u0() -> { + X x; + x.a = 5; + x.b = 6; + + u32 c = x.a + x.b; + + return; +}; diff --git a/tests/UDPEcho.nct b/examples/UDPEcho.nct similarity index 100% rename from tests/UDPEcho.nct rename to examples/UDPEcho.nct diff --git a/tests/UserListDLC.nct b/examples/UserListDLC.nct similarity index 92% rename from tests/UserListDLC.nct rename to examples/UserListDLC.nct index e771b50..d8c842a 100644 --- a/tests/UserListDLC.nct +++ b/examples/UserListDLC.nct @@ -6,6 +6,7 @@ use ListDLC; @instantiate ListDLC_add[u32, u32; 9]; main: u0() -> { + ListDLC[u32, u32; 9] list; ListDLC_add[u32, u32; 9](&list, 1234); ListDLC_add[u32, u32; 9](&list, 4321); ListDLC_add[u32, u32; 9](&list, 7777); @@ -15,5 +16,3 @@ main: u0() -> { }; @section(".bss"); - -ListDLC[u32, u32; 9] list:; diff --git a/tests/arrays.nct b/examples/arrays.nct similarity index 100% rename from tests/arrays.nct rename to examples/arrays.nct diff --git a/tests/bf.nct b/examples/bf.nct similarity index 100% rename from tests/bf.nct rename to examples/bf.nct diff --git a/tests/bit-rounding.nct b/examples/bit-rounding.nct similarity index 100% rename from tests/bit-rounding.nct rename to examples/bit-rounding.nct diff --git a/tests/cat.nct b/examples/cat.nct similarity index 100% rename from tests/cat.nct rename to examples/cat.nct diff --git a/examples/countwords.nct b/examples/countwords.nct new file mode 100644 index 0000000..acf1c15 --- /dev/null +++ b/examples/countwords.nct @@ -0,0 +1,48 @@ +@section(".data"); + +local u8[33] finalstring: "The amount of words in stdin is: "; + +local u8[4] answer: "0000"; + +@section(".text"); + +extern s32() getchar; +extern s32(s32, u8*, u32) write; + +increase: u0() -> { + answer[3] = answer[3] + 1; + if(answer[3] > 57) { + answer[3] = 48; + answer[2] = answer[2] + 1; + if(answer[2] > 57) { + answer[2] = 48; + answer[1] = answer[1] + 1; + if(answer[1] > 57) { + answer[1] = 48; + answer[0] = answer[0] + 1; + if(answer[0] > 57) { + answer[0] = 48; + } + } + } + } + + return; +}; + +main: u0() -> { + loop { + s32 c = getchar(); + if(c == -1) { + break; + } + if(c == 32) { + increase(); + } + } + + write(1, &finalstring, 33); + write(1, &answer, 4); + + return; +}; diff --git a/tests/funcdefs.nct b/examples/funcdefs.nct similarity index 100% rename from tests/funcdefs.nct rename to examples/funcdefs.nct diff --git a/tests/functions.nct b/examples/functions.nct similarity index 100% rename from tests/functions.nct rename to examples/functions.nct diff --git a/tests/if.nct b/examples/if.nct similarity index 100% rename from tests/if.nct rename to examples/if.nct diff --git a/tests/loopregalloc.nct b/examples/loopregalloc.nct similarity index 82% rename from tests/loopregalloc.nct rename to examples/loopregalloc.nct index 02c685d..9173acd 100644 --- a/tests/loopregalloc.nct +++ b/examples/loopregalloc.nct @@ -1,9 +1,11 @@ u8 a; +a = 2; + loop { a = 3; u8 b = 1; u8 c = 2; -} \ No newline at end of file +} diff --git a/tests/lvl1localrecord.nct b/examples/lvl1localrecord.nct similarity index 100% rename from tests/lvl1localrecord.nct rename to examples/lvl1localrecord.nct diff --git a/tests/lvl1symbolrecord.nct b/examples/lvl1symbolrecord.nct similarity index 100% rename from tests/lvl1symbolrecord.nct rename to examples/lvl1symbolrecord.nct diff --git a/tests/lvl2localrecord.nct b/examples/lvl2localrecord.nct similarity index 100% rename from tests/lvl2localrecord.nct rename to examples/lvl2localrecord.nct diff --git a/tests/lvl2symbolrecord.nct b/examples/lvl2symbolrecord.nct similarity index 100% rename from tests/lvl2symbolrecord.nct rename to examples/lvl2symbolrecord.nct diff --git a/tests/mandelbrot.b b/examples/mandelbrot.b similarity index 100% rename from tests/mandelbrot.b rename to examples/mandelbrot.b diff --git a/tests/mbr.nct b/examples/mbr.nct similarity index 100% rename from tests/mbr.nct rename to examples/mbr.nct diff --git a/tests/ops.nct b/examples/ops.nct similarity index 100% rename from tests/ops.nct rename to examples/ops.nct diff --git a/examples/parsenum.nct b/examples/parsenum.nct new file mode 100644 index 0000000..05e40b4 --- /dev/null +++ b/examples/parsenum.nct @@ -0,0 +1,23 @@ +@section(".data"); + +u8 buf: 0; + +@section(".text"); + +extern u0(u32) exit; +extern s32(u32, u8*, u32) read; + +_start: u0() -> { + u16 value = 0; + + loop { + if(read(0, &buf, 1) != 1) { + break; + } + buf = buf - 48; + value = value * 10; + value = value + buf; + } + + exit(value); +}; diff --git a/tests/scoping.nct b/examples/scoping.nct similarity index 100% rename from tests/scoping.nct rename to examples/scoping.nct diff --git a/tests/spill.nct b/examples/spill.nct similarity index 100% rename from tests/spill.nct rename to examples/spill.nct diff --git a/tests/stack.nct b/examples/stack.nct similarity index 100% rename from tests/stack.nct rename to examples/stack.nct diff --git a/src/ast.c b/src/ast.c index 2928784..8c12fdf 100644 --- a/src/ast.c +++ b/src/ast.c @@ -8,6 +8,7 @@ #include"ntc.h" #include"reporting.h" #include"utils.h" +#include"x86/arch.h" const char *AST_KIND_STR[] = { AST_KINDS(GEN_STRI) }; @@ -118,7 +119,7 @@ int ast_stmt_is_after(const AST *chunk, const AST *s1, const AST *s2) { while(1) { if(s && s->nodeKind == AST_STMT_LOOP) { int i = ast_stmt_is_after(s->stmtLoop.body, s1, s2); - if(i != -1) { + if(i == 1 || (i == 0 && s1 != NULL)) { return i; } } @@ -134,7 +135,7 @@ int ast_stmt_is_after(const AST *chunk, const AST *s1, const AST *s2) { if(s->nodeKind == AST_STMT_IF) { int i = ast_stmt_is_after(s->stmtIf.then, s1, s2); - if(i != -1) { + if(i == 1 || (i == 0 && s1 != NULL)) { return i; } } @@ -233,11 +234,19 @@ static void adduse(ScopeItem *vte, AST *use, AST *whole) { while(rd && rd->defCount == 0) rd = rd->parent; - if(!rd) return; - - for(size_t d = 0; d < rd->defCount; d++) { + if(rd) { + for(size_t d = 0; d < rd->defCount; d++) { + UseDef *ud = calloc(1, sizeof(*ud)); + ud->def = rd->defs[d]; + ud->use = use; + ud->stmt = whole; + ud->next = NULL; + + rawadduse(vte, ud); + } + } else { UseDef *ud = calloc(1, sizeof(*ud)); - ud->def = rd->defs[d]; + ud->def = NULL; ud->use = use; ud->stmt = whole; ud->next = NULL; @@ -316,9 +325,9 @@ static void mergedefsloop(AST *tlc, ScopeItem *vte, AST *daLoopStmt) { udnew->use = ud->use; udnew->stmt = ud->stmt; - if(udnew->next == NULL) { + /*if(udnew->next == NULL) { vte->data.var.usedefLast = udnew; - } + }*/ } ud = ud->next; @@ -334,22 +343,47 @@ static void mergedefsloopall(AST *tlc, AST *daLoopStmt) { } } -static void ast_usedef_pass(AST *tlc, AST *a, AST *wholestmt) { +struct UsedefPassState { + size_t loopDepth; +}; + +static void ast_usedef_pass(struct UsedefPassState *state, AST *tlc, AST *a, AST *wholestmt) { if(a->nodeKind == AST_CHUNK) { for(AST *s = a->chunk.statementFirst; s; s = s->statement.next) { - ast_usedef_pass(tlc, s, s); + ast_usedef_pass(state, tlc, s, s); } } else if(a->nodeKind == AST_STMT_IF) { pushdefsall(tlc); - ast_usedef_pass(tlc, a->stmtIf.expression, wholestmt); - ast_usedef_pass(tlc, a->stmtIf.then, wholestmt); + ast_usedef_pass(state, tlc, a->stmtIf.expression, wholestmt); + ast_usedef_pass(state, tlc, a->stmtIf.then, wholestmt); mergedefsall(tlc); } else if(a->nodeKind == AST_STMT_LOOP) { pushdefsall(tlc); - ast_usedef_pass(tlc, a->stmtLoop.body, wholestmt); + state->loopDepth++; + + ast_usedef_pass(state, tlc, a->stmtLoop.body, wholestmt); + + state->loopDepth--; + + if(state->loopDepth == 0) { + for(size_t vi = 0; vi < tlc->chunk.varCount; vi++) { + ScopeItem *si = tlc->chunk.vars[vi]; + + if(si->data.var.usedInLoop) { + if(ast_stmt_is_after(a->stmtLoop.body, si->data.var.declaration, si->data.var.declaration) == -1) { + if(ast_stmt_is_after(tlc, a, si->data.var.liveRangeStart) == 0) { + si->data.var.liveRangeStart = a; + } + si->data.var.liveRangeEnd = a; + } + } + + si->data.var.usedInLoop = false; + } + } mergedefsloopall(tlc, a); } else if(a->nodeKind == AST_STMT_ASSIGN) { @@ -357,32 +391,43 @@ static void ast_usedef_pass(AST *tlc, AST *a, AST *wholestmt) { overwritedefs(a->stmtAssign.what->exprVar.thing, a); } - ast_usedef_pass(tlc, a->stmtAssign.what, wholestmt); + ast_usedef_pass(state, tlc, a->stmtAssign.what, wholestmt); if(a->stmtAssign.to) { - ast_usedef_pass(tlc, a->stmtAssign.to, wholestmt); + ast_usedef_pass(state, tlc, a->stmtAssign.to, wholestmt); } } else if(a->nodeKind == AST_STMT_EXPR) { - ast_usedef_pass(tlc, a->stmtExpr.expr, wholestmt); + ast_usedef_pass(state, tlc, a->stmtExpr.expr, wholestmt); } else if(a->nodeKind == AST_EXPR_VAR) { - if(a->exprVar.thing->kind == SCOPEITEM_VAR) { - adduse(a->exprVar.thing, a, wholestmt); + ScopeItem *si = a->exprVar.thing; + + if(si->kind == SCOPEITEM_VAR) { + if(state->loopDepth > 0) { + si->data.var.usedInLoop = true; + } + + adduse(si, a, wholestmt); + + if(si->data.var.liveRangeStart == NULL) { + si->data.var.liveRangeStart = wholestmt; + } + si->data.var.liveRangeEnd = wholestmt; } } else if(a->nodeKind == AST_EXPR_BINARY_OP) { - ast_usedef_pass(tlc, a->exprBinOp.operands[0], wholestmt); - ast_usedef_pass(tlc, a->exprBinOp.operands[1], wholestmt); + ast_usedef_pass(state, tlc, a->exprBinOp.operands[0], wholestmt); + ast_usedef_pass(state, tlc, a->exprBinOp.operands[1], wholestmt); } else if(a->nodeKind == AST_EXPR_UNARY_OP) { - ast_usedef_pass(tlc, a->exprUnOp.operand, wholestmt); + ast_usedef_pass(state, tlc, a->exprUnOp.operand, wholestmt); } else if(a->nodeKind == AST_EXPR_CALL) { - ast_usedef_pass(tlc, a->exprCall.what, wholestmt); + ast_usedef_pass(state, tlc, a->exprCall.what, wholestmt); for(size_t p = 0; p < a->exprCall.what->expression.type->function.argCount; p++) { - ast_usedef_pass(tlc, a->exprCall.args[p], wholestmt); + ast_usedef_pass(state, tlc, a->exprCall.args[p], wholestmt); } } else if(a->nodeKind == AST_EXPR_PRIMITIVE) { } else if(a->nodeKind == AST_EXPR_STRING_LITERAL) { } else if(a->nodeKind == AST_EXPR_CAST) { - ast_usedef_pass(tlc, a->exprCast.what, wholestmt); + ast_usedef_pass(state, tlc, a->exprCast.what, wholestmt); } else if(a->nodeKind == AST_EXPR_STACK_POINTER) { } else if(a->nodeKind == AST_EXPR_EXT_SALLOC) { } else if(a->nodeKind == AST_STMT_BREAK) { @@ -391,20 +436,26 @@ static void ast_usedef_pass(AST *tlc, AST *a, AST *wholestmt) { } else if(a->nodeKind == AST_STMT_EXT_ORG) { } else if(a->nodeKind == AST_STMT_EXT_SECTION) { } else if(a->nodeKind == AST_STMT_DECL) { - assert(a->stmtDecl.thing->kind != SCOPEITEM_VAR || a->stmtDecl.expression); + ScopeItem *si = a->stmtDecl.thing; + + //assert(si->kind != SCOPEITEM_VAR || a->stmtDecl.expression); + + if(si->kind == SCOPEITEM_VAR) { + assert(!si->data.var.declaration || si->data.var.declaration == a); + si->data.var.declaration = a; + } } else if(a->nodeKind == AST_STMT_RETURN) { if(a->stmtReturn.val) { - ast_usedef_pass(tlc, a->stmtReturn.val, wholestmt); - } - } else if (a->nodeKind == AST_EXPR_EXT_SIZEOF) { - if (a->exprExtSizeOf.ofExpr) { - ast_usedef_pass(tlc, a->exprExtSizeOf.ofExpr, wholestmt); + ast_usedef_pass(state, tlc, a->stmtReturn.val, wholestmt); } } else { stahp_node(a, "ast_usedef_pass: unhandled %s", AST_KIND_STR[a->nodeKind]); } } +char *ast_dump(AST *tlc); +char *ast_dumpc(AST *tlc, AST *chu); + void ast_usedef_reset(AST *chu) { for(size_t i = 0; i < chu->chunk.varCount; i++) { ScopeItem *vte = chu->chunk.vars[i]; @@ -414,11 +465,78 @@ void ast_usedef_reset(AST *chu) { vte->data.var.reachingDefs = NULL; vte->data.var.usedefFirst = NULL; vte->data.var.usedefLast = NULL; + vte->data.var.liveRangeStart = NULL; + vte->data.var.liveRangeEnd = NULL; } pushdefsall(chu); - return ast_usedef_pass(chu, chu, NULL); + struct UsedefPassState state = {}; + + ast_usedef_pass(&state, chu, chu, NULL); + + for(size_t i = 0; i < chu->chunk.varCount; i++) { + ScopeItem *vte = chu->chunk.vars[i]; + + assert(vte->kind == SCOPEITEM_VAR); + + assert(!!vte->data.var.usedefFirst == !!vte->data.var.usedefLast); + assert(!!vte->data.var.usedefFirst == !!vte->data.var.liveRangeStart); + //assert(!!vte->data.var.liveRangeStart == !!vte->data.var.liveRangeEnd); + } + + if(ntc_get_int("pdbg")) { + char *astdump = ast_dump(chu); + fprintf(stderr, "### USEDEF GENERATED ###\n%s\n", astdump); + free(astdump); + } +} + +static void ast_tlc_add_var(AST *tlc, ScopeItem *si) { + tlc->chunk.vars = realloc(tlc->chunk.vars, sizeof(*tlc->chunk.vars) * ++tlc->chunk.varCount); + tlc->chunk.vars[tlc->chunk.varCount - 1] = si; +} + +/* Split away complex expression into a new local variable */ +static AST *varify(AST *tlc, AST *chunk, AST **stmtPrev, AST *stmt, AST *e) { + static size_t idx = 0; + + ScopeItem *vte = calloc(1, sizeof(*vte)); + vte->kind = SCOPEITEM_VAR; + vte->type = e->expression.type; + vte->data.var.name = malp("$varify_%lu", idx++); + + ast_tlc_add_var(tlc, vte); + + // Alter AST + + ASTExprVar *ev[2]; + for(int i = 0; i < 2; i++) { + ev[i] = calloc(1, sizeof(ASTExprVar)); + ev[i]->nodeKind = AST_EXPR_VAR; + ev[i]->type = e->expression.type; + ev[i]->thing = vte; + } + + ASTStmtAssign *assign = calloc(1, sizeof(*assign)); + assign->nodeKind = AST_STMT_ASSIGN; + assign->what = (AST*) ev[0]; + assign->to = e; + + if(*stmtPrev) { + (*stmtPrev)->statement.next = (AST*) assign; + } else { + chunk->chunk.statementFirst = (AST*) assign; + } + assign->next = stmt; + *stmtPrev = (AST*) assign; + + // Reset ud-chain + + vte->data.var.usedefFirst = NULL; + vte->data.var.usedefLast = NULL; + + return (AST*) ev[1]; } char *type_to_string(Type *t) { @@ -456,7 +574,7 @@ char *type_to_string(Type *t) { return strdup("@unimp"); } -static char *ast_dumpe(AST *e) { +static char *ast_dumpe(AST *tlc, AST *e) { if(e->nodeKind == AST_EXPR_PRIMITIVE) { return malp("%i", e->exprPrim.val); } else if(e->nodeKind == AST_EXPR_VAR) { @@ -485,13 +603,13 @@ static char *ast_dumpe(AST *e) { default: abort(); } - char *c = ast_dumpe(e->exprUnOp.operand); + char *c = ast_dumpe(tlc, e->exprUnOp.operand); char *r = malp("%s%s", op, c); free(c); return r; } else if(e->nodeKind == AST_EXPR_BINARY_OP) { - char *a = ast_dumpe(e->exprBinOp.operands[0]); - char *b = ast_dumpe(e->exprBinOp.operands[1]); + char *a = ast_dumpe(tlc, e->exprBinOp.operands[0]); + char *b = ast_dumpe(tlc, e->exprBinOp.operands[1]); const char *op; switch(e->exprBinOp.operator) { case BINOP_ADD: @@ -568,7 +686,7 @@ static char *ast_dumpe(AST *e) { } { - char *choonk = ast_dump(e->exprFunc.chunk); + char *choonk = ast_dumpc(tlc, e->exprFunc.chunk); char *out2 = malp("%s) {\n%s}", out, choonk); free(out); free(choonk); @@ -577,12 +695,12 @@ static char *ast_dumpe(AST *e) { return out; } else if(e->nodeKind == AST_EXPR_CALL) { - char *w = ast_dumpe(e->exprCall.what); + char *w = ast_dumpe(tlc, e->exprCall.what); char *out = malp("%s(", w); free(w); size_t argCount = e->exprCall.what->expression.type->function.argCount; for(size_t i = 0; i < argCount; i++) { - char *a = ast_dumpe(e->exprCall.args[i]); + char *a = ast_dumpe(tlc, e->exprCall.args[i]); char *out2 = malp(i == argCount - 1 ? "%s%s)" : "%s%s, ", out, a); free(a); free(out); @@ -595,14 +713,14 @@ static char *ast_dumpe(AST *e) { free(w); return out; } else if(e->nodeKind == AST_EXPR_CAST) { - char *a = ast_dumpe(e->exprCast.what); + char *a = ast_dumpe(tlc, e->exprCast.what); char *b = type_to_string(e->exprCast.to); char *out = malp("(%s as %s)", a, b); free(a); free(b); return out; } else if(e->nodeKind == AST_EXPR_DOT) { - char *a = ast_dumpe(e->exprDot.a); + char *a = ast_dumpe(tlc, e->exprDot.a); char *out = malp(e->nodeKind == AST_EXPR_BINARY_OP ? "(%s).%s" : "%s.%s", a, e->exprDot.b); free(a); return out; @@ -611,43 +729,41 @@ static char *ast_dumpe(AST *e) { return malp("@unimp:%s", AST_KIND_STR[e->nodeKind]); } -char *ast_dump(AST *tlc); - -static char *ast_dumps(AST *s) { +static char *ast_dumps(AST *tlc, AST *s) { if(s->nodeKind == AST_STMT_DECL) { ScopeItem *vte = s->stmtDecl.thing; if(vte->kind == SCOPEITEM_SYMBOL) { char *t = type_to_string(vte->type); - char *e = s->stmtDecl.expression ? ast_dumpe(s->stmtDecl.expression) : strdup(""); - char *r = malp("%s%s %s: %s;\n", vte->data.symbol.isExternal ? "external " : "", t, vte->data.symbol.name, e); + char *e = s->stmtDecl.expression ? ast_dumpe(tlc, s->stmtDecl.expression) : strdup(""); + char *r = malp("%s%s %s: %s;", vte->data.symbol.isExternal ? "external " : "", t, vte->data.symbol.name, e); free(t); free(e); return r; } } else if(s->nodeKind == AST_STMT_ASSIGN) { if(s->stmtAssign.to) { - char *a = ast_dumpe(s->stmtAssign.what); - char *b = ast_dumpe(s->stmtAssign.to); - char *r = malp("%s = %s;\n", a, b); + char *a = ast_dumpe(tlc, s->stmtAssign.what); + char *b = ast_dumpe(tlc, s->stmtAssign.to); + char *r = malp("%s = %s;", a, b); free(a); free(b); return r; } else { - char *a = ast_dumpe(s->stmtAssign.what); - char *r = malp("%s = ; /* fake def */\n", a); + char *a = ast_dumpe(tlc, s->stmtAssign.what); + char *r = malp("%s = ; /* fake def */", a); free(a); return r; } } else if(s->nodeKind == AST_STMT_LOOP) { - char *inner = ast_dump(s->stmtLoop.body); - char *c = malp("loop {\n%s}\n", inner); + char *inner = ast_dumpc(tlc, s->stmtLoop.body); + char *c = malp("loop {\n%s}", inner); free(inner); return c; } else if(s->nodeKind == AST_STMT_IF) { - char *cond = ast_dumpe(s->stmtIf.expression); - char *inner = ast_dump(s->stmtIf.then); - char *c = malp("if(%s) {\n%s}\n", cond, inner); + char *cond = ast_dumpe(tlc, s->stmtIf.expression); + char *inner = ast_dumpc(tlc, s->stmtIf.then); + char *c = malp("if(%s) {\n%s}", cond, inner); free(cond); free(inner); return c; @@ -660,33 +776,55 @@ static char *ast_dumps(AST *s) { name = s->stmtExpr.expr->exprVar.thing->data.symbol.name; } - return malp("%s; /* loop guard */\n", name); + return malp("%s; /* loop guard */", name); } else if(s->nodeKind == AST_STMT_EXPR) { - return ast_dumpe(s->stmtExpr.expr); + return ast_dumpe(tlc, s->stmtExpr.expr); } else if(s->nodeKind == AST_STMT_RETURN) { if(s->stmtReturn.val) { - char *e = ast_dumpe(s->stmtReturn.val); - char *c = malp("return %s;\n", e); + char *e = ast_dumpe(tlc, s->stmtReturn.val); + char *c = malp("return %s;", e); free(e); return c; } else { - return malp("return;\n"); + return malp("return;"); } } - return malp("@unimp:%s\n", AST_KIND_STR[s->nodeKind]); + return malp("@unimp:%s;", AST_KIND_STR[s->nodeKind]); } -char *ast_dump(AST *tlc) { - AST *stmt = tlc->chunk.statementFirst; +static char *stmt_live_range_dbgs(AST *tlc, AST *stmt) { + char *ret = malp(""); + for(size_t v = 0; v < tlc->chunk.varCount; v++) { + ScopeItem *si = tlc->chunk.vars[v]; + + if(si->data.var.liveRangeStart == stmt) { + char *ret2 = malp("%s (%s start)", ret, si->data.var.name); + free(ret); + ret = ret2; + } + + if(si->data.var.liveRangeEnd == stmt) { + char *ret2 = malp("%s (%s end)", ret, si->data.var.name); + free(ret); + ret = ret2; + } + } + return ret; +} + +char *ast_dumpc(AST *tlc, AST *chu) { + AST *stmt = chu->chunk.statementFirst; char *ret = malp(""); while(stmt) { - char *new = ast_dumps(stmt); - char *ret2 = malp("%s%s", ret, new); + char *new = ast_dumps(tlc, stmt); + char *users = stmt_live_range_dbgs(tlc, stmt); + char *ret2 = malp("%s%s%s\n", ret, new, users); free(ret); free(new); + free(users); ret = ret2; stmt = stmt->statement.next; @@ -695,6 +833,10 @@ char *ast_dump(AST *tlc) { return ret; } +char *ast_dump(AST *tlc) { + return ast_dumpc(tlc, tlc); +} + static void *memdup(void *a, size_t len) { void *r = malloc(len); memcpy(r, a, len); @@ -712,7 +854,10 @@ AST *ast_deep_copy(AST *src) { } AST *ast_cast_expr(AST *what, Type *to) { - if(what == NULL) goto fail; + if(what == NULL) { + stahp(0, 0, "NULL what passed to ast_cast_expr"); + goto fail; + } /* Only exists at parse-time, hence not part of type system and is handled separately */ if(what->nodeKind == AST_EXPR_STRING_LITERAL) { @@ -977,7 +1122,7 @@ static void ast_decompose_automatic_record(AST *tlc, ScopeItem *target) { } void ast_sroa(AST *tlc) { - for(size_t i = 0; i < tlc->chunk.varCount; i++) { + for(int i = 0; i < tlc->chunk.varCount; i++) { ScopeItem *si = tlc->chunk.vars[i]; if(!is_sroa_candidate(si)) { @@ -994,6 +1139,67 @@ void ast_sroa(AST *tlc) { tlc->chunk.varCount--; /* Restart */ - i = 0; + i = -1; } } + +static void ast_segmented_dereference_visitor(AST **aptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *tlc, void *ud) { + if(tlc != ud) { + return; + } + + AST *n = *aptr; + if(n->nodeKind == AST_EXPR_UNARY_OP && n->exprUnOp.operator == UNOP_DEREF && type_is_segmented_pointer(n->exprUnOp.operand->expression.type)) { + static size_t idx = 0; + + AST *v; + if(n->exprUnOp.operand->nodeKind == AST_EXPR_VAR) + v = n->exprUnOp.operand; + else + v = varify(tlc, chunk, &stmtPrev, stmt, n->exprUnOp.operand); + + ScopeItem *si = calloc(1, sizeof(*si)); + si->kind = SCOPEITEM_VAR; + si->type = primitive_parse("u16"); + si->data.var.preclassed = true; + si->data.var.registerClass = REG_CLASS_DATASEGS; + si->data.var.precolored = true; + si->data.var.color = 0; + si->data.var.name = malp("$segtemp_%lu", idx++); + ast_tlc_add_var(tlc, si); + + ASTExprVar *ev = calloc(1, sizeof(*ev)); + ev->nodeKind = AST_EXPR_VAR; + ev->type = si->type; + ev->thing = si; + + ASTExprDot *edseg = calloc(1, sizeof(*edseg)); + edseg->type = n->exprUnOp.operand->expression.type->record.fieldTypes[0]; + edseg->nodeKind = AST_EXPR_DOT; + edseg->a = v; + edseg->b = strdup("segment"); + + ASTStmtAssign *ass = calloc(1, sizeof(*ass)); + ass->nodeKind = AST_STMT_ASSIGN; + ass->what = (AST*) ev; + ass->to = (AST*) edseg; + ass->next = (AST*) stmt; + if(stmtPrev) + stmtPrev->statement.next = (AST*) ass; + else + chunk->chunk.statementFirst = (AST*) ass; + stmtPrev = (AST*) ass; + + ASTExprDot *ed = calloc(1, sizeof(*ed)); + ed->type = n->exprUnOp.operand->expression.type->record.fieldTypes[1]; + ed->nodeKind = AST_EXPR_DOT; + ed->a = ast_deep_copy(v); + ed->b = strdup("offset"); + + n->exprUnOp.operand = (AST*) ed; + } +} + +void ast_segmented_dereference(AST *tlc) { + generic_visitor(&tlc, NULL, NULL, tlc, tlc, tlc, ast_segmented_dereference_visitor, NULL); +} diff --git a/src/ast.h b/src/ast.h index 43f4c72..64f044d 100644 --- a/src/ast.h +++ b/src/ast.h @@ -17,6 +17,7 @@ #define GEN_STRI(x) #x, #define AST_KINDS(K) \ + K(AST_MISSING) \ K(AST_CHUNK) \ K(AST_STMT_DECL) \ K(AST_EXPR_PRIMITIVE) \ @@ -361,4 +362,8 @@ void ast_commutativity_pass(AST *tlc); void ast_sroa(AST *tlc); +// Convert segmented derefences like *x into segment move and *x.offset. +// Must be done before ast_sroa. +void ast_segmented_dereference(AST *tlc); + #endif diff --git a/src/ntc.c b/src/ntc.c index 95517e6..c180827 100644 --- a/src/ntc.c +++ b/src/ntc.c @@ -94,6 +94,7 @@ int main(int argc_, char **argv_) { free(astdump); } + ast_segmented_dereference(chunk); ast_sroa(chunk); dumben_pre(chunk); dumben_go(chunk); diff --git a/src/parse.c b/src/parse.c index 6cca1a1..45f4c8e 100644 --- a/src/parse.c +++ b/src/parse.c @@ -9,6 +9,7 @@ #include #include #include"ntc.h" +#include"x86/arch.h" #ifndef __GNUC__ static inline int __builtin_clzl(unsigned long x) { @@ -39,8 +40,6 @@ typedef struct { // Used to place guard variable uses after loops to stop reg allocation from fucking up Scope *loopScope; - size_t guardedVarCount; - ASTExprVar **guardedVars; // Used for generating statements that load & store arguments int isInFunction; @@ -144,7 +143,7 @@ static AST *exprvar(Parser *P, ScopeItem *v) { a->exprVar.type = v->type; a->exprVar.thing = v; - if(P->loopScope) { + /*if(P->loopScope) { // XXX: O(n)!!!!!!!!! int inloop = 0; @@ -172,7 +171,7 @@ static AST *exprvar(Parser *P, ScopeItem *v) { P->guardedVars[P->guardedVarCount++] = ev; } } - } + }*/ return a; } @@ -354,7 +353,13 @@ AST *nct_parse_expression(Parser *P, int lOP) { astop->nodeKind = AST_EXPR_UNARY_OP; astop->operator = UNOP_DEREF; astop->operand = nct_parse_expression(P, lOP); /* Not +1! */ - astop->type = astop->operand->expression.type->pointer.of; + + if(type_is_segmented_pointer(astop->operand->expression.type)) { + astop->type = astop->operand->expression.type->record.fieldTypes[1]->pointer.of; + } else { + assert(astop->operand->expression.type->type == TYPE_TYPE_POINTER); + astop->type = astop->operand->expression.type->pointer.of; + } return (AST*) astop; } else if(maybe(P, TOKEN_AMPERSAND)) { @@ -743,8 +748,34 @@ static Type *nct_parse_typename(Parser *P) { goto backtrack; } - while(peek(P, 0).type == TOKEN_PAREN_L || peek(P, 0).type == TOKEN_STAR || peek(P, 0).type == TOKEN_SQUAREN_L) { - if(maybe(P, TOKEN_STAR)) { + while(peek(P, 0).type == TOKEN_PAREN_L + || peek(P, 0).type == TOKEN_STAR + || peek(P, 0).type == TOKEN_SQUAREN_L + || (peek(P, 0).type == TOKEN_IDENTIFIER && !strcmp(peek(P, 0).content, "@far"))) { + + if(maybe(P, TOKEN_IDENTIFIER)) { + expect(P, TOKEN_STAR); + + TypeRecord *rec = calloc(1, sizeof(*rec)); + rec->type = TYPE_TYPE_RECORD; + rec->name = malp("%s @far*", type_to_string(ret)); + + rec->fieldCount = 2; + + rec->fieldTypes = calloc(2, sizeof(*rec->fieldTypes)); + rec->fieldTypes[0] = primitive_parse("u16"); + rec->fieldTypes[1] = type_pointer_wrap(ret); + + rec->fieldNames = calloc(2, sizeof(*rec->fieldNames)); + rec->fieldNames[0] = malp("segment"); + rec->fieldNames[1] = malp("offset"); + + rec->fieldOffsets = calloc(2, sizeof(*rec->fieldOffsets)); + rec->fieldOffsets[0] = 0; + rec->fieldOffsets[1] = 2; + + ret = (Type*) rec; + } else if(maybe(P, TOKEN_STAR)) { TypePointer *ptr = calloc(1, sizeof(*ptr)); ptr->type = TYPE_TYPE_POINTER; ptr->of = ret; @@ -844,6 +875,7 @@ static Type *nct_parse_typename(Parser *P) { P->scope = P->scope->parent; } } + } if(generics) { @@ -899,17 +931,22 @@ static AST *parse_declaration(Parser *P) { entry->data.var.priority = 1; entry->data.var.color = -1; - ASTStmtAssign *assign = alloc_node(P, sizeof(*assign)); - assign->nodeKind = AST_STMT_ASSIGN; - assign->next = NULL; + //ASTStmtAssign *assign = alloc_node(P, sizeof(*assign)); + //assign->nodeKind = AST_STMT_ASSIGN; + //assign->next = NULL; - //entry->data.var.reachingDefs = reachingdefs_push(NULL); - //reachingdefs_set(entry->data.var.reachingDefs, (AST*) assign); + //assign->what = exprvar(P, entry); - assign->what = exprvar(P, entry); - assign->to = peek(P, 0).type == TOKEN_SEMICOLON ? NULL : ast_cast_expr(nct_parse_expression(P, 0), assign->what->expression.type); + AST *expr = peek(P, 0).type == TOKEN_SEMICOLON ? NULL : ast_cast_expr(nct_parse_expression(P, 0), entry->type); + //assign->to = expr; - ret = (AST*) assign; + ASTStmtDecl *decl = alloc_node(P, sizeof(*ret)); + decl->nodeKind = AST_STMT_DECL; + decl->thing = entry; + decl->next = NULL; + decl->expression = expr; + + ret = (AST*) decl; } else { ASTStmtDecl *decl = alloc_node(P, sizeof(*ret)); @@ -1066,7 +1103,7 @@ static void nct_parse_statement(Parser *P) { if(isFirstLoop) { P->loopScope = NULL; - for(size_t i = 0; i < P->guardedVarCount; i++) { + /*for(size_t i = 0; i < P->guardedVarCount; i++) { ASTExprVar *ev = P->guardedVars[i]; AST *es = alloc_node(P, sizeof(ASTStmtExpr)); @@ -1078,7 +1115,7 @@ static void nct_parse_statement(Parser *P) { P->guardedVarCount = 0; free(P->guardedVars); - P->guardedVars = NULL; + P->guardedVars = NULL;*/ } return; @@ -1290,6 +1327,18 @@ static void nct_parse_statement(Parser *P) { // Don't pass declaration statements for generic functions, because they're useless if(decl->nodeKind != AST_STMT_DECL || !type_is_generic(decl->stmtDecl.thing->type)) { pushstat(P, decl); + + if(decl->stmtDecl.thing->kind == SCOPEITEM_VAR && decl->stmtDecl.expression) { + AST *expr = decl->stmtDecl.expression; + decl->stmtDecl.expression = NULL; + + ASTStmtAssign *ass = alloc_node(P, sizeof(*ass)); + ass->nodeKind = AST_STMT_ASSIGN; + ass->next = NULL; + ass->what = exprvar(P, decl->stmtDecl.thing); + ass->to = expr; + pushstat(P, ass); + } } return; } @@ -1596,6 +1645,8 @@ ASTChunk *nct_parse_chunk(Parser *P, int isTopLevel, int varPrioritize, Scope *t /* Now actual parsing. */ + arch_add_hidden_variables(P->scope); + while(peek(P, 0).type != TOKEN_EOF && peek(P, 0).type != TOKEN_SQUIGGLY_R) { nct_parse_statement(P); } diff --git a/src/scope.h b/src/scope.h index 60313b5..ad1c4a6 100644 --- a/src/scope.h +++ b/src/scope.h @@ -65,14 +65,16 @@ typedef struct ScopeItem { bool precolored, preclassed; int registerClass; - // Used during parsing - + // Used by ast_usedef_pass + union AST *declaration; ReachingDefs *reachingDefs; - - // Optimizations + bool usedInLoop; UseDef *usedefFirst; UseDef *usedefLast; + + union AST *liveRangeStart; + union AST *liveRangeEnd; } var; struct { Type *ptr; diff --git a/src/types.h b/src/types.h index 83ad614..a7ba157 100644 --- a/src/types.h +++ b/src/types.h @@ -4,6 +4,7 @@ #include #include #include +#include typedef enum { TYPE_TYPE_PRIMITIVE, TYPE_TYPE_RECORD, TYPE_TYPE_POINTER, TYPE_TYPE_FUNCTION, TYPE_TYPE_ARRAY, TYPE_TYPE_GENERIC, TYPE_TYPE_ERROR @@ -109,4 +110,8 @@ Type *type_shallow_copy(Type *t); bool type_is_generic(Type *t); +static inline bool type_is_segmented_pointer(Type *type) { + return type->type == TYPE_TYPE_RECORD && !!strstr(type->record.name, " @far*"); +} + #endif diff --git a/src/x86/arch.c b/src/x86/arch.c index bf84fc7..091f854 100644 --- a/src/x86/arch.c +++ b/src/x86/arch.c @@ -9,15 +9,15 @@ RegisterClass REG_CLASSES[] = { }, [REG_CLASS_NOT_8] = { .rMask = HWR_GPR, .w = 2, .p = 4, - .rs = {HWR_AX, HWR_EAX, HWR_BX, HWR_EBX, HWR_CX, HWR_ECX, HWR_DX, HWR_EDX, HWR_DI, HWR_EDI, HWR_SI, HWR_ESI}, - .rsN = {"ax", "eax", "bx", "ebx", "cx", "ecx", "dx", "edx", "di", "edi", "si", "esi"}, - .rsS = {2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4}, + .rs = {HWR_AX, HWR_EAX, HWR_BX, HWR_EBX, HWR_CX, HWR_ECX, HWR_DX, HWR_EDX, HWR_DI, HWR_EDI, HWR_SI, HWR_ESI, HWR_BP, HWR_EBP}, + .rsN = {"ax", "eax", "bx", "ebx", "cx", "ecx", "dx", "edx", "di", "edi", "si", "esi", "bp", "ebp"}, + .rsS = {2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4}, }, [REG_CLASS_16_32] = { .rMask = HWR_GPR, .w = 2, .p = 4, - .rs = {HWR_AX, HWR_EAX, HWR_BX, HWR_EBX, HWR_CX, HWR_ECX, HWR_DX, HWR_EDX}, - .rsN = {"ax", "eax", "bx", "ebx", "cx", "ecx", "dx", "edx"}, - .rsS = {2, 4, 2, 4, 2, 4, 2, 4}, + .rs = {HWR_AX, HWR_EAX, HWR_BX, HWR_EBX, HWR_CX, HWR_ECX, HWR_DX, HWR_EDX, HWR_BP, HWR_EBP}, + .rsN = {"ax", "eax", "bx", "ebx", "cx", "ecx", "dx", "edx", "bp", "ebp"}, + .rsS = {2, 4, 2, 4, 2, 4, 2, 4, 2, 4}, }, [REG_CLASS_IND] = { .rMask = HWR_IND, .w = 2, .p = 2, @@ -27,15 +27,15 @@ RegisterClass REG_CLASSES[] = { }, [REG_CLASS_IA16_PTRS] = { .rMask = HWR_IND | HWR_BX, - .rs = {HWR_DI, HWR_SI, HWR_BX}, - .rsN = {"di", "si", "bx"}, - .rsS = {2, 2, 2}, + .rs = {HWR_DI, HWR_SI, HWR_BX, HWR_BP}, + .rsN = {"di", "si", "bx", "bp"}, + .rsS = {2, 2, 2, 2}, }, [REG_CLASS_DATASEGS] = { - .rMask = HWR_IND | HWR_BX, + .rMask = HWR_SEGREGS, .rs = {HWR_DS, HWR_ES, HWR_FS, HWR_GS}, .rsN = {"ds", "es", "fs", "gs"}, - .rsS = {2, 2, 2}, + .rsS = {2, 2, 2, 2}, }, }; diff --git a/src/x86/arch.h b/src/x86/arch.h index 5aeb71e..ec6bc2d 100644 --- a/src/x86/arch.h +++ b/src/x86/arch.h @@ -17,11 +17,12 @@ #define HWR_DH 128 #define HWR_DI 256 #define HWR_SI 512 +#define HWR_BP 1024 -#define HWR_DS 1024 -#define HWR_ES 2048 -#define HWR_FS 4096 -#define HWR_GS 8192 +#define HWR_DS 2048 +#define HWR_ES 4096 +#define HWR_FS 8192 +#define HWR_GS 16384 #define HWR_AX (HWR_AL | HWR_AH) #define HWR_BX (HWR_BL | HWR_BH) @@ -35,12 +36,15 @@ #define HWR_EDI HWR_DI #define HWR_ESI HWR_SI +#define HWR_EBP HWR_BP -#define HWR_GPR (HWR_EAX | HWR_EBX | HWR_ECX | HWR_EDX) +#define HWR_GPR (HWR_EAX | HWR_EBX | HWR_ECX | HWR_EDX | HWR_EDI | HWR_ESI | HWR_EBP) #define HWR_IND (HWR_EDI | HWR_ESI) #define HWR_ALL (HWR_GPR | HWR_IND) -#define MAX_REGS_PER_CLASS 12 +#define HWR_SEGREGS (HWR_DS | HWR_ES | HWR_FS | HWR_GS) + +#define MAX_REGS_PER_CLASS 16 typedef struct RegisterClass { uint32_t rMask; uint16_t w; @@ -286,3 +290,16 @@ static inline WhysItBad_Huh x86_test_mul(AST *stmtPrev, AST *stmt) { return GUCCI; } + +static inline void arch_add_hidden_variables(Scope *scope) { + /*if(!scope_find(scope, "@seg_ds")) { + ScopeItem *si = calloc(1, sizeof(*si)); + si->type = primitive_parse("u16"); + si->kind = SCOPEITEM_VAR; + si->data.var.preclassed = true; + si->data.var.registerClass = REG_CLASS_DATASEGS; + si->data.var.precolored = true; + si->data.var.color = 0; + scope_set(scope, "@seg_ds", si); + }*/ +} diff --git a/src/x86/cg.c b/src/x86/cg.c index 5cee188..e0908c6 100644 --- a/src/x86/cg.c +++ b/src/x86/cg.c @@ -215,11 +215,11 @@ static const char *xop(AST *tlc, AST *e) { return xop_sz(tlc, e, type_size(e->expression.type)); } -static int ud_empty(ScopeItem *a) { +static int lr_empty(ScopeItem *a) { assert(a->kind == SCOPEITEM_VAR); - assert(!a->data.var.usedefFirst == !a->data.var.usedefLast); + //assert(!a->data.var.liveRangeStart == !a->data.var.liveRangeEnd); - return !a->data.var.usedefFirst; + return !a->data.var.liveRangeStart; } void cg_chunk(CGState *cg, AST *a) { @@ -250,61 +250,71 @@ void cg_chunk(CGState *cg, AST *a) { printf("align %u\n", val); } - } else if(s->nodeKind == AST_STMT_DECL && s->stmtDecl.thing->kind == SCOPEITEM_SYMBOL) { + } else if(s->nodeKind == AST_STMT_DECL) { + ScopeItem *v = s->stmtDecl.thing; - if(v->data.symbol.isExternal) { - // Do nothing. - // All external symbols are handled at once in the top-level chunk. - //printf("extern %s\n", v->data.symbol.name); - } else { - if(!v->data.symbol.isLocal) { - printf("global %s\n", v->data.symbol.name); - } + if(v->kind == SCOPEITEM_SYMBOL) { - if(s->stmtDecl.expression) { - printf("%s:", v->data.symbol.name); - if(v->type->type == TYPE_TYPE_PRIMITIVE) { + if(v->data.symbol.isExternal) { + // Do nothing. + // All external symbols are handled at once in the top-level chunk. + //printf("extern %s\n", v->data.symbol.name); + } else { + if(!v->data.symbol.isLocal) { + printf("global %s\n", v->data.symbol.name); + } - assert(s->stmtDecl.expression->nodeKind == AST_EXPR_PRIMITIVE); + if(s->stmtDecl.expression) { + printf("%s:", v->data.symbol.name); + if(v->type->type == TYPE_TYPE_PRIMITIVE) { - printf("%s %i", direct(type_size(v->type)), s->stmtDecl.expression->exprPrim.val); - - } else if(v->type->type == TYPE_TYPE_ARRAY && v->type->array.of->type == TYPE_TYPE_PRIMITIVE) { - - printf("%s ", direct(type_size(v->type->array.of))); - for(size_t i = 0; i < v->type->array.length; i++) { - printf("%i,", s->stmtDecl.expression->exprArray.items[i]->exprPrim.val); - } - - } else if(v->type->type == TYPE_TYPE_FUNCTION) { - - putchar('\n'); - - assert(s->stmtDecl.expression->nodeKind == AST_EXPR_FUNC); - - // Generic functions have non-NULL code blocks - if(!type_is_generic(s->stmtDecl.expression->expression.type)) { + assert(s->stmtDecl.expression->nodeKind == AST_EXPR_PRIMITIVE); - ast_sroa(s->stmtDecl.expression->exprFunc.chunk); + printf("%s %i", direct(type_size(v->type)), s->stmtDecl.expression->exprPrim.val); - dumben_pre(s->stmtDecl.expression->exprFunc.chunk); - - dumben_go(s->stmtDecl.expression->exprFunc.chunk); - while(!cg_go(s->stmtDecl.expression->exprFunc.chunk)) { - dumben_go(s->stmtDecl.expression->exprFunc.chunk); + } else if(v->type->type == TYPE_TYPE_ARRAY && v->type->array.of->type == TYPE_TYPE_PRIMITIVE) { + + printf("%s ", direct(type_size(v->type->array.of))); + for(size_t i = 0; i < v->type->array.length; i++) { + printf("%i,", s->stmtDecl.expression->exprArray.items[i]->exprPrim.val); } - } - - } else abort(); - putchar('\n'); - } else { - - printf("%s resb %lu\n", v->data.symbol.name, type_size(s->stmtDecl.thing->type)); + } else if(v->type->type == TYPE_TYPE_FUNCTION) { + + putchar('\n'); + + assert(s->stmtDecl.expression->nodeKind == AST_EXPR_FUNC); + + // Generic functions have non-NULL code blocks + if(!type_is_generic(s->stmtDecl.expression->expression.type)) { + + ast_segmented_dereference(s->stmtDecl.expression->exprFunc.chunk); + + ast_sroa(s->stmtDecl.expression->exprFunc.chunk); + + dumben_pre(s->stmtDecl.expression->exprFunc.chunk); + + dumben_go(s->stmtDecl.expression->exprFunc.chunk); + while(!cg_go(s->stmtDecl.expression->exprFunc.chunk)) { + dumben_go(s->stmtDecl.expression->exprFunc.chunk); + } + + } + + } else abort(); + putchar('\n'); + } else { + printf("%s resb %lu\n", v->data.symbol.name, type_size(s->stmtDecl.thing->type)); + + } } + + } else if(v->kind == SCOPEITEM_VAR) { + assert(s->stmtDecl.expression == NULL); } + } else if(s->nodeKind == AST_STMT_ASSIGN && s->stmtAssign.to && s->stmtAssign.what->nodeKind == AST_EXPR_VAR && s->stmtAssign.what->exprVar.thing->kind == SCOPEITEM_VAR && s->stmtAssign.to->nodeKind == AST_EXPR_CALL) { AST *e = s->stmtAssign.to; @@ -502,13 +512,13 @@ typedef ScopeItem *Adjacency[2]; static bool var_collision(AST *tlc, ScopeItem *v1, ScopeItem *v2) { /* 1D intersection test */ - bool liveRangeIntersection = !ud_empty(v1) && !ud_empty(v2) && ( - (ast_stmt_is_after(tlc, v1->data.var.usedefFirst->stmt, v2->data.var.usedefFirst->stmt) == 1 - && ast_stmt_is_after(tlc, v2->data.var.usedefLast->stmt, v1->data.var.usedefFirst->stmt) == 1) + bool liveRangeIntersection = !lr_empty(v1) && !lr_empty(v2) && (v1->data.var.liveRangeStart == v2->data.var.liveRangeStart || ( + (ast_stmt_is_after(tlc, v1->data.var.liveRangeStart, v2->data.var.liveRangeStart) == 1 + && ast_stmt_is_after(tlc, v2->data.var.liveRangeEnd, v1->data.var.liveRangeStart) == 1) || - (ast_stmt_is_after(tlc, v1->data.var.usedefLast->stmt, v2->data.var.usedefFirst->stmt) == 1 - && ast_stmt_is_after(tlc, v2->data.var.usedefLast->stmt, v1->data.var.usedefLast->stmt) == 1) - ); + (ast_stmt_is_after(tlc, v1->data.var.liveRangeEnd, v2->data.var.liveRangeStart) == 1 + && ast_stmt_is_after(tlc, v2->data.var.liveRangeEnd, v1->data.var.liveRangeEnd) == 1) + )); bool resourceIntersection = (REG_CLASSES[v1->data.var.registerClass].rMask & REG_CLASSES[v2->data.var.registerClass].rMask) != 0; @@ -840,7 +850,7 @@ cont:; ScopeItem *chosen = NULL; for(ssize_t i = a->chunk.varCount - 1; i >= 0; i--) { - if(!vars[i]->data.var.precolored && vars[i]->data.var.registerClass == mustSpillRegisterClass) { + if(vars[i]->data.var.registerClass == mustSpillRegisterClass && !vars[i]->data.var.precolored) { chosen = vars[i]; break; } diff --git a/src/x86/dumberdowner.c b/src/x86/dumberdowner.c index e4d3b1a..2bf28c2 100644 --- a/src/x86/dumberdowner.c +++ b/src/x86/dumberdowner.c @@ -85,11 +85,14 @@ static void mark_ptr(AST *a) { } struct DumbenState { + AST *targetTLC; int effective; }; static void dumben_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chu, AST *tlc, void *ud) { struct DumbenState *this = ud; + if(this->targetTLC != tlc) return; + AST *s = *nptr; if(s->nodeKind == AST_STMT_IF) { @@ -540,13 +543,19 @@ void dumben_pre(AST *tlc) { free(astdump); } - bool success; + struct DenoopState state = {.targetTLC = tlc}; do { - success = false; - generic_visitor(&tlc, NULL, NULL, tlc, tlc, &success, denoop_visitor, NULL); - } while(success); + state.success = false; + generic_visitor(&tlc, NULL, NULL, tlc, tlc, &state, denoop_visitor, NULL); + } while(state.success); ast_commutativity_pass(tlc); + + if(ntc_get_int("pdbg")) { + char *astdump = ast_dump(tlc); + fprintf(stderr, "### AFTER DENOOP ###\n%s\n", astdump); + free(astdump); + } } void dumben_go(AST* tlc) { @@ -556,8 +565,7 @@ void dumben_go(AST* tlc) { stahp(0, 0, "TOO MANY DUMBS. TOO MANY DUMBS."); } - struct DumbenState state; - memset(&state, 0, sizeof(state)); + struct DumbenState state = {.targetTLC = tlc}; generic_visitor(&tlc, NULL, NULL, tlc, tlc, &state, dumben_visitor, NULL);