Changeset 930:7985bb036db4
- Timestamp:
- 02/03/09 15:46:46
(3 years ago)
- Author:
- Christian Kamm <kamm incasoftware de>
- branch:
- default
- Message:
Follow the D ABI and pass the last arg in a register if it is a struct that fits.
-
Files:
-
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
| r913 |
r930 |
|
| 2692 | 2692 | this->usesThis = false; |
|---|
| 2693 | 2693 | this->usesNest = false; |
|---|
| | 2694 | this->structInregArg = false; |
|---|
| 2694 | 2695 | this->retAttrs = 0; |
|---|
| 2695 | 2696 | this->thisAttrs = 0; |
|---|
| 2696 | 2697 | this->reverseParams = false; |
|---|
| 2697 | | this->reverseIndex = 0; |
|---|
| | 2698 | this->firstRealArg = 0; |
|---|
| 2698 | 2699 | } |
|---|
| 2699 | 2700 | |
|---|
| … | … | |
| 2709 | 2710 | t->thisAttrs = thisAttrs; |
|---|
| 2710 | 2711 | t->reverseParams = reverseParams; |
|---|
| 2711 | | t->reverseIndex = reverseIndex; |
|---|
| | 2712 | t->firstRealArg = firstRealArg; |
|---|
| 2712 | 2713 | return t; |
|---|
| 2713 | 2714 | } |
|---|
| r875 |
r930 |
|
| 439 | 439 | bool usesThis; |
|---|
| 440 | 440 | bool usesNest; |
|---|
| | 441 | bool structInregArg; |
|---|
| 441 | 442 | unsigned retAttrs; |
|---|
| 442 | 443 | unsigned thisAttrs; // also used for nest |
|---|
| | 444 | // parameter index in the llvm function that contains the first not-implicit arg |
|---|
| | 445 | size_t firstRealArg; |
|---|
| 443 | 446 | |
|---|
| 444 | 447 | bool reverseParams; |
|---|
| 445 | | size_t reverseIndex; |
|---|
| 446 | 448 | }; |
|---|
| 447 | 449 | |
|---|
| r920 |
r930 |
|
| 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 | 107 | // number of formal params |
|---|
| 105 | 108 | size_t n = Argument::dim(f->parameters); |
|---|
| … | … | |
| 115 | 118 | { |
|---|
| 116 | 119 | f->reverseParams = true; |
|---|
| 117 | | f->reverseIndex = paramvec.size(); |
|---|
| 118 | 120 | } |
|---|
| 119 | 121 | } |
|---|
| … | … | |
| 178 | 180 | if (f->reverseParams) |
|---|
| 179 | 181 | { |
|---|
| 180 | | std::reverse(paramvec.begin() + f->reverseIndex, paramvec.end()); |
|---|
| 181 | | } |
|---|
| 182 | | |
|---|
| 183 | | // construct function type |
|---|
| 184 | | bool isvararg = !(dVararg || arrayVararg) && f->varargs; |
|---|
| 185 | | llvm::FunctionType* functype = llvm::FunctionType::get(actualRettype, paramvec, isvararg); |
|---|
| | 182 | std::reverse(paramvec.begin() + f->firstRealArg, paramvec.end()); |
|---|
| | 183 | } |
|---|
| 186 | 184 | |
|---|
| 187 | 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 | 187 | // ONLY extern(D) functions ! |
|---|
| 190 | 188 | if ((n > 0 || usesthis || usesnest) && f->linkage == LINKd) |
|---|
| … | … | |
| 193 | 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 | 193 | int n_inreg = f->reverseParams ? n - 1 : 0; |
|---|
| 199 | 194 | Argument* arg = Argument::getNth(f->parameters, n_inreg); |
|---|
| … | … | |
| 210 | 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 | 209 | // are candidate for being passed in EAX |
|---|
| 214 | 210 | if ( |
|---|
| … | … | |
| 217 | 213 | ((arg->storageClass & STCin) && |
|---|
| 218 | 214 | ((t->isscalar() && !t->isfloating()) || |
|---|
| 219 | | t->ty == Tclass || t->ty == Tsarray || t->ty == Taarray) && |
|---|
| 220 | | (t->size() <= PTRSIZE)) |
|---|
| | 215 | t->ty == Tclass || t->ty == Tsarray || t->ty == Taarray || |
|---|
| | 216 | (t->ty == Tstruct && t->size() != 3) |
|---|
| | 217 | ) && (t->size() <= PTRSIZE)) |
|---|
| 221 | 218 | ) |
|---|
| 222 | 219 | { |
|---|
| 223 | 220 | arg->llvmAttrs |= llvm::Attribute::InReg; |
|---|
| 224 | 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 | } |
|---|
| … | … | |
| 228 | 236 | } |
|---|
| 229 | 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 | 243 | // done |
|---|
| … | … | |
| 740 | 752 | VarDeclaration* vd = argsym->isVarDeclaration(); |
|---|
| 741 | 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 | 770 | #if DMDV2 |
|---|
| … | … | |
| 749 | 776 | fd->nestedVars.insert(vd); |
|---|
| 750 | 777 | } |
|---|
| 751 | | |
|---|
| 752 | | IrLocal* irloc = vd->ir.irLocal; |
|---|
| 753 | | assert(irloc); |
|---|
| 754 | 778 | |
|---|
| 755 | 779 | bool refout = vd->storage_class & (STCref | STCout); |
|---|
| r839 |
r930 |
|
| 371 | 371 | LLValue* arg = argval->getRVal(); |
|---|
| 372 | 372 | |
|---|
| | 373 | // if it's a struct inreg arg, load first to pass as first-class value |
|---|
| | 374 | if (tf->structInregArg && i == (tf->reverseParams ? n - 1 : 0)) |
|---|
| | 375 | { |
|---|
| | 376 | assert(fnarg->llvmAttrs & llvm::Attribute::InReg); |
|---|
| | 377 | arg = DtoLoad(arg); |
|---|
| | 378 | } |
|---|
| | 379 | |
|---|
| 373 | 380 | int j = tf->reverseParams ? beg + n - i - 1 : beg + i; |
|---|
| 374 | 381 | |
|---|
| … | … | |
| 396 | 403 | if (tf->reverseParams) |
|---|
| 397 | 404 | { |
|---|
| 398 | | std::reverse(args.begin() + tf->reverseIndex, args.end()); |
|---|
| | 405 | std::reverse(args.begin() + tf->firstRealArg, args.end()); |
|---|
| 399 | 406 | std::reverse(attrptr.begin(), attrptr.end()); |
|---|
| 400 | 407 | } |
|---|