| ... | ... | @@ -982,44 +982,36 @@ pub const DeclGen = struct { |
| 982 | 982 | |
| 983 | 983 | try llvm_field_types.ensureUnusedCapacity(gpa, tuple.types.len); |
| 984 | 984 | |
| 985 | | // We need to insert extra padding if LLVM's isn't enough. |
| 986 | | var zig_offset: u64 = 0; |
| 987 | | var llvm_offset: u64 = 0; |
| 988 | | var zig_big_align: u32 = 0; |
| 989 | | var llvm_big_align: u32 = 0; |
| 985 | comptime assert(struct_layout_version == 2); |
| 986 | var offset: u64 = 0; |
| 987 | var big_align: u32 = 0; |
| 990 | 988 | |
| 991 | 989 | for (tuple.types) |field_ty, i| { |
| 992 | 990 | const field_val = tuple.values[i]; |
| 993 | 991 | if (field_val.tag() != .unreachable_value) continue; |
| 994 | 992 | |
| 995 | 993 | const field_align = field_ty.abiAlignment(target); |
| 996 | | zig_big_align = @maximum(zig_big_align, field_align); |
| 997 | | zig_offset = std.mem.alignForwardGeneric(u64, zig_offset, field_align); |
| 994 | big_align = @maximum(big_align, field_align); |
| 995 | const prev_offset = offset; |
| 996 | offset = std.mem.alignForwardGeneric(u64, offset, field_align); |
| 998 | 997 | |
| 999 | | const field_llvm_ty = try dg.llvmType(field_ty); |
| 1000 | | const field_llvm_align = dg.object.target_data.ABIAlignmentOfType(field_llvm_ty); |
| 1001 | | llvm_big_align = @maximum(llvm_big_align, field_llvm_align); |
| 1002 | | llvm_offset = std.mem.alignForwardGeneric(u64, llvm_offset, field_llvm_align); |
| 1003 | | |
| 1004 | | const padding_len = @intCast(c_uint, zig_offset - llvm_offset); |
| 998 | const padding_len = offset - prev_offset; |
| 1005 | 999 | if (padding_len > 0) { |
| 1006 | | const llvm_array_ty = dg.context.intType(8).arrayType(padding_len); |
| 1000 | const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len)); |
| 1007 | 1001 | try llvm_field_types.append(gpa, llvm_array_ty); |
| 1008 | | llvm_offset = zig_offset; |
| 1009 | 1002 | } |
| 1003 | const field_llvm_ty = try dg.llvmType(field_ty); |
| 1010 | 1004 | try llvm_field_types.append(gpa, field_llvm_ty); |
| 1011 | 1005 | |
| 1012 | | llvm_offset += dg.object.target_data.ABISizeOfType(field_llvm_ty); |
| 1013 | | zig_offset += field_ty.abiSize(target); |
| 1006 | offset += field_ty.abiSize(target); |
| 1014 | 1007 | } |
| 1015 | 1008 | { |
| 1016 | | zig_offset = std.mem.alignForwardGeneric(u64, zig_offset, zig_big_align); |
| 1017 | | llvm_offset = std.mem.alignForwardGeneric(u64, llvm_offset, llvm_big_align); |
| 1018 | | const padding_len = @intCast(c_uint, zig_offset - llvm_offset); |
| 1009 | const prev_offset = offset; |
| 1010 | offset = std.mem.alignForwardGeneric(u64, offset, big_align); |
| 1011 | const padding_len = offset - prev_offset; |
| 1019 | 1012 | if (padding_len > 0) { |
| 1020 | | const llvm_array_ty = dg.context.intType(8).arrayType(padding_len); |
| 1013 | const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len)); |
| 1021 | 1014 | try llvm_field_types.append(gpa, llvm_array_ty); |
| 1022 | | llvm_offset = zig_offset; |
| 1023 | 1015 | } |
| 1024 | 1016 | } |
| 1025 | 1017 | |
| ... | ... | @@ -1055,43 +1047,35 @@ pub const DeclGen = struct { |
| 1055 | 1047 | |
| 1056 | 1048 | try llvm_field_types.ensureUnusedCapacity(gpa, struct_obj.fields.count()); |
| 1057 | 1049 | |
| 1058 | | // We need to insert extra padding if LLVM's isn't enough. |
| 1059 | | var zig_offset: u64 = 0; |
| 1060 | | var llvm_offset: u64 = 0; |
| 1061 | | var zig_big_align: u32 = 0; |
| 1062 | | var llvm_big_align: u32 = 0; |
| 1050 | comptime assert(struct_layout_version == 2); |
| 1051 | var offset: u64 = 0; |
| 1052 | var big_align: u32 = 0; |
| 1063 | 1053 | |
| 1064 | 1054 | for (struct_obj.fields.values()) |field| { |
| 1065 | 1055 | if (field.is_comptime or !field.ty.hasRuntimeBits()) continue; |
| 1066 | 1056 | |
| 1067 | 1057 | const field_align = field.normalAlignment(target); |
| 1068 | | zig_big_align = @maximum(zig_big_align, field_align); |
| 1069 | | zig_offset = std.mem.alignForwardGeneric(u64, zig_offset, field_align); |
| 1070 | | |
| 1071 | | const field_llvm_ty = try dg.llvmType(field.ty); |
| 1072 | | const field_llvm_align = dg.object.target_data.ABIAlignmentOfType(field_llvm_ty); |
| 1073 | | llvm_big_align = @maximum(llvm_big_align, field_llvm_align); |
| 1074 | | llvm_offset = std.mem.alignForwardGeneric(u64, llvm_offset, field_llvm_align); |
| 1058 | big_align = @maximum(big_align, field_align); |
| 1059 | const prev_offset = offset; |
| 1060 | offset = std.mem.alignForwardGeneric(u64, offset, field_align); |
| 1075 | 1061 | |
| 1076 | | const padding_len = @intCast(c_uint, zig_offset - llvm_offset); |
| 1062 | const padding_len = offset - prev_offset; |
| 1077 | 1063 | if (padding_len > 0) { |
| 1078 | | const llvm_array_ty = dg.context.intType(8).arrayType(padding_len); |
| 1064 | const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len)); |
| 1079 | 1065 | try llvm_field_types.append(gpa, llvm_array_ty); |
| 1080 | | llvm_offset = zig_offset; |
| 1081 | 1066 | } |
| 1067 | const field_llvm_ty = try dg.llvmType(field.ty); |
| 1082 | 1068 | try llvm_field_types.append(gpa, field_llvm_ty); |
| 1083 | 1069 | |
| 1084 | | llvm_offset += dg.object.target_data.ABISizeOfType(field_llvm_ty); |
| 1085 | | zig_offset += field.ty.abiSize(target); |
| 1070 | offset += field.ty.abiSize(target); |
| 1086 | 1071 | } |
| 1087 | 1072 | { |
| 1088 | | zig_offset = std.mem.alignForwardGeneric(u64, zig_offset, zig_big_align); |
| 1089 | | llvm_offset = std.mem.alignForwardGeneric(u64, llvm_offset, llvm_big_align); |
| 1090 | | const padding_len = @intCast(c_uint, zig_offset - llvm_offset); |
| 1073 | const prev_offset = offset; |
| 1074 | offset = std.mem.alignForwardGeneric(u64, offset, big_align); |
| 1075 | const padding_len = offset - prev_offset; |
| 1091 | 1076 | if (padding_len > 0) { |
| 1092 | | const llvm_array_ty = dg.context.intType(8).arrayType(padding_len); |
| 1077 | const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len)); |
| 1093 | 1078 | try llvm_field_types.append(gpa, llvm_array_ty); |
| 1094 | | llvm_offset = zig_offset; |
| 1095 | 1079 | } |
| 1096 | 1080 | } |
| 1097 | 1081 | |
| ... | ... | @@ -1111,71 +1095,61 @@ pub const DeclGen = struct { |
| 1111 | 1095 | // reference, we need to copy it here. |
| 1112 | 1096 | gop.key_ptr.* = try t.copy(dg.object.type_map_arena.allocator()); |
| 1113 | 1097 | |
| 1098 | const layout = t.unionGetLayout(target); |
| 1114 | 1099 | const union_obj = t.cast(Type.Payload.Union).?.data; |
| 1115 | | if (t.unionTagType()) |enum_tag_ty| { |
| 1116 | | const layout = union_obj.getLayout(target, true); |
| 1117 | 1100 | |
| 1118 | | if (layout.payload_size == 0) { |
| 1119 | | const enum_tag_llvm_ty = try dg.llvmType(enum_tag_ty); |
| 1120 | | gop.value_ptr.* = enum_tag_llvm_ty; |
| 1121 | | return enum_tag_llvm_ty; |
| 1122 | | } |
| 1101 | if (layout.payload_size == 0) { |
| 1102 | const enum_tag_llvm_ty = try dg.llvmType(union_obj.tag_ty); |
| 1103 | gop.value_ptr.* = enum_tag_llvm_ty; |
| 1104 | return enum_tag_llvm_ty; |
| 1105 | } |
| 1123 | 1106 | |
| 1124 | | const name = try union_obj.getFullyQualifiedName(gpa); |
| 1125 | | defer gpa.free(name); |
| 1107 | const name = try union_obj.getFullyQualifiedName(gpa); |
| 1108 | defer gpa.free(name); |
| 1126 | 1109 | |
| 1127 | | const llvm_union_ty = dg.context.structCreateNamed(name); |
| 1128 | | gop.value_ptr.* = llvm_union_ty; // must be done before any recursive calls |
| 1110 | const llvm_union_ty = dg.context.structCreateNamed(name); |
| 1111 | gop.value_ptr.* = llvm_union_ty; // must be done before any recursive calls |
| 1129 | 1112 | |
| 1130 | | const aligned_field = union_obj.fields.values()[layout.most_aligned_field]; |
| 1131 | | const llvm_aligned_field_ty = try dg.llvmType(aligned_field.ty); |
| 1113 | const aligned_field = union_obj.fields.values()[layout.most_aligned_field]; |
| 1114 | const llvm_aligned_field_ty = try dg.llvmType(aligned_field.ty); |
| 1132 | 1115 | |
| 1133 | | const llvm_payload_ty = t: { |
| 1134 | | if (layout.most_aligned_field_size == layout.payload_size) { |
| 1135 | | break :t llvm_aligned_field_ty; |
| 1136 | | } |
| 1137 | | const padding_len = @intCast(c_uint, layout.payload_size - layout.most_aligned_field_size); |
| 1138 | | const fields: [2]*const llvm.Type = .{ |
| 1139 | | llvm_aligned_field_ty, |
| 1140 | | dg.context.intType(8).arrayType(padding_len), |
| 1141 | | }; |
| 1142 | | break :t dg.context.structType(&fields, fields.len, .True); |
| 1116 | const llvm_payload_ty = t: { |
| 1117 | if (layout.most_aligned_field_size == layout.payload_size) { |
| 1118 | break :t llvm_aligned_field_ty; |
| 1119 | } |
| 1120 | const padding_len = @intCast(c_uint, layout.payload_size - layout.most_aligned_field_size); |
| 1121 | const fields: [2]*const llvm.Type = .{ |
| 1122 | llvm_aligned_field_ty, |
| 1123 | dg.context.intType(8).arrayType(padding_len), |
| 1143 | 1124 | }; |
| 1125 | break :t dg.context.structType(&fields, fields.len, .True); |
| 1126 | }; |
| 1144 | 1127 | |
| 1145 | | if (layout.tag_size == 0) { |
| 1146 | | var llvm_fields: [1]*const llvm.Type = .{llvm_payload_ty}; |
| 1147 | | llvm_union_ty.structSetBody(&llvm_fields, llvm_fields.len, .False); |
| 1148 | | return llvm_union_ty; |
| 1149 | | } |
| 1150 | | const enum_tag_llvm_ty = try dg.llvmType(enum_tag_ty); |
| 1151 | | |
| 1152 | | // Put the tag before or after the payload depending on which one's |
| 1153 | | // alignment is greater. |
| 1154 | | var llvm_fields: [2]*const llvm.Type = undefined; |
| 1155 | | if (layout.tag_align >= layout.payload_align) { |
| 1156 | | llvm_fields[0] = enum_tag_llvm_ty; |
| 1157 | | llvm_fields[1] = llvm_payload_ty; |
| 1158 | | } else { |
| 1159 | | llvm_fields[0] = llvm_payload_ty; |
| 1160 | | llvm_fields[1] = enum_tag_llvm_ty; |
| 1161 | | } |
| 1128 | if (layout.tag_size == 0) { |
| 1129 | var llvm_fields: [1]*const llvm.Type = .{llvm_payload_ty}; |
| 1162 | 1130 | llvm_union_ty.structSetBody(&llvm_fields, llvm_fields.len, .False); |
| 1163 | 1131 | return llvm_union_ty; |
| 1164 | 1132 | } |
| 1165 | | // Untagged union |
| 1166 | | const layout = union_obj.getLayout(target, false); |
| 1133 | const enum_tag_llvm_ty = try dg.llvmType(union_obj.tag_ty); |
| 1167 | 1134 | |
| 1168 | | const name = try union_obj.getFullyQualifiedName(gpa); |
| 1169 | | defer gpa.free(name); |
| 1135 | // Put the tag before or after the payload depending on which one's |
| 1136 | // alignment is greater. |
| 1137 | var llvm_fields: [3]*const llvm.Type = undefined; |
| 1138 | var llvm_fields_len: c_uint = 2; |
| 1170 | 1139 | |
| 1171 | | const llvm_union_ty = dg.context.structCreateNamed(name); |
| 1172 | | gop.value_ptr.* = llvm_union_ty; // must be done before any recursive calls |
| 1140 | if (layout.tag_align >= layout.payload_align) { |
| 1141 | llvm_fields = .{ enum_tag_llvm_ty, llvm_payload_ty, undefined }; |
| 1142 | } else { |
| 1143 | llvm_fields = .{ llvm_payload_ty, enum_tag_llvm_ty, undefined }; |
| 1144 | } |
| 1173 | 1145 | |
| 1174 | | const big_field = union_obj.fields.values()[layout.biggest_field]; |
| 1175 | | const llvm_big_field_ty = try dg.llvmType(big_field.ty); |
| 1146 | // Insert padding to make the LLVM struct ABI size match the Zig union ABI size. |
| 1147 | if (layout.padding != 0) { |
| 1148 | llvm_fields[2] = dg.context.intType(8).arrayType(layout.padding); |
| 1149 | llvm_fields_len = 3; |
| 1150 | } |
| 1176 | 1151 | |
| 1177 | | var llvm_fields: [1]*const llvm.Type = .{llvm_big_field_ty}; |
| 1178 | | llvm_union_ty.structSetBody(&llvm_fields, llvm_fields.len, .False); |
| 1152 | llvm_union_ty.structSetBody(&llvm_fields, llvm_fields_len, .False); |
| 1179 | 1153 | return llvm_union_ty; |
| 1180 | 1154 | }, |
| 1181 | 1155 | .Fn => { |
| ... | ... | @@ -1586,33 +1560,25 @@ pub const DeclGen = struct { |
| 1586 | 1560 | var llvm_fields = try std.ArrayListUnmanaged(*const llvm.Value).initCapacity(gpa, llvm_field_count); |
| 1587 | 1561 | defer llvm_fields.deinit(gpa); |
| 1588 | 1562 | |
| 1589 | | // These are used to detect where the extra padding fields are so that we |
| 1590 | | // can initialize them with undefined. |
| 1591 | | var zig_offset: u64 = 0; |
| 1592 | | var llvm_offset: u64 = 0; |
| 1593 | | var zig_big_align: u32 = 0; |
| 1594 | | var llvm_big_align: u32 = 0; |
| 1563 | comptime assert(struct_layout_version == 2); |
| 1564 | var offset: u64 = 0; |
| 1565 | var big_align: u32 = 0; |
| 1595 | 1566 | |
| 1596 | 1567 | var need_unnamed = false; |
| 1597 | 1568 | for (struct_obj.fields.values()) |field, i| { |
| 1598 | 1569 | if (field.is_comptime or !field.ty.hasRuntimeBits()) continue; |
| 1599 | 1570 | |
| 1600 | 1571 | const field_align = field.normalAlignment(target); |
| 1601 | | zig_big_align = @maximum(zig_big_align, field_align); |
| 1602 | | zig_offset = std.mem.alignForwardGeneric(u64, zig_offset, field_align); |
| 1603 | | |
| 1604 | | const field_llvm_ty = try dg.llvmType(field.ty); |
| 1605 | | const field_llvm_align = dg.object.target_data.ABIAlignmentOfType(field_llvm_ty); |
| 1606 | | llvm_big_align = @maximum(llvm_big_align, field_llvm_align); |
| 1607 | | llvm_offset = std.mem.alignForwardGeneric(u64, llvm_offset, field_llvm_align); |
| 1572 | big_align = @maximum(big_align, field_align); |
| 1573 | const prev_offset = offset; |
| 1574 | offset = std.mem.alignForwardGeneric(u64, offset, field_align); |
| 1608 | 1575 | |
| 1609 | | const padding_len = @intCast(c_uint, zig_offset - llvm_offset); |
| 1576 | const padding_len = offset - prev_offset; |
| 1610 | 1577 | if (padding_len > 0) { |
| 1611 | | const llvm_array_ty = dg.context.intType(8).arrayType(padding_len); |
| 1578 | const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len)); |
| 1612 | 1579 | // TODO make this and all other padding elsewhere in debug |
| 1613 | 1580 | // builds be 0xaa not undef. |
| 1614 | 1581 | llvm_fields.appendAssumeCapacity(llvm_array_ty.getUndef()); |
| 1615 | | llvm_offset = zig_offset; |
| 1616 | 1582 | } |
| 1617 | 1583 | |
| 1618 | 1584 | const field_llvm_val = try dg.genTypedValue(.{ |
| ... | ... | @@ -1624,17 +1590,15 @@ pub const DeclGen = struct { |
| 1624 | 1590 | |
| 1625 | 1591 | llvm_fields.appendAssumeCapacity(field_llvm_val); |
| 1626 | 1592 | |
| 1627 | | llvm_offset += dg.object.target_data.ABISizeOfType(field_llvm_ty); |
| 1628 | | zig_offset += field.ty.abiSize(target); |
| 1593 | offset += field.ty.abiSize(target); |
| 1629 | 1594 | } |
| 1630 | 1595 | { |
| 1631 | | zig_offset = std.mem.alignForwardGeneric(u64, zig_offset, zig_big_align); |
| 1632 | | llvm_offset = std.mem.alignForwardGeneric(u64, llvm_offset, llvm_big_align); |
| 1633 | | const padding_len = @intCast(c_uint, zig_offset - llvm_offset); |
| 1596 | const prev_offset = offset; |
| 1597 | offset = std.mem.alignForwardGeneric(u64, offset, big_align); |
| 1598 | const padding_len = offset - prev_offset; |
| 1634 | 1599 | if (padding_len > 0) { |
| 1635 | | const llvm_array_ty = dg.context.intType(8).arrayType(padding_len); |
| 1600 | const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len)); |
| 1636 | 1601 | llvm_fields.appendAssumeCapacity(llvm_array_ty.getUndef()); |
| 1637 | | llvm_offset = zig_offset; |
| 1638 | 1602 | } |
| 1639 | 1603 | } |
| 1640 | 1604 | |
| ... | ... | @@ -1703,16 +1667,21 @@ pub const DeclGen = struct { |
| 1703 | 1667 | .ty = tv.ty.unionTagType().?, |
| 1704 | 1668 | .val = tag_and_val.tag, |
| 1705 | 1669 | }); |
| 1706 | | var fields: [2]*const llvm.Value = undefined; |
| 1670 | var fields: [3]*const llvm.Value = undefined; |
| 1671 | var fields_len: c_uint = 2; |
| 1707 | 1672 | if (layout.tag_align >= layout.payload_align) { |
| 1708 | | fields = .{ llvm_tag_value, payload }; |
| 1673 | fields = .{ llvm_tag_value, payload, undefined }; |
| 1709 | 1674 | } else { |
| 1710 | | fields = .{ payload, llvm_tag_value }; |
| 1675 | fields = .{ payload, llvm_tag_value, undefined }; |
| 1676 | } |
| 1677 | if (layout.padding != 0) { |
| 1678 | fields[2] = dg.context.intType(8).arrayType(layout.padding).getUndef(); |
| 1679 | fields_len = 3; |
| 1711 | 1680 | } |
| 1712 | 1681 | if (need_unnamed) { |
| 1713 | | return dg.context.constStruct(&fields, fields.len, .False); |
| 1682 | return dg.context.constStruct(&fields, fields_len, .False); |
| 1714 | 1683 | } else { |
| 1715 | | return llvm_union_ty.constNamedStruct(&fields, fields.len); |
| 1684 | return llvm_union_ty.constNamedStruct(&fields, fields_len); |
| 1716 | 1685 | } |
| 1717 | 1686 | }, |
| 1718 | 1687 | .Vector => switch (tv.val.tag()) { |
| ... | ... | @@ -1867,7 +1836,7 @@ pub const DeclGen = struct { |
| 1867 | 1836 | }, |
| 1868 | 1837 | .Struct => { |
| 1869 | 1838 | var ty_buf: Type.Payload.Pointer = undefined; |
| 1870 | | const llvm_field_index = dg.llvmFieldIndex(parent.ty, field_index, &ty_buf).?; |
| 1839 | const llvm_field_index = llvmFieldIndex(parent.ty, field_index, target, &ty_buf).?; |
| 1871 | 1840 | const indices: [2]*const llvm.Value = .{ |
| 1872 | 1841 | llvm_u32.constInt(0, .False), |
| 1873 | 1842 | llvm_u32.constInt(llvm_field_index, .False), |
| ... | ... | @@ -2098,107 +2067,6 @@ pub const DeclGen = struct { |
| 2098 | 2067 | return null; |
| 2099 | 2068 | } |
| 2100 | 2069 | } |
| 2101 | | |
| 2102 | | /// Take into account 0 bit fields and padding. Returns null if an llvm |
| 2103 | | /// field could not be found. |
| 2104 | | /// This only happens if you want the field index of a zero sized field at |
| 2105 | | /// the end of the struct. |
| 2106 | | fn llvmFieldIndex( |
| 2107 | | dg: *DeclGen, |
| 2108 | | ty: Type, |
| 2109 | | field_index: usize, |
| 2110 | | ptr_pl_buf: *Type.Payload.Pointer, |
| 2111 | | ) ?c_uint { |
| 2112 | | const target = dg.module.getTarget(); |
| 2113 | | |
| 2114 | | // Detects where we inserted extra padding fields so that we can skip |
| 2115 | | // over them in this function. |
| 2116 | | var zig_offset: u64 = 0; |
| 2117 | | var llvm_offset: u64 = 0; |
| 2118 | | var zig_big_align: u32 = 0; |
| 2119 | | var llvm_big_align: u32 = 0; |
| 2120 | | |
| 2121 | | if (ty.isTupleOrAnonStruct()) { |
| 2122 | | const tuple = ty.tupleFields(); |
| 2123 | | var llvm_field_index: c_uint = 0; |
| 2124 | | for (tuple.types) |field_ty, i| { |
| 2125 | | if (tuple.values[i].tag() != .unreachable_value) continue; |
| 2126 | | |
| 2127 | | const field_align = field_ty.abiAlignment(target); |
| 2128 | | zig_big_align = @maximum(zig_big_align, field_align); |
| 2129 | | zig_offset = std.mem.alignForwardGeneric(u64, zig_offset, field_align); |
| 2130 | | |
| 2131 | | // assert no error because we have already seen a successful |
| 2132 | | // llvmType on this field. |
| 2133 | | const field_llvm_ty = dg.llvmType(field_ty) catch unreachable; |
| 2134 | | const field_llvm_align = dg.object.target_data.ABIAlignmentOfType(field_llvm_ty); |
| 2135 | | llvm_big_align = @maximum(llvm_big_align, field_llvm_align); |
| 2136 | | llvm_offset = std.mem.alignForwardGeneric(u64, llvm_offset, field_llvm_align); |
| 2137 | | |
| 2138 | | const padding_len = @intCast(c_uint, zig_offset - llvm_offset); |
| 2139 | | if (padding_len > 0) { |
| 2140 | | llvm_field_index += 1; |
| 2141 | | llvm_offset = zig_offset; |
| 2142 | | } |
| 2143 | | |
| 2144 | | if (field_index == i) { |
| 2145 | | ptr_pl_buf.* = .{ |
| 2146 | | .data = .{ |
| 2147 | | .pointee_type = field_ty, |
| 2148 | | .@"align" = field_align, |
| 2149 | | .@"addrspace" = .generic, |
| 2150 | | }, |
| 2151 | | }; |
| 2152 | | return llvm_field_index; |
| 2153 | | } |
| 2154 | | |
| 2155 | | llvm_field_index += 1; |
| 2156 | | llvm_offset += dg.object.target_data.ABISizeOfType(field_llvm_ty); |
| 2157 | | zig_offset += field_ty.abiSize(target); |
| 2158 | | } |
| 2159 | | return null; |
| 2160 | | } |
| 2161 | | assert(ty.containerLayout() != .Packed); |
| 2162 | | |
| 2163 | | var llvm_field_index: c_uint = 0; |
| 2164 | | for (ty.structFields().values()) |field, i| { |
| 2165 | | if (field.is_comptime or !field.ty.hasRuntimeBits()) continue; |
| 2166 | | |
| 2167 | | const field_align = field.normalAlignment(target); |
| 2168 | | zig_big_align = @maximum(zig_big_align, field_align); |
| 2169 | | zig_offset = std.mem.alignForwardGeneric(u64, zig_offset, field_align); |
| 2170 | | |
| 2171 | | // assert no error because we have already seen a successful llvmType on this field. |
| 2172 | | const field_llvm_ty = dg.llvmType(field.ty) catch unreachable; |
| 2173 | | const field_llvm_align = dg.object.target_data.ABIAlignmentOfType(field_llvm_ty); |
| 2174 | | llvm_big_align = @maximum(llvm_big_align, field_llvm_align); |
| 2175 | | llvm_offset = std.mem.alignForwardGeneric(u64, llvm_offset, field_llvm_align); |
| 2176 | | |
| 2177 | | const padding_len = @intCast(c_uint, zig_offset - llvm_offset); |
| 2178 | | if (padding_len > 0) { |
| 2179 | | llvm_field_index += 1; |
| 2180 | | llvm_offset = zig_offset; |
| 2181 | | } |
| 2182 | | |
| 2183 | | if (field_index == i) { |
| 2184 | | ptr_pl_buf.* = .{ |
| 2185 | | .data = .{ |
| 2186 | | .pointee_type = field.ty, |
| 2187 | | .@"align" = field_align, |
| 2188 | | .@"addrspace" = .generic, |
| 2189 | | }, |
| 2190 | | }; |
| 2191 | | return llvm_field_index; |
| 2192 | | } |
| 2193 | | |
| 2194 | | llvm_field_index += 1; |
| 2195 | | llvm_offset += dg.object.target_data.ABISizeOfType(field_llvm_ty); |
| 2196 | | zig_offset += field.ty.abiSize(target); |
| 2197 | | } else { |
| 2198 | | // We did not find an llvm field that corresponds to this zig field. |
| 2199 | | return null; |
| 2200 | | } |
| 2201 | | } |
| 2202 | 2070 | }; |
| 2203 | 2071 | |
| 2204 | 2072 | pub const FuncGen = struct { |
| ... | ... | @@ -2807,7 +2675,13 @@ pub const FuncGen = struct { |
| 2807 | 2675 | const cond = try self.resolveInst(pl_op.operand); |
| 2808 | 2676 | const switch_br = self.air.extraData(Air.SwitchBr, pl_op.payload); |
| 2809 | 2677 | const else_block = self.context.appendBasicBlock(self.llvm_func, "Else"); |
| 2810 | | const llvm_switch = self.builder.buildSwitch(cond, else_block, switch_br.data.cases_len); |
| 2678 | const target = self.dg.module.getTarget(); |
| 2679 | const llvm_usize = self.context.intType(target.cpu.arch.ptrBitWidth()); |
| 2680 | const cond_int = if (cond.typeOf().getTypeKind() == .Pointer) |
| 2681 | self.builder.buildPtrToInt(cond, llvm_usize, "") |
| 2682 | else |
| 2683 | cond; |
| 2684 | const llvm_switch = self.builder.buildSwitch(cond_int, else_block, switch_br.data.cases_len); |
| 2811 | 2685 | |
| 2812 | 2686 | var extra_index: usize = switch_br.end; |
| 2813 | 2687 | var case_i: u32 = 0; |
| ... | ... | @@ -2822,7 +2696,11 @@ pub const FuncGen = struct { |
| 2822 | 2696 | |
| 2823 | 2697 | for (items) |item| { |
| 2824 | 2698 | const llvm_item = try self.resolveInst(item); |
| 2825 | | llvm_switch.addCase(llvm_item, case_block); |
| 2699 | const llvm_int_item = if (llvm_item.typeOf().getTypeKind() == .Pointer) |
| 2700 | llvm_item.constPtrToInt(llvm_usize) |
| 2701 | else |
| 2702 | llvm_item; |
| 2703 | llvm_switch.addCase(llvm_int_item, case_block); |
| 2826 | 2704 | } |
| 2827 | 2705 | |
| 2828 | 2706 | self.builder.positionBuilderAtEnd(case_block); |
| ... | ... | @@ -3077,7 +2955,7 @@ pub const FuncGen = struct { |
| 3077 | 2955 | }, |
| 3078 | 2956 | else => { |
| 3079 | 2957 | var ptr_ty_buf: Type.Payload.Pointer = undefined; |
| 3080 | | const llvm_field_index = self.dg.llvmFieldIndex(struct_ty, field_index, &ptr_ty_buf).?; |
| 2958 | const llvm_field_index = llvmFieldIndex(struct_ty, field_index, target, &ptr_ty_buf).?; |
| 3081 | 2959 | return self.builder.buildExtractValue(struct_llvm_val, llvm_field_index, ""); |
| 3082 | 2960 | }, |
| 3083 | 2961 | }, |
| ... | ... | @@ -3092,7 +2970,7 @@ pub const FuncGen = struct { |
| 3092 | 2970 | .Struct => { |
| 3093 | 2971 | assert(struct_ty.containerLayout() != .Packed); |
| 3094 | 2972 | var ptr_ty_buf: Type.Payload.Pointer = undefined; |
| 3095 | | const llvm_field_index = self.dg.llvmFieldIndex(struct_ty, field_index, &ptr_ty_buf).?; |
| 2973 | const llvm_field_index = llvmFieldIndex(struct_ty, field_index, target, &ptr_ty_buf).?; |
| 3096 | 2974 | const field_ptr = self.builder.buildStructGEP(struct_llvm_val, llvm_field_index, ""); |
| 3097 | 2975 | const field_ptr_ty = Type.initPayload(&ptr_ty_buf.base); |
| 3098 | 2976 | return self.load(field_ptr, field_ptr_ty); |
| ... | ... | @@ -4907,6 +4785,7 @@ pub const FuncGen = struct { |
| 4907 | 4785 | const len = @intCast(usize, result_ty.arrayLen()); |
| 4908 | 4786 | const elements = @bitCast([]const Air.Inst.Ref, self.air.extra[ty_pl.payload..][0..len]); |
| 4909 | 4787 | const llvm_result_ty = try self.dg.llvmType(result_ty); |
| 4788 | const target = self.dg.module.getTarget(); |
| 4910 | 4789 | |
| 4911 | 4790 | switch (result_ty.zigTypeTag()) { |
| 4912 | 4791 | .Vector => { |
| ... | ... | @@ -4928,7 +4807,6 @@ pub const FuncGen = struct { |
| 4928 | 4807 | const alloca_inst = self.buildAlloca(llvm_result_ty); |
| 4929 | 4808 | // TODO in debug builds init to undef so that the padding will be 0xaa |
| 4930 | 4809 | // even if we fully populate the fields. |
| 4931 | | const target = self.dg.module.getTarget(); |
| 4932 | 4810 | alloca_inst.setAlignment(result_ty.abiAlignment(target)); |
| 4933 | 4811 | |
| 4934 | 4812 | var indices: [2]*const llvm.Value = .{ llvm_u32.constNull(), undefined }; |
| ... | ... | @@ -4936,7 +4814,7 @@ pub const FuncGen = struct { |
| 4936 | 4814 | if (result_ty.structFieldValueComptime(i) != null) continue; |
| 4937 | 4815 | |
| 4938 | 4816 | const llvm_elem = try self.resolveInst(elem); |
| 4939 | | const llvm_i = self.dg.llvmFieldIndex(result_ty, i, &ptr_ty_buf).?; |
| 4817 | const llvm_i = llvmFieldIndex(result_ty, i, target, &ptr_ty_buf).?; |
| 4940 | 4818 | indices[1] = llvm_u32.constInt(llvm_i, .False); |
| 4941 | 4819 | const field_ptr = self.builder.buildInBoundsGEP(alloca_inst, &indices, indices.len, ""); |
| 4942 | 4820 | const store_inst = self.builder.buildStore(llvm_elem, field_ptr); |
| ... | ... | @@ -4950,7 +4828,7 @@ pub const FuncGen = struct { |
| 4950 | 4828 | if (result_ty.structFieldValueComptime(i) != null) continue; |
| 4951 | 4829 | |
| 4952 | 4830 | const llvm_elem = try self.resolveInst(elem); |
| 4953 | | const llvm_i = self.dg.llvmFieldIndex(result_ty, i, &ptr_ty_buf).?; |
| 4831 | const llvm_i = llvmFieldIndex(result_ty, i, target, &ptr_ty_buf).?; |
| 4954 | 4832 | result = self.builder.buildInsertValue(result, llvm_elem, llvm_i, ""); |
| 4955 | 4833 | } |
| 4956 | 4834 | return result; |
| ... | ... | @@ -4960,7 +4838,6 @@ pub const FuncGen = struct { |
| 4960 | 4838 | assert(isByRef(result_ty)); |
| 4961 | 4839 | |
| 4962 | 4840 | const llvm_usize = try self.dg.llvmType(Type.usize); |
| 4963 | | const target = self.dg.module.getTarget(); |
| 4964 | 4841 | const alloca_inst = self.buildAlloca(llvm_result_ty); |
| 4965 | 4842 | alloca_inst.setAlignment(result_ty.abiAlignment(target)); |
| 4966 | 4843 | |
| ... | ... | @@ -5033,13 +4910,18 @@ pub const FuncGen = struct { |
| 5033 | 4910 | const fields: [1]*const llvm.Type = .{payload}; |
| 5034 | 4911 | break :t self.context.structType(&fields, fields.len, .False); |
| 5035 | 4912 | } |
| 5036 | | var fields: [2]*const llvm.Type = undefined; |
| 4913 | var fields: [3]*const llvm.Type = undefined; |
| 4914 | var fields_len: c_uint = 2; |
| 5037 | 4915 | if (layout.tag_align >= layout.payload_align) { |
| 5038 | | fields = .{ tag_llvm_ty, payload }; |
| 4916 | fields = .{ tag_llvm_ty, payload, undefined }; |
| 5039 | 4917 | } else { |
| 5040 | | fields = .{ payload, tag_llvm_ty }; |
| 4918 | fields = .{ payload, tag_llvm_ty, undefined }; |
| 4919 | } |
| 4920 | if (layout.padding != 0) { |
| 4921 | fields[2] = self.context.intType(8).arrayType(layout.padding); |
| 4922 | fields_len = 3; |
| 5041 | 4923 | } |
| 5042 | | break :t self.context.structType(&fields, fields.len, .False); |
| 4924 | break :t self.context.structType(&fields, fields_len, .False); |
| 5043 | 4925 | }; |
| 5044 | 4926 | |
| 5045 | 4927 | const casted_ptr = self.builder.buildBitCast(result_ptr, llvm_union_ty.pointerType(0), ""); |
| ... | ... | @@ -5255,8 +5137,9 @@ pub const FuncGen = struct { |
| 5255 | 5137 | return self.builder.buildBitCast(struct_ptr, result_llvm_ty, ""); |
| 5256 | 5138 | }, |
| 5257 | 5139 | else => { |
| 5140 | const target = self.dg.module.getTarget(); |
| 5258 | 5141 | var ty_buf: Type.Payload.Pointer = undefined; |
| 5259 | | if (self.dg.llvmFieldIndex(struct_ty, field_index, &ty_buf)) |llvm_field_index| { |
| 5142 | if (llvmFieldIndex(struct_ty, field_index, target, &ty_buf)) |llvm_field_index| { |
| 5260 | 5143 | return self.builder.buildStructGEP(struct_ptr, llvm_field_index, ""); |
| 5261 | 5144 | } else { |
| 5262 | 5145 | // If we found no index then this means this is a zero sized field at the |
| ... | ... | @@ -5667,6 +5550,88 @@ fn toLlvmCallConv(cc: std.builtin.CallingConvention, target: std.Target) llvm.Ca |
| 5667 | 5550 | }; |
| 5668 | 5551 | } |
| 5669 | 5552 | |
| 5553 | /// Take into account 0 bit fields and padding. Returns null if an llvm |
| 5554 | /// field could not be found. |
| 5555 | /// This only happens if you want the field index of a zero sized field at |
| 5556 | /// the end of the struct. |
| 5557 | fn llvmFieldIndex( |
| 5558 | ty: Type, |
| 5559 | field_index: usize, |
| 5560 | target: std.Target, |
| 5561 | ptr_pl_buf: *Type.Payload.Pointer, |
| 5562 | ) ?c_uint { |
| 5563 | // Detects where we inserted extra padding fields so that we can skip |
| 5564 | // over them in this function. |
| 5565 | comptime assert(struct_layout_version == 2); |
| 5566 | var offset: u64 = 0; |
| 5567 | var big_align: u32 = 0; |
| 5568 | |
| 5569 | if (ty.isTupleOrAnonStruct()) { |
| 5570 | const tuple = ty.tupleFields(); |
| 5571 | var llvm_field_index: c_uint = 0; |
| 5572 | for (tuple.types) |field_ty, i| { |
| 5573 | if (tuple.values[i].tag() != .unreachable_value) continue; |
| 5574 | |
| 5575 | const field_align = field_ty.abiAlignment(target); |
| 5576 | big_align = @maximum(big_align, field_align); |
| 5577 | const prev_offset = offset; |
| 5578 | offset = std.mem.alignForwardGeneric(u64, offset, field_align); |
| 5579 | |
| 5580 | const padding_len = offset - prev_offset; |
| 5581 | if (padding_len > 0) { |
| 5582 | llvm_field_index += 1; |
| 5583 | } |
| 5584 | |
| 5585 | if (field_index == i) { |
| 5586 | ptr_pl_buf.* = .{ |
| 5587 | .data = .{ |
| 5588 | .pointee_type = field_ty, |
| 5589 | .@"align" = field_align, |
| 5590 | .@"addrspace" = .generic, |
| 5591 | }, |
| 5592 | }; |
| 5593 | return llvm_field_index; |
| 5594 | } |
| 5595 | |
| 5596 | llvm_field_index += 1; |
| 5597 | offset += field_ty.abiSize(target); |
| 5598 | } |
| 5599 | return null; |
| 5600 | } |
| 5601 | assert(ty.containerLayout() != .Packed); |
| 5602 | |
| 5603 | var llvm_field_index: c_uint = 0; |
| 5604 | for (ty.structFields().values()) |field, i| { |
| 5605 | if (field.is_comptime or !field.ty.hasRuntimeBits()) continue; |
| 5606 | |
| 5607 | const field_align = field.normalAlignment(target); |
| 5608 | big_align = @maximum(big_align, field_align); |
| 5609 | const prev_offset = offset; |
| 5610 | offset = std.mem.alignForwardGeneric(u64, offset, field_align); |
| 5611 | |
| 5612 | const padding_len = offset - prev_offset; |
| 5613 | if (padding_len > 0) { |
| 5614 | llvm_field_index += 1; |
| 5615 | } |
| 5616 | |
| 5617 | if (field_index == i) { |
| 5618 | ptr_pl_buf.* = .{ |
| 5619 | .data = .{ |
| 5620 | .pointee_type = field.ty, |
| 5621 | .@"align" = field_align, |
| 5622 | .@"addrspace" = .generic, |
| 5623 | }, |
| 5624 | }; |
| 5625 | return llvm_field_index; |
| 5626 | } |
| 5627 | |
| 5628 | llvm_field_index += 1; |
| 5629 | offset += field.ty.abiSize(target); |
| 5630 | } else { |
| 5631 | // We did not find an llvm field that corresponds to this zig field. |
| 5632 | return null; |
| 5633 | } |
| 5634 | } |
| 5670 | 5635 | fn firstParamSRet(fn_info: Type.Payload.Function.Data, target: std.Target) bool { |
| 5671 | 5636 | switch (fn_info.cc) { |
| 5672 | 5637 | .Unspecified, .Inline => return isByRef(fn_info.return_type), |
| ... | ... | @@ -5757,3 +5722,12 @@ fn backendSupportsF80(target: std.Target) bool { |
| 5757 | 5722 | else => false, |
| 5758 | 5723 | }; |
| 5759 | 5724 | } |
| 5725 | |
| 5726 | /// We need to insert extra padding if LLVM's isn't enough. |
| 5727 | /// However we don't want to ever call LLVMABIAlignmentOfType or |
| 5728 | /// LLVMABISizeOfType because these functions will trip assertions |
| 5729 | /// when using them for self-referential types. So our strategy is |
| 5730 | /// to use non-packed llvm structs but to emit all padding explicitly. |
| 5731 | /// We can do this because for all types, Zig ABI alignment >= LLVM ABI |
| 5732 | /// alignment. |
| 5733 | const struct_layout_version = 2; |