Index: llvm/include/llvm/Transforms/Utils/Cloning.h =================================================================== --- llvm/include/llvm/Transforms/Utils/Cloning.h +++ llvm/include/llvm/Transforms/Utils/Cloning.h @@ -295,6 +295,13 @@ void identifyNoAliasScopesToClone( ArrayRef BBs, SmallVectorImpl &NoAliasDeclScopes); +/// Find the 'llvm.experimental.noalias.scope.decl' intrinsics in the specified +/// instruction range and extract their scope. These are candidates for +/// duplication when cloning. +void identifyNoAliasScopesToClone( + BasicBlock::iterator Start, BasicBlock::iterator End, + SmallVectorImpl &NoAliasDeclScopes); + /// Duplicate the specified list of noalias decl scopes. /// The 'Ext' string is added as an extension to the name. /// Afterwards, the ClonedScopes contains the mapping of the original scope Index: llvm/lib/Transforms/Scalar/JumpThreading.cpp =================================================================== --- llvm/lib/Transforms/Scalar/JumpThreading.cpp +++ llvm/lib/Transforms/Scalar/JumpThreading.cpp @@ -2076,6 +2076,15 @@ 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); + // 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 // instructions. @@ -2084,6 +2093,7 @@ New->setName(BI->getName()); NewBB->getInstList().push_back(New); 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/CloneFunction.cpp =================================================================== --- llvm/lib/Transforms/Utils/CloneFunction.cpp +++ llvm/lib/Transforms/Utils/CloneFunction.cpp @@ -1036,3 +1036,11 @@ if (auto *Decl = dyn_cast(&I)) NoAliasDeclScopes.push_back(Decl->getScopeList()); } + +void llvm::identifyNoAliasScopesToClone( + BasicBlock::iterator Start, BasicBlock::iterator End, + SmallVectorImpl &NoAliasDeclScopes) { + for (Instruction &I : make_range(Start, End)) + if (auto *Decl = dyn_cast(&I)) + NoAliasDeclScopes.push_back(Decl->getScopeList()); +} Index: llvm/test/Transforms/JumpThreading/noalias-scope-decl.ll =================================================================== --- /dev/null +++ llvm/test/Transforms/JumpThreading/noalias-scope-decl.ll @@ -0,0 +1,63 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt -S -jump-threading < %s | FileCheck %s + +define void @test(i8* %ptr) { +; CHECK-LABEL: @test( +; CHECK-NEXT: entry: +; CHECK-NEXT: call void @llvm.experimental.noalias.scope.decl(metadata !0) +; 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: 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: store i8 0, i8* [[PTR]], align 1, !noalias !0 +; CHECK-NEXT: store i8 1, i8* [[PTR]], align 1, !noalias !5 +; CHECK-NEXT: ret void +; +entry: + call void @llvm.experimental.noalias.scope.decl(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 ] + call void @llvm.experimental.noalias.scope.decl(metadata !3) + store i8 0, i8* %ptr, !noalias !0 + store i8 1, i8* %ptr, !noalias !3 + %i.inc = add i32 %i, 1 + br i1 %p, label %exit, label %loop + +exit: + ret void +} + +declare void @llvm.experimental.noalias.scope.decl(metadata) + +!0 = !{!1} +!1 = distinct !{!1, !2, !"scope1"} +!2 = distinct !{!2, !"domain"} +!3 = !{!4} +!4 = distinct !{!4, !2, !"scope2"} + +; CHECK: !0 = !{!1} +; CHECK: !1 = distinct !{!1, !2, !"scope1"} +; CHECK: !2 = distinct !{!2, !"domain"} +; CHECK: !3 = !{!4} +; CHECK: !4 = distinct !{!4, !2, !"scope2"} +; CHECK: !5 = !{!6} +; CHECK: !6 = distinct !{!6, !2, !"scope2:thread"}