Index: lib/Transforms/Utils/PromoteMemoryToRegister.cpp =================================================================== --- lib/Transforms/Utils/PromoteMemoryToRegister.cpp +++ lib/Transforms/Utils/PromoteMemoryToRegister.cpp @@ -425,14 +425,14 @@ /// using the Alloca. /// /// If we cannot promote this alloca (because it is read before it is written), -/// return true. This is necessary in cases where, due to control flow, the +/// return false. This is necessary in cases where, due to control flow, the /// alloca is potentially undefined on some control flow paths. e.g. code like /// this is potentially correct: /// /// for (...) { if (c) { A = undef; undef = B; } } /// /// ... so long as A is not used before undef is set. -static void promoteSingleBlockAlloca(AllocaInst *AI, const AllocaInfo &Info, +static bool promoteSingleBlockAlloca(AllocaInst *AI, const AllocaInfo &Info, LargeBlockInfo &LBI, AliasSetTracker *AST) { // The trickiest case to handle is when we have large blocks. Because of this, @@ -462,18 +462,25 @@ unsigned LoadIdx = LBI.getInstructionIndex(LI); // Find the nearest store that has a lower index than this load. - StoresByIndexTy::iterator I = + if (StoresByIndex.empty()) + // If there are no stores, the load takes the undef value. + LI->replaceAllUsesWith(UndefValue::get(LI->getType())); + else { + StoresByIndexTy::iterator I = std::lower_bound(StoresByIndex.begin(), StoresByIndex.end(), std::make_pair(LoadIdx, static_cast(nullptr)), less_first()); - if (I == StoresByIndex.begin()) - // If there is no store before this load, the load takes the undef value. - LI->replaceAllUsesWith(UndefValue::get(LI->getType())); - else - // Otherwise, there was a store before this load, the load takes its value. - LI->replaceAllUsesWith(std::prev(I)->second->getOperand(0)); + if (I == StoresByIndex.begin()) + // If there is no store before this load, bail out (load may be affected + // by the following stores - see main comment). + return false; + else + // Otherwise, there was a store before this load, the load takes its + // value. + LI->replaceAllUsesWith(std::prev(I)->second->getOperand(0)); + } if (AST && LI->getType()->isPointerTy()) AST->deleteValue(LI); @@ -506,6 +513,7 @@ } ++NumLocalPromoted; + return true; } void PromoteMem2Reg::run() { @@ -558,11 +566,11 @@ // If the alloca is only read and written in one basic block, just perform a // linear sweep over the block to eliminate it. if (Info.OnlyUsedInOneBlock) { - promoteSingleBlockAlloca(AI, Info, LBI, AST); - - // The alloca has been processed, move on. - RemoveFromAllocasList(AllocaNum); - continue; + if (promoteSingleBlockAlloca(AI, Info, LBI, AST)) { + // The alloca has been processed, move on. + RemoveFromAllocasList(AllocaNum); + continue; + } } // If we haven't computed a numbering for the BB's in the function, do so Index: test/Transforms/Mem2Reg/pr24179.ll =================================================================== --- test/Transforms/Mem2Reg/pr24179.ll +++ test/Transforms/Mem2Reg/pr24179.ll @@ -0,0 +1,44 @@ +; RUN: opt -mem2reg < %s -S | FileCheck %s + +declare i32 @def(i32) +declare i1 @use(i32) + +; Special case of a single-BB alloca does not apply here since the load +; is affected by the following store. Expect this case to be identified +; and a PHI node to be created. +define void @test1() { +; CHECK-LABEL: @test1( + entry: + %t = alloca i32 + br label %loop + + loop: + %v = load i32, i32* %t + %c = call i1 @use(i32 %v) +; CHECK: [[PHI:%.*]] = phi i32 [ undef, %entry ], [ %n, %loop ] +; CHECK: call i1 @use(i32 [[PHI]]) + %n = call i32 @def(i32 7) + store i32 %n, i32* %t + br i1 %c, label %loop, label %exit + + exit: + ret void +} + +; Same as above, except there is no following store. The alloca should just be +; replaced with an undef +define void @test2() { +; CHECK-LABEL: @test2( + entry: + %t = alloca i32 + br label %loop + + loop: + %v = load i32, i32* %t + %c = call i1 @use(i32 %v) +; CHECK: %c = call i1 @use(i32 undef) + br i1 %c, label %loop, label %exit + + exit: + ret void +}