Mercurial > projects > ldc
diff gen/abi.cpp @ 1024:9167d492cbc2
Abstracted more (most) ABI details out of the normal codegen.
author | Tomas Lindquist Olsen <tomas.l.olsen@gmail.com> |
---|---|
date | Tue, 03 Mar 2009 02:51:21 +0100 |
parents | e8c6dbcd33d1 |
children | 0477f98d357e |
line wrap: on
line diff
--- a/gen/abi.cpp Sun Mar 01 22:40:15 2009 +0100 +++ b/gen/abi.cpp Tue Mar 03 02:51:21 2009 +0100 @@ -1,5 +1,7 @@ #include "gen/llvm.h" +#include <algorithm> + #include "mars.h" #include "gen/irstate.h" @@ -8,59 +10,7 @@ #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; -} +#include "ir/irfunction.h" ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// @@ -69,33 +19,28 @@ ////////////////////////////////////////////////////////////////////////////// // simply swap of real/imag parts for proper x87 complex abi -struct X87_complex_swap : ABIRetRewrite +struct X87_complex_swap : ABIRewrite { - LLValue* get(LLValue* v) + LLValue* get(Type*, LLValue* v) { return DtoAggrPairSwap(v); } - LLValue* put(LLValue* v) + LLValue* put(Type*, LLValue* v) { return DtoAggrPairSwap(v); } - const LLType* type(const LLType* t) + const LLType* type(Type*, const LLType* t) { return t; } - bool test(TypeFunction* tf) - { - // extern(D) && is(T:creal) - return (tf->linkage == LINKd && tf->next->toBasetype()->iscomplex()); - } }; ////////////////////////////////////////////////////////////////////////////// -struct X86_cfloat_rewrite : ABIRetRewrite +struct X86_cfloat_rewrite : ABIRewrite { // i64 -> {float,float} - LLValue* get(LLValue* in) + LLValue* get(Type*, LLValue* in) { // extract real part LLValue* rpart = gIR->ir->CreateTrunc(in, LLType::Int32Ty); @@ -111,7 +56,7 @@ } // {float,float} -> i64 - LLValue* put(LLValue* v) + LLValue* put(Type*, LLValue* v) { // extract real LLValue* r = gIR->ir->CreateExtractValue(v, 0); @@ -134,16 +79,41 @@ } // {float,float} -> i64 - const LLType* type(const LLType* t) + const LLType* type(Type*, const LLType* t) { return LLType::Int64Ty; } +}; - // test if rewrite applies to function - bool test(TypeFunction* tf) +////////////////////////////////////////////////////////////////////////////// + +// FIXME: try into eliminating the alloca or if at least check +// if it gets optimized away + +// convert byval struct +// when +struct X86_struct_to_register : ABIRewrite +{ + // int -> struct + LLValue* get(Type* dty, LLValue* v) { - return (tf->linkage != LINKd) - && (tf->next->toBasetype() == Type::tcomplex32); + Logger::println("rewriting int -> struct"); + LLValue* mem = DtoAlloca(DtoType(dty), ".int_to_struct"); + DtoStore(v, DtoBitCast(mem, getPtrToType(v->getType()))); + return DtoLoad(mem); + } + // struct -> int + LLValue* put(Type* dty, LLValue* v) + { + Logger::println("rewriting struct -> int"); + LLValue* mem = DtoAlloca(v->getType(), ".struct_to_int"); + DtoStore(v, mem); + DtoLoad(DtoBitCast(mem, getPtrToType(type(dty, v->getType())))); + } + const LLType* type(Type*, const LLType* t) + { + size_t sz = getTypePaddedSize(t)*8; + return LLIntegerType::get(sz); } }; @@ -151,11 +121,9 @@ struct X86TargetABI : TargetABI { - X86TargetABI() - { - retOps.push_back(new X87_complex_swap); - retOps.push_back(new X86_cfloat_rewrite); - } + X87_complex_swap swapComplex; + X86_cfloat_rewrite cfloatToInt; + X86_struct_to_register structToReg; bool returnInArg(TypeFunction* tf) { @@ -168,6 +136,98 @@ else return (rt->ty == Tstruct || rt->ty == Tcomplex64 || rt->ty == Tcomplex80); } + + bool passByVal(Type* t) + { + return t->toBasetype()->ty == Tstruct; + } + + void rewriteFunctionType(TypeFunction* tf) + { + IrFuncTy* fty = tf->fty; + Type* rt = fty->ret->type->toBasetype(); + + // extern(D) + if (tf->linkage == LINKd) + { + // RETURN VALUE + + // complex {re,im} -> {im,re} + if (rt->iscomplex()) + { + fty->ret->rewrite = &swapComplex; + } + + // IMPLICIT PARAMETERS + + // mark this/nested params inreg + if (fty->arg_this) + { + fty->arg_this->attrs = llvm::Attribute::InReg; + } + else if (fty->arg_nest) + { + fty->arg_nest->attrs = llvm::Attribute::InReg; + } + // otherwise try to mark the last param inreg + else if (!fty->arg_sret && !fty->args.empty()) + { + // The last parameter is passed in EAX rather than being pushed on the stack if the following conditions are met: + // * It fits in EAX. + // * It is not a 3 byte struct. + // * It is not a floating point type. + + IrFuncTyArg* last = fty->args.back(); + Type* lastTy = last->type->toBasetype(); + unsigned sz = lastTy->size(); + + if (last->byref && !last->isByVal()) + { + last->attrs = llvm::Attribute::InReg; + } + else if (!lastTy->isfloating() && (sz == 1 || sz == 2 || sz == 4)) // right? + { + // rewrite the struct into an integer to make inreg work + if (lastTy->ty == Tstruct) + { + last->rewrite = &structToReg; + last->ltype = structToReg.type(last->type, last->ltype); + last->byref = false; + } + last->attrs = llvm::Attribute::InReg; + } + } + + // FIXME: tf->varargs == 1 need to use C calling convention and vararg mechanism to live up to the spec: + // "The caller is expected to clean the stack. _argptr is not passed, it is computed by the callee." + + // EXPLICIT PARAMETERS + + // reverse parameter order + // for non variadics + if (!fty->args.empty() && tf->varargs != 1) + { + fty->reverseParams = true; + } + } + + // extern(C) and all others + else + { + // RETURN VALUE + + // cfloat -> i64 + if (tf->next->toBasetype() == Type::tcomplex32) + { + fty->ret->rewrite = &cfloatToInt; + fty->ret->ltype = LLType::Int64Ty; + } + + // IMPLICIT PARAMETERS + + // EXPLICIT PARAMETERS + } + } }; ////////////////////////////////////////////////////////////////////////////// @@ -176,10 +236,10 @@ ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// -struct X86_64_cfloat_rewrite : ABIRetRewrite +struct X86_64_cfloat_rewrite : ABIRewrite { // {double} -> {float,float} - LLValue* get(LLValue* in) + LLValue* get(Type*, LLValue* in) { // extract double LLValue* v = gIR->ir->CreateExtractValue(in, 0); @@ -200,7 +260,7 @@ } // {float,float} -> {double} - LLValue* put(LLValue* v) + LLValue* put(Type*, LLValue* v) { // extract real LLValue* r = gIR->ir->CreateExtractValue(v, 0); @@ -231,33 +291,41 @@ } // {float,float} -> {double} - const LLType* type(const LLType* t) + const LLType* type(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); - } + X86_64_cfloat_rewrite cfloat_rewrite; bool returnInArg(TypeFunction* tf) { Type* rt = tf->next->toBasetype(); return (rt->ty == Tstruct); } + + bool passByVal(Type* t) + { + return t->toBasetype()->ty == Tstruct; + } + + void rewriteFunctionType(TypeFunction* tf) + { + IrFuncTy* fty = tf->fty; + Type* rt = fty->ret->type->toBasetype(); + + // rewrite cfloat return for !extern(D) + if (tf->linkage != LINKd && rt == Type::tcomplex32) + { + fty->ret->rewrite = &cfloat_rewrite; + fty->ret->ltype = cfloat_rewrite.type(fty->ret->type, fty->ret->ltype); + } + } }; ////////////////////////////////////////////////////////////////////////////// @@ -269,15 +337,19 @@ // Some reasonable defaults for when we don't know what ABI to use. struct UnknownTargetABI : TargetABI { - UnknownTargetABI() + bool returnInArg(TypeFunction* tf) { - // Don't push anything into retOps, assume defaults will be fine. + return (tf->next->toBasetype()->ty == Tstruct); } - bool returnInArg(TypeFunction* tf) + bool passByVal(Type* t) { - Type* rt = tf->next->toBasetype(); - return (rt->ty == Tstruct); + return t->toBasetype()->ty == Tstruct; + } + + void rewriteFunctionType(TypeFunction* t) + { + // why? } };