Index: include/llvm/Analysis/TargetLibraryInfo.def =================================================================== --- include/llvm/Analysis/TargetLibraryInfo.def +++ include/llvm/Analysis/TargetLibraryInfo.def @@ -195,6 +195,9 @@ /// void *__memset_chk(void *s, char v, size_t n, size_t s1size); TLI_DEFINE_ENUM_INTERNAL(memset_chk) TLI_DEFINE_STRING_INTERNAL("__memset_chk") +// float _Complex __mulsc3(float __a, float __b, float __c, float __d) +TLI_DEFINE_ENUM_INTERNAL(mulsc3) +TLI_DEFINE_STRING_INTERNAL("__mulsc3") /// double __sincospi_stret(double x); TLI_DEFINE_ENUM_INTERNAL(sincospi_stret) TLI_DEFINE_STRING_INTERNAL("__sincospi_stret") @@ -390,6 +393,9 @@ /// char *ctermid(char *s); TLI_DEFINE_ENUM_INTERNAL(ctermid) TLI_DEFINE_STRING_INTERNAL("ctermid") +// void exit(int status); +TLI_DEFINE_ENUM_INTERNAL(exit) +TLI_DEFINE_STRING_INTERNAL("exit") /// double exp(double x); TLI_DEFINE_ENUM_INTERNAL(exp) TLI_DEFINE_STRING_INTERNAL("exp") Index: include/llvm/Bitcode/LLVMBitCodes.h =================================================================== --- include/llvm/Bitcode/LLVMBitCodes.h +++ include/llvm/Bitcode/LLVMBitCodes.h @@ -482,7 +482,9 @@ ATTR_KIND_ARGMEMONLY = 45, ATTR_KIND_SWIFT_SELF = 46, ATTR_KIND_SWIFT_ERROR = 47, - ATTR_KIND_NO_RECURSE = 48 + ATTR_KIND_NO_RECURSE = 48, + ATTR_KIND_ALMOST_READ_NONE = 49, + ATTR_KIND_ALMOST_ARGMEM_ONLY = 50, }; enum ComdatSelectionKindCodes { Index: include/llvm/IR/Attributes.td =================================================================== --- include/llvm/IR/Attributes.td +++ include/llvm/IR/Attributes.td @@ -16,6 +16,18 @@ /// 0 means unaligned (different from align(1)). def Alignment : EnumAttr<"align">; +/// Function might access globals, but none of these globals can alias with +/// any memory location accessible from the IR being optimized (example - +/// internal states of libraries). Function does not access any memory +/// that is accessible from the IR. +def AlmostReadNone : EnumAttr<"almostreadnone">; + +/// Function might access globals, but none of these globals can alias with +/// any memory location accessible from the IR being optimized (example - +/// internal states of libraries). It may access memory pointed to by +/// its arguments. +def AlmostArgMemOnly : EnumAttr<"almostargmemonly">; + /// inline=always. def AlwaysInline : EnumAttr<"alwaysinline">; Index: include/llvm/IR/Function.h =================================================================== --- include/llvm/IR/Function.h +++ include/llvm/IR/Function.h @@ -293,6 +293,22 @@ } void setOnlyAccessesArgMemory() { addFnAttr(Attribute::ArgMemOnly); } + /// @brief Determine if the function may read only non IR visible globals, + /// and does not access any IR visible globals. + bool isAlmostReadNone() const { + return AttributeSets.hasAttribute(AttributeSet::FunctionIndex, + Attribute::AlmostReadNone); + } + void setAlmostReadNone() { addFnAttr(Attribute::AlmostReadNone); } + + /// @brief Determine if the function may read only non IR visible globals, + /// or only memory pointed to by pointer arguments. + bool isAlmostArgMemOnly() const { + return AttributeSets.hasAttribute(AttributeSet::FunctionIndex, + Attribute::AlmostArgMemOnly); + } + void setAlmostArgMemOnly() { addFnAttr(Attribute::AlmostArgMemOnly); } + /// @brief Determine if the function cannot return. bool doesNotReturn() const { return AttributeSets.hasAttribute(AttributeSet::FunctionIndex, Index: lib/Analysis/GlobalsModRef.cpp =================================================================== --- lib/Analysis/GlobalsModRef.cpp +++ lib/Analysis/GlobalsModRef.cpp @@ -507,7 +507,8 @@ if (F->isDeclaration()) { // Try to get mod/ref behaviour from function attributes. - if (F->doesNotAccessMemory()) { + if (F->doesNotAccessMemory() || F->isAlmostReadNone() || + F->onlyAccessesArgMemory() || F->isAlmostArgMemOnly()) { // Can't do better than that! } else if (F->onlyReadsMemory()) { FI.addModRefInfo(MRI_Ref); Index: lib/Bitcode/Writer/BitcodeWriter.cpp =================================================================== --- lib/Bitcode/Writer/BitcodeWriter.cpp +++ lib/Bitcode/Writer/BitcodeWriter.cpp @@ -164,6 +164,10 @@ switch (Kind) { case Attribute::Alignment: return bitc::ATTR_KIND_ALIGNMENT; + case Attribute::AlmostReadNone: + return bitc::ATTR_KIND_ALMOST_READ_NONE; + case Attribute::AlmostArgMemOnly: + return bitc::ATTR_KIND_ALMOST_ARGMEM_ONLY; case Attribute::AlwaysInline: return bitc::ATTR_KIND_ALWAYS_INLINE; case Attribute::ArgMemOnly: Index: lib/IR/Attributes.cpp =================================================================== --- lib/IR/Attributes.cpp +++ lib/IR/Attributes.cpp @@ -445,6 +445,8 @@ case Attribute::Convergent: return 1ULL << 46; case Attribute::SafeStack: return 1ULL << 47; case Attribute::NoRecurse: return 1ULL << 48; + case Attribute::AlmostReadNone: return 1ULL << 49; + case Attribute::AlmostArgMemOnly: return 1ULL << 50; case Attribute::Dereferenceable: llvm_unreachable("dereferenceable attribute not supported in raw format"); break; Index: lib/Transforms/IPO/FunctionAttrs.cpp =================================================================== --- lib/Transforms/IPO/FunctionAttrs.cpp +++ lib/Transforms/IPO/FunctionAttrs.cpp @@ -77,7 +77,7 @@ return false; } bool doFinalization(CallGraph &CG) override; - + void getAnalysisUsage(AnalysisUsage &AU) const override { AU.setPreservesCFG(); AU.addRequired(); @@ -963,6 +963,20 @@ } } +static void setAlmostReadNone(Function &F) { + if (!F.isAlmostReadNone()) { + F.setAlmostReadNone(); + ++NumAnnotated; + } +} + +static void setAlmostArgMemOnly(Function &F) { + if (!F.isAlmostArgMemOnly()) { + F.setAlmostArgMemOnly(); + ++NumAnnotated; + } +} + static void setDoesNotThrow(Function &F) { if (!F.doesNotThrow()) { F.setDoesNotThrow(); @@ -1176,6 +1190,7 @@ return false; setDoesNotThrow(F); setDoesNotAlias(F, 0); + setAlmostReadNone(F); break; case LibFunc::memcmp: if (FTy->getNumParams() != 3 || !FTy->getParamType(0)->isPointerTy() || @@ -1235,6 +1250,7 @@ setDoesNotThrow(F); setDoesNotAlias(F, 0); setDoesNotCapture(F, 1); + setAlmostArgMemOnly(F); break; case LibFunc::read: if (FTy->getNumParams() != 3 || !FTy->getParamType(1)->isPointerTy()) @@ -1312,6 +1328,7 @@ return false; setDoesNotThrow(F); setDoesNotAlias(F, 0); + setAlmostReadNone(F); break; case LibFunc::chmod: case LibFunc::chown: @@ -1385,6 +1402,10 @@ return false; setDoesNotThrow(F); setDoesNotCapture(F, 1); + if (TheLibFunc == LibFunc::free) { + // TODO: Perhaps others can be set too. + setAlmostArgMemOnly(F); + } break; case LibFunc::ferror: if (FTy->getNumParams() != 1 || !FTy->getParamType(0)->isPointerTy()) @@ -1445,6 +1466,7 @@ setDoesNotCapture(F, 1); setDoesNotCapture(F, 2); setOnlyReadsMemory(F, 2); + setAlmostArgMemOnly(F); break; case LibFunc::fgetpos: if (FTy->getNumParams() < 2 || !FTy->getParamType(0)->isPointerTy() || @@ -1537,6 +1559,7 @@ setDoesNotThrow(F); setDoesNotCapture(F, 1); setOnlyReadsMemory(F, 1); + setAlmostArgMemOnly(F); break; case LibFunc::pread: if (FTy->getNumParams() != 4 || !FTy->getParamType(1)->isPointerTy()) @@ -1794,6 +1817,18 @@ setDoesNotCapture(F, 1); setDoesNotCapture(F, 2); break; + case LibFunc::sin: + case LibFunc::cos: + case LibFunc::pow: + case LibFunc::sqrt: + case LibFunc::log: + case LibFunc::mulsc3: + setDoesNotThrow(F); + setDoesNotAccessMemory(F); + break; + case LibFunc::exit: + setDoesNotAccessMemory(F); + break; default: // Didn't mark any attributes. return false; @@ -1853,6 +1888,8 @@ static Attribute::AttrKind parseAttrKind(StringRef Kind) { return StringSwitch(Kind) + .Case("almostreadnone", Attribute::AlmostReadNone) + .Case("almostargmemonly", Attribute::AlmostArgMemOnly) .Case("alwaysinline", Attribute::AlwaysInline) .Case("builtin", Attribute::Builtin) .Case("cold", Attribute::Cold) @@ -1957,7 +1994,7 @@ Changed |= addNoAliasAttrs(SCCNodes); Changed |= addNonNullAttrs(SCCNodes, *TLI); } - + Changed |= addNoRecurseAttrs(SCC, Revisit); return Changed; }