1 //===- subzero/src/IceGlobalInits.h - Global declarations -------*- C++ -*-===// 2 // 3 // The Subzero Code Generator 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 /// 10 /// \file 11 /// \brief Declares the representation of function declarations, global variable 12 /// declarations, and the corresponding variable initializers in Subzero. 13 /// 14 /// Global variable initializers are represented as a sequence of simple 15 /// initializers. 16 /// 17 //===----------------------------------------------------------------------===// 18 19 #ifndef SUBZERO_SRC_ICEGLOBALINITS_H 20 #define SUBZERO_SRC_ICEGLOBALINITS_H 21 22 #include "IceDefs.h" 23 #include "IceFixups.h" 24 #include "IceGlobalContext.h" 25 #include "IceIntrinsics.h" 26 #include "IceMangling.h" 27 #include "IceOperand.h" 28 #include "IceTypes.h" 29 30 #ifdef __clang__ 31 #pragma clang diagnostic push 32 #pragma clang diagnostic ignored "-Wunused-parameter" 33 #endif // __clang__ 34 35 #include "llvm/Bitcode/NaCl/NaClBitcodeParser.h" // for NaClBitcodeRecord. 36 #include "llvm/IR/CallingConv.h" 37 #include "llvm/IR/GlobalValue.h" // for GlobalValue::LinkageTypes. 38 39 #ifdef __clang__ 40 #pragma clang diagnostic pop 41 #endif // __clang__ 42 43 #include <memory> 44 #include <utility> 45 46 // TODO(kschimpf): Remove ourselves from using LLVM representation for calling 47 // conventions and linkage types. 48 49 namespace Ice { 50 51 /// Base class for global variable and function declarations. 52 class GlobalDeclaration { 53 GlobalDeclaration() = delete; 54 GlobalDeclaration(const GlobalDeclaration &) = delete; 55 GlobalDeclaration &operator=(const GlobalDeclaration &) = delete; 56 57 public: 58 /// Discriminator for LLVM-style RTTI. 59 enum GlobalDeclarationKind { 60 FunctionDeclarationKind, 61 VariableDeclarationKind 62 }; getKind()63 GlobalDeclarationKind getKind() const { return Kind; } getName()64 GlobalString getName() const { return Name; } setName(GlobalContext * Ctx,const std::string & NewName)65 void setName(GlobalContext *Ctx, const std::string &NewName) { 66 Name = Ctx->getGlobalString(getSuppressMangling() ? NewName 67 : mangleName(NewName)); 68 } setName(GlobalString NewName)69 void setName(GlobalString NewName) { Name = NewName; } setName(GlobalContext * Ctx)70 void setName(GlobalContext *Ctx) { 71 Name = GlobalString::createWithoutString(Ctx); 72 } hasName()73 bool hasName() const { return Name.hasStdString(); } isInternal()74 bool isInternal() const { 75 return Linkage == llvm::GlobalValue::InternalLinkage; 76 } getLinkage()77 llvm::GlobalValue::LinkageTypes getLinkage() const { return Linkage; } setLinkage(llvm::GlobalValue::LinkageTypes L)78 void setLinkage(llvm::GlobalValue::LinkageTypes L) { 79 assert(!hasName()); 80 Linkage = L; 81 } isExternal()82 bool isExternal() const { 83 return Linkage == llvm::GlobalValue::ExternalLinkage; 84 } 85 virtual ~GlobalDeclaration() = default; 86 87 /// Prints out type of the global declaration. 88 virtual void dumpType(Ostream &Stream) const = 0; 89 90 /// Prints out the global declaration. 91 virtual void dump(Ostream &Stream) const = 0; 92 93 /// Returns true if when emitting names, we should suppress mangling. 94 virtual bool getSuppressMangling() const = 0; 95 96 /// Returns textual name of linkage. getLinkageName()97 const char *getLinkageName() const { 98 return isInternal() ? "internal" : "external"; 99 } 100 101 protected: GlobalDeclaration(GlobalDeclarationKind Kind,llvm::GlobalValue::LinkageTypes Linkage)102 GlobalDeclaration(GlobalDeclarationKind Kind, 103 llvm::GlobalValue::LinkageTypes Linkage) 104 : Kind(Kind), Linkage(Linkage) {} 105 106 /// Returns true if linkage is defined correctly for the global declaration, 107 /// based on default rules. verifyLinkageDefault()108 bool verifyLinkageDefault() const { 109 switch (Linkage) { 110 default: 111 return false; 112 case llvm::GlobalValue::InternalLinkage: 113 return true; 114 case llvm::GlobalValue::ExternalLinkage: 115 return getFlags().getAllowExternDefinedSymbols(); 116 } 117 } 118 119 const GlobalDeclarationKind Kind; 120 llvm::GlobalValue::LinkageTypes Linkage; 121 GlobalString Name; 122 }; 123 124 /// Models a function declaration. This includes the type signature of the 125 /// function, its calling conventions, and its linkage. 126 class FunctionDeclaration : public GlobalDeclaration { 127 FunctionDeclaration() = delete; 128 FunctionDeclaration(const FunctionDeclaration &) = delete; 129 FunctionDeclaration &operator=(const FunctionDeclaration &) = delete; 130 131 public: create(GlobalContext * Context,const FuncSigType & Signature,llvm::CallingConv::ID CallingConv,llvm::GlobalValue::LinkageTypes Linkage,bool IsProto)132 static FunctionDeclaration *create(GlobalContext *Context, 133 const FuncSigType &Signature, 134 llvm::CallingConv::ID CallingConv, 135 llvm::GlobalValue::LinkageTypes Linkage, 136 bool IsProto) { 137 return new (Context->allocate<FunctionDeclaration>()) 138 FunctionDeclaration(Signature, CallingConv, Linkage, IsProto); 139 } getSignature()140 const FuncSigType &getSignature() const { return Signature; } getCallingConv()141 llvm::CallingConv::ID getCallingConv() const { return CallingConv; } 142 /// isProto implies that there isn't a (local) definition for the function. isProto()143 bool isProto() const { return IsProto; } classof(const GlobalDeclaration * Addr)144 static bool classof(const GlobalDeclaration *Addr) { 145 return Addr->getKind() == FunctionDeclarationKind; 146 } 147 void dumpType(Ostream &Stream) const final; 148 void dump(Ostream &Stream) const final; getSuppressMangling()149 bool getSuppressMangling() const final { return isExternal() && IsProto; } 150 151 /// Returns true if linkage is correct for the function declaration. verifyLinkageCorrect(const GlobalContext * Ctx)152 bool verifyLinkageCorrect(const GlobalContext *Ctx) const { 153 return verifyLinkageDefault(); 154 } 155 156 /// Validates that the type signature of the function is correct. Returns true 157 /// if valid. 158 bool validateTypeSignature() const; 159 160 /// Generates an error message describing why validateTypeSignature returns 161 /// false. 162 std::string getTypeSignatureError(const GlobalContext *Ctx); 163 164 private: 165 const Ice::FuncSigType Signature; 166 llvm::CallingConv::ID CallingConv; 167 const bool IsProto; 168 FunctionDeclaration(const FuncSigType & Signature,llvm::CallingConv::ID CallingConv,llvm::GlobalValue::LinkageTypes Linkage,bool IsProto)169 FunctionDeclaration(const FuncSigType &Signature, 170 llvm::CallingConv::ID CallingConv, 171 llvm::GlobalValue::LinkageTypes Linkage, bool IsProto) 172 : GlobalDeclaration(FunctionDeclarationKind, Linkage), 173 Signature(Signature), CallingConv(CallingConv), IsProto(IsProto) {} 174 }; 175 176 /// Models a global variable declaration, and its initializers. 177 class VariableDeclaration : public GlobalDeclaration { 178 VariableDeclaration(const VariableDeclaration &) = delete; 179 VariableDeclaration &operator=(const VariableDeclaration &) = delete; 180 181 public: 182 /// Base class for a global variable initializer. 183 class Initializer { 184 Initializer(const Initializer &) = delete; 185 Initializer &operator=(const Initializer &) = delete; 186 187 public: 188 /// Discriminator for LLVM-style RTTI. 189 enum InitializerKind { 190 DataInitializerKind, 191 ZeroInitializerKind, 192 RelocInitializerKind 193 }; getKind()194 InitializerKind getKind() const { return Kind; } 195 virtual SizeT getNumBytes() const = 0; 196 virtual void dump(Ostream &Stream) const = 0; 197 virtual void dumpType(Ostream &Stream) const; 198 199 protected: Initializer(InitializerKind Kind)200 explicit Initializer(InitializerKind Kind) : Kind(Kind) {} 201 202 private: 203 const InitializerKind Kind; 204 }; 205 static_assert(std::is_trivially_destructible<Initializer>::value, 206 "Initializer must be trivially destructible."); 207 208 /// Models the data in a data initializer. 209 using DataVecType = char *; 210 211 /// Defines a sequence of byte values as a data initializer. 212 class DataInitializer : public Initializer { 213 DataInitializer(const DataInitializer &) = delete; 214 DataInitializer &operator=(const DataInitializer &) = delete; 215 216 public: 217 template <class... Args> create(VariableDeclarationList * VDL,Args &&...TheArgs)218 static DataInitializer *create(VariableDeclarationList *VDL, 219 Args &&... TheArgs) { 220 return new (VDL->allocate_initializer<DataInitializer>()) 221 DataInitializer(VDL, std::forward<Args>(TheArgs)...); 222 } 223 getContents()224 const llvm::StringRef getContents() const { 225 return llvm::StringRef(Contents, ContentsSize); 226 } getNumBytes()227 SizeT getNumBytes() const final { return ContentsSize; } 228 void dump(Ostream &Stream) const final; classof(const Initializer * D)229 static bool classof(const Initializer *D) { 230 return D->getKind() == DataInitializerKind; 231 } 232 233 private: DataInitializer(VariableDeclarationList * VDL,const llvm::NaClBitcodeRecord::RecordVector & Values)234 DataInitializer(VariableDeclarationList *VDL, 235 const llvm::NaClBitcodeRecord::RecordVector &Values) 236 : Initializer(DataInitializerKind), ContentsSize(Values.size()), 237 // ugh, we should actually do new char[], but this may involve 238 // implementation-specific details. Given that Contents is arena 239 // allocated, and never delete[]d, just use char -- 240 // AllocOwner->allocate_array will allocate a buffer with the right 241 // size. 242 Contents(new (VDL->allocate_initializer<char>(ContentsSize)) char) { 243 for (SizeT I = 0; I < Values.size(); ++I) 244 Contents[I] = static_cast<int8_t>(Values[I]); 245 } 246 DataInitializer(VariableDeclarationList * VDL,const char * Str,size_t StrLen)247 DataInitializer(VariableDeclarationList *VDL, const char *Str, 248 size_t StrLen) 249 : Initializer(DataInitializerKind), ContentsSize(StrLen), 250 Contents(new (VDL->allocate_initializer<char>(ContentsSize)) char) { 251 for (size_t i = 0; i < StrLen; ++i) 252 Contents[i] = Str[i]; 253 } 254 255 /// The byte contents of the data initializer. 256 const SizeT ContentsSize; 257 DataVecType Contents; 258 }; 259 static_assert(std::is_trivially_destructible<DataInitializer>::value, 260 "DataInitializer must be trivially destructible."); 261 262 /// Defines a sequence of bytes initialized to zero. 263 class ZeroInitializer : public Initializer { 264 ZeroInitializer(const ZeroInitializer &) = delete; 265 ZeroInitializer &operator=(const ZeroInitializer &) = delete; 266 267 public: create(VariableDeclarationList * VDL,SizeT Size)268 static ZeroInitializer *create(VariableDeclarationList *VDL, SizeT Size) { 269 return new (VDL->allocate_initializer<ZeroInitializer>()) 270 ZeroInitializer(Size); 271 } getNumBytes()272 SizeT getNumBytes() const final { return Size; } 273 void dump(Ostream &Stream) const final; classof(const Initializer * Z)274 static bool classof(const Initializer *Z) { 275 return Z->getKind() == ZeroInitializerKind; 276 } 277 278 private: ZeroInitializer(SizeT Size)279 explicit ZeroInitializer(SizeT Size) 280 : Initializer(ZeroInitializerKind), Size(Size) {} 281 282 /// The number of bytes to be zero initialized. 283 SizeT Size; 284 }; 285 static_assert(std::is_trivially_destructible<ZeroInitializer>::value, 286 "ZeroInitializer must be trivially destructible."); 287 288 /// Defines the relocation value of another global declaration. 289 class RelocInitializer : public Initializer { 290 RelocInitializer(const RelocInitializer &) = delete; 291 RelocInitializer &operator=(const RelocInitializer &) = delete; 292 293 public: create(VariableDeclarationList * VDL,const GlobalDeclaration * Declaration,const RelocOffsetArray & OffsetExpr)294 static RelocInitializer *create(VariableDeclarationList *VDL, 295 const GlobalDeclaration *Declaration, 296 const RelocOffsetArray &OffsetExpr) { 297 constexpr bool NoFixup = false; 298 return new (VDL->allocate_initializer<RelocInitializer>()) 299 RelocInitializer(VDL, Declaration, OffsetExpr, NoFixup); 300 } 301 create(VariableDeclarationList * VDL,const GlobalDeclaration * Declaration,const RelocOffsetArray & OffsetExpr,FixupKind Fixup)302 static RelocInitializer *create(VariableDeclarationList *VDL, 303 const GlobalDeclaration *Declaration, 304 const RelocOffsetArray &OffsetExpr, 305 FixupKind Fixup) { 306 constexpr bool HasFixup = true; 307 return new (VDL->allocate_initializer<RelocInitializer>()) 308 RelocInitializer(VDL, Declaration, OffsetExpr, HasFixup, Fixup); 309 } 310 getOffset()311 RelocOffsetT getOffset() const { 312 RelocOffsetT Offset = 0; 313 for (SizeT i = 0; i < OffsetExprSize; ++i) { 314 Offset += OffsetExpr[i]->getOffset(); 315 } 316 return Offset; 317 } 318 hasFixup()319 bool hasFixup() const { return HasFixup; } getFixup()320 FixupKind getFixup() const { 321 assert(HasFixup); 322 return Fixup; 323 } 324 getDeclaration()325 const GlobalDeclaration *getDeclaration() const { return Declaration; } getNumBytes()326 SizeT getNumBytes() const final { return RelocAddrSize; } 327 void dump(Ostream &Stream) const final; 328 void dumpType(Ostream &Stream) const final; classof(const Initializer * R)329 static bool classof(const Initializer *R) { 330 return R->getKind() == RelocInitializerKind; 331 } 332 333 private: 334 RelocInitializer(VariableDeclarationList *VDL, 335 const GlobalDeclaration *Declaration, 336 const RelocOffsetArray &OffsetExpr, bool HasFixup, 337 FixupKind Fixup = 0) Initializer(RelocInitializerKind)338 : Initializer(RelocInitializerKind), 339 Declaration(Declaration), // The global declaration used in the reloc. 340 OffsetExprSize(OffsetExpr.size()), 341 OffsetExpr(new (VDL->allocate_initializer<RelocOffset *>( 342 OffsetExprSize)) RelocOffset *), 343 HasFixup(HasFixup), Fixup(Fixup) { 344 for (SizeT i = 0; i < OffsetExprSize; ++i) { 345 this->OffsetExpr[i] = OffsetExpr[i]; 346 } 347 } 348 349 const GlobalDeclaration *Declaration; 350 /// The offset to add to the relocation. 351 const SizeT OffsetExprSize; 352 RelocOffset **OffsetExpr; 353 const bool HasFixup = false; 354 const FixupKind Fixup = 0; 355 }; 356 static_assert(std::is_trivially_destructible<RelocInitializer>::value, 357 "RelocInitializer must be trivially destructible."); 358 359 /// Models the list of initializers. 360 // TODO(jpp): missing allocator. 361 using InitializerListType = std::vector<Initializer *>; 362 363 static VariableDeclaration *create(VariableDeclarationList *VDL, 364 bool SuppressMangling = false, 365 llvm::GlobalValue::LinkageTypes Linkage = 366 llvm::GlobalValue::InternalLinkage) { 367 return new (VDL->allocate_variable_declaration<VariableDeclaration>()) 368 VariableDeclaration(Linkage, SuppressMangling); 369 } 370 createExternal(VariableDeclarationList * VDL)371 static VariableDeclaration *createExternal(VariableDeclarationList *VDL) { 372 constexpr bool SuppressMangling = true; 373 constexpr llvm::GlobalValue::LinkageTypes Linkage = 374 llvm::GlobalValue::ExternalLinkage; 375 return create(VDL, SuppressMangling, Linkage); 376 } 377 getInitializers()378 const InitializerListType &getInitializers() const { return Initializers; } getIsConstant()379 bool getIsConstant() const { return IsConstant; } setIsConstant(bool NewValue)380 void setIsConstant(bool NewValue) { IsConstant = NewValue; } getAlignment()381 uint32_t getAlignment() const { return Alignment; } setAlignment(uint32_t NewAlignment)382 void setAlignment(uint32_t NewAlignment) { Alignment = NewAlignment; } hasInitializer()383 bool hasInitializer() const { return HasInitializer; } hasNonzeroInitializer()384 bool hasNonzeroInitializer() const { 385 return !(Initializers.size() == 1 && 386 llvm::isa<ZeroInitializer>(Initializers[0])); 387 } 388 389 /// Returns the number of bytes for the initializer of the global address. getNumBytes()390 SizeT getNumBytes() const { 391 SizeT Count = 0; 392 for (const auto *Init : Initializers) { 393 Count += Init->getNumBytes(); 394 } 395 return Count; 396 } 397 398 /// Adds Initializer to the list of initializers. Takes ownership of the 399 /// initializer. addInitializer(Initializer * Initializer)400 void addInitializer(Initializer *Initializer) { 401 const bool OldSuppressMangling = getSuppressMangling(); 402 Initializers.emplace_back(Initializer); 403 HasInitializer = true; 404 // The getSuppressMangling() logic depends on whether the global variable 405 // has initializers. If its value changed as a result of adding an 406 // initializer, then make sure we haven't previously set the name based on 407 // faulty SuppressMangling logic. 408 const bool SameMangling = (OldSuppressMangling == getSuppressMangling()); 409 (void)SameMangling; 410 assert(Name.hasStdString() || SameMangling); 411 } 412 413 /// Prints out type for initializer associated with the declaration to Stream. 414 void dumpType(Ostream &Stream) const final; 415 416 /// Prints out the definition of the global variable declaration (including 417 /// initialization). 418 virtual void dump(Ostream &Stream) const override; 419 420 /// Returns true if linkage is correct for the variable declaration. verifyLinkageCorrect()421 bool verifyLinkageCorrect() const { return verifyLinkageDefault(); } 422 classof(const GlobalDeclaration * Addr)423 static bool classof(const GlobalDeclaration *Addr) { 424 return Addr->getKind() == VariableDeclarationKind; 425 } 426 getSuppressMangling()427 bool getSuppressMangling() const final { 428 if (ForceSuppressMangling) 429 return true; 430 return isExternal() && !hasInitializer(); 431 } 432 discardInitializers()433 void discardInitializers() { Initializers.clear(); } 434 435 private: 436 /// List of initializers for the declared variable. 437 InitializerListType Initializers; 438 bool HasInitializer = false; 439 /// The alignment of the declared variable. 440 uint32_t Alignment = 0; 441 /// True if a declared (global) constant. 442 bool IsConstant = false; 443 /// If set to true, force getSuppressMangling() to return true. 444 const bool ForceSuppressMangling; 445 VariableDeclaration(llvm::GlobalValue::LinkageTypes Linkage,bool SuppressMangling)446 VariableDeclaration(llvm::GlobalValue::LinkageTypes Linkage, 447 bool SuppressMangling) 448 : GlobalDeclaration(VariableDeclarationKind, Linkage), 449 ForceSuppressMangling(SuppressMangling) {} 450 }; 451 452 template <class StreamType> 453 inline StreamType &operator<<(StreamType &Stream, 454 const VariableDeclaration::Initializer &Init) { 455 Init.dump(Stream); 456 return Stream; 457 } 458 459 template <class StreamType> 460 inline StreamType &operator<<(StreamType &Stream, 461 const GlobalDeclaration &Addr) { 462 Addr.dump(Stream); 463 return Stream; 464 } 465 466 } // end of namespace Ice 467 468 #endif // SUBZERO_SRC_ICEGLOBALINITS_H 469