mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-10 04:45:56 +03:00
Merge branch 'master' into merge-2.068
Conflicts: runtime/druntime
This commit is contained in:
commit
d45170464e
22 changed files with 269 additions and 267 deletions
|
@ -99,7 +99,7 @@ build_script:
|
||||||
- cd ninja-ldc
|
- cd ninja-ldc
|
||||||
- cmake -G Ninja -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=c:\projects\ldc-x64 -DLLVM_ROOT_DIR=c:/projects/llvm-x64 -DLIBCONFIG_INCLUDE_DIR=c:/projects/libconfig/lib -DLIBCONFIG_LIBRARY=c:/projects/libconfig/lib/x64/ReleaseStatic/libconfig.lib ..\ldc
|
- cmake -G Ninja -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=c:\projects\ldc-x64 -DLLVM_ROOT_DIR=c:/projects/llvm-x64 -DLIBCONFIG_INCLUDE_DIR=c:/projects/libconfig/lib -DLIBCONFIG_LIBRARY=c:/projects/libconfig/lib/x64/ReleaseStatic/libconfig.lib ..\ldc
|
||||||
# Work around LDC issue #930
|
# Work around LDC issue #930
|
||||||
- ps: (gc build.ninja).replace('runtime/std/string-unittest-debug.obj -w -d -g -unittest', 'runtime/std/string-unittest-debug.obj -w -d -unittest') | sc build.ninja
|
- ps: (gc build.ninja).replace('runtime/std/string-unittest-debug.obj -w -d -g -link-debuglib -unittest', 'runtime/std/string-unittest-debug.obj -w -d -link-debuglib -unittest') | sc build.ninja
|
||||||
# Build LDC, druntime and phobos
|
# Build LDC, druntime and phobos
|
||||||
- ninja -j2
|
- ninja -j2
|
||||||
|
|
||||||
|
|
|
@ -90,15 +90,18 @@ static cl::list<std::string, StringsAdapter> importPaths("I",
|
||||||
cl::Prefix);
|
cl::Prefix);
|
||||||
|
|
||||||
static cl::opt<std::string> defaultLib("defaultlib",
|
static cl::opt<std::string> defaultLib("defaultlib",
|
||||||
cl::desc("Default libraries for non-debug-info build (overrides previous)"),
|
cl::desc("Default libraries to link with (overrides previous)"),
|
||||||
cl::value_desc("lib1,lib2,..."),
|
cl::value_desc("lib1,lib2,..."),
|
||||||
cl::ZeroOrMore);
|
cl::ZeroOrMore);
|
||||||
|
|
||||||
static cl::opt<std::string> debugLib("debuglib",
|
static cl::opt<std::string> debugLib("debuglib",
|
||||||
cl::desc("Default libraries for debug info build (overrides previous)"),
|
cl::desc("Debug versions of default libraries (overrides previous)"),
|
||||||
cl::value_desc("lib1,lib2,..."),
|
cl::value_desc("lib1,lib2,..."),
|
||||||
cl::ZeroOrMore);
|
cl::ZeroOrMore);
|
||||||
|
|
||||||
|
static cl::opt<bool> linkDebugLib("link-debuglib",
|
||||||
|
cl::desc("Link with libraries specified in -debuglib, not -defaultlib"),
|
||||||
|
cl::ZeroOrMore);
|
||||||
|
|
||||||
#if LDC_LLVM_VER < 304
|
#if LDC_LLVM_VER < 304
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
|
@ -420,8 +423,7 @@ static void parseCommandLine(int argc, char **argv, Strings &sourceFiles, bool &
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Parse comma-separated default library list.
|
// Parse comma-separated default library list.
|
||||||
std::stringstream libNames(
|
std::stringstream libNames(linkDebugLib ? debugLib : defaultLib);
|
||||||
global.params.symdebug ? debugLib : defaultLib);
|
|
||||||
while (libNames.good())
|
while (libNames.good())
|
||||||
{
|
{
|
||||||
std::string lib;
|
std::string lib;
|
||||||
|
|
|
@ -110,14 +110,13 @@ struct AArch64TargetABI : TargetABI
|
||||||
}
|
}
|
||||||
|
|
||||||
void vaCopy(LLValue* pDest, LLValue* src) {
|
void vaCopy(LLValue* pDest, LLValue* src) {
|
||||||
// Analog to va_start, we need to allocate a __va_list struct on the stack first
|
// Analog to va_start, we need to allocate a new __va_list struct on the stack,
|
||||||
// and set the passed 'dest' char* pointer to its address.
|
// fill it with a bitcopy of the source struct...
|
||||||
LLValue* valistmem = DtoRawAlloca(getValistType(), 0, "__va_list_mem");
|
src = DtoLoad(DtoBitCast(src, getValistType()->getPointerTo())); // *(__va_list*)src
|
||||||
DtoStore(DtoBitCast(valistmem, getVoidPtrType()), pDest);
|
LLValue* valistmem = DtoAllocaDump(src, 0, "__va_list_mem");
|
||||||
|
// ... and finally set the passed 'dest' char* pointer to the new struct's address.
|
||||||
// Now bitcopy the source struct over the destination struct.
|
DtoStore(DtoBitCast(valistmem, getVoidPtrType()),
|
||||||
src = DtoBitCast(src, valistmem->getType());
|
DtoBitCast(pDest, getPtrToType(getVoidPtrType())));
|
||||||
DtoStore(DtoLoad(src), valistmem); // *(__va_list*)dest = *(__va_list*)src
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LLValue* prepareVaArg(LLValue* pAp)
|
LLValue* prepareVaArg(LLValue* pAp)
|
||||||
|
|
|
@ -82,24 +82,23 @@ struct LLTypeMemoryLayout
|
||||||
/// Removes padding fields for (non-union-containing!) structs
|
/// Removes padding fields for (non-union-containing!) structs
|
||||||
struct RemoveStructPadding : ABIRewrite {
|
struct RemoveStructPadding : ABIRewrite {
|
||||||
/// get a rewritten value back to its original form
|
/// get a rewritten value back to its original form
|
||||||
LLValue* get(Type* dty, DValue* v) {
|
LLValue* get(Type* dty, LLValue* v) {
|
||||||
LLValue* lval = DtoAlloca(dty, ".rewritetmp");
|
LLValue* lval = DtoAlloca(dty, ".rewritetmp");
|
||||||
getL(dty, v, lval);
|
getL(dty, v, lval);
|
||||||
return lval;
|
return lval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// get a rewritten value back to its original form and store result in provided lvalue
|
/// get a rewritten value back to its original form and store result in provided lvalue
|
||||||
/// this one is optional and defaults to calling the one above
|
void getL(Type* dty, LLValue* v, LLValue* lval) {
|
||||||
void getL(Type* dty, DValue* v, LLValue* lval) {
|
|
||||||
// Make sure the padding is zero, so struct comparisons work.
|
// Make sure the padding is zero, so struct comparisons work.
|
||||||
// TODO: Only do this if there's padding, and/or only initialize padding.
|
// TODO: Only do this if there's padding, and/or only initialize padding.
|
||||||
DtoMemSetZero(lval, DtoConstSize_t(getTypePaddedSize(DtoType(dty))));
|
DtoMemSetZero(lval, DtoConstSize_t(getTypePaddedSize(DtoType(dty))));
|
||||||
DtoPaddedStruct(dty->toBasetype(), v->getRVal(), lval);
|
DtoPaddedStruct(dty->toBasetype(), v, lval);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// put out rewritten value
|
/// put out rewritten value
|
||||||
LLValue* put(Type* dty, DValue* v) {
|
LLValue* put(DValue* v) {
|
||||||
return DtoUnpaddedStruct(dty->toBasetype(), v->getRVal());
|
return DtoUnpaddedStruct(v->getType()->toBasetype(), v->getRVal());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// return the transformed type for this rewrite
|
/// return the transformed type for this rewrite
|
||||||
|
@ -154,26 +153,22 @@ struct IntegerRewrite : ABIRewrite
|
||||||
return LLTypeMemoryLayout::typesAreEquivalent(llType, integerType);
|
return LLTypeMemoryLayout::typesAreEquivalent(llType, integerType);
|
||||||
}
|
}
|
||||||
|
|
||||||
LLValue* get(Type* dty, DValue* dv)
|
LLValue* get(Type* dty, LLValue* v)
|
||||||
{
|
{
|
||||||
LLValue* integer = dv->getRVal();
|
LLValue* integerDump = DtoAllocaDump(v, dty, ".IntegerRewrite_dump");
|
||||||
LLValue* integerDump = storeToMemory(integer, 0, ".IntegerRewrite_dump");
|
|
||||||
|
|
||||||
LLType* type = DtoType(dty);
|
LLType* type = DtoType(dty);
|
||||||
return loadFromMemory(integerDump, type, ".IntegerRewrite_getResult");
|
return loadFromMemory(integerDump, type, ".IntegerRewrite_getResult");
|
||||||
}
|
}
|
||||||
|
|
||||||
void getL(Type* dty, DValue* dv, LLValue* lval)
|
void getL(Type* dty, LLValue* v, LLValue* lval)
|
||||||
{
|
{
|
||||||
LLValue* integer = dv->getRVal();
|
storeToMemory(v, lval);
|
||||||
storeToMemory(integer, lval);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LLValue* put(Type* dty, DValue* dv)
|
LLValue* put(DValue* dv)
|
||||||
{
|
{
|
||||||
assert(dty == dv->getType());
|
|
||||||
LLValue* address = getAddressOf(dv);
|
LLValue* address = getAddressOf(dv);
|
||||||
LLType* integerType = getIntegerType(dty->size());
|
LLType* integerType = getIntegerType(dv->getType()->size());
|
||||||
return loadFromMemory(address, integerType, ".IntegerRewrite_putResult");
|
return loadFromMemory(address, integerType, ".IntegerRewrite_putResult");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -205,21 +200,19 @@ struct ExplicitByvalRewrite : ABIRewrite
|
||||||
ExplicitByvalRewrite(size_t alignment = 16) : alignment(alignment)
|
ExplicitByvalRewrite(size_t alignment = 16) : alignment(alignment)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
LLValue* get(Type* dty, DValue* v)
|
LLValue* get(Type* dty, LLValue* v)
|
||||||
{
|
{
|
||||||
LLValue* pointer = v->getRVal();
|
return DtoLoad(v, ".ExplicitByvalRewrite_getResult");
|
||||||
return DtoLoad(pointer, ".ExplicitByvalRewrite_getResult");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void getL(Type* dty, DValue* v, LLValue* lval)
|
void getL(Type* dty, LLValue* v, LLValue* lval)
|
||||||
{
|
{
|
||||||
LLValue* pointer = v->getRVal();
|
DtoAggrCopy(lval, v);
|
||||||
DtoAggrCopy(lval, pointer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LLValue* put(Type* dty, DValue* v)
|
LLValue* put(DValue* v)
|
||||||
{
|
{
|
||||||
if (DtoIsPassedByRef(dty))
|
if (DtoIsPassedByRef(v->getType()))
|
||||||
{
|
{
|
||||||
LLValue* originalPointer = v->getRVal();
|
LLValue* originalPointer = v->getRVal();
|
||||||
LLType* type = originalPointer->getType()->getPointerElementType();
|
LLType* type = originalPointer->getType()->getPointerElementType();
|
||||||
|
@ -228,9 +221,7 @@ struct ExplicitByvalRewrite : ABIRewrite
|
||||||
return copyForCallee;
|
return copyForCallee;
|
||||||
}
|
}
|
||||||
|
|
||||||
LLValue* originalValue = v->getRVal();
|
return DtoAllocaDump(v->getRVal(), alignment, ".ExplicitByvalRewrite_putResult");
|
||||||
LLValue* copyForCallee = storeToMemory(originalValue, alignment, ".ExplicitByvalRewrite_putResult");
|
|
||||||
return copyForCallee;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LLType* type(Type* dty, LLType* t)
|
LLType* type(Type* dty, LLType* t)
|
||||||
|
|
|
@ -160,22 +160,21 @@ namespace {
|
||||||
* memory so that it's then readable as the other type (i.e., bit-casting).
|
* memory so that it's then readable as the other type (i.e., bit-casting).
|
||||||
*/
|
*/
|
||||||
struct X86_64_C_struct_rewrite : ABIRewrite {
|
struct X86_64_C_struct_rewrite : ABIRewrite {
|
||||||
LLValue* get(Type* dty, DValue* v)
|
LLValue* get(Type* dty, LLValue* v)
|
||||||
{
|
{
|
||||||
LLValue* address = storeToMemory(v->getRVal(), 0, ".X86_64_C_struct_rewrite_dump");
|
LLValue* address = DtoAllocaDump(v, dty, ".X86_64_C_struct_rewrite_dump");
|
||||||
LLType* type = DtoType(dty);
|
LLType* type = DtoType(dty);
|
||||||
return loadFromMemory(address, type, ".X86_64_C_struct_rewrite_getResult");
|
return loadFromMemory(address, type, ".X86_64_C_struct_rewrite_getResult");
|
||||||
}
|
}
|
||||||
|
|
||||||
void getL(Type* dty, DValue* v, LLValue* lval) {
|
void getL(Type* dty, LLValue* v, LLValue* lval) {
|
||||||
storeToMemory(v->getRVal(), lval);
|
storeToMemory(v, lval);
|
||||||
}
|
}
|
||||||
|
|
||||||
LLValue* put(Type* dty, DValue* v) {
|
LLValue* put(DValue* v) {
|
||||||
assert(dty == v->getType());
|
|
||||||
LLValue* address = getAddressOf(v);
|
LLValue* address = getAddressOf(v);
|
||||||
|
|
||||||
LLType* abiTy = getAbiType(dty);
|
LLType* abiTy = getAbiType(v->getType());
|
||||||
assert(abiTy && "Why are we rewriting a non-rewritten type?");
|
assert(abiTy && "Why are we rewriting a non-rewritten type?");
|
||||||
|
|
||||||
return loadFromMemory(address, abiTy, ".X86_64_C_struct_rewrite_putResult");
|
return loadFromMemory(address, abiTy, ".X86_64_C_struct_rewrite_putResult");
|
||||||
|
@ -195,18 +194,15 @@ struct X86_64_C_struct_rewrite : ABIRewrite {
|
||||||
* the ByVal LLVM attribute.
|
* the ByVal LLVM attribute.
|
||||||
*/
|
*/
|
||||||
struct ImplicitByvalRewrite : ABIRewrite {
|
struct ImplicitByvalRewrite : ABIRewrite {
|
||||||
LLValue* get(Type* dty, DValue* v) {
|
LLValue* get(Type* dty, LLValue* v) {
|
||||||
LLValue* pointer = v->getRVal();
|
return DtoLoad(v, ".ImplicitByvalRewrite_getResult");
|
||||||
return DtoLoad(pointer, ".ImplicitByvalRewrite_getResult");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void getL(Type* dty, DValue* v, LLValue* lval) {
|
void getL(Type* dty, LLValue* v, LLValue* lval) {
|
||||||
LLValue* pointer = v->getRVal();
|
DtoAggrCopy(lval, v);
|
||||||
DtoAggrCopy(lval, pointer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LLValue* put(Type* dty, DValue* v) {
|
LLValue* put(DValue* v) {
|
||||||
assert(dty == v->getType());
|
|
||||||
return getAddressOf(v);
|
return getAddressOf(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -388,15 +384,13 @@ LLValue* X86_64TargetABI::prepareVaStart(LLValue* pAp) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void X86_64TargetABI::vaCopy(LLValue* pDest, LLValue* src) {
|
void X86_64TargetABI::vaCopy(LLValue* pDest, LLValue* src) {
|
||||||
// Analog to va_start, we need to allocate a __va_list struct on the stack first
|
// Analog to va_start, we need to allocate a new __va_list struct on the stack,
|
||||||
// and set the passed 'dest' char* pointer to its address.
|
// fill it with a bitcopy of the source struct...
|
||||||
LLValue* valistmem = DtoRawAlloca(getValistType(), 0, "__va_list_mem");
|
src = DtoLoad(DtoBitCast(src, getValistType()->getPointerTo())); // *(__va_list*)src
|
||||||
|
LLValue* valistmem = DtoAllocaDump(src, 0, "__va_list_mem");
|
||||||
|
// ... and finally set the passed 'dest' char* pointer to the new struct's address.
|
||||||
DtoStore(DtoBitCast(valistmem, getVoidPtrType()),
|
DtoStore(DtoBitCast(valistmem, getVoidPtrType()),
|
||||||
DtoBitCast(pDest, getPtrToType(getVoidPtrType())));
|
DtoBitCast(pDest, getPtrToType(getVoidPtrType())));
|
||||||
|
|
||||||
// Now bitcopy the source struct over the destination struct.
|
|
||||||
src = DtoBitCast(src, valistmem->getType());
|
|
||||||
DtoStore(DtoLoad(src), valistmem); // *(__va_list*)dest = *(__va_list*)src
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LLValue* X86_64TargetABI::prepareVaArg(LLValue* pAp)
|
LLValue* X86_64TargetABI::prepareVaArg(LLValue* pAp)
|
||||||
|
|
27
gen/abi.cpp
27
gen/abi.cpp
|
@ -28,7 +28,7 @@
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void ABIRewrite::getL(Type* dty, DValue* v, LLValue* lval)
|
void ABIRewrite::getL(Type* dty, LLValue* v, LLValue* lval)
|
||||||
{
|
{
|
||||||
LLValue* rval = get(dty, v);
|
LLValue* rval = get(dty, v);
|
||||||
assert(rval->getType() == lval->getType()->getContainedType(0));
|
assert(rval->getType() == lval->getType()->getContainedType(0));
|
||||||
|
@ -49,29 +49,22 @@ LLValue* ABIRewrite::getAddressOf(DValue* v)
|
||||||
if (v->isLVal())
|
if (v->isLVal())
|
||||||
return v->getLVal();
|
return v->getLVal();
|
||||||
|
|
||||||
return storeToMemory(v->getRVal(), 0, ".getAddressOf_dump");
|
return DtoAllocaDump(v, ".getAddressOf_dump");
|
||||||
}
|
|
||||||
|
|
||||||
LLValue* ABIRewrite::storeToMemory(LLValue* rval, size_t alignment, const char* name)
|
|
||||||
{
|
|
||||||
LLValue* address = DtoRawAlloca(rval->getType(), alignment, name);
|
|
||||||
DtoStore(rval, address);
|
|
||||||
return address;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ABIRewrite::storeToMemory(LLValue* rval, LLValue* address)
|
void ABIRewrite::storeToMemory(LLValue* rval, LLValue* address)
|
||||||
{
|
{
|
||||||
LLType* pointerType = address->getType();
|
LLType* pointerType = address->getType();
|
||||||
assert(pointerType->isPointerTy());
|
assert(pointerType->isPointerTy());
|
||||||
LLType* pointerElementType = pointerType->getPointerElementType();
|
LLType* pointeeType = pointerType->getPointerElementType();
|
||||||
|
|
||||||
LLType* rvalType = rval->getType();
|
LLType* rvalType = rval->getType();
|
||||||
if (rvalType != pointerElementType)
|
if (rvalType != pointeeType)
|
||||||
{
|
{
|
||||||
if (getTypeStoreSize(rvalType) > getTypeAllocSize(pointerElementType))
|
if (getTypeStoreSize(rvalType) > getTypeAllocSize(pointeeType))
|
||||||
{
|
{
|
||||||
// not enough allocated memory
|
// not enough allocated memory
|
||||||
LLValue* paddedDump = storeToMemory(rval, 0, ".storeToMemory_paddedDump");
|
LLValue* paddedDump = DtoAllocaDump(rval, 0, ".storeToMemory_paddedDump");
|
||||||
DtoAggrCopy(address, paddedDump);
|
DtoAggrCopy(address, paddedDump);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -86,16 +79,16 @@ LLValue* ABIRewrite::loadFromMemory(LLValue* address, LLType* asType, const char
|
||||||
{
|
{
|
||||||
LLType* pointerType = address->getType();
|
LLType* pointerType = address->getType();
|
||||||
assert(pointerType->isPointerTy());
|
assert(pointerType->isPointerTy());
|
||||||
LLType* pointerElementType = pointerType->getPointerElementType();
|
LLType* pointeeType = pointerType->getPointerElementType();
|
||||||
|
|
||||||
if (asType == pointerElementType)
|
if (asType == pointeeType)
|
||||||
return DtoLoad(address, name);
|
return DtoLoad(address, name);
|
||||||
|
|
||||||
if (getTypeStoreSize(asType) > getTypeAllocSize(pointerElementType))
|
if (getTypeStoreSize(asType) > getTypeAllocSize(pointeeType))
|
||||||
{
|
{
|
||||||
// not enough allocated memory
|
// not enough allocated memory
|
||||||
LLValue* paddedDump = DtoRawAlloca(asType, 0, ".loadFromMemory_paddedDump");
|
LLValue* paddedDump = DtoRawAlloca(asType, 0, ".loadFromMemory_paddedDump");
|
||||||
DtoMemCpy(paddedDump, address, DtoConstSize_t(getTypeAllocSize(pointerElementType)));
|
DtoMemCpy(paddedDump, address, DtoConstSize_t(getTypeAllocSize(pointeeType)));
|
||||||
return DtoLoad(paddedDump, name);
|
return DtoLoad(paddedDump, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
10
gen/abi.h
10
gen/abi.h
|
@ -44,14 +44,14 @@ struct ABIRewrite
|
||||||
virtual ~ABIRewrite() {}
|
virtual ~ABIRewrite() {}
|
||||||
|
|
||||||
/// get a rewritten value back to its original form
|
/// get a rewritten value back to its original form
|
||||||
virtual llvm::Value* get(Type* dty, DValue* v) = 0;
|
virtual llvm::Value* get(Type* dty, llvm::Value* v) = 0;
|
||||||
|
|
||||||
/// get a rewritten value back to its original form and store result in provided lvalue
|
/// get a rewritten value back to its original form and store result in provided lvalue
|
||||||
/// this one is optional and defaults to calling the one above
|
/// this one is optional and defaults to calling the one above
|
||||||
virtual void getL(Type* dty, DValue* v, llvm::Value* lval);
|
virtual void getL(Type* dty, llvm::Value* v, llvm::Value* lval);
|
||||||
|
|
||||||
/// put out rewritten value
|
/// put out rewritten value
|
||||||
virtual llvm::Value* put(Type* dty, DValue* v) = 0;
|
virtual llvm::Value* put(DValue* v) = 0;
|
||||||
|
|
||||||
/// should return the transformed type for this rewrite
|
/// should return the transformed type for this rewrite
|
||||||
virtual llvm::Type* type(Type* dty, llvm::Type* t) = 0;
|
virtual llvm::Type* type(Type* dty, llvm::Type* t) = 0;
|
||||||
|
@ -62,10 +62,6 @@ protected:
|
||||||
// Returns the address of a D value, storing it to memory first if need be.
|
// Returns the address of a D value, storing it to memory first if need be.
|
||||||
static llvm::Value* getAddressOf(DValue* v);
|
static llvm::Value* getAddressOf(DValue* v);
|
||||||
|
|
||||||
// Stores a LL value to memory and returns its address.
|
|
||||||
static llvm::Value* storeToMemory(llvm::Value* rval, size_t alignment = 0,
|
|
||||||
const char* name = ".store_result");
|
|
||||||
|
|
||||||
// Stores a LL value to a specified memory address. The element type of the provided
|
// Stores a LL value to a specified memory address. The element type of the provided
|
||||||
// pointer doesn't need to match the value type (=> suited for bit-casting).
|
// pointer doesn't need to match the value type (=> suited for bit-casting).
|
||||||
static void storeToMemory(llvm::Value* rval, llvm::Value* address);
|
static void storeToMemory(llvm::Value* rval, llvm::Value* address);
|
||||||
|
|
|
@ -150,8 +150,7 @@ static void DtoArrayInit(Loc& loc, LLValue* ptr, LLValue* length, DValue* dvalue
|
||||||
gIR->topfunc());
|
gIR->topfunc());
|
||||||
|
|
||||||
// initialize iterator
|
// initialize iterator
|
||||||
LLValue *itr = DtoAlloca(Type::tsize_t, "arrayinit.itr");
|
LLValue *itr = DtoAllocaDump(DtoConstSize_t(0), 0, "arrayinit.itr");
|
||||||
DtoStore(DtoConstSize_t(0), itr);
|
|
||||||
|
|
||||||
// move into the for condition block, ie. start the loop
|
// move into the for condition block, ie. start the loop
|
||||||
assert(!gIR->scopereturned());
|
assert(!gIR->scopereturned());
|
||||||
|
|
|
@ -512,7 +512,7 @@ void CompoundAsmStatement_toIR(CompoundAsmStatement *stmt, IRState* p)
|
||||||
|
|
||||||
// location of the special value determining the goto label
|
// location of the special value determining the goto label
|
||||||
// will be set if post-asm dispatcher block is needed
|
// will be set if post-asm dispatcher block is needed
|
||||||
llvm::AllocaInst* jump_target = 0;
|
LLValue* jump_target = 0;
|
||||||
|
|
||||||
{
|
{
|
||||||
FuncDeclaration* fd = gIR->func()->decl;
|
FuncDeclaration* fd = gIR->func()->decl;
|
||||||
|
@ -577,8 +577,7 @@ void CompoundAsmStatement_toIR(CompoundAsmStatement *stmt, IRState* p)
|
||||||
outSetterStmt->code += asmGotoEndLabel.str()+":\n";
|
outSetterStmt->code += asmGotoEndLabel.str()+":\n";
|
||||||
|
|
||||||
// create storage for and initialize the temporary
|
// create storage for and initialize the temporary
|
||||||
jump_target = DtoAlloca(Type::tint32, "__llvm_jump_target");
|
jump_target = DtoAllocaDump(DtoConstUint(0), 0, "__llvm_jump_target");
|
||||||
gIR->ir->CreateStore(DtoConstUint(0), jump_target);
|
|
||||||
// setup variable for output from asm
|
// setup variable for output from asm
|
||||||
outSetterStmt->out_c = "=*m,";
|
outSetterStmt->out_c = "=*m,";
|
||||||
outSetterStmt->out.push_back(jump_target);
|
outSetterStmt->out.push_back(jump_target);
|
||||||
|
|
|
@ -841,9 +841,10 @@ void ldc::DIBuilder::EmitStopPoint(Loc& loc)
|
||||||
// (line 0), then we can just ignore it (see GitHub issue #998 for why we
|
// (line 0), then we can just ignore it (see GitHub issue #998 for why we
|
||||||
// cannot do this in all cases).
|
// cannot do this in all cases).
|
||||||
if (!loc.linnum &&
|
if (!loc.linnum &&
|
||||||
!IR->ir->getCurrentDebugLocation()
|
#if LDC_LLVM_VER >= 307
|
||||||
#if LDC_LLVM_VER < 307
|
IR->ir->getCurrentDebugLocation()
|
||||||
.isUnknown()
|
#else
|
||||||
|
!IR->ir->getCurrentDebugLocation().isUnknown()
|
||||||
#endif
|
#endif
|
||||||
)
|
)
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -819,8 +819,7 @@ void DtoDefineFunction(FuncDeclaration* fd)
|
||||||
LLValue* thismem = thisvar;
|
LLValue* thismem = thisvar;
|
||||||
if (!irFty.arg_this->byref)
|
if (!irFty.arg_this->byref)
|
||||||
{
|
{
|
||||||
thismem = DtoRawAlloca(thisvar->getType(), 0, "this"); // FIXME: align?
|
thismem = DtoAllocaDump(thisvar, 0, "this");
|
||||||
DtoStore(thisvar, thismem);
|
|
||||||
irFunc->thisArg = thismem;
|
irFunc->thisArg = thismem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -832,12 +831,7 @@ void DtoDefineFunction(FuncDeclaration* fd)
|
||||||
|
|
||||||
// give the 'nestArg' storage
|
// give the 'nestArg' storage
|
||||||
if (irFty.arg_nest)
|
if (irFty.arg_nest)
|
||||||
{
|
irFunc->nestArg = DtoAllocaDump(irFunc->nestArg, 0, "nestedFrame");
|
||||||
LLValue *nestArg = irFunc->nestArg;
|
|
||||||
LLValue *val = DtoRawAlloca(nestArg->getType(), 0, "nestedFrame");
|
|
||||||
DtoStore(nestArg, val);
|
|
||||||
irFunc->nestArg = val;
|
|
||||||
}
|
|
||||||
|
|
||||||
// give arguments storage and debug info
|
// give arguments storage and debug info
|
||||||
if (fd->parameters)
|
if (fd->parameters)
|
||||||
|
@ -873,8 +867,7 @@ void DtoDefineFunction(FuncDeclaration* fd)
|
||||||
LLValue* mem = DtoAlloca(irparam->arg->type, vd->ident->toChars());
|
LLValue* mem = DtoAlloca(irparam->arg->type, vd->ident->toChars());
|
||||||
|
|
||||||
// let the abi transform the argument back first
|
// let the abi transform the argument back first
|
||||||
DImValue arg_dval(vd->type, irparam->value);
|
irFty.getParam(vd->type, llArgIdx, irparam->value, mem);
|
||||||
irFty.getParam(vd->type, llArgIdx, &arg_dval, mem);
|
|
||||||
|
|
||||||
// set the arg var value to the alloca
|
// set the arg var value to the alloca
|
||||||
irparam->value = mem;
|
irparam->value = mem;
|
||||||
|
@ -912,10 +905,7 @@ void DtoDefineFunction(FuncDeclaration* fd)
|
||||||
llvm::CallInst::Create(GET_INTRINSIC_DECL(vastart), vaStartArg, "", gIR->scopebb());
|
llvm::CallInst::Create(GET_INTRINSIC_DECL(vastart), vaStartArg, "", gIR->scopebb());
|
||||||
|
|
||||||
// copy _arguments to a memory location
|
// copy _arguments to a memory location
|
||||||
LLType* argumentsType = irFunc->_arguments->getType();
|
irFunc->_arguments = DtoAllocaDump(irFunc->_arguments, 0, "_arguments_mem");
|
||||||
LLValue* argumentsmem = DtoRawAlloca(argumentsType, 0, "_arguments_mem");
|
|
||||||
new llvm::StoreInst(irFunc->_arguments, argumentsmem, gIR->scopebb());
|
|
||||||
irFunc->_arguments = argumentsmem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// output function body
|
// output function body
|
||||||
|
|
|
@ -174,6 +174,42 @@ LLValue* DtoGcMalloc(Loc& loc, LLType* lltype, const char* name)
|
||||||
return DtoBitCast(mem, getPtrToType(lltype), name);
|
return DtoBitCast(mem, getPtrToType(lltype), name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LLValue* DtoAllocaDump(DValue* val, const char* name)
|
||||||
|
{
|
||||||
|
return DtoAllocaDump(val->getRVal(), val->getType(), name);
|
||||||
|
}
|
||||||
|
|
||||||
|
LLValue* DtoAllocaDump(DValue* val, Type* asType, const char* name)
|
||||||
|
{
|
||||||
|
return DtoAllocaDump(val->getRVal(), asType, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
LLValue* DtoAllocaDump(DValue* val, LLType* asType, int alignment, const char* name)
|
||||||
|
{
|
||||||
|
return DtoAllocaDump(val->getRVal(), asType, alignment, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
LLValue* DtoAllocaDump(LLValue* val, int alignment, const char* name)
|
||||||
|
{
|
||||||
|
return DtoAllocaDump(val, val->getType(), alignment, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
LLValue* DtoAllocaDump(LLValue* val, Type* asType, const char* name)
|
||||||
|
{
|
||||||
|
return DtoAllocaDump(val, DtoType(asType), asType->alignsize(), name);
|
||||||
|
}
|
||||||
|
|
||||||
|
LLValue* DtoAllocaDump(LLValue* val, LLType* asType, int alignment, const char* name)
|
||||||
|
{
|
||||||
|
LLType* valType = i1ToI8(val->getType());
|
||||||
|
asType = i1ToI8(asType);
|
||||||
|
LLType* allocaType = (
|
||||||
|
getTypeStoreSize(valType) <= getTypeAllocSize(asType) ? asType : valType);
|
||||||
|
LLValue* mem = DtoRawAlloca(allocaType, alignment, name);
|
||||||
|
DtoStoreZextI8(val, DtoBitCast(mem, valType->getPointerTo()));
|
||||||
|
return DtoBitCast(mem, asType->getPointerTo());
|
||||||
|
}
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
/*////////////////////////////////////////////////////////////////////////////////////////
|
/*////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// ASSERT HELPER
|
// ASSERT HELPER
|
||||||
|
@ -1404,11 +1440,8 @@ LLValue* makeLValue(Loc& loc, DValue* value)
|
||||||
needsMemory = false;
|
needsMemory = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (needsMemory) {
|
if (needsMemory)
|
||||||
LLValue* tmp = DtoAlloca(valueType, ".makelvaluetmp");
|
valuePointer = DtoAllocaDump(value, ".makelvaluetmp");
|
||||||
DtoStoreZextI8(valuePointer, tmp);
|
|
||||||
valuePointer = tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
return valuePointer;
|
return valuePointer;
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,6 +37,13 @@ llvm::AllocaInst* DtoArrayAlloca(Type* type, unsigned arraysize, const char* nam
|
||||||
llvm::AllocaInst* DtoRawAlloca(LLType* lltype, size_t alignment, const char* name = "");
|
llvm::AllocaInst* DtoRawAlloca(LLType* lltype, size_t alignment, const char* name = "");
|
||||||
LLValue* DtoGcMalloc(Loc& loc, LLType* lltype, const char* name = "");
|
LLValue* DtoGcMalloc(Loc& loc, LLType* lltype, const char* name = "");
|
||||||
|
|
||||||
|
LLValue* DtoAllocaDump(DValue* val, const char* name = "");
|
||||||
|
LLValue* DtoAllocaDump(DValue* val, Type* asType, const char* name = "");
|
||||||
|
LLValue* DtoAllocaDump(DValue* val, LLType* asType, int alignment = 0, const char* name = "");
|
||||||
|
LLValue* DtoAllocaDump(LLValue* val, int alignment = 0, const char* name = "");
|
||||||
|
LLValue* DtoAllocaDump(LLValue* val, Type* asType, const char* name = "");
|
||||||
|
LLValue* DtoAllocaDump(LLValue* val, LLType* asType, int alignment = 0, const char* name = "");
|
||||||
|
|
||||||
// assertion generator
|
// assertion generator
|
||||||
void DtoAssert(Module* M, Loc& loc, DValue* msg);
|
void DtoAssert(Module* M, Loc& loc, DValue* msg);
|
||||||
|
|
||||||
|
|
|
@ -70,7 +70,12 @@ static std::string getProgram(const char *name, const cl::opt<std::string> &opt,
|
||||||
|
|
||||||
std::string getGcc()
|
std::string getGcc()
|
||||||
{
|
{
|
||||||
|
#if defined(__FreeBSD__) && __FreeBSD__ >= 10
|
||||||
|
// Default compiler on FreeBSD 10 is clang
|
||||||
|
return getProgram("clang", gcc, "CC");
|
||||||
|
#else
|
||||||
return getProgram("gcc", gcc, "CC");
|
return getProgram("gcc", gcc, "CC");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string getArchiver()
|
std::string getArchiver()
|
||||||
|
|
|
@ -191,7 +191,7 @@ public:
|
||||||
dval = toElemDtor(ae);
|
dval = toElemDtor(ae);
|
||||||
}
|
}
|
||||||
// do abi specific transformations on the return value
|
// do abi specific transformations on the return value
|
||||||
returnValue = getIrFunc(irs->func()->decl)->irFty.putRet(stmt->exp->type, dval);
|
returnValue = getIrFunc(irs->func()->decl)->irFty.putRet(dval);
|
||||||
}
|
}
|
||||||
|
|
||||||
IF_LOG Logger::cout() << "return value is '" << returnValue << "'\n";
|
IF_LOG Logger::cout() << "return value is '" << returnValue << "'\n";
|
||||||
|
@ -1150,7 +1150,7 @@ public:
|
||||||
if (stmt->key)
|
if (stmt->key)
|
||||||
keyvar = DtoRawVarDeclaration(stmt->key);
|
keyvar = DtoRawVarDeclaration(stmt->key);
|
||||||
else
|
else
|
||||||
keyvar = DtoRawAlloca(keytype, 0, "foreachkey"); // FIXME: align?
|
keyvar = DtoRawAlloca(keytype, 0, "foreachkey");
|
||||||
LLValue* zerokey = LLConstantInt::get(keytype, 0, false);
|
LLValue* zerokey = LLConstantInt::get(keytype, 0, false);
|
||||||
|
|
||||||
// value
|
// value
|
||||||
|
|
|
@ -166,9 +166,9 @@ static void addExplicitArguments(std::vector<LLValue*>& args, AttrSet& attrs,
|
||||||
|
|
||||||
llvm::Value* llVal = NULL;
|
llvm::Value* llVal = NULL;
|
||||||
if (isVararg)
|
if (isVararg)
|
||||||
llVal = irFty.putParam(argType, *irArg, argval);
|
llVal = irFty.putParam(*irArg, argval);
|
||||||
else
|
else
|
||||||
llVal = irFty.putParam(argType, i, argval);
|
llVal = irFty.putParam(i, argval);
|
||||||
|
|
||||||
const size_t llArgIdx = implicitLLArgCount +
|
const size_t llArgIdx = implicitLLArgCount +
|
||||||
(irFty.reverseParams ? explicitLLArgCount - i - 1 : i);
|
(irFty.reverseParams ? explicitLLArgCount - i - 1 : i);
|
||||||
|
@ -412,12 +412,8 @@ errorLoad:
|
||||||
load->setAlignment(getTypeAllocSize(load->getType()));
|
load->setAlignment(getTypeAllocSize(load->getType()));
|
||||||
load->setAtomic(llvm::AtomicOrdering(atomicOrdering));
|
load->setAtomic(llvm::AtomicOrdering(atomicOrdering));
|
||||||
llvm::Value* val = load;
|
llvm::Value* val = load;
|
||||||
if (val->getType() != ptrTy) {
|
if (val->getType() != ptrTy)
|
||||||
llvm::Value* tmp = DtoRawAlloca(val->getType(), 0);
|
val = DtoAllocaDump(val, retType);
|
||||||
DtoStore(val, tmp);
|
|
||||||
tmp = DtoBitCast(tmp, ptrTy->getPointerTo());
|
|
||||||
val = tmp;
|
|
||||||
}
|
|
||||||
result = new DImValue(retType, val);
|
result = new DImValue(retType, val);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -468,11 +464,8 @@ errorCmpxchg:
|
||||||
LLValue* ret = p->ir->CreateAtomicCmpXchg(ptr, cmp, val, llvm::AtomicOrdering(atomicOrdering));
|
LLValue* ret = p->ir->CreateAtomicCmpXchg(ptr, cmp, val, llvm::AtomicOrdering(atomicOrdering));
|
||||||
#endif
|
#endif
|
||||||
llvm::Value* retVal = ret;
|
llvm::Value* retVal = ret;
|
||||||
if (retVal->getType() != retTy) {
|
if (retVal->getType() != retTy)
|
||||||
llvm::Value* tmp = DtoRawAlloca(retVal->getType(), 0);
|
retVal = DtoAllocaDump(retVal, exp3->type);
|
||||||
DtoStore(retVal, tmp);
|
|
||||||
retVal = DtoBitCast(tmp, retTy->getPointerTo());
|
|
||||||
}
|
|
||||||
result = new DImValue(exp3->type, retVal);
|
result = new DImValue(exp3->type, retVal);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -629,29 +622,34 @@ DValue* DtoCallFunction(Loc& loc, Type* resulttype, DValue* fnval, Expressions*
|
||||||
DFuncValue* dfnval = fnval->isFunc();
|
DFuncValue* dfnval = fnval->isFunc();
|
||||||
|
|
||||||
// handle intrinsics
|
// handle intrinsics
|
||||||
bool intrinsic = (dfnval && dfnval->func && DtoIsIntrinsic(dfnval->func));
|
const bool intrinsic = (dfnval && dfnval->func && DtoIsIntrinsic(dfnval->func));
|
||||||
|
|
||||||
// get function type info
|
// get function type info
|
||||||
IrFuncTy& irFty = DtoIrTypeFunction(fnval);
|
IrFuncTy& irFty = DtoIrTypeFunction(fnval);
|
||||||
TypeFunction* tf = DtoTypeFunction(fnval);
|
TypeFunction* const tf = DtoTypeFunction(fnval);
|
||||||
|
Type* const returntype = tf->next;
|
||||||
|
const TY returnTy = returntype->toBasetype()->ty;
|
||||||
|
|
||||||
|
if (resulttype == NULL)
|
||||||
|
resulttype = returntype;
|
||||||
|
|
||||||
// misc
|
// misc
|
||||||
bool retinptr = irFty.arg_sret;
|
bool retinptr = irFty.arg_sret;
|
||||||
bool thiscall = irFty.arg_this;
|
const bool thiscall = irFty.arg_this;
|
||||||
bool delegatecall = (calleeType->toBasetype()->ty == Tdelegate);
|
const bool delegatecall = (calleeType->toBasetype()->ty == Tdelegate);
|
||||||
bool nestedcall = irFty.arg_nest;
|
const bool nestedcall = irFty.arg_nest;
|
||||||
bool dvarargs = irFty.arg_arguments;
|
const bool dvarargs = irFty.arg_arguments;
|
||||||
|
|
||||||
// get callee llvm value
|
// get callee llvm value
|
||||||
LLValue* callable = DtoCallableValue(fnval);
|
LLValue* const callable = DtoCallableValue(fnval);
|
||||||
LLFunctionType* callableTy = DtoExtractFunctionType(callable->getType());
|
LLFunctionType* const callableTy = DtoExtractFunctionType(callable->getType());
|
||||||
assert(callableTy);
|
assert(callableTy);
|
||||||
llvm::CallingConv::ID callconv = gABI->callingConv(callableTy, tf->linkage);
|
const llvm::CallingConv::ID callconv = gABI->callingConv(callableTy, tf->linkage);
|
||||||
|
|
||||||
// IF_LOG Logger::cout() << "callable: " << *callable << '\n';
|
// IF_LOG Logger::cout() << "callable: " << *callable << '\n';
|
||||||
|
|
||||||
// get number of explicit arguments
|
// get number of explicit arguments
|
||||||
size_t n_arguments = arguments ? arguments->dim : 0;
|
const size_t n_arguments = arguments ? arguments->dim : 0;
|
||||||
|
|
||||||
// get llvm argument iterator, for types
|
// get llvm argument iterator, for types
|
||||||
LLFunctionType::param_iterator argTypesBegin = callableTy->param_begin();
|
LLFunctionType::param_iterator argTypesBegin = callableTy->param_begin();
|
||||||
|
@ -800,28 +798,28 @@ DValue* DtoCallFunction(Loc& loc, Type* resulttype, DValue* fnval, Expressions*
|
||||||
// If the function returns a struct or a static array, and the return
|
// If the function returns a struct or a static array, and the return
|
||||||
// value is not a pointer to a struct or a static array, store it to
|
// value is not a pointer to a struct or a static array, store it to
|
||||||
// a stack slot before continuing.
|
// a stack slot before continuing.
|
||||||
Type* dReturnType = tf->next;
|
|
||||||
TY returnTy = dReturnType->toBasetype()->ty;
|
|
||||||
bool storeReturnValueOnStack =
|
bool storeReturnValueOnStack =
|
||||||
(returnTy == Tstruct && !isaPointer(retllval)) ||
|
(returnTy == Tstruct && !isaPointer(retllval)) ||
|
||||||
(returnTy == Tsarray && isaArray(retllval));
|
(returnTy == Tsarray && isaArray(retllval));
|
||||||
|
|
||||||
|
bool retValIsAlloca = false;
|
||||||
|
|
||||||
// Ignore ABI for intrinsics
|
// Ignore ABI for intrinsics
|
||||||
if (!intrinsic && !retinptr)
|
if (!intrinsic && !retinptr)
|
||||||
{
|
{
|
||||||
// do abi specific return value fixups
|
// do abi specific return value fixups
|
||||||
DImValue dretval(dReturnType, retllval);
|
|
||||||
if (storeReturnValueOnStack)
|
if (storeReturnValueOnStack)
|
||||||
{
|
{
|
||||||
Logger::println("Storing return value to stack slot");
|
Logger::println("Storing return value to stack slot");
|
||||||
LLValue* mem = DtoRawAlloca(DtoType(dReturnType), 0);
|
LLValue* mem = DtoAlloca(returntype);
|
||||||
irFty.getRet(dReturnType, &dretval, mem);
|
irFty.getRet(returntype, retllval, mem);
|
||||||
retllval = mem;
|
retllval = mem;
|
||||||
|
retValIsAlloca = true;
|
||||||
storeReturnValueOnStack = false;
|
storeReturnValueOnStack = false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
retllval = irFty.getRet(dReturnType, &dretval);
|
retllval = irFty.getRet(returntype, retllval);
|
||||||
storeReturnValueOnStack =
|
storeReturnValueOnStack =
|
||||||
(returnTy == Tstruct && !isaPointer(retllval)) ||
|
(returnTy == Tstruct && !isaPointer(retllval)) ||
|
||||||
(returnTy == Tsarray && isaArray(retllval));
|
(returnTy == Tsarray && isaArray(retllval));
|
||||||
|
@ -831,19 +829,16 @@ DValue* DtoCallFunction(Loc& loc, Type* resulttype, DValue* fnval, Expressions*
|
||||||
if (storeReturnValueOnStack)
|
if (storeReturnValueOnStack)
|
||||||
{
|
{
|
||||||
Logger::println("Storing return value to stack slot");
|
Logger::println("Storing return value to stack slot");
|
||||||
LLValue* mem = DtoRawAlloca(retllval->getType(), 0);
|
retllval = DtoAllocaDump(retllval, returntype);
|
||||||
DtoStore(retllval, mem);
|
retValIsAlloca = true;
|
||||||
retllval = mem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// repaint the type if necessary
|
// repaint the type if necessary
|
||||||
if (resulttype)
|
|
||||||
{
|
|
||||||
Type* rbase = stripModifiers(resulttype->toBasetype(), true);
|
Type* rbase = stripModifiers(resulttype->toBasetype(), true);
|
||||||
Type* nextbase = stripModifiers(tf->nextOf()->toBasetype(), true);
|
Type* nextbase = stripModifiers(returntype->toBasetype(), true);
|
||||||
if (!rbase->equals(nextbase))
|
if (!rbase->equals(nextbase))
|
||||||
{
|
{
|
||||||
IF_LOG Logger::println("repainting return value from '%s' to '%s'", tf->nextOf()->toChars(), rbase->toChars());
|
IF_LOG Logger::println("repainting return value from '%s' to '%s'", returntype->toChars(), rbase->toChars());
|
||||||
switch(rbase->ty)
|
switch(rbase->ty)
|
||||||
{
|
{
|
||||||
case Tarray:
|
case Tarray:
|
||||||
|
@ -875,11 +870,9 @@ DValue* DtoCallFunction(Loc& loc, Type* resulttype, DValue* fnval, Expressions*
|
||||||
// by value and not in an sret argument, so if the struct
|
// by value and not in an sret argument, so if the struct
|
||||||
// type will be used, give the return value storage here
|
// type will be used, give the return value storage here
|
||||||
// so that we get the right amount of indirections.
|
// so that we get the right amount of indirections.
|
||||||
LLValue* tmp = DtoAlloca(rbase, ".aalvauetmp");
|
|
||||||
LLValue* val = DtoInsertValue(
|
LLValue* val = DtoInsertValue(
|
||||||
llvm::UndefValue::get(DtoType(rbase)), retllval, 0);
|
llvm::UndefValue::get(DtoType(rbase)), retllval, 0);
|
||||||
DtoStore(val, tmp);
|
retllval = DtoAllocaDump(val, rbase, ".aalvaluetmp");
|
||||||
retllval = tmp;
|
|
||||||
retinptr = true;
|
retinptr = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -923,7 +916,6 @@ DValue* DtoCallFunction(Loc& loc, Type* resulttype, DValue* fnval, Expressions*
|
||||||
}
|
}
|
||||||
IF_LOG Logger::cout() << "final return value: " << *retllval << '\n';
|
IF_LOG Logger::cout() << "final return value: " << *retllval << '\n';
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// set calling convention and parameter attributes
|
// set calling convention and parameter attributes
|
||||||
#if LDC_LLVM_VER >= 303
|
#if LDC_LLVM_VER >= 303
|
||||||
|
@ -967,7 +959,7 @@ DValue* DtoCallFunction(Loc& loc, Type* resulttype, DValue* fnval, Expressions*
|
||||||
// if we are returning through a pointer arg
|
// if we are returning through a pointer arg
|
||||||
// or if we are returning a reference
|
// or if we are returning a reference
|
||||||
// make sure we provide a lvalue back!
|
// make sure we provide a lvalue back!
|
||||||
if (retinptr || (tf->isref && returnTy != Tvoid))
|
if (retinptr || (tf->isref && returnTy != Tvoid) || retValIsAlloca)
|
||||||
return new DVarValue(resulttype, retllval);
|
return new DVarValue(resulttype, retllval);
|
||||||
|
|
||||||
return new DImValue(resulttype, retllval);
|
return new DImValue(resulttype, retllval);
|
||||||
|
|
14
gen/toir.cpp
14
gen/toir.cpp
|
@ -302,8 +302,7 @@ public:
|
||||||
if (result && result->getType()->ty != Tvoid &&
|
if (result && result->getType()->ty != Tvoid &&
|
||||||
(result->isIm() || result->isSlice())
|
(result->isIm() || result->isSlice())
|
||||||
) {
|
) {
|
||||||
llvm::AllocaInst* alloca = DtoAlloca(result->getType());
|
LLValue* alloca = DtoAllocaDump(result);
|
||||||
DtoStoreZextI8(result->getRVal(), alloca);
|
|
||||||
result = new DVarValue(result->getType(), alloca);
|
result = new DVarValue(result->getType(), alloca);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1121,9 +1120,7 @@ public:
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
assert(v->isSlice());
|
assert(v->isSlice());
|
||||||
LLValue* rval = v->getRVal();
|
lval = DtoAllocaDump(v, ".tmp_slice_storage");
|
||||||
lval = DtoRawAlloca(rval->getType(), 0, ".tmp_slice_storage");
|
|
||||||
DtoStore(rval, lval);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
IF_LOG Logger::cout() << "lval: " << *lval << '\n';
|
IF_LOG Logger::cout() << "lval: " << *lval << '\n';
|
||||||
|
@ -2589,7 +2586,7 @@ public:
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
llvm::Value* storage = DtoRawAlloca(llStoType, 0, "arrayliteral");
|
llvm::Value* storage = DtoRawAlloca(llStoType, e->type->alignsize(), "arrayliteral");
|
||||||
initializeArrayLiteral(p, e, storage);
|
initializeArrayLiteral(p, e, storage);
|
||||||
result = new DImValue(e->type, storage);
|
result = new DImValue(e->type, storage);
|
||||||
}
|
}
|
||||||
|
@ -2628,7 +2625,7 @@ public:
|
||||||
DtoResolveStruct(e->sd);
|
DtoResolveStruct(e->sd);
|
||||||
|
|
||||||
// alloca a stack slot
|
// alloca a stack slot
|
||||||
e->inProgressMemory = DtoRawAlloca(DtoType(e->type), 0, ".structliteral");
|
e->inProgressMemory = DtoAlloca(e->type, ".structliteral");
|
||||||
|
|
||||||
// fill the allocated struct literal
|
// fill the allocated struct literal
|
||||||
write_struct_literal(e->loc, e->inProgressMemory, e->sd, e->elements);
|
write_struct_literal(e->loc, e->inProgressMemory, e->sd, e->elements);
|
||||||
|
@ -2795,9 +2792,8 @@ public:
|
||||||
LruntimeInit:
|
LruntimeInit:
|
||||||
|
|
||||||
// it should be possible to avoid the temporary in some cases
|
// it should be possible to avoid the temporary in some cases
|
||||||
LLValue* tmp = DtoAlloca(e->type, "aaliteral");
|
LLValue* tmp = DtoAllocaDump(LLConstant::getNullValue(DtoType(e->type)), e->type, "aaliteral");
|
||||||
result = new DVarValue(e->type, tmp);
|
result = new DVarValue(e->type, tmp);
|
||||||
DtoStore(LLConstant::getNullValue(DtoType(e->type)), tmp);
|
|
||||||
|
|
||||||
const size_t n = e->keys->dim;
|
const size_t n = e->keys->dim;
|
||||||
for (size_t i = 0; i<n; ++i)
|
for (size_t i = 0; i<n; ++i)
|
||||||
|
|
|
@ -19,65 +19,70 @@ IrFuncTyArg::IrFuncTyArg(Type* t, bool bref, const AttrBuilder& a)
|
||||||
: type(t), parametersIdx(0),
|
: type(t), parametersIdx(0),
|
||||||
ltype(t != Type::tvoid && bref ? DtoType(t->pointerTo()) : DtoType(t)),
|
ltype(t != Type::tvoid && bref ? DtoType(t->pointerTo()) : DtoType(t)),
|
||||||
attrs(a), byref(bref), rewrite(0)
|
attrs(a), byref(bref), rewrite(0)
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
|
|
||||||
bool IrFuncTyArg::isInReg() const { return attrs.contains(LDC_ATTRIBUTE(InReg)); }
|
bool IrFuncTyArg::isInReg() const { return attrs.contains(LDC_ATTRIBUTE(InReg)); }
|
||||||
bool IrFuncTyArg::isSRet() const { return attrs.contains(LDC_ATTRIBUTE(StructRet)); }
|
bool IrFuncTyArg::isSRet() const { return attrs.contains(LDC_ATTRIBUTE(StructRet)); }
|
||||||
bool IrFuncTyArg::isByVal() const { return attrs.contains(LDC_ATTRIBUTE(ByVal)); }
|
bool IrFuncTyArg::isByVal() const { return attrs.contains(LDC_ATTRIBUTE(ByVal)); }
|
||||||
|
|
||||||
llvm::Value* IrFuncTy::putRet(Type* dty, DValue* val)
|
llvm::Value* IrFuncTy::putRet(DValue* dval)
|
||||||
{
|
{
|
||||||
assert(!arg_sret);
|
assert(!arg_sret);
|
||||||
|
|
||||||
if (ret->rewrite) {
|
if (ret->rewrite) {
|
||||||
Logger::println("Rewrite: putRet");
|
Logger::println("Rewrite: putRet");
|
||||||
LOG_SCOPE
|
LOG_SCOPE
|
||||||
return ret->rewrite->put(dty, val);
|
return ret->rewrite->put(dval);
|
||||||
}
|
|
||||||
return val->getRVal();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
llvm::Value* IrFuncTy::getRet(Type* dty, DValue* val)
|
return dval->getRVal();
|
||||||
|
}
|
||||||
|
|
||||||
|
llvm::Value* IrFuncTy::getRet(Type* dty, LLValue* val)
|
||||||
{
|
{
|
||||||
assert(!arg_sret);
|
assert(!arg_sret);
|
||||||
|
|
||||||
if (ret->rewrite) {
|
if (ret->rewrite) {
|
||||||
Logger::println("Rewrite: getRet");
|
Logger::println("Rewrite: getRet");
|
||||||
LOG_SCOPE
|
LOG_SCOPE
|
||||||
return ret->rewrite->get(dty, val);
|
return ret->rewrite->get(dty, val);
|
||||||
}
|
}
|
||||||
return val->getRVal();
|
|
||||||
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
void IrFuncTy::getRet(Type* dty, DValue* val, llvm::Value* lval)
|
void IrFuncTy::getRet(Type* dty, LLValue* val, LLValue* address)
|
||||||
{
|
{
|
||||||
assert(!arg_sret);
|
assert(!arg_sret);
|
||||||
|
|
||||||
if (ret->rewrite) {
|
if (ret->rewrite) {
|
||||||
Logger::println("Rewrite: getRet (getL)");
|
Logger::println("Rewrite: getRet (getL)");
|
||||||
LOG_SCOPE
|
LOG_SCOPE
|
||||||
ret->rewrite->getL(dty, val, lval);
|
ret->rewrite->getL(dty, val, address);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
DtoStoreZextI8(val->getRVal(), lval);
|
DtoStoreZextI8(val, address);
|
||||||
}
|
}
|
||||||
|
|
||||||
llvm::Value* IrFuncTy::putParam(Type* dty, size_t idx, DValue* val)
|
llvm::Value* IrFuncTy::putParam(size_t idx, DValue* dval)
|
||||||
{
|
{
|
||||||
assert(idx < args.size() && "invalid putParam");
|
assert(idx < args.size() && "invalid putParam");
|
||||||
return putParam(dty, *args[idx], val);
|
return putParam(*args[idx], dval);
|
||||||
}
|
}
|
||||||
|
|
||||||
llvm::Value* IrFuncTy::putParam(Type* dty, const IrFuncTyArg& arg, DValue* val)
|
llvm::Value* IrFuncTy::putParam(const IrFuncTyArg& arg, DValue* dval)
|
||||||
{
|
{
|
||||||
if (arg.rewrite) {
|
if (arg.rewrite) {
|
||||||
Logger::println("Rewrite: putParam");
|
Logger::println("Rewrite: putParam");
|
||||||
LOG_SCOPE
|
LOG_SCOPE
|
||||||
return arg.rewrite->put(dty, val);
|
return arg.rewrite->put(dval);
|
||||||
}
|
|
||||||
return val->getRVal();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void IrFuncTy::getParam(Type* dty, size_t idx, DValue* val, llvm::Value* lval)
|
return dval->getRVal();
|
||||||
|
}
|
||||||
|
|
||||||
|
void IrFuncTy::getParam(Type* dty, size_t idx, LLValue* val, LLValue* address)
|
||||||
{
|
{
|
||||||
assert(idx < args.size() && "invalid getParam");
|
assert(idx < args.size() && "invalid getParam");
|
||||||
|
|
||||||
|
@ -85,9 +90,9 @@ void IrFuncTy::getParam(Type* dty, size_t idx, DValue* val, llvm::Value* lval)
|
||||||
{
|
{
|
||||||
Logger::println("Rewrite: getParam (getL)");
|
Logger::println("Rewrite: getParam (getL)");
|
||||||
LOG_SCOPE
|
LOG_SCOPE
|
||||||
args[idx]->rewrite->getL(dty, val, lval);
|
args[idx]->rewrite->getL(dty, val, address);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
DtoStoreZextI8(val->getRVal(), lval);
|
DtoStoreZextI8(val, address);
|
||||||
}
|
}
|
||||||
|
|
|
@ -133,13 +133,13 @@ struct IrFuncTy
|
||||||
tag(NULL)
|
tag(NULL)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
llvm::Value* putRet(Type* dty, DValue* dval);
|
llvm::Value* putRet(DValue* dval);
|
||||||
llvm::Value* getRet(Type* dty, DValue* dval);
|
llvm::Value* getRet(Type* dty, llvm::Value* val);
|
||||||
void getRet(Type* dty, DValue* dval, llvm::Value* lval);
|
void getRet(Type* dty, llvm::Value* val, llvm::Value* address);
|
||||||
|
|
||||||
llvm::Value* putParam(Type* dty, size_t idx, DValue* dval);
|
llvm::Value* putParam(size_t idx, DValue* dval);
|
||||||
llvm::Value* putParam(Type* dty, const IrFuncTyArg& arg, DValue* dval);
|
llvm::Value* putParam(const IrFuncTyArg& arg, DValue* dval);
|
||||||
void getParam(Type* dty, size_t idx, DValue* dval, llvm::Value* lval);
|
void getParam(Type* dty, size_t idx, llvm::Value* val, llvm::Value* address);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -13,7 +13,7 @@ set(BUILD_BC_LIBS OFF CACHE BOOL
|
||||||
set(INCLUDE_INSTALL_DIR ${CMAKE_INSTALL_PREFIX}/include/d CACHE PATH "Path to install D modules to")
|
set(INCLUDE_INSTALL_DIR ${CMAKE_INSTALL_PREFIX}/include/d CACHE PATH "Path to install D modules to")
|
||||||
set(BUILD_SHARED_LIBS OFF CACHE BOOL "Whether to build the runtime as a shared library")
|
set(BUILD_SHARED_LIBS OFF CACHE BOOL "Whether to build the runtime as a shared library")
|
||||||
set(D_FLAGS -w;-d CACHE STRING "Runtime build flags, separated by ;")
|
set(D_FLAGS -w;-d CACHE STRING "Runtime build flags, separated by ;")
|
||||||
set(D_FLAGS_DEBUG -g CACHE STRING "Runtime build flags (debug libraries), separated by ;")
|
set(D_FLAGS_DEBUG -g;-link-debuglib CACHE STRING "Runtime build flags (debug libraries), separated by ;")
|
||||||
set(D_FLAGS_RELEASE -O3;-release CACHE STRING "Runtime build flags (release libraries), separated by ;")
|
set(D_FLAGS_RELEASE -O3;-release CACHE STRING "Runtime build flags (release libraries), separated by ;")
|
||||||
if(MSVC)
|
if(MSVC)
|
||||||
set(LINK_WITH_MSVCRT ON CACHE BOOL "Link with MSVCRT.lib (DLL) instead of LIBCMT.lib (static)")
|
set(LINK_WITH_MSVCRT ON CACHE BOOL "Link with MSVCRT.lib (DLL) instead of LIBCMT.lib (static)")
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit e2689182f1db1b2dfe3edf1923317a962d8fc5f4
|
Subproject commit 5cedb90e29fdbb4dc76d58c183c8ea7342572b74
|
|
@ -25,11 +25,11 @@ endfunction()
|
||||||
# Would like to specify the "-release" flag for relase builds, but some of the
|
# Would like to specify the "-release" flag for relase builds, but some of the
|
||||||
# tests (e.g. 'testdstress') depend on contracts and invariants being active.
|
# tests (e.g. 'testdstress') depend on contracts and invariants being active.
|
||||||
# Need a solution integrated with d_do_test.
|
# Need a solution integrated with d_do_test.
|
||||||
add_testsuite("-debug" -gc ${host_model})
|
add_testsuite("-debug" "-gc -link-debuglib" ${host_model})
|
||||||
add_testsuite("" -O3 ${host_model})
|
add_testsuite("" -O3 ${host_model})
|
||||||
|
|
||||||
if(MULTILIB AND host_model EQUAL 64)
|
if(MULTILIB AND host_model EQUAL 64)
|
||||||
# Also test in 32 bit mode on x86_64 multilib builds.
|
# Also test in 32 bit mode on x86_64 multilib builds.
|
||||||
add_testsuite("-debug-32" -gc 32)
|
add_testsuite("-debug-32" "-gc -link-debuglib" 32)
|
||||||
add_testsuite("-32" -O3 32)
|
add_testsuite("-32" -O3 32)
|
||||||
endif()
|
endif()
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue