1/**
2 * Handles target-specific parameters
3 *
4 * In order to allow for cross compilation, when the compiler produces a binary
5 * for a different platform than it is running on, target information needs
6 * to be abstracted. This is done in this module, primarily through `Target`.
7 *
8 * Note:
9 * While DMD itself does not support cross-compilation, GDC and LDC do.
10 * Hence, this module is (sometimes heavily) modified by them,
11 * and contributors should review how their changes affect them.
12 *
13 * See_Also:
14 * - $(LINK2 https://wiki.osdev.org/Target_Triplet, Target Triplets)
15 * - $(LINK2 https://github.com/ldc-developers/ldc, LDC repository)
16 * - $(LINK2 https://github.com/D-Programming-GDC/gcc, GDC repository)
17 *
18 * Copyright:   Copyright (C) 1999-2022 by The D Language Foundation, All Rights Reserved
19 * Authors:     $(LINK2 https://www.digitalmars.com, Walter Bright)
20 * License:     $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
21 * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/target.d, _target.d)
22 * Documentation:  https://dlang.org/phobos/dmd_target.html
23 * Coverage:    https://codecov.io/gh/dlang/dmd/src/master/src/dmd/target.d
24 */
25
26module dmd.target;
27
28import dmd.globals : Param;
29
30enum CPU : ubyte
31{
32    x87,
33    mmx,
34    sse,
35    sse2,
36    sse3,
37    ssse3,
38    sse4_1,
39    sse4_2,
40    avx,                // AVX1 instruction set
41    avx2,               // AVX2 instruction set
42    avx512,             // AVX-512 instruction set
43
44    // Special values that don't survive past the command line processing
45    baseline,           // (default) the minimum capability CPU
46    native              // the machine the compiler is being run on
47}
48
49////////////////////////////////////////////////////////////////////////////////
50/**
51 * Describes a back-end target. At present it is incomplete, but in the future
52 * it should grow to contain most or all target machine and target O/S specific
53 * information.
54 *
55 * In many cases, calls to sizeof() can't be used directly for getting data type
56 * sizes since cross compiling is supported and would end up using the host
57 * sizes rather than the target sizes.
58 */
59extern (C++) struct Target
60{
61    import dmd.dscope : Scope;
62    import dmd.expression : Expression;
63    import dmd.func : FuncDeclaration;
64    import dmd.globals : Loc;
65    import dmd.astenums : LINK, TY;
66    import dmd.mtype : Type, TypeFunction, TypeTuple;
67    import dmd.root.ctfloat : real_t;
68    import dmd.statement : Statement;
69    import dmd.tokens : EXP;
70
71    /// Bit decoding of the Target.OS
72    enum OS : ubyte
73    {
74        /* These are mutually exclusive; one and only one is set.
75         * Match spelling and casing of corresponding version identifiers
76         */
77        none         = 0,
78        linux        = 1,
79        Windows      = 2,
80        OSX          = 4,
81        OpenBSD      = 8,
82        FreeBSD      = 0x10,
83        Solaris      = 0x20,
84        DragonFlyBSD = 0x40,
85
86        // Combination masks
87        all = linux | Windows | OSX | OpenBSD | FreeBSD | Solaris | DragonFlyBSD,
88        Posix = linux | OSX | OpenBSD | FreeBSD | Solaris | DragonFlyBSD,
89    }
90
91    OS os;
92    ubyte osMajor;
93
94    // D ABI
95    ubyte ptrsize;            /// size of a pointer in bytes
96    ubyte realsize;           /// size a real consumes in memory
97    ubyte realpad;            /// padding added to the CPU real size to bring it up to realsize
98    ubyte realalignsize;      /// alignment for reals
99    ubyte classinfosize;      /// size of `ClassInfo`
100    ulong maxStaticDataSize;  /// maximum size of static data
101
102    /// C ABI
103    TargetC c;
104
105    /// C++ ABI
106    TargetCPP cpp;
107
108    /// Objective-C ABI
109    TargetObjC objc;
110
111    /// Architecture name
112    const(char)[] architectureName;
113    CPU cpu = CPU.baseline; // CPU instruction set to target
114    bool is64bit;           // generate 64 bit code for x86_64; true by default for 64 bit dmd
115    bool isLP64;            // pointers are 64 bits
116
117    // Environmental
118    const(char)[] obj_ext;    /// extension for object files
119    const(char)[] lib_ext;    /// extension for static library files
120    const(char)[] dll_ext;    /// extension for dynamic library files
121    bool run_noext;           /// allow -run sources without extensions
122    bool omfobj = false;      // for Win32: write OMF object files instead of MsCoff
123    /**
124     * Values representing all properties for floating point types
125     */
126    extern (C++) struct FPTypeProperties(T)
127    {
128        real_t max;         /// largest representable value that's not infinity
129        real_t min_normal;  /// smallest representable normalized value that's not 0
130        real_t nan;         /// NaN value
131        real_t infinity;    /// infinity value
132        real_t epsilon;     /// smallest increment to the value 1
133
134        long dig;           /// number of decimal digits of precision
135        long mant_dig;      /// number of bits in mantissa
136        long max_exp;       /// maximum int value such that 2$(SUPERSCRIPT `max_exp-1`) is representable
137        long min_exp;       /// minimum int value such that 2$(SUPERSCRIPT `min_exp-1`) is representable as a normalized value
138        long max_10_exp;    /// maximum int value such that 10$(SUPERSCRIPT `max_10_exp` is representable)
139        long min_10_exp;    /// minimum int value such that 10$(SUPERSCRIPT `min_10_exp`) is representable as a normalized value
140    }
141
142    FPTypeProperties!float FloatProperties;     ///
143    FPTypeProperties!double DoubleProperties;   ///
144    FPTypeProperties!real_t RealProperties;     ///
145
146    private Type tvalist; // cached lazy result of va_listType()
147
148    private const(Param)* params;  // cached reference to global.params
149
150    /**
151     * Initialize the Target
152     */
153    extern (C++) void _init(ref const Param params);
154
155
156    /**
157     * Deinitializes the global state of the compiler.
158     *
159     * This can be used to restore the state set by `_init` to its original
160     * state.
161     */
162    void deinitialize()
163    {
164        this = this.init;
165    }
166
167    /**
168     * Requested target memory alignment size of the given type.
169     * Params:
170     *      type = type to inspect
171     * Returns:
172     *      alignment in bytes
173     */
174    extern (C++) uint alignsize(Type type);
175
176    /**
177     * Requested target field alignment size of the given type.
178     * Params:
179     *      type = type to inspect
180     * Returns:
181     *      alignment in bytes
182     */
183    extern (C++) uint fieldalign(Type type);
184
185    /**
186     * Type for the `va_list` type for the target; e.g., required for `_argptr`
187     * declarations.
188     * NOTE: For Posix/x86_64 this returns the type which will really
189     * be used for passing an argument of type va_list.
190     * Returns:
191     *      `Type` that represents `va_list`.
192     */
193    extern (C++) Type va_listType(const ref Loc loc, Scope* sc);
194
195    /**
196     * Checks whether the target supports a vector type.
197     * Params:
198     *      sz   = vector type size in bytes
199     *      type = vector element type
200     * Returns:
201     *      0   vector type is supported,
202     *      1   vector type is not supported on the target at all
203     *      2   vector element type is not supported
204     *      3   vector size is not supported
205     */
206    extern (C++) int isVectorTypeSupported(int sz, Type type);
207
208    /**
209     * Checks whether the target supports the given operation for vectors.
210     * Params:
211     *      type = target type of operation
212     *      op   = the unary or binary op being done on the `type`
213     *      t2   = type of second operand if `op` is a binary operation
214     * Returns:
215     *      true if the operation is supported or type is not a vector
216     */
217    extern (C++) bool isVectorOpSupported(Type type, EXP op, Type t2 = null);
218
219    /**
220     * Default system linkage for the target.
221     * Returns:
222     *      `LINK` to use for `extern(System)`
223     */
224    extern (C++) LINK systemLinkage();
225
226    /**
227     * Describes how an argument type is passed to a function on target.
228     * Params:
229     *      t = type to break down
230     * Returns:
231     *      tuple of types if type is passed in one or more registers
232     *      empty tuple if type is always passed on the stack
233     *      null if the type is a `void` or argtypes aren't supported by the target
234     */
235    extern (C++) TypeTuple toArgTypes(Type t);
236
237    /**
238     * Determine return style of function - whether in registers or
239     * through a hidden pointer to the caller's stack.
240     * Params:
241     *   tf = function type to check
242     *   needsThis = true if the function type is for a non-static member function
243     * Returns:
244     *   true if return value from function is on the stack
245     */
246    extern (C++) bool isReturnOnStack(TypeFunction tf, bool needsThis);
247
248    /**
249     * Decides whether an `in` parameter of the specified POD type is to be
250     * passed by reference or by value. To be used with `-preview=in` only!
251     * Params:
252     *  t = type of the `in` parameter, must be a POD
253     * Returns:
254     *  `true` if the `in` parameter is to be passed by reference
255     */
256    extern(C++) bool preferPassByRef(Type t);
257
258    /**
259     * Get targetInfo by key
260     * Params:
261     *  name = name of targetInfo to get
262     *  loc = location to use for error messages
263     * Returns:
264     *  Expression for the requested targetInfo
265     */
266    extern (C++) Expression getTargetInfo(const(char)* name, const ref Loc loc);
267
268    /**
269     * Params:
270     *  tf = type of function being called
271     * Returns: `true` if the callee invokes destructors for arguments.
272     */
273    extern (C++) bool isCalleeDestroyingArgs(TypeFunction tf);
274
275    /**
276     * Returns true if the implementation for object monitors is always defined
277     * in the D runtime library (rt/monitor_.d).
278     * Params:
279     *      fd = function with `synchronized` storage class.
280     *      fbody = entire function body of `fd`
281     * Returns:
282     *      `false` if the target backend handles synchronizing monitors.
283     */
284    extern (C++) bool libraryObjectMonitors(FuncDeclaration fd, Statement fbody);
285
286    /**
287     * Returns true if the target supports `pragma(linkerDirective)`.
288     * Returns:
289     *      `false` if the target does not support `pragma(linkerDirective)`.
290     */
291    extern (C++) bool supportsLinkerDirective() const;
292}
293
294////////////////////////////////////////////////////////////////////////////////
295/**
296 * Functions and variables specific to interfacing with extern(C) ABI.
297 */
298struct TargetC
299{
300    enum Runtime : ubyte
301    {
302        Unspecified,
303        Bionic,
304        DigitalMars,
305        Glibc,
306        Microsoft,
307        Musl,
308        Newlib,
309        UClibc,
310        WASI,
311    }
312
313    enum BitFieldStyle : ubyte
314    {
315        Unspecified,
316        DM,                   /// Digital Mars 32 bit C compiler
317        MS,                   /// Microsoft 32 and 64 bit C compilers
318                              /// https://docs.microsoft.com/en-us/cpp/c-language/c-bit-fields?view=msvc-160
319                              /// https://docs.microsoft.com/en-us/cpp/cpp/cpp-bit-fields?view=msvc-160
320        Gcc_Clang,            /// gcc and clang
321    }
322    bool  crtDestructorsSupported = true; /// Not all platforms support crt_destructor
323    ubyte boolsize;           /// size of a C `_Bool` type
324    ubyte shortsize;          /// size of a C `short` or `unsigned short` type
325    ubyte intsize;            /// size of a C `int` or `unsigned int` type
326    ubyte longsize;           /// size of a C `long` or `unsigned long` type
327    ubyte long_longsize;      /// size of a C `long long` or `unsigned long long` type
328    ubyte long_doublesize;    /// size of a C `long double`
329    ubyte wchar_tsize;        /// size of a C `wchar_t` type
330    Runtime runtime;          /// vendor of the C runtime to link against
331    BitFieldStyle bitFieldStyle; /// different C compilers do it differently
332}
333
334////////////////////////////////////////////////////////////////////////////////
335/**
336 * Functions and variables specific to interface with extern(C++) ABI.
337 */
338struct TargetCPP
339{
340    import dmd.dsymbol : Dsymbol;
341    import dmd.dclass : ClassDeclaration;
342    import dmd.func : FuncDeclaration;
343    import dmd.mtype : Type;
344
345    enum Runtime : ubyte
346    {
347        Unspecified,
348        Clang,
349        DigitalMars,
350        Gcc,
351        Microsoft,
352        Sun
353    }
354    bool reverseOverloads;    /// set if overloaded functions are grouped and in reverse order (such as in dmc and cl)
355    bool exceptions;          /// set if catching C++ exceptions is supported
356    bool twoDtorInVtable;     /// target C++ ABI puts deleting and non-deleting destructor into vtable
357    bool splitVBasetable;     /// set if C++ ABI uses separate tables for virtual functions and virtual bases
358    bool wrapDtorInExternD;   /// set if C++ dtors require a D wrapper to be callable from runtime
359    Runtime runtime;          /// vendor of the C++ runtime to link against
360
361    /**
362     * Mangle the given symbol for C++ ABI.
363     * Params:
364     *      s = declaration with C++ linkage
365     * Returns:
366     *      string mangling of symbol
367     */
368    extern (C++) const(char)* toMangle(Dsymbol s);
369
370    /**
371     * Get RTTI mangling of the given class declaration for C++ ABI.
372     * Params:
373     *      cd = class with C++ linkage
374     * Returns:
375     *      string mangling of C++ typeinfo
376     */
377    extern (C++) const(char)* typeInfoMangle(ClassDeclaration cd);
378
379    /**
380     * Get mangle name of a this-adjusting thunk to the given function
381     * declaration for C++ ABI.
382     * Params:
383     *      fd = function with C++ linkage
384     *      offset = call offset to the vptr
385     * Returns:
386     *      string mangling of C++ thunk, or null if unhandled
387     */
388    extern (C++) const(char)* thunkMangle(FuncDeclaration fd, int offset);
389
390    /**
391     * Gets vendor-specific type mangling for C++ ABI.
392     * Params:
393     *      t = type to inspect
394     * Returns:
395     *      string if type is mangled specially on target
396     *      null if unhandled
397     */
398    extern (C++) const(char)* typeMangle(Type t);
399
400    /**
401     * Get the type that will really be used for passing the given argument
402     * to an `extern(C++)` function, or `null` if unhandled.
403     * Params:
404     *      t = type to be passed.
405     * Returns:
406     *      `Type` to use for type `t`.
407     */
408    extern (C++) Type parameterType(Type t);
409
410    /**
411     * Checks whether type is a vendor-specific fundamental type.
412     * Params:
413     *      t = type to inspect
414     *      isFundamental = where to store result
415     * Returns:
416     *      true if isFundamental was set by function
417     */
418    extern (C++) bool fundamentalType(const Type t, ref bool isFundamental);
419
420    /**
421     * Get the starting offset position for fields of an `extern(C++)` class
422     * that is derived from the given base class.
423     * Params:
424     *      baseClass = base class with C++ linkage
425     * Returns:
426     *      starting offset to lay out derived class fields
427     */
428    extern (C++) uint derivedClassOffset(ClassDeclaration baseClass);
429}
430
431////////////////////////////////////////////////////////////////////////////////
432/**
433 * Functions and variables specific to interface with extern(Objective-C) ABI.
434 */
435struct TargetObjC
436{
437    bool supported;     /// set if compiler can interface with Objective-C
438}
439
440////////////////////////////////////////////////////////////////////////////////
441extern (C++) __gshared Target target;
442