blob: 7997865ac742b8c911dc72c47dc0d270a110c97c [file] [log] [blame]
Jan Voungf76fd372014-10-16 15:39:22 -07001//===- subzero/src/assembler.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//===----------------------------------------------------------------------===//
16//
17// This file declares the Assembler base class. Instructions are assembled
18// by architecture-specific assemblers that derive from this base class.
19// This base class manages buffers and fixups for emitting code, etc.
20//
21//===----------------------------------------------------------------------===//
22
23#ifndef SUBZERO_SRC_ASSEMBLER_H
24#define SUBZERO_SRC_ASSEMBLER_H
25
26#include "IceDefs.h"
Jan Voung8acded02014-09-22 18:02:25 -070027#include "IceFixups.h"
Jan Voung8acded02014-09-22 18:02:25 -070028
29namespace Ice {
30
Jan Voung8acded02014-09-22 18:02:25 -070031// Assembler buffers are used to emit binary code. They grow on demand.
32class AssemblerBuffer {
Jan Voungf76fd372014-10-16 15:39:22 -070033 AssemblerBuffer(const AssemblerBuffer &) = delete;
34 AssemblerBuffer &operator=(const AssemblerBuffer &) = delete;
35
Jan Voung8acded02014-09-22 18:02:25 -070036public:
37 AssemblerBuffer(Assembler &);
38 ~AssemblerBuffer();
39
40 // Basic support for emitting, loading, and storing.
41 template <typename T> void Emit(T value) {
42 assert(HasEnsuredCapacity());
43 *reinterpret_cast<T *>(cursor_) = value;
44 cursor_ += sizeof(T);
45 }
46
47 template <typename T> T Load(intptr_t position) const {
48 assert(position >= 0 &&
49 position <= (Size() - static_cast<intptr_t>(sizeof(T))));
50 return *reinterpret_cast<T *>(contents_ + position);
51 }
52
53 template <typename T> void Store(intptr_t position, T value) {
54 assert(position >= 0 &&
55 position <= (Size() - static_cast<intptr_t>(sizeof(T))));
56 *reinterpret_cast<T *>(contents_ + position) = value;
57 }
58
59 // Emit a fixup at the current location.
60 void EmitFixup(AssemblerFixup *fixup) {
61 fixup->set_position(Size());
Jan Voung8acded02014-09-22 18:02:25 -070062 }
63
64 // Get the size of the emitted code.
65 intptr_t Size() const { return cursor_ - contents_; }
66 uintptr_t contents() const { return contents_; }
67
Jan Voung8acded02014-09-22 18:02:25 -070068// To emit an instruction to the assembler buffer, the EnsureCapacity helper
69// must be used to guarantee that the underlying data area is big enough to
70// hold the emitted instruction. Usage:
71//
72// AssemblerBuffer buffer;
73// AssemblerBuffer::EnsureCapacity ensured(&buffer);
74// ... emit bytes for single instruction ...
75
Jan Voungf76fd372014-10-16 15:39:22 -070076#ifndef NDEBUG
Jan Voung8acded02014-09-22 18:02:25 -070077 class EnsureCapacity {
Jan Voungf76fd372014-10-16 15:39:22 -070078 EnsureCapacity(const EnsureCapacity &) = delete;
79 EnsureCapacity &operator=(const EnsureCapacity &) = delete;
80
Jan Voung8acded02014-09-22 18:02:25 -070081 public:
82 explicit EnsureCapacity(AssemblerBuffer *buffer);
83 ~EnsureCapacity();
84
85 private:
86 AssemblerBuffer *buffer_;
87 intptr_t gap_;
88
89 intptr_t ComputeGap() { return buffer_->Capacity() - buffer_->Size(); }
90 };
91
92 bool has_ensured_capacity_;
93 bool HasEnsuredCapacity() const { return has_ensured_capacity_; }
Jan Voungf76fd372014-10-16 15:39:22 -070094#else // NDEBUG
Jan Voung8acded02014-09-22 18:02:25 -070095 class EnsureCapacity {
Jan Voungf76fd372014-10-16 15:39:22 -070096 EnsureCapacity(const EnsureCapacity &) = delete;
97 EnsureCapacity &operator=(const EnsureCapacity &) = delete;
98
Jan Voung8acded02014-09-22 18:02:25 -070099 public:
100 explicit EnsureCapacity(AssemblerBuffer *buffer) {
101 if (buffer->cursor() >= buffer->limit())
102 buffer->ExtendCapacity();
103 }
104 };
105
106 // When building the C++ tests, assertion code is enabled. To allow
107 // asserting that the user of the assembler buffer has ensured the
108 // capacity needed for emitting, we add a dummy method in non-debug mode.
109 bool HasEnsuredCapacity() const { return true; }
Jan Voungf76fd372014-10-16 15:39:22 -0700110#endif // NDEBUG
Jan Voung8acded02014-09-22 18:02:25 -0700111
112 // Returns the position in the instruction stream.
113 intptr_t GetPosition() const { return cursor_ - contents_; }
114
Jan Voungec270732015-01-12 17:00:22 -0800115 // Create and track a fixup in the current function.
116 AssemblerFixup *createFixup(FixupKind Kind, const Constant *Value);
117
118 const FixupRefList &fixups() const { return fixups_; }
Jan Voung8acded02014-09-22 18:02:25 -0700119
120private:
121 // The limit is set to kMinimumGap bytes before the end of the data area.
122 // This leaves enough space for the longest possible instruction and allows
123 // for a single, fast space check per instruction.
124 static const intptr_t kMinimumGap = 32;
125
126 uintptr_t contents_;
127 uintptr_t cursor_;
128 uintptr_t limit_;
129 Assembler &assembler_;
Jan Voungec270732015-01-12 17:00:22 -0800130 // List of pool-allocated fixups relative to the current function.
131 FixupRefList fixups_;
Jan Voung8acded02014-09-22 18:02:25 -0700132
133 uintptr_t cursor() const { return cursor_; }
134 uintptr_t limit() const { return limit_; }
135 intptr_t Capacity() const {
136 assert(limit_ >= contents_);
137 return (limit_ - contents_) + kMinimumGap;
138 }
139
Jan Voung8acded02014-09-22 18:02:25 -0700140 // Compute the limit based on the data area and the capacity. See
141 // description of kMinimumGap for the reasoning behind the value.
142 static uintptr_t ComputeLimit(uintptr_t data, intptr_t capacity) {
143 return data + capacity - kMinimumGap;
144 }
145
146 void ExtendCapacity();
Jan Voung8acded02014-09-22 18:02:25 -0700147};
148
149class Assembler {
Jan Voungf76fd372014-10-16 15:39:22 -0700150 Assembler(const Assembler &) = delete;
151 Assembler &operator=(const Assembler &) = delete;
152
Jan Voung8acded02014-09-22 18:02:25 -0700153public:
Jan Voung0faec4c2014-11-05 17:29:56 -0800154 Assembler() : buffer_(*this) {}
Jan Voung7e1e4852014-10-24 10:29:30 -0700155 virtual ~Assembler() {}
Jan Voung8acded02014-09-22 18:02:25 -0700156
157 // Allocate a chunk of bytes using the per-Assembler allocator.
158 uintptr_t AllocateBytes(size_t bytes) {
159 // For now, alignment is not related to NaCl bundle alignment, since
160 // the buffer's GetPosition is relative to the base. So NaCl bundle
161 // alignment checks can be relative to that base. Later, the buffer
162 // will be copied out to a ".text" section (or an in memory-buffer
163 // that can be mprotect'ed with executable permission), and that
164 // second buffer should be aligned for NaCl.
165 const size_t Alignment = 16;
166 return reinterpret_cast<uintptr_t>(Allocator.Allocate(bytes, Alignment));
167 }
168
169 // Allocate data of type T using the per-Assembler allocator.
170 template <typename T> T *Allocate() { return Allocator.Allocate<T>(); }
171
Jan Voung08c3bcd2014-12-01 17:55:16 -0800172 // Align the tail end of the function to the required target alignment.
173 virtual void alignFunction() = 0;
174
175 virtual SizeT getBundleAlignLog2Bytes() const = 0;
176
177 virtual llvm::ArrayRef<uint8_t> getNonExecBundlePadding() const = 0;
178
179 // Mark the current text location as the start of a CFG node
180 // (represented by NodeNumber).
Jan Voung7e1e4852014-10-24 10:29:30 -0700181 virtual void BindCfgNodeLabel(SizeT NodeNumber) = 0;
182
Jan Voungec270732015-01-12 17:00:22 -0800183 virtual bool fixupIsPCRel(FixupKind Kind) const = 0;
184
Jan Voung08c3bcd2014-12-01 17:55:16 -0800185 // Return a view of all the bytes of code for the current function.
186 llvm::StringRef getBufferView() const;
187
Jan Voungec270732015-01-12 17:00:22 -0800188 const FixupRefList &fixups() const { return buffer_.fixups(); }
189
190 AssemblerFixup *createFixup(FixupKind Kind, const Constant *Value) {
191 return buffer_.createFixup(Kind, Value);
192 }
193
Jan Voung0faec4c2014-11-05 17:29:56 -0800194 void emitIASBytes(GlobalContext *Ctx) const;
195
Jan Voung8acded02014-09-22 18:02:25 -0700196private:
Jan Voung1d62cf02015-01-09 14:57:32 -0800197 ArenaAllocator<32 * 1024> Allocator;
Jan Voung0faec4c2014-11-05 17:29:56 -0800198
199protected:
200 AssemblerBuffer buffer_;
Jan Voung8acded02014-09-22 18:02:25 -0700201};
202
203} // end of namespace Ice
204
205#endif // SUBZERO_SRC_ASSEMBLER_H_