diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp --- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp +++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp @@ -2078,8 +2078,97 @@ SmallPtrSet InstructionsToSink; DenseMap> PHIOperands; LockstepReverseIterator LRI(UnconditionalPreds); - while (LRI.isValid() && - canSinkInstructions(*LRI, PHIOperands)) { + + // Code generation will be less efficient because of losing opportunity + // to generate offset addressing if phi is created based on + // elements of same array. + auto ProfitableToCreatePHINode = [&](LockstepReverseIterator &LRI) { + bool HasPHIOperands = false; + bool ContainsDifferentGEPs = false; + const Value *PossibleBasePointerValue = nullptr; + const GetElementPtrInst *PreviousGEPInstr = nullptr; + SmallVector ConstantIndicesNumber; + SmallVector PreviousConstantIndices; + SmallVector CurrentConstantIndices; + unsigned GEPInstructionsNumber = 0; + for (auto *Instruction : *LRI) { + for (auto *V : PHIOperands[Instruction]) { + HasPHIOperands = true; + Value *CurrentValue = V; + + if (auto *GEPInstruction = dyn_cast(V)) { + CurrentValue = GEPInstruction->getPointerOperand(); + + // Check that all GEPs are different and contain constant values. + unsigned Index = 1; + unsigned ConstantIndices = 0; + CurrentConstantIndices = + SmallVector(GEPInstruction->getNumIndices(), false); + for (auto IndexOperator = GEPInstruction->idx_begin(); + IndexOperator != GEPInstruction->idx_end(); + IndexOperator++, Index++) { + auto ConstantIndexValue = + dyn_cast(IndexOperator->get()); + if (ConstantIndexValue) { + ConstantIndices++; + CurrentConstantIndices[Index - 1] = true; + } + GEPInstructionsNumber++; + if (!ContainsDifferentGEPs && PreviousGEPInstr != nullptr) { + if (GEPInstruction->getNumIndices() != + PreviousGEPInstr->getNumIndices()) { + ContainsDifferentGEPs = true; + } else { + // Check constants. + const Value *IndexFromPreviousGEP = + PreviousGEPInstr->getOperand(Index); + if (IndexFromPreviousGEP != IndexOperator->get()) { + if (CurrentConstantIndices[Index - 1] && + PreviousConstantIndices[Index - 1]) { + ContainsDifferentGEPs |= + ConstantIndexValue->getValue() != + cast(IndexFromPreviousGEP)->getValue(); + } else { + ContainsDifferentGEPs = true; + } + } + } + } + } + if (PreviousGEPInstr == nullptr) { + PreviousGEPInstr = GEPInstruction; + } + if (!ContainsDifferentGEPs) { + PreviousConstantIndices = CurrentConstantIndices; + } + ConstantIndicesNumber.push_back(ConstantIndices); + } + + if (PossibleBasePointerValue == nullptr) { + PossibleBasePointerValue = CurrentValue; + } else if (CurrentValue != PossibleBasePointerValue) { + return true; + } + } + } + if (!HasPHIOperands || + (!ContainsDifferentGEPs && GEPInstructionsNumber > 1)) { + return true; + } + size_t GEPWithConstantIndicesNumber = + count_if(ConstantIndicesNumber, [](int i) { return i > 0; }); + if (GEPWithConstantIndicesNumber < ConstantIndicesNumber.size() / 2) { + return true; + } + LLVM_DEBUG(dbgs() << "SINK: PHI node for elements of same entity " + << *PossibleBasePointerValue << " was found\n"); + return false; + }; + + while (LRI.isValid() && canSinkInstructions(*LRI, PHIOperands)) { + if (!ProfitableToCreatePHINode(LRI)) { + return false; + } LLVM_DEBUG(dbgs() << "SINK: instruction can be sunk: " << *(*LRI)[0] << "\n"); InstructionsToSink.insert((*LRI).begin(), (*LRI).end()); diff --git a/llvm/test/Transforms/SimplifyCFG/phi-with-geps-sink.ll b/llvm/test/Transforms/SimplifyCFG/phi-with-geps-sink.ll --- a/llvm/test/Transforms/SimplifyCFG/phi-with-geps-sink.ll +++ b/llvm/test/Transforms/SimplifyCFG/phi-with-geps-sink.ll @@ -12,14 +12,14 @@ ; CHECK: if.then: ; CHECK-NEXT: [[DUMMY:%.*]] = add i32 [[X:%.*]], 5 ; CHECK-NEXT: [[GEPA:%.*]] = getelementptr inbounds [[STRUCT_ANON:%.*]], %struct.anon* [[S:%.*]], i32 0, i32 0 +; CHECK-NEXT: store i32 [[X]], i32* [[GEPA]], align 4 ; CHECK-NEXT: br label [[IF_END:%.*]] ; CHECK: if.else: ; CHECK-NEXT: [[DUMMY1:%.*]] = add i32 [[X]], 6 ; CHECK-NEXT: [[GEPB:%.*]] = getelementptr inbounds [[STRUCT_ANON]], %struct.anon* [[S]], i32 0, i32 1 +; CHECK-NEXT: store i32 [[X]], i32* [[GEPB]], align 4 ; CHECK-NEXT: br label [[IF_END]] ; CHECK: if.end: -; CHECK-NEXT: [[GEPB_SINK:%.*]] = phi i32* [ [[GEPB]], [[IF_ELSE]] ], [ [[GEPA]], [[IF_THEN]] ] -; CHECK-NEXT: store i32 [[X]], i32* [[GEPB_SINK]], align 4 ; CHECK-NEXT: ret i32 1 ; entry: @@ -48,14 +48,14 @@ ; CHECK-NEXT: br i1 [[FLAG:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] ; CHECK: if.then: ; CHECK-NEXT: [[DUMMY:%.*]] = add i32 [[X:%.*]], 5 +; CHECK-NEXT: store i32 [[X]], i32* [[ARRAY:%.*]], align 4 ; CHECK-NEXT: br label [[IF_END:%.*]] ; CHECK: if.else: ; CHECK-NEXT: [[DUMMY1:%.*]] = add i32 [[X]], 6 -; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, i32* [[ARRAY:%.*]], i64 1 +; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, i32* [[ARRAY]], i64 1 +; CHECK-NEXT: store i32 [[X]], i32* [[ARRAYIDX]], align 4 ; CHECK-NEXT: br label [[IF_END]] ; CHECK: if.end: -; CHECK-NEXT: [[ARRAYIDX_SINK:%.*]] = phi i32* [ [[ARRAYIDX]], [[IF_ELSE]] ], [ [[ARRAY]], [[IF_THEN]] ] -; CHECK-NEXT: store i32 [[X]], i32* [[ARRAYIDX_SINK]], align 4 ; CHECK-NEXT: ret i32 1 ; @@ -77,6 +77,7 @@ ret i32 1 } +; Negative test ; PHI node that consists of GEPs of different base. define i32 @test3(i1 %flag, i32 %x, %struct.anon* %s, %struct.anon* %s1) { ; CHECK-LABEL: @test3( @@ -114,6 +115,7 @@ ret i32 1 } +; Negative test ; PHI node that consists of not GEPs only. define i32 @test4(i1 %flag, i32* %array, i32 %x, %struct.anon* %s) { ; CHECK-LABEL: @test4( @@ -148,4 +150,4 @@ if.end: ret i32 1 -} \ No newline at end of file +}