1*700637cbSDimitry Andric //===----------------------------------------------------------------------===// 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 // These classes wrap the information about a call or function 10*700637cbSDimitry Andric // definition used to handle ABI compliancy. 11*700637cbSDimitry Andric // 12*700637cbSDimitry Andric //===----------------------------------------------------------------------===// 13*700637cbSDimitry Andric 14*700637cbSDimitry Andric #ifndef CLANG_LIB_CODEGEN_CIRGENCALL_H 15*700637cbSDimitry Andric #define CLANG_LIB_CODEGEN_CIRGENCALL_H 16*700637cbSDimitry Andric 17*700637cbSDimitry Andric #include "CIRGenValue.h" 18*700637cbSDimitry Andric #include "mlir/IR/Operation.h" 19*700637cbSDimitry Andric #include "clang/AST/GlobalDecl.h" 20*700637cbSDimitry Andric #include "llvm/ADT/SmallVector.h" 21*700637cbSDimitry Andric 22*700637cbSDimitry Andric namespace clang::CIRGen { 23*700637cbSDimitry Andric 24*700637cbSDimitry Andric class CIRGenFunction; 25*700637cbSDimitry Andric 26*700637cbSDimitry Andric /// Abstract information about a function or function prototype. 27*700637cbSDimitry Andric class CIRGenCalleeInfo { 28*700637cbSDimitry Andric const clang::FunctionProtoType *calleeProtoTy; 29*700637cbSDimitry Andric clang::GlobalDecl calleeDecl; 30*700637cbSDimitry Andric 31*700637cbSDimitry Andric public: CIRGenCalleeInfo()32*700637cbSDimitry Andric explicit CIRGenCalleeInfo() : calleeProtoTy(nullptr), calleeDecl() {} CIRGenCalleeInfo(const clang::FunctionProtoType * calleeProtoTy,clang::GlobalDecl calleeDecl)33*700637cbSDimitry Andric CIRGenCalleeInfo(const clang::FunctionProtoType *calleeProtoTy, 34*700637cbSDimitry Andric clang::GlobalDecl calleeDecl) 35*700637cbSDimitry Andric : calleeProtoTy(calleeProtoTy), calleeDecl(calleeDecl) {} CIRGenCalleeInfo(clang::GlobalDecl calleeDecl)36*700637cbSDimitry Andric CIRGenCalleeInfo(clang::GlobalDecl calleeDecl) 37*700637cbSDimitry Andric : calleeProtoTy(nullptr), calleeDecl(calleeDecl) {} 38*700637cbSDimitry Andric getCalleeFunctionProtoType()39*700637cbSDimitry Andric const clang::FunctionProtoType *getCalleeFunctionProtoType() const { 40*700637cbSDimitry Andric return calleeProtoTy; 41*700637cbSDimitry Andric } getCalleeDecl()42*700637cbSDimitry Andric clang::GlobalDecl getCalleeDecl() const { return calleeDecl; } 43*700637cbSDimitry Andric }; 44*700637cbSDimitry Andric 45*700637cbSDimitry Andric class CIRGenCallee { 46*700637cbSDimitry Andric enum class SpecialKind : uintptr_t { 47*700637cbSDimitry Andric Invalid, 48*700637cbSDimitry Andric Builtin, 49*700637cbSDimitry Andric 50*700637cbSDimitry Andric Last = Builtin, 51*700637cbSDimitry Andric }; 52*700637cbSDimitry Andric 53*700637cbSDimitry Andric struct BuiltinInfoStorage { 54*700637cbSDimitry Andric const clang::FunctionDecl *decl; 55*700637cbSDimitry Andric unsigned id; 56*700637cbSDimitry Andric }; 57*700637cbSDimitry Andric 58*700637cbSDimitry Andric SpecialKind kindOrFunctionPtr; 59*700637cbSDimitry Andric 60*700637cbSDimitry Andric union { 61*700637cbSDimitry Andric CIRGenCalleeInfo abstractInfo; 62*700637cbSDimitry Andric BuiltinInfoStorage builtinInfo; 63*700637cbSDimitry Andric }; 64*700637cbSDimitry Andric CIRGenCallee(SpecialKind kind)65*700637cbSDimitry Andric explicit CIRGenCallee(SpecialKind kind) : kindOrFunctionPtr(kind) {} 66*700637cbSDimitry Andric 67*700637cbSDimitry Andric public: CIRGenCallee()68*700637cbSDimitry Andric CIRGenCallee() : kindOrFunctionPtr(SpecialKind::Invalid) {} 69*700637cbSDimitry Andric CIRGenCallee(const CIRGenCalleeInfo & abstractInfo,mlir::Operation * funcPtr)70*700637cbSDimitry Andric CIRGenCallee(const CIRGenCalleeInfo &abstractInfo, mlir::Operation *funcPtr) 71*700637cbSDimitry Andric : kindOrFunctionPtr(SpecialKind(reinterpret_cast<uintptr_t>(funcPtr))), 72*700637cbSDimitry Andric abstractInfo(abstractInfo) { 73*700637cbSDimitry Andric assert(funcPtr && "configuring callee without function pointer"); 74*700637cbSDimitry Andric } 75*700637cbSDimitry Andric 76*700637cbSDimitry Andric static CIRGenCallee 77*700637cbSDimitry Andric forDirect(mlir::Operation *funcPtr, 78*700637cbSDimitry Andric const CIRGenCalleeInfo &abstractInfo = CIRGenCalleeInfo()) { 79*700637cbSDimitry Andric return CIRGenCallee(abstractInfo, funcPtr); 80*700637cbSDimitry Andric } 81*700637cbSDimitry Andric isBuiltin()82*700637cbSDimitry Andric bool isBuiltin() const { return kindOrFunctionPtr == SpecialKind::Builtin; } 83*700637cbSDimitry Andric getBuiltinDecl()84*700637cbSDimitry Andric const clang::FunctionDecl *getBuiltinDecl() const { 85*700637cbSDimitry Andric assert(isBuiltin()); 86*700637cbSDimitry Andric return builtinInfo.decl; 87*700637cbSDimitry Andric } getBuiltinID()88*700637cbSDimitry Andric unsigned getBuiltinID() const { 89*700637cbSDimitry Andric assert(isBuiltin()); 90*700637cbSDimitry Andric return builtinInfo.id; 91*700637cbSDimitry Andric } 92*700637cbSDimitry Andric forBuiltin(unsigned builtinID,const clang::FunctionDecl * builtinDecl)93*700637cbSDimitry Andric static CIRGenCallee forBuiltin(unsigned builtinID, 94*700637cbSDimitry Andric const clang::FunctionDecl *builtinDecl) { 95*700637cbSDimitry Andric CIRGenCallee result(SpecialKind::Builtin); 96*700637cbSDimitry Andric result.builtinInfo.decl = builtinDecl; 97*700637cbSDimitry Andric result.builtinInfo.id = builtinID; 98*700637cbSDimitry Andric return result; 99*700637cbSDimitry Andric } 100*700637cbSDimitry Andric isOrdinary()101*700637cbSDimitry Andric bool isOrdinary() const { 102*700637cbSDimitry Andric return uintptr_t(kindOrFunctionPtr) > uintptr_t(SpecialKind::Last); 103*700637cbSDimitry Andric } 104*700637cbSDimitry Andric 105*700637cbSDimitry Andric /// If this is a delayed callee computation of some sort, prepare a concrete 106*700637cbSDimitry Andric /// callee 107*700637cbSDimitry Andric CIRGenCallee prepareConcreteCallee(CIRGenFunction &cgf) const; 108*700637cbSDimitry Andric getAbstractInfo()109*700637cbSDimitry Andric CIRGenCalleeInfo getAbstractInfo() const { 110*700637cbSDimitry Andric assert(!cir::MissingFeatures::opCallVirtual()); 111*700637cbSDimitry Andric assert(isOrdinary()); 112*700637cbSDimitry Andric return abstractInfo; 113*700637cbSDimitry Andric } 114*700637cbSDimitry Andric getFunctionPointer()115*700637cbSDimitry Andric mlir::Operation *getFunctionPointer() const { 116*700637cbSDimitry Andric assert(isOrdinary()); 117*700637cbSDimitry Andric return reinterpret_cast<mlir::Operation *>(kindOrFunctionPtr); 118*700637cbSDimitry Andric } 119*700637cbSDimitry Andric }; 120*700637cbSDimitry Andric 121*700637cbSDimitry Andric /// Type for representing both the decl and type of parameters to a function. 122*700637cbSDimitry Andric /// The decl must be either a ParmVarDecl or ImplicitParamDecl. 123*700637cbSDimitry Andric class FunctionArgList : public llvm::SmallVector<const clang::VarDecl *, 16> {}; 124*700637cbSDimitry Andric 125*700637cbSDimitry Andric struct CallArg { 126*700637cbSDimitry Andric private: 127*700637cbSDimitry Andric union { 128*700637cbSDimitry Andric RValue rv; 129*700637cbSDimitry Andric LValue lv; // This argument is semantically a load from this l-value 130*700637cbSDimitry Andric }; 131*700637cbSDimitry Andric bool hasLV; 132*700637cbSDimitry Andric 133*700637cbSDimitry Andric /// A data-flow flag to make sure getRValue and/or copyInto are not 134*700637cbSDimitry Andric /// called twice for duplicated IR emission. 135*700637cbSDimitry Andric mutable bool isUsed; 136*700637cbSDimitry Andric 137*700637cbSDimitry Andric public: 138*700637cbSDimitry Andric clang::QualType ty; 139*700637cbSDimitry Andric CallArgCallArg140*700637cbSDimitry Andric CallArg(RValue rv, clang::QualType ty) 141*700637cbSDimitry Andric : rv(rv), hasLV(false), isUsed(false), ty(ty) {} 142*700637cbSDimitry Andric CallArgCallArg143*700637cbSDimitry Andric CallArg(LValue lv, clang::QualType ty) 144*700637cbSDimitry Andric : lv(lv), hasLV(true), isUsed(false), ty(ty) {} 145*700637cbSDimitry Andric hasLValueCallArg146*700637cbSDimitry Andric bool hasLValue() const { return hasLV; } 147*700637cbSDimitry Andric getKnownLValueCallArg148*700637cbSDimitry Andric LValue getKnownLValue() const { 149*700637cbSDimitry Andric assert(hasLV && !isUsed); 150*700637cbSDimitry Andric return lv; 151*700637cbSDimitry Andric } 152*700637cbSDimitry Andric getKnownRValueCallArg153*700637cbSDimitry Andric RValue getKnownRValue() const { 154*700637cbSDimitry Andric assert(!hasLV && !isUsed); 155*700637cbSDimitry Andric return rv; 156*700637cbSDimitry Andric } 157*700637cbSDimitry Andric isAggregateCallArg158*700637cbSDimitry Andric bool isAggregate() const { return hasLV || rv.isAggregate(); } 159*700637cbSDimitry Andric }; 160*700637cbSDimitry Andric 161*700637cbSDimitry Andric class CallArgList : public llvm::SmallVector<CallArg, 8> { 162*700637cbSDimitry Andric public: add(RValue rvalue,clang::QualType type)163*700637cbSDimitry Andric void add(RValue rvalue, clang::QualType type) { emplace_back(rvalue, type); } 164*700637cbSDimitry Andric addUncopiedAggregate(LValue lvalue,clang::QualType type)165*700637cbSDimitry Andric void addUncopiedAggregate(LValue lvalue, clang::QualType type) { 166*700637cbSDimitry Andric emplace_back(lvalue, type); 167*700637cbSDimitry Andric } 168*700637cbSDimitry Andric 169*700637cbSDimitry Andric /// Add all the arguments from another CallArgList to this one. After doing 170*700637cbSDimitry Andric /// this, the old CallArgList retains its list of arguments, but must not 171*700637cbSDimitry Andric /// be used to emit a call. addFrom(const CallArgList & other)172*700637cbSDimitry Andric void addFrom(const CallArgList &other) { 173*700637cbSDimitry Andric insert(end(), other.begin(), other.end()); 174*700637cbSDimitry Andric // Classic codegen has handling for these here. We may not need it here for 175*700637cbSDimitry Andric // CIR, but if not we should implement equivalent handling in lowering. 176*700637cbSDimitry Andric assert(!cir::MissingFeatures::writebacks()); 177*700637cbSDimitry Andric assert(!cir::MissingFeatures::cleanupsToDeactivate()); 178*700637cbSDimitry Andric assert(!cir::MissingFeatures::stackBase()); 179*700637cbSDimitry Andric } 180*700637cbSDimitry Andric }; 181*700637cbSDimitry Andric 182*700637cbSDimitry Andric /// Contains the address where the return value of a function can be stored, and 183*700637cbSDimitry Andric /// whether the address is volatile or not. 184*700637cbSDimitry Andric class ReturnValueSlot { 185*700637cbSDimitry Andric Address addr = Address::invalid(); 186*700637cbSDimitry Andric 187*700637cbSDimitry Andric public: 188*700637cbSDimitry Andric ReturnValueSlot() = default; ReturnValueSlot(Address addr)189*700637cbSDimitry Andric ReturnValueSlot(Address addr) : addr(addr) {} 190*700637cbSDimitry Andric getValue()191*700637cbSDimitry Andric Address getValue() const { return addr; } 192*700637cbSDimitry Andric }; 193*700637cbSDimitry Andric 194*700637cbSDimitry Andric } // namespace clang::CIRGen 195*700637cbSDimitry Andric 196*700637cbSDimitry Andric #endif // CLANG_LIB_CODEGEN_CIRGENCALL_H 197