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
49namespace Ice {
50
51/// Base class for global variable and function declarations.
52class GlobalDeclaration {
53  GlobalDeclaration() = delete;
54  GlobalDeclaration(const GlobalDeclaration &) = delete;
55  GlobalDeclaration &operator=(const GlobalDeclaration &) = delete;
56
57public:
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
105protected:
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.
130class FunctionDeclaration : public GlobalDeclaration {
131  FunctionDeclaration() = delete;
132  FunctionDeclaration(const FunctionDeclaration &) = delete;
133  FunctionDeclaration &operator=(const FunctionDeclaration &) = delete;
134
135public:
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
192private:
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.
220class VariableDeclaration : public GlobalDeclaration {
221  VariableDeclaration(const VariableDeclaration &) = delete;
222  VariableDeclaration &operator=(const VariableDeclaration &) = delete;
223
224public:
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
489private:
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
506template <class StreamType>
507inline StreamType &operator<<(StreamType &Stream,
508                              const VariableDeclaration::Initializer &Init) {
509  Init.dump(Stream);
510  return Stream;
511}
512
513template <class StreamType>
514inline 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