Karl Schimpf | 9d98d79 | 2014-10-13 15:01:08 -0700 | [diff] [blame] | 1 | //===- subzero/src/IceGlobalInits.h - Global declarations -------*- C++ -*-===// |
Karl Schimpf | e3f64d0 | 2014-10-07 10:38:22 -0700 | [diff] [blame] | 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 | //===----------------------------------------------------------------------===// |
Andrew Scull | 9612d32 | 2015-07-06 14:53:25 -0700 | [diff] [blame] | 9 | /// |
| 10 | /// \file |
Jim Stichnoth | 92a6e5b | 2015-12-02 16:52:44 -0800 | [diff] [blame] | 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. |
Andrew Scull | 9612d32 | 2015-07-06 14:53:25 -0700 | [diff] [blame] | 16 | /// |
Karl Schimpf | e3f64d0 | 2014-10-07 10:38:22 -0700 | [diff] [blame] | 17 | //===----------------------------------------------------------------------===// |
| 18 | |
| 19 | #ifndef SUBZERO_SRC_ICEGLOBALINITS_H |
| 20 | #define SUBZERO_SRC_ICEGLOBALINITS_H |
| 21 | |
John Porto | 67f8de9 | 2015-06-25 10:14:17 -0700 | [diff] [blame] | 22 | #include "IceDefs.h" |
John Porto | dc61925 | 2016-02-10 15:57:16 -0800 | [diff] [blame] | 23 | #include "IceFixups.h" |
John Porto | 67f8de9 | 2015-06-25 10:14:17 -0700 | [diff] [blame] | 24 | #include "IceGlobalContext.h" |
Karl Schimpf | bba7768 | 2016-01-15 07:33:15 -0800 | [diff] [blame] | 25 | #include "IceIntrinsics.h" |
Jim Stichnoth | 98ba006 | 2016-03-07 09:26:22 -0800 | [diff] [blame] | 26 | #include "IceMangling.h" |
John Porto | 844211e | 2016-02-04 08:42:48 -0800 | [diff] [blame] | 27 | #include "IceOperand.h" |
John Porto | 67f8de9 | 2015-06-25 10:14:17 -0700 | [diff] [blame] | 28 | #include "IceTypes.h" |
Jim Stichnoth | 98da966 | 2015-06-27 06:38:08 -0700 | [diff] [blame] | 29 | |
Jim Stichnoth | b0051df | 2016-01-13 11:39:15 -0800 | [diff] [blame] | 30 | #ifdef __clang__ |
Jim Stichnoth | 98da966 | 2015-06-27 06:38:08 -0700 | [diff] [blame] | 31 | #pragma clang diagnostic push |
| 32 | #pragma clang diagnostic ignored "-Wunused-parameter" |
Jim Stichnoth | b0051df | 2016-01-13 11:39:15 -0800 | [diff] [blame] | 33 | #endif // __clang__ |
| 34 | |
John Porto | 1bec8bc | 2015-06-22 10:51:13 -0700 | [diff] [blame] | 35 | #include "llvm/Bitcode/NaCl/NaClBitcodeParser.h" // for NaClBitcodeRecord. |
Karl Schimpf | 9d98d79 | 2014-10-13 15:01:08 -0700 | [diff] [blame] | 36 | #include "llvm/IR/CallingConv.h" |
John Porto | 1bec8bc | 2015-06-22 10:51:13 -0700 | [diff] [blame] | 37 | #include "llvm/IR/GlobalValue.h" // for GlobalValue::LinkageTypes. |
Jim Stichnoth | b0051df | 2016-01-13 11:39:15 -0800 | [diff] [blame] | 38 | |
| 39 | #ifdef __clang__ |
Jim Stichnoth | 98da966 | 2015-06-27 06:38:08 -0700 | [diff] [blame] | 40 | #pragma clang diagnostic pop |
Jim Stichnoth | b0051df | 2016-01-13 11:39:15 -0800 | [diff] [blame] | 41 | #endif // __clang__ |
Karl Schimpf | e3f64d0 | 2014-10-07 10:38:22 -0700 | [diff] [blame] | 42 | |
John Porto | 67f8de9 | 2015-06-25 10:14:17 -0700 | [diff] [blame] | 43 | #include <memory> |
| 44 | #include <utility> |
Karl Schimpf | 9d98d79 | 2014-10-13 15:01:08 -0700 | [diff] [blame] | 45 | |
| 46 | // TODO(kschimpf): Remove ourselves from using LLVM representation for calling |
| 47 | // conventions and linkage types. |
Karl Schimpf | e3f64d0 | 2014-10-07 10:38:22 -0700 | [diff] [blame] | 48 | |
| 49 | namespace Ice { |
| 50 | |
Karl Schimpf | 9d98d79 | 2014-10-13 15:01:08 -0700 | [diff] [blame] | 51 | /// Base class for global variable and function declarations. |
| 52 | class GlobalDeclaration { |
Jim Stichnoth | c6ead20 | 2015-02-24 09:30:30 -0800 | [diff] [blame] | 53 | GlobalDeclaration() = delete; |
Karl Schimpf | 9d98d79 | 2014-10-13 15:01:08 -0700 | [diff] [blame] | 54 | GlobalDeclaration(const GlobalDeclaration &) = delete; |
| 55 | GlobalDeclaration &operator=(const GlobalDeclaration &) = delete; |
Karl Schimpf | e3f64d0 | 2014-10-07 10:38:22 -0700 | [diff] [blame] | 56 | |
| 57 | public: |
Karl Schimpf | 9d98d79 | 2014-10-13 15:01:08 -0700 | [diff] [blame] | 58 | /// Discriminator for LLVM-style RTTI. |
| 59 | enum GlobalDeclarationKind { |
| 60 | FunctionDeclarationKind, |
| 61 | VariableDeclarationKind |
| 62 | }; |
| 63 | GlobalDeclarationKind getKind() const { return Kind; } |
Jim Stichnoth | 467ffe5 | 2016-03-29 15:01:06 -0700 | [diff] [blame] | 64 | GlobalString getName() const { return Name; } |
| 65 | void setName(GlobalContext *Ctx, const std::string &NewName) { |
| 66 | Name = Ctx->getGlobalString(getSuppressMangling() ? NewName |
| 67 | : mangleName(NewName)); |
Jim Stichnoth | 98ba006 | 2016-03-07 09:26:22 -0800 | [diff] [blame] | 68 | } |
Jim Stichnoth | 467ffe5 | 2016-03-29 15:01:06 -0700 | [diff] [blame] | 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(); } |
Karl Schimpf | df6f9d1 | 2014-10-20 14:09:00 -0700 | [diff] [blame] | 74 | bool isInternal() const { |
| 75 | return Linkage == llvm::GlobalValue::InternalLinkage; |
| 76 | } |
| 77 | llvm::GlobalValue::LinkageTypes getLinkage() const { return Linkage; } |
Sean Klein | 0a3c523 | 2016-03-11 09:49:36 -0800 | [diff] [blame] | 78 | void setLinkage(llvm::GlobalValue::LinkageTypes L) { |
| 79 | assert(!hasName()); |
| 80 | Linkage = L; |
| 81 | } |
Karl Schimpf | df6f9d1 | 2014-10-20 14:09:00 -0700 | [diff] [blame] | 82 | bool isExternal() const { |
| 83 | return Linkage == llvm::GlobalValue::ExternalLinkage; |
| 84 | } |
Jim Stichnoth | eafb56c | 2015-06-22 10:35:22 -0700 | [diff] [blame] | 85 | virtual ~GlobalDeclaration() = default; |
Karl Schimpf | 9d98d79 | 2014-10-13 15:01:08 -0700 | [diff] [blame] | 86 | |
Karl Schimpf | 9d98d79 | 2014-10-13 15:01:08 -0700 | [diff] [blame] | 87 | /// Prints out type of the global declaration. |
| 88 | virtual void dumpType(Ostream &Stream) const = 0; |
| 89 | |
| 90 | /// Prints out the global declaration. |
Jim Stichnoth | 98ba006 | 2016-03-07 09:26:22 -0800 | [diff] [blame] | 91 | virtual void dump(Ostream &Stream) const = 0; |
Karl Schimpf | df6f9d1 | 2014-10-20 14:09:00 -0700 | [diff] [blame] | 92 | |
| 93 | /// Returns true if when emitting names, we should suppress mangling. |
| 94 | virtual bool getSuppressMangling() const = 0; |
Karl Schimpf | 9d98d79 | 2014-10-13 15:01:08 -0700 | [diff] [blame] | 95 | |
Karl Schimpf | 57d31ac | 2015-10-07 09:53:12 -0700 | [diff] [blame] | 96 | /// Returns textual name of linkage. |
| 97 | const char *getLinkageName() const { |
| 98 | return isInternal() ? "internal" : "external"; |
| 99 | } |
| 100 | |
Sean Klein | 0a3c523 | 2016-03-11 09:49:36 -0800 | [diff] [blame] | 101 | /// Returns true if the name of this GlobalDeclaration indicates that it |
| 102 | /// should have ExternalLinkage (as a special case). |
Jim Stichnoth | 467ffe5 | 2016-03-29 15:01:06 -0700 | [diff] [blame] | 103 | virtual bool isPNaClABIExternalName(const std::string &Name) const = 0; |
Sean Klein | 0a3c523 | 2016-03-11 09:49:36 -0800 | [diff] [blame] | 104 | |
Karl Schimpf | 9d98d79 | 2014-10-13 15:01:08 -0700 | [diff] [blame] | 105 | protected: |
Karl Schimpf | df6f9d1 | 2014-10-20 14:09:00 -0700 | [diff] [blame] | 106 | GlobalDeclaration(GlobalDeclarationKind Kind, |
| 107 | llvm::GlobalValue::LinkageTypes Linkage) |
| 108 | : Kind(Kind), Linkage(Linkage) {} |
Karl Schimpf | 9d98d79 | 2014-10-13 15:01:08 -0700 | [diff] [blame] | 109 | |
Karl Schimpf | 57d31ac | 2015-10-07 09:53:12 -0700 | [diff] [blame] | 110 | /// Returns true if linkage is defined correctly for the global declaration, |
| 111 | /// based on default rules. |
Karl Schimpf | d469994 | 2016-04-02 09:55:31 -0700 | [diff] [blame] | 112 | bool verifyLinkageDefault() const { |
Karl Schimpf | 57d31ac | 2015-10-07 09:53:12 -0700 | [diff] [blame] | 113 | switch (Linkage) { |
| 114 | default: |
| 115 | return false; |
| 116 | case llvm::GlobalValue::InternalLinkage: |
| 117 | return true; |
| 118 | case llvm::GlobalValue::ExternalLinkage: |
Karl Schimpf | d469994 | 2016-04-02 09:55:31 -0700 | [diff] [blame] | 119 | return getFlags().getAllowExternDefinedSymbols(); |
Karl Schimpf | 57d31ac | 2015-10-07 09:53:12 -0700 | [diff] [blame] | 120 | } |
| 121 | } |
| 122 | |
Karl Schimpf | 9d98d79 | 2014-10-13 15:01:08 -0700 | [diff] [blame] | 123 | const GlobalDeclarationKind Kind; |
Sean Klein | 0a3c523 | 2016-03-11 09:49:36 -0800 | [diff] [blame] | 124 | llvm::GlobalValue::LinkageTypes Linkage; |
Jim Stichnoth | 467ffe5 | 2016-03-29 15:01:06 -0700 | [diff] [blame] | 125 | GlobalString Name; |
Karl Schimpf | 9d98d79 | 2014-10-13 15:01:08 -0700 | [diff] [blame] | 126 | }; |
| 127 | |
Andrew Scull | 57e1268 | 2015-09-16 11:30:19 -0700 | [diff] [blame] | 128 | /// Models a function declaration. This includes the type signature of the |
| 129 | /// function, its calling conventions, and its linkage. |
Karl Schimpf | 9d98d79 | 2014-10-13 15:01:08 -0700 | [diff] [blame] | 130 | class FunctionDeclaration : public GlobalDeclaration { |
Jim Stichnoth | c6ead20 | 2015-02-24 09:30:30 -0800 | [diff] [blame] | 131 | FunctionDeclaration() = delete; |
Karl Schimpf | 9d98d79 | 2014-10-13 15:01:08 -0700 | [diff] [blame] | 132 | FunctionDeclaration(const FunctionDeclaration &) = delete; |
| 133 | FunctionDeclaration &operator=(const FunctionDeclaration &) = delete; |
Karl Schimpf | 9d98d79 | 2014-10-13 15:01:08 -0700 | [diff] [blame] | 134 | |
| 135 | public: |
John Porto | 1bec8bc | 2015-06-22 10:51:13 -0700 | [diff] [blame] | 136 | static FunctionDeclaration *create(GlobalContext *Context, |
| 137 | const FuncSigType &Signature, |
Karl Schimpf | 9d98d79 | 2014-10-13 15:01:08 -0700 | [diff] [blame] | 138 | llvm::CallingConv::ID CallingConv, |
| 139 | llvm::GlobalValue::LinkageTypes Linkage, |
John Porto | 1bec8bc | 2015-06-22 10:51:13 -0700 | [diff] [blame] | 140 | bool IsProto) { |
| 141 | return new (Context->allocate<FunctionDeclaration>()) |
| 142 | FunctionDeclaration(Signature, CallingConv, Linkage, IsProto); |
| 143 | } |
Karl Schimpf | 9d98d79 | 2014-10-13 15:01:08 -0700 | [diff] [blame] | 144 | const FuncSigType &getSignature() const { return Signature; } |
| 145 | llvm::CallingConv::ID getCallingConv() const { return CallingConv; } |
Andrew Scull | 9612d32 | 2015-07-06 14:53:25 -0700 | [diff] [blame] | 146 | /// isProto implies that there isn't a (local) definition for the function. |
Karl Schimpf | 9d98d79 | 2014-10-13 15:01:08 -0700 | [diff] [blame] | 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; |
Jim Stichnoth | 98ba006 | 2016-03-07 09:26:22 -0800 | [diff] [blame] | 152 | void dump(Ostream &Stream) const final; |
Jim Stichnoth | dd842db | 2015-01-27 12:53:53 -0800 | [diff] [blame] | 153 | bool getSuppressMangling() const final { return isExternal() && IsProto; } |
Karl Schimpf | 9d98d79 | 2014-10-13 15:01:08 -0700 | [diff] [blame] | 154 | |
Karl Schimpf | 57d31ac | 2015-10-07 09:53:12 -0700 | [diff] [blame] | 155 | /// Returns true if linkage is correct for the function declaration. |
| 156 | bool verifyLinkageCorrect(const GlobalContext *Ctx) const { |
Jim Stichnoth | 467ffe5 | 2016-03-29 15:01:06 -0700 | [diff] [blame] | 157 | if (getName().hasStdString()) { |
| 158 | if (isPNaClABIExternalName(getName().toString()) || |
| 159 | isIntrinsicName(Ctx)) { |
| 160 | return Linkage == llvm::GlobalValue::ExternalLinkage; |
| 161 | } |
Sean Klein | 0a3c523 | 2016-03-11 09:49:36 -0800 | [diff] [blame] | 162 | } |
Karl Schimpf | d469994 | 2016-04-02 09:55:31 -0700 | [diff] [blame] | 163 | return verifyLinkageDefault(); |
Karl Schimpf | 57d31ac | 2015-10-07 09:53:12 -0700 | [diff] [blame] | 164 | } |
| 165 | |
Karl Schimpf | bba7768 | 2016-01-15 07:33:15 -0800 | [diff] [blame] | 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. |
Jim Stichnoth | 467ffe5 | 2016-03-29 15:01:06 -0700 | [diff] [blame] | 178 | std::string getTypeSignatureError(const GlobalContext *Ctx); |
Karl Schimpf | bba7768 | 2016-01-15 07:33:15 -0800 | [diff] [blame] | 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 | |
Karl Schimpf | 9d98d79 | 2014-10-13 15:01:08 -0700 | [diff] [blame] | 192 | private: |
| 193 | const Ice::FuncSigType Signature; |
| 194 | llvm::CallingConv::ID CallingConv; |
Jim Stichnoth | 98ba006 | 2016-03-07 09:26:22 -0800 | [diff] [blame] | 195 | const bool IsProto; |
Karl Schimpf | 9d98d79 | 2014-10-13 15:01:08 -0700 | [diff] [blame] | 196 | |
| 197 | FunctionDeclaration(const FuncSigType &Signature, |
| 198 | llvm::CallingConv::ID CallingConv, |
| 199 | llvm::GlobalValue::LinkageTypes Linkage, bool IsProto) |
Karl Schimpf | df6f9d1 | 2014-10-20 14:09:00 -0700 | [diff] [blame] | 200 | : GlobalDeclaration(FunctionDeclarationKind, Linkage), |
| 201 | Signature(Signature), CallingConv(CallingConv), IsProto(IsProto) {} |
Karl Schimpf | 57d31ac | 2015-10-07 09:53:12 -0700 | [diff] [blame] | 202 | |
Jim Stichnoth | 467ffe5 | 2016-03-29 15:01:06 -0700 | [diff] [blame] | 203 | bool isPNaClABIExternalName(const std::string &Name) const override { |
Sean Klein | 0a3c523 | 2016-03-11 09:49:36 -0800 | [diff] [blame] | 204 | return Name == "_start"; |
Karl Schimpf | 57d31ac | 2015-10-07 09:53:12 -0700 | [diff] [blame] | 205 | } |
| 206 | |
| 207 | bool isIntrinsicName(const GlobalContext *Ctx) const { |
Karl Schimpf | bba7768 | 2016-01-15 07:33:15 -0800 | [diff] [blame] | 208 | bool IsIntrinsic; |
| 209 | getIntrinsicInfo(Ctx, &IsIntrinsic); |
| 210 | return IsIntrinsic; |
Karl Schimpf | 57d31ac | 2015-10-07 09:53:12 -0700 | [diff] [blame] | 211 | } |
Karl Schimpf | bba7768 | 2016-01-15 07:33:15 -0800 | [diff] [blame] | 212 | |
| 213 | bool validateRegularTypeSignature() const; |
| 214 | |
| 215 | bool validateIntrinsicTypeSignature( |
| 216 | const Intrinsics::FullIntrinsicInfo *Info) const; |
Karl Schimpf | 9d98d79 | 2014-10-13 15:01:08 -0700 | [diff] [blame] | 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; |
Jim Stichnoth | dd842db | 2015-01-27 12:53:53 -0800 | [diff] [blame] | 223 | |
Karl Schimpf | 9d98d79 | 2014-10-13 15:01:08 -0700 | [diff] [blame] | 224 | public: |
Karl Schimpf | e3f64d0 | 2014-10-07 10:38:22 -0700 | [diff] [blame] | 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; } |
Karl Schimpf | e3f64d0 | 2014-10-07 10:38:22 -0700 | [diff] [blame] | 238 | virtual SizeT getNumBytes() const = 0; |
Jim Stichnoth | 98ba006 | 2016-03-07 09:26:22 -0800 | [diff] [blame] | 239 | virtual void dump(Ostream &Stream) const = 0; |
Karl Schimpf | e3f64d0 | 2014-10-07 10:38:22 -0700 | [diff] [blame] | 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 | }; |
John Porto | a78e4ba | 2016-03-15 09:28:04 -0700 | [diff] [blame] | 248 | static_assert(std::is_trivially_destructible<Initializer>::value, |
| 249 | "Initializer must be trivially destructible."); |
Karl Schimpf | e3f64d0 | 2014-10-07 10:38:22 -0700 | [diff] [blame] | 250 | |
Andrew Scull | 9612d32 | 2015-07-06 14:53:25 -0700 | [diff] [blame] | 251 | /// Models the data in a data initializer. |
John Porto | a78e4ba | 2016-03-15 09:28:04 -0700 | [diff] [blame] | 252 | using DataVecType = char *; |
Karl Schimpf | e3f64d0 | 2014-10-07 10:38:22 -0700 | [diff] [blame] | 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: |
John Porto | 1bec8bc | 2015-06-22 10:51:13 -0700 | [diff] [blame] | 260 | template <class... Args> |
John Porto | a78e4ba | 2016-03-15 09:28:04 -0700 | [diff] [blame] | 261 | static DataInitializer *create(VariableDeclarationList *VDL, |
| 262 | Args &&... TheArgs) { |
| 263 | return new (VDL->allocate_initializer<DataInitializer>()) |
| 264 | DataInitializer(VDL, std::forward<Args>(TheArgs)...); |
Karl Schimpf | e3f64d0 | 2014-10-07 10:38:22 -0700 | [diff] [blame] | 265 | } |
John Porto | 1bec8bc | 2015-06-22 10:51:13 -0700 | [diff] [blame] | 266 | |
John Porto | a78e4ba | 2016-03-15 09:28:04 -0700 | [diff] [blame] | 267 | const llvm::StringRef getContents() const { |
| 268 | return llvm::StringRef(Contents, ContentsSize); |
| 269 | } |
| 270 | SizeT getNumBytes() const final { return ContentsSize; } |
Jim Stichnoth | 98ba006 | 2016-03-07 09:26:22 -0800 | [diff] [blame] | 271 | void dump(Ostream &Stream) const final; |
Karl Schimpf | e3f64d0 | 2014-10-07 10:38:22 -0700 | [diff] [blame] | 272 | static bool classof(const Initializer *D) { |
| 273 | return D->getKind() == DataInitializerKind; |
| 274 | } |
| 275 | |
| 276 | private: |
John Porto | a78e4ba | 2016-03-15 09:28:04 -0700 | [diff] [blame] | 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 |
Thomas Lively | 3f5cb6f | 2016-06-13 11:23:29 -0700 | [diff] [blame] | 282 | // allocated, and never delete[]d, just use char -- |
John Porto | a78e4ba | 2016-03-15 09:28:04 -0700 | [diff] [blame] | 283 | // AllocOwner->allocate_array will allocate a buffer with the right |
| 284 | // size. |
| 285 | Contents(new (VDL->allocate_initializer<char>(ContentsSize)) char) { |
John Porto | 1bec8bc | 2015-06-22 10:51:13 -0700 | [diff] [blame] | 286 | for (SizeT I = 0; I < Values.size(); ++I) |
| 287 | Contents[I] = static_cast<int8_t>(Values[I]); |
| 288 | } |
| 289 | |
John Porto | a78e4ba | 2016-03-15 09:28:04 -0700 | [diff] [blame] | 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) { |
John Porto | 1bec8bc | 2015-06-22 10:51:13 -0700 | [diff] [blame] | 294 | for (size_t i = 0; i < StrLen; ++i) |
| 295 | Contents[i] = Str[i]; |
| 296 | } |
| 297 | |
Andrew Scull | 9612d32 | 2015-07-06 14:53:25 -0700 | [diff] [blame] | 298 | /// The byte contents of the data initializer. |
John Porto | a78e4ba | 2016-03-15 09:28:04 -0700 | [diff] [blame] | 299 | const SizeT ContentsSize; |
Karl Schimpf | e3f64d0 | 2014-10-07 10:38:22 -0700 | [diff] [blame] | 300 | DataVecType Contents; |
| 301 | }; |
John Porto | a78e4ba | 2016-03-15 09:28:04 -0700 | [diff] [blame] | 302 | static_assert(std::is_trivially_destructible<DataInitializer>::value, |
| 303 | "DataInitializer must be trivially destructible."); |
Karl Schimpf | e3f64d0 | 2014-10-07 10:38:22 -0700 | [diff] [blame] | 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: |
John Porto | a78e4ba | 2016-03-15 09:28:04 -0700 | [diff] [blame] | 311 | static ZeroInitializer *create(VariableDeclarationList *VDL, SizeT Size) { |
| 312 | return new (VDL->allocate_initializer<ZeroInitializer>()) |
| 313 | ZeroInitializer(Size); |
John Porto | 1bec8bc | 2015-06-22 10:51:13 -0700 | [diff] [blame] | 314 | } |
Karl Schimpf | 9d98d79 | 2014-10-13 15:01:08 -0700 | [diff] [blame] | 315 | SizeT getNumBytes() const final { return Size; } |
Jim Stichnoth | 98ba006 | 2016-03-07 09:26:22 -0800 | [diff] [blame] | 316 | void dump(Ostream &Stream) const final; |
Karl Schimpf | e3f64d0 | 2014-10-07 10:38:22 -0700 | [diff] [blame] | 317 | static bool classof(const Initializer *Z) { |
| 318 | return Z->getKind() == ZeroInitializerKind; |
| 319 | } |
| 320 | |
| 321 | private: |
John Porto | 1bec8bc | 2015-06-22 10:51:13 -0700 | [diff] [blame] | 322 | explicit ZeroInitializer(SizeT Size) |
| 323 | : Initializer(ZeroInitializerKind), Size(Size) {} |
| 324 | |
Andrew Scull | 9612d32 | 2015-07-06 14:53:25 -0700 | [diff] [blame] | 325 | /// The number of bytes to be zero initialized. |
Karl Schimpf | e3f64d0 | 2014-10-07 10:38:22 -0700 | [diff] [blame] | 326 | SizeT Size; |
| 327 | }; |
John Porto | a78e4ba | 2016-03-15 09:28:04 -0700 | [diff] [blame] | 328 | static_assert(std::is_trivially_destructible<ZeroInitializer>::value, |
| 329 | "ZeroInitializer must be trivially destructible."); |
Karl Schimpf | e3f64d0 | 2014-10-07 10:38:22 -0700 | [diff] [blame] | 330 | |
Karl Schimpf | 9d98d79 | 2014-10-13 15:01:08 -0700 | [diff] [blame] | 331 | /// Defines the relocation value of another global declaration. |
Karl Schimpf | e3f64d0 | 2014-10-07 10:38:22 -0700 | [diff] [blame] | 332 | class RelocInitializer : public Initializer { |
| 333 | RelocInitializer(const RelocInitializer &) = delete; |
| 334 | RelocInitializer &operator=(const RelocInitializer &) = delete; |
| 335 | |
| 336 | public: |
John Porto | a78e4ba | 2016-03-15 09:28:04 -0700 | [diff] [blame] | 337 | static RelocInitializer *create(VariableDeclarationList *VDL, |
| 338 | const GlobalDeclaration *Declaration, |
| 339 | const RelocOffsetArray &OffsetExpr) { |
John Porto | dc61925 | 2016-02-10 15:57:16 -0800 | [diff] [blame] | 340 | constexpr bool NoFixup = false; |
John Porto | a78e4ba | 2016-03-15 09:28:04 -0700 | [diff] [blame] | 341 | return new (VDL->allocate_initializer<RelocInitializer>()) |
| 342 | RelocInitializer(VDL, Declaration, OffsetExpr, NoFixup); |
John Porto | dc61925 | 2016-02-10 15:57:16 -0800 | [diff] [blame] | 343 | } |
| 344 | |
John Porto | a78e4ba | 2016-03-15 09:28:04 -0700 | [diff] [blame] | 345 | static RelocInitializer *create(VariableDeclarationList *VDL, |
| 346 | const GlobalDeclaration *Declaration, |
| 347 | const RelocOffsetArray &OffsetExpr, |
| 348 | FixupKind Fixup) { |
John Porto | dc61925 | 2016-02-10 15:57:16 -0800 | [diff] [blame] | 349 | constexpr bool HasFixup = true; |
John Porto | a78e4ba | 2016-03-15 09:28:04 -0700 | [diff] [blame] | 350 | return new (VDL->allocate_initializer<RelocInitializer>()) |
| 351 | RelocInitializer(VDL, Declaration, OffsetExpr, HasFixup, Fixup); |
John Porto | 1bec8bc | 2015-06-22 10:51:13 -0700 | [diff] [blame] | 352 | } |
| 353 | |
John Porto | 844211e | 2016-02-04 08:42:48 -0800 | [diff] [blame] | 354 | RelocOffsetT getOffset() const { |
| 355 | RelocOffsetT Offset = 0; |
John Porto | a78e4ba | 2016-03-15 09:28:04 -0700 | [diff] [blame] | 356 | for (SizeT i = 0; i < OffsetExprSize; ++i) { |
| 357 | Offset += OffsetExpr[i]->getOffset(); |
John Porto | 844211e | 2016-02-04 08:42:48 -0800 | [diff] [blame] | 358 | } |
| 359 | return Offset; |
| 360 | } |
| 361 | |
John Porto | dc61925 | 2016-02-10 15:57:16 -0800 | [diff] [blame] | 362 | bool hasFixup() const { return HasFixup; } |
| 363 | FixupKind getFixup() const { |
| 364 | assert(HasFixup); |
| 365 | return Fixup; |
| 366 | } |
| 367 | |
Karl Schimpf | 9d98d79 | 2014-10-13 15:01:08 -0700 | [diff] [blame] | 368 | const GlobalDeclaration *getDeclaration() const { return Declaration; } |
| 369 | SizeT getNumBytes() const final { return RelocAddrSize; } |
Jim Stichnoth | 98ba006 | 2016-03-07 09:26:22 -0800 | [diff] [blame] | 370 | void dump(Ostream &Stream) const final; |
Karl Schimpf | 9d98d79 | 2014-10-13 15:01:08 -0700 | [diff] [blame] | 371 | void dumpType(Ostream &Stream) const final; |
Karl Schimpf | e3f64d0 | 2014-10-07 10:38:22 -0700 | [diff] [blame] | 372 | static bool classof(const Initializer *R) { |
| 373 | return R->getKind() == RelocInitializerKind; |
| 374 | } |
| 375 | |
| 376 | private: |
John Porto | a78e4ba | 2016-03-15 09:28:04 -0700 | [diff] [blame] | 377 | RelocInitializer(VariableDeclarationList *VDL, |
| 378 | const GlobalDeclaration *Declaration, |
John Porto | dc61925 | 2016-02-10 15:57:16 -0800 | [diff] [blame] | 379 | const RelocOffsetArray &OffsetExpr, bool HasFixup, |
| 380 | FixupKind Fixup = 0) |
John Porto | 844211e | 2016-02-04 08:42:48 -0800 | [diff] [blame] | 381 | : Initializer(RelocInitializerKind), |
| 382 | Declaration(Declaration), // The global declaration used in the reloc. |
John Porto | a78e4ba | 2016-03-15 09:28:04 -0700 | [diff] [blame] | 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 | } |
John Porto | 1bec8bc | 2015-06-22 10:51:13 -0700 | [diff] [blame] | 391 | |
Karl Schimpf | 9d98d79 | 2014-10-13 15:01:08 -0700 | [diff] [blame] | 392 | const GlobalDeclaration *Declaration; |
Andrew Scull | 9612d32 | 2015-07-06 14:53:25 -0700 | [diff] [blame] | 393 | /// The offset to add to the relocation. |
John Porto | a78e4ba | 2016-03-15 09:28:04 -0700 | [diff] [blame] | 394 | const SizeT OffsetExprSize; |
| 395 | RelocOffset **OffsetExpr; |
John Porto | dc61925 | 2016-02-10 15:57:16 -0800 | [diff] [blame] | 396 | const bool HasFixup = false; |
| 397 | const FixupKind Fixup = 0; |
Karl Schimpf | e3f64d0 | 2014-10-07 10:38:22 -0700 | [diff] [blame] | 398 | }; |
John Porto | a78e4ba | 2016-03-15 09:28:04 -0700 | [diff] [blame] | 399 | static_assert(std::is_trivially_destructible<RelocInitializer>::value, |
| 400 | "RelocInitializer must be trivially destructible."); |
Karl Schimpf | e3f64d0 | 2014-10-07 10:38:22 -0700 | [diff] [blame] | 401 | |
| 402 | /// Models the list of initializers. |
John Porto | a78e4ba | 2016-03-15 09:28:04 -0700 | [diff] [blame] | 403 | // TODO(jpp): missing allocator. |
| 404 | using InitializerListType = std::vector<Initializer *>; |
Karl Schimpf | e3f64d0 | 2014-10-07 10:38:22 -0700 | [diff] [blame] | 405 | |
John Porto | a78e4ba | 2016-03-15 09:28:04 -0700 | [diff] [blame] | 406 | static VariableDeclaration *create(VariableDeclarationList *VDL, |
Jim Stichnoth | 98ba006 | 2016-03-07 09:26:22 -0800 | [diff] [blame] | 407 | bool SuppressMangling = false, |
| 408 | llvm::GlobalValue::LinkageTypes Linkage = |
| 409 | llvm::GlobalValue::InternalLinkage) { |
John Porto | a78e4ba | 2016-03-15 09:28:04 -0700 | [diff] [blame] | 410 | return new (VDL->allocate_variable_declaration<VariableDeclaration>()) |
Jim Stichnoth | 98ba006 | 2016-03-07 09:26:22 -0800 | [diff] [blame] | 411 | VariableDeclaration(Linkage, SuppressMangling); |
| 412 | } |
John Porto | a78e4ba | 2016-03-15 09:28:04 -0700 | [diff] [blame] | 413 | |
| 414 | static VariableDeclaration *createExternal(VariableDeclarationList *VDL) { |
Jim Stichnoth | 98ba006 | 2016-03-07 09:26:22 -0800 | [diff] [blame] | 415 | constexpr bool SuppressMangling = true; |
| 416 | constexpr llvm::GlobalValue::LinkageTypes Linkage = |
| 417 | llvm::GlobalValue::ExternalLinkage; |
John Porto | a78e4ba | 2016-03-15 09:28:04 -0700 | [diff] [blame] | 418 | return create(VDL, SuppressMangling, Linkage); |
John Porto | 1bec8bc | 2015-06-22 10:51:13 -0700 | [diff] [blame] | 419 | } |
Karl Schimpf | e3f64d0 | 2014-10-07 10:38:22 -0700 | [diff] [blame] | 420 | |
John Porto | a78e4ba | 2016-03-15 09:28:04 -0700 | [diff] [blame] | 421 | const InitializerListType &getInitializers() const { return Initializers; } |
Karl Schimpf | e3f64d0 | 2014-10-07 10:38:22 -0700 | [diff] [blame] | 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; } |
John Porto | 1bec8bc | 2015-06-22 10:51:13 -0700 | [diff] [blame] | 426 | bool hasInitializer() const { return HasInitializer; } |
Karl Schimpf | df6f9d1 | 2014-10-20 14:09:00 -0700 | [diff] [blame] | 427 | bool hasNonzeroInitializer() const { |
John Porto | a78e4ba | 2016-03-15 09:28:04 -0700 | [diff] [blame] | 428 | return !(Initializers.size() == 1 && |
| 429 | llvm::isa<ZeroInitializer>(Initializers[0])); |
Karl Schimpf | 9d98d79 | 2014-10-13 15:01:08 -0700 | [diff] [blame] | 430 | } |
Karl Schimpf | e3f64d0 | 2014-10-07 10:38:22 -0700 | [diff] [blame] | 431 | |
Andrew Scull | 57e1268 | 2015-09-16 11:30:19 -0700 | [diff] [blame] | 432 | /// Returns the number of bytes for the initializer of the global address. |
Karl Schimpf | e3f64d0 | 2014-10-07 10:38:22 -0700 | [diff] [blame] | 433 | SizeT getNumBytes() const { |
| 434 | SizeT Count = 0; |
John Porto | a78e4ba | 2016-03-15 09:28:04 -0700 | [diff] [blame] | 435 | for (const auto *Init : Initializers) { |
Karl Schimpf | e3f64d0 | 2014-10-07 10:38:22 -0700 | [diff] [blame] | 436 | Count += Init->getNumBytes(); |
| 437 | } |
| 438 | return Count; |
| 439 | } |
| 440 | |
Andrew Scull | 57e1268 | 2015-09-16 11:30:19 -0700 | [diff] [blame] | 441 | /// Adds Initializer to the list of initializers. Takes ownership of the |
| 442 | /// initializer. |
John Porto | a78e4ba | 2016-03-15 09:28:04 -0700 | [diff] [blame] | 443 | void addInitializer(Initializer *Initializer) { |
Jim Stichnoth | 98ba006 | 2016-03-07 09:26:22 -0800 | [diff] [blame] | 444 | const bool OldSuppressMangling = getSuppressMangling(); |
John Porto | a78e4ba | 2016-03-15 09:28:04 -0700 | [diff] [blame] | 445 | Initializers.emplace_back(Initializer); |
John Porto | 1bec8bc | 2015-06-22 10:51:13 -0700 | [diff] [blame] | 446 | HasInitializer = true; |
Jim Stichnoth | 98ba006 | 2016-03-07 09:26:22 -0800 | [diff] [blame] | 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; |
Jim Stichnoth | 467ffe5 | 2016-03-29 15:01:06 -0700 | [diff] [blame] | 453 | assert(Name.hasStdString() || SameMangling); |
Karl Schimpf | e3f64d0 | 2014-10-07 10:38:22 -0700 | [diff] [blame] | 454 | } |
| 455 | |
Andrew Scull | 57e1268 | 2015-09-16 11:30:19 -0700 | [diff] [blame] | 456 | /// Prints out type for initializer associated with the declaration to Stream. |
Karl Schimpf | 9d98d79 | 2014-10-13 15:01:08 -0700 | [diff] [blame] | 457 | void dumpType(Ostream &Stream) const final; |
Karl Schimpf | e3f64d0 | 2014-10-07 10:38:22 -0700 | [diff] [blame] | 458 | |
Andrew Scull | 57e1268 | 2015-09-16 11:30:19 -0700 | [diff] [blame] | 459 | /// Prints out the definition of the global variable declaration (including |
| 460 | /// initialization). |
Sean Klein | 0a3c523 | 2016-03-11 09:49:36 -0800 | [diff] [blame] | 461 | virtual void dump(Ostream &Stream) const override; |
Karl Schimpf | 9d98d79 | 2014-10-13 15:01:08 -0700 | [diff] [blame] | 462 | |
Karl Schimpf | 57d31ac | 2015-10-07 09:53:12 -0700 | [diff] [blame] | 463 | /// Returns true if linkage is correct for the variable declaration. |
Karl Schimpf | d469994 | 2016-04-02 09:55:31 -0700 | [diff] [blame] | 464 | bool verifyLinkageCorrect() const { |
Jim Stichnoth | 467ffe5 | 2016-03-29 15:01:06 -0700 | [diff] [blame] | 465 | if (getName().hasStdString()) { |
| 466 | if (isPNaClABIExternalName(getName().toString())) { |
| 467 | return Linkage == llvm::GlobalValue::ExternalLinkage; |
| 468 | } |
Sean Klein | 0a3c523 | 2016-03-11 09:49:36 -0800 | [diff] [blame] | 469 | } |
Karl Schimpf | d469994 | 2016-04-02 09:55:31 -0700 | [diff] [blame] | 470 | return verifyLinkageDefault(); |
Karl Schimpf | 57d31ac | 2015-10-07 09:53:12 -0700 | [diff] [blame] | 471 | } |
| 472 | |
Karl Schimpf | 9d98d79 | 2014-10-13 15:01:08 -0700 | [diff] [blame] | 473 | static bool classof(const GlobalDeclaration *Addr) { |
| 474 | return Addr->getKind() == VariableDeclarationKind; |
| 475 | } |
| 476 | |
Karl Schimpf | df6f9d1 | 2014-10-20 14:09:00 -0700 | [diff] [blame] | 477 | bool getSuppressMangling() const final { |
Jim Stichnoth | d9f1f9f | 2015-06-11 10:19:32 -0700 | [diff] [blame] | 478 | if (ForceSuppressMangling) |
| 479 | return true; |
Karl Schimpf | df6f9d1 | 2014-10-20 14:09:00 -0700 | [diff] [blame] | 480 | return isExternal() && !hasInitializer(); |
Karl Schimpf | 9d98d79 | 2014-10-13 15:01:08 -0700 | [diff] [blame] | 481 | } |
| 482 | |
John Porto | a78e4ba | 2016-03-15 09:28:04 -0700 | [diff] [blame] | 483 | void discardInitializers() { Initializers.clear(); } |
John Porto | 1bec8bc | 2015-06-22 10:51:13 -0700 | [diff] [blame] | 484 | |
Jim Stichnoth | 467ffe5 | 2016-03-29 15:01:06 -0700 | [diff] [blame] | 485 | bool isPNaClABIExternalName(const std::string &Name) const override { |
Sean Klein | 0a3c523 | 2016-03-11 09:49:36 -0800 | [diff] [blame] | 486 | return Name == "__pnacl_pso_root"; |
| 487 | } |
| 488 | |
Karl Schimpf | e3f64d0 | 2014-10-07 10:38:22 -0700 | [diff] [blame] | 489 | private: |
Andrew Scull | 9612d32 | 2015-07-06 14:53:25 -0700 | [diff] [blame] | 490 | /// List of initializers for the declared variable. |
John Porto | a78e4ba | 2016-03-15 09:28:04 -0700 | [diff] [blame] | 491 | InitializerListType Initializers; |
Jim Stichnoth | 98ba006 | 2016-03-07 09:26:22 -0800 | [diff] [blame] | 492 | bool HasInitializer = false; |
Andrew Scull | 9612d32 | 2015-07-06 14:53:25 -0700 | [diff] [blame] | 493 | /// The alignment of the declared variable. |
Jim Stichnoth | 98ba006 | 2016-03-07 09:26:22 -0800 | [diff] [blame] | 494 | uint32_t Alignment = 0; |
Andrew Scull | 9612d32 | 2015-07-06 14:53:25 -0700 | [diff] [blame] | 495 | /// True if a declared (global) constant. |
Jim Stichnoth | 98ba006 | 2016-03-07 09:26:22 -0800 | [diff] [blame] | 496 | bool IsConstant = false; |
Andrew Scull | 9612d32 | 2015-07-06 14:53:25 -0700 | [diff] [blame] | 497 | /// If set to true, force getSuppressMangling() to return true. |
Jim Stichnoth | 98ba006 | 2016-03-07 09:26:22 -0800 | [diff] [blame] | 498 | const bool ForceSuppressMangling; |
Karl Schimpf | 9d98d79 | 2014-10-13 15:01:08 -0700 | [diff] [blame] | 499 | |
Jim Stichnoth | 98ba006 | 2016-03-07 09:26:22 -0800 | [diff] [blame] | 500 | VariableDeclaration(llvm::GlobalValue::LinkageTypes Linkage, |
| 501 | bool SuppressMangling) |
| 502 | : GlobalDeclaration(VariableDeclarationKind, Linkage), |
Jim Stichnoth | 98ba006 | 2016-03-07 09:26:22 -0800 | [diff] [blame] | 503 | ForceSuppressMangling(SuppressMangling) {} |
Karl Schimpf | e3f64d0 | 2014-10-07 10:38:22 -0700 | [diff] [blame] | 504 | }; |
| 505 | |
| 506 | template <class StreamType> |
| 507 | inline StreamType &operator<<(StreamType &Stream, |
Karl Schimpf | 9d98d79 | 2014-10-13 15:01:08 -0700 | [diff] [blame] | 508 | const VariableDeclaration::Initializer &Init) { |
Karl Schimpf | e3f64d0 | 2014-10-07 10:38:22 -0700 | [diff] [blame] | 509 | Init.dump(Stream); |
| 510 | return Stream; |
| 511 | } |
| 512 | |
| 513 | template <class StreamType> |
Karl Schimpf | 9d98d79 | 2014-10-13 15:01:08 -0700 | [diff] [blame] | 514 | inline StreamType &operator<<(StreamType &Stream, |
| 515 | const GlobalDeclaration &Addr) { |
Karl Schimpf | e3f64d0 | 2014-10-07 10:38:22 -0700 | [diff] [blame] | 516 | Addr.dump(Stream); |
| 517 | return Stream; |
| 518 | } |
| 519 | |
| 520 | } // end of namespace Ice |
| 521 | |
| 522 | #endif // SUBZERO_SRC_ICEGLOBALINITS_H |