1 //===- SubtargetEmitter.cpp - Generate subtarget enumerations -------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This tablegen backend emits subtarget enumerations.
12 //===----------------------------------------------------------------------===//
14 #include "SubtargetEmitter.h"
15 #include "CodeGenTarget.h"
16 #include "llvm/TableGen/Record.h"
17 #include "llvm/ADT/StringExtras.h"
18 #include "llvm/Support/Debug.h"
23 // Enumeration - Emit the specified class as an enumeration.
25 void SubtargetEmitter::Enumeration(raw_ostream &OS,
26 const char *ClassName,
28 // Get all records of class and sort
29 std::vector<Record*> DefList = Records.getAllDerivedDefinitions(ClassName);
30 std::sort(DefList.begin(), DefList.end(), LessRecord());
32 unsigned N = DefList.size();
36 errs() << "Too many (> 64) subtarget features!\n";
40 OS << "namespace " << Target << " {\n";
42 // For bit flag enumerations with more than 32 items, emit constants.
43 // Emit an enum for everything else.
44 if (isBits && N > 32) {
46 for (unsigned i = 0; i < N; i++) {
48 Record *Def = DefList[i];
50 // Get and emit name and expression (1 << i)
51 OS << " const uint64_t " << Def->getName() << " = 1ULL << " << i << ";\n";
58 for (unsigned i = 0; i < N;) {
60 Record *Def = DefList[i];
63 OS << " " << Def->getName();
65 // If bit flags then emit expression (1 << i)
66 if (isBits) OS << " = " << " 1ULL << " << i;
68 // Depending on 'if more in the list' emit comma
69 if (++i < N) OS << ",";
82 // FeatureKeyValues - Emit data of all the subtarget features. Used by the
85 unsigned SubtargetEmitter::FeatureKeyValues(raw_ostream &OS) {
86 // Gather and sort all the features
87 std::vector<Record*> FeatureList =
88 Records.getAllDerivedDefinitions("SubtargetFeature");
90 if (FeatureList.empty())
93 std::sort(FeatureList.begin(), FeatureList.end(), LessRecordFieldName());
95 // Begin feature table
96 OS << "// Sorted (by key) array of values for CPU features.\n"
97 << "extern const llvm::SubtargetFeatureKV " << Target
98 << "FeatureKV[] = {\n";
101 unsigned NumFeatures = 0;
102 for (unsigned i = 0, N = FeatureList.size(); i < N; ++i) {
104 Record *Feature = FeatureList[i];
106 const std::string &Name = Feature->getName();
107 const std::string &CommandLineName = Feature->getValueAsString("Name");
108 const std::string &Desc = Feature->getValueAsString("Desc");
110 if (CommandLineName.empty()) continue;
112 // Emit as { "feature", "description", featureEnum, i1 | i2 | ... | in }
114 << "\"" << CommandLineName << "\", "
115 << "\"" << Desc << "\", "
116 << Target << "::" << Name << ", ";
118 const std::vector<Record*> &ImpliesList =
119 Feature->getValueAsListOfDefs("Implies");
121 if (ImpliesList.empty()) {
124 for (unsigned j = 0, M = ImpliesList.size(); j < M;) {
125 OS << Target << "::" << ImpliesList[j]->getName();
126 if (++j < M) OS << " | ";
133 // Depending on 'if more in the list' emit comma
134 if ((i + 1) < N) OS << ",";
146 // CPUKeyValues - Emit data of all the subtarget processors. Used by command
149 unsigned SubtargetEmitter::CPUKeyValues(raw_ostream &OS) {
150 // Gather and sort processor information
151 std::vector<Record*> ProcessorList =
152 Records.getAllDerivedDefinitions("Processor");
153 std::sort(ProcessorList.begin(), ProcessorList.end(), LessRecordFieldName());
155 // Begin processor table
156 OS << "// Sorted (by key) array of values for CPU subtype.\n"
157 << "extern const llvm::SubtargetFeatureKV " << Target
158 << "SubTypeKV[] = {\n";
160 // For each processor
161 for (unsigned i = 0, N = ProcessorList.size(); i < N;) {
163 Record *Processor = ProcessorList[i];
165 const std::string &Name = Processor->getValueAsString("Name");
166 const std::vector<Record*> &FeatureList =
167 Processor->getValueAsListOfDefs("Features");
169 // Emit as { "cpu", "description", f1 | f2 | ... fn },
171 << "\"" << Name << "\", "
172 << "\"Select the " << Name << " processor\", ";
174 if (FeatureList.empty()) {
177 for (unsigned j = 0, M = FeatureList.size(); j < M;) {
178 OS << Target << "::" << FeatureList[j]->getName();
179 if (++j < M) OS << " | ";
183 // The "0" is for the "implies" section of this data structure.
186 // Depending on 'if more in the list' emit comma
187 if (++i < N) OS << ",";
192 // End processor table
195 return ProcessorList.size();
199 // CollectAllItinClasses - Gathers and enumerates all the itinerary classes.
200 // Returns itinerary class count.
202 unsigned SubtargetEmitter::
203 CollectAllItinClasses(raw_ostream &OS,
204 std::map<std::string, unsigned> &ItinClassesMap,
205 std::vector<Record*> &ItinClassList) {
206 // For each itinerary class
207 unsigned N = ItinClassList.size();
208 for (unsigned i = 0; i < N; i++) {
209 // Next itinerary class
210 const Record *ItinClass = ItinClassList[i];
211 // Get name of itinerary class
212 // Assign itinerary class a unique number
213 ItinClassesMap[ItinClass->getName()] = i;
216 // Return itinerary class count
221 // FormItineraryStageString - Compose a string containing the stage
222 // data initialization for the specified itinerary. N is the number
225 void SubtargetEmitter::FormItineraryStageString(const std::string &Name,
227 std::string &ItinString,
230 const std::vector<Record*> &StageList =
231 ItinData->getValueAsListOfDefs("Stages");
234 unsigned N = NStages = StageList.size();
235 for (unsigned i = 0; i < N;) {
237 const Record *Stage = StageList[i];
239 // Form string as ,{ cycles, u1 | u2 | ... | un, timeinc, kind }
240 int Cycles = Stage->getValueAsInt("Cycles");
241 ItinString += " { " + itostr(Cycles) + ", ";
244 const std::vector<Record*> &UnitList = Stage->getValueAsListOfDefs("Units");
247 for (unsigned j = 0, M = UnitList.size(); j < M;) {
248 // Add name and bitwise or
249 ItinString += Name + "FU::" + UnitList[j]->getName();
250 if (++j < M) ItinString += " | ";
253 int TimeInc = Stage->getValueAsInt("TimeInc");
254 ItinString += ", " + itostr(TimeInc);
256 int Kind = Stage->getValueAsInt("Kind");
257 ItinString += ", (llvm::InstrStage::ReservationKinds)" + itostr(Kind);
261 if (++i < N) ItinString += ", ";
266 // FormItineraryOperandCycleString - Compose a string containing the
267 // operand cycle initialization for the specified itinerary. N is the
268 // number of operands that has cycles specified.
270 void SubtargetEmitter::FormItineraryOperandCycleString(Record *ItinData,
271 std::string &ItinString, unsigned &NOperandCycles) {
272 // Get operand cycle list
273 const std::vector<int64_t> &OperandCycleList =
274 ItinData->getValueAsListOfInts("OperandCycles");
276 // For each operand cycle
277 unsigned N = NOperandCycles = OperandCycleList.size();
278 for (unsigned i = 0; i < N;) {
279 // Next operand cycle
280 const int OCycle = OperandCycleList[i];
282 ItinString += " " + itostr(OCycle);
283 if (++i < N) ItinString += ", ";
287 void SubtargetEmitter::FormItineraryBypassString(const std::string &Name,
289 std::string &ItinString,
290 unsigned NOperandCycles) {
291 const std::vector<Record*> &BypassList =
292 ItinData->getValueAsListOfDefs("Bypasses");
293 unsigned N = BypassList.size();
296 ItinString += Name + "Bypass::" + BypassList[i]->getName();
297 if (++i < NOperandCycles) ItinString += ", ";
299 for (; i < NOperandCycles;) {
301 if (++i < NOperandCycles) ItinString += ", ";
306 // EmitStageAndOperandCycleData - Generate unique itinerary stages and
307 // operand cycle tables. Record itineraries for processors.
309 void SubtargetEmitter::EmitStageAndOperandCycleData(raw_ostream &OS,
310 unsigned NItinClasses,
311 std::map<std::string, unsigned> &ItinClassesMap,
312 std::vector<Record*> &ItinClassList,
313 std::vector<std::vector<InstrItinerary> > &ProcList) {
314 // Gather processor iteraries
315 std::vector<Record*> ProcItinList =
316 Records.getAllDerivedDefinitions("ProcessorItineraries");
318 // If just no itinerary then don't bother
319 if (ProcItinList.size() < 2) return;
321 // Emit functional units for all the itineraries.
322 for (unsigned i = 0, N = ProcItinList.size(); i < N; ++i) {
324 Record *Proc = ProcItinList[i];
326 std::vector<Record*> FUs = Proc->getValueAsListOfDefs("FU");
330 const std::string &Name = Proc->getName();
331 OS << "\n// Functional units for itineraries \"" << Name << "\"\n"
332 << "namespace " << Name << "FU {\n";
334 for (unsigned j = 0, FUN = FUs.size(); j < FUN; ++j)
335 OS << " const unsigned " << FUs[j]->getName()
336 << " = 1 << " << j << ";\n";
340 std::vector<Record*> BPs = Proc->getValueAsListOfDefs("BP");
342 OS << "\n// Pipeline forwarding pathes for itineraries \"" << Name
343 << "\"\n" << "namespace " << Name << "Bypass {\n";
345 OS << " const unsigned NoBypass = 0;\n";
346 for (unsigned j = 0, BPN = BPs.size(); j < BPN; ++j)
347 OS << " const unsigned " << BPs[j]->getName()
348 << " = 1 << " << j << ";\n";
354 // Begin stages table
355 std::string StageTable = "\nextern const llvm::InstrStage " + Target +
357 StageTable += " { 0, 0, 0, llvm::InstrStage::Required }, // No itinerary\n";
359 // Begin operand cycle table
360 std::string OperandCycleTable = "extern const unsigned " + Target +
361 "OperandCycles[] = {\n";
362 OperandCycleTable += " 0, // No itinerary\n";
364 // Begin pipeline bypass table
365 std::string BypassTable = "extern const unsigned " + Target +
366 "ForwardingPathes[] = {\n";
367 BypassTable += " 0, // No itinerary\n";
369 unsigned StageCount = 1, OperandCycleCount = 1;
370 std::map<std::string, unsigned> ItinStageMap, ItinOperandMap;
371 for (unsigned i = 0, N = ProcItinList.size(); i < N; i++) {
373 Record *Proc = ProcItinList[i];
375 // Get processor itinerary name
376 const std::string &Name = Proc->getName();
379 if (Name == "NoItineraries") continue;
381 // Create and expand processor itinerary to cover all itinerary classes
382 std::vector<InstrItinerary> ItinList;
383 ItinList.resize(NItinClasses);
385 // Get itinerary data list
386 std::vector<Record*> ItinDataList = Proc->getValueAsListOfDefs("IID");
388 // For each itinerary data
389 for (unsigned j = 0, M = ItinDataList.size(); j < M; j++) {
390 // Next itinerary data
391 Record *ItinData = ItinDataList[j];
393 // Get string and stage count
394 std::string ItinStageString;
396 FormItineraryStageString(Name, ItinData, ItinStageString, NStages);
398 // Get string and operand cycle count
399 std::string ItinOperandCycleString;
400 unsigned NOperandCycles;
401 FormItineraryOperandCycleString(ItinData, ItinOperandCycleString,
404 std::string ItinBypassString;
405 FormItineraryBypassString(Name, ItinData, ItinBypassString,
408 // Check to see if stage already exists and create if it doesn't
409 unsigned FindStage = 0;
411 FindStage = ItinStageMap[ItinStageString];
412 if (FindStage == 0) {
413 // Emit as { cycles, u1 | u2 | ... | un, timeinc }, // indices
414 StageTable += ItinStageString + ", // " + itostr(StageCount);
416 StageTable += "-" + itostr(StageCount + NStages - 1);
418 // Record Itin class number.
419 ItinStageMap[ItinStageString] = FindStage = StageCount;
420 StageCount += NStages;
424 // Check to see if operand cycle already exists and create if it doesn't
425 unsigned FindOperandCycle = 0;
426 if (NOperandCycles > 0) {
427 std::string ItinOperandString = ItinOperandCycleString+ItinBypassString;
428 FindOperandCycle = ItinOperandMap[ItinOperandString];
429 if (FindOperandCycle == 0) {
430 // Emit as cycle, // index
431 OperandCycleTable += ItinOperandCycleString + ", // ";
432 std::string OperandIdxComment = itostr(OperandCycleCount);
433 if (NOperandCycles > 1)
434 OperandIdxComment += "-"
435 + itostr(OperandCycleCount + NOperandCycles - 1);
436 OperandCycleTable += OperandIdxComment + "\n";
437 // Record Itin class number.
438 ItinOperandMap[ItinOperandCycleString] =
439 FindOperandCycle = OperandCycleCount;
440 // Emit as bypass, // index
441 BypassTable += ItinBypassString + ", // " + OperandIdxComment + "\n";
442 OperandCycleCount += NOperandCycles;
446 // Locate where to inject into processor itinerary table
447 const std::string &Name = ItinData->getValueAsDef("TheClass")->getName();
448 unsigned Find = ItinClassesMap[Name];
450 // Set up itinerary as location and location + stage count
451 unsigned NumUOps = ItinClassList[Find]->getValueAsInt("NumMicroOps");
452 InstrItinerary Intinerary = { NumUOps, FindStage, FindStage + NStages,
454 FindOperandCycle + NOperandCycles};
456 // Inject - empty slots will be 0, 0
457 ItinList[Find] = Intinerary;
460 // Add process itinerary to list
461 ProcList.push_back(ItinList);
465 StageTable += " { 0, 0, 0, llvm::InstrStage::Required } // End itinerary\n";
466 StageTable += "};\n";
468 // Closing operand cycles
469 OperandCycleTable += " 0 // End itinerary\n";
470 OperandCycleTable += "};\n";
472 BypassTable += " 0 // End itinerary\n";
473 BypassTable += "};\n";
477 OS << OperandCycleTable;
482 // EmitProcessorData - Generate data for processor itineraries.
484 void SubtargetEmitter::
485 EmitProcessorData(raw_ostream &OS,
486 std::vector<Record*> &ItinClassList,
487 std::vector<std::vector<InstrItinerary> > &ProcList) {
488 // Get an iterator for processor itinerary stages
489 std::vector<std::vector<InstrItinerary> >::iterator
490 ProcListIter = ProcList.begin();
492 // For each processor itinerary
493 std::vector<Record*> Itins =
494 Records.getAllDerivedDefinitions("ProcessorItineraries");
495 for (unsigned i = 0, N = Itins.size(); i < N; i++) {
497 Record *Itin = Itins[i];
499 // Get processor itinerary name
500 const std::string &Name = Itin->getName();
503 if (Name == "NoItineraries") continue;
505 // Begin processor itinerary table
507 OS << "static const llvm::InstrItinerary " << Name << "[] = {\n";
509 // For each itinerary class
510 std::vector<InstrItinerary> &ItinList = *ProcListIter++;
511 assert(ItinList.size() == ItinClassList.size() && "bad itinerary");
512 for (unsigned j = 0, M = ItinList.size(); j < M; ++j) {
513 InstrItinerary &Intinerary = ItinList[j];
515 // Emit in the form of
516 // { firstStage, lastStage, firstCycle, lastCycle } // index
517 if (Intinerary.FirstStage == 0) {
518 OS << " { 1, 0, 0, 0, 0 }";
521 Intinerary.NumMicroOps << ", " <<
522 Intinerary.FirstStage << ", " <<
523 Intinerary.LastStage << ", " <<
524 Intinerary.FirstOperandCycle << ", " <<
525 Intinerary.LastOperandCycle << " }";
528 OS << ", // " << j << " " << ItinClassList[j]->getName() << "\n";
531 // End processor itinerary table
532 OS << " { 1, ~0U, ~0U, ~0U, ~0U } // end marker\n";
538 // EmitProcessorLookup - generate cpu name to itinerary lookup table.
540 void SubtargetEmitter::EmitProcessorLookup(raw_ostream &OS) {
541 // Gather and sort processor information
542 std::vector<Record*> ProcessorList =
543 Records.getAllDerivedDefinitions("Processor");
544 std::sort(ProcessorList.begin(), ProcessorList.end(), LessRecordFieldName());
546 // Begin processor table
548 OS << "// Sorted (by key) array of itineraries for CPU subtype.\n"
549 << "extern const llvm::SubtargetInfoKV "
550 << Target << "ProcItinKV[] = {\n";
552 // For each processor
553 for (unsigned i = 0, N = ProcessorList.size(); i < N;) {
555 Record *Processor = ProcessorList[i];
557 const std::string &Name = Processor->getValueAsString("Name");
558 const std::string &ProcItin =
559 Processor->getValueAsDef("ProcItin")->getName();
561 // Emit as { "cpu", procinit },
563 << "\"" << Name << "\", "
564 << "(void *)&" << ProcItin;
568 // Depending on ''if more in the list'' emit comma
569 if (++i < N) OS << ",";
574 // End processor table
579 // EmitData - Emits all stages and itineries, folding common patterns.
581 void SubtargetEmitter::EmitData(raw_ostream &OS) {
582 std::map<std::string, unsigned> ItinClassesMap;
583 // Gather and sort all itinerary classes
584 std::vector<Record*> ItinClassList =
585 Records.getAllDerivedDefinitions("InstrItinClass");
586 std::sort(ItinClassList.begin(), ItinClassList.end(), LessRecord());
588 // Enumerate all the itinerary classes
589 unsigned NItinClasses = CollectAllItinClasses(OS, ItinClassesMap,
591 // Make sure the rest is worth the effort
592 HasItineraries = NItinClasses != 1; // Ignore NoItinerary.
594 if (HasItineraries) {
595 std::vector<std::vector<InstrItinerary> > ProcList;
596 // Emit the stage data
597 EmitStageAndOperandCycleData(OS, NItinClasses, ItinClassesMap,
598 ItinClassList, ProcList);
599 // Emit the processor itinerary data
600 EmitProcessorData(OS, ItinClassList, ProcList);
601 // Emit the processor lookup data
602 EmitProcessorLookup(OS);
607 // ParseFeaturesFunction - Produces a subtarget specific function for parsing
608 // the subtarget features string.
610 void SubtargetEmitter::ParseFeaturesFunction(raw_ostream &OS,
611 unsigned NumFeatures,
613 std::vector<Record*> Features =
614 Records.getAllDerivedDefinitions("SubtargetFeature");
615 std::sort(Features.begin(), Features.end(), LessRecord());
617 OS << "// ParseSubtargetFeatures - Parses features string setting specified\n"
618 << "// subtarget options.\n"
621 OS << "Subtarget::ParseSubtargetFeatures(StringRef CPU, StringRef FS) {\n"
622 << " DEBUG(dbgs() << \"\\nFeatures:\" << FS);\n"
623 << " DEBUG(dbgs() << \"\\nCPU:\" << CPU);\n";
625 if (Features.empty()) {
630 OS << " uint64_t Bits = ReInitMCSubtargetInfo(CPU, FS);\n";
632 for (unsigned i = 0; i < Features.size(); i++) {
634 Record *R = Features[i];
635 const std::string &Instance = R->getName();
636 const std::string &Value = R->getValueAsString("Value");
637 const std::string &Attribute = R->getValueAsString("Attribute");
639 if (Value=="true" || Value=="false")
640 OS << " if ((Bits & " << Target << "::"
641 << Instance << ") != 0) "
642 << Attribute << " = " << Value << ";\n";
644 OS << " if ((Bits & " << Target << "::"
645 << Instance << ") != 0 && "
646 << Attribute << " < " << Value << ") "
647 << Attribute << " = " << Value << ";\n";
654 // SubtargetEmitter::run - Main subtarget enumeration emitter.
656 void SubtargetEmitter::run(raw_ostream &OS) {
657 Target = CodeGenTarget(Records).getName();
659 EmitSourceFileHeader("Subtarget Enumeration Source Fragment", OS);
661 OS << "\n#ifdef GET_SUBTARGETINFO_ENUM\n";
662 OS << "#undef GET_SUBTARGETINFO_ENUM\n";
664 OS << "namespace llvm {\n";
665 Enumeration(OS, "SubtargetFeature", true);
666 OS << "} // End llvm namespace \n";
667 OS << "#endif // GET_SUBTARGETINFO_ENUM\n\n";
669 OS << "\n#ifdef GET_SUBTARGETINFO_MC_DESC\n";
670 OS << "#undef GET_SUBTARGETINFO_MC_DESC\n";
672 OS << "namespace llvm {\n";
674 OS << "namespace {\n";
676 unsigned NumFeatures = FeatureKeyValues(OS);
678 unsigned NumProcs = CPUKeyValues(OS);
686 // MCInstrInfo initialization routine.
687 OS << "static inline void Init" << Target
688 << "MCSubtargetInfo(MCSubtargetInfo *II, "
689 << "StringRef TT, StringRef CPU, StringRef FS) {\n";
690 OS << " II->InitMCSubtargetInfo(TT, CPU, FS, ";
692 OS << Target << "FeatureKV, ";
696 OS << Target << "SubTypeKV, ";
699 if (HasItineraries) {
700 OS << Target << "ProcItinKV, "
701 << Target << "Stages, "
702 << Target << "OperandCycles, "
703 << Target << "ForwardingPathes, ";
705 OS << "0, 0, 0, 0, ";
706 OS << NumFeatures << ", " << NumProcs << ");\n}\n\n";
708 OS << "} // End llvm namespace \n";
710 OS << "#endif // GET_SUBTARGETINFO_MC_DESC\n\n";
712 OS << "\n#ifdef GET_SUBTARGETINFO_TARGET_DESC\n";
713 OS << "#undef GET_SUBTARGETINFO_TARGET_DESC\n";
715 OS << "#include \"llvm/Support/Debug.h\"\n";
716 OS << "#include \"llvm/Support/raw_ostream.h\"\n";
717 ParseFeaturesFunction(OS, NumFeatures, NumProcs);
719 OS << "#endif // GET_SUBTARGETINFO_TARGET_DESC\n\n";
721 // Create a TargetSubtargetInfo subclass to hide the MC layer initialization.
722 OS << "\n#ifdef GET_SUBTARGETINFO_HEADER\n";
723 OS << "#undef GET_SUBTARGETINFO_HEADER\n";
725 std::string ClassName = Target + "GenSubtargetInfo";
726 OS << "namespace llvm {\n";
727 OS << "class DFAPacketizer;\n";
728 OS << "struct " << ClassName << " : public TargetSubtargetInfo {\n"
729 << " explicit " << ClassName << "(StringRef TT, StringRef CPU, "
730 << "StringRef FS);\n"
732 << " DFAPacketizer *createDFAPacketizer(const InstrItineraryData *IID)"
735 OS << "} // End llvm namespace \n";
737 OS << "#endif // GET_SUBTARGETINFO_HEADER\n\n";
739 OS << "\n#ifdef GET_SUBTARGETINFO_CTOR\n";
740 OS << "#undef GET_SUBTARGETINFO_CTOR\n";
742 OS << "namespace llvm {\n";
743 OS << "extern const llvm::SubtargetFeatureKV " << Target << "FeatureKV[];\n";
744 OS << "extern const llvm::SubtargetFeatureKV " << Target << "SubTypeKV[];\n";
745 if (HasItineraries) {
746 OS << "extern const llvm::SubtargetInfoKV " << Target << "ProcItinKV[];\n";
747 OS << "extern const llvm::InstrStage " << Target << "Stages[];\n";
748 OS << "extern const unsigned " << Target << "OperandCycles[];\n";
749 OS << "extern const unsigned " << Target << "ForwardingPathes[];\n";
752 OS << ClassName << "::" << ClassName << "(StringRef TT, StringRef CPU, "
754 << " : TargetSubtargetInfo() {\n"
755 << " InitMCSubtargetInfo(TT, CPU, FS, ";
757 OS << Target << "FeatureKV, ";
761 OS << Target << "SubTypeKV, ";
764 if (HasItineraries) {
765 OS << Target << "ProcItinKV, "
766 << Target << "Stages, "
767 << Target << "OperandCycles, "
768 << Target << "ForwardingPathes, ";
770 OS << "0, 0, 0, 0, ";
771 OS << NumFeatures << ", " << NumProcs << ");\n}\n\n";
772 OS << "} // End llvm namespace \n";
774 OS << "#endif // GET_SUBTARGETINFO_CTOR\n\n";