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 /// Returns true if the name of this GlobalDeclaration indicates that it 102 /// should have ExternalLinkage (as a special case). 103 virtual bool isPNaClABIExternalName(const std::string &Name) const = 0; 104 105 protected: GlobalDeclaration(GlobalDeclarationKind Kind,llvm::GlobalValue::LinkageTypes Linkage)106 GlobalDeclaration(GlobalDeclarationKind Kind, 107 llvm::GlobalValue::LinkageTypes Linkage) 108 : Kind(Kind), Linkage(Linkage) {} 109 110 /// Returns true if linkage is defined correctly for the global declaration, 111 /// based on default rules. verifyLinkageDefault()112 bool verifyLinkageDefault() const { 113 switch (Linkage) { 114 default: 115 return false; 116 case llvm::GlobalValue::InternalLinkage: 117 return true; 118 case llvm::GlobalValue::ExternalLinkage: 119 return getFlags().getAllowExternDefinedSymbols(); 120 } 121 } 122 123 const GlobalDeclarationKind Kind; 124 llvm::GlobalValue::LinkageTypes Linkage; 125 GlobalString Name; 126 }; 127 128 /// Models a function declaration. This includes the type signature of the 129 /// function, its calling conventions, and its linkage. 130 class FunctionDeclaration : public GlobalDeclaration { 131 FunctionDeclaration() = delete; 132 FunctionDeclaration(const FunctionDeclaration &) = delete; 133 FunctionDeclaration &operator=(const FunctionDeclaration &) = delete; 134 135 public: create(GlobalContext * Context,const FuncSigType & Signature,llvm::CallingConv::ID CallingConv,llvm::GlobalValue::LinkageTypes Linkage,bool IsProto)136 static FunctionDeclaration *create(GlobalContext *Context, 137 const FuncSigType &Signature, 138 llvm::CallingConv::ID CallingConv, 139 llvm::GlobalValue::LinkageTypes Linkage, 140 bool IsProto) { 141 return new (Context->allocate<FunctionDeclaration>()) 142 FunctionDeclaration(Signature, CallingConv, Linkage, IsProto); 143 } getSignature()144 const FuncSigType &getSignature() const { return Signature; } getCallingConv()145 llvm::CallingConv::ID getCallingConv() const { return CallingConv; } 146 /// isProto implies that there isn't a (local) definition for the function. isProto()147 bool isProto() const { return IsProto; } classof(const GlobalDeclaration * Addr)148 static bool classof(const GlobalDeclaration *Addr) { 149 return Addr->getKind() == FunctionDeclarationKind; 150 } 151 void dumpType(Ostream &Stream) const final; 152 void dump(Ostream &Stream) const final; getSuppressMangling()153 bool getSuppressMangling() const final { return isExternal() && IsProto; } 154 155 /// Returns true if linkage is correct for the function declaration. verifyLinkageCorrect(const GlobalContext * Ctx)156 bool verifyLinkageCorrect(const GlobalContext *Ctx) const { 157 if (getName().hasStdString()) { 158 if (isPNaClABIExternalName(getName().toString()) || 159 isIntrinsicName(Ctx)) { 160 return Linkage == llvm::GlobalValue::ExternalLinkage; 161 } 162 } 163 return verifyLinkageDefault(); 164 } 165 166 /// Validates that the type signature of the function is correct. Returns true 167 /// if valid. validateTypeSignature(const GlobalContext * Ctx)168 bool validateTypeSignature(const GlobalContext *Ctx) const { 169 bool IsIntrinsic; 170 if (const Intrinsics::FullIntrinsicInfo *Info = 171 getIntrinsicInfo(Ctx, &IsIntrinsic)) 172 return validateIntrinsicTypeSignature(Info); 173 return !IsIntrinsic && validateRegularTypeSignature(); 174 } 175 176 /// Generates an error message describing why validateTypeSignature returns 177 /// false. 178 std::string getTypeSignatureError(const GlobalContext *Ctx); 179 180 /// Returns corresponding PNaCl intrisic information. 181 const Intrinsics::FullIntrinsicInfo * getIntrinsicInfo(const GlobalContext * Ctx)182 getIntrinsicInfo(const GlobalContext *Ctx) const { 183 bool BadIntrinsic; 184 return getIntrinsicInfo(Ctx, &BadIntrinsic); 185 } 186 187 /// Same as above, except IsIntrinsic is true if the function is intrinsic 188 /// (even if not a PNaCl intrinsic). 189 const Intrinsics::FullIntrinsicInfo * 190 getIntrinsicInfo(const GlobalContext *Ctx, bool *IsIntrinsic) const; 191 192 private: 193 const Ice::FuncSigType Signature; 194 llvm::CallingConv::ID CallingConv; 195 const bool IsProto; 196 FunctionDeclaration(const FuncSigType & Signature,llvm::CallingConv::ID CallingConv,llvm::GlobalValue::LinkageTypes Linkage,bool IsProto)197 FunctionDeclaration(const FuncSigType &Signature, 198 llvm::CallingConv::ID CallingConv, 199 llvm::GlobalValue::LinkageTypes Linkage, bool IsProto) 200 : GlobalDeclaration(FunctionDeclarationKind, Linkage), 201 Signature(Signature), CallingConv(CallingConv), IsProto(IsProto) {} 202 isPNaClABIExternalName(const std::string & Name)203 bool isPNaClABIExternalName(const std::string &Name) const override { 204 return Name == "_start"; 205 } 206 isIntrinsicName(const GlobalContext * Ctx)207 bool isIntrinsicName(const GlobalContext *Ctx) const { 208 bool IsIntrinsic; 209 getIntrinsicInfo(Ctx, &IsIntrinsic); 210 return IsIntrinsic; 211 } 212 213 bool validateRegularTypeSignature() const; 214 215 bool validateIntrinsicTypeSignature( 216 const Intrinsics::FullIntrinsicInfo *Info) const; 217 }; 218 219 /// Models a global variable declaration, and its initializers. 220 class VariableDeclaration : public GlobalDeclaration { 221 VariableDeclaration(const VariableDeclaration &) = delete; 222 VariableDeclaration &operator=(const VariableDeclaration &) = delete; 223 224 public: 225 /// Base class for a global variable initializer. 226 class Initializer { 227 Initializer(const Initializer &) = delete; 228 Initializer &operator=(const Initializer &) = delete; 229 230 public: 231 /// Discriminator for LLVM-style RTTI. 232 enum InitializerKind { 233 DataInitializerKind, 234 ZeroInitializerKind, 235 RelocInitializerKind 236 }; getKind()237 InitializerKind getKind() const { return Kind; } 238 virtual SizeT getNumBytes() const = 0; 239 virtual void dump(Ostream &Stream) const = 0; 240 virtual void dumpType(Ostream &Stream) const; 241 242 protected: Initializer(InitializerKind Kind)243 explicit Initializer(InitializerKind Kind) : Kind(Kind) {} 244 245 private: 246 const InitializerKind Kind; 247 }; 248 static_assert(std::is_trivially_destructible<Initializer>::value, 249 "Initializer must be trivially destructible."); 250 251 /// Models the data in a data initializer. 252 using DataVecType = char *; 253 254 /// Defines a sequence of byte values as a data initializer. 255 class DataInitializer : public Initializer { 256 DataInitializer(const DataInitializer &) = delete; 257 DataInitializer &operator=(const DataInitializer &) = delete; 258 259 public: 260 template <class... Args> create(VariableDeclarationList * VDL,Args &&...TheArgs)261 static DataInitializer *create(VariableDeclarationList *VDL, 262 Args &&... TheArgs) { 263 return new (VDL->allocate_initializer<DataInitializer>()) 264 DataInitializer(VDL, std::forward<Args>(TheArgs)...); 265 } 266 getContents()267 const llvm::StringRef getContents() const { 268 return llvm::StringRef(Contents, ContentsSize); 269 } getNumBytes()270 SizeT getNumBytes() const final { return ContentsSize; } 271 void dump(Ostream &Stream) const final; classof(const Initializer * D)272 static bool classof(const Initializer *D) { 273 return D->getKind() == DataInitializerKind; 274 } 275 276 private: DataInitializer(VariableDeclarationList * VDL,const llvm::NaClBitcodeRecord::RecordVector & Values)277 DataInitializer(VariableDeclarationList *VDL, 278 const llvm::NaClBitcodeRecord::RecordVector &Values) 279 : Initializer(DataInitializerKind), ContentsSize(Values.size()), 280 // ugh, we should actually do new char[], but this may involve 281 // implementation-specific details. Given that Contents is arena 282 // allocated, and never delete[]d, just use char -- 283 // AllocOwner->allocate_array will allocate a buffer with the right 284 // size. 285 Contents(new (VDL->allocate_initializer<char>(ContentsSize)) char) { 286 for (SizeT I = 0; I < Values.size(); ++I) 287 Contents[I] = static_cast<int8_t>(Values[I]); 288 } 289 DataInitializer(VariableDeclarationList * VDL,const char * Str,size_t StrLen)290 DataInitializer(VariableDeclarationList *VDL, const char *Str, 291 size_t StrLen) 292 : Initializer(DataInitializerKind), ContentsSize(StrLen), 293 Contents(new (VDL->allocate_initializer<char>(ContentsSize)) char) { 294 for (size_t i = 0; i < StrLen; ++i) 295 Contents[i] = Str[i]; 296 } 297 298 /// The byte contents of the data initializer. 299 const SizeT ContentsSize; 300 DataVecType Contents; 301 }; 302 static_assert(std::is_trivially_destructible<DataInitializer>::value, 303 "DataInitializer must be trivially destructible."); 304 305 /// Defines a sequence of bytes initialized to zero. 306 class ZeroInitializer : public Initializer { 307 ZeroInitializer(const ZeroInitializer &) = delete; 308 ZeroInitializer &operator=(const ZeroInitializer &) = delete; 309 310 public: create(VariableDeclarationList * VDL,SizeT Size)311 static ZeroInitializer *create(VariableDeclarationList *VDL, SizeT Size) { 312 return new (VDL->allocate_initializer<ZeroInitializer>()) 313 ZeroInitializer(Size); 314 } getNumBytes()315 SizeT getNumBytes() const final { return Size; } 316 void dump(Ostream &Stream) const final; classof(const Initializer * Z)317 static bool classof(const Initializer *Z) { 318 return Z->getKind() == ZeroInitializerKind; 319 } 320 321 private: ZeroInitializer(SizeT Size)322 explicit ZeroInitializer(SizeT Size) 323 : Initializer(ZeroInitializerKind), Size(Size) {} 324 325 /// The number of bytes to be zero initialized. 326 SizeT Size; 327 }; 328 static_assert(std::is_trivially_destructible<ZeroInitializer>::value, 329 "ZeroInitializer must be trivially destructible."); 330 331 /// Defines the relocation value of another global declaration. 332 class RelocInitializer : public Initializer { 333 RelocInitializer(const RelocInitializer &) = delete; 334 RelocInitializer &operator=(const RelocInitializer &) = delete; 335 336 public: create(VariableDeclarationList * VDL,const GlobalDeclaration * Declaration,const RelocOffsetArray & OffsetExpr)337 static RelocInitializer *create(VariableDeclarationList *VDL, 338 const GlobalDeclaration *Declaration, 339 const RelocOffsetArray &OffsetExpr) { 340 constexpr bool NoFixup = false; 341 return new (VDL->allocate_initializer<RelocInitializer>()) 342 RelocInitializer(VDL, Declaration, OffsetExpr, NoFixup); 343 } 344 create(VariableDeclarationList * VDL,const GlobalDeclaration * Declaration,const RelocOffsetArray & OffsetExpr,FixupKind Fixup)345 static RelocInitializer *create(VariableDeclarationList *VDL, 346 const GlobalDeclaration *Declaration, 347 const RelocOffsetArray &OffsetExpr, 348 FixupKind Fixup) { 349 constexpr bool HasFixup = true; 350 return new (VDL->allocate_initializer<RelocInitializer>()) 351 RelocInitializer(VDL, Declaration, OffsetExpr, HasFixup, Fixup); 352 } 353 getOffset()354 RelocOffsetT getOffset() const { 355 RelocOffsetT Offset = 0; 356 for (SizeT i = 0; i < OffsetExprSize; ++i) { 357 Offset += OffsetExpr[i]->getOffset(); 358 } 359 return Offset; 360 } 361 hasFixup()362 bool hasFixup() const { return HasFixup; } getFixup()363 FixupKind getFixup() const { 364 assert(HasFixup); 365 return Fixup; 366 } 367 getDeclaration()368 const GlobalDeclaration *getDeclaration() const { return Declaration; } getNumBytes()369 SizeT getNumBytes() const final { return RelocAddrSize; } 370 void dump(Ostream &Stream) const final; 371 void dumpType(Ostream &Stream) const final; classof(const Initializer * R)372 static bool classof(const Initializer *R) { 373 return R->getKind() == RelocInitializerKind; 374 } 375 376 private: 377 RelocInitializer(VariableDeclarationList *VDL, 378 const GlobalDeclaration *Declaration, 379 const RelocOffsetArray &OffsetExpr, bool HasFixup, 380 FixupKind Fixup = 0) Initializer(RelocInitializerKind)381 : Initializer(RelocInitializerKind), 382 Declaration(Declaration), // The global declaration used in the reloc. 383 OffsetExprSize(OffsetExpr.size()), 384 OffsetExpr(new (VDL->allocate_initializer<RelocOffset *>( 385 OffsetExprSize)) RelocOffset *), 386 HasFixup(HasFixup), Fixup(Fixup) { 387 for (SizeT i = 0; i < OffsetExprSize; ++i) { 388 this->OffsetExpr[i] = OffsetExpr[i]; 389 } 390 } 391 392 const GlobalDeclaration *Declaration; 393 /// The offset to add to the relocation. 394 const SizeT OffsetExprSize; 395 RelocOffset **OffsetExpr; 396 const bool HasFixup = false; 397 const FixupKind Fixup = 0; 398 }; 399 static_assert(std::is_trivially_destructible<RelocInitializer>::value, 400 "RelocInitializer must be trivially destructible."); 401 402 /// Models the list of initializers. 403 // TODO(jpp): missing allocator. 404 using InitializerListType = std::vector<Initializer *>; 405 406 static VariableDeclaration *create(VariableDeclarationList *VDL, 407 bool SuppressMangling = false, 408 llvm::GlobalValue::LinkageTypes Linkage = 409 llvm::GlobalValue::InternalLinkage) { 410 return new (VDL->allocate_variable_declaration<VariableDeclaration>()) 411 VariableDeclaration(Linkage, SuppressMangling); 412 } 413 createExternal(VariableDeclarationList * VDL)414 static VariableDeclaration *createExternal(VariableDeclarationList *VDL) { 415 constexpr bool SuppressMangling = true; 416 constexpr llvm::GlobalValue::LinkageTypes Linkage = 417 llvm::GlobalValue::ExternalLinkage; 418 return create(VDL, SuppressMangling, Linkage); 419 } 420 getInitializers()421 const InitializerListType &getInitializers() const { return Initializers; } getIsConstant()422 bool getIsConstant() const { return IsConstant; } setIsConstant(bool NewValue)423 void setIsConstant(bool NewValue) { IsConstant = NewValue; } getAlignment()424 uint32_t getAlignment() const { return Alignment; } setAlignment(uint32_t NewAlignment)425 void setAlignment(uint32_t NewAlignment) { Alignment = NewAlignment; } hasInitializer()426 bool hasInitializer() const { return HasInitializer; } hasNonzeroInitializer()427 bool hasNonzeroInitializer() const { 428 return !(Initializers.size() == 1 && 429 llvm::isa<ZeroInitializer>(Initializers[0])); 430 } 431 432 /// Returns the number of bytes for the initializer of the global address. getNumBytes()433 SizeT getNumBytes() const { 434 SizeT Count = 0; 435 for (const auto *Init : Initializers) { 436 Count += Init->getNumBytes(); 437 } 438 return Count; 439 } 440 441 /// Adds Initializer to the list of initializers. Takes ownership of the 442 /// initializer. addInitializer(Initializer * Initializer)443 void addInitializer(Initializer *Initializer) { 444 const bool OldSuppressMangling = getSuppressMangling(); 445 Initializers.emplace_back(Initializer); 446 HasInitializer = true; 447 // The getSuppressMangling() logic depends on whether the global variable 448 // has initializers. If its value changed as a result of adding an 449 // initializer, then make sure we haven't previously set the name based on 450 // faulty SuppressMangling logic. 451 const bool SameMangling = (OldSuppressMangling == getSuppressMangling()); 452 (void)SameMangling; 453 assert(Name.hasStdString() || SameMangling); 454 } 455 456 /// Prints out type for initializer associated with the declaration to Stream. 457 void dumpType(Ostream &Stream) const final; 458 459 /// Prints out the definition of the global variable declaration (including 460 /// initialization). 461 virtual void dump(Ostream &Stream) const override; 462 463 /// Returns true if linkage is correct for the variable declaration. verifyLinkageCorrect()464 bool verifyLinkageCorrect() const { 465 if (getName().hasStdString()) { 466 if (isPNaClABIExternalName(getName().toString())) { 467 return Linkage == llvm::GlobalValue::ExternalLinkage; 468 } 469 } 470 return verifyLinkageDefault(); 471 } 472 classof(const GlobalDeclaration * Addr)473 static bool classof(const GlobalDeclaration *Addr) { 474 return Addr->getKind() == VariableDeclarationKind; 475 } 476 getSuppressMangling()477 bool getSuppressMangling() const final { 478 if (ForceSuppressMangling) 479 return true; 480 return isExternal() && !hasInitializer(); 481 } 482 discardInitializers()483 void discardInitializers() { Initializers.clear(); } 484 isPNaClABIExternalName(const std::string & Name)485 bool isPNaClABIExternalName(const std::string &Name) const override { 486 return Name == "__pnacl_pso_root"; 487 } 488 489 private: 490 /// List of initializers for the declared variable. 491 InitializerListType Initializers; 492 bool HasInitializer = false; 493 /// The alignment of the declared variable. 494 uint32_t Alignment = 0; 495 /// True if a declared (global) constant. 496 bool IsConstant = false; 497 /// If set to true, force getSuppressMangling() to return true. 498 const bool ForceSuppressMangling; 499 VariableDeclaration(llvm::GlobalValue::LinkageTypes Linkage,bool SuppressMangling)500 VariableDeclaration(llvm::GlobalValue::LinkageTypes Linkage, 501 bool SuppressMangling) 502 : GlobalDeclaration(VariableDeclarationKind, Linkage), 503 ForceSuppressMangling(SuppressMangling) {} 504 }; 505 506 template <class StreamType> 507 inline StreamType &operator<<(StreamType &Stream, 508 const VariableDeclaration::Initializer &Init) { 509 Init.dump(Stream); 510 return Stream; 511 } 512 513 template <class StreamType> 514 inline StreamType &operator<<(StreamType &Stream, 515 const GlobalDeclaration &Addr) { 516 Addr.dump(Stream); 517 return Stream; 518 } 519 520 } // end of namespace Ice 521 522 #endif // SUBZERO_SRC_ICEGLOBALINITS_H 523