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