Index: llvm/include/llvm/Analysis/TargetTransformInfoImpl.h =================================================================== --- llvm/include/llvm/Analysis/TargetTransformInfoImpl.h +++ llvm/include/llvm/Analysis/TargetTransformInfoImpl.h @@ -557,6 +557,7 @@ case Intrinsic::is_constant: case Intrinsic::lifetime_start: case Intrinsic::lifetime_end: + case Intrinsic::experimental_noalias_scope_decl: case Intrinsic::objectsize: case Intrinsic::ptr_annotation: case Intrinsic::var_annotation: Index: llvm/include/llvm/Analysis/VectorUtils.h =================================================================== --- llvm/include/llvm/Analysis/VectorUtils.h +++ llvm/include/llvm/Analysis/VectorUtils.h @@ -304,7 +304,7 @@ /// the incoming type is void, we return void. If the EC represents a /// scalar, we return the scalar type. inline Type *ToVectorTy(Type *Scalar, ElementCount EC) { - if (Scalar->isVoidTy() || EC.isScalar()) + if (Scalar->isVoidTy() || Scalar->isMetadataTy() || EC.isScalar()) return Scalar; return VectorType::get(Scalar, EC); } 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::experimental_noalias_scope_decl: case Intrinsic::sideeffect: case Intrinsic::pseudoprobe: return; Index: llvm/lib/Analysis/BasicAliasAnalysis.cpp =================================================================== --- llvm/lib/Analysis/BasicAliasAnalysis.cpp +++ llvm/lib/Analysis/BasicAliasAnalysis.cpp @@ -957,6 +957,10 @@ if (isIntrinsicCall(Call, Intrinsic::assume)) return ModRefInfo::NoModRef; + // The same is true for the llvm.experimental.noalias.scope.decl intrinsic. + if (isIntrinsicCall(Call, Intrinsic::experimental_noalias_scope_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. @@ -1010,6 +1014,11 @@ isIntrinsicCall(Call2, Intrinsic::assume)) return ModRefInfo::NoModRef; + // The same is true for the llvm.experimental.noalias.scope.decl intrinsic. + if (isIntrinsicCall(Call1, Intrinsic::experimental_noalias_scope_decl) || + isIntrinsicCall(Call2, Intrinsic::experimental_noalias_scope_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::experimental_noalias_scope_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::experimental_noalias_scope_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::experimental_noalias_scope_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,6 +125,7 @@ if (isTriviallyVectorizable(ID) || ID == Intrinsic::lifetime_start || ID == Intrinsic::lifetime_end || ID == Intrinsic::assume || + ID == Intrinsic::experimental_noalias_scope_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 @@ -519,11 +519,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::experimental_noalias_scope_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 @@ -1747,6 +1747,8 @@ } break; } + case Intrinsic::experimental_noalias_scope_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 @@ -2552,6 +2552,7 @@ case Intrinsic::lifetime_start: case Intrinsic::lifetime_end: case Intrinsic::objectsize: + case Intrinsic::experimental_noalias_scope_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 @@ -1232,6 +1232,14 @@ 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/lib/Transforms/Vectorize/LoopVectorize.cpp =================================================================== --- llvm/lib/Transforms/Vectorize/LoopVectorize.cpp +++ llvm/lib/Transforms/Vectorize/LoopVectorize.cpp @@ -8142,7 +8142,8 @@ Intrinsic::ID ID = getVectorIntrinsicIDForCall(CI, TLI); if (ID && (ID == Intrinsic::assume || ID == Intrinsic::lifetime_end || ID == Intrinsic::lifetime_start || ID == Intrinsic::sideeffect || - ID == Intrinsic::pseudoprobe)) + ID == Intrinsic::pseudoprobe || + ID == Intrinsic::experimental_noalias_scope_decl)) return nullptr; auto willWiden = [&](ElementCount VF) -> bool { 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 @@ -74,17 +74,11 @@ ; OPM-NEXT: call void @llvm.experimental.noalias.scope.decl ; OPM-NEXT: call void @print(i32 7) -; FIXME: After introduction of llvm.noalias.decl, this is not fully optimzed +; FIXME: After introduction of llvm.experimental.noalias.scope.decl, this is not fully optimzed ; with the new pass manager. -; NPM-NEXT: store i32 1, i32* [[SLOT]], align 4 ; NPM-NEXT: call void @llvm.experimental.noalias.scope.decl -; 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 void @llvm.experimental.noalias.scope.decl -; 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 void @llvm.experimental.noalias.scope.decl ; NPM-NEXT: [[RELOAD2:%.+]] = load i32, i32* [[SLOT]], align 4 ; NPM-NEXT: call void @print(i32 [[RELOAD2]])