llvm::FunctionType* DtoFunctionType(Type* type, IrFuncTy &irFty, Type* thistype, Type* nesttype, bool isMain, bool isCtor, bool isIntrinsic) { IF_LOG Logger::println("DtoFunctionType(%s)", type->toChars()); LOG_SCOPE // sanity check assert(type->ty == Tfunction); TypeFunction* f = static_cast<TypeFunction*>(type); assert(f->next && "Encountered function type with invalid return type; " "trying to codegen function ignored by the frontend?"); // Return cached type if available if (irFty.funcType) return irFty.funcType; TargetABI* abi = (isIntrinsic ? TargetABI::getIntrinsic() : gABI); // Tell the ABI we're resolving a new function type abi->newFunctionType(f); // Do not modify irFty yet; this function may be called recursively if any // of the argument types refer to this type. IrFuncTy newIrFty; // llvm idx counter size_t lidx = 0; // main needs a little special handling if (isMain) { newIrFty.ret = new IrFuncTyArg(Type::tint32, false); } // sane return value else { Type* rt = f->next; #if LDC_LLVM_VER >= 302 llvm::AttrBuilder attrBuilder; #else llvm::Attributes a = llvm::Attribute::None; #endif // sret return if (abi->returnInArg(f)) { #if LDC_LLVM_VER >= 302 #if LDC_LLVM_VER >= 303 newIrFty.arg_sret = new IrFuncTyArg(rt, true, llvm::AttrBuilder().addAttribute(llvm::Attribute::StructRet) .addAttribute(llvm::Attribute::NoAlias) #else newIrFty.arg_sret = new IrFuncTyArg(rt, true, llvm::Attributes::get(gIR->context(), llvm::AttrBuilder().addAttribute(llvm::Attributes::StructRet) .addAttribute(llvm::Attributes::NoAlias) #endif #if LDC_LLVM_VER == 302 ) #endif ); #else newIrFty.arg_sret = new IrFuncTyArg(rt, true, llvm::Attribute::StructRet | llvm::Attribute::NoAlias); #endif rt = Type::tvoid; lidx++; } // sext/zext return else {
llvm::FunctionType* DtoFunctionType(Type* type, Type* thistype, Type* nesttype, bool ismain) { if (Logger::enabled()) Logger::println("DtoFunctionType(%s)", type->toChars()); LOG_SCOPE // sanity check assert(type->ty == Tfunction); TypeFunction* f = static_cast<TypeFunction*>(type); TargetABI* abi = (f->linkage == LINKintrinsic ? TargetABI::getIntrinsic() : gABI); // Tell the ABI we're resolving a new function type abi->newFunctionType(f); // Do not modify f->fty yet; this function may be called recursively if any // of the argument types refer to this type. IrFuncTy fty; // llvm idx counter size_t lidx = 0; // main needs a little special handling if (ismain) { fty.ret = new IrFuncTyArg(Type::tint32, false); } // sane return value else { Type* rt = f->next; #if LDC_LLVM_VER >= 302 llvm::AttrBuilder attrBuilder; #else llvm::Attributes a = None; #endif // sret return if (abi->returnInArg(f)) { #if LDC_LLVM_VER >= 302 #if LDC_LLVM_VER >= 303 fty.arg_sret = new IrFuncTyArg(rt, true, llvm::AttrBuilder().addAttribute(llvm::Attribute::StructRet) .addAttribute(llvm::Attribute::NoAlias) #else fty.arg_sret = new IrFuncTyArg(rt, true, llvm::Attributes::get(gIR->context(), llvm::AttrBuilder().addAttribute(llvm::Attributes::StructRet) .addAttribute(llvm::Attributes::NoAlias) #endif #if LDC_LLVM_VER == 302 ) #endif ); #else fty.arg_sret = new IrFuncTyArg(rt, true, StructRet | NoAlias ); #endif rt = Type::tvoid; lidx++; } // sext/zext return else {
llvm::FunctionType* DtoFunctionType(Type* type, Type* thistype, Type* nesttype, bool ismain) { if (Logger::enabled()) Logger::println("DtoFunctionType(%s)", type->toChars()); LOG_SCOPE // sanity check assert(type->ty == Tfunction); TypeFunction* f = (TypeFunction*)type; TargetABI* abi = (f->linkage == LINKintrinsic ? TargetABI::getIntrinsic() : gABI); // Tell the ABI we're resolving a new function type abi->newFunctionType(f); // Do not modify f->fty yet; this function may be called recursively if any // of the argument types refer to this type. IrFuncTy fty; // llvm idx counter size_t lidx = 0; // main needs a little special handling if (ismain) { fty.ret = new IrFuncTyArg(Type::tint32, false); } // sane return value else { Type* rt = f->next; unsigned a = 0; // sret return if (abi->returnInArg(f)) { fty.arg_sret = new IrFuncTyArg(rt, true, StructRet | NoAlias | NoCapture); rt = Type::tvoid; lidx++; } // sext/zext return else { Type *t = rt; #if DMDV2 if (f->isref) t = t->pointerTo(); #endif if (unsigned se = DtoShouldExtend(t)) a = se; } #if DMDV2 fty.ret = new IrFuncTyArg(rt, f->isref, a); #else fty.ret = new IrFuncTyArg(rt, false, a); #endif } lidx++; // member functions if (thistype) { fty.arg_this = new IrFuncTyArg(thistype, thistype->toBasetype()->ty == Tstruct); lidx++; } // and nested functions else if (nesttype) { fty.arg_nest = new IrFuncTyArg(nesttype, false); lidx++; } // vararg functions are special too if (f->varargs) { if (f->linkage == LINKd) { // d style with hidden args // 2 (array) is handled by the frontend if (f->varargs == 1) { // _arguments fty.arg_arguments = new IrFuncTyArg(Type::typeinfo->type->arrayOf(), false); lidx++; // _argptr fty.arg_argptr = new IrFuncTyArg(Type::tvoid->pointerTo(), false, NoAlias | NoCapture); lidx++; } } else if (f->linkage == LINKc) { fty.c_vararg = true; } else { type->error(0, "invalid linkage for variadic function"); fatal(); } } // if this _Dmain() doesn't have an argument, we force it to have one int nargs = Parameter::dim(f->parameters); if (ismain && nargs == 0) { Type* mainargs = Type::tchar->arrayOf()->arrayOf(); fty.args.push_back(new IrFuncTyArg(mainargs, false)); lidx++; } // add explicit parameters else for (int i = 0; i < nargs; i++) { // get argument Parameter* arg = Parameter::getNth(f->parameters, i); // reference semantics? ref, out and d1 static arrays are bool byref = arg->storageClass & (STCref|STCout); #if !SARRAYVALUE byref = byref || (arg->type->toBasetype()->ty == Tsarray); #endif Type* argtype = arg->type; unsigned a = 0; // handle lazy args if (arg->storageClass & STClazy) { Logger::println("lazy param"); TypeFunction *ltf = new TypeFunction(NULL, arg->type, 0, LINKd); TypeDelegate *ltd = new TypeDelegate(ltf); argtype = ltd; } // byval else if (abi->passByVal(byref ? argtype->pointerTo() : argtype)) { if (!byref) a |= llvm::Attribute::ByVal; byref = true; } // sext/zext else if (!byref) { a |= DtoShouldExtend(argtype); } fty.args.push_back(new IrFuncTyArg(argtype, byref, a)); lidx++; } // Now we can modify f->fty safely. f->fty = fty; // let the abi rewrite the types as necesary abi->rewriteFunctionType(f); // Tell the ABI we're done with this function type abi->doneWithFunctionType(); // build the function type std::vector<LLType*> argtypes; argtypes.reserve(lidx); if (f->fty.arg_sret) argtypes.push_back(f->fty.arg_sret->ltype); if (f->fty.arg_this) argtypes.push_back(f->fty.arg_this->ltype); if (f->fty.arg_nest) argtypes.push_back(f->fty.arg_nest->ltype); if (f->fty.arg_arguments) argtypes.push_back(f->fty.arg_arguments->ltype); if (f->fty.arg_argptr) argtypes.push_back(f->fty.arg_argptr->ltype); size_t beg = argtypes.size(); size_t nargs2 = f->fty.args.size(); for (size_t i = 0; i < nargs2; i++) { argtypes.push_back(f->fty.args[i]->ltype); } // reverse params? if (f->fty.reverseParams && nargs2 > 1) { std::reverse(argtypes.begin() + beg, argtypes.end()); } LLFunctionType* functype = LLFunctionType::get(f->fty.ret->ltype, argtypes, f->fty.c_vararg); Logger::cout() << "Final function type: " << *functype << "\n"; return functype; }
llvm::FunctionType* DtoFunctionType(Type* type, IrFuncTy &irFty, Type* thistype, Type* nesttype, bool isMain, bool isCtor, bool isIntrinsic) { IF_LOG Logger::println("DtoFunctionType(%s)", type->toChars()); LOG_SCOPE // sanity check assert(type->ty == Tfunction); TypeFunction* f = static_cast<TypeFunction*>(type); assert(f->next && "Encountered function type with invalid return type; " "trying to codegen function ignored by the frontend?"); // Return cached type if available if (irFty.funcType) return irFty.funcType; TargetABI* abi = (isIntrinsic ? TargetABI::getIntrinsic() : gABI); // Do not modify irFty yet; this function may be called recursively if any // of the argument types refer to this type. IrFuncTy newIrFty; // llvm idx counter size_t lidx = 0; // main needs a little special handling if (isMain) { newIrFty.ret = new IrFuncTyArg(Type::tint32, false); } // sane return value else { Type* rt = f->next; AttrBuilder attrBuilder; // sret return if (abi->returnInArg(f)) { newIrFty.arg_sret = new IrFuncTyArg(rt, true, AttrBuilder().add(LDC_ATTRIBUTE(StructRet)).add(LDC_ATTRIBUTE(NoAlias))); rt = Type::tvoid; lidx++; } // sext/zext return else { Type *t = rt; if (f->isref) t = t->pointerTo(); attrBuilder.add(DtoShouldExtend(t)); } newIrFty.ret = new IrFuncTyArg(rt, f->isref, attrBuilder); } lidx++; // member functions if (thistype) { AttrBuilder attrBuilder; #if LDC_LLVM_VER >= 303 if (isCtor) attrBuilder.add(LDC_ATTRIBUTE(Returned)); #endif newIrFty.arg_this = new IrFuncTyArg(thistype, thistype->toBasetype()->ty == Tstruct, attrBuilder); lidx++; } // and nested functions else if (nesttype) { newIrFty.arg_nest = new IrFuncTyArg(nesttype, false); lidx++; } // vararg functions are special too if (f->varargs) { if (f->linkage == LINKd) { // d style with hidden args // 2 (array) is handled by the frontend if (f->varargs == 1) { // _arguments newIrFty.arg_arguments = new IrFuncTyArg(Type::dtypeinfo->type->arrayOf(), false); lidx++; } } newIrFty.c_vararg = true; } // if this _Dmain() doesn't have an argument, we force it to have one int nargs = Parameter::dim(f->parameters); if (isMain && nargs == 0) { Type* mainargs = Type::tchar->arrayOf()->arrayOf(); newIrFty.args.push_back(new IrFuncTyArg(mainargs, false)); lidx++; } // add explicit parameters else for (int i = 0; i < nargs; i++) { // get argument Parameter* arg = Parameter::getNth(f->parameters, i); // reference semantics? ref, out and d1 static arrays are bool byref = arg->storageClass & (STCref|STCout); Type* argtype = arg->type; AttrBuilder attrBuilder; // handle lazy args if (arg->storageClass & STClazy) { Logger::println("lazy param"); TypeFunction *ltf = new TypeFunction(NULL, arg->type, 0, LINKd); TypeDelegate *ltd = new TypeDelegate(ltf); argtype = ltd; } else if (!byref) { // byval if (abi->passByVal(argtype)) { attrBuilder.add(LDC_ATTRIBUTE(ByVal)); // set byref, because byval requires a pointed LLVM type byref = true; } // sext/zext else { attrBuilder.add(DtoShouldExtend(argtype)); } } newIrFty.args.push_back(new IrFuncTyArg(argtype, byref, attrBuilder)); lidx++; } // let the abi rewrite the types as necesary abi->rewriteFunctionType(f, newIrFty); // Now we can modify irFty safely. irFty = llvm_move(newIrFty); // build the function type std::vector<LLType*> argtypes; argtypes.reserve(lidx); if (irFty.arg_sret) argtypes.push_back(irFty.arg_sret->ltype); if (irFty.arg_this) argtypes.push_back(irFty.arg_this->ltype); if (irFty.arg_nest) argtypes.push_back(irFty.arg_nest->ltype); if (irFty.arg_arguments) argtypes.push_back(irFty.arg_arguments->ltype); size_t beg = argtypes.size(); size_t nargs2 = irFty.args.size(); for (size_t i = 0; i < nargs2; i++) { argtypes.push_back(irFty.args[i]->ltype); } // reverse params? if (irFty.reverseParams && nargs2 > 1) { std::reverse(argtypes.begin() + beg, argtypes.end()); } irFty.funcType = LLFunctionType::get(irFty.ret->ltype, argtypes, irFty.c_vararg); IF_LOG Logger::cout() << "Final function type: " << *irFty.funcType << "\n"; return irFty.funcType; }