1aff4ccf9a77b664127f2fd5bc0b98243008be067John Porto//===- subzero/src/IceAssembler.h - Integrated assembler --------*- C++ -*-===//
28acded039857a42b170c1cbc0ad4d1345419de3cJan Voung// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
38acded039857a42b170c1cbc0ad4d1345419de3cJan Voung// for details. All rights reserved. Use of this source code is governed by a
48acded039857a42b170c1cbc0ad4d1345419de3cJan Voung// BSD-style license that can be found in the LICENSE file.
58acded039857a42b170c1cbc0ad4d1345419de3cJan Voung//
68acded039857a42b170c1cbc0ad4d1345419de3cJan Voung// Modified by the Subzero authors.
78acded039857a42b170c1cbc0ad4d1345419de3cJan Voung//
8f76fd3774379179427a228c29d38cc3ca1d904c1Jan Voung//===----------------------------------------------------------------------===//
98acded039857a42b170c1cbc0ad4d1345419de3cJan Voung//
108acded039857a42b170c1cbc0ad4d1345419de3cJan Voung//                        The Subzero Code Generator
118acded039857a42b170c1cbc0ad4d1345419de3cJan Voung//
128acded039857a42b170c1cbc0ad4d1345419de3cJan Voung// This file is distributed under the University of Illinois Open Source
138acded039857a42b170c1cbc0ad4d1345419de3cJan Voung// License. See LICENSE.TXT for details.
148acded039857a42b170c1cbc0ad4d1345419de3cJan Voung//
158acded039857a42b170c1cbc0ad4d1345419de3cJan Voung//===----------------------------------------------------------------------===//
169612d32c7e5eb2cb403686ef31172d42e075e460Andrew Scull///
179612d32c7e5eb2cb403686ef31172d42e075e460Andrew Scull/// \file
1892a6e5b08ec68e7076d637ebc680da2fcc346a00Jim Stichnoth/// \brief Declares the Assembler base class.
1992a6e5b08ec68e7076d637ebc680da2fcc346a00Jim Stichnoth///
2092a6e5b08ec68e7076d637ebc680da2fcc346a00Jim Stichnoth/// Instructions are assembled by architecture-specific assemblers that derive
2192a6e5b08ec68e7076d637ebc680da2fcc346a00Jim Stichnoth/// from this base class. This base class manages buffers and fixups for
2292a6e5b08ec68e7076d637ebc680da2fcc346a00Jim Stichnoth/// emitting code, etc.
239612d32c7e5eb2cb403686ef31172d42e075e460Andrew Scull///
248acded039857a42b170c1cbc0ad4d1345419de3cJan Voung//===----------------------------------------------------------------------===//
258acded039857a42b170c1cbc0ad4d1345419de3cJan Voung
26aff4ccf9a77b664127f2fd5bc0b98243008be067John Porto#ifndef SUBZERO_SRC_ICEASSEMBLER_H
27aff4ccf9a77b664127f2fd5bc0b98243008be067John Porto#define SUBZERO_SRC_ICEASSEMBLER_H
288acded039857a42b170c1cbc0ad4d1345419de3cJan Voung
298acded039857a42b170c1cbc0ad4d1345419de3cJan Voung#include "IceDefs.h"
308acded039857a42b170c1cbc0ad4d1345419de3cJan Voung#include "IceFixups.h"
31467ffe51bebcb3ae3e3ce745c38fc20e8837c31cJim Stichnoth#include "IceStringPool.h"
3286df4e9e6d183f07638440afd2c225b485c03917Andrew Scull#include "IceUtils.h"
338acded039857a42b170c1cbc0ad4d1345419de3cJan Voung
34e82b560e649f8a68bcb252b9b002708e74d962d3John Porto#include "llvm/Support/Allocator.h"
35e82b560e649f8a68bcb252b9b002708e74d962d3John Porto
368acded039857a42b170c1cbc0ad4d1345419de3cJan Voungnamespace Ice {
378acded039857a42b170c1cbc0ad4d1345419de3cJan Voung
3867574d83d05f5bde748843a73adcab6247736601Karl Schimpfclass Assembler;
3967574d83d05f5bde748843a73adcab6247736601Karl Schimpf
4086df4e9e6d183f07638440afd2c225b485c03917Andrew Scull/// A Label can be in one of three states:
4186df4e9e6d183f07638440afd2c225b485c03917Andrew Scull///  - Unused.
4286df4e9e6d183f07638440afd2c225b485c03917Andrew Scull///  - Linked, unplaced and tracking the position of branches to the label.
4386df4e9e6d183f07638440afd2c225b485c03917Andrew Scull///  - Bound, placed and tracking its position.
4486df4e9e6d183f07638440afd2c225b485c03917Andrew Scullclass Label {
4586df4e9e6d183f07638440afd2c225b485c03917Andrew Scull  Label(const Label &) = delete;
4686df4e9e6d183f07638440afd2c225b485c03917Andrew Scull  Label &operator=(const Label &) = delete;
4786df4e9e6d183f07638440afd2c225b485c03917Andrew Scull
4886df4e9e6d183f07638440afd2c225b485c03917Andrew Scullpublic:
4986df4e9e6d183f07638440afd2c225b485c03917Andrew Scull  Label() = default;
50fc707ffe812339bddf4ca28fbe8c01045e2b42d6Sean Klein  virtual ~Label() = default;
5186df4e9e6d183f07638440afd2c225b485c03917Andrew Scull
5286df4e9e6d183f07638440afd2c225b485c03917Andrew Scull  virtual void finalCheck() const {
5386df4e9e6d183f07638440afd2c225b485c03917Andrew Scull    // Assert if label is being destroyed with unresolved branches pending.
5486df4e9e6d183f07638440afd2c225b485c03917Andrew Scull    assert(!isLinked());
5586df4e9e6d183f07638440afd2c225b485c03917Andrew Scull  }
5686df4e9e6d183f07638440afd2c225b485c03917Andrew Scull
57137e62bd843313d4b8697621989e0e6f5c2e7f81Karl Schimpf  /// Returns the encoded position stored in the label.
58137e62bd843313d4b8697621989e0e6f5c2e7f81Karl Schimpf  intptr_t getEncodedPosition() const { return Position; }
59137e62bd843313d4b8697621989e0e6f5c2e7f81Karl Schimpf
6086df4e9e6d183f07638440afd2c225b485c03917Andrew Scull  /// Returns the position for bound labels (branches that come after this are
6186df4e9e6d183f07638440afd2c225b485c03917Andrew Scull  /// considered backward branches). Cannot be used for unused or linked labels.
6286df4e9e6d183f07638440afd2c225b485c03917Andrew Scull  intptr_t getPosition() const {
6386df4e9e6d183f07638440afd2c225b485c03917Andrew Scull    assert(isBound());
6486df4e9e6d183f07638440afd2c225b485c03917Andrew Scull    return -Position - kWordSize;
6586df4e9e6d183f07638440afd2c225b485c03917Andrew Scull  }
6686df4e9e6d183f07638440afd2c225b485c03917Andrew Scull
6786df4e9e6d183f07638440afd2c225b485c03917Andrew Scull  /// Returns the position of an earlier branch instruction that was linked to
6857e126899b20c65ff3ea23a3b7d7a67ab30b99dcAndrew Scull  /// this label (branches that use this are considered forward branches). The
6986df4e9e6d183f07638440afd2c225b485c03917Andrew Scull  /// linked instructions form a linked list, of sorts, using the instruction's
7086df4e9e6d183f07638440afd2c225b485c03917Andrew Scull  /// displacement field for the location of the next instruction that is also
7186df4e9e6d183f07638440afd2c225b485c03917Andrew Scull  /// linked to this label.
7286df4e9e6d183f07638440afd2c225b485c03917Andrew Scull  intptr_t getLinkPosition() const {
7386df4e9e6d183f07638440afd2c225b485c03917Andrew Scull    assert(isLinked());
7486df4e9e6d183f07638440afd2c225b485c03917Andrew Scull    return Position - kWordSize;
7586df4e9e6d183f07638440afd2c225b485c03917Andrew Scull  }
7686df4e9e6d183f07638440afd2c225b485c03917Andrew Scull
77c5abdc1301260c79f60d60ec1117e8044312da30Karl Schimpf  void setPosition(intptr_t NewValue) { Position = NewValue; }
78c5abdc1301260c79f60d60ec1117e8044312da30Karl Schimpf
7986df4e9e6d183f07638440afd2c225b485c03917Andrew Scull  bool isBound() const { return Position < 0; }
8086df4e9e6d183f07638440afd2c225b485c03917Andrew Scull  bool isLinked() const { return Position > 0; }
81c5abdc1301260c79f60d60ec1117e8044312da30Karl Schimpf
8286df4e9e6d183f07638440afd2c225b485c03917Andrew Scull  virtual bool isUnused() const { return Position == 0; }
8386df4e9e6d183f07638440afd2c225b485c03917Andrew Scull
8486df4e9e6d183f07638440afd2c225b485c03917Andrew Scull  void bindTo(intptr_t position) {
8586df4e9e6d183f07638440afd2c225b485c03917Andrew Scull    assert(!isBound());
8686df4e9e6d183f07638440afd2c225b485c03917Andrew Scull    Position = -position - kWordSize;
8786df4e9e6d183f07638440afd2c225b485c03917Andrew Scull    assert(isBound());
8886df4e9e6d183f07638440afd2c225b485c03917Andrew Scull  }
8986df4e9e6d183f07638440afd2c225b485c03917Andrew Scull
9067574d83d05f5bde748843a73adcab6247736601Karl Schimpf  void linkTo(const Assembler &Asm, intptr_t position);
9186df4e9e6d183f07638440afd2c225b485c03917Andrew Scull
92137e62bd843313d4b8697621989e0e6f5c2e7f81Karl Schimpfprotected:
9386df4e9e6d183f07638440afd2c225b485c03917Andrew Scull  intptr_t Position = 0;
9486df4e9e6d183f07638440afd2c225b485c03917Andrew Scull
9586df4e9e6d183f07638440afd2c225b485c03917Andrew Scull  // TODO(jvoung): why are labels offset by this?
9686df4e9e6d183f07638440afd2c225b485c03917Andrew Scull  static constexpr uint32_t kWordSize = sizeof(uint32_t);
9786df4e9e6d183f07638440afd2c225b485c03917Andrew Scull};
9886df4e9e6d183f07638440afd2c225b485c03917Andrew Scull
999612d32c7e5eb2cb403686ef31172d42e075e460Andrew Scull/// Assembler buffers are used to emit binary code. They grow on demand.
1008acded039857a42b170c1cbc0ad4d1345419de3cJan Voungclass AssemblerBuffer {
101f76fd3774379179427a228c29d38cc3ca1d904c1Jan Voung  AssemblerBuffer(const AssemblerBuffer &) = delete;
102f76fd3774379179427a228c29d38cc3ca1d904c1Jan Voung  AssemblerBuffer &operator=(const AssemblerBuffer &) = delete;
103f76fd3774379179427a228c29d38cc3ca1d904c1Jan Voung
1048acded039857a42b170c1cbc0ad4d1345419de3cJan Voungpublic:
1058acded039857a42b170c1cbc0ad4d1345419de3cJan Voung  AssemblerBuffer(Assembler &);
1068acded039857a42b170c1cbc0ad4d1345419de3cJan Voung  ~AssemblerBuffer();
1078acded039857a42b170c1cbc0ad4d1345419de3cJan Voung
1086ef7949448bbe3fdb1a0cf3dcbd32fd46c4baf9dAndrew Scull  /// \name Basic support for emitting, loading, and storing.
1096ef7949448bbe3fdb1a0cf3dcbd32fd46c4baf9dAndrew Scull  /// @{
1106ef7949448bbe3fdb1a0cf3dcbd32fd46c4baf9dAndrew Scull  // These use memcpy instead of assignment to avoid undefined behaviour of
1116ef7949448bbe3fdb1a0cf3dcbd32fd46c4baf9dAndrew Scull  // assigning to unaligned addresses. Since the size of the copy is known the
1126ef7949448bbe3fdb1a0cf3dcbd32fd46c4baf9dAndrew Scull  // compiler can inline the memcpy with simple moves.
113aff4ccf9a77b664127f2fd5bc0b98243008be067John Porto  template <typename T> void emit(T Value) {
114aff4ccf9a77b664127f2fd5bc0b98243008be067John Porto    assert(hasEnsuredCapacity());
1156ef7949448bbe3fdb1a0cf3dcbd32fd46c4baf9dAndrew Scull    memcpy(reinterpret_cast<void *>(Cursor), &Value, sizeof(T));
116aff4ccf9a77b664127f2fd5bc0b98243008be067John Porto    Cursor += sizeof(T);
1178acded039857a42b170c1cbc0ad4d1345419de3cJan Voung  }
1188acded039857a42b170c1cbc0ad4d1345419de3cJan Voung
119aff4ccf9a77b664127f2fd5bc0b98243008be067John Porto  template <typename T> T load(intptr_t Position) const {
120aff4ccf9a77b664127f2fd5bc0b98243008be067John Porto    assert(Position >= 0 &&
121aff4ccf9a77b664127f2fd5bc0b98243008be067John Porto           Position <= (size() - static_cast<intptr_t>(sizeof(T))));
1226ef7949448bbe3fdb1a0cf3dcbd32fd46c4baf9dAndrew Scull    T Value;
1236ef7949448bbe3fdb1a0cf3dcbd32fd46c4baf9dAndrew Scull    memcpy(&Value, reinterpret_cast<void *>(Contents + Position), sizeof(T));
1246ef7949448bbe3fdb1a0cf3dcbd32fd46c4baf9dAndrew Scull    return Value;
1258acded039857a42b170c1cbc0ad4d1345419de3cJan Voung  }
1268acded039857a42b170c1cbc0ad4d1345419de3cJan Voung
127aff4ccf9a77b664127f2fd5bc0b98243008be067John Porto  template <typename T> void store(intptr_t Position, T Value) {
128aff4ccf9a77b664127f2fd5bc0b98243008be067John Porto    assert(Position >= 0 &&
129aff4ccf9a77b664127f2fd5bc0b98243008be067John Porto           Position <= (size() - static_cast<intptr_t>(sizeof(T))));
1306ef7949448bbe3fdb1a0cf3dcbd32fd46c4baf9dAndrew Scull    memcpy(reinterpret_cast<void *>(Contents + Position), &Value, sizeof(T));
1318acded039857a42b170c1cbc0ad4d1345419de3cJan Voung  }
1326ef7949448bbe3fdb1a0cf3dcbd32fd46c4baf9dAndrew Scull  /// @{
1338acded039857a42b170c1cbc0ad4d1345419de3cJan Voung
1349612d32c7e5eb2cb403686ef31172d42e075e460Andrew Scull  /// Emit a fixup at the current location.
135aff4ccf9a77b664127f2fd5bc0b98243008be067John Porto  void emitFixup(AssemblerFixup *Fixup) { Fixup->set_position(size()); }
1368acded039857a42b170c1cbc0ad4d1345419de3cJan Voung
1379612d32c7e5eb2cb403686ef31172d42e075e460Andrew Scull  /// Get the size of the emitted code.
138aff4ccf9a77b664127f2fd5bc0b98243008be067John Porto  intptr_t size() const { return Cursor - Contents; }
139aff4ccf9a77b664127f2fd5bc0b98243008be067John Porto  uintptr_t contents() const { return Contents; }
1408acded039857a42b170c1cbc0ad4d1345419de3cJan Voung
1419612d32c7e5eb2cb403686ef31172d42e075e460Andrew Scull  /// To emit an instruction to the assembler buffer, the EnsureCapacity helper
1429612d32c7e5eb2cb403686ef31172d42e075e460Andrew Scull  /// must be used to guarantee that the underlying data area is big enough to
1439612d32c7e5eb2cb403686ef31172d42e075e460Andrew Scull  /// hold the emitted instruction. Usage:
1449612d32c7e5eb2cb403686ef31172d42e075e460Andrew Scull  ///
1459612d32c7e5eb2cb403686ef31172d42e075e460Andrew Scull  ///     AssemblerBuffer buffer;
1469612d32c7e5eb2cb403686ef31172d42e075e460Andrew Scull  ///     AssemblerBuffer::EnsureCapacity ensured(&buffer);
1479612d32c7e5eb2cb403686ef31172d42e075e460Andrew Scull  ///     ... emit bytes for single instruction ...
1488acded039857a42b170c1cbc0ad4d1345419de3cJan Voung  class EnsureCapacity {
149f76fd3774379179427a228c29d38cc3ca1d904c1Jan Voung    EnsureCapacity(const EnsureCapacity &) = delete;
150f76fd3774379179427a228c29d38cc3ca1d904c1Jan Voung    EnsureCapacity &operator=(const EnsureCapacity &) = delete;
151f76fd3774379179427a228c29d38cc3ca1d904c1Jan Voung
1528acded039857a42b170c1cbc0ad4d1345419de3cJan Voung  public:
15320b71f5890ee8651983b126c5978594a01e0af96Jim Stichnoth    explicit EnsureCapacity(AssemblerBuffer *Buffer) : Buffer(Buffer) {
15420b71f5890ee8651983b126c5978594a01e0af96Jim Stichnoth      if (Buffer->cursor() >= Buffer->limit())
15520b71f5890ee8651983b126c5978594a01e0af96Jim Stichnoth        Buffer->extendCapacity();
15620b71f5890ee8651983b126c5978594a01e0af96Jim Stichnoth      if (BuildDefs::asserts())
15720b71f5890ee8651983b126c5978594a01e0af96Jim Stichnoth        validate(Buffer);
15820b71f5890ee8651983b126c5978594a01e0af96Jim Stichnoth    }
1598acded039857a42b170c1cbc0ad4d1345419de3cJan Voung    ~EnsureCapacity();
1608acded039857a42b170c1cbc0ad4d1345419de3cJan Voung
1618acded039857a42b170c1cbc0ad4d1345419de3cJan Voung  private:
162aff4ccf9a77b664127f2fd5bc0b98243008be067John Porto    AssemblerBuffer *Buffer;
16320b71f5890ee8651983b126c5978594a01e0af96Jim Stichnoth    intptr_t Gap = 0;
1648acded039857a42b170c1cbc0ad4d1345419de3cJan Voung
16520b71f5890ee8651983b126c5978594a01e0af96Jim Stichnoth    void validate(AssemblerBuffer *Buffer);
166aff4ccf9a77b664127f2fd5bc0b98243008be067John Porto    intptr_t computeGap() { return Buffer->capacity() - Buffer->size(); }
1678acded039857a42b170c1cbc0ad4d1345419de3cJan Voung  };
1688acded039857a42b170c1cbc0ad4d1345419de3cJan Voung
169aff4ccf9a77b664127f2fd5bc0b98243008be067John Porto  bool HasEnsuredCapacity;
17020b71f5890ee8651983b126c5978594a01e0af96Jim Stichnoth  bool hasEnsuredCapacity() const {
17120b71f5890ee8651983b126c5978594a01e0af96Jim Stichnoth    if (BuildDefs::asserts())
17220b71f5890ee8651983b126c5978594a01e0af96Jim Stichnoth      return HasEnsuredCapacity;
17320b71f5890ee8651983b126c5978594a01e0af96Jim Stichnoth    // Disable the actual check in non-debug mode.
17420b71f5890ee8651983b126c5978594a01e0af96Jim Stichnoth    return true;
17520b71f5890ee8651983b126c5978594a01e0af96Jim Stichnoth  }
1768acded039857a42b170c1cbc0ad4d1345419de3cJan Voung
1779612d32c7e5eb2cb403686ef31172d42e075e460Andrew Scull  /// Returns the position in the instruction stream.
178aff4ccf9a77b664127f2fd5bc0b98243008be067John Porto  intptr_t getPosition() const { return Cursor - Contents; }
1798acded039857a42b170c1cbc0ad4d1345419de3cJan Voung
1809612d32c7e5eb2cb403686ef31172d42e075e460Andrew Scull  /// Create and track a fixup in the current function.
181ec27073120be04bf6234a0742e40ae3454ef9d3fJan Voung  AssemblerFixup *createFixup(FixupKind Kind, const Constant *Value);
182ec27073120be04bf6234a0742e40ae3454ef9d3fJan Voung
1832fee2a2f3379d82e2e7a5a2de1e66a5004d50f27Karl Schimpf  /// Create and track a textual fixup in the current function.
1842fee2a2f3379d82e2e7a5a2de1e66a5004d50f27Karl Schimpf  AssemblerTextFixup *createTextFixup(const std::string &Text,
1852fee2a2f3379d82e2e7a5a2de1e66a5004d50f27Karl Schimpf                                      size_t BytesUsed);
1862fee2a2f3379d82e2e7a5a2de1e66a5004d50f27Karl Schimpf
1872fee2a2f3379d82e2e7a5a2de1e66a5004d50f27Karl Schimpf  /// Mark that an attempt was made to emit, but failed. Hence, in order to
1882fee2a2f3379d82e2e7a5a2de1e66a5004d50f27Karl Schimpf  /// continue, one must emit a text fixup.
1892fee2a2f3379d82e2e7a5a2de1e66a5004d50f27Karl Schimpf  void setNeedsTextFixup() { TextFixupNeeded = true; }
19082975ba6fc68c16f10bb437d95d9c0d1859b141eKarl Schimpf  void resetNeedsTextFixup() { TextFixupNeeded = false; }
1912fee2a2f3379d82e2e7a5a2de1e66a5004d50f27Karl Schimpf
1922fee2a2f3379d82e2e7a5a2de1e66a5004d50f27Karl Schimpf  /// Returns true if last emit failed and needs a text fixup.
1932fee2a2f3379d82e2e7a5a2de1e66a5004d50f27Karl Schimpf  bool needsTextFixup() const { return TextFixupNeeded; }
1942fee2a2f3379d82e2e7a5a2de1e66a5004d50f27Karl Schimpf
1952fee2a2f3379d82e2e7a5a2de1e66a5004d50f27Karl Schimpf  /// Installs a created fixup, after it has been allocated.
1962fee2a2f3379d82e2e7a5a2de1e66a5004d50f27Karl Schimpf  void installFixup(AssemblerFixup *F);
1972fee2a2f3379d82e2e7a5a2de1e66a5004d50f27Karl Schimpf
198aff4ccf9a77b664127f2fd5bc0b98243008be067John Porto  const FixupRefList &fixups() const { return Fixups; }
1998acded039857a42b170c1cbc0ad4d1345419de3cJan Voung
2009f42d8ca95d6ed94b6334e652181f82d2edcaa05Jim Stichnoth  void setSize(intptr_t NewSize) {
201aff4ccf9a77b664127f2fd5bc0b98243008be067John Porto    assert(NewSize <= size());
202aff4ccf9a77b664127f2fd5bc0b98243008be067John Porto    Cursor = Contents + NewSize;
2039f42d8ca95d6ed94b6334e652181f82d2edcaa05Jim Stichnoth  }
2049f42d8ca95d6ed94b6334e652181f82d2edcaa05Jim Stichnoth
2058acded039857a42b170c1cbc0ad4d1345419de3cJan Voungprivate:
2069612d32c7e5eb2cb403686ef31172d42e075e460Andrew Scull  /// The limit is set to kMinimumGap bytes before the end of the data area.
2079612d32c7e5eb2cb403686ef31172d42e075e460Andrew Scull  /// This leaves enough space for the longest possible instruction and allows
2089612d32c7e5eb2cb403686ef31172d42e075e460Andrew Scull  /// for a single, fast space check per instruction.
20920b71f5890ee8651983b126c5978594a01e0af96Jim Stichnoth  static constexpr intptr_t kMinimumGap = 32;
2108acded039857a42b170c1cbc0ad4d1345419de3cJan Voung
211aff4ccf9a77b664127f2fd5bc0b98243008be067John Porto  uintptr_t Contents;
212aff4ccf9a77b664127f2fd5bc0b98243008be067John Porto  uintptr_t Cursor;
213aff4ccf9a77b664127f2fd5bc0b98243008be067John Porto  uintptr_t Limit;
214aff4ccf9a77b664127f2fd5bc0b98243008be067John Porto  // The member variable is named Assemblr to avoid hiding the class Assembler.
215aff4ccf9a77b664127f2fd5bc0b98243008be067John Porto  Assembler &Assemblr;
2169612d32c7e5eb2cb403686ef31172d42e075e460Andrew Scull  /// List of pool-allocated fixups relative to the current function.
217aff4ccf9a77b664127f2fd5bc0b98243008be067John Porto  FixupRefList Fixups;
2182fee2a2f3379d82e2e7a5a2de1e66a5004d50f27Karl Schimpf  // True if a textual fixup is needed, because the assembler was unable to
2192fee2a2f3379d82e2e7a5a2de1e66a5004d50f27Karl Schimpf  // emit the last request.
2202fee2a2f3379d82e2e7a5a2de1e66a5004d50f27Karl Schimpf  bool TextFixupNeeded;
2218acded039857a42b170c1cbc0ad4d1345419de3cJan Voung
222aff4ccf9a77b664127f2fd5bc0b98243008be067John Porto  uintptr_t cursor() const { return Cursor; }
223aff4ccf9a77b664127f2fd5bc0b98243008be067John Porto  uintptr_t limit() const { return Limit; }
224aff4ccf9a77b664127f2fd5bc0b98243008be067John Porto  intptr_t capacity() const {
225aff4ccf9a77b664127f2fd5bc0b98243008be067John Porto    assert(Limit >= Contents);
226aff4ccf9a77b664127f2fd5bc0b98243008be067John Porto    return (Limit - Contents) + kMinimumGap;
2278acded039857a42b170c1cbc0ad4d1345419de3cJan Voung  }
2288acded039857a42b170c1cbc0ad4d1345419de3cJan Voung
22957e126899b20c65ff3ea23a3b7d7a67ab30b99dcAndrew Scull  /// Compute the limit based on the data area and the capacity. See description
23057e126899b20c65ff3ea23a3b7d7a67ab30b99dcAndrew Scull  /// of kMinimumGap for the reasoning behind the value.
231aff4ccf9a77b664127f2fd5bc0b98243008be067John Porto  static uintptr_t computeLimit(uintptr_t Data, intptr_t Capacity) {
232aff4ccf9a77b664127f2fd5bc0b98243008be067John Porto    return Data + Capacity - kMinimumGap;
2338acded039857a42b170c1cbc0ad4d1345419de3cJan Voung  }
2348acded039857a42b170c1cbc0ad4d1345419de3cJan Voung
235aff4ccf9a77b664127f2fd5bc0b98243008be067John Porto  void extendCapacity();
2368acded039857a42b170c1cbc0ad4d1345419de3cJan Voung};
2378acded039857a42b170c1cbc0ad4d1345419de3cJan Voung
2388acded039857a42b170c1cbc0ad4d1345419de3cJan Voungclass Assembler {
2392da710ce9fe3bf20b47aacc16e2f6bccc45370c7John Porto  Assembler() = delete;
240f76fd3774379179427a228c29d38cc3ca1d904c1Jan Voung  Assembler(const Assembler &) = delete;
241f76fd3774379179427a228c29d38cc3ca1d904c1Jan Voung  Assembler &operator=(const Assembler &) = delete;
242f76fd3774379179427a228c29d38cc3ca1d904c1Jan Voung
2438acded039857a42b170c1cbc0ad4d1345419de3cJan Voungpublic:
2442da710ce9fe3bf20b47aacc16e2f6bccc45370c7John Porto  enum AssemblerKind {
2452da710ce9fe3bf20b47aacc16e2f6bccc45370c7John Porto    Asm_ARM32,
2462da710ce9fe3bf20b47aacc16e2f6bccc45370c7John Porto    Asm_MIPS32,
2472da710ce9fe3bf20b47aacc16e2f6bccc45370c7John Porto    Asm_X8632,
2482da710ce9fe3bf20b47aacc16e2f6bccc45370c7John Porto    Asm_X8664,
2492da710ce9fe3bf20b47aacc16e2f6bccc45370c7John Porto  };
2502da710ce9fe3bf20b47aacc16e2f6bccc45370c7John Porto
251aff4ccf9a77b664127f2fd5bc0b98243008be067John Porto  virtual ~Assembler() = default;
2528acded039857a42b170c1cbc0ad4d1345419de3cJan Voung
2539612d32c7e5eb2cb403686ef31172d42e075e460Andrew Scull  /// Allocate a chunk of bytes using the per-Assembler allocator.
254aff4ccf9a77b664127f2fd5bc0b98243008be067John Porto  uintptr_t allocateBytes(size_t bytes) {
25557e126899b20c65ff3ea23a3b7d7a67ab30b99dcAndrew Scull    // For now, alignment is not related to NaCl bundle alignment, since the
25657e126899b20c65ff3ea23a3b7d7a67ab30b99dcAndrew Scull    // buffer's GetPosition is relative to the base. So NaCl bundle alignment
25757e126899b20c65ff3ea23a3b7d7a67ab30b99dcAndrew Scull    // checks can be relative to that base. Later, the buffer will be copied
25857e126899b20c65ff3ea23a3b7d7a67ab30b99dcAndrew Scull    // out to a ".text" section (or an in memory-buffer that can be mprotect'ed
25957e126899b20c65ff3ea23a3b7d7a67ab30b99dcAndrew Scull    // with executable permission), and that second buffer should be aligned
26057e126899b20c65ff3ea23a3b7d7a67ab30b99dcAndrew Scull    // for NaCl.
2618acded039857a42b170c1cbc0ad4d1345419de3cJan Voung    const size_t Alignment = 16;
2628acded039857a42b170c1cbc0ad4d1345419de3cJan Voung    return reinterpret_cast<uintptr_t>(Allocator.Allocate(bytes, Alignment));
2638acded039857a42b170c1cbc0ad4d1345419de3cJan Voung  }
2648acded039857a42b170c1cbc0ad4d1345419de3cJan Voung
2659612d32c7e5eb2cb403686ef31172d42e075e460Andrew Scull  /// Allocate data of type T using the per-Assembler allocator.
266aff4ccf9a77b664127f2fd5bc0b98243008be067John Porto  template <typename T> T *allocate() { return Allocator.Allocate<T>(); }
2678acded039857a42b170c1cbc0ad4d1345419de3cJan Voung
2689612d32c7e5eb2cb403686ef31172d42e075e460Andrew Scull  /// Align the tail end of the function to the required target alignment.
26908c3bcd66dc0101720da78c1d5f49230f4521c75Jan Voung  virtual void alignFunction() = 0;
27086df4e9e6d183f07638440afd2c225b485c03917Andrew Scull  /// Align the tail end of the basic block to the required target alignment.
27186df4e9e6d183f07638440afd2c225b485c03917Andrew Scull  void alignCfgNode() {
27286df4e9e6d183f07638440afd2c225b485c03917Andrew Scull    const SizeT Align = 1 << getBundleAlignLog2Bytes();
27386df4e9e6d183f07638440afd2c225b485c03917Andrew Scull    padWithNop(Utils::OffsetToAlignment(Buffer.getPosition(), Align));
27486df4e9e6d183f07638440afd2c225b485c03917Andrew Scull  }
27508c3bcd66dc0101720da78c1d5f49230f4521c75Jan Voung
2769612d32c7e5eb2cb403686ef31172d42e075e460Andrew Scull  /// Add nop padding of a particular width to the current bundle.
2779f42d8ca95d6ed94b6334e652181f82d2edcaa05Jim Stichnoth  virtual void padWithNop(intptr_t Padding) = 0;
2789f42d8ca95d6ed94b6334e652181f82d2edcaa05Jim Stichnoth
27908c3bcd66dc0101720da78c1d5f49230f4521c75Jan Voung  virtual SizeT getBundleAlignLog2Bytes() const = 0;
28008c3bcd66dc0101720da78c1d5f49230f4521c75Jan Voung
28186df4e9e6d183f07638440afd2c225b485c03917Andrew Scull  virtual const char *getAlignDirective() const = 0;
28208c3bcd66dc0101720da78c1d5f49230f4521c75Jan Voung  virtual llvm::ArrayRef<uint8_t> getNonExecBundlePadding() const = 0;
28308c3bcd66dc0101720da78c1d5f49230f4521c75Jan Voung
28486df4e9e6d183f07638440afd2c225b485c03917Andrew Scull  /// Get the label for a CfgNode.
285c2ec58179184e3357255a02b94ec6b219dc44080Jan Voung  virtual Label *getCfgNodeLabel(SizeT NodeNumber) = 0;
28650a3331c517ea0945987b616f4c5cf607aa81b9bKarl Schimpf  /// Mark the current text location as the start of a CFG node.
28750a3331c517ea0945987b616f4c5cf607aa81b9bKarl Schimpf  virtual void bindCfgNodeLabel(const CfgNode *Node) = 0;
2887e1e485744b7205c2bf62356cf0903371fc82b10Jan Voung
289ec27073120be04bf6234a0742e40ae3454ef9d3fJan Voung  virtual bool fixupIsPCRel(FixupKind Kind) const = 0;
290ec27073120be04bf6234a0742e40ae3454ef9d3fJan Voung
291e4289e23cd226f487ef767a59c96e6c77073309aKarl Schimpf  /// Return a view of all the bytes of code for the current function.
29208c3bcd66dc0101720da78c1d5f49230f4521c75Jan Voung  llvm::StringRef getBufferView() const;
29308c3bcd66dc0101720da78c1d5f49230f4521c75Jan Voung
294e4289e23cd226f487ef767a59c96e6c77073309aKarl Schimpf  /// Return the value of the given type in the corresponding buffer.
295e4289e23cd226f487ef767a59c96e6c77073309aKarl Schimpf  template <typename T> T load(intptr_t Position) const {
296e4289e23cd226f487ef767a59c96e6c77073309aKarl Schimpf    return Buffer.load<T>(Position);
297e4289e23cd226f487ef767a59c96e6c77073309aKarl Schimpf  }
298e4289e23cd226f487ef767a59c96e6c77073309aKarl Schimpf
2996e8d3fae541c3e3aa1cb213a9db3a8155edcdbe8John Porto  template <typename T> void store(intptr_t Position, T Value) {
3006e8d3fae541c3e3aa1cb213a9db3a8155edcdbe8John Porto    Buffer.store(Position, Value);
3016e8d3fae541c3e3aa1cb213a9db3a8155edcdbe8John Porto  }
3026e8d3fae541c3e3aa1cb213a9db3a8155edcdbe8John Porto
3032fee2a2f3379d82e2e7a5a2de1e66a5004d50f27Karl Schimpf  /// Emit a fixup at the current location.
3042fee2a2f3379d82e2e7a5a2de1e66a5004d50f27Karl Schimpf  void emitFixup(AssemblerFixup *Fixup) { Buffer.emitFixup(Fixup); }
3052fee2a2f3379d82e2e7a5a2de1e66a5004d50f27Karl Schimpf
306aff4ccf9a77b664127f2fd5bc0b98243008be067John Porto  const FixupRefList &fixups() const { return Buffer.fixups(); }
307ec27073120be04bf6234a0742e40ae3454ef9d3fJan Voung
308ec27073120be04bf6234a0742e40ae3454ef9d3fJan Voung  AssemblerFixup *createFixup(FixupKind Kind, const Constant *Value) {
309aff4ccf9a77b664127f2fd5bc0b98243008be067John Porto    return Buffer.createFixup(Kind, Value);
310ec27073120be04bf6234a0742e40ae3454ef9d3fJan Voung  }
311ec27073120be04bf6234a0742e40ae3454ef9d3fJan Voung
3122fee2a2f3379d82e2e7a5a2de1e66a5004d50f27Karl Schimpf  AssemblerTextFixup *createTextFixup(const std::string &Text,
3132fee2a2f3379d82e2e7a5a2de1e66a5004d50f27Karl Schimpf                                      size_t BytesUsed) {
3142fee2a2f3379d82e2e7a5a2de1e66a5004d50f27Karl Schimpf    return Buffer.createTextFixup(Text, BytesUsed);
3152fee2a2f3379d82e2e7a5a2de1e66a5004d50f27Karl Schimpf  }
3162fee2a2f3379d82e2e7a5a2de1e66a5004d50f27Karl Schimpf
317dc61925cf9de3cba7f310c9e8855c56b8e5b3edcJohn Porto  void bindRelocOffset(RelocOffset *Offset);
318dc61925cf9de3cba7f310c9e8855c56b8e5b3edcJohn Porto
3192fee2a2f3379d82e2e7a5a2de1e66a5004d50f27Karl Schimpf  void setNeedsTextFixup() { Buffer.setNeedsTextFixup(); }
32082975ba6fc68c16f10bb437d95d9c0d1859b141eKarl Schimpf  void resetNeedsTextFixup() { Buffer.resetNeedsTextFixup(); }
3212fee2a2f3379d82e2e7a5a2de1e66a5004d50f27Karl Schimpf
3222fee2a2f3379d82e2e7a5a2de1e66a5004d50f27Karl Schimpf  bool needsTextFixup() const { return Buffer.needsTextFixup(); }
3232fee2a2f3379d82e2e7a5a2de1e66a5004d50f27Karl Schimpf
3245bff61c44841990680781892036adb17b3cff0c4Jim Stichnoth  void emitIASBytes(GlobalContext *Ctx) const;
325bbca754a63fb1e80b4d0f034aa26538f3a8a2a26Jim Stichnoth  bool getInternal() const { return IsInternal; }
326bbca754a63fb1e80b4d0f034aa26538f3a8a2a26Jim Stichnoth  void setInternal(bool Internal) { IsInternal = Internal; }
327467ffe51bebcb3ae3e3ce745c38fc20e8837c31cJim Stichnoth  GlobalString getFunctionName() const { return FunctionName; }
328467ffe51bebcb3ae3e3ce745c38fc20e8837c31cJim Stichnoth  void setFunctionName(GlobalString NewName) { FunctionName = NewName; }
329aff4ccf9a77b664127f2fd5bc0b98243008be067John Porto  intptr_t getBufferSize() const { return Buffer.size(); }
3309612d32c7e5eb2cb403686ef31172d42e075e460Andrew Scull  /// Roll back to a (smaller) size.
331aff4ccf9a77b664127f2fd5bc0b98243008be067John Porto  void setBufferSize(intptr_t NewSize) { Buffer.setSize(NewSize); }
3329f42d8ca95d6ed94b6334e652181f82d2edcaa05Jim Stichnoth  void setPreliminary(bool Value) { Preliminary = Value; }
3339f42d8ca95d6ed94b6334e652181f82d2edcaa05Jim Stichnoth  bool getPreliminary() const { return Preliminary; }
3340faec4c9e067b974ec1d3f65c71af3abaca143aaJan Voung
3352da710ce9fe3bf20b47aacc16e2f6bccc45370c7John Porto  AssemblerKind getKind() const { return Kind; }
3362da710ce9fe3bf20b47aacc16e2f6bccc45370c7John Porto
3372da710ce9fe3bf20b47aacc16e2f6bccc45370c7John Portoprotected:
3385bff61c44841990680781892036adb17b3cff0c4Jim Stichnoth  explicit Assembler(AssemblerKind Kind)
3395bff61c44841990680781892036adb17b3cff0c4Jim Stichnoth      : Kind(Kind), Allocator(), Buffer(*this) {}
3402da710ce9fe3bf20b47aacc16e2f6bccc45370c7John Porto
3418acded039857a42b170c1cbc0ad4d1345419de3cJan Voungprivate:
3422da710ce9fe3bf20b47aacc16e2f6bccc45370c7John Porto  const AssemblerKind Kind;
3432da710ce9fe3bf20b47aacc16e2f6bccc45370c7John Porto
344e82b560e649f8a68bcb252b9b002708e74d962d3John Porto  using AssemblerAllocator =
345e82b560e649f8a68bcb252b9b002708e74d962d3John Porto      llvm::BumpPtrAllocatorImpl<llvm::MallocAllocator, /*SlabSize=*/32 * 1024>;
346e82b560e649f8a68bcb252b9b002708e74d962d3John Porto  AssemblerAllocator Allocator;
347e82b560e649f8a68bcb252b9b002708e74d962d3John Porto
34857e126899b20c65ff3ea23a3b7d7a67ab30b99dcAndrew Scull  /// FunctionName and IsInternal are transferred from the original Cfg object,
34957e126899b20c65ff3ea23a3b7d7a67ab30b99dcAndrew Scull  /// since the Cfg object may be deleted by the time the assembler buffer is
35057e126899b20c65ff3ea23a3b7d7a67ab30b99dcAndrew Scull  /// emitted.
351467ffe51bebcb3ae3e3ce745c38fc20e8837c31cJim Stichnoth  GlobalString FunctionName;
352eafb56cbab02dbf11071efbc56b4a7098bd40dc7Jim Stichnoth  bool IsInternal = false;
35357e126899b20c65ff3ea23a3b7d7a67ab30b99dcAndrew Scull  /// Preliminary indicates whether a preliminary pass is being made for
35457e126899b20c65ff3ea23a3b7d7a67ab30b99dcAndrew Scull  /// calculating bundle padding (Preliminary=true), versus the final pass where
35557e126899b20c65ff3ea23a3b7d7a67ab30b99dcAndrew Scull  /// all changes to label bindings, label links, and relocation fixups are
35657e126899b20c65ff3ea23a3b7d7a67ab30b99dcAndrew Scull  /// fully committed (Preliminary=false).
357eafb56cbab02dbf11071efbc56b4a7098bd40dc7Jim Stichnoth  bool Preliminary = false;
3581a9043e71827183679814c99f375ef5a2a6f15adJohn Porto
3592fee2a2f3379d82e2e7a5a2de1e66a5004d50f27Karl Schimpf  /// Installs a created fixup, after it has been allocated.
3602fee2a2f3379d82e2e7a5a2de1e66a5004d50f27Karl Schimpf  void installFixup(AssemblerFixup *F) { Buffer.installFixup(F); }
3612fee2a2f3379d82e2e7a5a2de1e66a5004d50f27Karl Schimpf
3621a9043e71827183679814c99f375ef5a2a6f15adJohn Portoprotected:
3631a9043e71827183679814c99f375ef5a2a6f15adJohn Porto  // Buffer's constructor uses the Allocator, so it needs to appear after it.
3641a9043e71827183679814c99f375ef5a2a6f15adJohn Porto  // TODO(jpp): dependencies on construction order are a nice way of shooting
3651a9043e71827183679814c99f375ef5a2a6f15adJohn Porto  // yourself in the foot. Fix this.
3661a9043e71827183679814c99f375ef5a2a6f15adJohn Porto  AssemblerBuffer Buffer;
3678acded039857a42b170c1cbc0ad4d1345419de3cJan Voung};
3688acded039857a42b170c1cbc0ad4d1345419de3cJan Voung
3698acded039857a42b170c1cbc0ad4d1345419de3cJan Voung} // end of namespace Ice
3708acded039857a42b170c1cbc0ad4d1345419de3cJan Voung
371aff4ccf9a77b664127f2fd5bc0b98243008be067John Porto#endif // SUBZERO_SRC_ICEASSEMBLER_H_
372