| author | |
| committer | |
| log | 1aa2c32055c53657fd3a9825427454e0d74c20ed |
| tree | 382eb6948ec3ae17e373ef0ec75945d14a2c2e4a |
| parent | ce6de2df826347feadb66d087c43c77b2891dc0b |
- 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 tests8 files changed, 107 insertions(+), 30 deletions(-)
lib/compiler_rt/aulldiv.zig+1-1| ... | ... | @@ -7,7 +7,7 @@ const common = @import("common.zig"); |
| 7 | 7 | pub const panic = common.panic; |
| 8 | 8 | |
| 9 | 9 | comptime { |
| 10 | if (arch == .x86 and abi == .msvc) { | |
| 10 | if (arch == .x86 and abi == .msvc and builtin.zig_backend != .stage2_c) { | |
| 11 | 11 | // Don't let LLVM apply the stdcall name mangling on those MSVC builtins |
| 12 | 12 | @export(_alldiv, .{ .name = "\x01__alldiv", .linkage = common.linkage, .visibility = common.visibility }); |
| 13 | 13 | @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"); |
| 7 | 7 | pub const panic = common.panic; |
| 8 | 8 | |
| 9 | 9 | comptime { |
| 10 | if (arch == .x86 and abi == .msvc) { | |
| 10 | if (arch == .x86 and abi == .msvc and builtin.zig_backend != .stage2_c) { | |
| 11 | 11 | // Don't let LLVM apply the stdcall name mangling on those MSVC builtins |
| 12 | 12 | @export(_allrem, .{ .name = "\x01__allrem", .linkage = common.linkage, .visibility = common.visibility }); |
| 13 | 13 | @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( |
| 1804 | 1804 | |
| 1805 | 1805 | /// This is a workaround for the C backend until zig has the ability to put |
| 1806 | 1806 | /// C code in inline assembly. |
| 1807 | extern fn zig_x86_windows_teb() callconv(.C) *anyopaque; | |
| 1807 | 1808 | extern fn zig_x86_64_windows_teb() callconv(.C) *anyopaque; |
| 1808 | 1809 | |
| 1809 | 1810 | pub fn teb() *TEB { |
| 1810 | 1811 | 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 | }, | |
| 1815 | 1822 | .x86_64 => blk: { |
| 1816 | 1823 | if (builtin.zig_backend == .stage2_c) { |
| 1817 | 1824 | 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; |
| 7 | 7 | export var __xl_a: std.os.windows.PIMAGE_TLS_CALLBACK linksection(".CRT$XLA") = null; |
| 8 | 8 | export var __xl_z: std.os.windows.PIMAGE_TLS_CALLBACK linksection(".CRT$XLZ") = null; |
| 9 | 9 | |
| 10 | const tls_array: u32 = 0x2c; | |
| 10 | 11 | comptime { |
| 11 | 12 | if (builtin.target.cpu.arch == .x86) { |
| 12 | 13 | // The __tls_array is the offset of the ThreadLocalStoragePointer field |
| 13 | 14 | // 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" }); | |
| 18 | 16 | } |
| 19 | 17 | } |
| 20 | 18 |
lib/zig.h+38-18| ... | ... | @@ -52,15 +52,20 @@ typedef char bool; |
| 52 | 52 | |
| 53 | 53 | #if _MSC_VER |
| 54 | 54 | #define zig_const_arr |
| 55 | #define zig_callconv(c) __##c | |
| 55 | 56 | #else |
| 56 | 57 | #define zig_const_arr static const |
| 58 | #define zig_callconv(c) __attribute__((c)) | |
| 57 | 59 | #endif |
| 58 | 60 | |
| 59 | 61 | #if zig_has_attribute(naked) || defined(zig_gnuc) |
| 62 | #define zig_naked_decl __attribute__((naked)) | |
| 60 | 63 | #define zig_naked __attribute__((naked)) |
| 61 | 64 | #elif defined(_MSC_VER) |
| 65 | #define zig_naked_decl | |
| 62 | 66 | #define zig_naked __declspec(naked) |
| 63 | 67 | #else |
| 68 | #define zig_naked_decl zig_naked_unavailable | |
| 64 | 69 | #define zig_naked zig_naked_unavailable |
| 65 | 70 | #endif |
| 66 | 71 | |
| ... | ... | @@ -1214,8 +1219,14 @@ typedef struct { zig_align(16) zig_i64 hi; zig_u64 lo; } zig_i128; |
| 1214 | 1219 | |
| 1215 | 1220 | #define zig_as_u128(hi, lo) ((zig_u128){ .h##i = (hi), .l##o = (lo) }) |
| 1216 | 1221 | #define zig_as_i128(hi, lo) ((zig_i128){ .h##i = (hi), .l##o = (lo) }) |
| 1222 | ||
| 1223 | #if _MSC_VER | |
| 1217 | 1224 | #define zig_as_constant_u128(hi, lo) { .h##i = (hi), .l##o = (lo) } |
| 1218 | 1225 | #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 | |
| 1219 | 1230 | #define zig_hi_u128(val) ((val).hi) |
| 1220 | 1231 | #define zig_lo_u128(val) ((val).lo) |
| 1221 | 1232 | #define zig_hi_i128(val) ((val).hi) |
| ... | ... | @@ -1344,13 +1355,13 @@ static inline zig_u128 zig_shr_u128(zig_u128 lhs, zig_u8 rhs) { |
| 1344 | 1355 | |
| 1345 | 1356 | static inline zig_u128 zig_shl_u128(zig_u128 lhs, zig_u8 rhs) { |
| 1346 | 1357 | 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 }; | |
| 1348 | 1359 | return (zig_u128){ .hi = lhs.hi << rhs | lhs.lo >> (zig_as_u8(64) - rhs), .lo = lhs.lo << rhs }; |
| 1349 | 1360 | } |
| 1350 | 1361 | |
| 1351 | 1362 | static inline zig_i128 zig_shl_i128(zig_i128 lhs, zig_u8 rhs) { |
| 1352 | 1363 | 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 }; | |
| 1354 | 1365 | return (zig_i128){ .hi = lhs.hi << rhs | lhs.lo >> (zig_as_u8(64) - rhs), .lo = lhs.lo << rhs }; |
| 1355 | 1366 | } |
| 1356 | 1367 | |
| ... | ... | @@ -1379,6 +1390,10 @@ static inline zig_i128 zig_sub_i128(zig_i128 lhs, zig_i128 rhs) { |
| 1379 | 1390 | } |
| 1380 | 1391 | |
| 1381 | 1392 | zig_extern zig_i128 __multi3(zig_i128 lhs, zig_i128 rhs); |
| 1393 | static 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 | ||
| 1382 | 1397 | static zig_i128 zig_mul_i128(zig_i128 lhs, zig_i128 rhs) { |
| 1383 | 1398 | return __multi3(lhs, rhs); |
| 1384 | 1399 | } |
| ... | ... | @@ -1474,17 +1489,6 @@ static inline zig_i128 zig_subw_i128(zig_i128 lhs, zig_i128 rhs, zig_u8 bits) { |
| 1474 | 1489 | return zig_wrap_i128(zig_bitcast_i128(zig_sub_u128(zig_bitcast_u128(lhs), zig_bitcast_u128(rhs))), bits); |
| 1475 | 1490 | } |
| 1476 | 1491 | |
| 1477 | #if _MSC_VER | |
| 1478 | static 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 | |
| 1485 | static zig_u128 zig_mul_u128(zig_u128 lhs, zig_u128 rhs); // TODO | |
| 1486 | #endif | |
| 1487 | ||
| 1488 | 1492 | static inline zig_u128 zig_mulw_u128(zig_u128 lhs, zig_u128 rhs, zig_u8 bits) { |
| 1489 | 1493 | return zig_wrap_u128(zig_mul_u128(lhs, rhs), bits); |
| 1490 | 1494 | } |
| ... | ... | @@ -2218,8 +2222,11 @@ zig_msvc_atomics(u16, 16) |
| 2218 | 2222 | zig_msvc_atomics(i16, 16) |
| 2219 | 2223 | zig_msvc_atomics(u32, ) |
| 2220 | 2224 | zig_msvc_atomics(i32, ) |
| 2225 | ||
| 2226 | #if _M_X64 | |
| 2221 | 2227 | zig_msvc_atomics(u64, 64) |
| 2222 | 2228 | zig_msvc_atomics(i64, 64) |
| 2229 | #endif | |
| 2223 | 2230 | |
| 2224 | 2231 | #define zig_msvc_flt_atomics(Type, ReprType, suffix) \ |
| 2225 | 2232 | 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) |
| 2259 | 2266 | } |
| 2260 | 2267 | |
| 2261 | 2268 | zig_msvc_flt_atomics(f32, u32, ) |
| 2269 | #if _M_X64 | |
| 2262 | 2270 | zig_msvc_flt_atomics(f64, u64, 64) |
| 2271 | #endif | |
| 2263 | 2272 | |
| 2264 | 2273 | #if _M_IX86 |
| 2265 | 2274 | static 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 |
| 2283 | 2292 | } |
| 2284 | 2293 | return exchanged; |
| 2285 | 2294 | } |
| 2286 | #else | |
| 2295 | #else /* _M_IX86 */ | |
| 2287 | 2296 | static inline void* zig_msvc_atomicrmw_xchg_p64(void** obj, zig_u64* arg) { |
| 2288 | 2297 | return _InterlockedExchangePointer(obj, arg); |
| 2289 | 2298 | } |
| ... | ... | @@ -2305,14 +2314,12 @@ static inline bool zig_msvc_cmpxchg_p64(void** obj, void** expected, void* desir |
| 2305 | 2314 | } |
| 2306 | 2315 | return exchanged; |
| 2307 | 2316 | } |
| 2308 | #endif | |
| 2309 | 2317 | |
| 2310 | 2318 | static inline bool zig_msvc_cmpxchg_u128(zig_u128 volatile* obj, zig_u128* expected, zig_u128 desired) { |
| 2311 | 2319 | return _InterlockedCompareExchange128((zig_i64 volatile*)obj, desired.hi, desired.lo, (zig_i64*)expected); |
| 2312 | 2320 | } |
| 2313 | 2321 | |
| 2314 | static 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); | |
| 2322 | static 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); | |
| 2316 | 2323 | } |
| 2317 | 2324 | |
| 2318 | 2325 | #define zig_msvc_atomics_128xchg(Type) \ |
| ... | ... | @@ -2350,6 +2357,7 @@ zig_msvc_atomics_128op(u128, and) |
| 2350 | 2357 | zig_msvc_atomics_128op(u128, nand) |
| 2351 | 2358 | zig_msvc_atomics_128op(u128, min) |
| 2352 | 2359 | zig_msvc_atomics_128op(u128, max) |
| 2360 | #endif /* _M_IX86 */ | |
| 2353 | 2361 | |
| 2354 | 2362 | #endif /* _MSC_VER && (_M_IX86 || _M_X64) */ |
| 2355 | 2363 | |
| ... | ... | @@ -2359,7 +2367,7 @@ zig_msvc_atomics_128op(u128, max) |
| 2359 | 2367 | |
| 2360 | 2368 | static inline void* zig_x86_64_windows_teb(void) { |
| 2361 | 2369 | #if _MSC_VER |
| 2362 | return __readgsqword(0x30); | |
| 2370 | return (void*)__readgsqword(0x30); | |
| 2363 | 2371 | #else |
| 2364 | 2372 | void* teb; |
| 2365 | 2373 | __asm volatile(" movq %%gs:0x30, %[ptr]": [ptr]"=r"(teb)::); |
| ... | ... | @@ -2367,6 +2375,18 @@ static inline void* zig_x86_64_windows_teb(void) { |
| 2367 | 2375 | #endif |
| 2368 | 2376 | } |
| 2369 | 2377 | |
| 2378 | #elif (_MSC_VER && _M_IX86) || defined(__i386__) || defined(__X86__) | |
| 2379 | ||
| 2380 | static 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 | ||
| 2370 | 2390 | #endif |
| 2371 | 2391 | |
| 2372 | 2392 | #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 { |
| 1459 | 1459 | |
| 1460 | 1460 | fn renderFunctionSignature(dg: *DeclGen, w: anytype, kind: TypedefKind, export_index: u32) !void { |
| 1461 | 1461 | 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 | } | |
| 1463 | 1468 | if (dg.decl.val.castTag(.function)) |func_payload| |
| 1464 | 1469 | if (func_payload.data.is_cold) try w.writeAll("zig_cold "); |
| 1465 | 1470 | |
| ... | ... | @@ -1469,6 +1474,13 @@ pub const DeclGen = struct { |
| 1469 | 1474 | |
| 1470 | 1475 | try dg.renderType(w, ret_ty, kind); |
| 1471 | 1476 | 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 | ||
| 1472 | 1484 | try dg.renderDeclName(w, dg.decl_index, export_index); |
| 1473 | 1485 | try w.writeByte('('); |
| 1474 | 1486 | |
| ... | ... | @@ -1488,7 +1500,7 @@ pub const DeclGen = struct { |
| 1488 | 1500 | try dg.renderType(w, Type.void, kind); |
| 1489 | 1501 | } |
| 1490 | 1502 | 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}); | |
| 1492 | 1504 | } |
| 1493 | 1505 | |
| 1494 | 1506 | fn renderPtrToFnTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 { |
| ... | ... | @@ -7035,6 +7047,15 @@ fn writeMemoryOrder(w: anytype, order: std.builtin.AtomicOrder) !void { |
| 7035 | 7047 | return w.writeAll(toMemoryOrder(order)); |
| 7036 | 7048 | } |
| 7037 | 7049 | |
| 7050 | fn 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 | ||
| 7038 | 7059 | fn toAtomicRmwSuffix(order: std.builtin.AtomicRmwOp) []const u8 { |
| 7039 | 7060 | return switch (order) { |
| 7040 | 7061 | .Xchg => "xchg", |
test/behavior/align.zig+3| ... | ... | @@ -65,6 +65,9 @@ test "alignment and size of structs with 128-bit fields" { |
| 65 | 65 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 66 | 66 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 67 | 67 | |
| 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 | ||
| 68 | 71 | const A = struct { |
| 69 | 72 | x: u128, |
| 70 | 73 | }; |
test/behavior/int128.zig+28| ... | ... | @@ -84,3 +84,31 @@ test "truncate int128" { |
| 84 | 84 | try expect(@truncate(i128, buff) == maxInt(i128)); |
| 85 | 85 | } |
| 86 | 86 | } |
| 87 | ||
| 88 | test "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 | ||
| 111 | fn 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 | } |