/** * 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-2023 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.location; 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;