Index: lib/CodeGen/CodeGenPrepare.cpp =================================================================== --- lib/CodeGen/CodeGenPrepare.cpp +++ lib/CodeGen/CodeGenPrepare.cpp @@ -2676,17 +2676,12 @@ struct ExtAddrMode : public TargetLowering::AddrMode { Value *BaseReg = nullptr; Value *ScaledReg = nullptr; + Value *OriginalValue = nullptr; ExtAddrMode() = default; void print(raw_ostream &OS) const; void dump() const; - - bool operator==(const ExtAddrMode& O) const { - return (BaseReg == O.BaseReg) && (ScaledReg == O.ScaledReg) && - (BaseGV == O.BaseGV) && (BaseOffs == O.BaseOffs) && - (HasBaseReg == O.HasBaseReg) && (Scale == O.Scale); - } }; } // end anonymous namespace @@ -4389,13 +4384,21 @@ SmallPtrSet Visited; worklist.push_back(Addr); + // When examining PHIs and selects we need to keep track of how the + // addressing modes differ from each other. + bool DifferentBaseReg = false; + bool DifferentBaseGV = false; + bool DifferentBaseOffs = false; + bool DifferentScaledReg = false; + bool DifferentScale = false; + bool TrivialAddrMode = true; + // Use a worklist to iteratively look through PHI and select nodes, and // ensure that the addressing mode obtained from the non-PHI/select roots of - // the graph are equivalent. - bool AddrModeFound = false; + // the graph are compatible. bool PhiOrSelectSeen = false; SmallVector AddrModeInsts; - ExtAddrMode AddrMode; + SmallVector AddrModes; TypePromotionTransaction TPT(RemovedInsts); TypePromotionTransaction::ConstRestorationPt LastKnownGood = TPT.getRestorationPoint(); @@ -4437,27 +4440,73 @@ ExtAddrMode NewAddrMode = AddressingModeMatcher::Match( V, AccessTy, AddrSpace, MemoryInst, AddrModeInsts, *TLI, *TRI, InsertedInsts, PromotedInsts, TPT); - - if (!AddrModeFound) { - AddrModeFound = true; - AddrMode = NewAddrMode; + NewAddrMode.OriginalValue = V; + + // AddrModes with a base reg or gv where the reg/gv is just the original + // value are trivial. We need to detect these to avoid introducing a phi or + // select which just duplicates what's already there. + if ((!NewAddrMode.BaseReg && !NewAddrMode.BaseGV) || + (NewAddrMode.BaseGV && + NewAddrMode.BaseGV != NewAddrMode.OriginalValue) || + (NewAddrMode.BaseReg && + NewAddrMode.BaseReg != NewAddrMode.OriginalValue)) + TrivialAddrMode = false; + + // If this is the first addrmode then everything is fine. + if (AddrModes.size() == 0) { + AddrModes.emplace_back(NewAddrMode); continue; } - if (NewAddrMode == AddrMode) + + // Figure out how different this is from the other address modes. + for (ExtAddrMode &AM : AddrModes) { + if (AM.BaseReg != NewAddrMode.BaseReg) + DifferentBaseReg = true; + if (AM.BaseGV != NewAddrMode.BaseGV) + DifferentBaseGV = true; + if (AM.BaseOffs != NewAddrMode.BaseOffs) + DifferentBaseOffs = true; + if (AM.ScaledReg != NewAddrMode.ScaledReg) + DifferentScaledReg = true; + // Don't count 0 as being a different scale, because that actually means + // unscaled (which will already be counted by having no ScaledReg). + if (AM.Scale && NewAddrMode.Scale && AM.Scale != NewAddrMode.Scale) + DifferentScale = true; + } + unsigned DifferCount = DifferentBaseReg + DifferentBaseGV + + DifferentBaseOffs + DifferentScaledReg + + DifferentScale; + + // If this addrmode is the same as all the others then everything is fine + // (which should only happen when there is actually only one addrmode). + if (DifferCount == 0) continue; - AddrModeFound = false; + // If NewAddrMode differs in only one dimension and comes from a phi or + // select then we can handle it by inserting a phi/select later on. + if ((isa(Addr) || isa(Addr)) && Addr->hasOneUse() && + DifferCount == 1) { + AddrModes.emplace_back(NewAddrMode); + continue; + } + + AddrModes.clear(); break; } // If the addressing mode couldn't be determined, or if multiple different - // ones were determined, bail out now. - if (!AddrModeFound) { + // ones were determined but we can't do anything useful with them, bail out + // now. + if (AddrModes.size() == 0 || (AddrModes.size() > 1 && TrivialAddrMode)) { TPT.rollback(LastKnownGood); return false; } TPT.commit(); + // If we have only one AddrMode then it will be first in AddrModes, otherwise + // we adjust the elements as we go. + ExtAddrMode AddrMode = AddrModes.front(); + // If all the instructions matched are already in this BB, don't do anything. // If we saw a Phi node then it is not local definitely, and if we saw a select // then we want to push the address calculation past it even if it's already @@ -4494,6 +4543,11 @@ Type *IntPtrTy = DL->getIntPtrType(Addr->getType()); Value *ResultPtr = nullptr, *ResultIndex = nullptr; + // TODO: Handle multiple AddrModes by inserting a select or phi for each + // field in which the AddrModes differ. + if (AddrModes.size() > 1) + return false; + // First, find the pointer. if (AddrMode.BaseReg && AddrMode.BaseReg->getType()->isPointerTy()) { ResultPtr = AddrMode.BaseReg; @@ -4616,6 +4670,10 @@ SunkAddr = Builder.CreatePointerCast(SunkAddr, Addr->getType()); } } else { + // When not sinking using GEPs we can't handle more than one AddrMode + if (AddrModes.size() > 1) + return false; + // We'd require a ptrtoint/inttoptr down the line, which we can't do for // non-integral pointers, so in that case bail out now. Type *BaseTy = AddrMode.BaseReg ? AddrMode.BaseReg->getType() : nullptr;