virtual bool forallInterferingAccesses(
StoreInst &SI, function_ref<bool(const Access &, bool)> CB) const = 0;
+ /// Call \p CB on all write accesses that might interfere with \p LI and
+ /// return true if all such accesses were known and the callback returned true
+ /// for all of them, false otherwise. In contrast to forallInterferingAccesses
+ /// this function will perform reasoning to exclude write accesses that cannot
+ /// affect the load even if they on the surface look as if they would.
+ virtual bool forallInterferingWrites(
+ Attributor &A, const AbstractAttribute &QueryingAA, LoadInst &LI,
+ function_ref<bool(const Access &, bool)> CB) const = 0;
+
/// This function should return true if the type of the \p AA is AAPointerInfo
static bool classof(const AbstractAttribute *AA) {
return (AA->getIdAddr() == &ID);
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/SCCIterator.h"
#include "llvm/ADT/SetOperations.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Analysis/AliasAnalysis.h"
cl::location(llvm::PotentialConstantIntValuesState::MaxPotentialValues),
cl::init(7));
+static cl::opt<unsigned>
+ MaxInterferingWrites("attributor-max-interfering-writes", cl::Hidden,
+ cl::desc("Maximum number of interfering writes to "
+ "check before assuming all might interfere."),
+ cl::init(6));
+
STATISTIC(NumAAs, "Number of abstract attributes created");
// Some helper macros to deal with statistics tracking.
const override {
return State::forallInterferingAccesses(SI, CB);
}
+ bool forallInterferingWrites(
+ Attributor &A, const AbstractAttribute &QueryingAA, LoadInst &LI,
+ function_ref<bool(const Access &, bool)> UserCB) const override {
+ SmallPtrSet<const Access *, 8> DominatingWrites;
+ SmallVector<std::pair<const Access *, bool>, 8> InterferingWrites;
+
+ Function &Scope = *LI.getFunction();
+ const auto &NoSyncAA = A.getAAFor<AANoSync>(
+ QueryingAA, IRPosition::function(Scope), DepClassTy::OPTIONAL);
+ const auto *ExecDomainAA = A.lookupAAFor<AAExecutionDomain>(
+ IRPosition::function(Scope), &QueryingAA, DepClassTy::OPTIONAL);
+ const bool NoSync = NoSyncAA.isAssumedNoSync();
+
+ // Helper to determine if we need to consider threading, which we cannot
+ // right now. However, if the function is (assumed) nosync or the thread
+ // executing all instructions is the main thread only we can ignore
+ // threading.
+ auto CanIgnoreThreading = [&](const Instruction &I) -> bool {
+ if (NoSync)
+ return true;
+ if (ExecDomainAA && ExecDomainAA->isExecutedByInitialThreadOnly(I))
+ return true;
+ return false;
+ };
+
+ // Helper to determine if the access is executed by the same thread as the
+ // load, for now it is sufficient to avoid any potential threading effects
+ // as we cannot deal with them anyway.
+ auto IsSameThreadAsLoad = [&](const Access &Acc) -> bool {
+ return CanIgnoreThreading(*Acc.getLocalInst());
+ };
+
+ // TODO: Use inter-procedural reachability and dominance.
+ const auto &NoRecurseAA = A.getAAFor<AANoRecurse>(
+ QueryingAA, IRPosition::function(*LI.getFunction()),
+ DepClassTy::OPTIONAL);
+
+ // Helper to determine if the instruction may reach the load.
+ auto IsReachableFrom = [&](const Instruction &I) {
+ const auto &ReachabilityAA = A.getAAFor<AAReachability>(
+ QueryingAA, IRPosition::function(*I.getFunction()),
+ DepClassTy::OPTIONAL);
+ return ReachabilityAA.isAssumedReachable(A, I, LI);
+ };
+
+ const bool CanUseCFGResoning =
+ NoRecurseAA.isKnownNoRecurse() && CanIgnoreThreading(LI);
+ InformationCache &InfoCache = A.getInfoCache();
+ const DominatorTree *DT =
+ InfoCache.getAnalysisResultForFunction<DominatorTreeAnalysis>(Scope);
+
+ auto AccessCB = [&](const Access &Acc, bool Exact) {
+ if (!Acc.isWrite())
+ return true;
+
+ // For now we only filter accesses based on CFG reasoning which does not
+ // work yet if we have threading effects, or the access is complicated.
+ if (CanUseCFGResoning) {
+ if (!IsReachableFrom(*Acc.getLocalInst()))
+ return true;
+ if (DT && Exact &&
+ (Acc.getLocalInst()->getFunction() == LI.getFunction()) &&
+ IsSameThreadAsLoad(Acc)) {
+ if (DT->dominates(Acc.getLocalInst(), &LI))
+ DominatingWrites.insert(&Acc);
+ }
+ }
+
+ InterferingWrites.push_back({&Acc, Exact});
+ return true;
+ };
+ if (!State::forallInterferingAccesses(LI, AccessCB))
+ return false;
+
+ // If we cannot use CFG reasoning we only filter the non-write accesses
+ // and are done here.
+ if (!CanUseCFGResoning) {
+ for (auto &It : InterferingWrites)
+ if (!UserCB(*It.first, It.second))
+ return false;
+ return true;
+ }
+
+ // Helper to determine if we can skip a specific write access. This is in
+ // the worst case quadratic as we are looking for another write that will
+ // hide the effect of this one.
+ auto CanSkipAccess = [&](const Access &Acc, bool Exact) {
+ if (!IsSameThreadAsLoad(Acc))
+ return false;
+ if (!DominatingWrites.count(&Acc))
+ return false;
+ for (const Access *DomAcc : DominatingWrites) {
+ assert(Acc.getLocalInst()->getFunction() ==
+ DomAcc->getLocalInst()->getFunction() &&
+ "Expected dominating writes to be in the same function!");
+
+ if (DomAcc != &Acc &&
+ DT->dominates(Acc.getLocalInst(), DomAcc->getLocalInst())) {
+ return true;
+ }
+ }
+ return false;
+ };
+
+ // Run the user callback on all writes we cannot skip and return if that
+ // succeeded for all or not.
+ unsigned NumInterferingWrites = InterferingWrites.size();
+ for (auto &It : InterferingWrites)
+ if (!DT || NumInterferingWrites > MaxInterferingWrites ||
+ !CanSkipAccess(*It.first, It.second))
+ if (!UserCB(*It.first, It.second))
+ return false;
+ return true;
+ }
ChangeStatus translateAndAddCalleeState(Attributor &A,
const AAPointerInfo &CalleeAA,
/// See AbstractAttribute::updateImpl(...).
ChangeStatus updateImpl(Attributor &A) override {
+ const auto &NoRecurseAA = A.getAAFor<AANoRecurse>(
+ *this, IRPosition::function(*getAnchorScope()), DepClassTy::REQUIRED);
+ if (!NoRecurseAA.isAssumedNoRecurse())
+ return indicatePessimisticFixpoint();
return ChangeStatus::UNCHANGED;
}
};
auto CheckAccess = [&](const AAPointerInfo::Access &Acc, bool IsExact) {
LLVM_DEBUG(dbgs() << " - visit access " << Acc << "\n");
- if (!Acc.isWrite())
- return true;
if (Acc.isWrittenValueYetUndetermined())
return true;
Value *Content = Acc.getWrittenValue();
auto &PI = A.getAAFor<AAPointerInfo>(AA, IRPosition::value(*Obj),
DepClassTy::REQUIRED);
- if (!PI.forallInterferingAccesses(L, CheckAccess))
+ if (!PI.forallInterferingWrites(A, AA, L, CheckAccess))
return false;
}
return true;
; IS__CGSCC____: attributes #[[ATTR1:[0-9]+]] = { argmemonly nofree nosync nounwind uwtable willreturn }
; IS__CGSCC____: attributes #[[ATTR2:[0-9]+]] = { argmemonly nofree nounwind willreturn writeonly }
; IS__CGSCC____: attributes #[[ATTR3:[0-9]+]] = { willreturn writeonly }
-; IS__CGSCC____: attributes #[[ATTR4:[0-9]+]] = { nounwind willreturn }
+; IS__CGSCC____: attributes #[[ATTR4:[0-9]+]] = { nosync nounwind willreturn }
;.
; IS__CGSCC____: attributes #[[ATTR4:[0-9]+]] = { argmemonly inlinehint nofree norecurse nosync nounwind uwtable willreturn "min-legal-vector-width"="256" "prefer-vector-width"="256" "target-features"="+avx2" }
; IS__CGSCC____: attributes #[[ATTR5:[0-9]+]] = { argmemonly nofree nounwind willreturn writeonly }
; IS__CGSCC____: attributes #[[ATTR6:[0-9]+]] = { willreturn writeonly }
-; IS__CGSCC____: attributes #[[ATTR7:[0-9]+]] = { nounwind willreturn }
+; IS__CGSCC____: attributes #[[ATTR7:[0-9]+]] = { nosync nounwind willreturn }
;.
; IS__CGSCC_NPM-SAME: (i32 [[TMP0:%.*]], i64 [[TMP1:%.*]], i32 [[TMP2:%.*]]) #[[ATTR0:[0-9]+]] {
; IS__CGSCC_NPM-NEXT: entry:
; IS__CGSCC_NPM-NEXT: [[X_PRIV:%.*]] = alloca i32, align 4
-; IS__CGSCC_NPM-NEXT: store i32 [[TMP2]], i32* [[X_PRIV]], align 4
; IS__CGSCC_NPM-NEXT: [[B_PRIV:%.*]] = alloca [[STRUCT_SS:%.*]], align 8
; IS__CGSCC_NPM-NEXT: [[B_PRIV_CAST:%.*]] = bitcast %struct.ss* [[B_PRIV]] to i32*
-; IS__CGSCC_NPM-NEXT: store i32 1, i32* [[B_PRIV_CAST]], align 8
; IS__CGSCC_NPM-NEXT: [[B_PRIV_0_1:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[B_PRIV]], i64 0, i32 1
; IS__CGSCC_NPM-NEXT: [[TMP:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[B_PRIV]], i32 0, i32 0
; IS__CGSCC_NPM-NEXT: [[TMP1:%.*]] = load i32, i32* [[TMP]], align 8
-; IS__CGSCC_NPM-NEXT: [[TMP2:%.*]] = add i32 [[TMP1]], 1
-; IS__CGSCC_NPM-NEXT: store i32 [[TMP2]], i32* [[TMP]], align 8
-; IS__CGSCC_NPM-NEXT: store i32 0, i32* [[X_PRIV]], align 4
+; IS__CGSCC_NPM-NEXT: [[TMP2:%.*]] = add i32 1, 1
; IS__CGSCC_NPM-NEXT: [[L:%.*]] = load i32, i32* [[X_PRIV]], align 4
-; IS__CGSCC_NPM-NEXT: [[A:%.*]] = add i32 [[L]], [[TMP2]]
-; IS__CGSCC_NPM-NEXT: ret i32 [[A]]
+; IS__CGSCC_NPM-NEXT: [[A:%.*]] = add i32 0, 2
+; IS__CGSCC_NPM-NEXT: ret i32 undef
;
entry:
; IS__CGSCC_OPM-NEXT: [[C:%.*]] = call i32 @f(%struct.ss* noalias nocapture nofree noundef nonnull readonly byval([[STRUCT_SS]]) align 8 dereferenceable(12) [[S]], i32* noalias nocapture nofree noundef nonnull readonly byval(i32) align 4 dereferenceable(4) [[X]]) #[[ATTR1:[0-9]+]]
; IS__CGSCC_OPM-NEXT: ret i32 [[C]]
;
-; IS__CGSCC_NPM: Function Attrs: argmemonly nofree norecurse nosync nounwind willreturn
+; IS__CGSCC_NPM: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@test
-; IS__CGSCC_NPM-SAME: (i32* nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[X:%.*]]) #[[ATTR1:[0-9]+]] {
+; IS__CGSCC_NPM-SAME: (i32* nocapture nofree nonnull readnone align 4 dereferenceable(4) [[X:%.*]]) #[[ATTR0]] {
; IS__CGSCC_NPM-NEXT: entry:
; IS__CGSCC_NPM-NEXT: [[S:%.*]] = alloca [[STRUCT_SS:%.*]], align 8
; IS__CGSCC_NPM-NEXT: [[TMP1:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 0
; IS__CGSCC_NPM-NEXT: [[TMP4:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 1
-; IS__CGSCC_NPM-NEXT: [[TMP0:%.*]] = load i32, i32* [[X]], align 4
-; IS__CGSCC_NPM-NEXT: [[C:%.*]] = call i32 @f(i32 undef, i64 undef, i32 [[TMP0]]) #[[ATTR2:[0-9]+]]
-; IS__CGSCC_NPM-NEXT: ret i32 [[C]]
+; IS__CGSCC_NPM-NEXT: ret i32 2
;
entry:
%S = alloca %struct.ss
; IS__CGSCC_OPM: attributes #[[ATTR1]] = { nounwind willreturn }
;.
; IS__CGSCC_NPM: attributes #[[ATTR0]] = { nofree norecurse nosync nounwind readnone willreturn }
-; IS__CGSCC_NPM: attributes #[[ATTR1]] = { argmemonly nofree norecurse nosync nounwind willreturn }
-; IS__CGSCC_NPM: attributes #[[ATTR2]] = { nounwind readnone willreturn }
;.
; IS__CGSCC_NPM-NEXT: [[X_PRIV:%.*]] = alloca i32, align 4
; IS__CGSCC_NPM-NEXT: [[B_PRIV:%.*]] = alloca [[STRUCT_SS:%.*]], align 8
; IS__CGSCC_NPM-NEXT: [[B_PRIV_CAST:%.*]] = bitcast %struct.ss* [[B_PRIV]] to i32*
-; IS__CGSCC_NPM-NEXT: store i32 1, i32* [[B_PRIV_CAST]], align 8
; IS__CGSCC_NPM-NEXT: [[B_PRIV_0_1:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[B_PRIV]], i64 0, i32 1
; IS__CGSCC_NPM-NEXT: [[TMP:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[B_PRIV]], i32 0, i32 0
; IS__CGSCC_NPM-NEXT: [[TMP1:%.*]] = load i32, i32* [[TMP]], align 8
-; IS__CGSCC_NPM-NEXT: [[TMP2:%.*]] = add i32 [[TMP1]], 1
-; IS__CGSCC_NPM-NEXT: store i32 [[TMP2]], i32* [[TMP]], align 8
+; IS__CGSCC_NPM-NEXT: [[TMP2:%.*]] = add i32 1, 1
; IS__CGSCC_NPM-NEXT: ret void
;
entry:
; IS__CGSCC_NPM-NEXT: entry:
; IS__CGSCC_NPM-NEXT: [[B_PRIV:%.*]] = alloca [[STRUCT_SS:%.*]], align 4
; IS__CGSCC_NPM-NEXT: [[B_PRIV_CAST:%.*]] = bitcast %struct.ss* [[B_PRIV]] to i32*
-; IS__CGSCC_NPM-NEXT: store i32 1, i32* [[B_PRIV_CAST]], align 8
; IS__CGSCC_NPM-NEXT: [[B_PRIV_0_1:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[B_PRIV]], i64 0, i32 1
; IS__CGSCC_NPM-NEXT: [[TMP:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[B_PRIV]], i32 0, i32 0
; IS__CGSCC_NPM-NEXT: [[TMP1:%.*]] = load i32, i32* [[TMP]], align 8
-; IS__CGSCC_NPM-NEXT: [[TMP2:%.*]] = add i32 [[TMP1]], 1
-; IS__CGSCC_NPM-NEXT: store i32 [[TMP2]], i32* [[TMP]], align 8
-; IS__CGSCC_NPM-NEXT: ret i32 [[TMP1]]
+; IS__CGSCC_NPM-NEXT: [[TMP2:%.*]] = add i32 1, 1
+; IS__CGSCC_NPM-NEXT: ret i32 undef
;
entry:
%tmp = getelementptr %struct.ss, %struct.ss* %b, i32 0, i32 0
; IS__CGSCC_NPM-NEXT: entry:
; IS__CGSCC_NPM-NEXT: [[B_PRIV:%.*]] = alloca [[STRUCT_SS:%.*]], align 4
; IS__CGSCC_NPM-NEXT: [[B_PRIV_CAST:%.*]] = bitcast %struct.ss* [[B_PRIV]] to i32*
-; IS__CGSCC_NPM-NEXT: store i32 1, i32* [[B_PRIV_CAST]], align 32
; IS__CGSCC_NPM-NEXT: [[B_PRIV_0_1:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[B_PRIV]], i64 0, i32 1
; IS__CGSCC_NPM-NEXT: [[TMP:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[B_PRIV]], i32 0, i32 0
; IS__CGSCC_NPM-NEXT: [[TMP1:%.*]] = load i32, i32* [[TMP]], align 32
-; IS__CGSCC_NPM-NEXT: [[TMP2:%.*]] = add i32 [[TMP1]], 1
-; IS__CGSCC_NPM-NEXT: store i32 [[TMP2]], i32* [[TMP]], align 32
-; IS__CGSCC_NPM-NEXT: ret i32 [[TMP2]]
+; IS__CGSCC_NPM-NEXT: [[TMP2:%.*]] = add i32 1, 1
+; IS__CGSCC_NPM-NEXT: ret i32 undef
;
entry:
%tmp = getelementptr %struct.ss, %struct.ss* %b, i32 0, i32 0
; IS__TUNIT_NPM-NEXT: [[TMP1:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 0
; IS__TUNIT_NPM-NEXT: store i32 1, i32* [[TMP1]], align 8
; IS__TUNIT_NPM-NEXT: [[TMP4:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 1
-; IS__TUNIT_NPM-NEXT: [[S_CAST:%.*]] = bitcast %struct.ss* [[S]] to i32*
-; IS__TUNIT_NPM-NEXT: [[TMP0:%.*]] = load i32, i32* [[S_CAST]], align 8
-; IS__TUNIT_NPM-NEXT: [[S_0_1:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i64 0, i32 1
-; IS__TUNIT_NPM-NEXT: [[TMP1:%.*]] = load i64, i64* [[S_0_1]], align 8
-; IS__TUNIT_NPM-NEXT: [[C0:%.*]] = call i32 @f(i32 [[TMP0]], i64 [[TMP1]]) #[[ATTR2:[0-9]+]]
; IS__TUNIT_NPM-NEXT: [[S_CAST1:%.*]] = bitcast %struct.ss* [[S]] to i32*
-; IS__TUNIT_NPM-NEXT: [[TMP2:%.*]] = load i32, i32* [[S_CAST1]], align 32
+; IS__TUNIT_NPM-NEXT: [[TMP0:%.*]] = load i32, i32* [[S_CAST1]], align 8
; IS__TUNIT_NPM-NEXT: [[S_0_12:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i64 0, i32 1
-; IS__TUNIT_NPM-NEXT: [[TMP3:%.*]] = load i64, i64* [[S_0_12]], align 32
+; IS__TUNIT_NPM-NEXT: [[TMP1:%.*]] = load i64, i64* [[S_0_12]], align 8
+; IS__TUNIT_NPM-NEXT: [[C0:%.*]] = call i32 @f(i32 [[TMP0]], i64 [[TMP1]]) #[[ATTR2:[0-9]+]]
+; IS__TUNIT_NPM-NEXT: [[S_CAST:%.*]] = bitcast %struct.ss* [[S]] to i32*
+; IS__TUNIT_NPM-NEXT: [[TMP2:%.*]] = load i32, i32* [[S_CAST]], align 32
+; IS__TUNIT_NPM-NEXT: [[S_0_1:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i64 0, i32 1
+; IS__TUNIT_NPM-NEXT: [[TMP3:%.*]] = load i64, i64* [[S_0_1]], align 32
; IS__TUNIT_NPM-NEXT: [[C1:%.*]] = call i32 @g(i32 [[TMP2]], i64 [[TMP3]]) #[[ATTR2]]
; IS__TUNIT_NPM-NEXT: [[A:%.*]] = add i32 [[C0]], [[C1]]
; IS__TUNIT_NPM-NEXT: ret i32 [[A]]
; IS__CGSCC_NPM-NEXT: [[S:%.*]] = alloca [[STRUCT_SS:%.*]], align 4
; IS__CGSCC_NPM-NEXT: [[TMP1:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 0
; IS__CGSCC_NPM-NEXT: [[TMP4:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 1
-; IS__CGSCC_NPM-NEXT: [[C0:%.*]] = call i32 @f(i32 undef, i64 undef) #[[ATTR1:[0-9]+]]
-; IS__CGSCC_NPM-NEXT: [[C1:%.*]] = call i32 @g(i32 undef, i64 undef) #[[ATTR1]]
-; IS__CGSCC_NPM-NEXT: [[A:%.*]] = add i32 [[C0]], [[C1]]
-; IS__CGSCC_NPM-NEXT: ret i32 [[A]]
+; IS__CGSCC_NPM-NEXT: ret i32 3
;
entry:
%S = alloca %struct.ss
; IS__CGSCC_OPM: attributes #[[ATTR2]] = { nounwind willreturn }
;.
; IS__CGSCC_NPM: attributes #[[ATTR0]] = { nofree norecurse nosync nounwind readnone willreturn }
-; IS__CGSCC_NPM: attributes #[[ATTR1]] = { nounwind readnone willreturn }
;.
; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@unions
; IS__TUNIT_NPM-SAME: () #[[ATTR0]] {
; IS__TUNIT_NPM-NEXT: entry:
-; IS__TUNIT_NPM-NEXT: [[MYSTR_CAST:%.*]] = bitcast %struct.MYstr* @mystr to i8*
-; IS__TUNIT_NPM-NEXT: [[TMP0:%.*]] = load i8, i8* [[MYSTR_CAST]], align 8
-; IS__TUNIT_NPM-NEXT: [[MYSTR_0_1:%.*]] = getelementptr [[STRUCT_MYSTR:%.*]], %struct.MYstr* @mystr, i64 0, i32 1
-; IS__TUNIT_NPM-NEXT: [[TMP1:%.*]] = load i32, i32* [[MYSTR_0_1]], align 8
-; IS__TUNIT_NPM-NEXT: call void @vfu1(i8 [[TMP0]], i32 [[TMP1]]) #[[ATTR0]]
; IS__TUNIT_NPM-NEXT: [[MYSTR_CAST1:%.*]] = bitcast %struct.MYstr* @mystr to i8*
-; IS__TUNIT_NPM-NEXT: [[TMP2:%.*]] = load i8, i8* [[MYSTR_CAST1]], align 8
-; IS__TUNIT_NPM-NEXT: [[MYSTR_0_12:%.*]] = getelementptr [[STRUCT_MYSTR]], %struct.MYstr* @mystr, i64 0, i32 1
-; IS__TUNIT_NPM-NEXT: [[TMP3:%.*]] = load i32, i32* [[MYSTR_0_12]], align 8
+; IS__TUNIT_NPM-NEXT: [[TMP0:%.*]] = load i8, i8* [[MYSTR_CAST1]], align 8
+; IS__TUNIT_NPM-NEXT: [[MYSTR_0_12:%.*]] = getelementptr [[STRUCT_MYSTR:%.*]], %struct.MYstr* @mystr, i64 0, i32 1
+; IS__TUNIT_NPM-NEXT: [[TMP1:%.*]] = load i32, i32* [[MYSTR_0_12]], align 8
+; IS__TUNIT_NPM-NEXT: call void @vfu1(i8 [[TMP0]], i32 [[TMP1]]) #[[ATTR0]]
+; IS__TUNIT_NPM-NEXT: [[MYSTR_CAST:%.*]] = bitcast %struct.MYstr* @mystr to i8*
+; IS__TUNIT_NPM-NEXT: [[TMP2:%.*]] = load i8, i8* [[MYSTR_CAST]], align 8
+; IS__TUNIT_NPM-NEXT: [[MYSTR_0_1:%.*]] = getelementptr [[STRUCT_MYSTR]], %struct.MYstr* @mystr, i64 0, i32 1
+; IS__TUNIT_NPM-NEXT: [[TMP3:%.*]] = load i32, i32* [[MYSTR_0_1]], align 8
; IS__TUNIT_NPM-NEXT: [[RESULT:%.*]] = call i32 @vfu2(i8 [[TMP2]], i32 [[TMP3]]) #[[ATTR2:[0-9]+]]
; IS__TUNIT_NPM-NEXT: ret i32 [[RESULT]]
;
; IS__CGSCC_NPM-NEXT: [[U_PRIV:%.*]] = alloca [[STRUCT_MYSTR:%.*]], align 8
; IS__CGSCC_NPM-NEXT: [[U_PRIV_CAST:%.*]] = bitcast %struct.MYstr* [[U_PRIV]] to i8*
; IS__CGSCC_NPM-NEXT: [[U_PRIV_0_1:%.*]] = getelementptr [[STRUCT_MYSTR]], %struct.MYstr* [[U_PRIV]], i64 0, i32 1
-; IS__CGSCC_NPM-NEXT: store i32 0, i32* [[U_PRIV_0_1]], align 4
; IS__CGSCC_NPM-NEXT: [[Z:%.*]] = getelementptr [[STRUCT_MYSTR]], %struct.MYstr* [[U_PRIV]], i32 0, i32 1
-; IS__CGSCC_NPM-NEXT: store i32 99, i32* [[Z]], align 4
; IS__CGSCC_NPM-NEXT: [[TMP2:%.*]] = getelementptr [[STRUCT_MYSTR]], %struct.MYstr* [[U_PRIV]], i32 0, i32 1
; IS__CGSCC_NPM-NEXT: [[TMP3:%.*]] = load i32, i32* [[TMP2]], align 4
; IS__CGSCC_NPM-NEXT: [[TMP4:%.*]] = getelementptr [[STRUCT_MYSTR]], %struct.MYstr* [[U_PRIV]], i32 0, i32 0
; IS__CGSCC_NPM-NEXT: [[TMP5:%.*]] = load i8, i8* [[TMP4]], align 8
; IS__CGSCC_NPM-NEXT: [[TMP6:%.*]] = zext i8 0 to i32
-; IS__CGSCC_NPM-NEXT: [[TMP7:%.*]] = add i32 0, [[TMP3]]
-; IS__CGSCC_NPM-NEXT: ret i32 [[TMP7]]
+; IS__CGSCC_NPM-NEXT: [[TMP7:%.*]] = add i32 0, 99
+; IS__CGSCC_NPM-NEXT: ret i32 undef
;
entry:
%z = getelementptr %struct.MYstr, %struct.MYstr* %u, i32 0, i32 1
; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@unions_v2
; IS__TUNIT_NPM-SAME: () #[[ATTR0]] {
; IS__TUNIT_NPM-NEXT: entry:
-; IS__TUNIT_NPM-NEXT: [[MYSTR_CAST:%.*]] = bitcast %struct.MYstr* @mystr to i8*
-; IS__TUNIT_NPM-NEXT: [[TMP0:%.*]] = load i8, i8* [[MYSTR_CAST]], align 8
-; IS__TUNIT_NPM-NEXT: [[MYSTR_0_1:%.*]] = getelementptr [[STRUCT_MYSTR:%.*]], %struct.MYstr* @mystr, i64 0, i32 1
-; IS__TUNIT_NPM-NEXT: [[TMP1:%.*]] = load i32, i32* [[MYSTR_0_1]], align 8
-; IS__TUNIT_NPM-NEXT: call void @vfu1(i8 [[TMP0]], i32 [[TMP1]]) #[[ATTR0]]
; IS__TUNIT_NPM-NEXT: [[MYSTR_CAST1:%.*]] = bitcast %struct.MYstr* @mystr to i8*
-; IS__TUNIT_NPM-NEXT: [[TMP2:%.*]] = load i8, i8* [[MYSTR_CAST1]], align 8
-; IS__TUNIT_NPM-NEXT: [[MYSTR_0_12:%.*]] = getelementptr [[STRUCT_MYSTR]], %struct.MYstr* @mystr, i64 0, i32 1
-; IS__TUNIT_NPM-NEXT: [[TMP3:%.*]] = load i32, i32* [[MYSTR_0_12]], align 8
+; IS__TUNIT_NPM-NEXT: [[TMP0:%.*]] = load i8, i8* [[MYSTR_CAST1]], align 8
+; IS__TUNIT_NPM-NEXT: [[MYSTR_0_12:%.*]] = getelementptr [[STRUCT_MYSTR:%.*]], %struct.MYstr* @mystr, i64 0, i32 1
+; IS__TUNIT_NPM-NEXT: [[TMP1:%.*]] = load i32, i32* [[MYSTR_0_12]], align 8
+; IS__TUNIT_NPM-NEXT: call void @vfu1(i8 [[TMP0]], i32 [[TMP1]]) #[[ATTR0]]
+; IS__TUNIT_NPM-NEXT: [[MYSTR_CAST:%.*]] = bitcast %struct.MYstr* @mystr to i8*
+; IS__TUNIT_NPM-NEXT: [[TMP2:%.*]] = load i8, i8* [[MYSTR_CAST]], align 8
+; IS__TUNIT_NPM-NEXT: [[MYSTR_0_1:%.*]] = getelementptr [[STRUCT_MYSTR]], %struct.MYstr* @mystr, i64 0, i32 1
+; IS__TUNIT_NPM-NEXT: [[TMP3:%.*]] = load i32, i32* [[MYSTR_0_1]], align 8
; IS__TUNIT_NPM-NEXT: [[RESULT:%.*]] = call i32 @vfu2_v2(i8 [[TMP2]], i32 [[TMP3]]) #[[ATTR2]]
; IS__TUNIT_NPM-NEXT: ret i32 [[RESULT]]
;
; IS__CGSCC_NPM-SAME: () #[[ATTR0]] {
; IS__CGSCC_NPM-NEXT: entry:
; IS__CGSCC_NPM-NEXT: call void @vfu1(i8 noundef 0, i32 undef) #[[ATTR0]]
-; IS__CGSCC_NPM-NEXT: [[RESULT:%.*]] = call i32 @vfu2_v2(i8 undef, i32 undef) #[[ATTR0]]
-; IS__CGSCC_NPM-NEXT: ret i32 [[RESULT]]
+; IS__CGSCC_NPM-NEXT: ret i32 99
;
entry:
call void @vfu1(%struct.MYstr* byval(%struct.MYstr) align 4 @mystr) nounwind
define void @test8() {
; CHECK-LABEL: define {{[^@]+}}@test8() {
; CHECK-NEXT: [[TMP1:%.*]] = tail call noalias i8* @malloc(i64 noundef 4)
-; CHECK-NEXT: tail call void @no_sync_func(i8* noalias nocapture nofree [[TMP1]])
+; CHECK-NEXT: tail call void @no_sync_func(i8* nocapture nofree [[TMP1]])
; CHECK-NEXT: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to i32*
; CHECK-NEXT: store i32 10, i32* [[TMP2]], align 4
; CHECK-NEXT: tail call void @foo(i32* noundef align 4 [[TMP2]])
define void @test9() {
; IS________OPM-LABEL: define {{[^@]+}}@test9() {
; IS________OPM-NEXT: [[TMP1:%.*]] = tail call noalias i8* @malloc(i64 noundef 4)
-; IS________OPM-NEXT: tail call void @no_sync_func(i8* noalias nocapture nofree [[TMP1]])
+; IS________OPM-NEXT: tail call void @no_sync_func(i8* nocapture nofree [[TMP1]])
; IS________OPM-NEXT: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to i32*
; IS________OPM-NEXT: store i32 10, i32* [[TMP2]], align 4
; IS________OPM-NEXT: tail call void @foo_nounw(i32* nofree noundef align 4 [[TMP2]]) #[[ATTR5]]
;
; IS________NPM-LABEL: define {{[^@]+}}@test9() {
; IS________NPM-NEXT: [[TMP1:%.*]] = tail call noalias i8* @malloc(i64 noundef 4)
-; IS________NPM-NEXT: tail call void @no_sync_func(i8* noalias nocapture nofree [[TMP1]])
+; IS________NPM-NEXT: tail call void @no_sync_func(i8* nocapture nofree [[TMP1]])
; IS________NPM-NEXT: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to i32*
; IS________NPM-NEXT: store i32 10, i32* [[TMP2]], align 4
; IS________NPM-NEXT: tail call void @foo_nounw(i32* nofree noundef align 4 [[TMP2]]) #[[ATTR6]]
define void @test8() {
; CHECK-LABEL: define {{[^@]+}}@test8() {
; CHECK-NEXT: [[TMP1:%.*]] = tail call noalias i8* @malloc(i64 noundef 4)
-; CHECK-NEXT: tail call void @no_sync_func(i8* noalias nocapture nofree [[TMP1]])
+; CHECK-NEXT: tail call void @no_sync_func(i8* nocapture nofree [[TMP1]])
; CHECK-NEXT: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to i32*
; CHECK-NEXT: store i32 10, i32* [[TMP2]], align 4
; CHECK-NEXT: tail call void @foo(i32* noundef align 4 [[TMP2]])
define void @test9() {
; CHECK-LABEL: define {{[^@]+}}@test9() {
; CHECK-NEXT: [[TMP1:%.*]] = tail call noalias i8* @malloc(i64 noundef 4)
-; CHECK-NEXT: tail call void @no_sync_func(i8* noalias nocapture nofree [[TMP1]])
+; CHECK-NEXT: tail call void @no_sync_func(i8* nocapture nofree [[TMP1]])
; CHECK-NEXT: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to i32*
; CHECK-NEXT: store i32 10, i32* [[TMP2]], align 4
; CHECK-NEXT: tail call void @foo_nounw(i32* nofree noundef align 4 [[TMP2]]) #[[ATTR5:[0-9]+]]
; IS__TUNIT____-SAME: (void (i8*)* nonnull [[FP:%.*]]) {
; IS__TUNIT____-NEXT: entry:
; IS__TUNIT____-NEXT: [[A:%.*]] = alloca i32, align 4
-; IS__TUNIT____-NEXT: call void @foo(i32* noalias nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[A]]) #[[ATTR1:[0-9]+]]
+; IS__TUNIT____-NEXT: call void @foo(i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[A]]) #[[ATTR1:[0-9]+]]
; IS__TUNIT____-NEXT: call void [[FP]](i8* bitcast (void (i32*)* @foo to i8*))
; IS__TUNIT____-NEXT: call void @callback1(void (i32*)* noundef nonnull @foo)
; IS__TUNIT____-NEXT: call void @callback2(void (i8*)* noundef bitcast (void (i32*)* @foo to void (i8*)*))
; IS__CGSCC____-SAME: (void (i8*)* noundef nonnull [[FP:%.*]]) {
; IS__CGSCC____-NEXT: entry:
; IS__CGSCC____-NEXT: [[A:%.*]] = alloca i32, align 4
-; IS__CGSCC____-NEXT: [[TMP:%.*]] = bitcast i32* [[A]] to i8*
-; IS__CGSCC____-NEXT: call void @foo(i32* noalias nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[A]]) #[[ATTR1:[0-9]+]]
+; IS__CGSCC____-NEXT: call void @foo(i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[A]]) #[[ATTR1:[0-9]+]]
; IS__CGSCC____-NEXT: call void [[FP]](i8* bitcast (void (i32*)* @foo to i8*))
; IS__CGSCC____-NEXT: call void @callback1(void (i32*)* noundef nonnull @foo)
; IS__CGSCC____-NEXT: call void @callback2(void (i8*)* noundef bitcast (void (i32*)* @foo to void (i8*)*))
; IS__TUNIT____-SAME: (void (i8*)* [[FP:%.*]]) {
; IS__TUNIT____-NEXT: entry:
; IS__TUNIT____-NEXT: [[A:%.*]] = alloca i32, align 4
-; IS__TUNIT____-NEXT: call void @foo(i32* noalias nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[A]]) #[[ATTR1]]
+; IS__TUNIT____-NEXT: call void @foo(i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[A]]) #[[ATTR1]]
; IS__TUNIT____-NEXT: call void @callback1(void (i32*)* noundef nonnull @foo)
; IS__TUNIT____-NEXT: call void @callback2(void (i8*)* noundef bitcast (void (i32*)* @foo to void (i8*)*))
; IS__TUNIT____-NEXT: call void @callback2(void (i8*)* [[FP]])
; IS__CGSCC____-SAME: (void (i8*)* [[FP:%.*]]) {
; IS__CGSCC____-NEXT: entry:
; IS__CGSCC____-NEXT: [[A:%.*]] = alloca i32, align 4
-; IS__CGSCC____-NEXT: call void @foo(i32* noalias nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[A]]) #[[ATTR1]]
+; IS__CGSCC____-NEXT: call void @foo(i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[A]]) #[[ATTR1]]
; IS__CGSCC____-NEXT: call void @callback1(void (i32*)* noundef nonnull @foo)
; IS__CGSCC____-NEXT: call void @callback2(void (i8*)* noundef bitcast (void (i32*)* @foo to void (i8*)*))
; IS__CGSCC____-NEXT: call void @callback2(void (i8*)* [[FP]])
define void @test12_2(){
; CHECK-LABEL: define {{[^@]+}}@test12_2() {
; CHECK-NEXT: [[A:%.*]] = tail call noalias i8* @malloc(i64 noundef 4)
-; CHECK-NEXT: tail call void @use_nocapture(i8* noalias nocapture [[A]])
-; CHECK-NEXT: tail call void @use_nocapture(i8* noalias nocapture [[A]])
+; CHECK-NEXT: tail call void @use_nocapture(i8* nocapture [[A]])
+; CHECK-NEXT: tail call void @use_nocapture(i8* nocapture [[A]])
; CHECK-NEXT: tail call void @use(i8* [[A]])
; CHECK-NEXT: tail call void @use_nocapture(i8* nocapture [[A]])
; CHECK-NEXT: ret void
; NOT_CGSCC_NPM-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[C]], 0
; NOT_CGSCC_NPM-NEXT: br i1 [[TOBOOL]], label [[IF_END:%.*]], label [[IF_THEN:%.*]]
; NOT_CGSCC_NPM: if.then:
-; NOT_CGSCC_NPM-NEXT: tail call void @only_store(i32* noalias nocapture nofree writeonly align 4 [[P]]) #[[ATTR7]]
+; NOT_CGSCC_NPM-NEXT: tail call void @only_store(i32* nocapture nofree writeonly align 4 [[P]]) #[[ATTR7]]
; NOT_CGSCC_NPM-NEXT: br label [[IF_END]]
; NOT_CGSCC_NPM: if.end:
; NOT_CGSCC_NPM-NEXT: tail call void @make_alias(i32* nofree writeonly [[P]]) #[[ATTR7]]
; NOT_CGSCC_NPM-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[C1]], 0
; NOT_CGSCC_NPM-NEXT: br i1 [[TOBOOL]], label [[IF_END:%.*]], label [[IF_THEN:%.*]]
; NOT_CGSCC_NPM: if.then:
-; NOT_CGSCC_NPM-NEXT: tail call void @only_store(i32* noalias nocapture nofree writeonly align 4 [[P]]) #[[ATTR7]]
+; NOT_CGSCC_NPM-NEXT: tail call void @only_store(i32* nocapture nofree writeonly align 4 [[P]]) #[[ATTR7]]
; NOT_CGSCC_NPM-NEXT: tail call void @make_alias(i32* nofree writeonly align 4 [[P]]) #[[ATTR7]]
; NOT_CGSCC_NPM-NEXT: br label [[IF_END]]
; NOT_CGSCC_NPM: if.end:
; IS__TUNIT____-NEXT: [[L:%.*]] = load i32, i32* [[A]], align 4
; IS__TUNIT____-NEXT: ret i32 [[L]]
;
-; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
-; IS__CGSCC____-LABEL: define {{[^@]+}}@local_alloca_simplifiable_3
-; IS__CGSCC____-SAME: () #[[ATTR2:[0-9]+]] {
-; IS__CGSCC____-NEXT: [[A:%.*]] = alloca i32, align 4
-; IS__CGSCC____-NEXT: store i32 1, i32* [[A]], align 4
-; IS__CGSCC____-NEXT: br label [[SPLIT:%.*]]
-; IS__CGSCC____: split:
-; IS__CGSCC____-NEXT: store i32 2, i32* [[A]], align 4
-; IS__CGSCC____-NEXT: [[L:%.*]] = load i32, i32* [[A]], align 4
-; IS__CGSCC____-NEXT: ret i32 [[L]]
+; IS__CGSCC_OPM: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
+; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@local_alloca_simplifiable_3
+; IS__CGSCC_OPM-SAME: () #[[ATTR2:[0-9]+]] {
+; IS__CGSCC_OPM-NEXT: [[A:%.*]] = alloca i32, align 4
+; IS__CGSCC_OPM-NEXT: store i32 1, i32* [[A]], align 4
+; IS__CGSCC_OPM-NEXT: br label [[SPLIT:%.*]]
+; IS__CGSCC_OPM: split:
+; IS__CGSCC_OPM-NEXT: store i32 2, i32* [[A]], align 4
+; IS__CGSCC_OPM-NEXT: [[L:%.*]] = load i32, i32* [[A]], align 4
+; IS__CGSCC_OPM-NEXT: ret i32 [[L]]
+;
+; IS__CGSCC_NPM: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
+; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@local_alloca_simplifiable_3
+; IS__CGSCC_NPM-SAME: () #[[ATTR2:[0-9]+]] {
+; IS__CGSCC_NPM-NEXT: br label [[SPLIT:%.*]]
+; IS__CGSCC_NPM: split:
+; IS__CGSCC_NPM-NEXT: ret i32 2
;
%A = alloca i32, align 4
store i32 1, i32* %A
;
; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
; IS__CGSCC____-LABEL: define {{[^@]+}}@local_alloca_simplifiable_4
-; IS__CGSCC____-SAME: () #[[ATTR2]] {
+; IS__CGSCC____-SAME: () #[[ATTR2:[0-9]+]] {
; IS__CGSCC____-NEXT: ret i32 undef
;
%A = alloca i32, align 4