Fix aliasing of launder.invariant.group
Summary:
Patch for capture tracking broke
bootstrap of clang with -fstict-vtable-pointers
which resulted in debbugging nightmare. It was fixed
https://reviews.llvm.org/D46900 but as it turned
out, there were other parts like inliner (computing of
noalias metadata) that I found after bootstraping with enabled
assertions.
Reviewers: hfinkel, rsmith, chandlerc, amharc, kuhar
Subscribers: JDevlieghere, eraman, llvm-commits, hiraditya
Differential Revision: https://reviews.llvm.org/D47088
llvm-svn: 333070
diff --git a/llvm/lib/Analysis/BasicAliasAnalysis.cpp b/llvm/lib/Analysis/BasicAliasAnalysis.cpp
index 55a53f2..c1582b6 100644
--- a/llvm/lib/Analysis/BasicAliasAnalysis.cpp
+++ b/llvm/lib/Analysis/BasicAliasAnalysis.cpp
@@ -132,16 +132,8 @@
/// Returns true if the pointer is one which would have been considered an
/// escape by isNonEscapingLocalObject.
static bool isEscapeSource(const Value *V) {
- if (auto CS = ImmutableCallSite(V)) {
- // launder_invariant_group captures its argument only by returning it,
- // so it might not be considered an escape by isNonEscapingLocalObject.
- // Note that adding similar special cases for intrinsics in CaptureTracking
- // requires handling them here too.
- if (CS.getIntrinsicID() == Intrinsic::launder_invariant_group)
- return false;
-
+ if (ImmutableCallSite(V))
return true;
- }
if (isa<Argument>(V))
return true;
@@ -438,11 +430,19 @@
const GEPOperator *GEPOp = dyn_cast<GEPOperator>(Op);
if (!GEPOp) {
- if (auto CS = ImmutableCallSite(V))
- if (const Value *RV = CS.getReturnedArgOperand()) {
- V = RV;
+ if (auto CS = ImmutableCallSite(V)) {
+ // Note: getArgumentAliasingToReturnedPointer keeps it in sync with
+ // CaptureTracking, which is needed for correctness. This is because
+ // some intrinsics like launder.invariant.group returns pointers that
+ // are aliasing it's argument, which is known to CaptureTracking.
+ // If AliasAnalysis does not use the same information, it could assume
+ // that pointer returned from launder does not alias it's argument
+ // because launder could not return it if the pointer was not captured.
+ if (auto *RP = getArgumentAliasingToReturnedPointer(CS)) {
+ V = RP;
continue;
}
+ }
// If it's not a GEP, hand it off to SimplifyInstruction to see if it
// can come up with something. This matches what GetUnderlyingObject does.
diff --git a/llvm/lib/Analysis/CaptureTracking.cpp b/llvm/lib/Analysis/CaptureTracking.cpp
index 54466cd..d4f73bd 100644
--- a/llvm/lib/Analysis/CaptureTracking.cpp
+++ b/llvm/lib/Analysis/CaptureTracking.cpp
@@ -22,6 +22,7 @@
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/Analysis/CFG.h"
#include "llvm/Analysis/OrderedBasicBlock.h"
+#include "llvm/Analysis/ValueTracking.h"
#include "llvm/IR/CallSite.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/Dominators.h"
@@ -247,11 +248,12 @@
if (CS.onlyReadsMemory() && CS.doesNotThrow() && I->getType()->isVoidTy())
break;
- // launder.invariant.group only captures pointer by returning it,
- // so the pointer wasn't captured if returned pointer is not captured.
- // Note that adding similar special cases for intrinsics requires handling
- // them in 'isEscapeSource' in BasicAA.
- if (CS.getIntrinsicID() == Intrinsic::launder_invariant_group) {
+ // The pointer is not captured if returned pointer is not captured.
+ // NOTE: CaptureTracking users should not assume that only functions
+ // marked with nocapture do not capture. This means that places like
+ // GetUnderlyingObject in ValueTracking or DecomposeGEPExpression
+ // in BasicAA also need to know about this property.
+ if (isIntrinsicReturningPointerAliasingArgumentWithoutCapturing(CS)) {
AddUses(I);
break;
}
diff --git a/llvm/lib/Analysis/Loads.cpp b/llvm/lib/Analysis/Loads.cpp
index fda1395..d319d4c 100644
--- a/llvm/lib/Analysis/Loads.cpp
+++ b/llvm/lib/Analysis/Loads.cpp
@@ -107,14 +107,11 @@
return isDereferenceableAndAlignedPointer(ASC->getOperand(0), Align, Size,
DL, CtxI, DT, Visited);
- if (auto CS = ImmutableCallSite(V)) {
- if (const Value *RV = CS.getReturnedArgOperand())
- return isDereferenceableAndAlignedPointer(RV, Align, Size, DL, CtxI, DT,
+ if (auto CS = ImmutableCallSite(V))
+ if (auto *RP = getArgumentAliasingToReturnedPointer(CS))
+ return isDereferenceableAndAlignedPointer(RP, Align, Size, DL, CtxI, DT,
Visited);
- if (CS.getIntrinsicID() == Intrinsic::launder_invariant_group)
- return isDereferenceableAndAlignedPointer(CS->getOperand(0), Align, Size,
- DL, CtxI, DT, Visited);
- }
+
// If we don't know, assume the worst.
return false;
}
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 0b0dfde..7f33c67 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -1956,8 +1956,8 @@
if (auto CS = ImmutableCallSite(V)) {
if (CS.isReturnNonNull())
return true;
- if (CS.getIntrinsicID() == Intrinsic::ID::launder_invariant_group)
- return isKnownNonZero(CS->getOperand(0), Depth + 1, Q);
+ if (const auto *RP = getArgumentAliasingToReturnedPointer(CS))
+ return isKnownNonZero(RP, Depth + 1, Q);
}
}
@@ -3385,6 +3385,22 @@
return Len == ~0ULL ? 1 : Len;
}
+const Value *llvm::getArgumentAliasingToReturnedPointer(ImmutableCallSite CS) {
+ assert(CS &&
+ "getArgumentAliasingToReturnedPointer only works on nonnull CallSite");
+ if (const Value *RV = CS.getReturnedArgOperand())
+ return RV;
+ // This can be used only as a aliasing property.
+ if (isIntrinsicReturningPointerAliasingArgumentWithoutCapturing(CS))
+ return CS.getArgOperand(0);
+ return nullptr;
+}
+
+bool llvm::isIntrinsicReturningPointerAliasingArgumentWithoutCapturing(
+ ImmutableCallSite CS) {
+ return CS.getIntrinsicID() == Intrinsic::launder_invariant_group;
+}
+
/// \p PN defines a loop-variant pointer to an object. Check if the
/// previous iteration of the loop was referring to the same object as \p PN.
static bool isSameUnderlyingObjectInLoop(const PHINode *PN,
@@ -3430,11 +3446,19 @@
// An alloca can't be further simplified.
return V;
} else {
- if (auto CS = CallSite(V))
- if (Value *RV = CS.getReturnedArgOperand()) {
- V = RV;
+ if (auto CS = CallSite(V)) {
+ // Note: getArgumentAliasingToReturnedPointer keeps it in sync with
+ // CaptureTracking, which is needed for correctness. This is because
+ // some intrinsics like launder.invariant.group returns pointers that
+ // are aliasing it's argument, which is known to CaptureTracking.
+ // If AliasAnalysis does not use the same information, it could assume
+ // that pointer returned from launder does not alias it's argument
+ // because launder could not return it if the pointer was not captured.
+ if (auto *RP = getArgumentAliasingToReturnedPointer(CS)) {
+ V = RP;
continue;
}
+ }
// See if InstructionSimplify knows any relevant tricks.
if (Instruction *I = dyn_cast<Instruction>(V))