Chromium Code Reviews| Index: runtime/vm/assembler_arm64.h |
| =================================================================== |
| --- runtime/vm/assembler_arm64.h (revision 0) |
| +++ runtime/vm/assembler_arm64.h (revision 0) |
| @@ -0,0 +1,333 @@ |
| +// Copyright (c) 2014, 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. |
| + |
| +#ifndef VM_ASSEMBLER_ARM64_H_ |
| +#define VM_ASSEMBLER_ARM64_H_ |
| + |
| +#ifndef VM_ASSEMBLER_H_ |
| +#error Do not include assembler_arm64.h directly; use assembler.h instead. |
| +#endif |
| + |
| +#include "platform/assert.h" |
| +#include "platform/utils.h" |
| +#include "vm/constants_arm64.h" |
| +#include "vm/object.h" |
| +#include "vm/simulator.h" |
| + |
| +namespace dart { |
| + |
| +// Forward declarations. |
| +class RuntimeEntry; |
| + |
| +// TODO(zra): Label, Address, and FieldAddress are copied from ARM, |
| +// they must be adapted to ARM64. |
| +class Label : public ValueObject { |
| + public: |
| + Label() : position_(0) { } |
| + |
| + ~Label() { |
| + // Assert if label is being destroyed with unresolved branches pending. |
| + ASSERT(!IsLinked()); |
| + } |
| + |
| + // Returns the position for bound and linked labels. Cannot be used |
| + // for unused labels. |
| + intptr_t Position() const { |
| + ASSERT(!IsUnused()); |
| + return IsBound() ? -position_ - kWordSize : position_ - kWordSize; |
| + } |
| + |
| + bool IsBound() const { return position_ < 0; } |
| + bool IsUnused() const { return position_ == 0; } |
| + bool IsLinked() const { return position_ > 0; } |
| + |
| + private: |
| + intptr_t position_; |
| + |
| + void Reinitialize() { |
| + position_ = 0; |
| + } |
| + |
| + void BindTo(intptr_t position) { |
| + ASSERT(!IsBound()); |
| + position_ = -position - kWordSize; |
| + ASSERT(IsBound()); |
| + } |
| + |
| + void LinkTo(intptr_t position) { |
| + ASSERT(!IsBound()); |
| + position_ = position + kWordSize; |
| + ASSERT(IsLinked()); |
| + } |
| + |
| + friend class Assembler; |
| + DISALLOW_COPY_AND_ASSIGN(Label); |
| +}; |
| + |
| + |
| +class Address : public ValueObject { |
| + public: |
| + Address(const Address& other) |
| + : ValueObject(), encoding_(other.encoding_) { |
| + } |
| + |
| + Address& operator=(const Address& other) { |
| + encoding_ = other.encoding_; |
| + return *this; |
| + } |
| + |
| + Address(Register rn, int32_t offset = 0) { |
| + ASSERT(Utils::IsAbsoluteUint(12, offset)); |
| + encoding_ = -1; |
| + } |
| + |
| + private: |
| + uint32_t encoding() const { return encoding_; } |
| + |
| + uint32_t encoding_; |
| + |
| + friend class Assembler; |
| +}; |
| + |
| + |
| +class FieldAddress : public Address { |
| + public: |
| + FieldAddress(Register base, int32_t disp) |
| + : Address(base, disp - kHeapObjectTag) { } |
| + |
| + FieldAddress(const FieldAddress& other) : Address(other) { } |
| + |
| + FieldAddress& operator=(const FieldAddress& other) { |
| + Address::operator=(other); |
| + return *this; |
| + } |
| +}; |
| + |
| + |
| +// Shift or Extend operand for ADD and SUB. |
| +class AddSubOperand : public ValueObject { |
|
regis
2014/04/01 22:25:15
Is AddSubOperand a good name?
There are more instr
zra
2014/04/02 00:04:25
I had anticipated the bitfield immediate operand t
|
| + public: |
| + // Data-processing operand - Uninitialized. |
| + AddSubOperand() : encoding_(-1) { } |
| + |
| + // Data-processing operands - Copy constructor. |
| + AddSubOperand(const AddSubOperand& other) |
| + : ValueObject(), encoding_(other.encoding_), type_(other.type_) { } |
| + |
| + explicit AddSubOperand(Register rm) { |
| + encoding_ = (static_cast<int32_t>(rm) << kRmShift); |
| + } |
| + |
| + AddSubOperand(Register rm, Shift shift, int32_t imm) { |
| + ASSERT(Utils::IsUint(6, imm)); |
| + encoding_ = |
| + (imm << kImm6Shift) | |
| + (static_cast<int32_t>(rm) << kRmShift) | |
| + (static_cast<int32_t>(shift) << kShiftTypeShift); |
| + type_ = ASShifted; |
| + } |
| + |
| + AddSubOperand(Register rm, Extend extend, int32_t imm) { |
| + ASSERT(Utils::IsUint(3, imm)); |
| + encoding_ = |
| + B21 | |
| + (static_cast<int32_t>(rm) << kRmShift) | |
| + (static_cast<int32_t>(extend) << kExtendTypeShift) | |
| + ((imm & 0x7) << kImm3Shift); |
| + type_ = ASExtended; |
| + } |
| + |
| + explicit AddSubOperand(int32_t imm) { |
| + if (Utils::IsUint(12, imm)) { |
| + encoding_ = imm << kImm12Shift; |
| + } else { |
| + // imm only has bits in [12, 24) set. |
| + ASSERT(((imm & 0xfff) == 0) && (Utils::IsUint(12, imm >> 12))); |
| + encoding_ = B22 | ((imm >> 12) << kImm12Shift); |
| + } |
| + type_ = ASImmediate; |
| + } |
| + |
| + enum ASOpType { |
|
regis
2014/04/01 22:25:15
Does this mean AddSubOperandType?
How about Opera
zra
2014/04/02 00:04:25
Done.
|
| + ASShifted, |
| + ASExtended, |
| + ASImmediate, |
| + }; |
| + |
| + private: |
| + uint32_t encoding() const { |
| + return encoding_; |
| + } |
| + ASOpType type() const { |
| + return type_; |
| + } |
| + |
| + uint32_t encoding_; |
| + ASOpType type_; |
| + |
| + friend class Assembler; |
| +}; |
| + |
| + |
| +class Assembler : public ValueObject { |
| + public: |
| + explicit Assembler(bool use_far_branches = false) |
| + : buffer_(), |
| + object_pool_(GrowableObjectArray::Handle()), |
| + prologue_offset_(-1), |
| + use_far_branches_(use_far_branches), |
| + comments_() { } |
| + ~Assembler() { } |
| + |
| + void PopRegister(Register r) { |
| + UNIMPLEMENTED(); |
| + } |
| + |
| + void Drop(intptr_t stack_elements) { |
| + UNIMPLEMENTED(); |
| + } |
| + |
| + void Bind(Label* label) { |
| + UNIMPLEMENTED(); |
| + } |
| + |
| + // Misc. functionality |
| + intptr_t CodeSize() const { return buffer_.Size(); } |
| + intptr_t prologue_offset() const { return prologue_offset_; } |
| + |
| + // Count the fixups that produce a pointer offset, without processing |
| + // the fixups. On ARM64 there are no pointers in code. |
| + intptr_t CountPointerOffsets() const { return 0; } |
| + |
| + const ZoneGrowableArray<intptr_t>& GetPointerOffsets() const { |
| + ASSERT(buffer_.pointer_offsets().length() == 0); // No pointers in code. |
| + return buffer_.pointer_offsets(); |
| + } |
| + const GrowableObjectArray& object_pool() const { return object_pool_; } |
| + |
| + bool use_far_branches() const { |
| + return FLAG_use_far_branches || use_far_branches_; |
| + } |
| + |
| + void set_use_far_branches(bool b) { |
| + ASSERT(buffer_.Size() == 0); |
| + use_far_branches_ = b; |
| + } |
| + |
| + void FinalizeInstructions(const MemoryRegion& region) { |
| + buffer_.FinalizeInstructions(region); |
| + } |
| + |
| + // Debugging and bringup support. |
| + void Stop(const char* message); |
| + void Unimplemented(const char* message); |
| + void Untested(const char* message); |
| + void Unreachable(const char* message); |
| + |
| + static void InitializeMemoryWithBreakpoints(uword data, intptr_t length); |
| + |
| + void Comment(const char* format, ...) PRINTF_ATTRIBUTE(2, 3); |
| + |
| + const Code::Comments& GetCodeComments() const; |
| + |
| + static const char* RegisterName(Register reg); |
| + |
| + static const char* FpuRegisterName(FpuRegister reg); |
| + |
| + // TODO(zra): Make sure this is right. |
| + // Instruction pattern from entrypoint is used in Dart frame prologs |
| + // to set up the frame and save a PC which can be used to figure out the |
| + // RawInstruction object corresponding to the code running in the frame. |
| + static const intptr_t kEntryPointToPcMarkerOffset = 0; |
| + |
| + // Emit data (e.g encoded instruction or immediate) in instruction stream. |
| + void Emit(int32_t value); |
| + |
| + // On some other platforms, we draw a distinction between safe and unsafe |
| + // smis. |
| + static bool IsSafe(const Object& object) { return true; } |
| + static bool IsSafeSmi(const Object& object) { return object.IsSmi(); } |
| + |
| + // Add unsigned immediate. |
| + // shifted = true => imm left-shifted by 12 then added. |
| + void addi(OperandSize os, Register rd, Register rn, AddSubOperand aso) { |
|
regis
2014/04/01 22:25:15
Passing OperandSize explicitly seems strange to me
zra
2014/04/02 00:04:25
Since add() become more complicated, I added a hel
|
| + ASSERT(aso.type() == AddSubOperand::ASImmediate); |
|
regis
2014/04/01 22:25:15
We will probably have a "macro" instruction AddImm
zra
2014/04/02 00:04:25
Done.
|
| + EmitAddSubImmOp(ADDI, rd, rn, aso, os, false); |
| + } |
| + |
| + // Add register. |
| + void add(OperandSize os, Register rd, Register rn, AddSubOperand aso) { |
| + ASSERT(aso.type() != AddSubOperand::ASImmediate); |
| + EmitAddSubShiftExtOp(ADD, rd, rn, aso, os, false); |
| + } |
| + |
| + // Function return. |
| + void ret(Register rn = R30) { |
| + EmitUnconditionalBranchRegOp(RET, rn); |
| + } |
| + |
| + private: |
| + AssemblerBuffer buffer_; // Contains position independent code. |
| + GrowableObjectArray& object_pool_; // Objects and patchable jump targets. |
| + int32_t prologue_offset_; |
| + |
| + bool use_far_branches_; |
| + |
| + class CodeComment : public ZoneAllocated { |
| + public: |
| + CodeComment(intptr_t pc_offset, const String& comment) |
| + : pc_offset_(pc_offset), comment_(comment) { } |
| + |
| + intptr_t pc_offset() const { return pc_offset_; } |
| + const String& comment() const { return comment_; } |
| + |
| + private: |
| + intptr_t pc_offset_; |
| + const String& comment_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(CodeComment); |
| + }; |
| + |
| + GrowableArray<CodeComment*> comments_; |
| + |
| + void EmitAddSubImmOp(AddSubImmOp op, Register rd, Register rn, |
| + AddSubOperand aso, OperandSize os, bool set_flags) { |
| + ASSERT((os == kDoubleWord) || (os == kWord)); |
| + const int32_t size = (os == kDoubleWord) ? B31 : 0; |
| + const int32_t s = set_flags ? B29 : 0; |
| + const int32_t encoding = |
| + op | size | s | |
| + (static_cast<int32_t>(rd) << kRdShift) | |
| + (static_cast<int32_t>(rn) << kRnShift) | |
| + aso.encoding(); |
| + Emit(encoding); |
| + } |
| + |
| + void EmitAddSubShiftExtOp(AddSubShiftExtOp op, |
| + Register rd, Register rn, AddSubOperand aso, |
| + OperandSize os, bool set_flags) { |
| + ASSERT((os == kDoubleWord) || (os == kWord)); |
| + const int32_t size = (os == kDoubleWord) ? B31 : 0; |
| + const int32_t s = set_flags ? B29 : 0; |
| + const int32_t encoding = |
| + op | size | s | |
| + (static_cast<int32_t>(rd) << kRdShift) | |
| + (static_cast<int32_t>(rn) << kRnShift) | |
| + aso.encoding(); |
| + Emit(encoding); |
| + } |
| + |
| + void EmitUnconditionalBranchRegOp(UnconditionalBranchRegOp op, Register rn) { |
| + const int32_t encoding = |
| + op | (static_cast<int32_t>(rn) << kRnShift); |
| + Emit(encoding); |
| + } |
| + |
| + DISALLOW_ALLOCATION(); |
| + DISALLOW_COPY_AND_ASSIGN(Assembler); |
| +}; |
| + |
| +} // namespace dart |
| + |
| +#endif // VM_ASSEMBLER_ARM64_H_ |