Jim Stichnoth | c4554d7 | 2014-09-30 16:49:38 -0700 | [diff] [blame] | 1 | //===- subzero/src/IceGlobalContext.cpp - Global context defs -------------===// |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -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 |
| 11 | /// This file defines aspects of the compilation that persist across |
| 12 | /// multiple functions. |
| 13 | /// |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 14 | //===----------------------------------------------------------------------===// |
| 15 | |
John Porto | 67f8de9 | 2015-06-25 10:14:17 -0700 | [diff] [blame] | 16 | #include "IceGlobalContext.h" |
Jim Stichnoth | 639c921 | 2014-12-11 10:04:32 -0800 | [diff] [blame] | 17 | |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 18 | #include "IceCfg.h" |
John Porto | f8b4cc8 | 2015-06-09 18:06:19 -0700 | [diff] [blame] | 19 | #include "IceCfgNode.h" |
Jim Stichnoth | 989a703 | 2014-08-08 10:13:44 -0700 | [diff] [blame] | 20 | #include "IceClFlags.h" |
Jim Stichnoth | a18cc9c | 2014-09-30 19:10:22 -0700 | [diff] [blame] | 21 | #include "IceDefs.h" |
Jan Voung | ec27073 | 2015-01-12 17:00:22 -0800 | [diff] [blame] | 22 | #include "IceELFObjectWriter.h" |
Karl Schimpf | 9d98d79 | 2014-10-13 15:01:08 -0700 | [diff] [blame] | 23 | #include "IceGlobalInits.h" |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 24 | #include "IceOperand.h" |
Jim Stichnoth | 5bc2b1d | 2014-05-22 13:38:48 -0700 | [diff] [blame] | 25 | #include "IceTargetLowering.h" |
Jim Stichnoth | c4554d7 | 2014-09-30 16:49:38 -0700 | [diff] [blame] | 26 | #include "IceTimerTree.h" |
Jim Stichnoth | a18cc9c | 2014-09-30 19:10:22 -0700 | [diff] [blame] | 27 | #include "IceTypes.h" |
Jim Stichnoth | 98da966 | 2015-06-27 06:38:08 -0700 | [diff] [blame] | 28 | |
| 29 | #pragma clang diagnostic push |
| 30 | #pragma clang diagnostic ignored "-Wunused-parameter" |
John Porto | 67f8de9 | 2015-06-25 10:14:17 -0700 | [diff] [blame] | 31 | #include "llvm/Support/Timer.h" |
Jim Stichnoth | 98da966 | 2015-06-27 06:38:08 -0700 | [diff] [blame] | 32 | #pragma clang diagnostic pop |
John Porto | 67f8de9 | 2015-06-25 10:14:17 -0700 | [diff] [blame] | 33 | |
Qining Lu | 7cd5351 | 2015-06-26 09:36:00 -0700 | [diff] [blame] | 34 | #include <algorithm> // max() |
Jan Voung | e0df91f | 2015-06-30 08:47:06 -0700 | [diff] [blame] | 35 | #include <cctype> // isdigit(), isupper() |
| 36 | #include <locale> // locale |
John Porto | 67f8de9 | 2015-06-25 10:14:17 -0700 | [diff] [blame] | 37 | #include <unordered_map> |
| 38 | |
Jim Stichnoth | dddaf9c | 2014-12-04 14:09:21 -0800 | [diff] [blame] | 39 | namespace std { |
| 40 | template <> struct hash<Ice::RelocatableTuple> { |
| 41 | size_t operator()(const Ice::RelocatableTuple &Key) const { |
| 42 | return hash<Ice::IceString>()(Key.Name) + |
| 43 | hash<Ice::RelocOffsetT>()(Key.Offset); |
Jim Stichnoth | d2cb436 | 2014-11-20 11:24:42 -0800 | [diff] [blame] | 44 | } |
| 45 | }; |
Jim Stichnoth | dddaf9c | 2014-12-04 14:09:21 -0800 | [diff] [blame] | 46 | } // end of namespace std |
Jim Stichnoth | d2cb436 | 2014-11-20 11:24:42 -0800 | [diff] [blame] | 47 | |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 48 | namespace Ice { |
| 49 | |
Jim Stichnoth | 5bfe215 | 2015-03-19 13:51:56 -0700 | [diff] [blame] | 50 | namespace { |
| 51 | |
| 52 | // Define the key comparison function for the constant pool's |
| 53 | // unordered_map, but only for key types of interest: integer types, |
| 54 | // floating point types, and the special RelocatableTuple. |
| 55 | template <typename KeyType, class Enable = void> struct KeyCompare {}; |
| 56 | |
| 57 | template <typename KeyType> |
| 58 | struct KeyCompare<KeyType, |
| 59 | typename std::enable_if< |
| 60 | std::is_integral<KeyType>::value || |
| 61 | std::is_same<KeyType, RelocatableTuple>::value>::type> { |
| 62 | bool operator()(const KeyType &Value1, const KeyType &Value2) const { |
| 63 | return Value1 == Value2; |
| 64 | } |
| 65 | }; |
| 66 | template <typename KeyType> |
| 67 | struct KeyCompare<KeyType, typename std::enable_if< |
| 68 | std::is_floating_point<KeyType>::value>::type> { |
| 69 | bool operator()(const KeyType &Value1, const KeyType &Value2) const { |
| 70 | return !memcmp(&Value1, &Value2, sizeof(KeyType)); |
| 71 | } |
| 72 | }; |
| 73 | |
Jim Stichnoth | 6e293c8 | 2015-04-09 09:11:18 -0700 | [diff] [blame] | 74 | // Define a key comparison function for sorting the constant pool's |
| 75 | // values after they are dumped to a vector. This covers integer |
| 76 | // types, floating point types, and ConstantRelocatable values. |
| 77 | template <typename ValueType, class Enable = void> struct KeyCompareLess {}; |
| 78 | |
| 79 | template <typename ValueType> |
| 80 | struct KeyCompareLess<ValueType, |
| 81 | typename std::enable_if<std::is_floating_point< |
| 82 | typename ValueType::PrimType>::value>::type> { |
| 83 | bool operator()(const Constant *Const1, const Constant *Const2) const { |
| 84 | typedef uint64_t CompareType; |
| 85 | static_assert(sizeof(typename ValueType::PrimType) <= sizeof(CompareType), |
| 86 | "Expected floating-point type of width 64-bit or less"); |
| 87 | typename ValueType::PrimType V1 = llvm::cast<ValueType>(Const1)->getValue(); |
| 88 | typename ValueType::PrimType V2 = llvm::cast<ValueType>(Const2)->getValue(); |
| 89 | // We avoid "V1<V2" because of NaN. |
| 90 | // We avoid "memcmp(&V1,&V2,sizeof(V1))<0" which depends on the |
| 91 | // endian-ness of the host system running Subzero. |
| 92 | // Instead, compare the result of bit_cast to uint64_t. |
| 93 | uint64_t I1 = 0, I2 = 0; |
| 94 | memcpy(&I1, &V1, sizeof(V1)); |
| 95 | memcpy(&I2, &V2, sizeof(V2)); |
| 96 | return I1 < I2; |
| 97 | } |
| 98 | }; |
| 99 | template <typename ValueType> |
| 100 | struct KeyCompareLess<ValueType, |
| 101 | typename std::enable_if<std::is_integral< |
| 102 | typename ValueType::PrimType>::value>::type> { |
| 103 | bool operator()(const Constant *Const1, const Constant *Const2) const { |
| 104 | typename ValueType::PrimType V1 = llvm::cast<ValueType>(Const1)->getValue(); |
| 105 | typename ValueType::PrimType V2 = llvm::cast<ValueType>(Const2)->getValue(); |
| 106 | return V1 < V2; |
| 107 | } |
| 108 | }; |
| 109 | template <typename ValueType> |
| 110 | struct KeyCompareLess< |
| 111 | ValueType, typename std::enable_if< |
| 112 | std::is_same<ValueType, ConstantRelocatable>::value>::type> { |
| 113 | bool operator()(const Constant *Const1, const Constant *Const2) const { |
| 114 | auto V1 = llvm::cast<ValueType>(Const1); |
| 115 | auto V2 = llvm::cast<ValueType>(Const2); |
| 116 | if (V1->getName() == V2->getName()) |
| 117 | return V1->getOffset() < V2->getOffset(); |
| 118 | return V1->getName() < V2->getName(); |
| 119 | } |
| 120 | }; |
| 121 | |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 122 | // TypePool maps constants of type KeyType (e.g. float) to pointers to |
Jim Stichnoth | d2cb436 | 2014-11-20 11:24:42 -0800 | [diff] [blame] | 123 | // type ValueType (e.g. ConstantFloat). |
| 124 | template <Type Ty, typename KeyType, typename ValueType> class TypePool { |
Jim Stichnoth | 0795ba0 | 2014-10-01 14:23:01 -0700 | [diff] [blame] | 125 | TypePool(const TypePool &) = delete; |
| 126 | TypePool &operator=(const TypePool &) = delete; |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 127 | |
| 128 | public: |
Jim Stichnoth | eafb56c | 2015-06-22 10:35:22 -0700 | [diff] [blame] | 129 | TypePool() = default; |
Jim Stichnoth | d2cb436 | 2014-11-20 11:24:42 -0800 | [diff] [blame] | 130 | ValueType *getOrAdd(GlobalContext *Ctx, KeyType Key) { |
| 131 | auto Iter = Pool.find(Key); |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 132 | if (Iter != Pool.end()) |
| 133 | return Iter->second; |
Jim Stichnoth | f61d5b2 | 2014-05-23 13:31:24 -0700 | [diff] [blame] | 134 | ValueType *Result = ValueType::create(Ctx, Ty, Key, NextPoolID++); |
Jim Stichnoth | d2cb436 | 2014-11-20 11:24:42 -0800 | [diff] [blame] | 135 | Pool[Key] = Result; |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 136 | return Result; |
| 137 | } |
Jim Stichnoth | f61d5b2 | 2014-05-23 13:31:24 -0700 | [diff] [blame] | 138 | ConstantList getConstantPool() const { |
| 139 | ConstantList Constants; |
| 140 | Constants.reserve(Pool.size()); |
Jim Stichnoth | f44f371 | 2014-10-01 14:05:51 -0700 | [diff] [blame] | 141 | for (auto &I : Pool) |
| 142 | Constants.push_back(I.second); |
Jim Stichnoth | 6e293c8 | 2015-04-09 09:11:18 -0700 | [diff] [blame] | 143 | // The sort (and its KeyCompareLess machinery) is not strictly |
| 144 | // necessary, but is desirable for producing output that is |
| 145 | // deterministic across unordered_map::iterator implementations. |
| 146 | std::sort(Constants.begin(), Constants.end(), KeyCompareLess<ValueType>()); |
Jim Stichnoth | f61d5b2 | 2014-05-23 13:31:24 -0700 | [diff] [blame] | 147 | return Constants; |
| 148 | } |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 149 | |
| 150 | private: |
Jim Stichnoth | 5bfe215 | 2015-03-19 13:51:56 -0700 | [diff] [blame] | 151 | // Use the default hash function, and a custom key comparison |
| 152 | // function. The key comparison function for floating point |
| 153 | // variables can't use the default == based implementation because |
| 154 | // of special C++ semantics regarding +0.0, -0.0, and NaN |
| 155 | // comparison. However, it's OK to use the default hash for |
| 156 | // floating point values because KeyCompare is the final source of |
| 157 | // truth - in the worst case a "false" collision must be resolved. |
| 158 | typedef std::unordered_map<KeyType, ValueType *, std::hash<KeyType>, |
| 159 | KeyCompare<KeyType>> ContainerType; |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 160 | ContainerType Pool; |
Jim Stichnoth | eafb56c | 2015-06-22 10:35:22 -0700 | [diff] [blame] | 161 | uint32_t NextPoolID = 0; |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 162 | }; |
| 163 | |
Matt Wala | d8f4a7d | 2014-06-18 09:55:03 -0700 | [diff] [blame] | 164 | // UndefPool maps ICE types to the corresponding ConstantUndef values. |
| 165 | class UndefPool { |
Jim Stichnoth | 0795ba0 | 2014-10-01 14:23:01 -0700 | [diff] [blame] | 166 | UndefPool(const UndefPool &) = delete; |
| 167 | UndefPool &operator=(const UndefPool &) = delete; |
Matt Wala | d8f4a7d | 2014-06-18 09:55:03 -0700 | [diff] [blame] | 168 | |
| 169 | public: |
Jim Stichnoth | eafb56c | 2015-06-22 10:35:22 -0700 | [diff] [blame] | 170 | UndefPool() : Pool(IceType_NUM) {} |
Matt Wala | d8f4a7d | 2014-06-18 09:55:03 -0700 | [diff] [blame] | 171 | |
| 172 | ConstantUndef *getOrAdd(GlobalContext *Ctx, Type Ty) { |
Jim Stichnoth | ae95320 | 2014-12-20 06:17:49 -0800 | [diff] [blame] | 173 | if (Pool[Ty] == nullptr) |
Jim Stichnoth | d2cb436 | 2014-11-20 11:24:42 -0800 | [diff] [blame] | 174 | Pool[Ty] = ConstantUndef::create(Ctx, Ty, NextPoolID++); |
| 175 | return Pool[Ty]; |
Matt Wala | d8f4a7d | 2014-06-18 09:55:03 -0700 | [diff] [blame] | 176 | } |
| 177 | |
| 178 | private: |
Jim Stichnoth | eafb56c | 2015-06-22 10:35:22 -0700 | [diff] [blame] | 179 | uint32_t NextPoolID = 0; |
Jim Stichnoth | d2cb436 | 2014-11-20 11:24:42 -0800 | [diff] [blame] | 180 | std::vector<ConstantUndef *> Pool; |
Matt Wala | d8f4a7d | 2014-06-18 09:55:03 -0700 | [diff] [blame] | 181 | }; |
| 182 | |
Jim Stichnoth | 5bfe215 | 2015-03-19 13:51:56 -0700 | [diff] [blame] | 183 | } // end of anonymous namespace |
| 184 | |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 185 | // The global constant pool bundles individual pools of each type of |
| 186 | // interest. |
| 187 | class ConstantPool { |
Jim Stichnoth | 0795ba0 | 2014-10-01 14:23:01 -0700 | [diff] [blame] | 188 | ConstantPool(const ConstantPool &) = delete; |
| 189 | ConstantPool &operator=(const ConstantPool &) = delete; |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 190 | |
| 191 | public: |
Jim Stichnoth | eafb56c | 2015-06-22 10:35:22 -0700 | [diff] [blame] | 192 | ConstantPool() = default; |
Jim Stichnoth | d2cb436 | 2014-11-20 11:24:42 -0800 | [diff] [blame] | 193 | TypePool<IceType_f32, float, ConstantFloat> Floats; |
| 194 | TypePool<IceType_f64, double, ConstantDouble> Doubles; |
| 195 | TypePool<IceType_i1, int8_t, ConstantInteger32> Integers1; |
| 196 | TypePool<IceType_i8, int8_t, ConstantInteger32> Integers8; |
| 197 | TypePool<IceType_i16, int16_t, ConstantInteger32> Integers16; |
| 198 | TypePool<IceType_i32, int32_t, ConstantInteger32> Integers32; |
| 199 | TypePool<IceType_i64, int64_t, ConstantInteger64> Integers64; |
| 200 | TypePool<IceType_i32, RelocatableTuple, ConstantRelocatable> Relocatables; |
Jan Voung | 261cae3 | 2015-02-01 10:31:03 -0800 | [diff] [blame] | 201 | TypePool<IceType_i32, RelocatableTuple, ConstantRelocatable> |
| 202 | ExternRelocatables; |
Matt Wala | d8f4a7d | 2014-06-18 09:55:03 -0700 | [diff] [blame] | 203 | UndefPool Undefs; |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 204 | }; |
| 205 | |
Jim Stichnoth | e4a8f40 | 2015-01-20 12:52:51 -0800 | [diff] [blame] | 206 | void GlobalContext::CodeStats::dump(const IceString &Name, Ostream &Str) { |
Jim Stichnoth | 20b71f5 | 2015-06-24 15:52:24 -0700 | [diff] [blame] | 207 | if (!BuildDefs::dump()) |
Jim Stichnoth | 639c921 | 2014-12-11 10:04:32 -0800 | [diff] [blame] | 208 | return; |
Jim Stichnoth | a1dd3cc | 2015-01-31 10:48:11 -0800 | [diff] [blame] | 209 | #define X(str, tag) \ |
| 210 | Str << "|" << Name << "|" str "|" << Stats[CS_##tag] << "\n"; |
| 211 | CODESTATS_TABLE |
| 212 | #undef X |
| 213 | Str << "|" << Name << "|Spills+Fills|" |
| 214 | << Stats[CS_NumSpills] + Stats[CS_NumFills] << "\n"; |
Jim Stichnoth | 639c921 | 2014-12-11 10:04:32 -0800 | [diff] [blame] | 215 | Str << "|" << Name << "|Memory Usage|"; |
| 216 | if (ssize_t MemUsed = llvm::TimeRecord::getCurrentTime(false).getMemUsed()) |
| 217 | Str << MemUsed; |
| 218 | else |
| 219 | Str << "(requires '-track-memory')"; |
| 220 | Str << "\n"; |
| 221 | } |
| 222 | |
Karl Schimpf | 2f67b92 | 2015-04-22 15:20:16 -0700 | [diff] [blame] | 223 | GlobalContext::GlobalContext(Ostream *OsDump, Ostream *OsEmit, Ostream *OsError, |
Jan Voung | 1f47ad0 | 2015-03-20 15:01:26 -0700 | [diff] [blame] | 224 | ELFStreamer *ELFStr, const ClFlags &Flags) |
Jim Stichnoth | fa4efea | 2015-01-27 05:06:03 -0800 | [diff] [blame] | 225 | : ConstPool(new ConstantPool()), ErrorStatus(), StrDump(OsDump), |
Karl Schimpf | 2f67b92 | 2015-04-22 15:20:16 -0700 | [diff] [blame] | 226 | StrEmit(OsEmit), StrError(OsError), Flags(Flags), |
| 227 | RNG(Flags.getRandomSeed()), ObjectWriter(), |
Jim Stichnoth | bbca754 | 2015-02-11 16:08:31 -0800 | [diff] [blame] | 228 | OptQ(/*Sequential=*/Flags.isSequential(), |
| 229 | /*MaxSize=*/Flags.getNumTranslationThreads()), |
| 230 | // EmitQ is allowed unlimited size. |
John Porto | 8b1a705 | 2015-06-17 13:20:08 -0700 | [diff] [blame] | 231 | EmitQ(/*Sequential=*/Flags.isSequential()), |
John Porto | 1bec8bc | 2015-06-22 10:51:13 -0700 | [diff] [blame] | 232 | DataLowering(TargetDataLowering::createLowering(this)) { |
Karl Schimpf | 2f67b92 | 2015-04-22 15:20:16 -0700 | [diff] [blame] | 233 | assert(OsDump && "OsDump is not defined for GlobalContext"); |
| 234 | assert(OsEmit && "OsEmit is not defined for GlobalContext"); |
| 235 | assert(OsError && "OsError is not defined for GlobalContext"); |
Jim Stichnoth | a5fe17a | 2015-01-26 11:10:03 -0800 | [diff] [blame] | 236 | // Make sure thread_local fields are properly initialized before any |
| 237 | // accesses are made. Do this here instead of at the start of |
| 238 | // main() so that all clients (e.g. unit tests) can benefit for |
| 239 | // free. |
| 240 | GlobalContext::TlsInit(); |
| 241 | Cfg::TlsInit(); |
Jim Stichnoth | e4a8f40 | 2015-01-20 12:52:51 -0800 | [diff] [blame] | 242 | // Create a new ThreadContext for the current thread. No need to |
| 243 | // lock AllThreadContexts at this point since no other threads have |
| 244 | // access yet to this GlobalContext object. |
Jim Stichnoth | 380d7b9 | 2015-01-30 13:10:39 -0800 | [diff] [blame] | 245 | ThreadContext *MyTLS = new ThreadContext(); |
| 246 | AllThreadContexts.push_back(MyTLS); |
| 247 | ICE_TLS_SET_FIELD(TLS, MyTLS); |
Jim Stichnoth | 8363a06 | 2014-10-07 10:02:38 -0700 | [diff] [blame] | 248 | // Pre-register built-in stack names. |
Jim Stichnoth | 20b71f5 | 2015-06-24 15:52:24 -0700 | [diff] [blame] | 249 | if (BuildDefs::dump()) { |
Jim Stichnoth | e4a8f40 | 2015-01-20 12:52:51 -0800 | [diff] [blame] | 250 | // TODO(stichnot): There needs to be a strong relationship between |
| 251 | // the newTimerStackID() return values and TSK_Default/TSK_Funcs. |
Jim Stichnoth | 1c44d81 | 2014-12-08 14:57:52 -0800 | [diff] [blame] | 252 | newTimerStackID("Total across all functions"); |
| 253 | newTimerStackID("Per-function summary"); |
| 254 | } |
Jim Stichnoth | 380d7b9 | 2015-01-30 13:10:39 -0800 | [diff] [blame] | 255 | Timers.initInto(MyTLS->Timers); |
Jim Stichnoth | d442e7e | 2015-02-12 14:01:48 -0800 | [diff] [blame] | 256 | switch (Flags.getOutFileType()) { |
| 257 | case FT_Elf: |
Jan Voung | 08c3bcd | 2014-12-01 17:55:16 -0800 | [diff] [blame] | 258 | ObjectWriter.reset(new ELFObjectWriter(*this, *ELFStr)); |
Jim Stichnoth | d442e7e | 2015-02-12 14:01:48 -0800 | [diff] [blame] | 259 | break; |
| 260 | case FT_Asm: |
| 261 | case FT_Iasm: |
| 262 | break; |
Jan Voung | 08c3bcd | 2014-12-01 17:55:16 -0800 | [diff] [blame] | 263 | } |
John Porto | 1bec8bc | 2015-06-22 10:51:13 -0700 | [diff] [blame] | 264 | |
| 265 | // ProfileBlockInfoVarDecl is initialized here because it takes this as a |
| 266 | // parameter -- we want to |
| 267 | // ensure that at least this' member variables are initialized. |
| 268 | ProfileBlockInfoVarDecl = VariableDeclaration::create(this); |
John Porto | 8b1a705 | 2015-06-17 13:20:08 -0700 | [diff] [blame] | 269 | ProfileBlockInfoVarDecl->setAlignment(typeWidthInBytes(IceType_i64)); |
| 270 | ProfileBlockInfoVarDecl->setIsConstant(true); |
| 271 | |
| 272 | // Note: if you change this symbol, make sure to update |
| 273 | // runtime/szrt_profiler.c as well. |
| 274 | ProfileBlockInfoVarDecl->setName("__Sz_block_profile_info"); |
| 275 | ProfileBlockInfoVarDecl->setSuppressMangling(); |
| 276 | ProfileBlockInfoVarDecl->setLinkage(llvm::GlobalValue::ExternalLinkage); |
Qining Lu | 253dc8a | 2015-06-22 10:10:23 -0700 | [diff] [blame] | 277 | |
| 278 | // Initialize the randomization cookie for constant blinding only if constant |
| 279 | // blinding or pooling is turned on. |
| 280 | // TODO(stichnot): Using RNG for constant blinding will affect the random |
| 281 | // number to be used in nop-insertion and randomize-regalloc. |
| 282 | if (Flags.getRandomizeAndPoolImmediatesOption() != RPI_None) |
| 283 | RandomizationCookie = |
| 284 | (uint32_t)RNG.next((uint64_t)std::numeric_limits<uint32_t>::max + 1); |
Jim Stichnoth | 8363a06 | 2014-10-07 10:02:38 -0700 | [diff] [blame] | 285 | } |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 286 | |
Jim Stichnoth | fa4efea | 2015-01-27 05:06:03 -0800 | [diff] [blame] | 287 | void GlobalContext::translateFunctions() { |
Jim Stichnoth | bbca754 | 2015-02-11 16:08:31 -0800 | [diff] [blame] | 288 | while (std::unique_ptr<Cfg> Func = optQueueBlockingPop()) { |
Jim Stichnoth | 8e92838 | 2015-02-02 17:03:08 -0800 | [diff] [blame] | 289 | // Install Func in TLS for Cfg-specific container allocators. |
| 290 | Cfg::setCurrentCfg(Func.get()); |
Jim Stichnoth | fa4efea | 2015-01-27 05:06:03 -0800 | [diff] [blame] | 291 | // Reset per-function stats being accumulated in TLS. |
| 292 | resetStats(); |
Jim Stichnoth | fa4efea | 2015-01-27 05:06:03 -0800 | [diff] [blame] | 293 | // Set verbose level to none if the current function does NOT |
| 294 | // match the -verbose-focus command-line option. |
Karl Schimpf | df80eb8 | 2015-02-09 14:20:22 -0800 | [diff] [blame] | 295 | if (!matchSymbolName(Func->getFunctionName(), |
| 296 | getFlags().getVerboseFocusOn())) |
Jim Stichnoth | fa4efea | 2015-01-27 05:06:03 -0800 | [diff] [blame] | 297 | Func->setVerbose(IceV_None); |
| 298 | // Disable translation if -notranslate is specified, or if the |
| 299 | // current function matches the -translate-only option. If |
| 300 | // translation is disabled, just dump the high-level IR and |
| 301 | // continue. |
Karl Schimpf | df80eb8 | 2015-02-09 14:20:22 -0800 | [diff] [blame] | 302 | if (getFlags().getDisableTranslation() || |
| 303 | !matchSymbolName(Func->getFunctionName(), |
| 304 | getFlags().getTranslateOnly())) { |
Jim Stichnoth | fa4efea | 2015-01-27 05:06:03 -0800 | [diff] [blame] | 305 | Func->dump(); |
Jim Stichnoth | bbca754 | 2015-02-11 16:08:31 -0800 | [diff] [blame] | 306 | Cfg::setCurrentCfg(nullptr); |
| 307 | continue; // Func goes out of scope and gets deleted |
| 308 | } |
John Porto | f8b4cc8 | 2015-06-09 18:06:19 -0700 | [diff] [blame] | 309 | |
Jim Stichnoth | bbca754 | 2015-02-11 16:08:31 -0800 | [diff] [blame] | 310 | Func->translate(); |
| 311 | EmitterWorkItem *Item = nullptr; |
| 312 | if (Func->hasError()) { |
| 313 | getErrorStatus()->assign(EC_Translation); |
| 314 | OstreamLocker L(this); |
Karl Schimpf | 2f67b92 | 2015-04-22 15:20:16 -0700 | [diff] [blame] | 315 | getStrError() << "ICE translation error: " << Func->getFunctionName() |
| 316 | << ": " << Func->getError() << "\n"; |
Jim Stichnoth | bbca754 | 2015-02-11 16:08:31 -0800 | [diff] [blame] | 317 | Item = new EmitterWorkItem(Func->getSequenceNumber()); |
Jim Stichnoth | fa4efea | 2015-01-27 05:06:03 -0800 | [diff] [blame] | 318 | } else { |
Jim Stichnoth | 24824e7 | 2015-02-12 21:35:34 -0800 | [diff] [blame] | 319 | Func->getAssembler<>()->setInternal(Func->getInternal()); |
Jim Stichnoth | d442e7e | 2015-02-12 14:01:48 -0800 | [diff] [blame] | 320 | switch (getFlags().getOutFileType()) { |
| 321 | case FT_Elf: |
| 322 | case FT_Iasm: { |
Jim Stichnoth | bbca754 | 2015-02-11 16:08:31 -0800 | [diff] [blame] | 323 | Func->emitIAS(); |
| 324 | // The Cfg has already emitted into the assembly buffer, so |
| 325 | // stats have been fully collected into this thread's TLS. |
| 326 | // Dump them before TLS is reset for the next Cfg. |
| 327 | dumpStats(Func->getFunctionName()); |
| 328 | Assembler *Asm = Func->releaseAssembler(); |
| 329 | // Copy relevant fields into Asm before Func is deleted. |
| 330 | Asm->setFunctionName(Func->getFunctionName()); |
Jim Stichnoth | bbca754 | 2015-02-11 16:08:31 -0800 | [diff] [blame] | 331 | Item = new EmitterWorkItem(Func->getSequenceNumber(), Asm); |
John Porto | f8b4cc8 | 2015-06-09 18:06:19 -0700 | [diff] [blame] | 332 | Item->setGlobalInits(Func->getGlobalInits()); |
Jim Stichnoth | d442e7e | 2015-02-12 14:01:48 -0800 | [diff] [blame] | 333 | } break; |
| 334 | case FT_Asm: |
Jim Stichnoth | bbca754 | 2015-02-11 16:08:31 -0800 | [diff] [blame] | 335 | // The Cfg has not been emitted yet, so stats are not ready |
| 336 | // to be dumped. |
John Porto | f8b4cc8 | 2015-06-09 18:06:19 -0700 | [diff] [blame] | 337 | std::unique_ptr<VariableDeclarationList> GlobalInits = |
| 338 | Func->getGlobalInits(); |
Jim Stichnoth | bbca754 | 2015-02-11 16:08:31 -0800 | [diff] [blame] | 339 | Item = new EmitterWorkItem(Func->getSequenceNumber(), Func.release()); |
John Porto | f8b4cc8 | 2015-06-09 18:06:19 -0700 | [diff] [blame] | 340 | Item->setGlobalInits(std::move(GlobalInits)); |
Jim Stichnoth | d442e7e | 2015-02-12 14:01:48 -0800 | [diff] [blame] | 341 | break; |
Jim Stichnoth | fa4efea | 2015-01-27 05:06:03 -0800 | [diff] [blame] | 342 | } |
Jim Stichnoth | fa4efea | 2015-01-27 05:06:03 -0800 | [diff] [blame] | 343 | } |
Jim Stichnoth | 8e92838 | 2015-02-02 17:03:08 -0800 | [diff] [blame] | 344 | Cfg::setCurrentCfg(nullptr); |
Jim Stichnoth | bbca754 | 2015-02-11 16:08:31 -0800 | [diff] [blame] | 345 | assert(Item); |
| 346 | emitQueueBlockingPush(Item); |
Jim Stichnoth | 8e92838 | 2015-02-02 17:03:08 -0800 | [diff] [blame] | 347 | // The Cfg now gets deleted as Func goes out of scope. |
Jim Stichnoth | fa4efea | 2015-01-27 05:06:03 -0800 | [diff] [blame] | 348 | } |
| 349 | } |
| 350 | |
Jim Stichnoth | bbca754 | 2015-02-11 16:08:31 -0800 | [diff] [blame] | 351 | namespace { |
| 352 | |
John Porto | 8b1a705 | 2015-06-17 13:20:08 -0700 | [diff] [blame] | 353 | void addBlockInfoPtrs(const VariableDeclarationList &Globals, |
| 354 | VariableDeclaration *ProfileBlockInfo) { |
John Porto | f8b4cc8 | 2015-06-09 18:06:19 -0700 | [diff] [blame] | 355 | for (const VariableDeclaration *Global : Globals) { |
| 356 | if (Cfg::isProfileGlobal(*Global)) { |
| 357 | constexpr RelocOffsetT BlockExecutionCounterOffset = 0; |
John Porto | 8b1a705 | 2015-06-17 13:20:08 -0700 | [diff] [blame] | 358 | ProfileBlockInfo->addInitializer( |
John Porto | 1bec8bc | 2015-06-22 10:51:13 -0700 | [diff] [blame] | 359 | VariableDeclaration::RelocInitializer::create( |
John Porto | 8b1a705 | 2015-06-17 13:20:08 -0700 | [diff] [blame] | 360 | Global, BlockExecutionCounterOffset)); |
John Porto | f8b4cc8 | 2015-06-09 18:06:19 -0700 | [diff] [blame] | 361 | } |
| 362 | } |
Jim Stichnoth | bbca754 | 2015-02-11 16:08:31 -0800 | [diff] [blame] | 363 | } |
| 364 | |
| 365 | // Ensure Pending is large enough that Pending[Index] is valid. |
| 366 | void resizePending(std::vector<EmitterWorkItem *> &Pending, uint32_t Index) { |
| 367 | if (Index >= Pending.size()) |
| 368 | Pending.resize(Index + 1); |
| 369 | } |
| 370 | |
| 371 | } // end of anonymous namespace |
| 372 | |
Jan Voung | fb79284 | 2015-06-11 15:27:50 -0700 | [diff] [blame] | 373 | void GlobalContext::emitFileHeader() { |
| 374 | TimerMarker T1(Ice::TimerStack::TT_emit, this); |
| 375 | if (getFlags().getOutFileType() == FT_Elf) { |
| 376 | getObjectWriter()->writeInitialELFHeader(); |
| 377 | } else { |
Jim Stichnoth | 20b71f5 | 2015-06-24 15:52:24 -0700 | [diff] [blame] | 378 | if (!BuildDefs::dump()) { |
Jim Stichnoth | c879968 | 2015-06-22 13:04:10 -0700 | [diff] [blame] | 379 | getStrError() << "emitFileHeader for non-ELF"; |
| 380 | getErrorStatus()->assign(EC_Translation); |
| 381 | } |
Jan Voung | fb79284 | 2015-06-11 15:27:50 -0700 | [diff] [blame] | 382 | TargetHeaderLowering::createLowering(this)->lower(); |
| 383 | } |
| 384 | } |
| 385 | |
Jim Stichnoth | cac003e | 2015-06-18 12:48:58 -0700 | [diff] [blame] | 386 | void GlobalContext::lowerConstants() { DataLowering->lowerConstants(); } |
John Porto | 8b1a705 | 2015-06-17 13:20:08 -0700 | [diff] [blame] | 387 | |
Andrew Scull | 86df4e9 | 2015-07-30 13:54:44 -0700 | [diff] [blame^] | 388 | void GlobalContext::lowerJumpTables() { DataLowering->lowerJumpTables(); } |
| 389 | |
John Porto | 8b1a705 | 2015-06-17 13:20:08 -0700 | [diff] [blame] | 390 | void GlobalContext::lowerGlobals(const IceString &SectionSuffix) { |
| 391 | TimerMarker T(TimerStack::TT_emitGlobalInitializers, this); |
Jim Stichnoth | 20b71f5 | 2015-06-24 15:52:24 -0700 | [diff] [blame] | 392 | const bool DumpGlobalVariables = BuildDefs::dump() && Flags.getVerbose() && |
| 393 | Flags.getVerboseFocusOn().empty(); |
John Porto | 8b1a705 | 2015-06-17 13:20:08 -0700 | [diff] [blame] | 394 | if (DumpGlobalVariables) { |
| 395 | OstreamLocker L(this); |
| 396 | Ostream &Stream = getStrDump(); |
| 397 | for (const Ice::VariableDeclaration *Global : Globals) { |
| 398 | Global->dump(this, Stream); |
| 399 | } |
| 400 | } |
| 401 | if (Flags.getDisableTranslation()) |
| 402 | return; |
| 403 | |
John Porto | 1bec8bc | 2015-06-22 10:51:13 -0700 | [diff] [blame] | 404 | addBlockInfoPtrs(Globals, ProfileBlockInfoVarDecl); |
Qining Lu | 7cd5351 | 2015-06-26 09:36:00 -0700 | [diff] [blame] | 405 | // If we need to shuffle the layout of global variables, shuffle them now. |
| 406 | if (getFlags().shouldReorderGlobalVariables()) { |
| 407 | auto *RNGPtr = &RNG; |
| 408 | RandomShuffle(Globals.begin(), Globals.end(), |
| 409 | [RNGPtr](int N) { return (uint32_t)RNGPtr->next(N); }); |
| 410 | } |
John Porto | 8b1a705 | 2015-06-17 13:20:08 -0700 | [diff] [blame] | 411 | DataLowering->lowerGlobals(Globals, SectionSuffix); |
John Porto | 1bec8bc | 2015-06-22 10:51:13 -0700 | [diff] [blame] | 412 | for (VariableDeclaration *Var : Globals) { |
| 413 | Var->discardInitializers(); |
| 414 | } |
John Porto | 8b1a705 | 2015-06-17 13:20:08 -0700 | [diff] [blame] | 415 | Globals.clear(); |
| 416 | } |
| 417 | |
| 418 | void GlobalContext::lowerProfileData() { |
John Porto | 1bec8bc | 2015-06-22 10:51:13 -0700 | [diff] [blame] | 419 | // ProfileBlockInfoVarDecl is initialized in the constructor, and will only |
| 420 | // ever be nullptr after this method completes. This assertion is a convoluted |
| 421 | // way of ensuring lowerProfileData is invoked a single time. |
| 422 | assert(ProfileBlockInfoVarDecl != nullptr); |
John Porto | 8b1a705 | 2015-06-17 13:20:08 -0700 | [diff] [blame] | 423 | // This adds a 64-bit sentinel entry to the end of our array. For 32-bit |
| 424 | // architectures this will waste 4 bytes. |
| 425 | const SizeT Sizeof64BitNullPtr = typeWidthInBytes(IceType_i64); |
| 426 | ProfileBlockInfoVarDecl->addInitializer( |
John Porto | 1bec8bc | 2015-06-22 10:51:13 -0700 | [diff] [blame] | 427 | VariableDeclaration::ZeroInitializer::create(Sizeof64BitNullPtr)); |
| 428 | Globals.push_back(ProfileBlockInfoVarDecl); |
John Porto | 8b1a705 | 2015-06-17 13:20:08 -0700 | [diff] [blame] | 429 | constexpr char ProfileDataSection[] = "$sz_profiler$"; |
| 430 | lowerGlobals(ProfileDataSection); |
John Porto | 1bec8bc | 2015-06-22 10:51:13 -0700 | [diff] [blame] | 431 | ProfileBlockInfoVarDecl = nullptr; |
John Porto | 8b1a705 | 2015-06-17 13:20:08 -0700 | [diff] [blame] | 432 | } |
| 433 | |
Jim Stichnoth | bbca754 | 2015-02-11 16:08:31 -0800 | [diff] [blame] | 434 | void GlobalContext::emitItems() { |
| 435 | const bool Threaded = !getFlags().isSequential(); |
| 436 | // Pending is a vector containing the reassembled, ordered list of |
| 437 | // work items. When we're ready for the next item, we first check |
| 438 | // whether it's in the Pending list. If not, we take an item from |
| 439 | // the work queue, and if it's not the item we're waiting for, we |
| 440 | // insert it into Pending and repeat. The work item is deleted |
| 441 | // after it is processed. |
| 442 | std::vector<EmitterWorkItem *> Pending; |
| 443 | uint32_t DesiredSequenceNumber = getFirstSequenceNumber(); |
Qining Lu | 7cd5351 | 2015-06-26 09:36:00 -0700 | [diff] [blame] | 444 | uint32_t ShuffleStartIndex = DesiredSequenceNumber; |
| 445 | uint32_t ShuffleEndIndex = DesiredSequenceNumber; |
| 446 | bool EmitQueueEmpty = false; |
| 447 | const uint32_t ShuffleWindowSize = |
| 448 | std::max(1u, getFlags().getReorderFunctionsWindowSize()); |
| 449 | bool Shuffle = Threaded && getFlags().shouldReorderFunctions(); |
| 450 | while (!EmitQueueEmpty) { |
Jim Stichnoth | bbca754 | 2015-02-11 16:08:31 -0800 | [diff] [blame] | 451 | resizePending(Pending, DesiredSequenceNumber); |
| 452 | // See if Pending contains DesiredSequenceNumber. |
| 453 | EmitterWorkItem *RawItem = Pending[DesiredSequenceNumber]; |
Qining Lu | 7cd5351 | 2015-06-26 09:36:00 -0700 | [diff] [blame] | 454 | if (RawItem == nullptr) { |
| 455 | // We need to fetch an EmitterWorkItem from the queue. |
Jim Stichnoth | bbca754 | 2015-02-11 16:08:31 -0800 | [diff] [blame] | 456 | RawItem = emitQueueBlockingPop(); |
Qining Lu | 7cd5351 | 2015-06-26 09:36:00 -0700 | [diff] [blame] | 457 | if (RawItem == nullptr) { |
| 458 | // This is the notifier for an empty queue. |
| 459 | EmitQueueEmpty = true; |
| 460 | } else { |
| 461 | // We get an EmitterWorkItem, we need to add it to Pending. |
| 462 | uint32_t ItemSeq = RawItem->getSequenceNumber(); |
| 463 | if (Threaded && ItemSeq != DesiredSequenceNumber) { |
| 464 | // Not the desired one, add it to Pending but do not increase |
| 465 | // DesiredSequenceNumber. Continue the loop, do not emit the item. |
| 466 | resizePending(Pending, ItemSeq); |
| 467 | Pending[ItemSeq] = RawItem; |
| 468 | continue; |
| 469 | } |
| 470 | // ItemSeq == DesiredSequenceNumber, we need to check if we should |
| 471 | // emit it or not. If !Threaded, we're OK with ItemSeq != |
| 472 | // DesiredSequenceNumber. |
| 473 | Pending[DesiredSequenceNumber] = RawItem; |
Jim Stichnoth | bbca754 | 2015-02-11 16:08:31 -0800 | [diff] [blame] | 474 | } |
Jim Stichnoth | bbca754 | 2015-02-11 16:08:31 -0800 | [diff] [blame] | 475 | } |
Qining Lu | 7cd5351 | 2015-06-26 09:36:00 -0700 | [diff] [blame] | 476 | // We have the desired EmitterWorkItem or nullptr as the end notifier. |
| 477 | // If the emitter queue is not empty, increase DesiredSequenceNumber and |
| 478 | // ShuffleEndIndex. |
| 479 | if (!EmitQueueEmpty) { |
| 480 | DesiredSequenceNumber++; |
| 481 | ShuffleEndIndex++; |
| 482 | } |
| 483 | |
| 484 | if (Shuffle) { |
| 485 | // Continue fetching EmitterWorkItem if function reordering is turned on, |
| 486 | // and emit queue is not empty, and the number of consecutive pending |
| 487 | // items is smaller than the window size, and RawItem is not a |
| 488 | // WI_GlobalInits kind. Emit WI_GlobalInits kind block first to avoid |
| 489 | // holding an arbitrarily large GlobalDeclarationList. |
| 490 | if (!EmitQueueEmpty && |
| 491 | ShuffleEndIndex - ShuffleStartIndex < ShuffleWindowSize && |
| 492 | RawItem->getKind() != EmitterWorkItem::WI_GlobalInits) |
| 493 | continue; |
| 494 | |
| 495 | // Emit the EmitterWorkItem between Pending[ShuffleStartIndex] to |
| 496 | // Pending[ShuffleEndIndex]. If function reordering turned on, shuffle the |
| 497 | // pending items from Pending[ShuffleStartIndex] to |
| 498 | // Pending[ShuffleEndIndex]. |
| 499 | RandomShuffle(Pending.begin() + ShuffleStartIndex, |
| 500 | Pending.begin() + ShuffleEndIndex, |
| 501 | [this](uint64_t N) { return (uint32_t)RNG.next(N); }); |
| 502 | } |
| 503 | |
| 504 | // Emit the item from ShuffleStartIndex to ShuffleEndIndex. |
| 505 | for (uint32_t I = ShuffleStartIndex; I < ShuffleEndIndex; I++) { |
| 506 | std::unique_ptr<EmitterWorkItem> Item(Pending[I]); |
| 507 | |
| 508 | switch (Item->getKind()) { |
| 509 | case EmitterWorkItem::WI_Nop: |
| 510 | break; |
| 511 | case EmitterWorkItem::WI_GlobalInits: { |
| 512 | accumulateGlobals(Item->getGlobalInits()); |
| 513 | } break; |
| 514 | case EmitterWorkItem::WI_Asm: { |
| 515 | lowerGlobalsIfNoCodeHasBeenSeen(); |
| 516 | accumulateGlobals(Item->getGlobalInits()); |
| 517 | |
| 518 | std::unique_ptr<Assembler> Asm = Item->getAsm(); |
| 519 | Asm->alignFunction(); |
| 520 | IceString MangledName = mangleName(Asm->getFunctionName()); |
| 521 | switch (getFlags().getOutFileType()) { |
| 522 | case FT_Elf: |
| 523 | getObjectWriter()->writeFunctionCode(MangledName, Asm->getInternal(), |
| 524 | Asm.get()); |
| 525 | break; |
| 526 | case FT_Iasm: { |
| 527 | OstreamLocker L(this); |
| 528 | Cfg::emitTextHeader(MangledName, this, Asm.get()); |
| 529 | Asm->emitIASBytes(this); |
| 530 | } break; |
| 531 | case FT_Asm: |
| 532 | llvm::report_fatal_error("Unexpected FT_Asm"); |
| 533 | break; |
| 534 | } |
| 535 | } break; |
| 536 | case EmitterWorkItem::WI_Cfg: { |
| 537 | if (!BuildDefs::dump()) |
| 538 | llvm::report_fatal_error("WI_Cfg work item created inappropriately"); |
| 539 | lowerGlobalsIfNoCodeHasBeenSeen(); |
| 540 | accumulateGlobals(Item->getGlobalInits()); |
| 541 | |
| 542 | assert(getFlags().getOutFileType() == FT_Asm); |
| 543 | std::unique_ptr<Cfg> Func = Item->getCfg(); |
| 544 | // Unfortunately, we have to temporarily install the Cfg in TLS |
| 545 | // because Variable::asType() uses the allocator to create the |
| 546 | // differently-typed copy. |
| 547 | Cfg::setCurrentCfg(Func.get()); |
| 548 | Func->emit(); |
| 549 | Cfg::setCurrentCfg(nullptr); |
| 550 | dumpStats(Func->getFunctionName()); |
| 551 | } break; |
| 552 | } |
| 553 | } |
| 554 | // Update the start index for next shuffling queue |
| 555 | ShuffleStartIndex = ShuffleEndIndex; |
Jim Stichnoth | bbca754 | 2015-02-11 16:08:31 -0800 | [diff] [blame] | 556 | } |
John Porto | f8b4cc8 | 2015-06-09 18:06:19 -0700 | [diff] [blame] | 557 | |
John Porto | 8b1a705 | 2015-06-17 13:20:08 -0700 | [diff] [blame] | 558 | // In case there are no code to be generated, we invoke the conditional |
| 559 | // lowerGlobals again -- this is a no-op if code has been emitted. |
| 560 | lowerGlobalsIfNoCodeHasBeenSeen(); |
Jim Stichnoth | bbca754 | 2015-02-11 16:08:31 -0800 | [diff] [blame] | 561 | } |
| 562 | |
Jim Stichnoth | 217dc08 | 2014-07-11 14:06:55 -0700 | [diff] [blame] | 563 | // Scan a string for S[0-9A-Z]*_ patterns and replace them with |
| 564 | // S<num>_ where <num> is the next base-36 value. If a type name |
| 565 | // legitimately contains that pattern, then the substitution will be |
| 566 | // made in error and most likely the link will fail. In this case, |
| 567 | // the test classes can be rewritten not to use that pattern, which is |
| 568 | // much simpler and more reliable than implementing a full demangling |
| 569 | // parser. Another substitution-in-error may occur if a type |
| 570 | // identifier ends with the pattern S[0-9A-Z]*, because an immediately |
| 571 | // following substitution string like "S1_" or "PS1_" may be combined |
| 572 | // with the previous type. |
| 573 | void GlobalContext::incrementSubstitutions(ManglerVector &OldName) const { |
| 574 | const std::locale CLocale("C"); |
| 575 | // Provide extra space in case the length of <num> increases. |
| 576 | ManglerVector NewName(OldName.size() * 2); |
| 577 | size_t OldPos = 0; |
| 578 | size_t NewPos = 0; |
| 579 | size_t OldLen = OldName.size(); |
| 580 | for (; OldPos < OldLen; ++OldPos, ++NewPos) { |
| 581 | if (OldName[OldPos] == '\0') |
| 582 | break; |
| 583 | if (OldName[OldPos] == 'S') { |
| 584 | // Search forward until we find _ or invalid character (including \0). |
| 585 | bool AllZs = true; |
| 586 | bool Found = false; |
| 587 | size_t Last; |
| 588 | for (Last = OldPos + 1; Last < OldLen; ++Last) { |
| 589 | char Ch = OldName[Last]; |
| 590 | if (Ch == '_') { |
| 591 | Found = true; |
| 592 | break; |
| 593 | } else if (std::isdigit(Ch) || std::isupper(Ch, CLocale)) { |
| 594 | if (Ch != 'Z') |
| 595 | AllZs = false; |
| 596 | } else { |
| 597 | // Invalid character, stop searching. |
| 598 | break; |
| 599 | } |
| 600 | } |
| 601 | if (Found) { |
| 602 | NewName[NewPos++] = OldName[OldPos++]; // 'S' |
| 603 | size_t Length = Last - OldPos; |
| 604 | // NewPos and OldPos point just past the 'S'. |
| 605 | assert(NewName[NewPos - 1] == 'S'); |
| 606 | assert(OldName[OldPos - 1] == 'S'); |
| 607 | assert(OldName[OldPos + Length] == '_'); |
| 608 | if (AllZs) { |
Jim Stichnoth | 78b4c0b | 2014-07-11 15:29:23 -0700 | [diff] [blame] | 609 | // Replace N 'Z' characters with a '0' (if N=0) or '1' (if |
| 610 | // N>0) followed by N '0' characters. |
| 611 | NewName[NewPos++] = (Length ? '1' : '0'); |
| 612 | for (size_t i = 0; i < Length; ++i) { |
Jim Stichnoth | 217dc08 | 2014-07-11 14:06:55 -0700 | [diff] [blame] | 613 | NewName[NewPos++] = '0'; |
| 614 | } |
| 615 | } else { |
| 616 | // Iterate right-to-left and increment the base-36 number. |
| 617 | bool Carry = true; |
| 618 | for (size_t i = 0; i < Length; ++i) { |
| 619 | size_t Offset = Length - 1 - i; |
| 620 | char Ch = OldName[OldPos + Offset]; |
| 621 | if (Carry) { |
| 622 | Carry = false; |
| 623 | switch (Ch) { |
| 624 | case '9': |
| 625 | Ch = 'A'; |
| 626 | break; |
| 627 | case 'Z': |
| 628 | Ch = '0'; |
| 629 | Carry = true; |
| 630 | break; |
| 631 | default: |
| 632 | ++Ch; |
| 633 | break; |
| 634 | } |
| 635 | } |
| 636 | NewName[NewPos + Offset] = Ch; |
| 637 | } |
| 638 | NewPos += Length; |
| 639 | } |
| 640 | OldPos = Last; |
| 641 | // Fall through and let the '_' be copied across. |
| 642 | } |
| 643 | } |
| 644 | NewName[NewPos] = OldName[OldPos]; |
| 645 | } |
| 646 | assert(NewName[NewPos] == '\0'); |
| 647 | OldName = NewName; |
| 648 | } |
| 649 | |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 650 | // In this context, name mangling means to rewrite a symbol using a |
| 651 | // given prefix. For a C++ symbol, nest the original symbol inside |
| 652 | // the "prefix" namespace. For other symbols, just prepend the |
| 653 | // prefix. |
| 654 | IceString GlobalContext::mangleName(const IceString &Name) const { |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 655 | // An already-nested name like foo::bar() gets pushed down one |
| 656 | // level, making it equivalent to Prefix::foo::bar(). |
| 657 | // _ZN3foo3barExyz ==> _ZN6Prefix3foo3barExyz |
| 658 | // A non-nested but mangled name like bar() gets nested, making it |
| 659 | // equivalent to Prefix::bar(). |
| 660 | // _Z3barxyz ==> ZN6Prefix3barExyz |
| 661 | // An unmangled, extern "C" style name, gets a simple prefix: |
| 662 | // bar ==> Prefixbar |
Jim Stichnoth | 20b71f5 | 2015-06-24 15:52:24 -0700 | [diff] [blame] | 663 | if (!BuildDefs::dump() || getFlags().getTestPrefix().empty()) |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 664 | return Name; |
| 665 | |
Jan Voung | 1f47ad0 | 2015-03-20 15:01:26 -0700 | [diff] [blame] | 666 | const IceString &TestPrefix = getFlags().getTestPrefix(); |
| 667 | unsigned PrefixLength = TestPrefix.length(); |
Jim Stichnoth | 217dc08 | 2014-07-11 14:06:55 -0700 | [diff] [blame] | 668 | ManglerVector NameBase(1 + Name.length()); |
Jim Stichnoth | 5bc2b1d | 2014-05-22 13:38:48 -0700 | [diff] [blame] | 669 | const size_t BufLen = 30 + Name.length() + PrefixLength; |
Jim Stichnoth | 217dc08 | 2014-07-11 14:06:55 -0700 | [diff] [blame] | 670 | ManglerVector NewName(BufLen); |
Jim Stichnoth | 5bc2b1d | 2014-05-22 13:38:48 -0700 | [diff] [blame] | 671 | uint32_t BaseLength = 0; // using uint32_t due to sscanf format string |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 672 | |
Derek Schuff | 44712d1 | 2014-06-17 14:34:34 -0700 | [diff] [blame] | 673 | int ItemsParsed = sscanf(Name.c_str(), "_ZN%s", NameBase.data()); |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 674 | if (ItemsParsed == 1) { |
| 675 | // Transform _ZN3foo3barExyz ==> _ZN6Prefix3foo3barExyz |
| 676 | // (splice in "6Prefix") ^^^^^^^ |
Derek Schuff | 44712d1 | 2014-06-17 14:34:34 -0700 | [diff] [blame] | 677 | snprintf(NewName.data(), BufLen, "_ZN%u%s%s", PrefixLength, |
Jan Voung | 1f47ad0 | 2015-03-20 15:01:26 -0700 | [diff] [blame] | 678 | TestPrefix.c_str(), NameBase.data()); |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 679 | // We ignore the snprintf return value (here and below). If we |
| 680 | // somehow miscalculated the output buffer length, the output will |
| 681 | // be truncated, but it will be truncated consistently for all |
| 682 | // mangleName() calls on the same input string. |
Jim Stichnoth | 217dc08 | 2014-07-11 14:06:55 -0700 | [diff] [blame] | 683 | incrementSubstitutions(NewName); |
Derek Schuff | 44712d1 | 2014-06-17 14:34:34 -0700 | [diff] [blame] | 684 | return NewName.data(); |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 685 | } |
| 686 | |
Jim Stichnoth | d97c7df | 2014-06-04 11:57:08 -0700 | [diff] [blame] | 687 | // Artificially limit BaseLength to 9 digits (less than 1 billion) |
| 688 | // because sscanf behavior is undefined on integer overflow. If |
| 689 | // there are more than 9 digits (which we test by looking at the |
| 690 | // beginning of NameBase), then we consider this a failure to parse |
| 691 | // a namespace mangling, and fall back to the simple prefixing. |
Derek Schuff | 44712d1 | 2014-06-17 14:34:34 -0700 | [diff] [blame] | 692 | ItemsParsed = sscanf(Name.c_str(), "_Z%9u%s", &BaseLength, NameBase.data()); |
| 693 | if (ItemsParsed == 2 && BaseLength <= strlen(NameBase.data()) && |
Jim Stichnoth | d97c7df | 2014-06-04 11:57:08 -0700 | [diff] [blame] | 694 | !isdigit(NameBase[0])) { |
Jim Stichnoth | 5bc2b1d | 2014-05-22 13:38:48 -0700 | [diff] [blame] | 695 | // Transform _Z3barxyz ==> _ZN6Prefix3barExyz |
| 696 | // ^^^^^^^^ ^ |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 697 | // (splice in "N6Prefix", and insert "E" after "3bar") |
Jim Stichnoth | 5bc2b1d | 2014-05-22 13:38:48 -0700 | [diff] [blame] | 698 | // But an "I" after the identifier indicates a template argument |
| 699 | // list terminated with "E"; insert the new "E" before/after the |
| 700 | // old "E". E.g.: |
| 701 | // Transform _Z3barIabcExyz ==> _ZN6Prefix3barIabcEExyz |
| 702 | // ^^^^^^^^ ^ |
| 703 | // (splice in "N6Prefix", and insert "E" after "3barIabcE") |
Jim Stichnoth | 217dc08 | 2014-07-11 14:06:55 -0700 | [diff] [blame] | 704 | ManglerVector OrigName(Name.length()); |
| 705 | ManglerVector OrigSuffix(Name.length()); |
Jim Stichnoth | 5bc2b1d | 2014-05-22 13:38:48 -0700 | [diff] [blame] | 706 | uint32_t ActualBaseLength = BaseLength; |
| 707 | if (NameBase[ActualBaseLength] == 'I') { |
| 708 | ++ActualBaseLength; |
| 709 | while (NameBase[ActualBaseLength] != 'E' && |
| 710 | NameBase[ActualBaseLength] != '\0') |
| 711 | ++ActualBaseLength; |
| 712 | } |
Derek Schuff | 44712d1 | 2014-06-17 14:34:34 -0700 | [diff] [blame] | 713 | strncpy(OrigName.data(), NameBase.data(), ActualBaseLength); |
Jim Stichnoth | 5bc2b1d | 2014-05-22 13:38:48 -0700 | [diff] [blame] | 714 | OrigName[ActualBaseLength] = '\0'; |
Derek Schuff | 44712d1 | 2014-06-17 14:34:34 -0700 | [diff] [blame] | 715 | strcpy(OrigSuffix.data(), NameBase.data() + ActualBaseLength); |
| 716 | snprintf(NewName.data(), BufLen, "_ZN%u%s%u%sE%s", PrefixLength, |
Jan Voung | 1f47ad0 | 2015-03-20 15:01:26 -0700 | [diff] [blame] | 717 | TestPrefix.c_str(), BaseLength, OrigName.data(), |
Derek Schuff | 44712d1 | 2014-06-17 14:34:34 -0700 | [diff] [blame] | 718 | OrigSuffix.data()); |
Jim Stichnoth | 217dc08 | 2014-07-11 14:06:55 -0700 | [diff] [blame] | 719 | incrementSubstitutions(NewName); |
Derek Schuff | 44712d1 | 2014-06-17 14:34:34 -0700 | [diff] [blame] | 720 | return NewName.data(); |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 721 | } |
| 722 | |
| 723 | // Transform bar ==> Prefixbar |
| 724 | // ^^^^^^ |
Jan Voung | 1f47ad0 | 2015-03-20 15:01:26 -0700 | [diff] [blame] | 725 | return TestPrefix + Name; |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 726 | } |
| 727 | |
Karl Schimpf | 9d98d79 | 2014-10-13 15:01:08 -0700 | [diff] [blame] | 728 | GlobalContext::~GlobalContext() { |
Jim Stichnoth | e4a8f40 | 2015-01-20 12:52:51 -0800 | [diff] [blame] | 729 | llvm::DeleteContainerPointers(AllThreadContexts); |
John Porto | 1bec8bc | 2015-06-22 10:51:13 -0700 | [diff] [blame] | 730 | LockedPtr<DestructorArray> Dtors = getDestructors(); |
| 731 | // Destructors are invoked in the opposite object construction order. |
| 732 | for (auto DtorIter = Dtors->crbegin(); DtorIter != Dtors->crend(); |
| 733 | ++DtorIter) { |
| 734 | (*DtorIter)(); |
| 735 | } |
Karl Schimpf | 9d98d79 | 2014-10-13 15:01:08 -0700 | [diff] [blame] | 736 | } |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 737 | |
Jim Stichnoth | e4a8f40 | 2015-01-20 12:52:51 -0800 | [diff] [blame] | 738 | // TODO(stichnot): Consider adding thread-local caches of constant |
| 739 | // pool entries to reduce contention. |
| 740 | |
| 741 | // All locking is done by the getConstantInt[0-9]+() target function. |
Jim Stichnoth | d2cb436 | 2014-11-20 11:24:42 -0800 | [diff] [blame] | 742 | Constant *GlobalContext::getConstantInt(Type Ty, int64_t Value) { |
| 743 | switch (Ty) { |
| 744 | case IceType_i1: |
| 745 | return getConstantInt1(Value); |
| 746 | case IceType_i8: |
| 747 | return getConstantInt8(Value); |
| 748 | case IceType_i16: |
| 749 | return getConstantInt16(Value); |
| 750 | case IceType_i32: |
| 751 | return getConstantInt32(Value); |
| 752 | case IceType_i64: |
| 753 | return getConstantInt64(Value); |
| 754 | default: |
| 755 | llvm_unreachable("Bad integer type for getConstant"); |
| 756 | } |
Jim Stichnoth | ae95320 | 2014-12-20 06:17:49 -0800 | [diff] [blame] | 757 | return nullptr; |
Jan Voung | bc00463 | 2014-09-16 15:09:10 -0700 | [diff] [blame] | 758 | } |
| 759 | |
Jim Stichnoth | d2cb436 | 2014-11-20 11:24:42 -0800 | [diff] [blame] | 760 | Constant *GlobalContext::getConstantInt1(int8_t ConstantInt1) { |
| 761 | ConstantInt1 &= INT8_C(1); |
Jim Stichnoth | e4a8f40 | 2015-01-20 12:52:51 -0800 | [diff] [blame] | 762 | return getConstPool()->Integers1.getOrAdd(this, ConstantInt1); |
Jim Stichnoth | d2cb436 | 2014-11-20 11:24:42 -0800 | [diff] [blame] | 763 | } |
| 764 | |
| 765 | Constant *GlobalContext::getConstantInt8(int8_t ConstantInt8) { |
Jim Stichnoth | e4a8f40 | 2015-01-20 12:52:51 -0800 | [diff] [blame] | 766 | return getConstPool()->Integers8.getOrAdd(this, ConstantInt8); |
Jim Stichnoth | d2cb436 | 2014-11-20 11:24:42 -0800 | [diff] [blame] | 767 | } |
| 768 | |
| 769 | Constant *GlobalContext::getConstantInt16(int16_t ConstantInt16) { |
Jim Stichnoth | e4a8f40 | 2015-01-20 12:52:51 -0800 | [diff] [blame] | 770 | return getConstPool()->Integers16.getOrAdd(this, ConstantInt16); |
Jim Stichnoth | d2cb436 | 2014-11-20 11:24:42 -0800 | [diff] [blame] | 771 | } |
| 772 | |
| 773 | Constant *GlobalContext::getConstantInt32(int32_t ConstantInt32) { |
Jim Stichnoth | e4a8f40 | 2015-01-20 12:52:51 -0800 | [diff] [blame] | 774 | return getConstPool()->Integers32.getOrAdd(this, ConstantInt32); |
Jim Stichnoth | d2cb436 | 2014-11-20 11:24:42 -0800 | [diff] [blame] | 775 | } |
| 776 | |
| 777 | Constant *GlobalContext::getConstantInt64(int64_t ConstantInt64) { |
Jim Stichnoth | e4a8f40 | 2015-01-20 12:52:51 -0800 | [diff] [blame] | 778 | return getConstPool()->Integers64.getOrAdd(this, ConstantInt64); |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 779 | } |
| 780 | |
| 781 | Constant *GlobalContext::getConstantFloat(float ConstantFloat) { |
Jim Stichnoth | e4a8f40 | 2015-01-20 12:52:51 -0800 | [diff] [blame] | 782 | return getConstPool()->Floats.getOrAdd(this, ConstantFloat); |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 783 | } |
| 784 | |
| 785 | Constant *GlobalContext::getConstantDouble(double ConstantDouble) { |
Jim Stichnoth | e4a8f40 | 2015-01-20 12:52:51 -0800 | [diff] [blame] | 786 | return getConstPool()->Doubles.getOrAdd(this, ConstantDouble); |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 787 | } |
| 788 | |
Jim Stichnoth | d2cb436 | 2014-11-20 11:24:42 -0800 | [diff] [blame] | 789 | Constant *GlobalContext::getConstantSym(RelocOffsetT Offset, |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 790 | const IceString &Name, |
| 791 | bool SuppressMangling) { |
Jim Stichnoth | e4a8f40 | 2015-01-20 12:52:51 -0800 | [diff] [blame] | 792 | return getConstPool()->Relocatables.getOrAdd( |
Jim Stichnoth | d2cb436 | 2014-11-20 11:24:42 -0800 | [diff] [blame] | 793 | this, RelocatableTuple(Offset, Name, SuppressMangling)); |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 794 | } |
| 795 | |
Jan Voung | 261cae3 | 2015-02-01 10:31:03 -0800 | [diff] [blame] | 796 | Constant *GlobalContext::getConstantExternSym(const IceString &Name) { |
| 797 | const RelocOffsetT Offset = 0; |
| 798 | const bool SuppressMangling = true; |
| 799 | return getConstPool()->ExternRelocatables.getOrAdd( |
| 800 | this, RelocatableTuple(Offset, Name, SuppressMangling)); |
| 801 | } |
| 802 | |
Matt Wala | d8f4a7d | 2014-06-18 09:55:03 -0700 | [diff] [blame] | 803 | Constant *GlobalContext::getConstantUndef(Type Ty) { |
Jim Stichnoth | e4a8f40 | 2015-01-20 12:52:51 -0800 | [diff] [blame] | 804 | return getConstPool()->Undefs.getOrAdd(this, Ty); |
Matt Wala | d8f4a7d | 2014-06-18 09:55:03 -0700 | [diff] [blame] | 805 | } |
| 806 | |
Jim Stichnoth | e4a8f40 | 2015-01-20 12:52:51 -0800 | [diff] [blame] | 807 | // All locking is done by the getConstant*() target function. |
Matt Wala | d8f4a7d | 2014-06-18 09:55:03 -0700 | [diff] [blame] | 808 | Constant *GlobalContext::getConstantZero(Type Ty) { |
| 809 | switch (Ty) { |
| 810 | case IceType_i1: |
Jim Stichnoth | d2cb436 | 2014-11-20 11:24:42 -0800 | [diff] [blame] | 811 | return getConstantInt1(0); |
Matt Wala | d8f4a7d | 2014-06-18 09:55:03 -0700 | [diff] [blame] | 812 | case IceType_i8: |
Jim Stichnoth | d2cb436 | 2014-11-20 11:24:42 -0800 | [diff] [blame] | 813 | return getConstantInt8(0); |
Matt Wala | d8f4a7d | 2014-06-18 09:55:03 -0700 | [diff] [blame] | 814 | case IceType_i16: |
Jim Stichnoth | d2cb436 | 2014-11-20 11:24:42 -0800 | [diff] [blame] | 815 | return getConstantInt16(0); |
Matt Wala | d8f4a7d | 2014-06-18 09:55:03 -0700 | [diff] [blame] | 816 | case IceType_i32: |
Jim Stichnoth | d2cb436 | 2014-11-20 11:24:42 -0800 | [diff] [blame] | 817 | return getConstantInt32(0); |
Matt Wala | d8f4a7d | 2014-06-18 09:55:03 -0700 | [diff] [blame] | 818 | case IceType_i64: |
Jim Stichnoth | d2cb436 | 2014-11-20 11:24:42 -0800 | [diff] [blame] | 819 | return getConstantInt64(0); |
Matt Wala | d8f4a7d | 2014-06-18 09:55:03 -0700 | [diff] [blame] | 820 | case IceType_f32: |
| 821 | return getConstantFloat(0); |
| 822 | case IceType_f64: |
| 823 | return getConstantDouble(0); |
Matt Wala | 928f129 | 2014-07-07 16:50:46 -0700 | [diff] [blame] | 824 | case IceType_v4i1: |
| 825 | case IceType_v8i1: |
| 826 | case IceType_v16i1: |
| 827 | case IceType_v16i8: |
| 828 | case IceType_v8i16: |
| 829 | case IceType_v4i32: |
| 830 | case IceType_v4f32: { |
| 831 | IceString Str; |
| 832 | llvm::raw_string_ostream BaseOS(Str); |
Jim Stichnoth | 78282f6 | 2014-07-27 23:14:00 -0700 | [diff] [blame] | 833 | BaseOS << "Unsupported constant type: " << Ty; |
Matt Wala | 928f129 | 2014-07-07 16:50:46 -0700 | [diff] [blame] | 834 | llvm_unreachable(BaseOS.str().c_str()); |
| 835 | } break; |
Matt Wala | d8f4a7d | 2014-06-18 09:55:03 -0700 | [diff] [blame] | 836 | case IceType_void: |
| 837 | case IceType_NUM: |
| 838 | break; |
| 839 | } |
| 840 | llvm_unreachable("Unknown type"); |
| 841 | } |
| 842 | |
Jim Stichnoth | e4a8f40 | 2015-01-20 12:52:51 -0800 | [diff] [blame] | 843 | ConstantList GlobalContext::getConstantPool(Type Ty) { |
Jim Stichnoth | f61d5b2 | 2014-05-23 13:31:24 -0700 | [diff] [blame] | 844 | switch (Ty) { |
| 845 | case IceType_i1: |
| 846 | case IceType_i8: |
Qining Lu | 253dc8a | 2015-06-22 10:10:23 -0700 | [diff] [blame] | 847 | return getConstPool()->Integers8.getConstantPool(); |
Jim Stichnoth | f61d5b2 | 2014-05-23 13:31:24 -0700 | [diff] [blame] | 848 | case IceType_i16: |
Qining Lu | 253dc8a | 2015-06-22 10:10:23 -0700 | [diff] [blame] | 849 | return getConstPool()->Integers16.getConstantPool(); |
Jim Stichnoth | f61d5b2 | 2014-05-23 13:31:24 -0700 | [diff] [blame] | 850 | case IceType_i32: |
Jim Stichnoth | e4a8f40 | 2015-01-20 12:52:51 -0800 | [diff] [blame] | 851 | return getConstPool()->Integers32.getConstantPool(); |
Jim Stichnoth | f61d5b2 | 2014-05-23 13:31:24 -0700 | [diff] [blame] | 852 | case IceType_i64: |
Jim Stichnoth | e4a8f40 | 2015-01-20 12:52:51 -0800 | [diff] [blame] | 853 | return getConstPool()->Integers64.getConstantPool(); |
Jim Stichnoth | f61d5b2 | 2014-05-23 13:31:24 -0700 | [diff] [blame] | 854 | case IceType_f32: |
Jim Stichnoth | e4a8f40 | 2015-01-20 12:52:51 -0800 | [diff] [blame] | 855 | return getConstPool()->Floats.getConstantPool(); |
Jim Stichnoth | f61d5b2 | 2014-05-23 13:31:24 -0700 | [diff] [blame] | 856 | case IceType_f64: |
Jim Stichnoth | e4a8f40 | 2015-01-20 12:52:51 -0800 | [diff] [blame] | 857 | return getConstPool()->Doubles.getConstantPool(); |
Matt Wala | 928f129 | 2014-07-07 16:50:46 -0700 | [diff] [blame] | 858 | case IceType_v4i1: |
| 859 | case IceType_v8i1: |
| 860 | case IceType_v16i1: |
| 861 | case IceType_v16i8: |
| 862 | case IceType_v8i16: |
| 863 | case IceType_v4i32: |
| 864 | case IceType_v4f32: { |
| 865 | IceString Str; |
| 866 | llvm::raw_string_ostream BaseOS(Str); |
Jim Stichnoth | 78282f6 | 2014-07-27 23:14:00 -0700 | [diff] [blame] | 867 | BaseOS << "Unsupported constant type: " << Ty; |
Matt Wala | 928f129 | 2014-07-07 16:50:46 -0700 | [diff] [blame] | 868 | llvm_unreachable(BaseOS.str().c_str()); |
| 869 | } break; |
Jim Stichnoth | f61d5b2 | 2014-05-23 13:31:24 -0700 | [diff] [blame] | 870 | case IceType_void: |
| 871 | case IceType_NUM: |
| 872 | break; |
| 873 | } |
| 874 | llvm_unreachable("Unknown type"); |
| 875 | } |
| 876 | |
Jan Voung | 261cae3 | 2015-02-01 10:31:03 -0800 | [diff] [blame] | 877 | ConstantList GlobalContext::getConstantExternSyms() { |
| 878 | return getConstPool()->ExternRelocatables.getConstantPool(); |
| 879 | } |
| 880 | |
Andrew Scull | 86df4e9 | 2015-07-30 13:54:44 -0700 | [diff] [blame^] | 881 | JumpTableData &GlobalContext::addJumpTable(IceString FuncName, SizeT Id, |
| 882 | SizeT NumTargets) { |
| 883 | auto JumpTables = getJumpTables(); |
| 884 | JumpTables->emplace_back(FuncName, Id, NumTargets); |
| 885 | return JumpTables->back(); |
| 886 | } |
| 887 | |
Jim Stichnoth | 8363a06 | 2014-10-07 10:02:38 -0700 | [diff] [blame] | 888 | TimerStackIdT GlobalContext::newTimerStackID(const IceString &Name) { |
Jim Stichnoth | 20b71f5 | 2015-06-24 15:52:24 -0700 | [diff] [blame] | 889 | if (!BuildDefs::dump()) |
Jim Stichnoth | 1c44d81 | 2014-12-08 14:57:52 -0800 | [diff] [blame] | 890 | return 0; |
Jim Stichnoth | e4a8f40 | 2015-01-20 12:52:51 -0800 | [diff] [blame] | 891 | auto Timers = getTimers(); |
| 892 | TimerStackIdT NewID = Timers->size(); |
| 893 | Timers->push_back(TimerStack(Name)); |
Jim Stichnoth | 8363a06 | 2014-10-07 10:02:38 -0700 | [diff] [blame] | 894 | return NewID; |
| 895 | } |
Jim Stichnoth | c4554d7 | 2014-09-30 16:49:38 -0700 | [diff] [blame] | 896 | |
Jim Stichnoth | e4a8f40 | 2015-01-20 12:52:51 -0800 | [diff] [blame] | 897 | TimerIdT GlobalContext::getTimerID(TimerStackIdT StackID, |
| 898 | const IceString &Name) { |
Jim Stichnoth | 380d7b9 | 2015-01-30 13:10:39 -0800 | [diff] [blame] | 899 | auto Timers = &ICE_TLS_GET_FIELD(TLS)->Timers; |
Jim Stichnoth | e4a8f40 | 2015-01-20 12:52:51 -0800 | [diff] [blame] | 900 | assert(StackID < Timers->size()); |
| 901 | return Timers->at(StackID).getTimerID(Name); |
| 902 | } |
| 903 | |
Jim Stichnoth | 8363a06 | 2014-10-07 10:02:38 -0700 | [diff] [blame] | 904 | void GlobalContext::pushTimer(TimerIdT ID, TimerStackIdT StackID) { |
Jim Stichnoth | 380d7b9 | 2015-01-30 13:10:39 -0800 | [diff] [blame] | 905 | auto Timers = &ICE_TLS_GET_FIELD(TLS)->Timers; |
Jim Stichnoth | e4a8f40 | 2015-01-20 12:52:51 -0800 | [diff] [blame] | 906 | assert(StackID < Timers->size()); |
| 907 | Timers->at(StackID).push(ID); |
Jim Stichnoth | 8363a06 | 2014-10-07 10:02:38 -0700 | [diff] [blame] | 908 | } |
| 909 | |
| 910 | void GlobalContext::popTimer(TimerIdT ID, TimerStackIdT StackID) { |
Jim Stichnoth | 380d7b9 | 2015-01-30 13:10:39 -0800 | [diff] [blame] | 911 | auto Timers = &ICE_TLS_GET_FIELD(TLS)->Timers; |
Jim Stichnoth | e4a8f40 | 2015-01-20 12:52:51 -0800 | [diff] [blame] | 912 | assert(StackID < Timers->size()); |
| 913 | Timers->at(StackID).pop(ID); |
Jim Stichnoth | 8363a06 | 2014-10-07 10:02:38 -0700 | [diff] [blame] | 914 | } |
Jim Stichnoth | c4554d7 | 2014-09-30 16:49:38 -0700 | [diff] [blame] | 915 | |
Jim Stichnoth | d14b1a0 | 2014-10-08 08:28:36 -0700 | [diff] [blame] | 916 | void GlobalContext::resetTimer(TimerStackIdT StackID) { |
Jim Stichnoth | 380d7b9 | 2015-01-30 13:10:39 -0800 | [diff] [blame] | 917 | auto Timers = &ICE_TLS_GET_FIELD(TLS)->Timers; |
Jim Stichnoth | e4a8f40 | 2015-01-20 12:52:51 -0800 | [diff] [blame] | 918 | assert(StackID < Timers->size()); |
| 919 | Timers->at(StackID).reset(); |
Jim Stichnoth | d14b1a0 | 2014-10-08 08:28:36 -0700 | [diff] [blame] | 920 | } |
| 921 | |
| 922 | void GlobalContext::setTimerName(TimerStackIdT StackID, |
| 923 | const IceString &NewName) { |
Jim Stichnoth | 380d7b9 | 2015-01-30 13:10:39 -0800 | [diff] [blame] | 924 | auto Timers = &ICE_TLS_GET_FIELD(TLS)->Timers; |
Jim Stichnoth | e4a8f40 | 2015-01-20 12:52:51 -0800 | [diff] [blame] | 925 | assert(StackID < Timers->size()); |
| 926 | Timers->at(StackID).setName(NewName); |
Jim Stichnoth | d14b1a0 | 2014-10-08 08:28:36 -0700 | [diff] [blame] | 927 | } |
| 928 | |
Jim Stichnoth | bbca754 | 2015-02-11 16:08:31 -0800 | [diff] [blame] | 929 | // Note: optQueueBlockingPush and optQueueBlockingPop use unique_ptr |
Jim Stichnoth | 8e92838 | 2015-02-02 17:03:08 -0800 | [diff] [blame] | 930 | // at the interface to take and transfer ownership, but they |
| 931 | // internally store the raw Cfg pointer in the work queue. This |
| 932 | // allows e.g. future queue optimizations such as the use of atomics |
| 933 | // to modify queue elements. |
Jim Stichnoth | bbca754 | 2015-02-11 16:08:31 -0800 | [diff] [blame] | 934 | void GlobalContext::optQueueBlockingPush(std::unique_ptr<Cfg> Func) { |
| 935 | assert(Func); |
| 936 | OptQ.blockingPush(Func.release()); |
| 937 | if (getFlags().isSequential()) |
| 938 | translateFunctions(); |
Jim Stichnoth | 8e92838 | 2015-02-02 17:03:08 -0800 | [diff] [blame] | 939 | } |
| 940 | |
Jim Stichnoth | bbca754 | 2015-02-11 16:08:31 -0800 | [diff] [blame] | 941 | std::unique_ptr<Cfg> GlobalContext::optQueueBlockingPop() { |
| 942 | return std::unique_ptr<Cfg>(OptQ.blockingPop()); |
| 943 | } |
| 944 | |
| 945 | void GlobalContext::emitQueueBlockingPush(EmitterWorkItem *Item) { |
| 946 | assert(Item); |
| 947 | EmitQ.blockingPush(Item); |
| 948 | if (getFlags().isSequential()) |
| 949 | emitItems(); |
| 950 | } |
| 951 | |
| 952 | EmitterWorkItem *GlobalContext::emitQueueBlockingPop() { |
| 953 | return EmitQ.blockingPop(); |
Jim Stichnoth | 8e92838 | 2015-02-02 17:03:08 -0800 | [diff] [blame] | 954 | } |
| 955 | |
Jim Stichnoth | ff9c706 | 2014-09-18 04:50:49 -0700 | [diff] [blame] | 956 | void GlobalContext::dumpStats(const IceString &Name, bool Final) { |
Karl Schimpf | df80eb8 | 2015-02-09 14:20:22 -0800 | [diff] [blame] | 957 | if (!getFlags().getDumpStats()) |
Karl Schimpf | b6c96af | 2014-11-17 10:58:39 -0800 | [diff] [blame] | 958 | return; |
Jim Stichnoth | e4a8f40 | 2015-01-20 12:52:51 -0800 | [diff] [blame] | 959 | OstreamLocker OL(this); |
| 960 | if (Final) { |
| 961 | getStatsCumulative()->dump(Name, getStrDump()); |
| 962 | } else { |
Jim Stichnoth | a5fe17a | 2015-01-26 11:10:03 -0800 | [diff] [blame] | 963 | ICE_TLS_GET_FIELD(TLS)->StatsFunction.dump(Name, getStrDump()); |
Jim Stichnoth | 1873560 | 2014-09-16 19:59:35 -0700 | [diff] [blame] | 964 | } |
| 965 | } |
| 966 | |
Jim Stichnoth | 8363a06 | 2014-10-07 10:02:38 -0700 | [diff] [blame] | 967 | void GlobalContext::dumpTimers(TimerStackIdT StackID, bool DumpCumulative) { |
Jim Stichnoth | 20b71f5 | 2015-06-24 15:52:24 -0700 | [diff] [blame] | 968 | if (!BuildDefs::dump()) |
Karl Schimpf | b6c96af | 2014-11-17 10:58:39 -0800 | [diff] [blame] | 969 | return; |
Jim Stichnoth | e4a8f40 | 2015-01-20 12:52:51 -0800 | [diff] [blame] | 970 | auto Timers = getTimers(); |
| 971 | assert(Timers->size() > StackID); |
| 972 | OstreamLocker L(this); |
| 973 | Timers->at(StackID).dump(getStrDump(), DumpCumulative); |
Jim Stichnoth | 8363a06 | 2014-10-07 10:02:38 -0700 | [diff] [blame] | 974 | } |
| 975 | |
Jim Stichnoth | 380d7b9 | 2015-01-30 13:10:39 -0800 | [diff] [blame] | 976 | void TimerMarker::push() { |
| 977 | switch (StackID) { |
| 978 | case GlobalContext::TSK_Default: |
Karl Schimpf | df80eb8 | 2015-02-09 14:20:22 -0800 | [diff] [blame] | 979 | Active = Ctx->getFlags().getSubzeroTimingEnabled(); |
Jim Stichnoth | 380d7b9 | 2015-01-30 13:10:39 -0800 | [diff] [blame] | 980 | break; |
| 981 | case GlobalContext::TSK_Funcs: |
Karl Schimpf | df80eb8 | 2015-02-09 14:20:22 -0800 | [diff] [blame] | 982 | Active = Ctx->getFlags().getTimeEachFunction(); |
Jim Stichnoth | 380d7b9 | 2015-01-30 13:10:39 -0800 | [diff] [blame] | 983 | break; |
| 984 | default: |
| 985 | break; |
Jim Stichnoth | 1c44d81 | 2014-12-08 14:57:52 -0800 | [diff] [blame] | 986 | } |
Jim Stichnoth | 380d7b9 | 2015-01-30 13:10:39 -0800 | [diff] [blame] | 987 | if (Active) |
| 988 | Ctx->pushTimer(ID, StackID); |
| 989 | } |
| 990 | |
| 991 | void TimerMarker::pushCfg(const Cfg *Func) { |
| 992 | Ctx = Func->getContext(); |
Karl Schimpf | df80eb8 | 2015-02-09 14:20:22 -0800 | [diff] [blame] | 993 | Active = |
| 994 | Func->getFocusedTiming() || Ctx->getFlags().getSubzeroTimingEnabled(); |
Jim Stichnoth | 380d7b9 | 2015-01-30 13:10:39 -0800 | [diff] [blame] | 995 | if (Active) |
| 996 | Ctx->pushTimer(ID, StackID); |
Jim Stichnoth | 8363a06 | 2014-10-07 10:02:38 -0700 | [diff] [blame] | 997 | } |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 998 | |
Jim Stichnoth | a5fe17a | 2015-01-26 11:10:03 -0800 | [diff] [blame] | 999 | ICE_TLS_DEFINE_FIELD(GlobalContext::ThreadContext *, GlobalContext, TLS); |
Jim Stichnoth | e4a8f40 | 2015-01-20 12:52:51 -0800 | [diff] [blame] | 1000 | |
Jim Stichnoth | f7c9a14 | 2014-04-29 10:52:43 -0700 | [diff] [blame] | 1001 | } // end of namespace Ice |