Abstracted more (most) ABI details out of the normal codegen.

This commit is contained in:
Tomas Lindquist Olsen 2009-03-03 02:51:21 +01:00
parent 100815c097
commit 5dbe3ee8e2
11 changed files with 488 additions and 434 deletions

View file

@ -2659,14 +2659,9 @@ TypeFunction::TypeFunction(Arguments *parameters, Type *treturn, int varargs, en
this->varargs = varargs; this->varargs = varargs;
this->linkage = linkage; this->linkage = linkage;
this->inuse = 0; this->inuse = 0;
this->retInPtr = false;
this->usesThis = false; // LDC
this->usesNest = false; this->fty = NULL;
this->structInregArg = NULL;
this->retAttrs = 0;
this->thisAttrs = 0;
this->reverseParams = false;
this->firstRealArg = 0;
} }
Type *TypeFunction::syntaxCopy() Type *TypeFunction::syntaxCopy()
@ -2674,13 +2669,6 @@ Type *TypeFunction::syntaxCopy()
Type *treturn = next ? next->syntaxCopy() : NULL; Type *treturn = next ? next->syntaxCopy() : NULL;
Arguments *params = Argument::arraySyntaxCopy(parameters); Arguments *params = Argument::arraySyntaxCopy(parameters);
TypeFunction *t = new TypeFunction(params, treturn, varargs, linkage); TypeFunction *t = new TypeFunction(params, treturn, varargs, linkage);
t->retInPtr = retInPtr;
t->usesThis = usesThis;
t->usesNest = usesNest;
t->retAttrs = retAttrs;
t->thisAttrs = thisAttrs;
t->reverseParams = reverseParams;
t->firstRealArg = firstRealArg;
return t; return t;
} }
@ -5316,7 +5304,6 @@ Argument::Argument(unsigned storageClass, Type *type, Identifier *ident, Express
this->ident = ident; this->ident = ident;
this->storageClass = storageClass; this->storageClass = storageClass;
this->defaultArg = defaultArg; this->defaultArg = defaultArg;
this->llvmAttrs = 0;
} }
Argument *Argument::syntaxCopy() Argument *Argument::syntaxCopy()
@ -5325,7 +5312,6 @@ Argument *Argument::syntaxCopy()
type ? type->syntaxCopy() : NULL, type ? type->syntaxCopy() : NULL,
ident, ident,
defaultArg ? defaultArg->syntaxCopy() : NULL); defaultArg ? defaultArg->syntaxCopy() : NULL);
a->llvmAttrs = llvmAttrs;
return a; return a;
} }

View file

@ -24,6 +24,7 @@
// llvm // llvm
#include "../ir/irtype.h" #include "../ir/irtype.h"
namespace llvm { class Type; } namespace llvm { class Type; }
struct IrFuncTy;
struct Scope; struct Scope;
struct Identifier; struct Identifier;
@ -436,17 +437,7 @@ struct TypeFunction : Type
unsigned totym(); unsigned totym();
// LDC // LDC
bool retInPtr; IrFuncTy* fty;
bool usesThis;
bool usesNest;
// when the last arg is a struct and passed in EAX, this holds its real type
const llvm::Type* structInregArg;
unsigned retAttrs;
unsigned thisAttrs; // also used for nest
// parameter index in the llvm function that contains the first not-implicit arg
size_t firstRealArg;
bool reverseParams;
}; };
struct TypeDelegate : Type struct TypeDelegate : Type
@ -699,9 +690,6 @@ struct Argument : Object
static void argsToDecoBuffer(OutBuffer *buf, Arguments *arguments); static void argsToDecoBuffer(OutBuffer *buf, Arguments *arguments);
static size_t dim(Arguments *arguments); static size_t dim(Arguments *arguments);
static Argument *getNth(Arguments *arguments, size_t nth, size_t *pn = NULL); static Argument *getNth(Arguments *arguments, size_t nth, size_t *pn = NULL);
// LDC
unsigned llvmAttrs;
}; };
extern int PTRSIZE; extern int PTRSIZE;

View file

@ -1,5 +1,7 @@
#include "gen/llvm.h" #include "gen/llvm.h"
#include <algorithm>
#include "mars.h" #include "mars.h"
#include "gen/irstate.h" #include "gen/irstate.h"
@ -8,59 +10,7 @@
#include "gen/abi.h" #include "gen/abi.h"
#include "gen/logger.h" #include "gen/logger.h"
////////////////////////////////////////////////////////////////////////////// #include "ir/irfunction.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;
}
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
@ -69,33 +19,28 @@ ABIRetRewrite * TargetABI::findRetRewrite(TypeFunction * tf)
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
// simply swap of real/imag parts for proper x87 complex abi // 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); return DtoAggrPairSwap(v);
} }
LLValue* put(LLValue* v) LLValue* put(Type*, LLValue* v)
{ {
return DtoAggrPairSwap(v); return DtoAggrPairSwap(v);
} }
const LLType* type(const LLType* t) const LLType* type(Type*, const LLType* t)
{ {
return 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} // i64 -> {float,float}
LLValue* get(LLValue* in) LLValue* get(Type*, LLValue* in)
{ {
// extract real part // extract real part
LLValue* rpart = gIR->ir->CreateTrunc(in, LLType::Int32Ty); LLValue* rpart = gIR->ir->CreateTrunc(in, LLType::Int32Ty);
@ -111,7 +56,7 @@ struct X86_cfloat_rewrite : ABIRetRewrite
} }
// {float,float} -> i64 // {float,float} -> i64
LLValue* put(LLValue* v) LLValue* put(Type*, LLValue* v)
{ {
// extract real // extract real
LLValue* r = gIR->ir->CreateExtractValue(v, 0); LLValue* r = gIR->ir->CreateExtractValue(v, 0);
@ -134,16 +79,41 @@ struct X86_cfloat_rewrite : ABIRetRewrite
} }
// {float,float} -> i64 // {float,float} -> i64
const LLType* type(const LLType* t) const LLType* type(Type*, const LLType* t)
{ {
return LLType::Int64Ty; 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) Logger::println("rewriting int -> struct");
&& (tf->next->toBasetype() == Type::tcomplex32); 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 X86_cfloat_rewrite : ABIRetRewrite
struct X86TargetABI : TargetABI struct X86TargetABI : TargetABI
{ {
X86TargetABI() X87_complex_swap swapComplex;
{ X86_cfloat_rewrite cfloatToInt;
retOps.push_back(new X87_complex_swap); X86_struct_to_register structToReg;
retOps.push_back(new X86_cfloat_rewrite);
}
bool returnInArg(TypeFunction* tf) bool returnInArg(TypeFunction* tf)
{ {
@ -168,6 +136,98 @@ struct X86TargetABI : TargetABI
else else
return (rt->ty == Tstruct || rt->ty == Tcomplex64 || rt->ty == Tcomplex80); 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 X86TargetABI : TargetABI
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
struct X86_64_cfloat_rewrite : ABIRetRewrite struct X86_64_cfloat_rewrite : ABIRewrite
{ {
// {double} -> {float,float} // {double} -> {float,float}
LLValue* get(LLValue* in) LLValue* get(Type*, LLValue* in)
{ {
// extract double // extract double
LLValue* v = gIR->ir->CreateExtractValue(in, 0); LLValue* v = gIR->ir->CreateExtractValue(in, 0);
@ -200,7 +260,7 @@ struct X86_64_cfloat_rewrite : ABIRetRewrite
} }
// {float,float} -> {double} // {float,float} -> {double}
LLValue* put(LLValue* v) LLValue* put(Type*, LLValue* v)
{ {
// extract real // extract real
LLValue* r = gIR->ir->CreateExtractValue(v, 0); LLValue* r = gIR->ir->CreateExtractValue(v, 0);
@ -231,33 +291,41 @@ struct X86_64_cfloat_rewrite : ABIRetRewrite
} }
// {float,float} -> {double} // {float,float} -> {double}
const LLType* type(const LLType* t) const LLType* type(Type*, const LLType* t)
{ {
return LLStructType::get(LLType::DoubleTy, NULL); 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 struct X86_64TargetABI : TargetABI
{ {
X86_64TargetABI() X86_64_cfloat_rewrite cfloat_rewrite;
{
retOps.push_back(new X86_64_cfloat_rewrite);
}
bool returnInArg(TypeFunction* tf) bool returnInArg(TypeFunction* tf)
{ {
Type* rt = tf->next->toBasetype(); Type* rt = tf->next->toBasetype();
return (rt->ty == Tstruct); 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 @@ struct X86_64TargetABI : TargetABI
// Some reasonable defaults for when we don't know what ABI to use. // Some reasonable defaults for when we don't know what ABI to use.
struct UnknownTargetABI : TargetABI struct UnknownTargetABI : TargetABI
{ {
UnknownTargetABI()
{
// Don't push anything into retOps, assume defaults will be fine.
}
bool returnInArg(TypeFunction* tf) bool returnInArg(TypeFunction* tf)
{ {
Type* rt = tf->next->toBasetype(); return (tf->next->toBasetype()->ty == Tstruct);
return (rt->ty == Tstruct); }
bool passByVal(Type* t)
{
return t->toBasetype()->ty == Tstruct;
}
void rewriteFunctionType(TypeFunction* t)
{
// why?
} }
}; };

View file

@ -4,6 +4,7 @@
#include <vector> #include <vector>
struct Type; struct Type;
struct IrFuncTyArg;
namespace llvm namespace llvm
{ {
class Type; class Type;
@ -11,38 +12,27 @@ namespace llvm
} }
// return rewrite rule // return rewrite rule
struct ABIRetRewrite struct ABIRewrite
{ {
// get original value from rewritten one // get original value from rewritten one
virtual LLValue* get(LLValue* v) = 0; virtual LLValue* get(Type* dty, LLValue* v) = 0;
// rewrite original value // rewrite original value
virtual LLValue* put(LLValue* v) = 0; virtual LLValue* put(Type* dty, LLValue* v) = 0;
// returns target type of this rewrite // returns target type of this rewrite
virtual const LLType* type(const LLType* t) = 0; virtual const LLType* type(Type* dty, const LLType* t) = 0;
// test if rewrite applies
virtual bool test(TypeFunction* tf) = 0;
}; };
// interface called by codegen // interface called by codegen
struct TargetABI struct TargetABI
{ {
static TargetABI* getTarget(); static TargetABI* getTarget();
TargetABI(); virtual bool returnInArg(TypeFunction* tf) = 0;
virtual bool passByVal(Type* t) = 0;
const llvm::Type* getRetType(TypeFunction* tf, const llvm::Type* t); virtual void rewriteFunctionType(TypeFunction* t) = 0;
llvm::Value* getRet(TypeFunction* tf, llvm::Value* v);
llvm::Value* putRet(TypeFunction* tf, llvm::Value* v);
virtual bool returnInArg(TypeFunction* t) = 0;
protected:
std::vector<ABIRetRewrite*> retOps;
ABIRetRewrite* findRetRewrite(TypeFunction* tf);
}; };
#endif #endif

View file

@ -22,136 +22,114 @@
#include "gen/dvalue.h" #include "gen/dvalue.h"
#include "gen/abi.h" #include "gen/abi.h"
#include <algorithm> const llvm::FunctionType* DtoFunctionType(Type* type, Type* thistype, Type* nesttype, bool ismain)
const llvm::FunctionType* DtoFunctionType(Type* type, const LLType* thistype, const LLType* nesttype, bool ismain)
{ {
// sanity check
assert(type->ty == Tfunction); assert(type->ty == Tfunction);
TypeFunction* f = (TypeFunction*)type; TypeFunction* f = (TypeFunction*)type;
// already built ?
if (type->ir.type != NULL) { if (type->ir.type != NULL) {
assert(f->fty != NULL);
return llvm::cast<llvm::FunctionType>(type->ir.type->get()); return llvm::cast<llvm::FunctionType>(type->ir.type->get());
} }
bool dVararg = false; // create new ir funcTy
bool arrayVararg = false; assert(f->fty == NULL);
if (f->linkage == LINKd) f->fty = new IrFuncTy();
{
if (f->varargs == 1)
dVararg = true;
else if (f->varargs == 2)
arrayVararg = true;
}
// return value type // llvm idx counter
const LLType* rettype; size_t lidx = 0;
const LLType* actualRettype;
Type* rt = f->next;
bool retinptr = false;
bool usesthis = false;
bool usesnest = false;
// parameter types // main needs a little special handling
std::vector<const LLType*> paramvec;
// special case main
if (ismain) if (ismain)
{ {
rettype = LLType::Int32Ty; f->fty->ret = new IrFuncTyArg(Type::tint32, false);
actualRettype = rettype;
if (Argument::dim(f->parameters) == 0)
{
const LLType* arrTy = DtoArrayType(LLType::Int8Ty);
const LLType* arrArrTy = DtoArrayType(arrTy);
paramvec.push_back(arrArrTy);
}
} }
// default handling // sane return value
else else
{ {
assert(rt); Type* rt = f->next;
if (f->linkage == LINKintrinsic) unsigned a = 0;
// sret return
if (gABI->returnInArg(f))
{ {
// Intrinsics don't care about ABI f->fty->arg_sret = new IrFuncTyArg(rt, true, llvm::Attribute::StructRet);
Logger::cout() << "Intrinsic returning " << rt->toChars() << '\n'; rt = Type::tvoid;
actualRettype = rettype = DtoType(rt); lidx++;
Logger::cout() << " (LLVM type: " << *rettype << ")\n"; }
// sext/zext return
else if (unsigned se = DtoShouldExtend(rt))
{
a = se;
}
f->fty->ret = new IrFuncTyArg(rt, false, a);
}
lidx++;
// member functions
if (thistype)
{
bool toref = (thistype->toBasetype()->ty == Tstruct);
f->fty->arg_this = new IrFuncTyArg(thistype, toref);
lidx++;
}
// and nested functions
else if (nesttype)
{
f->fty->arg_nest = new IrFuncTyArg(nesttype, false);
lidx++;
}
// vararg functions are special too
if (f->varargs)
{
if (f->linkage == LINKd)
{
// d style with hidden args
// 2 (array) is handled by the frontend
if (f->varargs == 1)
{
// _arguments
f->fty->arg_arguments = new IrFuncTyArg(Type::typeinfo->type->arrayOf(), false);
lidx++;
// _argptr
f->fty->arg_argptr = new IrFuncTyArg(Type::tvoid->pointerTo(), false);
lidx++;
}
}
else if (f->linkage == LINKc)
{
f->fty->c_vararg = true;
} }
else else
{ {
if (gABI->returnInArg(f)) type->error(0, "invalid linkage for variadic function");
{ fatal();
rettype = getPtrToType(DtoType(rt));
actualRettype = LLType::VoidTy;
f->retInPtr = retinptr = true;
}
else
{
rettype = DtoType(rt);
// do abi specific transformations
actualRettype = gABI->getRetType(f, rettype);
}
// FIXME: should probably be part of the abi
if (unsigned ea = DtoShouldExtend(rt))
{
f->retAttrs |= ea;
}
} }
} }
// build up parameter list // if this _Dmain() doesn't have an argument, we force it to have one
if (retinptr) { int nargs = Argument::dim(f->parameters);
//Logger::cout() << "returning through pointer parameter: " << *rettype << '\n';
paramvec.push_back(rettype);
}
// this/context param if (ismain && nargs == 0)
if (thistype) {
paramvec.push_back(thistype);
usesthis = true;
}
else if (nesttype) {
paramvec.push_back(nesttype);
usesnest = true;
}
// dstyle vararg
if (dVararg) {
paramvec.push_back(DtoType(Type::typeinfo->type->arrayOf())); // _arguments
paramvec.push_back(getVoidPtrType()); // _argptr
}
// now that all implicit args are done, store the start of the real args
f->firstRealArg = paramvec.size();
// number of formal params
size_t n = Argument::dim(f->parameters);
#if X86_REVERSE_PARAMS
// on x86 we need to reverse the formal params in some cases to match the ABI
if (global.params.cpu == ARCHx86)
{ {
// more than one formal arg, Type* mainargs = Type::tchar->arrayOf()->arrayOf();
// extern(D) linkage f->fty->args.push_back(new IrFuncTyArg(mainargs, false));
// not a D-style vararg lidx++;
if (n > 1 && f->linkage == LINKd && !dVararg)
{
f->reverseParams = true;
}
} }
#endif // X86_REVERSE_PARAMS // add explicit parameters
else for (int i = 0; i < nargs; i++)
{
for (int i=0; i < n; ++i) { // get argument
Argument* arg = Argument::getNth(f->parameters, i); Argument* arg = Argument::getNth(f->parameters, i);
// ensure scalar
Type* argT = arg->type->toBasetype();
assert(argT);
bool refOrOut = ((arg->storageClass & STCref) || (arg->storageClass & STCout)); // reference semantics? ref, out and static arrays are
bool byref = (arg->storageClass & (STCref|STCout)) || (arg->type->toBasetype()->ty == Tsarray);
const LLType* at = DtoType(argT); Type* argtype = arg->type;
unsigned a = 0;
// handle lazy args // handle lazy args
if (arg->storageClass & STClazy) if (arg->storageClass & STClazy)
@ -159,113 +137,51 @@ const llvm::FunctionType* DtoFunctionType(Type* type, const LLType* thistype, co
Logger::println("lazy param"); Logger::println("lazy param");
TypeFunction *ltf = new TypeFunction(NULL, arg->type, 0, LINKd); TypeFunction *ltf = new TypeFunction(NULL, arg->type, 0, LINKd);
TypeDelegate *ltd = new TypeDelegate(ltf); TypeDelegate *ltd = new TypeDelegate(ltf);
at = DtoType(ltd); argtype = ltd;
paramvec.push_back(at);
} }
// opaque types need special handling // byval
else if (llvm::isa<llvm::OpaqueType>(at)) { else if (gABI->passByVal(argtype))
Logger::println("opaque param");
assert(argT->ty == Tstruct || argT->ty == Tclass);
paramvec.push_back(getPtrToType(at));
}
// structs are passed as a reference, but by value
else if (argT->ty == Tstruct) {
Logger::println("struct param");
if (!refOrOut)
arg->llvmAttrs |= llvm::Attribute::ByVal;
paramvec.push_back(getPtrToType(at));
}
// static arrays are passed directly by reference
else if (argT->ty == Tsarray)
{ {
Logger::println("static array param"); if (!byref) a |= llvm::Attribute::ByVal;
at = getPtrToType(at); byref = true;
paramvec.push_back(at);
} }
// firstclass ' ref/out ' parameter // sext/zext
else if (refOrOut) { else if (!byref)
Logger::println("ref/out param"); {
at = getPtrToType(at); a |= DtoShouldExtend(argtype);
paramvec.push_back(at);
}
// firstclass ' in ' parameter
else {
Logger::println("in param");
if (unsigned ea = DtoShouldExtend(argT))
arg->llvmAttrs |= ea;
paramvec.push_back(at);
} }
f->fty->args.push_back(new IrFuncTyArg(argtype, byref, a));
lidx++;
}
// let the abi rewrite the types as necesary
gABI->rewriteFunctionType(f);
// build the function type
std::vector<const LLType*> argtypes;
argtypes.reserve(lidx);
if (f->fty->arg_sret) argtypes.push_back(f->fty->arg_sret->ltype);
if (f->fty->arg_this) argtypes.push_back(f->fty->arg_this->ltype);
if (f->fty->arg_nest) argtypes.push_back(f->fty->arg_nest->ltype);
if (f->fty->arg_arguments) argtypes.push_back(f->fty->arg_arguments->ltype);
if (f->fty->arg_argptr) argtypes.push_back(f->fty->arg_argptr->ltype);
size_t beg = argtypes.size();
size_t nargs2 = f->fty->args.size();
for (size_t i = 0; i < nargs2; i++)
{
argtypes.push_back(f->fty->args[i]->ltype);
} }
// reverse params? // reverse params?
if (f->reverseParams) if (f->fty->reverseParams && f->parameters->dim > 1)
{ {
std::reverse(paramvec.begin() + f->firstRealArg, paramvec.end()); std::reverse(argtypes.begin() + beg, argtypes.end());
} }
#if X86_PASS_IN_EAX llvm::FunctionType* functype = llvm::FunctionType::get(f->fty->ret->ltype, argtypes, f->fty->c_vararg);
// pass first param in EAX if it fits, is not floating point and is not a 3 byte struct.
// ONLY extern(D) functions !
if ((n > 0 || usesthis || usesnest) && f->linkage == LINKd)
{
// FIXME: Only x86 right now ...
if (global.params.cpu == ARCHx86)
{
int n_inreg = f->reverseParams ? n - 1 : 0;
Argument* arg = Argument::getNth(f->parameters, n_inreg);
// if there is a implicit context parameter, pass it in EAX
if (usesthis || usesnest)
{
f->thisAttrs |= llvm::Attribute::InReg;
assert((!arg || (arg->llvmAttrs & llvm::Attribute::InReg) == 0) && "can't have two inreg args!");
}
// otherwise check the first formal parameter
else
{
Type* t = arg->type->toBasetype();
// 32bit ints, pointers, classes, static arrays, AAs, ref and out params,
// and structs with size <= 4 and != 3
// are candidate for being passed in EAX
if (
(arg->storageClass & (STCref|STCout))
||
((arg->storageClass & STCin) &&
((t->isscalar() && !t->isfloating()) ||
t->ty == Tclass || t->ty == Tsarray || t->ty == Taarray ||
(t->ty == Tstruct && t->size() != 3)
) && (t->size() <= PTRSIZE))
)
{
arg->llvmAttrs |= llvm::Attribute::InReg;
assert((f->thisAttrs & llvm::Attribute::InReg) == 0 && "can't have two inreg args!");
// structs need to go from {...}* byval to i8/i16/i32 inreg
if ((arg->storageClass & STCin) && t->ty == Tstruct)
{
int n_param = f->reverseParams ? f->firstRealArg + n - 1 - n_inreg : f->firstRealArg + n_inreg;
assert(isaPointer(paramvec[n_param]) && (arg->llvmAttrs & llvm::Attribute::ByVal)
&& "struct parameter expected to be {...}* byval before inreg is applied");
f->structInregArg = paramvec[n_param]->getContainedType(0);
paramvec[n_param] = LLIntegerType::get(8*t->size());
arg->llvmAttrs &= ~llvm::Attribute::ByVal;
}
}
}
}
}
#endif // X86_PASS_IN_EAX
// construct function type
bool isvararg = !(dVararg || arrayVararg) && f->varargs;
llvm::FunctionType* functype = llvm::FunctionType::get(actualRettype, paramvec, isvararg);
// done
f->retInPtr = retinptr;
f->usesThis = usesthis;
f->usesNest = usesnest;
f->ir.type = new llvm::PATypeHolder(functype); f->ir.type = new llvm::PATypeHolder(functype);
return functype; return functype;
@ -283,10 +199,19 @@ static const llvm::FunctionType* DtoVaFunctionType(FuncDeclaration* fdecl)
TypeFunction* f = (TypeFunction*)fdecl->type; TypeFunction* f = (TypeFunction*)fdecl->type;
const llvm::FunctionType* fty = 0; const llvm::FunctionType* fty = 0;
// create new ir funcTy
assert(f->fty == NULL);
f->fty = new IrFuncTy();
f->fty->ret = new IrFuncTyArg(Type::tvoid, false);
f->fty->args.push_back(new IrFuncTyArg(Type::tvoid->pointerTo(), false));
if (fdecl->llvmInternal == LLVMva_start) if (fdecl->llvmInternal == LLVMva_start)
fty = GET_INTRINSIC_DECL(vastart)->getFunctionType(); fty = GET_INTRINSIC_DECL(vastart)->getFunctionType();
else if (fdecl->llvmInternal == LLVMva_copy) else if (fdecl->llvmInternal == LLVMva_copy) {
fty = GET_INTRINSIC_DECL(vacopy)->getFunctionType(); fty = GET_INTRINSIC_DECL(vacopy)->getFunctionType();
f->fty->args.push_back(new IrFuncTyArg(Type::tvoid->pointerTo(), false));
}
else if (fdecl->llvmInternal == LLVMva_end) else if (fdecl->llvmInternal == LLVMva_end)
fty = GET_INTRINSIC_DECL(vaend)->getFunctionType(); fty = GET_INTRINSIC_DECL(vaend)->getFunctionType();
assert(fty); assert(fty);
@ -307,13 +232,13 @@ const llvm::FunctionType* DtoFunctionType(FuncDeclaration* fdecl)
if (fdecl->type->ir.type != 0) if (fdecl->type->ir.type != 0)
return llvm::cast<llvm::FunctionType>(fdecl->type->ir.type->get()); return llvm::cast<llvm::FunctionType>(fdecl->type->ir.type->get());
const LLType* thisty = 0; Type *dthis=0, *dnest=0;
const LLType* nestty = 0;
if (fdecl->needThis()) { if (fdecl->needThis()) {
if (AggregateDeclaration* ad = fdecl->isMember2()) { if (AggregateDeclaration* ad = fdecl->isMember2()) {
Logger::println("isMember = this is: %s", ad->type->toChars()); Logger::println("isMember = this is: %s", ad->type->toChars());
thisty = DtoType(ad->type); dthis = ad->type;
const LLType* thisty = DtoType(dthis);
//Logger::cout() << "this llvm type: " << *thisty << '\n'; //Logger::cout() << "this llvm type: " << *thisty << '\n';
if (isaStruct(thisty) || (!gIR->structs.empty() && thisty == gIR->topstruct()->type->ir.type->get())) if (isaStruct(thisty) || (!gIR->structs.empty() && thisty == gIR->topstruct()->type->ir.type->get()))
thisty = getPtrToType(thisty); thisty = getPtrToType(thisty);
@ -324,10 +249,10 @@ const llvm::FunctionType* DtoFunctionType(FuncDeclaration* fdecl)
} }
} }
else if (fdecl->isNested()) { else if (fdecl->isNested()) {
nestty = getPtrToType(LLType::Int8Ty); dnest = Type::tvoid->pointerTo();
} }
const llvm::FunctionType* functype = DtoFunctionType(fdecl->type, thisty, nestty, fdecl->isMain()); const llvm::FunctionType* functype = DtoFunctionType(fdecl->type, dthis, dnest, fdecl->isMain());
return functype; return functype;
} }
@ -414,46 +339,35 @@ void DtoResolveFunction(FuncDeclaration* fdecl)
static void set_param_attrs(TypeFunction* f, llvm::Function* func, FuncDeclaration* fdecl) static void set_param_attrs(TypeFunction* f, llvm::Function* func, FuncDeclaration* fdecl)
{ {
int llidx = 0;
if (f->retInPtr) ++llidx;
if (f->usesThis) ++llidx;
else if (f->usesNest) ++llidx;
if (f->linkage == LINKd && f->varargs == 1)
llidx += 2;
int funcNumArgs = func->getArgumentList().size(); int funcNumArgs = func->getArgumentList().size();
LLSmallVector<llvm::AttributeWithIndex, 9> attrs; LLSmallVector<llvm::AttributeWithIndex, 9> attrs;
llvm::AttributeWithIndex PAWI; llvm::AttributeWithIndex PAWI;
// set return value attrs if any int idx = 0;
if (f->retAttrs)
{ // handle implicit args
PAWI.Index = 0; #define ADD_PA(X) \
PAWI.Attrs = f->retAttrs; if (f->fty->X) { \
attrs.push_back(PAWI); if (f->fty->X->attrs) { \
PAWI.Index = idx; \
PAWI.Attrs = f->fty->X->attrs; \
attrs.push_back(PAWI); \
} \
idx++; \
} }
// set sret param ADD_PA(ret)
if (f->retInPtr) ADD_PA(arg_sret)
{ ADD_PA(arg_this)
PAWI.Index = 1; ADD_PA(arg_nest)
PAWI.Attrs = llvm::Attribute::StructRet; ADD_PA(arg_arguments)
attrs.push_back(PAWI); ADD_PA(arg_argptr)
}
// set this/nest param attrs #undef ADD_PA
if (f->thisAttrs)
{
PAWI.Index = f->retInPtr ? 2 : 1;
PAWI.Attrs = f->thisAttrs;
attrs.push_back(PAWI);
}
// set attrs on the rest of the arguments // set attrs on the rest of the arguments
size_t n = Argument::dim(f->parameters); size_t n = Argument::dim(f->parameters);
assert(funcNumArgs >= n); // main might mismatch, for the implicit char[][] arg
LLSmallVector<unsigned,8> attrptr(n, 0); LLSmallVector<unsigned,8> attrptr(n, 0);
for (size_t k = 0; k < n; ++k) for (size_t k = 0; k < n; ++k)
@ -461,11 +375,11 @@ static void set_param_attrs(TypeFunction* f, llvm::Function* func, FuncDeclarati
Argument* fnarg = Argument::getNth(f->parameters, k); Argument* fnarg = Argument::getNth(f->parameters, k);
assert(fnarg); assert(fnarg);
attrptr[k] = fnarg->llvmAttrs; attrptr[k] = f->fty->args[k]->attrs;
} }
// reverse params? // reverse params?
if (f->reverseParams) if (f->fty->reverseParams)
{ {
std::reverse(attrptr.begin(), attrptr.end()); std::reverse(attrptr.begin(), attrptr.end());
} }
@ -475,7 +389,7 @@ static void set_param_attrs(TypeFunction* f, llvm::Function* func, FuncDeclarati
{ {
if (attrptr[i]) if (attrptr[i])
{ {
PAWI.Index = llidx+i+1; PAWI.Index = idx+i;
PAWI.Attrs = attrptr[i]; PAWI.Attrs = attrptr[i];
attrs.push_back(PAWI); attrs.push_back(PAWI);
} }
@ -575,26 +489,26 @@ void DtoDeclareFunction(FuncDeclaration* fdecl)
// name parameters // name parameters
llvm::Function::arg_iterator iarg = func->arg_begin(); llvm::Function::arg_iterator iarg = func->arg_begin();
if (f->retInPtr) { if (f->fty->arg_sret) {
iarg->setName(".sret_arg"); iarg->setName(".sret_arg");
fdecl->ir.irFunc->retArg = iarg; fdecl->ir.irFunc->retArg = iarg;
++iarg; ++iarg;
} }
if (f->usesThis) { if (f->fty->arg_this) {
iarg->setName(".this_arg"); iarg->setName(".this_arg");
fdecl->ir.irFunc->thisArg = iarg; fdecl->ir.irFunc->thisArg = iarg;
assert(fdecl->ir.irFunc->thisArg); assert(fdecl->ir.irFunc->thisArg);
++iarg; ++iarg;
} }
else if (f->usesNest) { else if (f->fty->arg_nest) {
iarg->setName(".nest_arg"); iarg->setName(".nest_arg");
fdecl->ir.irFunc->nestArg = iarg; fdecl->ir.irFunc->nestArg = iarg;
assert(fdecl->ir.irFunc->nestArg); assert(fdecl->ir.irFunc->nestArg);
++iarg; ++iarg;
} }
if (f->linkage == LINKd && f->varargs == 1) { if (f->fty->arg_argptr) {
iarg->setName("._arguments"); iarg->setName("._arguments");
fdecl->ir.irFunc->_arguments = iarg; fdecl->ir.irFunc->_arguments = iarg;
++iarg; ++iarg;
@ -610,7 +524,7 @@ void DtoDeclareFunction(FuncDeclaration* fdecl)
if (fdecl->parameters && fdecl->parameters->dim > k) if (fdecl->parameters && fdecl->parameters->dim > k)
{ {
Dsymbol* argsym; Dsymbol* argsym;
if (f->reverseParams) if (f->fty->reverseParams)
argsym = (Dsymbol*)fdecl->parameters->data[fdecl->parameters->dim-k-1]; argsym = (Dsymbol*)fdecl->parameters->data[fdecl->parameters->dim-k-1];
else else
argsym = (Dsymbol*)fdecl->parameters->data[k]; argsym = (Dsymbol*)fdecl->parameters->data[k];
@ -648,6 +562,8 @@ void DtoDeclareFunction(FuncDeclaration* fdecl)
////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////
// FIXME: this isn't too pretty!
void DtoDefineFunction(FuncDeclaration* fd) void DtoDefineFunction(FuncDeclaration* fd)
{ {
if (fd->ir.defined) return; if (fd->ir.defined) return;
@ -727,7 +643,7 @@ void DtoDefineFunction(FuncDeclaration* fd)
} }
// give the 'this' argument storage and debug info // give the 'this' argument storage and debug info
if (f->usesThis) if (f->fty->arg_this)
{ {
LLValue* thisvar = irfunction->thisArg; LLValue* thisvar = irfunction->thisArg;
assert(thisvar); assert(thisvar);
@ -757,7 +673,8 @@ void DtoDefineFunction(FuncDeclaration* fd)
// and debug info // and debug info
if (fd->parameters) if (fd->parameters)
{ {
size_t n = fd->parameters->dim; size_t n = f->fty->args.size();
assert(n == fd->parameters->dim);
for (int i=0; i < n; ++i) for (int i=0; i < n; ++i)
{ {
Dsymbol* argsym = (Dsymbol*)fd->parameters->data[i]; Dsymbol* argsym = (Dsymbol*)fd->parameters->data[i];
@ -767,20 +684,8 @@ void DtoDefineFunction(FuncDeclaration* fd)
IrLocal* irloc = vd->ir.irLocal; IrLocal* irloc = vd->ir.irLocal;
assert(irloc); assert(irloc);
// if it's inreg struct arg, allocate storage // let the abi transform the argument back first
if (f->structInregArg && i == (f->reverseParams ? n - 1 : 0)) LLValue* argvalue = f->fty->getParam(vd->type, i, irloc->value);
{
int n_param = f->reverseParams ? f->firstRealArg + n - 1 - i : f->firstRealArg + i;
const LLType* paramty = functype->getParamType(n_param);
assert(!f->usesNest && !f->usesThis &&
llvm::isa<LLIntegerType>(paramty) && isaStruct(f->structInregArg)
&& "Preconditions for inreg struct arg not met!");
LLValue* mem = DtoAlloca(f->structInregArg, "inregstructarg");
DtoStore(irloc->value, DtoBitCast(mem, getPtrToType(paramty)));
irloc->value = mem;
}
#if DMDV2 #if DMDV2
if (vd->nestedrefs.dim) if (vd->nestedrefs.dim)
@ -794,9 +699,9 @@ void DtoDefineFunction(FuncDeclaration* fd)
bool refout = vd->storage_class & (STCref | STCout); bool refout = vd->storage_class & (STCref | STCout);
bool lazy = vd->storage_class & STClazy; bool lazy = vd->storage_class & STClazy;
if (!refout && (!DtoIsPassedByRef(vd->type) || lazy)) if (!refout && (!f->fty->args[i]->byref || lazy))
{ {
LLValue* a = irloc->value; LLValue* a = argvalue;
LLValue* v = DtoAlloca(a->getType(), vd->ident->toChars()); LLValue* v = DtoAlloca(a->getType(), vd->ident->toChars());
DtoStore(a,v); DtoStore(a,v);
irloc->value = v; irloc->value = v;

View file

@ -1,7 +1,7 @@
#ifndef LDC_GEN_FUNCTIONS_H #ifndef LDC_GEN_FUNCTIONS_H
#define LDC_GEN_FUNCTIONS_H #define LDC_GEN_FUNCTIONS_H
const llvm::FunctionType* DtoFunctionType(Type* t, const LLType* thistype, const LLType* nesttype, bool ismain = false); const llvm::FunctionType* DtoFunctionType(Type* t, Type* thistype, Type* nesttype, bool ismain = false);
const llvm::FunctionType* DtoFunctionType(FuncDeclaration* fdecl); const llvm::FunctionType* DtoFunctionType(FuncDeclaration* fdecl);
const llvm::FunctionType* DtoBaseFunctionType(FuncDeclaration* fdecl); const llvm::FunctionType* DtoBaseFunctionType(FuncDeclaration* fdecl);

View file

@ -63,7 +63,6 @@ void ReturnStatement::toIR(IRState* p)
{ {
// sanity check // sanity check
IrFunction* f = p->func(); IrFunction* f = p->func();
assert(f->type->retInPtr);
assert(f->decl->ir.irFunc->retArg); assert(f->decl->ir.irFunc->retArg);
// emit dbg line // emit dbg line
@ -94,7 +93,7 @@ void ReturnStatement::toIR(IRState* p)
delete e; delete e;
// do abi specific transformations on the return value // do abi specific transformations on the return value
v = gABI->putRet(p->func()->type, v); v = p->func()->type->fty->putRet(exp->type, v);
if (Logger::enabled()) if (Logger::enabled())
Logger::cout() << "return value is '" <<*v << "'\n"; Logger::cout() << "return value is '" <<*v << "'\n";
@ -111,7 +110,7 @@ void ReturnStatement::toIR(IRState* p)
v = llvm::Constant::getNullValue(p->mainFunc->getReturnType()); v = llvm::Constant::getNullValue(p->mainFunc->getReturnType());
else else
v = gIR->ir->CreateBitCast(v, p->topfunc()->getReturnType(), "tmp"); v = gIR->ir->CreateBitCast(v, p->topfunc()->getReturnType(), "tmp");
if (Logger::enabled()) if (Logger::enabled())
Logger::cout() << "return value after cast: " << *v << '\n'; Logger::cout() << "return value after cast: " << *v << '\n';
} }

View file

@ -201,11 +201,11 @@ void DtoBuildDVarArgList(std::vector<LLValue*>& args, std::vector<llvm::Attribut
DValue* argval = DtoArgument(fnarg, (Expression*)arguments->data[i]); DValue* argval = DtoArgument(fnarg, (Expression*)arguments->data[i]);
args.push_back(argval->getRVal()); args.push_back(argval->getRVal());
if (fnarg->llvmAttrs) if (tf->fty->args[i]->attrs)
{ {
llvm::AttributeWithIndex Attr; llvm::AttributeWithIndex Attr;
Attr.Index = argidx; Attr.Index = argidx;
Attr.Attrs = fnarg->llvmAttrs; Attr.Attrs = tf->fty->args[i]->attrs;
attrs.push_back(Attr); attrs.push_back(Attr);
} }
@ -213,6 +213,7 @@ void DtoBuildDVarArgList(std::vector<LLValue*>& args, std::vector<llvm::Attribut
} }
} }
// FIXME: this function is a mess !
DValue* DtoCallFunction(Loc& loc, Type* resulttype, DValue* fnval, Expressions* arguments) DValue* DtoCallFunction(Loc& loc, Type* resulttype, DValue* fnval, Expressions* arguments)
{ {
@ -233,10 +234,10 @@ DValue* DtoCallFunction(Loc& loc, Type* resulttype, DValue* fnval, Expressions*
TypeFunction* tf = DtoTypeFunction(fnval); TypeFunction* tf = DtoTypeFunction(fnval);
// misc // misc
bool retinptr = tf->retInPtr; bool retinptr = tf->fty->arg_sret;
bool thiscall = tf->usesThis; bool thiscall = tf->fty->arg_this;
bool delegatecall = (calleeType->toBasetype()->ty == Tdelegate); bool delegatecall = (calleeType->toBasetype()->ty == Tdelegate);
bool nestedcall = tf->usesNest; bool nestedcall = tf->fty->arg_nest;
bool dvarargs = (tf->linkage == LINKd && tf->varargs == 1); bool dvarargs = (tf->linkage == LINKd && tf->varargs == 1);
unsigned callconv = DtoCallingConv(loc, tf->linkage); unsigned callconv = DtoCallingConv(loc, tf->linkage);
@ -261,15 +262,16 @@ DValue* DtoCallFunction(Loc& loc, Type* resulttype, DValue* fnval, Expressions*
llvm::AttributeWithIndex Attr; llvm::AttributeWithIndex Attr;
// return attrs // return attrs
if (tf->retAttrs) if (tf->fty->ret->attrs)
{ {
Attr.Index = 0; Attr.Index = 0;
Attr.Attrs = tf->retAttrs; Attr.Attrs = tf->fty->ret->attrs;
attrs.push_back(Attr); attrs.push_back(Attr);
} }
// handle implicit arguments // handle implicit arguments
std::vector<LLValue*> args; std::vector<LLValue*> args;
args.reserve(tf->fty->args.size());
// return in hidden ptr is first // return in hidden ptr is first
if (retinptr) if (retinptr)
@ -325,10 +327,16 @@ DValue* DtoCallFunction(Loc& loc, Type* resulttype, DValue* fnval, Expressions*
} }
// add attributes for context argument // add attributes for context argument
if (tf->thisAttrs) if (tf->fty->arg_this && tf->fty->arg_this->attrs)
{ {
Attr.Index = retinptr ? 2 : 1; Attr.Index = retinptr ? 2 : 1;
Attr.Attrs = tf->thisAttrs; Attr.Attrs = tf->fty->arg_this->attrs;
attrs.push_back(Attr);
}
else if (tf->fty->arg_nest && tf->fty->arg_nest->attrs)
{
Attr.Index = retinptr ? 2 : 1;
Attr.Attrs = tf->fty->arg_nest->attrs;
attrs.push_back(Attr); attrs.push_back(Attr);
} }
} }
@ -374,20 +382,15 @@ DValue* DtoCallFunction(Loc& loc, Type* resulttype, DValue* fnval, Expressions*
DValue* argval = DtoArgument(fnarg, (Expression*)arguments->data[i]); DValue* argval = DtoArgument(fnarg, (Expression*)arguments->data[i]);
LLValue* arg = argval->getRVal(); LLValue* arg = argval->getRVal();
int j = tf->reverseParams ? beg + n - i - 1 : beg + i; int j = tf->fty->reverseParams ? beg + n - i - 1 : beg + i;
// if it's a struct inreg arg, load first to pass as first-class value // give the ABI a say
if (tf->structInregArg && i == (tf->reverseParams ? n - 1 : 0)) arg = tf->fty->putParam(argval->getType(), i, arg);
{
assert((fnarg->llvmAttrs & llvm::Attribute::InReg) && isaStruct(tf->structInregArg));
arg = DtoBitCast(arg, getPtrToType(callableTy->getParamType(j)));
arg = DtoLoad(arg);
}
// parameter type mismatch, this is hard to get rid of // parameter type mismatch, this is hard to get rid of
if (arg->getType() != callableTy->getParamType(j)) if (arg->getType() != callableTy->getParamType(j))
{ {
#if 0 #if 1
if (Logger::enabled()) if (Logger::enabled())
{ {
Logger::cout() << "arg: " << *arg << '\n'; Logger::cout() << "arg: " << *arg << '\n';
@ -398,16 +401,16 @@ DValue* DtoCallFunction(Loc& loc, Type* resulttype, DValue* fnval, Expressions*
} }
// param attrs // param attrs
attrptr[i] = fnarg->llvmAttrs; attrptr[i] = tf->fty->args[i]->attrs;
++argiter; ++argiter;
args.push_back(arg); args.push_back(arg);
} }
// reverse the relevant params as well as the param attrs // reverse the relevant params as well as the param attrs
if (tf->reverseParams) if (tf->fty->reverseParams)
{ {
std::reverse(args.begin() + tf->firstRealArg, args.end()); std::reverse(args.begin() + beg, args.end());
std::reverse(attrptr.begin(), attrptr.end()); std::reverse(attrptr.begin(), attrptr.end());
} }
@ -475,10 +478,10 @@ DValue* DtoCallFunction(Loc& loc, Type* resulttype, DValue* fnval, Expressions*
retllval = mem; retllval = mem;
} }
} }
else else if (!retinptr)
{ {
// do abi specific return value fixups // do abi specific return value fixups
retllval = gABI->getRet(tf, retllval); retllval = tf->fty->getRet(tf->next, retllval);
} }
// repaint the type if necessary // repaint the type if necessary

View file

@ -227,7 +227,7 @@ const LLStructType* DtoDelegateType(Type* t)
{ {
assert(t->ty == Tdelegate); assert(t->ty == Tdelegate);
const LLType* i8ptr = getVoidPtrType(); const LLType* i8ptr = getVoidPtrType();
const LLType* func = DtoFunctionType(t->nextOf(), NULL, i8ptr); const LLType* func = DtoFunctionType(t->nextOf(), NULL, Type::tvoid->pointerTo());
const LLType* funcptr = getPtrToType(func); const LLType* funcptr = getPtrToType(func);
return LLStructType::get(i8ptr, funcptr, NULL); return LLStructType::get(i8ptr, funcptr, NULL);
} }

View file

@ -1,6 +1,7 @@
#include "gen/llvm.h" #include "gen/llvm.h"
#include "gen/tollvm.h" #include "gen/tollvm.h"
#include "gen/abi.h"
#include "ir/irfunction.h" #include "ir/irfunction.h"
#include <sstream> #include <sstream>
@ -9,6 +10,55 @@
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
IrFuncTyArg::IrFuncTyArg(Type* t, bool bref, unsigned a)
{
type = t;
ltype = bref ? DtoType(t->pointerTo()) : DtoType(t);
attrs = a;
byref = bref;
rewrite = NULL;
}
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
llvm::Value* IrFuncTy::putRet(Type* dty, llvm::Value* val)
{
assert(!arg_sret);
if (ret->rewrite)
return ret->rewrite->put(dty, val);
return val;
}
llvm::Value* IrFuncTy::getRet(Type* dty, llvm::Value* val)
{
assert(!arg_sret);
if (ret->rewrite)
return ret->rewrite->get(dty, val);
return val;
}
llvm::Value* IrFuncTy::putParam(Type* dty, int idx, llvm::Value* val)
{
assert(idx >= 0 && idx < args.size() && "invalid putParam");
if (args[idx]->rewrite)
return args[idx]->rewrite->put(dty, val);
return val;
}
llvm::Value* IrFuncTy::getParam(Type* dty, int idx, llvm::Value* val)
{
assert(idx >= 0 && idx < args.size() && "invalid getParam");
if (args[idx]->rewrite)
return args[idx]->rewrite->get(dty, val);
return val;
}
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
IrFunction::IrFunction(FuncDeclaration* fd) IrFunction::IrFunction(FuncDeclaration* fd)
{ {
decl = fd; decl = fd;

View file

@ -1,6 +1,7 @@
#ifndef LDC_IR_IRFUNCTION_H #ifndef LDC_IR_IRFUNCTION_H
#define LDC_IR_IRFUNCTION_H #define LDC_IR_IRFUNCTION_H
#include "gen/llvm.h"
#include "ir/ir.h" #include "ir/ir.h"
#include "ir/irlandingpad.h" #include "ir/irlandingpad.h"
@ -8,6 +9,66 @@
#include <stack> #include <stack>
#include <map> #include <map>
struct ABIRewrite;
// represents a function type argument
// both explicit and implicit as well as return values
struct IrFuncTyArg : IrBase
{
Type* type;
const llvm::Type* ltype;
unsigned attrs;
bool byref;
ABIRewrite* rewrite;
bool isInReg() const { return (attrs & llvm::Attribute::InReg) != 0; }
bool isSRet() const { return (attrs & llvm::Attribute::StructRet) != 0; }
bool isByVal() const { return (attrs & llvm::Attribute::ByVal) != 0; }
IrFuncTyArg(Type* t, bool byref, unsigned a = 0);
};
// represents a function type
struct IrFuncTy : IrBase
{
// return value
IrFuncTyArg* ret;
// null if not applicable
IrFuncTyArg* arg_sret;
IrFuncTyArg* arg_this;
IrFuncTyArg* arg_nest;
IrFuncTyArg* arg_arguments;
IrFuncTyArg* arg_argptr;
// normal explicit arguments
LLSmallVector<IrFuncTyArg*, 4> args;
// C varargs
bool c_vararg;
// range of normal parameters to reverse
bool reverseParams;
IrFuncTy()
: ret(NULL),
arg_sret(NULL),
arg_this(NULL),
arg_nest(NULL),
arg_arguments(NULL),
arg_argptr(NULL),
c_vararg(false),
reverseParams(false)
{}
llvm::Value* putRet(Type* dty, llvm::Value* val);
llvm::Value* getRet(Type* dty, llvm::Value* val);
llvm::Value* getParam(Type* dty, int idx, llvm::Value* val);
llvm::Value* putParam(Type* dty, int idx, llvm::Value* val);
};
// represents a function // represents a function
struct IrFunction : IrBase struct IrFunction : IrBase
{ {