From 5949851074597dbc315476237f42fa67a0b6770a Mon Sep 17 00:00:00 2001 From: kcbanner Date: Thu, 19 Jan 2023 00:37:20 -0500 Subject: [PATCH 1/3] llvm: pass non-scalars as byref in .Stdcall - add c_abi tests for .Stdcall - enable (x86|x86_64)-windows-gnu in the c_abi tests --- src/codegen/llvm.zig | 16 ++++++++++++++++ test/c_abi/cfuncs.c | 29 +++++++++++++++++++++++++++++ test/c_abi/main.zig | 36 ++++++++++++++++++++++++++++++++++++ test/tests.zig | 15 +++++++++++++++ 4 files changed, 96 insertions(+) diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 8604c7d7f6..178c0aaf0a 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -10798,6 +10798,22 @@ const ParamTypeIterator = struct { }, } }, + .Stdcall => { + it.zig_index += 1; + it.llvm_index += 1; + + if (it.target.cpu.arch != .x86 or it.target.os.tag != .windows) { + return .byval; + } + + const is_scalar = isScalar(ty); + if (is_scalar) { + return .byval; + } else { + it.byval_attr = true; + return .byref; + } + }, else => { it.zig_index += 1; it.llvm_index += 1; diff --git a/test/c_abi/cfuncs.c b/test/c_abi/cfuncs.c index 1cd2bbdcbc..50e58c508e 100644 --- a/test/c_abi/cfuncs.c +++ b/test/c_abi/cfuncs.c @@ -985,3 +985,32 @@ f128_struct c_f128_struct(f128_struct a) { return (f128_struct){56.78}; } #endif + +void __attribute__((stdcall)) stdcall_scalars(char a, short b, int c, float d, double e) { + assert_or_panic(a == 1); + assert_or_panic(b == 2); + assert_or_panic(c == 3); + assert_or_panic(d == 4.0); + assert_or_panic(e == 5.0); +} + +typedef struct { + short x; + short y; +} Coord2; + +void __attribute__((stdcall)) stdcall_coord2(Coord2 a, Coord2 b, Coord2 c) { + assert_or_panic(a.x == 0x1111); + assert_or_panic(a.y == 0x2222); + assert_or_panic(b.x == 0x3333); + assert_or_panic(b.y == 0x4444); + assert_or_panic(c.x == 0x5555); + assert_or_panic(c.y == 0x6666); +} + +void __attribute__((stdcall)) stdcall_big_union(union BigUnion x) { + assert_or_panic(x.a.a == 1); + assert_or_panic(x.a.b == 2); + assert_or_panic(x.a.c == 3); + assert_or_panic(x.a.d == 4); +} diff --git a/test/c_abi/main.zig b/test/c_abi/main.zig index 426651aa9e..5511094487 100644 --- a/test/c_abi/main.zig +++ b/test/c_abi/main.zig @@ -1147,3 +1147,39 @@ test "f128 struct" { const a = c_f128_struct(.{ .a = 12.34 }); try expect(@floatCast(f64, a.a) == 56.78); } + +// The stdcall attribute on C functions is ignored when compiled on non-x86 +const stdcall_callconv: std.builtin.CallingConvention = if (builtin.cpu.arch == .x86) .Stdcall else .C; + +extern fn stdcall_scalars(i8, i16, i32, f32, f64) callconv(stdcall_callconv) void; +test "Stdcall ABI scalars" { + stdcall_scalars(1, 2, 3, 4.0, 5.0); +} + +const Coord2 = extern struct { + x: i16, + y: i16, +}; + +extern fn stdcall_coord2(Coord2, Coord2, Coord2) callconv(stdcall_callconv) void; +test "Stdcall ABI structs" { + stdcall_coord2( + .{ .x = 0x1111, .y = 0x2222 }, + .{ .x = 0x3333, .y = 0x4444 }, + .{ .x = 0x5555, .y = 0x6666 }, + ); +} + +extern fn stdcall_big_union(BigUnion) callconv(stdcall_callconv) void; +test "Stdcall ABI big union" { + var x = BigUnion{ + .a = BigStruct{ + .a = 1, + .b = 2, + .c = 3, + .d = 4, + .e = 5, + }, + }; + stdcall_big_union(x); +} diff --git a/test/tests.zig b/test/tests.zig index ec567c29b5..ec538a0c67 100644 --- a/test/tests.zig +++ b/test/tests.zig @@ -1321,6 +1321,16 @@ const c_abi_targets = [_]CrossTarget{ .os_tag = .linux, .abi = .musl, }, + .{ + .cpu_arch = .x86, + .os_tag = .windows, + .abi = .gnu, + }, + .{ + .cpu_arch = .x86_64, + .os_tag = .windows, + .abi = .gnu, + }, }; pub fn addCAbiTests(b: *build.Builder, skip_non_native: bool, skip_release: bool) *build.Step { @@ -1343,6 +1353,11 @@ pub fn addCAbiTests(b: *build.Builder, skip_non_native: bool, skip_release: bool test_step.addCSourceFile("test/c_abi/cfuncs.c", &.{"-std=c99"}); test_step.setBuildMode(mode); + if (c_abi_target.isWindows() and c_abi_target.getCpuArch() == .x86) { + // LTO currently incorrectly strips stdcall name-mangled functions + test_step.want_lto = false; + } + const triple_prefix = c_abi_target.zigTriple(b.allocator) catch unreachable; test_step.setNamePrefix(b.fmt("{s}-{s}-{s} ", .{ "test-c-abi", From 2b7678bc421e2efbdbce60d0f25ac68ffa20e100 Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Thu, 19 Jan 2023 16:13:52 +0200 Subject: [PATCH 2/3] llvm: implement Stdcall return types --- src/codegen/llvm.zig | 15 +++++++++------ test/c_abi/cfuncs.c | 3 ++- test/c_abi/main.zig | 12 ++++++++++-- 3 files changed, 21 insertions(+), 9 deletions(-) diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 178c0aaf0a..6da4e0d9af 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -10412,6 +10412,7 @@ fn firstParamSRet(fn_info: Type.Payload.Function.Data, target: std.Target) bool .riscv32, .riscv64 => return riscv_c_abi.classifyType(fn_info.return_type, target) == .memory, else => return false, // TODO investigate C ABI for other architectures }, + .Stdcall => return !isScalar(fn_info.return_type), else => return false, } } @@ -10567,6 +10568,13 @@ fn lowerFnRetTy(dg: *DeclGen, fn_info: Type.Payload.Function.Data) !*llvm.Type { else => return dg.lowerType(fn_info.return_type), } }, + .Stdcall => { + if (isScalar(fn_info.return_type)) { + return dg.lowerType(fn_info.return_type); + } else { + return dg.context.voidType(); + } + }, else => return dg.lowerType(fn_info.return_type), } } @@ -10802,12 +10810,7 @@ const ParamTypeIterator = struct { it.zig_index += 1; it.llvm_index += 1; - if (it.target.cpu.arch != .x86 or it.target.os.tag != .windows) { - return .byval; - } - - const is_scalar = isScalar(ty); - if (is_scalar) { + if (isScalar(ty)) { return .byval; } else { it.byval_attr = true; diff --git a/test/c_abi/cfuncs.c b/test/c_abi/cfuncs.c index 50e58c508e..bd249335c5 100644 --- a/test/c_abi/cfuncs.c +++ b/test/c_abi/cfuncs.c @@ -999,13 +999,14 @@ typedef struct { short y; } Coord2; -void __attribute__((stdcall)) stdcall_coord2(Coord2 a, Coord2 b, Coord2 c) { +Coord2 __attribute__((stdcall)) stdcall_coord2(Coord2 a, Coord2 b, Coord2 c) { assert_or_panic(a.x == 0x1111); assert_or_panic(a.y == 0x2222); assert_or_panic(b.x == 0x3333); assert_or_panic(b.y == 0x4444); assert_or_panic(c.x == 0x5555); assert_or_panic(c.y == 0x6666); + return (Coord2){123, 456}; } void __attribute__((stdcall)) stdcall_big_union(union BigUnion x) { diff --git a/test/c_abi/main.zig b/test/c_abi/main.zig index 5511094487..e9543c4e7e 100644 --- a/test/c_abi/main.zig +++ b/test/c_abi/main.zig @@ -1161,17 +1161,25 @@ const Coord2 = extern struct { y: i16, }; -extern fn stdcall_coord2(Coord2, Coord2, Coord2) callconv(stdcall_callconv) void; +extern fn stdcall_coord2(Coord2, Coord2, Coord2) callconv(stdcall_callconv) Coord2; test "Stdcall ABI structs" { - stdcall_coord2( + if (comptime builtin.cpu.arch.isMIPS()) return error.SkipZigTest; + if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest; + if (comptime builtin.cpu.arch.isPPC64()) return error.SkipZigTest; + + const res = stdcall_coord2( .{ .x = 0x1111, .y = 0x2222 }, .{ .x = 0x3333, .y = 0x4444 }, .{ .x = 0x5555, .y = 0x6666 }, ); + try expect(res.x == 123); + try expect(res.y == 456); } extern fn stdcall_big_union(BigUnion) callconv(stdcall_callconv) void; test "Stdcall ABI big union" { + if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest; + var x = BigUnion{ .a = BigStruct{ .a = 1, From c1bdf01533462aabb78321b554580fd378cdc59c Mon Sep 17 00:00:00 2001 From: kcbanner Date: Thu, 19 Jan 2023 13:01:27 -0500 Subject: [PATCH 3/3] tests: disable c_abi tests for windows when compiling on linux --- test/tests.zig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/tests.zig b/test/tests.zig index ec538a0c67..8e972b9ba6 100644 --- a/test/tests.zig +++ b/test/tests.zig @@ -1353,8 +1353,9 @@ pub fn addCAbiTests(b: *build.Builder, skip_non_native: bool, skip_release: bool test_step.addCSourceFile("test/c_abi/cfuncs.c", &.{"-std=c99"}); test_step.setBuildMode(mode); - if (c_abi_target.isWindows() and c_abi_target.getCpuArch() == .x86) { + if (c_abi_target.isWindows() and (c_abi_target.getCpuArch() == .x86 or builtin.target.os.tag == .linux)) { // LTO currently incorrectly strips stdcall name-mangled functions + // LLD crashes in LTO here when cross compiling for windows on linux test_step.want_lto = false; }