Mercurial > projects > ldc
comparison gen/functions.cpp @ 121:9c79b61fb638 trunk
[svn r125] Renamed/moved a few backend member inside DMD structures for consistency.
Unit tests are now implemented.
author | lindquist |
---|---|
date | Tue, 27 Nov 2007 03:09:36 +0100 |
parents | 79c9ac745fbc |
children | 7f9a0a58394b |
comparison
equal
deleted
inserted
replaced
120:5ce8ab11e75a | 121:9c79b61fb638 |
---|---|
71 | 71 |
72 if (typesafeVararg) { | 72 if (typesafeVararg) { |
73 ClassDeclaration* ti = Type::typeinfo; | 73 ClassDeclaration* ti = Type::typeinfo; |
74 ti->toObjFile(); | 74 ti->toObjFile(); |
75 DtoForceConstInitDsymbol(ti); | 75 DtoForceConstInitDsymbol(ti); |
76 assert(ti->llvmInitZ); | 76 assert(ti->llvmConstInit); |
77 std::vector<const llvm::Type*> types; | 77 std::vector<const llvm::Type*> types; |
78 types.push_back(DtoSize_t()); | 78 types.push_back(DtoSize_t()); |
79 types.push_back(llvm::PointerType::get(llvm::PointerType::get(ti->llvmInitZ->getType()))); | 79 types.push_back(llvm::PointerType::get(llvm::PointerType::get(ti->llvmConstInit->getType()))); |
80 const llvm::Type* t1 = llvm::StructType::get(types); | 80 const llvm::Type* t1 = llvm::StructType::get(types); |
81 paramvec.push_back(llvm::PointerType::get(t1)); | 81 paramvec.push_back(llvm::PointerType::get(t1)); |
82 paramvec.push_back(llvm::PointerType::get(llvm::Type::Int8Ty)); | 82 paramvec.push_back(llvm::PointerType::get(llvm::Type::Int8Ty)); |
83 } | 83 } |
84 | 84 |
180 { | 180 { |
181 if ((fdecl->llvmInternal == LLVMva_start) || (fdecl->llvmInternal == LLVMva_intrinsic)) { | 181 if ((fdecl->llvmInternal == LLVMva_start) || (fdecl->llvmInternal == LLVMva_intrinsic)) { |
182 return DtoVaFunctionType(fdecl); | 182 return DtoVaFunctionType(fdecl); |
183 } | 183 } |
184 | 184 |
185 // unittest has null type, just build it manually | |
186 /*if (fdecl->isUnitTestDeclaration()) { | |
187 std::vector<const llvm::Type*> args; | |
188 return llvm::FunctionType::get(llvm::Type::VoidTy, args, false); | |
189 }*/ | |
190 | |
185 // type has already been resolved | 191 // type has already been resolved |
186 if (fdecl->type->llvmType != 0) { | 192 if (fdecl->type->llvmType != 0) { |
187 return llvm::cast<llvm::FunctionType>(fdecl->type->llvmType->get()); | 193 return llvm::cast<llvm::FunctionType>(fdecl->type->llvmType->get()); |
188 } | 194 } |
189 | 195 |
236 | 242 |
237 ////////////////////////////////////////////////////////////////////////////////////////// | 243 ////////////////////////////////////////////////////////////////////////////////////////// |
238 | 244 |
239 void DtoResolveFunction(FuncDeclaration* fdecl) | 245 void DtoResolveFunction(FuncDeclaration* fdecl) |
240 { | 246 { |
247 if (!global.params.useUnitTests && fdecl->isUnitTestDeclaration()) { | |
248 return; // ignore declaration completely | |
249 } | |
250 | |
241 if (fdecl->llvmResolved) return; | 251 if (fdecl->llvmResolved) return; |
242 fdecl->llvmResolved = true; | 252 fdecl->llvmResolved = true; |
243 | 253 |
244 Logger::println("DtoResolveFunction(%s)", fdecl->toPrettyChars()); | 254 Logger::println("DtoResolveFunction(%s)", fdecl->toPrettyChars()); |
245 LOG_SCOPE; | 255 LOG_SCOPE; |
246 | 256 |
247 if (fdecl->llvmRunTimeHack) { | 257 if (fdecl->llvmRunTimeHack) { |
248 gIR->declareList.push_back(fdecl); | 258 gIR->declareList.push_back(fdecl); |
249 return; | |
250 } | |
251 | |
252 if (fdecl->isUnitTestDeclaration()) { | |
253 Logger::attention("ignoring unittest declaration: %s", fdecl->toChars()); | |
254 return; | 259 return; |
255 } | 260 } |
256 | 261 |
257 if (fdecl->parent) | 262 if (fdecl->parent) |
258 if (TemplateInstance* tinst = fdecl->parent->isTemplateInstance()) | 263 if (TemplateInstance* tinst = fdecl->parent->isTemplateInstance()) |
291 Logger::println("DtoDeclareFunction(%s)", fdecl->toPrettyChars()); | 296 Logger::println("DtoDeclareFunction(%s)", fdecl->toPrettyChars()); |
292 LOG_SCOPE; | 297 LOG_SCOPE; |
293 | 298 |
294 assert(!fdecl->isAbstract()); | 299 assert(!fdecl->isAbstract()); |
295 | 300 |
301 // intrinsic sanity check | |
302 if (fdecl->llvmInternal == LLVMintrinsic && fdecl->fbody) { | |
303 error(fdecl->loc, "intrinsics cannot have function bodies"); | |
304 fatal(); | |
305 } | |
306 | |
296 if (fdecl->llvmRunTimeHack) { | 307 if (fdecl->llvmRunTimeHack) { |
297 Logger::println("runtime hack func chars: %s", fdecl->toChars()); | 308 Logger::println("runtime hack func chars: %s", fdecl->toChars()); |
298 if (!fdecl->llvmValue) | 309 if (!fdecl->llvmValue) |
299 fdecl->llvmValue = LLVM_D_GetRuntimeFunction(gIR->module, fdecl->toChars()); | 310 fdecl->llvmValue = LLVM_D_GetRuntimeFunction(gIR->module, fdecl->toChars()); |
300 return; | 311 return; |
315 char* mangled_name; | 326 char* mangled_name; |
316 if (fdecl->llvmInternal == LLVMintrinsic) | 327 if (fdecl->llvmInternal == LLVMintrinsic) |
317 mangled_name = fdecl->llvmInternal1; | 328 mangled_name = fdecl->llvmInternal1; |
318 else | 329 else |
319 mangled_name = fdecl->mangle(); | 330 mangled_name = fdecl->mangle(); |
320 | |
321 // unit test special handling | |
322 if (fdecl->isUnitTestDeclaration()) | |
323 { | |
324 assert(0 && "no unittests yet"); | |
325 /*const llvm::FunctionType* fnty = llvm::FunctionType::get(llvm::Type::VoidTy, std::vector<const llvm::Type*>(), false); | |
326 // make the function | |
327 llvm::Function* func = gIR->module->getFunction(mangled_name); | |
328 if (func == 0) | |
329 func = new llvm::Function(fnty,llvm::GlobalValue::InternalLinkage,mangled_name,gIR->module); | |
330 func->setCallingConv(llvm::CallingConv::Fast); | |
331 fdecl->llvmValue = func; | |
332 return func; | |
333 */ | |
334 } | |
335 | |
336 if (fdecl->llvmInternal == LLVMintrinsic && fdecl->fbody) { | |
337 error("intrinsics cannot have function bodies"); | |
338 fatal(); | |
339 } | |
340 | 331 |
341 llvm::Function* vafunc = 0; | 332 llvm::Function* vafunc = 0; |
342 if ((fdecl->llvmInternal == LLVMva_start) || (fdecl->llvmInternal == LLVMva_intrinsic)) { | 333 if ((fdecl->llvmInternal == LLVMva_start) || (fdecl->llvmInternal == LLVMva_intrinsic)) { |
343 vafunc = DtoDeclareVaFunction(fdecl); | 334 vafunc = DtoDeclareVaFunction(fdecl); |
344 } | 335 } |
385 // name parameters | 376 // name parameters |
386 llvm::Function::arg_iterator iarg = func->arg_begin(); | 377 llvm::Function::arg_iterator iarg = func->arg_begin(); |
387 int k = 0; | 378 int k = 0; |
388 if (f->llvmRetInPtr) { | 379 if (f->llvmRetInPtr) { |
389 iarg->setName("retval"); | 380 iarg->setName("retval"); |
390 f->llvmRetArg = iarg; | 381 fdecl->llvmRetArg = iarg; |
391 ++iarg; | 382 ++iarg; |
392 } | 383 } |
393 if (f->llvmUsesThis) { | 384 if (f->llvmUsesThis) { |
394 iarg->setName("this"); | 385 iarg->setName("this"); |
395 fdecl->llvmThisVar = iarg; | 386 fdecl->llvmThisVar = iarg; |
420 else { | 411 else { |
421 iarg->setName("unnamed"); | 412 iarg->setName("unnamed"); |
422 } | 413 } |
423 } | 414 } |
424 | 415 |
416 if (fdecl->isUnitTestDeclaration()) | |
417 gIR->unitTests.push_back(fdecl); | |
418 | |
425 if (!declareOnly) | 419 if (!declareOnly) |
426 gIR->defineList.push_back(fdecl); | 420 gIR->defineList.push_back(fdecl); |
427 | 421 |
428 Logger::cout() << "func decl: " << *func << '\n'; | 422 Logger::cout() << "func decl: " << *func << '\n'; |
429 } | 423 } |
430 | 424 |
431 ////////////////////////////////////////////////////////////////////////////////////////// | 425 ////////////////////////////////////////////////////////////////////////////////////////// |
432 | 426 |
433 // TODO split this monster up | |
434 void DtoDefineFunc(FuncDeclaration* fd) | 427 void DtoDefineFunc(FuncDeclaration* fd) |
435 { | 428 { |
436 if (fd->llvmDefined) return; | 429 if (fd->llvmDefined) return; |
437 fd->llvmDefined = true; | 430 fd->llvmDefined = true; |
438 | 431 |
450 fd->llvmDwarfSubProgram = DtoDwarfSubProgram(fd, mo->llvmCompileUnit); | 443 fd->llvmDwarfSubProgram = DtoDwarfSubProgram(fd, mo->llvmCompileUnit); |
451 } | 444 } |
452 | 445 |
453 Type* t = DtoDType(fd->type); | 446 Type* t = DtoDType(fd->type); |
454 TypeFunction* f = (TypeFunction*)t; | 447 TypeFunction* f = (TypeFunction*)t; |
455 | |
456 assert(f->llvmType); | 448 assert(f->llvmType); |
449 | |
457 llvm::Function* func = fd->llvmIRFunc->func; | 450 llvm::Function* func = fd->llvmIRFunc->func; |
458 const llvm::FunctionType* functype = func->getFunctionType(); | 451 const llvm::FunctionType* functype = func->getFunctionType(); |
459 | 452 |
460 // only members of the current module or template instances maybe be defined | 453 // only members of the current module or template instances maybe be defined |
461 if (fd->getModule() == gIR->dmodule || DtoIsTemplateInstance(fd->parent)) | 454 if (fd->getModule() == gIR->dmodule || DtoIsTemplateInstance(fd->parent)) |
477 | 470 |
478 //assert(gIR->scopes.empty()); | 471 //assert(gIR->scopes.empty()); |
479 gIR->scopes.push_back(IRScope(beginbb, endbb)); | 472 gIR->scopes.push_back(IRScope(beginbb, endbb)); |
480 | 473 |
481 // create alloca point | 474 // create alloca point |
482 f->llvmAllocaPoint = new llvm::BitCastInst(llvm::ConstantInt::get(llvm::Type::Int32Ty,0,false),llvm::Type::Int32Ty,"alloca point",gIR->scopebb()); | 475 llvm::Instruction* allocaPoint = new llvm::BitCastInst(llvm::ConstantInt::get(llvm::Type::Int32Ty,0,false),llvm::Type::Int32Ty,"alloca point",gIR->scopebb()); |
483 gIR->func()->allocapoint = f->llvmAllocaPoint; | 476 gIR->func()->allocapoint = allocaPoint; |
484 | 477 |
485 // need result variable? (not nested) | 478 // need result variable? (not nested) |
486 if (fd->vresult && !fd->vresult->nestedref) { | 479 if (fd->vresult && !fd->vresult->nestedref) { |
487 Logger::println("non-nested vresult value"); | 480 Logger::println("non-nested vresult value"); |
488 fd->vresult->llvmValue = new llvm::AllocaInst(DtoType(fd->vresult->type),"function_vresult",f->llvmAllocaPoint); | 481 fd->vresult->llvmValue = new llvm::AllocaInst(DtoType(fd->vresult->type),"function_vresult",allocaPoint); |
489 } | 482 } |
490 | 483 |
491 // give arguments storage | 484 // give arguments storage |
492 size_t n = Argument::dim(f->parameters); | 485 size_t n = Argument::dim(f->parameters); |
493 for (int i=0; i < n; ++i) { | 486 for (int i=0; i < n; ++i) { |
499 llvm::Value* a = vd->llvmValue; | 492 llvm::Value* a = vd->llvmValue; |
500 assert(a); | 493 assert(a); |
501 std::string s(a->getName()); | 494 std::string s(a->getName()); |
502 Logger::println("giving argument '%s' storage", s.c_str()); | 495 Logger::println("giving argument '%s' storage", s.c_str()); |
503 s.append("_storage"); | 496 s.append("_storage"); |
504 llvm::Value* v = new llvm::AllocaInst(a->getType(),s,f->llvmAllocaPoint); | 497 llvm::Value* v = new llvm::AllocaInst(a->getType(),s,allocaPoint); |
505 gIR->ir->CreateStore(a,v); | 498 gIR->ir->CreateStore(a,v); |
506 vd->llvmValue = v; | 499 vd->llvmValue = v; |
507 } | 500 } |
508 else { | 501 else { |
509 Logger::attention("some unknown argument: %s", arg ? arg->toChars() : 0); | 502 Logger::attention("some unknown argument: %s", arg ? arg->toChars() : 0); |
544 nestTypes.push_back(DtoType(vd->type)); | 537 nestTypes.push_back(DtoType(vd->type)); |
545 } | 538 } |
546 } | 539 } |
547 const llvm::StructType* nestSType = llvm::StructType::get(nestTypes); | 540 const llvm::StructType* nestSType = llvm::StructType::get(nestTypes); |
548 Logger::cout() << "nested var struct has type:" << '\n' << *nestSType; | 541 Logger::cout() << "nested var struct has type:" << '\n' << *nestSType; |
549 fd->llvmNested = new llvm::AllocaInst(nestSType,"nestedvars",f->llvmAllocaPoint); | 542 fd->llvmNested = new llvm::AllocaInst(nestSType,"nestedvars",allocaPoint); |
550 if (parentNested) { | 543 if (parentNested) { |
551 assert(fd->llvmThisVar); | 544 assert(fd->llvmThisVar); |
552 llvm::Value* ptr = gIR->ir->CreateBitCast(fd->llvmThisVar, parentNested->getType(), "tmp"); | 545 llvm::Value* ptr = gIR->ir->CreateBitCast(fd->llvmThisVar, parentNested->getType(), "tmp"); |
553 gIR->ir->CreateStore(ptr, DtoGEPi(fd->llvmNested, 0,0, "tmp")); | 546 gIR->ir->CreateStore(ptr, DtoGEPi(fd->llvmNested, 0,0, "tmp")); |
554 } | 547 } |
586 } | 579 } |
587 } | 580 } |
588 } | 581 } |
589 | 582 |
590 // erase alloca point | 583 // erase alloca point |
591 f->llvmAllocaPoint->eraseFromParent(); | 584 allocaPoint->eraseFromParent(); |
592 f->llvmAllocaPoint = 0; | 585 allocaPoint = 0; |
593 gIR->func()->allocapoint = 0; | 586 gIR->func()->allocapoint = 0; |
594 | 587 |
595 gIR->scopes.pop_back(); | 588 gIR->scopes.pop_back(); |
596 | 589 |
597 // get rid of the endentry block, it's never used | 590 // get rid of the endentry block, it's never used |
647 | 640 |
648 // call static ctors | 641 // call static ctors |
649 llvm::Function* fn = LLVM_D_GetRuntimeFunction(ir.module,"_moduleCtor"); | 642 llvm::Function* fn = LLVM_D_GetRuntimeFunction(ir.module,"_moduleCtor"); |
650 llvm::Instruction* apt = new llvm::CallInst(fn,"",bb); | 643 llvm::Instruction* apt = new llvm::CallInst(fn,"",bb); |
651 | 644 |
645 // run unit tests if -unittest is provided | |
646 if (global.params.useUnitTests) { | |
647 fn = LLVM_D_GetRuntimeFunction(ir.module,"_moduleUnitTests"); | |
648 llvm::Instruction* apt = new llvm::CallInst(fn,"",bb); | |
649 } | |
650 | |
652 // call user main function | 651 // call user main function |
653 const llvm::FunctionType* mainty = ir.mainFunc->getFunctionType(); | 652 const llvm::FunctionType* mainty = ir.mainFunc->getFunctionType(); |
654 llvm::CallInst* call; | 653 llvm::CallInst* call; |
655 if (mainty->getNumParams() > 0) | 654 if (mainty->getNumParams() > 0) |
656 { | 655 { |