authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-01-02 16:11:17-05:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-01-02 16:11:17-05:00
log4c1007fc044689b8cbc20634d73debb43df8efe1
tree967e4bd30091e0d28816febe1c9fea1b761b9a94
parent4172c2916684655a9742de99384be8110922ed07
parent23b1544f6c17dd1111ba8791189a7290581f945e
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #14002 from kcbanner/cbe_msvc_compatibility

CBE: MSVC-compatible code generation, and fixes to get behaviour tests passing and zig2.c building

16 files changed, 1507 insertions(+), 319 deletions(-)

lib/compiler_rt/divti3.zig+3-16
...@@ -7,21 +7,8 @@ const common = @import("common.zig");...@@ -7,21 +7,8 @@ const common = @import("common.zig");
7pub const panic = common.panic;7pub const panic = common.panic;
88
9comptime {9comptime {
10 if (builtin.os.tag == .windows) {10 if (common.want_windows_v2u64_abi) {
11 switch (arch) {11 @export(__divti3_windows_x86_64, .{ .name = "__divti3", .linkage = common.linkage, .visibility = common.visibility });
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 }
25 } else {12 } else {
26 @export(__divti3, .{ .name = "__divti3", .linkage = common.linkage, .visibility = common.visibility });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,7 +18,7 @@ pub fn __divti3(a: i128, b: i128) callconv(.C) i128 {
31 return div(a, b);18 return div(a, b);
32}19}
3320
34const v128 = @import("std").meta.Vector(2, u64);21const v128 = @Vector(2, u64);
3522
36fn __divti3_windows_x86_64(a: v128, b: v128) callconv(.C) v128 {23fn __divti3_windows_x86_64(a: v128, b: v128) callconv(.C) v128 {
37 return @bitCast(v128, div(@bitCast(i128, a), @bitCast(i128, b)));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,7 +16,7 @@ pub fn __fixunshfti(a: f16) callconv(.C) u128 {
16 return floatToInt(u128, a);16 return floatToInt(u128, a);
17}17}
1818
19const v2u64 = @import("std").meta.Vector(2, u64);19const v2u64 = @Vector(2, u64);
2020
21fn __fixunshfti_windows_x86_64(a: f16) callconv(.C) v2u64 {21fn __fixunshfti_windows_x86_64(a: f16) callconv(.C) v2u64 {
22 return @bitCast(v2u64, floatToInt(u128, a));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,6 +129,8 @@ pub fn __umodei4(r_p: [*c]u32, u_p: [*c]const u32, v_p: [*c]const u32, bits: usi
129}129}
130130
131test "__udivei4/__umodei4" {131test "__udivei4/__umodei4" {
132 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
133
132 const RndGen = std.rand.DefaultPrng;134 const RndGen = std.rand.DefaultPrng;
133 var rnd = RndGen.init(42);135 var rnd = RndGen.init(42);
134 var i: usize = 10000;136 var i: usize = 10000;
lib/std/math/big/int.zig+34
...@@ -1677,6 +1677,40 @@ pub const Mutable = struct {...@@ -1677,6 +1677,40 @@ pub const Mutable = struct {
1677 y.shiftRight(y.toConst(), norm_shift);1677 y.shiftRight(y.toConst(), norm_shift);
1678 }1678 }
16791679
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 /// Truncate an integer to a number of bits, following 2s-complement semantics.1714 /// Truncate an integer to a number of bits, following 2s-complement semantics.
1681 /// r may alias a.1715 /// r may alias a.
1682 ///1716 ///
lib/std/mem.zig+23-7
...@@ -3771,7 +3771,7 @@ pub fn doNotOptimizeAway(val: anytype) void {...@@ -3771,7 +3771,7 @@ pub fn doNotOptimizeAway(val: anytype) void {
3771 .Bool => doNotOptimizeAway(@boolToInt(val)),3771 .Bool => doNotOptimizeAway(@boolToInt(val)),
3772 .Int => {3772 .Int => {
3773 const bits = t.Int.bits;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 const val2 = @as(3775 const val2 = @as(
3776 std.meta.Int(t.Int.signedness, @max(8, std.math.ceilPowerOfTwoAssert(u16, bits))),3776 std.meta.Int(t.Int.signedness, @max(8, std.math.ceilPowerOfTwoAssert(u16, bits))),
3777 val,3777 val,
...@@ -3783,18 +3783,24 @@ pub fn doNotOptimizeAway(val: anytype) void {...@@ -3783,18 +3783,24 @@ pub fn doNotOptimizeAway(val: anytype) void {
3783 } else doNotOptimizeAway(&val);3783 } else doNotOptimizeAway(&val);
3784 },3784 },
3785 .Float => {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 asm volatile (""3787 asm volatile (""
3788 :3788 :
3789 : [val] "rm" (val),3789 : [val] "rm" (val),
3790 );3790 );
3791 } else doNotOptimizeAway(&val);3791 } else doNotOptimizeAway(&val);
3792 },3792 },
3793 .Pointer => asm volatile (""3793 .Pointer => {
3794 :3794 if (builtin.zig_backend == .stage2_c) {
3795 : [val] "m" (val),3795 doNotOptimizeAwayC(val);
3796 : "memory"3796 } else {
3797 ),3797 asm volatile (""
3798 :
3799 : [val] "m" (val),
3800 : "memory"
3801 );
3802 }
3803 },
3798 .Array => {3804 .Array => {
3799 if (t.Array.len * @sizeOf(t.Array.child) <= 64) {3805 if (t.Array.len * @sizeOf(t.Array.child) <= 64) {
3800 for (val) |v| doNotOptimizeAway(v);3806 for (val) |v| doNotOptimizeAway(v);
...@@ -3804,6 +3810,16 @@ pub fn doNotOptimizeAway(val: anytype) void {...@@ -3804,6 +3810,16 @@ pub fn doNotOptimizeAway(val: anytype) void {
3804 }3810 }
3805}3811}
38063812
3813/// .stage2_c doesn't support asm blocks yet, so use volatile stores instead
3814var deopt_target: if (builtin.zig_backend == .stage2_c) u8 else void = undefined;
3815fn 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
3807test "doNotOptimizeAway" {3823test "doNotOptimizeAway" {
3808 comptime doNotOptimizeAway("test");3824 comptime doNotOptimizeAway("test");
38093825
lib/std/os/windows.zig+29-4
...@@ -1776,16 +1776,26 @@ pub fn UnlockFile(...@@ -1776,16 +1776,26 @@ pub fn UnlockFile(
1776 }1776 }
1777}1777}
17781778
1779/// This is a workaround for the C backend until zig has the ability to put
1780/// C code in inline assembly.
1781extern fn zig_x86_64_windows_teb() callconv(.C) *anyopaque;
1782
1779pub fn teb() *TEB {1783pub fn teb() *TEB {
1780 return switch (native_arch) {1784 return switch (native_arch) {
1781 .x86 => asm volatile (1785 .x86 => asm volatile (
1782 \\ movl %%fs:0x18, %[ptr]1786 \\ movl %%fs:0x18, %[ptr]
1783 : [ptr] "=r" (-> *TEB),1787 : [ptr] "=r" (-> *TEB),
1784 ),1788 ),
1785 .x86_64 => asm volatile (1789 .x86_64 => blk: {
1786 \\ movq %%gs:0x30, %[ptr]1790 if (builtin.zig_backend == .stage2_c) {
1787 : [ptr] "=r" (-> *TEB),1791 break :blk @ptrCast(*TEB, @alignCast(@alignOf(TEB), zig_x86_64_windows_teb()));
1788 ),1792 } else {
1793 break :blk asm volatile (
1794 \\ movq %%gs:0x30, %[ptr]
1795 : [ptr] "=r" (-> *TEB),
1796 );
1797 }
1798 },
1789 .aarch64 => asm volatile (1799 .aarch64 => asm volatile (
1790 \\ mov %[ptr], x181800 \\ mov %[ptr], x18
1791 : [ptr] "=r" (-> *TEB),1801 : [ptr] "=r" (-> *TEB),
...@@ -3455,6 +3465,21 @@ pub const ASSEMBLY_STORAGE_MAP = opaque {};...@@ -3455,6 +3465,21 @@ pub const ASSEMBLY_STORAGE_MAP = opaque {};
3455pub const FLS_CALLBACK_INFO = opaque {};3465pub const FLS_CALLBACK_INFO = opaque {};
3456pub const RTL_BITMAP = opaque {};3466pub const RTL_BITMAP = opaque {};
3457pub const KAFFINITY = usize;3467pub const KAFFINITY = usize;
3468pub const KPRIORITY = i32;
3469
3470pub const CLIENT_ID = extern struct {
3471 UniqueProcess: HANDLE,
3472 UniqueThread: HANDLE,
3473};
3474
3475pub 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};
34583483
3459pub const TEB = extern struct {3484pub const TEB = extern struct {
3460 Reserved1: [12]PVOID,3485 Reserved1: [12]PVOID,
lib/std/zig/system/x86.zig+27-8
...@@ -1,4 +1,5 @@...@@ -1,4 +1,5 @@
1const std = @import("std");1const std = @import("std");
2const builtin = @import("builtin");
2const Target = std.Target;3const Target = std.Target;
3const CrossTarget = std.zig.CrossTarget;4const CrossTarget = std.zig.CrossTarget;
45
...@@ -527,25 +528,43 @@ const CpuidLeaf = packed struct {...@@ -527,25 +528,43 @@ const CpuidLeaf = packed struct {
527 edx: u32,528 edx: u32,
528};529};
529530
531/// This is a workaround for the C backend until zig has the ability to put
532/// C code in inline assembly.
533extern fn zig_x86_cpuid(leaf_id: u32, subid: u32, eax: *u32, ebx: *u32, ecx: *u32, edx: *u32) callconv(.C) void;
534
530fn cpuid(leaf_id: u32, subid: u32) CpuidLeaf {535fn cpuid(leaf_id: u32, subid: u32) CpuidLeaf {
531 // valid for both x86 and x86_64536 // valid for both x86 and x86_64
532 var eax: u32 = undefined;537 var eax: u32 = undefined;
533 var ebx: u32 = undefined;538 var ebx: u32 = undefined;
534 var ecx: u32 = undefined;539 var ecx: u32 = undefined;
535 var edx: u32 = undefined;540 var edx: u32 = undefined;
536 asm volatile ("cpuid"541
537 : [_] "={eax}" (eax),542 if (builtin.zig_backend == .stage2_c) {
538 [_] "={ebx}" (ebx),543 zig_x86_cpuid(leaf_id, subid, &eax, &ebx, &ecx, &edx);
539 [_] "={ecx}" (ecx),544 } else {
540 [_] "={edx}" (edx),545 asm volatile ("cpuid"
541 : [_] "{eax}" (leaf_id),546 : [_] "={eax}" (eax),
542 [_] "{ecx}" (subid),547 [_] "={ebx}" (ebx),
543 );548 [_] "={ecx}" (ecx),
549 [_] "={edx}" (edx),
550 : [_] "{eax}" (leaf_id),
551 [_] "{ecx}" (subid),
552 );
553 }
554
544 return .{ .eax = eax, .ebx = ebx, .ecx = ecx, .edx = edx };555 return .{ .eax = eax, .ebx = ebx, .ecx = ecx, .edx = edx };
545}556}
546557
558/// This is a workaround for the C backend until zig has the ability to put
559/// C code in inline assembly.
560extern fn zig_x86_get_xcr0() callconv(.C) u32;
561
547// Read control register 0 (XCR0). Used to detect features such as AVX.562// Read control register 0 (XCR0). Used to detect features such as AVX.
548fn getXCR0() u32 {563fn getXCR0() u32 {
564 if (builtin.zig_backend == .stage2_c) {
565 return zig_x86_get_xcr0();
566 }
567
549 return asm volatile (568 return asm volatile (
550 \\ xor %%ecx, %%ecx569 \\ xor %%ecx, %%ecx
551 \\ xgetbv570 \\ xgetbv
lib/zig.h+584-86
...@@ -6,6 +6,12 @@...@@ -6,6 +6,12 @@
6#include <stddef.h>6#include <stddef.h>
7#include <stdint.h>7#include <stdint.h>
88
9#if _MSC_VER
10#include <intrin.h>
11#elif defined(__i386__) || defined(__x86_64__)
12#include <cpuid.h>
13#endif
14
9#if !defined(__cplusplus) && __STDC_VERSION__ <= 201710L15#if !defined(__cplusplus) && __STDC_VERSION__ <= 201710L
10#if __STDC_VERSION__ >= 199901L16#if __STDC_VERSION__ >= 199901L
11#include <stdbool.h>17#include <stdbool.h>
...@@ -38,6 +44,12 @@ typedef char bool;...@@ -38,6 +44,12 @@ typedef char bool;
38#define zig_threadlocal zig_threadlocal_unavailable44#define zig_threadlocal zig_threadlocal_unavailable
39#endif45#endif
4046
47#if _MSC_VER
48#define zig_const_arr
49#else
50#define zig_const_arr static const
51#endif
52
41#if zig_has_attribute(naked) || defined(__GNUC__)53#if zig_has_attribute(naked) || defined(__GNUC__)
42#define zig_naked __attribute__((naked))54#define zig_naked __attribute__((naked))
43#elif defined(_MSC_VER)55#elif defined(_MSC_VER)
...@@ -65,7 +77,7 @@ typedef char bool;...@@ -65,7 +77,7 @@ typedef char bool;
65#elif zig_has_attribute(aligned)77#elif zig_has_attribute(aligned)
66#define zig_align(alignment) __attribute__((aligned(alignment)))78#define zig_align(alignment) __attribute__((aligned(alignment)))
67#elif _MSC_VER79#elif _MSC_VER
68#define zig_align zig_align_unavailable80#define zig_align(alignment) __declspec(align(alignment))
69#else81#else
70#define zig_align zig_align_unavailable82#define zig_align zig_align_unavailable
71#endif83#endif
...@@ -73,7 +85,7 @@ typedef char bool;...@@ -73,7 +85,7 @@ typedef char bool;
73#if zig_has_attribute(aligned)85#if zig_has_attribute(aligned)
74#define zig_align_fn(alignment) __attribute__((aligned(alignment)))86#define zig_align_fn(alignment) __attribute__((aligned(alignment)))
75#elif _MSC_VER87#elif _MSC_VER
76#define zig_align_fn zig_align_fn_unavailable88#define zig_align_fn(alignment)
77#else89#else
78#define zig_align_fn zig_align_fn_unavailable90#define zig_align_fn zig_align_fn_unavailable
79#endif91#endif
...@@ -92,6 +104,9 @@ typedef char bool;...@@ -92,6 +104,9 @@ typedef char bool;
92104
93#if zig_has_attribute(alias)105#if zig_has_attribute(alias)
94#define zig_export(sig, symbol, name) zig_extern sig __attribute__((alias(symbol)))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#else110#else
96#define zig_export(sig, symbol, name) __asm(name " = " symbol)111#define zig_export(sig, symbol, name) __asm(name " = " symbol)
97#endif112#endif
...@@ -136,22 +151,25 @@ typedef char bool;...@@ -136,22 +151,25 @@ typedef char bool;
136#define zig_wasm_memory_grow(index, delta) zig_unimplemented()151#define zig_wasm_memory_grow(index, delta) zig_unimplemented()
137#endif152#endif
138153
154#define zig_concat(lhs, rhs) lhs##rhs
155#define zig_expand_concat(lhs, rhs) zig_concat(lhs, rhs)
156
139#if __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_ATOMICS__)157#if __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_ATOMICS__)
140#include <stdatomic.h>158#include <stdatomic.h>
141#define zig_atomic(type) _Atomic(type)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)160#define zig_cmpxchg_strong(obj, expected, desired, succ, fail, type) 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)161#define zig_cmpxchg_weak(obj, expected, desired, succ, fail, type) atomic_compare_exchange_weak_explicit (obj, &(expected), desired, succ, fail)
144#define zig_atomicrmw_xchg(obj, arg, order) atomic_exchange_explicit (obj, arg, order)162#define zig_atomicrmw_xchg(obj, arg, order, type) atomic_exchange_explicit (obj, arg, order)
145#define zig_atomicrmw_add(obj, arg, order) atomic_fetch_add_explicit (obj, arg, order)163#define zig_atomicrmw_add(obj, arg, order, type) atomic_fetch_add_explicit (obj, arg, order)
146#define zig_atomicrmw_sub(obj, arg, order) atomic_fetch_sub_explicit (obj, arg, order)164#define zig_atomicrmw_sub(obj, arg, order, type) atomic_fetch_sub_explicit (obj, arg, order)
147#define zig_atomicrmw_or(obj, arg, order) atomic_fetch_or_explicit (obj, arg, order)165#define zig_atomicrmw_or(obj, arg, order, type) atomic_fetch_or_explicit (obj, arg, order)
148#define zig_atomicrmw_xor(obj, arg, order) atomic_fetch_xor_explicit (obj, arg, order)166#define zig_atomicrmw_xor(obj, arg, order, type) atomic_fetch_xor_explicit (obj, arg, order)
149#define zig_atomicrmw_and(obj, arg, order) atomic_fetch_and_explicit (obj, arg, order)167#define zig_atomicrmw_and(obj, arg, order, type) atomic_fetch_and_explicit (obj, arg, order)
150#define zig_atomicrmw_nand(obj, arg, order) __atomic_fetch_nand (obj, arg, order)168#define zig_atomicrmw_nand(obj, arg, order, type) __atomic_fetch_nand (obj, arg, order)
151#define zig_atomicrmw_min(obj, arg, order) __atomic_fetch_min (obj, arg, order)169#define zig_atomicrmw_min(obj, arg, order, type) __atomic_fetch_min (obj, arg, order)
152#define zig_atomicrmw_max(obj, arg, order) __atomic_fetch_max (obj, arg, order)170#define zig_atomicrmw_max(obj, arg, order, type) __atomic_fetch_max (obj, arg, order)
153#define zig_atomic_store(obj, arg, order) atomic_store_explicit (obj, arg, order)171#define zig_atomic_store(obj, arg, order, type) atomic_store_explicit (obj, arg, order)
154#define zig_atomic_load(obj, order) atomic_load_explicit (obj, order)172#define zig_atomic_load(obj, order, type) atomic_load_explicit (obj, order)
155#define zig_fence(order) atomic_thread_fence(order)173#define zig_fence(order) atomic_thread_fence(order)
156#elif defined(__GNUC__)174#elif defined(__GNUC__)
157#define memory_order_relaxed __ATOMIC_RELAXED175#define memory_order_relaxed __ATOMIC_RELAXED
...@@ -161,20 +179,43 @@ typedef char bool;...@@ -161,20 +179,43 @@ typedef char bool;
161#define memory_order_acq_rel __ATOMIC_ACQ_REL179#define memory_order_acq_rel __ATOMIC_ACQ_REL
162#define memory_order_seq_cst __ATOMIC_SEQ_CST180#define memory_order_seq_cst __ATOMIC_SEQ_CST
163#define zig_atomic(type) type181#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)182#define zig_cmpxchg_strong(obj, expected, desired, succ, fail, type) __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)183#define zig_cmpxchg_weak(obj, expected, desired, succ, fail, type) __atomic_compare_exchange_n(obj, &(expected), desired, true , succ, fail)
166#define zig_atomicrmw_xchg(obj, arg, order) __atomic_exchange_n(obj, arg, order)184#define zig_atomicrmw_xchg(obj, arg, order, type) __atomic_exchange_n(obj, arg, order)
167#define zig_atomicrmw_add(obj, arg, order) __atomic_fetch_add (obj, arg, order)185#define zig_atomicrmw_add(obj, arg, order, type) __atomic_fetch_add (obj, arg, order)
168#define zig_atomicrmw_sub(obj, arg, order) __atomic_fetch_sub (obj, arg, order)186#define zig_atomicrmw_sub(obj, arg, order, type) __atomic_fetch_sub (obj, arg, order)
169#define zig_atomicrmw_or(obj, arg, order) __atomic_fetch_or (obj, arg, order)187#define zig_atomicrmw_or(obj, arg, order, type) __atomic_fetch_or (obj, arg, order)
170#define zig_atomicrmw_xor(obj, arg, order) __atomic_fetch_xor (obj, arg, order)188#define zig_atomicrmw_xor(obj, arg, order, type) __atomic_fetch_xor (obj, arg, order)
171#define zig_atomicrmw_and(obj, arg, order) __atomic_fetch_and (obj, arg, order)189#define zig_atomicrmw_and(obj, arg, order, type) __atomic_fetch_and (obj, arg, order)
172#define zig_atomicrmw_nand(obj, arg, order) __atomic_fetch_nand(obj, arg, order)190#define zig_atomicrmw_nand(obj, arg, order, type) __atomic_fetch_nand(obj, arg, order)
173#define zig_atomicrmw_min(obj, arg, order) __atomic_fetch_min (obj, arg, order)191#define zig_atomicrmw_min(obj, arg, order, type) __atomic_fetch_min (obj, arg, order)
174#define zig_atomicrmw_max(obj, arg, order) __atomic_fetch_max (obj, arg, order)192#define zig_atomicrmw_max(obj, arg, order, type) __atomic_fetch_max (obj, arg, order)
175#define zig_atomic_store(obj, arg, order) __atomic_store_n (obj, arg, order)193#define zig_atomic_store(obj, arg, order, type) __atomic_store_n (obj, arg, order)
176#define zig_atomic_load(obj, order) __atomic_load_n (obj, order)194#define zig_atomic_load(obj, order, type) __atomic_load_n (obj, order)
177#define zig_fence(order) __atomic_thread_fence(order)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#else219#else
179#define memory_order_relaxed 0220#define memory_order_relaxed 0
180#define memory_order_consume 1221#define memory_order_consume 1
...@@ -183,19 +224,19 @@ typedef char bool;...@@ -183,19 +224,19 @@ typedef char bool;
183#define memory_order_acq_rel 4224#define memory_order_acq_rel 4
184#define memory_order_seq_cst 5225#define memory_order_seq_cst 5
185#define zig_atomic(type) type226#define zig_atomic(type) type
186#define zig_cmpxchg_strong(obj, expected, desired, succ, fail) zig_unimplemented()227#define zig_cmpxchg_strong(obj, expected, desired, succ, fail, type) zig_unimplemented()
187#define zig_cmpxchg_weak(obj, expected, desired, succ, fail) zig_unimplemented()228#define zig_cmpxchg_weak(obj, expected, desired, succ, fail, type) zig_unimplemented()
188#define zig_atomicrmw_xchg(obj, arg, order) zig_unimplemented()229#define zig_atomicrmw_xchg(obj, arg, order, type) zig_unimplemented()
189#define zig_atomicrmw_add(obj, arg, order) zig_unimplemented()230#define zig_atomicrmw_add(obj, arg, order, type) zig_unimplemented()
190#define zig_atomicrmw_sub(obj, arg, order) zig_unimplemented()231#define zig_atomicrmw_sub(obj, arg, order, type) zig_unimplemented()
191#define zig_atomicrmw_or(obj, arg, order) zig_unimplemented()232#define zig_atomicrmw_or(obj, arg, order, type) zig_unimplemented()
192#define zig_atomicrmw_xor(obj, arg, order) zig_unimplemented()233#define zig_atomicrmw_xor(obj, arg, order, type) zig_unimplemented()
193#define zig_atomicrmw_and(obj, arg, order) zig_unimplemented()234#define zig_atomicrmw_and(obj, arg, order, type) zig_unimplemented()
194#define zig_atomicrmw_nand(obj, arg, order) zig_unimplemented()235#define zig_atomicrmw_nand(obj, arg, order, type) zig_unimplemented()
195#define zig_atomicrmw_min(obj, arg, order) zig_unimplemented()236#define zig_atomicrmw_min(obj, arg, order, type) zig_unimplemented()
196#define zig_atomicrmw_max(obj, arg, order) zig_unimplemented()237#define zig_atomicrmw_max(obj, arg, order, type) zig_unimplemented()
197#define zig_atomic_store(obj, arg, order) zig_unimplemented()238#define zig_atomic_store(obj, arg, order, type) zig_unimplemented()
198#define zig_atomic_load(obj, order) zig_unimplemented()239#define zig_atomic_load(obj, order, type) zig_unimplemented()
199#define zig_fence(order) zig_unimplemented()240#define zig_fence(order) zig_unimplemented()
200#endif241#endif
201242
...@@ -209,9 +250,6 @@ typedef char bool;...@@ -209,9 +250,6 @@ typedef char bool;
209#define zig_noreturn void250#define zig_noreturn void
210#endif251#endif
211252
212#define zig_concat(lhs, rhs) lhs##rhs
213#define zig_expand_concat(lhs, rhs) zig_concat(lhs, rhs)
214
215#define zig_bitSizeOf(T) (CHAR_BIT * sizeof(T))253#define zig_bitSizeOf(T) (CHAR_BIT * sizeof(T))
216254
217typedef uintptr_t zig_usize;255typedef uintptr_t zig_usize;
...@@ -1141,6 +1179,8 @@ typedef signed __int128 zig_i128;...@@ -1141,6 +1179,8 @@ typedef signed __int128 zig_i128;
11411179
1142#define zig_as_u128(hi, lo) ((zig_u128)(hi)<<64|(lo))1180#define zig_as_u128(hi, lo) ((zig_u128)(hi)<<64|(lo))
1143#define zig_as_i128(hi, lo) ((zig_i128)zig_as_u128(hi, lo))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#define zig_hi_u128(val) ((zig_u64)((val) >> 64))1184#define zig_hi_u128(val) ((zig_u64)((val) >> 64))
1145#define zig_lo_u128(val) ((zig_u64)((val) >> 0))1185#define zig_lo_u128(val) ((zig_u64)((val) >> 0))
1146#define zig_hi_i128(val) ((zig_i64)((val) >> 64))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,6 +1208,8 @@ typedef struct { zig_align(16) zig_i64 hi; zig_u64 lo; } zig_i128;
11681208
1169#define zig_as_u128(hi, lo) ((zig_u128){ .h##i = (hi), .l##o = (lo) })1209#define zig_as_u128(hi, lo) ((zig_u128){ .h##i = (hi), .l##o = (lo) })
1170#define zig_as_i128(hi, lo) ((zig_i128){ .h##i = (hi), .l##o = (lo) })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#define zig_hi_u128(val) ((val).hi)1213#define zig_hi_u128(val) ((val).hi)
1172#define zig_lo_u128(val) ((val).lo)1214#define zig_lo_u128(val) ((val).lo)
1173#define zig_hi_i128(val) ((val).hi)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,51 +1331,79 @@ static inline zig_i128 zig_not_i128(zig_i128 val, zig_u8 bits) {
1289}1331}
12901332
1291static inline zig_u128 zig_shr_u128(zig_u128 lhs, zig_u8 rhs) {1333static 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 };1334 if (rhs == zig_as_u8(0)) return lhs;
1293 return (zig_u128){ .hi = lhs.hi << rhs | lhs.lo >> (zig_as_u8(64) - rhs), .lo = lhs.lo << rhs };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}
12951338
1296static inline zig_u128 zig_shl_u128(zig_u128 lhs, zig_u8 rhs) {1339static 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 return (zig_u128){ .hi = lhs.hi << rhs | lhs.lo >> (zig_as_u8(64) - rhs), .lo = lhs.lo << rhs };1342 return (zig_u128){ .hi = lhs.hi << rhs | lhs.lo >> (zig_as_u8(64) - rhs), .lo = lhs.lo << rhs };
1299}1343}
13001344
1301static inline zig_i128 zig_shl_i128(zig_i128 lhs, zig_u8 rhs) {1345static 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 return (zig_i128){ .hi = lhs.hi << rhs | lhs.lo >> (zig_as_u8(64) - rhs), .lo = lhs.lo << rhs };1348 return (zig_i128){ .hi = lhs.hi << rhs | lhs.lo >> (zig_as_u8(64) - rhs), .lo = lhs.lo << rhs };
1304}1349}
13051350
1306static inline zig_u128 zig_add_u128(zig_u128 lhs, zig_u128 rhs) {1351static inline zig_u128 zig_add_u128(zig_u128 lhs, zig_u128 rhs) {
1307 zig_u128 res;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 return res;1354 return res;
1310}1355}
13111356
1312static inline zig_i128 zig_add_i128(zig_i128 lhs, zig_i128 rhs) {1357static inline zig_i128 zig_add_i128(zig_i128 lhs, zig_i128 rhs) {
1313 zig_i128 res;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 return res;1360 return res;
1316}1361}
13171362
1318static inline zig_u128 zig_sub_u128(zig_u128 lhs, zig_u128 rhs) {1363static inline zig_u128 zig_sub_u128(zig_u128 lhs, zig_u128 rhs) {
1319 zig_u128 res;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 return res;1366 return res;
1322}1367}
13231368
1324static inline zig_i128 zig_sub_i128(zig_i128 lhs, zig_i128 rhs) {1369static inline zig_i128 zig_sub_i128(zig_i128 lhs, zig_i128 rhs) {
1325 zig_i128 res;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 return res;1372 return res;
1328}1373}
13291374
1330static inline zig_i128 zig_div_floor_i128(zig_i128 lhs, zig_i128 rhs) {1375zig_extern zig_i128 __multi3(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));1376static zig_i128 zig_mul_i128(zig_i128 lhs, zig_i128 rhs) {
1377 return __multi3(lhs, rhs);
1378}
1379
1380zig_extern zig_u128 __udivti3(zig_u128 lhs, zig_u128 rhs);
1381static zig_u128 zig_div_trunc_u128(zig_u128 lhs, zig_u128 rhs) {
1382 return __udivti3(lhs, rhs);
1383};
1384
1385zig_extern zig_i128 __divti3(zig_i128 lhs, zig_i128 rhs);
1386static zig_i128 zig_div_trunc_i128(zig_i128 lhs, zig_i128 rhs) {
1387 return __divti3(lhs, rhs);
1388};
1389
1390zig_extern zig_u128 __umodti3(zig_u128 lhs, zig_u128 rhs);
1391static zig_u128 zig_rem_u128(zig_u128 lhs, zig_u128 rhs) {
1392 return __umodti3(lhs, rhs);
1393}
1394
1395zig_extern zig_i128 __modti3(zig_i128 lhs, zig_i128 rhs);
1396static zig_i128 zig_rem_i128(zig_i128 lhs, zig_i128 rhs) {
1397 return __modti3(lhs, rhs);
1332}1398}
13331399
1334static inline zig_i128 zig_mod_i128(zig_i128 lhs, zig_i128 rhs) {1400static inline zig_i128 zig_mod_i128(zig_i128 lhs, zig_i128 rhs) {
1335 zig_i128 rem = zig_rem_i128(lhs, rhs);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
1405static 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}
13381408
1339#endif /* zig_has_int128 */1409#endif /* zig_has_int128 */
...@@ -1341,6 +1411,10 @@ static inline zig_i128 zig_mod_i128(zig_i128 lhs, zig_i128 rhs) {...@@ -1341,6 +1411,10 @@ static inline zig_i128 zig_mod_i128(zig_i128 lhs, zig_i128 rhs) {
1341#define zig_div_floor_u128 zig_div_trunc_u1281411#define zig_div_floor_u128 zig_div_trunc_u128
1342#define zig_mod_u128 zig_rem_u1281412#define zig_mod_u128 zig_rem_u128
13431413
1414static 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
1344static inline zig_u128 zig_min_u128(zig_u128 lhs, zig_u128 rhs) {1418static inline zig_u128 zig_min_u128(zig_u128 lhs, zig_u128 rhs) {
1345 return zig_cmp_u128(lhs, rhs) < zig_as_i32(0) ? lhs : rhs;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,7 +1432,7 @@ static inline zig_i128 zig_max_i128(zig_i128 lhs, zig_i128 rhs) {
1358}1432}
13591433
1360static inline zig_i128 zig_shr_i128(zig_i128 lhs, zig_u8 rhs) {1434static 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 return zig_xor_i128(zig_bitcast_i128(zig_shr_u128(zig_bitcast_u128(zig_xor_i128(lhs, sign_mask)), rhs)), sign_mask);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}
13641438
...@@ -1375,7 +1449,7 @@ static inline zig_u128 zig_shlw_u128(zig_u128 lhs, zig_u8 rhs, zig_u8 bits) {...@@ -1375,7 +1449,7 @@ static inline zig_u128 zig_shlw_u128(zig_u128 lhs, zig_u8 rhs, zig_u8 bits) {
1375}1449}
13761450
1377static inline zig_i128 zig_shlw_i128(zig_i128 lhs, zig_u8 rhs, zig_u8 bits) {1451static 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}
13801454
1381static inline zig_u128 zig_addw_u128(zig_u128 lhs, zig_u128 rhs, zig_u8 bits) {1455static 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,6 +1468,17 @@ static inline zig_i128 zig_subw_i128(zig_i128 lhs, zig_i128 rhs, zig_u8 bits) {
1394 return zig_wrap_i128(zig_bitcast_i128(zig_sub_u128(zig_bitcast_u128(lhs), zig_bitcast_u128(rhs))), bits);1468 return zig_wrap_i128(zig_bitcast_i128(zig_sub_u128(zig_bitcast_u128(lhs), zig_bitcast_u128(rhs))), bits);
1395}1469}
13961470
1471#if _MSC_VER
1472static 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
1479static zig_u128 zig_mul_u128(zig_u128 lhs, zig_u128 rhs); // TODO
1480#endif
1481
1397static inline zig_u128 zig_mulw_u128(zig_u128 lhs, zig_u128 rhs, zig_u8 bits) {1482static inline zig_u128 zig_mulw_u128(zig_u128 lhs, zig_u128 rhs, zig_u8 bits) {
1398 return zig_wrap_u128(zig_mul_u128(lhs, rhs), bits);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,18 +1489,6 @@ static inline zig_i128 zig_mulw_i128(zig_i128 lhs, zig_i128 rhs, zig_u8 bits) {
14041489
1405#if zig_has_int1281490#if zig_has_int128
14061491
1407static 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
1412static 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
1419static inline bool zig_addo_u128(zig_u128 *res, zig_u128 lhs, zig_u128 rhs, zig_u8 bits) {1492static inline bool zig_addo_u128(zig_u128 *res, zig_u128 lhs, zig_u128 rhs, zig_u8 bits) {
1420#if zig_has_builtin(add_overflow)1493#if zig_has_builtin(add_overflow)
1421 zig_u128 full_res;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,28 +1569,95 @@ static inline bool zig_mulo_i128(zig_i128 *res, zig_i128 lhs, zig_i128 rhs, zig_
14961569
1497#else /* zig_has_int128 */1570#else /* zig_has_int128 */
14981571
1499static inline bool zig_addo_u128(zig_u128 *res, zig_u128 lhs, zig_u128 rhs) {1572static inline bool zig_overflow_u128(bool overflow, zig_u128 full_res, zig_u8 bits) {
1500 return zig_addo_u64(&res->hi, lhs.hi, rhs.hi, UINT64_MAX) |1573 return overflow ||
1501 zig_addo_u64(&res->hi, res->hi, zig_addo_u64(&res->lo, lhs.lo, rhs.lo, UINT64_MAX));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
1578static 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
1584static 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
1593zig_extern zig_i128 __addoti4(zig_i128 lhs, zig_i128 rhs, zig_c_int *overflow);
1594static 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
1601static 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
1610zig_extern zig_i128 __suboti4(zig_i128 lhs, zig_i128 rhs, zig_c_int *overflow);
1611static 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
1618static 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}
15031623
1504static inline bool zig_subo_u128(zig_u128 *res, zig_u128 lhs, zig_u128 rhs) {1624zig_extern zig_i128 __muloti4(zig_i128 lhs, zig_i128 rhs, zig_c_int *overflow);
1505 return zig_subo_u64(&res->hi, lhs.hi, rhs.hi, UINT64_MAX) |1625static inline bool zig_mulo_i128(zig_i128 *res, zig_i128 lhs, zig_i128 rhs, zig_u8 bits) {
1506 zig_subo_u64(&res->hi, res->hi, zig_subo_u64(&res->lo, lhs.lo, rhs.lo, UINT64_MAX));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}
15081631
1509#endif /* zig_has_int128 */1632#endif /* zig_has_int128 */
15101633
1634static 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
1639static 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
1511static inline zig_u128 zig_shls_u128(zig_u128 lhs, zig_u128 rhs, zig_u8 bits) {1646static inline zig_u128 zig_shls_u128(zig_u128 lhs, zig_u128 rhs, zig_u8 bits) {
1512 zig_u128 res;1647 zig_u128 res;
1513 if (zig_cmp_u128(rhs, zig_as_u128(0, bits)) >= zig_as_i32(0))1648 if (zig_cmp_u128(rhs, zig_as_u128(0, bits)) >= zig_as_i32(0))
1514 return zig_cmp_u128(lhs, zig_as_u128(0, 0)) != zig_as_i32(0) ? zig_maxInt(u128, bits) : lhs;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 return zig_shlo_u128(&res, lhs, (zig_u8)rhs, bits) ? zig_maxInt(u128, bits) : res;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}
15171657
1518static inline zig_i128 zig_shls_i128(zig_i128 lhs, zig_i128 rhs, zig_u8 bits) {1658static inline zig_i128 zig_shls_i128(zig_i128 lhs, zig_i128 rhs, zig_u8 bits) {
1519 zig_i128 res;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 return zig_cmp_i128(lhs, zig_as_i128(0, 0)) < zig_as_i32(0) ? zig_minInt(i128, bits) : zig_maxInt(i128, bits);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}
15231663
...@@ -1555,8 +1695,9 @@ static inline zig_i128 zig_muls_i128(zig_i128 lhs, zig_i128 rhs, zig_u8 bits) {...@@ -1555,8 +1695,9 @@ static inline zig_i128 zig_muls_i128(zig_i128 lhs, zig_i128 rhs, zig_u8 bits) {
1555}1695}
15561696
1557static inline zig_u8 zig_clz_u128(zig_u128 val, zig_u8 bits) {1697static 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 if (zig_hi_u128(val) != 0) return zig_clz_u64(zig_hi_u128(val), bits - zig_as_u8(64));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}
15611702
1562static inline zig_u8 zig_clz_i128(zig_i128 val, zig_u8 bits) {1703static 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,7 +1734,7 @@ static inline zig_u128 zig_byte_swap_u128(zig_u128 val, zig_u8 bits) {
1593}1734}
15941735
1595static inline zig_i128 zig_byte_swap_i128(zig_i128 val, zig_u8 bits) {1736static 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}
15981739
1599static inline zig_u128 zig_bit_reverse_u128(zig_u128 val, zig_u8 bits) {1740static 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,15 +1744,47 @@ static inline zig_u128 zig_bit_reverse_u128(zig_u128 val, zig_u8 bits) {
1603}1744}
16041745
1605static inline zig_i128 zig_bit_reverse_i128(zig_i128 val, zig_u8 bits) {1746static 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}
16081749
1609/* ========================= Floating Point Support ========================= */1750/* ========================= Floating Point Support ========================= */
16101751
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#define zig_has_f16 11784#define zig_has_f16 1
1612#define zig_bitSizeOf_f16 161785#define zig_bitSizeOf_f16 16
1613#define zig_libc_name_f16(name) __##name##h1786#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#if FLT_MANT_DIG == 111788#if FLT_MANT_DIG == 11
1616typedef float zig_f16;1789typedef float zig_f16;
1617#define zig_as_f16(fp, repr) fp##f1790#define zig_as_f16(fp, repr) fp##f
...@@ -1636,12 +1809,18 @@ typedef zig_i16 zig_f16;...@@ -1636,12 +1809,18 @@ typedef zig_i16 zig_f16;
1636#define zig_as_f16(fp, repr) repr1809#define zig_as_f16(fp, repr) repr
1637#undef zig_as_special_f161810#undef zig_as_special_f16
1638#define zig_as_special_f16(sign, name, arg, repr) repr1811#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#endif1814#endif
16401815
1641#define zig_has_f32 11816#define zig_has_f32 1
1642#define zig_bitSizeOf_f32 321817#define zig_bitSizeOf_f32 32
1643#define zig_libc_name_f32(name) name##f1818#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#if FLT_MANT_DIG == 241824#if FLT_MANT_DIG == 24
1646typedef float zig_f32;1825typedef float zig_f32;
1647#define zig_as_f32(fp, repr) fp##f1826#define zig_as_f32(fp, repr) fp##f
...@@ -1663,12 +1842,18 @@ typedef zig_i32 zig_f32;...@@ -1663,12 +1842,18 @@ typedef zig_i32 zig_f32;
1663#define zig_as_f32(fp, repr) repr1842#define zig_as_f32(fp, repr) repr
1664#undef zig_as_special_f321843#undef zig_as_special_f32
1665#define zig_as_special_f32(sign, name, arg, repr) repr1844#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#endif1847#endif
16671848
1668#define zig_has_f64 11849#define zig_has_f64 1
1669#define zig_bitSizeOf_f64 641850#define zig_bitSizeOf_f64 64
1670#define zig_libc_name_f64(name) name1851#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#if FLT_MANT_DIG == 531857#if FLT_MANT_DIG == 53
1673typedef float zig_f64;1858typedef float zig_f64;
1674#define zig_as_f64(fp, repr) fp##f1859#define zig_as_f64(fp, repr) fp##f
...@@ -1693,12 +1878,14 @@ typedef zig_i64 zig_f64;...@@ -1693,12 +1878,14 @@ typedef zig_i64 zig_f64;
1693#define zig_as_f64(fp, repr) repr1878#define zig_as_f64(fp, repr) repr
1694#undef zig_as_special_f641879#undef zig_as_special_f64
1695#define zig_as_special_f64(sign, name, arg, repr) repr1880#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#endif1883#endif
16971884
1698#define zig_has_f80 11885#define zig_has_f80 1
1699#define zig_bitSizeOf_f80 801886#define zig_bitSizeOf_f80 80
1700#define zig_libc_name_f80(name) __##name##x1887#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#if FLT_MANT_DIG == 641889#if FLT_MANT_DIG == 64
1703typedef float zig_f80;1890typedef float zig_f80;
1704#define zig_as_f80(fp, repr) fp##f1891#define zig_as_f80(fp, repr) fp##f
...@@ -1726,12 +1913,14 @@ typedef zig_i128 zig_f80;...@@ -1726,12 +1913,14 @@ typedef zig_i128 zig_f80;
1726#define zig_as_f80(fp, repr) repr1913#define zig_as_f80(fp, repr) repr
1727#undef zig_as_special_f801914#undef zig_as_special_f80
1728#define zig_as_special_f80(sign, name, arg, repr) repr1915#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#endif1918#endif
17301919
1731#define zig_has_f128 11920#define zig_has_f128 1
1732#define zig_bitSizeOf_f128 1281921#define zig_bitSizeOf_f128 128
1733#define zig_libc_name_f128(name) name##q1922#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#if FLT_MANT_DIG == 1131924#if FLT_MANT_DIG == 113
1736typedef float zig_f128;1925typedef float zig_f128;
1737#define zig_as_f128(fp, repr) fp##f1926#define zig_as_f128(fp, repr) fp##f
...@@ -1761,13 +1950,57 @@ typedef zig_i128 zig_f128;...@@ -1761,13 +1950,57 @@ typedef zig_i128 zig_f128;
1761#define zig_as_f128(fp, repr) repr1950#define zig_as_f128(fp, repr) repr
1762#undef zig_as_special_f1281951#undef zig_as_special_f128
1763#define zig_as_special_f128(sign, name, arg, repr) repr1952#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#endif1955#endif
17651956
1766#define zig_has_c_longdouble 11957#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
1767typedef long double zig_c_longdouble;1961typedef long double zig_c_longdouble;
1768#define zig_as_c_longdouble(fp, repr) fp##l1962#define zig_as_c_longdouble(fp, repr) fp##l
1769#define zig_libc_name_c_longdouble(name) name##l1963#else
1770#define zig_as_special_c_longdouble(sign, name, arg, repr) sign __builtin_##name##l(arg)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
1969typedef 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
1983zig_float_from_repr(f16, u16)
1984zig_float_from_repr(f32, u32)
1985zig_float_from_repr(f64, u64)
1986zig_float_from_repr(f80, u128)
1987zig_float_from_repr(f128, u128)
1988zig_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
17712004
1772#define zig_convert_builtin(ResType, operation, ArgType, version) \2005#define zig_convert_builtin(ResType, operation, ArgType, version) \
1773 zig_extern zig_##ResType zig_expand_concat(zig_expand_concat(zig_expand_concat(__##operation, \2006 zig_extern zig_##ResType zig_expand_concat(zig_expand_concat(zig_expand_concat(__##operation, \
...@@ -1892,3 +2125,268 @@ zig_float_builtins(f64)...@@ -1892,3 +2125,268 @@ zig_float_builtins(f64)
1892zig_float_builtins(f80)2125zig_float_builtins(f80)
1893zig_float_builtins(f128)2126zig_float_builtins(f128)
1894zig_float_builtins(c_longdouble)2127zig_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
2209zig_msvc_atomics(u8, 8)
2210zig_msvc_atomics(i8, 8)
2211zig_msvc_atomics(u16, 16)
2212zig_msvc_atomics(i16, 16)
2213zig_msvc_atomics(u32, )
2214zig_msvc_atomics(i32, )
2215zig_msvc_atomics(u64, 64)
2216zig_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
2255zig_msvc_flt_atomics(f32, u32, )
2256zig_msvc_flt_atomics(f64, u64, 64)
2257
2258#if _M_IX86
2259static inline void* zig_msvc_atomicrmw_xchg_p32(void** obj, zig_u32* arg) {
2260 return _InterlockedExchangePointer(obj, arg);
2261}
2262
2263static inline void zig_msvc_atomic_store_p32(void** obj, zig_u32* arg) {
2264 _InterlockedExchangePointer(obj, arg);
2265}
2266
2267static inline void* zig_msvc_atomic_load_p32(void** obj, zig_u32* arg) {
2268 return (void*)_InterlockedOr((void*)obj, 0);
2269}
2270
2271static 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
2281static inline void* zig_msvc_atomicrmw_xchg_p64(void** obj, zig_u64* arg) {
2282 return _InterlockedExchangePointer(obj, arg);
2283}
2284
2285static inline void zig_msvc_atomic_store_p64(void** obj, zig_u64* arg) {
2286 _InterlockedExchangePointer(obj, arg);
2287}
2288
2289static inline void* zig_msvc_atomic_load_p64(void** obj) {
2290 return (void*)_InterlockedOr64((void*)obj, 0);
2291}
2292
2293static 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
2304static 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
2308static 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
2323zig_msvc_atomics_128xchg(u128)
2324zig_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
2339zig_msvc_atomics_128op(u128, add)
2340zig_msvc_atomics_128op(u128, sub)
2341zig_msvc_atomics_128op(u128, or)
2342zig_msvc_atomics_128op(u128, xor)
2343zig_msvc_atomics_128op(u128, and)
2344zig_msvc_atomics_128op(u128, nand)
2345zig_msvc_atomics_128op(u128, min)
2346zig_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
2354static 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
2368static 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
2381static 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,7 +90,15 @@ const FormatTypeAsCIdentContext = struct {
90const ValueRenderLocation = enum {90const ValueRenderLocation = enum {
91 FunctionArgument,91 FunctionArgument,
92 Initializer,92 Initializer,
93 StaticInitializer,
93 Other,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};
95103
96const BuiltinInfo = enum {104const BuiltinInfo = enum {
...@@ -312,7 +320,7 @@ pub const Function = struct {...@@ -312,7 +320,7 @@ pub const Function = struct {
312 try writer.writeAll("static ");320 try writer.writeAll("static ");
313 try f.object.dg.renderTypeAndName(writer, ty, decl_c_value, .Const, alignment, .Complete);321 try f.object.dg.renderTypeAndName(writer, ty, decl_c_value, .Const, alignment, .Complete);
314 try writer.writeAll(" = ");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 try writer.writeAll(";\n ");324 try writer.writeAll(";\n ");
317 break :result decl_c_value;325 break :result decl_c_value;
318 } else CValue{ .constant = inst };326 } else CValue{ .constant = inst };
...@@ -431,6 +439,10 @@ pub const Function = struct {...@@ -431,6 +439,10 @@ pub const Function = struct {
431 return f.object.dg.renderTypecast(w, t);439 return f.object.dg.renderTypecast(w, t);
432 }440 }
433441
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 fn fmtIntLiteral(f: *Function, ty: Type, val: Value) !std.fmt.Formatter(formatIntLiteral) {446 fn fmtIntLiteral(f: *Function, ty: Type, val: Value) !std.fmt.Formatter(formatIntLiteral) {
435 return f.object.dg.fmtIntLiteral(ty, val);447 return f.object.dg.fmtIntLiteral(ty, val);
436 }448 }
...@@ -502,6 +514,7 @@ pub const DeclGen = struct {...@@ -502,6 +514,7 @@ pub const DeclGen = struct {
502 ty: Type,514 ty: Type,
503 val: Value,515 val: Value,
504 decl_index: Decl.Index,516 decl_index: Decl.Index,
517 location: ValueRenderLocation,
505 ) error{ OutOfMemory, AnalysisFail }!void {518 ) error{ OutOfMemory, AnalysisFail }!void {
506 const decl = dg.module.declPtr(decl_index);519 const decl = dg.module.declPtr(decl_index);
507 assert(decl.has_tv);520 assert(decl.has_tv);
...@@ -515,12 +528,16 @@ pub const DeclGen = struct {...@@ -515,12 +528,16 @@ pub const DeclGen = struct {
515 inline for (.{ .function, .extern_fn }) |tag|528 inline for (.{ .function, .extern_fn }) |tag|
516 if (decl.val.castTag(tag)) |func|529 if (decl.val.castTag(tag)) |func|
517 if (func.data.owner_decl != decl_index)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);
519532
520 if (ty.isSlice()) {533 if (ty.isSlice()) {
521 try writer.writeByte('(');534 if (location == .StaticInitializer) {
522 try dg.renderTypecast(writer, ty);535 try writer.writeByte('{');
523 try writer.writeAll("){ .ptr = ");536 } else {
537 try writer.writeByte('(');
538 try dg.renderTypecast(writer, ty);
539 try writer.writeAll("){ .ptr = ");
540 }
524541
525 var buf: Type.SlicePtrFieldTypeBuffer = undefined;542 var buf: Type.SlicePtrFieldTypeBuffer = undefined;
526 try dg.renderValue(writer, ty.slicePtrFieldType(&buf), val.slicePtr(), .Initializer);543 try dg.renderValue(writer, ty.slicePtrFieldType(&buf), val.slicePtr(), .Initializer);
...@@ -530,7 +547,12 @@ pub const DeclGen = struct {...@@ -530,7 +547,12 @@ pub const DeclGen = struct {
530 .data = val.sliceLen(dg.module),547 .data = val.sliceLen(dg.module),
531 };548 };
532 const len_val = Value.initPayload(&len_pl.base);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 }
535557
536 // We shouldn't cast C function pointers as this is UB (when you call558 // We shouldn't cast C function pointers as this is UB (when you call
...@@ -552,7 +574,7 @@ pub const DeclGen = struct {...@@ -552,7 +574,7 @@ pub const DeclGen = struct {
552 // that its contents are defined with respect to.574 // that its contents are defined with respect to.
553 //575 //
554 // Used for .elem_ptr, .field_ptr, .opt_payload_ptr, .eu_payload_ptr576 // 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 if (!ptr_ty.isSlice()) {578 if (!ptr_ty.isSlice()) {
557 try writer.writeByte('(');579 try writer.writeByte('(');
558 try dg.renderTypecast(writer, ptr_ty);580 try dg.renderTypecast(writer, ptr_ty);
...@@ -567,7 +589,7 @@ pub const DeclGen = struct {...@@ -567,7 +589,7 @@ pub const DeclGen = struct {
567 .variable => ptr_val.castTag(.variable).?.data.owner_decl,589 .variable => ptr_val.castTag(.variable).?.data.owner_decl,
568 else => unreachable,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 .field_ptr => {594 .field_ptr => {
573 const ptr_info = ptr_ty.ptrInfo();595 const ptr_info = ptr_ty.ptrInfo();
...@@ -605,7 +627,7 @@ pub const DeclGen = struct {...@@ -605,7 +627,7 @@ pub const DeclGen = struct {
605 try writer.writeAll("&((");627 try writer.writeAll("&((");
606 try dg.renderTypecast(writer, u8_ptr_ty);628 try dg.renderTypecast(writer, u8_ptr_ty);
607 try writer.writeByte(')');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 return writer.print(")[{}]", .{try dg.fmtIntLiteral(Type.usize, byte_offset_val)});631 return writer.print(")[{}]", .{try dg.fmtIntLiteral(Type.usize, byte_offset_val)});
610 } else {632 } else {
611 var host_pl = Type.Payload.Bits{633 var host_pl = Type.Payload.Bits{
...@@ -617,7 +639,7 @@ pub const DeclGen = struct {...@@ -617,7 +639,7 @@ pub const DeclGen = struct {
617 try writer.writeByte('(');639 try writer.writeByte('(');
618 try dg.renderTypecast(writer, ptr_ty);640 try dg.renderTypecast(writer, ptr_ty);
619 try writer.writeByte(')');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 .Union => switch (container_ty.containerLayout()) {645 .Union => switch (container_ty.containerLayout()) {
...@@ -626,7 +648,7 @@ pub const DeclGen = struct {...@@ -626,7 +648,7 @@ pub const DeclGen = struct {
626 .ty = container_ty.unionFields().values()[index].ty,648 .ty = container_ty.unionFields().values()[index].ty,
627 },649 },
628 .Packed => {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 .Pointer => field_info: {654 .Pointer => field_info: {
...@@ -645,7 +667,7 @@ pub const DeclGen = struct {...@@ -645,7 +667,7 @@ pub const DeclGen = struct {
645 try dg.renderType(std.io.null_writer, field_ptr.container_ty, .Complete);667 try dg.renderType(std.io.null_writer, field_ptr.container_ty, .Complete);
646668
647 try writer.writeAll("&(");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 try writer.writeAll(")->");671 try writer.writeAll(")->");
650 switch (field_ptr.container_ty.tag()) {672 switch (field_ptr.container_ty.tag()) {
651 .union_tagged, .union_safety_tagged => try writer.writeAll("payload."),673 .union_tagged, .union_safety_tagged => try writer.writeAll("payload."),
...@@ -653,7 +675,7 @@ pub const DeclGen = struct {...@@ -653,7 +675,7 @@ pub const DeclGen = struct {
653 }675 }
654 try writer.print("{ }", .{fmtIdent(field_info.name)});676 try writer.print("{ }", .{fmtIdent(field_info.name)});
655 } else {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 .elem_ptr => {681 .elem_ptr => {
...@@ -665,7 +687,7 @@ pub const DeclGen = struct {...@@ -665,7 +687,7 @@ pub const DeclGen = struct {
665 const elem_ptr_ty = Type.initPayload(&elem_ptr_ty_pl.base);687 const elem_ptr_ty = Type.initPayload(&elem_ptr_ty_pl.base);
666688
667 try writer.writeAll("&(");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 try writer.print(")[{d}]", .{elem_ptr.index});691 try writer.print(")[{d}]", .{elem_ptr.index});
670 },692 },
671 .opt_payload_ptr, .eu_payload_ptr => {693 .opt_payload_ptr, .eu_payload_ptr => {
...@@ -680,7 +702,7 @@ pub const DeclGen = struct {...@@ -680,7 +702,7 @@ pub const DeclGen = struct {
680 try dg.renderType(std.io.null_writer, payload_ptr.container_ty, .Complete);702 try dg.renderType(std.io.null_writer, payload_ptr.container_ty, .Complete);
681703
682 try writer.writeAll("&(");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 try writer.writeAll(")->payload");706 try writer.writeAll(")->payload");
685 },707 },
686 else => unreachable,708 else => unreachable,
...@@ -699,6 +721,10 @@ pub const DeclGen = struct {...@@ -699,6 +721,10 @@ pub const DeclGen = struct {
699 val = rt.data;721 val = rt.data;
700 }722 }
701 const target = dg.module.getTarget();723 const target = dg.module.getTarget();
724 const initializer_type: ValueRenderLocation = switch (location) {
725 .StaticInitializer => .StaticInitializer,
726 else => .Initializer,
727 };
702728
703 const safety_on = switch (dg.module.optimizeMode()) {729 const safety_on = switch (dg.module.optimizeMode()) {
704 .Debug, .ReleaseSafe => true,730 .Debug, .ReleaseSafe => true,
...@@ -714,15 +740,15 @@ pub const DeclGen = struct {...@@ -714,15 +740,15 @@ pub const DeclGen = struct {
714 return writer.writeAll("false");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 .Float => {744 .Float => {
719 const bits = ty.floatBits(target);745 const bits = ty.floatBits(target);
720 var int_pl = Type.Payload.Bits{ .base = .{ .tag = .int_signed }, .data = bits };746 var int_pl = Type.Payload.Bits{ .base = .{ .tag = .int_signed }, .data = bits };
721 const int_ty = Type.initPayload(&int_pl.base);747 const int_ty = Type.initPayload(&int_pl.base);
722748
723 try writer.writeByte('(');749 try writer.writeAll("zig_cast_");
724 try dg.renderTypecast(writer, ty);750 try dg.renderTypeForBuiltinFnName(writer, ty);
725 try writer.writeAll(")zig_as_");751 try writer.writeAll(" zig_as_");
726 try dg.renderTypeForBuiltinFnName(writer, ty);752 try dg.renderTypeForBuiltinFnName(writer, ty);
727 try writer.writeByte('(');753 try writer.writeByte('(');
728 switch (bits) {754 switch (bits) {
...@@ -738,7 +764,7 @@ pub const DeclGen = struct {...@@ -738,7 +764,7 @@ pub const DeclGen = struct {
738 return writer.writeByte(')');764 return writer.writeByte(')');
739 },765 },
740 .Pointer => if (ty.isSlice()) {766 .Pointer => if (ty.isSlice()) {
741 if (location != .Initializer) {767 if (!location.isInitializer()) {
742 try writer.writeByte('(');768 try writer.writeByte('(');
743 try dg.renderTypecast(writer, ty);769 try dg.renderTypecast(writer, ty);
744 try writer.writeByte(')');770 try writer.writeByte(')');
...@@ -766,21 +792,21 @@ pub const DeclGen = struct {...@@ -766,21 +792,21 @@ pub const DeclGen = struct {
766 return dg.renderValue(writer, payload_ty, val, location);792 return dg.renderValue(writer, payload_ty, val, location);
767 }793 }
768794
769 if (location != .Initializer) {795 if (!location.isInitializer()) {
770 try writer.writeByte('(');796 try writer.writeByte('(');
771 try dg.renderTypecast(writer, ty);797 try dg.renderTypecast(writer, ty);
772 try writer.writeByte(')');798 try writer.writeByte(')');
773 }799 }
774800
775 try writer.writeAll("{ .payload = ");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 try writer.writeAll(", .is_null = ");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 return writer.writeAll(" }");805 return writer.writeAll(" }");
780 },806 },
781 .Struct => switch (ty.containerLayout()) {807 .Struct => switch (ty.containerLayout()) {
782 .Auto, .Extern => {808 .Auto, .Extern => {
783 if (location != .Initializer) {809 if (!location.isInitializer()) {
784 try writer.writeByte('(');810 try writer.writeByte('(');
785 try dg.renderTypecast(writer, ty);811 try dg.renderTypecast(writer, ty);
786 try writer.writeByte(')');812 try writer.writeByte(')');
...@@ -792,7 +818,7 @@ pub const DeclGen = struct {...@@ -792,7 +818,7 @@ pub const DeclGen = struct {
792 if (!field.ty.hasRuntimeBits()) continue;818 if (!field.ty.hasRuntimeBits()) continue;
793819
794 if (!empty) try writer.writeByte(',');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);
796822
797 empty = false;823 empty = false;
798 }824 }
...@@ -802,7 +828,7 @@ pub const DeclGen = struct {...@@ -802,7 +828,7 @@ pub const DeclGen = struct {
802 .Packed => return writer.print("{x}", .{try dg.fmtIntLiteral(ty, Value.undef)}),828 .Packed => return writer.print("{x}", .{try dg.fmtIntLiteral(ty, Value.undef)}),
803 },829 },
804 .Union => {830 .Union => {
805 if (location != .Initializer) {831 if (!location.isInitializer()) {
806 try writer.writeByte('(');832 try writer.writeByte('(');
807 try dg.renderTypecast(writer, ty);833 try dg.renderTypecast(writer, ty);
808 try writer.writeByte(')');834 try writer.writeByte(')');
...@@ -813,34 +839,34 @@ pub const DeclGen = struct {...@@ -813,34 +839,34 @@ pub const DeclGen = struct {
813 const layout = ty.unionGetLayout(target);839 const layout = ty.unionGetLayout(target);
814 if (layout.tag_size != 0) {840 if (layout.tag_size != 0) {
815 try writer.writeAll(" .tag = ");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 try writer.writeByte(',');843 try writer.writeByte(',');
818 }844 }
819 try writer.writeAll(" .payload = {");845 try writer.writeAll(" .payload = {");
820 }846 }
821 for (ty.unionFields().values()) |field| {847 for (ty.unionFields().values()) |field| {
822 if (!field.ty.hasRuntimeBits()) continue;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 break;850 break;
825 } else try writer.print("{x}", .{try dg.fmtIntLiteral(Type.u8, Value.undef)});851 } else try writer.print("{x}", .{try dg.fmtIntLiteral(Type.u8, Value.undef)});
826 if (ty.unionTagTypeSafety()) |_| try writer.writeByte('}');852 if (ty.unionTagTypeSafety()) |_| try writer.writeByte('}');
827 return writer.writeByte('}');853 return writer.writeByte('}');
828 },854 },
829 .ErrorUnion => {855 .ErrorUnion => {
830 if (location != .Initializer) {856 if (!location.isInitializer()) {
831 try writer.writeByte('(');857 try writer.writeByte('(');
832 try dg.renderTypecast(writer, ty);858 try dg.renderTypecast(writer, ty);
833 try writer.writeByte(')');859 try writer.writeByte(')');
834 }860 }
835861
836 try writer.writeAll("{ .payload = ");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 return writer.print(", .error = {x} }}", .{864 return writer.print(", .error = {x} }}", .{
839 try dg.fmtIntLiteral(ty.errorUnionSet(), val),865 try dg.fmtIntLiteral(ty.errorUnionSet(), val),
840 });866 });
841 },867 },
842 .Array, .Vector => {868 .Array, .Vector => {
843 if (location != .Initializer) {869 if (!location.isInitializer()) {
844 try writer.writeByte('(');870 try writer.writeByte('(');
845 try dg.renderTypecast(writer, ty);871 try dg.renderTypecast(writer, ty);
846 try writer.writeByte(')');872 try writer.writeByte(')');
...@@ -848,19 +874,20 @@ pub const DeclGen = struct {...@@ -848,19 +874,20 @@ pub const DeclGen = struct {
848874
849 const ai = ty.arrayInfo();875 const ai = ty.arrayInfo();
850 if (ai.elem_type.eql(Type.u8, dg.module)) {876 if (ai.elem_type.eql(Type.u8, dg.module)) {
851 try writer.writeByte('"');877 var literal = stringLiteral(writer);
878 try literal.start();
852 const c_len = ty.arrayLenIncludingSentinel();879 const c_len = ty.arrayLenIncludingSentinel();
853 var index: usize = 0;880 var index: usize = 0;
854 while (index < c_len) : (index += 1)881 while (index < c_len) : (index += 1)
855 try writeStringLiteralChar(writer, 0xaa);882 try literal.writeChar(0xaa);
856 return writer.writeByte('"');883 return literal.end();
857 } else {884 } else {
858 try writer.writeByte('{');885 try writer.writeByte('{');
859 const c_len = ty.arrayLenIncludingSentinel();886 const c_len = ty.arrayLenIncludingSentinel();
860 var index: usize = 0;887 var index: usize = 0;
861 while (index < c_len) : (index += 1) {888 while (index < c_len) : (index += 1) {
862 if (index > 0) try writer.writeAll(", ");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 return writer.writeByte('}');892 return writer.writeByte('}');
866 }893 }
...@@ -893,8 +920,8 @@ pub const DeclGen = struct {...@@ -893,8 +920,8 @@ pub const DeclGen = struct {
893 .eu_payload_ptr,920 .eu_payload_ptr,
894 .decl_ref_mut,921 .decl_ref_mut,
895 .decl_ref,922 .decl_ref,
896 => try dg.renderParentPtr(writer, val, ty),923 => try dg.renderParentPtr(writer, val, ty, location),
897 else => try writer.print("{}", .{try dg.fmtIntLiteral(ty, val)}),924 else => try writer.print("{}", .{try dg.fmtIntLiteralLoc(ty, val, location)}),
898 },925 },
899 .Float => {926 .Float => {
900 const bits = ty.floatBits(target);927 const bits = ty.floatBits(target);
...@@ -926,9 +953,10 @@ pub const DeclGen = struct {...@@ -926,9 +953,10 @@ pub const DeclGen = struct {
926 };953 };
927 const int_val = Value.initPayload(&int_val_pl.base);954 const int_val = Value.initPayload(&int_val_pl.base);
928955
929 try writer.writeByte('(');956 try writer.writeAll("zig_cast_");
930 try dg.renderTypecast(writer, ty);957 try dg.renderTypeForBuiltinFnName(writer, ty);
931 try writer.writeByte(')');958 try writer.writeByte(' ');
959 var empty = true;
932 if (std.math.isFinite(f128_val)) {960 if (std.math.isFinite(f128_val)) {
933 try writer.writeAll("zig_as_");961 try writer.writeAll("zig_as_");
934 try dg.renderTypeForBuiltinFnName(writer, ty);962 try dg.renderTypeForBuiltinFnName(writer, ty);
...@@ -941,17 +969,32 @@ pub const DeclGen = struct {...@@ -941,17 +969,32 @@ pub const DeclGen = struct {
941 128 => try writer.print("{x}", .{f128_val}),969 128 => try writer.print("{x}", .{f128_val}),
942 else => unreachable,970 else => unreachable,
943 }971 }
972 try writer.writeAll(", ");
973 empty = false;
944 } else {974 } else {
945 const operation = if (std.math.isSignalNan(f128_val))975 // isSignalNan is equivalent to isNan currently, and MSVC doens't have nans, so prefer nan
946 "nans"976 const operation = if (std.math.isNan(f128_val))
947 else if (std.math.isNan(f128_val))
948 "nan"977 "nan"
978 else if (std.math.isSignalNan(f128_val))
979 "nans"
949 else if (std.math.isInf(f128_val))980 else if (std.math.isInf(f128_val))
950 "inf"981 "inf"
951 else982 else
952 unreachable;983 unreachable;
953984
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 try writer.writeAll("zig_as_special_");996 try writer.writeAll("zig_as_special_");
997 if (location == .StaticInitializer) try writer.writeAll("constant_");
955 try dg.renderTypeForBuiltinFnName(writer, ty);998 try dg.renderTypeForBuiltinFnName(writer, ty);
956 try writer.writeByte('(');999 try writer.writeByte('(');
957 if (std.math.signbit(f128_val)) try writer.writeByte('-');1000 if (std.math.signbit(f128_val)) try writer.writeByte('-');
...@@ -968,8 +1011,12 @@ pub const DeclGen = struct {...@@ -968,8 +1011,12 @@ pub const DeclGen = struct {
968 128 => try writer.print("\"0x{x}\"", .{@bitCast(u128, f128_val)}),1011 128 => try writer.print("\"0x{x}\"", .{@bitCast(u128, f128_val)}),
969 else => unreachable,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 .Pointer => switch (val.tag()) {1021 .Pointer => switch (val.tag()) {
975 .null_value, .zero => if (ty.isSlice()) {1022 .null_value, .zero => if (ty.isSlice()) {
...@@ -987,10 +1034,10 @@ pub const DeclGen = struct {...@@ -987,10 +1034,10 @@ pub const DeclGen = struct {
987 },1034 },
988 .variable => {1035 .variable => {
989 const decl = val.castTag(.variable).?.data.owner_decl;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 .slice => {1039 .slice => {
993 if (location != .Initializer) {1040 if (!location.isInitializer()) {
994 try writer.writeByte('(');1041 try writer.writeByte('(');
995 try dg.renderTypecast(writer, ty);1042 try dg.renderTypecast(writer, ty);
996 try writer.writeByte(')');1043 try writer.writeByte(')');
...@@ -1000,9 +1047,9 @@ pub const DeclGen = struct {...@@ -1000,9 +1047,9 @@ pub const DeclGen = struct {
1000 var buf: Type.SlicePtrFieldTypeBuffer = undefined;1047 var buf: Type.SlicePtrFieldTypeBuffer = undefined;
10011048
1002 try writer.writeByte('{');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 try writer.writeAll(", ");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 try writer.writeByte('}');1053 try writer.writeByte('}');
1007 },1054 },
1008 .function => {1055 .function => {
...@@ -1024,7 +1071,7 @@ pub const DeclGen = struct {...@@ -1024,7 +1071,7 @@ pub const DeclGen = struct {
1024 .eu_payload_ptr,1071 .eu_payload_ptr,
1025 .decl_ref_mut,1072 .decl_ref_mut,
1026 .decl_ref,1073 .decl_ref,
1027 => try dg.renderParentPtr(writer, val, ty),1074 => try dg.renderParentPtr(writer, val, ty, location),
1028 else => unreachable,1075 else => unreachable,
1029 },1076 },
1030 .Array, .Vector => {1077 .Array, .Vector => {
...@@ -1040,7 +1087,7 @@ pub const DeclGen = struct {...@@ -1040,7 +1087,7 @@ pub const DeclGen = struct {
1040 try writer.writeByte('{');1087 try writer.writeByte('{');
1041 const ai = ty.arrayInfo();1088 const ai = ty.arrayInfo();
1042 if (ai.sentinel) |s| {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 } else {1091 } else {
1045 try writer.writeByte('0');1092 try writer.writeByte('0');
1046 }1093 }
...@@ -1060,34 +1107,51 @@ pub const DeclGen = struct {...@@ -1060,34 +1107,51 @@ pub const DeclGen = struct {
1060 defer arena.deinit();1107 defer arena.deinit();
1061 const arena_allocator = arena.allocator();1108 const arena_allocator = arena.allocator();
10621109
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 const ai = ty.arrayInfo();1113 const ai = ty.arrayInfo();
1064 if (ai.elem_type.eql(Type.u8, dg.module)) {1114 if (ai.elem_type.eql(Type.u8, dg.module)) {
1065 try writer.writeByte('"');1115 if (ai.len <= max_string_initializer_len) {
1066 var index: usize = 0;1116 var literal = stringLiteral(writer);
1067 while (index < ai.len) : (index += 1) {1117 try literal.start();
1068 const elem_val = try val.elemValue(dg.module, arena_allocator, index);1118 var index: usize = 0;
1069 const elem_val_u8 = if (elem_val.isUndef())1119 while (index < ai.len) : (index += 1) {
1070 undefPattern(u8)1120 const elem_val = try val.elemValue(dg.module, arena_allocator, index);
1071 else1121 const elem_val_u8 = if (elem_val.isUndef()) undefPattern(u8) else @intCast(u8, elem_val.toUnsignedInt(target));
1072 @intCast(u8, elem_val.toUnsignedInt(target));1122 try literal.writeChar(elem_val_u8);
1073 try writeStringLiteralChar(writer, elem_val_u8);1123 }
1074 }1124 if (ai.sentinel) |s| {
1075 if (ai.sentinel) |s| {1125 const s_u8 = @intCast(u8, s.toUnsignedInt(target));
1076 const s_u8 = @intCast(u8, s.toUnsignedInt(target));1126 try literal.writeChar(s_u8);
1077 try writeStringLiteralChar(writer, 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 } else {1144 } else {
1081 try writer.writeByte('{');1145 try writer.writeByte('{');
1082 var index: usize = 0;1146 var index: usize = 0;
1083 while (index < ai.len) : (index += 1) {1147 while (index < ai.len) : (index += 1) {
1084 if (index != 0) try writer.writeByte(',');1148 if (index != 0) try writer.writeByte(',');
1085 const elem_val = try val.elemValue(dg.module, arena_allocator, index);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 if (ai.sentinel) |s| {1152 if (ai.sentinel) |s| {
1089 if (index != 0) try writer.writeByte(',');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 try writer.writeByte('}');1156 try writer.writeByte('}');
1093 }1157 }
...@@ -1114,7 +1178,7 @@ pub const DeclGen = struct {...@@ -1114,7 +1178,7 @@ pub const DeclGen = struct {
1114 return dg.renderValue(writer, payload_ty, payload_val, location);1178 return dg.renderValue(writer, payload_ty, payload_val, location);
1115 }1179 }
11161180
1117 if (location != .Initializer) {1181 if (!location.isInitializer()) {
1118 try writer.writeByte('(');1182 try writer.writeByte('(');
1119 try dg.renderTypecast(writer, ty);1183 try dg.renderTypecast(writer, ty);
1120 try writer.writeByte(')');1184 try writer.writeByte(')');
...@@ -1123,9 +1187,9 @@ pub const DeclGen = struct {...@@ -1123,9 +1187,9 @@ pub const DeclGen = struct {
1123 const payload_val = if (val.castTag(.opt_payload)) |pl| pl.data else Value.undef;1187 const payload_val = if (val.castTag(.opt_payload)) |pl| pl.data else Value.undef;
11241188
1125 try writer.writeAll("{ .payload = ");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 try writer.writeAll(", .is_null = ");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 try writer.writeAll(" }");1193 try writer.writeAll(" }");
1130 },1194 },
1131 .ErrorSet => {1195 .ErrorSet => {
...@@ -1148,7 +1212,7 @@ pub const DeclGen = struct {...@@ -1148,7 +1212,7 @@ pub const DeclGen = struct {
1148 return dg.renderValue(writer, error_ty, val, location);1212 return dg.renderValue(writer, error_ty, val, location);
1149 }1213 }
11501214
1151 if (location != .Initializer) {1215 if (!location.isInitializer()) {
1152 try writer.writeByte('(');1216 try writer.writeByte('(');
1153 try dg.renderTypecast(writer, ty);1217 try dg.renderTypecast(writer, ty);
1154 try writer.writeByte(')');1218 try writer.writeByte(')');
...@@ -1158,9 +1222,9 @@ pub const DeclGen = struct {...@@ -1158,9 +1222,9 @@ pub const DeclGen = struct {
1158 const error_val = if (val.errorUnionIsPayload()) Value.zero else val;1222 const error_val = if (val.errorUnionIsPayload()) Value.zero else val;
11591223
1160 try writer.writeAll("{ .payload = ");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 try writer.writeAll(", .error = ");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 try writer.writeAll(" }");1228 try writer.writeAll(" }");
1165 },1229 },
1166 .Enum => {1230 .Enum => {
...@@ -1200,11 +1264,11 @@ pub const DeclGen = struct {...@@ -1200,11 +1264,11 @@ pub const DeclGen = struct {
1200 .Fn => switch (val.tag()) {1264 .Fn => switch (val.tag()) {
1201 .function => {1265 .function => {
1202 const decl = val.castTag(.function).?.data.owner_decl;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 .extern_fn => {1269 .extern_fn => {
1206 const decl = val.castTag(.extern_fn).?.data.owner_decl;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 else => unreachable,1273 else => unreachable,
1210 },1274 },
...@@ -1212,7 +1276,7 @@ pub const DeclGen = struct {...@@ -1212,7 +1276,7 @@ pub const DeclGen = struct {
1212 .Auto, .Extern => {1276 .Auto, .Extern => {
1213 const field_vals = val.castTag(.aggregate).?.data;1277 const field_vals = val.castTag(.aggregate).?.data;
12141278
1215 if (location != .Initializer) {1279 if (!location.isInitializer()) {
1216 try writer.writeByte('(');1280 try writer.writeByte('(');
1217 try dg.renderTypecast(writer, ty);1281 try dg.renderTypecast(writer, ty);
1218 try writer.writeByte(')');1282 try writer.writeByte(')');
...@@ -1225,7 +1289,7 @@ pub const DeclGen = struct {...@@ -1225,7 +1289,7 @@ pub const DeclGen = struct {
1225 if (!field_ty.hasRuntimeBits()) continue;1289 if (!field_ty.hasRuntimeBits()) continue;
12261290
1227 if (!empty) try writer.writeByte(',');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);
12291293
1230 empty = false;1294 empty = false;
1231 }1295 }
...@@ -1245,31 +1309,85 @@ pub const DeclGen = struct {...@@ -1245,31 +1309,85 @@ pub const DeclGen = struct {
1245 var bit_offset_val_pl: Value.Payload.U64 = .{ .base = .{ .tag = .int_u64 }, .data = 0 };1309 var bit_offset_val_pl: Value.Payload.U64 = .{ .base = .{ .tag = .int_u64 }, .data = 0 };
1246 const bit_offset_val = Value.initPayload(&bit_offset_val_pl.base);1310 const bit_offset_val = Value.initPayload(&bit_offset_val_pl.base);
12471311
1248 try writer.writeByte('(');1312 var eff_num_fields: usize = 0;
1249 var empty = true;1313 for (field_vals) |_, index| {
1250 for (field_vals) |field_val, index| {
1251 const field_ty = ty.structFieldType(index);1314 const field_ty = ty.structFieldType(index);
1252 if (!field_ty.hasRuntimeBitsIgnoreComptime()) continue;1315 if (!field_ty.hasRuntimeBitsIgnoreComptime()) continue;
12531316
1254 if (!empty) try writer.writeAll(" | ");1317 eff_num_fields += 1;
1318 }
1319
1320 if (eff_num_fields == 0) {
1255 try writer.writeByte('(');1321 try writer.writeByte('(');
1256 try dg.renderTypecast(writer, ty);1322 try dg.renderValue(writer, ty, Value.undef, initializer_type);
1257 try writer.writeByte(')');1323 try writer.writeByte(')');
1258 try dg.renderValue(writer, field_ty, field_val, .Other);1324 } else if (ty.bitSize(target) > 64) {
1259 try writer.writeAll(" << ");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))
1260 try dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument);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 }
12611332
1262 bit_offset_val_pl.data += field_ty.bitSize(target);1333 var eff_index: usize = 0;
1263 empty = false;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 .Union => {1387 .Union => {
1270 const union_obj = val.castTag(.@"union").?.data;1388 const union_obj = val.castTag(.@"union").?.data;
12711389
1272 if (location != .Initializer) {1390 if (!location.isInitializer()) {
1273 try writer.writeByte('(');1391 try writer.writeByte('(');
1274 try dg.renderTypecast(writer, ty);1392 try dg.renderTypecast(writer, ty);
1275 try writer.writeByte(')');1393 try writer.writeByte(')');
...@@ -1289,7 +1407,7 @@ pub const DeclGen = struct {...@@ -1289,7 +1407,7 @@ pub const DeclGen = struct {
1289 try dg.renderTypecast(writer, ty);1407 try dg.renderTypecast(writer, ty);
1290 try writer.writeByte(')');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 } else {1411 } else {
1294 try writer.writeAll("0");1412 try writer.writeAll("0");
1295 }1413 }
...@@ -1301,7 +1419,7 @@ pub const DeclGen = struct {...@@ -1301,7 +1419,7 @@ pub const DeclGen = struct {
1301 const layout = ty.unionGetLayout(target);1419 const layout = ty.unionGetLayout(target);
1302 if (layout.tag_size != 0) {1420 if (layout.tag_size != 0) {
1303 try writer.writeAll(".tag = ");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 try writer.writeAll(", ");1423 try writer.writeAll(", ");
1306 }1424 }
1307 try writer.writeAll(".payload = {");1425 try writer.writeAll(".payload = {");
...@@ -1310,11 +1428,11 @@ pub const DeclGen = struct {...@@ -1310,11 +1428,11 @@ pub const DeclGen = struct {
1310 var it = ty.unionFields().iterator();1428 var it = ty.unionFields().iterator();
1311 if (field_ty.hasRuntimeBits()) {1429 if (field_ty.hasRuntimeBits()) {
1312 try writer.print(".{ } = ", .{fmtIdent(field_name)});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 } else while (it.next()) |field| {1432 } else while (it.next()) |field| {
1315 if (!field.value_ptr.ty.hasRuntimeBits()) continue;1433 if (!field.value_ptr.ty.hasRuntimeBits()) continue;
1316 try writer.print(".{ } = ", .{fmtIdent(field.key_ptr.*)});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 break;1436 break;
1319 } else try writer.writeAll(".empty_union = 0");1437 } else try writer.writeAll(".empty_union = 0");
1320 if (ty.unionTagTypeSafety()) |_| try writer.writeByte('}');1438 if (ty.unionTagTypeSafety()) |_| try writer.writeByte('}');
...@@ -2085,6 +2203,103 @@ pub const DeclGen = struct {...@@ -2085,6 +2203,103 @@ pub const DeclGen = struct {
2085 });2203 });
2086 }2204 }
20872205
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 /// Renders a type in C typecast format.2303 /// Renders a type in C typecast format.
2089 ///2304 ///
2090 /// This is guaranteed to be valid in a typecast expression, but not2305 /// This is guaranteed to be valid in a typecast expression, but not
...@@ -2134,7 +2349,7 @@ pub const DeclGen = struct {...@@ -2134,7 +2349,7 @@ pub const DeclGen = struct {
2134 const c_len_val = Value.initPayload(&c_len_pl.base);2349 const c_len_val = Value.initPayload(&c_len_pl.base);
21352350
2136 try suffix_writer.writeByte('[');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 try suffix.writer().print("{}]", .{try dg.fmtIntLiteral(Type.usize, c_len_val)});2353 try suffix.writer().print("{}]", .{try dg.fmtIntLiteral(Type.usize, c_len_val)});
2139 render_ty = array_info.elem_type;2354 render_ty = array_info.elem_type;
2140 depth += 1;2355 depth += 1;
...@@ -2306,6 +2521,9 @@ pub const DeclGen = struct {...@@ -2306,6 +2521,9 @@ pub const DeclGen = struct {
2306 try dg.writeCValue(writer, member);2521 try dg.writeCValue(writer, member);
2307 }2522 }
23082523
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 fn renderDeclName(dg: *DeclGen, writer: anytype, decl_index: Decl.Index, export_index: u32) !void {2527 fn renderDeclName(dg: *DeclGen, writer: anytype, decl_index: Decl.Index, export_index: u32) !void {
2310 const decl = dg.module.declPtr(decl_index);2528 const decl = dg.module.declPtr(decl_index);
2311 dg.module.markDeclAlive(decl);2529 dg.module.markDeclAlive(decl);
...@@ -2323,7 +2541,18 @@ pub const DeclGen = struct {...@@ -2323,7 +2541,18 @@ pub const DeclGen = struct {
2323 const gpa = dg.gpa;2541 const gpa = dg.gpa;
2324 const name = try decl.getFullyQualifiedName(dg.module);2542 const name = try decl.getFullyQualifiedName(dg.module);
2325 defer gpa.free(name);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 }
23292558
...@@ -2336,6 +2565,10 @@ pub const DeclGen = struct {...@@ -2336,6 +2565,10 @@ pub const DeclGen = struct {
2336 try writer.print("{c}{d}", .{ signAbbrev(int_info.signedness), c_bits });2565 try writer.print("{c}{d}", .{ signAbbrev(int_info.signedness), c_bits });
2337 } else if (ty.isRuntimeFloat()) {2566 } else if (ty.isRuntimeFloat()) {
2338 try ty.print(writer, dg.module);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 } else return dg.fail("TODO: CBE: implement renderTypeForBuiltinFnName for type {}", .{2572 } else return dg.fail("TODO: CBE: implement renderTypeForBuiltinFnName for type {}", .{
2340 ty.fmt(dg.module),2573 ty.fmt(dg.module),
2341 });2574 });
...@@ -2388,6 +2621,19 @@ pub const DeclGen = struct {...@@ -2388,6 +2621,19 @@ pub const DeclGen = struct {
2388 .mod = dg.module,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};
23922638
2393pub fn genGlobalAsm(mod: *Module, code: *std.ArrayList(u8)) !void {2639pub fn genGlobalAsm(mod: *Module, code: *std.ArrayList(u8)) !void {
...@@ -2433,7 +2679,7 @@ pub fn genErrDecls(o: *Object) !void {...@@ -2433,7 +2679,7 @@ pub fn genErrDecls(o: *Object) !void {
2433 try writer.writeAll("static ");2679 try writer.writeAll("static ");
2434 try o.dg.renderTypeAndName(writer, name_ty, .{ .identifier = identifier }, .Const, 0, .Complete);2680 try o.dg.renderTypeAndName(writer, name_ty, .{ .identifier = identifier }, .Const, 0, .Complete);
2435 try writer.writeAll(" = ");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 try writer.writeAll(";\n");2683 try writer.writeAll(";\n");
2438 }2684 }
24392685
...@@ -2604,7 +2850,7 @@ pub fn genDecl(o: *Object) !void {...@@ -2604,7 +2850,7 @@ pub fn genDecl(o: *Object) !void {
2604 if (variable.is_threadlocal) try w.writeAll("zig_threadlocal ");2850 if (variable.is_threadlocal) try w.writeAll("zig_threadlocal ");
2605 try o.dg.renderTypeAndName(w, o.dg.decl.ty, decl_c_value, .Mut, o.dg.decl.@"align", .Complete);2851 try o.dg.renderTypeAndName(w, o.dg.decl.ty, decl_c_value, .Mut, o.dg.decl.@"align", .Complete);
2606 try w.writeAll(" = ");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 try w.writeByte(';');2854 try w.writeByte(';');
2609 try o.indent_writer.insertNewline();2855 try o.indent_writer.insertNewline();
2610 } else {2856 } else {
...@@ -2621,7 +2867,7 @@ pub fn genDecl(o: *Object) !void {...@@ -2621,7 +2867,7 @@ pub fn genDecl(o: *Object) !void {
2621 // https://github.com/ziglang/zig/issues/75822867 // https://github.com/ziglang/zig/issues/7582
2622 try o.dg.renderTypeAndName(writer, tv.ty, decl_c_value, .Mut, o.dg.decl.@"align", .Complete);2868 try o.dg.renderTypeAndName(writer, tv.ty, decl_c_value, .Mut, o.dg.decl.@"align", .Complete);
2623 try writer.writeAll(" = ");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 try writer.writeAll(";\n");2871 try writer.writeAll(";\n");
2626 }2872 }
2627}2873}
...@@ -3244,11 +3490,20 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3244,11 +3490,20 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {
3244 try f.object.dg.renderTypeForBuiltinFnName(writer, field_ty);3490 try f.object.dg.renderTypeForBuiltinFnName(writer, field_ty);
3245 try writer.writeAll("((");3491 try writer.writeAll("((");
3246 try f.renderTypecast(writer, field_ty);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 try f.object.dg.renderTypeForBuiltinFnName(writer, host_ty);3502 try f.object.dg.renderTypeForBuiltinFnName(writer, host_ty);
3249 try writer.writeByte('(');3503 try writer.writeByte('(');
3250 try f.writeCValueDeref(writer, operand);3504 try f.writeCValueDeref(writer, operand);
3251 try writer.print(", {})", .{try f.fmtIntLiteral(bit_offset_ty, bit_offset_val)});3505 try writer.print(", {})", .{try f.fmtIntLiteral(bit_offset_ty, bit_offset_val)});
3506 if (cant_cast) try writer.writeByte(')');
3252 try f.object.dg.renderBuiltinInfo(writer, field_ty, .Bits);3507 try f.object.dg.renderBuiltinInfo(writer, field_ty, .Bits);
3253 try writer.writeByte(')');3508 try writer.writeByte(')');
3254 } else {3509 } else {
...@@ -3322,11 +3577,11 @@ fn airIntCast(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3322,11 +3577,11 @@ fn airIntCast(f: *Function, inst: Air.Inst.Index) !CValue {
3322 const writer = f.object.writer();3577 const writer = f.object.writer();
3323 const inst_ty = f.air.typeOfIndex(inst);3578 const inst_ty = f.air.typeOfIndex(inst);
3324 const local = try f.allocLocal(inst, inst_ty);3579 const local = try f.allocLocal(inst, inst_ty);
3580 const operand_ty = f.air.typeOf(ty_op.operand);
3581
3325 try f.writeCValue(writer, local, .Other);3582 try f.writeCValue(writer, local, .Other);
3326 try writer.writeAll(" = (");3583 try writer.writeAll(" = ");
3327 try f.renderTypecast(writer, inst_ty);3584 try f.renderIntCast(writer, inst_ty, operand, operand_ty, .Other);
3328 try writer.writeByte(')');
3329 try f.writeCValue(writer, operand, .Other);
3330 try writer.writeAll(";\n");3585 try writer.writeAll(";\n");
3331 return local;3586 return local;
3332}3587}
...@@ -3346,15 +3601,27 @@ fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3346,15 +3601,27 @@ fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue {
3346 const target = f.object.dg.module.getTarget();3601 const target = f.object.dg.module.getTarget();
3347 const dest_int_info = inst_ty.intInfo(target);3602 const dest_int_info = inst_ty.intInfo(target);
3348 const dest_bits = dest_int_info.bits;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);
33493608
3350 try f.writeCValue(writer, local, .Other);3609 try f.writeCValue(writer, local, .Other);
3351 try writer.writeAll(" = (");3610 try writer.writeAll(" = ");
3352 try f.renderTypecast(writer, inst_ty);3611
3353 try writer.writeByte(')');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 }
33543622
3355 if (dest_bits >= 8 and std.math.isPowerOfTwo(dest_bits)) {3623 if (dest_bits >= 8 and std.math.isPowerOfTwo(dest_bits)) {
3356 try f.writeCValue(writer, operand, .Other);3624 try f.writeCValue(writer, operand, .Other);
3357 try writer.writeAll(";\n");
3358 } else switch (dest_int_info.signedness) {3625 } else switch (dest_int_info.signedness) {
3359 .unsigned => {3626 .unsigned => {
3360 var arena = std.heap.ArenaAllocator.init(f.object.dg.gpa);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,14 +3632,14 @@ fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue {
3365 std.heap.stackFallback(@sizeOf(ExpectedContents), arena.allocator());3632 std.heap.stackFallback(@sizeOf(ExpectedContents), arena.allocator());
33663633
3367 const mask_val = try inst_ty.maxInt(stack.get(), target);3634 const mask_val = try inst_ty.maxInt(stack.get(), target);
33683635 try writer.writeAll("zig_and_");
3636 try f.object.dg.renderTypeForBuiltinFnName(writer, operand_ty);
3369 try writer.writeByte('(');3637 try writer.writeByte('(');
3370 try f.writeCValue(writer, operand, .Other);3638 try f.writeCValue(writer, operand, .FunctionArgument);
3371 try writer.print(" & {x});\n", .{try f.fmtIntLiteral(inst_ty, mask_val)});3639 try writer.print(", {x})", .{try f.fmtIntLiteral(operand_ty, mask_val)});
3372 },3640 },
3373 .signed => {3641 .signed => {
3374 const operand_ty = f.air.typeOf(ty_op.operand);3642 const c_bits = toCIntBits(operand_int_info.bits) orelse
3375 const c_bits = toCIntBits(operand_ty.intInfo(target).bits) orelse
3376 return f.fail("TODO: C backend: implement integer types larger than 128 bits", .{});3643 return f.fail("TODO: C backend: implement integer types larger than 128 bits", .{});
3377 var shift_pl = Value.Payload.U64{3644 var shift_pl = Value.Payload.U64{
3378 .base = .{ .tag = .int_u64 },3645 .base = .{ .tag = .int_u64 },
...@@ -3380,11 +3647,29 @@ fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3380,11 +3647,29 @@ fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue {
3380 };3647 };
3381 const shift_val = Value.initPayload(&shift_pl.base);3648 const shift_val = Value.initPayload(&shift_pl.base);
33823649
3383 try writer.print("((int{d}_t)((uint{0d}_t)", .{c_bits});3650 try writer.writeAll("zig_shr_");
3384 try f.writeCValue(writer, operand, .Other);3651 try f.object.dg.renderTypeForBuiltinFnName(writer, operand_ty);
3385 try writer.print(" << {}) >> {0});\n", .{try f.fmtIntLiteral(Type.u8, shift_val)});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 return local;3673 return local;
3389}3674}
33903675
...@@ -3521,15 +3806,26 @@ fn airStore(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3521,15 +3806,26 @@ fn airStore(f: *Function, inst: Air.Inst.Index) !CValue {
3521 try f.writeCValueDeref(writer, ptr_val);3806 try f.writeCValueDeref(writer, ptr_val);
3522 try writer.print(", {x}), zig_shl_", .{try f.fmtIntLiteral(host_ty, mask_val)});3807 try writer.print(", {x}), zig_shl_", .{try f.fmtIntLiteral(host_ty, mask_val)});
3523 try f.object.dg.renderTypeForBuiltinFnName(writer, host_ty);3808 try f.object.dg.renderTypeForBuiltinFnName(writer, host_ty);
3524 try writer.writeAll("((");3809 try writer.writeByte('(');
3525 try f.renderTypecast(writer, host_ty);3810 const cant_cast = host_ty.isInt() and host_ty.bitSize(target) > 64;
3526 try writer.writeByte(')');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 if (src_ty.isPtrAtRuntime()) {3822 if (src_ty.isPtrAtRuntime()) {
3528 try writer.writeByte('(');3823 try writer.writeByte('(');
3529 try f.renderTypecast(writer, Type.usize);3824 try f.renderTypecast(writer, Type.usize);
3530 try writer.writeByte(')');3825 try writer.writeByte(')');
3531 }3826 }
3532 try f.writeCValue(writer, src_val, .Other);3827 try f.writeCValue(writer, src_val, .Other);
3828 if (cant_cast) try writer.writeByte(')');
3533 try writer.print(", {}))", .{try f.fmtIntLiteral(bit_offset_ty, bit_offset_val)});3829 try writer.print(", {}))", .{try f.fmtIntLiteral(bit_offset_ty, bit_offset_val)});
3534 } else {3830 } else {
3535 try f.writeCValueDeref(writer, ptr_val);3831 try f.writeCValueDeref(writer, ptr_val);
...@@ -3610,12 +3906,12 @@ fn airNot(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3610,12 +3906,12 @@ fn airNot(f: *Function, inst: Air.Inst.Index) !CValue {
36103906
3611 const writer = f.object.writer();3907 const writer = f.object.writer();
3612 const local = try f.allocLocal(inst, inst_ty);3908 const local = try f.allocLocal(inst, inst_ty);
3909
3613 try f.writeCValue(writer, local, .Other);3910 try f.writeCValue(writer, local, .Other);
3614 try writer.writeAll(" = ");3911 try writer.writeAll(" = ");
3615 try writer.writeByte('!');3912 try writer.writeByte('!');
3616 try f.writeCValue(writer, op, .Other);3913 try f.writeCValue(writer, op, .Other);
3617 try writer.writeAll(";\n");3914 try writer.writeAll(";\n");
3618
3619 return local;3915 return local;
3620}3916}
36213917
...@@ -4382,7 +4678,15 @@ fn airCondBr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4382,7 +4678,15 @@ fn airCondBr(f: *Function, inst: Air.Inst.Index) !CValue {
4382 try f.writeCValue(writer, cond, .Other);4678 try f.writeCValue(writer, cond, .Other);
4383 try writer.writeAll(") ");4679 try writer.writeAll(") ");
4384 try genBody(f, then_body);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 f.value_map.deinit();4690 f.value_map.deinit();
4387 f.value_map = cloned_map.move();4691 f.value_map = cloned_map.move();
4388 const free_locals = f.getFreeLocals();4692 const free_locals = f.getFreeLocals();
...@@ -4395,7 +4699,12 @@ fn airCondBr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4395,7 +4699,12 @@ fn airCondBr(f: *Function, inst: Air.Inst.Index) !CValue {
43954699
4396 try noticeBranchFrees(f, pre_locals_len, inst);4700 try noticeBranchFrees(f, pre_locals_len, inst);
43974701
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 try f.object.indent_writer.insertNewline();4708 try f.object.indent_writer.insertNewline();
44004709
4401 return CValue.none;4710 return CValue.none;
...@@ -5218,13 +5527,22 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5218,13 +5527,22 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
5218 try f.object.dg.renderTypeForBuiltinFnName(writer, field_int_ty);5527 try f.object.dg.renderTypeForBuiltinFnName(writer, field_int_ty);
5219 try writer.writeAll("((");5528 try writer.writeAll("((");
5220 try f.renderTypecast(writer, field_int_ty);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 try f.object.dg.renderTypeForBuiltinFnName(writer, struct_ty);5539 try f.object.dg.renderTypeForBuiltinFnName(writer, struct_ty);
5223 try writer.writeByte('(');5540 try writer.writeByte('(');
5224 try f.writeCValue(writer, struct_byval, .Other);5541 try f.writeCValue(writer, struct_byval, .Other);
5225 try writer.writeAll(", ");5542 try writer.writeAll(", ");
5226 try f.object.dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument);5543 try f.object.dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument);
5227 try writer.writeByte(')');5544 try writer.writeByte(')');
5545 if (cant_cast) try writer.writeByte(')');
5228 try f.object.dg.renderBuiltinInfo(writer, field_int_ty, .Bits);5546 try f.object.dg.renderBuiltinInfo(writer, field_int_ty, .Bits);
5229 try writer.writeAll(");\n");5547 try writer.writeAll(");\n");
5230 if (inst_ty.eql(field_int_ty, f.object.dg.module)) return temp_local;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,7 +6130,7 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue
5812 try writer.writeAll(";\n");6130 try writer.writeAll(";\n");
5813 try writer.writeAll("if (");6131 try writer.writeAll("if (");
5814 try writer.print("zig_cmpxchg_{s}((zig_atomic(", .{flavor});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 try writer.writeByte(')');6134 try writer.writeByte(')');
5817 if (ptr_ty.isVolatilePtr()) try writer.writeAll(" volatile");6135 if (ptr_ty.isVolatilePtr()) try writer.writeAll(" volatile");
5818 try writer.writeAll(" *)");6136 try writer.writeAll(" *)");
...@@ -5825,6 +6143,8 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue...@@ -5825,6 +6143,8 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue
5825 try writeMemoryOrder(writer, extra.successOrder());6143 try writeMemoryOrder(writer, extra.successOrder());
5826 try writer.writeAll(", ");6144 try writer.writeAll(", ");
5827 try writeMemoryOrder(writer, extra.failureOrder());6145 try writeMemoryOrder(writer, extra.failureOrder());
6146 try writer.writeAll(", ");
6147 try f.object.dg.renderTypeForBuiltinFnName(writer, ptr_ty.childType());
5828 try writer.writeByte(')');6148 try writer.writeByte(')');
5829 try writer.writeAll(") {\n");6149 try writer.writeAll(") {\n");
5830 f.object.indent_writer.pushIndent();6150 f.object.indent_writer.pushIndent();
...@@ -5839,7 +6159,7 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue...@@ -5839,7 +6159,7 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue
5839 try writer.writeAll(";\n");6159 try writer.writeAll(";\n");
5840 try f.writeCValue(writer, local, .Other);6160 try f.writeCValue(writer, local, .Other);
5841 try writer.print(".is_null = zig_cmpxchg_{s}((zig_atomic(", .{flavor});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 try writer.writeByte(')');6163 try writer.writeByte(')');
5844 if (ptr_ty.isVolatilePtr()) try writer.writeAll(" volatile");6164 if (ptr_ty.isVolatilePtr()) try writer.writeAll(" volatile");
5845 try writer.writeAll(" *)");6165 try writer.writeAll(" *)");
...@@ -5852,6 +6172,8 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue...@@ -5852,6 +6172,8 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue
5852 try writeMemoryOrder(writer, extra.successOrder());6172 try writeMemoryOrder(writer, extra.successOrder());
5853 try writer.writeAll(", ");6173 try writer.writeAll(", ");
5854 try writeMemoryOrder(writer, extra.failureOrder());6174 try writeMemoryOrder(writer, extra.failureOrder());
6175 try writer.writeAll(", ");
6176 try f.object.dg.renderTypeForBuiltinFnName(writer, ptr_ty.childType());
5855 try writer.writeByte(')');6177 try writer.writeByte(')');
5856 try writer.writeAll(";\n");6178 try writer.writeAll(";\n");
5857 }6179 }
...@@ -5874,8 +6196,8 @@ fn airAtomicRmw(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5874,8 +6196,8 @@ fn airAtomicRmw(f: *Function, inst: Air.Inst.Index) !CValue {
5874 try reap(f, inst, &.{ pl_op.operand, extra.operand });6196 try reap(f, inst, &.{ pl_op.operand, extra.operand });
5875 const writer = f.object.writer();6197 const writer = f.object.writer();
5876 const local = try f.allocLocal(inst, inst_ty);6198 const local = try f.allocLocal(inst, inst_ty);
5877 try f.writeCValue(writer, local, .Other);
58786199
6200 try f.writeCValue(writer, local, .Other);
5879 try writer.print(" = zig_atomicrmw_{s}((", .{toAtomicRmwSuffix(extra.op())});6201 try writer.print(" = zig_atomicrmw_{s}((", .{toAtomicRmwSuffix(extra.op())});
5880 switch (extra.op()) {6202 switch (extra.op()) {
5881 else => {6203 else => {
...@@ -5895,6 +6217,8 @@ fn airAtomicRmw(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5895,6 +6217,8 @@ fn airAtomicRmw(f: *Function, inst: Air.Inst.Index) !CValue {
5895 try f.writeCValue(writer, operand, .FunctionArgument);6217 try f.writeCValue(writer, operand, .FunctionArgument);
5896 try writer.writeAll(", ");6218 try writer.writeAll(", ");
5897 try writeMemoryOrder(writer, extra.ordering());6219 try writeMemoryOrder(writer, extra.ordering());
6220 try writer.writeAll(", ");
6221 try f.object.dg.renderTypeForBuiltinFnName(writer, ptr_ty.childType());
5898 try writer.writeAll(");\n");6222 try writer.writeAll(");\n");
58996223
5900 if (f.liveness.isUnused(inst)) {6224 if (f.liveness.isUnused(inst)) {
...@@ -5927,6 +6251,8 @@ fn airAtomicLoad(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5927,6 +6251,8 @@ fn airAtomicLoad(f: *Function, inst: Air.Inst.Index) !CValue {
5927 try f.writeCValue(writer, ptr, .Other);6251 try f.writeCValue(writer, ptr, .Other);
5928 try writer.writeAll(", ");6252 try writer.writeAll(", ");
5929 try writeMemoryOrder(writer, atomic_load.order);6253 try writeMemoryOrder(writer, atomic_load.order);
6254 try writer.writeAll(", ");
6255 try f.object.dg.renderTypeForBuiltinFnName(writer, ptr_ty.childType());
5930 try writer.writeAll(");\n");6256 try writer.writeAll(");\n");
59316257
5932 return local;6258 return local;
...@@ -5948,7 +6274,9 @@ fn airAtomicStore(f: *Function, inst: Air.Inst.Index, order: [*:0]const u8) !CVa...@@ -5948,7 +6274,9 @@ fn airAtomicStore(f: *Function, inst: Air.Inst.Index, order: [*:0]const u8) !CVa
5948 try f.writeCValue(writer, ptr, .Other);6274 try f.writeCValue(writer, ptr, .Other);
5949 try writer.writeAll(", ");6275 try writer.writeAll(", ");
5950 try f.writeCValue(writer, element, .FunctionArgument);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");
59526280
5953 return CValue.none;6281 return CValue.none;
5954}6282}
...@@ -6405,9 +6733,7 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6405,9 +6733,7 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
6405 },6733 },
6406 .Packed => {6734 .Packed => {
6407 try f.writeCValue(writer, local, .Other);6735 try f.writeCValue(writer, local, .Other);
6408 try writer.writeAll(" = (");6736 try writer.writeAll(" = ");
6409 try f.renderTypecast(writer, inst_ty);
6410 try writer.writeAll(")");
6411 const int_info = inst_ty.intInfo(target);6737 const int_info = inst_ty.intInfo(target);
64126738
6413 var bit_offset_ty_pl = Type.Payload.Bits{6739 var bit_offset_ty_pl = Type.Payload.Bits{
...@@ -6437,20 +6763,28 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6437,20 +6763,28 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
6437 if (!field_ty.hasRuntimeBitsIgnoreComptime()) continue;6763 if (!field_ty.hasRuntimeBitsIgnoreComptime()) continue;
64386764
6439 if (!empty) try writer.writeAll(", ");6765 if (!empty) try writer.writeAll(", ");
6766 // TODO: Skip this entire shift if val is 0?
6440 try writer.writeAll("zig_shlw_");6767 try writer.writeAll("zig_shlw_");
6441 try f.object.dg.renderTypeForBuiltinFnName(writer, inst_ty);6768 try f.object.dg.renderTypeForBuiltinFnName(writer, inst_ty);
6442 try writer.writeAll("((");6769 try writer.writeByte('(');
6443 try f.renderTypecast(writer, inst_ty);6770
6444 try writer.writeByte(')');6771 if (inst_ty.isAbiInt() and (field_ty.isAbiInt() or field_ty.isPtrAtRuntime())) {
6445 if (field_ty.isPtrAtRuntime()) {6772 try f.renderIntCast(writer, inst_ty, element, field_ty, .FunctionArgument);
6773 } else {
6446 try writer.writeByte('(');6774 try writer.writeByte('(');
6447 try f.renderTypecast(writer, switch (int_info.signedness) {6775 try f.renderTypecast(writer, inst_ty);
6448 .unsigned => Type.usize,
6449 .signed => Type.isize,
6450 });
6451 try writer.writeByte(')');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 try writer.writeAll(", ");6788 try writer.writeAll(", ");
6455 try f.object.dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument);6789 try f.object.dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument);
6456 try f.object.dg.renderBuiltinInfo(writer, inst_ty, .Bits);6790 try f.object.dg.renderBuiltinInfo(writer, inst_ty, .Bits);
...@@ -6460,7 +6794,14 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6460,7 +6794,14 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
6460 bit_offset_val_pl.data += field_ty.bitSize(target);6794 bit_offset_val_pl.data += field_ty.bitSize(target);
6461 empty = false;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 try writer.writeAll(";\n");6805 try writer.writeAll(";\n");
6465 },6806 },
6466 },6807 },
...@@ -6793,6 +7134,68 @@ fn compilerRtAbbrev(ty: Type, target: std.Target) []const u8 {...@@ -6793,6 +7134,68 @@ fn compilerRtAbbrev(ty: Type, target: std.Target) []const u8 {
6793 } else unreachable;7134 } else unreachable;
6794}7135}
67957136
7137fn 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
7195fn stringLiteral(child_stream: anytype) StringLiteral(@TypeOf(child_stream)) {
7196 return .{ .counting_writer = std.io.countingWriter(child_stream) };
7197}
7198
6796fn formatStringLiteral(7199fn formatStringLiteral(
6797 str: []const u8,7200 str: []const u8,
6798 comptime fmt: []const u8,7201 comptime fmt: []const u8,
...@@ -6800,44 +7203,25 @@ fn formatStringLiteral(...@@ -6800,44 +7203,25 @@ fn formatStringLiteral(
6800 writer: anytype,7203 writer: anytype,
6801) @TypeOf(writer).Error!void {7204) @TypeOf(writer).Error!void {
6802 if (fmt.len != 1 or fmt[0] != 's') @compileError("Invalid fmt: " ++ fmt);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 for (str) |c|7209 for (str) |c|
6805 try writeStringLiteralChar(writer, c);7210 try literal.writeChar(c);
6806 try writer.writeByte('\"');7211 try literal.end();
6807}7212}
68087213
6809fn fmtStringLiteral(str: []const u8) std.fmt.Formatter(formatStringLiteral) {7214fn fmtStringLiteral(str: []const u8) std.fmt.Formatter(formatStringLiteral) {
6810 return .{ .data = str };7215 return .{ .data = str };
6811}7216}
68127217
6813fn 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
6830fn undefPattern(comptime IntType: type) IntType {7218fn undefPattern(comptime IntType: type) IntType {
6831 const int_info = @typeInfo(IntType).Int;7219 const int_info = @typeInfo(IntType).Int;
6832 const UnsignedType = std.meta.Int(.unsigned, int_info.bits);7220 const UnsignedType = std.meta.Int(.unsigned, int_info.bits);
6833 return @bitCast(IntType, @as(UnsignedType, (1 << (int_info.bits | 1)) / 3));7221 return @bitCast(IntType, @as(UnsignedType, (1 << (int_info.bits | 1)) / 3));
6834}7222}
68357223
6836const FormatIntLiteralContext = struct {7224const FormatIntLiteralContext = struct { ty: Type, val: Value, mod: *Module, location: ?ValueRenderLocation = null };
6837 ty: Type,
6838 val: Value,
6839 mod: *Module,
6840};
6841fn formatIntLiteral(7225fn formatIntLiteral(
6842 data: FormatIntLiteralContext,7226 data: FormatIntLiteralContext,
6843 comptime fmt: []const u8,7227 comptime fmt: []const u8,
...@@ -6905,10 +7289,31 @@ fn formatIntLiteral(...@@ -6905,10 +7289,31 @@ fn formatIntLiteral(
6905 return writer.print("{s}_{s}", .{ abbrev, if (int.positive) "MAX" else "MIN" });7289 return writer.print("{s}_{s}", .{ abbrev, if (int.positive) "MAX" else "MIN" });
6906 }7290 }
69077291
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 switch (data.ty.tag()) {7307 switch (data.ty.tag()) {
6910 .c_short, .c_ushort, .c_int, .c_uint, .c_long, .c_ulong, .c_longlong, .c_ulonglong => {},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 }
69137318
6914 const limbs_count_64 = @divExact(64, @bitSizeOf(BigIntLimb));7319 const limbs_count_64 = @divExact(64, @bitSizeOf(BigIntLimb));
...@@ -6948,16 +7353,34 @@ fn formatIntLiteral(...@@ -6948,16 +7353,34 @@ fn formatIntLiteral(
6948 } else {7353 } else {
6949 assert(c_bits == 128);7354 assert(c_bits == 128);
6950 const split = std.math.min(int.limbs.len, limbs_count_64);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 }
69517374
6952 var upper_pl = Value.Payload.BigInt{7375 var upper_pl = Value.Payload.BigInt{
6953 .base = .{ .tag = .int_big_positive },7376 .base = .{ .tag = .int_big_positive },
6954 .data = int.limbs[split..],7377 .data = limbs[split..],
6955 };7378 };
6956 const upper_val = Value.initPayload(&upper_pl.base);7379 const upper_val = Value.initPayload(&upper_pl.base);
6957 try formatIntLiteral(.{7380 try formatIntLiteral(.{
6958 .ty = switch (int_info.signedness) {7381 .ty = switch (int_info.signedness) {
6959 .unsigned => Type.u64,7382 .unsigned => Type.u64,
6960 .signed => Type.i64,7383 .signed => if (use_twos_comp) Type.u64 else Type.i64,
6961 },7384 },
6962 .val = upper_val,7385 .val = upper_val,
6963 .mod = data.mod,7386 .mod = data.mod,
...@@ -6967,7 +7390,7 @@ fn formatIntLiteral(...@@ -6967,7 +7390,7 @@ fn formatIntLiteral(
69677390
6968 var lower_pl = Value.Payload.BigInt{7391 var lower_pl = Value.Payload.BigInt{
6969 .base = .{ .tag = .int_big_positive },7392 .base = .{ .tag = .int_big_positive },
6970 .data = int.limbs[0..split],7393 .data = limbs[0..split],
6971 };7394 };
6972 const lower_val = Value.initPayload(&lower_pl.base);7395 const lower_val = Value.initPayload(&lower_pl.base);
6973 try formatIntLiteral(.{7396 try formatIntLiteral(.{
...@@ -6976,6 +7399,7 @@ fn formatIntLiteral(...@@ -6976,6 +7399,7 @@ fn formatIntLiteral(
6976 .mod = data.mod,7399 .mod = data.mod,
6977 }, fmt, options, writer);7400 }, fmt, options, writer);
69787401
7402 if (!int.positive and c_bits > 64 and !use_twos_comp) try writer.writeByte(')');
6979 return writer.writeByte(')');7403 return writer.writeByte(')');
6980 }7404 }
69817405
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,6 +540,7 @@ test "align(N) on functions" {
540 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO540 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
541 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO541 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
542 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO542 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
543544
544 // function alignment is a compile error on wasm32/wasm64545 // function alignment is a compile error on wasm32/wasm64
545 if (native_arch == .wasm32 or native_arch == .wasm64) return error.SkipZigTest;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,6 +23,7 @@ test "module level assembly" {
23 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO23 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
24 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO24 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
25 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO25 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
26 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
2627
27 if (is_x86_64_linux) {28 if (is_x86_64_linux) {
28 try expect(this_is_my_alias() == 1234);29 try expect(this_is_my_alias() == 1234);
...@@ -35,6 +36,7 @@ test "output constraint modifiers" {...@@ -35,6 +36,7 @@ test "output constraint modifiers" {
35 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO36 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
36 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO37 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
37 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO38 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
39 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
3840
39 // This is only testing compilation.41 // This is only testing compilation.
40 var a: u32 = 3;42 var a: u32 = 3;
...@@ -56,6 +58,7 @@ test "alternative constraints" {...@@ -56,6 +58,7 @@ test "alternative constraints" {
56 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO58 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
57 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO59 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
58 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO60 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
61 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
5962
60 // Make sure we allow commas as a separator for alternative constraints.63 // Make sure we allow commas as a separator for alternative constraints.
61 var a: u32 = 3;64 var a: u32 = 3;
...@@ -72,6 +75,7 @@ test "sized integer/float in asm input" {...@@ -72,6 +75,7 @@ test "sized integer/float in asm input" {
72 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO75 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
73 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO76 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
74 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO77 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
78 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
7579
76 asm volatile (""80 asm volatile (""
77 :81 :
...@@ -121,6 +125,7 @@ test "struct/array/union types as input values" {...@@ -121,6 +125,7 @@ test "struct/array/union types as input values" {
121 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO125 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
122 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO126 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
123 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO127 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
128 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
124129
125 asm volatile (""130 asm volatile (""
126 :131 :
test/behavior/atomics.zig+133-22
...@@ -250,31 +250,142 @@ test "atomicrmw with ints" {...@@ -250,31 +250,142 @@ test "atomicrmw with ints" {
250 return error.SkipZigTest;250 return error.SkipZigTest;
251 }251 }
252252
253 try testAtomicRmwInt();253 try testAtomicRmwInts();
254 comptime try testAtomicRmwInt();254 comptime try testAtomicRmwInts();
255}255}
256256
257fn testAtomicRmwInt() !void {257fn testAtomicRmwInts() !void {
258 var x: u8 = 1;258 // TODO: Use the max atomic bit size for the target, maybe builtin?
259 var res = @atomicRmw(u8, &x, .Xchg, 3, .SeqCst);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
268fn 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 try expect(x == 3 and res == 1);273 try expect(x == 3 and res == 1);
261 _ = @atomicRmw(u8, &x, .Add, 3, .SeqCst);274
262 try expect(x == 6);275 res = @atomicRmw(int, &x, .Add, 3, .SeqCst);
263 _ = @atomicRmw(u8, &x, .Sub, 1, .SeqCst);276 var y: int = 3;
264 try expect(x == 5);277 try expect(res == y);
265 _ = @atomicRmw(u8, &x, .And, 4, .SeqCst);278 y = y + 3;
266 try expect(x == 4);279 try expect(x == y);
267 _ = @atomicRmw(u8, &x, .Nand, 4, .SeqCst);280
268 try expect(x == 0xfb);281 res = @atomicRmw(int, &x, .Sub, 1, .SeqCst);
269 _ = @atomicRmw(u8, &x, .Or, 6, .SeqCst);282 try expect(res == y);
270 try expect(x == 0xff);283 y = y - 1;
271 _ = @atomicRmw(u8, &x, .Xor, 2, .SeqCst);284 try expect(x == y);
272 try expect(x == 0xfd);285
273286 res = @atomicRmw(int, &x, .And, 4, .SeqCst);
274 _ = @atomicRmw(u8, &x, .Max, 1, .SeqCst);287 try expect(res == y);
275 try expect(x == 0xfd);288 y = y & 4;
276 _ = @atomicRmw(u8, &x, .Min, 1, .SeqCst);289 try expect(x == y);
277 try expect(x == 1);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
317test "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
332fn 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}
279390
280test "atomics with different types" {391test "atomics with different types" {
test/behavior/basic.zig+18
...@@ -37,6 +37,24 @@ test "truncate to non-power-of-two integers" {...@@ -37,6 +37,24 @@ test "truncate to non-power-of-two integers" {
37 try testTrunc(i32, i5, std.math.maxInt(i32), -1);37 try testTrunc(i32, i5, std.math.maxInt(i32), -1);
38}38}
3939
40test "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
40fn testTrunc(comptime Big: type, comptime Little: type, big: Big, little: Little) !void {58fn testTrunc(comptime Big: type, comptime Little: type, big: Big, little: Little) !void {
41 try expect(@truncate(Little, big) == little);59 try expect(@truncate(Little, big) == little);
42}60}
test/behavior/int128.zig+14-2
...@@ -64,11 +64,23 @@ test "int128" {...@@ -64,11 +64,23 @@ test "int128" {
64}64}
6565
66test "truncate int128" {66test "truncate int128" {
67 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
67 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO68 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
68 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO69 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
69 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO70 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
70 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO71 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
7172
72 var buff: u128 = maxInt(u128);73 {
73 try expect(@truncate(u64, buff) == maxInt(u64));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,6 +377,28 @@ fn testBinaryNot(x: u16) !void {
377 try expect(~x == 0b0101010101010101);377 try expect(~x == 0b0101010101010101);
378}378}
379379
380test "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
398fn testBinaryNot128(comptime Type: type, x: Type) !void {
399 try expect(~x == @as(Type, 0x55555555_55555555_55555555_55555555));
400}
401
380test "division" {402test "division" {
381 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO403 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
382 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO404 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
...@@ -632,10 +654,24 @@ test "128-bit multiplication" {...@@ -632,10 +654,24 @@ test "128-bit multiplication" {
632 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO654 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
633 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO655 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
634656
635 var a: i128 = 3;657 {
636 var b: i128 = 2;658 var a: i128 = 3;
637 var c = a * b;659 var b: i128 = 2;
638 try expect(c == 6);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}
640676
641test "@addWithOverflow" {677test "@addWithOverflow" {