1 //===--- PPC.cpp - Implement PPC target feature support -------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file implements PPC TargetInfo objects.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "PPC.h"
14 #include "clang/Basic/Diagnostic.h"
15 #include "clang/Basic/MacroBuilder.h"
16 #include "clang/Basic/TargetBuiltins.h"
17 
18 using namespace clang;
19 using namespace clang::targets;
20 
21 const Builtin::Info PPCTargetInfo::BuiltinInfo[] = {
22 #define BUILTIN(ID, TYPE, ATTRS)                                               \
23   {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr},
24 #define LIBBUILTIN(ID, TYPE, ATTRS, HEADER)                                    \
25   {#ID, TYPE, ATTRS, HEADER, ALL_LANGUAGES, nullptr},
26 #include "clang/Basic/BuiltinsPPC.def"
27 };
28 
29 /// handleTargetFeatures - Perform initialization based on the user
30 /// configured set of features.
31 bool PPCTargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
32                                          DiagnosticsEngine &Diags) {
33   for (const auto &Feature : Features) {
34     if (Feature == "+altivec") {
35       HasAltivec = true;
36     } else if (Feature == "+vsx") {
37       HasVSX = true;
38     } else if (Feature == "+bpermd") {
39       HasBPERMD = true;
40     } else if (Feature == "+extdiv") {
41       HasExtDiv = true;
42     } else if (Feature == "+power8-vector") {
43       HasP8Vector = true;
44     } else if (Feature == "+crypto") {
45       HasP8Crypto = true;
46     } else if (Feature == "+direct-move") {
47       HasDirectMove = true;
48     } else if (Feature == "+qpx") {
49       HasQPX = true;
50     } else if (Feature == "+htm") {
51       HasHTM = true;
52     } else if (Feature == "+float128") {
53       HasFloat128 = true;
54     } else if (Feature == "+power9-vector") {
55       HasP9Vector = true;
56     }
57     // TODO: Finish this list and add an assert that we've handled them
58     // all.
59   }
60 
61   return true;
62 }
63 
64 /// PPCTargetInfo::getTargetDefines - Return a set of the PowerPC-specific
65 /// #defines that are not tied to a specific subtarget.
66 void PPCTargetInfo::getTargetDefines(const LangOptions &Opts,
67                                      MacroBuilder &Builder) const {
68   // Target identification.
69   Builder.defineMacro("__ppc__");
70   Builder.defineMacro("__PPC__");
71   Builder.defineMacro("_ARCH_PPC");
72   Builder.defineMacro("__powerpc__");
73   Builder.defineMacro("__POWERPC__");
74   if (PointerWidth == 64) {
75     Builder.defineMacro("_ARCH_PPC64");
76     Builder.defineMacro("__powerpc64__");
77     Builder.defineMacro("__ppc64__");
78     Builder.defineMacro("__PPC64__");
79   }
80 
81   // Target properties.
82   if (getTriple().getArch() == llvm::Triple::ppc64le) {
83     Builder.defineMacro("_LITTLE_ENDIAN");
84   } else {
85     if (!getTriple().isOSNetBSD() &&
86         !getTriple().isOSOpenBSD())
87       Builder.defineMacro("_BIG_ENDIAN");
88   }
89 
90   // ABI options.
91   if (ABI == "elfv1" || ABI == "elfv1-qpx")
92     Builder.defineMacro("_CALL_ELF", "1");
93   if (ABI == "elfv2")
94     Builder.defineMacro("_CALL_ELF", "2");
95 
96   // This typically is only for a new enough linker (bfd >= 2.16.2 or gold), but
97   // our support post-dates this and it should work on all 64-bit ppc linux
98   // platforms. It is guaranteed to work on all elfv2 platforms.
99   if (getTriple().getOS() == llvm::Triple::Linux && PointerWidth == 64)
100     Builder.defineMacro("_CALL_LINUX", "1");
101 
102   // Subtarget options.
103   if (!getTriple().isOSAIX()){
104     Builder.defineMacro("__NATURAL_ALIGNMENT__");
105   }
106   Builder.defineMacro("__REGISTER_PREFIX__", "");
107 
108   // FIXME: Should be controlled by command line option.
109   if (LongDoubleWidth == 128) {
110     Builder.defineMacro("__LONG_DOUBLE_128__");
111     Builder.defineMacro("__LONGDOUBLE128");
112   }
113 
114   // Define this for elfv2 (64-bit only) or 64-bit darwin.
115   if (ABI == "elfv2" ||
116       (getTriple().getOS() == llvm::Triple::Darwin && PointerWidth == 64))
117     Builder.defineMacro("__STRUCT_PARM_ALIGN__", "16");
118 
119   if (ArchDefs & ArchDefineName)
120     Builder.defineMacro(Twine("_ARCH_", StringRef(CPU).upper()));
121   if (ArchDefs & ArchDefinePpcgr)
122     Builder.defineMacro("_ARCH_PPCGR");
123   if (ArchDefs & ArchDefinePpcsq)
124     Builder.defineMacro("_ARCH_PPCSQ");
125   if (ArchDefs & ArchDefine440)
126     Builder.defineMacro("_ARCH_440");
127   if (ArchDefs & ArchDefine603)
128     Builder.defineMacro("_ARCH_603");
129   if (ArchDefs & ArchDefine604)
130     Builder.defineMacro("_ARCH_604");
131   if (ArchDefs & ArchDefinePwr4)
132     Builder.defineMacro("_ARCH_PWR4");
133   if (ArchDefs & ArchDefinePwr5)
134     Builder.defineMacro("_ARCH_PWR5");
135   if (ArchDefs & ArchDefinePwr5x)
136     Builder.defineMacro("_ARCH_PWR5X");
137   if (ArchDefs & ArchDefinePwr6)
138     Builder.defineMacro("_ARCH_PWR6");
139   if (ArchDefs & ArchDefinePwr6x)
140     Builder.defineMacro("_ARCH_PWR6X");
141   if (ArchDefs & ArchDefinePwr7)
142     Builder.defineMacro("_ARCH_PWR7");
143   if (ArchDefs & ArchDefinePwr8)
144     Builder.defineMacro("_ARCH_PWR8");
145   if (ArchDefs & ArchDefinePwr9)
146     Builder.defineMacro("_ARCH_PWR9");
147   if (ArchDefs & ArchDefineA2)
148     Builder.defineMacro("_ARCH_A2");
149   if (ArchDefs & ArchDefineA2q) {
150     Builder.defineMacro("_ARCH_A2Q");
151     Builder.defineMacro("_ARCH_QP");
152   }
153 
154   if (getTriple().getVendor() == llvm::Triple::BGQ) {
155     Builder.defineMacro("__bg__");
156     Builder.defineMacro("__THW_BLUEGENE__");
157     Builder.defineMacro("__bgq__");
158     Builder.defineMacro("__TOS_BGQ__");
159   }
160 
161   if (HasAltivec) {
162     Builder.defineMacro("__VEC__", "10206");
163     Builder.defineMacro("__ALTIVEC__");
164   }
165   if (HasVSX)
166     Builder.defineMacro("__VSX__");
167   if (HasP8Vector)
168     Builder.defineMacro("__POWER8_VECTOR__");
169   if (HasP8Crypto)
170     Builder.defineMacro("__CRYPTO__");
171   if (HasHTM)
172     Builder.defineMacro("__HTM__");
173   if (HasFloat128)
174     Builder.defineMacro("__FLOAT128__");
175   if (HasP9Vector)
176     Builder.defineMacro("__POWER9_VECTOR__");
177 
178   Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1");
179   Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2");
180   Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4");
181   if (PointerWidth == 64)
182     Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8");
183 
184   // We have support for the bswap intrinsics so we can define this.
185   Builder.defineMacro("__HAVE_BSWAP__", "1");
186 
187   // FIXME: The following are not yet generated here by Clang, but are
188   //        generated by GCC:
189   //
190   //   _SOFT_FLOAT_
191   //   __RECIP_PRECISION__
192   //   __APPLE_ALTIVEC__
193   //   __RECIP__
194   //   __RECIPF__
195   //   __RSQRTE__
196   //   __RSQRTEF__
197   //   _SOFT_DOUBLE_
198   //   __NO_LWSYNC__
199   //   __CMODEL_MEDIUM__
200   //   __CMODEL_LARGE__
201   //   _CALL_SYSV
202   //   _CALL_DARWIN
203   //   __NO_FPRS__
204 }
205 
206 // Handle explicit options being passed to the compiler here: if we've
207 // explicitly turned off vsx and turned on any of:
208 // - power8-vector
209 // - direct-move
210 // - float128
211 // - power9-vector
212 // then go ahead and error since the customer has expressed an incompatible
213 // set of options.
214 static bool ppcUserFeaturesCheck(DiagnosticsEngine &Diags,
215                                  const std::vector<std::string> &FeaturesVec) {
216 
217   if (std::find(FeaturesVec.begin(), FeaturesVec.end(), "-vsx") !=
218       FeaturesVec.end()) {
219     if (std::find(FeaturesVec.begin(), FeaturesVec.end(), "+power8-vector") !=
220         FeaturesVec.end()) {
221       Diags.Report(diag::err_opt_not_valid_with_opt) << "-mpower8-vector"
222                                                      << "-mno-vsx";
223       return false;
224     }
225 
226     if (std::find(FeaturesVec.begin(), FeaturesVec.end(), "+direct-move") !=
227         FeaturesVec.end()) {
228       Diags.Report(diag::err_opt_not_valid_with_opt) << "-mdirect-move"
229                                                      << "-mno-vsx";
230       return false;
231     }
232 
233     if (std::find(FeaturesVec.begin(), FeaturesVec.end(), "+float128") !=
234         FeaturesVec.end()) {
235       Diags.Report(diag::err_opt_not_valid_with_opt) << "-mfloat128"
236                                                      << "-mno-vsx";
237       return false;
238     }
239 
240     if (std::find(FeaturesVec.begin(), FeaturesVec.end(), "+power9-vector") !=
241         FeaturesVec.end()) {
242       Diags.Report(diag::err_opt_not_valid_with_opt) << "-mpower9-vector"
243                                                      << "-mno-vsx";
244       return false;
245     }
246   }
247 
248   return true;
249 }
250 
251 bool PPCTargetInfo::initFeatureMap(
252     llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef CPU,
253     const std::vector<std::string> &FeaturesVec) const {
254   Features["altivec"] = llvm::StringSwitch<bool>(CPU)
255                             .Case("7400", true)
256                             .Case("g4", true)
257                             .Case("7450", true)
258                             .Case("g4+", true)
259                             .Case("970", true)
260                             .Case("g5", true)
261                             .Case("pwr6", true)
262                             .Case("pwr7", true)
263                             .Case("pwr8", true)
264                             .Case("pwr9", true)
265                             .Case("ppc64", true)
266                             .Case("ppc64le", true)
267                             .Default(false);
268 
269   Features["qpx"] = (CPU == "a2q");
270   Features["power9-vector"] = (CPU == "pwr9");
271   Features["crypto"] = llvm::StringSwitch<bool>(CPU)
272                            .Case("ppc64le", true)
273                            .Case("pwr9", true)
274                            .Case("pwr8", true)
275                            .Default(false);
276   Features["power8-vector"] = llvm::StringSwitch<bool>(CPU)
277                                   .Case("ppc64le", true)
278                                   .Case("pwr9", true)
279                                   .Case("pwr8", true)
280                                   .Default(false);
281   Features["bpermd"] = llvm::StringSwitch<bool>(CPU)
282                            .Case("ppc64le", true)
283                            .Case("pwr9", true)
284                            .Case("pwr8", true)
285                            .Case("pwr7", true)
286                            .Default(false);
287   Features["extdiv"] = llvm::StringSwitch<bool>(CPU)
288                            .Case("ppc64le", true)
289                            .Case("pwr9", true)
290                            .Case("pwr8", true)
291                            .Case("pwr7", true)
292                            .Default(false);
293   Features["direct-move"] = llvm::StringSwitch<bool>(CPU)
294                                 .Case("ppc64le", true)
295                                 .Case("pwr9", true)
296                                 .Case("pwr8", true)
297                                 .Default(false);
298   Features["vsx"] = llvm::StringSwitch<bool>(CPU)
299                         .Case("ppc64le", true)
300                         .Case("pwr9", true)
301                         .Case("pwr8", true)
302                         .Case("pwr7", true)
303                         .Default(false);
304   Features["htm"] = llvm::StringSwitch<bool>(CPU)
305                         .Case("ppc64le", true)
306                         .Case("pwr9", true)
307                         .Case("pwr8", true)
308                         .Default(false);
309 
310   if (!ppcUserFeaturesCheck(Diags, FeaturesVec))
311     return false;
312 
313   if (!(ArchDefs & ArchDefinePwr9) && (ArchDefs & ArchDefinePpcgr) &&
314       std::find(FeaturesVec.begin(), FeaturesVec.end(), "+float128") !=
315           FeaturesVec.end()) {
316     // We have __float128 on PPC but not power 9 and above.
317     Diags.Report(diag::err_opt_not_valid_with_opt) << "-mfloat128" << CPU;
318     return false;
319   }
320 
321   return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec);
322 }
323 
324 bool PPCTargetInfo::hasFeature(StringRef Feature) const {
325   return llvm::StringSwitch<bool>(Feature)
326       .Case("powerpc", true)
327       .Case("altivec", HasAltivec)
328       .Case("vsx", HasVSX)
329       .Case("power8-vector", HasP8Vector)
330       .Case("crypto", HasP8Crypto)
331       .Case("direct-move", HasDirectMove)
332       .Case("qpx", HasQPX)
333       .Case("htm", HasHTM)
334       .Case("bpermd", HasBPERMD)
335       .Case("extdiv", HasExtDiv)
336       .Case("float128", HasFloat128)
337       .Case("power9-vector", HasP9Vector)
338       .Default(false);
339 }
340 
341 void PPCTargetInfo::setFeatureEnabled(llvm::StringMap<bool> &Features,
342                                       StringRef Name, bool Enabled) const {
343   if (Enabled) {
344     // If we're enabling any of the vsx based features then enable vsx and
345     // altivec. We'll diagnose any problems later.
346     bool FeatureHasVSX = llvm::StringSwitch<bool>(Name)
347                              .Case("vsx", true)
348                              .Case("direct-move", true)
349                              .Case("power8-vector", true)
350                              .Case("power9-vector", true)
351                              .Case("float128", true)
352                              .Default(false);
353     if (FeatureHasVSX)
354       Features["vsx"] = Features["altivec"] = true;
355     if (Name == "power9-vector")
356       Features["power8-vector"] = true;
357     Features[Name] = true;
358   } else {
359     // If we're disabling altivec or vsx go ahead and disable all of the vsx
360     // features.
361     if ((Name == "altivec") || (Name == "vsx"))
362       Features["vsx"] = Features["direct-move"] = Features["power8-vector"] =
363           Features["float128"] = Features["power9-vector"] = false;
364     if (Name == "power8-vector")
365       Features["power9-vector"] = false;
366     Features[Name] = false;
367   }
368 }
369 
370 const char *const PPCTargetInfo::GCCRegNames[] = {
371     "r0",  "r1",     "r2",   "r3",      "r4",      "r5",  "r6",  "r7",  "r8",
372     "r9",  "r10",    "r11",  "r12",     "r13",     "r14", "r15", "r16", "r17",
373     "r18", "r19",    "r20",  "r21",     "r22",     "r23", "r24", "r25", "r26",
374     "r27", "r28",    "r29",  "r30",     "r31",     "f0",  "f1",  "f2",  "f3",
375     "f4",  "f5",     "f6",   "f7",      "f8",      "f9",  "f10", "f11", "f12",
376     "f13", "f14",    "f15",  "f16",     "f17",     "f18", "f19", "f20", "f21",
377     "f22", "f23",    "f24",  "f25",     "f26",     "f27", "f28", "f29", "f30",
378     "f31", "mq",     "lr",   "ctr",     "ap",      "cr0", "cr1", "cr2", "cr3",
379     "cr4", "cr5",    "cr6",  "cr7",     "xer",     "v0",  "v1",  "v2",  "v3",
380     "v4",  "v5",     "v6",   "v7",      "v8",      "v9",  "v10", "v11", "v12",
381     "v13", "v14",    "v15",  "v16",     "v17",     "v18", "v19", "v20", "v21",
382     "v22", "v23",    "v24",  "v25",     "v26",     "v27", "v28", "v29", "v30",
383     "v31", "vrsave", "vscr", "spe_acc", "spefscr", "sfp"
384 };
385 
386 ArrayRef<const char *> PPCTargetInfo::getGCCRegNames() const {
387   return llvm::makeArrayRef(GCCRegNames);
388 }
389 
390 const TargetInfo::GCCRegAlias PPCTargetInfo::GCCRegAliases[] = {
391     // While some of these aliases do map to different registers
392     // they still share the same register name.
393     {{"0"}, "r0"},     {{"1"}, "r1"},     {{"2"}, "r2"},     {{"3"}, "r3"},
394     {{"4"}, "r4"},     {{"5"}, "r5"},     {{"6"}, "r6"},     {{"7"}, "r7"},
395     {{"8"}, "r8"},     {{"9"}, "r9"},     {{"10"}, "r10"},   {{"11"}, "r11"},
396     {{"12"}, "r12"},   {{"13"}, "r13"},   {{"14"}, "r14"},   {{"15"}, "r15"},
397     {{"16"}, "r16"},   {{"17"}, "r17"},   {{"18"}, "r18"},   {{"19"}, "r19"},
398     {{"20"}, "r20"},   {{"21"}, "r21"},   {{"22"}, "r22"},   {{"23"}, "r23"},
399     {{"24"}, "r24"},   {{"25"}, "r25"},   {{"26"}, "r26"},   {{"27"}, "r27"},
400     {{"28"}, "r28"},   {{"29"}, "r29"},   {{"30"}, "r30"},   {{"31"}, "r31"},
401     {{"fr0"}, "f0"},   {{"fr1"}, "f1"},   {{"fr2"}, "f2"},   {{"fr3"}, "f3"},
402     {{"fr4"}, "f4"},   {{"fr5"}, "f5"},   {{"fr6"}, "f6"},   {{"fr7"}, "f7"},
403     {{"fr8"}, "f8"},   {{"fr9"}, "f9"},   {{"fr10"}, "f10"}, {{"fr11"}, "f11"},
404     {{"fr12"}, "f12"}, {{"fr13"}, "f13"}, {{"fr14"}, "f14"}, {{"fr15"}, "f15"},
405     {{"fr16"}, "f16"}, {{"fr17"}, "f17"}, {{"fr18"}, "f18"}, {{"fr19"}, "f19"},
406     {{"fr20"}, "f20"}, {{"fr21"}, "f21"}, {{"fr22"}, "f22"}, {{"fr23"}, "f23"},
407     {{"fr24"}, "f24"}, {{"fr25"}, "f25"}, {{"fr26"}, "f26"}, {{"fr27"}, "f27"},
408     {{"fr28"}, "f28"}, {{"fr29"}, "f29"}, {{"fr30"}, "f30"}, {{"fr31"}, "f31"},
409     {{"cc"}, "cr0"},
410 };
411 
412 ArrayRef<TargetInfo::GCCRegAlias> PPCTargetInfo::getGCCRegAliases() const {
413   return llvm::makeArrayRef(GCCRegAliases);
414 }
415 
416 // PPC ELFABIv2 DWARF Definitoin "Table 2.26. Mappings of Common Registers".
417 // vs0 ~ vs31 is mapping to 32 - 63,
418 // vs32 ~ vs63 is mapping to 77 - 108.
419 const TargetInfo::AddlRegName GCCAddlRegNames[] = {
420     // Table of additional register names to use in user input.
421     {{"vs0"}, 32},   {{"vs1"}, 33},   {{"vs2"}, 34},   {{"vs3"}, 35},
422     {{"vs4"}, 36},   {{"vs5"}, 37},   {{"vs6"}, 38},   {{"vs7"}, 39},
423     {{"vs8"}, 40},   {{"vs9"}, 41},   {{"vs10"}, 42},  {{"vs11"}, 43},
424     {{"vs12"}, 44},  {{"vs13"}, 45},  {{"vs14"}, 46},  {{"vs15"}, 47},
425     {{"vs16"}, 48},  {{"vs17"}, 49},  {{"vs18"}, 50},  {{"vs19"}, 51},
426     {{"vs20"}, 52},  {{"vs21"}, 53},  {{"vs22"}, 54},  {{"vs23"}, 55},
427     {{"vs24"}, 56},  {{"vs25"}, 57},  {{"vs26"}, 58},  {{"vs27"}, 59},
428     {{"vs28"}, 60},  {{"vs29"}, 61},  {{"vs30"}, 62},  {{"vs31"}, 63},
429     {{"vs32"}, 77},  {{"vs33"}, 78},  {{"vs34"}, 79},  {{"vs35"}, 80},
430     {{"vs36"}, 81},  {{"vs37"}, 82},  {{"vs38"}, 83},  {{"vs39"}, 84},
431     {{"vs40"}, 85},  {{"vs41"}, 86},  {{"vs42"}, 87},  {{"vs43"}, 88},
432     {{"vs44"}, 89},  {{"vs45"}, 90},  {{"vs46"}, 91},  {{"vs47"}, 92},
433     {{"vs48"}, 93},  {{"vs49"}, 94},  {{"vs50"}, 95},  {{"vs51"}, 96},
434     {{"vs52"}, 97},  {{"vs53"}, 98},  {{"vs54"}, 99},  {{"vs55"}, 100},
435     {{"vs56"}, 101}, {{"vs57"}, 102}, {{"vs58"}, 103}, {{"vs59"}, 104},
436     {{"vs60"}, 105}, {{"vs61"}, 106}, {{"vs62"}, 107}, {{"vs63"}, 108},
437 };
438 
439 ArrayRef<TargetInfo::AddlRegName> PPCTargetInfo::getGCCAddlRegNames() const {
440   if (ABI == "elfv2")
441     return llvm::makeArrayRef(GCCAddlRegNames);
442   else
443     return TargetInfo::getGCCAddlRegNames();
444 }
445 
446 static constexpr llvm::StringLiteral ValidCPUNames[] = {
447     {"generic"}, {"440"},         {"450"},     {"601"},    {"602"},
448     {"603"},     {"603e"},        {"603ev"},   {"604"},    {"604e"},
449     {"620"},     {"630"},         {"g3"},      {"7400"},   {"g4"},
450     {"7450"},    {"g4+"},         {"750"},     {"970"},    {"g5"},
451     {"a2"},      {"a2q"},         {"e500mc"},  {"e5500"},  {"power3"},
452     {"pwr3"},    {"power4"},      {"pwr4"},    {"power5"}, {"pwr5"},
453     {"power5x"}, {"pwr5x"},       {"power6"},  {"pwr6"},   {"power6x"},
454     {"pwr6x"},   {"power7"},      {"pwr7"},    {"power8"}, {"pwr8"},
455     {"power9"},  {"pwr9"},        {"powerpc"}, {"ppc"},    {"powerpc64"},
456     {"ppc64"},   {"powerpc64le"}, {"ppc64le"},
457 };
458 
459 bool PPCTargetInfo::isValidCPUName(StringRef Name) const {
460   return llvm::find(ValidCPUNames, Name) != std::end(ValidCPUNames);
461 }
462 
463 void PPCTargetInfo::fillValidCPUList(SmallVectorImpl<StringRef> &Values) const {
464   Values.append(std::begin(ValidCPUNames), std::end(ValidCPUNames));
465 }
466 
467 void PPCTargetInfo::adjust(LangOptions &Opts) {
468   if (HasAltivec)
469     Opts.AltiVec = 1;
470   TargetInfo::adjust(Opts);
471 }
472 
473 ArrayRef<Builtin::Info> PPCTargetInfo::getTargetBuiltins() const {
474   return llvm::makeArrayRef(BuiltinInfo, clang::PPC::LastTSBuiltin -
475                                              Builtin::FirstTSBuiltin);
476 }
477