authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-05-05 12:53:23-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-05-05 12:53:23-04:00
log59905a62f9da9946a797cc35a2523c9929663600
tree93ca52f59d1803fca320819fc5a7058fbb58e61b
parent49a7ceb5bcd87d8aeb7b25f8b2972ad4ec0b9e24
parent44252f4d352d53afd86d678c0b0a40b3f681c7eb
signature Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #11583 from ziglang/stage2-test-behavior

stage2 behavior tests for all targets passing with the LLVM backend

17 files changed, 505 insertions(+), 210 deletions(-)

lib/std/target.zig+82
...@@ -1773,6 +1773,88 @@ pub const Target = struct {...@@ -1773,6 +1773,88 @@ pub const Target = struct {
1773 else => false,1773 else => false,
1774 };1774 };
1775 }1775 }
1776
1777 pub inline fn maxIntAlignment(target: Target) u16 {
1778 return switch (target.cpu.arch) {
1779 .avr => 1,
1780 .msp430 => 2,
1781 .xcore => 4,
1782
1783 .arm,
1784 .armeb,
1785 .thumb,
1786 .thumbeb,
1787 .hexagon,
1788 .mips,
1789 .mipsel,
1790 .powerpc,
1791 .powerpcle,
1792 .r600,
1793 .amdgcn,
1794 .riscv32,
1795 .sparc,
1796 .sparcel,
1797 .s390x,
1798 .lanai,
1799 .wasm32,
1800 .wasm64,
1801 => 8,
1802
1803 .i386 => return switch (target.os.tag) {
1804 .windows => 8,
1805 else => 4,
1806 },
1807
1808 // For x86_64, LLVMABIAlignmentOfType(i128) reports 8. However I think 16
1809 // is a better number for two reasons:
1810 // 1. Better machine code when loading into SIMD register.
1811 // 2. The C ABI wants 16 for extern structs.
1812 // 3. 16-byte cmpxchg needs 16-byte alignment.
1813 // Same logic for riscv64, powerpc64, mips64, sparcv9.
1814 .x86_64,
1815 .riscv64,
1816 .powerpc64,
1817 .powerpc64le,
1818 .mips64,
1819 .mips64el,
1820 .sparcv9,
1821
1822 // Even LLVMABIAlignmentOfType(i128) agrees on these targets.
1823 .aarch64,
1824 .aarch64_be,
1825 .aarch64_32,
1826 .bpfel,
1827 .bpfeb,
1828 .nvptx,
1829 .nvptx64,
1830 => 16,
1831
1832 // Below this comment are unverified but based on the fact that C requires
1833 // int128_t to be 16 bytes aligned, it's a safe default.
1834 .spu_2,
1835 .csky,
1836 .arc,
1837 .m68k,
1838 .tce,
1839 .tcele,
1840 .le32,
1841 .amdil,
1842 .hsail,
1843 .spir,
1844 .kalimba,
1845 .renderscript32,
1846 .spirv32,
1847 .shave,
1848 .le64,
1849 .amdil64,
1850 .hsail64,
1851 .spir64,
1852 .renderscript64,
1853 .ve,
1854 .spirv64,
1855 => 16,
1856 };
1857 }
1776};1858};
17771859
1778test {1860test {
src/AstGen.zig+10-50
...@@ -7423,42 +7423,22 @@ fn builtinCall(...@@ -7423,42 +7423,22 @@ fn builtinCall(
7423 },7423 },
74247424
7425 .atomic_load => {7425 .atomic_load => {
7426 const int_type = try typeExpr(gz, scope, params[0]);7426 const result = try gz.addPlNode(.atomic_load, node, Zir.Inst.AtomicLoad{
7427 // TODO allow this pointer type to be volatile
7428 const ptr_type = try gz.add(.{ .tag = .ptr_type_simple, .data = .{
7429 .ptr_type_simple = .{
7430 .is_allowzero = false,
7431 .is_mutable = false,
7432 .is_volatile = false,
7433 .size = .One,
7434 .elem_type = int_type,
7435 },
7436 } });
7437 const result = try gz.addPlNode(.atomic_load, node, Zir.Inst.Bin{
7438 // zig fmt: off7427 // zig fmt: off
7439 .lhs = try expr(gz, scope, .{ .coerced_ty = ptr_type }, params[1]),7428 .elem_type = try typeExpr(gz, scope, params[0]),
7440 .rhs = try expr(gz, scope, .{ .coerced_ty = .atomic_order_type }, params[2]),7429 .ptr = try expr (gz, scope, .none, params[1]),
7430 .ordering = try expr (gz, scope, .{ .coerced_ty = .atomic_order_type }, params[2]),
7441 // zig fmt: on7431 // zig fmt: on
7442 });7432 });
7443 return rvalue(gz, rl, result, node);7433 return rvalue(gz, rl, result, node);
7444 },7434 },
7445 .atomic_rmw => {7435 .atomic_rmw => {
7446 const int_type = try typeExpr(gz, scope, params[0]);7436 const int_type = try typeExpr(gz, scope, params[0]);
7447 // TODO allow this pointer type to be volatile
7448 const ptr_type = try gz.add(.{ .tag = .ptr_type_simple, .data = .{
7449 .ptr_type_simple = .{
7450 .is_allowzero = false,
7451 .is_mutable = true,
7452 .is_volatile = false,
7453 .size = .One,
7454 .elem_type = int_type,
7455 },
7456 } });
7457 const result = try gz.addPlNode(.atomic_rmw, node, Zir.Inst.AtomicRmw{7437 const result = try gz.addPlNode(.atomic_rmw, node, Zir.Inst.AtomicRmw{
7458 // zig fmt: off7438 // zig fmt: off
7459 .ptr = try expr(gz, scope, .{ .coerced_ty = ptr_type }, params[1]),7439 .ptr = try expr(gz, scope, .none, params[1]),
7460 .operation = try expr(gz, scope, .{ .coerced_ty = .atomic_rmw_op_type }, params[2]),7440 .operation = try expr(gz, scope, .{ .coerced_ty = .atomic_rmw_op_type }, params[2]),
7461 .operand = try expr(gz, scope, .{ .coerced_ty = int_type }, params[3]),7441 .operand = try expr(gz, scope, .{ .ty = int_type }, params[3]),
7462 .ordering = try expr(gz, scope, .{ .coerced_ty = .atomic_order_type }, params[4]),7442 .ordering = try expr(gz, scope, .{ .coerced_ty = .atomic_order_type }, params[4]),
7463 // zig fmt: on7443 // zig fmt: on
7464 });7444 });
...@@ -7466,20 +7446,10 @@ fn builtinCall(...@@ -7466,20 +7446,10 @@ fn builtinCall(
7466 },7446 },
7467 .atomic_store => {7447 .atomic_store => {
7468 const int_type = try typeExpr(gz, scope, params[0]);7448 const int_type = try typeExpr(gz, scope, params[0]);
7469 // TODO allow this pointer type to be volatile
7470 const ptr_type = try gz.add(.{ .tag = .ptr_type_simple, .data = .{
7471 .ptr_type_simple = .{
7472 .is_allowzero = false,
7473 .is_mutable = true,
7474 .is_volatile = false,
7475 .size = .One,
7476 .elem_type = int_type,
7477 },
7478 } });
7479 const result = try gz.addPlNode(.atomic_store, node, Zir.Inst.AtomicStore{7449 const result = try gz.addPlNode(.atomic_store, node, Zir.Inst.AtomicStore{
7480 // zig fmt: off7450 // zig fmt: off
7481 .ptr = try expr(gz, scope, .{ .coerced_ty = ptr_type }, params[1]),7451 .ptr = try expr(gz, scope, .none, params[1]),
7482 .operand = try expr(gz, scope, .{ .coerced_ty = int_type }, params[2]),7452 .operand = try expr(gz, scope, .{ .ty = int_type }, params[2]),
7483 .ordering = try expr(gz, scope, .{ .coerced_ty = .atomic_order_type }, params[3]),7453 .ordering = try expr(gz, scope, .{ .coerced_ty = .atomic_order_type }, params[3]),
7484 // zig fmt: on7454 // zig fmt: on
7485 });7455 });
...@@ -7684,20 +7654,10 @@ fn cmpxchg(...@@ -7684,20 +7654,10 @@ fn cmpxchg(
7684 tag: Zir.Inst.Tag,7654 tag: Zir.Inst.Tag,
7685) InnerError!Zir.Inst.Ref {7655) InnerError!Zir.Inst.Ref {
7686 const int_type = try typeExpr(gz, scope, params[0]);7656 const int_type = try typeExpr(gz, scope, params[0]);
7687 // TODO: allow this to be volatile
7688 const ptr_type = try gz.add(.{ .tag = .ptr_type_simple, .data = .{
7689 .ptr_type_simple = .{
7690 .is_allowzero = false,
7691 .is_mutable = true,
7692 .is_volatile = false,
7693 .size = .One,
7694 .elem_type = int_type,
7695 },
7696 } });
7697 const result = try gz.addPlNode(tag, node, Zir.Inst.Cmpxchg{7657 const result = try gz.addPlNode(tag, node, Zir.Inst.Cmpxchg{
7698 // zig fmt: off7658 // zig fmt: off
7699 .ptr = try expr(gz, scope, .{ .coerced_ty = ptr_type }, params[1]),7659 .ptr = try expr(gz, scope, .none, params[1]),
7700 .expected_value = try expr(gz, scope, .{ .coerced_ty = int_type }, params[2]),7660 .expected_value = try expr(gz, scope, .{ .ty = int_type }, params[2]),
7701 .new_value = try expr(gz, scope, .{ .coerced_ty = int_type }, params[3]),7661 .new_value = try expr(gz, scope, .{ .coerced_ty = int_type }, params[3]),
7702 .success_order = try expr(gz, scope, .{ .coerced_ty = .atomic_order_type }, params[4]),7662 .success_order = try expr(gz, scope, .{ .coerced_ty = .atomic_order_type }, params[4]),
7703 .failure_order = try expr(gz, scope, .{ .coerced_ty = .atomic_order_type }, params[5]),7663 .failure_order = try expr(gz, scope, .{ .coerced_ty = .atomic_order_type }, params[5]),
src/Module.zig+15
...@@ -151,6 +151,8 @@ allocated_decls: std.SegmentedList(Decl, 0) = .{},...@@ -151,6 +151,8 @@ allocated_decls: std.SegmentedList(Decl, 0) = .{},
151/// When a Decl object is freed from `allocated_decls`, it is pushed into this stack.151/// When a Decl object is freed from `allocated_decls`, it is pushed into this stack.
152decls_free_list: std.ArrayListUnmanaged(Decl.Index) = .{},152decls_free_list: std.ArrayListUnmanaged(Decl.Index) = .{},
153153
154global_assembly: std.AutoHashMapUnmanaged(Decl.Index, []u8) = .{},
155
154const MonomorphedFuncsSet = std.HashMapUnmanaged(156const MonomorphedFuncsSet = std.HashMapUnmanaged(
155 *Fn,157 *Fn,
156 void,158 void,
...@@ -2831,6 +2833,7 @@ pub fn deinit(mod: *Module) void {...@@ -2831,6 +2833,7 @@ pub fn deinit(mod: *Module) void {
28312833
2832 mod.decls_free_list.deinit(gpa);2834 mod.decls_free_list.deinit(gpa);
2833 mod.allocated_decls.deinit(gpa);2835 mod.allocated_decls.deinit(gpa);
2836 mod.global_assembly.deinit(gpa);
2834}2837}
28352838
2836pub fn destroyDecl(mod: *Module, decl_index: Decl.Index) void {2839pub fn destroyDecl(mod: *Module, decl_index: Decl.Index) void {
...@@ -2842,6 +2845,9 @@ pub fn destroyDecl(mod: *Module, decl_index: Decl.Index) void {...@@ -2842,6 +2845,9 @@ pub fn destroyDecl(mod: *Module, decl_index: Decl.Index) void {
2842 if (decl.deletion_flag) {2845 if (decl.deletion_flag) {
2843 assert(mod.deletion_set.swapRemove(decl_index));2846 assert(mod.deletion_set.swapRemove(decl_index));
2844 }2847 }
2848 if (mod.global_assembly.fetchRemove(decl_index)) |kv| {
2849 gpa.free(kv.value);
2850 }
2845 if (decl.has_tv) {2851 if (decl.has_tv) {
2846 if (decl.getInnerNamespace()) |namespace| {2852 if (decl.getInnerNamespace()) |namespace| {
2847 namespace.destroyDecls(mod);2853 namespace.destroyDecls(mod);
...@@ -5714,3 +5720,12 @@ pub fn markDeclAlive(mod: *Module, decl: *Decl) void {...@@ -5714,3 +5720,12 @@ pub fn markDeclAlive(mod: *Module, decl: *Decl) void {
5714fn markDeclIndexAlive(mod: *Module, decl_index: Decl.Index) void {5720fn markDeclIndexAlive(mod: *Module, decl_index: Decl.Index) void {
5715 return mod.markDeclAlive(mod.declPtr(decl_index));5721 return mod.markDeclAlive(mod.declPtr(decl_index));
5716}5722}
5723
5724pub fn addGlobalAssembly(mod: *Module, decl_index: Decl.Index, source: []const u8) !void {
5725 try mod.global_assembly.ensureUnusedCapacity(mod.gpa, 1);
5726
5727 const duped_source = try mod.gpa.dupe(u8, source);
5728 errdefer mod.gpa.free(duped_source);
5729
5730 mod.global_assembly.putAssumeCapacityNoClobber(decl_index, duped_source);
5731}
src/Sema.zig+110-80
...@@ -10517,16 +10517,35 @@ fn zirAsm(...@@ -10517,16 +10517,35 @@ fn zirAsm(
10517 const is_volatile = @truncate(u1, extended.small >> 15) != 0;10517 const is_volatile = @truncate(u1, extended.small >> 15) != 0;
10518 const is_global_assembly = sema.func == null;10518 const is_global_assembly = sema.func == null;
1051910519
10520 if (block.is_comptime and !is_global_assembly) {
10521 try sema.requireRuntimeBlock(block, src);
10522 }
10523
10524 if (extra.data.asm_source == 0) {10520 if (extra.data.asm_source == 0) {
10525 // This can move to become an AstGen error after inline assembly improvements land10521 // This can move to become an AstGen error after inline assembly improvements land
10526 // and stage1 code matches stage2 code.10522 // and stage1 code matches stage2 code.
10527 return sema.fail(block, src, "assembly code must use string literal syntax", .{});10523 return sema.fail(block, src, "assembly code must use string literal syntax", .{});
10528 }10524 }
1052910525
10526 const asm_source = sema.code.nullTerminatedString(extra.data.asm_source);
10527
10528 if (is_global_assembly) {
10529 if (outputs_len != 0) {
10530 return sema.fail(block, src, "module-level assembly does not support outputs", .{});
10531 }
10532 if (inputs_len != 0) {
10533 return sema.fail(block, src, "module-level assembly does not support inputs", .{});
10534 }
10535 if (clobbers_len != 0) {
10536 return sema.fail(block, src, "module-level assembly does not support clobbers", .{});
10537 }
10538 if (is_volatile) {
10539 return sema.fail(block, src, "volatile keyword is redundant on module-level assembly", .{});
10540 }
10541 try sema.mod.addGlobalAssembly(sema.owner_decl_index, asm_source);
10542 return Air.Inst.Ref.void_value;
10543 }
10544
10545 if (block.is_comptime) {
10546 try sema.requireRuntimeBlock(block, src);
10547 }
10548
10530 if (outputs_len > 1) {10549 if (outputs_len > 1) {
10531 return sema.fail(block, src, "TODO implement Sema for asm with more than 1 output", .{});10550 return sema.fail(block, src, "TODO implement Sema for asm with more than 1 output", .{});
10532 }10551 }
...@@ -10591,7 +10610,6 @@ fn zirAsm(...@@ -10591,7 +10610,6 @@ fn zirAsm(
10591 needed_capacity += name.*.len / 4 + 1;10610 needed_capacity += name.*.len / 4 + 1;
10592 }10611 }
1059310612
10594 const asm_source = sema.code.nullTerminatedString(extra.data.asm_source);
10595 needed_capacity += (asm_source.len + 3) / 4;10613 needed_capacity += (asm_source.len + 3) / 4;
1059610614
10597 const gpa = sema.gpa;10615 const gpa = sema.gpa;
...@@ -14715,51 +14733,64 @@ fn checkNumericType(...@@ -14715,51 +14733,64 @@ fn checkNumericType(
14715 }14733 }
14716}14734}
1471714735
14718fn checkAtomicOperandType(14736/// Returns the casted pointer.
14737fn checkAtomicPtrOperand(
14719 sema: *Sema,14738 sema: *Sema,
14720 block: *Block,14739 block: *Block,
14721 ty_src: LazySrcLoc,14740 elem_ty: Type,
14722 ty: Type,14741 elem_ty_src: LazySrcLoc,
14723) CompileError!void {14742 ptr: Air.Inst.Ref,
14724 var buffer: Type.Payload.Bits = undefined;14743 ptr_src: LazySrcLoc,
14744 ptr_const: bool,
14745) CompileError!Air.Inst.Ref {
14725 const target = sema.mod.getTarget();14746 const target = sema.mod.getTarget();
14726 const max_atomic_bits = target_util.largestAtomicBits(target);14747 var diag: target_util.AtomicPtrAlignmentDiagnostics = .{};
14727 const int_ty = switch (ty.zigTypeTag()) {14748 const alignment = target_util.atomicPtrAlignment(target, elem_ty, &diag) catch |err| switch (err) {
14728 .Int => ty,14749 error.FloatTooBig => return sema.fail(
14729 .Enum => ty.intTagType(&buffer),14750 block,
14730 .Float => {14751 elem_ty_src,
14731 const bit_count = ty.floatBits(target);14752 "expected {d}-bit float type or smaller; found {d}-bit float type",
14732 if (bit_count > max_atomic_bits) {14753 .{ diag.max_bits, diag.bits },
14733 return sema.fail(14754 ),
14734 block,14755 error.IntTooBig => return sema.fail(
14735 ty_src,14756 block,
14736 "expected {d}-bit float type or smaller; found {d}-bit float type",14757 elem_ty_src,
14737 .{ max_atomic_bits, bit_count },14758 "expected {d}-bit integer type or smaller; found {d}-bit integer type",
14738 );14759 .{ diag.max_bits, diag.bits },
14739 }14760 ),
14740 return;14761 error.BadType => return sema.fail(
14741 },14762 block,
14742 .Bool => return, // Will be treated as `u8`.14763 elem_ty_src,
14743 else => {14764 "expected bool, integer, float, enum, or pointer type; found {}",
14744 if (ty.isPtrAtRuntime()) return;14765 .{elem_ty.fmt(sema.mod)},
14766 ),
14767 };
1474514768
14746 return sema.fail(14769 var wanted_ptr_data: Type.Payload.Pointer.Data = .{
14747 block,14770 .pointee_type = elem_ty,
14748 ty_src,14771 .@"align" = alignment,
14749 "expected bool, integer, float, enum, or pointer type; found {}",14772 .@"addrspace" = .generic,
14750 .{ty.fmt(sema.mod)},14773 .mutable = !ptr_const,
14751 );14774 };
14775
14776 const ptr_ty = sema.typeOf(ptr);
14777 const ptr_data = switch (try ptr_ty.zigTypeTagOrPoison()) {
14778 .Pointer => ptr_ty.ptrInfo().data,
14779 else => {
14780 const wanted_ptr_ty = try Type.ptr(sema.arena, sema.mod, wanted_ptr_data);
14781 _ = try sema.coerce(block, wanted_ptr_ty, ptr, ptr_src);
14782 unreachable;
14752 },14783 },
14753 };14784 };
14754 const bit_count = int_ty.intInfo(target).bits;14785
14755 if (bit_count > max_atomic_bits) {14786 wanted_ptr_data.@"addrspace" = ptr_data.@"addrspace";
14756 return sema.fail(14787 wanted_ptr_data.@"allowzero" = ptr_data.@"allowzero";
14757 block,14788 wanted_ptr_data.@"volatile" = ptr_data.@"volatile";
14758 ty_src,14789
14759 "expected {d}-bit integer type or smaller; found {d}-bit integer type",14790 const wanted_ptr_ty = try Type.ptr(sema.arena, sema.mod, wanted_ptr_data);
14760 .{ max_atomic_bits, bit_count },14791 const casted_ptr = try sema.coerce(block, wanted_ptr_ty, ptr, ptr_src);
14761 );14792
14762 }14793 return casted_ptr;
14763}14794}
1476414795
14765fn checkPtrIsNotComptimeMutable(14796fn checkPtrIsNotComptimeMutable(
...@@ -15036,10 +15067,8 @@ fn zirCmpxchg(...@@ -15036,10 +15067,8 @@ fn zirCmpxchg(
15036 const success_order_src: LazySrcLoc = .{ .node_offset_builtin_call_arg4 = inst_data.src_node };15067 const success_order_src: LazySrcLoc = .{ .node_offset_builtin_call_arg4 = inst_data.src_node };
15037 const failure_order_src: LazySrcLoc = .{ .node_offset_builtin_call_arg5 = inst_data.src_node };15068 const failure_order_src: LazySrcLoc = .{ .node_offset_builtin_call_arg5 = inst_data.src_node };
15038 // zig fmt: on15069 // zig fmt: on
15039 const ptr = sema.resolveInst(extra.ptr);15070 const expected_value = sema.resolveInst(extra.expected_value);
15040 const ptr_ty = sema.typeOf(ptr);15071 const elem_ty = sema.typeOf(expected_value);
15041 const elem_ty = ptr_ty.elemType();
15042 try sema.checkAtomicOperandType(block, elem_ty_src, elem_ty);
15043 if (elem_ty.zigTypeTag() == .Float) {15072 if (elem_ty.zigTypeTag() == .Float) {
15044 return sema.fail(15073 return sema.fail(
15045 block,15074 block,
...@@ -15048,7 +15077,8 @@ fn zirCmpxchg(...@@ -15048,7 +15077,8 @@ fn zirCmpxchg(
15048 .{elem_ty.fmt(sema.mod)},15077 .{elem_ty.fmt(sema.mod)},
15049 );15078 );
15050 }15079 }
15051 const expected_value = try sema.coerce(block, elem_ty, sema.resolveInst(extra.expected_value), expected_src);15080 const uncasted_ptr = sema.resolveInst(extra.ptr);
15081 const ptr = try sema.checkAtomicPtrOperand(block, elem_ty, elem_ty_src, uncasted_ptr, ptr_src, false);
15052 const new_value = try sema.coerce(block, elem_ty, sema.resolveInst(extra.new_value), new_value_src);15082 const new_value = try sema.coerce(block, elem_ty, sema.resolveInst(extra.new_value), new_value_src);
15053 const success_order = try sema.resolveAtomicOrder(block, success_order_src, extra.success_order);15083 const success_order = try sema.resolveAtomicOrder(block, success_order_src, extra.success_order);
15054 const failure_order = try sema.resolveAtomicOrder(block, failure_order_src, extra.failure_order);15084 const failure_order = try sema.resolveAtomicOrder(block, failure_order_src, extra.failure_order);
...@@ -15081,6 +15111,7 @@ fn zirCmpxchg(...@@ -15081,6 +15111,7 @@ fn zirCmpxchg(
15081 // to become undef as well15111 // to become undef as well
15082 return sema.addConstUndef(result_ty);15112 return sema.addConstUndef(result_ty);
15083 }15113 }
15114 const ptr_ty = sema.typeOf(ptr);
15084 const stored_val = (try sema.pointerDeref(block, ptr_src, ptr_val, ptr_ty)) orelse break :rs ptr_src;15115 const stored_val = (try sema.pointerDeref(block, ptr_src, ptr_val, ptr_ty)) orelse break :rs ptr_src;
15085 const result_val = if (stored_val.eql(expected_val, elem_ty, sema.mod)) blk: {15116 const result_val = if (stored_val.eql(expected_val, elem_ty, sema.mod)) blk: {
15086 try sema.storePtr(block, src, ptr, new_value);15117 try sema.storePtr(block, src, ptr, new_value);
...@@ -15487,17 +15518,16 @@ fn zirSelect(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air....@@ -15487,17 +15518,16 @@ fn zirSelect(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
1548715518
15488fn zirAtomicLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {15519fn zirAtomicLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
15489 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;15520 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
15490 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;15521 const extra = sema.code.extraData(Zir.Inst.AtomicLoad, inst_data.payload_index).data;
15491 // zig fmt: off15522 // zig fmt: off
15492 const elem_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };15523 const elem_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
15493 const ptr_src : LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };15524 const ptr_src : LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
15494 const order_src : LazySrcLoc = .{ .node_offset_builtin_call_arg2 = inst_data.src_node };15525 const order_src : LazySrcLoc = .{ .node_offset_builtin_call_arg2 = inst_data.src_node };
15495 // zig fmt: on15526 // zig fmt: on
15496 const ptr = sema.resolveInst(extra.lhs);15527 const elem_ty = try sema.resolveType(block, elem_ty_src, extra.elem_type);
15497 const ptr_ty = sema.typeOf(ptr);15528 const uncasted_ptr = sema.resolveInst(extra.ptr);
15498 const elem_ty = ptr_ty.elemType();15529 const ptr = try sema.checkAtomicPtrOperand(block, elem_ty, elem_ty_src, uncasted_ptr, ptr_src, true);
15499 try sema.checkAtomicOperandType(block, elem_ty_src, elem_ty);15530 const order = try sema.resolveAtomicOrder(block, order_src, extra.ordering);
15500 const order = try sema.resolveAtomicOrder(block, order_src, extra.rhs);
1550115531
15502 switch (order) {15532 switch (order) {
15503 .Release, .AcqRel => {15533 .Release, .AcqRel => {
...@@ -15516,7 +15546,7 @@ fn zirAtomicLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!...@@ -15516,7 +15546,7 @@ fn zirAtomicLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
15516 }15546 }
1551715547
15518 if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| {15548 if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| {
15519 if (try sema.pointerDeref(block, ptr_src, ptr_val, ptr_ty)) |elem_val| {15549 if (try sema.pointerDeref(block, ptr_src, ptr_val, sema.typeOf(ptr))) |elem_val| {
15520 return sema.addConstant(elem_ty, elem_val);15550 return sema.addConstant(elem_ty, elem_val);
15521 }15551 }
15522 }15552 }
...@@ -15536,19 +15566,19 @@ fn zirAtomicRmw(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A...@@ -15536,19 +15566,19 @@ fn zirAtomicRmw(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
15536 const extra = sema.code.extraData(Zir.Inst.AtomicRmw, inst_data.payload_index).data;15566 const extra = sema.code.extraData(Zir.Inst.AtomicRmw, inst_data.payload_index).data;
15537 const src = inst_data.src();15567 const src = inst_data.src();
15538 // zig fmt: off15568 // zig fmt: off
15539 const operand_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };15569 const elem_ty_src : LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
15540 const ptr_src : LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };15570 const ptr_src : LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
15541 const op_src : LazySrcLoc = .{ .node_offset_builtin_call_arg2 = inst_data.src_node };15571 const op_src : LazySrcLoc = .{ .node_offset_builtin_call_arg2 = inst_data.src_node };
15542 const operand_src : LazySrcLoc = .{ .node_offset_builtin_call_arg3 = inst_data.src_node };15572 const operand_src : LazySrcLoc = .{ .node_offset_builtin_call_arg3 = inst_data.src_node };
15543 const order_src : LazySrcLoc = .{ .node_offset_builtin_call_arg4 = inst_data.src_node };15573 const order_src : LazySrcLoc = .{ .node_offset_builtin_call_arg4 = inst_data.src_node };
15544 // zig fmt: on15574 // zig fmt: on
15545 const ptr = sema.resolveInst(extra.ptr);15575 const operand = sema.resolveInst(extra.operand);
15546 const ptr_ty = sema.typeOf(ptr);15576 const elem_ty = sema.typeOf(operand);
15547 const operand_ty = ptr_ty.elemType();15577 const uncasted_ptr = sema.resolveInst(extra.ptr);
15548 try sema.checkAtomicOperandType(block, operand_ty_src, operand_ty);15578 const ptr = try sema.checkAtomicPtrOperand(block, elem_ty, elem_ty_src, uncasted_ptr, ptr_src, false);
15549 const op = try sema.resolveAtomicRmwOp(block, op_src, extra.operation);15579 const op = try sema.resolveAtomicRmwOp(block, op_src, extra.operation);
1555015580
15551 switch (operand_ty.zigTypeTag()) {15581 switch (elem_ty.zigTypeTag()) {
15552 .Enum => if (op != .Xchg) {15582 .Enum => if (op != .Xchg) {
15553 return sema.fail(block, op_src, "@atomicRmw with enum only allowed with .Xchg", .{});15583 return sema.fail(block, op_src, "@atomicRmw with enum only allowed with .Xchg", .{});
15554 },15584 },
...@@ -15561,7 +15591,6 @@ fn zirAtomicRmw(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A...@@ -15561,7 +15591,6 @@ fn zirAtomicRmw(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
15561 },15591 },
15562 else => {},15592 else => {},
15563 }15593 }
15564 const operand = try sema.coerce(block, operand_ty, sema.resolveInst(extra.operand), operand_src);
15565 const order = try sema.resolveAtomicOrder(block, order_src, extra.ordering);15594 const order = try sema.resolveAtomicOrder(block, order_src, extra.ordering);
1556615595
15567 if (order == .Unordered) {15596 if (order == .Unordered) {
...@@ -15569,8 +15598,8 @@ fn zirAtomicRmw(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A...@@ -15569,8 +15598,8 @@ fn zirAtomicRmw(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
15569 }15598 }
1557015599
15571 // special case zero bit types15600 // special case zero bit types
15572 if (try sema.typeHasOnePossibleValue(block, operand_ty_src, operand_ty)) |val| {15601 if (try sema.typeHasOnePossibleValue(block, elem_ty_src, elem_ty)) |val| {
15573 return sema.addConstant(operand_ty, val);15602 return sema.addConstant(elem_ty, val);
15574 }15603 }
1557515604
15576 const runtime_src = if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| rs: {15605 const runtime_src = if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| rs: {
...@@ -15581,22 +15610,23 @@ fn zirAtomicRmw(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A...@@ -15581,22 +15610,23 @@ fn zirAtomicRmw(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
15581 };15610 };
15582 if (ptr_val.isComptimeMutablePtr()) {15611 if (ptr_val.isComptimeMutablePtr()) {
15583 const target = sema.mod.getTarget();15612 const target = sema.mod.getTarget();
15613 const ptr_ty = sema.typeOf(ptr);
15584 const stored_val = (try sema.pointerDeref(block, ptr_src, ptr_val, ptr_ty)) orelse break :rs ptr_src;15614 const stored_val = (try sema.pointerDeref(block, ptr_src, ptr_val, ptr_ty)) orelse break :rs ptr_src;
15585 const new_val = switch (op) {15615 const new_val = switch (op) {
15586 // zig fmt: off15616 // zig fmt: off
15587 .Xchg => operand_val,15617 .Xchg => operand_val,
15588 .Add => try stored_val.numberAddWrap(operand_val, operand_ty, sema.arena, target),15618 .Add => try stored_val.numberAddWrap(operand_val, elem_ty, sema.arena, target),
15589 .Sub => try stored_val.numberSubWrap(operand_val, operand_ty, sema.arena, target),15619 .Sub => try stored_val.numberSubWrap(operand_val, elem_ty, sema.arena, target),
15590 .And => try stored_val.bitwiseAnd (operand_val, operand_ty, sema.arena, target),15620 .And => try stored_val.bitwiseAnd (operand_val, elem_ty, sema.arena, target),
15591 .Nand => try stored_val.bitwiseNand (operand_val, operand_ty, sema.arena, target),15621 .Nand => try stored_val.bitwiseNand (operand_val, elem_ty, sema.arena, target),
15592 .Or => try stored_val.bitwiseOr (operand_val, operand_ty, sema.arena, target),15622 .Or => try stored_val.bitwiseOr (operand_val, elem_ty, sema.arena, target),
15593 .Xor => try stored_val.bitwiseXor (operand_val, operand_ty, sema.arena, target),15623 .Xor => try stored_val.bitwiseXor (operand_val, elem_ty, sema.arena, target),
15594 .Max => stored_val.numberMax (operand_val, target),15624 .Max => stored_val.numberMax (operand_val, target),
15595 .Min => stored_val.numberMin (operand_val, target),15625 .Min => stored_val.numberMin (operand_val, target),
15596 // zig fmt: on15626 // zig fmt: on
15597 };15627 };
15598 try sema.storePtrVal(block, src, ptr_val, new_val, operand_ty);15628 try sema.storePtrVal(block, src, ptr_val, new_val, elem_ty);
15599 return sema.addConstant(operand_ty, stored_val);15629 return sema.addConstant(elem_ty, stored_val);
15600 } else break :rs ptr_src;15630 } else break :rs ptr_src;
15601 } else ptr_src;15631 } else ptr_src;
1560215632
...@@ -15620,15 +15650,15 @@ fn zirAtomicStore(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -15620,15 +15650,15 @@ fn zirAtomicStore(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
15620 const extra = sema.code.extraData(Zir.Inst.AtomicStore, inst_data.payload_index).data;15650 const extra = sema.code.extraData(Zir.Inst.AtomicStore, inst_data.payload_index).data;
15621 const src = inst_data.src();15651 const src = inst_data.src();
15622 // zig fmt: off15652 // zig fmt: off
15623 const operand_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };15653 const elem_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
15624 const ptr_src : LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };15654 const ptr_src : LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
15625 const operand_src : LazySrcLoc = .{ .node_offset_builtin_call_arg2 = inst_data.src_node };15655 const operand_src : LazySrcLoc = .{ .node_offset_builtin_call_arg2 = inst_data.src_node };
15626 const order_src : LazySrcLoc = .{ .node_offset_builtin_call_arg3 = inst_data.src_node };15656 const order_src : LazySrcLoc = .{ .node_offset_builtin_call_arg3 = inst_data.src_node };
15627 // zig fmt: on15657 // zig fmt: on
15628 const ptr = sema.resolveInst(extra.ptr);15658 const operand = sema.resolveInst(extra.operand);
15629 const operand_ty = sema.typeOf(ptr).elemType();15659 const elem_ty = sema.typeOf(operand);
15630 try sema.checkAtomicOperandType(block, operand_ty_src, operand_ty);15660 const uncasted_ptr = sema.resolveInst(extra.ptr);
15631 const operand = try sema.coerce(block, operand_ty, sema.resolveInst(extra.operand), operand_src);15661 const ptr = try sema.checkAtomicPtrOperand(block, elem_ty, elem_ty_src, uncasted_ptr, ptr_src, false);
15632 const order = try sema.resolveAtomicOrder(block, order_src, extra.ordering);15662 const order = try sema.resolveAtomicOrder(block, order_src, extra.ordering);
1563315663
15634 const air_tag: Air.Inst.Tag = switch (order) {15664 const air_tag: Air.Inst.Tag = switch (order) {
src/Zir.zig+7-1
...@@ -903,7 +903,7 @@ pub const Inst = struct {...@@ -903,7 +903,7 @@ pub const Inst = struct {
903 /// Uses the `pl_node` union field with payload `Select`.903 /// Uses the `pl_node` union field with payload `Select`.
904 select,904 select,
905 /// Implements the `@atomicLoad` builtin.905 /// Implements the `@atomicLoad` builtin.
906 /// Uses the `pl_node` union field with payload `Bin`.906 /// Uses the `pl_node` union field with payload `AtomicLoad`.
907 atomic_load,907 atomic_load,
908 /// Implements the `@atomicRmw` builtin.908 /// Implements the `@atomicRmw` builtin.
909 /// Uses the `pl_node` union field with payload `AtomicRmw`.909 /// Uses the `pl_node` union field with payload `AtomicRmw`.
...@@ -3293,6 +3293,12 @@ pub const Inst = struct {...@@ -3293,6 +3293,12 @@ pub const Inst = struct {
3293 ordering: Ref,3293 ordering: Ref,
3294 };3294 };
32953295
3296 pub const AtomicLoad = struct {
3297 elem_type: Ref,
3298 ptr: Ref,
3299 ordering: Ref,
3300 };
3301
3296 pub const MulAdd = struct {3302 pub const MulAdd = struct {
3297 mulend1: Ref,3303 mulend1: Ref,
3298 mulend2: Ref,3304 mulend2: Ref,
src/arch/x86_64/abi.zig+9-8
...@@ -12,13 +12,10 @@ pub fn classifyWindows(ty: Type, target: Target) Class {...@@ -12,13 +12,10 @@ pub fn classifyWindows(ty: Type, target: Target) Class {
12 // and the registers used for those arguments. Any argument that doesn't fit in 812 // and the registers used for those arguments. Any argument that doesn't fit in 8
13 // bytes, or isn't 1, 2, 4, or 8 bytes, must be passed by reference. A single argument13 // bytes, or isn't 1, 2, 4, or 8 bytes, must be passed by reference. A single argument
14 // is never spread across multiple registers."14 // is never spread across multiple registers."
15 // "All floating point operations are done using the 16 XMM registers."
15 // "Structs and unions of size 8, 16, 32, or 64 bits, and __m64 types, are passed16 // "Structs and unions of size 8, 16, 32, or 64 bits, and __m64 types, are passed
16 // as if they were integers of the same size."17 // as if they were integers of the same size."
17 switch (ty.abiSize(target)) {18 switch (ty.zigTypeTag()) {
18 1, 2, 4, 8 => {},
19 else => return .memory,
20 }
21 return switch (ty.zigTypeTag()) {
22 .Pointer,19 .Pointer,
23 .Int,20 .Int,
24 .Bool,21 .Bool,
...@@ -33,9 +30,13 @@ pub fn classifyWindows(ty: Type, target: Target) Class {...@@ -33,9 +30,13 @@ pub fn classifyWindows(ty: Type, target: Target) Class {
33 .ErrorUnion,30 .ErrorUnion,
34 .AnyFrame,31 .AnyFrame,
35 .Frame,32 .Frame,
36 => .integer,33 => switch (ty.abiSize(target)) {
34 0 => unreachable,
35 1, 2, 4, 8 => return .integer,
36 else => return .memory,
37 },
3738
38 .Float, .Vector => .sse,39 .Float, .Vector => return .sse,
3940
40 .Type,41 .Type,
41 .ComptimeFloat,42 .ComptimeFloat,
...@@ -47,7 +48,7 @@ pub fn classifyWindows(ty: Type, target: Target) Class {...@@ -47,7 +48,7 @@ pub fn classifyWindows(ty: Type, target: Target) Class {
47 .Opaque,48 .Opaque,
48 .EnumLiteral,49 .EnumLiteral,
49 => unreachable,50 => unreachable,
50 };51 }
51}52}
5253
53/// There are a maximum of 8 possible return slots. Returned values are in54/// There are a maximum of 8 possible return slots. Returned values are in
src/codegen/llvm.zig+45-4
...@@ -476,6 +476,19 @@ pub const Object = struct {...@@ -476,6 +476,19 @@ pub const Object = struct {
476 _ = builder.buildRet(is_lt);476 _ = builder.buildRet(is_lt);
477 }477 }
478478
479 fn genModuleLevelAssembly(object: *Object, comp: *Compilation) !void {
480 const mod = comp.bin_file.options.module.?;
481 if (mod.global_assembly.count() == 0) return;
482 var buffer = std.ArrayList(u8).init(comp.gpa);
483 defer buffer.deinit();
484 var it = mod.global_assembly.iterator();
485 while (it.next()) |kv| {
486 try buffer.appendSlice(kv.value_ptr.*);
487 try buffer.append('\n');
488 }
489 object.llvm_module.setModuleInlineAsm2(buffer.items.ptr, buffer.items.len - 1);
490 }
491
479 pub fn flushModule(self: *Object, comp: *Compilation, prog_node: *std.Progress.Node) !void {492 pub fn flushModule(self: *Object, comp: *Compilation, prog_node: *std.Progress.Node) !void {
480 var sub_prog_node = prog_node.start("LLVM Emit Object", 0);493 var sub_prog_node = prog_node.start("LLVM Emit Object", 0);
481 sub_prog_node.activate();494 sub_prog_node.activate();
...@@ -484,6 +497,7 @@ pub const Object = struct {...@@ -484,6 +497,7 @@ pub const Object = struct {
484497
485 try self.genErrorNameTable(comp);498 try self.genErrorNameTable(comp);
486 try self.genCmpLtErrorsLenFunction(comp);499 try self.genCmpLtErrorsLenFunction(comp);
500 try self.genModuleLevelAssembly(comp);
487501
488 if (self.di_builder) |dib| {502 if (self.di_builder) |dib| {
489 // When lowering debug info for pointers, we emitted the element types as503 // When lowering debug info for pointers, we emitted the element types as
...@@ -630,7 +644,17 @@ pub const Object = struct {...@@ -630,7 +644,17 @@ pub const Object = struct {
630 if (!param_ty.hasRuntimeBitsIgnoreComptime()) continue;644 if (!param_ty.hasRuntimeBitsIgnoreComptime()) continue;
631645
632 const llvm_arg_i = @intCast(c_uint, args.items.len) + param_offset;646 const llvm_arg_i = @intCast(c_uint, args.items.len) + param_offset;
633 try args.append(llvm_func.getParam(llvm_arg_i));647 const param = llvm_func.getParam(llvm_arg_i);
648 // It is possible for the calling convention to make the argument's by-reference nature
649 // disagree with our canonical value for it, in which case we must dereference here.
650 const need_deref = !param_ty.isPtrAtRuntime() and !isByRef(param_ty) and
651 (param.typeOf().getTypeKind() == .Pointer);
652 const loaded_param = if (!need_deref) param else l: {
653 const load_inst = builder.buildLoad(param, "");
654 load_inst.setAlignment(param_ty.abiAlignment(target));
655 break :l load_inst;
656 };
657 try args.append(loaded_param);
634 }658 }
635659
636 var di_file: ?*llvm.DIFile = null;660 var di_file: ?*llvm.DIFile = null;
...@@ -3729,6 +3753,19 @@ pub const FuncGen = struct {...@@ -3729,6 +3753,19 @@ pub const FuncGen = struct {
3729 arg_ptr.setAlignment(alignment);3753 arg_ptr.setAlignment(alignment);
3730 const store_inst = self.builder.buildStore(llvm_arg, arg_ptr);3754 const store_inst = self.builder.buildStore(llvm_arg, arg_ptr);
3731 store_inst.setAlignment(alignment);3755 store_inst.setAlignment(alignment);
3756
3757 if (abi_llvm_ty.getTypeKind() == .Pointer) {
3758 // In this case, the calling convention wants a pointer, but
3759 // we have a value.
3760 if (arg_ptr.typeOf() == abi_llvm_ty) {
3761 try llvm_args.append(arg_ptr);
3762 continue;
3763 }
3764 const casted_ptr = self.builder.buildBitCast(arg_ptr, abi_llvm_ty, "");
3765 try llvm_args.append(casted_ptr);
3766 continue;
3767 }
3768
3732 break :p self.builder.buildBitCast(arg_ptr, ptr_abi_ty, "");3769 break :p self.builder.buildBitCast(arg_ptr, ptr_abi_ty, "");
3733 };3770 };
37343771
...@@ -7583,7 +7620,7 @@ pub const FuncGen = struct {...@@ -7583,7 +7620,7 @@ pub const FuncGen = struct {
7583 const size_bytes = elem_ty.abiSize(target);7620 const size_bytes = elem_ty.abiSize(target);
7584 _ = self.builder.buildMemCpy(7621 _ = self.builder.buildMemCpy(
7585 self.builder.buildBitCast(ptr, llvm_ptr_u8, ""),7622 self.builder.buildBitCast(ptr, llvm_ptr_u8, ""),
7586 ptr_ty.ptrAlignment(target),7623 ptr_alignment,
7587 self.builder.buildBitCast(elem, llvm_ptr_u8, ""),7624 self.builder.buildBitCast(elem, llvm_ptr_u8, ""),
7588 elem_ty.abiAlignment(target),7625 elem_ty.abiAlignment(target),
7589 self.context.intType(Type.usize.intInfo(target).bits).constInt(size_bytes, .False),7626 self.context.intType(Type.usize.intInfo(target).bits).constInt(size_bytes, .False),
...@@ -7917,6 +7954,8 @@ fn llvmFieldIndex(...@@ -7917,6 +7954,8 @@ fn llvmFieldIndex(
7917}7954}
79187955
7919fn firstParamSRet(fn_info: Type.Payload.Function.Data, target: std.Target) bool {7956fn firstParamSRet(fn_info: Type.Payload.Function.Data, target: std.Target) bool {
7957 if (!fn_info.return_type.hasRuntimeBitsIgnoreComptime()) return false;
7958
7920 switch (fn_info.cc) {7959 switch (fn_info.cc) {
7921 .Unspecified, .Inline => return isByRef(fn_info.return_type),7960 .Unspecified, .Inline => return isByRef(fn_info.return_type),
7922 .C => switch (target.cpu.arch) {7961 .C => switch (target.cpu.arch) {
...@@ -8016,7 +8055,8 @@ fn lowerFnRetTy(dg: *DeclGen, fn_info: Type.Payload.Function.Data) !*const llvm....@@ -8016,7 +8055,8 @@ fn lowerFnRetTy(dg: *DeclGen, fn_info: Type.Payload.Function.Data) !*const llvm.
8016 }8055 }
8017 }8056 }
8018 if (classes[0] == .integer and classes[1] == .none) {8057 if (classes[0] == .integer and classes[1] == .none) {
8019 return llvm_types_buffer[0];8058 const abi_size = fn_info.return_type.abiSize(target);
8059 return dg.context.intType(@intCast(c_uint, abi_size * 8));
8020 }8060 }
8021 return dg.context.structType(&llvm_types_buffer, llvm_types_index, .False);8061 return dg.context.structType(&llvm_types_buffer, llvm_types_index, .False);
8022 },8062 },
...@@ -8110,7 +8150,8 @@ fn lowerFnParamTy(dg: *DeclGen, cc: std.builtin.CallingConvention, ty: Type) !*c...@@ -8110,7 +8150,8 @@ fn lowerFnParamTy(dg: *DeclGen, cc: std.builtin.CallingConvention, ty: Type) !*c
8110 }8150 }
8111 }8151 }
8112 if (classes[0] == .integer and classes[1] == .none) {8152 if (classes[0] == .integer and classes[1] == .none) {
8113 return llvm_types_buffer[0];8153 const abi_size = ty.abiSize(target);
8154 return dg.context.intType(@intCast(c_uint, abi_size * 8));
8114 }8155 }
8115 return dg.context.structType(&llvm_types_buffer, llvm_types_index, .False);8156 return dg.context.structType(&llvm_types_buffer, llvm_types_index, .False);
8116 },8157 },
src/codegen/llvm/bindings.zig+3
...@@ -381,6 +381,9 @@ pub const Module = opaque {...@@ -381,6 +381,9 @@ pub const Module = opaque {
381381
382 pub const createDIBuilder = ZigLLVMCreateDIBuilder;382 pub const createDIBuilder = ZigLLVMCreateDIBuilder;
383 extern fn ZigLLVMCreateDIBuilder(module: *const Module, allow_unresolved: bool) *DIBuilder;383 extern fn ZigLLVMCreateDIBuilder(module: *const Module, allow_unresolved: bool) *DIBuilder;
384
385 pub const setModuleInlineAsm2 = LLVMSetModuleInlineAsm2;
386 extern fn LLVMSetModuleInlineAsm2(M: *const Module, Asm: [*]const u8, Len: usize) void;
384};387};
385388
386pub const lookupIntrinsicID = LLVMLookupIntrinsicID;389pub const lookupIntrinsicID = LLVMLookupIntrinsicID;
src/print_zir.zig+14-1
...@@ -283,6 +283,7 @@ const Writer = struct {...@@ -283,6 +283,7 @@ const Writer = struct {
283 => try self.writeStructInit(stream, inst),283 => try self.writeStructInit(stream, inst),
284284
285 .cmpxchg_strong, .cmpxchg_weak => try self.writeCmpxchg(stream, inst),285 .cmpxchg_strong, .cmpxchg_weak => try self.writeCmpxchg(stream, inst),
286 .atomic_load => try self.writeAtomicLoad(stream, inst),
286 .atomic_store => try self.writeAtomicStore(stream, inst),287 .atomic_store => try self.writeAtomicStore(stream, inst),
287 .atomic_rmw => try self.writeAtomicRmw(stream, inst),288 .atomic_rmw => try self.writeAtomicRmw(stream, inst),
288 .memcpy => try self.writeMemcpy(stream, inst),289 .memcpy => try self.writeMemcpy(stream, inst),
...@@ -351,7 +352,6 @@ const Writer = struct {...@@ -351,7 +352,6 @@ const Writer = struct {
351 .offset_of,352 .offset_of,
352 .splat,353 .splat,
353 .reduce,354 .reduce,
354 .atomic_load,
355 .bitcast,355 .bitcast,
356 .vector_type,356 .vector_type,
357 .maximum,357 .maximum,
...@@ -929,6 +929,19 @@ const Writer = struct {...@@ -929,6 +929,19 @@ const Writer = struct {
929 try self.writeSrc(stream, inst_data.src());929 try self.writeSrc(stream, inst_data.src());
930 }930 }
931931
932 fn writeAtomicLoad(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
933 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
934 const extra = self.code.extraData(Zir.Inst.AtomicLoad, inst_data.payload_index).data;
935
936 try self.writeInstRef(stream, extra.elem_type);
937 try stream.writeAll(", ");
938 try self.writeInstRef(stream, extra.ptr);
939 try stream.writeAll(", ");
940 try self.writeInstRef(stream, extra.ordering);
941 try stream.writeAll(") ");
942 try self.writeSrc(stream, inst_data.src());
943 }
944
932 fn writeAtomicStore(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {945 fn writeAtomicStore(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
933 const inst_data = self.code.instructions.items(.data)[inst].pl_node;946 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
934 const extra = self.code.extraData(Zir.Inst.AtomicStore, inst_data.payload_index).data;947 const extra = self.code.extraData(Zir.Inst.AtomicStore, inst_data.payload_index).data;
src/stage1/analyze.cpp+1
...@@ -7686,6 +7686,7 @@ ZigType *make_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits) {...@@ -7686,6 +7686,7 @@ ZigType *make_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits) {
7686 // However for some targets, LLVM incorrectly reports this as 8.7686 // However for some targets, LLVM incorrectly reports this as 8.
7687 // See: https://github.com/ziglang/zig/issues/29877687 // See: https://github.com/ziglang/zig/issues/2987
7688 entry->abi_align = 16;7688 entry->abi_align = 16;
7689 entry->abi_size = align_forward(entry->abi_size, entry->abi_align);
7689 }7690 }
7690 }7691 }
76917692
src/target.zig+57-4
...@@ -1,5 +1,6 @@...@@ -1,5 +1,6 @@
1const std = @import("std");1const std = @import("std");
2const llvm = @import("codegen/llvm/bindings.zig");2const llvm = @import("codegen/llvm/bindings.zig");
3const Type = @import("type.zig").Type;
34
4pub const ArchOsAbi = struct {5pub const ArchOsAbi = struct {
5 arch: std.Target.Cpu.Arch,6 arch: std.Target.Cpu.Arch,
...@@ -543,10 +544,28 @@ pub fn needUnwindTables(target: std.Target) bool {...@@ -543,10 +544,28 @@ pub fn needUnwindTables(target: std.Target) bool {
543 return target.os.tag == .windows;544 return target.os.tag == .windows;
544}545}
545546
546/// TODO this was ported from stage1 but it does not take into account CPU features,547pub const AtomicPtrAlignmentError = error{
547/// which can affect this value. Audit this!548 FloatTooBig,
548pub fn largestAtomicBits(target: std.Target) u32 {549 IntTooBig,
549 return switch (target.cpu.arch) {550 BadType,
551};
552
553pub const AtomicPtrAlignmentDiagnostics = struct {
554 bits: u16 = undefined,
555 max_bits: u16 = undefined,
556};
557
558/// If ABI alignment of `ty` is OK for atomic operations, returns 0.
559/// Otherwise returns the alignment required on a pointer for the target
560/// to perform atomic operations.
561pub fn atomicPtrAlignment(
562 target: std.Target,
563 ty: Type,
564 diags: *AtomicPtrAlignmentDiagnostics,
565) AtomicPtrAlignmentError!u32 {
566 // TODO this was ported from stage1 but it does not take into account CPU features,
567 // which can affect this value. Audit this!
568 const max_atomic_bits: u16 = switch (target.cpu.arch) {
550 .avr,569 .avr,
551 .msp430,570 .msp430,
552 .spu_2,571 .spu_2,
...@@ -611,6 +630,40 @@ pub fn largestAtomicBits(target: std.Target) u32 {...@@ -611,6 +630,40 @@ pub fn largestAtomicBits(target: std.Target) u32 {
611630
612 .x86_64 => 128,631 .x86_64 => 128,
613 };632 };
633
634 var buffer: Type.Payload.Bits = undefined;
635
636 const int_ty = switch (ty.zigTypeTag()) {
637 .Int => ty,
638 .Enum => ty.intTagType(&buffer),
639 .Float => {
640 const bit_count = ty.floatBits(target);
641 if (bit_count > max_atomic_bits) {
642 diags.* = .{
643 .bits = bit_count,
644 .max_bits = max_atomic_bits,
645 };
646 return error.FloatTooBig;
647 }
648 return 0;
649 },
650 .Bool => return 0,
651 else => {
652 if (ty.isPtrAtRuntime()) return 0;
653 return error.BadType;
654 },
655 };
656
657 const bit_count = int_ty.intInfo(target).bits;
658 if (bit_count > max_atomic_bits) {
659 diags.* = .{
660 .bits = bit_count,
661 .max_bits = max_atomic_bits,
662 };
663 return error.IntTooBig;
664 }
665
666 return 0;
614}667}
615668
616pub fn defaultAddressSpace(669pub fn defaultAddressSpace(
src/type.zig+24-16
...@@ -2788,11 +2788,6 @@ pub const Type = extern union {...@@ -2788,11 +2788,6 @@ pub const Type = extern union {
2788 return AbiAlignmentAdvanced{ .scalar = target_util.defaultFunctionAlignment(target) };2788 return AbiAlignmentAdvanced{ .scalar = target_util.defaultFunctionAlignment(target) };
2789 },2789 },
27902790
2791 .i16, .u16 => return AbiAlignmentAdvanced{ .scalar = 2 },
2792 .i32, .u32 => return AbiAlignmentAdvanced{ .scalar = 4 },
2793 .i64, .u64 => return AbiAlignmentAdvanced{ .scalar = 8 },
2794 .u128, .i128 => return AbiAlignmentAdvanced{ .scalar = 16 },
2795
2796 .isize,2791 .isize,
2797 .usize,2792 .usize,
2798 .single_const_pointer_to_comptime_int,2793 .single_const_pointer_to_comptime_int,
...@@ -2865,14 +2860,15 @@ pub const Type = extern union {...@@ -2865,14 +2860,15 @@ pub const Type = extern union {
2865 // ABI alignment of vectors?2860 // ABI alignment of vectors?
2866 .vector => return AbiAlignmentAdvanced{ .scalar = 16 },2861 .vector => return AbiAlignmentAdvanced{ .scalar = 16 },
28672862
2863 .i16, .u16 => return AbiAlignmentAdvanced{ .scalar = intAbiAlignment(16, target) },
2864 .i32, .u32 => return AbiAlignmentAdvanced{ .scalar = intAbiAlignment(32, target) },
2865 .i64, .u64 => return AbiAlignmentAdvanced{ .scalar = intAbiAlignment(64, target) },
2866 .u128, .i128 => return AbiAlignmentAdvanced{ .scalar = intAbiAlignment(128, target) },
2867
2868 .int_signed, .int_unsigned => {2868 .int_signed, .int_unsigned => {
2869 const bits: u16 = ty.cast(Payload.Bits).?.data;2869 const bits: u16 = ty.cast(Payload.Bits).?.data;
2870 if (bits == 0) return AbiAlignmentAdvanced{ .scalar = 0 };2870 if (bits == 0) return AbiAlignmentAdvanced{ .scalar = 0 };
2871 if (bits <= 8) return AbiAlignmentAdvanced{ .scalar = 1 };2871 return AbiAlignmentAdvanced{ .scalar = intAbiAlignment(bits, target) };
2872 if (bits <= 16) return AbiAlignmentAdvanced{ .scalar = 2 };
2873 if (bits <= 32) return AbiAlignmentAdvanced{ .scalar = 4 };
2874 if (bits <= 64) return AbiAlignmentAdvanced{ .scalar = 8 };
2875 return AbiAlignmentAdvanced{ .scalar = 16 };
2876 },2872 },
28772873
2878 .optional => {2874 .optional => {
...@@ -3113,10 +3109,6 @@ pub const Type = extern union {...@@ -3113,10 +3109,6 @@ pub const Type = extern union {
3113 assert(elem_size >= payload.elem_type.abiAlignment(target));3109 assert(elem_size >= payload.elem_type.abiAlignment(target));
3114 return (payload.len + 1) * elem_size;3110 return (payload.len + 1) * elem_size;
3115 },3111 },
3116 .i16, .u16 => return 2,
3117 .i32, .u32 => return 4,
3118 .i64, .u64 => return 8,
3119 .u128, .i128 => return 16,
31203112
3121 .isize,3113 .isize,
3122 .usize,3114 .usize,
...@@ -3189,10 +3181,14 @@ pub const Type = extern union {...@@ -3189,10 +3181,14 @@ pub const Type = extern union {
3189 .error_set_merged,3181 .error_set_merged,
3190 => return 2, // TODO revisit this when we have the concept of the error tag type3182 => return 2, // TODO revisit this when we have the concept of the error tag type
31913183
3184 .i16, .u16 => return intAbiSize(16, target),
3185 .i32, .u32 => return intAbiSize(32, target),
3186 .i64, .u64 => return intAbiSize(64, target),
3187 .u128, .i128 => return intAbiSize(128, target),
3192 .int_signed, .int_unsigned => {3188 .int_signed, .int_unsigned => {
3193 const bits: u16 = self.cast(Payload.Bits).?.data;3189 const bits: u16 = self.cast(Payload.Bits).?.data;
3194 if (bits == 0) return 0;3190 if (bits == 0) return 0;
3195 return std.math.ceilPowerOfTwoPromote(u16, (bits + 7) / 8);3191 return intAbiSize(bits, target);
3196 },3192 },
31973193
3198 .optional => {3194 .optional => {
...@@ -3234,6 +3230,18 @@ pub const Type = extern union {...@@ -3234,6 +3230,18 @@ pub const Type = extern union {
3234 };3230 };
3235 }3231 }
32363232
3233 fn intAbiSize(bits: u16, target: Target) u64 {
3234 const alignment = intAbiAlignment(bits, target);
3235 return std.mem.alignForwardGeneric(u64, (bits + 7) / 8, alignment);
3236 }
3237
3238 fn intAbiAlignment(bits: u16, target: Target) u32 {
3239 return @minimum(
3240 std.math.ceilPowerOfTwoPromote(u16, (bits + 7) / 8),
3241 target.maxIntAlignment(),
3242 );
3243 }
3244
3237 /// Asserts the type has the bit size already resolved.3245 /// Asserts the type has the bit size already resolved.
3238 pub fn bitSize(ty: Type, target: Target) u64 {3246 pub fn bitSize(ty: Type, target: Target) u64 {
3239 return switch (ty.tag()) {3247 return switch (ty.tag()) {
...@@ -5169,7 +5177,7 @@ pub const Type = extern union {...@@ -5169,7 +5177,7 @@ pub const Type = extern union {
51695177
5170 const field = it.struct_obj.fields.values()[it.field];5178 const field = it.struct_obj.fields.values()[it.field];
5171 defer it.field += 1;5179 defer it.field += 1;
5172 if (!field.ty.hasRuntimeBits())5180 if (!field.ty.hasRuntimeBits() or field.is_comptime)
5173 return FieldOffset{ .field = it.field, .offset = it.offset };5181 return FieldOffset{ .field = it.field, .offset = it.offset };
51745182
5175 const field_align = field.normalAlignment(it.target);5183 const field_align = field.normalAlignment(it.target);
test/behavior/align.zig+111-26
...@@ -47,41 +47,128 @@ fn expects4(x: *align(4) u32) void {...@@ -47,41 +47,128 @@ fn expects4(x: *align(4) u32) void {
47 x.* += 1;47 x.* += 1;
48}48}
4949
50test "alignment of structs" {50test "alignment of struct with pointer has same alignment as usize" {
51 try expect(@alignOf(struct {51 try expect(@alignOf(struct {
52 a: i32,52 a: i32,
53 b: *i32,53 b: *i32,
54 }) == @alignOf(usize));54 }) == @alignOf(usize));
55}55}
5656
57test "alignment of >= 128-bit integer type" {57test "alignment and size of structs with 128-bit fields" {
58 try expect(@alignOf(u128) == 16);58 if (builtin.zig_backend == .stage1) {
59 try expect(@alignOf(u129) == 16);59 // stage1 gets the wrong answer for a lot of targets
60}60 return error.SkipZigTest;
61
62test "alignment of struct with 128-bit field" {
63 try expect(@alignOf(struct {
64 x: u128,
65 }) == 16);
66
67 comptime {
68 try expect(@alignOf(struct {
69 x: u128,
70 }) == 16);
71 }61 }
72}62 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
63 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
7364
74test "size of extern struct with 128-bit field" {65 const A = struct {
75 try expect(@sizeOf(extern struct {66 x: u128,
67 };
68 const B = extern struct {
76 x: u128,69 x: u128,
77 y: u8,70 y: u8,
78 }) == 32);71 };
7972 const expected = switch (builtin.cpu.arch) {
73 .arm,
74 .armeb,
75 .thumb,
76 .thumbeb,
77 .hexagon,
78 .mips,
79 .mipsel,
80 .powerpc,
81 .powerpcle,
82 .r600,
83 .amdgcn,
84 .riscv32,
85 .sparc,
86 .sparcel,
87 .s390x,
88 .lanai,
89 .wasm32,
90 .wasm64,
91 => .{
92 .a_align = 8,
93 .a_size = 16,
94
95 .b_align = 8,
96 .b_size = 24,
97
98 .u128_align = 8,
99 .u128_size = 16,
100 .u129_align = 8,
101 .u129_size = 24,
102 },
103
104 .i386 => switch (builtin.os.tag) {
105 .windows => .{
106 .a_align = 8,
107 .a_size = 16,
108
109 .b_align = 8,
110 .b_size = 24,
111
112 .u128_align = 8,
113 .u128_size = 16,
114 .u129_align = 8,
115 .u129_size = 24,
116 },
117 else => .{
118 .a_align = 4,
119 .a_size = 16,
120
121 .b_align = 4,
122 .b_size = 20,
123
124 .u128_align = 4,
125 .u128_size = 16,
126 .u129_align = 4,
127 .u129_size = 20,
128 },
129 },
130
131 .mips64,
132 .mips64el,
133 .powerpc64,
134 .powerpc64le,
135 .riscv64,
136 .sparcv9,
137 .x86_64,
138 .aarch64,
139 .aarch64_be,
140 .aarch64_32,
141 .bpfel,
142 .bpfeb,
143 .nvptx,
144 .nvptx64,
145 => .{
146 .a_align = 16,
147 .a_size = 16,
148
149 .b_align = 16,
150 .b_size = 32,
151
152 .u128_align = 16,
153 .u128_size = 16,
154 .u129_align = 16,
155 .u129_size = 32,
156 },
157
158 else => return error.SkipZigTest,
159 };
80 comptime {160 comptime {
81 try expect(@sizeOf(extern struct {161 std.debug.assert(@alignOf(A) == expected.a_align);
82 x: u128,162 std.debug.assert(@sizeOf(A) == expected.a_size);
83 y: u8,163
84 }) == 32);164 std.debug.assert(@alignOf(B) == expected.b_align);
165 std.debug.assert(@sizeOf(B) == expected.b_size);
166
167 std.debug.assert(@alignOf(u128) == expected.u128_align);
168 std.debug.assert(@sizeOf(u128) == expected.u128_size);
169
170 std.debug.assert(@alignOf(u129) == expected.u129_align);
171 std.debug.assert(@sizeOf(u129) == expected.u129_size);
85 }172 }
86}173}
87174
...@@ -328,7 +415,6 @@ test "read 128-bit field from default aligned struct in stack memory" {...@@ -328,7 +415,6 @@ test "read 128-bit field from default aligned struct in stack memory" {
328 .nevermind = 1,415 .nevermind = 1,
329 .badguy = 12,416 .badguy = 12,
330 };417 };
331 try expect((@ptrToInt(&default_aligned.badguy) % 16) == 0);
332 try expect(12 == default_aligned.badguy);418 try expect(12 == default_aligned.badguy);
333}419}
334420
...@@ -345,7 +431,6 @@ test "read 128-bit field from default aligned struct in global memory" {...@@ -345,7 +431,6 @@ test "read 128-bit field from default aligned struct in global memory" {
345 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;431 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
346 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;432 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
347433
348 try expect((@ptrToInt(&default_aligned_global.badguy) % 16) == 0);
349 try expect(12 == default_aligned_global.badguy);434 try expect(12 == default_aligned_global.badguy);
350}435}
351436
test/behavior/asm.zig-1
...@@ -23,7 +23,6 @@ test "module level assembly" {...@@ -23,7 +23,6 @@ test "module level assembly" {
23 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO23 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
24 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO24 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
25 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO25 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
26 if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; // TODO
2726
28 if (is_x86_64_linux) {27 if (is_x86_64_linux) {
29 try expect(this_is_my_alias() == 1234);28 try expect(this_is_my_alias() == 1234);
test/behavior/atomics.zig+1-1
...@@ -127,7 +127,7 @@ test "128-bit cmpxchg" {...@@ -127,7 +127,7 @@ test "128-bit cmpxchg" {
127}127}
128128
129fn test_u128_cmpxchg() !void {129fn test_u128_cmpxchg() !void {
130 var x: u128 = 1234;130 var x: u128 align(16) = 1234;
131 if (@cmpxchgWeak(u128, &x, 99, 5678, .SeqCst, .SeqCst)) |x1| {131 if (@cmpxchgWeak(u128, &x, 99, 5678, .SeqCst, .SeqCst)) |x1| {
132 try expect(x1 == 1234);132 try expect(x1 == 1234);
133 } else {133 } else {
test/behavior/bitcast.zig+7-12
...@@ -120,6 +120,10 @@ test "bitcast generates a temporary value" {...@@ -120,6 +120,10 @@ test "bitcast generates a temporary value" {
120}120}
121121
122test "@bitCast packed structs at runtime and comptime" {122test "@bitCast packed structs at runtime and comptime" {
123 if (builtin.zig_backend == .stage1) {
124 // stage1 gets the wrong answer for a lot of targets
125 return error.SkipZigTest;
126 }
123 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;127 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
124 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;128 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
125 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;129 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
...@@ -138,18 +142,9 @@ test "@bitCast packed structs at runtime and comptime" {...@@ -138,18 +142,9 @@ test "@bitCast packed structs at runtime and comptime" {
138 fn doTheTest() !void {142 fn doTheTest() !void {
139 var full = Full{ .number = 0x1234 };143 var full = Full{ .number = 0x1234 };
140 var two_halves = @bitCast(Divided, full);144 var two_halves = @bitCast(Divided, full);
141 switch (native_endian) {145 try expect(two_halves.half1 == 0x34);
142 .Big => {146 try expect(two_halves.quarter3 == 0x2);
143 try expect(two_halves.half1 == 0x12);147 try expect(two_halves.quarter4 == 0x1);
144 try expect(two_halves.quarter3 == 0x3);
145 try expect(two_halves.quarter4 == 0x4);
146 },
147 .Little => {
148 try expect(two_halves.half1 == 0x34);
149 try expect(two_halves.quarter3 == 0x2);
150 try expect(two_halves.quarter4 == 0x1);
151 },
152 }
153 }148 }
154 };149 };
155 try S.doTheTest();150 try S.doTheTest();
test/behavior/struct.zig+9-6
...@@ -499,17 +499,18 @@ const Bitfields = packed struct {...@@ -499,17 +499,18 @@ const Bitfields = packed struct {
499 f7: u8,499 f7: u8,
500};500};
501501
502test "native bit field understands endianness" {502test "packed struct fields are ordered from LSB to MSB" {
503 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;503 if (builtin.zig_backend == .stage1) {
504 // stage1 gets the wrong answer for a lot of targets
505 return error.SkipZigTest;
506 }
507 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
504 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO508 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
505 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO509 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
506 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO510 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
507 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO511 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
508512
509 var all: u64 = if (native_endian != .Little)513 var all: u64 = 0x7765443322221111;
510 0x1111222233445677
511 else
512 0x7765443322221111;
513 var bytes: [8]u8 = undefined;514 var bytes: [8]u8 = undefined;
514 @memcpy(&bytes, @ptrCast([*]u8, &all), 8);515 @memcpy(&bytes, @ptrCast([*]u8, &all), 8);
515 var bitfields = @ptrCast(*Bitfields, &bytes).*;516 var bitfields = @ptrCast(*Bitfields, &bytes).*;
...@@ -974,6 +975,8 @@ test "comptime struct field" {...@@ -974,6 +975,8 @@ test "comptime struct field" {
974 comptime b: i32 = 1234,975 comptime b: i32 = 1234,
975 };976 };
976977
978 comptime std.debug.assert(@sizeOf(T) == 4);
979
977 var foo: T = undefined;980 var foo: T = undefined;
978 comptime try expect(foo.b == 1234);981 comptime try expect(foo.b == 1234);
979}982}