mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-02 08:01:11 +03:00
SWITCHED TO LLVM 2.5 !
Applied patch from ticket #129 to compile against latest LLVM. Thanks Frits van Bommel. Fixed implicit return by asm block at the end of a function on x86-32. Other architectures will produce an error at the moment. Adding support for new targets is fairly simple. Fixed return calling convention for complex numbers, ST and ST(1) were switched around. Added some testcases. I've run a dstress test and there are no regressions. However, the runtime does not seem to compile with symbolic debug information. -O3 -release -inline works well and is what I used for the dstress run. Tango does not compile, a small workaround is needed in tango.io.digest.Digest.Digest.hexDigest. See ticket #206 .
This commit is contained in:
parent
3f7c7c5327
commit
fc480b7fd8
29 changed files with 404 additions and 81 deletions
|
@ -663,6 +663,9 @@ struct FuncDeclaration : Declaration
|
||||||
|
|
||||||
// if this is an array operation it gets a little special attention
|
// if this is an array operation it gets a little special attention
|
||||||
bool isArrayOp;
|
bool isArrayOp;
|
||||||
|
|
||||||
|
// true if overridden with the pragma(allow_inline); stmt
|
||||||
|
bool allowInlining;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FuncAliasDeclaration : FuncDeclaration
|
struct FuncAliasDeclaration : FuncDeclaration
|
||||||
|
|
|
@ -80,6 +80,7 @@ FuncDeclaration::FuncDeclaration(Loc loc, Loc endloc, Identifier *id, enum STC s
|
||||||
|
|
||||||
// LDC
|
// LDC
|
||||||
isArrayOp = false;
|
isArrayOp = false;
|
||||||
|
allowInlining = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Dsymbol *FuncDeclaration::syntaxCopy(Dsymbol *s)
|
Dsymbol *FuncDeclaration::syntaxCopy(Dsymbol *s)
|
||||||
|
|
|
@ -224,6 +224,7 @@ Msgtable msgtable[] =
|
||||||
{ "vaend", "va_end" },
|
{ "vaend", "va_end" },
|
||||||
{ "vaarg", "va_arg" },
|
{ "vaarg", "va_arg" },
|
||||||
{ "ldc" },
|
{ "ldc" },
|
||||||
|
{ "allow_inline" },
|
||||||
|
|
||||||
// For special functions
|
// For special functions
|
||||||
{ "tohash", "toHash" },
|
{ "tohash", "toHash" },
|
||||||
|
|
|
@ -2146,6 +2146,13 @@ Statement *PragmaStatement::semantic(Scope *sc)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LDC
|
||||||
|
else if (ident == Id::allow_inline)
|
||||||
|
{
|
||||||
|
sc->func->allowInlining = true;
|
||||||
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
error("unrecognized pragma(%s)", ident->toChars());
|
error("unrecognized pragma(%s)", ident->toChars());
|
||||||
|
|
||||||
|
|
|
@ -161,15 +161,16 @@ struct Statement : Object
|
||||||
// Back end
|
// Back end
|
||||||
virtual void toIR(IRState *irs);
|
virtual void toIR(IRState *irs);
|
||||||
|
|
||||||
// LDC
|
|
||||||
virtual void toNakedIR(IRState *irs);
|
|
||||||
|
|
||||||
// Avoid dynamic_cast
|
// Avoid dynamic_cast
|
||||||
virtual DeclarationStatement *isDeclarationStatement() { return NULL; }
|
virtual DeclarationStatement *isDeclarationStatement() { return NULL; }
|
||||||
virtual CompoundStatement *isCompoundStatement() { return NULL; }
|
virtual CompoundStatement *isCompoundStatement() { return NULL; }
|
||||||
virtual ReturnStatement *isReturnStatement() { return NULL; }
|
virtual ReturnStatement *isReturnStatement() { return NULL; }
|
||||||
virtual IfStatement *isIfStatement() { return NULL; }
|
virtual IfStatement *isIfStatement() { return NULL; }
|
||||||
virtual CaseStatement* isCaseStatement() { return NULL; }
|
virtual CaseStatement* isCaseStatement() { return NULL; }
|
||||||
|
|
||||||
|
// LDC
|
||||||
|
virtual void toNakedIR(IRState *irs);
|
||||||
|
virtual AsmBlockStatement* endsWithAsm();
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ExpStatement : Statement
|
struct ExpStatement : Statement
|
||||||
|
@ -242,6 +243,7 @@ struct CompoundStatement : Statement
|
||||||
|
|
||||||
// LDC
|
// LDC
|
||||||
virtual void toNakedIR(IRState *irs);
|
virtual void toNakedIR(IRState *irs);
|
||||||
|
virtual AsmBlockStatement* endsWithAsm();
|
||||||
|
|
||||||
virtual CompoundStatement *isCompoundStatement() { return this; }
|
virtual CompoundStatement *isCompoundStatement() { return this; }
|
||||||
};
|
};
|
||||||
|
@ -905,6 +907,9 @@ struct AsmBlockStatement : CompoundStatement
|
||||||
|
|
||||||
void toIR(IRState *irs);
|
void toIR(IRState *irs);
|
||||||
void toNakedIR(IRState *irs);
|
void toNakedIR(IRState *irs);
|
||||||
|
AsmBlockStatement* endsWithAsm();
|
||||||
|
|
||||||
|
llvm::Value* abiret;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* DMD_STATEMENT_H */
|
#endif /* DMD_STATEMENT_H */
|
||||||
|
|
|
@ -675,6 +675,9 @@ struct FuncDeclaration : Declaration
|
||||||
|
|
||||||
// if this is an array operation it gets a little special attention
|
// if this is an array operation it gets a little special attention
|
||||||
bool isArrayOp;
|
bool isArrayOp;
|
||||||
|
|
||||||
|
// true if overridden with the pragma(allow_inline); stmt
|
||||||
|
bool allowInlining;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FuncAliasDeclaration : FuncDeclaration
|
struct FuncAliasDeclaration : FuncDeclaration
|
||||||
|
|
|
@ -80,6 +80,7 @@ FuncDeclaration::FuncDeclaration(Loc loc, Loc endloc, Identifier *id, enum STC s
|
||||||
|
|
||||||
// LDC
|
// LDC
|
||||||
isArrayOp = false;
|
isArrayOp = false;
|
||||||
|
allowInlining = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Dsymbol *FuncDeclaration::syntaxCopy(Dsymbol *s)
|
Dsymbol *FuncDeclaration::syntaxCopy(Dsymbol *s)
|
||||||
|
|
|
@ -240,6 +240,7 @@ Msgtable msgtable[] =
|
||||||
{ "vaend", "va_end" },
|
{ "vaend", "va_end" },
|
||||||
{ "vaarg", "va_arg" },
|
{ "vaarg", "va_arg" },
|
||||||
{ "ldc" },
|
{ "ldc" },
|
||||||
|
{ "allow_inline" },
|
||||||
|
|
||||||
// For special functions
|
// For special functions
|
||||||
{ "tohash", "toHash" },
|
{ "tohash", "toHash" },
|
||||||
|
|
|
@ -2197,6 +2197,13 @@ Statement *IfStatement::semantic(Scope *sc)
|
||||||
condition = new AssignExp(loc, v, condition);
|
condition = new AssignExp(loc, v, condition);
|
||||||
condition = condition->semantic(scd);
|
condition = condition->semantic(scd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LDC
|
||||||
|
else if (ident == Id::allow_inline)
|
||||||
|
{
|
||||||
|
sc->func->allowInlining = true;
|
||||||
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
scd = sc->push();
|
scd = sc->push();
|
||||||
ifbody = ifbody->semantic(scd);
|
ifbody = ifbody->semantic(scd);
|
||||||
|
|
|
@ -162,15 +162,16 @@ struct Statement : Object
|
||||||
// Back end
|
// Back end
|
||||||
virtual void toIR(IRState *irs);
|
virtual void toIR(IRState *irs);
|
||||||
|
|
||||||
// LDC
|
|
||||||
virtual void toNakedIR(IRState *irs);
|
|
||||||
|
|
||||||
// Avoid dynamic_cast
|
// Avoid dynamic_cast
|
||||||
virtual DeclarationStatement *isDeclarationStatement() { return NULL; }
|
virtual DeclarationStatement *isDeclarationStatement() { return NULL; }
|
||||||
virtual CompoundStatement *isCompoundStatement() { return NULL; }
|
virtual CompoundStatement *isCompoundStatement() { return NULL; }
|
||||||
virtual ReturnStatement *isReturnStatement() { return NULL; }
|
virtual ReturnStatement *isReturnStatement() { return NULL; }
|
||||||
virtual IfStatement *isIfStatement() { return NULL; }
|
virtual IfStatement *isIfStatement() { return NULL; }
|
||||||
virtual CaseStatement* isCaseStatement() { return NULL; }
|
virtual CaseStatement* isCaseStatement() { return NULL; }
|
||||||
|
|
||||||
|
// LDC
|
||||||
|
virtual void toNakedIR(IRState *irs);
|
||||||
|
virtual AsmBlockStatement* endsWithAsm();
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ExpStatement : Statement
|
struct ExpStatement : Statement
|
||||||
|
@ -245,6 +246,7 @@ struct CompoundStatement : Statement
|
||||||
|
|
||||||
// LDC
|
// LDC
|
||||||
virtual void toNakedIR(IRState *irs);
|
virtual void toNakedIR(IRState *irs);
|
||||||
|
virtual AsmBlockStatement* endsWithAsm();
|
||||||
|
|
||||||
virtual CompoundStatement *isCompoundStatement() { return this; }
|
virtual CompoundStatement *isCompoundStatement() { return this; }
|
||||||
};
|
};
|
||||||
|
@ -941,6 +943,9 @@ struct AsmBlockStatement : CompoundStatement
|
||||||
|
|
||||||
void toIR(IRState *irs);
|
void toIR(IRState *irs);
|
||||||
virtual void toNakedIR(IRState *irs);
|
virtual void toNakedIR(IRState *irs);
|
||||||
|
AsmBlockStatement* endsWithAsm();
|
||||||
|
|
||||||
|
llvm::Value* abiret;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* DMD_STATEMENT_H */
|
#endif /* DMD_STATEMENT_H */
|
||||||
|
|
|
@ -77,7 +77,7 @@ DValue* DtoAAIndex(Loc& loc, Type* type, DValue* aa, DValue* key, bool lvalue)
|
||||||
keyti = DtoBitCast(keyti, funcTy->getParamType(1));
|
keyti = DtoBitCast(keyti, funcTy->getParamType(1));
|
||||||
|
|
||||||
// valuesize param
|
// valuesize param
|
||||||
LLValue* valsize = DtoConstSize_t(getABITypeSize(DtoType(type)));
|
LLValue* valsize = DtoConstSize_t(getTypePaddedSize(DtoType(type)));
|
||||||
|
|
||||||
// pkey param
|
// pkey param
|
||||||
LLValue* pkey = to_pkey(loc, key);
|
LLValue* pkey = to_pkey(loc, key);
|
||||||
|
|
|
@ -100,7 +100,7 @@ void DtoArrayInit(Loc& loc, DValue* array, DValue* value)
|
||||||
// this simplifies codegen later on as llvm null's have no address!
|
// this simplifies codegen later on as llvm null's have no address!
|
||||||
if (isaConstant(val) && isaConstant(val)->isNullValue())
|
if (isaConstant(val) && isaConstant(val)->isNullValue())
|
||||||
{
|
{
|
||||||
size_t X = getABITypeSize(val->getType());
|
size_t X = getTypePaddedSize(val->getType());
|
||||||
LLValue* nbytes = gIR->ir->CreateMul(dim, DtoConstSize_t(X), ".nbytes");
|
LLValue* nbytes = gIR->ir->CreateMul(dim, DtoConstSize_t(X), ".nbytes");
|
||||||
DtoMemSetZero(ptr, nbytes);
|
DtoMemSetZero(ptr, nbytes);
|
||||||
return;
|
return;
|
||||||
|
@ -181,7 +181,7 @@ void DtoArrayInit(Loc& loc, DValue* array, DValue* value)
|
||||||
assert(arrayelemty == valuety && "ArrayInit doesn't work on elem-initialized static arrays");
|
assert(arrayelemty == valuety && "ArrayInit doesn't work on elem-initialized static arrays");
|
||||||
args[0] = DtoBitCast(args[0], getVoidPtrType());
|
args[0] = DtoBitCast(args[0], getVoidPtrType());
|
||||||
args[2] = DtoBitCast(args[2], getVoidPtrType());
|
args[2] = DtoBitCast(args[2], getVoidPtrType());
|
||||||
args.push_back(DtoConstSize_t(getABITypeSize(DtoType(arrayelemty))));
|
args.push_back(DtoConstSize_t(getTypePaddedSize(DtoType(arrayelemty))));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -331,7 +331,7 @@ static LLValue* get_slice_ptr(DSliceValue* e, LLValue*& sz)
|
||||||
{
|
{
|
||||||
assert(e->len != 0);
|
assert(e->len != 0);
|
||||||
const LLType* t = e->ptr->getType()->getContainedType(0);
|
const LLType* t = e->ptr->getType()->getContainedType(0);
|
||||||
sz = gIR->ir->CreateMul(DtoConstSize_t(getABITypeSize(t)), e->len, "tmp");
|
sz = gIR->ir->CreateMul(DtoConstSize_t(getTypePaddedSize(t)), e->len, "tmp");
|
||||||
return e->ptr;
|
return e->ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -362,7 +362,7 @@ void DtoStaticArrayCopy(LLValue* dst, LLValue* src)
|
||||||
{
|
{
|
||||||
Logger::println("StaticArrayCopy");
|
Logger::println("StaticArrayCopy");
|
||||||
|
|
||||||
size_t n = getABITypeSize(dst->getType()->getContainedType(0));
|
size_t n = getTypePaddedSize(dst->getType()->getContainedType(0));
|
||||||
DtoMemCpy(dst, src, DtoConstSize_t(n));
|
DtoMemCpy(dst, src, DtoConstSize_t(n));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -534,7 +534,7 @@ DSliceValue* DtoCatAssignArray(DValue* arr, Expression* exp)
|
||||||
src1 = gIR->ir->CreateGEP(src1,len1,"tmp");
|
src1 = gIR->ir->CreateGEP(src1,len1,"tmp");
|
||||||
|
|
||||||
// memcpy
|
// memcpy
|
||||||
LLValue* elemSize = DtoConstSize_t(getABITypeSize(src2->getType()->getContainedType(0)));
|
LLValue* elemSize = DtoConstSize_t(getTypePaddedSize(src2->getType()->getContainedType(0)));
|
||||||
LLValue* bytelen = gIR->ir->CreateMul(len2, elemSize, "tmp");
|
LLValue* bytelen = gIR->ir->CreateMul(len2, elemSize, "tmp");
|
||||||
DtoMemCpy(src1,src2,bytelen);
|
DtoMemCpy(src1,src2,bytelen);
|
||||||
|
|
||||||
|
@ -570,7 +570,7 @@ DSliceValue* DtoCatArrays(Type* type, Expression* exp1, Expression* exp2)
|
||||||
src2 = DtoArrayPtr(e2);
|
src2 = DtoArrayPtr(e2);
|
||||||
|
|
||||||
// first memcpy
|
// first memcpy
|
||||||
LLValue* elemSize = DtoConstSize_t(getABITypeSize(src1->getType()->getContainedType(0)));
|
LLValue* elemSize = DtoConstSize_t(getTypePaddedSize(src1->getType()->getContainedType(0)));
|
||||||
LLValue* bytelen = gIR->ir->CreateMul(len1, elemSize, "tmp");
|
LLValue* bytelen = gIR->ir->CreateMul(len1, elemSize, "tmp");
|
||||||
DtoMemCpy(mem,src1,bytelen);
|
DtoMemCpy(mem,src1,bytelen);
|
||||||
|
|
||||||
|
@ -613,7 +613,7 @@ DSliceValue* DtoCatArrayElement(Type* type, Expression* exp1, Expression* exp2)
|
||||||
|
|
||||||
mem = gIR->ir->CreateGEP(mem,DtoConstSize_t(1),"tmp");
|
mem = gIR->ir->CreateGEP(mem,DtoConstSize_t(1),"tmp");
|
||||||
|
|
||||||
LLValue* elemSize = DtoConstSize_t(getABITypeSize(src1->getType()->getContainedType(0)));
|
LLValue* elemSize = DtoConstSize_t(getTypePaddedSize(src1->getType()->getContainedType(0)));
|
||||||
LLValue* bytelen = gIR->ir->CreateMul(len1, elemSize, "tmp");
|
LLValue* bytelen = gIR->ir->CreateMul(len1, elemSize, "tmp");
|
||||||
DtoMemCpy(mem,src1,bytelen);
|
DtoMemCpy(mem,src1,bytelen);
|
||||||
|
|
||||||
|
@ -632,7 +632,7 @@ DSliceValue* DtoCatArrayElement(Type* type, Expression* exp1, Expression* exp2)
|
||||||
|
|
||||||
src1 = DtoArrayPtr(e1);
|
src1 = DtoArrayPtr(e1);
|
||||||
|
|
||||||
LLValue* elemSize = DtoConstSize_t(getABITypeSize(src1->getType()->getContainedType(0)));
|
LLValue* elemSize = DtoConstSize_t(getTypePaddedSize(src1->getType()->getContainedType(0)));
|
||||||
LLValue* bytelen = gIR->ir->CreateMul(len1, elemSize, "tmp");
|
LLValue* bytelen = gIR->ir->CreateMul(len1, elemSize, "tmp");
|
||||||
DtoMemCpy(mem,src1,bytelen);
|
DtoMemCpy(mem,src1,bytelen);
|
||||||
|
|
||||||
|
@ -769,8 +769,8 @@ LLValue* DtoArrayCastLength(LLValue* len, const LLType* elemty, const LLType* ne
|
||||||
assert(elemty);
|
assert(elemty);
|
||||||
assert(newelemty);
|
assert(newelemty);
|
||||||
|
|
||||||
size_t esz = getABITypeSize(elemty);
|
size_t esz = getTypePaddedSize(elemty);
|
||||||
size_t nsz = getABITypeSize(newelemty);
|
size_t nsz = getTypePaddedSize(newelemty);
|
||||||
if (esz == nsz)
|
if (esz == nsz)
|
||||||
return len;
|
return len;
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include "gen/logger.h"
|
#include "gen/logger.h"
|
||||||
#include "gen/todebug.h"
|
#include "gen/todebug.h"
|
||||||
#include "gen/llvmhelpers.h"
|
#include "gen/llvmhelpers.h"
|
||||||
|
#include "gen/functions.h"
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
Arg_Integer,
|
Arg_Integer,
|
||||||
|
@ -400,6 +401,8 @@ AsmBlockStatement::AsmBlockStatement(Loc loc, Statements* s)
|
||||||
{
|
{
|
||||||
enclosinghandler = NULL;
|
enclosinghandler = NULL;
|
||||||
tf = NULL;
|
tf = NULL;
|
||||||
|
|
||||||
|
abiret = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// rewrite argument indices to the block scope indices
|
// rewrite argument indices to the block scope indices
|
||||||
|
@ -452,18 +455,21 @@ static void remap_inargs(std::string& insnt, size_t nargs, size_t& idx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LLValue* DtoAggrPairSwap(LLValue* aggr);
|
||||||
|
|
||||||
void AsmBlockStatement::toIR(IRState* p)
|
void AsmBlockStatement::toIR(IRState* p)
|
||||||
{
|
{
|
||||||
Logger::println("AsmBlockStatement::toIR(): %s", loc.toChars());
|
Logger::println("AsmBlockStatement::toIR(): %s", loc.toChars());
|
||||||
LOG_SCOPE;
|
LOG_SCOPE;
|
||||||
Logger::println("BEGIN ASM");
|
Logger::println("BEGIN ASM");
|
||||||
|
|
||||||
// disable inlining
|
// disable inlining by default
|
||||||
gIR->func()->setNeverInline();
|
if (!p->func()->decl->allowInlining)
|
||||||
|
p->func()->setNeverInline();
|
||||||
|
|
||||||
// create asm block structure
|
// create asm block structure
|
||||||
assert(!p->asmBlock);
|
assert(!p->asmBlock);
|
||||||
IRAsmBlock* asmblock = new IRAsmBlock;
|
IRAsmBlock* asmblock = new IRAsmBlock(this);
|
||||||
assert(asmblock);
|
assert(asmblock);
|
||||||
p->asmBlock = asmblock;
|
p->asmBlock = asmblock;
|
||||||
|
|
||||||
|
@ -562,6 +568,20 @@ void AsmBlockStatement::toIR(IRState* p)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// build a fall-off-end-properly asm statement
|
||||||
|
|
||||||
|
FuncDeclaration* thisfunc = p->func()->decl;
|
||||||
|
bool useabiret = false;
|
||||||
|
p->asmBlock->asmBlock->abiret = NULL;
|
||||||
|
if (thisfunc->fbody->endsWithAsm() == this && thisfunc->type->nextOf()->ty != Tvoid)
|
||||||
|
{
|
||||||
|
// there can't be goto forwarders in this case
|
||||||
|
assert(gotoToVal.empty());
|
||||||
|
emitABIReturnAsmStmt(asmblock, loc, thisfunc);
|
||||||
|
useabiret = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// build asm block
|
// build asm block
|
||||||
std::vector<LLValue*> outargs;
|
std::vector<LLValue*> outargs;
|
||||||
std::vector<LLValue*> inargs;
|
std::vector<LLValue*> inargs;
|
||||||
|
@ -571,8 +591,9 @@ void AsmBlockStatement::toIR(IRState* p)
|
||||||
std::string in_c;
|
std::string in_c;
|
||||||
std::string clobbers;
|
std::string clobbers;
|
||||||
std::string code;
|
std::string code;
|
||||||
size_t asmIdx = 0;
|
size_t asmIdx = asmblock->retn;
|
||||||
|
|
||||||
|
Logger::println("do outputs");
|
||||||
size_t n = asmblock->s.size();
|
size_t n = asmblock->s.size();
|
||||||
for (size_t i=0; i<n; ++i)
|
for (size_t i=0; i<n; ++i)
|
||||||
{
|
{
|
||||||
|
@ -590,6 +611,8 @@ void AsmBlockStatement::toIR(IRState* p)
|
||||||
}
|
}
|
||||||
remap_outargs(a->code, onn+a->in.size(), asmIdx);
|
remap_outargs(a->code, onn+a->in.size(), asmIdx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Logger::println("do inputs");
|
||||||
for (size_t i=0; i<n; ++i)
|
for (size_t i=0; i<n; ++i)
|
||||||
{
|
{
|
||||||
IRAsmStmt* a = asmblock->s[i];
|
IRAsmStmt* a = asmblock->s[i];
|
||||||
|
@ -628,10 +651,18 @@ void AsmBlockStatement::toIR(IRState* p)
|
||||||
Logger::println("code = \"%s\"", code.c_str());
|
Logger::println("code = \"%s\"", code.c_str());
|
||||||
Logger::println("constraints = \"%s\"", out_c.c_str());
|
Logger::println("constraints = \"%s\"", out_c.c_str());
|
||||||
|
|
||||||
|
// build return types
|
||||||
|
const LLType* retty;
|
||||||
|
if (asmblock->retn)
|
||||||
|
retty = asmblock->retty;
|
||||||
|
else
|
||||||
|
retty = llvm::Type::VoidTy;
|
||||||
|
|
||||||
|
// build argument types
|
||||||
std::vector<const LLType*> types;
|
std::vector<const LLType*> types;
|
||||||
types.insert(types.end(), outtypes.begin(), outtypes.end());
|
types.insert(types.end(), outtypes.begin(), outtypes.end());
|
||||||
types.insert(types.end(), intypes.begin(), intypes.end());
|
types.insert(types.end(), intypes.begin(), intypes.end());
|
||||||
llvm::FunctionType* fty = llvm::FunctionType::get(llvm::Type::VoidTy, types, false);
|
llvm::FunctionType* fty = llvm::FunctionType::get(retty, types, false);
|
||||||
if (Logger::enabled())
|
if (Logger::enabled())
|
||||||
Logger::cout() << "function type = " << *fty << '\n';
|
Logger::cout() << "function type = " << *fty << '\n';
|
||||||
llvm::InlineAsm* ia = llvm::InlineAsm::get(fty, code, out_c, true);
|
llvm::InlineAsm* ia = llvm::InlineAsm::get(fty, code, out_c, true);
|
||||||
|
@ -640,6 +671,10 @@ void AsmBlockStatement::toIR(IRState* p)
|
||||||
args.insert(args.end(), outargs.begin(), outargs.end());
|
args.insert(args.end(), outargs.begin(), outargs.end());
|
||||||
args.insert(args.end(), inargs.begin(), inargs.end());
|
args.insert(args.end(), inargs.begin(), inargs.end());
|
||||||
llvm::CallInst* call = p->ir->CreateCall(ia, args.begin(), args.end(), "");
|
llvm::CallInst* call = p->ir->CreateCall(ia, args.begin(), args.end(), "");
|
||||||
|
if (useabiret)
|
||||||
|
{
|
||||||
|
p->asmBlock->asmBlock->abiret = call;
|
||||||
|
}
|
||||||
|
|
||||||
p->asmBlock = NULL;
|
p->asmBlock = NULL;
|
||||||
Logger::println("END ASM");
|
Logger::println("END ASM");
|
||||||
|
|
|
@ -973,8 +973,8 @@ void DtoInitClass(TypeClass* tc, LLValue* dst)
|
||||||
{
|
{
|
||||||
DtoForceConstInitDsymbol(tc->sym);
|
DtoForceConstInitDsymbol(tc->sym);
|
||||||
|
|
||||||
size_t presz = 2*getABITypeSize(DtoSize_t());
|
size_t presz = 2*getTypePaddedSize(DtoSize_t());
|
||||||
uint64_t n = getABITypeSize(tc->ir.type->get()) - presz;
|
uint64_t n = getTypePaddedSize(tc->ir.type->get()) - presz;
|
||||||
|
|
||||||
// set vtable field seperately, this might give better optimization
|
// set vtable field seperately, this might give better optimization
|
||||||
assert(tc->sym->ir.irStruct->vtbl);
|
assert(tc->sym->ir.irStruct->vtbl);
|
||||||
|
@ -1494,7 +1494,7 @@ void DtoDefineClassInfo(ClassDeclaration* cd)
|
||||||
{
|
{
|
||||||
c = DtoBitCast(ir->init, voidPtr);
|
c = DtoBitCast(ir->init, voidPtr);
|
||||||
//Logger::cout() << *ir->constInit->getType() << std::endl;
|
//Logger::cout() << *ir->constInit->getType() << std::endl;
|
||||||
size_t initsz = getABITypeSize(ir->init->getType()->getContainedType(0));
|
size_t initsz = getTypePaddedSize(ir->init->getType()->getContainedType(0));
|
||||||
c = DtoConstSlice(DtoConstSize_t(initsz), c);
|
c = DtoConstSlice(DtoConstSize_t(initsz), c);
|
||||||
}
|
}
|
||||||
inits.push_back(c);
|
inits.push_back(c);
|
||||||
|
|
|
@ -907,6 +907,10 @@ void DtoDefineFunction(FuncDeclaration* fd)
|
||||||
// output function body
|
// output function body
|
||||||
fd->fbody->toIR(gIR);
|
fd->fbody->toIR(gIR);
|
||||||
|
|
||||||
|
// TODO: clean up this mess
|
||||||
|
|
||||||
|
// std::cout << *func << std::endl;
|
||||||
|
|
||||||
// llvm requires all basic blocks to end with a TerminatorInst but DMD does not put a return statement
|
// llvm requires all basic blocks to end with a TerminatorInst but DMD does not put a return statement
|
||||||
// in automatically, so we do it here.
|
// in automatically, so we do it here.
|
||||||
if (!gIR->scopereturned()) {
|
if (!gIR->scopereturned()) {
|
||||||
|
@ -917,12 +921,23 @@ void DtoDefineFunction(FuncDeclaration* fd)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (!fd->isMain())
|
if (!fd->isMain())
|
||||||
|
{
|
||||||
|
AsmBlockStatement* asmb = fd->fbody->endsWithAsm();
|
||||||
|
if (asmb) {
|
||||||
|
assert(asmb->abiret);
|
||||||
|
llvm::ReturnInst::Create(asmb->abiret, gIR->scopebb());
|
||||||
|
}
|
||||||
|
else {
|
||||||
llvm::ReturnInst::Create(llvm::UndefValue::get(func->getReturnType()), gIR->scopebb());
|
llvm::ReturnInst::Create(llvm::UndefValue::get(func->getReturnType()), gIR->scopebb());
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
llvm::ReturnInst::Create(llvm::Constant::getNullValue(func->getReturnType()), gIR->scopebb());
|
llvm::ReturnInst::Create(llvm::Constant::getNullValue(func->getReturnType()), gIR->scopebb());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// std::cout << *func << std::endl;
|
||||||
|
|
||||||
// erase alloca point
|
// erase alloca point
|
||||||
allocaPoint->eraseFromParent();
|
allocaPoint->eraseFromParent();
|
||||||
allocaPoint = 0;
|
allocaPoint = 0;
|
||||||
|
@ -934,28 +949,9 @@ void DtoDefineFunction(FuncDeclaration* fd)
|
||||||
assert(!func->getBasicBlockList().empty());
|
assert(!func->getBasicBlockList().empty());
|
||||||
func->getBasicBlockList().pop_back();
|
func->getBasicBlockList().pop_back();
|
||||||
|
|
||||||
// if the last block is empty now, it must be unreachable or it's a bug somewhere else
|
|
||||||
// would be nice to figure out how to assert that this is correct
|
|
||||||
llvm::BasicBlock* lastbb = &func->getBasicBlockList().back();
|
|
||||||
if (lastbb->empty())
|
|
||||||
{
|
|
||||||
new llvm::UnreachableInst(lastbb);
|
|
||||||
}
|
|
||||||
|
|
||||||
// if the last block is not terminated we return a null value or void
|
|
||||||
// for some unknown reason this is needed when a void main() has a inline asm block ...
|
|
||||||
// this should be harmless for well formed code!
|
|
||||||
lastbb = &func->getBasicBlockList().back();
|
|
||||||
if (!lastbb->getTerminator())
|
|
||||||
{
|
|
||||||
Logger::println("adding missing return statement");
|
|
||||||
if (func->getReturnType() == LLType::VoidTy)
|
|
||||||
llvm::ReturnInst::Create(lastbb);
|
|
||||||
else
|
|
||||||
llvm::ReturnInst::Create(llvm::Constant::getNullValue(func->getReturnType()), lastbb);
|
|
||||||
}
|
|
||||||
|
|
||||||
gIR->functions.pop_back();
|
gIR->functions.pop_back();
|
||||||
|
|
||||||
|
// std::cout << *func << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -9,7 +9,9 @@ const llvm::FunctionType* DtoBaseFunctionType(FuncDeclaration* fdecl);
|
||||||
void DtoResolveFunction(FuncDeclaration* fdecl);
|
void DtoResolveFunction(FuncDeclaration* fdecl);
|
||||||
void DtoDeclareFunction(FuncDeclaration* fdecl);
|
void DtoDeclareFunction(FuncDeclaration* fdecl);
|
||||||
void DtoDefineFunction(FuncDeclaration* fd);
|
void DtoDefineFunction(FuncDeclaration* fd);
|
||||||
|
|
||||||
void DtoDefineNakedFunction(FuncDeclaration* fd);
|
void DtoDefineNakedFunction(FuncDeclaration* fd);
|
||||||
|
void emitABIReturnAsmStmt(IRAsmBlock* asmblock, Loc loc, FuncDeclaration* fdecl);
|
||||||
|
|
||||||
DValue* DtoArgument(Argument* fnarg, Expression* argexp);
|
DValue* DtoArgument(Argument* fnarg, Expression* argexp);
|
||||||
void DtoVariadicArgument(Expression* argexp, LLValue* dst);
|
void DtoVariadicArgument(Expression* argexp, LLValue* dst);
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#define LDC_GEN_IRSTATE_H
|
#define LDC_GEN_IRSTATE_H
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <deque>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
|
@ -78,11 +79,17 @@ struct IRAsmStmt
|
||||||
|
|
||||||
struct IRAsmBlock
|
struct IRAsmBlock
|
||||||
{
|
{
|
||||||
std::vector<IRAsmStmt*> s;
|
std::deque<IRAsmStmt*> s;
|
||||||
std::set<std::string> clobs;
|
std::set<std::string> clobs;
|
||||||
|
|
||||||
// stores the labels within the asm block
|
// stores the labels within the asm block
|
||||||
std::vector<Identifier*> internalLabels;
|
std::vector<Identifier*> internalLabels;
|
||||||
|
|
||||||
|
AsmBlockStatement* asmBlock;
|
||||||
|
const LLType* retty;
|
||||||
|
unsigned retn;
|
||||||
|
|
||||||
|
IRAsmBlock(AsmBlockStatement* b) : asmBlock(b), retty(NULL), retn(0) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
// llvm::CallInst and llvm::InvokeInst don't share a common base
|
// llvm::CallInst and llvm::InvokeInst don't share a common base
|
||||||
|
|
|
@ -1486,7 +1486,6 @@ LLConstant* DtoConstExpInit(Loc loc, Type* type, Expression* exp)
|
||||||
return exp->toConstElem(gIR);
|
return exp->toConstElem(gIR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void DtoAnnotation(const char* str)
|
void DtoAnnotation(const char* str)
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include "gen/logger.h"
|
#include "gen/logger.h"
|
||||||
#include "gen/irstate.h"
|
#include "gen/irstate.h"
|
||||||
#include "gen/llvmhelpers.h"
|
#include "gen/llvmhelpers.h"
|
||||||
|
#include "gen/tollvm.h"
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@ -164,3 +165,63 @@ void DtoDefineNakedFunction(FuncDeclaration* fd)
|
||||||
|
|
||||||
gIR->functions.pop_back();
|
gIR->functions.pop_back();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void emitABIReturnAsmStmt(IRAsmBlock* asmblock, Loc loc, FuncDeclaration* fdecl)
|
||||||
|
{
|
||||||
|
Logger::println("emitABIReturnAsmStmt(%s)", fdecl->mangle());
|
||||||
|
LOG_SCOPE;
|
||||||
|
|
||||||
|
IRAsmStmt* as = new IRAsmStmt;
|
||||||
|
|
||||||
|
const LLType* llretTy = DtoType(fdecl->type->nextOf());
|
||||||
|
asmblock->retty = llretTy;
|
||||||
|
asmblock->retn = 1;
|
||||||
|
|
||||||
|
// x86
|
||||||
|
if (global.params.cpu == ARCHx86)
|
||||||
|
{
|
||||||
|
LINK l = fdecl->linkage;
|
||||||
|
assert((l == LINKd || l == LINKc || l == LINKwindows) && "invalid linkage for asm implicit return");
|
||||||
|
|
||||||
|
Type* rt = fdecl->type->nextOf()->toBasetype();
|
||||||
|
if (rt->isintegral() || rt->ty == Tpointer || rt->ty == Tclass || rt->ty == Taarray)
|
||||||
|
{
|
||||||
|
if (rt->size() == 8) {
|
||||||
|
as->out_c = "=A,";
|
||||||
|
} else {
|
||||||
|
as->out_c = "={ax},";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (rt->isfloating())
|
||||||
|
{
|
||||||
|
if (rt->iscomplex()) {
|
||||||
|
as->out_c = "={st},={st(1)},";
|
||||||
|
asmblock->retn = 2;
|
||||||
|
} else {
|
||||||
|
as->out_c = "={st},";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (rt->ty == Tarray || rt->ty == Tdelegate)
|
||||||
|
{
|
||||||
|
as->out_c = "={ax},={dx},";
|
||||||
|
asmblock->retn = 2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
error(loc, "unimplemented return type '%s' for implicit abi return", rt->toChars());
|
||||||
|
fatal();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// unsupported
|
||||||
|
else
|
||||||
|
{
|
||||||
|
error(loc, "this target (%s) does not implement inline asm falling off the end of the function", global.params.targetTriple);
|
||||||
|
fatal();
|
||||||
|
}
|
||||||
|
|
||||||
|
// return values always go in the front
|
||||||
|
asmblock->s.push_front(as);
|
||||||
|
}
|
||||||
|
|
|
@ -81,6 +81,12 @@ void ReturnStatement::toIR(IRState* p)
|
||||||
LLValue* v = e->getRVal();
|
LLValue* v = e->getRVal();
|
||||||
delete e;
|
delete e;
|
||||||
|
|
||||||
|
// swap real/imag parts on a x87
|
||||||
|
if (global.params.cpu == ARCHx86 && exp->type->toBasetype()->iscomplex())
|
||||||
|
{
|
||||||
|
v = DtoAggrPairSwap(v);
|
||||||
|
}
|
||||||
|
|
||||||
if (Logger::enabled())
|
if (Logger::enabled())
|
||||||
Logger::cout() << "return value is '" <<*v << "'\n";
|
Logger::cout() << "return value is '" <<*v << "'\n";
|
||||||
|
|
||||||
|
@ -1198,6 +1204,9 @@ void LabelStatement::toIR(IRState* p)
|
||||||
a->code += ":";
|
a->code += ":";
|
||||||
p->asmBlock->s.push_back(a);
|
p->asmBlock->s.push_back(a);
|
||||||
p->asmBlock->internalLabels.push_back(ident);
|
p->asmBlock->internalLabels.push_back(ident);
|
||||||
|
|
||||||
|
// disable inlining
|
||||||
|
gIR->func()->setNeverInline();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1453,3 +1462,31 @@ STUBST(Statement);
|
||||||
#if DMDV2
|
#if DMDV2
|
||||||
STUBST(PragmaStatement);
|
STUBST(PragmaStatement);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
AsmBlockStatement* Statement::endsWithAsm()
|
||||||
|
{
|
||||||
|
// does not end with inline asm
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
AsmBlockStatement* CompoundStatement::endsWithAsm()
|
||||||
|
{
|
||||||
|
// make the last inner statement decide
|
||||||
|
if (statements && statements->dim)
|
||||||
|
{
|
||||||
|
unsigned last = statements->dim - 1;
|
||||||
|
Statement* s = (Statement*)statements->data[last];
|
||||||
|
if (s) return s->endsWithAsm();
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
AsmBlockStatement* AsmBlockStatement::endsWithAsm()
|
||||||
|
{
|
||||||
|
// yes this is inline asm
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
|
@ -239,7 +239,7 @@ Lpadding:
|
||||||
}
|
}
|
||||||
|
|
||||||
// there might still be padding after the last one, make sure that is defaulted/zeroed as well
|
// there might still be padding after the last one, make sure that is defaulted/zeroed as well
|
||||||
size_t structsize = getABITypeSize(structtype);
|
size_t structsize = getTypePaddedSize(structtype);
|
||||||
|
|
||||||
// if there is space before the next explicit initializer
|
// if there is space before the next explicit initializer
|
||||||
// FIXME: this should be handled in the loop above as well
|
// FIXME: this should be handled in the loop above as well
|
||||||
|
@ -292,7 +292,7 @@ Lpadding2:
|
||||||
{
|
{
|
||||||
Logger::cout() << "constant struct initializer: " << *c << '\n';
|
Logger::cout() << "constant struct initializer: " << *c << '\n';
|
||||||
}
|
}
|
||||||
assert(getABITypeSize(c->getType()) == structsize);
|
assert(getTypePaddedSize(c->getType()) == structsize);
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -406,7 +406,7 @@ std::vector<llvm::Value*> DtoStructLiteralValues(const StructDeclaration* sd, co
|
||||||
|
|
||||||
// fill out rest with default initializers
|
// fill out rest with default initializers
|
||||||
const LLType* structtype = DtoType(sd->type);
|
const LLType* structtype = DtoType(sd->type);
|
||||||
size_t structsize = getABITypeSize(structtype);
|
size_t structsize = getTypePaddedSize(structtype);
|
||||||
|
|
||||||
// FIXME: this could probably share some code with the above
|
// FIXME: this could probably share some code with the above
|
||||||
if (structsize > lastoffset+lastsize)
|
if (structsize > lastoffset+lastsize)
|
||||||
|
@ -558,7 +558,7 @@ void DtoResolveStruct(StructDeclaration* sd)
|
||||||
printf(" index: %u offset: %u\n", v->ir.irField->index, v->ir.irField->unionOffset);
|
printf(" index: %u offset: %u\n", v->ir.irField->index, v->ir.irField->unionOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned llvmSize = (unsigned)getABITypeSize(ST);
|
unsigned llvmSize = (unsigned)getTypePaddedSize(ST);
|
||||||
unsigned dmdSize = (unsigned)sd->type->size();
|
unsigned dmdSize = (unsigned)sd->type->size();
|
||||||
printf(" llvm size: %u dmd size: %u\n", llvmSize, dmdSize);
|
printf(" llvm size: %u dmd size: %u\n", llvmSize, dmdSize);
|
||||||
assert(llvmSize == dmdSize);
|
assert(llvmSize == dmdSize);
|
||||||
|
@ -685,7 +685,7 @@ LLValue* DtoStructEquals(TOK op, DValue* lhs, DValue* rhs)
|
||||||
cmpop = llvm::ICmpInst::ICMP_NE;
|
cmpop = llvm::ICmpInst::ICMP_NE;
|
||||||
|
|
||||||
// call memcmp
|
// call memcmp
|
||||||
size_t sz = getABITypeSize(DtoType(t));
|
size_t sz = getTypePaddedSize(DtoType(t));
|
||||||
LLValue* val = DtoMemCmp(lhs->getRVal(), rhs->getRVal(), DtoConstSize_t(sz));
|
LLValue* val = DtoMemCmp(lhs->getRVal(), rhs->getRVal(), DtoConstSize_t(sz));
|
||||||
return gIR->ir->CreateICmp(cmpop, val, LLConstantInt::get(val->getType(), 0, false), "tmp");
|
return gIR->ir->CreateICmp(cmpop, val, LLConstantInt::get(val->getType(), 0, false), "tmp");
|
||||||
}
|
}
|
||||||
|
|
|
@ -136,7 +136,7 @@ void DtoBuildDVarArgList(std::vector<LLValue*>& args, std::vector<llvm::Attribut
|
||||||
{
|
{
|
||||||
Expression* argexp = (Expression*)arguments->data[i];
|
Expression* argexp = (Expression*)arguments->data[i];
|
||||||
vtypes.push_back(DtoType(argexp->type));
|
vtypes.push_back(DtoType(argexp->type));
|
||||||
size_t sz = getABITypeSize(vtypes.back());
|
size_t sz = getTypePaddedSize(vtypes.back());
|
||||||
if (sz < PTRSIZE)
|
if (sz < PTRSIZE)
|
||||||
vtypes.back() = DtoSize_t();
|
vtypes.back() = DtoSize_t();
|
||||||
}
|
}
|
||||||
|
@ -463,6 +463,12 @@ DValue* DtoCallFunction(Loc& loc, Type* resulttype, DValue* fnval, Expressions*
|
||||||
// get return value
|
// get return value
|
||||||
LLValue* retllval = (retinptr) ? args[0] : call->get();
|
LLValue* retllval = (retinptr) ? args[0] : call->get();
|
||||||
|
|
||||||
|
// swap real/imag parts on a x87
|
||||||
|
if (global.params.cpu == ARCHx86 && tf->nextOf()->toBasetype()->iscomplex())
|
||||||
|
{
|
||||||
|
retllval = DtoAggrPairSwap(retllval);
|
||||||
|
}
|
||||||
|
|
||||||
// repaint the type if necessary
|
// repaint the type if necessary
|
||||||
if (resulttype)
|
if (resulttype)
|
||||||
{
|
{
|
||||||
|
|
|
@ -419,11 +419,9 @@ void DtoMemSetZero(LLValue* dst, LLValue* nbytes)
|
||||||
{
|
{
|
||||||
dst = DtoBitCast(dst,getVoidPtrType());
|
dst = DtoBitCast(dst,getVoidPtrType());
|
||||||
|
|
||||||
llvm::Function* fn;
|
const LLType* intTy = DtoSize_t();
|
||||||
if (global.params.is64bit)
|
llvm::Function* fn = llvm::Intrinsic::getDeclaration(gIR->module,
|
||||||
fn = GET_INTRINSIC_DECL(memset_i64);
|
llvm::Intrinsic::memset, &intTy, 1);
|
||||||
else
|
|
||||||
fn = GET_INTRINSIC_DECL(memset_i32);
|
|
||||||
|
|
||||||
gIR->ir->CreateCall4(fn, dst, DtoConstUbyte(0), nbytes, DtoConstUint(0), "");
|
gIR->ir->CreateCall4(fn, dst, DtoConstUbyte(0), nbytes, DtoConstUint(0), "");
|
||||||
}
|
}
|
||||||
|
@ -435,11 +433,9 @@ void DtoMemCpy(LLValue* dst, LLValue* src, LLValue* nbytes)
|
||||||
dst = DtoBitCast(dst,getVoidPtrType());
|
dst = DtoBitCast(dst,getVoidPtrType());
|
||||||
src = DtoBitCast(src,getVoidPtrType());
|
src = DtoBitCast(src,getVoidPtrType());
|
||||||
|
|
||||||
llvm::Function* fn;
|
const LLType* intTy = DtoSize_t();
|
||||||
if (global.params.is64bit)
|
llvm::Function* fn = llvm::Intrinsic::getDeclaration(gIR->module,
|
||||||
fn = GET_INTRINSIC_DECL(memcpy_i64);
|
llvm::Intrinsic::memcpy, &intTy, 1);
|
||||||
else
|
|
||||||
fn = GET_INTRINSIC_DECL(memcpy_i32);
|
|
||||||
|
|
||||||
gIR->ir->CreateCall4(fn, dst, src, nbytes, DtoConstUint(0), "");
|
gIR->ir->CreateCall4(fn, dst, src, nbytes, DtoConstUint(0), "");
|
||||||
}
|
}
|
||||||
|
@ -700,9 +696,9 @@ size_t getTypeStoreSize(const LLType* t)
|
||||||
return gTargetData->getTypeStoreSize(t);
|
return gTargetData->getTypeStoreSize(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t getABITypeSize(const LLType* t)
|
size_t getTypePaddedSize(const LLType* t)
|
||||||
{
|
{
|
||||||
size_t sz = gTargetData->getABITypeSize(t);
|
size_t sz = gTargetData->getTypePaddedSize(t);
|
||||||
//Logger::cout() << "abi type size of: " << *t << " == " << sz << '\n';
|
//Logger::cout() << "abi type size of: " << *t << " == " << sz << '\n';
|
||||||
return sz;
|
return sz;
|
||||||
}
|
}
|
||||||
|
@ -728,7 +724,7 @@ const LLType* getBiggestType(const LLType** begin, size_t n)
|
||||||
{
|
{
|
||||||
const LLType* T = *begin;
|
const LLType* T = *begin;
|
||||||
|
|
||||||
size_t sz = getABITypeSize(T);
|
size_t sz = getTypePaddedSize(T);
|
||||||
size_t ali = getABITypeAlign(T);
|
size_t ali = getABITypeAlign(T);
|
||||||
if (sz > bigSize || (sz == bigSize && ali > bigAlign))
|
if (sz > bigSize || (sz == bigSize && ali > bigAlign))
|
||||||
{
|
{
|
||||||
|
@ -881,3 +877,11 @@ LLValue* DtoAggrPaint(LLValue* aggr, const LLType* as)
|
||||||
V = DtoBitCast(V, as->getContainedType(1));
|
V = DtoBitCast(V, as->getContainedType(1));
|
||||||
return gIR->ir->CreateInsertValue(res, V, 1, "tmp");
|
return gIR->ir->CreateInsertValue(res, V, 1, "tmp");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LLValue* DtoAggrPairSwap(LLValue* aggr)
|
||||||
|
{
|
||||||
|
Logger::println("swapping aggr pair");
|
||||||
|
LLValue* r = gIR->ir->CreateExtractValue(aggr, 0);
|
||||||
|
LLValue* i = gIR->ir->CreateExtractValue(aggr, 1);
|
||||||
|
return DtoAggrPair(i, r, "swapped");
|
||||||
|
}
|
||||||
|
|
|
@ -92,7 +92,7 @@ LLConstant* getNullValue(const LLType* t);
|
||||||
// type sizes
|
// type sizes
|
||||||
size_t getTypeBitSize(const LLType* t);
|
size_t getTypeBitSize(const LLType* t);
|
||||||
size_t getTypeStoreSize(const LLType* t);
|
size_t getTypeStoreSize(const LLType* t);
|
||||||
size_t getABITypeSize(const LLType* t);
|
size_t getTypePaddedSize(const LLType* t);
|
||||||
|
|
||||||
// type alignments
|
// type alignments
|
||||||
unsigned char getABITypeAlign(const LLType* t);
|
unsigned char getABITypeAlign(const LLType* t);
|
||||||
|
@ -105,6 +105,7 @@ const LLType* getBiggestType(const LLType** begin, size_t n);
|
||||||
LLValue* DtoAggrPair(const LLType* type, LLValue* V1, LLValue* V2, const char* name = 0);
|
LLValue* DtoAggrPair(const LLType* type, LLValue* V1, LLValue* V2, const char* name = 0);
|
||||||
LLValue* DtoAggrPair(LLValue* V1, LLValue* V2, const char* name = 0);
|
LLValue* DtoAggrPair(LLValue* V1, LLValue* V2, const char* name = 0);
|
||||||
LLValue* DtoAggrPaint(LLValue* aggr, const LLType* as);
|
LLValue* DtoAggrPaint(LLValue* aggr, const LLType* as);
|
||||||
|
LLValue* DtoAggrPairSwap(LLValue* aggr);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates a call to llvm.memset.i32 (or i64 depending on architecture).
|
* Generates a call to llvm.memset.i32 (or i64 depending on architecture).
|
||||||
|
|
|
@ -255,7 +255,7 @@ void Module::genobjfile(int multiobj)
|
||||||
Logger::println("Writing native asm to: %s\n", spath.c_str());
|
Logger::println("Writing native asm to: %s\n", spath.c_str());
|
||||||
std::string err;
|
std::string err;
|
||||||
{
|
{
|
||||||
llvm::raw_fd_ostream out(spath.c_str(), err);
|
llvm::raw_fd_ostream out(spath.c_str(), false, err);
|
||||||
write_asm_to_file(Target, *ir.module, out);
|
write_asm_to_file(Target, *ir.module, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -328,7 +328,7 @@ void IrStruct::buildDefaultConstInit(std::vector<llvm::Constant*>& inits)
|
||||||
|
|
||||||
// there might still be padding after the last one, make sure that is zeroed as well
|
// there might still be padding after the last one, make sure that is zeroed as well
|
||||||
// is there space in between last last offset and this one?
|
// is there space in between last last offset and this one?
|
||||||
size_t structsize = getABITypeSize(structtype);
|
size_t structsize = getTypePaddedSize(structtype);
|
||||||
|
|
||||||
if (structsize > lastoffset+lastsize)
|
if (structsize > lastoffset+lastsize)
|
||||||
{
|
{
|
||||||
|
|
|
@ -24,5 +24,4 @@ void main()
|
||||||
call printf;
|
call printf;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
23
tests/mini/asm5.d
Normal file
23
tests/mini/asm5.d
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
int foo()
|
||||||
|
{
|
||||||
|
version(X86)
|
||||||
|
asm { mov EAX, 42; }
|
||||||
|
else static assert(0, "todo");
|
||||||
|
}
|
||||||
|
|
||||||
|
ulong bar()
|
||||||
|
{
|
||||||
|
version(X86)
|
||||||
|
asm { mov EAX, 0xFF; mov EDX, 0xAA; }
|
||||||
|
else static assert(0, "todo");
|
||||||
|
}
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
long l = 1;
|
||||||
|
l = 2;
|
||||||
|
l = 4;
|
||||||
|
l = 8;
|
||||||
|
assert(foo() == 42);
|
||||||
|
assert(bar() == 0x000000AA000000FF);
|
||||||
|
}
|
119
tests/mini/asm8.d
Normal file
119
tests/mini/asm8.d
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
int foo()
|
||||||
|
{
|
||||||
|
version(X86)
|
||||||
|
asm { mov EAX, 42; }
|
||||||
|
else static assert(0, "todo");
|
||||||
|
}
|
||||||
|
|
||||||
|
ulong bar()
|
||||||
|
{
|
||||||
|
version(X86)
|
||||||
|
asm { mov EDX, 0xAA; mov EAX, 0xFF; }
|
||||||
|
else static assert(0, "todo");
|
||||||
|
}
|
||||||
|
|
||||||
|
float onef()
|
||||||
|
{
|
||||||
|
version(X86)
|
||||||
|
asm { fld1; }
|
||||||
|
else static assert(0, "todo");
|
||||||
|
}
|
||||||
|
|
||||||
|
double oned()
|
||||||
|
{
|
||||||
|
version(X86)
|
||||||
|
asm { fld1; }
|
||||||
|
else static assert(0, "todo");
|
||||||
|
}
|
||||||
|
|
||||||
|
real oner()
|
||||||
|
{
|
||||||
|
version(X86)
|
||||||
|
asm { fld1; }
|
||||||
|
else static assert(0, "todo");
|
||||||
|
}
|
||||||
|
|
||||||
|
real two = 2.0;
|
||||||
|
|
||||||
|
creal cr()
|
||||||
|
{
|
||||||
|
version(X86)
|
||||||
|
asm { fld1; fld two; }
|
||||||
|
else static assert(0, "todo");
|
||||||
|
}
|
||||||
|
|
||||||
|
creal cr2()
|
||||||
|
{
|
||||||
|
version(X86)
|
||||||
|
asm
|
||||||
|
{
|
||||||
|
naked;
|
||||||
|
fld1;
|
||||||
|
fld two;
|
||||||
|
ret;
|
||||||
|
}
|
||||||
|
else static assert(0, "todo");
|
||||||
|
}
|
||||||
|
|
||||||
|
void* vp()
|
||||||
|
{
|
||||||
|
version(X86)
|
||||||
|
asm { mov EAX, 0x80; }
|
||||||
|
else static assert(0, "todo");
|
||||||
|
}
|
||||||
|
|
||||||
|
int[int] gaa;
|
||||||
|
|
||||||
|
int[int] aa()
|
||||||
|
{
|
||||||
|
version(X86)
|
||||||
|
asm { mov EAX, gaa; }
|
||||||
|
else static assert(0, "todo");
|
||||||
|
}
|
||||||
|
|
||||||
|
Object gobj;
|
||||||
|
|
||||||
|
Object ob()
|
||||||
|
{
|
||||||
|
version(X86)
|
||||||
|
asm { mov EAX, gobj; }
|
||||||
|
else static assert(0, "todo");
|
||||||
|
}
|
||||||
|
|
||||||
|
char[] ghello = "hello world";
|
||||||
|
|
||||||
|
char[] str()
|
||||||
|
{
|
||||||
|
version(X86)
|
||||||
|
asm { lea ECX, ghello; mov EAX, [ECX]; mov EDX, [ECX+4]; }
|
||||||
|
else static assert(0, "todo");
|
||||||
|
}
|
||||||
|
|
||||||
|
char[] delegate() dg()
|
||||||
|
{
|
||||||
|
version(X86)
|
||||||
|
asm { mov EAX, gobj; lea EDX, Object.toString; }
|
||||||
|
else static assert(0, "todo");
|
||||||
|
}
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
gaa[4] = 5;
|
||||||
|
gobj = new Object;
|
||||||
|
auto adg = &gobj.toString;
|
||||||
|
|
||||||
|
assert(foo() == 42);
|
||||||
|
assert(bar() == 0x000000AA000000FF);
|
||||||
|
assert(onef() == 1);
|
||||||
|
assert(oned() == 1);
|
||||||
|
assert(oner() == 1);
|
||||||
|
assert(cr() == 1+2i);
|
||||||
|
assert(cr2() == 1+2i);
|
||||||
|
assert(vp() == cast(void*)0x80);
|
||||||
|
assert(aa() is gaa);
|
||||||
|
assert(ob() is gobj);
|
||||||
|
assert(str() == "hello world");
|
||||||
|
assert(dg()() == "object.Object");
|
||||||
|
}
|
||||||
|
|
||||||
|
extern(C) int printf(char*, ...);
|
Loading…
Add table
Add a link
Reference in a new issue