authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-28 16:20:38-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-28 16:27:45-07:00
logf4a357d7209db61acdfcb24ecec316da66eb318d
tree4cca3c0a134ceda850bcc23309cda5352774185a
parentc546608fcae4e36a593c4ff6c566b864d379e741

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

2 files changed, 71 insertions(+), 132 deletions(-)

src/Sema.zig+2
...@@ -11091,6 +11091,8 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -11091,6 +11091,8 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
11091 break :t try set_field_ty_decl.val.toType(&buffer).copy(fields_anon_decl.arena());11091 break :t try set_field_ty_decl.val.toType(&buffer).copy(fields_anon_decl.arena());
11092 };11092 };
1109311093
11094 try sema.queueFullTypeResolution(try error_field_ty.copy(sema.arena));
11095
11094 // If the error set is inferred it has to be resolved at this point11096 // If the error set is inferred it has to be resolved at this point
11095 try sema.resolveInferredErrorSetTy(block, src, ty);11097 try sema.resolveInferredErrorSetTy(block, src, ty);
1109611098
src/codegen/llvm.zig+69-132
...@@ -1388,8 +1388,13 @@ pub const Object = struct {...@@ -1388,8 +1388,13 @@ pub const Object = struct {
1388 if (ty.castTag(.@"struct")) |payload| {1388 if (ty.castTag(.@"struct")) |payload| {
1389 const struct_obj = payload.data;1389 const struct_obj = payload.data;
1390 if (!struct_obj.haveFieldTypes()) {1390 if (!struct_obj.haveFieldTypes()) {
1391 // TODO: improve the frontend to populate this struct.1391 // This can happen if a struct type makes it all the way to
1392 // For now we treat it as a zero bit type.1392 // flush() without ever being instantiated or referenced (even
1393 // via pointer). The only reason we are hearing about it now is
1394 // that it is being used as a namespace to put other debug types
1395 // into. Therefore we can satisfy this by making an empty namespace,
1396 // rather than changing the frontend to unnecessarily resolve the
1397 // struct field types.
1393 const owner_decl = ty.getOwnerDecl();1398 const owner_decl = ty.getOwnerDecl();
1394 const struct_di_ty = try o.makeEmptyNamespaceDIType(owner_decl);1399 const struct_di_ty = try o.makeEmptyNamespaceDIType(owner_decl);
1395 dib.replaceTemporary(fwd_decl, struct_di_ty);1400 dib.replaceTemporary(fwd_decl, struct_di_ty);
...@@ -1471,16 +1476,6 @@ pub const Object = struct {...@@ -1471,16 +1476,6 @@ pub const Object = struct {
1471 const name = try ty.nameAlloc(gpa, target);1476 const name = try ty.nameAlloc(gpa, target);
1472 defer gpa.free(name);1477 defer gpa.free(name);
14731478
1474 if (ty.cast(Type.Payload.Union)) |payload| {
1475 const union_obj = payload.data;
1476 if (union_obj.layout == .Packed) {
1477 const bit_size = ty.bitSize(target);
1478 const di_ty = dib.createBasicType(name, bit_size, DW.ATE.unsigned);
1479 gop.value_ptr.* = AnnotatedDITypePtr.initFull(di_ty);
1480 return di_ty;
1481 }
1482 }
1483
1484 const fwd_decl = opt_fwd_decl orelse blk: {1479 const fwd_decl = opt_fwd_decl orelse blk: {
1485 const fwd_decl = dib.createReplaceableCompositeType(1480 const fwd_decl = dib.createReplaceableCompositeType(
1486 DW.TAG.structure_type,1481 DW.TAG.structure_type,
...@@ -1494,12 +1489,7 @@ pub const Object = struct {...@@ -1494,12 +1489,7 @@ pub const Object = struct {
1494 break :blk fwd_decl;1489 break :blk fwd_decl;
1495 };1490 };
14961491
1497 const union_obj = ty.cast(Type.Payload.Union).?.data;1492 if (!ty.hasRuntimeBitsIgnoreComptime()) {
1498
1499 // TODO COPYPASTE >>>
1500 if (!union_obj.haveFieldTypes()) {
1501 // TODO: improve the frontend to populate this union.
1502 // For now we treat it as a zero bit type.
1503 const union_di_ty = try o.makeEmptyNamespaceDIType(owner_decl);1493 const union_di_ty = try o.makeEmptyNamespaceDIType(owner_decl);
1504 dib.replaceTemporary(fwd_decl, union_di_ty);1494 dib.replaceTemporary(fwd_decl, union_di_ty);
1505 // The recursive call to `lowerDebugType` via `makeEmptyNamespaceDIType`1495 // The recursive call to `lowerDebugType` via `makeEmptyNamespaceDIType`
...@@ -1507,15 +1497,33 @@ pub const Object = struct {...@@ -1507,15 +1497,33 @@ pub const Object = struct {
1507 try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(union_di_ty), .{ .target = o.target });1497 try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(union_di_ty), .{ .target = o.target });
1508 return union_di_ty;1498 return union_di_ty;
1509 }1499 }
1510 // TODO <<<
15111500
1512 if (!ty.hasRuntimeBitsIgnoreComptime()) {1501 const layout = ty.unionGetLayout(target);
1513 const union_di_ty = try o.makeEmptyNamespaceDIType(owner_decl);1502 const union_obj = ty.cast(Type.Payload.Union).?.data;
1514 dib.replaceTemporary(fwd_decl, union_di_ty);1503
1504 if (layout.payload_size == 0) {
1505 const tag_di_ty = try o.lowerDebugType(union_obj.tag_ty, .full);
1506 const di_fields = [_]*llvm.DIType{tag_di_ty};
1507 const full_di_ty = dib.createStructType(
1508 compile_unit_scope,
1509 name.ptr,
1510 null, // file
1511 0, // line
1512 ty.abiSize(target) * 8, // size in bits
1513 ty.abiAlignment(target) * 8, // align in bits
1514 0, // flags
1515 null, // derived from
1516 &di_fields,
1517 di_fields.len,
1518 0, // run time lang
1519 null, // vtable holder
1520 "", // unique id
1521 );
1522 dib.replaceTemporary(fwd_decl, full_di_ty);
1515 // The recursive call to `lowerDebugType` via `makeEmptyNamespaceDIType`1523 // The recursive call to `lowerDebugType` via `makeEmptyNamespaceDIType`
1516 // means we can't use `gop` anymore.1524 // means we can't use `gop` anymore.
1517 try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(union_di_ty), .{ .target = o.target });1525 try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(full_di_ty), .{ .target = o.target });
1518 return union_di_ty;1526 return full_di_ty;
1519 }1527 }
15201528
1521 var di_fields: std.ArrayListUnmanaged(*llvm.DIType) = .{};1529 var di_fields: std.ArrayListUnmanaged(*llvm.DIType) = .{};
...@@ -1523,8 +1531,8 @@ pub const Object = struct {...@@ -1523,8 +1531,8 @@ pub const Object = struct {
15231531
1524 try di_fields.ensureUnusedCapacity(gpa, union_obj.fields.count());1532 try di_fields.ensureUnusedCapacity(gpa, union_obj.fields.count());
15251533
1526 var field_iterator = union_obj.fields.iterator();1534 var it = union_obj.fields.iterator();
1527 while (field_iterator.next()) |kv| {1535 while (it.next()) |kv| {
1528 const field_name = kv.key_ptr.*;1536 const field_name = kv.key_ptr.*;
1529 const field = kv.value_ptr.*;1537 const field = kv.value_ptr.*;
15301538
...@@ -1536,7 +1544,7 @@ pub const Object = struct {...@@ -1536,7 +1544,7 @@ pub const Object = struct {
1536 const field_name_copy = try gpa.dupeZ(u8, field_name);1544 const field_name_copy = try gpa.dupeZ(u8, field_name);
1537 defer gpa.free(field_name_copy);1545 defer gpa.free(field_name_copy);
15381546
1539 try di_fields.append(gpa, dib.createMemberType(1547 di_fields.appendAssumeCapacity(dib.createMemberType(
1540 fwd_decl.toScope(),1548 fwd_decl.toScope(),
1541 field_name_copy,1549 field_name_copy,
1542 null, // file1550 null, // file
...@@ -1549,31 +1557,11 @@ pub const Object = struct {...@@ -1549,31 +1557,11 @@ pub const Object = struct {
1549 ));1557 ));
1550 }1558 }
15511559
1552 const tag_ty = union_obj.tag_ty;1560 const union_name = if (layout.tag_size == 0) "AnonUnion" else name.ptr;
1553 if (!tag_ty.hasRuntimeBitsIgnoreComptime()) {
1554 const union_di_ty = dib.createUnionType(
1555 compile_unit_scope,
1556 name.ptr,
1557 null, // file
1558 0, // line
1559 ty.abiSize(target) * 8, // size in bits
1560 ty.abiAlignment(target) * 8, // align in bits
1561 0, // flags
1562 di_fields.items.ptr,
1563 @intCast(c_int, di_fields.items.len),
1564 0, // run time lang
1565 "", // unique id
1566 );
1567
1568 dib.replaceTemporary(fwd_decl, union_di_ty);
1569 // The recursive call to `lowerDebugType` means we can't use `gop` anymore.
1570 try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(union_di_ty), .{ .target = o.target });
1571 return union_di_ty;
1572 }
15731561
1574 const union_di_ty = dib.createUnionType(1562 const union_di_ty = dib.createUnionType(
1575 fwd_decl.toScope(),1563 compile_unit_scope,
1576 "AnonUnion",1564 union_name,
1577 null, // file1565 null, // file
1578 0, // line1566 0, // line
1579 ty.abiSize(target) * 8, // size in bits1567 ty.abiSize(target) * 8, // size in bits
...@@ -1585,47 +1573,50 @@ pub const Object = struct {...@@ -1585,47 +1573,50 @@ pub const Object = struct {
1585 "", // unique id1573 "", // unique id
1586 );1574 );
15871575
1588 const payload_size = ty.abiSize(target);1576 if (layout.tag_size == 0) {
1589 const payload_align = ty.abiAlignment(target);1577 dib.replaceTemporary(fwd_decl, union_di_ty);
1590 const tag_size = tag_ty.abiSize(target);1578 // The recursive call to `lowerDebugType` means we can't use `gop` anymore.
1591 const tag_align = tag_ty.abiAlignment(target);1579 try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(union_di_ty), .{ .target = o.target });
15921580 return union_di_ty;
1593 assert(tag_size > 0);1581 }
1594 assert(tag_align > 0);
15951582
1596 var offset: u64 = 0;1583 var tag_offset: u64 = undefined;
1597 offset += payload_size;1584 var payload_offset: u64 = undefined;
1598 offset = std.mem.alignForwardGeneric(u64, offset, tag_align);1585 if (layout.tag_align >= layout.payload_align) {
1599 const tag_offset = offset;1586 tag_offset = 0;
1587 payload_offset = std.mem.alignForwardGeneric(u64, layout.tag_size, layout.payload_align);
1588 } else {
1589 payload_offset = 0;
1590 tag_offset = std.mem.alignForwardGeneric(u64, layout.payload_size, layout.tag_align);
1591 }
16001592
1601 const payload_di = dib.createMemberType(1593 const tag_di = dib.createMemberType(
1602 fwd_decl.toScope(),1594 fwd_decl.toScope(),
1603 "payload",1595 "tag",
1604 null, // file1596 null, // file
1605 0, // line1597 0, // line
1606 payload_size * 8, // size in bits1598 layout.tag_size * 8,
1607 payload_align * 8, // align in bits1599 layout.tag_align * 8, // align in bits
1608 0, // field_offset * 8, // offset in bits1600 tag_offset * 8, // offset in bits
1609 0, // flags1601 0, // flags
1610 union_di_ty,1602 try o.lowerDebugType(union_obj.tag_ty, .full),
1611 );1603 );
16121604
1613 const tag_di = dib.createMemberType(1605 const payload_di = dib.createMemberType(
1614 fwd_decl.toScope(),1606 fwd_decl.toScope(),
1615 "tag",1607 "payload",
1616 null, // file1608 null, // file
1617 0, // line1609 0, // line
1618 tag_size * 8, // TODO: should this be multiplied by 8??? analyze.cpp:92371610 layout.payload_size * 8, // size in bits
1619 tag_align * 8, // align in bits1611 layout.payload_align * 8, // align in bits
1620 tag_offset * 8, // offset in bits1612 payload_offset * 8, // offset in bits
1621 0, // flags1613 0, // flags
1622 try o.lowerDebugType(tag_ty, .full),1614 union_di_ty,
1623 );1615 );
16241616
1625 const full_di_fields = [_]*llvm.DIType {1617 const full_di_fields: [2]*llvm.DIType =
1626 payload_di,1618 if (layout.tag_align >= layout.payload_align)
1627 tag_di,1619 .{ tag_di, payload_di } else .{ payload_di, tag_di };
1628 };
16291620
1630 const full_di_ty = dib.createStructType(1621 const full_di_ty = dib.createStructType(
1631 compile_unit_scope,1622 compile_unit_scope,
...@@ -1637,7 +1628,7 @@ pub const Object = struct {...@@ -1637,7 +1628,7 @@ pub const Object = struct {
1637 0, // flags1628 0, // flags
1638 null, // derived from1629 null, // derived from
1639 &full_di_fields,1630 &full_di_fields,
1640 @intCast(c_int, full_di_fields.len),1631 full_di_fields.len,
1641 0, // run time lang1632 0, // run time lang
1642 null, // vtable holder1633 null, // vtable holder
1643 "", // unique id1634 "", // unique id
...@@ -1646,60 +1637,6 @@ pub const Object = struct {...@@ -1646,60 +1637,6 @@ pub const Object = struct {
1646 // The recursive call to `lowerDebugType` means we can't use `gop` anymore.1637 // The recursive call to `lowerDebugType` means we can't use `gop` anymore.
1647 try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(full_di_ty), .{ .target = o.target });1638 try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(full_di_ty), .{ .target = o.target });
1648 return full_di_ty;1639 return full_di_ty;
1649
1650 //if (layout.payload_size == 0) {
1651 // const enum_tag_llvm_ty = try dg.llvmType(union_obj.tag_ty);
1652 // gop.value_ptr.* = enum_tag_llvm_ty;
1653 // return enum_tag_llvm_ty;
1654 //}
1655
1656 //const name = try union_obj.getFullyQualifiedName(gpa);
1657 //defer gpa.free(name);
1658
1659 //const llvm_union_ty = dg.context.structCreateNamed(name);
1660 //gop.value_ptr.* = llvm_union_ty; // must be done before any recursive calls
1661
1662 //const aligned_field = union_obj.fields.values()[layout.most_aligned_field];
1663 //const llvm_aligned_field_ty = try dg.llvmType(aligned_field.ty);
1664
1665 //const llvm_payload_ty = ty: {
1666 // if (layout.most_aligned_field_size == layout.payload_size) {
1667 // break :ty llvm_aligned_field_ty;
1668 // }
1669 // const padding_len = @intCast(c_uint, layout.payload_size - layout.most_aligned_field_size);
1670 // const fields: [2]*const llvm.Type = .{
1671 // llvm_aligned_field_ty,
1672 // dg.context.intType(8).arrayType(padding_len),
1673 // };
1674 // break :ty dg.context.structType(&fields, fields.len, .True);
1675 //};
1676
1677 //if (layout.tag_size == 0) {
1678 // var llvm_fields: [1]*const llvm.Type = .{llvm_payload_ty};
1679 // llvm_union_ty.structSetBody(&llvm_fields, llvm_fields.len, .False);
1680 // return llvm_union_ty;
1681 //}
1682 //const enum_tag_llvm_ty = try dg.llvmType(union_obj.tag_ty);
1683
1684 //// Put the tag before or after the payload depending on which one's
1685 //// alignment is greater.
1686 //var llvm_fields: [3]*const llvm.Type = undefined;
1687 //var llvm_fields_len: c_uint = 2;
1688
1689 //if (layout.tag_align >= layout.payload_align) {
1690 // llvm_fields = .{ enum_tag_llvm_ty, llvm_payload_ty, undefined };
1691 //} else {
1692 // llvm_fields = .{ llvm_payload_ty, enum_tag_llvm_ty, undefined };
1693 //}
1694
1695 //// Insert padding to make the LLVM struct ABI size match the Zig union ABI size.
1696 //if (layout.padding != 0) {
1697 // llvm_fields[2] = dg.context.intType(8).arrayType(layout.padding);
1698 // llvm_fields_len = 3;
1699 //}
1700
1701 //llvm_union_ty.structSetBody(&llvm_fields, llvm_fields_len, .False);
1702 //return llvm_union_ty;
1703 },1640 },
1704 .Fn => {1641 .Fn => {
1705 const fn_info = ty.fnInfo();1642 const fn_info = ty.fnInfo();