1 //===- subzero/src/IceAssembler.h - Integrated assembler --------*- C++ -*-===// 2 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 3 // for details. All rights reserved. Use of this source code is governed by a 4 // BSD-style license that can be found in the LICENSE file. 5 // 6 // Modified by the Subzero authors. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // The Subzero Code Generator 11 // 12 // This file is distributed under the University of Illinois Open Source 13 // License. See LICENSE.TXT for details. 14 // 15 //===----------------------------------------------------------------------===// 16 /// 17 /// \file 18 /// \brief Declares the Assembler base class. 19 /// 20 /// Instructions are assembled by architecture-specific assemblers that derive 21 /// from this base class. This base class manages buffers and fixups for 22 /// emitting code, etc. 23 /// 24 //===----------------------------------------------------------------------===// 25 26 #ifndef SUBZERO_SRC_ICEASSEMBLER_H 27 #define SUBZERO_SRC_ICEASSEMBLER_H 28 29 #include "IceDefs.h" 30 #include "IceFixups.h" 31 #include "IceStringPool.h" 32 #include "IceUtils.h" 33 34 #include "llvm/Support/Allocator.h" 35 36 namespace Ice { 37 38 class Assembler; 39 40 /// A Label can be in one of three states: 41 /// - Unused. 42 /// - Linked, unplaced and tracking the position of branches to the label. 43 /// - Bound, placed and tracking its position. 44 class Label { 45 Label(const Label &) = delete; 46 Label &operator=(const Label &) = delete; 47 48 public: 49 Label() = default; 50 virtual ~Label() = default; 51 finalCheck()52 virtual void finalCheck() const { 53 // Assert if label is being destroyed with unresolved branches pending. 54 assert(!isLinked()); 55 } 56 57 /// Returns the encoded position stored in the label. getEncodedPosition()58 intptr_t getEncodedPosition() const { return Position; } 59 60 /// Returns the position for bound labels (branches that come after this are 61 /// considered backward branches). Cannot be used for unused or linked labels. getPosition()62 intptr_t getPosition() const { 63 assert(isBound()); 64 return -Position - kWordSize; 65 } 66 67 /// Returns the position of an earlier branch instruction that was linked to 68 /// this label (branches that use this are considered forward branches). The 69 /// linked instructions form a linked list, of sorts, using the instruction's 70 /// displacement field for the location of the next instruction that is also 71 /// linked to this label. getLinkPosition()72 intptr_t getLinkPosition() const { 73 assert(isLinked()); 74 return Position - kWordSize; 75 } 76 setPosition(intptr_t NewValue)77 void setPosition(intptr_t NewValue) { Position = NewValue; } 78 isBound()79 bool isBound() const { return Position < 0; } isLinked()80 bool isLinked() const { return Position > 0; } 81 isUnused()82 virtual bool isUnused() const { return Position == 0; } 83 bindTo(intptr_t position)84 void bindTo(intptr_t position) { 85 assert(!isBound()); 86 Position = -position - kWordSize; 87 assert(isBound()); 88 } 89 90 void linkTo(const Assembler &Asm, intptr_t position); 91 92 protected: 93 intptr_t Position = 0; 94 95 // TODO(jvoung): why are labels offset by this? 96 static constexpr uint32_t kWordSize = sizeof(uint32_t); 97 }; 98 99 /// Assembler buffers are used to emit binary code. They grow on demand. 100 class AssemblerBuffer { 101 AssemblerBuffer(const AssemblerBuffer &) = delete; 102 AssemblerBuffer &operator=(const AssemblerBuffer &) = delete; 103 104 public: 105 AssemblerBuffer(Assembler &); 106 ~AssemblerBuffer(); 107 108 /// \name Basic support for emitting, loading, and storing. 109 /// @{ 110 // These use memcpy instead of assignment to avoid undefined behaviour of 111 // assigning to unaligned addresses. Since the size of the copy is known the 112 // compiler can inline the memcpy with simple moves. emit(T Value)113 template <typename T> void emit(T Value) { 114 assert(hasEnsuredCapacity()); 115 memcpy(reinterpret_cast<void *>(Cursor), &Value, sizeof(T)); 116 Cursor += sizeof(T); 117 } 118 load(intptr_t Position)119 template <typename T> T load(intptr_t Position) const { 120 assert(Position >= 0 && 121 Position <= (size() - static_cast<intptr_t>(sizeof(T)))); 122 T Value; 123 memcpy(&Value, reinterpret_cast<void *>(Contents + Position), sizeof(T)); 124 return Value; 125 } 126 store(intptr_t Position,T Value)127 template <typename T> void store(intptr_t Position, T Value) { 128 assert(Position >= 0 && 129 Position <= (size() - static_cast<intptr_t>(sizeof(T)))); 130 memcpy(reinterpret_cast<void *>(Contents + Position), &Value, sizeof(T)); 131 } 132 /// @{ 133 134 /// Emit a fixup at the current location. emitFixup(AssemblerFixup * Fixup)135 void emitFixup(AssemblerFixup *Fixup) { Fixup->set_position(size()); } 136 137 /// Get the size of the emitted code. size()138 intptr_t size() const { return Cursor - Contents; } contents()139 uintptr_t contents() const { return Contents; } 140 141 /// To emit an instruction to the assembler buffer, the EnsureCapacity helper 142 /// must be used to guarantee that the underlying data area is big enough to 143 /// hold the emitted instruction. Usage: 144 /// 145 /// AssemblerBuffer buffer; 146 /// AssemblerBuffer::EnsureCapacity ensured(&buffer); 147 /// ... emit bytes for single instruction ... 148 class EnsureCapacity { 149 EnsureCapacity(const EnsureCapacity &) = delete; 150 EnsureCapacity &operator=(const EnsureCapacity &) = delete; 151 152 public: EnsureCapacity(AssemblerBuffer * Buffer)153 explicit EnsureCapacity(AssemblerBuffer *Buffer) : Buffer(Buffer) { 154 if (Buffer->cursor() >= Buffer->limit()) 155 Buffer->extendCapacity(); 156 if (BuildDefs::asserts()) 157 validate(Buffer); 158 } 159 ~EnsureCapacity(); 160 161 private: 162 AssemblerBuffer *Buffer; 163 intptr_t Gap = 0; 164 165 void validate(AssemblerBuffer *Buffer); computeGap()166 intptr_t computeGap() { return Buffer->capacity() - Buffer->size(); } 167 }; 168 169 bool HasEnsuredCapacity; hasEnsuredCapacity()170 bool hasEnsuredCapacity() const { 171 if (BuildDefs::asserts()) 172 return HasEnsuredCapacity; 173 // Disable the actual check in non-debug mode. 174 return true; 175 } 176 177 /// Returns the position in the instruction stream. getPosition()178 intptr_t getPosition() const { return Cursor - Contents; } 179 180 /// Create and track a fixup in the current function. 181 AssemblerFixup *createFixup(FixupKind Kind, const Constant *Value); 182 183 /// Create and track a textual fixup in the current function. 184 AssemblerTextFixup *createTextFixup(const std::string &Text, 185 size_t BytesUsed); 186 187 /// Mark that an attempt was made to emit, but failed. Hence, in order to 188 /// continue, one must emit a text fixup. setNeedsTextFixup()189 void setNeedsTextFixup() { TextFixupNeeded = true; } resetNeedsTextFixup()190 void resetNeedsTextFixup() { TextFixupNeeded = false; } 191 192 /// Returns true if last emit failed and needs a text fixup. needsTextFixup()193 bool needsTextFixup() const { return TextFixupNeeded; } 194 195 /// Installs a created fixup, after it has been allocated. 196 void installFixup(AssemblerFixup *F); 197 fixups()198 const FixupRefList &fixups() const { return Fixups; } 199 setSize(intptr_t NewSize)200 void setSize(intptr_t NewSize) { 201 assert(NewSize <= size()); 202 Cursor = Contents + NewSize; 203 } 204 205 private: 206 /// The limit is set to kMinimumGap bytes before the end of the data area. 207 /// This leaves enough space for the longest possible instruction and allows 208 /// for a single, fast space check per instruction. 209 static constexpr intptr_t kMinimumGap = 32; 210 211 uintptr_t Contents; 212 uintptr_t Cursor; 213 uintptr_t Limit; 214 // The member variable is named Assemblr to avoid hiding the class Assembler. 215 Assembler &Assemblr; 216 /// List of pool-allocated fixups relative to the current function. 217 FixupRefList Fixups; 218 // True if a textual fixup is needed, because the assembler was unable to 219 // emit the last request. 220 bool TextFixupNeeded; 221 cursor()222 uintptr_t cursor() const { return Cursor; } limit()223 uintptr_t limit() const { return Limit; } capacity()224 intptr_t capacity() const { 225 assert(Limit >= Contents); 226 return (Limit - Contents) + kMinimumGap; 227 } 228 229 /// Compute the limit based on the data area and the capacity. See description 230 /// of kMinimumGap for the reasoning behind the value. computeLimit(uintptr_t Data,intptr_t Capacity)231 static uintptr_t computeLimit(uintptr_t Data, intptr_t Capacity) { 232 return Data + Capacity - kMinimumGap; 233 } 234 235 void extendCapacity(); 236 }; 237 238 class Assembler { 239 Assembler() = delete; 240 Assembler(const Assembler &) = delete; 241 Assembler &operator=(const Assembler &) = delete; 242 243 public: 244 enum AssemblerKind { 245 Asm_ARM32, 246 Asm_MIPS32, 247 Asm_X8632, 248 Asm_X8664, 249 }; 250 251 virtual ~Assembler() = default; 252 253 /// Allocate a chunk of bytes using the per-Assembler allocator. allocateBytes(size_t bytes)254 uintptr_t allocateBytes(size_t bytes) { 255 // For now, alignment is not related to NaCl bundle alignment, since the 256 // buffer's GetPosition is relative to the base. So NaCl bundle alignment 257 // checks can be relative to that base. Later, the buffer will be copied 258 // out to a ".text" section (or an in memory-buffer that can be mprotect'ed 259 // with executable permission), and that second buffer should be aligned 260 // for NaCl. 261 const size_t Alignment = 16; 262 return reinterpret_cast<uintptr_t>(Allocator.Allocate(bytes, Alignment)); 263 } 264 265 /// Allocate data of type T using the per-Assembler allocator. allocate()266 template <typename T> T *allocate() { return Allocator.Allocate<T>(); } 267 268 /// Align the tail end of the function to the required target alignment. 269 virtual void alignFunction() = 0; 270 /// Align the tail end of the basic block to the required target alignment. alignCfgNode()271 void alignCfgNode() { 272 const SizeT Align = 1 << getBundleAlignLog2Bytes(); 273 padWithNop(Utils::OffsetToAlignment(Buffer.getPosition(), Align)); 274 } 275 276 /// Add nop padding of a particular width to the current bundle. 277 virtual void padWithNop(intptr_t Padding) = 0; 278 279 virtual SizeT getBundleAlignLog2Bytes() const = 0; 280 281 virtual const char *getAlignDirective() const = 0; 282 virtual llvm::ArrayRef<uint8_t> getNonExecBundlePadding() const = 0; 283 284 /// Get the label for a CfgNode. 285 virtual Label *getCfgNodeLabel(SizeT NodeNumber) = 0; 286 /// Mark the current text location as the start of a CFG node. 287 virtual void bindCfgNodeLabel(const CfgNode *Node) = 0; 288 289 virtual bool fixupIsPCRel(FixupKind Kind) const = 0; 290 291 /// Return a view of all the bytes of code for the current function. 292 llvm::StringRef getBufferView() const; 293 294 /// Return the value of the given type in the corresponding buffer. load(intptr_t Position)295 template <typename T> T load(intptr_t Position) const { 296 return Buffer.load<T>(Position); 297 } 298 store(intptr_t Position,T Value)299 template <typename T> void store(intptr_t Position, T Value) { 300 Buffer.store(Position, Value); 301 } 302 303 /// Emit a fixup at the current location. emitFixup(AssemblerFixup * Fixup)304 void emitFixup(AssemblerFixup *Fixup) { Buffer.emitFixup(Fixup); } 305 fixups()306 const FixupRefList &fixups() const { return Buffer.fixups(); } 307 createFixup(FixupKind Kind,const Constant * Value)308 AssemblerFixup *createFixup(FixupKind Kind, const Constant *Value) { 309 return Buffer.createFixup(Kind, Value); 310 } 311 createTextFixup(const std::string & Text,size_t BytesUsed)312 AssemblerTextFixup *createTextFixup(const std::string &Text, 313 size_t BytesUsed) { 314 return Buffer.createTextFixup(Text, BytesUsed); 315 } 316 317 void bindRelocOffset(RelocOffset *Offset); 318 setNeedsTextFixup()319 void setNeedsTextFixup() { Buffer.setNeedsTextFixup(); } resetNeedsTextFixup()320 void resetNeedsTextFixup() { Buffer.resetNeedsTextFixup(); } 321 needsTextFixup()322 bool needsTextFixup() const { return Buffer.needsTextFixup(); } 323 324 void emitIASBytes(GlobalContext *Ctx) const; getInternal()325 bool getInternal() const { return IsInternal; } setInternal(bool Internal)326 void setInternal(bool Internal) { IsInternal = Internal; } getFunctionName()327 GlobalString getFunctionName() const { return FunctionName; } setFunctionName(GlobalString NewName)328 void setFunctionName(GlobalString NewName) { FunctionName = NewName; } getBufferSize()329 intptr_t getBufferSize() const { return Buffer.size(); } 330 /// Roll back to a (smaller) size. setBufferSize(intptr_t NewSize)331 void setBufferSize(intptr_t NewSize) { Buffer.setSize(NewSize); } setPreliminary(bool Value)332 void setPreliminary(bool Value) { Preliminary = Value; } getPreliminary()333 bool getPreliminary() const { return Preliminary; } 334 getKind()335 AssemblerKind getKind() const { return Kind; } 336 337 protected: Assembler(AssemblerKind Kind)338 explicit Assembler(AssemblerKind Kind) 339 : Kind(Kind), Allocator(), Buffer(*this) {} 340 341 private: 342 const AssemblerKind Kind; 343 344 using AssemblerAllocator = 345 llvm::BumpPtrAllocatorImpl<llvm::MallocAllocator, /*SlabSize=*/32 * 1024>; 346 AssemblerAllocator Allocator; 347 348 /// FunctionName and IsInternal are transferred from the original Cfg object, 349 /// since the Cfg object may be deleted by the time the assembler buffer is 350 /// emitted. 351 GlobalString FunctionName; 352 bool IsInternal = false; 353 /// Preliminary indicates whether a preliminary pass is being made for 354 /// calculating bundle padding (Preliminary=true), versus the final pass where 355 /// all changes to label bindings, label links, and relocation fixups are 356 /// fully committed (Preliminary=false). 357 bool Preliminary = false; 358 359 /// Installs a created fixup, after it has been allocated. installFixup(AssemblerFixup * F)360 void installFixup(AssemblerFixup *F) { Buffer.installFixup(F); } 361 362 protected: 363 // Buffer's constructor uses the Allocator, so it needs to appear after it. 364 // TODO(jpp): dependencies on construction order are a nice way of shooting 365 // yourself in the foot. Fix this. 366 AssemblerBuffer Buffer; 367 }; 368 369 } // end of namespace Ice 370 371 #endif // SUBZERO_SRC_ICEASSEMBLER_H_ 372