LLVMBasicBlockRef DeclareBB(LLVMBasicBlockRef Src) { // Check if this is something we already computed. { auto i = BBMap.find(Src); if (i != BBMap.end()) { return i->second; } } LLVMValueRef V = LLVMBasicBlockAsValue(Src); if (!LLVMValueIsBasicBlock(V) || LLVMValueAsBasicBlock(V) != Src) report_fatal_error("Basic block is not a basic block"); const char *Name = LLVMGetBasicBlockName(Src); const char *VName = LLVMGetValueName(V); if (Name != VName) report_fatal_error("Basic block name mismatch"); LLVMBasicBlockRef BB = LLVMAppendBasicBlock(Fun, Name); return BBMap[Src] = BB; }
static void insertAndConnectBlocks(BasicBlockMap& newBlocks, ir::ControlFlowGraph::iterator& functionEntry, ir::ControlFlowGraph::iterator& functionExit, ir::IRKernel& kernel, unsigned int& nextRegister, const ir::IRKernel& inlinedKernel) { typedef std::unordered_map<ir::PTXOperand::RegisterType, ir::PTXOperand::RegisterType> RegisterMap; ir::IRKernel copy; const ir::IRKernel* inlinedKernelPointer = &inlinedKernel; // create a copy if the call is recursive if(inlinedKernelPointer == &kernel) { copy = inlinedKernel; inlinedKernelPointer = © } // Insert new blocks for(auto block = inlinedKernelPointer->cfg()->begin(); block != inlinedKernelPointer->cfg()->end(); ++block) { auto newBlock = kernel.cfg()->clone_block(block); newBlocks.insert(std::make_pair(block, newBlock)); } // Connect new blocks, rename branch labels for(auto block = newBlocks.begin(); block != newBlocks.end(); ++block) { for(auto edge = block->first->out_edges.begin(); edge != block->first->out_edges.end(); ++edge) { auto headBlock = block->second; auto tail = (*edge)->tail; auto tailBlock = newBlocks.find(tail); assert(tailBlock != newBlocks.end()); kernel.cfg()->insert_edge(ir::Edge(headBlock, tailBlock->second, (*edge)->type)); if((*edge)->type == ir::Edge::Branch) { assert(!headBlock->instructions.empty()); auto instruction = headBlock->instructions.back(); auto branch = static_cast<ir::PTXInstruction*>(instruction); if(branch->opcode == ir::PTXInstruction::Ret) continue; assertM(branch->opcode == ir::PTXInstruction::Bra, "Expecting " << branch->toString() << " to be a branch"); branch->d.identifier = tailBlock->second->label(); } } } // Assign copied blocks new registers RegisterMap newRegisters; for(auto block = newBlocks.begin(); block != newBlocks.end(); ++block) { for(auto instruction = block->second->instructions.begin(); instruction != block->second->instructions.end(); ++instruction) { ir::PTXInstruction& ptx = static_cast<ir::PTXInstruction&>( **instruction); ir::PTXOperand* operands[] = {&ptx.pg, &ptx.pq, &ptx.d, &ptx.a, &ptx.b, &ptx.c}; for(unsigned int i = 0; i < 6; ++i) { ir::PTXOperand& operand = *operands[i]; if( operand.addressMode != ir::PTXOperand::Register && operand.addressMode != ir::PTXOperand::Indirect && operand.addressMode != ir::PTXOperand::ArgumentList) { continue; } if(operand.type != ir::PTXOperand::pred) { if(operand.array.empty() && operand.addressMode != ir::PTXOperand::ArgumentList) { auto mapping = newRegisters.find(operand.reg); if(mapping == newRegisters.end()) { mapping = newRegisters.insert(std::make_pair( operand.reg, nextRegister++)).first; } operand.reg = mapping->second; } else { for(auto subOperand = operand.array.begin(); subOperand != operand.array.end(); ++subOperand ) { if(!subOperand->isRegister()) continue; auto mapping = newRegisters.find(subOperand->reg); if(mapping == newRegisters.end()) { mapping = newRegisters.insert(std::make_pair( subOperand->reg, nextRegister++)).first; } subOperand->reg = mapping->second; } } } else if(operand.addressMode != ir::PTXOperand::ArgumentList) { if(operand.condition == ir::PTXOperand::Pred || operand.condition == ir::PTXOperand::InvPred) { auto mapping = newRegisters.find(operand.reg); if(mapping == newRegisters.end()) { mapping = newRegisters.insert(std::make_pair( operand.reg, nextRegister++)).first; } operand.reg = mapping->second; } } } } } // Assign copied blocks new local variables typedef std::unordered_map<std::string, std::string> LocalMap; LocalMap locals; for(auto local = inlinedKernel.locals.begin(); local != inlinedKernel.locals.end(); ++local) { std::string newName = "_Zinlined_" + local->first; locals.insert(std::make_pair(local->first, newName)); auto newLocal = kernel.locals.insert( std::make_pair(newName, local->second)).first; newLocal->second.name = newName; } for(auto block = newBlocks.begin(); block != newBlocks.end(); ++block) { for(auto instruction = block->second->instructions.begin(); instruction != block->second->instructions.end(); ++instruction) { ir::PTXInstruction& ptx = static_cast<ir::PTXInstruction&>( **instruction); if(!ptx.mayHaveAddressableOperand()) continue; ir::PTXOperand* operands[] = {&ptx.pg, &ptx.pq, &ptx.d, &ptx.a, &ptx.b, &ptx.c}; for(unsigned int i = 0; i < 6; ++i) { ir::PTXOperand& operand = *operands[i]; if(operand.addressMode != ir::PTXOperand::Address) continue; auto local = locals.find(operand.identifier); if(local == locals.end()) continue; operand.identifier = local->second; } } } // Get the entry and exit points auto entryMapping = newBlocks.find( inlinedKernelPointer->cfg()->get_entry_block()); assert(entryMapping != newBlocks.end()); functionEntry = entryMapping->second; auto exitMapping = newBlocks.find( inlinedKernelPointer->cfg()->get_exit_block()); assert(exitMapping != newBlocks.end()); functionExit = exitMapping->second; }