Index: llvm/include/llvm/Analysis/TargetTransformInfoImpl.h =================================================================== --- llvm/include/llvm/Analysis/TargetTransformInfoImpl.h +++ llvm/include/llvm/Analysis/TargetTransformInfoImpl.h @@ -537,6 +537,7 @@ case Intrinsic::is_constant: case Intrinsic::lifetime_start: case Intrinsic::lifetime_end: + case Intrinsic::noalias_decl: case Intrinsic::objectsize: case Intrinsic::ptr_annotation: case Intrinsic::var_annotation: Index: llvm/lib/Analysis/AliasSetTracker.cpp =================================================================== --- llvm/lib/Analysis/AliasSetTracker.cpp +++ llvm/lib/Analysis/AliasSetTracker.cpp @@ -438,6 +438,7 @@ break; // FIXME: Add lifetime/invariant intrinsics (See: PR30807). case Intrinsic::assume: + case Intrinsic::noalias_decl: case Intrinsic::sideeffect: case Intrinsic::pseudoprobe: return; Index: llvm/lib/Analysis/BasicAliasAnalysis.cpp =================================================================== --- llvm/lib/Analysis/BasicAliasAnalysis.cpp +++ llvm/lib/Analysis/BasicAliasAnalysis.cpp @@ -952,6 +952,10 @@ if (isIntrinsicCall(Call, Intrinsic::assume)) return ModRefInfo::NoModRef; + // The same is true for the llvm.noalias.decl intrinsic. + if (isIntrinsicCall(Call, Intrinsic::noalias_decl)) + return ModRefInfo::NoModRef; + // Like assumes, guard intrinsics are also marked as arbitrarily writing so // that proper control dependencies are maintained but they never mods any // particular memory location. @@ -1005,6 +1009,11 @@ isIntrinsicCall(Call2, Intrinsic::assume)) return ModRefInfo::NoModRef; + // The same is true for the llvm.noalias.decl intrinsic. + if (isIntrinsicCall(Call1, Intrinsic::noalias_decl) || + isIntrinsicCall(Call2, Intrinsic::noalias_decl)) + return ModRefInfo::NoModRef; + // Like assumes, guard intrinsics are also marked as arbitrarily writing so // that proper control dependencies are maintained but they never mod any // particular memory location. Index: llvm/lib/Analysis/MemorySSA.cpp =================================================================== --- llvm/lib/Analysis/MemorySSA.cpp +++ llvm/lib/Analysis/MemorySSA.cpp @@ -285,6 +285,7 @@ case Intrinsic::invariant_start: case Intrinsic::invariant_end: case Intrinsic::assume: + case Intrinsic::noalias_decl: return {false, NoAlias}; case Intrinsic::dbg_addr: case Intrinsic::dbg_declare: @@ -1767,9 +1768,15 @@ // dependencies here. // FIXME: Replace this special casing with a more accurate modelling of // assume's control dependency. - if (IntrinsicInst *II = dyn_cast(I)) - if (II->getIntrinsicID() == Intrinsic::assume) + if (IntrinsicInst *II = dyn_cast(I)) { + switch (II->getIntrinsicID()) { + default: + break; + case Intrinsic::assume: + case Intrinsic::noalias_decl: return nullptr; + } + } // Using a nonstandard AA pipelines might leave us with unexpected modref // results for I, so add a check to not model instructions that may not read Index: llvm/lib/Analysis/ValueTracking.cpp =================================================================== --- llvm/lib/Analysis/ValueTracking.cpp +++ llvm/lib/Analysis/ValueTracking.cpp @@ -536,6 +536,7 @@ case Intrinsic::invariant_end: case Intrinsic::lifetime_start: case Intrinsic::lifetime_end: + case Intrinsic::noalias_decl: case Intrinsic::objectsize: case Intrinsic::ptr_annotation: case Intrinsic::var_annotation: Index: llvm/lib/Analysis/VectorUtils.cpp =================================================================== --- llvm/lib/Analysis/VectorUtils.cpp +++ llvm/lib/Analysis/VectorUtils.cpp @@ -125,7 +125,8 @@ if (isTriviallyVectorizable(ID) || ID == Intrinsic::lifetime_start || ID == Intrinsic::lifetime_end || ID == Intrinsic::assume || - ID == Intrinsic::sideeffect || ID == Intrinsic::pseudoprobe) + ID == Intrinsic::noalias_decl || ID == Intrinsic::sideeffect || + ID == Intrinsic::pseudoprobe) return ID; return Intrinsic::not_intrinsic; } Index: llvm/lib/CodeGen/Analysis.cpp =================================================================== --- llvm/lib/CodeGen/Analysis.cpp +++ llvm/lib/CodeGen/Analysis.cpp @@ -540,11 +540,12 @@ // Pseudo probe intrinsics do not block tail call optimization either. if (isa(BBI)) continue; - // A lifetime end or assume intrinsic should not stop tail call - // optimization. + // A lifetime end, assume or noalias.decl intrinsic should not stop tail + // call optimization. if (const IntrinsicInst *II = dyn_cast(BBI)) if (II->getIntrinsicID() == Intrinsic::lifetime_end || - II->getIntrinsicID() == Intrinsic::assume) + II->getIntrinsicID() == Intrinsic::assume || + II->getIntrinsicID() == Intrinsic::noalias_decl) continue; if (BBI->mayHaveSideEffects() || BBI->mayReadFromMemory() || !isSafeToSpeculativelyExecute(&*BBI)) Index: llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp +++ llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp @@ -1748,6 +1748,8 @@ } break; } + case Intrinsic::noalias_decl: + break; default: { // Handle target specific intrinsics Optional V = targetInstCombineIntrinsic(*II); Index: llvm/lib/Transforms/InstCombine/InstructionCombining.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstructionCombining.cpp +++ llvm/lib/Transforms/InstCombine/InstructionCombining.cpp @@ -2551,6 +2551,7 @@ case Intrinsic::lifetime_start: case Intrinsic::lifetime_end: case Intrinsic::objectsize: + case Intrinsic::noalias_decl: Users.emplace_back(I); continue; } Index: llvm/lib/Transforms/Scalar/EarlyCSE.cpp =================================================================== --- llvm/lib/Transforms/Scalar/EarlyCSE.cpp +++ llvm/lib/Transforms/Scalar/EarlyCSE.cpp @@ -1226,6 +1226,13 @@ continue; } + // Likewise, noalias intrinsics don't actually write. + if (match(&Inst, m_Intrinsic())) { + LLVM_DEBUG(dbgs() << "EarlyCSE skipping noalias intrinsic: " << Inst + << '\n'); + continue; + } + // Skip sideeffect intrinsics, for the same reason as assume intrinsics. if (match(&Inst, m_Intrinsic())) { LLVM_DEBUG(dbgs() << "EarlyCSE skipping sideeffect: " << Inst << '\n'); Index: llvm/test/Transforms/Coroutines/coro-retcon-resume-values.ll =================================================================== --- llvm/test/Transforms/Coroutines/coro-retcon-resume-values.ll +++ llvm/test/Transforms/Coroutines/coro-retcon-resume-values.ll @@ -76,15 +76,9 @@ ; FIXME: After introduction of llvm.noalias.decl, this is not fully optimzed ; with the new pass manager. -; NPM-NEXT: store i32 1, i32* [[SLOT]], align 4 ; NPM-NEXT: call i8* @llvm.noalias.decl.p0i8.p0p0i8.i64 -; NPM-NEXT: [[RELOAD0:%.+]] = load i32, i32* [[SLOT]], align 4 -; NPM-NEXT: [[SUM0:%.+]] = add i32 [[RELOAD0]], 2 -; NPM-NEXT: store i32 [[SUM0]], i32* [[SLOT]], align 4 ; NPM-NEXT: call i8* @llvm.noalias.decl.p0i8.p0p0i8.i64 -; NPM-NEXT: [[RELOAD1:%.+]] = load i32, i32* [[SLOT]], align 4 -; NPM-NEXT: [[SUM2:%.+]] = add i32 [[RELOAD1]], 4 -; NPM-NEXT: store i32 [[SUM2]], i32* [[SLOT]], align 4 +; NPM-NEXT: store i32 7, i32* [[SLOT]], align 4 ; NPM-NEXT: call i8* @llvm.noalias.decl.p0i8.p0p0i8.i64 ; NPM-NEXT: [[RELOAD2:%.+]] = load i32, i32* [[SLOT]], align 4 ; NPM-NEXT: call void @print(i32 [[RELOAD2]])