337 lines · c
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-exception6//7//===----------------------------------------------------------------------===//8//9// This class provides a simple wrapper for a pair of a pointer and an10// alignment.11//12//===----------------------------------------------------------------------===//13 14#ifndef LLVM_CLANG_LIB_CODEGEN_ADDRESS_H15#define LLVM_CLANG_LIB_CODEGEN_ADDRESS_H16 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 24namespace clang {25namespace CodeGen {26 27class Address;28class CGBuilderTy;29class CodeGenFunction;30class CodeGenModule;31 32// Indicates whether a pointer is known not to be null.33enum KnownNonNull_t { NotKnownNonNull, KnownNonNull };34 35/// An abstract representation of an aligned address. This is designed to be an36/// IR-level abstraction, carrying just the information necessary to perform IR37/// operations on an address like loads and stores. In particular, it doesn't38/// carry C type information or allow the representation of things like39/// bit-fields; clients working at that level should generally be using40/// `LValue`.41/// The pointer contained in this class is known to be unsigned.42class RawAddress {43 llvm::PointerIntPair<llvm::Value *, 1, bool> PointerAndKnownNonNull;44 llvm::Type *ElementType;45 CharUnits Alignment;46 47protected:48 RawAddress(std::nullptr_t) : ElementType(nullptr) {}49 50public: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 and99 /// 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 the111/// pointer contained in this class is possibly signed.112///113/// This is designed to be an IR-level abstraction, carrying just the114/// information necessary to perform IR operations on an address like loads and115/// stores. In particular, it doesn't carry C type information or allow the116/// representation of things like bit-fields; clients working at that level117/// should generally be using `LValue`.118///119/// An address may be either *raw*, meaning that it's an ordinary machine120/// pointer, or *signed*, meaning that the pointer carries an embedded121/// pointer-authentication signature. Representing signed pointers directly in122/// this abstraction allows the authentication to be delayed as long as possible123/// without forcing IRGen to use totally different code paths for signed and124/// unsigned values or to separately propagate signature information through125/// every API that manipulates addresses. Pointer arithmetic on signed addresses126/// (e.g. drilling down to a struct field) is accumulated into a separate offset127/// which is applied when the address is finally accessed.128class 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 type135 /// information in Address makes it more convenient to work with Address136 /// 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 base145 /// pointer is signed.146 llvm::Value *Offset = nullptr;147 148 llvm::Value *emitRawPointerSlow(CodeGenFunction &CGF) const;149 150protected:151 Address(std::nullptr_t) : ElementType(nullptr) {}152 153public: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 llvm::Value *getPointerIfNotSigned() const {180 assert(isValid() && "pointer isn't valid");181 return !isSigned() ? Pointer.getPointer() : nullptr;182 }183 184 /// This function is used in situations where the caller is doing some sort of185 /// opaque "laundering" of the pointer.186 void replaceBasePointer(llvm::Value *P) {187 assert(isValid() && "pointer isn't valid");188 assert(P->getType() == Pointer.getPointer()->getType() &&189 "Pointer's type changed");190 Pointer.setPointer(P);191 assert(isValid() && "pointer is invalid after replacement");192 }193 194 CharUnits getAlignment() const { return Alignment; }195 196 void setAlignment(CharUnits Value) { Alignment = Value; }197 198 llvm::Value *getBasePointer() const {199 assert(isValid() && "pointer isn't valid");200 return Pointer.getPointer();201 }202 203 /// Return the type of the pointer value.204 llvm::PointerType *getType() const {205 return llvm::cast<llvm::PointerType>(Pointer.getPointer()->getType());206 }207 208 /// Return the type of the values stored in this address.209 llvm::Type *getElementType() const {210 assert(isValid());211 return ElementType;212 }213 214 /// Return the address space that this address resides in.215 unsigned getAddressSpace() const { return getType()->getAddressSpace(); }216 217 /// Return the IR name of the pointer value.218 llvm::StringRef getName() const { return Pointer.getPointer()->getName(); }219 220 const CGPointerAuthInfo &getPointerAuthInfo() const { return PtrAuthInfo; }221 void setPointerAuthInfo(const CGPointerAuthInfo &Info) { PtrAuthInfo = Info; }222 223 // This function is called only in CGBuilderBaseTy::CreateElementBitCast.224 void setElementType(llvm::Type *Ty) {225 assert(hasOffset() &&226 "this funcion shouldn't be called when there is no offset");227 ElementType = Ty;228 }229 230 bool isSigned() const { return PtrAuthInfo.isSigned(); }231 232 /// Whether the pointer is known not to be null.233 KnownNonNull_t isKnownNonNull() const {234 assert(isValid());235 return (KnownNonNull_t)Pointer.getInt();236 }237 238 Address setKnownNonNull() {239 assert(isValid());240 Pointer.setInt(KnownNonNull);241 return *this;242 }243 244 bool hasOffset() const { return Offset; }245 246 llvm::Value *getOffset() const { return Offset; }247 248 Address getResignedAddress(const CGPointerAuthInfo &NewInfo,249 CodeGenFunction &CGF) const;250 251 /// Return the pointer contained in this class after authenticating it and252 /// adding offset to it if necessary.253 llvm::Value *emitRawPointer(CodeGenFunction &CGF) const {254 if (!isSigned())255 return getBasePointer();256 return emitRawPointerSlow(CGF);257 }258 259 /// Return address with different pointer, but same element type and260 /// alignment.261 Address withPointer(llvm::Value *NewPointer,262 KnownNonNull_t IsKnownNonNull) const {263 return Address(NewPointer, getElementType(), getAlignment(),264 IsKnownNonNull);265 }266 267 /// Return address with different alignment, but same pointer and element268 /// type.269 Address withAlignment(CharUnits NewAlignment) const {270 return Address(Pointer.getPointer(), getElementType(), NewAlignment,271 isKnownNonNull());272 }273 274 /// Return address with different element type, but same pointer and275 /// alignment.276 Address withElementType(llvm::Type *ElemTy) const {277 if (!hasOffset())278 return Address(getBasePointer(), ElemTy, getAlignment(),279 getPointerAuthInfo(), /*Offset=*/nullptr,280 isKnownNonNull());281 Address A(*this);282 A.ElementType = ElemTy;283 return A;284 }285};286 287inline RawAddress::RawAddress(Address Addr)288 : PointerAndKnownNonNull(Addr.isValid() ? Addr.getBasePointer() : nullptr,289 Addr.isValid() ? Addr.isKnownNonNull()290 : NotKnownNonNull),291 ElementType(Addr.isValid() ? Addr.getElementType() : nullptr),292 Alignment(Addr.isValid() ? Addr.getAlignment() : CharUnits::Zero()) {}293 294/// A specialization of Address that requires the address to be an295/// LLVM Constant.296class ConstantAddress : public RawAddress {297 ConstantAddress(std::nullptr_t) : RawAddress(nullptr) {}298 299public:300 ConstantAddress(llvm::Constant *pointer, llvm::Type *elementType,301 CharUnits alignment)302 : RawAddress(pointer, elementType, alignment) {}303 304 static ConstantAddress invalid() {305 return ConstantAddress(nullptr);306 }307 308 llvm::Constant *getPointer() const {309 return llvm::cast<llvm::Constant>(RawAddress::getPointer());310 }311 312 ConstantAddress withElementType(llvm::Type *ElemTy) const {313 return ConstantAddress(getPointer(), ElemTy, getAlignment());314 }315 316 static bool isaImpl(RawAddress addr) {317 return llvm::isa<llvm::Constant>(addr.getPointer());318 }319 static ConstantAddress castImpl(RawAddress addr) {320 return ConstantAddress(llvm::cast<llvm::Constant>(addr.getPointer()),321 addr.getElementType(), addr.getAlignment());322 }323};324}325 326// Present a minimal LLVM-like casting interface.327template <class U> inline U cast(CodeGen::Address addr) {328 return U::castImpl(addr);329}330template <class U> inline bool isa(CodeGen::Address addr) {331 return U::isaImpl(addr);332}333 334}335 336#endif337