| author | |
| committer | |
| log | fe6dcdba1407f00584725318404814571cdbd828 |
| tree | 4ca30c3db0fadcfa489ff9007a3ed8f773670c80 |
| parent | d3599ec73cc07692c2579a8cf7151c918eea525f |
| parent | c1bdf01533462aabb78321b554580fd378cdc59c |
| signature |
llvm: implement Stdcall calling convention4 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 architectures | 10414 | 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 | #endif | 987 | #endif |
| 988 | |||
| 989 | void __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 | |||
| 997 | typedef struct { | ||
| 998 | short x; | ||
| 999 | short y; | ||
| 1000 | } Coord2; | ||
| 1001 | |||
| 1002 | Coord2 __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 | |||
| 1012 | void __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 | ||
| 1151 | const stdcall_callconv: std.builtin.CallingConvention = if (builtin.cpu.arch == .x86) .Stdcall else .C; | ||
| 1152 | |||
| 1153 | extern fn stdcall_scalars(i8, i16, i32, f32, f64) callconv(stdcall_callconv) void; | ||
| 1154 | test "Stdcall ABI scalars" { | ||
| 1155 | stdcall_scalars(1, 2, 3, 4.0, 5.0); | ||
| 1156 | } | ||
| 1157 | |||
| 1158 | const Coord2 = extern struct { | ||
| 1159 | x: i16, | ||
| 1160 | y: i16, | ||
| 1161 | }; | ||
| 1162 | |||
| 1163 | extern fn stdcall_coord2(Coord2, Coord2, Coord2) callconv(stdcall_callconv) Coord2; | ||
| 1164 | test "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 | |||
| 1178 | extern fn stdcall_big_union(BigUnion) callconv(stdcall_callconv) void; | ||
| 1179 | test "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 | }; |
| 1325 | 1335 | ||
| 1326 | pub fn addCAbiTests(b: *build.Builder, skip_non_native: bool, skip_release: bool) *build.Step { | 1336 | pub 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); |
| 1345 | 1355 | ||
| 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", |