Index: include/llvm/IR/Value.h =================================================================== --- include/llvm/IR/Value.h +++ include/llvm/IR/Value.h @@ -399,27 +399,31 @@ /// /// Returns the original uncasted value. If this is called on a non-pointer /// value, it returns 'this'. - Value *stripPointerCasts(); - const Value *stripPointerCasts() const { - return const_cast(this)->stripPointerCasts(); + Value *stripPointerCasts(bool LookThroughNoAlias = false); + const Value *stripPointerCasts(bool LookThroughNoAlias = false) const { + return const_cast(this)->stripPointerCasts(LookThroughNoAlias); } /// \brief Strip off pointer casts and all-zero GEPs. /// /// Returns the original uncasted value. If this is called on a non-pointer /// value, it returns 'this'. - Value *stripPointerCastsNoFollowAliases(); - const Value *stripPointerCastsNoFollowAliases() const { - return const_cast(this)->stripPointerCastsNoFollowAliases(); + Value *stripPointerCastsNoFollowAliases(bool LookThroughNoAlias = false); + const Value *stripPointerCastsNoFollowAliases( + bool LookThroughNoAlias = false) const { + return const_cast(this)-> + stripPointerCastsNoFollowAliases(LookThroughNoAlias); } /// \brief Strip off pointer casts and all-constant inbounds GEPs. /// /// Returns the original pointer value. If this is called on a non-pointer /// value, it returns 'this'. - Value *stripInBoundsConstantOffsets(); - const Value *stripInBoundsConstantOffsets() const { - return const_cast(this)->stripInBoundsConstantOffsets(); + Value *stripInBoundsConstantOffsets(bool LookThroughNoAlias = false); + const Value *stripInBoundsConstantOffsets( + bool LookThroughNoAlias = false) const { + return const_cast(this)-> + stripInBoundsConstantOffsets(LookThroughNoAlias); } /// \brief Accumulate offsets from \a stripInBoundsConstantOffsets(). @@ -430,20 +434,21 @@ /// /// If this is called on a non-pointer value, it returns 'this'. Value *stripAndAccumulateInBoundsConstantOffsets(const DataLayout &DL, - APInt &Offset); + APInt &Offset, bool LookThroughNoAlias = false); const Value *stripAndAccumulateInBoundsConstantOffsets(const DataLayout &DL, - APInt &Offset) const { + APInt &Offset, bool LookThroughNoAlias = false) const { return const_cast(this) - ->stripAndAccumulateInBoundsConstantOffsets(DL, Offset); + ->stripAndAccumulateInBoundsConstantOffsets(DL, Offset, + LookThroughNoAlias); } /// \brief Strip off pointer casts and inbounds GEPs. /// /// Returns the original pointer value. If this is called on a non-pointer /// value, it returns 'this'. - Value *stripInBoundsOffsets(); - const Value *stripInBoundsOffsets() const { - return const_cast(this)->stripInBoundsOffsets(); + Value *stripInBoundsOffsets(bool LookThroughNoAlias = false); + const Value *stripInBoundsOffsets(bool LookThroughNoAlias = false) const { + return const_cast(this)->stripInBoundsOffsets(LookThroughNoAlias); } /// \brief Translate PHI node to its predecessor from the given basic block. Index: lib/Analysis/BasicAliasAnalysis.cpp =================================================================== --- lib/Analysis/BasicAliasAnalysis.cpp +++ lib/Analysis/BasicAliasAnalysis.cpp @@ -321,6 +321,12 @@ const GEPOperator *GEPOp = dyn_cast(Op); if (!GEPOp) { + if (const IntrinsicInst *I = dyn_cast(V)) + if (I->getIntrinsicID() == Intrinsic::noalias) { + V = I->getOperand(0); + 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. if (const Instruction *I = dyn_cast(V)) @@ -890,7 +896,10 @@ const GEPOperator *GEP2, uint64_t V2Size, const DataLayout &DL) { - assert(GEP1->getPointerOperand() == GEP2->getPointerOperand() && + assert(GEP1->getPointerOperand()->stripPointerCasts(true) == + GEP2->getPointerOperand()->stripPointerCasts(true) && + GEP1->getPointerOperand()->getType() == + GEP2->getPointerOperand()->getType() && "Expected GEPs with the same pointer operand"); // Try to determine whether GEP1 and GEP2 index through arrays, into structs, @@ -1087,8 +1096,12 @@ // 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 (DL && GEP1->getPointerOperand() == GEP2->getPointerOperand()) { - AliasResult R = aliasSameBasePointerGEPs(GEP1, V1Size, GEP2, V2Size, *DL); + if (DL && GEP1->getPointerOperand()->stripPointerCasts(true) == + GEP2->getPointerOperand()->stripPointerCasts(true) && + GEP1->getPointerOperand()->getType() == + GEP2->getPointerOperand()->getType()) { + AliasResult R = + aliasSameBasePointerGEPs(GEP1, V1Size, GEP2, V2Size, *DL); // If we couldn't find anything interesting, don't abandon just yet. if (R != MayAlias) return R; @@ -1386,8 +1399,8 @@ return NoAlias; // Strip off any casts if they exist. - V1 = V1->stripPointerCasts(); - V2 = V2->stripPointerCasts(); + V1 = V1->stripPointerCasts(/*LookThroughNoAlias*/true); + V2 = V2->stripPointerCasts(/*LookThroughNoAlias*/true); // Are we checking for alias of the same value? // Because we look 'through' phi nodes we could look at "Value" pointers from Index: lib/Analysis/ValueTracking.cpp =================================================================== --- lib/Analysis/ValueTracking.cpp +++ lib/Analysis/ValueTracking.cpp @@ -2780,6 +2780,12 @@ return V; V = GA->getAliasee(); } else { + if (IntrinsicInst *I = dyn_cast(V)) + if (I->getIntrinsicID() == Intrinsic::noalias) { + V = I->getOperand(0); + continue; + } + // See if InstructionSimplify knows any relevant tricks. if (Instruction *I = dyn_cast(V)) // TODO: Acquire a DominatorTree and AssumptionCache and use them. Index: lib/IR/Value.cpp =================================================================== --- lib/IR/Value.cpp +++ lib/IR/Value.cpp @@ -380,7 +380,7 @@ }; template -static Value *stripPointerCastsAndOffsets(Value *V) { +static Value *stripPointerCastsAndOffsets(Value *V, bool LookThroughNoAlias) { if (!V->getType()->isPointerTy()) return V; @@ -415,6 +415,13 @@ return V; V = GA->getAliasee(); } else { + if (LookThroughNoAlias) + if (IntrinsicInst *I = dyn_cast(V)) + if (I->getIntrinsicID() == Intrinsic::noalias) { + V = I->getOperand(0); + continue; + } + return V; } assert(V->getType()->isPointerTy() && "Unexpected operand type!"); @@ -424,20 +431,22 @@ } } // namespace -Value *Value::stripPointerCasts() { - return stripPointerCastsAndOffsets(this); +Value *Value::stripPointerCasts(bool LookThroughNoAlias) { + return stripPointerCastsAndOffsets( + this, LookThroughNoAlias); } -Value *Value::stripPointerCastsNoFollowAliases() { - return stripPointerCastsAndOffsets(this); +Value *Value::stripPointerCastsNoFollowAliases(bool LookThroughNoAlias) { + return stripPointerCastsAndOffsets(this, LookThroughNoAlias); } -Value *Value::stripInBoundsConstantOffsets() { - return stripPointerCastsAndOffsets(this); +Value *Value::stripInBoundsConstantOffsets(bool LookThroughNoAlias) { + return stripPointerCastsAndOffsets( + this, LookThroughNoAlias); } Value *Value::stripAndAccumulateInBoundsConstantOffsets(const DataLayout &DL, - APInt &Offset) { + APInt &Offset, bool LookThroughNoAlias) { if (!getType()->isPointerTy()) return this; @@ -465,6 +474,13 @@ } else if (GlobalAlias *GA = dyn_cast(V)) { V = GA->getAliasee(); } else { + if (LookThroughNoAlias) + if (IntrinsicInst *I = dyn_cast(V)) + if (I->getIntrinsicID() == Intrinsic::noalias) { + V = I->getOperand(0); + continue; + } + return V; } assert(V->getType()->isPointerTy() && "Unexpected operand type!"); @@ -473,8 +489,8 @@ return V; } -Value *Value::stripInBoundsOffsets() { - return stripPointerCastsAndOffsets(this); +Value *Value::stripInBoundsOffsets(bool LookThroughNoAlias) { + return stripPointerCastsAndOffsets(this, LookThroughNoAlias); } Value *Value::DoPHITranslation(const BasicBlock *CurBB, Index: test/Analysis/BasicAA/noalias.ll =================================================================== --- /dev/null +++ test/Analysis/BasicAA/noalias.ll @@ -0,0 +1,48 @@ +; RUN: opt < %s -basicaa -aa-eval -print-all-alias-modref-info -disable-output 2>&1 | FileCheck %s + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + +%struct = type { i32, i32, i32 } + +; CHECK-LABEL: test_simple + +; CHECK-DAG: MustAlias: %struct* %st, %struct* %sta + +; CHECK-DAG: PartialAlias: %struct* %st, i32* %x +; CHECK-DAG: PartialAlias: %struct* %st, i32* %y +; CHECK-DAG: PartialAlias: %struct* %st, i32* %z + +; CHECK-DAG: NoAlias: i32* %x, i32* %y +; CHECK-DAG: NoAlias: i32* %x, i32* %z +; CHECK-DAG: NoAlias: i32* %y, i32* %z + +; CHECK-DAG: PartialAlias: %struct* %st, %struct* %y_12 +; CHECK-DAG: PartialAlias: %struct* %y_12, i32* %x +; CHECK-DAG: PartialAlias: i32* %x, i80* %y_10 + +; CHECK-DAG: PartialAlias: %struct* %st, i64* %y_8 +; CHECK-DAG: PartialAlias: i32* %z, i64* %y_8 +; CHECK-DAG: NoAlias: i32* %x, i64* %y_8 + +; CHECK-DAG: MustAlias: %struct* %y_12, i32* %y +; CHECK-DAG: MustAlias: i32* %y, i64* %y_8 +; CHECK-DAG: MustAlias: i32* %y, i80* %y_10 + +define void @test_simple(%struct* %st, i64 %i, i64 %j, i64 %k) { + %x = getelementptr %struct, %struct* %st, i64 %i, i32 0 + %y = getelementptr %struct, %struct* %st, i64 %j, i32 1 + %sta = call %struct* @llvm.noalias.p0struct(%struct* %st, metadata !1) + %z = getelementptr %struct, %struct* %sta, i64 %k, i32 2 + %y_12 = bitcast i32* %y to %struct* + %y_10 = bitcast i32* %y to i80* + %ya = call i32* @llvm.noalias.p0i32(i32* %y, metadata !1) + %y_8 = bitcast i32* %ya to i64* + ret void +} + +declare i32* @llvm.noalias.p0i32(i32*, metadata) nounwind +declare %struct* @llvm.noalias.p0struct(%struct*, metadata) nounwind + +!0 = !{!0, !"some domain"} +!1 = !{!1, !0, !"some scope"} +