[IR] move nomerge attribute from function declaration/definition to callsites

Move nomerge attribute from function declaration/definition to callsites to
allow virtual function calls attach the attribute.

Differential Revision: https://reviews.llvm.org/D94537
This commit is contained in:
Zequan Wu 2021-01-12 11:22:31 -08:00
parent 6cd44b204c
commit e53bbd9951
3 changed files with 35 additions and 38 deletions

View File

@ -1985,7 +1985,9 @@ void CodeGenModule::ConstructAttributeList(
FuncAttrs.addAttribute(llvm::Attribute::NoReturn);
NBA = Fn->getAttr<NoBuiltinAttr>();
}
if (!AttrOnCallSite && TargetDecl->hasAttr<NoMergeAttr>())
// Only place nomerge attribute on call sites, never functions. This
// allows it to work on indirect virtual function calls.
if (AttrOnCallSite && TargetDecl->hasAttr<NoMergeAttr>())
FuncAttrs.addAttribute(llvm::Attribute::NoMerge);
}
@ -5018,13 +5020,11 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
Attrs.addAttribute(getLLVMContext(), llvm::AttributeList::FunctionIndex,
llvm::Attribute::StrictFP);
// Add nomerge attribute to the call-site if the callee function doesn't have
// the attribute.
if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(TargetDecl))
if (!FD->hasAttr<NoMergeAttr>() && InNoMergeAttributedStmt)
Attrs = Attrs.addAttribute(getLLVMContext(),
llvm::AttributeList::FunctionIndex,
llvm::Attribute::NoMerge);
// Add call-site nomerge attribute if exists.
if (InNoMergeAttributedStmt)
Attrs =
Attrs.addAttribute(getLLVMContext(), llvm::AttributeList::FunctionIndex,
llvm::Attribute::NoMerge);
// Apply some call-site-specific attributes.
// TODO: work this into building the attribute set.

View File

@ -1772,9 +1772,6 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,
B.addAttribute(llvm::Attribute::MinSize);
}
if (D->hasAttr<NoMergeAttr>())
B.addAttribute(llvm::Attribute::NoMerge);
F->addAttributes(llvm::AttributeList::FunctionIndex, B);
unsigned alignment = D->getMaxAlignment() / Context.getCharWidth();

View File

@ -3,7 +3,7 @@
class A {
public:
[[clang::nomerge]] A();
[[clang::nomerge]] ~A();
[[clang::nomerge]] virtual ~A();
[[clang::nomerge]] void f();
[[clang::nomerge]] virtual void g();
[[clang::nomerge]] static void f1();
@ -14,14 +14,14 @@ public:
void g() override;
};
[[clang::nomerge]] bool bar();
bool bar();
[[clang::nomerge]] void f(bool, bool);
void foo(int i, A *ap, B *bp) {
[[clang::nomerge]] bar();
[[clang::nomerge]] (i = 4, bar());
[[clang::nomerge]] (void)(bar());
[[clang::nomerge]] f(bar(), bar());
f(bar(), bar());
[[clang::nomerge]] [] { bar(); bar(); }(); // nomerge only applies to the anonymous function call
[[clang::nomerge]] for (bar(); bar(); bar()) {}
[[clang::nomerge]] { asm("nop"); }
@ -37,6 +37,9 @@ void foo(int i, A *ap, B *bp) {
B b;
b.g();
A *newA = new B();
delete newA;
}
int g(int i);
@ -57,37 +60,34 @@ void something_else_again() {
g(1);
}
// CHECK: call zeroext i1 @_Z3barv() #[[ATTR0:[0-9]+]]
// CHECK: call zeroext i1 @_Z3barv() #[[ATTR0]]
// CHECK: call zeroext i1 @_Z3barv() #[[ATTR0]]
// CHECK: call zeroext i1 @_Z3barv(){{$}}
// CHECK: call zeroext i1 @_Z3barv(){{$}}
// CHECK: call zeroext i1 @_Z3barv(){{$}}
// CHECK: call zeroext i1 @_Z3barv(){{$}}
// CHECK: call zeroext i1 @_Z3barv(){{$}}
// CHECK: call void @_Z1fbb({{.*}}){{$}}
// CHECK: call void @"_ZZ3fooiP1AP1BENK3$_0clEv"{{.*}} #[[ATTR0:[0-9]+]]
// CHECK: call zeroext i1 @_Z3barv(){{$}}
// CHECK: call zeroext i1 @_Z3barv(){{$}}
// CHECK: call zeroext i1 @_Z3barv(){{$}}
// CHECK: call void @_Z1fbb({{.*}}) #[[ATTR0]]
// CHECK: call void @"_ZZ3fooiP1AP1BENK3$_0clEv"{{.*}} #[[ATTR0]]
// CHECK: call zeroext i1 @_Z3barv() #[[ATTR0]]
// CHECK-LABEL: for.cond:
// CHECK: call zeroext i1 @_Z3barv() #[[ATTR0]]
// CHECK-LABEL: for.inc:
// CHECK: call zeroext i1 @_Z3barv() #[[ATTR0]]
// CHECK: call void asm sideeffect "nop"{{.*}} #[[ATTR1:[0-9]+]]
// CHECK: call zeroext i1 @_Z3barv(){{$}}
// CHECK: %[[AG:.*]] = load void (%class.A*)*, void (%class.A*)**
// CHECK-NEXT: call void %[[AG]](%class.A* nonnull dereferenceable
// CHECK-NEXT: call void %[[AG]](%class.A* {{.*}}) #[[ATTR0]]
// CHECK: %[[BG:.*]] = load void (%class.B*)*, void (%class.B*)**
// CHECK-NEXT: call void %[[BG]](%class.B* nonnull dereferenceable
// CHECK-DAG: declare zeroext i1 @_Z3barv() #[[ATTR2:[0-9]+]]
// CHECK-DAG: declare void @_Z1fbb(i1 zeroext, i1 zeroext) #[[ATTR2]]
// CHECK-DAG: declare void @_ZN1AC1Ev{{.*}} #[[ATTR2]]
// CHECK-DAG: declare void @_ZN1A1fEv{{.*}} #[[ATTR2]]
// CHECK-DAG: declare void @_ZN1A1gEv{{.*}} #[[ATTR2]]
// CHECK-DAG: declare void @_ZN1A2f1Ev{{.*}} #[[ATTR2]]
// CHECK-DAG: declare void @_ZN1AC2Ev{{.*}} #[[ATTR2]]
// CHECK-DAG: declare void @_ZN1AD1Ev{{.*}} #[[ATTR3:[0-9]+]]
// CHECK-DAG: declare void @_ZN1AD2Ev{{.*}} #[[ATTR3]]
// CHECK-DAG: define{{.*}} i32 @_Z1gi(i32 %i) #[[ATTR4:[0-9]+]] {
// CHECK: call void @_ZN1AC1Ev({{.*}}) #[[ATTR0]]
// CHECK: call void @_ZN1A1fEv({{.*}}) #[[ATTR0]]
// CHECK: call void @_ZN1A1gEv({{.*}}) #[[ATTR0]]
// CHECK: call void @_ZN1A2f1Ev() #[[ATTR0]]
// CHECK: call void @_ZN1BC1Ev({{.*}}){{$}}
// CHECK: call void @_ZN1B1gEv({{.*}}){{$}}
// CHECK: call void @_ZN1BC1Ev({{.*}}){{$}}
// CHECK: %[[AG:.*]] = load void (%class.A*)*, void (%class.A*)**
// CHECK-NEXT: call void %[[AG]](%class.A* {{.*}}) #[[ATTR1]]
// CHECK: call void @_ZN1AD1Ev(%class.A* {{.*}}) #[[ATTR1]]
// CHECK-DAG: attributes #[[ATTR0]] = {{{.*}}nomerge{{.*}}}
// CHECK-DAG: attributes #[[ATTR1]] = {{{.*}}nomerge{{.*}}}
// CHECK-DAG: attributes #[[ATTR2]] = {{{.*}}nomerge{{.*}}}
// CHECK-DAG: attributes #[[ATTR3]] = {{{.*}}nomerge{{.*}}}
// CHECK-DAG: attributes #[[ATTR4]] = {{{.*}}nomerge{{.*}}}