We can always look through single-argument (LCSSA) phi nodes when
performing alias analysis. getUnderlyingObject() already does this,
but stripPointerCastsAndInvariantGroups() does not. We still look
through these phi nodes with the usual aliasPhi() logic, but
sometimes get sub-optimal results due to the restrictions on value
equivalence when looking through arbitrary phi nodes. I think it's
generally beneficial to keep the underlying object logic and the
pointer cast stripping logic in sync, insofar as it is possible.
With this patch we get marginally better results:
aa.NumMayAlias | 5010069 | 5009861
aa.NumMustAlias | 347518 | 347674
aa.NumNoAlias |
27201336 |
27201528
...
licm.NumPromoted | 1293 | 1296
I've renamed the relevant strip method to stripPointerCastsForAliasAnalysis(),
as we're past the point where we can explicitly spell out everything
that's getting stripped.
Differential Revision: https://reviews.llvm.org/D96668
->stripPointerCastsSameRepresentation());
}
- /// Strip off pointer casts, all-zero GEPs and invariant group info.
+ /// Strip off pointer casts, all-zero GEPs, single-argument phi nodes and
+ /// invariant group info.
///
/// Returns the original uncasted value. If this is called on a non-pointer
/// value, it returns 'this'. This function should be used only in
/// Alias analysis.
- const Value *stripPointerCastsAndInvariantGroups() const;
- Value *stripPointerCastsAndInvariantGroups() {
+ const Value *stripPointerCastsForAliasAnalysis() const;
+ Value *stripPointerCastsForAliasAnalysis() {
return const_cast<Value *>(static_cast<const Value *>(this)
- ->stripPointerCastsAndInvariantGroups());
+ ->stripPointerCastsForAliasAnalysis());
}
/// Strip off pointer casts and all-constant inbounds GEPs.
return NoAlias;
// Strip off any casts if they exist.
- V1 = V1->stripPointerCastsAndInvariantGroups();
- V2 = V2->stripPointerCastsAndInvariantGroups();
+ V1 = V1->stripPointerCastsForAliasAnalysis();
+ V2 = V2->stripPointerCastsForAliasAnalysis();
// If V1 or V2 is undef, the result is NoAlias because we can always pick a
// value for undef that aliases nothing in the program.
AAQueryInfo &AAQI) {
// Get the base object these pointers point to.
const Value *UV1 =
- getUnderlyingObject(LocA.Ptr->stripPointerCastsAndInvariantGroups());
+ getUnderlyingObject(LocA.Ptr->stripPointerCastsForAliasAnalysis());
const Value *UV2 =
- getUnderlyingObject(LocB.Ptr->stripPointerCastsAndInvariantGroups());
+ getUnderlyingObject(LocB.Ptr->stripPointerCastsForAliasAnalysis());
// If either of the underlying values is a global, they may be non-addr-taken
// globals, which we can answer queries about.
PSK_ZeroIndices,
PSK_ZeroIndicesAndAliases,
PSK_ZeroIndicesSameRepresentation,
- PSK_ZeroIndicesAndInvariantGroups,
+ PSK_ForAliasAnalysis,
PSK_InBoundsConstantIndices,
PSK_InBounds
};
case PSK_ZeroIndices:
case PSK_ZeroIndicesAndAliases:
case PSK_ZeroIndicesSameRepresentation:
- case PSK_ZeroIndicesAndInvariantGroups:
+ case PSK_ForAliasAnalysis:
if (!GEP->hasAllZeroIndices())
return V;
break;
V = cast<Operator>(V)->getOperand(0);
} else if (StripKind == PSK_ZeroIndicesAndAliases && isa<GlobalAlias>(V)) {
V = cast<GlobalAlias>(V)->getAliasee();
+ } else if (StripKind == PSK_ForAliasAnalysis && isa<PHINode>(V) &&
+ cast<PHINode>(V)->getNumIncomingValues() == 1) {
+ V = cast<PHINode>(V)->getIncomingValue(0);
} else {
if (const auto *Call = dyn_cast<CallBase>(V)) {
if (const Value *RV = Call->getReturnedArgOperand()) {
// The result of launder.invariant.group must alias it's argument,
// but it can't be marked with returned attribute, that's why it needs
// special case.
- if (StripKind == PSK_ZeroIndicesAndInvariantGroups &&
+ if (StripKind == PSK_ForAliasAnalysis &&
(Call->getIntrinsicID() == Intrinsic::launder_invariant_group ||
Call->getIntrinsicID() == Intrinsic::strip_invariant_group)) {
V = Call->getArgOperand(0);
return stripPointerCastsAndOffsets<PSK_InBoundsConstantIndices>(this);
}
-const Value *Value::stripPointerCastsAndInvariantGroups() const {
- return stripPointerCastsAndOffsets<PSK_ZeroIndicesAndInvariantGroups>(this);
+const Value *Value::stripPointerCastsForAliasAnalysis() const {
+ return stripPointerCastsAndOffsets<PSK_ForAliasAnalysis>(this);
}
const Value *Value::stripAndAccumulateConstantOffsets(
if (asA == AMDGPUAS::FLAT_ADDRESS &&
(asB == AMDGPUAS::LOCAL_ADDRESS || asB == AMDGPUAS::PRIVATE_ADDRESS)) {
const auto *ObjA =
- getUnderlyingObject(A.Ptr->stripPointerCastsAndInvariantGroups());
+ getUnderlyingObject(A.Ptr->stripPointerCastsForAliasAnalysis());
if (const LoadInst *LI = dyn_cast<LoadInst>(ObjA)) {
// If a generic pointer is loaded from the constant address space, it
// could only be a GLOBAL or CONSTANT one as that address space is soley
InstCombinerImpl &IC) {
auto *Arg = II.getArgOperand(0);
auto *StrippedArg = Arg->stripPointerCasts();
- auto *StrippedInvariantGroupsArg = Arg->stripPointerCastsAndInvariantGroups();
+ auto *StrippedInvariantGroupsArg = StrippedArg;
+ while (auto *Intr = dyn_cast<IntrinsicInst>(StrippedInvariantGroupsArg)) {
+ if (Intr->getIntrinsicID() != Intrinsic::launder_invariant_group &&
+ Intr->getIntrinsicID() != Intrinsic::strip_invariant_group)
+ break;
+ StrippedInvariantGroupsArg = Intr->getArgOperand(0)->stripPointerCasts();
+ }
if (StrippedArg == StrippedInvariantGroupsArg)
return nullptr; // No launders/strips to remove.
}
; CHECK-LABEL: single_arg_phi
-; CHECK: MayAlias: i32* %ptr, i32* %ptr.next
+; CHECK: NoAlias: i32* %ptr, i32* %ptr.next
+; CHECK: MustAlias: i32* %ptr, i32* %ptr.phi
; CHECK: MustAlias: i32* %ptr.next, i32* %ptr.next.phi
-; TODO: The first one could be MustAlias as well.
define void @single_arg_phi(i32* %ptr.base) {
entry:
br label %loop