Ensure sys::getProcessTriple always uses a normalized triple. Patch by
[oota-llvm.git] / lib / Support / Host.cpp
1 //===-- Host.cpp - Implement OS Host Concept --------------------*- C++ -*-===//
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 header file implements the operating system Host concept.
11 //
12 //===----------------------------------------------------------------------===//
13
14 #include "llvm/Support/Host.h"
15 #include "llvm/ADT/SmallVector.h"
16 #include "llvm/ADT/StringRef.h"
17 #include "llvm/ADT/StringSwitch.h"
18 #include "llvm/ADT/Triple.h"
19 #include "llvm/Config/config.h"
20 #include "llvm/Support/DataStream.h"
21 #include "llvm/Support/Debug.h"
22 #include "llvm/Support/raw_ostream.h"
23 #include <string.h>
24
25 // Include the platform-specific parts of this class.
26 #ifdef LLVM_ON_UNIX
27 #include "Unix/Host.inc"
28 #endif
29 #ifdef LLVM_ON_WIN32
30 #include "Windows/Host.inc"
31 #endif
32 #ifdef _MSC_VER
33 #include <intrin.h>
34 #endif
35 #if defined(__APPLE__) && (defined(__ppc__) || defined(__powerpc__))
36 #include <mach/mach.h>
37 #include <mach/mach_host.h>
38 #include <mach/host_info.h>
39 #include <mach/machine.h>
40 #endif
41
42 //===----------------------------------------------------------------------===//
43 //
44 //  Implementations of the CPU detection routines
45 //
46 //===----------------------------------------------------------------------===//
47
48 using namespace llvm;
49
50 #if defined(i386) || defined(__i386__) || defined(__x86__) || defined(_M_IX86)\
51  || defined(__x86_64__) || defined(_M_AMD64) || defined (_M_X64)
52
53 /// GetX86CpuIDAndInfo - Execute the specified cpuid and return the 4 values in the
54 /// specified arguments.  If we can't run cpuid on the host, return true.
55 static bool GetX86CpuIDAndInfo(unsigned value, unsigned *rEAX,
56                             unsigned *rEBX, unsigned *rECX, unsigned *rEDX) {
57 #if defined(__x86_64__) || defined(_M_AMD64) || defined (_M_X64)
58   #if defined(__GNUC__)
59     // gcc doesn't know cpuid would clobber ebx/rbx. Preseve it manually.
60     asm ("movq\t%%rbx, %%rsi\n\t"
61          "cpuid\n\t"
62          "xchgq\t%%rbx, %%rsi\n\t"
63          : "=a" (*rEAX),
64            "=S" (*rEBX),
65            "=c" (*rECX),
66            "=d" (*rEDX)
67          :  "a" (value));
68     return false;
69   #elif defined(_MSC_VER)
70     int registers[4];
71     __cpuid(registers, value);
72     *rEAX = registers[0];
73     *rEBX = registers[1];
74     *rECX = registers[2];
75     *rEDX = registers[3];
76     return false;
77   #else
78     return true;
79   #endif
80 #elif defined(i386) || defined(__i386__) || defined(__x86__) || defined(_M_IX86)
81   #if defined(__GNUC__)
82     asm ("movl\t%%ebx, %%esi\n\t"
83          "cpuid\n\t"
84          "xchgl\t%%ebx, %%esi\n\t"
85          : "=a" (*rEAX),
86            "=S" (*rEBX),
87            "=c" (*rECX),
88            "=d" (*rEDX)
89          :  "a" (value));
90     return false;
91   #elif defined(_MSC_VER)
92     __asm {
93       mov   eax,value
94       cpuid
95       mov   esi,rEAX
96       mov   dword ptr [esi],eax
97       mov   esi,rEBX
98       mov   dword ptr [esi],ebx
99       mov   esi,rECX
100       mov   dword ptr [esi],ecx
101       mov   esi,rEDX
102       mov   dword ptr [esi],edx
103     }
104     return false;
105 // pedantic #else returns to appease -Wunreachable-code (so we don't generate
106 // postprocessed code that looks like "return true; return false;")
107   #else
108     return true;
109   #endif
110 #else
111   return true;
112 #endif
113 }
114
115 static bool OSHasAVXSupport() {
116 #if defined(__GNUC__)
117   // Check xgetbv; this uses a .byte sequence instead of the instruction
118   // directly because older assemblers do not include support for xgetbv and
119   // there is no easy way to conditionally compile based on the assembler used.
120   int rEAX, rEDX;
121   __asm__ (".byte 0x0f, 0x01, 0xd0" : "=a" (rEAX), "=d" (rEDX) : "c" (0));
122 #elif defined(_MSC_FULL_VER) && defined(_XCR_XFEATURE_ENABLED_MASK)
123   unsigned long long rEAX = _xgetbv(_XCR_XFEATURE_ENABLED_MASK);
124 #else
125   int rEAX = 0; // Ensures we return false
126 #endif
127   return (rEAX & 6) == 6;
128 }
129
130 static void DetectX86FamilyModel(unsigned EAX, unsigned &Family,
131                                  unsigned &Model) {
132   Family = (EAX >> 8) & 0xf; // Bits 8 - 11
133   Model  = (EAX >> 4) & 0xf; // Bits 4 - 7
134   if (Family == 6 || Family == 0xf) {
135     if (Family == 0xf)
136       // Examine extended family ID if family ID is F.
137       Family += (EAX >> 20) & 0xff;    // Bits 20 - 27
138     // Examine extended model ID if family ID is 6 or F.
139     Model += ((EAX >> 16) & 0xf) << 4; // Bits 16 - 19
140   }
141 }
142
143 std::string sys::getHostCPUName() {
144   unsigned EAX = 0, EBX = 0, ECX = 0, EDX = 0;
145   if (GetX86CpuIDAndInfo(0x1, &EAX, &EBX, &ECX, &EDX))
146     return "generic";
147   unsigned Family = 0;
148   unsigned Model  = 0;
149   DetectX86FamilyModel(EAX, Family, Model);
150
151   bool HasSSE3 = (ECX & 0x1);
152   // If CPUID indicates support for XSAVE, XRESTORE and AVX, and XGETBV 
153   // indicates that the AVX registers will be saved and restored on context
154   // switch, then we have full AVX support.
155   const unsigned AVXBits = (1 << 27) | (1 << 28);
156   bool HasAVX = ((ECX & AVXBits) == AVXBits) && OSHasAVXSupport();
157   GetX86CpuIDAndInfo(0x80000001, &EAX, &EBX, &ECX, &EDX);
158   bool Em64T = (EDX >> 29) & 0x1;
159
160   union {
161     unsigned u[3];
162     char     c[12];
163   } text;
164
165   GetX86CpuIDAndInfo(0, &EAX, text.u+0, text.u+2, text.u+1);
166   if (memcmp(text.c, "GenuineIntel", 12) == 0) {
167     switch (Family) {
168     case 3:
169       return "i386";
170     case 4:
171       switch (Model) {
172       case 0: // Intel486 DX processors
173       case 1: // Intel486 DX processors
174       case 2: // Intel486 SX processors
175       case 3: // Intel487 processors, IntelDX2 OverDrive processors,
176               // IntelDX2 processors
177       case 4: // Intel486 SL processor
178       case 5: // IntelSX2 processors
179       case 7: // Write-Back Enhanced IntelDX2 processors
180       case 8: // IntelDX4 OverDrive processors, IntelDX4 processors
181       default: return "i486";
182       }
183     case 5:
184       switch (Model) {
185       case  1: // Pentium OverDrive processor for Pentium processor (60, 66),
186                // Pentium processors (60, 66)
187       case  2: // Pentium OverDrive processor for Pentium processor (75, 90,
188                // 100, 120, 133), Pentium processors (75, 90, 100, 120, 133,
189                // 150, 166, 200)
190       case  3: // Pentium OverDrive processors for Intel486 processor-based
191                // systems
192         return "pentium";
193
194       case  4: // Pentium OverDrive processor with MMX technology for Pentium
195                // processor (75, 90, 100, 120, 133), Pentium processor with
196                // MMX technology (166, 200)
197         return "pentium-mmx";
198
199       default: return "pentium";
200       }
201     case 6:
202       switch (Model) {
203       case  1: // Pentium Pro processor
204         return "pentiumpro";
205
206       case  3: // Intel Pentium II OverDrive processor, Pentium II processor,
207                // model 03
208       case  5: // Pentium II processor, model 05, Pentium II Xeon processor,
209                // model 05, and Intel Celeron processor, model 05
210       case  6: // Celeron processor, model 06
211         return "pentium2";
212
213       case  7: // Pentium III processor, model 07, and Pentium III Xeon
214                // processor, model 07
215       case  8: // Pentium III processor, model 08, Pentium III Xeon processor,
216                // model 08, and Celeron processor, model 08
217       case 10: // Pentium III Xeon processor, model 0Ah
218       case 11: // Pentium III processor, model 0Bh
219         return "pentium3";
220
221       case  9: // Intel Pentium M processor, Intel Celeron M processor model 09.
222       case 13: // Intel Pentium M processor, Intel Celeron M processor, model
223                // 0Dh. All processors are manufactured using the 90 nm process.
224         return "pentium-m";
225
226       case 14: // Intel Core Duo processor, Intel Core Solo processor, model
227                // 0Eh. All processors are manufactured using the 65 nm process.
228         return "yonah";
229
230       case 15: // Intel Core 2 Duo processor, Intel Core 2 Duo mobile
231                // processor, Intel Core 2 Quad processor, Intel Core 2 Quad
232                // mobile processor, Intel Core 2 Extreme processor, Intel
233                // Pentium Dual-Core processor, Intel Xeon processor, model
234                // 0Fh. All processors are manufactured using the 65 nm process.
235       case 22: // Intel Celeron processor model 16h. All processors are
236                // manufactured using the 65 nm process
237         return "core2";
238
239       case 21: // Intel EP80579 Integrated Processor and Intel EP80579
240                // Integrated Processor with Intel QuickAssist Technology
241         return "i686"; // FIXME: ???
242
243       case 23: // Intel Core 2 Extreme processor, Intel Xeon processor, model
244                // 17h. All processors are manufactured using the 45 nm process.
245                //
246                // 45nm: Penryn , Wolfdale, Yorkfield (XE)
247         return "penryn";
248
249       case 26: // Intel Core i7 processor and Intel Xeon processor. All
250                // processors are manufactured using the 45 nm process.
251       case 29: // Intel Xeon processor MP. All processors are manufactured using
252                // the 45 nm process.
253       case 30: // Intel(R) Core(TM) i7 CPU         870  @ 2.93GHz.
254                // As found in a Summer 2010 model iMac.
255       case 37: // Intel Core i7, laptop version.
256       case 44: // Intel Core i7 processor and Intel Xeon processor. All
257                // processors are manufactured using the 32 nm process.
258       case 46: // Nehalem EX
259       case 47: // Westmere EX
260         return "corei7";
261
262       // SandyBridge:
263       case 42: // Intel Core i7 processor. All processors are manufactured
264                // using the 32 nm process.
265       case 45:
266         // Not all Sandy Bridge processors support AVX (such as the Pentium
267         // versions instead of the i7 versions).
268         return HasAVX ? "corei7-avx" : "corei7";
269
270       // Ivy Bridge:
271       case 58:
272         // Not all Ivy Bridge processors support AVX (such as the Pentium
273         // versions instead of the i7 versions).
274         return HasAVX ? "core-avx-i" : "corei7";
275
276       case 28: // Most 45 nm Intel Atom processors
277       case 38: // 45 nm Atom Lincroft
278       case 39: // 32 nm Atom Medfield
279       case 53: // 32 nm Atom Midview
280       case 54: // 32 nm Atom Midview
281         return "atom";
282
283       default: return (Em64T) ? "x86-64" : "i686";
284       }
285     case 15: {
286       switch (Model) {
287       case  0: // Pentium 4 processor, Intel Xeon processor. All processors are
288                // model 00h and manufactured using the 0.18 micron process.
289       case  1: // Pentium 4 processor, Intel Xeon processor, Intel Xeon
290                // processor MP, and Intel Celeron processor. All processors are
291                // model 01h and manufactured using the 0.18 micron process.
292       case  2: // Pentium 4 processor, Mobile Intel Pentium 4 processor - M,
293                // Intel Xeon processor, Intel Xeon processor MP, Intel Celeron
294                // processor, and Mobile Intel Celeron processor. All processors
295                // are model 02h and manufactured using the 0.13 micron process.
296         return (Em64T) ? "x86-64" : "pentium4";
297
298       case  3: // Pentium 4 processor, Intel Xeon processor, Intel Celeron D
299                // processor. All processors are model 03h and manufactured using
300                // the 90 nm process.
301       case  4: // Pentium 4 processor, Pentium 4 processor Extreme Edition,
302                // Pentium D processor, Intel Xeon processor, Intel Xeon
303                // processor MP, Intel Celeron D processor. All processors are
304                // model 04h and manufactured using the 90 nm process.
305       case  6: // Pentium 4 processor, Pentium D processor, Pentium processor
306                // Extreme Edition, Intel Xeon processor, Intel Xeon processor
307                // MP, Intel Celeron D processor. All processors are model 06h
308                // and manufactured using the 65 nm process.
309         return (Em64T) ? "nocona" : "prescott";
310
311       default:
312         return (Em64T) ? "x86-64" : "pentium4";
313       }
314     }
315
316     default:
317       return "generic";
318     }
319   } else if (memcmp(text.c, "AuthenticAMD", 12) == 0) {
320     // FIXME: this poorly matches the generated SubtargetFeatureKV table.  There
321     // appears to be no way to generate the wide variety of AMD-specific targets
322     // from the information returned from CPUID.
323     switch (Family) {
324       case 4:
325         return "i486";
326       case 5:
327         switch (Model) {
328         case 6:
329         case 7:  return "k6";
330         case 8:  return "k6-2";
331         case 9:
332         case 13: return "k6-3";
333         case 10: return "geode";
334         default: return "pentium";
335         }
336       case 6:
337         switch (Model) {
338         case 4:  return "athlon-tbird";
339         case 6:
340         case 7:
341         case 8:  return "athlon-mp";
342         case 10: return "athlon-xp";
343         default: return "athlon";
344         }
345       case 15:
346         if (HasSSE3)
347           return "k8-sse3";
348         switch (Model) {
349         case 1:  return "opteron";
350         case 5:  return "athlon-fx"; // also opteron
351         default: return "athlon64";
352         }
353       case 16:
354         return "amdfam10";
355       case 20:
356         return "btver1";
357       case 21:
358         if (!HasAVX) // If the OS doesn't support AVX provide a sane fallback.
359           return "btver1";
360         if (Model > 15 && Model <= 31)
361           return "bdver2";
362         return "bdver1";
363       case 22:
364         if (!HasAVX) // If the OS doesn't support AVX provide a sane fallback.
365           return "btver1";
366         return "btver2";
367     default:
368       return "generic";
369     }
370   }
371   return "generic";
372 }
373 #elif defined(__APPLE__) && (defined(__ppc__) || defined(__powerpc__))
374 std::string sys::getHostCPUName() {
375   host_basic_info_data_t hostInfo;
376   mach_msg_type_number_t infoCount;
377
378   infoCount = HOST_BASIC_INFO_COUNT;
379   host_info(mach_host_self(), HOST_BASIC_INFO, (host_info_t)&hostInfo, 
380             &infoCount);
381             
382   if (hostInfo.cpu_type != CPU_TYPE_POWERPC) return "generic";
383
384   switch(hostInfo.cpu_subtype) {
385   case CPU_SUBTYPE_POWERPC_601:   return "601";
386   case CPU_SUBTYPE_POWERPC_602:   return "602";
387   case CPU_SUBTYPE_POWERPC_603:   return "603";
388   case CPU_SUBTYPE_POWERPC_603e:  return "603e";
389   case CPU_SUBTYPE_POWERPC_603ev: return "603ev";
390   case CPU_SUBTYPE_POWERPC_604:   return "604";
391   case CPU_SUBTYPE_POWERPC_604e:  return "604e";
392   case CPU_SUBTYPE_POWERPC_620:   return "620";
393   case CPU_SUBTYPE_POWERPC_750:   return "750";
394   case CPU_SUBTYPE_POWERPC_7400:  return "7400";
395   case CPU_SUBTYPE_POWERPC_7450:  return "7450";
396   case CPU_SUBTYPE_POWERPC_970:   return "970";
397   default: ;
398   }
399   
400   return "generic";
401 }
402 #elif defined(__linux__) && (defined(__ppc__) || defined(__powerpc__))
403 std::string sys::getHostCPUName() {
404   // Access to the Processor Version Register (PVR) on PowerPC is privileged,
405   // and so we must use an operating-system interface to determine the current
406   // processor type. On Linux, this is exposed through the /proc/cpuinfo file.
407   const char *generic = "generic";
408
409   // Note: We cannot mmap /proc/cpuinfo here and then process the resulting
410   // memory buffer because the 'file' has 0 size (it can be read from only
411   // as a stream).
412
413   std::string Err;
414   DataStreamer *DS = getDataFileStreamer("/proc/cpuinfo", &Err);
415   if (!DS) {
416     DEBUG(dbgs() << "Unable to open /proc/cpuinfo: " << Err << "\n");
417     return generic;
418   }
419
420   // The cpu line is second (after the 'processor: 0' line), so if this
421   // buffer is too small then something has changed (or is wrong).
422   char buffer[1024];
423   size_t CPUInfoSize = DS->GetBytes((unsigned char*) buffer, sizeof(buffer));
424   delete DS;
425
426   const char *CPUInfoStart = buffer;
427   const char *CPUInfoEnd = buffer + CPUInfoSize;
428
429   const char *CIP = CPUInfoStart;
430
431   const char *CPUStart = 0;
432   size_t CPULen = 0;
433
434   // We need to find the first line which starts with cpu, spaces, and a colon.
435   // After the colon, there may be some additional spaces and then the cpu type.
436   while (CIP < CPUInfoEnd && CPUStart == 0) {
437     if (CIP < CPUInfoEnd && *CIP == '\n')
438       ++CIP;
439
440     if (CIP < CPUInfoEnd && *CIP == 'c') {
441       ++CIP;
442       if (CIP < CPUInfoEnd && *CIP == 'p') {
443         ++CIP;
444         if (CIP < CPUInfoEnd && *CIP == 'u') {
445           ++CIP;
446           while (CIP < CPUInfoEnd && (*CIP == ' ' || *CIP == '\t'))
447             ++CIP;
448   
449           if (CIP < CPUInfoEnd && *CIP == ':') {
450             ++CIP;
451             while (CIP < CPUInfoEnd && (*CIP == ' ' || *CIP == '\t'))
452               ++CIP;
453   
454             if (CIP < CPUInfoEnd) {
455               CPUStart = CIP;
456               while (CIP < CPUInfoEnd && (*CIP != ' ' && *CIP != '\t' &&
457                                           *CIP != ',' && *CIP != '\n'))
458                 ++CIP;
459               CPULen = CIP - CPUStart;
460             }
461           }
462         }
463       }
464     }
465
466     if (CPUStart == 0)
467       while (CIP < CPUInfoEnd && *CIP != '\n')
468         ++CIP;
469   }
470
471   if (CPUStart == 0)
472     return generic;
473
474   return StringSwitch<const char *>(StringRef(CPUStart, CPULen))
475     .Case("604e", "604e")
476     .Case("604", "604")
477     .Case("7400", "7400")
478     .Case("7410", "7400")
479     .Case("7447", "7400")
480     .Case("7455", "7450")
481     .Case("G4", "g4")
482     .Case("POWER4", "970")
483     .Case("PPC970FX", "970")
484     .Case("PPC970MP", "970")
485     .Case("G5", "g5")
486     .Case("POWER5", "g5")
487     .Case("A2", "a2")
488     .Case("POWER6", "pwr6")
489     .Case("POWER7", "pwr7")
490     .Default(generic);
491 }
492 #elif defined(__linux__) && defined(__arm__)
493 std::string sys::getHostCPUName() {
494   // The cpuid register on arm is not accessible from user space. On Linux,
495   // it is exposed through the /proc/cpuinfo file.
496   // Note: We cannot mmap /proc/cpuinfo here and then process the resulting
497   // memory buffer because the 'file' has 0 size (it can be read from only
498   // as a stream).
499
500   std::string Err;
501   DataStreamer *DS = getDataFileStreamer("/proc/cpuinfo", &Err);
502   if (!DS) {
503     DEBUG(dbgs() << "Unable to open /proc/cpuinfo: " << Err << "\n");
504     return "generic";
505   }
506
507   // Read 1024 bytes from /proc/cpuinfo, which should contain the CPU part line
508   // in all cases.
509   char buffer[1024];
510   size_t CPUInfoSize = DS->GetBytes((unsigned char*) buffer, sizeof(buffer));
511   delete DS;
512
513   StringRef Str(buffer, CPUInfoSize);
514
515   SmallVector<StringRef, 32> Lines;
516   Str.split(Lines, "\n");
517
518   // Look for the CPU implementer line.
519   StringRef Implementer;
520   for (unsigned I = 0, E = Lines.size(); I != E; ++I)
521     if (Lines[I].startswith("CPU implementer"))
522       Implementer = Lines[I].substr(15).ltrim("\t :");
523
524   if (Implementer == "0x41") // ARM Ltd.
525     // Look for the CPU part line.
526     for (unsigned I = 0, E = Lines.size(); I != E; ++I)
527       if (Lines[I].startswith("CPU part"))
528         // The CPU part is a 3 digit hexadecimal number with a 0x prefix. The
529         // values correspond to the "Part number" in the CP15/c0 register. The
530         // contents are specified in the various processor manuals.
531         return StringSwitch<const char *>(Lines[I].substr(8).ltrim("\t :"))
532           .Case("0x926", "arm926ej-s")
533           .Case("0xb02", "mpcore")
534           .Case("0xb36", "arm1136j-s")
535           .Case("0xb56", "arm1156t2-s")
536           .Case("0xb76", "arm1176jz-s")
537           .Case("0xc08", "cortex-a8")
538           .Case("0xc09", "cortex-a9")
539           .Case("0xc0f", "cortex-a15")
540           .Case("0xc20", "cortex-m0")
541           .Case("0xc23", "cortex-m3")
542           .Case("0xc24", "cortex-m4")
543           .Default("generic");
544
545   return "generic";
546 }
547 #else
548 std::string sys::getHostCPUName() {
549   return "generic";
550 }
551 #endif
552
553 #if defined(__linux__) && defined(__arm__)
554 bool sys::getHostCPUFeatures(StringMap<bool> &Features) {
555   std::string Err;
556   DataStreamer *DS = getDataFileStreamer("/proc/cpuinfo", &Err);
557   if (!DS) {
558     DEBUG(dbgs() << "Unable to open /proc/cpuinfo: " << Err << "\n");
559     return false;
560   }
561
562   // Read 1024 bytes from /proc/cpuinfo, which should contain the Features line
563   // in all cases.
564   char buffer[1024];
565   size_t CPUInfoSize = DS->GetBytes((unsigned char*) buffer, sizeof(buffer));
566   delete DS;
567
568   StringRef Str(buffer, CPUInfoSize);
569
570   SmallVector<StringRef, 32> Lines;
571   Str.split(Lines, "\n");
572
573   SmallVector<StringRef, 32> CPUFeatures;
574
575   // Look for the CPU features.
576   for (unsigned I = 0, E = Lines.size(); I != E; ++I)
577     if (Lines[I].startswith("Features")) {
578       Lines[I].split(CPUFeatures, " ");
579       break;
580     }
581
582   for (unsigned I = 0, E = CPUFeatures.size(); I != E; ++I) {
583     StringRef LLVMFeatureStr = StringSwitch<StringRef>(CPUFeatures[I])
584       .Case("half", "fp16")
585       .Case("neon", "neon")
586       .Case("vfpv3", "vfp3")
587       .Case("vfpv3d16", "d16")
588       .Case("vfpv4", "vfp4")
589       .Case("idiva", "hwdiv-arm")
590       .Case("idivt", "hwdiv")
591       .Default("");
592
593     if (LLVMFeatureStr != "")
594       Features.GetOrCreateValue(LLVMFeatureStr).setValue(true);
595   }
596
597   return true;
598 }
599 #else
600 bool sys::getHostCPUFeatures(StringMap<bool> &Features){
601   return false;
602 }
603 #endif
604
605 std::string sys::getProcessTriple() {
606   Triple PT(Triple::normalize(LLVM_HOST_TRIPLE));
607
608   if (sizeof(void *) == 8 && PT.isArch32Bit())
609     PT = PT.get64BitArchVariant();
610   if (sizeof(void *) == 4 && PT.isArch64Bit())
611     PT = PT.get32BitArchVariant();
612
613   return PT.str();
614 }