commit ca87307666e26afeb337c89259f900a34ac09eb3
parent c9ca244381beb97ce49c08eb7c1dacbcb8c79f67
Author: Drew DeVault <sir@cmpwn.com>
Date: Sat, 24 Jul 2021 09:37:05 +0200
gen: implement automatic dereference
Signed-off-by: Drew DeVault <sir@cmpwn.com>
Diffstat:
3 files changed, 46 insertions(+), 2 deletions(-)
diff --git a/src/gen.c b/src/gen.c
@@ -161,6 +161,24 @@ gen_copy(struct gen_context *ctx,
store_temp(ctx, dest, &value);
}
+static void
+auto_deref(struct gen_context *ctx, struct gen_temp *val)
+{
+ const struct type *type = val->type;
+ struct qbe_value qval = {0};
+ qval_temp(ctx, &qval, val);
+ while (type_dealias(type)->storage == STORAGE_POINTER) {
+ type = type_dealias(type)->pointer.referent;
+ // XXX: On some obsolete architectures, uintptr and pointer are
+ // not necessarily the same representation.
+ pushi(ctx->current, &qval,
+ load_for_type(ctx, &builtin_type_uintptr),
+ &qval, NULL);
+ }
+ val->type = type;
+ val->indirect = true;
+}
+
static void gen_expr(struct gen_context *ctx,
const struct expression *expr, const struct gen_temp *out);
@@ -200,15 +218,19 @@ gen_address_field(struct gen_context *ctx, struct gen_temp *temp,
const struct expression *object = access->_struct;
assert(object->type == EXPR_ACCESS); // TODO: Other cases?
+ pushc(ctx->current, "XXX");
+
struct gen_temp base = {0};
struct qbe_value qbase = {0}, field = {0}, offset = {0};
gen_access_address(ctx, &base, object);
+ auto_deref(ctx, &base);
qval_temp(ctx, &qbase, &base);
gen_qtemp(ctx, &field, ctx->arch.ptr, "field.%d");
constl(&offset, access->field->offset);
pushi(ctx->current, &field, Q_ADD, &qbase, &offset, NULL);
temp->name = field.name;
temp->type = access->field->type;
+ temp->indirect = true;
}
static void
@@ -217,12 +239,14 @@ gen_address_index(struct gen_context *ctx, struct gen_temp *temp,
{
assert(access->type == ACCESS_INDEX);
- const struct type *atype = access->array->result;
+ const struct type *atype = type_dereference(access->array->result);
+ assert(atype->storage == STORAGE_ARRAY);
const struct expression *object = access->array;
assert(object->type == EXPR_ACCESS); // TODO: Other cases?
struct gen_temp base = {0};
gen_access_address(ctx, &base, object);
+ auto_deref(ctx, &base);
struct gen_temp index = {0};
gen_direct(ctx, &index, &builtin_type_size, "index.%d");
diff --git a/tests/904-deref.ha b/tests/904-deref.ha
@@ -0,0 +1,18 @@
+type coords = struct { x: int, y: int };
+
+export fn main() int = {
+ let a = coords { x = 10, y = 20 };
+ let b = &a;
+ let c = &b;
+ assert(a.x == 10);
+ assert(b.x == 10);
+ assert(c.x == 10);
+
+ let x = [1, 3, 3, 7];
+ let y = &x;
+ let z = &y;
+ assert(x[2] == 3);
+ assert(y[2] == 3);
+ assert(z[2] == 3);
+ return 0;
+};
diff --git a/tests/configure b/tests/configure
@@ -6,7 +6,9 @@ tests() {
for t in \
900-basics \
901-primitives \
- 902-arithm
+ 902-arithm \
+ 903-call \
+ 904-deref
do
cat <<EOF
tests/$t: tests/$t.ha