# HG changeset patch # User Christian Kamm # Date 1233694006 -3600 # Node ID 7985bb036db488f8680bd571374ddf4a5c8b74e3 # Parent 0749c0757a43d4189fb5e3da1b3978244da88d8f Follow the D ABI and pass the last arg in a register if it is a struct that fits. diff -r 0749c0757a43 -r 7985bb036db4 dmd/mtype.c --- a/dmd/mtype.c Tue Feb 03 18:11:39 2009 +0100 +++ b/dmd/mtype.c Tue Feb 03 21:46:46 2009 +0100 @@ -2691,10 +2691,11 @@ this->retInPtr = false; this->usesThis = false; this->usesNest = false; + this->structInregArg = false; this->retAttrs = 0; this->thisAttrs = 0; this->reverseParams = false; - this->reverseIndex = 0; + this->firstRealArg = 0; } Type *TypeFunction::syntaxCopy() @@ -2708,7 +2709,7 @@ t->retAttrs = retAttrs; t->thisAttrs = thisAttrs; t->reverseParams = reverseParams; - t->reverseIndex = reverseIndex; + t->firstRealArg = firstRealArg; return t; } diff -r 0749c0757a43 -r 7985bb036db4 dmd/mtype.h --- a/dmd/mtype.h Tue Feb 03 18:11:39 2009 +0100 +++ b/dmd/mtype.h Tue Feb 03 21:46:46 2009 +0100 @@ -438,11 +438,13 @@ bool retInPtr; bool usesThis; bool usesNest; + bool 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; - size_t reverseIndex; }; struct TypeDelegate : Type diff -r 0749c0757a43 -r 7985bb036db4 gen/functions.cpp --- a/gen/functions.cpp Tue Feb 03 18:11:39 2009 +0100 +++ b/gen/functions.cpp Tue Feb 03 21:46:46 2009 +0100 @@ -101,6 +101,9 @@ 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); @@ -114,7 +117,6 @@ if (n > 1 && f->linkage == LINKd && !dVararg) { f->reverseParams = true; - f->reverseIndex = paramvec.size(); } } #endif // X86_REVERSE_PARAMS @@ -177,24 +179,17 @@ // reverse params? 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 - // 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 ! if ((n > 0 || usesthis || usesnest) && f->linkage == LINKd) { // FIXME: Only x86 right now ... 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; Argument* arg = Argument::getNth(f->parameters, n_inreg); @@ -209,25 +204,42 @@ { 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 if ( (arg->storageClass & (STCref|STCout)) || ((arg->storageClass & STCin) && ((t->isscalar() && !t->isfloating()) || - t->ty == Tclass || t->ty == Tsarray || t->ty == Taarray) && - (t->size() <= PTRSIZE)) + 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 {...} 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 + // 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; @@ -740,6 +752,21 @@ VarDeclaration* vd = argsym->isVarDeclaration(); 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 (vd->nestedrefs.dim) #else @@ -749,9 +776,6 @@ fd->nestedVars.insert(vd); } - IrLocal* irloc = vd->ir.irLocal; - assert(irloc); - bool refout = vd->storage_class & (STCref | STCout); bool lazy = vd->storage_class & STClazy; diff -r 0749c0757a43 -r 7985bb036db4 gen/tocall.cpp --- a/gen/tocall.cpp Tue Feb 03 18:11:39 2009 +0100 +++ b/gen/tocall.cpp Tue Feb 03 21:46:46 2009 +0100 @@ -370,6 +370,13 @@ DValue* argval = DtoArgument(fnarg, (Expression*)arguments->data[i]); 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; // parameter type mismatch, this is hard to get rid of @@ -395,7 +402,7 @@ // reverse the relevant params as well as the param attrs 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()); }