| author | |
| committer | |
| log | d968d9d10329234afc1d7743bb9981245695ca2b |
| tree | f856364f1a31d9bb5615ddc1ed600a26949e7cca |
| parent | 9e276d32f3f8d980e4bf4c0a52df0fa97717aacb |
Closes #136056 files changed, 152 insertions(+), 11 deletions(-)
src/codegen/llvm.zig+64-3| ... | @@ -4700,9 +4700,9 @@ pub const FuncGen = struct { | ... | @@ -4700,9 +4700,9 @@ pub const FuncGen = struct { |
| 4700 | break :blk ret_ptr; | 4700 | break :blk ret_ptr; |
| 4701 | }; | 4701 | }; |
| 4702 | 4702 | ||
| 4703 | if (fn_info.return_type.isError() and | 4703 | const err_return_tracing = fn_info.return_type.isError() and |
| 4704 | self.dg.module.comp.bin_file.options.error_return_tracing) | 4704 | self.dg.module.comp.bin_file.options.error_return_tracing; |
| 4705 | { | 4705 | if (err_return_tracing) { |
| 4706 | try llvm_args.append(self.err_ret_trace.?); | 4706 | try llvm_args.append(self.err_ret_trace.?); |
| 4707 | } | 4707 | } |
| 4708 | 4708 | ||
| ... | @@ -4890,6 +4890,66 @@ pub const FuncGen = struct { | ... | @@ -4890,6 +4890,66 @@ pub const FuncGen = struct { |
| 4890 | "", | 4890 | "", |
| 4891 | ); | 4891 | ); |
| 4892 | 4892 | ||
| 4893 | if (callee_ty.zigTypeTag() == .Pointer) { | ||
| 4894 | // Add argument attributes for function pointer calls. | ||
| 4895 | it = iterateParamTypes(self.dg, fn_info); | ||
| 4896 | it.llvm_index += @boolToInt(sret); | ||
| 4897 | it.llvm_index += @boolToInt(err_return_tracing); | ||
| 4898 | while (it.next()) |lowering| switch (lowering) { | ||
| 4899 | .byval => { | ||
| 4900 | const param_index = it.zig_index - 1; | ||
| 4901 | const param_ty = fn_info.param_types[param_index]; | ||
| 4902 | if (!isByRef(param_ty)) { | ||
| 4903 | self.dg.addByValParamAttrs(call, param_ty, param_index, fn_info, it.llvm_index - 1); | ||
| 4904 | } | ||
| 4905 | }, | ||
| 4906 | .byref => { | ||
| 4907 | const param_index = it.zig_index - 1; | ||
| 4908 | const param_ty = fn_info.param_types[param_index]; | ||
| 4909 | const param_llvm_ty = try self.dg.lowerType(param_ty); | ||
| 4910 | const alignment = param_ty.abiAlignment(target); | ||
| 4911 | self.dg.addByRefParamAttrs(call, it.llvm_index - 1, alignment, it.byval_attr, param_llvm_ty); | ||
| 4912 | }, | ||
| 4913 | .byref_mut => { | ||
| 4914 | self.dg.addArgAttr(call, it.llvm_index - 1, "noundef"); | ||
| 4915 | }, | ||
| 4916 | // No attributes needed for these. | ||
| 4917 | .no_bits, | ||
| 4918 | .abi_sized_int, | ||
| 4919 | .multiple_llvm_types, | ||
| 4920 | .as_u16, | ||
| 4921 | .float_array, | ||
| 4922 | .i32_array, | ||
| 4923 | .i64_array, | ||
| 4924 | => continue, | ||
| 4925 | |||
| 4926 | .slice => { | ||
| 4927 | assert(!it.byval_attr); | ||
| 4928 | const param_ty = fn_info.param_types[it.zig_index - 1]; | ||
| 4929 | const ptr_info = param_ty.ptrInfo().data; | ||
| 4930 | const llvm_arg_i = it.llvm_index - 2; | ||
| 4931 | |||
| 4932 | if (math.cast(u5, it.zig_index - 1)) |i| { | ||
| 4933 | if (@truncate(u1, fn_info.noalias_bits >> i) != 0) { | ||
| 4934 | self.dg.addArgAttr(call, llvm_arg_i, "noalias"); | ||
| 4935 | } | ||
| 4936 | } | ||
| 4937 | if (param_ty.zigTypeTag() != .Optional) { | ||
| 4938 | self.dg.addArgAttr(call, llvm_arg_i, "nonnull"); | ||
| 4939 | } | ||
| 4940 | if (!ptr_info.mutable) { | ||
| 4941 | self.dg.addArgAttr(call, llvm_arg_i, "readonly"); | ||
| 4942 | } | ||
| 4943 | if (ptr_info.@"align" != 0) { | ||
| 4944 | self.dg.addArgAttrInt(call, llvm_arg_i, "align", ptr_info.@"align"); | ||
| 4945 | } else { | ||
| 4946 | const elem_align = @max(ptr_info.pointee_type.abiAlignment(target), 1); | ||
| 4947 | self.dg.addArgAttrInt(call, llvm_arg_i, "align", elem_align); | ||
| 4948 | } | ||
| 4949 | }, | ||
| 4950 | }; | ||
| 4951 | } | ||
| 4952 | |||
| 4893 | if (return_type.isNoReturn() and attr != .AlwaysTail) { | 4953 | if (return_type.isNoReturn() and attr != .AlwaysTail) { |
| 4894 | _ = self.builder.buildUnreachable(); | 4954 | _ = self.builder.buildUnreachable(); |
| 4895 | return null; | 4955 | return null; |
| ... | @@ -10469,6 +10529,7 @@ const ParamTypeIterator = struct { | ... | @@ -10469,6 +10529,7 @@ const ParamTypeIterator = struct { |
| 10469 | it.llvm_index += 1; | 10529 | it.llvm_index += 1; |
| 10470 | var buf: Type.Payload.ElemType = undefined; | 10530 | var buf: Type.Payload.ElemType = undefined; |
| 10471 | if (ty.isSlice() or (ty.zigTypeTag() == .Optional and ty.optionalChild(&buf).isSlice())) { | 10531 | if (ty.isSlice() or (ty.zigTypeTag() == .Optional and ty.optionalChild(&buf).isSlice())) { |
| 10532 | it.llvm_index += 1; | ||
| 10472 | return .slice; | 10533 | return .slice; |
| 10473 | } else if (isByRef(ty)) { | 10534 | } else if (isByRef(ty)) { |
| 10474 | return .byref; | 10535 | return .byref; |
src/codegen/llvm/bindings.zig+2-2| ... | @@ -88,8 +88,8 @@ pub const Context = opaque { | ... | @@ -88,8 +88,8 @@ pub const Context = opaque { |
| 88 | }; | 88 | }; |
| 89 | 89 | ||
| 90 | pub const Value = opaque { | 90 | pub const Value = opaque { |
| 91 | pub const addAttributeAtIndex = LLVMAddAttributeAtIndex; | 91 | pub const addAttributeAtIndex = ZigLLVMAddAttributeAtIndex; |
| 92 | extern fn LLVMAddAttributeAtIndex(*Value, Idx: AttributeIndex, A: *Attribute) void; | 92 | extern fn ZigLLVMAddAttributeAtIndex(*Value, Idx: AttributeIndex, A: *Attribute) void; |
| 93 | 93 | ||
| 94 | pub const removeEnumAttributeAtIndex = LLVMRemoveEnumAttributeAtIndex; | 94 | pub const removeEnumAttributeAtIndex = LLVMRemoveEnumAttributeAtIndex; |
| 95 | extern fn LLVMRemoveEnumAttributeAtIndex(F: *Value, Idx: AttributeIndex, KindID: c_uint) void; | 95 | extern fn LLVMRemoveEnumAttributeAtIndex(F: *Value, Idx: AttributeIndex, KindID: c_uint) void; |
src/zig_llvm.cpp+24-6| ... | @@ -444,6 +444,15 @@ LLVMValueRef ZigLLVMBuildCall(LLVMBuilderRef B, LLVMTypeRef Ty, LLVMValueRef Fn, | ... | @@ -444,6 +444,15 @@ LLVMValueRef ZigLLVMBuildCall(LLVMBuilderRef B, LLVMTypeRef Ty, LLVMValueRef Fn, |
| 444 | return wrap(call_inst); | 444 | return wrap(call_inst); |
| 445 | } | 445 | } |
| 446 | 446 | ||
| 447 | void ZigLLVMAddAttributeAtIndex(LLVMValueRef Val, unsigned Idx, LLVMAttributeRef A) { | ||
| 448 | if (isa<Function>(unwrap(Val))) { | ||
| 449 | unwrap<Function>(Val)->addAttributeAtIndex(Idx, unwrap(A)); | ||
| 450 | } else { | ||
| 451 | unwrap<CallInst>(Val)->addAttributeAtIndex(Idx, unwrap(A)); | ||
| 452 | } | ||
| 453 | } | ||
| 454 | |||
| 455 | |||
| 447 | LLVMValueRef ZigLLVMBuildMemCpy(LLVMBuilderRef B, LLVMValueRef Dst, unsigned DstAlign, | 456 | LLVMValueRef ZigLLVMBuildMemCpy(LLVMBuilderRef B, LLVMValueRef Dst, unsigned DstAlign, |
| 448 | LLVMValueRef Src, unsigned SrcAlign, LLVMValueRef Size, bool isVolatile) | 457 | LLVMValueRef Src, unsigned SrcAlign, LLVMValueRef Size, bool isVolatile) |
| 449 | { | 458 | { |
| ... | @@ -1065,12 +1074,21 @@ void ZigLLVMSetFastMath(LLVMBuilderRef builder_wrapped, bool on_state) { | ... | @@ -1065,12 +1074,21 @@ void ZigLLVMSetFastMath(LLVMBuilderRef builder_wrapped, bool on_state) { |
| 1065 | } | 1074 | } |
| 1066 | } | 1075 | } |
| 1067 | 1076 | ||
| 1068 | void ZigLLVMAddByValAttr(LLVMValueRef fn_ref, unsigned ArgNo, LLVMTypeRef type_val) { | 1077 | void ZigLLVMAddByValAttr(LLVMValueRef Val, unsigned ArgNo, LLVMTypeRef type_val) { |
| 1069 | Function *func = unwrap<Function>(fn_ref); | 1078 | if (isa<Function>(unwrap(Val))) { |
| 1070 | AttrBuilder attr_builder(func->getContext()); | 1079 | Function *func = unwrap<Function>(Val); |
| 1071 | Type *llvm_type = unwrap<Type>(type_val); | 1080 | AttrBuilder attr_builder(func->getContext()); |
| 1072 | attr_builder.addByValAttr(llvm_type); | 1081 | Type *llvm_type = unwrap<Type>(type_val); |
| 1073 | func->addParamAttrs(ArgNo, attr_builder); | 1082 | attr_builder.addByValAttr(llvm_type); |
| 1083 | func->addParamAttrs(ArgNo, attr_builder); | ||
| 1084 | } else { | ||
| 1085 | CallInst *call = unwrap<CallInst>(Val); | ||
| 1086 | AttrBuilder attr_builder(call->getContext()); | ||
| 1087 | Type *llvm_type = unwrap<Type>(type_val); | ||
| 1088 | attr_builder.addByValAttr(llvm_type); | ||
| 1089 | // NOTE: +1 here since index 0 refers to the return value | ||
| 1090 | call->addAttributeAtIndex(ArgNo + 1, attr_builder.getAttribute(Attribute::ByVal)); | ||
| 1091 | } | ||
| 1074 | } | 1092 | } |
| 1075 | 1093 | ||
| 1076 | void ZigLLVMAddSretAttr(LLVMValueRef fn_ref, LLVMTypeRef type_val) { | 1094 | void ZigLLVMAddSretAttr(LLVMValueRef fn_ref, LLVMTypeRef type_val) { |
src/zig_llvm.h+2| ... | @@ -129,6 +129,8 @@ ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildCall(LLVMBuilderRef B, LLVMTypeRef functio | ... | @@ -129,6 +129,8 @@ ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildCall(LLVMBuilderRef B, LLVMTypeRef functio |
| 129 | LLVMValueRef Fn, LLVMValueRef *Args, unsigned NumArgs, enum ZigLLVM_CallingConv CC, | 129 | LLVMValueRef Fn, LLVMValueRef *Args, unsigned NumArgs, enum ZigLLVM_CallingConv CC, |
| 130 | enum ZigLLVM_CallAttr attr, const char *Name); | 130 | enum ZigLLVM_CallAttr attr, const char *Name); |
| 131 | 131 | ||
| 132 | ZIG_EXTERN_C void ZigLLVMAddAttributeAtIndex(LLVMValueRef Val, unsigned Idx, LLVMAttributeRef A); | ||
| 133 | |||
| 132 | ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildMemCpy(LLVMBuilderRef B, LLVMValueRef Dst, unsigned DstAlign, | 134 | ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildMemCpy(LLVMBuilderRef B, LLVMValueRef Dst, unsigned DstAlign, |
| 133 | LLVMValueRef Src, unsigned SrcAlign, LLVMValueRef Size, bool isVolatile); | 135 | LLVMValueRef Src, unsigned SrcAlign, LLVMValueRef Size, bool isVolatile); |
| 134 | 136 |
test/c_abi/cfuncs.c+29| ... | @@ -842,3 +842,32 @@ struct ByRef c_modify_by_ref_param(struct ByRef in) { | ... | @@ -842,3 +842,32 @@ struct ByRef c_modify_by_ref_param(struct ByRef in) { |
| 842 | in.val = 42; | 842 | in.val = 42; |
| 843 | return in; | 843 | return in; |
| 844 | } | 844 | } |
| 845 | |||
| 846 | struct ByVal { | ||
| 847 | struct { | ||
| 848 | unsigned long x; | ||
| 849 | unsigned long y; | ||
| 850 | unsigned long z; | ||
| 851 | } origin; | ||
| 852 | struct { | ||
| 853 | unsigned long width; | ||
| 854 | unsigned long height; | ||
| 855 | unsigned long depth; | ||
| 856 | } size; | ||
| 857 | }; | ||
| 858 | |||
| 859 | void c_func_ptr_byval(void *a, void *b, struct ByVal in, unsigned long c, void *d, unsigned long e) { | ||
| 860 | assert_or_panic((intptr_t)a == 1); | ||
| 861 | assert_or_panic((intptr_t)b == 2); | ||
| 862 | |||
| 863 | assert_or_panic(in.origin.x == 9); | ||
| 864 | assert_or_panic(in.origin.y == 10); | ||
| 865 | assert_or_panic(in.origin.z == 11); | ||
| 866 | assert_or_panic(in.size.width == 12); | ||
| 867 | assert_or_panic(in.size.height == 13); | ||
| 868 | assert_or_panic(in.size.depth == 14); | ||
| 869 | |||
| 870 | assert_or_panic(c == 3); | ||
| 871 | assert_or_panic((intptr_t)d == 4); | ||
| 872 | assert_or_panic(e == 5); | ||
| 873 | } |
test/c_abi/main.zig+31| ... | @@ -1001,3 +1001,34 @@ test "C function modifies by ref param" { | ... | @@ -1001,3 +1001,34 @@ test "C function modifies by ref param" { |
| 1001 | const res = c_modify_by_ref_param(.{ .val = 1, .arr = undefined }); | 1001 | const res = c_modify_by_ref_param(.{ .val = 1, .arr = undefined }); |
| 1002 | try expect(res.val == 42); | 1002 | try expect(res.val == 42); |
| 1003 | } | 1003 | } |
| 1004 | |||
| 1005 | const ByVal = extern struct { | ||
| 1006 | origin: extern struct { | ||
| 1007 | x: c_ulong, | ||
| 1008 | y: c_ulong, | ||
| 1009 | z: c_ulong, | ||
| 1010 | }, | ||
| 1011 | size: extern struct { | ||
| 1012 | width: c_ulong, | ||
| 1013 | height: c_ulong, | ||
| 1014 | depth: c_ulong, | ||
| 1015 | }, | ||
| 1016 | }; | ||
| 1017 | |||
| 1018 | extern fn c_func_ptr_byval(*anyopaque, *anyopaque, ByVal, c_ulong, *anyopaque, c_ulong) void; | ||
| 1019 | test "C function that takes byval struct called via function pointer" { | ||
| 1020 | if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest; | ||
| 1021 | |||
| 1022 | var fn_ptr = &c_func_ptr_byval; | ||
| 1023 | fn_ptr( | ||
| 1024 | @intToPtr(*anyopaque, 1), | ||
| 1025 | @intToPtr(*anyopaque, 2), | ||
| 1026 | ByVal{ | ||
| 1027 | .origin = .{ .x = 9, .y = 10, .z = 11 }, | ||
| 1028 | .size = .{ .width = 12, .height = 13, .depth = 14 }, | ||
| 1029 | }, | ||
| 1030 | @as(c_ulong, 3), | ||
| 1031 | @intToPtr(*anyopaque, 4), | ||
| 1032 | @as(c_ulong, 5), | ||
| 1033 | ); | ||
| 1034 | } |