//==-- CIRGenFunctionInfo.h - Representation of fn argument/return types ---==// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // Defines CIRGenFunctionInfo and associated types used in representing the // CIR source types and ABI-coerced types for function arguments and // return values. // //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_CIR_CIRGENFUNCTIONINFO_H #define LLVM_CLANG_CIR_CIRGENFUNCTIONINFO_H #include "clang/AST/CanonicalType.h" #include "clang/CIR/MissingFeatures.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/Support/TrailingObjects.h" namespace clang::CIRGen { /// A class for recording the number of arguments that a function signature /// requires. class RequiredArgs { /// The number of required arguments, or ~0 if the signature does not permit /// optional arguments. unsigned numRequired; public: enum All_t { All }; RequiredArgs(All_t _) : numRequired(~0U) {} explicit RequiredArgs(unsigned n) : numRequired(n) { assert(n != ~0U); } unsigned getOpaqueData() const { return numRequired; } bool allowsOptionalArgs() const { return numRequired != ~0U; } /// Compute the arguments required by the given formal prototype, given that /// there may be some additional, non-formal arguments in play. /// /// If FD is not null, this will consider pass_object_size params in FD. static RequiredArgs getFromProtoWithExtraSlots(const clang::FunctionProtoType *prototype, unsigned additional) { if (!prototype->isVariadic()) return All; if (prototype->hasExtParameterInfos()) llvm_unreachable("NYI"); return RequiredArgs(prototype->getNumParams() + additional); } static RequiredArgs getFromProtoWithExtraSlots(clang::CanQual prototype, unsigned additional) { return getFromProtoWithExtraSlots(prototype.getTypePtr(), additional); } unsigned getNumRequiredArgs() const { assert(allowsOptionalArgs()); return numRequired; } }; // The TrailingObjects for this class contain the function return type in the // first CanQualType slot, followed by the argument types. class CIRGenFunctionInfo final : public llvm::FoldingSetNode, private llvm::TrailingObjects { RequiredArgs required; unsigned numArgs; CanQualType *getArgTypes() { return getTrailingObjects(); } const CanQualType *getArgTypes() const { return getTrailingObjects(); } CIRGenFunctionInfo() : required(RequiredArgs::All) {} public: static CIRGenFunctionInfo *create(CanQualType resultType, llvm::ArrayRef argTypes, RequiredArgs required); void operator delete(void *p) { ::operator delete(p); } // Friending class TrailingObjects is apparantly not good enough for MSVC, so // these have to be public. friend class TrailingObjects; using const_arg_iterator = const CanQualType *; using arg_iterator = CanQualType *; // This function has to be CamelCase because llvm::FoldingSet requires so. // NOLINTNEXTLINE(readability-identifier-naming) static void Profile(llvm::FoldingSetNodeID &id, RequiredArgs required, CanQualType resultType, llvm::ArrayRef argTypes) { id.AddBoolean(required.getOpaqueData()); resultType.Profile(id); for (const CanQualType &arg : argTypes) arg.Profile(id); } // NOLINTNEXTLINE(readability-identifier-naming) void Profile(llvm::FoldingSetNodeID &id) { // If the Profile functions get out of sync, we can end up with incorrect // function signatures, so we call the static Profile function here rather // than duplicating the logic. Profile(id, required, getReturnType(), arguments()); } llvm::ArrayRef arguments() const { return llvm::ArrayRef(argTypesBegin(), numArgs); } llvm::ArrayRef requiredArguments() const { return llvm::ArrayRef(argTypesBegin(), getNumRequiredArgs()); } CanQualType getReturnType() const { return getArgTypes()[0]; } const_arg_iterator argTypesBegin() const { return getArgTypes() + 1; } const_arg_iterator argTypesEnd() const { return getArgTypes() + 1 + numArgs; } arg_iterator argTypesBegin() { return getArgTypes() + 1; } arg_iterator argTypesEnd() { return getArgTypes() + 1 + numArgs; } unsigned argTypeSize() const { return numArgs; } llvm::MutableArrayRef argTypes() { return llvm::MutableArrayRef(argTypesBegin(), numArgs); } llvm::ArrayRef argTypes() const { return llvm::ArrayRef(argTypesBegin(), numArgs); } bool isVariadic() const { return required.allowsOptionalArgs(); } RequiredArgs getRequiredArgs() const { return required; } unsigned getNumRequiredArgs() const { return isVariadic() ? getRequiredArgs().getNumRequiredArgs() : argTypeSize(); } }; } // namespace clang::CIRGen #endif