diff --git a/llvm/include/llvm/Analysis/MemoryDependenceAnalysis.h b/llvm/include/llvm/Analysis/MemoryDependenceAnalysis.h --- a/llvm/include/llvm/Analysis/MemoryDependenceAnalysis.h +++ b/llvm/include/llvm/Analysis/MemoryDependenceAnalysis.h @@ -19,6 +19,7 @@ #include "llvm/ADT/PointerSumType.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/Analysis/MemoryLocation.h" +#include "llvm/Analysis/PHITransAddr.h" #include "llvm/IR/PassManager.h" #include "llvm/IR/PredIteratorCache.h" #include "llvm/IR/ValueHandle.h" @@ -31,7 +32,6 @@ class AssumptionCache; class BatchAAResults; class DominatorTree; -class PHITransAddr; /// A memory dependence query can return one of three different answers. class MemDepResult { @@ -77,11 +77,6 @@ /// calls or memory use intrinsics with identical callees and no /// intervening clobbers. No validation is done that the operands to /// the calls are the same. - /// 4. For loads and stores, this could be a select instruction that - /// defines pointer to this memory location. In this case, users can - /// find non-clobbered Defs for both select values that are reaching - // the desired memory location (there is still a guarantee that there - // are no clobbers between analyzed memory location and select). Def, /// This marker indicates that the query has no known dependency in the @@ -103,6 +98,8 @@ /// This marker indicates that the query has no dependency in the specified /// function. NonFuncLocal, + /// This marker indicates that the query depends from select instruction. + Select, /// This marker indicates that the query dependency is unknown. Unknown }; @@ -135,6 +132,9 @@ static MemDepResult getNonFuncLocal() { return MemDepResult(ValueTy::create(NonFuncLocal)); } + static MemDepResult getSelect() { + return MemDepResult(ValueTy::create(Select)); + } static MemDepResult getUnknown() { return MemDepResult(ValueTy::create(Unknown)); } @@ -162,6 +162,12 @@ return Value.is() && Value.cast() == NonFuncLocal; } + /// Tests if this MemDepResult represents a query that has a dependency from + /// the select instruction. + bool isSelect() const { + return Value.is() && Value.cast() == Select; + } + /// Tests if this MemDepResult represents a query which cannot and/or will /// not be computed. bool isUnknown() const { @@ -230,10 +236,11 @@ /// (potentially phi translated) address that was live in the block. class NonLocalDepResult { NonLocalDepEntry Entry; - Value *Address; + SelectAddr Address; public: - NonLocalDepResult(BasicBlock *BB, MemDepResult Result, Value *Address) + NonLocalDepResult(BasicBlock *BB, MemDepResult Result, + const SelectAddr &Address) : Entry(BB, Result), Address(Address) {} // BB is the sort key, it can't be changed. @@ -254,7 +261,7 @@ /// a cached result and that address was deleted. /// /// The address is always null for a non-local 'call' dependence. - Value *getAddress() const { return Address; } + SelectAddr getAddress() const { return Address; } }; /// Provides a lazy, caching interface for making common memory aliasing diff --git a/llvm/include/llvm/Analysis/PHITransAddr.h b/llvm/include/llvm/Analysis/PHITransAddr.h --- a/llvm/include/llvm/Analysis/PHITransAddr.h +++ b/llvm/include/llvm/Analysis/PHITransAddr.h @@ -15,6 +15,7 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/IR/Instruction.h" +#include "llvm/IR/Instructions.h" namespace llvm { class AssumptionCache; @@ -22,6 +23,40 @@ class DataLayout; class TargetLibraryInfo; +// SelectAddr - storage of normal Value address or Condition value and pair of +// addresses for true and false variant of select dependency. If Addrs are not +// present (both values are nullptr), V is a normal address; otherwise, V is a +// select condition and SelectAddrs are "true" and "false" addresses. +class SelectAddr { +public: + using SelectAddrs = std::pair; + + SelectAddr(Value *Addr) : V(Addr), Addrs(nullptr, nullptr) {} + SelectAddr(Value *Cond, SelectAddrs Addrs) : V(Cond), Addrs(Addrs) { + assert(Cond && "Condition must be present"); + assert(hasSelectAddrs() && "Addrs must be present"); + }; + Value *getAddr() const { + assert(!hasSelectAddrs()); + return V; + } + std::pair getSelectCondAndAddrs() const { + // If Addrs is present, return it. + if (hasSelectAddrs()) + return {V, Addrs}; + // Otherwise V must be SelectInst; return condition and both addresses from + // its operands. + auto *SI = cast(V); + return {SI->getCondition(), {SI->getTrueValue(), SI->getFalseValue()}}; + } + +private: + Value *V; + SelectAddrs Addrs; + + bool hasSelectAddrs() const { return Addrs.first && Addrs.second; } +}; + /// PHITransAddr - An address value which tracks and handles phi translation. /// As we walk "up" the CFG through predecessors, we need to ensure that the /// address we're tracking is kept up to date. For example, if we're analyzing @@ -57,6 +92,15 @@ Value *getAddr() const { return Addr; } + /// getSelectCondition - if address has select input, return its condition + /// (otherwise nullptr). + Value *getSelectCondition() const { + for (auto *I : InstInputs) + if (auto *SI = dyn_cast(I)) + return SI->getCondition(); + return nullptr; + } + /// needsPHITranslationFromBlock - Return true if moving from the specified /// BasicBlock to its predecessors requires PHI translation. bool needsPHITranslationFromBlock(BasicBlock *BB) const { @@ -78,6 +122,12 @@ Value *translateValue(BasicBlock *CurBB, BasicBlock *PredBB, const DominatorTree *DT, bool MustDominate); + /// translateValue - PHI translate the current address from \p CurBB to \p + /// PredBB, and if the resulted address depends on select instructions with \p + /// Cond predicate, translate both cases of this selects. + SelectAddr::SelectAddrs translateValue(BasicBlock *CurBB, BasicBlock *PredBB, + const DominatorTree *DT, Value *Cond); + /// translateWithInsertion - PHI translate this value into the specified /// predecessor block, inserting a computation of the value if it is /// unavailable. @@ -97,8 +147,13 @@ bool verify() const; private: + /// translateSubExpr - recursively translate value \p V from \p CurBB to \p + /// PredBB, and if value depends from selects with \p Cond condition, also + /// translate it through these selects with \p CondVal predicate. Return + /// nullptr on failure. Value *translateSubExpr(Value *V, BasicBlock *CurBB, BasicBlock *PredBB, - const DominatorTree *DT); + const DominatorTree *DT, Value *Cond = nullptr, + bool CondVal = false); /// insertTranslatedSubExpr - Insert a computation of the PHI translated /// version of 'V' for the edge PredBB->CurBB into the end of the PredBB diff --git a/llvm/include/llvm/Transforms/Scalar/GVN.h b/llvm/include/llvm/Transforms/Scalar/GVN.h --- a/llvm/include/llvm/Transforms/Scalar/GVN.h +++ b/llvm/include/llvm/Transforms/Scalar/GVN.h @@ -52,6 +52,7 @@ class NonLocalDepResult; class OptimizationRemarkEmitter; class PHINode; +class SelectAddr; class TargetLibraryInfo; class Value; /// A private "module" namespace for types and utilities used by GVN. These @@ -317,6 +318,12 @@ bool processNonLocalLoad(LoadInst *L); bool processAssumeIntrinsic(AssumeInst *II); + /// Given a load with Select dependency, determine if its value is available + /// for both sides of select (true and false values). + std::optional + AnalyzeSelectAvailability(LoadInst *Load, const SelectAddr &Addr, + Instruction *From); + /// Given a local dependency (Def or Clobber) determine if a value is /// available for the load. std::optional diff --git a/llvm/lib/Analysis/MemoryDependenceAnalysis.cpp b/llvm/lib/Analysis/MemoryDependenceAnalysis.cpp --- a/llvm/lib/Analysis/MemoryDependenceAnalysis.cpp +++ b/llvm/lib/Analysis/MemoryDependenceAnalysis.cpp @@ -23,7 +23,6 @@ #include "llvm/Analysis/AssumptionCache.h" #include "llvm/Analysis/MemoryBuiltins.h" #include "llvm/Analysis/MemoryLocation.h" -#include "llvm/Analysis/PHITransAddr.h" #include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/Analysis/ValueTracking.h" #include "llvm/IR/BasicBlock.h" @@ -592,10 +591,10 @@ return MemDepResult::getDef(Inst); } - // If we found a select instruction for MemLoc pointer, return it as Def + // If we found a select instruction for MemLoc pointer, return it as Select // dependency. if (isa(Inst) && MemLoc.Ptr == Inst) - return MemDepResult::getDef(Inst); + return MemDepResult::getSelect(); if (isInvariantLoad) continue; @@ -1346,8 +1345,20 @@ // predecessor, then we have to assume that the pointer is clobbered in // that predecessor. We can still do PRE of the load, which would insert // a computation of the pointer in this predecessor. - if (!PredPtrVal) + if (!PredPtrVal) { + // If we have translation failure, but there is a select input in + // address, try to translate both sides of it. + if (Value *Cond = PredPointer.getSelectCondition()) { + auto SelectAddrs = + PHITransAddr(Pointer).translateValue(BB, Pred, &DT, Cond); + if (SelectAddrs.first && SelectAddrs.second) { + Result.push_back(NonLocalDepResult(Pred, MemDepResult::getSelect(), + SelectAddr(Cond, SelectAddrs))); + continue; + } + } CanTranslate = false; + } // FIXME: it is entirely possible that PHI translating will end up with // the same value. Consider PHI translating something like: diff --git a/llvm/lib/Analysis/PHITransAddr.cpp b/llvm/lib/Analysis/PHITransAddr.cpp --- a/llvm/lib/Analysis/PHITransAddr.cpp +++ b/llvm/lib/Analysis/PHITransAddr.cpp @@ -16,7 +16,6 @@ #include "llvm/Config/llvm-config.h" #include "llvm/IR/Constants.h" #include "llvm/IR/Dominators.h" -#include "llvm/IR/Instructions.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; @@ -126,9 +125,14 @@ RemoveInstInputs(OpInst, InstInputs); } +/// translateSubExpr - recursively translate value \p V from \p CurBB to \p +/// PredBB, and if value depends from selects with \p Cond condition, also +/// translate it through these selects with \p CondVal predicate. Return nullptr +/// on failure. Value *PHITransAddr::translateSubExpr(Value *V, BasicBlock *CurBB, BasicBlock *PredBB, - const DominatorTree *DT) { + const DominatorTree *DT, Value *Cond, + bool CondVal) { // If this is a non-instruction value, it can't require PHI translation. Instruction *Inst = dyn_cast(V); if (!Inst) return V; @@ -151,8 +155,13 @@ InstInputs.erase(find(InstInputs, Inst)); // If this is a PHI, go ahead and translate it. - if (PHINode *PN = dyn_cast(Inst)) - return addAsInput(PN->getIncomingValueForBlock(PredBB)); + if (PHINode *PN = dyn_cast(Inst)) { + auto *V = PN->getIncomingValueForBlock(PredBB); + if (auto *SI = dyn_cast(V)) + if (SI->getCondition() == Cond) + return addAsInput(CondVal ? SI->getTrueValue() : SI->getFalseValue()); + return addAsInput(V); + } // If this is a non-phi value, and it is analyzable, we can incorporate it // into the expression by making all instruction operands be inputs. @@ -170,7 +179,8 @@ // operands need to be phi translated, and if so, reconstruct it. if (CastInst *Cast = dyn_cast(Inst)) { - Value *PHIIn = translateSubExpr(Cast->getOperand(0), CurBB, PredBB, DT); + Value *PHIIn = + translateSubExpr(Cast->getOperand(0), CurBB, PredBB, DT, Cond, CondVal); if (!PHIIn) return nullptr; if (PHIIn == Cast->getOperand(0)) return Cast; @@ -201,7 +211,7 @@ SmallVector GEPOps; bool AnyChanged = false; for (Value *Op : GEP->operands()) { - Value *GEPOp = translateSubExpr(Op, CurBB, PredBB, DT); + Value *GEPOp = translateSubExpr(Op, CurBB, PredBB, DT, Cond, CondVal); if (!GEPOp) return nullptr; AnyChanged |= GEPOp != Op; @@ -245,7 +255,8 @@ bool isNSW = cast(Inst)->hasNoSignedWrap(); bool isNUW = cast(Inst)->hasNoUnsignedWrap(); - Value *LHS = translateSubExpr(Inst->getOperand(0), CurBB, PredBB, DT); + Value *LHS = + translateSubExpr(Inst->getOperand(0), CurBB, PredBB, DT, Cond, CondVal); if (!LHS) return nullptr; // If the PHI translated LHS is an add of a constant, fold the immediates. @@ -315,6 +326,20 @@ return Addr; } +/// translateValue - PHI translate the current address from \p CurBB to \p +/// PredBB, and if the resulted address depends on select instructions with \p +/// Cond predicate, translate both cases of this selects. +SelectAddr::SelectAddrs PHITransAddr::translateValue(BasicBlock *CurBB, + BasicBlock *PredBB, + const DominatorTree *DT, + Value *Cond) { + Value *TrueAddr = + PHITransAddr(*this).translateSubExpr(Addr, CurBB, PredBB, DT, Cond, true); + Value *FalseAddr = PHITransAddr(*this).translateSubExpr(Addr, CurBB, PredBB, + DT, Cond, false); + return {TrueAddr, FalseAddr}; +} + /// PHITranslateWithInsertion - PHI translate this value into the specified /// predecessor block, inserting a computation of the value if it is /// unavailable. 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 @@ -200,6 +200,8 @@ unsigned Offset = 0; /// V1, V2 - The dominating non-clobbered values of SelectVal. Value *V1 = nullptr, *V2 = nullptr; + /// InsertPt - The position for select materialization. + Instruction *InsertPt = nullptr; static AvailableValue get(Value *V, unsigned Offset = 0) { AvailableValue Res; @@ -233,13 +235,15 @@ return Res; } - static AvailableValue getSelect(SelectInst *Sel, Value *V1, Value *V2) { + static AvailableValue getSelect(Value *Cond, Value *V1, Value *V2, + Instruction *InsertPt) { AvailableValue Res; - Res.Val = Sel; + Res.Val = Cond; Res.Kind = ValType::SelectVal; Res.Offset = 0; Res.V1 = V1; Res.V2 = V2; + Res.InsertPt = InsertPt; return Res; } @@ -264,11 +268,6 @@ return cast(Val); } - SelectInst *getSelectValue() const { - assert(isSelectValue() && "Wrong accessor"); - return cast(Val); - } - /// 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, @@ -300,11 +299,6 @@ return get(BB, AvailableValue::getUndef()); } - static AvailableValueInBlock getSelect(BasicBlock *BB, SelectInst *Sel, - Value *V1, Value *V2) { - return get(BB, AvailableValue::getSelect(Sel, V1, V2)); - } - /// 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 { @@ -1019,9 +1013,8 @@ << "\n\n\n"); } else if (isSelectValue()) { // Introduce a new value select for a load from an eligible pointer select. - SelectInst *Sel = getSelectValue(); assert(V1 && V2 && "both value operands of the select must be present"); - Res = SelectInst::Create(Sel->getCondition(), V1, V2, "", Sel); + Res = SelectInst::Create(Val, V1, V2, "", InsertPt); } else { llvm_unreachable("Should not materialize value from dead block"); } @@ -1132,6 +1125,32 @@ return nullptr; } +// Check if load with Addr dependent from select can be converted to select +// between load values. There must be no clobbers between the found loads and +// From instruction. +std::optional +GVNPass::AnalyzeSelectAvailability(LoadInst *Load, const SelectAddr &Addr, + Instruction *From) { + auto [Cond, SelectAddrs] = Addr.getSelectCondAndAddrs(); + auto [TrueAddr, FalseAddr] = SelectAddrs; + assert(TrueAddr && "Missing address of true side of select dependency"); + assert(TrueAddr->getType() == Load->getPointerOperandType() && + "Invalid address type of true side of select dependency"); + assert(FalseAddr && "Missing address of false side of select dependency"); + assert(FalseAddr->getType() == Load->getPointerOperandType() && + "Invalid address type of false side of select dependency"); + auto Loc = MemoryLocation::get(Load); + Value *V1 = findDominatingValue(Loc.getWithNewPtr(TrueAddr), Load->getType(), + From, getAliasAnalysis()); + if (!V1) + return std::nullopt; + Value *V2 = findDominatingValue(Loc.getWithNewPtr(FalseAddr), Load->getType(), + From, getAliasAnalysis()); + if (!V2) + return std::nullopt; + return AvailableValue::getSelect(Cond, V1, V2, From); +} + std::optional GVNPass::AnalyzeLoadAvailability(LoadInst *Load, MemDepResult DepInfo, Value *Address) { @@ -1246,25 +1265,6 @@ return AvailableValue::getLoad(LD); } - // Check if load with Addr dependent from select can be converted to select - // between load values. There must be no instructions between the found - // loads and DepInst that may clobber the loads. - if (auto *Sel = dyn_cast(DepInst)) { - assert(Sel->getType() == Load->getPointerOperandType()); - auto Loc = MemoryLocation::get(Load); - Value *V1 = - findDominatingValue(Loc.getWithNewPtr(Sel->getTrueValue()), - Load->getType(), DepInst, getAliasAnalysis()); - if (!V1) - return std::nullopt; - Value *V2 = - findDominatingValue(Loc.getWithNewPtr(Sel->getFalseValue()), - Load->getType(), DepInst, getAliasAnalysis()); - if (!V2) - return std::nullopt; - return AvailableValue::getSelect(Sel, V1, V2); - } - // Unknown def - must be conservative LLVM_DEBUG( // fast print dep, using operator<< on instruction is too slow. @@ -1283,6 +1283,7 @@ for (const auto &Dep : Deps) { BasicBlock *DepBB = Dep.getBB(); MemDepResult DepInfo = Dep.getResult(); + SelectAddr Addr = Dep.getAddress(); if (DeadBlocks.count(DepBB)) { // Dead dependent mem-op disguise as a load evaluating the same value @@ -1292,6 +1293,13 @@ } if (!DepInfo.isLocal()) { + if (DepInfo.isSelect()) + if (auto AV = + AnalyzeSelectAvailability(Load, Addr, DepBB->getTerminator())) { + ValuesPerBlock.push_back( + AvailableValueInBlock::get(DepBB, std::move(*AV))); + continue; + } UnavailableBlocks.push_back(DepBB); continue; } @@ -1299,7 +1307,7 @@ // 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. - if (auto AV = AnalyzeLoadAvailability(Load, DepInfo, Dep.getAddress())) { + if (auto AV = AnalyzeLoadAvailability(Load, DepInfo, Addr.getAddr())) { // subtlety: because we know this was a non-local dependency, we know // it's safe to materialize anywhere between the instruction within // DepInfo and the end of it's block. @@ -1738,7 +1746,7 @@ // If we had a phi translation failure, we'll have a single entry which is a // clobber in the current block. Reject this early. if (NumDeps == 1 && - !Deps[0].getResult().isDef() && !Deps[0].getResult().isClobber()) { + !Deps[0].getResult().isLocal() && !Deps[0].getResult().isSelect()) { LLVM_DEBUG(dbgs() << "GVN: non-local load "; Load->printAsOperand(dbgs()); dbgs() << " has unknown dependencies\n";); return false; @@ -2028,8 +2036,12 @@ if (Dep.isNonLocal()) return processNonLocalLoad(L); - // Only handle the local case below - if (!Dep.isLocal()) { + std::optional AV; + if (Dep.isLocal()) + AV = AnalyzeLoadAvailability(L, Dep, L->getPointerOperand()); + else if (Dep.isSelect()) + AV = AnalyzeSelectAvailability(L, L->getPointerOperand(), L); + else { // This might be a NonFuncLocal or an Unknown LLVM_DEBUG( // fast print dep, using operator<< on instruction is too slow. @@ -2038,7 +2050,6 @@ return false; } - auto AV = AnalyzeLoadAvailability(L, Dep, L->getPointerOperand()); if (!AV) return false; diff --git a/llvm/test/Transforms/GVN/PRE/pre-load-through-select.ll b/llvm/test/Transforms/GVN/PRE/pre-load-through-select.ll --- a/llvm/test/Transforms/GVN/PRE/pre-load-through-select.ll +++ b/llvm/test/Transforms/GVN/PRE/pre-load-through-select.ll @@ -9,8 +9,8 @@ ; CHECK-NEXT: [[L_1:%.*]] = load i32, ptr [[A:%.*]], align 4 ; CHECK-NEXT: [[L_2:%.*]] = load i32, ptr [[B:%.*]], 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]], ptr [[A]], ptr [[B]] +; CHECK-NEXT: [[TMP0:%.*]] = select i1 [[CMP_I_I_I]], i32 [[L_1]], i32 [[L_2]] ; CHECK-NEXT: br label [[EXIT:%.*]] ; CHECK: else: ; CHECK-NEXT: [[RES_2_PRE:%.*]] = load i32, ptr [[A]], align 4 @@ -48,8 +48,8 @@ ; CHECK: then: ; CHECK-NEXT: [[L_2:%.*]] = load i32, ptr [[B:%.*]], 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]], ptr [[A]], ptr [[B]] +; CHECK-NEXT: [[TMP0:%.*]] = select i1 [[CMP_I_I_I]], i32 [[L_1]], i32 [[L_2]] ; CHECK-NEXT: br label [[EXIT:%.*]] ; CHECK: else: ; CHECK-NEXT: [[RES_2_PRE:%.*]] = load i32, ptr [[C:%.*]], align 4 @@ -200,8 +200,8 @@ ; CHECK-NEXT: [[L_2:%.*]] = load i32, ptr [[B:%.*]], align 4 ; CHECK-NEXT: store i32 99, ptr [[C:%.*]], 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]], ptr [[A]], ptr [[B]] +; CHECK-NEXT: [[TMP0:%.*]] = select i1 [[CMP_I_I_I]], i32 [[L_1]], i32 [[L_2]] ; CHECK-NEXT: br label [[EXIT:%.*]] ; CHECK: else: ; CHECK-NEXT: [[RES_2_PRE:%.*]] = load i32, ptr [[A]], align 4 @@ -316,8 +316,8 @@ ; CHECK-NEXT: [[L_1:%.*]] = load i32, ptr [[A:%.*]], align 4 ; CHECK-NEXT: [[L_2:%.*]] = load i32, ptr [[B:%.*]], 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]], ptr [[A]], ptr [[B]] +; CHECK-NEXT: [[TMP0:%.*]] = select i1 [[CMP_I_I_I]], i32 [[L_1]], i32 [[L_2]] ; CHECK-NEXT: br label [[EXIT:%.*]] ; CHECK: else: ; CHECK-NEXT: [[RES_2_PRE:%.*]] = load i32, ptr [[A]], align 4 @@ -734,8 +734,8 @@ ; CHECK-NEXT: [[L_1:%.*]] = load i32, ptr [[A:%.*]], align 4 ; CHECK-NEXT: [[L_2:%.*]] = load i32, ptr [[B:%.*]], 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]], ptr [[A]], ptr [[B]] +; CHECK-NEXT: [[TMP0:%.*]] = select i1 [[CMP_I_I_I]], i32 [[L_1]], i32 [[L_2]] ; CHECK-NEXT: ret i32 [[TMP0]] ; entry: @@ -816,8 +816,8 @@ ; CHECK-NEXT: [[L_1:%.*]] = load i32, ptr [[A:%.*]], align 4 ; CHECK-NEXT: [[L_2:%.*]] = load i32, ptr [[B:%.*]], 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]], ptr [[A]], ptr [[B]] +; CHECK-NEXT: [[TMP0:%.*]] = select i1 [[CMP_I_I_I]], i32 [[L_1]], i32 [[L_2]] ; CHECK-NEXT: store i32 99, ptr [[C:%.*]], align 4 ; CHECK-NEXT: ret i32 [[TMP0]] ; @@ -835,10 +835,15 @@ ; CHECK-LABEL: @test_phi_select_index_non_local( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[I:%.*]], [[N:%.*]] -; CHECK-NEXT: br i1 [[CMP]], label [[LAND_LHS_TRUE:%.*]], label [[IF_END:%.*]] +; CHECK-NEXT: br i1 [[CMP]], label [[LAND_LHS_TRUE:%.*]], label [[ENTRY_IF_END_CRIT_EDGE:%.*]] +; CHECK: entry.if.end_crit_edge: +; CHECK-NEXT: [[IDXPROM5_PHI_TRANS_INSERT:%.*]] = sext i32 [[I]] to i64 +; CHECK-NEXT: [[ARRAYIDX6_PHI_TRANS_INSERT:%.*]] = getelementptr inbounds i32, ptr [[A:%.*]], i64 [[IDXPROM5_PHI_TRANS_INSERT]] +; CHECK-NEXT: [[DOTPRE:%.*]] = load i32, ptr [[ARRAYIDX6_PHI_TRANS_INSERT]], align 4 +; CHECK-NEXT: br label [[IF_END:%.*]] ; CHECK: land.lhs.true: ; CHECK-NEXT: [[IDXPROM:%.*]] = sext i32 [[I]] to i64 -; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, ptr [[A:%.*]], i64 [[IDXPROM]] +; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, ptr [[A]], i64 [[IDXPROM]] ; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[ARRAYIDX]], align 4 ; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[I]], 1 ; CHECK-NEXT: [[IDXPROM1:%.*]] = sext i32 [[ADD]] to i64 @@ -846,13 +851,15 @@ ; CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[ARRAYIDX2]], align 4 ; CHECK-NEXT: [[CMP3:%.*]] = icmp slt i32 [[TMP0]], [[TMP1]] ; CHECK-NEXT: [[SPEC_SELECT:%.*]] = select i1 [[CMP3]], i32 [[ADD]], i32 [[I]] +; CHECK-NEXT: [[TMP2:%.*]] = select i1 [[CMP3]], i32 [[TMP1]], i32 [[TMP0]] +; CHECK-NEXT: [[DOTPRE1:%.*]] = sext i32 [[SPEC_SELECT]] to i64 ; CHECK-NEXT: br label [[IF_END]] ; CHECK: if.end: -; CHECK-NEXT: [[I_ADDR_0:%.*]] = phi i32 [ [[I]], [[ENTRY:%.*]] ], [ [[SPEC_SELECT]], [[LAND_LHS_TRUE]] ] -; CHECK-NEXT: [[IDXPROM5:%.*]] = sext i32 [[I_ADDR_0]] to i64 -; CHECK-NEXT: [[ARRAYIDX6:%.*]] = getelementptr inbounds i32, ptr [[A]], i64 [[IDXPROM5]] -; CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[ARRAYIDX6]], align 4 -; CHECK-NEXT: ret i32 [[TMP2]] +; CHECK-NEXT: [[IDXPROM5_PRE_PHI:%.*]] = phi i64 [ [[IDXPROM5_PHI_TRANS_INSERT]], [[ENTRY_IF_END_CRIT_EDGE]] ], [ [[DOTPRE1]], [[LAND_LHS_TRUE]] ] +; CHECK-NEXT: [[TMP3:%.*]] = phi i32 [ [[DOTPRE]], [[ENTRY_IF_END_CRIT_EDGE]] ], [ [[TMP2]], [[LAND_LHS_TRUE]] ] +; CHECK-NEXT: [[I_ADDR_0:%.*]] = phi i32 [ [[I]], [[ENTRY_IF_END_CRIT_EDGE]] ], [ [[SPEC_SELECT]], [[LAND_LHS_TRUE]] ] +; CHECK-NEXT: [[ARRAYIDX6:%.*]] = getelementptr inbounds i32, ptr [[A]], i64 [[IDXPROM5_PRE_PHI]] +; CHECK-NEXT: ret i32 [[TMP3]] ; entry: %cmp = icmp slt i32 %i, %N @@ -884,20 +891,22 @@ ; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[N:%.*]], 1 ; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY_PREHEADER:%.*]], label [[FOR_COND_CLEANUP:%.*]] ; CHECK: for.body.preheader: +; CHECK-NEXT: [[DOTPRE:%.*]] = load i32, ptr [[A:%.*]], align 4 ; CHECK-NEXT: br label [[FOR_BODY:%.*]] ; CHECK: for.body: +; CHECK-NEXT: [[TMP0:%.*]] = phi i32 [ [[TMP2:%.*]], [[FOR_BODY]] ], [ [[DOTPRE]], [[FOR_BODY_PREHEADER]] ] ; CHECK-NEXT: [[IDX:%.*]] = phi i32 [ [[IDX_NEXT:%.*]], [[FOR_BODY]] ], [ 1, [[FOR_BODY_PREHEADER]] ] ; CHECK-NEXT: [[RES:%.*]] = phi i32 [ [[SPEC_SELECT:%.*]], [[FOR_BODY]] ], [ 0, [[FOR_BODY_PREHEADER]] ] ; CHECK-NEXT: [[IDXPROM:%.*]] = sext i32 [[IDX]] to i64 -; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, ptr [[A:%.*]], i64 [[IDXPROM]] -; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[ARRAYIDX]], align 4 +; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, ptr [[A]], i64 [[IDXPROM]] +; CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[ARRAYIDX]], align 4 ; CHECK-NEXT: [[IDXPROM1:%.*]] = sext i32 [[RES]] to i64 ; CHECK-NEXT: [[ARRAYIDX1:%.*]] = getelementptr inbounds i32, ptr [[A]], i64 [[IDXPROM1]] -; CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[ARRAYIDX1]], align 4 -; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 [[TMP0]], [[TMP1]] +; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 [[TMP1]], [[TMP0]] ; CHECK-NEXT: [[SPEC_SELECT]] = select i1 [[CMP1]], i32 [[IDX]], i32 [[RES]] ; CHECK-NEXT: [[IDX_NEXT]] = add nsw i32 [[IDX]], 1 ; CHECK-NEXT: [[EXITCOND_NOT:%.*]] = icmp eq i32 [[IDX_NEXT]], [[N]] +; CHECK-NEXT: [[TMP2]] = select i1 [[CMP1]], i32 [[TMP1]], i32 [[TMP0]] ; CHECK-NEXT: br i1 [[EXITCOND_NOT]], label [[FOR_COND_CLEANUP_LOOPEXIT:%.*]], label [[FOR_BODY]] ; CHECK: for.cond.cleanup.loopexit: ; CHECK-NEXT: br label [[FOR_COND_CLEANUP]] 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 @@ -13,10 +13,10 @@ ; CHECK-NEXT: [[MIN_PTR:%.*]] = phi ptr [ [[PTR]], [[ENTRY]] ], [ [[MIN_SELECT:%.*]], [[LOOP]] ] ; CHECK-NEXT: [[L_1:%.*]] = load i32, ptr [[PTR_IV]], 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]], ptr [[PTR_IV]], ptr [[MIN_PTR]] ; CHECK-NEXT: [[PTR_IV_NEXT]] = getelementptr inbounds i32, ptr [[PTR_IV]], i64 1 ; CHECK-NEXT: [[EC:%.*]] = icmp eq ptr [[PTR_IV_NEXT]], [[END:%.*]] +; CHECK-NEXT: [[TMP0]] = select i1 [[CMP_I_I_I]], i32 [[L_1]], i32 [[L_2]] ; CHECK-NEXT: br i1 [[EC]], label [[EXIT:%.*]], label [[LOOP]] ; CHECK: exit: ; CHECK-NEXT: [[RES:%.*]] = load i32, ptr [[MIN_SELECT]], align 4 @@ -54,10 +54,10 @@ ; CHECK-NEXT: [[MIN_PTR:%.*]] = phi ptr [ [[PTR]], [[ENTRY]] ], [ [[MIN_SELECT:%.*]], [[LOOP]] ] ; CHECK-NEXT: [[L_1:%.*]] = load i32, ptr [[PTR_IV]], 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]], ptr [[PTR_IV]], ptr [[MIN_PTR]] ; CHECK-NEXT: [[PTR_IV_NEXT]] = getelementptr inbounds i32, ptr [[PTR_IV]], i64 1 ; CHECK-NEXT: [[EC:%.*]] = icmp eq ptr [[PTR_IV_NEXT]], [[END:%.*]] +; CHECK-NEXT: [[TMP0]] = select i1 [[CMP_I_I_I]], i32 [[L_1]], i32 [[L_2]] ; CHECK-NEXT: br i1 [[EC]], label [[EXIT:%.*]], label [[LOOP]] ; CHECK: exit: ; CHECK-NEXT: [[RES:%.*]] = load i32, ptr [[MIN_SELECT]], align 4 @@ -95,10 +95,10 @@ ; CHECK-NEXT: [[MIN_PTR:%.*]] = phi ptr [ [[B]], [[ENTRY]] ], [ [[MIN_SELECT:%.*]], [[LOOP]] ] ; CHECK-NEXT: [[L_1:%.*]] = load i32, ptr [[PTR_IV]], 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]], ptr [[PTR_IV]], ptr [[MIN_PTR]] ; CHECK-NEXT: [[PTR_IV_NEXT]] = getelementptr inbounds i32, ptr [[PTR_IV]], i64 1 ; CHECK-NEXT: [[EC:%.*]] = icmp eq ptr [[PTR_IV_NEXT]], [[END:%.*]] +; CHECK-NEXT: [[TMP0]] = select i1 [[CMP_I_I_I]], i32 [[L_1]], i32 [[L_2]] ; CHECK-NEXT: br i1 [[EC]], label [[EXIT:%.*]], label [[LOOP]] ; CHECK: exit: ; CHECK-NEXT: [[RES:%.*]] = load i32, ptr [[MIN_SELECT]], align 4 @@ -130,15 +130,15 @@ ; CHECK-NEXT: [[L_2_PRE:%.*]] = load i32, ptr [[PTR]], align 4 ; CHECK-NEXT: br label [[LOOP:%.*]] ; CHECK: loop: -; CHECK-NEXT: [[L_2:%.*]] = phi i32 [ [[L_2_PRE]], [[ENTRY:%.*]] ], [ [[TMP0:%.*]], [[LOOP]] ] +; CHECK-NEXT: [[L_3:%.*]] = phi i32 [ [[L_2_PRE]], [[ENTRY:%.*]] ], [ [[TMP0:%.*]], [[LOOP]] ] ; CHECK-NEXT: [[PTR_IV:%.*]] = phi ptr [ [[START_PTR]], [[ENTRY]] ], [ [[PTR_IV_NEXT:%.*]], [[LOOP]] ] ; CHECK-NEXT: [[MIN_PTR:%.*]] = phi ptr [ [[PTR]], [[ENTRY]] ], [ [[MIN_SELECT:%.*]], [[LOOP]] ] ; CHECK-NEXT: [[L_1:%.*]] = load i32, ptr [[PTR_IV]], 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: [[CMP_I_I_I:%.*]] = icmp ult i32 [[L_1]], [[L_3]] ; CHECK-NEXT: [[MIN_SELECT]] = select i1 [[CMP_I_I_I]], ptr [[PTR_IV]], ptr [[MIN_PTR]] ; CHECK-NEXT: [[PTR_IV_NEXT]] = getelementptr inbounds i32, ptr [[PTR_IV]], i64 1 ; CHECK-NEXT: [[EC:%.*]] = icmp eq ptr [[PTR_IV_NEXT]], [[END:%.*]] +; CHECK-NEXT: [[TMP0]] = select i1 [[CMP_I_I_I]], i32 [[L_1]], i32 [[L_3]] ; CHECK-NEXT: br i1 [[EC]], label [[EXIT:%.*]], label [[LOOP]] ; CHECK: exit: ; CHECK-NEXT: [[RES:%.*]] = load i32, ptr [[MIN_SELECT]], align 4 @@ -177,10 +177,10 @@ ; CHECK-NEXT: [[MIN_PTR:%.*]] = phi ptr [ [[PTR]], [[ENTRY]] ], [ [[MIN_SELECT:%.*]], [[LOOP]] ] ; CHECK-NEXT: [[L_1:%.*]] = load i32, ptr [[PTR_IV]], 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]], ptr [[PTR_IV]], ptr [[MIN_PTR]] ; CHECK-NEXT: [[PTR_IV_NEXT]] = getelementptr inbounds i32, ptr [[PTR_IV]], i64 1 ; CHECK-NEXT: [[EC:%.*]] = icmp eq ptr [[PTR_IV_NEXT]], [[END:%.*]] +; CHECK-NEXT: [[TMP0]] = select i1 [[CMP_I_I_I]], i32 [[L_1]], i32 [[L_2]] ; CHECK-NEXT: br i1 [[EC]], label [[EXIT:%.*]], label [[LOOP]] ; CHECK: exit: ; CHECK-NEXT: [[RES:%.*]] = load i32, ptr [[MIN_SELECT]], align 4 @@ -260,10 +260,10 @@ ; CHECK-NEXT: [[MIN_PTR:%.*]] = phi ptr [ [[MIN_SELECT:%.*]], [[LOOP]] ], [ [[PTR]], [[LOOP_PREHEADER]] ] ; CHECK-NEXT: [[L_1:%.*]] = load i32, ptr [[PTR_IV]], 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]], ptr [[PTR_IV]], ptr [[MIN_PTR]] ; CHECK-NEXT: [[PTR_IV_NEXT]] = getelementptr inbounds i32, ptr [[PTR_IV]], i64 1 ; CHECK-NEXT: [[EC:%.*]] = icmp eq ptr [[PTR_IV_NEXT]], [[END:%.*]] +; CHECK-NEXT: [[TMP0]] = select i1 [[CMP_I_I_I]], i32 [[L_1]], i32 [[L_2]] ; CHECK-NEXT: br i1 [[EC]], label [[LOOP_EXIT:%.*]], label [[LOOP]] ; CHECK: loop.exit: ; CHECK-NEXT: br label [[EXIT]] @@ -311,10 +311,10 @@ ; CHECK-NEXT: [[L_1:%.*]] = load i32, ptr [[PTR_IV]], align 4 ; CHECK-NEXT: [[L_2:%.*]] = load i32, ptr [[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]], ptr [[PTR_IV]], ptr [[MIN_PTR]] ; CHECK-NEXT: [[PTR_IV_NEXT]] = getelementptr inbounds i32, ptr [[PTR_IV]], i64 1 ; CHECK-NEXT: [[EC:%.*]] = icmp eq ptr [[PTR_IV_NEXT]], [[END:%.*]] +; CHECK-NEXT: [[TMP0:%.*]] = select i1 [[CMP_I_I_I]], i32 [[L_1]], i32 [[L_2]] ; CHECK-NEXT: br i1 [[EC]], label [[EXIT:%.*]], label [[LOOP]] ; CHECK: exit: ; CHECK-NEXT: ret i32 [[TMP0]] @@ -350,10 +350,10 @@ ; CHECK-NEXT: call void @may_throw() ; CHECK-NEXT: [[L_2:%.*]] = load i32, ptr [[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]], ptr [[PTR_IV]], ptr [[MIN_PTR]] ; CHECK-NEXT: [[PTR_IV_NEXT]] = getelementptr inbounds i32, ptr [[PTR_IV]], i64 1 ; CHECK-NEXT: [[EC:%.*]] = icmp eq ptr [[PTR_IV_NEXT]], [[END:%.*]] +; CHECK-NEXT: [[TMP0:%.*]] = select i1 [[CMP_I_I_I]], i32 [[L_1]], i32 [[L_2]] ; CHECK-NEXT: br i1 [[EC]], label [[EXIT:%.*]], label [[LOOP]] ; CHECK: exit: ; CHECK-NEXT: ret i32 [[TMP0]] @@ -514,10 +514,10 @@ ; CHECK-NEXT: [[L_1:%.*]] = load i32, ptr [[PTR_IV]], align 4 ; CHECK-NEXT: [[L_2:%.*]] = load i32, ptr [[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]], ptr [[PTR_IV]], ptr [[MIN_PTR]] ; CHECK-NEXT: [[PTR_IV_NEXT]] = getelementptr inbounds i32, ptr [[PTR_IV]], i64 1 ; CHECK-NEXT: [[EC:%.*]] = icmp eq ptr [[PTR_IV_NEXT]], [[END:%.*]] +; CHECK-NEXT: [[TMP0:%.*]] = select i1 [[CMP_I_I_I]], i32 [[L_1]], i32 [[L_2]] ; CHECK-NEXT: br i1 [[EC]], label [[EXIT:%.*]], label [[LOOP]] ; CHECK: exit: ; CHECK-NEXT: ret i32 [[TMP0]] @@ -681,10 +681,10 @@ ; CHECK-NEXT: [[MIN_PTR:%.*]] = phi ptr [ [[PTR]], [[ENTRY]] ], [ [[MIN_SELECT:%.*]], [[LOOP]] ] ; CHECK-NEXT: [[L_1:%.*]] = load i32, ptr [[PTR_IV]], 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]], ptr [[PTR_IV]], ptr [[MIN_PTR]] ; CHECK-NEXT: [[PTR_IV_NEXT]] = getelementptr inbounds i32, ptr [[PTR_IV]], i64 1 ; CHECK-NEXT: [[EC:%.*]] = icmp eq ptr [[PTR_IV_NEXT]], [[END:%.*]] +; CHECK-NEXT: [[TMP0]] = select i1 [[CMP_I_I_I]], i32 [[L_1]], i32 [[L_2]] ; CHECK-NEXT: br i1 [[EC]], label [[EXIT_PREHEADER:%.*]], label [[LOOP]] ; CHECK: exit.preheader: ; CHECK-NEXT: br label [[EXIT:%.*]] @@ -728,10 +728,10 @@ ; CHECK-NEXT: [[MIN_PTR:%.*]] = phi ptr [ [[PTR]], [[ENTRY]] ], [ [[MIN_SELECT:%.*]], [[LOOP]] ] ; CHECK-NEXT: [[L_1:%.*]] = load i32, ptr [[PTR_IV]], 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]], ptr [[PTR_IV]], ptr [[MIN_PTR]] ; CHECK-NEXT: [[PTR_IV_NEXT]] = getelementptr inbounds i32, ptr [[PTR_IV]], i64 1 ; CHECK-NEXT: [[EC:%.*]] = icmp eq ptr [[PTR_IV_NEXT]], [[END:%.*]] +; CHECK-NEXT: [[TMP0]] = select i1 [[CMP_I_I_I]], i32 [[L_1]], i32 [[L_2]] ; CHECK-NEXT: br i1 [[EC]], label [[EXIT:%.*]], label [[LOOP]] ; CHECK: exit: ; CHECK-NEXT: store i32 0, ptr [[START_PTR]], align 4 @@ -771,10 +771,10 @@ ; CHECK-NEXT: [[MIN_PTR:%.*]] = phi ptr [ [[PTR]], [[ENTRY]] ], [ [[MIN_SELECT:%.*]], [[LOOP]] ] ; CHECK-NEXT: [[L_1:%.*]] = load i32, ptr [[PTR_IV]], 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]], ptr [[PTR_IV]], ptr [[MIN_PTR]] ; CHECK-NEXT: [[PTR_IV_NEXT]] = getelementptr inbounds i32, ptr [[PTR_IV]], i64 1 ; CHECK-NEXT: [[EC:%.*]] = icmp eq ptr [[PTR_IV_NEXT]], [[END:%.*]] +; CHECK-NEXT: [[TMP0]] = select i1 [[CMP_I_I_I]], i32 [[L_1]], i32 [[L_2]] ; CHECK-NEXT: br i1 [[EC]], label [[EXIT_1:%.*]], label [[LOOP]] ; CHECK: exit.1: ; CHECK-NEXT: store i32 0, ptr [[START_PTR]], align 4 @@ -820,10 +820,10 @@ ; CHECK-NEXT: [[MIN_PTR:%.*]] = phi ptr [ [[PTR]], [[ENTRY]] ], [ [[MIN_SELECT:%.*]], [[LOOP]] ] ; CHECK-NEXT: [[L_1:%.*]] = load i32, ptr [[PTR_IV]], 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]], ptr [[PTR_IV]], ptr [[MIN_PTR]] ; CHECK-NEXT: [[PTR_IV_NEXT]] = getelementptr inbounds i32, ptr [[PTR_IV]], i64 1 ; CHECK-NEXT: [[EC:%.*]] = icmp eq ptr [[PTR_IV_NEXT]], [[END:%.*]] +; CHECK-NEXT: [[TMP0]] = select i1 [[CMP_I_I_I]], i32 [[L_1]], i32 [[L_2]] ; CHECK-NEXT: br i1 [[EC]], label [[EXIT_1:%.*]], label [[LOOP]] ; CHECK: exit.1: ; CHECK-NEXT: store i32 0, ptr [[START_PTR]], align 4 @@ -916,20 +916,16 @@ ; CHECK-NEXT: [[L_2_PRE:%.*]] = load i32, ptr [[PTR]], align 4 ; CHECK-NEXT: br label [[LOOP:%.*]] ; CHECK: 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 ptr [ [[START_PTR]], [[ENTRY]] ], [ [[PTR_IV_NEXT:%.*]], [[LOOP_LOOP_CRIT_EDGE]] ] -; CHECK-NEXT: [[MIN_PTR:%.*]] = phi ptr [ [[PTR]], [[ENTRY]] ], [ [[MIN_SELECT:%.*]], [[LOOP_LOOP_CRIT_EDGE]] ] +; CHECK-NEXT: [[L_3:%.*]] = phi i32 [ [[L_2_PRE]], [[ENTRY:%.*]] ], [ [[TMP0:%.*]], [[LOOP]] ] +; CHECK-NEXT: [[PTR_IV:%.*]] = phi ptr [ [[START_PTR]], [[ENTRY]] ], [ [[PTR_IV_NEXT:%.*]], [[LOOP]] ] +; CHECK-NEXT: [[MIN_PTR:%.*]] = phi ptr [ [[PTR]], [[ENTRY]] ], [ [[MIN_SELECT:%.*]], [[LOOP]] ] ; CHECK-NEXT: [[L_1:%.*]] = load i32, ptr [[PTR_IV]], 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: [[CMP_I_I_I:%.*]] = icmp ult i32 [[L_1]], [[L_3]] ; CHECK-NEXT: [[MIN_SELECT]] = select i1 [[CMP_I_I_I]], ptr [[PTR_IV]], ptr [[MIN_PTR]] ; CHECK-NEXT: [[PTR_IV_NEXT]] = getelementptr inbounds i32, ptr [[PTR_IV]], i32 [[L_3]] ; CHECK-NEXT: [[EC:%.*]] = icmp eq ptr [[PTR_IV_NEXT]], [[END:%.*]] -; CHECK-NEXT: br i1 [[EC]], label [[EXIT:%.*]], label [[LOOP_LOOP_CRIT_EDGE]] -; CHECK: loop.loop_crit_edge: -; CHECK-NEXT: [[L_3_PRE]] = load i32, ptr [[MIN_SELECT]], align 4 -; CHECK-NEXT: br label [[LOOP]] +; CHECK-NEXT: [[TMP0]] = select i1 [[CMP_I_I_I]], i32 [[L_1]], i32 [[L_3]] +; CHECK-NEXT: br i1 [[EC]], label [[EXIT:%.*]], label [[LOOP]] ; CHECK: exit: ; CHECK-NEXT: [[RES:%.*]] = load i32, ptr [[MIN_SELECT]], align 4 ; CHECK-NEXT: ret i32 [[RES]] @@ -967,12 +963,12 @@ ; CHECK-NEXT: [[MIN_PTR:%.*]] = phi ptr [ [[PTR]], [[ENTRY]] ], [ [[MIN_SELECT:%.*]], [[LOOP]] ] ; CHECK-NEXT: [[L_1:%.*]] = load i32, ptr [[PTR_IV]], 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]], ptr [[PTR_IV]], ptr [[MIN_PTR]] ; CHECK-NEXT: [[GEP_MIN_PTR:%.*]] = getelementptr inbounds i32, ptr [[MIN_PTR]], i32 1 ; CHECK-NEXT: [[L_3:%.*]] = load i32, ptr [[GEP_MIN_PTR]], align 4 ; CHECK-NEXT: [[PTR_IV_NEXT]] = getelementptr inbounds i32, ptr [[PTR_IV]], i32 [[L_3]] ; CHECK-NEXT: [[EC:%.*]] = icmp eq ptr [[PTR_IV_NEXT]], [[END:%.*]] +; CHECK-NEXT: [[TMP0]] = select i1 [[CMP_I_I_I]], i32 [[L_1]], i32 [[L_2]] ; CHECK-NEXT: br i1 [[EC]], label [[EXIT:%.*]], label [[LOOP]] ; CHECK: exit: ; CHECK-NEXT: [[RES:%.*]] = load i32, ptr [[MIN_SELECT]], align 4 diff --git a/llvm/test/Transforms/GVN/opaque-ptr.ll b/llvm/test/Transforms/GVN/opaque-ptr.ll --- a/llvm/test/Transforms/GVN/opaque-ptr.ll +++ b/llvm/test/Transforms/GVN/opaque-ptr.ll @@ -179,8 +179,8 @@ ; CHECK-NEXT: [[T2:%.*]] = load i32, ptr [[PY:%.*]], align 4 ; CHECK-NEXT: [[T3:%.*]] = load i32, ptr [[PX:%.*]], align 4 ; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[T2]], [[T3]] -; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[CMP]], i32 [[T3]], i32 [[T2]] ; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[CMP]], ptr [[PX]], ptr [[PY]] +; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[CMP]], i32 [[T3]], i32 [[T2]] ; CHECK-NEXT: ret i32 [[TMP1]] ; %t2 = load i32, ptr %py, align 4