|  | /* | 
|  | * 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"); | 
|  | } |