diff --git a/src/arch/x86_64/abi.zig b/src/arch/x86_64/abi.zig index a6c71d398f..b0ab1acefd 100644 --- a/src/arch/x86_64/abi.zig +++ b/src/arch/x86_64/abi.zig @@ -18,10 +18,34 @@ pub fn classifyWindows(ty: Type, target: Target) Class { else => return .memory, } return switch (ty.zigTypeTag()) { - .Int, .Bool, .Enum, .Void, .NoReturn, .ErrorSet, .Struct, .Union => .integer, - .Optional => if (ty.isPtrLikeOptional()) return .integer else return .memory, + .Pointer, + .Int, + .Bool, + .Enum, + .Void, + .NoReturn, + .ErrorSet, + .Struct, + .Union, + .Optional, + .Array, + .ErrorUnion, + .AnyFrame, + .Frame, + => .integer, + .Float, .Vector => .sse, - else => unreachable, + + .Type, + .ComptimeFloat, + .ComptimeInt, + .Undefined, + .Null, + .BoundFn, + .Fn, + .Opaque, + .EnumLiteral, + => unreachable, }; } diff --git a/src/stage1/analyze.cpp b/src/stage1/analyze.cpp index ff68198fc3..c7756424a8 100644 --- a/src/stage1/analyze.cpp +++ b/src/stage1/analyze.cpp @@ -8255,23 +8255,53 @@ Error file_fetch(CodeGen *g, Buf *resolved_path, Buf *contents_buf) { static X64CABIClass type_windows_abi_x86_64_class(CodeGen *g, ZigType *ty, size_t ty_size) { // https://docs.microsoft.com/en-gb/cpp/build/x64-calling-convention?view=vs-2017 + switch (ty_size) { + case 1: + case 2: + case 4: + case 8: + break; + case 16: + return (ty->id == ZigTypeIdVector) ? X64CABIClass_SSE : X64CABIClass_MEMORY; + default: + return X64CABIClass_MEMORY; + } switch (ty->id) { - case ZigTypeIdEnum: + case ZigTypeIdInvalid: + case ZigTypeIdMetaType: + case ZigTypeIdComptimeFloat: + case ZigTypeIdComptimeInt: + case ZigTypeIdNull: + case ZigTypeIdUndefined: + case ZigTypeIdBoundFn: + case ZigTypeIdOpaque: + case ZigTypeIdEnumLiteral: + zig_unreachable(); + + case ZigTypeIdFn: + case ZigTypeIdPointer: case ZigTypeIdInt: case ZigTypeIdBool: + case ZigTypeIdEnum: + case ZigTypeIdVoid: + case ZigTypeIdUnreachable: + case ZigTypeIdErrorSet: + case ZigTypeIdErrorUnion: + case ZigTypeIdStruct: + case ZigTypeIdUnion: + case ZigTypeIdOptional: + case ZigTypeIdFnFrame: + case ZigTypeIdAnyFrame: return X64CABIClass_INTEGER; + case ZigTypeIdFloat: case ZigTypeIdVector: return X64CABIClass_SSE; - case ZigTypeIdStruct: - case ZigTypeIdUnion: { - if (ty_size <= 8) - return X64CABIClass_INTEGER; - return X64CABIClass_MEMORY; - } - default: + + case ZigTypeIdArray: return X64CABIClass_Unknown; } + zig_unreachable(); } static X64CABIClass type_system_V_abi_x86_64_class(CodeGen *g, ZigType *ty, size_t ty_size) { @@ -8350,17 +8380,19 @@ static X64CABIClass type_system_V_abi_x86_64_class(CodeGen *g, ZigType *ty, size X64CABIClass type_c_abi_x86_64_class(CodeGen *g, ZigType *ty) { Error err; - const size_t ty_size = type_size(g, ty); + + if (g->zig_target->os == OsWindows || g->zig_target->os == OsUefi) { + return type_windows_abi_x86_64_class(g, ty, ty_size); + } + ZigType *ptr_type; if ((err = get_codegen_ptr_type(g, ty, &ptr_type))) return X64CABIClass_Unknown; if (ptr_type != nullptr) return X64CABIClass_INTEGER; - if (g->zig_target->os == OsWindows || g->zig_target->os == OsUefi) { - return type_windows_abi_x86_64_class(g, ty, ty_size); - } else if (g->zig_target->arch == ZigLLVM_aarch64 || - g->zig_target->arch == ZigLLVM_aarch64_be) + if (g->zig_target->arch == ZigLLVM_aarch64 || + g->zig_target->arch == ZigLLVM_aarch64_be) { X64CABIClass result = type_system_V_abi_x86_64_class(g, ty, ty_size); return (result == X64CABIClass_MEMORY) ? X64CABIClass_MEMORY_nobyval : result; @@ -8660,14 +8692,23 @@ static Error resolve_llvm_c_abi_type(CodeGen *g, ZigType *ty) { if (ty->data.structure.fields[i]->offset >= 8) { eightbyte_index = 1; } - X64CABIClass field_class = type_c_abi_x86_64_class(g, ty->data.structure.fields[i]->type_entry); + ZigType *field_ty = ty->data.structure.fields[i]->type_entry; + X64CABIClass field_class = type_c_abi_x86_64_class(g, field_ty); if (field_class == X64CABIClass_INTEGER) { type_classes[eightbyte_index] = X64CABIClass_INTEGER; } else if (type_classes[eightbyte_index] == X64CABIClass_Unknown) { type_classes[eightbyte_index] = field_class; } - type_sizes[eightbyte_index] += ty->data.structure.fields[i]->type_entry->abi_size; + if (field_ty->abi_size > 8) { + assert(eightbyte_index == 0); + type_sizes[0] = 8; + type_sizes[1] = field_ty->abi_size - 8; + type_classes[1] = type_classes[0]; + eightbyte_index = 1; + } else { + type_sizes[eightbyte_index] += field_ty->abi_size; + } } LLVMTypeRef return_elem_types[] = { @@ -8956,8 +8997,12 @@ static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveS struct_type->data.structure.llvm_full_type_queue_index = SIZE_MAX; } - if (struct_type->abi_size <= 16 && (struct_type->data.structure.layout == ContainerLayoutExtern || struct_type->data.structure.layout == ContainerLayoutPacked)) + if (struct_type->abi_size <= 16 && + (struct_type->data.structure.layout == ContainerLayoutExtern || + struct_type->data.structure.layout == ContainerLayoutPacked)) + { resolve_llvm_c_abi_type(g, struct_type); + } } // This is to be used instead of void for debug info types, to avoid tripping diff --git a/test/stage1/c_abi/build.zig b/test/stage1/c_abi/build.zig index cf21d403f7..b9151f6dda 100644 --- a/test/stage1/c_abi/build.zig +++ b/test/stage1/c_abi/build.zig @@ -2,15 +2,18 @@ const Builder = @import("std").build.Builder; pub fn build(b: *Builder) void { const rel_opts = b.standardReleaseOptions(); + const target = b.standardTargetOptions(.{}); const c_obj = b.addObject("cfuncs", null); c_obj.addCSourceFile("cfuncs.c", &[_][]const u8{"-std=c99"}); c_obj.setBuildMode(rel_opts); c_obj.linkSystemLibrary("c"); + c_obj.target = target; const main = b.addTest("main.zig"); main.setBuildMode(rel_opts); main.addObject(c_obj); + main.target = target; const test_step = b.step("test", "Test the program"); test_step.dependOn(&main.step); diff --git a/test/stage1/c_abi/cfuncs.c b/test/stage1/c_abi/cfuncs.c index a2a5895ab4..f5c90adba0 100644 --- a/test/stage1/c_abi/cfuncs.c +++ b/test/stage1/c_abi/cfuncs.c @@ -11,14 +11,24 @@ static void assert_or_panic(bool ok) { } } +struct i128 { + __int128 value; +}; + +struct u128 { + unsigned __int128 value; +}; + void zig_u8(uint8_t); void zig_u16(uint16_t); void zig_u32(uint32_t); void zig_u64(uint64_t); +void zig_struct_u128(struct u128); void zig_i8(int8_t); void zig_i16(int16_t); void zig_i32(int32_t); void zig_i64(int64_t); +void zig_struct_i128(struct i128); void zig_five_integers(int32_t, int32_t, int32_t, int32_t, int32_t); void zig_f32(float); @@ -130,11 +140,19 @@ void run_c_tests(void) { zig_u16(0xfffe); zig_u32(0xfffffffd); zig_u64(0xfffffffffffffffc); + { + struct u128 s = {0xfffffffffffffffc}; + zig_struct_u128(s); + } zig_i8(-1); zig_i16(-2); zig_i32(-3); zig_i64(-4); + { + struct i128 s = {-6}; + zig_struct_i128(s); + } zig_five_integers(12, 34, 56, 78, 90); zig_f32(12.34f); @@ -221,6 +239,10 @@ void c_u64(uint64_t x) { assert_or_panic(x == 0xfffffffffffffffcULL); } +void c_struct_u128(struct u128 x) { + assert_or_panic(x.value == 0xfffffffffffffffcULL); +} + void c_i8(int8_t x) { assert_or_panic(x == -1); } @@ -237,6 +259,10 @@ void c_i64(int64_t x) { assert_or_panic(x == -4); } +void c_struct_i128(struct i128 x) { + assert_or_panic(x.value == -6); +} + void c_f32(float x) { assert_or_panic(x == 12.34f); } diff --git a/test/stage1/c_abi/main.zig b/test/stage1/c_abi/main.zig index abd9be4922..71a53bedea 100644 --- a/test/stage1/c_abi/main.zig +++ b/test/stage1/c_abi/main.zig @@ -16,20 +16,22 @@ extern fn c_u8(u8) void; extern fn c_u16(u16) void; extern fn c_u32(u32) void; extern fn c_u64(u64) void; +extern fn c_struct_u128(U128) void; extern fn c_i8(i8) void; extern fn c_i16(i16) void; extern fn c_i32(i32) void; extern fn c_i64(i64) void; +extern fn c_struct_i128(I128) void; // On windows x64, the first 4 are passed via registers, others on the stack. extern fn c_five_integers(i32, i32, i32, i32, i32) void; export fn zig_five_integers(a: i32, b: i32, c: i32, d: i32, e: i32) void { - expect(a == 12) catch @panic("test failure"); - expect(b == 34) catch @panic("test failure"); - expect(c == 56) catch @panic("test failure"); - expect(d == 78) catch @panic("test failure"); - expect(e == 90) catch @panic("test failure"); + expect(a == 12) catch @panic("test failure: zig_five_integers 12"); + expect(b == 34) catch @panic("test failure: zig_five_integers 34"); + expect(c == 56) catch @panic("test failure: zig_five_integers 56"); + expect(d == 78) catch @panic("test failure: zig_five_integers 78"); + expect(e == 90) catch @panic("test failure: zig_five_integers 90"); } test "C ABI integers" { @@ -37,37 +39,52 @@ test "C ABI integers" { c_u16(0xfffe); c_u32(0xfffffffd); c_u64(0xfffffffffffffffc); + c_struct_u128(.{ .value = 0xfffffffffffffffc }); c_i8(-1); c_i16(-2); c_i32(-3); c_i64(-4); + c_struct_i128(.{ .value = -6 }); c_five_integers(12, 34, 56, 78, 90); } export fn zig_u8(x: u8) void { - expect(x == 0xff) catch @panic("test failure"); + expect(x == 0xff) catch @panic("test failure: zig_u8"); } export fn zig_u16(x: u16) void { - expect(x == 0xfffe) catch @panic("test failure"); + expect(x == 0xfffe) catch @panic("test failure: zig_u16"); } export fn zig_u32(x: u32) void { - expect(x == 0xfffffffd) catch @panic("test failure"); + expect(x == 0xfffffffd) catch @panic("test failure: zig_u32"); } export fn zig_u64(x: u64) void { - expect(x == 0xfffffffffffffffc) catch @panic("test failure"); + expect(x == 0xfffffffffffffffc) catch @panic("test failure: zig_u64"); } export fn zig_i8(x: i8) void { - expect(x == -1) catch @panic("test failure"); + expect(x == -1) catch @panic("test failure: zig_i8"); } export fn zig_i16(x: i16) void { - expect(x == -2) catch @panic("test failure"); + expect(x == -2) catch @panic("test failure: zig_i16"); } export fn zig_i32(x: i32) void { - expect(x == -3) catch @panic("test failure"); + expect(x == -3) catch @panic("test failure: zig_i32"); } export fn zig_i64(x: i64) void { - expect(x == -4) catch @panic("test failure"); + expect(x == -4) catch @panic("test failure: zig_i64"); +} + +const I128 = extern struct { + value: i128, +}; +const U128 = extern struct { + value: u128, +}; +export fn zig_struct_i128(a: I128) void { + expect(a.value == -6) catch @panic("test failure: zig_struct_i128"); +} +export fn zig_struct_u128(a: U128) void { + expect(a.value == 0xfffffffffffffffc) catch @panic("test failure: zig_struct_u128"); } extern fn c_f32(f32) void; @@ -77,11 +94,11 @@ extern fn c_f64(f64) void; extern fn c_five_floats(f32, f32, f32, f32, f32) void; export fn zig_five_floats(a: f32, b: f32, c: f32, d: f32, e: f32) void { - expect(a == 1.0) catch @panic("test failure"); - expect(b == 2.0) catch @panic("test failure"); - expect(c == 3.0) catch @panic("test failure"); - expect(d == 4.0) catch @panic("test failure"); - expect(e == 5.0) catch @panic("test failure"); + expect(a == 1.0) catch @panic("test failure: zig_five_floats 1.0"); + expect(b == 2.0) catch @panic("test failure: zig_five_floats 2.0"); + expect(c == 3.0) catch @panic("test failure: zig_five_floats 3.0"); + expect(d == 4.0) catch @panic("test failure: zig_five_floats 4.0"); + expect(e == 5.0) catch @panic("test failure: zig_five_floats 5.0"); } test "C ABI floats" { @@ -91,10 +108,10 @@ test "C ABI floats" { } export fn zig_f32(x: f32) void { - expect(x == 12.34) catch @panic("test failure"); + expect(x == 12.34) catch @panic("test failure: zig_f32"); } export fn zig_f64(x: f64) void { - expect(x == 56.78) catch @panic("test failure"); + expect(x == 56.78) catch @panic("test failure: zig_f64"); } extern fn c_ptr(*anyopaque) void; @@ -104,7 +121,7 @@ test "C ABI pointer" { } export fn zig_ptr(x: *anyopaque) void { - expect(@ptrToInt(x) == 0xdeadbeef) catch @panic("test failure"); + expect(@ptrToInt(x) == 0xdeadbeef) catch @panic("test failure: zig_ptr"); } extern fn c_bool(bool) void; @@ -114,7 +131,7 @@ test "C ABI bool" { } export fn zig_bool(x: bool) void { - expect(x) catch @panic("test failure"); + expect(x) catch @panic("test failure: zig_bool"); } const BigStruct = extern struct { @@ -138,11 +155,11 @@ test "C ABI big struct" { } export fn zig_big_struct(x: BigStruct) void { - expect(x.a == 1) catch @panic("test failure"); - expect(x.b == 2) catch @panic("test failure"); - expect(x.c == 3) catch @panic("test failure"); - expect(x.d == 4) catch @panic("test failure"); - expect(x.e == 5) catch @panic("test failure"); + expect(x.a == 1) catch @panic("test failure: zig_big_struct 1"); + expect(x.b == 2) catch @panic("test failure: zig_big_struct 2"); + expect(x.c == 3) catch @panic("test failure: zig_big_struct 3"); + expect(x.d == 4) catch @panic("test failure: zig_big_struct 4"); + expect(x.e == 5) catch @panic("test failure: zig_big_struct 5"); } const BigUnion = extern union { @@ -164,11 +181,11 @@ test "C ABI big union" { } export fn zig_big_union(x: BigUnion) void { - expect(x.a.a == 1) catch @panic("test failure"); - expect(x.a.b == 2) catch @panic("test failure"); - expect(x.a.c == 3) catch @panic("test failure"); - expect(x.a.d == 4) catch @panic("test failure"); - expect(x.a.e == 5) catch @panic("test failure"); + expect(x.a.a == 1) catch @panic("test failure: zig_big_union a"); + expect(x.a.b == 2) catch @panic("test failure: zig_big_union b"); + expect(x.a.c == 3) catch @panic("test failure: zig_big_union c"); + expect(x.a.d == 4) catch @panic("test failure: zig_big_union d"); + expect(x.a.e == 5) catch @panic("test failure: zig_big_union e"); } const MedStructMixed = extern struct {