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...@@ -10413,6 +10413,7 @@ fn firstParamSRet(fn_info: Type.Payload.Function.Data, target: std.Target) bool
10413 .riscv32, .riscv64 => return riscv_c_abi.classifyType(fn_info.return_type, target) == .memory,10413 .riscv32, .riscv64 => return riscv_c_abi.classifyType(fn_info.return_type, target) == .memory,
10414 else => return false, // TODO investigate C ABI for other architectures10414 else => return false, // TODO investigate C ABI for other architectures
10415 },10415 },
10416 .Stdcall => return !isScalar(fn_info.return_type),
10416 else => return false,10417 else => return false,
10417 }10418 }
10418}10419}
...@@ -10568,6 +10569,13 @@ fn lowerFnRetTy(dg: *DeclGen, fn_info: Type.Payload.Function.Data) !*llvm.Type {...@@ -10568,6 +10569,13 @@ fn lowerFnRetTy(dg: *DeclGen, fn_info: Type.Payload.Function.Data) !*llvm.Type {
10568 else => return dg.lowerType(fn_info.return_type),10569 else => return dg.lowerType(fn_info.return_type),
10569 }10570 }
10570 },10571 },
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 },
10571 else => return dg.lowerType(fn_info.return_type),10579 else => return dg.lowerType(fn_info.return_type),
10572 }10580 }
10573}10581}
...@@ -10798,6 +10806,17 @@ const ParamTypeIterator = struct {...@@ -10798,6 +10806,17 @@ const ParamTypeIterator = struct {
10798 },10806 },
10799 }10807 }
10800 },10808 },
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 },
10801 else => {10820 else => {
10802 it.zig_index += 1;10821 it.zig_index += 1;
10803 it.llvm_index += 1;10822 it.llvm_index += 1;
test/c_abi/cfuncs.c+30
...@@ -985,3 +985,33 @@ f128_struct c_f128_struct(f128_struct a) {...@@ -985,3 +985,33 @@ f128_struct c_f128_struct(f128_struct a) {
985 return (f128_struct){56.78};985 return (f128_struct){56.78};
986}986}
987#endif987#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" {...@@ -1146,3 +1146,47 @@ test "f128 struct" {
1146 const a = c_f128_struct(.{ .a = 12.34 });1146 const a = c_f128_struct(.{ .a = 12.34 });
1147 try expect(@floatCast(f64, a.a) == 56.78);1147 try expect(@floatCast(f64, a.a) == 56.78);
1148}1148}
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{...@@ -1321,6 +1321,16 @@ const c_abi_targets = [_]CrossTarget{
1321 .os_tag = .linux,1321 .os_tag = .linux,
1322 .abi = .musl,1322 .abi = .musl,
1323 },1323 },
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 },
1324};1334};
13251335
1326pub fn addCAbiTests(b: *build.Builder, skip_non_native: bool, skip_release: bool) *build.Step {1336pub 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...@@ -1343,6 +1353,12 @@ pub fn addCAbiTests(b: *build.Builder, skip_non_native: bool, skip_release: bool
1343 test_step.addCSourceFile("test/c_abi/cfuncs.c", &.{"-std=c99"});1353 test_step.addCSourceFile("test/c_abi/cfuncs.c", &.{"-std=c99"});
1344 test_step.setBuildMode(mode);1354 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
1346 const triple_prefix = c_abi_target.zigTriple(b.allocator) catch unreachable;1362 const triple_prefix = c_abi_target.zigTriple(b.allocator) catch unreachable;
1347 test_step.setNamePrefix(b.fmt("{s}-{s}-{s} ", .{1363 test_step.setNamePrefix(b.fmt("{s}-{s}-{s} ", .{
1348 "test-c-abi",1364 "test-c-abi",