OLD | NEW |
| 1 //===- subzero/src/assembler.h - Integrated assembler -----------*- C++ -*-===// |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 2 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 3 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 4 // BSD-style license that can be found in the LICENSE file. |
4 // | 5 // |
5 // Modified by the Subzero authors. | 6 // Modified by the Subzero authors. |
6 // | 7 // |
7 //===- subzero/src/assembler.h - Integrated assembler -----------*- C++ -*-===// | 8 //===----------------------------------------------------------------------===// |
8 // | 9 // |
9 // The Subzero Code Generator | 10 // The Subzero Code Generator |
10 // | 11 // |
11 // This file is distributed under the University of Illinois Open Source | 12 // This file is distributed under the University of Illinois Open Source |
12 // License. See LICENSE.TXT for details. | 13 // License. See LICENSE.TXT for details. |
13 // | 14 // |
14 //===----------------------------------------------------------------------===// | 15 //===----------------------------------------------------------------------===// |
15 // | 16 // |
16 // This file declares the Assembler base class. Instructions are assembled | 17 // This file declares the Assembler base class. Instructions are assembled |
17 // by architecture-specific assemblers that derive from this base class. | 18 // by architecture-specific assemblers that derive from this base class. |
(...skipping 15 matching lines...) Expand all Loading... |
33 class Assembler; | 34 class Assembler; |
34 class AssemblerFixup; | 35 class AssemblerFixup; |
35 class AssemblerBuffer; | 36 class AssemblerBuffer; |
36 class ConstantRelocatable; | 37 class ConstantRelocatable; |
37 class MemoryRegion; | 38 class MemoryRegion; |
38 | 39 |
39 // Assembler fixups are positions in generated code that hold relocation | 40 // Assembler fixups are positions in generated code that hold relocation |
40 // information that needs to be processed before finalizing the code | 41 // information that needs to be processed before finalizing the code |
41 // into executable memory. | 42 // into executable memory. |
42 class AssemblerFixup { | 43 class AssemblerFixup { |
| 44 AssemblerFixup(const AssemblerFixup &) = delete; |
| 45 AssemblerFixup &operator=(const AssemblerFixup &) = delete; |
| 46 |
43 public: | 47 public: |
44 virtual void Process(const MemoryRegion ®ion, intptr_t position) = 0; | 48 virtual void Process(const MemoryRegion ®ion, intptr_t position) = 0; |
45 | 49 |
46 // It would be ideal if the destructor method could be made private, | 50 // It would be ideal if the destructor method could be made private, |
47 // but the g++ compiler complains when this is subclassed. | 51 // but the g++ compiler complains when this is subclassed. |
48 virtual ~AssemblerFixup() { llvm_unreachable("~AssemblerFixup used"); } | 52 virtual ~AssemblerFixup() { llvm_unreachable("~AssemblerFixup used"); } |
49 | 53 |
50 intptr_t position() const { return position_; } | 54 intptr_t position() const { return position_; } |
51 | 55 |
52 FixupKind kind() const { return kind_; } | 56 FixupKind kind() const { return kind_; } |
53 | 57 |
54 const ConstantRelocatable *value() const { return value_; } | 58 const ConstantRelocatable *value() const { return value_; } |
55 | 59 |
56 protected: | 60 protected: |
57 AssemblerFixup(FixupKind Kind, const ConstantRelocatable *Value) | 61 AssemblerFixup(FixupKind Kind, const ConstantRelocatable *Value) |
58 : position_(0), kind_(Kind), value_(Value) {} | 62 : position_(0), kind_(Kind), value_(Value) {} |
59 | 63 |
60 private: | 64 private: |
61 intptr_t position_; | 65 intptr_t position_; |
62 FixupKind kind_; | 66 FixupKind kind_; |
63 const ConstantRelocatable *value_; | 67 const ConstantRelocatable *value_; |
64 | 68 |
65 void set_position(intptr_t position) { position_ = position; } | 69 void set_position(intptr_t position) { position_ = position; } |
66 | 70 |
67 AssemblerFixup(const AssemblerFixup &) = delete; | |
68 AssemblerFixup &operator=(const AssemblerFixup &) = delete; | |
69 friend class AssemblerBuffer; | 71 friend class AssemblerBuffer; |
70 }; | 72 }; |
71 | 73 |
72 // Assembler buffers are used to emit binary code. They grow on demand. | 74 // Assembler buffers are used to emit binary code. They grow on demand. |
73 class AssemblerBuffer { | 75 class AssemblerBuffer { |
| 76 AssemblerBuffer(const AssemblerBuffer &) = delete; |
| 77 AssemblerBuffer &operator=(const AssemblerBuffer &) = delete; |
| 78 |
74 public: | 79 public: |
75 AssemblerBuffer(Assembler &); | 80 AssemblerBuffer(Assembler &); |
76 ~AssemblerBuffer(); | 81 ~AssemblerBuffer(); |
77 | 82 |
78 // Basic support for emitting, loading, and storing. | 83 // Basic support for emitting, loading, and storing. |
79 template <typename T> void Emit(T value) { | 84 template <typename T> void Emit(T value) { |
80 assert(HasEnsuredCapacity()); | 85 assert(HasEnsuredCapacity()); |
81 *reinterpret_cast<T *>(cursor_) = value; | 86 *reinterpret_cast<T *>(cursor_) = value; |
82 cursor_ += sizeof(T); | 87 cursor_ += sizeof(T); |
83 } | 88 } |
(...skipping 27 matching lines...) Expand all Loading... |
111 void FinalizeInstructions(const MemoryRegion ®ion); | 116 void FinalizeInstructions(const MemoryRegion ®ion); |
112 | 117 |
113 // To emit an instruction to the assembler buffer, the EnsureCapacity helper | 118 // To emit an instruction to the assembler buffer, the EnsureCapacity helper |
114 // must be used to guarantee that the underlying data area is big enough to | 119 // must be used to guarantee that the underlying data area is big enough to |
115 // hold the emitted instruction. Usage: | 120 // hold the emitted instruction. Usage: |
116 // | 121 // |
117 // AssemblerBuffer buffer; | 122 // AssemblerBuffer buffer; |
118 // AssemblerBuffer::EnsureCapacity ensured(&buffer); | 123 // AssemblerBuffer::EnsureCapacity ensured(&buffer); |
119 // ... emit bytes for single instruction ... | 124 // ... emit bytes for single instruction ... |
120 | 125 |
121 #if defined(DEBUG) | 126 #ifndef NDEBUG |
122 class EnsureCapacity { | 127 class EnsureCapacity { |
| 128 EnsureCapacity(const EnsureCapacity &) = delete; |
| 129 EnsureCapacity &operator=(const EnsureCapacity &) = delete; |
| 130 |
123 public: | 131 public: |
124 explicit EnsureCapacity(AssemblerBuffer *buffer); | 132 explicit EnsureCapacity(AssemblerBuffer *buffer); |
125 ~EnsureCapacity(); | 133 ~EnsureCapacity(); |
126 | 134 |
127 private: | 135 private: |
128 AssemblerBuffer *buffer_; | 136 AssemblerBuffer *buffer_; |
129 intptr_t gap_; | 137 intptr_t gap_; |
130 | 138 |
131 intptr_t ComputeGap() { return buffer_->Capacity() - buffer_->Size(); } | 139 intptr_t ComputeGap() { return buffer_->Capacity() - buffer_->Size(); } |
132 }; | 140 }; |
133 | 141 |
134 bool has_ensured_capacity_; | 142 bool has_ensured_capacity_; |
135 bool HasEnsuredCapacity() const { return has_ensured_capacity_; } | 143 bool HasEnsuredCapacity() const { return has_ensured_capacity_; } |
136 #else | 144 #else // NDEBUG |
137 class EnsureCapacity { | 145 class EnsureCapacity { |
| 146 EnsureCapacity(const EnsureCapacity &) = delete; |
| 147 EnsureCapacity &operator=(const EnsureCapacity &) = delete; |
| 148 |
138 public: | 149 public: |
139 explicit EnsureCapacity(AssemblerBuffer *buffer) { | 150 explicit EnsureCapacity(AssemblerBuffer *buffer) { |
140 if (buffer->cursor() >= buffer->limit()) | 151 if (buffer->cursor() >= buffer->limit()) |
141 buffer->ExtendCapacity(); | 152 buffer->ExtendCapacity(); |
142 } | 153 } |
143 }; | 154 }; |
144 | 155 |
145 // When building the C++ tests, assertion code is enabled. To allow | 156 // When building the C++ tests, assertion code is enabled. To allow |
146 // asserting that the user of the assembler buffer has ensured the | 157 // asserting that the user of the assembler buffer has ensured the |
147 // capacity needed for emitting, we add a dummy method in non-debug mode. | 158 // capacity needed for emitting, we add a dummy method in non-debug mode. |
148 bool HasEnsuredCapacity() const { return true; } | 159 bool HasEnsuredCapacity() const { return true; } |
149 #endif | 160 #endif // NDEBUG |
150 | 161 |
151 // Returns the position in the instruction stream. | 162 // Returns the position in the instruction stream. |
152 intptr_t GetPosition() const { return cursor_ - contents_; } | 163 intptr_t GetPosition() const { return cursor_ - contents_; } |
153 | 164 |
154 // For bringup only. | 165 // For bringup only. |
155 AssemblerFixup *GetLatestFixup() const; | 166 AssemblerFixup *GetLatestFixup() const; |
156 | 167 |
157 private: | 168 private: |
158 // The limit is set to kMinimumGap bytes before the end of the data area. | 169 // The limit is set to kMinimumGap bytes before the end of the data area. |
159 // This leaves enough space for the longest possible instruction and allows | 170 // This leaves enough space for the longest possible instruction and allows |
160 // for a single, fast space check per instruction. | 171 // for a single, fast space check per instruction. |
161 static const intptr_t kMinimumGap = 32; | 172 static const intptr_t kMinimumGap = 32; |
162 | 173 |
163 uintptr_t contents_; | 174 uintptr_t contents_; |
164 uintptr_t cursor_; | 175 uintptr_t cursor_; |
165 uintptr_t limit_; | 176 uintptr_t limit_; |
166 Assembler &assembler_; | 177 Assembler &assembler_; |
167 std::vector<AssemblerFixup *> fixups_; | 178 std::vector<AssemblerFixup *> fixups_; |
168 #if defined(DEBUG) | 179 #ifndef NDEBUG |
169 bool fixups_processed_; | 180 bool fixups_processed_; |
170 #endif | 181 #endif // !NDEBUG |
171 | 182 |
172 uintptr_t cursor() const { return cursor_; } | 183 uintptr_t cursor() const { return cursor_; } |
173 uintptr_t limit() const { return limit_; } | 184 uintptr_t limit() const { return limit_; } |
174 intptr_t Capacity() const { | 185 intptr_t Capacity() const { |
175 assert(limit_ >= contents_); | 186 assert(limit_ >= contents_); |
176 return (limit_ - contents_) + kMinimumGap; | 187 return (limit_ - contents_) + kMinimumGap; |
177 } | 188 } |
178 | 189 |
179 // Process the fixup chain. | 190 // Process the fixup chain. |
180 void ProcessFixups(const MemoryRegion ®ion); | 191 void ProcessFixups(const MemoryRegion ®ion); |
181 | 192 |
182 // Compute the limit based on the data area and the capacity. See | 193 // Compute the limit based on the data area and the capacity. See |
183 // description of kMinimumGap for the reasoning behind the value. | 194 // description of kMinimumGap for the reasoning behind the value. |
184 static uintptr_t ComputeLimit(uintptr_t data, intptr_t capacity) { | 195 static uintptr_t ComputeLimit(uintptr_t data, intptr_t capacity) { |
185 return data + capacity - kMinimumGap; | 196 return data + capacity - kMinimumGap; |
186 } | 197 } |
187 | 198 |
188 void ExtendCapacity(); | 199 void ExtendCapacity(); |
189 | 200 |
190 friend class AssemblerFixup; | 201 friend class AssemblerFixup; |
191 }; | 202 }; |
192 | 203 |
193 class Assembler { | 204 class Assembler { |
| 205 Assembler(const Assembler &) = delete; |
| 206 Assembler &operator=(const Assembler &) = delete; |
| 207 |
194 public: | 208 public: |
195 Assembler() {} | 209 Assembler() {} |
196 ~Assembler() {} | 210 ~Assembler() {} |
197 | 211 |
198 // Allocate a chunk of bytes using the per-Assembler allocator. | 212 // Allocate a chunk of bytes using the per-Assembler allocator. |
199 uintptr_t AllocateBytes(size_t bytes) { | 213 uintptr_t AllocateBytes(size_t bytes) { |
200 // For now, alignment is not related to NaCl bundle alignment, since | 214 // For now, alignment is not related to NaCl bundle alignment, since |
201 // the buffer's GetPosition is relative to the base. So NaCl bundle | 215 // the buffer's GetPosition is relative to the base. So NaCl bundle |
202 // alignment checks can be relative to that base. Later, the buffer | 216 // alignment checks can be relative to that base. Later, the buffer |
203 // will be copied out to a ".text" section (or an in memory-buffer | 217 // will be copied out to a ".text" section (or an in memory-buffer |
204 // that can be mprotect'ed with executable permission), and that | 218 // that can be mprotect'ed with executable permission), and that |
205 // second buffer should be aligned for NaCl. | 219 // second buffer should be aligned for NaCl. |
206 const size_t Alignment = 16; | 220 const size_t Alignment = 16; |
207 return reinterpret_cast<uintptr_t>(Allocator.Allocate(bytes, Alignment)); | 221 return reinterpret_cast<uintptr_t>(Allocator.Allocate(bytes, Alignment)); |
208 } | 222 } |
209 | 223 |
210 // Allocate data of type T using the per-Assembler allocator. | 224 // Allocate data of type T using the per-Assembler allocator. |
211 template <typename T> T *Allocate() { return Allocator.Allocate<T>(); } | 225 template <typename T> T *Allocate() { return Allocator.Allocate<T>(); } |
212 | 226 |
213 private: | 227 private: |
214 llvm::BumpPtrAllocator Allocator; | 228 llvm::BumpPtrAllocator Allocator; |
215 | |
216 Assembler(const Assembler &) = delete; | |
217 Assembler &operator=(const Assembler &) = delete; | |
218 }; | 229 }; |
219 | 230 |
220 } // end of namespace Ice | 231 } // end of namespace Ice |
221 | 232 |
222 #endif // SUBZERO_SRC_ASSEMBLER_H_ | 233 #endif // SUBZERO_SRC_ASSEMBLER_H_ |
OLD | NEW |