mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 05:44:20 +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;
|
||||
};
|
||||
|
||||
if (fn_info.return_type.isError() and
|
||||
self.dg.module.comp.bin_file.options.error_return_tracing)
|
||||
{
|
||||
const err_return_tracing = fn_info.return_type.isError() and
|
||||
self.dg.module.comp.bin_file.options.error_return_tracing;
|
||||
if (err_return_tracing) {
|
||||
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) {
|
||||
_ = self.builder.buildUnreachable();
|
||||
return null;
|
||||
|
|
@ -10469,6 +10529,7 @@ const ParamTypeIterator = struct {
|
|||
it.llvm_index += 1;
|
||||
var buf: Type.Payload.ElemType = undefined;
|
||||
if (ty.isSlice() or (ty.zigTypeTag() == .Optional and ty.optionalChild(&buf).isSlice())) {
|
||||
it.llvm_index += 1;
|
||||
return .slice;
|
||||
} else if (isByRef(ty)) {
|
||||
return .byref;
|
||||
|
|
|
|||
|
|
@ -88,8 +88,8 @@ pub const Context = opaque {
|
|||
};
|
||||
|
||||
pub const Value = opaque {
|
||||
pub const addAttributeAtIndex = LLVMAddAttributeAtIndex;
|
||||
extern fn LLVMAddAttributeAtIndex(*Value, Idx: AttributeIndex, A: *Attribute) void;
|
||||
pub const addAttributeAtIndex = ZigLLVMAddAttributeAtIndex;
|
||||
extern fn ZigLLVMAddAttributeAtIndex(*Value, Idx: AttributeIndex, A: *Attribute) void;
|
||||
|
||||
pub const removeEnumAttributeAtIndex = LLVMRemoveEnumAttributeAtIndex;
|
||||
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);
|
||||
}
|
||||
|
||||
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 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) {
|
||||
Function *func = unwrap<Function>(fn_ref);
|
||||
AttrBuilder attr_builder(func->getContext());
|
||||
Type *llvm_type = unwrap<Type>(type_val);
|
||||
attr_builder.addByValAttr(llvm_type);
|
||||
func->addParamAttrs(ArgNo, attr_builder);
|
||||
void ZigLLVMAddByValAttr(LLVMValueRef Val, unsigned ArgNo, LLVMTypeRef type_val) {
|
||||
if (isa<Function>(unwrap(Val))) {
|
||||
Function *func = unwrap<Function>(Val);
|
||||
AttrBuilder attr_builder(func->getContext());
|
||||
Type *llvm_type = unwrap<Type>(type_val);
|
||||
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) {
|
||||
|
|
|
|||
|
|
@ -129,6 +129,8 @@ ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildCall(LLVMBuilderRef B, LLVMTypeRef functio
|
|||
LLVMValueRef Fn, LLVMValueRef *Args, unsigned NumArgs, enum ZigLLVM_CallingConv CC,
|
||||
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,
|
||||
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;
|
||||
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 });
|
||||
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