[llvm] r365830 - [Attributor] Deduce "nosync" function attribute.

Stefan Stipanovic via llvm-commits llvm-commits at lists.llvm.org
Thu Jul 11 14:37:40 PDT 2019


Author: sstefan
Date: Thu Jul 11 14:37:40 2019
New Revision: 365830

URL: http://llvm.org/viewvc/llvm-project?rev=365830&view=rev
Log:
[Attributor] Deduce "nosync" function attribute.

Introduce and deduce "nosync" function attribute to indicate that a function
does not synchronize with another thread in a way that other thread might free memory.

Reviewers: jdoerfert, jfb, nhaehnle, arsenm

Subscribers: wdng, hfinkel, nhaenhle, mehdi_amini, steven_wu,
dexonsmith, arsenm, uenoku, hiraditya, jfb, llvm-commits

Differential Revision: https://reviews.llvm.org/D62766

Added:
    llvm/trunk/test/Transforms/FunctionAttrs/nosync.ll
Modified:
    llvm/trunk/docs/LangRef.rst
    llvm/trunk/include/llvm/Bitcode/LLVMBitCodes.h
    llvm/trunk/include/llvm/IR/Attributes.td
    llvm/trunk/include/llvm/Transforms/IPO/Attributor.h
    llvm/trunk/lib/AsmParser/LLLexer.cpp
    llvm/trunk/lib/AsmParser/LLParser.cpp
    llvm/trunk/lib/AsmParser/LLToken.h
    llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp
    llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp
    llvm/trunk/lib/IR/Attributes.cpp
    llvm/trunk/lib/IR/Verifier.cpp
    llvm/trunk/lib/Transforms/IPO/Attributor.cpp
    llvm/trunk/lib/Transforms/Utils/CodeExtractor.cpp
    llvm/trunk/test/Bitcode/attributes.ll
    llvm/trunk/test/Transforms/FunctionAttrs/arg_returned.ll
    llvm/trunk/test/Transforms/FunctionAttrs/fn_noreturn.ll
    llvm/trunk/test/Transforms/FunctionAttrs/nounwind.ll
    llvm/trunk/test/Transforms/FunctionAttrs/read_write_returned_arguments_scc.ll

Modified: llvm/trunk/docs/LangRef.rst
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/docs/LangRef.rst?rev=365830&r1=365829&r2=365830&view=diff
==============================================================================
--- llvm/trunk/docs/LangRef.rst (original)
+++ llvm/trunk/docs/LangRef.rst Thu Jul 11 14:37:40 2019
@@ -1493,6 +1493,16 @@ example:
     Annotated functions may still raise an exception, i.a., ``nounwind`` is not implied.
     If an invocation of an annotated function does not return control back
     to a point in the call stack, the behavior is undefined.
+``nosync``
+    This function attribute indicates that the function does not communicate
+    (synchronize) with another thread through memory or other well-defined means.
+    Synchronization is considered possible in the presence of `atomic` accesses
+    that enforce an order, thus not "unordered" and "monotonic", `volatile` accesses,
+    as well as `convergent` function calls. Note that through `convergent` function calls
+    non-memory communication, e.g., cross-lane operations, are possible and are also
+    considered synchronization. However `convergent` does not contradict `nosync`.
+    If an annotated function does ever synchronize with another thread,
+    the behavior is undefined.
 ``nounwind``
     This function attribute indicates that the function never raises an
     exception. If the function does raise an exception, its runtime

Modified: llvm/trunk/include/llvm/Bitcode/LLVMBitCodes.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Bitcode/LLVMBitCodes.h?rev=365830&r1=365829&r2=365830&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Bitcode/LLVMBitCodes.h (original)
+++ llvm/trunk/include/llvm/Bitcode/LLVMBitCodes.h Thu Jul 11 14:37:40 2019
@@ -629,7 +629,8 @@ enum AttributeKindCodes {
   ATTR_KIND_SPECULATIVE_LOAD_HARDENING = 59,
   ATTR_KIND_IMMARG = 60,
   ATTR_KIND_WILLRETURN = 61,
-  ATTR_KIND_NOFREE = 62
+  ATTR_KIND_NOFREE = 62,
+  ATTR_KIND_NOSYNC = 63
 };
 
 enum ComdatSelectionKindCodes {

Modified: llvm/trunk/include/llvm/IR/Attributes.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/IR/Attributes.td?rev=365830&r1=365829&r2=365830&view=diff
==============================================================================
--- llvm/trunk/include/llvm/IR/Attributes.td (original)
+++ llvm/trunk/include/llvm/IR/Attributes.td Thu Jul 11 14:37:40 2019
@@ -109,6 +109,9 @@ def NoRedZone : EnumAttr<"noredzone">;
 /// Mark the function as not returning.
 def NoReturn : EnumAttr<"noreturn">;
 
+/// Function does not synchronize.
+def NoSync : EnumAttr<"nosync">;
+
 /// Disable Indirect Branch Tracking.
 def NoCfCheck : EnumAttr<"nocf_check">;
 

Modified: llvm/trunk/include/llvm/Transforms/IPO/Attributor.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Transforms/IPO/Attributor.h?rev=365830&r1=365829&r2=365830&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Transforms/IPO/Attributor.h (original)
+++ llvm/trunk/include/llvm/Transforms/IPO/Attributor.h Thu Jul 11 14:37:40 2019
@@ -377,7 +377,7 @@ struct AbstractState {
 /// state will catch up with the assumed one, for a pessimistic fixpoint it is
 /// the other way around.
 struct IntegerState : public AbstractState {
-  /// Undrlying integer type, we assume 32 bits to be enough.
+  /// Underlying integer type, we assume 32 bits to be enough.
   using base_t = uint32_t;
 
   /// Initialize the (best) state.
@@ -664,20 +664,40 @@ struct AAReturnedValues : public Abstrac
 };
 
 struct AANoUnwind : public AbstractAttribute {
-    /// An abstract interface for all nosync attributes.
-    AANoUnwind(Value &V, InformationCache &InfoCache)
-        : AbstractAttribute(V, InfoCache) {}
+  /// An abstract interface for all nosync attributes.
+  AANoUnwind(Value &V, InformationCache &InfoCache)
+      : AbstractAttribute(V, InfoCache) {}
 
-    /// See AbstractAttribute::getAttrKind()/
-    virtual Attribute::AttrKind getAttrKind() const override { return ID; }
+  /// See AbstractAttribute::getAttrKind()/
+  virtual Attribute::AttrKind getAttrKind() const override { return ID; }
+
+  static constexpr Attribute::AttrKind ID = Attribute::NoUnwind;
+
+  /// Returns true if nounwind is assumed.
+  virtual bool isAssumedNoUnwind() const = 0;
+
+  /// Returns true if nounwind is known.
+  virtual bool isKnownNoUnwind() const = 0;
+};
+
+struct AANoSync : public AbstractAttribute {
+  /// An abstract interface for all nosync attributes.
+  AANoSync(Value &V, InformationCache &InfoCache)
+      : AbstractAttribute(V, InfoCache) {}
+
+  /// See AbstractAttribute::getAttrKind().
+  virtual Attribute::AttrKind getAttrKind() const override {
+    return ID;
+  }
 
-    static constexpr Attribute::AttrKind ID = Attribute::NoUnwind;
+  static constexpr Attribute::AttrKind ID =
+      Attribute::AttrKind(Attribute::NoSync);
 
-    /// Returns true if nounwind is assumed.
-    virtual bool isAssumedNoUnwind() const = 0;
+  /// Returns true if "nosync" is assumed.
+  virtual bool isAssumedNoSync() const = 0;
 
-    /// Returns true if nounwind is known.
-    virtual bool isKnownNoUnwind() const = 0;
+  /// Returns true if "nosync" is known.
+  virtual bool isKnownNoSync() const = 0;
 };
 
 } // end namespace llvm

Modified: llvm/trunk/lib/AsmParser/LLLexer.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/AsmParser/LLLexer.cpp?rev=365830&r1=365829&r2=365830&view=diff
==============================================================================
--- llvm/trunk/lib/AsmParser/LLLexer.cpp (original)
+++ llvm/trunk/lib/AsmParser/LLLexer.cpp Thu Jul 11 14:37:40 2019
@@ -658,6 +658,7 @@ lltok::Kind LLLexer::LexIdentifier() {
   KEYWORD(nonnull);
   KEYWORD(noredzone);
   KEYWORD(noreturn);
+  KEYWORD(nosync);
   KEYWORD(nocf_check);
   KEYWORD(nounwind);
   KEYWORD(optforfuzzing);

Modified: llvm/trunk/lib/AsmParser/LLParser.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/AsmParser/LLParser.cpp?rev=365830&r1=365829&r2=365830&view=diff
==============================================================================
--- llvm/trunk/lib/AsmParser/LLParser.cpp (original)
+++ llvm/trunk/lib/AsmParser/LLParser.cpp Thu Jul 11 14:37:40 2019
@@ -1287,6 +1287,7 @@ bool LLParser::ParseFnAttributeValuePair
     case lltok::kw_nonlazybind: B.addAttribute(Attribute::NonLazyBind); break;
     case lltok::kw_noredzone: B.addAttribute(Attribute::NoRedZone); break;
     case lltok::kw_noreturn: B.addAttribute(Attribute::NoReturn); break;
+    case lltok::kw_nosync: B.addAttribute(Attribute::NoSync); break;
     case lltok::kw_nocf_check: B.addAttribute(Attribute::NoCfCheck); break;
     case lltok::kw_norecurse: B.addAttribute(Attribute::NoRecurse); break;
     case lltok::kw_nounwind: B.addAttribute(Attribute::NoUnwind); break;

Modified: llvm/trunk/lib/AsmParser/LLToken.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/AsmParser/LLToken.h?rev=365830&r1=365829&r2=365830&view=diff
==============================================================================
--- llvm/trunk/lib/AsmParser/LLToken.h (original)
+++ llvm/trunk/lib/AsmParser/LLToken.h Thu Jul 11 14:37:40 2019
@@ -203,6 +203,7 @@ enum Kind {
   kw_nonnull,
   kw_noredzone,
   kw_noreturn,
+  kw_nosync,
   kw_nocf_check,
   kw_nounwind,
   kw_optforfuzzing,

Modified: llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp?rev=365830&r1=365829&r2=365830&view=diff
==============================================================================
--- llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp (original)
+++ llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp Thu Jul 11 14:37:40 2019
@@ -1280,6 +1280,9 @@ static uint64_t getRawAttributeMask(Attr
     return 1ULL << 62;
   case Attribute::NoFree:
     return 1ULL << 63;
+  case Attribute::NoSync:
+    llvm_unreachable("nosync attribute not supported in raw format");
+    break;
   case Attribute::Dereferenceable:
     llvm_unreachable("dereferenceable attribute not supported in raw format");
     break;
@@ -1305,7 +1308,8 @@ static void addRawAttributeValue(AttrBui
     if (I == Attribute::Dereferenceable ||
         I == Attribute::DereferenceableOrNull ||
         I == Attribute::ArgMemOnly ||
-        I == Attribute::AllocSize)
+        I == Attribute::AllocSize ||
+        I == Attribute::NoSync)
       continue;
     if (uint64_t A = (Val & getRawAttributeMask(I))) {
       if (I == Attribute::Alignment)
@@ -1466,6 +1470,8 @@ static Attribute::AttrKind getAttrFromCo
     return Attribute::NoRedZone;
   case bitc::ATTR_KIND_NO_RETURN:
     return Attribute::NoReturn;
+  case bitc::ATTR_KIND_NOSYNC:
+    return Attribute::NoSync;
   case bitc::ATTR_KIND_NOCF_CHECK:
     return Attribute::NoCfCheck;
   case bitc::ATTR_KIND_NO_UNWIND:

Modified: llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp?rev=365830&r1=365829&r2=365830&view=diff
==============================================================================
--- llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp (original)
+++ llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp Thu Jul 11 14:37:40 2019
@@ -659,6 +659,8 @@ static uint64_t getAttrKindEncoding(Attr
     return bitc::ATTR_KIND_NO_RED_ZONE;
   case Attribute::NoReturn:
     return bitc::ATTR_KIND_NO_RETURN;
+  case Attribute::NoSync:
+    return bitc::ATTR_KIND_NOSYNC;
   case Attribute::NoCfCheck:
     return bitc::ATTR_KIND_NOCF_CHECK;
   case Attribute::NoUnwind:

Modified: llvm/trunk/lib/IR/Attributes.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/IR/Attributes.cpp?rev=365830&r1=365829&r2=365830&view=diff
==============================================================================
--- llvm/trunk/lib/IR/Attributes.cpp (original)
+++ llvm/trunk/lib/IR/Attributes.cpp Thu Jul 11 14:37:40 2019
@@ -335,6 +335,8 @@ std::string Attribute::getAsString(bool
     return "noredzone";
   if (hasAttribute(Attribute::NoReturn))
     return "noreturn";
+  if (hasAttribute(Attribute::NoSync))
+    return "nosync";
   if (hasAttribute(Attribute::WillReturn))
     return "willreturn";
   if (hasAttribute(Attribute::NoCfCheck))

Modified: llvm/trunk/lib/IR/Verifier.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/IR/Verifier.cpp?rev=365830&r1=365829&r2=365830&view=diff
==============================================================================
--- llvm/trunk/lib/IR/Verifier.cpp (original)
+++ llvm/trunk/lib/IR/Verifier.cpp Thu Jul 11 14:37:40 2019
@@ -1493,6 +1493,7 @@ void Verifier::visitModuleFlagCGProfileE
 static bool isFuncOnlyAttr(Attribute::AttrKind Kind) {
   switch (Kind) {
   case Attribute::NoReturn:
+  case Attribute::NoSync:
   case Attribute::WillReturn:
   case Attribute::NoCfCheck:
   case Attribute::NoUnwind:

Modified: llvm/trunk/lib/Transforms/IPO/Attributor.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/IPO/Attributor.cpp?rev=365830&r1=365829&r2=365830&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/IPO/Attributor.cpp (original)
+++ llvm/trunk/lib/Transforms/IPO/Attributor.cpp Thu Jul 11 14:37:40 2019
@@ -23,6 +23,7 @@
 #include "llvm/IR/Argument.h"
 #include "llvm/IR/Attributes.h"
 #include "llvm/IR/InstIterator.h"
+#include "llvm/IR/IntrinsicInst.h"
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/raw_ostream.h"
@@ -48,6 +49,7 @@ STATISTIC(NumFnUniqueReturned, "Number o
 STATISTIC(NumFnKnownReturns, "Number of function with known return values");
 STATISTIC(NumFnArgumentReturned,
           "Number of function arguments marked returned");
+STATISTIC(NumFnNoSync, "Number of functions marked nosync");
 
 // TODO: Determine a good default value.
 //
@@ -99,6 +101,9 @@ static void bookkeeping(AbstractAttribut
   case Attribute::Returned:
     NumFnArgumentReturned++;
     return;
+  case Attribute::NoSync:
+    NumFnNoSync++;
+    break;
   default:
     return;
   }
@@ -719,6 +724,191 @@ ChangeStatus AAReturnedValuesImpl::updat
   return Changed;
 }
 
+/// ------------------------ NoSync Function Attribute -------------------------
+
+struct AANoSyncFunction : AANoSync, BooleanState {
+
+  AANoSyncFunction(Function &F, InformationCache &InfoCache)
+      : AANoSync(F, InfoCache) {}
+
+  /// See AbstractAttribute::getState()
+  /// {
+  AbstractState &getState() override { return *this; }
+  const AbstractState &getState() const override { return *this; }
+  /// }
+
+  /// See AbstractAttribute::getManifestPosition().
+  virtual ManifestPosition getManifestPosition() const override {
+    return MP_FUNCTION;
+  }
+
+  virtual const std::string getAsStr() const override {
+    return getAssumed() ? "nosync" : "may-sync";
+  }
+
+  /// See AbstractAttribute::updateImpl(...).
+  virtual ChangeStatus updateImpl(Attributor &A) override;
+
+  /// See AANoSync::isAssumedNoSync()
+  virtual bool isAssumedNoSync() const override { return getAssumed(); }
+
+  /// See AANoSync::isKnownNoSync()
+  virtual bool isKnownNoSync() const override { return getKnown(); }
+
+  /// Helper function used to determine whether an instruction is non-relaxed
+  /// atomic. In other words, if an atomic instruction does not have unordered
+  /// or monotonic ordering
+  static bool isNonRelaxedAtomic(Instruction *I);
+
+  /// Helper function used to determine whether an instruction is volatile.
+  static bool isVolatile(Instruction *I);
+
+  /// Helper function uset to check if intrinsic is volatile (memcpy, memmove, memset).
+  static bool isNoSyncIntrinsic(Instruction *I);
+};
+
+bool AANoSyncFunction::isNonRelaxedAtomic(Instruction *I) {
+  if (!I->isAtomic())
+    return false;
+
+  AtomicOrdering Ordering;
+  switch (I->getOpcode()) {
+  case Instruction::AtomicRMW:
+    Ordering = cast<AtomicRMWInst>(I)->getOrdering();
+    break;
+  case Instruction::Store:
+    Ordering = cast<StoreInst>(I)->getOrdering();
+    break;
+  case Instruction::Load:
+    Ordering = cast<LoadInst>(I)->getOrdering();
+    break;
+  case Instruction::Fence: {
+    auto *FI = cast<FenceInst>(I);
+    if (FI->getSyncScopeID() == SyncScope::SingleThread)
+      return false;
+    Ordering = FI->getOrdering();
+    break;
+  }
+  case Instruction::AtomicCmpXchg: {
+    AtomicOrdering Success = cast<AtomicCmpXchgInst>(I)->getSuccessOrdering();
+    AtomicOrdering Failure = cast<AtomicCmpXchgInst>(I)->getFailureOrdering();
+    // Only if both are relaxed, than it can be treated as relaxed.
+    // Otherwise it is non-relaxed.
+    if (Success != AtomicOrdering::Unordered &&
+        Success != AtomicOrdering::Monotonic)
+      return true;
+    if (Failure != AtomicOrdering::Unordered &&
+        Failure != AtomicOrdering::Monotonic)
+      return true;
+    return false;
+  }
+  default:
+    llvm_unreachable(
+        "New atomic operations need to be known in the attributor.");
+  }
+
+  // Relaxed.
+  if (Ordering == AtomicOrdering::Unordered ||
+      Ordering == AtomicOrdering::Monotonic)
+    return false;
+  return true;
+}
+
+/// Checks if an intrinsic is nosync. Currently only checks mem* intrinsics.
+/// FIXME: We should ipmrove the handling of intrinsics.
+bool AANoSyncFunction::isNoSyncIntrinsic(Instruction *I) {
+  if (auto *II = dyn_cast<IntrinsicInst>(I)) {
+    switch (II->getIntrinsicID()) {
+    /// Element wise atomic memory intrinsics are can only be unordered,
+    /// therefore nosync.
+    case Intrinsic::memset_element_unordered_atomic:
+    case Intrinsic::memmove_element_unordered_atomic:
+    case Intrinsic::memcpy_element_unordered_atomic:
+      return true;
+    case Intrinsic::memset:
+    case Intrinsic::memmove:
+    case Intrinsic::memcpy:
+      if (!cast<MemIntrinsic>(II)->isVolatile())
+        return true;
+      return false;
+    default:
+      return false;
+    }
+  }
+  return false;
+}
+
+bool AANoSyncFunction::isVolatile(Instruction *I) {
+  assert(!ImmutableCallSite(I) && !isa<CallBase>(I) &&
+         "Calls should not be checked here");
+
+  switch (I->getOpcode()) {
+  case Instruction::AtomicRMW:
+    return cast<AtomicRMWInst>(I)->isVolatile();
+  case Instruction::Store:
+    return cast<StoreInst>(I)->isVolatile();
+  case Instruction::Load:
+    return cast<LoadInst>(I)->isVolatile();
+  case Instruction::AtomicCmpXchg:
+    return cast<AtomicCmpXchgInst>(I)->isVolatile();
+  default:
+    return false;
+  }
+}
+
+ChangeStatus AANoSyncFunction::updateImpl(Attributor &A) {
+  Function &F = getAnchorScope();
+
+  /// We are looking for volatile instructions or Non-Relaxed atomics.
+  /// FIXME: We should ipmrove the handling of intrinsics.
+  for (Instruction *I : InfoCache.getReadOrWriteInstsForFunction(F)) {
+    ImmutableCallSite ICS(I);
+    auto *NoSyncAA = A.getAAFor<AANoSyncFunction>(*this, *I);
+
+    if (isa<IntrinsicInst>(I) && isNoSyncIntrinsic(I))
+        continue;
+
+    if (ICS && (!NoSyncAA || !NoSyncAA->isAssumedNoSync()) &&
+        !ICS.hasFnAttr(Attribute::NoSync)) {
+      indicatePessimisticFixpoint();
+      return ChangeStatus::CHANGED;
+    }
+
+    if(ICS)
+      continue;
+
+    if (!isVolatile(I) && !isNonRelaxedAtomic(I))
+      continue;
+
+    indicatePessimisticFixpoint();
+    return ChangeStatus::CHANGED;
+  }
+
+  auto &OpcodeInstMap = InfoCache.getOpcodeInstMapForFunction(F);
+  auto Opcodes = {(unsigned)Instruction::Invoke, (unsigned)Instruction::CallBr,
+                  (unsigned)Instruction::Call};
+
+  for (unsigned Opcode : Opcodes) {
+    for (Instruction *I : OpcodeInstMap[Opcode]) {
+      // At this point we handled all read/write effects and they are all
+      // nosync, so they can be skipped.
+      if (I->mayReadOrWriteMemory())
+        continue;
+
+      ImmutableCallSite ICS(I);
+
+      // non-convergent and readnone imply nosync.
+      if (!ICS.isConvergent())
+        continue;
+
+      indicatePessimisticFixpoint();
+      return ChangeStatus::CHANGED;
+    }
+  }
+
+  return ChangeStatus::UNCHANGED;
+}
+
 /// ----------------------------------------------------------------------------
 ///                               Attributor
 /// ----------------------------------------------------------------------------
@@ -864,6 +1054,9 @@ void Attributor::identifyDefaultAbstract
   // Every function can be nounwind.
   registerAA(*new AANoUnwindFunction(F, InfoCache));
 
+  // Every function might be marked "nosync"
+  registerAA(*new AANoSyncFunction(F, InfoCache));
+
   // Return attributes are only appropriate if the return type is non void.
   Type *ReturnType = F.getReturnType();
   if (!ReturnType->isVoidTy()) {

Modified: llvm/trunk/lib/Transforms/Utils/CodeExtractor.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Utils/CodeExtractor.cpp?rev=365830&r1=365829&r2=365830&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/Utils/CodeExtractor.cpp (original)
+++ llvm/trunk/lib/Transforms/Utils/CodeExtractor.cpp Thu Jul 11 14:37:40 2019
@@ -809,6 +809,7 @@ Function *CodeExtractor::constructFuncti
       case Attribute::NoBuiltin:
       case Attribute::NoCapture:
       case Attribute::NoReturn:
+      case Attribute::NoSync:
       case Attribute::None:
       case Attribute::NonNull:
       case Attribute::ReadNone:

Modified: llvm/trunk/test/Bitcode/attributes.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Bitcode/attributes.ll?rev=365830&r1=365829&r2=365830&view=diff
==============================================================================
--- llvm/trunk/test/Bitcode/attributes.ll (original)
+++ llvm/trunk/test/Bitcode/attributes.ll Thu Jul 11 14:37:40 2019
@@ -203,8 +203,8 @@ declare void @nobuiltin()
 define void @f34()
 ; CHECK: define void @f34()
 {
-        call void @nobuiltin() nobuiltin
-; CHECK: call void @nobuiltin() #38
+  call void @nobuiltin() nobuiltin
+; CHECK: call void @nobuiltin() #39
         ret void;
 }
 
@@ -362,6 +362,12 @@ define void @f61() nofree {
   ret void
 }
 
+; CHECK: define void @f62() #38
+define void @f62() nosync
+{
+  ret void
+}
+
 ; CHECK: attributes #0 = { noreturn }
 ; CHECK: attributes #1 = { nounwind }
 ; CHECK: attributes #2 = { readnone }
@@ -400,4 +406,5 @@ define void @f61() nofree {
 ; CHECK: attributes #35 = { shadowcallstack }
 ; CHECK: attributes #36 = { willreturn }
 ; CHECK: attributes #37 = { nofree }
-; CHECK: attributes #38 = { nobuiltin }
+; CHECK: attributes #38 = { nosync }
+; CHECK: attributes #39 = { nobuiltin }

Modified: llvm/trunk/test/Transforms/FunctionAttrs/arg_returned.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/FunctionAttrs/arg_returned.ll?rev=365830&r1=365829&r2=365830&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/FunctionAttrs/arg_returned.ll (original)
+++ llvm/trunk/test/Transforms/FunctionAttrs/arg_returned.ll Thu Jul 11 14:37:40 2019
@@ -8,13 +8,13 @@
 
 ; TEST SCC test returning an integer value argument
 ;
-; BOTH: Function Attrs: noinline norecurse nounwind readnone uwtable
+; BOTH: Function Attrs: noinline norecurse nosync nounwind readnone uwtable
 ; BOTH-NEXT: define i32 @sink_r0(i32 returned %r)
-; BOTH: Function Attrs: noinline nounwind readnone uwtable
+; BOTH: Function Attrs: noinline nosync nounwind readnone uwtable
 ; BOTH-NEXT: define i32 @scc_r1(i32 %a, i32 returned %r, i32 %b)
-; BOTH: Function Attrs: noinline nounwind readnone uwtable
+; BOTH: Function Attrs: noinline nosync nounwind readnone uwtable
 ; BOTH-NEXT: define i32 @scc_r2(i32 %a, i32 %b, i32 returned %r)
-; BOTH: Function Attrs: noinline nounwind readnone uwtable
+; BOTH: Function Attrs: noinline nosync nounwind readnone uwtable
 ; BOTH-NEXT: define i32 @scc_rX(i32 %a, i32 %b, i32 %r)
 ;
 ; FNATTR: define i32 @sink_r0(i32 returned %r)
@@ -159,20 +159,23 @@ return:
 
 ; TEST SCC test returning a pointer value argument
 ;
-; BOTH: Function Attrs: noinline norecurse nounwind readnone uwtable
+; BOTH: Function Attrs: noinline norecurse nosync nounwind readnone uwtable
 ; BOTH-NEXT: define double* @ptr_sink_r0(double* readnone returned %r)
-; BOTH: Function Attrs: noinline nounwind readnone uwtable
+; BOTH: Function Attrs: noinline nosync nounwind readnone uwtable
 ; BOTH-NEXT: define double* @ptr_scc_r1(double* %a, double* readnone returned %r, double* nocapture readnone %b)
-; BOTH: Function Attrs: noinline nounwind readnone uwtable
+; BOTH: Function Attrs: noinline nosync nounwind readnone uwtable
 ; BOTH-NEXT: define double* @ptr_scc_r2(double* readnone %a, double* readnone %b, double* readnone returned %r)
 ;
 ; FNATTR: define double* @ptr_sink_r0(double* readnone returned %r)
 ; FNATTR: define double* @ptr_scc_r1(double* %a, double* readnone %r, double* nocapture readnone %b)
 ; FNATTR: define double* @ptr_scc_r2(double* readnone %a, double* readnone %b, double* readnone %r)
 ;
-; ATTRIBUTOR: define double* @ptr_sink_r0(double* returned %r)
-; ATTRIBUTOR: define double* @ptr_scc_r1(double* %a, double* returned %r, double* %b)
-; ATTRIBUTOR: define double* @ptr_scc_r2(double* %a, double* %b, double* returned %r)
+; ATTRIBUTOR: Function Attrs: noinline nosync nounwind uwtable
+; ATTRIBUTOR-NEXT: define double* @ptr_sink_r0(double* returned %r)
+; ATTRIBUTOR: Function Attrs: noinline nosync nounwind uwtable
+; ATTRIBUTOR-NEXT: define double* @ptr_scc_r1(double* %a, double* returned %r, double* %b)
+; ATTRIBUTOR: Function Attrs: noinline nosync nounwind uwtable
+; ATTRIBUTOR-NEXT: define double* @ptr_scc_r2(double* %a, double* %b, double* returned %r)
 ;
 ; double* ptr_scc_r1(double* a, double* b, double* r);
 ; double* ptr_scc_r2(double* a, double* b, double* r);
@@ -258,7 +261,7 @@ return:
 ;
 ; FIXME: no-return missing
 ; FNATTR:  define i32* @rt0(i32* readonly %a)
-; BOTH: Function Attrs: noinline nounwind readonly uwtable
+; BOTH: Function Attrs: noinline nosync nounwind readonly uwtable
 ; BOTH-NEXT:    define i32* @rt0(i32* readonly returned %a)
 define i32* @rt0(i32* %a) #0 {
 entry:
@@ -277,7 +280,7 @@ entry:
 ;
 ; FIXME: no-return missing
 ; FNATTR:  define noalias i32* @rt1(i32* nocapture readonly %a)
-; BOTH: Function Attrs: noinline nounwind readonly uwtable
+; BOTH: Function Attrs: noinline nosync nounwind readonly uwtable
 ; BOTH-NEXT:    define noalias i32* @rt1(i32* nocapture readonly %a)
 define i32* @rt1(i32* %a) #0 {
 entry:
@@ -438,11 +441,12 @@ entry:
 ;   return b == 0? b : x;
 ; }
 ;
-; BOTH: Function Attrs: noinline norecurse nounwind readnone uwtable
+; BOTH: Function Attrs: noinline norecurse nosync nounwind readnone uwtable
 ; BOTH-NEXT: define double @select_and_phi(double returned %b)
 ;
 ; FNATTR:     define double @select_and_phi(double %b)
-; ATTRIBUTOR: define double @select_and_phi(double returned %b)
+; ATTRIBUTOR: Function Attrs: noinline nosync nounwind uwtable
+; ATTRIBUTOR-NEXT: define double @select_and_phi(double returned %b)
 define double @select_and_phi(double %b) #0 {
 entry:
   %cmp = fcmp ogt double %b, 0.000000e+00
@@ -468,11 +472,13 @@ if.end:
 ;   return b == 0? b : x;
 ; }
 ;
-; BOTH: Function Attrs: noinline nounwind readnone uwtable
+; BOTH: Function Attrs: noinline nosync nounwind readnone uwtable
 ; BOTH-NEXT: define double @recursion_select_and_phi(i32 %a, double returned %b)
 ;
 ; FNATTR:     define double @recursion_select_and_phi(i32 %a, double %b)
-; ATTRIBUTOR: define double @recursion_select_and_phi(i32 %a, double returned %b)
+;
+; ATTRIBUTOR: Function Attrs: noinline nosync nounwind uwtable
+; ATTRIBUTOR-NEXT: define double @recursion_select_and_phi(i32 %a, double returned %b)
 define double @recursion_select_and_phi(i32 %a, double %b) #0 {
 entry:
   %dec = add nsw i32 %a, -1
@@ -497,11 +503,13 @@ if.end:
 ;   return (double*)b;
 ; }
 ;
-; BOTH: Function Attrs: noinline norecurse nounwind readnone uwtable
+; BOTH: Function Attrs: noinline norecurse nosync nounwind readnone uwtable
 ; BOTH-NEXT:  define double* @bitcast(i32* readnone returned %b)
 ;
 ; FNATTR:     define double* @bitcast(i32* readnone %b)
-; ATTRIBUTOR: define double* @bitcast(i32* returned %b)
+;
+; ATTRIBUTOR: Function Attrs: noinline nosync nounwind uwtable
+; ATTRIBUTOR-NEXT: define double* @bitcast(i32* returned %b)
 define double* @bitcast(i32* %b) #0 {
 entry:
   %bc0 = bitcast i32* %b to double*
@@ -518,11 +526,13 @@ entry:
 ;   return b != 0 ? b : x;
 ; }
 ;
-; BOTH: Function Attrs: noinline norecurse nounwind readnone uwtable
+; BOTH: Function Attrs: noinline norecurse nosync nounwind readnone uwtable
 ; BOTH-NEXT: define double* @bitcasts_select_and_phi(i32* readnone returned %b)
 ;
 ; FNATTR:     define double* @bitcasts_select_and_phi(i32* readnone %b)
-; ATTRIBUTOR: define double* @bitcasts_select_and_phi(i32* returned %b)
+;
+; ATTRIBUTOR: Function Attrs: noinline nosync nounwind uwtable
+; ATTRIBUTOR-NEXT: define double* @bitcasts_select_and_phi(i32* returned %b)
 define double* @bitcasts_select_and_phi(i32* %b) #0 {
 entry:
   %bc0 = bitcast i32* %b to double*
@@ -554,11 +564,13 @@ if.end:
 ;   /* return undef */
 ; }
 ;
-; BOTH: Function Attrs: noinline norecurse nounwind readnone uwtable
+; BOTH: Function Attrs: noinline norecurse nosync nounwind readnone uwtable
 ; BOTH-NEXT:  define double* @ret_arg_arg_undef(i32* readnone returned %b)
 ;
 ; FNATTR:     define double* @ret_arg_arg_undef(i32* readnone %b)
-; ATTRIBUTOR: define double* @ret_arg_arg_undef(i32* returned %b)
+;
+; ATTRIBUTOR: Function Attrs: noinline nosync nounwind uwtable
+; ATTRIBUTOR-NEXT: define double* @ret_arg_arg_undef(i32* returned %b)
 define double* @ret_arg_arg_undef(i32* %b) #0 {
 entry:
   %bc0 = bitcast i32* %b to double*
@@ -590,11 +602,13 @@ ret_undef:
 ;   /* return undef */
 ; }
 ;
-; BOTH: Function Attrs: noinline norecurse nounwind readnone uwtable
+; BOTH: Function Attrs: noinline norecurse nosync nounwind readnone uwtable
 ; BOTH-NEXT:  define double* @ret_undef_arg_arg(i32* readnone returned %b)
 ;
 ; FNATTR:     define double* @ret_undef_arg_arg(i32* readnone %b)
-; ATTRIBUTOR: define double* @ret_undef_arg_arg(i32* returned %b)
+;
+; ATTRIBUTOR: Function Attrs: noinline nosync nounwind uwtable
+; ATTRIBUTOR-NEXT: define double* @ret_undef_arg_arg(i32* returned %b)
 define double* @ret_undef_arg_arg(i32* %b) #0 {
 entry:
   %bc0 = bitcast i32* %b to double*
@@ -626,7 +640,7 @@ ret_arg1:
 ;   /* return undef */
 ; }
 ;
-; BOTH: Function Attrs: noinline norecurse nounwind readnone uwtable
+; BOTH: Function Attrs: noinline norecurse nosync nounwind readnone uwtable
 ; BOTH-NEXT:  define double* @ret_undef_arg_undef(i32* readnone returned %b)
 ;
 ; FNATTR:     define double* @ret_undef_arg_undef(i32* readnone %b)
@@ -730,8 +744,8 @@ unreachableblock2:
 attributes #0 = { noinline nounwind uwtable }
 
 ; BOTH-NOT: attributes #
-; BOTH-DAG: attributes #{{[0-9]*}} = { noinline norecurse nounwind readnone uwtable }
-; BOTH-DAG: attributes #{{[0-9]*}} = { noinline nounwind readnone uwtable }
-; BOTH-DAG: attributes #{{[0-9]*}} = { noinline nounwind readonly uwtable }
+; BOTH-DAG: attributes #{{[0-9]*}} = { noinline norecurse nosync nounwind readnone uwtable }
+; BOTH-DAG: attributes #{{[0-9]*}} = { noinline nosync nounwind readnone uwtable }
+; BOTH-DAG: attributes #{{[0-9]*}} = { noinline nosync nounwind readonly uwtable }
 ; BOTH-DAG: attributes #{{[0-9]*}} = { noinline nounwind uwtable }
 ; BOTH-NOT: attributes #

Modified: llvm/trunk/test/Transforms/FunctionAttrs/fn_noreturn.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/FunctionAttrs/fn_noreturn.ll?rev=365830&r1=365829&r2=365830&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/FunctionAttrs/fn_noreturn.ll (original)
+++ llvm/trunk/test/Transforms/FunctionAttrs/fn_noreturn.ll Thu Jul 11 14:37:40 2019
@@ -20,7 +20,7 @@ target datalayout = "e-m:e-i64:64-f80:12
 ; }
 ;
 ; FIXME: no-return missing
-; CHECK: Function Attrs: noinline nounwind readnone uwtable
+; CHECK: Function Attrs: noinline nosync nounwind readnone uwtable
 ; CHECK: define void @srec0()
 ;
 define void @srec0() #0 {
@@ -37,7 +37,7 @@ entry:
 ; }
 ;
 ; FIXME: no-return missing
-; CHECK: Function Attrs: noinline nounwind readnone uwtable
+; CHECK: Function Attrs: noinline nosync nounwind readnone uwtable
 ; CHECK: define i32 @srec16(i32 %a)
 ;
 define i32 @srec16(i32 %a) #0 {
@@ -69,7 +69,7 @@ entry:
 ; }
 ;
 ; FIXME: no-return missing
-; CHECK: Function Attrs: noinline norecurse nounwind readnone uwtable
+; CHECK: Function Attrs: noinline norecurse nosync nounwind readnone uwtable
 ; CHECK: define i32 @endless_loop(i32 %a)
 ;
 define i32 @endless_loop(i32 %a) #0 {
@@ -89,7 +89,7 @@ while.body:
 ; }
 ;
 ; FIXME: no-return missing
-; CHECK: Function Attrs: noinline norecurse nounwind readnone uwtable
+; CHECK: Function Attrs: noinline norecurse nosync nounwind readnone uwtable
 ; CHECK: define i32 @dead_return(i32 returned %a)
 ;
 define i32 @dead_return(i32 %a) #0 {
@@ -111,7 +111,7 @@ return:
 ; }
 ;
 ; FIXME: no-return missing
-; CHECK: Function Attrs: noinline nounwind readnone uwtable
+; CHECK: Function Attrs: noinline nosync nounwind readnone uwtable
 ; CHECK: define i32 @multiple_noreturn_calls(i32 %a)
 ;
 define i32 @multiple_noreturn_calls(i32 %a) #0 {

Added: llvm/trunk/test/Transforms/FunctionAttrs/nosync.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/FunctionAttrs/nosync.ll?rev=365830&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/FunctionAttrs/nosync.ll (added)
+++ llvm/trunk/test/Transforms/FunctionAttrs/nosync.ll Thu Jul 11 14:37:40 2019
@@ -0,0 +1,352 @@
+; RUN: opt -functionattrs -S < %s | FileCheck %s --check-prefix=FNATTR
+; RUN: opt -attributor -attributor-disable=false -S < %s | FileCheck %s --check-prefix=ATTRIBUTOR
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+; Test cases designed for the nosync function attribute.
+; FIXME's are used to indicate problems and missing attributes.
+
+; struct RT {
+;   char A;
+;   int B[10][20];
+;   char C;
+; };
+; struct ST {
+;   int X;
+;   double Y;
+;   struct RT Z;
+; };
+;
+; int *foo(struct ST *s) {
+;   return &s[1].Z.B[5][13];
+; }
+
+; TEST 1
+; non-convergent and readnone implies nosync
+%struct.RT = type { i8, [10 x [20 x i32]], i8 }
+%struct.ST = type { i32, double, %struct.RT }
+
+; FNATTR: Function Attrs: norecurse nounwind optsize readnone ssp uwtable
+; FNATTR-NEXT: define nonnull i32* @foo(%struct.ST* readnone %s)
+; ATTRIBUTOR: Function Attrs: nosync nounwind optsize readnone ssp uwtable
+; ATTRIBUTOR-NEXT: define i32* @foo(%struct.ST* %s)
+define i32* @foo(%struct.ST* %s) nounwind uwtable readnone optsize ssp {
+entry:
+  %arrayidx = getelementptr inbounds %struct.ST, %struct.ST* %s, i64 1, i32 2, i32 1, i64 5, i64 13
+  ret i32* %arrayidx
+}
+
+; TEST 2
+; atomic load with monotonic ordering
+; int load_monotonic(_Atomic int *num) {
+;   int n = atomic_load_explicit(num, memory_order_relaxed);
+;   return n;
+; }
+
+; FNATTR: Function Attrs: nofree norecurse nounwind uwtable
+; FNATTR-NEXT: define i32 @load_monotonic(i32* nocapture readonly)
+; ATTRIBUTOR: Function Attrs: norecurse nosync nounwind uwtable
+; ATTRIBUTOR-NEXT: define i32 @load_monotonic(i32* nocapture readonly)
+define i32 @load_monotonic(i32* nocapture readonly) norecurse nounwind uwtable {
+  %2 = load atomic i32, i32* %0 monotonic, align 4
+  ret i32 %2
+}
+
+
+; TEST 3
+; atomic store with monotonic ordering.
+; void store_monotonic(_Atomic int *num) {
+;   atomic_load_explicit(num, memory_order_relaxed);
+; }
+
+; FNATTR: Function Attrs: nofree norecurse nounwind uwtable
+; FNATTR-NEXT: define void @store_monotonic(i32* nocapture)
+; ATTRIBUTOR: Function Attrs: norecurse nosync nounwind uwtable
+; ATTRIBUTOR-NEXT: define void @store_monotonic(i32* nocapture)
+define void @store_monotonic(i32* nocapture) norecurse nounwind uwtable {
+  store atomic i32 10, i32* %0 monotonic, align 4
+  ret void
+}
+
+; TEST 4 - negative, should not deduce nosync
+; atomic load with acquire ordering.
+; int load_acquire(_Atomic int *num) {
+;   int n = atomic_load_explicit(num, memory_order_acquire);
+;   return n;
+; }
+
+; FNATTR: Function Attrs: nofree norecurse nounwind uwtable
+; FNATTR-NEXT: define i32 @load_acquire(i32* nocapture readonly)
+; ATTRIBUTOR: Function Attrs: norecurse nounwind uwtable
+; ATTRIBUTOR-NOT: nosync
+; ATTRIBUTOR-NEXT: define i32 @load_acquire(i32* nocapture readonly)
+define i32 @load_acquire(i32* nocapture readonly) norecurse nounwind uwtable {
+  %2 = load atomic i32, i32* %0 acquire, align 4
+  ret i32 %2
+}
+
+; TEST 5 - negative, should not deduce nosync
+; atomic load with release ordering
+; void load_release(_Atomic int *num) {
+;   atomic_store_explicit(num, 10, memory_order_release);
+; }
+
+; FNATTR: Function Attrs: nofree norecurse nounwind uwtable
+; FNATTR-NEXT: define void @load_release(i32* nocapture)
+; ATTRIBUTOR: Function Attrs: norecurse nounwind uwtable
+; ATTRIBUTOR-NOT: nosync
+; ATTRIBUTOR-NEXT: define void @load_release(i32* nocapture)
+define void @load_release(i32* nocapture) norecurse nounwind uwtable {
+  store atomic volatile i32 10, i32* %0 release, align 4
+  ret void
+}
+
+; TEST 6 - negative volatile, relaxed atomic
+
+; FNATTR: Function Attrs: nofree norecurse nounwind uwtable
+; FNATTR-NEXT: define void @load_volatile_release(i32* nocapture)
+; ATTRIBUTOR: Function Attrs: norecurse nounwind uwtable
+; ATTRIBUTOR-NOT: nosync
+; ATTRIBUTOR-NEXT: define void @load_volatile_release(i32* nocapture)
+define void @load_volatile_release(i32* nocapture) norecurse nounwind uwtable {
+  store atomic volatile i32 10, i32* %0 release, align 4
+  ret void
+}
+
+; TEST 7 - negative, should not deduce nosync
+; volatile store.
+; void volatile_store(volatile int *num) {
+;   *num = 14;
+; }
+
+; FNATTR: Function Attrs: nofree norecurse nounwind uwtable
+; FNATTR-NEXT: define void @volatile_store(i32*)
+; ATTRIBUTOR: Function Attrs: norecurse nounwind uwtable
+; ATTRIBUTOR-NOT: nosync
+; ATTRIBUTOR-NEXT: define void @volatile_store(i32*)
+define void @volatile_store(i32*) norecurse nounwind uwtable {
+  store volatile i32 14, i32* %0, align 4
+  ret void
+}
+
+; TEST 8 - negative, should not deduce nosync
+; volatile load.
+; int volatile_load(volatile int *num) {
+;   int n = *num;
+;   return n;
+; }
+
+; FNATTR: Function Attrs: nofree norecurse nounwind uwtable
+; FNATTR-NEXT: define i32 @volatile_load(i32*)
+; ATTRIBUTOR: Function Attrs: norecurse nounwind uwtable
+; ATTRIBUTOR-NOT: nosync
+; ATTRIBUTOR-NEXT: define i32 @volatile_load(i32*)
+define i32 @volatile_load(i32*) norecurse nounwind uwtable {
+  %2 = load volatile i32, i32* %0, align 4
+  ret i32 %2
+}
+
+; TEST 9
+
+; FNATTR: Function Attrs: noinline nosync nounwind uwtable
+; FNATTR-NEXT: declare void @nosync_function()
+; ATTRIBUTOR: Function Attrs: noinline nosync nounwind uwtable
+; ATTRIBUTOR-NEXT: declare void @nosync_function()
+declare void @nosync_function() noinline nounwind uwtable nosync
+
+; FNATTR: Function Attrs: noinline nounwind uwtable
+; FNATTR-NEXT: define void @call_nosync_function()
+; ATTRIBUTOR: Function Attrs: noinline nosync nounwind uwtable
+; ATTRIBUTOR-next: define void @call_nosync_function()
+define void @call_nosync_function() nounwind uwtable noinline {
+  tail call void @nosync_function() noinline nounwind uwtable
+  ret void
+}
+
+; TEST 10 - negative, should not deduce nosync
+
+; FNATTR: Function Attrs: noinline nounwind uwtable
+; FNATTR-NEXT: declare void @might_sync()
+; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable
+; ATTRIBUTOR-NEXT: declare void @might_sync()
+declare void @might_sync() noinline nounwind uwtable
+
+; FNATTR: Function Attrs: noinline nounwind uwtable
+; FNATTR-NEXT: define void @call_might_sync()
+; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable
+; ATTRIBUTOR-NOT: nosync
+; ATTRIBUTOR-NEXT: define void @call_might_sync()
+define void @call_might_sync() nounwind uwtable noinline {
+  tail call void @might_sync() noinline nounwind uwtable
+  ret void
+}
+
+; TEST 11 - negative, should not deduce nosync
+; volatile operation in same scc. Call volatile_load defined in TEST 8.
+
+; FNATTR: Function Attrs: nofree noinline nounwind uwtable
+; FNATTR-NEXT: define i32 @scc1(i32*)
+; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable
+; ATTRIBUTOR-NOT: nosync
+; ATTRIBUTOR-NEXT: define i32 @scc1(i32*)
+define i32 @scc1(i32*) noinline nounwind uwtable {
+  tail call void @scc2(i32* %0);
+  %val = tail call i32 @volatile_load(i32* %0);
+  ret i32 %val;
+}
+
+; FNATTR: Function Attrs: nofree noinline nounwind uwtable
+; FNATTR-NEXT: define void @scc2(i32*)
+; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable
+; ATTRIBUTOR-NOT: nosync
+; ATTRIBUTOR-NEXT: define void @scc2(i32*)
+define void @scc2(i32*) noinline nounwind uwtable {
+  tail call i32 @scc1(i32* %0);
+  ret void;
+}
+
+; TEST 12 - fences, negative
+;
+; void foo1(int *a, std::atomic<bool> flag){
+;   *a = 100;
+;   atomic_thread_fence(std::memory_order_release);
+;   flag.store(true, std::memory_order_relaxed);
+; }
+;
+; void bar(int *a, std::atomic<bool> flag){
+;   while(!flag.load(std::memory_order_relaxed))
+;     ;
+;
+;   atomic_thread_fence(std::memory_order_acquire);
+;   int b = *a;
+; }
+
+%"struct.std::atomic" = type { %"struct.std::__atomic_base" }
+%"struct.std::__atomic_base" = type { i8 }
+
+; FNATTR: Function Attrs: nofree norecurse nounwind
+; FNATTR-NEXT: define void @foo1(i32* nocapture, %"struct.std::atomic"* nocapture)
+; ATTRIBUTOR-NOT: nosync
+; ATTRIBUTOR: define void @foo1(i32*, %"struct.std::atomic"*)
+define void @foo1(i32*, %"struct.std::atomic"*) {
+  store i32 100, i32* %0, align 4
+  fence release
+  %3 = getelementptr inbounds %"struct.std::atomic", %"struct.std::atomic"* %1, i64 0, i32 0, i32 0
+  store atomic i8 1, i8* %3 monotonic, align 1
+  ret void
+}
+
+; FNATTR: Function Attrs: nofree norecurse nounwind
+; FNATTR-NEXT: define void @bar(i32* nocapture readnone, %"struct.std::atomic"* nocapture readonly)
+; ATTRIBUTOR-NOT: nosync
+; ATTRIBUTOR: define void @bar(i32*, %"struct.std::atomic"*)
+define void @bar(i32 *, %"struct.std::atomic"*) {
+  %3 = getelementptr inbounds %"struct.std::atomic", %"struct.std::atomic"* %1, i64 0, i32 0, i32 0
+  br label %4
+
+4:                                                ; preds = %4, %2
+  %5 = load atomic i8, i8* %3  monotonic, align 1
+  %6 = and i8 %5, 1
+  %7 = icmp eq i8 %6, 0
+  br i1 %7, label %4, label %8
+
+8:                                                ; preds = %4
+  fence acquire
+  ret void
+}
+
+; TEST 13 - Fence syncscope("singlethread") seq_cst
+; FNATTR: Function Attrs: nofree norecurse nounwind
+; FNATTR-NEXT: define void @foo1_singlethread(i32* nocapture, %"struct.std::atomic"* nocapture)
+; ATTRIBUTOR: Function Attrs: nosync
+; ATTRIBUTOR: define void @foo1_singlethread(i32*, %"struct.std::atomic"*)
+define void @foo1_singlethread(i32*, %"struct.std::atomic"*) {
+  store i32 100, i32* %0, align 4
+  fence syncscope("singlethread") release
+  %3 = getelementptr inbounds %"struct.std::atomic", %"struct.std::atomic"* %1, i64 0, i32 0, i32 0
+  store atomic i8 1, i8* %3 monotonic, align 1
+  ret void
+}
+
+; FNATTR: Function Attrs: nofree norecurse nounwind
+; FNATTR-NEXT: define void @bar_singlethread(i32* nocapture readnone, %"struct.std::atomic"* nocapture readonly)
+; ATTRIBUTOR: Function Attrs: nosync
+; ATTRIBUTOR: define void @bar_singlethread(i32*, %"struct.std::atomic"*)
+define void @bar_singlethread(i32 *, %"struct.std::atomic"*) {
+  %3 = getelementptr inbounds %"struct.std::atomic", %"struct.std::atomic"* %1, i64 0, i32 0, i32 0
+  br label %4
+
+4:                                                ; preds = %4, %2
+  %5 = load atomic i8, i8* %3  monotonic, align 1
+  %6 = and i8 %5, 1
+  %7 = icmp eq i8 %6, 0
+  br i1 %7, label %4, label %8
+
+8:                                                ; preds = %4
+  fence syncscope("singlethread") acquire
+  ret void
+}
+
+declare void @llvm.memcpy(i8* %dest, i8* %src, i32 %len, i1 %isvolatile)
+declare void @llvm.memset(i8* %dest, i8 %val, i32 %len, i1 %isvolatile)
+
+; TEST 14 - negative, checking volatile intrinsics.
+
+; ATTRIBUTOR: Function Attrs: nounwind
+; ATTRIBUTOR-NOT: nosync
+; ATTRIBUTOR-NEXT: define i32 @memcpy_volatile(i8* %ptr1, i8* %ptr2)
+define i32 @memcpy_volatile(i8* %ptr1, i8* %ptr2) {
+  call void @llvm.memcpy(i8* %ptr1, i8* %ptr2, i32 8, i1 1)
+  ret i32 4
+}
+
+; TEST 15 - positive, non-volatile intrinsic.
+
+; ATTRIBUTOR: Function Attrs: nosync
+; ATTRIBUTOR-NEXT: define i32 @memset_non_volatile(i8* %ptr1, i8 %val)
+define i32 @memset_non_volatile(i8* %ptr1, i8 %val) {
+  call void @llvm.memset(i8* %ptr1, i8 %val, i32 8, i1 0)
+  ret i32 4
+}
+
+; TEST 16 - negative, inline assembly.
+
+; ATTRIBUTOR: define i32 @inline_asm_test(i32 %x)
+define i32 @inline_asm_test(i32 %x) {
+  call i32 asm "bswap $0", "=r,r"(i32 %x)
+  ret i32 4
+}
+
+declare void @readnone_test() convergent readnone
+
+; ATTRIBUTOR: define void @convergent_readnone()
+; TEST 17 - negative. Convergent
+define void @convergent_readnone(){
+    call void @readnone_test()
+    ret void
+}
+
+; ATTRIBUTOR: Function Attrs: nounwind
+; ATTRIBUTOR-NEXT: declare void @llvm.x86.sse2.clflush(i8*)
+declare void @llvm.x86.sse2.clflush(i8*)
+ at a = common global i32 0, align 4
+
+; TEST 18 - negative. Synchronizing intrinsic
+
+; ATTRIBUTOR: Function Attrs: nounwind
+; ATTRIBUTOR-NOT: nosync
+; ATTRIBUTOR-NEXT: define void @i_totally_sync()
+define void @i_totally_sync() {
+  tail call void @llvm.x86.sse2.clflush(i8* bitcast (i32* @a to i8*))
+  ret void
+}
+
+declare float @llvm.cos(float %val) readnone
+
+; TEST 19 - positive, readnone & non-convergent intrinsic.
+
+; ATTRIBUTOR: Function Attrs: nosync nounwind
+; ATTRIBUTOR-NEXT: define i32 @cos_test(float %x)
+define i32 @cos_test(float %x) {
+  call float @llvm.cos(float %x)
+  ret i32 4
+}

Modified: llvm/trunk/test/Transforms/FunctionAttrs/nounwind.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/FunctionAttrs/nounwind.ll?rev=365830&r1=365829&r2=365830&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/FunctionAttrs/nounwind.ll (original)
+++ llvm/trunk/test/Transforms/FunctionAttrs/nounwind.ll Thu Jul 11 14:37:40 2019
@@ -4,7 +4,7 @@
 ; TEST 1
 ; CHECK: Function Attrs: norecurse nounwind readnone
 ; CHECK-NEXT: define i32 @foo1()
-; ATTRIBUTOR: Function Attrs: nounwind
+; ATTRIBUTOR: Function Attrs: nosync nounwind
 ; ATTRIBUTOR-NEXT: define i32 @foo1()
 define i32 @foo1() {
   ret i32 1
@@ -13,7 +13,7 @@ define i32 @foo1() {
 ; TEST 2
 ; CHECK: Function Attrs: nounwind readnone
 ; CHECK-NEXT: define i32 @scc1_foo()
-; ATTRIBUTOR: Function Attrs: nounwind
+; ATTRIBUTOR: Function Attrs: nosync nounwind
 ; ATTRIBUTOR-NEXT: define i32 @scc1_foo()
 define i32 @scc1_foo() {
   %1 = call i32 @scc1_bar()
@@ -24,7 +24,7 @@ define i32 @scc1_foo() {
 ; TEST 3
 ; CHECK: Function Attrs: nounwind readnone
 ; CHECK-NEXT: define i32 @scc1_bar()
-; ATTRIBUTOR: Function Attrs: nounwind
+; ATTRIBUTOR: Function Attrs: nosync nounwind
 ; ATTRIBUTOR-NEXT: define i32 @scc1_bar()
 define i32 @scc1_bar() {
   %1 = call i32 @scc1_foo()

Modified: llvm/trunk/test/Transforms/FunctionAttrs/read_write_returned_arguments_scc.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/FunctionAttrs/read_write_returned_arguments_scc.ll?rev=365830&r1=365829&r2=365830&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/FunctionAttrs/read_write_returned_arguments_scc.ll (original)
+++ llvm/trunk/test/Transforms/FunctionAttrs/read_write_returned_arguments_scc.ll Thu Jul 11 14:37:40 2019
@@ -30,7 +30,7 @@
 ;
 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
 
-; CHECK: Function Attrs: nofree nounwind
+; CHECK: Function Attrs: nofree nosync nounwind
 ; CHECK-NEXT: define i32* @external_ret2_nrw(i32* %n0, i32* %r0, i32* returned %w0)
 define i32* @external_ret2_nrw(i32* %n0, i32* %r0, i32* %w0) {
 entry:
@@ -41,7 +41,7 @@ entry:
   ret i32* %call3
 }
 
-; CHECK: Function Attrs: nofree nounwind
+; CHECK: Function Attrs: nofree nosync nounwind
 ; CHECK-NEXT: define internal i32* @internal_ret0_nw(i32* returned %n0, i32* %w0)
 define internal i32* @internal_ret0_nw(i32* %n0, i32* %w0) {
 entry:
@@ -70,7 +70,7 @@ return:
   ret i32* %retval.0
 }
 
-; CHECK: Function Attrs: nofree nounwind
+; CHECK: Function Attrs: nofree nosync nounwind
 ; CHECK-NEXT: define internal i32* @internal_ret1_rrw(i32* %r0, i32* returned %r1, i32* %w0)
 define internal i32* @internal_ret1_rrw(i32* %r0, i32* %r1, i32* %w0) {
 entry:
@@ -102,7 +102,7 @@ return:
   ret i32* %retval.0
 }
 
-; CHECK: Function Attrs: nofree norecurse nounwind
+; CHECK: Function Attrs: nofree norecurse nosync nounwind
 ; CHECK-NEXT: define i32* @external_sink_ret2_nrw(i32* readnone %n0, i32* nocapture readonly %r0, i32* returned %w0)
 define i32* @external_sink_ret2_nrw(i32* %n0, i32* %r0, i32* %w0) {
 entry:
@@ -121,7 +121,7 @@ return:
   ret i32* %w0
 }
 
-; CHECK: Function Attrs: nofree nounwind
+; CHECK: Function Attrs: nofree nosync nounwind
 ; CHECK-NEXT: define internal i32* @internal_ret1_rw(i32* %r0, i32* returned %w0)
 define internal i32* @internal_ret1_rw(i32* %r0, i32* %w0) {
 entry:
@@ -147,7 +147,7 @@ return:
   ret i32* %retval.0
 }
 
-; CHECK: Function Attrs: nofree nounwind
+; CHECK: Function Attrs: nofree nosync nounwind
 ; CHECK-NEXT: define i32* @external_source_ret2_nrw(i32* %n0, i32* %r0, i32* returned %w0)
 define i32* @external_source_ret2_nrw(i32* %n0, i32* %r0, i32* %w0) {
 entry:
@@ -160,6 +160,6 @@ entry:
 ; for a subset relation.
 ;
 ; CHECK-NOT: attributes #
-; CHECK: attributes #{{.*}} = { nofree nounwind }
-; CHECK: attributes #{{.*}} = { nofree norecurse nounwind }
+; CHECK: attributes #{{.*}} = { nofree nosync nounwind }
+; CHECK: attributes #{{.*}} = { nofree norecurse nosync nounwind }
 ; CHECK-NOT: attributes #




More information about the llvm-commits mailing list