diff --git a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp index fb0e0a0bf569..6cf666ffe6b8 100644 --- a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp +++ b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp @@ -997,6 +997,8 @@ struct OffsetInfo { return Offsets == RHS.Offsets; } + bool operator!=(const OffsetInfo &RHS) const { return !(*this == RHS); } + void insert(int64_t Offset) { Offsets.push_back(Offset); } bool isUnassigned() const { return Offsets.size() == 0; } @@ -1348,7 +1350,11 @@ struct AAPointerInfoFloating : public AAPointerInfoImpl { /// See AbstractAttribute::updateImpl(...). ChangeStatus updateImpl(Attributor &A) override; - void collectConstantsForGEP(Attributor &A, const DataLayout &DL, + /// If the indices to \p GEP can be traced to constants, incorporate all + /// of these into \p UsrOI. + /// + /// \return true iff \p UsrOI is updated. + bool collectConstantsForGEP(Attributor &A, const DataLayout &DL, OffsetInfo &UsrOI, const OffsetInfo &PtrOI, const GEPOperator *GEP); @@ -1358,9 +1364,7 @@ struct AAPointerInfoFloating : public AAPointerInfoImpl { } }; -/// If the indices to \p GEP can be traced to constants, incorporate all -/// of these into \p UsrOI. -void AAPointerInfoFloating::collectConstantsForGEP(Attributor &A, +bool AAPointerInfoFloating::collectConstantsForGEP(Attributor &A, const DataLayout &DL, OffsetInfo &UsrOI, const OffsetInfo &PtrOI, @@ -1375,7 +1379,7 @@ void AAPointerInfoFloating::collectConstantsForGEP(Attributor &A, if (!GEP->collectOffset(DL, BitWidth, VariableOffsets, ConstantOffset)) { UsrOI.setUnknown(); - return; + return true; } LLVM_DEBUG(dbgs() << "[AAPointerInfo] GEP offset is " @@ -1393,14 +1397,19 @@ void AAPointerInfoFloating::collectConstantsForGEP(Attributor &A, *this, IRPosition::value(*VI.first), DepClassTy::OPTIONAL); if (!PotentialConstantsAA.isValidState()) { UsrOI.setUnknown(); - return; + return true; } auto &AssumedSet = PotentialConstantsAA.getAssumedSet(); - // Nothing to pick if AssumedSet is empty, i.e., not yet discovered. - if (AssumedSet.empty()) - continue; + // We need at least one constant in every set to compute an actual offset. + // Otherwise, we end up pessimizing AAPointerInfo by respecting offsets that + // don't actually exist. In other words, the absence of constant values + // implies that the operation can be assumed dead for now. + // + // UndefValue is treated as a zero. + if (!PotentialConstantsAA.undefIsContained() && AssumedSet.empty()) + return false; OffsetInfo Product; for (const auto &ConstOffset : AssumedSet) { @@ -1413,7 +1422,7 @@ void AAPointerInfoFloating::collectConstantsForGEP(Attributor &A, } UsrOI = std::move(Union); - return; + return true; } ChangeStatus AAPointerInfoFloating::updateImpl(Attributor &A) { @@ -1469,14 +1478,13 @@ ChangeStatus AAPointerInfoFloating::updateImpl(Attributor &A) { if (UsrOI.isUnknown()) return true; - Follow = true; - if (PtrOI.isUnknown()) { + Follow = true; UsrOI.setUnknown(); return true; } - collectConstantsForGEP(A, DL, UsrOI, PtrOI, GEP); + Follow = collectConstantsForGEP(A, DL, UsrOI, PtrOI, GEP); return true; } if (isa(Usr)) @@ -9108,11 +9116,15 @@ struct AAPotentialConstantValuesImpl : AAPotentialConstantValues { } bool fillSetWithConstantValues(Attributor &A, const IRPosition &IRP, SetTy &S, - bool &ContainsUndef) { + bool &ContainsUndef, bool ForSelf) { SmallVector Values; bool UsedAssumedInformation = false; if (!A.getAssumedSimplifiedValues(IRP, *this, Values, AA::Interprocedural, UsedAssumedInformation)) { + // Avoid recursion when the caller is computing constant values for this + // IRP itself. + if (ForSelf) + return false; if (!IRP.getAssociatedType()->isIntegerTy()) return false; auto &PotentialValuesAA = A.getAAFor( @@ -9124,15 +9136,21 @@ struct AAPotentialConstantValuesImpl : AAPotentialConstantValues { return true; } + // Copy all the constant values, except UndefValue. ContainsUndef is true + // iff Values contains only UndefValue instances. If there are other known + // constants, then UndefValue is dropped. + ContainsUndef = false; for (auto &It : Values) { - if (isa(It.getValue())) + if (isa(It.getValue())) { + ContainsUndef = true; continue; + } auto *CI = dyn_cast(It.getValue()); if (!CI) return false; S.insert(CI->getValue()); } - ContainsUndef = S.empty(); + ContainsUndef &= S.empty(); return true; } @@ -9328,9 +9346,9 @@ struct AAPotentialConstantValuesFloating : AAPotentialConstantValuesImpl { bool LHSContainsUndef = false, RHSContainsUndef = false; SetTy LHSAAPVS, RHSAAPVS; if (!fillSetWithConstantValues(A, IRPosition::value(*LHS), LHSAAPVS, - LHSContainsUndef) || + LHSContainsUndef, /* ForSelf */ false) || !fillSetWithConstantValues(A, IRPosition::value(*RHS), RHSAAPVS, - RHSContainsUndef)) + RHSContainsUndef, /* ForSelf */ false)) return indicatePessimisticFixpoint(); // TODO: make use of undef flag to limit potential values aggressively. @@ -9393,12 +9411,14 @@ struct AAPotentialConstantValuesFloating : AAPotentialConstantValuesImpl { bool LHSContainsUndef = false, RHSContainsUndef = false; SetTy LHSAAPVS, RHSAAPVS; - if (!OnlyRight && !fillSetWithConstantValues(A, IRPosition::value(*LHS), - LHSAAPVS, LHSContainsUndef)) + if (!OnlyRight && + !fillSetWithConstantValues(A, IRPosition::value(*LHS), LHSAAPVS, + LHSContainsUndef, /* ForSelf */ false)) return indicatePessimisticFixpoint(); - if (!OnlyLeft && !fillSetWithConstantValues(A, IRPosition::value(*RHS), - RHSAAPVS, RHSContainsUndef)) + if (!OnlyLeft && + !fillSetWithConstantValues(A, IRPosition::value(*RHS), RHSAAPVS, + RHSContainsUndef, /* ForSelf */ false)) return indicatePessimisticFixpoint(); if (OnlyLeft || OnlyRight) { @@ -9437,7 +9457,7 @@ struct AAPotentialConstantValuesFloating : AAPotentialConstantValuesImpl { bool SrcContainsUndef = false; SetTy SrcPVS; if (!fillSetWithConstantValues(A, IRPosition::value(*Src), SrcPVS, - SrcContainsUndef)) + SrcContainsUndef, /* ForSelf */ false)) return indicatePessimisticFixpoint(); if (SrcContainsUndef) @@ -9460,9 +9480,9 @@ struct AAPotentialConstantValuesFloating : AAPotentialConstantValuesImpl { bool LHSContainsUndef = false, RHSContainsUndef = false; SetTy LHSAAPVS, RHSAAPVS; if (!fillSetWithConstantValues(A, IRPosition::value(*LHS), LHSAAPVS, - LHSContainsUndef) || + LHSContainsUndef, /* ForSelf */ false) || !fillSetWithConstantValues(A, IRPosition::value(*RHS), RHSAAPVS, - RHSContainsUndef)) + RHSContainsUndef, /* ForSelf */ false)) return indicatePessimisticFixpoint(); const APInt Zero = APInt(LHS->getType()->getIntegerBitWidth(), 0); @@ -9493,6 +9513,23 @@ struct AAPotentialConstantValuesFloating : AAPotentialConstantValuesImpl { : ChangeStatus::CHANGED; } + ChangeStatus updateWithInstruction(Attributor &A, Instruction *Inst) { + auto AssumedBefore = getAssumed(); + SetTy Incoming; + bool ContainsUndef; + if (!fillSetWithConstantValues(A, IRPosition::value(*Inst), Incoming, + ContainsUndef, /* ForSelf */ true)) + return indicatePessimisticFixpoint(); + if (ContainsUndef) { + unionAssumedWithUndef(); + } else { + for (const auto &It : Incoming) + unionAssumed(It); + } + return AssumedBefore == getAssumed() ? ChangeStatus::UNCHANGED + : ChangeStatus::CHANGED; + } + /// See AbstractAttribute::updateImpl(...). ChangeStatus updateImpl(Attributor &A) override { Value &V = getAssociatedValue(); @@ -9510,6 +9547,9 @@ struct AAPotentialConstantValuesFloating : AAPotentialConstantValuesImpl { if (auto *BinOp = dyn_cast(I)) return updateWithBinaryOperator(A, BinOp); + if (isa(I) || isa(I)) + return updateWithInstruction(A, I); + return indicatePessimisticFixpoint(); } diff --git a/llvm/test/Transforms/Attributor/ArgumentPromotion/2008-02-01-ReturnAttrs.ll b/llvm/test/Transforms/Attributor/ArgumentPromotion/2008-02-01-ReturnAttrs.ll index aa2992d407f4..771e2b8a9126 100644 --- a/llvm/test/Transforms/Attributor/ArgumentPromotion/2008-02-01-ReturnAttrs.ll +++ b/llvm/test/Transforms/Attributor/ArgumentPromotion/2008-02-01-ReturnAttrs.ll @@ -1,5 +1,5 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals -; 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,TUNIT +; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=11 -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT ; 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(i32* %x) nounwind { diff --git a/llvm/test/Transforms/Attributor/IPConstantProp/openmp_parallel_for.ll b/llvm/test/Transforms/Attributor/IPConstantProp/openmp_parallel_for.ll index cc9429ff491e..dcd8d64c74c4 100644 --- a/llvm/test/Transforms/Attributor/IPConstantProp/openmp_parallel_for.ll +++ b/llvm/test/Transforms/Attributor/IPConstantProp/openmp_parallel_for.ll @@ -1,5 +1,5 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals -; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=16 -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT +; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=18 -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT ; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,CGSCC ; ; void bar(int, float, double); diff --git a/llvm/test/Transforms/Attributor/IPConstantProp/return-argument.ll b/llvm/test/Transforms/Attributor/IPConstantProp/return-argument.ll index 3536ee0849bf..1e50c74bf5b6 100644 --- a/llvm/test/Transforms/Attributor/IPConstantProp/return-argument.ll +++ b/llvm/test/Transforms/Attributor/IPConstantProp/return-argument.ll @@ -1,5 +1,5 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals -; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=11 -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT +; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=13 -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT ; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,CGSCC ;; This function returns its second argument on all return statements diff --git a/llvm/test/Transforms/Attributor/multiple-offsets-pointer-info.ll b/llvm/test/Transforms/Attributor/multiple-offsets-pointer-info.ll index a2915d0c5e95..02664665cf6f 100644 --- a/llvm/test/Transforms/Attributor/multiple-offsets-pointer-info.ll +++ b/llvm/test/Transforms/Attributor/multiple-offsets-pointer-info.ll @@ -457,16 +457,12 @@ join: ret i8 %i } -; FIXME: This should be simplifiable. See comment inside. - -define i8 @phi_offsets_fixme(i1 %cnd1, i1 %cnd2) { +define i8 @phi_offsets(i1 %cnd1, i1 %cnd2) { ; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none) -; CHECK-LABEL: define {{[^@]+}}@phi_offsets_fixme +; CHECK-LABEL: define {{[^@]+}}@phi_offsets ; CHECK-SAME: (i1 [[CND1:%.*]], i1 [[CND2:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: entry: ; CHECK-NEXT: [[BYTES:%.*]] = alloca [1024 x i8], align 16 -; CHECK-NEXT: [[GEP_FIXED:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 0 -; CHECK-NEXT: store i8 100, i8* [[GEP_FIXED]], align 16 ; CHECK-NEXT: br i1 [[CND1]], label [[THEN:%.*]], label [[ELSE:%.*]] ; CHECK: then: ; CHECK-NEXT: br label [[JOIN:%.*]] @@ -475,9 +471,7 @@ define i8 @phi_offsets_fixme(i1 %cnd1, i1 %cnd2) { ; CHECK: join: ; CHECK-NEXT: [[PHI:%.*]] = phi i64 [ 3, [[THEN]] ], [ 11, [[ELSE]] ] ; CHECK-NEXT: [[GEP_PHI:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 [[PHI]] -; CHECK-NEXT: store i8 42, i8* [[GEP_PHI]], align 4 -; CHECK-NEXT: [[I:%.*]] = load i8, i8* [[GEP_FIXED]], align 16 -; CHECK-NEXT: ret i8 [[I]] +; CHECK-NEXT: ret i8 100 ; entry: %Bytes = alloca [1024 x i8], align 16 @@ -492,8 +486,6 @@ else: br label %join join: - ; FIXME: AAPotentialConstantValues does not detect the constant values for the - ; PHI below. It needs to rely on AAPotentialValues. %phi = phi i64 [ 3, %then ], [ 11, %else ] %gep.phi = getelementptr inbounds [1024 x i8], [1024 x i8]* %Bytes, i64 0, i64 %phi store i8 42, i8* %gep.phi, align 4 diff --git a/llvm/test/Transforms/Attributor/value-simplify-dbg.ll b/llvm/test/Transforms/Attributor/value-simplify-dbg.ll index 14807aced134..626d6eee4faa 100644 --- a/llvm/test/Transforms/Attributor/value-simplify-dbg.ll +++ b/llvm/test/Transforms/Attributor/value-simplify-dbg.ll @@ -1,5 +1,5 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals -; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=2 -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT +; 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,TUNIT ; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,CGSCC @G = internal global i32 undef, align 4, !dbg !0 diff --git a/llvm/test/Transforms/Attributor/value-simplify-pointer-info.ll b/llvm/test/Transforms/Attributor/value-simplify-pointer-info.ll index 97a94cf2cd97..6bf722e82a41 100644 --- a/llvm/test/Transforms/Attributor/value-simplify-pointer-info.ll +++ b/llvm/test/Transforms/Attributor/value-simplify-pointer-info.ll @@ -3130,19 +3130,14 @@ entry: ret i8 %i } -; FIXME: This should be simplifiable. See comment inside. - define i8 @gep_index_from_memory(i1 %cnd1, i1 %cnd2) { ; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none) ; CHECK-LABEL: define {{[^@]+}}@gep_index_from_memory ; CHECK-SAME: (i1 [[CND1:%.*]], i1 [[CND2:%.*]]) #[[ATTR4]] { ; CHECK-NEXT: entry: ; CHECK-NEXT: [[BYTES:%.*]] = alloca [1024 x i8], align 16 -; CHECK-NEXT: [[GEP_FIXED:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 12 ; CHECK-NEXT: [[GEP_LOADED:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 12 -; CHECK-NEXT: store i8 100, i8* [[GEP_LOADED]], align 4 -; CHECK-NEXT: [[I:%.*]] = load i8, i8* [[GEP_FIXED]], align 4 -; CHECK-NEXT: ret i8 [[I]] +; CHECK-NEXT: ret i8 100 ; entry: %Bytes = alloca [1024 x i8], align 16 @@ -3152,8 +3147,6 @@ entry: %offset = load i64, i64* %gep.addr, align 8 %gep.fixed = getelementptr inbounds [1024 x i8], [1024 x i8]* %Bytes, i64 0, i64 12 - ; FIXME: AAPotentialConstantValues does not detect the constant offset being - ; passed to this GEP. It needs to rely on AAPotentialValues. %gep.loaded = getelementptr inbounds [1024 x i8], [1024 x i8]* %Bytes, i64 0, i64 %offset store i8 100, i8* %gep.loaded, align 4 diff --git a/llvm/test/Transforms/Attributor/value-simplify.ll b/llvm/test/Transforms/Attributor/value-simplify.ll index 99e0bdbc7b46..490b5bb7e876 100644 --- a/llvm/test/Transforms/Attributor/value-simplify.ll +++ b/llvm/test/Transforms/Attributor/value-simplify.ll @@ -188,11 +188,12 @@ define void @test-select-phi(i1 %c) { ; CHECK-NEXT: [[PHI_NOT_SAME:%.*]] = phi i32 [ 0, [[IF_TRUE]] ], [ 1, [[IF_FALSE]] ] ; CHECK-NEXT: [[PHI_SAME_PROP:%.*]] = phi i32 [ 1, [[IF_TRUE]] ], [ 1, [[IF_FALSE]] ] ; CHECK-NEXT: [[PHI_SAME_UNDEF:%.*]] = phi i32 [ 1, [[IF_TRUE]] ], [ undef, [[IF_FALSE]] ] +; CHECK-NEXT: [[SELECT_NOT_SAME_UNDEF:%.*]] = select i1 [[C]], i32 [[PHI_NOT_SAME]], i32 undef ; CHECK-NEXT: tail call void @use(i32 noundef 1) ; CHECK-NEXT: tail call void @use(i32 noundef [[PHI_NOT_SAME]]) ; CHECK-NEXT: tail call void @use(i32 noundef 1) ; CHECK-NEXT: tail call void @use(i32 1) -; CHECK-NEXT: tail call void @use(i32 [[PHI_NOT_SAME]]) +; CHECK-NEXT: tail call void @use(i32 [[SELECT_NOT_SAME_UNDEF]]) ; CHECK-NEXT: ret void ; %select-same = select i1 %c, i32 1, i32 1 diff --git a/llvm/test/Transforms/Attributor/willreturn.ll b/llvm/test/Transforms/Attributor/willreturn.ll index a84393c73f30..76675f9c8ab6 100644 --- a/llvm/test/Transforms/Attributor/willreturn.ll +++ b/llvm/test/Transforms/Attributor/willreturn.ll @@ -1,5 +1,5 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals -; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=15 -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT +; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=14 -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT ; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,CGSCC target datalayout = "e-m:e-i54:64-f80:128-n8:16:32:64-S128"