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