1*700637cbSDimitry Andric //==-- CIRGenFunctionInfo.h - Representation of fn argument/return types ---==// 2*700637cbSDimitry Andric // 3*700637cbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*700637cbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*700637cbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*700637cbSDimitry Andric // 7*700637cbSDimitry Andric //===----------------------------------------------------------------------===// 8*700637cbSDimitry Andric // 9*700637cbSDimitry Andric // Defines CIRGenFunctionInfo and associated types used in representing the 10*700637cbSDimitry Andric // CIR source types and ABI-coerced types for function arguments and 11*700637cbSDimitry Andric // return values. 12*700637cbSDimitry Andric // 13*700637cbSDimitry Andric //===----------------------------------------------------------------------===// 14*700637cbSDimitry Andric 15*700637cbSDimitry Andric #ifndef LLVM_CLANG_CIR_CIRGENFUNCTIONINFO_H 16*700637cbSDimitry Andric #define LLVM_CLANG_CIR_CIRGENFUNCTIONINFO_H 17*700637cbSDimitry Andric 18*700637cbSDimitry Andric #include "clang/AST/CanonicalType.h" 19*700637cbSDimitry Andric #include "clang/CIR/MissingFeatures.h" 20*700637cbSDimitry Andric #include "llvm/ADT/FoldingSet.h" 21*700637cbSDimitry Andric #include "llvm/Support/TrailingObjects.h" 22*700637cbSDimitry Andric 23*700637cbSDimitry Andric namespace clang::CIRGen { 24*700637cbSDimitry Andric 25*700637cbSDimitry Andric /// A class for recording the number of arguments that a function signature 26*700637cbSDimitry Andric /// requires. 27*700637cbSDimitry Andric class RequiredArgs { 28*700637cbSDimitry Andric /// The number of required arguments, or ~0 if the signature does not permit 29*700637cbSDimitry Andric /// optional arguments. 30*700637cbSDimitry Andric unsigned numRequired; 31*700637cbSDimitry Andric 32*700637cbSDimitry Andric public: 33*700637cbSDimitry Andric enum All_t { All }; 34*700637cbSDimitry Andric RequiredArgs(All_t _)35*700637cbSDimitry Andric RequiredArgs(All_t _) : numRequired(~0U) {} RequiredArgs(unsigned n)36*700637cbSDimitry Andric explicit RequiredArgs(unsigned n) : numRequired(n) { assert(n != ~0U); } 37*700637cbSDimitry Andric getOpaqueData()38*700637cbSDimitry Andric unsigned getOpaqueData() const { return numRequired; } 39*700637cbSDimitry Andric allowsOptionalArgs()40*700637cbSDimitry Andric bool allowsOptionalArgs() const { return numRequired != ~0U; } 41*700637cbSDimitry Andric 42*700637cbSDimitry Andric /// Compute the arguments required by the given formal prototype, given that 43*700637cbSDimitry Andric /// there may be some additional, non-formal arguments in play. 44*700637cbSDimitry Andric /// 45*700637cbSDimitry Andric /// If FD is not null, this will consider pass_object_size params in FD. 46*700637cbSDimitry Andric static RequiredArgs getFromProtoWithExtraSlots(const clang::FunctionProtoType * prototype,unsigned additional)47*700637cbSDimitry Andric getFromProtoWithExtraSlots(const clang::FunctionProtoType *prototype, 48*700637cbSDimitry Andric unsigned additional) { 49*700637cbSDimitry Andric if (!prototype->isVariadic()) 50*700637cbSDimitry Andric return All; 51*700637cbSDimitry Andric 52*700637cbSDimitry Andric if (prototype->hasExtParameterInfos()) 53*700637cbSDimitry Andric llvm_unreachable("NYI"); 54*700637cbSDimitry Andric 55*700637cbSDimitry Andric return RequiredArgs(prototype->getNumParams() + additional); 56*700637cbSDimitry Andric } 57*700637cbSDimitry Andric 58*700637cbSDimitry Andric static RequiredArgs getFromProtoWithExtraSlots(clang::CanQual<clang::FunctionProtoType> prototype,unsigned additional)59*700637cbSDimitry Andric getFromProtoWithExtraSlots(clang::CanQual<clang::FunctionProtoType> prototype, 60*700637cbSDimitry Andric unsigned additional) { 61*700637cbSDimitry Andric return getFromProtoWithExtraSlots(prototype.getTypePtr(), additional); 62*700637cbSDimitry Andric } 63*700637cbSDimitry Andric getNumRequiredArgs()64*700637cbSDimitry Andric unsigned getNumRequiredArgs() const { 65*700637cbSDimitry Andric assert(allowsOptionalArgs()); 66*700637cbSDimitry Andric return numRequired; 67*700637cbSDimitry Andric } 68*700637cbSDimitry Andric }; 69*700637cbSDimitry Andric 70*700637cbSDimitry Andric // The TrailingObjects for this class contain the function return type in the 71*700637cbSDimitry Andric // first CanQualType slot, followed by the argument types. 72*700637cbSDimitry Andric class CIRGenFunctionInfo final 73*700637cbSDimitry Andric : public llvm::FoldingSetNode, 74*700637cbSDimitry Andric private llvm::TrailingObjects<CIRGenFunctionInfo, CanQualType> { 75*700637cbSDimitry Andric RequiredArgs required; 76*700637cbSDimitry Andric 77*700637cbSDimitry Andric unsigned numArgs; 78*700637cbSDimitry Andric getArgTypes()79*700637cbSDimitry Andric CanQualType *getArgTypes() { return getTrailingObjects(); } getArgTypes()80*700637cbSDimitry Andric const CanQualType *getArgTypes() const { return getTrailingObjects(); } 81*700637cbSDimitry Andric CIRGenFunctionInfo()82*700637cbSDimitry Andric CIRGenFunctionInfo() : required(RequiredArgs::All) {} 83*700637cbSDimitry Andric 84*700637cbSDimitry Andric public: 85*700637cbSDimitry Andric static CIRGenFunctionInfo *create(CanQualType resultType, 86*700637cbSDimitry Andric llvm::ArrayRef<CanQualType> argTypes, 87*700637cbSDimitry Andric RequiredArgs required); 88*700637cbSDimitry Andric delete(void * p)89*700637cbSDimitry Andric void operator delete(void *p) { ::operator delete(p); } 90*700637cbSDimitry Andric 91*700637cbSDimitry Andric // Friending class TrailingObjects is apparantly not good enough for MSVC, so 92*700637cbSDimitry Andric // these have to be public. 93*700637cbSDimitry Andric friend class TrailingObjects; 94*700637cbSDimitry Andric 95*700637cbSDimitry Andric using const_arg_iterator = const CanQualType *; 96*700637cbSDimitry Andric using arg_iterator = CanQualType *; 97*700637cbSDimitry Andric 98*700637cbSDimitry Andric // This function has to be CamelCase because llvm::FoldingSet requires so. 99*700637cbSDimitry Andric // NOLINTNEXTLINE(readability-identifier-naming) Profile(llvm::FoldingSetNodeID & id,RequiredArgs required,CanQualType resultType,llvm::ArrayRef<CanQualType> argTypes)100*700637cbSDimitry Andric static void Profile(llvm::FoldingSetNodeID &id, RequiredArgs required, 101*700637cbSDimitry Andric CanQualType resultType, 102*700637cbSDimitry Andric llvm::ArrayRef<CanQualType> argTypes) { 103*700637cbSDimitry Andric id.AddBoolean(required.getOpaqueData()); 104*700637cbSDimitry Andric resultType.Profile(id); 105*700637cbSDimitry Andric for (const CanQualType &arg : argTypes) 106*700637cbSDimitry Andric arg.Profile(id); 107*700637cbSDimitry Andric } 108*700637cbSDimitry Andric 109*700637cbSDimitry Andric // NOLINTNEXTLINE(readability-identifier-naming) Profile(llvm::FoldingSetNodeID & id)110*700637cbSDimitry Andric void Profile(llvm::FoldingSetNodeID &id) { 111*700637cbSDimitry Andric // If the Profile functions get out of sync, we can end up with incorrect 112*700637cbSDimitry Andric // function signatures, so we call the static Profile function here rather 113*700637cbSDimitry Andric // than duplicating the logic. 114*700637cbSDimitry Andric Profile(id, required, getReturnType(), arguments()); 115*700637cbSDimitry Andric } 116*700637cbSDimitry Andric arguments()117*700637cbSDimitry Andric llvm::ArrayRef<CanQualType> arguments() const { 118*700637cbSDimitry Andric return llvm::ArrayRef<CanQualType>(argTypesBegin(), numArgs); 119*700637cbSDimitry Andric } 120*700637cbSDimitry Andric requiredArguments()121*700637cbSDimitry Andric llvm::ArrayRef<CanQualType> requiredArguments() const { 122*700637cbSDimitry Andric return llvm::ArrayRef<CanQualType>(argTypesBegin(), getNumRequiredArgs()); 123*700637cbSDimitry Andric } 124*700637cbSDimitry Andric getReturnType()125*700637cbSDimitry Andric CanQualType getReturnType() const { return getArgTypes()[0]; } 126*700637cbSDimitry Andric argTypesBegin()127*700637cbSDimitry Andric const_arg_iterator argTypesBegin() const { return getArgTypes() + 1; } argTypesEnd()128*700637cbSDimitry Andric const_arg_iterator argTypesEnd() const { return getArgTypes() + 1 + numArgs; } argTypesBegin()129*700637cbSDimitry Andric arg_iterator argTypesBegin() { return getArgTypes() + 1; } argTypesEnd()130*700637cbSDimitry Andric arg_iterator argTypesEnd() { return getArgTypes() + 1 + numArgs; } 131*700637cbSDimitry Andric argTypeSize()132*700637cbSDimitry Andric unsigned argTypeSize() const { return numArgs; } 133*700637cbSDimitry Andric argTypes()134*700637cbSDimitry Andric llvm::MutableArrayRef<CanQualType> argTypes() { 135*700637cbSDimitry Andric return llvm::MutableArrayRef<CanQualType>(argTypesBegin(), numArgs); 136*700637cbSDimitry Andric } argTypes()137*700637cbSDimitry Andric llvm::ArrayRef<CanQualType> argTypes() const { 138*700637cbSDimitry Andric return llvm::ArrayRef<CanQualType>(argTypesBegin(), numArgs); 139*700637cbSDimitry Andric } 140*700637cbSDimitry Andric isVariadic()141*700637cbSDimitry Andric bool isVariadic() const { return required.allowsOptionalArgs(); } getRequiredArgs()142*700637cbSDimitry Andric RequiredArgs getRequiredArgs() const { return required; } getNumRequiredArgs()143*700637cbSDimitry Andric unsigned getNumRequiredArgs() const { 144*700637cbSDimitry Andric return isVariadic() ? getRequiredArgs().getNumRequiredArgs() 145*700637cbSDimitry Andric : argTypeSize(); 146*700637cbSDimitry Andric } 147*700637cbSDimitry Andric }; 148*700637cbSDimitry Andric 149*700637cbSDimitry Andric } // namespace clang::CIRGen 150*700637cbSDimitry Andric 151*700637cbSDimitry Andric #endif 152