authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-11-20 20:14:03+02:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-11-20 20:25:12+02:00
logd968d9d10329234afc1d7743bb9981245695ca2b
treef856364f1a31d9bb5615ddc1ed600a26949e7cca
parent9e276d32f3f8d980e4bf4c0a52df0fa97717aacb

llvm: add attributes to the arguments of function pointer calls

Closes #13605

6 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 };
47024702
4703 if (fn_info.return_type.isError() and4703 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 }
47084708
...@@ -4890,6 +4890,66 @@ pub const FuncGen = struct {...@@ -4890,6 +4890,66 @@ pub const FuncGen = struct {
4890 "",4890 "",
4891 );4891 );
48924892
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};
8989
90pub const Value = opaque {90pub 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;
9393
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}
446446
447void 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
447LLVMValueRef ZigLLVMBuildMemCpy(LLVMBuilderRef B, LLVMValueRef Dst, unsigned DstAlign,456LLVMValueRef 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}
10671076
1068void ZigLLVMAddByValAttr(LLVMValueRef fn_ref, unsigned ArgNo, LLVMTypeRef type_val) {1077void 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}
10751093
1076void ZigLLVMAddSretAttr(LLVMValueRef fn_ref, LLVMTypeRef type_val) {1094void 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);
131131
132ZIG_EXTERN_C void ZigLLVMAddAttributeAtIndex(LLVMValueRef Val, unsigned Idx, LLVMAttributeRef A);
133
132ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildMemCpy(LLVMBuilderRef B, LLVMValueRef Dst, unsigned DstAlign,134ZIG_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);
134136
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
846struct 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
859void 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
1005const 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
1018extern fn c_func_ptr_byval(*anyopaque, *anyopaque, ByVal, c_ulong, *anyopaque, c_ulong) void;
1019test "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}