From 13146c7e3b143f021e3e58a7bdb642e43f8e7b57 Mon Sep 17 00:00:00 2001 From: Owen Anderson Date: Tue, 26 May 2015 23:48:40 +0000 Subject: [PATCH] Add initial support for the convergent attribute. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@238264 91177308-0d34-0410-b5e6-96231b3b80d8 --- docs/LangRef.rst | 7 +++++++ include/llvm/Bitcode/LLVMBitCodes.h | 3 ++- include/llvm/IR/Attributes.h | 1 + include/llvm/IR/Function.h | 10 ++++++++++ include/llvm/IR/Intrinsics.td | 5 +++++ lib/AsmParser/LLLexer.cpp | 1 + lib/AsmParser/LLParser.cpp | 1 + lib/AsmParser/LLToken.h | 1 + lib/Bitcode/Reader/BitcodeReader.cpp | 2 ++ lib/Bitcode/Writer/BitcodeWriter.cpp | 2 ++ lib/IR/Attributes.cpp | 3 +++ lib/IR/Verifier.cpp | 3 ++- test/Bitcode/attributes.ll | 10 ++++++++-- utils/TableGen/CodeGenIntrinsics.h | 3 +++ utils/TableGen/CodeGenTarget.cpp | 3 +++ utils/TableGen/IntrinsicEmitter.cpp | 11 ++++++++++- 16 files changed, 61 insertions(+), 5 deletions(-) diff --git a/docs/LangRef.rst b/docs/LangRef.rst index 1ee16f866d6..397d5fe3756 100644 --- a/docs/LangRef.rst +++ b/docs/LangRef.rst @@ -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 diff --git a/include/llvm/Bitcode/LLVMBitCodes.h b/include/llvm/Bitcode/LLVMBitCodes.h index fe6d3662954..3a6b5c704d1 100644 --- a/include/llvm/Bitcode/LLVMBitCodes.h +++ b/include/llvm/Bitcode/LLVMBitCodes.h @@ -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 { diff --git a/include/llvm/IR/Attributes.h b/include/llvm/IR/Attributes.h index 86af13f864f..e2a0a7ee395 100644 --- a/include/llvm/IR/Attributes.h +++ b/include/llvm/IR/Attributes.h @@ -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. diff --git a/include/llvm/IR/Function.h b/include/llvm/IR/Function.h index 73f22b129ad..6c228eae633 100644 --- a/include/llvm/IR/Function.h +++ b/include/llvm/IR/Function.h @@ -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 { diff --git a/include/llvm/IR/Intrinsics.td b/include/llvm/IR/Intrinsics.td index 8f772b5193b..8f6cdebb049 100644 --- a/include/llvm/IR/Intrinsics.td +++ b/include/llvm/IR/Intrinsics.td @@ -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. //===----------------------------------------------------------------------===// diff --git a/lib/AsmParser/LLLexer.cpp b/lib/AsmParser/LLLexer.cpp index a72f713c490..05c24285028 100644 --- a/lib/AsmParser/LLLexer.cpp +++ b/lib/AsmParser/LLLexer.cpp @@ -597,6 +597,7 @@ lltok::Kind LLLexer::LexIdentifier() { KEYWORD(byval); KEYWORD(inalloca); KEYWORD(cold); + KEYWORD(convergent); KEYWORD(dereferenceable); KEYWORD(dereferenceable_or_null); KEYWORD(inlinehint); diff --git a/lib/AsmParser/LLParser.cpp b/lib/AsmParser/LLParser.cpp index 713aba790ef..a52e20fb35b 100644 --- a/lib/AsmParser/LLParser.cpp +++ b/lib/AsmParser/LLParser.cpp @@ -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; diff --git a/lib/AsmParser/LLToken.h b/lib/AsmParser/LLToken.h index 2bdc53b3e2e..c47f5e1654d 100644 --- a/lib/AsmParser/LLToken.h +++ b/lib/AsmParser/LLToken.h @@ -105,6 +105,7 @@ namespace lltok { kw_byval, kw_inalloca, kw_cold, + kw_convergent, kw_dereferenceable, kw_dereferenceable_or_null, kw_inlinehint, diff --git a/lib/Bitcode/Reader/BitcodeReader.cpp b/lib/Bitcode/Reader/BitcodeReader.cpp index 3f21bb9fbac..95cf51f1419 100644 --- a/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/lib/Bitcode/Reader/BitcodeReader.cpp @@ -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: diff --git a/lib/Bitcode/Writer/BitcodeWriter.cpp b/lib/Bitcode/Writer/BitcodeWriter.cpp index 3a539e12926..97caefb4c49 100644 --- a/lib/Bitcode/Writer/BitcodeWriter.cpp +++ b/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -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: diff --git a/lib/IR/Attributes.cpp b/lib/IR/Attributes.cpp index 55d3122bbd8..fef05c8f92d 100644 --- a/lib/IR/Attributes.cpp +++ b/lib/IR/Attributes.cpp @@ -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; diff --git a/lib/IR/Verifier.cpp b/lib/IR/Verifier.cpp index 635e8efa11b..5ed137abd0e 100644 --- a/lib/IR/Verifier.cpp +++ b/lib/IR/Verifier.cpp @@ -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); diff --git a/test/Bitcode/attributes.ll b/test/Bitcode/attributes.ll index 9fbdfeb0ef0..cae6a2e01e6 100644 --- a/test/Bitcode/attributes.ll +++ b/test/Bitcode/attributes.ll @@ -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 } diff --git a/utils/TableGen/CodeGenIntrinsics.h b/utils/TableGen/CodeGenIntrinsics.h index 1f1adf11fb3..f4055571b1c 100644 --- a/utils/TableGen/CodeGenIntrinsics.h +++ b/utils/TableGen/CodeGenIntrinsics.h @@ -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, diff --git a/utils/TableGen/CodeGenTarget.cpp b/utils/TableGen/CodeGenTarget.cpp index da54a75713b..076537002a6 100644 --- a/utils/TableGen/CodeGenTarget.cpp +++ b/utils/TableGen/CodeGenTarget.cpp @@ -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")) { diff --git a/utils/TableGen/IntrinsicEmitter.cpp b/utils/TableGen/IntrinsicEmitter.cpp index 1a2555ebbf6..3f62f205fe5 100644 --- a/utils/TableGen/IntrinsicEmitter.cpp +++ b/utils/TableGen/IntrinsicEmitter.cpp @@ -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 &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 &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;