[llvm] c42aa1b - [Attributor] Keep loads feeding in `llvm.assume` if stores stays
Johannes Doerfert via llvm-commits
llvm-commits at lists.llvm.org
Tue Apr 5 21:07:40 PDT 2022
Author: Johannes Doerfert
Date: 2022-04-05T23:07:12-05:00
New Revision: c42aa1be74cbe457779ae185b9d2c0fe0fa06fd9
URL: https://github.com/llvm/llvm-project/commit/c42aa1be74cbe457779ae185b9d2c0fe0fa06fd9
DIFF: https://github.com/llvm/llvm-project/commit/c42aa1be74cbe457779ae185b9d2c0fe0fa06fd9.diff
LOG: [Attributor] Keep loads feeding in `llvm.assume` if stores stays
If a load is only used by an `llvm.assume` and the stores feeding into
the load are not removable, keep the load.
Added:
Modified:
llvm/include/llvm/Transforms/IPO/Attributor.h
llvm/lib/Transforms/IPO/Attributor.cpp
llvm/lib/Transforms/IPO/AttributorAttributes.cpp
llvm/test/Transforms/Attributor/align.ll
llvm/test/Transforms/Attributor/value-simplify-assume.ll
Removed:
################################################################################
diff --git a/llvm/include/llvm/Transforms/IPO/Attributor.h b/llvm/include/llvm/Transforms/IPO/Attributor.h
index 9b77ba538b06c..8eb054c4dfc83 100644
--- a/llvm/include/llvm/Transforms/IPO/Attributor.h
+++ b/llvm/include/llvm/Transforms/IPO/Attributor.h
@@ -204,18 +204,20 @@ bool getAssumedUnderlyingObjects(Attributor &A, const Value &Ptr,
/// Collect all potential values \p LI could read into \p PotentialValues. That
/// is, the only values read by \p LI are assumed to be known and all are in
-/// \p PotentialValues. Dependences onto \p QueryingAA are properly tracked,
-/// \p UsedAssumedInformation will inform the caller if assumed information was
+/// \p PotentialValues. \p PotentialValueOrigins will contain all the
+/// instructions that might have put a potential value into \p PotentialValues.
+/// Dependences onto \p QueryingAA are properly tracked, \p
+/// UsedAssumedInformation will inform the caller if assumed information was
/// used.
///
/// \returns True if the assumed potential copies are all in \p PotentialValues,
/// false if something went wrong and the copies could not be
/// determined.
-bool getPotentiallyLoadedValues(Attributor &A, LoadInst &LI,
- SmallSetVector<Value *, 4> &PotentialValues,
- const AbstractAttribute &QueryingAA,
- bool &UsedAssumedInformation,
- bool OnlyExact = false);
+bool getPotentiallyLoadedValues(
+ Attributor &A, LoadInst &LI, SmallSetVector<Value *, 4> &PotentialValues,
+ SmallSetVector<Instruction *, 4> &PotentialValueOrigins,
+ const AbstractAttribute &QueryingAA, bool &UsedAssumedInformation,
+ bool OnlyExact = false);
/// Collect all potential values of the one stored by \p SI into
/// \p PotentialCopies. That is, the only copies that were made via the
@@ -1057,6 +1059,10 @@ struct InformationCache {
return FI.CalledViaMustTail || FI.ContainsMustTailCall;
}
+ bool isOnlyUsedByAssume(const Instruction &I) const {
+ return AssumeOnlyValues.contains(&I);
+ }
+
/// Return the analysis result from a pass \p AP for function \p F.
template <typename AP>
typename AP::Result *getAnalysisResultForFunction(const Function &F) {
@@ -1149,6 +1155,9 @@ struct InformationCache {
/// A map with knowledge retained in `llvm.assume` instructions.
RetainedKnowledgeMap KnowledgeMap;
+ /// A container for all instructions that are only used by `llvm.assume`.
+ SetVector<const Instruction *> AssumeOnlyValues;
+
/// Getters for analysis.
AnalysisGetter &AG;
@@ -3412,6 +3421,12 @@ struct AAIsDead
/// Returns true if \p I is known dead.
virtual bool isKnownDead(const Instruction *I) const = 0;
+ /// Return true if the underlying value is a store that is known to be
+ /// removable. This is
diff erent from dead stores as the removable store
+ /// can have an effect on live values, especially loads, but that effect
+ /// is propagated which allows us to remove the store in turn.
+ virtual bool isRemovableStore() const { return false; }
+
/// This method is used to check if at least one instruction in a collection
/// of instructions is live.
template <typename T> bool isLiveInstSet(T begin, T end) const {
diff --git a/llvm/lib/Transforms/IPO/Attributor.cpp b/llvm/lib/Transforms/IPO/Attributor.cpp
index 40d6cc10a5624..ac8bf46ba1286 100644
--- a/llvm/lib/Transforms/IPO/Attributor.cpp
+++ b/llvm/lib/Transforms/IPO/Attributor.cpp
@@ -322,11 +322,11 @@ AA::combineOptionalValuesInAAValueLatice(const Optional<Value *> &A,
}
template <bool IsLoad, typename Ty>
-static bool
-getPotentialCopiesOfMemoryValue(Attributor &A, Ty &I,
- SmallSetVector<Value *, 4> &PotentialCopies,
- const AbstractAttribute &QueryingAA,
- bool &UsedAssumedInformation, bool OnlyExact) {
+static bool getPotentialCopiesOfMemoryValue(
+ Attributor &A, Ty &I, SmallSetVector<Value *, 4> &PotentialCopies,
+ SmallSetVector<Instruction *, 4> &PotentialValueOrigins,
+ const AbstractAttribute &QueryingAA, bool &UsedAssumedInformation,
+ bool OnlyExact) {
LLVM_DEBUG(dbgs() << "Trying to determine the potential copies of " << I
<< " (only exact: " << OnlyExact << ")\n";);
@@ -344,6 +344,7 @@ getPotentialCopiesOfMemoryValue(Attributor &A, Ty &I,
// dependences and potential copies in the provided container.
SmallVector<const AAPointerInfo *> PIs;
SmallVector<Value *> NewCopies;
+ SmallVector<Instruction *> NewCopyOrigins;
const auto *TLI =
A.getInfoCache().getTargetLibraryInfoForFunction(*I.getFunction());
@@ -383,6 +384,7 @@ getPotentialCopiesOfMemoryValue(Attributor &A, Ty &I,
if (!InitialValue)
return false;
NewCopies.push_back(InitialValue);
+ NewCopyOrigins.push_back(nullptr);
}
auto CheckAccess = [&](const AAPointerInfo::Access &Acc, bool IsExact) {
@@ -400,6 +402,7 @@ getPotentialCopiesOfMemoryValue(Attributor &A, Ty &I,
assert(isa<LoadInst>(I) && "Expected load or store instruction only!");
if (!Acc.isWrittenValueUnknown()) {
NewCopies.push_back(Acc.getWrittenValue());
+ NewCopyOrigins.push_back(Acc.getRemoteInst());
return true;
}
auto *SI = dyn_cast<StoreInst>(Acc.getRemoteInst());
@@ -410,6 +413,7 @@ getPotentialCopiesOfMemoryValue(Attributor &A, Ty &I,
return false;
}
NewCopies.push_back(SI->getValueOperand());
+ NewCopyOrigins.push_back(SI);
} else {
assert(isa<StoreInst>(I) && "Expected load or store instruction only!");
auto *LI = dyn_cast<LoadInst>(Acc.getRemoteInst());
@@ -445,25 +449,29 @@ getPotentialCopiesOfMemoryValue(Attributor &A, Ty &I,
A.recordDependence(*PI, QueryingAA, DepClassTy::OPTIONAL);
}
PotentialCopies.insert(NewCopies.begin(), NewCopies.end());
+ PotentialValueOrigins.insert(NewCopyOrigins.begin(), NewCopyOrigins.end());
return true;
}
-bool AA::getPotentiallyLoadedValues(Attributor &A, LoadInst &LI,
- SmallSetVector<Value *, 4> &PotentialValues,
- const AbstractAttribute &QueryingAA,
- bool &UsedAssumedInformation,
- bool OnlyExact) {
+bool AA::getPotentiallyLoadedValues(
+ Attributor &A, LoadInst &LI, SmallSetVector<Value *, 4> &PotentialValues,
+ SmallSetVector<Instruction *, 4> &PotentialValueOrigins,
+ const AbstractAttribute &QueryingAA, bool &UsedAssumedInformation,
+ bool OnlyExact) {
return getPotentialCopiesOfMemoryValue</* IsLoad */ true>(
- A, LI, PotentialValues, QueryingAA, UsedAssumedInformation, OnlyExact);
+ A, LI, PotentialValues, PotentialValueOrigins, QueryingAA,
+ UsedAssumedInformation, OnlyExact);
}
bool AA::getPotentialCopiesOfStoredValue(
Attributor &A, StoreInst &SI, SmallSetVector<Value *, 4> &PotentialCopies,
const AbstractAttribute &QueryingAA, bool &UsedAssumedInformation,
bool OnlyExact) {
+ SmallSetVector<Instruction *, 4> PotentialValueOrigins;
return getPotentialCopiesOfMemoryValue</* IsLoad */ false>(
- A, SI, PotentialCopies, QueryingAA, UsedAssumedInformation, OnlyExact);
+ A, SI, PotentialCopies, PotentialValueOrigins, QueryingAA,
+ UsedAssumedInformation, OnlyExact);
}
static bool isAssumedReadOnlyOrReadNone(Attributor &A, const IRPosition &IRP,
@@ -1152,6 +1160,19 @@ bool Attributor::isAssumedDead(const Use &U,
BasicBlock *IncomingBB = PHI->getIncomingBlock(U);
return isAssumedDead(*IncomingBB->getTerminator(), QueryingAA, FnLivenessAA,
UsedAssumedInformation, CheckBBLivenessOnly, DepClass);
+ } else if (StoreInst *SI = dyn_cast<StoreInst>(UserI)) {
+ if (!CheckBBLivenessOnly && SI->getPointerOperand() != U.get()) {
+ const IRPosition IRP = IRPosition::inst(*SI);
+ const AAIsDead &IsDeadAA =
+ getOrCreateAAFor<AAIsDead>(IRP, QueryingAA, DepClassTy::NONE);
+ if (IsDeadAA.isRemovableStore()) {
+ if (QueryingAA)
+ recordDependence(IsDeadAA, *QueryingAA, DepClass);
+ if (!IsDeadAA.isKnown(AAIsDead::IS_REMOVABLE))
+ UsedAssumedInformation = true;
+ return true;
+ }
+ }
}
return isAssumedDead(IRPosition::inst(*UserI), QueryingAA, FnLivenessAA,
@@ -2655,6 +2676,30 @@ void InformationCache::initializeInformationCache(const Function &CF,
// queried by abstract attributes during their initialization or update.
// This has to happen before we create attributes.
+ DenseMap<const Value *, Optional<short>> AssumeUsesMap;
+
+ // Add \p V to the assume uses map which track the number of uses outside of
+ // "visited" assumes. If no outside uses are left the value is added to the
+ // assume only use vector.
+ auto AddToAssumeUsesMap = [&](const Value &V) -> void {
+ SmallVector<const Instruction *> Worklist;
+ if (auto *I = dyn_cast<Instruction>(&V))
+ Worklist.push_back(I);
+ while (!Worklist.empty()) {
+ const Instruction *I = Worklist.pop_back_val();
+ Optional<short> &NumUses = AssumeUsesMap[I];
+ if (!NumUses.hasValue())
+ NumUses = I->getNumUses();
+ NumUses = NumUses.getValue() - /* this assume */ 1;
+ if (NumUses.getValue() != 0)
+ continue;
+ AssumeOnlyValues.insert(I);
+ for (const Value *Op : I->operands())
+ if (auto *OpI = dyn_cast<Instruction>(Op))
+ Worklist.push_back(OpI);
+ }
+ };
+
for (Instruction &I : instructions(&F)) {
bool IsInterestingOpcode = false;
@@ -2675,6 +2720,7 @@ void InformationCache::initializeInformationCache(const Function &CF,
// For `must-tail` calls we remember the caller and callee.
if (auto *Assume = dyn_cast<AssumeInst>(&I)) {
fillMapFromAssume(*Assume, KnowledgeMap);
+ AddToAssumeUsesMap(*Assume->getArgOperand(0));
} else if (cast<CallInst>(I).isMustTailCall()) {
FI.ContainsMustTailCall = true;
if (const Function *Callee = cast<CallInst>(I).getCalledFunction())
diff --git a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
index 4610ec7b90c88..8151bd5ebc572 100644
--- a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
+++ b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
@@ -409,9 +409,11 @@ static bool genericValueTraversal(
// will simply end up here again. The load is as far as we can make it.
if (LI->getPointerOperand() != InitialV) {
SmallSetVector<Value *, 4> PotentialCopies;
- if (AA::getPotentiallyLoadedValues(A, *LI, PotentialCopies, QueryingAA,
- UsedAssumedInformation,
- /* OnlyExact */ true)) {
+ SmallSetVector<Instruction *, 4> PotentialValueOrigins;
+ if (AA::getPotentiallyLoadedValues(A, *LI, PotentialCopies,
+ PotentialValueOrigins, QueryingAA,
+ UsedAssumedInformation,
+ /* OnlyExact */ true)) {
// Values have to be dynamically unique or we loose the fact that a
// single llvm::Value might represent two runtime values (e.g., stack
// locations in
diff erent recursive calls).
@@ -421,9 +423,9 @@ static bool genericValueTraversal(
});
if (DynamicallyUnique &&
(!Intraprocedural || !CtxI ||
- llvm::all_of(PotentialCopies, [CtxI](Value *PC) {
- return AA::isValidInScope(*PC, CtxI->getFunction());
- }))) {
+ llvm::all_of(PotentialCopies, [CtxI](Value *PC) {
+ return AA::isValidInScope(*PC, CtxI->getFunction());
+ }))) {
for (auto *PotentialCopy : PotentialCopies)
Worklist.push_back({PotentialCopy, CtxI});
continue;
@@ -3611,6 +3613,10 @@ struct AAIsDeadFloating : public AAIsDeadValueImpl {
return ChangeStatus::UNCHANGED;
}
+ bool isRemovableStore() const override {
+ return isAssumed(IS_REMOVABLE) && isa<StoreInst>(&getAssociatedValue());
+ }
+
/// See AbstractAttribute::manifest(...).
ChangeStatus manifest(Attributor &A) override {
Value &V = getAssociatedValue();
@@ -5670,6 +5676,36 @@ struct AAValueSimplifyFloating : AAValueSimplifyImpl {
ChangeStatus updateImpl(Attributor &A) override {
auto Before = SimplifiedAssociatedValue;
+ // Do not simplify loads that are only used in llvm.assume if we cannot also
+ // remove all stores that may feed into the load. The reason is that the
+ // assume is probably worth something as long as the stores are around.
+ if (auto *LI = dyn_cast<LoadInst>(&getAssociatedValue())) {
+ InformationCache &InfoCache = A.getInfoCache();
+ if (InfoCache.isOnlyUsedByAssume(*LI)) {
+ SmallSetVector<Value *, 4> PotentialCopies;
+ SmallSetVector<Instruction *, 4> PotentialValueOrigins;
+ bool UsedAssumedInformation = false;
+ if (AA::getPotentiallyLoadedValues(A, *LI, PotentialCopies,
+ PotentialValueOrigins, *this,
+ UsedAssumedInformation,
+ /* OnlyExact */ true)) {
+ if (!llvm::all_of(PotentialValueOrigins, [&](Instruction *I) {
+ if (!I)
+ return true;
+ if (auto *SI = dyn_cast<StoreInst>(I))
+ return A.isAssumedDead(SI->getOperandUse(0), this,
+ /* LivenessAA */ nullptr,
+ UsedAssumedInformation,
+ /* CheckBBLivenessOnly */ false);
+ return A.isAssumedDead(*I, this, /* LivenessAA */ nullptr,
+ UsedAssumedInformation,
+ /* CheckBBLivenessOnly */ false);
+ }))
+ return indicatePessimisticFixpoint();
+ }
+ }
+ }
+
auto VisitValueCB = [&](Value &V, const Instruction *CtxI, bool &,
bool Stripped) -> bool {
auto &AA = A.getAAFor<AAValueSimplify>(
diff --git a/llvm/test/Transforms/Attributor/align.ll b/llvm/test/Transforms/Attributor/align.ll
index a45356e953915..e3fb1a7096208 100644
--- a/llvm/test/Transforms/Attributor/align.ll
+++ b/llvm/test/Transforms/Attributor/align.ll
@@ -1,6 +1,6 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals
-; RUN: opt -attributor -enable-new-pm=0 -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=4 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
-; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=4 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
+; RUN: opt -attributor -enable-new-pm=0 -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=6 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
+; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=6 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -enable-new-pm=0 -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
diff --git a/llvm/test/Transforms/Attributor/value-simplify-assume.ll b/llvm/test/Transforms/Attributor/value-simplify-assume.ll
index 69dcc515ab0b3..b6a953b9b003f 100644
--- a/llvm/test/Transforms/Attributor/value-simplify-assume.ll
+++ b/llvm/test/Transforms/Attributor/value-simplify-assume.ll
@@ -1,6 +1,6 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals
-; RUN: opt -attributor -enable-new-pm=0 -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=3 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
-; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=3 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
+; RUN: opt -attributor -enable-new-pm=0 -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=4 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
+; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=4 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -enable-new-pm=0 -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
@@ -244,7 +244,8 @@ define void @assume_1b_nr(i1 %arg, i1 %cond) norecurse {
; CHECK-SAME: (i1 [[ARG:%.*]], i1 [[COND:%.*]]) #[[ATTR3]] {
; CHECK-NEXT: [[STACK:%.*]] = alloca i1, align 1
; CHECK-NEXT: store i1 [[ARG]], i1* [[STACK]], align 1
-; CHECK-NEXT: call void @llvm.assume(i1 noundef [[ARG]]) #[[ATTR4]]
+; CHECK-NEXT: [[L:%.*]] = load i1, i1* [[STACK]], align 1
+; CHECK-NEXT: call void @llvm.assume(i1 noundef [[L]]) #[[ATTR4]]
; CHECK-NEXT: br i1 [[COND]], label [[T:%.*]], label [[F:%.*]]
; CHECK: t:
; CHECK-NEXT: br label [[M:%.*]]
@@ -340,7 +341,8 @@ define i1 @assume_3_nr(i1 %arg, i1 %cond) norecurse {
; CHECK-SAME: (i1 [[ARG:%.*]], i1 [[COND:%.*]]) #[[ATTR3]] {
; CHECK-NEXT: [[STACK:%.*]] = alloca i1, align 1
; CHECK-NEXT: store i1 [[ARG]], i1* [[STACK]], align 1
-; CHECK-NEXT: call void @llvm.assume(i1 noundef [[ARG]]) #[[ATTR4]]
+; CHECK-NEXT: [[L:%.*]] = load i1, i1* [[STACK]], align 1
+; CHECK-NEXT: call void @llvm.assume(i1 noundef [[L]]) #[[ATTR4]]
; CHECK-NEXT: br i1 [[COND]], label [[T:%.*]], label [[F:%.*]]
; CHECK: t:
; CHECK-NEXT: store i1 true, i1* [[STACK]], align 1
@@ -404,49 +406,29 @@ m:
}
define i1 @assume_5_nr(i1 %arg, i1 %cond) norecurse {
-; IS________OPM: Function Attrs: inaccessiblememonly nofree norecurse nosync nounwind willreturn
-; IS________OPM-LABEL: define {{[^@]+}}@assume_5_nr
-; IS________OPM-SAME: (i1 [[ARG:%.*]], i1 [[COND:%.*]]) #[[ATTR3]] {
-; IS________OPM-NEXT: [[STACK:%.*]] = alloca i1, align 1
-; IS________OPM-NEXT: store i1 [[ARG]], i1* [[STACK]], align 1
-; IS________OPM-NEXT: call void @llvm.assume(i1 noundef [[ARG]]) #[[ATTR4]]
-; IS________OPM-NEXT: br i1 [[COND]], label [[T:%.*]], label [[F:%.*]]
-; IS________OPM: t:
-; IS________OPM-NEXT: store i1 true, i1* [[STACK]], align 1
-; IS________OPM-NEXT: [[L2:%.*]] = load i1, i1* [[STACK]], align 1
-; IS________OPM-NEXT: call void @llvm.assume(i1 noundef [[L2]]) #[[ATTR4]]
-; IS________OPM-NEXT: br label [[M:%.*]]
-; IS________OPM: f:
-; IS________OPM-NEXT: store i1 false, i1* [[STACK]], align 1
-; IS________OPM-NEXT: [[L3:%.*]] = load i1, i1* [[STACK]], align 1
-; IS________OPM-NEXT: call void @llvm.assume(i1 noundef [[L3]]) #[[ATTR4]]
-; IS________OPM-NEXT: br label [[M]]
-; IS________OPM: m:
-; IS________OPM-NEXT: [[L4:%.*]] = load i1, i1* [[STACK]], align 1
-; IS________OPM-NEXT: call void @llvm.assume(i1 noundef [[L4]]) #[[ATTR4]]
-; IS________OPM-NEXT: [[R:%.*]] = call i1 @readI1p(i1* noalias nocapture nofree noundef nonnull readonly dereferenceable(1) [[STACK]]) #[[ATTR5]]
-; IS________OPM-NEXT: ret i1 [[R]]
-;
-; IS________NPM: Function Attrs: inaccessiblememonly nofree norecurse nosync nounwind willreturn
-; IS________NPM-LABEL: define {{[^@]+}}@assume_5_nr
-; IS________NPM-SAME: (i1 [[ARG:%.*]], i1 [[COND:%.*]]) #[[ATTR3]] {
-; IS________NPM-NEXT: [[STACK:%.*]] = alloca i1, align 1
-; IS________NPM-NEXT: store i1 [[ARG]], i1* [[STACK]], align 1
-; IS________NPM-NEXT: call void @llvm.assume(i1 noundef [[ARG]]) #[[ATTR4]]
-; IS________NPM-NEXT: br i1 [[COND]], label [[T:%.*]], label [[F:%.*]]
-; IS________NPM: t:
-; IS________NPM-NEXT: store i1 true, i1* [[STACK]], align 1
-; IS________NPM-NEXT: call void @llvm.assume(i1 noundef true) #[[ATTR4]]
-; IS________NPM-NEXT: br label [[M:%.*]]
-; IS________NPM: f:
-; IS________NPM-NEXT: store i1 false, i1* [[STACK]], align 1
-; IS________NPM-NEXT: call void @llvm.assume(i1 noundef false) #[[ATTR4]]
-; IS________NPM-NEXT: br label [[M]]
-; IS________NPM: m:
-; IS________NPM-NEXT: [[L4:%.*]] = load i1, i1* [[STACK]], align 1
-; IS________NPM-NEXT: call void @llvm.assume(i1 noundef [[L4]]) #[[ATTR4]]
-; IS________NPM-NEXT: [[R:%.*]] = call i1 @readI1p(i1* noalias nocapture nofree noundef nonnull readonly dereferenceable(1) [[STACK]]) #[[ATTR5]]
-; IS________NPM-NEXT: ret i1 [[R]]
+; CHECK: Function Attrs: inaccessiblememonly nofree norecurse nosync nounwind willreturn
+; CHECK-LABEL: define {{[^@]+}}@assume_5_nr
+; CHECK-SAME: (i1 [[ARG:%.*]], i1 [[COND:%.*]]) #[[ATTR3]] {
+; CHECK-NEXT: [[STACK:%.*]] = alloca i1, align 1
+; CHECK-NEXT: store i1 [[ARG]], i1* [[STACK]], align 1
+; CHECK-NEXT: [[L1:%.*]] = load i1, i1* [[STACK]], align 1
+; CHECK-NEXT: call void @llvm.assume(i1 noundef [[L1]]) #[[ATTR4]]
+; CHECK-NEXT: br i1 [[COND]], label [[T:%.*]], label [[F:%.*]]
+; CHECK: t:
+; CHECK-NEXT: store i1 true, i1* [[STACK]], align 1
+; CHECK-NEXT: [[L2:%.*]] = load i1, i1* [[STACK]], align 1
+; CHECK-NEXT: call void @llvm.assume(i1 noundef [[L2]]) #[[ATTR4]]
+; CHECK-NEXT: br label [[M:%.*]]
+; CHECK: f:
+; CHECK-NEXT: store i1 false, i1* [[STACK]], align 1
+; CHECK-NEXT: [[L3:%.*]] = load i1, i1* [[STACK]], align 1
+; CHECK-NEXT: call void @llvm.assume(i1 noundef [[L3]]) #[[ATTR4]]
+; CHECK-NEXT: br label [[M]]
+; CHECK: m:
+; CHECK-NEXT: [[L4:%.*]] = load i1, i1* [[STACK]], align 1
+; CHECK-NEXT: call void @llvm.assume(i1 noundef [[L4]]) #[[ATTR4]]
+; CHECK-NEXT: [[R:%.*]] = call i1 @readI1p(i1* noalias nocapture nofree noundef nonnull readonly dereferenceable(1) [[STACK]]) #[[ATTR5]]
+; CHECK-NEXT: ret i1 [[R]]
;
%stack = alloca i1
store i1 %arg, i1* %stack
@@ -471,48 +453,29 @@ m:
}
define i1 @assume_5c_nr(i1 %cond) norecurse {
-; IS________OPM: Function Attrs: inaccessiblememonly nofree norecurse nosync nounwind willreturn
-; IS________OPM-LABEL: define {{[^@]+}}@assume_5c_nr
-; IS________OPM-SAME: (i1 [[COND:%.*]]) #[[ATTR3]] {
-; IS________OPM-NEXT: [[STACK:%.*]] = alloca i1, align 1
-; IS________OPM-NEXT: store i1 true, i1* [[STACK]], align 1
-; IS________OPM-NEXT: call void @llvm.assume(i1 noundef true) #[[ATTR4]]
-; IS________OPM-NEXT: br i1 [[COND]], label [[T:%.*]], label [[F:%.*]]
-; IS________OPM: t:
-; IS________OPM-NEXT: store i1 true, i1* [[STACK]], align 1
-; IS________OPM-NEXT: call void @llvm.assume(i1 noundef true) #[[ATTR4]]
-; IS________OPM-NEXT: br label [[M:%.*]]
-; IS________OPM: f:
-; IS________OPM-NEXT: store i1 false, i1* [[STACK]], align 1
-; IS________OPM-NEXT: [[L3:%.*]] = load i1, i1* [[STACK]], align 1
-; IS________OPM-NEXT: call void @llvm.assume(i1 noundef [[L3]]) #[[ATTR4]]
-; IS________OPM-NEXT: br label [[M]]
-; IS________OPM: m:
-; IS________OPM-NEXT: [[L4:%.*]] = load i1, i1* [[STACK]], align 1
-; IS________OPM-NEXT: call void @llvm.assume(i1 noundef [[L4]]) #[[ATTR4]]
-; IS________OPM-NEXT: [[R:%.*]] = call i1 @readI1p(i1* noalias nocapture nofree noundef nonnull readonly dereferenceable(1) [[STACK]]) #[[ATTR5]]
-; IS________OPM-NEXT: ret i1 [[R]]
-;
-; IS________NPM: Function Attrs: inaccessiblememonly nofree norecurse nosync nounwind willreturn
-; IS________NPM-LABEL: define {{[^@]+}}@assume_5c_nr
-; IS________NPM-SAME: (i1 [[COND:%.*]]) #[[ATTR3]] {
-; IS________NPM-NEXT: [[STACK:%.*]] = alloca i1, align 1
-; IS________NPM-NEXT: store i1 true, i1* [[STACK]], align 1
-; IS________NPM-NEXT: call void @llvm.assume(i1 noundef true) #[[ATTR4]]
-; IS________NPM-NEXT: br i1 [[COND]], label [[T:%.*]], label [[F:%.*]]
-; IS________NPM: t:
-; IS________NPM-NEXT: store i1 true, i1* [[STACK]], align 1
-; IS________NPM-NEXT: call void @llvm.assume(i1 noundef true) #[[ATTR4]]
-; IS________NPM-NEXT: br label [[M:%.*]]
-; IS________NPM: f:
-; IS________NPM-NEXT: store i1 false, i1* [[STACK]], align 1
-; IS________NPM-NEXT: call void @llvm.assume(i1 noundef false) #[[ATTR4]]
-; IS________NPM-NEXT: br label [[M]]
-; IS________NPM: m:
-; IS________NPM-NEXT: [[L4:%.*]] = load i1, i1* [[STACK]], align 1
-; IS________NPM-NEXT: call void @llvm.assume(i1 noundef [[L4]]) #[[ATTR4]]
-; IS________NPM-NEXT: [[R:%.*]] = call i1 @readI1p(i1* noalias nocapture nofree noundef nonnull readonly dereferenceable(1) [[STACK]]) #[[ATTR5]]
-; IS________NPM-NEXT: ret i1 [[R]]
+; CHECK: Function Attrs: inaccessiblememonly nofree norecurse nosync nounwind willreturn
+; CHECK-LABEL: define {{[^@]+}}@assume_5c_nr
+; CHECK-SAME: (i1 [[COND:%.*]]) #[[ATTR3]] {
+; CHECK-NEXT: [[STACK:%.*]] = alloca i1, align 1
+; CHECK-NEXT: store i1 true, i1* [[STACK]], align 1
+; CHECK-NEXT: [[L1:%.*]] = load i1, i1* [[STACK]], align 1
+; CHECK-NEXT: call void @llvm.assume(i1 noundef [[L1]]) #[[ATTR4]]
+; CHECK-NEXT: br i1 [[COND]], label [[T:%.*]], label [[F:%.*]]
+; CHECK: t:
+; CHECK-NEXT: store i1 true, i1* [[STACK]], align 1
+; CHECK-NEXT: [[L2:%.*]] = load i1, i1* [[STACK]], align 1
+; CHECK-NEXT: call void @llvm.assume(i1 noundef [[L2]]) #[[ATTR4]]
+; CHECK-NEXT: br label [[M:%.*]]
+; CHECK: f:
+; CHECK-NEXT: store i1 false, i1* [[STACK]], align 1
+; CHECK-NEXT: [[L3:%.*]] = load i1, i1* [[STACK]], align 1
+; CHECK-NEXT: call void @llvm.assume(i1 noundef [[L3]]) #[[ATTR4]]
+; CHECK-NEXT: br label [[M]]
+; CHECK: m:
+; CHECK-NEXT: [[L4:%.*]] = load i1, i1* [[STACK]], align 1
+; CHECK-NEXT: call void @llvm.assume(i1 noundef [[L4]]) #[[ATTR4]]
+; CHECK-NEXT: [[R:%.*]] = call i1 @readI1p(i1* noalias nocapture nofree noundef nonnull readonly dereferenceable(1) [[STACK]]) #[[ATTR5]]
+; CHECK-NEXT: ret i1 [[R]]
;
%stack = alloca i1
store i1 true, i1* %stack
@@ -750,7 +713,8 @@ define void @assume_1b(i1 %arg, i1 %cond) {
; CHECK-SAME: (i1 [[ARG:%.*]], i1 [[COND:%.*]]) #[[ATTR3]] {
; CHECK-NEXT: [[STACK:%.*]] = alloca i1, align 1
; CHECK-NEXT: store i1 [[ARG]], i1* [[STACK]], align 1
-; CHECK-NEXT: call void @llvm.assume(i1 noundef [[ARG]]) #[[ATTR4]]
+; CHECK-NEXT: [[L:%.*]] = load i1, i1* [[STACK]], align 1
+; CHECK-NEXT: call void @llvm.assume(i1 noundef [[L]]) #[[ATTR4]]
; CHECK-NEXT: br i1 [[COND]], label [[T:%.*]], label [[F:%.*]]
; CHECK: t:
; CHECK-NEXT: br label [[M:%.*]]
@@ -846,7 +810,8 @@ define i1 @assume_3(i1 %arg, i1 %cond) {
; CHECK-SAME: (i1 [[ARG:%.*]], i1 [[COND:%.*]]) #[[ATTR3]] {
; CHECK-NEXT: [[STACK:%.*]] = alloca i1, align 1
; CHECK-NEXT: store i1 [[ARG]], i1* [[STACK]], align 1
-; CHECK-NEXT: call void @llvm.assume(i1 noundef [[ARG]]) #[[ATTR4]]
+; CHECK-NEXT: [[L:%.*]] = load i1, i1* [[STACK]], align 1
+; CHECK-NEXT: call void @llvm.assume(i1 noundef [[L]]) #[[ATTR4]]
; CHECK-NEXT: br i1 [[COND]], label [[T:%.*]], label [[F:%.*]]
; CHECK: t:
; CHECK-NEXT: store i1 true, i1* [[STACK]], align 1
@@ -915,7 +880,8 @@ define i1 @assume_5(i1 %arg, i1 %cond) {
; CHECK-SAME: (i1 [[ARG:%.*]], i1 [[COND:%.*]]) #[[ATTR3]] {
; CHECK-NEXT: [[STACK:%.*]] = alloca i1, align 1
; CHECK-NEXT: store i1 [[ARG]], i1* [[STACK]], align 1
-; CHECK-NEXT: call void @llvm.assume(i1 noundef [[ARG]]) #[[ATTR4]]
+; CHECK-NEXT: [[L1:%.*]] = load i1, i1* [[STACK]], align 1
+; CHECK-NEXT: call void @llvm.assume(i1 noundef [[L1]]) #[[ATTR4]]
; CHECK-NEXT: br i1 [[COND]], label [[T:%.*]], label [[F:%.*]]
; CHECK: t:
; CHECK-NEXT: store i1 true, i1* [[STACK]], align 1
@@ -961,11 +927,13 @@ define i1 @assume_5c(i1 %cond) {
; CHECK-SAME: (i1 [[COND:%.*]]) #[[ATTR3]] {
; CHECK-NEXT: [[STACK:%.*]] = alloca i1, align 1
; CHECK-NEXT: store i1 true, i1* [[STACK]], align 1
-; CHECK-NEXT: call void @llvm.assume(i1 noundef true) #[[ATTR4]]
+; CHECK-NEXT: [[L1:%.*]] = load i1, i1* [[STACK]], align 1
+; CHECK-NEXT: call void @llvm.assume(i1 noundef [[L1]]) #[[ATTR4]]
; CHECK-NEXT: br i1 [[COND]], label [[T:%.*]], label [[F:%.*]]
; CHECK: t:
; CHECK-NEXT: store i1 true, i1* [[STACK]], align 1
-; CHECK-NEXT: call void @llvm.assume(i1 noundef true) #[[ATTR4]]
+; CHECK-NEXT: [[L2:%.*]] = load i1, i1* [[STACK]], align 1
+; CHECK-NEXT: call void @llvm.assume(i1 noundef [[L2]]) #[[ATTR4]]
; CHECK-NEXT: br label [[M:%.*]]
; CHECK: f:
; CHECK-NEXT: store i1 false, i1* [[STACK]], align 1
More information about the llvm-commits
mailing list