hotspot/src/cpu/arm/vm/assembler_arm.hpp
changeset 42664 29142a56c193
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/cpu/arm/vm/assembler_arm.hpp	Mon Dec 19 12:39:01 2016 -0500
@@ -0,0 +1,404 @@
+/*
+ * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef CPU_ARM_VM_ASSEMBLER_ARM_HPP
+#define CPU_ARM_VM_ASSEMBLER_ARM_HPP
+
+#include "utilities/macros.hpp"
+
+enum AsmCondition {
+  eq, ne, cs, cc, mi, pl, vs, vc,
+  hi, ls, ge, lt, gt, le, al, nv,
+  number_of_conditions,
+  // alternative names
+  hs = cs,
+  lo = cc
+};
+
+enum AsmShift {
+  lsl, lsr, asr, ror
+};
+
+#ifdef AARCH64
+enum AsmExtendOp {
+  ex_uxtb, ex_uxth, ex_uxtw, ex_uxtx,
+  ex_sxtb, ex_sxth, ex_sxtw, ex_sxtx,
+
+  ex_lsl = ex_uxtx
+};
+#endif
+
+enum AsmOffset {
+#ifdef AARCH64
+  basic_offset = 0b00,
+  pre_indexed  = 0b11,
+  post_indexed = 0b01
+#else
+  basic_offset = 1 << 24,
+  pre_indexed  = 1 << 24 | 1 << 21,
+  post_indexed = 0
+#endif
+};
+
+
+#ifndef AARCH64
+enum AsmWriteback {
+  no_writeback,
+  writeback
+};
+
+enum AsmOffsetOp {
+  sub_offset = 0,
+  add_offset = 1
+};
+#endif
+
+
+// ARM Addressing Modes 2 and 3 - Load and store
+class Address VALUE_OBJ_CLASS_SPEC {
+ private:
+  Register  _base;
+  Register  _index;
+  int       _disp;
+  AsmOffset _mode;
+  RelocationHolder   _rspec;
+  int       _shift_imm;
+#ifdef AARCH64
+  AsmExtendOp _extend;
+#else
+  AsmShift  _shift;
+  AsmOffsetOp _offset_op;
+
+  static inline int abs(int x) { return x < 0 ? -x : x; }
+  static inline int up (int x) { return x < 0 ?  0 : 1; }
+#endif
+
+#ifdef AARCH64
+  static const AsmExtendOp LSL = ex_lsl;
+#else
+  static const AsmShift LSL = lsl;
+#endif
+
+ public:
+  Address() : _base(noreg) {}
+
+  Address(Register rn, int offset = 0, AsmOffset mode = basic_offset) {
+    _base = rn;
+    _index = noreg;
+    _disp = offset;
+    _mode = mode;
+    _shift_imm = 0;
+#ifdef AARCH64
+    _extend = ex_lsl;
+#else
+    _shift = lsl;
+    _offset_op = add_offset;
+#endif
+  }
+
+#ifdef ASSERT
+  Address(Register rn, ByteSize offset, AsmOffset mode = basic_offset) {
+    _base = rn;
+    _index = noreg;
+    _disp = in_bytes(offset);
+    _mode = mode;
+    _shift_imm = 0;
+#ifdef AARCH64
+    _extend = ex_lsl;
+#else
+    _shift = lsl;
+    _offset_op = add_offset;
+#endif
+  }
+#endif
+
+#ifdef AARCH64
+  Address(Register rn, Register rm, AsmExtendOp extend = ex_lsl, int shift_imm = 0) {
+    assert ((extend == ex_uxtw) || (extend == ex_lsl) || (extend == ex_sxtw) || (extend == ex_sxtx), "invalid extend for address mode");
+    assert ((0 <= shift_imm) && (shift_imm <= 4), "shift amount is out of range");
+    _base = rn;
+    _index = rm;
+    _disp = 0;
+    _mode = basic_offset;
+    _extend = extend;
+    _shift_imm = shift_imm;
+  }
+#else
+  Address(Register rn, Register rm, AsmShift shift = lsl,
+          int shift_imm = 0, AsmOffset mode = basic_offset,
+          AsmOffsetOp offset_op = add_offset) {
+    _base = rn;
+    _index = rm;
+    _disp = 0;
+    _shift = shift;
+    _shift_imm = shift_imm;
+    _mode = mode;
+    _offset_op = offset_op;
+  }
+
+  Address(Register rn, RegisterOrConstant offset, AsmShift shift = lsl,
+          int shift_imm = 0) {
+    _base = rn;
+    if (offset.is_constant()) {
+      _index = noreg;
+      {
+        int off = (int) offset.as_constant();
+        if (shift_imm != 0) {
+          assert(shift == lsl,"shift not yet encoded");
+          off =  off << shift_imm;
+        }
+        _disp = off;
+      }
+      _shift = lsl;
+      _shift_imm = 0;
+    } else {
+      _index = offset.as_register();
+      _disp = 0;
+      _shift = shift;
+      _shift_imm = shift_imm;
+    }
+    _mode = basic_offset;
+    _offset_op = add_offset;
+  }
+#endif // AARCH64
+
+  // [base + index * wordSize]
+  static Address indexed_ptr(Register base, Register index) {
+    return Address(base, index, LSL, LogBytesPerWord);
+  }
+
+  // [base + index * BytesPerInt]
+  static Address indexed_32(Register base, Register index) {
+    return Address(base, index, LSL, LogBytesPerInt);
+  }
+
+  // [base + index * BytesPerHeapOop]
+  static Address indexed_oop(Register base, Register index) {
+    return Address(base, index, LSL, LogBytesPerHeapOop);
+  }
+
+  Address plus_disp(int disp) const {
+    assert((disp == 0) || (_index == noreg),"can't apply an offset to a register indexed address");
+    Address a = (*this);
+    a._disp += disp;
+    return a;
+  }
+
+  Address rebase(Register new_base) const {
+    Address a = (*this);
+    a._base = new_base;
+    return a;
+  }
+
+#ifdef AARCH64
+  int encoding_simd() const {
+    assert(_index != SP, "encoding constraint");
+    assert(_disp == 0 || _mode == post_indexed,  "encoding constraint");
+    assert(_index == noreg || _mode == basic_offset, "encoding constraint");
+    assert(_mode == basic_offset || _mode == post_indexed, "encoding constraint");
+    assert(_extend == ex_lsl, "encoding constraint");
+    int index;
+    if (_index == noreg) {
+      if (_mode == post_indexed)
+        index = 0b100 << 5 | 31;
+      else
+        index = 0;
+    } else {
+      index = 0b100 << 5 | _index->encoding();
+    }
+    return index << 16 | _base->encoding_with_sp() << 5;
+  }
+#else /* !AARCH64 */
+  int encoding2() const {
+    assert(_mode == basic_offset || _base != PC, "unpredictable instruction");
+    if (_index == noreg) {
+      assert(-4096 < _disp && _disp < 4096, "encoding constraint");
+      return _mode | up(_disp) << 23 | _base->encoding() << 16 | abs(_disp);
+    } else {
+      assert(_index != PC && (_mode == basic_offset || _index != _base), "unpredictable instruction");
+      assert(_disp == 0 && (_shift_imm >> 5) == 0, "encoding constraint");
+      return 1 << 25 | _offset_op << 23 | _mode | _base->encoding() << 16 |
+             _shift_imm << 7 | _shift << 5 | _index->encoding();
+    }
+  }
+
+  int encoding3() const {
+    assert(_mode == basic_offset || _base != PC, "unpredictable instruction");
+    if (_index == noreg) {
+      assert(-256 < _disp && _disp < 256, "encoding constraint");
+      return _mode | up(_disp) << 23 | 1 << 22 | _base->encoding() << 16 |
+             (abs(_disp) & 0xf0) << 4 | abs(_disp) & 0x0f;
+    } else {
+      assert(_index != PC && (_mode == basic_offset || _index != _base), "unpredictable instruction");
+      assert(_disp == 0 && _shift == lsl && _shift_imm == 0, "encoding constraint");
+      return _mode | _offset_op << 23 | _base->encoding() << 16 | _index->encoding();
+    }
+  }
+
+  int encoding_ex() const {
+    assert(_index == noreg && _disp == 0 && _mode == basic_offset &&
+           _base != PC, "encoding constraint");
+    return _base->encoding() << 16;
+  }
+
+  int encoding_vfp() const {
+    assert(_index == noreg && _mode == basic_offset, "encoding constraint");
+    assert(-1024 < _disp && _disp < 1024 && (_disp & 3) == 0, "encoding constraint");
+    return _base->encoding() << 16 | up(_disp) << 23 | abs(_disp) >> 2;
+  }
+
+  int encoding_simd() const {
+    assert(_base != PC, "encoding constraint");
+    assert(_index != PC && _index != SP, "encoding constraint");
+    assert(_disp == 0, "encoding constraint");
+    assert(_shift == 0, "encoding constraint");
+    assert(_index == noreg || _mode == basic_offset, "encoding constraint");
+    assert(_mode == basic_offset || _mode == post_indexed, "encoding constraint");
+    int index;
+    if (_index == noreg) {
+      if (_mode == post_indexed)
+        index = 13;
+      else
+        index = 15;
+    } else {
+      index = _index->encoding();
+    }
+
+    return _base->encoding() << 16 | index;
+  }
+#endif // !AARCH64
+
+  Register base() const {
+    return _base;
+  }
+
+  Register index() const {
+    return _index;
+  }
+
+  int disp() const {
+    return _disp;
+  }
+
+  AsmOffset mode() const {
+    return _mode;
+  }
+
+  int shift_imm() const {
+    return _shift_imm;
+  }
+
+#ifdef AARCH64
+  AsmExtendOp extend() const {
+    return _extend;
+  }
+#else
+  AsmShift shift() const {
+    return _shift;
+  }
+
+  AsmOffsetOp offset_op() const {
+    return _offset_op;
+  }
+#endif
+
+  bool uses(Register reg) const { return _base == reg || _index == reg; }
+
+  const relocInfo::relocType rtype() { return _rspec.type(); }
+  const RelocationHolder&    rspec() { return _rspec; }
+
+  // Convert the raw encoding form into the form expected by the
+  // constructor for Address.
+  static Address make_raw(int base, int index, int scale, int disp, relocInfo::relocType disp_reloc);
+};
+
+#ifdef COMPILER2
+class VFP VALUE_OBJ_CLASS_SPEC {
+  // Helper classes to detect whether a floating point constant can be
+  // encoded in a fconstd or fconsts instruction
+  // The conversion from the imm8, 8 bit constant, to the floating
+  // point value encoding is done with either:
+  // for single precision: imm8<7>:NOT(imm8<6>):Replicate(imm8<6>,5):imm8<5:0>:Zeros(19)
+  // or
+  // for double precision: imm8<7>:NOT(imm8<6>):Replicate(imm8<6>,8):imm8<5:0>:Zeros(48)
+
+ private:
+  class fpnum {
+   public:
+    virtual unsigned int f_hi4() const = 0;
+    virtual bool f_lo_is_null() const = 0;
+    virtual int e() const = 0;
+    virtual unsigned int s() const = 0;
+
+    inline bool can_be_imm8() const { return e() >= -3 && e() <= 4 && f_lo_is_null(); }
+    inline unsigned char imm8() const { int v = (s() << 7) | (((e() - 1) & 0x7) << 4) | f_hi4(); assert((v >> 8) == 0, "overflow"); return v; }
+  };
+
+ public:
+  class float_num : public fpnum {
+   public:
+    float_num(float v) {
+      _num.val = v;
+    }
+
+    virtual unsigned int f_hi4() const { return (_num.bits << 9) >> (19+9); }
+    virtual bool f_lo_is_null() const { return (_num.bits & ((1 << 19) - 1)) == 0; }
+    virtual int e() const { return ((_num.bits << 1) >> (23+1)) - 127; }
+    virtual unsigned int s() const { return _num.bits >> 31; }
+
+   private:
+    union {
+      float val;
+      unsigned int bits;
+    } _num;
+  };
+
+  class double_num : public fpnum {
+   public:
+    double_num(double v) {
+      _num.val = v;
+    }
+
+    virtual unsigned int f_hi4() const { return (_num.bits << 12) >> (48+12); }
+    virtual bool f_lo_is_null() const { return (_num.bits & ((1LL << 48) - 1)) == 0; }
+    virtual int e() const { return ((_num.bits << 1) >> (52+1)) - 1023; }
+    virtual unsigned int s() const { return _num.bits >> 63; }
+
+   private:
+    union {
+      double val;
+      unsigned long long bits;
+    } _num;
+  };
+};
+#endif
+
+#ifdef AARCH64
+#include "assembler_arm_64.hpp"
+#else
+#include "assembler_arm_32.hpp"
+#endif
+
+
+#endif // CPU_ARM_VM_ASSEMBLER_ARM_HPP