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