mirror of
https://github.com/ziglang/zig.git
synced 2026-02-10 03:20:58 +00:00
LLVM: fix C ABI for windows
* sret logic needed a check for hasRuntimeBits()
* lower f128 on windows targets with the "sse" class rather than
"memory". For reference, clang emits a compile error when __float128
is used with the MSVC ABI, saying that this type is not supported.
The docs for the x64 calling convention have both of these sentences:
- "Any argument that doesn't fit in 8 bytes, or isn't 1, 2, 4, or 8 bytes,
must be passed by reference."
- "All floating point operations are done using the 16 XMM registers."
* For i128, however, it is clear that the Windows calling convention
wants such an object to be passed by reference. I fixed the LLVM
lowering for function parameters to make this work.
This commit is contained in:
parent
17fc44dd12
commit
44252f4d35
@ -12,13 +12,10 @@ pub fn classifyWindows(ty: Type, target: Target) Class {
|
||||
// and the registers used for those arguments. Any argument that doesn't fit in 8
|
||||
// bytes, or isn't 1, 2, 4, or 8 bytes, must be passed by reference. A single argument
|
||||
// is never spread across multiple registers."
|
||||
// "All floating point operations are done using the 16 XMM registers."
|
||||
// "Structs and unions of size 8, 16, 32, or 64 bits, and __m64 types, are passed
|
||||
// as if they were integers of the same size."
|
||||
switch (ty.abiSize(target)) {
|
||||
1, 2, 4, 8 => {},
|
||||
else => return .memory,
|
||||
}
|
||||
return switch (ty.zigTypeTag()) {
|
||||
switch (ty.zigTypeTag()) {
|
||||
.Pointer,
|
||||
.Int,
|
||||
.Bool,
|
||||
@ -33,9 +30,13 @@ pub fn classifyWindows(ty: Type, target: Target) Class {
|
||||
.ErrorUnion,
|
||||
.AnyFrame,
|
||||
.Frame,
|
||||
=> .integer,
|
||||
=> switch (ty.abiSize(target)) {
|
||||
0 => unreachable,
|
||||
1, 2, 4, 8 => return .integer,
|
||||
else => return .memory,
|
||||
},
|
||||
|
||||
.Float, .Vector => .sse,
|
||||
.Float, .Vector => return .sse,
|
||||
|
||||
.Type,
|
||||
.ComptimeFloat,
|
||||
@ -47,7 +48,7 @@ pub fn classifyWindows(ty: Type, target: Target) Class {
|
||||
.Opaque,
|
||||
.EnumLiteral,
|
||||
=> unreachable,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// There are a maximum of 8 possible return slots. Returned values are in
|
||||
|
||||
@ -644,7 +644,17 @@ pub const Object = struct {
|
||||
if (!param_ty.hasRuntimeBitsIgnoreComptime()) continue;
|
||||
|
||||
const llvm_arg_i = @intCast(c_uint, args.items.len) + param_offset;
|
||||
try args.append(llvm_func.getParam(llvm_arg_i));
|
||||
const param = llvm_func.getParam(llvm_arg_i);
|
||||
// It is possible for the calling convention to make the argument's by-reference nature
|
||||
// disagree with our canonical value for it, in which case we must dereference here.
|
||||
const need_deref = !param_ty.isPtrAtRuntime() and !isByRef(param_ty) and
|
||||
(param.typeOf().getTypeKind() == .Pointer);
|
||||
const loaded_param = if (!need_deref) param else l: {
|
||||
const load_inst = builder.buildLoad(param, "");
|
||||
load_inst.setAlignment(param_ty.abiAlignment(target));
|
||||
break :l load_inst;
|
||||
};
|
||||
try args.append(loaded_param);
|
||||
}
|
||||
|
||||
var di_file: ?*llvm.DIFile = null;
|
||||
@ -3743,6 +3753,19 @@ pub const FuncGen = struct {
|
||||
arg_ptr.setAlignment(alignment);
|
||||
const store_inst = self.builder.buildStore(llvm_arg, arg_ptr);
|
||||
store_inst.setAlignment(alignment);
|
||||
|
||||
if (abi_llvm_ty.getTypeKind() == .Pointer) {
|
||||
// In this case, the calling convention wants a pointer, but
|
||||
// we have a value.
|
||||
if (arg_ptr.typeOf() == abi_llvm_ty) {
|
||||
try llvm_args.append(arg_ptr);
|
||||
continue;
|
||||
}
|
||||
const casted_ptr = self.builder.buildBitCast(arg_ptr, abi_llvm_ty, "");
|
||||
try llvm_args.append(casted_ptr);
|
||||
continue;
|
||||
}
|
||||
|
||||
break :p self.builder.buildBitCast(arg_ptr, ptr_abi_ty, "");
|
||||
};
|
||||
|
||||
@ -7931,6 +7954,8 @@ fn llvmFieldIndex(
|
||||
}
|
||||
|
||||
fn firstParamSRet(fn_info: Type.Payload.Function.Data, target: std.Target) bool {
|
||||
if (!fn_info.return_type.hasRuntimeBitsIgnoreComptime()) return false;
|
||||
|
||||
switch (fn_info.cc) {
|
||||
.Unspecified, .Inline => return isByRef(fn_info.return_type),
|
||||
.C => switch (target.cpu.arch) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user