mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-11 13:26:08 +03:00
Follow the D ABI and pass the last arg in a register if it is a struct that fits.
This commit is contained in:
parent
aa2cd42536
commit
bbcea86cf2
4 changed files with 54 additions and 20 deletions
|
@ -2691,10 +2691,11 @@ TypeFunction::TypeFunction(Arguments *parameters, Type *treturn, int varargs, en
|
||||||
this->retInPtr = false;
|
this->retInPtr = false;
|
||||||
this->usesThis = false;
|
this->usesThis = false;
|
||||||
this->usesNest = false;
|
this->usesNest = false;
|
||||||
|
this->structInregArg = false;
|
||||||
this->retAttrs = 0;
|
this->retAttrs = 0;
|
||||||
this->thisAttrs = 0;
|
this->thisAttrs = 0;
|
||||||
this->reverseParams = false;
|
this->reverseParams = false;
|
||||||
this->reverseIndex = 0;
|
this->firstRealArg = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Type *TypeFunction::syntaxCopy()
|
Type *TypeFunction::syntaxCopy()
|
||||||
|
@ -2708,7 +2709,7 @@ Type *TypeFunction::syntaxCopy()
|
||||||
t->retAttrs = retAttrs;
|
t->retAttrs = retAttrs;
|
||||||
t->thisAttrs = thisAttrs;
|
t->thisAttrs = thisAttrs;
|
||||||
t->reverseParams = reverseParams;
|
t->reverseParams = reverseParams;
|
||||||
t->reverseIndex = reverseIndex;
|
t->firstRealArg = firstRealArg;
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -438,11 +438,13 @@ struct TypeFunction : Type
|
||||||
bool retInPtr;
|
bool retInPtr;
|
||||||
bool usesThis;
|
bool usesThis;
|
||||||
bool usesNest;
|
bool usesNest;
|
||||||
|
bool structInregArg;
|
||||||
unsigned retAttrs;
|
unsigned retAttrs;
|
||||||
unsigned thisAttrs; // also used for nest
|
unsigned thisAttrs; // also used for nest
|
||||||
|
// parameter index in the llvm function that contains the first not-implicit arg
|
||||||
|
size_t firstRealArg;
|
||||||
|
|
||||||
bool reverseParams;
|
bool reverseParams;
|
||||||
size_t reverseIndex;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TypeDelegate : Type
|
struct TypeDelegate : Type
|
||||||
|
|
|
@ -101,6 +101,9 @@ const llvm::FunctionType* DtoFunctionType(Type* type, const LLType* thistype, co
|
||||||
paramvec.push_back(getVoidPtrType()); // _argptr
|
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
|
// number of formal params
|
||||||
size_t n = Argument::dim(f->parameters);
|
size_t n = Argument::dim(f->parameters);
|
||||||
|
|
||||||
|
@ -114,7 +117,6 @@ const llvm::FunctionType* DtoFunctionType(Type* type, const LLType* thistype, co
|
||||||
if (n > 1 && f->linkage == LINKd && !dVararg)
|
if (n > 1 && f->linkage == LINKd && !dVararg)
|
||||||
{
|
{
|
||||||
f->reverseParams = true;
|
f->reverseParams = true;
|
||||||
f->reverseIndex = paramvec.size();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif // X86_REVERSE_PARAMS
|
#endif // X86_REVERSE_PARAMS
|
||||||
|
@ -177,24 +179,17 @@ const llvm::FunctionType* DtoFunctionType(Type* type, const LLType* thistype, co
|
||||||
// reverse params?
|
// reverse params?
|
||||||
if (f->reverseParams)
|
if (f->reverseParams)
|
||||||
{
|
{
|
||||||
std::reverse(paramvec.begin() + f->reverseIndex, paramvec.end());
|
std::reverse(paramvec.begin() + f->firstRealArg, paramvec.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
// construct function type
|
|
||||||
bool isvararg = !(dVararg || arrayVararg) && f->varargs;
|
|
||||||
llvm::FunctionType* functype = llvm::FunctionType::get(actualRettype, paramvec, isvararg);
|
|
||||||
|
|
||||||
#if X86_PASS_IN_EAX
|
#if X86_PASS_IN_EAX
|
||||||
// tell first param to be passed in a register if we can
|
// pass first param in EAX if it fits, is not floating point and is not a 3 byte struct.
|
||||||
// ONLY extern(D) functions !
|
// ONLY extern(D) functions !
|
||||||
if ((n > 0 || usesthis || usesnest) && f->linkage == LINKd)
|
if ((n > 0 || usesthis || usesnest) && f->linkage == LINKd)
|
||||||
{
|
{
|
||||||
// FIXME: Only x86 right now ...
|
// FIXME: Only x86 right now ...
|
||||||
if (global.params.cpu == ARCHx86)
|
if (global.params.cpu == ARCHx86)
|
||||||
{
|
{
|
||||||
// pass first param in EAX if it fits, is not floating point and is not a 3 byte struct.
|
|
||||||
// FIXME: struct are not passed in EAX yet
|
|
||||||
|
|
||||||
int n_inreg = f->reverseParams ? n - 1 : 0;
|
int n_inreg = f->reverseParams ? n - 1 : 0;
|
||||||
Argument* arg = Argument::getNth(f->parameters, n_inreg);
|
Argument* arg = Argument::getNth(f->parameters, n_inreg);
|
||||||
|
|
||||||
|
@ -209,25 +204,42 @@ const llvm::FunctionType* DtoFunctionType(Type* type, const LLType* thistype, co
|
||||||
{
|
{
|
||||||
Type* t = arg->type->toBasetype();
|
Type* t = arg->type->toBasetype();
|
||||||
|
|
||||||
// 32bit ints, pointers, classes, static arrays, AAs, ref and out params
|
// 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
|
// are candidate for being passed in EAX
|
||||||
if (
|
if (
|
||||||
(arg->storageClass & (STCref|STCout))
|
(arg->storageClass & (STCref|STCout))
|
||||||
||
|
||
|
||||||
((arg->storageClass & STCin) &&
|
((arg->storageClass & STCin) &&
|
||||||
((t->isscalar() && !t->isfloating()) ||
|
((t->isscalar() && !t->isfloating()) ||
|
||||||
t->ty == Tclass || t->ty == Tsarray || t->ty == Taarray) &&
|
t->ty == Tclass || t->ty == Tsarray || t->ty == Taarray ||
|
||||||
(t->size() <= PTRSIZE))
|
(t->ty == Tstruct && t->size() != 3)
|
||||||
|
) && (t->size() <= PTRSIZE))
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
arg->llvmAttrs |= llvm::Attribute::InReg;
|
arg->llvmAttrs |= llvm::Attribute::InReg;
|
||||||
assert((f->thisAttrs & llvm::Attribute::InReg) == 0 && "can't have two inreg args!");
|
assert((f->thisAttrs & llvm::Attribute::InReg) == 0 && "can't have two inreg args!");
|
||||||
|
|
||||||
|
// structs need to go from {...}* byval to {...} 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");
|
||||||
|
paramvec[n_param] = paramvec[n_param]->getContainedType(0);
|
||||||
|
arg->llvmAttrs &= ~llvm::Attribute::ByVal;
|
||||||
|
f->structInregArg = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif // X86_PASS_IN_EAX
|
#endif // X86_PASS_IN_EAX
|
||||||
|
|
||||||
|
// construct function type
|
||||||
|
bool isvararg = !(dVararg || arrayVararg) && f->varargs;
|
||||||
|
llvm::FunctionType* functype = llvm::FunctionType::get(actualRettype, paramvec, isvararg);
|
||||||
|
|
||||||
// done
|
// done
|
||||||
f->retInPtr = retinptr;
|
f->retInPtr = retinptr;
|
||||||
f->usesThis = usesthis;
|
f->usesThis = usesthis;
|
||||||
|
@ -740,6 +752,21 @@ void DtoDefineFunction(FuncDeclaration* fd)
|
||||||
VarDeclaration* vd = argsym->isVarDeclaration();
|
VarDeclaration* vd = argsym->isVarDeclaration();
|
||||||
assert(vd);
|
assert(vd);
|
||||||
|
|
||||||
|
IrLocal* irloc = vd->ir.irLocal;
|
||||||
|
assert(irloc);
|
||||||
|
|
||||||
|
// if it's inreg struct arg, allocate storage
|
||||||
|
if (f->structInregArg && i == (f->reverseParams ? n - 1 : 0))
|
||||||
|
{
|
||||||
|
int n_param = f->reverseParams ? f->firstRealArg + n - 1 - i : f->firstRealArg + i;
|
||||||
|
assert(!f->usesNest && !f->usesThis && isaStruct(functype->getParamType(n_param))
|
||||||
|
&& "Preconditions for inreg struct arg not met!");
|
||||||
|
|
||||||
|
LLValue* mem = DtoAlloca(functype->getParamType(n_param), "inregstructarg");
|
||||||
|
DtoStore(irloc->value, mem);
|
||||||
|
irloc->value = mem;
|
||||||
|
}
|
||||||
|
|
||||||
#if DMDV2
|
#if DMDV2
|
||||||
if (vd->nestedrefs.dim)
|
if (vd->nestedrefs.dim)
|
||||||
#else
|
#else
|
||||||
|
@ -749,9 +776,6 @@ void DtoDefineFunction(FuncDeclaration* fd)
|
||||||
fd->nestedVars.insert(vd);
|
fd->nestedVars.insert(vd);
|
||||||
}
|
}
|
||||||
|
|
||||||
IrLocal* irloc = vd->ir.irLocal;
|
|
||||||
assert(irloc);
|
|
||||||
|
|
||||||
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;
|
||||||
|
|
||||||
|
|
|
@ -370,6 +370,13 @@ 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();
|
||||||
|
|
||||||
|
// if it's a struct inreg arg, load first to pass as first-class value
|
||||||
|
if (tf->structInregArg && i == (tf->reverseParams ? n - 1 : 0))
|
||||||
|
{
|
||||||
|
assert(fnarg->llvmAttrs & llvm::Attribute::InReg);
|
||||||
|
arg = DtoLoad(arg);
|
||||||
|
}
|
||||||
|
|
||||||
int j = tf->reverseParams ? beg + n - i - 1 : beg + i;
|
int j = tf->reverseParams ? beg + n - i - 1 : beg + i;
|
||||||
|
|
||||||
// parameter type mismatch, this is hard to get rid of
|
// parameter type mismatch, this is hard to get rid of
|
||||||
|
@ -395,7 +402,7 @@ DValue* DtoCallFunction(Loc& loc, Type* resulttype, DValue* fnval, Expressions*
|
||||||
// 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->reverseParams)
|
||||||
{
|
{
|
||||||
std::reverse(args.begin() + tf->reverseIndex, args.end());
|
std::reverse(args.begin() + tf->firstRealArg, args.end());
|
||||||
std::reverse(attrptr.begin(), attrptr.end());
|
std::reverse(attrptr.begin(), attrptr.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue