10b57cec5SDimitry Andric //===-- Address.h - An aligned address -------------------------*- C++ -*-===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This class provides a simple wrapper for a pair of a pointer and an 100b57cec5SDimitry Andric // alignment. 110b57cec5SDimitry Andric // 120b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 130b57cec5SDimitry Andric 140b57cec5SDimitry Andric #ifndef LLVM_CLANG_LIB_CODEGEN_ADDRESS_H 150b57cec5SDimitry Andric #define LLVM_CLANG_LIB_CODEGEN_ADDRESS_H 160b57cec5SDimitry Andric 17*0fca6ea1SDimitry Andric #include "CGPointerAuthInfo.h" 180b57cec5SDimitry Andric #include "clang/AST/CharUnits.h" 19*0fca6ea1SDimitry Andric #include "clang/AST/Type.h" 2004eeddc0SDimitry Andric #include "llvm/ADT/PointerIntPair.h" 2104eeddc0SDimitry Andric #include "llvm/IR/Constants.h" 2204eeddc0SDimitry Andric #include "llvm/Support/MathExtras.h" 230b57cec5SDimitry Andric 240b57cec5SDimitry Andric namespace clang { 250b57cec5SDimitry Andric namespace CodeGen { 260b57cec5SDimitry Andric 27*0fca6ea1SDimitry Andric class Address; 28*0fca6ea1SDimitry Andric class CGBuilderTy; 29*0fca6ea1SDimitry Andric class CodeGenFunction; 30*0fca6ea1SDimitry Andric class CodeGenModule; 31*0fca6ea1SDimitry Andric 3206c3fb27SDimitry Andric // Indicates whether a pointer is known not to be null. 3306c3fb27SDimitry Andric enum KnownNonNull_t { NotKnownNonNull, KnownNonNull }; 3404eeddc0SDimitry Andric 35*0fca6ea1SDimitry Andric /// An abstract representation of an aligned address. This is designed to be an 36*0fca6ea1SDimitry Andric /// IR-level abstraction, carrying just the information necessary to perform IR 37*0fca6ea1SDimitry Andric /// operations on an address like loads and stores. In particular, it doesn't 38*0fca6ea1SDimitry Andric /// carry C type information or allow the representation of things like 39*0fca6ea1SDimitry Andric /// bit-fields; clients working at that level should generally be using 40*0fca6ea1SDimitry Andric /// `LValue`. 41*0fca6ea1SDimitry Andric /// The pointer contained in this class is known to be unsigned. 42*0fca6ea1SDimitry Andric class RawAddress { 4306c3fb27SDimitry Andric llvm::PointerIntPair<llvm::Value *, 1, bool> PointerAndKnownNonNull; 4406c3fb27SDimitry Andric llvm::Type *ElementType; 4506c3fb27SDimitry Andric CharUnits Alignment; 4604eeddc0SDimitry Andric 4704eeddc0SDimitry Andric protected: 48*0fca6ea1SDimitry Andric RawAddress(std::nullptr_t) : ElementType(nullptr) {} 4904eeddc0SDimitry Andric 5004eeddc0SDimitry Andric public: 51*0fca6ea1SDimitry Andric RawAddress(llvm::Value *Pointer, llvm::Type *ElementType, CharUnits Alignment, 5206c3fb27SDimitry Andric KnownNonNull_t IsKnownNonNull = NotKnownNonNull) 5306c3fb27SDimitry Andric : PointerAndKnownNonNull(Pointer, IsKnownNonNull), 5406c3fb27SDimitry Andric ElementType(ElementType), Alignment(Alignment) { 5504eeddc0SDimitry Andric assert(Pointer != nullptr && "Pointer cannot be null"); 5604eeddc0SDimitry Andric assert(ElementType != nullptr && "Element type cannot be null"); 570b57cec5SDimitry Andric } 580b57cec5SDimitry Andric 59*0fca6ea1SDimitry Andric inline RawAddress(Address Addr); 60*0fca6ea1SDimitry Andric 61*0fca6ea1SDimitry Andric static RawAddress invalid() { return RawAddress(nullptr); } 6206c3fb27SDimitry Andric bool isValid() const { 6306c3fb27SDimitry Andric return PointerAndKnownNonNull.getPointer() != nullptr; 6406c3fb27SDimitry Andric } 650b57cec5SDimitry Andric 660b57cec5SDimitry Andric llvm::Value *getPointer() const { 670b57cec5SDimitry Andric assert(isValid()); 6806c3fb27SDimitry Andric return PointerAndKnownNonNull.getPointer(); 690b57cec5SDimitry Andric } 700b57cec5SDimitry Andric 710b57cec5SDimitry Andric /// Return the type of the pointer value. 720b57cec5SDimitry Andric llvm::PointerType *getType() const { 730b57cec5SDimitry Andric return llvm::cast<llvm::PointerType>(getPointer()->getType()); 740b57cec5SDimitry Andric } 750b57cec5SDimitry Andric 760b57cec5SDimitry Andric /// Return the type of the values stored in this address. 770b57cec5SDimitry Andric llvm::Type *getElementType() const { 780eae32dcSDimitry Andric assert(isValid()); 7906c3fb27SDimitry Andric return ElementType; 800b57cec5SDimitry Andric } 810b57cec5SDimitry Andric 820b57cec5SDimitry Andric /// Return the address space that this address resides in. 830b57cec5SDimitry Andric unsigned getAddressSpace() const { 840b57cec5SDimitry Andric return getType()->getAddressSpace(); 850b57cec5SDimitry Andric } 860b57cec5SDimitry Andric 870b57cec5SDimitry Andric /// Return the IR name of the pointer value. 880b57cec5SDimitry Andric llvm::StringRef getName() const { 890b57cec5SDimitry Andric return getPointer()->getName(); 900b57cec5SDimitry Andric } 910b57cec5SDimitry Andric 920b57cec5SDimitry Andric /// Return the alignment of this pointer. 930b57cec5SDimitry Andric CharUnits getAlignment() const { 940b57cec5SDimitry Andric assert(isValid()); 9506c3fb27SDimitry Andric return Alignment; 960b57cec5SDimitry Andric } 970eae32dcSDimitry Andric 98*0fca6ea1SDimitry Andric /// Return address with different element type, but same pointer and 99*0fca6ea1SDimitry Andric /// alignment. 100*0fca6ea1SDimitry Andric RawAddress withElementType(llvm::Type *ElemTy) const { 101*0fca6ea1SDimitry Andric return RawAddress(getPointer(), ElemTy, getAlignment(), isKnownNonNull()); 102*0fca6ea1SDimitry Andric } 103*0fca6ea1SDimitry Andric 104*0fca6ea1SDimitry Andric KnownNonNull_t isKnownNonNull() const { 105*0fca6ea1SDimitry Andric assert(isValid()); 106*0fca6ea1SDimitry Andric return (KnownNonNull_t)PointerAndKnownNonNull.getInt(); 107*0fca6ea1SDimitry Andric } 108*0fca6ea1SDimitry Andric }; 109*0fca6ea1SDimitry Andric 110*0fca6ea1SDimitry Andric /// Like RawAddress, an abstract representation of an aligned address, but the 111*0fca6ea1SDimitry Andric /// pointer contained in this class is possibly signed. 112*0fca6ea1SDimitry Andric /// 113*0fca6ea1SDimitry Andric /// This is designed to be an IR-level abstraction, carrying just the 114*0fca6ea1SDimitry Andric /// information necessary to perform IR operations on an address like loads and 115*0fca6ea1SDimitry Andric /// stores. In particular, it doesn't carry C type information or allow the 116*0fca6ea1SDimitry Andric /// representation of things like bit-fields; clients working at that level 117*0fca6ea1SDimitry Andric /// should generally be using `LValue`. 118*0fca6ea1SDimitry Andric /// 119*0fca6ea1SDimitry Andric /// An address may be either *raw*, meaning that it's an ordinary machine 120*0fca6ea1SDimitry Andric /// pointer, or *signed*, meaning that the pointer carries an embedded 121*0fca6ea1SDimitry Andric /// pointer-authentication signature. Representing signed pointers directly in 122*0fca6ea1SDimitry Andric /// this abstraction allows the authentication to be delayed as long as possible 123*0fca6ea1SDimitry Andric /// without forcing IRGen to use totally different code paths for signed and 124*0fca6ea1SDimitry Andric /// unsigned values or to separately propagate signature information through 125*0fca6ea1SDimitry Andric /// every API that manipulates addresses. Pointer arithmetic on signed addresses 126*0fca6ea1SDimitry Andric /// (e.g. drilling down to a struct field) is accumulated into a separate offset 127*0fca6ea1SDimitry Andric /// which is applied when the address is finally accessed. 128*0fca6ea1SDimitry Andric class Address { 129*0fca6ea1SDimitry Andric friend class CGBuilderTy; 130*0fca6ea1SDimitry Andric 131*0fca6ea1SDimitry Andric // The boolean flag indicates whether the pointer is known to be non-null. 132*0fca6ea1SDimitry Andric llvm::PointerIntPair<llvm::Value *, 1, bool> Pointer; 133*0fca6ea1SDimitry Andric 134*0fca6ea1SDimitry Andric /// The expected IR type of the pointer. Carrying accurate element type 135*0fca6ea1SDimitry Andric /// information in Address makes it more convenient to work with Address 136*0fca6ea1SDimitry Andric /// values and allows frontend assertions to catch simple mistakes. 137*0fca6ea1SDimitry Andric llvm::Type *ElementType = nullptr; 138*0fca6ea1SDimitry Andric 139*0fca6ea1SDimitry Andric CharUnits Alignment; 140*0fca6ea1SDimitry Andric 141*0fca6ea1SDimitry Andric /// The ptrauth information needed to authenticate the base pointer. 142*0fca6ea1SDimitry Andric CGPointerAuthInfo PtrAuthInfo; 143*0fca6ea1SDimitry Andric 144*0fca6ea1SDimitry Andric /// Offset from the base pointer. This is non-null only when the base 145*0fca6ea1SDimitry Andric /// pointer is signed. 146*0fca6ea1SDimitry Andric llvm::Value *Offset = nullptr; 147*0fca6ea1SDimitry Andric 148*0fca6ea1SDimitry Andric llvm::Value *emitRawPointerSlow(CodeGenFunction &CGF) const; 149*0fca6ea1SDimitry Andric 150*0fca6ea1SDimitry Andric protected: 151*0fca6ea1SDimitry Andric Address(std::nullptr_t) : ElementType(nullptr) {} 152*0fca6ea1SDimitry Andric 153*0fca6ea1SDimitry Andric public: 154*0fca6ea1SDimitry Andric Address(llvm::Value *pointer, llvm::Type *elementType, CharUnits alignment, 155*0fca6ea1SDimitry Andric KnownNonNull_t IsKnownNonNull = NotKnownNonNull) 156*0fca6ea1SDimitry Andric : Pointer(pointer, IsKnownNonNull), ElementType(elementType), 157*0fca6ea1SDimitry Andric Alignment(alignment) { 158*0fca6ea1SDimitry Andric assert(pointer != nullptr && "Pointer cannot be null"); 159*0fca6ea1SDimitry Andric assert(elementType != nullptr && "Element type cannot be null"); 160*0fca6ea1SDimitry Andric assert(!alignment.isZero() && "Alignment cannot be zero"); 161*0fca6ea1SDimitry Andric } 162*0fca6ea1SDimitry Andric 163*0fca6ea1SDimitry Andric Address(llvm::Value *BasePtr, llvm::Type *ElementType, CharUnits Alignment, 164*0fca6ea1SDimitry Andric CGPointerAuthInfo PtrAuthInfo, llvm::Value *Offset, 165*0fca6ea1SDimitry Andric KnownNonNull_t IsKnownNonNull = NotKnownNonNull) 166*0fca6ea1SDimitry Andric : Pointer(BasePtr, IsKnownNonNull), ElementType(ElementType), 167*0fca6ea1SDimitry Andric Alignment(Alignment), PtrAuthInfo(PtrAuthInfo), Offset(Offset) {} 168*0fca6ea1SDimitry Andric 169*0fca6ea1SDimitry Andric Address(RawAddress RawAddr) 170*0fca6ea1SDimitry Andric : Pointer(RawAddr.isValid() ? RawAddr.getPointer() : nullptr, 171*0fca6ea1SDimitry Andric RawAddr.isValid() ? RawAddr.isKnownNonNull() : NotKnownNonNull), 172*0fca6ea1SDimitry Andric ElementType(RawAddr.isValid() ? RawAddr.getElementType() : nullptr), 173*0fca6ea1SDimitry Andric Alignment(RawAddr.isValid() ? RawAddr.getAlignment() 174*0fca6ea1SDimitry Andric : CharUnits::Zero()) {} 175*0fca6ea1SDimitry Andric 176*0fca6ea1SDimitry Andric static Address invalid() { return Address(nullptr); } 177*0fca6ea1SDimitry Andric bool isValid() const { return Pointer.getPointer() != nullptr; } 178*0fca6ea1SDimitry Andric 179*0fca6ea1SDimitry Andric /// This function is used in situations where the caller is doing some sort of 180*0fca6ea1SDimitry Andric /// opaque "laundering" of the pointer. 181*0fca6ea1SDimitry Andric void replaceBasePointer(llvm::Value *P) { 182*0fca6ea1SDimitry Andric assert(isValid() && "pointer isn't valid"); 183*0fca6ea1SDimitry Andric assert(P->getType() == Pointer.getPointer()->getType() && 184*0fca6ea1SDimitry Andric "Pointer's type changed"); 185*0fca6ea1SDimitry Andric Pointer.setPointer(P); 186*0fca6ea1SDimitry Andric assert(isValid() && "pointer is invalid after replacement"); 187*0fca6ea1SDimitry Andric } 188*0fca6ea1SDimitry Andric 189*0fca6ea1SDimitry Andric CharUnits getAlignment() const { return Alignment; } 190*0fca6ea1SDimitry Andric 191*0fca6ea1SDimitry Andric void setAlignment(CharUnits Value) { Alignment = Value; } 192*0fca6ea1SDimitry Andric 193*0fca6ea1SDimitry Andric llvm::Value *getBasePointer() const { 194*0fca6ea1SDimitry Andric assert(isValid() && "pointer isn't valid"); 195*0fca6ea1SDimitry Andric return Pointer.getPointer(); 196*0fca6ea1SDimitry Andric } 197*0fca6ea1SDimitry Andric 198*0fca6ea1SDimitry Andric /// Return the type of the pointer value. 199*0fca6ea1SDimitry Andric llvm::PointerType *getType() const { 200*0fca6ea1SDimitry Andric return llvm::PointerType::get( 201*0fca6ea1SDimitry Andric ElementType, 202*0fca6ea1SDimitry Andric llvm::cast<llvm::PointerType>(Pointer.getPointer()->getType()) 203*0fca6ea1SDimitry Andric ->getAddressSpace()); 204*0fca6ea1SDimitry Andric } 205*0fca6ea1SDimitry Andric 206*0fca6ea1SDimitry Andric /// Return the type of the values stored in this address. 207*0fca6ea1SDimitry Andric llvm::Type *getElementType() const { 208*0fca6ea1SDimitry Andric assert(isValid()); 209*0fca6ea1SDimitry Andric return ElementType; 210*0fca6ea1SDimitry Andric } 211*0fca6ea1SDimitry Andric 212*0fca6ea1SDimitry Andric /// Return the address space that this address resides in. 213*0fca6ea1SDimitry Andric unsigned getAddressSpace() const { return getType()->getAddressSpace(); } 214*0fca6ea1SDimitry Andric 215*0fca6ea1SDimitry Andric /// Return the IR name of the pointer value. 216*0fca6ea1SDimitry Andric llvm::StringRef getName() const { return Pointer.getPointer()->getName(); } 217*0fca6ea1SDimitry Andric 218*0fca6ea1SDimitry Andric const CGPointerAuthInfo &getPointerAuthInfo() const { return PtrAuthInfo; } 219*0fca6ea1SDimitry Andric void setPointerAuthInfo(const CGPointerAuthInfo &Info) { PtrAuthInfo = Info; } 220*0fca6ea1SDimitry Andric 221*0fca6ea1SDimitry Andric // This function is called only in CGBuilderBaseTy::CreateElementBitCast. 222*0fca6ea1SDimitry Andric void setElementType(llvm::Type *Ty) { 223*0fca6ea1SDimitry Andric assert(hasOffset() && 224*0fca6ea1SDimitry Andric "this funcion shouldn't be called when there is no offset"); 225*0fca6ea1SDimitry Andric ElementType = Ty; 226*0fca6ea1SDimitry Andric } 227*0fca6ea1SDimitry Andric 228*0fca6ea1SDimitry Andric bool isSigned() const { return PtrAuthInfo.isSigned(); } 229*0fca6ea1SDimitry Andric 230*0fca6ea1SDimitry Andric /// Whether the pointer is known not to be null. 231*0fca6ea1SDimitry Andric KnownNonNull_t isKnownNonNull() const { 232*0fca6ea1SDimitry Andric assert(isValid()); 233*0fca6ea1SDimitry Andric return (KnownNonNull_t)Pointer.getInt(); 234*0fca6ea1SDimitry Andric } 235*0fca6ea1SDimitry Andric 236*0fca6ea1SDimitry Andric Address setKnownNonNull() { 237*0fca6ea1SDimitry Andric assert(isValid()); 238*0fca6ea1SDimitry Andric Pointer.setInt(KnownNonNull); 239*0fca6ea1SDimitry Andric return *this; 240*0fca6ea1SDimitry Andric } 241*0fca6ea1SDimitry Andric 242*0fca6ea1SDimitry Andric bool hasOffset() const { return Offset; } 243*0fca6ea1SDimitry Andric 244*0fca6ea1SDimitry Andric llvm::Value *getOffset() const { return Offset; } 245*0fca6ea1SDimitry Andric 246*0fca6ea1SDimitry Andric Address getResignedAddress(const CGPointerAuthInfo &NewInfo, 247*0fca6ea1SDimitry Andric CodeGenFunction &CGF) const; 248*0fca6ea1SDimitry Andric 249*0fca6ea1SDimitry Andric /// Return the pointer contained in this class after authenticating it and 250*0fca6ea1SDimitry Andric /// adding offset to it if necessary. 251*0fca6ea1SDimitry Andric llvm::Value *emitRawPointer(CodeGenFunction &CGF) const { 252*0fca6ea1SDimitry Andric if (!isSigned()) 253*0fca6ea1SDimitry Andric return getBasePointer(); 254*0fca6ea1SDimitry Andric return emitRawPointerSlow(CGF); 255*0fca6ea1SDimitry Andric } 256*0fca6ea1SDimitry Andric 2570eae32dcSDimitry Andric /// Return address with different pointer, but same element type and 2580eae32dcSDimitry Andric /// alignment. 25906c3fb27SDimitry Andric Address withPointer(llvm::Value *NewPointer, 26006c3fb27SDimitry Andric KnownNonNull_t IsKnownNonNull) const { 26106c3fb27SDimitry Andric return Address(NewPointer, getElementType(), getAlignment(), 26206c3fb27SDimitry Andric IsKnownNonNull); 2630eae32dcSDimitry Andric } 2640eae32dcSDimitry Andric 2650eae32dcSDimitry Andric /// Return address with different alignment, but same pointer and element 2660eae32dcSDimitry Andric /// type. 2670eae32dcSDimitry Andric Address withAlignment(CharUnits NewAlignment) const { 268*0fca6ea1SDimitry Andric return Address(Pointer.getPointer(), getElementType(), NewAlignment, 26906c3fb27SDimitry Andric isKnownNonNull()); 27006c3fb27SDimitry Andric } 27106c3fb27SDimitry Andric 27206c3fb27SDimitry Andric /// Return address with different element type, but same pointer and 27306c3fb27SDimitry Andric /// alignment. 27406c3fb27SDimitry Andric Address withElementType(llvm::Type *ElemTy) const { 275*0fca6ea1SDimitry Andric if (!hasOffset()) 276*0fca6ea1SDimitry Andric return Address(getBasePointer(), ElemTy, getAlignment(), 277*0fca6ea1SDimitry Andric getPointerAuthInfo(), /*Offset=*/nullptr, 278*0fca6ea1SDimitry Andric isKnownNonNull()); 279*0fca6ea1SDimitry Andric Address A(*this); 280*0fca6ea1SDimitry Andric A.ElementType = ElemTy; 281*0fca6ea1SDimitry Andric return A; 2820eae32dcSDimitry Andric } 2830b57cec5SDimitry Andric }; 2840b57cec5SDimitry Andric 285*0fca6ea1SDimitry Andric inline RawAddress::RawAddress(Address Addr) 286*0fca6ea1SDimitry Andric : PointerAndKnownNonNull(Addr.isValid() ? Addr.getBasePointer() : nullptr, 287*0fca6ea1SDimitry Andric Addr.isValid() ? Addr.isKnownNonNull() 288*0fca6ea1SDimitry Andric : NotKnownNonNull), 289*0fca6ea1SDimitry Andric ElementType(Addr.isValid() ? Addr.getElementType() : nullptr), 290*0fca6ea1SDimitry Andric Alignment(Addr.isValid() ? Addr.getAlignment() : CharUnits::Zero()) {} 291*0fca6ea1SDimitry Andric 2920b57cec5SDimitry Andric /// A specialization of Address that requires the address to be an 2930b57cec5SDimitry Andric /// LLVM Constant. 294*0fca6ea1SDimitry Andric class ConstantAddress : public RawAddress { 295*0fca6ea1SDimitry Andric ConstantAddress(std::nullptr_t) : RawAddress(nullptr) {} 2960eae32dcSDimitry Andric 2970b57cec5SDimitry Andric public: 2980eae32dcSDimitry Andric ConstantAddress(llvm::Constant *pointer, llvm::Type *elementType, 2990eae32dcSDimitry Andric CharUnits alignment) 300*0fca6ea1SDimitry Andric : RawAddress(pointer, elementType, alignment) {} 3010b57cec5SDimitry Andric 3020b57cec5SDimitry Andric static ConstantAddress invalid() { 3030eae32dcSDimitry Andric return ConstantAddress(nullptr); 3040b57cec5SDimitry Andric } 3050b57cec5SDimitry Andric 3060b57cec5SDimitry Andric llvm::Constant *getPointer() const { 307*0fca6ea1SDimitry Andric return llvm::cast<llvm::Constant>(RawAddress::getPointer()); 3080b57cec5SDimitry Andric } 3090b57cec5SDimitry Andric 31006c3fb27SDimitry Andric ConstantAddress withElementType(llvm::Type *ElemTy) const { 31106c3fb27SDimitry Andric return ConstantAddress(getPointer(), ElemTy, getAlignment()); 3120b57cec5SDimitry Andric } 3130b57cec5SDimitry Andric 314*0fca6ea1SDimitry Andric static bool isaImpl(RawAddress addr) { 3150b57cec5SDimitry Andric return llvm::isa<llvm::Constant>(addr.getPointer()); 3160b57cec5SDimitry Andric } 317*0fca6ea1SDimitry Andric static ConstantAddress castImpl(RawAddress addr) { 3180b57cec5SDimitry Andric return ConstantAddress(llvm::cast<llvm::Constant>(addr.getPointer()), 3190eae32dcSDimitry Andric addr.getElementType(), addr.getAlignment()); 3200b57cec5SDimitry Andric } 3210b57cec5SDimitry Andric }; 3220b57cec5SDimitry Andric } 3230b57cec5SDimitry Andric 3240b57cec5SDimitry Andric // Present a minimal LLVM-like casting interface. 3250b57cec5SDimitry Andric template <class U> inline U cast(CodeGen::Address addr) { 3260b57cec5SDimitry Andric return U::castImpl(addr); 3270b57cec5SDimitry Andric } 3280b57cec5SDimitry Andric template <class U> inline bool isa(CodeGen::Address addr) { 3290b57cec5SDimitry Andric return U::isaImpl(addr); 3300b57cec5SDimitry Andric } 3310b57cec5SDimitry Andric 3320b57cec5SDimitry Andric } 3330b57cec5SDimitry Andric 3340b57cec5SDimitry Andric #endif 335