commit df8e73dd8c00a501a3b593bb97730af95321f574
parent 3fd5286ad48412a72fd8adde095d9d1784622ef0
Author: Ryan Sepassi <rsepassi@gmail.com>
Date: Mon, 25 May 2026 15:07:10 -0700
Fix C backend bitfield base addresses
Diffstat:
1 file changed, 45 insertions(+), 1 deletion(-)
diff --git a/src/arch/c_target/emit.c b/src/arch/c_target/emit.c
@@ -2736,13 +2736,57 @@ static const char* c_bf_storage_type(u32 size) {
}
}
+/* Spell an address expression for a backend-addressable lvalue operand.
+ * Unlike c_emit_operand, this never reads the object value; it materializes
+ * the address of the local/global/indirect storage itself. */
+static void c_emit_lvalue_addr_expr_raw(CTarget* t, Operand addr) {
+ char buf[24];
+ SrcLoc loc = t->cur_fn ? t->cur_fn->loc : (SrcLoc){0, 0, 0};
+ switch (addr.kind) {
+ case OPK_LOCAL:
+ cbuf_putc(&t->body, '&');
+ c_slot_name(addr.v.frame_slot, buf, sizeof buf);
+ cbuf_puts(&t->body, buf);
+ return;
+ case OPK_GLOBAL: {
+ obj_sym_mark_referenced(t->obj, addr.v.global.sym);
+ const char* nm = c_sym_name(t, addr.v.global.sym);
+ cbuf_puts(&t->body, "((char*)&");
+ cbuf_puts(&t->body, nm);
+ if (addr.v.global.addend != 0) {
+ cbuf_puts(&t->body, " + ");
+ cbuf_put_i64(&t->body, addr.v.global.addend);
+ }
+ cbuf_putc(&t->body, ')');
+ return;
+ }
+ case OPK_INDIRECT: {
+ CAddrMode m = c_addr_mode(addr);
+ if ((u32)m.base >= t->reg_cap || !t->reg_declared[m.base]) {
+ compiler_panic(t->c, loc,
+ "C target: bitfield on undeclared base reg v%u",
+ (unsigned)m.base);
+ }
+ cbuf_putc(&t->body, '(');
+ c_emit_indirect_addr_expr(t, m);
+ cbuf_putc(&t->body, ')');
+ return;
+ }
+ default:
+ compiler_panic(t->c, loc,
+ "C target: bitfield address on operand kind %d not "
+ "supported",
+ (int)addr.kind);
+ }
+}
+
/* Spell `*(uintN_t*)((char*)addr + bf.storage_offset)` into the body. */
static void c_bf_storage_lvalue(CTarget* t, Operand addr, BitFieldAccess bf,
const char* storage_ty) {
cbuf_puts(&t->body, "(*(");
cbuf_puts(&t->body, storage_ty);
cbuf_puts(&t->body, "*)((char*)");
- c_emit_operand(t, addr);
+ c_emit_lvalue_addr_expr_raw(t, addr);
if (bf.storage_offset != 0) {
cbuf_puts(&t->body, " + ");
cbuf_put_u64(&t->body, (u64)bf.storage_offset);