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 {...@@ -542,9 +542,14 @@ pub const DeclGen = struct {
542 return dg.renderParentPtr(writer, field_ptr.container_ptr, host_ty);542 return dg.renderParentPtr(writer, field_ptr.container_ptr, host_ty);
543 },543 },
544 },544 },
545 .Union => FieldInfo{545 .Union => switch (container_ty.containerLayout()) {
546 .name = container_ty.unionFields().keys()[index],546 .Auto, .Extern => FieldInfo{
547 .ty = container_ty.unionFields().values()[index].ty,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 },
548 },553 },
549 .Pointer => field_info: {554 .Pointer => field_info: {
550 assert(container_ty.isSlice());555 assert(container_ty.isSlice());
...@@ -1165,6 +1170,27 @@ pub const DeclGen = struct {...@@ -1165,6 +1170,27 @@ pub const DeclGen = struct {
1165 try writer.writeByte(')');1170 try writer.writeByte(')');
1166 }1171 }
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
1168 try writer.writeByte('{');1194 try writer.writeByte('{');
1169 if (ty.unionTagTypeSafety()) |tag_ty| {1195 if (ty.unionTagTypeSafety()) |tag_ty| {
1170 const layout = ty.unionGetLayout(target);1196 const layout = ty.unionGetLayout(target);
...@@ -1176,9 +1202,6 @@ pub const DeclGen = struct {...@@ -1176,9 +1202,6 @@ pub const DeclGen = struct {
1176 try writer.writeAll(".payload = {");1202 try writer.writeAll(".payload = {");
1177 }1203 }
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];
1182 var it = ty.unionFields().iterator();1205 var it = ty.unionFields().iterator();
1183 if (field_ty.hasRuntimeBits()) {1206 if (field_ty.hasRuntimeBits()) {
1184 try writer.print(".{ } = ", .{fmtIdent(field_name)});1207 try writer.print(".{ } = ", .{fmtIdent(field_name)});
...@@ -1794,9 +1817,17 @@ pub const DeclGen = struct {...@@ -1794,9 +1817,17 @@ pub const DeclGen = struct {
17941817
1795 return w.writeAll(name);1818 return w.writeAll(name);
1796 },1819 },
1797 .Struct, .Union => |tag| if (tag == .Struct and t.containerLayout() == .Packed)1820 .Struct, .Union => |tag| if (t.containerLayout() == .Packed) {
1798 try dg.renderType(w, t.castTag(.@"struct").?.data.backing_int_ty, kind)1821 if (t.castTag(.@"struct")) |struct_obj| {
1799 else if (t.isSimpleTupleOrAnonStruct()) {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()) {
1800 const ExpectedContents = struct { types: [8]Type, values: [8]Value };1831 const ExpectedContents = struct { types: [8]Type, values: [8]Value };
1801 var stack align(@alignOf(ExpectedContents)) =1832 var stack align(@alignOf(ExpectedContents)) =
1802 std.heap.stackFallback(@sizeOf(ExpectedContents), dg.gpa);1833 std.heap.stackFallback(@sizeOf(ExpectedContents), dg.gpa);
...@@ -4388,7 +4419,11 @@ fn structFieldPtr(f: *Function, inst: Air.Inst.Index, struct_ptr_ty: Type, struc...@@ -4388,7 +4419,11 @@ fn structFieldPtr(f: *Function, inst: Air.Inst.Index, struct_ptr_ty: Type, struc
4388 return local;4419 return local;
4389 } else @as(CValue, CValue.none), // this @as is needed because of a stage1 bug4420 } else @as(CValue, CValue.none), // this @as is needed because of a stage1 bug
4390 },4421 },
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 .{
4392 .identifier = struct_ty.unionFields().keys()[index],4427 .identifier = struct_ty.unionFields().keys()[index],
4393 },4428 },
4394 .tuple, .anon_struct => field_name: {4429 .tuple, .anon_struct => field_name: {
...@@ -4502,7 +4537,26 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4502,7 +4537,26 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
4502 return local;4537 return local;
4503 },4538 },
4504 },4539 },
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 .{
4506 .identifier = struct_ty.unionFields().keys()[extra.field_index],4560 .identifier = struct_ty.unionFields().keys()[extra.field_index],
4507 },4561 },
4508 .tuple, .anon_struct => blk: {4562 .tuple, .anon_struct => blk: {
...@@ -5565,6 +5619,13 @@ fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5565,6 +5619,13 @@ fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue {
55655619
5566 const writer = f.object.writer();5620 const writer = f.object.writer();
5567 const local = try f.allocLocal(union_ty, .Const);5621 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
5568 try writer.writeAll(" = {");5629 try writer.writeAll(" = {");
5569 if (union_ty.unionTagTypeSafety()) |tag_ty| {5630 if (union_ty.unionTagTypeSafety()) |tag_ty| {
5570 const layout = union_ty.unionGetLayout(target);5631 const layout = union_ty.unionGetLayout(target);
test/behavior/union.zig-1
...@@ -1376,7 +1376,6 @@ test "union field ptr - zero sized field" {...@@ -1376,7 +1376,6 @@ test "union field ptr - zero sized field" {
13761376
1377test "packed union in packed struct" {1377test "packed union in packed struct" {
1378 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO1378 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1379 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
1380 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1379 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1381 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1380 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1382 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO1381 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO