Index: include/llvm/IR/Value.h =================================================================== --- include/llvm/IR/Value.h +++ include/llvm/IR/Value.h @@ -481,6 +481,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; @@ -466,8 +466,14 @@ } else { if (auto CS = CallSite(V)) if (Value *RV = CS.getReturnedArgOperand()) { - V = RV; - continue; + bool IsNoAlias = false; + if (auto *I = dyn_cast(V)) + IsNoAlias = I->getIntrinsicID() == Intrinsic::noalias; + + if (StripNoAlias || !IsNoAlias) { + V = RV; + continue; + } } return V; @@ -487,6 +493,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 @@ -1655,7 +1655,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"}