Mercurial > projects > ldc
comparison gen/functions.cpp @ 930:7985bb036db4
Follow the D ABI and pass the last arg in a register if it is a struct that fits.
author | Christian Kamm <kamm incasoftware de> |
---|---|
date | Tue, 03 Feb 2009 21:46:46 +0100 |
parents | 545f54041d91 |
children | d3a6f1a96731 a904cc9bc064 |
comparison
equal
deleted
inserted
replaced
922:0749c0757a43 | 930:7985bb036db4 |
---|---|
99 if (dVararg) { | 99 if (dVararg) { |
100 paramvec.push_back(DtoType(Type::typeinfo->type->arrayOf())); // _arguments | 100 paramvec.push_back(DtoType(Type::typeinfo->type->arrayOf())); // _arguments |
101 paramvec.push_back(getVoidPtrType()); // _argptr | 101 paramvec.push_back(getVoidPtrType()); // _argptr |
102 } | 102 } |
103 | 103 |
104 // now that all implicit args are done, store the start of the real args | |
105 f->firstRealArg = paramvec.size(); | |
106 | |
104 // number of formal params | 107 // number of formal params |
105 size_t n = Argument::dim(f->parameters); | 108 size_t n = Argument::dim(f->parameters); |
106 | 109 |
107 #if X86_REVERSE_PARAMS | 110 #if X86_REVERSE_PARAMS |
108 // on x86 we need to reverse the formal params in some cases to match the ABI | 111 // on x86 we need to reverse the formal params in some cases to match the ABI |
112 // extern(D) linkage | 115 // extern(D) linkage |
113 // not a D-style vararg | 116 // not a D-style vararg |
114 if (n > 1 && f->linkage == LINKd && !dVararg) | 117 if (n > 1 && f->linkage == LINKd && !dVararg) |
115 { | 118 { |
116 f->reverseParams = true; | 119 f->reverseParams = true; |
117 f->reverseIndex = paramvec.size(); | |
118 } | 120 } |
119 } | 121 } |
120 #endif // X86_REVERSE_PARAMS | 122 #endif // X86_REVERSE_PARAMS |
121 | 123 |
122 | 124 |
175 } | 177 } |
176 | 178 |
177 // reverse params? | 179 // reverse params? |
178 if (f->reverseParams) | 180 if (f->reverseParams) |
179 { | 181 { |
180 std::reverse(paramvec.begin() + f->reverseIndex, paramvec.end()); | 182 std::reverse(paramvec.begin() + f->firstRealArg, paramvec.end()); |
181 } | 183 } |
182 | |
183 // construct function type | |
184 bool isvararg = !(dVararg || arrayVararg) && f->varargs; | |
185 llvm::FunctionType* functype = llvm::FunctionType::get(actualRettype, paramvec, isvararg); | |
186 | 184 |
187 #if X86_PASS_IN_EAX | 185 #if X86_PASS_IN_EAX |
188 // tell first param to be passed in a register if we can | 186 // pass first param in EAX if it fits, is not floating point and is not a 3 byte struct. |
189 // ONLY extern(D) functions ! | 187 // ONLY extern(D) functions ! |
190 if ((n > 0 || usesthis || usesnest) && f->linkage == LINKd) | 188 if ((n > 0 || usesthis || usesnest) && f->linkage == LINKd) |
191 { | 189 { |
192 // FIXME: Only x86 right now ... | 190 // FIXME: Only x86 right now ... |
193 if (global.params.cpu == ARCHx86) | 191 if (global.params.cpu == ARCHx86) |
194 { | 192 { |
195 // pass first param in EAX if it fits, is not floating point and is not a 3 byte struct. | |
196 // FIXME: struct are not passed in EAX yet | |
197 | |
198 int n_inreg = f->reverseParams ? n - 1 : 0; | 193 int n_inreg = f->reverseParams ? n - 1 : 0; |
199 Argument* arg = Argument::getNth(f->parameters, n_inreg); | 194 Argument* arg = Argument::getNth(f->parameters, n_inreg); |
200 | 195 |
201 // if there is a implicit context parameter, pass it in EAX | 196 // if there is a implicit context parameter, pass it in EAX |
202 if (usesthis || usesnest) | 197 if (usesthis || usesnest) |
207 // otherwise check the first formal parameter | 202 // otherwise check the first formal parameter |
208 else | 203 else |
209 { | 204 { |
210 Type* t = arg->type->toBasetype(); | 205 Type* t = arg->type->toBasetype(); |
211 | 206 |
212 // 32bit ints, pointers, classes, static arrays, AAs, ref and out params | 207 // 32bit ints, pointers, classes, static arrays, AAs, ref and out params, |
208 // and structs with size <= 4 and != 3 | |
213 // are candidate for being passed in EAX | 209 // are candidate for being passed in EAX |
214 if ( | 210 if ( |
215 (arg->storageClass & (STCref|STCout)) | 211 (arg->storageClass & (STCref|STCout)) |
216 || | 212 || |
217 ((arg->storageClass & STCin) && | 213 ((arg->storageClass & STCin) && |
218 ((t->isscalar() && !t->isfloating()) || | 214 ((t->isscalar() && !t->isfloating()) || |
219 t->ty == Tclass || t->ty == Tsarray || t->ty == Taarray) && | 215 t->ty == Tclass || t->ty == Tsarray || t->ty == Taarray || |
220 (t->size() <= PTRSIZE)) | 216 (t->ty == Tstruct && t->size() != 3) |
217 ) && (t->size() <= PTRSIZE)) | |
221 ) | 218 ) |
222 { | 219 { |
223 arg->llvmAttrs |= llvm::Attribute::InReg; | 220 arg->llvmAttrs |= llvm::Attribute::InReg; |
224 assert((f->thisAttrs & llvm::Attribute::InReg) == 0 && "can't have two inreg args!"); | 221 assert((f->thisAttrs & llvm::Attribute::InReg) == 0 && "can't have two inreg args!"); |
222 | |
223 // structs need to go from {...}* byval to {...} inreg | |
224 if ((arg->storageClass & STCin) && t->ty == Tstruct) | |
225 { | |
226 int n_param = f->reverseParams ? f->firstRealArg + n - 1 - n_inreg : f->firstRealArg + n_inreg; | |
227 assert(isaPointer(paramvec[n_param]) && (arg->llvmAttrs & llvm::Attribute::ByVal) | |
228 && "struct parameter expected to be {...}* byval before inreg is applied"); | |
229 paramvec[n_param] = paramvec[n_param]->getContainedType(0); | |
230 arg->llvmAttrs &= ~llvm::Attribute::ByVal; | |
231 f->structInregArg = true; | |
232 } | |
225 } | 233 } |
226 } | 234 } |
227 } | 235 } |
228 } | 236 } |
229 #endif // X86_PASS_IN_EAX | 237 #endif // X86_PASS_IN_EAX |
238 | |
239 // construct function type | |
240 bool isvararg = !(dVararg || arrayVararg) && f->varargs; | |
241 llvm::FunctionType* functype = llvm::FunctionType::get(actualRettype, paramvec, isvararg); | |
230 | 242 |
231 // done | 243 // done |
232 f->retInPtr = retinptr; | 244 f->retInPtr = retinptr; |
233 f->usesThis = usesthis; | 245 f->usesThis = usesthis; |
234 f->usesNest = usesnest; | 246 f->usesNest = usesnest; |
737 for (int i=0; i < n; ++i) | 749 for (int i=0; i < n; ++i) |
738 { | 750 { |
739 Dsymbol* argsym = (Dsymbol*)fd->parameters->data[i]; | 751 Dsymbol* argsym = (Dsymbol*)fd->parameters->data[i]; |
740 VarDeclaration* vd = argsym->isVarDeclaration(); | 752 VarDeclaration* vd = argsym->isVarDeclaration(); |
741 assert(vd); | 753 assert(vd); |
754 | |
755 IrLocal* irloc = vd->ir.irLocal; | |
756 assert(irloc); | |
757 | |
758 // if it's inreg struct arg, allocate storage | |
759 if (f->structInregArg && i == (f->reverseParams ? n - 1 : 0)) | |
760 { | |
761 int n_param = f->reverseParams ? f->firstRealArg + n - 1 - i : f->firstRealArg + i; | |
762 assert(!f->usesNest && !f->usesThis && isaStruct(functype->getParamType(n_param)) | |
763 && "Preconditions for inreg struct arg not met!"); | |
764 | |
765 LLValue* mem = DtoAlloca(functype->getParamType(n_param), "inregstructarg"); | |
766 DtoStore(irloc->value, mem); | |
767 irloc->value = mem; | |
768 } | |
742 | 769 |
743 #if DMDV2 | 770 #if DMDV2 |
744 if (vd->nestedrefs.dim) | 771 if (vd->nestedrefs.dim) |
745 #else | 772 #else |
746 if (vd->nestedref) | 773 if (vd->nestedref) |
747 #endif | 774 #endif |
748 { | 775 { |
749 fd->nestedVars.insert(vd); | 776 fd->nestedVars.insert(vd); |
750 } | 777 } |
751 | |
752 IrLocal* irloc = vd->ir.irLocal; | |
753 assert(irloc); | |
754 | 778 |
755 bool refout = vd->storage_class & (STCref | STCout); | 779 bool refout = vd->storage_class & (STCref | STCout); |
756 bool lazy = vd->storage_class & STClazy; | 780 bool lazy = vd->storage_class & STClazy; |
757 | 781 |
758 if (!refout && (!DtoIsPassedByRef(vd->type) || lazy)) | 782 if (!refout && (!DtoIsPassedByRef(vd->type) || lazy)) |