mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-02 16:11:08 +03:00
Abstracted more (most) ABI details out of the normal codegen.
This commit is contained in:
parent
100815c097
commit
5dbe3ee8e2
11 changed files with 488 additions and 434 deletions
20
dmd/mtype.c
20
dmd/mtype.c
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
16
dmd/mtype.h
16
dmd/mtype.h
|
@ -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;
|
||||||
|
|
266
gen/abi.cpp
266
gen/abi.cpp
|
@ -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?
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
26
gen/abi.h
26
gen/abi.h
|
@ -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
|
||||||
|
|
|
@ -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
|
|
||||||
else
|
|
||||||
{
|
|
||||||
assert(rt);
|
|
||||||
if (f->linkage == LINKintrinsic)
|
|
||||||
{
|
|
||||||
// Intrinsics don't care about ABI
|
|
||||||
Logger::cout() << "Intrinsic returning " << rt->toChars() << '\n';
|
|
||||||
actualRettype = rettype = DtoType(rt);
|
|
||||||
Logger::cout() << " (LLVM type: " << *rettype << ")\n";
|
|
||||||
}
|
}
|
||||||
|
// sane return value
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
Type* rt = f->next;
|
||||||
|
unsigned a = 0;
|
||||||
|
// sret return
|
||||||
if (gABI->returnInArg(f))
|
if (gABI->returnInArg(f))
|
||||||
{
|
{
|
||||||
rettype = getPtrToType(DtoType(rt));
|
f->fty->arg_sret = new IrFuncTyArg(rt, true, llvm::Attribute::StructRet);
|
||||||
actualRettype = LLType::VoidTy;
|
rt = Type::tvoid;
|
||||||
f->retInPtr = retinptr = true;
|
lidx++;
|
||||||
|
}
|
||||||
|
// 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
|
||||||
{
|
{
|
||||||
rettype = DtoType(rt);
|
type->error(0, "invalid linkage for variadic function");
|
||||||
// do abi specific transformations
|
fatal();
|
||||||
actualRettype = gABI->getRetType(f, rettype);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: should probably be part of the abi
|
// if this _Dmain() doesn't have an argument, we force it to have one
|
||||||
if (unsigned ea = DtoShouldExtend(rt))
|
int nargs = Argument::dim(f->parameters);
|
||||||
|
|
||||||
|
if (ismain && nargs == 0)
|
||||||
{
|
{
|
||||||
f->retAttrs |= ea;
|
Type* mainargs = Type::tchar->arrayOf()->arrayOf();
|
||||||
|
f->fty->args.push_back(new IrFuncTyArg(mainargs, false));
|
||||||
|
lidx++;
|
||||||
}
|
}
|
||||||
}
|
// add explicit parameters
|
||||||
}
|
else for (int i = 0; i < nargs; i++)
|
||||||
|
|
||||||
// build up parameter list
|
|
||||||
if (retinptr) {
|
|
||||||
//Logger::cout() << "returning through pointer parameter: " << *rettype << '\n';
|
|
||||||
paramvec.push_back(rettype);
|
|
||||||
}
|
|
||||||
|
|
||||||
// this/context param
|
|
||||||
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,
|
// get argument
|
||||||
// extern(D) linkage
|
|
||||||
// not a D-style vararg
|
|
||||||
if (n > 1 && f->linkage == LINKd && !dVararg)
|
|
||||||
{
|
|
||||||
f->reverseParams = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif // X86_REVERSE_PARAMS
|
|
||||||
|
|
||||||
|
|
||||||
for (int i=0; i < n; ++i) {
|
|
||||||
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 {
|
f->fty->args.push_back(new IrFuncTyArg(argtype, byref, a));
|
||||||
Logger::println("in param");
|
lidx++;
|
||||||
if (unsigned ea = DtoShouldExtend(argT))
|
|
||||||
arg->llvmAttrs |= ea;
|
|
||||||
paramvec.push_back(at);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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";
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue