ldc/ddmd/target.d
David Nadlinger 9f998a398d Initial merge of upstream v2.071.0-b2
Notably, the glue layer side of the changed multiple interface
inheritance layout (DMD a54e89d) has not been implemented yet.

This corresponds to DMD commit 3f6a763c0589dd03c1c206eafd434b593702564e.
2016-04-03 15:15:14 +01:00

409 lines
No EOL
12 KiB
D

// Compiler implementation of the D programming language
// Copyright (c) 1999-2015 by Digital Mars
// All Rights Reserved
// written by Walter Bright
// http://www.digitalmars.com
// Distributed under the Boost Software License, Version 1.0.
// http://www.boost.org/LICENSE_1_0.txt
module ddmd.target;
import core.stdc.string;
import ddmd.dmodule;
import ddmd.expression;
import ddmd.globals;
import ddmd.identifier;
import ddmd.mtype;
import ddmd.root.longdouble;
import ddmd.root.outbuffer;
version(IN_LLVM)
{
extern(C++) struct Target
{
static __gshared int ptrsize;
static __gshared int realsize; // size a real consumes in memory
static __gshared int realpad; // 'padding' added to the CPU real size to bring it up to realsize
static __gshared int realalignsize; // alignment for reals
static __gshared bool reverseCppOverloads; // with dmc and cl, overloaded functions are grouped and in reverse order
static __gshared bool cppExceptions; // set if catching C++ exceptions is supported
static __gshared int c_longsize; // size of a C 'long' or 'unsigned long' type
static __gshared int c_long_doublesize; // size of a C 'long double'
static __gshared int classinfosize; // size of 'ClassInfo'
static void _init();
// Type sizes and support.
static uint alignsize(Type type);
static uint fieldalign(Type type);
static uint critsecsize();
static Type va_listType(); // get type of va_list
static int checkVectorType(int sz, Type type);
// CTFE support for cross-compilation.
static Expression paintAsType(Expression e, Type type);
// ABI and backend.
static void loadModule(Module m);
static void prefixName(OutBuffer *buf, LINK linkage);
}
}
else
{
/***********************************************************
*/
struct Target
{
extern (C++) static __gshared int ptrsize;
extern (C++) static __gshared int realsize; // size a real consumes in memory
extern (C++) static __gshared int realpad; // 'padding' added to the CPU real size to bring it up to realsize
extern (C++) static __gshared int realalignsize; // alignment for reals
extern (C++) static __gshared bool reverseCppOverloads; // with dmc and cl, overloaded functions are grouped and in reverse order
extern (C++) static __gshared bool cppExceptions; // set if catching C++ exceptions is supported
extern (C++) static __gshared int c_longsize; // size of a C 'long' or 'unsigned long' type
extern (C++) static __gshared int c_long_doublesize; // size of a C 'long double'
extern (C++) static __gshared int classinfosize; // size of 'ClassInfo'
extern (C++) static void _init()
{
// These have default values for 32 bit code, they get
// adjusted for 64 bit code.
ptrsize = 4;
classinfosize = 0x4C; // 76
if (global.params.isLP64)
{
ptrsize = 8;
classinfosize = 0x98; // 152
}
if (global.params.isLinux || global.params.isFreeBSD || global.params.isOpenBSD || global.params.isSolaris)
{
realsize = 12;
realpad = 2;
realalignsize = 4;
c_longsize = 4;
}
else if (global.params.isOSX)
{
realsize = 16;
realpad = 6;
realalignsize = 16;
c_longsize = 4;
}
else if (global.params.isWindows)
{
realsize = 10;
realpad = 0;
realalignsize = 2;
reverseCppOverloads = true;
c_longsize = 4;
}
else
assert(0);
if (global.params.is64bit)
{
if (global.params.isLinux || global.params.isFreeBSD || global.params.isSolaris)
{
realsize = 16;
realpad = 6;
realalignsize = 16;
c_longsize = 8;
}
else if (global.params.isOSX)
{
c_longsize = 8;
}
}
c_long_doublesize = realsize;
if (global.params.is64bit && global.params.isWindows)
c_long_doublesize = 8;
cppExceptions = global.params.dwarfeh || global.params.isLinux || global.params.isFreeBSD ||
(global.params.isOSX && global.params.is64bit);
}
/******************************
* Return memory alignment size of type.
*/
extern (C++) static uint alignsize(Type type)
{
assert(type.isTypeBasic());
switch (type.ty)
{
case Tfloat80:
case Timaginary80:
case Tcomplex80:
return Target.realalignsize;
case Tcomplex32:
if (global.params.isLinux || global.params.isOSX || global.params.isFreeBSD || global.params.isOpenBSD || global.params.isSolaris)
return 4;
break;
case Tint64:
case Tuns64:
case Tfloat64:
case Timaginary64:
case Tcomplex64:
if (global.params.isLinux || global.params.isOSX || global.params.isFreeBSD || global.params.isOpenBSD || global.params.isSolaris)
return global.params.is64bit ? 8 : 4;
break;
default:
break;
}
return cast(uint)type.size(Loc());
}
/******************************
* Return field alignment size of type.
*/
extern (C++) static uint fieldalign(Type type)
{
return type.alignsize();
}
/***********************************
* Return size of OS critical section.
* NOTE: can't use the sizeof() calls directly since cross compiling is
* supported and would end up using the host sizes rather than the target
* sizes.
*/
extern (C++) static uint critsecsize()
{
if (global.params.isWindows)
{
// sizeof(CRITICAL_SECTION) for Windows.
return global.params.isLP64 ? 40 : 24;
}
else if (global.params.isLinux)
{
// sizeof(pthread_mutex_t) for Linux.
if (global.params.is64bit)
return global.params.isLP64 ? 40 : 32;
else
return global.params.isLP64 ? 40 : 24;
}
else if (global.params.isFreeBSD)
{
// sizeof(pthread_mutex_t) for FreeBSD.
return global.params.isLP64 ? 8 : 4;
}
else if (global.params.isOpenBSD)
{
// sizeof(pthread_mutex_t) for OpenBSD.
return global.params.isLP64 ? 8 : 4;
}
else if (global.params.isOSX)
{
// sizeof(pthread_mutex_t) for OSX.
return global.params.isLP64 ? 64 : 44;
}
else if (global.params.isSolaris)
{
// sizeof(pthread_mutex_t) for Solaris.
return 24;
}
assert(0);
}
/***********************************
* Returns a Type for the va_list type of the target.
* NOTE: For Posix/x86_64 this returns the type which will really
* be used for passing an argument of type va_list.
*/
extern (C++) static Type va_listType()
{
if (global.params.isWindows)
{
return Type.tchar.pointerTo();
}
else if (global.params.isLinux || global.params.isFreeBSD || global.params.isOpenBSD || global.params.isSolaris || global.params.isOSX)
{
if (global.params.is64bit)
{
return (new TypeIdentifier(Loc(), Identifier.idPool("__va_list_tag"))).pointerTo();
}
else
{
return Type.tchar.pointerTo();
}
}
else
{
assert(0);
}
}
/*
* Return true if the given type is supported for this target
*/
extern (C++) static int checkVectorType(int sz, Type type)
{
if (!global.params.is64bit && !global.params.isOSX)
return 1; // not supported
if (sz != 16 && sz != 32)
return 2; // wrong size
switch (type.ty)
{
case Tvoid:
case Tint8:
case Tuns8:
case Tint16:
case Tuns16:
case Tint32:
case Tuns32:
case Tfloat32:
case Tint64:
case Tuns64:
case Tfloat64:
break;
default:
return 3; // wrong base type
}
return 0;
}
/******************************
* Encode the given expression, which is assumed to be an rvalue literal
* as another type for use in CTFE.
* This corresponds roughly to the idiom *(Type *)&e.
*/
extern (C++) static Expression paintAsType(Expression e, Type type)
{
// We support up to 512-bit values.
ubyte[64] buffer;
assert(e.type.size() == type.size());
// Write the expression into the buffer.
switch (e.type.ty)
{
case Tint32:
case Tuns32:
case Tint64:
case Tuns64:
encodeInteger(e, buffer.ptr);
break;
case Tfloat32:
case Tfloat64:
encodeReal(e, buffer.ptr);
break;
default:
assert(0);
}
// Interpret the buffer as a new type.
switch (type.ty)
{
case Tint32:
case Tuns32:
case Tint64:
case Tuns64:
return decodeInteger(e.loc, type, buffer.ptr);
case Tfloat32:
case Tfloat64:
return decodeReal(e.loc, type, buffer.ptr);
default:
assert(0);
}
}
/******************************
* For the given module, perform any post parsing analysis.
* Certain compiler backends (ie: GDC) have special placeholder
* modules whose source are empty, but code gets injected
* immediately after loading.
*/
extern (C++) static void loadModule(Module m)
{
}
/******************************
* For the given symbol written to the OutBuffer, apply any
* target-specific prefixes based on the given linkage.
*/
extern (C++) static void prefixName(OutBuffer* buf, LINK linkage)
{
switch (linkage)
{
case LINKcpp:
if (global.params.isOSX)
buf.prependbyte('_');
break;
default:
break;
}
}
}
/******************************
* Private helpers for Target::paintAsType.
*/
// Write the integer value of 'e' into a unsigned byte buffer.
extern (C++) static void encodeInteger(Expression e, ubyte* buffer)
{
dinteger_t value = e.toInteger();
int size = cast(int)e.type.size();
for (int p = 0; p < size; p++)
{
int offset = p; // Would be (size - 1) - p; on BigEndian
buffer[offset] = ((value >> (p * 8)) & 0xFF);
}
}
// Write the bytes encoded in 'buffer' into an integer and returns
// the value as a new IntegerExp.
extern (C++) static Expression decodeInteger(Loc loc, Type type, ubyte* buffer)
{
dinteger_t value = 0;
int size = cast(int)type.size();
for (int p = 0; p < size; p++)
{
int offset = p; // Would be (size - 1) - p; on BigEndian
value |= (cast(dinteger_t)buffer[offset] << (p * 8));
}
return new IntegerExp(loc, value, type);
}
// Write the real value of 'e' into a unsigned byte buffer.
extern (C++) static void encodeReal(Expression e, ubyte* buffer)
{
switch (e.type.ty)
{
case Tfloat32:
{
float* p = cast(float*)buffer;
*p = cast(float)e.toReal();
break;
}
case Tfloat64:
{
double* p = cast(double*)buffer;
*p = cast(double)e.toReal();
break;
}
default:
assert(0);
}
}
// Write the bytes encoded in 'buffer' into a longdouble and returns
// the value as a new RealExp.
extern (C++) static Expression decodeReal(Loc loc, Type type, ubyte* buffer)
{
real value;
switch (type.ty)
{
case Tfloat32:
{
float* p = cast(float*)buffer;
value = ldouble(*p);
break;
}
case Tfloat64:
{
double* p = cast(double*)buffer;
value = ldouble(*p);
break;
}
default:
assert(0);
}
return new RealExp(loc, value, type);
}
} // !IN_LLVM