Add initial support for the convergent attribute.
authorOwen Anderson <resistor@mac.com>
Tue, 26 May 2015 23:48:40 +0000 (23:48 +0000)
committerOwen Anderson <resistor@mac.com>
Tue, 26 May 2015 23:48:40 +0000 (23:48 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@238264 91177308-0d34-0410-b5e6-96231b3b80d8

16 files changed:
docs/LangRef.rst
include/llvm/Bitcode/LLVMBitCodes.h
include/llvm/IR/Attributes.h
include/llvm/IR/Function.h
include/llvm/IR/Intrinsics.td
lib/AsmParser/LLLexer.cpp
lib/AsmParser/LLParser.cpp
lib/AsmParser/LLToken.h
lib/Bitcode/Reader/BitcodeReader.cpp
lib/Bitcode/Writer/BitcodeWriter.cpp
lib/IR/Attributes.cpp
lib/IR/Verifier.cpp
test/Bitcode/attributes.ll
utils/TableGen/CodeGenIntrinsics.h
utils/TableGen/CodeGenTarget.cpp
utils/TableGen/IntrinsicEmitter.cpp

index 1ee16f8..397d5fe 100644 (file)
@@ -1196,6 +1196,13 @@ example:
     computing edge weights, basic blocks post-dominated by a cold
     function call are also considered to be cold; and, thus, given low
     weight.
+``convergent``
+    This attribute indicates that the callee is dependent on a convergent
+    thread execution pattern under certain parallel execution models.
+    Transformations that are execution model agnostic may only move or
+    tranform this call if the final location is control equivalent to its
+    original position in the program, where control equivalence is defined as
+    A dominates B and B post-dominates A, or vice versa.
 ``inlinehint``
     This attribute indicates that the source code contained a hint that
     inlining this function is desirable (such as the "inline" keyword in
index fe6d366..3a6b5c7 100644 (file)
@@ -402,7 +402,8 @@ namespace bitc {
     ATTR_KIND_NON_NULL = 39,
     ATTR_KIND_JUMP_TABLE = 40,
     ATTR_KIND_DEREFERENCEABLE = 41,
-    ATTR_KIND_DEREFERENCEABLE_OR_NULL = 42
+    ATTR_KIND_DEREFERENCEABLE_OR_NULL = 42,
+    ATTR_KIND_CONVERGENT = 43
   };
 
   enum ComdatSelectionKindCodes {
index 86af13f..e2a0a7e 100644 (file)
@@ -73,6 +73,7 @@ public:
     ByVal,                 ///< Pass structure by value
     InAlloca,              ///< Pass structure in an alloca
     Cold,                  ///< Marks function as being in a cold path.
+    Convergent,            ///< Can only be moved to control-equivalent blocks
     InlineHint,            ///< Source said inlining was desirable
     InReg,                 ///< Force argument to be passed in register
     JumpTable,             ///< Build jump-instruction tables and replace refs.
index 73f22b1..6c228ea 100644 (file)
@@ -308,6 +308,16 @@ public:
     addFnAttr(Attribute::NoDuplicate);
   }
 
+  /// @brief Determine if the call is convergent.
+  bool isConvergent() const {
+    return AttributeSets.hasAttribute(AttributeSet::FunctionIndex,
+                                      Attribute::Convergent);
+  }
+  void setConvergent() {
+    addFnAttr(Attribute::Convergent);
+  }
+
+
   /// @brief True if the ABI mandates (or the user requested) that this
   /// function be in a unwind table.
   bool hasUWTable() const {
index 8f772b5..8f6cdeb 100644 (file)
@@ -73,6 +73,11 @@ def IntrNoReturn : IntrinsicProperty;
 // Parallels the noduplicate attribute on LLVM IR functions.
 def IntrNoDuplicate : IntrinsicProperty;
 
+// IntrConvergent - Calls to this intrinsic are convergent and may only be
+// moved to control equivalent blocks.
+// Parallels the convergent attribute on LLVM IR functions.
+def IntrConvergent : IntrinsicProperty;
+
 //===----------------------------------------------------------------------===//
 // Types used by intrinsics.
 //===----------------------------------------------------------------------===//
index a72f713..05c2428 100644 (file)
@@ -597,6 +597,7 @@ lltok::Kind LLLexer::LexIdentifier() {
   KEYWORD(byval);
   KEYWORD(inalloca);
   KEYWORD(cold);
+  KEYWORD(convergent);
   KEYWORD(dereferenceable);
   KEYWORD(dereferenceable_or_null);
   KEYWORD(inlinehint);
index 713aba7..a52e20f 100644 (file)
@@ -937,6 +937,7 @@ bool LLParser::ParseFnAttributeValuePairs(AttrBuilder &B,
     case lltok::kw_alwaysinline:      B.addAttribute(Attribute::AlwaysInline); break;
     case lltok::kw_builtin:           B.addAttribute(Attribute::Builtin); break;
     case lltok::kw_cold:              B.addAttribute(Attribute::Cold); break;
+    case lltok::kw_convergent:        B.addAttribute(Attribute::Convergent); break;
     case lltok::kw_inlinehint:        B.addAttribute(Attribute::InlineHint); break;
     case lltok::kw_jumptable:         B.addAttribute(Attribute::JumpTable); break;
     case lltok::kw_minsize:           B.addAttribute(Attribute::MinSize); break;
index 2bdc53b..c47f5e1 100644 (file)
@@ -105,6 +105,7 @@ namespace lltok {
     kw_byval,
     kw_inalloca,
     kw_cold,
+    kw_convergent,
     kw_dereferenceable,
     kw_dereferenceable_or_null,
     kw_inlinehint,
index 3f21bb9..95cf51f 100644 (file)
@@ -1095,6 +1095,8 @@ static Attribute::AttrKind GetAttrFromCode(uint64_t Code) {
     return Attribute::InAlloca;
   case bitc::ATTR_KIND_COLD:
     return Attribute::Cold;
+  case bitc::ATTR_KIND_CONVERGENT:
+    return Attribute::Convergent;
   case bitc::ATTR_KIND_INLINE_HINT:
     return Attribute::InlineHint;
   case bitc::ATTR_KIND_IN_REG:
index 3a539e1..97caefb 100644 (file)
@@ -166,6 +166,8 @@ static uint64_t getAttrKindEncoding(Attribute::AttrKind Kind) {
     return bitc::ATTR_KIND_BUILTIN;
   case Attribute::ByVal:
     return bitc::ATTR_KIND_BY_VAL;
+  case Attribute::Convergent:
+    return bitc::ATTR_KIND_CONVERGENT;
   case Attribute::InAlloca:
     return bitc::ATTR_KIND_IN_ALLOCA;
   case Attribute::Cold:
index 55d3122..fef05c8 100644 (file)
@@ -194,6 +194,8 @@ std::string Attribute::getAsString(bool InAttrGrp) const {
     return "builtin";
   if (hasAttribute(Attribute::ByVal))
     return "byval";
+  if (hasAttribute(Attribute::Convergent))
+    return "convergent";
   if (hasAttribute(Attribute::InAlloca))
     return "inalloca";
   if (hasAttribute(Attribute::InlineHint))
@@ -434,6 +436,7 @@ uint64_t AttributeImpl::getAttrMask(Attribute::AttrKind Val) {
   case Attribute::InAlloca:        return 1ULL << 43;
   case Attribute::NonNull:         return 1ULL << 44;
   case Attribute::JumpTable:       return 1ULL << 45;
+  case Attribute::Convergent:      return 1ULL << 46;
   case Attribute::Dereferenceable:
     llvm_unreachable("dereferenceable attribute not supported in raw format");
     break;
index 635e8ef..5ed137a 100644 (file)
@@ -1268,7 +1268,8 @@ void Verifier::VerifyAttributeTypes(AttributeSet Attrs, unsigned Idx,
         I->getKindAsEnum() == Attribute::NoBuiltin ||
         I->getKindAsEnum() == Attribute::Cold ||
         I->getKindAsEnum() == Attribute::OptimizeNone ||
-        I->getKindAsEnum() == Attribute::JumpTable) {
+        I->getKindAsEnum() == Attribute::JumpTable ||
+        I->getKindAsEnum() == Attribute::Convergent) {
       if (!isFunction) {
         CheckFailed("Attribute '" + I->getAsString() +
                     "' only applies to functions!", V);
index 9fbdfeb..cae6a2e 100644 (file)
@@ -204,7 +204,7 @@ define void @f34()
 ; CHECK: define void @f34()
 {
         call void @nobuiltin() nobuiltin
-; CHECK: call void @nobuiltin() #25
+; CHECK: call void @nobuiltin() #26
         ret void;
 }
 
@@ -251,6 +251,11 @@ define dereferenceable_or_null(8) i8* @f42(i8* dereferenceable_or_null(8) %foo)
   ret i8* %foo
 }
 
+; CHECK: define void @f43() #25
+define void @f43() convergent {
+  ret void
+}
+
 ; CHECK: attributes #0 = { noreturn }
 ; CHECK: attributes #1 = { nounwind }
 ; CHECK: attributes #2 = { readnone }
@@ -276,4 +281,5 @@ define dereferenceable_or_null(8) i8* @f42(i8* dereferenceable_or_null(8) %foo)
 ; CHECK: attributes #22 = { minsize }
 ; CHECK: attributes #23 = { noinline optnone }
 ; CHECK: attributes #24 = { jumptable }
-; CHECK: attributes #25 = { nobuiltin }
+; CHECK: attributes #25 = { convergent }
+; CHECK: attributes #26 = { nobuiltin }
index 1f1adf1..f405557 100644 (file)
@@ -80,6 +80,9 @@ namespace llvm {
     /// isNoReturn - True if the intrinsic is no-return.
     bool isNoReturn;
 
+    /// isConvergent - True if the intrinsic is marked as convergent.
+    bool isConvergent;
+
     enum ArgAttribute {
       NoCapture,
       ReadOnly,
index da54a75..0765370 100644 (file)
@@ -444,6 +444,7 @@ CodeGenIntrinsic::CodeGenIntrinsic(Record *R) {
   canThrow = false;
   isNoReturn = false;
   isNoDuplicate = false;
+  isConvergent = false;
 
   if (DefName.size() <= 4 ||
       std::string(DefName.begin(), DefName.begin() + 4) != "int_")
@@ -574,6 +575,8 @@ CodeGenIntrinsic::CodeGenIntrinsic(Record *R) {
       canThrow = true;
     else if (Property->getName() == "IntrNoDuplicate")
       isNoDuplicate = true;
+    else if (Property->getName() == "IntrConvergent")
+      isConvergent = true;
     else if (Property->getName() == "IntrNoReturn")
       isNoReturn = true;
     else if (Property->isSubClassOf("NoCapture")) {
index 1a2555e..3f62f20 100644 (file)
@@ -537,6 +537,9 @@ struct AttributeComparator {
     if (L->isNoReturn != R->isNoReturn)
       return R->isNoReturn;
 
+    if (L->isConvergent != R->isConvergent)
+      return R->isConvergent;
+
     // Try to order by readonly/readnone attribute.
     ModRefKind LK = getModRefKind(*L);
     ModRefKind RK = getModRefKind(*R);
@@ -649,7 +652,7 @@ EmitAttributes(const std::vector<CodeGenIntrinsic> &Ints, raw_ostream &OS) {
     ModRefKind modRef = getModRefKind(intrinsic);
 
     if (!intrinsic.canThrow || modRef || intrinsic.isNoReturn ||
-        intrinsic.isNoDuplicate) {
+        intrinsic.isNoDuplicate || intrinsic.isConvergent) {
       OS << "      const Attribute::AttrKind Atts[] = {";
       bool addComma = false;
       if (!intrinsic.canThrow) {
@@ -668,6 +671,12 @@ EmitAttributes(const std::vector<CodeGenIntrinsic> &Ints, raw_ostream &OS) {
         OS << "Attribute::NoDuplicate";
         addComma = true;
       }
+      if (intrinsic.isConvergent) {
+        if (addComma)
+          OS << ",";
+        OS << "Attribute::Convergent";
+        addComma = true;
+      }
 
       switch (modRef) {
       case MRK_none: break;