summaryrefslogtreecommitdiff
path: root/codegen.c
diff options
context:
space:
mode:
authorMatthew Sotoudeh <matthew@masot.net>2023-07-26 10:53:27 -0700
committerMatthew Sotoudeh <matthew@masot.net>2023-07-26 10:53:27 -0700
commitf35b7e32809c5d54850ce75c4dad1a8598235cf0 (patch)
treea741ac273b8109db35b2abd59423a5efe6293a04 /codegen.c
parent36fc249a02eb0ef32d3bc1d4e596683b64b1eb5f (diff)
simplify code a fair bit
Diffstat (limited to 'codegen.c')
-rw-r--r--codegen.c270
1 files changed, 203 insertions, 67 deletions
diff --git a/codegen.c b/codegen.c
index 9eaac4a..7e8565a 100644
--- a/codegen.c
+++ b/codegen.c
@@ -8,25 +8,60 @@ int is_bad_number(double x) {
return (x != x) || (x == 1./0.) || (-x == 1./0.);
}
-static FILE *output_file;
-static int RETURN_TMP;
-
-static void printnoln(char *fmt, ...);
-static void println(char *fmt, ...);
-static void print_tok(Token *tok);
-
-FILE *BUFFER;
-int DO_BUFFER;
-
-static void flush_buffer() {
- rewind(BUFFER);
+/////////// PRINTING
+static FILE *CURR_BUFFER,
+ // the typedefs at the very beginning
+ *TYPE_BUFFER,
+ // everything after the typedefs
+ *MAIN_BUFFER,
+ // code inside a function (after all declarations, which go into
+ // the main buffer immediately)
+ *CODE_BUFFER;
+
+FILE *BUFFER_STACK[8];
+int N_BUFFER_STACK;
+static void push_buffer(FILE *which) {
+ assert(N_BUFFER_STACK < 8);
+ BUFFER_STACK[N_BUFFER_STACK++] = which;
+ CURR_BUFFER = which;
+}
+static void pop_buffer(FILE *which) {
+ assert(N_BUFFER_STACK--);
+ assert(BUFFER_STACK[N_BUFFER_STACK] == which);
+ CURR_BUFFER = BUFFER_STACK[N_BUFFER_STACK - 1];
+}
+static void flush_buffer(FILE *to_buffer, FILE *from_buffer) {
+ rewind(from_buffer);
int c;
- while ((c = fgetc(BUFFER)) != EOF)
- fputc(c, output_file);
- rewind(BUFFER);
- ftruncate(fileno(BUFFER), 0);
+ while ((c = fgetc(from_buffer)) != EOF)
+ fputc(c, to_buffer);
+ rewind(from_buffer);
+ ftruncate(fileno(from_buffer), 0);
+}
+__attribute__((format(printf, 1, 2)))
+static void printnoln(char *fmt, ...) {
+ va_list ap;
+ va_start(ap, fmt);
+ vfprintf(CURR_BUFFER, fmt, ap);
+ va_end(ap);
+}
+__attribute__((format(printf, 1, 2)))
+static void println(char *fmt, ...) {
+ va_list ap;
+ va_start(ap, fmt);
+ vfprintf(CURR_BUFFER, fmt, ap);
+ va_end(ap);
+ fputc('\n', CURR_BUFFER);
+}
+/////////// END PRINTING
+
+static int count(void) {
+ static int i = 1;
+ return i++;
}
+static int RETURN_TMP;
+
void print_label(char *label) {
printnoln("_l");
for (; *label; label++) {
@@ -57,52 +92,147 @@ void print_obj(Obj *obj) {
}
}
+///////// TYPES
+const void typedecl(Type *type) {
+ if (type->id) return;
+ Type *hashed = hash_lookup(type);
+ if (hashed && !(hashed->typedecling)) {
+ assert(hashed->id);
+ type->id = hashed->id;
+ if (hashed->pointer_type) type->pointer_type = hashed->pointer_type;
+ if (hashed->return_ty) type->return_ty = hashed->return_ty;
+ if (hashed->params) type->params = hashed->params;
+ return;
+ }
+ type->typedecling = 1;
+ type->id = count();
+ hash_insert(type);
+ switch (type->kind) {
+ case TY_FLOAT:
+ println("typedef float Type_%d ;", type->id);
+ break;
+ case TY_DOUBLE:
+ println("typedef double Type_%d ;", type->id);
+ break;
+ case TY_LDOUBLE:
+ println("typedef long double Type_%d ;", type->id);
+ break;
+ case TY_INT:
+ if (type->is_unsigned)
+ println("typedef unsigned int Type_%d ;", type->id);
+ else
+ println("typedef int Type_%d ;", type->id);
+ break;
+ case TY_LONG:
+ if (type->is_unsigned)
+ println("typedef unsigned long Type_%d ;", type->id);
+ else
+ println("typedef long Type_%d ;", type->id);
+ break;
+ case TY_SHORT:
+ if (type->is_unsigned)
+ println("typedef unsigned short Type_%d ;", type->id);
+ else
+ println("typedef short Type_%d ;", type->id);
+ break;
+ case TY_VOID:
+ println("typedef void Type_%d ;", type->id);
+ break;
+ case TY_BOOL:
+ println("typedef _Bool Type_%d ;", type->id);
+ break;
+ case TY_CHAR:
+ println("typedef char Type_%d ;", type->id);
+ break;
+ case TY_PTR:
+ typedecl(type->base);
+ println("typedef Type_%d * Type_%d ;", type->base->id, type->id);
+ break;
+ case TY_FUNC: {
+ typedecl(type->return_ty);
+ for (Type *p = type->params; p; p = p->next)
+ typedecl(p);
+ printnoln("typedef Type_%d Type_%d ( ", type->return_ty->id, type->id);
+
+ int i = 0;
+ for (Type *p = type->params; p; p = p->next, i++)
+ if (i) printnoln(", Type_%d ", p->id);
+ else printnoln("Type_%d ", p->id);
+
+ if (type->is_variadic) {
+ if (i) printnoln(", ... ");
+ // else printnoln("... ");
+ }
+ println(") ;");
+ break;
+ }
+ case TY_ARRAY:
+ typedecl(type->base);
+ if (type->array_len == -1)
+ println("typedef Type_%d Type_%d [ ] ;", type->base->id, type->id);
+ else
+ println("typedef Type_%d Type_%d [ %d ] ;", type->base->id, type->id,
+ type->array_len);
+ break;
+ case TY_STRUCT:
+ case TY_UNION:
+ if (type->kind == TY_STRUCT)
+ println("typedef struct Struct_%d Type_%d ;", type->id, type->id);
+ else
+ println("typedef union Union_%d Type_%d ;", type->id, type->id);
+
+ for (Member *m = type->members; m; m = m->next)
+ typedecl(m->ty);
+
+ if (type->kind == TY_STRUCT) printnoln("struct Struct_%d { ", type->id);
+ else printnoln("union Union_%d { ", type->id);
+ for (Member *m = type->members; m; m = m->next) {
+ printnoln("Type_%d ", m->ty->id);
+ if (m->name)
+ print_tok(m->name);
+ else if (m->ty->kind == TY_STRUCT || m->ty->kind == TY_UNION)
+ printnoln("___dietc_f%d", m->idx);
+ else
+ printnoln("__field_%d", count());
+ printnoln(" ; ");
+ }
+ println("} ;");
+ break;
+ case TY_ENUM:
+ println("typedef enum Enum_%d { EN_%d } Type_%d ;", type->id, type->id, type->id);
+ break;
+ case TY_VLA:
+ assert(!"unimplemented vla?");
+ break;
+ default:
+ assert(!"unimplemented?");
+ break;
+ }
+ type->typedecling = 0;
+}
+void ensure_pointer_to(Type *type) {
+ if (type->pointer_type) return;
+ type->pointer_type = pointer_to(type);
+}
+//////////// END TYPES
+
const void print_type(Type *type) {
if (type->kind == TY_FUNC) {
- assert(type->pointer_type);
+ ensure_pointer_to(type);
print_type(type->pointer_type);
} else {
+ push_buffer(TYPE_BUFFER);
+ typedecl(type);
+ pop_buffer(TYPE_BUFFER);
assert(type->id);
printnoln("Type_%d", type->id);
}
}
-static int depth;
static Obj *current_fn;
static void gen_expr(Node *node, int to_tmp);
static void gen_stmt(Node *node);
-__attribute__((format(printf, 1, 2)))
-static void println(char *fmt, ...) {
- va_list ap;
- va_start(ap, fmt);
- if (DO_BUFFER)
- vfprintf(BUFFER, fmt, ap);
- else
- vfprintf(output_file, fmt, ap);
- va_end(ap);
- if (DO_BUFFER)
- fprintf(BUFFER, "\n");
- else
- fprintf(output_file, "\n");
-}
-
-__attribute__((format(printf, 1, 2)))
-static void printnoln(char *fmt, ...) {
- va_list ap;
- va_start(ap, fmt);
- if (DO_BUFFER)
- vfprintf(BUFFER, fmt, ap);
- else
- vfprintf(output_file, fmt, ap);
- va_end(ap);
-}
-
-static int count(void) {
- static int i = 1;
- return i++;
-}
-
// Round up `n` to the nearest multiple of `align`. For instance,
// align_to(5, 8) returns 8 and align_to(11, 8) returns 16.
int align_to(int n, int align) {
@@ -110,15 +240,16 @@ int align_to(int n, int align) {
}
void decltmp(Type *type, int c) {
- DO_BUFFER = 0;
+ // Write directly to the main buffer so it decls before the code.
+ push_buffer(MAIN_BUFFER);
printnoln("\t");
print_type(type);
println(" t%d ;", c);
- DO_BUFFER = 1;
+ pop_buffer(MAIN_BUFFER);
}
void decltmpptr(Type *type, int c) {
- assert(type->pointer_type);
+ ensure_pointer_to(type);
decltmp(type->pointer_type, c);
}
@@ -268,6 +399,7 @@ static void gen_expr(Node *node, int to_tmp) {
int c = count();
if (node->ty->kind == TY_VOID) {
gen_expr(node->lhs, c);
+ push_buffer(TYPE_BUFFER); typedecl(node->ty); pop_buffer(TYPE_BUFFER);
println("\t( Type_%d ) t%d ;", node->ty->id, c);
} else if (node->lhs->ty->kind == TY_UNION) {
// union *tuptr = &union
@@ -531,16 +663,11 @@ static void assign_lvar_offsets(Obj *prog) {
if (!fn->is_function)
continue;
- // If a function has many parameters, some parameters are
- // inevitably passed by stack rather than by register.
- // The first passed-by-stack parameter resides at RBP+16.
- int c = 1;
-
for (Obj *var = fn->params; var; var = var->next)
- var->offset = c++;
+ var->offset = count();
for (Obj *var = fn->locals; var; var = var->next)
if (!(var->offset))
- var->offset = c++;
+ var->offset = count();
}
}
@@ -663,6 +790,9 @@ void emit_constant(int pos, char *data, Relocation **rel, Type *type) {
static void emit_data(Obj *prog) {
for (Obj *var = prog; var; var = var->next) {
+ push_buffer(TYPE_BUFFER);
+ typedecl(var->ty);
+ pop_buffer(TYPE_BUFFER);
if (var->is_static && var->is_function) {
printnoln("static Type_%d ", var->ty->id);
print_obj(var); println(" ;");
@@ -732,7 +862,6 @@ static void emit_text(Obj *prog) {
}
for (Obj *var = fn->locals; var; var = var->next) {
- if (!(var->ty->id)) continue;
if (var->is_param) continue;
if (var == fn->va_area) continue;
if (var == fn->alloca_bottom) continue;
@@ -744,11 +873,10 @@ static void emit_text(Obj *prog) {
}
// Emit code
- DO_BUFFER = 1;
+ push_buffer(CODE_BUFFER);
gen_stmt(fn->body);
- assert(depth == 0);
- flush_buffer();
- DO_BUFFER = 0;
+ pop_buffer(CODE_BUFFER);
+ flush_buffer(MAIN_BUFFER, CODE_BUFFER);
println("\t_L_RETURN :");
if (fn->ty->return_ty->kind != TY_VOID) {
@@ -762,10 +890,18 @@ static void emit_text(Obj *prog) {
}
void codegen(Obj *prog, FILE *out) {
- output_file = out;
-
- BUFFER = tmpfile();
+ TYPE_BUFFER = tmpfile();
+ MAIN_BUFFER = tmpfile();
+ CODE_BUFFER = tmpfile();
assign_lvar_offsets(prog);
+
+ // Everything defaults to writing to main
+ push_buffer(MAIN_BUFFER);
emit_data(prog);
emit_text(prog);
+ pop_buffer(MAIN_BUFFER);
+
+ fprintf(out, "#include \"%s/scripts/dietc_helpers.h\"\n", DIETC_ROOT);
+ flush_buffer(out, TYPE_BUFFER);
+ flush_buffer(out, MAIN_BUFFER);
}
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback