diff --git a/llvm/lib/Transforms/Scalar/LICM.cpp b/llvm/lib/Transforms/Scalar/LICM.cpp --- a/llvm/lib/Transforms/Scalar/LICM.cpp +++ b/llvm/lib/Transforms/Scalar/LICM.cpp @@ -1959,6 +1959,7 @@ bool DereferenceableInPH = false; bool SafeToInsertStore = false; + bool StoreIsGuanteedToExecute = false; bool FoundLoadToPromote = false; SmallVector LoopUses; @@ -2039,10 +2040,12 @@ // alignment than any other guaranteed stores, in which case we can // raise the alignment on the promoted store. Align InstAlignment = Store->getAlign(); - + bool GuaranteedToExecute = + SafetyInfo->isGuaranteedToExecute(*UI, DT, CurLoop); + StoreIsGuanteedToExecute |= GuaranteedToExecute; if (!DereferenceableInPH || !SafeToInsertStore || (InstAlignment > Alignment)) { - if (SafetyInfo->isGuaranteedToExecute(*UI, DT, CurLoop)) { + if (GuaranteedToExecute) { DereferenceableInPH = true; SafeToInsertStore = true; Alignment = std::max(Alignment, InstAlignment); @@ -2156,21 +2159,38 @@ // Set up the preheader to have a definition of the value. It is the live-out // value from the preheader that uses in the loop will use. - LoadInst *PreheaderLoad = new LoadInst( - AccessTy, SomePtr, SomePtr->getName() + ".promoted", - Preheader->getTerminator()); - if (SawUnorderedAtomic) - PreheaderLoad->setOrdering(AtomicOrdering::Unordered); - PreheaderLoad->setAlignment(Alignment); - PreheaderLoad->setDebugLoc(DebugLoc()); - if (AATags) - PreheaderLoad->setAAMetadata(AATags); - SSA.AddAvailableValue(Preheader, PreheaderLoad); - - MemoryAccess *PreheaderLoadMemoryAccess = MSSAU.createMemoryAccessInBB( - PreheaderLoad, nullptr, PreheaderLoad->getParent(), MemorySSA::End); - MemoryUse *NewMemUse = cast(PreheaderLoadMemoryAccess); - MSSAU.insertUse(NewMemUse, /*RenameUses=*/true); + LoadInst *PreheaderLoad = nullptr; + if (FoundLoadToPromote || !StoreIsGuanteedToExecute) { + // Verify that we do not introduce a load to memory accessible outside the + // current function, if it is marked as writeonly. + Value *Object = getUnderlyingObject(SomePtr); + (void)Object; + assert((!Preheader->getParent()->hasFnAttribute(Attribute::WriteOnly) || + StoreIsGuanteedToExecute || + (isNoAliasCall(Object) && + !PointerMayBeCaptured(Object, /* ReturnCaptures */ true, + /* StoreCaptures */ true)) || + isa(Object)) && + "Would add a load to writeonly function"); + + PreheaderLoad = + new LoadInst(AccessTy, SomePtr, SomePtr->getName() + ".promoted", + Preheader->getTerminator()); + if (SawUnorderedAtomic) + PreheaderLoad->setOrdering(AtomicOrdering::Unordered); + PreheaderLoad->setAlignment(Alignment); + PreheaderLoad->setDebugLoc(DebugLoc()); + if (AATags) + PreheaderLoad->setAAMetadata(AATags); + + MemoryAccess *PreheaderLoadMemoryAccess = MSSAU.createMemoryAccessInBB( + PreheaderLoad, nullptr, PreheaderLoad->getParent(), MemorySSA::End); + MemoryUse *NewMemUse = cast(PreheaderLoadMemoryAccess); + MSSAU.insertUse(NewMemUse, /*RenameUses=*/true); + SSA.AddAvailableValue(Preheader, PreheaderLoad); + } else { + SSA.AddAvailableValue(Preheader, PoisonValue::get(AccessTy)); + } if (VerifyMemorySSA) MSSAU.getMemorySSA()->verifyMemorySSA(); @@ -2181,7 +2201,7 @@ if (VerifyMemorySSA) MSSAU.getMemorySSA()->verifyMemorySSA(); // If the SSAUpdater didn't use the load in the preheader, just zap it now. - if (PreheaderLoad->use_empty()) + if (PreheaderLoad && PreheaderLoad->use_empty()) eraseInstruction(*PreheaderLoad, *SafetyInfo, MSSAU); return true; diff --git a/llvm/test/Transforms/LICM/scalar-promote.ll b/llvm/test/Transforms/LICM/scalar-promote.ll --- a/llvm/test/Transforms/LICM/scalar-promote.ll +++ b/llvm/test/Transforms/LICM/scalar-promote.ll @@ -606,10 +606,9 @@ ; CHECK: Function Attrs: writeonly ; CHECK-LABEL: @test_sink_store_only( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[GLB_PROMOTED:%.*]] = load i8, i8* @glb, align 1 ; CHECK-NEXT: br label [[LOOP_HEADER:%.*]] ; CHECK: loop.header: -; CHECK-NEXT: [[DIV1:%.*]] = phi i8 [ [[GLB_PROMOTED]], [[ENTRY:%.*]] ], [ [[DIV:%.*]], [[LOOP_LATCH:%.*]] ] +; CHECK-NEXT: [[DIV1:%.*]] = phi i8 [ poison, [[ENTRY:%.*]] ], [ [[DIV:%.*]], [[LOOP_LATCH:%.*]] ] ; CHECK-NEXT: [[I:%.*]] = phi i8 [ 0, [[ENTRY]] ], [ [[ADD:%.*]], [[LOOP_LATCH]] ] ; CHECK-NEXT: [[CMP:%.*]] = icmp ult i8 [[I]], 4 ; CHECK-NEXT: br i1 [[CMP]], label [[LOOP_LATCH]], label [[EXIT:%.*]] @@ -645,10 +644,9 @@ ; CHECK-LABEL: @test_sink_store_to_local_object_only_loop_must_execute( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[A:%.*]] = alloca i8, align 1 -; CHECK-NEXT: [[A_PROMOTED:%.*]] = load i8, i8* [[A]], align 1 ; CHECK-NEXT: br label [[LOOP_HEADER:%.*]] ; CHECK: loop.header: -; CHECK-NEXT: [[DIV1:%.*]] = phi i8 [ [[A_PROMOTED]], [[ENTRY:%.*]] ], [ [[DIV:%.*]], [[LOOP_LATCH:%.*]] ] +; CHECK-NEXT: [[DIV1:%.*]] = phi i8 [ poison, [[ENTRY:%.*]] ], [ [[DIV:%.*]], [[LOOP_LATCH:%.*]] ] ; CHECK-NEXT: [[I:%.*]] = phi i8 [ 0, [[ENTRY]] ], [ [[ADD:%.*]], [[LOOP_LATCH]] ] ; CHECK-NEXT: [[CMP:%.*]] = icmp ult i8 [[I]], 4 ; CHECK-NEXT: br i1 [[CMP]], label [[LOOP_LATCH]], label [[EXIT:%.*]] @@ -804,17 +802,16 @@ ; CHECK: loop.2.header: ; CHECK-NEXT: br i1 false, label [[LOOP_3_HEADER_PREHEADER:%.*]], label [[LOOP_1_LATCH:%.*]] ; CHECK: loop.3.header.preheader: -; CHECK-NEXT: [[PTR_PROMOTED:%.*]] = load i32, i32* [[PTR:%.*]], align 4 ; CHECK-NEXT: br label [[LOOP_3_HEADER:%.*]] ; CHECK: loop.3.header: -; CHECK-NEXT: [[I_11:%.*]] = phi i32 [ [[I_1:%.*]], [[LOOP_3_LATCH:%.*]] ], [ [[PTR_PROMOTED]], [[LOOP_3_HEADER_PREHEADER]] ] +; CHECK-NEXT: [[I_11:%.*]] = phi i32 [ [[I_1:%.*]], [[LOOP_3_LATCH:%.*]] ], [ poison, [[LOOP_3_HEADER_PREHEADER]] ] ; CHECK-NEXT: [[I_1]] = phi i32 [ 1, [[LOOP_3_LATCH]] ], [ 0, [[LOOP_3_HEADER_PREHEADER]] ] ; CHECK-NEXT: br i1 true, label [[LOOP_3_LATCH]], label [[LOOP_2_LATCH:%.*]] ; CHECK: loop.3.latch: ; CHECK-NEXT: br label [[LOOP_3_HEADER]] ; CHECK: loop.2.latch: ; CHECK-NEXT: [[I_11_LCSSA:%.*]] = phi i32 [ [[I_11]], [[LOOP_3_HEADER]] ] -; CHECK-NEXT: store i32 [[I_11_LCSSA]], i32* [[PTR]], align 4 +; CHECK-NEXT: store i32 [[I_11_LCSSA]], i32* [[PTR:%.*]], align 4 ; CHECK-NEXT: br label [[LOOP_2_HEADER]] ; CHECK: loop.1.latch: ; CHECK-NEXT: br i1 [[C:%.*]], label [[LOOP_1_HEADER]], label [[EXIT:%.*]]