|  | //===----- CGCall.h - Encapsulate calling convention details ----*- C++ -*-===// | 
|  | // | 
|  | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | 
|  | // See https://llvm.org/LICENSE.txt for license information. | 
|  | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  | // | 
|  | // These classes wrap the information about a call or function | 
|  | // definition used to handle ABI compliancy. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #ifndef LLVM_CLANG_LIB_CODEGEN_CGCALL_H | 
|  | #define LLVM_CLANG_LIB_CODEGEN_CGCALL_H | 
|  |  | 
|  | #include "CGValue.h" | 
|  | #include "EHScopeStack.h" | 
|  | #include "clang/AST/CanonicalType.h" | 
|  | #include "clang/AST/GlobalDecl.h" | 
|  | #include "clang/AST/Type.h" | 
|  | #include "llvm/IR/Value.h" | 
|  |  | 
|  | // FIXME: Restructure so we don't have to expose so much stuff. | 
|  | #include "ABIInfo.h" | 
|  |  | 
|  | namespace llvm { | 
|  | class AttributeList; | 
|  | class Function; | 
|  | class Type; | 
|  | class Value; | 
|  | } // namespace llvm | 
|  |  | 
|  | namespace clang { | 
|  | class ASTContext; | 
|  | class Decl; | 
|  | class FunctionDecl; | 
|  | class ObjCMethodDecl; | 
|  | class VarDecl; | 
|  |  | 
|  | namespace CodeGen { | 
|  |  | 
|  | /// Abstract information about a function or function prototype. | 
|  | class CGCalleeInfo { | 
|  | /// The function prototype of the callee. | 
|  | const FunctionProtoType *CalleeProtoTy; | 
|  | /// The function declaration of the callee. | 
|  | GlobalDecl CalleeDecl; | 
|  |  | 
|  | public: | 
|  | explicit CGCalleeInfo() : CalleeProtoTy(nullptr), CalleeDecl() {} | 
|  | CGCalleeInfo(const FunctionProtoType *calleeProtoTy, GlobalDecl calleeDecl) | 
|  | : CalleeProtoTy(calleeProtoTy), CalleeDecl(calleeDecl) {} | 
|  | CGCalleeInfo(const FunctionProtoType *calleeProtoTy) | 
|  | : CalleeProtoTy(calleeProtoTy), CalleeDecl() {} | 
|  | CGCalleeInfo(GlobalDecl calleeDecl) | 
|  | : CalleeProtoTy(nullptr), CalleeDecl(calleeDecl) {} | 
|  |  | 
|  | const FunctionProtoType *getCalleeFunctionProtoType() const { | 
|  | return CalleeProtoTy; | 
|  | } | 
|  | const GlobalDecl getCalleeDecl() const { return CalleeDecl; } | 
|  | }; | 
|  |  | 
|  | /// All available information about a concrete callee. | 
|  | class CGCallee { | 
|  | enum class SpecialKind : uintptr_t { | 
|  | Invalid, | 
|  | Builtin, | 
|  | PseudoDestructor, | 
|  | Virtual, | 
|  |  | 
|  | Last = Virtual | 
|  | }; | 
|  |  | 
|  | struct BuiltinInfoStorage { | 
|  | const FunctionDecl *Decl; | 
|  | unsigned ID; | 
|  | }; | 
|  | struct PseudoDestructorInfoStorage { | 
|  | const CXXPseudoDestructorExpr *Expr; | 
|  | }; | 
|  | struct VirtualInfoStorage { | 
|  | const CallExpr *CE; | 
|  | GlobalDecl MD; | 
|  | Address Addr; | 
|  | llvm::FunctionType *FTy; | 
|  | }; | 
|  |  | 
|  | SpecialKind KindOrFunctionPointer; | 
|  | union { | 
|  | CGCalleeInfo AbstractInfo; | 
|  | BuiltinInfoStorage BuiltinInfo; | 
|  | PseudoDestructorInfoStorage PseudoDestructorInfo; | 
|  | VirtualInfoStorage VirtualInfo; | 
|  | }; | 
|  |  | 
|  | explicit CGCallee(SpecialKind kind) : KindOrFunctionPointer(kind) {} | 
|  |  | 
|  | CGCallee(const FunctionDecl *builtinDecl, unsigned builtinID) | 
|  | : KindOrFunctionPointer(SpecialKind::Builtin) { | 
|  | BuiltinInfo.Decl = builtinDecl; | 
|  | BuiltinInfo.ID = builtinID; | 
|  | } | 
|  |  | 
|  | public: | 
|  | CGCallee() : KindOrFunctionPointer(SpecialKind::Invalid) {} | 
|  |  | 
|  | /// Construct a callee.  Call this constructor directly when this | 
|  | /// isn't a direct call. | 
|  | CGCallee(const CGCalleeInfo &abstractInfo, llvm::Value *functionPtr) | 
|  | : KindOrFunctionPointer(SpecialKind(uintptr_t(functionPtr))) { | 
|  | AbstractInfo = abstractInfo; | 
|  | assert(functionPtr && "configuring callee without function pointer"); | 
|  | assert(functionPtr->getType()->isPointerTy()); | 
|  | assert(functionPtr->getType()->getPointerElementType()->isFunctionTy()); | 
|  | } | 
|  |  | 
|  | static CGCallee forBuiltin(unsigned builtinID, | 
|  | const FunctionDecl *builtinDecl) { | 
|  | CGCallee result(SpecialKind::Builtin); | 
|  | result.BuiltinInfo.Decl = builtinDecl; | 
|  | result.BuiltinInfo.ID = builtinID; | 
|  | return result; | 
|  | } | 
|  |  | 
|  | static CGCallee forPseudoDestructor(const CXXPseudoDestructorExpr *E) { | 
|  | CGCallee result(SpecialKind::PseudoDestructor); | 
|  | result.PseudoDestructorInfo.Expr = E; | 
|  | return result; | 
|  | } | 
|  |  | 
|  | static CGCallee forDirect(llvm::Constant *functionPtr, | 
|  | const CGCalleeInfo &abstractInfo = CGCalleeInfo()) { | 
|  | return CGCallee(abstractInfo, functionPtr); | 
|  | } | 
|  |  | 
|  | static CGCallee forDirect(llvm::FunctionCallee functionPtr, | 
|  | const CGCalleeInfo &abstractInfo = CGCalleeInfo()) { | 
|  | return CGCallee(abstractInfo, functionPtr.getCallee()); | 
|  | } | 
|  |  | 
|  | static CGCallee forVirtual(const CallExpr *CE, GlobalDecl MD, Address Addr, | 
|  | llvm::FunctionType *FTy) { | 
|  | CGCallee result(SpecialKind::Virtual); | 
|  | result.VirtualInfo.CE = CE; | 
|  | result.VirtualInfo.MD = MD; | 
|  | result.VirtualInfo.Addr = Addr; | 
|  | result.VirtualInfo.FTy = FTy; | 
|  | return result; | 
|  | } | 
|  |  | 
|  | bool isBuiltin() const { | 
|  | return KindOrFunctionPointer == SpecialKind::Builtin; | 
|  | } | 
|  | const FunctionDecl *getBuiltinDecl() const { | 
|  | assert(isBuiltin()); | 
|  | return BuiltinInfo.Decl; | 
|  | } | 
|  | unsigned getBuiltinID() const { | 
|  | assert(isBuiltin()); | 
|  | return BuiltinInfo.ID; | 
|  | } | 
|  |  | 
|  | bool isPseudoDestructor() const { | 
|  | return KindOrFunctionPointer == SpecialKind::PseudoDestructor; | 
|  | } | 
|  | const CXXPseudoDestructorExpr *getPseudoDestructorExpr() const { | 
|  | assert(isPseudoDestructor()); | 
|  | return PseudoDestructorInfo.Expr; | 
|  | } | 
|  |  | 
|  | bool isOrdinary() const { | 
|  | return uintptr_t(KindOrFunctionPointer) > uintptr_t(SpecialKind::Last); | 
|  | } | 
|  | CGCalleeInfo getAbstractInfo() const { | 
|  | if (isVirtual()) | 
|  | return VirtualInfo.MD; | 
|  | assert(isOrdinary()); | 
|  | return AbstractInfo; | 
|  | } | 
|  | llvm::Value *getFunctionPointer() const { | 
|  | assert(isOrdinary()); | 
|  | return reinterpret_cast<llvm::Value *>(uintptr_t(KindOrFunctionPointer)); | 
|  | } | 
|  | void setFunctionPointer(llvm::Value *functionPtr) { | 
|  | assert(isOrdinary()); | 
|  | KindOrFunctionPointer = SpecialKind(uintptr_t(functionPtr)); | 
|  | } | 
|  |  | 
|  | bool isVirtual() const { | 
|  | return KindOrFunctionPointer == SpecialKind::Virtual; | 
|  | } | 
|  | const CallExpr *getVirtualCallExpr() const { | 
|  | assert(isVirtual()); | 
|  | return VirtualInfo.CE; | 
|  | } | 
|  | GlobalDecl getVirtualMethodDecl() const { | 
|  | assert(isVirtual()); | 
|  | return VirtualInfo.MD; | 
|  | } | 
|  | Address getThisAddress() const { | 
|  | assert(isVirtual()); | 
|  | return VirtualInfo.Addr; | 
|  | } | 
|  | llvm::FunctionType *getVirtualFunctionType() const { | 
|  | assert(isVirtual()); | 
|  | return VirtualInfo.FTy; | 
|  | } | 
|  |  | 
|  | /// If this is a delayed callee computation of some sort, prepare | 
|  | /// a concrete callee. | 
|  | CGCallee prepareConcreteCallee(CodeGenFunction &CGF) const; | 
|  | }; | 
|  |  | 
|  | struct CallArg { | 
|  | private: | 
|  | union { | 
|  | RValue RV; | 
|  | LValue LV; /// The argument is semantically a load from this l-value. | 
|  | }; | 
|  | bool HasLV; | 
|  |  | 
|  | /// A data-flow flag to make sure getRValue and/or copyInto are not | 
|  | /// called twice for duplicated IR emission. | 
|  | mutable bool IsUsed; | 
|  |  | 
|  | public: | 
|  | QualType Ty; | 
|  | CallArg(RValue rv, QualType ty) | 
|  | : RV(rv), HasLV(false), IsUsed(false), Ty(ty) {} | 
|  | CallArg(LValue lv, QualType ty) | 
|  | : LV(lv), HasLV(true), IsUsed(false), Ty(ty) {} | 
|  | bool hasLValue() const { return HasLV; } | 
|  | QualType getType() const { return Ty; } | 
|  |  | 
|  | /// \returns an independent RValue. If the CallArg contains an LValue, | 
|  | /// a temporary copy is returned. | 
|  | RValue getRValue(CodeGenFunction &CGF) const; | 
|  |  | 
|  | LValue getKnownLValue() const { | 
|  | assert(HasLV && !IsUsed); | 
|  | return LV; | 
|  | } | 
|  | RValue getKnownRValue() const { | 
|  | assert(!HasLV && !IsUsed); | 
|  | return RV; | 
|  | } | 
|  | void setRValue(RValue _RV) { | 
|  | assert(!HasLV); | 
|  | RV = _RV; | 
|  | } | 
|  |  | 
|  | bool isAggregate() const { return HasLV || RV.isAggregate(); } | 
|  |  | 
|  | void copyInto(CodeGenFunction &CGF, Address A) const; | 
|  | }; | 
|  |  | 
|  | /// CallArgList - Type for representing both the value and type of | 
|  | /// arguments in a call. | 
|  | class CallArgList : public SmallVector<CallArg, 8> { | 
|  | public: | 
|  | CallArgList() : StackBase(nullptr) {} | 
|  |  | 
|  | struct Writeback { | 
|  | /// The original argument.  Note that the argument l-value | 
|  | /// is potentially null. | 
|  | LValue Source; | 
|  |  | 
|  | /// The temporary alloca. | 
|  | Address Temporary; | 
|  |  | 
|  | /// A value to "use" after the writeback, or null. | 
|  | llvm::Value *ToUse; | 
|  | }; | 
|  |  | 
|  | struct CallArgCleanup { | 
|  | EHScopeStack::stable_iterator Cleanup; | 
|  |  | 
|  | /// The "is active" insertion point.  This instruction is temporary and | 
|  | /// will be removed after insertion. | 
|  | llvm::Instruction *IsActiveIP; | 
|  | }; | 
|  |  | 
|  | void add(RValue rvalue, QualType type) { push_back(CallArg(rvalue, type)); } | 
|  |  | 
|  | void addUncopiedAggregate(LValue LV, QualType type) { | 
|  | push_back(CallArg(LV, type)); | 
|  | } | 
|  |  | 
|  | /// Add all the arguments from another CallArgList to this one. After doing | 
|  | /// this, the old CallArgList retains its list of arguments, but must not | 
|  | /// be used to emit a call. | 
|  | void addFrom(const CallArgList &other) { | 
|  | insert(end(), other.begin(), other.end()); | 
|  | Writebacks.insert(Writebacks.end(), other.Writebacks.begin(), | 
|  | other.Writebacks.end()); | 
|  | CleanupsToDeactivate.insert(CleanupsToDeactivate.end(), | 
|  | other.CleanupsToDeactivate.begin(), | 
|  | other.CleanupsToDeactivate.end()); | 
|  | assert(!(StackBase && other.StackBase) && "can't merge stackbases"); | 
|  | if (!StackBase) | 
|  | StackBase = other.StackBase; | 
|  | } | 
|  |  | 
|  | void addWriteback(LValue srcLV, Address temporary, llvm::Value *toUse) { | 
|  | Writeback writeback = {srcLV, temporary, toUse}; | 
|  | Writebacks.push_back(writeback); | 
|  | } | 
|  |  | 
|  | bool hasWritebacks() const { return !Writebacks.empty(); } | 
|  |  | 
|  | typedef llvm::iterator_range<SmallVectorImpl<Writeback>::const_iterator> | 
|  | writeback_const_range; | 
|  |  | 
|  | writeback_const_range writebacks() const { | 
|  | return writeback_const_range(Writebacks.begin(), Writebacks.end()); | 
|  | } | 
|  |  | 
|  | void addArgCleanupDeactivation(EHScopeStack::stable_iterator Cleanup, | 
|  | llvm::Instruction *IsActiveIP) { | 
|  | CallArgCleanup ArgCleanup; | 
|  | ArgCleanup.Cleanup = Cleanup; | 
|  | ArgCleanup.IsActiveIP = IsActiveIP; | 
|  | CleanupsToDeactivate.push_back(ArgCleanup); | 
|  | } | 
|  |  | 
|  | ArrayRef<CallArgCleanup> getCleanupsToDeactivate() const { | 
|  | return CleanupsToDeactivate; | 
|  | } | 
|  |  | 
|  | void allocateArgumentMemory(CodeGenFunction &CGF); | 
|  | llvm::Instruction *getStackBase() const { return StackBase; } | 
|  | void freeArgumentMemory(CodeGenFunction &CGF) const; | 
|  |  | 
|  | /// Returns if we're using an inalloca struct to pass arguments in | 
|  | /// memory. | 
|  | bool isUsingInAlloca() const { return StackBase; } | 
|  |  | 
|  | private: | 
|  | SmallVector<Writeback, 1> Writebacks; | 
|  |  | 
|  | /// Deactivate these cleanups immediately before making the call.  This | 
|  | /// is used to cleanup objects that are owned by the callee once the call | 
|  | /// occurs. | 
|  | SmallVector<CallArgCleanup, 1> CleanupsToDeactivate; | 
|  |  | 
|  | /// The stacksave call.  It dominates all of the argument evaluation. | 
|  | llvm::CallInst *StackBase; | 
|  | }; | 
|  |  | 
|  | /// FunctionArgList - Type for representing both the decl and type | 
|  | /// of parameters to a function. The decl must be either a | 
|  | /// ParmVarDecl or ImplicitParamDecl. | 
|  | class FunctionArgList : public SmallVector<const VarDecl *, 16> {}; | 
|  |  | 
|  | /// ReturnValueSlot - Contains the address where the return value of a | 
|  | /// function can be stored, and whether the address is volatile or not. | 
|  | class ReturnValueSlot { | 
|  | llvm::PointerIntPair<llvm::Value *, 2, unsigned int> Value; | 
|  | CharUnits Alignment; | 
|  |  | 
|  | // Return value slot flags | 
|  | enum Flags { | 
|  | IS_VOLATILE = 0x1, | 
|  | IS_UNUSED = 0x2, | 
|  | }; | 
|  |  | 
|  | public: | 
|  | ReturnValueSlot() {} | 
|  | ReturnValueSlot(Address Addr, bool IsVolatile, bool IsUnused = false) | 
|  | : Value(Addr.isValid() ? Addr.getPointer() : nullptr, | 
|  | (IsVolatile ? IS_VOLATILE : 0) | (IsUnused ? IS_UNUSED : 0)), | 
|  | Alignment(Addr.isValid() ? Addr.getAlignment() : CharUnits::Zero()) {} | 
|  |  | 
|  | bool isNull() const { return !getValue().isValid(); } | 
|  |  | 
|  | bool isVolatile() const { return Value.getInt() & IS_VOLATILE; } | 
|  | Address getValue() const { return Address(Value.getPointer(), Alignment); } | 
|  | bool isUnused() const { return Value.getInt() & IS_UNUSED; } | 
|  | }; | 
|  |  | 
|  | } // end namespace CodeGen | 
|  | } // end namespace clang | 
|  |  | 
|  | #endif |