authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2023-01-20 04:38:49+02:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-01-20 04:38:49+02:00
logfe6dcdba1407f00584725318404814571cdbd828
tree4ca30c3db0fadcfa489ff9007a3ed8f773670c80
parentd3599ec73cc07692c2579a8cf7151c918eea525f
parentc1bdf01533462aabb78321b554580fd378cdc59c
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #14357 from kcbanner/llvm_byval_struct

llvm: implement Stdcall calling convention

4 files changed, 109 insertions(+), 0 deletions(-)

src/codegen/llvm.zig+19
......@@ -10413,6 +10413,7 @@ fn firstParamSRet(fn_info: Type.Payload.Function.Data, target: std.Target) bool
1041310413 .riscv32, .riscv64 => return riscv_c_abi.classifyType(fn_info.return_type, target) == .memory,
1041410414 else => return false, // TODO investigate C ABI for other architectures
1041510415 },
10416 .Stdcall => return !isScalar(fn_info.return_type),
1041610417 else => return false,
1041710418 }
1041810419}
......@@ -10568,6 +10569,13 @@ fn lowerFnRetTy(dg: *DeclGen, fn_info: Type.Payload.Function.Data) !*llvm.Type {
1056810569 else => return dg.lowerType(fn_info.return_type),
1056910570 }
1057010571 },
10572 .Stdcall => {
10573 if (isScalar(fn_info.return_type)) {
10574 return dg.lowerType(fn_info.return_type);
10575 } else {
10576 return dg.context.voidType();
10577 }
10578 },
1057110579 else => return dg.lowerType(fn_info.return_type),
1057210580 }
1057310581}
......@@ -10798,6 +10806,17 @@ const ParamTypeIterator = struct {
1079810806 },
1079910807 }
1080010808 },
10809 .Stdcall => {
10810 it.zig_index += 1;
10811 it.llvm_index += 1;
10812
10813 if (isScalar(ty)) {
10814 return .byval;
10815 } else {
10816 it.byval_attr = true;
10817 return .byref;
10818 }
10819 },
1080110820 else => {
1080210821 it.zig_index += 1;
1080310822 it.llvm_index += 1;
test/c_abi/cfuncs.c+30
......@@ -985,3 +985,33 @@ f128_struct c_f128_struct(f128_struct a) {
985985 return (f128_struct){56.78};
986986}
987987#endif
988
989void __attribute__((stdcall)) stdcall_scalars(char a, short b, int c, float d, double e) {
990 assert_or_panic(a == 1);
991 assert_or_panic(b == 2);
992 assert_or_panic(c == 3);
993 assert_or_panic(d == 4.0);
994 assert_or_panic(e == 5.0);
995}
996
997typedef struct {
998 short x;
999 short y;
1000} Coord2;
1001
1002Coord2 __attribute__((stdcall)) stdcall_coord2(Coord2 a, Coord2 b, Coord2 c) {
1003 assert_or_panic(a.x == 0x1111);
1004 assert_or_panic(a.y == 0x2222);
1005 assert_or_panic(b.x == 0x3333);
1006 assert_or_panic(b.y == 0x4444);
1007 assert_or_panic(c.x == 0x5555);
1008 assert_or_panic(c.y == 0x6666);
1009 return (Coord2){123, 456};
1010}
1011
1012void __attribute__((stdcall)) stdcall_big_union(union BigUnion x) {
1013 assert_or_panic(x.a.a == 1);
1014 assert_or_panic(x.a.b == 2);
1015 assert_or_panic(x.a.c == 3);
1016 assert_or_panic(x.a.d == 4);
1017}
test/c_abi/main.zig+44
......@@ -1146,3 +1146,47 @@ test "f128 struct" {
11461146 const a = c_f128_struct(.{ .a = 12.34 });
11471147 try expect(@floatCast(f64, a.a) == 56.78);
11481148}
1149
1150// The stdcall attribute on C functions is ignored when compiled on non-x86
1151const stdcall_callconv: std.builtin.CallingConvention = if (builtin.cpu.arch == .x86) .Stdcall else .C;
1152
1153extern fn stdcall_scalars(i8, i16, i32, f32, f64) callconv(stdcall_callconv) void;
1154test "Stdcall ABI scalars" {
1155 stdcall_scalars(1, 2, 3, 4.0, 5.0);
1156}
1157
1158const Coord2 = extern struct {
1159 x: i16,
1160 y: i16,
1161};
1162
1163extern fn stdcall_coord2(Coord2, Coord2, Coord2) callconv(stdcall_callconv) Coord2;
1164test "Stdcall ABI structs" {
1165 if (comptime builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
1166 if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest;
1167 if (comptime builtin.cpu.arch.isPPC64()) return error.SkipZigTest;
1168
1169 const res = stdcall_coord2(
1170 .{ .x = 0x1111, .y = 0x2222 },
1171 .{ .x = 0x3333, .y = 0x4444 },
1172 .{ .x = 0x5555, .y = 0x6666 },
1173 );
1174 try expect(res.x == 123);
1175 try expect(res.y == 456);
1176}
1177
1178extern fn stdcall_big_union(BigUnion) callconv(stdcall_callconv) void;
1179test "Stdcall ABI big union" {
1180 if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest;
1181
1182 var x = BigUnion{
1183 .a = BigStruct{
1184 .a = 1,
1185 .b = 2,
1186 .c = 3,
1187 .d = 4,
1188 .e = 5,
1189 },
1190 };
1191 stdcall_big_union(x);
1192}
test/tests.zig+16
......@@ -1321,6 +1321,16 @@ const c_abi_targets = [_]CrossTarget{
13211321 .os_tag = .linux,
13221322 .abi = .musl,
13231323 },
1324 .{
1325 .cpu_arch = .x86,
1326 .os_tag = .windows,
1327 .abi = .gnu,
1328 },
1329 .{
1330 .cpu_arch = .x86_64,
1331 .os_tag = .windows,
1332 .abi = .gnu,
1333 },
13241334};
13251335
13261336pub fn addCAbiTests(b: *build.Builder, skip_non_native: bool, skip_release: bool) *build.Step {
......@@ -1343,6 +1353,12 @@ pub fn addCAbiTests(b: *build.Builder, skip_non_native: bool, skip_release: bool
13431353 test_step.addCSourceFile("test/c_abi/cfuncs.c", &.{"-std=c99"});
13441354 test_step.setBuildMode(mode);
13451355
1356 if (c_abi_target.isWindows() and (c_abi_target.getCpuArch() == .x86 or builtin.target.os.tag == .linux)) {
1357 // LTO currently incorrectly strips stdcall name-mangled functions
1358 // LLD crashes in LTO here when cross compiling for windows on linux
1359 test_step.want_lto = false;
1360 }
1361
13461362 const triple_prefix = c_abi_target.zigTriple(b.allocator) catch unreachable;
13471363 test_step.setNamePrefix(b.fmt("{s}-{s}-{s} ", .{
13481364 "test-c-abi",