forked from OSchip/llvm-project
[InstCombine] Fold PHIs with equal incoming pointers
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
This commit is contained in:
parent
9a1c243aa5
commit
bbb29738b5
|
@ -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);
|
||||
|
|
|
@ -1122,6 +1122,63 @@ Instruction *InstCombiner::SliceUpIllegalIntegerPHI(PHINode &FirstPhi) {
|
|||
return replaceInstUsesWith(FirstPhi, Undef);
|
||||
}
|
||||
|
||||
Instruction *InstCombiner::FoldPHIWithEqualPointers(PHINode &PN) {
|
||||
auto *PhiTy = dyn_cast<PointerType>(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<PointerType>(Base->getType());
|
||||
if (BaseTy->getAddressSpace() != PhiTy->getAddressSpace())
|
||||
return nullptr;
|
||||
|
||||
for (Use &Incoming : PN.incoming_values()) {
|
||||
if (!isa<Instruction>(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<Instruction>(Base)) {
|
||||
if (isa<PHINode>(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())
|
||||
replaceInstUsesWith(*cast<Instruction>(Incoming), GEPTyped);
|
||||
return replaceInstUsesWith(PN, GEPTyped);
|
||||
}
|
||||
|
||||
// PHINode simplification
|
||||
//
|
||||
Instruction *InstCombiner::visitPHINode(PHINode &PN) {
|
||||
|
@ -1143,6 +1200,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.
|
||||
|
|
|
@ -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]]
|
||||
;
|
||||
|
@ -58,20 +54,16 @@ exit:
|
|||
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 +105,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 +162,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 +201,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 +241,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 +278,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 +320,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 +359,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 +458,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 +507,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 +547,229 @@ 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 {
|
||||
; CHECK-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 {
|
||||
; CHECK-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
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue