| ... | ... | @@ -284,9 +284,8 @@ pub fn defineComplete( |
| 284 | 284 | }, |
| 285 | 285 | }, |
| 286 | 286 | .array => if (ty.hasRuntimeBits(zcu)) { |
| 287 | | const elem_ty = ty.childType(zcu); |
| 288 | 287 | const name_cty: CType = .{ .arr = ty }; |
| 289 | | const elem_cty: CType = try .lower(elem_ty, deps, arena, zcu); |
| 288 | const elem_cty: CType = try .lower(ty.childType(zcu), deps, arena, zcu); |
| 290 | 289 | const array_cty: CType = .{ .array = .{ |
| 291 | 290 | .len = ty.arrayLenIncludingSentinel(zcu), |
| 292 | 291 | .elem_ty = &elem_cty, |
| ... | ... | @@ -296,28 +295,17 @@ pub fn defineComplete( |
| 296 | 295 | break :nonstring Value.compareHetero(s, .neq, .zero_comptime_int, zcu); |
| 297 | 296 | }, |
| 298 | 297 | } }; |
| 299 | | if (elem_ty.defaultStructFieldAlignment(.auto, zcu) == elem_ty.abiAlignment(zcu)) { |
| 300 | | try w.print("{f} {{ {f}array{f}; }}; /* {f} */\n", .{ |
| 301 | | name_cty.fmtTypeName(zcu), |
| 302 | | array_cty.fmtDeclaratorPrefix(zcu), |
| 303 | | array_cty.fmtDeclaratorSuffix(zcu), |
| 304 | | ty.fmt(pt), |
| 305 | | }); |
| 306 | | } else { |
| 307 | | try w.print("zig_packed({f} {{ zig_under_align({d}) {f}array{f}; }}); /* {f} */\n", .{ |
| 308 | | name_cty.fmtTypeName(zcu), |
| 309 | | elem_ty.abiAlignment(zcu).toByteUnits().?, |
| 310 | | array_cty.fmtDeclaratorPrefix(zcu), |
| 311 | | array_cty.fmtDeclaratorSuffix(zcu), |
| 312 | | ty.fmt(pt), |
| 313 | | }); |
| 314 | | } |
| 298 | try w.print("{f} {{ {f}array{f}; }}; /* {f} */\n", .{ |
| 299 | name_cty.fmtTypeName(zcu), |
| 300 | array_cty.fmtDeclaratorPrefix(zcu), |
| 301 | array_cty.fmtDeclaratorSuffix(zcu), |
| 302 | ty.fmt(pt), |
| 303 | }); |
| 315 | 304 | try writeStaticAssertLayout(ty, name_cty, w, zcu); |
| 316 | 305 | }, |
| 317 | 306 | .vector => if (ty.hasRuntimeBits(zcu)) { |
| 318 | | const elem_ty = ty.childType(zcu); |
| 319 | 307 | const name_cty: CType = .{ .vec = ty }; |
| 320 | | const elem_cty: CType = try .lower(elem_ty, deps, arena, zcu); |
| 308 | const elem_cty: CType = try .lower(ty.childType(zcu), deps, arena, zcu); |
| 321 | 309 | const array_cty: CType = .{ .array = .{ |
| 322 | 310 | .len = ty.arrayLenIncludingSentinel(zcu), |
| 323 | 311 | .elem_ty = &elem_cty, |
| ... | ... | @@ -363,39 +351,21 @@ fn defineTuple( |
| 363 | 351 | const ip = &zcu.intern_pool; |
| 364 | 352 | const tuple = ip.indexToKey(ty.toIntern()).tuple_type; |
| 365 | 353 | |
| 366 | | const tuple_align = ty.abiAlignment(zcu); |
| 354 | // Fields cannot be underaligned, because tuple fields cannot have specified alignments. |
| 355 | // However, overaligned fields are possible thanks to intermediate zero-bit fields. |
| 367 | 356 | |
| 368 | | // If there are any underaligned fields, we need to byte-pack the tuple. |
| 369 | | const pack: bool = pack: { |
| 370 | | var offset: u64 = 0; |
| 371 | | for (tuple.types.get(ip)) |field_ty_ip| { |
| 372 | | const field_ty: Type = .fromInterned(field_ty_ip); |
| 373 | | if (!field_ty.hasRuntimeBits(zcu)) continue; |
| 374 | | const natural_align = field_ty.defaultStructFieldAlignment(.auto, zcu); |
| 375 | | const natural_offset = natural_align.forward(offset); |
| 376 | | offset = field_ty.abiAlignment(zcu).forward(offset); |
| 377 | | if (offset < natural_offset) break :pack true; |
| 378 | | // Also pack if any field is more aligned than the tuple should be. |
| 379 | | if (natural_align.compareStrict(.gt, tuple_align)) break :pack true; |
| 380 | | offset += field_ty.abiSize(zcu); |
| 381 | | } |
| 382 | | break :pack false; |
| 383 | | }; |
| 357 | const tuple_align = ty.abiAlignment(zcu); |
| 384 | 358 | |
| 385 | 359 | // If the alignment of other fields would not give the tuple sufficient alignment, we |
| 386 | 360 | // need to align the first field (which does not affect its offset, because 0 is always |
| 387 | 361 | // well-aligned) to indirectly specify the tuple alignment. |
| 388 | | const overalign: bool = switch (pack) { |
| 389 | | true => tuple_align.compareStrict(.gt, .@"1"), |
| 390 | | false => for (tuple.types.get(ip)) |field_ty_ip| { |
| 391 | | const field_ty: Type = .fromInterned(field_ty_ip); |
| 392 | | if (!field_ty.hasRuntimeBits(zcu)) continue; |
| 393 | | const natural_align = field_ty.defaultStructFieldAlignment(.auto, zcu); |
| 394 | | if (natural_align.compareStrict(.gte, tuple_align)) break false; |
| 395 | | } else true, |
| 396 | | }; |
| 362 | const overalign: bool = for (tuple.types.get(ip)) |field_ty_ip| { |
| 363 | const field_ty: Type = .fromInterned(field_ty_ip); |
| 364 | if (!field_ty.hasRuntimeBits(zcu)) continue; |
| 365 | const natural_align = field_ty.defaultStructFieldAlignment(.auto, zcu); |
| 366 | if (natural_align.compareStrict(.gte, tuple_align)) break false; |
| 367 | } else true; |
| 397 | 368 | |
| 398 | | if (pack) try w.writeAll("zig_packed("); |
| 399 | 369 | const name_cty: CType = .{ .@"struct" = ty }; |
| 400 | 370 | try w.print("{f} {{ /* {f} */\n", .{ |
| 401 | 371 | name_cty.fmtTypeName(zcu), |
| ... | ... | @@ -406,18 +376,18 @@ fn defineTuple( |
| 406 | 376 | for (tuple.types.get(ip), tuple.values.get(ip), 0..) |field_ty_ip, field_val_ip, field_index| { |
| 407 | 377 | if (field_val_ip != .none) continue; // `comptime` field |
| 408 | 378 | const field_ty: Type = .fromInterned(field_ty_ip); |
| 409 | | zig_offset = field_ty.abiAlignment(zcu).forward(zig_offset); |
| 379 | const field_align = field_ty.abiAlignment(zcu); |
| 380 | zig_offset = field_align.forward(zig_offset); |
| 410 | 381 | if (!field_ty.hasRuntimeBits(zcu)) continue; |
| 411 | | if (!pack) c_offset = field_ty.defaultStructFieldAlignment(.auto, zcu).forward(c_offset); |
| 382 | c_offset = field_align.forward(c_offset); |
| 412 | 383 | try w.writeByte(' '); |
| 413 | 384 | if (zig_offset == 0 and overalign) { |
| 414 | 385 | // This is the first field; specify its alignment to align the tuple. |
| 415 | 386 | try writeFieldAlign(field_ty, tuple_align, w, zcu); |
| 416 | 387 | } else if (zig_offset > c_offset) { |
| 417 | | // This field needs to be underaligned or overaligned compared to what its |
| 418 | | // offset would otherwise be. |
| 388 | // This field needs to be overaligned compared to what its offset would otherwise be. |
| 419 | 389 | const need_align: Alignment = .minStrict( |
| 420 | | tuple_align, // don't make the tuple more aligned than it should be |
| 390 | tuple_align, // don't make the struct more aligned than it should be |
| 421 | 391 | .fromLog2Units(@ctz(zig_offset)), |
| 422 | 392 | ); |
| 423 | 393 | try writeFieldAlign(field_ty, need_align, w, zcu); |
| ... | ... | @@ -433,9 +403,7 @@ fn defineTuple( |
| 433 | 403 | zig_offset += field_size; |
| 434 | 404 | c_offset += field_size; |
| 435 | 405 | } |
| 436 | | try w.writeByte('}'); |
| 437 | | if (pack) try w.writeByte(')'); |
| 438 | | try w.writeAll(";\n"); |
| 406 | try w.writeAll("};\n"); |
| 439 | 407 | |
| 440 | 408 | try writeStaticAssertLayout(ty, name_cty, w, zcu); |
| 441 | 409 | } |
| ... | ... | @@ -553,7 +521,7 @@ fn defineUnionAuto( |
| 553 | 521 | const pack: bool = for (union_type.field_types.get(ip)) |field_ty_ip| { |
| 554 | 522 | const field_ty: Type = .fromInterned(field_ty_ip); |
| 555 | 523 | if (!field_ty.hasRuntimeBits(zcu)) continue; |
| 556 | | const natural_align = field_ty.defaultStructFieldAlignment(.auto, zcu); |
| 524 | const natural_align = field_ty.abiAlignment(zcu); |
| 557 | 525 | if (natural_align.compareStrict(.gt, union_type.alignment)) break true; |
| 558 | 526 | // The tag will immediately follow the payload. This layout may put the tag in what would |
| 559 | 527 | // otherwise be padding on the payload union, because if the most-aligned union field is not |
| ... | ... | @@ -571,7 +539,7 @@ fn defineUnionAuto( |
| 571 | 539 | false => for (union_type.field_types.get(ip)) |field_ty_ip| { |
| 572 | 540 | const field_ty: Type = .fromInterned(field_ty_ip); |
| 573 | 541 | if (!field_ty.hasRuntimeBits(zcu)) continue; |
| 574 | | const natural_align = field_ty.defaultStructFieldAlignment(.auto, zcu); |
| 542 | const natural_align = field_ty.abiAlignment(zcu); |
| 575 | 543 | if (natural_align.compareStrict(.gte, union_type.alignment)) break false; |
| 576 | 544 | } else overalign: { |
| 577 | 545 | if (union_type.has_runtime_tag) { |
| ... | ... | @@ -642,7 +610,7 @@ fn defineUnionExtern( |
| 642 | 610 | const pack: bool = for (union_type.field_types.get(ip)) |field_ty_ip| { |
| 643 | 611 | const field_ty: Type = .fromInterned(field_ty_ip); |
| 644 | 612 | if (!field_ty.hasRuntimeBits(zcu)) continue; |
| 645 | | const natural_align = field_ty.defaultStructFieldAlignment(.@"extern", zcu); |
| 613 | const natural_align = field_ty.abiAlignment(zcu); |
| 646 | 614 | if (natural_align.compareStrict(.gt, union_type.alignment)) break true; |
| 647 | 615 | } else false; |
| 648 | 616 | |
| ... | ... | @@ -654,7 +622,7 @@ fn defineUnionExtern( |
| 654 | 622 | false => for (union_type.field_types.get(ip)) |field_ty_ip| { |
| 655 | 623 | const field_ty: Type = .fromInterned(field_ty_ip); |
| 656 | 624 | if (!field_ty.hasRuntimeBits(zcu)) continue; |
| 657 | | const natural_align = field_ty.defaultStructFieldAlignment(.@"extern", zcu); |
| 625 | const natural_align = field_ty.abiAlignment(zcu); |
| 658 | 626 | if (natural_align.compareStrict(.gte, union_type.alignment)) break false; |
| 659 | 627 | } else overalign: { |
| 660 | 628 | if (union_type.has_runtime_tag) { |
| ... | ... | @@ -704,7 +672,7 @@ fn writeFieldAlign( |
| 704 | 672 | w: *Writer, |
| 705 | 673 | zcu: *const Zcu, |
| 706 | 674 | ) Writer.Error!void { |
| 707 | | if (alignment.compareStrict(.lt, ty.defaultStructFieldAlignment(.auto, zcu))) { |
| 675 | if (alignment.compareStrict(.lt, ty.abiAlignment(zcu))) { |
| 708 | 676 | try w.print("zig_under_align({d}) ", .{alignment.toByteUnits().?}); |
| 709 | 677 | } else { |
| 710 | 678 | try w.print("zig_align({d}) ", .{alignment.toByteUnits().?}); |