blob: d254e87d7f41794434f81c9937f910efc4312480 [file] [log] [blame]
// Copyright 2019 The Clspv Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "ComputeStructuredOrder.h"
using namespace clspv;
using namespace llvm;
void clspv::ComputeStructuredOrder(BasicBlock *block, DominatorTree *DT,
const LoopInfo &LI,
std::deque<BasicBlock *> *order,
DenseSet<BasicBlock *> *visited) {
if (!visited->insert(block).second)
return;
// Identify the merge and continue blocks for special treatment.
const auto *terminator = block->getTerminator();
BasicBlock *continue_block = nullptr;
BasicBlock *merge_block = nullptr;
if (LI.isLoopHeader(block)) {
Loop *loop = LI.getLoopFor(block);
merge_block = loop->getExitBlock();
if (loop->isLoopLatch(block)) {
// The header is also the latch (i.e. a single block loop).
continue_block = block;
} else {
// The continue block satisfies the following conditions:
// 1. Is dominated by the header (true by construction at this point).
// 2. Dominates the latch block.
// We can assume the loop has multiple blocks since the single block loop
// is handled above. By construction the header always dominates the
// latch block, so we exclude that case specifically.
auto *header = loop->getHeader();
auto *latch = loop->getLoopLatch();
for (auto *bb : loop->blocks()) {
if (bb == header)
continue;
// Several block might dominate the latch, we can pick any.
if (DT->dominates(bb, latch))
continue_block = bb;
}
}
// At least the latch dominates itself so we will always find a continue
// block.
assert(continue_block && merge_block && "Bad loop");
} else if (terminator->getNumSuccessors() > 1) {
// This is potentially a selection case, but it could also be a conditional
// branch with one arm back to the loop header, which would make this block
// the latch block.
bool has_back_edge = false;
for (unsigned i = 0; i < terminator->getNumSuccessors(); ++i) {
if (LI.isLoopHeader(terminator->getSuccessor(i)))
has_back_edge = true;
}
if (!has_back_edge) {
// The cfg structurizer generates a cfg where the true branch goes into
// the then/else region and the false branch skips the region. Therefore,
// we use the false branch here as the merge.
merge_block = terminator->getSuccessor(1);
}
}
// Traverse merge and continue first.
if (merge_block) {
ComputeStructuredOrder(merge_block, DT, LI, order, visited);
if (continue_block)
ComputeStructuredOrder(continue_block, DT, LI, order, visited);
}
for (unsigned i = 0; i < terminator->getNumSuccessors(); ++i) {
auto *successor = terminator->getSuccessor(i);
if (successor != merge_block && successor != continue_block)
ComputeStructuredOrder(successor, DT, LI, order, visited);
}
order->push_front(block);
}