Mercurial > projects > ldc
diff gen/functions.cpp @ 244:a95056b3c996 trunk
[svn r261] Fixed debug info for integer and floating local variables, can now be inspected in GDB.
Did a lot of smaller cleans up here and there.
Replaced more llvm::Foo with LLFoo for common stuff.
Split up tollvm.cpp.
author | lindquist |
---|---|
date | Mon, 09 Jun 2008 09:37:08 +0200 |
parents | 53568c37cfa7 |
children | d61ce72c39ab |
line wrap: on
line diff
--- a/gen/functions.cpp Mon Jun 09 03:02:14 2008 +0200 +++ b/gen/functions.cpp Mon Jun 09 09:37:08 2008 +0200 @@ -10,6 +10,7 @@ #include "gen/irstate.h" #include "gen/tollvm.h" +#include "gen/llvmhelpers.h" #include "gen/runtime.h" #include "gen/arrays.h" #include "gen/logger.h" @@ -49,7 +50,7 @@ if (ismain) { - rettype = llvm::Type::Int32Ty; + rettype = LLType::Int32Ty; actualRettype = rettype; if (Argument::dim(f->parameters) == 0) { @@ -63,7 +64,7 @@ Type* rtfin = DtoDType(rt); if (DtoIsReturnedInArg(rt)) { rettype = getPtrToType(DtoType(rt)); - actualRettype = llvm::Type::VoidTy; + actualRettype = LLType::VoidTy; f->llvmRetInPtr = retinptr = true; } else { @@ -92,7 +93,7 @@ types.push_back(getPtrToType(getPtrToType(ti->ir.irStruct->constInit->getType()))); const LLType* t1 = llvm::StructType::get(types); paramvec.push_back(getPtrToType(t1)); - paramvec.push_back(getPtrToType(llvm::Type::Int8Ty)); + paramvec.push_back(getPtrToType(LLType::Int8Ty)); } else if (arrayVararg) { @@ -172,7 +173,7 @@ TypeFunction* f = (TypeFunction*)fdecl->type; assert(f != 0); - const llvm::PointerType* i8pty = getPtrToType(llvm::Type::Int8Ty); + const llvm::PointerType* i8pty = getPtrToType(LLType::Int8Ty); std::vector<const LLType*> args; if (fdecl->llvmInternal == LLVMva_start) { @@ -187,7 +188,7 @@ else assert(0); - const llvm::FunctionType* fty = llvm::FunctionType::get(llvm::Type::VoidTy, args, false); + const llvm::FunctionType* fty = llvm::FunctionType::get(LLType::VoidTy, args, false); f->ir.type = new llvm::PATypeHolder(fty); @@ -205,7 +206,7 @@ // unittest has null type, just build it manually /*if (fdecl->isUnitTestDeclaration()) { std::vector<const LLType*> args; - return llvm::FunctionType::get(llvm::Type::VoidTy, args, false); + return llvm::FunctionType::get(LLType::VoidTy, args, false); }*/ // type has already been resolved @@ -228,7 +229,7 @@ } } else if (fdecl->isNested()) { - thisty = getPtrToType(llvm::Type::Int8Ty); + thisty = getPtrToType(LLType::Int8Ty); } const llvm::FunctionType* functype = DtoFunctionType(fdecl->type, thisty, fdecl->isMain()); @@ -549,194 +550,195 @@ const llvm::FunctionType* functype = func->getFunctionType(); // only members of the current module or template instances maybe be defined - if (fd->getModule() == gIR->dmodule || DtoIsTemplateInstance(fd->parent)) - { - fd->ir.DModule = gIR->dmodule; + if (!(fd->getModule() == gIR->dmodule || DtoIsTemplateInstance(fd->parent))) + return; - // function definition - if (fd->fbody != 0) - { - Logger::println("Doing function body for: %s", fd->toChars()); - assert(fd->ir.irFunc); - gIR->functions.push_back(fd->ir.irFunc); - - if (fd->isMain()) - gIR->emitMain = true; - - std::string entryname("entry_"); - entryname.append(fd->toPrettyChars()); + // set module owner + fd->ir.DModule = gIR->dmodule; - llvm::BasicBlock* beginbb = llvm::BasicBlock::Create(entryname,func); - llvm::BasicBlock* endbb = llvm::BasicBlock::Create("endentry",func); - - //assert(gIR->scopes.empty()); - gIR->scopes.push_back(IRScope(beginbb, endbb)); + // is there a body? + if (fd->fbody == NULL) + return; - // create alloca point - llvm::Instruction* allocaPoint = new llvm::AllocaInst(llvm::Type::Int32Ty, "alloca point", beginbb); - gIR->func()->allocapoint = allocaPoint; - - // need result variable? (not nested) - if (fd->vresult && !fd->vresult->nestedref) { - Logger::println("non-nested vresult value"); - fd->vresult->ir.irLocal = new IrLocal(fd->vresult); - fd->vresult->ir.irLocal->value = new llvm::AllocaInst(DtoType(fd->vresult->type),"function_vresult",allocaPoint); - } + Logger::println("Doing function body for: %s", fd->toChars()); + assert(fd->ir.irFunc); + gIR->functions.push_back(fd->ir.irFunc); - // give arguments storage - if (fd->parameters) - { - size_t n = fd->parameters->dim; - for (int i=0; i < n; ++i) - { - Dsymbol* argsym = (Dsymbol*)fd->parameters->data[i]; - VarDeclaration* vd = argsym->isVarDeclaration(); - assert(vd); + if (fd->isMain()) + gIR->emitMain = true; - if (!vd->needsStorage || vd->nestedref || vd->isRef() || vd->isOut() || DtoIsPassedByRef(vd->type)) - continue; - - LLValue* a = vd->ir.irLocal->value; - assert(a); - std::string s(a->getName()); - Logger::println("giving argument '%s' storage", s.c_str()); - s.append("_storage"); + std::string entryname("entry_"); + entryname.append(fd->toPrettyChars()); - LLValue* v = new llvm::AllocaInst(a->getType(),s,allocaPoint); - gIR->ir->CreateStore(a,v); - vd->ir.irLocal->value = v; - } - } - - // debug info - if (global.params.symdebug) DtoDwarfFuncStart(fd); + llvm::BasicBlock* beginbb = llvm::BasicBlock::Create(entryname,func); + llvm::BasicBlock* endbb = llvm::BasicBlock::Create("endentry",func); - LLValue* parentNested = NULL; - if (FuncDeclaration* fd2 = fd->toParent2()->isFuncDeclaration()) { - if (!fd->isStatic()) // huh? - parentNested = fd2->ir.irFunc->nestedVar; - } + //assert(gIR->scopes.empty()); + gIR->scopes.push_back(IRScope(beginbb, endbb)); - // need result variable? (nested) - if (fd->vresult && fd->vresult->nestedref) { - Logger::println("nested vresult value: %s", fd->vresult->toChars()); - fd->nestedVars.insert(fd->vresult); - } + // create alloca point + llvm::Instruction* allocaPoint = new llvm::AllocaInst(LLType::Int32Ty, "alloca point", beginbb); + gIR->func()->allocapoint = allocaPoint; - // construct nested variables struct - if (!fd->nestedVars.empty() || parentNested) { - std::vector<const LLType*> nestTypes; - int j = 0; - if (parentNested) { - nestTypes.push_back(parentNested->getType()); - j++; - } - for (std::set<VarDeclaration*>::iterator i=fd->nestedVars.begin(); i!=fd->nestedVars.end(); ++i) { - VarDeclaration* vd = *i; - Logger::println("referenced nested variable %s", vd->toChars()); - if (!vd->ir.irLocal) - vd->ir.irLocal = new IrLocal(vd); - vd->ir.irLocal->nestedIndex = j++; - if (vd->isParameter()) { - if (!vd->ir.irLocal->value) { - assert(vd == fd->vthis); - vd->ir.irLocal->value = fd->ir.irFunc->thisVar; - } - assert(vd->ir.irLocal->value); - nestTypes.push_back(vd->ir.irLocal->value->getType()); - } - else { - nestTypes.push_back(DtoType(vd->type)); - } - } - const llvm::StructType* nestSType = llvm::StructType::get(nestTypes); - Logger::cout() << "nested var struct has type:" << *nestSType << '\n'; - fd->ir.irFunc->nestedVar = new llvm::AllocaInst(nestSType,"nestedvars",allocaPoint); - if (parentNested) { - assert(fd->ir.irFunc->thisVar); - LLValue* ptr = gIR->ir->CreateBitCast(fd->ir.irFunc->thisVar, parentNested->getType(), "tmp"); - gIR->ir->CreateStore(ptr, DtoGEPi(fd->ir.irFunc->nestedVar, 0,0, "tmp")); - } - for (std::set<VarDeclaration*>::iterator i=fd->nestedVars.begin(); i!=fd->nestedVars.end(); ++i) { - VarDeclaration* vd = *i; - if (vd->isParameter()) { - assert(vd->ir.irLocal); - gIR->ir->CreateStore(vd->ir.irLocal->value, DtoGEPi(fd->ir.irFunc->nestedVar, 0, vd->ir.irLocal->nestedIndex, "tmp")); - vd->ir.irLocal->value = fd->ir.irFunc->nestedVar; - } - } - } - - // copy _argptr to a memory location - if (f->linkage == LINKd && f->varargs == 1) - { - LLValue* argptrmem = new llvm::AllocaInst(fd->ir.irFunc->_argptr->getType(), "_argptrmem", gIR->topallocapoint()); - new llvm::StoreInst(fd->ir.irFunc->_argptr, argptrmem, gIR->scopebb()); - fd->ir.irFunc->_argptr = argptrmem; - } - - // output function body - fd->fbody->toIR(gIR); + // need result variable? (not nested) + if (fd->vresult && !fd->vresult->nestedref) { + Logger::println("non-nested vresult value"); + fd->vresult->ir.irLocal = new IrLocal(fd->vresult); + fd->vresult->ir.irLocal->value = new llvm::AllocaInst(DtoType(fd->vresult->type),"function_vresult",allocaPoint); + } - // llvm requires all basic blocks to end with a TerminatorInst but DMD does not put a return statement - // in automatically, so we do it here. - if (!fd->isMain()) { - if (!gIR->scopereturned()) { - // pass the previous block into this block - if (global.params.symdebug) DtoDwarfFuncEnd(fd); - if (func->getReturnType() == llvm::Type::VoidTy) { - llvm::ReturnInst::Create(gIR->scopebb()); - } - else { - llvm::ReturnInst::Create(llvm::UndefValue::get(func->getReturnType()), gIR->scopebb()); - } - } - } - - // erase alloca point - allocaPoint->eraseFromParent(); - allocaPoint = 0; - gIR->func()->allocapoint = 0; - - gIR->scopes.pop_back(); - - // get rid of the endentry block, it's never used - assert(!func->getBasicBlockList().empty()); - func->getBasicBlockList().pop_back(); + // give arguments storage + if (fd->parameters) + { + size_t n = fd->parameters->dim; + for (int i=0; i < n; ++i) + { + Dsymbol* argsym = (Dsymbol*)fd->parameters->data[i]; + VarDeclaration* vd = argsym->isVarDeclaration(); + assert(vd); - // if the last block is empty now, it must be unreachable or it's a bug somewhere else - // would be nice to figure out how to assert that this is correct - llvm::BasicBlock* lastbb = &func->getBasicBlockList().back(); - if (lastbb->empty()) { - if (lastbb->getNumUses() == 0) - lastbb->eraseFromParent(); - else { - new llvm::UnreachableInst(lastbb); - /*if (func->getReturnType() == llvm::Type::VoidTy) { - llvm::ReturnInst::Create(lastbb); - } - else { - llvm::ReturnInst::Create(llvm::UndefValue::get(func->getReturnType()), lastbb); - }*/ - } - } + if (!vd->needsStorage || vd->nestedref || vd->isRef() || vd->isOut() || DtoIsPassedByRef(vd->type)) + continue; - // if the last block is not terminated we return a null value or void - // for some unknown reason this is needed when a void main() has a inline asm block ... - // this should be harmless for well formed code! - lastbb = &func->getBasicBlockList().back(); - if (!lastbb->getTerminator()) - { - Logger::println("adding missing return statement"); - if (func->getReturnType() == llvm::Type::VoidTy) - llvm::ReturnInst::Create(lastbb); - else - llvm::ReturnInst::Create(llvm::Constant::getNullValue(func->getReturnType()), lastbb); - } + LLValue* a = vd->ir.irLocal->value; + assert(a); + std::string s(a->getName()); + Logger::println("giving argument '%s' storage", s.c_str()); + s.append("_storage"); - gIR->functions.pop_back(); + LLValue* v = new llvm::AllocaInst(a->getType(),s,allocaPoint); + gIR->ir->CreateStore(a,v); + vd->ir.irLocal->value = v; } } + + // debug info + if (global.params.symdebug) DtoDwarfFuncStart(fd); + + LLValue* parentNested = NULL; + if (FuncDeclaration* fd2 = fd->toParent2()->isFuncDeclaration()) { + if (!fd->isStatic()) // huh? + parentNested = fd2->ir.irFunc->nestedVar; + } + + // need result variable? (nested) + if (fd->vresult && fd->vresult->nestedref) { + Logger::println("nested vresult value: %s", fd->vresult->toChars()); + fd->nestedVars.insert(fd->vresult); + } + + // construct nested variables struct + if (!fd->nestedVars.empty() || parentNested) { + std::vector<const LLType*> nestTypes; + int j = 0; + if (parentNested) { + nestTypes.push_back(parentNested->getType()); + j++; + } + for (std::set<VarDeclaration*>::iterator i=fd->nestedVars.begin(); i!=fd->nestedVars.end(); ++i) { + VarDeclaration* vd = *i; + Logger::println("referenced nested variable %s", vd->toChars()); + if (!vd->ir.irLocal) + vd->ir.irLocal = new IrLocal(vd); + vd->ir.irLocal->nestedIndex = j++; + if (vd->isParameter()) { + if (!vd->ir.irLocal->value) { + assert(vd == fd->vthis); + vd->ir.irLocal->value = fd->ir.irFunc->thisVar; + } + assert(vd->ir.irLocal->value); + nestTypes.push_back(vd->ir.irLocal->value->getType()); + } + else { + nestTypes.push_back(DtoType(vd->type)); + } + } + const llvm::StructType* nestSType = llvm::StructType::get(nestTypes); + Logger::cout() << "nested var struct has type:" << *nestSType << '\n'; + fd->ir.irFunc->nestedVar = new llvm::AllocaInst(nestSType,"nestedvars",allocaPoint); + if (parentNested) { + assert(fd->ir.irFunc->thisVar); + LLValue* ptr = gIR->ir->CreateBitCast(fd->ir.irFunc->thisVar, parentNested->getType(), "tmp"); + gIR->ir->CreateStore(ptr, DtoGEPi(fd->ir.irFunc->nestedVar, 0,0, "tmp")); + } + for (std::set<VarDeclaration*>::iterator i=fd->nestedVars.begin(); i!=fd->nestedVars.end(); ++i) { + VarDeclaration* vd = *i; + if (vd->isParameter()) { + assert(vd->ir.irLocal); + gIR->ir->CreateStore(vd->ir.irLocal->value, DtoGEPi(fd->ir.irFunc->nestedVar, 0, vd->ir.irLocal->nestedIndex, "tmp")); + vd->ir.irLocal->value = fd->ir.irFunc->nestedVar; + } + } + } + + // copy _argptr to a memory location + if (f->linkage == LINKd && f->varargs == 1) + { + LLValue* argptrmem = new llvm::AllocaInst(fd->ir.irFunc->_argptr->getType(), "_argptrmem", gIR->topallocapoint()); + new llvm::StoreInst(fd->ir.irFunc->_argptr, argptrmem, gIR->scopebb()); + fd->ir.irFunc->_argptr = argptrmem; + } + + // output function body + fd->fbody->toIR(gIR); + + // llvm requires all basic blocks to end with a TerminatorInst but DMD does not put a return statement + // in automatically, so we do it here. + if (!fd->isMain()) { + if (!gIR->scopereturned()) { + // pass the previous block into this block + if (global.params.symdebug) DtoDwarfFuncEnd(fd); + if (func->getReturnType() == LLType::VoidTy) { + llvm::ReturnInst::Create(gIR->scopebb()); + } + else { + llvm::ReturnInst::Create(llvm::UndefValue::get(func->getReturnType()), gIR->scopebb()); + } + } + } + + // erase alloca point + allocaPoint->eraseFromParent(); + allocaPoint = 0; + gIR->func()->allocapoint = 0; + + gIR->scopes.pop_back(); + + // get rid of the endentry block, it's never used + assert(!func->getBasicBlockList().empty()); + func->getBasicBlockList().pop_back(); + + // if the last block is empty now, it must be unreachable or it's a bug somewhere else + // would be nice to figure out how to assert that this is correct + llvm::BasicBlock* lastbb = &func->getBasicBlockList().back(); + if (lastbb->empty()) { + if (lastbb->getNumUses() == 0) + lastbb->eraseFromParent(); + else { + new llvm::UnreachableInst(lastbb); + /*if (func->getReturnType() == LLType::VoidTy) { + llvm::ReturnInst::Create(lastbb); + } + else { + llvm::ReturnInst::Create(llvm::UndefValue::get(func->getReturnType()), lastbb); + }*/ + } + } + + // if the last block is not terminated we return a null value or void + // for some unknown reason this is needed when a void main() has a inline asm block ... + // this should be harmless for well formed code! + lastbb = &func->getBasicBlockList().back(); + if (!lastbb->getTerminator()) + { + Logger::println("adding missing return statement"); + if (func->getReturnType() == LLType::VoidTy) + llvm::ReturnInst::Create(lastbb); + else + llvm::ReturnInst::Create(llvm::Constant::getNullValue(func->getReturnType()), lastbb); + } + + gIR->functions.pop_back(); } //////////////////////////////////////////////////////////////////////////////////////////