authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-12-23 23:57:02-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-12-23 23:57:02-07:00
log5b171f446f46c97de111bce0575452be0334a05e
treec3ce543696892a846f21241863c07c62f2fcf7f2
parent3763580e1e734b558499df5512f6a165f6db988b

stage2: initial implementation of packed structs

Layout algorithm: all `align(0)` fields are squished together as if they were a single integer with a number of bits equal to `@bitSizeOf` each field added together. Then the natural ABI alignment of that integer is used for that pseudo-field.

7 files changed, 737 insertions(+), 292 deletions(-)

src/Module.zig+18
......@@ -849,6 +849,24 @@ pub const Struct = struct {
849849 /// undefined until `status` is `have_layout`.
850850 offset: u32,
851851 is_comptime: bool,
852
853 /// Returns the field alignment, assuming the struct is packed.
854 pub fn packedAlignment(field: Field) u32 {
855 if (field.abi_align.tag() == .abi_align_default) {
856 return 0;
857 } else {
858 return @intCast(u32, field.abi_align.toUnsignedInt());
859 }
860 }
861
862 /// Returns the field alignment, assuming the struct is not packed.
863 pub fn normalAlignment(field: Field, target: Target) u32 {
864 if (field.abi_align.tag() == .abi_align_default) {
865 return field.ty.abiAlignment(target);
866 } else {
867 return @intCast(u32, field.abi_align.toUnsignedInt());
868 }
869 }
852870 };
853871
854872 pub fn getFullyQualifiedName(s: *Struct, gpa: Allocator) ![:0]u8 {
src/Sema.zig+52-2
......@@ -12125,11 +12125,61 @@ fn structFieldPtr(
1212512125 return sema.failWithBadStructFieldAccess(block, struct_obj, field_name_src, field_name);
1212612126 const field_index = @intCast(u32, field_index_big);
1212712127 const field = struct_obj.fields.values()[field_index];
12128 const ptr_field_ty = try Type.ptr(arena, .{
12128
12129 var ptr_ty_data: Type.Payload.Pointer.Data = .{
1212912130 .pointee_type = field.ty,
1213012131 .mutable = struct_ptr_ty.ptrIsMutable(),
1213112132 .@"addrspace" = struct_ptr_ty.ptrAddressSpace(),
12132 });
12133 };
12134 // TODO handle when the struct pointer is overaligned, we should return a potentially
12135 // over-aligned field pointer too.
12136 if (struct_obj.layout == .Packed) p: {
12137 const target = sema.mod.getTarget();
12138 comptime assert(Type.packed_struct_layout_version == 1);
12139
12140 var offset: u64 = 0;
12141 var running_bits: u16 = 0;
12142 for (struct_obj.fields.values()) |f, i| {
12143 if (!f.ty.hasCodeGenBits()) continue;
12144
12145 const field_align = f.packedAlignment();
12146 if (field_align == 0) {
12147 if (i == field_index) {
12148 ptr_ty_data.bit_offset = running_bits;
12149 }
12150 running_bits += @intCast(u16, f.ty.bitSize(target));
12151 } else {
12152 if (running_bits != 0) {
12153 var int_payload: Type.Payload.Bits = .{
12154 .base = .{ .tag = .int_unsigned },
12155 .data = running_bits,
12156 };
12157 const int_ty: Type = .{ .ptr_otherwise = &int_payload.base };
12158 if (i > field_index) {
12159 ptr_ty_data.host_size = @intCast(u16, int_ty.abiSize(target));
12160 break :p;
12161 }
12162 const int_align = int_ty.abiAlignment(target);
12163 offset = std.mem.alignForwardGeneric(u64, offset, int_align);
12164 offset += int_ty.abiSize(target);
12165 running_bits = 0;
12166 }
12167 offset = std.mem.alignForwardGeneric(u64, offset, field_align);
12168 if (i == field_index) {
12169 break :p;
12170 }
12171 offset += f.ty.abiSize(target);
12172 }
12173 }
12174 assert(running_bits != 0);
12175 var int_payload: Type.Payload.Bits = .{
12176 .base = .{ .tag = .int_unsigned },
12177 .data = running_bits,
12178 };
12179 const int_ty: Type = .{ .ptr_otherwise = &int_payload.base };
12180 ptr_ty_data.host_size = @intCast(u16, int_ty.abiSize(target));
12181 }
12182 const ptr_field_ty = try Type.ptr(arena, ptr_ty_data);
1213312183
1213412184 if (try sema.resolveDefinedValue(block, src, struct_ptr)) |struct_ptr_val| {
1213512185 return sema.addConstant(
src/codegen/llvm.zig+403-115
......@@ -844,15 +844,77 @@ pub const DeclGen = struct {
844844 var llvm_field_types = try std.ArrayListUnmanaged(*const llvm.Type).initCapacity(gpa, struct_obj.fields.count());
845845 defer llvm_field_types.deinit(gpa);
846846
847 for (struct_obj.fields.values()) |field| {
848 if (!field.ty.hasCodeGenBits()) continue;
849 llvm_field_types.appendAssumeCapacity(try dg.llvmType(field.ty));
847 if (struct_obj.layout == .Packed) {
848 const target = dg.module.getTarget();
849 comptime assert(Type.packed_struct_layout_version == 1);
850 var offset: u64 = 0;
851 var running_bits: u16 = 0;
852 for (struct_obj.fields.values()) |field| {
853 if (!field.ty.hasCodeGenBits()) continue;
854
855 const field_align = field.packedAlignment();
856 if (field_align == 0) {
857 running_bits += @intCast(u16, field.ty.bitSize(target));
858 } else {
859 if (running_bits != 0) {
860 var int_payload: Type.Payload.Bits = .{
861 .base = .{ .tag = .int_unsigned },
862 .data = running_bits,
863 };
864 const int_ty: Type = .{ .ptr_otherwise = &int_payload.base };
865 const int_align = int_ty.abiAlignment(target);
866 const llvm_int_ty = try dg.llvmType(int_ty);
867 const prev_offset = offset;
868 offset = std.mem.alignForwardGeneric(u64, offset, int_align);
869 const padding_bytes = @intCast(c_uint, offset - prev_offset);
870 if (padding_bytes != 0) {
871 const padding = dg.context.intType(8).arrayType(padding_bytes);
872 llvm_field_types.appendAssumeCapacity(padding);
873 }
874 llvm_field_types.appendAssumeCapacity(llvm_int_ty);
875 offset += int_ty.abiSize(target);
876 running_bits = 0;
877 }
878 const prev_offset = offset;
879 offset = std.mem.alignForwardGeneric(u64, offset, field_align);
880 const padding_bytes = @intCast(c_uint, offset - prev_offset);
881 if (padding_bytes != 0) {
882 const padding = dg.context.intType(8).arrayType(padding_bytes);
883 llvm_field_types.appendAssumeCapacity(padding);
884 }
885 llvm_field_types.appendAssumeCapacity(try dg.llvmType(field.ty));
886 offset += field.ty.abiSize(target);
887 }
888 }
889
890 if (running_bits != 0) {
891 var int_payload: Type.Payload.Bits = .{
892 .base = .{ .tag = .int_unsigned },
893 .data = running_bits,
894 };
895 const int_ty: Type = .{ .ptr_otherwise = &int_payload.base };
896 const int_align = int_ty.abiAlignment(target);
897 const prev_offset = offset;
898 offset = std.mem.alignForwardGeneric(u64, offset, int_align);
899 const padding_bytes = @intCast(c_uint, offset - prev_offset);
900 if (padding_bytes != 0) {
901 const padding = dg.context.intType(8).arrayType(padding_bytes);
902 llvm_field_types.appendAssumeCapacity(padding);
903 }
904 const llvm_int_ty = try dg.llvmType(int_ty);
905 llvm_field_types.appendAssumeCapacity(llvm_int_ty);
906 }
907 } else {
908 for (struct_obj.fields.values()) |field| {
909 if (!field.ty.hasCodeGenBits()) continue;
910 llvm_field_types.appendAssumeCapacity(try dg.llvmType(field.ty));
911 }
850912 }
851913
852914 llvm_struct_ty.structSetBody(
853915 llvm_field_types.items.ptr,
854916 @intCast(c_uint, llvm_field_types.items.len),
855 llvm.Bool.fromBool(struct_obj.layout == .Packed),
917 .False,
856918 );
857919
858920 return llvm_struct_ty;
......@@ -980,23 +1042,23 @@ pub const DeclGen = struct {
9801042 }
9811043 }
9821044
983 fn genTypedValue(self: *DeclGen, tv: TypedValue) Error!*const llvm.Value {
1045 fn genTypedValue(dg: *DeclGen, tv: TypedValue) Error!*const llvm.Value {
9841046 if (tv.val.isUndef()) {
985 const llvm_type = try self.llvmType(tv.ty);
1047 const llvm_type = try dg.llvmType(tv.ty);
9861048 return llvm_type.getUndef();
9871049 }
9881050
9891051 switch (tv.ty.zigTypeTag()) {
9901052 .Bool => {
991 const llvm_type = try self.llvmType(tv.ty);
1053 const llvm_type = try dg.llvmType(tv.ty);
9921054 return if (tv.val.toBool()) llvm_type.constAllOnes() else llvm_type.constNull();
9931055 },
9941056 .Int => {
9951057 var bigint_space: Value.BigIntSpace = undefined;
9961058 const bigint = tv.val.toBigInt(&bigint_space);
997 const target = self.module.getTarget();
1059 const target = dg.module.getTarget();
9981060 const int_info = tv.ty.intInfo(target);
999 const llvm_type = self.context.intType(int_info.bits);
1061 const llvm_type = dg.context.intType(int_info.bits);
10001062
10011063 const unsigned_val = v: {
10021064 if (bigint.limbs.len == 1) {
......@@ -1022,9 +1084,9 @@ pub const DeclGen = struct {
10221084 var bigint_space: Value.BigIntSpace = undefined;
10231085 const bigint = int_val.toBigInt(&bigint_space);
10241086
1025 const target = self.module.getTarget();
1087 const target = dg.module.getTarget();
10261088 const int_info = tv.ty.intInfo(target);
1027 const llvm_type = self.context.intType(int_info.bits);
1089 const llvm_type = dg.context.intType(int_info.bits);
10281090
10291091 const unsigned_val = v: {
10301092 if (bigint.limbs.len == 1) {
......@@ -1044,8 +1106,8 @@ pub const DeclGen = struct {
10441106 return unsigned_val;
10451107 },
10461108 .Float => {
1047 const llvm_ty = try self.llvmType(tv.ty);
1048 if (tv.ty.floatBits(self.module.getTarget()) <= 64) {
1109 const llvm_ty = try dg.llvmType(tv.ty);
1110 if (tv.ty.floatBits(dg.module.getTarget()) <= 64) {
10491111 return llvm_ty.constReal(tv.val.toFloat(f64));
10501112 }
10511113
......@@ -1056,18 +1118,18 @@ pub const DeclGen = struct {
10561118 std.mem.swap(u64, &buf[0], &buf[1]);
10571119 }
10581120
1059 const int = self.context.intType(128).constIntOfArbitraryPrecision(buf.len, &buf);
1121 const int = dg.context.intType(128).constIntOfArbitraryPrecision(buf.len, &buf);
10601122 return int.constBitCast(llvm_ty);
10611123 },
10621124 .Pointer => switch (tv.val.tag()) {
1063 .decl_ref_mut => return lowerDeclRefValue(self, tv, tv.val.castTag(.decl_ref_mut).?.data.decl),
1064 .decl_ref => return lowerDeclRefValue(self, tv, tv.val.castTag(.decl_ref).?.data),
1125 .decl_ref_mut => return lowerDeclRefValue(dg, tv, tv.val.castTag(.decl_ref_mut).?.data.decl),
1126 .decl_ref => return lowerDeclRefValue(dg, tv, tv.val.castTag(.decl_ref).?.data),
10651127 .variable => {
10661128 const decl = tv.val.castTag(.variable).?.data.owner_decl;
10671129 decl.alive = true;
1068 const val = try self.resolveGlobalDecl(decl);
1069 const llvm_var_type = try self.llvmType(tv.ty);
1070 const llvm_addrspace = self.llvmAddressSpace(decl.@"addrspace");
1130 const val = try dg.resolveGlobalDecl(decl);
1131 const llvm_var_type = try dg.llvmType(tv.ty);
1132 const llvm_addrspace = dg.llvmAddressSpace(decl.@"addrspace");
10711133 const llvm_type = llvm_var_type.pointerType(llvm_addrspace);
10721134 return val.constBitCast(llvm_type);
10731135 },
......@@ -1075,26 +1137,26 @@ pub const DeclGen = struct {
10751137 const slice = tv.val.castTag(.slice).?.data;
10761138 var buf: Type.SlicePtrFieldTypeBuffer = undefined;
10771139 const fields: [2]*const llvm.Value = .{
1078 try self.genTypedValue(.{
1140 try dg.genTypedValue(.{
10791141 .ty = tv.ty.slicePtrFieldType(&buf),
10801142 .val = slice.ptr,
10811143 }),
1082 try self.genTypedValue(.{
1144 try dg.genTypedValue(.{
10831145 .ty = Type.usize,
10841146 .val = slice.len,
10851147 }),
10861148 };
1087 return self.context.constStruct(&fields, fields.len, .False);
1149 return dg.context.constStruct(&fields, fields.len, .False);
10881150 },
10891151 .int_u64, .one, .int_big_positive => {
1090 const llvm_usize = try self.llvmType(Type.usize);
1152 const llvm_usize = try dg.llvmType(Type.usize);
10911153 const llvm_int = llvm_usize.constInt(tv.val.toUnsignedInt(), .False);
1092 return llvm_int.constIntToPtr(try self.llvmType(tv.ty));
1154 return llvm_int.constIntToPtr(try dg.llvmType(tv.ty));
10931155 },
10941156 .field_ptr => {
10951157 const field_ptr = tv.val.castTag(.field_ptr).?.data;
1096 const parent_ptr = try self.lowerParentPtr(field_ptr.container_ptr);
1097 const llvm_u32 = self.context.intType(32);
1158 const parent_ptr = try dg.lowerParentPtr(field_ptr.container_ptr);
1159 const llvm_u32 = dg.context.intType(32);
10981160 const indices: [2]*const llvm.Value = .{
10991161 llvm_u32.constInt(0, .False),
11001162 llvm_u32.constInt(field_ptr.field_index, .False),
......@@ -1103,8 +1165,8 @@ pub const DeclGen = struct {
11031165 },
11041166 .elem_ptr => {
11051167 const elem_ptr = tv.val.castTag(.elem_ptr).?.data;
1106 const parent_ptr = try self.lowerParentPtr(elem_ptr.array_ptr);
1107 const llvm_usize = try self.llvmType(Type.usize);
1168 const parent_ptr = try dg.lowerParentPtr(elem_ptr.array_ptr);
1169 const llvm_usize = try dg.llvmType(Type.usize);
11081170 if (parent_ptr.typeOf().getElementType().getTypeKind() == .Array) {
11091171 const indices: [2]*const llvm.Value = .{
11101172 llvm_usize.constInt(0, .False),
......@@ -1119,15 +1181,15 @@ pub const DeclGen = struct {
11191181 }
11201182 },
11211183 .null_value, .zero => {
1122 const llvm_type = try self.llvmType(tv.ty);
1184 const llvm_type = try dg.llvmType(tv.ty);
11231185 return llvm_type.constNull();
11241186 },
1125 else => |tag| return self.todo("implement const of pointer type '{}' ({})", .{ tv.ty, tag }),
1187 else => |tag| return dg.todo("implement const of pointer type '{}' ({})", .{ tv.ty, tag }),
11261188 },
11271189 .Array => switch (tv.val.tag()) {
11281190 .bytes => {
11291191 const bytes = tv.val.castTag(.bytes).?.data;
1130 return self.context.constString(
1192 return dg.context.constString(
11311193 bytes.ptr,
11321194 @intCast(c_uint, bytes.len),
11331195 .True, // don't null terminate. bytes has the sentinel, if any.
......@@ -1136,13 +1198,13 @@ pub const DeclGen = struct {
11361198 .array => {
11371199 const elem_vals = tv.val.castTag(.array).?.data;
11381200 const elem_ty = tv.ty.elemType();
1139 const gpa = self.gpa;
1201 const gpa = dg.gpa;
11401202 const llvm_elems = try gpa.alloc(*const llvm.Value, elem_vals.len);
11411203 defer gpa.free(llvm_elems);
11421204 for (elem_vals) |elem_val, i| {
1143 llvm_elems[i] = try self.genTypedValue(.{ .ty = elem_ty, .val = elem_val });
1205 llvm_elems[i] = try dg.genTypedValue(.{ .ty = elem_ty, .val = elem_val });
11441206 }
1145 const llvm_elem_ty = try self.llvmType(elem_ty);
1207 const llvm_elem_ty = try dg.llvmType(elem_ty);
11461208 return llvm_elem_ty.constArray(
11471209 llvm_elems.ptr,
11481210 @intCast(c_uint, llvm_elems.len),
......@@ -1154,16 +1216,16 @@ pub const DeclGen = struct {
11541216 const sentinel = tv.ty.sentinel();
11551217 const len = @intCast(usize, tv.ty.arrayLen());
11561218 const len_including_sent = len + @boolToInt(sentinel != null);
1157 const gpa = self.gpa;
1219 const gpa = dg.gpa;
11581220 const llvm_elems = try gpa.alloc(*const llvm.Value, len_including_sent);
11591221 defer gpa.free(llvm_elems);
11601222 for (llvm_elems[0..len]) |*elem| {
1161 elem.* = try self.genTypedValue(.{ .ty = elem_ty, .val = val });
1223 elem.* = try dg.genTypedValue(.{ .ty = elem_ty, .val = val });
11621224 }
11631225 if (sentinel) |sent| {
1164 llvm_elems[len] = try self.genTypedValue(.{ .ty = elem_ty, .val = sent });
1226 llvm_elems[len] = try dg.genTypedValue(.{ .ty = elem_ty, .val = sent });
11651227 }
1166 const llvm_elem_ty = try self.llvmType(elem_ty);
1228 const llvm_elem_ty = try dg.llvmType(elem_ty);
11671229 return llvm_elem_ty.constArray(
11681230 llvm_elems.ptr,
11691231 @intCast(c_uint, llvm_elems.len),
......@@ -1172,9 +1234,9 @@ pub const DeclGen = struct {
11721234 .empty_array_sentinel => {
11731235 const elem_ty = tv.ty.elemType();
11741236 const sent_val = tv.ty.sentinel().?;
1175 const sentinel = try self.genTypedValue(.{ .ty = elem_ty, .val = sent_val });
1237 const sentinel = try dg.genTypedValue(.{ .ty = elem_ty, .val = sent_val });
11761238 const llvm_elems: [1]*const llvm.Value = .{sentinel};
1177 const llvm_elem_ty = try self.llvmType(elem_ty);
1239 const llvm_elem_ty = try dg.llvmType(elem_ty);
11781240 return llvm_elem_ty.constArray(&llvm_elems, llvm_elems.len);
11791241 },
11801242 else => unreachable,
......@@ -1182,7 +1244,7 @@ pub const DeclGen = struct {
11821244 .Optional => {
11831245 var buf: Type.Payload.ElemType = undefined;
11841246 const payload_ty = tv.ty.optionalChild(&buf);
1185 const llvm_i1 = self.context.intType(1);
1247 const llvm_i1 = dg.context.intType(1);
11861248 const is_pl = !tv.val.isNull();
11871249 const non_null_bit = if (is_pl) llvm_i1.constAllOnes() else llvm_i1.constNull();
11881250 if (!payload_ty.hasCodeGenBits()) {
......@@ -1190,22 +1252,22 @@ pub const DeclGen = struct {
11901252 }
11911253 if (tv.ty.isPtrLikeOptional()) {
11921254 if (tv.val.castTag(.opt_payload)) |payload| {
1193 return self.genTypedValue(.{ .ty = payload_ty, .val = payload.data });
1255 return dg.genTypedValue(.{ .ty = payload_ty, .val = payload.data });
11941256 } else if (is_pl) {
1195 return self.genTypedValue(.{ .ty = payload_ty, .val = tv.val });
1257 return dg.genTypedValue(.{ .ty = payload_ty, .val = tv.val });
11961258 } else {
1197 const llvm_ty = try self.llvmType(tv.ty);
1259 const llvm_ty = try dg.llvmType(tv.ty);
11981260 return llvm_ty.constNull();
11991261 }
12001262 }
12011263 const fields: [2]*const llvm.Value = .{
1202 try self.genTypedValue(.{
1264 try dg.genTypedValue(.{
12031265 .ty = payload_ty,
12041266 .val = if (tv.val.castTag(.opt_payload)) |pl| pl.data else Value.initTag(.undef),
12051267 }),
12061268 non_null_bit,
12071269 };
1208 return self.context.constStruct(&fields, fields.len, .False);
1270 return dg.context.constStruct(&fields, fields.len, .False);
12091271 },
12101272 .Fn => {
12111273 const fn_decl = switch (tv.val.tag()) {
......@@ -1214,14 +1276,14 @@ pub const DeclGen = struct {
12141276 else => unreachable,
12151277 };
12161278 fn_decl.alive = true;
1217 return self.resolveLlvmFunction(fn_decl);
1279 return dg.resolveLlvmFunction(fn_decl);
12181280 },
12191281 .ErrorSet => {
1220 const llvm_ty = try self.llvmType(tv.ty);
1282 const llvm_ty = try dg.llvmType(tv.ty);
12211283 switch (tv.val.tag()) {
12221284 .@"error" => {
12231285 const err_name = tv.val.castTag(.@"error").?.data.name;
1224 const kv = try self.module.getErrorValue(err_name);
1286 const kv = try dg.module.getErrorValue(err_name);
12251287 return llvm_ty.constInt(kv.value, .False);
12261288 },
12271289 else => {
......@@ -1238,76 +1300,138 @@ pub const DeclGen = struct {
12381300 if (!payload_type.hasCodeGenBits()) {
12391301 // We use the error type directly as the type.
12401302 const err_val = if (!is_pl) tv.val else Value.initTag(.zero);
1241 return self.genTypedValue(.{ .ty = error_type, .val = err_val });
1303 return dg.genTypedValue(.{ .ty = error_type, .val = err_val });
12421304 }
12431305
12441306 const fields: [2]*const llvm.Value = .{
1245 try self.genTypedValue(.{
1307 try dg.genTypedValue(.{
12461308 .ty = error_type,
12471309 .val = if (is_pl) Value.initTag(.zero) else tv.val,
12481310 }),
1249 try self.genTypedValue(.{
1311 try dg.genTypedValue(.{
12501312 .ty = payload_type,
12511313 .val = if (tv.val.castTag(.eu_payload)) |pl| pl.data else Value.initTag(.undef),
12521314 }),
12531315 };
1254 return self.context.constStruct(&fields, fields.len, .False);
1316 return dg.context.constStruct(&fields, fields.len, .False);
12551317 },
12561318 .Struct => {
1257 const llvm_struct_ty = try self.llvmType(tv.ty);
1319 const llvm_struct_ty = try dg.llvmType(tv.ty);
12581320 const field_vals = tv.val.castTag(.@"struct").?.data;
1259 const gpa = self.gpa;
1321 const gpa = dg.gpa;
12601322
12611323 var llvm_fields = try std.ArrayListUnmanaged(*const llvm.Value).initCapacity(gpa, field_vals.len);
12621324 defer llvm_fields.deinit(gpa);
12631325
1264 for (field_vals) |field_val, i| {
1265 const field_ty = tv.ty.structFieldType(i);
1266 if (!field_ty.hasCodeGenBits()) continue;
1267
1268 llvm_fields.appendAssumeCapacity(try self.genTypedValue(.{
1269 .ty = field_ty,
1270 .val = field_val,
1271 }));
1326 const struct_obj = tv.ty.castTag(.@"struct").?.data;
1327 if (struct_obj.layout == .Packed) {
1328 const target = dg.module.getTarget();
1329 const fields = struct_obj.fields.values();
1330 comptime assert(Type.packed_struct_layout_version == 1);
1331 var offset: u64 = 0;
1332 var running_bits: u16 = 0;
1333 var running_int: *const llvm.Value = llvm_struct_ty.structGetTypeAtIndex(0).constNull();
1334 for (field_vals) |field_val, i| {
1335 const field = fields[i];
1336 if (!field.ty.hasCodeGenBits()) continue;
1337
1338 const field_align = field.packedAlignment();
1339 if (field_align == 0) {
1340 const non_int_val = try dg.genTypedValue(.{
1341 .ty = field.ty,
1342 .val = field_val,
1343 });
1344 const ty_bit_size = @intCast(u16, field.ty.bitSize(target));
1345 const llvm_int_ty = dg.context.intType(ty_bit_size);
1346 const int_val = non_int_val.constBitCast(llvm_int_ty);
1347 const shift_rhs = llvm_int_ty.constInt(running_bits, .False);
1348 const shifted = int_val.constShl(shift_rhs);
1349 running_int = running_int.constOr(shifted);
1350 running_bits += ty_bit_size;
1351 } else {
1352 if (running_bits != 0) {
1353 var int_payload: Type.Payload.Bits = .{
1354 .base = .{ .tag = .int_unsigned },
1355 .data = running_bits,
1356 };
1357 const int_ty: Type = .{ .ptr_otherwise = &int_payload.base };
1358 const int_align = int_ty.abiAlignment(target);
1359 const prev_offset = offset;
1360 offset = std.mem.alignForwardGeneric(u64, offset, int_align);
1361 const padding_bytes = @intCast(c_uint, offset - prev_offset);
1362 if (padding_bytes != 0) {
1363 const padding = dg.context.intType(8).arrayType(padding_bytes);
1364 llvm_fields.appendAssumeCapacity(padding.getUndef());
1365 }
1366 llvm_fields.appendAssumeCapacity(running_int);
1367 running_int = llvm_struct_ty.structGetTypeAtIndex(@intCast(c_uint, llvm_fields.items.len)).constNull();
1368 offset += int_ty.abiSize(target);
1369 running_bits = 0;
1370 }
1371 const prev_offset = offset;
1372 offset = std.mem.alignForwardGeneric(u64, offset, field_align);
1373 const padding_bytes = @intCast(c_uint, offset - prev_offset);
1374 if (padding_bytes != 0) {
1375 const padding = dg.context.intType(8).arrayType(padding_bytes);
1376 llvm_fields.appendAssumeCapacity(padding.getUndef());
1377 }
1378 llvm_fields.appendAssumeCapacity(try dg.genTypedValue(.{
1379 .ty = field.ty,
1380 .val = field_val,
1381 }));
1382 offset += field.ty.abiSize(target);
1383 }
1384 }
1385 } else {
1386 for (field_vals) |field_val, i| {
1387 const field_ty = tv.ty.structFieldType(i);
1388 if (!field_ty.hasCodeGenBits()) continue;
1389
1390 llvm_fields.appendAssumeCapacity(try dg.genTypedValue(.{
1391 .ty = field_ty,
1392 .val = field_val,
1393 }));
1394 }
12721395 }
1396
12731397 return llvm_struct_ty.constNamedStruct(
12741398 llvm_fields.items.ptr,
12751399 @intCast(c_uint, llvm_fields.items.len),
12761400 );
12771401 },
12781402 .Union => {
1279 const llvm_union_ty = try self.llvmType(tv.ty);
1403 const llvm_union_ty = try dg.llvmType(tv.ty);
12801404 const tag_and_val = tv.val.castTag(.@"union").?.data;
12811405
1282 const target = self.module.getTarget();
1406 const target = dg.module.getTarget();
12831407 const layout = tv.ty.unionGetLayout(target);
12841408
12851409 if (layout.payload_size == 0) {
1286 return genTypedValue(self, .{ .ty = tv.ty.unionTagType().?, .val = tag_and_val.tag });
1410 return genTypedValue(dg, .{ .ty = tv.ty.unionTagType().?, .val = tag_and_val.tag });
12871411 }
12881412 const field_ty = tv.ty.unionFieldType(tag_and_val.tag);
12891413 const payload = p: {
12901414 if (!field_ty.hasCodeGenBits()) {
12911415 const padding_len = @intCast(c_uint, layout.payload_size);
1292 break :p self.context.intType(8).arrayType(padding_len).getUndef();
1416 break :p dg.context.intType(8).arrayType(padding_len).getUndef();
12931417 }
1294 const field = try genTypedValue(self, .{ .ty = field_ty, .val = tag_and_val.val });
1418 const field = try genTypedValue(dg, .{ .ty = field_ty, .val = tag_and_val.val });
12951419 const field_size = field_ty.abiSize(target);
12961420 if (field_size == layout.payload_size) {
12971421 break :p field;
12981422 }
12991423 const padding_len = @intCast(c_uint, layout.payload_size - field_size);
13001424 const fields: [2]*const llvm.Value = .{
1301 field, self.context.intType(8).arrayType(padding_len).getUndef(),
1425 field, dg.context.intType(8).arrayType(padding_len).getUndef(),
13021426 };
1303 break :p self.context.constStruct(&fields, fields.len, .False);
1427 break :p dg.context.constStruct(&fields, fields.len, .False);
13041428 };
13051429 if (layout.tag_size == 0) {
13061430 const llvm_payload_ty = llvm_union_ty.structGetTypeAtIndex(0);
13071431 const fields: [1]*const llvm.Value = .{payload.constBitCast(llvm_payload_ty)};
13081432 return llvm_union_ty.constNamedStruct(&fields, fields.len);
13091433 }
1310 const llvm_tag_value = try genTypedValue(self, .{
1434 const llvm_tag_value = try genTypedValue(dg, .{
13111435 .ty = tv.ty.unionTagType().?,
13121436 .val = tag_and_val.tag,
13131437 });
......@@ -1329,15 +1453,15 @@ pub const DeclGen = struct {
13291453 assert(vector_len == bytes.len or vector_len + 1 == bytes.len);
13301454
13311455 const elem_ty = tv.ty.elemType();
1332 const llvm_elems = try self.gpa.alloc(*const llvm.Value, vector_len);
1333 defer self.gpa.free(llvm_elems);
1456 const llvm_elems = try dg.gpa.alloc(*const llvm.Value, vector_len);
1457 defer dg.gpa.free(llvm_elems);
13341458 for (llvm_elems) |*elem, i| {
13351459 var byte_payload: Value.Payload.U64 = .{
13361460 .base = .{ .tag = .int_u64 },
13371461 .data = bytes[i],
13381462 };
13391463
1340 elem.* = try self.genTypedValue(.{
1464 elem.* = try dg.genTypedValue(.{
13411465 .ty = elem_ty,
13421466 .val = Value.initPayload(&byte_payload.base),
13431467 });
......@@ -1354,10 +1478,10 @@ pub const DeclGen = struct {
13541478 const vector_len = @intCast(usize, tv.ty.arrayLen());
13551479 assert(vector_len == elem_vals.len or vector_len + 1 == elem_vals.len);
13561480 const elem_ty = tv.ty.elemType();
1357 const llvm_elems = try self.gpa.alloc(*const llvm.Value, vector_len);
1358 defer self.gpa.free(llvm_elems);
1481 const llvm_elems = try dg.gpa.alloc(*const llvm.Value, vector_len);
1482 defer dg.gpa.free(llvm_elems);
13591483 for (llvm_elems) |*elem, i| {
1360 elem.* = try self.genTypedValue(.{ .ty = elem_ty, .val = elem_vals[i] });
1484 elem.* = try dg.genTypedValue(.{ .ty = elem_ty, .val = elem_vals[i] });
13611485 }
13621486 return llvm.constVector(
13631487 llvm_elems.ptr,
......@@ -1369,10 +1493,10 @@ pub const DeclGen = struct {
13691493 const val = tv.val.castTag(.repeated).?.data;
13701494 const elem_ty = tv.ty.elemType();
13711495 const len = @intCast(usize, tv.ty.arrayLen());
1372 const llvm_elems = try self.gpa.alloc(*const llvm.Value, len);
1373 defer self.gpa.free(llvm_elems);
1496 const llvm_elems = try dg.gpa.alloc(*const llvm.Value, len);
1497 defer dg.gpa.free(llvm_elems);
13741498 for (llvm_elems) |*elem| {
1375 elem.* = try self.genTypedValue(.{ .ty = elem_ty, .val = val });
1499 elem.* = try dg.genTypedValue(.{ .ty = elem_ty, .val = val });
13761500 }
13771501 return llvm.constVector(
13781502 llvm_elems.ptr,
......@@ -1395,7 +1519,7 @@ pub const DeclGen = struct {
13951519
13961520 .Frame,
13971521 .AnyFrame,
1398 => return self.todo("implement const of type '{}'", .{tv.ty}),
1522 => return dg.todo("implement const of type '{}'", .{tv.ty}),
13991523 }
14001524 }
14011525
......@@ -2403,26 +2527,28 @@ pub const FuncGen = struct {
24032527
24042528 assert(isByRef(struct_ty));
24052529
2406 const field_ptr = switch (struct_ty.zigTypeTag()) {
2407 .Struct => blk: {
2408 const llvm_field_index = llvmFieldIndex(struct_ty, field_index);
2409 break :blk self.builder.buildStructGEP(struct_llvm_val, llvm_field_index, "");
2530 const target = self.dg.module.getTarget();
2531 switch (struct_ty.zigTypeTag()) {
2532 .Struct => {
2533 var ptr_ty_buf: Type.Payload.Pointer = undefined;
2534 const llvm_field_index = llvmFieldIndex(struct_ty, field_index, target, &ptr_ty_buf);
2535 const field_ptr = self.builder.buildStructGEP(struct_llvm_val, llvm_field_index, "");
2536 const field_ptr_ty = Type.initPayload(&ptr_ty_buf.base);
2537 return self.load(field_ptr, field_ptr_ty);
24102538 },
2411 .Union => blk: {
2539 .Union => {
24122540 const llvm_field_ty = try self.dg.llvmType(field_ty);
2413 const target = self.dg.module.getTarget();
24142541 const layout = struct_ty.unionGetLayout(target);
24152542 const payload_index = @boolToInt(layout.tag_align >= layout.payload_align);
24162543 const union_field_ptr = self.builder.buildStructGEP(struct_llvm_val, payload_index, "");
2417 break :blk self.builder.buildBitCast(union_field_ptr, llvm_field_ty.pointerType(0), "");
2544 const field_ptr = self.builder.buildBitCast(union_field_ptr, llvm_field_ty.pointerType(0), "");
2545 if (isByRef(field_ty)) {
2546 return field_ptr;
2547 } else {
2548 return self.builder.buildLoad(field_ptr, "");
2549 }
24182550 },
24192551 else => unreachable,
2420 };
2421
2422 if (isByRef(field_ty)) {
2423 return field_ptr;
2424 } else {
2425 return self.builder.buildLoad(field_ptr, "");
24262552 }
24272553 }
24282554
......@@ -3730,11 +3856,11 @@ pub const FuncGen = struct {
37303856 if (opt_abi_ty) |abi_ty| {
37313857 // operand needs widening and truncating
37323858 const casted_ptr = self.builder.buildBitCast(ptr, abi_ty.pointerType(0), "");
3733 const load_inst = self.load(casted_ptr, ptr_ty).?;
3859 const load_inst = (try self.load(casted_ptr, ptr_ty)).?;
37343860 load_inst.setOrdering(ordering);
37353861 return self.builder.buildTrunc(load_inst, try self.dg.llvmType(operand_ty), "");
37363862 }
3737 const load_inst = self.load(ptr, ptr_ty).?;
3863 const load_inst = (try self.load(ptr, ptr_ty)).?;
37383864 load_inst.setOrdering(ordering);
37393865 return load_inst;
37403866 }
......@@ -3997,7 +4123,9 @@ pub const FuncGen = struct {
39974123 const struct_ty = struct_ptr_ty.childType();
39984124 switch (struct_ty.zigTypeTag()) {
39994125 .Struct => {
4000 const llvm_field_index = llvmFieldIndex(struct_ty, field_index);
4126 const target = self.dg.module.getTarget();
4127 var ty_buf: Type.Payload.Pointer = undefined;
4128 const llvm_field_index = llvmFieldIndex(struct_ty, field_index, target, &ty_buf);
40014129 return self.builder.buildStructGEP(struct_ptr, llvm_field_index, "");
40024130 },
40034131 .Union => return self.unionFieldPtr(inst, struct_ptr, struct_ty, field_index),
......@@ -4041,15 +4169,52 @@ pub const FuncGen = struct {
40414169 return self.llvmModule().getIntrinsicDeclaration(id, types.ptr, types.len);
40424170 }
40434171
4044 fn load(self: *FuncGen, ptr: *const llvm.Value, ptr_ty: Type) ?*const llvm.Value {
4045 const pointee_ty = ptr_ty.childType();
4046 if (!pointee_ty.hasCodeGenBits()) return null;
4047 if (isByRef(pointee_ty)) return ptr;
4048 const llvm_inst = self.builder.buildLoad(ptr, "");
4172 fn load(self: *FuncGen, ptr: *const llvm.Value, ptr_ty: Type) !?*const llvm.Value {
4173 const info = ptr_ty.ptrInfo().data;
4174 if (!info.pointee_type.hasCodeGenBits()) return null;
4175
40494176 const target = self.dg.module.getTarget();
4050 llvm_inst.setAlignment(ptr_ty.ptrAlignment(target));
4051 llvm_inst.setVolatile(llvm.Bool.fromBool(ptr_ty.isVolatilePtr()));
4052 return llvm_inst;
4177 const ptr_alignment = ptr_ty.ptrAlignment(target);
4178 const ptr_volatile = llvm.Bool.fromBool(ptr_ty.isVolatilePtr());
4179 if (info.host_size == 0) {
4180 if (isByRef(info.pointee_type)) return ptr;
4181 const llvm_inst = self.builder.buildLoad(ptr, "");
4182 llvm_inst.setAlignment(ptr_alignment);
4183 llvm_inst.setVolatile(ptr_volatile);
4184 return llvm_inst;
4185 }
4186
4187 const int_ptr_ty = self.context.intType(info.host_size * 8).pointerType(0);
4188 const int_ptr = self.builder.buildBitCast(ptr, int_ptr_ty, "");
4189 const containing_int = self.builder.buildLoad(int_ptr, "");
4190 containing_int.setAlignment(ptr_alignment);
4191 containing_int.setVolatile(ptr_volatile);
4192
4193 const elem_bits = @intCast(c_uint, ptr_ty.elemType().bitSize(target));
4194 const shift_amt = containing_int.typeOf().constInt(info.bit_offset, .False);
4195 const shifted_value = self.builder.buildLShr(containing_int, shift_amt, "");
4196 const elem_llvm_ty = try self.dg.llvmType(info.pointee_type);
4197
4198 if (isByRef(info.pointee_type)) {
4199 const result_align = info.pointee_type.abiAlignment(target);
4200 const result_ptr = self.buildAlloca(elem_llvm_ty);
4201 result_ptr.setAlignment(result_align);
4202
4203 const same_size_int = self.context.intType(elem_bits);
4204 const truncated_int = self.builder.buildTrunc(shifted_value, same_size_int, "");
4205 const bitcasted_ptr = self.builder.buildBitCast(result_ptr, same_size_int.pointerType(0), "");
4206 const store_inst = self.builder.buildStore(truncated_int, bitcasted_ptr);
4207 store_inst.setAlignment(result_align);
4208 return result_ptr;
4209 }
4210
4211 if (info.pointee_type.zigTypeTag() == .Float) {
4212 const same_size_int = self.context.intType(elem_bits);
4213 const truncated_int = self.builder.buildTrunc(shifted_value, same_size_int, "");
4214 return self.builder.buildBitCast(truncated_int, elem_llvm_ty, "");
4215 }
4216
4217 return self.builder.buildTrunc(shifted_value, elem_llvm_ty, "");
40534218 }
40544219
40554220 fn store(
......@@ -4059,16 +4224,50 @@ pub const FuncGen = struct {
40594224 elem: *const llvm.Value,
40604225 ordering: llvm.AtomicOrdering,
40614226 ) void {
4062 const elem_ty = ptr_ty.childType();
4227 const info = ptr_ty.ptrInfo().data;
4228 const elem_ty = info.pointee_type;
40634229 if (!elem_ty.hasCodeGenBits()) {
40644230 return;
40654231 }
40664232 const target = self.dg.module.getTarget();
4233 const ptr_alignment = ptr_ty.ptrAlignment(target);
4234 const ptr_volatile = llvm.Bool.fromBool(info.@"volatile");
4235 if (info.host_size != 0) {
4236 const int_ptr_ty = self.context.intType(info.host_size * 8).pointerType(0);
4237 const int_ptr = self.builder.buildBitCast(ptr, int_ptr_ty, "");
4238 const containing_int = self.builder.buildLoad(int_ptr, "");
4239 assert(ordering == .NotAtomic);
4240 containing_int.setAlignment(ptr_alignment);
4241 containing_int.setVolatile(ptr_volatile);
4242 const elem_bits = @intCast(c_uint, ptr_ty.elemType().bitSize(target));
4243 const containing_int_ty = containing_int.typeOf();
4244 const shift_amt = containing_int_ty.constInt(info.bit_offset, .False);
4245 // Convert to equally-sized integer type in order to perform the bit
4246 // operations on the value to store
4247 const value_bits_type = self.context.intType(elem_bits);
4248 const value_bits = self.builder.buildBitCast(elem, value_bits_type, "");
4249
4250 var mask_val = value_bits_type.constAllOnes();
4251 mask_val = mask_val.constZExt(containing_int_ty);
4252 mask_val = mask_val.constShl(shift_amt);
4253 mask_val = mask_val.constNot();
4254
4255 const anded_containing_int = self.builder.buildAnd(containing_int, mask_val, "");
4256 const extended_value = self.builder.buildZExt(value_bits, containing_int_ty, "");
4257 const shifted_value = self.builder.buildShl(extended_value, shift_amt, "");
4258 const ored_value = self.builder.buildOr(shifted_value, anded_containing_int, "");
4259
4260 const store_inst = self.builder.buildStore(ored_value, int_ptr);
4261 assert(ordering == .NotAtomic);
4262 store_inst.setAlignment(ptr_alignment);
4263 store_inst.setVolatile(ptr_volatile);
4264 return;
4265 }
40674266 if (!isByRef(elem_ty)) {
40684267 const store_inst = self.builder.buildStore(elem, ptr);
40694268 store_inst.setOrdering(ordering);
4070 store_inst.setAlignment(ptr_ty.ptrAlignment(target));
4071 store_inst.setVolatile(llvm.Bool.fromBool(ptr_ty.isVolatilePtr()));
4269 store_inst.setAlignment(ptr_alignment);
4270 store_inst.setVolatile(ptr_volatile);
40724271 return;
40734272 }
40744273 assert(ordering == .NotAtomic);
......@@ -4080,7 +4279,7 @@ pub const FuncGen = struct {
40804279 self.builder.buildBitCast(elem, llvm_ptr_u8, ""),
40814280 elem_ty.abiAlignment(target),
40824281 self.context.intType(Type.usize.intInfo(target).bits).constInt(size_bytes, .False),
4083 ptr_ty.isVolatilePtr(),
4282 info.@"volatile",
40844283 );
40854284 }
40864285};
......@@ -4323,15 +4522,104 @@ fn toLlvmCallConv(cc: std.builtin.CallingConvention, target: std.Target) llvm.Ca
43234522}
43244523
43254524/// Take into account 0 bit fields.
4326fn llvmFieldIndex(ty: Type, index: u32) c_uint {
4525fn llvmFieldIndex(
4526 ty: Type,
4527 field_index: u32,
4528 target: std.Target,
4529 ptr_pl_buf: *Type.Payload.Pointer,
4530) c_uint {
43274531 const struct_obj = ty.castTag(.@"struct").?.data;
4328 var result: c_uint = 0;
4329 for (struct_obj.fields.values()[0..index]) |field| {
4330 if (field.ty.hasCodeGenBits()) {
4331 result += 1;
4532 if (struct_obj.layout != .Packed) {
4533 var llvm_field_index: c_uint = 0;
4534 for (struct_obj.fields.values()) |field, i| {
4535 if (!field.ty.hasCodeGenBits()) continue;
4536
4537 if (i == field_index) {
4538 ptr_pl_buf.* = .{
4539 .data = .{
4540 .pointee_type = field.ty,
4541 .@"align" = field.normalAlignment(target),
4542 .@"addrspace" = .generic,
4543 },
4544 };
4545 return llvm_field_index;
4546 }
4547 llvm_field_index += 1;
4548 }
4549 unreachable;
4550 }
4551
4552 // Our job here is to return the host integer field index.
4553 comptime assert(Type.packed_struct_layout_version == 1);
4554 var offset: u64 = 0;
4555 var running_bits: u16 = 0;
4556 var llvm_field_index: c_uint = 0;
4557 for (struct_obj.fields.values()) |field, i| {
4558 if (!field.ty.hasCodeGenBits()) continue;
4559
4560 const field_align = field.packedAlignment();
4561 if (field_align == 0) {
4562 if (i == field_index) {
4563 ptr_pl_buf.* = .{
4564 .data = .{
4565 .pointee_type = field.ty,
4566 .bit_offset = running_bits,
4567 .@"addrspace" = .generic,
4568 },
4569 };
4570 }
4571 running_bits += @intCast(u16, field.ty.bitSize(target));
4572 } else {
4573 if (running_bits != 0) {
4574 var int_payload: Type.Payload.Bits = .{
4575 .base = .{ .tag = .int_unsigned },
4576 .data = running_bits,
4577 };
4578 const int_ty: Type = .{ .ptr_otherwise = &int_payload.base };
4579 if (i > field_index) {
4580 ptr_pl_buf.data.host_size = @intCast(u16, int_ty.abiSize(target));
4581 return llvm_field_index;
4582 }
4583
4584 const int_align = int_ty.abiAlignment(target);
4585 const prev_offset = offset;
4586 offset = std.mem.alignForwardGeneric(u64, offset, int_align);
4587 const padding_bytes = @intCast(c_uint, offset - prev_offset);
4588 if (padding_bytes != 0) {
4589 llvm_field_index += 1;
4590 }
4591 llvm_field_index += 1;
4592 offset += int_ty.abiSize(target);
4593 running_bits = 0;
4594 }
4595 const prev_offset = offset;
4596 offset = std.mem.alignForwardGeneric(u64, offset, field_align);
4597 const padding_bytes = @intCast(c_uint, offset - prev_offset);
4598 if (padding_bytes != 0) {
4599 llvm_field_index += 1;
4600 }
4601 if (i == field_index) {
4602 ptr_pl_buf.* = .{
4603 .data = .{
4604 .pointee_type = field.ty,
4605 .@"align" = field_align,
4606 .@"addrspace" = .generic,
4607 },
4608 };
4609 return llvm_field_index;
4610 }
4611 llvm_field_index += 1;
4612 offset += field.ty.abiSize(target);
43324613 }
43334614 }
4334 return result;
4615 assert(running_bits != 0);
4616 var int_payload: Type.Payload.Bits = .{
4617 .base = .{ .tag = .int_unsigned },
4618 .data = running_bits,
4619 };
4620 const int_ty: Type = .{ .ptr_otherwise = &int_payload.base };
4621 ptr_pl_buf.data.host_size = @intCast(u16, int_ty.abiSize(target));
4622 return llvm_field_index;
43354623}
43364624
43374625fn firstParamSRet(fn_info: Type.Payload.Function.Data, target: std.Target) bool {
src/codegen/llvm/bindings.zig+12
......@@ -148,6 +148,18 @@ pub const Value = opaque {
148148 pub const constPtrToInt = LLVMConstPtrToInt;
149149 extern fn LLVMConstPtrToInt(ConstantVal: *const Value, ToType: *const Type) *const Value;
150150
151 pub const constShl = LLVMConstShl;
152 extern fn LLVMConstShl(LHSConstant: *const Value, RHSConstant: *const Value) *const Value;
153
154 pub const constOr = LLVMConstOr;
155 extern fn LLVMConstOr(LHSConstant: *const Value, RHSConstant: *const Value) *const Value;
156
157 pub const constZExt = LLVMConstZExt;
158 extern fn LLVMConstZExt(ConstantVal: *const Value, ToType: *const Type) *const Value;
159
160 pub const constNot = LLVMConstNot;
161 extern fn LLVMConstNot(ConstantVal: *const Value) *const Value;
162
151163 pub const setWeak = LLVMSetWeak;
152164 extern fn LLVMSetWeak(CmpXchgInst: *const Value, IsWeak: Bool) void;
153165
src/type.zig+97-20
......@@ -1173,7 +1173,7 @@ pub const Type = extern union {
11731173 .C => try writer.writeAll("[*c]"),
11741174 .Slice => try writer.writeAll("[]"),
11751175 }
1176 if (payload.@"align" != 0) {
1176 if (payload.@"align" != 0 or payload.host_size != 0) {
11771177 try writer.print("align({d}", .{payload.@"align"});
11781178
11791179 if (payload.bit_offset != 0) {
......@@ -1867,24 +1867,57 @@ pub const Type = extern union {
18671867
18681868 .@"struct" => {
18691869 const fields = self.structFields();
1870 if (self.castTag(.@"struct")) |payload| {
1870 const is_packed = if (self.castTag(.@"struct")) |payload| p: {
18711871 const struct_obj = payload.data;
18721872 assert(struct_obj.status == .have_layout);
1873 const is_packed = struct_obj.layout == .Packed;
1874 if (is_packed) @panic("TODO packed structs");
1873 break :p struct_obj.layout == .Packed;
1874 } else false;
1875
1876 if (!is_packed) {
1877 var big_align: u32 = 0;
1878 for (fields.values()) |field| {
1879 if (!field.ty.hasCodeGenBits()) continue;
1880
1881 const field_align = field.normalAlignment(target);
1882 big_align = @maximum(big_align, field_align);
1883 }
1884 return big_align;
18751885 }
1886
1887 // For packed structs, we take the maximum alignment of the backing integers.
1888 comptime assert(Type.packed_struct_layout_version == 1);
18761889 var big_align: u32 = 0;
1890 var running_bits: u16 = 0;
1891
18771892 for (fields.values()) |field| {
18781893 if (!field.ty.hasCodeGenBits()) continue;
18791894
1880 const field_align = a: {
1881 if (field.abi_align.tag() == .abi_align_default) {
1882 break :a field.ty.abiAlignment(target);
1883 } else {
1884 break :a @intCast(u32, field.abi_align.toUnsignedInt());
1895 const field_align = field.packedAlignment();
1896 if (field_align == 0) {
1897 running_bits += @intCast(u16, field.ty.bitSize(target));
1898 } else {
1899 if (running_bits != 0) {
1900 var int_payload: Payload.Bits = .{
1901 .base = .{ .tag = .int_unsigned },
1902 .data = running_bits,
1903 };
1904 const int_ty: Type = .{ .ptr_otherwise = &int_payload.base };
1905 const int_align = int_ty.abiAlignment(target);
1906 big_align = @maximum(big_align, int_align);
1907 running_bits = 0;
18851908 }
1909 big_align = @maximum(big_align, field_align);
1910 }
1911 }
1912
1913 if (running_bits != 0) {
1914 var int_payload: Payload.Bits = .{
1915 .base = .{ .tag = .int_unsigned },
1916 .data = running_bits,
18861917 };
1887 big_align = @maximum(big_align, field_align);
1918 const int_ty: Type = .{ .ptr_otherwise = &int_payload.base };
1919 const int_align = int_ty.abiAlignment(target);
1920 big_align = @maximum(big_align, int_align);
18881921 }
18891922 return big_align;
18901923 },
......@@ -3635,30 +3668,70 @@ pub const Type = extern union {
36353668 }
36363669
36373670 /// Supports structs and unions.
3671 /// For packed structs, it returns the byte offset of the containing integer.
36383672 pub fn structFieldOffset(ty: Type, index: usize, target: Target) u64 {
36393673 switch (ty.tag()) {
36403674 .@"struct" => {
36413675 const struct_obj = ty.castTag(.@"struct").?.data;
36423676 assert(struct_obj.status == .have_layout);
36433677 const is_packed = struct_obj.layout == .Packed;
3644 if (is_packed) @panic("TODO packed structs");
3678 if (!is_packed) {
3679 var offset: u64 = 0;
3680 var big_align: u32 = 0;
3681 for (struct_obj.fields.values()) |field, i| {
3682 if (!field.ty.hasCodeGenBits()) continue;
3683
3684 const field_align = field.normalAlignment(target);
3685 big_align = @maximum(big_align, field_align);
3686 offset = std.mem.alignForwardGeneric(u64, offset, field_align);
3687 if (i == index) return offset;
3688 offset += field.ty.abiSize(target);
3689 }
3690 offset = std.mem.alignForwardGeneric(u64, offset, big_align);
3691 return offset;
3692 }
36453693
3694 comptime assert(Type.packed_struct_layout_version == 1);
36463695 var offset: u64 = 0;
36473696 var big_align: u32 = 0;
3697 var running_bits: u16 = 0;
36483698 for (struct_obj.fields.values()) |field, i| {
36493699 if (!field.ty.hasCodeGenBits()) continue;
36503700
3651 const field_align = a: {
3652 if (field.abi_align.tag() == .abi_align_default) {
3653 break :a field.ty.abiAlignment(target);
3654 } else {
3655 break :a @intCast(u32, field.abi_align.toUnsignedInt());
3701 const field_align = field.packedAlignment();
3702 if (field_align == 0) {
3703 if (i == index) return offset;
3704 running_bits += @intCast(u16, field.ty.bitSize(target));
3705 } else {
3706 big_align = @maximum(big_align, field_align);
3707
3708 if (running_bits != 0) {
3709 var int_payload: Payload.Bits = .{
3710 .base = .{ .tag = .int_unsigned },
3711 .data = running_bits,
3712 };
3713 const int_ty: Type = .{ .ptr_otherwise = &int_payload.base };
3714 const int_align = int_ty.abiAlignment(target);
3715 big_align = @maximum(big_align, int_align);
3716 offset = std.mem.alignForwardGeneric(u64, offset, int_align);
3717 offset += int_ty.abiSize(target);
3718 running_bits = 0;
36563719 }
3720 offset = std.mem.alignForwardGeneric(u64, offset, field_align);
3721 if (i == index) return offset;
3722 offset += field.ty.abiSize(target);
3723 }
3724 }
3725 if (running_bits != 0) {
3726 var int_payload: Payload.Bits = .{
3727 .base = .{ .tag = .int_unsigned },
3728 .data = running_bits,
36573729 };
3658 big_align = @maximum(big_align, field_align);
3659 offset = std.mem.alignForwardGeneric(u64, offset, field_align);
3660 if (i == index) return offset;
3661 offset += field.ty.abiSize(target);
3730 const int_ty: Type = .{ .ptr_otherwise = &int_payload.base };
3731 const int_align = int_ty.abiAlignment(target);
3732 big_align = @maximum(big_align, int_align);
3733 offset = std.mem.alignForwardGeneric(u64, offset, int_align);
3734 offset += int_ty.abiSize(target);
36623735 }
36633736 offset = std.mem.alignForwardGeneric(u64, offset, big_align);
36643737 return offset;
......@@ -4350,6 +4423,10 @@ pub const Type = extern union {
43504423 else => return Tag.int_unsigned.create(arena, bits),
43514424 };
43524425 }
4426
4427 /// This is only used for comptime asserts. Bump this number when you make a change
4428 /// to packed struct layout to find out all the places in the codebase you need to edit!
4429 pub const packed_struct_layout_version = 1;
43534430};
43544431
43554432pub const CType = enum {
test/behavior/struct_llvm.zig+155
......@@ -91,3 +91,158 @@ const Expr = union(enum) {
9191fn alloc(comptime T: type) []T {
9292 return &[_]T{};
9393}
94
95const APackedStruct = packed struct {
96 x: u8,
97 y: u8,
98};
99
100test "packed struct" {
101 var foo = APackedStruct{
102 .x = 1,
103 .y = 2,
104 };
105 foo.y += 1;
106 const four = foo.x + foo.y;
107 try expect(four == 4);
108}
109
110const Foo24Bits = packed struct {
111 field: u24,
112};
113const Foo96Bits = packed struct {
114 a: u24,
115 b: u24,
116 c: u24,
117 d: u24,
118};
119
120test "packed struct 24bits" {
121 comptime {
122 try expect(@sizeOf(Foo24Bits) == 4);
123 if (@sizeOf(usize) == 4) {
124 try expect(@sizeOf(Foo96Bits) == 12);
125 } else {
126 try expect(@sizeOf(Foo96Bits) == 16);
127 }
128 }
129
130 var value = Foo96Bits{
131 .a = 0,
132 .b = 0,
133 .c = 0,
134 .d = 0,
135 };
136 value.a += 1;
137 try expect(value.a == 1);
138 try expect(value.b == 0);
139 try expect(value.c == 0);
140 try expect(value.d == 0);
141
142 value.b += 1;
143 try expect(value.a == 1);
144 try expect(value.b == 1);
145 try expect(value.c == 0);
146 try expect(value.d == 0);
147
148 value.c += 1;
149 try expect(value.a == 1);
150 try expect(value.b == 1);
151 try expect(value.c == 1);
152 try expect(value.d == 0);
153
154 value.d += 1;
155 try expect(value.a == 1);
156 try expect(value.b == 1);
157 try expect(value.c == 1);
158 try expect(value.d == 1);
159}
160
161test "runtime struct initialization of bitfield" {
162 const s1 = Nibbles{
163 .x = x1,
164 .y = x1,
165 };
166 const s2 = Nibbles{
167 .x = @intCast(u4, x2),
168 .y = @intCast(u4, x2),
169 };
170
171 try expect(s1.x == x1);
172 try expect(s1.y == x1);
173 try expect(s2.x == @intCast(u4, x2));
174 try expect(s2.y == @intCast(u4, x2));
175}
176
177var x1 = @as(u4, 1);
178var x2 = @as(u8, 2);
179
180const Nibbles = packed struct {
181 x: u4,
182 y: u4,
183};
184
185const Bitfields = packed struct {
186 f1: u16,
187 f2: u16,
188 f3: u8,
189 f4: u8,
190 f5: u4,
191 f6: u4,
192 f7: u8,
193};
194
195test "native bit field understands endianness" {
196 var all: u64 = if (native_endian != .Little)
197 0x1111222233445677
198 else
199 0x7765443322221111;
200 var bytes: [8]u8 = undefined;
201 @memcpy(&bytes, @ptrCast([*]u8, &all), 8);
202 var bitfields = @ptrCast(*Bitfields, &bytes).*;
203
204 try expect(bitfields.f1 == 0x1111);
205 try expect(bitfields.f2 == 0x2222);
206 try expect(bitfields.f3 == 0x33);
207 try expect(bitfields.f4 == 0x44);
208 try expect(bitfields.f5 == 0x5);
209 try expect(bitfields.f6 == 0x6);
210 try expect(bitfields.f7 == 0x77);
211}
212
213test "implicit cast packed struct field to const ptr" {
214 const LevelUpMove = packed struct {
215 move_id: u9,
216 level: u7,
217
218 fn toInt(value: u7) u7 {
219 return value;
220 }
221 };
222
223 var lup: LevelUpMove = undefined;
224 lup.level = 12;
225 const res = LevelUpMove.toInt(lup.level);
226 try expect(res == 12);
227}
228
229test "zero-bit field in packed struct" {
230 const S = packed struct {
231 x: u10,
232 y: void,
233 };
234 var x: S = undefined;
235 _ = x;
236}
237
238test "packed struct with non-ABI-aligned field" {
239 const S = packed struct {
240 x: u9,
241 y: u183,
242 };
243 var s: S = undefined;
244 s.x = 1;
245 s.y = 42;
246 try expect(s.x == 1);
247 try expect(s.y == 42);
248}
test/behavior/struct_stage1.zig-155
......@@ -6,21 +6,6 @@ const expectEqual = std.testing.expectEqual;
66const expectEqualSlices = std.testing.expectEqualSlices;
77const maxInt = std.math.maxInt;
88
9const APackedStruct = packed struct {
10 x: u8,
11 y: u8,
12};
13
14test "packed struct" {
15 var foo = APackedStruct{
16 .x = 1,
17 .y = 2,
18 };
19 foo.y += 1;
20 const four = foo.x + foo.y;
21 try expect(four == 4);
22}
23
249const BitField1 = packed struct {
2510 a: u3,
2611 b: u3,
......@@ -60,57 +45,6 @@ fn getC(data: *const BitField1) u2 {
6045 return data.c;
6146}
6247
63const Foo24Bits = packed struct {
64 field: u24,
65};
66const Foo96Bits = packed struct {
67 a: u24,
68 b: u24,
69 c: u24,
70 d: u24,
71};
72
73test "packed struct 24bits" {
74 comptime {
75 try expect(@sizeOf(Foo24Bits) == 4);
76 if (@sizeOf(usize) == 4) {
77 try expect(@sizeOf(Foo96Bits) == 12);
78 } else {
79 try expect(@sizeOf(Foo96Bits) == 16);
80 }
81 }
82
83 var value = Foo96Bits{
84 .a = 0,
85 .b = 0,
86 .c = 0,
87 .d = 0,
88 };
89 value.a += 1;
90 try expect(value.a == 1);
91 try expect(value.b == 0);
92 try expect(value.c == 0);
93 try expect(value.d == 0);
94
95 value.b += 1;
96 try expect(value.a == 1);
97 try expect(value.b == 1);
98 try expect(value.c == 0);
99 try expect(value.d == 0);
100
101 value.c += 1;
102 try expect(value.a == 1);
103 try expect(value.b == 1);
104 try expect(value.c == 1);
105 try expect(value.d == 0);
106
107 value.d += 1;
108 try expect(value.a == 1);
109 try expect(value.b == 1);
110 try expect(value.c == 1);
111 try expect(value.d == 1);
112}
113
11448const Foo32Bits = packed struct {
11549 field: u24,
11650 pad: u8,
......@@ -188,74 +122,6 @@ test "aligned array of packed struct" {
188122 try expect(ptr.a[1].b == 0xbb);
189123}
190124
191test "runtime struct initialization of bitfield" {
192 const s1 = Nibbles{
193 .x = x1,
194 .y = x1,
195 };
196 const s2 = Nibbles{
197 .x = @intCast(u4, x2),
198 .y = @intCast(u4, x2),
199 };
200
201 try expect(s1.x == x1);
202 try expect(s1.y == x1);
203 try expect(s2.x == @intCast(u4, x2));
204 try expect(s2.y == @intCast(u4, x2));
205}
206
207var x1 = @as(u4, 1);
208var x2 = @as(u8, 2);
209
210const Nibbles = packed struct {
211 x: u4,
212 y: u4,
213};
214
215const Bitfields = packed struct {
216 f1: u16,
217 f2: u16,
218 f3: u8,
219 f4: u8,
220 f5: u4,
221 f6: u4,
222 f7: u8,
223};
224
225test "native bit field understands endianness" {
226 var all: u64 = if (native_endian != .Little)
227 0x1111222233445677
228 else
229 0x7765443322221111;
230 var bytes: [8]u8 = undefined;
231 @memcpy(&bytes, @ptrCast([*]u8, &all), 8);
232 var bitfields = @ptrCast(*Bitfields, &bytes).*;
233
234 try expect(bitfields.f1 == 0x1111);
235 try expect(bitfields.f2 == 0x2222);
236 try expect(bitfields.f3 == 0x33);
237 try expect(bitfields.f4 == 0x44);
238 try expect(bitfields.f5 == 0x5);
239 try expect(bitfields.f6 == 0x6);
240 try expect(bitfields.f7 == 0x77);
241}
242
243test "implicit cast packed struct field to const ptr" {
244 const LevelUpMove = packed struct {
245 move_id: u9,
246 level: u7,
247
248 fn toInt(value: u7) u7 {
249 return value;
250 }
251 };
252
253 var lup: LevelUpMove = undefined;
254 lup.level = 12;
255 const res = LevelUpMove.toInt(lup.level);
256 try expect(res == 12);
257}
258
259125test "pointer to packed struct member in a stack variable" {
260126 const S = packed struct {
261127 a: u2,
......@@ -379,27 +245,6 @@ test "fn with C calling convention returns struct by value" {
379245 comptime try S.entry();
380246}
381247
382test "zero-bit field in packed struct" {
383 const S = packed struct {
384 x: u10,
385 y: void,
386 };
387 var x: S = undefined;
388 _ = x;
389}
390
391test "packed struct with non-ABI-aligned field" {
392 const S = packed struct {
393 x: u9,
394 y: u183,
395 };
396 var s: S = undefined;
397 s.x = 1;
398 s.y = 42;
399 try expect(s.x == 1);
400 try expect(s.y == 42);
401}
402
403248test "non-packed struct with u128 entry in union" {
404249 const U = union(enum) {
405250 Num: u128,