/// ImpCastExprToType - If Expr is not of type 'Type', insert an implicit cast. /// If there is already an implicit cast, merge into the existing one. /// If isLvalue, the result of the cast is an lvalue. void Sema::ImpCastExprToType(Expr *&Expr, QualType Ty, CastExpr::CastKind Kind, bool isLvalue) { QualType ExprTy = Context.getCanonicalType(Expr->getType()); QualType TypeTy = Context.getCanonicalType(Ty); if (ExprTy == TypeTy) return; if (Expr->getType()->isPointerType() && Ty->isPointerType()) { QualType ExprBaseType = cast<PointerType>(ExprTy)->getPointeeType(); QualType BaseType = cast<PointerType>(TypeTy)->getPointeeType(); if (ExprBaseType.getAddressSpace() != BaseType.getAddressSpace()) { Diag(Expr->getExprLoc(), diag::err_implicit_pointer_address_space_cast) << Expr->getSourceRange(); } } CheckImplicitConversion(Expr, Ty); if (ImplicitCastExpr *ImpCast = dyn_cast<ImplicitCastExpr>(Expr)) { if (ImpCast->getCastKind() == Kind) { ImpCast->setType(Ty); ImpCast->setLvalueCast(isLvalue); return; } } Expr = new (Context) ImplicitCastExpr(Ty, Kind, Expr, isLvalue); }
unsigned clang_getAddressSpace(CXType CT) { QualType T = GetQualType(CT); // For non language-specific address space, use separate helper function. if (T.getAddressSpace() >= LangAS::FirstTargetAddressSpace) { return T.getQualifiers().getAddressSpaceAttributePrintValue(); } // FIXME: this function returns either a LangAS or a target AS // Those values can overlap which makes this function rather unpredictable // for any caller return (unsigned)T.getAddressSpace(); }
/// HandleAddressSpaceTypeAttribute - Process an address_space attribute on the /// specified type. The attribute contains 1 argument, the id of the address /// space for the type. static void HandleAddressSpaceTypeAttribute(QualType &Type, const AttributeList &Attr, Sema &S){ // If this type is already address space qualified, reject it. // Clause 6.7.3 - Type qualifiers: "No type shall be qualified by qualifiers // for two or more different address spaces." if (Type.getAddressSpace()) { S.Diag(Attr.getLoc(), diag::err_attribute_address_multiple_qualifiers); return; } // Check the attribute arguments. if (Attr.getNumArgs() != 1) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; return; } Expr *ASArgExpr = static_cast<Expr *>(Attr.getArg(0)); llvm::APSInt addrSpace(32); if (!ASArgExpr->isIntegerConstantExpr(addrSpace, S.Context)) { S.Diag(Attr.getLoc(), diag::err_attribute_address_space_not_int) << ASArgExpr->getSourceRange(); return; } unsigned ASIdx = static_cast<unsigned>(addrSpace.getZExtValue()); Type = S.Context.getAddrSpaceQualType(Type, ASIdx); }
llvm::GlobalVariable * CodeGenFunction::CreateStaticBlockVarDecl(const VarDecl &D, const char *Separator, llvm::GlobalValue::LinkageTypes Linkage) { QualType Ty = D.getType(); assert(Ty->isConstantSizeType() && "VLAs can't be static"); std::string Name; if (getContext().getLangOptions().CPlusPlus) { Name = CGM.getMangledName(&D); } else { std::string ContextName; if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CurFuncDecl)) ContextName = CGM.getMangledName(FD); else if (isa<ObjCMethodDecl>(CurFuncDecl)) ContextName = CurFn->getName(); else assert(0 && "Unknown context for block var decl"); Name = ContextName + Separator + D.getNameAsString(); } const llvm::Type *LTy = CGM.getTypes().ConvertTypeForMem(Ty); return new llvm::GlobalVariable(CGM.getModule(), LTy, Ty.isConstant(getContext()), Linkage, CGM.EmitNullConstant(D.getType()), Name, 0, D.isThreadSpecified(), Ty.getAddressSpace()); }
/// ImpCastExprToType - If Expr is not of type 'Type', insert an implicit cast. /// If there is already an implicit cast, merge into the existing one. /// The result is of the given category. void Sema::ImpCastExprToType(Expr *&Expr, QualType Ty, CastExpr::CastKind Kind, ImplicitCastExpr::ResultCategory Category, const CXXCastPath *BasePath) { QualType ExprTy = Context.getCanonicalType(Expr->getType()); QualType TypeTy = Context.getCanonicalType(Ty); if (ExprTy == TypeTy) return; if (Expr->getType()->isPointerType() && Ty->isPointerType()) { QualType ExprBaseType = cast<PointerType>(ExprTy)->getPointeeType(); QualType BaseType = cast<PointerType>(TypeTy)->getPointeeType(); if (ExprBaseType.getAddressSpace() != BaseType.getAddressSpace()) { Diag(Expr->getExprLoc(), diag::err_implicit_pointer_address_space_cast) << Expr->getSourceRange(); } } // If this is a derived-to-base cast to a through a virtual base, we // need a vtable. if (Kind == CastExpr::CK_DerivedToBase && BasePathInvolvesVirtualBase(*BasePath)) { QualType T = Expr->getType(); if (const PointerType *Pointer = T->getAs<PointerType>()) T = Pointer->getPointeeType(); if (const RecordType *RecordTy = T->getAs<RecordType>()) MarkVTableUsed(Expr->getLocStart(), cast<CXXRecordDecl>(RecordTy->getDecl())); } if (ImplicitCastExpr *ImpCast = dyn_cast<ImplicitCastExpr>(Expr)) { if (ImpCast->getCastKind() == Kind && (!BasePath || BasePath->empty())) { ImpCast->setType(Ty); ImpCast->setCategory(Category); return; } } Expr = ImplicitCastExpr::Create(Context, Ty, Kind, Expr, BasePath, Category); }
llvm::GlobalVariable * CodeGenFunction::CreateStaticBlockVarDecl(const VarDecl &D, const char *Separator, llvm::GlobalValue::LinkageTypes Linkage) { QualType Ty = D.getType(); assert(Ty->isConstantSizeType() && "VLAs can't be static"); std::string Name = GetStaticDeclName(*this, D, Separator); const llvm::Type *LTy = CGM.getTypes().ConvertTypeForMem(Ty); llvm::GlobalVariable *GV = new llvm::GlobalVariable(CGM.getModule(), LTy, Ty.isConstant(getContext()), Linkage, CGM.EmitNullConstant(D.getType()), Name, 0, D.isThreadSpecified(), Ty.getAddressSpace()); GV->setAlignment(getContext().getDeclAlignInBytes(&D)); return GV; }
const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) { const clang::Type &Ty = *Context.getCanonicalType(T).getTypePtr(); switch (Ty.getTypeClass()) { #define TYPE(Class, Base) #define ABSTRACT_TYPE(Class, Base) #define NON_CANONICAL_TYPE(Class, Base) case Type::Class: #define DEPENDENT_TYPE(Class, Base) case Type::Class: #define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base) case Type::Class: #include "clang/AST/TypeNodes.def" assert(false && "Non-canonical or dependent types aren't possible."); break; case Type::Builtin: { switch (cast<BuiltinType>(Ty).getKind()) { case BuiltinType::Void: case BuiltinType::ObjCId: case BuiltinType::ObjCClass: case BuiltinType::ObjCSel: // LLVM void type can only be used as the result of a function call. Just // map to the same as char. return llvm::Type::getInt8Ty(getLLVMContext()); case BuiltinType::Bool: // Note that we always return bool as i1 for use as a scalar type. return llvm::Type::getInt1Ty(getLLVMContext()); case BuiltinType::Char_S: case BuiltinType::Char_U: case BuiltinType::SChar: case BuiltinType::UChar: case BuiltinType::Short: case BuiltinType::UShort: case BuiltinType::Int: case BuiltinType::UInt: case BuiltinType::Long: case BuiltinType::ULong: case BuiltinType::LongLong: case BuiltinType::ULongLong: case BuiltinType::WChar_S: case BuiltinType::WChar_U: case BuiltinType::Char16: case BuiltinType::Char32: return llvm::IntegerType::get(getLLVMContext(), static_cast<unsigned>(Context.getTypeSize(T))); #ifdef __SNUCL_COMPILER__ case BuiltinType::Half: #endif case BuiltinType::Float: case BuiltinType::Double: case BuiltinType::LongDouble: return getTypeForFormat(getLLVMContext(), Context.getFloatTypeSemantics(T)); case BuiltinType::NullPtr: { // Model std::nullptr_t as i8* const llvm::Type *Ty = llvm::Type::getInt8Ty(getLLVMContext()); return llvm::PointerType::getUnqual(Ty); } case BuiltinType::UInt128: case BuiltinType::Int128: return llvm::IntegerType::get(getLLVMContext(), 128); case BuiltinType::Overload: case BuiltinType::Dependent: assert(0 && "Unexpected builtin type!"); break; } assert(0 && "Unknown builtin type!"); break; } case Type::Complex: { const llvm::Type *EltTy = ConvertTypeRecursive(cast<ComplexType>(Ty).getElementType()); return llvm::StructType::get(TheModule.getContext(), EltTy, EltTy, NULL); } case Type::LValueReference: case Type::RValueReference: { const ReferenceType &RTy = cast<ReferenceType>(Ty); QualType ETy = RTy.getPointeeType(); llvm::OpaqueType *PointeeType = llvm::OpaqueType::get(getLLVMContext()); PointersToResolve.push_back(std::make_pair(ETy, PointeeType)); return llvm::PointerType::get(PointeeType, ETy.getAddressSpace()); } case Type::Pointer: { const PointerType &PTy = cast<PointerType>(Ty); QualType ETy = PTy.getPointeeType(); llvm::OpaqueType *PointeeType = llvm::OpaqueType::get(getLLVMContext()); PointersToResolve.push_back(std::make_pair(ETy, PointeeType)); return llvm::PointerType::get(PointeeType, ETy.getAddressSpace()); } case Type::VariableArray: { const VariableArrayType &A = cast<VariableArrayType>(Ty); assert(A.getIndexTypeCVRQualifiers() == 0 && "FIXME: We only handle trivial array types so far!"); // VLAs resolve to the innermost element type; this matches // the return of alloca, and there isn't any obviously better choice. return ConvertTypeForMemRecursive(A.getElementType()); } case Type::IncompleteArray: { const IncompleteArrayType &A = cast<IncompleteArrayType>(Ty); assert(A.getIndexTypeCVRQualifiers() == 0 && "FIXME: We only handle trivial array types so far!"); // int X[] -> [0 x int] return llvm::ArrayType::get(ConvertTypeForMemRecursive(A.getElementType()), 0); } case Type::ConstantArray: { const ConstantArrayType &A = cast<ConstantArrayType>(Ty); const llvm::Type *EltTy = ConvertTypeForMemRecursive(A.getElementType()); return llvm::ArrayType::get(EltTy, A.getSize().getZExtValue()); } case Type::ExtVector: case Type::Vector: { const VectorType &VT = cast<VectorType>(Ty); return llvm::VectorType::get(ConvertTypeRecursive(VT.getElementType()), VT.getNumElements()); } case Type::FunctionNoProto: case Type::FunctionProto: { // First, check whether we can build the full function type. If the // function type depends on an incomplete type (e.g. a struct or enum), we // cannot lower the function type. Instead, turn it into an Opaque pointer // and have UpdateCompletedType revisit the function type when/if the opaque // argument type is defined. if (const TagType *TT = VerifyFuncTypeComplete(&Ty)) { // This function's type depends on an incomplete tag type; make sure // we have an opaque type corresponding to the tag type. ConvertTagDeclType(TT->getDecl()); // Create an opaque type for this function type, save it, and return it. llvm::Type *ResultType = llvm::OpaqueType::get(getLLVMContext()); FunctionTypes.insert(std::make_pair(&Ty, ResultType)); return ResultType; } // The function type can be built; call the appropriate routines to // build it. const CGFunctionInfo *FI; bool isVariadic; if (const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(&Ty)) { FI = &getFunctionInfo( CanQual<FunctionProtoType>::CreateUnsafe(QualType(FPT, 0)), true /*Recursive*/); isVariadic = FPT->isVariadic(); } else { const FunctionNoProtoType *FNPT = cast<FunctionNoProtoType>(&Ty); FI = &getFunctionInfo( CanQual<FunctionNoProtoType>::CreateUnsafe(QualType(FNPT, 0)), true /*Recursive*/); isVariadic = true; } return GetFunctionType(*FI, isVariadic, true); } case Type::ObjCObject: return ConvertTypeRecursive(cast<ObjCObjectType>(Ty).getBaseType()); case Type::ObjCInterface: { // Objective-C interfaces are always opaque (outside of the // runtime, which can do whatever it likes); we never refine // these. const llvm::Type *&T = InterfaceTypes[cast<ObjCInterfaceType>(&Ty)]; if (!T) T = llvm::OpaqueType::get(getLLVMContext()); return T; } case Type::ObjCObjectPointer: { // Protocol qualifications do not influence the LLVM type, we just return a // pointer to the underlying interface type. We don't need to worry about // recursive conversion. const llvm::Type *T = ConvertTypeRecursive(cast<ObjCObjectPointerType>(Ty).getPointeeType()); return llvm::PointerType::getUnqual(T); } case Type::Record: case Type::Enum: { const TagDecl *TD = cast<TagType>(Ty).getDecl(); const llvm::Type *Res = ConvertTagDeclType(TD); llvm::SmallString<256> TypeName; llvm::raw_svector_ostream OS(TypeName); OS << TD->getKindName() << '.'; // Name the codegen type after the typedef name // if there is no tag type name available if (TD->getIdentifier()) { // FIXME: We should not have to check for a null decl context here. // Right now we do it because the implicit Obj-C decls don't have one. if (TD->getDeclContext()) OS << TD->getQualifiedNameAsString(); else TD->printName(OS); } else if (const TypedefDecl *TDD = TD->getTypedefForAnonDecl()) { // FIXME: We should not have to check for a null decl context here. // Right now we do it because the implicit Obj-C decls don't have one. if (TDD->getDeclContext()) OS << TDD->getQualifiedNameAsString(); else TDD->printName(OS); } else OS << "anon"; TheModule.addTypeName(OS.str(), Res); return Res; } case Type::BlockPointer: { const QualType FTy = cast<BlockPointerType>(Ty).getPointeeType(); llvm::OpaqueType *PointeeType = llvm::OpaqueType::get(getLLVMContext()); PointersToResolve.push_back(std::make_pair(FTy, PointeeType)); return llvm::PointerType::get(PointeeType, FTy.getAddressSpace()); } case Type::MemberPointer: { return getCXXABI().ConvertMemberPointerType(cast<MemberPointerType>(&Ty)); } } // FIXME: implement. return llvm::OpaqueType::get(getLLVMContext()); }
const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) { const clang::Type &Ty = *Context.getCanonicalType(T).getTypePtr(); switch (Ty.getTypeClass()) { #define TYPE(Class, Base) #define ABSTRACT_TYPE(Class, Base) #define NON_CANONICAL_TYPE(Class, Base) case Type::Class: #define DEPENDENT_TYPE(Class, Base) case Type::Class: #include "clang/AST/TypeNodes.def" assert(false && "Non-canonical or dependent types aren't possible."); break; case Type::Builtin: { switch (cast<BuiltinType>(Ty).getKind()) { default: assert(0 && "Unknown builtin type!"); case BuiltinType::Void: case BuiltinType::ObjCId: case BuiltinType::ObjCClass: case BuiltinType::ObjCSel: // LLVM void type can only be used as the result of a function call. Just // map to the same as char. return llvm::IntegerType::get(getLLVMContext(), 8); case BuiltinType::Bool: // Note that we always return bool as i1 for use as a scalar type. return llvm::Type::getInt1Ty(getLLVMContext()); case BuiltinType::Char_S: case BuiltinType::Char_U: case BuiltinType::SChar: case BuiltinType::UChar: case BuiltinType::Short: case BuiltinType::UShort: case BuiltinType::Int: case BuiltinType::UInt: case BuiltinType::Long: case BuiltinType::ULong: case BuiltinType::LongLong: case BuiltinType::ULongLong: case BuiltinType::WChar: case BuiltinType::Char16: case BuiltinType::Char32: return llvm::IntegerType::get(getLLVMContext(), static_cast<unsigned>(Context.getTypeSize(T))); case BuiltinType::Float: case BuiltinType::Double: case BuiltinType::LongDouble: return getTypeForFormat(getLLVMContext(), Context.getFloatTypeSemantics(T)); case BuiltinType::NullPtr: { // Model std::nullptr_t as i8* const llvm::Type *Ty = llvm::IntegerType::get(getLLVMContext(), 8); return llvm::PointerType::getUnqual(Ty); } case BuiltinType::UInt128: case BuiltinType::Int128: return llvm::IntegerType::get(getLLVMContext(), 128); } break; } case Type::FixedWidthInt: return llvm::IntegerType::get(getLLVMContext(), cast<FixedWidthIntType>(T)->getWidth()); case Type::Complex: { const llvm::Type *EltTy = ConvertTypeRecursive(cast<ComplexType>(Ty).getElementType()); return llvm::StructType::get(TheModule.getContext(), EltTy, EltTy, NULL); } case Type::LValueReference: case Type::RValueReference: { const ReferenceType &RTy = cast<ReferenceType>(Ty); QualType ETy = RTy.getPointeeType(); llvm::OpaqueType *PointeeType = llvm::OpaqueType::get(getLLVMContext()); PointersToResolve.push_back(std::make_pair(ETy, PointeeType)); return llvm::PointerType::get(PointeeType, ETy.getAddressSpace()); } case Type::Pointer: { const PointerType &PTy = cast<PointerType>(Ty); QualType ETy = PTy.getPointeeType(); llvm::OpaqueType *PointeeType = llvm::OpaqueType::get(getLLVMContext()); PointersToResolve.push_back(std::make_pair(ETy, PointeeType)); return llvm::PointerType::get(PointeeType, ETy.getAddressSpace()); } case Type::VariableArray: { const VariableArrayType &A = cast<VariableArrayType>(Ty); assert(A.getIndexTypeCVRQualifiers() == 0 && "FIXME: We only handle trivial array types so far!"); // VLAs resolve to the innermost element type; this matches // the return of alloca, and there isn't any obviously better choice. return ConvertTypeForMemRecursive(A.getElementType()); } case Type::IncompleteArray: { const IncompleteArrayType &A = cast<IncompleteArrayType>(Ty); assert(A.getIndexTypeCVRQualifiers() == 0 && "FIXME: We only handle trivial array types so far!"); // int X[] -> [0 x int] return llvm::ArrayType::get(ConvertTypeForMemRecursive(A.getElementType()), 0); } case Type::ConstantArray: { const ConstantArrayType &A = cast<ConstantArrayType>(Ty); const llvm::Type *EltTy = ConvertTypeForMemRecursive(A.getElementType()); return llvm::ArrayType::get(EltTy, A.getSize().getZExtValue()); } case Type::ExtVector: case Type::Vector: { const VectorType &VT = cast<VectorType>(Ty); return llvm::VectorType::get(ConvertTypeRecursive(VT.getElementType()), VT.getNumElements()); } case Type::FunctionNoProto: case Type::FunctionProto: { // First, check whether we can build the full function type. if (const TagType* TT = VerifyFuncTypeComplete(&Ty)) { // This function's type depends on an incomplete tag type; make sure // we have an opaque type corresponding to the tag type. ConvertTagDeclType(TT->getDecl()); // Create an opaque type for this function type, save it, and return it. llvm::Type *ResultType = llvm::OpaqueType::get(getLLVMContext()); FunctionTypes.insert(std::make_pair(&Ty, ResultType)); return ResultType; } // The function type can be built; call the appropriate routines to // build it. if (const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(&Ty)) return GetFunctionType(getFunctionInfo(FPT), FPT->isVariadic()); const FunctionNoProtoType *FNPT = cast<FunctionNoProtoType>(&Ty); return GetFunctionType(getFunctionInfo(FNPT), true); } case Type::ObjCInterface: { // Objective-C interfaces are always opaque (outside of the // runtime, which can do whatever it likes); we never refine // these. const llvm::Type *&T = InterfaceTypes[cast<ObjCInterfaceType>(&Ty)]; if (!T) T = llvm::OpaqueType::get(getLLVMContext()); return T; } case Type::ObjCObjectPointer: { // Protocol qualifications do not influence the LLVM type, we just return a // pointer to the underlying interface type. We don't need to worry about // recursive conversion. const llvm::Type *T = ConvertTypeRecursive(cast<ObjCObjectPointerType>(Ty).getPointeeType()); return llvm::PointerType::getUnqual(T); } case Type::Record: case Type::Enum: { const TagDecl *TD = cast<TagType>(Ty).getDecl(); const llvm::Type *Res = ConvertTagDeclType(TD); std::string TypeName(TD->getKindName()); TypeName += '.'; // Name the codegen type after the typedef name // if there is no tag type name available if (TD->getIdentifier()) // FIXME: We should not have to check for a null decl context here. // Right now we do it because the implicit Obj-C decls don't have one. TypeName += TD->getDeclContext() ? TD->getQualifiedNameAsString() : TD->getNameAsString(); else if (const TypedefType *TdT = dyn_cast<TypedefType>(T)) // FIXME: We should not have to check for a null decl context here. // Right now we do it because the implicit Obj-C decls don't have one. TypeName += TdT->getDecl()->getDeclContext() ? TdT->getDecl()->getQualifiedNameAsString() : TdT->getDecl()->getNameAsString(); else TypeName += "anon"; TheModule.addTypeName(TypeName, Res); return Res; } case Type::BlockPointer: { const QualType FTy = cast<BlockPointerType>(Ty).getPointeeType(); llvm::OpaqueType *PointeeType = llvm::OpaqueType::get(getLLVMContext()); PointersToResolve.push_back(std::make_pair(FTy, PointeeType)); return llvm::PointerType::get(PointeeType, FTy.getAddressSpace()); } case Type::MemberPointer: { // FIXME: This is ABI dependent. We use the Itanium C++ ABI. // http://www.codesourcery.com/public/cxx-abi/abi.html#member-pointers // If we ever want to support other ABIs this needs to be abstracted. QualType ETy = cast<MemberPointerType>(Ty).getPointeeType(); const llvm::Type *PtrDiffTy = ConvertTypeRecursive(Context.getPointerDiffType()); if (ETy->isFunctionType()) { return llvm::StructType::get(TheModule.getContext(), PtrDiffTy, PtrDiffTy, NULL); } else return PtrDiffTy; } case Type::TemplateSpecialization: assert(false && "Dependent types can't get here"); } // FIXME: implement. return llvm::OpaqueType::get(getLLVMContext()); }
const llvm::FunctionType * CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI, bool IsVariadic) { std::vector<const llvm::Type*> ArgTys; const llvm::Type *ResultType = 0; QualType RetTy = FI.getReturnType(); const ABIArgInfo &RetAI = FI.getReturnInfo(); switch (RetAI.getKind()) { case ABIArgInfo::Expand: assert(0 && "Invalid ABI kind for return argument"); case ABIArgInfo::Extend: case ABIArgInfo::Direct: ResultType = ConvertType(RetTy); break; case ABIArgInfo::Indirect: { assert(!RetAI.getIndirectAlign() && "Align unused on indirect return."); ResultType = llvm::Type::getVoidTy(getLLVMContext()); const llvm::Type *STy = ConvertType(RetTy); ArgTys.push_back(llvm::PointerType::get(STy, RetTy.getAddressSpace())); break; } case ABIArgInfo::Ignore: ResultType = llvm::Type::getVoidTy(getLLVMContext()); break; case ABIArgInfo::Coerce: ResultType = RetAI.getCoerceToType(); break; } for (CGFunctionInfo::const_arg_iterator it = FI.arg_begin(), ie = FI.arg_end(); it != ie; ++it) { const ABIArgInfo &AI = it->info; switch (AI.getKind()) { case ABIArgInfo::Ignore: break; case ABIArgInfo::Coerce: ArgTys.push_back(AI.getCoerceToType()); break; case ABIArgInfo::Indirect: { // indirect arguments are always on the stack, which is addr space #0. const llvm::Type *LTy = ConvertTypeForMem(it->type); ArgTys.push_back(llvm::PointerType::getUnqual(LTy)); break; } case ABIArgInfo::Extend: case ABIArgInfo::Direct: ArgTys.push_back(ConvertType(it->type)); break; case ABIArgInfo::Expand: GetExpandedTypes(it->type, ArgTys); break; } } return llvm::FunctionType::get(ResultType, ArgTys, IsVariadic); }