harec

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

commit d640112768a02f3e6df835269877c994f5f4abd0
parent aad6f3700a12f7bb82d3ecc3e3790794a47e2a4a
Author: Drew DeVault <sir@cmpwn.com>
Date:   Mon,  2 Aug 2021 15:50:35 +0200

gen: implement gen_copy_struct

Signed-off-by: Drew DeVault <sir@cmpwn.com>

Diffstat:
Minclude/gen.h | 2++
Msrc/gen.c | 41+++++++++++++++++++++++++++++++++++++++--
Msrc/genutil.c | 13+++++++++++++
3 files changed, 54 insertions(+), 2 deletions(-)

diff --git a/include/gen.h b/include/gen.h @@ -67,6 +67,8 @@ 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); +struct qbe_value mkcopy(struct gen_context *ctx, + struct gen_value *value, const char *fmt); // qinstr.c enum qbe_instr alloc_for_align(size_t align); diff --git a/src/gen.c b/src/gen.c @@ -37,6 +37,44 @@ gen_copy_memcpy(struct gen_context *ctx, } static void +gen_copy_struct(struct gen_context *ctx, + struct gen_value dest, struct gen_value src) +{ + const struct type *stype = type_dealias(dest.type); + assert(stype->storage == STORAGE_STRUCT); + if (stype->size > 128) { + gen_copy_memcpy(ctx, dest, src); + return; + } + enum qbe_instr load, store; + assert(dest.type->align && (dest.type->align & (dest.type->align - 1)) == 0); + switch (dest.type->align) { + case 1: load = Q_LOADUB, store = Q_STOREB; break; + case 2: load = Q_LOADUH, store = Q_STOREH; break; + case 4: load = Q_LOADUW, store = Q_STOREW; break; + default: + assert(dest.type->align == 8); + load = Q_LOADL, store = Q_STOREL; + break; + } + struct qbe_value temp = { + .kind = QV_TEMPORARY, + .type = ctx->arch.ptr, + .name = gen_name(ctx, "item.%d"), + }; + struct qbe_value destp = mkcopy(ctx, &dest, "dest.%d"); + struct qbe_value srcp = mkcopy(ctx, &src, "src.%d"); + struct qbe_value align = constl(dest.type->align); + for (size_t offset = 0; offset < dest.type->size; + offset += dest.type->align) { + pushi(ctx->current, &temp, load, &srcp, NULL); + pushi(ctx->current, NULL, store, &temp, &destp, NULL); + pushi(ctx->current, &srcp, Q_ADD, &srcp, &align, NULL); + pushi(ctx->current, &destp, Q_ADD, &destp, &align, NULL); + } +} + +static void gen_store(struct gen_context *ctx, struct gen_value object, struct gen_value value) @@ -47,8 +85,7 @@ gen_store(struct gen_context *ctx, case STORAGE_STRING: assert(0); // TODO case STORAGE_STRUCT: - // TODO: More specific approach - gen_copy_memcpy(ctx, object, value); + gen_copy_struct(ctx, object, value); return; case STORAGE_TAGGED: case STORAGE_TUPLE: diff --git a/src/genutil.c b/src/genutil.c @@ -44,6 +44,19 @@ mklval(struct gen_context *ctx, struct gen_value *value) return qval; } +struct qbe_value +mkcopy(struct gen_context *ctx, struct gen_value *value, const char *fmt) +{ + struct qbe_value qval = mkqval(ctx, value); + struct qbe_value copy = { + .kind = QV_TEMPORARY, + .type = ctx->arch.ptr, + .name = gen_name(ctx, fmt), + }; + pushi(ctx->current, &copy, Q_COPY, &qval, NULL); + return copy; +} + struct gen_value mktemp(struct gen_context *ctx, const struct type *type, const char *fmt) {