aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2022-03-28 16:20:38 -0700
committerAndrew Kelley <andrew@ziglang.org>2022-03-28 16:27:45 -0700
commitf4a357d7209db61acdfcb24ecec316da66eb318d (patch)
tree4cca3c0a134ceda850bcc23309cda5352774185a /src
parentc546608fcae4e36a593c4ff6c566b864d379e741 (diff)
downloadzig-f4a357d7209db61acdfcb24ecec316da66eb318d.tar.gz
zig-f4a357d7209db61acdfcb24ecec316da66eb318d.zip
stage2: finish debug info for unions in the LLVM backend
Sema: * queue full resolution of std.builtin.Type.Error when doing `@typeInfo` for error sets. LLVM backend: * change a TODO comment to a proper explanation of why debug info for structs is left as a fwd decl sometimes. * remove handling of packed unions which does not match the type information or constant generation code. * remove copy+pasted code * fix union debug info not matching the memory layout * remove unnecessary error checks and type casting
Diffstat (limited to 'src')
-rw-r--r--src/Sema.zig2
-rw-r--r--src/codegen/llvm.zig201
2 files changed, 71 insertions, 132 deletions
diff --git a/src/Sema.zig b/src/Sema.zig
index e79e358907..8842c74ca7 100644
--- a/src/Sema.zig
+++ b/src/Sema.zig
@@ -11091,6 +11091,8 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
break :t try set_field_ty_decl.val.toType(&buffer).copy(fields_anon_decl.arena());
};
+ try sema.queueFullTypeResolution(try error_field_ty.copy(sema.arena));
+
// If the error set is inferred it has to be resolved at this point
try sema.resolveInferredErrorSetTy(block, src, ty);
diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig
index e0fb3103c2..74de485721 100644
--- a/src/codegen/llvm.zig
+++ b/src/codegen/llvm.zig
@@ -1388,8 +1388,13 @@ pub const Object = struct {
if (ty.castTag(.@"struct")) |payload| {
const struct_obj = payload.data;
if (!struct_obj.haveFieldTypes()) {
- // TODO: improve the frontend to populate this struct.
- // For now we treat it as a zero bit type.
+ // This can happen if a struct type makes it all the way to
+ // flush() without ever being instantiated or referenced (even
+ // via pointer). The only reason we are hearing about it now is
+ // that it is being used as a namespace to put other debug types
+ // into. Therefore we can satisfy this by making an empty namespace,
+ // rather than changing the frontend to unnecessarily resolve the
+ // struct field types.
const owner_decl = ty.getOwnerDecl();
const struct_di_ty = try o.makeEmptyNamespaceDIType(owner_decl);
dib.replaceTemporary(fwd_decl, struct_di_ty);
@@ -1471,16 +1476,6 @@ pub const Object = struct {
const name = try ty.nameAlloc(gpa, target);
defer gpa.free(name);
- if (ty.cast(Type.Payload.Union)) |payload| {
- const union_obj = payload.data;
- if (union_obj.layout == .Packed) {
- const bit_size = ty.bitSize(target);
- const di_ty = dib.createBasicType(name, bit_size, DW.ATE.unsigned);
- gop.value_ptr.* = AnnotatedDITypePtr.initFull(di_ty);
- return di_ty;
- }
- }
-
const fwd_decl = opt_fwd_decl orelse blk: {
const fwd_decl = dib.createReplaceableCompositeType(
DW.TAG.structure_type,
@@ -1494,12 +1489,7 @@ pub const Object = struct {
break :blk fwd_decl;
};
- const union_obj = ty.cast(Type.Payload.Union).?.data;
-
- // TODO COPYPASTE >>>
- if (!union_obj.haveFieldTypes()) {
- // TODO: improve the frontend to populate this union.
- // For now we treat it as a zero bit type.
+ if (!ty.hasRuntimeBitsIgnoreComptime()) {
const union_di_ty = try o.makeEmptyNamespaceDIType(owner_decl);
dib.replaceTemporary(fwd_decl, union_di_ty);
// The recursive call to `lowerDebugType` via `makeEmptyNamespaceDIType`
@@ -1507,15 +1497,33 @@ pub const Object = struct {
try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(union_di_ty), .{ .target = o.target });
return union_di_ty;
}
- // TODO <<<
- if (!ty.hasRuntimeBitsIgnoreComptime()) {
- const union_di_ty = try o.makeEmptyNamespaceDIType(owner_decl);
- dib.replaceTemporary(fwd_decl, union_di_ty);
+ const layout = ty.unionGetLayout(target);
+ const union_obj = ty.cast(Type.Payload.Union).?.data;
+
+ if (layout.payload_size == 0) {
+ const tag_di_ty = try o.lowerDebugType(union_obj.tag_ty, .full);
+ const di_fields = [_]*llvm.DIType{tag_di_ty};
+ const full_di_ty = dib.createStructType(
+ compile_unit_scope,
+ name.ptr,
+ null, // file
+ 0, // line
+ ty.abiSize(target) * 8, // size in bits
+ ty.abiAlignment(target) * 8, // align in bits
+ 0, // flags
+ null, // derived from
+ &di_fields,
+ di_fields.len,
+ 0, // run time lang
+ null, // vtable holder
+ "", // unique id
+ );
+ dib.replaceTemporary(fwd_decl, full_di_ty);
// The recursive call to `lowerDebugType` via `makeEmptyNamespaceDIType`
// means we can't use `gop` anymore.
- try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(union_di_ty), .{ .target = o.target });
- return union_di_ty;
+ try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(full_di_ty), .{ .target = o.target });
+ return full_di_ty;
}
var di_fields: std.ArrayListUnmanaged(*llvm.DIType) = .{};
@@ -1523,8 +1531,8 @@ pub const Object = struct {
try di_fields.ensureUnusedCapacity(gpa, union_obj.fields.count());
- var field_iterator = union_obj.fields.iterator();
- while (field_iterator.next()) |kv| {
+ var it = union_obj.fields.iterator();
+ while (it.next()) |kv| {
const field_name = kv.key_ptr.*;
const field = kv.value_ptr.*;
@@ -1536,7 +1544,7 @@ pub const Object = struct {
const field_name_copy = try gpa.dupeZ(u8, field_name);
defer gpa.free(field_name_copy);
- try di_fields.append(gpa, dib.createMemberType(
+ di_fields.appendAssumeCapacity(dib.createMemberType(
fwd_decl.toScope(),
field_name_copy,
null, // file
@@ -1549,31 +1557,11 @@ pub const Object = struct {
));
}
- const tag_ty = union_obj.tag_ty;
- if (!tag_ty.hasRuntimeBitsIgnoreComptime()) {
- const union_di_ty = dib.createUnionType(
- compile_unit_scope,
- name.ptr,
- null, // file
- 0, // line
- ty.abiSize(target) * 8, // size in bits
- ty.abiAlignment(target) * 8, // align in bits
- 0, // flags
- di_fields.items.ptr,
- @intCast(c_int, di_fields.items.len),
- 0, // run time lang
- "", // unique id
- );
-
- dib.replaceTemporary(fwd_decl, union_di_ty);
- // The recursive call to `lowerDebugType` means we can't use `gop` anymore.
- try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(union_di_ty), .{ .target = o.target });
- return union_di_ty;
- }
+ const union_name = if (layout.tag_size == 0) "AnonUnion" else name.ptr;
const union_di_ty = dib.createUnionType(
- fwd_decl.toScope(),
- "AnonUnion",
+ compile_unit_scope,
+ union_name,
null, // file
0, // line
ty.abiSize(target) * 8, // size in bits
@@ -1585,47 +1573,50 @@ pub const Object = struct {
"", // unique id
);
- const payload_size = ty.abiSize(target);
- const payload_align = ty.abiAlignment(target);
- const tag_size = tag_ty.abiSize(target);
- const tag_align = tag_ty.abiAlignment(target);
-
- assert(tag_size > 0);
- assert(tag_align > 0);
+ if (layout.tag_size == 0) {
+ dib.replaceTemporary(fwd_decl, union_di_ty);
+ // The recursive call to `lowerDebugType` means we can't use `gop` anymore.
+ try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(union_di_ty), .{ .target = o.target });
+ return union_di_ty;
+ }
- var offset: u64 = 0;
- offset += payload_size;
- offset = std.mem.alignForwardGeneric(u64, offset, tag_align);
- const tag_offset = offset;
+ var tag_offset: u64 = undefined;
+ var payload_offset: u64 = undefined;
+ if (layout.tag_align >= layout.payload_align) {
+ tag_offset = 0;
+ payload_offset = std.mem.alignForwardGeneric(u64, layout.tag_size, layout.payload_align);
+ } else {
+ payload_offset = 0;
+ tag_offset = std.mem.alignForwardGeneric(u64, layout.payload_size, layout.tag_align);
+ }
- const payload_di = dib.createMemberType(
+ const tag_di = dib.createMemberType(
fwd_decl.toScope(),
- "payload",
+ "tag",
null, // file
0, // line
- payload_size * 8, // size in bits
- payload_align * 8, // align in bits
- 0, // field_offset * 8, // offset in bits
+ layout.tag_size * 8,
+ layout.tag_align * 8, // align in bits
+ tag_offset * 8, // offset in bits
0, // flags
- union_di_ty,
+ try o.lowerDebugType(union_obj.tag_ty, .full),
);
- const tag_di = dib.createMemberType(
+ const payload_di = dib.createMemberType(
fwd_decl.toScope(),
- "tag",
+ "payload",
null, // file
0, // line
- tag_size * 8, // TODO: should this be multiplied by 8??? analyze.cpp:9237
- tag_align * 8, // align in bits
- tag_offset * 8, // offset in bits
+ layout.payload_size * 8, // size in bits
+ layout.payload_align * 8, // align in bits
+ payload_offset * 8, // offset in bits
0, // flags
- try o.lowerDebugType(tag_ty, .full),
+ union_di_ty,
);
- const full_di_fields = [_]*llvm.DIType {
- payload_di,
- tag_di,
- };
+ const full_di_fields: [2]*llvm.DIType =
+ if (layout.tag_align >= layout.payload_align)
+ .{ tag_di, payload_di } else .{ payload_di, tag_di };
const full_di_ty = dib.createStructType(
compile_unit_scope,
@@ -1637,7 +1628,7 @@ pub const Object = struct {
0, // flags
null, // derived from
&full_di_fields,
- @intCast(c_int, full_di_fields.len),
+ full_di_fields.len,
0, // run time lang
null, // vtable holder
"", // unique id
@@ -1646,60 +1637,6 @@ pub const Object = struct {
// The recursive call to `lowerDebugType` means we can't use `gop` anymore.
try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(full_di_ty), .{ .target = o.target });
return full_di_ty;
-
- //if (layout.payload_size == 0) {
- // const enum_tag_llvm_ty = try dg.llvmType(union_obj.tag_ty);
- // gop.value_ptr.* = enum_tag_llvm_ty;
- // return enum_tag_llvm_ty;
- //}
-
- //const name = try union_obj.getFullyQualifiedName(gpa);
- //defer gpa.free(name);
-
- //const llvm_union_ty = dg.context.structCreateNamed(name);
- //gop.value_ptr.* = llvm_union_ty; // must be done before any recursive calls
-
- //const aligned_field = union_obj.fields.values()[layout.most_aligned_field];
- //const llvm_aligned_field_ty = try dg.llvmType(aligned_field.ty);
-
- //const llvm_payload_ty = ty: {
- // if (layout.most_aligned_field_size == layout.payload_size) {
- // break :ty llvm_aligned_field_ty;
- // }
- // const padding_len = @intCast(c_uint, layout.payload_size - layout.most_aligned_field_size);
- // const fields: [2]*const llvm.Type = .{
- // llvm_aligned_field_ty,
- // dg.context.intType(8).arrayType(padding_len),
- // };
- // break :ty dg.context.structType(&fields, fields.len, .True);
- //};
-
- //if (layout.tag_size == 0) {
- // var llvm_fields: [1]*const llvm.Type = .{llvm_payload_ty};
- // llvm_union_ty.structSetBody(&llvm_fields, llvm_fields.len, .False);
- // return llvm_union_ty;
- //}
- //const enum_tag_llvm_ty = try dg.llvmType(union_obj.tag_ty);
-
- //// Put the tag before or after the payload depending on which one's
- //// alignment is greater.
- //var llvm_fields: [3]*const llvm.Type = undefined;
- //var llvm_fields_len: c_uint = 2;
-
- //if (layout.tag_align >= layout.payload_align) {
- // llvm_fields = .{ enum_tag_llvm_ty, llvm_payload_ty, undefined };
- //} else {
- // llvm_fields = .{ llvm_payload_ty, enum_tag_llvm_ty, undefined };
- //}
-
- //// Insert padding to make the LLVM struct ABI size match the Zig union ABI size.
- //if (layout.padding != 0) {
- // llvm_fields[2] = dg.context.intType(8).arrayType(layout.padding);
- // llvm_fields_len = 3;
- //}
-
- //llvm_union_ty.structSetBody(&llvm_fields, llvm_fields_len, .False);
- //return llvm_union_ty;
},
.Fn => {
const fn_info = ty.fnInfo();