SlotIndexes.cpp revision b3661585c0f87b6045f0d65b5cac16921ae27086
1233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames//===-- SlotIndexes.cpp - Slot Indexes Pass ------------------------------===// 2233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames// 3233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames// The LLVM Compiler Infrastructure 4233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames// 5233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames// This file is distributed under the University of Illinois Open Source 6233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames// License. See LICENSE.TXT for details. 7233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames// 8233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames//===----------------------------------------------------------------------===// 9233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames 10233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames#define DEBUG_TYPE "slotindexes" 11233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames 12233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames#include "llvm/CodeGen/SlotIndexes.h" 13233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames#include "llvm/CodeGen/MachineFunction.h" 14233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames#include "llvm/Support/Debug.h" 15233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames#include "llvm/Support/raw_ostream.h" 1616dcaf59960d699735a57b1623092d561c18a165Lang Hames#include "llvm/Support/ManagedStatic.h" 17233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames 18233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hamesusing namespace llvm; 19233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames 20d6ef7fac1a020c58ec61cad2325e5f6afd0bbee6Lang Hames 21d6ef7fac1a020c58ec61cad2325e5f6afd0bbee6Lang Hames// Yep - these are thread safe. See the header for details. 2216dcaf59960d699735a57b1623092d561c18a165Lang Hamesnamespace { 2316dcaf59960d699735a57b1623092d561c18a165Lang Hames 2416dcaf59960d699735a57b1623092d561c18a165Lang Hames 2516dcaf59960d699735a57b1623092d561c18a165Lang Hames class EmptyIndexListEntry : public IndexListEntry { 2616dcaf59960d699735a57b1623092d561c18a165Lang Hames public: 2716dcaf59960d699735a57b1623092d561c18a165Lang Hames EmptyIndexListEntry() : IndexListEntry(EMPTY_KEY) {} 2816dcaf59960d699735a57b1623092d561c18a165Lang Hames }; 2916dcaf59960d699735a57b1623092d561c18a165Lang Hames 3016dcaf59960d699735a57b1623092d561c18a165Lang Hames class TombstoneIndexListEntry : public IndexListEntry { 3116dcaf59960d699735a57b1623092d561c18a165Lang Hames public: 3216dcaf59960d699735a57b1623092d561c18a165Lang Hames TombstoneIndexListEntry() : IndexListEntry(TOMBSTONE_KEY) {} 3316dcaf59960d699735a57b1623092d561c18a165Lang Hames }; 3416dcaf59960d699735a57b1623092d561c18a165Lang Hames 3516dcaf59960d699735a57b1623092d561c18a165Lang Hames // The following statics are thread safe. They're read only, and you 3616dcaf59960d699735a57b1623092d561c18a165Lang Hames // can't step from them to any other list entries. 3716dcaf59960d699735a57b1623092d561c18a165Lang Hames ManagedStatic<EmptyIndexListEntry> IndexListEntryEmptyKey; 3816dcaf59960d699735a57b1623092d561c18a165Lang Hames ManagedStatic<TombstoneIndexListEntry> IndexListEntryTombstoneKey; 3916dcaf59960d699735a57b1623092d561c18a165Lang Hames} 40233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames 41233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hameschar SlotIndexes::ID = 0; 42233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hamesstatic RegisterPass<SlotIndexes> X("slotindexes", "Slot index numbering"); 43233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames 4416dcaf59960d699735a57b1623092d561c18a165Lang HamesIndexListEntry* IndexListEntry::getEmptyKeyEntry() { 4516dcaf59960d699735a57b1623092d561c18a165Lang Hames return &*IndexListEntryEmptyKey; 4616dcaf59960d699735a57b1623092d561c18a165Lang Hames} 4716dcaf59960d699735a57b1623092d561c18a165Lang Hames 4816dcaf59960d699735a57b1623092d561c18a165Lang HamesIndexListEntry* IndexListEntry::getTombstoneKeyEntry() { 4916dcaf59960d699735a57b1623092d561c18a165Lang Hames return &*IndexListEntryTombstoneKey; 5016dcaf59960d699735a57b1623092d561c18a165Lang Hames} 5116dcaf59960d699735a57b1623092d561c18a165Lang Hames 5216dcaf59960d699735a57b1623092d561c18a165Lang Hames 53233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hamesvoid SlotIndexes::getAnalysisUsage(AnalysisUsage &au) const { 54233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames au.setPreservesAll(); 55233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames MachineFunctionPass::getAnalysisUsage(au); 56233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames} 57233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames 58233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hamesvoid SlotIndexes::releaseMemory() { 59233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames mi2iMap.clear(); 60233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames mbb2IdxMap.clear(); 61233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames idx2MBBMap.clear(); 62233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames terminatorGaps.clear(); 63233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames clearList(); 64233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames} 65233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames 66233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hamesbool SlotIndexes::runOnMachineFunction(MachineFunction &fn) { 67233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames 68233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames // Compute numbering as follows: 69233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames // Grab an iterator to the start of the index list. 70233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames // Iterate over all MBBs, and within each MBB all MIs, keeping the MI 71233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames // iterator in lock-step (though skipping it over indexes which have 72233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames // null pointers in the instruction field). 73233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames // At each iteration assert that the instruction pointed to in the index 74233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames // is the same one pointed to by the MI iterator. This 75233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames 76233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames // FIXME: This can be simplified. The mi2iMap_, Idx2MBBMap, etc. should 77233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames // only need to be set up once after the first numbering is computed. 78233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames 79233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames mf = &fn; 80233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames initList(); 81233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames 82233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames // Check that the list contains only the sentinal. 83233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames assert(indexListHead->getNext() == 0 && 84233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames "Index list non-empty at initial numbering?"); 85233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames assert(idx2MBBMap.empty() && 86233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames "Index -> MBB mapping non-empty at initial numbering?"); 87233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames assert(mbb2IdxMap.empty() && 88233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames "MBB -> Index mapping non-empty at initial numbering?"); 89233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames assert(mi2iMap.empty() && 90233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames "MachineInstr -> Index mapping non-empty at initial numbering?"); 91233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames 92233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames functionSize = 0; 93233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames unsigned index = 0; 94233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames 95233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames // Iterate over the the function. 96233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames for (MachineFunction::iterator mbbItr = mf->begin(), mbbEnd = mf->end(); 97233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames mbbItr != mbbEnd; ++mbbItr) { 98233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames MachineBasicBlock *mbb = &*mbbItr; 99233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames 100233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames // Insert an index for the MBB start. 101233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames push_back(createEntry(0, index)); 102233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames SlotIndex blockStartIndex(back(), SlotIndex::LOAD); 103233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames 104fbb8fa247ec13067d9ad3f0c426e2029d15222b2Lang Hames index += SlotIndex::NUM; 105233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames 106233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames for (MachineBasicBlock::iterator miItr = mbb->begin(), miEnd = mbb->end(); 107233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames miItr != miEnd; ++miItr) { 108233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames MachineInstr *mi = &*miItr; 109233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames 110233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames if (miItr == mbb->getFirstTerminator()) { 111233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames push_back(createEntry(0, index)); 112233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames terminatorGaps.insert( 113233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames std::make_pair(mbb, SlotIndex(back(), SlotIndex::PHI_BIT))); 114fbb8fa247ec13067d9ad3f0c426e2029d15222b2Lang Hames index += SlotIndex::NUM; 115233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames } 116233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames 117233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames // Insert a store index for the instr. 118233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames push_back(createEntry(mi, index)); 119233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames 120233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames // Save this base index in the maps. 121233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames mi2iMap.insert( 122233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames std::make_pair(mi, SlotIndex(back(), SlotIndex::LOAD))); 123233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames 124233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames ++functionSize; 125233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames 126233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames unsigned Slots = mi->getDesc().getNumDefs(); 127233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames if (Slots == 0) 128233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames Slots = 1; 129233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames 130fbb8fa247ec13067d9ad3f0c426e2029d15222b2Lang Hames index += (Slots + 1) * SlotIndex::NUM; 131233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames } 132233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames 133233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames if (mbb->getFirstTerminator() == mbb->end()) { 134233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames push_back(createEntry(0, index)); 135233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames terminatorGaps.insert( 136233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames std::make_pair(mbb, SlotIndex(back(), SlotIndex::PHI_BIT))); 137fbb8fa247ec13067d9ad3f0c426e2029d15222b2Lang Hames index += SlotIndex::NUM; 138233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames } 139233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames 140233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames SlotIndex blockEndIndex(back(), SlotIndex::STORE); 141233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames mbb2IdxMap.insert( 142233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames std::make_pair(mbb, std::make_pair(blockStartIndex, blockEndIndex))); 143233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames 144233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames idx2MBBMap.push_back(IdxMBBPair(blockStartIndex, mbb)); 145233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames } 146233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames 147233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames // One blank instruction at the end. 148233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames push_back(createEntry(0, index)); 149233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames 150233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames // Sort the Idx2MBBMap 151233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames std::sort(idx2MBBMap.begin(), idx2MBBMap.end(), Idx2MBBCompare()); 152233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames 153233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames DEBUG(dump()); 154233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames 155233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames // And we're done! 156233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames return false; 157233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames} 158233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames 159b3661585c0f87b6045f0d65b5cac16921ae27086Lang Hamesvoid SlotIndexes::renumberIndexes() { 160233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames 161fbb8fa247ec13067d9ad3f0c426e2029d15222b2Lang Hames // Renumber updates the index of every element of the index list. 162fbb8fa247ec13067d9ad3f0c426e2029d15222b2Lang Hames // If all instrs in the function have been allocated an index (which has been 163fbb8fa247ec13067d9ad3f0c426e2029d15222b2Lang Hames // placed in the index list in the order of instruction iteration) then the 164fbb8fa247ec13067d9ad3f0c426e2029d15222b2Lang Hames // resulting numbering will match what would have been generated by the 165fbb8fa247ec13067d9ad3f0c426e2029d15222b2Lang Hames // pass during the initial numbering of the function if the new instructions 166fbb8fa247ec13067d9ad3f0c426e2029d15222b2Lang Hames // had been present. 167233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames 168fbb8fa247ec13067d9ad3f0c426e2029d15222b2Lang Hames functionSize = 0; 169fbb8fa247ec13067d9ad3f0c426e2029d15222b2Lang Hames unsigned index = 0; 170fbb8fa247ec13067d9ad3f0c426e2029d15222b2Lang Hames 171fbb8fa247ec13067d9ad3f0c426e2029d15222b2Lang Hames for (IndexListEntry *curEntry = front(); curEntry != getTail(); 172fbb8fa247ec13067d9ad3f0c426e2029d15222b2Lang Hames curEntry = curEntry->getNext()) { 173fbb8fa247ec13067d9ad3f0c426e2029d15222b2Lang Hames 174fbb8fa247ec13067d9ad3f0c426e2029d15222b2Lang Hames curEntry->setIndex(index); 175fbb8fa247ec13067d9ad3f0c426e2029d15222b2Lang Hames 176fbb8fa247ec13067d9ad3f0c426e2029d15222b2Lang Hames if (curEntry->getInstr() == 0) { 177fbb8fa247ec13067d9ad3f0c426e2029d15222b2Lang Hames // MBB start entry or terminator gap. Just step index by 1. 178fbb8fa247ec13067d9ad3f0c426e2029d15222b2Lang Hames index += SlotIndex::NUM; 179fbb8fa247ec13067d9ad3f0c426e2029d15222b2Lang Hames } 180fbb8fa247ec13067d9ad3f0c426e2029d15222b2Lang Hames else { 181fbb8fa247ec13067d9ad3f0c426e2029d15222b2Lang Hames ++functionSize; 182fbb8fa247ec13067d9ad3f0c426e2029d15222b2Lang Hames unsigned Slots = curEntry->getInstr()->getDesc().getNumDefs(); 183fbb8fa247ec13067d9ad3f0c426e2029d15222b2Lang Hames if (Slots == 0) 184fbb8fa247ec13067d9ad3f0c426e2029d15222b2Lang Hames Slots = 1; 185233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames 186fbb8fa247ec13067d9ad3f0c426e2029d15222b2Lang Hames index += (Slots + 1) * SlotIndex::NUM; 187fbb8fa247ec13067d9ad3f0c426e2029d15222b2Lang Hames } 188fbb8fa247ec13067d9ad3f0c426e2029d15222b2Lang Hames } 189233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames} 190233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames 191233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hamesvoid SlotIndexes::dump() const { 192233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames for (const IndexListEntry *itr = front(); itr != getTail(); 193233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames itr = itr->getNext()) { 194233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames errs() << itr->getIndex() << " "; 195233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames 196233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames if (itr->getInstr() != 0) { 197233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames errs() << *itr->getInstr(); 198233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames } else { 199233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames errs() << "\n"; 200233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames } 201233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames } 202233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames 20381cf4325698b48b02eddab921ac333c7f25005c3Jeffrey Yasskin for (MBB2IdxMap::const_iterator itr = mbb2IdxMap.begin(); 204233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames itr != mbb2IdxMap.end(); ++itr) { 205233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames errs() << "MBB " << itr->first->getNumber() << " (" << itr->first << ") - [" 206233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames << itr->second.first << ", " << itr->second.second << "]\n"; 207233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames } 208233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames} 209233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames 210233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames// Print a SlotIndex to a raw_ostream. 211233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hamesvoid SlotIndex::print(raw_ostream &os) const { 212233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames os << getIndex(); 213233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames if (isPHI()) 214233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames os << "*"; 215233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames} 216233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames 217233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames// Dump a SlotIndex to stderr. 218233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hamesvoid SlotIndex::dump() const { 219233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames print(errs()); 220233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames errs() << "\n"; 221233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames} 222233a60ec40b41027ff429e2f2c27fa2be762f2e9Lang Hames 223