Mercurial > projects > ldc
view gen/abi.cpp @ 1002:c749648ed2b8
Fix cfloat return on x86_64: only perform ABI transformation for non-extern(D)
functions.
There's no need to waste cycles with extern(D), which we get to define
ourselves. Fixes tests/mini/asm8.d. (Since the asm abiret code already assumed
{xmm0, xmm1} returns)
author | Frits van Bommel <fvbommel wxs.nl> |
---|---|
date | Thu, 26 Feb 2009 23:35:39 +0100 |
parents | 6e7dc3caccdd |
children | e8c6dbcd33d1 |
line wrap: on
line source
#include "gen/llvm.h" #include "mars.h" #include "gen/irstate.h" #include "gen/llvmhelpers.h" #include "gen/tollvm.h" #include "gen/abi.h" #include "gen/logger.h" ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// ///////////////////// baseclass //////////////////////////// ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // FIXME: Would be nice to come up a better and faster way to do this, right // now I'm more worried about actually making this abstraction work at all ... // It's definitely way overkill with the amount of return value rewrites we // have right now, but I expect this to change with proper x86-64 abi support TargetABI::TargetABI() { } llvm::Value* TargetABI::getRet(TypeFunction* tf, llvm::Value* io) { if (ABIRetRewrite* r = findRetRewrite(tf)) { return r->get(io); } return io; } llvm::Value* TargetABI::putRet(TypeFunction* tf, llvm::Value* io) { if (ABIRetRewrite* r = findRetRewrite(tf)) { return r->put(io); } return io; } const llvm::Type* TargetABI::getRetType(TypeFunction* tf, const llvm::Type* t) { if (ABIRetRewrite* r = findRetRewrite(tf)) { return r->type(t); } return t; } ABIRetRewrite * TargetABI::findRetRewrite(TypeFunction * tf) { size_t n = retOps.size(); if (n) for (size_t i = 0; i < n; i++) { if (retOps[i]->test(tf)) return retOps[i]; } return NULL; } ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// ///////////////////// X86 //////////////////////////// ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // simply swap of real/imag parts for proper x87 complex abi struct X87_complex_swap : ABIRetRewrite { LLValue* get(LLValue* v) { return DtoAggrPairSwap(v); } LLValue* put(LLValue* v) { return DtoAggrPairSwap(v); } const LLType* type(const LLType* t) { return t; } bool test(TypeFunction* tf) { return (tf->next->toBasetype()->iscomplex()); } }; ////////////////////////////////////////////////////////////////////////////// struct X86TargetABI : TargetABI { X86TargetABI() { retOps.push_back(new X87_complex_swap); } bool returnInArg(Type* t) { Type* rt = t->toBasetype(); return (rt->ty == Tstruct); } bool passByRef(Type* t) { t = t->toBasetype(); return (t->ty == Tstruct || t->ty == Tsarray); } }; ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// /////////////////// X86-64 ////////////////////////// ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// struct X86_64_cfloat_rewrite : ABIRetRewrite { // {double} -> {float,float} LLValue* get(LLValue* in) { // extract double LLValue* v = gIR->ir->CreateExtractValue(in, 0); // cast to i64 v = gIR->ir->CreateBitCast(v, LLType::Int64Ty); // extract real part LLValue* rpart = gIR->ir->CreateTrunc(v, LLType::Int32Ty); rpart = gIR->ir->CreateBitCast(rpart, LLType::FloatTy, ".re"); // extract imag part LLValue* ipart = gIR->ir->CreateLShr(v, 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} -> {double} 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 v = gIR->ir->CreateOr(r, i); // cast to double v = gIR->ir->CreateBitCast(v, LLType::DoubleTy); // return {double} const LLType* t = LLStructType::get(LLType::DoubleTy, NULL); LLValue* undef = llvm::UndefValue::get(t); return gIR->ir->CreateInsertValue(undef, v, 0); } // {float,float} -> {double} const LLType* type(const LLType* t) { return LLStructType::get(LLType::DoubleTy, NULL); } // test if rewrite applies to function bool test(TypeFunction* tf) { return (tf->linkage != LINKd) && (tf->next->toBasetype() == Type::tcomplex32); } }; ////////////////////////////////////////////////////////////////////////////// struct X86_64TargetABI : TargetABI { X86_64TargetABI() { retOps.push_back(new X86_64_cfloat_rewrite); } bool returnInArg(Type* t) { Type* rt = t->toBasetype(); return (rt->ty == Tstruct); } bool passByRef(Type* t) { t = t->toBasetype(); return (t->ty == Tstruct || t->ty == Tsarray); } }; ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// /////////////////// Unknown targets ////////////////////////// ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // Some reasonable defaults for when we don't know what ABI to use. struct UnknownTargetABI : TargetABI { UnknownTargetABI() { // Don't push anything into retOps, assume defaults will be fine. } bool returnInArg(Type* t) { Type* rt = t->toBasetype(); return (rt->ty == Tstruct); } bool passByRef(Type* t) { t = t->toBasetype(); return (t->ty == Tstruct || t->ty == Tsarray); } }; ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// TargetABI * TargetABI::getTarget() { switch(global.params.cpu) { case ARCHx86: return new X86TargetABI; case ARCHx86_64: return new X86_64TargetABI; default: Logger::cout() << "WARNING: Unknown ABI, guessing...\n"; return new UnknownTargetABI; } }