1 //===- subzero/src/IceDefs.h - Common Subzero declarations ------*- C++ -*-===// 2 // 3 // The Subzero Code Generator 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 /// 10 /// \file 11 /// \brief Declares various useful types and classes that have widespread use 12 /// across Subzero. 13 /// 14 //===----------------------------------------------------------------------===// 15 16 #ifndef SUBZERO_SRC_ICEDEFS_H 17 #define SUBZERO_SRC_ICEDEFS_H 18 19 #include "IceBuildDefs.h" // TODO(stichnot): move into individual files 20 #include "IceMemory.h" 21 #include "IceTLS.h" 22 23 #include "llvm/ADT/ArrayRef.h" 24 #include "llvm/ADT/ilist.h" 25 #include "llvm/ADT/ilist_node.h" 26 #include "llvm/ADT/iterator_range.h" 27 #include "llvm/ADT/SmallVector.h" 28 #include "llvm/ADT/STLExtras.h" 29 #include "llvm/Support/Casting.h" 30 #include "llvm/Support/ELF.h" 31 #include "llvm/Support/raw_ostream.h" 32 33 #include <cassert> 34 #include <cstdint> 35 #include <cstdio> // snprintf 36 #include <functional> // std::less 37 #include <limits> 38 #include <list> 39 #include <map> 40 #include <memory> 41 #include <mutex> 42 #include <set> 43 #include <string> 44 #include <system_error> 45 #include <unordered_map> 46 #include <unordered_set> 47 #include <utility> 48 #include <vector> 49 50 #define XSTRINGIFY(x) STRINGIFY(x) 51 #define STRINGIFY(x) #x 52 53 namespace Ice { 54 55 class Assembler; 56 template <template <typename> class> class BitVectorTmpl; 57 class Cfg; 58 class CfgNode; 59 class Constant; 60 class ELFFileStreamer; 61 class ELFObjectWriter; 62 class ELFStreamer; 63 class FunctionDeclaration; 64 class GlobalContext; 65 class GlobalDeclaration; 66 class Inst; 67 class InstAssign; 68 class InstJumpTable; 69 class InstPhi; 70 class InstSwitch; 71 class InstTarget; 72 class LiveRange; 73 class Liveness; 74 class Operand; 75 class TargetDataLowering; 76 class TargetLowering; 77 class Variable; 78 class VariableDeclaration; 79 class VariablesMetadata; 80 81 /// SizeT is for holding small-ish limits like number of source operands in an 82 /// instruction. It is used instead of size_t (which may be 64-bits wide) when 83 /// we want to save space. 84 using SizeT = uint32_t; 85 86 constexpr char GlobalOffsetTable[] = "_GLOBAL_OFFSET_TABLE_"; 87 // makeUnique should be used when memory is expected to be allocated from the 88 // heap (as opposed to allocated from some Allocator.) It is intended to be 89 // used instead of new. 90 // 91 // The expected usage is as follows 92 // 93 // class MyClass { 94 // public: 95 // static std::unique_ptr<MyClass> create(<ctor_args>) { 96 // return makeUnique<MyClass>(<ctor_args>); 97 // } 98 // 99 // private: 100 // ENABLE_MAKE_UNIQUE; 101 // 102 // MyClass(<ctor_args>) ... 103 // } 104 // 105 // ENABLE_MAKE_UNIQUE is a trick that is necessary if MyClass' ctor is private. 106 // Private ctors are highly encouraged when you're writing a class that you'd 107 // like to have allocated with makeUnique as it would prevent users from 108 // declaring stack allocated variables. 109 namespace Internal { 110 struct MakeUniqueEnabler { 111 template <class T, class... Args> 112 static std::unique_ptr<T> create(Args &&... TheArgs) { 113 std::unique_ptr<T> Unique(new T(std::forward<Args>(TheArgs)...)); 114 return Unique; 115 } 116 }; 117 } // end of namespace Internal 118 119 template <class T, class... Args> 120 static std::unique_ptr<T> makeUnique(Args &&... TheArgs) { 121 return ::Ice::Internal::MakeUniqueEnabler::create<T>( 122 std::forward<Args>(TheArgs)...); 123 } 124 125 #define ENABLE_MAKE_UNIQUE friend struct ::Ice::Internal::MakeUniqueEnabler 126 127 using InstList = llvm::ilist<Inst>; 128 // Ideally PhiList would be llvm::ilist<InstPhi>, and similar for AssignList, 129 // but this runs into issues with SFINAE. 130 using PhiList = InstList; 131 using AssignList = InstList; 132 133 // Standard library containers with CfgLocalAllocator. 134 template <typename T> using CfgList = std::list<T, CfgLocalAllocator<T>>; 135 template <typename T, typename H = std::hash<T>, typename Eq = std::equal_to<T>> 136 using CfgUnorderedSet = std::unordered_set<T, H, Eq, CfgLocalAllocator<T>>; 137 template <typename T, typename Cmp = std::less<T>> 138 using CfgSet = std::set<T, Cmp, CfgLocalAllocator<T>>; 139 template <typename T, typename U, typename H = std::hash<T>, 140 typename Eq = std::equal_to<T>> 141 using CfgUnorderedMap = 142 std::unordered_map<T, U, H, Eq, CfgLocalAllocator<std::pair<const T, U>>>; 143 template <typename T> using CfgVector = std::vector<T, CfgLocalAllocator<T>>; 144 145 // Containers that are arena-allocated from the Cfg's allocator. 146 using OperandList = CfgVector<Operand *>; 147 using VarList = CfgVector<Variable *>; 148 using NodeList = CfgVector<CfgNode *>; 149 150 // Containers that use the default (global) allocator. 151 using ConstantList = std::vector<Constant *>; 152 using FunctionDeclarationList = std::vector<FunctionDeclaration *>; 153 154 /// VariableDeclarationList is a container for holding VariableDeclarations -- 155 /// i.e., Global Variables. It is also used to create said variables, and their 156 /// initializers in an arena. 157 class VariableDeclarationList { 158 VariableDeclarationList(const VariableDeclarationList &) = delete; 159 VariableDeclarationList &operator=(const VariableDeclarationList &) = delete; 160 VariableDeclarationList(VariableDeclarationList &&) = delete; 161 VariableDeclarationList &operator=(VariableDeclarationList &&) = delete; 162 163 public: 164 using VariableDeclarationArray = std::vector<VariableDeclaration *>; 165 166 VariableDeclarationList() : Arena(new ArenaAllocator()) {} 167 168 ~VariableDeclarationList() { clearAndPurge(); } 169 170 template <typename T> T *allocate_initializer(SizeT Count = 1) { 171 static_assert( 172 std::is_trivially_destructible<T>::value, 173 "allocate_initializer can only allocate trivially destructible types."); 174 return Arena->Allocate<T>(Count); 175 } 176 177 template <typename T> T *allocate_variable_declaration() { 178 static_assert(!std::is_trivially_destructible<T>::value, 179 "allocate_variable_declaration expects non-trivially " 180 "destructible types."); 181 T *Ret = Arena->Allocate<T>(); 182 Dtors.emplace_back([Ret]() { Ret->~T(); }); 183 return Ret; 184 } 185 186 // This do nothing method is invoked when a global variable is created, but it 187 // will not be emitted. If we ever need to track the created variable, having 188 // this hook is handy. 189 void willNotBeEmitted(VariableDeclaration *) {} 190 191 /// Merges Other with this, effectively resetting Other to an empty state. 192 void merge(VariableDeclarationList *Other) { 193 assert(Other != nullptr); 194 addArena(std::move(Other->Arena)); 195 for (std::size_t i = 0; i < Other->MergedArenas.size(); ++i) { 196 addArena(std::move(Other->MergedArenas[i])); 197 } 198 Other->MergedArenas.clear(); 199 200 Dtors.insert(Dtors.end(), Other->Dtors.begin(), Other->Dtors.end()); 201 Other->Dtors.clear(); 202 203 Globals.insert(Globals.end(), Other->Globals.begin(), Other->Globals.end()); 204 Other->Globals.clear(); 205 } 206 207 /// Destroys all GlobalVariables and initializers that this knows about 208 /// (including those merged with it), and releases memory. 209 void clearAndPurge() { 210 if (Arena == nullptr) { 211 // Arena is only null if this was merged, so we ensure there's no state 212 // being held by this. 213 assert(Dtors.empty()); 214 assert(Globals.empty()); 215 assert(MergedArenas.empty()); 216 return; 217 } 218 // Invokes destructors in reverse creation order. 219 for (auto Dtor = Dtors.rbegin(); Dtor != Dtors.rend(); ++Dtor) { 220 (*Dtor)(); 221 } 222 Dtors.clear(); 223 Globals.clear(); 224 MergedArenas.clear(); 225 Arena->Reset(); 226 } 227 228 /// Adapt the relevant parts of the std::vector<VariableDeclaration *> 229 /// interface. 230 /// @{ 231 VariableDeclarationArray::iterator begin() { return Globals.begin(); } 232 233 VariableDeclarationArray::iterator end() { return Globals.end(); } 234 235 VariableDeclarationArray::const_iterator begin() const { 236 return Globals.begin(); 237 } 238 239 VariableDeclarationArray::const_iterator end() const { return Globals.end(); } 240 241 bool empty() const { return Globals.empty(); } 242 243 VariableDeclarationArray::size_type size() const { return Globals.size(); } 244 245 VariableDeclarationArray::reference 246 at(VariableDeclarationArray::size_type Pos) { 247 return Globals.at(Pos); 248 } 249 250 void push_back(VariableDeclaration *Global) { Globals.push_back(Global); } 251 252 void reserve(VariableDeclarationArray::size_type Capacity) { 253 Globals.reserve(Capacity); 254 } 255 256 void clear() { Globals.clear(); } 257 258 VariableDeclarationArray::reference back() { return Globals.back(); } 259 /// @} 260 261 private: 262 using ArenaPtr = std::unique_ptr<ArenaAllocator>; 263 using DestructorsArray = std::vector<std::function<void()>>; 264 265 void addArena(ArenaPtr NewArena) { 266 MergedArenas.emplace_back(std::move(NewArena)); 267 } 268 269 ArenaPtr Arena; 270 VariableDeclarationArray Globals; 271 DestructorsArray Dtors; 272 std::vector<ArenaPtr> MergedArenas; 273 }; 274 275 /// InstNumberT is for holding an instruction number. Instruction numbers are 276 /// used for representing Variable live ranges. 277 using InstNumberT = int32_t; 278 279 /// A LiveBeginEndMapEntry maps a Variable::Number value to an Inst::Number 280 /// value, giving the instruction number that begins or ends a variable's live 281 /// range. 282 template <typename T> 283 using LivenessVector = std::vector<T, LivenessAllocator<T>>; 284 using LiveBeginEndMapEntry = std::pair<SizeT, InstNumberT>; 285 using LiveBeginEndMap = LivenessVector<LiveBeginEndMapEntry>; 286 using LivenessBV = BitVectorTmpl<LivenessAllocator>; 287 288 using TimerStackIdT = uint32_t; 289 using TimerIdT = uint32_t; 290 291 /// Use alignas(MaxCacheLineSize) to isolate variables/fields that might be 292 /// contended while multithreading. Assumes the maximum cache line size is 64. 293 enum { MaxCacheLineSize = 64 }; 294 // Use ICE_CACHELINE_BOUNDARY to force the next field in a declaration 295 // list to be aligned to the next cache line. 296 #if defined(_MSC_VER) 297 #define ICE_CACHELINE_BOUNDARY __declspec(align(MaxCacheLineSize)) int : 0; 298 #else // !defined(_MSC_VER) 299 // Note: zero is added to work around the following GCC 4.8 bug (fixed in 4.9): 300 // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=55382 301 #define ICE_CACHELINE_BOUNDARY \ 302 __attribute__((aligned(MaxCacheLineSize + 0))) int : 0 303 #endif // !defined(_MSC_VER) 304 305 /// PNaCl is ILP32, so theoretically we should only need 32-bit offsets. 306 using RelocOffsetT = int32_t; 307 enum { RelocAddrSize = 4 }; 308 309 enum LivenessMode { 310 /// Basic version of live-range-end calculation. Marks the last uses of 311 /// variables based on dataflow analysis. Records the set of live-in and 312 /// live-out variables for each block. Identifies and deletes dead 313 /// instructions (primarily stores). 314 Liveness_Basic, 315 316 /// In addition to Liveness_Basic, also calculate the complete live range for 317 /// each variable in a form suitable for interference calculation and register 318 /// allocation. 319 Liveness_Intervals 320 }; 321 322 enum LCSEOptions { 323 LCSE_Disabled, 324 LCSE_EnabledSSA, // Default Mode, assumes SSA. 325 LCSE_EnabledNoSSA // Does not assume SSA, to be enabled if CSE is done later. 326 }; 327 328 enum RegAllocKind { 329 RAK_Unknown, 330 RAK_Global, /// full, global register allocation 331 RAK_SecondChance, /// second-chance bin-packing after full regalloc attempt 332 RAK_Phi, /// infinite-weight Variables with active spilling/filling 333 RAK_InfOnly /// allocation only for infinite-weight Variables 334 }; 335 336 enum VerboseItem { 337 IceV_None = 0, 338 IceV_Instructions = 1 << 0, 339 IceV_Deleted = 1 << 1, 340 IceV_InstNumbers = 1 << 2, 341 IceV_Preds = 1 << 3, 342 IceV_Succs = 1 << 4, 343 IceV_Liveness = 1 << 5, 344 IceV_RegOrigins = 1 << 6, 345 IceV_LinearScan = 1 << 7, 346 IceV_Frame = 1 << 8, 347 IceV_AddrOpt = 1 << 9, 348 IceV_Random = 1 << 10, 349 IceV_Folding = 1 << 11, 350 IceV_RMW = 1 << 12, 351 IceV_Loop = 1 << 13, 352 IceV_Mem = 1 << 14, 353 // Leave some extra space to make it easier to add new per-pass items. 354 IceV_NO_PER_PASS_DUMP_BEYOND = 1 << 19, 355 // Items greater than IceV_NO_PER_PASS_DUMP_BEYOND don't by themselves trigger 356 // per-pass Cfg dump output. 357 IceV_Status = 1 << 20, 358 IceV_AvailableRegs = 1 << 21, 359 IceV_GlobalInit = 1 << 22, 360 IceV_ConstPoolStats = 1 << 23, 361 IceV_Wasm = 1 << 24, 362 IceV_ShufMat = 1 << 25, 363 IceV_All = ~IceV_None, 364 IceV_Most = 365 IceV_All & ~IceV_LinearScan & ~IceV_GlobalInit & ~IceV_ConstPoolStats 366 }; 367 using VerboseMask = uint32_t; 368 369 enum FileType { 370 FT_Elf, /// ELF .o file 371 FT_Asm, /// Assembly .s file 372 FT_Iasm /// "Integrated assembler" .byte-style .s file 373 }; 374 375 enum ABI { 376 ABI_PNaCl, /// x32 for unsandboxed 64-bit x86 377 ABI_Platform /// Native executable ABI 378 }; 379 380 using Ostream = llvm::raw_ostream; 381 using Fdstream = llvm::raw_fd_ostream; 382 383 using GlobalLockType = std::mutex; 384 385 /// LockedPtr is an RAII wrapper that allows automatically locked access to a 386 /// given pointer, automatically unlocking it when when the LockedPtr goes out 387 /// of scope. 388 template <typename T> class LockedPtr { 389 LockedPtr() = delete; 390 LockedPtr(const LockedPtr &) = delete; 391 LockedPtr &operator=(const LockedPtr &) = delete; 392 393 public: 394 LockedPtr(T *Value, GlobalLockType *Lock) : Value(Value), Lock(Lock) { 395 Lock->lock(); 396 } 397 LockedPtr(LockedPtr &&Other) : Value(Other.Value), Lock(Other.Lock) { 398 Other.Value = nullptr; 399 Other.Lock = nullptr; 400 } 401 ~LockedPtr() { 402 if (Lock != nullptr) 403 Lock->unlock(); 404 } 405 T *operator->() const { return Value; } 406 T &operator*() const { return *Value; } 407 T *get() { return Value; } 408 409 private: 410 T *Value; 411 GlobalLockType *Lock; 412 }; 413 414 enum ErrorCodes { EC_None = 0, EC_Args, EC_Bitcode, EC_Translation }; 415 416 /// Wrapper around std::error_code for allowing multiple errors to be folded 417 /// into one. The current implementation keeps track of the first error, which 418 /// is likely to be the most useful one, and this could be extended to e.g. 419 /// collect a vector of errors. 420 class ErrorCode : public std::error_code { 421 ErrorCode(const ErrorCode &) = delete; 422 ErrorCode &operator=(const ErrorCode &) = delete; 423 424 public: 425 ErrorCode() = default; 426 void assign(ErrorCodes Code) { 427 if (!HasError) { 428 HasError = true; 429 std::error_code::assign(Code, std::generic_category()); 430 } 431 } 432 void assign(int Code) { assign(static_cast<ErrorCodes>(Code)); } 433 434 private: 435 bool HasError = false; 436 }; 437 438 /// Reverse range adaptors written in terms of llvm::make_range(). 439 template <typename T> 440 llvm::iterator_range<typename T::const_reverse_iterator> 441 reverse_range(const T &Container) { 442 return llvm::make_range(Container.rbegin(), Container.rend()); 443 } 444 template <typename T> 445 llvm::iterator_range<typename T::reverse_iterator> reverse_range(T &Container) { 446 return llvm::make_range(Container.rbegin(), Container.rend()); 447 } 448 449 /// Options for pooling and randomization of immediates. 450 enum RandomizeAndPoolImmediatesEnum { RPI_None, RPI_Randomize, RPI_Pool }; 451 452 /// Salts for Random number generator for different randomization passes. 453 enum RandomizationPassesEnum { 454 RPE_BasicBlockReordering, 455 RPE_ConstantBlinding, 456 RPE_FunctionReordering, 457 RPE_GlobalVariableReordering, 458 RPE_NopInsertion, 459 RPE_PooledConstantReordering, 460 RPE_RegAllocRandomization, 461 RPE_num 462 }; 463 464 using RelocOffsetArray = llvm::SmallVector<class RelocOffset *, 4>; 465 466 } // end of namespace Ice 467 468 #endif // SUBZERO_SRC_ICEDEFS_H 469