commit e75a186f908f2dbc7b2ef5e506a4c5e9c8177358
parent ca270dd081d4878f0863339779c6383a3f14f16d
Author: Drew DeVault <sir@cmpwn.com>
Date: Fri, 26 Feb 2021 17:48:56 -0500
Support referencing symbols in global initializers
This kind of half-assed, we'll have to flesh out all of the edge cases
later
Diffstat:
6 files changed, 96 insertions(+), 17 deletions(-)
diff --git a/include/expr.h b/include/expr.h
@@ -161,18 +161,22 @@ struct struct_constant {
struct struct_constant *next;
};
-union expression_constant {
- bool bval;
- double fval;
- intmax_t ival;
- uintmax_t uval;
- uint32_t rune;
- struct {
- size_t len;
- char *value;
- } string;
- struct array_constant *array;
- struct struct_constant *_struct;
+struct expression_constant {
+ // If non-null, ival is an offset from this object's address
+ const struct scope_object *object;
+ union {
+ bool bval;
+ double fval;
+ intmax_t ival;
+ uintmax_t uval;
+ uint32_t rune;
+ struct {
+ size_t len;
+ char *value;
+ } string;
+ struct array_constant *array;
+ struct struct_constant *_struct;
+ };
};
struct expression_control {
@@ -315,7 +319,7 @@ struct expression {
struct expression_binding binding;
struct expression_call call;
struct expression_cast cast;
- union expression_constant constant;
+ struct expression_constant constant;
struct expression_defer defer;
struct expression_delete delete;
struct expression_control control;
diff --git a/include/qbe.h b/include/qbe.h
@@ -221,6 +221,7 @@ enum qbe_datatype {
QD_VALUE,
QD_ZEROED,
QD_STRING,
+ QD_SYMOFFS,
};
struct qbe_data_item {
@@ -232,6 +233,10 @@ struct qbe_data_item {
char *str;
size_t sz;
};
+ struct {
+ char *sym;
+ long offset;
+ };
};
struct qbe_data_item *next;
};
diff --git a/src/emit.c b/src/emit.c
@@ -277,6 +277,9 @@ is_zeroes(struct qbe_data_item *data)
return false;
}
}
+ break;
+ case QD_SYMOFFS:
+ return false;
}
if (!data->next) {
return true;
@@ -315,6 +318,10 @@ emit_data(struct qbe_def *def, FILE *out)
case QD_STRING:
emit_data_string(item->str, item->sz, out);
break;
+ case QD_SYMOFFS:
+ // XXX: ARCH
+ fprintf(out, "l $%s + %ld", item->sym, item->offset);
+ break;
}
fprintf(out, item->next ? ", " : " ");
diff --git a/src/eval.c b/src/eval.c
@@ -2,6 +2,7 @@
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
+#include "check.h"
#include "eval.h"
#include "expr.h"
#include "scope.h"
@@ -9,6 +10,30 @@
#include "types.h"
#include "util.h"
+static enum eval_result
+eval_access(struct context *ctx, struct expression *in, struct expression *out)
+{
+ out->type = EXPR_CONSTANT;
+ out->result = in->result;
+
+ // TODO: Probably have not considered all of the edge cases here
+ switch (in->access.type) {
+ case ACCESS_IDENTIFIER:
+ out->constant.object = in->access.object;
+ out->constant.ival = 0;
+ assert(in->access.object->otype == O_DECL); // TODO: Bubble this up
+ break;
+ case ACCESS_INDEX:
+ assert(0); // TODO
+ case ACCESS_FIELD:
+ assert(0); // TODO
+ case ACCESS_TUPLE:
+ assert(0); // TODO
+ }
+
+ return EVAL_OK;
+}
+
static uintmax_t
itrunc(const struct type *type, uintmax_t val)
{
@@ -510,12 +535,41 @@ eval_struct(struct context *ctx, struct expression *in, struct expression *out)
return EVAL_OK;
}
+static enum eval_result
+eval_unarithm(struct context *ctx, struct expression *in, struct expression *out)
+{
+ struct expression lvalue = {0};
+ enum eval_result r = eval_expr(ctx, in->binarithm.lvalue, &lvalue);
+ if (r != EVAL_OK) {
+ return r;
+ }
+
+ out->type = EXPR_CONSTANT;
+ switch (in->unarithm.op) {
+ case UN_ADDRESS:
+ assert(lvalue.type == EXPR_CONSTANT);
+ assert(lvalue.constant.object);
+ out->result = type_store_lookup_pointer(
+ ctx->store, lvalue.result, 0);
+ out->constant = lvalue.constant;
+ break;
+ case UN_BNOT:
+ case UN_DEREF:
+ case UN_LNOT:
+ case UN_MINUS:
+ case UN_PLUS:
+ assert(0); // TODO
+ }
+
+ return EVAL_OK;
+}
+
enum eval_result
eval_expr(struct context *ctx, struct expression *in, struct expression *out)
{
switch (in->type) {
case EXPR_ACCESS:
- assert(0); // TODO
+ return eval_access(ctx, in, out);
case EXPR_BINARITHM:
return eval_binarithm(ctx, in, out);
case EXPR_CAST:
@@ -528,8 +582,9 @@ eval_expr(struct context *ctx, struct expression *in, struct expression *out)
return eval_struct(ctx, in, out);
case EXPR_SLICE:
case EXPR_TUPLE:
- case EXPR_UNARITHM:
assert(0); // TODO
+ case EXPR_UNARITHM:
+ return eval_unarithm(ctx, in, out);
case EXPR_ALLOC:
case EXPR_APPEND:
case EXPR_ASSERT:
diff --git a/src/gen.c b/src/gen.c
@@ -2599,8 +2599,15 @@ gen_data_item(struct gen_context *ctx, struct expression *expr,
assert(expr->type == EXPR_CONSTANT);
struct qbe_def *def;
- const union expression_constant *constant = &expr->constant;
+ const struct expression_constant *constant = &expr->constant;
const struct type *type = type_dealias(expr->result);
+ if (constant->object) {
+ item->type = QD_SYMOFFS;
+ item->sym = ident_to_sym(&constant->object->ident);
+ item->offset = constant->ival;
+ return item;
+ }
+
switch (type->storage) {
case STORAGE_I8:
case STORAGE_U8:
diff --git a/src/typedef.c b/src/typedef.c
@@ -54,7 +54,8 @@ static void
emit_const(const struct expression *expr, FILE *out)
{
assert(expr->type == EXPR_CONSTANT);
- const union expression_constant *val = &expr->constant;
+ const struct expression_constant *val = &expr->constant;
+ assert(!val->object);
switch (expr->result->storage) {
case STORAGE_BOOL:
fprintf(out, "%s", val->bval ? "false" : "true");