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