Index: clang/test/CodeGen/aarch64-ls64.c =================================================================== --- clang/test/CodeGen/aarch64-ls64.c +++ clang/test/CodeGen/aarch64-ls64.c @@ -21,6 +21,7 @@ // CHECK-NEXT: [[__ADDR_ADDR_I:%.*]] = alloca i8*, align 8 // CHECK-NEXT: [[REF_TMP:%.*]] = alloca [[STRUCT_DATA512_T:%.*]], align 8 // CHECK-NEXT: [[TMP0:%.*]] = load i8*, i8** @addr, align 8 +// CHECK-NEXT: call void @llvm.experimental.noalias.scope.decl(metadata !6) // CHECK-NEXT: store i8* [[TMP0]], i8** [[__ADDR_ADDR_I]], align 8, !noalias !6 // CHECK-NEXT: [[TMP1:%.*]] = load i8*, i8** [[__ADDR_ADDR_I]], align 8, !noalias !6 // CHECK-NEXT: [[VAL_I:%.*]] = getelementptr inbounds [[STRUCT_DATA512_T]], %struct.data512_t* [[REF_TMP]], i32 0, i32 0 Index: llvm/lib/Transforms/Utils/InlineFunction.cpp =================================================================== --- llvm/lib/Transforms/Utils/InlineFunction.cpp +++ llvm/lib/Transforms/Utils/InlineFunction.cpp @@ -79,6 +79,12 @@ cl::Hidden, cl::desc("Convert noalias attributes to metadata during inlining.")); +static cl::opt + UseNoAliasIntrinsic("use-noalias-intrinsic-during-inlining", cl::Hidden, + cl::ZeroOrMore, cl::init(true), + cl::desc("Use the llvm.experimental.noalias.scope.decl " + "intrinsic during inlining.")); + // Disabled by default, because the added alignment assumptions may increase // compile-time and block optimizations. This option is not suitable for use // with frontends that emit comprehensive parameter alignment annotations. @@ -821,91 +827,119 @@ } } -/// When inlining a function that contains noalias scope metadata, -/// this metadata needs to be cloned so that the inlined blocks -/// have different "unique scopes" at every call site. Were this not done, then -/// aliasing scopes from a function inlined into a caller multiple times could -/// not be differentiated (and this would lead to miscompiles because the -/// non-aliasing property communicated by the metadata could have -/// call-site-specific control dependencies). -static void CloneAliasScopeMetadata(CallBase &CB, ValueToValueMapTy &VMap) { - const Function *CalledFunc = CB.getCalledFunction(); +/// Utility for cloning !noalias and !alias.scope metadata. When a code region +/// using scoped alias metadata is inlined, the aliasing relationships may not +/// hold between the two version. It is necessary to create a deep clone of the +/// metadata, putting the two versions in separate scope domains. +class ScopedAliasMetadataDeepCloner { + using MetadataMap = DenseMap; SetVector MD; - - // Note: We could only clone the metadata if it is already used in the - // caller. I'm omitting that check here because it might confuse - // inter-procedural alias analysis passes. We can revisit this if it becomes - // an efficiency or overhead problem. - - for (const BasicBlock &I : *CalledFunc) - for (const Instruction &J : I) { - if (const MDNode *M = J.getMetadata(LLVMContext::MD_alias_scope)) + MetadataMap MDMap; + void addRecursiveMetadataUses(); + +public: + ScopedAliasMetadataDeepCloner(const Function *F); + + /// Create a new clone of the scoped alias metadata, which will be used by + /// subsequent remap() calls. + void clone(); + + /// Remap instructions in the given VMap from the original to the cloned + /// metadata. + void remap(ValueToValueMapTy &VMap); +}; + +ScopedAliasMetadataDeepCloner::ScopedAliasMetadataDeepCloner( + const Function *F) { + for (const BasicBlock &BB : *F) { + for (const Instruction &I : BB) { + if (const MDNode *M = I.getMetadata(LLVMContext::MD_alias_scope)) MD.insert(M); - if (const MDNode *M = J.getMetadata(LLVMContext::MD_noalias)) + if (const MDNode *M = I.getMetadata(LLVMContext::MD_noalias)) MD.insert(M); - } - if (MD.empty()) - return; + // We also need to clone the metadata in noalias intrinsics. + if (const auto *II = dyn_cast(&I)) + if (II->getIntrinsicID() == Intrinsic::experimental_noalias_scope_decl) + if (const auto *M = dyn_cast( + cast( + II->getOperand(Intrinsic::NoAliasScopeDeclScopeArg)) + ->getMetadata())) + MD.insert(M); + } + } + addRecursiveMetadataUses(); +} - // Walk the existing metadata, adding the complete (perhaps cyclic) chain to - // the set. +void ScopedAliasMetadataDeepCloner::addRecursiveMetadataUses() { SmallVector Queue(MD.begin(), MD.end()); while (!Queue.empty()) { const MDNode *M = cast(Queue.pop_back_val()); - for (unsigned i = 0, ie = M->getNumOperands(); i != ie; ++i) - if (const MDNode *M1 = dyn_cast(M->getOperand(i))) - if (MD.insert(M1)) - Queue.push_back(M1); + for (const Metadata *Op : M->operands()) + if (const MDNode *OpMD = dyn_cast(Op)) + if (MD.insert(OpMD)) + Queue.push_back(OpMD); } +} + +void ScopedAliasMetadataDeepCloner::clone() { + assert(MDMap.empty() && "clone() already called ?"); - // Now we have a complete set of all metadata in the chains used to specify - // the noalias scopes and the lists of those scopes. SmallVector DummyNodes; - DenseMap MDMap; for (const MDNode *I : MD) { - DummyNodes.push_back(MDTuple::getTemporary(CalledFunc->getContext(), None)); + DummyNodes.push_back(MDTuple::getTemporary(I->getContext(), None)); MDMap[I].reset(DummyNodes.back().get()); } // Create new metadata nodes to replace the dummy nodes, replacing old // metadata references with either a dummy node or an already-created new // node. + SmallVector NewOps; for (const MDNode *I : MD) { - SmallVector NewOps; - for (unsigned i = 0, ie = I->getNumOperands(); i != ie; ++i) { - const Metadata *V = I->getOperand(i); - if (const MDNode *M = dyn_cast(V)) + for (const Metadata *Op : I->operands()) { + if (const MDNode *M = dyn_cast(Op)) NewOps.push_back(MDMap[M]); else - NewOps.push_back(const_cast(V)); + NewOps.push_back(const_cast(Op)); } - MDNode *NewM = MDNode::get(CalledFunc->getContext(), NewOps); + MDNode *NewM = MDNode::get(I->getContext(), NewOps); MDTuple *TempM = cast(MDMap[I]); assert(TempM->isTemporary() && "Expected temporary node"); TempM->replaceAllUsesWith(NewM); + NewOps.clear(); } +} - // Now replace the metadata in the new inlined instructions with the - // repacements from the map. - for (ValueToValueMapTy::iterator VMI = VMap.begin(), VMIE = VMap.end(); - VMI != VMIE; ++VMI) { +void ScopedAliasMetadataDeepCloner::remap(ValueToValueMapTy &VMap) { + if (MDMap.empty()) + return; // Nothing to do. + + for (auto Entry : VMap) { // Check that key is an instruction, to skip the Argument mapping, which // points to an instruction in the original function, not the inlined one. - if (!VMI->second || !isa(VMI->first)) + if (!Entry->second || !isa(Entry->first)) continue; - Instruction *NI = dyn_cast(VMI->second); - if (!NI) + Instruction *I = dyn_cast(Entry->second); + if (!I) continue; - if (MDNode *M = NI->getMetadata(LLVMContext::MD_alias_scope)) - NI->setMetadata(LLVMContext::MD_alias_scope, MDMap[M]); + if (MDNode *M = I->getMetadata(LLVMContext::MD_alias_scope)) + I->setMetadata(LLVMContext::MD_alias_scope, MDMap[M]); - if (MDNode *M = NI->getMetadata(LLVMContext::MD_noalias)) - NI->setMetadata(LLVMContext::MD_noalias, MDMap[M]); + if (MDNode *M = I->getMetadata(LLVMContext::MD_noalias)) + I->setMetadata(LLVMContext::MD_noalias, MDMap[M]); + + if (auto *II = dyn_cast(I)) + if (II->getIntrinsicID() == Intrinsic::experimental_noalias_scope_decl) { + auto *MV = cast( + II->getOperand(Intrinsic::NoAliasScopeDeclScopeArg)); + auto *NewMV = MetadataAsValue::get( + II->getContext(), MDMap[cast(MV->getMetadata())]); + II->setOperand(Intrinsic::NoAliasScopeDeclScopeArg, NewMV); + } } } @@ -962,6 +996,17 @@ // property of the callee, but also all control dependencies in the caller. MDNode *NewScope = MDB.createAnonymousAliasScope(NewDomain, Name); NewScopes.insert(std::make_pair(A, NewScope)); + + if (UseNoAliasIntrinsic) { + // Introduce a llvm.experimental.noalias.scope.decl for the noalias + // argument. + MDNode *AScopeList = MDNode::get(CalledFunc->getContext(), NewScope); + auto *NoAliasDecl = + IRBuilder<>(&CB).CreateNoAliasScopeDeclaration(AScopeList); + // Ignore the result for now. The result will be used when the + // llvm.noalias intrinsic is introduced. + (void)NoAliasDecl; + } } // Iterate over all new instructions in the map; for all memory-access @@ -1759,6 +1804,14 @@ // Keep a list of pair (dst, src) to emit byval initializations. SmallVector, 4> ByValInit; + // When inlining a function that contains noalias scope metadata, + // this metadata needs to be cloned so that the inlined blocks + // have different "unique scopes" at every call site. + // Track the metadata that must be cloned. Do this before other changes to + // the function, so that we do not get in trouble when inlining caller == + // callee. + ScopedAliasMetadataDeepCloner SAMetadataCloner(CB.getCalledFunction()); + auto &DL = Caller->getParent()->getDataLayout(); // Calculate the vector of arguments to pass into the function cloner, which @@ -1876,8 +1929,9 @@ fixupLineNumbers(Caller, FirstNewBlock, &CB, CalledFunc->getSubprogram() != nullptr); - // Clone existing noalias metadata if necessary. - CloneAliasScopeMetadata(CB, VMap); + // Now clone the inlined noalias scope metadata. + SAMetadataCloner.clone(); + SAMetadataCloner.remap(VMap); // Add noalias metadata if necessary. AddAliasScopeMetadata(CB, VMap, DL, CalleeAAR); Index: llvm/test/Transforms/Coroutines/ArgAddr.ll =================================================================== --- llvm/test/Transforms/Coroutines/ArgAddr.ll +++ llvm/test/Transforms/Coroutines/ArgAddr.ll @@ -54,10 +54,12 @@ ; CHECK-NEXT: bitcast i8* %index.addr12.i to i1* ; CHECK-NEXT: store i1 false ; CHECK-NEXT: store i32 3 +; CHECK-NEXT: call void @llvm.experimental.noalias.scope.decl ; CHECK-NEXT: store i32 3 ; CHECK-NEXT: call void @print(i32 3) ; CHECK-NEXT: store i1 false ; CHECK-NEXT: store i32 2 +; CHECK-NEXT: call void @llvm.experimental.noalias.scope.decl ; CHECK-NEXT: store i32 2 ; CHECK-NEXT: call void @print(i32 2) ; CHECK: ret i32 0 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 @@ -1,5 +1,5 @@ ; RUN: opt < %s -enable-coroutines -O2 -S | FileCheck %s -; RUN: opt < %s -enable-coroutines -passes='default' -S | FileCheck %s +; RUN: opt < %s -enable-coroutines -passes='default' -aa-pipeline=default -S | FileCheck %s define i8* @f(i8* %buffer, i32 %n) { entry: @@ -67,7 +67,10 @@ ; CHECK-NEXT: entry: ; CHECK: [[BUFFER:%.*]] = alloca [8 x i8], align 4 ; CHECK: [[SLOT:%.*]] = bitcast [8 x i8]* [[BUFFER]] to i32* +; CHECK-NEXT: call void @llvm.experimental.noalias.scope.decl +; CHECK-NEXT: call void @llvm.experimental.noalias.scope.decl ; CHECK-NEXT: store i32 7, i32* [[SLOT]], align 4 +; CHECK-NEXT: call void @llvm.experimental.noalias.scope.decl ; CHECK-NEXT: call void @print(i32 7) ; CHECK-NEXT: ret i32 0 Index: llvm/test/Transforms/Coroutines/coro-retcon-value.ll =================================================================== --- llvm/test/Transforms/Coroutines/coro-retcon-value.ll +++ llvm/test/Transforms/Coroutines/coro-retcon-value.ll @@ -79,14 +79,17 @@ ; CHECK: [[SLOT:%.*]] = bitcast [8 x i8]* [[BUFFER]] to i32* ; CHECK-NEXT: store i32 4, i32* [[SLOT]], align 4 ; CHECK-NEXT: call void @print(i32 4) +; CHECK-NEXT: call void @llvm.experimental.noalias.scope.decl ; CHECK-NEXT: [[LOAD:%.*]] = load i32, i32* [[SLOT]], align 4 ; CHECK-NEXT: [[INC:%.*]] = add i32 [[LOAD]], 1 ; CHECK-NEXT: store i32 [[INC]], i32* [[SLOT]], align 4 ; CHECK-NEXT: call void @print(i32 [[INC]]) +; CHECK-NEXT: call void @llvm.experimental.noalias.scope.decl ; CHECK-NEXT: [[LOAD:%.*]] = load i32, i32* [[SLOT]], align 4 ; CHECK-NEXT: [[INC:%.*]] = add i32 [[LOAD]], 1 ; CHECK-NEXT: store i32 [[INC]], i32* [[SLOT]], align 4 ; CHECK-NEXT: call void @print(i32 [[INC]]) +; CHECK-NEXT: call void @llvm.experimental.noalias.scope.decl ; CHECK-NEXT: ret i32 0 declare token @llvm.coro.id.retcon(i32, i32, i8*, i8*, i8*, i8*) Index: llvm/test/Transforms/Coroutines/coro-retcon.ll =================================================================== --- llvm/test/Transforms/Coroutines/coro-retcon.ll +++ llvm/test/Transforms/Coroutines/coro-retcon.ll @@ -69,13 +69,16 @@ ; CHECK: [[SLOT:%.*]] = bitcast [8 x i8]* [[BUFFER]] to i32* ; CHECK-NEXT: store i32 4, i32* [[SLOT]], align 4 ; CHECK-NEXT: call void @print(i32 4) +; CHECK-NEXT: call void @llvm.experimental.noalias.scope.decl ; CHECK-NEXT: [[LOAD:%.*]] = load i32, i32* [[SLOT]], align 4 ; CHECK-NEXT: [[INC:%.*]] = add i32 [[LOAD]], 1 ; CHECK-NEXT: store i32 [[INC]], i32* [[SLOT]], align 4 ; CHECK-NEXT: call void @print(i32 [[INC]]) +; CHECK-NEXT: call void @llvm.experimental.noalias.scope.decl ; CHECK-NEXT: [[LOAD:%.*]] = load i32, i32* [[SLOT]], align 4 ; CHECK-NEXT: [[INC:%.*]] = add i32 [[LOAD]], 1 ; CHECK-NEXT: call void @print(i32 [[INC]]) +; CHECK-NEXT: call void @llvm.experimental.noalias.scope.decl ; CHECK-NEXT: ret i32 0 define hidden { i8*, i8* } @g(i8* %buffer, i16* %ptr) { Index: llvm/test/Transforms/Coroutines/ex2.ll =================================================================== --- llvm/test/Transforms/Coroutines/ex2.ll +++ llvm/test/Transforms/Coroutines/ex2.ll @@ -49,7 +49,9 @@ ret i32 0 ; CHECK-NOT: call i8* @CustomAlloc ; CHECK: call void @print(i32 4) +; CHECK-NEXT: call void @llvm.experimental.noalias.scope.decl ; CHECK-NEXT: call void @print(i32 5) +; CHECK-NEXT: call void @llvm.experimental.noalias.scope.decl ; CHECK-NEXT: call void @print(i32 6) ; CHECK-NEXT: ret i32 0 } Index: llvm/test/Transforms/Coroutines/ex3.ll =================================================================== --- llvm/test/Transforms/Coroutines/ex3.ll +++ llvm/test/Transforms/Coroutines/ex3.ll @@ -53,7 +53,9 @@ ret i32 0 ; CHECK-NOT: i8* @malloc ; CHECK: call void @print(i32 4) +; CHECK-NEXT: call void @llvm.experimental.noalias.scope.decl ; CHECK-NEXT: call void @print(i32 -5) +; CHECK-NEXT: call void @llvm.experimental.noalias.scope.decl ; CHECK-NEXT: call void @print(i32 5) ; CHECK: ret i32 0 } Index: llvm/test/Transforms/Coroutines/ex4.ll =================================================================== --- llvm/test/Transforms/Coroutines/ex4.ll +++ llvm/test/Transforms/Coroutines/ex4.ll @@ -50,7 +50,9 @@ call void @llvm.coro.destroy(i8* %hdl) ret i32 0 ; CHECK: call void @print(i32 4) +; CHECK-NEXT: call void @llvm.experimental.noalias.scope.decl ; CHECK-NEXT: call void @print(i32 5) +; CHECK-NEXT: call void @llvm.experimental.noalias.scope.decl ; CHECK-NEXT: call void @print(i32 6) ; CHECK: ret i32 0 } Index: llvm/test/Transforms/Inline/launder.invariant.group.ll =================================================================== --- llvm/test/Transforms/Inline/launder.invariant.group.ll +++ llvm/test/Transforms/Inline/launder.invariant.group.ll @@ -23,7 +23,7 @@ ; CHECK-LABEL: define i32 @foo(%struct.A* noalias define i32 @foo(%struct.A* noalias) { ; CHECK-NOT: call i32 @bar( - ; CHECK-NOT: noalias + ; CHECK-NOT: !noalias %2 = tail call i32 @bar(%struct.A* %0) ret i32 %2 } Index: llvm/test/Transforms/Inline/noalias-calls-always.ll =================================================================== --- llvm/test/Transforms/Inline/noalias-calls-always.ll +++ llvm/test/Transforms/Inline/noalias-calls-always.ll @@ -1,3 +1,4 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt -aa-pipeline=basic-aa -passes=always-inline -enable-noalias-to-md-conversion -S < %s | FileCheck %s target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128" target triple = "x86_64-unknown-linux-gnu" @@ -6,6 +7,16 @@ declare void @hey() #0 define void @hello(i8* noalias nocapture %a, i8* noalias nocapture readonly %c, i8* nocapture %b) #1 { +; CHECK-LABEL: @hello( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[L:%.*]] = alloca i8, i32 512, align 1 +; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 16 [[A:%.*]], i8* align 16 [[B:%.*]], i64 16, i1 false) +; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 16 [[B]], i8* align 16 [[C:%.*]], i64 16, i1 false) +; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 16 [[A]], i8* align 16 [[C]], i64 16, i1 false) +; CHECK-NEXT: call void @hey() +; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 16 [[L]], i8* align 16 [[C]], i64 16, i1 false) +; CHECK-NEXT: ret void +; entry: %l = alloca i8, i32 512, align 1 call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 16 %a, i8* align 16 %b, i64 16, i1 0) @@ -17,12 +28,36 @@ } define void @foo(i8* nocapture %a, i8* nocapture readonly %c, i8* nocapture %b) #2 { +; CHECK-LABEL: @foo( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[L_I:%.*]] = alloca i8, i32 512, align 1 +; CHECK-NEXT: call void @llvm.experimental.noalias.scope.decl([[META0:metadata !.*]]) +; CHECK-NEXT: call void @llvm.experimental.noalias.scope.decl([[META3:metadata !.*]]) +; CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 512, i8* [[L_I]]) +; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 16 [[A:%.*]], i8* align 16 [[B:%.*]], i64 16, i1 false) [[ATTR4:#.*]], !noalias !3 +; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 16 [[B]], i8* align 16 [[C:%.*]], i64 16, i1 false) [[ATTR4]], !noalias !0 +; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 16 [[A]], i8* align 16 [[C]], i64 16, i1 false) [[ATTR4]], !alias.scope !5 +; CHECK-NEXT: call void @hey() [[ATTR4]], !noalias !5 +; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 16 [[L_I]], i8* align 16 [[C]], i64 16, i1 false) [[ATTR4]], !noalias !0 +; CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 512, i8* [[L_I]]) +; CHECK-NEXT: ret void +; entry: tail call void @hello(i8* %a, i8* %c, i8* %b) ret void } define void @hello_cs(i8* nocapture %a, i8* nocapture readonly %c, i8* nocapture %b) #1 { +; CHECK-LABEL: @hello_cs( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[L:%.*]] = alloca i8, i32 512, align 1 +; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 16 [[A:%.*]], i8* align 16 [[B:%.*]], i64 16, i1 false) +; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 16 [[B]], i8* align 16 [[C:%.*]], i64 16, i1 false) +; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 16 [[A]], i8* align 16 [[C]], i64 16, i1 false) +; CHECK-NEXT: call void @hey() +; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 16 [[L]], i8* align 16 [[C]], i64 16, i1 false) +; CHECK-NEXT: ret void +; entry: %l = alloca i8, i32 512, align 1 call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 16 %a, i8* align 16 %b, i64 16, i1 0) @@ -34,46 +69,39 @@ } define void @foo_cs(i8* nocapture %a, i8* nocapture readonly %c, i8* nocapture %b) #2 { +; CHECK-LABEL: @foo_cs( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[L_I:%.*]] = alloca i8, i32 512, align 1 +; CHECK-NEXT: call void @llvm.experimental.noalias.scope.decl([[META6:metadata !.*]]) +; CHECK-NEXT: call void @llvm.experimental.noalias.scope.decl([[META9:metadata !.*]]) +; CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 512, i8* [[L_I]]) +; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 16 [[A:%.*]], i8* align 16 [[B:%.*]], i64 16, i1 false) [[ATTR4]], !noalias !9 +; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 16 [[B]], i8* align 16 [[C:%.*]], i64 16, i1 false) [[ATTR4]], !noalias !6 +; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 16 [[A]], i8* align 16 [[C]], i64 16, i1 false) [[ATTR4]], !alias.scope !11 +; CHECK-NEXT: call void @hey() [[ATTR4]], !noalias !11 +; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 16 [[L_I]], i8* align 16 [[C]], i64 16, i1 false) [[ATTR4]], !noalias !6 +; CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 512, i8* [[L_I]]) +; CHECK-NEXT: ret void +; entry: tail call void @hello_cs(i8* noalias %a, i8* noalias %c, i8* %b) ret void } -; CHECK: define void @foo(i8* nocapture %a, i8* nocapture readonly %c, i8* nocapture %b) -; CHECK: entry: -; CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 16 %a, i8* align 16 %b, i64 16, i1 false) #4, !noalias !0 -; CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 16 %b, i8* align 16 %c, i64 16, i1 false) #4, !noalias !3 -; CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 16 %a, i8* align 16 %c, i64 16, i1 false) #4, !alias.scope !5 -; CHECK: call void @hey() #4, !noalias !5 -; CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 16 %{{.*}}, i8* align 16 %c, i64 16, i1 false) #4, !noalias !3 -; CHECK: ret void -; CHECK: } - -; CHECK: define void @foo_cs(i8* nocapture %a, i8* nocapture readonly %c, i8* nocapture %b) -; CHECK: entry: -; CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 16 %a, i8* align 16 %b, i64 16, i1 false) #4, !noalias !6 -; CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 16 %b, i8* align 16 %c, i64 16, i1 false) #4, !noalias !9 -; CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 16 %a, i8* align 16 %c, i64 16, i1 false) #4, !alias.scope !11 -; CHECK: call void @hey() #4, !noalias !11 -; CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 16 %{{.*}}, i8* align 16 %c, i64 16, i1 false) #4, !noalias !9 -; CHECK: ret void -; CHECK: } - attributes #0 = { nounwind argmemonly willreturn } attributes #1 = { nounwind alwaysinline } attributes #2 = { nounwind uwtable } ; CHECK: !0 = !{!1} -; CHECK: !1 = distinct !{!1, !2, !"hello: %c"} +; CHECK: !1 = distinct !{!1, !2, !"hello: %a"} ; CHECK: !2 = distinct !{!2, !"hello"} ; CHECK: !3 = !{!4} -; CHECK: !4 = distinct !{!4, !2, !"hello: %a"} -; CHECK: !5 = !{!4, !1} +; CHECK: !4 = distinct !{!4, !2, !"hello: %c"} +; CHECK: !5 = !{!1, !4} ; CHECK: !6 = !{!7} -; CHECK: !7 = distinct !{!7, !8, !"hello_cs: %c"} +; CHECK: !7 = distinct !{!7, !8, !"hello_cs: %a"} ; CHECK: !8 = distinct !{!8, !"hello_cs"} ; CHECK: !9 = !{!10} -; CHECK: !10 = distinct !{!10, !8, !"hello_cs: %a"} -; CHECK: !11 = !{!10, !7} - +; CHECK: !10 = distinct !{!10, !8, !"hello_cs: %c"} +; CHECK: !11 = !{!7, !10} Index: llvm/test/Transforms/Inline/noalias-calls.ll =================================================================== --- llvm/test/Transforms/Inline/noalias-calls.ll +++ llvm/test/Transforms/Inline/noalias-calls.ll @@ -8,6 +8,17 @@ declare void @hey() #0 define void @hello(i8* noalias nocapture %a, i8* noalias nocapture readonly %c, i8* nocapture %b) #1 { +; CHECK-LABEL: define {{[^@]+}}@hello +; CHECK-SAME: (i8* noalias nocapture [[A:%.*]], i8* noalias nocapture readonly [[C:%.*]], i8* nocapture [[B:%.*]]) [[ATTR1:#.*]] { +; CHECK-NEXT: entry: +; CHECK-NEXT: [[L:%.*]] = alloca i8, i32 512, align 1 +; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 16 [[A]], i8* align 16 [[B]], i64 16, i1 false) +; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 16 [[B]], i8* align 16 [[C]], i64 16, i1 false) +; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 16 [[A]], i8* align 16 [[C]], i64 16, i1 false) +; CHECK-NEXT: call void @hey() +; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 16 [[L]], i8* align 16 [[C]], i64 16, i1 false) +; CHECK-NEXT: ret void +; entry: %l = alloca i8, i32 512, align 1 call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 16 %a, i8* align 16 %b, i64 16, i1 0) @@ -19,12 +30,38 @@ } define void @foo(i8* nocapture %a, i8* nocapture readonly %c, i8* nocapture %b) #2 { +; CHECK-LABEL: define {{[^@]+}}@foo +; CHECK-SAME: (i8* nocapture [[A:%.*]], i8* nocapture readonly [[C:%.*]], i8* nocapture [[B:%.*]]) [[ATTR2:#.*]] { +; CHECK-NEXT: entry: +; CHECK-NEXT: [[L_I:%.*]] = alloca i8, i32 512, align 1 +; CHECK-NEXT: call void @llvm.experimental.noalias.scope.decl([[META0:metadata !.*]]) +; CHECK-NEXT: call void @llvm.experimental.noalias.scope.decl([[META3:metadata !.*]]) +; CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 512, i8* [[L_I]]) +; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 16 [[A]], i8* align 16 [[B]], i64 16, i1 false) [[ATTR2]], !noalias !3 +; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 16 [[B]], i8* align 16 [[C]], i64 16, i1 false) [[ATTR2]], !noalias !0 +; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 16 [[A]], i8* align 16 [[C]], i64 16, i1 false) [[ATTR2]], !alias.scope !5 +; CHECK-NEXT: call void @hey() [[ATTR2]], !noalias !5 +; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 16 [[L_I]], i8* align 16 [[C]], i64 16, i1 false) [[ATTR2]], !noalias !0 +; CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 512, i8* [[L_I]]) +; CHECK-NEXT: ret void +; entry: tail call void @hello(i8* %a, i8* %c, i8* %b) ret void } define void @hello_cs(i8* nocapture %a, i8* nocapture readonly %c, i8* nocapture %b) #1 { +; CHECK-LABEL: define {{[^@]+}}@hello_cs +; CHECK-SAME: (i8* nocapture [[A:%.*]], i8* nocapture readonly [[C:%.*]], i8* nocapture [[B:%.*]]) [[ATTR1]] { +; CHECK-NEXT: entry: +; CHECK-NEXT: [[L:%.*]] = alloca i8, i32 512, align 1 +; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 16 [[A]], i8* align 16 [[B]], i64 16, i1 false) +; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 16 [[B]], i8* align 16 [[C]], i64 16, i1 false) +; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 16 [[A]], i8* align 16 [[C]], i64 16, i1 false) +; CHECK-NEXT: call void @hey() +; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 16 [[L]], i8* align 16 [[C]], i64 16, i1 false) +; CHECK-NEXT: ret void +; entry: %l = alloca i8, i32 512, align 1 call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 16 %a, i8* align 16 %b, i64 16, i1 0) @@ -36,46 +73,41 @@ } define void @foo_cs(i8* nocapture %a, i8* nocapture readonly %c, i8* nocapture %b) #2 { +; CHECK-LABEL: define {{[^@]+}}@foo_cs +; CHECK-SAME: (i8* nocapture [[A:%.*]], i8* nocapture readonly [[C:%.*]], i8* nocapture [[B:%.*]]) [[ATTR2]] { +; CHECK-NEXT: entry: +; CHECK-NEXT: [[L_I:%.*]] = alloca i8, i32 512, align 1 +; CHECK-NEXT: call void @llvm.experimental.noalias.scope.decl([[META6:metadata !.*]]) +; CHECK-NEXT: call void @llvm.experimental.noalias.scope.decl([[META9:metadata !.*]]) +; CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 512, i8* [[L_I]]) +; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 16 [[A]], i8* align 16 [[B]], i64 16, i1 false) [[ATTR2]], !noalias !9 +; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 16 [[B]], i8* align 16 [[C]], i64 16, i1 false) [[ATTR2]], !noalias !6 +; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 16 [[A]], i8* align 16 [[C]], i64 16, i1 false) [[ATTR2]], !alias.scope !11 +; CHECK-NEXT: call void @hey() [[ATTR2]], !noalias !11 +; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 16 [[L_I]], i8* align 16 [[C]], i64 16, i1 false) [[ATTR2]], !noalias !6 +; CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 512, i8* [[L_I]]) +; CHECK-NEXT: ret void +; entry: tail call void @hello_cs(i8* noalias %a, i8* noalias %c, i8* %b) ret void } -; CHECK: define void @foo(i8* nocapture %a, i8* nocapture readonly %c, i8* nocapture %b) #2 { -; CHECK: entry: -; CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 16 %a, i8* align 16 %b, i64 16, i1 false) #2, !noalias !0 -; CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 16 %b, i8* align 16 %c, i64 16, i1 false) #2, !noalias !3 -; CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 16 %a, i8* align 16 %c, i64 16, i1 false) #2, !alias.scope !5 -; CHECK: call void @hey() #2, !noalias !5 -; CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 16 %{{.*}}, i8* align 16 %c, i64 16, i1 false) #2, !noalias !3 -; CHECK: ret void -; CHECK: } - -; CHECK: define void @foo_cs(i8* nocapture %a, i8* nocapture readonly %c, i8* nocapture %b) #2 { -; CHECK: entry: -; CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 16 %a, i8* align 16 %b, i64 16, i1 false) #2, !noalias !6 -; CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 16 %b, i8* align 16 %c, i64 16, i1 false) #2, !noalias !9 -; CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 16 %a, i8* align 16 %c, i64 16, i1 false) #2, !alias.scope !11 -; CHECK: call void @hey() #2, !noalias !11 -; CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 16 %{{.*}}, i8* align 16 %c, i64 16, i1 false) #2, !noalias !9 -; CHECK: ret void -; CHECK: } - attributes #0 = { argmemonly nofree nosync nounwind willreturn } attributes #1 = { argmemonly nounwind willreturn } attributes #2 = { nounwind } attributes #3 = { nounwind uwtable } ; CHECK: !0 = !{!1} -; CHECK: !1 = distinct !{!1, !2, !"hello: %c"} +; CHECK: !1 = distinct !{!1, !2, !"hello: %a"} ; CHECK: !2 = distinct !{!2, !"hello"} ; CHECK: !3 = !{!4} -; CHECK: !4 = distinct !{!4, !2, !"hello: %a"} -; CHECK: !5 = !{!4, !1} +; CHECK: !4 = distinct !{!4, !2, !"hello: %c"} +; CHECK: !5 = !{!1, !4} ; CHECK: !6 = !{!7} -; CHECK: !7 = distinct !{!7, !8, !"hello_cs: %c"} +; CHECK: !7 = distinct !{!7, !8, !"hello_cs: %a"} ; CHECK: !8 = distinct !{!8, !"hello_cs"} ; CHECK: !9 = !{!10} -; CHECK: !10 = distinct !{!10, !8, !"hello_cs: %a"} -; CHECK: !11 = !{!10, !7} +; CHECK: !10 = distinct !{!10, !8, !"hello_cs: %c"} +; CHECK: !11 = !{!7, !10} Index: llvm/test/Transforms/Inline/noalias-calls2.ll =================================================================== --- /dev/null +++ llvm/test/Transforms/Inline/noalias-calls2.ll @@ -0,0 +1,166 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature +; RUN: opt -basic-aa -inline -enable-noalias-to-md-conversion -S < %s | FileCheck %s +; RUN: opt -aa-pipeline=basic-aa -passes=inline -enable-noalias-to-md-conversion -S < %s | FileCheck %s + +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +declare void @llvm.experimental.noalias.scope.decl(metadata) #0 + +define void @caller_equals_callee(i32* noalias %p0, i32* noalias %p1, i32 %cnt) { +; CHECK-LABEL: define {{[^@]+}}@caller_equals_callee +; CHECK-SAME: (i32* noalias [[P0:%.*]], i32* noalias [[P1:%.*]], i32 [[CNT:%.*]]) { +; CHECK-NEXT: entry: +; CHECK-NEXT: [[ADD_PTR:%.*]] = getelementptr inbounds i32, i32* [[P0]], i64 2 +; CHECK-NEXT: [[ADD_PTR1:%.*]] = getelementptr inbounds i32, i32* [[P1]], i64 2 +; CHECK-NEXT: tail call void @llvm.experimental.noalias.scope.decl(metadata !0) +; CHECK-NEXT: tail call void @llvm.experimental.noalias.scope.decl(metadata !3) +; CHECK-NEXT: store i32 10, i32* [[ADD_PTR]], align 4, !alias.scope !0, !noalias !3 +; CHECK-NEXT: store i32 20, i32* [[ADD_PTR1]], align 4, !alias.scope !3, !noalias !0 +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[CNT]], 0 +; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] +; CHECK: if.then: +; CHECK-NEXT: store i32 11, i32* [[P0]], align 4 +; CHECK-NEXT: br label [[IF_END:%.*]] +; CHECK: if.else: +; CHECK-NEXT: [[ADD_PTR2:%.*]] = getelementptr inbounds i32, i32* [[P1]], i64 1 +; CHECK-NEXT: [[ADD_PTR3:%.*]] = getelementptr inbounds i32, i32* [[P0]], i64 1 +; CHECK-NEXT: call void @llvm.experimental.noalias.scope.decl(metadata !5) +; CHECK-NEXT: call void @llvm.experimental.noalias.scope.decl(metadata !8) +; CHECK-NEXT: [[ADD_PTR_I:%.*]] = getelementptr inbounds i32, i32* [[ADD_PTR2]], i64 2 +; CHECK-NEXT: [[ADD_PTR1_I:%.*]] = getelementptr inbounds i32, i32* [[ADD_PTR3]], i64 2 +; CHECK-NEXT: tail call void @llvm.experimental.noalias.scope.decl(metadata !10), !noalias !13 +; CHECK-NEXT: tail call void @llvm.experimental.noalias.scope.decl(metadata !14), !noalias !13 +; CHECK-NEXT: store i32 10, i32* [[ADD_PTR_I]], align 4, !alias.scope !16, !noalias !17 +; CHECK-NEXT: store i32 20, i32* [[ADD_PTR1_I]], align 4, !alias.scope !17, !noalias !16 +; CHECK-NEXT: store i32 11, i32* [[ADD_PTR2]], align 4, !alias.scope !5, !noalias !8 +; CHECK-NEXT: store i32 12, i32* [[P1]], align 4 +; CHECK-NEXT: br label [[IF_END]] +; CHECK: if.end: +; CHECK-NEXT: ret void +; +entry: + %add.ptr = getelementptr inbounds i32, i32* %p0, i64 2 + %add.ptr1 = getelementptr inbounds i32, i32* %p1, i64 2 + tail call void @llvm.experimental.noalias.scope.decl(metadata !0) + tail call void @llvm.experimental.noalias.scope.decl(metadata !3) + store i32 10, i32* %add.ptr, align 4, !alias.scope !0, !noalias !3 + store i32 20, i32* %add.ptr1, align 4, !alias.scope !3, !noalias !0 + %cmp = icmp eq i32 %cnt, 0 + br i1 %cmp, label %if.then, label %if.else + +if.then: ; preds = %entry + store i32 11, i32* %p0, align 4 + br label %if.end + +if.else: ; preds = %entry + %add.ptr2 = getelementptr inbounds i32, i32* %p1, i64 1 + %add.ptr3 = getelementptr inbounds i32, i32* %p0, i64 1 + tail call void @caller_equals_callee(i32* nonnull %add.ptr2, i32* nonnull %add.ptr3, i32 0) + store i32 12, i32* %p1, align 4 + br label %if.end + +if.end: ; preds = %if.else, %if.then + ret void +} + +define void @test01(i32* noalias %p0, i32* noalias %p1, i32 %cnt) { +; CHECK-LABEL: define {{[^@]+}}@test01 +; CHECK-SAME: (i32* noalias [[P0:%.*]], i32* noalias [[P1:%.*]], i32 [[CNT:%.*]]) { +; CHECK-NEXT: entry: +; CHECK-NEXT: store i32 13, i32* [[P0]], align 4 +; CHECK-NEXT: [[ADD_PTR:%.*]] = getelementptr inbounds i32, i32* [[P0]], i64 1 +; CHECK-NEXT: [[ADD_PTR1:%.*]] = getelementptr inbounds i32, i32* [[P1]], i64 1 +; CHECK-NEXT: call void @llvm.experimental.noalias.scope.decl(metadata !18) +; CHECK-NEXT: call void @llvm.experimental.noalias.scope.decl(metadata !21) +; CHECK-NEXT: [[ADD_PTR_I:%.*]] = getelementptr inbounds i32, i32* [[ADD_PTR]], i64 2 +; CHECK-NEXT: [[ADD_PTR1_I:%.*]] = getelementptr inbounds i32, i32* [[ADD_PTR1]], i64 2 +; CHECK-NEXT: call void @llvm.experimental.noalias.scope.decl(metadata !23), !noalias !26 +; CHECK-NEXT: call void @llvm.experimental.noalias.scope.decl(metadata !27), !noalias !26 +; CHECK-NEXT: store i32 10, i32* [[ADD_PTR_I]], align 4, !alias.scope !29, !noalias !30 +; CHECK-NEXT: store i32 20, i32* [[ADD_PTR1_I]], align 4, !alias.scope !30, !noalias !29 +; CHECK-NEXT: [[CMP_I:%.*]] = icmp eq i32 [[CNT]], 0 +; CHECK-NEXT: br i1 [[CMP_I]], label [[IF_THEN_I:%.*]], label [[IF_ELSE_I:%.*]] +; CHECK: if.then.i: +; CHECK-NEXT: store i32 11, i32* [[ADD_PTR]], align 4, !alias.scope !18, !noalias !21 +; CHECK-NEXT: br label [[CALLER_EQUALS_CALLEE_EXIT:%.*]] +; CHECK: if.else.i: +; CHECK-NEXT: [[ADD_PTR2_I:%.*]] = getelementptr inbounds i32, i32* [[ADD_PTR1]], i64 1 +; CHECK-NEXT: [[ADD_PTR3_I:%.*]] = getelementptr inbounds i32, i32* [[ADD_PTR]], i64 1 +; CHECK-NEXT: call void @llvm.experimental.noalias.scope.decl(metadata !31), !noalias !26 +; CHECK-NEXT: call void @llvm.experimental.noalias.scope.decl(metadata !34), !noalias !26 +; CHECK-NEXT: [[ADD_PTR_I_I:%.*]] = getelementptr inbounds i32, i32* [[ADD_PTR2_I]], i64 2 +; CHECK-NEXT: [[ADD_PTR1_I_I:%.*]] = getelementptr inbounds i32, i32* [[ADD_PTR3_I]], i64 2 +; CHECK-NEXT: call void @llvm.experimental.noalias.scope.decl(metadata !36), !noalias !39 +; CHECK-NEXT: call void @llvm.experimental.noalias.scope.decl(metadata !40), !noalias !39 +; CHECK-NEXT: store i32 10, i32* [[ADD_PTR_I_I]], align 4, !alias.scope !42, !noalias !43 +; CHECK-NEXT: store i32 20, i32* [[ADD_PTR1_I_I]], align 4, !alias.scope !43, !noalias !42 +; CHECK-NEXT: store i32 11, i32* [[ADD_PTR2_I]], align 4, !alias.scope !44, !noalias !45 +; CHECK-NEXT: store i32 12, i32* [[ADD_PTR1]], align 4, !alias.scope !21, !noalias !18 +; CHECK-NEXT: br label [[CALLER_EQUALS_CALLEE_EXIT]] +; CHECK: caller_equals_callee.exit: +; CHECK-NEXT: ret void +; +entry: + store i32 13, i32* %p0, align 4 + %add.ptr = getelementptr inbounds i32, i32* %p0, i64 1 + %add.ptr1 = getelementptr inbounds i32, i32* %p1, i64 1 + call void @caller_equals_callee(i32* nonnull %add.ptr, i32* nonnull %add.ptr1, i32 %cnt) + ret void +} + +attributes #0 = { inaccessiblememonly nofree nosync nounwind willreturn } + +!0 = !{!1} +!1 = distinct !{!1, !2, !"do_store: %p0"} +!2 = distinct !{!2, !"do_store"} +!3 = !{!4} +!4 = distinct !{!4, !2, !"do_store: %p1"} + +; CHECK: !0 = !{!1} +; CHECK: !1 = distinct !{!1, !2, !"do_store: %p0"} +; CHECK: !2 = distinct !{!2, !"do_store"} +; CHECK: !3 = !{!4} +; CHECK: !4 = distinct !{!4, !2, !"do_store: %p1"} +; CHECK: !5 = !{!6} +; CHECK: !6 = distinct !{!6, !7, !"caller_equals_callee: %p0"} +; CHECK: !7 = distinct !{!7, !"caller_equals_callee"} +; CHECK: !8 = !{!9} +; CHECK: !9 = distinct !{!9, !7, !"caller_equals_callee: %p1"} +; CHECK: !10 = !{!11} +; CHECK: !11 = distinct !{!11, !12, !"do_store: %p0"} +; CHECK: !12 = distinct !{!12, !"do_store"} +; CHECK: !13 = !{!6, !9} +; CHECK: !14 = !{!15} +; CHECK: !15 = distinct !{!15, !12, !"do_store: %p1"} +; CHECK: !16 = !{!11, !6} +; CHECK: !17 = !{!15, !9} + +; CHECK: !18 = !{!19} +; CHECK: !19 = distinct !{!19, !20, !"caller_equals_callee: %p0"} +; CHECK: !20 = distinct !{!20, !"caller_equals_callee"} +; CHECK: !21 = !{!22} +; CHECK: !22 = distinct !{!22, !20, !"caller_equals_callee: %p1"} +; CHECK: !23 = !{!24} +; CHECK: !24 = distinct !{!24, !25, !"do_store: %p0"} +; CHECK: !25 = distinct !{!25, !"do_store"} +; CHECK: !26 = !{!19, !22} +; CHECK: !27 = !{!28} +; CHECK: !28 = distinct !{!28, !25, !"do_store: %p1"} +; CHECK: !29 = !{!24, !19} +; CHECK: !30 = !{!28, !22} +; CHECK: !31 = !{!32} +; CHECK: !32 = distinct !{!32, !33, !"caller_equals_callee: %p0"} +; CHECK: !33 = distinct !{!33, !"caller_equals_callee"} +; CHECK: !34 = !{!35} +; CHECK: !35 = distinct !{!35, !33, !"caller_equals_callee: %p1"} +; CHECK: !36 = !{!37} +; CHECK: !37 = distinct !{!37, !38, !"do_store: %p0"} +; CHECK: !38 = distinct !{!38, !"do_store"} +; CHECK: !39 = !{!32, !35, !19, !22} +; CHECK: !40 = !{!41} +; CHECK: !41 = distinct !{!41, !38, !"do_store: %p1"} +; CHECK: !42 = !{!37, !32, !22} +; CHECK: !43 = !{!41, !35, !19} +; CHECK: !44 = !{!32, !22} +; CHECK: !45 = !{!35, !19} Index: llvm/test/Transforms/Inline/noalias-cs.ll =================================================================== --- llvm/test/Transforms/Inline/noalias-cs.ll +++ llvm/test/Transforms/Inline/noalias-cs.ll @@ -5,7 +5,23 @@ ; This callee uses scoped alias metadata internally itself. define void @callee_with_metadata(float* nocapture %a, float* nocapture %b, float* nocapture readonly %c) #0 { +; CHECK-LABEL: @callee_with_metadata( +; CHECK-NEXT: entry: +; CHECK-NEXT: call void @llvm.experimental.noalias.scope.decl(metadata !0) +; CHECK-NEXT: call void @llvm.experimental.noalias.scope.decl(metadata !3) +; CHECK-NEXT: [[TMP0:%.*]] = load float, float* [[C:%.*]], align 4, !noalias !5 +; CHECK-NEXT: [[ARRAYIDX_I:%.*]] = getelementptr inbounds float, float* [[A:%.*]], i64 5 +; CHECK-NEXT: store float [[TMP0]], float* [[ARRAYIDX_I]], align 4, !alias.scope !0, !noalias !3 +; CHECK-NEXT: [[ARRAYIDX1_I:%.*]] = getelementptr inbounds float, float* [[B:%.*]], i64 8 +; CHECK-NEXT: store float [[TMP0]], float* [[ARRAYIDX1_I]], align 4, !alias.scope !3, !noalias !0 +; CHECK-NEXT: [[TMP1:%.*]] = load float, float* [[C]], align 4 +; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds float, float* [[A]], i64 7 +; CHECK-NEXT: store float [[TMP1]], float* [[ARRAYIDX]], align 4 +; CHECK-NEXT: ret void +; entry: + call void @llvm.experimental.noalias.scope.decl(metadata !7) + call void @llvm.experimental.noalias.scope.decl(metadata !8) %0 = load float, float* %c, align 4, !noalias !3 %arrayidx.i = getelementptr inbounds float, float* %a, i64 5 store float %0, float* %arrayidx.i, align 4, !alias.scope !7, !noalias !8 @@ -17,8 +33,22 @@ ret void } +declare void @llvm.experimental.noalias.scope.decl(metadata); + ; This callee does not make use of scoped alias metadata itself. define void @callee_without_metadata(float* nocapture %a, float* nocapture %b, float* nocapture readonly %c) #0 { +; CHECK-LABEL: @callee_without_metadata( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[TMP0:%.*]] = load float, float* [[C:%.*]], align 4 +; CHECK-NEXT: [[ARRAYIDX_I:%.*]] = getelementptr inbounds float, float* [[A:%.*]], i64 5 +; CHECK-NEXT: store float [[TMP0]], float* [[ARRAYIDX_I]], align 4 +; CHECK-NEXT: [[ARRAYIDX1_I:%.*]] = getelementptr inbounds float, float* [[B:%.*]], i64 8 +; CHECK-NEXT: store float [[TMP0]], float* [[ARRAYIDX1_I]], align 4 +; CHECK-NEXT: [[TMP1:%.*]] = load float, float* [[C]], align 4 +; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds float, float* [[A]], i64 7 +; CHECK-NEXT: store float [[TMP1]], float* [[ARRAYIDX]], align 4 +; CHECK-NEXT: ret void +; entry: %0 = load float, float* %c, align 4 %arrayidx.i = getelementptr inbounds float, float* %a, i64 5 @@ -35,19 +65,23 @@ ; CHECK-LABEL: @caller( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[C:%.*]] = load float*, float** [[C_PTR:%.*]], align 8, !alias.scope !6 -; CHECK-NEXT: [[TMP0:%.*]] = load float, float* [[C]], align 4, !noalias !9 +; CHECK-NEXT: call void @llvm.experimental.noalias.scope.decl(metadata !9) [[ATTR2:#.*]], !noalias !6 +; CHECK-NEXT: call void @llvm.experimental.noalias.scope.decl(metadata !12) [[ATTR2]], !noalias !6 +; CHECK-NEXT: [[TMP0:%.*]] = load float, float* [[C]], align 4, !noalias !14 ; CHECK-NEXT: [[ARRAYIDX_I_I:%.*]] = getelementptr inbounds float, float* [[A:%.*]], i64 5 -; CHECK-NEXT: store float [[TMP0]], float* [[ARRAYIDX_I_I]], align 4, !alias.scope !13, !noalias !14 +; CHECK-NEXT: store float [[TMP0]], float* [[ARRAYIDX_I_I]], align 4, !alias.scope !9, !noalias !15 ; CHECK-NEXT: [[ARRAYIDX1_I_I:%.*]] = getelementptr inbounds float, float* [[B:%.*]], i64 8 -; CHECK-NEXT: store float [[TMP0]], float* [[ARRAYIDX1_I_I]], align 4, !alias.scope !15, !noalias !16 +; CHECK-NEXT: store float [[TMP0]], float* [[ARRAYIDX1_I_I]], align 4, !alias.scope !12, !noalias !16 ; CHECK-NEXT: [[TMP1:%.*]] = load float, float* [[C]], align 4, !noalias !6 ; CHECK-NEXT: [[ARRAYIDX_I:%.*]] = getelementptr inbounds float, float* [[A]], i64 7 ; CHECK-NEXT: store float [[TMP1]], float* [[ARRAYIDX_I]], align 4, !noalias !6 -; CHECK-NEXT: [[TMP2:%.*]] = load float, float* [[A]], align 4, !alias.scope !6, !noalias !17 +; CHECK-NEXT: call void @llvm.experimental.noalias.scope.decl(metadata !17) [[ATTR2]], !alias.scope !6 +; CHECK-NEXT: call void @llvm.experimental.noalias.scope.decl(metadata !20) [[ATTR2]], !alias.scope !6 +; CHECK-NEXT: [[TMP2:%.*]] = load float, float* [[A]], align 4, !alias.scope !6, !noalias !22 ; CHECK-NEXT: [[ARRAYIDX_I_I7:%.*]] = getelementptr inbounds float, float* [[B]], i64 5 -; CHECK-NEXT: store float [[TMP2]], float* [[ARRAYIDX_I_I7]], align 4, !alias.scope !21, !noalias !22 +; CHECK-NEXT: store float [[TMP2]], float* [[ARRAYIDX_I_I7]], align 4, !alias.scope !23, !noalias !20 ; CHECK-NEXT: [[ARRAYIDX1_I_I8:%.*]] = getelementptr inbounds float, float* [[B]], i64 8 -; CHECK-NEXT: store float [[TMP2]], float* [[ARRAYIDX1_I_I8]], align 4, !alias.scope !23, !noalias !24 +; CHECK-NEXT: store float [[TMP2]], float* [[ARRAYIDX1_I_I8]], align 4, !alias.scope !24, !noalias !17 ; CHECK-NEXT: [[TMP3:%.*]] = load float, float* [[A]], align 4, !alias.scope !6 ; CHECK-NEXT: [[ARRAYIDX_I9:%.*]] = getelementptr inbounds float, float* [[B]], i64 7 ; CHECK-NEXT: store float [[TMP3]], float* [[ARRAYIDX_I9]], align 4, !alias.scope !6 @@ -90,28 +124,28 @@ !7 = !{!4} !8 = !{!6} -; CHECK: !0 = !{!1, !3} +; CHECK: !0 = !{!1} ; CHECK: !1 = distinct !{!1, !2, !"hello2: %a"} ; CHECK: !2 = distinct !{!2, !"hello2"} -; CHECK: !3 = distinct !{!3, !2, !"hello2: %b"} -; CHECK: !4 = !{!1} -; CHECK: !5 = !{!3} +; CHECK: !3 = !{!4} +; CHECK: !4 = distinct !{!4, !2, !"hello2: %b"} +; CHECK: !5 = !{!1, !4} ; CHECK: !6 = !{!7} ; CHECK: !7 = distinct !{!7, !8, !"hello: %a"} ; CHECK: !8 = distinct !{!8, !"hello"} -; CHECK: !9 = !{!10, !12, !7} +; CHECK: !9 = !{!10} ; CHECK: !10 = distinct !{!10, !11, !"hello2: %a"} ; CHECK: !11 = distinct !{!11, !"hello2"} -; CHECK: !12 = distinct !{!12, !11, !"hello2: %b"} -; CHECK: !13 = !{!10} -; CHECK: !14 = !{!12, !7} -; CHECK: !15 = !{!12} +; CHECK: !12 = !{!13} +; CHECK: !13 = distinct !{!13, !11, !"hello2: %b"} +; CHECK: !14 = !{!10, !13, !7} +; CHECK: !15 = !{!13, !7} ; CHECK: !16 = !{!10, !7} -; CHECK: !17 = !{!18, !20} +; CHECK: !17 = !{!18} ; CHECK: !18 = distinct !{!18, !19, !"hello2: %a"} ; CHECK: !19 = distinct !{!19, !"hello2"} -; CHECK: !20 = distinct !{!20, !19, !"hello2: %b"} -; CHECK: !21 = !{!18, !7} -; CHECK: !22 = !{!20} -; CHECK: !23 = !{!20, !7} -; CHECK: !24 = !{!18} +; CHECK: !20 = !{!21} +; CHECK: !21 = distinct !{!21, !19, !"hello2: %b"} +; CHECK: !22 = !{!18, !21} +; CHECK: !23 = !{!18, !7} +; CHECK: !24 = !{!21, !7} Index: llvm/test/Transforms/Inline/noalias.ll =================================================================== --- llvm/test/Transforms/Inline/noalias.ll +++ llvm/test/Transforms/Inline/noalias.ll @@ -19,14 +19,15 @@ ret void } -; CHECK: define void @foo(float* nocapture %a, float* nocapture readonly %c) #0 { +; CHECK-LABEL: define void @foo(float* nocapture %a, float* nocapture readonly %c) #0 { ; CHECK: entry: -; CHECK: %0 = load float, float* %c, align 4, !noalias !0 +; CHECK: call void @llvm.experimental.noalias.scope.decl +; CHECK: [[TMP0:%.+]] = load float, float* %c, align 4, !noalias !0 ; CHECK: %arrayidx.i = getelementptr inbounds float, float* %a, i64 5 -; CHECK: store float %0, float* %arrayidx.i, align 4, !alias.scope !0 -; CHECK: %1 = load float, float* %c, align 4 +; CHECK: store float [[TMP0]], float* %arrayidx.i, align 4, !alias.scope !0 +; CHECK: [[TMP1:%.+]] = load float, float* %c, align 4 ; CHECK: %arrayidx = getelementptr inbounds float, float* %a, i64 7 -; CHECK: store float %1, float* %arrayidx, align 4 +; CHECK: store float [[TMP1]], float* %arrayidx, align 4 ; CHECK: ret void ; CHECK: } @@ -49,16 +50,18 @@ ret void } -; CHECK: define void @foo2(float* nocapture %a, float* nocapture %b, float* nocapture readonly %c) #0 { +; CHECK-LABEL: define void @foo2(float* nocapture %a, float* nocapture %b, float* nocapture readonly %c) #0 { ; CHECK: entry: -; CHECK: %0 = load float, float* %c, align 4, !noalias !3 +; CHECK: call void @llvm.experimental.noalias.scope.decl(metadata !3) +; CHECK: call void @llvm.experimental.noalias.scope.decl(metadata !6) +; CHECK: [[TMP0:%.+]] = load float, float* %c, align 4, !noalias !8 ; CHECK: %arrayidx.i = getelementptr inbounds float, float* %a, i64 5 -; CHECK: store float %0, float* %arrayidx.i, align 4, !alias.scope !7, !noalias !8 +; CHECK: store float [[TMP0]], float* %arrayidx.i, align 4, !alias.scope !3, !noalias !6 ; CHECK: %arrayidx1.i = getelementptr inbounds float, float* %b, i64 8 -; CHECK: store float %0, float* %arrayidx1.i, align 4, !alias.scope !8, !noalias !7 -; CHECK: %1 = load float, float* %c, align 4 +; CHECK: store float [[TMP0]], float* %arrayidx1.i, align 4, !alias.scope !6, !noalias !3 +; CHECK: [[TMP1:%.+]] = load float, float* %c, align 4 ; CHECK: %arrayidx = getelementptr inbounds float, float* %a, i64 7 -; CHECK: store float %1, float* %arrayidx, align 4 +; CHECK: store float [[TMP1]], float* %arrayidx, align 4 ; CHECK: ret void ; CHECK: } @@ -67,10 +70,9 @@ ; CHECK: !0 = !{!1} ; CHECK: !1 = distinct !{!1, !2, !"hello: %a"} ; CHECK: !2 = distinct !{!2, !"hello"} -; CHECK: !3 = !{!4, !6} +; CHECK: !3 = !{!4} ; CHECK: !4 = distinct !{!4, !5, !"hello2: %a"} ; CHECK: !5 = distinct !{!5, !"hello2"} -; CHECK: !6 = distinct !{!6, !5, !"hello2: %b"} -; CHECK: !7 = !{!4} -; CHECK: !8 = !{!6} - +; CHECK: !6 = !{!7} +; CHECK: !7 = distinct !{!7, !5, !"hello2: %b"} +; CHECK: !8 = !{!4, !7} Index: llvm/test/Transforms/Inline/noalias2.ll =================================================================== --- llvm/test/Transforms/Inline/noalias2.ll +++ llvm/test/Transforms/Inline/noalias2.ll @@ -25,9 +25,11 @@ ; CHECK-LABEL: define {{[^@]+}}@foo ; CHECK-SAME: (float* noalias nocapture [[A:%.*]], float* noalias nocapture readonly [[C:%.*]]) [[ATTR0]] { ; CHECK-NEXT: entry: -; CHECK-NEXT: [[TMP0:%.*]] = load float, float* [[C]], align 4, !alias.scope !0, !noalias !3 +; CHECK-NEXT: call void @llvm.experimental.noalias.scope.decl(metadata !0) +; CHECK-NEXT: call void @llvm.experimental.noalias.scope.decl(metadata !3) +; CHECK-NEXT: [[TMP0:%.*]] = load float, float* [[C]], align 4, !alias.scope !3, !noalias !0 ; CHECK-NEXT: [[ARRAYIDX_I:%.*]] = getelementptr inbounds float, float* [[A]], i64 5 -; CHECK-NEXT: store float [[TMP0]], float* [[ARRAYIDX_I]], align 4, !alias.scope !3, !noalias !0 +; CHECK-NEXT: store float [[TMP0]], float* [[ARRAYIDX_I]], align 4, !alias.scope !0, !noalias !3 ; CHECK-NEXT: [[TMP1:%.*]] = load float, float* [[C]], align 4 ; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds float, float* [[A]], i64 7 ; CHECK-NEXT: store float [[TMP1]], float* [[ARRAYIDX]], align 4 @@ -67,17 +69,23 @@ ; CHECK-LABEL: define {{[^@]+}}@foo2 ; CHECK-SAME: (float* nocapture [[A:%.*]], float* nocapture [[B:%.*]], float* nocapture readonly [[C:%.*]]) [[ATTR0]] { ; CHECK-NEXT: entry: -; CHECK-NEXT: [[TMP0:%.*]] = load float, float* [[C]], align 4, !alias.scope !5, !noalias !10 +; CHECK-NEXT: call void @llvm.experimental.noalias.scope.decl(metadata !5) +; CHECK-NEXT: call void @llvm.experimental.noalias.scope.decl(metadata !8) +; CHECK-NEXT: call void @llvm.experimental.noalias.scope.decl(metadata !10) [[ATTR2:#.*]], !noalias !13 +; CHECK-NEXT: call void @llvm.experimental.noalias.scope.decl(metadata !14) [[ATTR2]], !noalias !13 +; CHECK-NEXT: [[TMP0:%.*]] = load float, float* [[C]], align 4, !alias.scope !16, !noalias !17 ; CHECK-NEXT: [[ARRAYIDX_I_I:%.*]] = getelementptr inbounds float, float* [[A]], i64 5 -; CHECK-NEXT: store float [[TMP0]], float* [[ARRAYIDX_I_I]], align 4, !alias.scope !10, !noalias !5 -; CHECK-NEXT: [[TMP1:%.*]] = load float, float* [[C]], align 4, !alias.scope !13, !noalias !14 +; CHECK-NEXT: store float [[TMP0]], float* [[ARRAYIDX_I_I]], align 4, !alias.scope !17, !noalias !16 +; CHECK-NEXT: [[TMP1:%.*]] = load float, float* [[C]], align 4, !alias.scope !8, !noalias !5 ; CHECK-NEXT: [[ARRAYIDX_I:%.*]] = getelementptr inbounds float, float* [[A]], i64 7 -; CHECK-NEXT: store float [[TMP1]], float* [[ARRAYIDX_I]], align 4, !alias.scope !14, !noalias !13 -; CHECK-NEXT: [[TMP2:%.*]] = load float, float* [[C]], align 4, !noalias !15 +; CHECK-NEXT: store float [[TMP1]], float* [[ARRAYIDX_I]], align 4, !alias.scope !5, !noalias !8 +; CHECK-NEXT: call void @llvm.experimental.noalias.scope.decl(metadata !18) +; CHECK-NEXT: call void @llvm.experimental.noalias.scope.decl(metadata !21) +; CHECK-NEXT: [[TMP2:%.*]] = load float, float* [[C]], align 4, !noalias !23 ; CHECK-NEXT: [[ARRAYIDX_I1:%.*]] = getelementptr inbounds float, float* [[A]], i64 6 -; CHECK-NEXT: store float [[TMP2]], float* [[ARRAYIDX_I1]], align 4, !alias.scope !19, !noalias !20 +; CHECK-NEXT: store float [[TMP2]], float* [[ARRAYIDX_I1]], align 4, !alias.scope !18, !noalias !21 ; CHECK-NEXT: [[ARRAYIDX1_I:%.*]] = getelementptr inbounds float, float* [[B]], i64 8 -; CHECK-NEXT: store float [[TMP2]], float* [[ARRAYIDX1_I]], align 4, !alias.scope !20, !noalias !19 +; CHECK-NEXT: store float [[TMP2]], float* [[ARRAYIDX1_I]], align 4, !alias.scope !21, !noalias !18 ; CHECK-NEXT: [[TMP3:%.*]] = load float, float* [[C]], align 4 ; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds float, float* [[A]], i64 7 ; CHECK-NEXT: store float [[TMP3]], float* [[ARRAYIDX]], align 4 @@ -93,26 +101,29 @@ } ; CHECK: !0 = !{!1} -; CHECK: !1 = distinct !{!1, !2, !"hello: %c"} +; CHECK: !1 = distinct !{!1, !2, !"hello: %a"} ; CHECK: !2 = distinct !{!2, !"hello"} ; CHECK: !3 = !{!4} -; CHECK: !4 = distinct !{!4, !2, !"hello: %a"} -; CHECK: !5 = !{!6, !8} -; CHECK: !6 = distinct !{!6, !7, !"hello: %c"} -; CHECK: !7 = distinct !{!7, !"hello"} -; CHECK: !8 = distinct !{!8, !9, !"foo: %c"} -; CHECK: !9 = distinct !{!9, !"foo"} -; CHECK: !10 = !{!11, !12} -; CHECK: !11 = distinct !{!11, !7, !"hello: %a"} -; CHECK: !12 = distinct !{!12, !9, !"foo: %a"} -; CHECK: !13 = !{!8} -; CHECK: !14 = !{!12} -; CHECK: !15 = !{!16, !18} -; CHECK: !16 = distinct !{!16, !17, !"hello2: %a"} -; CHECK: !17 = distinct !{!17, !"hello2"} -; CHECK: !18 = distinct !{!18, !17, !"hello2: %b"} -; CHECK: !19 = !{!16} -; CHECK: !20 = !{!18} +; CHECK: !4 = distinct !{!4, !2, !"hello: %c"} +; CHECK: !5 = !{!6} +; CHECK: !6 = distinct !{!6, !7, !"foo: %a"} +; CHECK: !7 = distinct !{!7, !"foo"} +; CHECK: !8 = !{!9} +; CHECK: !9 = distinct !{!9, !7, !"foo: %c"} +; CHECK: !10 = !{!11} +; CHECK: !11 = distinct !{!11, !12, !"hello: %a"} +; CHECK: !12 = distinct !{!12, !"hello"} +; CHECK: !13 = !{!6, !9} +; CHECK: !14 = !{!15} +; CHECK: !15 = distinct !{!15, !12, !"hello: %c"} +; CHECK: !16 = !{!15, !9} +; CHECK: !17 = !{!11, !6} +; CHECK: !18 = !{!19} +; CHECK: !19 = distinct !{!19, !20, !"hello2: %a"} +; CHECK: !20 = distinct !{!20, !"hello2"} +; CHECK: !21 = !{!22} +; CHECK: !22 = distinct !{!22, !20, !"hello2: %b"} +; CHECK: !23 = !{!19, !22} attributes #0 = { nounwind uwtable } Index: llvm/test/Transforms/PhaseOrdering/inlining-alignment-assumptions.ll =================================================================== --- llvm/test/Transforms/PhaseOrdering/inlining-alignment-assumptions.ll +++ llvm/test/Transforms/PhaseOrdering/inlining-alignment-assumptions.ll @@ -95,6 +95,7 @@ define amdgpu_kernel void @caller2() { ; CHECK-LABEL: @caller2( +; CHECK-NEXT: tail call void @llvm.experimental.noalias.scope.decl([[META0:metadata !.*]]) ; CHECK-NEXT: ret void ; %alloca = alloca i64, align 8, addrspace(5) Index: llvm/test/Transforms/PhaseOrdering/instcombine-sroa-inttoptr.ll =================================================================== --- llvm/test/Transforms/PhaseOrdering/instcombine-sroa-inttoptr.ll +++ llvm/test/Transforms/PhaseOrdering/instcombine-sroa-inttoptr.ll @@ -70,6 +70,7 @@ ; CHECK-NEXT: [[I2:%.*]] = alloca [[TMP0:%.*]], align 8 ; CHECK-NEXT: [[I1_SROA_0_0_I5_SROA_IDX:%.*]] = getelementptr inbounds [[TMP0]], %0* [[ARG:%.*]], i64 0, i32 0 ; CHECK-NEXT: [[I1_SROA_0_0_COPYLOAD:%.*]] = load i32*, i32** [[I1_SROA_0_0_I5_SROA_IDX]], align 8 +; CHECK-NEXT: tail call void @llvm.experimental.noalias.scope.decl([[META0:metadata !.*]]) ; CHECK-NEXT: [[I_SROA_0_0_I6_SROA_IDX:%.*]] = getelementptr inbounds [[TMP0]], %0* [[I2]], i64 0, i32 0 ; CHECK-NEXT: store i32* [[I1_SROA_0_0_COPYLOAD]], i32** [[I_SROA_0_0_I6_SROA_IDX]], align 8 ; CHECK-NEXT: tail call void @_Z7escape01S(%0* nonnull byval(%0) align 8 [[I2]]) @@ -109,6 +110,7 @@ ; CHECK-NEXT: bb: ; CHECK-NEXT: [[I1_SROA_0_0_I4_SROA_IDX:%.*]] = getelementptr inbounds [[TMP0:%.*]], %0* [[ARG:%.*]], i64 0, i32 0 ; CHECK-NEXT: [[I1_SROA_0_0_COPYLOAD:%.*]] = load i32*, i32** [[I1_SROA_0_0_I4_SROA_IDX]], align 8 +; CHECK-NEXT: tail call void @llvm.experimental.noalias.scope.decl([[META3:metadata !.*]]) ; CHECK-NEXT: [[I5:%.*]] = tail call i32 @_Z4condv() ; CHECK-NEXT: [[I6_NOT:%.*]] = icmp eq i32 [[I5]], 0 ; CHECK-NEXT: br i1 [[I6_NOT]], label [[BB10:%.*]], label [[BB7:%.*]] Index: llvm/test/Transforms/PhaseOrdering/pr39282.ll =================================================================== --- llvm/test/Transforms/PhaseOrdering/pr39282.ll +++ llvm/test/Transforms/PhaseOrdering/pr39282.ll @@ -19,12 +19,20 @@ define void @pr39282(i32* %addr1, i32* %addr2) { ; CHECK-LABEL: @pr39282( ; CHECK-NEXT: start: -; CHECK-NEXT: [[X_I:%.*]] = load i32, i32* [[ADDR1:%.*]], align 4, !alias.scope !0, !noalias !3 +; CHECK-NEXT: tail call void @llvm.experimental.noalias.scope.decl([[META0:metadata !.*]]) +; CHECK-NEXT: tail call void @llvm.experimental.noalias.scope.decl([[META3:metadata !.*]]) +; CHECK-NEXT: [[X_I:%.*]] = load i32, i32* [[ADDR1:%.*]], align 4, !alias.scope !3, !noalias !0 ; CHECK-NEXT: [[ADDR1I_1:%.*]] = getelementptr inbounds i32, i32* [[ADDR1]], i64 1 ; CHECK-NEXT: [[ADDR2I_1:%.*]] = getelementptr inbounds i32, i32* [[ADDR2:%.*]], i64 1 -; CHECK-NEXT: [[X_I_1:%.*]] = load i32, i32* [[ADDR1I_1]], align 4, !alias.scope !0, !noalias !3 -; CHECK-NEXT: store i32 [[X_I]], i32* [[ADDR2]], align 4, !alias.scope !3, !noalias !0 -; CHECK-NEXT: store i32 [[X_I_1]], i32* [[ADDR2I_1]], align 4, !alias.scope !3, !noalias !0 +; CHECK-NEXT: tail call void @llvm.experimental.noalias.scope.decl([[META0]]) +; CHECK-NEXT: tail call void @llvm.experimental.noalias.scope.decl([[META3]]) +; CHECK-NEXT: [[X_I_1:%.*]] = load i32, i32* [[ADDR1I_1]], align 4, !alias.scope !3, !noalias !0 +; CHECK-NEXT: tail call void @llvm.experimental.noalias.scope.decl([[META0]]) +; CHECK-NEXT: tail call void @llvm.experimental.noalias.scope.decl([[META3]]) +; CHECK-NEXT: store i32 [[X_I]], i32* [[ADDR2]], align 4, !alias.scope !0, !noalias !3 +; CHECK-NEXT: tail call void @llvm.experimental.noalias.scope.decl([[META0]]) +; CHECK-NEXT: tail call void @llvm.experimental.noalias.scope.decl([[META3]]) +; CHECK-NEXT: store i32 [[X_I_1]], i32* [[ADDR2I_1]], align 4, !alias.scope !0, !noalias !3 ; CHECK-NEXT: ret void ; start: