xref: /freebsd/contrib/llvm-project/clang/lib/CIR/CodeGen/CIRGenCall.h (revision 700637cbb5e582861067a11aaca4d053546871d2)
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