blob: 6f2ec8118c92545f98bdbdefc21853828eb820d6 [file] [log] [blame]
Jan Voungf76fd372014-10-16 15:39:22 -07001//===- subzero/src/assembler.cpp - Assembler base class -------------------===//
Jan Voung8acded02014-09-22 18:02:25 -07002// 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//
Jan Voungf76fd372014-10-16 15:39:22 -07008//===----------------------------------------------------------------------===//
Jan Voung8acded02014-09-22 18:02:25 -07009//
10// The Subzero Code Generator
11//
12// This file is distributed under the University of Illinois Open Source
13// License. See LICENSE.TXT for details.
14//
15//===----------------------------------------------------------------------===//
16//
17// This file implements the Assembler class.
18//
19//===----------------------------------------------------------------------===//
20
21#include "assembler.h"
22#include "IceMemoryRegion.h"
23
24namespace Ice {
25
26static uintptr_t NewContents(Assembler &assembler, intptr_t capacity) {
27 uintptr_t result = assembler.AllocateBytes(capacity);
28 return result;
29}
30
Jan Voungf76fd372014-10-16 15:39:22 -070031#ifndef NDEBUG
Jan Voung8acded02014-09-22 18:02:25 -070032AssemblerBuffer::EnsureCapacity::EnsureCapacity(AssemblerBuffer *buffer) {
33 if (buffer->cursor() >= buffer->limit())
34 buffer->ExtendCapacity();
35 // In debug mode, we save the assembler buffer along with the gap
36 // size before we start emitting to the buffer. This allows us to
37 // check that any single generated instruction doesn't overflow the
38 // limit implied by the minimum gap size.
39 buffer_ = buffer;
40 gap_ = ComputeGap();
41 // Make sure that extending the capacity leaves a big enough gap
42 // for any kind of instruction.
43 assert(gap_ >= kMinimumGap);
44 // Mark the buffer as having ensured the capacity.
45 assert(!buffer->HasEnsuredCapacity()); // Cannot nest.
46 buffer->has_ensured_capacity_ = true;
47}
48
49AssemblerBuffer::EnsureCapacity::~EnsureCapacity() {
50 // Unmark the buffer, so we cannot emit after this.
51 buffer_->has_ensured_capacity_ = false;
52 // Make sure the generated instruction doesn't take up more
53 // space than the minimum gap.
54 intptr_t delta = gap_ - ComputeGap();
55 assert(delta <= kMinimumGap);
56}
Jan Voungf76fd372014-10-16 15:39:22 -070057#endif // !NDEBUG
Jan Voung8acded02014-09-22 18:02:25 -070058
59AssemblerBuffer::AssemblerBuffer(Assembler &assembler) : assembler_(assembler) {
60 const intptr_t OneKB = 1024;
61 static const intptr_t kInitialBufferCapacity = 4 * OneKB;
62 contents_ = NewContents(assembler_, kInitialBufferCapacity);
63 cursor_ = contents_;
64 limit_ = ComputeLimit(contents_, kInitialBufferCapacity);
Jan Voungf76fd372014-10-16 15:39:22 -070065#ifndef NDEBUG
Jan Voung8acded02014-09-22 18:02:25 -070066 has_ensured_capacity_ = false;
67 fixups_processed_ = false;
Jan Voungf76fd372014-10-16 15:39:22 -070068#endif // !NDEBUG
Jan Voung8acded02014-09-22 18:02:25 -070069
70 // Verify internal state.
71 assert(Capacity() == kInitialBufferCapacity);
72 assert(Size() == 0);
73}
74
75AssemblerBuffer::~AssemblerBuffer() {}
76
77AssemblerFixup *AssemblerBuffer::GetLatestFixup() const {
78 if (fixups_.empty())
79 return NULL;
80 return fixups_.back();
81}
82
83void AssemblerBuffer::ProcessFixups(const MemoryRegion &region) {
84 for (SizeT I = 0; I < fixups_.size(); ++I) {
85 AssemblerFixup *fixup = fixups_[I];
86 fixup->Process(region, fixup->position());
87 }
88}
89
90void AssemblerBuffer::FinalizeInstructions(const MemoryRegion &instructions) {
91 // Copy the instructions from the buffer.
92 MemoryRegion from(reinterpret_cast<void *>(contents()), Size());
93 instructions.CopyFrom(0, from);
94
95 // Process fixups in the instructions.
96 ProcessFixups(instructions);
Jan Voungf76fd372014-10-16 15:39:22 -070097#ifndef NDEBUG
Jan Voung8acded02014-09-22 18:02:25 -070098 fixups_processed_ = true;
Jan Voungf76fd372014-10-16 15:39:22 -070099#endif // !NDEBUG
Jan Voung8acded02014-09-22 18:02:25 -0700100}
101
102void AssemblerBuffer::ExtendCapacity() {
103 intptr_t old_size = Size();
104 intptr_t old_capacity = Capacity();
105 const intptr_t OneMB = 1 << 20;
106 intptr_t new_capacity = std::min(old_capacity * 2, old_capacity + OneMB);
107 if (new_capacity < old_capacity) {
108 // FATAL
109 llvm_unreachable("Unexpected overflow in AssemblerBuffer::ExtendCapacity");
110 }
111
112 // Allocate the new data area and copy contents of the old one to it.
113 uintptr_t new_contents = NewContents(assembler_, new_capacity);
114 memmove(reinterpret_cast<void *>(new_contents),
115 reinterpret_cast<void *>(contents_), old_size);
116
117 // Compute the relocation delta and switch to the new contents area.
118 intptr_t delta = new_contents - contents_;
119 contents_ = new_contents;
120
121 // Update the cursor and recompute the limit.
122 cursor_ += delta;
123 limit_ = ComputeLimit(new_contents, new_capacity);
124
125 // Verify internal state.
126 assert(Capacity() == new_capacity);
127 assert(Size() == old_size);
128}
129
130} // end of namespace Ice