|  | //===- 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 |