| //===- subzero/src/IceGlobalInits.h - Global declarations -------*- C++ -*-===// | 
 | // | 
 | //                        The Subzero Code Generator | 
 | // | 
 | // This file is distributed under the University of Illinois Open Source | 
 | // License. See LICENSE.TXT for details. | 
 | // | 
 | //===----------------------------------------------------------------------===// | 
 | /// | 
 | /// \file | 
 | /// \brief Declares the representation of function declarations, global variable | 
 | /// declarations, and the corresponding variable initializers in Subzero. | 
 | /// | 
 | /// Global variable initializers are represented as a sequence of simple | 
 | /// initializers. | 
 | /// | 
 | //===----------------------------------------------------------------------===// | 
 |  | 
 | #ifndef SUBZERO_SRC_ICEGLOBALINITS_H | 
 | #define SUBZERO_SRC_ICEGLOBALINITS_H | 
 |  | 
 | #include "IceDefs.h" | 
 | #include "IceFixups.h" | 
 | #include "IceGlobalContext.h" | 
 | #include "IceIntrinsics.h" | 
 | #include "IceMangling.h" | 
 | #include "IceOperand.h" | 
 | #include "IceTypes.h" | 
 |  | 
 | #ifdef __clang__ | 
 | #pragma clang diagnostic push | 
 | #pragma clang diagnostic ignored "-Wunused-parameter" | 
 | #endif // __clang__ | 
 |  | 
 | #include "llvm/Bitcode/NaCl/NaClBitcodeParser.h" // for NaClBitcodeRecord. | 
 | #include "llvm/IR/CallingConv.h" | 
 | #include "llvm/IR/GlobalValue.h" // for GlobalValue::LinkageTypes. | 
 |  | 
 | #ifdef __clang__ | 
 | #pragma clang diagnostic pop | 
 | #endif // __clang__ | 
 |  | 
 | #include <memory> | 
 | #include <utility> | 
 |  | 
 | // TODO(kschimpf): Remove ourselves from using LLVM representation for calling | 
 | // conventions and linkage types. | 
 |  | 
 | namespace Ice { | 
 |  | 
 | /// Base class for global variable and function declarations. | 
 | class GlobalDeclaration { | 
 |   GlobalDeclaration() = delete; | 
 |   GlobalDeclaration(const GlobalDeclaration &) = delete; | 
 |   GlobalDeclaration &operator=(const GlobalDeclaration &) = delete; | 
 |  | 
 | public: | 
 |   /// Discriminator for LLVM-style RTTI. | 
 |   enum GlobalDeclarationKind { | 
 |     FunctionDeclarationKind, | 
 |     VariableDeclarationKind | 
 |   }; | 
 |   GlobalDeclarationKind getKind() const { return Kind; } | 
 |   GlobalString getName() const { return Name; } | 
 |   void setName(GlobalContext *Ctx, const std::string &NewName) { | 
 |     Name = Ctx->getGlobalString(getSuppressMangling() ? NewName | 
 |                                                       : mangleName(NewName)); | 
 |   } | 
 |   void setName(GlobalString NewName) { Name = NewName; } | 
 |   void setName(GlobalContext *Ctx) { | 
 |     Name = GlobalString::createWithoutString(Ctx); | 
 |   } | 
 |   bool hasName() const { return Name.hasStdString(); } | 
 |   bool isInternal() const { | 
 |     return Linkage == llvm::GlobalValue::InternalLinkage; | 
 |   } | 
 |   llvm::GlobalValue::LinkageTypes getLinkage() const { return Linkage; } | 
 |   void setLinkage(llvm::GlobalValue::LinkageTypes L) { | 
 |     assert(!hasName()); | 
 |     Linkage = L; | 
 |   } | 
 |   bool isExternal() const { | 
 |     return Linkage == llvm::GlobalValue::ExternalLinkage; | 
 |   } | 
 |   virtual ~GlobalDeclaration() = default; | 
 |  | 
 |   /// Prints out type of the global declaration. | 
 |   virtual void dumpType(Ostream &Stream) const = 0; | 
 |  | 
 |   /// Prints out the global declaration. | 
 |   virtual void dump(Ostream &Stream) const = 0; | 
 |  | 
 |   /// Returns true if when emitting names, we should suppress mangling. | 
 |   virtual bool getSuppressMangling() const = 0; | 
 |  | 
 |   /// Returns textual name of linkage. | 
 |   const char *getLinkageName() const { | 
 |     return isInternal() ? "internal" : "external"; | 
 |   } | 
 |  | 
 |   /// Returns true if the name of this GlobalDeclaration indicates that it | 
 |   /// should have ExternalLinkage (as a special case). | 
 |   virtual bool isPNaClABIExternalName(const std::string &Name) const = 0; | 
 |  | 
 | protected: | 
 |   GlobalDeclaration(GlobalDeclarationKind Kind, | 
 |                     llvm::GlobalValue::LinkageTypes Linkage) | 
 |       : Kind(Kind), Linkage(Linkage) {} | 
 |  | 
 |   /// Returns true if linkage is defined correctly for the global declaration, | 
 |   /// based on default rules. | 
 |   bool verifyLinkageDefault() const { | 
 |     switch (Linkage) { | 
 |     default: | 
 |       return false; | 
 |     case llvm::GlobalValue::InternalLinkage: | 
 |       return true; | 
 |     case llvm::GlobalValue::ExternalLinkage: | 
 |       return getFlags().getAllowExternDefinedSymbols(); | 
 |     } | 
 |   } | 
 |  | 
 |   const GlobalDeclarationKind Kind; | 
 |   llvm::GlobalValue::LinkageTypes Linkage; | 
 |   GlobalString Name; | 
 | }; | 
 |  | 
 | /// Models a function declaration. This includes the type signature of the | 
 | /// function, its calling conventions, and its linkage. | 
 | class FunctionDeclaration : public GlobalDeclaration { | 
 |   FunctionDeclaration() = delete; | 
 |   FunctionDeclaration(const FunctionDeclaration &) = delete; | 
 |   FunctionDeclaration &operator=(const FunctionDeclaration &) = delete; | 
 |  | 
 | public: | 
 |   static FunctionDeclaration *create(GlobalContext *Context, | 
 |                                      const FuncSigType &Signature, | 
 |                                      llvm::CallingConv::ID CallingConv, | 
 |                                      llvm::GlobalValue::LinkageTypes Linkage, | 
 |                                      bool IsProto) { | 
 |     return new (Context->allocate<FunctionDeclaration>()) | 
 |         FunctionDeclaration(Signature, CallingConv, Linkage, IsProto); | 
 |   } | 
 |   const FuncSigType &getSignature() const { return Signature; } | 
 |   llvm::CallingConv::ID getCallingConv() const { return CallingConv; } | 
 |   /// isProto implies that there isn't a (local) definition for the function. | 
 |   bool isProto() const { return IsProto; } | 
 |   static bool classof(const GlobalDeclaration *Addr) { | 
 |     return Addr->getKind() == FunctionDeclarationKind; | 
 |   } | 
 |   void dumpType(Ostream &Stream) const final; | 
 |   void dump(Ostream &Stream) const final; | 
 |   bool getSuppressMangling() const final { return isExternal() && IsProto; } | 
 |  | 
 |   /// Returns true if linkage is correct for the function declaration. | 
 |   bool verifyLinkageCorrect(const GlobalContext *Ctx) const { | 
 |     if (getName().hasStdString()) { | 
 |       if (isPNaClABIExternalName(getName().toString()) || | 
 |           isIntrinsicName(Ctx)) { | 
 |         return Linkage == llvm::GlobalValue::ExternalLinkage; | 
 |       } | 
 |     } | 
 |     return verifyLinkageDefault(); | 
 |   } | 
 |  | 
 |   /// Validates that the type signature of the function is correct. Returns true | 
 |   /// if valid. | 
 |   bool validateTypeSignature(const GlobalContext *Ctx) const { | 
 |     bool IsIntrinsic; | 
 |     if (const Intrinsics::FullIntrinsicInfo *Info = | 
 |             getIntrinsicInfo(Ctx, &IsIntrinsic)) | 
 |       return validateIntrinsicTypeSignature(Info); | 
 |     return !IsIntrinsic && validateRegularTypeSignature(); | 
 |   } | 
 |  | 
 |   /// Generates an error message describing why validateTypeSignature returns | 
 |   /// false. | 
 |   std::string getTypeSignatureError(const GlobalContext *Ctx); | 
 |  | 
 |   /// Returns corresponding PNaCl intrisic information. | 
 |   const Intrinsics::FullIntrinsicInfo * | 
 |   getIntrinsicInfo(const GlobalContext *Ctx) const { | 
 |     bool BadIntrinsic; | 
 |     return getIntrinsicInfo(Ctx, &BadIntrinsic); | 
 |   } | 
 |  | 
 |   /// Same as above, except IsIntrinsic is true if the function is intrinsic | 
 |   /// (even if not a PNaCl intrinsic). | 
 |   const Intrinsics::FullIntrinsicInfo * | 
 |   getIntrinsicInfo(const GlobalContext *Ctx, bool *IsIntrinsic) const; | 
 |  | 
 | private: | 
 |   const Ice::FuncSigType Signature; | 
 |   llvm::CallingConv::ID CallingConv; | 
 |   const bool IsProto; | 
 |  | 
 |   FunctionDeclaration(const FuncSigType &Signature, | 
 |                       llvm::CallingConv::ID CallingConv, | 
 |                       llvm::GlobalValue::LinkageTypes Linkage, bool IsProto) | 
 |       : GlobalDeclaration(FunctionDeclarationKind, Linkage), | 
 |         Signature(Signature), CallingConv(CallingConv), IsProto(IsProto) {} | 
 |  | 
 |   bool isPNaClABIExternalName(const std::string &Name) const override { | 
 |     return Name == "_start"; | 
 |   } | 
 |  | 
 |   bool isIntrinsicName(const GlobalContext *Ctx) const { | 
 |     bool IsIntrinsic; | 
 |     getIntrinsicInfo(Ctx, &IsIntrinsic); | 
 |     return IsIntrinsic; | 
 |   } | 
 |  | 
 |   bool validateRegularTypeSignature() const; | 
 |  | 
 |   bool validateIntrinsicTypeSignature( | 
 |       const Intrinsics::FullIntrinsicInfo *Info) const; | 
 | }; | 
 |  | 
 | /// Models a global variable declaration, and its initializers. | 
 | class VariableDeclaration : public GlobalDeclaration { | 
 |   VariableDeclaration(const VariableDeclaration &) = delete; | 
 |   VariableDeclaration &operator=(const VariableDeclaration &) = delete; | 
 |  | 
 | public: | 
 |   /// Base class for a global variable initializer. | 
 |   class Initializer { | 
 |     Initializer(const Initializer &) = delete; | 
 |     Initializer &operator=(const Initializer &) = delete; | 
 |  | 
 |   public: | 
 |     /// Discriminator for LLVM-style RTTI. | 
 |     enum InitializerKind { | 
 |       DataInitializerKind, | 
 |       ZeroInitializerKind, | 
 |       RelocInitializerKind | 
 |     }; | 
 |     InitializerKind getKind() const { return Kind; } | 
 |     virtual SizeT getNumBytes() const = 0; | 
 |     virtual void dump(Ostream &Stream) const = 0; | 
 |     virtual void dumpType(Ostream &Stream) const; | 
 |  | 
 |   protected: | 
 |     explicit Initializer(InitializerKind Kind) : Kind(Kind) {} | 
 |  | 
 |   private: | 
 |     const InitializerKind Kind; | 
 |   }; | 
 |   static_assert(std::is_trivially_destructible<Initializer>::value, | 
 |                 "Initializer must be trivially destructible."); | 
 |  | 
 |   /// Models the data in a data initializer. | 
 |   using DataVecType = char *; | 
 |  | 
 |   /// Defines a sequence of byte values as a data initializer. | 
 |   class DataInitializer : public Initializer { | 
 |     DataInitializer(const DataInitializer &) = delete; | 
 |     DataInitializer &operator=(const DataInitializer &) = delete; | 
 |  | 
 |   public: | 
 |     template <class... Args> | 
 |     static DataInitializer *create(VariableDeclarationList *VDL, | 
 |                                    Args &&... TheArgs) { | 
 |       return new (VDL->allocate_initializer<DataInitializer>()) | 
 |           DataInitializer(VDL, std::forward<Args>(TheArgs)...); | 
 |     } | 
 |  | 
 |     const llvm::StringRef getContents() const { | 
 |       return llvm::StringRef(Contents, ContentsSize); | 
 |     } | 
 |     SizeT getNumBytes() const final { return ContentsSize; } | 
 |     void dump(Ostream &Stream) const final; | 
 |     static bool classof(const Initializer *D) { | 
 |       return D->getKind() == DataInitializerKind; | 
 |     } | 
 |  | 
 |   private: | 
 |     DataInitializer(VariableDeclarationList *VDL, | 
 |                     const llvm::NaClBitcodeRecord::RecordVector &Values) | 
 |         : Initializer(DataInitializerKind), ContentsSize(Values.size()), | 
 |           // ugh, we should actually do new char[], but this may involve | 
 |           // implementation-specific details. Given that Contents is arena | 
 |           // allocated, and never delete[]d, just use char -- | 
 |           // AllocOwner->allocate_array will allocate a buffer with the right | 
 |           // size. | 
 |           Contents(new (VDL->allocate_initializer<char>(ContentsSize)) char) { | 
 |       for (SizeT I = 0; I < Values.size(); ++I) | 
 |         Contents[I] = static_cast<int8_t>(Values[I]); | 
 |     } | 
 |  | 
 |     DataInitializer(VariableDeclarationList *VDL, const char *Str, | 
 |                     size_t StrLen) | 
 |         : Initializer(DataInitializerKind), ContentsSize(StrLen), | 
 |           Contents(new (VDL->allocate_initializer<char>(ContentsSize)) char) { | 
 |       for (size_t i = 0; i < StrLen; ++i) | 
 |         Contents[i] = Str[i]; | 
 |     } | 
 |  | 
 |     /// The byte contents of the data initializer. | 
 |     const SizeT ContentsSize; | 
 |     DataVecType Contents; | 
 |   }; | 
 |   static_assert(std::is_trivially_destructible<DataInitializer>::value, | 
 |                 "DataInitializer must be trivially destructible."); | 
 |  | 
 |   /// Defines a sequence of bytes initialized to zero. | 
 |   class ZeroInitializer : public Initializer { | 
 |     ZeroInitializer(const ZeroInitializer &) = delete; | 
 |     ZeroInitializer &operator=(const ZeroInitializer &) = delete; | 
 |  | 
 |   public: | 
 |     static ZeroInitializer *create(VariableDeclarationList *VDL, SizeT Size) { | 
 |       return new (VDL->allocate_initializer<ZeroInitializer>()) | 
 |           ZeroInitializer(Size); | 
 |     } | 
 |     SizeT getNumBytes() const final { return Size; } | 
 |     void dump(Ostream &Stream) const final; | 
 |     static bool classof(const Initializer *Z) { | 
 |       return Z->getKind() == ZeroInitializerKind; | 
 |     } | 
 |  | 
 |   private: | 
 |     explicit ZeroInitializer(SizeT Size) | 
 |         : Initializer(ZeroInitializerKind), Size(Size) {} | 
 |  | 
 |     /// The number of bytes to be zero initialized. | 
 |     SizeT Size; | 
 |   }; | 
 |   static_assert(std::is_trivially_destructible<ZeroInitializer>::value, | 
 |                 "ZeroInitializer must be trivially destructible."); | 
 |  | 
 |   /// Defines the relocation value of another global declaration. | 
 |   class RelocInitializer : public Initializer { | 
 |     RelocInitializer(const RelocInitializer &) = delete; | 
 |     RelocInitializer &operator=(const RelocInitializer &) = delete; | 
 |  | 
 |   public: | 
 |     static RelocInitializer *create(VariableDeclarationList *VDL, | 
 |                                     const GlobalDeclaration *Declaration, | 
 |                                     const RelocOffsetArray &OffsetExpr) { | 
 |       constexpr bool NoFixup = false; | 
 |       return new (VDL->allocate_initializer<RelocInitializer>()) | 
 |           RelocInitializer(VDL, Declaration, OffsetExpr, NoFixup); | 
 |     } | 
 |  | 
 |     static RelocInitializer *create(VariableDeclarationList *VDL, | 
 |                                     const GlobalDeclaration *Declaration, | 
 |                                     const RelocOffsetArray &OffsetExpr, | 
 |                                     FixupKind Fixup) { | 
 |       constexpr bool HasFixup = true; | 
 |       return new (VDL->allocate_initializer<RelocInitializer>()) | 
 |           RelocInitializer(VDL, Declaration, OffsetExpr, HasFixup, Fixup); | 
 |     } | 
 |  | 
 |     RelocOffsetT getOffset() const { | 
 |       RelocOffsetT Offset = 0; | 
 |       for (SizeT i = 0; i < OffsetExprSize; ++i) { | 
 |         Offset += OffsetExpr[i]->getOffset(); | 
 |       } | 
 |       return Offset; | 
 |     } | 
 |  | 
 |     bool hasFixup() const { return HasFixup; } | 
 |     FixupKind getFixup() const { | 
 |       assert(HasFixup); | 
 |       return Fixup; | 
 |     } | 
 |  | 
 |     const GlobalDeclaration *getDeclaration() const { return Declaration; } | 
 |     SizeT getNumBytes() const final { return RelocAddrSize; } | 
 |     void dump(Ostream &Stream) const final; | 
 |     void dumpType(Ostream &Stream) const final; | 
 |     static bool classof(const Initializer *R) { | 
 |       return R->getKind() == RelocInitializerKind; | 
 |     } | 
 |  | 
 |   private: | 
 |     RelocInitializer(VariableDeclarationList *VDL, | 
 |                      const GlobalDeclaration *Declaration, | 
 |                      const RelocOffsetArray &OffsetExpr, bool HasFixup, | 
 |                      FixupKind Fixup = 0) | 
 |         : Initializer(RelocInitializerKind), | 
 |           Declaration(Declaration), // The global declaration used in the reloc. | 
 |           OffsetExprSize(OffsetExpr.size()), | 
 |           OffsetExpr(new (VDL->allocate_initializer<RelocOffset *>( | 
 |               OffsetExprSize)) RelocOffset *), | 
 |           HasFixup(HasFixup), Fixup(Fixup) { | 
 |       for (SizeT i = 0; i < OffsetExprSize; ++i) { | 
 |         this->OffsetExpr[i] = OffsetExpr[i]; | 
 |       } | 
 |     } | 
 |  | 
 |     const GlobalDeclaration *Declaration; | 
 |     /// The offset to add to the relocation. | 
 |     const SizeT OffsetExprSize; | 
 |     RelocOffset **OffsetExpr; | 
 |     const bool HasFixup = false; | 
 |     const FixupKind Fixup = 0; | 
 |   }; | 
 |   static_assert(std::is_trivially_destructible<RelocInitializer>::value, | 
 |                 "RelocInitializer must be trivially destructible."); | 
 |  | 
 |   /// Models the list of initializers. | 
 |   // TODO(jpp): missing allocator. | 
 |   using InitializerListType = std::vector<Initializer *>; | 
 |  | 
 |   static VariableDeclaration *create(VariableDeclarationList *VDL, | 
 |                                      bool SuppressMangling = false, | 
 |                                      llvm::GlobalValue::LinkageTypes Linkage = | 
 |                                          llvm::GlobalValue::InternalLinkage) { | 
 |     return new (VDL->allocate_variable_declaration<VariableDeclaration>()) | 
 |         VariableDeclaration(Linkage, SuppressMangling); | 
 |   } | 
 |  | 
 |   static VariableDeclaration *createExternal(VariableDeclarationList *VDL) { | 
 |     constexpr bool SuppressMangling = true; | 
 |     constexpr llvm::GlobalValue::LinkageTypes Linkage = | 
 |         llvm::GlobalValue::ExternalLinkage; | 
 |     return create(VDL, SuppressMangling, Linkage); | 
 |   } | 
 |  | 
 |   const InitializerListType &getInitializers() const { return Initializers; } | 
 |   bool getIsConstant() const { return IsConstant; } | 
 |   void setIsConstant(bool NewValue) { IsConstant = NewValue; } | 
 |   uint32_t getAlignment() const { return Alignment; } | 
 |   void setAlignment(uint32_t NewAlignment) { Alignment = NewAlignment; } | 
 |   bool hasInitializer() const { return HasInitializer; } | 
 |   bool hasNonzeroInitializer() const { | 
 |     return !(Initializers.size() == 1 && | 
 |              llvm::isa<ZeroInitializer>(Initializers[0])); | 
 |   } | 
 |  | 
 |   /// Returns the number of bytes for the initializer of the global address. | 
 |   SizeT getNumBytes() const { | 
 |     SizeT Count = 0; | 
 |     for (const auto *Init : Initializers) { | 
 |       Count += Init->getNumBytes(); | 
 |     } | 
 |     return Count; | 
 |   } | 
 |  | 
 |   /// Adds Initializer to the list of initializers. Takes ownership of the | 
 |   /// initializer. | 
 |   void addInitializer(Initializer *Initializer) { | 
 |     const bool OldSuppressMangling = getSuppressMangling(); | 
 |     Initializers.emplace_back(Initializer); | 
 |     HasInitializer = true; | 
 |     // The getSuppressMangling() logic depends on whether the global variable | 
 |     // has initializers.  If its value changed as a result of adding an | 
 |     // initializer, then make sure we haven't previously set the name based on | 
 |     // faulty SuppressMangling logic. | 
 |     const bool SameMangling = (OldSuppressMangling == getSuppressMangling()); | 
 |     (void)SameMangling; | 
 |     assert(Name.hasStdString() || SameMangling); | 
 |   } | 
 |  | 
 |   /// Prints out type for initializer associated with the declaration to Stream. | 
 |   void dumpType(Ostream &Stream) const final; | 
 |  | 
 |   /// Prints out the definition of the global variable declaration (including | 
 |   /// initialization). | 
 |   virtual void dump(Ostream &Stream) const override; | 
 |  | 
 |   /// Returns true if linkage is correct for the variable declaration. | 
 |   bool verifyLinkageCorrect() const { | 
 |     if (getName().hasStdString()) { | 
 |       if (isPNaClABIExternalName(getName().toString())) { | 
 |         return Linkage == llvm::GlobalValue::ExternalLinkage; | 
 |       } | 
 |     } | 
 |     return verifyLinkageDefault(); | 
 |   } | 
 |  | 
 |   static bool classof(const GlobalDeclaration *Addr) { | 
 |     return Addr->getKind() == VariableDeclarationKind; | 
 |   } | 
 |  | 
 |   bool getSuppressMangling() const final { | 
 |     if (ForceSuppressMangling) | 
 |       return true; | 
 |     return isExternal() && !hasInitializer(); | 
 |   } | 
 |  | 
 |   void discardInitializers() { Initializers.clear(); } | 
 |  | 
 |   bool isPNaClABIExternalName(const std::string &Name) const override { | 
 |     return Name == "__pnacl_pso_root"; | 
 |   } | 
 |  | 
 | private: | 
 |   /// List of initializers for the declared variable. | 
 |   InitializerListType Initializers; | 
 |   bool HasInitializer = false; | 
 |   /// The alignment of the declared variable. | 
 |   uint32_t Alignment = 0; | 
 |   /// True if a declared (global) constant. | 
 |   bool IsConstant = false; | 
 |   /// If set to true, force getSuppressMangling() to return true. | 
 |   const bool ForceSuppressMangling; | 
 |  | 
 |   VariableDeclaration(llvm::GlobalValue::LinkageTypes Linkage, | 
 |                       bool SuppressMangling) | 
 |       : GlobalDeclaration(VariableDeclarationKind, Linkage), | 
 |         ForceSuppressMangling(SuppressMangling) {} | 
 | }; | 
 |  | 
 | template <class StreamType> | 
 | inline StreamType &operator<<(StreamType &Stream, | 
 |                               const VariableDeclaration::Initializer &Init) { | 
 |   Init.dump(Stream); | 
 |   return Stream; | 
 | } | 
 |  | 
 | template <class StreamType> | 
 | inline StreamType &operator<<(StreamType &Stream, | 
 |                               const GlobalDeclaration &Addr) { | 
 |   Addr.dump(Stream); | 
 |   return Stream; | 
 | } | 
 |  | 
 | } // end of namespace Ice | 
 |  | 
 | #endif // SUBZERO_SRC_ICEGLOBALINITS_H |