Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion clang/lib/CodeGen/CGCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3024,6 +3024,11 @@ void CodeGenModule::ConstructAttributeList(StringRef Name,
}
assert(ArgNo == FI.arg_size());

// We can't see all potential arguments in a varargs declaration; treat them
// as if they can access memory.
if (!AttrOnCallSite && FI.isVariadic())
AddPotentialArgAccess();

ArgNo = 0;
if (AddedPotentialArgAccess && MemAttrForPtrArgs) {
llvm::FunctionType *FunctionType = getTypes().GetFunctionType(FI);
Expand All @@ -3035,7 +3040,14 @@ void CodeGenModule::ConstructAttributeList(StringRef Name,
unsigned FirstIRArg, NumIRArgs;
std::tie(FirstIRArg, NumIRArgs) = IRFunctionArgs.getIRArgs(ArgNo);
for (unsigned i = FirstIRArg; i < FirstIRArg + NumIRArgs; ++i) {
if (FunctionType->getParamType(i)->isPointerTy()) {
// The index may be out-of-bounds if the callee is a varargs
// function.
//
// FIXME: We can compute the types of varargs arguments without going
// through the function type, but the relevant code isn't exposed
// in a way that can be called from here.
if (i < FunctionType->getNumParams() &&
FunctionType->getParamType(i)->isPointerTy()) {
ArgAttrs[i] =
ArgAttrs[i].addAttribute(getLLVMContext(), *MemAttrForPtrArgs);
}
Expand Down
39 changes: 34 additions & 5 deletions clang/test/CodeGen/struct-passing.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,47 @@ int __attribute__((pure)) f5(T1 a);
T1 __attribute__((const)) f6(void*, int);
T1 __attribute__((pure)) f7(void*, int);

void *ps[] = { f0, f1, f2, f3, f4, f5, f6, f7 };
T1 __attribute__((const)) f8(int, ...);
int __attribute__((const)) f9(int, ...);

void *ps[] = { f0, f1, f2, f3, f4, f5, f6, f7, f8, f9 };

// Check markings for varargs arguments.
//
// FIXME: We can add markings in more cases.
void test(T1 t1, void *p) {
f8(1);
f8(1, t1);
f8(1, p);

f9(1);
f9(1, t1);
f9(1, p);
}

// CHECK: declare i32 @f0() [[RN:#[0-9]+]]
// CHECK: declare i32 @f1() [[RO:#[0-9]+]]
// CHECK: declare void @f2(ptr {{[^,]*}} sret({{[^)]*}}) align 4) [[RNRW:#[0-9]+]]
// CHECK: declare void @f3(ptr {{[^,]*}} sret({{[^)]*}}) align 4) [[RORW:#[0-9]+]]
// CHECK: declare i32 @f4(ptr {{[^,]*}} byval({{[^)]*}}) align 4) [[RNRW:#[0-9]+]]
// CHECK: declare i32 @f5(ptr {{[^,]*}} byval({{[^)]*}}) align 4) [[RORW:#[0-9]+]]
// CHECK: declare void @f6(ptr {{[^,]*}} sret({{[^)]*}}) align 4, ptr {{[^,]*}} readnone, i32 {{[^,]*}}) [[RNRW:#[0-9]+]]
// CHECK: declare void @f7(ptr {{[^,]*}} sret({{[^)]*}}) align 4, ptr {{[^,]*}} readonly, i32 {{[^,]*}}) [[RORW:#[0-9]+]]
// CHECK: declare i32 @f4(ptr {{[^,]*}} byval({{[^)]*}}) align 4) [[RNRW]]
// CHECK: declare i32 @f5(ptr {{[^,]*}} byval({{[^)]*}}) align 4) [[RORW]]
// CHECK: declare void @f6(ptr {{[^,]*}} sret({{[^)]*}}) align 4, ptr {{[^,]*}} readnone, i32 {{[^,]*}}) [[RNRW]]
// CHECK: declare void @f7(ptr {{[^,]*}} sret({{[^)]*}}) align 4, ptr {{[^,]*}} readonly, i32 {{[^,]*}}) [[RORW]]
// CHECK: declare void @f8(ptr dead_on_unwind writable sret(%struct.T1) align 4, i32 noundef, ...) [[RNRW]]
// CHECK: declare i32 @f9(i32 noundef, ...) [[RNRW]]


// CHECK: call void (ptr, i32, ...) @f8(ptr dead_on_unwind writable sret(%struct.T1) align 4 {{.*}}, i32 noundef 1) [[RNRW_CALL:#[0-9]+]]
// CHECK: call void (ptr, i32, ...) @f8(ptr dead_on_unwind writable sret(%struct.T1) align 4 {{.*}}, i32 noundef 1, ptr noundef byval(%struct.T1) align 4 {{.*}}) [[RNRW_CALL]]
// CHECK: call void (ptr, i32, ...) @f8(ptr dead_on_unwind writable sret(%struct.T1) align 4 {{.*}}, i32 noundef 1, ptr noundef %0) [[RNRW_CALL]]
// CHECK: call i32 (i32, ...) @f9(i32 noundef 1) [[RN_CALL:#[0-9]+]]
// CHECK: call i32 (i32, ...) @f9(i32 noundef 1, ptr noundef byval(%struct.T1) align 4 {{.*}}) [[RNRW_CALL]]
// CHECK: call i32 (i32, ...) @f9(i32 noundef 1, ptr noundef %1) [[RN_CALL]]


// CHECK: attributes [[RN]] = { nounwind willreturn memory(none){{.*}} }
// CHECK: attributes [[RO]] = { nounwind willreturn memory(read){{.*}} }
// CHECK: attributes [[RNRW]] = { nounwind willreturn memory(argmem: readwrite){{.*}} }
// CHECK: attributes [[RORW]] = { nounwind willreturn memory(read, argmem: readwrite){{.*}} }
// CHECK: attributes [[RNRW_CALL]] = { nounwind willreturn memory(argmem: readwrite) }
// CHECK: attributes [[RN_CALL]] = { nounwind willreturn memory(none) }
Loading