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))