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
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 {
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.
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 {
// 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.
//===----------------------------------------------------------------------===//
KEYWORD(byval);
KEYWORD(inalloca);
KEYWORD(cold);
+ KEYWORD(convergent);
KEYWORD(dereferenceable);
KEYWORD(dereferenceable_or_null);
KEYWORD(inlinehint);
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;
kw_byval,
kw_inalloca,
kw_cold,
+ kw_convergent,
kw_dereferenceable,
kw_dereferenceable_or_null,
kw_inlinehint,
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:
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:
return "builtin";
if (hasAttribute(Attribute::ByVal))
return "byval";
+ if (hasAttribute(Attribute::Convergent))
+ return "convergent";
if (hasAttribute(Attribute::InAlloca))
return "inalloca";
if (hasAttribute(Attribute::InlineHint))
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;
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);
; CHECK: define void @f34()
{
call void @nobuiltin() nobuiltin
-; CHECK: call void @nobuiltin() #25
+; CHECK: call void @nobuiltin() #26
ret void;
}
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 }
; 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 }
/// 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,
canThrow = false;
isNoReturn = false;
isNoDuplicate = false;
+ isConvergent = false;
if (DefName.size() <= 4 ||
std::string(DefName.begin(), DefName.begin() + 4) != "int_")
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")) {
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);
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) {
OS << "Attribute::NoDuplicate";
addComma = true;
}
+ if (intrinsic.isConvergent) {
+ if (addComma)
+ OS << ",";
+ OS << "Attribute::Convergent";
+ addComma = true;
+ }
switch (modRef) {
case MRK_none: break;