# HG changeset patch # User Tomas Lindquist Olsen # Date 1235930465 -3600 # Node ID e8c6dbcd33d1ee64c8043dbb0122dd30657151c5 # Parent a771843e98de8538434f1d1bb01ef2eb3c9c481a - Fixed x86-32 C ABI for complex number return values. - Removed unused code from the ABI class. diff -r a771843e98de -r e8c6dbcd33d1 gen/abi.cpp --- a/gen/abi.cpp Sun Mar 01 11:04:05 2009 +0100 +++ b/gen/abi.cpp Sun Mar 01 19:01:05 2009 +0100 @@ -85,7 +85,65 @@ } bool test(TypeFunction* tf) { - return (tf->next->toBasetype()->iscomplex()); + // extern(D) && is(T:creal) + return (tf->linkage == LINKd && tf->next->toBasetype()->iscomplex()); + } +}; + +////////////////////////////////////////////////////////////////////////////// + +struct X86_cfloat_rewrite : ABIRetRewrite +{ + // i64 -> {float,float} + LLValue* get(LLValue* in) + { + // extract real part + LLValue* rpart = gIR->ir->CreateTrunc(in, LLType::Int32Ty); + rpart = gIR->ir->CreateBitCast(rpart, LLType::FloatTy, ".re"); + + // extract imag part + LLValue* ipart = gIR->ir->CreateLShr(in, LLConstantInt::get(LLType::Int64Ty, 32, false)); + ipart = gIR->ir->CreateTrunc(ipart, LLType::Int32Ty); + ipart = gIR->ir->CreateBitCast(ipart, LLType::FloatTy, ".im"); + + // return {float,float} aggr pair with same bits + return DtoAggrPair(rpart, ipart, ".final_cfloat"); + } + + // {float,float} -> i64 + LLValue* put(LLValue* v) + { + // extract real + LLValue* r = gIR->ir->CreateExtractValue(v, 0); + // cast to i32 + r = gIR->ir->CreateBitCast(r, LLType::Int32Ty); + // zext to i64 + r = gIR->ir->CreateZExt(r, LLType::Int64Ty); + + // extract imag + LLValue* i = gIR->ir->CreateExtractValue(v, 1); + // cast to i32 + i = gIR->ir->CreateBitCast(i, LLType::Int32Ty); + // zext to i64 + i = gIR->ir->CreateZExt(i, LLType::Int64Ty); + // shift up + i = gIR->ir->CreateShl(i, LLConstantInt::get(LLType::Int64Ty, 32, false)); + + // combine and return + return v = gIR->ir->CreateOr(r, i); + } + + // {float,float} -> i64 + const LLType* type(const LLType* t) + { + return LLType::Int64Ty; + } + + // test if rewrite applies to function + bool test(TypeFunction* tf) + { + return (tf->linkage != LINKd) + && (tf->next->toBasetype() == Type::tcomplex32); } }; @@ -96,18 +154,19 @@ X86TargetABI() { retOps.push_back(new X87_complex_swap); + retOps.push_back(new X86_cfloat_rewrite); } - bool returnInArg(Type* t) + bool returnInArg(TypeFunction* tf) { - Type* rt = t->toBasetype(); - return (rt->ty == Tstruct); - } - - bool passByRef(Type* t) - { - t = t->toBasetype(); - return (t->ty == Tstruct || t->ty == Tsarray); + Type* rt = tf->next->toBasetype(); + // D only returns structs on the stack + if (tf->linkage == LINKd) + return (rt->ty == Tstruct); + // other ABI's follow C, which is cdouble and creal returned on the stack + // as well as structs + else + return (rt->ty == Tstruct || rt->ty == Tcomplex64 || rt->ty == Tcomplex80); } }; @@ -194,17 +253,11 @@ retOps.push_back(new X86_64_cfloat_rewrite); } - bool returnInArg(Type* t) + bool returnInArg(TypeFunction* tf) { - Type* rt = t->toBasetype(); + Type* rt = tf->next->toBasetype(); return (rt->ty == Tstruct); } - - bool passByRef(Type* t) - { - t = t->toBasetype(); - return (t->ty == Tstruct || t->ty == Tsarray); - } }; ////////////////////////////////////////////////////////////////////////////// @@ -221,17 +274,11 @@ // Don't push anything into retOps, assume defaults will be fine. } - bool returnInArg(Type* t) + bool returnInArg(TypeFunction* tf) { - Type* rt = t->toBasetype(); + Type* rt = tf->next->toBasetype(); return (rt->ty == Tstruct); } - - bool passByRef(Type* t) - { - t = t->toBasetype(); - return (t->ty == Tstruct || t->ty == Tsarray); - } }; ////////////////////////////////////////////////////////////////////////////// diff -r a771843e98de -r e8c6dbcd33d1 gen/abi.h --- a/gen/abi.h Sun Mar 01 11:04:05 2009 +0100 +++ b/gen/abi.h Sun Mar 01 19:01:05 2009 +0100 @@ -38,8 +38,7 @@ llvm::Value* getRet(TypeFunction* tf, llvm::Value* v); llvm::Value* putRet(TypeFunction* tf, llvm::Value* v); - virtual bool returnInArg(Type* t) = 0; - virtual bool passByRef(Type* t) = 0; + virtual bool returnInArg(TypeFunction* t) = 0; protected: std::vector retOps; diff -r a771843e98de -r e8c6dbcd33d1 gen/functions.cpp --- a/gen/functions.cpp Sun Mar 01 11:04:05 2009 +0100 +++ b/gen/functions.cpp Sun Mar 01 19:01:05 2009 +0100 @@ -79,7 +79,7 @@ } else { - if (gABI->returnInArg(rt)) + if (gABI->returnInArg(f)) { rettype = getPtrToType(DtoType(rt)); actualRettype = LLType::VoidTy; diff -r a771843e98de -r e8c6dbcd33d1 gen/llvmhelpers.cpp --- a/gen/llvmhelpers.cpp Sun Mar 01 11:04:05 2009 +0100 +++ b/gen/llvmhelpers.cpp Sun Mar 01 19:01:05 2009 +0100 @@ -392,6 +392,8 @@ // ASSIGNMENT HELPER (store this in that) ////////////////////////////////////////////////////////////////////////////////////////*/ +// is this a good approach at all ? + void DtoAssign(Loc& loc, DValue* lhs, DValue* rhs) { Logger::println("DtoAssign(...);\n"); @@ -402,7 +404,7 @@ if (t->ty == Tstruct) { if (!t->equals(t2)) { - // TODO: fix this, use 'rhs' for something + // FIXME: use 'rhs' for something !?! DtoAggrZeroInit(lhs->getLVal()); } else { @@ -476,7 +478,7 @@ DtoStore(r, l); } else if (t->iscomplex()) { - LLValue* dst; + LLValue *dst, *src; if (DLRValue* lr = lhs->isLRValue()) { dst = lr->getLVal(); rhs = DtoCastComplex(loc, rhs, lr->getLType()); diff -r a771843e98de -r e8c6dbcd33d1 gen/naked.cpp --- a/gen/naked.cpp Sun Mar 01 11:04:05 2009 +0100 +++ b/gen/naked.cpp Sun Mar 01 19:01:05 2009 +0100 @@ -175,6 +175,13 @@ return b->CreateInsertValue(undef, orig, 0, "asm.ret"); } +static LLValue* x86_cfloatRetFixup(IRBuilderHelper b, LLValue* orig) { + assert(orig->getType() == LLType::DoubleTy); + LLType* retty = LLStructType::get(LLType::DoubleTy, NULL); + LLValue* undef = llvm::UndefValue::get(retty); + return b->CreateInsertValue(undef, orig, 0, "asm.ret"); +} + void emitABIReturnAsmStmt(IRAsmBlock* asmblock, Loc loc, FuncDeclaration* fdecl) { Logger::println("emitABIReturnAsmStmt(%s)", fdecl->mangle()); @@ -204,8 +211,19 @@ else if (rt->isfloating()) { if (rt->iscomplex()) { - as->out_c = "={st},={st(1)},"; - asmblock->retn = 2; + if (fdecl->linkage == LINKd) { + // extern(D) always returns on the FPU stack + as->out_c = "={st},={st(1)},"; + asmblock->retn = 2; + } else if (rt->ty == Tcomplex32) { + // extern(C) cfloat is return as i64 + as->out_c = "=A,"; + asmblock->retty = LLType::Int64Ty; + } else { + // cdouble and creal extern(C) are returned in pointer + // don't add anything! + return; + } } else { as->out_c = "={st},"; } diff -r a771843e98de -r e8c6dbcd33d1 gen/tocall.cpp --- a/gen/tocall.cpp Sun Mar 01 11:04:05 2009 +0100 +++ b/gen/tocall.cpp Sun Mar 01 19:01:05 2009 +0100 @@ -527,5 +527,10 @@ call.setCallingConv(callconv); call.setAttributes(attrlist); + // if we are returning through a pointer arg + // make sure we provide a lvalue back! + if (retinptr) + return new DVarValue(resulttype, retllval); + return new DImValue(resulttype, retllval); } diff -r a771843e98de -r e8c6dbcd33d1 tests/mini/asm8.d --- a/tests/mini/asm8.d Sun Mar 01 11:04:05 2009 +0100 +++ b/tests/mini/asm8.d Sun Mar 01 19:01:05 2009 +0100 @@ -131,7 +131,10 @@ { version(X86) { - asm { fld1; fld two_f; } + asm { + mov EAX, [one_f]; + mov EDX, [two_f]; + } } else version (X86_64) { @@ -180,8 +183,8 @@ asm { naked; - fld1; - fld two_f; + mov EAX, [one_f]; + mov EDX, [two_f]; ret; } }