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; }
/// 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);
}
};
-/// 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,
if (!GEP->collectOffset(DL, BitWidth, VariableOffsets, ConstantOffset)) {
UsrOI.setUnknown();
- return;
+ return true;
}
LLVM_DEBUG(dbgs() << "[AAPointerInfo] GEP offset is "
*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) {
}
UsrOI = std::move(Union);
- return;
+ return true;
}
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<PtrToIntInst>(Usr))
}
bool fillSetWithConstantValues(Attributor &A, const IRPosition &IRP, SetTy &S,
- bool &ContainsUndef) {
+ bool &ContainsUndef, bool ForSelf) {
SmallVector<AA::ValueAndContext> 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<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<UndefValue>(It.getValue()))
+ if (isa<UndefValue>(It.getValue())) {
+ ContainsUndef = true;
continue;
+ }
auto *CI = dyn_cast<ConstantInt>(It.getValue());
if (!CI)
return false;
S.insert(CI->getValue());
}
- ContainsUndef = S.empty();
+ ContainsUndef &= S.empty();
return true;
}
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.
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) {
bool SrcContainsUndef = false;
SetTy SrcPVS;
if (!fillSetWithConstantValues(A, IRPosition::value(*Src), SrcPVS,
- SrcContainsUndef))
+ SrcContainsUndef, /* ForSelf */ false))
return indicatePessimisticFixpoint();
if (SrcContainsUndef)
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);
: 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();
if (auto *BinOp = dyn_cast<BinaryOperator>(I))
return updateWithBinaryOperator(A, BinOp);
+ if (isa<PHINode>(I) || isa<LoadInst>(I))
+ return updateWithInstruction(A, I);
+
return indicatePessimisticFixpoint();
}
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:%.*]]
; 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
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
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
%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