commit 2501f5630ea984629189a1585abc0c1f40b0d0ad
parent 1e39643dc342926d80fedd5ce6bc6aae7e075060
Author: Drew DeVault <sir@cmpwn.com>
Date: Thu, 31 Dec 2020 16:27:46 -0500
all: bootstrap runtime
Diffstat:
17 files changed, 114 insertions(+), 65 deletions(-)
diff --git a/Makefile b/Makefile
@@ -19,6 +19,10 @@ include rt/Makefile
$(CPP) $(CFLAGS) -MM -MT $@ $< >> $(OUTDIR)/cppcache
@$(CC) -c $(CFLAGS) -o $@ $<
+.s.o:
+ @printf 'AS\t$@\n'
+ @$(AS) -o $@ $<
+
docs:
clean:
diff --git a/include/ast.h b/include/ast.h
@@ -2,12 +2,13 @@
#define HARE_AST_H
#include <stdbool.h>
#include <stdint.h>
-#include "check.h"
#include "expr.h"
#include "identifier.h"
#include "lex.h"
#include "types.h"
+struct ast_type;
+
enum ast_import_mode {
AST_IMPORT_IDENTIFIER, // use foo::bar;
AST_IMPORT_ALIAS, // use foo::bar = x::y;
diff --git a/include/check.h b/include/check.h
@@ -3,11 +3,19 @@
#include <stdbool.h>
#include "identifier.h"
#include "types.h"
+#include "type_store.h"
-struct context;
struct expression;
struct scope;
+struct context {
+ struct type_store store;
+ const struct type *current_fntype;
+ struct identifier *ns;
+ struct scope *unit;
+ struct scope *scope;
+};
+
enum func_decl_flags {
FN_FINI = 1 << 0,
FN_INIT = 1 << 1,
@@ -51,7 +59,9 @@ struct unit {
struct ast_expression;
struct ast_unit;
-void check(const struct ast_unit *aunit, struct unit *unit);
+void check(struct context *ctx,
+ const struct ast_unit *aunit,
+ struct unit *unit);
void check_expression(struct context *ctx,
const struct ast_expression *aexpr, struct expression *expr);
diff --git a/include/scope.h b/include/scope.h
@@ -12,7 +12,10 @@ enum object_type {
// XXX: This might be better as a hash map
struct scope_object {
enum object_type otype;
- struct identifier ident;
+ // name is the name of the object within this scope (for lookups)
+ // ident is the global identifier
+ // (these may be different in some cases)
+ struct identifier name, ident;
const struct type *type;
struct expression *value; // For O_CONST
struct scope_object *next;
@@ -35,9 +38,11 @@ struct scope *scope_pop(struct scope **stack, enum trace_sys sys);
void scope_free(struct scope *scope);
void scope_free_all(struct scopes *scopes);
-const struct scope_object *scope_insert(struct scope *scope,
- enum object_type otype, const struct identifier *ident,
+const struct scope_object *scope_insert(
+ struct scope *scope, enum object_type otype,
+ const struct identifier *ident, const struct identifier *name,
const struct type *type, struct expression *value);
+
const struct scope_object *scope_lookup(struct scope *scope,
const struct identifier *ident);
diff --git a/include/type_store.h b/include/type_store.h
@@ -21,6 +21,8 @@ bool type_is_assignable(struct type_store *store,
const struct type *to, const struct type *from);
bool type_is_castable(const struct type *to, const struct type *from);
+struct ast_type;
+
const struct type *type_store_lookup_atype(
struct type_store *store, const struct ast_type *atype);
diff --git a/rt/+linux/start.s b/rt/+linux/start.s
@@ -0,0 +1,6 @@
+.text
+.global _start
+_start:
+ xor %rbp, %rbp
+ movq %rsp, %rdi
+ call rt.start_ha
diff --git a/rt/+linux/syscall+x86_64.s b/rt/+linux/syscall+x86_64.s
@@ -1,27 +1,27 @@
.text
-.global sys.syscall0
-sys.syscall0:
+.global rt.syscall0
+rt.syscall0:
movq %rdi, %rax
syscall
ret
-.global sys.syscall1
-sys.syscall1:
+.global rt.syscall1
+rt.syscall1:
movq %rdi, %rax
movq %rsi, %rdi
syscall
ret
-.global sys.syscall2
-sys.syscall2:
+.global rt.syscall2
+rt.syscall2:
movq %rdi, %rax
movq %rsi, %rdi
movq %rdx, %rsi
syscall
ret
-.global sys.syscall3
-sys.syscall3:
+.global rt.syscall3
+rt.syscall3:
movq %rdi, %rax
movq %rsi, %rdi
movq %rdx, %rsi
@@ -29,8 +29,8 @@ sys.syscall3:
syscall
ret
-.global sys.syscall4
-sys.syscall4:
+.global rt.syscall4
+rt.syscall4:
movq %rdi, %rax
movq %r8, %r10
movq %rsi, %rdi
@@ -39,8 +39,8 @@ sys.syscall4:
syscall
ret
-.global sys.syscall5
-sys.syscall5:
+.global rt.syscall5
+rt.syscall5:
movq %rdi, %rax
movq %r8, %r10
movq %rsi, %rdi
@@ -50,8 +50,8 @@ sys.syscall5:
syscall
ret
-.global sys.syscall6
-sys.syscall6:
+.global rt.syscall6
+rt.syscall6:
movq %rdi, %rax
movq %r8, %r10
movq %rsi, %rdi
diff --git a/rt/Makefile b/rt/Makefile
@@ -1,14 +1,11 @@
-libhart_srcs=\
+libhart_srcs+=\
rt/abort.ha \
- rt/malloc.ha \
- rt/memcmp.ha \
- rt/memcpy.ha \
- rt/memset.ha
+ rt/rtmain.ha
-libhart.a: $(libhart_srcs)
+libhart.a: harec $(libhart_srcs) $(libhart_objs)
@printf 'HAREC\t$@\n'
@./harec -N rt -o $@.ssa $(libhart_srcs)
@qbe -o $@.s $@.ssa
@$(AS) -o $@.o $@.s
- @$(AR) -csr $@ $@.o
+ @$(AR) -csr $@ $@.o $(libhart_objs)
@rm $@.o $@.s $@.ssa
diff --git a/rt/abort.ha b/rt/abort.ha
@@ -1,9 +1,9 @@
export @noreturn @symbol("rt.abort") fn _abort(msg: str) void = {
- const prefix = "Abort: ";
+ const prefix = "Abort: ", newline = "\n";
// XXX: This causes const to fall off, we should catch that (may need
// spec update)
write(2, prefix: *const char, len(prefix));
write(2, msg: *const char, len(msg));
- write(2, "\n": *const char, 1z);
+ write(2, newline: *const char, 1z);
kill(getpid(), SIGABRT);
};
diff --git a/rt/configure b/rt/configure
@@ -2,5 +2,22 @@
all="$all rt"
rt() {
- echo "rt: libhart.a"
+ case $(uname) in
+ Linux)
+ cat <<-EOF
+ libhart_srcs=\
+ rt/+linux/syscallno+x86_64.ha \
+ rt/+linux/syscalls.ha
+
+ libhart_objs=\
+ rt/+linux/syscall+x86_64.o
+
+ rt: libhart.a rt/+linux/start.o
+ EOF
+ ;;
+ *)
+ printf "rt not supported for %s\n" "$(uname)" >&2
+ exit 1
+ ;;
+ esac
}
diff --git a/rt/rtmain.ha b/rt/rtmain.ha
@@ -0,0 +1,7 @@
+@symbol("main") fn main() int;
+fn exit(status: int) void;
+
+export fn start_ha(iv: [*]uintptr) void = {
+ main();
+ exit(0);
+};
diff --git a/src/check.c b/src/check.c
@@ -13,14 +13,6 @@
#include "types.h"
#include "util.h"
-struct context {
- struct type_store store;
- const struct type *current_fntype;
- struct identifier *ns;
- struct scope *unit;
- struct scope *scope;
-};
-
static void
mkident(struct context *ctx, struct identifier *out, const struct identifier *in)
{
@@ -38,7 +30,7 @@ expect(const struct location *loc, bool constraint, char *fmt, ...)
va_list ap;
va_start(ap, fmt);
- fprintf(stderr, "Error: %s:%d:%d: ",
+ fprintf(stderr, "Error %s:%d:%d: ",
loc->path, loc->lineno, loc->colno);
vfprintf(stderr, fmt, ap);
fprintf(stderr, "\n");
@@ -64,7 +56,7 @@ check_expr_access(struct context *ctx,
obj = scope_lookup(ctx->scope, &aexpr->access.ident);
char buf[1024];
identifier_unparse_static(&aexpr->access.ident, buf, sizeof(buf));
- expect(&aexpr->loc, obj, "Unknown object", buf);
+ expect(&aexpr->loc, obj, "Unknown object '%s'", buf);
if (obj->otype == O_CONST) {
// Lower constants
*expr = *obj->value;
@@ -256,7 +248,7 @@ check_expr_binding(struct context *ctx,
"Initializer is not assignable to binding type");
const struct scope_object *obj = scope_insert(
- ctx->scope, O_BIND, &ident, type, NULL);
+ ctx->scope, O_BIND, &ident, &ident, type, NULL);
binding->object = obj;
binding->initializer = initializer;
@@ -766,7 +758,8 @@ check_function(struct context *ctx,
};
const struct type *type = type_store_lookup_atype(
&ctx->store, params->type);
- scope_insert(decl->func.scope, O_BIND, &ident, type, NULL);
+ scope_insert(decl->func.scope, O_BIND,
+ &ident, &ident, type, NULL);
params = params->next;
}
@@ -844,8 +837,12 @@ scan_function(struct context *ctx, const struct ast_function_decl *decl)
assert(fntype); // TODO: Forward references
struct identifier ident = {0};
- mkident(ctx, &ident, &decl->ident);
- scope_insert(ctx->unit, O_DECL, &ident, fntype, NULL);
+ if (decl->symbol) {
+ ident.name = strdup(decl->symbol);
+ } else {
+ mkident(ctx, &ident, &decl->ident);
+ }
+ scope_insert(ctx->unit, O_DECL, &ident, &decl->ident, fntype, NULL);
char buf[1024];
identifier_unparse_static(&decl->ident, buf, sizeof(buf));
@@ -880,7 +877,7 @@ scan_const(struct context *ctx, const struct ast_global_decl *decl)
struct identifier ident = {0};
mkident(ctx, &ident, &decl->ident);
- scope_insert(ctx->unit, O_CONST, &ident, type, value);
+ scope_insert(ctx->unit, O_CONST, &ident, &decl->ident, type, value);
trleave(TR_SCAN, NULL);
}
@@ -909,11 +906,10 @@ scan_declarations(struct context *ctx, const struct ast_decls *decls)
}
void
-check(const struct ast_unit *aunit, struct unit *unit)
+check(struct context *ctx, const struct ast_unit *aunit, struct unit *unit)
{
- struct context ctx = {0};
- ctx.store.check_context = &ctx;
- ctx.ns = unit->ns;
+ ctx->store.check_context = ctx;
+ ctx->ns = unit->ns;
// Top-level scope management involves:
//
@@ -923,7 +919,7 @@ check(const struct ast_unit *aunit, struct unit *unit)
//
// Further down the call frame, subsequent functions will create
// sub-scopes for each declaration, expression-list, etc.
- ctx.unit = scope_push(&ctx.scope, TR_MAX);
+ ctx->unit = scope_push(&ctx->scope, TR_MAX);
struct scopes *subunit_scopes;
struct scopes **next = &subunit_scopes;
@@ -931,13 +927,13 @@ check(const struct ast_unit *aunit, struct unit *unit)
// First pass populates the type graph
for (const struct ast_subunit *su = &aunit->subunits;
su; su = su->next) {
- scope_push(&ctx.scope, TR_SCAN);
+ scope_push(&ctx->scope, TR_SCAN);
assert(!su->imports); // TODO
- scan_declarations(&ctx, &su->decls);
+ scan_declarations(ctx, &su->decls);
*next = xcalloc(1, sizeof(struct scopes));
- (*next)->scope = scope_pop(&ctx.scope, TR_SCAN);
+ (*next)->scope = scope_pop(&ctx->scope, TR_SCAN);
next = &(*next)->next;
}
@@ -946,9 +942,9 @@ check(const struct ast_unit *aunit, struct unit *unit)
struct declarations **next_decl = &unit->declarations;
for (const struct ast_subunit *su = &aunit->subunits;
su; su = su->next) {
- ctx.scope = scope->scope;
- trenter(TR_CHECK, "scope %p", ctx.scope);
- next_decl = check_declarations(&ctx, &su->decls, next_decl);
+ ctx->scope = scope->scope;
+ trenter(TR_CHECK, "scope %p", ctx->scope);
+ next_decl = check_declarations(ctx, &su->decls, next_decl);
trleave(TR_CHECK, NULL);
scope = scope->next;
}
diff --git a/src/gen.c b/src/gen.c
@@ -100,10 +100,12 @@ qval_for_object(struct gen_context *ctx,
binding = binding_lookup(ctx, obj);
val->kind = QV_TEMPORARY;
val->indirect = true;
+ val->name = strdup(binding->name);
break;
case O_DECL:
val->kind = QV_GLOBAL;
val->indirect = false;
+ val->name = ident_to_sym(&obj->ident);
break;
case O_CONST:
assert(0); // Invariant (lowered in check)
@@ -115,8 +117,6 @@ qval_for_object(struct gen_context *ctx,
} else {
val->type = &qbe_long; // XXX: ARCH
}
-
- val->name = binding ? strdup(binding->name) : ident_to_sym(&obj->ident);
}
static void
diff --git a/src/main.c b/src/main.c
@@ -125,7 +125,8 @@ main(int argc, char *argv[])
return 0;
}
- check(&aunit, &unit);
+ struct context ctx = {0};
+ check(&ctx, &aunit, &unit);
if (stage == STAGE_CHECK) {
return 0;
}
diff --git a/src/parse.c b/src/parse.c
@@ -6,6 +6,7 @@
#include <stdlib.h>
#include <string.h>
#include "ast.h"
+#include "check.h"
#include "identifier.h"
#include "lex.h"
#include "parse.h"
diff --git a/src/scope.c b/src/scope.c
@@ -62,14 +62,13 @@ scope_free_all(struct scopes *scopes)
}
const struct scope_object *
-scope_insert(struct scope *scope,
- enum object_type otype,
- const struct identifier *ident,
- const struct type *type,
- struct expression *value)
+scope_insert(struct scope *scope, enum object_type otype,
+ const struct identifier *ident, const struct identifier *name,
+ const struct type *type, struct expression *value)
{
struct scope_object *o = xcalloc(1, sizeof(struct scope_object));
identifier_dup(&o->ident, ident);
+ identifier_dup(&o->name, name);
o->otype = otype;
o->type = type;
o->value = value;
@@ -87,7 +86,7 @@ scope_lookup(struct scope *scope, const struct identifier *ident)
{
struct scope_object *o = scope->objects;
while (o) {
- if (identifier_eq(&o->ident, ident)) {
+ if (identifier_eq(&o->name, ident)) {
return o;
}
o = o->next;
diff --git a/src/type_store.c b/src/type_store.c
@@ -320,6 +320,9 @@ static bool
type_eq_type(struct type_store *store,
const struct type *a, const struct type *b)
{
+ if (a == b) {
+ return true;
+ }
if (a->storage != b->storage || a->flags != b->flags) {
return false;
}