in lib/llvm/Support/Triple.cpp [753:940]
std::string Triple::normalize(StringRef Str) {
bool IsMinGW32 = false;
bool IsCygwin = false;
// Parse into components.
SmallVector<StringRef, 4> Components;
Str.split(Components, '-');
// If the first component corresponds to a known architecture, preferentially
// use it for the architecture. If the second component corresponds to a
// known vendor, preferentially use it for the vendor, etc. This avoids silly
// component movement when a component parses as (eg) both a valid arch and a
// valid os.
ArchType Arch = UnknownArch;
if (Components.size() > 0)
Arch = parseArch(Components[0]);
VendorType Vendor = UnknownVendor;
if (Components.size() > 1)
Vendor = parseVendor(Components[1]);
OSType OS = UnknownOS;
if (Components.size() > 2) {
OS = parseOS(Components[2]);
IsCygwin = Components[2].startswith("cygwin");
IsMinGW32 = Components[2].startswith("mingw");
}
EnvironmentType Environment = UnknownEnvironment;
if (Components.size() > 3)
Environment = parseEnvironment(Components[3]);
ObjectFormatType ObjectFormat = UnknownObjectFormat;
if (Components.size() > 4)
ObjectFormat = parseFormat(Components[4]);
// Note which components are already in their final position. These will not
// be moved.
bool Found[4];
Found[0] = Arch != UnknownArch;
Found[1] = Vendor != UnknownVendor;
Found[2] = OS != UnknownOS;
Found[3] = Environment != UnknownEnvironment;
// If they are not there already, permute the components into their canonical
// positions by seeing if they parse as a valid architecture, and if so moving
// the component to the architecture position etc.
for (unsigned Pos = 0; Pos != array_lengthof(Found); ++Pos) {
if (Found[Pos])
continue; // Already in the canonical position.
for (unsigned Idx = 0; Idx != Components.size(); ++Idx) {
// Do not reparse any components that already matched.
if (Idx < array_lengthof(Found) && Found[Idx])
continue;
// Does this component parse as valid for the target position?
bool Valid = false;
StringRef Comp = Components[Idx];
switch (Pos) {
default: llvm_unreachable("unexpected component type!");
case 0:
Arch = parseArch(Comp);
Valid = Arch != UnknownArch;
break;
case 1:
Vendor = parseVendor(Comp);
Valid = Vendor != UnknownVendor;
break;
case 2:
OS = parseOS(Comp);
IsCygwin = Comp.startswith("cygwin");
IsMinGW32 = Comp.startswith("mingw");
Valid = OS != UnknownOS || IsCygwin || IsMinGW32;
break;
case 3:
Environment = parseEnvironment(Comp);
Valid = Environment != UnknownEnvironment;
if (!Valid) {
ObjectFormat = parseFormat(Comp);
Valid = ObjectFormat != UnknownObjectFormat;
}
break;
}
if (!Valid)
continue; // Nope, try the next component.
// Move the component to the target position, pushing any non-fixed
// components that are in the way to the right. This tends to give
// good results in the common cases of a forgotten vendor component
// or a wrongly positioned environment.
if (Pos < Idx) {
// Insert left, pushing the existing components to the right. For
// example, a-b-i386 -> i386-a-b when moving i386 to the front.
StringRef CurrentComponent(""); // The empty component.
// Replace the component we are moving with an empty component.
std::swap(CurrentComponent, Components[Idx]);
// Insert the component being moved at Pos, displacing any existing
// components to the right.
for (unsigned i = Pos; !CurrentComponent.empty(); ++i) {
// Skip over any fixed components.
while (i < array_lengthof(Found) && Found[i])
++i;
// Place the component at the new position, getting the component
// that was at this position - it will be moved right.
std::swap(CurrentComponent, Components[i]);
}
} else if (Pos > Idx) {
// Push right by inserting empty components until the component at Idx
// reaches the target position Pos. For example, pc-a -> -pc-a when
// moving pc to the second position.
do {
// Insert one empty component at Idx.
StringRef CurrentComponent(""); // The empty component.
for (unsigned i = Idx; i < Components.size();) {
// Place the component at the new position, getting the component
// that was at this position - it will be moved right.
std::swap(CurrentComponent, Components[i]);
// If it was placed on top of an empty component then we are done.
if (CurrentComponent.empty())
break;
// Advance to the next component, skipping any fixed components.
while (++i < array_lengthof(Found) && Found[i])
;
}
// The last component was pushed off the end - append it.
if (!CurrentComponent.empty())
Components.push_back(CurrentComponent);
// Advance Idx to the component's new position.
while (++Idx < array_lengthof(Found) && Found[Idx])
;
} while (Idx < Pos); // Add more until the final position is reached.
}
assert(Pos < Components.size() && Components[Pos] == Comp &&
"Component moved wrong!");
Found[Pos] = true;
break;
}
}
// Special case logic goes here. At this point Arch, Vendor and OS have the
// correct values for the computed components.
std::string NormalizedEnvironment;
if (Environment == Triple::Android && Components[3].startswith("androideabi")) {
StringRef AndroidVersion = Components[3].drop_front(strlen("androideabi"));
if (AndroidVersion.empty()) {
Components[3] = "android";
} else {
NormalizedEnvironment = Twine("android", AndroidVersion).str();
Components[3] = NormalizedEnvironment;
}
}
// SUSE uses "gnueabi" to mean "gnueabihf"
if (Vendor == Triple::SUSE && Environment == llvm::Triple::GNUEABI)
Components[3] = "gnueabihf";
if (OS == Triple::Win32) {
Components.resize(4);
Components[2] = "windows";
if (Environment == UnknownEnvironment) {
if (ObjectFormat == UnknownObjectFormat || ObjectFormat == Triple::COFF)
Components[3] = "msvc";
else
Components[3] = getObjectFormatTypeName(ObjectFormat);
}
} else if (IsMinGW32) {
Components.resize(4);
Components[2] = "windows";
Components[3] = "gnu";
} else if (IsCygwin) {
Components.resize(4);
Components[2] = "windows";
Components[3] = "cygnus";
}
if (IsMinGW32 || IsCygwin ||
(OS == Triple::Win32 && Environment != UnknownEnvironment)) {
if (ObjectFormat != UnknownObjectFormat && ObjectFormat != Triple::COFF) {
Components.resize(5);
Components[4] = getObjectFormatTypeName(ObjectFormat);
}
}
// Stick the corrected components back together to form the normalized string.
std::string Normalized;
for (unsigned i = 0, e = Components.size(); i != e; ++i) {
if (i) Normalized += '-';
Normalized += Components[i];
}
return Normalized;
}