| author | |
| committer | |
| log | 44252f4d352d53afd86d678c0b0a40b3f681c7eb |
| tree | 91dddc4c240b1aa429ea6d80835640b4a85e2c23 |
| parent | 17fc44dd1287163c25832c40f7e81cd5532e52bd |
* 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.2 files changed, 35 insertions(+), 9 deletions(-)
src/arch/x86_64/abi.zig+9-8| ... | @@ -12,13 +12,10 @@ pub fn classifyWindows(ty: Type, target: Target) Class { | ... | @@ -12,13 +12,10 @@ pub fn classifyWindows(ty: Type, target: Target) Class { |
| 12 | // and the registers used for those arguments. Any argument that doesn't fit in 8 | 12 | // and the registers used for those arguments. Any argument that doesn't fit in 8 |
| 13 | // bytes, or isn't 1, 2, 4, or 8 bytes, must be passed by reference. A single argument | 13 | // bytes, or isn't 1, 2, 4, or 8 bytes, must be passed by reference. A single argument |
| 14 | // is never spread across multiple registers." | 14 | // is never spread across multiple registers." |
| 15 | // "All floating point operations are done using the 16 XMM registers." | ||
| 15 | // "Structs and unions of size 8, 16, 32, or 64 bits, and __m64 types, are passed | 16 | // "Structs and unions of size 8, 16, 32, or 64 bits, and __m64 types, are passed |
| 16 | // as if they were integers of the same size." | 17 | // as if they were integers of the same size." |
| 17 | switch (ty.abiSize(target)) { | 18 | switch (ty.zigTypeTag()) { |
| 18 | 1, 2, 4, 8 => {}, | ||
| 19 | else => return .memory, | ||
| 20 | } | ||
| 21 | return switch (ty.zigTypeTag()) { | ||
| 22 | .Pointer, | 19 | .Pointer, |
| 23 | .Int, | 20 | .Int, |
| 24 | .Bool, | 21 | .Bool, |
| ... | @@ -33,9 +30,13 @@ pub fn classifyWindows(ty: Type, target: Target) Class { | ... | @@ -33,9 +30,13 @@ pub fn classifyWindows(ty: Type, target: Target) Class { |
| 33 | .ErrorUnion, | 30 | .ErrorUnion, |
| 34 | .AnyFrame, | 31 | .AnyFrame, |
| 35 | .Frame, | 32 | .Frame, |
| 36 | => .integer, | 33 | => switch (ty.abiSize(target)) { |
| 34 | 0 => unreachable, | ||
| 35 | 1, 2, 4, 8 => return .integer, | ||
| 36 | else => return .memory, | ||
| 37 | }, | ||
| 37 | 38 | ||
| 38 | .Float, .Vector => .sse, | 39 | .Float, .Vector => return .sse, |
| 39 | 40 | ||
| 40 | .Type, | 41 | .Type, |
| 41 | .ComptimeFloat, | 42 | .ComptimeFloat, |
| ... | @@ -47,7 +48,7 @@ pub fn classifyWindows(ty: Type, target: Target) Class { | ... | @@ -47,7 +48,7 @@ pub fn classifyWindows(ty: Type, target: Target) Class { |
| 47 | .Opaque, | 48 | .Opaque, |
| 48 | .EnumLiteral, | 49 | .EnumLiteral, |
| 49 | => unreachable, | 50 | => unreachable, |
| 50 | }; | 51 | } |
| 51 | } | 52 | } |
| 52 | 53 | ||
| 53 | /// There are a maximum of 8 possible return slots. Returned values are in | 54 | /// There are a maximum of 8 possible return slots. Returned values are in |
src/codegen/llvm.zig+26-1| ... | @@ -644,7 +644,17 @@ pub const Object = struct { | ... | @@ -644,7 +644,17 @@ pub const Object = struct { |
| 644 | if (!param_ty.hasRuntimeBitsIgnoreComptime()) continue; | 644 | if (!param_ty.hasRuntimeBitsIgnoreComptime()) continue; |
| 645 | 645 | ||
| 646 | const llvm_arg_i = @intCast(c_uint, args.items.len) + param_offset; | 646 | const llvm_arg_i = @intCast(c_uint, args.items.len) + param_offset; |
| 647 | try args.append(llvm_func.getParam(llvm_arg_i)); | 647 | const param = llvm_func.getParam(llvm_arg_i); |
| 648 | // It is possible for the calling convention to make the argument's by-reference nature | ||
| 649 | // disagree with our canonical value for it, in which case we must dereference here. | ||
| 650 | const need_deref = !param_ty.isPtrAtRuntime() and !isByRef(param_ty) and | ||
| 651 | (param.typeOf().getTypeKind() == .Pointer); | ||
| 652 | const loaded_param = if (!need_deref) param else l: { | ||
| 653 | const load_inst = builder.buildLoad(param, ""); | ||
| 654 | load_inst.setAlignment(param_ty.abiAlignment(target)); | ||
| 655 | break :l load_inst; | ||
| 656 | }; | ||
| 657 | try args.append(loaded_param); | ||
| 648 | } | 658 | } |
| 649 | 659 | ||
| 650 | var di_file: ?*llvm.DIFile = null; | 660 | var di_file: ?*llvm.DIFile = null; |
| ... | @@ -3743,6 +3753,19 @@ pub const FuncGen = struct { | ... | @@ -3743,6 +3753,19 @@ pub const FuncGen = struct { |
| 3743 | arg_ptr.setAlignment(alignment); | 3753 | arg_ptr.setAlignment(alignment); |
| 3744 | const store_inst = self.builder.buildStore(llvm_arg, arg_ptr); | 3754 | const store_inst = self.builder.buildStore(llvm_arg, arg_ptr); |
| 3745 | store_inst.setAlignment(alignment); | 3755 | store_inst.setAlignment(alignment); |
| 3756 | |||
| 3757 | if (abi_llvm_ty.getTypeKind() == .Pointer) { | ||
| 3758 | // In this case, the calling convention wants a pointer, but | ||
| 3759 | // we have a value. | ||
| 3760 | if (arg_ptr.typeOf() == abi_llvm_ty) { | ||
| 3761 | try llvm_args.append(arg_ptr); | ||
| 3762 | continue; | ||
| 3763 | } | ||
| 3764 | const casted_ptr = self.builder.buildBitCast(arg_ptr, abi_llvm_ty, ""); | ||
| 3765 | try llvm_args.append(casted_ptr); | ||
| 3766 | continue; | ||
| 3767 | } | ||
| 3768 | |||
| 3746 | break :p self.builder.buildBitCast(arg_ptr, ptr_abi_ty, ""); | 3769 | break :p self.builder.buildBitCast(arg_ptr, ptr_abi_ty, ""); |
| 3747 | }; | 3770 | }; |
| 3748 | 3771 | ||
| ... | @@ -7931,6 +7954,8 @@ fn llvmFieldIndex( | ... | @@ -7931,6 +7954,8 @@ fn llvmFieldIndex( |
| 7931 | } | 7954 | } |
| 7932 | 7955 | ||
| 7933 | fn firstParamSRet(fn_info: Type.Payload.Function.Data, target: std.Target) bool { | 7956 | fn firstParamSRet(fn_info: Type.Payload.Function.Data, target: std.Target) bool { |
| 7957 | if (!fn_info.return_type.hasRuntimeBitsIgnoreComptime()) return false; | ||
| 7958 | |||
| 7934 | switch (fn_info.cc) { | 7959 | switch (fn_info.cc) { |
| 7935 | .Unspecified, .Inline => return isByRef(fn_info.return_type), | 7960 | .Unspecified, .Inline => return isByRef(fn_info.return_type), |
| 7936 | .C => switch (target.cpu.arch) { | 7961 | .C => switch (target.cpu.arch) { |