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: |
32 | explicit CIRGenCalleeInfo() : calleeProtoTy(nullptr), calleeDecl() {} |
33 | CIRGenCalleeInfo(const clang::FunctionProtoType *calleeProtoTy, |
34 | clang::GlobalDecl calleeDecl) |
35 | : calleeProtoTy(calleeProtoTy), calleeDecl(calleeDecl) {} |
36 | CIRGenCalleeInfo(clang::GlobalDecl calleeDecl) : calleeDecl(calleeDecl) {} |
37 | |
38 | const clang::FunctionProtoType *getCalleeFunctionProtoType() const { |
39 | return calleeProtoTy; |
40 | } |
41 | clang::GlobalDecl getCalleeDecl() const { return calleeDecl; } |
42 | }; |
43 | |
44 | class CIRGenCallee { |
45 | enum class SpecialKind : uintptr_t { |
46 | Invalid, |
47 | Builtin, |
48 | |
49 | Last = Builtin, |
50 | }; |
51 | |
52 | struct BuiltinInfoStorage { |
53 | const clang::FunctionDecl *decl; |
54 | unsigned id; |
55 | }; |
56 | |
57 | SpecialKind kindOrFunctionPtr; |
58 | |
59 | union { |
60 | CIRGenCalleeInfo abstractInfo; |
61 | BuiltinInfoStorage builtinInfo; |
62 | }; |
63 | |
64 | explicit CIRGenCallee(SpecialKind kind) : kindOrFunctionPtr(kind) {} |
65 | |
66 | public: |
67 | CIRGenCallee() : kindOrFunctionPtr(SpecialKind::Invalid) {} |
68 | |
69 | CIRGenCallee(const CIRGenCalleeInfo &abstractInfo, mlir::Operation *funcPtr) |
70 | : kindOrFunctionPtr(SpecialKind(reinterpret_cast<uintptr_t>(funcPtr))), |
71 | abstractInfo(abstractInfo) { |
72 | assert(funcPtr && "configuring callee without function pointer" ); |
73 | } |
74 | |
75 | static CIRGenCallee |
76 | forDirect(mlir::Operation *funcPtr, |
77 | const CIRGenCalleeInfo &abstractInfo = CIRGenCalleeInfo()) { |
78 | return CIRGenCallee(abstractInfo, funcPtr); |
79 | } |
80 | |
81 | bool isBuiltin() const { return kindOrFunctionPtr == SpecialKind::Builtin; } |
82 | |
83 | const clang::FunctionDecl *getBuiltinDecl() const { |
84 | assert(isBuiltin()); |
85 | return builtinInfo.decl; |
86 | } |
87 | unsigned getBuiltinID() const { |
88 | assert(isBuiltin()); |
89 | return builtinInfo.id; |
90 | } |
91 | |
92 | static CIRGenCallee forBuiltin(unsigned builtinID, |
93 | const clang::FunctionDecl *builtinDecl) { |
94 | CIRGenCallee result(SpecialKind::Builtin); |
95 | result.builtinInfo.decl = builtinDecl; |
96 | result.builtinInfo.id = builtinID; |
97 | return result; |
98 | } |
99 | |
100 | bool isOrdinary() const { |
101 | return uintptr_t(kindOrFunctionPtr) > uintptr_t(SpecialKind::Last); |
102 | } |
103 | |
104 | /// If this is a delayed callee computation of some sort, prepare a concrete |
105 | /// callee |
106 | CIRGenCallee prepareConcreteCallee(CIRGenFunction &cgf) const; |
107 | |
108 | mlir::Operation *getFunctionPointer() const { |
109 | assert(isOrdinary()); |
110 | return reinterpret_cast<mlir::Operation *>(kindOrFunctionPtr); |
111 | } |
112 | }; |
113 | |
114 | /// Type for representing both the decl and type of parameters to a function. |
115 | /// The decl must be either a ParmVarDecl or ImplicitParamDecl. |
116 | class FunctionArgList : public llvm::SmallVector<const clang::VarDecl *, 16> {}; |
117 | |
118 | struct CallArg { |
119 | private: |
120 | union { |
121 | RValue rv; |
122 | LValue lv; // This argument is semantically a load from this l-value |
123 | }; |
124 | bool hasLV; |
125 | |
126 | /// A data-flow flag to make sure getRValue and/or copyInto are not |
127 | /// called twice for duplicated IR emission. |
128 | mutable bool isUsed; |
129 | |
130 | public: |
131 | clang::QualType ty; |
132 | |
133 | CallArg(RValue rv, clang::QualType ty) |
134 | : rv(rv), hasLV(false), isUsed(false), ty(ty) {} |
135 | |
136 | bool hasLValue() const { return hasLV; } |
137 | |
138 | RValue getKnownRValue() const { |
139 | assert(!hasLV && !isUsed); |
140 | return rv; |
141 | } |
142 | |
143 | bool isAggregate() const { return hasLV || rv.isAggregate(); } |
144 | }; |
145 | |
146 | class CallArgList : public llvm::SmallVector<CallArg, 8> { |
147 | public: |
148 | void add(RValue rvalue, clang::QualType type) { emplace_back(Args&: rvalue, Args&: type); } |
149 | |
150 | /// Add all the arguments from another CallArgList to this one. After doing |
151 | /// this, the old CallArgList retains its list of arguments, but must not |
152 | /// be used to emit a call. |
153 | void addFrom(const CallArgList &other) { |
154 | insert(I: end(), From: other.begin(), To: other.end()); |
155 | // Classic codegen has handling for these here. We may not need it here for |
156 | // CIR, but if not we should implement equivalent handling in lowering. |
157 | assert(!cir::MissingFeatures::writebacks()); |
158 | assert(!cir::MissingFeatures::cleanupsToDeactivate()); |
159 | assert(!cir::MissingFeatures::stackBase()); |
160 | } |
161 | }; |
162 | |
163 | /// Contains the address where the return value of a function can be stored, and |
164 | /// whether the address is volatile or not. |
165 | class ReturnValueSlot {}; |
166 | |
167 | } // namespace clang::CIRGen |
168 | |
169 | #endif // CLANG_LIB_CODEGEN_CIRGENCALL_H |
170 | |