[IR] Adds mustprogress as a LLVM IR attribute

This adds the LLVM IR attribute `mustprogress` as defined in LangRef through D86233. This attribute will be applied to functions with in languages like C++ where forward progress is guaranteed. Functions without this attribute are not required to make progress.

Reviewed By: nikic

Differential Revision: https://reviews.llvm.org/D85393
This commit is contained in:
Atmn Patel 2020-10-20 02:48:18 -04:00 committed by Atmn Patel
parent 08c8d5bc51
commit 595c615606
15 changed files with 54 additions and 0 deletions

View File

@ -650,6 +650,7 @@ enum AttributeKindCodes {
ATTR_KIND_NULL_POINTER_IS_VALID = 67,
ATTR_KIND_NOUNDEF = 68,
ATTR_KIND_BYREF = 69,
ATTR_KIND_MUSTPROGRESS = 70,
};
enum ComdatSelectionKindCodes {

View File

@ -235,6 +235,9 @@ def WriteOnly : EnumAttr<"writeonly">;
/// Zero extended before/after call.
def ZExt : EnumAttr<"zeroext">;
/// Function is required to make Forward Progress.
def MustProgress : TypeAttr<"mustprogress">;
/// Target-independent string attributes.
def LessPreciseFPMAD : StrBoolAttr<"less-precise-fpmad">;
def NoInfsFPMath : StrBoolAttr<"no-infs-fp-math">;

View File

@ -622,6 +622,13 @@ public:
addFnAttr(Attribute::NoRecurse);
}
/// Determine if the function is required to make forward progress.
bool mustProgress() const {
return hasFnAttribute(Attribute::MustProgress) ||
hasFnAttribute(Attribute::WillReturn);
}
void setMustProgress() { addFnAttr(Attribute::MustProgress); }
/// True if the ABI mandates (or the user requested) that this
/// function be in a unwind table.
bool hasUWTable() const {

View File

@ -698,6 +698,7 @@ lltok::Kind LLLexer::LexIdentifier() {
KEYWORD(zeroext);
KEYWORD(immarg);
KEYWORD(byref);
KEYWORD(mustprogress);
KEYWORD(type);
KEYWORD(opaque);

View File

@ -1309,6 +1309,9 @@ bool LLParser::ParseFnAttributeValuePairs(AttrBuilder &B,
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;
case lltok::kw_mustprogress:
B.addAttribute(Attribute::MustProgress);
break;
case lltok::kw_naked: B.addAttribute(Attribute::Naked); break;
case lltok::kw_nobuiltin: B.addAttribute(Attribute::NoBuiltin); break;
case lltok::kw_noduplicate: B.addAttribute(Attribute::NoDuplicate); break;
@ -1724,6 +1727,7 @@ bool LLParser::ParseOptionalParamAttrs(AttrBuilder &B) {
case lltok::kw_inlinehint:
case lltok::kw_jumptable:
case lltok::kw_minsize:
case lltok::kw_mustprogress:
case lltok::kw_naked:
case lltok::kw_nobuiltin:
case lltok::kw_noduplicate:
@ -1828,6 +1832,7 @@ bool LLParser::ParseOptionalReturnAttrs(AttrBuilder &B) {
case lltok::kw_inlinehint:
case lltok::kw_jumptable:
case lltok::kw_minsize:
case lltok::kw_mustprogress:
case lltok::kw_naked:
case lltok::kw_nobuiltin:
case lltok::kw_noduplicate:

View File

@ -241,6 +241,7 @@ enum Kind {
kw_zeroext,
kw_immarg,
kw_byref,
kw_mustprogress,
kw_type,
kw_opaque,

View File

@ -1535,6 +1535,8 @@ static Attribute::AttrKind getAttrFromCode(uint64_t Code) {
return Attribute::NoUndef;
case bitc::ATTR_KIND_BYREF:
return Attribute::ByRef;
case bitc::ATTR_KIND_MUSTPROGRESS:
return Attribute::MustProgress;
}
}

View File

@ -743,6 +743,8 @@ static uint64_t getAttrKindEncoding(Attribute::AttrKind Kind) {
return bitc::ATTR_KIND_NOUNDEF;
case Attribute::ByRef:
return bitc::ATTR_KIND_BYREF;
case Attribute::MustProgress:
return bitc::ATTR_KIND_MUSTPROGRESS;
case Attribute::EndAttrKinds:
llvm_unreachable("Can not encode end-attribute kinds marker.");
case Attribute::None:

View File

@ -451,6 +451,8 @@ std::string Attribute::getAsString(bool InAttrGrp) const {
return "immarg";
if (hasAttribute(Attribute::NoUndef))
return "noundef";
if (hasAttribute(Attribute::MustProgress))
return "mustprogress";
const bool IsByVal = hasAttribute(Attribute::ByVal);
if (IsByVal || hasAttribute(Attribute::StructRet)) {

View File

@ -1613,6 +1613,7 @@ static bool isFuncOnlyAttr(Attribute::AttrKind Kind) {
case Attribute::Speculatable:
case Attribute::StrictFP:
case Attribute::NullPointerIsValid:
case Attribute::MustProgress:
return true;
default:
break;

View File

@ -931,6 +931,7 @@ Function *CodeExtractor::constructFunction(const ValueSet &inputs,
case Attribute::StrictFP:
case Attribute::UWTable:
case Attribute::NoCfCheck:
case Attribute::MustProgress:
break;
}

View File

@ -0,0 +1,7 @@
; RUN: not llvm-as < %s 2>&1 | FileCheck %s
; CHECK: [[@LINE+1]]:35: error: invalid use of function-only attribute
define void @test_mustprogress(i8 mustprogress %a) {
ret void
}

View File

@ -0,0 +1,7 @@
; RUN: not llvm-as < %s 2>&1 | FileCheck %s
; CHECK: [[@LINE+1]]:8: error: invalid use of function-only attribute
define mustprogress void @test_mustprogress(i8 %a) {
ret void
}

View File

@ -0,0 +1,7 @@
; RUN: not llvm-as < %s 2>&1 | FileCheck %s
; CHECK: [[@LINE+1]]:52: error: expected '{' in function body
define i32* @test_mustprogress(i8 %a) mustprogress 8 {
ret void
}

View File

@ -398,6 +398,12 @@ define void @f67(i32* byref(i32) %a)
ret void
}
; CHECK: define void @f68() #41
define void @f68() mustprogress
{
ret void
}
; CHECK: attributes #0 = { noreturn }
; CHECK: attributes #1 = { nounwind }
; CHECK: attributes #2 = { readnone }
@ -439,4 +445,5 @@ define void @f67(i32* byref(i32) %a)
; CHECK: attributes #38 = { nosync }
; CHECK: attributes #39 = { sanitize_memtag }
; CHECK: attributes #40 = { null_pointer_is_valid }
; CHECK: attributes #41 = { mustprogress }
; CHECK: attributes #[[NOBUILTIN]] = { nobuiltin }