commit 977703eb2a9ef97b18375935fc07cc8594fffc48
parent cb04bf126f6fc918fbb49da08c18ec1f81fa5451
Author: Drew DeVault <sir@cmpwn.com>
Date: Sun, 1 Aug 2021 10:51:36 +0200
gen: struct expressions
Signed-off-by: Drew DeVault <sir@cmpwn.com>
Diffstat:
3 files changed, 94 insertions(+), 2 deletions(-)
diff --git a/include/gen.h b/include/gen.h
@@ -63,6 +63,8 @@ void gen(const struct unit *unit,
// genutil.c
char *gen_name(struct gen_context *ctx, const char *fmt);
+struct gen_value mktemp(struct gen_context *ctx,
+ const struct type *type, const char *fmt);
struct qbe_value mkqval(struct gen_context *ctx, struct gen_value *value);
struct qbe_value mklval(struct gen_context *ctx, struct gen_value *value);
diff --git a/src/gen.c b/src/gen.c
@@ -14,19 +14,49 @@ static const struct gen_value gv_void = {
};
static void
+gen_copy_memcpy(struct gen_context *ctx,
+ struct gen_value dest, struct gen_value src)
+{
+ struct qbe_value rtfunc = {
+ .kind = QV_GLOBAL,
+ .name = strdup("rt.memcpy"),
+ .type = &qbe_long,
+ };
+ struct qbe_value sz = constl(dest.type->size);
+ struct qbe_value dtemp = {
+ .kind = QV_TEMPORARY,
+ .type = ctx->arch.ptr,
+ .name = dest.name,
+ }, stemp = {
+ .kind = QV_TEMPORARY,
+ .type = ctx->arch.ptr,
+ .name = src.name,
+ };
+ pushi(ctx->current, NULL, Q_CALL, &rtfunc,
+ &dtemp, &stemp, &sz, NULL);
+}
+
+static void
gen_store(struct gen_context *ctx,
struct gen_value object,
struct gen_value value)
{
switch (type_dealias(object.type)->storage) {
case STORAGE_ARRAY:
- case STORAGE_ENUM:
case STORAGE_SLICE:
case STORAGE_STRING:
+ assert(0); // TODO
case STORAGE_STRUCT:
+ // TODO: More specific approach
+ gen_copy_memcpy(ctx, object, value);
+ return;
case STORAGE_TAGGED:
case STORAGE_TUPLE:
+ assert(0); // TODO
case STORAGE_UNION:
+ gen_copy_memcpy(ctx, object, value);
+ return;
+ case STORAGE_ENUM:
assert(0); // TODO
default:
break; // no-op
@@ -43,13 +73,14 @@ gen_load(struct gen_context *ctx, struct gen_value object)
{
switch (type_dealias(object.type)->storage) {
case STORAGE_ARRAY:
- case STORAGE_ENUM:
case STORAGE_SLICE:
case STORAGE_STRING:
case STORAGE_STRUCT:
case STORAGE_TAGGED:
case STORAGE_TUPLE:
case STORAGE_UNION:
+ return object;
+ case STORAGE_ENUM:
assert(0); // TODO
default:
break; // no-op
@@ -117,6 +148,8 @@ gen_expr_binding(struct gen_context *ctx, const struct expression *expr)
enum qbe_instr qi = alloc_for_align(type->align);
pushprei(ctx->current, &qv, qi, &sz, NULL);
+ // TODO: We likely want to special-case this to avoid emitting a
+ // copy for every new aggregate binding.
struct gen_value init = gen_expr(ctx, binding->initializer);
gen_store(ctx, gb->value, init);
}
@@ -200,6 +233,51 @@ gen_expr_return(struct gen_context *ctx, const struct expression *expr)
}
static struct gen_value
+gen_expr_struct(struct gen_context *ctx, const struct expression *expr)
+{
+ // TODO: Merge me into constant expressions
+ struct gen_value stemp = mktemp(ctx, expr->result, "struct.%d");
+ struct qbe_value base = mkqval(ctx, &stemp);
+ struct qbe_value sz = constl(expr->result->size);
+ enum qbe_instr ai = alloc_for_align(expr->result->align);
+ pushprei(ctx->current, &base, ai, &sz, NULL);
+
+ if (expr->_struct.autofill) {
+ struct qbe_value rtfunc = {
+ .kind = QV_GLOBAL,
+ .name = strdup("rt.memset"),
+ .type = &qbe_long,
+ };
+ struct qbe_value size =
+ constl(expr->result->size), zero = constl(0);
+ pushi(ctx->current, NULL, Q_CALL, &rtfunc,
+ &base, &zero, &size, NULL);
+ }
+
+ struct gen_value ftemp = mktemp(ctx, &builtin_type_void, "field.%d");
+ for (const struct expr_struct_field *field = &expr->_struct.fields;
+ field; field = field->next) {
+ if (!field->value) {
+ assert(expr->_struct.autofill);
+ field = field->next;
+ continue;
+ }
+
+ // TODO: We likely want to special-case this in the same way as
+ // the comment for gen_expr_binding describes.
+ struct qbe_value offs = constl(field->field->offset);
+ ftemp.type = field->value->result;
+ struct qbe_value ptr = mkqval(ctx, &ftemp);
+ pushi(ctx->current, &ptr, Q_ADD, &base, &offs, NULL);
+
+ struct gen_value init = gen_expr(ctx, field->value);
+ gen_store(ctx, ftemp, init);
+ }
+
+ return stemp;
+}
+
+static struct gen_value
gen_expr(struct gen_context *ctx, const struct expression *expr)
{
switch (expr->type) {
@@ -237,7 +315,9 @@ gen_expr(struct gen_context *ctx, const struct expression *expr)
case EXPR_RETURN:
return gen_expr_return(ctx, expr);
case EXPR_SLICE:
+ assert(0); // TODO
case EXPR_STRUCT:
+ return gen_expr_struct(ctx, expr);
case EXPR_SWITCH:
case EXPR_TUPLE:
case EXPR_UNARITHM:
diff --git a/src/genutil.c b/src/genutil.c
@@ -43,3 +43,13 @@ mklval(struct gen_context *ctx, struct gen_value *value)
qval.type = ctx->arch.ptr;
return qval;
}
+
+struct gen_value
+mktemp(struct gen_context *ctx, const struct type *type, const char *fmt)
+{
+ return (struct gen_value){
+ .kind = GV_TEMP,
+ .type = type,
+ .name = gen_name(ctx, fmt),
+ };
+}