| author | |
| committer | |
| log | 4c1007fc044689b8cbc20634d73debb43df8efe1 |
| tree | 967e4bd30091e0d28816febe1c9fea1b761b9a94 |
| parent | 4172c2916684655a9742de99384be8110922ed07 |
| parent | 23b1544f6c17dd1111ba8791189a7290581f945e |
| signature |
CBE: MSVC-compatible code generation, and fixes to get behaviour tests passing and zig2.c building16 files changed, 1507 insertions(+), 319 deletions(-)
lib/compiler_rt/divti3.zig+3-16| ... | ... | @@ -7,21 +7,8 @@ const common = @import("common.zig"); |
| 7 | 7 | pub const panic = common.panic; |
| 8 | 8 | |
| 9 | 9 | comptime { |
| 10 | if (builtin.os.tag == .windows) { | |
| 11 | switch (arch) { | |
| 12 | .x86 => { | |
| 13 | @export(__divti3, .{ .name = "__divti3", .linkage = common.linkage, .visibility = common.visibility }); | |
| 14 | }, | |
| 15 | .x86_64 => { | |
| 16 | // The "ti" functions must use Vector(2, u64) parameter types to adhere to the ABI | |
| 17 | // that LLVM expects compiler-rt to have. | |
| 18 | @export(__divti3_windows_x86_64, .{ .name = "__divti3", .linkage = common.linkage, .visibility = common.visibility }); | |
| 19 | }, | |
| 20 | else => {}, | |
| 21 | } | |
| 22 | if (arch.isAARCH64()) { | |
| 23 | @export(__divti3, .{ .name = "__divti3", .linkage = common.linkage, .visibility = common.visibility }); | |
| 24 | } | |
| 10 | if (common.want_windows_v2u64_abi) { | |
| 11 | @export(__divti3_windows_x86_64, .{ .name = "__divti3", .linkage = common.linkage, .visibility = common.visibility }); | |
| 25 | 12 | } else { |
| 26 | 13 | @export(__divti3, .{ .name = "__divti3", .linkage = common.linkage, .visibility = common.visibility }); |
| 27 | 14 | } |
| ... | ... | @@ -31,7 +18,7 @@ pub fn __divti3(a: i128, b: i128) callconv(.C) i128 { |
| 31 | 18 | return div(a, b); |
| 32 | 19 | } |
| 33 | 20 | |
| 34 | const v128 = @import("std").meta.Vector(2, u64); | |
| 21 | const v128 = @Vector(2, u64); | |
| 35 | 22 | |
| 36 | 23 | fn __divti3_windows_x86_64(a: v128, b: v128) callconv(.C) v128 { |
| 37 | 24 | return @bitCast(v128, div(@bitCast(i128, a), @bitCast(i128, b))); |
lib/compiler_rt/fixunshfti.zig+1-1| ... | ... | @@ -16,7 +16,7 @@ pub fn __fixunshfti(a: f16) callconv(.C) u128 { |
| 16 | 16 | return floatToInt(u128, a); |
| 17 | 17 | } |
| 18 | 18 | |
| 19 | const v2u64 = @import("std").meta.Vector(2, u64); | |
| 19 | const v2u64 = @Vector(2, u64); | |
| 20 | 20 | |
| 21 | 21 | fn __fixunshfti_windows_x86_64(a: f16) callconv(.C) v2u64 { |
| 22 | 22 | return @bitCast(v2u64, floatToInt(u128, a)); |
lib/compiler_rt/udivmodei4.zig+2| ... | ... | @@ -129,6 +129,8 @@ pub fn __umodei4(r_p: [*c]u32, u_p: [*c]const u32, v_p: [*c]const u32, bits: usi |
| 129 | 129 | } |
| 130 | 130 | |
| 131 | 131 | test "__udivei4/__umodei4" { |
| 132 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | |
| 133 | ||
| 132 | 134 | const RndGen = std.rand.DefaultPrng; |
| 133 | 135 | var rnd = RndGen.init(42); |
| 134 | 136 | var i: usize = 10000; |
lib/std/math/big/int.zig+34| ... | ... | @@ -1677,6 +1677,40 @@ pub const Mutable = struct { |
| 1677 | 1677 | y.shiftRight(y.toConst(), norm_shift); |
| 1678 | 1678 | } |
| 1679 | 1679 | |
| 1680 | /// If a is positive, this passes through to truncate. | |
| 1681 | /// If a is negative, then r is set to positive with the bit pattern ~(a - 1). | |
| 1682 | /// | |
| 1683 | /// Asserts `r` has enough storage to store the result. | |
| 1684 | /// The upper bound is `calcTwosCompLimbCount(a.len)`. | |
| 1685 | pub fn convertToTwosComplement(r: *Mutable, a: Const, signedness: Signedness, bit_count: usize) void { | |
| 1686 | if (a.positive) { | |
| 1687 | r.truncate(a, signedness, bit_count); | |
| 1688 | return; | |
| 1689 | } | |
| 1690 | ||
| 1691 | const req_limbs = calcTwosCompLimbCount(bit_count); | |
| 1692 | if (req_limbs == 0 or a.eqZero()) { | |
| 1693 | r.set(0); | |
| 1694 | return; | |
| 1695 | } | |
| 1696 | ||
| 1697 | const bit = @truncate(Log2Limb, bit_count - 1); | |
| 1698 | const signmask = @as(Limb, 1) << bit; | |
| 1699 | const mask = (signmask << 1) -% 1; | |
| 1700 | ||
| 1701 | r.addScalar(a.abs(), -1); | |
| 1702 | if (req_limbs > r.len) { | |
| 1703 | mem.set(Limb, r.limbs[r.len..req_limbs], 0); | |
| 1704 | } | |
| 1705 | ||
| 1706 | assert(r.limbs.len >= req_limbs); | |
| 1707 | r.len = req_limbs; | |
| 1708 | ||
| 1709 | llnot(r.limbs[0..r.len]); | |
| 1710 | r.limbs[r.len - 1] &= mask; | |
| 1711 | r.normalize(r.len); | |
| 1712 | } | |
| 1713 | ||
| 1680 | 1714 | /// Truncate an integer to a number of bits, following 2s-complement semantics. |
| 1681 | 1715 | /// r may alias a. |
| 1682 | 1716 | /// |
lib/std/mem.zig+23-7| ... | ... | @@ -3771,7 +3771,7 @@ pub fn doNotOptimizeAway(val: anytype) void { |
| 3771 | 3771 | .Bool => doNotOptimizeAway(@boolToInt(val)), |
| 3772 | 3772 | .Int => { |
| 3773 | 3773 | const bits = t.Int.bits; |
| 3774 | if (bits <= max_gp_register_bits) { | |
| 3774 | if (bits <= max_gp_register_bits and builtin.zig_backend != .stage2_c) { | |
| 3775 | 3775 | const val2 = @as( |
| 3776 | 3776 | std.meta.Int(t.Int.signedness, @max(8, std.math.ceilPowerOfTwoAssert(u16, bits))), |
| 3777 | 3777 | val, |
| ... | ... | @@ -3783,18 +3783,24 @@ pub fn doNotOptimizeAway(val: anytype) void { |
| 3783 | 3783 | } else doNotOptimizeAway(&val); |
| 3784 | 3784 | }, |
| 3785 | 3785 | .Float => { |
| 3786 | if (t.Float.bits == 32 or t.Float.bits == 64) { | |
| 3786 | if ((t.Float.bits == 32 or t.Float.bits == 64) and builtin.zig_backend != .stage2_c) { | |
| 3787 | 3787 | asm volatile ("" |
| 3788 | 3788 | : |
| 3789 | 3789 | : [val] "rm" (val), |
| 3790 | 3790 | ); |
| 3791 | 3791 | } else doNotOptimizeAway(&val); |
| 3792 | 3792 | }, |
| 3793 | .Pointer => asm volatile ("" | |
| 3794 | : | |
| 3795 | : [val] "m" (val), | |
| 3796 | : "memory" | |
| 3797 | ), | |
| 3793 | .Pointer => { | |
| 3794 | if (builtin.zig_backend == .stage2_c) { | |
| 3795 | doNotOptimizeAwayC(val); | |
| 3796 | } else { | |
| 3797 | asm volatile ("" | |
| 3798 | : | |
| 3799 | : [val] "m" (val), | |
| 3800 | : "memory" | |
| 3801 | ); | |
| 3802 | } | |
| 3803 | }, | |
| 3798 | 3804 | .Array => { |
| 3799 | 3805 | if (t.Array.len * @sizeOf(t.Array.child) <= 64) { |
| 3800 | 3806 | for (val) |v| doNotOptimizeAway(v); |
| ... | ... | @@ -3804,6 +3810,16 @@ pub fn doNotOptimizeAway(val: anytype) void { |
| 3804 | 3810 | } |
| 3805 | 3811 | } |
| 3806 | 3812 | |
| 3813 | /// .stage2_c doesn't support asm blocks yet, so use volatile stores instead | |
| 3814 | var deopt_target: if (builtin.zig_backend == .stage2_c) u8 else void = undefined; | |
| 3815 | fn doNotOptimizeAwayC(ptr: anytype) void { | |
| 3816 | const dest = @ptrCast(*volatile u8, &deopt_target); | |
| 3817 | for (asBytes(ptr)) |b| { | |
| 3818 | dest.* = b; | |
| 3819 | } | |
| 3820 | dest.* = 0; | |
| 3821 | } | |
| 3822 | ||
| 3807 | 3823 | test "doNotOptimizeAway" { |
| 3808 | 3824 | comptime doNotOptimizeAway("test"); |
| 3809 | 3825 |
lib/std/os/windows.zig+29-4| ... | ... | @@ -1776,16 +1776,26 @@ pub fn UnlockFile( |
| 1776 | 1776 | } |
| 1777 | 1777 | } |
| 1778 | 1778 | |
| 1779 | /// This is a workaround for the C backend until zig has the ability to put | |
| 1780 | /// C code in inline assembly. | |
| 1781 | extern fn zig_x86_64_windows_teb() callconv(.C) *anyopaque; | |
| 1782 | ||
| 1779 | 1783 | pub fn teb() *TEB { |
| 1780 | 1784 | return switch (native_arch) { |
| 1781 | 1785 | .x86 => asm volatile ( |
| 1782 | 1786 | \\ movl %%fs:0x18, %[ptr] |
| 1783 | 1787 | : [ptr] "=r" (-> *TEB), |
| 1784 | 1788 | ), |
| 1785 | .x86_64 => asm volatile ( | |
| 1786 | \\ movq %%gs:0x30, %[ptr] | |
| 1787 | : [ptr] "=r" (-> *TEB), | |
| 1788 | ), | |
| 1789 | .x86_64 => blk: { | |
| 1790 | if (builtin.zig_backend == .stage2_c) { | |
| 1791 | break :blk @ptrCast(*TEB, @alignCast(@alignOf(TEB), zig_x86_64_windows_teb())); | |
| 1792 | } else { | |
| 1793 | break :blk asm volatile ( | |
| 1794 | \\ movq %%gs:0x30, %[ptr] | |
| 1795 | : [ptr] "=r" (-> *TEB), | |
| 1796 | ); | |
| 1797 | } | |
| 1798 | }, | |
| 1789 | 1799 | .aarch64 => asm volatile ( |
| 1790 | 1800 | \\ mov %[ptr], x18 |
| 1791 | 1801 | : [ptr] "=r" (-> *TEB), |
| ... | ... | @@ -3455,6 +3465,21 @@ pub const ASSEMBLY_STORAGE_MAP = opaque {}; |
| 3455 | 3465 | pub const FLS_CALLBACK_INFO = opaque {}; |
| 3456 | 3466 | pub const RTL_BITMAP = opaque {}; |
| 3457 | 3467 | pub const KAFFINITY = usize; |
| 3468 | pub const KPRIORITY = i32; | |
| 3469 | ||
| 3470 | pub const CLIENT_ID = extern struct { | |
| 3471 | UniqueProcess: HANDLE, | |
| 3472 | UniqueThread: HANDLE, | |
| 3473 | }; | |
| 3474 | ||
| 3475 | pub const THREAD_BASIC_INFORMATION = extern struct { | |
| 3476 | ExitStatus: NTSTATUS, | |
| 3477 | TebBaseAddress: PVOID, | |
| 3478 | ClientId: CLIENT_ID, | |
| 3479 | AffinityMask: KAFFINITY, | |
| 3480 | Priority: KPRIORITY, | |
| 3481 | BasePriority: KPRIORITY, | |
| 3482 | }; | |
| 3458 | 3483 | |
| 3459 | 3484 | pub const TEB = extern struct { |
| 3460 | 3485 | Reserved1: [12]PVOID, |
lib/std/zig/system/x86.zig+27-8| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | 1 | const std = @import("std"); |
| 2 | const builtin = @import("builtin"); | |
| 2 | 3 | const Target = std.Target; |
| 3 | 4 | const CrossTarget = std.zig.CrossTarget; |
| 4 | 5 | |
| ... | ... | @@ -527,25 +528,43 @@ const CpuidLeaf = packed struct { |
| 527 | 528 | edx: u32, |
| 528 | 529 | }; |
| 529 | 530 | |
| 531 | /// This is a workaround for the C backend until zig has the ability to put | |
| 532 | /// C code in inline assembly. | |
| 533 | extern fn zig_x86_cpuid(leaf_id: u32, subid: u32, eax: *u32, ebx: *u32, ecx: *u32, edx: *u32) callconv(.C) void; | |
| 534 | ||
| 530 | 535 | fn cpuid(leaf_id: u32, subid: u32) CpuidLeaf { |
| 531 | 536 | // valid for both x86 and x86_64 |
| 532 | 537 | var eax: u32 = undefined; |
| 533 | 538 | var ebx: u32 = undefined; |
| 534 | 539 | var ecx: u32 = undefined; |
| 535 | 540 | var edx: u32 = undefined; |
| 536 | asm volatile ("cpuid" | |
| 537 | : [_] "={eax}" (eax), | |
| 538 | [_] "={ebx}" (ebx), | |
| 539 | [_] "={ecx}" (ecx), | |
| 540 | [_] "={edx}" (edx), | |
| 541 | : [_] "{eax}" (leaf_id), | |
| 542 | [_] "{ecx}" (subid), | |
| 543 | ); | |
| 541 | ||
| 542 | if (builtin.zig_backend == .stage2_c) { | |
| 543 | zig_x86_cpuid(leaf_id, subid, &eax, &ebx, &ecx, &edx); | |
| 544 | } else { | |
| 545 | asm volatile ("cpuid" | |
| 546 | : [_] "={eax}" (eax), | |
| 547 | [_] "={ebx}" (ebx), | |
| 548 | [_] "={ecx}" (ecx), | |
| 549 | [_] "={edx}" (edx), | |
| 550 | : [_] "{eax}" (leaf_id), | |
| 551 | [_] "{ecx}" (subid), | |
| 552 | ); | |
| 553 | } | |
| 554 | ||
| 544 | 555 | return .{ .eax = eax, .ebx = ebx, .ecx = ecx, .edx = edx }; |
| 545 | 556 | } |
| 546 | 557 | |
| 558 | /// This is a workaround for the C backend until zig has the ability to put | |
| 559 | /// C code in inline assembly. | |
| 560 | extern fn zig_x86_get_xcr0() callconv(.C) u32; | |
| 561 | ||
| 547 | 562 | // Read control register 0 (XCR0). Used to detect features such as AVX. |
| 548 | 563 | fn getXCR0() u32 { |
| 564 | if (builtin.zig_backend == .stage2_c) { | |
| 565 | return zig_x86_get_xcr0(); | |
| 566 | } | |
| 567 | ||
| 549 | 568 | return asm volatile ( |
| 550 | 569 | \\ xor %%ecx, %%ecx |
| 551 | 570 | \\ xgetbv |
lib/zig.h+584-86| ... | ... | @@ -6,6 +6,12 @@ |
| 6 | 6 | #include <stddef.h> |
| 7 | 7 | #include <stdint.h> |
| 8 | 8 | |
| 9 | #if _MSC_VER | |
| 10 | #include <intrin.h> | |
| 11 | #elif defined(__i386__) || defined(__x86_64__) | |
| 12 | #include <cpuid.h> | |
| 13 | #endif | |
| 14 | ||
| 9 | 15 | #if !defined(__cplusplus) && __STDC_VERSION__ <= 201710L |
| 10 | 16 | #if __STDC_VERSION__ >= 199901L |
| 11 | 17 | #include <stdbool.h> |
| ... | ... | @@ -38,6 +44,12 @@ typedef char bool; |
| 38 | 44 | #define zig_threadlocal zig_threadlocal_unavailable |
| 39 | 45 | #endif |
| 40 | 46 | |
| 47 | #if _MSC_VER | |
| 48 | #define zig_const_arr | |
| 49 | #else | |
| 50 | #define zig_const_arr static const | |
| 51 | #endif | |
| 52 | ||
| 41 | 53 | #if zig_has_attribute(naked) || defined(__GNUC__) |
| 42 | 54 | #define zig_naked __attribute__((naked)) |
| 43 | 55 | #elif defined(_MSC_VER) |
| ... | ... | @@ -65,7 +77,7 @@ typedef char bool; |
| 65 | 77 | #elif zig_has_attribute(aligned) |
| 66 | 78 | #define zig_align(alignment) __attribute__((aligned(alignment))) |
| 67 | 79 | #elif _MSC_VER |
| 68 | #define zig_align zig_align_unavailable | |
| 80 | #define zig_align(alignment) __declspec(align(alignment)) | |
| 69 | 81 | #else |
| 70 | 82 | #define zig_align zig_align_unavailable |
| 71 | 83 | #endif |
| ... | ... | @@ -73,7 +85,7 @@ typedef char bool; |
| 73 | 85 | #if zig_has_attribute(aligned) |
| 74 | 86 | #define zig_align_fn(alignment) __attribute__((aligned(alignment))) |
| 75 | 87 | #elif _MSC_VER |
| 76 | #define zig_align_fn zig_align_fn_unavailable | |
| 88 | #define zig_align_fn(alignment) | |
| 77 | 89 | #else |
| 78 | 90 | #define zig_align_fn zig_align_fn_unavailable |
| 79 | 91 | #endif |
| ... | ... | @@ -92,6 +104,9 @@ typedef char bool; |
| 92 | 104 | |
| 93 | 105 | #if zig_has_attribute(alias) |
| 94 | 106 | #define zig_export(sig, symbol, name) zig_extern sig __attribute__((alias(symbol))) |
| 107 | #elif _MSC_VER | |
| 108 | #define zig_export(sig, symbol, name) sig;\ | |
| 109 | __pragma(comment(linker, "/alternatename:" name "=" symbol )) | |
| 95 | 110 | #else |
| 96 | 111 | #define zig_export(sig, symbol, name) __asm(name " = " symbol) |
| 97 | 112 | #endif |
| ... | ... | @@ -136,22 +151,25 @@ typedef char bool; |
| 136 | 151 | #define zig_wasm_memory_grow(index, delta) zig_unimplemented() |
| 137 | 152 | #endif |
| 138 | 153 | |
| 154 | #define zig_concat(lhs, rhs) lhs##rhs | |
| 155 | #define zig_expand_concat(lhs, rhs) zig_concat(lhs, rhs) | |
| 156 | ||
| 139 | 157 | #if __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_ATOMICS__) |
| 140 | 158 | #include <stdatomic.h> |
| 141 | 159 | #define zig_atomic(type) _Atomic(type) |
| 142 | #define zig_cmpxchg_strong(obj, expected, desired, succ, fail) atomic_compare_exchange_strong_explicit(obj, &(expected), desired, succ, fail) | |
| 143 | #define zig_cmpxchg_weak(obj, expected, desired, succ, fail) atomic_compare_exchange_weak_explicit (obj, &(expected), desired, succ, fail) | |
| 144 | #define zig_atomicrmw_xchg(obj, arg, order) atomic_exchange_explicit (obj, arg, order) | |
| 145 | #define zig_atomicrmw_add(obj, arg, order) atomic_fetch_add_explicit (obj, arg, order) | |
| 146 | #define zig_atomicrmw_sub(obj, arg, order) atomic_fetch_sub_explicit (obj, arg, order) | |
| 147 | #define zig_atomicrmw_or(obj, arg, order) atomic_fetch_or_explicit (obj, arg, order) | |
| 148 | #define zig_atomicrmw_xor(obj, arg, order) atomic_fetch_xor_explicit (obj, arg, order) | |
| 149 | #define zig_atomicrmw_and(obj, arg, order) atomic_fetch_and_explicit (obj, arg, order) | |
| 150 | #define zig_atomicrmw_nand(obj, arg, order) __atomic_fetch_nand (obj, arg, order) | |
| 151 | #define zig_atomicrmw_min(obj, arg, order) __atomic_fetch_min (obj, arg, order) | |
| 152 | #define zig_atomicrmw_max(obj, arg, order) __atomic_fetch_max (obj, arg, order) | |
| 153 | #define zig_atomic_store(obj, arg, order) atomic_store_explicit (obj, arg, order) | |
| 154 | #define zig_atomic_load(obj, order) atomic_load_explicit (obj, order) | |
| 160 | #define zig_cmpxchg_strong(obj, expected, desired, succ, fail, type) atomic_compare_exchange_strong_explicit(obj, &(expected), desired, succ, fail) | |
| 161 | #define zig_cmpxchg_weak(obj, expected, desired, succ, fail, type) atomic_compare_exchange_weak_explicit (obj, &(expected), desired, succ, fail) | |
| 162 | #define zig_atomicrmw_xchg(obj, arg, order, type) atomic_exchange_explicit (obj, arg, order) | |
| 163 | #define zig_atomicrmw_add(obj, arg, order, type) atomic_fetch_add_explicit (obj, arg, order) | |
| 164 | #define zig_atomicrmw_sub(obj, arg, order, type) atomic_fetch_sub_explicit (obj, arg, order) | |
| 165 | #define zig_atomicrmw_or(obj, arg, order, type) atomic_fetch_or_explicit (obj, arg, order) | |
| 166 | #define zig_atomicrmw_xor(obj, arg, order, type) atomic_fetch_xor_explicit (obj, arg, order) | |
| 167 | #define zig_atomicrmw_and(obj, arg, order, type) atomic_fetch_and_explicit (obj, arg, order) | |
| 168 | #define zig_atomicrmw_nand(obj, arg, order, type) __atomic_fetch_nand (obj, arg, order) | |
| 169 | #define zig_atomicrmw_min(obj, arg, order, type) __atomic_fetch_min (obj, arg, order) | |
| 170 | #define zig_atomicrmw_max(obj, arg, order, type) __atomic_fetch_max (obj, arg, order) | |
| 171 | #define zig_atomic_store(obj, arg, order, type) atomic_store_explicit (obj, arg, order) | |
| 172 | #define zig_atomic_load(obj, order, type) atomic_load_explicit (obj, order) | |
| 155 | 173 | #define zig_fence(order) atomic_thread_fence(order) |
| 156 | 174 | #elif defined(__GNUC__) |
| 157 | 175 | #define memory_order_relaxed __ATOMIC_RELAXED |
| ... | ... | @@ -161,20 +179,43 @@ typedef char bool; |
| 161 | 179 | #define memory_order_acq_rel __ATOMIC_ACQ_REL |
| 162 | 180 | #define memory_order_seq_cst __ATOMIC_SEQ_CST |
| 163 | 181 | #define zig_atomic(type) type |
| 164 | #define zig_cmpxchg_strong(obj, expected, desired, succ, fail) __atomic_compare_exchange_n(obj, &(expected), desired, false, succ, fail) | |
| 165 | #define zig_cmpxchg_weak(obj, expected, desired, succ, fail) __atomic_compare_exchange_n(obj, &(expected), desired, true , succ, fail) | |
| 166 | #define zig_atomicrmw_xchg(obj, arg, order) __atomic_exchange_n(obj, arg, order) | |
| 167 | #define zig_atomicrmw_add(obj, arg, order) __atomic_fetch_add (obj, arg, order) | |
| 168 | #define zig_atomicrmw_sub(obj, arg, order) __atomic_fetch_sub (obj, arg, order) | |
| 169 | #define zig_atomicrmw_or(obj, arg, order) __atomic_fetch_or (obj, arg, order) | |
| 170 | #define zig_atomicrmw_xor(obj, arg, order) __atomic_fetch_xor (obj, arg, order) | |
| 171 | #define zig_atomicrmw_and(obj, arg, order) __atomic_fetch_and (obj, arg, order) | |
| 172 | #define zig_atomicrmw_nand(obj, arg, order) __atomic_fetch_nand(obj, arg, order) | |
| 173 | #define zig_atomicrmw_min(obj, arg, order) __atomic_fetch_min (obj, arg, order) | |
| 174 | #define zig_atomicrmw_max(obj, arg, order) __atomic_fetch_max (obj, arg, order) | |
| 175 | #define zig_atomic_store(obj, arg, order) __atomic_store_n (obj, arg, order) | |
| 176 | #define zig_atomic_load(obj, order) __atomic_load_n (obj, order) | |
| 182 | #define zig_cmpxchg_strong(obj, expected, desired, succ, fail, type) __atomic_compare_exchange_n(obj, &(expected), desired, false, succ, fail) | |
| 183 | #define zig_cmpxchg_weak(obj, expected, desired, succ, fail, type) __atomic_compare_exchange_n(obj, &(expected), desired, true , succ, fail) | |
| 184 | #define zig_atomicrmw_xchg(obj, arg, order, type) __atomic_exchange_n(obj, arg, order) | |
| 185 | #define zig_atomicrmw_add(obj, arg, order, type) __atomic_fetch_add (obj, arg, order) | |
| 186 | #define zig_atomicrmw_sub(obj, arg, order, type) __atomic_fetch_sub (obj, arg, order) | |
| 187 | #define zig_atomicrmw_or(obj, arg, order, type) __atomic_fetch_or (obj, arg, order) | |
| 188 | #define zig_atomicrmw_xor(obj, arg, order, type) __atomic_fetch_xor (obj, arg, order) | |
| 189 | #define zig_atomicrmw_and(obj, arg, order, type) __atomic_fetch_and (obj, arg, order) | |
| 190 | #define zig_atomicrmw_nand(obj, arg, order, type) __atomic_fetch_nand(obj, arg, order) | |
| 191 | #define zig_atomicrmw_min(obj, arg, order, type) __atomic_fetch_min (obj, arg, order) | |
| 192 | #define zig_atomicrmw_max(obj, arg, order, type) __atomic_fetch_max (obj, arg, order) | |
| 193 | #define zig_atomic_store(obj, arg, order, type) __atomic_store_n (obj, arg, order) | |
| 194 | #define zig_atomic_load(obj, order, type) __atomic_load_n (obj, order) | |
| 177 | 195 | #define zig_fence(order) __atomic_thread_fence(order) |
| 196 | #elif _MSC_VER && (_M_IX86 || _M_X64) | |
| 197 | #define memory_order_relaxed 0 | |
| 198 | #define memory_order_consume 1 | |
| 199 | #define memory_order_acquire 2 | |
| 200 | #define memory_order_release 3 | |
| 201 | #define memory_order_acq_rel 4 | |
| 202 | #define memory_order_seq_cst 5 | |
| 203 | #define zig_atomic(type) type | |
| 204 | #define zig_cmpxchg_strong(obj, expected, desired, succ, fail, type) zig_expand_concat(zig_msvc_cmpxchg_, type)(obj, &(expected), desired) | |
| 205 | #define zig_cmpxchg_weak(obj, expected, desired, succ, fail, type) zig_cmpxchg_strong(obj, expected, desired, succ, fail, type) | |
| 206 | #define zig_atomicrmw_xchg(obj, arg, order, type) zig_expand_concat(zig_msvc_atomicrmw_xchg_, type)(obj, arg) | |
| 207 | #define zig_atomicrmw_add(obj, arg, order, type) zig_expand_concat(zig_msvc_atomicrmw_add_, type)(obj, arg) | |
| 208 | #define zig_atomicrmw_sub(obj, arg, order, type) zig_expand_concat(zig_msvc_atomicrmw_sub_, type)(obj, arg) | |
| 209 | #define zig_atomicrmw_or(obj, arg, order, type) zig_expand_concat(zig_msvc_atomicrmw_or_, type)(obj, arg) | |
| 210 | #define zig_atomicrmw_xor(obj, arg, order, type) zig_expand_concat(zig_msvc_atomicrmw_xor_, type)(obj, arg) | |
| 211 | #define zig_atomicrmw_and(obj, arg, order, type) zig_expand_concat(zig_msvc_atomicrmw_and_, type)(obj, arg) | |
| 212 | #define zig_atomicrmw_nand(obj, arg, order, type) zig_expand_concat(zig_msvc_atomicrmw_nand_, type)(obj, arg) | |
| 213 | #define zig_atomicrmw_min(obj, arg, order, type) zig_expand_concat(zig_msvc_atomicrmw_min_, type)(obj, arg) | |
| 214 | #define zig_atomicrmw_max(obj, arg, order, type) zig_expand_concat(zig_msvc_atomicrmw_max_, type)(obj, arg) | |
| 215 | #define zig_atomic_store(obj, arg, order, type) zig_expand_concat(zig_msvc_atomic_store_, type)(obj, arg) | |
| 216 | #define zig_atomic_load(obj, order, type) zig_expand_concat(zig_msvc_atomic_load_, type)(obj) | |
| 217 | #define zig_fence(order) __faststorefence() | |
| 218 | // TODO: _MSC_VER && (_M_ARM || _M_ARM64) | |
| 178 | 219 | #else |
| 179 | 220 | #define memory_order_relaxed 0 |
| 180 | 221 | #define memory_order_consume 1 |
| ... | ... | @@ -183,19 +224,19 @@ typedef char bool; |
| 183 | 224 | #define memory_order_acq_rel 4 |
| 184 | 225 | #define memory_order_seq_cst 5 |
| 185 | 226 | #define zig_atomic(type) type |
| 186 | #define zig_cmpxchg_strong(obj, expected, desired, succ, fail) zig_unimplemented() | |
| 187 | #define zig_cmpxchg_weak(obj, expected, desired, succ, fail) zig_unimplemented() | |
| 188 | #define zig_atomicrmw_xchg(obj, arg, order) zig_unimplemented() | |
| 189 | #define zig_atomicrmw_add(obj, arg, order) zig_unimplemented() | |
| 190 | #define zig_atomicrmw_sub(obj, arg, order) zig_unimplemented() | |
| 191 | #define zig_atomicrmw_or(obj, arg, order) zig_unimplemented() | |
| 192 | #define zig_atomicrmw_xor(obj, arg, order) zig_unimplemented() | |
| 193 | #define zig_atomicrmw_and(obj, arg, order) zig_unimplemented() | |
| 194 | #define zig_atomicrmw_nand(obj, arg, order) zig_unimplemented() | |
| 195 | #define zig_atomicrmw_min(obj, arg, order) zig_unimplemented() | |
| 196 | #define zig_atomicrmw_max(obj, arg, order) zig_unimplemented() | |
| 197 | #define zig_atomic_store(obj, arg, order) zig_unimplemented() | |
| 198 | #define zig_atomic_load(obj, order) zig_unimplemented() | |
| 227 | #define zig_cmpxchg_strong(obj, expected, desired, succ, fail, type) zig_unimplemented() | |
| 228 | #define zig_cmpxchg_weak(obj, expected, desired, succ, fail, type) zig_unimplemented() | |
| 229 | #define zig_atomicrmw_xchg(obj, arg, order, type) zig_unimplemented() | |
| 230 | #define zig_atomicrmw_add(obj, arg, order, type) zig_unimplemented() | |
| 231 | #define zig_atomicrmw_sub(obj, arg, order, type) zig_unimplemented() | |
| 232 | #define zig_atomicrmw_or(obj, arg, order, type) zig_unimplemented() | |
| 233 | #define zig_atomicrmw_xor(obj, arg, order, type) zig_unimplemented() | |
| 234 | #define zig_atomicrmw_and(obj, arg, order, type) zig_unimplemented() | |
| 235 | #define zig_atomicrmw_nand(obj, arg, order, type) zig_unimplemented() | |
| 236 | #define zig_atomicrmw_min(obj, arg, order, type) zig_unimplemented() | |
| 237 | #define zig_atomicrmw_max(obj, arg, order, type) zig_unimplemented() | |
| 238 | #define zig_atomic_store(obj, arg, order, type) zig_unimplemented() | |
| 239 | #define zig_atomic_load(obj, order, type) zig_unimplemented() | |
| 199 | 240 | #define zig_fence(order) zig_unimplemented() |
| 200 | 241 | #endif |
| 201 | 242 | |
| ... | ... | @@ -209,9 +250,6 @@ typedef char bool; |
| 209 | 250 | #define zig_noreturn void |
| 210 | 251 | #endif |
| 211 | 252 | |
| 212 | #define zig_concat(lhs, rhs) lhs##rhs | |
| 213 | #define zig_expand_concat(lhs, rhs) zig_concat(lhs, rhs) | |
| 214 | ||
| 215 | 253 | #define zig_bitSizeOf(T) (CHAR_BIT * sizeof(T)) |
| 216 | 254 | |
| 217 | 255 | typedef uintptr_t zig_usize; |
| ... | ... | @@ -1141,6 +1179,8 @@ typedef signed __int128 zig_i128; |
| 1141 | 1179 | |
| 1142 | 1180 | #define zig_as_u128(hi, lo) ((zig_u128)(hi)<<64|(lo)) |
| 1143 | 1181 | #define zig_as_i128(hi, lo) ((zig_i128)zig_as_u128(hi, lo)) |
| 1182 | #define zig_as_constant_u128(hi, lo) zig_as_u128(hi, lo) | |
| 1183 | #define zig_as_constant_i128(hi, lo) zig_as_i128(hi, lo) | |
| 1144 | 1184 | #define zig_hi_u128(val) ((zig_u64)((val) >> 64)) |
| 1145 | 1185 | #define zig_lo_u128(val) ((zig_u64)((val) >> 0)) |
| 1146 | 1186 | #define zig_hi_i128(val) ((zig_i64)((val) >> 64)) |
| ... | ... | @@ -1168,6 +1208,8 @@ typedef struct { zig_align(16) zig_i64 hi; zig_u64 lo; } zig_i128; |
| 1168 | 1208 | |
| 1169 | 1209 | #define zig_as_u128(hi, lo) ((zig_u128){ .h##i = (hi), .l##o = (lo) }) |
| 1170 | 1210 | #define zig_as_i128(hi, lo) ((zig_i128){ .h##i = (hi), .l##o = (lo) }) |
| 1211 | #define zig_as_constant_u128(hi, lo) { .h##i = (hi), .l##o = (lo) } | |
| 1212 | #define zig_as_constant_i128(hi, lo) { .h##i = (hi), .l##o = (lo) } | |
| 1171 | 1213 | #define zig_hi_u128(val) ((val).hi) |
| 1172 | 1214 | #define zig_lo_u128(val) ((val).lo) |
| 1173 | 1215 | #define zig_hi_i128(val) ((val).hi) |
| ... | ... | @@ -1289,51 +1331,79 @@ static inline zig_i128 zig_not_i128(zig_i128 val, zig_u8 bits) { |
| 1289 | 1331 | } |
| 1290 | 1332 | |
| 1291 | 1333 | static inline zig_u128 zig_shr_u128(zig_u128 lhs, zig_u8 rhs) { |
| 1292 | if (rhs >= zig_as_u8(64)) return (zig_u128){ .hi = lhs.hi << (rhs - zig_as_u8(64)), .lo = zig_minInt_u64 }; | |
| 1293 | return (zig_u128){ .hi = lhs.hi << rhs | lhs.lo >> (zig_as_u8(64) - rhs), .lo = lhs.lo << rhs }; | |
| 1334 | if (rhs == zig_as_u8(0)) return lhs; | |
| 1335 | if (rhs >= zig_as_u8(64)) return (zig_u128){ .hi = zig_minInt_u64, .lo = lhs.hi >> (rhs - zig_as_u8(64)) }; | |
| 1336 | return (zig_u128){ .hi = lhs.hi >> rhs, .lo = lhs.hi << (zig_as_u8(64) - rhs) | lhs.lo >> rhs }; | |
| 1294 | 1337 | } |
| 1295 | 1338 | |
| 1296 | 1339 | static inline zig_u128 zig_shl_u128(zig_u128 lhs, zig_u8 rhs) { |
| 1297 | if (rhs >= zig_as_u8(64)) return (zig_u128){ .hi = lhs.hi << (rhs - zig_as_u8(64)), .lo = zig_minInt_u64 }; | |
| 1340 | if (rhs == zig_as_u8(0)) return lhs; | |
| 1341 | if (rhs >= zig_as_u8(64)) return (zig_u128){ .hi = lhs.lo << rhs, .lo = zig_minInt_u64 }; | |
| 1298 | 1342 | return (zig_u128){ .hi = lhs.hi << rhs | lhs.lo >> (zig_as_u8(64) - rhs), .lo = lhs.lo << rhs }; |
| 1299 | 1343 | } |
| 1300 | 1344 | |
| 1301 | 1345 | static inline zig_i128 zig_shl_i128(zig_i128 lhs, zig_u8 rhs) { |
| 1302 | if (rhs >= zig_as_u8(64)) return (zig_i128){ .hi = lhs.hi << (rhs - zig_as_u8(64)), .lo = zig_minInt_u64 }; | |
| 1346 | if (rhs == zig_as_u8(0)) return lhs; | |
| 1347 | if (rhs >= zig_as_u8(64)) return (zig_i128){ .hi = lhs.lo << rhs, .lo = zig_minInt_u64 }; | |
| 1303 | 1348 | return (zig_i128){ .hi = lhs.hi << rhs | lhs.lo >> (zig_as_u8(64) - rhs), .lo = lhs.lo << rhs }; |
| 1304 | 1349 | } |
| 1305 | 1350 | |
| 1306 | 1351 | static inline zig_u128 zig_add_u128(zig_u128 lhs, zig_u128 rhs) { |
| 1307 | 1352 | zig_u128 res; |
| 1308 | res.hi = lhs.hi + rhs.hi + zig_addo_u64(&res.lo, lhs.lo, rhs.lo, zig_maxInt_u64); | |
| 1353 | res.hi = lhs.hi + rhs.hi + zig_addo_u64(&res.lo, lhs.lo, rhs.lo, 64); | |
| 1309 | 1354 | return res; |
| 1310 | 1355 | } |
| 1311 | 1356 | |
| 1312 | 1357 | static inline zig_i128 zig_add_i128(zig_i128 lhs, zig_i128 rhs) { |
| 1313 | 1358 | zig_i128 res; |
| 1314 | res.hi = lhs.hi + rhs.hi + zig_addo_u64(&res.lo, lhs.lo, rhs.lo, zig_maxInt_u64); | |
| 1359 | res.hi = lhs.hi + rhs.hi + zig_addo_u64(&res.lo, lhs.lo, rhs.lo, 64); | |
| 1315 | 1360 | return res; |
| 1316 | 1361 | } |
| 1317 | 1362 | |
| 1318 | 1363 | static inline zig_u128 zig_sub_u128(zig_u128 lhs, zig_u128 rhs) { |
| 1319 | 1364 | zig_u128 res; |
| 1320 | res.hi = lhs.hi - rhs.hi - zig_subo_u64(&res.lo, lhs.lo, rhs.lo, zig_maxInt_u64); | |
| 1365 | res.hi = lhs.hi - rhs.hi - zig_subo_u64(&res.lo, lhs.lo, rhs.lo, 64); | |
| 1321 | 1366 | return res; |
| 1322 | 1367 | } |
| 1323 | 1368 | |
| 1324 | 1369 | static inline zig_i128 zig_sub_i128(zig_i128 lhs, zig_i128 rhs) { |
| 1325 | 1370 | zig_i128 res; |
| 1326 | res.hi = lhs.hi - rhs.hi - zig_subo_u64(&res.lo, lhs.lo, rhs.lo, zig_maxInt_u64); | |
| 1371 | res.hi = lhs.hi - rhs.hi - zig_subo_u64(&res.lo, lhs.lo, rhs.lo, 64); | |
| 1327 | 1372 | return res; |
| 1328 | 1373 | } |
| 1329 | 1374 | |
| 1330 | static inline zig_i128 zig_div_floor_i128(zig_i128 lhs, zig_i128 rhs) { | |
| 1331 | return zig_sub_i128(zig_div_trunc_i128(lhs, rhs), (((lhs.hi ^ rhs.hi) & zig_rem_i128(lhs, rhs).hi) < zig_as_i64(0)) ? zig_as_i128(0, 1) : zig_as_i128(0, 0)); | |
| 1375 | zig_extern zig_i128 __multi3(zig_i128 lhs, zig_i128 rhs); | |
| 1376 | static zig_i128 zig_mul_i128(zig_i128 lhs, zig_i128 rhs) { | |
| 1377 | return __multi3(lhs, rhs); | |
| 1378 | } | |
| 1379 | ||
| 1380 | zig_extern zig_u128 __udivti3(zig_u128 lhs, zig_u128 rhs); | |
| 1381 | static zig_u128 zig_div_trunc_u128(zig_u128 lhs, zig_u128 rhs) { | |
| 1382 | return __udivti3(lhs, rhs); | |
| 1383 | }; | |
| 1384 | ||
| 1385 | zig_extern zig_i128 __divti3(zig_i128 lhs, zig_i128 rhs); | |
| 1386 | static zig_i128 zig_div_trunc_i128(zig_i128 lhs, zig_i128 rhs) { | |
| 1387 | return __divti3(lhs, rhs); | |
| 1388 | }; | |
| 1389 | ||
| 1390 | zig_extern zig_u128 __umodti3(zig_u128 lhs, zig_u128 rhs); | |
| 1391 | static zig_u128 zig_rem_u128(zig_u128 lhs, zig_u128 rhs) { | |
| 1392 | return __umodti3(lhs, rhs); | |
| 1393 | } | |
| 1394 | ||
| 1395 | zig_extern zig_i128 __modti3(zig_i128 lhs, zig_i128 rhs); | |
| 1396 | static zig_i128 zig_rem_i128(zig_i128 lhs, zig_i128 rhs) { | |
| 1397 | return __modti3(lhs, rhs); | |
| 1332 | 1398 | } |
| 1333 | 1399 | |
| 1334 | 1400 | static inline zig_i128 zig_mod_i128(zig_i128 lhs, zig_i128 rhs) { |
| 1335 | 1401 | zig_i128 rem = zig_rem_i128(lhs, rhs); |
| 1336 | return rem + (((lhs.hi ^ rhs.hi) & rem.hi) < zig_as_i64(0) ? rhs : zig_as_i128(0, 0)); | |
| 1402 | return zig_add_i128(rem, (((lhs.hi ^ rhs.hi) & rem.hi) < zig_as_i64(0) ? rhs : zig_as_i128(0, 0))); | |
| 1403 | } | |
| 1404 | ||
| 1405 | static inline zig_i128 zig_div_floor_i128(zig_i128 lhs, zig_i128 rhs) { | |
| 1406 | return zig_sub_i128(zig_div_trunc_i128(lhs, rhs), zig_as_i128(0, zig_cmp_i128(zig_and_i128(zig_xor_i128(lhs, rhs), zig_rem_i128(lhs, rhs)), zig_as_i128(0, 0)) < zig_as_i32(0))); | |
| 1337 | 1407 | } |
| 1338 | 1408 | |
| 1339 | 1409 | #endif /* zig_has_int128 */ |
| ... | ... | @@ -1341,6 +1411,10 @@ static inline zig_i128 zig_mod_i128(zig_i128 lhs, zig_i128 rhs) { |
| 1341 | 1411 | #define zig_div_floor_u128 zig_div_trunc_u128 |
| 1342 | 1412 | #define zig_mod_u128 zig_rem_u128 |
| 1343 | 1413 | |
| 1414 | static inline zig_u128 zig_nand_u128(zig_u128 lhs, zig_u128 rhs) { | |
| 1415 | return zig_not_u128(zig_and_u128(lhs, rhs), 128); | |
| 1416 | } | |
| 1417 | ||
| 1344 | 1418 | static inline zig_u128 zig_min_u128(zig_u128 lhs, zig_u128 rhs) { |
| 1345 | 1419 | return zig_cmp_u128(lhs, rhs) < zig_as_i32(0) ? lhs : rhs; |
| 1346 | 1420 | } |
| ... | ... | @@ -1358,7 +1432,7 @@ static inline zig_i128 zig_max_i128(zig_i128 lhs, zig_i128 rhs) { |
| 1358 | 1432 | } |
| 1359 | 1433 | |
| 1360 | 1434 | static inline zig_i128 zig_shr_i128(zig_i128 lhs, zig_u8 rhs) { |
| 1361 | zig_i128 sign_mask = zig_cmp_i128(lhs, zig_as_i128(0, 0)) < zig_as_i32(0) ? -zig_as_i128(0, 1) : zig_as_i128(0, 0); | |
| 1435 | zig_i128 sign_mask = zig_cmp_i128(lhs, zig_as_i128(0, 0)) < zig_as_i32(0) ? zig_sub_i128(zig_as_i128(0, 0), zig_as_i128(0, 1)) : zig_as_i128(0, 0); | |
| 1362 | 1436 | return zig_xor_i128(zig_bitcast_i128(zig_shr_u128(zig_bitcast_u128(zig_xor_i128(lhs, sign_mask)), rhs)), sign_mask); |
| 1363 | 1437 | } |
| 1364 | 1438 | |
| ... | ... | @@ -1375,7 +1449,7 @@ static inline zig_u128 zig_shlw_u128(zig_u128 lhs, zig_u8 rhs, zig_u8 bits) { |
| 1375 | 1449 | } |
| 1376 | 1450 | |
| 1377 | 1451 | static inline zig_i128 zig_shlw_i128(zig_i128 lhs, zig_u8 rhs, zig_u8 bits) { |
| 1378 | return zig_wrap_i128(zig_bitcast_i128(zig_shl_u128(zig_bitcast_u128(lhs), zig_bitcast_u128(rhs))), bits); | |
| 1452 | return zig_wrap_i128(zig_bitcast_i128(zig_shl_u128(zig_bitcast_u128(lhs), rhs)), bits); | |
| 1379 | 1453 | } |
| 1380 | 1454 | |
| 1381 | 1455 | static inline zig_u128 zig_addw_u128(zig_u128 lhs, zig_u128 rhs, zig_u8 bits) { |
| ... | ... | @@ -1394,6 +1468,17 @@ static inline zig_i128 zig_subw_i128(zig_i128 lhs, zig_i128 rhs, zig_u8 bits) { |
| 1394 | 1468 | return zig_wrap_i128(zig_bitcast_i128(zig_sub_u128(zig_bitcast_u128(lhs), zig_bitcast_u128(rhs))), bits); |
| 1395 | 1469 | } |
| 1396 | 1470 | |
| 1471 | #if _MSC_VER | |
| 1472 | static zig_u128 zig_mul_u128(zig_u128 lhs, zig_u128 rhs) { | |
| 1473 | zig_u64 lo_carry; | |
| 1474 | zig_u64 lo = _umul128(lhs.lo, rhs.lo, &lo_carry); | |
| 1475 | zig_u64 hi = lhs.hi * rhs.lo + lhs.lo * rhs.hi + lo_carry; | |
| 1476 | return zig_as_u128(hi, lo); | |
| 1477 | } | |
| 1478 | #else | |
| 1479 | static zig_u128 zig_mul_u128(zig_u128 lhs, zig_u128 rhs); // TODO | |
| 1480 | #endif | |
| 1481 | ||
| 1397 | 1482 | static inline zig_u128 zig_mulw_u128(zig_u128 lhs, zig_u128 rhs, zig_u8 bits) { |
| 1398 | 1483 | return zig_wrap_u128(zig_mul_u128(lhs, rhs), bits); |
| 1399 | 1484 | } |
| ... | ... | @@ -1404,18 +1489,6 @@ static inline zig_i128 zig_mulw_i128(zig_i128 lhs, zig_i128 rhs, zig_u8 bits) { |
| 1404 | 1489 | |
| 1405 | 1490 | #if zig_has_int128 |
| 1406 | 1491 | |
| 1407 | static inline bool zig_shlo_u128(zig_u128 *res, zig_u128 lhs, zig_u8 rhs, zig_u8 bits) { | |
| 1408 | *res = zig_shlw_u128(lhs, rhs, bits); | |
| 1409 | return zig_cmp_u128(lhs, zig_shr_u128(zig_maxInt(u128, bits), rhs)) > zig_as_i32(0); | |
| 1410 | } | |
| 1411 | ||
| 1412 | static inline bool zig_shlo_i128(zig_i128 *res, zig_i128 lhs, zig_u8 rhs, zig_u8 bits) { | |
| 1413 | *res = zig_shlw_i128(lhs, rhs, bits); | |
| 1414 | zig_i128 mask = zig_bitcast_i128(zig_shl_u128(zig_maxInt_u128, bits - rhs - zig_as_u8(1))); | |
| 1415 | return zig_cmp_i128(zig_and_i128(lhs, mask), zig_as_i128(0, 0)) != zig_as_i32(0) && | |
| 1416 | zig_cmp_i128(zig_and_i128(lhs, mask), mask) != zig_as_i32(0); | |
| 1417 | } | |
| 1418 | ||
| 1419 | 1492 | static inline bool zig_addo_u128(zig_u128 *res, zig_u128 lhs, zig_u128 rhs, zig_u8 bits) { |
| 1420 | 1493 | #if zig_has_builtin(add_overflow) |
| 1421 | 1494 | zig_u128 full_res; |
| ... | ... | @@ -1496,28 +1569,95 @@ static inline bool zig_mulo_i128(zig_i128 *res, zig_i128 lhs, zig_i128 rhs, zig_ |
| 1496 | 1569 | |
| 1497 | 1570 | #else /* zig_has_int128 */ |
| 1498 | 1571 | |
| 1499 | static inline bool zig_addo_u128(zig_u128 *res, zig_u128 lhs, zig_u128 rhs) { | |
| 1500 | return zig_addo_u64(&res->hi, lhs.hi, rhs.hi, UINT64_MAX) | | |
| 1501 | zig_addo_u64(&res->hi, res->hi, zig_addo_u64(&res->lo, lhs.lo, rhs.lo, UINT64_MAX)); | |
| 1572 | static inline bool zig_overflow_u128(bool overflow, zig_u128 full_res, zig_u8 bits) { | |
| 1573 | return overflow || | |
| 1574 | zig_cmp_u128(full_res, zig_minInt(u128, bits)) < zig_as_i32(0) || | |
| 1575 | zig_cmp_u128(full_res, zig_maxInt(u128, bits)) > zig_as_i32(0); | |
| 1576 | } | |
| 1577 | ||
| 1578 | static inline bool zig_overflow_i128(bool overflow, zig_i128 full_res, zig_u8 bits) { | |
| 1579 | return overflow || | |
| 1580 | zig_cmp_i128(full_res, zig_minInt(i128, bits)) < zig_as_i32(0) || | |
| 1581 | zig_cmp_i128(full_res, zig_maxInt(i128, bits)) > zig_as_i32(0); | |
| 1582 | } | |
| 1583 | ||
| 1584 | static inline bool zig_addo_u128(zig_u128 *res, zig_u128 lhs, zig_u128 rhs, zig_u8 bits) { | |
| 1585 | zig_u128 full_res; | |
| 1586 | bool overflow = | |
| 1587 | zig_addo_u64(&full_res.hi, lhs.hi, rhs.hi, 64) | | |
| 1588 | zig_addo_u64(&full_res.hi, full_res.hi, zig_addo_u64(&full_res.lo, lhs.lo, rhs.lo, 64), 64); | |
| 1589 | *res = zig_wrap_u128(full_res, bits); | |
| 1590 | return zig_overflow_u128(overflow, full_res, bits); | |
| 1591 | } | |
| 1592 | ||
| 1593 | zig_extern zig_i128 __addoti4(zig_i128 lhs, zig_i128 rhs, zig_c_int *overflow); | |
| 1594 | static inline bool zig_addo_i128(zig_i128 *res, zig_i128 lhs, zig_i128 rhs, zig_u8 bits) { | |
| 1595 | zig_c_int overflow_int; | |
| 1596 | zig_i128 full_res = __addoti4(lhs, rhs, &overflow_int); | |
| 1597 | *res = zig_wrap_i128(full_res, bits); | |
| 1598 | return zig_overflow_i128(overflow_int, full_res, bits); | |
| 1599 | } | |
| 1600 | ||
| 1601 | static inline bool zig_subo_u128(zig_u128 *res, zig_u128 lhs, zig_u128 rhs, zig_u8 bits) { | |
| 1602 | zig_u128 full_res; | |
| 1603 | bool overflow = | |
| 1604 | zig_subo_u64(&full_res.hi, lhs.hi, rhs.hi, 64) | | |
| 1605 | zig_subo_u64(&full_res.hi, full_res.hi, zig_subo_u64(&full_res.lo, lhs.lo, rhs.lo, 64), 64); | |
| 1606 | *res = zig_wrap_u128(full_res, bits); | |
| 1607 | return zig_overflow_u128(overflow, full_res, bits); | |
| 1608 | } | |
| 1609 | ||
| 1610 | zig_extern zig_i128 __suboti4(zig_i128 lhs, zig_i128 rhs, zig_c_int *overflow); | |
| 1611 | static inline bool zig_subo_i128(zig_i128 *res, zig_i128 lhs, zig_i128 rhs, zig_u8 bits) { | |
| 1612 | zig_c_int overflow_int; | |
| 1613 | zig_i128 full_res = __suboti4(lhs, rhs, &overflow_int); | |
| 1614 | *res = zig_wrap_i128(full_res, bits); | |
| 1615 | return zig_overflow_i128(overflow_int, full_res, bits); | |
| 1616 | } | |
| 1617 | ||
| 1618 | static inline bool zig_mulo_u128(zig_u128 *res, zig_u128 lhs, zig_u128 rhs, zig_u8 bits) { | |
| 1619 | *res = zig_mulw_u128(lhs, rhs, bits); | |
| 1620 | return zig_cmp_u128(*res, zig_as_u128(0, 0)) != zig_as_i32(0) && | |
| 1621 | zig_cmp_u128(lhs, zig_div_trunc_u128(zig_maxInt(u128, bits), rhs)) > zig_as_i32(0); | |
| 1502 | 1622 | } |
| 1503 | 1623 | |
| 1504 | static inline bool zig_subo_u128(zig_u128 *res, zig_u128 lhs, zig_u128 rhs) { | |
| 1505 | return zig_subo_u64(&res->hi, lhs.hi, rhs.hi, UINT64_MAX) | | |
| 1506 | zig_subo_u64(&res->hi, res->hi, zig_subo_u64(&res->lo, lhs.lo, rhs.lo, UINT64_MAX)); | |
| 1624 | zig_extern zig_i128 __muloti4(zig_i128 lhs, zig_i128 rhs, zig_c_int *overflow); | |
| 1625 | static inline bool zig_mulo_i128(zig_i128 *res, zig_i128 lhs, zig_i128 rhs, zig_u8 bits) { | |
| 1626 | zig_c_int overflow_int; | |
| 1627 | zig_i128 full_res = __muloti4(lhs, rhs, &overflow_int); | |
| 1628 | *res = zig_wrap_i128(full_res, bits); | |
| 1629 | return zig_overflow_i128(overflow_int, full_res, bits); | |
| 1507 | 1630 | } |
| 1508 | 1631 | |
| 1509 | 1632 | #endif /* zig_has_int128 */ |
| 1510 | 1633 | |
| 1634 | static inline bool zig_shlo_u128(zig_u128 *res, zig_u128 lhs, zig_u8 rhs, zig_u8 bits) { | |
| 1635 | *res = zig_shlw_u128(lhs, rhs, bits); | |
| 1636 | return zig_cmp_u128(lhs, zig_shr_u128(zig_maxInt(u128, bits), rhs)) > zig_as_i32(0); | |
| 1637 | } | |
| 1638 | ||
| 1639 | static inline bool zig_shlo_i128(zig_i128 *res, zig_i128 lhs, zig_u8 rhs, zig_u8 bits) { | |
| 1640 | *res = zig_shlw_i128(lhs, rhs, bits); | |
| 1641 | zig_i128 mask = zig_bitcast_i128(zig_shl_u128(zig_maxInt_u128, bits - rhs - zig_as_u8(1))); | |
| 1642 | return zig_cmp_i128(zig_and_i128(lhs, mask), zig_as_i128(0, 0)) != zig_as_i32(0) && | |
| 1643 | zig_cmp_i128(zig_and_i128(lhs, mask), mask) != zig_as_i32(0); | |
| 1644 | } | |
| 1645 | ||
| 1511 | 1646 | static inline zig_u128 zig_shls_u128(zig_u128 lhs, zig_u128 rhs, zig_u8 bits) { |
| 1512 | 1647 | zig_u128 res; |
| 1513 | 1648 | if (zig_cmp_u128(rhs, zig_as_u128(0, bits)) >= zig_as_i32(0)) |
| 1514 | 1649 | return zig_cmp_u128(lhs, zig_as_u128(0, 0)) != zig_as_i32(0) ? zig_maxInt(u128, bits) : lhs; |
| 1650 | ||
| 1651 | #if zig_has_int128 | |
| 1515 | 1652 | return zig_shlo_u128(&res, lhs, (zig_u8)rhs, bits) ? zig_maxInt(u128, bits) : res; |
| 1653 | #else | |
| 1654 | return zig_shlo_u128(&res, lhs, (zig_u8)rhs.lo, bits) ? zig_maxInt(u128, bits) : res; | |
| 1655 | #endif | |
| 1516 | 1656 | } |
| 1517 | 1657 | |
| 1518 | 1658 | static inline zig_i128 zig_shls_i128(zig_i128 lhs, zig_i128 rhs, zig_u8 bits) { |
| 1519 | 1659 | zig_i128 res; |
| 1520 | if (zig_cmp_u128(zig_bitcast_u128(rhs), zig_as_u128(0, bits)) < zig_as_i32(0) && !zig_shlo_i128(&res, lhs, rhs, bits)) return res; | |
| 1660 | if (zig_cmp_u128(zig_bitcast_u128(rhs), zig_as_u128(0, bits)) < zig_as_i32(0) && !zig_shlo_i128(&res, lhs, zig_lo_i128(rhs), bits)) return res; | |
| 1521 | 1661 | return zig_cmp_i128(lhs, zig_as_i128(0, 0)) < zig_as_i32(0) ? zig_minInt(i128, bits) : zig_maxInt(i128, bits); |
| 1522 | 1662 | } |
| 1523 | 1663 | |
| ... | ... | @@ -1555,8 +1695,9 @@ static inline zig_i128 zig_muls_i128(zig_i128 lhs, zig_i128 rhs, zig_u8 bits) { |
| 1555 | 1695 | } |
| 1556 | 1696 | |
| 1557 | 1697 | static inline zig_u8 zig_clz_u128(zig_u128 val, zig_u8 bits) { |
| 1698 | if (bits <= zig_as_u8(64)) return zig_clz_u64(zig_lo_u128(val), bits); | |
| 1558 | 1699 | if (zig_hi_u128(val) != 0) return zig_clz_u64(zig_hi_u128(val), bits - zig_as_u8(64)); |
| 1559 | return zig_clz_u64(zig_lo_u128(val), zig_as_u8(64)) + zig_as_u8(64); | |
| 1700 | return zig_clz_u64(zig_lo_u128(val), zig_as_u8(64)) + (bits - zig_as_u8(64)); | |
| 1560 | 1701 | } |
| 1561 | 1702 | |
| 1562 | 1703 | static inline zig_u8 zig_clz_i128(zig_i128 val, zig_u8 bits) { |
| ... | ... | @@ -1593,7 +1734,7 @@ static inline zig_u128 zig_byte_swap_u128(zig_u128 val, zig_u8 bits) { |
| 1593 | 1734 | } |
| 1594 | 1735 | |
| 1595 | 1736 | static inline zig_i128 zig_byte_swap_i128(zig_i128 val, zig_u8 bits) { |
| 1596 | return zig_byte_swap_u128(zig_bitcast_u128(val), bits); | |
| 1737 | return zig_bitcast_i128(zig_byte_swap_u128(zig_bitcast_u128(val), bits)); | |
| 1597 | 1738 | } |
| 1598 | 1739 | |
| 1599 | 1740 | static inline zig_u128 zig_bit_reverse_u128(zig_u128 val, zig_u8 bits) { |
| ... | ... | @@ -1603,15 +1744,47 @@ static inline zig_u128 zig_bit_reverse_u128(zig_u128 val, zig_u8 bits) { |
| 1603 | 1744 | } |
| 1604 | 1745 | |
| 1605 | 1746 | static inline zig_i128 zig_bit_reverse_i128(zig_i128 val, zig_u8 bits) { |
| 1606 | return zig_bit_reverse_u128(zig_bitcast_u128(val), bits); | |
| 1747 | return zig_bitcast_i128(zig_bit_reverse_u128(zig_bitcast_u128(val), bits)); | |
| 1607 | 1748 | } |
| 1608 | 1749 | |
| 1609 | 1750 | /* ========================= Floating Point Support ========================= */ |
| 1610 | 1751 | |
| 1752 | #if _MSC_VER | |
| 1753 | #define zig_msvc_flt_inf ((double)(1e+300 * 1e+300)) | |
| 1754 | #define zig_msvc_flt_inff ((float)(1e+300 * 1e+300)) | |
| 1755 | #define zig_msvc_flt_infl ((long double)(1e+300 * 1e+300)) | |
| 1756 | #define zig_msvc_flt_nan ((double)(zig_msvc_flt_inf * 0.f)) | |
| 1757 | #define zig_msvc_flt_nanf ((float)(zig_msvc_flt_inf * 0.f)) | |
| 1758 | #define zig_msvc_flt_nanl ((long double)(zig_msvc_flt_inf * 0.f)) | |
| 1759 | #define __builtin_nan(str) nan(str) | |
| 1760 | #define __builtin_nanf(str) nanf(str) | |
| 1761 | #define __builtin_nanl(str) nanl(str) | |
| 1762 | #define __builtin_inf() zig_msvc_flt_inf | |
| 1763 | #define __builtin_inff() zig_msvc_flt_inff | |
| 1764 | #define __builtin_infl() zig_msvc_flt_infl | |
| 1765 | #endif | |
| 1766 | ||
| 1767 | #define zig_has_float_builtins (zig_has_builtin(nan) && zig_has_builtin(nans) && zig_has_builtin(inf)) | |
| 1768 | #if zig_has_float_builtins | |
| 1769 | #define zig_as_special_f16(sign, name, arg, repr) sign zig_as_f16(__builtin_##name, )(arg) | |
| 1770 | #define zig_as_special_f32(sign, name, arg, repr) sign zig_as_f32(__builtin_##name, )(arg) | |
| 1771 | #define zig_as_special_f64(sign, name, arg, repr) sign zig_as_f64(__builtin_##name, )(arg) | |
| 1772 | #define zig_as_special_f80(sign, name, arg, repr) sign zig_as_f80(__builtin_##name, )(arg) | |
| 1773 | #define zig_as_special_f128(sign, name, arg, repr) sign zig_as_f128(__builtin_##name, )(arg) | |
| 1774 | #define zig_as_special_c_longdouble(sign, name, arg, repr) sign zig_as_c_longdouble(__builtin_##name, )(arg) | |
| 1775 | #else | |
| 1776 | #define zig_as_special_f16(sign, name, arg, repr) zig_float_from_repr_f16(repr) | |
| 1777 | #define zig_as_special_f32(sign, name, arg, repr) zig_float_from_repr_f32(repr) | |
| 1778 | #define zig_as_special_f64(sign, name, arg, repr) zig_float_from_repr_f64(repr) | |
| 1779 | #define zig_as_special_f80(sign, name, arg, repr) zig_float_from_repr_f80(repr) | |
| 1780 | #define zig_as_special_f128(sign, name, arg, repr) zig_float_from_repr_f128(repr) | |
| 1781 | #define zig_as_special_c_longdouble(sign, name, arg, repr) zig_float_from_repr_c_longdouble(repr) | |
| 1782 | #endif | |
| 1783 | ||
| 1611 | 1784 | #define zig_has_f16 1 |
| 1612 | 1785 | #define zig_bitSizeOf_f16 16 |
| 1613 | 1786 | #define zig_libc_name_f16(name) __##name##h |
| 1614 | #define zig_as_special_f16(sign, name, arg, repr) sign zig_as_f16(__builtin_##name, )(arg) | |
| 1787 | #define zig_as_special_constant_f16(sign, name, arg, repr) zig_as_special_f16(sign, name, arg, repr) | |
| 1615 | 1788 | #if FLT_MANT_DIG == 11 |
| 1616 | 1789 | typedef float zig_f16; |
| 1617 | 1790 | #define zig_as_f16(fp, repr) fp##f |
| ... | ... | @@ -1636,12 +1809,18 @@ typedef zig_i16 zig_f16; |
| 1636 | 1809 | #define zig_as_f16(fp, repr) repr |
| 1637 | 1810 | #undef zig_as_special_f16 |
| 1638 | 1811 | #define zig_as_special_f16(sign, name, arg, repr) repr |
| 1812 | #undef zig_as_special_constant_f16 | |
| 1813 | #define zig_as_special_constant_f16(sign, name, arg, repr) repr | |
| 1639 | 1814 | #endif |
| 1640 | 1815 | |
| 1641 | 1816 | #define zig_has_f32 1 |
| 1642 | 1817 | #define zig_bitSizeOf_f32 32 |
| 1643 | 1818 | #define zig_libc_name_f32(name) name##f |
| 1644 | #define zig_as_special_f32(sign, name, arg, repr) sign zig_as_f32(__builtin_##name, )(arg) | |
| 1819 | #if _MSC_VER | |
| 1820 | #define zig_as_special_constant_f32(sign, name, arg, repr) sign zig_as_f32(zig_msvc_flt_##name, ) | |
| 1821 | #else | |
| 1822 | #define zig_as_special_constant_f32(sign, name, arg, repr) zig_as_special_f32(sign, name, arg, repr) | |
| 1823 | #endif | |
| 1645 | 1824 | #if FLT_MANT_DIG == 24 |
| 1646 | 1825 | typedef float zig_f32; |
| 1647 | 1826 | #define zig_as_f32(fp, repr) fp##f |
| ... | ... | @@ -1663,12 +1842,18 @@ typedef zig_i32 zig_f32; |
| 1663 | 1842 | #define zig_as_f32(fp, repr) repr |
| 1664 | 1843 | #undef zig_as_special_f32 |
| 1665 | 1844 | #define zig_as_special_f32(sign, name, arg, repr) repr |
| 1845 | #undef zig_as_special_constant_f32 | |
| 1846 | #define zig_as_special_constant_f32(sign, name, arg, repr) repr | |
| 1666 | 1847 | #endif |
| 1667 | 1848 | |
| 1668 | 1849 | #define zig_has_f64 1 |
| 1669 | 1850 | #define zig_bitSizeOf_f64 64 |
| 1670 | 1851 | #define zig_libc_name_f64(name) name |
| 1671 | #define zig_as_special_f64(sign, name, arg, repr) sign zig_as_f64(__builtin_##name, )(arg) | |
| 1852 | #if _MSC_VER | |
| 1853 | #define zig_as_special_constant_f64(sign, name, arg, repr) sign zig_as_f64(zig_msvc_flt_##name, ) | |
| 1854 | #else | |
| 1855 | #define zig_as_special_constant_f64(sign, name, arg, repr) zig_as_special_f64(sign, name, arg, repr) | |
| 1856 | #endif | |
| 1672 | 1857 | #if FLT_MANT_DIG == 53 |
| 1673 | 1858 | typedef float zig_f64; |
| 1674 | 1859 | #define zig_as_f64(fp, repr) fp##f |
| ... | ... | @@ -1693,12 +1878,14 @@ typedef zig_i64 zig_f64; |
| 1693 | 1878 | #define zig_as_f64(fp, repr) repr |
| 1694 | 1879 | #undef zig_as_special_f64 |
| 1695 | 1880 | #define zig_as_special_f64(sign, name, arg, repr) repr |
| 1881 | #undef zig_as_special_constant_f64 | |
| 1882 | #define zig_as_special_constant_f64(sign, name, arg, repr) repr | |
| 1696 | 1883 | #endif |
| 1697 | 1884 | |
| 1698 | 1885 | #define zig_has_f80 1 |
| 1699 | 1886 | #define zig_bitSizeOf_f80 80 |
| 1700 | 1887 | #define zig_libc_name_f80(name) __##name##x |
| 1701 | #define zig_as_special_f80(sign, name, arg, repr) sign zig_as_f80(__builtin_##name, )(arg) | |
| 1888 | #define zig_as_special_constant_f80(sign, name, arg, repr) zig_as_special_f80(sign, name, arg, repr) | |
| 1702 | 1889 | #if FLT_MANT_DIG == 64 |
| 1703 | 1890 | typedef float zig_f80; |
| 1704 | 1891 | #define zig_as_f80(fp, repr) fp##f |
| ... | ... | @@ -1726,12 +1913,14 @@ typedef zig_i128 zig_f80; |
| 1726 | 1913 | #define zig_as_f80(fp, repr) repr |
| 1727 | 1914 | #undef zig_as_special_f80 |
| 1728 | 1915 | #define zig_as_special_f80(sign, name, arg, repr) repr |
| 1916 | #undef zig_as_special_constant_f80 | |
| 1917 | #define zig_as_special_constant_f80(sign, name, arg, repr) repr | |
| 1729 | 1918 | #endif |
| 1730 | 1919 | |
| 1731 | 1920 | #define zig_has_f128 1 |
| 1732 | 1921 | #define zig_bitSizeOf_f128 128 |
| 1733 | 1922 | #define zig_libc_name_f128(name) name##q |
| 1734 | #define zig_as_special_f128(sign, name, arg, repr) sign zig_as_f128(__builtin_##name, )(arg) | |
| 1923 | #define zig_as_special_constant_f128(sign, name, arg, repr) zig_as_special_f128(sign, name, arg, repr) | |
| 1735 | 1924 | #if FLT_MANT_DIG == 113 |
| 1736 | 1925 | typedef float zig_f128; |
| 1737 | 1926 | #define zig_as_f128(fp, repr) fp##f |
| ... | ... | @@ -1761,13 +1950,57 @@ typedef zig_i128 zig_f128; |
| 1761 | 1950 | #define zig_as_f128(fp, repr) repr |
| 1762 | 1951 | #undef zig_as_special_f128 |
| 1763 | 1952 | #define zig_as_special_f128(sign, name, arg, repr) repr |
| 1953 | #undef zig_as_special_constant_f128 | |
| 1954 | #define zig_as_special_constant_f128(sign, name, arg, repr) repr | |
| 1764 | 1955 | #endif |
| 1765 | 1956 | |
| 1766 | 1957 | #define zig_has_c_longdouble 1 |
| 1958 | #define zig_libc_name_c_longdouble(name) name##l | |
| 1959 | #define zig_as_special_constant_c_longdouble(sign, name, arg, repr) zig_as_special_c_longdouble(sign, name, arg, repr) | |
| 1960 | #ifdef zig_bitSizeOf_c_longdouble | |
| 1767 | 1961 | typedef long double zig_c_longdouble; |
| 1768 | 1962 | #define zig_as_c_longdouble(fp, repr) fp##l |
| 1769 | #define zig_libc_name_c_longdouble(name) name##l | |
| 1770 | #define zig_as_special_c_longdouble(sign, name, arg, repr) sign __builtin_##name##l(arg) | |
| 1963 | #else | |
| 1964 | #undef zig_has_c_longdouble | |
| 1965 | #define zig_bitSizeOf_c_longdouble 80 | |
| 1966 | #define zig_compiler_rt_abbrev_c_longdouble zig_compiler_rt_abbrev_f80 | |
| 1967 | #define zig_has_c_longdouble 0 | |
| 1968 | #define zig_repr_c_longdouble i128 | |
| 1969 | typedef zig_i128 zig_c_longdouble; | |
| 1970 | #define zig_as_c_longdouble(fp, repr) repr | |
| 1971 | #undef zig_as_special_c_longdouble | |
| 1972 | #define zig_as_special_c_longdouble(sign, name, arg, repr) repr | |
| 1973 | #undef zig_as_special_constant_c_longdouble | |
| 1974 | #define zig_as_special_constant_c_longdouble(sign, name, arg, repr) repr | |
| 1975 | #endif | |
| 1976 | ||
| 1977 | #if !zig_has_float_builtins | |
| 1978 | #define zig_float_from_repr(Type, ReprType) \ | |
| 1979 | static inline zig_##Type zig_float_from_repr_##Type(zig_##ReprType repr) { \ | |
| 1980 | return *((zig_##Type*)&repr); \ | |
| 1981 | } | |
| 1982 | ||
| 1983 | zig_float_from_repr(f16, u16) | |
| 1984 | zig_float_from_repr(f32, u32) | |
| 1985 | zig_float_from_repr(f64, u64) | |
| 1986 | zig_float_from_repr(f80, u128) | |
| 1987 | zig_float_from_repr(f128, u128) | |
| 1988 | zig_float_from_repr(c_longdouble, u128) | |
| 1989 | #endif | |
| 1990 | ||
| 1991 | #define zig_cast_f16 (zig_f16) | |
| 1992 | #define zig_cast_f32 (zig_f32) | |
| 1993 | #define zig_cast_f64 (zig_f64) | |
| 1994 | ||
| 1995 | #if _MSC_VER && !zig_has_f128 | |
| 1996 | #define zig_cast_f80 | |
| 1997 | #define zig_cast_c_longdouble | |
| 1998 | #define zig_cast_f128 | |
| 1999 | #else | |
| 2000 | #define zig_cast_f80 (zig_f80) | |
| 2001 | #define zig_cast_c_longdouble (zig_c_longdouble) | |
| 2002 | #define zig_cast_f128 (zig_f128) | |
| 2003 | #endif | |
| 1771 | 2004 | |
| 1772 | 2005 | #define zig_convert_builtin(ResType, operation, ArgType, version) \ |
| 1773 | 2006 | zig_extern zig_##ResType zig_expand_concat(zig_expand_concat(zig_expand_concat(__##operation, \ |
| ... | ... | @@ -1892,3 +2125,268 @@ zig_float_builtins(f64) |
| 1892 | 2125 | zig_float_builtins(f80) |
| 1893 | 2126 | zig_float_builtins(f128) |
| 1894 | 2127 | zig_float_builtins(c_longdouble) |
| 2128 | ||
| 2129 | #if _MSC_VER && (_M_IX86 || _M_X64) | |
| 2130 | ||
| 2131 | // TODO: zig_msvc_atomic_load should load 32 bit without interlocked on x86, and load 64 bit without interlocked on x64 | |
| 2132 | ||
| 2133 | #define zig_msvc_atomics(Type, suffix) \ | |
| 2134 | static inline bool zig_msvc_cmpxchg_##Type(zig_##Type volatile* obj, zig_##Type* expected, zig_##Type desired) { \ | |
| 2135 | zig_##Type comparand = *expected; \ | |
| 2136 | zig_##Type initial = _InterlockedCompareExchange##suffix(obj, desired, comparand); \ | |
| 2137 | bool exchanged = initial == comparand; \ | |
| 2138 | if (!exchanged) { \ | |
| 2139 | *expected = initial; \ | |
| 2140 | } \ | |
| 2141 | return exchanged; \ | |
| 2142 | } \ | |
| 2143 | static inline zig_##Type zig_msvc_atomicrmw_xchg_##Type(zig_##Type volatile* obj, zig_##Type value) { \ | |
| 2144 | return _InterlockedExchange##suffix(obj, value); \ | |
| 2145 | } \ | |
| 2146 | static inline zig_##Type zig_msvc_atomicrmw_add_##Type(zig_##Type volatile* obj, zig_##Type value) { \ | |
| 2147 | return _InterlockedExchangeAdd##suffix(obj, value); \ | |
| 2148 | } \ | |
| 2149 | static inline zig_##Type zig_msvc_atomicrmw_sub_##Type(zig_##Type volatile* obj, zig_##Type value) { \ | |
| 2150 | bool success = false; \ | |
| 2151 | zig_##Type new; \ | |
| 2152 | zig_##Type prev; \ | |
| 2153 | while (!success) { \ | |
| 2154 | prev = *obj; \ | |
| 2155 | new = prev - value; \ | |
| 2156 | success = zig_msvc_cmpxchg_##Type(obj, &prev, new); \ | |
| 2157 | } \ | |
| 2158 | return prev; \ | |
| 2159 | } \ | |
| 2160 | static inline zig_##Type zig_msvc_atomicrmw_or_##Type(zig_##Type volatile* obj, zig_##Type value) { \ | |
| 2161 | return _InterlockedOr##suffix(obj, value); \ | |
| 2162 | } \ | |
| 2163 | static inline zig_##Type zig_msvc_atomicrmw_xor_##Type(zig_##Type volatile* obj, zig_##Type value) { \ | |
| 2164 | return _InterlockedXor##suffix(obj, value); \ | |
| 2165 | } \ | |
| 2166 | static inline zig_##Type zig_msvc_atomicrmw_and_##Type(zig_##Type volatile* obj, zig_##Type value) { \ | |
| 2167 | return _InterlockedAnd##suffix(obj, value); \ | |
| 2168 | } \ | |
| 2169 | static inline zig_##Type zig_msvc_atomicrmw_nand_##Type(zig_##Type volatile* obj, zig_##Type value) { \ | |
| 2170 | bool success = false; \ | |
| 2171 | zig_##Type new; \ | |
| 2172 | zig_##Type prev; \ | |
| 2173 | while (!success) { \ | |
| 2174 | prev = *obj; \ | |
| 2175 | new = ~(prev & value); \ | |
| 2176 | success = zig_msvc_cmpxchg_##Type(obj, &prev, new); \ | |
| 2177 | } \ | |
| 2178 | return prev; \ | |
| 2179 | } \ | |
| 2180 | static inline zig_##Type zig_msvc_atomicrmw_min_##Type(zig_##Type volatile* obj, zig_##Type value) { \ | |
| 2181 | bool success = false; \ | |
| 2182 | zig_##Type new; \ | |
| 2183 | zig_##Type prev; \ | |
| 2184 | while (!success) { \ | |
| 2185 | prev = *obj; \ | |
| 2186 | new = value < prev ? value : prev; \ | |
| 2187 | success = zig_msvc_cmpxchg_##Type(obj, &prev, new); \ | |
| 2188 | } \ | |
| 2189 | return prev; \ | |
| 2190 | } \ | |
| 2191 | static inline zig_##Type zig_msvc_atomicrmw_max_##Type(zig_##Type volatile* obj, zig_##Type value) { \ | |
| 2192 | bool success = false; \ | |
| 2193 | zig_##Type new; \ | |
| 2194 | zig_##Type prev; \ | |
| 2195 | while (!success) { \ | |
| 2196 | prev = *obj; \ | |
| 2197 | new = value > prev ? value : prev; \ | |
| 2198 | success = zig_msvc_cmpxchg_##Type(obj, &prev, new); \ | |
| 2199 | } \ | |
| 2200 | return prev; \ | |
| 2201 | } \ | |
| 2202 | static inline void zig_msvc_atomic_store_##Type(zig_##Type volatile* obj, zig_##Type value) { \ | |
| 2203 | _InterlockedExchange##suffix(obj, value); \ | |
| 2204 | } \ | |
| 2205 | static inline zig_##Type zig_msvc_atomic_load_##Type(zig_##Type volatile* obj) { \ | |
| 2206 | return _InterlockedOr##suffix(obj, 0); \ | |
| 2207 | } | |
| 2208 | ||
| 2209 | zig_msvc_atomics(u8, 8) | |
| 2210 | zig_msvc_atomics(i8, 8) | |
| 2211 | zig_msvc_atomics(u16, 16) | |
| 2212 | zig_msvc_atomics(i16, 16) | |
| 2213 | zig_msvc_atomics(u32, ) | |
| 2214 | zig_msvc_atomics(i32, ) | |
| 2215 | zig_msvc_atomics(u64, 64) | |
| 2216 | zig_msvc_atomics(i64, 64) | |
| 2217 | ||
| 2218 | #define zig_msvc_flt_atomics(Type, ReprType, suffix) \ | |
| 2219 | static inline bool zig_msvc_cmpxchg_##Type(zig_##Type volatile* obj, zig_##Type* expected, zig_##Type desired) { \ | |
| 2220 | zig_##ReprType comparand = *((zig_##ReprType*)expected); \ | |
| 2221 | zig_##ReprType initial = _InterlockedCompareExchange##suffix((zig_##ReprType volatile*)obj, *((zig_##ReprType*)&desired), comparand); \ | |
| 2222 | bool exchanged = initial == comparand; \ | |
| 2223 | if (!exchanged) { \ | |
| 2224 | *expected = *((zig_##Type*)&initial); \ | |
| 2225 | } \ | |
| 2226 | return exchanged; \ | |
| 2227 | } \ | |
| 2228 | static inline zig_##Type zig_msvc_atomicrmw_xchg_##Type(zig_##Type volatile* obj, zig_##Type value) { \ | |
| 2229 | zig_##ReprType initial = _InterlockedExchange##suffix((zig_##ReprType volatile*)obj, *((zig_##ReprType*)&value)); \ | |
| 2230 | return *((zig_##Type*)&initial); \ | |
| 2231 | } \ | |
| 2232 | static inline zig_##Type zig_msvc_atomicrmw_add_##Type(zig_##Type volatile* obj, zig_##Type value) { \ | |
| 2233 | bool success = false; \ | |
| 2234 | zig_##ReprType new; \ | |
| 2235 | zig_##Type prev; \ | |
| 2236 | while (!success) { \ | |
| 2237 | prev = *obj; \ | |
| 2238 | new = prev + value; \ | |
| 2239 | success = zig_msvc_cmpxchg_##Type(obj, &prev, *((zig_##ReprType*)&new)); \ | |
| 2240 | } \ | |
| 2241 | return prev; \ | |
| 2242 | } \ | |
| 2243 | static inline zig_##Type zig_msvc_atomicrmw_sub_##Type(zig_##Type volatile* obj, zig_##Type value) { \ | |
| 2244 | bool success = false; \ | |
| 2245 | zig_##ReprType new; \ | |
| 2246 | zig_##Type prev; \ | |
| 2247 | while (!success) { \ | |
| 2248 | prev = *obj; \ | |
| 2249 | new = prev - value; \ | |
| 2250 | success = zig_msvc_cmpxchg_##Type(obj, &prev, *((zig_##ReprType*)&new)); \ | |
| 2251 | } \ | |
| 2252 | return prev; \ | |
| 2253 | } | |
| 2254 | ||
| 2255 | zig_msvc_flt_atomics(f32, u32, ) | |
| 2256 | zig_msvc_flt_atomics(f64, u64, 64) | |
| 2257 | ||
| 2258 | #if _M_IX86 | |
| 2259 | static inline void* zig_msvc_atomicrmw_xchg_p32(void** obj, zig_u32* arg) { | |
| 2260 | return _InterlockedExchangePointer(obj, arg); | |
| 2261 | } | |
| 2262 | ||
| 2263 | static inline void zig_msvc_atomic_store_p32(void** obj, zig_u32* arg) { | |
| 2264 | _InterlockedExchangePointer(obj, arg); | |
| 2265 | } | |
| 2266 | ||
| 2267 | static inline void* zig_msvc_atomic_load_p32(void** obj, zig_u32* arg) { | |
| 2268 | return (void*)_InterlockedOr((void*)obj, 0); | |
| 2269 | } | |
| 2270 | ||
| 2271 | static inline bool zig_msvc_cmpxchg_p32(void** obj, void** expected, void* desired) { | |
| 2272 | void* comparand = *expected; | |
| 2273 | void* initial = _InterlockedCompareExchangePointer(obj, desired, comparand); | |
| 2274 | bool exchanged = initial == comparand; | |
| 2275 | if (!exchanged) { | |
| 2276 | *expected = initial; | |
| 2277 | } | |
| 2278 | return exchanged; | |
| 2279 | } | |
| 2280 | #else | |
| 2281 | static inline void* zig_msvc_atomicrmw_xchg_p64(void** obj, zig_u64* arg) { | |
| 2282 | return _InterlockedExchangePointer(obj, arg); | |
| 2283 | } | |
| 2284 | ||
| 2285 | static inline void zig_msvc_atomic_store_p64(void** obj, zig_u64* arg) { | |
| 2286 | _InterlockedExchangePointer(obj, arg); | |
| 2287 | } | |
| 2288 | ||
| 2289 | static inline void* zig_msvc_atomic_load_p64(void** obj) { | |
| 2290 | return (void*)_InterlockedOr64((void*)obj, 0); | |
| 2291 | } | |
| 2292 | ||
| 2293 | static inline bool zig_msvc_cmpxchg_p64(void** obj, void** expected, void* desired) { | |
| 2294 | void* comparand = *expected; | |
| 2295 | void* initial = _InterlockedCompareExchangePointer(obj, desired, comparand); | |
| 2296 | bool exchanged = initial == comparand; | |
| 2297 | if (!exchanged) { | |
| 2298 | *expected = initial; | |
| 2299 | } | |
| 2300 | return exchanged; | |
| 2301 | } | |
| 2302 | #endif | |
| 2303 | ||
| 2304 | static inline bool zig_msvc_cmpxchg_u128(zig_u128 volatile* obj, zig_u128* expected, zig_u128 desired) { | |
| 2305 | return _InterlockedCompareExchange128((zig_i64 volatile*)obj, desired.hi, desired.lo, (zig_i64*)expected); | |
| 2306 | } | |
| 2307 | ||
| 2308 | static inline bool zig_msvc_cmpxchg_i128(zig_i128 volatile* obj, zig_i128* expected, zig_i128 desired) { | |
| 2309 | return _InterlockedCompareExchange128((zig_i64 volatile*)obj, desired.hi, desired.lo, (zig_u64*)expected); | |
| 2310 | } | |
| 2311 | ||
| 2312 | #define zig_msvc_atomics_128xchg(Type) \ | |
| 2313 | static inline zig_##Type zig_msvc_atomicrmw_xchg_##Type(zig_##Type volatile* obj, zig_##Type value) { \ | |
| 2314 | bool success = false; \ | |
| 2315 | zig_##Type prev; \ | |
| 2316 | while (!success) { \ | |
| 2317 | prev = *obj; \ | |
| 2318 | success = zig_msvc_cmpxchg_##Type(obj, &prev, value); \ | |
| 2319 | } \ | |
| 2320 | return prev; \ | |
| 2321 | } | |
| 2322 | ||
| 2323 | zig_msvc_atomics_128xchg(u128) | |
| 2324 | zig_msvc_atomics_128xchg(i128) | |
| 2325 | ||
| 2326 | #define zig_msvc_atomics_128op(Type, operation) \ | |
| 2327 | static inline zig_##Type zig_msvc_atomicrmw_##operation##_##Type(zig_##Type volatile* obj, zig_##Type value) { \ | |
| 2328 | bool success = false; \ | |
| 2329 | zig_##Type new; \ | |
| 2330 | zig_##Type prev; \ | |
| 2331 | while (!success) { \ | |
| 2332 | prev = *obj; \ | |
| 2333 | new = zig_##operation##_##Type(prev, value); \ | |
| 2334 | success = zig_msvc_cmpxchg_##Type(obj, &prev, new); \ | |
| 2335 | } \ | |
| 2336 | return prev; \ | |
| 2337 | } | |
| 2338 | ||
| 2339 | zig_msvc_atomics_128op(u128, add) | |
| 2340 | zig_msvc_atomics_128op(u128, sub) | |
| 2341 | zig_msvc_atomics_128op(u128, or) | |
| 2342 | zig_msvc_atomics_128op(u128, xor) | |
| 2343 | zig_msvc_atomics_128op(u128, and) | |
| 2344 | zig_msvc_atomics_128op(u128, nand) | |
| 2345 | zig_msvc_atomics_128op(u128, min) | |
| 2346 | zig_msvc_atomics_128op(u128, max) | |
| 2347 | ||
| 2348 | #endif /* _MSC_VER && (_M_IX86 || _M_X64) */ | |
| 2349 | ||
| 2350 | /* ========================= Special Case Intrinsics ========================= */ | |
| 2351 | ||
| 2352 | #if (_MSC_VER && _M_X64) || defined(__x86_64__) | |
| 2353 | ||
| 2354 | static inline void* zig_x86_64_windows_teb(void) { | |
| 2355 | #if _MSC_VER | |
| 2356 | return __readgsqword(0x30); | |
| 2357 | #else | |
| 2358 | void* teb; | |
| 2359 | __asm volatile(" movq %%gs:0x30, %[ptr]": [ptr]"=r"(teb)::); | |
| 2360 | return teb; | |
| 2361 | #endif | |
| 2362 | } | |
| 2363 | ||
| 2364 | #endif | |
| 2365 | ||
| 2366 | #if (_MSC_VER && (_M_IX86 || _M_X64)) || defined(__i386__) || defined(__x86_64__) | |
| 2367 | ||
| 2368 | static inline void zig_x86_cpuid(zig_u32 leaf_id, zig_u32 subid, zig_u32* eax, zig_u32* ebx, zig_u32* ecx, zig_u32* edx) { | |
| 2369 | zig_u32 cpu_info[4]; | |
| 2370 | #if _MSC_VER | |
| 2371 | __cpuidex(cpu_info, leaf_id, subid); | |
| 2372 | #else | |
| 2373 | __cpuid_count(leaf_id, subid, cpu_info[0], cpu_info[1], cpu_info[2], cpu_info[3]); | |
| 2374 | #endif | |
| 2375 | *eax = cpu_info[0]; | |
| 2376 | *ebx = cpu_info[1]; | |
| 2377 | *ecx = cpu_info[2]; | |
| 2378 | *edx = cpu_info[3]; | |
| 2379 | } | |
| 2380 | ||
| 2381 | static inline zig_u32 zig_x86_get_xcr0(void) { | |
| 2382 | #if _MSC_VER | |
| 2383 | return (zig_u32)_xgetbv(0); | |
| 2384 | #else | |
| 2385 | zig_u32 eax; | |
| 2386 | zig_u32 edx; | |
| 2387 | __asm__("xgetbv" : "=a"(eax), "=d"(edx) : "c"(0)); | |
| 2388 | return eax; | |
| 2389 | #endif | |
| 2390 | } | |
| 2391 | ||
| 2392 | #endif |
src/codegen/c.zig+593-169| ... | ... | @@ -90,7 +90,15 @@ const FormatTypeAsCIdentContext = struct { |
| 90 | 90 | const ValueRenderLocation = enum { |
| 91 | 91 | FunctionArgument, |
| 92 | 92 | Initializer, |
| 93 | StaticInitializer, | |
| 93 | 94 | Other, |
| 95 | ||
| 96 | pub fn isInitializer(self: ValueRenderLocation) bool { | |
| 97 | return switch (self) { | |
| 98 | .Initializer, .StaticInitializer => true, | |
| 99 | else => false, | |
| 100 | }; | |
| 101 | } | |
| 94 | 102 | }; |
| 95 | 103 | |
| 96 | 104 | const BuiltinInfo = enum { |
| ... | ... | @@ -312,7 +320,7 @@ pub const Function = struct { |
| 312 | 320 | try writer.writeAll("static "); |
| 313 | 321 | try f.object.dg.renderTypeAndName(writer, ty, decl_c_value, .Const, alignment, .Complete); |
| 314 | 322 | try writer.writeAll(" = "); |
| 315 | try f.object.dg.renderValue(writer, ty, val, .Initializer); | |
| 323 | try f.object.dg.renderValue(writer, ty, val, .StaticInitializer); | |
| 316 | 324 | try writer.writeAll(";\n "); |
| 317 | 325 | break :result decl_c_value; |
| 318 | 326 | } else CValue{ .constant = inst }; |
| ... | ... | @@ -431,6 +439,10 @@ pub const Function = struct { |
| 431 | 439 | return f.object.dg.renderTypecast(w, t); |
| 432 | 440 | } |
| 433 | 441 | |
| 442 | fn renderIntCast(f: *Function, w: anytype, dest_ty: Type, src: CValue, src_ty: Type, location: ValueRenderLocation) !void { | |
| 443 | return f.object.dg.renderIntCast(w, dest_ty, .{ .c_value = .{ .f = f, .value = src } }, src_ty, location); | |
| 444 | } | |
| 445 | ||
| 434 | 446 | fn fmtIntLiteral(f: *Function, ty: Type, val: Value) !std.fmt.Formatter(formatIntLiteral) { |
| 435 | 447 | return f.object.dg.fmtIntLiteral(ty, val); |
| 436 | 448 | } |
| ... | ... | @@ -502,6 +514,7 @@ pub const DeclGen = struct { |
| 502 | 514 | ty: Type, |
| 503 | 515 | val: Value, |
| 504 | 516 | decl_index: Decl.Index, |
| 517 | location: ValueRenderLocation, | |
| 505 | 518 | ) error{ OutOfMemory, AnalysisFail }!void { |
| 506 | 519 | const decl = dg.module.declPtr(decl_index); |
| 507 | 520 | assert(decl.has_tv); |
| ... | ... | @@ -515,12 +528,16 @@ pub const DeclGen = struct { |
| 515 | 528 | inline for (.{ .function, .extern_fn }) |tag| |
| 516 | 529 | if (decl.val.castTag(tag)) |func| |
| 517 | 530 | if (func.data.owner_decl != decl_index) |
| 518 | return dg.renderDeclValue(writer, ty, val, func.data.owner_decl); | |
| 531 | return dg.renderDeclValue(writer, ty, val, func.data.owner_decl, location); | |
| 519 | 532 | |
| 520 | 533 | if (ty.isSlice()) { |
| 521 | try writer.writeByte('('); | |
| 522 | try dg.renderTypecast(writer, ty); | |
| 523 | try writer.writeAll("){ .ptr = "); | |
| 534 | if (location == .StaticInitializer) { | |
| 535 | try writer.writeByte('{'); | |
| 536 | } else { | |
| 537 | try writer.writeByte('('); | |
| 538 | try dg.renderTypecast(writer, ty); | |
| 539 | try writer.writeAll("){ .ptr = "); | |
| 540 | } | |
| 524 | 541 | |
| 525 | 542 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; |
| 526 | 543 | try dg.renderValue(writer, ty.slicePtrFieldType(&buf), val.slicePtr(), .Initializer); |
| ... | ... | @@ -530,7 +547,12 @@ pub const DeclGen = struct { |
| 530 | 547 | .data = val.sliceLen(dg.module), |
| 531 | 548 | }; |
| 532 | 549 | const len_val = Value.initPayload(&len_pl.base); |
| 533 | return writer.print(", .len = {} }}", .{try dg.fmtIntLiteral(Type.usize, len_val)}); | |
| 550 | ||
| 551 | if (location == .StaticInitializer) { | |
| 552 | return writer.print(", {} }}", .{try dg.fmtIntLiteral(Type.usize, len_val)}); | |
| 553 | } else { | |
| 554 | return writer.print(", .len = {} }}", .{try dg.fmtIntLiteral(Type.usize, len_val)}); | |
| 555 | } | |
| 534 | 556 | } |
| 535 | 557 | |
| 536 | 558 | // We shouldn't cast C function pointers as this is UB (when you call |
| ... | ... | @@ -552,7 +574,7 @@ pub const DeclGen = struct { |
| 552 | 574 | // that its contents are defined with respect to. |
| 553 | 575 | // |
| 554 | 576 | // Used for .elem_ptr, .field_ptr, .opt_payload_ptr, .eu_payload_ptr |
| 555 | fn renderParentPtr(dg: *DeclGen, writer: anytype, ptr_val: Value, ptr_ty: Type) error{ OutOfMemory, AnalysisFail }!void { | |
| 577 | fn renderParentPtr(dg: *DeclGen, writer: anytype, ptr_val: Value, ptr_ty: Type, location: ValueRenderLocation) error{ OutOfMemory, AnalysisFail }!void { | |
| 556 | 578 | if (!ptr_ty.isSlice()) { |
| 557 | 579 | try writer.writeByte('('); |
| 558 | 580 | try dg.renderTypecast(writer, ptr_ty); |
| ... | ... | @@ -567,7 +589,7 @@ pub const DeclGen = struct { |
| 567 | 589 | .variable => ptr_val.castTag(.variable).?.data.owner_decl, |
| 568 | 590 | else => unreachable, |
| 569 | 591 | }; |
| 570 | try dg.renderDeclValue(writer, ptr_ty, ptr_val, decl_index); | |
| 592 | try dg.renderDeclValue(writer, ptr_ty, ptr_val, decl_index, location); | |
| 571 | 593 | }, |
| 572 | 594 | .field_ptr => { |
| 573 | 595 | const ptr_info = ptr_ty.ptrInfo(); |
| ... | ... | @@ -605,7 +627,7 @@ pub const DeclGen = struct { |
| 605 | 627 | try writer.writeAll("&(("); |
| 606 | 628 | try dg.renderTypecast(writer, u8_ptr_ty); |
| 607 | 629 | try writer.writeByte(')'); |
| 608 | try dg.renderParentPtr(writer, field_ptr.container_ptr, container_ptr_ty); | |
| 630 | try dg.renderParentPtr(writer, field_ptr.container_ptr, container_ptr_ty, location); | |
| 609 | 631 | return writer.print(")[{}]", .{try dg.fmtIntLiteral(Type.usize, byte_offset_val)}); |
| 610 | 632 | } else { |
| 611 | 633 | var host_pl = Type.Payload.Bits{ |
| ... | ... | @@ -617,7 +639,7 @@ pub const DeclGen = struct { |
| 617 | 639 | try writer.writeByte('('); |
| 618 | 640 | try dg.renderTypecast(writer, ptr_ty); |
| 619 | 641 | try writer.writeByte(')'); |
| 620 | return dg.renderParentPtr(writer, field_ptr.container_ptr, host_ty); | |
| 642 | return dg.renderParentPtr(writer, field_ptr.container_ptr, host_ty, location); | |
| 621 | 643 | }, |
| 622 | 644 | }, |
| 623 | 645 | .Union => switch (container_ty.containerLayout()) { |
| ... | ... | @@ -626,7 +648,7 @@ pub const DeclGen = struct { |
| 626 | 648 | .ty = container_ty.unionFields().values()[index].ty, |
| 627 | 649 | }, |
| 628 | 650 | .Packed => { |
| 629 | return dg.renderParentPtr(writer, field_ptr.container_ptr, ptr_ty); | |
| 651 | return dg.renderParentPtr(writer, field_ptr.container_ptr, ptr_ty, location); | |
| 630 | 652 | }, |
| 631 | 653 | }, |
| 632 | 654 | .Pointer => field_info: { |
| ... | ... | @@ -645,7 +667,7 @@ pub const DeclGen = struct { |
| 645 | 667 | try dg.renderType(std.io.null_writer, field_ptr.container_ty, .Complete); |
| 646 | 668 | |
| 647 | 669 | try writer.writeAll("&("); |
| 648 | try dg.renderParentPtr(writer, field_ptr.container_ptr, container_ptr_ty); | |
| 670 | try dg.renderParentPtr(writer, field_ptr.container_ptr, container_ptr_ty, location); | |
| 649 | 671 | try writer.writeAll(")->"); |
| 650 | 672 | switch (field_ptr.container_ty.tag()) { |
| 651 | 673 | .union_tagged, .union_safety_tagged => try writer.writeAll("payload."), |
| ... | ... | @@ -653,7 +675,7 @@ pub const DeclGen = struct { |
| 653 | 675 | } |
| 654 | 676 | try writer.print("{ }", .{fmtIdent(field_info.name)}); |
| 655 | 677 | } else { |
| 656 | try dg.renderParentPtr(writer, field_ptr.container_ptr, container_ptr_ty); | |
| 678 | try dg.renderParentPtr(writer, field_ptr.container_ptr, container_ptr_ty, location); | |
| 657 | 679 | } |
| 658 | 680 | }, |
| 659 | 681 | .elem_ptr => { |
| ... | ... | @@ -665,7 +687,7 @@ pub const DeclGen = struct { |
| 665 | 687 | const elem_ptr_ty = Type.initPayload(&elem_ptr_ty_pl.base); |
| 666 | 688 | |
| 667 | 689 | try writer.writeAll("&("); |
| 668 | try dg.renderParentPtr(writer, elem_ptr.array_ptr, elem_ptr_ty); | |
| 690 | try dg.renderParentPtr(writer, elem_ptr.array_ptr, elem_ptr_ty, location); | |
| 669 | 691 | try writer.print(")[{d}]", .{elem_ptr.index}); |
| 670 | 692 | }, |
| 671 | 693 | .opt_payload_ptr, .eu_payload_ptr => { |
| ... | ... | @@ -680,7 +702,7 @@ pub const DeclGen = struct { |
| 680 | 702 | try dg.renderType(std.io.null_writer, payload_ptr.container_ty, .Complete); |
| 681 | 703 | |
| 682 | 704 | try writer.writeAll("&("); |
| 683 | try dg.renderParentPtr(writer, payload_ptr.container_ptr, container_ptr_ty); | |
| 705 | try dg.renderParentPtr(writer, payload_ptr.container_ptr, container_ptr_ty, location); | |
| 684 | 706 | try writer.writeAll(")->payload"); |
| 685 | 707 | }, |
| 686 | 708 | else => unreachable, |
| ... | ... | @@ -699,6 +721,10 @@ pub const DeclGen = struct { |
| 699 | 721 | val = rt.data; |
| 700 | 722 | } |
| 701 | 723 | const target = dg.module.getTarget(); |
| 724 | const initializer_type: ValueRenderLocation = switch (location) { | |
| 725 | .StaticInitializer => .StaticInitializer, | |
| 726 | else => .Initializer, | |
| 727 | }; | |
| 702 | 728 | |
| 703 | 729 | const safety_on = switch (dg.module.optimizeMode()) { |
| 704 | 730 | .Debug, .ReleaseSafe => true, |
| ... | ... | @@ -714,15 +740,15 @@ pub const DeclGen = struct { |
| 714 | 740 | return writer.writeAll("false"); |
| 715 | 741 | } |
| 716 | 742 | }, |
| 717 | .Int, .Enum, .ErrorSet => return writer.print("{x}", .{try dg.fmtIntLiteral(ty, val)}), | |
| 743 | .Int, .Enum, .ErrorSet => return writer.print("{x}", .{try dg.fmtIntLiteralLoc(ty, val, location)}), | |
| 718 | 744 | .Float => { |
| 719 | 745 | const bits = ty.floatBits(target); |
| 720 | 746 | var int_pl = Type.Payload.Bits{ .base = .{ .tag = .int_signed }, .data = bits }; |
| 721 | 747 | const int_ty = Type.initPayload(&int_pl.base); |
| 722 | 748 | |
| 723 | try writer.writeByte('('); | |
| 724 | try dg.renderTypecast(writer, ty); | |
| 725 | try writer.writeAll(")zig_as_"); | |
| 749 | try writer.writeAll("zig_cast_"); | |
| 750 | try dg.renderTypeForBuiltinFnName(writer, ty); | |
| 751 | try writer.writeAll(" zig_as_"); | |
| 726 | 752 | try dg.renderTypeForBuiltinFnName(writer, ty); |
| 727 | 753 | try writer.writeByte('('); |
| 728 | 754 | switch (bits) { |
| ... | ... | @@ -738,7 +764,7 @@ pub const DeclGen = struct { |
| 738 | 764 | return writer.writeByte(')'); |
| 739 | 765 | }, |
| 740 | 766 | .Pointer => if (ty.isSlice()) { |
| 741 | if (location != .Initializer) { | |
| 767 | if (!location.isInitializer()) { | |
| 742 | 768 | try writer.writeByte('('); |
| 743 | 769 | try dg.renderTypecast(writer, ty); |
| 744 | 770 | try writer.writeByte(')'); |
| ... | ... | @@ -766,21 +792,21 @@ pub const DeclGen = struct { |
| 766 | 792 | return dg.renderValue(writer, payload_ty, val, location); |
| 767 | 793 | } |
| 768 | 794 | |
| 769 | if (location != .Initializer) { | |
| 795 | if (!location.isInitializer()) { | |
| 770 | 796 | try writer.writeByte('('); |
| 771 | 797 | try dg.renderTypecast(writer, ty); |
| 772 | 798 | try writer.writeByte(')'); |
| 773 | 799 | } |
| 774 | 800 | |
| 775 | 801 | try writer.writeAll("{ .payload = "); |
| 776 | try dg.renderValue(writer, payload_ty, val, .Initializer); | |
| 802 | try dg.renderValue(writer, payload_ty, val, initializer_type); | |
| 777 | 803 | try writer.writeAll(", .is_null = "); |
| 778 | try dg.renderValue(writer, Type.bool, val, .Initializer); | |
| 804 | try dg.renderValue(writer, Type.bool, val, initializer_type); | |
| 779 | 805 | return writer.writeAll(" }"); |
| 780 | 806 | }, |
| 781 | 807 | .Struct => switch (ty.containerLayout()) { |
| 782 | 808 | .Auto, .Extern => { |
| 783 | if (location != .Initializer) { | |
| 809 | if (!location.isInitializer()) { | |
| 784 | 810 | try writer.writeByte('('); |
| 785 | 811 | try dg.renderTypecast(writer, ty); |
| 786 | 812 | try writer.writeByte(')'); |
| ... | ... | @@ -792,7 +818,7 @@ pub const DeclGen = struct { |
| 792 | 818 | if (!field.ty.hasRuntimeBits()) continue; |
| 793 | 819 | |
| 794 | 820 | if (!empty) try writer.writeByte(','); |
| 795 | try dg.renderValue(writer, field.ty, val, .Initializer); | |
| 821 | try dg.renderValue(writer, field.ty, val, initializer_type); | |
| 796 | 822 | |
| 797 | 823 | empty = false; |
| 798 | 824 | } |
| ... | ... | @@ -802,7 +828,7 @@ pub const DeclGen = struct { |
| 802 | 828 | .Packed => return writer.print("{x}", .{try dg.fmtIntLiteral(ty, Value.undef)}), |
| 803 | 829 | }, |
| 804 | 830 | .Union => { |
| 805 | if (location != .Initializer) { | |
| 831 | if (!location.isInitializer()) { | |
| 806 | 832 | try writer.writeByte('('); |
| 807 | 833 | try dg.renderTypecast(writer, ty); |
| 808 | 834 | try writer.writeByte(')'); |
| ... | ... | @@ -813,34 +839,34 @@ pub const DeclGen = struct { |
| 813 | 839 | const layout = ty.unionGetLayout(target); |
| 814 | 840 | if (layout.tag_size != 0) { |
| 815 | 841 | try writer.writeAll(" .tag = "); |
| 816 | try dg.renderValue(writer, tag_ty, val, .Initializer); | |
| 842 | try dg.renderValue(writer, tag_ty, val, initializer_type); | |
| 817 | 843 | try writer.writeByte(','); |
| 818 | 844 | } |
| 819 | 845 | try writer.writeAll(" .payload = {"); |
| 820 | 846 | } |
| 821 | 847 | for (ty.unionFields().values()) |field| { |
| 822 | 848 | if (!field.ty.hasRuntimeBits()) continue; |
| 823 | try dg.renderValue(writer, field.ty, val, .Initializer); | |
| 849 | try dg.renderValue(writer, field.ty, val, initializer_type); | |
| 824 | 850 | break; |
| 825 | 851 | } else try writer.print("{x}", .{try dg.fmtIntLiteral(Type.u8, Value.undef)}); |
| 826 | 852 | if (ty.unionTagTypeSafety()) |_| try writer.writeByte('}'); |
| 827 | 853 | return writer.writeByte('}'); |
| 828 | 854 | }, |
| 829 | 855 | .ErrorUnion => { |
| 830 | if (location != .Initializer) { | |
| 856 | if (!location.isInitializer()) { | |
| 831 | 857 | try writer.writeByte('('); |
| 832 | 858 | try dg.renderTypecast(writer, ty); |
| 833 | 859 | try writer.writeByte(')'); |
| 834 | 860 | } |
| 835 | 861 | |
| 836 | 862 | try writer.writeAll("{ .payload = "); |
| 837 | try dg.renderValue(writer, ty.errorUnionPayload(), val, .Initializer); | |
| 863 | try dg.renderValue(writer, ty.errorUnionPayload(), val, initializer_type); | |
| 838 | 864 | return writer.print(", .error = {x} }}", .{ |
| 839 | 865 | try dg.fmtIntLiteral(ty.errorUnionSet(), val), |
| 840 | 866 | }); |
| 841 | 867 | }, |
| 842 | 868 | .Array, .Vector => { |
| 843 | if (location != .Initializer) { | |
| 869 | if (!location.isInitializer()) { | |
| 844 | 870 | try writer.writeByte('('); |
| 845 | 871 | try dg.renderTypecast(writer, ty); |
| 846 | 872 | try writer.writeByte(')'); |
| ... | ... | @@ -848,19 +874,20 @@ pub const DeclGen = struct { |
| 848 | 874 | |
| 849 | 875 | const ai = ty.arrayInfo(); |
| 850 | 876 | if (ai.elem_type.eql(Type.u8, dg.module)) { |
| 851 | try writer.writeByte('"'); | |
| 877 | var literal = stringLiteral(writer); | |
| 878 | try literal.start(); | |
| 852 | 879 | const c_len = ty.arrayLenIncludingSentinel(); |
| 853 | 880 | var index: usize = 0; |
| 854 | 881 | while (index < c_len) : (index += 1) |
| 855 | try writeStringLiteralChar(writer, 0xaa); | |
| 856 | return writer.writeByte('"'); | |
| 882 | try literal.writeChar(0xaa); | |
| 883 | return literal.end(); | |
| 857 | 884 | } else { |
| 858 | 885 | try writer.writeByte('{'); |
| 859 | 886 | const c_len = ty.arrayLenIncludingSentinel(); |
| 860 | 887 | var index: usize = 0; |
| 861 | 888 | while (index < c_len) : (index += 1) { |
| 862 | 889 | if (index > 0) try writer.writeAll(", "); |
| 863 | try dg.renderValue(writer, ty.childType(), val, .Initializer); | |
| 890 | try dg.renderValue(writer, ty.childType(), val, initializer_type); | |
| 864 | 891 | } |
| 865 | 892 | return writer.writeByte('}'); |
| 866 | 893 | } |
| ... | ... | @@ -893,8 +920,8 @@ pub const DeclGen = struct { |
| 893 | 920 | .eu_payload_ptr, |
| 894 | 921 | .decl_ref_mut, |
| 895 | 922 | .decl_ref, |
| 896 | => try dg.renderParentPtr(writer, val, ty), | |
| 897 | else => try writer.print("{}", .{try dg.fmtIntLiteral(ty, val)}), | |
| 923 | => try dg.renderParentPtr(writer, val, ty, location), | |
| 924 | else => try writer.print("{}", .{try dg.fmtIntLiteralLoc(ty, val, location)}), | |
| 898 | 925 | }, |
| 899 | 926 | .Float => { |
| 900 | 927 | const bits = ty.floatBits(target); |
| ... | ... | @@ -926,9 +953,10 @@ pub const DeclGen = struct { |
| 926 | 953 | }; |
| 927 | 954 | const int_val = Value.initPayload(&int_val_pl.base); |
| 928 | 955 | |
| 929 | try writer.writeByte('('); | |
| 930 | try dg.renderTypecast(writer, ty); | |
| 931 | try writer.writeByte(')'); | |
| 956 | try writer.writeAll("zig_cast_"); | |
| 957 | try dg.renderTypeForBuiltinFnName(writer, ty); | |
| 958 | try writer.writeByte(' '); | |
| 959 | var empty = true; | |
| 932 | 960 | if (std.math.isFinite(f128_val)) { |
| 933 | 961 | try writer.writeAll("zig_as_"); |
| 934 | 962 | try dg.renderTypeForBuiltinFnName(writer, ty); |
| ... | ... | @@ -941,17 +969,32 @@ pub const DeclGen = struct { |
| 941 | 969 | 128 => try writer.print("{x}", .{f128_val}), |
| 942 | 970 | else => unreachable, |
| 943 | 971 | } |
| 972 | try writer.writeAll(", "); | |
| 973 | empty = false; | |
| 944 | 974 | } else { |
| 945 | const operation = if (std.math.isSignalNan(f128_val)) | |
| 946 | "nans" | |
| 947 | else if (std.math.isNan(f128_val)) | |
| 975 | // isSignalNan is equivalent to isNan currently, and MSVC doens't have nans, so prefer nan | |
| 976 | const operation = if (std.math.isNan(f128_val)) | |
| 948 | 977 | "nan" |
| 978 | else if (std.math.isSignalNan(f128_val)) | |
| 979 | "nans" | |
| 949 | 980 | else if (std.math.isInf(f128_val)) |
| 950 | 981 | "inf" |
| 951 | 982 | else |
| 952 | 983 | unreachable; |
| 953 | 984 | |
| 985 | if (location == .StaticInitializer) { | |
| 986 | if (!std.math.isNan(f128_val) and std.math.isSignalNan(f128_val)) | |
| 987 | return dg.fail("TODO: C backend: implement nans rendering in static initializers", .{}); | |
| 988 | ||
| 989 | // MSVC doesn't have a way to define a custom or signaling NaN value in a constant expression | |
| 990 | ||
| 991 | // TODO: Re-enable this check, otherwise we're writing qnan bit patterns on msvc incorrectly | |
| 992 | // if (std.math.isNan(f128_val) and f128_val != std.math.qnan_f128) | |
| 993 | // return dg.fail("Only quiet nans are supported in global variable initializers", .{}); | |
| 994 | } | |
| 995 | ||
| 954 | 996 | try writer.writeAll("zig_as_special_"); |
| 997 | if (location == .StaticInitializer) try writer.writeAll("constant_"); | |
| 955 | 998 | try dg.renderTypeForBuiltinFnName(writer, ty); |
| 956 | 999 | try writer.writeByte('('); |
| 957 | 1000 | if (std.math.signbit(f128_val)) try writer.writeByte('-'); |
| ... | ... | @@ -968,8 +1011,12 @@ pub const DeclGen = struct { |
| 968 | 1011 | 128 => try writer.print("\"0x{x}\"", .{@bitCast(u128, f128_val)}), |
| 969 | 1012 | else => unreachable, |
| 970 | 1013 | }; |
| 1014 | try writer.writeAll(", "); | |
| 1015 | empty = false; | |
| 971 | 1016 | } |
| 972 | return writer.print(", {x})", .{try dg.fmtIntLiteral(int_ty, int_val)}); | |
| 1017 | try writer.print("{x}", .{try dg.fmtIntLiteralLoc(int_ty, int_val, location)}); | |
| 1018 | if (!empty) try writer.writeByte(')'); | |
| 1019 | return; | |
| 973 | 1020 | }, |
| 974 | 1021 | .Pointer => switch (val.tag()) { |
| 975 | 1022 | .null_value, .zero => if (ty.isSlice()) { |
| ... | ... | @@ -987,10 +1034,10 @@ pub const DeclGen = struct { |
| 987 | 1034 | }, |
| 988 | 1035 | .variable => { |
| 989 | 1036 | const decl = val.castTag(.variable).?.data.owner_decl; |
| 990 | return dg.renderDeclValue(writer, ty, val, decl); | |
| 1037 | return dg.renderDeclValue(writer, ty, val, decl, location); | |
| 991 | 1038 | }, |
| 992 | 1039 | .slice => { |
| 993 | if (location != .Initializer) { | |
| 1040 | if (!location.isInitializer()) { | |
| 994 | 1041 | try writer.writeByte('('); |
| 995 | 1042 | try dg.renderTypecast(writer, ty); |
| 996 | 1043 | try writer.writeByte(')'); |
| ... | ... | @@ -1000,9 +1047,9 @@ pub const DeclGen = struct { |
| 1000 | 1047 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; |
| 1001 | 1048 | |
| 1002 | 1049 | try writer.writeByte('{'); |
| 1003 | try dg.renderValue(writer, ty.slicePtrFieldType(&buf), slice.ptr, .Initializer); | |
| 1050 | try dg.renderValue(writer, ty.slicePtrFieldType(&buf), slice.ptr, initializer_type); | |
| 1004 | 1051 | try writer.writeAll(", "); |
| 1005 | try dg.renderValue(writer, Type.usize, slice.len, .Initializer); | |
| 1052 | try dg.renderValue(writer, Type.usize, slice.len, initializer_type); | |
| 1006 | 1053 | try writer.writeByte('}'); |
| 1007 | 1054 | }, |
| 1008 | 1055 | .function => { |
| ... | ... | @@ -1024,7 +1071,7 @@ pub const DeclGen = struct { |
| 1024 | 1071 | .eu_payload_ptr, |
| 1025 | 1072 | .decl_ref_mut, |
| 1026 | 1073 | .decl_ref, |
| 1027 | => try dg.renderParentPtr(writer, val, ty), | |
| 1074 | => try dg.renderParentPtr(writer, val, ty, location), | |
| 1028 | 1075 | else => unreachable, |
| 1029 | 1076 | }, |
| 1030 | 1077 | .Array, .Vector => { |
| ... | ... | @@ -1040,7 +1087,7 @@ pub const DeclGen = struct { |
| 1040 | 1087 | try writer.writeByte('{'); |
| 1041 | 1088 | const ai = ty.arrayInfo(); |
| 1042 | 1089 | if (ai.sentinel) |s| { |
| 1043 | try dg.renderValue(writer, ai.elem_type, s, .Initializer); | |
| 1090 | try dg.renderValue(writer, ai.elem_type, s, initializer_type); | |
| 1044 | 1091 | } else { |
| 1045 | 1092 | try writer.writeByte('0'); |
| 1046 | 1093 | } |
| ... | ... | @@ -1060,34 +1107,51 @@ pub const DeclGen = struct { |
| 1060 | 1107 | defer arena.deinit(); |
| 1061 | 1108 | const arena_allocator = arena.allocator(); |
| 1062 | 1109 | |
| 1110 | // MSVC throws C2078 if an array of size 65536 or greater is initialized with a string literal | |
| 1111 | const max_string_initializer_len = 65535; | |
| 1112 | ||
| 1063 | 1113 | const ai = ty.arrayInfo(); |
| 1064 | 1114 | if (ai.elem_type.eql(Type.u8, dg.module)) { |
| 1065 | try writer.writeByte('"'); | |
| 1066 | var index: usize = 0; | |
| 1067 | while (index < ai.len) : (index += 1) { | |
| 1068 | const elem_val = try val.elemValue(dg.module, arena_allocator, index); | |
| 1069 | const elem_val_u8 = if (elem_val.isUndef()) | |
| 1070 | undefPattern(u8) | |
| 1071 | else | |
| 1072 | @intCast(u8, elem_val.toUnsignedInt(target)); | |
| 1073 | try writeStringLiteralChar(writer, elem_val_u8); | |
| 1074 | } | |
| 1075 | if (ai.sentinel) |s| { | |
| 1076 | const s_u8 = @intCast(u8, s.toUnsignedInt(target)); | |
| 1077 | try writeStringLiteralChar(writer, s_u8); | |
| 1115 | if (ai.len <= max_string_initializer_len) { | |
| 1116 | var literal = stringLiteral(writer); | |
| 1117 | try literal.start(); | |
| 1118 | var index: usize = 0; | |
| 1119 | while (index < ai.len) : (index += 1) { | |
| 1120 | const elem_val = try val.elemValue(dg.module, arena_allocator, index); | |
| 1121 | const elem_val_u8 = if (elem_val.isUndef()) undefPattern(u8) else @intCast(u8, elem_val.toUnsignedInt(target)); | |
| 1122 | try literal.writeChar(elem_val_u8); | |
| 1123 | } | |
| 1124 | if (ai.sentinel) |s| { | |
| 1125 | const s_u8 = @intCast(u8, s.toUnsignedInt(target)); | |
| 1126 | try literal.writeChar(s_u8); | |
| 1127 | } | |
| 1128 | try literal.end(); | |
| 1129 | } else { | |
| 1130 | try writer.writeByte('{'); | |
| 1131 | var index: usize = 0; | |
| 1132 | while (index < ai.len) : (index += 1) { | |
| 1133 | if (index != 0) try writer.writeByte(','); | |
| 1134 | const elem_val = try val.elemValue(dg.module, arena_allocator, index); | |
| 1135 | const elem_val_u8 = if (elem_val.isUndef()) undefPattern(u8) else @intCast(u8, elem_val.toUnsignedInt(target)); | |
| 1136 | try writer.print("'\\x{x}'", .{elem_val_u8}); | |
| 1137 | } | |
| 1138 | if (ai.sentinel) |s| { | |
| 1139 | if (index != 0) try writer.writeByte(','); | |
| 1140 | try dg.renderValue(writer, ai.elem_type, s, initializer_type); | |
| 1141 | } | |
| 1142 | try writer.writeByte('}'); | |
| 1078 | 1143 | } |
| 1079 | try writer.writeByte('"'); | |
| 1080 | 1144 | } else { |
| 1081 | 1145 | try writer.writeByte('{'); |
| 1082 | 1146 | var index: usize = 0; |
| 1083 | 1147 | while (index < ai.len) : (index += 1) { |
| 1084 | 1148 | if (index != 0) try writer.writeByte(','); |
| 1085 | 1149 | const elem_val = try val.elemValue(dg.module, arena_allocator, index); |
| 1086 | try dg.renderValue(writer, ai.elem_type, elem_val, .Initializer); | |
| 1150 | try dg.renderValue(writer, ai.elem_type, elem_val, initializer_type); | |
| 1087 | 1151 | } |
| 1088 | 1152 | if (ai.sentinel) |s| { |
| 1089 | 1153 | if (index != 0) try writer.writeByte(','); |
| 1090 | try dg.renderValue(writer, ai.elem_type, s, .Initializer); | |
| 1154 | try dg.renderValue(writer, ai.elem_type, s, initializer_type); | |
| 1091 | 1155 | } |
| 1092 | 1156 | try writer.writeByte('}'); |
| 1093 | 1157 | } |
| ... | ... | @@ -1114,7 +1178,7 @@ pub const DeclGen = struct { |
| 1114 | 1178 | return dg.renderValue(writer, payload_ty, payload_val, location); |
| 1115 | 1179 | } |
| 1116 | 1180 | |
| 1117 | if (location != .Initializer) { | |
| 1181 | if (!location.isInitializer()) { | |
| 1118 | 1182 | try writer.writeByte('('); |
| 1119 | 1183 | try dg.renderTypecast(writer, ty); |
| 1120 | 1184 | try writer.writeByte(')'); |
| ... | ... | @@ -1123,9 +1187,9 @@ pub const DeclGen = struct { |
| 1123 | 1187 | const payload_val = if (val.castTag(.opt_payload)) |pl| pl.data else Value.undef; |
| 1124 | 1188 | |
| 1125 | 1189 | try writer.writeAll("{ .payload = "); |
| 1126 | try dg.renderValue(writer, payload_ty, payload_val, .Initializer); | |
| 1190 | try dg.renderValue(writer, payload_ty, payload_val, initializer_type); | |
| 1127 | 1191 | try writer.writeAll(", .is_null = "); |
| 1128 | try dg.renderValue(writer, Type.bool, is_null_val, .Initializer); | |
| 1192 | try dg.renderValue(writer, Type.bool, is_null_val, initializer_type); | |
| 1129 | 1193 | try writer.writeAll(" }"); |
| 1130 | 1194 | }, |
| 1131 | 1195 | .ErrorSet => { |
| ... | ... | @@ -1148,7 +1212,7 @@ pub const DeclGen = struct { |
| 1148 | 1212 | return dg.renderValue(writer, error_ty, val, location); |
| 1149 | 1213 | } |
| 1150 | 1214 | |
| 1151 | if (location != .Initializer) { | |
| 1215 | if (!location.isInitializer()) { | |
| 1152 | 1216 | try writer.writeByte('('); |
| 1153 | 1217 | try dg.renderTypecast(writer, ty); |
| 1154 | 1218 | try writer.writeByte(')'); |
| ... | ... | @@ -1158,9 +1222,9 @@ pub const DeclGen = struct { |
| 1158 | 1222 | const error_val = if (val.errorUnionIsPayload()) Value.zero else val; |
| 1159 | 1223 | |
| 1160 | 1224 | try writer.writeAll("{ .payload = "); |
| 1161 | try dg.renderValue(writer, payload_ty, payload_val, .Initializer); | |
| 1225 | try dg.renderValue(writer, payload_ty, payload_val, initializer_type); | |
| 1162 | 1226 | try writer.writeAll(", .error = "); |
| 1163 | try dg.renderValue(writer, error_ty, error_val, .Initializer); | |
| 1227 | try dg.renderValue(writer, error_ty, error_val, initializer_type); | |
| 1164 | 1228 | try writer.writeAll(" }"); |
| 1165 | 1229 | }, |
| 1166 | 1230 | .Enum => { |
| ... | ... | @@ -1200,11 +1264,11 @@ pub const DeclGen = struct { |
| 1200 | 1264 | .Fn => switch (val.tag()) { |
| 1201 | 1265 | .function => { |
| 1202 | 1266 | const decl = val.castTag(.function).?.data.owner_decl; |
| 1203 | return dg.renderDeclValue(writer, ty, val, decl); | |
| 1267 | return dg.renderDeclValue(writer, ty, val, decl, location); | |
| 1204 | 1268 | }, |
| 1205 | 1269 | .extern_fn => { |
| 1206 | 1270 | const decl = val.castTag(.extern_fn).?.data.owner_decl; |
| 1207 | return dg.renderDeclValue(writer, ty, val, decl); | |
| 1271 | return dg.renderDeclValue(writer, ty, val, decl, location); | |
| 1208 | 1272 | }, |
| 1209 | 1273 | else => unreachable, |
| 1210 | 1274 | }, |
| ... | ... | @@ -1212,7 +1276,7 @@ pub const DeclGen = struct { |
| 1212 | 1276 | .Auto, .Extern => { |
| 1213 | 1277 | const field_vals = val.castTag(.aggregate).?.data; |
| 1214 | 1278 | |
| 1215 | if (location != .Initializer) { | |
| 1279 | if (!location.isInitializer()) { | |
| 1216 | 1280 | try writer.writeByte('('); |
| 1217 | 1281 | try dg.renderTypecast(writer, ty); |
| 1218 | 1282 | try writer.writeByte(')'); |
| ... | ... | @@ -1225,7 +1289,7 @@ pub const DeclGen = struct { |
| 1225 | 1289 | if (!field_ty.hasRuntimeBits()) continue; |
| 1226 | 1290 | |
| 1227 | 1291 | if (!empty) try writer.writeByte(','); |
| 1228 | try dg.renderValue(writer, field_ty, field_val, .Initializer); | |
| 1292 | try dg.renderValue(writer, field_ty, field_val, initializer_type); | |
| 1229 | 1293 | |
| 1230 | 1294 | empty = false; |
| 1231 | 1295 | } |
| ... | ... | @@ -1245,31 +1309,85 @@ pub const DeclGen = struct { |
| 1245 | 1309 | var bit_offset_val_pl: Value.Payload.U64 = .{ .base = .{ .tag = .int_u64 }, .data = 0 }; |
| 1246 | 1310 | const bit_offset_val = Value.initPayload(&bit_offset_val_pl.base); |
| 1247 | 1311 | |
| 1248 | try writer.writeByte('('); | |
| 1249 | var empty = true; | |
| 1250 | for (field_vals) |field_val, index| { | |
| 1312 | var eff_num_fields: usize = 0; | |
| 1313 | for (field_vals) |_, index| { | |
| 1251 | 1314 | const field_ty = ty.structFieldType(index); |
| 1252 | 1315 | if (!field_ty.hasRuntimeBitsIgnoreComptime()) continue; |
| 1253 | 1316 | |
| 1254 | if (!empty) try writer.writeAll(" | "); | |
| 1317 | eff_num_fields += 1; | |
| 1318 | } | |
| 1319 | ||
| 1320 | if (eff_num_fields == 0) { | |
| 1255 | 1321 | try writer.writeByte('('); |
| 1256 | try dg.renderTypecast(writer, ty); | |
| 1322 | try dg.renderValue(writer, ty, Value.undef, initializer_type); | |
| 1257 | 1323 | try writer.writeByte(')'); |
| 1258 | try dg.renderValue(writer, field_ty, field_val, .Other); | |
| 1259 | try writer.writeAll(" << "); | |
| 1260 | try dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument); | |
| 1324 | } else if (ty.bitSize(target) > 64) { | |
| 1325 | // zig_or_u128(zig_or_u128(zig_shl_u128(a, a_off), zig_shl_u128(b, b_off)), zig_shl_u128(c, c_off)) | |
| 1326 | var num_or = eff_num_fields - 1; | |
| 1327 | while (num_or > 0) : (num_or -= 1) { | |
| 1328 | try writer.writeAll("zig_or_"); | |
| 1329 | try dg.renderTypeForBuiltinFnName(writer, ty); | |
| 1330 | try writer.writeByte('('); | |
| 1331 | } | |
| 1261 | 1332 | |
| 1262 | bit_offset_val_pl.data += field_ty.bitSize(target); | |
| 1263 | empty = false; | |
| 1333 | var eff_index: usize = 0; | |
| 1334 | var needs_closing_paren = false; | |
| 1335 | for (field_vals) |field_val, index| { | |
| 1336 | const field_ty = ty.structFieldType(index); | |
| 1337 | if (!field_ty.hasRuntimeBitsIgnoreComptime()) continue; | |
| 1338 | ||
| 1339 | const cast_context = IntCastContext{ .value = .{ .value = field_val } }; | |
| 1340 | if (bit_offset_val_pl.data != 0) { | |
| 1341 | try writer.writeAll("zig_shl_"); | |
| 1342 | try dg.renderTypeForBuiltinFnName(writer, ty); | |
| 1343 | try writer.writeByte('('); | |
| 1344 | try dg.renderIntCast(writer, ty, cast_context, field_ty, .FunctionArgument); | |
| 1345 | try writer.writeAll(", "); | |
| 1346 | try dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument); | |
| 1347 | try writer.writeByte(')'); | |
| 1348 | } else { | |
| 1349 | try dg.renderIntCast(writer, ty, cast_context, field_ty, .FunctionArgument); | |
| 1350 | } | |
| 1351 | ||
| 1352 | if (needs_closing_paren) try writer.writeByte(')'); | |
| 1353 | if (eff_index != eff_num_fields - 1) try writer.writeAll(", "); | |
| 1354 | ||
| 1355 | bit_offset_val_pl.data += field_ty.bitSize(target); | |
| 1356 | needs_closing_paren = true; | |
| 1357 | eff_index += 1; | |
| 1358 | } | |
| 1359 | } else { | |
| 1360 | try writer.writeByte('('); | |
| 1361 | // a << a_off | b << b_off | c << c_off | |
| 1362 | var empty = true; | |
| 1363 | for (field_vals) |field_val, index| { | |
| 1364 | const field_ty = ty.structFieldType(index); | |
| 1365 | if (!field_ty.hasRuntimeBitsIgnoreComptime()) continue; | |
| 1366 | ||
| 1367 | if (!empty) try writer.writeAll(" | "); | |
| 1368 | try writer.writeByte('('); | |
| 1369 | try dg.renderTypecast(writer, ty); | |
| 1370 | try writer.writeByte(')'); | |
| 1371 | ||
| 1372 | if (bit_offset_val_pl.data != 0) { | |
| 1373 | try dg.renderValue(writer, field_ty, field_val, .Other); | |
| 1374 | try writer.writeAll(" << "); | |
| 1375 | try dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument); | |
| 1376 | } else { | |
| 1377 | try dg.renderValue(writer, field_ty, field_val, .Other); | |
| 1378 | } | |
| 1379 | ||
| 1380 | bit_offset_val_pl.data += field_ty.bitSize(target); | |
| 1381 | empty = false; | |
| 1382 | } | |
| 1383 | try writer.writeByte(')'); | |
| 1264 | 1384 | } |
| 1265 | if (empty) try dg.renderValue(writer, ty, Value.undef, .Initializer); | |
| 1266 | try writer.writeByte(')'); | |
| 1267 | 1385 | }, |
| 1268 | 1386 | }, |
| 1269 | 1387 | .Union => { |
| 1270 | 1388 | const union_obj = val.castTag(.@"union").?.data; |
| 1271 | 1389 | |
| 1272 | if (location != .Initializer) { | |
| 1390 | if (!location.isInitializer()) { | |
| 1273 | 1391 | try writer.writeByte('('); |
| 1274 | 1392 | try dg.renderTypecast(writer, ty); |
| 1275 | 1393 | try writer.writeByte(')'); |
| ... | ... | @@ -1289,7 +1407,7 @@ pub const DeclGen = struct { |
| 1289 | 1407 | try dg.renderTypecast(writer, ty); |
| 1290 | 1408 | try writer.writeByte(')'); |
| 1291 | 1409 | } |
| 1292 | try dg.renderValue(writer, field_ty, union_obj.val, .Initializer); | |
| 1410 | try dg.renderValue(writer, field_ty, union_obj.val, initializer_type); | |
| 1293 | 1411 | } else { |
| 1294 | 1412 | try writer.writeAll("0"); |
| 1295 | 1413 | } |
| ... | ... | @@ -1301,7 +1419,7 @@ pub const DeclGen = struct { |
| 1301 | 1419 | const layout = ty.unionGetLayout(target); |
| 1302 | 1420 | if (layout.tag_size != 0) { |
| 1303 | 1421 | try writer.writeAll(".tag = "); |
| 1304 | try dg.renderValue(writer, tag_ty, union_obj.tag, .Initializer); | |
| 1422 | try dg.renderValue(writer, tag_ty, union_obj.tag, initializer_type); | |
| 1305 | 1423 | try writer.writeAll(", "); |
| 1306 | 1424 | } |
| 1307 | 1425 | try writer.writeAll(".payload = {"); |
| ... | ... | @@ -1310,11 +1428,11 @@ pub const DeclGen = struct { |
| 1310 | 1428 | var it = ty.unionFields().iterator(); |
| 1311 | 1429 | if (field_ty.hasRuntimeBits()) { |
| 1312 | 1430 | try writer.print(".{ } = ", .{fmtIdent(field_name)}); |
| 1313 | try dg.renderValue(writer, field_ty, union_obj.val, .Initializer); | |
| 1431 | try dg.renderValue(writer, field_ty, union_obj.val, initializer_type); | |
| 1314 | 1432 | } else while (it.next()) |field| { |
| 1315 | 1433 | if (!field.value_ptr.ty.hasRuntimeBits()) continue; |
| 1316 | 1434 | try writer.print(".{ } = ", .{fmtIdent(field.key_ptr.*)}); |
| 1317 | try dg.renderValue(writer, field.value_ptr.ty, Value.undef, .Initializer); | |
| 1435 | try dg.renderValue(writer, field.value_ptr.ty, Value.undef, initializer_type); | |
| 1318 | 1436 | break; |
| 1319 | 1437 | } else try writer.writeAll(".empty_union = 0"); |
| 1320 | 1438 | if (ty.unionTagTypeSafety()) |_| try writer.writeByte('}'); |
| ... | ... | @@ -2085,6 +2203,103 @@ pub const DeclGen = struct { |
| 2085 | 2203 | }); |
| 2086 | 2204 | } |
| 2087 | 2205 | |
| 2206 | const IntCastContext = union(enum) { | |
| 2207 | c_value: struct { | |
| 2208 | f: *Function, | |
| 2209 | value: CValue, | |
| 2210 | }, | |
| 2211 | value: struct { | |
| 2212 | value: Value, | |
| 2213 | }, | |
| 2214 | ||
| 2215 | pub fn writeValue(self: *const IntCastContext, dg: *DeclGen, w: anytype, value_ty: Type, location: ValueRenderLocation) !void { | |
| 2216 | switch (self.*) { | |
| 2217 | .c_value => |v| { | |
| 2218 | try v.f.writeCValue(w, v.value, location); | |
| 2219 | }, | |
| 2220 | .value => |v| { | |
| 2221 | try dg.renderValue(w, value_ty, v.value, location); | |
| 2222 | }, | |
| 2223 | } | |
| 2224 | } | |
| 2225 | }; | |
| 2226 | ||
| 2227 | /// Renders a cast to an int type, from either an int or a pointer. | |
| 2228 | /// | |
| 2229 | /// Some platforms don't have 128 bit integers, so we need to use | |
| 2230 | /// the zig_as_ and zig_lo_ macros in those cases. | |
| 2231 | /// | |
| 2232 | /// | Dest type bits | Src type | Result | |
| 2233 | /// |------------------|------------------|---------------------------| | |
| 2234 | /// | < 64 bit integer | pointer | (zig_<dest_ty>)(zig_<u|i>size)src | |
| 2235 | /// | < 64 bit integer | < 64 bit integer | (zig_<dest_ty>)src | |
| 2236 | /// | < 64 bit integer | > 64 bit integer | zig_lo(src) | |
| 2237 | /// | > 64 bit integer | pointer | zig_as_<dest_ty>(0, (zig_<u|i>size)src) | |
| 2238 | /// | > 64 bit integer | < 64 bit integer | zig_as_<dest_ty>(0, src) | |
| 2239 | /// | > 64 bit integer | > 64 bit integer | zig_as_<dest_ty>(zig_hi_<src_ty>(src), zig_lo_<src_ty>(src)) | |
| 2240 | fn renderIntCast(dg: *DeclGen, w: anytype, dest_ty: Type, context: IntCastContext, src_ty: Type, location: ValueRenderLocation) !void { | |
| 2241 | const target = dg.module.getTarget(); | |
| 2242 | const dest_bits = dest_ty.bitSize(target); | |
| 2243 | const dest_int_info = dest_ty.intInfo(target); | |
| 2244 | ||
| 2245 | const src_is_ptr = src_ty.isPtrAtRuntime(); | |
| 2246 | const src_eff_ty: Type = if (src_is_ptr) switch (dest_int_info.signedness) { | |
| 2247 | .unsigned => Type.usize, | |
| 2248 | .signed => Type.isize, | |
| 2249 | } else src_ty; | |
| 2250 | ||
| 2251 | const src_bits = src_eff_ty.bitSize(target); | |
| 2252 | const src_int_info = if (src_eff_ty.isAbiInt()) src_eff_ty.intInfo(target) else null; | |
| 2253 | if (dest_bits <= 64 and src_bits <= 64) { | |
| 2254 | const needs_cast = src_int_info == null or | |
| 2255 | (toCIntBits(dest_int_info.bits) != toCIntBits(src_int_info.?.bits) or | |
| 2256 | dest_int_info.signedness != src_int_info.?.signedness); | |
| 2257 | ||
| 2258 | if (needs_cast) { | |
| 2259 | try w.writeByte('('); | |
| 2260 | try dg.renderTypecast(w, dest_ty); | |
| 2261 | try w.writeByte(')'); | |
| 2262 | } | |
| 2263 | if (src_is_ptr) { | |
| 2264 | try w.writeByte('('); | |
| 2265 | try dg.renderTypecast(w, src_eff_ty); | |
| 2266 | try w.writeByte(')'); | |
| 2267 | } | |
| 2268 | try context.writeValue(dg, w, src_ty, location); | |
| 2269 | } else if (dest_bits <= 64 and src_bits > 64) { | |
| 2270 | assert(!src_is_ptr); | |
| 2271 | try w.writeAll("zig_lo_"); | |
| 2272 | try dg.renderTypeForBuiltinFnName(w, src_eff_ty); | |
| 2273 | try w.writeByte('('); | |
| 2274 | try context.writeValue(dg, w, src_ty, .FunctionArgument); | |
| 2275 | try w.writeByte(')'); | |
| 2276 | } else if (dest_bits > 64 and src_bits <= 64) { | |
| 2277 | try w.writeAll("zig_as_"); | |
| 2278 | try dg.renderTypeForBuiltinFnName(w, dest_ty); | |
| 2279 | try w.writeAll("(0, "); // TODO: Should the 0 go through fmtIntLiteral? | |
| 2280 | if (src_is_ptr) { | |
| 2281 | try w.writeByte('('); | |
| 2282 | try dg.renderTypecast(w, src_eff_ty); | |
| 2283 | try w.writeByte(')'); | |
| 2284 | } | |
| 2285 | try context.writeValue(dg, w, src_ty, .FunctionArgument); | |
| 2286 | try w.writeByte(')'); | |
| 2287 | } else { | |
| 2288 | assert(!src_is_ptr); | |
| 2289 | try w.writeAll("zig_as_"); | |
| 2290 | try dg.renderTypeForBuiltinFnName(w, dest_ty); | |
| 2291 | try w.writeAll("(zig_hi_"); | |
| 2292 | try dg.renderTypeForBuiltinFnName(w, src_eff_ty); | |
| 2293 | try w.writeByte('('); | |
| 2294 | try context.writeValue(dg, w, src_ty, .FunctionArgument); | |
| 2295 | try w.writeAll("), zig_lo_"); | |
| 2296 | try dg.renderTypeForBuiltinFnName(w, src_eff_ty); | |
| 2297 | try w.writeByte('('); | |
| 2298 | try context.writeValue(dg, w, src_ty, .FunctionArgument); | |
| 2299 | try w.writeAll("))"); | |
| 2300 | } | |
| 2301 | } | |
| 2302 | ||
| 2088 | 2303 | /// Renders a type in C typecast format. |
| 2089 | 2304 | /// |
| 2090 | 2305 | /// This is guaranteed to be valid in a typecast expression, but not |
| ... | ... | @@ -2134,7 +2349,7 @@ pub const DeclGen = struct { |
| 2134 | 2349 | const c_len_val = Value.initPayload(&c_len_pl.base); |
| 2135 | 2350 | |
| 2136 | 2351 | try suffix_writer.writeByte('['); |
| 2137 | if (mutability == .ConstArgument and depth == 0) try suffix_writer.writeAll("static const "); | |
| 2352 | if (mutability == .ConstArgument and depth == 0) try suffix_writer.writeAll("zig_const_arr "); | |
| 2138 | 2353 | try suffix.writer().print("{}]", .{try dg.fmtIntLiteral(Type.usize, c_len_val)}); |
| 2139 | 2354 | render_ty = array_info.elem_type; |
| 2140 | 2355 | depth += 1; |
| ... | ... | @@ -2306,6 +2521,9 @@ pub const DeclGen = struct { |
| 2306 | 2521 | try dg.writeCValue(writer, member); |
| 2307 | 2522 | } |
| 2308 | 2523 | |
| 2524 | const IdentHasher = std.crypto.auth.siphash.SipHash128(1, 3); | |
| 2525 | const ident_hasher_init: IdentHasher = IdentHasher.init(&[_]u8{0} ** IdentHasher.key_length); | |
| 2526 | ||
| 2309 | 2527 | fn renderDeclName(dg: *DeclGen, writer: anytype, decl_index: Decl.Index, export_index: u32) !void { |
| 2310 | 2528 | const decl = dg.module.declPtr(decl_index); |
| 2311 | 2529 | dg.module.markDeclAlive(decl); |
| ... | ... | @@ -2323,7 +2541,18 @@ pub const DeclGen = struct { |
| 2323 | 2541 | const gpa = dg.gpa; |
| 2324 | 2542 | const name = try decl.getFullyQualifiedName(dg.module); |
| 2325 | 2543 | defer gpa.free(name); |
| 2326 | return writer.print("{}", .{fmtIdent(name)}); | |
| 2544 | ||
| 2545 | // MSVC has a limit of 4095 character token length limit, and fmtIdent can (worst case), expand | |
| 2546 | // to 3x the length of its input | |
| 2547 | if (name.len > 1365) { | |
| 2548 | var hash = ident_hasher_init; | |
| 2549 | hash.update(name); | |
| 2550 | const ident_hash = hash.finalInt(); | |
| 2551 | try writer.writeAll("zig_D_"); | |
| 2552 | return std.fmt.formatIntValue(ident_hash, "x", .{}, writer); | |
| 2553 | } else { | |
| 2554 | return writer.print("{}", .{fmtIdent(name)}); | |
| 2555 | } | |
| 2327 | 2556 | } |
| 2328 | 2557 | } |
| 2329 | 2558 | |
| ... | ... | @@ -2336,6 +2565,10 @@ pub const DeclGen = struct { |
| 2336 | 2565 | try writer.print("{c}{d}", .{ signAbbrev(int_info.signedness), c_bits }); |
| 2337 | 2566 | } else if (ty.isRuntimeFloat()) { |
| 2338 | 2567 | try ty.print(writer, dg.module); |
| 2568 | } else if (ty.isPtrAtRuntime()) { | |
| 2569 | try writer.print("p{d}", .{ty.bitSize(target)}); | |
| 2570 | } else if (ty.zigTypeTag() == .Bool) { | |
| 2571 | try writer.print("u8", .{}); | |
| 2339 | 2572 | } else return dg.fail("TODO: CBE: implement renderTypeForBuiltinFnName for type {}", .{ |
| 2340 | 2573 | ty.fmt(dg.module), |
| 2341 | 2574 | }); |
| ... | ... | @@ -2388,6 +2621,19 @@ pub const DeclGen = struct { |
| 2388 | 2621 | .mod = dg.module, |
| 2389 | 2622 | } }; |
| 2390 | 2623 | } |
| 2624 | ||
| 2625 | fn fmtIntLiteralLoc( | |
| 2626 | dg: *DeclGen, | |
| 2627 | ty: Type, | |
| 2628 | val: Value, | |
| 2629 | location: ValueRenderLocation, // TODO: Instead add this as optional arg to fmtIntLiteral | |
| 2630 | ) !std.fmt.Formatter(formatIntLiteral) { | |
| 2631 | const int_info = ty.intInfo(dg.module.getTarget()); | |
| 2632 | const c_bits = toCIntBits(int_info.bits); | |
| 2633 | if (c_bits == null or c_bits.? > 128) | |
| 2634 | return dg.fail("TODO implement integer constants larger than 128 bits", .{}); | |
| 2635 | return std.fmt.Formatter(formatIntLiteral){ .data = .{ .ty = ty, .val = val, .mod = dg.module, .location = location } }; | |
| 2636 | } | |
| 2391 | 2637 | }; |
| 2392 | 2638 | |
| 2393 | 2639 | pub fn genGlobalAsm(mod: *Module, code: *std.ArrayList(u8)) !void { |
| ... | ... | @@ -2433,7 +2679,7 @@ pub fn genErrDecls(o: *Object) !void { |
| 2433 | 2679 | try writer.writeAll("static "); |
| 2434 | 2680 | try o.dg.renderTypeAndName(writer, name_ty, .{ .identifier = identifier }, .Const, 0, .Complete); |
| 2435 | 2681 | try writer.writeAll(" = "); |
| 2436 | try o.dg.renderValue(writer, name_ty, name_val, .Initializer); | |
| 2682 | try o.dg.renderValue(writer, name_ty, name_val, .StaticInitializer); | |
| 2437 | 2683 | try writer.writeAll(";\n"); |
| 2438 | 2684 | } |
| 2439 | 2685 | |
| ... | ... | @@ -2604,7 +2850,7 @@ pub fn genDecl(o: *Object) !void { |
| 2604 | 2850 | if (variable.is_threadlocal) try w.writeAll("zig_threadlocal "); |
| 2605 | 2851 | try o.dg.renderTypeAndName(w, o.dg.decl.ty, decl_c_value, .Mut, o.dg.decl.@"align", .Complete); |
| 2606 | 2852 | try w.writeAll(" = "); |
| 2607 | try o.dg.renderValue(w, tv.ty, variable.init, .Initializer); | |
| 2853 | try o.dg.renderValue(w, tv.ty, variable.init, .StaticInitializer); | |
| 2608 | 2854 | try w.writeByte(';'); |
| 2609 | 2855 | try o.indent_writer.insertNewline(); |
| 2610 | 2856 | } else { |
| ... | ... | @@ -2621,7 +2867,7 @@ pub fn genDecl(o: *Object) !void { |
| 2621 | 2867 | // https://github.com/ziglang/zig/issues/7582 |
| 2622 | 2868 | try o.dg.renderTypeAndName(writer, tv.ty, decl_c_value, .Mut, o.dg.decl.@"align", .Complete); |
| 2623 | 2869 | try writer.writeAll(" = "); |
| 2624 | try o.dg.renderValue(writer, tv.ty, tv.val, .Initializer); | |
| 2870 | try o.dg.renderValue(writer, tv.ty, tv.val, .StaticInitializer); | |
| 2625 | 2871 | try writer.writeAll(";\n"); |
| 2626 | 2872 | } |
| 2627 | 2873 | } |
| ... | ... | @@ -3244,11 +3490,20 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3244 | 3490 | try f.object.dg.renderTypeForBuiltinFnName(writer, field_ty); |
| 3245 | 3491 | try writer.writeAll("(("); |
| 3246 | 3492 | try f.renderTypecast(writer, field_ty); |
| 3247 | try writer.writeAll(")zig_shr_"); | |
| 3493 | try writer.writeByte(')'); | |
| 3494 | const cant_cast = host_ty.isInt() and host_ty.bitSize(target) > 64; | |
| 3495 | if (cant_cast) { | |
| 3496 | if (field_ty.bitSize(target) > 64) return f.fail("TODO: C backend: implement casting between types > 64 bits", .{}); | |
| 3497 | try writer.writeAll("zig_lo_"); | |
| 3498 | try f.object.dg.renderTypeForBuiltinFnName(writer, host_ty); | |
| 3499 | try writer.writeByte('('); | |
| 3500 | } | |
| 3501 | try writer.writeAll("zig_shr_"); | |
| 3248 | 3502 | try f.object.dg.renderTypeForBuiltinFnName(writer, host_ty); |
| 3249 | 3503 | try writer.writeByte('('); |
| 3250 | 3504 | try f.writeCValueDeref(writer, operand); |
| 3251 | 3505 | try writer.print(", {})", .{try f.fmtIntLiteral(bit_offset_ty, bit_offset_val)}); |
| 3506 | if (cant_cast) try writer.writeByte(')'); | |
| 3252 | 3507 | try f.object.dg.renderBuiltinInfo(writer, field_ty, .Bits); |
| 3253 | 3508 | try writer.writeByte(')'); |
| 3254 | 3509 | } else { |
| ... | ... | @@ -3322,11 +3577,11 @@ fn airIntCast(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3322 | 3577 | const writer = f.object.writer(); |
| 3323 | 3578 | const inst_ty = f.air.typeOfIndex(inst); |
| 3324 | 3579 | const local = try f.allocLocal(inst, inst_ty); |
| 3580 | const operand_ty = f.air.typeOf(ty_op.operand); | |
| 3581 | ||
| 3325 | 3582 | try f.writeCValue(writer, local, .Other); |
| 3326 | try writer.writeAll(" = ("); | |
| 3327 | try f.renderTypecast(writer, inst_ty); | |
| 3328 | try writer.writeByte(')'); | |
| 3329 | try f.writeCValue(writer, operand, .Other); | |
| 3583 | try writer.writeAll(" = "); | |
| 3584 | try f.renderIntCast(writer, inst_ty, operand, operand_ty, .Other); | |
| 3330 | 3585 | try writer.writeAll(";\n"); |
| 3331 | 3586 | return local; |
| 3332 | 3587 | } |
| ... | ... | @@ -3346,15 +3601,27 @@ fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3346 | 3601 | const target = f.object.dg.module.getTarget(); |
| 3347 | 3602 | const dest_int_info = inst_ty.intInfo(target); |
| 3348 | 3603 | const dest_bits = dest_int_info.bits; |
| 3604 | const dest_c_bits = toCIntBits(dest_int_info.bits) orelse | |
| 3605 | return f.fail("TODO: C backend: implement integer types larger than 128 bits", .{}); | |
| 3606 | const operand_ty = f.air.typeOf(ty_op.operand); | |
| 3607 | const operand_int_info = operand_ty.intInfo(target); | |
| 3349 | 3608 | |
| 3350 | 3609 | try f.writeCValue(writer, local, .Other); |
| 3351 | try writer.writeAll(" = ("); | |
| 3352 | try f.renderTypecast(writer, inst_ty); | |
| 3353 | try writer.writeByte(')'); | |
| 3610 | try writer.writeAll(" = "); | |
| 3611 | ||
| 3612 | const needs_lo = operand_int_info.bits > 64 and dest_bits <= 64; | |
| 3613 | if (needs_lo) { | |
| 3614 | try writer.writeAll("zig_lo_"); | |
| 3615 | try f.object.dg.renderTypeForBuiltinFnName(writer, operand_ty); | |
| 3616 | try writer.writeByte('('); | |
| 3617 | } else if (dest_c_bits <= 64) { | |
| 3618 | try writer.writeByte('('); | |
| 3619 | try f.renderTypecast(writer, inst_ty); | |
| 3620 | try writer.writeByte(')'); | |
| 3621 | } | |
| 3354 | 3622 | |
| 3355 | 3623 | if (dest_bits >= 8 and std.math.isPowerOfTwo(dest_bits)) { |
| 3356 | 3624 | try f.writeCValue(writer, operand, .Other); |
| 3357 | try writer.writeAll(";\n"); | |
| 3358 | 3625 | } else switch (dest_int_info.signedness) { |
| 3359 | 3626 | .unsigned => { |
| 3360 | 3627 | var arena = std.heap.ArenaAllocator.init(f.object.dg.gpa); |
| ... | ... | @@ -3365,14 +3632,14 @@ fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3365 | 3632 | std.heap.stackFallback(@sizeOf(ExpectedContents), arena.allocator()); |
| 3366 | 3633 | |
| 3367 | 3634 | const mask_val = try inst_ty.maxInt(stack.get(), target); |
| 3368 | ||
| 3635 | try writer.writeAll("zig_and_"); | |
| 3636 | try f.object.dg.renderTypeForBuiltinFnName(writer, operand_ty); | |
| 3369 | 3637 | try writer.writeByte('('); |
| 3370 | try f.writeCValue(writer, operand, .Other); | |
| 3371 | try writer.print(" & {x});\n", .{try f.fmtIntLiteral(inst_ty, mask_val)}); | |
| 3638 | try f.writeCValue(writer, operand, .FunctionArgument); | |
| 3639 | try writer.print(", {x})", .{try f.fmtIntLiteral(operand_ty, mask_val)}); | |
| 3372 | 3640 | }, |
| 3373 | 3641 | .signed => { |
| 3374 | const operand_ty = f.air.typeOf(ty_op.operand); | |
| 3375 | const c_bits = toCIntBits(operand_ty.intInfo(target).bits) orelse | |
| 3642 | const c_bits = toCIntBits(operand_int_info.bits) orelse | |
| 3376 | 3643 | return f.fail("TODO: C backend: implement integer types larger than 128 bits", .{}); |
| 3377 | 3644 | var shift_pl = Value.Payload.U64{ |
| 3378 | 3645 | .base = .{ .tag = .int_u64 }, |
| ... | ... | @@ -3380,11 +3647,29 @@ fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3380 | 3647 | }; |
| 3381 | 3648 | const shift_val = Value.initPayload(&shift_pl.base); |
| 3382 | 3649 | |
| 3383 | try writer.print("((int{d}_t)((uint{0d}_t)", .{c_bits}); | |
| 3384 | try f.writeCValue(writer, operand, .Other); | |
| 3385 | try writer.print(" << {}) >> {0});\n", .{try f.fmtIntLiteral(Type.u8, shift_val)}); | |
| 3650 | try writer.writeAll("zig_shr_"); | |
| 3651 | try f.object.dg.renderTypeForBuiltinFnName(writer, operand_ty); | |
| 3652 | if (c_bits == 128) { | |
| 3653 | try writer.print("(zig_bitcast_i{d}(", .{c_bits}); | |
| 3654 | } else { | |
| 3655 | try writer.print("((int{d}_t)", .{c_bits}); | |
| 3656 | } | |
| 3657 | try writer.print("zig_shl_u{d}(", .{c_bits}); | |
| 3658 | if (c_bits == 128) { | |
| 3659 | try writer.print("zig_bitcast_u{d}(", .{c_bits}); | |
| 3660 | } else { | |
| 3661 | try writer.print("(uint{d}_t)", .{c_bits}); | |
| 3662 | } | |
| 3663 | try f.writeCValue(writer, operand, .FunctionArgument); | |
| 3664 | if (c_bits == 128) try writer.writeByte(')'); | |
| 3665 | try writer.print(", {})", .{try f.fmtIntLiteral(Type.u8, shift_val)}); | |
| 3666 | if (c_bits == 128) try writer.writeByte(')'); | |
| 3667 | try writer.print(", {})", .{try f.fmtIntLiteral(Type.u8, shift_val)}); | |
| 3386 | 3668 | }, |
| 3387 | 3669 | } |
| 3670 | ||
| 3671 | if (needs_lo) try writer.writeByte(')'); | |
| 3672 | try writer.writeAll(";\n"); | |
| 3388 | 3673 | return local; |
| 3389 | 3674 | } |
| 3390 | 3675 | |
| ... | ... | @@ -3521,15 +3806,26 @@ fn airStore(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3521 | 3806 | try f.writeCValueDeref(writer, ptr_val); |
| 3522 | 3807 | try writer.print(", {x}), zig_shl_", .{try f.fmtIntLiteral(host_ty, mask_val)}); |
| 3523 | 3808 | try f.object.dg.renderTypeForBuiltinFnName(writer, host_ty); |
| 3524 | try writer.writeAll("(("); | |
| 3525 | try f.renderTypecast(writer, host_ty); | |
| 3526 | try writer.writeByte(')'); | |
| 3809 | try writer.writeByte('('); | |
| 3810 | const cant_cast = host_ty.isInt() and host_ty.bitSize(target) > 64; | |
| 3811 | if (cant_cast) { | |
| 3812 | if (src_ty.bitSize(target) > 64) return f.fail("TODO: C backend: implement casting between types > 64 bits", .{}); | |
| 3813 | try writer.writeAll("zig_as_"); | |
| 3814 | try f.object.dg.renderTypeForBuiltinFnName(writer, host_ty); | |
| 3815 | try writer.writeAll("(0, "); | |
| 3816 | } else { | |
| 3817 | try writer.writeByte('('); | |
| 3818 | try f.renderTypecast(writer, host_ty); | |
| 3819 | try writer.writeByte(')'); | |
| 3820 | } | |
| 3821 | ||
| 3527 | 3822 | if (src_ty.isPtrAtRuntime()) { |
| 3528 | 3823 | try writer.writeByte('('); |
| 3529 | 3824 | try f.renderTypecast(writer, Type.usize); |
| 3530 | 3825 | try writer.writeByte(')'); |
| 3531 | 3826 | } |
| 3532 | 3827 | try f.writeCValue(writer, src_val, .Other); |
| 3828 | if (cant_cast) try writer.writeByte(')'); | |
| 3533 | 3829 | try writer.print(", {}))", .{try f.fmtIntLiteral(bit_offset_ty, bit_offset_val)}); |
| 3534 | 3830 | } else { |
| 3535 | 3831 | try f.writeCValueDeref(writer, ptr_val); |
| ... | ... | @@ -3610,12 +3906,12 @@ fn airNot(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3610 | 3906 | |
| 3611 | 3907 | const writer = f.object.writer(); |
| 3612 | 3908 | const local = try f.allocLocal(inst, inst_ty); |
| 3909 | ||
| 3613 | 3910 | try f.writeCValue(writer, local, .Other); |
| 3614 | 3911 | try writer.writeAll(" = "); |
| 3615 | 3912 | try writer.writeByte('!'); |
| 3616 | 3913 | try f.writeCValue(writer, op, .Other); |
| 3617 | 3914 | try writer.writeAll(";\n"); |
| 3618 | ||
| 3619 | 3915 | return local; |
| 3620 | 3916 | } |
| 3621 | 3917 | |
| ... | ... | @@ -4382,7 +4678,15 @@ fn airCondBr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4382 | 4678 | try f.writeCValue(writer, cond, .Other); |
| 4383 | 4679 | try writer.writeAll(") "); |
| 4384 | 4680 | try genBody(f, then_body); |
| 4385 | try writer.writeAll(" else "); | |
| 4681 | ||
| 4682 | // TODO: If body ends in goto, elide the else block? | |
| 4683 | const needs_else = then_body.len <= 0 or f.air.instructions.items(.tag)[then_body[then_body.len - 1]] != .br; | |
| 4684 | if (needs_else) { | |
| 4685 | try writer.writeAll(" else "); | |
| 4686 | } else { | |
| 4687 | try writer.writeByte('\n'); | |
| 4688 | } | |
| 4689 | ||
| 4386 | 4690 | f.value_map.deinit(); |
| 4387 | 4691 | f.value_map = cloned_map.move(); |
| 4388 | 4692 | const free_locals = f.getFreeLocals(); |
| ... | ... | @@ -4395,7 +4699,12 @@ fn airCondBr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4395 | 4699 | |
| 4396 | 4700 | try noticeBranchFrees(f, pre_locals_len, inst); |
| 4397 | 4701 | |
| 4398 | try genBody(f, else_body); | |
| 4702 | if (needs_else) { | |
| 4703 | try genBody(f, else_body); | |
| 4704 | } else { | |
| 4705 | try genBodyInner(f, else_body); | |
| 4706 | } | |
| 4707 | ||
| 4399 | 4708 | try f.object.indent_writer.insertNewline(); |
| 4400 | 4709 | |
| 4401 | 4710 | return CValue.none; |
| ... | ... | @@ -5218,13 +5527,22 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5218 | 5527 | try f.object.dg.renderTypeForBuiltinFnName(writer, field_int_ty); |
| 5219 | 5528 | try writer.writeAll("(("); |
| 5220 | 5529 | try f.renderTypecast(writer, field_int_ty); |
| 5221 | try writer.writeAll(")zig_shr_"); | |
| 5530 | try writer.writeByte(')'); | |
| 5531 | const cant_cast = int_info.bits > 64; | |
| 5532 | if (cant_cast) { | |
| 5533 | if (field_int_ty.bitSize(target) > 64) return f.fail("TODO: C backend: implement casting between types > 64 bits", .{}); | |
| 5534 | try writer.writeAll("zig_lo_"); | |
| 5535 | try f.object.dg.renderTypeForBuiltinFnName(writer, struct_ty); | |
| 5536 | try writer.writeByte('('); | |
| 5537 | } | |
| 5538 | try writer.writeAll("zig_shr_"); | |
| 5222 | 5539 | try f.object.dg.renderTypeForBuiltinFnName(writer, struct_ty); |
| 5223 | 5540 | try writer.writeByte('('); |
| 5224 | 5541 | try f.writeCValue(writer, struct_byval, .Other); |
| 5225 | 5542 | try writer.writeAll(", "); |
| 5226 | 5543 | try f.object.dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument); |
| 5227 | 5544 | try writer.writeByte(')'); |
| 5545 | if (cant_cast) try writer.writeByte(')'); | |
| 5228 | 5546 | try f.object.dg.renderBuiltinInfo(writer, field_int_ty, .Bits); |
| 5229 | 5547 | try writer.writeAll(");\n"); |
| 5230 | 5548 | if (inst_ty.eql(field_int_ty, f.object.dg.module)) return temp_local; |
| ... | ... | @@ -5812,7 +6130,7 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue |
| 5812 | 6130 | try writer.writeAll(";\n"); |
| 5813 | 6131 | try writer.writeAll("if ("); |
| 5814 | 6132 | try writer.print("zig_cmpxchg_{s}((zig_atomic(", .{flavor}); |
| 5815 | try f.renderTypecast(writer, ptr_ty.elemType()); | |
| 6133 | try f.renderTypecast(writer, ptr_ty.childType()); | |
| 5816 | 6134 | try writer.writeByte(')'); |
| 5817 | 6135 | if (ptr_ty.isVolatilePtr()) try writer.writeAll(" volatile"); |
| 5818 | 6136 | try writer.writeAll(" *)"); |
| ... | ... | @@ -5825,6 +6143,8 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue |
| 5825 | 6143 | try writeMemoryOrder(writer, extra.successOrder()); |
| 5826 | 6144 | try writer.writeAll(", "); |
| 5827 | 6145 | try writeMemoryOrder(writer, extra.failureOrder()); |
| 6146 | try writer.writeAll(", "); | |
| 6147 | try f.object.dg.renderTypeForBuiltinFnName(writer, ptr_ty.childType()); | |
| 5828 | 6148 | try writer.writeByte(')'); |
| 5829 | 6149 | try writer.writeAll(") {\n"); |
| 5830 | 6150 | f.object.indent_writer.pushIndent(); |
| ... | ... | @@ -5839,7 +6159,7 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue |
| 5839 | 6159 | try writer.writeAll(";\n"); |
| 5840 | 6160 | try f.writeCValue(writer, local, .Other); |
| 5841 | 6161 | try writer.print(".is_null = zig_cmpxchg_{s}((zig_atomic(", .{flavor}); |
| 5842 | try f.renderTypecast(writer, ptr_ty.elemType()); | |
| 6162 | try f.renderTypecast(writer, ptr_ty.childType()); | |
| 5843 | 6163 | try writer.writeByte(')'); |
| 5844 | 6164 | if (ptr_ty.isVolatilePtr()) try writer.writeAll(" volatile"); |
| 5845 | 6165 | try writer.writeAll(" *)"); |
| ... | ... | @@ -5852,6 +6172,8 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue |
| 5852 | 6172 | try writeMemoryOrder(writer, extra.successOrder()); |
| 5853 | 6173 | try writer.writeAll(", "); |
| 5854 | 6174 | try writeMemoryOrder(writer, extra.failureOrder()); |
| 6175 | try writer.writeAll(", "); | |
| 6176 | try f.object.dg.renderTypeForBuiltinFnName(writer, ptr_ty.childType()); | |
| 5855 | 6177 | try writer.writeByte(')'); |
| 5856 | 6178 | try writer.writeAll(";\n"); |
| 5857 | 6179 | } |
| ... | ... | @@ -5874,8 +6196,8 @@ fn airAtomicRmw(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5874 | 6196 | try reap(f, inst, &.{ pl_op.operand, extra.operand }); |
| 5875 | 6197 | const writer = f.object.writer(); |
| 5876 | 6198 | const local = try f.allocLocal(inst, inst_ty); |
| 5877 | try f.writeCValue(writer, local, .Other); | |
| 5878 | 6199 | |
| 6200 | try f.writeCValue(writer, local, .Other); | |
| 5879 | 6201 | try writer.print(" = zig_atomicrmw_{s}((", .{toAtomicRmwSuffix(extra.op())}); |
| 5880 | 6202 | switch (extra.op()) { |
| 5881 | 6203 | else => { |
| ... | ... | @@ -5895,6 +6217,8 @@ fn airAtomicRmw(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5895 | 6217 | try f.writeCValue(writer, operand, .FunctionArgument); |
| 5896 | 6218 | try writer.writeAll(", "); |
| 5897 | 6219 | try writeMemoryOrder(writer, extra.ordering()); |
| 6220 | try writer.writeAll(", "); | |
| 6221 | try f.object.dg.renderTypeForBuiltinFnName(writer, ptr_ty.childType()); | |
| 5898 | 6222 | try writer.writeAll(");\n"); |
| 5899 | 6223 | |
| 5900 | 6224 | if (f.liveness.isUnused(inst)) { |
| ... | ... | @@ -5927,6 +6251,8 @@ fn airAtomicLoad(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5927 | 6251 | try f.writeCValue(writer, ptr, .Other); |
| 5928 | 6252 | try writer.writeAll(", "); |
| 5929 | 6253 | try writeMemoryOrder(writer, atomic_load.order); |
| 6254 | try writer.writeAll(", "); | |
| 6255 | try f.object.dg.renderTypeForBuiltinFnName(writer, ptr_ty.childType()); | |
| 5930 | 6256 | try writer.writeAll(");\n"); |
| 5931 | 6257 | |
| 5932 | 6258 | return local; |
| ... | ... | @@ -5948,7 +6274,9 @@ fn airAtomicStore(f: *Function, inst: Air.Inst.Index, order: [*:0]const u8) !CVa |
| 5948 | 6274 | try f.writeCValue(writer, ptr, .Other); |
| 5949 | 6275 | try writer.writeAll(", "); |
| 5950 | 6276 | try f.writeCValue(writer, element, .FunctionArgument); |
| 5951 | try writer.print(", {s});\n", .{order}); | |
| 6277 | try writer.print(", {s}, ", .{order}); | |
| 6278 | try f.object.dg.renderTypeForBuiltinFnName(writer, ptr_ty.childType()); | |
| 6279 | try writer.writeAll(");\n"); | |
| 5952 | 6280 | |
| 5953 | 6281 | return CValue.none; |
| 5954 | 6282 | } |
| ... | ... | @@ -6405,9 +6733,7 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6405 | 6733 | }, |
| 6406 | 6734 | .Packed => { |
| 6407 | 6735 | try f.writeCValue(writer, local, .Other); |
| 6408 | try writer.writeAll(" = ("); | |
| 6409 | try f.renderTypecast(writer, inst_ty); | |
| 6410 | try writer.writeAll(")"); | |
| 6736 | try writer.writeAll(" = "); | |
| 6411 | 6737 | const int_info = inst_ty.intInfo(target); |
| 6412 | 6738 | |
| 6413 | 6739 | var bit_offset_ty_pl = Type.Payload.Bits{ |
| ... | ... | @@ -6437,20 +6763,28 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6437 | 6763 | if (!field_ty.hasRuntimeBitsIgnoreComptime()) continue; |
| 6438 | 6764 | |
| 6439 | 6765 | if (!empty) try writer.writeAll(", "); |
| 6766 | // TODO: Skip this entire shift if val is 0? | |
| 6440 | 6767 | try writer.writeAll("zig_shlw_"); |
| 6441 | 6768 | try f.object.dg.renderTypeForBuiltinFnName(writer, inst_ty); |
| 6442 | try writer.writeAll("(("); | |
| 6443 | try f.renderTypecast(writer, inst_ty); | |
| 6444 | try writer.writeByte(')'); | |
| 6445 | if (field_ty.isPtrAtRuntime()) { | |
| 6769 | try writer.writeByte('('); | |
| 6770 | ||
| 6771 | if (inst_ty.isAbiInt() and (field_ty.isAbiInt() or field_ty.isPtrAtRuntime())) { | |
| 6772 | try f.renderIntCast(writer, inst_ty, element, field_ty, .FunctionArgument); | |
| 6773 | } else { | |
| 6446 | 6774 | try writer.writeByte('('); |
| 6447 | try f.renderTypecast(writer, switch (int_info.signedness) { | |
| 6448 | .unsigned => Type.usize, | |
| 6449 | .signed => Type.isize, | |
| 6450 | }); | |
| 6775 | try f.renderTypecast(writer, inst_ty); | |
| 6451 | 6776 | try writer.writeByte(')'); |
| 6777 | if (field_ty.isPtrAtRuntime()) { | |
| 6778 | try writer.writeByte('('); | |
| 6779 | try f.renderTypecast(writer, switch (int_info.signedness) { | |
| 6780 | .unsigned => Type.usize, | |
| 6781 | .signed => Type.isize, | |
| 6782 | }); | |
| 6783 | try writer.writeByte(')'); | |
| 6784 | } | |
| 6785 | try f.writeCValue(writer, element, .Other); | |
| 6452 | 6786 | } |
| 6453 | try f.writeCValue(writer, element, .Other); | |
| 6787 | ||
| 6454 | 6788 | try writer.writeAll(", "); |
| 6455 | 6789 | try f.object.dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument); |
| 6456 | 6790 | try f.object.dg.renderBuiltinInfo(writer, inst_ty, .Bits); |
| ... | ... | @@ -6460,7 +6794,14 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6460 | 6794 | bit_offset_val_pl.data += field_ty.bitSize(target); |
| 6461 | 6795 | empty = false; |
| 6462 | 6796 | } |
| 6463 | if (empty) try f.writeCValue(writer, .{ .undef = inst_ty }, .Initializer); | |
| 6797 | ||
| 6798 | if (empty) { | |
| 6799 | try writer.writeByte('('); | |
| 6800 | try f.renderTypecast(writer, inst_ty); | |
| 6801 | try writer.writeByte(')'); | |
| 6802 | try f.writeCValue(writer, .{ .undef = inst_ty }, .Initializer); | |
| 6803 | } | |
| 6804 | ||
| 6464 | 6805 | try writer.writeAll(";\n"); |
| 6465 | 6806 | }, |
| 6466 | 6807 | }, |
| ... | ... | @@ -6793,6 +7134,68 @@ fn compilerRtAbbrev(ty: Type, target: std.Target) []const u8 { |
| 6793 | 7134 | } else unreachable; |
| 6794 | 7135 | } |
| 6795 | 7136 | |
| 7137 | fn StringLiteral(comptime WriterType: type) type { | |
| 7138 | // MSVC has a length limit of 16380 per string literal (before concatenation) | |
| 7139 | const max_char_len = 4; | |
| 7140 | const max_len = 16380 - max_char_len; | |
| 7141 | ||
| 7142 | return struct { | |
| 7143 | cur_len: u64 = 0, | |
| 7144 | counting_writer: std.io.CountingWriter(WriterType), | |
| 7145 | ||
| 7146 | pub const Error = WriterType.Error; | |
| 7147 | ||
| 7148 | const Self = @This(); | |
| 7149 | ||
| 7150 | pub fn start(self: *Self) Error!void { | |
| 7151 | const writer = self.counting_writer.writer(); | |
| 7152 | try writer.writeByte('\"'); | |
| 7153 | } | |
| 7154 | ||
| 7155 | pub fn end(self: *Self) Error!void { | |
| 7156 | const writer = self.counting_writer.writer(); | |
| 7157 | try writer.writeByte('\"'); | |
| 7158 | } | |
| 7159 | ||
| 7160 | fn writeStringLiteralChar(writer: anytype, c: u8) !void { | |
| 7161 | switch (c) { | |
| 7162 | 7 => try writer.writeAll("\\a"), | |
| 7163 | 8 => try writer.writeAll("\\b"), | |
| 7164 | '\t' => try writer.writeAll("\\t"), | |
| 7165 | '\n' => try writer.writeAll("\\n"), | |
| 7166 | 11 => try writer.writeAll("\\v"), | |
| 7167 | 12 => try writer.writeAll("\\f"), | |
| 7168 | '\r' => try writer.writeAll("\\r"), | |
| 7169 | '"', '\'', '?', '\\' => try writer.print("\\{c}", .{c}), | |
| 7170 | else => switch (c) { | |
| 7171 | ' '...'~' => try writer.writeByte(c), | |
| 7172 | else => try writer.print("\\{o:0>3}", .{c}), | |
| 7173 | }, | |
| 7174 | } | |
| 7175 | } | |
| 7176 | ||
| 7177 | pub fn writeChar(self: *Self, c: u8) Error!void { | |
| 7178 | const writer = self.counting_writer.writer(); | |
| 7179 | ||
| 7180 | if (self.cur_len == 0 and self.counting_writer.bytes_written > 1) | |
| 7181 | try writer.writeAll("\"\""); | |
| 7182 | ||
| 7183 | const len = self.counting_writer.bytes_written; | |
| 7184 | try writeStringLiteralChar(writer, c); | |
| 7185 | ||
| 7186 | const char_length = self.counting_writer.bytes_written - len; | |
| 7187 | assert(char_length <= max_char_len); | |
| 7188 | self.cur_len += char_length; | |
| 7189 | ||
| 7190 | if (self.cur_len >= max_len) self.cur_len = 0; | |
| 7191 | } | |
| 7192 | }; | |
| 7193 | } | |
| 7194 | ||
| 7195 | fn stringLiteral(child_stream: anytype) StringLiteral(@TypeOf(child_stream)) { | |
| 7196 | return .{ .counting_writer = std.io.countingWriter(child_stream) }; | |
| 7197 | } | |
| 7198 | ||
| 6796 | 7199 | fn formatStringLiteral( |
| 6797 | 7200 | str: []const u8, |
| 6798 | 7201 | comptime fmt: []const u8, |
| ... | ... | @@ -6800,44 +7203,25 @@ fn formatStringLiteral( |
| 6800 | 7203 | writer: anytype, |
| 6801 | 7204 | ) @TypeOf(writer).Error!void { |
| 6802 | 7205 | if (fmt.len != 1 or fmt[0] != 's') @compileError("Invalid fmt: " ++ fmt); |
| 6803 | try writer.writeByte('\"'); | |
| 7206 | ||
| 7207 | var literal = stringLiteral(writer); | |
| 7208 | try literal.start(); | |
| 6804 | 7209 | for (str) |c| |
| 6805 | try writeStringLiteralChar(writer, c); | |
| 6806 | try writer.writeByte('\"'); | |
| 7210 | try literal.writeChar(c); | |
| 7211 | try literal.end(); | |
| 6807 | 7212 | } |
| 6808 | 7213 | |
| 6809 | 7214 | fn fmtStringLiteral(str: []const u8) std.fmt.Formatter(formatStringLiteral) { |
| 6810 | 7215 | return .{ .data = str }; |
| 6811 | 7216 | } |
| 6812 | 7217 | |
| 6813 | fn writeStringLiteralChar(writer: anytype, c: u8) !void { | |
| 6814 | switch (c) { | |
| 6815 | 7 => try writer.writeAll("\\a"), | |
| 6816 | 8 => try writer.writeAll("\\b"), | |
| 6817 | '\t' => try writer.writeAll("\\t"), | |
| 6818 | '\n' => try writer.writeAll("\\n"), | |
| 6819 | 11 => try writer.writeAll("\\v"), | |
| 6820 | 12 => try writer.writeAll("\\f"), | |
| 6821 | '\r' => try writer.writeAll("\\r"), | |
| 6822 | '"', '\'', '?', '\\' => try writer.print("\\{c}", .{c}), | |
| 6823 | else => switch (c) { | |
| 6824 | ' '...'~' => try writer.writeByte(c), | |
| 6825 | else => try writer.print("\\{o:0>3}", .{c}), | |
| 6826 | }, | |
| 6827 | } | |
| 6828 | } | |
| 6829 | ||
| 6830 | 7218 | fn undefPattern(comptime IntType: type) IntType { |
| 6831 | 7219 | const int_info = @typeInfo(IntType).Int; |
| 6832 | 7220 | const UnsignedType = std.meta.Int(.unsigned, int_info.bits); |
| 6833 | 7221 | return @bitCast(IntType, @as(UnsignedType, (1 << (int_info.bits | 1)) / 3)); |
| 6834 | 7222 | } |
| 6835 | 7223 | |
| 6836 | const FormatIntLiteralContext = struct { | |
| 6837 | ty: Type, | |
| 6838 | val: Value, | |
| 6839 | mod: *Module, | |
| 6840 | }; | |
| 7224 | const FormatIntLiteralContext = struct { ty: Type, val: Value, mod: *Module, location: ?ValueRenderLocation = null }; | |
| 6841 | 7225 | fn formatIntLiteral( |
| 6842 | 7226 | data: FormatIntLiteralContext, |
| 6843 | 7227 | comptime fmt: []const u8, |
| ... | ... | @@ -6905,10 +7289,31 @@ fn formatIntLiteral( |
| 6905 | 7289 | return writer.print("{s}_{s}", .{ abbrev, if (int.positive) "MAX" else "MIN" }); |
| 6906 | 7290 | } |
| 6907 | 7291 | |
| 6908 | if (!int.positive) try writer.writeByte('-'); | |
| 7292 | var use_twos_comp = false; | |
| 7293 | if (!int.positive) { | |
| 7294 | if (c_bits > 64) { | |
| 7295 | // TODO: Can this be done for decimal literals as well? | |
| 7296 | if (fmt.len == 1 and fmt[0] != 'd') { | |
| 7297 | use_twos_comp = true; | |
| 7298 | } else { | |
| 7299 | // TODO: Use fmtIntLiteral for 0? | |
| 7300 | try writer.print("zig_sub_{c}{d}(zig_as_{c}{d}(0, 0), ", .{ signAbbrev(int_info.signedness), c_bits, signAbbrev(int_info.signedness), c_bits }); | |
| 7301 | } | |
| 7302 | } else { | |
| 7303 | try writer.writeByte('-'); | |
| 7304 | } | |
| 7305 | } | |
| 7306 | ||
| 6909 | 7307 | switch (data.ty.tag()) { |
| 6910 | 7308 | .c_short, .c_ushort, .c_int, .c_uint, .c_long, .c_ulong, .c_longlong, .c_ulonglong => {}, |
| 6911 | else => try writer.print("zig_as_{c}{d}(", .{ signAbbrev(int_info.signedness), c_bits }), | |
| 7309 | else => { | |
| 7310 | if (int_info.bits > 64 and data.location != null and data.location.? == .StaticInitializer) { | |
| 7311 | // MSVC treats casting the struct initializer as not constant (C2099), so an alternate form is used in global initializers | |
| 7312 | try writer.print("zig_as_constant_{c}{d}(", .{ signAbbrev(int_info.signedness), c_bits }); | |
| 7313 | } else { | |
| 7314 | try writer.print("zig_as_{c}{d}(", .{ signAbbrev(int_info.signedness), c_bits }); | |
| 7315 | } | |
| 7316 | }, | |
| 6912 | 7317 | } |
| 6913 | 7318 | |
| 6914 | 7319 | const limbs_count_64 = @divExact(64, @bitSizeOf(BigIntLimb)); |
| ... | ... | @@ -6948,16 +7353,34 @@ fn formatIntLiteral( |
| 6948 | 7353 | } else { |
| 6949 | 7354 | assert(c_bits == 128); |
| 6950 | 7355 | const split = std.math.min(int.limbs.len, limbs_count_64); |
| 7356 | var twos_comp_limbs: [BigInt.calcTwosCompLimbCount(128)]BigIntLimb = undefined; | |
| 7357 | ||
| 7358 | // Adding a negation in the C code before the doesn't work in all cases: | |
| 7359 | // - struct versions would require an extra zig_sub_ call to negate, which wouldn't work in constant expressions | |
| 7360 | // - negating the f80 int representation (i128) doesn't make sense | |
| 7361 | // Instead we write out the literal as a negative number in twos complement | |
| 7362 | var limbs = int.limbs; | |
| 7363 | ||
| 7364 | if (use_twos_comp) { | |
| 7365 | var twos_comp = BigInt.Mutable{ | |
| 7366 | .limbs = &twos_comp_limbs, | |
| 7367 | .positive = undefined, | |
| 7368 | .len = undefined, | |
| 7369 | }; | |
| 7370 | ||
| 7371 | twos_comp.convertToTwosComplement(int, .signed, int_info.bits); | |
| 7372 | limbs = twos_comp.limbs; | |
| 7373 | } | |
| 6951 | 7374 | |
| 6952 | 7375 | var upper_pl = Value.Payload.BigInt{ |
| 6953 | 7376 | .base = .{ .tag = .int_big_positive }, |
| 6954 | .data = int.limbs[split..], | |
| 7377 | .data = limbs[split..], | |
| 6955 | 7378 | }; |
| 6956 | 7379 | const upper_val = Value.initPayload(&upper_pl.base); |
| 6957 | 7380 | try formatIntLiteral(.{ |
| 6958 | 7381 | .ty = switch (int_info.signedness) { |
| 6959 | 7382 | .unsigned => Type.u64, |
| 6960 | .signed => Type.i64, | |
| 7383 | .signed => if (use_twos_comp) Type.u64 else Type.i64, | |
| 6961 | 7384 | }, |
| 6962 | 7385 | .val = upper_val, |
| 6963 | 7386 | .mod = data.mod, |
| ... | ... | @@ -6967,7 +7390,7 @@ fn formatIntLiteral( |
| 6967 | 7390 | |
| 6968 | 7391 | var lower_pl = Value.Payload.BigInt{ |
| 6969 | 7392 | .base = .{ .tag = .int_big_positive }, |
| 6970 | .data = int.limbs[0..split], | |
| 7393 | .data = limbs[0..split], | |
| 6971 | 7394 | }; |
| 6972 | 7395 | const lower_val = Value.initPayload(&lower_pl.base); |
| 6973 | 7396 | try formatIntLiteral(.{ |
| ... | ... | @@ -6976,6 +7399,7 @@ fn formatIntLiteral( |
| 6976 | 7399 | .mod = data.mod, |
| 6977 | 7400 | }, fmt, options, writer); |
| 6978 | 7401 | |
| 7402 | if (!int.positive and c_bits > 64 and !use_twos_comp) try writer.writeByte(')'); | |
| 6979 | 7403 | return writer.writeByte(')'); |
| 6980 | 7404 | } |
| 6981 | 7405 |
stage1/zig1.wasm| Binary files a/stage1/zig1.wasm and b/stage1/zig1.wasm differ |
test/behavior/align.zig+1| ... | ... | @@ -540,6 +540,7 @@ test "align(N) on functions" { |
| 540 | 540 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 541 | 541 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 542 | 542 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 543 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO this is not supported on MSVC | |
| 543 | 544 | |
| 544 | 545 | // function alignment is a compile error on wasm32/wasm64 |
| 545 | 546 | if (native_arch == .wasm32 or native_arch == .wasm64) return error.SkipZigTest; |
test/behavior/asm.zig+5| ... | ... | @@ -23,6 +23,7 @@ test "module level assembly" { |
| 23 | 23 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 24 | 24 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 25 | 25 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 26 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | |
| 26 | 27 | |
| 27 | 28 | if (is_x86_64_linux) { |
| 28 | 29 | try expect(this_is_my_alias() == 1234); |
| ... | ... | @@ -35,6 +36,7 @@ test "output constraint modifiers" { |
| 35 | 36 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 36 | 37 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 37 | 38 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 39 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | |
| 38 | 40 | |
| 39 | 41 | // This is only testing compilation. |
| 40 | 42 | var a: u32 = 3; |
| ... | ... | @@ -56,6 +58,7 @@ test "alternative constraints" { |
| 56 | 58 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 57 | 59 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 58 | 60 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 61 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | |
| 59 | 62 | |
| 60 | 63 | // Make sure we allow commas as a separator for alternative constraints. |
| 61 | 64 | var a: u32 = 3; |
| ... | ... | @@ -72,6 +75,7 @@ test "sized integer/float in asm input" { |
| 72 | 75 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 73 | 76 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 74 | 77 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 78 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | |
| 75 | 79 | |
| 76 | 80 | asm volatile ("" |
| 77 | 81 | : |
| ... | ... | @@ -121,6 +125,7 @@ test "struct/array/union types as input values" { |
| 121 | 125 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 122 | 126 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 123 | 127 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 128 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | |
| 124 | 129 | |
| 125 | 130 | asm volatile ("" |
| 126 | 131 | : |
test/behavior/atomics.zig+133-22| ... | ... | @@ -250,31 +250,142 @@ test "atomicrmw with ints" { |
| 250 | 250 | return error.SkipZigTest; |
| 251 | 251 | } |
| 252 | 252 | |
| 253 | try testAtomicRmwInt(); | |
| 254 | comptime try testAtomicRmwInt(); | |
| 253 | try testAtomicRmwInts(); | |
| 254 | comptime try testAtomicRmwInts(); | |
| 255 | 255 | } |
| 256 | 256 | |
| 257 | fn testAtomicRmwInt() !void { | |
| 258 | var x: u8 = 1; | |
| 259 | var res = @atomicRmw(u8, &x, .Xchg, 3, .SeqCst); | |
| 257 | fn testAtomicRmwInts() !void { | |
| 258 | // TODO: Use the max atomic bit size for the target, maybe builtin? | |
| 259 | try testAtomicRmwInt(8); | |
| 260 | ||
| 261 | if (builtin.cpu.arch == .x86_64) { | |
| 262 | try testAtomicRmwInt(16); | |
| 263 | try testAtomicRmwInt(32); | |
| 264 | try testAtomicRmwInt(64); | |
| 265 | } | |
| 266 | } | |
| 267 | ||
| 268 | fn testAtomicRmwInt(comptime signedness: std.builtin.Signedness, comptime N: usize) !void { | |
| 269 | const int = std.meta.Int(signedness, N); | |
| 270 | ||
| 271 | var x: int = 1; | |
| 272 | var res = @atomicRmw(int, &x, .Xchg, 3, .SeqCst); | |
| 260 | 273 | try expect(x == 3 and res == 1); |
| 261 | _ = @atomicRmw(u8, &x, .Add, 3, .SeqCst); | |
| 262 | try expect(x == 6); | |
| 263 | _ = @atomicRmw(u8, &x, .Sub, 1, .SeqCst); | |
| 264 | try expect(x == 5); | |
| 265 | _ = @atomicRmw(u8, &x, .And, 4, .SeqCst); | |
| 266 | try expect(x == 4); | |
| 267 | _ = @atomicRmw(u8, &x, .Nand, 4, .SeqCst); | |
| 268 | try expect(x == 0xfb); | |
| 269 | _ = @atomicRmw(u8, &x, .Or, 6, .SeqCst); | |
| 270 | try expect(x == 0xff); | |
| 271 | _ = @atomicRmw(u8, &x, .Xor, 2, .SeqCst); | |
| 272 | try expect(x == 0xfd); | |
| 273 | ||
| 274 | _ = @atomicRmw(u8, &x, .Max, 1, .SeqCst); | |
| 275 | try expect(x == 0xfd); | |
| 276 | _ = @atomicRmw(u8, &x, .Min, 1, .SeqCst); | |
| 277 | try expect(x == 1); | |
| 274 | ||
| 275 | res = @atomicRmw(int, &x, .Add, 3, .SeqCst); | |
| 276 | var y: int = 3; | |
| 277 | try expect(res == y); | |
| 278 | y = y + 3; | |
| 279 | try expect(x == y); | |
| 280 | ||
| 281 | res = @atomicRmw(int, &x, .Sub, 1, .SeqCst); | |
| 282 | try expect(res == y); | |
| 283 | y = y - 1; | |
| 284 | try expect(x == y); | |
| 285 | ||
| 286 | res = @atomicRmw(int, &x, .And, 4, .SeqCst); | |
| 287 | try expect(res == y); | |
| 288 | y = y & 4; | |
| 289 | try expect(x == y); | |
| 290 | ||
| 291 | res = @atomicRmw(int, &x, .Nand, 4, .SeqCst); | |
| 292 | try expect(res == y); | |
| 293 | y = ~(y & 4); | |
| 294 | try expect(x == y); | |
| 295 | ||
| 296 | res = @atomicRmw(int, &x, .Or, 6, .SeqCst); | |
| 297 | try expect(res == y); | |
| 298 | y = y | 6; | |
| 299 | try expect(x == y); | |
| 300 | ||
| 301 | res = @atomicRmw(int, &x, .Xor, 2, .SeqCst); | |
| 302 | try expect(res == y); | |
| 303 | y = y ^ 2; | |
| 304 | try expect(x == y); | |
| 305 | ||
| 306 | res = @atomicRmw(int, &x, .Max, 1, .SeqCst); | |
| 307 | try expect(res == y); | |
| 308 | y = @max(y, 1); | |
| 309 | try expect(x == y); | |
| 310 | ||
| 311 | res = @atomicRmw(int, &x, .Min, 1, .SeqCst); | |
| 312 | try expect(res == y); | |
| 313 | y = @min(y, 1); | |
| 314 | try expect(x == y); | |
| 315 | } | |
| 316 | ||
| 317 | test "atomicrmw with 128-bit ints" { | |
| 318 | if (builtin.cpu.arch != .x86_64) { | |
| 319 | // TODO: Ideally this could use target.atomicPtrAlignment and check for IntTooBig | |
| 320 | return error.SkipZigTest; | |
| 321 | } | |
| 322 | ||
| 323 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | |
| 324 | ||
| 325 | // TODO "ld.lld: undefined symbol: __sync_lock_test_and_set_16" on -mcpu x86_64 | |
| 326 | if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; | |
| 327 | ||
| 328 | try testAtomicRmwInt128(.unsigned); | |
| 329 | comptime try testAtomicRmwInt128(.unsigned); | |
| 330 | } | |
| 331 | ||
| 332 | fn testAtomicRmwInt128(comptime signedness: std.builtin.Signedness) !void { | |
| 333 | const int = std.meta.Int(signedness, 128); | |
| 334 | ||
| 335 | const initial: int = 0xaaaaaaaa_bbbbbbbb_cccccccc_dddddddd; | |
| 336 | const replacement: int = 0x00000000_00000005_00000000_00000003; | |
| 337 | ||
| 338 | var x: int align(16) = initial; | |
| 339 | var res = @atomicRmw(int, &x, .Xchg, replacement, .SeqCst); | |
| 340 | try expect(x == replacement and res == initial); | |
| 341 | ||
| 342 | var operator: int = 0x00000001_00000000_20000000_00000000; | |
| 343 | res = @atomicRmw(int, &x, .Add, operator, .SeqCst); | |
| 344 | var y: int = replacement; | |
| 345 | try expect(res == y); | |
| 346 | y = y + operator; | |
| 347 | try expect(x == y); | |
| 348 | ||
| 349 | operator = 0x00000000_10000000_00000000_20000000; | |
| 350 | res = @atomicRmw(int, &x, .Sub, operator, .SeqCst); | |
| 351 | try expect(res == y); | |
| 352 | y = y - operator; | |
| 353 | try expect(x == y); | |
| 354 | ||
| 355 | operator = 0x12345678_87654321_12345678_87654321; | |
| 356 | res = @atomicRmw(int, &x, .And, operator, .SeqCst); | |
| 357 | try expect(res == y); | |
| 358 | y = y & operator; | |
| 359 | try expect(x == y); | |
| 360 | ||
| 361 | operator = 0x00000000_10000000_00000000_20000000; | |
| 362 | res = @atomicRmw(int, &x, .Nand, operator, .SeqCst); | |
| 363 | try expect(res == y); | |
| 364 | y = ~(y & operator); | |
| 365 | try expect(x == y); | |
| 366 | ||
| 367 | operator = 0x12340000_56780000_67890000_98760000; | |
| 368 | res = @atomicRmw(int, &x, .Or, operator, .SeqCst); | |
| 369 | try expect(res == y); | |
| 370 | y = y | operator; | |
| 371 | try expect(x == y); | |
| 372 | ||
| 373 | operator = 0x0a0b0c0d_0e0f0102_03040506_0708090a; | |
| 374 | res = @atomicRmw(int, &x, .Xor, operator, .SeqCst); | |
| 375 | try expect(res == y); | |
| 376 | y = y ^ operator; | |
| 377 | try expect(x == y); | |
| 378 | ||
| 379 | operator = 0x00000000_10000000_00000000_20000000; | |
| 380 | res = @atomicRmw(int, &x, .Max, operator, .SeqCst); | |
| 381 | try expect(res == y); | |
| 382 | y = @max(y, operator); | |
| 383 | try expect(x == y); | |
| 384 | ||
| 385 | res = @atomicRmw(int, &x, .Min, operator, .SeqCst); | |
| 386 | try expect(res == y); | |
| 387 | y = @min(y, operator); | |
| 388 | try expect(x == y); | |
| 278 | 389 | } |
| 279 | 390 | |
| 280 | 391 | test "atomics with different types" { |
test/behavior/basic.zig+18| ... | ... | @@ -37,6 +37,24 @@ test "truncate to non-power-of-two integers" { |
| 37 | 37 | try testTrunc(i32, i5, std.math.maxInt(i32), -1); |
| 38 | 38 | } |
| 39 | 39 | |
| 40 | test "truncate to non-power-of-two integers from 128-bit" { | |
| 41 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | |
| 42 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | |
| 43 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 44 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | |
| 45 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | |
| 46 | ||
| 47 | try testTrunc(u128, u1, 0xffffffff_ffffffff_ffffffff_01010101, 0x01); | |
| 48 | try testTrunc(u128, u1, 0xffffffff_ffffffff_ffffffff_01010110, 0x00); | |
| 49 | try testTrunc(u128, u2, 0xffffffff_ffffffff_ffffffff_01010101, 0x01); | |
| 50 | try testTrunc(u128, u2, 0xffffffff_ffffffff_ffffffff_01010102, 0x02); | |
| 51 | try testTrunc(i128, i5, -4, -4); | |
| 52 | try testTrunc(i128, i5, 4, 4); | |
| 53 | try testTrunc(i128, i5, -28, 4); | |
| 54 | try testTrunc(i128, i5, 28, -4); | |
| 55 | try testTrunc(i128, i5, std.math.maxInt(i128), -1); | |
| 56 | } | |
| 57 | ||
| 40 | 58 | fn testTrunc(comptime Big: type, comptime Little: type, big: Big, little: Little) !void { |
| 41 | 59 | try expect(@truncate(Little, big) == little); |
| 42 | 60 | } |
test/behavior/int128.zig+14-2| ... | ... | @@ -64,11 +64,23 @@ test "int128" { |
| 64 | 64 | } |
| 65 | 65 | |
| 66 | 66 | test "truncate int128" { |
| 67 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | |
| 67 | 68 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 68 | 69 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 69 | 70 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 70 | 71 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 71 | 72 | |
| 72 | var buff: u128 = maxInt(u128); | |
| 73 | try expect(@truncate(u64, buff) == maxInt(u64)); | |
| 73 | { | |
| 74 | var buff: u128 = maxInt(u128); | |
| 75 | try expect(@truncate(u64, buff) == maxInt(u64)); | |
| 76 | try expect(@truncate(u90, buff) == maxInt(u90)); | |
| 77 | try expect(@truncate(u128, buff) == maxInt(u128)); | |
| 78 | } | |
| 79 | ||
| 80 | { | |
| 81 | var buff: i128 = maxInt(i128); | |
| 82 | try expect(@truncate(i64, buff) == -1); | |
| 83 | try expect(@truncate(i90, buff) == -1); | |
| 84 | try expect(@truncate(i128, buff) == maxInt(i128)); | |
| 85 | } | |
| 74 | 86 | } |
test/behavior/math.zig+40-4| ... | ... | @@ -377,6 +377,28 @@ fn testBinaryNot(x: u16) !void { |
| 377 | 377 | try expect(~x == 0b0101010101010101); |
| 378 | 378 | } |
| 379 | 379 | |
| 380 | test "binary not 128-bit" { | |
| 381 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | |
| 382 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | |
| 383 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 384 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | |
| 385 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | |
| 386 | ||
| 387 | try expect(comptime x: { | |
| 388 | break :x ~@as(u128, 0x55555555_55555555_55555555_55555555) == 0xaaaaaaaa_aaaaaaaa_aaaaaaaa_aaaaaaaa; | |
| 389 | }); | |
| 390 | try expect(comptime x: { | |
| 391 | break :x ~@as(i128, 0x55555555_55555555_55555555_55555555) == @bitCast(i128, @as(u128, 0xaaaaaaaa_aaaaaaaa_aaaaaaaa_aaaaaaaa)); | |
| 392 | }); | |
| 393 | ||
| 394 | try testBinaryNot128(u128, 0xaaaaaaaa_aaaaaaaa_aaaaaaaa_aaaaaaaa); | |
| 395 | try testBinaryNot128(i128, @bitCast(i128, @as(u128, 0xaaaaaaaa_aaaaaaaa_aaaaaaaa_aaaaaaaa))); | |
| 396 | } | |
| 397 | ||
| 398 | fn testBinaryNot128(comptime Type: type, x: Type) !void { | |
| 399 | try expect(~x == @as(Type, 0x55555555_55555555_55555555_55555555)); | |
| 400 | } | |
| 401 | ||
| 380 | 402 | test "division" { |
| 381 | 403 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 382 | 404 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| ... | ... | @@ -632,10 +654,24 @@ test "128-bit multiplication" { |
| 632 | 654 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 633 | 655 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 634 | 656 | |
| 635 | var a: i128 = 3; | |
| 636 | var b: i128 = 2; | |
| 637 | var c = a * b; | |
| 638 | try expect(c == 6); | |
| 657 | { | |
| 658 | var a: i128 = 3; | |
| 659 | var b: i128 = 2; | |
| 660 | var c = a * b; | |
| 661 | try expect(c == 6); | |
| 662 | ||
| 663 | a = -3; | |
| 664 | b = 2; | |
| 665 | c = a * b; | |
| 666 | try expect(c == -6); | |
| 667 | } | |
| 668 | ||
| 669 | { | |
| 670 | var a: u128 = 0xffffffffffffffff; | |
| 671 | var b: u128 = 100; | |
| 672 | var c = a * b; | |
| 673 | try expect(c == 0x63ffffffffffffff9c); | |
| 674 | } | |
| 639 | 675 | } |
| 640 | 676 | |
| 641 | 677 | test "@addWithOverflow" { |