| Index: src/assembler.h
|
| diff --git a/src/assembler.h b/src/assembler.h
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..92cc98d1f9c5ba9b4bc0d81a7f5918f56b8b694b
|
| --- /dev/null
|
| +++ b/src/assembler.h
|
| @@ -0,0 +1,222 @@
|
| +// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
|
| +// for details. All rights reserved. Use of this source code is governed by a
|
| +// BSD-style license that can be found in the LICENSE file.
|
| +//
|
| +// Modified by the Subzero authors.
|
| +//
|
| +//===- subzero/src/assembler.h - Integrated assembler -----------*- C++ -*-===//
|
| +//
|
| +// The Subzero Code Generator
|
| +//
|
| +// This file is distributed under the University of Illinois Open Source
|
| +// License. See LICENSE.TXT for details.
|
| +//
|
| +//===----------------------------------------------------------------------===//
|
| +//
|
| +// This file declares the Assembler base class. Instructions are assembled
|
| +// by architecture-specific assemblers that derive from this base class.
|
| +// This base class manages buffers and fixups for emitting code, etc.
|
| +//
|
| +//===----------------------------------------------------------------------===//
|
| +
|
| +#ifndef SUBZERO_SRC_ASSEMBLER_H
|
| +#define SUBZERO_SRC_ASSEMBLER_H
|
| +
|
| +#include "IceDefs.h"
|
| +
|
| +#include "IceFixups.h"
|
| +#include "llvm/Support/Allocator.h"
|
| +
|
| +namespace Ice {
|
| +
|
| +// Forward declarations.
|
| +class Assembler;
|
| +class AssemblerFixup;
|
| +class AssemblerBuffer;
|
| +class ConstantRelocatable;
|
| +class MemoryRegion;
|
| +
|
| +// Assembler fixups are positions in generated code that hold relocation
|
| +// information that needs to be processed before finalizing the code
|
| +// into executable memory.
|
| +class AssemblerFixup {
|
| +public:
|
| + virtual void Process(const MemoryRegion ®ion, intptr_t position) = 0;
|
| +
|
| + // It would be ideal if the destructor method could be made private,
|
| + // but the g++ compiler complains when this is subclassed.
|
| + virtual ~AssemblerFixup() { llvm_unreachable("~AssemblerFixup used"); }
|
| +
|
| + intptr_t position() const { return position_; }
|
| +
|
| + FixupKind kind() const { return kind_; }
|
| +
|
| + const ConstantRelocatable *value() const { return value_; }
|
| +
|
| +protected:
|
| + AssemblerFixup(FixupKind Kind, const ConstantRelocatable *Value)
|
| + : position_(0), kind_(Kind), value_(Value) {}
|
| +
|
| +private:
|
| + intptr_t position_;
|
| + FixupKind kind_;
|
| + const ConstantRelocatable *value_;
|
| +
|
| + void set_position(intptr_t position) { position_ = position; }
|
| +
|
| + AssemblerFixup(const AssemblerFixup &) LLVM_DELETED_FUNCTION;
|
| + AssemblerFixup &operator=(const AssemblerFixup &) LLVM_DELETED_FUNCTION;
|
| + friend class AssemblerBuffer;
|
| +};
|
| +
|
| +// Assembler buffers are used to emit binary code. They grow on demand.
|
| +class AssemblerBuffer {
|
| +public:
|
| + AssemblerBuffer(Assembler &);
|
| + ~AssemblerBuffer();
|
| +
|
| + // Basic support for emitting, loading, and storing.
|
| + template <typename T> void Emit(T value) {
|
| + assert(HasEnsuredCapacity());
|
| + *reinterpret_cast<T *>(cursor_) = value;
|
| + cursor_ += sizeof(T);
|
| + }
|
| +
|
| + template <typename T> T Load(intptr_t position) const {
|
| + assert(position >= 0 &&
|
| + position <= (Size() - static_cast<intptr_t>(sizeof(T))));
|
| + return *reinterpret_cast<T *>(contents_ + position);
|
| + }
|
| +
|
| + template <typename T> void Store(intptr_t position, T value) {
|
| + assert(position >= 0 &&
|
| + position <= (Size() - static_cast<intptr_t>(sizeof(T))));
|
| + *reinterpret_cast<T *>(contents_ + position) = value;
|
| + }
|
| +
|
| + // Emit a fixup at the current location.
|
| + void EmitFixup(AssemblerFixup *fixup) {
|
| + fixup->set_position(Size());
|
| + fixups_.push_back(fixup);
|
| + }
|
| +
|
| + // Get the size of the emitted code.
|
| + intptr_t Size() const { return cursor_ - contents_; }
|
| + uintptr_t contents() const { return contents_; }
|
| +
|
| + // Copy the assembled instructions into the specified memory block
|
| + // and apply all fixups.
|
| + // TODO(jvoung): This will be different. We'll be writing the text
|
| + // and reloc section to a file?
|
| + void FinalizeInstructions(const MemoryRegion ®ion);
|
| +
|
| +// To emit an instruction to the assembler buffer, the EnsureCapacity helper
|
| +// must be used to guarantee that the underlying data area is big enough to
|
| +// hold the emitted instruction. Usage:
|
| +//
|
| +// AssemblerBuffer buffer;
|
| +// AssemblerBuffer::EnsureCapacity ensured(&buffer);
|
| +// ... emit bytes for single instruction ...
|
| +
|
| +#if defined(DEBUG)
|
| + class EnsureCapacity {
|
| + public:
|
| + explicit EnsureCapacity(AssemblerBuffer *buffer);
|
| + ~EnsureCapacity();
|
| +
|
| + private:
|
| + AssemblerBuffer *buffer_;
|
| + intptr_t gap_;
|
| +
|
| + intptr_t ComputeGap() { return buffer_->Capacity() - buffer_->Size(); }
|
| + };
|
| +
|
| + bool has_ensured_capacity_;
|
| + bool HasEnsuredCapacity() const { return has_ensured_capacity_; }
|
| +#else
|
| + class EnsureCapacity {
|
| + public:
|
| + explicit EnsureCapacity(AssemblerBuffer *buffer) {
|
| + if (buffer->cursor() >= buffer->limit())
|
| + buffer->ExtendCapacity();
|
| + }
|
| + };
|
| +
|
| + // When building the C++ tests, assertion code is enabled. To allow
|
| + // asserting that the user of the assembler buffer has ensured the
|
| + // capacity needed for emitting, we add a dummy method in non-debug mode.
|
| + bool HasEnsuredCapacity() const { return true; }
|
| +#endif
|
| +
|
| + // Returns the position in the instruction stream.
|
| + intptr_t GetPosition() const { return cursor_ - contents_; }
|
| +
|
| + // For bringup only.
|
| + AssemblerFixup *GetLatestFixup() const;
|
| +
|
| +private:
|
| + // The limit is set to kMinimumGap bytes before the end of the data area.
|
| + // This leaves enough space for the longest possible instruction and allows
|
| + // for a single, fast space check per instruction.
|
| + static const intptr_t kMinimumGap = 32;
|
| +
|
| + uintptr_t contents_;
|
| + uintptr_t cursor_;
|
| + uintptr_t limit_;
|
| + Assembler &assembler_;
|
| + std::vector<AssemblerFixup *> fixups_;
|
| +#if defined(DEBUG)
|
| + bool fixups_processed_;
|
| +#endif
|
| +
|
| + uintptr_t cursor() const { return cursor_; }
|
| + uintptr_t limit() const { return limit_; }
|
| + intptr_t Capacity() const {
|
| + assert(limit_ >= contents_);
|
| + return (limit_ - contents_) + kMinimumGap;
|
| + }
|
| +
|
| + // Process the fixup chain.
|
| + void ProcessFixups(const MemoryRegion ®ion);
|
| +
|
| + // Compute the limit based on the data area and the capacity. See
|
| + // description of kMinimumGap for the reasoning behind the value.
|
| + static uintptr_t ComputeLimit(uintptr_t data, intptr_t capacity) {
|
| + return data + capacity - kMinimumGap;
|
| + }
|
| +
|
| + void ExtendCapacity();
|
| +
|
| + friend class AssemblerFixup;
|
| +};
|
| +
|
| +class Assembler {
|
| +public:
|
| + Assembler() {}
|
| + ~Assembler() {}
|
| +
|
| + // Allocate a chunk of bytes using the per-Assembler allocator.
|
| + uintptr_t AllocateBytes(size_t bytes) {
|
| + // For now, alignment is not related to NaCl bundle alignment, since
|
| + // the buffer's GetPosition is relative to the base. So NaCl bundle
|
| + // alignment checks can be relative to that base. Later, the buffer
|
| + // will be copied out to a ".text" section (or an in memory-buffer
|
| + // that can be mprotect'ed with executable permission), and that
|
| + // second buffer should be aligned for NaCl.
|
| + const size_t Alignment = 16;
|
| + return reinterpret_cast<uintptr_t>(Allocator.Allocate(bytes, Alignment));
|
| + }
|
| +
|
| + // Allocate data of type T using the per-Assembler allocator.
|
| + template <typename T> T *Allocate() { return Allocator.Allocate<T>(); }
|
| +
|
| +private:
|
| + llvm::BumpPtrAllocator Allocator;
|
| +
|
| + Assembler(const Assembler &) LLVM_DELETED_FUNCTION;
|
| + Assembler &operator=(const Assembler &) LLVM_DELETED_FUNCTION;
|
| +};
|
| +
|
| +} // end of namespace Ice
|
| +
|
| +#endif // SUBZERO_SRC_ASSEMBLER_H_
|
|
|