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