[llvm] r333070 - Fix aliasing of launder.invariant.group
Piotr Padlewski via llvm-commits
llvm-commits at lists.llvm.org
Wed May 23 02:16:44 PDT 2018
Author: prazek
Date: Wed May 23 02:16:44 2018
New Revision: 333070
URL: http://llvm.org/viewvc/llvm-project?rev=333070&view=rev
Log:
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
Added:
llvm/trunk/test/Transforms/Inline/launder.invariant.group.ll
Modified:
llvm/trunk/include/llvm/Analysis/ValueTracking.h
llvm/trunk/lib/Analysis/BasicAliasAnalysis.cpp
llvm/trunk/lib/Analysis/CaptureTracking.cpp
llvm/trunk/lib/Analysis/Loads.cpp
llvm/trunk/lib/Analysis/ValueTracking.cpp
llvm/trunk/test/Analysis/ValueTracking/known-nonnull-at.ll
Modified: llvm/trunk/include/llvm/Analysis/ValueTracking.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Analysis/ValueTracking.h?rev=333070&r1=333069&r2=333070&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Analysis/ValueTracking.h (original)
+++ llvm/trunk/include/llvm/Analysis/ValueTracking.h Wed May 23 02:16:44 2018
@@ -276,6 +276,22 @@ class Value;
/// pointer, return 'len+1'. If we can't, return 0.
uint64_t GetStringLength(const Value *V, unsigned CharSize = 8);
+ /// This function returns call pointer argument that is considered the same by
+ /// aliasing rules. You CAN'T use it to replace one value with another.
+ const Value *getArgumentAliasingToReturnedPointer(ImmutableCallSite CS);
+ inline Value *getArgumentAliasingToReturnedPointer(CallSite CS) {
+ return const_cast<Value *>(
+ getArgumentAliasingToReturnedPointer(ImmutableCallSite(CS)));
+ }
+
+ // {launder,strip}.invariant.group returns pointer that aliases its argument,
+ // and it only captures pointer by returning it.
+ // These intrinsics are not marked as nocapture, because returning is
+ // considered as capture. The arguments are not marked as returned neither,
+ // because it would make it useless.
+ bool isIntrinsicReturningPointerAliasingArgumentWithoutCapturing(
+ ImmutableCallSite CS);
+
/// This method strips off any GEP address adjustments and pointer casts from
/// the specified value, returning the original object being addressed. Note
/// that the returned value has pointer type if the specified value does. If
Modified: llvm/trunk/lib/Analysis/BasicAliasAnalysis.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/BasicAliasAnalysis.cpp?rev=333070&r1=333069&r2=333070&view=diff
==============================================================================
--- llvm/trunk/lib/Analysis/BasicAliasAnalysis.cpp (original)
+++ llvm/trunk/lib/Analysis/BasicAliasAnalysis.cpp Wed May 23 02:16:44 2018
@@ -132,16 +132,8 @@ static bool isNonEscapingLocalObject(con
/// 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 @@ bool BasicAAResult::DecomposeGEPExpressi
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.
Modified: llvm/trunk/lib/Analysis/CaptureTracking.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/CaptureTracking.cpp?rev=333070&r1=333069&r2=333070&view=diff
==============================================================================
--- llvm/trunk/lib/Analysis/CaptureTracking.cpp (original)
+++ llvm/trunk/lib/Analysis/CaptureTracking.cpp Wed May 23 02:16:44 2018
@@ -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 @@ void llvm::PointerMayBeCaptured(const Va
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;
}
Modified: llvm/trunk/lib/Analysis/Loads.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/Loads.cpp?rev=333070&r1=333069&r2=333070&view=diff
==============================================================================
--- llvm/trunk/lib/Analysis/Loads.cpp (original)
+++ llvm/trunk/lib/Analysis/Loads.cpp Wed May 23 02:16:44 2018
@@ -107,14 +107,11 @@ static bool isDereferenceableAndAlignedP
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;
}
Modified: llvm/trunk/lib/Analysis/ValueTracking.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/ValueTracking.cpp?rev=333070&r1=333069&r2=333070&view=diff
==============================================================================
--- llvm/trunk/lib/Analysis/ValueTracking.cpp (original)
+++ llvm/trunk/lib/Analysis/ValueTracking.cpp Wed May 23 02:16:44 2018
@@ -1956,8 +1956,8 @@ bool isKnownNonZero(const Value *V, unsi
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 @@ uint64_t llvm::GetStringLength(const Val
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 @@ Value *llvm::GetUnderlyingObject(Value *
// 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))
Modified: llvm/trunk/test/Analysis/ValueTracking/known-nonnull-at.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Analysis/ValueTracking/known-nonnull-at.ll?rev=333070&r1=333069&r2=333070&view=diff
==============================================================================
--- llvm/trunk/test/Analysis/ValueTracking/known-nonnull-at.ll (original)
+++ llvm/trunk/test/Analysis/ValueTracking/known-nonnull-at.ll Wed May 23 02:16:44 2018
@@ -98,3 +98,24 @@ exc:
unreachable
}
+declare i8* @returningPtr(i8* returned %p)
+
+define i1 @nonnullReturnTest(i8* nonnull %x) {
+; CHECK-LABEL: @nonnullReturnTest(
+; CHECK-NEXT: %x2 = call i8* @returningPtr(i8* %x)
+; CHECK-NEXT: ret i1 false
+ %x2 = call i8* @returningPtr(i8* %x)
+ %null_check = icmp eq i8* %x2, null
+ ret i1 %null_check
+}
+
+define i1 @unknownReturnTest(i8* %x) {
+; CHECK-LABEL: @unknownReturnTest(
+; CHECK-NEXT: %x2 = call i8* @returningPtr(i8* %x)
+; CHECK-NEXT: %null_check = icmp eq i8* %x2, null
+; CHECK-NEXT: ret i1 %null_check
+ %x2 = call i8* @returningPtr(i8* %x)
+ %null_check = icmp eq i8* %x2, null
+ ret i1 %null_check
+}
+
Added: llvm/trunk/test/Transforms/Inline/launder.invariant.group.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/Inline/launder.invariant.group.ll?rev=333070&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/Inline/launder.invariant.group.ll (added)
+++ llvm/trunk/test/Transforms/Inline/launder.invariant.group.ll Wed May 23 02:16:44 2018
@@ -0,0 +1,31 @@
+; RUN: opt -S -inline < %s | FileCheck %s
+; RUN: opt -S -O3 < %s | FileCheck %s
+
+; This test checks if value returned from the launder is considered aliasing
+; with its argument. Due to bug caused by handling launder in capture tracking
+; sometimes it would be considered noalias.
+
+%struct.A = type <{ i32 (...)**, i32, [4 x i8] }>
+
+; CHECK: define i32 @bar(%struct.A* noalias
+define i32 @bar(%struct.A* noalias) {
+; CHECK-NOT: noalias
+ %2 = bitcast %struct.A* %0 to i8*
+ %3 = call i8* @llvm.launder.invariant.group.p0i8(i8* %2)
+ %4 = getelementptr inbounds i8, i8* %3, i64 8
+ %5 = bitcast i8* %4 to i32*
+ store i32 42, i32* %5, align 8
+ %6 = getelementptr inbounds %struct.A, %struct.A* %0, i64 0, i32 1
+ %7 = load i32, i32* %6, align 8
+ ret i32 %7
+}
+
+; CHECK-LABEL: define i32 @foo(%struct.A* noalias
+define i32 @foo(%struct.A* noalias) {
+ ; CHECK-NOT: call i32 @bar(
+ ; CHECK-NOT: noalias
+ %2 = tail call i32 @bar(%struct.A* %0)
+ ret i32 %2
+}
+
+declare i8* @llvm.launder.invariant.group.p0i8(i8*)
More information about the llvm-commits
mailing list