Index: llvm/lib/Transforms/InstCombine/InstructionCombining.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstructionCombining.cpp +++ llvm/lib/Transforms/InstCombine/InstructionCombining.cpp @@ -1109,6 +1109,26 @@ return true; } +static bool couldBeExpensiveGEP(ArrayRef Indices) { + // We try to maintain that GEPs have either all constant offset or exactly + // one non-constant offset. If merging GEPs can break this, we do not merge. + bool FoundNonConst = false; + bool FoundNonZeroConst = false; + for (unsigned Idx = 0, Size = Indices.size(); Idx != Size; ++Idx) { + if (auto *C = dyn_cast(Indices[Idx])) { + if (!C->isNullValue()) + FoundNonZeroConst = true; + } else { + if (FoundNonConst) + return true; + FoundNonConst = true; + } + if (FoundNonConst && FoundNonZeroConst) + return true; + } + return false; +} + /// Return a value X such that Val = X * Scale, or null if none. /// If the multiplication is known not to overflow, then NoSignedWrap is set. Value *InstCombiner::Descale(Value *Val, APInt Scale, bool &NoSignedWrap) { @@ -1778,10 +1798,17 @@ // Update the GEP in place if possible. if (Src->getNumOperands() == 2) { + if (!Src->hasOneUse()) { + Indices.push_back(Sum); + Indices.append(GEP.op_begin() + 2, GEP.op_end()); + if (couldBeExpensiveGEP(Indices)) + return nullptr; + } GEP.setOperand(0, Src->getOperand(0)); GEP.setOperand(1, Sum); return &GEP; } + Indices.append(Src->op_begin()+1, Src->op_end()-1); Indices.push_back(Sum); Indices.append(GEP.op_begin()+2, GEP.op_end()); @@ -1793,7 +1820,10 @@ Indices.append(GEP.idx_begin()+1, GEP.idx_end()); } - if (!Indices.empty()) + if (!Indices.empty()) { + if (!Src->hasOneUse() && couldBeExpensiveGEP(Indices)) + return nullptr; + return GEP.isInBounds() && Src->isInBounds() ? GetElementPtrInst::CreateInBounds( Src->getSourceElementType(), Src->getOperand(0), Indices, @@ -1801,6 +1831,7 @@ : GetElementPtrInst::Create(Src->getSourceElementType(), Src->getOperand(0), Indices, GEP.getName()); + } } if (GEP.getNumIndices() == 1) { Index: llvm/test/Transforms/InstCombine/gepphigep.ll =================================================================== --- llvm/test/Transforms/InstCombine/gepphigep.ll +++ llvm/test/Transforms/InstCombine/gepphigep.ll @@ -52,9 +52,9 @@ ret i32 %tmp25 ; CHECK-LABEL: @test2( -; CHECK: getelementptr inbounds %struct2, %struct2* %tmp1, i64 %tmp9, i32 0 +; CHECK: getelementptr inbounds %struct2, %struct2* %tmp10, i64 0, i32 0 ; CHECK: getelementptr inbounds %struct2, %struct2* %tmp1, i64 %tmp19, i32 0 -; CHECK: getelementptr inbounds %struct2, %struct2* %tmp1, i64 %tmp9, i32 1 +; CHECK: getelementptr inbounds %struct2, %struct2* %tmp10, i64 0, i32 1 } ; Check that instcombine doesn't insert GEPs before landingpad. Index: llvm/test/Transforms/InstCombine/unit_skip_gep_merge.ll =================================================================== --- /dev/null +++ llvm/test/Transforms/InstCombine/unit_skip_gep_merge.ll @@ -0,0 +1,28 @@ +; RUN: opt -instcombine -S < %s | FileCheck %s + +%ST = type {i8*, i8*, i8*} +declare void @bar(i8*) + +; CHECK-LABEL: @foo +; CHECK-LABEL: entry +; CHECK: %tmp1 = getelementptr inbounds %ST, %ST* %arrayidx8 +; CHECK-LABEL: BB0 +; CHECK: %tmp2 = getelementptr inbounds %ST, %ST* %arrayidx8 +define void @foo(%ST* %B, i1 %c, i64 %v, i8** %S, i8** %S2) { +entry: + %arrayidx8 = getelementptr inbounds %ST, %ST* %B, i64 %v + %tmp1 = getelementptr inbounds %ST, %ST* %arrayidx8, i64 0, i32 1 + %r = load i8*, i8** %tmp1 + store i8* %r, i8** %S2 + br i1 %c, label %BB0, label %BB2 + +BB0: + %tmp2 = getelementptr inbounds %ST, %ST* %arrayidx8, i64 0, i32 2 + %l = load i8*, i8** %tmp2 + store i8* %l, i8** %S + br label %BB2 + +BB2: + ret void +} +