Merge pull request #14357 from kcbanner/llvm_byval_struct

llvm: implement Stdcall calling convention
This commit is contained in:
Veikka Tuominen 2023-01-20 04:38:49 +02:00 committed by GitHub
commit fe6dcdba14
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 109 additions and 0 deletions

View File

@ -10413,6 +10413,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,
}
}
@ -10568,6 +10569,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),
}
}
@ -10798,6 +10806,17 @@ const ParamTypeIterator = struct {
},
}
},
.Stdcall => {
it.zig_index += 1;
it.llvm_index += 1;
if (isScalar(ty)) {
return .byval;
} else {
it.byval_attr = true;
return .byref;
}
},
else => {
it.zig_index += 1;
it.llvm_index += 1;

View File

@ -985,3 +985,33 @@ 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;
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) {
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);
}

View File

@ -1146,3 +1146,47 @@ 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) Coord2;
test "Stdcall ABI structs" {
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,
.b = 2,
.c = 3,
.d = 4,
.e = 5,
},
};
stdcall_big_union(x);
}

View File

@ -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,12 @@ 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 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;
}
const triple_prefix = c_abi_target.zigTriple(b.allocator) catch unreachable;
test_step.setNamePrefix(b.fmt("{s}-{s}-{s} ", .{
"test-c-abi",