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