Index: lib/CodeGen/CodeGenPrepare.cpp =================================================================== --- lib/CodeGen/CodeGenPrepare.cpp +++ lib/CodeGen/CodeGenPrepare.cpp @@ -3417,10 +3417,11 @@ } /// \brief Combine the addressing modes we've collected into a single - /// addressing mode. + /// addressing mode. OnlySingleAddrMode means that only single AddrMode + /// can be combined. /// \return True iff we successfully combined them or we only had one so /// didn't need to combine them anyway. - bool combineAddrModes() { + bool combineAddrModes(bool OnlySingleAddrMode) { // If we have no AddrModes then they can't be combined. if (AddrModes.size() == 0) return false; @@ -3429,6 +3430,10 @@ if (AddrModes.size() == 1) return true; + // If we cannot process other than single AddrMode, bail out now. + if (OnlySingleAddrMode) + return false; + // If the AddrModes we collected are all just equal to the value they are // derived from then combining them wouldn't do anything useful. if (AllAddrModesTrivial) @@ -4530,7 +4535,8 @@ // 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 compatible. - bool PhiOrSelectSeen = false; + unsigned CountPhiSeen = 0; + unsigned CountSelectSeen = 0; SmallVector AddrModeInsts; AddressingModeCombiner AddrModes; TypePromotionTransaction TPT(RemovedInsts); @@ -4556,14 +4562,14 @@ if (PHINode *P = dyn_cast(V)) { for (Value *IncValue : P->incoming_values()) worklist.push_back(IncValue); - PhiOrSelectSeen = true; + CountPhiSeen++; continue; } // Similar for select. if (SelectInst *SI = dyn_cast(V)) { worklist.push_back(SI->getFalseValue()); worklist.push_back(SI->getTrueValue()); - PhiOrSelectSeen = true; + CountSelectSeen++; continue; } @@ -4580,10 +4586,16 @@ break; } + // If we saw both selects and phis we support only one AddrMode now. + bool OnlySingleAddrMode = CountPhiSeen && CountSelectSeen; + // If we saw two selects we support only one AddrMode now. + if (!OnlySingleAddrMode) + OnlySingleAddrMode = CountSelectSeen > 1; + // Try to combine the AddrModes we've collected. If we couldn't collect any, // or we have multiple but either couldn't combine them or combining them // wouldn't do anything useful, bail out now. - if (!AddrModes.combineAddrModes()) { + if (!AddrModes.combineAddrModes(OnlySingleAddrMode)) { TPT.rollback(LastKnownGood); return false; } @@ -4596,9 +4608,10 @@ // 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 // in this BB. - if (!PhiOrSelectSeen && none_of(AddrModeInsts, [&](Value *V) { + if (!(CountPhiSeen || CountSelectSeen) && + none_of(AddrModeInsts, [&](Value *V) { return IsNonLocalValue(V, MemoryInst->getParent()); - })) { + })) { DEBUG(dbgs() << "CGP: Found local addrmode: " << AddrMode << "\n"); return false; } Index: test/Transforms/CodeGenPrepare/X86/sink-addrmode.ll =================================================================== --- test/Transforms/CodeGenPrepare/X86/sink-addrmode.ll +++ test/Transforms/CodeGenPrepare/X86/sink-addrmode.ll @@ -268,3 +268,24 @@ call void @foo(i32 %v) ret void } + +; Make sure we can eliminate a select when both arguments perform equivalent +; address computation. Select of Select case. +define void @test11(i1 %cond1, i1 %cond2, i64* %base) { +; CHECK-LABEL: @test11 +; CHECK: getelementptr i8, {{.+}} 40 +; CHECK-NOT: select +entry: + %gep1 = getelementptr inbounds i64, i64* %base, i64 5 + %gep1.casted = bitcast i64* %gep1 to i32* + %base.casted = bitcast i64* %base to i32* + %gep2 = getelementptr inbounds i32, i32* %base.casted, i64 10 + %base2.casted = bitcast i64* %base to i8* + %gep3 = getelementptr inbounds i8, i8* %base2.casted, i64 40 + %gep3.casted = bitcast i8* %gep3 to i32* + %casted.merged = select i1 %cond1, i32* %gep1.casted, i32* %gep2 + %casted2.merged = select i1 %cond2, i32* %gep3.casted, i32* %casted.merged + %v = load i32, i32* %casted2.merged, align 4 + call void @foo(i32 %v) + ret void +}