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