/// 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
-/// 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,
+/// return false. This is necessary in cases where, due to control flow, the
+/// alloca is undefined only on some control flow paths. e.g. code like
+/// this is correct in LLVM IR:
+/// // A is an alloca with no stores so far
+/// for (...) {
+/// int t = *A;
+/// if (!first_iteration)
+/// use(t);
+/// *A = 42;
+/// }
+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,
std::make_pair(LoadIdx,
static_cast<StoreInst *>(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()));
+ if (I == StoresByIndex.begin()) {
+ if (StoresByIndex.empty())
+ // If there are no stores, the load takes the undef value.
+ LI->replaceAllUsesWith(UndefValue::get(LI->getType()));
+ else
+ // 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));
}
++NumLocalPromoted;
+ return true;
}
void PromoteMem2Reg::run() {
// 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);
-
+ if (Info.OnlyUsedInOneBlock &&
+ promoteSingleBlockAlloca(AI, Info, LBI, AST)) {
// The alloca has been processed, move on.
RemoveFromAllocasList(AllocaNum);
continue;
--- /dev/null
+; 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
+}