You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Theodosius/dependencies/asmjit/core/environment.h

613 lines
20 KiB

// AsmJit - Machine code generation for C++
//
// * Official AsmJit Home Page: https://asmjit.com
// * Official Github Repository: https://github.com/asmjit/asmjit
//
// Copyright (c) 2008-2020 The AsmJit Authors
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.
#ifndef ASMJIT_CORE_ENVIRONMENT_H_INCLUDED
#define ASMJIT_CORE_ENVIRONMENT_H_INCLUDED
#include "../core/globals.h"
#if defined(__APPLE__)
#include <TargetConditionals.h>
#endif
ASMJIT_BEGIN_NAMESPACE
//! \addtogroup asmjit_core
//! \{
// ============================================================================
// [asmjit::Environment]
// ============================================================================
//! Represents an environment, which is usually related to a \ref Target.
//!
//! Environment has usually an 'arch-subarch-vendor-os-abi' format, which is
//! sometimes called "Triple" (historically it used to be 3 only parts) or
//! "Tuple", which is a convention used by Debian Linux.
//!
//! AsmJit doesn't support all possible combinations or architectures and ABIs,
//! however, it models the environment similarly to other compilers for future
//! extensibility.
class Environment {
public:
//! Architecture type, see \ref Arch.
uint8_t _arch;
//! Sub-architecture type, see \ref SubArch.
uint8_t _subArch;
//! Vendor type, see \ref Vendor.
uint8_t _vendor;
//! Platform type, see \ref Platform.
uint8_t _platform;
//! ABI type, see \ref Abi.
uint8_t _abi;
//! Object format, see \ref Format.
uint8_t _format;
//! Reserved for future use, must be zero.
uint16_t _reserved;
//! Architecture.
enum Arch : uint32_t {
//! Unknown or uninitialized architecture.
kArchUnknown = 0,
//! Mask used by 32-bit architectures (odd are 32-bit, even are 64-bit).
kArch32BitMask = 0x01,
//! Mask used by big-endian architectures.
kArchBigEndianMask = 0x80u,
//! 32-bit X86 architecture.
kArchX86 = 1,
//! 64-bit X86 architecture also known as X86_64 and AMD64.
kArchX64 = 2,
//! 32-bit RISC-V architecture.
kArchRISCV32 = 3,
//! 64-bit RISC-V architecture.
kArchRISCV64 = 4,
//! 32-bit ARM architecture (little endian).
kArchARM = 5,
//! 32-bit ARM architecture (big endian).
kArchARM_BE = kArchARM | kArchBigEndianMask,
//! 64-bit ARM architecture in (little endian).
kArchAArch64 = 6,
//! 64-bit ARM architecture in (big endian).
kArchAArch64_BE = kArchAArch64 | kArchBigEndianMask,
//! 32-bit ARM in Thumb mode (little endian).
kArchThumb = 7,
//! 32-bit ARM in Thumb mode (big endian).
kArchThumb_BE = kArchThumb | kArchBigEndianMask,
// 8 is not used, even numbers are 64-bit architectures.
//! 32-bit MIPS architecture in (little endian).
kArchMIPS32_LE = 9,
//! 32-bit MIPS architecture in (big endian).
kArchMIPS32_BE = kArchMIPS32_LE | kArchBigEndianMask,
//! 64-bit MIPS architecture in (little endian).
kArchMIPS64_LE = 10,
//! 64-bit MIPS architecture in (big endian).
kArchMIPS64_BE = kArchMIPS64_LE | kArchBigEndianMask,
//! Count of architectures.
kArchCount = 11
};
//! Sub-architecture.
enum SubArch : uint32_t {
//! Unknown or uninitialized architecture sub-type.
kSubArchUnknown = 0,
//! Count of sub-architectures.
kSubArchCount
};
//! Vendor.
//!
//! \note AsmJit doesn't use vendor information at the moment. It's provided
//! for future use, if required.
enum Vendor : uint32_t {
//! Unknown or uninitialized vendor.
kVendorUnknown = 0,
//! Count of vendor identifiers.
kVendorCount
};
//! Platform / OS.
enum Platform : uint32_t {
//! Unknown or uninitialized platform.
kPlatformUnknown = 0,
//! Windows OS.
kPlatformWindows,
//! Other platform, most likely POSIX based.
kPlatformOther,
//! Linux OS.
kPlatformLinux,
//! GNU/Hurd OS.
kPlatformHurd,
//! FreeBSD OS.
kPlatformFreeBSD,
//! OpenBSD OS.
kPlatformOpenBSD,
//! NetBSD OS.
kPlatformNetBSD,
//! DragonFly BSD OS.
kPlatformDragonFlyBSD,
//! Haiku OS.
kPlatformHaiku,
//! Apple OSX.
kPlatformOSX,
//! Apple iOS.
kPlatformIOS,
//! Apple TVOS.
kPlatformTVOS,
//! Apple WatchOS.
kPlatformWatchOS,
//! Emscripten platform.
kPlatformEmscripten,
//! Count of platform identifiers.
kPlatformCount
};
//! ABI.
enum Abi : uint32_t {
//! Unknown or uninitialied environment.
kAbiUnknown = 0,
//! Microsoft ABI.
kAbiMSVC,
//! GNU ABI.
kAbiGNU,
//! Android Environment / ABI.
kAbiAndroid,
//! Cygwin ABI.
kAbiCygwin,
//! Count of known ABI types.
kAbiCount
};
//! Object format.
//!
//! \note AsmJit doesn't really use anything except \ref kFormatUnknown and
//! \ref kFormatJIT at the moment. Object file formats are provided for
//! future extensibility and a possibility to generate object files at some
//! point.
enum Format : uint32_t {
//! Unknown or uninitialized object format.
kFormatUnknown = 0,
//! JIT code generation object, most likely \ref JitRuntime or a custom
//! \ref Target implementation.
kFormatJIT,
//! Executable and linkable format (ELF).
kFormatELF,
//! Common object file format.
kFormatCOFF,
//! Extended COFF object format.
kFormatXCOFF,
//! Mach object file format.
kFormatMachO,
//! Count of object format types.
kFormatCount
};
//! \name Environment Detection
//! \{
#ifdef _DOXYGEN
//! Architecture detected at compile-time (architecture of the host).
static constexpr Arch kArchHost = DETECTED_AT_COMPILE_TIME;
//! Sub-architecture detected at compile-time (sub-architecture of the host).
static constexpr SubArch kSubArchHost = DETECTED_AT_COMPILE_TIME;
//! Vendor detected at compile-time (vendor of the host).
static constexpr Vendor kVendorHost = DETECTED_AT_COMPILE_TIME;
//! Platform detected at compile-time (platform of the host).
static constexpr Platform kPlatformHost = DETECTED_AT_COMPILE_TIME;
//! ABI detected at compile-time (ABI of the host).
static constexpr Abi kAbiHost = DETECTED_AT_COMPILE_TIME;
#else
static constexpr Arch kArchHost =
ASMJIT_ARCH_X86 == 32 ? kArchX86 :
ASMJIT_ARCH_X86 == 64 ? kArchX64 :
ASMJIT_ARCH_ARM == 32 && ASMJIT_ARCH_LE ? kArchARM :
ASMJIT_ARCH_ARM == 32 && ASMJIT_ARCH_BE ? kArchARM_BE :
ASMJIT_ARCH_ARM == 64 && ASMJIT_ARCH_LE ? kArchAArch64 :
ASMJIT_ARCH_ARM == 64 && ASMJIT_ARCH_BE ? kArchAArch64_BE :
ASMJIT_ARCH_MIPS == 32 && ASMJIT_ARCH_LE ? kArchMIPS32_LE :
ASMJIT_ARCH_MIPS == 32 && ASMJIT_ARCH_BE ? kArchMIPS32_BE :
ASMJIT_ARCH_MIPS == 64 && ASMJIT_ARCH_LE ? kArchMIPS64_LE :
ASMJIT_ARCH_MIPS == 64 && ASMJIT_ARCH_BE ? kArchMIPS64_BE :
kArchUnknown;
static constexpr SubArch kSubArchHost =
kSubArchUnknown;
static constexpr Vendor kVendorHost =
kVendorUnknown;
static constexpr Platform kPlatformHost =
#if defined(__EMSCRIPTEN__)
kPlatformEmscripten
#elif defined(_WIN32)
kPlatformWindows
#elif defined(__linux__)
kPlatformLinux
#elif defined(__gnu_hurd__)
kPlatformHurd
#elif defined(__FreeBSD__)
kPlatformFreeBSD
#elif defined(__OpenBSD__)
kPlatformOpenBSD
#elif defined(__NetBSD__)
kPlatformNetBSD
#elif defined(__DragonFly__)
kPlatformDragonFlyBSD
#elif defined(__HAIKU__)
kPlatformHaiku
#elif defined(__APPLE__) && TARGET_OS_OSX
kPlatformOSX
#elif defined(__APPLE__) && TARGET_OS_TV
kPlatformTVOS
#elif defined(__APPLE__) && TARGET_OS_WATCH
kPlatformWatchOS
#elif defined(__APPLE__) && TARGET_OS_IPHONE
kPlatformIOS
#else
kPlatformOther
#endif
;
static constexpr Abi kAbiHost =
#if defined(_MSC_VER)
kAbiMSVC
#elif defined(__CYGWIN__)
kAbiCygwin
#elif defined(__MINGW32__) || defined(__GLIBC__)
kAbiGNU
#elif defined(__ANDROID__)
kAbiAndroid
#else
kAbiUnknown
#endif
;
#endif
//! \}
//! \name Construction / Destruction
//! \{
inline Environment() noexcept :
_arch(uint8_t(kArchUnknown)),
_subArch(uint8_t(kSubArchUnknown)),
_vendor(uint8_t(kVendorUnknown)),
_platform(uint8_t(kPlatformUnknown)),
_abi(uint8_t(kAbiUnknown)),
_format(uint8_t(kFormatUnknown)),
_reserved(0) {}
inline Environment(const Environment& other) noexcept = default;
inline explicit Environment(uint32_t arch,
uint32_t subArch = kSubArchUnknown,
uint32_t vendor = kVendorUnknown,
uint32_t platform = kPlatformUnknown,
uint32_t abi = kAbiUnknown,
uint32_t format = kFormatUnknown) noexcept {
init(arch, subArch, vendor, platform, abi, format);
}
//! \}
//! \name Overloaded Operators
//! \{
inline Environment& operator=(const Environment& other) noexcept = default;
inline bool operator==(const Environment& other) const noexcept { return equals(other); }
inline bool operator!=(const Environment& other) const noexcept { return !equals(other); }
//! \}
//! \name Accessors
//! \{
//! Tests whether the environment is not set up.
//!
//! Returns true if all members are zero, and thus unknown.
inline bool empty() const noexcept {
// Unfortunately compilers won't optimize fields are checked one by one...
return _packed() == 0;
}
//! Tests whether the environment is intialized, which means it must have
//! a valid architecture.
inline bool isInitialized() const noexcept {
return _arch != kArchUnknown;
}
inline uint64_t _packed() const noexcept {
uint64_t x;
memcpy(&x, this, 8);
return x;
}
//! Resets all members of the environment to zero / unknown.
inline void reset() noexcept {
_arch = uint8_t(kArchUnknown);
_subArch = uint8_t(kSubArchUnknown);
_vendor = uint8_t(kVendorUnknown);
_platform = uint8_t(kPlatformUnknown);
_abi = uint8_t(kAbiUnknown);
_format = uint8_t(kFormatUnknown);
_reserved = 0;
}
inline bool equals(const Environment& other) const noexcept {
return _packed() == other._packed();
}
//! Returns the architecture, see \ref Arch.
inline uint32_t arch() const noexcept { return _arch; }
//! Returns the sub-architecture, see \ref SubArch.
inline uint32_t subArch() const noexcept { return _subArch; }
//! Returns vendor, see \ref Vendor.
inline uint32_t vendor() const noexcept { return _vendor; }
//! Returns target's platform or operating system, see \ref Platform.
inline uint32_t platform() const noexcept { return _platform; }
//! Returns target's ABI, see \ref Abi.
inline uint32_t abi() const noexcept { return _abi; }
//! Returns target's object format, see \ref Format.
inline uint32_t format() const noexcept { return _format; }
inline void init(uint32_t arch,
uint32_t subArch = kSubArchUnknown,
uint32_t vendor = kVendorUnknown,
uint32_t platform = kPlatformUnknown,
uint32_t abi = kAbiUnknown,
uint32_t format = kFormatUnknown) noexcept {
_arch = uint8_t(arch);
_subArch = uint8_t(subArch);
_vendor = uint8_t(vendor);
_platform = uint8_t(platform);
_abi = uint8_t(abi);
_format = uint8_t(format);
_reserved = 0;
}
inline bool isArchX86() const noexcept { return _arch == kArchX86; }
inline bool isArchX64() const noexcept { return _arch == kArchX64; }
inline bool isArchRISCV32() const noexcept { return _arch == kArchRISCV32; }
inline bool isArchRISCV64() const noexcept { return _arch == kArchRISCV64; }
inline bool isArchARM() const noexcept { return (_arch & ~kArchBigEndianMask) == kArchARM; }
inline bool isArchThumb() const noexcept { return (_arch & ~kArchBigEndianMask) == kArchThumb; }
inline bool isArchAArch64() const noexcept { return (_arch & ~kArchBigEndianMask) == kArchAArch64; }
inline bool isArchMIPS32() const noexcept { return (_arch & ~kArchBigEndianMask) == kArchMIPS32_LE; }
inline bool isArchMIPS64() const noexcept { return (_arch & ~kArchBigEndianMask) == kArchMIPS64_LE; }
//! Tests whether the architecture is 32-bit.
inline bool is32Bit() const noexcept { return is32Bit(_arch); }
//! Tests whether the architecture is 64-bit.
inline bool is64Bit() const noexcept { return is64Bit(_arch); }
//! Tests whether the architecture is little endian.
inline bool isLittleEndian() const noexcept { return isLittleEndian(_arch); }
//! Tests whether the architecture is big endian.
inline bool isBigEndian() const noexcept { return isBigEndian(_arch); }
//! Tests whether this architecture is of X86 family.
inline bool isFamilyX86() const noexcept { return isFamilyX86(_arch); }
//! Tests whether this architecture family is RISC-V (both 32-bit and 64-bit).
inline bool isFamilyRISCV() const noexcept { return isFamilyRISCV(_arch); }
//! Tests whether this architecture family is ARM, Thumb, or AArch64.
inline bool isFamilyARM() const noexcept { return isFamilyARM(_arch); }
//! Tests whether this architecture family is MISP or MIPS64.
inline bool isFamilyMIPS() const noexcept { return isFamilyMIPS(_arch); }
//! Tests whether the environment platform is Windows.
inline bool isPlatformWindows() const noexcept { return _platform == kPlatformWindows; }
//! Tests whether the environment platform is Linux.
inline bool isPlatformLinux() const noexcept { return _platform == kPlatformLinux; }
//! Tests whether the environment platform is Hurd.
inline bool isPlatformHurd() const noexcept { return _platform == kPlatformHurd; }
//! Tests whether the environment platform is Haiku.
inline bool isPlatformHaiku() const noexcept { return _platform == kPlatformHaiku; }
//! Tests whether the environment platform is any BSD.
inline bool isPlatformBSD() const noexcept {
return _platform == kPlatformFreeBSD ||
_platform == kPlatformOpenBSD ||
_platform == kPlatformNetBSD ||
_platform == kPlatformDragonFlyBSD;
}
//! Tests whether the environment platform is any Apple platform (OSX, iOS, TVOS, WatchOS).
inline bool isPlatformApple() const noexcept {
return _platform == kPlatformOSX ||
_platform == kPlatformIOS ||
_platform == kPlatformTVOS ||
_platform == kPlatformWatchOS;
}
//! Tests whether the ABI is MSVC.
inline bool isAbiMSVC() const noexcept { return _abi == kAbiMSVC; }
//! Tests whether the ABI is GNU.
inline bool isAbiGNU() const noexcept { return _abi == kAbiGNU; }
//! Returns a calculated stack alignment for this environment.
ASMJIT_API uint32_t stackAlignment() const noexcept;
//! Returns a native register size of this architecture.
uint32_t registerSize() const noexcept { return registerSizeFromArch(_arch); }
//! Sets the architecture to `arch`.
inline void setArch(uint32_t arch) noexcept { _arch = uint8_t(arch); }
//! Sets the sub-architecture to `subArch`.
inline void setSubArch(uint32_t subArch) noexcept { _subArch = uint8_t(subArch); }
//! Sets the vendor to `vendor`.
inline void setVendor(uint32_t vendor) noexcept { _vendor = uint8_t(vendor); }
//! Sets the platform to `platform`.
inline void setPlatform(uint32_t platform) noexcept { _platform = uint8_t(platform); }
//! Sets the ABI to `abi`.
inline void setAbi(uint32_t abi) noexcept { _abi = uint8_t(abi); }
//! Sets the object format to `format`.
inline void setFormat(uint32_t format) noexcept { _format = uint8_t(format); }
//! \}
//! \name Static Utilities
//! \{
static inline bool isValidArch(uint32_t arch) noexcept {
return (arch & ~kArchBigEndianMask) != 0 &&
(arch & ~kArchBigEndianMask) < kArchCount;
}
//! Tests whether the given architecture `arch` is 32-bit.
static inline bool is32Bit(uint32_t arch) noexcept {
return (arch & kArch32BitMask) == kArch32BitMask;
}
//! Tests whether the given architecture `arch` is 64-bit.
static inline bool is64Bit(uint32_t arch) noexcept {
return (arch & kArch32BitMask) == 0;
}
//! Tests whether the given architecture `arch` is little endian.
static inline bool isLittleEndian(uint32_t arch) noexcept {
return (arch & kArchBigEndianMask) == 0;
}
//! Tests whether the given architecture `arch` is big endian.
static inline bool isBigEndian(uint32_t arch) noexcept {
return (arch & kArchBigEndianMask) == kArchBigEndianMask;
}
//! Tests whether the given architecture is AArch64.
static inline bool isArchAArch64(uint32_t arch) noexcept {
arch &= ~kArchBigEndianMask;
return arch == kArchAArch64;
}
//! Tests whether the given architecture family is X86 or X64.
static inline bool isFamilyX86(uint32_t arch) noexcept {
return arch == kArchX86 ||
arch == kArchX64;
}
//! Tests whether the given architecture family is RISC-V (both 32-bit and 64-bit).
static inline bool isFamilyRISCV(uint32_t arch) noexcept {
return arch == kArchRISCV32 ||
arch == kArchRISCV64;
}
//! Tests whether the given architecture family is ARM, Thumb, or AArch64.
static inline bool isFamilyARM(uint32_t arch) noexcept {
arch &= ~kArchBigEndianMask;
return arch == kArchARM ||
arch == kArchAArch64 ||
arch == kArchThumb;
}
//! Tests whether the given architecture family is MISP or MIPS64.
static inline bool isFamilyMIPS(uint32_t arch) noexcept {
arch &= ~kArchBigEndianMask;
return arch == kArchMIPS32_LE ||
arch == kArchMIPS64_LE;
}
//! Returns a native general purpose register size from the given architecture.
static uint32_t registerSizeFromArch(uint32_t arch) noexcept {
return is32Bit(arch) ? 4u : 8u;
}
//! \}
};
//! Returns the host environment constructed from preprocessor macros defined
//! by the compiler.
//!
//! The returned environment should precisely match the target host architecture,
//! sub-architecture, platform, and ABI.
static ASMJIT_INLINE Environment hostEnvironment() noexcept {
return Environment(Environment::kArchHost,
Environment::kSubArchHost,
Environment::kVendorHost,
Environment::kPlatformHost,
Environment::kAbiHost,
Environment::kFormatUnknown);
}
static_assert(sizeof(Environment) == 8,
"Environment must occupy exactly 8 bytes.");
//! \}
#ifndef ASMJIT_NO_DEPRECATED
class ASMJIT_DEPRECATED_STRUCT("Use Environment instead") ArchInfo : public Environment {
public:
inline ArchInfo() noexcept : Environment() {}
inline ArchInfo(const Environment& other) noexcept : Environment(other) {}
inline explicit ArchInfo(uint32_t arch, uint32_t subArch = kSubArchUnknown) noexcept
: Environment(arch, subArch) {}
enum Id : uint32_t {
kIdNone = Environment::kArchUnknown,
kIdX86 = Environment::kArchX86,
kIdX64 = Environment::kArchX64,
kIdA32 = Environment::kArchARM,
kIdA64 = Environment::kArchAArch64,
kIdHost = Environment::kArchHost
};
enum SubType : uint32_t {
kSubIdNone = Environment::kSubArchUnknown
};
static inline ArchInfo host() noexcept { return ArchInfo(hostEnvironment()); }
};
#endif // !ASMJIT_NO_DEPRECATED
ASMJIT_END_NAMESPACE
#endif // ASMJIT_CORE_ENVIRONMENT_H_INCLUDED