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
signaturebadge-question-mark 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 {
17731773 else => false,
17741774 };
17751775 }
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 }
17761858};
17771859
17781860test {
src/AstGen.zig+10-50
......@@ -7423,42 +7423,22 @@ fn builtinCall(
74237423 },
74247424
74257425 .atomic_load => {
7426 const int_type = try typeExpr(gz, scope, params[0]);
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{
7426 const result = try gz.addPlNode(.atomic_load, node, Zir.Inst.AtomicLoad{
74387427 // zig fmt: off
7439 .lhs = try expr(gz, scope, .{ .coerced_ty = ptr_type }, params[1]),
7440 .rhs = try expr(gz, scope, .{ .coerced_ty = .atomic_order_type }, params[2]),
7428 .elem_type = try typeExpr(gz, scope, params[0]),
7429 .ptr = try expr (gz, scope, .none, params[1]),
7430 .ordering = try expr (gz, scope, .{ .coerced_ty = .atomic_order_type }, params[2]),
74417431 // zig fmt: on
74427432 });
74437433 return rvalue(gz, rl, result, node);
74447434 },
74457435 .atomic_rmw => {
74467436 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 } });
74577437 const result = try gz.addPlNode(.atomic_rmw, node, Zir.Inst.AtomicRmw{
74587438 // zig fmt: off
7459 .ptr = try expr(gz, scope, .{ .coerced_ty = ptr_type }, params[1]),
7439 .ptr = try expr(gz, scope, .none, params[1]),
74607440 .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]),
74627442 .ordering = try expr(gz, scope, .{ .coerced_ty = .atomic_order_type }, params[4]),
74637443 // zig fmt: on
74647444 });
......@@ -7466,20 +7446,10 @@ fn builtinCall(
74667446 },
74677447 .atomic_store => {
74687448 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 } });
74797449 const result = try gz.addPlNode(.atomic_store, node, Zir.Inst.AtomicStore{
74807450 // zig fmt: off
7481 .ptr = try expr(gz, scope, .{ .coerced_ty = ptr_type }, params[1]),
7482 .operand = try expr(gz, scope, .{ .coerced_ty = int_type }, params[2]),
7451 .ptr = try expr(gz, scope, .none, params[1]),
7452 .operand = try expr(gz, scope, .{ .ty = int_type }, params[2]),
74837453 .ordering = try expr(gz, scope, .{ .coerced_ty = .atomic_order_type }, params[3]),
74847454 // zig fmt: on
74857455 });
......@@ -7684,20 +7654,10 @@ fn cmpxchg(
76847654 tag: Zir.Inst.Tag,
76857655) InnerError!Zir.Inst.Ref {
76867656 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 } });
76977657 const result = try gz.addPlNode(tag, node, Zir.Inst.Cmpxchg{
76987658 // zig fmt: off
7699 .ptr = try expr(gz, scope, .{ .coerced_ty = ptr_type }, params[1]),
7700 .expected_value = try expr(gz, scope, .{ .coerced_ty = int_type }, params[2]),
7659 .ptr = try expr(gz, scope, .none, params[1]),
7660 .expected_value = try expr(gz, scope, .{ .ty = int_type }, params[2]),
77017661 .new_value = try expr(gz, scope, .{ .coerced_ty = int_type }, params[3]),
77027662 .success_order = try expr(gz, scope, .{ .coerced_ty = .atomic_order_type }, params[4]),
77037663 .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) = .{},
151151/// When a Decl object is freed from `allocated_decls`, it is pushed into this stack.
152152decls_free_list: std.ArrayListUnmanaged(Decl.Index) = .{},
153153
154global_assembly: std.AutoHashMapUnmanaged(Decl.Index, []u8) = .{},
155
154156const MonomorphedFuncsSet = std.HashMapUnmanaged(
155157 *Fn,
156158 void,
......@@ -2831,6 +2833,7 @@ pub fn deinit(mod: *Module) void {
28312833
28322834 mod.decls_free_list.deinit(gpa);
28332835 mod.allocated_decls.deinit(gpa);
2836 mod.global_assembly.deinit(gpa);
28342837}
28352838
28362839pub fn destroyDecl(mod: *Module, decl_index: Decl.Index) void {
......@@ -2842,6 +2845,9 @@ pub fn destroyDecl(mod: *Module, decl_index: Decl.Index) void {
28422845 if (decl.deletion_flag) {
28432846 assert(mod.deletion_set.swapRemove(decl_index));
28442847 }
2848 if (mod.global_assembly.fetchRemove(decl_index)) |kv| {
2849 gpa.free(kv.value);
2850 }
28452851 if (decl.has_tv) {
28462852 if (decl.getInnerNamespace()) |namespace| {
28472853 namespace.destroyDecls(mod);
......@@ -5714,3 +5720,12 @@ pub fn markDeclAlive(mod: *Module, decl: *Decl) void {
57145720fn markDeclIndexAlive(mod: *Module, decl_index: Decl.Index) void {
57155721 return mod.markDeclAlive(mod.declPtr(decl_index));
57165722}
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(
1051710517 const is_volatile = @truncate(u1, extended.small >> 15) != 0;
1051810518 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
1052410520 if (extra.data.asm_source == 0) {
1052510521 // This can move to become an AstGen error after inline assembly improvements land
1052610522 // and stage1 code matches stage2 code.
1052710523 return sema.fail(block, src, "assembly code must use string literal syntax", .{});
1052810524 }
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
1053010549 if (outputs_len > 1) {
1053110550 return sema.fail(block, src, "TODO implement Sema for asm with more than 1 output", .{});
1053210551 }
......@@ -10591,7 +10610,6 @@ fn zirAsm(
1059110610 needed_capacity += name.*.len / 4 + 1;
1059210611 }
1059310612
10594 const asm_source = sema.code.nullTerminatedString(extra.data.asm_source);
1059510613 needed_capacity += (asm_source.len + 3) / 4;
1059610614
1059710615 const gpa = sema.gpa;
......@@ -14715,51 +14733,64 @@ fn checkNumericType(
1471514733 }
1471614734}
1471714735
14718fn checkAtomicOperandType(
14736/// Returns the casted pointer.
14737fn checkAtomicPtrOperand(
1471914738 sema: *Sema,
1472014739 block: *Block,
14721 ty_src: LazySrcLoc,
14722 ty: Type,
14723) CompileError!void {
14724 var buffer: Type.Payload.Bits = undefined;
14740 elem_ty: Type,
14741 elem_ty_src: LazySrcLoc,
14742 ptr: Air.Inst.Ref,
14743 ptr_src: LazySrcLoc,
14744 ptr_const: bool,
14745) CompileError!Air.Inst.Ref {
1472514746 const target = sema.mod.getTarget();
14726 const max_atomic_bits = target_util.largestAtomicBits(target);
14727 const int_ty = switch (ty.zigTypeTag()) {
14728 .Int => ty,
14729 .Enum => ty.intTagType(&buffer),
14730 .Float => {
14731 const bit_count = ty.floatBits(target);
14732 if (bit_count > max_atomic_bits) {
14733 return sema.fail(
14734 block,
14735 ty_src,
14736 "expected {d}-bit float type or smaller; found {d}-bit float type",
14737 .{ max_atomic_bits, bit_count },
14738 );
14739 }
14740 return;
14741 },
14742 .Bool => return, // Will be treated as `u8`.
14743 else => {
14744 if (ty.isPtrAtRuntime()) return;
14747 var diag: target_util.AtomicPtrAlignmentDiagnostics = .{};
14748 const alignment = target_util.atomicPtrAlignment(target, elem_ty, &diag) catch |err| switch (err) {
14749 error.FloatTooBig => return sema.fail(
14750 block,
14751 elem_ty_src,
14752 "expected {d}-bit float type or smaller; found {d}-bit float type",
14753 .{ diag.max_bits, diag.bits },
14754 ),
14755 error.IntTooBig => return sema.fail(
14756 block,
14757 elem_ty_src,
14758 "expected {d}-bit integer type or smaller; found {d}-bit integer type",
14759 .{ diag.max_bits, diag.bits },
14760 ),
14761 error.BadType => return sema.fail(
14762 block,
14763 elem_ty_src,
14764 "expected bool, integer, float, enum, or pointer type; found {}",
14765 .{elem_ty.fmt(sema.mod)},
14766 ),
14767 };
1474514768
14746 return sema.fail(
14747 block,
14748 ty_src,
14749 "expected bool, integer, float, enum, or pointer type; found {}",
14750 .{ty.fmt(sema.mod)},
14751 );
14769 var wanted_ptr_data: Type.Payload.Pointer.Data = .{
14770 .pointee_type = elem_ty,
14771 .@"align" = alignment,
14772 .@"addrspace" = .generic,
14773 .mutable = !ptr_const,
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;
1475214783 },
1475314784 };
14754 const bit_count = int_ty.intInfo(target).bits;
14755 if (bit_count > max_atomic_bits) {
14756 return sema.fail(
14757 block,
14758 ty_src,
14759 "expected {d}-bit integer type or smaller; found {d}-bit integer type",
14760 .{ max_atomic_bits, bit_count },
14761 );
14762 }
14785
14786 wanted_ptr_data.@"addrspace" = ptr_data.@"addrspace";
14787 wanted_ptr_data.@"allowzero" = ptr_data.@"allowzero";
14788 wanted_ptr_data.@"volatile" = ptr_data.@"volatile";
14789
14790 const wanted_ptr_ty = try Type.ptr(sema.arena, sema.mod, wanted_ptr_data);
14791 const casted_ptr = try sema.coerce(block, wanted_ptr_ty, ptr, ptr_src);
14792
14793 return casted_ptr;
1476314794}
1476414795
1476514796fn checkPtrIsNotComptimeMutable(
......@@ -15036,10 +15067,8 @@ fn zirCmpxchg(
1503615067 const success_order_src: LazySrcLoc = .{ .node_offset_builtin_call_arg4 = inst_data.src_node };
1503715068 const failure_order_src: LazySrcLoc = .{ .node_offset_builtin_call_arg5 = inst_data.src_node };
1503815069 // zig fmt: on
15039 const ptr = sema.resolveInst(extra.ptr);
15040 const ptr_ty = sema.typeOf(ptr);
15041 const elem_ty = ptr_ty.elemType();
15042 try sema.checkAtomicOperandType(block, elem_ty_src, elem_ty);
15070 const expected_value = sema.resolveInst(extra.expected_value);
15071 const elem_ty = sema.typeOf(expected_value);
1504315072 if (elem_ty.zigTypeTag() == .Float) {
1504415073 return sema.fail(
1504515074 block,
......@@ -15048,7 +15077,8 @@ fn zirCmpxchg(
1504815077 .{elem_ty.fmt(sema.mod)},
1504915078 );
1505015079 }
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);
1505215082 const new_value = try sema.coerce(block, elem_ty, sema.resolveInst(extra.new_value), new_value_src);
1505315083 const success_order = try sema.resolveAtomicOrder(block, success_order_src, extra.success_order);
1505415084 const failure_order = try sema.resolveAtomicOrder(block, failure_order_src, extra.failure_order);
......@@ -15081,6 +15111,7 @@ fn zirCmpxchg(
1508115111 // to become undef as well
1508215112 return sema.addConstUndef(result_ty);
1508315113 }
15114 const ptr_ty = sema.typeOf(ptr);
1508415115 const stored_val = (try sema.pointerDeref(block, ptr_src, ptr_val, ptr_ty)) orelse break :rs ptr_src;
1508515116 const result_val = if (stored_val.eql(expected_val, elem_ty, sema.mod)) blk: {
1508615117 try sema.storePtr(block, src, ptr, new_value);
......@@ -15487,17 +15518,16 @@ fn zirSelect(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
1548715518
1548815519fn zirAtomicLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
1548915520 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;
1549115522 // zig fmt: off
1549215523 const elem_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
1549315524 const ptr_src : LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
1549415525 const order_src : LazySrcLoc = .{ .node_offset_builtin_call_arg2 = inst_data.src_node };
1549515526 // zig fmt: on
15496 const ptr = sema.resolveInst(extra.lhs);
15497 const ptr_ty = sema.typeOf(ptr);
15498 const elem_ty = ptr_ty.elemType();
15499 try sema.checkAtomicOperandType(block, elem_ty_src, elem_ty);
15500 const order = try sema.resolveAtomicOrder(block, order_src, extra.rhs);
15527 const elem_ty = try sema.resolveType(block, elem_ty_src, extra.elem_type);
15528 const uncasted_ptr = sema.resolveInst(extra.ptr);
15529 const ptr = try sema.checkAtomicPtrOperand(block, elem_ty, elem_ty_src, uncasted_ptr, ptr_src, true);
15530 const order = try sema.resolveAtomicOrder(block, order_src, extra.ordering);
1550115531
1550215532 switch (order) {
1550315533 .Release, .AcqRel => {
......@@ -15516,7 +15546,7 @@ fn zirAtomicLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
1551615546 }
1551715547
1551815548 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| {
1552015550 return sema.addConstant(elem_ty, elem_val);
1552115551 }
1552215552 }
......@@ -15536,19 +15566,19 @@ fn zirAtomicRmw(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
1553615566 const extra = sema.code.extraData(Zir.Inst.AtomicRmw, inst_data.payload_index).data;
1553715567 const src = inst_data.src();
1553815568 // 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 };
1554015570 const ptr_src : LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
1554115571 const op_src : LazySrcLoc = .{ .node_offset_builtin_call_arg2 = inst_data.src_node };
1554215572 const operand_src : LazySrcLoc = .{ .node_offset_builtin_call_arg3 = inst_data.src_node };
1554315573 const order_src : LazySrcLoc = .{ .node_offset_builtin_call_arg4 = inst_data.src_node };
1554415574 // zig fmt: on
15545 const ptr = sema.resolveInst(extra.ptr);
15546 const ptr_ty = sema.typeOf(ptr);
15547 const operand_ty = ptr_ty.elemType();
15548 try sema.checkAtomicOperandType(block, operand_ty_src, operand_ty);
15575 const operand = sema.resolveInst(extra.operand);
15576 const elem_ty = sema.typeOf(operand);
15577 const uncasted_ptr = sema.resolveInst(extra.ptr);
15578 const ptr = try sema.checkAtomicPtrOperand(block, elem_ty, elem_ty_src, uncasted_ptr, ptr_src, false);
1554915579 const op = try sema.resolveAtomicRmwOp(block, op_src, extra.operation);
1555015580
15551 switch (operand_ty.zigTypeTag()) {
15581 switch (elem_ty.zigTypeTag()) {
1555215582 .Enum => if (op != .Xchg) {
1555315583 return sema.fail(block, op_src, "@atomicRmw with enum only allowed with .Xchg", .{});
1555415584 },
......@@ -15561,7 +15591,6 @@ fn zirAtomicRmw(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
1556115591 },
1556215592 else => {},
1556315593 }
15564 const operand = try sema.coerce(block, operand_ty, sema.resolveInst(extra.operand), operand_src);
1556515594 const order = try sema.resolveAtomicOrder(block, order_src, extra.ordering);
1556615595
1556715596 if (order == .Unordered) {
......@@ -15569,8 +15598,8 @@ fn zirAtomicRmw(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
1556915598 }
1557015599
1557115600 // special case zero bit types
15572 if (try sema.typeHasOnePossibleValue(block, operand_ty_src, operand_ty)) |val| {
15573 return sema.addConstant(operand_ty, val);
15601 if (try sema.typeHasOnePossibleValue(block, elem_ty_src, elem_ty)) |val| {
15602 return sema.addConstant(elem_ty, val);
1557415603 }
1557515604
1557615605 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
1558115610 };
1558215611 if (ptr_val.isComptimeMutablePtr()) {
1558315612 const target = sema.mod.getTarget();
15613 const ptr_ty = sema.typeOf(ptr);
1558415614 const stored_val = (try sema.pointerDeref(block, ptr_src, ptr_val, ptr_ty)) orelse break :rs ptr_src;
1558515615 const new_val = switch (op) {
1558615616 // zig fmt: off
1558715617 .Xchg => operand_val,
15588 .Add => try stored_val.numberAddWrap(operand_val, operand_ty, sema.arena, target),
15589 .Sub => try stored_val.numberSubWrap(operand_val, operand_ty, sema.arena, target),
15590 .And => try stored_val.bitwiseAnd (operand_val, operand_ty, sema.arena, target),
15591 .Nand => try stored_val.bitwiseNand (operand_val, operand_ty, sema.arena, target),
15592 .Or => try stored_val.bitwiseOr (operand_val, operand_ty, sema.arena, target),
15593 .Xor => try stored_val.bitwiseXor (operand_val, operand_ty, sema.arena, target),
15594 .Max => stored_val.numberMax (operand_val, target),
15595 .Min => stored_val.numberMin (operand_val, target),
15618 .Add => try stored_val.numberAddWrap(operand_val, elem_ty, sema.arena, target),
15619 .Sub => try stored_val.numberSubWrap(operand_val, elem_ty, sema.arena, target),
15620 .And => try stored_val.bitwiseAnd (operand_val, elem_ty, sema.arena, target),
15621 .Nand => try stored_val.bitwiseNand (operand_val, elem_ty, sema.arena, target),
15622 .Or => try stored_val.bitwiseOr (operand_val, elem_ty, sema.arena, target),
15623 .Xor => try stored_val.bitwiseXor (operand_val, elem_ty, sema.arena, target),
15624 .Max => stored_val.numberMax (operand_val, target),
15625 .Min => stored_val.numberMin (operand_val, target),
1559615626 // zig fmt: on
1559715627 };
15598 try sema.storePtrVal(block, src, ptr_val, new_val, operand_ty);
15599 return sema.addConstant(operand_ty, stored_val);
15628 try sema.storePtrVal(block, src, ptr_val, new_val, elem_ty);
15629 return sema.addConstant(elem_ty, stored_val);
1560015630 } else break :rs ptr_src;
1560115631 } else ptr_src;
1560215632
......@@ -15620,15 +15650,15 @@ fn zirAtomicStore(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1562015650 const extra = sema.code.extraData(Zir.Inst.AtomicStore, inst_data.payload_index).data;
1562115651 const src = inst_data.src();
1562215652 // 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 };
1562415654 const ptr_src : LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
1562515655 const operand_src : LazySrcLoc = .{ .node_offset_builtin_call_arg2 = inst_data.src_node };
1562615656 const order_src : LazySrcLoc = .{ .node_offset_builtin_call_arg3 = inst_data.src_node };
1562715657 // zig fmt: on
15628 const ptr = sema.resolveInst(extra.ptr);
15629 const operand_ty = sema.typeOf(ptr).elemType();
15630 try sema.checkAtomicOperandType(block, operand_ty_src, operand_ty);
15631 const operand = try sema.coerce(block, operand_ty, sema.resolveInst(extra.operand), operand_src);
15658 const operand = sema.resolveInst(extra.operand);
15659 const elem_ty = sema.typeOf(operand);
15660 const uncasted_ptr = sema.resolveInst(extra.ptr);
15661 const ptr = try sema.checkAtomicPtrOperand(block, elem_ty, elem_ty_src, uncasted_ptr, ptr_src, false);
1563215662 const order = try sema.resolveAtomicOrder(block, order_src, extra.ordering);
1563315663
1563415664 const air_tag: Air.Inst.Tag = switch (order) {
src/Zir.zig+7-1
......@@ -903,7 +903,7 @@ pub const Inst = struct {
903903 /// Uses the `pl_node` union field with payload `Select`.
904904 select,
905905 /// Implements the `@atomicLoad` builtin.
906 /// Uses the `pl_node` union field with payload `Bin`.
906 /// Uses the `pl_node` union field with payload `AtomicLoad`.
907907 atomic_load,
908908 /// Implements the `@atomicRmw` builtin.
909909 /// Uses the `pl_node` union field with payload `AtomicRmw`.
......@@ -3293,6 +3293,12 @@ pub const Inst = struct {
32933293 ordering: Ref,
32943294 };
32953295
3296 pub const AtomicLoad = struct {
3297 elem_type: Ref,
3298 ptr: Ref,
3299 ordering: Ref,
3300 };
3301
32963302 pub const MulAdd = struct {
32973303 mulend1: Ref,
32983304 mulend2: Ref,
src/arch/x86_64/abi.zig+9-8
......@@ -12,13 +12,10 @@ pub fn classifyWindows(ty: Type, target: Target) Class {
1212 // and the registers used for those arguments. Any argument that doesn't fit in 8
1313 // bytes, or isn't 1, 2, 4, or 8 bytes, must be passed by reference. A single argument
1414 // is never spread across multiple registers."
15 // "All floating point operations are done using the 16 XMM registers."
1516 // "Structs and unions of size 8, 16, 32, or 64 bits, and __m64 types, are passed
1617 // as if they were integers of the same size."
17 switch (ty.abiSize(target)) {
18 1, 2, 4, 8 => {},
19 else => return .memory,
20 }
21 return switch (ty.zigTypeTag()) {
18 switch (ty.zigTypeTag()) {
2219 .Pointer,
2320 .Int,
2421 .Bool,
......@@ -33,9 +30,13 @@ pub fn classifyWindows(ty: Type, target: Target) Class {
3330 .ErrorUnion,
3431 .AnyFrame,
3532 .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
4041 .Type,
4142 .ComptimeFloat,
......@@ -47,7 +48,7 @@ pub fn classifyWindows(ty: Type, target: Target) Class {
4748 .Opaque,
4849 .EnumLiteral,
4950 => unreachable,
50 };
51 }
5152}
5253
5354/// 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 {
476476 _ = builder.buildRet(is_lt);
477477 }
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
479492 pub fn flushModule(self: *Object, comp: *Compilation, prog_node: *std.Progress.Node) !void {
480493 var sub_prog_node = prog_node.start("LLVM Emit Object", 0);
481494 sub_prog_node.activate();
......@@ -484,6 +497,7 @@ pub const Object = struct {
484497
485498 try self.genErrorNameTable(comp);
486499 try self.genCmpLtErrorsLenFunction(comp);
500 try self.genModuleLevelAssembly(comp);
487501
488502 if (self.di_builder) |dib| {
489503 // When lowering debug info for pointers, we emitted the element types as
......@@ -630,7 +644,17 @@ pub const Object = struct {
630644 if (!param_ty.hasRuntimeBitsIgnoreComptime()) continue;
631645
632646 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);
634658 }
635659
636660 var di_file: ?*llvm.DIFile = null;
......@@ -3729,6 +3753,19 @@ pub const FuncGen = struct {
37293753 arg_ptr.setAlignment(alignment);
37303754 const store_inst = self.builder.buildStore(llvm_arg, arg_ptr);
37313755 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
37323769 break :p self.builder.buildBitCast(arg_ptr, ptr_abi_ty, "");
37333770 };
37343771
......@@ -7583,7 +7620,7 @@ pub const FuncGen = struct {
75837620 const size_bytes = elem_ty.abiSize(target);
75847621 _ = self.builder.buildMemCpy(
75857622 self.builder.buildBitCast(ptr, llvm_ptr_u8, ""),
7586 ptr_ty.ptrAlignment(target),
7623 ptr_alignment,
75877624 self.builder.buildBitCast(elem, llvm_ptr_u8, ""),
75887625 elem_ty.abiAlignment(target),
75897626 self.context.intType(Type.usize.intInfo(target).bits).constInt(size_bytes, .False),
......@@ -7917,6 +7954,8 @@ fn llvmFieldIndex(
79177954}
79187955
79197956fn firstParamSRet(fn_info: Type.Payload.Function.Data, target: std.Target) bool {
7957 if (!fn_info.return_type.hasRuntimeBitsIgnoreComptime()) return false;
7958
79207959 switch (fn_info.cc) {
79217960 .Unspecified, .Inline => return isByRef(fn_info.return_type),
79227961 .C => switch (target.cpu.arch) {
......@@ -8016,7 +8055,8 @@ fn lowerFnRetTy(dg: *DeclGen, fn_info: Type.Payload.Function.Data) !*const llvm.
80168055 }
80178056 }
80188057 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));
80208060 }
80218061 return dg.context.structType(&llvm_types_buffer, llvm_types_index, .False);
80228062 },
......@@ -8110,7 +8150,8 @@ fn lowerFnParamTy(dg: *DeclGen, cc: std.builtin.CallingConvention, ty: Type) !*c
81108150 }
81118151 }
81128152 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));
81148155 }
81158156 return dg.context.structType(&llvm_types_buffer, llvm_types_index, .False);
81168157 },
src/codegen/llvm/bindings.zig+3
......@@ -381,6 +381,9 @@ pub const Module = opaque {
381381
382382 pub const createDIBuilder = ZigLLVMCreateDIBuilder;
383383 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;
384387};
385388
386389pub const lookupIntrinsicID = LLVMLookupIntrinsicID;
src/print_zir.zig+14-1
......@@ -283,6 +283,7 @@ const Writer = struct {
283283 => try self.writeStructInit(stream, inst),
284284
285285 .cmpxchg_strong, .cmpxchg_weak => try self.writeCmpxchg(stream, inst),
286 .atomic_load => try self.writeAtomicLoad(stream, inst),
286287 .atomic_store => try self.writeAtomicStore(stream, inst),
287288 .atomic_rmw => try self.writeAtomicRmw(stream, inst),
288289 .memcpy => try self.writeMemcpy(stream, inst),
......@@ -351,7 +352,6 @@ const Writer = struct {
351352 .offset_of,
352353 .splat,
353354 .reduce,
354 .atomic_load,
355355 .bitcast,
356356 .vector_type,
357357 .maximum,
......@@ -929,6 +929,19 @@ const Writer = struct {
929929 try self.writeSrc(stream, inst_data.src());
930930 }
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
932945 fn writeAtomicStore(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
933946 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
934947 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) {
76867686 // However for some targets, LLVM incorrectly reports this as 8.
76877687 // See: https://github.com/ziglang/zig/issues/2987
76887688 entry->abi_align = 16;
7689 entry->abi_size = align_forward(entry->abi_size, entry->abi_align);
76897690 }
76907691 }
76917692
src/target.zig+57-4
......@@ -1,5 +1,6 @@
11const std = @import("std");
22const llvm = @import("codegen/llvm/bindings.zig");
3const Type = @import("type.zig").Type;
34
45pub const ArchOsAbi = struct {
56 arch: std.Target.Cpu.Arch,
......@@ -543,10 +544,28 @@ pub fn needUnwindTables(target: std.Target) bool {
543544 return target.os.tag == .windows;
544545}
545546
546/// TODO this was ported from stage1 but it does not take into account CPU features,
547/// which can affect this value. Audit this!
548pub fn largestAtomicBits(target: std.Target) u32 {
549 return switch (target.cpu.arch) {
547pub const AtomicPtrAlignmentError = error{
548 FloatTooBig,
549 IntTooBig,
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) {
550569 .avr,
551570 .msp430,
552571 .spu_2,
......@@ -611,6 +630,40 @@ pub fn largestAtomicBits(target: std.Target) u32 {
611630
612631 .x86_64 => 128,
613632 };
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;
614667}
615668
616669pub fn defaultAddressSpace(
src/type.zig+24-16
......@@ -2788,11 +2788,6 @@ pub const Type = extern union {
27882788 return AbiAlignmentAdvanced{ .scalar = target_util.defaultFunctionAlignment(target) };
27892789 },
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
27962791 .isize,
27972792 .usize,
27982793 .single_const_pointer_to_comptime_int,
......@@ -2865,14 +2860,15 @@ pub const Type = extern union {
28652860 // ABI alignment of vectors?
28662861 .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
28682868 .int_signed, .int_unsigned => {
28692869 const bits: u16 = ty.cast(Payload.Bits).?.data;
28702870 if (bits == 0) return AbiAlignmentAdvanced{ .scalar = 0 };
2871 if (bits <= 8) return AbiAlignmentAdvanced{ .scalar = 1 };
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 };
2871 return AbiAlignmentAdvanced{ .scalar = intAbiAlignment(bits, target) };
28762872 },
28772873
28782874 .optional => {
......@@ -3113,10 +3109,6 @@ pub const Type = extern union {
31133109 assert(elem_size >= payload.elem_type.abiAlignment(target));
31143110 return (payload.len + 1) * elem_size;
31153111 },
3116 .i16, .u16 => return 2,
3117 .i32, .u32 => return 4,
3118 .i64, .u64 => return 8,
3119 .u128, .i128 => return 16,
31203112
31213113 .isize,
31223114 .usize,
......@@ -3189,10 +3181,14 @@ pub const Type = extern union {
31893181 .error_set_merged,
31903182 => 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),
31923188 .int_signed, .int_unsigned => {
31933189 const bits: u16 = self.cast(Payload.Bits).?.data;
31943190 if (bits == 0) return 0;
3195 return std.math.ceilPowerOfTwoPromote(u16, (bits + 7) / 8);
3191 return intAbiSize(bits, target);
31963192 },
31973193
31983194 .optional => {
......@@ -3234,6 +3230,18 @@ pub const Type = extern union {
32343230 };
32353231 }
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
32373245 /// Asserts the type has the bit size already resolved.
32383246 pub fn bitSize(ty: Type, target: Target) u64 {
32393247 return switch (ty.tag()) {
......@@ -5169,7 +5177,7 @@ pub const Type = extern union {
51695177
51705178 const field = it.struct_obj.fields.values()[it.field];
51715179 defer it.field += 1;
5172 if (!field.ty.hasRuntimeBits())
5180 if (!field.ty.hasRuntimeBits() or field.is_comptime)
51735181 return FieldOffset{ .field = it.field, .offset = it.offset };
51745182
51755183 const field_align = field.normalAlignment(it.target);
test/behavior/align.zig+111-26
......@@ -47,41 +47,128 @@ fn expects4(x: *align(4) u32) void {
4747 x.* += 1;
4848}
4949
50test "alignment of structs" {
50test "alignment of struct with pointer has same alignment as usize" {
5151 try expect(@alignOf(struct {
5252 a: i32,
5353 b: *i32,
5454 }) == @alignOf(usize));
5555}
5656
57test "alignment of >= 128-bit integer type" {
58 try expect(@alignOf(u128) == 16);
59 try expect(@alignOf(u129) == 16);
60}
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);
57test "alignment and size of structs with 128-bit fields" {
58 if (builtin.zig_backend == .stage1) {
59 // stage1 gets the wrong answer for a lot of targets
60 return error.SkipZigTest;
7161 }
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" {
75 try expect(@sizeOf(extern struct {
65 const A = struct {
66 x: u128,
67 };
68 const B = extern struct {
7669 x: u128,
7770 y: u8,
78 }) == 32);
79
71 };
72 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 };
80160 comptime {
81 try expect(@sizeOf(extern struct {
82 x: u128,
83 y: u8,
84 }) == 32);
161 std.debug.assert(@alignOf(A) == expected.a_align);
162 std.debug.assert(@sizeOf(A) == expected.a_size);
163
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);
85172 }
86173}
87174
......@@ -328,7 +415,6 @@ test "read 128-bit field from default aligned struct in stack memory" {
328415 .nevermind = 1,
329416 .badguy = 12,
330417 };
331 try expect((@ptrToInt(&default_aligned.badguy) % 16) == 0);
332418 try expect(12 == default_aligned.badguy);
333419}
334420
......@@ -345,7 +431,6 @@ test "read 128-bit field from default aligned struct in global memory" {
345431 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
346432 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
347433
348 try expect((@ptrToInt(&default_aligned_global.badguy) % 16) == 0);
349434 try expect(12 == default_aligned_global.badguy);
350435}
351436
test/behavior/asm.zig-1
......@@ -23,7 +23,6 @@ test "module level assembly" {
2323 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
2424 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2525 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
26 if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; // TODO
2726
2827 if (is_x86_64_linux) {
2928 try expect(this_is_my_alias() == 1234);
test/behavior/atomics.zig+1-1
......@@ -127,7 +127,7 @@ test "128-bit cmpxchg" {
127127}
128128
129129fn test_u128_cmpxchg() !void {
130 var x: u128 = 1234;
130 var x: u128 align(16) = 1234;
131131 if (@cmpxchgWeak(u128, &x, 99, 5678, .SeqCst, .SeqCst)) |x1| {
132132 try expect(x1 == 1234);
133133 } else {
test/behavior/bitcast.zig+7-12
......@@ -120,6 +120,10 @@ test "bitcast generates a temporary value" {
120120}
121121
122122test "@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 }
123127 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
124128 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
125129 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
......@@ -138,18 +142,9 @@ test "@bitCast packed structs at runtime and comptime" {
138142 fn doTheTest() !void {
139143 var full = Full{ .number = 0x1234 };
140144 var two_halves = @bitCast(Divided, full);
141 switch (native_endian) {
142 .Big => {
143 try expect(two_halves.half1 == 0x12);
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 }
145 try expect(two_halves.half1 == 0x34);
146 try expect(two_halves.quarter3 == 0x2);
147 try expect(two_halves.quarter4 == 0x1);
153148 }
154149 };
155150 try S.doTheTest();
test/behavior/struct.zig+9-6
......@@ -499,17 +499,18 @@ const Bitfields = packed struct {
499499 f7: u8,
500500};
501501
502test "native bit field understands endianness" {
503 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
502test "packed struct fields are ordered from LSB to MSB" {
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
504508 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
505509 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
506510 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
507511 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
508512
509 var all: u64 = if (native_endian != .Little)
510 0x1111222233445677
511 else
512 0x7765443322221111;
513 var all: u64 = 0x7765443322221111;
513514 var bytes: [8]u8 = undefined;
514515 @memcpy(&bytes, @ptrCast([*]u8, &all), 8);
515516 var bitfields = @ptrCast(*Bitfields, &bytes).*;
......@@ -974,6 +975,8 @@ test "comptime struct field" {
974975 comptime b: i32 = 1234,
975976 };
976977
978 comptime std.debug.assert(@sizeOf(T) == 4);
979
977980 var foo: T = undefined;
978981 comptime try expect(foo.b == 1234);
979982}