blob: de518ec8430b9dfc5707b5c9746bf4bfcd418150 [file] [log] [blame]
/*
* Copyright (c) 2012-2015 Advanced Micro Devices, Inc.
* All rights reserved.
*
* For use for simulation and test purposes only
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* Author: Steve Reinhardt
*/
#include "gpu-compute/kernel_cfg.hh"
#include <algorithm>
#include <cassert>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <iterator>
#include <map>
#include <string>
#include "gpu-compute/gpu_static_inst.hh"
void
ControlFlowInfo::assignImmediatePostDominators(
const std::vector<GPUStaticInst*>& instructions)
{
ControlFlowInfo cfg(instructions);
cfg.findImmediatePostDominators();
}
ControlFlowInfo::ControlFlowInfo(const std::vector<GPUStaticInst*>& insts) :
instructions(insts)
{
createBasicBlocks();
connectBasicBlocks();
}
BasicBlock*
ControlFlowInfo::basicBlock(int inst_addr) const {
for (auto& block: basicBlocks) {
int first_block_addr = block->firstInstruction->instAddr();
if (inst_addr >= first_block_addr && inst_addr <
first_block_addr + block->size * sizeof(TheGpuISA::RawMachInst)) {
return block.get();
}
}
return nullptr;
}
GPUStaticInst*
ControlFlowInfo::lastInstruction(const BasicBlock* block) const
{
if (block->isExit()) {
return nullptr;
}
return instructions.at(block->firstInstruction->instNum() +
block->size - 1);
}
BasicBlock*
ControlFlowInfo::postDominator(const BasicBlock* block) const
{
if (block->isExit()) {
return nullptr;
}
return basicBlock(lastInstruction(block)->ipdInstNum());
}
void
ControlFlowInfo::createBasicBlocks()
{
assert(!instructions.empty());
std::set<int> leaders;
// first instruction is a leader
leaders.insert(0);
for (const auto &instruction : instructions) {
if (instruction->isBranch()) {
const int target_pc = instruction->getTargetPc();
leaders.insert(target_pc);
leaders.insert(instruction->nextInstAddr());
}
}
size_t block_size = 0;
for (const auto &instruction : instructions) {
if (leaders.find(instruction->instAddr()) != leaders.end()) {
uint32_t id = basicBlocks.size();
if (id > 0) {
basicBlocks.back()->size = block_size;
}
block_size = 0;
basicBlocks.emplace_back(new BasicBlock(id, instruction));
}
block_size++;
}
basicBlocks.back()->size = block_size;
// exit basic block
basicBlocks.emplace_back(new BasicBlock(basicBlocks.size(), nullptr));
}
void
ControlFlowInfo::connectBasicBlocks()
{
BasicBlock* exit_bb = basicBlocks.back().get();
for (auto& bb : basicBlocks) {
if (bb->isExit()) {
break;
}
GPUStaticInst* last = lastInstruction(bb.get());
if (last->isReturn()) {
bb->successorIds.insert(exit_bb->id);
continue;
}
if (last->isBranch()) {
const uint32_t target_pc = last->getTargetPc();
BasicBlock* target_bb = basicBlock(target_pc);
bb->successorIds.insert(target_bb->id);
}
// Unconditional jump instructions have a unique successor
if (!last->isUnconditionalJump()) {
BasicBlock* next_bb = basicBlock(last->nextInstAddr());
bb->successorIds.insert(next_bb->id);
}
}
}
// In-place set intersection
static void
intersect(std::set<uint32_t>& a, const std::set<uint32_t>& b)
{
std::set<uint32_t>::iterator it = a.begin();
while (it != a.end()) {
it = b.find(*it) != b.end() ? ++it : a.erase(it);
}
}
void
ControlFlowInfo::findPostDominators()
{
// the only postdominator of the exit block is itself
basicBlocks.back()->postDominatorIds.insert(basicBlocks.back()->id);
//copy all basic blocks to all postdominator lists except for exit block
for (auto& block : basicBlocks) {
if (!block->isExit()) {
for (uint32_t i = 0; i < basicBlocks.size(); i++) {
block->postDominatorIds.insert(i);
}
}
}
bool change = true;
while (change) {
change = false;
for (int h = basicBlocks.size() - 2; h >= 0; --h) {
size_t num_postdominators =
basicBlocks[h]->postDominatorIds.size();
for (int s : basicBlocks[h]->successorIds) {
intersect(basicBlocks[h]->postDominatorIds,
basicBlocks[s]->postDominatorIds);
}
basicBlocks[h]->postDominatorIds.insert(h);
change |= (num_postdominators
!= basicBlocks[h]->postDominatorIds.size());
}
}
}
// In-place set difference
static void
setDifference(std::set<uint32_t>&a,
const std::set<uint32_t>& b, uint32_t exception)
{
for (uint32_t b_elem : b) {
if (b_elem != exception) {
a.erase(b_elem);
}
}
}
void
ControlFlowInfo::findImmediatePostDominators()
{
assert(basicBlocks.size() > 1); // Entry and exit blocks must be present
findPostDominators();
for (auto& basicBlock : basicBlocks) {
if (basicBlock->isExit()) {
continue;
}
std::set<uint32_t> candidates = basicBlock->postDominatorIds;
candidates.erase(basicBlock->id);
for (uint32_t postDominatorId : basicBlock->postDominatorIds) {
if (postDominatorId != basicBlock->id) {
setDifference(candidates,
basicBlocks[postDominatorId]->postDominatorIds,
postDominatorId);
}
}
assert(candidates.size() == 1);
GPUStaticInst* last_instruction = lastInstruction(basicBlock.get());
BasicBlock* ipd_block = basicBlocks[*(candidates.begin())].get();
if (!ipd_block->isExit()) {
GPUStaticInst* ipd_first_inst = ipd_block->firstInstruction;
last_instruction->ipdInstNum(ipd_first_inst->instAddr());
} else {
last_instruction->ipdInstNum(last_instruction->nextInstAddr());
}
}
}
void
ControlFlowInfo::printPostDominators() const
{
for (auto& block : basicBlocks) {
std::cout << "PD(" << block->id << ") = {";
std::copy(block->postDominatorIds.begin(),
block->postDominatorIds.end(),
std::ostream_iterator<uint32_t>(std::cout, ", "));
std::cout << "}" << std::endl;
}
}
void
ControlFlowInfo::printImmediatePostDominators() const
{
for (const auto& block : basicBlocks) {
if (block->isExit()) {
continue;
}
std::cout << "IPD(" << block->id << ") = ";
std::cout << postDominator(block.get())->id << ", ";
}
std::cout << std::endl;
}
void
ControlFlowInfo::printBasicBlocks() const
{
for (GPUStaticInst* inst : instructions) {
int inst_addr = inst->instAddr();
std::cout << inst_addr << " [" << basicBlock(inst_addr)->id
<< "]: " << inst->disassemble();
if (inst->isBranch()) {
std::cout << ", PC = " << inst->getTargetPc();
}
std::cout << std::endl;
}
}
void
ControlFlowInfo::printBasicBlockDot() const
{
printf("digraph {\n");
for (const auto& basic_block : basicBlocks) {
printf("\t");
for (uint32_t successorId : basic_block->successorIds) {
printf("%d -> %d; ", basic_block->id, successorId);
}
printf("\n");
}
printf("}\n");
}