Restructure source tree, SRoA and variable pointer size
This commit is contained in:
parent
438c3b3467
commit
923ec25d79
155
src/ast.c
155
src/ast.c
@ -7,10 +7,9 @@
|
|||||||
#include<stdarg.h>
|
#include<stdarg.h>
|
||||||
#include"ntc.h"
|
#include"ntc.h"
|
||||||
#include"reporting.h"
|
#include"reporting.h"
|
||||||
|
#include"utils.h"
|
||||||
|
|
||||||
const char *AST_KIND_STR[] = {
|
const char *AST_KIND_STR[] = { AST_KINDS(GEN_STRI) };
|
||||||
AST_KINDS(GEN_STRI)
|
|
||||||
};
|
|
||||||
|
|
||||||
void generic_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chu, AST *tlc, void *ud, GenericVisitorHandler preHandler, GenericVisitorHandler postHandler) {
|
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);
|
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);
|
generic_visitor(&n->exprExtSizeOf.ofExpr, stmt, stmtPrev, chu, tlc, ud, preHandler, postHandler);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
abort();
|
stahp_node(n, "generic_visitor: unhandled %s", AST_KIND_STR[n->nodeKind]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(postHandler) postHandler(nptr, stmt, stmtPrev, chu, tlc, ud);
|
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);
|
ast_usedef_pass(tlc, a->stmtReturn.val, wholestmt);
|
||||||
}
|
}
|
||||||
} else {
|
} 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);
|
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) {
|
char *type_to_string(Type *t) {
|
||||||
if(t->type == TYPE_TYPE_PRIMITIVE) {
|
if(t->type == TYPE_TYPE_PRIMITIVE) {
|
||||||
char ret[16] = {};
|
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);
|
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) {
|
// This pass makes sure that integer literals are always operand 1 in a binary operation,
|
||||||
AST *a = *aptr;
|
// simplifying passes further down
|
||||||
|
|
||||||
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
|
|
||||||
static void commutativity_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *tlc, void *ud) {
|
static void commutativity_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *tlc, void *ud) {
|
||||||
AST *n = *nptr;
|
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) {
|
void ast_commutativity_pass(AST *tlc) {
|
||||||
generic_visitor(&tlc, NULL, NULL, tlc, tlc, NULL, NULL, commutativity_visitor);
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
27
src/ast.h
27
src/ast.h
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
#include"types.h"
|
#include"types.h"
|
||||||
#include"lexer.h"
|
#include"lexer.h"
|
||||||
#include"vartable.h"
|
#include"scope.h"
|
||||||
|
|
||||||
#pragma pack(push, 1)
|
#pragma pack(push, 1)
|
||||||
|
|
||||||
@ -19,13 +19,11 @@
|
|||||||
#define AST_KINDS(K) \
|
#define AST_KINDS(K) \
|
||||||
K(AST_CHUNK) \
|
K(AST_CHUNK) \
|
||||||
K(AST_STMT_DECL) \
|
K(AST_STMT_DECL) \
|
||||||
K(AST_TYPE_IDENTIFIER) \
|
|
||||||
K(AST_EXPR_PRIMITIVE) \
|
K(AST_EXPR_PRIMITIVE) \
|
||||||
K(AST_STMT_IF) \
|
K(AST_STMT_IF) \
|
||||||
K(AST_EXPR_BINARY_OP) \
|
K(AST_EXPR_BINARY_OP) \
|
||||||
K(AST_EXPR_VAR) \
|
K(AST_EXPR_VAR) \
|
||||||
K(AST_EXPR_STACK_POINTER) \
|
K(AST_EXPR_STACK_POINTER) \
|
||||||
K(AST_TYPE_POINTER) \
|
|
||||||
K(AST_EXPR_UNARY_OP) \
|
K(AST_EXPR_UNARY_OP) \
|
||||||
K(AST_STMT_LOOP) \
|
K(AST_STMT_LOOP) \
|
||||||
K(AST_STMT_BREAK) \
|
K(AST_STMT_BREAK) \
|
||||||
@ -177,25 +175,6 @@ typedef struct {
|
|||||||
size_t endTokI;
|
size_t endTokI;
|
||||||
} ASTExprFunc;
|
} 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 {
|
typedef struct {
|
||||||
ASTBase;
|
ASTBase;
|
||||||
union AST *next;
|
union AST *next;
|
||||||
@ -378,6 +357,8 @@ void ast_typecheck(AST *tlc);
|
|||||||
|
|
||||||
void ast_grow_stack_frame(AST *tlc, size_t bytes);
|
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
|
#endif
|
||||||
|
8
src/cg.h
8
src/cg.h
@ -1,8 +0,0 @@
|
|||||||
#ifndef H_CG
|
|
||||||
#define H_CG
|
|
||||||
|
|
||||||
#include"ast.h"
|
|
||||||
|
|
||||||
int cg_go(union AST*);
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,6 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include"ast.h"
|
|
||||||
|
|
||||||
void dumben_pre(AST *tlc);
|
|
||||||
void dumben_go(AST* tlc);
|
|
24
src/ntc.c
24
src/ntc.c
@ -7,15 +7,12 @@
|
|||||||
#include"parse.h"
|
#include"parse.h"
|
||||||
#include"ntc.h"
|
#include"ntc.h"
|
||||||
#include"reporting.h"
|
#include"reporting.h"
|
||||||
#include"cg.h"
|
|
||||||
#include"dumberdowner.h"
|
|
||||||
#include"x86.h"
|
|
||||||
#include"utils.h"
|
#include"utils.h"
|
||||||
|
|
||||||
static int argc;
|
static int argc;
|
||||||
static char **argv;
|
static char **argv;
|
||||||
|
|
||||||
static char **includePaths;
|
static const char **includePaths;
|
||||||
const char **ntc_get_import_paths() {
|
const char **ntc_get_import_paths() {
|
||||||
return (const char**) includePaths;
|
return (const char**) includePaths;
|
||||||
}
|
}
|
||||||
@ -35,15 +32,19 @@ const char* ntc_get_arg(const char *name) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
intmax_t ntc_get_int(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);
|
const char *val = ntc_get_arg(name);
|
||||||
|
|
||||||
if(!val) {
|
if(!val) {
|
||||||
return 0;
|
return def;
|
||||||
}
|
}
|
||||||
|
|
||||||
long result = 0;
|
long result = 0;
|
||||||
if(!unstupid_strtol(val, (const char**) &val, 0, &result)) {
|
if(!unstupid_strtol(val, (char**) &val, 0, &result)) {
|
||||||
return 0;
|
return def;
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@ -53,7 +54,7 @@ int main(int argc_, char **argv_) {
|
|||||||
argc = argc_;
|
argc = argc_;
|
||||||
argv = argv_;
|
argv = argv_;
|
||||||
|
|
||||||
if(x86_target() == IUNKNOWN86) {
|
if(!arch_verify_target()) {
|
||||||
stahp(0, 0, "Unknown architecture %s", ntc_get_arg("target"));
|
stahp(0, 0, "Unknown architecture %s", ntc_get_arg("target"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,17 +94,12 @@ int main(int argc_, char **argv_) {
|
|||||||
free(astdump);
|
free(astdump);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ast_sroa(chunk);
|
||||||
dumben_pre(chunk);
|
dumben_pre(chunk);
|
||||||
dumben_go(chunk);
|
dumben_go(chunk);
|
||||||
|
|
||||||
while(!cg_go(chunk)) {
|
while(!cg_go(chunk)) {
|
||||||
dumben_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;
|
return 0;
|
||||||
|
@ -3,11 +3,20 @@
|
|||||||
|
|
||||||
#include<stddef.h>
|
#include<stddef.h>
|
||||||
#include<stdint.h>
|
#include<stdint.h>
|
||||||
|
#include<stdbool.h>
|
||||||
|
|
||||||
const char **ntc_get_import_paths();
|
const char **ntc_get_import_paths();
|
||||||
|
|
||||||
const char* ntc_get_arg(const char *name);
|
const char* ntc_get_arg(const char *name);
|
||||||
|
|
||||||
intmax_t ntc_get_int(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
|
#endif
|
||||||
|
60
src/parse.c
60
src/parse.c
@ -4,11 +4,11 @@
|
|||||||
#include<stdlib.h>
|
#include<stdlib.h>
|
||||||
#include<string.h>
|
#include<string.h>
|
||||||
#include"utils.h"
|
#include"utils.h"
|
||||||
#include"vartable.h"
|
#include"scope.h"
|
||||||
#include"reporting.h"
|
#include"reporting.h"
|
||||||
#include<stdint.h>
|
#include<stdint.h>
|
||||||
#include<signal.h>
|
#include<signal.h>
|
||||||
#include"x86.h"
|
#include"ntc.h"
|
||||||
|
|
||||||
#ifndef __GNUC__
|
#ifndef __GNUC__
|
||||||
static inline int __builtin_clzl(unsigned long x) {
|
static inline int __builtin_clzl(unsigned long x) {
|
||||||
@ -177,9 +177,10 @@ static AST *exprvar(Parser *P, ScopeItem *v) {
|
|||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
ASTChunk *nct_parse_chunk(Parser*, int, int, Scope*, Type *ft);
|
static ASTChunk *nct_parse_chunk(Parser*, int, int, Scope*, Type *ft);
|
||||||
Type *nct_parse_typename(Parser *P);
|
static Type *nct_parse_typename(Parser *P);
|
||||||
static bool parse_parametrization(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 char *parametrize_function_name(Type *t, const char *original, Scope *scope);
|
||||||
|
|
||||||
static void binop_implicit_cast(/*Parser *P, */ASTExprBinaryOp *binop) {
|
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->type = NULL;
|
||||||
astop->operator = op;
|
astop->operator = op;
|
||||||
astop->operands[0] = ret;
|
astop->operands[0] = ret;
|
||||||
|
astop->operands[1] = nct_parse_expression(P, lOP + 1);
|
||||||
ASTExpr *operand = &(astop->operands[1] = nct_parse_expression(P, lOP + 1))->expression;
|
|
||||||
|
|
||||||
if(!type_is_number(astop->operands[0]->expression.type)
|
if(!type_is_number(astop->operands[0]->expression.type)
|
||||||
|| !type_is_number(astop->operands[1]->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. */
|
/* 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;
|
int oldIdx = P->i;
|
||||||
|
|
||||||
bool generics = peek(P, 0).type == TOKEN_SQUAREN_L;
|
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;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*static void add_parametrizations_to_scope(Parser *P, Parametrizations *parametrizations, Parametrizations *renames) {
|
static void nct_parse_statement(Parser *P) {
|
||||||
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) {
|
|
||||||
if(maybe(P, TOKEN_IF)) {
|
if(maybe(P, TOKEN_IF)) {
|
||||||
expect(P, TOKEN_PAREN_L);
|
expect(P, TOKEN_PAREN_L);
|
||||||
AST *e = nct_parse_expression(P, 0);
|
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.
|
* This function inserts VTEs into the *current* scope.
|
||||||
* Make sure to create a child scope before using.
|
* 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);
|
expect(P, TOKEN_SQUAREN_L);
|
||||||
|
|
||||||
bool integerMode = false;
|
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.vars = NULL;
|
||||||
ret->chunk.stackReservation = 0;
|
ret->chunk.stackReservation = 0;
|
||||||
|
|
||||||
AST *oldChunk = (AST*) P->currentChunk;
|
ASTChunk *oldChunk = P->currentChunk;
|
||||||
P->currentChunk = &ret->chunk;
|
P->currentChunk = &ret->chunk;
|
||||||
|
|
||||||
Scope *oldScope = P->scope;
|
Scope *oldScope = P->scope;
|
||||||
|
@ -12,7 +12,6 @@ static void stahp_va(int row, int column, const char *error, va_list l) {
|
|||||||
fputc('\n', stderr);
|
fputc('\n', stderr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Abort immediately on first error (for now) */
|
|
||||||
void stahp(int row, int column, const char *error, ...) {
|
void stahp(int row, int column, const char *error, ...) {
|
||||||
va_list l;
|
va_list l;
|
||||||
va_start(l, error);
|
va_start(l, error);
|
||||||
|
@ -99,7 +99,7 @@ size_t type_size(Type *t) {
|
|||||||
|
|
||||||
return w;
|
return w;
|
||||||
} else if(t->type == TYPE_TYPE_POINTER || t->type == TYPE_TYPE_FUNCTION) {
|
} 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) {
|
} else if(t->type == TYPE_TYPE_ARRAY) {
|
||||||
return type_size(t->array.of) * t->array.length;
|
return type_size(t->array.of) * t->array.length;
|
||||||
} else if(t->type == TYPE_TYPE_RECORD) {
|
} else if(t->type == TYPE_TYPE_RECORD) {
|
||||||
|
16
src/utils.h
16
src/utils.h
@ -5,6 +5,8 @@
|
|||||||
#include<stdbool.h>
|
#include<stdbool.h>
|
||||||
#include<errno.h>
|
#include<errno.h>
|
||||||
#include<stdlib.h>
|
#include<stdlib.h>
|
||||||
|
#include<stdarg.h>
|
||||||
|
#include<stdio.h>
|
||||||
|
|
||||||
inline static size_t djb2(const char *str) {
|
inline static size_t djb2(const char *str) {
|
||||||
size_t hash = 5381;
|
size_t hash = 5381;
|
||||||
@ -38,4 +40,18 @@ inline static bool unstupid_strtol(const char *str, char **endptr, int base, lon
|
|||||||
return true;
|
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
|
#endif
|
||||||
|
112
src/vartable.c
112
src/vartable.c
@ -1,112 +0,0 @@
|
|||||||
#include"vartable.h"
|
|
||||||
|
|
||||||
#include"utils.h"
|
|
||||||
#include<stdlib.h>
|
|
||||||
#include<string.h>
|
|
||||||
#include<assert.h>
|
|
||||||
#include<stdio.h>
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
111
src/vartable.h
111
src/vartable.h
@ -1,111 +0,0 @@
|
|||||||
#ifndef NCTREF_VARTABLE_H
|
|
||||||
#define NCTREF_VARTABLE_H
|
|
||||||
|
|
||||||
#include"types.h"
|
|
||||||
#include<stdbool.h>
|
|
||||||
|
|
||||||
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
|
|
52
src/x86/arch.c
Normal file
52
src/x86/arch.c
Normal file
@ -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;
|
||||||
|
}
|
@ -18,6 +18,11 @@
|
|||||||
#define HWR_DI 256
|
#define HWR_DI 256
|
||||||
#define HWR_SI 512
|
#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_AX (HWR_AL | HWR_AH)
|
||||||
#define HWR_BX (HWR_BL | HWR_BH)
|
#define HWR_BX (HWR_BL | HWR_BH)
|
||||||
#define HWR_CX (HWR_CL | HWR_CH)
|
#define HWR_CX (HWR_CL | HWR_CH)
|
||||||
@ -50,7 +55,9 @@ typedef struct RegisterClass {
|
|||||||
#define REG_CLASS_NOT_8 1
|
#define REG_CLASS_NOT_8 1
|
||||||
#define REG_CLASS_16_32 2
|
#define REG_CLASS_16_32 2
|
||||||
#define REG_CLASS_IND 3
|
#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
|
// lol
|
||||||
static inline bool is_reg_b(int cls, int res) {
|
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?
|
// Can expression be expressed as a single x86 operand?
|
||||||
#define XOP_NOT_XOP 0
|
#define XOP_NOT_XOP 0
|
||||||
#define XOP_NOT_MEM 1
|
#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(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;
|
return XOP_MEM;
|
||||||
} else if(
|
} 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) ||
|
(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,
|
GUCCI,
|
||||||
} WhysItBad_Huh;
|
} 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) {
|
static inline WhysItBad_Huh x86_test_mul_matching_mulhi(AST *mulhi, AST *mul) {
|
||||||
assert(mulhi->statement.next == mul);
|
assert(mulhi->statement.next == mul);
|
||||||
|
|
@ -1,14 +1,12 @@
|
|||||||
#include"cg.h"
|
|
||||||
|
|
||||||
#include<stdlib.h>
|
#include<stdlib.h>
|
||||||
#include<signal.h>
|
#include<signal.h>
|
||||||
#include<string.h>
|
#include<string.h>
|
||||||
#include<assert.h>
|
#include<assert.h>
|
||||||
#include"dumberdowner.h"
|
#include"ntc.h"
|
||||||
#include"reporting.h"
|
#include"reporting.h"
|
||||||
#include"ast.h"
|
#include"ast.h"
|
||||||
|
#include"arch.h"
|
||||||
#include"x86.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"};
|
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) {
|
static const char *xv_sz(ScopeItem *v, int sz) {
|
||||||
assert(v->kind == SCOPEITEM_VAR);
|
assert(v->kind == SCOPEITEM_VAR);
|
||||||
|
|
||||||
|
if(sz == 0) sz = arch_ptr_size();
|
||||||
|
|
||||||
#define XVBUFS 8
|
#define XVBUFS 8
|
||||||
#define XVBUFSZ 16
|
#define XVBUFSZ 16
|
||||||
static char bufs[XVBUFS][XVBUFSZ];
|
static char bufs[XVBUFS][XVBUFSZ];
|
||||||
@ -137,11 +137,6 @@ static const char *xop_sz(AST *tlc, AST *e, int sz) {
|
|||||||
|
|
||||||
char *ret = bufs[bufidx];
|
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) {
|
if(e->nodeKind == AST_EXPR_UNARY_OP && e->exprUnOp.operator == UNOP_DEREF) {
|
||||||
AST *p = e->exprUnOp.operand;
|
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) {
|
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]",
|
snprintf(ret, XOPBUFSZ, "%s [%s + %s]",
|
||||||
spec(sz),
|
spec(sz),
|
||||||
xv_sz(p->exprBinOp.operands[0]->exprVar.thing, 4),
|
xv_sz(p->exprBinOp.operands[0]->exprVar.thing, 0),
|
||||||
xv_sz(p->exprBinOp.operands[1]->exprVar.thing, 4));
|
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) {
|
} 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]",
|
snprintf(ret, XOPBUFSZ, "%s [%s + %s]",
|
||||||
spec(sz),
|
spec(sz),
|
||||||
p->exprBinOp.operands[0]->exprUnOp.operand->exprVar.thing->data.symbol.name,
|
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)) {
|
} else if(is_field_access(e)) {
|
||||||
e = 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),
|
spec(sz),
|
||||||
p->exprBinOp.operands[0]->exprUnOp.operand->exprVar.thing->data.symbol.name,
|
p->exprBinOp.operands[0]->exprUnOp.operand->exprVar.thing->data.symbol.name,
|
||||||
p->exprBinOp.operands[1]->exprBinOp.operands[0]->exprPrim.val,
|
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) {
|
} 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) {
|
} 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);
|
snprintf(ret, XOPBUFSZ, "[esp + %i]", p->exprBinOp.operands[1]->exprPrim.val);
|
||||||
} else {
|
} else {
|
||||||
@ -291,6 +286,8 @@ void cg_chunk(CGState *cg, AST *a) {
|
|||||||
// Generic functions have non-NULL code blocks
|
// Generic functions have non-NULL code blocks
|
||||||
if(!type_is_generic(s->stmtDecl.expression->expression.type)) {
|
if(!type_is_generic(s->stmtDecl.expression->expression.type)) {
|
||||||
|
|
||||||
|
ast_sroa(s->stmtDecl.expression->exprFunc.chunk);
|
||||||
|
|
||||||
dumben_pre(s->stmtDecl.expression->exprFunc.chunk);
|
dumben_pre(s->stmtDecl.expression->exprFunc.chunk);
|
||||||
|
|
||||||
dumben_go(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) {
|
} 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",
|
printf("lea %s, [%s + %i]\n",
|
||||||
xv_sz(s->stmtAssign.what->exprVar.thing, 4),
|
xv_sz(s->stmtAssign.what->exprVar.thing, 0),
|
||||||
xv_sz(s->stmtAssign.to->exprBinOp.operands[0]->exprVar.thing, 4),
|
xv_sz(s->stmtAssign.to->exprBinOp.operands[0]->exprVar.thing, 0),
|
||||||
s->stmtAssign.to->exprBinOp.operands[1]->exprPrim.val);
|
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)) {
|
} 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];
|
typedef ScopeItem *Adjacency[2];
|
||||||
|
|
||||||
static bool var_collision(AST *tlc, ScopeItem *v1, ScopeItem *v2) {
|
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;
|
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 {
|
struct CalleeSavedState {
|
||||||
AST *targetTLC;
|
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) {
|
static void determine_register_classes(AST *tlc) {
|
||||||
for(size_t v = 0; v < tlc->chunk.varCount; v++) {
|
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) {
|
if(type_size(tlc->chunk.vars[v]->type) == 1) {
|
||||||
tlc->chunk.vars[v]->data.var.registerClass = REG_CLASS_8;
|
tlc->chunk.vars[v]->data.var.registerClass = REG_CLASS_8;
|
||||||
} else {
|
} else {
|
||||||
tlc->chunk.vars[v]->data.var.registerClass = REG_CLASS_NOT_8;
|
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 */
|
/* Welsh-Powell graph coloring */
|
||||||
@ -933,72 +699,16 @@ static int comparator(const void *A, const void *B) {
|
|||||||
ScopeItem *const *b = B;
|
ScopeItem *const *b = B;
|
||||||
return ((*a)->data.var.degree * (*a)->data.var.priority) - ((*b)->data.var.degree * (*b)->data.var.priority);
|
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;
|
int mustSpillRegisterClass = -1;
|
||||||
|
|
||||||
/* Welsh plow my ass */
|
/* Welsh plow my ass */
|
||||||
for(int v = 0; v < a->chunk.varCount; v++) {
|
for(int v = 0; v < a->chunk.varCount; v++) {
|
||||||
|
if(vars[v]->data.var.preclassed != preclassed) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if(vars[v]->data.var.color != -1) {
|
if(vars[v]->data.var.color != -1) {
|
||||||
// Already assigned.
|
// Already assigned.
|
||||||
continue;
|
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);
|
free(adjs);
|
||||||
|
|
||||||
if(mustSpillRegisterClass != -1) {
|
if(mustSpillRegisterClass != -1) {
|
||||||
@ -1062,6 +848,12 @@ nextColor:;
|
|||||||
|
|
||||||
assert(chosen != NULL);
|
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);
|
ast_spill_to_stack(a, chosen);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
@ -1,11 +1,10 @@
|
|||||||
#include"dumberdowner.h"
|
|
||||||
|
|
||||||
#include<stdlib.h>
|
#include<stdlib.h>
|
||||||
#include<assert.h>
|
#include<assert.h>
|
||||||
#include<string.h>
|
#include<string.h>
|
||||||
|
|
||||||
#include"x86.h"
|
#include"arch.h"
|
||||||
#include"reporting.h"
|
#include"reporting.h"
|
||||||
|
#include"utils.h"
|
||||||
|
|
||||||
// This is the dumbing down pass.
|
// 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);
|
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 {
|
struct DumbenState {
|
||||||
int effective;
|
int effective;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void dumben_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chu, AST *tlc, void *ud) {
|
static void dumben_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chu, AST *tlc, void *ud) {
|
||||||
struct DumbenState *this = 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->nodeKind == AST_EXPR_UNARY_OP && s->stmtAssign.to->exprUnOp.operator == UNOP_DEREF) {
|
||||||
|
|
||||||
s->stmtAssign.to = varify(tlc, chu, stmtPrev, s, s->stmtAssign.to);
|
s->stmtAssign.to = varify(tlc, chu, stmtPrev, s, s->stmtAssign.to);
|
||||||
|
|
||||||
this->effective = 1;
|
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)) {
|
} 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);
|
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;
|
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) {
|
} 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) {
|
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);
|
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;
|
this->effective = 1;
|
||||||
} else if(s->stmtAssign.to->nodeKind == AST_EXPR_BINARY_OP && s->stmtAssign.to->exprBinOp.operator == BINOP_MUL) {
|
} 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) {
|
static void pre_dumb_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *tlc, void *ud) {
|
||||||
AST *n = *nptr;
|
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) {
|
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;
|
AST *n = *nptr;
|
||||||
|
|
||||||
if(n->nodeKind == AST_EXPR_DOT) {
|
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) {
|
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;
|
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) {
|
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`
|
// 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) {
|
void dumben_pre(AST *tlc) {
|
||||||
generic_visitor(&tlc, NULL, NULL, tlc, tlc, tlc, pre_dumb_visitor, NULL);
|
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) {
|
if(tlc->chunk.vars[t]->type->type == TYPE_TYPE_RECORD) {
|
||||||
ast_spill_to_stack(tlc, tlc->chunk.vars[t]);
|
ast_spill_to_stack(tlc, tlc->chunk.vars[t]);
|
||||||
|
} else {
|
||||||
|
t++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user