Home | History | Annotate | Download | only in src
      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