Mercurial > projects > ldc
comparison gen/functions.cpp @ 445:cc40db549aea
Changed the handling of variadic intrinsics a bit.
Removed the -fp80 option and made real be 80bit floats on X86, this is what the D spec really says it should be and fixes a bunch of issues.
Changed the handling of parameter attributes to a bit more generalized approach.
Added sext/zext attributes for byte/short/ubyte/ushort parameters, fixes #60 .
Parameter attribs now properly set for intrinsic calls if necessary.
Made the tango.math.Math patch less intrusive.
Fixed/added some mini tests.
author | Tomas Lindquist Olsen <tomas.l.olsen@gmail.com> |
---|---|
date | Fri, 01 Aug 2008 17:59:58 +0200 |
parents | 44f08170f4ef |
children | 7a67dedbf933 |
comparison
equal
deleted
inserted
replaced
444:f2b5f86348ef | 445:cc40db549aea |
---|---|
1 #include "gen/llvm.h" | 1 #include "gen/llvm.h" |
2 #include "llvm/Support/CFG.h" | 2 #include "llvm/Support/CFG.h" |
3 #include "llvm/Intrinsics.h" | |
3 | 4 |
4 #include "mtype.h" | 5 #include "mtype.h" |
5 #include "aggregate.h" | 6 #include "aggregate.h" |
6 #include "init.h" | 7 #include "init.h" |
7 #include "declaration.h" | 8 #include "declaration.h" |
60 paramvec.push_back(getPtrToType(arrArrTy)); | 61 paramvec.push_back(getPtrToType(arrArrTy)); |
61 } | 62 } |
62 } | 63 } |
63 else{ | 64 else{ |
64 assert(rt); | 65 assert(rt); |
65 Type* rtfin = DtoDType(rt); | |
66 if (DtoIsReturnedInArg(rt)) { | 66 if (DtoIsReturnedInArg(rt)) { |
67 rettype = getPtrToType(DtoType(rt)); | 67 rettype = getPtrToType(DtoType(rt)); |
68 actualRettype = LLType::VoidTy; | 68 actualRettype = LLType::VoidTy; |
69 f->llvmRetInPtr = retinptr = true; | 69 f->llvmRetInPtr = retinptr = true; |
70 } | 70 } |
71 else { | 71 else { |
72 rettype = DtoType(rt); | 72 rettype = DtoType(rt); |
73 actualRettype = rettype; | 73 actualRettype = rettype; |
74 } | |
75 | |
76 if (unsigned ea = DtoShouldExtend(rt)) | |
77 { | |
78 f->llvmRetAttrs |= ea; | |
74 } | 79 } |
75 } | 80 } |
76 | 81 |
77 if (retinptr) { | 82 if (retinptr) { |
78 //Logger::cout() << "returning through pointer parameter: " << *rettype << '\n'; | 83 //Logger::cout() << "returning through pointer parameter: " << *rettype << '\n'; |
101 // do nothing? | 106 // do nothing? |
102 } | 107 } |
103 | 108 |
104 size_t n = Argument::dim(f->parameters); | 109 size_t n = Argument::dim(f->parameters); |
105 | 110 |
106 int nbyval = 0; | |
107 | |
108 for (int i=0; i < n; ++i) { | 111 for (int i=0; i < n; ++i) { |
109 Argument* arg = Argument::getNth(f->parameters, i); | 112 Argument* arg = Argument::getNth(f->parameters, i); |
110 // ensure scalar | 113 // ensure scalar |
111 Type* argT = DtoDType(arg->type); | 114 Type* argT = DtoDType(arg->type); |
112 assert(argT); | 115 assert(argT); |
115 | 118 |
116 const LLType* at = DtoType(argT); | 119 const LLType* at = DtoType(argT); |
117 if (isaStruct(at)) { | 120 if (isaStruct(at)) { |
118 Logger::println("struct param"); | 121 Logger::println("struct param"); |
119 paramvec.push_back(getPtrToType(at)); | 122 paramvec.push_back(getPtrToType(at)); |
120 arg->llvmByVal = !refOrOut; | 123 if (!refOrOut) |
124 arg->llvmAttrs |= llvm::ParamAttr::ByVal; | |
121 } | 125 } |
122 else if (isaArray(at)) { | 126 else if (isaArray(at)) { |
123 // static array are passed by reference | 127 // static array are passed by reference |
124 Logger::println("sarray param"); | 128 Logger::println("sarray param"); |
125 assert(argT->ty == Tsarray); | 129 assert(argT->ty == Tsarray); |
135 Logger::println("by ref param"); | 139 Logger::println("by ref param"); |
136 at = getPtrToType(at); | 140 at = getPtrToType(at); |
137 } | 141 } |
138 else { | 142 else { |
139 Logger::println("in param"); | 143 Logger::println("in param"); |
144 if (unsigned ea = DtoShouldExtend(argT)) | |
145 { | |
146 arg->llvmAttrs |= ea; | |
147 } | |
140 } | 148 } |
141 paramvec.push_back(at); | 149 paramvec.push_back(at); |
142 } | 150 } |
143 | 151 |
144 // handle lazy args | 152 // handle lazy args |
149 TypeDelegate *ltd = new TypeDelegate(ltf); | 157 TypeDelegate *ltd = new TypeDelegate(ltf); |
150 at = getPtrToType(DtoType(ltd)); | 158 at = getPtrToType(DtoType(ltd)); |
151 Logger::cout() << "lazy updated to: " << *at << '\n'; | 159 Logger::cout() << "lazy updated to: " << *at << '\n'; |
152 paramvec.back() = at; | 160 paramvec.back() = at; |
153 } | 161 } |
154 | |
155 if (arg->llvmByVal) | |
156 nbyval++; | |
157 } | 162 } |
158 | 163 |
159 //warning("set %d byval args for type: %s", nbyval, f->toChars()); | 164 //warning("set %d byval args for type: %s", nbyval, f->toChars()); |
160 | 165 |
161 // construct function type | 166 // construct function type |
178 if (fdecl->type->ir.type != 0) { | 183 if (fdecl->type->ir.type != 0) { |
179 return llvm::cast<llvm::FunctionType>(fdecl->type->ir.type->get()); | 184 return llvm::cast<llvm::FunctionType>(fdecl->type->ir.type->get()); |
180 } | 185 } |
181 | 186 |
182 TypeFunction* f = (TypeFunction*)fdecl->type; | 187 TypeFunction* f = (TypeFunction*)fdecl->type; |
183 assert(f != 0); | 188 const llvm::FunctionType* fty = 0; |
184 | 189 |
185 const llvm::PointerType* i8pty = getPtrToType(LLType::Int8Ty); | 190 if (fdecl->llvmInternal == LLVMva_start) |
186 std::vector<const LLType*> args; | 191 fty = GET_INTRINSIC_DECL(vastart)->getFunctionType(); |
187 | 192 else if (fdecl->llvmInternal == LLVMva_copy) |
188 if (fdecl->llvmInternal == LLVMva_start) { | 193 fty = GET_INTRINSIC_DECL(vacopy)->getFunctionType(); |
189 args.push_back(i8pty); | 194 else if (fdecl->llvmInternal == LLVMva_end) |
190 } | 195 fty = GET_INTRINSIC_DECL(vaend)->getFunctionType(); |
191 else if (fdecl->llvmInternal == LLVMva_intrinsic) { | 196 assert(fty); |
192 size_t n = Argument::dim(f->parameters); | |
193 for (size_t i=0; i<n; ++i) { | |
194 args.push_back(i8pty); | |
195 } | |
196 } | |
197 else | |
198 assert(0); | |
199 | |
200 const llvm::FunctionType* fty = llvm::FunctionType::get(LLType::VoidTy, args, false); | |
201 | 197 |
202 f->ir.type = new llvm::PATypeHolder(fty); | 198 f->ir.type = new llvm::PATypeHolder(fty); |
203 | |
204 return fty; | 199 return fty; |
205 } | 200 } |
206 | 201 |
207 ////////////////////////////////////////////////////////////////////////////////////////// | 202 ////////////////////////////////////////////////////////////////////////////////////////// |
208 | 203 |
209 const llvm::FunctionType* DtoFunctionType(FuncDeclaration* fdecl) | 204 const llvm::FunctionType* DtoFunctionType(FuncDeclaration* fdecl) |
210 { | 205 { |
211 if ((fdecl->llvmInternal == LLVMva_start) || (fdecl->llvmInternal == LLVMva_intrinsic)) { | 206 // handle for C vararg intrinsics |
207 if (fdecl->isVaIntrinsic()) | |
212 return DtoVaFunctionType(fdecl); | 208 return DtoVaFunctionType(fdecl); |
213 } | |
214 | 209 |
215 // type has already been resolved | 210 // type has already been resolved |
216 if (fdecl->type->ir.type != 0) { | 211 if (fdecl->type->ir.type != 0) |
217 return llvm::cast<llvm::FunctionType>(fdecl->type->ir.type->get()); | 212 return llvm::cast<llvm::FunctionType>(fdecl->type->ir.type->get()); |
218 } | |
219 | 213 |
220 const LLType* thisty = NULL; | 214 const LLType* thisty = NULL; |
221 if (fdecl->needThis()) { | 215 if (fdecl->needThis()) { |
222 if (AggregateDeclaration* ad = fdecl->isMember2()) { | 216 if (AggregateDeclaration* ad = fdecl->isMember2()) { |
223 Logger::println("isMember = this is: %s", ad->type->toChars()); | 217 Logger::println("isMember = this is: %s", ad->type->toChars()); |
244 | 238 |
245 static llvm::Function* DtoDeclareVaFunction(FuncDeclaration* fdecl) | 239 static llvm::Function* DtoDeclareVaFunction(FuncDeclaration* fdecl) |
246 { | 240 { |
247 TypeFunction* f = (TypeFunction*)DtoDType(fdecl->type); | 241 TypeFunction* f = (TypeFunction*)DtoDType(fdecl->type); |
248 const llvm::FunctionType* fty = DtoVaFunctionType(fdecl); | 242 const llvm::FunctionType* fty = DtoVaFunctionType(fdecl); |
249 LLConstant* fn = 0; | 243 llvm::Function* func = 0; |
250 | 244 |
251 if (fdecl->llvmInternal == LLVMva_start) { | 245 if (fdecl->llvmInternal == LLVMva_start) |
252 fn = gIR->module->getOrInsertFunction("llvm.va_start", fty); | 246 func = GET_INTRINSIC_DECL(vastart); |
253 assert(fn); | 247 else if (fdecl->llvmInternal == LLVMva_copy) |
254 } | 248 func = GET_INTRINSIC_DECL(vacopy); |
255 else if (fdecl->llvmInternal == LLVMva_intrinsic) { | 249 else if (fdecl->llvmInternal == LLVMva_end) |
256 fn = gIR->module->getOrInsertFunction(fdecl->intrinsicName, fty); | 250 func = GET_INTRINSIC_DECL(vaend); |
257 assert(fn); | |
258 } | |
259 else | |
260 assert(0); | |
261 | |
262 llvm::Function* func = llvm::dyn_cast<llvm::Function>(fn); | |
263 assert(func); | 251 assert(func); |
264 assert(func->isIntrinsic()); | 252 |
265 fdecl->ir.irFunc->func = func; | 253 fdecl->ir.irFunc->func = func; |
266 return func; | 254 return func; |
267 } | 255 } |
268 | 256 |
269 ////////////////////////////////////////////////////////////////////////////////////////// | 257 ////////////////////////////////////////////////////////////////////////////////////////// |
328 | 316 |
329 int funcNumArgs = func->getArgumentList().size(); | 317 int funcNumArgs = func->getArgumentList().size(); |
330 std::vector<llvm::ParamAttrsWithIndex> attrs; | 318 std::vector<llvm::ParamAttrsWithIndex> attrs; |
331 int k = 0; | 319 int k = 0; |
332 | 320 |
333 int nbyval = 0; | 321 llvm::ParamAttrsWithIndex PAWI; |
334 | 322 |
323 // set zext/sext attr on return value if necessary | |
324 if (f->next->isintegral() && f->next->size() < PTRSIZE) | |
325 { | |
326 PAWI.Index = 0; | |
327 if (f->next->isunsigned()) | |
328 PAWI.Attrs = llvm::ParamAttr::ZExt; | |
329 else | |
330 PAWI.Attrs = llvm::ParamAttr::SExt; | |
331 attrs.push_back(PAWI); | |
332 } | |
333 | |
334 // set byval attrs on implicit main arg | |
335 if (fdecl->isMain() && Argument::dim(f->parameters) == 0) | 335 if (fdecl->isMain() && Argument::dim(f->parameters) == 0) |
336 { | 336 { |
337 llvm::ParamAttrsWithIndex PAWI; | |
338 PAWI.Index = llidx; | 337 PAWI.Index = llidx; |
339 PAWI.Attrs = llvm::ParamAttr::ByVal; | 338 PAWI.Attrs = llvm::ParamAttr::ByVal; |
340 attrs.push_back(PAWI); | 339 attrs.push_back(PAWI); |
341 llidx++; | 340 llidx++; |
342 nbyval++; | 341 } |
343 } | 342 |
344 | 343 // set attrs on the rest of the arguments |
345 for (; llidx <= funcNumArgs && f->parameters->dim > k; ++llidx,++k) | 344 for (; llidx <= funcNumArgs && f->parameters->dim > k; ++llidx,++k) |
346 { | 345 { |
347 Argument* fnarg = (Argument*)f->parameters->data[k]; | 346 Argument* fnarg = (Argument*)f->parameters->data[k]; |
348 assert(fnarg); | 347 assert(fnarg); |
349 if (fnarg->llvmByVal) | 348 |
350 { | 349 PAWI.Index = llidx; |
351 llvm::ParamAttrsWithIndex PAWI; | 350 PAWI.Attrs = fnarg->llvmAttrs; |
352 PAWI.Index = llidx; | 351 |
353 PAWI.Attrs = llvm::ParamAttr::ByVal; | 352 if (PAWI.Attrs) |
354 attrs.push_back(PAWI); | 353 attrs.push_back(PAWI); |
355 nbyval++; | 354 } |
356 } | 355 |
357 } | 356 llvm::PAListPtr palist = llvm::PAListPtr::get(attrs.begin(), attrs.end()); |
358 | 357 func->setParamAttrs(palist); |
359 if (nbyval) { | |
360 llvm::PAListPtr palist = llvm::PAListPtr::get(attrs.begin(), attrs.end()); | |
361 func->setParamAttrs(palist); | |
362 } | |
363 } | 358 } |
364 | 359 |
365 ////////////////////////////////////////////////////////////////////////////////////////// | 360 ////////////////////////////////////////////////////////////////////////////////////////// |
366 | 361 |
367 void DtoDeclareFunction(FuncDeclaration* fdecl) | 362 void DtoDeclareFunction(FuncDeclaration* fdecl) |
410 mangled_name = fdecl->intrinsicName.c_str(); | 405 mangled_name = fdecl->intrinsicName.c_str(); |
411 else | 406 else |
412 mangled_name = fdecl->mangle(); | 407 mangled_name = fdecl->mangle(); |
413 | 408 |
414 llvm::Function* vafunc = 0; | 409 llvm::Function* vafunc = 0; |
415 if ((fdecl->llvmInternal == LLVMva_start) || (fdecl->llvmInternal == LLVMva_intrinsic)) { | 410 if (fdecl->isVaIntrinsic()) |
416 vafunc = DtoDeclareVaFunction(fdecl); | 411 vafunc = DtoDeclareVaFunction(fdecl); |
417 } | |
418 | 412 |
419 // construct function | 413 // construct function |
420 const llvm::FunctionType* functype = DtoFunctionType(fdecl); | 414 const llvm::FunctionType* functype = DtoFunctionType(fdecl); |
421 llvm::Function* func = vafunc ? vafunc : gIR->module->getFunction(mangled_name); | 415 llvm::Function* func = vafunc ? vafunc : gIR->module->getFunction(mangled_name); |
422 if (!func) | 416 if (!func) |
435 | 429 |
436 fdecl->ir.irFunc->func = func; | 430 fdecl->ir.irFunc->func = func; |
437 assert(llvm::isa<llvm::FunctionType>(f->ir.type->get())); | 431 assert(llvm::isa<llvm::FunctionType>(f->ir.type->get())); |
438 | 432 |
439 // parameter attributes | 433 // parameter attributes |
440 if (f->parameters) { | 434 if (f->parameters && !fdecl->isIntrinsic()) { |
441 set_param_attrs(f, func, fdecl); | 435 set_param_attrs(f, func, fdecl); |
442 } | 436 } |
443 | 437 |
444 // main | 438 // main |
445 if (fdecl->isMain()) { | 439 if (fdecl->isMain()) { |
810 DVarValue vv(argexp->type, dst, true); | 804 DVarValue vv(argexp->type, dst, true); |
811 DtoAssign(argexp->loc, &vv, argexp->toElem(gIR)); | 805 DtoAssign(argexp->loc, &vv, argexp->toElem(gIR)); |
812 } | 806 } |
813 | 807 |
814 ////////////////////////////////////////////////////////////////////////////////////////// | 808 ////////////////////////////////////////////////////////////////////////////////////////// |
809 | |
810 bool FuncDeclaration::isIntrinsic() | |
811 { | |
812 return (llvmInternal == LLVMintrinsic || isVaIntrinsic()); | |
813 } | |
814 | |
815 bool FuncDeclaration::isVaIntrinsic() | |
816 { | |
817 return (llvmInternal == LLVMva_start || | |
818 llvmInternal == LLVMva_copy || | |
819 llvmInternal == LLVMva_end); | |
820 } |