Home | History | Annotate | Download | only in src
      1 //===- subzero/src/IceAssembler.cpp - Assembler base class ----------------===//
      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 // This is forked from Dart revision 39313.
      9 // Please update the revision if we merge back changes from Dart.
     10 // https://code.google.com/p/dart/wiki/GettingTheSource
     11 //
     12 //===----------------------------------------------------------------------===//
     13 //
     14 //                        The Subzero Code Generator
     15 //
     16 // This file is distributed under the University of Illinois Open Source
     17 // License. See LICENSE.TXT for details.
     18 //
     19 //===----------------------------------------------------------------------===//
     20 ///
     21 /// \file
     22 /// \brief Implements the Assembler base class.
     23 ///
     24 //===----------------------------------------------------------------------===//
     25 
     26 #include "IceAssembler.h"
     27 
     28 #include "IceGlobalContext.h"
     29 #include "IceOperand.h"
     30 
     31 namespace Ice {
     32 
     33 static uintptr_t NewContents(Assembler &Assemblr, intptr_t Capacity) {
     34   uintptr_t Result = Assemblr.allocateBytes(Capacity);
     35   return Result;
     36 }
     37 
     38 void Label::linkTo(const Assembler &Asm, intptr_t Pos) {
     39   // We must not set the link until the position is absolutely known. This means
     40   // not during the preliminary (sandboxing) pass, and not when the instruction
     41   // needs a text fixup (hybrid iasm mode).
     42   if (Asm.getPreliminary() || Asm.needsTextFixup())
     43     return;
     44   assert(!isBound());
     45   Position = Pos + kWordSize;
     46   assert(isLinked());
     47 }
     48 
     49 void AssemblerBuffer::installFixup(AssemblerFixup *F) {
     50   if (!Assemblr.getPreliminary())
     51     Fixups.push_back(F);
     52 }
     53 
     54 AssemblerFixup *AssemblerBuffer::createFixup(FixupKind Kind,
     55                                              const Constant *Value) {
     56   AssemblerFixup *F =
     57       new (Assemblr.allocate<AssemblerFixup>()) AssemblerFixup();
     58   F->set_kind(Kind);
     59   F->set_value(Value);
     60   installFixup(F);
     61   return F;
     62 }
     63 
     64 AssemblerTextFixup *AssemblerBuffer::createTextFixup(const std::string &Text,
     65                                                      size_t BytesUsed) {
     66   AssemblerTextFixup *F = new (Assemblr.allocate<AssemblerTextFixup>())
     67       AssemblerTextFixup(Text, BytesUsed);
     68   installFixup(F);
     69   resetNeedsTextFixup();
     70   return F;
     71 }
     72 
     73 void AssemblerBuffer::EnsureCapacity::validate(AssemblerBuffer *buffer) {
     74   // In debug mode, we save the assembler buffer along with the gap size before
     75   // we start emitting to the buffer. This allows us to check that any single
     76   // generated instruction doesn't overflow the limit implied by the minimum
     77   // gap size.
     78   Gap = computeGap();
     79   // Make sure that extending the capacity leaves a big enough gap for any kind
     80   // of instruction.
     81   assert(Gap >= kMinimumGap);
     82   // Mark the buffer as having ensured the capacity.
     83   assert(!buffer->hasEnsuredCapacity()); // Cannot nest.
     84   buffer->HasEnsuredCapacity = true;
     85 }
     86 
     87 AssemblerBuffer::EnsureCapacity::~EnsureCapacity() {
     88   // Unmark the buffer, so we cannot emit after this.
     89   Buffer->HasEnsuredCapacity = false;
     90   // Make sure the generated instruction doesn't take up more space than the
     91   // minimum gap.
     92   intptr_t delta = Gap - computeGap();
     93   (void)delta;
     94   assert(delta <= kMinimumGap);
     95 }
     96 
     97 AssemblerBuffer::AssemblerBuffer(Assembler &Asm) : Assemblr(Asm) {
     98   constexpr intptr_t OneKB = 1024;
     99   static constexpr intptr_t kInitialBufferCapacity = 4 * OneKB;
    100   Contents = NewContents(Assemblr, kInitialBufferCapacity);
    101   Cursor = Contents;
    102   Limit = computeLimit(Contents, kInitialBufferCapacity);
    103   HasEnsuredCapacity = false;
    104   TextFixupNeeded = false;
    105 
    106   // Verify internal state.
    107   assert(capacity() == kInitialBufferCapacity);
    108   assert(size() == 0);
    109 }
    110 
    111 AssemblerBuffer::~AssemblerBuffer() = default;
    112 
    113 void AssemblerBuffer::extendCapacity() {
    114   intptr_t old_size = size();
    115   intptr_t old_capacity = capacity();
    116   constexpr intptr_t OneMB = 1 << 20;
    117   intptr_t new_capacity = std::min(old_capacity * 2, old_capacity + OneMB);
    118   if (new_capacity < old_capacity) {
    119     llvm::report_fatal_error(
    120         "Unexpected overflow in AssemblerBuffer::ExtendCapacity");
    121   }
    122 
    123   // Allocate the new data area and copy contents of the old one to it.
    124   uintptr_t new_contents = NewContents(Assemblr, new_capacity);
    125   memmove(reinterpret_cast<void *>(new_contents),
    126           reinterpret_cast<void *>(Contents), old_size);
    127 
    128   // Compute the relocation delta and switch to the new contents area.
    129   intptr_t delta = new_contents - Contents;
    130   Contents = new_contents;
    131 
    132   // Update the cursor and recompute the limit.
    133   Cursor += delta;
    134   Limit = computeLimit(new_contents, new_capacity);
    135 
    136   // Verify internal state.
    137   assert(capacity() == new_capacity);
    138   assert(size() == old_size);
    139 }
    140 
    141 llvm::StringRef Assembler::getBufferView() const {
    142   return llvm::StringRef(reinterpret_cast<const char *>(Buffer.contents()),
    143                          Buffer.size());
    144 }
    145 
    146 void Assembler::bindRelocOffset(RelocOffset *Offset) {
    147   if (!getPreliminary()) {
    148     Offset->setOffset(Buffer.getPosition());
    149   }
    150 }
    151 
    152 void Assembler::emitIASBytes(GlobalContext *Ctx) const {
    153   Ostream &Str = Ctx->getStrEmit();
    154   intptr_t EndPosition = Buffer.size();
    155   intptr_t CurPosition = 0;
    156   for (const AssemblerFixup *NextFixup : fixups()) {
    157     intptr_t NextFixupLoc = NextFixup->position();
    158     for (intptr_t i = CurPosition; i < NextFixupLoc; ++i) {
    159       Str << "\t.byte 0x";
    160       Str.write_hex(Buffer.load<uint8_t>(i));
    161       Str << "\n";
    162     }
    163     CurPosition = NextFixupLoc + NextFixup->emit(Ctx, *this);
    164     assert(CurPosition <= EndPosition);
    165   }
    166   // Handle any bytes that are not prefixed by a fixup.
    167   for (intptr_t i = CurPosition; i < EndPosition; ++i) {
    168     Str << "\t.byte 0x";
    169     Str.write_hex(Buffer.load<uint8_t>(i));
    170     Str << "\n";
    171   }
    172 }
    173 
    174 } // end of namespace Ice
    175