[llvm] r274485 - Add writeonly IR attribute

Nicolai Haehnle via llvm-commits llvm-commits at lists.llvm.org
Mon Jul 4 01:01:29 PDT 2016


Author: nha
Date: Mon Jul  4 03:01:29 2016
New Revision: 274485

URL: http://llvm.org/viewvc/llvm-project?rev=274485&view=rev
Log:
Add writeonly IR attribute

Summary:
This complements the earlier addition of IntrWriteMem and IntrWriteArgMem
LLVM intrinsic properties, see D18291.

Also start using the attribute for memset, memcpy, and memmove intrinsics,
and remove their special-casing in BasicAliasAnalysis.

Reviewers: reames, joker.eph

Subscribers: joker.eph, llvm-commits

Differential Revision: http://reviews.llvm.org/D18714

Added:
    llvm/trunk/test/Verifier/writeonly.ll
Modified:
    llvm/trunk/docs/LangRef.rst
    llvm/trunk/include/llvm/Analysis/AliasAnalysis.h
    llvm/trunk/include/llvm/Bitcode/LLVMBitCodes.h
    llvm/trunk/include/llvm/IR/Attributes.td
    llvm/trunk/include/llvm/IR/CallSite.h
    llvm/trunk/include/llvm/IR/Function.h
    llvm/trunk/include/llvm/IR/Instructions.h
    llvm/trunk/include/llvm/IR/Intrinsics.td
    llvm/trunk/lib/Analysis/AliasAnalysis.cpp
    llvm/trunk/lib/Analysis/BasicAliasAnalysis.cpp
    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/test/Analysis/BasicAA/cs-cs.ll
    llvm/trunk/test/Bindings/llvm-c/Inputs/invalid.ll.bc
    llvm/trunk/test/Bindings/llvm-c/invalid-bitcode.test
    llvm/trunk/test/Bitcode/attributes.ll
    llvm/trunk/test/Bitcode/compatibility.ll
    llvm/trunk/test/Bitcode/invalid.ll
    llvm/trunk/test/Bitcode/invalid.ll.bc
    llvm/trunk/test/LTO/X86/Inputs/invalid.ll.bc
    llvm/trunk/test/LTO/X86/invalid.ll
    llvm/trunk/utils/TableGen/CodeGenIntrinsics.h
    llvm/trunk/utils/TableGen/CodeGenTarget.cpp
    llvm/trunk/utils/TableGen/IntrinsicEmitter.cpp

Modified: llvm/trunk/docs/LangRef.rst
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/docs/LangRef.rst?rev=274485&r1=274484&r2=274485&view=diff
==============================================================================
--- llvm/trunk/docs/LangRef.rst (original)
+++ llvm/trunk/docs/LangRef.rst Mon Jul  4 03:01:29 2016
@@ -1474,6 +1474,13 @@ example:
     On an argument, this attribute indicates that the function does not write
     through this pointer argument, even though it may write to the memory that
     the pointer points to.
+``writeonly``
+    On a function, this attribute indicates that the function may write to but
+    does not read from memory.
+
+    On an argument, this attribute indicates that the function may write to but
+    does not read through this pointer argument (even though it may read from
+    the memory that the pointer points to).
 ``argmemonly``
     This attribute indicates that the only memory accesses inside function are
     loads and stores from objects pointed to by its pointer-typed arguments,

Modified: llvm/trunk/include/llvm/Analysis/AliasAnalysis.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Analysis/AliasAnalysis.h?rev=274485&r1=274484&r2=274485&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Analysis/AliasAnalysis.h (original)
+++ llvm/trunk/include/llvm/Analysis/AliasAnalysis.h Mon Jul  4 03:01:29 2016
@@ -151,6 +151,13 @@ enum FunctionModRefBehavior {
   /// This property corresponds to the IntrReadMem LLVM intrinsic flag.
   FMRB_OnlyReadsMemory = FMRL_Anywhere | MRI_Ref,
 
+  // This function does not read from memory anywhere, but may write to any
+  // memory location.
+  //
+  // This property corresponds to the LLVM IR 'writeonly' attribute.
+  // This property corresponds to the IntrWriteMem LLVM intrinsic flag.
+  FMRB_DoesNotReadMemory = FMRL_Anywhere | MRI_Mod,
+
   /// This indicates that the function could not be classified into one of the
   /// behaviors above.
   FMRB_UnknownModRefBehavior = FMRL_Anywhere | MRI_ModRef
@@ -312,6 +319,12 @@ public:
     return !(MRB & MRI_Mod);
   }
 
+  /// Checks if functions with the specified behavior are known to only write
+  /// memory (or not access memory at all).
+  static bool doesNotReadMemory(FunctionModRefBehavior MRB) {
+    return !(MRB & MRI_Ref);
+  }
+
   /// Checks if functions with the specified behavior are known to read and
   /// write at most from objects pointed to by their pointer-typed arguments
   /// (with arbitrary offsets).

Modified: llvm/trunk/include/llvm/Bitcode/LLVMBitCodes.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Bitcode/LLVMBitCodes.h?rev=274485&r1=274484&r2=274485&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Bitcode/LLVMBitCodes.h (original)
+++ llvm/trunk/include/llvm/Bitcode/LLVMBitCodes.h Mon Jul  4 03:01:29 2016
@@ -521,7 +521,8 @@ enum AttributeKindCodes {
   ATTR_KIND_NO_RECURSE = 48,
   ATTR_KIND_INACCESSIBLEMEM_ONLY = 49,
   ATTR_KIND_INACCESSIBLEMEM_OR_ARGMEMONLY = 50,
-  ATTR_KIND_ALLOC_SIZE = 51
+  ATTR_KIND_ALLOC_SIZE = 51,
+  ATTR_KIND_WRITEONLY = 52
 };
 
 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=274485&r1=274484&r2=274485&view=diff
==============================================================================
--- llvm/trunk/include/llvm/IR/Attributes.td (original)
+++ llvm/trunk/include/llvm/IR/Attributes.td Mon Jul  4 03:01:29 2016
@@ -167,6 +167,9 @@ def SwiftSelf : EnumAttr<"swiftself">;
 /// Function must be in a unwind table.
 def UWTable : EnumAttr<"uwtable">;
 
+/// Function only writes to memory.
+def WriteOnly : EnumAttr<"writeonly">;
+
 /// Zero extended before/after call.
 def ZExt : EnumAttr<"zeroext">;
 

Modified: llvm/trunk/include/llvm/IR/CallSite.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/IR/CallSite.h?rev=274485&r1=274484&r2=274485&view=diff
==============================================================================
--- llvm/trunk/include/llvm/IR/CallSite.h (original)
+++ llvm/trunk/include/llvm/IR/CallSite.h Mon Jul  4 03:01:29 2016
@@ -417,6 +417,14 @@ public:
     CALLSITE_DELEGATE_SETTER(setOnlyReadsMemory());
   }
 
+  /// @brief Determine if the call does not access or only writes memory.
+  bool doesNotReadMemory() const {
+    CALLSITE_DELEGATE_GETTER(doesNotReadMemory());
+  }
+  void setDoesNotReadMemory() {
+    CALLSITE_DELEGATE_SETTER(setDoesNotReadMemory());
+  }
+
   /// @brief Determine if the call can access memmory only using pointers based
   /// on its arguments.
   bool onlyAccessesArgMemory() const {

Modified: llvm/trunk/include/llvm/IR/Function.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/IR/Function.h?rev=274485&r1=274484&r2=274485&view=diff
==============================================================================
--- llvm/trunk/include/llvm/IR/Function.h (original)
+++ llvm/trunk/include/llvm/IR/Function.h Mon Jul  4 03:01:29 2016
@@ -298,6 +298,14 @@ public:
     addFnAttr(Attribute::ReadOnly);
   }
 
+  /// @brief Determine if the function does not access or only writes memory.
+  bool doesNotReadMemory() const {
+    return doesNotAccessMemory() || hasFnAttribute(Attribute::WriteOnly);
+  }
+  void setDoesNotReadMemory() {
+    addFnAttr(Attribute::WriteOnly);
+  }
+
   /// @brief Determine if the call can access memmory only using pointers based
   /// on its arguments.
   bool onlyAccessesArgMemory() const {

Modified: llvm/trunk/include/llvm/IR/Instructions.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/IR/Instructions.h?rev=274485&r1=274484&r2=274485&view=diff
==============================================================================
--- llvm/trunk/include/llvm/IR/Instructions.h (original)
+++ llvm/trunk/include/llvm/IR/Instructions.h Mon Jul  4 03:01:29 2016
@@ -1739,6 +1739,14 @@ public:
     addAttribute(AttributeSet::FunctionIndex, Attribute::ReadOnly);
   }
 
+  /// \brief Determine if the call does not access or only writes memory.
+  bool doesNotReadMemory() const {
+    return doesNotAccessMemory() || hasFnAttr(Attribute::WriteOnly);
+  }
+  void setDoesNotReadMemory() {
+    addAttribute(AttributeSet::FunctionIndex, Attribute::WriteOnly);
+  }
+
   /// @brief Determine if the call can access memmory only using pointers based
   /// on its arguments.
   bool onlyAccessesArgMemory() const {
@@ -3691,6 +3699,14 @@ public:
     addAttribute(AttributeSet::FunctionIndex, Attribute::ReadOnly);
   }
 
+  /// \brief Determine if the call does not access or only writes memory.
+  bool doesNotReadMemory() const {
+    return doesNotAccessMemory() || hasFnAttr(Attribute::WriteOnly);
+  }
+  void setDoesNotReadMemory() {
+    addAttribute(AttributeSet::FunctionIndex, Attribute::WriteOnly);
+  }
+
   /// @brief Determine if the call access memmory only using it's pointer
   /// arguments.
   bool onlyAccessesArgMemory() const {

Modified: llvm/trunk/include/llvm/IR/Intrinsics.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/IR/Intrinsics.td?rev=274485&r1=274484&r2=274485&view=diff
==============================================================================
--- llvm/trunk/include/llvm/IR/Intrinsics.td (original)
+++ llvm/trunk/include/llvm/IR/Intrinsics.td Mon Jul  4 03:01:29 2016
@@ -60,6 +60,12 @@ class ReadOnly<int argNo> : IntrinsicPro
   int ArgNo = argNo;
 }
 
+// WriteOnly - The intrinsic does not read memory through the specified
+// argument pointer.
+class WriteOnly<int argNo> : IntrinsicProperty {
+  int ArgNo = argNo;
+}
+
 // ReadNone - The specified argument pointer is not dereferenced by the
 // intrinsic.
 class ReadNone<int argNo> : IntrinsicProperty {
@@ -349,7 +355,7 @@ def int_memcpy  : Intrinsic<[],
                              [llvm_anyptr_ty, llvm_anyptr_ty, llvm_anyint_ty,
                               llvm_i32_ty, llvm_i1_ty],
                             [IntrArgMemOnly, NoCapture<0>, NoCapture<1>,
-                             ReadOnly<1>]>;
+                             WriteOnly<0>, ReadOnly<1>]>;
 def int_memmove : Intrinsic<[],
                             [llvm_anyptr_ty, llvm_anyptr_ty, llvm_anyint_ty,
                              llvm_i32_ty, llvm_i1_ty],
@@ -358,7 +364,7 @@ def int_memmove : Intrinsic<[],
 def int_memset  : Intrinsic<[],
                             [llvm_anyptr_ty, llvm_i8_ty, llvm_anyint_ty,
                              llvm_i32_ty, llvm_i1_ty],
-                            [IntrArgMemOnly, NoCapture<0>]>;
+                            [IntrArgMemOnly, NoCapture<0>, WriteOnly<0>]>;
 
 let IntrProperties = [IntrNoMem] in {
   def int_fma  : Intrinsic<[llvm_anyfloat_ty],

Modified: llvm/trunk/lib/Analysis/AliasAnalysis.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/AliasAnalysis.cpp?rev=274485&r1=274484&r2=274485&view=diff
==============================================================================
--- llvm/trunk/lib/Analysis/AliasAnalysis.cpp (original)
+++ llvm/trunk/lib/Analysis/AliasAnalysis.cpp Mon Jul  4 03:01:29 2016
@@ -142,6 +142,8 @@ ModRefInfo AAResults::getModRefInfo(Immu
 
   if (onlyReadsMemory(MRB))
     Result = ModRefInfo(Result & MRI_Ref);
+  else if (doesNotReadMemory(MRB))
+    Result = ModRefInfo(Result & MRI_Mod);
 
   if (onlyAccessesArgPointees(MRB)) {
     bool DoesAlias = false;
@@ -207,6 +209,8 @@ ModRefInfo AAResults::getModRefInfo(Immu
   // from CS1 reading memory written by CS2.
   if (onlyReadsMemory(CS1B))
     Result = ModRefInfo(Result & MRI_Ref);
+  else if (doesNotReadMemory(CS1B))
+    Result = ModRefInfo(Result & MRI_Mod);
 
   // If CS2 only access memory through arguments, accumulate the mod/ref
   // information from CS1's references to the memory referenced by

Modified: llvm/trunk/lib/Analysis/BasicAliasAnalysis.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/BasicAliasAnalysis.cpp?rev=274485&r1=274484&r2=274485&view=diff
==============================================================================
--- llvm/trunk/lib/Analysis/BasicAliasAnalysis.cpp (original)
+++ llvm/trunk/lib/Analysis/BasicAliasAnalysis.cpp Mon Jul  4 03:01:29 2016
@@ -563,6 +563,8 @@ FunctionModRefBehavior BasicAAResult::ge
   // than that.
   if (CS.onlyReadsMemory())
     Min = FMRB_OnlyReadsMemory;
+  else if (CS.doesNotReadMemory())
+    Min = FMRB_DoesNotReadMemory;
 
   if (CS.onlyAccessesArgMemory())
     Min = FunctionModRefBehavior(Min & FMRB_OnlyAccessesArgumentPointees);
@@ -590,6 +592,8 @@ FunctionModRefBehavior BasicAAResult::ge
   // If the function declares it only reads memory, go with that.
   if (F->onlyReadsMemory())
     Min = FMRB_OnlyReadsMemory;
+  else if (F->doesNotReadMemory())
+    Min = FMRB_DoesNotReadMemory;
 
   if (F->onlyAccessesArgMemory())
     Min = FunctionModRefBehavior(Min & FMRB_OnlyAccessesArgumentPointees);
@@ -597,32 +601,18 @@ FunctionModRefBehavior BasicAAResult::ge
   return Min;
 }
 
-/// Returns true if this is a writeonly (i.e Mod only) parameter.  Currently,
-/// we don't have a writeonly attribute, so this only knows about builtin
-/// intrinsics and target library functions.  We could consider adding a
-/// writeonly attribute in the future and moving all of these facts to either
-/// Intrinsics.td or InferFunctionAttr.cpp
+/// Returns true if this is a writeonly (i.e Mod only) parameter.
 static bool isWriteOnlyParam(ImmutableCallSite CS, unsigned ArgIdx,
                              const TargetLibraryInfo &TLI) {
-  if (const IntrinsicInst *II = dyn_cast<IntrinsicInst>(CS.getInstruction()))
-    switch (II->getIntrinsicID()) {
-    default:
-      break;
-    case Intrinsic::memset:
-    case Intrinsic::memcpy:
-    case Intrinsic::memmove:
-      // We don't currently have a writeonly attribute.  All other properties
-      // of these intrinsics are nicely described via attributes in
-      // Intrinsics.td and handled generically.
-      if (ArgIdx == 0)
-        return true;
-    }
+  if (CS.paramHasAttr(ArgIdx + 1, Attribute::WriteOnly))
+    return true;
 
   // We can bound the aliasing properties of memset_pattern16 just as we can
   // for memcpy/memset.  This is particularly important because the
   // LoopIdiomRecognizer likes to turn loops into calls to memset_pattern16
-  // whenever possible.  Note that all but the missing writeonly attribute are
-  // handled via InferFunctionAttr.
+  // whenever possible.
+  // FIXME Consider handling this in InferFunctionAttr.cpp together with other
+  // attributes.
   LibFunc::Func F;
   if (CS.getCalledFunction() && TLI.getLibFunc(*CS.getCalledFunction(), F) &&
       F == LibFunc::memset_pattern16 && TLI.has(F))
@@ -639,8 +629,7 @@ static bool isWriteOnlyParam(ImmutableCa
 ModRefInfo BasicAAResult::getArgModRefInfo(ImmutableCallSite CS,
                                            unsigned ArgIdx) {
 
-  // Emulate the missing writeonly attribute by checking for known builtin
-  // intrinsics and target library functions.
+  // Checking for known builtin intrinsics and target library functions.
   if (isWriteOnlyParam(CS, ArgIdx, TLI))
     return MRI_Mod;
 

Modified: llvm/trunk/lib/AsmParser/LLLexer.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/AsmParser/LLLexer.cpp?rev=274485&r1=274484&r2=274485&view=diff
==============================================================================
--- llvm/trunk/lib/AsmParser/LLLexer.cpp (original)
+++ llvm/trunk/lib/AsmParser/LLLexer.cpp Mon Jul  4 03:01:29 2016
@@ -660,6 +660,7 @@ lltok::Kind LLLexer::LexIdentifier() {
   KEYWORD(swifterror);
   KEYWORD(swiftself);
   KEYWORD(uwtable);
+  KEYWORD(writeonly);
   KEYWORD(zeroext);
 
   KEYWORD(type);

Modified: llvm/trunk/lib/AsmParser/LLParser.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/AsmParser/LLParser.cpp?rev=274485&r1=274484&r2=274485&view=diff
==============================================================================
--- llvm/trunk/lib/AsmParser/LLParser.cpp (original)
+++ llvm/trunk/lib/AsmParser/LLParser.cpp Mon Jul  4 03:01:29 2016
@@ -1098,6 +1098,7 @@ bool LLParser::ParseFnAttributeValuePair
     case lltok::kw_sanitize_memory:
       B.addAttribute(Attribute::SanitizeMemory); break;
     case lltok::kw_uwtable: B.addAttribute(Attribute::UWTable); break;
+    case lltok::kw_writeonly: B.addAttribute(Attribute::WriteOnly); break;
 
     // Error handling.
     case lltok::kw_inreg:
@@ -1394,6 +1395,7 @@ bool LLParser::ParseOptionalParamAttrs(A
     case lltok::kw_sret:            B.addAttribute(Attribute::StructRet); break;
     case lltok::kw_swifterror:      B.addAttribute(Attribute::SwiftError); break;
     case lltok::kw_swiftself:       B.addAttribute(Attribute::SwiftSelf); break;
+    case lltok::kw_writeonly:       B.addAttribute(Attribute::WriteOnly); break;
     case lltok::kw_zeroext:         B.addAttribute(Attribute::ZExt); break;
 
     case lltok::kw_alignstack:

Modified: llvm/trunk/lib/AsmParser/LLToken.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/AsmParser/LLToken.h?rev=274485&r1=274484&r2=274485&view=diff
==============================================================================
--- llvm/trunk/lib/AsmParser/LLToken.h (original)
+++ llvm/trunk/lib/AsmParser/LLToken.h Mon Jul  4 03:01:29 2016
@@ -205,6 +205,7 @@ enum Kind {
   kw_swifterror,
   kw_swiftself,
   kw_uwtable,
+  kw_writeonly,
   kw_zeroext,
 
   kw_type,

Modified: llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp?rev=274485&r1=274484&r2=274485&view=diff
==============================================================================
--- llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp (original)
+++ llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp Mon Jul  4 03:01:29 2016
@@ -1464,6 +1464,8 @@ static Attribute::AttrKind getAttrFromCo
     return Attribute::SwiftSelf;
   case bitc::ATTR_KIND_UW_TABLE:
     return Attribute::UWTable;
+  case bitc::ATTR_KIND_WRITEONLY:
+    return Attribute::WriteOnly;
   case bitc::ATTR_KIND_Z_EXT:
     return Attribute::ZExt;
   }

Modified: llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp?rev=274485&r1=274484&r2=274485&view=diff
==============================================================================
--- llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp (original)
+++ llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp Mon Jul  4 03:01:29 2016
@@ -667,6 +667,8 @@ static uint64_t getAttrKindEncoding(Attr
     return bitc::ATTR_KIND_SWIFT_SELF;
   case Attribute::UWTable:
     return bitc::ATTR_KIND_UW_TABLE;
+  case Attribute::WriteOnly:
+    return bitc::ATTR_KIND_WRITEONLY;
   case Attribute::ZExt:
     return bitc::ATTR_KIND_Z_EXT;
   case Attribute::EndAttrKinds:

Modified: llvm/trunk/lib/IR/Attributes.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/IR/Attributes.cpp?rev=274485&r1=274484&r2=274485&view=diff
==============================================================================
--- llvm/trunk/lib/IR/Attributes.cpp (original)
+++ llvm/trunk/lib/IR/Attributes.cpp Mon Jul  4 03:01:29 2016
@@ -292,6 +292,8 @@ std::string Attribute::getAsString(bool
     return "readnone";
   if (hasAttribute(Attribute::ReadOnly))
     return "readonly";
+  if (hasAttribute(Attribute::WriteOnly))
+    return "writeonly";
   if (hasAttribute(Attribute::Returned))
     return "returned";
   if (hasAttribute(Attribute::ReturnsTwice))
@@ -516,6 +518,7 @@ uint64_t AttributeImpl::getAttrMask(Attr
   case Attribute::InaccessibleMemOrArgMemOnly: return 1ULL << 50;
   case Attribute::SwiftSelf:       return 1ULL << 51;
   case Attribute::SwiftError:      return 1ULL << 52;
+  case Attribute::WriteOnly:       return 1ULL << 53;
   case Attribute::Dereferenceable:
     llvm_unreachable("dereferenceable attribute not supported in raw format");
     break;

Modified: llvm/trunk/lib/IR/Verifier.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/IR/Verifier.cpp?rev=274485&r1=274484&r2=274485&view=diff
==============================================================================
--- llvm/trunk/lib/IR/Verifier.cpp (original)
+++ llvm/trunk/lib/IR/Verifier.cpp Mon Jul  4 03:01:29 2016
@@ -1309,6 +1309,7 @@ void Verifier::verifyAttributeTypes(Attr
         return;
       }
     } else if (I->getKindAsEnum() == Attribute::ReadOnly ||
+               I->getKindAsEnum() == Attribute::WriteOnly ||
                I->getKindAsEnum() == Attribute::ReadNone) {
       if (Idx == 0) {
         CheckFailed("Attribute '" + I->getAsString() +
@@ -1382,6 +1383,18 @@ void Verifier::verifyParameterAttrs(Attr
          "'readnone and readonly' are incompatible!",
          V);
 
+  Assert(!(Attrs.hasAttribute(Idx, Attribute::ReadNone) &&
+           Attrs.hasAttribute(Idx, Attribute::WriteOnly)),
+         "Attributes "
+         "'readnone and writeonly' are incompatible!",
+         V);
+
+  Assert(!(Attrs.hasAttribute(Idx, Attribute::ReadOnly) &&
+           Attrs.hasAttribute(Idx, Attribute::WriteOnly)),
+         "Attributes "
+         "'readonly and writeonly' are incompatible!",
+         V);
+
   Assert(!(Attrs.hasAttribute(Idx, Attribute::NoInline) &&
            Attrs.hasAttribute(Idx, Attribute::AlwaysInline)),
          "Attributes "
@@ -1499,6 +1512,16 @@ void Verifier::verifyFunctionAttrs(Funct
 
   Assert(
       !(Attrs.hasAttribute(AttributeSet::FunctionIndex, Attribute::ReadNone) &&
+        Attrs.hasAttribute(AttributeSet::FunctionIndex, Attribute::WriteOnly)),
+      "Attributes 'readnone and writeonly' are incompatible!", V);
+
+  Assert(
+      !(Attrs.hasAttribute(AttributeSet::FunctionIndex, Attribute::ReadOnly) &&
+        Attrs.hasAttribute(AttributeSet::FunctionIndex, Attribute::WriteOnly)),
+      "Attributes 'readonly and writeonly' are incompatible!", V);
+
+  Assert(
+      !(Attrs.hasAttribute(AttributeSet::FunctionIndex, Attribute::ReadNone) &&
         Attrs.hasAttribute(AttributeSet::FunctionIndex, 
                            Attribute::InaccessibleMemOrArgMemOnly)),
       "Attributes 'readnone and inaccessiblemem_or_argmemonly' are incompatible!", V);

Modified: llvm/trunk/test/Analysis/BasicAA/cs-cs.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Analysis/BasicAA/cs-cs.ll?rev=274485&r1=274484&r2=274485&view=diff
==============================================================================
--- llvm/trunk/test/Analysis/BasicAA/cs-cs.ll (original)
+++ llvm/trunk/test/Analysis/BasicAA/cs-cs.ll Mon Jul  4 03:01:29 2016
@@ -9,6 +9,7 @@ declare void @llvm.memset.p0i8.i64(i8* n
 declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture, i8* nocapture, i64, i32, i1) nounwind
 
 declare void @a_readonly_func(i8 *) noinline nounwind readonly
+declare void @a_writeonly_func(i8 *) noinline nounwind writeonly
 
 define <8 x i16> @test1(i8* %p, <8 x i16> %y) {
 entry:
@@ -22,18 +23,18 @@ entry:
 ; CHECK-LABEL: Function: test1:
 
 ; CHECK: NoAlias:      i8* %p, i8* %q
-; CHECK: Just Ref:  Ptr: i8* %p        <->  %a = call <8 x i16> @llvm.arm.neon.vld1.v8i16.p0i8(i8* %p, i32 16) #4
-; CHECK: NoModRef:  Ptr: i8* %q        <->  %a = call <8 x i16> @llvm.arm.neon.vld1.v8i16.p0i8(i8* %p, i32 16) #4
+; CHECK: Just Ref:  Ptr: i8* %p        <->  %a = call <8 x i16> @llvm.arm.neon.vld1.v8i16.p0i8(i8* %p, i32 16) #5
+; CHECK: NoModRef:  Ptr: i8* %q        <->  %a = call <8 x i16> @llvm.arm.neon.vld1.v8i16.p0i8(i8* %p, i32 16) #5
 ; CHECK: NoModRef:  Ptr: i8* %p        <->  call void @llvm.arm.neon.vst1.p0i8.v8i16(i8* %q, <8 x i16> %y, i32 16)
 ; CHECK: Both ModRef:  Ptr: i8* %q     <->  call void @llvm.arm.neon.vst1.p0i8.v8i16(i8* %q, <8 x i16> %y, i32 16)
-; CHECK: Just Ref:  Ptr: i8* %p        <->  %b = call <8 x i16> @llvm.arm.neon.vld1.v8i16.p0i8(i8* %p, i32 16) #4
-; CHECK: NoModRef:  Ptr: i8* %q        <->  %b = call <8 x i16> @llvm.arm.neon.vld1.v8i16.p0i8(i8* %p, i32 16) #4
-; CHECK: NoModRef:   %a = call <8 x i16> @llvm.arm.neon.vld1.v8i16.p0i8(i8* %p, i32 16) #4 <->   call void @llvm.arm.neon.vst1.p0i8.v8i16(i8* %q, <8 x i16> %y, i32 16)
-; CHECK: NoModRef:   %a = call <8 x i16> @llvm.arm.neon.vld1.v8i16.p0i8(i8* %p, i32 16) #4 <->   %b = call <8 x i16> @llvm.arm.neon.vld1.v8i16.p0i8(i8* %p, i32 16) #4
-; CHECK: NoModRef:   call void @llvm.arm.neon.vst1.p0i8.v8i16(i8* %q, <8 x i16> %y, i32 16) <->   %a = call <8 x i16> @llvm.arm.neon.vld1.v8i16.p0i8(i8* %p, i32 16) #4
-; CHECK: NoModRef:   call void @llvm.arm.neon.vst1.p0i8.v8i16(i8* %q, <8 x i16> %y, i32 16) <->   %b = call <8 x i16> @llvm.arm.neon.vld1.v8i16.p0i8(i8* %p, i32 16) #4
-; CHECK: NoModRef:   %b = call <8 x i16> @llvm.arm.neon.vld1.v8i16.p0i8(i8* %p, i32 16) #4 <->   %a = call <8 x i16> @llvm.arm.neon.vld1.v8i16.p0i8(i8* %p, i32 16) #4
-; CHECK: NoModRef:   %b = call <8 x i16> @llvm.arm.neon.vld1.v8i16.p0i8(i8* %p, i32 16) #4 <->   call void @llvm.arm.neon.vst1.p0i8.v8i16(i8* %q, <8 x i16> %y, i32 16)
+; CHECK: Just Ref:  Ptr: i8* %p        <->  %b = call <8 x i16> @llvm.arm.neon.vld1.v8i16.p0i8(i8* %p, i32 16) #5
+; CHECK: NoModRef:  Ptr: i8* %q        <->  %b = call <8 x i16> @llvm.arm.neon.vld1.v8i16.p0i8(i8* %p, i32 16) #5
+; CHECK: NoModRef:   %a = call <8 x i16> @llvm.arm.neon.vld1.v8i16.p0i8(i8* %p, i32 16) #5 <->   call void @llvm.arm.neon.vst1.p0i8.v8i16(i8* %q, <8 x i16> %y, i32 16)
+; CHECK: NoModRef:   %a = call <8 x i16> @llvm.arm.neon.vld1.v8i16.p0i8(i8* %p, i32 16) #5 <->   %b = call <8 x i16> @llvm.arm.neon.vld1.v8i16.p0i8(i8* %p, i32 16) #5
+; CHECK: NoModRef:   call void @llvm.arm.neon.vst1.p0i8.v8i16(i8* %q, <8 x i16> %y, i32 16) <->   %a = call <8 x i16> @llvm.arm.neon.vld1.v8i16.p0i8(i8* %p, i32 16) #5
+; CHECK: NoModRef:   call void @llvm.arm.neon.vst1.p0i8.v8i16(i8* %q, <8 x i16> %y, i32 16) <->   %b = call <8 x i16> @llvm.arm.neon.vld1.v8i16.p0i8(i8* %p, i32 16) #5
+; CHECK: NoModRef:   %b = call <8 x i16> @llvm.arm.neon.vld1.v8i16.p0i8(i8* %p, i32 16) #5 <->   %a = call <8 x i16> @llvm.arm.neon.vld1.v8i16.p0i8(i8* %p, i32 16) #5
+; CHECK: NoModRef:   %b = call <8 x i16> @llvm.arm.neon.vld1.v8i16.p0i8(i8* %p, i32 16) #5 <->   call void @llvm.arm.neon.vst1.p0i8.v8i16(i8* %q, <8 x i16> %y, i32 16)
 }
 
 define void @test2(i8* %P, i8* %Q) nounwind ssp {
@@ -233,9 +234,23 @@ define void @test6(i8* %P) nounwind ssp
 ; CHECK: Just Ref:   call void @a_readonly_func(i8* %P) <->   call void @llvm.memset.p0i8.i64(i8* %P, i8 -51, i64 32, i32 8, i1 false)
 }
 
-attributes #0 = { nounwind readonly argmemonly }
-attributes #1 = { nounwind argmemonly }
+define void @test7(i8* %P) nounwind ssp {
+  call void @a_writeonly_func(i8* %P)
+  call void @a_readonly_func(i8* %P)
+  ret void
+
+; CHECK-LABEL: Function: test7:
+
+; CHECK: Just Mod:  Ptr: i8* %P        <->  call void @a_writeonly_func(i8* %P)
+; CHECK: Just Ref:  Ptr: i8* %P        <->  call void @a_readonly_func(i8* %P)
+; CHECK: Just Mod:   call void @a_writeonly_func(i8* %P) <->   call void @a_readonly_func(i8* %P)
+; CHECK: Just Ref:   call void @a_readonly_func(i8* %P) <->   call void @a_writeonly_func(i8* %P)
+}
+
+attributes #0 = { argmemonly nounwind readonly }
+attributes #1 = { argmemonly nounwind }
 attributes #2 = { noinline nounwind readonly }
-attributes #3 = { nounwind ssp }
-attributes #4 = { nounwind }
+attributes #3 = { noinline nounwind writeonly }
+attributes #4 = { nounwind ssp }
+attributes #5 = { nounwind }
 

Modified: llvm/trunk/test/Bindings/llvm-c/Inputs/invalid.ll.bc
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Bindings/llvm-c/Inputs/invalid.ll.bc?rev=274485&r1=274484&r2=274485&view=diff
==============================================================================
Binary files llvm/trunk/test/Bindings/llvm-c/Inputs/invalid.ll.bc (original) and llvm/trunk/test/Bindings/llvm-c/Inputs/invalid.ll.bc Mon Jul  4 03:01:29 2016 differ

Modified: llvm/trunk/test/Bindings/llvm-c/invalid-bitcode.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Bindings/llvm-c/invalid-bitcode.test?rev=274485&r1=274484&r2=274485&view=diff
==============================================================================
--- llvm/trunk/test/Bindings/llvm-c/invalid-bitcode.test (original)
+++ llvm/trunk/test/Bindings/llvm-c/invalid-bitcode.test Mon Jul  4 03:01:29 2016
@@ -1,13 +1,13 @@
 ; RUN: not llvm-c-test --module-dump < %S/Inputs/invalid.ll.bc 2>&1 | FileCheck %s
 ; RUN: not llvm-c-test --lazy-module-dump < %S/Inputs/invalid.ll.bc 2>&1 | FileCheck %s
 
-CHECK: Error parsing bitcode: Unknown attribute kind (52)
+CHECK: Error parsing bitcode: Unknown attribute kind (63)
 
 
 ; RUN: not llvm-c-test --new-module-dump < %S/Inputs/invalid.ll.bc 2>&1 | FileCheck --check-prefix=NEW %s
 ; RUN: not llvm-c-test --lazy-new-module-dump < %S/Inputs/invalid.ll.bc 2>&1 | FileCheck --check-prefix=NEW %s
 
-NEW: Error with new bitcode parser: Unknown attribute kind (52)
+NEW: Error with new bitcode parser: Unknown attribute kind (63)
 
 ; RUN: llvm-c-test --test-diagnostic-handler < %S/Inputs/invalid.ll.bc 2>&1 | FileCheck --check-prefix=DIAGNOSTIC %s
 

Modified: llvm/trunk/test/Bitcode/attributes.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Bitcode/attributes.ll?rev=274485&r1=274484&r2=274485&view=diff
==============================================================================
--- llvm/trunk/test/Bitcode/attributes.ll (original)
+++ llvm/trunk/test/Bitcode/attributes.ll Mon Jul  4 03:01:29 2016
@@ -204,7 +204,7 @@ define void @f34()
 ; CHECK: define void @f34()
 {
         call void @nobuiltin() nobuiltin
-; CHECK: call void @nobuiltin() #32
+; CHECK: call void @nobuiltin() #33
         ret void;
 }
 
@@ -328,6 +328,12 @@ define i8* @f55(i32, i32) allocsize(0, 1
   ret i8* null
 }
 
+; CHECK: define void @f56() #32
+define void @f56() writeonly
+{
+  ret void
+}
+
 ; CHECK: attributes #0 = { noreturn }
 ; CHECK: attributes #1 = { nounwind }
 ; CHECK: attributes #2 = { readnone }
@@ -360,4 +366,5 @@ define i8* @f55(i32, i32) allocsize(0, 1
 ; CHECK: attributes #29 = { inaccessiblemem_or_argmemonly }
 ; CHECK: attributes #30 = { allocsize(0) }
 ; CHECK: attributes #31 = { allocsize(0,1) }
-; CHECK: attributes #32 = { nobuiltin }
+; CHECK: attributes #32 = { writeonly }
+; CHECK: attributes #33 = { nobuiltin }

Modified: llvm/trunk/test/Bitcode/compatibility.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Bitcode/compatibility.ll?rev=274485&r1=274484&r2=274485&view=diff
==============================================================================
--- llvm/trunk/test/Bitcode/compatibility.ll (original)
+++ llvm/trunk/test/Bitcode/compatibility.ll Mon Jul  4 03:01:29 2016
@@ -1244,7 +1244,7 @@ exit:
   ; CHECK: select <2 x i1> <i1 true, i1 false>, <2 x i8> <i8 2, i8 3>, <2 x i8> <i8 3, i8 2>
 
   call void @f.nobuiltin() builtin
-  ; CHECK: call void @f.nobuiltin() #39
+  ; CHECK: call void @f.nobuiltin() #40
 
   call fastcc noalias i32* @f.noalias() noinline
   ; CHECK: call fastcc noalias i32* @f.noalias() #12
@@ -1590,6 +1590,8 @@ normal:
   ret void
 }
 
+declare void @f.writeonly() writeonly
+; CHECK: declare void @f.writeonly() #39
 
 ; CHECK: attributes #0 = { alignstack=4 }
 ; CHECK: attributes #1 = { alignstack=8 }
@@ -1630,7 +1632,8 @@ normal:
 ; CHECK: attributes #36 = { argmemonly nounwind readonly }
 ; CHECK: attributes #37 = { argmemonly nounwind }
 ; CHECK: attributes #38 = { nounwind readonly }
-; CHECK: attributes #39 = { builtin }
+; CHECK: attributes #39 = { writeonly }
+; CHECK: attributes #40 = { builtin }
 
 ;; Metadata
 

Modified: llvm/trunk/test/Bitcode/invalid.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Bitcode/invalid.ll?rev=274485&r1=274484&r2=274485&view=diff
==============================================================================
--- llvm/trunk/test/Bitcode/invalid.ll (original)
+++ llvm/trunk/test/Bitcode/invalid.ll Mon Jul  4 03:01:29 2016
@@ -1,6 +1,6 @@
 ; RUN:  not llvm-dis < %s.bc 2>&1 | FileCheck %s
 
-; CHECK: llvm-dis{{(\.EXE|\.exe)?}}: error: Unknown attribute kind (52)
+; CHECK: llvm-dis{{(\.EXE|\.exe)?}}: error: Unknown attribute kind (63)
 
 ; invalid.ll.bc has an invalid attribute number.
 ; The test checks that LLVM reports the error and doesn't access freed memory

Modified: llvm/trunk/test/Bitcode/invalid.ll.bc
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Bitcode/invalid.ll.bc?rev=274485&r1=274484&r2=274485&view=diff
==============================================================================
Binary files llvm/trunk/test/Bitcode/invalid.ll.bc (original) and llvm/trunk/test/Bitcode/invalid.ll.bc Mon Jul  4 03:01:29 2016 differ

Modified: llvm/trunk/test/LTO/X86/Inputs/invalid.ll.bc
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/LTO/X86/Inputs/invalid.ll.bc?rev=274485&r1=274484&r2=274485&view=diff
==============================================================================
Binary files - no diff available.

Modified: llvm/trunk/test/LTO/X86/invalid.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/LTO/X86/invalid.ll?rev=274485&r1=274484&r2=274485&view=diff
==============================================================================
--- llvm/trunk/test/LTO/X86/invalid.ll (original)
+++ llvm/trunk/test/LTO/X86/invalid.ll Mon Jul  4 03:01:29 2016
@@ -1,4 +1,4 @@
 ; RUN: not llvm-lto %S/Inputs/invalid.ll.bc 2>&1 | FileCheck %s
 
 
-; CHECK: llvm-lto{{.*}}: error loading file '{{.*}}/Inputs/invalid.ll.bc': Unknown attribute kind (52)
+; CHECK: llvm-lto{{.*}}: error loading file '{{.*}}/Inputs/invalid.ll.bc': Unknown attribute kind (63)

Added: llvm/trunk/test/Verifier/writeonly.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Verifier/writeonly.ll?rev=274485&view=auto
==============================================================================
--- llvm/trunk/test/Verifier/writeonly.ll (added)
+++ llvm/trunk/test/Verifier/writeonly.ll Mon Jul  4 03:01:29 2016
@@ -0,0 +1,13 @@
+; RUN: not llvm-as %s -o /dev/null 2>&1 | FileCheck %s
+
+declare void @a() readnone writeonly
+; CHECK: Attributes {{.*}} are incompatible
+
+declare void @b() readonly writeonly
+; CHECK: Attributes {{.*}} are incompatible
+
+declare void @c(i32* readnone writeonly %p)
+; CHECK: Attributes {{.*}} are incompatible
+
+declare void @d(i32* readonly writeonly %p)
+; CHECK: Attributes {{.*}} are incompatible

Modified: llvm/trunk/utils/TableGen/CodeGenIntrinsics.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/utils/TableGen/CodeGenIntrinsics.h?rev=274485&r1=274484&r2=274485&view=diff
==============================================================================
--- llvm/trunk/utils/TableGen/CodeGenIntrinsics.h (original)
+++ llvm/trunk/utils/TableGen/CodeGenIntrinsics.h Mon Jul  4 03:01:29 2016
@@ -112,6 +112,7 @@ namespace llvm {
     enum ArgAttribute {
       NoCapture,
       ReadOnly,
+      WriteOnly,
       ReadNone
     };
     std::vector<std::pair<unsigned, ArgAttribute> > ArgumentAttributes;

Modified: llvm/trunk/utils/TableGen/CodeGenTarget.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/utils/TableGen/CodeGenTarget.cpp?rev=274485&r1=274484&r2=274485&view=diff
==============================================================================
--- llvm/trunk/utils/TableGen/CodeGenTarget.cpp (original)
+++ llvm/trunk/utils/TableGen/CodeGenTarget.cpp Mon Jul  4 03:01:29 2016
@@ -595,6 +595,9 @@ CodeGenIntrinsic::CodeGenIntrinsic(Recor
     } else if (Property->isSubClassOf("ReadOnly")) {
       unsigned ArgNo = Property->getValueAsInt("ArgNo");
       ArgumentAttributes.push_back(std::make_pair(ArgNo, ReadOnly));
+    } else if (Property->isSubClassOf("WriteOnly")) {
+      unsigned ArgNo = Property->getValueAsInt("ArgNo");
+      ArgumentAttributes.push_back(std::make_pair(ArgNo, WriteOnly));
     } else if (Property->isSubClassOf("ReadNone")) {
       unsigned ArgNo = Property->getValueAsInt("ArgNo");
       ArgumentAttributes.push_back(std::make_pair(ArgNo, ReadNone));

Modified: llvm/trunk/utils/TableGen/IntrinsicEmitter.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/utils/TableGen/IntrinsicEmitter.cpp?rev=274485&r1=274484&r2=274485&view=diff
==============================================================================
--- llvm/trunk/utils/TableGen/IntrinsicEmitter.cpp (original)
+++ llvm/trunk/utils/TableGen/IntrinsicEmitter.cpp Mon Jul  4 03:01:29 2016
@@ -554,6 +554,12 @@ EmitAttributes(const std::vector<CodeGen
             OS << "Attribute::ReadOnly";
             addComma = true;
             break;
+          case CodeGenIntrinsic::WriteOnly:
+            if (addComma)
+              OS << ",";
+            OS << "Attribute::WriteOnly";
+            addComma = true;
+            break;
           case CodeGenIntrinsic::ReadNone:
             if (addComma)
               OS << ",";
@@ -617,12 +623,21 @@ EmitAttributes(const std::vector<CodeGen
         OS << "Attribute::ReadOnly";
         break;
       case CodeGenIntrinsic::WriteArgMem:
-      case CodeGenIntrinsic::ReadWriteArgMem:
         if (addComma)
           OS << ",";
+        OS << "Attribute::WriteOnly,";
         OS << "Attribute::ArgMemOnly";
         break;
       case CodeGenIntrinsic::WriteMem:
+        if (addComma)
+          OS << ",";
+        OS << "Attribute::WriteOnly";
+        break;
+      case CodeGenIntrinsic::ReadWriteArgMem:
+        if (addComma)
+          OS << ",";
+        OS << "Attribute::ArgMemOnly";
+        break;
       case CodeGenIntrinsic::ReadWriteMem:
         break;
       }




More information about the llvm-commits mailing list