| ... | @@ -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(); |
| 1469 | | 1470 | |
| 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); |
| 1472 | | 1473 | |
| | 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 | }; |
| 1485 | | 1496 | |
| 1486 | const TODO_implement_this = true; // TODO | 1497 | 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 | ); |
| 1495 | | 1612 | |
| 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 | ); |
| 1499 | | 1624 | |
| 1500 | //// The Type memory is ephemeral; since we want to store a longer-lived | 1625 | 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 | }; |
| 1503 | | 1629 | |
| 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; |
| 1506 | | 1649 | |
| 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); |