authorgravatar for kcbanner@gmail.comCasey Banner <kcbanner@gmail.com> 2023-01-19 23:36:42-05:00
committergravatar for kcbanner@gmail.comCasey Banner <kcbanner@gmail.com> 2023-01-23 13:48:36-05:00
log1aa2c32055c53657fd3a9825427454e0d74c20ed
tree382eb6948ec3ae17e373ef0ec75945d14a2c2e4a
parentce6de2df826347feadb66d087c43c77b2891dc0b

cbe: fixes for x86

- Emit calling convention - Fix .Naked handling for msvc - Add teb helper for x86 - Fix 128-bit shl implementation when rhs is >= 64 - Add 128-bit shl tests

8 files changed, 107 insertions(+), 30 deletions(-)

lib/compiler_rt/aulldiv.zig+1-1
......@@ -7,7 +7,7 @@ const common = @import("common.zig");
77pub const panic = common.panic;
88
99comptime {
10 if (arch == .x86 and abi == .msvc) {
10 if (arch == .x86 and abi == .msvc and builtin.zig_backend != .stage2_c) {
1111 // Don't let LLVM apply the stdcall name mangling on those MSVC builtins
1212 @export(_alldiv, .{ .name = "\x01__alldiv", .linkage = common.linkage, .visibility = common.visibility });
1313 @export(_aulldiv, .{ .name = "\x01__aulldiv", .linkage = common.linkage, .visibility = common.visibility });
lib/compiler_rt/aullrem.zig+1-1
......@@ -7,7 +7,7 @@ const common = @import("common.zig");
77pub const panic = common.panic;
88
99comptime {
10 if (arch == .x86 and abi == .msvc) {
10 if (arch == .x86 and abi == .msvc and builtin.zig_backend != .stage2_c) {
1111 // Don't let LLVM apply the stdcall name mangling on those MSVC builtins
1212 @export(_allrem, .{ .name = "\x01__allrem", .linkage = common.linkage, .visibility = common.visibility });
1313 @export(_aullrem, .{ .name = "\x01__aullrem", .linkage = common.linkage, .visibility = common.visibility });
lib/std/os/windows.zig+11-4
......@@ -1804,14 +1804,21 @@ pub fn UnlockFile(
18041804
18051805/// This is a workaround for the C backend until zig has the ability to put
18061806/// C code in inline assembly.
1807extern fn zig_x86_windows_teb() callconv(.C) *anyopaque;
18071808extern fn zig_x86_64_windows_teb() callconv(.C) *anyopaque;
18081809
18091810pub fn teb() *TEB {
18101811 return switch (native_arch) {
1811 .x86 => asm volatile (
1812 \\ movl %%fs:0x18, %[ptr]
1813 : [ptr] "=r" (-> *TEB),
1814 ),
1812 .x86 => blk: {
1813 if (builtin.zig_backend == .stage2_c) {
1814 break :blk @ptrCast(*TEB, @alignCast(@alignOf(TEB), zig_x86_windows_teb()));
1815 } else {
1816 break :blk asm volatile (
1817 \\ movl %%fs:0x18, %[ptr]
1818 : [ptr] "=r" (-> *TEB),
1819 );
1820 }
1821 },
18151822 .x86_64 => blk: {
18161823 if (builtin.zig_backend == .stage2_c) {
18171824 break :blk @ptrCast(*TEB, @alignCast(@alignOf(TEB), zig_x86_64_windows_teb()));
lib/std/start_windows_tls.zig+2-4
......@@ -7,14 +7,12 @@ export var _tls_end: u8 linksection(".tls$ZZZ") = 0;
77export var __xl_a: std.os.windows.PIMAGE_TLS_CALLBACK linksection(".CRT$XLA") = null;
88export var __xl_z: std.os.windows.PIMAGE_TLS_CALLBACK linksection(".CRT$XLZ") = null;
99
10const tls_array: u32 = 0x2c;
1011comptime {
1112 if (builtin.target.cpu.arch == .x86) {
1213 // The __tls_array is the offset of the ThreadLocalStoragePointer field
1314 // in the TEB block whose base address held in the %fs segment.
14 asm (
15 \\ .global __tls_array
16 \\ __tls_array = 0x2C
17 );
15 @export(tls_array, .{ .name = "_tls_array" });
1816 }
1917}
2018
lib/zig.h+38-18
......@@ -52,15 +52,20 @@ typedef char bool;
5252
5353#if _MSC_VER
5454#define zig_const_arr
55#define zig_callconv(c) __##c
5556#else
5657#define zig_const_arr static const
58#define zig_callconv(c) __attribute__((c))
5759#endif
5860
5961#if zig_has_attribute(naked) || defined(zig_gnuc)
62#define zig_naked_decl __attribute__((naked))
6063#define zig_naked __attribute__((naked))
6164#elif defined(_MSC_VER)
65#define zig_naked_decl
6266#define zig_naked __declspec(naked)
6367#else
68#define zig_naked_decl zig_naked_unavailable
6469#define zig_naked zig_naked_unavailable
6570#endif
6671
......@@ -1214,8 +1219,14 @@ typedef struct { zig_align(16) zig_i64 hi; zig_u64 lo; } zig_i128;
12141219
12151220#define zig_as_u128(hi, lo) ((zig_u128){ .h##i = (hi), .l##o = (lo) })
12161221#define zig_as_i128(hi, lo) ((zig_i128){ .h##i = (hi), .l##o = (lo) })
1222
1223#if _MSC_VER
12171224#define zig_as_constant_u128(hi, lo) { .h##i = (hi), .l##o = (lo) }
12181225#define zig_as_constant_i128(hi, lo) { .h##i = (hi), .l##o = (lo) }
1226#else
1227#define zig_as_constant_u128(hi, lo) zig_as_u128(hi, lo)
1228#define zig_as_constant_i128(hi, lo) zig_as_i128(hi, lo)
1229#endif
12191230#define zig_hi_u128(val) ((val).hi)
12201231#define zig_lo_u128(val) ((val).lo)
12211232#define zig_hi_i128(val) ((val).hi)
......@@ -1344,13 +1355,13 @@ static inline zig_u128 zig_shr_u128(zig_u128 lhs, zig_u8 rhs) {
13441355
13451356static inline zig_u128 zig_shl_u128(zig_u128 lhs, zig_u8 rhs) {
13461357 if (rhs == zig_as_u8(0)) return lhs;
1347 if (rhs >= zig_as_u8(64)) return (zig_u128){ .hi = lhs.lo << rhs, .lo = zig_minInt_u64 };
1358 if (rhs >= zig_as_u8(64)) return (zig_u128){ .hi = lhs.lo << (rhs - zig_as_u8(64)), .lo = zig_minInt_u64 };
13481359 return (zig_u128){ .hi = lhs.hi << rhs | lhs.lo >> (zig_as_u8(64) - rhs), .lo = lhs.lo << rhs };
13491360}
13501361
13511362static inline zig_i128 zig_shl_i128(zig_i128 lhs, zig_u8 rhs) {
13521363 if (rhs == zig_as_u8(0)) return lhs;
1353 if (rhs >= zig_as_u8(64)) return (zig_i128){ .hi = lhs.lo << rhs, .lo = zig_minInt_u64 };
1364 if (rhs >= zig_as_u8(64)) return (zig_i128){ .hi = lhs.lo << (rhs - zig_as_u8(64)), .lo = zig_minInt_u64 };
13541365 return (zig_i128){ .hi = lhs.hi << rhs | lhs.lo >> (zig_as_u8(64) - rhs), .lo = lhs.lo << rhs };
13551366}
13561367
......@@ -1379,6 +1390,10 @@ static inline zig_i128 zig_sub_i128(zig_i128 lhs, zig_i128 rhs) {
13791390}
13801391
13811392zig_extern zig_i128 __multi3(zig_i128 lhs, zig_i128 rhs);
1393static zig_u128 zig_mul_u128(zig_u128 lhs, zig_u128 rhs) {
1394 return zig_bitcast_u128(__multi3(zig_bitcast_i128(lhs), zig_bitcast_i128(rhs)));
1395}
1396
13821397static zig_i128 zig_mul_i128(zig_i128 lhs, zig_i128 rhs) {
13831398 return __multi3(lhs, rhs);
13841399}
......@@ -1474,17 +1489,6 @@ static inline zig_i128 zig_subw_i128(zig_i128 lhs, zig_i128 rhs, zig_u8 bits) {
14741489 return zig_wrap_i128(zig_bitcast_i128(zig_sub_u128(zig_bitcast_u128(lhs), zig_bitcast_u128(rhs))), bits);
14751490}
14761491
1477#if _MSC_VER
1478static zig_u128 zig_mul_u128(zig_u128 lhs, zig_u128 rhs) {
1479 zig_u64 lo_carry;
1480 zig_u64 lo = _umul128(lhs.lo, rhs.lo, &lo_carry);
1481 zig_u64 hi = lhs.hi * rhs.lo + lhs.lo * rhs.hi + lo_carry;
1482 return zig_as_u128(hi, lo);
1483}
1484#else
1485static zig_u128 zig_mul_u128(zig_u128 lhs, zig_u128 rhs); // TODO
1486#endif
1487
14881492static inline zig_u128 zig_mulw_u128(zig_u128 lhs, zig_u128 rhs, zig_u8 bits) {
14891493 return zig_wrap_u128(zig_mul_u128(lhs, rhs), bits);
14901494}
......@@ -2218,8 +2222,11 @@ zig_msvc_atomics(u16, 16)
22182222zig_msvc_atomics(i16, 16)
22192223zig_msvc_atomics(u32, )
22202224zig_msvc_atomics(i32, )
2225
2226#if _M_X64
22212227zig_msvc_atomics(u64, 64)
22222228zig_msvc_atomics(i64, 64)
2229#endif
22232230
22242231#define zig_msvc_flt_atomics(Type, ReprType, suffix) \
22252232 static inline bool zig_msvc_cmpxchg_##Type(zig_##Type volatile* obj, zig_##Type* expected, zig_##Type desired) { \
......@@ -2259,7 +2266,9 @@ zig_msvc_atomics(i64, 64)
22592266 }
22602267
22612268zig_msvc_flt_atomics(f32, u32, )
2269#if _M_X64
22622270zig_msvc_flt_atomics(f64, u64, 64)
2271#endif
22632272
22642273#if _M_IX86
22652274static inline void* zig_msvc_atomicrmw_xchg_p32(void** obj, zig_u32* arg) {
......@@ -2283,7 +2292,7 @@ static inline bool zig_msvc_cmpxchg_p32(void** obj, void** expected, void* desir
22832292 }
22842293 return exchanged;
22852294}
2286#else
2295#else /* _M_IX86 */
22872296static inline void* zig_msvc_atomicrmw_xchg_p64(void** obj, zig_u64* arg) {
22882297 return _InterlockedExchangePointer(obj, arg);
22892298}
......@@ -2305,14 +2314,12 @@ static inline bool zig_msvc_cmpxchg_p64(void** obj, void** expected, void* desir
23052314 }
23062315 return exchanged;
23072316}
2308#endif
23092317
23102318static inline bool zig_msvc_cmpxchg_u128(zig_u128 volatile* obj, zig_u128* expected, zig_u128 desired) {
23112319 return _InterlockedCompareExchange128((zig_i64 volatile*)obj, desired.hi, desired.lo, (zig_i64*)expected);
23122320}
23132321
2314static inline bool zig_msvc_cmpxchg_i128(zig_i128 volatile* obj, zig_i128* expected, zig_i128 desired) {
2315 return _InterlockedCompareExchange128((zig_i64 volatile*)obj, desired.hi, desired.lo, (zig_u64*)expected);
2322static inline bool zig_msvc_cmpxchg_i128(zig_i128 volatile* obj, zig_i128* expected, zig_i128 desired) { return _InterlockedCompareExchange128((zig_i64 volatile*)obj, desired.hi, desired.lo, (zig_u64*)expected);
23162323}
23172324
23182325#define zig_msvc_atomics_128xchg(Type) \
......@@ -2350,6 +2357,7 @@ zig_msvc_atomics_128op(u128, and)
23502357zig_msvc_atomics_128op(u128, nand)
23512358zig_msvc_atomics_128op(u128, min)
23522359zig_msvc_atomics_128op(u128, max)
2360#endif /* _M_IX86 */
23532361
23542362#endif /* _MSC_VER && (_M_IX86 || _M_X64) */
23552363
......@@ -2359,7 +2367,7 @@ zig_msvc_atomics_128op(u128, max)
23592367
23602368static inline void* zig_x86_64_windows_teb(void) {
23612369#if _MSC_VER
2362 return __readgsqword(0x30);
2370 return (void*)__readgsqword(0x30);
23632371#else
23642372 void* teb;
23652373 __asm volatile(" movq %%gs:0x30, %[ptr]": [ptr]"=r"(teb)::);
......@@ -2367,6 +2375,18 @@ static inline void* zig_x86_64_windows_teb(void) {
23672375#endif
23682376}
23692377
2378#elif (_MSC_VER && _M_IX86) || defined(__i386__) || defined(__X86__)
2379
2380static inline void* zig_x86_windows_teb(void) {
2381#if _MSC_VER
2382 return (void*)__readfsdword(0x18);
2383#else
2384 void* teb;
2385 __asm volatile(" movl %%fs:0x18, %[ptr]": [ptr]"=r"(teb)::);
2386 return teb;
2387#endif
2388}
2389
23702390#endif
23712391
23722392#if (_MSC_VER && (_M_IX86 || _M_X64)) || defined(__i386__) || defined(__x86_64__)
src/codegen/c.zig+23-2
......@@ -1459,7 +1459,12 @@ pub const DeclGen = struct {
14591459
14601460 fn renderFunctionSignature(dg: *DeclGen, w: anytype, kind: TypedefKind, export_index: u32) !void {
14611461 const fn_info = dg.decl.ty.fnInfo();
1462 if (fn_info.cc == .Naked) try w.writeAll("zig_naked ");
1462 if (fn_info.cc == .Naked) {
1463 switch (kind) {
1464 .Forward => try w.writeAll("zig_naked_decl "),
1465 .Complete => try w.writeAll("zig_naked "),
1466 }
1467 }
14631468 if (dg.decl.val.castTag(.function)) |func_payload|
14641469 if (func_payload.data.is_cold) try w.writeAll("zig_cold ");
14651470
......@@ -1469,6 +1474,13 @@ pub const DeclGen = struct {
14691474
14701475 try dg.renderType(w, ret_ty, kind);
14711476 try w.writeByte(' ');
1477
1478 if (toCallingConvention(fn_info.cc)) |call_conv| {
1479 try w.print("zig_callconv({s}) ", .{call_conv});
1480 }
1481
1482 if (fn_info.alignment > 0 and kind == .Complete) try w.print(" zig_align_fn({})", .{ fn_info.alignment });
1483
14721484 try dg.renderDeclName(w, dg.decl_index, export_index);
14731485 try w.writeByte('(');
14741486
......@@ -1488,7 +1500,7 @@ pub const DeclGen = struct {
14881500 try dg.renderType(w, Type.void, kind);
14891501 }
14901502 try w.writeByte(')');
1491 if (fn_info.alignment > 0) try w.print(" zig_align_fn({})", .{fn_info.alignment});
1503 if (fn_info.alignment > 0 and kind == .Forward) try w.print(" zig_align_fn({})", .{fn_info.alignment});
14921504 }
14931505
14941506 fn renderPtrToFnTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 {
......@@ -7035,6 +7047,15 @@ fn writeMemoryOrder(w: anytype, order: std.builtin.AtomicOrder) !void {
70357047 return w.writeAll(toMemoryOrder(order));
70367048}
70377049
7050fn toCallingConvention(call_conv: std.builtin.CallingConvention) ?[]const u8 {
7051 return switch (call_conv) {
7052 .Stdcall => "stdcall",
7053 .Fastcall => "fastcall",
7054 .Vectorcall => "vectorcall",
7055 else => null,
7056 };
7057}
7058
70387059fn toAtomicRmwSuffix(order: std.builtin.AtomicRmwOp) []const u8 {
70397060 return switch (order) {
70407061 .Xchg => "xchg",
test/behavior/align.zig+3
......@@ -65,6 +65,9 @@ test "alignment and size of structs with 128-bit fields" {
6565 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
6666 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
6767
68 // https://github.com/ziglang/zig/issues/14371
69 if (builtin.zig_backend == .stage2_c and builtin.target.cpu.arch == .x86) return error.SkipZigTest;
70
6871 const A = struct {
6972 x: u128,
7073 };
test/behavior/int128.zig+28
......@@ -84,3 +84,31 @@ test "truncate int128" {
8484 try expect(@truncate(i128, buff) == maxInt(i128));
8585 }
8686}
87
88test "shift int128" {
89 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
90 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
91 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
92 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
93 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
94
95 const types = .{ u128, i128 };
96 inline for (types) |t| {
97 try testShlTrunc(t, 0x8, 123);
98 comptime try testShlTrunc(t, 0x8, 123);
99
100 try testShlTrunc(t, 0x40000000_00000000, 64);
101 comptime try testShlTrunc(t, 0x40000000_00000000, 64);
102
103 try testShlTrunc(t, 0x01000000_00000000_00000000, 38);
104 comptime try testShlTrunc(t, 0x01000000_00000000_00000000, 38);
105
106 try testShlTrunc(t, 0x00000008_00000000_00000000_00000000, 27);
107 comptime try testShlTrunc(t, 0x00000008_00000000_00000000_00000000, 27);
108 }
109}
110
111fn testShlTrunc(comptime Type: type, x: Type, rhs: u7) !void {
112 const shifted = x << rhs;
113 try expect(shifted == @as(Type, 0x40000000_00000000_00000000_00000000));
114}