diff --git a/lib/zig.h b/lib/zig.h index 9a5e751f79..d336ecb2e2 100644 --- a/lib/zig.h +++ b/lib/zig.h @@ -316,7 +316,7 @@ zig_extern void *memset (void *, int, size_t); /* ===================== 8/16/32/64-bit Integer Support ===================== */ -#if __STDC_VERSION__ >= 199901L +#if __STDC_VERSION__ >= 199901L || _MSC_VER #include #else @@ -1923,6 +1923,7 @@ typedef double zig_f16; #define zig_make_f16(fp, repr) fp #elif LDBL_MANT_DIG == 11 #define zig_bitSizeOf_c_longdouble 16 +typedef uint16_t zig_repr_c_longdouble; typedef long double zig_f16; #define zig_make_f16(fp, repr) fp##l #elif FLT16_MANT_DIG == 11 && (zig_has_builtin(inff16) || defined(zig_gnuc)) @@ -1959,6 +1960,7 @@ typedef double zig_f32; #define zig_make_f32(fp, repr) fp #elif LDBL_MANT_DIG == 24 #define zig_bitSizeOf_c_longdouble 32 +typedef uint32_t zig_repr_c_longdouble; typedef long double zig_f32; #define zig_make_f32(fp, repr) fp##l #elif FLT32_MANT_DIG == 24 @@ -1982,6 +1984,7 @@ typedef int32_t zig_f32; #if _MSC_VER #ifdef ZIG_TARGET_ABI_MSVC #define zig_bitSizeOf_c_longdouble 64 +typedef uint64_t zig_repr_c_longdouble; #endif #define zig_make_special_constant_f64(sign, name, arg, repr) sign zig_make_f64(zig_msvc_flt_##name, ) #else /* _MSC_VER */ @@ -1995,6 +1998,7 @@ typedef double zig_f64; #define zig_make_f64(fp, repr) fp #elif LDBL_MANT_DIG == 53 #define zig_bitSizeOf_c_longdouble 64 +typedef uint64_t zig_repr_c_longdouble; typedef long double zig_f64; #define zig_make_f64(fp, repr) fp##l #elif FLT64_MANT_DIG == 53 @@ -2027,6 +2031,7 @@ typedef double zig_f80; #define zig_make_f80(fp, repr) fp #elif LDBL_MANT_DIG == 64 #define zig_bitSizeOf_c_longdouble 80 +typedef zig_u128 zig_repr_c_longdouble; typedef long double zig_f80; #define zig_make_f80(fp, repr) fp##l #elif FLT80_MANT_DIG == 64 @@ -2062,6 +2067,7 @@ typedef double zig_f128; #define zig_make_f128(fp, repr) fp #elif LDBL_MANT_DIG == 113 #define zig_bitSizeOf_c_longdouble 128 +typedef zig_u128 zig_repr_c_longdouble; typedef long double zig_f128; #define zig_make_f128(fp, repr) fp##l #elif FLT128_MANT_DIG == 113 @@ -2099,9 +2105,10 @@ typedef zig_i128 zig_f128; #ifdef zig_bitSizeOf_c_longdouble #ifdef ZIG_TARGET_ABI_MSVC -typedef double zig_c_longdouble; #undef zig_bitSizeOf_c_longdouble #define zig_bitSizeOf_c_longdouble 64 +typedef uint64_t zig_repr_c_longdouble; +typedef zig_f64 zig_c_longdouble; #define zig_make_c_longdouble(fp, repr) fp #else typedef long double zig_c_longdouble; @@ -2113,6 +2120,7 @@ typedef long double zig_c_longdouble; #undef zig_has_c_longdouble #define zig_has_c_longdouble 0 #define zig_bitSizeOf_c_longdouble 80 +typedef zig_u128 zig_repr_c_longdouble; #define zig_compiler_rt_abbrev_c_longdouble zig_compiler_rt_abbrev_f80 #define zig_bitSizeOf_repr_c_longdouble 128 typedef zig_i128 zig_c_longdouble; @@ -2126,21 +2134,18 @@ typedef zig_i128 zig_c_longdouble; #if !zig_has_float_builtins #define zig_float_from_repr(Type, ReprType) \ - static inline zig_##Type zig_float_from_repr_##Type(zig_##ReprType repr) { \ - return *((zig_##Type*)&repr); \ + static inline zig_##Type zig_float_from_repr_##Type(ReprType repr) { \ + zig_##Type result; \ + memcpy(&result, &repr, sizeof(result)); \ + return result; \ } -zig_float_from_repr(f16, u16) -zig_float_from_repr(f32, u32) -zig_float_from_repr(f64, u64) -zig_float_from_repr(f80, u128) -zig_float_from_repr(f128, u128) -#if zig_bitSizeOf_c_longdouble == 80 -zig_float_from_repr(c_longdouble, u128) -#else -#define zig_expand_float_from_repr(Type, ReprType) zig_float_from_repr(Type, ReprType) -zig_expand_float_from_repr(c_longdouble, zig_expand_concat(u, zig_bitSizeOf_c_longdouble)) -#endif +zig_float_from_repr(f16, uint16_t) +zig_float_from_repr(f32, uint32_t) +zig_float_from_repr(f64, uint64_t) +zig_float_from_repr(f80, zig_u128) +zig_float_from_repr(f128, zig_u128) +zig_float_from_repr(c_longdouble, zig_repr_c_longdouble) #endif #define zig_cast_f16 (zig_f16) @@ -2288,98 +2293,98 @@ zig_float_builtins(c_longdouble) // TODO: zig_msvc_atomic_load should load 32 bit without interlocked on x86, and load 64 bit without interlocked on x64 -#define zig_msvc_atomics(Type, suffix) \ - static inline bool zig_msvc_cmpxchg_##Type(zig_##Type volatile* obj, zig_##Type* expected, zig_##Type desired) { \ - zig_##Type comparand = *expected; \ - zig_##Type initial = _InterlockedCompareExchange##suffix(obj, desired, comparand); \ +#define zig_msvc_atomics(ZigType, Type, suffix) \ + static inline bool zig_msvc_cmpxchg_##ZigType(Type volatile* obj, Type* expected, Type desired) { \ + Type comparand = *expected; \ + Type initial = _InterlockedCompareExchange##suffix(obj, desired, comparand); \ bool exchanged = initial == comparand; \ if (!exchanged) { \ *expected = initial; \ } \ return exchanged; \ } \ - static inline zig_##Type zig_msvc_atomicrmw_xchg_##Type(zig_##Type volatile* obj, zig_##Type value) { \ + static inline Type zig_msvc_atomicrmw_xchg_##ZigType(Type volatile* obj, Type value) { \ return _InterlockedExchange##suffix(obj, value); \ } \ - static inline zig_##Type zig_msvc_atomicrmw_add_##Type(zig_##Type volatile* obj, zig_##Type value) { \ + static inline Type zig_msvc_atomicrmw_add_##ZigType(Type volatile* obj, Type value) { \ return _InterlockedExchangeAdd##suffix(obj, value); \ } \ - static inline zig_##Type zig_msvc_atomicrmw_sub_##Type(zig_##Type volatile* obj, zig_##Type value) { \ + static inline Type zig_msvc_atomicrmw_sub_##ZigType(Type volatile* obj, Type value) { \ bool success = false; \ - zig_##Type new; \ - zig_##Type prev; \ + Type new; \ + Type prev; \ while (!success) { \ prev = *obj; \ new = prev - value; \ - success = zig_msvc_cmpxchg_##Type(obj, &prev, new); \ + success = zig_msvc_cmpxchg_##ZigType(obj, &prev, new); \ } \ return prev; \ } \ - static inline zig_##Type zig_msvc_atomicrmw_or_##Type(zig_##Type volatile* obj, zig_##Type value) { \ + static inline Type zig_msvc_atomicrmw_or_##ZigType(Type volatile* obj, Type value) { \ return _InterlockedOr##suffix(obj, value); \ } \ - static inline zig_##Type zig_msvc_atomicrmw_xor_##Type(zig_##Type volatile* obj, zig_##Type value) { \ + static inline Type zig_msvc_atomicrmw_xor_##ZigType(Type volatile* obj, Type value) { \ return _InterlockedXor##suffix(obj, value); \ } \ - static inline zig_##Type zig_msvc_atomicrmw_and_##Type(zig_##Type volatile* obj, zig_##Type value) { \ + static inline Type zig_msvc_atomicrmw_and_##ZigType(Type volatile* obj, Type value) { \ return _InterlockedAnd##suffix(obj, value); \ } \ - static inline zig_##Type zig_msvc_atomicrmw_nand_##Type(zig_##Type volatile* obj, zig_##Type value) { \ + static inline Type zig_msvc_atomicrmw_nand_##ZigType(Type volatile* obj, Type value) { \ bool success = false; \ - zig_##Type new; \ - zig_##Type prev; \ + Type new; \ + Type prev; \ while (!success) { \ prev = *obj; \ new = ~(prev & value); \ - success = zig_msvc_cmpxchg_##Type(obj, &prev, new); \ + success = zig_msvc_cmpxchg_##ZigType(obj, &prev, new); \ } \ return prev; \ } \ - static inline zig_##Type zig_msvc_atomicrmw_min_##Type(zig_##Type volatile* obj, zig_##Type value) { \ + static inline Type zig_msvc_atomicrmw_min_##ZigType(Type volatile* obj, Type value) { \ bool success = false; \ - zig_##Type new; \ - zig_##Type prev; \ + Type new; \ + Type prev; \ while (!success) { \ prev = *obj; \ new = value < prev ? value : prev; \ - success = zig_msvc_cmpxchg_##Type(obj, &prev, new); \ + success = zig_msvc_cmpxchg_##ZigType(obj, &prev, new); \ } \ return prev; \ } \ - static inline zig_##Type zig_msvc_atomicrmw_max_##Type(zig_##Type volatile* obj, zig_##Type value) { \ + static inline Type zig_msvc_atomicrmw_max_##ZigType(Type volatile* obj, Type value) { \ bool success = false; \ - zig_##Type new; \ - zig_##Type prev; \ + Type new; \ + Type prev; \ while (!success) { \ prev = *obj; \ new = value > prev ? value : prev; \ - success = zig_msvc_cmpxchg_##Type(obj, &prev, new); \ + success = zig_msvc_cmpxchg_##ZigType(obj, &prev, new); \ } \ return prev; \ } \ - static inline void zig_msvc_atomic_store_##Type(zig_##Type volatile* obj, zig_##Type value) { \ + static inline void zig_msvc_atomic_store_##ZigType(Type volatile* obj, Type value) { \ _InterlockedExchange##suffix(obj, value); \ } \ - static inline zig_##Type zig_msvc_atomic_load_##Type(zig_##Type volatile* obj) { \ + static inline Type zig_msvc_atomic_load_##ZigType(Type volatile* obj) { \ return _InterlockedOr##suffix(obj, 0); \ } -zig_msvc_atomics(u8, 8) -zig_msvc_atomics(i8, 8) -zig_msvc_atomics(u16, 16) -zig_msvc_atomics(i16, 16) -zig_msvc_atomics(u32, ) -zig_msvc_atomics(i32, ) +zig_msvc_atomics( u8, uint8_t, 8) +zig_msvc_atomics( i8, int8_t, 8) +zig_msvc_atomics(u16, uint16_t, 16) +zig_msvc_atomics(i16, int16_t, 16) +zig_msvc_atomics(u32, uint32_t, ) +zig_msvc_atomics(i32, int32_t, ) #if _M_X64 -zig_msvc_atomics(u64, 64) -zig_msvc_atomics(i64, 64) +zig_msvc_atomics(u64, uint64_t, 64) +zig_msvc_atomics(i64, int64_t, 64) #endif #define zig_msvc_flt_atomics(Type, ReprType, suffix) \ static inline bool zig_msvc_cmpxchg_##Type(zig_##Type volatile* obj, zig_##Type* expected, zig_##Type desired) { \ - zig_##ReprType comparand = *((zig_##ReprType*)expected); \ - zig_##ReprType initial = _InterlockedCompareExchange##suffix((zig_##ReprType volatile*)obj, *((zig_##ReprType*)&desired), comparand); \ + ReprType comparand = *((ReprType*)expected); \ + ReprType initial = _InterlockedCompareExchange##suffix((ReprType volatile*)obj, *((ReprType*)&desired), comparand); \ bool exchanged = initial == comparand; \ if (!exchanged) { \ *expected = *((zig_##Type*)&initial); \ @@ -2387,35 +2392,35 @@ zig_msvc_atomics(i64, 64) return exchanged; \ } \ static inline zig_##Type zig_msvc_atomicrmw_xchg_##Type(zig_##Type volatile* obj, zig_##Type value) { \ - zig_##ReprType initial = _InterlockedExchange##suffix((zig_##ReprType volatile*)obj, *((zig_##ReprType*)&value)); \ + ReprType initial = _InterlockedExchange##suffix((ReprType volatile*)obj, *((ReprType*)&value)); \ return *((zig_##Type*)&initial); \ } \ static inline zig_##Type zig_msvc_atomicrmw_add_##Type(zig_##Type volatile* obj, zig_##Type value) { \ bool success = false; \ - zig_##ReprType new; \ + ReprType new; \ zig_##Type prev; \ while (!success) { \ prev = *obj; \ new = prev + value; \ - success = zig_msvc_cmpxchg_##Type(obj, &prev, *((zig_##ReprType*)&new)); \ + success = zig_msvc_cmpxchg_##Type(obj, &prev, *((ReprType*)&new)); \ } \ return prev; \ } \ static inline zig_##Type zig_msvc_atomicrmw_sub_##Type(zig_##Type volatile* obj, zig_##Type value) { \ bool success = false; \ - zig_##ReprType new; \ + ReprType new; \ zig_##Type prev; \ while (!success) { \ prev = *obj; \ new = prev - value; \ - success = zig_msvc_cmpxchg_##Type(obj, &prev, *((zig_##ReprType*)&new)); \ + success = zig_msvc_cmpxchg_##Type(obj, &prev, *((ReprType*)&new)); \ } \ return prev; \ } -zig_msvc_flt_atomics(f32, u32, ) +zig_msvc_flt_atomics(f32, uint32_t, ) #if _M_X64 -zig_msvc_flt_atomics(f64, u64, 64) +zig_msvc_flt_atomics(f64, uint64_t, 64) #endif #if _M_IX86 @@ -2426,11 +2431,11 @@ static inline void zig_msvc_atomic_barrier() { } } -static inline void* zig_msvc_atomicrmw_xchg_p32(void** obj, uint32_t* arg) { +static inline void* zig_msvc_atomicrmw_xchg_p32(void** obj, void* arg) { return _InterlockedExchangePointer(obj, arg); } -static inline void zig_msvc_atomic_store_p32(void** obj, uint32_t* arg) { +static inline void zig_msvc_atomic_store_p32(void** obj, void* arg) { _InterlockedExchangePointer(obj, arg); } @@ -2448,11 +2453,11 @@ static inline bool zig_msvc_cmpxchg_p32(void** obj, void** expected, void* desir return exchanged; } #else /* _M_IX86 */ -static inline void* zig_msvc_atomicrmw_xchg_p64(void** obj, uint64_t* arg) { +static inline void* zig_msvc_atomicrmw_xchg_p64(void** obj, void* arg) { return _InterlockedExchangePointer(obj, arg); } -static inline void zig_msvc_atomic_store_p64(void** obj, uint64_t* arg) { +static inline void zig_msvc_atomic_store_p64(void** obj, void* arg) { _InterlockedExchangePointer(obj, arg); } diff --git a/src/codegen/c.zig b/src/codegen/c.zig index 4ddfe3213a..1db4fc5d51 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -2058,6 +2058,7 @@ fn renderTypePrefix( .zig_f64, .zig_f80, .zig_f128, + .zig_c_longdouble, => |tag| try w.writeAll(@tagName(tag)), .pointer, @@ -2225,6 +2226,7 @@ fn renderTypeSuffix( .zig_f64, .zig_f80, .zig_f128, + .zig_c_longdouble, => {}, .pointer, @@ -3062,6 +3064,7 @@ fn airPtrElemPtr(f: *Function, inst: Air.Inst.Index) !CValue { return CValue.none; } + const inst_ty = f.air.typeOfIndex(inst); const ptr_ty = f.air.typeOf(bin_op.lhs); const child_ty = ptr_ty.childType(); @@ -3076,7 +3079,9 @@ fn airPtrElemPtr(f: *Function, inst: Air.Inst.Index) !CValue { const writer = f.object.writer(); const local = try f.allocLocal(inst, f.air.typeOfIndex(inst)); try f.writeCValue(writer, local, .Other); - try writer.writeAll(" = &("); + try writer.writeAll(" = ("); + try f.renderTypecast(writer, inst_ty); + try writer.writeAll(")&("); if (ptr_ty.ptrSize() == .One) { // It's a pointer to an array, so we need to de-reference. try f.writeCValueDeref(writer, ptr); @@ -3902,32 +3907,31 @@ fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: u8) !CValue { try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs }); const inst_ty = f.air.typeOfIndex(inst); - const elem_ty = switch (inst_ty.ptrSize()) { - .One => blk: { - const array_ty = inst_ty.childType(); - break :blk array_ty.childType(); - }, - else => inst_ty.childType(), - }; + const elem_ty = inst_ty.elemType2(); - // We must convert to and from integer types to prevent UB if the operation - // results in a NULL pointer, or if LHS is NULL. The operation is only UB - // if the result is NULL and then dereferenced. const local = try f.allocLocal(inst, inst_ty); const writer = f.object.writer(); try f.writeCValue(writer, local, .Other); - try writer.writeAll(" = ("); - try f.renderTypecast(writer, inst_ty); - try writer.writeAll(")(((uintptr_t)"); - try f.writeCValue(writer, lhs, .Other); - try writer.writeAll(") "); - try writer.writeByte(operator); - try writer.writeAll(" ("); - try f.writeCValue(writer, rhs, .Other); - try writer.writeAll("*sizeof("); - try f.renderTypecast(writer, elem_ty); - try writer.writeAll(")));\n"); + try writer.writeAll(" = "); + if (elem_ty.hasRuntimeBitsIgnoreComptime()) { + // We must convert to and from integer types to prevent UB if the operation + // results in a NULL pointer, or if LHS is NULL. The operation is only UB + // if the result is NULL and then dereferenced. + try writer.writeByte('('); + try f.renderTypecast(writer, inst_ty); + try writer.writeAll(")(((uintptr_t)"); + try f.writeCValue(writer, lhs, .Other); + try writer.writeAll(") "); + try writer.writeByte(operator); + try writer.writeAll(" ("); + try f.writeCValue(writer, rhs, .Other); + try writer.writeAll("*sizeof("); + try f.renderTypecast(writer, elem_ty); + try writer.writeAll(")))"); + } else try f.writeCValue(writer, lhs, .Initializer); + + try writer.writeAll(";\n"); return local; } @@ -5264,21 +5268,21 @@ fn structFieldPtr(f: *Function, inst: Air.Inst.Index, struct_ptr_ty: Type, struc else => unreachable, }; - try writer.writeByte('&'); - switch (field_loc) { - .begin, .end => { - try writer.writeByte('('); - try f.writeCValue(writer, struct_ptr, .Other); - try writer.print(")[{}]", .{ - @boolToInt(field_loc == .end and struct_ty.hasRuntimeBitsIgnoreComptime()), - }); - }, - .field => |field| if (extra_name != .none) { - try f.writeCValueDerefMember(writer, struct_ptr, extra_name); - try writer.writeByte('.'); - try f.writeCValue(writer, field, .Other); - } else try f.writeCValueDerefMember(writer, struct_ptr, field), - } + if (struct_ty.hasRuntimeBitsIgnoreComptime()) { + try writer.writeByte('&'); + switch (field_loc) { + .begin, .end => { + try writer.writeByte('('); + try f.writeCValue(writer, struct_ptr, .Other); + try writer.print(")[{}]", .{@boolToInt(field_loc == .end)}); + }, + .field => |field| if (extra_name != .none) { + try f.writeCValueDerefMember(writer, struct_ptr, extra_name); + try writer.writeByte('.'); + try f.writeCValue(writer, field, .Other); + } else try f.writeCValueDerefMember(writer, struct_ptr, field), + } + } else try f.writeCValue(writer, struct_ptr, .Other); try writer.writeAll(";\n"); return local; } diff --git a/src/codegen/c/type.zig b/src/codegen/c/type.zig index d6424b1f27..bf148a8b87 100644 --- a/src/codegen/c/type.zig +++ b/src/codegen/c/type.zig @@ -102,6 +102,7 @@ pub const CType = extern union { zig_f64, zig_f80, zig_f128, + zig_c_longdouble, // Keep last_no_payload_tag updated! // After this, the tag requires a payload. pointer, @@ -127,7 +128,7 @@ pub const CType = extern union { function, varargs_function, - pub const last_no_payload_tag = Tag.zig_f128; + pub const last_no_payload_tag = Tag.zig_c_longdouble; pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1; pub fn hasPayload(self: Tag) bool { @@ -177,6 +178,7 @@ pub const CType = extern union { .zig_f64, .zig_f80, .zig_f128, + .zig_c_longdouble, => @compileError("Type Tag " ++ @tagName(self) ++ " has no payload"), .pointer, @@ -557,6 +559,7 @@ pub const CType = extern union { .zig_f64, .zig_f80, .zig_f128, + .zig_c_longdouble, => false, .pointer, @@ -674,6 +677,7 @@ pub const CType = extern union { .zig_f64, .zig_f80, .zig_f128, + .zig_c_longdouble, => {}, .pointer, @@ -980,7 +984,7 @@ pub const CType = extern union { .f64 => .zig_f64, .f80 => .zig_f80, .f128 => .zig_f128, - .c_longdouble => .@"long double", + .c_longdouble => .zig_c_longdouble, else => unreachable, }), @@ -1374,6 +1378,7 @@ pub const CType = extern union { .zig_f64, .zig_f80, .zig_f128, + .zig_c_longdouble, => return self, .pointer, diff --git a/test/behavior/asm.zig b/test/behavior/asm.zig index e9a01226b1..b242374ef8 100644 --- a/test/behavior/asm.zig +++ b/test/behavior/asm.zig @@ -7,6 +7,7 @@ const is_x86_64_linux = builtin.cpu.arch == .x86_64 and builtin.os.tag == .linux comptime { if (builtin.zig_backend != .stage2_arm and builtin.zig_backend != .stage2_aarch64 and + !(builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) and // MSVC doesn't support inline assembly is_x86_64_linux) { asm ( @@ -24,6 +25,8 @@ test "module level assembly" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) return error.SkipZigTest; // MSVC doesn't support inline assembly + if (is_x86_64_linux) { try expect(this_is_my_alias() == 1234); } @@ -36,6 +39,8 @@ test "output constraint modifiers" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) return error.SkipZigTest; // MSVC doesn't support inline assembly + // This is only testing compilation. var a: u32 = 3; asm volatile ("" @@ -57,6 +62,8 @@ test "alternative constraints" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) return error.SkipZigTest; // MSVC doesn't support inline assembly + // Make sure we allow commas as a separator for alternative constraints. var a: u32 = 3; asm volatile ("" @@ -73,6 +80,8 @@ test "sized integer/float in asm input" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) return error.SkipZigTest; // MSVC doesn't support inline assembly + asm volatile ("" : : [_] "m" (@as(usize, 3)), @@ -122,6 +131,8 @@ test "struct/array/union types as input values" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) return error.SkipZigTest; // MSVC doesn't support inline assembly + asm volatile ("" : : [_] "m" (@as([1]u32, undefined)), @@ -146,6 +157,8 @@ test "asm modifiers (AArch64)" { if (builtin.target.cpu.arch != .aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) return error.SkipZigTest; // MSVC doesn't support inline assembly + var x: u32 = 15; const double = asm ("add %[ret:w], %[in:w], %[in:w]" : [ret] "=r" (-> u32),