authorgravatar for kcbanner@gmail.comCasey Banner <kcbanner@gmail.com> 2022-12-28 02:05:15-05:00
committergravatar for kcbanner@gmail.comCasey Banner <kcbanner@gmail.com> 2023-01-01 16:44:29-05:00
log676e4f3824054cf39c87d008909b0e57bb9bdcc8
tree5d00fe5e028d1bee54aac16303a2824053c57abf
parentf07d33f54b3448019f5e7c74c1f9063a5079b961

cbe: changes to get zig2.c compiling under msvc

- Add cpuid / getXCR0 functions for the cbe to use instead of asm blocks - Don't cast between 128 bit types during truncation - Fixup truncation to use functions for shifts / adds - Fixup float casts for undefined values - Add test for 128 bit integer truncation

4 files changed, 107 insertions(+), 32 deletions(-)

lib/std/zig/system/x86.zig+23-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,39 @@ const CpuidLeaf = packed struct {...@@ -527,25 +528,39 @@ const CpuidLeaf = packed struct {
527 edx: u32,528 edx: u32,
528};529};
529530
531extern fn zig_cpuid(leaf_id: u32, subid: u32, eax: *u32, ebx: *u32, ecx: *u32, edx: *u32) void;
532
530fn cpuid(leaf_id: u32, subid: u32) CpuidLeaf {533fn cpuid(leaf_id: u32, subid: u32) CpuidLeaf {
531 // valid for both x86 and x86_64534 // valid for both x86 and x86_64
532 var eax: u32 = undefined;535 var eax: u32 = undefined;
533 var ebx: u32 = undefined;536 var ebx: u32 = undefined;
534 var ecx: u32 = undefined;537 var ecx: u32 = undefined;
535 var edx: u32 = undefined;538 var edx: u32 = undefined;
536 asm volatile ("cpuid"539
537 : [_] "={eax}" (eax),540 if (builtin.zig_backend == .stage2_c) {
538 [_] "={ebx}" (ebx),541 zig_cpuid(leaf_id, subid, &eax, &ebx, &ecx, &edx);
539 [_] "={ecx}" (ecx),542 } else {
540 [_] "={edx}" (edx),543 asm volatile ("cpuid"
541 : [_] "{eax}" (leaf_id),544 : [_] "={eax}" (eax),
542 [_] "{ecx}" (subid),545 [_] "={ebx}" (ebx),
543 );546 [_] "={ecx}" (ecx),
547 [_] "={edx}" (edx),
548 : [_] "{eax}" (leaf_id),
549 [_] "{ecx}" (subid),
550 );
551 }
552
544 return .{ .eax = eax, .ebx = ebx, .ecx = ecx, .edx = edx };553 return .{ .eax = eax, .ebx = ebx, .ecx = ecx, .edx = edx };
545}554}
546555
556extern fn zig_get_xcr0() u32;
557
547// Read control register 0 (XCR0). Used to detect features such as AVX.558// Read control register 0 (XCR0). Used to detect features such as AVX.
548fn getXCR0() u32 {559fn getXCR0() u32 {
560 if (builtin.zig_backend == .stage2_c) {
561 return zig_get_xcr0();
562 }
563
549 return asm volatile (564 return asm volatile (
550 \\ xor %%ecx, %%ecx565 \\ xor %%ecx, %%ecx
551 \\ xgetbv566 \\ xgetbv
lib/zig.h+41-7
...@@ -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#else
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>
...@@ -188,7 +194,6 @@ typedef char bool;...@@ -188,7 +194,6 @@ typedef char bool;
188#define zig_atomic_load(obj, order, type) __atomic_load_n (obj, order)194#define zig_atomic_load(obj, order, type) __atomic_load_n (obj, order)
189#define zig_fence(order) __atomic_thread_fence(order)195#define zig_fence(order) __atomic_thread_fence(order)
190#elif _MSC_VER && (_M_IX86 || _M_X64)196#elif _MSC_VER && (_M_IX86 || _M_X64)
191#include <intrin.h>
192#define memory_order_relaxed 0197#define memory_order_relaxed 0
193#define memory_order_consume 1198#define memory_order_consume 1
194#define memory_order_acquire 2199#define memory_order_acquire 2
...@@ -1367,6 +1372,11 @@ static inline zig_i128 zig_sub_i128(zig_i128 lhs, zig_i128 rhs) {...@@ -1367,6 +1372,11 @@ static inline zig_i128 zig_sub_i128(zig_i128 lhs, zig_i128 rhs) {
1367 return res;1372 return res;
1368}1373}
13691374
1375zig_extern zig_i128 __multi3(zig_i128 lhs, zig_i128 rhs);
1376static zig_i128 zig_mul_i128(zig_i128 lhs, zig_i128 rhs) {
1377 return __multi3(lhs, rhs);
1378}
1379
1370zig_extern zig_u128 __udivti3(zig_u128 lhs, zig_u128 rhs);1380zig_extern zig_u128 __udivti3(zig_u128 lhs, zig_u128 rhs);
1371static zig_u128 zig_div_trunc_u128(zig_u128 lhs, zig_u128 rhs) {1381static zig_u128 zig_div_trunc_u128(zig_u128 lhs, zig_u128 rhs) {
1372 return __udivti3(lhs, rhs);1382 return __udivti3(lhs, rhs);
...@@ -1392,6 +1402,10 @@ static inline zig_i128 zig_mod_i128(zig_i128 lhs, zig_i128 rhs) {...@@ -1392,6 +1402,10 @@ static inline zig_i128 zig_mod_i128(zig_i128 lhs, zig_i128 rhs) {
1392 return zig_add_i128(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)));
1393}1403}
13941404
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)));
1407}
1408
1395#endif /* zig_has_int128 */1409#endif /* zig_has_int128 */
13961410
1397#define zig_div_floor_u128 zig_div_trunc_u1281411#define zig_div_floor_u128 zig_div_trunc_u128
...@@ -1465,11 +1479,6 @@ static zig_u128 zig_mul_u128(zig_u128 lhs, zig_u128 rhs) {...@@ -1465,11 +1479,6 @@ static zig_u128 zig_mul_u128(zig_u128 lhs, zig_u128 rhs) {
1465static zig_u128 zig_mul_u128(zig_u128 lhs, zig_u128 rhs); // TODO1479static zig_u128 zig_mul_u128(zig_u128 lhs, zig_u128 rhs); // TODO
1466#endif1480#endif
14671481
1468zig_extern zig_i128 __multi3(zig_i128 lhs, zig_i128 rhs);
1469static zig_i128 zig_mul_i128(zig_i128 lhs, zig_i128 rhs) {
1470 return __multi3(lhs, rhs);
1471}
1472
1473static 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) {
1474 return zig_wrap_u128(zig_mul_u128(lhs, rhs), bits);1483 return zig_wrap_u128(zig_mul_u128(lhs, rhs), bits);
1475}1484}
...@@ -2118,7 +2127,6 @@ zig_float_builtins(f128)...@@ -2118,7 +2127,6 @@ zig_float_builtins(f128)
2118zig_float_builtins(c_longdouble)2127zig_float_builtins(c_longdouble)
21192128
2120#if _MSC_VER && (_M_IX86 || _M_X64)2129#if _MSC_VER && (_M_IX86 || _M_X64)
2121#include <intrin.h>
21222130
2123// TODO: zig_msvc_atomic_load should load 32 bit without interlocked on x86, and load 64 bit without interlocked on x642131// TODO: zig_msvc_atomic_load should load 32 bit without interlocked on x86, and load 64 bit without interlocked on x64
21242132
...@@ -2338,3 +2346,29 @@ zig_msvc_atomics_128op(u128, min)...@@ -2338,3 +2346,29 @@ zig_msvc_atomics_128op(u128, min)
2338zig_msvc_atomics_128op(u128, max)2346zig_msvc_atomics_128op(u128, max)
23392347
2340#endif2348#endif
2349
2350/* ========================= Special Case Intrinsics ========================= */
2351
2352static inline void zig_cpuid(zig_u32 leaf_id, zig_u32 subid, zig_u32* eax, zig_u32* ebx, zig_u32* ecx, zig_u32* edx) {
2353#if _MSC_VER
2354 zig_u32 cpu_info[4];
2355 __cpuidex(cpu_info, leaf_id, subid);
2356 *eax = cpu_info[0];
2357 *ebx = cpu_info[1];
2358 *ecx = cpu_info[2];
2359 *edx = cpu_info[3];
2360#else
2361 __cpuid_count(leaf_id, subid, eax, ebx, ecx, edx);
2362#endif
2363}
2364
2365static inline zig_u32 zig_get_xcr0() {
2366#if _MSC_VER
2367 return (zig_u32)_xgetbv(0);
2368#else
2369 zig_u32 eax;
2370 zig_u32 edx;
2371 __asm__("xgetbv" : "=a"(eax), "=d"(edx) : "c"(0));
2372 return eax;
2373#endif
2374}
src/codegen/c.zig+29-17
...@@ -746,9 +746,9 @@ pub const DeclGen = struct {...@@ -746,9 +746,9 @@ pub const DeclGen = struct {
746 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 };
747 const int_ty = Type.initPayload(&int_pl.base);747 const int_ty = Type.initPayload(&int_pl.base);
748748
749 try writer.writeByte('(');749 try writer.writeAll("zig_cast_");
750 try dg.renderTypecast(writer, ty);750 try dg.renderTypeForBuiltinFnName(writer, ty);
751 try writer.writeAll(")zig_as_");751 try writer.writeAll(" zig_as_");
752 try dg.renderTypeForBuiltinFnName(writer, ty);752 try dg.renderTypeForBuiltinFnName(writer, ty);
753 try writer.writeByte('(');753 try writer.writeByte('(');
754 switch (bits) {754 switch (bits) {
...@@ -3616,16 +3616,14 @@ fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3616,16 +3616,14 @@ fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue {
3616 try writer.writeAll(" = ");3616 try writer.writeAll(" = ");
36173617
3618 const needs_lo = operand_int_info.bits > 64 and dest_bits <= 64;3618 const needs_lo = operand_int_info.bits > 64 and dest_bits <= 64;
3619 if (!needs_lo or dest_c_bits != 64 or dest_int_info.signedness != operand_int_info.signedness) {
3620 try writer.writeByte('(');
3621 try f.renderTypecast(writer, inst_ty);
3622 try writer.writeByte(')');
3623 }
3624
3625 if (needs_lo) {3619 if (needs_lo) {
3626 try writer.writeAll("zig_lo_");3620 try writer.writeAll("zig_lo_");
3627 try f.object.dg.renderTypeForBuiltinFnName(writer, operand_ty);3621 try f.object.dg.renderTypeForBuiltinFnName(writer, operand_ty);
3628 try writer.writeByte('(');3622 try writer.writeByte('(');
3623 } else if (dest_c_bits <= 64) {
3624 try writer.writeByte('(');
3625 try f.renderTypecast(writer, inst_ty);
3626 try writer.writeByte(')');
3629 }3627 }
36303628
3631 if (dest_bits >= 8 and std.math.isPowerOfTwo(dest_bits)) {3629 if (dest_bits >= 8 and std.math.isPowerOfTwo(dest_bits)) {
...@@ -3640,11 +3638,11 @@ fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3640,11 +3638,11 @@ fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue {
3640 std.heap.stackFallback(@sizeOf(ExpectedContents), arena.allocator());3638 std.heap.stackFallback(@sizeOf(ExpectedContents), arena.allocator());
36413639
3642 const mask_val = try inst_ty.maxInt(stack.get(), target);3640 const mask_val = try inst_ty.maxInt(stack.get(), target);
36433641 try writer.writeAll("zig_and_");
3644 // TODO: This needs to use _and_ to do this to support > 64 bits and !zig_has_int1283642 try f.object.dg.renderTypeForBuiltinFnName(writer, operand_ty);
3645 try writer.writeByte('(');3643 try writer.writeByte('(');
3646 try f.writeCValue(writer, operand, .Other);3644 try f.writeCValue(writer, operand, .FunctionArgument);
3647 try writer.print(" & {x})", .{try f.fmtIntLiteral(inst_ty, mask_val)});3645 try writer.print(", {x})", .{try f.fmtIntLiteral(operand_ty, mask_val)});
3648 },3646 },
3649 .signed => {3647 .signed => {
3650 const c_bits = toCIntBits(operand_int_info.bits) orelse3648 const c_bits = toCIntBits(operand_int_info.bits) orelse
...@@ -3655,10 +3653,24 @@ fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3655,10 +3653,24 @@ fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue {
3655 };3653 };
3656 const shift_val = Value.initPayload(&shift_pl.base);3654 const shift_val = Value.initPayload(&shift_pl.base);
36573655
3658 // TODO: This needs to use shl and shr to do this to support > 64 bits and !zig_has_int1283656 try writer.writeAll("zig_shr_");
3659 try writer.print("((int{d}_t)((uint{0d}_t)", .{c_bits});3657 try f.object.dg.renderTypeForBuiltinFnName(writer, operand_ty);
3660 try f.writeCValue(writer, operand, .Other);3658 if (c_bits == 128) {
3661 try writer.print(" << {}) >> {0})", .{try f.fmtIntLiteral(Type.u8, shift_val)});3659 try writer.print("(zig_bitcast_i{d}(", .{c_bits});
3660 } else {
3661 try writer.print("((int{d}_t)", .{c_bits});
3662 }
3663 try writer.print("zig_shl_u{d}(", .{c_bits});
3664 if (c_bits == 128) {
3665 try writer.print("zig_bitcast_u{d}(", .{c_bits});
3666 } else {
3667 try writer.print("(uint{d}_t)", .{c_bits});
3668 }
3669 try f.writeCValue(writer, operand, .FunctionArgument);
3670 if (c_bits == 128) try writer.writeByte(')');
3671 try writer.print(", {})", .{ try f.fmtIntLiteral(Type.u8, shift_val) });
3672 if (c_bits == 128) try writer.writeByte(')');
3673 try writer.print(", {})", .{ try f.fmtIntLiteral(Type.u8, shift_val) });
3662 },3674 },
3663 }3675 }
36643676
test/behavior/basic.zig+14
...@@ -37,6 +37,20 @@ test "truncate to non-power-of-two integers" {...@@ -37,6 +37,20 @@ 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_sparc64) return error.SkipZigTest; // TODO
42
43 try testTrunc(u128, u1, 0xffffffff_ffffffff_ffffffff_01010101, 0x01);
44 try testTrunc(u128, u1, 0xffffffff_ffffffff_ffffffff_01010110, 0x00);
45 try testTrunc(u128, u2, 0xffffffff_ffffffff_ffffffff_01010101, 0x01);
46 try testTrunc(u128, u2, 0xffffffff_ffffffff_ffffffff_01010102, 0x02);
47 try testTrunc(i128, i5, -4, -4);
48 try testTrunc(i128, i5, 4, 4);
49 try testTrunc(i128, i5, -28, 4);
50 try testTrunc(i128, i5, 28, -4);
51 try testTrunc(i128, i5, std.math.maxInt(i128), -1);
52}
53
40fn testTrunc(comptime Big: type, comptime Little: type, big: Big, little: Little) !void {54fn testTrunc(comptime Big: type, comptime Little: type, big: Big, little: Little) !void {
41 try expect(@truncate(Little, big) == little);55 try expect(@truncate(Little, big) == little);
42}56}