Mercurial > projects > ldc
diff gen/abi.cpp @ 989:420ef073448d
Forgot new files that were supposed to be in last commit.
author | Tomas Lindquist Olsen <tomas.l.olsen@gmail.com> |
---|---|
date | Thu, 26 Feb 2009 14:13:27 +0100 |
parents | |
children | 223a679053dd |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gen/abi.cpp Thu Feb 26 14:13:27 2009 +0100 @@ -0,0 +1,225 @@ +#include "gen/llvm.h" + +#include "mars.h" + +#include "gen/irstate.h" +#include "gen/llvmhelpers.h" +#include "gen/tollvm.h" +#include "gen/abi.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, 0); + 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, 0); + } + + // test if rewrite applies to function + bool test(TypeFunction* tf) + { + return (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); + } +}; + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +TargetABI * TargetABI::getTarget() +{ + switch(global.params.cpu) + { + case ARCHx86: + return new X86TargetABI; + case ARCHx86_64: + return new X86_64TargetABI; + default: + return NULL; + } +}