From: Simon Pilgrim Date: Tue, 13 Jul 2021 18:06:13 +0000 (+0100) Subject: [InstCombine] Fold (select C, (gep Ptr, Idx), Ptr) -> (gep Ptr, (select C, Idx, 0... X-Git-Tag: llvmorg-14-init~1512 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=b803294cf78714303db2d3647291a2308347ef23;p=platform%2Fupstream%2Fllvm.git [InstCombine] Fold (select C, (gep Ptr, Idx), Ptr) -> (gep Ptr, (select C, Idx, 0)) (PR50183) As discussed on PR50183, we already fold to prefer 'select-of-idx' vs 'select-of-gep': define <4 x i32>* @select0a(<4 x i32>* %a0, i64 %a1, i1 %a2, i64 %a3) { %gep0 = getelementptr inbounds <4 x i32>, <4 x i32>* %a0, i64 %a1 %gep1 = getelementptr inbounds <4 x i32>, <4 x i32>* %a0, i64 %a3 %sel = select i1 %a2, <4 x i32>* %gep0, <4 x i32>* %gep1 ret <4 x i32>* %sel } --> define <4 x i32>* @select1a(<4 x i32>* %a0, i64 %a1, i1 %a2, i64 %a3) { %sel = select i1 %a2, i64 %a1, i64 %a3 %gep = getelementptr inbounds <4 x i32>, <4 x i32>* %a0, i64 %sel ret <4 x i32>* %gep } This patch adds basic handling for the 'fallthrough' cases where the gep idx == 0 has been folded away to the base address: define <4 x i32>* @select0(<4 x i32>* %a0, i64 %a1, i1 %a2) { %gep = getelementptr inbounds <4 x i32>, <4 x i32>* %a0, i64 %a1 %sel = select i1 %a2, <4 x i32>* %a0, <4 x i32>* %gep ret <4 x i32>* %sel } --> define <4 x i32>* @select1(<4 x i32>* %a0, i64 %a1, i1 %a2) { %sel = select i1 %a2, i64 0, i64 %a1 %gep = getelementptr inbounds <4 x i32>, <4 x i32>* %a0, i64 %sel ret <4 x i32>* %gep } Differential Revision: https://reviews.llvm.org/D105901 --- diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp index eadc826..fb9750d5 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp @@ -2933,6 +2933,33 @@ Instruction *InstCombinerImpl::visitSelectInst(SelectInst &SI) { if (Instruction *I = foldSelectExtConst(SI)) return I; + // Fold (select C, (gep Ptr, Idx), Ptr) -> (gep Ptr, (select C, Idx, 0)) + // Fold (select C, Ptr, (gep Ptr, Idx)) -> (gep Ptr, (select C, 0, Idx)) + auto SelectGepWithBase = [&](GetElementPtrInst *Gep, Value *Base, + bool Swap) -> GetElementPtrInst * { + Value *Ptr = Gep->getPointerOperand(); + if (Gep->getNumOperands() != 2 || Gep->getPointerOperand() != Base || + !Gep->hasOneUse()) + return nullptr; + Type *ElementType = Gep->getResultElementType(); + Value *Idx = Gep->getOperand(1); + Value *NewT = Idx; + Value *NewF = Constant::getNullValue(Idx->getType()); + if (Swap) + std::swap(NewT, NewF); + Value *NewSI = + Builder.CreateSelect(CondVal, NewT, NewF, SI.getName() + ".idx", &SI); + return Gep->isInBounds() + ? GetElementPtrInst::CreateInBounds(ElementType, Ptr, {NewSI}) + : GetElementPtrInst::Create(ElementType, Ptr, {NewSI}); + }; + if (auto *TrueGep = dyn_cast(TrueVal)) + if (auto *NewGep = SelectGepWithBase(TrueGep, FalseVal, false)) + return NewGep; + if (auto *FalseGep = dyn_cast(FalseVal)) + if (auto *NewGep = SelectGepWithBase(FalseGep, TrueVal, true)) + return NewGep; + // See if we can fold the select into one of our operands. if (SelType->isIntOrIntVectorTy() || SelType->isFPOrFPVectorTy()) { if (Instruction *FoldI = foldSelectIntoOp(SI, TrueVal, FalseVal)) diff --git a/llvm/test/Transforms/InstCombine/select-gep.ll b/llvm/test/Transforms/InstCombine/select-gep.ll index 77710ce..bba6709 100644 --- a/llvm/test/Transforms/InstCombine/select-gep.ll +++ b/llvm/test/Transforms/InstCombine/select-gep.ll @@ -74,9 +74,9 @@ define i32* @test2(i32* %p, i64 %x, i64 %y) { ; PR50183 define i32* @test2a(i32* %p, i64 %x, i64 %y) { ; CHECK-LABEL: @test2a( -; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i32, i32* [[P:%.*]], i64 [[X:%.*]] -; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i64 [[X]], [[Y:%.*]] -; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[CMP]], i32* [[GEP]], i32* [[P]] +; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i64 [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: [[SELECT_IDX:%.*]] = select i1 [[CMP]], i64 [[X]], i64 0 +; CHECK-NEXT: [[SELECT:%.*]] = getelementptr inbounds i32, i32* [[P:%.*]], i64 [[SELECT_IDX]] ; CHECK-NEXT: ret i32* [[SELECT]] ; %gep = getelementptr inbounds i32, i32* %p, i64 %x @@ -88,9 +88,9 @@ define i32* @test2a(i32* %p, i64 %x, i64 %y) { ; PR50183 define i32* @test2b(i32* %p, i64 %x, i64 %y) { ; CHECK-LABEL: @test2b( -; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i32, i32* [[P:%.*]], i64 [[X:%.*]] -; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i64 [[X]], [[Y:%.*]] -; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[CMP]], i32* [[P]], i32* [[GEP]] +; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i64 [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: [[SELECT_IDX:%.*]] = select i1 [[CMP]], i64 0, i64 [[X]] +; CHECK-NEXT: [[SELECT:%.*]] = getelementptr inbounds i32, i32* [[P:%.*]], i64 [[SELECT_IDX]] ; CHECK-NEXT: ret i32* [[SELECT]] ; %gep = getelementptr inbounds i32, i32* %p, i64 %x