authorgravatar for john.schmidt.h@gmail.comJohn Schmidt <john.schmidt.h@gmail.com> 2022-03-27 14:37:13+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-28 16:24:51-07:00
logc546608fcae4e36a593c4ff6c566b864d379e741
treee7221c19ce276655dd9402fc08f8503969bd2b93
parentb6ccde47adeb0dbd7b39150c36498100e0d98075

stage2: LLVM: (WIP) add union fields debug info


3 files changed, 156 insertions(+), 25 deletions(-)

src/Module.zig+2-14
...@@ -1231,13 +1231,7 @@ pub const Union = struct {...@@ -1231,13 +1231,7 @@ pub const Union = struct {
1231 for (u.fields.values()) |field, i| {1231 for (u.fields.values()) |field, i| {
1232 if (!field.ty.hasRuntimeBits()) continue;1232 if (!field.ty.hasRuntimeBits()) continue;
12331233
1234 const field_align = a: {1234 const field_align = field.normalAlignment(target);
1235 if (field.abi_align == 0) {
1236 break :a field.ty.abiAlignment(target);
1237 } else {
1238 break :a field.abi_align;
1239 }
1240 };
1241 if (field_align > most_alignment) {1235 if (field_align > most_alignment) {
1242 most_alignment = field_align;1236 most_alignment = field_align;
1243 most_index = i;1237 most_index = i;
...@@ -1253,13 +1247,7 @@ pub const Union = struct {...@@ -1253,13 +1247,7 @@ pub const Union = struct {
1253 for (u.fields.values()) |field| {1247 for (u.fields.values()) |field| {
1254 if (!field.ty.hasRuntimeBits()) continue;1248 if (!field.ty.hasRuntimeBits()) continue;
12551249
1256 const field_align = a: {1250 const field_align = field.normalAlignment(target);
1257 if (field.abi_align == 0) {
1258 break :a field.ty.abiAlignment(target);
1259 } else {
1260 break :a field.abi_align;
1261 }
1262 };
1263 max_align = @maximum(max_align, field_align);1251 max_align = @maximum(max_align, field_align);
1264 }1252 }
1265 return max_align;1253 return max_align;
src/codegen/llvm.zig+153-10
...@@ -1465,11 +1465,22 @@ pub const Object = struct {...@@ -1465,11 +1465,22 @@ pub const Object = struct {
1465 return full_di_ty;1465 return full_di_ty;
1466 },1466 },
1467 .Union => {1467 .Union => {
1468 const compile_unit_scope = o.di_compile_unit.?.toScope();
1468 const owner_decl = ty.getOwnerDecl();1469 const owner_decl = ty.getOwnerDecl();
14691470
1470 const name = try ty.nameAlloc(gpa, target);1471 const name = try ty.nameAlloc(gpa, target);
1471 defer gpa.free(name);1472 defer gpa.free(name);
14721473
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
1473 const fwd_decl = opt_fwd_decl orelse blk: {1484 const fwd_decl = opt_fwd_decl orelse blk: {
1474 const fwd_decl = dib.createReplaceableCompositeType(1485 const fwd_decl = dib.createReplaceableCompositeType(
1475 DW.TAG.structure_type,1486 DW.TAG.structure_type,
...@@ -1483,8 +1494,12 @@ pub const Object = struct {...@@ -1483,8 +1494,12 @@ pub const Object = struct {
1483 break :blk fwd_decl;1494 break :blk fwd_decl;
1484 };1495 };
14851496
1486 const TODO_implement_this = true; // TODO1497 const union_obj = ty.cast(Type.Payload.Union).?.data;
1487 if (TODO_implement_this or !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.
1488 const union_di_ty = try o.makeEmptyNamespaceDIType(owner_decl);1503 const union_di_ty = try o.makeEmptyNamespaceDIType(owner_decl);
1489 dib.replaceTemporary(fwd_decl, union_di_ty);1504 dib.replaceTemporary(fwd_decl, union_di_ty);
1490 // The recursive call to `lowerDebugType` via `makeEmptyNamespaceDIType`1505 // The recursive call to `lowerDebugType` via `makeEmptyNamespaceDIType`
...@@ -1492,17 +1507,145 @@ pub const Object = struct {...@@ -1492,17 +1507,145 @@ pub const Object = struct {
1492 try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(union_di_ty), .{ .target = o.target });1507 try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(union_di_ty), .{ .target = o.target });
1493 return union_di_ty;1508 return union_di_ty;
1494 }1509 }
1510 // TODO <<<
1511
1512 if (!ty.hasRuntimeBitsIgnoreComptime()) {
1513 const union_di_ty = try o.makeEmptyNamespaceDIType(owner_decl);
1514 dib.replaceTemporary(fwd_decl, union_di_ty);
1515 // The recursive call to `lowerDebugType` via `makeEmptyNamespaceDIType`
1516 // means we can't use `gop` anymore.
1517 try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(union_di_ty), .{ .target = o.target });
1518 return union_di_ty;
1519 }
1520
1521 var di_fields: std.ArrayListUnmanaged(*llvm.DIType) = .{};
1522 defer di_fields.deinit(gpa);
1523
1524 try di_fields.ensureUnusedCapacity(gpa, union_obj.fields.count());
1525
1526 var field_iterator = union_obj.fields.iterator();
1527 while (field_iterator.next()) |kv| {
1528 const field_name = kv.key_ptr.*;
1529 const field = kv.value_ptr.*;
1530
1531 if (!field.ty.hasRuntimeBitsIgnoreComptime()) continue;
1532
1533 const field_size = field.ty.abiSize(target);
1534 const field_align = field.normalAlignment(target);
1535
1536 const field_name_copy = try gpa.dupeZ(u8, field_name);
1537 defer gpa.free(field_name_copy);
1538
1539 try di_fields.append(gpa, dib.createMemberType(
1540 fwd_decl.toScope(),
1541 field_name_copy,
1542 null, // file
1543 0, // line
1544 field_size * 8, // size in bits
1545 field_align * 8, // align in bits
1546 0, // offset in bits
1547 0, // flags
1548 try o.lowerDebugType(field.ty, .full),
1549 ));
1550 }
1551
1552 const tag_ty = union_obj.tag_ty;
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 }
1573
1574 const union_di_ty = dib.createUnionType(
1575 fwd_decl.toScope(),
1576 "AnonUnion",
1577 null, // file
1578 0, // line
1579 ty.abiSize(target) * 8, // size in bits
1580 ty.abiAlignment(target) * 8, // align in bits
1581 0, // flags
1582 di_fields.items.ptr,
1583 @intCast(c_int, di_fields.items.len),
1584 0, // run time lang
1585 "", // unique id
1586 );
1587
1588 const payload_size = ty.abiSize(target);
1589 const payload_align = ty.abiAlignment(target);
1590 const tag_size = tag_ty.abiSize(target);
1591 const tag_align = tag_ty.abiAlignment(target);
1592
1593 assert(tag_size > 0);
1594 assert(tag_align > 0);
1595
1596 var offset: u64 = 0;
1597 offset += payload_size;
1598 offset = std.mem.alignForwardGeneric(u64, offset, tag_align);
1599 const tag_offset = offset;
1600
1601 const payload_di = dib.createMemberType(
1602 fwd_decl.toScope(),
1603 "payload",
1604 null, // file
1605 0, // line
1606 payload_size * 8, // size in bits
1607 payload_align * 8, // align in bits
1608 0, // field_offset * 8, // offset in bits
1609 0, // flags
1610 union_di_ty,
1611 );
14951612
1496 @panic("TODO debug info type for union");1613 const tag_di = dib.createMemberType(
1497 //const gop = try o.type_map.getOrPut(gpa, ty);1614 fwd_decl.toScope(),
1498 //if (gop.found_existing) return gop.value_ptr.*;1615 "tag",
1616 null, // file
1617 0, // line
1618 tag_size * 8, // TODO: should this be multiplied by 8??? analyze.cpp:9237
1619 tag_align * 8, // align in bits
1620 tag_offset * 8, // offset in bits
1621 0, // flags
1622 try o.lowerDebugType(tag_ty, .full),
1623 );
14991624
1500 //// The Type memory is ephemeral; since we want to store a longer-lived1625 const full_di_fields = [_]*llvm.DIType {
1501 //// reference, we need to copy it here.1626 payload_di,
1502 //gop.key_ptr.* = try ty.copy(o.type_map_arena.allocator());1627 tag_di,
1628 };
15031629
1504 //const layout = ty.unionGetLayout(target);1630 const full_di_ty = dib.createStructType(
1505 //const union_obj = ty.cast(Type.Payload.Union).?.data;1631 compile_unit_scope,
1632 name.ptr,
1633 null, // file
1634 0, // line
1635 ty.abiSize(target) * 8, // size in bits
1636 ty.abiAlignment(target) * 8, // align in bits
1637 0, // flags
1638 null, // derived from
1639 &full_di_fields,
1640 @intCast(c_int, full_di_fields.len),
1641 0, // run time lang
1642 null, // vtable holder
1643 "", // unique id
1644 );
1645 dib.replaceTemporary(fwd_decl, full_di_ty);
1646 // 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 });
1648 return full_di_ty;
15061649
1507 //if (layout.payload_size == 0) {1650 //if (layout.payload_size == 0) {
1508 // const enum_tag_llvm_ty = try dg.llvmType(union_obj.tag_ty);1651 // const enum_tag_llvm_ty = try dg.llvmType(union_obj.tag_ty);
src/codegen/llvm/bindings.zig+1-1
...@@ -1601,7 +1601,7 @@ pub const DIBuilder = opaque {...@@ -1601,7 +1601,7 @@ pub const DIBuilder = opaque {
1601 dib: *DIBuilder,1601 dib: *DIBuilder,
1602 scope: *DIScope,1602 scope: *DIScope,
1603 name: [*:0]const u8,1603 name: [*:0]const u8,
1604 file: *DIFile,1604 file: ?*DIFile,
1605 line_number: c_uint,1605 line_number: c_uint,
1606 size_in_bits: u64,1606 size_in_bits: u64,
1607 align_in_bits: u64,1607 align_in_bits: u64,