diff --git a/llvm/include/llvm/Bitcode/LLVMBitCodes.h b/llvm/include/llvm/Bitcode/LLVMBitCodes.h --- a/llvm/include/llvm/Bitcode/LLVMBitCodes.h +++ b/llvm/include/llvm/Bitcode/LLVMBitCodes.h @@ -660,6 +660,7 @@ ATTR_KIND_HOT = 72, ATTR_KIND_NO_PROFILE = 73, ATTR_KIND_VSCALE_RANGE = 74, + ATTR_KIND_NO_INTERPROCEDURAL_ANALYSIS = 75, }; enum ComdatSelectionKindCodes { diff --git a/llvm/include/llvm/IR/Attributes.td b/llvm/include/llvm/IR/Attributes.td --- a/llvm/include/llvm/IR/Attributes.td +++ b/llvm/include/llvm/IR/Attributes.td @@ -124,6 +124,9 @@ /// inline=never. def NoInline : EnumAttr<"noinline">; +/// Do not do interprocedural analysis or optimization including this function +def NoInterproceduralAnalysis : EnumAttr<"noipa">; + /// Function is called early and/or often, so lazy binding isn't worthwhile. def NonLazyBind : EnumAttr<"nonlazybind">; diff --git a/llvm/include/llvm/IR/Function.h b/llvm/include/llvm/IR/Function.h --- a/llvm/include/llvm/IR/Function.h +++ b/llvm/include/llvm/IR/Function.h @@ -709,6 +709,11 @@ /// Do not optimize this function (-O0). bool hasOptNone() const { return hasFnAttribute(Attribute::OptimizeNone); } + /// Do not perform interprocedural analysis or optimization of this function. + bool hasNoIPA() const { + return hasFnAttribute(Attribute::NoInterproceduralAnalysis); + } + /// Optimize this function for minimum size (-Oz). bool hasMinSize() const { return hasFnAttribute(Attribute::MinSize); } diff --git a/llvm/include/llvm/IR/GlobalValue.h b/llvm/include/llvm/IR/GlobalValue.h --- a/llvm/include/llvm/IR/GlobalValue.h +++ b/llvm/include/llvm/IR/GlobalValue.h @@ -125,26 +125,7 @@ /// Returns true if the definition of this global may be replaced by a /// differently optimized variant of the same source level function at link /// time. - bool mayBeDerefined() const { - switch (getLinkage()) { - case WeakODRLinkage: - case LinkOnceODRLinkage: - case AvailableExternallyLinkage: - return true; - - case WeakAnyLinkage: - case LinkOnceAnyLinkage: - case CommonLinkage: - case ExternalWeakLinkage: - case ExternalLinkage: - case AppendingLinkage: - case InternalLinkage: - case PrivateLinkage: - return isInterposable(); - } - - llvm_unreachable("Fully covered switch above!"); - } + bool mayBeDerefined() const; protected: /// The intrinsic ID for this subclass (which must be a Function). diff --git a/llvm/lib/AsmParser/LLLexer.cpp b/llvm/lib/AsmParser/LLLexer.cpp --- a/llvm/lib/AsmParser/LLLexer.cpp +++ b/llvm/lib/AsmParser/LLLexer.cpp @@ -659,6 +659,7 @@ KEYWORD(nofree); KEYWORD(noimplicitfloat); KEYWORD(noinline); + KEYWORD(noipa); KEYWORD(norecurse); KEYWORD(nonlazybind); KEYWORD(nomerge); diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp --- a/llvm/lib/AsmParser/LLParser.cpp +++ b/llvm/lib/AsmParser/LLParser.cpp @@ -1388,6 +1388,9 @@ case lltok::kw_noimplicitfloat: B.addAttribute(Attribute::NoImplicitFloat); break; case lltok::kw_noinline: B.addAttribute(Attribute::NoInline); break; + case lltok::kw_noipa: + B.addAttribute(Attribute::NoInterproceduralAnalysis); + break; case lltok::kw_nonlazybind: B.addAttribute(Attribute::NonLazyBind); break; case lltok::kw_nomerge: B.addAttribute(Attribute::NoMerge); break; case lltok::kw_noredzone: B.addAttribute(Attribute::NoRedZone); break; diff --git a/llvm/lib/AsmParser/LLToken.h b/llvm/lib/AsmParser/LLToken.h --- a/llvm/lib/AsmParser/LLToken.h +++ b/llvm/lib/AsmParser/LLToken.h @@ -206,6 +206,7 @@ kw_nofree, kw_noimplicitfloat, kw_noinline, + kw_noipa, kw_norecurse, kw_nonlazybind, kw_nomerge, diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp --- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp @@ -1548,6 +1548,8 @@ return Attribute::MustProgress; case bitc::ATTR_KIND_HOT: return Attribute::Hot; + case bitc::ATTR_KIND_NO_INTERPROCEDURAL_ANALYSIS: + return Attribute::NoInterproceduralAnalysis; } } diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp --- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp +++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -758,6 +758,8 @@ return bitc::ATTR_KIND_BYREF; case Attribute::MustProgress: return bitc::ATTR_KIND_MUSTPROGRESS; + case Attribute::NoInterproceduralAnalysis: + return bitc::ATTR_KIND_NO_INTERPROCEDURAL_ANALYSIS; case Attribute::EndAttrKinds: llvm_unreachable("Can not encode end-attribute kinds marker."); case Attribute::None: diff --git a/llvm/lib/IR/Attributes.cpp b/llvm/lib/IR/Attributes.cpp --- a/llvm/lib/IR/Attributes.cpp +++ b/llvm/lib/IR/Attributes.cpp @@ -446,6 +446,8 @@ return "optnone"; if (hasAttribute(Attribute::OptimizeForSize)) return "optsize"; + if (hasAttribute(Attribute::NoInterproceduralAnalysis)) + return "noipa"; if (hasAttribute(Attribute::ReadNone)) return "readnone"; if (hasAttribute(Attribute::ReadOnly)) diff --git a/llvm/lib/IR/Globals.cpp b/llvm/lib/IR/Globals.cpp --- a/llvm/lib/IR/Globals.cpp +++ b/llvm/lib/IR/Globals.cpp @@ -326,6 +326,30 @@ return hasAtLeastLocalUnnamedAddr(); } + bool GlobalValue::mayBeDerefined() const { + switch (getLinkage()) { + case WeakODRLinkage: + case LinkOnceODRLinkage: + case AvailableExternallyLinkage: + return true; + + case WeakAnyLinkage: + case LinkOnceAnyLinkage: + case CommonLinkage: + case ExternalWeakLinkage: + case ExternalLinkage: + case AppendingLinkage: + case InternalLinkage: + case PrivateLinkage: { + if (const Function *F = dyn_cast(this)) + if (F->hasNoIPA()) + return true; + return isInterposable(); + } + } + + llvm_unreachable("Fully covered switch above!"); + } //===----------------------------------------------------------------------===// // GlobalVariable Implementation //===----------------------------------------------------------------------===// diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -1689,6 +1689,7 @@ case Attribute::Hot: case Attribute::OptForFuzzing: case Attribute::OptimizeNone: + case Attribute::NoInterproceduralAnalysis: case Attribute::JumpTable: case Attribute::Convergent: case Attribute::ArgMemOnly: diff --git a/llvm/lib/Transforms/Utils/CodeExtractor.cpp b/llvm/lib/Transforms/Utils/CodeExtractor.cpp --- a/llvm/lib/Transforms/Utils/CodeExtractor.cpp +++ b/llvm/lib/Transforms/Utils/CodeExtractor.cpp @@ -956,6 +956,7 @@ case Attribute::NullPointerIsValid: case Attribute::OptForFuzzing: case Attribute::OptimizeNone: + case Attribute::NoInterproceduralAnalysis: case Attribute::OptimizeForSize: case Attribute::SafeStack: case Attribute::ShadowCallStack: diff --git a/llvm/test/Bitcode/attributes.ll b/llvm/test/Bitcode/attributes.ll --- a/llvm/test/Bitcode/attributes.ll +++ b/llvm/test/Bitcode/attributes.ll @@ -447,6 +447,11 @@ ret void } +; CHECK: define void @f76() #48 +define void @f76() noipa +{ + ret void +} ; CHECK: attributes #0 = { noreturn } ; CHECK: attributes #1 = { nounwind } ; CHECK: attributes #2 = { readnone } @@ -495,4 +500,5 @@ ; CHECK: attributes #45 = { vscale_range(8,8) } ; CHECK: attributes #46 = { vscale_range(1,8) } ; CHECK: attributes #47 = { vscale_range(1,0) } +; CHECK: attributes #48 = { noipa } ; CHECK: attributes #[[NOBUILTIN]] = { nobuiltin } diff --git a/llvm/unittests/IR/FunctionTest.cpp b/llvm/unittests/IR/FunctionTest.cpp --- a/llvm/unittests/IR/FunctionTest.cpp +++ b/llvm/unittests/IR/FunctionTest.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "llvm/IR/Function.h" +#include "llvm/IR/Attributes.h" #include "llvm/IR/Module.h" #include "gtest/gtest.h" using namespace llvm; @@ -162,4 +163,17 @@ EXPECT_EQ(Align(4), Func->getPointerAlignment(DataLayout("Fn32"))); } +TEST(FunctionTest, NoIPAInexact) { + LLVMContext Context; + Type *VoidType = Type::getVoidTy(Context); + FunctionType *FuncType = FunctionType::get(VoidType, false); + std::unique_ptr Func( + Function::Create(FuncType, GlobalValue::ExternalLinkage)); + EXPECT_TRUE(Func->isDefinitionExact()); + AttrBuilder B; + B.addAttribute(Attribute::NoInterproceduralAnalysis); + Func->addAttributes(llvm::AttributeList::FunctionIndex, B); + EXPECT_FALSE(Func->isDefinitionExact()); +} + } // end namespace diff --git a/llvm/utils/emacs/llvm-mode.el b/llvm/utils/emacs/llvm-mode.el --- a/llvm/utils/emacs/llvm-mode.el +++ b/llvm/utils/emacs/llvm-mode.el @@ -24,7 +24,7 @@ `(,(regexp-opt '("alwaysinline" "argmemonly" "allocsize" "builtin" "cold" "convergent" "dereferenceable" "dereferenceable_or_null" "hot" "inaccessiblememonly" "inaccessiblemem_or_argmemonly" "inalloca" "inlinehint" "jumptable" "minsize" "mustprogress" "naked" "nobuiltin" "nonnull" - "nocallback" "nocf_check" "noduplicate" "nofree" "noimplicitfloat" "noinline" "nomerge" "nonlazybind" "noprofile" "noredzone" "noreturn" + "nocallback" "nocf_check" "noduplicate" "nofree" "noimplicitfloat" "noinline" "noipa" "nomerge" "nonlazybind" "noprofile" "noredzone" "noreturn" "norecurse" "nosync" "noundef" "nounwind" "null_pointer_is_valid" "optforfuzzing" "optnone" "optsize" "preallocated" "readnone" "readonly" "returned" "returns_twice" "shadowcallstack" "speculatable" "speculative_load_hardening" "ssp" "sspreq" "sspstrong" "safestack" "sanitize_address" "sanitize_hwaddress" "sanitize_memtag" "sanitize_thread" "sanitize_memory" "strictfp" "swifterror" "uwtable" "vscale_range" "willreturn" "writeonly" "immarg") 'symbols) . font-lock-constant-face) diff --git a/llvm/utils/kate/llvm.xml b/llvm/utils/kate/llvm.xml --- a/llvm/utils/kate/llvm.xml +++ b/llvm/utils/kate/llvm.xml @@ -104,6 +104,7 @@ nofree noimplicitfloat noinline + noipa nomerge noprofile noredzone diff --git a/llvm/utils/vim/syntax/llvm.vim b/llvm/utils/vim/syntax/llvm.vim --- a/llvm/utils/vim/syntax/llvm.vim +++ b/llvm/utils/vim/syntax/llvm.vim @@ -128,6 +128,7 @@ \ nofree \ noimplicitfloat \ noinline + \ noipa \ nomerge \ nonlazybind \ nonnull diff --git a/llvm/utils/vscode/llvm/syntaxes/ll.tmLanguage.yaml b/llvm/utils/vscode/llvm/syntaxes/ll.tmLanguage.yaml --- a/llvm/utils/vscode/llvm/syntaxes/ll.tmLanguage.yaml +++ b/llvm/utils/vscode/llvm/syntaxes/ll.tmLanguage.yaml @@ -227,6 +227,7 @@ \\bnofree\\b|\ \\bnoimplicitfloat\\b|\ \\bnoinline\\b|\ + \\bnoipa\\b|\ \\bnomerge\\b|\ \\bnonlazybind\\b|\ \\bnonnull\\b|\