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 }