aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorkcbanner <kcbanner@gmail.com>2022-12-28 02:05:15 -0500
committerkcbanner <kcbanner@gmail.com>2023-01-01 16:44:29 -0500
commit676e4f3824054cf39c87d008909b0e57bb9bdcc8 (patch)
tree5d00fe5e028d1bee54aac16303a2824053c57abf
parentf07d33f54b3448019f5e7c74c1f9063a5079b961 (diff)
downloadzig-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.zig31
-rw-r--r--lib/zig.h48
-rw-r--r--src/codegen/c.zig46
-rw-r--r--test/behavior/basic.zig14
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
diff --git a/lib/zig.h b/lib/zig.h
index 4455316bc3..0bd526b436 100644
--- a/lib/zig.h
+++ b/lib/zig.h
@@ -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);
}