Index: llvm/lib/Transforms/IPO/ArgumentPromotion.cpp =================================================================== --- llvm/lib/Transforms/IPO/ArgumentPromotion.cpp +++ llvm/lib/Transforms/IPO/ArgumentPromotion.cpp @@ -163,7 +163,9 @@ for (User *U : make_early_inc_range(I->users())) { Instruction *UI = cast(U); Type *SrcTy; - if (LoadInst *L = dyn_cast(UI)) + IndicesVector Indices; + LoadInst *L = dyn_cast(UI); + if (L) SrcTy = L->getType(); else SrcTy = cast(UI)->getSourceElementType(); @@ -173,20 +175,21 @@ continue; } - IndicesVector Indices; - Indices.reserve(UI->getNumOperands() - 1); - // Since loads will only have a single operand, and GEPs only a single - // non-index operand, this will record direct loads without any indices, - // and gep+loads with the GEP indices. - for (User::op_iterator II = UI->op_begin() + 1, IE = UI->op_end(); - II != IE; ++II) - Indices.push_back(cast(*II)->getSExtValue()); - // GEPs with a single 0 index can be merged with direct loads - if (Indices.size() == 1 && Indices.front() == 0) - Indices.clear(); + if (L == nullptr) { // not a direct load (loads can have 2 operands) + Indices.reserve(UI->getNumOperands() - 1); + // Since loads will only have a single operand, and GEPs only a single + // non-index operand, this will record direct loads without any + // indices, and gep+loads with the GEP indices. + for (User::op_iterator II = UI->op_begin() + 1, IE = UI->op_end(); + II != IE; ++II) + Indices.push_back(cast(*II)->getSExtValue()); + // GEPs with a single 0 index can be merged with direct loads + if (Indices.size() == 1 && Indices.front() == 0) + Indices.clear(); + } ArgIndices.insert(std::make_pair(SrcTy, Indices)); LoadInst *OrigLoad; - if (LoadInst *L = dyn_cast(UI)) + if (L) OrigLoad = L; else // Take any load, we will use it only to update Alias Analysis @@ -317,6 +320,7 @@ AAMDNodes AAInfo; OrigLoad->getAAMetadata(AAInfo); newLoad->setAAMetadata(AAInfo); + newLoad->setAAMetadataNoAliasProvenance(AAInfo); Args.push_back(newLoad); ArgAttrVec.push_back(AttributeSet()); Index: llvm/lib/Transforms/IPO/FunctionAttrs.cpp =================================================================== --- llvm/lib/Transforms/IPO/FunctionAttrs.cpp +++ llvm/lib/Transforms/IPO/FunctionAttrs.cpp @@ -1018,6 +1018,12 @@ case Instruction::Call: case Instruction::Invoke: { CallBase &CB = cast(*RVI); + if (CB.getIntrinsicID() == Intrinsic::noalias_arg_guard || + CB.getIntrinsicID() == Intrinsic::noalias_copy_guard) { + // Look through a noalias arg/copy guard + FlowsToReturn.insert(RVI->getOperand(0)); + continue; + } Function *Callee = CB.getCalledFunction(); // A call to a node within the SCC is assumed to return null until // proven otherwise Index: llvm/lib/Transforms/IPO/GlobalOpt.cpp =================================================================== --- llvm/lib/Transforms/IPO/GlobalOpt.cpp +++ llvm/lib/Transforms/IPO/GlobalOpt.cpp @@ -215,6 +215,9 @@ Value *V = SI->getValueOperand(); if (isa(V)) { Changed = true; + // skip potential second use from ptr_provenance before the erase + if ((UI != E) && (*UI == SI)) + UI++; SI->eraseFromParent(); } else if (Instruction *I = dyn_cast(V)) { if (I->hasOneUse()) @@ -796,6 +799,9 @@ Changed |= OptimizeAwayTrappingUsesOfValue(LI, LV); // If we were able to delete all uses of the loads if (LI->use_empty()) { + // skip potential second use from ptr_provenance before the erase + if ((GUI != E) && (*GUI == LI)) + GUI++; LI->eraseFromParent(); Changed = true; } else { Index: llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp +++ llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp @@ -1977,6 +1977,22 @@ return V.getValue(); break; } + case Intrinsic::noalias_decl: { + Value *Op0 = II->getOperand(0); + Value *BaseOp0 = Op0->stripPointerCasts(); + if (Op0 != BaseOp0) { + auto *NewNoAlias = Builder.CreateNoAliasDeclaration( + BaseOp0, II->getOperand(1), II->getOperand(2)); + // bwaahh seems we need to do everything ourselves ? + II->replaceAllUsesWith(NewNoAlias); + Worklist.remove(II); + II->eraseFromParent(); + MadeIRChange = true; + + return nullptr; + } + break; + } } // Some intrinsics (like experimental_gc_statepoint) can be used in invoke // context, so it is handled in visitCallBase and we should trigger it. Index: llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp +++ llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp @@ -469,10 +469,20 @@ NewPtr->getType()->getPointerAddressSpace() == AS)) NewPtr = Builder.CreateBitCast(Ptr, NewTy->getPointerTo(AS)); + Value *NewProvenancePtr = nullptr; + if (LI.hasNoaliasProvenanceOperand()) { + NewProvenancePtr = Builder.CreateBitCast(LI.getNoaliasProvenanceOperand(), + NewTy->getPointerTo(AS)); + } + LoadInst *NewLoad = Builder.CreateAlignedLoad( NewTy, NewPtr, LI.getAlign(), LI.isVolatile(), LI.getName() + Suffix); NewLoad->setAtomic(LI.getOrdering(), LI.getSyncScopeID()); copyMetadataForLoad(*NewLoad, LI); + if (LI.hasNoaliasProvenanceOperand()) { + assert(NewProvenancePtr); + NewLoad->setNoaliasProvenanceOperand(NewProvenancePtr); + } return NewLoad; } @@ -489,6 +499,12 @@ SmallVector, 8> MD; SI.getAllMetadata(MD); + Value *NewProvenancePtr = nullptr; + if (SI.hasNoaliasProvenanceOperand()) { + NewProvenancePtr = IC.Builder.CreateBitCast( + SI.getNoaliasProvenanceOperand(), V->getType()->getPointerTo(AS)); + } + StoreInst *NewStore = IC.Builder.CreateAlignedStore( V, IC.Builder.CreateBitCast(Ptr, V->getType()->getPointerTo(AS)), SI.getAlign(), SI.isVolatile()); @@ -530,6 +546,11 @@ } } + if (SI.hasNoaliasProvenanceOperand()) { + assert(NewProvenancePtr); + NewStore->setNoaliasProvenanceOperand(NewProvenancePtr); + } + return NewStore; } @@ -671,6 +692,7 @@ AAMDNodes AAMD; LI.getAAMetadata(AAMD); L->setAAMetadata(AAMD); + L->setAAMetadataNoAliasProvenance(AAMD); V = IC.Builder.CreateInsertValue(V, L, i); } @@ -720,6 +742,7 @@ AAMDNodes AAMD; LI.getAAMetadata(AAMD); L->setAAMetadata(AAMD); + L->setAAMetadataNoAliasProvenance(AAMD); V = IC.Builder.CreateInsertValue(V, L, i); Offset += EltSize; } @@ -937,6 +960,15 @@ Instruction *InstCombinerImpl::visitLoadInst(LoadInst &LI) { Value *Op = LI.getOperand(0); + if (LI.hasNoaliasProvenanceOperand()) { + if (LI.getNoaliasProvenanceOperand() == LI.getPointerOperand() || + isa(LI.getNoaliasProvenanceOperand())) { + // degenerated ptr_provenance + LI.removeNoaliasProvenanceOperand(); + return &LI; + } + } + // Try to canonicalize the loaded type. if (Instruction *Res = combineLoadToOperationType(*this, LI)) return Res; @@ -1199,6 +1231,7 @@ AAMDNodes AAMD; SI.getAAMetadata(AAMD); NS->setAAMetadata(AAMD); + NS->setAAMetadataNoAliasProvenance(AAMD); } return true; @@ -1247,6 +1280,7 @@ AAMDNodes AAMD; SI.getAAMetadata(AAMD); NS->setAAMetadata(AAMD); + NS->setAAMetadataNoAliasProvenance(AAMD); Offset += EltSize; } @@ -1341,6 +1375,15 @@ Value *Val = SI.getOperand(0); Value *Ptr = SI.getOperand(1); + if (SI.hasNoaliasProvenanceOperand()) { + if (SI.getNoaliasProvenanceOperand() == SI.getPointerOperand() || + isa(SI.getNoaliasProvenanceOperand())) { + // degenerated ptr_provenance + SI.removeNoaliasProvenanceOperand(); + return &SI; + } + } + // Try to canonicalize the stored type. if (combineStoreToValueType(*this, SI)) return eraseInstFromFunction(SI); @@ -1562,6 +1605,7 @@ if (AATags) { OtherStore->getAAMetadata(AATags, /* Merge = */ true); NewSI->setAAMetadata(AATags); + NewSI->setAAMetadataNoAliasProvenance(AATags); } // Nuke the old stores. Index: llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp +++ llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp @@ -698,11 +698,8 @@ new LoadInst(FirstLI->getType(), NewPN, "", isVolatile, LoadAlignment); unsigned KnownIDs[] = { - LLVMContext::MD_tbaa, LLVMContext::MD_range, LLVMContext::MD_invariant_load, - LLVMContext::MD_alias_scope, - LLVMContext::MD_noalias, LLVMContext::MD_nonnull, LLVMContext::MD_align, LLVMContext::MD_dereferenceable, @@ -714,14 +711,19 @@ NewLI->setMetadata(ID, FirstLI->getMetadata(ID)); // Add all operands to the new PHI and combine TBAA metadata. + AAMDNodes AAInfo; + FirstLI->getAAMetadata(AAInfo); for (unsigned i = 1, e = PN.getNumIncomingValues(); i != e; ++i) { LoadInst *LI = cast(PN.getIncomingValue(i)); combineMetadata(NewLI, LI, KnownIDs, true); + LI->getAAMetadata(AAInfo, true); Value *NewInVal = LI->getOperand(0); if (NewInVal != InVal) InVal = nullptr; NewPN->addIncoming(NewInVal, PN.getIncomingBlock(i)); } + NewLI->setAAMetadata(AAInfo); + NewLI->setAAMetadataNoAliasProvenance(AAInfo); if (InVal) { // The new PHI unions all of the same values together. This is really Index: llvm/lib/Transforms/InstCombine/InstructionCombining.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstructionCombining.cpp +++ llvm/lib/Transforms/InstCombine/InstructionCombining.cpp @@ -2576,6 +2576,7 @@ case Intrinsic::lifetime_start: case Intrinsic::lifetime_end: case Intrinsic::objectsize: + case Intrinsic::noalias_decl: Users.emplace_back(I); continue; } @@ -3097,9 +3098,21 @@ AAMDNodes Nodes; L->getAAMetadata(Nodes); NL->setAAMetadata(Nodes); + NL->setAAMetadataNoAliasProvenance(Nodes); // Returning the load directly will cause the main loop to insert it in - // the wrong spot, so use replaceInstUsesWith(). - return replaceInstUsesWith(EV, NL); + // the wrong spot, so use ReplaceInstUsesWith(). + { + for (auto mdtag : + {LLVMContext::MD_dbg, LLVMContext::MD_prof, LLVMContext::MD_fpmath, + LLVMContext::MD_tbaa_struct, LLVMContext::MD_invariant_load, + LLVMContext::MD_nontemporal, + LLVMContext::MD_mem_parallel_loop_access}) { + if (auto *MD = L->getMetadata(mdtag)) { + NL->setMetadata(mdtag, MD); + } + } + return replaceInstUsesWith(EV, NL); + } } // We could simplify extracts from other values. Note that nested extracts may // already be simplified implicitly by the above: extract (extract (insert) ) Index: llvm/lib/Transforms/Scalar/GVN.cpp =================================================================== --- llvm/lib/Transforms/Scalar/GVN.cpp +++ llvm/lib/Transforms/Scalar/GVN.cpp @@ -1216,8 +1216,11 @@ // Transfer the old load's AA tags to the new load. AAMDNodes Tags; Load->getAAMetadata(Tags); - if (Tags) + if (Tags) { NewLoad->setAAMetadata(Tags); + // Note: ptr_provenance propagation is not done here. A dependend + // provenance should be migrated first ! + } if (auto *MD = Load->getMetadata(LLVMContext::MD_invariant_load)) NewLoad->setMetadata(LLVMContext::MD_invariant_load, MD); Index: llvm/lib/Transforms/Scalar/JumpThreading.cpp =================================================================== --- llvm/lib/Transforms/Scalar/JumpThreading.cpp +++ llvm/lib/Transforms/Scalar/JumpThreading.cpp @@ -567,6 +567,18 @@ if (isa(I)) continue; + // Noalias intrinsics are free too. + if (isa(I)) + continue; + if (auto II = dyn_cast(I)) { + auto ID = II->getIntrinsicID(); + if (ID == Intrinsic::noalias_decl || ID == Intrinsic::noalias || + ID == Intrinsic::provenance_noalias || + ID == Intrinsic::noalias_arg_guard || + ID == Intrinsic::noalias_copy_guard) + continue; + } + // Bail out if this instruction gives back a token type, it is not possible // to duplicate it if it is used outside this BB. if (I->getType()->isTokenTy() && I->isUsedOutsideOfBlock(BB)) @@ -1497,8 +1509,11 @@ LoadI->getOrdering(), LoadI->getSyncScopeID(), UnavailablePred->getTerminator()); NewVal->setDebugLoc(LoadI->getDebugLoc()); - if (AATags) + if (AATags) { NewVal->setAAMetadata(AATags); + // Note: ptr_provenance propagation is not done here. A dependend + // provenance should be migrated first ! + } AvailablePreds.emplace_back(UnavailablePred, NewVal); } @@ -2079,7 +2094,6 @@ // copy of the block 'NewBB'. If there are PHI nodes in the source basic // block, evaluate them to account for entry from PredBB. DenseMap ValueMapping; - // Clone the phi nodes of the source basic block into NewBB. The resulting // phi nodes are trivial since NewBB only has one predecessor, but SSAUpdater // might need to rewrite the operand of the cloned phi. @@ -2089,14 +2103,7 @@ ValueMapping[PN] = NewPN; } - // Clone noalias scope declarations in the threaded block. When threading a - // loop exit, we would otherwise end up with two idential scope declarations - // visible at the same time. - SmallVector NoAliasScopes; - DenseMap ClonedScopes; - LLVMContext &Context = PredBB->getContext(); - identifyNoAliasScopesToClone(BI, BE, NoAliasScopes); - cloneNoAliasScopes(NoAliasScopes, ClonedScopes, "thread", Context); + // Cloning noalias scopes is allowed and will refer to the same scope. // Clone the non-phi instructions of the source basic block into NewBB, // keeping track of the mapping and using it to remap operands in the cloned @@ -2105,8 +2112,18 @@ Instruction *New = BI->clone(); New->setName(BI->getName()); NewBB->getInstList().push_back(New); + // Also track the ptr_provenance + if (auto *SI = dyn_cast(BI)) { + if (SI->hasNoaliasProvenanceOperand()) + cast(New)->setNoaliasProvenanceOperand( + SI->getNoaliasProvenanceOperand()); + } else if (auto *LI = dyn_cast(BI)) { + if (LI->hasNoaliasProvenanceOperand()) + cast(New)->setNoaliasProvenanceOperand( + LI->getNoaliasProvenanceOperand()); + } + ValueMapping[&*BI] = New; - adaptNoAliasScopes(New, ClonedScopes, Context); // Remap operands to patch up intra-block references. for (unsigned i = 0, e = New->getNumOperands(); i != e; ++i) Index: llvm/lib/Transforms/Utils/SimplifyCFG.cpp =================================================================== --- llvm/lib/Transforms/Utils/SimplifyCFG.cpp +++ llvm/lib/Transforms/Utils/SimplifyCFG.cpp @@ -1503,6 +1503,7 @@ LLVMContext::MD_dereferenceable, LLVMContext::MD_dereferenceable_or_null, LLVMContext::MD_mem_parallel_loop_access, + LLVMContext::MD_noalias, LLVMContext::MD_access_group, LLVMContext::MD_preserve_access_index}; combineMetadata(I1, I2, KnownIDs, true); @@ -3482,8 +3483,9 @@ StoreInst *SI = cast(QB.CreateStore(QPHI, Address)); AAMDNodes AAMD; PStore->getAAMetadata(AAMD, /*Merge=*/false); - PStore->getAAMetadata(AAMD, /*Merge=*/true); + QStore->getAAMetadata(AAMD, /*Merge=*/true); SI->setAAMetadata(AAMD); + SI->setAAMetadataNoAliasProvenance(AAMD); // Choose the minimum alignment. If we could prove both stores execute, we // could use biggest one. In this case, though, we only know that one of the // stores executes. And we don't know it's safe to take the alignment from a Index: llvm/test/Transforms/FunctionAttrs/nonnull.ll =================================================================== --- llvm/test/Transforms/FunctionAttrs/nonnull.ll +++ llvm/test/Transforms/FunctionAttrs/nonnull.ll @@ -779,5 +779,15 @@ br i1 %11, label %7, label %8 } +; Return a pointer trivially nonnull (argument attribute) through a llvm.noalias.arg.guard +; FNATTR: define nonnull i8* @test_noalias_arg_guard +define i8* @test_noalias_arg_guard(i8* nonnull %p) { + %ret = tail call i8* @llvm.noalias.arg.guard.p0i8.p0i8(i8* %p, i8* %p) + ret i8* %p +} + +; Function Attrs: nounwind readnone +declare i8* @llvm.noalias.arg.guard.p0i8.p0i8(i8*, i8*) nounwind readnone + attributes #0 = { null_pointer_is_valid } attributes #1 = { nounwind willreturn} Index: llvm/test/Transforms/InstCombine/fold-phi-load-metadata.ll =================================================================== --- llvm/test/Transforms/InstCombine/fold-phi-load-metadata.ll +++ llvm/test/Transforms/InstCombine/fold-phi-load-metadata.ll @@ -40,10 +40,10 @@ ; CHECK: ![[TBAA]] = !{![[TAG1:[0-9]+]], ![[TAG1]], i64 0} ; CHECK: ![[TAG1]] = !{!"int", !{{[0-9]+}}, i64 0} ; CHECK: ![[RANGE]] = !{i32 10, i32 25} -; CHECK: ![[ALIAS_SCOPE]] = !{![[SCOPE0:[0-9]+]], ![[SCOPE1:[0-9]+]], ![[SCOPE2:[0-9]+]]} +; CHECK: ![[ALIAS_SCOPE]] = !{![[SCOPE0:[0-9]+]], ![[SCOPE2:[0-9]+]], ![[SCOPE1:[0-9]+]]} ; CHECK: ![[SCOPE0]] = distinct !{![[SCOPE0]], !{{[0-9]+}}, !"scope0"} -; CHECK: ![[SCOPE1]] = distinct !{![[SCOPE1]], !{{[0-9]+}}, !"scope1"} ; CHECK: ![[SCOPE2]] = distinct !{![[SCOPE2]], !{{[0-9]+}}, !"scope2"} +; CHECK: ![[SCOPE1]] = distinct !{![[SCOPE1]], !{{[0-9]+}}, !"scope1"} ; CHECK: ![[NOALIAS]] = !{![[SCOPE3:[0-9]+]]} ; CHECK: ![[SCOPE3]] = distinct !{![[SCOPE3]], !{{[0-9]+}}, !"scope3"} Index: llvm/test/Transforms/InstCombine/noalias.ll =================================================================== --- /dev/null +++ llvm/test/Transforms/InstCombine/noalias.ll @@ -0,0 +1,49 @@ +; RUN: opt < %s -instcombine -S | FileCheck %s + +target datalayout = "e-i8:8:8-i16:16:16-i32:32:32-i64:32:32-f32:32:32-f64:32:32-p:32:32:32:32:8-s0:32:32-a0:8:8-S32-n32-v128:32:32-P0-p0:32:32:32:32:8-p10:32:32:32:32:8-p20:32:32:32:32:8" + +@__const.f1.i = private unnamed_addr constant { i8*, [4 x i8] } { i8* null, [4 x i8] undef }, align 4 + +declare void @do_something(i8*) + +; Function Attrs: nounwind optsize +define dso_local i64 @test01() local_unnamed_addr #0 { +entry: + %i.sroa.6 = alloca [2 x i8], align 2 + %i.sroa.6.0..sroa_idx6 = getelementptr inbounds [2 x i8], [2 x i8]* %i.sroa.6, i32 0, i32 0 + call void @llvm.lifetime.start.p0i8(i64 2, i8* %i.sroa.6.0..sroa_idx6) + %0 = call i8* @llvm.noalias.decl.p0i8.p0a2i8.i32([2 x i8]* %i.sroa.6, i32 2, metadata !2) + call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 2 %i.sroa.6.0..sroa_idx6, i8* align 2 getelementptr inbounds (i8, i8* bitcast ({ i8*, [4 x i8] }* @__const.f1.i to i8*), i32 2), i32 2, i1 false) + %i.sroa.6.cast = bitcast [2 x i8]* %i.sroa.6 to i8* + call void @do_something(i8* %i.sroa.6.cast) + call void @llvm.lifetime.end.p0i8(i64 2, i8* %i.sroa.6.0..sroa_idx6) + ret i64 undef +} + +; CHECK-LABEL: @test01( +; CHECK: %i.sroa.6 = alloca i16, align 2 +; CHECK: %0 = call i8* @llvm.noalias.decl.p0i8.p0i16.i32(i16* nonnull %i.sroa.6, i32 2, metadata !2) + +; Function Attrs: argmemonly nounwind +declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture) #1 + +; Function Attrs: argmemonly nounwind +declare void @llvm.memcpy.p0i8.p0i8.i32(i8* nocapture writeonly, i8* nocapture readonly, i32, i1 immarg) #1 + +; Function Attrs: argmemonly nounwind +declare void @llvm.lifetime.end.p0i8(i64 immarg, i8* nocapture) #1 + +; Function Attrs: argmemonly nounwind +declare i8* @llvm.noalias.decl.p0i8.p0a2i8.i32([2 x i8]*, i32, metadata) #1 + +attributes #0 = { nounwind optsize "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { argmemonly nounwind } + +!llvm.module.flags = !{!0} +!llvm.ident = !{!1} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{!"clang"} +!2 = !{!3} +!3 = distinct !{!3, !4, !"f1: i"} +!4 = distinct !{!4, !"f1"} Index: llvm/test/Transforms/JumpThreading/noalias-decl.ll =================================================================== --- /dev/null +++ llvm/test/Transforms/JumpThreading/noalias-decl.ll @@ -0,0 +1,74 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt -S -jump-threading < %s | FileCheck %s + +define void @test01(i32* %ptr1, i32* %ptr2) { +; CHECK-LABEL: @test01( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[V1_DECL:%.*]] = call i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32** null, i32 0, metadata [[META0:![0-9]+]]) +; CHECK-NEXT: [[V1_PROV:%.*]] = call i32* @llvm.provenance.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* [[PTR1:%.*]], i8* [[V1_DECL]], i32** null, i32** null, i32 0, metadata [[META0]]) +; CHECK-NEXT: br label [[LOOP:%.*]] +; CHECK: loop: +; CHECK-NEXT: [[I:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[I_INC:%.*]], [[LATCH:%.*]] ] +; CHECK-NEXT: [[C:%.*]] = icmp eq i32 [[I]], 100 +; CHECK-NEXT: br i1 [[C]], label [[EXIT:%.*]], label [[LATCH]] +; CHECK: latch: +; CHECK-NEXT: [[V2_DECL:%.*]] = call i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32** null, i32 0, metadata [[META3:![0-9]+]]) +; CHECK-NEXT: [[V2_PROV:%.*]] = call i32* @llvm.provenance.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* [[PTR2:%.*]], i8* [[V2_DECL]], i32** null, i32** null, i32 0, metadata [[META3]]) +; CHECK-NEXT: store i32 0, i32* [[PTR1]], ptr_provenance i32* [[V1_PROV]], align 4, !noalias !0 +; CHECK-NEXT: store i32 1, i32* [[PTR2]], ptr_provenance i32* [[V2_PROV]], align 4, !noalias !3 +; CHECK-NEXT: [[I_INC]] = add i32 [[I]], 1 +; CHECK-NEXT: br label [[LOOP]] +; CHECK: exit: +; CHECK-NEXT: [[V2_DECL2:%.*]] = call i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32** null, i32 0, metadata [[META3]]) +; CHECK-NEXT: [[V2_PROV3:%.*]] = call i32* @llvm.provenance.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* [[PTR2]], i8* [[V2_DECL2]], i32** null, i32** null, i32 0, metadata [[META3]]) +; CHECK-NEXT: store i32 0, i32* [[PTR1]], ptr_provenance i32* [[V1_PROV]], align 4, !noalias !0 +; CHECK-NEXT: store i32 1, i32* [[PTR2]], ptr_provenance i32* [[V2_PROV3]], align 4, !noalias !3 +; CHECK-NEXT: ret void +; +entry: + %v1.decl = call i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32** null, i32 0, metadata !0) + %v1.prov = call i32* @llvm.provenance.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %ptr1, i8* %v1.decl, i32** null, i32** null, i32 0, metadata !0) + br label %loop + +loop: + %i = phi i32 [ 0, %entry ], [ %i.inc, %latch ] + %c = icmp eq i32 %i, 100 + br i1 %c, label %if, label %latch + +if: + br label %latch + +latch: + %p = phi i1 [ true, %if ], [ false, %loop ] + %v2.decl = call i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32** null, i32 0, metadata !3) + %v2.prov = call i32* @llvm.provenance.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %ptr2, i8* %v2.decl, i32** null, i32** null, i32 0, metadata !3) + store i32 0, i32* %ptr1, ptr_provenance i32* %v1.prov, !noalias !0 + store i32 1, i32* %ptr2, ptr_provenance i32* %v2.prov, !noalias !3 + ; store i32 2, i32* %ptr2, ptr_provenance i32* %v2.prov, !noalias !5 + %i.inc = add i32 %i, 1 + br i1 %p, label %exit, label %loop + +exit: + ret void +} + +; Function Attrs: argmemonly nounwind +declare i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32**, i32, metadata) + +; Function Attrs: nounwind readnone speculatable +declare i32* @llvm.provenance.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32*, i8*, i32**, i32**, i32, metadata) + +!0 = !{!1} +!1 = distinct !{!1, !2, !"scope1"} +!2 = distinct !{!2, !"domain"} +!3 = !{!4} +!4 = distinct !{!4, !2, !"scope2"} +!5 = !{!1, !4} + +; CHECK: !0 = !{!1} +; CHECK: !1 = distinct !{!1, !2, !"scope1"} +; CHECK: !2 = distinct !{!2, !"domain"} +; CHECK: !3 = !{!4} +; CHECK: !4 = distinct !{!4, !2, !"scope2"} +; CHECK-NOT: = + Index: llvm/test/Transforms/JumpThreading/noalias-scope-decl.ll =================================================================== --- llvm/test/Transforms/JumpThreading/noalias-scope-decl.ll +++ llvm/test/Transforms/JumpThreading/noalias-scope-decl.ll @@ -4,22 +4,22 @@ define void @test(i8* %ptr) { ; CHECK-LABEL: @test( ; CHECK-NEXT: entry: -; CHECK-NEXT: call void @llvm.experimental.noalias.scope.decl(metadata !0) +; CHECK-NEXT: call void @llvm.experimental.noalias.scope.decl(metadata [[META0:![0-9]+]]) ; CHECK-NEXT: br label [[LOOP:%.*]] ; CHECK: loop: ; CHECK-NEXT: [[I:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[I_INC:%.*]], [[LATCH:%.*]] ] ; CHECK-NEXT: [[C:%.*]] = icmp eq i32 [[I]], 100 ; CHECK-NEXT: br i1 [[C]], label [[EXIT:%.*]], label [[LATCH]] ; CHECK: latch: -; CHECK-NEXT: call void @llvm.experimental.noalias.scope.decl(metadata !3) +; CHECK-NEXT: call void @llvm.experimental.noalias.scope.decl(metadata [[META3:![0-9]+]]) ; CHECK-NEXT: store i8 0, i8* [[PTR:%.*]], align 1, !noalias !0 ; CHECK-NEXT: store i8 1, i8* [[PTR]], align 1, !noalias !3 ; CHECK-NEXT: [[I_INC]] = add i32 [[I]], 1 ; CHECK-NEXT: br label [[LOOP]] ; CHECK: exit: -; CHECK-NEXT: call void @llvm.experimental.noalias.scope.decl(metadata !5) +; CHECK-NEXT: call void @llvm.experimental.noalias.scope.decl(metadata [[META3]]) ; CHECK-NEXT: store i8 0, i8* [[PTR]], align 1, !noalias !0 -; CHECK-NEXT: store i8 1, i8* [[PTR]], align 1, !noalias !5 +; CHECK-NEXT: store i8 1, i8* [[PTR]], align 1, !noalias !3 ; CHECK-NEXT: ret void ; entry: @@ -59,5 +59,4 @@ ; CHECK: !2 = distinct !{!2, !"domain"} ; CHECK: !3 = !{!4} ; CHECK: !4 = distinct !{!4, !2, !"scope2"} -; CHECK: !5 = !{!6} -; CHECK: !6 = distinct !{!6, !2, !"scope2:thread"} +; CHECK-NOT: =