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