cbe: implement packed unions

This commit is contained in:
Veikka Tuominen 2022-11-27 19:21:22 +02:00
parent 1a1a5702ab
commit 2dcac348e5
2 changed files with 72 additions and 12 deletions

View File

@ -542,9 +542,14 @@ pub const DeclGen = struct {
return dg.renderParentPtr(writer, field_ptr.container_ptr, host_ty);
},
},
.Union => FieldInfo{
.name = container_ty.unionFields().keys()[index],
.ty = container_ty.unionFields().values()[index].ty,
.Union => switch (container_ty.containerLayout()) {
.Auto, .Extern => FieldInfo{
.name = container_ty.unionFields().keys()[index],
.ty = container_ty.unionFields().values()[index].ty,
},
.Packed => {
return dg.renderParentPtr(writer, field_ptr.container_ptr, ptr_ty);
},
},
.Pointer => field_info: {
assert(container_ty.isSlice());
@ -1165,6 +1170,27 @@ pub const DeclGen = struct {
try writer.writeByte(')');
}
const index = ty.unionTagFieldIndex(union_obj.tag, dg.module).?;
const field_ty = ty.unionFields().values()[index].ty;
const field_name = ty.unionFields().keys()[index];
if (ty.containerLayout() == .Packed) {
if (field_ty.hasRuntimeBits()) {
if (field_ty.isPtrAtRuntime()) {
try writer.writeByte('(');
try dg.renderTypecast(writer, ty);
try writer.writeByte(')');
} else if (field_ty.zigTypeTag() == .Float) {
try writer.writeByte('(');
try dg.renderTypecast(writer, ty);
try writer.writeByte(')');
}
try dg.renderValue(writer, field_ty, union_obj.val, .Initializer);
} else {
try writer.writeAll("0");
}
return;
}
try writer.writeByte('{');
if (ty.unionTagTypeSafety()) |tag_ty| {
const layout = ty.unionGetLayout(target);
@ -1176,9 +1202,6 @@ pub const DeclGen = struct {
try writer.writeAll(".payload = {");
}
const index = ty.unionTagFieldIndex(union_obj.tag, dg.module).?;
const field_ty = ty.unionFields().values()[index].ty;
const field_name = ty.unionFields().keys()[index];
var it = ty.unionFields().iterator();
if (field_ty.hasRuntimeBits()) {
try writer.print(".{ } = ", .{fmtIdent(field_name)});
@ -1794,9 +1817,17 @@ pub const DeclGen = struct {
return w.writeAll(name);
},
.Struct, .Union => |tag| if (tag == .Struct and t.containerLayout() == .Packed)
try dg.renderType(w, t.castTag(.@"struct").?.data.backing_int_ty, kind)
else if (t.isSimpleTupleOrAnonStruct()) {
.Struct, .Union => |tag| if (t.containerLayout() == .Packed) {
if (t.castTag(.@"struct")) |struct_obj| {
try dg.renderType(w, struct_obj.data.backing_int_ty, kind);
} else {
var buf: Type.Payload.Bits = .{
.base = .{ .tag = .int_unsigned },
.data = @intCast(u16, t.bitSize(target)),
};
try dg.renderType(w, Type.initPayload(&buf.base), kind);
}
} else if (t.isSimpleTupleOrAnonStruct()) {
const ExpectedContents = struct { types: [8]Type, values: [8]Value };
var stack align(@alignOf(ExpectedContents)) =
std.heap.stackFallback(@sizeOf(ExpectedContents), dg.gpa);
@ -4388,7 +4419,11 @@ fn structFieldPtr(f: *Function, inst: Air.Inst.Index, struct_ptr_ty: Type, struc
return local;
} else @as(CValue, CValue.none), // this @as is needed because of a stage1 bug
},
.@"union", .union_safety_tagged, .union_tagged => .{
.@"union", .union_safety_tagged, .union_tagged => if (struct_ty.containerLayout() == .Packed) {
try f.writeCValue(writer, struct_ptr, .Other);
try writer.writeAll(";\n");
return local;
} else .{
.identifier = struct_ty.unionFields().keys()[index],
},
.tuple, .anon_struct => field_name: {
@ -4502,7 +4537,26 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
return local;
},
},
.@"union", .union_safety_tagged, .union_tagged => .{
.@"union", .union_safety_tagged, .union_tagged => if (struct_ty.containerLayout() == .Packed) {
const operand_lval = if (struct_byval == .constant) blk: {
const operand_local = try f.allocLocal(struct_ty, .Const);
try writer.writeAll(" = ");
try f.writeCValue(writer, struct_byval, .Initializer);
try writer.writeAll(";\n");
break :blk operand_local;
} else struct_byval;
const local = try f.allocLocal(inst_ty, .Mut);
try writer.writeAll(";\n");
try writer.writeAll("memcpy(&");
try f.writeCValue(writer, local, .FunctionArgument);
try writer.writeAll(", &");
try f.writeCValue(writer, operand_lval, .FunctionArgument);
try writer.writeAll(", sizeof(");
try f.renderTypecast(writer, inst_ty);
try writer.writeAll("));\n");
return local;
} else .{
.identifier = struct_ty.unionFields().keys()[extra.field_index],
},
.tuple, .anon_struct => blk: {
@ -5565,6 +5619,13 @@ fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue {
const writer = f.object.writer();
const local = try f.allocLocal(union_ty, .Const);
if (union_obj.layout == .Packed) {
try writer.writeAll(" = ");
try f.writeCValue(writer, payload, .Initializer);
try writer.writeAll(";\n");
return local;
}
try writer.writeAll(" = {");
if (union_ty.unionTagTypeSafety()) |tag_ty| {
const layout = union_ty.unionGetLayout(target);

View File

@ -1376,7 +1376,6 @@ test "union field ptr - zero sized field" {
test "packed union in packed struct" {
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO