/// A definition of a register may mark the end of a range. void LiveDebugValues::transferRegisterDef(MachineInstr &MI, OpenRangesSet &OpenRanges, const VarLocMap &VarLocIDs) { MachineFunction *MF = MI.getParent()->getParent(); const TargetLowering *TLI = MF->getSubtarget().getTargetLowering(); unsigned SP = TLI->getStackPointerRegisterToSaveRestore(); SparseBitVector<> KillSet; for (const MachineOperand &MO : MI.operands()) { if (MO.isReg() && MO.isDef() && MO.getReg() && TRI->isPhysicalRegister(MO.getReg())) { // Remove ranges of all aliased registers. for (MCRegAliasIterator RAI(MO.getReg(), TRI, true); RAI.isValid(); ++RAI) for (unsigned ID : OpenRanges.getVarLocs()) if (VarLocIDs[ID].isDescribedByReg() == *RAI) KillSet.set(ID); } else if (MO.isRegMask()) { // Remove ranges of all clobbered registers. Register masks don't usually // list SP as preserved. While the debug info may be off for an // instruction or two around callee-cleanup calls, transferring the // DEBUG_VALUE across the call is still a better user experience. for (unsigned ID : OpenRanges.getVarLocs()) { unsigned Reg = VarLocIDs[ID].isDescribedByReg(); if (Reg && Reg != SP && MO.clobbersPhysReg(Reg)) KillSet.set(ID); } } } OpenRanges.erase(KillSet, VarLocIDs); }
Error llvm::pdb::writeSparseBitVector(BinaryStreamWriter &Writer, SparseBitVector<> &Vec) { constexpr int BitsPerWord = 8 * sizeof(uint32_t); int ReqBits = Vec.find_last() + 1; uint32_t ReqWords = alignTo(ReqBits, BitsPerWord) / BitsPerWord; if (auto EC = Writer.writeInteger(ReqWords)) return joinErrors( std::move(EC), make_error<RawError>(raw_error_code::corrupt_file, "Could not write linear map number of words")); uint32_t Idx = 0; for (uint32_t I = 0; I != ReqWords; ++I) { uint32_t Word = 0; for (uint32_t WordIdx = 0; WordIdx < 32; ++WordIdx, ++Idx) { if (Vec.test(Idx)) Word |= (1 << WordIdx); } if (auto EC = Writer.writeInteger(Word)) return joinErrors(std::move(EC), make_error<RawError>( raw_error_code::corrupt_file, "Could not write linear map word")); } return Error::success(); }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void SimpleDeadCodeElimination::RemoveDeadVariables(Function* function) { SparseBitVector liveVars; // Scan every instruction in the function and mark any local variable // that appears as an operand. All variables that are not marked are deleted. function->ForEachInstruction([&liveVars](Instruction* instr) -> bool { for(int i = 0; i < instr->SourceOpCount(); i++) { if(auto variableRef = instr->GetSourceOp(i)->As<VariableReference>()) { auto variable = variableRef->GetVariable(); // Only local variables. if(variable && (variable->IsParameter() == false)) { liveVars.SetBit(variable->Id()); } } } return true; }); // Now removed all unused variables. for(int i = 0; i < function->VariableCount(); i++) { auto variable = function->Variables()[i]; if(liveVars.IsSet(variable->Id()) == false) { function->RemoveVariable(variable); i--; } } }
void LazyLiveness::computeBackedgeChain(MachineFunction& mf, MachineBasicBlock* MBB) { SparseBitVector<128> tmp = rv[MBB]; tmp.set(preorder[MBB]); tmp &= backedge_source; calculated.set(preorder[MBB]); for (SparseBitVector<128>::iterator I = tmp.begin(); I != tmp.end(); ++I) { assert(rev_preorder.size() > *I && "Unknown block!"); MachineBasicBlock* SrcMBB = rev_preorder[*I]; for (MachineBasicBlock::succ_iterator SI = SrcMBB->succ_begin(), SE = SrcMBB->succ_end(); SI != SE; ++SI) { MachineBasicBlock* TgtMBB = *SI; if (backedges.count(std::make_pair(SrcMBB, TgtMBB)) && !rv[MBB].test(preorder[TgtMBB])) { if (!calculated.test(preorder[TgtMBB])) computeBackedgeChain(mf, TgtMBB); tv[MBB].set(preorder[TgtMBB]); SparseBitVector<128> right = tv[TgtMBB]; tv[MBB] |= right; } } tv[MBB].reset(preorder[MBB]); } }
void SIFixWWMLiveness::addDefs(const MachineInstr &MI, SparseBitVector<> &Regs) { for (const MachineOperand &Op : MI.defs()) { if (Op.isReg()) { unsigned Reg = Op.getReg(); if (TRI->isVGPR(*MRI, Reg)) Regs.set(Reg); } } }
const TBlock* GetStartBlock(const TFunction* function) { // It's possible that the function has multiple exit blocks. // In this case we need to create a fake block that acts like an // "unique" exit block, whose predecessors are the real exit blocks. if(exitBlock_) { // A fake exit block has been already created. return exitBlock_; } StaticList<const TBlock*, 16> exitBlocks; const TBlock* block = function->FirstBlock(); while(block) { if(block->SuccessorCount() == 0) { // This is an exit block. exitBlocks.Add(block); returnBlocks_.SetBit(block->Id()); } block = block->NextBlock(); } // Now return the exit block. If there is no unique block // we create a "fake" one that has all the exit blocks // as its predecessors. This block will be deleted after the analysis. if(exitBlocks.Count() == 1) { // There is a single exit block. return exitBlocks[0]; } else if(exitBlocks.Count() > 1) { // There are multiple exit blocks, create a fake block. exitBlock_ = TBlock::GetBlock("#fakeBlock"); for(int i = 0; i < exitBlocks.Count(); i++) { exitBlock_->AddPredecessor(const_cast<TBlock*>(exitBlocks[i])); } return exitBlock_; } else { // There is no exit block. This can happen, for example, if the last // block represents an infinite loop. In this case return the last block. return function->LastBlock(); } }
Error llvm::pdb::readSparseBitVector(BinaryStreamReader &Stream, SparseBitVector<> &V) { uint32_t NumWords; if (auto EC = Stream.readInteger(NumWords)) return joinErrors( std::move(EC), make_error<RawError>(raw_error_code::corrupt_file, "Expected hash table number of words")); for (uint32_t I = 0; I != NumWords; ++I) { uint32_t Word; if (auto EC = Stream.readInteger(Word)) return joinErrors(std::move(EC), make_error<RawError>(raw_error_code::corrupt_file, "Expected hash table word")); for (unsigned Idx = 0; Idx < 32; ++Idx) if (Word & (1U << Idx)) V.set((I * 32) + Idx); } return Error::success(); }
Error NameMap::load(StreamReader &Stream) { // This is some sort of weird string-set/hash table encoded in the stream. // It starts with the number of bytes in the table. uint32_t NumberOfBytes; if (auto EC = Stream.readInteger(NumberOfBytes)) return joinErrors(std::move(EC), make_error<RawError>(raw_error_code::corrupt_file, "Expected name map length")); if (Stream.bytesRemaining() < NumberOfBytes) return make_error<RawError>(raw_error_code::corrupt_file, "Invalid name map length"); // Following that field is the starting offset of strings in the name table. uint32_t StringsOffset = Stream.getOffset(); Stream.setOffset(StringsOffset + NumberOfBytes); // This appears to be equivalent to the total number of strings *actually* // in the name table. uint32_t HashSize; if (auto EC = Stream.readInteger(HashSize)) return joinErrors(std::move(EC), make_error<RawError>(raw_error_code::corrupt_file, "Expected name map hash size")); // This appears to be an upper bound on the number of strings in the name // table. uint32_t MaxNumberOfStrings; if (auto EC = Stream.readInteger(MaxNumberOfStrings)) return joinErrors(std::move(EC), make_error<RawError>(raw_error_code::corrupt_file, "Expected name map max strings")); if (MaxNumberOfStrings > (UINT32_MAX / sizeof(uint32_t))) return make_error<RawError>(raw_error_code::corrupt_file, "Implausible number of strings"); const uint32_t MaxNumberOfWords = UINT32_MAX / (sizeof(uint32_t) * 8); // This appears to be a hash table which uses bitfields to determine whether // or not a bucket is 'present'. uint32_t NumPresentWords; if (auto EC = Stream.readInteger(NumPresentWords)) return joinErrors(std::move(EC), make_error<RawError>(raw_error_code::corrupt_file, "Expected name map num words")); if (NumPresentWords > MaxNumberOfWords) return make_error<RawError>(raw_error_code::corrupt_file, "Number of present words is too large"); SparseBitVector<> Present; for (uint32_t I = 0; I != NumPresentWords; ++I) { uint32_t Word; if (auto EC = Stream.readInteger(Word)) return joinErrors(std::move(EC), make_error<RawError>(raw_error_code::corrupt_file, "Expected name map word")); for (unsigned Idx = 0; Idx < 32; ++Idx) if (Word & (1U << Idx)) Present.set((I * 32) + Idx); } // This appears to be a hash table which uses bitfields to determine whether // or not a bucket is 'deleted'. uint32_t NumDeletedWords; if (auto EC = Stream.readInteger(NumDeletedWords)) return joinErrors( std::move(EC), make_error<RawError>(raw_error_code::corrupt_file, "Expected name map num deleted words")); if (NumDeletedWords > MaxNumberOfWords) return make_error<RawError>(raw_error_code::corrupt_file, "Number of deleted words is too large"); SparseBitVector<> Deleted; for (uint32_t I = 0; I != NumDeletedWords; ++I) { uint32_t Word; if (auto EC = Stream.readInteger(Word)) return joinErrors(std::move(EC), make_error<RawError>(raw_error_code::corrupt_file, "Expected name map word")); for (unsigned Idx = 0; Idx < 32; ++Idx) if (Word & (1U << Idx)) Deleted.set((I * 32) + Idx); } for (unsigned I : Present) { // For all present entries, dump out their mapping. (void)I; // This appears to be an offset relative to the start of the strings. // It tells us where the null-terminated string begins. uint32_t NameOffset; if (auto EC = Stream.readInteger(NameOffset)) return joinErrors(std::move(EC), make_error<RawError>(raw_error_code::corrupt_file, "Expected name map name offset")); // This appears to be a stream number into the stream directory. uint32_t NameIndex; if (auto EC = Stream.readInteger(NameIndex)) return joinErrors(std::move(EC), make_error<RawError>(raw_error_code::corrupt_file, "Expected name map name index")); // Compute the offset of the start of the string relative to the stream. uint32_t StringOffset = StringsOffset + NameOffset; uint32_t OldOffset = Stream.getOffset(); // Pump out our c-string from the stream. StringRef Str; Stream.setOffset(StringOffset); if (auto EC = Stream.readZeroString(Str)) return joinErrors(std::move(EC), make_error<RawError>(raw_error_code::corrupt_file, "Expected name map name")); Stream.setOffset(OldOffset); // Add this to a string-map from name to stream number. Mapping.insert({Str, NameIndex}); } return Error::success(); }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void AggregateCopyPropagation::IterateToFixedpoint() { // We use an iterative data-flow algorithm to propagate the copies // that are available on entry of each block. Add the blocks // in reverse-postorder, this minimizes the number of iterations. StaticList<Block*, 64> worklist; SparseBitVector inWorklist; CFGInfo<Block, Function> cfgInfo(funct_->FirstBlock(), false); auto& postorderList = cfgInfo.PostorderList(); int copyCount = infoList_.Count(); // Add all blocks to the worklist. for(int i = 0; i < postorderList.Count(); i++) { auto block = const_cast<Block*>(postorderList[i]); worklist.Add(block); inWorklist.SetBit(block->Id()); } while(worklist.IsNotEmpty()) { // Extract a block from the worklist. auto block = worklist.RemoveLast(); inWorklist.ResetBit(block->Id()); // Compute the 'in' set, which is the intersection // out the 'out' sets of the predecessors. BitVector inSet(copyCount, false); auto predecessorEnum = block->GetPredecessorEnum(); bool first = true; while(predecessorEnum.IsValid()) { auto predecessorBlock = predecessorEnum.Next(); if(first) { inSet = outSets_[predecessorBlock]; first = false; } else inSet.And(outSets_[predecessorBlock]); } // Save the 'in' set, it's needed later // when we want to eliminate the copies. inSets_.Add(block, inSet); // Now compute the new 'out' set, which is the union of the 'copy' set // with the 'in' set, from which the 'kill' set has been subtracted. // Out(B) = Copy(B) U (In(B) - Kill(B)) BitVector outSet = copySets_[block]; inSet.Difference(killSets_[block]); outSet.Or(inSet); if(outSets_[block] != outSet) { // The 'out' set must be updated, and all successors // must be added to the worklist and reprocessed. outSets_[block] = outSet; auto successorEnum = block->GetSuccessorEnum(); while(successorEnum.IsValid()) { auto successorBlock = successorEnum.Next(); if(inWorklist.IsSet(successorBlock->Id()) == false) { worklist.Add(successorBlock); inWorklist.IsSet(successorBlock->Id()); } } } } }
bool IsReturnBlock(const TBlock* block) { return returnBlocks_.IsSet(block->Id()); }