diff --git a/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp b/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp --- a/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp +++ b/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp @@ -32,7 +32,6 @@ #include "llvm/Analysis/MemoryLocation.h" #include "llvm/Analysis/MemorySSA.h" #include "llvm/Analysis/MemorySSAUpdater.h" -#include "llvm/Analysis/PostDominators.h" #include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/Analysis/ValueTracking.h" #include "llvm/IR/Argument.h" @@ -1475,7 +1474,6 @@ AliasAnalysis &AA; MemorySSA &MSSA; DominatorTree &DT; - PostDominatorTree &PDT; const TargetLibraryInfo &TLI; // All MemoryDefs that potentially could kill other MemDefs. @@ -1490,33 +1488,43 @@ // Post-order numbers for each basic block. Used to figure out if memory // accesses are executed before another access. DenseMap PostOrderNumbers; + // Set of the last MemoryDefs or MemoryPhis before a function exit, that is + // defs or phis without any users that are defs or phis. + SmallPtrSet LastDefOrPhi; /// Keep track of instructions (partly) overlapping with killing MemoryDefs per /// basic block. DenseMap IOLs; DSEState(Function &F, AliasAnalysis &AA, MemorySSA &MSSA, DominatorTree &DT, - PostDominatorTree &PDT, const TargetLibraryInfo &TLI) - : F(F), AA(AA), MSSA(MSSA), DT(DT), PDT(PDT), TLI(TLI) {} + const TargetLibraryInfo &TLI) + : F(F), AA(AA), MSSA(MSSA), DT(DT), TLI(TLI) {} static DSEState get(Function &F, AliasAnalysis &AA, MemorySSA &MSSA, - DominatorTree &DT, PostDominatorTree &PDT, - const TargetLibraryInfo &TLI) { - DSEState State(F, AA, MSSA, DT, PDT, TLI); + DominatorTree &DT, const TargetLibraryInfo &TLI) { + DSEState State(F, AA, MSSA, DT, TLI); + // Collect blocks with throwing instructions not modeled in MemorySSA and // alloc-like objects. unsigned PO = 0; for (BasicBlock *BB : post_order(&F)) { State.PostOrderNumbers[BB] = PO++; for (Instruction &I : *BB) { - if (I.mayThrow() && !MSSA.getMemoryAccess(&I)) + MemoryAccess *MA = MSSA.getMemoryAccess(&I); + if (I.mayThrow() && !MA) State.ThrowingBlocks.insert(I.getParent()); - auto *MD = dyn_cast_or_null(MSSA.getMemoryAccess(&I)); + auto *MD = dyn_cast_or_null(MA); if (MD && State.MemDefs.size() < MemorySSADefsPerBlockLimit && hasAnalyzableMemoryWrite(&I, TLI) && isRemovable(&I)) State.MemDefs.push_back(MD); + if (MA && (MD || isa(MA)) && !any_of(MA->uses(), [](Use &U) { + User *Acc = U.getUser(); + return isa(Acc) || isa(Acc); + })) + State.LastDefOrPhi.insert(MA); + // Track alloca and alloca-like objects. Here we care about objects not // visible to the caller during function execution. Alloca objects are // invalid in the caller, for alloca-like objects we ensure that they @@ -1561,7 +1569,7 @@ } /// Returns true if \p Use completely overwrites \p DefLoc. - bool isCompleteOverwrite(MemoryLocation DefLoc, Instruction *UseInst) const { + bool isMustWriteClobber(MemoryLocation DefLoc, Instruction *UseInst) const { // UseInst has a MemoryDef associated in MemorySSA. It's possible for a // MemoryDef to not write to memory, e.g. a volatile load is modeled as a // MemoryDef. @@ -1573,13 +1581,18 @@ return false; ModRefInfo MR = AA.getModRefInfo(UseInst, DefLoc); - // If necessary, perform additional analysis. - if (isModSet(MR)) - MR = AA.callCapturesBefore(UseInst, DefLoc, &DT); - Optional UseLoc = getLocForWriteEx(UseInst); return isModSet(MR) && isMustSet(MR) && - UseLoc->Size.getValue() >= DefLoc.Size.getValue(); + (UseLoc->Size.hasValue() && DefLoc.Size.hasValue() && + UseLoc->Size.getValue() >= DefLoc.Size.getValue()); + } + + bool isAccessibleAfterReturn(MemoryLocation Loc) const { + DataLayout DL = F.getParent()->getDataLayout(); + const Value *UO = GetUnderlyingObject(Loc.Ptr, DL); + /// Maybe pre-compute + return !UO || InvisibleToCaller.find(UO) == InvisibleToCaller.end() || + (!isa(UO) && PointerMayBeCaptured(UO, true, false)); } /// Returns true if \p Use may read from \p DefLoc. @@ -1587,9 +1600,10 @@ if (!UseInst->mayReadFromMemory()) return false; - if (auto CS = CallSite(UseInst)) + if (auto CS = CallSite(UseInst)) { if (CS.onlyAccessesInaccessibleMemory()) return false; + } ModRefInfo MR = AA.getModRefInfo(UseInst, DefLoc); // If necessary, perform additional analysis. @@ -1599,7 +1613,8 @@ } // Find a MemoryDef writing to \p DefLoc and dominating \p Current, with no - // read access in between or return None otherwise. The returned value may not + // read access between them or on any other path to a function exit block. If + // there is no such MemoryDef, return None. The returned value may not // (completely) overwrite \p DefLoc. Currently we bail out when we encounter // an aliasing MemoryUse (read). Optional getDomMemoryDef(MemoryDef *KillingDef, @@ -1632,12 +1647,9 @@ if (isa(DomAccess)) break; - // Check if we can skip DomDef for DSE. We also require the KillingDef - // execute whenever DomDef executes and use post-dominance to ensure that. - + // Check if we can skip DomDef for DSE. MemoryDef *DomDef = dyn_cast(DomAccess); - if ((DomDef && canSkipDef(DomDef, DefVisibleToCaller)) || - !PDT.dominates(KillingDef->getBlock(), DomDef->getBlock())) { + if ((DomDef && canSkipDef(DomDef, DefVisibleToCaller))) { StepAgain = true; Current = DomDef->getDefiningAccess(); } @@ -1657,6 +1669,8 @@ }; PushMemUses(DomAccess); + // TODO: Ideally we only compute it once, but only when required. + bool AccessibleAfterReturn = isAccessibleAfterReturn(DefLoc); // Check if DomDef may be read. for (unsigned I = 0; I < WorkList.size(); I++) { MemoryAccess *UseAccess = WorkList[I]; @@ -1668,6 +1682,12 @@ } if (isa(UseAccess)) { + if (LastDefOrPhi.find(UseAccess) != LastDefOrPhi.end() && + AccessibleAfterReturn) { + LLVM_DEBUG(dbgs() << " ... object accessible after return is not " + "overwritten on a path to a function exit\n"); + return None; + } PushMemUses(UseAccess); continue; } @@ -1705,8 +1725,26 @@ // 3 = Def(1) ; <---- Current (3, 2) = NoAlias, (3,1) = MayAlias, // stores [0,1] if (MemoryDef *UseDef = dyn_cast(UseAccess)) { - if (!isCompleteOverwrite(DefLoc, UseInst)) + int64_t InstWriteOffset, DepWriteOffset; + auto CC = getLocForWriteEx(UseInst); + InstOverlapIntervalsTy IOL; + + const DataLayout &DL = F.getParent()->getDataLayout(); + + if (!isMustWriteClobber(DefLoc, UseInst) || + (CC && + isOverwrite(DefLoc, *CC, DL, TLI, DepWriteOffset, InstWriteOffset, + UseInst, IOL, AA, &F) != OW_Complete)) { + LLVM_DEBUG(dbgs() << " ... found non-aliasing MemoryDef\n"); + if (LastDefOrPhi.find(UseAccess) != LastDefOrPhi.end() && + AccessibleAfterReturn) { + LLVM_DEBUG(dbgs() << " ... object accessible after return is not " + "overwritten on a path to a function exit\n"); + return None; + } + PushMemUses(UseDef); + } } } @@ -1795,12 +1833,11 @@ bool eliminateDeadStoresMemorySSA(Function &F, AliasAnalysis &AA, MemorySSA &MSSA, DominatorTree &DT, - PostDominatorTree &PDT, const TargetLibraryInfo &TLI) { const DataLayout &DL = F.getParent()->getDataLayout(); bool MadeChange = false; - DSEState State = DSEState::get(F, AA, MSSA, DT, PDT, TLI); + DSEState State = DSEState::get(F, AA, MSSA, DT, TLI); // For each store: for (unsigned I = 0; I < State.MemDefs.size(); I++) { MemoryDef *KillingDef = State.MemDefs[I]; @@ -1933,9 +1970,7 @@ if (EnableMemorySSA) { MemorySSA &MSSA = AM.getResult(F).getMSSA(); - PostDominatorTree &PDT = AM.getResult(F); - - if (!eliminateDeadStoresMemorySSA(F, AA, MSSA, DT, PDT, TLI)) + if (!eliminateDeadStoresMemorySSA(F, AA, MSSA, DT, TLI)) return PreservedAnalyses::all(); } else { MemoryDependenceResults &MD = AM.getResult(F); @@ -1976,10 +2011,7 @@ if (EnableMemorySSA) { MemorySSA &MSSA = getAnalysis().getMSSA(); - PostDominatorTree &PDT = - getAnalysis().getPostDomTree(); - - return eliminateDeadStoresMemorySSA(F, AA, MSSA, DT, PDT, TLI); + return eliminateDeadStoresMemorySSA(F, AA, MSSA, DT, TLI); } else { MemoryDependenceResults &MD = getAnalysis().getMemDep(); @@ -1997,9 +2029,7 @@ AU.addPreserved(); if (EnableMemorySSA) { - AU.addRequired(); AU.addRequired(); - AU.addPreserved(); AU.addPreserved(); } else { AU.addRequired(); @@ -2015,7 +2045,6 @@ INITIALIZE_PASS_BEGIN(DSELegacyPass, "dse", "Dead Store Elimination", false, false) INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass) -INITIALIZE_PASS_DEPENDENCY(PostDominatorTreeWrapperPass) INITIALIZE_PASS_DEPENDENCY(AAResultsWrapperPass) INITIALIZE_PASS_DEPENDENCY(GlobalsAAWrapperPass) INITIALIZE_PASS_DEPENDENCY(MemorySSAWrapperPass) diff --git a/llvm/test/Transforms/DeadStoreElimination/MSSA/memset-missing-debugloc.ll b/llvm/test/Transforms/DeadStoreElimination/MSSA/memset-missing-debugloc.ll --- a/llvm/test/Transforms/DeadStoreElimination/MSSA/memset-missing-debugloc.ll +++ b/llvm/test/Transforms/DeadStoreElimination/MSSA/memset-missing-debugloc.ll @@ -21,10 +21,9 @@ ; } -define dso_local i32 @_Z1av() !dbg !7 { +define dso_local i32 @_Z1av([5 x i64]* %b) !dbg !7 { entry: %retval = alloca i32, align 4 - %b = alloca [5 x i64], align 16 call void @llvm.dbg.declare(metadata [5 x i64]* %b, metadata !11, metadata !DIExpression()), !dbg !16 %0 = bitcast [5 x i64]* %b to i8*, !dbg !16 call void @llvm.memset.p0i8.i64(i8* align 16 %0, i8 0, i64 40, i1 false), !dbg !16 @@ -37,7 +36,7 @@ store i64 2, i64* %4, align 16, !dbg !16 %5 = getelementptr inbounds [5 x i64], [5 x i64]* %1, i32 0, i32 3, !dbg !16 store i64 2, i64* %5, align 8, !dbg !16 - %call = call i32 @_Z1av(), !dbg !17 + %call = call i32 @_Z1av([5 x i64]* %b), !dbg !17 %tobool = icmp ne i32 %call, 0, !dbg !17 br i1 %tobool, label %if.then, label %if.end, !dbg !19 diff --git a/llvm/test/Transforms/DeadStoreElimination/MSSA/memset-unknown-sizes.ll b/llvm/test/Transforms/DeadStoreElimination/MSSA/memset-unknown-sizes.ll --- a/llvm/test/Transforms/DeadStoreElimination/MSSA/memset-unknown-sizes.ll +++ b/llvm/test/Transforms/DeadStoreElimination/MSSA/memset-unknown-sizes.ll @@ -13,7 +13,7 @@ ; CHECK: cond.true.i.i.i: ; CHECK-NEXT: ret void ; CHECK: cond.end.i.i.i: -; CHECK-NEXT: [[CALL_I_I_I_I_I:%.*]] = tail call noalias nonnull i8* @_Znam() #2 +; CHECK-NEXT: [[CALL_I_I_I_I_I:%.*]] = tail call noalias nonnull i8* @_Znam() ; CHECK-NEXT: [[TMP0:%.*]] = bitcast i8* [[CALL_I_I_I_I_I]] to i64* ; CHECK-NEXT: tail call void @llvm.memset.p0i8.i64(i8* nonnull align 8 [[CALL_I_I_I_I_I]], i8 0, i64 undef, i1 false) ; CHECK-NEXT: store i64 0, i64* [[TMP0]], align 8 @@ -42,7 +42,7 @@ ; CHECK-NEXT: br i1 [[C:%.*]], label [[CLEANUP_CONT104:%.*]], label [[IF_THEN:%.*]] ; CHECK: if.then: ; CHECK-NEXT: [[MUL_I_I_I_I:%.*]] = shl nuw nsw i64 undef, 3 -; CHECK-NEXT: [[CALL_I_I_I_I_I_I131:%.*]] = call noalias nonnull i8* @_Znwm() #2 +; CHECK-NEXT: [[CALL_I_I_I_I_I_I131:%.*]] = call noalias nonnull i8* @_Znwm() ; CHECK-NEXT: [[DOTCAST_I_I:%.*]] = bitcast i8* [[CALL_I_I_I_I_I_I131]] to i64* ; CHECK-NEXT: store i64 0, i64* [[DOTCAST_I_I]], align 8 ; CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* nonnull align 8 [[CALL_I_I_I_I_I_I131]], i8 0, i64 [[MUL_I_I_I_I]], i1 false) diff --git a/llvm/test/Transforms/DeadStoreElimination/MSSA/multiblock-malloc-free.ll b/llvm/test/Transforms/DeadStoreElimination/MSSA/multiblock-malloc-free.ll --- a/llvm/test/Transforms/DeadStoreElimination/MSSA/multiblock-malloc-free.ll +++ b/llvm/test/Transforms/DeadStoreElimination/MSSA/multiblock-malloc-free.ll @@ -1,8 +1,5 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; XFAIL: * -; TODO: Handling of free not implemented yet. - ; RUN: opt < %s -basicaa -dse -enable-dse-memoryssa -S | FileCheck %s target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64" @@ -95,7 +92,8 @@ ; CHECK-NEXT: entry: ; CHECK-NEXT: [[ARRAYIDX0:%.*]] = getelementptr inbounds i32, i32* [[P:%.*]], i64 1 ; CHECK-NEXT: [[P3:%.*]] = bitcast i32* [[ARRAYIDX0]] to i8* -; CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* align 4 [[P3]], i8 0, i64 28, i1 false) +; CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds i8, i8* [[P3]], i64 4 +; CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* align 4 [[TMP0]], i8 0, i64 24, i1 false) ; CHECK-NEXT: br i1 true, label [[BB1:%.*]], label [[BB2:%.*]] ; CHECK: bb1: ; CHECK-NEXT: br label [[BB3:%.*]] @@ -308,7 +306,7 @@ define noalias %struct.SystemCallMapElementStruct* @SystemCallMapElement_new(i8* nocapture readonly %label, i32 %initialSize) { ; CHECK-LABEL: @SystemCallMapElement_new( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[CALL:%.*]] = tail call dereferenceable_or_null(24) i8* @malloc(i64 24) #7 +; CHECK-NEXT: [[CALL:%.*]] = tail call dereferenceable_or_null(24) i8* @malloc(i64 24) #6 ; CHECK-NEXT: [[TMP0:%.*]] = bitcast i8* [[CALL]] to %struct.SystemCallMapElementStruct* ; CHECK-NEXT: [[TOBOOL:%.*]] = icmp eq i8* [[CALL]], null ; CHECK-NEXT: br i1 [[TOBOOL]], label [[CLEANUP:%.*]], label [[IF_THEN:%.*]] @@ -380,7 +378,7 @@ define noalias %struct.BitfieldStruct* @Bitfield_new(i32 %bitsNeeded) { ; CHECK-LABEL: @Bitfield_new( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[CALL:%.*]] = tail call dereferenceable_or_null(16) i8* @malloc(i64 16) #7 +; CHECK-NEXT: [[CALL:%.*]] = tail call dereferenceable_or_null(16) i8* @malloc(i64 16) #6 ; CHECK-NEXT: [[TMP0:%.*]] = bitcast i8* [[CALL]] to %struct.BitfieldStruct* ; CHECK-NEXT: [[TOBOOL:%.*]] = icmp eq i8* [[CALL]], null ; CHECK-NEXT: br i1 [[TOBOOL]], label [[CLEANUP:%.*]], label [[IF_END:%.*]] @@ -388,7 +386,7 @@ ; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[BITSNEEDED:%.*]], 7 ; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[ADD]], 8 ; CHECK-NEXT: [[CONV:%.*]] = sext i32 [[DIV]] to i64 -; CHECK-NEXT: [[CALL1:%.*]] = tail call i8* @calloc(i64 [[CONV]], i64 1) #8 +; CHECK-NEXT: [[CALL1:%.*]] = tail call i8* @calloc(i64 [[CONV]], i64 1) #7 ; CHECK-NEXT: [[BITFIELD:%.*]] = getelementptr inbounds i8, i8* [[CALL]], i64 8 ; CHECK-NEXT: [[TMP1:%.*]] = bitcast i8* [[BITFIELD]] to i8** ; CHECK-NEXT: store i8* [[CALL1]], i8** [[TMP1]], align 8 diff --git a/llvm/test/Transforms/DeadStoreElimination/MSSA/multiblock-memintrinsics.ll b/llvm/test/Transforms/DeadStoreElimination/MSSA/multiblock-memintrinsics.ll --- a/llvm/test/Transforms/DeadStoreElimination/MSSA/multiblock-memintrinsics.ll +++ b/llvm/test/Transforms/DeadStoreElimination/MSSA/multiblock-memintrinsics.ll @@ -11,7 +11,8 @@ ; CHECK-NEXT: entry: ; CHECK-NEXT: [[ARRAYIDX0:%.*]] = getelementptr inbounds i32, i32* [[P:%.*]], i64 1 ; CHECK-NEXT: [[P3:%.*]] = bitcast i32* [[ARRAYIDX0]] to i8* -; CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* align 4 [[P3]], i8 0, i64 28, i1 false) +; CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds i8, i8* [[P3]], i64 4 +; CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* align 4 [[TMP0]], i8 0, i64 24, i1 false) ; CHECK-NEXT: br i1 true, label [[BB1:%.*]], label [[BB2:%.*]] ; CHECK: bb1: ; CHECK-NEXT: br label [[BB3:%.*]] diff --git a/llvm/test/Transforms/DeadStoreElimination/MSSA/multiblock-multipath.ll b/llvm/test/Transforms/DeadStoreElimination/MSSA/multiblock-multipath.ll --- a/llvm/test/Transforms/DeadStoreElimination/MSSA/multiblock-multipath.ll +++ b/llvm/test/Transforms/DeadStoreElimination/MSSA/multiblock-multipath.ll @@ -7,10 +7,9 @@ define void @test4(i32* noalias %P, i1 %c1) { ; CHECK-LABEL: @test4( -; CHECK-NEXT: store i32 1, i32* [[P:%.*]] ; CHECK-NEXT: br i1 [[C1:%.*]], label [[BB1:%.*]], label [[BB2:%.*]] ; CHECK: bb1: -; CHECK-NEXT: store i32 0, i32* [[P]] +; CHECK-NEXT: store i32 0, i32* [[P:%.*]] ; CHECK-NEXT: br label [[BB5:%.*]] ; CHECK: bb2: ; CHECK-NEXT: store i32 3, i32* [[P]] @@ -36,10 +35,9 @@ define void @test5(i32* noalias %P) { ; CHECK-LABEL: @test5( -; CHECK-NEXT: store i32 1, i32* [[P:%.*]] ; CHECK-NEXT: br i1 true, label [[BB1:%.*]], label [[BB2:%.*]] ; CHECK: bb1: -; CHECK-NEXT: store i32 0, i32* [[P]] +; CHECK-NEXT: store i32 0, i32* [[P:%.*]] ; CHECK-NEXT: br label [[BB5:%.*]] ; CHECK: bb2: ; CHECK-NEXT: br i1 undef, label [[BB3:%.*]], label [[BB4:%.*]] diff --git a/llvm/test/Transforms/DeadStoreElimination/MSSA/multiblock-simple.ll b/llvm/test/Transforms/DeadStoreElimination/MSSA/multiblock-simple.ll --- a/llvm/test/Transforms/DeadStoreElimination/MSSA/multiblock-simple.ll +++ b/llvm/test/Transforms/DeadStoreElimination/MSSA/multiblock-simple.ll @@ -28,12 +28,11 @@ define void @test3(i32* noalias %P) { ; CHECK-LABEL: @test3( -; CHECK-NEXT: store i32 0, i32* [[P:%.*]] ; CHECK-NEXT: br i1 true, label [[BB1:%.*]], label [[BB2:%.*]] ; CHECK: bb1: ; CHECK-NEXT: br label [[BB3:%.*]] ; CHECK: bb2: -; CHECK-NEXT: store i32 0, i32* [[P]] +; CHECK-NEXT: store i32 0, i32* [[P:%.*]] ; CHECK-NEXT: br label [[BB3]] ; CHECK: bb3: ; CHECK-NEXT: ret void @@ -92,14 +91,13 @@ define void @test9(i32* noalias %P) { ; CHECK-LABEL: @test9( -; CHECK-NEXT: store i32 0, i32* [[P:%.*]] ; CHECK-NEXT: br i1 true, label [[BB1:%.*]], label [[BB2:%.*]] ; CHECK: bb1: ; CHECK-NEXT: br label [[BB3:%.*]] ; CHECK: bb2: ; CHECK-NEXT: ret void ; CHECK: bb3: -; CHECK-NEXT: store i32 0, i32* [[P]] +; CHECK-NEXT: store i32 0, i32* [[P:%.*]] ; CHECK-NEXT: ret void ; store i32 0, i32* %P @@ -150,10 +148,9 @@ define void @test10(i32* %P) { ; CHECK-LABEL: @test10( -; CHECK-NEXT: store i32 0, i32* [[P:%.*]] ; CHECK-NEXT: br i1 true, label [[BB1:%.*]], label [[BB2:%.*]] ; CHECK: bb1: -; CHECK-NEXT: store i32 0, i32* [[P]] +; CHECK-NEXT: store i32 0, i32* [[P:%.*]] ; CHECK-NEXT: br label [[BB3:%.*]] ; CHECK: bb2: ; CHECK-NEXT: ret void @@ -175,7 +172,6 @@ define void @test11() { ; CHECK-LABEL: @test11( ; CHECK-NEXT: [[P:%.*]] = alloca i32 -; CHECK-NEXT: store i32 0, i32* [[P]] ; CHECK-NEXT: br i1 true, label [[BB1:%.*]], label [[BB2:%.*]] ; CHECK: bb1: ; CHECK-NEXT: store i32 0, i32* [[P]] @@ -200,10 +196,9 @@ define void @test12(i32* %P) { ; CHECK-LABEL: @test12( -; CHECK-NEXT: store i32 0, i32* [[P:%.*]] ; CHECK-NEXT: br i1 true, label [[BB1:%.*]], label [[BB2:%.*]] ; CHECK: bb1: -; CHECK-NEXT: store i32 1, i32* [[P]] +; CHECK-NEXT: store i32 1, i32* [[P:%.*]] ; CHECK-NEXT: br label [[BB3:%.*]] ; CHECK: bb2: ; CHECK-NEXT: store i32 1, i32* [[P]] @@ -226,10 +221,9 @@ define void @test13(i32* %P) { ; CHECK-LABEL: @test13( -; CHECK-NEXT: store i32 0, i32* [[P:%.*]] ; CHECK-NEXT: br i1 true, label [[BB1:%.*]], label [[BB2:%.*]] ; CHECK: bb1: -; CHECK-NEXT: store i32 1, i32* [[P]] +; CHECK-NEXT: store i32 1, i32* [[P:%.*]] ; CHECK-NEXT: br label [[BB3:%.*]] ; CHECK: bb2: ; CHECK-NEXT: store i32 1, i32* [[P]]