summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPiotr Padlewski <piotr.padlewski@gmail.com>2017-04-24 19:37:17 +0000
committerPiotr Padlewski <piotr.padlewski@gmail.com>2017-04-24 19:37:17 +0000
commit610c966a4e90775860e9c3eb91efbd6b1e0dd28b (patch)
treec84ced328dd0f77856db909a5fb3f13a69e9828f
parent9e536081fe7d66304913d8118a1123340f2b74e3 (diff)
downloadbcm5719-llvm-610c966a4e90775860e9c3eb91efbd6b1e0dd28b.tar.gz
bcm5719-llvm-610c966a4e90775860e9c3eb91efbd6b1e0dd28b.zip
Handle invariant.group.barrier in BasicAA
Summary: llvm.invariant.group.barrier returns pointer that mustalias pointer it takes. It can't be marked with `returned` attribute, because it would be remove easily. The other reason is that only Alias Analysis can know about this, because if any other pass would know it, then the result would be replaced with it's argument, which would be invalid. We can think about returned pointer as something that mustalias, but it doesn't have to be bitwise the same as the argument. Reviewers: dberlin, chandlerc, hfinkel, sanjoy Subscribers: reames, nlewycky, rsmith, anna, amharc Differential Revision: https://reviews.llvm.org/D31585 llvm-svn: 301227
-rw-r--r--llvm/include/llvm/IR/Value.h11
-rw-r--r--llvm/lib/Analysis/BasicAliasAnalysis.cpp12
-rw-r--r--llvm/lib/IR/Value.cpp19
-rw-r--r--llvm/test/Other/Inputs/invariant.group.barrier.ll15
-rw-r--r--llvm/test/Transforms/GVN/invariant.group.ll12
5 files changed, 56 insertions, 13 deletions
diff --git a/llvm/include/llvm/IR/Value.h b/llvm/include/llvm/IR/Value.h
index a4b48d7f353..00f82139925 100644
--- a/llvm/include/llvm/IR/Value.h
+++ b/llvm/include/llvm/IR/Value.h
@@ -482,6 +482,17 @@ public:
static_cast<const Value *>(this)->stripPointerCasts());
}
+ /// \brief Strip off pointer casts, all-zero GEPs, aliases and barriers.
+ ///
+ /// 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 *stripPointerCastsAndBarriers() const;
+ Value *stripPointerCastsAndBarriers() {
+ return const_cast<Value *>(
+ static_cast<const Value *>(this)->stripPointerCastsAndBarriers());
+ }
+
/// \brief Strip off pointer casts and all-zero GEPs.
///
/// Returns the original uncasted value. If this is called on a non-pointer
diff --git a/llvm/lib/Analysis/BasicAliasAnalysis.cpp b/llvm/lib/Analysis/BasicAliasAnalysis.cpp
index 3db041cc0fa..53782302030 100644
--- a/llvm/lib/Analysis/BasicAliasAnalysis.cpp
+++ b/llvm/lib/Analysis/BasicAliasAnalysis.cpp
@@ -924,8 +924,8 @@ static AliasResult aliasSameBasePointerGEPs(const GEPOperator *GEP1,
uint64_t V2Size,
const DataLayout &DL) {
- assert(GEP1->getPointerOperand()->stripPointerCasts() ==
- GEP2->getPointerOperand()->stripPointerCasts() &&
+ assert(GEP1->getPointerOperand()->stripPointerCastsAndBarriers() ==
+ GEP2->getPointerOperand()->stripPointerCastsAndBarriers() &&
GEP1->getPointerOperandType() == GEP2->getPointerOperandType() &&
"Expected GEPs with the same pointer operand");
@@ -1184,8 +1184,8 @@ AliasResult BasicAAResult::aliasGEP(const GEPOperator *GEP1, uint64_t V1Size,
// If we know the two GEPs are based off of the exact same pointer (and not
// just the same underlying object), see if that tells us anything about
// the resulting pointers.
- if (GEP1->getPointerOperand()->stripPointerCasts() ==
- GEP2->getPointerOperand()->stripPointerCasts() &&
+ if (GEP1->getPointerOperand()->stripPointerCastsAndBarriers() ==
+ GEP2->getPointerOperand()->stripPointerCastsAndBarriers() &&
GEP1->getPointerOperandType() == GEP2->getPointerOperandType()) {
AliasResult R = aliasSameBasePointerGEPs(GEP1, V1Size, GEP2, V2Size, DL);
// If we couldn't find anything interesting, don't abandon just yet.
@@ -1500,8 +1500,8 @@ AliasResult BasicAAResult::aliasCheck(const Value *V1, uint64_t V1Size,
return NoAlias;
// Strip off any casts if they exist.
- V1 = V1->stripPointerCasts();
- V2 = V2->stripPointerCasts();
+ V1 = V1->stripPointerCastsAndBarriers();
+ V2 = V2->stripPointerCastsAndBarriers();
// 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.
diff --git a/llvm/lib/IR/Value.cpp b/llvm/lib/IR/Value.cpp
index b07c57685a2..d83bdf2acd4 100644
--- a/llvm/lib/IR/Value.cpp
+++ b/llvm/lib/IR/Value.cpp
@@ -432,6 +432,7 @@ namespace {
enum PointerStripKind {
PSK_ZeroIndices,
PSK_ZeroIndicesAndAliases,
+ PSK_ZeroIndicesAndAliasesAndBarriers,
PSK_InBoundsConstantIndices,
PSK_InBounds
};
@@ -450,6 +451,7 @@ static const Value *stripPointerCastsAndOffsets(const Value *V) {
if (auto *GEP = dyn_cast<GEPOperator>(V)) {
switch (StripKind) {
case PSK_ZeroIndicesAndAliases:
+ case PSK_ZeroIndicesAndAliasesAndBarriers:
case PSK_ZeroIndices:
if (!GEP->hasAllZeroIndices())
return V;
@@ -472,12 +474,20 @@ static const Value *stripPointerCastsAndOffsets(const Value *V) {
return V;
V = GA->getAliasee();
} else {
- if (auto CS = ImmutableCallSite(V))
+ if (auto CS = ImmutableCallSite(V)) {
if (const Value *RV = CS.getReturnedArgOperand()) {
V = RV;
continue;
}
-
+ // The result of invariant.group.barrier must alias it's argument,
+ // but it can't be marked with returned attribute, that's why it needs
+ // special case.
+ if (StripKind == PSK_ZeroIndicesAndAliasesAndBarriers &&
+ CS.getIntrinsicID() == Intrinsic::invariant_group_barrier) {
+ V = CS.getArgOperand(0);
+ continue;
+ }
+ }
return V;
}
assert(V->getType()->isPointerTy() && "Unexpected operand type!");
@@ -499,6 +509,11 @@ const Value *Value::stripInBoundsConstantOffsets() const {
return stripPointerCastsAndOffsets<PSK_InBoundsConstantIndices>(this);
}
+const Value *Value::stripPointerCastsAndBarriers() const {
+ return stripPointerCastsAndOffsets<PSK_ZeroIndicesAndAliasesAndBarriers>(
+ this);
+}
+
const Value *
Value::stripAndAccumulateInBoundsConstantOffsets(const DataLayout &DL,
APInt &Offset) const {
diff --git a/llvm/test/Other/Inputs/invariant.group.barrier.ll b/llvm/test/Other/Inputs/invariant.group.barrier.ll
new file mode 100644
index 00000000000..565b0989ecb
--- /dev/null
+++ b/llvm/test/Other/Inputs/invariant.group.barrier.ll
@@ -0,0 +1,15 @@
+; RUN: opt -S -gvn < %s | FileCheck %s
+; RUN: opt -S -newgvn < %s | FileCheck %s
+; RUN: opt -S -O3 < %s | FileCheck %s
+
+; This test check if optimizer is not proving equality based on mustalias
+; CHECK-LABEL: define void @dontProveEquality(i8* %a)
+define void @dontProveEquality(i8* %a) {
+ %b = call i8* @llvm.invariant.group.barrier(i8* %a)
+ %r = i1 icmp eq i8* %b, i8* %a
+;CHECK: call void @use(%r)
+ call void @use(%r)
+}
+
+declare void @use(i1)
+declare i8* @llvm.invariant.group.barrier(i8 *)
diff --git a/llvm/test/Transforms/GVN/invariant.group.ll b/llvm/test/Transforms/GVN/invariant.group.ll
index 570519bec52..787a1035d9c 100644
--- a/llvm/test/Transforms/GVN/invariant.group.ll
+++ b/llvm/test/Transforms/GVN/invariant.group.ll
@@ -237,15 +237,16 @@ entry:
ret i8 %a
}
-; CHECK-LABEL: define i8 @unoptimizable4() {
-define i8 @unoptimizable4() {
+; CHECK-LABEL: define i8 @optimizable4() {
+define i8 @optimizable4() {
entry:
%ptr = alloca i8
store i8 42, i8* %ptr, !invariant.group !0
%ptr2 = call i8* @llvm.invariant.group.barrier(i8* %ptr)
+; CHECK-NOT: load
%a = load i8, i8* %ptr2, !invariant.group !0
-; CHECK: ret i8 %a
+; CHECK: ret i8 42
ret i8 %a
}
@@ -314,8 +315,9 @@ entry:
store i8 %unknownValue, i8* %ptr, !invariant.group !0
%newPtr2 = call i8* @llvm.invariant.group.barrier(i8* %ptr)
- %d = load i8, i8* %newPtr2, !invariant.group !0 ; Can't step through invariant.group.barrier to get value of %ptr
-; CHECK: ret i8 %d
+; CHECK-NOT: load
+ %d = load i8, i8* %newPtr2, !invariant.group !0
+; CHECK: ret i8 %unknownValue
ret i8 %d
}
OpenPOWER on IntegriCloud