Index: include/llvm/IR/Value.h =================================================================== --- include/llvm/IR/Value.h +++ include/llvm/IR/Value.h @@ -530,6 +530,17 @@ static_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'. + const Value *stripPointerCastsExceptNoAlias() const; + Value *stripPointerCastsExceptNoAlias() { + return const_cast( + static_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 @@ -465,7 +465,8 @@ }; template -static const Value *stripPointerCastsAndOffsets(const Value *V) { +static const Value *stripPointerCastsAndOffsets(const Value *V, + bool StripNoAlias = true) { if (!V->getType()->isPointerTy()) return V; @@ -503,8 +504,14 @@ } else { if (auto CS = ImmutableCallSite(V)) { if (const 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; + } } // 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 @@ -528,6 +535,10 @@ return stripPointerCastsAndOffsets(this); } +const Value *Value::stripPointerCastsExceptNoAlias() const { + return stripPointerCastsAndOffsets(this, false); +} + const Value *Value::stripPointerCastsNoFollowAliases() const { return stripPointerCastsAndOffsets(this); } Index: lib/Transforms/InstCombine/InstructionCombining.cpp =================================================================== --- lib/Transforms/InstCombine/InstructionCombining.cpp +++ lib/Transforms/InstCombine/InstructionCombining.cpp @@ -1730,7 +1730,7 @@ return nullptr; // Handle gep(bitcast x) and gep(gep x, 0, 0, 0). - Value *StrippedPtr = PtrOp->stripPointerCasts(); + Value *StrippedPtr = PtrOp->stripPointerCastsExceptNoAlias(); PointerType *StrippedPtrTy = cast(StrippedPtr->getType()); if (StrippedPtr != PtrOp) { 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"}