authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-11-27 19:21:22+02:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-11-30 15:14:33+02:00
log2dcac348e57a2b071270cd3183d3e4f63af4ca7c
treea9561a91f7feffc86d45e5e74c31d62383f27b98
parent1a1a5702abd61bb670b26bfa4a02d0ff7a6cc84b

cbe: implement packed unions


2 files changed, 72 insertions(+), 12 deletions(-)

src/codegen/c.zig+72-11
......@@ -542,9 +542,14 @@ pub const DeclGen = struct {
542542 return dg.renderParentPtr(writer, field_ptr.container_ptr, host_ty);
543543 },
544544 },
545 .Union => FieldInfo{
546 .name = container_ty.unionFields().keys()[index],
547 .ty = container_ty.unionFields().values()[index].ty,
545 .Union => switch (container_ty.containerLayout()) {
546 .Auto, .Extern => FieldInfo{
547 .name = container_ty.unionFields().keys()[index],
548 .ty = container_ty.unionFields().values()[index].ty,
549 },
550 .Packed => {
551 return dg.renderParentPtr(writer, field_ptr.container_ptr, ptr_ty);
552 },
548553 },
549554 .Pointer => field_info: {
550555 assert(container_ty.isSlice());
......@@ -1165,6 +1170,27 @@ pub const DeclGen = struct {
11651170 try writer.writeByte(')');
11661171 }
11671172
1173 const index = ty.unionTagFieldIndex(union_obj.tag, dg.module).?;
1174 const field_ty = ty.unionFields().values()[index].ty;
1175 const field_name = ty.unionFields().keys()[index];
1176 if (ty.containerLayout() == .Packed) {
1177 if (field_ty.hasRuntimeBits()) {
1178 if (field_ty.isPtrAtRuntime()) {
1179 try writer.writeByte('(');
1180 try dg.renderTypecast(writer, ty);
1181 try writer.writeByte(')');
1182 } else if (field_ty.zigTypeTag() == .Float) {
1183 try writer.writeByte('(');
1184 try dg.renderTypecast(writer, ty);
1185 try writer.writeByte(')');
1186 }
1187 try dg.renderValue(writer, field_ty, union_obj.val, .Initializer);
1188 } else {
1189 try writer.writeAll("0");
1190 }
1191 return;
1192 }
1193
11681194 try writer.writeByte('{');
11691195 if (ty.unionTagTypeSafety()) |tag_ty| {
11701196 const layout = ty.unionGetLayout(target);
......@@ -1176,9 +1202,6 @@ pub const DeclGen = struct {
11761202 try writer.writeAll(".payload = {");
11771203 }
11781204
1179 const index = ty.unionTagFieldIndex(union_obj.tag, dg.module).?;
1180 const field_ty = ty.unionFields().values()[index].ty;
1181 const field_name = ty.unionFields().keys()[index];
11821205 var it = ty.unionFields().iterator();
11831206 if (field_ty.hasRuntimeBits()) {
11841207 try writer.print(".{ } = ", .{fmtIdent(field_name)});
......@@ -1794,9 +1817,17 @@ pub const DeclGen = struct {
17941817
17951818 return w.writeAll(name);
17961819 },
1797 .Struct, .Union => |tag| if (tag == .Struct and t.containerLayout() == .Packed)
1798 try dg.renderType(w, t.castTag(.@"struct").?.data.backing_int_ty, kind)
1799 else if (t.isSimpleTupleOrAnonStruct()) {
1820 .Struct, .Union => |tag| if (t.containerLayout() == .Packed) {
1821 if (t.castTag(.@"struct")) |struct_obj| {
1822 try dg.renderType(w, struct_obj.data.backing_int_ty, kind);
1823 } else {
1824 var buf: Type.Payload.Bits = .{
1825 .base = .{ .tag = .int_unsigned },
1826 .data = @intCast(u16, t.bitSize(target)),
1827 };
1828 try dg.renderType(w, Type.initPayload(&buf.base), kind);
1829 }
1830 } else if (t.isSimpleTupleOrAnonStruct()) {
18001831 const ExpectedContents = struct { types: [8]Type, values: [8]Value };
18011832 var stack align(@alignOf(ExpectedContents)) =
18021833 std.heap.stackFallback(@sizeOf(ExpectedContents), dg.gpa);
......@@ -4388,7 +4419,11 @@ fn structFieldPtr(f: *Function, inst: Air.Inst.Index, struct_ptr_ty: Type, struc
43884419 return local;
43894420 } else @as(CValue, CValue.none), // this @as is needed because of a stage1 bug
43904421 },
4391 .@"union", .union_safety_tagged, .union_tagged => .{
4422 .@"union", .union_safety_tagged, .union_tagged => if (struct_ty.containerLayout() == .Packed) {
4423 try f.writeCValue(writer, struct_ptr, .Other);
4424 try writer.writeAll(";\n");
4425 return local;
4426 } else .{
43924427 .identifier = struct_ty.unionFields().keys()[index],
43934428 },
43944429 .tuple, .anon_struct => field_name: {
......@@ -4502,7 +4537,26 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
45024537 return local;
45034538 },
45044539 },
4505 .@"union", .union_safety_tagged, .union_tagged => .{
4540 .@"union", .union_safety_tagged, .union_tagged => if (struct_ty.containerLayout() == .Packed) {
4541 const operand_lval = if (struct_byval == .constant) blk: {
4542 const operand_local = try f.allocLocal(struct_ty, .Const);
4543 try writer.writeAll(" = ");
4544 try f.writeCValue(writer, struct_byval, .Initializer);
4545 try writer.writeAll(";\n");
4546 break :blk operand_local;
4547 } else struct_byval;
4548
4549 const local = try f.allocLocal(inst_ty, .Mut);
4550 try writer.writeAll(";\n");
4551 try writer.writeAll("memcpy(&");
4552 try f.writeCValue(writer, local, .FunctionArgument);
4553 try writer.writeAll(", &");
4554 try f.writeCValue(writer, operand_lval, .FunctionArgument);
4555 try writer.writeAll(", sizeof(");
4556 try f.renderTypecast(writer, inst_ty);
4557 try writer.writeAll("));\n");
4558 return local;
4559 } else .{
45064560 .identifier = struct_ty.unionFields().keys()[extra.field_index],
45074561 },
45084562 .tuple, .anon_struct => blk: {
......@@ -5565,6 +5619,13 @@ fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue {
55655619
55665620 const writer = f.object.writer();
55675621 const local = try f.allocLocal(union_ty, .Const);
5622 if (union_obj.layout == .Packed) {
5623 try writer.writeAll(" = ");
5624 try f.writeCValue(writer, payload, .Initializer);
5625 try writer.writeAll(";\n");
5626 return local;
5627 }
5628
55685629 try writer.writeAll(" = {");
55695630 if (union_ty.unionTagTypeSafety()) |tag_ty| {
55705631 const layout = union_ty.unionGetLayout(target);
test/behavior/union.zig-1
......@@ -1376,7 +1376,6 @@ test "union field ptr - zero sized field" {
13761376
13771377test "packed union in packed struct" {
13781378 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1379 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
13801379 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
13811380 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
13821381 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO