1 //===-- Address.h - An aligned address -------------------------*- C++ -*-===// 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 // This class provides a simple wrapper for a pair of a pointer and an 10 // alignment. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #ifndef LLVM_CLANG_LIB_CODEGEN_ADDRESS_H 15 #define LLVM_CLANG_LIB_CODEGEN_ADDRESS_H 16 17 #include "CGPointerAuthInfo.h" 18 #include "clang/AST/CharUnits.h" 19 #include "clang/AST/Type.h" 20 #include "llvm/ADT/PointerIntPair.h" 21 #include "llvm/IR/Constants.h" 22 #include "llvm/Support/MathExtras.h" 23 24 namespace clang { 25 namespace CodeGen { 26 27 class Address; 28 class CGBuilderTy; 29 class CodeGenFunction; 30 class CodeGenModule; 31 32 // Indicates whether a pointer is known not to be null. 33 enum KnownNonNull_t { NotKnownNonNull, KnownNonNull }; 34 35 /// An abstract representation of an aligned address. This is designed to be an 36 /// IR-level abstraction, carrying just the information necessary to perform IR 37 /// operations on an address like loads and stores. In particular, it doesn't 38 /// carry C type information or allow the representation of things like 39 /// bit-fields; clients working at that level should generally be using 40 /// `LValue`. 41 /// The pointer contained in this class is known to be unsigned. 42 class RawAddress { 43 llvm::PointerIntPair<llvm::Value *, 1, bool> PointerAndKnownNonNull; 44 llvm::Type *ElementType; 45 CharUnits Alignment; 46 47 protected: 48 RawAddress(std::nullptr_t) : ElementType(nullptr) {} 49 50 public: 51 RawAddress(llvm::Value *Pointer, llvm::Type *ElementType, CharUnits Alignment, 52 KnownNonNull_t IsKnownNonNull = NotKnownNonNull) 53 : PointerAndKnownNonNull(Pointer, IsKnownNonNull), 54 ElementType(ElementType), Alignment(Alignment) { 55 assert(Pointer != nullptr && "Pointer cannot be null"); 56 assert(ElementType != nullptr && "Element type cannot be null"); 57 } 58 59 inline RawAddress(Address Addr); 60 61 static RawAddress invalid() { return RawAddress(nullptr); } 62 bool isValid() const { 63 return PointerAndKnownNonNull.getPointer() != nullptr; 64 } 65 66 llvm::Value *getPointer() const { 67 assert(isValid()); 68 return PointerAndKnownNonNull.getPointer(); 69 } 70 71 /// Return the type of the pointer value. 72 llvm::PointerType *getType() const { 73 return llvm::cast<llvm::PointerType>(getPointer()->getType()); 74 } 75 76 /// Return the type of the values stored in this address. 77 llvm::Type *getElementType() const { 78 assert(isValid()); 79 return ElementType; 80 } 81 82 /// Return the address space that this address resides in. 83 unsigned getAddressSpace() const { 84 return getType()->getAddressSpace(); 85 } 86 87 /// Return the IR name of the pointer value. 88 llvm::StringRef getName() const { 89 return getPointer()->getName(); 90 } 91 92 /// Return the alignment of this pointer. 93 CharUnits getAlignment() const { 94 assert(isValid()); 95 return Alignment; 96 } 97 98 /// Return address with different element type, but same pointer and 99 /// alignment. 100 RawAddress withElementType(llvm::Type *ElemTy) const { 101 return RawAddress(getPointer(), ElemTy, getAlignment(), isKnownNonNull()); 102 } 103 104 KnownNonNull_t isKnownNonNull() const { 105 assert(isValid()); 106 return (KnownNonNull_t)PointerAndKnownNonNull.getInt(); 107 } 108 }; 109 110 /// Like RawAddress, an abstract representation of an aligned address, but the 111 /// pointer contained in this class is possibly signed. 112 /// 113 /// This is designed to be an IR-level abstraction, carrying just the 114 /// information necessary to perform IR operations on an address like loads and 115 /// stores. In particular, it doesn't carry C type information or allow the 116 /// representation of things like bit-fields; clients working at that level 117 /// should generally be using `LValue`. 118 /// 119 /// An address may be either *raw*, meaning that it's an ordinary machine 120 /// pointer, or *signed*, meaning that the pointer carries an embedded 121 /// pointer-authentication signature. Representing signed pointers directly in 122 /// this abstraction allows the authentication to be delayed as long as possible 123 /// without forcing IRGen to use totally different code paths for signed and 124 /// unsigned values or to separately propagate signature information through 125 /// every API that manipulates addresses. Pointer arithmetic on signed addresses 126 /// (e.g. drilling down to a struct field) is accumulated into a separate offset 127 /// which is applied when the address is finally accessed. 128 class Address { 129 friend class CGBuilderTy; 130 131 // The boolean flag indicates whether the pointer is known to be non-null. 132 llvm::PointerIntPair<llvm::Value *, 1, bool> Pointer; 133 134 /// The expected IR type of the pointer. Carrying accurate element type 135 /// information in Address makes it more convenient to work with Address 136 /// values and allows frontend assertions to catch simple mistakes. 137 llvm::Type *ElementType = nullptr; 138 139 CharUnits Alignment; 140 141 /// The ptrauth information needed to authenticate the base pointer. 142 CGPointerAuthInfo PtrAuthInfo; 143 144 /// Offset from the base pointer. This is non-null only when the base 145 /// pointer is signed. 146 llvm::Value *Offset = nullptr; 147 148 llvm::Value *emitRawPointerSlow(CodeGenFunction &CGF) const; 149 150 protected: 151 Address(std::nullptr_t) : ElementType(nullptr) {} 152 153 public: 154 Address(llvm::Value *pointer, llvm::Type *elementType, CharUnits alignment, 155 KnownNonNull_t IsKnownNonNull = NotKnownNonNull) 156 : Pointer(pointer, IsKnownNonNull), ElementType(elementType), 157 Alignment(alignment) { 158 assert(pointer != nullptr && "Pointer cannot be null"); 159 assert(elementType != nullptr && "Element type cannot be null"); 160 assert(!alignment.isZero() && "Alignment cannot be zero"); 161 } 162 163 Address(llvm::Value *BasePtr, llvm::Type *ElementType, CharUnits Alignment, 164 CGPointerAuthInfo PtrAuthInfo, llvm::Value *Offset, 165 KnownNonNull_t IsKnownNonNull = NotKnownNonNull) 166 : Pointer(BasePtr, IsKnownNonNull), ElementType(ElementType), 167 Alignment(Alignment), PtrAuthInfo(PtrAuthInfo), Offset(Offset) {} 168 169 Address(RawAddress RawAddr) 170 : Pointer(RawAddr.isValid() ? RawAddr.getPointer() : nullptr, 171 RawAddr.isValid() ? RawAddr.isKnownNonNull() : NotKnownNonNull), 172 ElementType(RawAddr.isValid() ? RawAddr.getElementType() : nullptr), 173 Alignment(RawAddr.isValid() ? RawAddr.getAlignment() 174 : CharUnits::Zero()) {} 175 176 static Address invalid() { return Address(nullptr); } 177 bool isValid() const { return Pointer.getPointer() != nullptr; } 178 179 /// This function is used in situations where the caller is doing some sort of 180 /// opaque "laundering" of the pointer. 181 void replaceBasePointer(llvm::Value *P) { 182 assert(isValid() && "pointer isn't valid"); 183 assert(P->getType() == Pointer.getPointer()->getType() && 184 "Pointer's type changed"); 185 Pointer.setPointer(P); 186 assert(isValid() && "pointer is invalid after replacement"); 187 } 188 189 CharUnits getAlignment() const { return Alignment; } 190 191 void setAlignment(CharUnits Value) { Alignment = Value; } 192 193 llvm::Value *getBasePointer() const { 194 assert(isValid() && "pointer isn't valid"); 195 return Pointer.getPointer(); 196 } 197 198 /// Return the type of the pointer value. 199 llvm::PointerType *getType() const { 200 return llvm::PointerType::get( 201 ElementType, 202 llvm::cast<llvm::PointerType>(Pointer.getPointer()->getType()) 203 ->getAddressSpace()); 204 } 205 206 /// Return the type of the values stored in this address. 207 llvm::Type *getElementType() const { 208 assert(isValid()); 209 return ElementType; 210 } 211 212 /// Return the address space that this address resides in. 213 unsigned getAddressSpace() const { return getType()->getAddressSpace(); } 214 215 /// Return the IR name of the pointer value. 216 llvm::StringRef getName() const { return Pointer.getPointer()->getName(); } 217 218 const CGPointerAuthInfo &getPointerAuthInfo() const { return PtrAuthInfo; } 219 void setPointerAuthInfo(const CGPointerAuthInfo &Info) { PtrAuthInfo = Info; } 220 221 // This function is called only in CGBuilderBaseTy::CreateElementBitCast. 222 void setElementType(llvm::Type *Ty) { 223 assert(hasOffset() && 224 "this funcion shouldn't be called when there is no offset"); 225 ElementType = Ty; 226 } 227 228 bool isSigned() const { return PtrAuthInfo.isSigned(); } 229 230 /// Whether the pointer is known not to be null. 231 KnownNonNull_t isKnownNonNull() const { 232 assert(isValid()); 233 return (KnownNonNull_t)Pointer.getInt(); 234 } 235 236 Address setKnownNonNull() { 237 assert(isValid()); 238 Pointer.setInt(KnownNonNull); 239 return *this; 240 } 241 242 bool hasOffset() const { return Offset; } 243 244 llvm::Value *getOffset() const { return Offset; } 245 246 Address getResignedAddress(const CGPointerAuthInfo &NewInfo, 247 CodeGenFunction &CGF) const; 248 249 /// Return the pointer contained in this class after authenticating it and 250 /// adding offset to it if necessary. 251 llvm::Value *emitRawPointer(CodeGenFunction &CGF) const { 252 if (!isSigned()) 253 return getBasePointer(); 254 return emitRawPointerSlow(CGF); 255 } 256 257 /// Return address with different pointer, but same element type and 258 /// alignment. 259 Address withPointer(llvm::Value *NewPointer, 260 KnownNonNull_t IsKnownNonNull) const { 261 return Address(NewPointer, getElementType(), getAlignment(), 262 IsKnownNonNull); 263 } 264 265 /// Return address with different alignment, but same pointer and element 266 /// type. 267 Address withAlignment(CharUnits NewAlignment) const { 268 return Address(Pointer.getPointer(), getElementType(), NewAlignment, 269 isKnownNonNull()); 270 } 271 272 /// Return address with different element type, but same pointer and 273 /// alignment. 274 Address withElementType(llvm::Type *ElemTy) const { 275 if (!hasOffset()) 276 return Address(getBasePointer(), ElemTy, getAlignment(), 277 getPointerAuthInfo(), /*Offset=*/nullptr, 278 isKnownNonNull()); 279 Address A(*this); 280 A.ElementType = ElemTy; 281 return A; 282 } 283 }; 284 285 inline RawAddress::RawAddress(Address Addr) 286 : PointerAndKnownNonNull(Addr.isValid() ? Addr.getBasePointer() : nullptr, 287 Addr.isValid() ? Addr.isKnownNonNull() 288 : NotKnownNonNull), 289 ElementType(Addr.isValid() ? Addr.getElementType() : nullptr), 290 Alignment(Addr.isValid() ? Addr.getAlignment() : CharUnits::Zero()) {} 291 292 /// A specialization of Address that requires the address to be an 293 /// LLVM Constant. 294 class ConstantAddress : public RawAddress { 295 ConstantAddress(std::nullptr_t) : RawAddress(nullptr) {} 296 297 public: 298 ConstantAddress(llvm::Constant *pointer, llvm::Type *elementType, 299 CharUnits alignment) 300 : RawAddress(pointer, elementType, alignment) {} 301 302 static ConstantAddress invalid() { 303 return ConstantAddress(nullptr); 304 } 305 306 llvm::Constant *getPointer() const { 307 return llvm::cast<llvm::Constant>(RawAddress::getPointer()); 308 } 309 310 ConstantAddress withElementType(llvm::Type *ElemTy) const { 311 return ConstantAddress(getPointer(), ElemTy, getAlignment()); 312 } 313 314 static bool isaImpl(RawAddress addr) { 315 return llvm::isa<llvm::Constant>(addr.getPointer()); 316 } 317 static ConstantAddress castImpl(RawAddress addr) { 318 return ConstantAddress(llvm::cast<llvm::Constant>(addr.getPointer()), 319 addr.getElementType(), addr.getAlignment()); 320 } 321 }; 322 } 323 324 // Present a minimal LLVM-like casting interface. 325 template <class U> inline U cast(CodeGen::Address addr) { 326 return U::castImpl(addr); 327 } 328 template <class U> inline bool isa(CodeGen::Address addr) { 329 return U::isaImpl(addr); 330 } 331 332 } 333 334 #endif 335