• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
NewContents(Assembler & Assemblr,intptr_t Capacity)33 static uintptr_t NewContents(Assembler &Assemblr, intptr_t Capacity) {
34   uintptr_t Result = Assemblr.allocateBytes(Capacity);
35   return Result;
36 }
37 
linkTo(const Assembler & Asm,intptr_t Pos)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 
installFixup(AssemblerFixup * F)49 void AssemblerBuffer::installFixup(AssemblerFixup *F) {
50   if (!Assemblr.getPreliminary())
51     Fixups.push_back(F);
52 }
53 
createFixup(FixupKind Kind,const Constant * Value)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 
createTextFixup(const std::string & Text,size_t BytesUsed)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 
validate(AssemblerBuffer * buffer)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 
~EnsureCapacity()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 
AssemblerBuffer(Assembler & Asm)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 
extendCapacity()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 
getBufferView() const141 llvm::StringRef Assembler::getBufferView() const {
142   return llvm::StringRef(reinterpret_cast<const char *>(Buffer.contents()),
143                          Buffer.size());
144 }
145 
bindRelocOffset(RelocOffset * Offset)146 void Assembler::bindRelocOffset(RelocOffset *Offset) {
147   if (!getPreliminary()) {
148     Offset->setOffset(Buffer.getPosition());
149   }
150 }
151 
emitIASBytes(GlobalContext * Ctx) const152 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