alnyan/yggdrasil: Yggdrasil target support

This commit is contained in:
Mark Poliakov 2024-11-11 23:18:27 +02:00
parent ab51eccf88
commit 0b21467e61
14 changed files with 409 additions and 4 deletions

View File

@ -142,6 +142,8 @@ std::unique_ptr<TargetInfo> AllocateTarget(const llvm::Triple &Triple,
return std::make_unique<DarwinAArch64TargetInfo>(Triple, Opts); return std::make_unique<DarwinAArch64TargetInfo>(Triple, Opts);
switch (os) { switch (os) {
case llvm::Triple::Yggdrasil:
return std::make_unique<YggdrasilTargetInfo<AArch64leTargetInfo>>(Triple, Opts);
case llvm::Triple::FreeBSD: case llvm::Triple::FreeBSD:
return std::make_unique<FreeBSDTargetInfo<AArch64leTargetInfo>>(Triple, return std::make_unique<FreeBSDTargetInfo<AArch64leTargetInfo>>(Triple,
Opts); Opts);
@ -578,6 +580,8 @@ std::unique_ptr<TargetInfo> AllocateTarget(const llvm::Triple &Triple,
} }
case llvm::Triple::Haiku: case llvm::Triple::Haiku:
return std::make_unique<HaikuX86_32TargetInfo>(Triple, Opts); return std::make_unique<HaikuX86_32TargetInfo>(Triple, Opts);
case llvm::Triple::Yggdrasil:
return std::make_unique<YggdrasilTargetInfo<X86_32TargetInfo>>(Triple, Opts);
case llvm::Triple::RTEMS: case llvm::Triple::RTEMS:
return std::make_unique<RTEMSX86_32TargetInfo>(Triple, Opts); return std::make_unique<RTEMSX86_32TargetInfo>(Triple, Opts);
case llvm::Triple::NaCl: case llvm::Triple::NaCl:
@ -638,6 +642,8 @@ std::unique_ptr<TargetInfo> AllocateTarget(const llvm::Triple &Triple,
} }
case llvm::Triple::Haiku: case llvm::Triple::Haiku:
return std::make_unique<HaikuTargetInfo<X86_64TargetInfo>>(Triple, Opts); return std::make_unique<HaikuTargetInfo<X86_64TargetInfo>>(Triple, Opts);
case llvm::Triple::Yggdrasil:
return std::make_unique<YggdrasilTargetInfo<X86_64TargetInfo>>(Triple, Opts);
case llvm::Triple::NaCl: case llvm::Triple::NaCl:
return std::make_unique<NaClTargetInfo<X86_64TargetInfo>>(Triple, Opts); return std::make_unique<NaClTargetInfo<X86_64TargetInfo>>(Triple, Opts);
case llvm::Triple::PS4: case llvm::Triple::PS4:

View File

@ -878,6 +878,25 @@ public:
} }
}; };
// Yggdrasil Target
template <typename Target>
class LLVM_LIBRARY_VISIBILITY YggdrasilTargetInfo : public OSTargetInfo<Target> {
protected:
void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
MacroBuilder &Builder) const override {
Builder.defineMacro("__yggdrasil__");
Builder.defineMacro("__FLOAT128__");
this->PlatformName = "yggdrasil";
}
public:
YggdrasilTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
: OSTargetInfo<Target>(Triple, Opts) {
this->WIntType = TargetInfo::UnsignedInt;
this->MCountName = "__mcount";
this->HasFloat128 = true;
}
};
// WebAssembly target // WebAssembly target
template <typename Target> template <typename Target>
class LLVM_LIBRARY_VISIBILITY WebAssemblyOSTargetInfo class LLVM_LIBRARY_VISIBILITY WebAssemblyOSTargetInfo

View File

@ -85,6 +85,7 @@ add_clang_library(clangDriver
ToolChains/PPCFreeBSD.cpp ToolChains/PPCFreeBSD.cpp
ToolChains/InterfaceStubs.cpp ToolChains/InterfaceStubs.cpp
ToolChains/ZOS.cpp ToolChains/ZOS.cpp
ToolChains/Yggdrasil.cpp
Types.cpp Types.cpp
XRayArgs.cpp XRayArgs.cpp

View File

@ -21,6 +21,7 @@
#include "ToolChains/DragonFly.h" #include "ToolChains/DragonFly.h"
#include "ToolChains/FreeBSD.h" #include "ToolChains/FreeBSD.h"
#include "ToolChains/Fuchsia.h" #include "ToolChains/Fuchsia.h"
#include "ToolChains/Yggdrasil.h"
#include "ToolChains/Gnu.h" #include "ToolChains/Gnu.h"
#include "ToolChains/HIPAMD.h" #include "ToolChains/HIPAMD.h"
#include "ToolChains/HIPSPV.h" #include "ToolChains/HIPSPV.h"
@ -6351,6 +6352,9 @@ const ToolChain &Driver::getToolChain(const ArgList &Args,
case llvm::Triple::Haiku: case llvm::Triple::Haiku:
TC = std::make_unique<toolchains::Haiku>(*this, Target, Args); TC = std::make_unique<toolchains::Haiku>(*this, Target, Args);
break; break;
case llvm::Triple::Yggdrasil:
TC = std::make_unique<toolchains::Yggdrasil>(*this, Target, Args);
break;
case llvm::Triple::Darwin: case llvm::Triple::Darwin:
case llvm::Triple::MacOSX: case llvm::Triple::MacOSX:
case llvm::Triple::IOS: case llvm::Triple::IOS:

View File

@ -0,0 +1,255 @@
#include "Yggdrasil.h"
#include "CommonArgs.h"
#include "clang/Config/config.h"
#include "clang/Driver/Compilation.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/MultilibBuilder.h"
#include "clang/Driver/Options.h"
#include "clang/Driver/SanitizerArgs.h"
#include "llvm/Option/ArgList.h"
#include "llvm/ProfileData/InstrProf.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/VirtualFileSystem.h"
#include <iostream>
using namespace clang::driver;
using namespace clang::driver::toolchains;
using namespace clang::driver::tools;
using namespace clang;
using namespace llvm::opt;
using tools::addMultilibFlag;
void yggdrasil::Linker::ConstructJob(
Compilation &C,
const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
const ArgList &Args,
const char *LinkingOutput
) const {
const toolchains::Yggdrasil &ToolChain = static_cast<const toolchains::Yggdrasil &>(getToolChain());
const Driver &D = ToolChain.getDriver();
ArgStringList CmdArgs;
// Silence warning for "clang -g foo.o -o foo"
Args.ClaimAllArgs(options::OPT_g_Group);
// and "clang -emit-llvm foo.o -o foo"
Args.ClaimAllArgs(options::OPT_emit_llvm);
// and for "clang -w foo.o -o foo". Other warning options are already
// handled somewhere else.
Args.ClaimAllArgs(options::OPT_w);
const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath());
CmdArgs.push_back("-z");
CmdArgs.push_back("max-page-size=4096");
CmdArgs.push_back("--eh-frame-hdr");
if (!Args.hasArg(options::OPT_shared) &&
!Args.hasArg(options::OPT_static) &&
!Args.hasArg(options::OPT_r)) {
CmdArgs.push_back("-pie");
}
if (Args.hasArg(options::OPT_r)) {
CmdArgs.push_back("-r");
} else {
CmdArgs.push_back("--build-id");
CmdArgs.push_back("--hash-style=gnu");
}
if (!D.SysRoot.empty()) {
CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));
}
if (Args.hasArg(options::OPT_s)) {
CmdArgs.push_back("-s");
}
if (Args.hasArg(options::OPT_static)) {
CmdArgs.push_back("-Bstatic");
} else {
if (Args.hasArg(options::OPT_shared)) {
CmdArgs.push_back("-shared");
}
CmdArgs.push_back("--dynamic-linker=/libexec/dyn-loader");
}
CmdArgs.push_back("-o");
CmdArgs.push_back(Output.getFilename());
if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles, options::OPT_r)) {
if (!Args.hasArg(options::OPT_shared)) {
CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt0.o")));
}
}
Args.AddAllArgs(CmdArgs, options::OPT_L);
Args.AddAllArgs(CmdArgs, options::OPT_u);
ToolChain.AddFilePathLibArgs(Args, CmdArgs);
// if (D.isUsingLTO()) {
// assert(!Inputs.empty() && "Must have at least one input.");
// addLTOOptions(ToolChain, Args, CmdArgs, Output, Inputs[0],
// D.getLTOMode() == LTOK_Thin);
// }
if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
AddRunTimeLibs(ToolChain, D, CmdArgs, Args);
if (!Args.hasArg(options::OPT_nolibc)) {
CmdArgs.push_back("-lygglibc");
}
if (D.CCCIsCXX()) {
if (ToolChain.ShouldLinkCXXStdlib(Args)) {
ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
// CmdArgs.push_back("-lm");
// CmdArgs.push_back("-lpthread");
}
}
}
AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA);
C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(),
Exec, CmdArgs, Inputs, Output));
}
/// Yggdrasil - Yggdrasil OS tool chain which can call as(1) and ld(1) directly.
Yggdrasil::Yggdrasil(
const Driver &D,
const llvm::Triple &Triple,
const ArgList &Args
): ToolChain(D, Triple, Args) {
getProgramPaths().push_back(getDriver().Dir);
if (!D.SysRoot.empty()) {
SmallString<128> P(D.SysRoot);
llvm::sys::path::append(P, "lib");
getFilePaths().push_back(std::string(P));
}
}
std::string Yggdrasil::ComputeEffectiveClangTriple(const ArgList &Args,
types::ID InputType) const {
llvm::Triple Triple(ComputeLLVMTriple(Args, InputType));
return Triple.str();
}
Tool *Yggdrasil::buildLinker() const {
return new tools::yggdrasil::Linker(*this);
}
ToolChain::RuntimeLibType Yggdrasil::GetRuntimeLibType(const ArgList &Args) const {
return ToolChain::RLT_CompilerRT;
}
ToolChain::RuntimeLibType Yggdrasil::GetDefaultRuntimeLibType() const {
return ToolChain::RLT_CompilerRT;
}
ToolChain::CXXStdlibType Yggdrasil::GetDefaultCXXStdlibType() const {
return ToolChain::CST_Libcxx;
}
ToolChain::UnwindLibType Yggdrasil::GetUnwindLibType(const ArgList &Args) const {
return ToolChain::UNW_None;
}
ToolChain::CXXStdlibType Yggdrasil::GetCXXStdlibType(const ArgList &Args) const {
return ToolChain::CST_Libcxx;
}
ToolChain::UnwindTableLevel Yggdrasil::getDefaultUnwindTableLevel(const llvm::opt::ArgList &Args) const {
return ToolChain::UnwindTableLevel::None;
}
void Yggdrasil::addClangTargetOptions(const ArgList &DriverArgs,
ArgStringList &CC1Args,
Action::OffloadKind) const {
if (getArch() == llvm::Triple::x86) {
CC1Args.push_back("-mstack-alignment=16");
}
// if (!DriverArgs.hasFlag(options::OPT_fuse_init_array,
// options::OPT_fno_use_init_array, true))
// CC1Args.push_back("-fno-use-init-array");
// CC1Args.push_back("-mlong-double-64"); // for newlib + libc++ compat
// CC1Args.push_back("-ffunction-sections"); // better to optimize binary sizes
// CC1Args.push_back("-fdata-sections");
}
void Yggdrasil::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
ArgStringList &CC1Args) const {
const Driver &D = getDriver();
if (DriverArgs.hasArg(options::OPT_nostdinc)) {
return;
}
if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
SmallString<128> P(D.ResourceDir);
llvm::sys::path::append(P, "include");
addSystemInclude(DriverArgs, CC1Args, P);
}
if (DriverArgs.hasArg(options::OPT_nostdlibinc)) {
return;
}
if (!D.SysRoot.empty()) {
SmallString<128> P(D.SysRoot);
llvm::sys::path::append(P, "include");
addExternCSystemInclude(DriverArgs, CC1Args, P.str());
}
}
void Yggdrasil::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
ArgStringList &CC1Args) const {
if (DriverArgs.hasArg(options::OPT_nostdlibinc) ||
DriverArgs.hasArg(options::OPT_nostdincxx)) {
return;
}
switch (GetCXXStdlibType(DriverArgs)) {
case ToolChain::CST_Libcxx: {
SmallString<128> P(getDriver().SysRoot);
llvm::sys::path::append(P, "include", "c++", "v1");
addSystemInclude(DriverArgs, CC1Args, P.str());
break;
}
default:
llvm_unreachable("invalid stdlib name");
}
}
void Yggdrasil::AddCXXStdlibLibArgs(const ArgList &Args,
ArgStringList &CmdArgs) const {
switch (GetCXXStdlibType(Args)) {
case ToolChain::CST_Libcxx:
CmdArgs.push_back("-lc++");
break;
case ToolChain::CST_Libstdcxx:
llvm_unreachable("invalid stdlib name");
}
}
std::string Yggdrasil::getCompilerRTPath() const {
SmallString<128> Path(getDriver().SysRoot);
llvm::sys::path::append(Path, "lib", getOSLibName());
return std::string(Path.str());
}

View File

@ -0,0 +1,98 @@
#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_YGGDRASIL_H
#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_YGGDRASIL_H
#include "Gnu.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Driver/Tool.h"
#include "clang/Driver/ToolChain.h"
#include "llvm/MC/MCTargetOptions.h"
namespace clang {
namespace driver {
namespace tools {
namespace yggdrasil {
class LLVM_LIBRARY_VISIBILITY Linker final : public Tool {
public:
Linker(const ToolChain &TC) : Tool("yggdrasil::Linker", "ld.lld", TC) {}
bool hasIntegratedCPP() const override { return false; }
bool isLinkJob() const override { return true; }
void ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output, const InputInfoList &Inputs,
const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const override;
};
} // end yggdrasil
} // end tools
namespace toolchains {
class LLVM_LIBRARY_VISIBILITY Yggdrasil : public ToolChain {
public:
Yggdrasil(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args);
bool HasNativeLLVMSupport() const override { return true; }
bool IsIntegratedAssemblerDefault() const override { return true; }
bool IsMathErrnoDefault() const override { return false; }
bool useRelaxRelocations() const override { return true; }
UnwindTableLevel getDefaultUnwindTableLevel(const llvm::opt::ArgList &Args) const override;
RuntimeLibType GetDefaultRuntimeLibType() const override;
CXXStdlibType GetDefaultCXXStdlibType() const override;
bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args) const {
return true;
}
llvm::ExceptionHandling GetExceptionModel(const llvm::opt::ArgList &Args) const override {
return llvm::ExceptionHandling::DwarfCFI;
}
bool isPICDefault() const override { return false; }
bool isPIEDefault(const llvm::opt::ArgList &Args) const override { return false; }
bool isPICDefaultForced() const override { return false; }
llvm::DebuggerKind getDefaultDebuggerTuning() const override {
return llvm::DebuggerKind::GDB;
}
LangOptions::StackProtectorMode GetDefaultStackProtectorLevel(bool KernelOrKext) const override {
return LangOptions::SSPStrong;
}
std::string ComputeEffectiveClangTriple(const llvm::opt::ArgList &Args,
types::ID InputType) const override;
RuntimeLibType
GetRuntimeLibType(const llvm::opt::ArgList &Args) const override;
UnwindLibType
GetUnwindLibType(const llvm::opt::ArgList &Args) const override;
CXXStdlibType
GetCXXStdlibType(const llvm::opt::ArgList &Args) const override;
void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args,
Action::OffloadKind DeviceOffloadKind) const override;
void
AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const override;
void
AddClangCXXStdlibIncludeArgs(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const override;
void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs) const override;
const char *getDefaultLinker() const override {
return "ld.lld";
}
virtual std::string getCompilerRTPath() const override;
protected:
Tool *buildLinker() const override;
};
} // end toolchains
} // end driver
} // end clang
#endif

View File

@ -1157,8 +1157,11 @@ int CONSTRUCTOR_ATTRIBUTE __cpu_indicator_init(void) {
unsigned Vendor; unsigned Vendor;
unsigned Model, Family; unsigned Model, Family;
unsigned Features[(CPU_FEATURE_MAX + 31) / 32] = {0}; unsigned Features[(CPU_FEATURE_MAX + 31) / 32] = {0};
// TODO static_assert is not defined
#if !defined(__yggdrasil__)
static_assert(sizeof(Features) / sizeof(Features[0]) == 4, ""); static_assert(sizeof(Features) / sizeof(Features[0]) == 4, "");
static_assert(sizeof(__cpu_features2) / sizeof(__cpu_features2[0]) == 3, ""); static_assert(sizeof(__cpu_features2) / sizeof(__cpu_features2[0]) == 3, "");
#endif
// This function needs to run just once. // This function needs to run just once.
if (__cpu_model.__cpu_vendor) if (__cpu_model.__cpu_vendor)

View File

@ -314,7 +314,7 @@ public:
# else # else
static const mask __regex_word = 1 << 10; static const mask __regex_word = 1 << 10;
# endif // defined(__BIONIC__) # endif // defined(__BIONIC__)
#elif defined(__GLIBC__) #elif defined(__GLIBC__) || defined(__yggdrasil__)
typedef unsigned short mask; typedef unsigned short mask;
static const mask space = _ISspace; static const mask space = _ISspace;
static const mask print = _ISprint; static const mask print = _ISprint;
@ -326,7 +326,7 @@ public:
static const mask punct = _ISpunct; static const mask punct = _ISpunct;
static const mask xdigit = _ISxdigit; static const mask xdigit = _ISxdigit;
static const mask blank = _ISblank; static const mask blank = _ISblank;
# if defined(__mips__) || (BYTE_ORDER == BIG_ENDIAN) # if !defined(__yggdrasil__) && (defined(__mips__) || (BYTE_ORDER == BIG_ENDIAN))
static const mask __regex_word = static_cast<mask>(_ISbit(15)); static const mask __regex_word = static_cast<mask>(_ISbit(15));
# else # else
static const mask __regex_word = 0x80; static const mask __regex_word = 0x80;

View File

@ -244,7 +244,11 @@ _LIBCPP_PUSH_MACROS
_LIBCPP_BEGIN_NAMESPACE_STD _LIBCPP_BEGIN_NAMESPACE_STD
#if defined(__yggdrasil__)
typedef ssize_t streamsize;
#else
typedef ptrdiff_t streamsize; typedef ptrdiff_t streamsize;
#endif
class _LIBCPP_EXPORTED_FROM_ABI ios_base { class _LIBCPP_EXPORTED_FROM_ABI ios_base {
public: public:

View File

@ -101,6 +101,18 @@ static void __libcpp_platform_wake_by_address(__cxx_atomic_contention_t const vo
_umtx_op(const_cast<__cxx_atomic_contention_t*>(__ptr), UMTX_OP_WAKE, __notify_one ? 1 : INT_MAX, NULL, NULL); _umtx_op(const_cast<__cxx_atomic_contention_t*>(__ptr), UMTX_OP_WAKE, __notify_one ? 1 : INT_MAX, NULL, NULL);
} }
#elif defined(__yggdrasil__)
static void __libcpp_platform_wait_on_address(
__cxx_atomic_contention_t const volatile* __ptr,
__cxx_contention_t __val
) {}
static void __libcpp_platform_wake_by_address(
__cxx_atomic_contention_t const volatile*,
bool
) {}
#else // <- Add other operating systems here #else // <- Add other operating systems here
// Baseline is just a timed backoff // Baseline is just a timed backoff

View File

@ -985,7 +985,7 @@ const ctype<char>::mask* ctype<char>::classic_table() noexcept {
return _LIBCPP_GET_C_LOCALE->__ctype_b; return _LIBCPP_GET_C_LOCALE->__ctype_b;
# elif defined(_LIBCPP_MSVCRT) || defined(__MINGW32__) # elif defined(_LIBCPP_MSVCRT) || defined(__MINGW32__)
return __pctype_func(); return __pctype_func();
# elif defined(__EMSCRIPTEN__) # elif defined(__EMSCRIPTEN__) || defined(__yggdrasil__)
return *__ctype_b_loc(); return *__ctype_b_loc();
# elif defined(_NEWLIB_VERSION) # elif defined(_NEWLIB_VERSION)
// Newlib has a 257-entry table in ctype_.c, where (char)0 starts at [1]. // Newlib has a 257-entry table in ctype_.c, where (char)0 starts at [1].

View File

@ -217,7 +217,7 @@ elseif(FUCHSIA OR UNIX)
else() else()
set(LLVM_HAVE_LINK_VERSION_SCRIPT 1) set(LLVM_HAVE_LINK_VERSION_SCRIPT 1)
endif() endif()
elseif(CMAKE_SYSTEM_NAME STREQUAL "Generic") elseif(CMAKE_SYSTEM_NAME STREQUAL "Generic" OR CMAKE_SYSTEM_NAME STREQUAL "yggdrasil")
set(LLVM_ON_WIN32 0) set(LLVM_ON_WIN32 0)
set(LLVM_ON_UNIX 0) set(LLVM_ON_UNIX 0)
set(LLVM_HAVE_LINK_VERSION_SCRIPT 0) set(LLVM_HAVE_LINK_VERSION_SCRIPT 0)

View File

@ -238,6 +238,7 @@ public:
ShaderModel, // DirectX ShaderModel ShaderModel, // DirectX ShaderModel
LiteOS, LiteOS,
Serenity, Serenity,
Yggdrasil,
Vulkan, // Vulkan SPIR-V Vulkan, // Vulkan SPIR-V
LastOSType = Vulkan LastOSType = Vulkan
}; };

View File

@ -292,6 +292,7 @@ StringRef Triple::getOSTypeName(OSType Kind) {
case RTEMS: return "rtems"; case RTEMS: return "rtems";
case Solaris: return "solaris"; case Solaris: return "solaris";
case Serenity: return "serenity"; case Serenity: return "serenity";
case Yggdrasil: return "yggdrasil";
case TvOS: return "tvos"; case TvOS: return "tvos";
case UEFI: return "uefi"; case UEFI: return "uefi";
case WASI: return "wasi"; case WASI: return "wasi";
@ -686,6 +687,7 @@ static Triple::OSType parseOS(StringRef OSName) {
.StartsWith("shadermodel", Triple::ShaderModel) .StartsWith("shadermodel", Triple::ShaderModel)
.StartsWith("liteos", Triple::LiteOS) .StartsWith("liteos", Triple::LiteOS)
.StartsWith("serenity", Triple::Serenity) .StartsWith("serenity", Triple::Serenity)
.StartsWith("yggdrasil", Triple::Yggdrasil)
.StartsWith("vulkan", Triple::Vulkan) .StartsWith("vulkan", Triple::Vulkan)
.Default(Triple::UnknownOS); .Default(Triple::UnknownOS);
} }