mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 13:54:21 +00:00
llvm: add attributes to the arguments of function pointer calls
Closes #13605
This commit is contained in:
parent
9e276d32f3
commit
d968d9d103
6 changed files with 152 additions and 11 deletions
|
|
@ -4700,9 +4700,9 @@ pub const FuncGen = struct {
|
||||||
break :blk ret_ptr;
|
break :blk ret_ptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
if (fn_info.return_type.isError() and
|
const err_return_tracing = fn_info.return_type.isError() and
|
||||||
self.dg.module.comp.bin_file.options.error_return_tracing)
|
self.dg.module.comp.bin_file.options.error_return_tracing;
|
||||||
{
|
if (err_return_tracing) {
|
||||||
try llvm_args.append(self.err_ret_trace.?);
|
try llvm_args.append(self.err_ret_trace.?);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -4890,6 +4890,66 @@ pub const FuncGen = struct {
|
||||||
"",
|
"",
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (callee_ty.zigTypeTag() == .Pointer) {
|
||||||
|
// Add argument attributes for function pointer calls.
|
||||||
|
it = iterateParamTypes(self.dg, fn_info);
|
||||||
|
it.llvm_index += @boolToInt(sret);
|
||||||
|
it.llvm_index += @boolToInt(err_return_tracing);
|
||||||
|
while (it.next()) |lowering| switch (lowering) {
|
||||||
|
.byval => {
|
||||||
|
const param_index = it.zig_index - 1;
|
||||||
|
const param_ty = fn_info.param_types[param_index];
|
||||||
|
if (!isByRef(param_ty)) {
|
||||||
|
self.dg.addByValParamAttrs(call, param_ty, param_index, fn_info, it.llvm_index - 1);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
.byref => {
|
||||||
|
const param_index = it.zig_index - 1;
|
||||||
|
const param_ty = fn_info.param_types[param_index];
|
||||||
|
const param_llvm_ty = try self.dg.lowerType(param_ty);
|
||||||
|
const alignment = param_ty.abiAlignment(target);
|
||||||
|
self.dg.addByRefParamAttrs(call, it.llvm_index - 1, alignment, it.byval_attr, param_llvm_ty);
|
||||||
|
},
|
||||||
|
.byref_mut => {
|
||||||
|
self.dg.addArgAttr(call, it.llvm_index - 1, "noundef");
|
||||||
|
},
|
||||||
|
// No attributes needed for these.
|
||||||
|
.no_bits,
|
||||||
|
.abi_sized_int,
|
||||||
|
.multiple_llvm_types,
|
||||||
|
.as_u16,
|
||||||
|
.float_array,
|
||||||
|
.i32_array,
|
||||||
|
.i64_array,
|
||||||
|
=> continue,
|
||||||
|
|
||||||
|
.slice => {
|
||||||
|
assert(!it.byval_attr);
|
||||||
|
const param_ty = fn_info.param_types[it.zig_index - 1];
|
||||||
|
const ptr_info = param_ty.ptrInfo().data;
|
||||||
|
const llvm_arg_i = it.llvm_index - 2;
|
||||||
|
|
||||||
|
if (math.cast(u5, it.zig_index - 1)) |i| {
|
||||||
|
if (@truncate(u1, fn_info.noalias_bits >> i) != 0) {
|
||||||
|
self.dg.addArgAttr(call, llvm_arg_i, "noalias");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (param_ty.zigTypeTag() != .Optional) {
|
||||||
|
self.dg.addArgAttr(call, llvm_arg_i, "nonnull");
|
||||||
|
}
|
||||||
|
if (!ptr_info.mutable) {
|
||||||
|
self.dg.addArgAttr(call, llvm_arg_i, "readonly");
|
||||||
|
}
|
||||||
|
if (ptr_info.@"align" != 0) {
|
||||||
|
self.dg.addArgAttrInt(call, llvm_arg_i, "align", ptr_info.@"align");
|
||||||
|
} else {
|
||||||
|
const elem_align = @max(ptr_info.pointee_type.abiAlignment(target), 1);
|
||||||
|
self.dg.addArgAttrInt(call, llvm_arg_i, "align", elem_align);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
if (return_type.isNoReturn() and attr != .AlwaysTail) {
|
if (return_type.isNoReturn() and attr != .AlwaysTail) {
|
||||||
_ = self.builder.buildUnreachable();
|
_ = self.builder.buildUnreachable();
|
||||||
return null;
|
return null;
|
||||||
|
|
@ -10469,6 +10529,7 @@ const ParamTypeIterator = struct {
|
||||||
it.llvm_index += 1;
|
it.llvm_index += 1;
|
||||||
var buf: Type.Payload.ElemType = undefined;
|
var buf: Type.Payload.ElemType = undefined;
|
||||||
if (ty.isSlice() or (ty.zigTypeTag() == .Optional and ty.optionalChild(&buf).isSlice())) {
|
if (ty.isSlice() or (ty.zigTypeTag() == .Optional and ty.optionalChild(&buf).isSlice())) {
|
||||||
|
it.llvm_index += 1;
|
||||||
return .slice;
|
return .slice;
|
||||||
} else if (isByRef(ty)) {
|
} else if (isByRef(ty)) {
|
||||||
return .byref;
|
return .byref;
|
||||||
|
|
|
||||||
|
|
@ -88,8 +88,8 @@ pub const Context = opaque {
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Value = opaque {
|
pub const Value = opaque {
|
||||||
pub const addAttributeAtIndex = LLVMAddAttributeAtIndex;
|
pub const addAttributeAtIndex = ZigLLVMAddAttributeAtIndex;
|
||||||
extern fn LLVMAddAttributeAtIndex(*Value, Idx: AttributeIndex, A: *Attribute) void;
|
extern fn ZigLLVMAddAttributeAtIndex(*Value, Idx: AttributeIndex, A: *Attribute) void;
|
||||||
|
|
||||||
pub const removeEnumAttributeAtIndex = LLVMRemoveEnumAttributeAtIndex;
|
pub const removeEnumAttributeAtIndex = LLVMRemoveEnumAttributeAtIndex;
|
||||||
extern fn LLVMRemoveEnumAttributeAtIndex(F: *Value, Idx: AttributeIndex, KindID: c_uint) void;
|
extern fn LLVMRemoveEnumAttributeAtIndex(F: *Value, Idx: AttributeIndex, KindID: c_uint) void;
|
||||||
|
|
|
||||||
|
|
@ -444,6 +444,15 @@ LLVMValueRef ZigLLVMBuildCall(LLVMBuilderRef B, LLVMTypeRef Ty, LLVMValueRef Fn,
|
||||||
return wrap(call_inst);
|
return wrap(call_inst);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ZigLLVMAddAttributeAtIndex(LLVMValueRef Val, unsigned Idx, LLVMAttributeRef A) {
|
||||||
|
if (isa<Function>(unwrap(Val))) {
|
||||||
|
unwrap<Function>(Val)->addAttributeAtIndex(Idx, unwrap(A));
|
||||||
|
} else {
|
||||||
|
unwrap<CallInst>(Val)->addAttributeAtIndex(Idx, unwrap(A));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
LLVMValueRef ZigLLVMBuildMemCpy(LLVMBuilderRef B, LLVMValueRef Dst, unsigned DstAlign,
|
LLVMValueRef ZigLLVMBuildMemCpy(LLVMBuilderRef B, LLVMValueRef Dst, unsigned DstAlign,
|
||||||
LLVMValueRef Src, unsigned SrcAlign, LLVMValueRef Size, bool isVolatile)
|
LLVMValueRef Src, unsigned SrcAlign, LLVMValueRef Size, bool isVolatile)
|
||||||
{
|
{
|
||||||
|
|
@ -1065,12 +1074,21 @@ void ZigLLVMSetFastMath(LLVMBuilderRef builder_wrapped, bool on_state) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ZigLLVMAddByValAttr(LLVMValueRef fn_ref, unsigned ArgNo, LLVMTypeRef type_val) {
|
void ZigLLVMAddByValAttr(LLVMValueRef Val, unsigned ArgNo, LLVMTypeRef type_val) {
|
||||||
Function *func = unwrap<Function>(fn_ref);
|
if (isa<Function>(unwrap(Val))) {
|
||||||
AttrBuilder attr_builder(func->getContext());
|
Function *func = unwrap<Function>(Val);
|
||||||
Type *llvm_type = unwrap<Type>(type_val);
|
AttrBuilder attr_builder(func->getContext());
|
||||||
attr_builder.addByValAttr(llvm_type);
|
Type *llvm_type = unwrap<Type>(type_val);
|
||||||
func->addParamAttrs(ArgNo, attr_builder);
|
attr_builder.addByValAttr(llvm_type);
|
||||||
|
func->addParamAttrs(ArgNo, attr_builder);
|
||||||
|
} else {
|
||||||
|
CallInst *call = unwrap<CallInst>(Val);
|
||||||
|
AttrBuilder attr_builder(call->getContext());
|
||||||
|
Type *llvm_type = unwrap<Type>(type_val);
|
||||||
|
attr_builder.addByValAttr(llvm_type);
|
||||||
|
// NOTE: +1 here since index 0 refers to the return value
|
||||||
|
call->addAttributeAtIndex(ArgNo + 1, attr_builder.getAttribute(Attribute::ByVal));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ZigLLVMAddSretAttr(LLVMValueRef fn_ref, LLVMTypeRef type_val) {
|
void ZigLLVMAddSretAttr(LLVMValueRef fn_ref, LLVMTypeRef type_val) {
|
||||||
|
|
|
||||||
|
|
@ -129,6 +129,8 @@ ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildCall(LLVMBuilderRef B, LLVMTypeRef functio
|
||||||
LLVMValueRef Fn, LLVMValueRef *Args, unsigned NumArgs, enum ZigLLVM_CallingConv CC,
|
LLVMValueRef Fn, LLVMValueRef *Args, unsigned NumArgs, enum ZigLLVM_CallingConv CC,
|
||||||
enum ZigLLVM_CallAttr attr, const char *Name);
|
enum ZigLLVM_CallAttr attr, const char *Name);
|
||||||
|
|
||||||
|
ZIG_EXTERN_C void ZigLLVMAddAttributeAtIndex(LLVMValueRef Val, unsigned Idx, LLVMAttributeRef A);
|
||||||
|
|
||||||
ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildMemCpy(LLVMBuilderRef B, LLVMValueRef Dst, unsigned DstAlign,
|
ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildMemCpy(LLVMBuilderRef B, LLVMValueRef Dst, unsigned DstAlign,
|
||||||
LLVMValueRef Src, unsigned SrcAlign, LLVMValueRef Size, bool isVolatile);
|
LLVMValueRef Src, unsigned SrcAlign, LLVMValueRef Size, bool isVolatile);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -842,3 +842,32 @@ struct ByRef c_modify_by_ref_param(struct ByRef in) {
|
||||||
in.val = 42;
|
in.val = 42;
|
||||||
return in;
|
return in;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct ByVal {
|
||||||
|
struct {
|
||||||
|
unsigned long x;
|
||||||
|
unsigned long y;
|
||||||
|
unsigned long z;
|
||||||
|
} origin;
|
||||||
|
struct {
|
||||||
|
unsigned long width;
|
||||||
|
unsigned long height;
|
||||||
|
unsigned long depth;
|
||||||
|
} size;
|
||||||
|
};
|
||||||
|
|
||||||
|
void c_func_ptr_byval(void *a, void *b, struct ByVal in, unsigned long c, void *d, unsigned long e) {
|
||||||
|
assert_or_panic((intptr_t)a == 1);
|
||||||
|
assert_or_panic((intptr_t)b == 2);
|
||||||
|
|
||||||
|
assert_or_panic(in.origin.x == 9);
|
||||||
|
assert_or_panic(in.origin.y == 10);
|
||||||
|
assert_or_panic(in.origin.z == 11);
|
||||||
|
assert_or_panic(in.size.width == 12);
|
||||||
|
assert_or_panic(in.size.height == 13);
|
||||||
|
assert_or_panic(in.size.depth == 14);
|
||||||
|
|
||||||
|
assert_or_panic(c == 3);
|
||||||
|
assert_or_panic((intptr_t)d == 4);
|
||||||
|
assert_or_panic(e == 5);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1001,3 +1001,34 @@ test "C function modifies by ref param" {
|
||||||
const res = c_modify_by_ref_param(.{ .val = 1, .arr = undefined });
|
const res = c_modify_by_ref_param(.{ .val = 1, .arr = undefined });
|
||||||
try expect(res.val == 42);
|
try expect(res.val == 42);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const ByVal = extern struct {
|
||||||
|
origin: extern struct {
|
||||||
|
x: c_ulong,
|
||||||
|
y: c_ulong,
|
||||||
|
z: c_ulong,
|
||||||
|
},
|
||||||
|
size: extern struct {
|
||||||
|
width: c_ulong,
|
||||||
|
height: c_ulong,
|
||||||
|
depth: c_ulong,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
extern fn c_func_ptr_byval(*anyopaque, *anyopaque, ByVal, c_ulong, *anyopaque, c_ulong) void;
|
||||||
|
test "C function that takes byval struct called via function pointer" {
|
||||||
|
if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest;
|
||||||
|
|
||||||
|
var fn_ptr = &c_func_ptr_byval;
|
||||||
|
fn_ptr(
|
||||||
|
@intToPtr(*anyopaque, 1),
|
||||||
|
@intToPtr(*anyopaque, 2),
|
||||||
|
ByVal{
|
||||||
|
.origin = .{ .x = 9, .y = 10, .z = 11 },
|
||||||
|
.size = .{ .width = 12, .height = 13, .depth = 14 },
|
||||||
|
},
|
||||||
|
@as(c_ulong, 3),
|
||||||
|
@intToPtr(*anyopaque, 4),
|
||||||
|
@as(c_ulong, 5),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue