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