Index: lib/Transforms/InstCombine/InstCombineSelect.cpp =================================================================== --- lib/Transforms/InstCombine/InstCombineSelect.cpp +++ lib/Transforms/InstCombine/InstCombineSelect.cpp @@ -300,12 +300,13 @@ TI->getType()); } - // Only handle binary operators with one-use here. As with the cast case - // above, it may be possible to relax the one-use constraint, but that needs - // be examined carefully since it may not reduce the total number of - // instructions. - BinaryOperator *BO = dyn_cast(TI); - if (!BO || !TI->hasOneUse() || !FI->hasOneUse()) + // Only handle binary operators (including two-operand getelementptr) with + // one-use here. As with the cast case above, it may be possible to relax the + // one-use constraint, but that needs be examined carefully since it may not + // reduce the total number of instructions. + if (TI->getNumOperands() != 2 || FI->getNumOperands() != 2 || + (!isa(TI) && !isa(TI)) || + !TI->hasOneUse() || !FI->hasOneUse()) return nullptr; // Figure out if the operations have any operands in common. @@ -342,7 +343,18 @@ SI.getName() + ".v", &SI); Value *Op0 = MatchIsOpZero ? MatchOp : NewSI; Value *Op1 = MatchIsOpZero ? NewSI : MatchOp; - return BinaryOperator::Create(BO->getOpcode(), Op0, Op1); + if (auto *BO = dyn_cast(TI)) { + return BinaryOperator::Create(BO->getOpcode(), Op0, Op1); + } + if (auto *TGEP = dyn_cast(TI)) { + auto *FGEP = cast(FI); + Type *ElementType = TGEP->getResultElementType(); + return TGEP->isInBounds() && FGEP->isInBounds() + ? GetElementPtrInst::CreateInBounds(ElementType, Op0, {Op1}) + : GetElementPtrInst::Create(ElementType, Op0, {Op1}); + } + llvm_unreachable("Expected BinaryOperator or GEP"); + return nullptr; } static bool isSelect01(const APInt &C1I, const APInt &C2I) { Index: test/Transforms/InstCombine/select-gep.ll =================================================================== --- test/Transforms/InstCombine/select-gep.ll +++ test/Transforms/InstCombine/select-gep.ll @@ -3,10 +3,9 @@ define i32* @test1a(i32* %p, i32* %q) { ; CHECK-LABEL: @test1a( -; CHECK-NEXT: [[GEP1:%.*]] = getelementptr i32, i32* [[P:%.*]], i64 4 -; CHECK-NEXT: [[GEP2:%.*]] = getelementptr i32, i32* [[Q:%.*]], i64 4 -; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i32* [[P]], [[Q]] -; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[CMP]], i32* [[GEP1]], i32* [[GEP2]] +; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i32* [[P:%.*]], [[Q:%.*]] +; CHECK-NEXT: [[SELECT_V:%.*]] = select i1 [[CMP]], i32* [[P]], i32* [[Q]] +; CHECK-NEXT: [[SELECT:%.*]] = getelementptr i32, i32* [[SELECT_V]], i64 4 ; CHECK-NEXT: ret i32* [[SELECT]] ; %gep1 = getelementptr i32, i32* %p, i64 4 @@ -18,10 +17,9 @@ define i32* @test1b(i32* %p, i32* %q) { ; CHECK-LABEL: @test1b( -; CHECK-NEXT: [[GEP1:%.*]] = getelementptr inbounds i32, i32* [[P:%.*]], i64 4 -; CHECK-NEXT: [[GEP2:%.*]] = getelementptr i32, i32* [[Q:%.*]], i64 4 -; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i32* [[P]], [[Q]] -; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[CMP]], i32* [[GEP1]], i32* [[GEP2]] +; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i32* [[P:%.*]], [[Q:%.*]] +; CHECK-NEXT: [[SELECT_V:%.*]] = select i1 [[CMP]], i32* [[P]], i32* [[Q]] +; CHECK-NEXT: [[SELECT:%.*]] = getelementptr i32, i32* [[SELECT_V]], i64 4 ; CHECK-NEXT: ret i32* [[SELECT]] ; %gep1 = getelementptr inbounds i32, i32* %p, i64 4 @@ -33,10 +31,9 @@ define i32* @test1c(i32* %p, i32* %q) { ; CHECK-LABEL: @test1c( -; CHECK-NEXT: [[GEP1:%.*]] = getelementptr i32, i32* [[P:%.*]], i64 4 -; CHECK-NEXT: [[GEP2:%.*]] = getelementptr inbounds i32, i32* [[Q:%.*]], i64 4 -; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i32* [[P]], [[Q]] -; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[CMP]], i32* [[GEP1]], i32* [[GEP2]] +; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i32* [[P:%.*]], [[Q:%.*]] +; CHECK-NEXT: [[SELECT_V:%.*]] = select i1 [[CMP]], i32* [[P]], i32* [[Q]] +; CHECK-NEXT: [[SELECT:%.*]] = getelementptr i32, i32* [[SELECT_V]], i64 4 ; CHECK-NEXT: ret i32* [[SELECT]] ; %gep1 = getelementptr i32, i32* %p, i64 4 @@ -48,10 +45,9 @@ define i32* @test1d(i32* %p, i32* %q) { ; CHECK-LABEL: @test1d( -; CHECK-NEXT: [[GEP1:%.*]] = getelementptr inbounds i32, i32* [[P:%.*]], i64 4 -; CHECK-NEXT: [[GEP2:%.*]] = getelementptr inbounds i32, i32* [[Q:%.*]], i64 4 -; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i32* [[P]], [[Q]] -; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[CMP]], i32* [[GEP1]], i32* [[GEP2]] +; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i32* [[P:%.*]], [[Q:%.*]] +; CHECK-NEXT: [[SELECT_V:%.*]] = select i1 [[CMP]], i32* [[P]], i32* [[Q]] +; CHECK-NEXT: [[SELECT:%.*]] = getelementptr inbounds i32, i32* [[SELECT_V]], i64 4 ; CHECK-NEXT: ret i32* [[SELECT]] ; %gep1 = getelementptr inbounds i32, i32* %p, i64 4 @@ -63,10 +59,9 @@ define i32* @test2(i32* %p, i64 %x, i64 %y) { ; CHECK-LABEL: @test2( -; CHECK-NEXT: [[GEP1:%.*]] = getelementptr inbounds i32, i32* [[P:%.*]], i64 [[X:%.*]] -; CHECK-NEXT: [[GEP2:%.*]] = getelementptr inbounds i32, i32* [[P]], i64 [[Y:%.*]] -; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i64 [[X]], [[Y]] -; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[CMP]], i32* [[GEP1]], i32* [[GEP2]] +; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i64 [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: [[SELECT_V:%.*]] = select i1 [[CMP]], i64 [[X]], i64 [[Y]] +; CHECK-NEXT: [[SELECT:%.*]] = getelementptr inbounds i32, i32* [[P:%.*]], i64 [[SELECT_V]] ; CHECK-NEXT: ret i32* [[SELECT]] ; %gep1 = getelementptr inbounds i32, i32* %p, i64 %x