From: Daniil Suchkov Date: Thu, 14 Nov 2019 08:25:31 +0000 (+0700) Subject: [InstCombine] Fold PHIs with equal incoming pointers X-Git-Tag: llvmorg-11-init~4301 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=a2f6ae9abffcba260c22bb235879f0576bf3b783;p=platform%2Fupstream%2Fllvm.git [InstCombine] Fold PHIs with equal incoming pointers This is a resubmission of bbb29738b58aaf6f6518269abdcf8f64131665a9 that was reverted due to clang tests failures. It includes the fix and additional IR tests for the missed case. Summary: In case when all incoming values of a PHI are equal pointers, this transformation inserts a definition of such a pointer right after definition of the base pointer and replaces with this value both PHI and all it's incoming pointers. Primary goal of this transformation is canonicalization of this pattern in order to enable optimizations that can't handle PHIs. Non-inbounds pointers aren't currently supported. Reviewers: spatel, RKSimon, lebedev.ri, apilipenko Reviewed By: apilipenko Tags: #llvm Subscribers: hiraditya, llvm-commits Differential Revision: https://reviews.llvm.org/D68128 --- diff --git a/llvm/lib/Transforms/InstCombine/InstCombineInternal.h b/llvm/lib/Transforms/InstCombine/InstCombineInternal.h index 524f9313d8c4..52aeb787aaf9 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineInternal.h +++ b/llvm/lib/Transforms/InstCombine/InstCombineInternal.h @@ -895,6 +895,11 @@ private: /// insert a new pointer typed PHI and replace the original one. Instruction *FoldIntegerTypedPHI(PHINode &PN); + /// If all incoming values of a pointer typed PHI are pointers with the same + /// base and offset, replace the PHI and all incoming values with one + /// definition of such pointer. + Instruction *FoldPHIWithEqualPointers(PHINode &PN); + /// Helper function for FoldPHIArgXIntoPHI() to set debug location for the /// folded operation. void PHIArgMergedDebugLoc(Instruction *Inst, PHINode &PN); diff --git a/llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp b/llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp index e0376b7582f3..d1035414560b 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp @@ -1122,6 +1122,68 @@ Instruction *InstCombiner::SliceUpIllegalIntegerPHI(PHINode &FirstPhi) { return replaceInstUsesWith(FirstPhi, Undef); } +Instruction *InstCombiner::FoldPHIWithEqualPointers(PHINode &PN) { + auto *PhiTy = dyn_cast(PN.getType()); + if (!PhiTy) + return nullptr; + + // Make sure all incoming pointers have the same base pointers and offsets. + // Also, make sure no addrspacecasts involved. + // Note: only inbounds GEPs are supported! + const DataLayout &DL = PN.getModule()->getDataLayout(); + Value *FirstValue = PN.getIncomingValue(0); + int64_t Offset; + Value *Base = GetPointerBaseWithConstantOffset( + FirstValue, Offset, DL, /* AllowNonInbounds */ false); + + auto *BaseTy = cast(Base->getType()); + if (BaseTy->getAddressSpace() != PhiTy->getAddressSpace()) + return nullptr; + + for (Use &Incoming : PN.incoming_values()) { + if (!isa(Incoming)) + return nullptr; + int64_t CurrentOffset; + Value *CurrentBase = GetPointerBaseWithConstantOffset( + Incoming, CurrentOffset, DL, /* AllowNonInbounds */ false); + if (CurrentBase != Base || CurrentOffset != Offset) + return nullptr; + } + + Instruction *InsertPt = nullptr; + if (auto *BaseInst = dyn_cast(Base)) { + if (isa(BaseInst)) { + BasicBlock *InsertBB = BaseInst->getParent(); + BasicBlock::iterator InsertPtIter = InsertBB->getFirstInsertionPt(); + // Make sure the insertion point exists. At the moment the only reason why + // insertion point may not exist is EHPad being a terminator. This check + // is a bit more future-proof than just `if (!TI->isEHPad())`. + if (InsertPtIter != InsertBB->end()) + InsertPt = &*InsertPtIter; + } else + InsertPt = BaseInst->getNextNode(); + } else + InsertPt = &*PN.getFunction()->getEntryBlock().getFirstInsertionPt(); + + if (!InsertPt) + return nullptr; + + Builder.SetInsertPoint(InsertPt); + Type *I8PtrTy = Builder.getInt8PtrTy(PhiTy->getAddressSpace()); + Value *BaseI8Ptr = Builder.CreateBitCast(Base, I8PtrTy); + Value *GEP = Builder.CreateConstInBoundsGEP1_64(BaseI8Ptr, Offset); + Value *GEPTyped = Builder.CreateBitCast(GEP, PhiTy); + + for (Use &Incoming : PN.incoming_values()) { + auto *IncomingInst = cast(Incoming); + // If we haven't already replaced this instruction. + if (IncomingInst != GEPTyped) + replaceInstUsesWith(*IncomingInst, GEPTyped); + } + + return replaceInstUsesWith(PN, GEPTyped); +} + // PHINode simplification // Instruction *InstCombiner::visitPHINode(PHINode &PN) { @@ -1143,6 +1205,9 @@ Instruction *InstCombiner::visitPHINode(PHINode &PN) { if (Instruction *Result = FoldPHIArgOpIntoPHI(PN)) return Result; + if (Instruction *Result = FoldPHIWithEqualPointers(PN)) + return Result; + // If this is a trivial cycle in the PHI node graph, remove it. Basically, if // this PHI only has a single use (a PHI), and if that PHI only has one use (a // PHI)... break the cycle. diff --git a/llvm/test/Transforms/InstCombine/phi-equal-incoming-pointers.ll b/llvm/test/Transforms/InstCombine/phi-equal-incoming-pointers.ll index 882df7b37229..4404126c33a4 100644 --- a/llvm/test/Transforms/InstCombine/phi-equal-incoming-pointers.ll +++ b/llvm/test/Transforms/InstCombine/phi-equal-incoming-pointers.ll @@ -13,20 +13,16 @@ define i32 @test_gep_and_bitcast(i1 %cond, i1 %cond2) { ; ALL-LABEL: @test_gep_and_bitcast( ; ALL-NEXT: entry: ; ALL-NEXT: [[OBJ:%.*]] = call i8* @get_ptr.i8() +; ALL-NEXT: [[TMP0:%.*]] = getelementptr inbounds i8, i8* [[OBJ]], i64 16 +; ALL-NEXT: [[TMP1:%.*]] = bitcast i8* [[TMP0]] to i32* ; ALL-NEXT: br i1 [[COND:%.*]], label [[BB1:%.*]], label [[BB2:%.*]] ; ALL: bb1: -; ALL-NEXT: [[PTR1:%.*]] = getelementptr inbounds i8, i8* [[OBJ]], i64 16 -; ALL-NEXT: [[PTR1_TYPED:%.*]] = bitcast i8* [[PTR1]] to i32* ; ALL-NEXT: br label [[EXIT:%.*]] ; ALL: bb2: -; ALL-NEXT: [[PTR2:%.*]] = getelementptr inbounds i8, i8* [[OBJ]], i64 16 -; ALL-NEXT: [[PTR2_TYPED:%.*]] = bitcast i8* [[PTR2]] to i32* ; ALL-NEXT: br label [[EXIT]] ; ALL: exit: -; ALL-NEXT: [[PTR_TYPED:%.*]] = phi i32* [ [[PTR1_TYPED]], [[BB1]] ], [ [[PTR2_TYPED]], [[BB2]] ] -; ALL-NEXT: [[RES_PHI_IN:%.*]] = phi i32* [ [[PTR1_TYPED]], [[BB1]] ], [ [[PTR2_TYPED]], [[BB2]] ] -; ALL-NEXT: [[RES_PHI:%.*]] = load i32, i32* [[RES_PHI_IN]], align 4 -; ALL-NEXT: store i32 1, i32* [[PTR_TYPED]], align 4 +; ALL-NEXT: [[RES_PHI:%.*]] = load i32, i32* [[TMP1]], align 4 +; ALL-NEXT: store i32 1, i32* [[TMP1]], align 4 ; ALL-NEXT: [[RES:%.*]] = select i1 [[COND2:%.*]], i32 [[RES_PHI]], i32 1 ; ALL-NEXT: ret i32 [[RES]] ; @@ -55,23 +51,122 @@ exit: ret i32 %res } +define i32 @test_gep_and_bitcast_2_same_incoming_instructions(i1 %cond, i1 %cond2, i1 %cond3) { +; ALL-LABEL: @test_gep_and_bitcast_2_same_incoming_instructions( +; ALL-NEXT: entry: +; ALL-NEXT: [[OBJ:%.*]] = call i8* @get_ptr.i8() +; ALL-NEXT: [[TMP0:%.*]] = getelementptr inbounds i8, i8* [[OBJ]], i64 16 +; ALL-NEXT: [[TMP1:%.*]] = bitcast i8* [[TMP0]] to i32* +; ALL-NEXT: br i1 [[COND:%.*]], label [[BB1:%.*]], label [[BB2:%.*]] +; ALL: bb1: +; ALL-NEXT: [[RES1:%.*]] = load i32, i32* [[TMP1]], align 4 +; ALL-NEXT: br label [[EXIT:%.*]] +; ALL: bb2: +; ALL-NEXT: [[RES2:%.*]] = load i32, i32* [[TMP1]], align 4 +; ALL-NEXT: br i1 [[COND3:%.*]], label [[EXIT]], label [[BB3:%.*]] +; ALL: bb3: +; ALL-NEXT: br label [[EXIT]] +; ALL: exit: +; ALL-NEXT: [[RES_PHI:%.*]] = phi i32 [ [[RES1]], [[BB1]] ], [ [[RES2]], [[BB2]] ], [ [[RES2]], [[BB3]] ] +; ALL-NEXT: store i32 1, i32* [[TMP1]], align 4 +; ALL-NEXT: [[RES:%.*]] = select i1 [[COND2:%.*]], i32 [[RES_PHI]], i32 1 +; ALL-NEXT: ret i32 [[RES]] +; +entry: + %obj = call i8* @get_ptr.i8() + br i1 %cond, label %bb1, label %bb2 + +bb1: + %ptr1 = getelementptr inbounds i8, i8* %obj, i64 16 + %ptr1.typed = bitcast i8* %ptr1 to i32* + %res1 = load i32, i32* %ptr1.typed + br label %exit + +bb2: + %ptr2 = getelementptr inbounds i8, i8* %obj, i64 16 + %ptr2.typed = bitcast i8* %ptr2 to i32* + %res2 = load i32, i32* %ptr2.typed + br i1 %cond3, label %exit, label %bb3 + +bb3: + br label %exit + +exit: + %ptr.typed = phi i32* [ %ptr1.typed, %bb1 ], [ %ptr2.typed, %bb2 ], [ %ptr2.typed, %bb3 ] + %res.phi = phi i32 [ %res1, %bb1 ], [ %res2, %bb2 ], [ %res2, %bb3 ] + store i32 1, i32* %ptr.typed + %res.load = load i32, i32* %ptr.typed + %res = select i1 %cond2, i32 %res.phi, i32 %res.load + ret i32 %res +} + +define i32 @test_gep_and_bitcast_3_same_incoming_instructions(i1 %cond, i1 %cond2, i1 %cond3, i1 %cond4) { +; ALL-LABEL: @test_gep_and_bitcast_3_same_incoming_instructions( +; ALL-NEXT: entry: +; ALL-NEXT: [[OBJ:%.*]] = call i8* @get_ptr.i8() +; ALL-NEXT: [[TMP0:%.*]] = getelementptr inbounds i8, i8* [[OBJ]], i64 16 +; ALL-NEXT: [[TMP1:%.*]] = bitcast i8* [[TMP0]] to i32* +; ALL-NEXT: br i1 [[COND:%.*]], label [[BB1:%.*]], label [[BB2:%.*]] +; ALL: bb1: +; ALL-NEXT: [[RES1:%.*]] = load i32, i32* [[TMP1]], align 4 +; ALL-NEXT: br label [[EXIT:%.*]] +; ALL: bb2: +; ALL-NEXT: [[RES2:%.*]] = load i32, i32* [[TMP1]], align 4 +; ALL-NEXT: br i1 [[COND3:%.*]], label [[EXIT]], label [[BB3:%.*]] +; ALL: bb3: +; ALL-NEXT: br i1 [[COND4:%.*]], label [[EXIT]], label [[BB4:%.*]] +; ALL: bb4: +; ALL-NEXT: br label [[EXIT]] +; ALL: exit: +; ALL-NEXT: [[RES_PHI:%.*]] = phi i32 [ [[RES1]], [[BB1]] ], [ [[RES2]], [[BB2]] ], [ [[RES2]], [[BB3]] ], [ [[RES2]], [[BB4]] ] +; ALL-NEXT: store i32 1, i32* [[TMP1]], align 4 +; ALL-NEXT: [[RES:%.*]] = select i1 [[COND2:%.*]], i32 [[RES_PHI]], i32 1 +; ALL-NEXT: ret i32 [[RES]] +; +entry: + %obj = call i8* @get_ptr.i8() + br i1 %cond, label %bb1, label %bb2 + +bb1: + %ptr1 = getelementptr inbounds i8, i8* %obj, i64 16 + %ptr1.typed = bitcast i8* %ptr1 to i32* + %res1 = load i32, i32* %ptr1.typed + br label %exit + +bb2: + %ptr2 = getelementptr inbounds i8, i8* %obj, i64 16 + %ptr2.typed = bitcast i8* %ptr2 to i32* + %res2 = load i32, i32* %ptr2.typed + br i1 %cond3, label %exit, label %bb3 + +bb3: + br i1 %cond4, label %exit, label %bb4 + +bb4: + br label %exit + +exit: + %ptr.typed = phi i32* [ %ptr1.typed, %bb1 ], [ %ptr2.typed, %bb2 ], [ %ptr2.typed, %bb3 ], [ %ptr2.typed, %bb4 ] + %res.phi = phi i32 [ %res1, %bb1 ], [ %res2, %bb2 ], [ %res2, %bb3 ], [ %res2, %bb4 ] + store i32 1, i32* %ptr.typed + %res.load = load i32, i32* %ptr.typed + %res = select i1 %cond2, i32 %res.phi, i32 %res.load + ret i32 %res +} + define i32 @test_gep_and_bitcast_arg(i8* %obj, i1 %cond, i1 %cond2) { ; ALL-LABEL: @test_gep_and_bitcast_arg( ; ALL-NEXT: entry: +; ALL-NEXT: [[TMP0:%.*]] = getelementptr inbounds i8, i8* [[OBJ:%.*]], i64 16 +; ALL-NEXT: [[TMP1:%.*]] = bitcast i8* [[TMP0]] to i32* ; ALL-NEXT: br i1 [[COND:%.*]], label [[BB1:%.*]], label [[BB2:%.*]] ; ALL: bb1: -; ALL-NEXT: [[PTR1:%.*]] = getelementptr inbounds i8, i8* [[OBJ:%.*]], i64 16 -; ALL-NEXT: [[PTR1_TYPED:%.*]] = bitcast i8* [[PTR1]] to i32* ; ALL-NEXT: br label [[EXIT:%.*]] ; ALL: bb2: -; ALL-NEXT: [[PTR2:%.*]] = getelementptr inbounds i8, i8* [[OBJ]], i64 16 -; ALL-NEXT: [[PTR2_TYPED:%.*]] = bitcast i8* [[PTR2]] to i32* ; ALL-NEXT: br label [[EXIT]] ; ALL: exit: -; ALL-NEXT: [[PTR_TYPED:%.*]] = phi i32* [ [[PTR1_TYPED]], [[BB1]] ], [ [[PTR2_TYPED]], [[BB2]] ] -; ALL-NEXT: [[RES_PHI_IN:%.*]] = phi i32* [ [[PTR1_TYPED]], [[BB1]] ], [ [[PTR2_TYPED]], [[BB2]] ] -; ALL-NEXT: [[RES_PHI:%.*]] = load i32, i32* [[RES_PHI_IN]], align 4 -; ALL-NEXT: store i32 1, i32* [[PTR_TYPED]], align 4 +; ALL-NEXT: [[RES_PHI:%.*]] = load i32, i32* [[TMP1]], align 4 +; ALL-NEXT: store i32 1, i32* [[TMP1]], align 4 ; ALL-NEXT: [[RES:%.*]] = select i1 [[COND2:%.*]], i32 [[RES_PHI]], i32 1 ; ALL-NEXT: ret i32 [[RES]] ; @@ -113,21 +208,17 @@ define i32 @test_gep_and_bitcast_phi(i1 %cond, i1 %cond2, i1 %cond3) { ; ALL: merge: ; ALL-NEXT: [[OBJ:%.*]] = phi i8* [ [[OBJ1]], [[BB1]] ], [ [[OBJ2]], [[BB2]] ] ; ALL-NEXT: [[ANOTHER_PHI:%.*]] = phi i8* [ [[OBJ1]], [[BB1]] ], [ null, [[BB2]] ] +; ALL-NEXT: [[TMP0:%.*]] = getelementptr inbounds i8, i8* [[OBJ]], i64 16 +; ALL-NEXT: [[TMP1:%.*]] = bitcast i8* [[TMP0]] to i32* ; ALL-NEXT: call void @foo.i8(i8* [[ANOTHER_PHI]]) ; ALL-NEXT: br i1 [[COND2:%.*]], label [[BB3:%.*]], label [[BB4:%.*]] ; ALL: bb3: -; ALL-NEXT: [[PTR1:%.*]] = getelementptr inbounds i8, i8* [[OBJ]], i64 16 -; ALL-NEXT: [[PTR1_TYPED:%.*]] = bitcast i8* [[PTR1]] to i32* ; ALL-NEXT: br label [[EXIT:%.*]] ; ALL: bb4: -; ALL-NEXT: [[PTR2:%.*]] = getelementptr inbounds i8, i8* [[OBJ]], i64 16 -; ALL-NEXT: [[PTR2_TYPED:%.*]] = bitcast i8* [[PTR2]] to i32* ; ALL-NEXT: br label [[EXIT]] ; ALL: exit: -; ALL-NEXT: [[PTR_TYPED:%.*]] = phi i32* [ [[PTR1_TYPED]], [[BB3]] ], [ [[PTR2_TYPED]], [[BB4]] ] -; ALL-NEXT: [[RES_PHI_IN:%.*]] = phi i32* [ [[PTR1_TYPED]], [[BB3]] ], [ [[PTR2_TYPED]], [[BB4]] ] -; ALL-NEXT: [[RES_PHI:%.*]] = load i32, i32* [[RES_PHI_IN]], align 4 -; ALL-NEXT: store i32 1, i32* [[PTR_TYPED]], align 4 +; ALL-NEXT: [[RES_PHI:%.*]] = load i32, i32* [[TMP1]], align 4 +; ALL-NEXT: store i32 1, i32* [[TMP1]], align 4 ; ALL-NEXT: [[RES:%.*]] = select i1 [[COND3:%.*]], i32 [[RES_PHI]], i32 1 ; ALL-NEXT: ret i32 [[RES]] ; @@ -174,18 +265,15 @@ define i32 @test_gep_i32ptr(i1 %cond, i1 %cond2) { ; ALL-LABEL: @test_gep_i32ptr( ; ALL-NEXT: entry: ; ALL-NEXT: [[OBJ:%.*]] = call i32* @get_ptr.i32() +; ALL-NEXT: [[TMP0:%.*]] = getelementptr inbounds i32, i32* [[OBJ]], i64 16 ; ALL-NEXT: br i1 [[COND:%.*]], label [[BB1:%.*]], label [[BB2:%.*]] ; ALL: bb1: -; ALL-NEXT: [[PTR1_TYPED:%.*]] = getelementptr inbounds i32, i32* [[OBJ]], i64 16 ; ALL-NEXT: br label [[EXIT:%.*]] ; ALL: bb2: -; ALL-NEXT: [[PTR2_TYPED:%.*]] = getelementptr inbounds i32, i32* [[OBJ]], i64 16 ; ALL-NEXT: br label [[EXIT]] ; ALL: exit: -; ALL-NEXT: [[PTR_TYPED:%.*]] = phi i32* [ [[PTR1_TYPED]], [[BB1]] ], [ [[PTR2_TYPED]], [[BB2]] ] -; ALL-NEXT: [[RES_PHI_IN:%.*]] = phi i32* [ [[PTR1_TYPED]], [[BB1]] ], [ [[PTR2_TYPED]], [[BB2]] ] -; ALL-NEXT: [[RES_PHI:%.*]] = load i32, i32* [[RES_PHI_IN]], align 4 -; ALL-NEXT: store i32 1, i32* [[PTR_TYPED]], align 4 +; ALL-NEXT: [[RES_PHI:%.*]] = load i32, i32* [[TMP0]], align 4 +; ALL-NEXT: store i32 1, i32* [[TMP0]], align 4 ; ALL-NEXT: [[RES:%.*]] = select i1 [[COND2:%.*]], i32 [[RES_PHI]], i32 1 ; ALL-NEXT: ret i32 [[RES]] ; @@ -216,20 +304,16 @@ define i32 @test_gep_and_bitcast_gep_base_ptr(i1 %cond, i1 %cond2) { ; ALL-LABEL: @test_gep_and_bitcast_gep_base_ptr( ; ALL-NEXT: entry: ; ALL-NEXT: [[OBJ0:%.*]] = call i8* @get_ptr.i8() +; ALL-NEXT: [[TMP0:%.*]] = getelementptr inbounds i8, i8* [[OBJ0]], i64 32 +; ALL-NEXT: [[TMP1:%.*]] = bitcast i8* [[TMP0]] to i32* ; ALL-NEXT: br i1 [[COND:%.*]], label [[BB1:%.*]], label [[BB2:%.*]] ; ALL: bb1: -; ALL-NEXT: [[PTR1:%.*]] = getelementptr inbounds i8, i8* [[OBJ0]], i64 32 -; ALL-NEXT: [[PTR1_TYPED:%.*]] = bitcast i8* [[PTR1]] to i32* ; ALL-NEXT: br label [[EXIT:%.*]] ; ALL: bb2: -; ALL-NEXT: [[PTR2:%.*]] = getelementptr inbounds i8, i8* [[OBJ0]], i64 32 -; ALL-NEXT: [[PTR2_TYPED:%.*]] = bitcast i8* [[PTR2]] to i32* ; ALL-NEXT: br label [[EXIT]] ; ALL: exit: -; ALL-NEXT: [[PTR_TYPED:%.*]] = phi i32* [ [[PTR1_TYPED]], [[BB1]] ], [ [[PTR2_TYPED]], [[BB2]] ] -; ALL-NEXT: [[RES_PHI_IN:%.*]] = phi i32* [ [[PTR1_TYPED]], [[BB1]] ], [ [[PTR2_TYPED]], [[BB2]] ] -; ALL-NEXT: [[RES_PHI:%.*]] = load i32, i32* [[RES_PHI_IN]], align 4 -; ALL-NEXT: store i32 1, i32* [[PTR_TYPED]], align 4 +; ALL-NEXT: [[RES_PHI:%.*]] = load i32, i32* [[TMP1]], align 4 +; ALL-NEXT: store i32 1, i32* [[TMP1]], align 4 ; ALL-NEXT: [[RES:%.*]] = select i1 [[COND2:%.*]], i32 [[RES_PHI]], i32 1 ; ALL-NEXT: ret i32 [[RES]] ; @@ -260,37 +344,19 @@ exit: } define i32 @test_gep_and_bitcast_same_bb(i1 %cond, i1 %cond2) { -; INSTCOMBINE-LABEL: @test_gep_and_bitcast_same_bb( -; INSTCOMBINE-NEXT: entry: -; INSTCOMBINE-NEXT: [[OBJ:%.*]] = call i8* @get_ptr.i8() -; INSTCOMBINE-NEXT: [[PTR1:%.*]] = getelementptr inbounds i8, i8* [[OBJ]], i64 16 -; INSTCOMBINE-NEXT: [[PTR1_TYPED:%.*]] = bitcast i8* [[PTR1]] to i32* -; INSTCOMBINE-NEXT: br i1 [[COND:%.*]], label [[EXIT:%.*]], label [[BB2:%.*]] -; INSTCOMBINE: bb2: -; INSTCOMBINE-NEXT: [[PTR2:%.*]] = getelementptr inbounds i8, i8* [[OBJ]], i64 16 -; INSTCOMBINE-NEXT: [[PTR2_TYPED:%.*]] = bitcast i8* [[PTR2]] to i32* -; INSTCOMBINE-NEXT: br label [[EXIT]] -; INSTCOMBINE: exit: -; INSTCOMBINE-NEXT: [[PTR_TYPED:%.*]] = phi i32* [ [[PTR1_TYPED]], [[ENTRY:%.*]] ], [ [[PTR2_TYPED]], [[BB2]] ] -; INSTCOMBINE-NEXT: [[RES_PHI_IN:%.*]] = phi i32* [ [[PTR1_TYPED]], [[ENTRY]] ], [ [[PTR2_TYPED]], [[BB2]] ] -; INSTCOMBINE-NEXT: [[RES_PHI:%.*]] = load i32, i32* [[RES_PHI_IN]], align 4 -; INSTCOMBINE-NEXT: store i32 1, i32* [[PTR_TYPED]], align 4 -; INSTCOMBINE-NEXT: [[RES:%.*]] = select i1 [[COND2:%.*]], i32 [[RES_PHI]], i32 1 -; INSTCOMBINE-NEXT: ret i32 [[RES]] -; -; INSTCOMBINEGVN-LABEL: @test_gep_and_bitcast_same_bb( -; INSTCOMBINEGVN-NEXT: entry: -; INSTCOMBINEGVN-NEXT: [[OBJ:%.*]] = call i8* @get_ptr.i8() -; INSTCOMBINEGVN-NEXT: [[PTR1:%.*]] = getelementptr inbounds i8, i8* [[OBJ]], i64 16 -; INSTCOMBINEGVN-NEXT: [[PTR1_TYPED:%.*]] = bitcast i8* [[PTR1]] to i32* -; INSTCOMBINEGVN-NEXT: br i1 [[COND:%.*]], label [[EXIT:%.*]], label [[BB2:%.*]] -; INSTCOMBINEGVN: bb2: -; INSTCOMBINEGVN-NEXT: br label [[EXIT]] -; INSTCOMBINEGVN: exit: -; INSTCOMBINEGVN-NEXT: [[RES_PHI:%.*]] = load i32, i32* [[PTR1_TYPED]], align 4 -; INSTCOMBINEGVN-NEXT: store i32 1, i32* [[PTR1_TYPED]], align 4 -; INSTCOMBINEGVN-NEXT: [[RES:%.*]] = select i1 [[COND2:%.*]], i32 [[RES_PHI]], i32 1 -; INSTCOMBINEGVN-NEXT: ret i32 [[RES]] +; ALL-LABEL: @test_gep_and_bitcast_same_bb( +; ALL-NEXT: entry: +; ALL-NEXT: [[OBJ:%.*]] = call i8* @get_ptr.i8() +; ALL-NEXT: [[TMP0:%.*]] = getelementptr inbounds i8, i8* [[OBJ]], i64 16 +; ALL-NEXT: [[TMP1:%.*]] = bitcast i8* [[TMP0]] to i32* +; ALL-NEXT: br i1 [[COND:%.*]], label [[EXIT:%.*]], label [[BB2:%.*]] +; ALL: bb2: +; ALL-NEXT: br label [[EXIT]] +; ALL: exit: +; ALL-NEXT: [[RES_PHI:%.*]] = load i32, i32* [[TMP1]], align 4 +; ALL-NEXT: store i32 1, i32* [[TMP1]], align 4 +; ALL-NEXT: [[RES:%.*]] = select i1 [[COND2:%.*]], i32 [[RES_PHI]], i32 1 +; ALL-NEXT: ret i32 [[RES]] ; entry: %obj = call i8* @get_ptr.i8() @@ -315,39 +381,20 @@ exit: } define i32 @test_gep_and_bitcast_same_bb_and_extra_use(i1 %cond, i1 %cond2) { -; INSTCOMBINE-LABEL: @test_gep_and_bitcast_same_bb_and_extra_use( -; INSTCOMBINE-NEXT: entry: -; INSTCOMBINE-NEXT: [[OBJ:%.*]] = call i8* @get_ptr.i8() -; INSTCOMBINE-NEXT: [[PTR1:%.*]] = getelementptr inbounds i8, i8* [[OBJ]], i64 16 -; INSTCOMBINE-NEXT: [[PTR1_TYPED:%.*]] = bitcast i8* [[PTR1]] to i32* -; INSTCOMBINE-NEXT: call void @foo.i32(i32* nonnull [[PTR1_TYPED]]) -; INSTCOMBINE-NEXT: br i1 [[COND:%.*]], label [[EXIT:%.*]], label [[BB2:%.*]] -; INSTCOMBINE: bb2: -; INSTCOMBINE-NEXT: [[PTR2:%.*]] = getelementptr inbounds i8, i8* [[OBJ]], i64 16 -; INSTCOMBINE-NEXT: [[PTR2_TYPED:%.*]] = bitcast i8* [[PTR2]] to i32* -; INSTCOMBINE-NEXT: br label [[EXIT]] -; INSTCOMBINE: exit: -; INSTCOMBINE-NEXT: [[PTR_TYPED:%.*]] = phi i32* [ [[PTR1_TYPED]], [[ENTRY:%.*]] ], [ [[PTR2_TYPED]], [[BB2]] ] -; INSTCOMBINE-NEXT: [[RES_PHI_IN:%.*]] = phi i32* [ [[PTR1_TYPED]], [[ENTRY]] ], [ [[PTR2_TYPED]], [[BB2]] ] -; INSTCOMBINE-NEXT: [[RES_PHI:%.*]] = load i32, i32* [[RES_PHI_IN]], align 4 -; INSTCOMBINE-NEXT: store i32 1, i32* [[PTR_TYPED]], align 4 -; INSTCOMBINE-NEXT: [[RES:%.*]] = select i1 [[COND2:%.*]], i32 [[RES_PHI]], i32 1 -; INSTCOMBINE-NEXT: ret i32 [[RES]] -; -; INSTCOMBINEGVN-LABEL: @test_gep_and_bitcast_same_bb_and_extra_use( -; INSTCOMBINEGVN-NEXT: entry: -; INSTCOMBINEGVN-NEXT: [[OBJ:%.*]] = call i8* @get_ptr.i8() -; INSTCOMBINEGVN-NEXT: [[PTR1:%.*]] = getelementptr inbounds i8, i8* [[OBJ]], i64 16 -; INSTCOMBINEGVN-NEXT: [[PTR1_TYPED:%.*]] = bitcast i8* [[PTR1]] to i32* -; INSTCOMBINEGVN-NEXT: call void @foo.i32(i32* nonnull [[PTR1_TYPED]]) -; INSTCOMBINEGVN-NEXT: br i1 [[COND:%.*]], label [[EXIT:%.*]], label [[BB2:%.*]] -; INSTCOMBINEGVN: bb2: -; INSTCOMBINEGVN-NEXT: br label [[EXIT]] -; INSTCOMBINEGVN: exit: -; INSTCOMBINEGVN-NEXT: [[RES_PHI:%.*]] = load i32, i32* [[PTR1_TYPED]], align 4 -; INSTCOMBINEGVN-NEXT: store i32 1, i32* [[PTR1_TYPED]], align 4 -; INSTCOMBINEGVN-NEXT: [[RES:%.*]] = select i1 [[COND2:%.*]], i32 [[RES_PHI]], i32 1 -; INSTCOMBINEGVN-NEXT: ret i32 [[RES]] +; ALL-LABEL: @test_gep_and_bitcast_same_bb_and_extra_use( +; ALL-NEXT: entry: +; ALL-NEXT: [[OBJ:%.*]] = call i8* @get_ptr.i8() +; ALL-NEXT: [[TMP0:%.*]] = getelementptr inbounds i8, i8* [[OBJ]], i64 16 +; ALL-NEXT: [[TMP1:%.*]] = bitcast i8* [[TMP0]] to i32* +; ALL-NEXT: call void @foo.i32(i32* nonnull [[TMP1]]) +; ALL-NEXT: br i1 [[COND:%.*]], label [[EXIT:%.*]], label [[BB2:%.*]] +; ALL: bb2: +; ALL-NEXT: br label [[EXIT]] +; ALL: exit: +; ALL-NEXT: [[RES_PHI:%.*]] = load i32, i32* [[TMP1]], align 4 +; ALL-NEXT: store i32 1, i32* [[TMP1]], align 4 +; ALL-NEXT: [[RES:%.*]] = select i1 [[COND2:%.*]], i32 [[RES_PHI]], i32 1 +; ALL-NEXT: ret i32 [[RES]] ; entry: %obj = call i8* @get_ptr.i8() @@ -376,18 +423,15 @@ define i8 @test_gep(i1 %cond, i1 %cond2) { ; ALL-LABEL: @test_gep( ; ALL-NEXT: entry: ; ALL-NEXT: [[OBJ:%.*]] = call i8* @get_ptr.i8() +; ALL-NEXT: [[TMP0:%.*]] = getelementptr inbounds i8, i8* [[OBJ]], i64 16 ; ALL-NEXT: br i1 [[COND:%.*]], label [[BB1:%.*]], label [[BB2:%.*]] ; ALL: bb1: -; ALL-NEXT: [[PTR1:%.*]] = getelementptr inbounds i8, i8* [[OBJ]], i64 16 ; ALL-NEXT: br label [[EXIT:%.*]] ; ALL: bb2: -; ALL-NEXT: [[PTR2:%.*]] = getelementptr inbounds i8, i8* [[OBJ]], i64 16 ; ALL-NEXT: br label [[EXIT]] ; ALL: exit: -; ALL-NEXT: [[PTR_TYPED:%.*]] = phi i8* [ [[PTR1]], [[BB1]] ], [ [[PTR2]], [[BB2]] ] -; ALL-NEXT: [[RES_PHI_IN:%.*]] = phi i8* [ [[PTR1]], [[BB1]] ], [ [[PTR2]], [[BB2]] ] -; ALL-NEXT: [[RES_PHI:%.*]] = load i8, i8* [[RES_PHI_IN]], align 1 -; ALL-NEXT: store i8 1, i8* [[PTR_TYPED]], align 1 +; ALL-NEXT: [[RES_PHI:%.*]] = load i8, i8* [[TMP0]], align 1 +; ALL-NEXT: store i8 1, i8* [[TMP0]], align 1 ; ALL-NEXT: [[RES:%.*]] = select i1 [[COND2:%.*]], i8 [[RES_PHI]], i8 1 ; ALL-NEXT: ret i8 [[RES]] ; @@ -418,23 +462,20 @@ define i32 @test_extra_uses(i1 %cond, i1 %cond2) { ; ALL-LABEL: @test_extra_uses( ; ALL-NEXT: entry: ; ALL-NEXT: [[OBJ:%.*]] = call i8* @get_ptr.i8() +; ALL-NEXT: [[TMP0:%.*]] = getelementptr inbounds i8, i8* [[OBJ]], i64 16 +; ALL-NEXT: [[TMP1:%.*]] = bitcast i8* [[TMP0]] to i32* ; ALL-NEXT: br i1 [[COND:%.*]], label [[BB1:%.*]], label [[BB2:%.*]] ; ALL: bb1: -; ALL-NEXT: [[PTR1:%.*]] = getelementptr inbounds i8, i8* [[OBJ]], i64 16 -; ALL-NEXT: [[PTR1_TYPED:%.*]] = bitcast i8* [[PTR1]] to i32* -; ALL-NEXT: [[RES1:%.*]] = load i32, i32* [[PTR1_TYPED]], align 4 -; ALL-NEXT: call void @foo.i32(i32* nonnull [[PTR1_TYPED]]) +; ALL-NEXT: [[RES1:%.*]] = load i32, i32* [[TMP1]], align 4 +; ALL-NEXT: call void @foo.i32(i32* nonnull [[TMP1]]) ; ALL-NEXT: br label [[EXIT:%.*]] ; ALL: bb2: -; ALL-NEXT: [[PTR2:%.*]] = getelementptr inbounds i8, i8* [[OBJ]], i64 16 -; ALL-NEXT: [[PTR2_TYPED:%.*]] = bitcast i8* [[PTR2]] to i32* -; ALL-NEXT: [[RES2:%.*]] = load i32, i32* [[PTR2_TYPED]], align 4 -; ALL-NEXT: call void @foo.i32(i32* nonnull [[PTR2_TYPED]]) +; ALL-NEXT: [[RES2:%.*]] = load i32, i32* [[TMP1]], align 4 +; ALL-NEXT: call void @foo.i32(i32* nonnull [[TMP1]]) ; ALL-NEXT: br label [[EXIT]] ; ALL: exit: -; ALL-NEXT: [[PTR_TYPED:%.*]] = phi i32* [ [[PTR1_TYPED]], [[BB1]] ], [ [[PTR2_TYPED]], [[BB2]] ] ; ALL-NEXT: [[RES_PHI:%.*]] = phi i32 [ [[RES1]], [[BB1]] ], [ [[RES2]], [[BB2]] ] -; ALL-NEXT: store i32 1, i32* [[PTR_TYPED]], align 4 +; ALL-NEXT: store i32 1, i32* [[TMP1]], align 4 ; ALL-NEXT: [[RES:%.*]] = select i1 [[COND2:%.*]], i32 [[RES_PHI]], i32 1 ; ALL-NEXT: ret i32 [[RES]] ; @@ -520,23 +561,20 @@ define i32 @test_extra_uses_multiple_geps(i1 %cond, i1 %cond2) { ; ALL-LABEL: @test_extra_uses_multiple_geps( ; ALL-NEXT: entry: ; ALL-NEXT: [[OBJ:%.*]] = call i8* @get_ptr.i8() +; ALL-NEXT: [[TMP0:%.*]] = getelementptr inbounds i8, i8* [[OBJ]], i64 16 +; ALL-NEXT: [[TMP1:%.*]] = bitcast i8* [[TMP0]] to i32* ; ALL-NEXT: br i1 [[COND:%.*]], label [[BB1:%.*]], label [[BB2:%.*]] ; ALL: bb1: -; ALL-NEXT: [[PTR1:%.*]] = getelementptr inbounds i8, i8* [[OBJ]], i64 16 -; ALL-NEXT: [[PTR1_TYPED:%.*]] = bitcast i8* [[PTR1]] to i32* -; ALL-NEXT: [[RES1:%.*]] = load i32, i32* [[PTR1_TYPED]], align 4 -; ALL-NEXT: call void @foo.i32(i32* nonnull [[PTR1_TYPED]]) +; ALL-NEXT: [[RES1:%.*]] = load i32, i32* [[TMP1]], align 4 +; ALL-NEXT: call void @foo.i32(i32* nonnull [[TMP1]]) ; ALL-NEXT: br label [[EXIT:%.*]] ; ALL: bb2: -; ALL-NEXT: [[PTR2_1:%.*]] = getelementptr inbounds i8, i8* [[OBJ]], i64 16 -; ALL-NEXT: [[PTR2_TYPED:%.*]] = bitcast i8* [[PTR2_1]] to i32* -; ALL-NEXT: [[RES2:%.*]] = load i32, i32* [[PTR2_TYPED]], align 4 -; ALL-NEXT: call void @foo.i32(i32* nonnull [[PTR2_TYPED]]) +; ALL-NEXT: [[RES2:%.*]] = load i32, i32* [[TMP1]], align 4 +; ALL-NEXT: call void @foo.i32(i32* nonnull [[TMP1]]) ; ALL-NEXT: br label [[EXIT]] ; ALL: exit: -; ALL-NEXT: [[PTR_TYPED:%.*]] = phi i32* [ [[PTR1_TYPED]], [[BB1]] ], [ [[PTR2_TYPED]], [[BB2]] ] ; ALL-NEXT: [[RES_PHI:%.*]] = phi i32 [ [[RES1]], [[BB1]] ], [ [[RES2]], [[BB2]] ] -; ALL-NEXT: store i32 1, i32* [[PTR_TYPED]], align 4 +; ALL-NEXT: store i32 1, i32* [[TMP1]], align 4 ; ALL-NEXT: [[RES:%.*]] = select i1 [[COND2:%.*]], i32 [[RES_PHI]], i32 1 ; ALL-NEXT: ret i32 [[RES]] ; @@ -572,21 +610,19 @@ define i8 @test_gep_extra_uses(i1 %cond, i1 %cond2) { ; ALL-LABEL: @test_gep_extra_uses( ; ALL-NEXT: entry: ; ALL-NEXT: [[OBJ:%.*]] = call i8* @get_ptr.i8() +; ALL-NEXT: [[TMP0:%.*]] = getelementptr inbounds i8, i8* [[OBJ]], i64 16 ; ALL-NEXT: br i1 [[COND:%.*]], label [[BB1:%.*]], label [[BB2:%.*]] ; ALL: bb1: -; ALL-NEXT: [[PTR1:%.*]] = getelementptr inbounds i8, i8* [[OBJ]], i64 16 -; ALL-NEXT: [[RES1:%.*]] = load i8, i8* [[PTR1]], align 1 -; ALL-NEXT: call void @foo.i8(i8* nonnull [[PTR1]]) +; ALL-NEXT: [[RES1:%.*]] = load i8, i8* [[TMP0]], align 1 +; ALL-NEXT: call void @foo.i8(i8* nonnull [[TMP0]]) ; ALL-NEXT: br label [[EXIT:%.*]] ; ALL: bb2: -; ALL-NEXT: [[PTR2:%.*]] = getelementptr inbounds i8, i8* [[OBJ]], i64 16 -; ALL-NEXT: [[RES2:%.*]] = load i8, i8* [[PTR2]], align 1 -; ALL-NEXT: call void @foo.i8(i8* nonnull [[PTR2]]) +; ALL-NEXT: [[RES2:%.*]] = load i8, i8* [[TMP0]], align 1 +; ALL-NEXT: call void @foo.i8(i8* nonnull [[TMP0]]) ; ALL-NEXT: br label [[EXIT]] ; ALL: exit: -; ALL-NEXT: [[PTR_TYPED:%.*]] = phi i8* [ [[PTR1]], [[BB1]] ], [ [[PTR2]], [[BB2]] ] ; ALL-NEXT: [[RES_PHI:%.*]] = phi i8 [ [[RES1]], [[BB1]] ], [ [[RES2]], [[BB2]] ] -; ALL-NEXT: store i8 1, i8* [[PTR_TYPED]], align 1 +; ALL-NEXT: store i8 1, i8* [[TMP0]], align 1 ; ALL-NEXT: [[RES:%.*]] = select i1 [[COND2:%.*]], i8 [[RES_PHI]], i8 1 ; ALL-NEXT: ret i8 [[RES]] ; @@ -614,3 +650,231 @@ exit: %res = select i1 %cond2, i8 %res.phi, i8 %res.load ret i8 %res } + +define i32 @test_neg_extra_uses_inbounds_mismatch(i1 %cond, i1 %cond2) { +; ALL-LABEL: @test_neg_extra_uses_inbounds_mismatch( +; ALL-NEXT: entry: +; ALL-NEXT: [[OBJ:%.*]] = call i8* @get_ptr.i8() +; ALL-NEXT: br i1 [[COND:%.*]], label [[BB1:%.*]], label [[BB2:%.*]] +; ALL: bb1: +; ALL-NEXT: [[PTR1:%.*]] = getelementptr i8, i8* [[OBJ]], i64 16 +; ALL-NEXT: [[PTR1_TYPED:%.*]] = bitcast i8* [[PTR1]] to i32* +; ALL-NEXT: [[RES1:%.*]] = load i32, i32* [[PTR1_TYPED]], align 4 +; ALL-NEXT: call void @foo.i32(i32* [[PTR1_TYPED]]) +; ALL-NEXT: br label [[EXIT:%.*]] +; ALL: bb2: +; ALL-NEXT: [[PTR2:%.*]] = getelementptr inbounds i8, i8* [[OBJ]], i64 16 +; ALL-NEXT: [[PTR2_TYPED:%.*]] = bitcast i8* [[PTR2]] to i32* +; ALL-NEXT: [[RES2:%.*]] = load i32, i32* [[PTR2_TYPED]], align 4 +; ALL-NEXT: call void @foo.i32(i32* nonnull [[PTR2_TYPED]]) +; ALL-NEXT: br label [[EXIT]] +; ALL: exit: +; ALL-NEXT: [[PTR_TYPED:%.*]] = phi i32* [ [[PTR1_TYPED]], [[BB1]] ], [ [[PTR2_TYPED]], [[BB2]] ] +; ALL-NEXT: [[RES_PHI:%.*]] = phi i32 [ [[RES1]], [[BB1]] ], [ [[RES2]], [[BB2]] ] +; ALL-NEXT: store i32 1, i32* [[PTR_TYPED]], align 4 +; ALL-NEXT: [[RES:%.*]] = select i1 [[COND2:%.*]], i32 [[RES_PHI]], i32 1 +; ALL-NEXT: ret i32 [[RES]] +; +entry: + %obj = call i8* @get_ptr.i8() + br i1 %cond, label %bb1, label %bb2 + +bb1: + %ptr1 = getelementptr i8, i8* %obj, i64 16 + %ptr1.typed = bitcast i8* %ptr1 to i32* + %res1 = load i32, i32* %ptr1.typed + call void @foo.i32(i32* %ptr1.typed) + br label %exit + +bb2: + %ptr2 = getelementptr inbounds i8, i8* %obj, i64 16 + %ptr2.typed = bitcast i8* %ptr2 to i32* + %res2 = load i32, i32* %ptr2.typed + call void @foo.i32(i32* %ptr2.typed) + br label %exit + +exit: + %ptr.typed = phi i32* [ %ptr1.typed, %bb1 ], [ %ptr2.typed, %bb2 ] + %res.phi = phi i32 [ %res1, %bb1 ], [ %res2, %bb2 ] + store i32 1, i32* %ptr.typed + %res.load = load i32, i32* %ptr.typed + %res = select i1 %cond2, i32 %res.phi, i32 %res.load + ret i32 %res +} + +define i32 @test_neg_gep_and_bitcast_different_offset(i1 %cond, i1 %cond2) { +; ALL-LABEL: @test_neg_gep_and_bitcast_different_offset( +; ALL-NEXT: entry: +; ALL-NEXT: [[OBJ:%.*]] = call i8* @get_ptr.i8() +; ALL-NEXT: br i1 [[COND:%.*]], label [[BB1:%.*]], label [[BB2:%.*]] +; ALL: bb1: +; ALL-NEXT: [[PTR1:%.*]] = getelementptr inbounds i8, i8* [[OBJ]], i64 16 +; ALL-NEXT: [[PTR1_TYPED:%.*]] = bitcast i8* [[PTR1]] to i32* +; ALL-NEXT: br label [[EXIT:%.*]] +; ALL: bb2: +; ALL-NEXT: [[PTR2:%.*]] = getelementptr inbounds i8, i8* [[OBJ]], i64 20 +; ALL-NEXT: [[PTR2_TYPED:%.*]] = bitcast i8* [[PTR2]] to i32* +; ALL-NEXT: br label [[EXIT]] +; ALL: exit: +; ALL-NEXT: [[PTR_TYPED:%.*]] = phi i32* [ [[PTR1_TYPED]], [[BB1]] ], [ [[PTR2_TYPED]], [[BB2]] ] +; ALL-NEXT: [[RES_PHI_IN:%.*]] = phi i32* [ [[PTR1_TYPED]], [[BB1]] ], [ [[PTR2_TYPED]], [[BB2]] ] +; ALL-NEXT: [[RES_PHI:%.*]] = load i32, i32* [[RES_PHI_IN]], align 4 +; ALL-NEXT: store i32 1, i32* [[PTR_TYPED]], align 4 +; ALL-NEXT: [[RES:%.*]] = select i1 [[COND2:%.*]], i32 [[RES_PHI]], i32 1 +; ALL-NEXT: ret i32 [[RES]] +; +entry: + %obj = call i8* @get_ptr.i8() + br i1 %cond, label %bb1, label %bb2 + +bb1: + %ptr1 = getelementptr inbounds i8, i8* %obj, i64 16 + %ptr1.typed = bitcast i8* %ptr1 to i32* + %res1 = load i32, i32* %ptr1.typed + br label %exit + +bb2: + %ptr2 = getelementptr inbounds i8, i8* %obj, i64 20 + %ptr2.typed = bitcast i8* %ptr2 to i32* + %res2 = load i32, i32* %ptr2.typed + br label %exit + +exit: + %ptr.typed = phi i32* [ %ptr1.typed, %bb1 ], [ %ptr2.typed, %bb2 ] + %res.phi = phi i32 [ %res1, %bb1 ], [ %res2, %bb2 ] + store i32 1, i32* %ptr.typed + %res.load = load i32, i32* %ptr.typed + %res = select i1 %cond2, i32 %res.phi, i32 %res.load + ret i32 %res +} + +define i32 @test_neg_gep_and_bitcast_different_base_ptr(i1 %cond, i1 %cond2) { +; ALL-LABEL: @test_neg_gep_and_bitcast_different_base_ptr( +; ALL-NEXT: entry: +; ALL-NEXT: [[OBJ:%.*]] = call i8* @get_ptr.i8() +; ALL-NEXT: [[OBJ2:%.*]] = call i8* @get_ptr.i8() +; ALL-NEXT: br i1 [[COND:%.*]], label [[BB1:%.*]], label [[BB2:%.*]] +; ALL: bb1: +; ALL-NEXT: [[PTR1:%.*]] = getelementptr inbounds i8, i8* [[OBJ]], i64 16 +; ALL-NEXT: [[PTR1_TYPED:%.*]] = bitcast i8* [[PTR1]] to i32* +; ALL-NEXT: br label [[EXIT:%.*]] +; ALL: bb2: +; ALL-NEXT: [[PTR2:%.*]] = getelementptr inbounds i8, i8* [[OBJ2]], i64 16 +; ALL-NEXT: [[PTR2_TYPED:%.*]] = bitcast i8* [[PTR2]] to i32* +; ALL-NEXT: br label [[EXIT]] +; ALL: exit: +; ALL-NEXT: [[PTR_TYPED:%.*]] = phi i32* [ [[PTR1_TYPED]], [[BB1]] ], [ [[PTR2_TYPED]], [[BB2]] ] +; ALL-NEXT: [[RES_PHI_IN:%.*]] = phi i32* [ [[PTR1_TYPED]], [[BB1]] ], [ [[PTR2_TYPED]], [[BB2]] ] +; ALL-NEXT: [[RES_PHI:%.*]] = load i32, i32* [[RES_PHI_IN]], align 4 +; ALL-NEXT: store i32 1, i32* [[PTR_TYPED]], align 4 +; ALL-NEXT: [[RES:%.*]] = select i1 [[COND2:%.*]], i32 [[RES_PHI]], i32 1 +; ALL-NEXT: ret i32 [[RES]] +; +entry: + %obj = call i8* @get_ptr.i8() + %obj2 = call i8* @get_ptr.i8() + br i1 %cond, label %bb1, label %bb2 + +bb1: + %ptr1 = getelementptr inbounds i8, i8* %obj, i64 16 + %ptr1.typed = bitcast i8* %ptr1 to i32* + %res1 = load i32, i32* %ptr1.typed + br label %exit + +bb2: + %ptr2 = getelementptr inbounds i8, i8* %obj2, i64 16 + %ptr2.typed = bitcast i8* %ptr2 to i32* + %res2 = load i32, i32* %ptr2.typed + br label %exit + +exit: + %ptr.typed = phi i32* [ %ptr1.typed, %bb1 ], [ %ptr2.typed, %bb2 ] + %res.phi = phi i32 [ %res1, %bb1 ], [ %res2, %bb2 ] + store i32 1, i32* %ptr.typed + %res.load = load i32, i32* %ptr.typed + %res = select i1 %cond2, i32 %res.phi, i32 %res.load + ret i32 %res +} + +; Just to make sure we don't generate invalid IR in this case. +; There is no insertion point right after base pointer def here. +define i32 @test_neg_gep_and_bitcast_invoke(i1 %cond, i1 %cond2) personality i8 0 { +; ALL-LABEL: @test_neg_gep_and_bitcast_invoke( +; +entry: + %obj = invoke i8* @get_ptr.i8() to label %bb0 unwind label %lpad + +lpad: + %ll = landingpad { i8*, i32 } + cleanup + ret i32 0 + +bb0: + br i1 %cond, label %bb1, label %bb2 + +bb1: + %ptr1 = getelementptr inbounds i8, i8* %obj, i64 16 + %ptr1.typed = bitcast i8* %ptr1 to i32* + %res1 = load i32, i32* %ptr1.typed + br label %exit + +bb2: + %ptr2 = getelementptr inbounds i8, i8* %obj, i64 16 + %ptr2.typed = bitcast i8* %ptr2 to i32* + %res2 = load i32, i32* %ptr2.typed + br label %exit + +exit: + %ptr.typed = phi i32* [ %ptr1.typed, %bb1 ], [ %ptr2.typed, %bb2 ] + %res.phi = phi i32 [ %res1, %bb1 ], [ %res2, %bb2 ] + store i32 1, i32* %ptr.typed + %res.load = load i32, i32* %ptr.typed + %res = select i1 %cond2, i32 %res.phi, i32 %res.load + ret i32 %res +} + +; Just to make sure we don't generate invalid IR in this case. +define i32 @test_neg_gep_and_bitcast_phi_no_insert_pt(i1 %cond, i1 %cond2) personality i8 0 { +; ALL-LABEL: @test_neg_gep_and_bitcast_phi_no_insert_pt( +; +entry: + %obj1 = call i8* @get_ptr.i8() + invoke void @foo.i8(i8* null) to label %cont unwind label %catch + +cont: + %obj2.typed = call i32* @get_ptr.i32() + %obj2 = bitcast i32* %obj2.typed to i8* + invoke void @foo.i8(i8* null) to label %unreachable unwind label %catch + +catch: + ; There is no insertion point in this basic block! + %obj = phi i8* [ %obj1, %entry ], [ %obj2, %cont ] + %cs = catchswitch within none [label %doit] unwind to caller + +doit: + %cl = catchpad within %cs [] + br i1 %cond, label %bb1, label %bb2 + +bb1: + %ptr1 = getelementptr inbounds i8, i8* %obj, i64 16 + %ptr1.typed = bitcast i8* %ptr1 to i32* + %res1 = load i32, i32* %ptr1.typed + br label %exit + +bb2: + %ptr2 = getelementptr inbounds i8, i8* %obj, i64 16 + %ptr2.typed = bitcast i8* %ptr2 to i32* + %res2 = load i32, i32* %ptr2.typed + br label %exit + +exit: + %ptr.typed = phi i32* [ %ptr1.typed, %bb1 ], [ %ptr2.typed, %bb2 ] + %res.phi = phi i32 [ %res1, %bb1 ], [ %res2, %bb2 ] + store i32 1, i32* %ptr.typed + %res.load = load i32, i32* %ptr.typed + %res = select i1 %cond2, i32 %res.phi, i32 %res.load + ret i32 %res + +unreachable: + unreachable +}