[llvm] [SimplifyCFG] Use hash map to continue hoisting the common instructions (PR #78615)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Mar 20 11:52:29 PDT 2024
================
@@ -1635,87 +1675,149 @@ bool SimplifyCFGOpt::hoistCommonCodeFromSuccessors(BasicBlock *BB,
// many instructions we skip, serving as a compilation time control as well as
// preventing excessive increase of life ranges.
unsigned NumSkipped = 0;
- // If we find an unreachable instruction at the beginning of a basic block, we
- // can still hoist instructions from the rest of the basic blocks.
- if (SuccIterPairs.size() > 2) {
- erase_if(SuccIterPairs,
- [](const auto &Pair) { return isa<UnreachableInst>(Pair.first); });
- if (SuccIterPairs.size() < 2)
- return false;
- }
bool Changed = false;
+ auto *SuccIterPairBegin = SuccIterPairs.begin();
+ ++SuccIterPairBegin;
+ auto BBItrPair = *SuccIterPairBegin++;
+ auto OtherSuccIterPairRange =
+ iterator_range(SuccIterPairBegin, SuccIterPairs.end());
+
+ DenseMap<llvm::hash_code, SmallVector<Instruction *, 2>> OtherSuccessorsHash;
+ DenseMap<Instruction *, unsigned> InstToSkipFlag;
+ unsigned skipFlag = 0;
+ Instruction *I = nullptr;
+ do {
+ I = &*BBItrPair.first;
+ auto HashValue = getHash(I);
+ skipFlag |= skippedInstrFlags(I);
+ // For the first successor we created hashmap for, put all instructions
+ // in the hashmap execept for the ones that have the same hash as some
+ // previous instruction in that BB.
+ if (OtherSuccessorsHash.find(HashValue) == OtherSuccessorsHash.end()) {
+ OtherSuccessorsHash[HashValue] = {I};
+ InstToSkipFlag[I] = skipFlag;
+ }
+ BBItrPair.first++;
+ } while (!I->isTerminator());
+
+ unsigned Index = 1;
+ for (auto BBItrPair : OtherSuccIterPairRange) {
+ // Fill the hashmap for every other successor
+ unsigned skipFlag = 0;
+ Instruction *I = nullptr;
+ do {
+ I = &*BBItrPair.first;
+ auto HashValue = getHash(I);
+ skipFlag |= skippedInstrFlags(I);
+ auto &InstVec = OtherSuccessorsHash[HashValue];
+ // For other successors put the instrcution in the map only if there are
+ // instructions with the same hash from other successors and this is the
+ // first instruction with this hash value from current successor.
+ if (OtherSuccessorsHash.find(HashValue) != OtherSuccessorsHash.end() &&
+ InstVec.size() == Index) {
+ InstVec.push_back(I);
+ InstToSkipFlag[I] = skipFlag;
+ }
+ BBItrPair.first++;
+ } while (!I->isTerminator());
+ Index++;
+ }
+
+ // Keep track of instructions skipped in the first successor
+ unsigned SkipFlagsBB1 = 0;
+ bool SameLevelHoist = true;
for (;;) {
auto *SuccIterPairBegin = SuccIterPairs.begin();
auto &BB1ItrPair = *SuccIterPairBegin++;
auto OtherSuccIterPairRange =
iterator_range(SuccIterPairBegin, SuccIterPairs.end());
auto OtherSuccIterRange = make_first_range(OtherSuccIterPairRange);
-
Instruction *I1 = &*BB1ItrPair.first;
// Skip debug info if it is not identical.
- bool AllDbgInstsAreIdentical = all_of(OtherSuccIterRange, [I1](auto &Iter) {
+ bool IdenticalDebugs = all_of(OtherSuccIterRange, [I1](auto &Iter) {
Instruction *I2 = &*Iter;
return I1->isIdenticalToWhenDefined(I2);
});
- if (!AllDbgInstsAreIdentical) {
+ if (!IdenticalDebugs) {
while (isa<DbgInfoIntrinsic>(I1))
I1 = &*++BB1ItrPair.first;
- for (auto &SuccIter : OtherSuccIterRange) {
- Instruction *I2 = &*SuccIter;
- while (isa<DbgInfoIntrinsic>(I2))
- I2 = &*++SuccIter;
- }
}
-
- bool AllInstsAreIdentical = true;
- bool HasTerminator = I1->isTerminator();
- for (auto &SuccIter : OtherSuccIterRange) {
- Instruction *I2 = &*SuccIter;
- HasTerminator |= I2->isTerminator();
- if (AllInstsAreIdentical && !I1->isIdenticalToWhenDefined(I2))
- AllInstsAreIdentical = false;
+ auto OtherInsts = OtherSuccessorsHash[getHash(I1)];
+
+ // Check if there are identical instructions in all other successors
+ // We might face with same hash values for different instructions.
+ // If that happens, ignore the instruction.
+ bool HasIdenticalInst =
+ OtherSuccessorsHash.find(getHash(I1)) != OtherSuccessorsHash.end() &&
+ OtherInsts.size() == (SuccIterPairs.size() - 1) &&
+ all_of(OtherInsts, [&](Instruction *I2) {
+ return I2->isIdenticalToWhenDefined(I1);
+ });
+
+ if (!HasIdenticalInst) {
+ if (NumSkipped >= HoistCommonSkipLimit)
+ return Changed;
+ SkipFlagsBB1 |= skippedInstrFlags(I1);
+ if (SameLevelHoist) {
+ for (auto &SuccIterPair : OtherSuccIterPairRange) {
+ Instruction *I = &*SuccIterPair.first++;
+ SuccIterPair.second |= skippedInstrFlags(I);
+ }
+ }
+ ++NumSkipped;
+ if (I1->isTerminator())
+ return Changed;
+ ++BB1ItrPair.first;
+ continue;
}
- SmallVector<Instruction *, 8> OtherInsts;
- for (auto &SuccIter : OtherSuccIterRange)
- OtherInsts.push_back(&*SuccIter);
-
// If we are hoisting the terminator instruction, don't move one (making a
// broken BB), instead clone it, and remove BI.
- if (HasTerminator) {
+ if (I1->isTerminator()) {
// Even if BB, which contains only one unreachable instruction, is ignored
// at the beginning of the loop, we can hoist the terminator instruction.
// If any instructions remain in the block, we cannot hoist terminators.
- if (NumSkipped || !AllInstsAreIdentical) {
+ if (NumSkipped) {
hoistLockstepIdenticalDPValues(TI, I1, OtherInsts);
return Changed;
}
-
- return hoistSuccIdenticalTerminatorToSwitchOrIf(TI, I1, OtherInsts) ||
- Changed;
+ SmallVector<Instruction *, 8> Insts;
+ for (auto *I2 : OtherInsts) {
+ // BB holding I2 should only contain the branch instruction
+ auto itr = I2->getParent()->instructionsWithoutDebug();
+ if (&*itr.begin() != I2)
+ return Changed;
+ Insts.push_back(I2);
+ }
+ return hoistSuccIdenticalTerminatorToSwitchOrIf(TI, I1, Insts) || Changed;
}
- if (AllInstsAreIdentical) {
- unsigned SkipFlagsBB1 = BB1ItrPair.second;
- AllInstsAreIdentical =
- isSafeToHoistInstr(I1, SkipFlagsBB1) &&
- all_of(OtherSuccIterPairRange, [=](const auto &Pair) {
- Instruction *I2 = &*Pair.first;
- unsigned SkipFlagsBB2 = Pair.second;
- // Even if the instructions are identical, it may not
- // be safe to hoist them if we have skipped over
- // instructions with side effects or their operands
- // weren't hoisted.
- return isSafeToHoistInstr(I2, SkipFlagsBB2) &&
- shouldHoistCommonInstructions(I1, I2, TTI);
- });
+ bool SafeToHoist = isSafeToHoistInstr(I1, SkipFlagsBB1);
+ for (auto [SuccIterPair, I2] : zip(OtherSuccIterPairRange, OtherInsts)) {
+ // If instructions of all successors are at the same level, use the
----------------
goldsteinn wrote:
Think simpler and faster would just be put `if(!SafeToHoist) break`. then get rid of the `SafeToHoist &&` below.
https://github.com/llvm/llvm-project/pull/78615
More information about the llvm-commits
mailing list