blob: 4e57a0cef74bba50ee0a9689ac045aac2bb41345 [file] [log] [blame]
John Portoaff4ccf2015-06-10 16:35:06 -07001//===- subzero/src/IceAssembler.h - Integrated assembler --------*- C++ -*-===//
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//===----------------------------------------------------------------------===//
Andrew Scull9612d322015-07-06 14:53:25 -070016///
17/// \file
Jim Stichnoth92a6e5b2015-12-02 16:52:44 -080018/// \brief Declares the Assembler base class.
19///
20/// Instructions are assembled by architecture-specific assemblers that derive
21/// from this base class. This base class manages buffers and fixups for
22/// emitting code, etc.
Andrew Scull9612d322015-07-06 14:53:25 -070023///
Jan Voung8acded02014-09-22 18:02:25 -070024//===----------------------------------------------------------------------===//
25
John Portoaff4ccf2015-06-10 16:35:06 -070026#ifndef SUBZERO_SRC_ICEASSEMBLER_H
27#define SUBZERO_SRC_ICEASSEMBLER_H
Jan Voung8acded02014-09-22 18:02:25 -070028
29#include "IceDefs.h"
Jan Voung8acded02014-09-22 18:02:25 -070030#include "IceFixups.h"
Jim Stichnoth467ffe52016-03-29 15:01:06 -070031#include "IceStringPool.h"
Andrew Scull86df4e92015-07-30 13:54:44 -070032#include "IceUtils.h"
Jan Voung8acded02014-09-22 18:02:25 -070033
John Portoe82b5602016-02-24 15:58:55 -080034#include "llvm/Support/Allocator.h"
35
Jan Voung8acded02014-09-22 18:02:25 -070036namespace Ice {
37
Karl Schimpf67574d82015-12-08 15:37:00 -080038class Assembler;
39
Andrew Scull86df4e92015-07-30 13:54:44 -070040/// A Label can be in one of three states:
41/// - Unused.
42/// - Linked, unplaced and tracking the position of branches to the label.
43/// - Bound, placed and tracking its position.
44class Label {
45 Label(const Label &) = delete;
46 Label &operator=(const Label &) = delete;
47
48public:
49 Label() = default;
Sean Kleinfc707ff2016-02-29 16:44:07 -080050 virtual ~Label() = default;
Andrew Scull86df4e92015-07-30 13:54:44 -070051
52 virtual void finalCheck() const {
53 // Assert if label is being destroyed with unresolved branches pending.
54 assert(!isLinked());
55 }
56
Karl Schimpf137e62b2015-10-27 07:28:09 -070057 /// Returns the encoded position stored in the label.
58 intptr_t getEncodedPosition() const { return Position; }
59
Andrew Scull86df4e92015-07-30 13:54:44 -070060 /// Returns the position for bound labels (branches that come after this are
61 /// considered backward branches). Cannot be used for unused or linked labels.
62 intptr_t getPosition() const {
63 assert(isBound());
64 return -Position - kWordSize;
65 }
66
67 /// Returns the position of an earlier branch instruction that was linked to
Andrew Scull57e12682015-09-16 11:30:19 -070068 /// this label (branches that use this are considered forward branches). The
Andrew Scull86df4e92015-07-30 13:54:44 -070069 /// linked instructions form a linked list, of sorts, using the instruction's
70 /// displacement field for the location of the next instruction that is also
71 /// linked to this label.
72 intptr_t getLinkPosition() const {
73 assert(isLinked());
74 return Position - kWordSize;
75 }
76
Karl Schimpfc5abdc12015-10-09 13:29:13 -070077 void setPosition(intptr_t NewValue) { Position = NewValue; }
78
Andrew Scull86df4e92015-07-30 13:54:44 -070079 bool isBound() const { return Position < 0; }
80 bool isLinked() const { return Position > 0; }
Karl Schimpfc5abdc12015-10-09 13:29:13 -070081
Andrew Scull86df4e92015-07-30 13:54:44 -070082 virtual bool isUnused() const { return Position == 0; }
83
Andrew Scull86df4e92015-07-30 13:54:44 -070084 void bindTo(intptr_t position) {
85 assert(!isBound());
86 Position = -position - kWordSize;
87 assert(isBound());
88 }
89
Karl Schimpf67574d82015-12-08 15:37:00 -080090 void linkTo(const Assembler &Asm, intptr_t position);
Andrew Scull86df4e92015-07-30 13:54:44 -070091
Karl Schimpf137e62b2015-10-27 07:28:09 -070092protected:
Andrew Scull86df4e92015-07-30 13:54:44 -070093 intptr_t Position = 0;
94
Andrew Scull86df4e92015-07-30 13:54:44 -070095 // TODO(jvoung): why are labels offset by this?
96 static constexpr uint32_t kWordSize = sizeof(uint32_t);
97};
98
Andrew Scull9612d322015-07-06 14:53:25 -070099/// Assembler buffers are used to emit binary code. They grow on demand.
Jan Voung8acded02014-09-22 18:02:25 -0700100class AssemblerBuffer {
Jan Voungf76fd372014-10-16 15:39:22 -0700101 AssemblerBuffer(const AssemblerBuffer &) = delete;
102 AssemblerBuffer &operator=(const AssemblerBuffer &) = delete;
103
Jan Voung8acded02014-09-22 18:02:25 -0700104public:
105 AssemblerBuffer(Assembler &);
106 ~AssemblerBuffer();
107
Andrew Scull6ef79492015-09-09 15:50:42 -0700108 /// \name Basic support for emitting, loading, and storing.
109 /// @{
110 // These use memcpy instead of assignment to avoid undefined behaviour of
111 // assigning to unaligned addresses. Since the size of the copy is known the
112 // compiler can inline the memcpy with simple moves.
John Portoaff4ccf2015-06-10 16:35:06 -0700113 template <typename T> void emit(T Value) {
114 assert(hasEnsuredCapacity());
Andrew Scull6ef79492015-09-09 15:50:42 -0700115 memcpy(reinterpret_cast<void *>(Cursor), &Value, sizeof(T));
John Portoaff4ccf2015-06-10 16:35:06 -0700116 Cursor += sizeof(T);
Jan Voung8acded02014-09-22 18:02:25 -0700117 }
118
John Portoaff4ccf2015-06-10 16:35:06 -0700119 template <typename T> T load(intptr_t Position) const {
120 assert(Position >= 0 &&
121 Position <= (size() - static_cast<intptr_t>(sizeof(T))));
Andrew Scull6ef79492015-09-09 15:50:42 -0700122 T Value;
123 memcpy(&Value, reinterpret_cast<void *>(Contents + Position), sizeof(T));
124 return Value;
Jan Voung8acded02014-09-22 18:02:25 -0700125 }
126
John Portoaff4ccf2015-06-10 16:35:06 -0700127 template <typename T> void store(intptr_t Position, T Value) {
128 assert(Position >= 0 &&
129 Position <= (size() - static_cast<intptr_t>(sizeof(T))));
Andrew Scull6ef79492015-09-09 15:50:42 -0700130 memcpy(reinterpret_cast<void *>(Contents + Position), &Value, sizeof(T));
Jan Voung8acded02014-09-22 18:02:25 -0700131 }
Andrew Scull6ef79492015-09-09 15:50:42 -0700132 /// @{
Jan Voung8acded02014-09-22 18:02:25 -0700133
Andrew Scull9612d322015-07-06 14:53:25 -0700134 /// Emit a fixup at the current location.
John Portoaff4ccf2015-06-10 16:35:06 -0700135 void emitFixup(AssemblerFixup *Fixup) { Fixup->set_position(size()); }
Jan Voung8acded02014-09-22 18:02:25 -0700136
Andrew Scull9612d322015-07-06 14:53:25 -0700137 /// Get the size of the emitted code.
John Portoaff4ccf2015-06-10 16:35:06 -0700138 intptr_t size() const { return Cursor - Contents; }
139 uintptr_t contents() const { return Contents; }
Jan Voung8acded02014-09-22 18:02:25 -0700140
Andrew Scull9612d322015-07-06 14:53:25 -0700141 /// To emit an instruction to the assembler buffer, the EnsureCapacity helper
142 /// must be used to guarantee that the underlying data area is big enough to
143 /// hold the emitted instruction. Usage:
144 ///
145 /// AssemblerBuffer buffer;
146 /// AssemblerBuffer::EnsureCapacity ensured(&buffer);
147 /// ... emit bytes for single instruction ...
Jan Voung8acded02014-09-22 18:02:25 -0700148 class EnsureCapacity {
Jan Voungf76fd372014-10-16 15:39:22 -0700149 EnsureCapacity(const EnsureCapacity &) = delete;
150 EnsureCapacity &operator=(const EnsureCapacity &) = delete;
151
Jan Voung8acded02014-09-22 18:02:25 -0700152 public:
Jim Stichnoth20b71f52015-06-24 15:52:24 -0700153 explicit EnsureCapacity(AssemblerBuffer *Buffer) : Buffer(Buffer) {
154 if (Buffer->cursor() >= Buffer->limit())
155 Buffer->extendCapacity();
156 if (BuildDefs::asserts())
157 validate(Buffer);
158 }
Jan Voung8acded02014-09-22 18:02:25 -0700159 ~EnsureCapacity();
160
161 private:
John Portoaff4ccf2015-06-10 16:35:06 -0700162 AssemblerBuffer *Buffer;
Jim Stichnoth20b71f52015-06-24 15:52:24 -0700163 intptr_t Gap = 0;
Jan Voung8acded02014-09-22 18:02:25 -0700164
Jim Stichnoth20b71f52015-06-24 15:52:24 -0700165 void validate(AssemblerBuffer *Buffer);
John Portoaff4ccf2015-06-10 16:35:06 -0700166 intptr_t computeGap() { return Buffer->capacity() - Buffer->size(); }
Jan Voung8acded02014-09-22 18:02:25 -0700167 };
168
John Portoaff4ccf2015-06-10 16:35:06 -0700169 bool HasEnsuredCapacity;
Jim Stichnoth20b71f52015-06-24 15:52:24 -0700170 bool hasEnsuredCapacity() const {
171 if (BuildDefs::asserts())
172 return HasEnsuredCapacity;
173 // Disable the actual check in non-debug mode.
174 return true;
175 }
Jan Voung8acded02014-09-22 18:02:25 -0700176
Andrew Scull9612d322015-07-06 14:53:25 -0700177 /// Returns the position in the instruction stream.
John Portoaff4ccf2015-06-10 16:35:06 -0700178 intptr_t getPosition() const { return Cursor - Contents; }
Jan Voung8acded02014-09-22 18:02:25 -0700179
Andrew Scull9612d322015-07-06 14:53:25 -0700180 /// Create and track a fixup in the current function.
Jan Voungec270732015-01-12 17:00:22 -0800181 AssemblerFixup *createFixup(FixupKind Kind, const Constant *Value);
182
Karl Schimpf2fee2a22015-10-22 08:19:26 -0700183 /// Create and track a textual fixup in the current function.
184 AssemblerTextFixup *createTextFixup(const std::string &Text,
185 size_t BytesUsed);
186
187 /// Mark that an attempt was made to emit, but failed. Hence, in order to
188 /// continue, one must emit a text fixup.
189 void setNeedsTextFixup() { TextFixupNeeded = true; }
Karl Schimpf82975ba2016-02-02 10:17:01 -0800190 void resetNeedsTextFixup() { TextFixupNeeded = false; }
Karl Schimpf2fee2a22015-10-22 08:19:26 -0700191
192 /// Returns true if last emit failed and needs a text fixup.
193 bool needsTextFixup() const { return TextFixupNeeded; }
194
195 /// Installs a created fixup, after it has been allocated.
196 void installFixup(AssemblerFixup *F);
197
John Portoaff4ccf2015-06-10 16:35:06 -0700198 const FixupRefList &fixups() const { return Fixups; }
Jan Voung8acded02014-09-22 18:02:25 -0700199
Jim Stichnoth9f42d8c2015-02-20 09:20:14 -0800200 void setSize(intptr_t NewSize) {
John Portoaff4ccf2015-06-10 16:35:06 -0700201 assert(NewSize <= size());
202 Cursor = Contents + NewSize;
Jim Stichnoth9f42d8c2015-02-20 09:20:14 -0800203 }
204
Jan Voung8acded02014-09-22 18:02:25 -0700205private:
Andrew Scull9612d322015-07-06 14:53:25 -0700206 /// The limit is set to kMinimumGap bytes before the end of the data area.
207 /// This leaves enough space for the longest possible instruction and allows
208 /// for a single, fast space check per instruction.
Jim Stichnoth20b71f52015-06-24 15:52:24 -0700209 static constexpr intptr_t kMinimumGap = 32;
Jan Voung8acded02014-09-22 18:02:25 -0700210
John Portoaff4ccf2015-06-10 16:35:06 -0700211 uintptr_t Contents;
212 uintptr_t Cursor;
213 uintptr_t Limit;
214 // The member variable is named Assemblr to avoid hiding the class Assembler.
215 Assembler &Assemblr;
Andrew Scull9612d322015-07-06 14:53:25 -0700216 /// List of pool-allocated fixups relative to the current function.
John Portoaff4ccf2015-06-10 16:35:06 -0700217 FixupRefList Fixups;
Karl Schimpf2fee2a22015-10-22 08:19:26 -0700218 // True if a textual fixup is needed, because the assembler was unable to
219 // emit the last request.
220 bool TextFixupNeeded;
Jan Voung8acded02014-09-22 18:02:25 -0700221
John Portoaff4ccf2015-06-10 16:35:06 -0700222 uintptr_t cursor() const { return Cursor; }
223 uintptr_t limit() const { return Limit; }
224 intptr_t capacity() const {
225 assert(Limit >= Contents);
226 return (Limit - Contents) + kMinimumGap;
Jan Voung8acded02014-09-22 18:02:25 -0700227 }
228
Andrew Scull57e12682015-09-16 11:30:19 -0700229 /// Compute the limit based on the data area and the capacity. See description
230 /// of kMinimumGap for the reasoning behind the value.
John Portoaff4ccf2015-06-10 16:35:06 -0700231 static uintptr_t computeLimit(uintptr_t Data, intptr_t Capacity) {
232 return Data + Capacity - kMinimumGap;
Jan Voung8acded02014-09-22 18:02:25 -0700233 }
234
John Portoaff4ccf2015-06-10 16:35:06 -0700235 void extendCapacity();
Jan Voung8acded02014-09-22 18:02:25 -0700236};
237
238class Assembler {
John Porto2da710c2015-06-29 07:57:02 -0700239 Assembler() = delete;
Jan Voungf76fd372014-10-16 15:39:22 -0700240 Assembler(const Assembler &) = delete;
241 Assembler &operator=(const Assembler &) = delete;
242
Jan Voung8acded02014-09-22 18:02:25 -0700243public:
John Porto2da710c2015-06-29 07:57:02 -0700244 enum AssemblerKind {
245 Asm_ARM32,
246 Asm_MIPS32,
247 Asm_X8632,
248 Asm_X8664,
249 };
250
John Portoaff4ccf2015-06-10 16:35:06 -0700251 virtual ~Assembler() = default;
Jan Voung8acded02014-09-22 18:02:25 -0700252
Andrew Scull9612d322015-07-06 14:53:25 -0700253 /// Allocate a chunk of bytes using the per-Assembler allocator.
John Portoaff4ccf2015-06-10 16:35:06 -0700254 uintptr_t allocateBytes(size_t bytes) {
Andrew Scull57e12682015-09-16 11:30:19 -0700255 // For now, alignment is not related to NaCl bundle alignment, since the
256 // buffer's GetPosition is relative to the base. So NaCl bundle alignment
257 // checks can be relative to that base. Later, the buffer will be copied
258 // out to a ".text" section (or an in memory-buffer that can be mprotect'ed
259 // with executable permission), and that second buffer should be aligned
260 // for NaCl.
Jan Voung8acded02014-09-22 18:02:25 -0700261 const size_t Alignment = 16;
262 return reinterpret_cast<uintptr_t>(Allocator.Allocate(bytes, Alignment));
263 }
264
Andrew Scull9612d322015-07-06 14:53:25 -0700265 /// Allocate data of type T using the per-Assembler allocator.
John Portoaff4ccf2015-06-10 16:35:06 -0700266 template <typename T> T *allocate() { return Allocator.Allocate<T>(); }
Jan Voung8acded02014-09-22 18:02:25 -0700267
Andrew Scull9612d322015-07-06 14:53:25 -0700268 /// Align the tail end of the function to the required target alignment.
Jan Voung08c3bcd2014-12-01 17:55:16 -0800269 virtual void alignFunction() = 0;
Andrew Scull86df4e92015-07-30 13:54:44 -0700270 /// Align the tail end of the basic block to the required target alignment.
271 void alignCfgNode() {
272 const SizeT Align = 1 << getBundleAlignLog2Bytes();
273 padWithNop(Utils::OffsetToAlignment(Buffer.getPosition(), Align));
274 }
Jan Voung08c3bcd2014-12-01 17:55:16 -0800275
Andrew Scull9612d322015-07-06 14:53:25 -0700276 /// Add nop padding of a particular width to the current bundle.
Jim Stichnoth9f42d8c2015-02-20 09:20:14 -0800277 virtual void padWithNop(intptr_t Padding) = 0;
278
Jan Voung08c3bcd2014-12-01 17:55:16 -0800279 virtual SizeT getBundleAlignLog2Bytes() const = 0;
280
Andrew Scull86df4e92015-07-30 13:54:44 -0700281 virtual const char *getAlignDirective() const = 0;
Jan Voung08c3bcd2014-12-01 17:55:16 -0800282 virtual llvm::ArrayRef<uint8_t> getNonExecBundlePadding() const = 0;
283
Andrew Scull86df4e92015-07-30 13:54:44 -0700284 /// Get the label for a CfgNode.
Jan Voungc2ec5812015-08-05 09:35:18 -0700285 virtual Label *getCfgNodeLabel(SizeT NodeNumber) = 0;
Karl Schimpf50a33312015-10-23 09:19:48 -0700286 /// Mark the current text location as the start of a CFG node.
287 virtual void bindCfgNodeLabel(const CfgNode *Node) = 0;
Jan Voung7e1e4852014-10-24 10:29:30 -0700288
Jan Voungec270732015-01-12 17:00:22 -0800289 virtual bool fixupIsPCRel(FixupKind Kind) const = 0;
290
Karl Schimpfe4289e22015-10-27 15:16:27 -0700291 /// Return a view of all the bytes of code for the current function.
Jan Voung08c3bcd2014-12-01 17:55:16 -0800292 llvm::StringRef getBufferView() const;
293
Karl Schimpfe4289e22015-10-27 15:16:27 -0700294 /// Return the value of the given type in the corresponding buffer.
295 template <typename T> T load(intptr_t Position) const {
296 return Buffer.load<T>(Position);
297 }
298
John Porto6e8d3fa2016-02-04 10:35:20 -0800299 template <typename T> void store(intptr_t Position, T Value) {
300 Buffer.store(Position, Value);
301 }
302
Karl Schimpf2fee2a22015-10-22 08:19:26 -0700303 /// Emit a fixup at the current location.
304 void emitFixup(AssemblerFixup *Fixup) { Buffer.emitFixup(Fixup); }
305
John Portoaff4ccf2015-06-10 16:35:06 -0700306 const FixupRefList &fixups() const { return Buffer.fixups(); }
Jan Voungec270732015-01-12 17:00:22 -0800307
308 AssemblerFixup *createFixup(FixupKind Kind, const Constant *Value) {
John Portoaff4ccf2015-06-10 16:35:06 -0700309 return Buffer.createFixup(Kind, Value);
Jan Voungec270732015-01-12 17:00:22 -0800310 }
311
Karl Schimpf2fee2a22015-10-22 08:19:26 -0700312 AssemblerTextFixup *createTextFixup(const std::string &Text,
313 size_t BytesUsed) {
314 return Buffer.createTextFixup(Text, BytesUsed);
315 }
316
John Portodc619252016-02-10 15:57:16 -0800317 void bindRelocOffset(RelocOffset *Offset);
318
Karl Schimpf2fee2a22015-10-22 08:19:26 -0700319 void setNeedsTextFixup() { Buffer.setNeedsTextFixup(); }
Karl Schimpf82975ba2016-02-02 10:17:01 -0800320 void resetNeedsTextFixup() { Buffer.resetNeedsTextFixup(); }
Karl Schimpf2fee2a22015-10-22 08:19:26 -0700321
322 bool needsTextFixup() const { return Buffer.needsTextFixup(); }
323
Jim Stichnoth5bff61c2015-10-28 09:26:00 -0700324 void emitIASBytes(GlobalContext *Ctx) const;
Jim Stichnothbbca7542015-02-11 16:08:31 -0800325 bool getInternal() const { return IsInternal; }
326 void setInternal(bool Internal) { IsInternal = Internal; }
Jim Stichnoth467ffe52016-03-29 15:01:06 -0700327 GlobalString getFunctionName() const { return FunctionName; }
328 void setFunctionName(GlobalString NewName) { FunctionName = NewName; }
John Portoaff4ccf2015-06-10 16:35:06 -0700329 intptr_t getBufferSize() const { return Buffer.size(); }
Andrew Scull9612d322015-07-06 14:53:25 -0700330 /// Roll back to a (smaller) size.
John Portoaff4ccf2015-06-10 16:35:06 -0700331 void setBufferSize(intptr_t NewSize) { Buffer.setSize(NewSize); }
Jim Stichnoth9f42d8c2015-02-20 09:20:14 -0800332 void setPreliminary(bool Value) { Preliminary = Value; }
333 bool getPreliminary() const { return Preliminary; }
Jan Voung0faec4c2014-11-05 17:29:56 -0800334
John Porto2da710c2015-06-29 07:57:02 -0700335 AssemblerKind getKind() const { return Kind; }
336
337protected:
Jim Stichnoth5bff61c2015-10-28 09:26:00 -0700338 explicit Assembler(AssemblerKind Kind)
339 : Kind(Kind), Allocator(), Buffer(*this) {}
John Porto2da710c2015-06-29 07:57:02 -0700340
Jan Voung8acded02014-09-22 18:02:25 -0700341private:
John Porto2da710c2015-06-29 07:57:02 -0700342 const AssemblerKind Kind;
343
John Portoe82b5602016-02-24 15:58:55 -0800344 using AssemblerAllocator =
345 llvm::BumpPtrAllocatorImpl<llvm::MallocAllocator, /*SlabSize=*/32 * 1024>;
346 AssemblerAllocator Allocator;
347
Andrew Scull57e12682015-09-16 11:30:19 -0700348 /// FunctionName and IsInternal are transferred from the original Cfg object,
349 /// since the Cfg object may be deleted by the time the assembler buffer is
350 /// emitted.
Jim Stichnoth467ffe52016-03-29 15:01:06 -0700351 GlobalString FunctionName;
Jim Stichnotheafb56c2015-06-22 10:35:22 -0700352 bool IsInternal = false;
Andrew Scull57e12682015-09-16 11:30:19 -0700353 /// Preliminary indicates whether a preliminary pass is being made for
354 /// calculating bundle padding (Preliminary=true), versus the final pass where
355 /// all changes to label bindings, label links, and relocation fixups are
356 /// fully committed (Preliminary=false).
Jim Stichnotheafb56c2015-06-22 10:35:22 -0700357 bool Preliminary = false;
John Porto1a9043e2015-06-11 09:35:18 -0700358
Karl Schimpf2fee2a22015-10-22 08:19:26 -0700359 /// Installs a created fixup, after it has been allocated.
360 void installFixup(AssemblerFixup *F) { Buffer.installFixup(F); }
361
John Porto1a9043e2015-06-11 09:35:18 -0700362protected:
363 // Buffer's constructor uses the Allocator, so it needs to appear after it.
364 // TODO(jpp): dependencies on construction order are a nice way of shooting
365 // yourself in the foot. Fix this.
366 AssemblerBuffer Buffer;
Jan Voung8acded02014-09-22 18:02:25 -0700367};
368
369} // end of namespace Ice
370
John Portoaff4ccf2015-06-10 16:35:06 -0700371#endif // SUBZERO_SRC_ICEASSEMBLER_H_