aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorlemon <lsof@mailbox.org>2025-10-24 20:30:13 +0200
committerlemon <lsof@mailbox.org>2025-10-24 21:25:31 +0200
commita6693fca1061712db165b9af03008d24a1b7554f (patch)
tree6643dac2cbad1852950c31e1020281ab14f1f3af
parente732643b8640bfdc822e2e4bd994977279b2f58b (diff)
c: bitfield initialzers
-rw-r--r--c/c.c48
-rw-r--r--endian.h43
2 files changed, 73 insertions, 18 deletions
diff --git a/c/c.c b/c/c.c
index fd5da52..377ccc8 100644
--- a/c/c.c
+++ b/c/c.c
@@ -1226,17 +1226,15 @@ expr2reloc(union ref *psym, vlong *paddend, const struct expr *ex)
}
static void
-iniwrite(struct comp *cm, struct initparser *ip, uint off, union type ty, struct expr *ex)
+iniwrite(struct comp *cm, struct initparser *ip, uint off, uint bitsiz, uint bitoff, union type ty, struct expr *ex)
{
uchar *p;
- uint bitsiz, bitoff;
if (ex->ty.t == TYSTRUCT) {
assert(ty.bits == ex->ty.bits);
for (uint i = 0, n = nmemb(ex->ty); i < n; ++i) {
uint suboff;
union type sub = membertype(&suboff, &bitsiz, &bitoff, ex->ty, i);
- assert(!bitsiz);
- iniwrite(cm, ip, off + suboff, sub, &mkexpr(EGETF, ex->span, sub, .sub = ex));
+ iniwrite(cm, ip, off + suboff, bitsiz, bitoff, sub, exprdup(cm, &mkexpr(EGETF, ex->span, sub, .sub = ex)));
}
} else if (ip->ev == EVSTATICINI) {
uint siz = typesize(ty);
@@ -1256,18 +1254,26 @@ iniwrite(struct comp *cm, struct initparser *ip, uint off, union type ty, struct
struct expr *e = ex, tmp;
if (ex->ty.bits != ty.bits && ty.t != TYPTR) {
tmp = mkexpr(ECAST, ex->span, ty, .sub = ex);
- e = &tmp;
+ e = exprdup(cm, &tmp);
eval(e, EVSTATICINI);
assert(e->t == ENUMLIT);
}
- // efmt("#%u' wr %lx at %u\n", ip->dyn?0:ip->off, e->u, off);
- // ioflush(&bstderr);
- switch (siz) {
+ if (!bitsiz) switch (siz) {
default: assert(0);
case 1: *p = e->u; break;
case 2: wr16targ(p, e->u); break;
case 4: isint(ty) ? wr32targ(p, e->u) : wrf32targ(p, e->f); break;
case 8: isint(ty) ? wr64targ(p, e->u) : wrf64targ(p, e->f); break;
+ } else {
+ uvlong mask = (bitsiz == 64 ? -1ull : (1ull << bitsiz) - 1) << bitoff;
+ if (bitoff + bitsiz > siz*8) siz <<= 1; /* straddles an allocation boundary */
+ switch (siz) {
+ default: assert(0);
+ case 1: *p = (*p &~ mask) | (e->u << bitoff & mask); break;
+ case 2: wr16targ(p, (rd16targ(p) &~ mask) | (e->u << bitoff & mask)); break;
+ case 4: wr32targ(p, (rd32targ(p) &~ mask) | (e->u << bitoff & mask)); break;
+ case 8: wr64targ(p, (rd64targ(p) &~ mask) | (e->u << bitoff & mask)); break;
+ }
}
} else if (ty.t == TYARRAY && ex->t == ESTRLIT) {
uint n = ex->s.n * typesize(typechild(ty));
@@ -1296,11 +1302,13 @@ iniwrite(struct comp *cm, struct initparser *ip, uint off, union type ty, struct
struct init *init = ip->init;
struct initval val = {
.off = off,
+ .bitoff = bitoff,
+ .bitsiz = bitsiz,
.ex = *ex
}, *new = alloccopy(&cm->exarena, &val, sizeof val, 0);
*init->tail = new;
init->tail = &new->next;
- for (uint i = off, end = i + typesize(ex->ty); i < end; ++i) {
+ if (!bitsiz) for (uint i = off, end = i + typesize(ex->ty); i < end; ++i) {
if (BSSIZE(end) > arraylength(init->zero)) break;
bsclr(init->zero, i);
}
@@ -1369,7 +1377,6 @@ ininext(struct initparser *ip, struct comp *cm)
Retry:
targ = membertype(&off, &bitsiz, &bitoff, ip->sub->ty, ip->sub->idx);
- assert(!bitsiz);
if (isagg(ip->sub->ty) && targ.t == TYARRAY && !typearrlen(targ)) {
error(&ex.span, "cannot initialize flexible array member");
@@ -1379,7 +1386,7 @@ Retry:
if (ex.t == ESTRLIT && chrarrayof(targ, typechild(ex.ty))) {
assert(!isincomplete(targ));
inistrlit(cm, &ex, &targ);
- iniwrite(cm, ip, ip->sub->off + off, targ, &ex);
+ iniwrite(cm, ip, ip->sub->off + off, 0,0, targ, &ex);
++ip->sub->idx;
return;
} else if (ex.t == ESTRLIT && ip->sub->idx == 0 && chrarrayof(ip->sub->ty, typechild(ex.ty))) {
@@ -1387,7 +1394,7 @@ Retry:
assert(off == 0);
targ = ip->sub->ty;
inistrlit(cm, &ex, &targ);
- iniwrite(cm, ip, ip->sub->off, targ, &ex);
+ iniwrite(cm, ip, ip->sub->off, 0,0, targ, &ex);
if (ip->sub == ip->buf && ip->arrlen < ex.s.n+1)
ip->arrlen = ex.s.n+1;
--ip->sub;
@@ -1423,7 +1430,7 @@ Retry:
ex = mkexpr(ECAST, ex.span, targ, .sub = exprdup(cm, &ex));
pex = exprdup(cm, &ex);
}
- iniwrite(cm, ip, ip->sub->off + off, targ, pex);
+ iniwrite(cm, ip, ip->sub->off + off, bitsiz, bitoff, targ, pex);
}
}
}
@@ -1564,7 +1571,7 @@ initializer(struct comp *cm, union type *ty, enum evalmode ev, bool globl,
struct expr ex = expr(cm);
if (ex.t == ESTRLIT && chrarrayof(*ty, typechild(ex.ty))) {
inistrlit(cm, &ex, ty);
- iniwrite(cm, ip, 0, *ty, &ex);
+ iniwrite(cm, ip, 0, 0, 0, *ty, &ex);
if (ip->dyn)
goto Dynfix;
}
@@ -1574,7 +1581,7 @@ initializer(struct comp *cm, union type *ty, enum evalmode ev, bool globl,
if (ev && !eval(&ex, ev) && ev != EVFOLD)
error(&ex.span, "cannot evaluate expression statically");
else
- iniwrite(cm, ip, 0, *ty, &ex);
+ iniwrite(cm, ip, 0, 0, 0, *ty, &ex);
}
return ex;
}
@@ -2661,6 +2668,9 @@ genstore(struct function *fn, union type t, union ref ptr, union ref val)
return addinstr(fn, ins);
}
+static void genbitfstore(struct function *fn, const union type ty, union ref addr,
+ const struct exgetfld *fld, union ref tmp, union ref val);
+
static void
geninit(struct function *fn, union type t, union ref dst, const struct expr *src)
{
@@ -2694,8 +2704,11 @@ geninit(struct function *fn, union type t, union ref dst, const struct expr *src
geninit(fn, ex->ty, adr, ex);
} else if (isagg(ex->ty)) {
structcopy(fn, ex->ty, adr, expraddr(fn, ex));
- } else {
+ } else if (!val->bitsiz) {
genstore(fn, ex->ty, adr, exprvalue(fn, ex));
+ } else {
+ union ref q = exprvalue(fn, ex);
+ genbitfstore(fn, ex->ty, adr, &(struct exgetfld){0, val->bitsiz, val->bitoff}, NOREF, q);
}
}
} else if (src->t == ESTRLIT) {
@@ -3383,7 +3396,7 @@ deflabel(struct comp *cm, struct function *fn, const struct span *span, const ch
}
}
label->usespan = (struct span){0};
- label->blk = fn->curblk;
+ label->blk = new;
if (!nerror) useblk(fn, new);
} else {
struct label l = { cm->labels, name };
@@ -3759,6 +3772,7 @@ stmt(struct comp *cm, struct function *fn)
if (!label) {
/* create reloc list */
struct label l = { cm->labels, tk.s, fn->curblk, tk.span };
+ assert(l.usespan.ex.len);
cm->labels = alloccopy(fn->arena, &l, sizeof l, 0);
fn->curblk = NULL;
} else if (label && label->usespan.ex.len != 0) {
diff --git a/endian.h b/endian.h
index e1e9740..08ce78f 100644
--- a/endian.h
+++ b/endian.h
@@ -105,7 +105,48 @@ wr64be(uchar *p, uvlong x)
memcpy(p, &x, sizeof x);
}
-/** target-endian memory writes **/
+/** target-endian memory read/write **/
+
+static inline ushort
+rd16targ(uchar *p)
+{
+ ushort x;
+ memcpy(&x, p, sizeof x);
+ if (!hostntarg_sameendian()) x = bswap16(x);
+ return x;
+}
+
+static inline uint
+rd32targ(uchar *p)
+{
+ uint x;
+ memcpy(&x, p, sizeof x);
+ if (!hostntarg_sameendian()) x = bswap16(x);
+ return x;
+}
+
+static inline uvlong
+rd64targ(uchar *p)
+{
+ uvlong x;
+ memcpy(&x, p, sizeof x);
+ if (!hostntarg_sameendian()) x = bswap16(x);
+ return x;
+}
+
+static inline float
+rdf32targ(uchar *p)
+{
+ union { uint i; float f; } u = { rd32targ(p) };
+ return u.f;
+}
+
+static inline double
+rdf64targ(uchar *p)
+{
+ union { uvlong i; double f; } u = { rd64targ(p) };
+ return u.f;
+}
static inline void
wr16targ(uchar *p, ushort x)