Mercurial > projects > ldc
comparison gen/functions.cpp @ 1024:9167d492cbc2
Abstracted more (most) ABI details out of the normal codegen.
author | Tomas Lindquist Olsen <tomas.l.olsen@gmail.com> |
---|---|
date | Tue, 03 Mar 2009 02:51:21 +0100 |
parents | e8c6dbcd33d1 |
children | 45af482e3832 |
comparison
equal
deleted
inserted
replaced
1023:ca191c141cec | 1024:9167d492cbc2 |
---|---|
20 #include "gen/todebug.h" | 20 #include "gen/todebug.h" |
21 #include "gen/classes.h" | 21 #include "gen/classes.h" |
22 #include "gen/dvalue.h" | 22 #include "gen/dvalue.h" |
23 #include "gen/abi.h" | 23 #include "gen/abi.h" |
24 | 24 |
25 #include <algorithm> | 25 const llvm::FunctionType* DtoFunctionType(Type* type, Type* thistype, Type* nesttype, bool ismain) |
26 | 26 { |
27 const llvm::FunctionType* DtoFunctionType(Type* type, const LLType* thistype, const LLType* nesttype, bool ismain) | 27 // sanity check |
28 { | |
29 assert(type->ty == Tfunction); | 28 assert(type->ty == Tfunction); |
30 TypeFunction* f = (TypeFunction*)type; | 29 TypeFunction* f = (TypeFunction*)type; |
31 | 30 |
31 // already built ? | |
32 if (type->ir.type != NULL) { | 32 if (type->ir.type != NULL) { |
33 assert(f->fty != NULL); | |
33 return llvm::cast<llvm::FunctionType>(type->ir.type->get()); | 34 return llvm::cast<llvm::FunctionType>(type->ir.type->get()); |
34 } | 35 } |
35 | 36 |
36 bool dVararg = false; | 37 // create new ir funcTy |
37 bool arrayVararg = false; | 38 assert(f->fty == NULL); |
38 if (f->linkage == LINKd) | 39 f->fty = new IrFuncTy(); |
39 { | 40 |
40 if (f->varargs == 1) | 41 // llvm idx counter |
41 dVararg = true; | 42 size_t lidx = 0; |
42 else if (f->varargs == 2) | 43 |
43 arrayVararg = true; | 44 // main needs a little special handling |
44 } | |
45 | |
46 // return value type | |
47 const LLType* rettype; | |
48 const LLType* actualRettype; | |
49 Type* rt = f->next; | |
50 bool retinptr = false; | |
51 bool usesthis = false; | |
52 bool usesnest = false; | |
53 | |
54 // parameter types | |
55 std::vector<const LLType*> paramvec; | |
56 | |
57 // special case main | |
58 if (ismain) | 45 if (ismain) |
59 { | 46 { |
60 rettype = LLType::Int32Ty; | 47 f->fty->ret = new IrFuncTyArg(Type::tint32, false); |
61 actualRettype = rettype; | 48 } |
62 if (Argument::dim(f->parameters) == 0) | 49 // sane return value |
63 { | |
64 const LLType* arrTy = DtoArrayType(LLType::Int8Ty); | |
65 const LLType* arrArrTy = DtoArrayType(arrTy); | |
66 paramvec.push_back(arrArrTy); | |
67 } | |
68 } | |
69 // default handling | |
70 else | 50 else |
71 { | 51 { |
72 assert(rt); | 52 Type* rt = f->next; |
73 if (f->linkage == LINKintrinsic) | 53 unsigned a = 0; |
74 { | 54 // sret return |
75 // Intrinsics don't care about ABI | 55 if (gABI->returnInArg(f)) |
76 Logger::cout() << "Intrinsic returning " << rt->toChars() << '\n'; | 56 { |
77 actualRettype = rettype = DtoType(rt); | 57 f->fty->arg_sret = new IrFuncTyArg(rt, true, llvm::Attribute::StructRet); |
78 Logger::cout() << " (LLVM type: " << *rettype << ")\n"; | 58 rt = Type::tvoid; |
59 lidx++; | |
60 } | |
61 // sext/zext return | |
62 else if (unsigned se = DtoShouldExtend(rt)) | |
63 { | |
64 a = se; | |
65 } | |
66 f->fty->ret = new IrFuncTyArg(rt, false, a); | |
67 } | |
68 lidx++; | |
69 | |
70 // member functions | |
71 if (thistype) | |
72 { | |
73 bool toref = (thistype->toBasetype()->ty == Tstruct); | |
74 f->fty->arg_this = new IrFuncTyArg(thistype, toref); | |
75 lidx++; | |
76 } | |
77 | |
78 // and nested functions | |
79 else if (nesttype) | |
80 { | |
81 f->fty->arg_nest = new IrFuncTyArg(nesttype, false); | |
82 lidx++; | |
83 } | |
84 | |
85 // vararg functions are special too | |
86 if (f->varargs) | |
87 { | |
88 if (f->linkage == LINKd) | |
89 { | |
90 // d style with hidden args | |
91 // 2 (array) is handled by the frontend | |
92 if (f->varargs == 1) | |
93 { | |
94 // _arguments | |
95 f->fty->arg_arguments = new IrFuncTyArg(Type::typeinfo->type->arrayOf(), false); | |
96 lidx++; | |
97 // _argptr | |
98 f->fty->arg_argptr = new IrFuncTyArg(Type::tvoid->pointerTo(), false); | |
99 lidx++; | |
100 } | |
101 } | |
102 else if (f->linkage == LINKc) | |
103 { | |
104 f->fty->c_vararg = true; | |
79 } | 105 } |
80 else | 106 else |
81 { | 107 { |
82 if (gABI->returnInArg(f)) | 108 type->error(0, "invalid linkage for variadic function"); |
83 { | 109 fatal(); |
84 rettype = getPtrToType(DtoType(rt)); | 110 } |
85 actualRettype = LLType::VoidTy; | 111 } |
86 f->retInPtr = retinptr = true; | 112 |
87 } | 113 // if this _Dmain() doesn't have an argument, we force it to have one |
88 else | 114 int nargs = Argument::dim(f->parameters); |
89 { | 115 |
90 rettype = DtoType(rt); | 116 if (ismain && nargs == 0) |
91 // do abi specific transformations | 117 { |
92 actualRettype = gABI->getRetType(f, rettype); | 118 Type* mainargs = Type::tchar->arrayOf()->arrayOf(); |
93 } | 119 f->fty->args.push_back(new IrFuncTyArg(mainargs, false)); |
94 | 120 lidx++; |
95 // FIXME: should probably be part of the abi | 121 } |
96 if (unsigned ea = DtoShouldExtend(rt)) | 122 // add explicit parameters |
97 { | 123 else for (int i = 0; i < nargs; i++) |
98 f->retAttrs |= ea; | 124 { |
99 } | 125 // get argument |
100 } | |
101 } | |
102 | |
103 // build up parameter list | |
104 if (retinptr) { | |
105 //Logger::cout() << "returning through pointer parameter: " << *rettype << '\n'; | |
106 paramvec.push_back(rettype); | |
107 } | |
108 | |
109 // this/context param | |
110 if (thistype) { | |
111 paramvec.push_back(thistype); | |
112 usesthis = true; | |
113 } | |
114 else if (nesttype) { | |
115 paramvec.push_back(nesttype); | |
116 usesnest = true; | |
117 } | |
118 | |
119 // dstyle vararg | |
120 if (dVararg) { | |
121 paramvec.push_back(DtoType(Type::typeinfo->type->arrayOf())); // _arguments | |
122 paramvec.push_back(getVoidPtrType()); // _argptr | |
123 } | |
124 | |
125 // now that all implicit args are done, store the start of the real args | |
126 f->firstRealArg = paramvec.size(); | |
127 | |
128 // number of formal params | |
129 size_t n = Argument::dim(f->parameters); | |
130 | |
131 #if X86_REVERSE_PARAMS | |
132 // on x86 we need to reverse the formal params in some cases to match the ABI | |
133 if (global.params.cpu == ARCHx86) | |
134 { | |
135 // more than one formal arg, | |
136 // extern(D) linkage | |
137 // not a D-style vararg | |
138 if (n > 1 && f->linkage == LINKd && !dVararg) | |
139 { | |
140 f->reverseParams = true; | |
141 } | |
142 } | |
143 #endif // X86_REVERSE_PARAMS | |
144 | |
145 | |
146 for (int i=0; i < n; ++i) { | |
147 Argument* arg = Argument::getNth(f->parameters, i); | 126 Argument* arg = Argument::getNth(f->parameters, i); |
148 // ensure scalar | 127 |
149 Type* argT = arg->type->toBasetype(); | 128 // reference semantics? ref, out and static arrays are |
150 assert(argT); | 129 bool byref = (arg->storageClass & (STCref|STCout)) || (arg->type->toBasetype()->ty == Tsarray); |
151 | 130 |
152 bool refOrOut = ((arg->storageClass & STCref) || (arg->storageClass & STCout)); | 131 Type* argtype = arg->type; |
153 | 132 unsigned a = 0; |
154 const LLType* at = DtoType(argT); | |
155 | 133 |
156 // handle lazy args | 134 // handle lazy args |
157 if (arg->storageClass & STClazy) | 135 if (arg->storageClass & STClazy) |
158 { | 136 { |
159 Logger::println("lazy param"); | 137 Logger::println("lazy param"); |
160 TypeFunction *ltf = new TypeFunction(NULL, arg->type, 0, LINKd); | 138 TypeFunction *ltf = new TypeFunction(NULL, arg->type, 0, LINKd); |
161 TypeDelegate *ltd = new TypeDelegate(ltf); | 139 TypeDelegate *ltd = new TypeDelegate(ltf); |
162 at = DtoType(ltd); | 140 argtype = ltd; |
163 paramvec.push_back(at); | 141 } |
164 } | 142 // byval |
165 // opaque types need special handling | 143 else if (gABI->passByVal(argtype)) |
166 else if (llvm::isa<llvm::OpaqueType>(at)) { | 144 { |
167 Logger::println("opaque param"); | 145 if (!byref) a |= llvm::Attribute::ByVal; |
168 assert(argT->ty == Tstruct || argT->ty == Tclass); | 146 byref = true; |
169 paramvec.push_back(getPtrToType(at)); | 147 } |
170 } | 148 // sext/zext |
171 // structs are passed as a reference, but by value | 149 else if (!byref) |
172 else if (argT->ty == Tstruct) { | 150 { |
173 Logger::println("struct param"); | 151 a |= DtoShouldExtend(argtype); |
174 if (!refOrOut) | 152 } |
175 arg->llvmAttrs |= llvm::Attribute::ByVal; | 153 |
176 paramvec.push_back(getPtrToType(at)); | 154 f->fty->args.push_back(new IrFuncTyArg(argtype, byref, a)); |
177 } | 155 lidx++; |
178 // static arrays are passed directly by reference | 156 } |
179 else if (argT->ty == Tsarray) | 157 |
180 { | 158 // let the abi rewrite the types as necesary |
181 Logger::println("static array param"); | 159 gABI->rewriteFunctionType(f); |
182 at = getPtrToType(at); | 160 |
183 paramvec.push_back(at); | 161 // build the function type |
184 } | 162 std::vector<const LLType*> argtypes; |
185 // firstclass ' ref/out ' parameter | 163 argtypes.reserve(lidx); |
186 else if (refOrOut) { | 164 |
187 Logger::println("ref/out param"); | 165 if (f->fty->arg_sret) argtypes.push_back(f->fty->arg_sret->ltype); |
188 at = getPtrToType(at); | 166 if (f->fty->arg_this) argtypes.push_back(f->fty->arg_this->ltype); |
189 paramvec.push_back(at); | 167 if (f->fty->arg_nest) argtypes.push_back(f->fty->arg_nest->ltype); |
190 } | 168 if (f->fty->arg_arguments) argtypes.push_back(f->fty->arg_arguments->ltype); |
191 // firstclass ' in ' parameter | 169 if (f->fty->arg_argptr) argtypes.push_back(f->fty->arg_argptr->ltype); |
192 else { | 170 |
193 Logger::println("in param"); | 171 size_t beg = argtypes.size(); |
194 if (unsigned ea = DtoShouldExtend(argT)) | 172 size_t nargs2 = f->fty->args.size(); |
195 arg->llvmAttrs |= ea; | 173 for (size_t i = 0; i < nargs2; i++) |
196 paramvec.push_back(at); | 174 { |
197 } | 175 argtypes.push_back(f->fty->args[i]->ltype); |
198 } | 176 } |
199 | 177 |
200 // reverse params? | 178 // reverse params? |
201 if (f->reverseParams) | 179 if (f->fty->reverseParams && f->parameters->dim > 1) |
202 { | 180 { |
203 std::reverse(paramvec.begin() + f->firstRealArg, paramvec.end()); | 181 std::reverse(argtypes.begin() + beg, argtypes.end()); |
204 } | 182 } |
205 | 183 |
206 #if X86_PASS_IN_EAX | 184 llvm::FunctionType* functype = llvm::FunctionType::get(f->fty->ret->ltype, argtypes, f->fty->c_vararg); |
207 // pass first param in EAX if it fits, is not floating point and is not a 3 byte struct. | |
208 // ONLY extern(D) functions ! | |
209 if ((n > 0 || usesthis || usesnest) && f->linkage == LINKd) | |
210 { | |
211 // FIXME: Only x86 right now ... | |
212 if (global.params.cpu == ARCHx86) | |
213 { | |
214 int n_inreg = f->reverseParams ? n - 1 : 0; | |
215 Argument* arg = Argument::getNth(f->parameters, n_inreg); | |
216 | |
217 // if there is a implicit context parameter, pass it in EAX | |
218 if (usesthis || usesnest) | |
219 { | |
220 f->thisAttrs |= llvm::Attribute::InReg; | |
221 assert((!arg || (arg->llvmAttrs & llvm::Attribute::InReg) == 0) && "can't have two inreg args!"); | |
222 } | |
223 // otherwise check the first formal parameter | |
224 else | |
225 { | |
226 Type* t = arg->type->toBasetype(); | |
227 | |
228 // 32bit ints, pointers, classes, static arrays, AAs, ref and out params, | |
229 // and structs with size <= 4 and != 3 | |
230 // are candidate for being passed in EAX | |
231 if ( | |
232 (arg->storageClass & (STCref|STCout)) | |
233 || | |
234 ((arg->storageClass & STCin) && | |
235 ((t->isscalar() && !t->isfloating()) || | |
236 t->ty == Tclass || t->ty == Tsarray || t->ty == Taarray || | |
237 (t->ty == Tstruct && t->size() != 3) | |
238 ) && (t->size() <= PTRSIZE)) | |
239 ) | |
240 { | |
241 arg->llvmAttrs |= llvm::Attribute::InReg; | |
242 assert((f->thisAttrs & llvm::Attribute::InReg) == 0 && "can't have two inreg args!"); | |
243 | |
244 // structs need to go from {...}* byval to i8/i16/i32 inreg | |
245 if ((arg->storageClass & STCin) && t->ty == Tstruct) | |
246 { | |
247 int n_param = f->reverseParams ? f->firstRealArg + n - 1 - n_inreg : f->firstRealArg + n_inreg; | |
248 assert(isaPointer(paramvec[n_param]) && (arg->llvmAttrs & llvm::Attribute::ByVal) | |
249 && "struct parameter expected to be {...}* byval before inreg is applied"); | |
250 f->structInregArg = paramvec[n_param]->getContainedType(0); | |
251 paramvec[n_param] = LLIntegerType::get(8*t->size()); | |
252 arg->llvmAttrs &= ~llvm::Attribute::ByVal; | |
253 } | |
254 } | |
255 } | |
256 } | |
257 } | |
258 #endif // X86_PASS_IN_EAX | |
259 | |
260 // construct function type | |
261 bool isvararg = !(dVararg || arrayVararg) && f->varargs; | |
262 llvm::FunctionType* functype = llvm::FunctionType::get(actualRettype, paramvec, isvararg); | |
263 | |
264 // done | |
265 f->retInPtr = retinptr; | |
266 f->usesThis = usesthis; | |
267 f->usesNest = usesnest; | |
268 | |
269 f->ir.type = new llvm::PATypeHolder(functype); | 185 f->ir.type = new llvm::PATypeHolder(functype); |
270 | 186 |
271 return functype; | 187 return functype; |
272 } | 188 } |
273 | 189 |
281 } | 197 } |
282 | 198 |
283 TypeFunction* f = (TypeFunction*)fdecl->type; | 199 TypeFunction* f = (TypeFunction*)fdecl->type; |
284 const llvm::FunctionType* fty = 0; | 200 const llvm::FunctionType* fty = 0; |
285 | 201 |
202 // create new ir funcTy | |
203 assert(f->fty == NULL); | |
204 f->fty = new IrFuncTy(); | |
205 f->fty->ret = new IrFuncTyArg(Type::tvoid, false); | |
206 | |
207 f->fty->args.push_back(new IrFuncTyArg(Type::tvoid->pointerTo(), false)); | |
208 | |
286 if (fdecl->llvmInternal == LLVMva_start) | 209 if (fdecl->llvmInternal == LLVMva_start) |
287 fty = GET_INTRINSIC_DECL(vastart)->getFunctionType(); | 210 fty = GET_INTRINSIC_DECL(vastart)->getFunctionType(); |
288 else if (fdecl->llvmInternal == LLVMva_copy) | 211 else if (fdecl->llvmInternal == LLVMva_copy) { |
289 fty = GET_INTRINSIC_DECL(vacopy)->getFunctionType(); | 212 fty = GET_INTRINSIC_DECL(vacopy)->getFunctionType(); |
213 f->fty->args.push_back(new IrFuncTyArg(Type::tvoid->pointerTo(), false)); | |
214 } | |
290 else if (fdecl->llvmInternal == LLVMva_end) | 215 else if (fdecl->llvmInternal == LLVMva_end) |
291 fty = GET_INTRINSIC_DECL(vaend)->getFunctionType(); | 216 fty = GET_INTRINSIC_DECL(vaend)->getFunctionType(); |
292 assert(fty); | 217 assert(fty); |
293 | 218 |
294 f->ir.type = new llvm::PATypeHolder(fty); | 219 f->ir.type = new llvm::PATypeHolder(fty); |
305 | 230 |
306 // type has already been resolved | 231 // type has already been resolved |
307 if (fdecl->type->ir.type != 0) | 232 if (fdecl->type->ir.type != 0) |
308 return llvm::cast<llvm::FunctionType>(fdecl->type->ir.type->get()); | 233 return llvm::cast<llvm::FunctionType>(fdecl->type->ir.type->get()); |
309 | 234 |
310 const LLType* thisty = 0; | 235 Type *dthis=0, *dnest=0; |
311 const LLType* nestty = 0; | |
312 | 236 |
313 if (fdecl->needThis()) { | 237 if (fdecl->needThis()) { |
314 if (AggregateDeclaration* ad = fdecl->isMember2()) { | 238 if (AggregateDeclaration* ad = fdecl->isMember2()) { |
315 Logger::println("isMember = this is: %s", ad->type->toChars()); | 239 Logger::println("isMember = this is: %s", ad->type->toChars()); |
316 thisty = DtoType(ad->type); | 240 dthis = ad->type; |
241 const LLType* thisty = DtoType(dthis); | |
317 //Logger::cout() << "this llvm type: " << *thisty << '\n'; | 242 //Logger::cout() << "this llvm type: " << *thisty << '\n'; |
318 if (isaStruct(thisty) || (!gIR->structs.empty() && thisty == gIR->topstruct()->type->ir.type->get())) | 243 if (isaStruct(thisty) || (!gIR->structs.empty() && thisty == gIR->topstruct()->type->ir.type->get())) |
319 thisty = getPtrToType(thisty); | 244 thisty = getPtrToType(thisty); |
320 } | 245 } |
321 else { | 246 else { |
322 Logger::println("chars: %s type: %s kind: %s", fdecl->toChars(), fdecl->type->toChars(), fdecl->kind()); | 247 Logger::println("chars: %s type: %s kind: %s", fdecl->toChars(), fdecl->type->toChars(), fdecl->kind()); |
323 assert(0); | 248 assert(0); |
324 } | 249 } |
325 } | 250 } |
326 else if (fdecl->isNested()) { | 251 else if (fdecl->isNested()) { |
327 nestty = getPtrToType(LLType::Int8Ty); | 252 dnest = Type::tvoid->pointerTo(); |
328 } | 253 } |
329 | 254 |
330 const llvm::FunctionType* functype = DtoFunctionType(fdecl->type, thisty, nestty, fdecl->isMain()); | 255 const llvm::FunctionType* functype = DtoFunctionType(fdecl->type, dthis, dnest, fdecl->isMain()); |
331 | 256 |
332 return functype; | 257 return functype; |
333 } | 258 } |
334 | 259 |
335 ////////////////////////////////////////////////////////////////////////////////////////// | 260 ////////////////////////////////////////////////////////////////////////////////////////// |
412 | 337 |
413 ////////////////////////////////////////////////////////////////////////////////////////// | 338 ////////////////////////////////////////////////////////////////////////////////////////// |
414 | 339 |
415 static void set_param_attrs(TypeFunction* f, llvm::Function* func, FuncDeclaration* fdecl) | 340 static void set_param_attrs(TypeFunction* f, llvm::Function* func, FuncDeclaration* fdecl) |
416 { | 341 { |
417 int llidx = 0; | |
418 if (f->retInPtr) ++llidx; | |
419 if (f->usesThis) ++llidx; | |
420 else if (f->usesNest) ++llidx; | |
421 if (f->linkage == LINKd && f->varargs == 1) | |
422 llidx += 2; | |
423 | |
424 int funcNumArgs = func->getArgumentList().size(); | 342 int funcNumArgs = func->getArgumentList().size(); |
425 | 343 |
426 LLSmallVector<llvm::AttributeWithIndex, 9> attrs; | 344 LLSmallVector<llvm::AttributeWithIndex, 9> attrs; |
427 llvm::AttributeWithIndex PAWI; | 345 llvm::AttributeWithIndex PAWI; |
428 | 346 |
429 // set return value attrs if any | 347 int idx = 0; |
430 if (f->retAttrs) | 348 |
431 { | 349 // handle implicit args |
432 PAWI.Index = 0; | 350 #define ADD_PA(X) \ |
433 PAWI.Attrs = f->retAttrs; | 351 if (f->fty->X) { \ |
434 attrs.push_back(PAWI); | 352 if (f->fty->X->attrs) { \ |
435 } | 353 PAWI.Index = idx; \ |
436 | 354 PAWI.Attrs = f->fty->X->attrs; \ |
437 // set sret param | 355 attrs.push_back(PAWI); \ |
438 if (f->retInPtr) | 356 } \ |
439 { | 357 idx++; \ |
440 PAWI.Index = 1; | 358 } |
441 PAWI.Attrs = llvm::Attribute::StructRet; | 359 |
442 attrs.push_back(PAWI); | 360 ADD_PA(ret) |
443 } | 361 ADD_PA(arg_sret) |
444 | 362 ADD_PA(arg_this) |
445 // set this/nest param attrs | 363 ADD_PA(arg_nest) |
446 if (f->thisAttrs) | 364 ADD_PA(arg_arguments) |
447 { | 365 ADD_PA(arg_argptr) |
448 PAWI.Index = f->retInPtr ? 2 : 1; | 366 |
449 PAWI.Attrs = f->thisAttrs; | 367 #undef ADD_PA |
450 attrs.push_back(PAWI); | |
451 } | |
452 | 368 |
453 // set attrs on the rest of the arguments | 369 // set attrs on the rest of the arguments |
454 size_t n = Argument::dim(f->parameters); | 370 size_t n = Argument::dim(f->parameters); |
455 assert(funcNumArgs >= n); // main might mismatch, for the implicit char[][] arg | |
456 | |
457 LLSmallVector<unsigned,8> attrptr(n, 0); | 371 LLSmallVector<unsigned,8> attrptr(n, 0); |
458 | 372 |
459 for (size_t k = 0; k < n; ++k) | 373 for (size_t k = 0; k < n; ++k) |
460 { | 374 { |
461 Argument* fnarg = Argument::getNth(f->parameters, k); | 375 Argument* fnarg = Argument::getNth(f->parameters, k); |
462 assert(fnarg); | 376 assert(fnarg); |
463 | 377 |
464 attrptr[k] = fnarg->llvmAttrs; | 378 attrptr[k] = f->fty->args[k]->attrs; |
465 } | 379 } |
466 | 380 |
467 // reverse params? | 381 // reverse params? |
468 if (f->reverseParams) | 382 if (f->fty->reverseParams) |
469 { | 383 { |
470 std::reverse(attrptr.begin(), attrptr.end()); | 384 std::reverse(attrptr.begin(), attrptr.end()); |
471 } | 385 } |
472 | 386 |
473 // build rest of attrs list | 387 // build rest of attrs list |
474 for (int i = 0; i < n; i++) | 388 for (int i = 0; i < n; i++) |
475 { | 389 { |
476 if (attrptr[i]) | 390 if (attrptr[i]) |
477 { | 391 { |
478 PAWI.Index = llidx+i+1; | 392 PAWI.Index = idx+i; |
479 PAWI.Attrs = attrptr[i]; | 393 PAWI.Attrs = attrptr[i]; |
480 attrs.push_back(PAWI); | 394 attrs.push_back(PAWI); |
481 } | 395 } |
482 } | 396 } |
483 | 397 |
573 if (!declareOnly) | 487 if (!declareOnly) |
574 { | 488 { |
575 // name parameters | 489 // name parameters |
576 llvm::Function::arg_iterator iarg = func->arg_begin(); | 490 llvm::Function::arg_iterator iarg = func->arg_begin(); |
577 | 491 |
578 if (f->retInPtr) { | 492 if (f->fty->arg_sret) { |
579 iarg->setName(".sret_arg"); | 493 iarg->setName(".sret_arg"); |
580 fdecl->ir.irFunc->retArg = iarg; | 494 fdecl->ir.irFunc->retArg = iarg; |
581 ++iarg; | 495 ++iarg; |
582 } | 496 } |
583 | 497 |
584 if (f->usesThis) { | 498 if (f->fty->arg_this) { |
585 iarg->setName(".this_arg"); | 499 iarg->setName(".this_arg"); |
586 fdecl->ir.irFunc->thisArg = iarg; | 500 fdecl->ir.irFunc->thisArg = iarg; |
587 assert(fdecl->ir.irFunc->thisArg); | 501 assert(fdecl->ir.irFunc->thisArg); |
588 ++iarg; | 502 ++iarg; |
589 } | 503 } |
590 else if (f->usesNest) { | 504 else if (f->fty->arg_nest) { |
591 iarg->setName(".nest_arg"); | 505 iarg->setName(".nest_arg"); |
592 fdecl->ir.irFunc->nestArg = iarg; | 506 fdecl->ir.irFunc->nestArg = iarg; |
593 assert(fdecl->ir.irFunc->nestArg); | 507 assert(fdecl->ir.irFunc->nestArg); |
594 ++iarg; | 508 ++iarg; |
595 } | 509 } |
596 | 510 |
597 if (f->linkage == LINKd && f->varargs == 1) { | 511 if (f->fty->arg_argptr) { |
598 iarg->setName("._arguments"); | 512 iarg->setName("._arguments"); |
599 fdecl->ir.irFunc->_arguments = iarg; | 513 fdecl->ir.irFunc->_arguments = iarg; |
600 ++iarg; | 514 ++iarg; |
601 iarg->setName("._argptr"); | 515 iarg->setName("._argptr"); |
602 fdecl->ir.irFunc->_argptr = iarg; | 516 fdecl->ir.irFunc->_argptr = iarg; |
608 for (; iarg != func->arg_end(); ++iarg) | 522 for (; iarg != func->arg_end(); ++iarg) |
609 { | 523 { |
610 if (fdecl->parameters && fdecl->parameters->dim > k) | 524 if (fdecl->parameters && fdecl->parameters->dim > k) |
611 { | 525 { |
612 Dsymbol* argsym; | 526 Dsymbol* argsym; |
613 if (f->reverseParams) | 527 if (f->fty->reverseParams) |
614 argsym = (Dsymbol*)fdecl->parameters->data[fdecl->parameters->dim-k-1]; | 528 argsym = (Dsymbol*)fdecl->parameters->data[fdecl->parameters->dim-k-1]; |
615 else | 529 else |
616 argsym = (Dsymbol*)fdecl->parameters->data[k]; | 530 argsym = (Dsymbol*)fdecl->parameters->data[k]; |
617 | 531 |
618 VarDeclaration* argvd = argsym->isVarDeclaration(); | 532 VarDeclaration* argvd = argsym->isVarDeclaration(); |
646 Logger::cout() << "func decl: " << *func << '\n'; | 560 Logger::cout() << "func decl: " << *func << '\n'; |
647 } | 561 } |
648 | 562 |
649 ////////////////////////////////////////////////////////////////////////////////////////// | 563 ////////////////////////////////////////////////////////////////////////////////////////// |
650 | 564 |
565 // FIXME: this isn't too pretty! | |
566 | |
651 void DtoDefineFunction(FuncDeclaration* fd) | 567 void DtoDefineFunction(FuncDeclaration* fd) |
652 { | 568 { |
653 if (fd->ir.defined) return; | 569 if (fd->ir.defined) return; |
654 fd->ir.defined = true; | 570 fd->ir.defined = true; |
655 | 571 |
725 LLFunction* hack = GET_INTRINSIC_DECL(eh_unwind_init); | 641 LLFunction* hack = GET_INTRINSIC_DECL(eh_unwind_init); |
726 gIR->ir->CreateCall(hack, ""); | 642 gIR->ir->CreateCall(hack, ""); |
727 } | 643 } |
728 | 644 |
729 // give the 'this' argument storage and debug info | 645 // give the 'this' argument storage and debug info |
730 if (f->usesThis) | 646 if (f->fty->arg_this) |
731 { | 647 { |
732 LLValue* thisvar = irfunction->thisArg; | 648 LLValue* thisvar = irfunction->thisArg; |
733 assert(thisvar); | 649 assert(thisvar); |
734 | 650 |
735 LLValue* thismem = DtoAlloca(thisvar->getType(), "this"); | 651 LLValue* thismem = DtoAlloca(thisvar->getType(), "this"); |
755 | 671 |
756 // give arguments storage | 672 // give arguments storage |
757 // and debug info | 673 // and debug info |
758 if (fd->parameters) | 674 if (fd->parameters) |
759 { | 675 { |
760 size_t n = fd->parameters->dim; | 676 size_t n = f->fty->args.size(); |
677 assert(n == fd->parameters->dim); | |
761 for (int i=0; i < n; ++i) | 678 for (int i=0; i < n; ++i) |
762 { | 679 { |
763 Dsymbol* argsym = (Dsymbol*)fd->parameters->data[i]; | 680 Dsymbol* argsym = (Dsymbol*)fd->parameters->data[i]; |
764 VarDeclaration* vd = argsym->isVarDeclaration(); | 681 VarDeclaration* vd = argsym->isVarDeclaration(); |
765 assert(vd); | 682 assert(vd); |
766 | 683 |
767 IrLocal* irloc = vd->ir.irLocal; | 684 IrLocal* irloc = vd->ir.irLocal; |
768 assert(irloc); | 685 assert(irloc); |
769 | 686 |
770 // if it's inreg struct arg, allocate storage | 687 // let the abi transform the argument back first |
771 if (f->structInregArg && i == (f->reverseParams ? n - 1 : 0)) | 688 LLValue* argvalue = f->fty->getParam(vd->type, i, irloc->value); |
772 { | |
773 int n_param = f->reverseParams ? f->firstRealArg + n - 1 - i : f->firstRealArg + i; | |
774 const LLType* paramty = functype->getParamType(n_param); | |
775 assert(!f->usesNest && !f->usesThis && | |
776 llvm::isa<LLIntegerType>(paramty) && isaStruct(f->structInregArg) | |
777 && "Preconditions for inreg struct arg not met!"); | |
778 | |
779 LLValue* mem = DtoAlloca(f->structInregArg, "inregstructarg"); | |
780 | |
781 DtoStore(irloc->value, DtoBitCast(mem, getPtrToType(paramty))); | |
782 irloc->value = mem; | |
783 } | |
784 | 689 |
785 #if DMDV2 | 690 #if DMDV2 |
786 if (vd->nestedrefs.dim) | 691 if (vd->nestedrefs.dim) |
787 #else | 692 #else |
788 if (vd->nestedref) | 693 if (vd->nestedref) |
792 } | 697 } |
793 | 698 |
794 bool refout = vd->storage_class & (STCref | STCout); | 699 bool refout = vd->storage_class & (STCref | STCout); |
795 bool lazy = vd->storage_class & STClazy; | 700 bool lazy = vd->storage_class & STClazy; |
796 | 701 |
797 if (!refout && (!DtoIsPassedByRef(vd->type) || lazy)) | 702 if (!refout && (!f->fty->args[i]->byref || lazy)) |
798 { | 703 { |
799 LLValue* a = irloc->value; | 704 LLValue* a = argvalue; |
800 LLValue* v = DtoAlloca(a->getType(), vd->ident->toChars()); | 705 LLValue* v = DtoAlloca(a->getType(), vd->ident->toChars()); |
801 DtoStore(a,v); | 706 DtoStore(a,v); |
802 irloc->value = v; | 707 irloc->value = v; |
803 } | 708 } |
804 if (global.params.symdebug && !(isaArgument(irloc->value) && !isaArgument(irloc->value)->hasByValAttr()) && !refout) | 709 if (global.params.symdebug && !(isaArgument(irloc->value) && !isaArgument(irloc->value)->hasByValAttr()) && !refout) |