Skip to content

Commit

Permalink
[Attributor] Create AAMustProgress for the mustprogress attribute
Browse files Browse the repository at this point in the history
Derive the mustprogress attribute based on the willreturn attribute
or the fact that all callers are mustprogress.

Differential Revision: https://reviews.llvm.org/D94740
  • Loading branch information
jdoerfert committed Jun 5, 2023
1 parent f6ea869 commit dbbe9b3
Show file tree
Hide file tree
Showing 105 changed files with 2,465 additions and 2,352 deletions.
32 changes: 32 additions & 0 deletions llvm/include/llvm/Transforms/IPO/Attributor.h
Expand Up @@ -3404,6 +3404,38 @@ struct AANoSync
static const char ID;
};

/// An abstract interface for all nonnull attributes.
struct AAMustProgress
: public IRAttribute<Attribute::MustProgress,
StateWrapper<BooleanState, AbstractAttribute>> {
AAMustProgress(const IRPosition &IRP, Attributor &A) : IRAttribute(IRP) {}

/// Return true if we assume that the underlying value is nonnull.
bool isAssumedMustProgress() const { return getAssumed(); }

/// Return true if we know that underlying value is nonnull.
bool isKnownMustProgress() const { return getKnown(); }

/// Create an abstract attribute view for the position \p IRP.
static AAMustProgress &createForPosition(const IRPosition &IRP,
Attributor &A);

/// See AbstractAttribute::getName()
const std::string getName() const override { return "AAMustProgress"; }

/// See AbstractAttribute::getIdAddr()
const char *getIdAddr() const override { return &ID; }

/// This function should return true if the type of the \p AA is
/// AAMustProgress
static bool classof(const AbstractAttribute *AA) {
return (AA->getIdAddr() == &ID);
}

/// Unique ID (due to the unique address)
static const char ID;
};

/// An abstract interface for all nonnull attributes.
struct AANonNull
: public IRAttribute<Attribute::NonNull,
Expand Down
3 changes: 3 additions & 0 deletions llvm/lib/Transforms/IPO/Attributor.cpp
Expand Up @@ -3193,6 +3193,9 @@ void Attributor::identifyDefaultAbstractAttributes(Function &F) {
// Every function might be "will-return".
getOrCreateAAFor<AAWillReturn>(FPos);

// Every function might be "must-progress".
getOrCreateAAFor<AAMustProgress>(FPos);

// Every function might contain instructions that cause "undefined behavior".
getOrCreateAAFor<AAUndefinedBehavior>(FPos);

Expand Down
74 changes: 74 additions & 0 deletions llvm/lib/Transforms/IPO/AttributorAttributes.cpp
Expand Up @@ -161,6 +161,7 @@ PIPE_OPERATOR(AAWillReturn)
PIPE_OPERATOR(AANoReturn)
PIPE_OPERATOR(AAReturnedValues)
PIPE_OPERATOR(AANonNull)
PIPE_OPERATOR(AAMustProgress)
PIPE_OPERATOR(AANoAlias)
PIPE_OPERATOR(AADereferenceable)
PIPE_OPERATOR(AAAlign)
Expand Down Expand Up @@ -2854,6 +2855,77 @@ struct AANonNullCallSiteReturned final
};
} // namespace

/// ------------------------ Must-Progress Attributes --------------------------
namespace {
struct AAMustProgressImpl : public AAMustProgress {
AAMustProgressImpl(const IRPosition &IRP, Attributor &A)
: AAMustProgress(IRP, A) {}

/// See AbstractAttribute::getAsStr()
const std::string getAsStr() const override {
return getAssumed() ? "mustprogress" : "may-not-progress";
}
};

struct AAMustProgressFunction final : AAMustProgressImpl {
AAMustProgressFunction(const IRPosition &IRP, Attributor &A)
: AAMustProgressImpl(IRP, A) {}

/// See AbstractAttribute::updateImpl(...).
ChangeStatus updateImpl(Attributor &A) override {
const auto &WillReturnAA =
A.getAAFor<AAWillReturn>(*this, getIRPosition(), DepClassTy::OPTIONAL);
if (WillReturnAA.isKnownWillReturn())
return indicateOptimisticFixpoint();
if (WillReturnAA.isAssumedWillReturn())
return ChangeStatus::UNCHANGED;

auto CheckForMustProgress = [&](AbstractCallSite ACS) {
IRPosition IPos = IRPosition::callsite_function(*ACS.getInstruction());
const auto &MustProgressAA =
A.getAAFor<AAMustProgress>(*this, IPos, DepClassTy::OPTIONAL);
return MustProgressAA.isAssumedMustProgress();
};

bool AllCallSitesKnown = true;
if (!A.checkForAllCallSites(CheckForMustProgress, *this,
/* RequireAllCallSites */ true,
AllCallSitesKnown))
return indicatePessimisticFixpoint();

return ChangeStatus::UNCHANGED;
}

/// See AbstractAttribute::trackStatistics()
void trackStatistics() const override {
STATS_DECLTRACK_FN_ATTR(mustprogress)
}
};

/// MustProgress attribute deduction for a call sites.
struct AAMustProgressCallSite final : AAMustProgressImpl {
AAMustProgressCallSite(const IRPosition &IRP, Attributor &A)
: AAMustProgressImpl(IRP, A) {}

/// See AbstractAttribute::updateImpl(...).
ChangeStatus updateImpl(Attributor &A) override {
// TODO: Once we have call site specific value information we can provide
// call site specific liveness information and then it makes
// sense to specialize attributes for call sites arguments instead of
// redirecting requests to the callee argument.
const IRPosition &FnPos = IRPosition::function(*getAnchorScope());
const auto &FnAA =
A.getAAFor<AAMustProgress>(*this, FnPos, DepClassTy::OPTIONAL);
return clampStateAndIndicateChange(getState(), FnAA.getState());
}

/// See AbstractAttribute::trackStatistics()
void trackStatistics() const override {
STATS_DECLTRACK_CS_ATTR(mustprogress);
}
};
} // namespace

/// ------------------------ No-Recurse Attributes ----------------------------

namespace {
Expand Down Expand Up @@ -11879,6 +11951,7 @@ const char AANoUnwind::ID = 0;
const char AANoSync::ID = 0;
const char AANoFree::ID = 0;
const char AANonNull::ID = 0;
const char AAMustProgress::ID = 0;
const char AANoRecurse::ID = 0;
const char AANonConvergent::ID = 0;
const char AAWillReturn::ID = 0;
Expand Down Expand Up @@ -12009,6 +12082,7 @@ CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAReturnedValues)
CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAMemoryLocation)
CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION(AACallEdges)
CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAAssumptionInfo)
CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAMustProgress)

CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION(AANonNull)
CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION(AANoAlias)
Expand Down
Expand Up @@ -3,7 +3,7 @@
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,CGSCC

define internal i32 @deref(ptr %x) nounwind {
; CGSCC: Function Attrs: nofree norecurse nosync nounwind willreturn memory(argmem: read)
; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read)
; CGSCC-LABEL: define {{[^@]+}}@deref
; CGSCC-SAME: (i32 [[TMP0:%.*]]) #[[ATTR0:[0-9]+]] {
; CGSCC-NEXT: entry:
Expand All @@ -18,15 +18,15 @@ entry:
}

define i32 @f(i32 %x) {
; TUNIT: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define {{[^@]+}}@f
; TUNIT-SAME: (i32 returned [[X:%.*]]) #[[ATTR0:[0-9]+]] {
; TUNIT-NEXT: entry:
; TUNIT-NEXT: [[X_ADDR:%.*]] = alloca i32, align 4
; TUNIT-NEXT: store i32 [[X]], ptr [[X_ADDR]], align 4
; TUNIT-NEXT: ret i32 [[X]]
;
; CGSCC: Function Attrs: nofree nosync nounwind willreturn memory(none)
; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define {{[^@]+}}@f
; CGSCC-SAME: (i32 [[X:%.*]]) #[[ATTR1:[0-9]+]] {
; CGSCC-NEXT: entry:
Expand All @@ -42,10 +42,10 @@ entry:
ret i32 %tmp1
}
;.
; TUNIT: attributes #[[ATTR0]] = { nofree norecurse nosync nounwind willreturn memory(none) }
; TUNIT: attributes #[[ATTR0]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) }
;.
; CGSCC: attributes #[[ATTR0]] = { nofree norecurse nosync nounwind willreturn memory(argmem: read) }
; CGSCC: attributes #[[ATTR1]] = { nofree nosync nounwind willreturn memory(none) }
; CGSCC: attributes #[[ATTR0]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read) }
; CGSCC: attributes #[[ATTR1]] = { mustprogress nofree nosync nounwind willreturn memory(none) }
; CGSCC: attributes #[[ATTR2]] = { nounwind willreturn }
;.
;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
Expand Down
Expand Up @@ -7,7 +7,7 @@
; because there is a load of %A in the entry block
define internal i32 @callee(i1 %C, ptr %A) {
;
; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(argmem: read)
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read)
; CHECK-LABEL: define {{[^@]+}}@callee
; CHECK-SAME: (ptr nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[A:%.*]]) #[[ATTR0:[0-9]+]] {
; CHECK-NEXT: entry:
Expand Down Expand Up @@ -36,13 +36,13 @@ F:
}

define i32 @foo(ptr %A) {
; TUNIT: Function Attrs: nofree norecurse nosync nounwind willreturn memory(argmem: read)
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read)
; TUNIT-LABEL: define {{[^@]+}}@foo
; TUNIT-SAME: (ptr nocapture nofree readonly [[A:%.*]]) #[[ATTR0]] {
; TUNIT-NEXT: [[X:%.*]] = call i32 @callee(ptr nocapture nofree readonly align 4 [[A]]) #[[ATTR1:[0-9]+]]
; TUNIT-NEXT: ret i32 [[X]]
;
; CGSCC: Function Attrs: nofree nosync nounwind willreturn memory(argmem: read)
; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(argmem: read)
; CGSCC-LABEL: define {{[^@]+}}@foo
; CGSCC-SAME: (ptr nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[A:%.*]]) #[[ATTR1:[0-9]+]] {
; CGSCC-NEXT: [[X:%.*]] = call i32 @callee(ptr nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[A]]) #[[ATTR2:[0-9]+]]
Expand All @@ -53,10 +53,10 @@ define i32 @foo(ptr %A) {
}

;.
; TUNIT: attributes #[[ATTR0]] = { nofree norecurse nosync nounwind willreturn memory(argmem: read) }
; TUNIT: attributes #[[ATTR0]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read) }
; TUNIT: attributes #[[ATTR1]] = { nofree nosync nounwind willreturn }
;.
; CGSCC: attributes #[[ATTR0]] = { nofree norecurse nosync nounwind willreturn memory(argmem: read) }
; CGSCC: attributes #[[ATTR1]] = { nofree nosync nounwind willreturn memory(argmem: read) }
; CGSCC: attributes #[[ATTR0]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read) }
; CGSCC: attributes #[[ATTR1]] = { mustprogress nofree nosync nounwind willreturn memory(argmem: read) }
; CGSCC: attributes #[[ATTR2]] = { willreturn }
;.
Expand Up @@ -3,7 +3,7 @@
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,CGSCC

define internal fastcc i32 @hash(ptr %ts, i32 %mod) nounwind {
; CGSCC: Function Attrs: nofree norecurse noreturn nosync nounwind willreturn memory(none)
; CGSCC: Function Attrs: mustprogress nofree norecurse noreturn nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define {{[^@]+}}@hash
; CGSCC-SAME: () #[[ATTR0:[0-9]+]] {
; CGSCC-NEXT: entry:
Expand All @@ -14,13 +14,13 @@ entry:
}

define void @encode(ptr %m, ptr %ts, ptr %new) nounwind {
; TUNIT: Function Attrs: nofree norecurse noreturn nosync nounwind willreturn memory(none)
; TUNIT: Function Attrs: mustprogress nofree norecurse noreturn nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define {{[^@]+}}@encode
; TUNIT-SAME: (ptr nocapture nofree readnone [[M:%.*]], ptr nocapture nofree readnone [[TS:%.*]], ptr nocapture nofree readnone [[NEW:%.*]]) #[[ATTR0:[0-9]+]] {
; TUNIT-NEXT: entry:
; TUNIT-NEXT: unreachable
;
; CGSCC: Function Attrs: nofree noreturn nosync nounwind willreturn memory(none)
; CGSCC: Function Attrs: mustprogress nofree noreturn nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define {{[^@]+}}@encode
; CGSCC-SAME: (ptr nocapture nofree readnone [[M:%.*]], ptr nocapture nofree readnone [[TS:%.*]], ptr nocapture nofree readnone [[NEW:%.*]]) #[[ATTR1:[0-9]+]] {
; CGSCC-NEXT: entry:
Expand All @@ -31,10 +31,10 @@ entry:
unreachable
}
;.
; TUNIT: attributes #[[ATTR0]] = { nofree norecurse noreturn nosync nounwind willreturn memory(none) }
; TUNIT: attributes #[[ATTR0]] = { mustprogress nofree norecurse noreturn nosync nounwind willreturn memory(none) }
;.
; CGSCC: attributes #[[ATTR0]] = { nofree norecurse noreturn nosync nounwind willreturn memory(none) }
; CGSCC: attributes #[[ATTR1]] = { nofree noreturn nosync nounwind willreturn memory(none) }
; CGSCC: attributes #[[ATTR0]] = { mustprogress nofree norecurse noreturn nosync nounwind willreturn memory(none) }
; CGSCC: attributes #[[ATTR1]] = { mustprogress nofree noreturn nosync nounwind willreturn memory(none) }
;.
;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
; CHECK: {{.*}}
Expand Up @@ -3,7 +3,7 @@
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,CGSCC

define internal fastcc i32 @term_SharingList(ptr %Term, ptr %List) nounwind {
; CGSCC: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define {{[^@]+}}@term_SharingList
; CGSCC-SAME: () #[[ATTR0:[0-9]+]] {
; CGSCC-NEXT: entry:
Expand All @@ -25,7 +25,7 @@ bb5: ; preds = %entry
}

define i32 @term_Sharing(ptr %Term) nounwind {
; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define {{[^@]+}}@term_Sharing
; CHECK-SAME: (ptr nocapture nofree readnone [[TERM:%.*]]) #[[ATTR0:[0-9]+]] {
; CHECK-NEXT: entry:
Expand All @@ -46,7 +46,7 @@ bb14: ; preds = %entry
ret i32 0
}
;.
; CHECK: attributes #[[ATTR0]] = { nofree norecurse nosync nounwind willreturn memory(none) }
; CHECK: attributes #[[ATTR0]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) }
;.
;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
; TUNIT: {{.*}}
20 changes: 10 additions & 10 deletions llvm/test/Transforms/Attributor/ArgumentPromotion/X86/attributes.ll
Expand Up @@ -7,7 +7,7 @@
target triple = "x86_64-unknown-linux-gnu"

define internal fastcc void @no_promote_avx2(ptr %arg, ptr readonly %arg1) #0 {
; CHECK: Function Attrs: inlinehint nofree norecurse nosync nounwind willreturn memory(argmem: readwrite) uwtable
; CHECK: Function Attrs: inlinehint mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite) uwtable
; CHECK-LABEL: define {{[^@]+}}@no_promote_avx2
; CHECK-SAME: (ptr noalias nocapture nofree noundef nonnull writeonly align 32 dereferenceable(32) [[ARG:%.*]], ptr noalias nocapture nofree noundef nonnull readonly align 32 dereferenceable(32) [[ARG1:%.*]]) #[[ATTR0:[0-9]+]] {
; CHECK-NEXT: bb:
Expand All @@ -22,7 +22,7 @@ bb:
}

define void @no_promote(ptr %arg) #1 {
; TUNIT: Function Attrs: nofree norecurse nosync nounwind willreturn memory(argmem: readwrite) uwtable
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite) uwtable
; TUNIT-LABEL: define {{[^@]+}}@no_promote
; TUNIT-SAME: (ptr nocapture nofree writeonly [[ARG:%.*]]) #[[ATTR1:[0-9]+]] {
; TUNIT-NEXT: bb:
Expand All @@ -34,7 +34,7 @@ define void @no_promote(ptr %arg) #1 {
; TUNIT-NEXT: store <4 x i64> [[TMP4]], ptr [[ARG]], align 2
; TUNIT-NEXT: ret void
;
; CGSCC: Function Attrs: nofree nosync nounwind willreturn memory(argmem: readwrite) uwtable
; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(argmem: readwrite) uwtable
; CGSCC-LABEL: define {{[^@]+}}@no_promote
; CGSCC-SAME: (ptr nocapture nofree noundef nonnull writeonly align 2 dereferenceable(32) [[ARG:%.*]]) #[[ATTR1:[0-9]+]] {
; CGSCC-NEXT: bb:
Expand All @@ -57,7 +57,7 @@ bb:
}

define internal fastcc void @promote_avx2(ptr %arg, ptr readonly %arg1) #0 {
; CHECK: Function Attrs: inlinehint nofree norecurse nosync nounwind willreturn memory(argmem: readwrite) uwtable
; CHECK: Function Attrs: inlinehint mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite) uwtable
; CHECK-LABEL: define {{[^@]+}}@promote_avx2
; CHECK-SAME: (ptr noalias nocapture nofree noundef nonnull writeonly align 32 dereferenceable(32) [[ARG:%.*]], <4 x i64> [[TMP0:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: bb:
Expand All @@ -74,7 +74,7 @@ bb:
}

define void @promote(ptr %arg) #0 {
; TUNIT: Function Attrs: inlinehint nofree norecurse nosync nounwind willreturn memory(argmem: readwrite) uwtable
; TUNIT: Function Attrs: inlinehint mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite) uwtable
; TUNIT-LABEL: define {{[^@]+}}@promote
; TUNIT-SAME: (ptr nocapture nofree writeonly [[ARG:%.*]]) #[[ATTR0]] {
; TUNIT-NEXT: bb:
Expand All @@ -87,7 +87,7 @@ define void @promote(ptr %arg) #0 {
; TUNIT-NEXT: store <4 x i64> [[TMP4]], ptr [[ARG]], align 2
; TUNIT-NEXT: ret void
;
; CGSCC: Function Attrs: inlinehint nofree norecurse nosync nounwind willreturn memory(argmem: readwrite) uwtable
; CGSCC: Function Attrs: inlinehint mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite) uwtable
; CGSCC-LABEL: define {{[^@]+}}@promote
; CGSCC-SAME: (ptr nocapture nofree noundef nonnull writeonly align 2 dereferenceable(32) [[ARG:%.*]]) #[[ATTR0]] {
; CGSCC-NEXT: bb:
Expand Down Expand Up @@ -117,14 +117,14 @@ attributes #0 = { inlinehint norecurse nounwind uwtable "target-features"="+avx2
attributes #1 = { nounwind uwtable }
attributes #2 = { argmemonly nounwind }
;.
; TUNIT: attributes #[[ATTR0]] = { inlinehint nofree norecurse nosync nounwind willreturn memory(argmem: readwrite) uwtable "target-features"="+avx2" }
; TUNIT: attributes #[[ATTR1]] = { nofree norecurse nosync nounwind willreturn memory(argmem: readwrite) uwtable }
; TUNIT: attributes #[[ATTR0]] = { inlinehint mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite) uwtable "target-features"="+avx2" }
; TUNIT: attributes #[[ATTR1]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite) uwtable }
; TUNIT: attributes #[[ATTR2:[0-9]+]] = { nocallback nofree nounwind willreturn memory(argmem: write) }
; TUNIT: attributes #[[ATTR3]] = { willreturn }
; TUNIT: attributes #[[ATTR4]] = { nofree nosync nounwind willreturn }
;.
; CGSCC: attributes #[[ATTR0]] = { inlinehint nofree norecurse nosync nounwind willreturn memory(argmem: readwrite) uwtable "target-features"="+avx2" }
; CGSCC: attributes #[[ATTR1]] = { nofree nosync nounwind willreturn memory(argmem: readwrite) uwtable }
; CGSCC: attributes #[[ATTR0]] = { inlinehint mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite) uwtable "target-features"="+avx2" }
; CGSCC: attributes #[[ATTR1]] = { mustprogress nofree nosync nounwind willreturn memory(argmem: readwrite) uwtable }
; CGSCC: attributes #[[ATTR2:[0-9]+]] = { nocallback nofree nounwind willreturn memory(argmem: write) }
; CGSCC: attributes #[[ATTR3]] = { willreturn }
; CGSCC: attributes #[[ATTR4]] = { nounwind willreturn }
Expand Down

0 comments on commit dbbe9b3

Please sign in to comment.