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