diff options
| author | kcbanner <kcbanner@gmail.com> | 2022-12-28 02:05:15 -0500 |
|---|---|---|
| committer | kcbanner <kcbanner@gmail.com> | 2023-01-01 16:44:29 -0500 |
| commit | 676e4f3824054cf39c87d008909b0e57bb9bdcc8 (patch) | |
| tree | 5d00fe5e028d1bee54aac16303a2824053c57abf | |
| parent | f07d33f54b3448019f5e7c74c1f9063a5079b961 (diff) | |
| download | zig-676e4f3824054cf39c87d008909b0e57bb9bdcc8.tar.gz zig-676e4f3824054cf39c87d008909b0e57bb9bdcc8.zip | |
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
| -rw-r--r-- | lib/std/zig/system/x86.zig | 31 | ||||
| -rw-r--r-- | lib/zig.h | 48 | ||||
| -rw-r--r-- | src/codegen/c.zig | 46 | ||||
| -rw-r--r-- | test/behavior/basic.zig | 14 |
4 files changed, 107 insertions, 32 deletions
diff --git a/lib/std/zig/system/x86.zig b/lib/std/zig/system/x86.zig index 66468ba6ff..da09983ac7 100644 --- a/lib/std/zig/system/x86.zig +++ b/lib/std/zig/system/x86.zig @@ -1,4 +1,5 @@ const std = @import("std"); +const builtin = @import("builtin"); const Target = std.Target; const CrossTarget = std.zig.CrossTarget; @@ -527,25 +528,39 @@ const CpuidLeaf = packed struct { edx: u32, }; +extern fn zig_cpuid(leaf_id: u32, subid: u32, eax: *u32, ebx: *u32, ecx: *u32, edx: *u32) void; + fn cpuid(leaf_id: u32, subid: u32) CpuidLeaf { // valid for both x86 and x86_64 var eax: u32 = undefined; var ebx: u32 = undefined; var ecx: u32 = undefined; var edx: u32 = undefined; - asm volatile ("cpuid" - : [_] "={eax}" (eax), - [_] "={ebx}" (ebx), - [_] "={ecx}" (ecx), - [_] "={edx}" (edx), - : [_] "{eax}" (leaf_id), - [_] "{ecx}" (subid), - ); + + if (builtin.zig_backend == .stage2_c) { + zig_cpuid(leaf_id, subid, &eax, &ebx, &ecx, &edx); + } else { + asm volatile ("cpuid" + : [_] "={eax}" (eax), + [_] "={ebx}" (ebx), + [_] "={ecx}" (ecx), + [_] "={edx}" (edx), + : [_] "{eax}" (leaf_id), + [_] "{ecx}" (subid), + ); + } + return .{ .eax = eax, .ebx = ebx, .ecx = ecx, .edx = edx }; } +extern fn zig_get_xcr0() u32; + // Read control register 0 (XCR0). Used to detect features such as AVX. fn getXCR0() u32 { + if (builtin.zig_backend == .stage2_c) { + return zig_get_xcr0(); + } + return asm volatile ( \\ xor %%ecx, %%ecx \\ xgetbv @@ -6,6 +6,12 @@ #include <stddef.h> #include <stdint.h> +#if _MSC_VER +#include <intrin.h> +#else +#include <cpuid.h> +#endif + #if !defined(__cplusplus) && __STDC_VERSION__ <= 201710L #if __STDC_VERSION__ >= 199901L #include <stdbool.h> @@ -188,7 +194,6 @@ typedef char bool; #define zig_atomic_load(obj, order, type) __atomic_load_n (obj, order) #define zig_fence(order) __atomic_thread_fence(order) #elif _MSC_VER && (_M_IX86 || _M_X64) -#include <intrin.h> #define memory_order_relaxed 0 #define memory_order_consume 1 #define memory_order_acquire 2 @@ -1367,6 +1372,11 @@ static inline zig_i128 zig_sub_i128(zig_i128 lhs, zig_i128 rhs) { return res; } +zig_extern zig_i128 __multi3(zig_i128 lhs, zig_i128 rhs); +static zig_i128 zig_mul_i128(zig_i128 lhs, zig_i128 rhs) { + return __multi3(lhs, rhs); +} + zig_extern zig_u128 __udivti3(zig_u128 lhs, zig_u128 rhs); static zig_u128 zig_div_trunc_u128(zig_u128 lhs, zig_u128 rhs) { return __udivti3(lhs, rhs); @@ -1392,6 +1402,10 @@ static inline zig_i128 zig_mod_i128(zig_i128 lhs, zig_i128 rhs) { return zig_add_i128(rem, (((lhs.hi ^ rhs.hi) & rem.hi) < zig_as_i64(0) ? rhs : zig_as_i128(0, 0))); } +static inline zig_i128 zig_div_floor_i128(zig_i128 lhs, zig_i128 rhs) { + 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))); +} + #endif /* zig_has_int128 */ #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) { static zig_u128 zig_mul_u128(zig_u128 lhs, zig_u128 rhs); // TODO #endif -zig_extern zig_i128 __multi3(zig_i128 lhs, zig_i128 rhs); -static zig_i128 zig_mul_i128(zig_i128 lhs, zig_i128 rhs) { - return __multi3(lhs, rhs); -} - static inline zig_u128 zig_mulw_u128(zig_u128 lhs, zig_u128 rhs, zig_u8 bits) { return zig_wrap_u128(zig_mul_u128(lhs, rhs), bits); } @@ -2118,7 +2127,6 @@ zig_float_builtins(f128) zig_float_builtins(c_longdouble) #if _MSC_VER && (_M_IX86 || _M_X64) -#include <intrin.h> // TODO: zig_msvc_atomic_load should load 32 bit without interlocked on x86, and load 64 bit without interlocked on x64 @@ -2338,3 +2346,29 @@ zig_msvc_atomics_128op(u128, min) zig_msvc_atomics_128op(u128, max) #endif + +/* ========================= Special Case Intrinsics ========================= */ + +static inline void zig_cpuid(zig_u32 leaf_id, zig_u32 subid, zig_u32* eax, zig_u32* ebx, zig_u32* ecx, zig_u32* edx) { +#if _MSC_VER + zig_u32 cpu_info[4]; + __cpuidex(cpu_info, leaf_id, subid); + *eax = cpu_info[0]; + *ebx = cpu_info[1]; + *ecx = cpu_info[2]; + *edx = cpu_info[3]; +#else + __cpuid_count(leaf_id, subid, eax, ebx, ecx, edx); +#endif +} + +static inline zig_u32 zig_get_xcr0() { +#if _MSC_VER + return (zig_u32)_xgetbv(0); +#else + zig_u32 eax; + zig_u32 edx; + __asm__("xgetbv" : "=a"(eax), "=d"(edx) : "c"(0)); + return eax; +#endif +} diff --git a/src/codegen/c.zig b/src/codegen/c.zig index 216366e576..b97626990d 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -746,9 +746,9 @@ pub const DeclGen = struct { var int_pl = Type.Payload.Bits{ .base = .{ .tag = .int_signed }, .data = bits }; const int_ty = Type.initPayload(&int_pl.base); - try writer.writeByte('('); - try dg.renderTypecast(writer, ty); - try writer.writeAll(")zig_as_"); + try writer.writeAll("zig_cast_"); + try dg.renderTypeForBuiltinFnName(writer, ty); + try writer.writeAll(" zig_as_"); try dg.renderTypeForBuiltinFnName(writer, ty); try writer.writeByte('('); switch (bits) { @@ -3616,16 +3616,14 @@ fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue { try writer.writeAll(" = "); const needs_lo = operand_int_info.bits > 64 and dest_bits <= 64; - if (!needs_lo or dest_c_bits != 64 or dest_int_info.signedness != operand_int_info.signedness) { - try writer.writeByte('('); - try f.renderTypecast(writer, inst_ty); - try writer.writeByte(')'); - } - if (needs_lo) { try writer.writeAll("zig_lo_"); try f.object.dg.renderTypeForBuiltinFnName(writer, operand_ty); try writer.writeByte('('); + } else if (dest_c_bits <= 64) { + try writer.writeByte('('); + try f.renderTypecast(writer, inst_ty); + try writer.writeByte(')'); } if (dest_bits >= 8 and std.math.isPowerOfTwo(dest_bits)) { @@ -3640,11 +3638,11 @@ fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue { std.heap.stackFallback(@sizeOf(ExpectedContents), arena.allocator()); const mask_val = try inst_ty.maxInt(stack.get(), target); - - // TODO: This needs to use _and_ to do this to support > 64 bits and !zig_has_int128 + try writer.writeAll("zig_and_"); + try f.object.dg.renderTypeForBuiltinFnName(writer, operand_ty); try writer.writeByte('('); - try f.writeCValue(writer, operand, .Other); - try writer.print(" & {x})", .{try f.fmtIntLiteral(inst_ty, mask_val)}); + try f.writeCValue(writer, operand, .FunctionArgument); + try writer.print(", {x})", .{try f.fmtIntLiteral(operand_ty, mask_val)}); }, .signed => { const c_bits = toCIntBits(operand_int_info.bits) orelse @@ -3655,10 +3653,24 @@ fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue { }; const shift_val = Value.initPayload(&shift_pl.base); - // TODO: This needs to use shl and shr to do this to support > 64 bits and !zig_has_int128 - try writer.print("((int{d}_t)((uint{0d}_t)", .{c_bits}); - try f.writeCValue(writer, operand, .Other); - try writer.print(" << {}) >> {0})", .{try f.fmtIntLiteral(Type.u8, shift_val)}); + try writer.writeAll("zig_shr_"); + try f.object.dg.renderTypeForBuiltinFnName(writer, operand_ty); + if (c_bits == 128) { + try writer.print("(zig_bitcast_i{d}(", .{c_bits}); + } else { + try writer.print("((int{d}_t)", .{c_bits}); + } + try writer.print("zig_shl_u{d}(", .{c_bits}); + if (c_bits == 128) { + try writer.print("zig_bitcast_u{d}(", .{c_bits}); + } else { + try writer.print("(uint{d}_t)", .{c_bits}); + } + try f.writeCValue(writer, operand, .FunctionArgument); + if (c_bits == 128) try writer.writeByte(')'); + try writer.print(", {})", .{ try f.fmtIntLiteral(Type.u8, shift_val) }); + if (c_bits == 128) try writer.writeByte(')'); + try writer.print(", {})", .{ try f.fmtIntLiteral(Type.u8, shift_val) }); }, } diff --git a/test/behavior/basic.zig b/test/behavior/basic.zig index 6fcef06fc1..e704e190f3 100644 --- a/test/behavior/basic.zig +++ b/test/behavior/basic.zig @@ -37,6 +37,20 @@ test "truncate to non-power-of-two integers" { try testTrunc(i32, i5, std.math.maxInt(i32), -1); } +test "truncate to non-power-of-two integers from 128-bit" { + if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + + try testTrunc(u128, u1, 0xffffffff_ffffffff_ffffffff_01010101, 0x01); + try testTrunc(u128, u1, 0xffffffff_ffffffff_ffffffff_01010110, 0x00); + try testTrunc(u128, u2, 0xffffffff_ffffffff_ffffffff_01010101, 0x01); + try testTrunc(u128, u2, 0xffffffff_ffffffff_ffffffff_01010102, 0x02); + try testTrunc(i128, i5, -4, -4); + try testTrunc(i128, i5, 4, 4); + try testTrunc(i128, i5, -28, 4); + try testTrunc(i128, i5, 28, -4); + try testTrunc(i128, i5, std.math.maxInt(i128), -1); +} + fn testTrunc(comptime Big: type, comptime Little: type, big: Big, little: Little) !void { try expect(@truncate(Little, big) == little); } |
