From 923ec25d7907038c1e3a7e6d2bd0adb3945bd9ce Mon Sep 17 00:00:00 2001 From: Mid <> Date: Mon, 30 Jun 2025 20:37:51 +0300 Subject: [PATCH] Restructure source tree, SRoA and variable pointer size --- src/ast.c | 155 ++++++++----- src/ast.h | 27 +-- src/cg.h | 8 - src/dumberdowner.h | 6 - src/ntc.c | 24 +- src/ntc.h | 9 + src/parse.c | 60 +---- src/reporting.c | 1 - src/types.c | 2 +- src/utils.h | 16 ++ src/vartable.c | 112 ---------- src/vartable.h | 111 --------- src/x86/arch.c | 52 +++++ src/{x86.h => x86/arch.h} | 115 ++++++---- src/{ => x86}/cg.c | 420 +++++++++-------------------------- src/{ => x86}/dumberdowner.c | 43 +++- 16 files changed, 413 insertions(+), 748 deletions(-) delete mode 100644 src/cg.h delete mode 100644 src/dumberdowner.h delete mode 100644 src/vartable.c delete mode 100644 src/vartable.h create mode 100644 src/x86/arch.c rename src/{x86.h => x86/arch.h} (93%) rename src/{ => x86}/cg.c (78%) rename src/{ => x86}/dumberdowner.c (95%) diff --git a/src/ast.c b/src/ast.c index 5859ecb..72164bd 100644 --- a/src/ast.c +++ b/src/ast.c @@ -7,10 +7,9 @@ #include #include"ntc.h" #include"reporting.h" +#include"utils.h" -const char *AST_KIND_STR[] = { - AST_KINDS(GEN_STRI) -}; +const char *AST_KIND_STR[] = { AST_KINDS(GEN_STRI) }; void generic_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chu, AST *tlc, void *ud, GenericVisitorHandler preHandler, GenericVisitorHandler postHandler) { if(preHandler) preHandler(nptr, stmt, stmtPrev, chu, tlc, ud); @@ -85,7 +84,7 @@ void generic_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chu, AST *tlc, v generic_visitor(&n->exprExtSizeOf.ofExpr, stmt, stmtPrev, chu, tlc, ud, preHandler, postHandler); } } else { - abort(); + stahp_node(n, "generic_visitor: unhandled %s", AST_KIND_STR[n->nodeKind]); } if(postHandler) postHandler(nptr, stmt, stmtPrev, chu, tlc, ud); @@ -398,7 +397,7 @@ static void ast_usedef_pass(AST *tlc, AST *a, AST *wholestmt) { ast_usedef_pass(tlc, a->stmtReturn.val, wholestmt); } } else { - abort(); + stahp_node(a, "ast_usedef_pass: unhandled %s", AST_KIND_STR[a->nodeKind]); } } @@ -418,20 +417,6 @@ void ast_usedef_reset(AST *chu) { return ast_usedef_pass(chu, chu, NULL); } -__attribute__((format(printf, 1, 2))) char *malp(const char *fmt, ...) { - va_list v1, v2; - va_start(v1, fmt); - va_copy(v2, v1); - size_t len = vsnprintf(NULL, 0, fmt, v1); - va_end(v1); - va_start(v2, fmt); - char *str = malloc(len + 1); - vsnprintf(str, len + 1, fmt, v2); - str[len] = 0; - va_end(v2); - return str; -} - char *type_to_string(Type *t) { if(t->type == TYPE_TYPE_PRIMITIVE) { char ret[16] = {}; @@ -893,39 +878,8 @@ void ast_grow_stack_frame(AST *tlc, size_t bytes) { generic_visitor(&tlc, NULL, NULL, tlc, tlc, &state, spill2stack_visitor, NULL); } -static void typecheck_visitor(AST **aptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *tlc, void *ud) { - AST *a = *aptr; - - if(a->nodeKind == AST_EXPR_CALL) { - if(a->exprCall.what->expression.type->type != TYPE_TYPE_FUNCTION) { - stahp_node(a, "Only function types may be called."); - } - } else if(a->nodeKind == AST_EXPR_BINARY_OP) { - if(!type_is_number(a->exprBinOp.operands[0]->expression.type) || !type_is_number(a->exprBinOp.operands[1]->expression.type)) { - stahp_node(a, "Operands must be numbers."); - } - - if(type_size(a->exprBinOp.operands[0]->expression.type) < type_size(a->exprBinOp.operands[1]->expression.type)) { - a->exprBinOp.operands[0] = ast_cast_expr(a->exprBinOp.operands[0], a->exprBinOp.operands[1]->expression.type); - } - - if(type_size(a->exprBinOp.operands[1]->expression.type) < type_size(a->exprBinOp.operands[0]->expression.type)) { - a->exprBinOp.operands[1] = ast_cast_expr(a->exprBinOp.operands[1], a->exprBinOp.operands[0]->expression.type); - } - - if(!a->exprBinOp.type) { - a->exprBinOp.type = a->exprBinOp.operands[0]->expression.type; - } - } else if(a->nodeKind == AST_EXPR_UNARY_OP) { - - } -} -void ast_type_check(AST *tlc, ScopeItem *vte) { - generic_visitor(&tlc, NULL, NULL, tlc, tlc, NULL, NULL, typecheck_visitor); -} - -// The commutativity pass makes sure that integer literals are always operand 1 in a binary operation -// This simplifies passes further down +// This pass makes sure that integer literals are always operand 1 in a binary operation, +// simplifying passes further down static void commutativity_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *tlc, void *ud) { AST *n = *nptr; @@ -942,3 +896,100 @@ static void commutativity_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chu void ast_commutativity_pass(AST *tlc) { generic_visitor(&tlc, NULL, NULL, tlc, tlc, NULL, NULL, commutativity_visitor); } + +static bool is_sroa_candidate(ScopeItem *si) { + return si->type->type == TYPE_TYPE_RECORD && type_size(si->type) <= ntc_get_int_default("sroa-threshold", 32); +} + +struct IsScopeItemReferenced { + bool yes; + ScopeItem *si; +}; +static void is_scopeitem_referenced_visitor(AST **aptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *tlc, void *ud) { + struct IsScopeItemReferenced *state = ud; + + AST *n = *aptr; + if(n->nodeKind == AST_EXPR_UNARY_OP) { + if(n->exprUnOp.operand->nodeKind == AST_EXPR_VAR && n->exprUnOp.operator == UNOP_REF && n->exprUnOp.operand->exprVar.thing == state->si) { + state->yes = true; + } + } +} +static bool is_scopeitem_referenced(AST *tlc, ScopeItem *si) { + struct IsScopeItemReferenced state = {.si = si}; + generic_visitor(&tlc, NULL, NULL, tlc, tlc, &state, NULL, is_scopeitem_referenced_visitor); + return state.yes; +} + +struct DecomposeAutomaticRecordState { + AST *tlc; + ScopeItem *target; + ScopeItem **replacements; +}; +static void ast_decompose_automatic_record_visitor(AST **aptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *tlc, void *ud) { + AST *n = *aptr; + + struct DecomposeAutomaticRecordState *state = ud; + + if(state->tlc != tlc) return; + + if(n->nodeKind == AST_EXPR_DOT && n->exprDot.a->nodeKind == AST_EXPR_VAR && n->exprDot.a->exprVar.thing == state->target) { + size_t idx; + for(idx = 0; strcmp(state->target->type->record.fieldNames[idx], n->exprDot.b); idx++); + + AST *ev = calloc(1, sizeof(ASTExprVar)); + ev->nodeKind = AST_EXPR_VAR; + ev->expression.type = state->target->type->record.fieldTypes[idx]; + ev->exprVar.thing = state->replacements[idx]; + + *aptr = (AST*) ev; + } +} +static void ast_decompose_automatic_record(AST *tlc, ScopeItem *target) { + assert(target->kind == SCOPEITEM_VAR); + assert(target->type->type == TYPE_TYPE_RECORD); + + struct DecomposeAutomaticRecordState state = { + .tlc = tlc, + .target = target, + .replacements = calloc(target->type->record.fieldCount, sizeof(ScopeItem)), + }; + + tlc->chunk.vars = realloc(tlc->chunk.vars, sizeof(*tlc->chunk.vars) * (tlc->chunk.varCount + target->type->record.fieldCount)); + + for(size_t f = 0; f < target->type->record.fieldCount; f++) { + ScopeItem *si = calloc(1, sizeof(*si)); + si->kind = SCOPEITEM_VAR; + si->type = target->type->record.fieldTypes[f]; + si->data.var.name = malp("%s_sroa_%s", target->data.var.name, target->type->record.fieldNames[f]); + state.replacements[f] = si; + + tlc->chunk.vars[tlc->chunk.varCount++] = si; + } + + generic_visitor(&tlc, NULL, NULL, tlc, tlc, &state, ast_decompose_automatic_record_visitor, NULL); + + free(state.replacements); +} + +void ast_sroa(AST *tlc) { + for(size_t i = 0; i < tlc->chunk.varCount; i++) { + ScopeItem *si = tlc->chunk.vars[i]; + + if(!is_sroa_candidate(si)) { + continue; + } + + if(is_scopeitem_referenced(tlc, si)) { + continue; + } + + ast_decompose_automatic_record(tlc, si); + + memmove(tlc->chunk.vars + i, tlc->chunk.vars + i + 1, sizeof(*tlc->chunk.vars) * (tlc->chunk.varCount - i - 1)); + tlc->chunk.varCount--; + + /* Restart */ + i = 0; + } +} diff --git a/src/ast.h b/src/ast.h index ae91588..43f4c72 100644 --- a/src/ast.h +++ b/src/ast.h @@ -3,7 +3,7 @@ #include"types.h" #include"lexer.h" -#include"vartable.h" +#include"scope.h" #pragma pack(push, 1) @@ -19,13 +19,11 @@ #define AST_KINDS(K) \ K(AST_CHUNK) \ K(AST_STMT_DECL) \ - K(AST_TYPE_IDENTIFIER) \ K(AST_EXPR_PRIMITIVE) \ K(AST_STMT_IF) \ K(AST_EXPR_BINARY_OP) \ K(AST_EXPR_VAR) \ K(AST_EXPR_STACK_POINTER) \ - K(AST_TYPE_POINTER) \ K(AST_EXPR_UNARY_OP) \ K(AST_STMT_LOOP) \ K(AST_STMT_BREAK) \ @@ -177,25 +175,6 @@ typedef struct { size_t endTokI; } ASTExprFunc; -typedef struct { - ASTBase; - - size_t size; -} ASTType; - -typedef struct { - ASTType; - - Token identifier; -} ASTTypeIdentifier; - -typedef struct { - ASTType; - - union AST *child; - int levels; -} ASTTypePointer; - typedef struct { ASTBase; union AST *next; @@ -378,6 +357,8 @@ void ast_typecheck(AST *tlc); void ast_grow_stack_frame(AST *tlc, size_t bytes); -__attribute__((format(printf, 1, 2))) char *malp(const char *fmt, ...); +void ast_commutativity_pass(AST *tlc); + +void ast_sroa(AST *tlc); #endif diff --git a/src/cg.h b/src/cg.h deleted file mode 100644 index bc74619..0000000 --- a/src/cg.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef H_CG -#define H_CG - -#include"ast.h" - -int cg_go(union AST*); - -#endif diff --git a/src/dumberdowner.h b/src/dumberdowner.h deleted file mode 100644 index ae44e44..0000000 --- a/src/dumberdowner.h +++ /dev/null @@ -1,6 +0,0 @@ -#pragma once - -#include"ast.h" - -void dumben_pre(AST *tlc); -void dumben_go(AST* tlc); diff --git a/src/ntc.c b/src/ntc.c index 0115adc..95517e6 100644 --- a/src/ntc.c +++ b/src/ntc.c @@ -7,15 +7,12 @@ #include"parse.h" #include"ntc.h" #include"reporting.h" -#include"cg.h" -#include"dumberdowner.h" -#include"x86.h" #include"utils.h" static int argc; static char **argv; -static char **includePaths; +static const char **includePaths; const char **ntc_get_import_paths() { return (const char**) includePaths; } @@ -35,15 +32,19 @@ const char* ntc_get_arg(const char *name) { } intmax_t ntc_get_int(const char *name) { + return ntc_get_int_default(name, 0); +} + +intmax_t ntc_get_int_default(const char *name, intmax_t def) { const char *val = ntc_get_arg(name); if(!val) { - return 0; + return def; } long result = 0; - if(!unstupid_strtol(val, (const char**) &val, 0, &result)) { - return 0; + if(!unstupid_strtol(val, (char**) &val, 0, &result)) { + return def; } return result; @@ -53,7 +54,7 @@ int main(int argc_, char **argv_) { argc = argc_; argv = argv_; - if(x86_target() == IUNKNOWN86) { + if(!arch_verify_target()) { stahp(0, 0, "Unknown architecture %s", ntc_get_arg("target")); } @@ -93,17 +94,12 @@ int main(int argc_, char **argv_) { free(astdump); } + ast_sroa(chunk); dumben_pre(chunk); dumben_go(chunk); while(!cg_go(chunk)) { dumben_go(chunk); - - if(ntc_get_int("pdbg")) { - char *astdump = ast_dump(chunk); - fprintf(stderr, "### CG FAILURE ###\n%s\n", astdump); - free(astdump); - } } return 0; diff --git a/src/ntc.h b/src/ntc.h index 84bc5ef..3d533bc 100644 --- a/src/ntc.h +++ b/src/ntc.h @@ -3,11 +3,20 @@ #include #include +#include const char **ntc_get_import_paths(); const char* ntc_get_arg(const char *name); intmax_t ntc_get_int(const char *name); +intmax_t ntc_get_int_default(const char *name, intmax_t def); + +union AST; +bool arch_verify_target(); +int arch_ptr_size(); +void dumben_pre(union AST *tlc); +void dumben_go(union AST *tlc); +int cg_go(union AST *tlc); #endif diff --git a/src/parse.c b/src/parse.c index bc60309..4b793ac 100644 --- a/src/parse.c +++ b/src/parse.c @@ -4,11 +4,11 @@ #include #include #include"utils.h" -#include"vartable.h" +#include"scope.h" #include"reporting.h" #include #include -#include"x86.h" +#include"ntc.h" #ifndef __GNUC__ static inline int __builtin_clzl(unsigned long x) { @@ -177,9 +177,10 @@ static AST *exprvar(Parser *P, ScopeItem *v) { return a; } -ASTChunk *nct_parse_chunk(Parser*, int, int, Scope*, Type *ft); -Type *nct_parse_typename(Parser *P); +static ASTChunk *nct_parse_chunk(Parser*, int, int, Scope*, Type *ft); +static Type *nct_parse_typename(Parser *P); static bool parse_parametrization(Parser *P); +static void parse_genericization(Parser *P); static char *parametrize_function_name(Type *t, const char *original, Scope *scope); static void binop_implicit_cast(/*Parser *P, */ASTExprBinaryOp *binop) { @@ -571,8 +572,7 @@ AST *nct_parse_expression(Parser *P, int lOP) { astop->type = NULL; astop->operator = op; astop->operands[0] = ret; - - ASTExpr *operand = &(astop->operands[1] = nct_parse_expression(P, lOP + 1))->expression; + astop->operands[1] = nct_parse_expression(P, lOP + 1); if(!type_is_number(astop->operands[0]->expression.type) || !type_is_number(astop->operands[1]->expression.type)) { @@ -713,7 +713,7 @@ backtrack: } /* Since this function backtracks, don't use aborting functions like expect. */ -Type *nct_parse_typename(Parser *P) { +static Type *nct_parse_typename(Parser *P) { int oldIdx = P->i; bool generics = peek(P, 0).type == TOKEN_SQUAREN_L; @@ -1028,47 +1028,7 @@ static char *parametrize_function_name(Type *t, const char *original, Scope *sco return s; } -/*static void add_parametrizations_to_scope(Parser *P, Parametrizations *parametrizations, Parametrizations *renames) { - Parametrization *c = parametrizations->typeParams; - Parametrization *g = renames->typeParams; - while(c && g) { - Type *ct = (Type*) c->param; - Type *gt = (Type*) g->param; - - assert(!!ct == !!gt); - - ScopeItem *vte = calloc(1, sizeof(*vte)); - vte->kind = SCOPEITEM_TYPE; - vte->data.type.ptr = ct; - scope_set(P->scope, gt->generic.paramName, vte); - - c = c->next; - g = g->next; - } - - size_t idx = 0; - c = parametrizations->intParams; - g = renames->intParams; - while(c && g) { - AST *node = c->param; - char *name = g->param; - - assert(!!node == !!name); - - ScopeItem *vte = calloc(1, sizeof(*vte)); - vte->kind = SCOPEITEM_CEXPR; - vte->data.cexpr.paramIdx = idx; - vte->data.cexpr.paramName = name; - vte->data.cexpr.concrete = node; - scope_set(P->scope, name, vte); - - c = c->next; - g = g->next; - idx++; - } -}*/ - -void nct_parse_statement(Parser *P) { +static void nct_parse_statement(Parser *P) { if(maybe(P, TOKEN_IF)) { expect(P, TOKEN_PAREN_L); AST *e = nct_parse_expression(P, 0); @@ -1369,7 +1329,7 @@ void nct_parse_statement(Parser *P) { * This function inserts VTEs into the *current* scope. * Make sure to create a child scope before using. * */ -void parse_genericization(Parser *P) { +static void parse_genericization(Parser *P) { expect(P, TOKEN_SQUAREN_L); bool integerMode = false; @@ -1602,7 +1562,7 @@ ASTChunk *nct_parse_chunk(Parser *P, int isTopLevel, int varPrioritize, Scope *t ret->chunk.vars = NULL; ret->chunk.stackReservation = 0; - AST *oldChunk = (AST*) P->currentChunk; + ASTChunk *oldChunk = P->currentChunk; P->currentChunk = &ret->chunk; Scope *oldScope = P->scope; diff --git a/src/reporting.c b/src/reporting.c index 5014185..be7b088 100644 --- a/src/reporting.c +++ b/src/reporting.c @@ -12,7 +12,6 @@ static void stahp_va(int row, int column, const char *error, va_list l) { fputc('\n', stderr); } -/* Abort immediately on first error (for now) */ void stahp(int row, int column, const char *error, ...) { va_list l; va_start(l, error); diff --git a/src/types.c b/src/types.c index 97a8fe0..0734837 100644 --- a/src/types.c +++ b/src/types.c @@ -99,7 +99,7 @@ size_t type_size(Type *t) { return w; } else if(t->type == TYPE_TYPE_POINTER || t->type == TYPE_TYPE_FUNCTION) { - return 4; + return arch_ptr_size(); } else if(t->type == TYPE_TYPE_ARRAY) { return type_size(t->array.of) * t->array.length; } else if(t->type == TYPE_TYPE_RECORD) { diff --git a/src/utils.h b/src/utils.h index 2e8724e..e3d3f5a 100644 --- a/src/utils.h +++ b/src/utils.h @@ -5,6 +5,8 @@ #include #include #include +#include +#include inline static size_t djb2(const char *str) { size_t hash = 5381; @@ -38,4 +40,18 @@ inline static bool unstupid_strtol(const char *str, char **endptr, int base, lon return true; } +__attribute__((format(printf, 1, 2))) static inline char *malp(const char *fmt, ...) { + va_list v1, v2; + va_start(v1, fmt); + va_copy(v2, v1); + size_t len = vsnprintf(NULL, 0, fmt, v1); + va_end(v1); + va_start(v2, fmt); + char *str = malloc(len + 1); + vsnprintf(str, len + 1, fmt, v2); + str[len] = 0; + va_end(v2); + return str; +} + #endif diff --git a/src/vartable.c b/src/vartable.c deleted file mode 100644 index 5cb73d7..0000000 --- a/src/vartable.c +++ /dev/null @@ -1,112 +0,0 @@ -#include"vartable.h" - -#include"utils.h" -#include -#include -#include -#include - -struct ReachingDefs *reachingdefs_push(struct ReachingDefs *this) { - struct ReachingDefs *ret = calloc(1, sizeof(*ret)); - ret->parent = this; - return ret; -} - -struct ReachingDefs *reachingdefs_coalesce(struct ReachingDefs *this) { - struct ReachingDefs *parent = this->parent; - if(parent) { - parent->defs = realloc(parent->defs, sizeof(*parent->defs) * (parent->defCount + this->defCount)); - memcpy(&parent->defs[parent->defCount], this->defs, sizeof(*this->defs) * this->defCount); - parent->defCount += this->defCount; - } - free(this->defs); - free(this); - return parent; -} - -void reachingdefs_set(struct ReachingDefs *this, union AST *def) { - this->defCount = 1; - this->defs = realloc(this->defs, sizeof(*this->defs) * this->defCount); - this->defs[0] = def; - this->excludeParent = 1; -} - -Scope *scope_new(Scope *parent) { - Scope *ret = calloc(1, sizeof(*ret)); - ret->parent = parent; - ret->count = 0; - ret->names = NULL; - ret->data = NULL; - - return ret; -} - -ScopeItem *scope_get(Scope *this, const char *name) { - for(size_t v = 0; v < this->count; v++) { - if(!strcmp(name, this->names[v])) return this->data[v]; - } - return NULL; -} - -ScopeItem *scope_find(Scope *this, const char *name) { - Scope *tbl = this; - while(tbl) { - ScopeItem *entry = scope_get(tbl, name); - if(entry) { - return entry; - } - tbl = tbl->parent; - } - return NULL; -} - -ScopeItem *scope_set(Scope *this, const char *name, ScopeItem *e) { - name = strdup(name); - - this->names = realloc(this->names, sizeof(*this->names) * (this->count + 1)); - this->data = realloc(this->data, sizeof(*this->data) * (this->count + 1)); - this->names[this->count] = name; - this->data[this->count] = e; - this->count++; - if(e->kind == SCOPEITEM_VAR) e->data.var.name = name; - e->owner = this; - return e; -} - -ScopeItem *scope_find_int(Scope *scope, intmax_t val, const char *suffix) { - char buf[64]; - snprintf(buf, sizeof(buf), "%li%s", val, suffix ? suffix : ""); - - return scope_find(scope, buf); -} - -Scope *scope_merge(Scope *child) { - Scope *parent = child->parent; - - parent->names = realloc(parent->names, sizeof(*parent->names) * (parent->count + child->count)); - parent->data = realloc(parent->data, sizeof(*parent->data) * (parent->count + child->count)); - - for(size_t i = 0; i < child->count; i++) { - child->data[i]->owner = parent; - - parent->names[parent->count] = child->names[i]; - parent->data[parent->count] = child->data[i]; - - parent->count++; - } - - //free(child->names); - //free(child->data); - //free(child); - - return parent; -} - -void vte_precolor(ScopeItem *vte, int class, int color) { - assert(vte->kind == SCOPEITEM_VAR && "vte must be var"); - assert(!vte->data.var.precolored && "already precolored"); - - vte->data.var.precolored = true; - vte->data.var.registerClass = class; - vte->data.var.color = color; -} diff --git a/src/vartable.h b/src/vartable.h deleted file mode 100644 index 78fb887..0000000 --- a/src/vartable.h +++ /dev/null @@ -1,111 +0,0 @@ -#ifndef NCTREF_VARTABLE_H -#define NCTREF_VARTABLE_H - -#include"types.h" -#include - -struct Token; -union AST; - -typedef enum { - SCOPEITEM_SYMBOL, SCOPEITEM_VAR, SCOPEITEM_TYPE, SCOPEITEM_CEXPR -} ScopeItemKind; - -union AST; -typedef struct UseDef { - union AST *def; // assign stmt - union AST *use; // corresponding AST_EXPR_VAR - union AST *stmt; // whole using stmt - struct UseDef *next; -} UseDef; - -// Stack, necessary for "possible reaching defs" such as from if statements -typedef struct ReachingDefs { - size_t defCount; - union AST **defs; - - int excludeParent; - struct ReachingDefs *parent; -} ReachingDefs; -struct ReachingDefs *reachingdefs_push(struct ReachingDefs*); -struct ReachingDefs *reachingdefs_coalesce(struct ReachingDefs*); -void reachingdefs_set(struct ReachingDefs*, union AST*); - -struct Scope; -typedef struct ScopeItem { - Type *type; - - struct Scope *owner; - - ScopeItemKind kind; - union { - struct { - char isLocal; - char isExternal; - const char *name; - - struct { - struct Scope *scope; - struct Token *rangeTokens; - size_t startTokI; - size_t endTokI; - } genfunc; - } symbol; - struct { - // For debugging - - const char *name; - - // Register allocation - - // vars in loops have higher priority - // a more advanced approach would be to use weights for different colors (e.g. multipliers "should" be in eax) - uint8_t priority; - int16_t color, degree; - bool precolored; - int registerClass; - - // Used during parsing - - ReachingDefs *reachingDefs; - - // Optimizations - - UseDef *usedefFirst; - UseDef *usedefLast; - } var; - struct { - Type *ptr; - } type; - struct { - // cexpr is used for expression parametization as opposed to type parametrization - // I don't like the idea of having a special ScopeItem kind for these, but all other places were worse - const char *paramName; - size_t paramIdx; - - // If the cexpr has been parametrized (as opposed to just being a symbol), this field will be non-NULL - union AST *concrete; - } cexpr; - } data; -} ScopeItem; - -typedef struct Scope { - struct Scope *parent; - - size_t count; - const char **names; - ScopeItem **data; -} Scope; - -Scope *scope_new(Scope*); -ScopeItem *scope_get(Scope*, const char*); -ScopeItem *scope_find(Scope*, const char*); -ScopeItem *scope_set(Scope*, const char*, ScopeItem*); - -ScopeItem *scope_find_int(Scope*, intmax_t, const char*); - -Scope *scope_merge(Scope *child); - -void vte_precolor(ScopeItem *vte, int resclass, int color); - -#endif diff --git a/src/x86/arch.c b/src/x86/arch.c new file mode 100644 index 0000000..bf84fc7 --- /dev/null +++ b/src/x86/arch.c @@ -0,0 +1,52 @@ +#include"arch.h" + +RegisterClass REG_CLASSES[] = { + [REG_CLASS_8] = { + .rMask = HWR_GPR, .w = 1, .p = 8, + .rs = {HWR_AL, HWR_AH, HWR_BL, HWR_BH, HWR_CL, HWR_CH, HWR_DL, HWR_DH}, + .rsN = {"al", "ah", "bl", "bh", "cl", "ch", "dl", "dh"}, + .rsS = {1, 1, 1, 1, 1, 1, 1, 1}, + }, + [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}, + }, + [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}, + }, + [REG_CLASS_IND] = { + .rMask = HWR_IND, .w = 2, .p = 2, + .rs = {HWR_DI, HWR_EDI, HWR_SI, HWR_ESI}, + .rsN = {"di", "edi", "si", "esi"}, + .rsS = {2, 4, 2, 4}, + }, + [REG_CLASS_IA16_PTRS] = { + .rMask = HWR_IND | HWR_BX, + .rs = {HWR_DI, HWR_SI, HWR_BX}, + .rsN = {"di", "si", "bx"}, + .rsS = {2, 2, 2}, + }, + [REG_CLASS_DATASEGS] = { + .rMask = HWR_IND | HWR_BX, + .rs = {HWR_DS, HWR_ES, HWR_FS, HWR_GS}, + .rsN = {"ds", "es", "fs", "gs"}, + .rsS = {2, 2, 2}, + }, +}; + +bool arch_verify_target() { + if(x86_target() == IUNKNOWN86) { + return false; + } + + return true; +} + +int arch_ptr_size() { + return x86_ia16() ? 2 : 4; +} diff --git a/src/x86.h b/src/x86/arch.h similarity index 93% rename from src/x86.h rename to src/x86/arch.h index ee8f779..5aeb71e 100644 --- a/src/x86.h +++ b/src/x86/arch.h @@ -18,6 +18,11 @@ #define HWR_DI 256 #define HWR_SI 512 +#define HWR_DS 1024 +#define HWR_ES 2048 +#define HWR_FS 4096 +#define HWR_GS 8192 + #define HWR_AX (HWR_AL | HWR_AH) #define HWR_BX (HWR_BL | HWR_BH) #define HWR_CX (HWR_CL | HWR_CH) @@ -50,7 +55,9 @@ typedef struct RegisterClass { #define REG_CLASS_NOT_8 1 #define REG_CLASS_16_32 2 #define REG_CLASS_IND 3 -extern RegisterClass REG_CLASSES[4]; +#define REG_CLASS_IA16_PTRS 4 +#define REG_CLASS_DATASEGS 5 +extern RegisterClass REG_CLASSES[]; // lol static inline bool is_reg_b(int cls, int res) { @@ -88,6 +95,58 @@ static inline void reg_cast_up(int *cls, int *res) { } } +typedef enum { + I086 = 0, + I186 = 1, + I286 = 2, + I386 = 3, + IUNKNOWN86 = 255, +} X86Target; + +static inline X86Target x86_target() { + const char *str = ntc_get_arg("target"); + + if(!str) return I386; + + if(!strcmp(str, "086")) { + return I086; + } + + if(!strcmp(str, "186")) { + return I186; + } + + if(!strcmp(str, "286")) { + return I286; + } + + if(!strcmp(str, "386")) { + return I386; + } + + return IUNKNOWN86; +} + +static inline bool x86_ia16() { + return x86_target() < I386; +} + +static inline size_t x86_max_gpr_size() { + switch(x86_target()) { + case I086: + case I186: + case I286: + return 2; + case I386: + return 4; + default: abort(); + } +} + +static inline bool x86_imul_supported() { + return x86_target() >= I186; +} + // Can expression be expressed as a single x86 operand? #define XOP_NOT_XOP 0 #define XOP_NOT_MEM 1 @@ -113,6 +172,12 @@ static inline int is_xop(AST *e) { } if(c->nodeKind == AST_EXPR_VAR && c->exprVar.thing->kind == SCOPEITEM_VAR) { + if(x86_ia16()) { // In IA-16, pointers MUST be preclassed to REG_CLASS_IA16_PTRS + if(!c->exprVar.thing->data.var.preclassed || c->exprVar.thing->data.var.registerClass != REG_CLASS_IA16_PTRS) { + return XOP_NOT_XOP; + } + } + return XOP_MEM; } else if( (c->nodeKind == AST_EXPR_BINARY_OP && c->exprBinOp.operator == BINOP_ADD && c->exprBinOp.operands[0]->nodeKind == AST_EXPR_UNARY_OP && c->exprBinOp.operands[0]->exprUnOp.operator == UNOP_REF && c->exprBinOp.operands[0]->exprUnOp.operand->nodeKind == AST_EXPR_VAR) || @@ -150,54 +215,6 @@ typedef enum { GUCCI, } WhysItBad_Huh; -typedef enum { - I086 = 0, - I186 = 1, - I286 = 2, - I386 = 3, - IUNKNOWN86 = 255, -} X86Target; - -static inline X86Target x86_target() { - const char *str = ntc_get_arg("target"); - - if(!str) return I386; - - if(!strcmp(str, "086")) { - return I086; - } - - if(!strcmp(str, "186")) { - return I186; - } - - if(!strcmp(str, "286")) { - return I286; - } - - if(!strcmp(str, "386")) { - return I386; - } - - return IUNKNOWN86; -} - -static inline size_t x86_max_gpr_size() { - switch(x86_target()) { - case I086: - case I186: - case I286: - return 2; - case I386: - return 4; - default: abort(); - } -} - -static inline bool x86_imul_supported() { - return x86_target() >= I186; -} - static inline WhysItBad_Huh x86_test_mul_matching_mulhi(AST *mulhi, AST *mul) { assert(mulhi->statement.next == mul); diff --git a/src/cg.c b/src/x86/cg.c similarity index 78% rename from src/cg.c rename to src/x86/cg.c index 1f5cd53..cf21819 100644 --- a/src/cg.c +++ b/src/x86/cg.c @@ -1,14 +1,12 @@ -#include"cg.h" - #include #include #include #include -#include"dumberdowner.h" +#include"ntc.h" #include"reporting.h" #include"ast.h" - -#include"x86.h" +#include"arch.h" +#include"utils.h" static const char *BINOP_SIMPLE_INSTRS[] = {[BINOP_ADD] = "add", [BINOP_SUB] = "sub", [BINOP_BITWISE_AND] = "and", [BINOP_BITWISE_OR] = "or", [BINOP_BITWISE_XOR] = "xor"}; @@ -65,6 +63,8 @@ static const char *specexpr(AST *e) { static const char *xv_sz(ScopeItem *v, int sz) { assert(v->kind == SCOPEITEM_VAR); + if(sz == 0) sz = arch_ptr_size(); + #define XVBUFS 8 #define XVBUFSZ 16 static char bufs[XVBUFS][XVBUFSZ]; @@ -137,11 +137,6 @@ static const char *xop_sz(AST *tlc, AST *e, int sz) { char *ret = bufs[bufidx]; - //if(e->nodeKind == AST_EXPR_CAST && e->exprCast.what->expression.type->type == TYPE_TYPE_POINTER && e->exprCast.to->type == TYPE_TYPE_POINTER) { - /*if(e->nodeKind == AST_EXPR_CAST) { - e = e->exprCast.what; - }*/ - if(e->nodeKind == AST_EXPR_UNARY_OP && e->exprUnOp.operator == UNOP_DEREF) { AST *p = e->exprUnOp.operand; @@ -152,13 +147,13 @@ static const char *xop_sz(AST *tlc, AST *e, int sz) { if(p->nodeKind == AST_EXPR_BINARY_OP && p->exprBinOp.operator == BINOP_ADD && p->exprBinOp.operands[0]->nodeKind == AST_EXPR_VAR && p->exprBinOp.operands[1]->nodeKind == AST_EXPR_VAR && p->exprBinOp.operands[0]->exprVar.thing->kind == SCOPEITEM_VAR && p->exprBinOp.operands[1]->exprVar.thing->kind == SCOPEITEM_VAR) { snprintf(ret, XOPBUFSZ, "%s [%s + %s]", spec(sz), - xv_sz(p->exprBinOp.operands[0]->exprVar.thing, 4), - xv_sz(p->exprBinOp.operands[1]->exprVar.thing, 4)); + xv_sz(p->exprBinOp.operands[0]->exprVar.thing, 0), + xv_sz(p->exprBinOp.operands[1]->exprVar.thing, 0)); } else if(p->nodeKind == AST_EXPR_BINARY_OP && p->exprBinOp.operator == BINOP_ADD && p->exprBinOp.operands[0]->nodeKind == AST_EXPR_UNARY_OP && p->exprBinOp.operands[1]->nodeKind == AST_EXPR_VAR && p->exprBinOp.operands[0]->exprUnOp.operator == UNOP_REF && p->exprBinOp.operands[0]->exprUnOp.operand->nodeKind == AST_EXPR_VAR && p->exprBinOp.operands[0]->exprUnOp.operand->exprVar.thing->kind == SCOPEITEM_SYMBOL && p->exprBinOp.operands[1]->exprVar.thing->kind == SCOPEITEM_VAR) { snprintf(ret, XOPBUFSZ, "%s [%s + %s]", spec(sz), p->exprBinOp.operands[0]->exprUnOp.operand->exprVar.thing->data.symbol.name, - xv_sz(p->exprBinOp.operands[1]->exprVar.thing, 4)); + xv_sz(p->exprBinOp.operands[1]->exprVar.thing, 0)); } else if(is_field_access(e)) { e = is_field_access(e); @@ -184,9 +179,9 @@ static const char *xop_sz(AST *tlc, AST *e, int sz) { spec(sz), p->exprBinOp.operands[0]->exprUnOp.operand->exprVar.thing->data.symbol.name, p->exprBinOp.operands[1]->exprBinOp.operands[0]->exprPrim.val, - xv_sz(p->exprBinOp.operands[1]->exprBinOp.operands[1]->exprVar.thing, 4)); + xv_sz(p->exprBinOp.operands[1]->exprBinOp.operands[1]->exprVar.thing, 0)); } else if(p->nodeKind == AST_EXPR_VAR && p->exprVar.thing->kind == SCOPEITEM_VAR) { - snprintf(ret, XOPBUFSZ, "%s [%s]", spec(sz), xv_sz(p->exprVar.thing, 4)); + snprintf(ret, XOPBUFSZ, "%s [%s]", spec(sz), xv_sz(p->exprVar.thing, 0)); } else if(p->nodeKind == AST_EXPR_BINARY_OP && p->exprBinOp.operator == BINOP_ADD && p->exprBinOp.operands[0]->nodeKind == AST_EXPR_STACK_POINTER && p->exprBinOp.operands[1]->nodeKind == AST_EXPR_PRIMITIVE) { snprintf(ret, XOPBUFSZ, "[esp + %i]", p->exprBinOp.operands[1]->exprPrim.val); } else { @@ -291,6 +286,8 @@ void cg_chunk(CGState *cg, AST *a) { // Generic functions have non-NULL code blocks if(!type_is_generic(s->stmtDecl.expression->expression.type)) { + ast_sroa(s->stmtDecl.expression->exprFunc.chunk); + dumben_pre(s->stmtDecl.expression->exprFunc.chunk); dumben_go(s->stmtDecl.expression->exprFunc.chunk); @@ -397,8 +394,8 @@ void cg_chunk(CGState *cg, AST *a) { } else if(s->stmtAssign.what->nodeKind == AST_EXPR_VAR && s->stmtAssign.to->nodeKind == AST_EXPR_BINARY_OP && s->stmtAssign.to->exprBinOp.operator == BINOP_ADD && s->stmtAssign.to->exprBinOp.operands[0]->nodeKind == AST_EXPR_VAR && s->stmtAssign.to->exprBinOp.operands[1]->nodeKind == AST_EXPR_PRIMITIVE && s->stmtAssign.to->exprBinOp.operands[0]->exprVar.thing->kind == SCOPEITEM_VAR) { printf("lea %s, [%s + %i]\n", - xv_sz(s->stmtAssign.what->exprVar.thing, 4), - xv_sz(s->stmtAssign.to->exprBinOp.operands[0]->exprVar.thing, 4), + xv_sz(s->stmtAssign.what->exprVar.thing, 0), + xv_sz(s->stmtAssign.to->exprBinOp.operands[0]->exprVar.thing, 0), s->stmtAssign.to->exprBinOp.operands[1]->exprPrim.val); } else if(s->stmtAssign.to->nodeKind == AST_EXPR_UNARY_OP && s->stmtAssign.to->exprUnOp.operator == UNOP_NEGATE && ast_expression_equal(s->stmtAssign.what, s->stmtAssign.to->exprUnOp.operand)) { @@ -501,174 +498,6 @@ void cg_chunk(CGState *cg, AST *a) { } } -struct Spill2VarState { - ScopeItem *target; -}; -static void spill2var_visitor(AST **aptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *tlc, void *ud) { - static size_t vidx = 0; - - struct Spill2VarState *this = ud; - - AST *a = *aptr; - - if(a->nodeKind == AST_STMT_ASSIGN && a->stmtAssign.to->nodeKind == AST_EXPR_CALL) { - assert(a->stmtAssign.what->nodeKind == AST_EXPR_VAR && a->stmtAssign.what->exprVar.thing->kind == SCOPEITEM_VAR); - - if(a->stmtAssign.what->exprVar.thing == this->target) { - - ScopeItem *new = calloc(1, sizeof(*new)); - new->kind = SCOPEITEM_VAR; - new->type = a->stmtAssign.what->exprVar.thing->type; - new->data.var.name = malp("$s2v_%lu", vidx++); - - tlc->chunk.vars = realloc(tlc->chunk.vars, sizeof(*tlc->chunk.vars) * (++tlc->chunk.varCount)); - tlc->chunk.vars[tlc->chunk.varCount - 1] = new; - - ASTExprVar *ev0 = calloc(1, sizeof(*ev0)); - ev0->nodeKind = AST_EXPR_VAR; - ev0->type = new->type; - ev0->thing = a->stmtAssign.what->exprVar.thing; - - ASTExprVar *ev1 = calloc(1, sizeof(*ev1)); - ev1->nodeKind = AST_EXPR_VAR; - ev1->type = new->type; - ev1->thing = new; - - ASTStmtAssign *ass = calloc(1, sizeof(*ass)); - ass->nodeKind = AST_STMT_ASSIGN; - ass->what = (AST*) ev0; - ass->to = (AST*) ev1; - - a->stmtAssign.what->exprVar.thing = new; - - ass->next = a->statement.next; - a->statement.next = (AST*) ass; - - if(!ass->next) { - chunk->chunk.statementLast = (AST*) ass; - } - - } - } - - if(a->nodeKind == AST_STMT_RETURN && a->stmtReturn.val && a->stmtReturn.val->nodeKind == AST_EXPR_VAR && a->stmtReturn.val->exprVar.thing == this->target) { - - ScopeItem *new = calloc(1, sizeof(*new)); - new->kind = SCOPEITEM_VAR; - new->type = a->stmtReturn.val->exprVar.thing->type; - new->data.var.name = malp("$s2v_%lu", vidx++); - - tlc->chunk.vars = realloc(tlc->chunk.vars, sizeof(*tlc->chunk.vars) * (++tlc->chunk.varCount)); - tlc->chunk.vars[tlc->chunk.varCount - 1] = new; - - ASTExprVar *ev0 = calloc(1, sizeof(*ev0)); - ev0->nodeKind = AST_EXPR_VAR; - ev0->type = new->type; - ev0->thing = a->stmtReturn.val->exprVar.thing; - - ASTExprVar *ev1 = calloc(1, sizeof(*ev1)); - ev1->nodeKind = AST_EXPR_VAR; - ev1->type = new->type; - ev1->thing = new; - - ASTStmtAssign *ass = calloc(1, sizeof(*ass)); - ass->nodeKind = AST_STMT_ASSIGN; - ass->what = (AST*) ev1; - ass->to = (AST*) ev0; - - stmt->stmtReturn.val->exprVar.thing = new; - - ass->next = stmt; - - if(stmtPrev) { - stmtPrev->statement.next = (AST*) ass; - } else { - chunk->chunk.statementFirst = (AST*) ass; - } - } -} - -/*struct PrecolorState { - ScopeItem *mustBeSpilled; -}; -static void precolor_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *tlc, void *ud) { - struct PrecolorState *this = ud; - - if(this->mustBeSpilled) { - // Since something must be spilled first, we can't do anything else. Quit ASAP. - return; - } - - AST *n = *nptr; - - if(n == tlc) { - for(size_t i = 0; i < n->chunk.varCount; i++) { - n->chunk.vars[i]->data.var.color = -1; - n->chunk.vars[i]->data.var.precolored = false; - } - } - - if(n->nodeKind == AST_STMT_RETURN && n->stmtReturn.val) { - assert(n->stmtReturn.val->nodeKind == AST_EXPR_VAR && n->stmtReturn.val->exprVar.thing->kind == SCOPEITEM_VAR); - - ScopeItem *vte = n->stmtReturn.val->exprVar.thing; - - const int requiredColor = COLOR_EAX; - - if(vte->data.var.precolored && vte->data.var.color != requiredColor) { - // Precoloring collision! - this->mustBeSpilled = vte; - return; - } - - vte->data.var.color = requiredColor; - vte->data.var.precolored = true; - } else if(n->nodeKind == AST_STMT_ASSIGN && n->stmtAssign.to->nodeKind == AST_EXPR_CALL) { - assert(n->stmtAssign.what->nodeKind == AST_EXPR_VAR && n->stmtAssign.what->exprVar.thing->kind == SCOPEITEM_VAR); - - ScopeItem *vte = n->stmtAssign.what->exprVar.thing; - - const int requiredColor = COLOR_EAX; - - if(vte->data.var.precolored && vte->data.var.color != requiredColor) { - // Precoloring collision! - this->mustBeSpilled = vte; - return; - } - - vte->data.var.color = requiredColor; - vte->data.var.precolored = true; - } else if(n->nodeKind == AST_STMT_ASSIGN && n->stmtAssign.what->nodeKind == AST_EXPR_VAR && n->stmtAssign.what->exprVar.thing->kind == SCOPEITEM_VAR && n->stmtAssign.to->nodeKind == AST_EXPR_BINARY_OP && n->stmtAssign.to->exprBinOp.operator == BINOP_MUL) { - - ScopeItem *vte = n->stmtAssign.what->exprVar.thing; - - const int requiredColor = COLOR_EAX; - - if(vte->data.var.precolored && vte->data.var.color != requiredColor) { - // Precoloring collision! - this->mustBeSpilled = vte; - return; - } - - vte->data.var.color = requiredColor; - vte->data.var.precolored = true; - } else if(n->nodeKind == AST_STMT_ASSIGN && n->stmtAssign.what->nodeKind == AST_EXPR_VAR && n->stmtAssign.what->exprVar.thing->kind == SCOPEITEM_VAR && n->stmtAssign.to->nodeKind == AST_EXPR_BINARY_OP && n->stmtAssign.to->exprBinOp.operator == BINOP_MULHI) { - - ScopeItem *vte = n->stmtAssign.what->exprVar.thing; - - const int requiredColor = COLOR_EDX; - - if(vte->data.var.precolored && vte->data.var.color != requiredColor) { - // Precoloring collision! - this->mustBeSpilled = vte; - return; - } - - vte->data.var.color = requiredColor; - vte->data.var.precolored = true; - } -}*/ - typedef ScopeItem *Adjacency[2]; static bool var_collision(AST *tlc, ScopeItem *v1, ScopeItem *v2) { @@ -686,51 +515,6 @@ static bool var_collision(AST *tlc, ScopeItem *v1, ScopeItem *v2) { return liveRangeIntersection && resourceIntersection; } -/*static ScopeItem *get_precolor_spill_candidate(AST *tlc) { - Adjacency *adjs = NULL; - size_t adjCount = 0; - - for(size_t i = 0; i < tlc->chunk.varCount; i++) { - tlc->chunk.vars[i]->data.var.degree = 0; - - for(size_t j = 0; j < tlc->chunk.varCount; j++) { - - if( tlc->chunk.vars[i]->data.var.precolored - && tlc->chunk.vars[j]->data.var.precolored - && tlc->chunk.vars[i]->data.var.color == tlc->chunk.vars[j]->data.var.color - && var_collision(tlc, tlc->chunk.vars[i], tlc->chunk.vars[j])) { - - adjs = realloc(adjs, sizeof(*adjs) * ++adjCount); - - adjs[adjCount - 1][0] = tlc->chunk.vars[i]; - adjs[adjCount - 1][1] = tlc->chunk.vars[j]; - } - - } - } - - if(adjCount == 0) { - return NULL; - } - - for(size_t a = 0; a < adjCount; a++) { - adjs[a][0]->data.var.degree++; - adjs[a][1]->data.var.degree++; - } - - ScopeItem *maxdeg = tlc->chunk.vars[0]; - - for(size_t v = 1; v < tlc->chunk.varCount; v++) { - if(maxdeg->data.var.degree < tlc->chunk.vars[v]->data.var.degree) { - maxdeg = tlc->chunk.vars[v]; - } - } - - free(adjs); - - return maxdeg; -}*/ - struct CalleeSavedState { AST *targetTLC; @@ -895,36 +679,18 @@ static void callee_saved(AST *tlc) { } } -/*struct DetermineRegisterClassesState { - int isInDereference; -}; -static void determine_register_classes_visitor_pre(AST **nptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *tlc, void *ud) { - struct DetermineRegisterClassesState *this = ud; - - AST *n = *nptr; - if(n->nodeKind == AST_EXPR_UNARY_OP && n->exprUnOp.operator == UNOP_DEREF) { - this->isInDereference++; - } -} -static void determine_register_classes_visitor_post(AST **nptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *tlc, void *ud) { - struct DetermineRegisterClassesState *this = ud; - - AST *n = *nptr; - if(n->nodeKind == AST_EXPR_UNARY_OP && n->exprUnOp.operator == UNOP_DEREF) { - this->isInDereference--; - } -}*/ static void determine_register_classes(AST *tlc) { for(size_t v = 0; v < tlc->chunk.varCount; v++) { + if(tlc->chunk.vars[v]->data.var.preclassed) { + continue; + } + if(type_size(tlc->chunk.vars[v]->type) == 1) { tlc->chunk.vars[v]->data.var.registerClass = REG_CLASS_8; } else { tlc->chunk.vars[v]->data.var.registerClass = REG_CLASS_NOT_8; } } - - //struct DetermineRegisterClassesState state = {}; - //generic_visitor(&tlc, NULL, NULL, tlc, tlc, &state, determine_register_classes_visitor_pre, determine_register_classes_visitor_post); } /* Welsh-Powell graph coloring */ @@ -933,72 +699,16 @@ static int comparator(const void *A, const void *B) { ScopeItem *const *b = B; return ((*a)->data.var.degree * (*a)->data.var.priority) - ((*b)->data.var.degree * (*b)->data.var.priority); } -int cg_go(AST *a) { - assert(a->nodeKind == AST_CHUNK); - - for(size_t e = 0; e < a->chunk.externCount; e++) { - assert(a->chunk.externs[e]->kind == SCOPEITEM_SYMBOL); - assert(a->chunk.externs[e]->data.symbol.isExternal); - - printf("extern %s\n", a->chunk.externs[e]->data.symbol.name); - } - - ast_usedef_reset(a); - - size_t adjCount = 0; - Adjacency *adjs = calloc(adjCount, sizeof(*adjs)); - - ScopeItem **vars = a->chunk.vars; - - for(size_t vi = 0; vi < a->chunk.varCount; vi++) { - vars[vi]->data.var.priority = 1; - vars[vi]->data.var.degree = 0; - vars[vi]->data.var.registerClass = -1; - - if(!vars[vi]->data.var.precolored) { - vars[vi]->data.var.color = -1; - } - } - - determine_register_classes(a); - - for(size_t v1i = 0; v1i < a->chunk.varCount; v1i++) { - for(size_t v2i = 0; v2i < a->chunk.varCount; v2i++) { - if(v1i == v2i) continue; - - ScopeItem *v1 = vars[v1i]; - ScopeItem *v2 = vars[v2i]; - - if(var_collision(a, v1, v2)) { - ScopeItem *min = v1 < v2 ? v1 : v2; - ScopeItem *max = v1 < v2 ? v2 : v1; - - for(size_t a = 0; a < adjCount; a++) { - if(adjs[a][0] == min && adjs[a][1] == max) { - goto cont; - } - } - - adjs = realloc(adjs, sizeof(*adjs) * ++adjCount); - adjs[adjCount - 1][0] = min; - adjs[adjCount - 1][1] = max; - -cont:; - } - } - } - - for(size_t a = 0; a < adjCount; a++) { - adjs[a][0]->data.var.degree++; - adjs[a][1]->data.var.degree++; - } - - qsort(vars, a->chunk.varCount, sizeof(*vars), comparator); - + +static int assign_coloring(AST *a, ScopeItem **vars, size_t adjCount, Adjacency *adjs, bool preclassed) { int mustSpillRegisterClass = -1; /* Welsh plow my ass */ for(int v = 0; v < a->chunk.varCount; v++) { + if(vars[v]->data.var.preclassed != preclassed) { + continue; + } + if(vars[v]->data.var.color != -1) { // Already assigned. continue; @@ -1047,6 +757,82 @@ nextColor:; } } + return mustSpillRegisterClass; +} + +int cg_go(AST *a) { + assert(a->nodeKind == AST_CHUNK); + + for(size_t e = 0; e < a->chunk.externCount; e++) { + assert(a->chunk.externs[e]->kind == SCOPEITEM_SYMBOL); + assert(a->chunk.externs[e]->data.symbol.isExternal); + + printf("extern %s\n", a->chunk.externs[e]->data.symbol.name); + } + + ast_usedef_reset(a); + + size_t adjCount = 0; + Adjacency *adjs = calloc(adjCount, sizeof(*adjs)); + + ScopeItem **vars = a->chunk.vars; + + for(size_t vi = 0; vi < a->chunk.varCount; vi++) { + vars[vi]->data.var.priority = 1; + vars[vi]->data.var.degree = 0; + + if(!vars[vi]->data.var.preclassed) { + vars[vi]->data.var.registerClass = -1; + } + + if(!vars[vi]->data.var.precolored) { + vars[vi]->data.var.color = -1; + } + } + + determine_register_classes(a); + + for(size_t v1i = 0; v1i < a->chunk.varCount; v1i++) { + for(size_t v2i = 0; v2i < a->chunk.varCount; v2i++) { + if(v1i == v2i) continue; + + ScopeItem *v1 = vars[v1i]; + ScopeItem *v2 = vars[v2i]; + + if(var_collision(a, v1, v2)) { + ScopeItem *min = v1 < v2 ? v1 : v2; + ScopeItem *max = v1 < v2 ? v2 : v1; + + for(size_t a = 0; a < adjCount; a++) { + if(adjs[a][0] == min && adjs[a][1] == max) { + goto cont; + } + } + + adjs = realloc(adjs, sizeof(*adjs) * ++adjCount); + adjs[adjCount - 1][0] = min; + adjs[adjCount - 1][1] = max; + +cont:; + } + } + } + + for(size_t a = 0; a < adjCount; a++) { + adjs[a][0]->data.var.degree++; + adjs[a][1]->data.var.degree++; + } + + qsort(vars, a->chunk.varCount, sizeof(*vars), comparator); + + int mustSpillRegisterClass; + + // Important to prioritize preclassed variables + mustSpillRegisterClass = assign_coloring(a, vars, adjCount, adjs, true); + if(mustSpillRegisterClass == -1) { + mustSpillRegisterClass = assign_coloring(a, vars, adjCount, adjs, false); + } + free(adjs); if(mustSpillRegisterClass != -1) { @@ -1062,6 +848,12 @@ nextColor:; assert(chosen != NULL); + if(ntc_get_int("pdbg")) { + char *astdump = ast_dump(a); + fprintf(stderr, "### CG FAILURE ###\n%s\n", astdump); + free(astdump); + } + ast_spill_to_stack(a, chosen); return 0; diff --git a/src/dumberdowner.c b/src/x86/dumberdowner.c similarity index 95% rename from src/dumberdowner.c rename to src/x86/dumberdowner.c index 80de349..6fdb184 100644 --- a/src/dumberdowner.c +++ b/src/x86/dumberdowner.c @@ -1,11 +1,10 @@ -#include"dumberdowner.h" - #include #include #include -#include"x86.h" +#include"arch.h" #include"reporting.h" +#include"utils.h" // This is the dumbing down pass. // @@ -73,10 +72,21 @@ static AST *xopify(AST *tlc, AST *chunk, AST *stmtPrev, AST *stmt, AST *e) { return varify(tlc, chunk, stmtPrev, stmt, e); } +static void mark_ptr(AST *a) { + assert(a->nodeKind == AST_EXPR_VAR); + assert(a->exprVar.thing->kind == SCOPEITEM_VAR); + + if(x86_ia16()) { + assert(!a->exprVar.thing->data.var.preclassed || a->exprVar.thing->data.var.registerClass == REG_CLASS_IA16_PTRS); + + a->exprVar.thing->data.var.preclassed = true; + a->exprVar.thing->data.var.registerClass = REG_CLASS_IA16_PTRS; + } +} + struct DumbenState { int effective; }; - static void dumben_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chu, AST *tlc, void *ud) { struct DumbenState *this = ud; @@ -188,11 +198,15 @@ static void dumben_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chu, AST * && s->stmtAssign.to->nodeKind == AST_EXPR_UNARY_OP && s->stmtAssign.to->exprUnOp.operator == UNOP_DEREF) { s->stmtAssign.to = varify(tlc, chu, stmtPrev, s, s->stmtAssign.to); + this->effective = 1; } else if(s->stmtAssign.what->nodeKind == AST_EXPR_UNARY_OP && s->stmtAssign.what->exprUnOp.operator == UNOP_DEREF && !is_xop(s->stmtAssign.what)) { s->stmtAssign.what->exprUnOp.operand = varify(tlc, chu, stmtPrev, s, s->stmtAssign.what->exprUnOp.operand); + + mark_ptr(s->stmtAssign.what->exprUnOp.operand); + this->effective = 1; } else if(s->stmtAssign.what && s->stmtAssign.what->nodeKind == AST_EXPR_VAR && s->stmtAssign.what->exprVar.thing->kind == SCOPEITEM_VAR && s->stmtAssign.to->nodeKind == AST_EXPR_CALL) { @@ -236,6 +250,8 @@ static void dumben_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chu, AST * if(s->stmtAssign.to->nodeKind == AST_EXPR_UNARY_OP && s->stmtAssign.to->exprUnOp.operator == UNOP_DEREF) { s->stmtAssign.to->exprUnOp.operand = varify(tlc, chu, stmtPrev, s, s->stmtAssign.to->exprUnOp.operand); + mark_ptr(s->stmtAssign.to->exprUnOp.operand); + this->effective = 1; } else if(s->stmtAssign.to->nodeKind == AST_EXPR_BINARY_OP && s->stmtAssign.to->exprBinOp.operator == BINOP_MUL) { @@ -330,6 +346,11 @@ static void dumben_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chu, AST * } } +struct DenoopState { + AST *targetTLC; + bool success; +}; + static void pre_dumb_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *tlc, void *ud) { AST *n = *nptr; @@ -387,6 +408,8 @@ static void pre_dumb_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chunk, A } static void decompose_symbol_record_field_access(AST **nptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *tlc, void *ud) { + if(tlc != (AST*) ud) return; + AST *n = *nptr; if(n->nodeKind == AST_EXPR_DOT) { @@ -438,9 +461,13 @@ static bool is_double_field_access(AST *e) { } static void denoop_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *tlc, void *ud) { + struct DenoopState *state = ud; + + if(state->targetTLC != tlc) return; + AST *n = *nptr; - bool *success = ud; + bool *success = &state->success; if(n->nodeKind == AST_EXPR_UNARY_OP && n->exprUnOp.operator == UNOP_REF && n->exprUnOp.operand->nodeKind == AST_EXPR_UNARY_OP && n->exprUnOp.operand->exprUnOp.operator == UNOP_DEREF) { // Turn `&*a` into `a` @@ -497,11 +524,13 @@ static void denoop_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chunk, AST void dumben_pre(AST *tlc) { generic_visitor(&tlc, NULL, NULL, tlc, tlc, tlc, pre_dumb_visitor, NULL); - generic_visitor(&tlc, NULL, NULL, tlc, tlc, NULL, decompose_symbol_record_field_access, NULL); + generic_visitor(&tlc, NULL, NULL, tlc, tlc, tlc, decompose_symbol_record_field_access, NULL); - for(size_t t = 0; t < tlc->chunk.varCount; t++) { + for(size_t t = 0; t < tlc->chunk.varCount;) { if(tlc->chunk.vars[t]->type->type == TYPE_TYPE_RECORD) { ast_spill_to_stack(tlc, tlc->chunk.vars[t]); + } else { + t++; } }