Andrew Trick | 2661b41 | 2012-07-07 04:00:00 +0000 | [diff] [blame] | 1 | //===- CodeGenSchedule.cpp - Scheduling MachineModels ---------------------===// |
| 2 | // |
| 3 | // The LLVM Compiler Infrastructure |
| 4 | // |
| 5 | // This file is distributed under the University of Illinois Open Source |
| 6 | // License. See LICENSE.TXT for details. |
| 7 | // |
| 8 | //===----------------------------------------------------------------------===// |
| 9 | // |
| 10 | // This file defines structures to encapsulate the machine model as decribed in |
| 11 | // the target description. |
| 12 | // |
| 13 | //===----------------------------------------------------------------------===// |
| 14 | |
| 15 | #define DEBUG_TYPE "subtarget-emitter" |
| 16 | |
| 17 | #include "CodeGenSchedule.h" |
| 18 | #include "CodeGenTarget.h" |
Andrew Trick | 48605c3 | 2012-09-15 00:19:57 +0000 | [diff] [blame^] | 19 | #include "llvm/TableGen/Error.h" |
Andrew Trick | 2661b41 | 2012-07-07 04:00:00 +0000 | [diff] [blame] | 20 | #include "llvm/Support/Debug.h" |
| 21 | |
| 22 | using namespace llvm; |
| 23 | |
Andrew Trick | 48605c3 | 2012-09-15 00:19:57 +0000 | [diff] [blame^] | 24 | #ifndef NDEBUG |
| 25 | static void dumpIdxVec(const IdxVec &V) { |
| 26 | for (unsigned i = 0, e = V.size(); i < e; ++i) { |
| 27 | dbgs() << V[i] << ", "; |
| 28 | } |
| 29 | } |
| 30 | #endif |
| 31 | |
| 32 | /// CodeGenModels ctor interprets machine model records and populates maps. |
Andrew Trick | 2661b41 | 2012-07-07 04:00:00 +0000 | [diff] [blame] | 33 | CodeGenSchedModels::CodeGenSchedModels(RecordKeeper &RK, |
| 34 | const CodeGenTarget &TGT): |
Andrew Trick | 48605c3 | 2012-09-15 00:19:57 +0000 | [diff] [blame^] | 35 | Records(RK), Target(TGT), NumItineraryClasses(0) { |
Andrew Trick | 2661b41 | 2012-07-07 04:00:00 +0000 | [diff] [blame] | 36 | |
Andrew Trick | 48605c3 | 2012-09-15 00:19:57 +0000 | [diff] [blame^] | 37 | // Instantiate a CodeGenProcModel for each SchedMachineModel with the values |
| 38 | // that are explicitly referenced in tablegen records. Resources associated |
| 39 | // with each processor will be derived later. Populate ProcModelMap with the |
| 40 | // CodeGenProcModel instances. |
| 41 | collectProcModels(); |
Andrew Trick | 2661b41 | 2012-07-07 04:00:00 +0000 | [diff] [blame] | 42 | |
Andrew Trick | 48605c3 | 2012-09-15 00:19:57 +0000 | [diff] [blame^] | 43 | // Instantiate a CodeGenSchedRW for each SchedReadWrite record explicitly |
| 44 | // defined, and populate SchedReads and SchedWrites vectors. Implicit |
| 45 | // SchedReadWrites that represent sequences derived from expanded variant will |
| 46 | // be inferred later. |
| 47 | collectSchedRW(); |
| 48 | |
| 49 | // Instantiate a CodeGenSchedClass for each unique SchedRW signature directly |
| 50 | // required by an instruction definition, and populate SchedClassIdxMap. Set |
| 51 | // NumItineraryClasses to the number of explicit itinerary classes referenced |
| 52 | // by instructions. Set NumInstrSchedClasses to the number of itinerary |
| 53 | // classes plus any classes implied by instructions that derive from class |
| 54 | // Sched and provide SchedRW list. This does not infer any new classes from |
| 55 | // SchedVariant. |
| 56 | collectSchedClasses(); |
| 57 | |
| 58 | // Find instruction itineraries for each processor. Sort and populate |
| 59 | // CodeGenProcMode::ItinDefList. (Cycle-to-cycle itineraries). This requires |
| 60 | // all itinerary classes to be discovered. |
| 61 | collectProcItins(); |
| 62 | |
| 63 | // Find ItinRW records for each processor and itinerary class. |
| 64 | // (For per-operand resources mapped to itinerary classes). |
| 65 | collectProcItinRW(); |
Andrew Trick | 2661b41 | 2012-07-07 04:00:00 +0000 | [diff] [blame] | 66 | } |
| 67 | |
Andrew Trick | 48605c3 | 2012-09-15 00:19:57 +0000 | [diff] [blame^] | 68 | /// Gather all processor models. |
| 69 | void CodeGenSchedModels::collectProcModels() { |
| 70 | RecVec ProcRecords = Records.getAllDerivedDefinitions("Processor"); |
| 71 | std::sort(ProcRecords.begin(), ProcRecords.end(), LessRecordFieldName()); |
Andrew Trick | 2661b41 | 2012-07-07 04:00:00 +0000 | [diff] [blame] | 72 | |
Andrew Trick | 48605c3 | 2012-09-15 00:19:57 +0000 | [diff] [blame^] | 73 | // Reserve space because we can. Reallocation would be ok. |
| 74 | ProcModels.reserve(ProcRecords.size()+1); |
| 75 | |
| 76 | // Use idx=0 for NoModel/NoItineraries. |
| 77 | Record *NoModelDef = Records.getDef("NoSchedModel"); |
| 78 | Record *NoItinsDef = Records.getDef("NoItineraries"); |
| 79 | ProcModels.push_back(CodeGenProcModel(0, "NoSchedModel", |
| 80 | NoModelDef, NoItinsDef)); |
| 81 | ProcModelMap[NoModelDef] = 0; |
| 82 | |
| 83 | // For each processor, find a unique machine model. |
| 84 | for (unsigned i = 0, N = ProcRecords.size(); i < N; ++i) |
| 85 | addProcModel(ProcRecords[i]); |
| 86 | } |
| 87 | |
| 88 | /// Get a unique processor model based on the defined MachineModel and |
| 89 | /// ProcessorItineraries. |
| 90 | void CodeGenSchedModels::addProcModel(Record *ProcDef) { |
| 91 | Record *ModelKey = getModelOrItinDef(ProcDef); |
| 92 | if (!ProcModelMap.insert(std::make_pair(ModelKey, ProcModels.size())).second) |
| 93 | return; |
| 94 | |
| 95 | std::string Name = ModelKey->getName(); |
| 96 | if (ModelKey->isSubClassOf("SchedMachineModel")) { |
| 97 | Record *ItinsDef = ModelKey->getValueAsDef("Itineraries"); |
| 98 | ProcModels.push_back( |
| 99 | CodeGenProcModel(ProcModels.size(), Name, ModelKey, ItinsDef)); |
| 100 | } |
| 101 | else { |
| 102 | // An itinerary is defined without a machine model. Infer a new model. |
| 103 | if (!ModelKey->getValueAsListOfDefs("IID").empty()) |
| 104 | Name = Name + "Model"; |
| 105 | ProcModels.push_back( |
| 106 | CodeGenProcModel(ProcModels.size(), Name, |
| 107 | ProcDef->getValueAsDef("SchedModel"), ModelKey)); |
| 108 | } |
| 109 | DEBUG(ProcModels.back().dump()); |
| 110 | } |
| 111 | |
| 112 | // Recursively find all reachable SchedReadWrite records. |
| 113 | static void scanSchedRW(Record *RWDef, RecVec &RWDefs, |
| 114 | SmallPtrSet<Record*, 16> &RWSet) { |
| 115 | if (!RWSet.insert(RWDef)) |
| 116 | return; |
| 117 | RWDefs.push_back(RWDef); |
| 118 | // Reads don't current have sequence records, but it can be added later. |
| 119 | if (RWDef->isSubClassOf("WriteSequence")) { |
| 120 | RecVec Seq = RWDef->getValueAsListOfDefs("Writes"); |
| 121 | for (RecIter I = Seq.begin(), E = Seq.end(); I != E; ++I) |
| 122 | scanSchedRW(*I, RWDefs, RWSet); |
| 123 | } |
| 124 | else if (RWDef->isSubClassOf("SchedVariant")) { |
| 125 | // Visit each variant (guarded by a different predicate). |
| 126 | RecVec Vars = RWDef->getValueAsListOfDefs("Variants"); |
| 127 | for (RecIter VI = Vars.begin(), VE = Vars.end(); VI != VE; ++VI) { |
| 128 | // Visit each RW in the sequence selected by the current variant. |
| 129 | RecVec Selected = (*VI)->getValueAsListOfDefs("Selected"); |
| 130 | for (RecIter I = Selected.begin(), E = Selected.end(); I != E; ++I) |
| 131 | scanSchedRW(*I, RWDefs, RWSet); |
| 132 | } |
| 133 | } |
| 134 | } |
| 135 | |
| 136 | // Collect and sort all SchedReadWrites reachable via tablegen records. |
| 137 | // More may be inferred later when inferring new SchedClasses from variants. |
| 138 | void CodeGenSchedModels::collectSchedRW() { |
| 139 | // Reserve idx=0 for invalid writes/reads. |
| 140 | SchedWrites.resize(1); |
| 141 | SchedReads.resize(1); |
| 142 | |
| 143 | SmallPtrSet<Record*, 16> RWSet; |
| 144 | |
| 145 | // Find all SchedReadWrites referenced by instruction defs. |
| 146 | RecVec SWDefs, SRDefs; |
| 147 | for (CodeGenTarget::inst_iterator I = Target.inst_begin(), |
| 148 | E = Target.inst_end(); I != E; ++I) { |
| 149 | Record *SchedDef = (*I)->TheDef; |
| 150 | if (!SchedDef->isSubClassOf("Sched")) |
| 151 | continue; |
| 152 | RecVec RWs = SchedDef->getValueAsListOfDefs("SchedRW"); |
| 153 | for (RecIter RWI = RWs.begin(), RWE = RWs.end(); RWI != RWE; ++RWI) { |
| 154 | if ((*RWI)->isSubClassOf("SchedWrite")) |
| 155 | scanSchedRW(*RWI, SWDefs, RWSet); |
| 156 | else { |
| 157 | assert((*RWI)->isSubClassOf("SchedRead") && "Unknown SchedReadWrite"); |
| 158 | scanSchedRW(*RWI, SRDefs, RWSet); |
| 159 | } |
| 160 | } |
| 161 | } |
| 162 | // Find all ReadWrites referenced by InstRW. |
| 163 | RecVec InstRWDefs = Records.getAllDerivedDefinitions("InstRW"); |
| 164 | for (RecIter OI = InstRWDefs.begin(), OE = InstRWDefs.end(); OI != OE; ++OI) { |
| 165 | // For all OperandReadWrites. |
| 166 | RecVec RWDefs = (*OI)->getValueAsListOfDefs("OperandReadWrites"); |
| 167 | for (RecIter RWI = RWDefs.begin(), RWE = RWDefs.end(); |
| 168 | RWI != RWE; ++RWI) { |
| 169 | if ((*RWI)->isSubClassOf("SchedWrite")) |
| 170 | scanSchedRW(*RWI, SWDefs, RWSet); |
| 171 | else { |
| 172 | assert((*RWI)->isSubClassOf("SchedRead") && "Unknown SchedReadWrite"); |
| 173 | scanSchedRW(*RWI, SRDefs, RWSet); |
| 174 | } |
| 175 | } |
| 176 | } |
| 177 | // Find all ReadWrites referenced by ItinRW. |
| 178 | RecVec ItinRWDefs = Records.getAllDerivedDefinitions("ItinRW"); |
| 179 | for (RecIter II = ItinRWDefs.begin(), IE = ItinRWDefs.end(); II != IE; ++II) { |
| 180 | // For all OperandReadWrites. |
| 181 | RecVec RWDefs = (*II)->getValueAsListOfDefs("OperandReadWrites"); |
| 182 | for (RecIter RWI = RWDefs.begin(), RWE = RWDefs.end(); |
| 183 | RWI != RWE; ++RWI) { |
| 184 | if ((*RWI)->isSubClassOf("SchedWrite")) |
| 185 | scanSchedRW(*RWI, SWDefs, RWSet); |
| 186 | else { |
| 187 | assert((*RWI)->isSubClassOf("SchedRead") && "Unknown SchedReadWrite"); |
| 188 | scanSchedRW(*RWI, SRDefs, RWSet); |
| 189 | } |
| 190 | } |
| 191 | } |
| 192 | // Sort and add the SchedReadWrites directly referenced by instructions or |
| 193 | // itinerary resources. Index reads and writes in separate domains. |
| 194 | std::sort(SWDefs.begin(), SWDefs.end(), LessRecord()); |
| 195 | for (RecIter SWI = SWDefs.begin(), SWE = SWDefs.end(); SWI != SWE; ++SWI) { |
| 196 | assert(!getSchedRWIdx(*SWI, /*IsRead=*/false) && "duplicate SchedWrite"); |
| 197 | SchedWrites.push_back(CodeGenSchedRW(*SWI)); |
| 198 | } |
| 199 | std::sort(SRDefs.begin(), SRDefs.end(), LessRecord()); |
| 200 | for (RecIter SRI = SRDefs.begin(), SRE = SRDefs.end(); SRI != SRE; ++SRI) { |
| 201 | assert(!getSchedRWIdx(*SRI, /*IsRead-*/true) && "duplicate SchedWrite"); |
| 202 | SchedReads.push_back(CodeGenSchedRW(*SRI)); |
| 203 | } |
| 204 | // Initialize WriteSequence vectors. |
| 205 | for (std::vector<CodeGenSchedRW>::iterator WI = SchedWrites.begin(), |
| 206 | WE = SchedWrites.end(); WI != WE; ++WI) { |
| 207 | if (!WI->IsSequence) |
| 208 | continue; |
| 209 | findRWs(WI->TheDef->getValueAsListOfDefs("Writes"), WI->Sequence, |
| 210 | /*IsRead=*/false); |
| 211 | } |
| 212 | DEBUG( |
| 213 | for (unsigned WIdx = 0, WEnd = SchedWrites.size(); WIdx != WEnd; ++WIdx) { |
| 214 | dbgs() << WIdx << ": "; |
| 215 | SchedWrites[WIdx].dump(); |
| 216 | dbgs() << '\n'; |
| 217 | } |
| 218 | for (unsigned RIdx = 0, REnd = SchedReads.size(); RIdx != REnd; ++RIdx) { |
| 219 | dbgs() << RIdx << ": "; |
| 220 | SchedReads[RIdx].dump(); |
| 221 | dbgs() << '\n'; |
| 222 | } |
| 223 | RecVec RWDefs = Records.getAllDerivedDefinitions("SchedReadWrite"); |
| 224 | for (RecIter RI = RWDefs.begin(), RE = RWDefs.end(); |
| 225 | RI != RE; ++RI) { |
| 226 | if (!getSchedRWIdx(*RI, (*RI)->isSubClassOf("SchedRead"))) { |
| 227 | const std::string &Name = (*RI)->getName(); |
| 228 | if (Name != "NoWrite" && Name != "ReadDefault") |
| 229 | dbgs() << "Unused SchedReadWrite " << (*RI)->getName() << '\n'; |
| 230 | } |
| 231 | }); |
| 232 | } |
| 233 | |
| 234 | /// Compute a SchedWrite name from a sequence of writes. |
| 235 | std::string CodeGenSchedModels::genRWName(const IdxVec& Seq, bool IsRead) { |
| 236 | std::string Name("("); |
| 237 | for (IdxIter I = Seq.begin(), E = Seq.end(); I != E; ++I) { |
| 238 | if (I != Seq.begin()) |
| 239 | Name += '_'; |
| 240 | Name += getSchedRW(*I, IsRead).Name; |
| 241 | } |
| 242 | Name += ')'; |
| 243 | return Name; |
| 244 | } |
| 245 | |
| 246 | unsigned CodeGenSchedModels::getSchedRWIdx(Record *Def, bool IsRead, |
| 247 | unsigned After) const { |
| 248 | const std::vector<CodeGenSchedRW> &RWVec = IsRead ? SchedReads : SchedWrites; |
| 249 | assert(After < RWVec.size() && "start position out of bounds"); |
| 250 | for (std::vector<CodeGenSchedRW>::const_iterator I = RWVec.begin() + After, |
| 251 | E = RWVec.end(); I != E; ++I) { |
| 252 | if (I->TheDef == Def) |
| 253 | return I - RWVec.begin(); |
| 254 | } |
| 255 | return 0; |
| 256 | } |
| 257 | |
| 258 | namespace llvm { |
| 259 | void splitSchedReadWrites(const RecVec &RWDefs, |
| 260 | RecVec &WriteDefs, RecVec &ReadDefs) { |
| 261 | for (RecIter RWI = RWDefs.begin(), RWE = RWDefs.end(); RWI != RWE; ++RWI) { |
| 262 | if ((*RWI)->isSubClassOf("SchedWrite")) |
| 263 | WriteDefs.push_back(*RWI); |
| 264 | else { |
| 265 | assert((*RWI)->isSubClassOf("SchedRead") && "unknown SchedReadWrite"); |
| 266 | ReadDefs.push_back(*RWI); |
| 267 | } |
| 268 | } |
| 269 | } |
| 270 | } // namespace llvm |
| 271 | |
| 272 | // Split the SchedReadWrites defs and call findRWs for each list. |
| 273 | void CodeGenSchedModels::findRWs(const RecVec &RWDefs, |
| 274 | IdxVec &Writes, IdxVec &Reads) const { |
| 275 | RecVec WriteDefs; |
| 276 | RecVec ReadDefs; |
| 277 | splitSchedReadWrites(RWDefs, WriteDefs, ReadDefs); |
| 278 | findRWs(WriteDefs, Writes, false); |
| 279 | findRWs(ReadDefs, Reads, true); |
| 280 | } |
| 281 | |
| 282 | // Call getSchedRWIdx for all elements in a sequence of SchedRW defs. |
| 283 | void CodeGenSchedModels::findRWs(const RecVec &RWDefs, IdxVec &RWs, |
| 284 | bool IsRead) const { |
| 285 | for (RecIter RI = RWDefs.begin(), RE = RWDefs.end(); RI != RE; ++RI) { |
| 286 | unsigned Idx = getSchedRWIdx(*RI, IsRead); |
| 287 | assert(Idx && "failed to collect SchedReadWrite"); |
| 288 | RWs.push_back(Idx); |
| 289 | } |
| 290 | } |
| 291 | |
| 292 | /// Visit all the instruction definitions for this target to gather and |
| 293 | /// enumerate the itinerary classes. These are the explicitly specified |
| 294 | /// SchedClasses. More SchedClasses may be inferred. |
| 295 | void CodeGenSchedModels::collectSchedClasses() { |
| 296 | |
| 297 | // NoItinerary is always the first class at Idx=0 |
Andrew Trick | 2661b41 | 2012-07-07 04:00:00 +0000 | [diff] [blame] | 298 | SchedClasses.resize(1); |
| 299 | SchedClasses.back().Name = "NoItinerary"; |
Andrew Trick | 48605c3 | 2012-09-15 00:19:57 +0000 | [diff] [blame^] | 300 | SchedClasses.back().ProcIndices.push_back(0); |
Andrew Trick | 2661b41 | 2012-07-07 04:00:00 +0000 | [diff] [blame] | 301 | SchedClassIdxMap[SchedClasses.back().Name] = 0; |
| 302 | |
| 303 | // Gather and sort all itinerary classes used by instruction descriptions. |
Andrew Trick | 48605c3 | 2012-09-15 00:19:57 +0000 | [diff] [blame^] | 304 | RecVec ItinClassList; |
Andrew Trick | 2661b41 | 2012-07-07 04:00:00 +0000 | [diff] [blame] | 305 | for (CodeGenTarget::inst_iterator I = Target.inst_begin(), |
| 306 | E = Target.inst_end(); I != E; ++I) { |
Andrew Trick | 48605c3 | 2012-09-15 00:19:57 +0000 | [diff] [blame^] | 307 | Record *ItinDef = (*I)->TheDef->getValueAsDef("Itinerary"); |
Andrew Trick | 2661b41 | 2012-07-07 04:00:00 +0000 | [diff] [blame] | 308 | // Map a new SchedClass with no index. |
Andrew Trick | 48605c3 | 2012-09-15 00:19:57 +0000 | [diff] [blame^] | 309 | if (!SchedClassIdxMap.count(ItinDef->getName())) { |
| 310 | SchedClassIdxMap[ItinDef->getName()] = 0; |
| 311 | ItinClassList.push_back(ItinDef); |
Andrew Trick | 2661b41 | 2012-07-07 04:00:00 +0000 | [diff] [blame] | 312 | } |
| 313 | } |
| 314 | // Assign each itinerary class unique number, skipping NoItinerary==0 |
| 315 | NumItineraryClasses = ItinClassList.size(); |
| 316 | std::sort(ItinClassList.begin(), ItinClassList.end(), LessRecord()); |
| 317 | for (unsigned i = 0, N = NumItineraryClasses; i < N; i++) { |
| 318 | Record *ItinDef = ItinClassList[i]; |
| 319 | SchedClassIdxMap[ItinDef->getName()] = SchedClasses.size(); |
| 320 | SchedClasses.push_back(CodeGenSchedClass(ItinDef)); |
| 321 | } |
Andrew Trick | 48605c3 | 2012-09-15 00:19:57 +0000 | [diff] [blame^] | 322 | // Infer classes from SchedReadWrite resources listed for each |
| 323 | // instruction definition that inherits from class Sched. |
| 324 | for (CodeGenTarget::inst_iterator I = Target.inst_begin(), |
| 325 | E = Target.inst_end(); I != E; ++I) { |
| 326 | if (!(*I)->TheDef->isSubClassOf("Sched")) |
| 327 | continue; |
| 328 | IdxVec Writes, Reads; |
| 329 | findRWs((*I)->TheDef->getValueAsListOfDefs("SchedRW"), Writes, Reads); |
| 330 | // ProcIdx == 0 indicates the class applies to all processors. |
| 331 | IdxVec ProcIndices(1, 0); |
| 332 | addSchedClass(Writes, Reads, ProcIndices); |
| 333 | } |
| 334 | // Create classes for InstReadWrite defs. |
| 335 | RecVec InstRWDefs = Records.getAllDerivedDefinitions("InstRW"); |
| 336 | std::sort(InstRWDefs.begin(), InstRWDefs.end(), LessRecord()); |
| 337 | for (RecIter OI = InstRWDefs.begin(), OE = InstRWDefs.end(); OI != OE; ++OI) |
| 338 | createInstRWClass(*OI); |
Andrew Trick | 2661b41 | 2012-07-07 04:00:00 +0000 | [diff] [blame] | 339 | |
Andrew Trick | 48605c3 | 2012-09-15 00:19:57 +0000 | [diff] [blame^] | 340 | NumInstrSchedClasses = SchedClasses.size(); |
Andrew Trick | 2661b41 | 2012-07-07 04:00:00 +0000 | [diff] [blame] | 341 | |
Andrew Trick | 48605c3 | 2012-09-15 00:19:57 +0000 | [diff] [blame^] | 342 | bool EnableDump = false; |
| 343 | DEBUG(EnableDump = true); |
| 344 | if (!EnableDump) |
Andrew Trick | 2661b41 | 2012-07-07 04:00:00 +0000 | [diff] [blame] | 345 | return; |
Andrew Trick | 48605c3 | 2012-09-15 00:19:57 +0000 | [diff] [blame^] | 346 | for (CodeGenTarget::inst_iterator I = Target.inst_begin(), |
| 347 | E = Target.inst_end(); I != E; ++I) { |
| 348 | Record *SchedDef = (*I)->TheDef; |
| 349 | std::string InstName = (*I)->TheDef->getName(); |
| 350 | if (SchedDef->isSubClassOf("Sched")) { |
| 351 | IdxVec Writes; |
| 352 | IdxVec Reads; |
| 353 | findRWs((*I)->TheDef->getValueAsListOfDefs("SchedRW"), Writes, Reads); |
| 354 | dbgs() << "SchedRW machine model for " << InstName; |
| 355 | for (IdxIter WI = Writes.begin(), WE = Writes.end(); WI != WE; ++WI) |
| 356 | dbgs() << " " << SchedWrites[*WI].Name; |
| 357 | for (IdxIter RI = Reads.begin(), RE = Reads.end(); RI != RE; ++RI) |
| 358 | dbgs() << " " << SchedReads[*RI].Name; |
| 359 | dbgs() << '\n'; |
| 360 | } |
| 361 | unsigned SCIdx = InstrClassMap.lookup((*I)->TheDef); |
| 362 | if (SCIdx) { |
| 363 | const RecVec &RWDefs = SchedClasses[SCIdx].InstRWs; |
| 364 | for (RecIter RWI = RWDefs.begin(), RWE = RWDefs.end(); |
| 365 | RWI != RWE; ++RWI) { |
| 366 | const CodeGenProcModel &ProcModel = |
| 367 | getProcModel((*RWI)->getValueAsDef("SchedModel")); |
| 368 | dbgs() << "InstrRW on " << ProcModel.ModelName << " for " << InstName; |
| 369 | IdxVec Writes; |
| 370 | IdxVec Reads; |
| 371 | findRWs((*RWI)->getValueAsListOfDefs("OperandReadWrites"), |
| 372 | Writes, Reads); |
| 373 | for (IdxIter WI = Writes.begin(), WE = Writes.end(); WI != WE; ++WI) |
| 374 | dbgs() << " " << SchedWrites[*WI].Name; |
| 375 | for (IdxIter RI = Reads.begin(), RE = Reads.end(); RI != RE; ++RI) |
| 376 | dbgs() << " " << SchedReads[*RI].Name; |
| 377 | dbgs() << '\n'; |
| 378 | } |
| 379 | continue; |
| 380 | } |
| 381 | if (!SchedDef->isSubClassOf("Sched") |
| 382 | && (SchedDef->getValueAsDef("Itinerary")->getName() == "NoItinerary")) { |
| 383 | dbgs() << "No machine model for " << (*I)->TheDef->getName() << '\n'; |
Andrew Trick | 2661b41 | 2012-07-07 04:00:00 +0000 | [diff] [blame] | 384 | } |
| 385 | } |
Andrew Trick | 48605c3 | 2012-09-15 00:19:57 +0000 | [diff] [blame^] | 386 | } |
| 387 | |
| 388 | unsigned CodeGenSchedModels::getSchedClassIdx( |
| 389 | const RecVec &RWDefs) const { |
| 390 | |
| 391 | IdxVec Writes, Reads; |
| 392 | findRWs(RWDefs, Writes, Reads); |
| 393 | return findSchedClassIdx(Writes, Reads); |
| 394 | } |
| 395 | |
| 396 | /// Find an SchedClass that has been inferred from a per-operand list of |
| 397 | /// SchedWrites and SchedReads. |
| 398 | unsigned CodeGenSchedModels::findSchedClassIdx(const IdxVec &Writes, |
| 399 | const IdxVec &Reads) const { |
| 400 | for (SchedClassIter I = schedClassBegin(), E = schedClassEnd(); I != E; ++I) { |
| 401 | // Classes with InstRWs may have the same Writes/Reads as a class originally |
| 402 | // produced by a SchedRW definition. We need to be able to recover the |
| 403 | // original class index for processors that don't match any InstRWs. |
| 404 | if (I->ItinClassDef || !I->InstRWs.empty()) |
| 405 | continue; |
| 406 | |
| 407 | if (I->Writes == Writes && I->Reads == Reads) { |
| 408 | return I - schedClassBegin(); |
| 409 | } |
Andrew Trick | 2661b41 | 2012-07-07 04:00:00 +0000 | [diff] [blame] | 410 | } |
Andrew Trick | 48605c3 | 2012-09-15 00:19:57 +0000 | [diff] [blame^] | 411 | return 0; |
| 412 | } |
Andrew Trick | 2661b41 | 2012-07-07 04:00:00 +0000 | [diff] [blame] | 413 | |
Andrew Trick | 48605c3 | 2012-09-15 00:19:57 +0000 | [diff] [blame^] | 414 | // Get the SchedClass index for an instruction. |
| 415 | unsigned CodeGenSchedModels::getSchedClassIdx( |
| 416 | const CodeGenInstruction &Inst) const { |
Andrew Trick | 2661b41 | 2012-07-07 04:00:00 +0000 | [diff] [blame] | 417 | |
Andrew Trick | 48605c3 | 2012-09-15 00:19:57 +0000 | [diff] [blame^] | 418 | unsigned SCIdx = InstrClassMap.lookup(Inst.TheDef); |
| 419 | if (SCIdx) |
| 420 | return SCIdx; |
Andrew Trick | 2661b41 | 2012-07-07 04:00:00 +0000 | [diff] [blame] | 421 | |
Andrew Trick | 48605c3 | 2012-09-15 00:19:57 +0000 | [diff] [blame^] | 422 | // If this opcode isn't mapped by the subtarget fallback to the instruction |
| 423 | // definition's SchedRW or ItinDef values. |
| 424 | if (Inst.TheDef->isSubClassOf("Sched")) { |
| 425 | RecVec RWs = Inst.TheDef->getValueAsListOfDefs("SchedRW"); |
| 426 | return getSchedClassIdx(RWs); |
| 427 | } |
| 428 | Record *ItinDef = Inst.TheDef->getValueAsDef("Itinerary"); |
| 429 | assert(SchedClassIdxMap.count(ItinDef->getName()) && "missing ItinClass"); |
| 430 | unsigned Idx = SchedClassIdxMap.lookup(ItinDef->getName()); |
| 431 | assert(Idx <= NumItineraryClasses && "bad ItinClass index"); |
| 432 | return Idx; |
| 433 | } |
| 434 | |
| 435 | std::string CodeGenSchedModels::createSchedClassName( |
| 436 | const IdxVec &OperWrites, const IdxVec &OperReads) { |
| 437 | |
| 438 | std::string Name; |
| 439 | for (IdxIter WI = OperWrites.begin(), WE = OperWrites.end(); WI != WE; ++WI) { |
| 440 | if (WI != OperWrites.begin()) |
| 441 | Name += '_'; |
| 442 | Name += SchedWrites[*WI].Name; |
| 443 | } |
| 444 | for (IdxIter RI = OperReads.begin(), RE = OperReads.end(); RI != RE; ++RI) { |
| 445 | Name += '_'; |
| 446 | Name += SchedReads[*RI].Name; |
| 447 | } |
| 448 | return Name; |
| 449 | } |
| 450 | |
| 451 | std::string CodeGenSchedModels::createSchedClassName(const RecVec &InstDefs) { |
| 452 | |
| 453 | std::string Name; |
| 454 | for (RecIter I = InstDefs.begin(), E = InstDefs.end(); I != E; ++I) { |
| 455 | if (I != InstDefs.begin()) |
| 456 | Name += '_'; |
| 457 | Name += (*I)->getName(); |
| 458 | } |
| 459 | return Name; |
| 460 | } |
| 461 | |
| 462 | /// Add an inferred sched class from a per-operand list of SchedWrites and |
| 463 | /// SchedReads. ProcIndices contains the set of IDs of processors that may |
| 464 | /// utilize this class. |
| 465 | unsigned CodeGenSchedModels::addSchedClass(const IdxVec &OperWrites, |
| 466 | const IdxVec &OperReads, |
| 467 | const IdxVec &ProcIndices) |
| 468 | { |
| 469 | assert(!ProcIndices.empty() && "expect at least one ProcIdx"); |
| 470 | |
| 471 | unsigned Idx = findSchedClassIdx(OperWrites, OperReads); |
| 472 | if (Idx) { |
| 473 | IdxVec PI; |
| 474 | std::set_union(SchedClasses[Idx].ProcIndices.begin(), |
| 475 | SchedClasses[Idx].ProcIndices.end(), |
| 476 | ProcIndices.begin(), ProcIndices.end(), |
| 477 | std::back_inserter(PI)); |
| 478 | SchedClasses[Idx].ProcIndices.swap(PI); |
| 479 | return Idx; |
| 480 | } |
| 481 | Idx = SchedClasses.size(); |
| 482 | SchedClasses.resize(Idx+1); |
| 483 | CodeGenSchedClass &SC = SchedClasses.back(); |
| 484 | SC.Name = createSchedClassName(OperWrites, OperReads); |
| 485 | SC.Writes = OperWrites; |
| 486 | SC.Reads = OperReads; |
| 487 | SC.ProcIndices = ProcIndices; |
| 488 | |
| 489 | return Idx; |
| 490 | } |
| 491 | |
| 492 | // Create classes for each set of opcodes that are in the same InstReadWrite |
| 493 | // definition across all processors. |
| 494 | void CodeGenSchedModels::createInstRWClass(Record *InstRWDef) { |
| 495 | // ClassInstrs will hold an entry for each subset of Instrs in InstRWDef that |
| 496 | // intersects with an existing class via a previous InstRWDef. Instrs that do |
| 497 | // not intersect with an existing class refer back to their former class as |
| 498 | // determined from ItinDef or SchedRW. |
| 499 | SmallVector<std::pair<unsigned, SmallVector<Record *, 8> >, 4> ClassInstrs; |
| 500 | // Sort Instrs into sets. |
| 501 | RecVec InstDefs = InstRWDef->getValueAsListOfDefs("Instrs"); |
| 502 | std::sort(InstDefs.begin(), InstDefs.end(), LessRecord()); |
| 503 | for (RecIter I = InstDefs.begin(), E = InstDefs.end(); I != E; ++I) { |
| 504 | unsigned SCIdx = 0; |
| 505 | InstClassMapTy::const_iterator Pos = InstrClassMap.find(*I); |
| 506 | if (Pos != InstrClassMap.end()) |
| 507 | SCIdx = Pos->second; |
| 508 | else { |
| 509 | // This instruction has not been mapped yet. Get the original class. All |
| 510 | // instructions in the same InstrRW class must be from the same original |
| 511 | // class because that is the fall-back class for other processors. |
| 512 | Record *ItinDef = (*I)->getValueAsDef("Itinerary"); |
| 513 | SCIdx = SchedClassIdxMap.lookup(ItinDef->getName()); |
| 514 | if (!SCIdx && (*I)->isSubClassOf("Sched")) |
| 515 | SCIdx = getSchedClassIdx((*I)->getValueAsListOfDefs("SchedRW")); |
| 516 | } |
| 517 | unsigned CIdx = 0, CEnd = ClassInstrs.size(); |
| 518 | for (; CIdx != CEnd; ++CIdx) { |
| 519 | if (ClassInstrs[CIdx].first == SCIdx) |
| 520 | break; |
| 521 | } |
| 522 | if (CIdx == CEnd) { |
| 523 | ClassInstrs.resize(CEnd + 1); |
| 524 | ClassInstrs[CIdx].first = SCIdx; |
| 525 | } |
| 526 | ClassInstrs[CIdx].second.push_back(*I); |
| 527 | } |
| 528 | // For each set of Instrs, create a new class if necessary, and map or remap |
| 529 | // the Instrs to it. |
| 530 | unsigned CIdx = 0, CEnd = ClassInstrs.size(); |
| 531 | for (; CIdx != CEnd; ++CIdx) { |
| 532 | unsigned OldSCIdx = ClassInstrs[CIdx].first; |
| 533 | ArrayRef<Record*> InstDefs = ClassInstrs[CIdx].second; |
| 534 | // If the all instrs in the current class are accounted for, then leave |
| 535 | // them mapped to their old class. |
| 536 | if (SchedClasses[OldSCIdx].InstRWs.size() == InstDefs.size()) { |
| 537 | assert(SchedClasses[OldSCIdx].ProcIndices[0] == 0 && |
| 538 | "expected a generic SchedClass"); |
| 539 | continue; |
| 540 | } |
| 541 | unsigned SCIdx = SchedClasses.size(); |
| 542 | SchedClasses.resize(SCIdx+1); |
| 543 | CodeGenSchedClass &SC = SchedClasses.back(); |
| 544 | SC.Name = createSchedClassName(InstDefs); |
| 545 | // Preserve ItinDef and Writes/Reads for processors without an InstRW entry. |
| 546 | SC.ItinClassDef = SchedClasses[OldSCIdx].ItinClassDef; |
| 547 | SC.Writes = SchedClasses[OldSCIdx].Writes; |
| 548 | SC.Reads = SchedClasses[OldSCIdx].Reads; |
| 549 | SC.ProcIndices.push_back(0); |
| 550 | // Map each Instr to this new class. |
| 551 | // Note that InstDefs may be a smaller list than InstRWDef's "Instrs". |
| 552 | for (ArrayRef<Record*>::const_iterator |
| 553 | II = InstDefs.begin(), IE = InstDefs.end(); II != IE; ++II) { |
| 554 | unsigned OldSCIdx = InstrClassMap[*II]; |
| 555 | if (OldSCIdx) { |
| 556 | SC.InstRWs.insert(SC.InstRWs.end(), |
| 557 | SchedClasses[OldSCIdx].InstRWs.begin(), |
| 558 | SchedClasses[OldSCIdx].InstRWs.end()); |
| 559 | } |
| 560 | InstrClassMap[*II] = SCIdx; |
| 561 | } |
| 562 | SC.InstRWs.push_back(InstRWDef); |
| 563 | } |
Andrew Trick | 2661b41 | 2012-07-07 04:00:00 +0000 | [diff] [blame] | 564 | } |
| 565 | |
| 566 | // Gather the processor itineraries. |
Andrew Trick | 48605c3 | 2012-09-15 00:19:57 +0000 | [diff] [blame^] | 567 | void CodeGenSchedModels::collectProcItins() { |
| 568 | for (std::vector<CodeGenProcModel>::iterator PI = ProcModels.begin(), |
| 569 | PE = ProcModels.end(); PI != PE; ++PI) { |
| 570 | CodeGenProcModel &ProcModel = *PI; |
| 571 | RecVec ItinRecords = ProcModel.ItinsDef->getValueAsListOfDefs("IID"); |
| 572 | // Skip empty itinerary. |
| 573 | if (ItinRecords.empty()) |
Andrew Trick | 2661b41 | 2012-07-07 04:00:00 +0000 | [diff] [blame] | 574 | continue; |
Andrew Trick | 48605c3 | 2012-09-15 00:19:57 +0000 | [diff] [blame^] | 575 | |
| 576 | ProcModel.ItinDefList.resize(NumItineraryClasses+1); |
| 577 | |
| 578 | // Insert each itinerary data record in the correct position within |
| 579 | // the processor model's ItinDefList. |
| 580 | for (unsigned i = 0, N = ItinRecords.size(); i < N; i++) { |
| 581 | Record *ItinData = ItinRecords[i]; |
| 582 | Record *ItinDef = ItinData->getValueAsDef("TheClass"); |
| 583 | if (!SchedClassIdxMap.count(ItinDef->getName())) { |
| 584 | DEBUG(dbgs() << ProcModel.ItinsDef->getName() |
| 585 | << " has unused itinerary class " << ItinDef->getName() << '\n'); |
| 586 | continue; |
| 587 | } |
| 588 | assert(SchedClassIdxMap.count(ItinDef->getName()) && "missing ItinClass"); |
| 589 | unsigned Idx = SchedClassIdxMap.lookup(ItinDef->getName()); |
| 590 | assert(Idx <= NumItineraryClasses && "bad ItinClass index"); |
| 591 | ProcModel.ItinDefList[Idx] = ItinData; |
Andrew Trick | 2661b41 | 2012-07-07 04:00:00 +0000 | [diff] [blame] | 592 | } |
Andrew Trick | 48605c3 | 2012-09-15 00:19:57 +0000 | [diff] [blame^] | 593 | // Check for missing itinerary entries. |
| 594 | assert(!ProcModel.ItinDefList[0] && "NoItinerary class can't have rec"); |
| 595 | DEBUG( |
| 596 | for (unsigned i = 1, N = ProcModel.ItinDefList.size(); i < N; ++i) { |
| 597 | if (!ProcModel.ItinDefList[i]) |
| 598 | dbgs() << ProcModel.ItinsDef->getName() |
| 599 | << " missing itinerary for class " |
| 600 | << SchedClasses[i].Name << '\n'; |
| 601 | }); |
Andrew Trick | 2661b41 | 2012-07-07 04:00:00 +0000 | [diff] [blame] | 602 | } |
Andrew Trick | 2661b41 | 2012-07-07 04:00:00 +0000 | [diff] [blame] | 603 | } |
Andrew Trick | 48605c3 | 2012-09-15 00:19:57 +0000 | [diff] [blame^] | 604 | |
| 605 | // Gather the read/write types for each itinerary class. |
| 606 | void CodeGenSchedModels::collectProcItinRW() { |
| 607 | RecVec ItinRWDefs = Records.getAllDerivedDefinitions("ItinRW"); |
| 608 | std::sort(ItinRWDefs.begin(), ItinRWDefs.end(), LessRecord()); |
| 609 | for (RecIter II = ItinRWDefs.begin(), IE = ItinRWDefs.end(); II != IE; ++II) { |
| 610 | if (!(*II)->getValueInit("SchedModel")->isComplete()) |
| 611 | throw TGError((*II)->getLoc(), "SchedModel is undefined"); |
| 612 | Record *ModelDef = (*II)->getValueAsDef("SchedModel"); |
| 613 | ProcModelMapTy::const_iterator I = ProcModelMap.find(ModelDef); |
| 614 | if (I == ProcModelMap.end()) { |
| 615 | throw TGError((*II)->getLoc(), "Undefined SchedMachineModel " |
| 616 | + ModelDef->getName()); |
| 617 | } |
| 618 | ProcModels[I->second].ItinRWDefs.push_back(*II); |
| 619 | } |
| 620 | } |
| 621 | |
| 622 | #ifndef NDEBUG |
| 623 | void CodeGenProcModel::dump() const { |
| 624 | dbgs() << Index << ": " << ModelName << " " |
| 625 | << (ModelDef ? ModelDef->getName() : "inferred") << " " |
| 626 | << (ItinsDef ? ItinsDef->getName() : "no itinerary") << '\n'; |
| 627 | } |
| 628 | |
| 629 | void CodeGenSchedRW::dump() const { |
| 630 | dbgs() << Name << (IsVariadic ? " (V) " : " "); |
| 631 | if (IsSequence) { |
| 632 | dbgs() << "("; |
| 633 | dumpIdxVec(Sequence); |
| 634 | dbgs() << ")"; |
| 635 | } |
| 636 | } |
| 637 | |
| 638 | void CodeGenSchedClass::dump(const CodeGenSchedModels* SchedModels) const { |
| 639 | dbgs() << "SCHEDCLASS " << Name << '\n' |
| 640 | << " Writes: "; |
| 641 | for (unsigned i = 0, N = Writes.size(); i < N; ++i) { |
| 642 | SchedModels->getSchedWrite(Writes[i]).dump(); |
| 643 | if (i < N-1) { |
| 644 | dbgs() << '\n'; |
| 645 | dbgs().indent(10); |
| 646 | } |
| 647 | } |
| 648 | dbgs() << "\n Reads: "; |
| 649 | for (unsigned i = 0, N = Reads.size(); i < N; ++i) { |
| 650 | SchedModels->getSchedRead(Reads[i]).dump(); |
| 651 | if (i < N-1) { |
| 652 | dbgs() << '\n'; |
| 653 | dbgs().indent(10); |
| 654 | } |
| 655 | } |
| 656 | dbgs() << "\n ProcIdx: "; dumpIdxVec(ProcIndices); dbgs() << '\n'; |
| 657 | } |
| 658 | #endif // NDEBUG |