diff --git a/llvm/include/llvm/IR/InstrTypes.h b/llvm/include/llvm/IR/InstrTypes.h --- a/llvm/include/llvm/IR/InstrTypes.h +++ b/llvm/include/llvm/IR/InstrTypes.h @@ -25,6 +25,7 @@ #include "llvm/ADT/iterator_range.h" #include "llvm/IR/Attributes.h" #include "llvm/IR/CallingConv.h" +#include "llvm/IR/Constants.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Function.h" #include "llvm/IR/Instruction.h" @@ -1613,12 +1614,18 @@ /// Get the attribute of a given kind for the function. Attribute getFnAttr(StringRef Kind) const { - return getAttributes().getFnAttr(Kind); + Attribute Attr = getAttributes().getFnAttr(Kind); + if (Attr.isValid()) + return Attr; + return getFnAttrOnCalledFunction(Kind); } /// Get the attribute of a given kind for the function. Attribute getFnAttr(Attribute::AttrKind Kind) const { - return getAttributes().getFnAttr(Kind); + Attribute A = getAttributes().getFnAttr(Kind); + if (A.isValid()) + return A; + return getFnAttrOnCalledFunction(Kind); } /// Get the attribute of a given kind from a given arg @@ -2311,6 +2318,7 @@ return hasFnAttrOnCalledFunction(Kind); } + template Attribute getFnAttrOnCalledFunction(AK Kind) const; /// A specialized version of hasFnAttrImpl for when the caller wants to /// know if an attribute's semantics are implied, not whether the attribute diff --git a/llvm/lib/Analysis/InlineCost.cpp b/llvm/lib/Analysis/InlineCost.cpp --- a/llvm/lib/Analysis/InlineCost.cpp +++ b/llvm/lib/Analysis/InlineCost.cpp @@ -142,28 +142,9 @@ "disable-gep-const-evaluation", cl::Hidden, cl::init(false), cl::desc("Disables evaluation of GetElementPtr with constant operands")); -namespace { -/// This function behaves more like CallBase::hasFnAttr: when it looks for the -/// requested attribute, it check both the call instruction and the called -/// function (if it's available and operand bundles don't prohibit that). -Attribute getFnAttr(CallBase &CB, StringRef AttrKind) { - Attribute CallAttr = CB.getFnAttr(AttrKind); - if (CallAttr.isValid()) - return CallAttr; - - // Operand bundles override attributes on the called function, but don't - // override attributes directly present on the call instruction. - if (!CB.isFnAttrDisallowedByOpBundle(AttrKind)) - if (const Function *F = CB.getCalledFunction()) - return F->getFnAttribute(AttrKind); - - return {}; -} -} // namespace - namespace llvm { Optional getStringFnAttrAsInt(CallBase &CB, StringRef AttrKind) { - Attribute Attr = getFnAttr(CB, AttrKind); + Attribute Attr = CB.getFnAttr(AttrKind); int AttrValue; if (Attr.getValueAsString().getAsInteger(10, AttrValue)) return None; diff --git a/llvm/lib/IR/Instructions.cpp b/llvm/lib/IR/Instructions.cpp --- a/llvm/lib/IR/Instructions.cpp +++ b/llvm/lib/IR/Instructions.cpp @@ -372,6 +372,27 @@ return false; } +template +Attribute CallBase::getFnAttrOnCalledFunction(AK Kind) const { + // Operand bundles override attributes on the called function, but don't + // override attributes directly present on the call instruction. + if (isFnAttrDisallowedByOpBundle(Kind)) + return Attribute(); + Value *V = getCalledOperand(); + if (auto *CE = dyn_cast(V)) + if (CE->getOpcode() == BitCast) + V = CE->getOperand(0); + + if (auto *F = dyn_cast(V)) + return F->getAttributes().getFnAttr(Kind); + + return Attribute(); +} + +template Attribute +CallBase::getFnAttrOnCalledFunction(Attribute::AttrKind Kind) const; +template Attribute CallBase::getFnAttrOnCalledFunction(StringRef Kind) const; + void CallBase::getOperandBundlesAsDefs( SmallVectorImpl &Defs) const { for (unsigned i = 0, e = getNumOperandBundles(); i != e; ++i) diff --git a/llvm/test/Transforms/Attributor/assumes_info.ll b/llvm/test/Transforms/Attributor/assumes_info.ll --- a/llvm/test/Transforms/Attributor/assumes_info.ll +++ b/llvm/test/Transforms/Attributor/assumes_info.ll @@ -8,9 +8,9 @@ ; CHECK-LABEL: define {{[^@]+}}@entry ; CHECK-SAME: (i1 [[COND:%.*]]) #[[ATTR0:[0-9]+]] { ; CHECK-NEXT: entry: -; CHECK-NEXT: call void @foo(i1 [[COND]]) #[[ATTR1:[0-9]+]] -; CHECK-NEXT: call void @bar() #[[ATTR2:[0-9]+]] -; CHECK-NEXT: call void @qux() #[[ATTR1]] +; CHECK-NEXT: call void @foo(i1 [[COND]]) +; CHECK-NEXT: call void @bar() +; CHECK-NEXT: call void @qux() #[[ATTR1:[0-9]+]] ; CHECK-NEXT: ret void ; entry: @@ -24,7 +24,7 @@ ; CHECK-LABEL: define {{[^@]+}}@foo ; CHECK-SAME: (i1 [[COND:%.*]]) #[[ATTR1]] { ; CHECK-NEXT: entry: -; CHECK-NEXT: call void @baz(i1 [[COND]]) #[[ATTR1]] +; CHECK-NEXT: call void @baz(i1 [[COND]]) ; CHECK-NEXT: ret void ; entry: @@ -34,7 +34,7 @@ define internal void @bar() #2 { ; CHECK-LABEL: define {{[^@]+}}@bar -; CHECK-SAME: () #[[ATTR2]] { +; CHECK-SAME: () #[[ATTR2:[0-9]+]] { ; CHECK-NEXT: entry: ; CHECK-NEXT: call void @baz(i1 noundef false) #[[ATTR2]] ; CHECK-NEXT: ret void @@ -51,10 +51,10 @@ ; CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne i1 [[COND]], false ; CHECK-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] ; CHECK: if.then: -; CHECK-NEXT: call void @baz(i1 noundef false) #[[ATTR1]] +; CHECK-NEXT: call void @baz(i1 noundef false) ; CHECK-NEXT: br label [[IF_END]] ; CHECK: if.end: -; CHECK-NEXT: call void @qux() #[[ATTR1]] +; CHECK-NEXT: call void @qux() ; CHECK-NEXT: ret void ; entry: @@ -74,7 +74,7 @@ ; CHECK-LABEL: define {{[^@]+}}@qux ; CHECK-SAME: () #[[ATTR1]] { ; CHECK-NEXT: entry: -; CHECK-NEXT: call void @call() #[[ATTR2]] +; CHECK-NEXT: call void @call() ; CHECK-NEXT: ret void ; entry: diff --git a/llvm/test/Transforms/OpenMP/remove_globalization.ll b/llvm/test/Transforms/OpenMP/remove_globalization.ll --- a/llvm/test/Transforms/OpenMP/remove_globalization.ll +++ b/llvm/test/Transforms/OpenMP/remove_globalization.ll @@ -32,7 +32,7 @@ ; CHECK-NEXT: [[TMP0:%.*]] = call i32 @__kmpc_target_init(%struct.ident_t* nonnull null, i8 1, i1 false, i1 true) ; CHECK-NEXT: call void @foo() #[[ATTR0:[0-9]+]] ; CHECK-NEXT: call void @bar() #[[ATTR0]] -; CHECK-NEXT: call void @unknown_no_openmp() #[[ATTR5:[0-9]+]] +; CHECK-NEXT: call void @unknown_no_openmp() ; CHECK-NEXT: call void @__kmpc_target_deinit(%struct.ident_t* nonnull null, i8 1, i1 true) ; CHECK-NEXT: ret void ; @@ -41,7 +41,7 @@ ; CHECK-DISABLED-NEXT: [[TMP0:%.*]] = call i32 @__kmpc_target_init(%struct.ident_t* nonnull null, i8 1, i1 false, i1 true) ; CHECK-DISABLED-NEXT: call void @foo() #[[ATTR0:[0-9]+]] ; CHECK-DISABLED-NEXT: call void @bar() #[[ATTR0]] -; CHECK-DISABLED-NEXT: call void @unknown_no_openmp() #[[ATTR5:[0-9]+]] +; CHECK-DISABLED-NEXT: call void @unknown_no_openmp() ; CHECK-DISABLED-NEXT: call void @__kmpc_target_deinit(%struct.ident_t* nonnull null, i8 1, i1 true) ; CHECK-DISABLED-NEXT: ret void ; @@ -185,7 +185,7 @@ ; CHECK: attributes #[[ATTR2]] = { nounwind readnone } ; CHECK: attributes #[[ATTR3]] = { nofree nosync nounwind writeonly } ; CHECK: attributes #[[ATTR4:[0-9]+]] = { nosync nounwind allocsize(0) } -; CHECK: attributes #[[ATTR5]] = { "llvm.assume"="omp_no_openmp" } +; CHECK: attributes #[[ATTR5:[0-9]+]] = { "llvm.assume"="omp_no_openmp" } ; CHECK: attributes #[[ATTR6]] = { nosync nounwind writeonly } ;. ; CHECK-DISABLED: attributes #[[ATTR0]] = { nounwind } @@ -193,7 +193,7 @@ ; CHECK-DISABLED: attributes #[[ATTR2]] = { nounwind readnone } ; CHECK-DISABLED: attributes #[[ATTR3]] = { nofree nosync nounwind writeonly } ; CHECK-DISABLED: attributes #[[ATTR4:[0-9]+]] = { nosync nounwind allocsize(0) } -; CHECK-DISABLED: attributes #[[ATTR5]] = { "llvm.assume"="omp_no_openmp" } +; CHECK-DISABLED: attributes #[[ATTR5:[0-9]+]] = { "llvm.assume"="omp_no_openmp" } ; CHECK-DISABLED: attributes #[[ATTR6]] = { nosync nounwind writeonly } ;. ; CHECK: [[META0:![0-9]+]] = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 13.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, splitDebugInlining: false, nameTableKind: None) diff --git a/llvm/test/Transforms/OpenMP/replace_globalization.ll b/llvm/test/Transforms/OpenMP/replace_globalization.ll --- a/llvm/test/Transforms/OpenMP/replace_globalization.ll +++ b/llvm/test/Transforms/OpenMP/replace_globalization.ll @@ -146,7 +146,7 @@ ; CHECK-NEXT: entry: ; CHECK-NEXT: [[C:%.*]] = call i32 @__kmpc_target_init(%struct.ident_t* @[[GLOB1]], i8 1, i1 false, i1 true) ; CHECK-NEXT: [[X:%.*]] = call align 4 i8* @__kmpc_alloc_shared(i64 4) #[[ATTR7:[0-9]+]] -; CHECK-NEXT: call void @unknown_no_openmp() #[[ATTR6:[0-9]+]] +; CHECK-NEXT: call void @unknown_no_openmp() ; CHECK-NEXT: [[X_ON_STACK:%.*]] = bitcast i8* [[X]] to i32* ; CHECK-NEXT: [[TMP0:%.*]] = bitcast i32* [[X_ON_STACK]] to i8* ; CHECK-NEXT: call void @use.internalized(i8* nofree [[TMP0]]) #[[ATTR8:[0-9]+]] @@ -158,7 +158,7 @@ ; CHECK-LABEL: define {{[^@]+}}@bar ; CHECK-SAME: () #[[ATTR0]] { ; CHECK-NEXT: [[C:%.*]] = call i32 @__kmpc_target_init(%struct.ident_t* @[[GLOB1]], i8 1, i1 false, i1 true) -; CHECK-NEXT: call void @unknown_no_openmp() #[[ATTR6]] +; CHECK-NEXT: call void @unknown_no_openmp() ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[C]], -1 ; CHECK-NEXT: br i1 [[CMP]], label [[MASTER1:%.*]], label [[EXIT:%.*]] ; CHECK: master1: @@ -167,7 +167,7 @@ ; CHECK-NEXT: call void @use.internalized(i8* nofree [[A0]]) #[[ATTR8]] ; CHECK-NEXT: br label [[NEXT:%.*]] ; CHECK: next: -; CHECK-NEXT: call void @unknown_no_openmp() #[[ATTR6]] +; CHECK-NEXT: call void @unknown_no_openmp() ; CHECK-NEXT: br label [[MASTER2:%.*]] ; CHECK: master2: ; CHECK-NEXT: [[Y_ON_STACK:%.*]] = bitcast i8* addrspacecast (i8 addrspace(3)* getelementptr inbounds ([4 x i8], [4 x i8] addrspace(3)* @y_shared, i32 0, i32 0) to i8*) to [4 x i32]* @@ -182,7 +182,7 @@ ; CHECK-LABEL: define {{[^@]+}}@baz_spmd ; CHECK-SAME: () #[[ATTR0]] { ; CHECK-NEXT: [[C:%.*]] = call i32 @__kmpc_target_init(%struct.ident_t* @[[GLOB1]], i8 2, i1 true, i1 true) -; CHECK-NEXT: call void @unknown_no_openmp() #[[ATTR6]] +; CHECK-NEXT: call void @unknown_no_openmp() ; CHECK-NEXT: [[C0:%.*]] = icmp eq i32 [[C]], -1 ; CHECK-NEXT: br i1 [[C0]], label [[MASTER3:%.*]], label [[EXIT:%.*]] ; CHECK: master3: @@ -225,7 +225,7 @@ ; CHECK: attributes #[[ATTR3:[0-9]+]] = { nosync nounwind } ; CHECK: attributes #[[ATTR4:[0-9]+]] = { nounwind readnone speculatable } ; CHECK: attributes #[[ATTR5:[0-9]+]] = { nocallback nofree nosync nounwind readnone speculatable willreturn } -; CHECK: attributes #[[ATTR6]] = { "llvm.assume"="omp_no_openmp" } +; CHECK: attributes #[[ATTR6:[0-9]+]] = { "llvm.assume"="omp_no_openmp" } ; CHECK: attributes #[[ATTR7]] = { nounwind readonly } ; CHECK: attributes #[[ATTR8]] = { nounwind writeonly } ; CHECK: attributes #[[ATTR9]] = { nounwind }