diff --git a/dmd/declaration.h b/dmd/declaration.h index 836c0719..60dd2d96 100644 --- a/dmd/declaration.h +++ b/dmd/declaration.h @@ -663,6 +663,9 @@ struct FuncDeclaration : Declaration // if this is an array operation it gets a little special attention bool isArrayOp; + + // true if overridden with the pragma(allow_inline); stmt + bool allowInlining; }; struct FuncAliasDeclaration : FuncDeclaration diff --git a/dmd/func.c b/dmd/func.c index a18651ea..aaae4424 100644 --- a/dmd/func.c +++ b/dmd/func.c @@ -80,6 +80,7 @@ FuncDeclaration::FuncDeclaration(Loc loc, Loc endloc, Identifier *id, enum STC s // LDC isArrayOp = false; + allowInlining = false; } Dsymbol *FuncDeclaration::syntaxCopy(Dsymbol *s) diff --git a/dmd/idgen.c b/dmd/idgen.c index 661cc681..99511b85 100644 --- a/dmd/idgen.c +++ b/dmd/idgen.c @@ -224,6 +224,7 @@ Msgtable msgtable[] = { "vaend", "va_end" }, { "vaarg", "va_arg" }, { "ldc" }, + { "allow_inline" }, // For special functions { "tohash", "toHash" }, diff --git a/dmd/statement.c b/dmd/statement.c index c8bfe86a..ccddb463 100644 --- a/dmd/statement.c +++ b/dmd/statement.c @@ -2146,6 +2146,13 @@ Statement *PragmaStatement::semantic(Scope *sc) } #endif } + + // LDC + else if (ident == Id::allow_inline) + { + sc->func->allowInlining = true; + } + else error("unrecognized pragma(%s)", ident->toChars()); diff --git a/dmd/statement.h b/dmd/statement.h index 607d4761..f165d12b 100644 --- a/dmd/statement.h +++ b/dmd/statement.h @@ -161,15 +161,16 @@ struct Statement : Object // Back end virtual void toIR(IRState *irs); - // LDC - virtual void toNakedIR(IRState *irs); - // Avoid dynamic_cast virtual DeclarationStatement *isDeclarationStatement() { return NULL; } virtual CompoundStatement *isCompoundStatement() { return NULL; } virtual ReturnStatement *isReturnStatement() { return NULL; } virtual IfStatement *isIfStatement() { return NULL; } virtual CaseStatement* isCaseStatement() { return NULL; } + + // LDC + virtual void toNakedIR(IRState *irs); + virtual AsmBlockStatement* endsWithAsm(); }; struct ExpStatement : Statement @@ -242,6 +243,7 @@ struct CompoundStatement : Statement // LDC virtual void toNakedIR(IRState *irs); + virtual AsmBlockStatement* endsWithAsm(); virtual CompoundStatement *isCompoundStatement() { return this; } }; @@ -905,6 +907,9 @@ struct AsmBlockStatement : CompoundStatement void toIR(IRState *irs); void toNakedIR(IRState *irs); + AsmBlockStatement* endsWithAsm(); + + llvm::Value* abiret; }; #endif /* DMD_STATEMENT_H */ diff --git a/dmd2/declaration.h b/dmd2/declaration.h index 7e26a2c6..441d694d 100644 --- a/dmd2/declaration.h +++ b/dmd2/declaration.h @@ -675,6 +675,9 @@ struct FuncDeclaration : Declaration // if this is an array operation it gets a little special attention bool isArrayOp; + + // true if overridden with the pragma(allow_inline); stmt + bool allowInlining; }; struct FuncAliasDeclaration : FuncDeclaration diff --git a/dmd2/func.c b/dmd2/func.c index 1b468986..0c99cadb 100644 --- a/dmd2/func.c +++ b/dmd2/func.c @@ -80,6 +80,7 @@ FuncDeclaration::FuncDeclaration(Loc loc, Loc endloc, Identifier *id, enum STC s // LDC isArrayOp = false; + allowInlining = false; } Dsymbol *FuncDeclaration::syntaxCopy(Dsymbol *s) diff --git a/dmd2/idgen.c b/dmd2/idgen.c index 2882abf6..cc46b0bb 100644 --- a/dmd2/idgen.c +++ b/dmd2/idgen.c @@ -240,6 +240,7 @@ Msgtable msgtable[] = { "vaend", "va_end" }, { "vaarg", "va_arg" }, { "ldc" }, + { "allow_inline" }, // For special functions { "tohash", "toHash" }, diff --git a/dmd2/statement.c b/dmd2/statement.c index c4ab1bf1..38f06677 100644 --- a/dmd2/statement.c +++ b/dmd2/statement.c @@ -2197,6 +2197,13 @@ Statement *IfStatement::semantic(Scope *sc) condition = new AssignExp(loc, v, condition); condition = condition->semantic(scd); } + + // LDC + else if (ident == Id::allow_inline) + { + sc->func->allowInlining = true; + } + else scd = sc->push(); ifbody = ifbody->semantic(scd); diff --git a/dmd2/statement.h b/dmd2/statement.h index 98221a83..be6b78e2 100644 --- a/dmd2/statement.h +++ b/dmd2/statement.h @@ -162,15 +162,16 @@ struct Statement : Object // Back end virtual void toIR(IRState *irs); - // LDC - virtual void toNakedIR(IRState *irs); - // Avoid dynamic_cast virtual DeclarationStatement *isDeclarationStatement() { return NULL; } virtual CompoundStatement *isCompoundStatement() { return NULL; } virtual ReturnStatement *isReturnStatement() { return NULL; } virtual IfStatement *isIfStatement() { return NULL; } virtual CaseStatement* isCaseStatement() { return NULL; } + + // LDC + virtual void toNakedIR(IRState *irs); + virtual AsmBlockStatement* endsWithAsm(); }; struct ExpStatement : Statement @@ -245,6 +246,7 @@ struct CompoundStatement : Statement // LDC virtual void toNakedIR(IRState *irs); + virtual AsmBlockStatement* endsWithAsm(); virtual CompoundStatement *isCompoundStatement() { return this; } }; @@ -941,6 +943,9 @@ struct AsmBlockStatement : CompoundStatement void toIR(IRState *irs); virtual void toNakedIR(IRState *irs); + AsmBlockStatement* endsWithAsm(); + + llvm::Value* abiret; }; #endif /* DMD_STATEMENT_H */ diff --git a/gen/aa.cpp b/gen/aa.cpp index 484421c0..7d733e58 100644 --- a/gen/aa.cpp +++ b/gen/aa.cpp @@ -77,7 +77,7 @@ DValue* DtoAAIndex(Loc& loc, Type* type, DValue* aa, DValue* key, bool lvalue) keyti = DtoBitCast(keyti, funcTy->getParamType(1)); // valuesize param - LLValue* valsize = DtoConstSize_t(getABITypeSize(DtoType(type))); + LLValue* valsize = DtoConstSize_t(getTypePaddedSize(DtoType(type))); // pkey param LLValue* pkey = to_pkey(loc, key); diff --git a/gen/arrays.cpp b/gen/arrays.cpp index 43645f73..0bcd04a2 100644 --- a/gen/arrays.cpp +++ b/gen/arrays.cpp @@ -100,7 +100,7 @@ void DtoArrayInit(Loc& loc, DValue* array, DValue* value) // this simplifies codegen later on as llvm null's have no address! 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"); DtoMemSetZero(ptr, nbytes); 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"); args[0] = DtoBitCast(args[0], getVoidPtrType()); args[2] = DtoBitCast(args[2], getVoidPtrType()); - args.push_back(DtoConstSize_t(getABITypeSize(DtoType(arrayelemty)))); + args.push_back(DtoConstSize_t(getTypePaddedSize(DtoType(arrayelemty)))); break; default: @@ -331,7 +331,7 @@ static LLValue* get_slice_ptr(DSliceValue* e, LLValue*& sz) { assert(e->len != 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; } @@ -362,7 +362,7 @@ void DtoStaticArrayCopy(LLValue* dst, LLValue* src) { 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)); } @@ -534,7 +534,7 @@ DSliceValue* DtoCatAssignArray(DValue* arr, Expression* exp) src1 = gIR->ir->CreateGEP(src1,len1,"tmp"); // 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"); DtoMemCpy(src1,src2,bytelen); @@ -570,7 +570,7 @@ DSliceValue* DtoCatArrays(Type* type, Expression* exp1, Expression* exp2) src2 = DtoArrayPtr(e2); // 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"); 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"); - 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"); DtoMemCpy(mem,src1,bytelen); @@ -632,7 +632,7 @@ DSliceValue* DtoCatArrayElement(Type* type, Expression* exp1, Expression* exp2) 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"); DtoMemCpy(mem,src1,bytelen); @@ -769,8 +769,8 @@ LLValue* DtoArrayCastLength(LLValue* len, const LLType* elemty, const LLType* ne assert(elemty); assert(newelemty); - size_t esz = getABITypeSize(elemty); - size_t nsz = getABITypeSize(newelemty); + size_t esz = getTypePaddedSize(elemty); + size_t nsz = getTypePaddedSize(newelemty); if (esz == nsz) return len; diff --git a/gen/asmstmt.cpp b/gen/asmstmt.cpp index db94271a..b1e22f6c 100644 --- a/gen/asmstmt.cpp +++ b/gen/asmstmt.cpp @@ -26,6 +26,7 @@ #include "gen/logger.h" #include "gen/todebug.h" #include "gen/llvmhelpers.h" +#include "gen/functions.h" typedef enum { Arg_Integer, @@ -400,6 +401,8 @@ AsmBlockStatement::AsmBlockStatement(Loc loc, Statements* s) { enclosinghandler = NULL; tf = NULL; + + abiret = NULL; } // 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) { Logger::println("AsmBlockStatement::toIR(): %s", loc.toChars()); LOG_SCOPE; Logger::println("BEGIN ASM"); - // disable inlining - gIR->func()->setNeverInline(); + // disable inlining by default + if (!p->func()->decl->allowInlining) + p->func()->setNeverInline(); // create asm block structure assert(!p->asmBlock); - IRAsmBlock* asmblock = new IRAsmBlock; + IRAsmBlock* asmblock = new IRAsmBlock(this); assert(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 std::vector outargs; std::vector inargs; @@ -571,8 +591,9 @@ void AsmBlockStatement::toIR(IRState* p) std::string in_c; std::string clobbers; std::string code; - size_t asmIdx = 0; + size_t asmIdx = asmblock->retn; + Logger::println("do outputs"); size_t n = asmblock->s.size(); for (size_t i=0; icode, onn+a->in.size(), asmIdx); } + + Logger::println("do inputs"); for (size_t i=0; is[i]; @@ -628,10 +651,18 @@ void AsmBlockStatement::toIR(IRState* p) Logger::println("code = \"%s\"", code.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 types; types.insert(types.end(), outtypes.begin(), outtypes.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()) Logger::cout() << "function type = " << *fty << '\n'; 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(), inargs.begin(), inargs.end()); llvm::CallInst* call = p->ir->CreateCall(ia, args.begin(), args.end(), ""); + if (useabiret) + { + p->asmBlock->asmBlock->abiret = call; + } p->asmBlock = NULL; Logger::println("END ASM"); diff --git a/gen/classes.cpp b/gen/classes.cpp index c37f7ca6..9cfa8ac6 100644 --- a/gen/classes.cpp +++ b/gen/classes.cpp @@ -973,8 +973,8 @@ void DtoInitClass(TypeClass* tc, LLValue* dst) { DtoForceConstInitDsymbol(tc->sym); - size_t presz = 2*getABITypeSize(DtoSize_t()); - uint64_t n = getABITypeSize(tc->ir.type->get()) - presz; + size_t presz = 2*getTypePaddedSize(DtoSize_t()); + uint64_t n = getTypePaddedSize(tc->ir.type->get()) - presz; // set vtable field seperately, this might give better optimization assert(tc->sym->ir.irStruct->vtbl); @@ -1494,7 +1494,7 @@ void DtoDefineClassInfo(ClassDeclaration* cd) { c = DtoBitCast(ir->init, voidPtr); //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); } inits.push_back(c); diff --git a/gen/functions.cpp b/gen/functions.cpp index aa94dd44..4e2f6e1f 100644 --- a/gen/functions.cpp +++ b/gen/functions.cpp @@ -907,6 +907,10 @@ void DtoDefineFunction(FuncDeclaration* fd) // output function body 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 // in automatically, so we do it here. if (!gIR->scopereturned()) { @@ -917,12 +921,23 @@ void DtoDefineFunction(FuncDeclaration* fd) } else { if (!fd->isMain()) - llvm::ReturnInst::Create(llvm::UndefValue::get(func->getReturnType()), gIR->scopebb()); + { + 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()); + } + } else llvm::ReturnInst::Create(llvm::Constant::getNullValue(func->getReturnType()), gIR->scopebb()); } } +// std::cout << *func << std::endl; + // erase alloca point allocaPoint->eraseFromParent(); allocaPoint = 0; @@ -934,28 +949,9 @@ void DtoDefineFunction(FuncDeclaration* fd) assert(!func->getBasicBlockList().empty()); 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(); + +// std::cout << *func << std::endl; } ////////////////////////////////////////////////////////////////////////////////////////// diff --git a/gen/functions.h b/gen/functions.h index 1d31c6f4..7c433b96 100644 --- a/gen/functions.h +++ b/gen/functions.h @@ -9,7 +9,9 @@ const llvm::FunctionType* DtoBaseFunctionType(FuncDeclaration* fdecl); void DtoResolveFunction(FuncDeclaration* fdecl); void DtoDeclareFunction(FuncDeclaration* fdecl); void DtoDefineFunction(FuncDeclaration* fd); + void DtoDefineNakedFunction(FuncDeclaration* fd); +void emitABIReturnAsmStmt(IRAsmBlock* asmblock, Loc loc, FuncDeclaration* fdecl); DValue* DtoArgument(Argument* fnarg, Expression* argexp); void DtoVariadicArgument(Expression* argexp, LLValue* dst); diff --git a/gen/irstate.h b/gen/irstate.h index a8b378dd..84af9056 100644 --- a/gen/irstate.h +++ b/gen/irstate.h @@ -2,6 +2,7 @@ #define LDC_GEN_IRSTATE_H #include +#include #include #include @@ -78,11 +79,17 @@ struct IRAsmStmt struct IRAsmBlock { - std::vector s; + std::deque s; std::set clobs; // stores the labels within the asm block std::vector 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 diff --git a/gen/llvmhelpers.cpp b/gen/llvmhelpers.cpp index fe95aaaa..b77e0948 100644 --- a/gen/llvmhelpers.cpp +++ b/gen/llvmhelpers.cpp @@ -1486,7 +1486,6 @@ LLConstant* DtoConstExpInit(Loc loc, Type* type, Expression* exp) return exp->toConstElem(gIR); } - ////////////////////////////////////////////////////////////////////////////////////////// void DtoAnnotation(const char* str) diff --git a/gen/naked.cpp b/gen/naked.cpp index fb75c0e5..ffb967b7 100644 --- a/gen/naked.cpp +++ b/gen/naked.cpp @@ -9,6 +9,7 @@ #include "gen/logger.h" #include "gen/irstate.h" #include "gen/llvmhelpers.h" +#include "gen/tollvm.h" ////////////////////////////////////////////////////////////////////////////////////////// @@ -164,3 +165,63 @@ void DtoDefineNakedFunction(FuncDeclaration* fd) 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); +} diff --git a/gen/statements.cpp b/gen/statements.cpp index 7d83a283..eb1676f1 100644 --- a/gen/statements.cpp +++ b/gen/statements.cpp @@ -81,6 +81,12 @@ void ReturnStatement::toIR(IRState* p) LLValue* v = e->getRVal(); delete e; + // swap real/imag parts on a x87 + if (global.params.cpu == ARCHx86 && exp->type->toBasetype()->iscomplex()) + { + v = DtoAggrPairSwap(v); + } + if (Logger::enabled()) Logger::cout() << "return value is '" <<*v << "'\n"; @@ -1198,6 +1204,9 @@ void LabelStatement::toIR(IRState* p) a->code += ":"; p->asmBlock->s.push_back(a); p->asmBlock->internalLabels.push_back(ident); + + // disable inlining + gIR->func()->setNeverInline(); } else { @@ -1453,3 +1462,31 @@ STUBST(Statement); #if DMDV2 STUBST(PragmaStatement); #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; +} diff --git a/gen/structs.cpp b/gen/structs.cpp index fbebcbcd..a5e1da47 100644 --- a/gen/structs.cpp +++ b/gen/structs.cpp @@ -239,7 +239,7 @@ Lpadding: } // 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 // FIXME: this should be handled in the loop above as well @@ -292,7 +292,7 @@ Lpadding2: { Logger::cout() << "constant struct initializer: " << *c << '\n'; } - assert(getABITypeSize(c->getType()) == structsize); + assert(getTypePaddedSize(c->getType()) == structsize); return c; } @@ -406,7 +406,7 @@ std::vector DtoStructLiteralValues(const StructDeclaration* sd, co // fill out rest with default initializers 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 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); } - unsigned llvmSize = (unsigned)getABITypeSize(ST); + unsigned llvmSize = (unsigned)getTypePaddedSize(ST); unsigned dmdSize = (unsigned)sd->type->size(); printf(" llvm size: %u dmd size: %u\n", llvmSize, dmdSize); assert(llvmSize == dmdSize); @@ -685,7 +685,7 @@ LLValue* DtoStructEquals(TOK op, DValue* lhs, DValue* rhs) cmpop = llvm::ICmpInst::ICMP_NE; // call memcmp - size_t sz = getABITypeSize(DtoType(t)); + size_t sz = getTypePaddedSize(DtoType(t)); LLValue* val = DtoMemCmp(lhs->getRVal(), rhs->getRVal(), DtoConstSize_t(sz)); return gIR->ir->CreateICmp(cmpop, val, LLConstantInt::get(val->getType(), 0, false), "tmp"); } diff --git a/gen/tocall.cpp b/gen/tocall.cpp index 6a191d0b..004d5e21 100644 --- a/gen/tocall.cpp +++ b/gen/tocall.cpp @@ -136,7 +136,7 @@ void DtoBuildDVarArgList(std::vector& args, std::vectordata[i]; vtypes.push_back(DtoType(argexp->type)); - size_t sz = getABITypeSize(vtypes.back()); + size_t sz = getTypePaddedSize(vtypes.back()); if (sz < PTRSIZE) vtypes.back() = DtoSize_t(); } @@ -463,6 +463,12 @@ DValue* DtoCallFunction(Loc& loc, Type* resulttype, DValue* fnval, Expressions* // get return value 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 if (resulttype) { diff --git a/gen/tollvm.cpp b/gen/tollvm.cpp index ddf0fd31..73b61e28 100644 --- a/gen/tollvm.cpp +++ b/gen/tollvm.cpp @@ -419,11 +419,9 @@ void DtoMemSetZero(LLValue* dst, LLValue* nbytes) { dst = DtoBitCast(dst,getVoidPtrType()); - llvm::Function* fn; - if (global.params.is64bit) - fn = GET_INTRINSIC_DECL(memset_i64); - else - fn = GET_INTRINSIC_DECL(memset_i32); + const LLType* intTy = DtoSize_t(); + llvm::Function* fn = llvm::Intrinsic::getDeclaration(gIR->module, + llvm::Intrinsic::memset, &intTy, 1); 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()); src = DtoBitCast(src,getVoidPtrType()); - llvm::Function* fn; - if (global.params.is64bit) - fn = GET_INTRINSIC_DECL(memcpy_i64); - else - fn = GET_INTRINSIC_DECL(memcpy_i32); + const LLType* intTy = DtoSize_t(); + llvm::Function* fn = llvm::Intrinsic::getDeclaration(gIR->module, + llvm::Intrinsic::memcpy, &intTy, 1); gIR->ir->CreateCall4(fn, dst, src, nbytes, DtoConstUint(0), ""); } @@ -700,9 +696,9 @@ size_t getTypeStoreSize(const LLType* 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'; return sz; } @@ -728,7 +724,7 @@ const LLType* getBiggestType(const LLType** begin, size_t n) { const LLType* T = *begin; - size_t sz = getABITypeSize(T); + size_t sz = getTypePaddedSize(T); size_t ali = getABITypeAlign(T); if (sz > bigSize || (sz == bigSize && ali > bigAlign)) { @@ -881,3 +877,11 @@ LLValue* DtoAggrPaint(LLValue* aggr, const LLType* as) V = DtoBitCast(V, as->getContainedType(1)); 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"); +} diff --git a/gen/tollvm.h b/gen/tollvm.h index ad407b86..8da71a39 100644 --- a/gen/tollvm.h +++ b/gen/tollvm.h @@ -92,7 +92,7 @@ LLConstant* getNullValue(const LLType* t); // type sizes size_t getTypeBitSize(const LLType* t); size_t getTypeStoreSize(const LLType* t); -size_t getABITypeSize(const LLType* t); +size_t getTypePaddedSize(const LLType* t); // type alignments 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(LLValue* V1, LLValue* V2, const char* name = 0); LLValue* DtoAggrPaint(LLValue* aggr, const LLType* as); +LLValue* DtoAggrPairSwap(LLValue* aggr); /** * Generates a call to llvm.memset.i32 (or i64 depending on architecture). diff --git a/gen/toobj.cpp b/gen/toobj.cpp index c6bedfb0..5a3e6e6b 100644 --- a/gen/toobj.cpp +++ b/gen/toobj.cpp @@ -255,7 +255,7 @@ void Module::genobjfile(int multiobj) Logger::println("Writing native asm to: %s\n", spath.c_str()); 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); } diff --git a/ir/irstruct.cpp b/ir/irstruct.cpp index e87ee190..709e485d 100644 --- a/ir/irstruct.cpp +++ b/ir/irstruct.cpp @@ -328,7 +328,7 @@ void IrStruct::buildDefaultConstInit(std::vector& inits) // 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? - size_t structsize = getABITypeSize(structtype); + size_t structsize = getTypePaddedSize(structtype); if (structsize > lastoffset+lastsize) { diff --git a/tests/mini/asm3.d b/tests/mini/asm3.d index 517b5e05..c5e8c6d4 100644 --- a/tests/mini/asm3.d +++ b/tests/mini/asm3.d @@ -8,21 +8,20 @@ void main() printf(fmt); version (LLVM_InlineAsm_X86) { - asm - { - push fmt; - call printf; - pop EAX; - } + asm + { + push fmt; + call printf; + pop EAX; + } } else version(LLVM_InlineAsm_X86_64) { asm { - movq RDI, fmt; - xor AL, AL; - call printf; + movq RDI, fmt; + xor AL, AL; + call printf; } } - } diff --git a/tests/mini/asm5.d b/tests/mini/asm5.d new file mode 100644 index 00000000..12b1c06f --- /dev/null +++ b/tests/mini/asm5.d @@ -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); +} diff --git a/tests/mini/asm8.d b/tests/mini/asm8.d new file mode 100644 index 00000000..f813f288 --- /dev/null +++ b/tests/mini/asm8.d @@ -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*, ...);