Oh who gives a fuck?

This commit is contained in:
Mid 2024-02-13 21:33:49 +02:00
parent 83e0771f2c
commit a1077f7c03
12 changed files with 447 additions and 32 deletions

View File

@ -4,14 +4,6 @@
#include<string.h> #include<string.h>
#include<stdlib.h> #include<stdlib.h>
int BINOP_COMMUTATIVE[] = {
[BINOP_ADD] = 1,
[BINOP_SUB] = 0,
[BINOP_MUL] = 1,
[BINOP_DIV] = 0
};
AST *ast_expression_optimize(AST *ast) { AST *ast_expression_optimize(AST *ast) {
return ast; return ast;
} }

View File

@ -5,7 +5,20 @@
#include"lexer.h" #include"lexer.h"
#include"vartable.h" #include"vartable.h"
typedef enum { // VISITORS APPEAR IN varify_change_usedefs,ast_expr_is_equal,ast_stmt_is_after,
// dumben_chunk, cg_go, loop_second_pass AND OTHERS
//
// THEY ***MUST*** BE CHANGED ACCORDINGLY IF AST IS ALTERED
#pragma pack(push, 1)
#ifdef __GNUC__
#define ENUMPAK __attribute__((packed))
#else
#define ENUMPAK
#endif
typedef enum ENUMPAK {
AST_CHUNK, AST_CHUNK,
AST_STMT_DECL, AST_STMT_DECL,
AST_TYPE_IDENTIFIER, AST_TYPE_IDENTIFIER,
@ -29,7 +42,7 @@ typedef enum {
AST_STMT_EXT_SECTION, AST_STMT_EXT_SECTION,
} ASTKind; } ASTKind;
typedef enum { typedef enum ENUMPAK {
BINOP_ADD = 0, BINOP_ADD = 0,
BINOP_SUB = 1, BINOP_SUB = 1,
BINOP_BITWISE_AND = 2, BINOP_BITWISE_AND = 2,
@ -44,7 +57,6 @@ typedef enum {
BINOP_WTF = 999, BINOP_WTF = 999,
} BinaryOp; } BinaryOp;
extern int BINOP_COMMUTATIVE[];
static inline int binop_is_comparison(BinaryOp op) { static inline int binop_is_comparison(BinaryOp op) {
return op == BINOP_EQUAL || op == BINOP_NEQUAL; return op == BINOP_EQUAL || op == BINOP_NEQUAL;
@ -59,7 +71,7 @@ static inline BinaryOp binop_comp_opposite(BinaryOp op) {
return BINOP_WTF; return BINOP_WTF;
} }
typedef enum { typedef enum ENUMPAK {
UNOP_DEREF = 0, UNOP_DEREF = 0,
UNOP_NEGATE = 1, UNOP_NEGATE = 1,
UNOP_BITWISE_NOT = 2, UNOP_BITWISE_NOT = 2,
@ -251,6 +263,8 @@ typedef union AST {
ASTStmtExtSection stmtExtSection; ASTStmtExtSection stmtExtSection;
} AST; } AST;
#pragma pack(pop)
AST *ast_expression_optimize(AST*); AST *ast_expression_optimize(AST*);
int ast_expression_equal(AST*, AST*); int ast_expression_equal(AST*, AST*);

View File

@ -12,7 +12,7 @@ static const char *BINOP_SIMPLE_INSTRS[] = {[BINOP_ADD] = "add", [BINOP_SUB] = "
static size_t nextLocalLabel = 0; static size_t nextLocalLabel = 0;
#define LOOPSTACKSIZE 64 #define LOOPSTACKSIZE 96
static size_t loopStackStart[LOOPSTACKSIZE]; static size_t loopStackStart[LOOPSTACKSIZE];
static size_t loopStackEnd[LOOPSTACKSIZE]; static size_t loopStackEnd[LOOPSTACKSIZE];
static size_t loopStackIdx; static size_t loopStackIdx;
@ -37,6 +37,16 @@ static const char *spec(int size) {
abort(); abort();
} }
static int log_size(int size) {
switch(size) {
case 1: return 0;
case 2: return 1;
case 4: return 2;
case 8: return 3;
}
abort();
}
static const char *specexpr(AST *e) { static const char *specexpr(AST *e) {
return spec(type_size(e->expression.type)); return spec(type_size(e->expression.type));
} }
@ -54,7 +64,7 @@ static const char *xv(VarTableEntry *v) {
#ifdef DEBUG #ifdef DEBUG
snprintf(ret, XVBUFSZ, "@%i", v->data.var.color); snprintf(ret, XVBUFSZ, "@%i", v->data.var.color);
#else #else
snprintf(ret, XVBUFSZ, "%s", regs[v->data.var.color][2]); snprintf(ret, XVBUFSZ, "%s", regs[v->data.var.color][log_size(type_size(v->type))]);
#endif #endif
bufidx = (bufidx + 1) % XVBUFS; bufidx = (bufidx + 1) % XVBUFS;
@ -87,7 +97,7 @@ static const char *xop(AST *e) {
snprintf(ret, XOPBUFSZ, "[%s]", v->data.symbol.name); snprintf(ret, XOPBUFSZ, "[%s]", v->data.symbol.name);
} else abort(); } else abort();
} else if(e->nodeKind == AST_EXPR_PRIMITIVE) { } else if(e->nodeKind == AST_EXPR_PRIMITIVE) {
snprintf(ret, XOPBUFSZ, "%i", e->exprPrim.val); snprintf(ret, XOPBUFSZ, "%s %i", specexpr(e), e->exprPrim.val);
} else if(e->nodeKind == AST_EXPR_UNARY_OP && e->exprUnOp.operator == UNOP_DEREF && e->exprUnOp.operand->nodeKind == AST_EXPR_BINARY_OP && e->exprUnOp.operand->exprBinOp.operator == BINOP_ADD && e->exprUnOp.operand->exprBinOp.operands[0]->nodeKind == AST_EXPR_UNARY_OP && e->exprUnOp.operand->exprBinOp.operands[1]->nodeKind == AST_EXPR_VAR && e->exprUnOp.operand->exprBinOp.operands[0]->exprUnOp.operator == UNOP_REF && e->exprUnOp.operand->exprBinOp.operands[0]->exprUnOp.operand->nodeKind == AST_EXPR_VAR && e->exprUnOp.operand->exprBinOp.operands[0]->exprUnOp.operand->exprVar.thing->kind == VARTABLEENTRY_SYMBOL && e->exprUnOp.operand->exprBinOp.operands[1]->exprVar.thing->kind == VARTABLEENTRY_VAR) { } else if(e->nodeKind == AST_EXPR_UNARY_OP && e->exprUnOp.operator == UNOP_DEREF && e->exprUnOp.operand->nodeKind == AST_EXPR_BINARY_OP && e->exprUnOp.operand->exprBinOp.operator == BINOP_ADD && e->exprUnOp.operand->exprBinOp.operands[0]->nodeKind == AST_EXPR_UNARY_OP && e->exprUnOp.operand->exprBinOp.operands[1]->nodeKind == AST_EXPR_VAR && e->exprUnOp.operand->exprBinOp.operands[0]->exprUnOp.operator == UNOP_REF && e->exprUnOp.operand->exprBinOp.operands[0]->exprUnOp.operand->nodeKind == AST_EXPR_VAR && e->exprUnOp.operand->exprBinOp.operands[0]->exprUnOp.operand->exprVar.thing->kind == VARTABLEENTRY_SYMBOL && e->exprUnOp.operand->exprBinOp.operands[1]->exprVar.thing->kind == VARTABLEENTRY_VAR) {
snprintf(ret, XOPBUFSZ, "[%s + %s]", snprintf(ret, XOPBUFSZ, "[%s + %s]",
e->exprUnOp.operand->exprBinOp.operands[0]->exprUnOp.operand->exprVar.thing->data.symbol.name, e->exprUnOp.operand->exprBinOp.operands[0]->exprUnOp.operand->exprVar.thing->data.symbol.name,
@ -124,6 +134,16 @@ void cg_chunk(AST *a) {
printf("org %lu\n", s->stmtExtOrg.val); printf("org %lu\n", s->stmtExtOrg.val);
} else if(s->nodeKind == AST_STMT_EXT_ALIGN) {
uint32_t val = s->stmtExtAlign.val;
if((val & (val - 1))) {
// nasm does not support non-PoT alignments, so pad manually
printf("times ($ - $$ + %u) / %u * %u - ($ - $$) db 0\n", val - 1, val, val);
} else {
printf("align %u\n", val);
}
} else if(s->nodeKind == AST_STMT_DECL && s->stmtDecl.thing->kind == VARTABLEENTRY_SYMBOL) { } else if(s->nodeKind == AST_STMT_DECL && s->stmtDecl.thing->kind == VARTABLEENTRY_SYMBOL) {
VarTableEntry *v = s->stmtDecl.thing; VarTableEntry *v = s->stmtDecl.thing;
@ -135,9 +155,26 @@ void cg_chunk(AST *a) {
} }
if(s->stmtDecl.expression) { if(s->stmtDecl.expression) {
puts("A"); printf("%s:", v->data.symbol.name);
if(v->type->type == TYPE_TYPE_PRIMITIVE) {
assert(s->stmtDecl.expression->nodeKind == AST_EXPR_PRIMITIVE);
printf("%s %i", direct(type_size(v->type)), s->stmtDecl.expression->exprPrim.val);
} else if(v->type->type == TYPE_TYPE_ARRAY && v->type->array.of->type == TYPE_TYPE_PRIMITIVE) {
printf("%s ", direct(type_size(v->type->array.of)));
for(size_t i = 0; i < v->type->array.length; i++) {
printf("%i,", s->stmtDecl.expression->exprArray.items[i]->exprPrim.val);
}
} else printf("A");
putchar('\n');
} else { } else {
printf("%s resb %lu\n", v->data.symbol.name, type_size(s->stmtDecl.thing->type)); printf("%s resb %lu\n", v->data.symbol.name, type_size(s->stmtDecl.thing->type));
} }
} }
} else if(s->nodeKind == AST_STMT_ASSIGN) { } else if(s->nodeKind == AST_STMT_ASSIGN) {

249
src/dumberdowner.c Normal file
View File

@ -0,0 +1,249 @@
#include"dumberdowner.h"
#include<stdlib.h>
#include<assert.h>
// This is the dumbing down pass.
//
// Complex expressions are to be "broken down" into simpler ones until the AST
// can be trivially translated to the target architecture.
//
// This pass, along with CG is strictly dependent on x86 and will fail for
// any other architecture.
// Can expression be expressed as a single x86 operand?
#define XOP_NOT_XOP 0
#define XOP_NOT_MEM 1
#define XOP_MEM 2
static int is_xop(AST *e) {
if(e->nodeKind == AST_EXPR_PRIMITIVE) {
return XOP_NOT_MEM;
} else if(e->nodeKind == AST_EXPR_VAR) {
return e->exprVar.thing->kind == VARTABLEENTRY_VAR ? XOP_NOT_MEM : XOP_MEM;
} else if(e->nodeKind == AST_EXPR_UNARY_OP && e->exprUnOp.operator == UNOP_REF && e->exprUnOp.operand->nodeKind == AST_EXPR_VAR && e->exprUnOp.operand->exprVar.thing->kind == VARTABLEENTRY_SYMBOL) {
return XOP_NOT_MEM;
} else if(e->nodeKind == AST_EXPR_UNARY_OP && e->exprUnOp.operator == UNOP_DEREF) {
AST *c = e->exprUnOp.operand;
if(c->nodeKind == AST_EXPR_VAR && c->exprVar.thing->kind == VARTABLEENTRY_VAR) {
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) {
if(c->exprBinOp.operands[1]->nodeKind == AST_EXPR_VAR) {
return XOP_MEM;
} else if(c->exprBinOp.operands[1]->nodeKind == AST_EXPR_BINARY_OP && c->exprBinOp.operands[1]->exprBinOp.operator == BINOP_MUL && c->exprBinOp.operands[1]->exprBinOp.operands[0]->nodeKind == AST_EXPR_PRIMITIVE && c->exprBinOp.operands[1]->exprBinOp.operands[1]->nodeKind == AST_EXPR_VAR) {
int scale = c->exprBinOp.operands[1]->exprBinOp.operands[0]->exprPrim.val;
if(scale == 1 || scale == 2 || scale == 4 || scale == 8) {
return XOP_MEM;
}
}
}
}
return XOP_NOT_XOP;
}
static void varify_change_usedefs(AST *e, AST *oldStmt, AST *newStmt) {
if(e->nodeKind == AST_EXPR_VAR) {
if(e->exprVar.thing->kind != VARTABLEENTRY_VAR) {
return;
}
UseDef *swapWithPrev = NULL;
UseDef *swapWith = NULL;
UseDef *udPrev = NULL;
UseDef *ud = e->exprVar.thing->data.var.usedefFirst;
while(ud && ud->use != e) {
if(ud->stmt == oldStmt && !swapWith) {
swapWithPrev = udPrev;
swapWith = ud;
}
udPrev = ud;
ud = ud->next;
}
if(ud) {
assert(ud->stmt == oldStmt);
ud->stmt = newStmt;
// We must make sure all newStmt usedefs are before the oldStmt ones, so swap
if(swapWith) {
assert(!!swapWithPrev + !!udPrev != 0);
if(swapWithPrev) {
swapWithPrev->next = ud;
} else {
e->exprVar.thing->data.var.usedefFirst = ud;
}
if(udPrev) {
udPrev->next = swapWith;
} else {
e->exprVar.thing->data.var.usedefFirst = swapWith;
}
UseDef *temp = ud->next;
ud->next = swapWith->next;
swapWith->next = temp;
assert(!!ud->next + !!swapWith->next != 0);
if(!swapWith->next) {
e->exprVar.thing->data.var.usedefLast = swapWith;
}
if(!ud->next) {
e->exprVar.thing->data.var.usedefLast = ud;
}
}
}
} else if(e->nodeKind == AST_EXPR_BINARY_OP) {
varify_change_usedefs(e->exprBinOp.operands[0], oldStmt, newStmt);
varify_change_usedefs(e->exprBinOp.operands[1], oldStmt, newStmt);
} else if(e->nodeKind == AST_EXPR_UNARY_OP) {
varify_change_usedefs(e->exprUnOp.operand, oldStmt, newStmt);
} else if(e->nodeKind == AST_EXPR_CALL) {
varify_change_usedefs(e->exprCall.what, oldStmt, newStmt);
int argCount = e->exprCall.what->expression.type->function.argCount;
for(int i = 0; i < argCount; i++) {
varify_change_usedefs(e->exprCall.args[i], oldStmt, newStmt);
}
} else if(e->nodeKind == AST_EXPR_ARRAY) {
int sz = e->exprArray.type->array.length;
for(int i = 0; i < sz; i++) {
varify_change_usedefs(e->exprArray.items[i], oldStmt, newStmt);
}
} else if(e->nodeKind == AST_EXPR_CAST) {
varify_change_usedefs(e->exprCast.what, oldStmt, newStmt);
}
}
/* Split away complex expression into a new local variable */
static AST *varify(AST *tlc, AST *chunk, AST *stmtPrev, AST *stmt, AST *e) {
VarTableEntry *vte = malloc(sizeof(*vte));
vte->kind = VARTABLEENTRY_VAR;
vte->type = e->expression.type;
vte->data.var.color = 0;
vte->data.var.degree = 0;
vte->data.var.priority = 0;
vte->data.var.reachingDefs = NULL;
// Add to var array
tlc->chunk.vars = realloc(tlc->chunk.vars, sizeof(*tlc->chunk.vars) * (++tlc->chunk.varCount));
tlc->chunk.vars[tlc->chunk.varCount - 1] = vte;
// Alter AST
ASTExprVar *ev[2];
for(int i = 0; i < 2; i++) {
ev[i] = malloc(sizeof(ASTExprVar));
ev[i]->nodeKind = AST_EXPR_VAR;
ev[i]->type = e->expression.type;
ev[i]->thing = vte;
}
ASTStmtAssign *assign = malloc(sizeof(*assign));
assign->nodeKind = AST_STMT_ASSIGN;
assign->what = (AST*) ev[0];
assign->to = e;
if(stmtPrev) {
stmtPrev->statement.next = (AST*) assign;
} else {
chunk->chunk.statementFirst = (AST*) assign;
}
assign->next = stmt;
// Assemble ud-chain
UseDef *ud[2];
ud[0] = malloc(sizeof(UseDef));
ud[0]->stmt = (AST*) assign;
ud[0]->use = assign->what;
ud[0]->def = (AST*) assign;
ud[0]->next = ud[1];
ud[1] = malloc(sizeof(UseDef));
ud[1]->stmt = stmt;
ud[1]->use = (AST*) ev[1];
ud[1]->def = (AST*) assign;
ud[1]->next = NULL;
vte->data.var.usedefFirst = ud[0];
vte->data.var.usedefLast = ud[1];
// Correct the ud-chain of variables used in varified expression `e`
varify_change_usedefs(e, stmt, (AST*) assign);
return (AST*) ev[1];
}
static AST *xopify(AST *tlc, AST *chunk, AST *stmtPrev, AST *stmt, AST *e) {
return varify(tlc, chunk, stmtPrev, stmt, e);
}
static void dumben_chunk(AST *tlc, AST *chu) {
AST *sPrev = NULL;
AST *s = chu->chunk.statementFirst;
while(s) {
if(s->nodeKind == AST_STMT_IF) {
AST *e = s->stmtIf.expression;
if(e->nodeKind == AST_EXPR_BINARY_OP && binop_is_comparison(e->exprBinOp.operator)) {
if(is_xop(e->exprBinOp.operands[0]) == XOP_NOT_XOP) {
e->exprBinOp.operands[0] = xopify(tlc, chu, sPrev, s, e->exprBinOp.operands[0]);
}
if(is_xop(e->exprBinOp.operands[1]) == XOP_NOT_XOP) {
e->exprBinOp.operands[1] = xopify(tlc, chu, sPrev, s, e->exprBinOp.operands[1]);
}
if(is_xop(e->exprBinOp.operands[0]) == XOP_MEM && is_xop(e->exprBinOp.operands[1]) == XOP_MEM) {
// Can't have two mems; put one in var
e->exprBinOp.operands[1] = varify(tlc, chu, sPrev, s, e->exprBinOp.operands[1]);
}
}
dumben_chunk(tlc, s->stmtIf.then);
} else if(s->nodeKind == AST_STMT_LOOP) {
dumben_chunk(tlc, s->stmtLoop.body);
} else if(s->nodeKind == AST_STMT_ASSIGN) {
if(s->stmtAssign.what->nodeKind == AST_EXPR_UNARY_OP && s->stmtAssign.what->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, sPrev, s, s->stmtAssign.to);
}
} else if(s->nodeKind == AST_STMT_EXPR && s->stmtExpr.expr->nodeKind == AST_EXPR_CALL) {
int argCount = s->stmtExpr.expr->exprCall.what->expression.type->function.argCount;
for(int i = 0; i < argCount; i++) {
if(is_xop(s->stmtExpr.expr->exprCall.args[i]) == XOP_NOT_XOP) {
s->stmtExpr.expr->exprCall.args[i] = xopify(tlc, chu, sPrev, s, s->stmtExpr.expr->exprCall.args[i]);
}
}
}
sPrev = s;
s = s->statement.next;
}
}
void dumben_go(AST* tlc) {
dumben_chunk(tlc, tlc);
}

5
src/dumberdowner.h Normal file
View File

@ -0,0 +1,5 @@
#pragma once
#include"ast.h"
void dumben_go(AST* a);

View File

@ -7,6 +7,7 @@
#include"ntc.h" #include"ntc.h"
#include"reporting.h" #include"reporting.h"
#include"cg.h" #include"cg.h"
#include"dumberdowner.h"
static int argc; static int argc;
static char **argv; static char **argv;
@ -36,6 +37,8 @@ int main(int argc_, char **argv_) {
free(tokens); free(tokens);
dumben_go(chunk);
cg_go(chunk); cg_go(chunk);
return 0; return 0;

View File

@ -9,6 +9,21 @@
#include<stdint.h> #include<stdint.h>
#include<signal.h> #include<signal.h>
#ifndef __GNUC__
static inline int __builtin_clzl(unsigned long x) {
unsigned long n = 32;
unsigned long y;
y = x >>16; if (y != 0) { n = n -16; x = y; }
y = x >> 8; if (y != 0) { n = n - 8; x = y; }
y = x >> 4; if (y != 0) { n = n - 4; x = y; }
y = x >> 2; if (y != 0) { n = n - 2; x = y; }
y = x >> 1; if (y != 0) return n - 2;
return n - x;
}
#endif
typedef struct { typedef struct {
UseDef ud; UseDef ud;
VarTableEntry *to; VarTableEntry *to;
@ -75,6 +90,11 @@ static void pushstat(Parser *P, void *a) {
memcpy(ud, &P->udsToAdd[i].ud, sizeof(*ud)); memcpy(ud, &P->udsToAdd[i].ud, sizeof(*ud));
ud->stmt = a; ud->stmt = a;
/*if(ud->stmt->nodeKind == AST_STMT_ASSIGN && ud->stmt->stmtAssign.what == ud->use) {
// Forget. The x in `x = y` is not a use of x.
continue;
}*/
if(to->data.var.usedefFirst) { if(to->data.var.usedefFirst) {
to->data.var.usedefLast->next = ud; to->data.var.usedefLast->next = ud;
to->data.var.usedefLast = ud; to->data.var.usedefLast = ud;
@ -96,7 +116,6 @@ static void pushstat(Parser *P, void *a) {
static ASTExprPrimitive *parse_prim(Parser *P) { static ASTExprPrimitive *parse_prim(Parser *P) {
ASTExprPrimitive *ret = malloc(sizeof(*ret)); ASTExprPrimitive *ret = malloc(sizeof(*ret));
ret->nodeKind = AST_EXPR_PRIMITIVE; ret->nodeKind = AST_EXPR_PRIMITIVE;
ret->type = (Type*) primitive_parse("s16");
Token tok = get(P); Token tok = get(P);
@ -109,17 +128,32 @@ static ASTExprPrimitive *parse_prim(Parser *P) {
ret->val = strtol(str, NULL, base); ret->val = strtol(str, NULL, base);
// Smallest integer type to store number
char buf[8];
snprintf(buf, sizeof(buf), "s%i", ret->val ? (64 - __builtin_clzl(ret->val - 1)) : 1);
ret->type = (Type*) primitive_parse(buf);
return ret; return ret;
} }
static void newusedef(Parser *P, VarTableEntry *v, AST *expr) { static void newusedef(Parser *P, VarTableEntry *v, AST *expr) {
for(size_t i = 0; i < v->data.var.reachingDefs->defCount; i++) { ReachingDefs *defs = v->data.var.reachingDefs;
P->udsToAdd = realloc(P->udsToAdd, sizeof(*P->udsToAdd) * (++P->udsToAddCount));
P->udsToAdd[P->udsToAddCount - 1].ud.def = v->data.var.reachingDefs->defs[i]; while(defs) {
P->udsToAdd[P->udsToAddCount - 1].ud.use = expr; for(size_t i = 0; i < defs->defCount; i++) {
P->udsToAdd[P->udsToAddCount - 1].ud.stmt = NULL; // set by pushstmt P->udsToAdd = realloc(P->udsToAdd, sizeof(*P->udsToAdd) * (++P->udsToAddCount));
P->udsToAdd[P->udsToAddCount - 1].ud.next = NULL; P->udsToAdd[P->udsToAddCount - 1].ud.def = defs->defs[i];
P->udsToAdd[P->udsToAddCount - 1].to = v; P->udsToAdd[P->udsToAddCount - 1].ud.use = expr;
P->udsToAdd[P->udsToAddCount - 1].ud.stmt = NULL; // set by pushstmt
P->udsToAdd[P->udsToAddCount - 1].ud.next = NULL;
P->udsToAdd[P->udsToAddCount - 1].to = v;
}
if(defs->excludeParent) {
break;
}
defs = defs->parent;
} }
} }
@ -159,10 +193,14 @@ AST *nct_cast_expr(AST *what, Type *to) {
} }
return (AST*) ret; return (AST*) ret;
} else if(to->type == TYPE_TYPE_PRIMITIVE && to->primitive.width == 32) { } else if(to->type == TYPE_TYPE_PRIMITIVE) {
if(to->primitive.width != what->exprStrLit.length * 8) {
stahp(0, 0, "Size mismatch between string literal and target type");
}
ASTExprPrimitive *ret = malloc(sizeof(*ret)); ASTExprPrimitive *ret = malloc(sizeof(*ret));
ret->nodeKind = AST_EXPR_PRIMITIVE; ret->nodeKind = AST_EXPR_PRIMITIVE;
ret->type = primitive_parse("u32"); ret->type = to;
memcpy(&ret->val, what->exprStrLit.data, sizeof(ret->val)); memcpy(&ret->val, what->exprStrLit.data, sizeof(ret->val));
return (AST*) ret; return (AST*) ret;
} else abort(); } else abort();
@ -181,6 +219,9 @@ AST *nct_cast_expr(AST *what, Type *to) {
ret->val = what->exprPrim.val & (((int64_t) 1 << to->primitive.width) - 1); ret->val = what->exprPrim.val & (((int64_t) 1 << to->primitive.width) - 1);
return (AST*) ret; return (AST*) ret;
} else { } else {
// Silently fail :)
return what;
ASTExprCast *ret = malloc(sizeof(*ret)); ASTExprCast *ret = malloc(sizeof(*ret));
ret->nodeKind = AST_EXPR_CAST; ret->nodeKind = AST_EXPR_CAST;
ret->type = to; ret->type = to;
@ -629,6 +670,77 @@ backtrack:
return NULL; return NULL;
} }
/* Imagine the following pseudocode:
x = ...
while ... {
(do something with x)
x = ...
}
The second definition of x reaches the code *before* it.
Therefore we must go over the loop body a second time with known reaching definitions and add the necessary usedefs.*/
static void loop_second_pass(AST *a) {
if(a->nodeKind == AST_CHUNK) {
for(AST *s = a->chunk.statementFirst; s; s = s->statement.next) {
loop_second_pass(s);
}
} else if(a->nodeKind == AST_STMT_IF) {
loop_second_pass(a->stmtIf.expression);
loop_second_pass(a->stmtIf.then);
} else if(a->nodeKind == AST_STMT_LOOP) {
loop_second_pass(a->stmtLoop.body);
} else if(a->nodeKind == AST_STMT_ASSIGN) {
loop_second_pass(a->stmtAssign.what);
loop_second_pass(a->stmtAssign.to);
/* TODO: Per-variable flag.to cease additional usedefs after assignment?
It is okay to have too many usedefs, so this isn't high priority.*/
} else if(a->nodeKind == AST_STMT_EXPR) {
loop_second_pass(a->stmtExpr.expr);
} else if(a->nodeKind == AST_EXPR_VAR) {
UseDef *udPrev = NULL;
UseDef *ud = a->exprVar.thing->data.var.usedefFirst;
while(ud && ud->use != a) {
udPrev = ud;
ud = ud->next;
}
if(ud) {
ReachingDefs *defs = a->exprVar.thing->data.var.reachingDefs;
while(defs) {
for(size_t i = 0; i < defs->defCount; i++) {
UseDef *newud = calloc(1, sizeof(*newud));
memcpy(newud, ud, sizeof(*ud));
newud->def = defs->defs[i];
udPrev->next = newud;
newud->next = ud;
ud = newud;
}
if(defs->excludeParent) {
break;
}
defs = defs->parent;
}
}
} else if(a->nodeKind == AST_EXPR_BINARY_OP) {
loop_second_pass(a->exprBinOp.operands[0]);
loop_second_pass(a->exprBinOp.operands[1]);
} else if(a->nodeKind == AST_EXPR_UNARY_OP) {
loop_second_pass(a->exprUnOp.operand);
} else if(a->nodeKind == AST_EXPR_CAST) {
loop_second_pass(a->exprCast.what);
} else if(a->nodeKind == AST_EXPR_CALL) {
loop_second_pass(a->exprCall.what);
size_t argCount = a->exprCall.what->expression.type->function.argCount;
for(size_t i = 0; i < argCount; i++) {
loop_second_pass(a->exprCall.args[i]);
}
}
}
ASTChunk *nct_parse_chunk(Parser*, int, int); ASTChunk *nct_parse_chunk(Parser*, int, int);
void nct_parse_statement(Parser *P) { void nct_parse_statement(Parser *P) {
if(maybe(P, TOKEN_IF)) { if(maybe(P, TOKEN_IF)) {
@ -657,6 +769,8 @@ void nct_parse_statement(Parser *P) {
ret->body = (AST*) nct_parse_chunk(P, 0, 1); ret->body = (AST*) nct_parse_chunk(P, 0, 1);
expect(P, TOKEN_SQUIGGLY_R); expect(P, TOKEN_SQUIGGLY_R);
loop_second_pass(ret->body);
pushstat(P, ret); pushstat(P, ret);
return; return;
} else if(maybe(P, TOKEN_BREAK)) { } else if(maybe(P, TOKEN_BREAK)) {
@ -745,7 +859,7 @@ void nct_parse_statement(Parser *P) {
ret->nodeKind = AST_STMT_ASSIGN; ret->nodeKind = AST_STMT_ASSIGN;
ret->next = NULL; ret->next = NULL;
ret->what = e; ret->what = e;
ret->to = nct_parse_expression(P, 0);//nct_cast_expr(nct_parse_expression(P, 0), ret->what->expression.type); ret->to = nct_cast_expr(nct_parse_expression(P, 0), ret->what->expression.type);
if(ret->what->nodeKind == AST_EXPR_VAR) { if(ret->what->nodeKind == AST_EXPR_VAR) {
reachingdefs_set(ret->what->exprVar.thing->data.var.reachingDefs, (AST*) ret); reachingdefs_set(ret->what->exprVar.thing->data.var.reachingDefs, (AST*) ret);

View File

@ -22,7 +22,7 @@ Type *primitive_parse(const char *src) {
TypePrimitive *ret = malloc(sizeof(*ret)); TypePrimitive *ret = malloc(sizeof(*ret));
ret->type = TYPE_TYPE_PRIMITIVE; ret->type = TYPE_TYPE_PRIMITIVE;
ret->src = src; ret->src = strdup(src);
if(*src == 'n') { if(*src == 'n') {
src++; src++;

View File

@ -62,6 +62,7 @@ typedef union Type {
extern Type TYPE_ERROR; extern Type TYPE_ERROR;
Type *primitive_parse(const char*); Type *primitive_parse(const char*);
Type *primitive_make(uint16_t width);
size_t type_size(Type*); size_t type_size(Type*);
int type_equal(Type*, Type*); int type_equal(Type*, Type*);

View File

@ -26,6 +26,7 @@ void reachingdefs_set(struct ReachingDefs *this, union AST *def) {
this->defCount = 1; this->defCount = 1;
this->defs = realloc(this->defs, sizeof(*this->defs) * this->defCount); this->defs = realloc(this->defs, sizeof(*this->defs) * this->defCount);
this->defs[0] = def; this->defs[0] = def;
this->excludeParent = 1;
} }
VarTable *vartable_new(VarTable *parent) { VarTable *vartable_new(VarTable *parent) {

View File

@ -20,6 +20,7 @@ typedef struct ReachingDefs {
size_t defCount; size_t defCount;
union AST **defs; union AST **defs;
int excludeParent;
struct ReachingDefs *parent; struct ReachingDefs *parent;
} ReachingDefs; } ReachingDefs;
struct ReachingDefs *reachingdefs_push(struct ReachingDefs*); struct ReachingDefs *reachingdefs_push(struct ReachingDefs*);

View File

@ -30,12 +30,10 @@ loop {
data[dataPtr] = data[dataPtr] - 1; data[dataPtr] = data[dataPtr] - 1;
} }
if(code[codePtr] == 46) { if(code[codePtr] == 46) {
u32 z = &data + dataPtr; write(1, &data + dataPtr, 1);
write(1, z, 1);
} }
if(code[codePtr] == 44) { if(code[codePtr] == 44) {
u32 z = &data + dataPtr; read(0, &data + dataPtr, 1);
read(0, z, 1);
} }
if(code[codePtr] == 91) { if(code[codePtr] == 91) {
if(data[dataPtr] == 0) { if(data[dataPtr] == 0) {