blob: eb85c676a4b5dda29a63c81240e7f1c1f724f1eb [file] [log] [blame]
/**
* Handles target-specific parameters
*
* In order to allow for cross compilation, when the compiler produces a binary
* for a different platform than it is running on, target information needs
* to be abstracted. This is done in this module, primarily through `Target`.
*
* Note:
* While DMD itself does not support cross-compilation, GDC and LDC do.
* Hence, this module is (sometimes heavily) modified by them,
* and contributors should review how their changes affect them.
*
* See_Also:
* - $(LINK2 https://wiki.osdev.org/Target_Triplet, Target Triplets)
* - $(LINK2 https://github.com/ldc-developers/ldc, LDC repository)
* - $(LINK2 https://github.com/D-Programming-GDC/gcc, GDC repository)
*
* Copyright: Copyright (C) 1999-2022 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
* Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/target.d, _target.d)
* Documentation: https://dlang.org/phobos/dmd_target.html
* Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/target.d
*/
module dmd.target;
import dmd.globals : Param;
enum CPU : ubyte
{
x87,
mmx,
sse,
sse2,
sse3,
ssse3,
sse4_1,
sse4_2,
avx, // AVX1 instruction set
avx2, // AVX2 instruction set
avx512, // AVX-512 instruction set
// Special values that don't survive past the command line processing
baseline, // (default) the minimum capability CPU
native // the machine the compiler is being run on
}
////////////////////////////////////////////////////////////////////////////////
/**
* Describes a back-end target. At present it is incomplete, but in the future
* it should grow to contain most or all target machine and target O/S specific
* information.
*
* In many cases, calls to sizeof() can't be used directly for getting data type
* sizes since cross compiling is supported and would end up using the host
* sizes rather than the target sizes.
*/
extern (C++) struct Target
{
import dmd.dscope : Scope;
import dmd.expression : Expression;
import dmd.func : FuncDeclaration;
import dmd.globals : Loc;
import dmd.astenums : LINK, TY;
import dmd.mtype : Type, TypeFunction, TypeTuple;
import dmd.root.ctfloat : real_t;
import dmd.statement : Statement;
import dmd.tokens : EXP;
/// Bit decoding of the Target.OS
enum OS : ubyte
{
/* These are mutually exclusive; one and only one is set.
* Match spelling and casing of corresponding version identifiers
*/
none = 0,
linux = 1,
Windows = 2,
OSX = 4,
OpenBSD = 8,
FreeBSD = 0x10,
Solaris = 0x20,
DragonFlyBSD = 0x40,
// Combination masks
all = linux | Windows | OSX | OpenBSD | FreeBSD | Solaris | DragonFlyBSD,
Posix = linux | OSX | OpenBSD | FreeBSD | Solaris | DragonFlyBSD,
}
OS os;
ubyte osMajor;
// D ABI
ubyte ptrsize; /// size of a pointer in bytes
ubyte realsize; /// size a real consumes in memory
ubyte realpad; /// padding added to the CPU real size to bring it up to realsize
ubyte realalignsize; /// alignment for reals
ubyte classinfosize; /// size of `ClassInfo`
ulong maxStaticDataSize; /// maximum size of static data
/// C ABI
TargetC c;
/// C++ ABI
TargetCPP cpp;
/// Objective-C ABI
TargetObjC objc;
/// Architecture name
const(char)[] architectureName;
CPU cpu = CPU.baseline; // CPU instruction set to target
bool is64bit; // generate 64 bit code for x86_64; true by default for 64 bit dmd
bool isLP64; // pointers are 64 bits
// Environmental
const(char)[] obj_ext; /// extension for object files
const(char)[] lib_ext; /// extension for static library files
const(char)[] dll_ext; /// extension for dynamic library files
bool run_noext; /// allow -run sources without extensions
bool omfobj = false; // for Win32: write OMF object files instead of MsCoff
/**
* Values representing all properties for floating point types
*/
extern (C++) struct FPTypeProperties(T)
{
real_t max; /// largest representable value that's not infinity
real_t min_normal; /// smallest representable normalized value that's not 0
real_t nan; /// NaN value
real_t infinity; /// infinity value
real_t epsilon; /// smallest increment to the value 1
long dig; /// number of decimal digits of precision
long mant_dig; /// number of bits in mantissa
long max_exp; /// maximum int value such that 2$(SUPERSCRIPT `max_exp-1`) is representable
long min_exp; /// minimum int value such that 2$(SUPERSCRIPT `min_exp-1`) is representable as a normalized value
long max_10_exp; /// maximum int value such that 10$(SUPERSCRIPT `max_10_exp` is representable)
long min_10_exp; /// minimum int value such that 10$(SUPERSCRIPT `min_10_exp`) is representable as a normalized value
}
FPTypeProperties!float FloatProperties; ///
FPTypeProperties!double DoubleProperties; ///
FPTypeProperties!real_t RealProperties; ///
private Type tvalist; // cached lazy result of va_listType()
private const(Param)* params; // cached reference to global.params
/**
* Initialize the Target
*/
extern (C++) void _init(ref const Param params);
/**
* Deinitializes the global state of the compiler.
*
* This can be used to restore the state set by `_init` to its original
* state.
*/
void deinitialize()
{
this = this.init;
}
/**
* Requested target memory alignment size of the given type.
* Params:
* type = type to inspect
* Returns:
* alignment in bytes
*/
extern (C++) uint alignsize(Type type);
/**
* Requested target field alignment size of the given type.
* Params:
* type = type to inspect
* Returns:
* alignment in bytes
*/
extern (C++) uint fieldalign(Type type);
/**
* Type for the `va_list` type for the target; e.g., required for `_argptr`
* declarations.
* NOTE: For Posix/x86_64 this returns the type which will really
* be used for passing an argument of type va_list.
* Returns:
* `Type` that represents `va_list`.
*/
extern (C++) Type va_listType(const ref Loc loc, Scope* sc);
/**
* Checks whether the target supports a vector type.
* Params:
* sz = vector type size in bytes
* type = vector element type
* Returns:
* 0 vector type is supported,
* 1 vector type is not supported on the target at all
* 2 vector element type is not supported
* 3 vector size is not supported
*/
extern (C++) int isVectorTypeSupported(int sz, Type type);
/**
* Checks whether the target supports the given operation for vectors.
* Params:
* type = target type of operation
* op = the unary or binary op being done on the `type`
* t2 = type of second operand if `op` is a binary operation
* Returns:
* true if the operation is supported or type is not a vector
*/
extern (C++) bool isVectorOpSupported(Type type, EXP op, Type t2 = null);
/**
* Default system linkage for the target.
* Returns:
* `LINK` to use for `extern(System)`
*/
extern (C++) LINK systemLinkage();
/**
* Describes how an argument type is passed to a function on target.
* Params:
* t = type to break down
* Returns:
* tuple of types if type is passed in one or more registers
* empty tuple if type is always passed on the stack
* null if the type is a `void` or argtypes aren't supported by the target
*/
extern (C++) TypeTuple toArgTypes(Type t);
/**
* Determine return style of function - whether in registers or
* through a hidden pointer to the caller's stack.
* Params:
* tf = function type to check
* needsThis = true if the function type is for a non-static member function
* Returns:
* true if return value from function is on the stack
*/
extern (C++) bool isReturnOnStack(TypeFunction tf, bool needsThis);
/**
* Decides whether an `in` parameter of the specified POD type is to be
* passed by reference or by value. To be used with `-preview=in` only!
* Params:
* t = type of the `in` parameter, must be a POD
* Returns:
* `true` if the `in` parameter is to be passed by reference
*/
extern(C++) bool preferPassByRef(Type t);
/**
* Get targetInfo by key
* Params:
* name = name of targetInfo to get
* loc = location to use for error messages
* Returns:
* Expression for the requested targetInfo
*/
extern (C++) Expression getTargetInfo(const(char)* name, const ref Loc loc);
/**
* Params:
* tf = type of function being called
* Returns: `true` if the callee invokes destructors for arguments.
*/
extern (C++) bool isCalleeDestroyingArgs(TypeFunction tf);
/**
* Returns true if the implementation for object monitors is always defined
* in the D runtime library (rt/monitor_.d).
* Params:
* fd = function with `synchronized` storage class.
* fbody = entire function body of `fd`
* Returns:
* `false` if the target backend handles synchronizing monitors.
*/
extern (C++) bool libraryObjectMonitors(FuncDeclaration fd, Statement fbody);
/**
* Returns true if the target supports `pragma(linkerDirective)`.
* Returns:
* `false` if the target does not support `pragma(linkerDirective)`.
*/
extern (C++) bool supportsLinkerDirective() const;
}
////////////////////////////////////////////////////////////////////////////////
/**
* Functions and variables specific to interfacing with extern(C) ABI.
*/
struct TargetC
{
enum Runtime : ubyte
{
Unspecified,
Bionic,
DigitalMars,
Glibc,
Microsoft,
Musl,
Newlib,
UClibc,
WASI,
}
enum BitFieldStyle : ubyte
{
Unspecified,
DM, /// Digital Mars 32 bit C compiler
MS, /// Microsoft 32 and 64 bit C compilers
/// https://docs.microsoft.com/en-us/cpp/c-language/c-bit-fields?view=msvc-160
/// https://docs.microsoft.com/en-us/cpp/cpp/cpp-bit-fields?view=msvc-160
Gcc_Clang, /// gcc and clang
}
bool crtDestructorsSupported = true; /// Not all platforms support crt_destructor
ubyte boolsize; /// size of a C `_Bool` type
ubyte shortsize; /// size of a C `short` or `unsigned short` type
ubyte intsize; /// size of a C `int` or `unsigned int` type
ubyte longsize; /// size of a C `long` or `unsigned long` type
ubyte long_longsize; /// size of a C `long long` or `unsigned long long` type
ubyte long_doublesize; /// size of a C `long double`
ubyte wchar_tsize; /// size of a C `wchar_t` type
Runtime runtime; /// vendor of the C runtime to link against
BitFieldStyle bitFieldStyle; /// different C compilers do it differently
}
////////////////////////////////////////////////////////////////////////////////
/**
* Functions and variables specific to interface with extern(C++) ABI.
*/
struct TargetCPP
{
import dmd.dsymbol : Dsymbol;
import dmd.dclass : ClassDeclaration;
import dmd.func : FuncDeclaration;
import dmd.mtype : Type;
enum Runtime : ubyte
{
Unspecified,
Clang,
DigitalMars,
Gcc,
Microsoft,
Sun
}
bool reverseOverloads; /// set if overloaded functions are grouped and in reverse order (such as in dmc and cl)
bool exceptions; /// set if catching C++ exceptions is supported
bool twoDtorInVtable; /// target C++ ABI puts deleting and non-deleting destructor into vtable
bool splitVBasetable; /// set if C++ ABI uses separate tables for virtual functions and virtual bases
bool wrapDtorInExternD; /// set if C++ dtors require a D wrapper to be callable from runtime
Runtime runtime; /// vendor of the C++ runtime to link against
/**
* Mangle the given symbol for C++ ABI.
* Params:
* s = declaration with C++ linkage
* Returns:
* string mangling of symbol
*/
extern (C++) const(char)* toMangle(Dsymbol s);
/**
* Get RTTI mangling of the given class declaration for C++ ABI.
* Params:
* cd = class with C++ linkage
* Returns:
* string mangling of C++ typeinfo
*/
extern (C++) const(char)* typeInfoMangle(ClassDeclaration cd);
/**
* Get mangle name of a this-adjusting thunk to the given function
* declaration for C++ ABI.
* Params:
* fd = function with C++ linkage
* offset = call offset to the vptr
* Returns:
* string mangling of C++ thunk, or null if unhandled
*/
extern (C++) const(char)* thunkMangle(FuncDeclaration fd, int offset);
/**
* Gets vendor-specific type mangling for C++ ABI.
* Params:
* t = type to inspect
* Returns:
* string if type is mangled specially on target
* null if unhandled
*/
extern (C++) const(char)* typeMangle(Type t);
/**
* Get the type that will really be used for passing the given argument
* to an `extern(C++)` function, or `null` if unhandled.
* Params:
* t = type to be passed.
* Returns:
* `Type` to use for type `t`.
*/
extern (C++) Type parameterType(Type t);
/**
* Checks whether type is a vendor-specific fundamental type.
* Params:
* t = type to inspect
* isFundamental = where to store result
* Returns:
* true if isFundamental was set by function
*/
extern (C++) bool fundamentalType(const Type t, ref bool isFundamental);
/**
* Get the starting offset position for fields of an `extern(C++)` class
* that is derived from the given base class.
* Params:
* baseClass = base class with C++ linkage
* Returns:
* starting offset to lay out derived class fields
*/
extern (C++) uint derivedClassOffset(ClassDeclaration baseClass);
}
////////////////////////////////////////////////////////////////////////////////
/**
* Functions and variables specific to interface with extern(Objective-C) ABI.
*/
struct TargetObjC
{
bool supported; /// set if compiler can interface with Objective-C
}
////////////////////////////////////////////////////////////////////////////////
extern (C++) __gshared Target target;