mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-04-30 23:20:40 +03:00

Fixed some nasty static array-initializer bugs. Fixed bug in DtoArrayLen and DtoArrayPtr for full slices of static arrays.
730 lines
25 KiB
C++
730 lines
25 KiB
C++
#include "gen/llvm.h"
|
|
|
|
#include "mtype.h"
|
|
#include "aggregate.h"
|
|
#include "init.h"
|
|
#include "declaration.h"
|
|
#include "template.h"
|
|
#include "module.h"
|
|
#include "statement.h"
|
|
|
|
#include "gen/irstate.h"
|
|
#include "gen/tollvm.h"
|
|
#include "gen/runtime.h"
|
|
#include "gen/arrays.h"
|
|
#include "gen/logger.h"
|
|
#include "gen/functions.h"
|
|
#include "gen/todebug.h"
|
|
#include "gen/classes.h"
|
|
|
|
const llvm::FunctionType* DtoFunctionType(Type* type, const llvm::Type* thistype, bool ismain)
|
|
{
|
|
TypeFunction* f = (TypeFunction*)type;
|
|
assert(f != 0);
|
|
|
|
if (type->llvmType != NULL) {
|
|
return llvm::cast<llvm::FunctionType>(type->llvmType->get());
|
|
}
|
|
|
|
bool typesafeVararg = false;
|
|
if (f->linkage == LINKd && f->varargs == 1) {
|
|
typesafeVararg = true;
|
|
}
|
|
|
|
// return value type
|
|
const llvm::Type* rettype;
|
|
const llvm::Type* actualRettype;
|
|
Type* rt = f->next;
|
|
bool retinptr = false;
|
|
bool usesthis = false;
|
|
|
|
if (ismain) {
|
|
rettype = llvm::Type::Int32Ty;
|
|
actualRettype = rettype;
|
|
}
|
|
else {
|
|
assert(rt);
|
|
Type* rtfin = DtoDType(rt);
|
|
if (DtoIsPassedByRef(rt)) {
|
|
rettype = llvm::PointerType::get(DtoType(rt));
|
|
actualRettype = llvm::Type::VoidTy;
|
|
f->llvmRetInPtr = retinptr = true;
|
|
}
|
|
else {
|
|
rettype = DtoType(rt);
|
|
actualRettype = rettype;
|
|
}
|
|
}
|
|
|
|
// parameter types
|
|
std::vector<const llvm::Type*> paramvec;
|
|
|
|
if (retinptr) {
|
|
Logger::cout() << "returning through pointer parameter: " << *rettype << '\n';
|
|
paramvec.push_back(rettype);
|
|
}
|
|
|
|
if (thistype) {
|
|
paramvec.push_back(thistype);
|
|
usesthis = true;
|
|
}
|
|
|
|
if (typesafeVararg) {
|
|
ClassDeclaration* ti = Type::typeinfo;
|
|
ti->toObjFile();
|
|
DtoForceConstInitDsymbol(ti);
|
|
assert(ti->llvmInitZ);
|
|
std::vector<const llvm::Type*> types;
|
|
types.push_back(DtoSize_t());
|
|
types.push_back(llvm::PointerType::get(llvm::PointerType::get(ti->llvmInitZ->getType())));
|
|
const llvm::Type* t1 = llvm::StructType::get(types);
|
|
paramvec.push_back(llvm::PointerType::get(t1));
|
|
paramvec.push_back(llvm::PointerType::get(llvm::Type::Int8Ty));
|
|
}
|
|
|
|
size_t n = Argument::dim(f->parameters);
|
|
|
|
for (int i=0; i < n; ++i) {
|
|
Argument* arg = Argument::getNth(f->parameters, i);
|
|
// ensure scalar
|
|
Type* argT = DtoDType(arg->type);
|
|
assert(argT);
|
|
|
|
if ((arg->storageClass & STCref) || (arg->storageClass & STCout)) {
|
|
//assert(arg->vardecl);
|
|
//arg->vardecl->refparam = true;
|
|
}
|
|
else
|
|
arg->llvmCopy = true;
|
|
|
|
const llvm::Type* at = DtoType(argT);
|
|
if (isaStruct(at)) {
|
|
Logger::println("struct param");
|
|
paramvec.push_back(llvm::PointerType::get(at));
|
|
}
|
|
else if (isaArray(at)) {
|
|
Logger::println("sarray param");
|
|
assert(argT->ty == Tsarray);
|
|
//paramvec.push_back(llvm::PointerType::get(at->getContainedType(0)));
|
|
paramvec.push_back(llvm::PointerType::get(at));
|
|
}
|
|
else if (llvm::isa<llvm::OpaqueType>(at)) {
|
|
Logger::println("opaque param");
|
|
assert(argT->ty == Tstruct || argT->ty == Tclass);
|
|
paramvec.push_back(llvm::PointerType::get(at));
|
|
}
|
|
else {
|
|
if (!arg->llvmCopy) {
|
|
Logger::println("ref param");
|
|
at = llvm::PointerType::get(at);
|
|
}
|
|
else {
|
|
Logger::println("in param");
|
|
}
|
|
paramvec.push_back(at);
|
|
}
|
|
}
|
|
|
|
// construct function type
|
|
bool isvararg = !typesafeVararg && f->varargs;
|
|
llvm::FunctionType* functype = llvm::FunctionType::get(actualRettype, paramvec, isvararg);
|
|
|
|
f->llvmRetInPtr = retinptr;
|
|
f->llvmUsesThis = usesthis;
|
|
|
|
//if (!f->llvmType)
|
|
f->llvmType = new llvm::PATypeHolder(functype);
|
|
//else
|
|
//assert(functype == f->llvmType->get());
|
|
|
|
return functype;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static const llvm::FunctionType* DtoVaFunctionType(FuncDeclaration* fdecl)
|
|
{
|
|
// type has already been resolved
|
|
if (fdecl->type->llvmType != 0) {
|
|
return llvm::cast<llvm::FunctionType>(fdecl->type->llvmType->get());
|
|
}
|
|
|
|
TypeFunction* f = (TypeFunction*)fdecl->type;
|
|
assert(f != 0);
|
|
|
|
const llvm::PointerType* i8pty = llvm::PointerType::get(llvm::Type::Int8Ty);
|
|
std::vector<const llvm::Type*> args;
|
|
|
|
if (fdecl->llvmInternal == LLVMva_start) {
|
|
args.push_back(i8pty);
|
|
}
|
|
else if (fdecl->llvmInternal == LLVMva_intrinsic) {
|
|
size_t n = Argument::dim(f->parameters);
|
|
for (size_t i=0; i<n; ++i) {
|
|
args.push_back(i8pty);
|
|
}
|
|
}
|
|
else
|
|
assert(0);
|
|
|
|
const llvm::FunctionType* fty = llvm::FunctionType::get(llvm::Type::VoidTy, args, false);
|
|
|
|
f->llvmType = new llvm::PATypeHolder(fty);
|
|
|
|
return fty;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
const llvm::FunctionType* DtoFunctionType(FuncDeclaration* fdecl)
|
|
{
|
|
if ((fdecl->llvmInternal == LLVMva_start) || (fdecl->llvmInternal == LLVMva_intrinsic)) {
|
|
return DtoVaFunctionType(fdecl);
|
|
}
|
|
|
|
// type has already been resolved
|
|
if (fdecl->type->llvmType != 0) {
|
|
return llvm::cast<llvm::FunctionType>(fdecl->type->llvmType->get());
|
|
}
|
|
|
|
const llvm::Type* thisty = NULL;
|
|
if (fdecl->needThis()) {
|
|
if (AggregateDeclaration* ad = fdecl->isMember()) {
|
|
Logger::print("isMember = this is: %s\n", ad->type->toChars());
|
|
thisty = DtoType(ad->type);
|
|
//Logger::cout() << "this llvm type: " << *thisty << '\n';
|
|
if (isaStruct(thisty) || (!gIR->structs.empty() && thisty == gIR->topstruct()->recty.get()))
|
|
thisty = llvm::PointerType::get(thisty);
|
|
}
|
|
else
|
|
assert(0);
|
|
}
|
|
else if (fdecl->isNested()) {
|
|
thisty = llvm::PointerType::get(llvm::Type::Int8Ty);
|
|
}
|
|
|
|
const llvm::FunctionType* functype = DtoFunctionType(fdecl->type, thisty, fdecl->isMain());
|
|
|
|
return functype;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static llvm::Function* DtoDeclareVaFunction(FuncDeclaration* fdecl)
|
|
{
|
|
TypeFunction* f = (TypeFunction*)DtoDType(fdecl->type);
|
|
const llvm::FunctionType* fty = DtoVaFunctionType(fdecl);
|
|
llvm::Constant* fn = 0;
|
|
|
|
if (fdecl->llvmInternal == LLVMva_start) {
|
|
fn = gIR->module->getOrInsertFunction("llvm.va_start", fty);
|
|
assert(fn);
|
|
}
|
|
else if (fdecl->llvmInternal == LLVMva_intrinsic) {
|
|
fn = gIR->module->getOrInsertFunction(fdecl->llvmInternal1, fty);
|
|
assert(fn);
|
|
}
|
|
else
|
|
assert(0);
|
|
|
|
llvm::Function* func = llvm::dyn_cast<llvm::Function>(fn);
|
|
assert(func);
|
|
assert(func->isIntrinsic());
|
|
fdecl->llvmValue = func;
|
|
return func;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
void DtoResolveFunction(FuncDeclaration* fdecl)
|
|
{
|
|
if (fdecl->llvmResolved) return;
|
|
fdecl->llvmResolved = true;
|
|
|
|
Logger::println("DtoResolveFunction(%s)", fdecl->toPrettyChars());
|
|
LOG_SCOPE;
|
|
|
|
if (fdecl->llvmRunTimeHack) {
|
|
gIR->declareList.push_back(fdecl);
|
|
return;
|
|
}
|
|
|
|
if (fdecl->isUnitTestDeclaration()) {
|
|
Logger::attention("ignoring unittest declaration: %s", fdecl->toChars());
|
|
return;
|
|
}
|
|
|
|
if (fdecl->parent)
|
|
if (TemplateInstance* tinst = fdecl->parent->isTemplateInstance())
|
|
{
|
|
TemplateDeclaration* tempdecl = tinst->tempdecl;
|
|
if (tempdecl->llvmInternal == LLVMva_arg)
|
|
{
|
|
Logger::println("magic va_arg found");
|
|
fdecl->llvmInternal = LLVMva_arg;
|
|
fdecl->llvmDeclared = true;
|
|
fdecl->llvmInitialized = true;
|
|
fdecl->llvmDefined = true;
|
|
return; // this gets mapped to an instruction so a declaration makes no sence
|
|
}
|
|
else if (tempdecl->llvmInternal == LLVMva_start)
|
|
{
|
|
Logger::println("magic va_start found");
|
|
fdecl->llvmInternal = LLVMva_start;
|
|
}
|
|
}
|
|
|
|
DtoFunctionType(fdecl);
|
|
|
|
// queue declaration
|
|
if (!fdecl->isAbstract())
|
|
gIR->declareList.push_back(fdecl);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
void DtoDeclareFunction(FuncDeclaration* fdecl)
|
|
{
|
|
if (fdecl->llvmDeclared) return;
|
|
fdecl->llvmDeclared = true;
|
|
|
|
Logger::println("DtoDeclareFunction(%s)", fdecl->toPrettyChars());
|
|
LOG_SCOPE;
|
|
|
|
assert(!fdecl->isAbstract());
|
|
|
|
if (fdecl->llvmRunTimeHack) {
|
|
Logger::println("runtime hack func chars: %s", fdecl->toChars());
|
|
if (!fdecl->llvmValue)
|
|
fdecl->llvmValue = LLVM_D_GetRuntimeFunction(gIR->module, fdecl->toChars());
|
|
return;
|
|
}
|
|
|
|
bool declareOnly = false;
|
|
bool templInst = fdecl->parent && DtoIsTemplateInstance(fdecl->parent);
|
|
if (!templInst && fdecl->getModule() != gIR->dmodule)
|
|
declareOnly = true;
|
|
else if (fdecl->llvmInternal == LLVMva_start)
|
|
declareOnly = true;
|
|
|
|
if (!fdecl->llvmIRFunc) {
|
|
fdecl->llvmIRFunc = new IRFunction(fdecl);
|
|
}
|
|
|
|
// mangled name
|
|
char* mangled_name;
|
|
if (fdecl->llvmInternal == LLVMintrinsic)
|
|
mangled_name = fdecl->llvmInternal1;
|
|
else
|
|
mangled_name = fdecl->mangle();
|
|
|
|
// unit test special handling
|
|
if (fdecl->isUnitTestDeclaration())
|
|
{
|
|
assert(0 && "no unittests yet");
|
|
/*const llvm::FunctionType* fnty = llvm::FunctionType::get(llvm::Type::VoidTy, std::vector<const llvm::Type*>(), false);
|
|
// make the function
|
|
llvm::Function* func = gIR->module->getFunction(mangled_name);
|
|
if (func == 0)
|
|
func = new llvm::Function(fnty,llvm::GlobalValue::InternalLinkage,mangled_name,gIR->module);
|
|
func->setCallingConv(llvm::CallingConv::Fast);
|
|
fdecl->llvmValue = func;
|
|
return func;
|
|
*/
|
|
}
|
|
|
|
if (fdecl->llvmInternal == LLVMintrinsic && fdecl->fbody) {
|
|
error("intrinsics cannot have function bodies");
|
|
fatal();
|
|
}
|
|
|
|
llvm::Function* vafunc = 0;
|
|
if ((fdecl->llvmInternal == LLVMva_start) || (fdecl->llvmInternal == LLVMva_intrinsic)) {
|
|
vafunc = DtoDeclareVaFunction(fdecl);
|
|
}
|
|
|
|
Type* t = DtoDType(fdecl->type);
|
|
TypeFunction* f = (TypeFunction*)t;
|
|
|
|
// construct function
|
|
const llvm::FunctionType* functype = DtoFunctionType(fdecl);
|
|
llvm::Function* func = vafunc ? vafunc : gIR->module->getFunction(mangled_name);
|
|
if (!func)
|
|
func = new llvm::Function(functype, DtoLinkage(fdecl->protection, fdecl->storage_class), mangled_name, gIR->module);
|
|
else
|
|
assert(func->getFunctionType() == functype);
|
|
|
|
// add func to IRFunc
|
|
fdecl->llvmIRFunc->func = func;
|
|
|
|
// calling convention
|
|
if (!vafunc && fdecl->llvmInternal != LLVMintrinsic)
|
|
func->setCallingConv(DtoCallingConv(f->linkage));
|
|
|
|
// template instances should have weak linkage
|
|
if (!vafunc && fdecl->llvmInternal != LLVMintrinsic && fdecl->parent && DtoIsTemplateInstance(fdecl->parent))
|
|
func->setLinkage(llvm::GlobalValue::WeakLinkage);
|
|
|
|
fdecl->llvmValue = func;
|
|
assert(llvm::isa<llvm::FunctionType>(f->llvmType->get()));
|
|
|
|
// main
|
|
if (fdecl->isMain()) {
|
|
gIR->mainFunc = func;
|
|
}
|
|
|
|
// static ctor
|
|
if (fdecl->isStaticCtorDeclaration()) {
|
|
gIR->ctors.push_back(fdecl);
|
|
}
|
|
// static dtor
|
|
else if (fdecl->isStaticDtorDeclaration()) {
|
|
gIR->dtors.push_back(fdecl);
|
|
}
|
|
|
|
// name parameters
|
|
llvm::Function::arg_iterator iarg = func->arg_begin();
|
|
int k = 0;
|
|
if (f->llvmRetInPtr) {
|
|
iarg->setName("retval");
|
|
f->llvmRetArg = iarg;
|
|
++iarg;
|
|
}
|
|
if (f->llvmUsesThis) {
|
|
iarg->setName("this");
|
|
fdecl->llvmThisVar = iarg;
|
|
assert(fdecl->llvmThisVar);
|
|
++iarg;
|
|
}
|
|
int varargs = -1;
|
|
if (f->linkage == LINKd && f->varargs == 1)
|
|
varargs = 0;
|
|
for (; iarg != func->arg_end(); ++iarg)
|
|
{
|
|
Argument* arg = Argument::getNth(f->parameters, k++);
|
|
//arg->llvmValue = iarg;
|
|
//Logger::println("identifier: '%s' %p\n", arg->ident->toChars(), arg->ident);
|
|
if (arg && arg->ident != 0) {
|
|
if (arg->vardecl) {
|
|
arg->vardecl->llvmValue = iarg;
|
|
}
|
|
iarg->setName(arg->ident->toChars());
|
|
}
|
|
else if (!arg && varargs >= 0) {
|
|
if (varargs == 0) {
|
|
iarg->setName("_arguments");
|
|
fdecl->llvmArguments = iarg;
|
|
}
|
|
else if (varargs == 1) {
|
|
iarg->setName("_argptr");
|
|
fdecl->llvmArgPtr = iarg;
|
|
}
|
|
else
|
|
assert(0);
|
|
varargs++;
|
|
}
|
|
else {
|
|
iarg->setName("unnamed");
|
|
}
|
|
}
|
|
|
|
if (!declareOnly)
|
|
gIR->defineList.push_back(fdecl);
|
|
|
|
Logger::cout() << "func decl: " << *func << '\n';
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// TODO split this monster up
|
|
void DtoDefineFunc(FuncDeclaration* fd)
|
|
{
|
|
if (fd->llvmDefined) return;
|
|
fd->llvmDefined = true;
|
|
|
|
assert(fd->llvmDeclared);
|
|
|
|
Logger::println("DtoDefineFunc(%s)", fd->toPrettyChars());
|
|
LOG_SCOPE;
|
|
|
|
// debug info
|
|
if (global.params.symdebug) {
|
|
Module* mo = fd->getModule();
|
|
if (!mo->llvmCompileUnit) {
|
|
mo->llvmCompileUnit = DtoDwarfCompileUnit(mo,false);
|
|
}
|
|
fd->llvmDwarfSubProgram = DtoDwarfSubProgram(fd, mo->llvmCompileUnit);
|
|
}
|
|
|
|
Type* t = DtoDType(fd->type);
|
|
TypeFunction* f = (TypeFunction*)t;
|
|
|
|
assert(f->llvmType);
|
|
llvm::Function* func = fd->llvmIRFunc->func;
|
|
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->llvmDModule = gIR->dmodule;
|
|
|
|
// handle static constructor / destructor
|
|
if (fd->isStaticCtorDeclaration() || fd->isStaticDtorDeclaration()) {
|
|
const llvm::ArrayType* sctor_type = llvm::ArrayType::get(llvm::PointerType::get(functype),1);
|
|
//Logger::cout() << "static ctor type: " << *sctor_type << '\n';
|
|
|
|
llvm::Constant* sctor_func = llvm::cast<llvm::Constant>(fd->llvmValue);
|
|
//Logger::cout() << "static ctor func: " << *sctor_func << '\n';
|
|
|
|
llvm::Constant* sctor_init = llvm::ConstantArray::get(sctor_type,&sctor_func,1);
|
|
|
|
//Logger::cout() << "static ctor init: " << *sctor_init << '\n';
|
|
|
|
// output the llvm.global_ctors array
|
|
const char* varname = fd->isStaticCtorDeclaration() ? "_d_module_ctor_array" : "_d_module_dtor_array";
|
|
llvm::GlobalVariable* sctor_arr = new llvm::GlobalVariable(sctor_type, false, llvm::GlobalValue::AppendingLinkage, sctor_init, varname, gIR->module);
|
|
}
|
|
|
|
// function definition
|
|
if (fd->fbody != 0)
|
|
{
|
|
Logger::println("Doing function body for: %s", fd->toChars());
|
|
assert(fd->llvmIRFunc);
|
|
gIR->functions.push_back(fd->llvmIRFunc);
|
|
|
|
/* // moved to declaration
|
|
// this handling
|
|
if (f->llvmUsesThis) {
|
|
Logger::println("uses this");
|
|
if (f->llvmRetInPtr)
|
|
fd->llvmThisVar = ++func->arg_begin();
|
|
else
|
|
fd->llvmThisVar = func->arg_begin();
|
|
assert(fd->llvmThisVar != 0);
|
|
}
|
|
*/
|
|
|
|
if (fd->isMain())
|
|
gIR->emitMain = true;
|
|
|
|
llvm::BasicBlock* beginbb = new llvm::BasicBlock("entry",func);
|
|
llvm::BasicBlock* endbb = new llvm::BasicBlock("endentry",func);
|
|
|
|
//assert(gIR->scopes.empty());
|
|
gIR->scopes.push_back(IRScope(beginbb, endbb));
|
|
|
|
// create alloca point
|
|
f->llvmAllocaPoint = new llvm::BitCastInst(llvm::ConstantInt::get(llvm::Type::Int32Ty,0,false),llvm::Type::Int32Ty,"alloca point",gIR->scopebb());
|
|
gIR->func()->allocapoint = f->llvmAllocaPoint;
|
|
|
|
// need result variable? (not nested)
|
|
if (fd->vresult && !fd->vresult->nestedref) {
|
|
Logger::println("non-nested vresult value");
|
|
fd->vresult->llvmValue = new llvm::AllocaInst(DtoType(fd->vresult->type),"function_vresult",f->llvmAllocaPoint);
|
|
}
|
|
|
|
// give arguments storage
|
|
size_t n = Argument::dim(f->parameters);
|
|
for (int i=0; i < n; ++i) {
|
|
Argument* arg = Argument::getNth(f->parameters, i);
|
|
if (arg && arg->vardecl) {
|
|
VarDeclaration* vd = arg->vardecl;
|
|
if (!vd->llvmNeedsStorage || vd->nestedref || vd->isRef() || vd->isOut() || DtoIsPassedByRef(vd->type))
|
|
continue;
|
|
llvm::Value* a = vd->llvmValue;
|
|
assert(a);
|
|
std::string s(a->getName());
|
|
Logger::println("giving argument '%s' storage", s.c_str());
|
|
s.append("_storage");
|
|
llvm::Value* v = new llvm::AllocaInst(a->getType(),s,f->llvmAllocaPoint);
|
|
gIR->ir->CreateStore(a,v);
|
|
vd->llvmValue = v;
|
|
}
|
|
else {
|
|
Logger::attention("some unknown argument: %s", arg ? arg->toChars() : 0);
|
|
}
|
|
}
|
|
|
|
// debug info
|
|
if (global.params.symdebug) DtoDwarfFuncStart(fd);
|
|
|
|
llvm::Value* parentNested = NULL;
|
|
if (FuncDeclaration* fd2 = fd->toParent()->isFuncDeclaration()) {
|
|
if (!fd->isStatic())
|
|
parentNested = fd2->llvmNested;
|
|
}
|
|
|
|
// need result variable? (nested)
|
|
if (fd->vresult && fd->vresult->nestedref) {
|
|
Logger::println("nested vresult value: %s", fd->vresult->toChars());
|
|
fd->llvmNestedVars.insert(fd->vresult);
|
|
}
|
|
|
|
// construct nested variables struct
|
|
if (!fd->llvmNestedVars.empty() || parentNested) {
|
|
std::vector<const llvm::Type*> nestTypes;
|
|
int j = 0;
|
|
if (parentNested) {
|
|
nestTypes.push_back(parentNested->getType());
|
|
j++;
|
|
}
|
|
for (std::set<VarDeclaration*>::iterator i=fd->llvmNestedVars.begin(); i!=fd->llvmNestedVars.end(); ++i) {
|
|
VarDeclaration* vd = *i;
|
|
vd->llvmNestedIndex = j++;
|
|
if (vd->isParameter()) {
|
|
assert(vd->llvmValue);
|
|
nestTypes.push_back(vd->llvmValue->getType());
|
|
}
|
|
else {
|
|
nestTypes.push_back(DtoType(vd->type));
|
|
}
|
|
}
|
|
const llvm::StructType* nestSType = llvm::StructType::get(nestTypes);
|
|
Logger::cout() << "nested var struct has type:" << '\n' << *nestSType;
|
|
fd->llvmNested = new llvm::AllocaInst(nestSType,"nestedvars",f->llvmAllocaPoint);
|
|
if (parentNested) {
|
|
assert(fd->llvmThisVar);
|
|
llvm::Value* ptr = gIR->ir->CreateBitCast(fd->llvmThisVar, parentNested->getType(), "tmp");
|
|
gIR->ir->CreateStore(ptr, DtoGEPi(fd->llvmNested, 0,0, "tmp"));
|
|
}
|
|
for (std::set<VarDeclaration*>::iterator i=fd->llvmNestedVars.begin(); i!=fd->llvmNestedVars.end(); ++i) {
|
|
VarDeclaration* vd = *i;
|
|
if (vd->isParameter()) {
|
|
gIR->ir->CreateStore(vd->llvmValue, DtoGEPi(fd->llvmNested, 0, vd->llvmNestedIndex, "tmp"));
|
|
vd->llvmValue = fd->llvmNested;
|
|
}
|
|
}
|
|
}
|
|
|
|
// copy _argptr to a memory location
|
|
if (f->linkage == LINKd && f->varargs == 1)
|
|
{
|
|
llvm::Value* argptrmem = new llvm::AllocaInst(fd->llvmArgPtr->getType(), "_argptrmem", gIR->topallocapoint());
|
|
new llvm::StoreInst(fd->llvmArgPtr, argptrmem, gIR->scopebb());
|
|
fd->llvmArgPtr = 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() == llvm::Type::VoidTy) {
|
|
new llvm::ReturnInst(gIR->scopebb());
|
|
}
|
|
else {
|
|
new llvm::ReturnInst(llvm::UndefValue::get(func->getReturnType()), gIR->scopebb());
|
|
}
|
|
}
|
|
}
|
|
|
|
// erase alloca point
|
|
f->llvmAllocaPoint->eraseFromParent();
|
|
f->llvmAllocaPoint = 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() == llvm::Type::VoidTy) {
|
|
new llvm::ReturnInst(lastbb);
|
|
}
|
|
else {
|
|
new llvm::ReturnInst(llvm::UndefValue::get(func->getReturnType()), lastbb);
|
|
}*/
|
|
}
|
|
}
|
|
|
|
gIR->functions.pop_back();
|
|
}
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
void DtoMain()
|
|
{
|
|
// emit main function llvm style
|
|
// int main(int argc, char**argv, char**env);
|
|
|
|
assert(gIR != 0);
|
|
IRState& ir = *gIR;
|
|
|
|
assert(ir.emitMain && ir.mainFunc);
|
|
|
|
// parameter types
|
|
std::vector<const llvm::Type*> pvec;
|
|
pvec.push_back((const llvm::Type*)llvm::Type::Int32Ty);
|
|
const llvm::Type* chPtrType = (const llvm::Type*)llvm::PointerType::get(llvm::Type::Int8Ty);
|
|
pvec.push_back((const llvm::Type*)llvm::PointerType::get(chPtrType));
|
|
pvec.push_back((const llvm::Type*)llvm::PointerType::get(chPtrType));
|
|
const llvm::Type* rettype = (const llvm::Type*)llvm::Type::Int32Ty;
|
|
|
|
llvm::FunctionType* functype = llvm::FunctionType::get(rettype, pvec, false);
|
|
llvm::Function* func = new llvm::Function(functype,llvm::GlobalValue::ExternalLinkage,"main",ir.module);
|
|
|
|
llvm::BasicBlock* bb = new llvm::BasicBlock("entry",func);
|
|
|
|
// call static ctors
|
|
llvm::Function* fn = LLVM_D_GetRuntimeFunction(ir.module,"_d_run_module_ctors");
|
|
llvm::Instruction* apt = new llvm::CallInst(fn,"",bb);
|
|
|
|
// call user main function
|
|
const llvm::FunctionType* mainty = ir.mainFunc->getFunctionType();
|
|
llvm::CallInst* call;
|
|
if (mainty->getNumParams() > 0)
|
|
{
|
|
// main with arguments
|
|
assert(mainty->getNumParams() == 1);
|
|
std::vector<llvm::Value*> args;
|
|
llvm::Function* mfn = LLVM_D_GetRuntimeFunction(ir.module,"_d_main_args");
|
|
|
|
llvm::Function::arg_iterator argi = func->arg_begin();
|
|
args.push_back(argi++);
|
|
args.push_back(argi++);
|
|
|
|
const llvm::Type* at = mainty->getParamType(0)->getContainedType(0);
|
|
llvm::Value* arr = new llvm::AllocaInst(at->getContainedType(1)->getContainedType(0), func->arg_begin(), "argstorage", apt);
|
|
llvm::Value* a = new llvm::AllocaInst(at, "argarray", apt);
|
|
llvm::Value* ptr = DtoGEPi(a,0,0,"tmp",bb);
|
|
llvm::Value* v = args[0];
|
|
if (v->getType() != DtoSize_t())
|
|
v = new llvm::ZExtInst(v, DtoSize_t(), "tmp", bb);
|
|
new llvm::StoreInst(v,ptr,bb);
|
|
ptr = DtoGEPi(a,0,1,"tmp",bb);
|
|
new llvm::StoreInst(arr,ptr,bb);
|
|
args.push_back(a);
|
|
new llvm::CallInst(mfn, args.begin(), args.end(), "", bb);
|
|
call = new llvm::CallInst(ir.mainFunc,a,"ret",bb);
|
|
}
|
|
else
|
|
{
|
|
// main with no arguments
|
|
call = new llvm::CallInst(ir.mainFunc,"ret",bb);
|
|
}
|
|
call->setCallingConv(ir.mainFunc->getCallingConv());
|
|
|
|
// call static dtors
|
|
fn = LLVM_D_GetRuntimeFunction(ir.module,"_d_run_module_dtors");
|
|
new llvm::CallInst(fn,"",bb);
|
|
|
|
// return
|
|
new llvm::ReturnInst(call,bb);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|