diff --git a/llvm/lib/Transforms/Scalar/GVN.cpp b/llvm/lib/Transforms/Scalar/GVN.cpp --- a/llvm/lib/Transforms/Scalar/GVN.cpp +++ b/llvm/lib/Transforms/Scalar/GVN.cpp @@ -182,12 +182,14 @@ SimpleVal, // A simple offsetted value that is accessed. LoadVal, // A value produced by a load. MemIntrin, // A memory intrinsic which is loaded from. - UndefVal // A UndefValue representing a value from dead block (which + UndefVal, // A UndefValue representing a value from dead block (which // is not yet physically removed from the CFG). + SelectVal, // A pointer select which is loaded from and for which the load + // can be replace by a value select. }; /// V - The value that is live out of the block. - PointerIntPair Val; + PointerIntPair Val; /// Offset - The byte offset in Val that is interesting for the load query. unsigned Offset = 0; @@ -224,10 +226,19 @@ return Res; } + static AvailableValue getSelect(SelectInst *Sel) { + AvailableValue Res; + Res.Val.setPointer(Sel); + Res.Val.setInt(SelectVal); + Res.Offset = 0; + return Res; + } + bool isSimpleValue() const { return Val.getInt() == SimpleVal; } bool isCoercedLoadValue() const { return Val.getInt() == LoadVal; } bool isMemIntrinValue() const { return Val.getInt() == MemIntrin; } bool isUndefValue() const { return Val.getInt() == UndefVal; } + bool isSelectValue() const { return Val.getInt() == SelectVal; } Value *getSimpleValue() const { assert(isSimpleValue() && "Wrong accessor"); @@ -244,6 +255,11 @@ return cast(Val.getPointer()); } + SelectInst *getSelectValue() const { + assert(isSelectValue() && "Wrong accessor"); + return cast(Val.getPointer()); + } + /// Emit code at the specified insertion point to adjust the value defined /// here to the specified type. This handles various coercion cases. Value *MaterializeAdjustedValue(LoadInst *Load, Instruction *InsertPt, @@ -275,6 +291,10 @@ return get(BB, AvailableValue::getUndef()); } + static AvailableValueInBlock getSelect(BasicBlock *BB, SelectInst *Sel) { + return get(BB, AvailableValue::getSelect(Sel)); + } + /// Emit code at the end of this block to adjust the value defined here to /// the specified type. This handles various coercion cases. Value *MaterializeAdjustedValue(LoadInst *Load, GVNPass &gvn) const { @@ -937,6 +957,26 @@ << " " << *getMemIntrinValue() << '\n' << *Res << '\n' << "\n\n\n"); + } else if (isSelectValue()) { + // Introduce a new value select for a load from an eligible pointer select. + auto *Sel = getSelectValue(); + auto FindDominatingLoad = [Sel, &gvn](Value *Ptr) -> LoadInst * { + for (Value *U : Ptr->users()) { + auto *LI = dyn_cast(U); + if (LI && LI->getParent() == Sel->getParent() && + gvn.getDominatorTree().dominates(LI, Sel)) + return LI; + } + return nullptr; + }; + + auto *L1 = FindDominatingLoad(Sel->getOperand(1)); + auto *L2 = FindDominatingLoad(Sel->getOperand(2)); + assert(L1 && L2 && + "must be able to obtain dominating loads for both value operands of " + "the select"); + Value *NewSel = SelectInst::Create(Sel->getCondition(), L1, L2, "", Sel); + Res = NewSel; } else { llvm_unreachable("Should not materialize value from dead block"); } @@ -1157,6 +1197,37 @@ return false; } +/// Check if a load from pointer-select \p Address in \p DepBB can be converted +/// to a value select. The following conditions need to be satisfied: +/// 1. The pointer select (\p Address) must be defined in \p DepBB. +/// 2. Both value operands of the pointer select must be loaded in the same +/// basic block, before the pointer select. +/// 3. \p DepBB must be read-only. +static Optional +tryToConvertLoadOfPtrSelect(BasicBlock *DepBB, Value *Address, + DominatorTree &DT) { + + auto *Sel = dyn_cast_or_null(Address); + if (!Sel || DepBB != Sel->getParent()) + return None; + + auto FindDominatingLoad = [Sel, &DT](Value *Ptr) -> LoadInst * { + for (Value *U : Ptr->users()) { + auto *LI = dyn_cast(U); + if (LI && LI->getParent() == Sel->getParent() && DT.dominates(LI, Sel)) + return LI; + } + return nullptr; + }; + + auto *L1 = FindDominatingLoad(Sel->getOperand(1)); + auto *L2 = FindDominatingLoad(Sel->getOperand(2)); + if (!L1 || !L2) + return None; + + return AvailableValueInBlock::getSelect(Sel->getParent(), + cast(Address)); +} void GVNPass::AnalyzeLoadAvailability(LoadInst *Load, LoadDepVect &Deps, AvailValInBlkVect &ValuesPerBlock, UnavailBlkVect &UnavailableBlocks) { @@ -1176,16 +1247,21 @@ continue; } - if (!DepInfo.isDef() && !DepInfo.isClobber()) { - UnavailableBlocks.push_back(DepBB); - continue; - } - // The address being loaded in this non-local block may not be the same as // the pointer operand of the load if PHI translation occurs. Make sure // to consider the right address. Value *Address = Deps[i].getAddress(); + if (!DepInfo.isDef() && !DepInfo.isClobber()) { + if (auto R = + tryToConvertLoadOfPtrSelect(DepBB, Address, getDominatorTree())) { + ValuesPerBlock.push_back(*R); + continue; + } + UnavailableBlocks.push_back(DepBB); + continue; + } + AvailableValue AV; if (AnalyzeLoadAvailability(Load, DepInfo, Address, AV)) { // subtlety: because we know this was a non-local dependency, we know diff --git a/llvm/test/Transforms/GVN/PRE/pre-loop-load-through-select.ll b/llvm/test/Transforms/GVN/PRE/pre-loop-load-through-select.ll --- a/llvm/test/Transforms/GVN/PRE/pre-loop-load-through-select.ll +++ b/llvm/test/Transforms/GVN/PRE/pre-loop-load-through-select.ll @@ -5,13 +5,15 @@ ; CHECK-LABEL: @test_pointer_phi_select_same_object( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[START_PTR:%.*]] = getelementptr inbounds i32, i32* [[PTR:%.*]], i64 1 +; CHECK-NEXT: [[L_2_PRE:%.*]] = load i32, i32* [[PTR]], align 4 ; CHECK-NEXT: br label [[LOOP:%.*]] ; CHECK: loop: -; CHECK-NEXT: [[PTR_IV:%.*]] = phi i32* [ [[START_PTR]], [[ENTRY:%.*]] ], [ [[PTR_IV_NEXT:%.*]], [[LOOP]] ] +; CHECK-NEXT: [[L_2:%.*]] = phi i32 [ [[L_2_PRE]], [[ENTRY:%.*]] ], [ [[TMP0:%.*]], [[LOOP]] ] +; CHECK-NEXT: [[PTR_IV:%.*]] = phi i32* [ [[START_PTR]], [[ENTRY]] ], [ [[PTR_IV_NEXT:%.*]], [[LOOP]] ] ; CHECK-NEXT: [[MIN_PTR:%.*]] = phi i32* [ [[PTR]], [[ENTRY]] ], [ [[MIN_SELECT:%.*]], [[LOOP]] ] ; CHECK-NEXT: [[L_1:%.*]] = load i32, i32* [[PTR_IV]], align 4 -; CHECK-NEXT: [[L_2:%.*]] = load i32, i32* [[MIN_PTR]], align 4 ; CHECK-NEXT: [[CMP_I_I_I:%.*]] = icmp ult i32 [[L_1]], [[L_2]] +; CHECK-NEXT: [[TMP0]] = select i1 [[CMP_I_I_I]], i32 [[L_1]], i32 [[L_2]] ; CHECK-NEXT: [[MIN_SELECT]] = select i1 [[CMP_I_I_I]], i32* [[PTR_IV]], i32* [[MIN_PTR]] ; CHECK-NEXT: [[PTR_IV_NEXT]] = getelementptr inbounds i32, i32* [[PTR_IV]], i64 1 ; CHECK-NEXT: [[EC:%.*]] = icmp eq i32* [[PTR_IV_NEXT]], [[END:%.*]] @@ -44,13 +46,15 @@ ; CHECK-LABEL: @test_pointer_phi_select_same_object_lcssa( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[START_PTR:%.*]] = getelementptr inbounds i32, i32* [[PTR:%.*]], i64 1 +; CHECK-NEXT: [[L_2_PRE:%.*]] = load i32, i32* [[PTR]], align 4 ; CHECK-NEXT: br label [[LOOP:%.*]] ; CHECK: loop: -; CHECK-NEXT: [[PTR_IV:%.*]] = phi i32* [ [[START_PTR]], [[ENTRY:%.*]] ], [ [[PTR_IV_NEXT:%.*]], [[LOOP]] ] +; CHECK-NEXT: [[L_2:%.*]] = phi i32 [ [[L_2_PRE]], [[ENTRY:%.*]] ], [ [[TMP0:%.*]], [[LOOP]] ] +; CHECK-NEXT: [[PTR_IV:%.*]] = phi i32* [ [[START_PTR]], [[ENTRY]] ], [ [[PTR_IV_NEXT:%.*]], [[LOOP]] ] ; CHECK-NEXT: [[MIN_PTR:%.*]] = phi i32* [ [[PTR]], [[ENTRY]] ], [ [[MIN_SELECT:%.*]], [[LOOP]] ] ; CHECK-NEXT: [[L_1:%.*]] = load i32, i32* [[PTR_IV]], align 4 -; CHECK-NEXT: [[L_2:%.*]] = load i32, i32* [[MIN_PTR]], align 4 ; CHECK-NEXT: [[CMP_I_I_I:%.*]] = icmp ult i32 [[L_1]], [[L_2]] +; CHECK-NEXT: [[TMP0]] = select i1 [[CMP_I_I_I]], i32 [[L_1]], i32 [[L_2]] ; CHECK-NEXT: [[MIN_SELECT]] = select i1 [[CMP_I_I_I]], i32* [[PTR_IV]], i32* [[MIN_PTR]] ; CHECK-NEXT: [[PTR_IV_NEXT]] = getelementptr inbounds i32, i32* [[PTR_IV]], i64 1 ; CHECK-NEXT: [[EC:%.*]] = icmp eq i32* [[PTR_IV_NEXT]], [[END:%.*]] @@ -83,13 +87,15 @@ define i32 @test_pointer_phi_select_different_objects(i32* %A, i32 *%B, i32* %end) { ; CHECK-LABEL: @test_pointer_phi_select_different_objects( ; CHECK-NEXT: entry: +; CHECK-NEXT: [[L_2_PRE:%.*]] = load i32, i32* [[B:%.*]], align 4 ; CHECK-NEXT: br label [[LOOP:%.*]] ; CHECK: loop: -; CHECK-NEXT: [[PTR_IV:%.*]] = phi i32* [ [[A:%.*]], [[ENTRY:%.*]] ], [ [[PTR_IV_NEXT:%.*]], [[LOOP]] ] -; CHECK-NEXT: [[MIN_PTR:%.*]] = phi i32* [ [[B:%.*]], [[ENTRY]] ], [ [[MIN_SELECT:%.*]], [[LOOP]] ] +; CHECK-NEXT: [[L_2:%.*]] = phi i32 [ [[L_2_PRE]], [[ENTRY:%.*]] ], [ [[TMP0:%.*]], [[LOOP]] ] +; CHECK-NEXT: [[PTR_IV:%.*]] = phi i32* [ [[A:%.*]], [[ENTRY]] ], [ [[PTR_IV_NEXT:%.*]], [[LOOP]] ] +; CHECK-NEXT: [[MIN_PTR:%.*]] = phi i32* [ [[B]], [[ENTRY]] ], [ [[MIN_SELECT:%.*]], [[LOOP]] ] ; CHECK-NEXT: [[L_1:%.*]] = load i32, i32* [[PTR_IV]], align 4 -; CHECK-NEXT: [[L_2:%.*]] = load i32, i32* [[MIN_PTR]], align 4 ; CHECK-NEXT: [[CMP_I_I_I:%.*]] = icmp ult i32 [[L_1]], [[L_2]] +; CHECK-NEXT: [[TMP0]] = select i1 [[CMP_I_I_I]], i32 [[L_1]], i32 [[L_2]] ; CHECK-NEXT: [[MIN_SELECT]] = select i1 [[CMP_I_I_I]], i32* [[PTR_IV]], i32* [[MIN_PTR]] ; CHECK-NEXT: [[PTR_IV_NEXT]] = getelementptr inbounds i32, i32* [[PTR_IV]], i64 1 ; CHECK-NEXT: [[EC:%.*]] = icmp eq i32* [[PTR_IV_NEXT]], [[END:%.*]] @@ -121,13 +127,15 @@ ; CHECK-LABEL: @test_pointer_phi_select_same_object_multiple_loads_1( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[START_PTR:%.*]] = getelementptr inbounds i32, i32* [[PTR:%.*]], i64 1 +; CHECK-NEXT: [[L_2_PRE:%.*]] = load i32, i32* [[PTR]], align 4 ; CHECK-NEXT: br label [[LOOP:%.*]] ; CHECK: loop: -; CHECK-NEXT: [[PTR_IV:%.*]] = phi i32* [ [[START_PTR]], [[ENTRY:%.*]] ], [ [[PTR_IV_NEXT:%.*]], [[LOOP]] ] +; CHECK-NEXT: [[L_2:%.*]] = phi i32 [ [[L_2_PRE]], [[ENTRY:%.*]] ], [ [[TMP0:%.*]], [[LOOP]] ] +; CHECK-NEXT: [[PTR_IV:%.*]] = phi i32* [ [[START_PTR]], [[ENTRY]] ], [ [[PTR_IV_NEXT:%.*]], [[LOOP]] ] ; CHECK-NEXT: [[MIN_PTR:%.*]] = phi i32* [ [[PTR]], [[ENTRY]] ], [ [[MIN_SELECT:%.*]], [[LOOP]] ] ; CHECK-NEXT: [[L_1:%.*]] = load i32, i32* [[PTR_IV]], align 4 -; CHECK-NEXT: [[L_2:%.*]] = load i32, i32* [[MIN_PTR]], align 4 ; CHECK-NEXT: [[CMP_I_I_I:%.*]] = icmp ult i32 [[L_1]], [[L_2]] +; CHECK-NEXT: [[TMP0]] = select i1 [[CMP_I_I_I]], i32 [[L_1]], i32 [[L_2]] ; CHECK-NEXT: [[MIN_SELECT]] = select i1 [[CMP_I_I_I]], i32* [[PTR_IV]], i32* [[MIN_PTR]] ; CHECK-NEXT: [[PTR_IV_NEXT]] = getelementptr inbounds i32, i32* [[PTR_IV]], i64 1 ; CHECK-NEXT: [[EC:%.*]] = icmp eq i32* [[PTR_IV_NEXT]], [[END:%.*]] @@ -161,13 +169,15 @@ ; CHECK-LABEL: @test_pointer_phi_select_same_object_multiple_loads_2( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[START_PTR:%.*]] = getelementptr inbounds i32, i32* [[PTR:%.*]], i64 1 +; CHECK-NEXT: [[L_2_PRE:%.*]] = load i32, i32* [[PTR]], align 4 ; CHECK-NEXT: br label [[LOOP:%.*]] ; CHECK: loop: -; CHECK-NEXT: [[PTR_IV:%.*]] = phi i32* [ [[START_PTR]], [[ENTRY:%.*]] ], [ [[PTR_IV_NEXT:%.*]], [[LOOP]] ] +; CHECK-NEXT: [[L_2:%.*]] = phi i32 [ [[L_2_PRE]], [[ENTRY:%.*]] ], [ [[TMP0:%.*]], [[LOOP]] ] +; CHECK-NEXT: [[PTR_IV:%.*]] = phi i32* [ [[START_PTR]], [[ENTRY]] ], [ [[PTR_IV_NEXT:%.*]], [[LOOP]] ] ; CHECK-NEXT: [[MIN_PTR:%.*]] = phi i32* [ [[PTR]], [[ENTRY]] ], [ [[MIN_SELECT:%.*]], [[LOOP]] ] ; CHECK-NEXT: [[L_1:%.*]] = load i32, i32* [[PTR_IV]], align 4 -; CHECK-NEXT: [[L_2:%.*]] = load i32, i32* [[MIN_PTR]], align 4 ; CHECK-NEXT: [[CMP_I_I_I:%.*]] = icmp ult i32 [[L_1]], [[L_2]] +; CHECK-NEXT: [[TMP0]] = select i1 [[CMP_I_I_I]], i32 [[L_1]], i32 [[L_2]] ; CHECK-NEXT: [[MIN_SELECT]] = select i1 [[CMP_I_I_I]], i32* [[PTR_IV]], i32* [[MIN_PTR]] ; CHECK-NEXT: [[PTR_IV_NEXT]] = getelementptr inbounds i32, i32* [[PTR_IV]], i64 1 ; CHECK-NEXT: [[EC:%.*]] = icmp eq i32* [[PTR_IV_NEXT]], [[END:%.*]] @@ -242,13 +252,15 @@ ; CHECK-NEXT: [[START_PTR:%.*]] = getelementptr inbounds i32, i32* [[PTR:%.*]], i64 1 ; CHECK-NEXT: br i1 [[C:%.*]], label [[EXIT:%.*]], label [[LOOP_PREHEADER:%.*]] ; CHECK: loop.preheader: +; CHECK-NEXT: [[L_2_PRE:%.*]] = load i32, i32* [[PTR]], align 4 ; CHECK-NEXT: br label [[LOOP:%.*]] ; CHECK: loop: +; CHECK-NEXT: [[L_2:%.*]] = phi i32 [ [[TMP0:%.*]], [[LOOP]] ], [ [[L_2_PRE]], [[LOOP_PREHEADER]] ] ; CHECK-NEXT: [[PTR_IV:%.*]] = phi i32* [ [[PTR_IV_NEXT:%.*]], [[LOOP]] ], [ [[START_PTR]], [[LOOP_PREHEADER]] ] ; CHECK-NEXT: [[MIN_PTR:%.*]] = phi i32* [ [[MIN_SELECT:%.*]], [[LOOP]] ], [ [[PTR]], [[LOOP_PREHEADER]] ] ; CHECK-NEXT: [[L_1:%.*]] = load i32, i32* [[PTR_IV]], align 4 -; CHECK-NEXT: [[L_2:%.*]] = load i32, i32* [[MIN_PTR]], align 4 ; CHECK-NEXT: [[CMP_I_I_I:%.*]] = icmp ult i32 [[L_1]], [[L_2]] +; CHECK-NEXT: [[TMP0]] = select i1 [[CMP_I_I_I]], i32 [[L_1]], i32 [[L_2]] ; CHECK-NEXT: [[MIN_SELECT]] = select i1 [[CMP_I_I_I]], i32* [[PTR_IV]], i32* [[MIN_PTR]] ; CHECK-NEXT: [[PTR_IV_NEXT]] = getelementptr inbounds i32, i32* [[PTR_IV]], i64 1 ; CHECK-NEXT: [[EC:%.*]] = icmp eq i32* [[PTR_IV_NEXT]], [[END:%.*]] @@ -661,13 +673,15 @@ ; CHECK-LABEL: @test_pointer_phi_select_same_object_ptr_use_cycle( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[START_PTR:%.*]] = getelementptr inbounds i32, i32* [[PTR:%.*]], i64 1 +; CHECK-NEXT: [[L_2_PRE:%.*]] = load i32, i32* [[PTR]], align 4 ; CHECK-NEXT: br label [[LOOP:%.*]] ; CHECK: loop: -; CHECK-NEXT: [[PTR_IV:%.*]] = phi i32* [ [[START_PTR]], [[ENTRY:%.*]] ], [ [[PTR_IV_NEXT:%.*]], [[LOOP]] ] +; CHECK-NEXT: [[L_2:%.*]] = phi i32 [ [[L_2_PRE]], [[ENTRY:%.*]] ], [ [[TMP0:%.*]], [[LOOP]] ] +; CHECK-NEXT: [[PTR_IV:%.*]] = phi i32* [ [[START_PTR]], [[ENTRY]] ], [ [[PTR_IV_NEXT:%.*]], [[LOOP]] ] ; CHECK-NEXT: [[MIN_PTR:%.*]] = phi i32* [ [[PTR]], [[ENTRY]] ], [ [[MIN_SELECT:%.*]], [[LOOP]] ] ; CHECK-NEXT: [[L_1:%.*]] = load i32, i32* [[PTR_IV]], align 4 -; CHECK-NEXT: [[L_2:%.*]] = load i32, i32* [[MIN_PTR]], align 4 ; CHECK-NEXT: [[CMP_I_I_I:%.*]] = icmp ult i32 [[L_1]], [[L_2]] +; CHECK-NEXT: [[TMP0]] = select i1 [[CMP_I_I_I]], i32 [[L_1]], i32 [[L_2]] ; CHECK-NEXT: [[MIN_SELECT]] = select i1 [[CMP_I_I_I]], i32* [[PTR_IV]], i32* [[MIN_PTR]] ; CHECK-NEXT: [[PTR_IV_NEXT]] = getelementptr inbounds i32, i32* [[PTR_IV]], i64 1 ; CHECK-NEXT: [[EC:%.*]] = icmp eq i32* [[PTR_IV_NEXT]], [[END:%.*]] @@ -706,13 +720,15 @@ ; CHECK-LABEL: @test_pointer_phi_select_same_object_maybe_clobbered_in_exit( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[START_PTR:%.*]] = getelementptr inbounds i32, i32* [[PTR:%.*]], i64 1 +; CHECK-NEXT: [[L_2_PRE:%.*]] = load i32, i32* [[PTR]], align 4 ; CHECK-NEXT: br label [[LOOP:%.*]] ; CHECK: loop: -; CHECK-NEXT: [[PTR_IV:%.*]] = phi i32* [ [[START_PTR]], [[ENTRY:%.*]] ], [ [[PTR_IV_NEXT:%.*]], [[LOOP]] ] +; CHECK-NEXT: [[L_2:%.*]] = phi i32 [ [[L_2_PRE]], [[ENTRY:%.*]] ], [ [[TMP0:%.*]], [[LOOP]] ] +; CHECK-NEXT: [[PTR_IV:%.*]] = phi i32* [ [[START_PTR]], [[ENTRY]] ], [ [[PTR_IV_NEXT:%.*]], [[LOOP]] ] ; CHECK-NEXT: [[MIN_PTR:%.*]] = phi i32* [ [[PTR]], [[ENTRY]] ], [ [[MIN_SELECT:%.*]], [[LOOP]] ] ; CHECK-NEXT: [[L_1:%.*]] = load i32, i32* [[PTR_IV]], align 4 -; CHECK-NEXT: [[L_2:%.*]] = load i32, i32* [[MIN_PTR]], align 4 ; CHECK-NEXT: [[CMP_I_I_I:%.*]] = icmp ult i32 [[L_1]], [[L_2]] +; CHECK-NEXT: [[TMP0]] = select i1 [[CMP_I_I_I]], i32 [[L_1]], i32 [[L_2]] ; CHECK-NEXT: [[MIN_SELECT]] = select i1 [[CMP_I_I_I]], i32* [[PTR_IV]], i32* [[MIN_PTR]] ; CHECK-NEXT: [[PTR_IV_NEXT]] = getelementptr inbounds i32, i32* [[PTR_IV]], i64 1 ; CHECK-NEXT: [[EC:%.*]] = icmp eq i32* [[PTR_IV_NEXT]], [[END:%.*]] @@ -747,13 +763,15 @@ ; CHECK-LABEL: @test_pointer_phi_select_same_object_maybe_clobbered_in_exit_2( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[START_PTR:%.*]] = getelementptr inbounds i32, i32* [[PTR:%.*]], i64 1 +; CHECK-NEXT: [[L_2_PRE:%.*]] = load i32, i32* [[PTR]], align 4 ; CHECK-NEXT: br label [[LOOP:%.*]] ; CHECK: loop: -; CHECK-NEXT: [[PTR_IV:%.*]] = phi i32* [ [[START_PTR]], [[ENTRY:%.*]] ], [ [[PTR_IV_NEXT:%.*]], [[LOOP]] ] +; CHECK-NEXT: [[L_2:%.*]] = phi i32 [ [[L_2_PRE]], [[ENTRY:%.*]] ], [ [[TMP0:%.*]], [[LOOP]] ] +; CHECK-NEXT: [[PTR_IV:%.*]] = phi i32* [ [[START_PTR]], [[ENTRY]] ], [ [[PTR_IV_NEXT:%.*]], [[LOOP]] ] ; CHECK-NEXT: [[MIN_PTR:%.*]] = phi i32* [ [[PTR]], [[ENTRY]] ], [ [[MIN_SELECT:%.*]], [[LOOP]] ] ; CHECK-NEXT: [[L_1:%.*]] = load i32, i32* [[PTR_IV]], align 4 -; CHECK-NEXT: [[L_2:%.*]] = load i32, i32* [[MIN_PTR]], align 4 ; CHECK-NEXT: [[CMP_I_I_I:%.*]] = icmp ult i32 [[L_1]], [[L_2]] +; CHECK-NEXT: [[TMP0]] = select i1 [[CMP_I_I_I]], i32 [[L_1]], i32 [[L_2]] ; CHECK-NEXT: [[MIN_SELECT]] = select i1 [[CMP_I_I_I]], i32* [[PTR_IV]], i32* [[MIN_PTR]] ; CHECK-NEXT: [[PTR_IV_NEXT]] = getelementptr inbounds i32, i32* [[PTR_IV]], i64 1 ; CHECK-NEXT: [[EC:%.*]] = icmp eq i32* [[PTR_IV_NEXT]], [[END:%.*]] @@ -794,13 +812,15 @@ ; CHECK-LABEL: @test_pointer_phi_select_same_object_invoke_in_chain( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[START_PTR:%.*]] = getelementptr inbounds i32, i32* [[PTR:%.*]], i64 1 +; CHECK-NEXT: [[L_2_PRE:%.*]] = load i32, i32* [[PTR]], align 4 ; CHECK-NEXT: br label [[LOOP:%.*]] ; CHECK: loop: -; CHECK-NEXT: [[PTR_IV:%.*]] = phi i32* [ [[START_PTR]], [[ENTRY:%.*]] ], [ [[PTR_IV_NEXT:%.*]], [[LOOP]] ] +; CHECK-NEXT: [[L_2:%.*]] = phi i32 [ [[L_2_PRE]], [[ENTRY:%.*]] ], [ [[TMP0:%.*]], [[LOOP]] ] +; CHECK-NEXT: [[PTR_IV:%.*]] = phi i32* [ [[START_PTR]], [[ENTRY]] ], [ [[PTR_IV_NEXT:%.*]], [[LOOP]] ] ; CHECK-NEXT: [[MIN_PTR:%.*]] = phi i32* [ [[PTR]], [[ENTRY]] ], [ [[MIN_SELECT:%.*]], [[LOOP]] ] ; CHECK-NEXT: [[L_1:%.*]] = load i32, i32* [[PTR_IV]], align 4 -; CHECK-NEXT: [[L_2:%.*]] = load i32, i32* [[MIN_PTR]], align 4 ; CHECK-NEXT: [[CMP_I_I_I:%.*]] = icmp ult i32 [[L_1]], [[L_2]] +; CHECK-NEXT: [[TMP0]] = select i1 [[CMP_I_I_I]], i32 [[L_1]], i32 [[L_2]] ; CHECK-NEXT: [[MIN_SELECT]] = select i1 [[CMP_I_I_I]], i32* [[PTR_IV]], i32* [[MIN_PTR]] ; CHECK-NEXT: [[PTR_IV_NEXT]] = getelementptr inbounds i32, i32* [[PTR_IV]], i64 1 ; CHECK-NEXT: [[EC:%.*]] = icmp eq i32* [[PTR_IV_NEXT]], [[END:%.*]] @@ -893,17 +913,23 @@ ; CHECK-LABEL: @test_pointer_phi_used_by_others_in_loop_1( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[START_PTR:%.*]] = getelementptr inbounds i32, i32* [[PTR:%.*]], i64 1 +; CHECK-NEXT: [[L_2_PRE:%.*]] = load i32, i32* [[PTR]], align 4 ; CHECK-NEXT: br label [[LOOP:%.*]] ; CHECK: loop: -; CHECK-NEXT: [[PTR_IV:%.*]] = phi i32* [ [[START_PTR]], [[ENTRY:%.*]] ], [ [[PTR_IV_NEXT:%.*]], [[LOOP]] ] -; CHECK-NEXT: [[MIN_PTR:%.*]] = phi i32* [ [[PTR]], [[ENTRY]] ], [ [[MIN_SELECT:%.*]], [[LOOP]] ] +; CHECK-NEXT: [[L_3:%.*]] = phi i32 [ [[L_2_PRE]], [[ENTRY:%.*]] ], [ [[L_3_PRE:%.*]], [[LOOP_LOOP_CRIT_EDGE:%.*]] ] +; CHECK-NEXT: [[L_2:%.*]] = phi i32 [ [[L_2_PRE]], [[ENTRY]] ], [ [[TMP0:%.*]], [[LOOP_LOOP_CRIT_EDGE]] ] +; CHECK-NEXT: [[PTR_IV:%.*]] = phi i32* [ [[START_PTR]], [[ENTRY]] ], [ [[PTR_IV_NEXT:%.*]], [[LOOP_LOOP_CRIT_EDGE]] ] +; CHECK-NEXT: [[MIN_PTR:%.*]] = phi i32* [ [[PTR]], [[ENTRY]] ], [ [[MIN_SELECT:%.*]], [[LOOP_LOOP_CRIT_EDGE]] ] ; CHECK-NEXT: [[L_1:%.*]] = load i32, i32* [[PTR_IV]], align 4 -; CHECK-NEXT: [[L_2:%.*]] = load i32, i32* [[MIN_PTR]], align 4 ; CHECK-NEXT: [[CMP_I_I_I:%.*]] = icmp ult i32 [[L_1]], [[L_2]] +; CHECK-NEXT: [[TMP0]] = select i1 [[CMP_I_I_I]], i32 [[L_1]], i32 [[L_2]] ; CHECK-NEXT: [[MIN_SELECT]] = select i1 [[CMP_I_I_I]], i32* [[PTR_IV]], i32* [[MIN_PTR]] -; CHECK-NEXT: [[PTR_IV_NEXT]] = getelementptr inbounds i32, i32* [[PTR_IV]], i32 [[L_2]] +; CHECK-NEXT: [[PTR_IV_NEXT]] = getelementptr inbounds i32, i32* [[PTR_IV]], i32 [[L_3]] ; CHECK-NEXT: [[EC:%.*]] = icmp eq i32* [[PTR_IV_NEXT]], [[END:%.*]] -; CHECK-NEXT: br i1 [[EC]], label [[EXIT:%.*]], label [[LOOP]] +; CHECK-NEXT: br i1 [[EC]], label [[EXIT:%.*]], label [[LOOP_LOOP_CRIT_EDGE]] +; CHECK: loop.loop_crit_edge: +; CHECK-NEXT: [[L_3_PRE]] = load i32, i32* [[MIN_SELECT]], align 4 +; CHECK-NEXT: br label [[LOOP]] ; CHECK: exit: ; CHECK-NEXT: [[RES:%.*]] = load i32, i32* [[MIN_SELECT]], align 4 ; CHECK-NEXT: ret i32 [[RES]] @@ -933,13 +959,15 @@ ; CHECK-LABEL: @test_pointer_phi_used_by_others_in_loop_2( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[START_PTR:%.*]] = getelementptr inbounds i32, i32* [[PTR:%.*]], i64 1 +; CHECK-NEXT: [[L_2_PRE:%.*]] = load i32, i32* [[PTR]], align 4 ; CHECK-NEXT: br label [[LOOP:%.*]] ; CHECK: loop: -; CHECK-NEXT: [[PTR_IV:%.*]] = phi i32* [ [[START_PTR]], [[ENTRY:%.*]] ], [ [[PTR_IV_NEXT:%.*]], [[LOOP]] ] +; CHECK-NEXT: [[L_2:%.*]] = phi i32 [ [[L_2_PRE]], [[ENTRY:%.*]] ], [ [[TMP0:%.*]], [[LOOP]] ] +; CHECK-NEXT: [[PTR_IV:%.*]] = phi i32* [ [[START_PTR]], [[ENTRY]] ], [ [[PTR_IV_NEXT:%.*]], [[LOOP]] ] ; CHECK-NEXT: [[MIN_PTR:%.*]] = phi i32* [ [[PTR]], [[ENTRY]] ], [ [[MIN_SELECT:%.*]], [[LOOP]] ] ; CHECK-NEXT: [[L_1:%.*]] = load i32, i32* [[PTR_IV]], align 4 -; CHECK-NEXT: [[L_2:%.*]] = load i32, i32* [[MIN_PTR]], align 4 ; CHECK-NEXT: [[CMP_I_I_I:%.*]] = icmp ult i32 [[L_1]], [[L_2]] +; CHECK-NEXT: [[TMP0]] = select i1 [[CMP_I_I_I]], i32 [[L_1]], i32 [[L_2]] ; CHECK-NEXT: [[MIN_SELECT]] = select i1 [[CMP_I_I_I]], i32* [[PTR_IV]], i32* [[MIN_PTR]] ; CHECK-NEXT: [[GEP_MIN_PTR:%.*]] = getelementptr inbounds i32, i32* [[MIN_PTR]], i32 1 ; CHECK-NEXT: [[L_3:%.*]] = load i32, i32* [[GEP_MIN_PTR]], align 4