xref: /aosp_15_r20/external/swiftshader/third_party/subzero/src/IceAssembler.h (revision 03ce13f70fcc45d86ee91b7ee4cab1936a95046e)
1*03ce13f7SAndroid Build Coastguard Worker //===- subzero/src/IceAssembler.h - Integrated assembler --------*- C++ -*-===//
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 //===----------------------------------------------------------------------===//
9*03ce13f7SAndroid Build Coastguard Worker //
10*03ce13f7SAndroid Build Coastguard Worker //                        The Subzero Code Generator
11*03ce13f7SAndroid Build Coastguard Worker //
12*03ce13f7SAndroid Build Coastguard Worker // This file is distributed under the University of Illinois Open Source
13*03ce13f7SAndroid Build Coastguard Worker // License. See LICENSE.TXT for details.
14*03ce13f7SAndroid Build Coastguard Worker //
15*03ce13f7SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
16*03ce13f7SAndroid Build Coastguard Worker ///
17*03ce13f7SAndroid Build Coastguard Worker /// \file
18*03ce13f7SAndroid Build Coastguard Worker /// \brief Declares the Assembler base class.
19*03ce13f7SAndroid Build Coastguard Worker ///
20*03ce13f7SAndroid Build Coastguard Worker /// Instructions are assembled by architecture-specific assemblers that derive
21*03ce13f7SAndroid Build Coastguard Worker /// from this base class. This base class manages buffers and fixups for
22*03ce13f7SAndroid Build Coastguard Worker /// emitting code, etc.
23*03ce13f7SAndroid Build Coastguard Worker ///
24*03ce13f7SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
25*03ce13f7SAndroid Build Coastguard Worker 
26*03ce13f7SAndroid Build Coastguard Worker #ifndef SUBZERO_SRC_ICEASSEMBLER_H
27*03ce13f7SAndroid Build Coastguard Worker #define SUBZERO_SRC_ICEASSEMBLER_H
28*03ce13f7SAndroid Build Coastguard Worker 
29*03ce13f7SAndroid Build Coastguard Worker #include "IceDefs.h"
30*03ce13f7SAndroid Build Coastguard Worker #include "IceFixups.h"
31*03ce13f7SAndroid Build Coastguard Worker #include "IceStringPool.h"
32*03ce13f7SAndroid Build Coastguard Worker #include "IceUtils.h"
33*03ce13f7SAndroid Build Coastguard Worker 
34*03ce13f7SAndroid Build Coastguard Worker #include "llvm/Support/Allocator.h"
35*03ce13f7SAndroid Build Coastguard Worker 
36*03ce13f7SAndroid Build Coastguard Worker namespace Ice {
37*03ce13f7SAndroid Build Coastguard Worker 
38*03ce13f7SAndroid Build Coastguard Worker class Assembler;
39*03ce13f7SAndroid Build Coastguard Worker 
40*03ce13f7SAndroid Build Coastguard Worker /// A Label can be in one of three states:
41*03ce13f7SAndroid Build Coastguard Worker ///  - Unused.
42*03ce13f7SAndroid Build Coastguard Worker ///  - Linked, unplaced and tracking the position of branches to the label.
43*03ce13f7SAndroid Build Coastguard Worker ///  - Bound, placed and tracking its position.
44*03ce13f7SAndroid Build Coastguard Worker class Label {
45*03ce13f7SAndroid Build Coastguard Worker   Label(const Label &) = delete;
46*03ce13f7SAndroid Build Coastguard Worker   Label &operator=(const Label &) = delete;
47*03ce13f7SAndroid Build Coastguard Worker 
48*03ce13f7SAndroid Build Coastguard Worker public:
49*03ce13f7SAndroid Build Coastguard Worker   Label() = default;
50*03ce13f7SAndroid Build Coastguard Worker   virtual ~Label() = default;
51*03ce13f7SAndroid Build Coastguard Worker 
finalCheck()52*03ce13f7SAndroid Build Coastguard Worker   virtual void finalCheck() const {
53*03ce13f7SAndroid Build Coastguard Worker     // Assert if label is being destroyed with unresolved branches pending.
54*03ce13f7SAndroid Build Coastguard Worker     assert(!isLinked());
55*03ce13f7SAndroid Build Coastguard Worker   }
56*03ce13f7SAndroid Build Coastguard Worker 
57*03ce13f7SAndroid Build Coastguard Worker   /// Returns the encoded position stored in the label.
getEncodedPosition()58*03ce13f7SAndroid Build Coastguard Worker   intptr_t getEncodedPosition() const { return Position; }
59*03ce13f7SAndroid Build Coastguard Worker 
60*03ce13f7SAndroid Build Coastguard Worker   /// Returns the position for bound labels (branches that come after this are
61*03ce13f7SAndroid Build Coastguard Worker   /// considered backward branches). Cannot be used for unused or linked labels.
getPosition()62*03ce13f7SAndroid Build Coastguard Worker   intptr_t getPosition() const {
63*03ce13f7SAndroid Build Coastguard Worker     assert(isBound());
64*03ce13f7SAndroid Build Coastguard Worker     return -Position - kWordSize;
65*03ce13f7SAndroid Build Coastguard Worker   }
66*03ce13f7SAndroid Build Coastguard Worker 
67*03ce13f7SAndroid Build Coastguard Worker   /// Returns the position of an earlier branch instruction that was linked to
68*03ce13f7SAndroid Build Coastguard Worker   /// this label (branches that use this are considered forward branches). The
69*03ce13f7SAndroid Build Coastguard Worker   /// linked instructions form a linked list, of sorts, using the instruction's
70*03ce13f7SAndroid Build Coastguard Worker   /// displacement field for the location of the next instruction that is also
71*03ce13f7SAndroid Build Coastguard Worker   /// linked to this label.
getLinkPosition()72*03ce13f7SAndroid Build Coastguard Worker   intptr_t getLinkPosition() const {
73*03ce13f7SAndroid Build Coastguard Worker     assert(isLinked());
74*03ce13f7SAndroid Build Coastguard Worker     return Position - kWordSize;
75*03ce13f7SAndroid Build Coastguard Worker   }
76*03ce13f7SAndroid Build Coastguard Worker 
setPosition(intptr_t NewValue)77*03ce13f7SAndroid Build Coastguard Worker   void setPosition(intptr_t NewValue) { Position = NewValue; }
78*03ce13f7SAndroid Build Coastguard Worker 
isBound()79*03ce13f7SAndroid Build Coastguard Worker   bool isBound() const { return Position < 0; }
isLinked()80*03ce13f7SAndroid Build Coastguard Worker   bool isLinked() const { return Position > 0; }
81*03ce13f7SAndroid Build Coastguard Worker 
isUnused()82*03ce13f7SAndroid Build Coastguard Worker   virtual bool isUnused() const { return Position == 0; }
83*03ce13f7SAndroid Build Coastguard Worker 
bindTo(intptr_t position)84*03ce13f7SAndroid Build Coastguard Worker   void bindTo(intptr_t position) {
85*03ce13f7SAndroid Build Coastguard Worker     assert(!isBound());
86*03ce13f7SAndroid Build Coastguard Worker     Position = -position - kWordSize;
87*03ce13f7SAndroid Build Coastguard Worker     assert(isBound());
88*03ce13f7SAndroid Build Coastguard Worker   }
89*03ce13f7SAndroid Build Coastguard Worker 
90*03ce13f7SAndroid Build Coastguard Worker   void linkTo(const Assembler &Asm, intptr_t position);
91*03ce13f7SAndroid Build Coastguard Worker 
92*03ce13f7SAndroid Build Coastguard Worker protected:
93*03ce13f7SAndroid Build Coastguard Worker   intptr_t Position = 0;
94*03ce13f7SAndroid Build Coastguard Worker 
95*03ce13f7SAndroid Build Coastguard Worker   // TODO(jvoung): why are labels offset by this?
96*03ce13f7SAndroid Build Coastguard Worker   static constexpr uint32_t kWordSize = sizeof(uint32_t);
97*03ce13f7SAndroid Build Coastguard Worker };
98*03ce13f7SAndroid Build Coastguard Worker 
99*03ce13f7SAndroid Build Coastguard Worker /// Assembler buffers are used to emit binary code. They grow on demand.
100*03ce13f7SAndroid Build Coastguard Worker class AssemblerBuffer {
101*03ce13f7SAndroid Build Coastguard Worker   AssemblerBuffer(const AssemblerBuffer &) = delete;
102*03ce13f7SAndroid Build Coastguard Worker   AssemblerBuffer &operator=(const AssemblerBuffer &) = delete;
103*03ce13f7SAndroid Build Coastguard Worker 
104*03ce13f7SAndroid Build Coastguard Worker public:
105*03ce13f7SAndroid Build Coastguard Worker   AssemblerBuffer(Assembler &);
106*03ce13f7SAndroid Build Coastguard Worker   ~AssemblerBuffer();
107*03ce13f7SAndroid Build Coastguard Worker 
108*03ce13f7SAndroid Build Coastguard Worker   /// \name Basic support for emitting, loading, and storing.
109*03ce13f7SAndroid Build Coastguard Worker   /// @{
110*03ce13f7SAndroid Build Coastguard Worker   // These use memcpy instead of assignment to avoid undefined behaviour of
111*03ce13f7SAndroid Build Coastguard Worker   // assigning to unaligned addresses. Since the size of the copy is known the
112*03ce13f7SAndroid Build Coastguard Worker   // compiler can inline the memcpy with simple moves.
emit(T Value)113*03ce13f7SAndroid Build Coastguard Worker   template <typename T> void emit(T Value) {
114*03ce13f7SAndroid Build Coastguard Worker     assert(hasEnsuredCapacity());
115*03ce13f7SAndroid Build Coastguard Worker     memcpy(reinterpret_cast<void *>(Cursor), &Value, sizeof(T));
116*03ce13f7SAndroid Build Coastguard Worker     Cursor += sizeof(T);
117*03ce13f7SAndroid Build Coastguard Worker   }
118*03ce13f7SAndroid Build Coastguard Worker 
load(intptr_t Position)119*03ce13f7SAndroid Build Coastguard Worker   template <typename T> T load(intptr_t Position) const {
120*03ce13f7SAndroid Build Coastguard Worker     assert(Position >= 0 &&
121*03ce13f7SAndroid Build Coastguard Worker            Position <= (size() - static_cast<intptr_t>(sizeof(T))));
122*03ce13f7SAndroid Build Coastguard Worker     T Value;
123*03ce13f7SAndroid Build Coastguard Worker     memcpy(&Value, reinterpret_cast<void *>(Contents + Position), sizeof(T));
124*03ce13f7SAndroid Build Coastguard Worker     return Value;
125*03ce13f7SAndroid Build Coastguard Worker   }
126*03ce13f7SAndroid Build Coastguard Worker 
store(intptr_t Position,T Value)127*03ce13f7SAndroid Build Coastguard Worker   template <typename T> void store(intptr_t Position, T Value) {
128*03ce13f7SAndroid Build Coastguard Worker     assert(Position >= 0 &&
129*03ce13f7SAndroid Build Coastguard Worker            Position <= (size() - static_cast<intptr_t>(sizeof(T))));
130*03ce13f7SAndroid Build Coastguard Worker     memcpy(reinterpret_cast<void *>(Contents + Position), &Value, sizeof(T));
131*03ce13f7SAndroid Build Coastguard Worker   }
132*03ce13f7SAndroid Build Coastguard Worker   /// @{
133*03ce13f7SAndroid Build Coastguard Worker 
134*03ce13f7SAndroid Build Coastguard Worker   /// Emit a fixup at the current location.
emitFixup(AssemblerFixup * Fixup)135*03ce13f7SAndroid Build Coastguard Worker   void emitFixup(AssemblerFixup *Fixup) { Fixup->set_position(size()); }
136*03ce13f7SAndroid Build Coastguard Worker 
137*03ce13f7SAndroid Build Coastguard Worker   /// Get the size of the emitted code.
size()138*03ce13f7SAndroid Build Coastguard Worker   intptr_t size() const { return Cursor - Contents; }
contents()139*03ce13f7SAndroid Build Coastguard Worker   uintptr_t contents() const { return Contents; }
140*03ce13f7SAndroid Build Coastguard Worker 
141*03ce13f7SAndroid Build Coastguard Worker   /// To emit an instruction to the assembler buffer, the EnsureCapacity helper
142*03ce13f7SAndroid Build Coastguard Worker   /// must be used to guarantee that the underlying data area is big enough to
143*03ce13f7SAndroid Build Coastguard Worker   /// hold the emitted instruction. Usage:
144*03ce13f7SAndroid Build Coastguard Worker   ///
145*03ce13f7SAndroid Build Coastguard Worker   ///     AssemblerBuffer buffer;
146*03ce13f7SAndroid Build Coastguard Worker   ///     AssemblerBuffer::EnsureCapacity ensured(&buffer);
147*03ce13f7SAndroid Build Coastguard Worker   ///     ... emit bytes for single instruction ...
148*03ce13f7SAndroid Build Coastguard Worker   class EnsureCapacity {
149*03ce13f7SAndroid Build Coastguard Worker     EnsureCapacity(const EnsureCapacity &) = delete;
150*03ce13f7SAndroid Build Coastguard Worker     EnsureCapacity &operator=(const EnsureCapacity &) = delete;
151*03ce13f7SAndroid Build Coastguard Worker 
152*03ce13f7SAndroid Build Coastguard Worker   public:
EnsureCapacity(AssemblerBuffer * Buffer)153*03ce13f7SAndroid Build Coastguard Worker     explicit EnsureCapacity(AssemblerBuffer *Buffer) : Buffer(Buffer) {
154*03ce13f7SAndroid Build Coastguard Worker       if (Buffer->cursor() >= Buffer->limit())
155*03ce13f7SAndroid Build Coastguard Worker         Buffer->extendCapacity();
156*03ce13f7SAndroid Build Coastguard Worker       if (BuildDefs::asserts())
157*03ce13f7SAndroid Build Coastguard Worker         validate(Buffer);
158*03ce13f7SAndroid Build Coastguard Worker     }
159*03ce13f7SAndroid Build Coastguard Worker     ~EnsureCapacity();
160*03ce13f7SAndroid Build Coastguard Worker 
161*03ce13f7SAndroid Build Coastguard Worker   private:
162*03ce13f7SAndroid Build Coastguard Worker     AssemblerBuffer *Buffer;
163*03ce13f7SAndroid Build Coastguard Worker     intptr_t Gap = 0;
164*03ce13f7SAndroid Build Coastguard Worker 
165*03ce13f7SAndroid Build Coastguard Worker     void validate(AssemblerBuffer *Buffer);
computeGap()166*03ce13f7SAndroid Build Coastguard Worker     intptr_t computeGap() { return Buffer->capacity() - Buffer->size(); }
167*03ce13f7SAndroid Build Coastguard Worker   };
168*03ce13f7SAndroid Build Coastguard Worker 
169*03ce13f7SAndroid Build Coastguard Worker   bool HasEnsuredCapacity;
hasEnsuredCapacity()170*03ce13f7SAndroid Build Coastguard Worker   bool hasEnsuredCapacity() const {
171*03ce13f7SAndroid Build Coastguard Worker     if (BuildDefs::asserts())
172*03ce13f7SAndroid Build Coastguard Worker       return HasEnsuredCapacity;
173*03ce13f7SAndroid Build Coastguard Worker     // Disable the actual check in non-debug mode.
174*03ce13f7SAndroid Build Coastguard Worker     return true;
175*03ce13f7SAndroid Build Coastguard Worker   }
176*03ce13f7SAndroid Build Coastguard Worker 
177*03ce13f7SAndroid Build Coastguard Worker   /// Returns the position in the instruction stream.
getPosition()178*03ce13f7SAndroid Build Coastguard Worker   intptr_t getPosition() const { return Cursor - Contents; }
179*03ce13f7SAndroid Build Coastguard Worker 
180*03ce13f7SAndroid Build Coastguard Worker   /// Create and track a fixup in the current function.
181*03ce13f7SAndroid Build Coastguard Worker   AssemblerFixup *createFixup(FixupKind Kind, const Constant *Value);
182*03ce13f7SAndroid Build Coastguard Worker 
183*03ce13f7SAndroid Build Coastguard Worker   /// Create and track a textual fixup in the current function.
184*03ce13f7SAndroid Build Coastguard Worker   AssemblerTextFixup *createTextFixup(const std::string &Text,
185*03ce13f7SAndroid Build Coastguard Worker                                       size_t BytesUsed);
186*03ce13f7SAndroid Build Coastguard Worker 
187*03ce13f7SAndroid Build Coastguard Worker   /// Mark that an attempt was made to emit, but failed. Hence, in order to
188*03ce13f7SAndroid Build Coastguard Worker   /// continue, one must emit a text fixup.
setNeedsTextFixup()189*03ce13f7SAndroid Build Coastguard Worker   void setNeedsTextFixup() { TextFixupNeeded = true; }
resetNeedsTextFixup()190*03ce13f7SAndroid Build Coastguard Worker   void resetNeedsTextFixup() { TextFixupNeeded = false; }
191*03ce13f7SAndroid Build Coastguard Worker 
192*03ce13f7SAndroid Build Coastguard Worker   /// Returns true if last emit failed and needs a text fixup.
needsTextFixup()193*03ce13f7SAndroid Build Coastguard Worker   bool needsTextFixup() const { return TextFixupNeeded; }
194*03ce13f7SAndroid Build Coastguard Worker 
195*03ce13f7SAndroid Build Coastguard Worker   /// Installs a created fixup, after it has been allocated.
196*03ce13f7SAndroid Build Coastguard Worker   void installFixup(AssemblerFixup *F);
197*03ce13f7SAndroid Build Coastguard Worker 
fixups()198*03ce13f7SAndroid Build Coastguard Worker   const FixupRefList &fixups() const { return Fixups; }
199*03ce13f7SAndroid Build Coastguard Worker 
setSize(intptr_t NewSize)200*03ce13f7SAndroid Build Coastguard Worker   void setSize(intptr_t NewSize) {
201*03ce13f7SAndroid Build Coastguard Worker     assert(NewSize <= size());
202*03ce13f7SAndroid Build Coastguard Worker     Cursor = Contents + NewSize;
203*03ce13f7SAndroid Build Coastguard Worker   }
204*03ce13f7SAndroid Build Coastguard Worker 
205*03ce13f7SAndroid Build Coastguard Worker private:
206*03ce13f7SAndroid Build Coastguard Worker   /// The limit is set to kMinimumGap bytes before the end of the data area.
207*03ce13f7SAndroid Build Coastguard Worker   /// This leaves enough space for the longest possible instruction and allows
208*03ce13f7SAndroid Build Coastguard Worker   /// for a single, fast space check per instruction.
209*03ce13f7SAndroid Build Coastguard Worker   static constexpr intptr_t kMinimumGap = 32;
210*03ce13f7SAndroid Build Coastguard Worker 
211*03ce13f7SAndroid Build Coastguard Worker   uintptr_t Contents;
212*03ce13f7SAndroid Build Coastguard Worker   uintptr_t Cursor;
213*03ce13f7SAndroid Build Coastguard Worker   uintptr_t Limit;
214*03ce13f7SAndroid Build Coastguard Worker   // The member variable is named Assemblr to avoid hiding the class Assembler.
215*03ce13f7SAndroid Build Coastguard Worker   Assembler &Assemblr;
216*03ce13f7SAndroid Build Coastguard Worker   /// List of pool-allocated fixups relative to the current function.
217*03ce13f7SAndroid Build Coastguard Worker   FixupRefList Fixups;
218*03ce13f7SAndroid Build Coastguard Worker   // True if a textual fixup is needed, because the assembler was unable to
219*03ce13f7SAndroid Build Coastguard Worker   // emit the last request.
220*03ce13f7SAndroid Build Coastguard Worker   bool TextFixupNeeded;
221*03ce13f7SAndroid Build Coastguard Worker 
cursor()222*03ce13f7SAndroid Build Coastguard Worker   uintptr_t cursor() const { return Cursor; }
limit()223*03ce13f7SAndroid Build Coastguard Worker   uintptr_t limit() const { return Limit; }
capacity()224*03ce13f7SAndroid Build Coastguard Worker   intptr_t capacity() const {
225*03ce13f7SAndroid Build Coastguard Worker     assert(Limit >= Contents);
226*03ce13f7SAndroid Build Coastguard Worker     return (Limit - Contents) + kMinimumGap;
227*03ce13f7SAndroid Build Coastguard Worker   }
228*03ce13f7SAndroid Build Coastguard Worker 
229*03ce13f7SAndroid Build Coastguard Worker   /// Compute the limit based on the data area and the capacity. See description
230*03ce13f7SAndroid Build Coastguard Worker   /// of kMinimumGap for the reasoning behind the value.
computeLimit(uintptr_t Data,intptr_t Capacity)231*03ce13f7SAndroid Build Coastguard Worker   static uintptr_t computeLimit(uintptr_t Data, intptr_t Capacity) {
232*03ce13f7SAndroid Build Coastguard Worker     return Data + Capacity - kMinimumGap;
233*03ce13f7SAndroid Build Coastguard Worker   }
234*03ce13f7SAndroid Build Coastguard Worker 
235*03ce13f7SAndroid Build Coastguard Worker   void extendCapacity();
236*03ce13f7SAndroid Build Coastguard Worker };
237*03ce13f7SAndroid Build Coastguard Worker 
238*03ce13f7SAndroid Build Coastguard Worker class Assembler {
239*03ce13f7SAndroid Build Coastguard Worker   Assembler() = delete;
240*03ce13f7SAndroid Build Coastguard Worker   Assembler(const Assembler &) = delete;
241*03ce13f7SAndroid Build Coastguard Worker   Assembler &operator=(const Assembler &) = delete;
242*03ce13f7SAndroid Build Coastguard Worker 
243*03ce13f7SAndroid Build Coastguard Worker public:
244*03ce13f7SAndroid Build Coastguard Worker   enum AssemblerKind {
245*03ce13f7SAndroid Build Coastguard Worker     Asm_ARM32,
246*03ce13f7SAndroid Build Coastguard Worker     Asm_MIPS32,
247*03ce13f7SAndroid Build Coastguard Worker     Asm_X8632,
248*03ce13f7SAndroid Build Coastguard Worker     Asm_X8664,
249*03ce13f7SAndroid Build Coastguard Worker   };
250*03ce13f7SAndroid Build Coastguard Worker 
251*03ce13f7SAndroid Build Coastguard Worker   virtual ~Assembler() = default;
252*03ce13f7SAndroid Build Coastguard Worker 
253*03ce13f7SAndroid Build Coastguard Worker   /// Allocate a chunk of bytes using the per-Assembler allocator.
allocateBytes(size_t bytes)254*03ce13f7SAndroid Build Coastguard Worker   uintptr_t allocateBytes(size_t bytes) {
255*03ce13f7SAndroid Build Coastguard Worker     // For now, alignment is not related to NaCl bundle alignment, since the
256*03ce13f7SAndroid Build Coastguard Worker     // buffer's GetPosition is relative to the base. So NaCl bundle alignment
257*03ce13f7SAndroid Build Coastguard Worker     // checks can be relative to that base. Later, the buffer will be copied
258*03ce13f7SAndroid Build Coastguard Worker     // out to a ".text" section (or an in memory-buffer that can be mprotect'ed
259*03ce13f7SAndroid Build Coastguard Worker     // with executable permission), and that second buffer should be aligned
260*03ce13f7SAndroid Build Coastguard Worker     // for NaCl.
261*03ce13f7SAndroid Build Coastguard Worker     const size_t Alignment = 16;
262*03ce13f7SAndroid Build Coastguard Worker     return reinterpret_cast<uintptr_t>(Allocator.Allocate(bytes, Alignment));
263*03ce13f7SAndroid Build Coastguard Worker   }
264*03ce13f7SAndroid Build Coastguard Worker 
265*03ce13f7SAndroid Build Coastguard Worker   /// Allocate data of type T using the per-Assembler allocator.
allocate()266*03ce13f7SAndroid Build Coastguard Worker   template <typename T> T *allocate() { return Allocator.Allocate<T>(); }
267*03ce13f7SAndroid Build Coastguard Worker 
268*03ce13f7SAndroid Build Coastguard Worker   /// Align the tail end of the function to the required target alignment.
269*03ce13f7SAndroid Build Coastguard Worker   virtual void alignFunction() = 0;
270*03ce13f7SAndroid Build Coastguard Worker   /// Align the tail end of the basic block to the required target alignment.
alignCfgNode()271*03ce13f7SAndroid Build Coastguard Worker   void alignCfgNode() {
272*03ce13f7SAndroid Build Coastguard Worker     const SizeT Align = 1 << getBundleAlignLog2Bytes();
273*03ce13f7SAndroid Build Coastguard Worker     padWithNop(Utils::OffsetToAlignment(Buffer.getPosition(), Align));
274*03ce13f7SAndroid Build Coastguard Worker   }
275*03ce13f7SAndroid Build Coastguard Worker 
276*03ce13f7SAndroid Build Coastguard Worker   /// Add nop padding of a particular width to the current bundle.
277*03ce13f7SAndroid Build Coastguard Worker   virtual void padWithNop(intptr_t Padding) = 0;
278*03ce13f7SAndroid Build Coastguard Worker 
279*03ce13f7SAndroid Build Coastguard Worker   virtual SizeT getBundleAlignLog2Bytes() const = 0;
280*03ce13f7SAndroid Build Coastguard Worker 
281*03ce13f7SAndroid Build Coastguard Worker   virtual const char *getAlignDirective() const = 0;
282*03ce13f7SAndroid Build Coastguard Worker   virtual llvm::ArrayRef<uint8_t> getNonExecBundlePadding() const = 0;
283*03ce13f7SAndroid Build Coastguard Worker 
284*03ce13f7SAndroid Build Coastguard Worker   /// Get the label for a CfgNode.
285*03ce13f7SAndroid Build Coastguard Worker   virtual Label *getCfgNodeLabel(SizeT NodeNumber) = 0;
286*03ce13f7SAndroid Build Coastguard Worker   /// Mark the current text location as the start of a CFG node.
287*03ce13f7SAndroid Build Coastguard Worker   virtual void bindCfgNodeLabel(const CfgNode *Node) = 0;
288*03ce13f7SAndroid Build Coastguard Worker 
289*03ce13f7SAndroid Build Coastguard Worker   virtual bool fixupIsPCRel(FixupKind Kind) const = 0;
290*03ce13f7SAndroid Build Coastguard Worker 
291*03ce13f7SAndroid Build Coastguard Worker   /// Return a view of all the bytes of code for the current function.
292*03ce13f7SAndroid Build Coastguard Worker   llvm::StringRef getBufferView() const;
293*03ce13f7SAndroid Build Coastguard Worker 
294*03ce13f7SAndroid Build Coastguard Worker   /// Return the value of the given type in the corresponding buffer.
load(intptr_t Position)295*03ce13f7SAndroid Build Coastguard Worker   template <typename T> T load(intptr_t Position) const {
296*03ce13f7SAndroid Build Coastguard Worker     return Buffer.load<T>(Position);
297*03ce13f7SAndroid Build Coastguard Worker   }
298*03ce13f7SAndroid Build Coastguard Worker 
store(intptr_t Position,T Value)299*03ce13f7SAndroid Build Coastguard Worker   template <typename T> void store(intptr_t Position, T Value) {
300*03ce13f7SAndroid Build Coastguard Worker     Buffer.store(Position, Value);
301*03ce13f7SAndroid Build Coastguard Worker   }
302*03ce13f7SAndroid Build Coastguard Worker 
303*03ce13f7SAndroid Build Coastguard Worker   /// Emit a fixup at the current location.
emitFixup(AssemblerFixup * Fixup)304*03ce13f7SAndroid Build Coastguard Worker   void emitFixup(AssemblerFixup *Fixup) { Buffer.emitFixup(Fixup); }
305*03ce13f7SAndroid Build Coastguard Worker 
fixups()306*03ce13f7SAndroid Build Coastguard Worker   const FixupRefList &fixups() const { return Buffer.fixups(); }
307*03ce13f7SAndroid Build Coastguard Worker 
createFixup(FixupKind Kind,const Constant * Value)308*03ce13f7SAndroid Build Coastguard Worker   AssemblerFixup *createFixup(FixupKind Kind, const Constant *Value) {
309*03ce13f7SAndroid Build Coastguard Worker     return Buffer.createFixup(Kind, Value);
310*03ce13f7SAndroid Build Coastguard Worker   }
311*03ce13f7SAndroid Build Coastguard Worker 
createTextFixup(const std::string & Text,size_t BytesUsed)312*03ce13f7SAndroid Build Coastguard Worker   AssemblerTextFixup *createTextFixup(const std::string &Text,
313*03ce13f7SAndroid Build Coastguard Worker                                       size_t BytesUsed) {
314*03ce13f7SAndroid Build Coastguard Worker     return Buffer.createTextFixup(Text, BytesUsed);
315*03ce13f7SAndroid Build Coastguard Worker   }
316*03ce13f7SAndroid Build Coastguard Worker 
317*03ce13f7SAndroid Build Coastguard Worker   void bindRelocOffset(RelocOffset *Offset);
318*03ce13f7SAndroid Build Coastguard Worker 
setNeedsTextFixup()319*03ce13f7SAndroid Build Coastguard Worker   void setNeedsTextFixup() { Buffer.setNeedsTextFixup(); }
resetNeedsTextFixup()320*03ce13f7SAndroid Build Coastguard Worker   void resetNeedsTextFixup() { Buffer.resetNeedsTextFixup(); }
321*03ce13f7SAndroid Build Coastguard Worker 
needsTextFixup()322*03ce13f7SAndroid Build Coastguard Worker   bool needsTextFixup() const { return Buffer.needsTextFixup(); }
323*03ce13f7SAndroid Build Coastguard Worker 
324*03ce13f7SAndroid Build Coastguard Worker   void emitIASBytes(GlobalContext *Ctx) const;
getInternal()325*03ce13f7SAndroid Build Coastguard Worker   bool getInternal() const { return IsInternal; }
setInternal(bool Internal)326*03ce13f7SAndroid Build Coastguard Worker   void setInternal(bool Internal) { IsInternal = Internal; }
getFunctionName()327*03ce13f7SAndroid Build Coastguard Worker   GlobalString getFunctionName() const { return FunctionName; }
setFunctionName(GlobalString NewName)328*03ce13f7SAndroid Build Coastguard Worker   void setFunctionName(GlobalString NewName) { FunctionName = NewName; }
getBufferSize()329*03ce13f7SAndroid Build Coastguard Worker   intptr_t getBufferSize() const { return Buffer.size(); }
330*03ce13f7SAndroid Build Coastguard Worker   /// Roll back to a (smaller) size.
setBufferSize(intptr_t NewSize)331*03ce13f7SAndroid Build Coastguard Worker   void setBufferSize(intptr_t NewSize) { Buffer.setSize(NewSize); }
setPreliminary(bool Value)332*03ce13f7SAndroid Build Coastguard Worker   void setPreliminary(bool Value) { Preliminary = Value; }
getPreliminary()333*03ce13f7SAndroid Build Coastguard Worker   bool getPreliminary() const { return Preliminary; }
334*03ce13f7SAndroid Build Coastguard Worker 
getKind()335*03ce13f7SAndroid Build Coastguard Worker   AssemblerKind getKind() const { return Kind; }
336*03ce13f7SAndroid Build Coastguard Worker 
337*03ce13f7SAndroid Build Coastguard Worker protected:
Assembler(AssemblerKind Kind)338*03ce13f7SAndroid Build Coastguard Worker   explicit Assembler(AssemblerKind Kind)
339*03ce13f7SAndroid Build Coastguard Worker       : Kind(Kind), Allocator(), Buffer(*this) {}
340*03ce13f7SAndroid Build Coastguard Worker 
341*03ce13f7SAndroid Build Coastguard Worker private:
342*03ce13f7SAndroid Build Coastguard Worker   const AssemblerKind Kind;
343*03ce13f7SAndroid Build Coastguard Worker 
344*03ce13f7SAndroid Build Coastguard Worker   using AssemblerAllocator =
345*03ce13f7SAndroid Build Coastguard Worker       llvm::BumpPtrAllocatorImpl<llvm::MallocAllocator, /*SlabSize=*/32 * 1024>;
346*03ce13f7SAndroid Build Coastguard Worker   AssemblerAllocator Allocator;
347*03ce13f7SAndroid Build Coastguard Worker 
348*03ce13f7SAndroid Build Coastguard Worker   /// FunctionName and IsInternal are transferred from the original Cfg object,
349*03ce13f7SAndroid Build Coastguard Worker   /// since the Cfg object may be deleted by the time the assembler buffer is
350*03ce13f7SAndroid Build Coastguard Worker   /// emitted.
351*03ce13f7SAndroid Build Coastguard Worker   GlobalString FunctionName;
352*03ce13f7SAndroid Build Coastguard Worker   bool IsInternal = false;
353*03ce13f7SAndroid Build Coastguard Worker   /// Preliminary indicates whether a preliminary pass is being made for
354*03ce13f7SAndroid Build Coastguard Worker   /// calculating bundle padding (Preliminary=true), versus the final pass where
355*03ce13f7SAndroid Build Coastguard Worker   /// all changes to label bindings, label links, and relocation fixups are
356*03ce13f7SAndroid Build Coastguard Worker   /// fully committed (Preliminary=false).
357*03ce13f7SAndroid Build Coastguard Worker   bool Preliminary = false;
358*03ce13f7SAndroid Build Coastguard Worker 
359*03ce13f7SAndroid Build Coastguard Worker   /// Installs a created fixup, after it has been allocated.
installFixup(AssemblerFixup * F)360*03ce13f7SAndroid Build Coastguard Worker   void installFixup(AssemblerFixup *F) { Buffer.installFixup(F); }
361*03ce13f7SAndroid Build Coastguard Worker 
362*03ce13f7SAndroid Build Coastguard Worker protected:
363*03ce13f7SAndroid Build Coastguard Worker   // Buffer's constructor uses the Allocator, so it needs to appear after it.
364*03ce13f7SAndroid Build Coastguard Worker   // TODO(jpp): dependencies on construction order are a nice way of shooting
365*03ce13f7SAndroid Build Coastguard Worker   // yourself in the foot. Fix this.
366*03ce13f7SAndroid Build Coastguard Worker   AssemblerBuffer Buffer;
367*03ce13f7SAndroid Build Coastguard Worker };
368*03ce13f7SAndroid Build Coastguard Worker 
369*03ce13f7SAndroid Build Coastguard Worker } // end of namespace Ice
370*03ce13f7SAndroid Build Coastguard Worker 
371*03ce13f7SAndroid Build Coastguard Worker #endif // SUBZERO_SRC_ICEASSEMBLER_H_
372