Home | History | Annotate | Download | only in src
      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   };
     63   GlobalDeclarationKind getKind() const { return Kind; }
     64   GlobalString getName() const { return Name; }
     65   void setName(GlobalContext *Ctx, const std::string &NewName) {
     66     Name = Ctx->getGlobalString(getSuppressMangling() ? NewName
     67                                                       : mangleName(NewName));
     68   }
     69   void setName(GlobalString NewName) { Name = NewName; }
     70   void setName(GlobalContext *Ctx) {
     71     Name = GlobalString::createWithoutString(Ctx);
     72   }
     73   bool hasName() const { return Name.hasStdString(); }
     74   bool isInternal() const {
     75     return Linkage == llvm::GlobalValue::InternalLinkage;
     76   }
     77   llvm::GlobalValue::LinkageTypes getLinkage() const { return Linkage; }
     78   void setLinkage(llvm::GlobalValue::LinkageTypes L) {
     79     assert(!hasName());
     80     Linkage = L;
     81   }
     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.
     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:
    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.
    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:
    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   }
    144   const FuncSigType &getSignature() const { return Signature; }
    145   llvm::CallingConv::ID getCallingConv() const { return CallingConv; }
    146   /// isProto implies that there isn't a (local) definition for the function.
    147   bool isProto() const { return IsProto; }
    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;
    153   bool getSuppressMangling() const final { return isExternal() && IsProto; }
    154 
    155   /// Returns true if linkage is correct for the function declaration.
    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.
    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 *
    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 
    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 
    203   bool isPNaClABIExternalName(const std::string &Name) const override {
    204     return Name == "_start";
    205   }
    206 
    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     };
    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:
    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>
    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 
    267     const llvm::StringRef getContents() const {
    268       return llvm::StringRef(Contents, ContentsSize);
    269     }
    270     SizeT getNumBytes() const final { return ContentsSize; }
    271     void dump(Ostream &Stream) const final;
    272     static bool classof(const Initializer *D) {
    273       return D->getKind() == DataInitializerKind;
    274     }
    275 
    276   private:
    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 
    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:
    311     static ZeroInitializer *create(VariableDeclarationList *VDL, SizeT Size) {
    312       return new (VDL->allocate_initializer<ZeroInitializer>())
    313           ZeroInitializer(Size);
    314     }
    315     SizeT getNumBytes() const final { return Size; }
    316     void dump(Ostream &Stream) const final;
    317     static bool classof(const Initializer *Z) {
    318       return Z->getKind() == ZeroInitializerKind;
    319     }
    320 
    321   private:
    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:
    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 
    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 
    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 
    362     bool hasFixup() const { return HasFixup; }
    363     FixupKind getFixup() const {
    364       assert(HasFixup);
    365       return Fixup;
    366     }
    367 
    368     const GlobalDeclaration *getDeclaration() const { return Declaration; }
    369     SizeT getNumBytes() const final { return RelocAddrSize; }
    370     void dump(Ostream &Stream) const final;
    371     void dumpType(Ostream &Stream) const final;
    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)
    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 
    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 
    421   const InitializerListType &getInitializers() const { return Initializers; }
    422   bool getIsConstant() const { return IsConstant; }
    423   void setIsConstant(bool NewValue) { IsConstant = NewValue; }
    424   uint32_t getAlignment() const { return Alignment; }
    425   void setAlignment(uint32_t NewAlignment) { Alignment = NewAlignment; }
    426   bool hasInitializer() const { return HasInitializer; }
    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.
    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.
    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.
    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 
    473   static bool classof(const GlobalDeclaration *Addr) {
    474     return Addr->getKind() == VariableDeclarationKind;
    475   }
    476 
    477   bool getSuppressMangling() const final {
    478     if (ForceSuppressMangling)
    479       return true;
    480     return isExternal() && !hasInitializer();
    481   }
    482 
    483   void discardInitializers() { Initializers.clear(); }
    484 
    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 
    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