Index: include/llvm/IR/Value.h =================================================================== --- include/llvm/IR/Value.h +++ include/llvm/IR/Value.h @@ -480,6 +480,16 @@ return const_cast(this)->stripInBoundsConstantOffsets(); } + /// \brief Strip off pointer casts and all-zero GEPs without stripping + /// @llvm.noalias intrinsics. + /// + /// Returns the original uncasted value. If this is called on a non-pointer + /// value, it returns 'this'. + Value *stripPointerCastsExceptNoAlias(); + const Value *stripPointerCastsExceptNoAlias() const { + return const_cast(this)->stripPointerCastsExceptNoAlias(); + } + /// \brief Accumulate offsets from \a stripInBoundsConstantOffsets(). /// /// Stores the resulting constant offset stripped into the APInt provided. Index: lib/IR/Value.cpp =================================================================== --- lib/IR/Value.cpp +++ lib/IR/Value.cpp @@ -429,7 +429,7 @@ }; template -static Value *stripPointerCastsAndOffsets(Value *V) { +static Value *stripPointerCastsAndOffsets(Value *V, bool StripNoAlias = true) { if (!V->getType()->isPointerTy()) return V; @@ -465,7 +465,7 @@ V = GA->getAliasee(); } else { if (IntrinsicInst *I = dyn_cast(V)) - if (I->getIntrinsicID() == Intrinsic::noalias) { + if (StripNoAlias && I->getIntrinsicID() == Intrinsic::noalias) { V = I->getOperand(0); continue; } @@ -487,6 +487,10 @@ return stripPointerCastsAndOffsets(this); } +Value *Value::stripPointerCastsExceptNoAlias() { + return stripPointerCastsAndOffsets(this, false); +} + Value *Value::stripInBoundsConstantOffsets() { return stripPointerCastsAndOffsets(this); } Index: lib/Transforms/InstCombine/InstructionCombining.cpp =================================================================== --- lib/Transforms/InstCombine/InstructionCombining.cpp +++ lib/Transforms/InstCombine/InstructionCombining.cpp @@ -1605,7 +1605,7 @@ } // Handle gep(bitcast x) and gep(gep x, 0, 0, 0). - Value *StrippedPtr = PtrOp->stripPointerCasts(); + Value *StrippedPtr = PtrOp->stripPointerCastsExceptNoAlias(); PointerType *StrippedPtrTy = dyn_cast(StrippedPtr->getType()); // We do not handle pointer-vector geps here. Index: test/Transforms/InstCombine/noalias.ll =================================================================== --- /dev/null +++ test/Transforms/InstCombine/noalias.ll @@ -0,0 +1,24 @@ +; RUN: opt < %s -instcombine -S | FileCheck %s + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + +@g = global i32* null + +define i32 @test1(i32* %q, i32* %p, i1 %b) { + %pa = tail call i32* @llvm.noalias.p0i32(i32* %p, metadata !0) + %tmp2 = getelementptr inbounds i32, i32* %pa, i64 2 + %val = load i32, i32* %tmp2, align 4 + store i32 0, i32* %pa, align 4 + store i32* %q, i32** @g, align 8 + ret i32 %val + +; CHECK-LABEL: @test1 +; CHECK: call i32* @llvm.noalias.p0i32 +; CHECK: getelementptr inbounds i32, i32* %pa, i64 2 +; CHECK: ret i32 +} + +declare i32* @llvm.noalias.p0i32(i32*, metadata) nounwind + +!0 = !{!0, !"some domain"} +!1 = !{!1, !0, !"some scope"}