1 /**
2  * Compiler implementation of the
3  * $(LINK2 http://www.dlang.org, D programming language).
4  *
5  * Copyright:   Copyright (c) 1999-2016 by Digital Mars, All Rights Reserved
6  * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
7  * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
8  * Source:      $(DMDSRC _target.d)
9  */
10 
11 module ddmd.target;
12 
13 import ddmd.dmodule;
14 import ddmd.expression;
15 import ddmd.globals;
16 import ddmd.identifier;
17 import ddmd.mtype;
18 import ddmd.root.ctfloat;
19 import ddmd.root.outbuffer;
20 
21 /***********************************************************
22  */
23 struct Target
24 {
25     extern (C++) static __gshared int ptrsize;
26     extern (C++) static __gshared int realsize;             // size a real consumes in memory
27     extern (C++) static __gshared int realpad;              // 'padding' added to the CPU real size to bring it up to realsize
28     extern (C++) static __gshared int realalignsize;        // alignment for reals
29     extern (C++) static __gshared bool realislongdouble;    // distinguish between C 'long double' and '__float128'
30     extern (C++) static __gshared bool reverseCppOverloads; // with dmc and cl, overloaded functions are grouped and in reverse order
31     extern (C++) static __gshared bool cppExceptions;       // set if catching C++ exceptions is supported
32     extern (C++) static __gshared int c_longsize;           // size of a C 'long' or 'unsigned long' type
33     extern (C++) static __gshared int c_long_doublesize;    // size of a C 'long double'
34     extern (C++) static __gshared int classinfosize;        // size of 'ClassInfo'
35 
36     template FPTypeProperties(T)
37     {
38         enum : real_t
39         {
40             max = T.max,
41             min_normal = T.min_normal,
42             nan = T.nan,
43             snan = T.init,
44             infinity = T.infinity,
45             epsilon = T.epsilon
46         }
47 
48         enum : long
49         {
50             dig = T.dig,
51             mant_dig = T.mant_dig,
52             max_exp = T.max_exp,
53             min_exp = T.min_exp,
54             max_10_exp = T.max_10_exp,
55             min_10_exp = T.min_10_exp
56         }
57     }
58 
59     alias FloatProperties = FPTypeProperties!float;
60     alias DoubleProperties = FPTypeProperties!double;
61     alias RealProperties = FPTypeProperties!real;
62 
63     extern (C++) static void _init()
64     {
65         // These have default values for 32 bit code, they get
66         // adjusted for 64 bit code.
67         ptrsize = 4;
68         classinfosize = 0x4C; // 76
69         if (global.params.isLP64)
70         {
71             ptrsize = 8;
72             classinfosize = 0x98; // 152
73         }
74         if (global.params.isLinux || global.params.isFreeBSD || global.params.isOpenBSD || global.params.isSolaris)
75         {
76             realsize = 12;
77             realpad = 2;
78             realalignsize = 4;
79             c_longsize = 4;
80         }
81         else if (global.params.isOSX)
82         {
83             realsize = 16;
84             realpad = 6;
85             realalignsize = 16;
86             c_longsize = 4;
87         }
88         else if (global.params.isWindows)
89         {
90             realsize = 10;
91             realpad = 0;
92             realalignsize = 2;
93             reverseCppOverloads = true;
94             c_longsize = 4;
95         }
96         else
97             assert(0);
98         if (global.params.is64bit)
99         {
100             if (global.params.isLinux || global.params.isFreeBSD || global.params.isSolaris)
101             {
102                 realsize = 16;
103                 realpad = 6;
104                 realalignsize = 16;
105                 c_longsize = 8;
106             }
107             else if (global.params.isOSX)
108             {
109                 c_longsize = 8;
110             }
111         }
112         realislongdouble = true;
113         c_long_doublesize = realsize;
114         if (global.params.is64bit && global.params.isWindows)
115             c_long_doublesize = 8;
116 
117         cppExceptions = global.params.isLinux || global.params.isFreeBSD ||
118             global.params.isOSX;
119     }
120 
121     /******************************
122      * Return memory alignment size of type.
123      */
124     extern (C++) static uint alignsize(Type type)
125     {
126         assert(type.isTypeBasic());
127         switch (type.ty)
128         {
129         case Tfloat80:
130         case Timaginary80:
131         case Tcomplex80:
132             return Target.realalignsize;
133         case Tcomplex32:
134             if (global.params.isLinux || global.params.isOSX || global.params.isFreeBSD || global.params.isOpenBSD || global.params.isSolaris)
135                 return 4;
136             break;
137         case Tint64:
138         case Tuns64:
139         case Tfloat64:
140         case Timaginary64:
141         case Tcomplex64:
142             if (global.params.isLinux || global.params.isOSX || global.params.isFreeBSD || global.params.isOpenBSD || global.params.isSolaris)
143                 return global.params.is64bit ? 8 : 4;
144             break;
145         default:
146             break;
147         }
148         return cast(uint)type.size(Loc());
149     }
150 
151     /******************************
152      * Return field alignment size of type.
153      */
154     extern (C++) static uint fieldalign(Type type)
155     {
156         return type.alignsize();
157     }
158 
159     /***********************************
160      * Return size of OS critical section.
161      * NOTE: can't use the sizeof() calls directly since cross compiling is
162      * supported and would end up using the host sizes rather than the target
163      * sizes.
164      */
165     extern (C++) static uint critsecsize()
166     {
167         if (global.params.isWindows)
168         {
169             // sizeof(CRITICAL_SECTION) for Windows.
170             return global.params.isLP64 ? 40 : 24;
171         }
172         else if (global.params.isLinux)
173         {
174             // sizeof(pthread_mutex_t) for Linux.
175             if (global.params.is64bit)
176                 return global.params.isLP64 ? 40 : 32;
177             else
178                 return global.params.isLP64 ? 40 : 24;
179         }
180         else if (global.params.isFreeBSD)
181         {
182             // sizeof(pthread_mutex_t) for FreeBSD.
183             return global.params.isLP64 ? 8 : 4;
184         }
185         else if (global.params.isOpenBSD)
186         {
187             // sizeof(pthread_mutex_t) for OpenBSD.
188             return global.params.isLP64 ? 8 : 4;
189         }
190         else if (global.params.isOSX)
191         {
192             // sizeof(pthread_mutex_t) for OSX.
193             return global.params.isLP64 ? 64 : 44;
194         }
195         else if (global.params.isSolaris)
196         {
197             // sizeof(pthread_mutex_t) for Solaris.
198             return 24;
199         }
200         assert(0);
201     }
202 
203     /***********************************
204      * Returns a Type for the va_list type of the target.
205      * NOTE: For Posix/x86_64 this returns the type which will really
206      * be used for passing an argument of type va_list.
207      */
208     extern (C++) static Type va_listType()
209     {
210         if (global.params.isWindows)
211         {
212             return Type.tchar.pointerTo();
213         }
214         else if (global.params.isLinux || global.params.isFreeBSD || global.params.isOpenBSD || global.params.isSolaris || global.params.isOSX)
215         {
216             if (global.params.is64bit)
217             {
218                 return (new TypeIdentifier(Loc(), Identifier.idPool("__va_list_tag"))).pointerTo();
219             }
220             else
221             {
222                 return Type.tchar.pointerTo();
223             }
224         }
225         else
226         {
227             assert(0);
228         }
229     }
230 
231     /**
232      * Checks whether the target supports a vector type with total size `sz`
233      * (in bytes) and element type `type`.
234      *
235      * Returns: 0 if the type is supported, or else: 1 if vector types are not
236      *     supported on the target at all, 2 if the given size isn't, or 3 if
237      *     the element type isn't.
238      */
239     extern (C++) static int checkVectorType(int sz, Type type)
240     {
241         if (!global.params.is64bit && !global.params.isOSX)
242             return 1; // not supported
243         if (sz != 16 && sz != 32)
244             return 2; // wrong size
245         switch (type.ty)
246         {
247         case Tvoid:
248         case Tint8:
249         case Tuns8:
250         case Tint16:
251         case Tuns16:
252         case Tint32:
253         case Tuns32:
254         case Tfloat32:
255         case Tint64:
256         case Tuns64:
257         case Tfloat64:
258             break;
259         default:
260             return 3; // wrong base type
261         }
262         return 0;
263     }
264 
265     /******************************
266      * Encode the given expression, which is assumed to be an rvalue literal
267      * as another type for use in CTFE.
268      * This corresponds roughly to the idiom *(Type *)&e.
269      */
270     extern (C++) static Expression paintAsType(Expression e, Type type)
271     {
272         // We support up to 512-bit values.
273         ubyte[64] buffer;
274         assert(e.type.size() == type.size());
275         // Write the expression into the buffer.
276         switch (e.type.ty)
277         {
278         case Tint32:
279         case Tuns32:
280         case Tint64:
281         case Tuns64:
282             encodeInteger(e, buffer.ptr);
283             break;
284         case Tfloat32:
285         case Tfloat64:
286             encodeReal(e, buffer.ptr);
287             break;
288         default:
289             assert(0);
290         }
291         // Interpret the buffer as a new type.
292         switch (type.ty)
293         {
294         case Tint32:
295         case Tuns32:
296         case Tint64:
297         case Tuns64:
298             return decodeInteger(e.loc, type, buffer.ptr);
299         case Tfloat32:
300         case Tfloat64:
301             return decodeReal(e.loc, type, buffer.ptr);
302         default:
303             assert(0);
304         }
305     }
306 
307     /******************************
308      * For the given module, perform any post parsing analysis.
309      * Certain compiler backends (ie: GDC) have special placeholder
310      * modules whose source are empty, but code gets injected
311      * immediately after loading.
312      */
313     extern (C++) static void loadModule(Module m)
314     {
315     }
316 
317     /******************************
318      * For the given symbol written to the OutBuffer, apply any
319      * target-specific prefixes based on the given linkage.
320      */
321     extern (C++) static void prefixName(OutBuffer* buf, LINK linkage)
322     {
323         switch (linkage)
324         {
325         case LINKcpp:
326             if (global.params.isOSX)
327                 buf.prependbyte('_');
328             break;
329         default:
330             break;
331         }
332     }
333 }
334 
335 /******************************
336  * Private helpers for Target::paintAsType.
337  */
338 // Write the integer value of 'e' into a unsigned byte buffer.
339 extern (C++) static void encodeInteger(Expression e, ubyte* buffer)
340 {
341     dinteger_t value = e.toInteger();
342     int size = cast(int)e.type.size();
343     for (int p = 0; p < size; p++)
344     {
345         int offset = p; // Would be (size - 1) - p; on BigEndian
346         buffer[offset] = ((value >> (p * 8)) & 0xFF);
347     }
348 }
349 
350 // Write the bytes encoded in 'buffer' into an integer and returns
351 // the value as a new IntegerExp.
352 extern (C++) static Expression decodeInteger(Loc loc, Type type, ubyte* buffer)
353 {
354     dinteger_t value = 0;
355     int size = cast(int)type.size();
356     for (int p = 0; p < size; p++)
357     {
358         int offset = p; // Would be (size - 1) - p; on BigEndian
359         value |= (cast(dinteger_t)buffer[offset] << (p * 8));
360     }
361     return new IntegerExp(loc, value, type);
362 }
363 
364 // Write the real_t value of 'e' into a unsigned byte buffer.
365 extern (C++) static void encodeReal(Expression e, ubyte* buffer)
366 {
367     switch (e.type.ty)
368     {
369     case Tfloat32:
370         {
371             float* p = cast(float*)buffer;
372             *p = cast(float)e.toReal();
373             break;
374         }
375     case Tfloat64:
376         {
377             double* p = cast(double*)buffer;
378             *p = cast(double)e.toReal();
379             break;
380         }
381     default:
382         assert(0);
383     }
384 }
385 
386 // Write the bytes encoded in 'buffer' into a real_t and returns
387 // the value as a new RealExp.
388 extern (C++) static Expression decodeReal(Loc loc, Type type, ubyte* buffer)
389 {
390     real_t value;
391     switch (type.ty)
392     {
393     case Tfloat32:
394         {
395             float* p = cast(float*)buffer;
396             value = real_t(*p);
397             break;
398         }
399     case Tfloat64:
400         {
401             double* p = cast(double*)buffer;
402             value = real_t(*p);
403             break;
404         }
405     default:
406         assert(0);
407     }
408     return new RealExp(loc, value, type);
409 }