Skip to content

Commit 5e4fd50

Browse files
authored
[clang] Add missing readonly/readnone annotations (#158424)
When arg memory effects are lost due to indirect arguments, apply readonly/readnone attribute to the other pointer arguments of the function. Fixes #157693 .
1 parent 3ddb549 commit 5e4fd50

File tree

2 files changed

+41
-7
lines changed

2 files changed

+41
-7
lines changed

clang/lib/CodeGen/CGCall.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2438,7 +2438,10 @@ void CodeGenModule::ConstructAttributeList(StringRef Name,
24382438

24392439
// Some ABIs may result in additional accesses to arguments that may
24402440
// otherwise not be present.
2441+
std::optional<llvm::Attribute::AttrKind> MemAttrForPtrArgs;
2442+
bool AddedPotentialArgAccess = false;
24412443
auto AddPotentialArgAccess = [&]() {
2444+
AddedPotentialArgAccess = true;
24422445
llvm::Attribute A = FuncAttrs.getAttribute(llvm::Attribute::Memory);
24432446
if (A.isValid())
24442447
FuncAttrs.addMemoryAttr(A.getMemoryEffects() |
@@ -2499,11 +2502,13 @@ void CodeGenModule::ConstructAttributeList(StringRef Name,
24992502
// gcc specifies that 'const' functions have greater restrictions than
25002503
// 'pure' functions, so they also cannot have infinite loops.
25012504
FuncAttrs.addAttribute(llvm::Attribute::WillReturn);
2505+
MemAttrForPtrArgs = llvm::Attribute::ReadNone;
25022506
} else if (TargetDecl->hasAttr<PureAttr>()) {
25032507
FuncAttrs.addMemoryAttr(llvm::MemoryEffects::readOnly());
25042508
FuncAttrs.addAttribute(llvm::Attribute::NoUnwind);
25052509
// gcc specifies that 'pure' functions cannot have infinite loops.
25062510
FuncAttrs.addAttribute(llvm::Attribute::WillReturn);
2511+
MemAttrForPtrArgs = llvm::Attribute::ReadOnly;
25072512
} else if (TargetDecl->hasAttr<NoAliasAttr>()) {
25082513
FuncAttrs.addMemoryAttr(llvm::MemoryEffects::inaccessibleOrArgMemOnly());
25092514
FuncAttrs.addAttribute(llvm::Attribute::NoUnwind);
@@ -3011,6 +3016,27 @@ void CodeGenModule::ConstructAttributeList(StringRef Name,
30113016
}
30123017
assert(ArgNo == FI.arg_size());
30133018

3019+
ArgNo = 0;
3020+
if (AddedPotentialArgAccess && MemAttrForPtrArgs) {
3021+
llvm::FunctionType *FunctionType = FunctionType =
3022+
getTypes().GetFunctionType(FI);
3023+
for (CGFunctionInfo::const_arg_iterator I = FI.arg_begin(),
3024+
E = FI.arg_end();
3025+
I != E; ++I, ++ArgNo) {
3026+
if (I->info.isDirect() || I->info.isExpand() ||
3027+
I->info.isCoerceAndExpand()) {
3028+
unsigned FirstIRArg, NumIRArgs;
3029+
std::tie(FirstIRArg, NumIRArgs) = IRFunctionArgs.getIRArgs(ArgNo);
3030+
for (unsigned i = FirstIRArg; i < FirstIRArg + NumIRArgs; ++i) {
3031+
if (FunctionType->getParamType(i)->isPointerTy()) {
3032+
ArgAttrs[i] =
3033+
ArgAttrs[i].addAttribute(getLLVMContext(), *MemAttrForPtrArgs);
3034+
}
3035+
}
3036+
}
3037+
}
3038+
}
3039+
30143040
AttrList = llvm::AttributeList::get(
30153041
getLLVMContext(), llvm::AttributeSet::get(getLLVMContext(), FuncAttrs),
30163042
llvm::AttributeSet::get(getLLVMContext(), RetAttrs), ArgAttrs);

clang/test/CodeGen/struct-passing.c

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,25 @@ T0 __attribute__((const)) f0(void);
1111
T0 __attribute__((pure)) f1(void);
1212
T1 __attribute__((const)) f2(void);
1313
T1 __attribute__((pure)) f3(void);
14-
void __attribute__((const)) f4(T1 a);
15-
void __attribute__((pure)) f5(T1 a);
14+
int __attribute__((const)) f4(T1 a);
15+
int __attribute__((pure)) f5(T1 a);
1616

17-
void *ps[] = { f0, f1, f2, f3, f4, f5 };
17+
// NOTE: The int parameters verifies non-ptr parameters are not a problem
18+
T1 __attribute__((const)) f6(void*, int);
19+
T1 __attribute__((pure)) f7(void*, int);
20+
21+
void *ps[] = { f0, f1, f2, f3, f4, f5, f6, f7 };
1822

1923
// CHECK: declare i32 @f0() [[RN:#[0-9]+]]
2024
// CHECK: declare i32 @f1() [[RO:#[0-9]+]]
21-
// CHECK: declare void @f2({{.*}} sret({{.*}}) align 4)
22-
// CHECK: declare void @f3({{.*}} sret({{.*}}) align 4)
23-
// CHECK: declare void @f4({{.*}} byval({{.*}}) align 4)
24-
// CHECK: declare void @f5({{.*}} byval({{.*}}) align 4)
25+
// CHECK: declare void @f2(ptr {{[^,]*}} sret({{[^)]*}}) align 4) [[RNRW:#[0-9]+]]
26+
// CHECK: declare void @f3(ptr {{[^,]*}} sret({{[^)]*}}) align 4) [[RORW:#[0-9]+]]
27+
// CHECK: declare i32 @f4(ptr {{[^,]*}} byval({{[^)]*}}) align 4) [[RNRW:#[0-9]+]]
28+
// CHECK: declare i32 @f5(ptr {{[^,]*}} byval({{[^)]*}}) align 4) [[RORW:#[0-9]+]]
29+
// CHECK: declare void @f6(ptr {{[^,]*}} sret({{[^)]*}}) align 4, ptr {{[^,]*}} readnone, i32 {{[^,]*}}) [[RNRW:#[0-9]+]]
30+
// CHECK: declare void @f7(ptr {{[^,]*}} sret({{[^)]*}}) align 4, ptr {{[^,]*}} readonly, i32 {{[^,]*}}) [[RORW:#[0-9]+]]
2531

2632
// CHECK: attributes [[RN]] = { nounwind willreturn memory(none){{.*}} }
2733
// CHECK: attributes [[RO]] = { nounwind willreturn memory(read){{.*}} }
34+
// CHECK: attributes [[RNRW]] = { nounwind willreturn memory(argmem: readwrite){{.*}} }
35+
// CHECK: attributes [[RORW]] = { nounwind willreturn memory(read, argmem: readwrite){{.*}} }

0 commit comments

Comments
 (0)