Skip to content

Commit 4c1007f

Browse files
authored
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
2 parents 4172c29 + 23b1544 commit 4c1007f

File tree

16 files changed

+1507
-319
lines changed

16 files changed

+1507
-319
lines changed

lib/compiler_rt/divti3.zig

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,21 +7,8 @@ const common = @import("common.zig");
77
pub const panic = common.panic;
88

99
comptime {
10-
if (builtin.os.tag == .windows) {
11-
switch (arch) {
12-
.x86 => {
13-
@export(__divti3, .{ .name = "__divti3", .linkage = common.linkage, .visibility = common.visibility });
14-
},
15-
.x86_64 => {
16-
// The "ti" functions must use Vector(2, u64) parameter types to adhere to the ABI
17-
// that LLVM expects compiler-rt to have.
18-
@export(__divti3_windows_x86_64, .{ .name = "__divti3", .linkage = common.linkage, .visibility = common.visibility });
19-
},
20-
else => {},
21-
}
22-
if (arch.isAARCH64()) {
23-
@export(__divti3, .{ .name = "__divti3", .linkage = common.linkage, .visibility = common.visibility });
24-
}
10+
if (common.want_windows_v2u64_abi) {
11+
@export(__divti3_windows_x86_64, .{ .name = "__divti3", .linkage = common.linkage, .visibility = common.visibility });
2512
} else {
2613
@export(__divti3, .{ .name = "__divti3", .linkage = common.linkage, .visibility = common.visibility });
2714
}
@@ -31,7 +18,7 @@ pub fn __divti3(a: i128, b: i128) callconv(.C) i128 {
3118
return div(a, b);
3219
}
3320

34-
const v128 = @import("std").meta.Vector(2, u64);
21+
const v128 = @Vector(2, u64);
3522

3623
fn __divti3_windows_x86_64(a: v128, b: v128) callconv(.C) v128 {
3724
return @bitCast(v128, div(@bitCast(i128, a), @bitCast(i128, b)));

lib/compiler_rt/fixunshfti.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ pub fn __fixunshfti(a: f16) callconv(.C) u128 {
1616
return floatToInt(u128, a);
1717
}
1818

19-
const v2u64 = @import("std").meta.Vector(2, u64);
19+
const v2u64 = @Vector(2, u64);
2020

2121
fn __fixunshfti_windows_x86_64(a: f16) callconv(.C) v2u64 {
2222
return @bitCast(v2u64, floatToInt(u128, a));

lib/compiler_rt/udivmodei4.zig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,8 @@ pub fn __umodei4(r_p: [*c]u32, u_p: [*c]const u32, v_p: [*c]const u32, bits: usi
129129
}
130130

131131
test "__udivei4/__umodei4" {
132+
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
133+
132134
const RndGen = std.rand.DefaultPrng;
133135
var rnd = RndGen.init(42);
134136
var i: usize = 10000;

lib/std/math/big/int.zig

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1677,6 +1677,40 @@ pub const Mutable = struct {
16771677
y.shiftRight(y.toConst(), norm_shift);
16781678
}
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+
16801714
/// Truncate an integer to a number of bits, following 2s-complement semantics.
16811715
/// r may alias a.
16821716
///

lib/std/mem.zig

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3771,7 +3771,7 @@ pub fn doNotOptimizeAway(val: anytype) void {
37713771
.Bool => doNotOptimizeAway(@boolToInt(val)),
37723772
.Int => {
37733773
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) {
37753775
const val2 = @as(
37763776
std.meta.Int(t.Int.signedness, @max(8, std.math.ceilPowerOfTwoAssert(u16, bits))),
37773777
val,
@@ -3783,18 +3783,24 @@ pub fn doNotOptimizeAway(val: anytype) void {
37833783
} else doNotOptimizeAway(&val);
37843784
},
37853785
.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) {
37873787
asm volatile (""
37883788
:
37893789
: [val] "rm" (val),
37903790
);
37913791
} else doNotOptimizeAway(&val);
37923792
},
3793-
.Pointer => asm volatile (""
3794-
:
3795-
: [val] "m" (val),
3796-
: "memory"
3797-
),
3793+
.Pointer => {
3794+
if (builtin.zig_backend == .stage2_c) {
3795+
doNotOptimizeAwayC(val);
3796+
} else {
3797+
asm volatile (""
3798+
:
3799+
: [val] "m" (val),
3800+
: "memory"
3801+
);
3802+
}
3803+
},
37983804
.Array => {
37993805
if (t.Array.len * @sizeOf(t.Array.child) <= 64) {
38003806
for (val) |v| doNotOptimizeAway(v);
@@ -3804,6 +3810,16 @@ pub fn doNotOptimizeAway(val: anytype) void {
38043810
}
38053811
}
38063812

3813+
/// .stage2_c doesn't support asm blocks yet, so use volatile stores instead
3814+
var deopt_target: if (builtin.zig_backend == .stage2_c) u8 else void = undefined;
3815+
fn doNotOptimizeAwayC(ptr: anytype) void {
3816+
const dest = @ptrCast(*volatile u8, &deopt_target);
3817+
for (asBytes(ptr)) |b| {
3818+
dest.* = b;
3819+
}
3820+
dest.* = 0;
3821+
}
3822+
38073823
test "doNotOptimizeAway" {
38083824
comptime doNotOptimizeAway("test");
38093825

lib/std/os/windows.zig

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1776,16 +1776,26 @@ pub fn UnlockFile(
17761776
}
17771777
}
17781778

1779+
/// This is a workaround for the C backend until zig has the ability to put
1780+
/// C code in inline assembly.
1781+
extern fn zig_x86_64_windows_teb() callconv(.C) *anyopaque;
1782+
17791783
pub fn teb() *TEB {
17801784
return switch (native_arch) {
17811785
.x86 => asm volatile (
17821786
\\ movl %%fs:0x18, %[ptr]
17831787
: [ptr] "=r" (-> *TEB),
17841788
),
1785-
.x86_64 => asm volatile (
1786-
\\ movq %%gs:0x30, %[ptr]
1787-
: [ptr] "=r" (-> *TEB),
1788-
),
1789+
.x86_64 => blk: {
1790+
if (builtin.zig_backend == .stage2_c) {
1791+
break :blk @ptrCast(*TEB, @alignCast(@alignOf(TEB), zig_x86_64_windows_teb()));
1792+
} else {
1793+
break :blk asm volatile (
1794+
\\ movq %%gs:0x30, %[ptr]
1795+
: [ptr] "=r" (-> *TEB),
1796+
);
1797+
}
1798+
},
17891799
.aarch64 => asm volatile (
17901800
\\ mov %[ptr], x18
17911801
: [ptr] "=r" (-> *TEB),
@@ -3455,6 +3465,21 @@ pub const ASSEMBLY_STORAGE_MAP = opaque {};
34553465
pub const FLS_CALLBACK_INFO = opaque {};
34563466
pub const RTL_BITMAP = opaque {};
34573467
pub const KAFFINITY = usize;
3468+
pub const KPRIORITY = i32;
3469+
3470+
pub const CLIENT_ID = extern struct {
3471+
UniqueProcess: HANDLE,
3472+
UniqueThread: HANDLE,
3473+
};
3474+
3475+
pub const THREAD_BASIC_INFORMATION = extern struct {
3476+
ExitStatus: NTSTATUS,
3477+
TebBaseAddress: PVOID,
3478+
ClientId: CLIENT_ID,
3479+
AffinityMask: KAFFINITY,
3480+
Priority: KPRIORITY,
3481+
BasePriority: KPRIORITY,
3482+
};
34583483

34593484
pub const TEB = extern struct {
34603485
Reserved1: [12]PVOID,

lib/std/zig/system/x86.zig

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
const std = @import("std");
2+
const builtin = @import("builtin");
23
const Target = std.Target;
34
const CrossTarget = std.zig.CrossTarget;
45

@@ -527,25 +528,43 @@ const CpuidLeaf = packed struct {
527528
edx: u32,
528529
};
529530

531+
/// This is a workaround for the C backend until zig has the ability to put
532+
/// C code in inline assembly.
533+
extern fn zig_x86_cpuid(leaf_id: u32, subid: u32, eax: *u32, ebx: *u32, ecx: *u32, edx: *u32) callconv(.C) void;
534+
530535
fn cpuid(leaf_id: u32, subid: u32) CpuidLeaf {
531536
// valid for both x86 and x86_64
532537
var eax: u32 = undefined;
533538
var ebx: u32 = undefined;
534539
var ecx: u32 = undefined;
535540
var edx: u32 = undefined;
536-
asm volatile ("cpuid"
537-
: [_] "={eax}" (eax),
538-
[_] "={ebx}" (ebx),
539-
[_] "={ecx}" (ecx),
540-
[_] "={edx}" (edx),
541-
: [_] "{eax}" (leaf_id),
542-
[_] "{ecx}" (subid),
543-
);
541+
542+
if (builtin.zig_backend == .stage2_c) {
543+
zig_x86_cpuid(leaf_id, subid, &eax, &ebx, &ecx, &edx);
544+
} else {
545+
asm volatile ("cpuid"
546+
: [_] "={eax}" (eax),
547+
[_] "={ebx}" (ebx),
548+
[_] "={ecx}" (ecx),
549+
[_] "={edx}" (edx),
550+
: [_] "{eax}" (leaf_id),
551+
[_] "{ecx}" (subid),
552+
);
553+
}
554+
544555
return .{ .eax = eax, .ebx = ebx, .ecx = ecx, .edx = edx };
545556
}
546557

558+
/// This is a workaround for the C backend until zig has the ability to put
559+
/// C code in inline assembly.
560+
extern fn zig_x86_get_xcr0() callconv(.C) u32;
561+
547562
// Read control register 0 (XCR0). Used to detect features such as AVX.
548563
fn getXCR0() u32 {
564+
if (builtin.zig_backend == .stage2_c) {
565+
return zig_x86_get_xcr0();
566+
}
567+
549568
return asm volatile (
550569
\\ xor %%ecx, %%ecx
551570
\\ xgetbv

0 commit comments

Comments
 (0)