Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/Java/Openjdk/src/hotspot/cpu/aarch64/   (Sun/Oracle ©)  Datei vom 10.0.2023 mit Größe 150 kB image not shown  

SSL assembler_aarch64.hpp   Sprache: C

 
/*
 * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
 * Copyright (c) 2014, 2021, Red Hat Inc. 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_AARCH64_ASSEMBLER_AARCH64_HPP
#define CPU_AARCH64_ASSEMBLER_AARCH64_HPP

#include "asm/register.hpp"
#include "metaprogramming/enableIf.hpp"
#include "utilities/debug.hpp"
#include "utilities/globalDefinitions.hpp"
#include "utilities/macros.hpp"
#include <type_traits>

#ifdef __GNUC__

// __nop needs volatile so that compiler doesn't optimize it away
#define NOP() asm volatile ("nop");

#elif defined(_MSC_VER)

// Use MSVC intrinsic: https://docs.microsoft.com/en-us/cpp/intrinsics/arm64-intrinsics?view=vs-2019#I
#define NOP() __nop();

#endif


// definitions of various symbolic names for machine registers

// First intercalls between C and Java which use 8 general registers
// and 8 floating registers

// we also have to copy between x86 and ARM registers but that's a
// secondary complication -- not all code employing C call convention
// executes as x86 code though -- we generate some of it

class Argument {
 public:
  enum {
    n_int_register_parameters_c   = 8,  // r0, r1, ... r7 (c_rarg0, c_rarg1, ...)
    n_float_register_parameters_c = 8,  // v0, v1, ... v7 (c_farg0, c_farg1, ... )

    n_int_register_parameters_j   = 8, // r1, ... r7, r0 (rj_rarg0, j_rarg1, ...
    n_float_register_parameters_j = 8  // v0, v1, ... v7 (j_farg0, j_farg1, ...
  };
};

constexpr Register c_rarg0 = r0;
constexpr Register c_rarg1 = r1;
constexpr Register c_rarg2 = r2;
constexpr Register c_rarg3 = r3;
constexpr Register c_rarg4 = r4;
constexpr Register c_rarg5 = r5;
constexpr Register c_rarg6 = r6;
constexpr Register c_rarg7 = r7;

constexpr FloatRegister c_farg0 = v0;
constexpr FloatRegister c_farg1 = v1;
constexpr FloatRegister c_farg2 = v2;
constexpr FloatRegister c_farg3 = v3;
constexpr FloatRegister c_farg4 = v4;
constexpr FloatRegister c_farg5 = v5;
constexpr FloatRegister c_farg6 = v6;
constexpr FloatRegister c_farg7 = v7;

// Symbolically name the register arguments used by the Java calling convention.
// We have control over the convention for java so we can do what we please.
// What pleases us is to offset the java calling convention so that when
// we call a suitable jni method the arguments are lined up and we don't
// have to do much shuffling. A suitable jni method is non-static and a
// small number of arguments
//
//  |--------------------------------------------------------------------|
//  | c_rarg0  c_rarg1  c_rarg2 c_rarg3 c_rarg4 c_rarg5 c_rarg6 c_rarg7  |
//  |--------------------------------------------------------------------|
//  | r0       r1       r2      r3      r4      r5      r6      r7       |
//  |--------------------------------------------------------------------|
//  | j_rarg7  j_rarg0  j_rarg1 j_rarg2 j_rarg3 j_rarg4 j_rarg5 j_rarg6  |
//  |--------------------------------------------------------------------|


constexpr Register j_rarg0 = c_rarg1;
constexpr Register j_rarg1 = c_rarg2;
constexpr Register j_rarg2 = c_rarg3;
constexpr Register j_rarg3 = c_rarg4;
constexpr Register j_rarg4 = c_rarg5;
constexpr Register j_rarg5 = c_rarg6;
constexpr Register j_rarg6 = c_rarg7;
constexpr Register j_rarg7 = c_rarg0;

// Java floating args are passed as per C

constexpr FloatRegister j_farg0 = v0;
constexpr FloatRegister j_farg1 = v1;
constexpr FloatRegister j_farg2 = v2;
constexpr FloatRegister j_farg3 = v3;
constexpr FloatRegister j_farg4 = v4;
constexpr FloatRegister j_farg5 = v5;
constexpr FloatRegister j_farg6 = v6;
constexpr FloatRegister j_farg7 = v7;

// registers used to hold VM data either temporarily within a method
// or across method calls

// volatile (caller-save) registers

// r8 is used for indirect result location return
// we use it and r9 as scratch registers
constexpr Register rscratch1 = r8;
constexpr Register rscratch2 = r9;

// current method -- must be in a call-clobbered register
constexpr Register rmethod = r12;

// non-volatile (callee-save) registers are r16-29
// of which the following are dedicated global state

constexpr Register lr            = r30; // link register
constexpr Register rfp           = r29; // frame pointer
constexpr Register rthread       = r28; // current thread
constexpr Register rheapbase     = r27; // base of heap
constexpr Register rcpool        = r26; // constant pool cache
constexpr Register rlocals       = r24; // locals on stack
constexpr Register rbcp          = r22; // bytecode pointer
constexpr Register rdispatch     = r21; // dispatch table base
constexpr Register esp           = r20; // Java expression stack pointer
constexpr Register r19_sender_sp = r19; // sender's SP while in interpreter

// Preserved predicate register with all elements set TRUE.
constexpr PRegister ptrue = p7;

#define assert_cond(ARG1) assert(ARG1, #ARG1)

namespace asm_util {
  uint32_t encode_logical_immediate(bool is32, uint64_t imm);
  uint32_t encode_sve_logical_immediate(unsigned elembits, uint64_t imm);
  bool operand_valid_for_immediate_bits(int64_t imm, unsigned nbits);
};

using namespace asm_util;


class Assembler;

class Instruction_aarch64 {
  unsigned insn;
#ifdef ASSERT
  unsigned bits;
#endif
  Assembler *assem;

public:

  Instruction_aarch64(class Assembler *as) {
#ifdef ASSERT
    bits = 0;
#endif
    insn = 0;
    assem = as;
  }

  inline ~Instruction_aarch64();

  unsigned &get_insn() { return insn; }
#ifdef ASSERT
  unsigned &get_bits() { return bits; }
#endif

  static inline int32_t extend(unsigned val, int hi = 31, int lo = 0) {
    union {
      unsigned u;
      int n;
    };

    u = val << (31 - hi);
    n = n >> (31 - hi + lo);
    return n;
  }

  static inline uint32_t extract(uint32_t val, int msb, int lsb) {
    int nbits = msb - lsb + 1;
    assert_cond(msb >= lsb);
    uint32_t mask = checked_cast<uint32_t>(right_n_bits(nbits));
    uint32_t result = val >> lsb;
    result &= mask;
    return result;
  }

  static inline int32_t sextract(uint32_t val, int msb, int lsb) {
    uint32_t uval = extract(val, msb, lsb);
    return extend(uval, msb - lsb);
  }

  static ALWAYSINLINE void patch(address a, int msb, int lsb, uint64_t val) {
    int nbits = msb - lsb + 1;
    guarantee(val < (1ULL << nbits), "Field too big for insn");
    assert_cond(msb >= lsb);
    unsigned mask = checked_cast<unsigned>(right_n_bits(nbits));
    val <<= lsb;
    mask <<= lsb;
    unsigned target = *(unsigned *)a;
    target &= ~mask;
    target |= val;
    *(unsigned *)a = target;
  }

  static void spatch(address a, int msb, int lsb, int64_t val) {
    int nbits = msb - lsb + 1;
    int64_t chk = val >> (nbits - 1);
    guarantee (chk == -1 || chk == 0, "Field too big for insn");
    unsigned uval = val;
    unsigned mask = checked_cast<unsigned>(right_n_bits(nbits));
    uval &= mask;
    uval <<= lsb;
    mask <<= lsb;
    unsigned target = *(unsigned *)a;
    target &= ~mask;
    target |= uval;
    *(unsigned *)a = target;
  }

  void f(unsigned val, int msb, int lsb) {
    int nbits = msb - lsb + 1;
    guarantee(val < (1ULL << nbits), "Field too big for insn");
    assert_cond(msb >= lsb);
    val <<= lsb;
    insn |= val;
#ifdef ASSERT
    unsigned mask = checked_cast<unsigned>(right_n_bits(nbits));
    mask <<= lsb;
    assert_cond((bits & mask) == 0);
    bits |= mask;
#endif
  }

  void f(unsigned val, int bit) {
    f(val, bit, bit);
  }

  void sf(int64_t val, int msb, int lsb) {
    int nbits = msb - lsb + 1;
    int64_t chk = val >> (nbits - 1);
    guarantee (chk == -1 || chk == 0, "Field too big for insn");
    unsigned uval = val;
    unsigned mask = checked_cast<unsigned>(right_n_bits(nbits));
    uval &= mask;
    f(uval, lsb + nbits - 1, lsb);
  }

  void rf(Register r, int lsb) {
    f(r->raw_encoding(), lsb + 4, lsb);
  }

  // reg|ZR
  void zrf(Register r, int lsb) {
    f(r->raw_encoding() - (r == zr), lsb + 4, lsb);
  }

  // reg|SP
  void srf(Register r, int lsb) {
    f(r == sp ? 31 : r->raw_encoding(), lsb + 4, lsb);
  }

  void rf(FloatRegister r, int lsb) {
    f(r->raw_encoding(), lsb + 4, lsb);
  }

  void prf(PRegister r, int lsb) {
    f(r->raw_encoding(), lsb + 3, lsb);
  }

  void pgrf(PRegister r, int lsb) {
    f(r->raw_encoding(), lsb + 2, lsb);
  }

  unsigned get(int msb = 31, int lsb = 0) {
    int nbits = msb - lsb + 1;
    unsigned mask = checked_cast<unsigned>(right_n_bits(nbits)) << lsb;
    assert_cond((bits & mask) == mask);
    return (insn & mask) >> lsb;
  }
};

#define starti Instruction_aarch64 current_insn(this);

class PrePost {
  int _offset;
  Register _r;
protected:
  PrePost(Register reg, int o) : _offset(o), _r(reg) { }
  ~PrePost() = default;
  PrePost(const PrePost&) = default;
  PrePost& operator=(const PrePost&) = default;
public:
  int offset() const { return _offset; }
  Register reg() const { return _r; }
};

class Pre : public PrePost {
public:
  Pre(Register reg, int o) : PrePost(reg, o) { }
};

class Post : public PrePost {
  Register _idx;
  bool _is_postreg;
public:
  Post(Register reg, int o) : PrePost(reg, o), _idx(noreg), _is_postreg(false) {}
  Post(Register reg, Register idx) : PrePost(reg, 0), _idx(idx), _is_postreg(true) {}
  Register idx_reg() const { return _idx; }
  bool is_postreg() const { return _is_postreg; }
};

namespace ext
{
  enum operation { uxtb, uxth, uxtw, uxtx, sxtb, sxth, sxtw, sxtx };
};

// Addressing modes
class Address {
 public:

  enum mode { no_mode, base_plus_offset, pre, post, post_reg,
              base_plus_offset_reg, literal };

  // Shift and extend for base reg + reg offset addressing
  class extend {
    int _option, _shift;
    ext::operation _op;
  public:
    extend() { }
    extend(int s, int o, ext::operation op) : _option(o), _shift(s), _op(op) { }
    int option() constreturn _option; }
    int shift() const { return _shift; }
    ext::operation op() const { return _op; }
  };

  static extend uxtw(int shift = -1) { return extend(shift, 0b010, ext::uxtw); }
  static extend lsl(int shift = -1)  { return extend(shift, 0b011, ext::uxtx); }
  static extend sxtw(int shift = -1) { return extend(shift, 0b110, ext::sxtw); }
  static extend sxtx(int shift = -1) { return extend(shift, 0b111, ext::sxtx); }

 private:
  struct Nonliteral {
    Nonliteral(Register base, Register index, int64_t offset, extend ext = extend())
      : _base(base), _index(index), _offset(offset), _ext(ext) {}
    Register _base;
    Register _index;
    int64_t _offset;
    extend _ext;
  };

  struct Literal {
    Literal(address target, const RelocationHolder& rspec)
      : _target(target), _rspec(rspec) {}

    // If the target is far we'll need to load the ea of this to a
    // register to reach it. Otherwise if near we can do PC-relative
    // addressing.
    address _target;

    RelocationHolder _rspec;
  };

  void assert_is_nonliteral() const NOT_DEBUG_RETURN;
  void assert_is_literal() const NOT_DEBUG_RETURN;

  // Discriminated union, based on _mode.
  // - no_mode: uses dummy _nonliteral, for ease of copying.
  // - literal: only _literal is used.
  // - others: only _nonliteral is used.
  enum mode _mode;
  union {
    Nonliteral _nonliteral;
    Literal _literal;
  };

  // Helper for copy constructor and assignment operator.
  // Copy mode-relevant part of a into this.
  void copy_data(const Address& a) {
    assert(_mode == a._mode, "precondition");
    if (_mode == literal) {
      new (&_literal) Literal(a._literal);
    } else {
      // non-literal mode or no_mode.
      new (&_nonliteral) Nonliteral(a._nonliteral);
    }
  }

 public:
  // no_mode initializes _nonliteral for ease of copying.
  Address() :
    _mode(no_mode),
    _nonliteral(noreg, noreg, 0)
  {}

  Address(Register r) :
    _mode(base_plus_offset),
    _nonliteral(r, noreg, 0)
  {}

  template<typename T, ENABLE_IF(std::is_integral<T>::value)>
  Address(Register r, T o) :
    _mode(base_plus_offset),
    _nonliteral(r, noreg, o)
  {}

  Address(Register r, ByteSize disp) : Address(r, in_bytes(disp)) {}

  Address(Register r, Register r1, extend ext = lsl()) :
    _mode(base_plus_offset_reg),
    _nonliteral(r, r1, 0, ext)
  {}

  Address(Pre p) :
    _mode(pre),
    _nonliteral(p.reg(), noreg, p.offset())
  {}

  Address(Post p) :
    _mode(p.is_postreg() ? post_reg : post),
    _nonliteral(p.reg(), p.idx_reg(), p.offset())
  {}

  Address(address target, const RelocationHolder& rspec) :
    _mode(literal),
    _literal(target, rspec)
  {}

  Address(address target, relocInfo::relocType rtype = relocInfo::external_word_type);

  Address(Register base, RegisterOrConstant index, extend ext = lsl()) {
    if (index.is_register()) {
      _mode = base_plus_offset_reg;
      new (&_nonliteral) Nonliteral(base, index.as_register(), 0, ext);
    } else {
      guarantee(ext.option() == ext::uxtx, "should be");
      assert(index.is_constant(), "should be");
      _mode = base_plus_offset;
      new (&_nonliteral) Nonliteral(base,
                                    noreg,
                                    index.as_constant() << ext.shift());
    }
  }

  Address(const Address& a) : _mode(a._mode) { copy_data(a); }

  // Verify the value is trivially destructible regardless of mode, so our
  // destructor can also be trivial, and so our assignment operator doesn't
  // need to destruct the old value before copying over it.
  static_assert(std::is_trivially_destructible<Literal>::value, "must be");
  static_assert(std::is_trivially_destructible<Nonliteral>::value, "must be");

  Address& operator=(const Address& a) {
    _mode = a._mode;
    copy_data(a);
    return *this;
  }

  ~Address() = default;

  Register base() const {
    assert_is_nonliteral();
    return _nonliteral._base;
  }

  int64_t offset() const {
    assert_is_nonliteral();
    return _nonliteral._offset;
  }

  Register index() const {
    assert_is_nonliteral();
    return _nonliteral._index;
  }

  extend ext() const {
    assert_is_nonliteral();
    return _nonliteral._ext;
  }

  mode getMode() const {
    return _mode;
  }

  bool uses(Register reg) const {
    switch (_mode) {
    case literal:
    case no_mode:
      return false;
    case base_plus_offset:
    case base_plus_offset_reg:
    case pre:
    case post:
    case post_reg:
      return base() == reg || index() == reg;
    default:
      ShouldNotReachHere();
      return false;
    }
  }

  address target() const {
    assert_is_literal();
    return _literal._target;
  }

  const RelocationHolder& rspec() const {
    assert_is_literal();
    return _literal._rspec;
  }

  void encode(Instruction_aarch64 *i) const {
    i->f(0b111, 29, 27);
    i->srf(base(), 5);

    switch(_mode) {
    case base_plus_offset:
      {
        unsigned size = i->get(31, 30);
        if (i->get(26, 26) && i->get(23, 23)) {
          // SIMD Q Type - Size = 128 bits
          assert(size == 0, "bad size");
          size = 0b100;
        }
        assert(offset_ok_for_immed(offset(), size),
               "must be, was: " INT64_FORMAT ", %d", offset(), size);
        unsigned mask = (1 << size) - 1;
        if (offset() < 0 || offset() & mask) {
          i->f(0b00, 25, 24);
          i->f(0, 21), i->f(0b00, 11, 10);
          i->sf(offset(), 20, 12);
        } else {
          i->f(0b01, 25, 24);
          i->f(offset() >> size, 21, 10);
        }
      }
      break;

    case base_plus_offset_reg:
      {
        i->f(0b00, 25, 24);
        i->f(1, 21);
        i->rf(index(), 16);
        i->f(ext().option(), 15, 13);
        unsigned size = i->get(31, 30);
        if (i->get(26, 26) && i->get(23, 23)) {
          // SIMD Q Type - Size = 128 bits
          assert(size == 0, "bad size");
          size = 0b100;
        }
        if (size == 0) // It's a byte
          i->f(ext().shift() >= 0, 12);
        else {
          assert(ext().shift() <= 0 || ext().shift() == (int)size, "bad shift");
          i->f(ext().shift() > 0, 12);
        }
        i->f(0b10, 11, 10);
      }
      break;

    case pre:
      i->f(0b00, 25, 24);
      i->f(0, 21), i->f(0b11, 11, 10);
      i->sf(offset(), 20, 12);
      break;

    case post:
      i->f(0b00, 25, 24);
      i->f(0, 21), i->f(0b01, 11, 10);
      i->sf(offset(), 20, 12);
      break;

    default:
      ShouldNotReachHere();
    }
  }

  void encode_pair(Instruction_aarch64 *i) const {
    switch(_mode) {
    case base_plus_offset:
      i->f(0b010, 25, 23);
      break;
    case pre:
      i->f(0b011, 25, 23);
      break;
    case post:
      i->f(0b001, 25, 23);
      break;
    default:
      ShouldNotReachHere();
    }

    unsigned size; // Operand shift in 32-bit words

    if (i->get(26, 26)) { // float
      switch(i->get(31, 30)) {
      case 0b10:
        size = 2; break;
      case 0b01:
        size = 1; break;
      case 0b00:
        size = 0; break;
      default:
        ShouldNotReachHere();
        size = 0;  // unreachable
      }
    } else {
      size = i->get(31, 31);
    }

    size = 4 << size;
    guarantee(offset() % size == 0, "bad offset");
    i->sf(offset() / size, 21, 15);
    i->srf(base(), 5);
  }

  void encode_nontemporal_pair(Instruction_aarch64 *i) const {
    guarantee(_mode == base_plus_offset, "Bad addressing mode for nontemporal op");
    i->f(0b000, 25, 23);
    unsigned size = i->get(31, 31);
    size = 4 << size;
    guarantee(offset() % size == 0, "bad offset");
    i->sf(offset() / size, 21, 15);
    i->srf(base(), 5);
  }

  void lea(MacroAssembler *, Registerconst;

  static bool offset_ok_for_immed(int64_t offset, uint shift);

  static bool offset_ok_for_sve_immed(int64_t offset, int shift, int vl /* sve vector length */) {
    if (offset % vl == 0) {
      // Convert address offset into sve imm offset (MUL VL).
      int sve_offset = offset / vl;
      if (((-(1 << (shift - 1))) <= sve_offset) && (sve_offset < (1 << (shift - 1)))) {
        // sve_offset can be encoded
        return true;
      }
    }
    return false;
  }
};

// Convenience classes
class RuntimeAddress: public Address {

  public:

  RuntimeAddress(address target) : Address(target, relocInfo::runtime_call_type) {}

};

class OopAddress: public Address {

  public:

  OopAddress(address target) : Address(target, relocInfo::oop_type){}

};

class ExternalAddress: public Address {
 private:
  static relocInfo::relocType reloc_for_target(address target) {
    // Sometimes ExternalAddress is used for values which aren't
    // exactly addresses, like the card table base.
    // external_word_type can't be used for values in the first page
    // so just skip the reloc in that case.
    return external_word_Relocation::can_be_relocated(target) ? relocInfo::external_word_type : relocInfo::none;
  }

 public:

  ExternalAddress(address target) : Address(target, reloc_for_target(target)) {}

};

class InternalAddress: public Address {

  public:

  InternalAddress(address target) : Address(target, relocInfo::internal_word_type) {}
};

const int FPUStateSizeInWords = FloatRegister::number_of_registers * FloatRegister::save_slots_per_register;

typedef enum {
  PLDL1KEEP = 0b00000, PLDL1STRM, PLDL2KEEP, PLDL2STRM, PLDL3KEEP, PLDL3STRM,
  PSTL1KEEP = 0b10000, PSTL1STRM, PSTL2KEEP, PSTL2STRM, PSTL3KEEP, PSTL3STRM,
  PLIL1KEEP = 0b01000, PLIL1STRM, PLIL2KEEP, PLIL2STRM, PLIL3KEEP, PLIL3STRM
} prfop;

class Assembler : public AbstractAssembler {

public:

#ifndef PRODUCT
  static const uintptr_t asm_bp;

  void emit_int32(jint x) {
    if ((uintptr_t)pc() == asm_bp)
      NOP();
    AbstractAssembler::emit_int32(x);
  }
#else
  void emit_int32(jint x) {
    AbstractAssembler::emit_int32(x);
  }
#endif

  enum { instruction_size = 4 };

  //---<  calculate length of instruction  >---
  // We just use the values set above.
  // instruction must start at passed address
  static unsigned int instr_len(unsigned char *instr) { return instruction_size; }

  //---<  longest instructions  >---
  static unsigned int instr_maxlen() { return instruction_size; }

  Address adjust(Register base, int offset, bool preIncrement) {
    if (preIncrement)
      return Address(Pre(base, offset));
    else
      return Address(Post(base, offset));
  }

  Address pre(Register base, int offset) {
    return adjust(base, offset, true);
  }

  Address post(Register base, int offset) {
    return adjust(base, offset, false);
  }

  Address post(Register base, Register idx) {
    return Address(Post(base, idx));
  }

  static address locate_next_instruction(address inst);

#define f current_insn.f
#define sf current_insn.sf
#define rf current_insn.rf
#define srf current_insn.srf
#define zrf current_insn.zrf
#define prf current_insn.prf
#define pgrf current_insn.pgrf

  typedef void (Assembler::* uncond_branch_insn)(address dest);
  typedef void (Assembler::* compare_and_branch_insn)(Register Rt, address dest);
  typedef void (Assembler::* test_and_branch_insn)(Register Rt, int bitpos, address dest);
  typedef void (Assembler::* prefetch_insn)(address target, prfop);

  void wrap_label(Label &L, uncond_branch_insn insn);
  void wrap_label(Register r, Label &L, compare_and_branch_insn insn);
  void wrap_label(Register r, int bitpos, Label &L, test_and_branch_insn insn);
  void wrap_label(Label &L, prfop, prefetch_insn insn);

  // PC-rel. addressing

  void adr(Register Rd, address dest);
  void _adrp(Register Rd, address dest);

  void adr(Register Rd, const Address &dest);
  void _adrp(Register Rd, const Address &dest);

  void adr(Register Rd, Label &L) {
    wrap_label(Rd, L, &Assembler::Assembler::adr);
  }
  void _adrp(Register Rd, Label &L) {
    wrap_label(Rd, L, &Assembler::_adrp);
  }

  void adrp(Register Rd, const Address &dest, uint64_t &offset) = delete;

#undef INSN

  void add_sub_immediate(Instruction_aarch64 ¤t_insn, Register Rd, Register Rn,
                         unsigned uimm, int op, int negated_op);

  // Add/subtract (immediate)
#define INSN(NAME, decode, negated)                                     \
  void NAME(Register Rd, Register Rn, unsigned imm, unsigned shift) {   \
    starti;                                                             \
    f(decode, 31, 29), f(0b10001, 28, 24), f(shift, 23, 22), f(imm, 21, 10); \
    zrf(Rd, 0), srf(Rn, 5);                                             \
  }                                                                     \
                                                                        \
  void NAME(Register Rd, Register Rn, unsigned imm) {                   \
    starti;                                                             \
    add_sub_immediate(current_insn, Rd, Rn, imm, decode, negated);      \
  }

  INSN(addsw, 0b001, 0b011);
  INSN(subsw, 0b011, 0b001);
  INSN(adds,  0b101, 0b111);
  INSN(subs,  0b111, 0b101);

#undef INSN

#define INSN(NAME, decode, negated)                     \
  void NAME(Register Rd, Register Rn, unsigned imm) {   \
    starti;                                             \
    add_sub_immediate(current_insn, Rd, Rn, imm, decode, negated);     \
  }

  INSN(addw, 0b000, 0b010);
  INSN(subw, 0b010, 0b000);
  INSN(add,  0b100, 0b110);
  INSN(sub,  0b110, 0b100);

#undef INSN

 // Logical (immediate)
#define INSN(NAME, decode, is32)                                \
  void NAME(Register Rd, Register Rn, uint64_t imm) {           \
    starti;                                                     \
    uint32_t val = encode_logical_immediate(is32, imm);         \
    f(decode, 31, 29), f(0b100100, 28, 23), f(val, 22, 10);     \
    srf(Rd, 0), zrf(Rn, 5);                                     \
  }

  INSN(andw, 0b000, true);
  INSN(orrw, 0b001, true);
  INSN(eorw, 0b010, true);
  INSN(andr, 0b100, false);
  INSN(orr,  0b101, false);
  INSN(eor,  0b110, false);

#undef INSN

#define INSN(NAME, decode, is32)                                \
  void NAME(Register Rd, Register Rn, uint64_t imm) {           \
    starti;                                                     \
    uint32_t val = encode_logical_immediate(is32, imm);         \
    f(decode, 31, 29), f(0b100100, 28, 23), f(val, 22, 10);     \
    zrf(Rd, 0), zrf(Rn, 5);                                     \
  }

  INSN(ands, 0b111, false);
  INSN(andsw, 0b011, true);

#undef INSN

  // Move wide (immediate)
#define INSN(NAME, opcode)                                              \
  void NAME(Register Rd, unsigned imm, unsigned shift = 0) {            \
    assert_cond((shift/16)*16 == shift);                                \
    starti;                                                             \
    f(opcode, 31, 29), f(0b100101, 28, 23), f(shift/16, 22, 21),        \
      f(imm, 20, 5);                                                    \
    zrf(Rd, 0);                                                         \
  }

  INSN(movnw, 0b000);
  INSN(movzw, 0b010);
  INSN(movkw, 0b011);
  INSN(movn,  0b100);
  INSN(movz,  0b110);
  INSN(movk,  0b111);

#undef INSN

  // Bitfield
#define INSN(NAME, opcode, size)                                        \
  void NAME(Register Rd, Register Rn, unsigned immr, unsigned imms) {   \
    starti;                                                             \
    guarantee(size == 1 || (immr < 32 && imms < 32), "incorrect immr/imms");\
    f(opcode, 31, 22), f(immr, 21, 16), f(imms, 15, 10);                \
    zrf(Rn, 5), rf(Rd, 0);                                              \
  }

  INSN(sbfmw, 0b0001001100, 0);
  INSN(bfmw,  0b0011001100, 0);
  INSN(ubfmw, 0b0101001100, 0);
  INSN(sbfm,  0b1001001101, 1);
  INSN(bfm,   0b1011001101, 1);
  INSN(ubfm,  0b1101001101, 1);

#undef INSN

  // Extract
#define INSN(NAME, opcode, size)                                        \
  void NAME(Register Rd, Register Rn, Register Rm, unsigned imms) {     \
    starti;                                                             \
    guarantee(size == 1 || imms < 32, "incorrect imms");                \
    f(opcode, 31, 21), f(imms, 15, 10);                                 \
    zrf(Rm, 16), zrf(Rn, 5), zrf(Rd, 0);                                \
  }

  INSN(extrw, 0b00010011100, 0);
  INSN(extr,  0b10010011110, 1);

#undef INSN

  // The maximum range of a branch is fixed for the AArch64
  // architecture.  In debug mode we shrink it in order to test
  // trampolines, but not so small that branches in the interpreter
  // are out of range.
  static const uint64_t branch_range = NOT_DEBUG(128 * M) DEBUG_ONLY(2 * M);

  static bool reachable_from_branch_at(address branch, address target) {
    return uabs(target - branch) < branch_range;
  }

  // Unconditional branch (immediate)
#define INSN(NAME, opcode)                                              \
  void NAME(address dest) {                                             \
    starti;                                                             \
    int64_t offset = (dest - pc()) >> 2;                                \
    DEBUG_ONLY(assert(reachable_from_branch_at(pc(), dest), "debug only")); \
    f(opcode, 31), f(0b00101, 30, 26), sf(offset, 25, 0);               \
  }                                                                     \
  void NAME(Label &L) {                                                 \
    wrap_label(L, &Assembler::NAME);                                    \
  }                                                                     \
  void NAME(const Address &dest);

  INSN(b, 0);
  INSN(bl, 1);

#undef INSN

  // Compare & branch (immediate)
#define INSN(NAME, opcode)                              \
  void NAME(Register Rt, address dest) {                \
    int64_t offset = (dest - pc()) >> 2;                \
    starti;                                             \
    f(opcode, 31, 24), sf(offset, 23, 5), rf(Rt, 0);    \
  }                                                     \
  void NAME(Register Rt, Label &L) {                    \
    wrap_label(Rt, L, &Assembler::NAME);                \
  }

  INSN(cbzw,  0b00110100);
  INSN(cbnzw, 0b00110101);
  INSN(cbz,   0b10110100);
  INSN(cbnz,  0b10110101);

#undef INSN

  // Test & branch (immediate)
#define INSN(NAME, opcode)                                              \
  void NAME(Register Rt, int bitpos, address dest) {                    \
    int64_t offset = (dest - pc()) >> 2;                                \
    int b5 = bitpos >> 5;                                               \
    bitpos &= 0x1f;                                                     \
    starti;                                                             \
    f(b5, 31), f(opcode, 30, 24), f(bitpos, 23, 19), sf(offset, 18, 5); \
    rf(Rt, 0);                                                          \
  }                                                                     \
  void NAME(Register Rt, int bitpos, Label &L) {                        \
    wrap_label(Rt, bitpos, L, &Assembler::NAME);                        \
  }

  INSN(tbz,  0b0110110);
  INSN(tbnz, 0b0110111);

#undef INSN

  // Conditional branch (immediate)
  enum Condition
    {EQ, NE, HS, CS=HS, LO, CC=LO, MI, PL, VS, VC, HI, LS, GE, LT, GT, LE, AL, NV};

  void br(Condition  cond, address dest) {
    int64_t offset = (dest - pc()) >> 2;
    starti;
    f(0b0101010, 31, 25), f(0, 24), sf(offset, 23, 5), f(0, 4), f(cond, 3, 0);
  }

#define INSN(NAME, cond)                        \
  void NAME(address dest) {                     \
    br(cond, dest);                             \
  }

  INSN(beq, EQ);
  INSN(bne, NE);
  INSN(bhs, HS);
  INSN(bcs, CS);
  INSN(blo, LO);
  INSN(bcc, CC);
  INSN(bmi, MI);
  INSN(bpl, PL);
  INSN(bvs, VS);
  INSN(bvc, VC);
  INSN(bhi, HI);
  INSN(bls, LS);
  INSN(bge, GE);
  INSN(blt, LT);
  INSN(bgt, GT);
  INSN(ble, LE);
  INSN(bal, AL);
  INSN(bnv, NV);

  void br(Condition cc, Label &L);

#undef INSN

  // Exception generation
  void generate_exception(int opc, int op2, int LL, unsigned imm) {
    starti;
    f(0b11010100, 31, 24);
    f(opc, 23, 21), f(imm, 20, 5), f(op2, 4, 2), f(LL, 1, 0);
  }

#define INSN(NAME, opc, op2, LL)                \
  void NAME(unsigned imm) {                     \
    generate_exception(opc, op2, LL, imm);      \
  }

  INSN(svc, 0b000, 0, 0b01);
  INSN(hvc, 0b000, 0, 0b10);
  INSN(smc, 0b000, 0, 0b11);
  INSN(brk, 0b001, 0, 0b00);
  INSN(hlt, 0b010, 0, 0b00);
  INSN(dcps1, 0b101, 0, 0b01);
  INSN(dcps2, 0b101, 0, 0b10);
  INSN(dcps3, 0b101, 0, 0b11);

#undef INSN

  // System
  void system(int op0, int op1, int CRn, int CRm, int op2,
              Register rt = dummy_reg)
  {
    starti;
    f(0b11010101000, 31, 21);
    f(op0, 20, 19);
    f(op1, 18, 16);
    f(CRn, 15, 12);
    f(CRm, 11, 8);
    f(op2, 7, 5);
    rf(rt, 0);
  }

  // Hint instructions

#define INSN(NAME, crm, op2)               \
  void NAME() {                            \
    system(0b00, 0b011, 0b0010, crm, op2); \
  }

  INSN(nop,   0b000, 0b0000);
  INSN(yield, 0b000, 0b0001);
  INSN(wfe,   0b000, 0b0010);
  INSN(wfi,   0b000, 0b0011);
  INSN(sev,   0b000, 0b0100);
  INSN(sevl,  0b000, 0b0101);

  INSN(autia1716, 0b0001, 0b100);
  INSN(autiasp,   0b0011, 0b101);
  INSN(autiaz,    0b0011, 0b100);
  INSN(autib1716, 0b0001, 0b110);
  INSN(autibsp,   0b0011, 0b111);
  INSN(autibz,    0b0011, 0b110);
  INSN(pacia1716, 0b0001, 0b000);
  INSN(paciasp,   0b0011, 0b001);
  INSN(paciaz,    0b0011, 0b000);
  INSN(pacib1716, 0b0001, 0b010);
  INSN(pacibsp,   0b0011, 0b011);
  INSN(pacibz,    0b0011, 0b010);
  INSN(xpaclri,   0b0000, 0b111);

#undef INSN

  // we only provide mrs and msr for the special purpose system
  // registers where op1 (instr[20:19]) == 11 and, (currently) only
  // use it for FPSR n.b msr has L (instr[21]) == 0 mrs has L == 1

  void msr(int op1, int CRn, int CRm, int op2, Register rt) {
    starti;
    f(0b1101010100011, 31, 19);
    f(op1, 18, 16);
    f(CRn, 15, 12);
    f(CRm, 11, 8);
    f(op2, 7, 5);
    // writing zr is ok
    zrf(rt, 0);
  }

  void mrs(int op1, int CRn, int CRm, int op2, Register rt) {
    starti;
    f(0b1101010100111, 31, 19);
    f(op1, 18, 16);
    f(CRn, 15, 12);
    f(CRm, 11, 8);
    f(op2, 7, 5);
    // reading to zr is a mistake
    rf(rt, 0);
  }

  enum barrier {OSHLD = 0b0001, OSHST, OSH, NSHLD=0b0101, NSHST, NSH,
                ISHLD = 0b1001, ISHST, ISH, LD=0b1101, ST, SY};

  void dsb(barrier imm) {
    system(0b00, 0b011, 0b00011, imm, 0b100);
  }

  void dmb(barrier imm) {
    system(0b00, 0b011, 0b00011, imm, 0b101);
  }

  void isb() {
    system(0b00, 0b011, 0b00011, SY, 0b110);
  }

  void sys(int op1, int CRn, int CRm, int op2,
           Register rt = as_Register(0b11111)) {
    system(0b01, op1, CRn, CRm, op2, rt);
  }

  // Only implement operations accessible from EL0 or higher, i.e.,
  //            op1    CRn    CRm    op2
  // IC IVAU     3      7      5      1
  // DC CVAC     3      7      10     1
  // DC CVAP     3      7      12     1
  // DC CVAU     3      7      11     1
  // DC CIVAC    3      7      14     1
  // DC ZVA      3      7      4      1
  // So only deal with the CRm field.
  enum icache_maintenance {IVAU = 0b0101};
  enum dcache_maintenance {CVAC = 0b1010, CVAP = 0b1100, CVAU = 0b1011, CIVAC = 0b1110, ZVA = 0b100};

  void dc(dcache_maintenance cm, Register Rt) {
    sys(0b011, 0b0111, cm, 0b001, Rt);
  }

  void ic(icache_maintenance cm, Register Rt) {
    sys(0b011, 0b0111, cm, 0b001, Rt);
  }

  // A more convenient access to dmb for our purposes
  enum Membar_mask_bits {
    // We can use ISH for a barrier because the Arm ARM says "This
    // architecture assumes that all Processing Elements that use the
    // same operating system or hypervisor are in the same Inner
    // Shareable shareability domain."
    StoreStore = ISHST,
    LoadStore  = ISHLD,
    LoadLoad   = ISHLD,
    StoreLoad  = ISH,
    AnyAny     = ISH
  };

  void membar(Membar_mask_bits order_constraint) {
    dmb(Assembler::barrier(order_constraint));
  }

  // Unconditional branch (register)

  void branch_reg(int OP, int A, int M, Register RN, Register RM) {
    starti;
    f(0b1101011, 31, 25);
    f(OP, 24, 21);
    f(0b111110000, 20, 12);
    f(A, 11, 11);
    f(M, 10, 10);
    rf(RN, 5);
    rf(RM, 0);
  }

#define INSN(NAME, opc)                         \
  void NAME(Register RN) {                      \
    branch_reg(opc, 0, 0, RN, r0);              \
  }

  INSN(br,  0b0000);
  INSN(blr, 0b0001);
  INSN(ret, 0b0010);

  void ret(void *p); // This forces a compile-time error for ret(0)

#undef INSN

#define INSN(NAME, opc)                         \
  void NAME() {                                 \
    branch_reg(opc, 0, 0, dummy_reg, r0);       \
  }

  INSN(eret, 0b0100);
  INSN(drps, 0b0101);

#undef INSN

#define INSN(NAME, M)                                  \
  void NAME() {                                        \
    branch_reg(0b0010, 1, M, dummy_reg, dummy_reg);    \
  }

  INSN(retaa, 0);
  INSN(retab, 1);

#undef INSN

#define INSN(NAME, OP, M)                   \
  void NAME(Register rn) {                  \
    branch_reg(OP, 1, M, rn, dummy_reg);    \
  }

  INSN(braaz,  0b0000, 0);
  INSN(brabz,  0b0000, 1);
  INSN(blraaz, 0b0001, 0);
  INSN(blrabz, 0b0001, 1);

#undef INSN

#define INSN(NAME, OP, M)                  \
  void NAME(Register rn, Register rm) {    \
    branch_reg(OP, 1, M, rn, rm);          \
  }

  INSN(braa,  0b1000, 0);
  INSN(brab,  0b1000, 1);
  INSN(blraa, 0b1001, 0);
  INSN(blrab, 0b1001, 1);

#undef INSN

  // Load/store exclusive
  enum operand_size { byte, halfword, word, xword };

  void load_store_exclusive(Register Rs, Register Rt1, Register Rt2,
    Register Rn, enum operand_size sz, int op, bool ordered) {
    starti;
    f(sz, 31, 30), f(0b001000, 29, 24), f(op, 23, 21);
    rf(Rs, 16), f(ordered, 15), zrf(Rt2, 10), srf(Rn, 5), zrf(Rt1, 0);
  }

  void load_exclusive(Register dst, Register addr,
                      enum operand_size sz, bool ordered) {
    load_store_exclusive(dummy_reg, dst, dummy_reg, addr,
                         sz, 0b010, ordered);
  }

  void store_exclusive(Register status, Register new_val, Register addr,
                       enum operand_size sz, bool ordered) {
    load_store_exclusive(status, new_val, dummy_reg, addr,
                         sz, 0b000, ordered);
  }

#define INSN4(NAME, sz, op, o0) /* Four registers */                    \
  void NAME(Register Rs, Register Rt1, Register Rt2, Register Rn) {     \
    guarantee(Rs != Rn && Rs != Rt1 && Rs != Rt2, "unpredictable instruction"); \
    load_store_exclusive(Rs, Rt1, Rt2, Rn, sz, op, o0);                 \
  }

#define INSN3(NAME, sz, op, o0) /* Three registers */                   \
  void NAME(Register Rs, Register Rt, Register Rn) {                    \
    guarantee(Rs != Rn && Rs != Rt, "unpredictable instruction");       \
    load_store_exclusive(Rs, Rt, dummy_reg, Rn, sz, op, o0); \
  }

#define INSN2(NAME, sz, op, o0) /* Two registers */                     \
  void NAME(Register Rt, Register Rn) {                                 \
    load_store_exclusive(dummy_reg, Rt, dummy_reg, \
                         Rn, sz, op, o0);                               \
  }

#define INSN_FOO(NAME, sz, op, o0) /* Three registers, encoded differently */ \
  void NAME(Register Rt1, Register Rt2, Register Rn) {                  \
    guarantee(Rt1 != Rt2, "unpredictable instruction");                 \
    load_store_exclusive(dummy_reg, Rt1, Rt2, Rn, sz, op, o0);          \
  }

  // bytes
  INSN3(stxrb,  byte, 0b000, 0);
  INSN3(stlxrb, byte, 0b000, 1);
  INSN2(ldxrb,  byte, 0b010, 0);
  INSN2(ldaxrb, byte, 0b010, 1);
  INSN2(stlrb,  byte, 0b100, 1);
  INSN2(ldarb,  byte, 0b110, 1);

  // halfwords
  INSN3(stxrh,  halfword, 0b000, 0);
  INSN3(stlxrh, halfword, 0b000, 1);
  INSN2(ldxrh,  halfword, 0b010, 0);
  INSN2(ldaxrh, halfword, 0b010, 1);
  INSN2(stlrh,  halfword, 0b100, 1);
  INSN2(ldarh,  halfword, 0b110, 1);

  // words
  INSN3(stxrw,  word, 0b000, 0);
  INSN3(stlxrw, word, 0b000, 1);
  INSN4(stxpw,  word, 0b001, 0);
  INSN4(stlxpw, word, 0b001, 1);
  INSN2(ldxrw,  word, 0b010, 0);
  INSN2(ldaxrw, word, 0b010, 1);
  INSN2(stlrw,  word, 0b100, 1);
  INSN2(ldarw,  word, 0b110, 1);
  // pairs of words
  INSN_FOO(ldxpw,  word, 0b011, 0);
  INSN_FOO(ldaxpw, word, 0b011, 1);

  // xwords
  INSN3(stxr,  xword, 0b000, 0);
  INSN3(stlxr, xword, 0b000, 1);
  INSN4(stxp,  xword, 0b001, 0);
  INSN4(stlxp, xword, 0b001, 1);
  INSN2(ldxr,  xword, 0b010, 0);
  INSN2(ldaxr, xword, 0b010, 1);
  INSN2(stlr,  xword, 0b100, 1);
  INSN2(ldar,  xword, 0b110, 1);
  // pairs of xwords
  INSN_FOO(ldxp,  xword, 0b011, 0);
  INSN_FOO(ldaxp, xword, 0b011, 1);

#undef INSN2
#undef INSN3
#undef INSN4
#undef INSN_FOO

  // 8.1 Compare and swap extensions
  void lse_cas(Register Rs, Register Rt, Register Rn,
                        enum operand_size sz, bool a, bool r, bool not_pair) {
    starti;
    if (! not_pair) { // Pair
      assert(sz == word || sz == xword, "invalid size");
      /* The size bit is in bit 30, not 31 */
      sz = (operand_size)(sz == word ? 0b00:0b01);
    }
    f(sz, 31, 30), f(0b001000, 29, 24), f(not_pair ? 1 : 0, 23), f(a, 22), f(1, 21);
    zrf(Rs, 16), f(r, 15), f(0b11111, 14, 10), srf(Rn, 5), zrf(Rt, 0);
  }

  // CAS
#define INSN(NAME, a, r)                                                \
  void NAME(operand_size sz, Register Rs, Register Rt, Register Rn) {   \
    assert(Rs != Rn && Rs != Rt, "unpredictable instruction");          \
    lse_cas(Rs, Rt, Rn, sz, a, r, true);                                \
  }
  INSN(cas,   falsefalse)
  INSN(casa,  true,  false)
  INSN(casl,  falsetrue)
  INSN(casal, true,  true)
#undef INSN

  // CASP
#define INSN(NAME, a, r)                                                \
  void NAME(operand_size sz, Register Rs, Register Rs1,                 \
            Register Rt, Register Rt1, Register Rn) {                   \
    assert((Rs->encoding() & 1) == 0 && (Rt->encoding() & 1) == 0 &&    \
           Rs->successor() == Rs1 && Rt->successor() == Rt1 &&          \
           Rs != Rn && Rs1 != Rn && Rs != Rt, "invalid registers");     \
    lse_cas(Rs, Rt, Rn, sz, a, r, false);                               \
  }
  INSN(casp,   falsefalse)
  INSN(caspa,  true,  false)
  INSN(caspl,  falsetrue)
  INSN(caspal, true,  true)
#undef INSN

  // 8.1 Atomic operations
  void lse_atomic(Register Rs, Register Rt, Register Rn,
                  enum operand_size sz, int op1, int op2, bool a, bool r) {
    starti;
    f(sz, 31, 30), f(0b111000, 29, 24), f(a, 23), f(r, 22), f(1, 21);
    zrf(Rs, 16), f(op1, 15), f(op2, 14, 12), f(0, 11, 10), srf(Rn, 5), zrf(Rt, 0);
  }

#define INSN(NAME, NAME_A, NAME_L, NAME_AL, op1, op2)                   \
  void NAME(operand_size sz, Register Rs, Register Rt, Register Rn) {   \
    lse_atomic(Rs, Rt, Rn, sz, op1, op2, falsefalse);                 \
  }                                                                     \
  void NAME_A(operand_size sz, Register Rs, Register Rt, Register Rn) { \
    lse_atomic(Rs, Rt, Rn, sz, op1, op2, truefalse);                  \
  }                                                                     \
  void NAME_L(operand_size sz, Register Rs, Register Rt, Register Rn) { \
    lse_atomic(Rs, Rt, Rn, sz, op1, op2, falsetrue);                  \
  }                                                                     \
  void NAME_AL(operand_size sz, Register Rs, Register Rt, Register Rn) {\
    lse_atomic(Rs, Rt, Rn, sz, op1, op2, truetrue);                   \
  }
  INSN(ldadd,  ldadda,  ldaddl,  ldaddal,  0, 0b000);
  INSN(ldbic,  ldbica,  ldbicl,  ldbical,  0, 0b001);
  INSN(ldeor,  ldeora,  ldeorl,  ldeoral,  0, 0b010);
  INSN(ldorr,  ldorra,  ldorrl,  ldorral,  0, 0b011);
  INSN(ldsmax, ldsmaxa, ldsmaxl, ldsmaxal, 0, 0b100);
  INSN(ldsmin, ldsmina, ldsminl, ldsminal, 0, 0b101);
  INSN(ldumax, ldumaxa, ldumaxl, ldumaxal, 0, 0b110);
  INSN(ldumin, ldumina, lduminl, lduminal, 0, 0b111);
  INSN(swp,    swpa,    swpl,    swpal,    1, 0b000);
#undef INSN

  // Load register (literal)
#define INSN(NAME, opc, V)                                              \
  void NAME(Register Rt, address dest) {                                \
    int64_t offset = (dest - pc()) >> 2;                                \
    starti;                                                             \
    f(opc, 31, 30), f(0b011, 29, 27), f(V, 26), f(0b00, 25, 24),        \
      sf(offset, 23, 5);                                                \
    rf(Rt, 0);                                                          \
  }                                                                     \
  void NAME(Register Rt, address dest, relocInfo::relocType rtype) {    \
    InstructionMark im(this);                                           \
    guarantee(rtype == relocInfo::internal_word_type,                   \
              "only internal_word_type relocs make sense here");        \
    code_section()->relocate(inst_mark(), InternalAddress(dest).rspec()); \
    NAME(Rt, dest);                                                     \
  }                                                                     \
  void NAME(Register Rt, Label &L) {                                    \
    wrap_label(Rt, L, &Assembler::NAME);                                \
  }

  INSN(ldrw, 0b00, 0);
  INSN(ldr, 0b01, 0);
  INSN(ldrsw, 0b10, 0);

#undef INSN

#define INSN(NAME, opc, V)                                              \
  void NAME(FloatRegister Rt, address dest) {                           \
    int64_t offset = (dest - pc()) >> 2;                                \
    starti;                                                             \
    f(opc, 31, 30), f(0b011, 29, 27), f(V, 26), f(0b00, 25, 24),        \
      sf(offset, 23, 5);                                                \
    rf(as_Register(Rt), 0);                                             \
  }

  INSN(ldrs, 0b00, 1);
  INSN(ldrd, 0b01, 1);
  INSN(ldrq, 0b10, 1);

#undef INSN

#define INSN(NAME, size, opc)                                           \
  void NAME(FloatRegister Rt, Register Rn) {                            \
    starti;                                                             \
    f(size, 31, 30), f(0b111100, 29, 24), f(opc, 23, 22), f(0, 21);     \
    f(0, 20, 12), f(0b01, 11, 10);                                      \
    rf(Rn, 5), rf(as_Register(Rt), 0);                                  \
  }

  INSN(ldrs, 0b10, 0b01);
  INSN(ldrd, 0b11, 0b01);
  INSN(ldrq, 0b00, 0b11);

#undef INSN


#define INSN(NAME, opc, V)                                              \
  void NAME(address dest, prfop op = PLDL1KEEP) {                       \
    int64_t offset = (dest - pc()) >> 2;                                \
    starti;                                                             \
    f(opc, 31, 30), f(0b011, 29, 27), f(V, 26), f(0b00, 25, 24),        \
      sf(offset, 23, 5);                                                \
    f(op, 4, 0);                                                        \
  }                                                                     \
  void NAME(Label &L, prfop op = PLDL1KEEP) {                           \
    wrap_label(L, op, &Assembler::NAME);                                \
  }

  INSN(prfm, 0b11, 0);

#undef INSN

  // Load/store
  void ld_st1(int opc, int p1, int V, int L,
              Register Rt1, Register Rt2, Address adr, bool no_allocate) {
    starti;
    f(opc, 31, 30), f(p1, 29, 27), f(V, 26), f(L, 22);
    zrf(Rt2, 10), zrf(Rt1, 0);
    if (no_allocate) {
      adr.encode_nontemporal_pair(¤t_insn);
    } else {
      adr.encode_pair(¤t_insn);
    }
  }

  // Load/store register pair (offset)
#define INSN(NAME, size, p1, V, L, no_allocate)         \
  void NAME(Register Rt1, Register Rt2, Address adr) {  \
    ld_st1(size, p1, V, L, Rt1, Rt2, adr, no_allocate); \
   }

  INSN(stpw,  0b00, 0b101, 0, 0, false);
  INSN(ldpw,  0b00, 0b101, 0, 1, false);
  INSN(ldpsw, 0b01, 0b101, 0, 1, false);
  INSN(stp,   0b10, 0b101, 0, 0, false);
  INSN(ldp,   0b10, 0b101, 0, 1, false);

  // Load/store no-allocate pair (offset)
  INSN(stnpw, 0b00, 0b101, 0, 0, true);
  INSN(ldnpw, 0b00, 0b101, 0, 1, true);
  INSN(stnp,  0b10, 0b101, 0, 0, true);
  INSN(ldnp,  0b10, 0b101, 0, 1, true);

#undef INSN

#define INSN(NAME, size, p1, V, L, no_allocate)                         \
  void NAME(FloatRegister Rt1, FloatRegister Rt2, Address adr) {        \
    ld_st1(size, p1, V, L,                                              \
           as_Register(Rt1), as_Register(Rt2), adr, no_allocate);       \
   }

  INSN(stps, 0b00, 0b101, 1, 0, false);
  INSN(ldps, 0b00, 0b101, 1, 1, false);
  INSN(stpd, 0b01, 0b101, 1, 0, false);
  INSN(ldpd, 0b01, 0b101, 1, 1, false);
  INSN(stpq, 0b10, 0b101, 1, 0, false);
  INSN(ldpq, 0b10, 0b101, 1, 1, false);

#undef INSN

  // Load/store register (all modes)
  void ld_st2(Register Rt, const Address &adr, int size, int op, int V = 0) {
    starti;

    f(V, 26); // general reg?
    zrf(Rt, 0);

    // Encoding for literal loads is done here (rather than pushed
    // down into Address::encode) because the encoding of this
    // instruction is too different from all of the other forms to
    // make it worth sharing.
    if (adr.getMode() == Address::literal) {
      assert(size == 0b10 || size == 0b11, "bad operand size in ldr");
      assert(op == 0b01, "literal form can only be used with loads");
      f(size & 0b01, 31, 30), f(0b011, 29, 27), f(0b00, 25, 24);
      int64_t offset = (adr.target() - pc()) >> 2;
      sf(offset, 23, 5);
      code_section()->relocate(pc(), adr.rspec());
      return;
    }

    f(size, 31, 30);
    f(op, 23, 22); // str
    adr.encode(¤t_insn);
  }

#define INSN(NAME, size, op)                            \
  void NAME(Register Rt, const Address &adr) {          \
    ld_st2(Rt, adr, size, op);                          \
  }                                                     \

  INSN(str,  0b11, 0b00);
  INSN(strw, 0b10, 0b00);
  INSN(strb, 0b00, 0b00);
  INSN(strh, 0b01, 0b00);

  INSN(ldr,  0b11, 0b01);
  INSN(ldrw, 0b10, 0b01);
  INSN(ldrb, 0b00, 0b01);
  INSN(ldrh, 0b01, 0b01);

  INSN(ldrsb,  0b00, 0b10);
  INSN(ldrsbw, 0b00, 0b11);
  INSN(ldrsh,  0b01, 0b10);
  INSN(ldrshw, 0b01, 0b11);
  INSN(ldrsw,  0b10, 0b10);

#undef INSN

#define INSN(NAME, size, op)                                    \
  void NAME(const Address &adr, prfop pfop = PLDL1KEEP) {       \
    ld_st2(as_Register(pfop), adr, size, op);                   \
  }

  INSN(prfm, 0b11, 0b10); // FIXME: PRFM should not be used with
                          // writeback modes, but the assembler
                          // doesn't enfore that.

#undef INSN

#define INSN(NAME, size, op)                            \
  void NAME(FloatRegister Rt, const Address &adr) {     \
    ld_st2(as_Register(Rt), adr, size, op, 1);          \
  }

  INSN(strd, 0b11, 0b00);
  INSN(strs, 0b10, 0b00);
  INSN(ldrd, 0b11, 0b01);
  INSN(ldrs, 0b10, 0b01);
  INSN(strq, 0b00, 0b10);
  INSN(ldrq, 0x00, 0b11);

#undef INSN

/* SIMD extensions
 *
 * We just use FloatRegister in the following. They are exactly the same
 * as SIMD registers.
 */

public:

  enum SIMD_Arrangement {
    T8B, T16B, T4H, T8H, T2S, T4S, T1D, T2D, T1Q, INVALID_ARRANGEMENT
  };

  enum SIMD_RegVariant {
      B, H, S, D, Q, INVALID
  };

private:

  static SIMD_Arrangement _esize2arrangement_table[9][2];
  static SIMD_RegVariant _esize2regvariant[9];

public:

  static SIMD_Arrangement esize2arrangement(unsigned esize, bool isQ);
  static SIMD_RegVariant elemType_to_regVariant(BasicType bt);
  static SIMD_RegVariant elemBytes_to_regVariant(unsigned esize);
  // Return the corresponding bits for different SIMD_RegVariant value.
  static unsigned regVariant_to_elemBits(SIMD_RegVariant T);

  enum shift_kind { LSL, LSR, ASR, ROR };

  void op_shifted_reg(Instruction_aarch64 ¤t_insn, unsigned decode,
                      enum shift_kind kind, unsigned shift,
                      unsigned size, unsigned op) {
    f(size, 31);
    f(op, 30, 29);
    f(decode, 28, 24);
    f(shift, 15, 10);
    f(kind, 23, 22);
  }

  // Logical (shifted register)
#define INSN(NAME, size, op, N)                                         \
  void NAME(Register Rd, Register Rn, Register Rm,                      \
            enum shift_kind kind = LSL, unsigned shift = 0) {           \
    starti;                                                             \
    guarantee(size == 1 || shift < 32, "incorrect shift");              \
    f(N, 21);                                                           \
    zrf(Rm, 16), zrf(Rn, 5), zrf(Rd, 0);                                \
    op_shifted_reg(current_insn, 0b01010, kind, shift, size, op);       \
  }

  INSN(andr,  1, 0b00, 0);
  INSN(orr,   1, 0b01, 0);
  INSN(eor,   1, 0b10, 0);
  INSN(ands,  1, 0b11, 0);
  INSN(andw,  0, 0b00, 0);
  INSN(orrw,  0, 0b01, 0);
  INSN(eorw,  0, 0b10, 0);
  INSN(andsw, 0, 0b11, 0);

#undef INSN

#define INSN(NAME, size, op, N)                                         \
  void NAME(Register Rd, Register Rn, Register Rm,                      \
            enum shift_kind kind = LSL, unsigned shift = 0) {           \
    starti;                                                             \
    f(N, 21);                                                           \
    zrf(Rm, 16), zrf(Rn, 5), zrf(Rd, 0);                                \
    op_shifted_reg(current_insn, 0b01010, kind, shift, size, op);       \
  }                                                                     \
                                                                        \
  /* These instructions have no immediate form. Provide an overload so  \
     that if anyone does try to use an immediate operand -- this has    \
     happened! -- we'll get a compile-time error. */

  void NAME(Register Rd, Register Rn, unsigned imm,                     \
            enum shift_kind kind = LSL, unsigned shift = 0) {           \
    assert(false" can't be used with immediate operand");             \
  }

  INSN(bic,   1, 0b00, 1);
  INSN(orn,   1, 0b01, 1);
  INSN(eon,   1, 0b10, 1);
  INSN(bics,  1, 0b11, 1);
  INSN(bicw,  0, 0b00, 1);
  INSN(ornw,  0, 0b01, 1);
  INSN(eonw,  0, 0b10, 1);
  INSN(bicsw, 0, 0b11, 1);

#undef INSN

#ifdef _WIN64
// In MSVC, `mvn` is defined as a macro and it affects compilation
#undef mvn
#endif

  // Aliases for short forms of orn
void mvn(Register Rd, Register Rm,
            enum shift_kind kind = LSL, unsigned shift = 0) {
  orn(Rd, zr, Rm, kind, shift);
}

void mvnw(Register Rd, Register Rm,
            enum shift_kind kind = LSL, unsigned shift = 0) {
  ornw(Rd, zr, Rm, kind, shift);
}

  // Add/subtract (shifted register)
#define INSN(NAME, size, op)                            \
  void NAME(Register Rd, Register Rn, Register Rm,      \
            enum shift_kind kind, unsigned shift = 0) { \
    starti;                                             \
    f(0, 21);                                           \
    assert_cond(kind != ROR);                           \
    guarantee(size == 1 || shift < 32, "incorrect shift");\
    zrf(Rd, 0), zrf(Rn, 5), zrf(Rm, 16);                \
    op_shifted_reg(current_insn, 0b01011, kind, shift, size, op);      \
  }

  INSN(add,  1, 0b000);
  INSN(sub,  1, 0b10);
  INSN(addw, 0, 0b000);
  INSN(subw, 0, 0b10);

  INSN(adds,  1, 0b001);
  INSN(subs,  1, 0b11);
  INSN(addsw, 0, 0b001);
  INSN(subsw, 0, 0b11);

#undef INSN

  // Add/subtract (extended register)
#define INSN(NAME, op)                                                  \
  void NAME(Register Rd, Register Rn, Register Rm,                      \
           ext::operation option, int amount = 0) {                     \
    starti;                                                             \
    zrf(Rm, 16), srf(Rn, 5), srf(Rd, 0);                                \
    add_sub_extended_reg(current_insn, op, 0b01011, Rd, Rn, Rm, 0b00, option, amount); \
  }

  void add_sub_extended_reg(Instruction_aarch64 ¤t_insn, unsigned op, unsigned decode,
    Register Rd, Register Rn, Register Rm,
    unsigned opt, ext::operation option, unsigned imm) {
    guarantee(imm <= 4, "shift amount must be <= 4");
    f(op, 31, 29), f(decode, 28, 24), f(opt, 23, 22), f(1, 21);
    f(option, 15, 13), f(imm, 12, 10);
  }

  INSN(addw, 0b000);
  INSN(subw, 0b010);
  INSN(add,  0b100);
  INSN(sub,  0b110);

#undef INSN

#define INSN(NAME, op)                                                  \
  void NAME(Register Rd, Register Rn, Register Rm,                      \
           ext::operation option, int amount = 0) {                     \
    starti;                                                             \
    zrf(Rm, 16), srf(Rn, 5), zrf(Rd, 0);                                \
    add_sub_extended_reg(current_insn, op, 0b01011, Rd, Rn, Rm, 0b00, option, amount); \
  }

  INSN(addsw, 0b001);
  INSN(subsw, 0b011);
  INSN(adds,  0b101);
  INSN(subs,  0b111);

#undef INSN

  // Aliases for short forms of add and sub
#define INSN(NAME)                                      \
  void NAME(Register Rd, Register Rn, Register Rm) {    \
    if (Rd == sp || Rn == sp)                           \
      NAME(Rd, Rn, Rm, ext::uxtx);                      \
    else                                                \
      NAME(Rd, Rn, Rm, LSL);                            \
  }

  INSN(addw);
  INSN(subw);
  INSN(add);
  INSN(sub);

  INSN(addsw);
  INSN(subsw);
  INSN(adds);
  INSN(subs);

#undef INSN

  // Add/subtract (with carry)
  void add_sub_carry(unsigned op, Register Rd, Register Rn, Register Rm) {
    starti;
    f(op, 31, 29);
    f(0b11010000, 28, 21);
    f(0b000000, 15, 10);
    zrf(Rm, 16), zrf(Rn, 5), zrf(Rd, 0);
  }

  #define INSN(NAME, op)                                \
    void NAME(Register Rd, Register Rn, Register Rm) {  \
      add_sub_carry(op, Rd, Rn, Rm);                    \
    }

  INSN(adcw,  0b000);
  INSN(adcsw, 0b001);
  INSN(sbcw,  0b010);
  INSN(sbcsw, 0b011);
  INSN(adc,   0b100);
  INSN(adcs,  0b101);
  INSN(sbc,   0b110);
  INSN(sbcs,  0b111);

#undef INSN

  // Conditional compare (both kinds)
  void conditional_compare(unsigned op, int o1, int o2, int o3,
                           Register Rn, unsigned imm5, unsigned nzcv,
                           unsigned cond) {
    starti;
    f(op, 31, 29);
    f(0b11010010, 28, 21);
    f(cond, 15, 12);
    f(o1, 11);
    f(o2, 10);
    f(o3, 4);
    f(nzcv, 3, 0);
    f(imm5, 20, 16), zrf(Rn, 5);
  }

#define INSN(NAME, op)                                                  \
  void NAME(Register Rn, Register Rm, int imm, Condition cond) {        \
    int regNumber = (Rm == zr ? 31 : Rm->encoding());                   \
    conditional_compare(op, 0, 0, 0, Rn, regNumber, imm, cond);         \
  }                                                                     \
                                                                        \
  void NAME(Register Rn, int imm5, int imm, Condition cond) {           \
    conditional_compare(op, 1, 0, 0, Rn, imm5, imm, cond);              \
  }

  INSN(ccmnw, 0b001);
  INSN(ccmpw, 0b011);
  INSN(ccmn, 0b101);
  INSN(ccmp, 0b111);

#undef INSN

  // Conditional select
  void conditional_select(unsigned op, unsigned op2,
                          Register Rd, Register Rn, Register Rm,
                          unsigned cond) {
    starti;
    f(op, 31, 29);
    f(0b11010100, 28, 21);
    f(cond, 15, 12);
    f(op2, 11, 10);
    zrf(Rm, 16), zrf(Rn, 5), rf(Rd, 0);
  }

#define INSN(NAME, op, op2)                                             \
  void NAME(Register Rd, Register Rn, Register Rm, Condition cond) {    \
    conditional_select(op, op2, Rd, Rn, Rm, cond);                      \
  }

  INSN(cselw,  0b000, 0b00);
  INSN(csincw, 0b000, 0b01);
  INSN(csinvw, 0b010, 0b00);
  INSN(csnegw, 0b010, 0b01);
  INSN(csel,   0b100, 0b00);
  INSN(csinc,  0b100, 0b01);
  INSN(csinv,  0b110, 0b00);
  INSN(csneg,  0b110, 0b01);

#undef INSN

  // Data processing
  void data_processing(Instruction_aarch64 ¤t_insn, unsigned op29, unsigned opcode,
                       Register Rd, Register Rn) {
    f(op29, 31, 29), f(0b11010110, 28, 21);
    f(opcode, 15, 10);
    rf(Rn, 5), rf(Rd, 0);
  }

  // (1 source)
#define INSN(NAME, op29, opcode2, opcode)                       \
  void NAME(Register Rd, Register Rn) {                         \
    starti;                                                     \
    f(opcode2, 20, 16);                                         \
    data_processing(current_insn, op29, opcode, Rd, Rn);        \
  }

  INSN(rbitw,  0b010, 0b00000, 0b00000);
  INSN(rev16w, 0b010, 0b00000, 0b00001);
  INSN(revw,   0b010, 0b00000, 0b00010);
  INSN(clzw,   0b010, 0b00000, 0b00100);
  INSN(clsw,   0b010, 0b00000, 0b00101);

  INSN(rbit,   0b110, 0b00000, 0b00000);
  INSN(rev16,  0b110, 0b00000, 0b00001);
  INSN(rev32,  0b110, 0b00000, 0b00010);
  INSN(rev,    0b110, 0b00000, 0b00011);
  INSN(clz,    0b110, 0b00000, 0b00100);
  INSN(cls,    0b110, 0b00000, 0b00101);

  // PAC instructions
  INSN(pacia,  0b110, 0b00001, 0b00000);
  INSN(pacib,  0b110, 0b00001, 0b00001);
  INSN(pacda,  0b110, 0b00001, 0b00010);
  INSN(pacdb,  0b110, 0b00001, 0b00011);
  INSN(autia,  0b110, 0b00001, 0b00100);
  INSN(autib,  0b110, 0b00001, 0b00101);
  INSN(autda,  0b110, 0b00001, 0b00110);
  INSN(autdb,  0b110, 0b00001, 0b00111);

#undef INSN

#define INSN(NAME, op29, opcode2, opcode)                       \
  void NAME(Register Rd) {                                      \
    starti;                                                     \
    f(opcode2, 20, 16);                                         \
    data_processing(current_insn, op29, opcode, Rd, dummy_reg); \
  }

  // PAC instructions (with zero modifier)
  INSN(paciza,  0b110, 0b00001, 0b01000);
  INSN(pacizb,  0b110, 0b00001, 0b01001);
  INSN(pacdza,  0b110, 0b00001, 0b01010);
  INSN(pacdzb,  0b110, 0b00001, 0b01011);
  INSN(autiza,  0b110, 0b00001, 0b01100);
  INSN(autizb,  0b110, 0b00001, 0b01101);
  INSN(autdza,  0b110, 0b00001, 0b01110);
  INSN(autdzb,  0b110, 0b00001, 0b01111);
  INSN(xpaci,   0b110, 0b00001, 0b10000);
  INSN(xpacd,   0b110, 0b00001, 0b10001);

#undef INSN

  // Data-processing (2 source)
#define INSN(NAME, op29, opcode)                                \
  void NAME(Register Rd, Register Rn, Register Rm) {            \
    starti;                                                     \
    rf(Rm, 16);                                                 \
    data_processing(current_insn, op29, opcode, Rd, Rn);        \
  }

  INSN(udivw, 0b000, 0b000010);
  INSN(sdivw, 0b000, 0b000011);
  INSN(lslvw, 0b000, 0b001000);
  INSN(lsrvw, 0b000, 0b001001);
  INSN(asrvw, 0b000, 0b001010);
  INSN(rorvw, 0b000, 0b001011);

  INSN(udiv, 0b100, 0b000010);
  INSN(sdiv, 0b100, 0b000011);
  INSN(lslv, 0b100, 0b001000);
  INSN(lsrv, 0b100, 0b001001);
  INSN(asrv, 0b100, 0b001010);
  INSN(rorv, 0b100, 0b001011);

#undef INSN

  // Data-processing (3 source)
  void data_processing(unsigned op54, unsigned op31, unsigned o0,
                       Register Rd, Register Rn, Register Rm,
                       Register Ra) {
    starti;
    f(op54, 31, 29), f(0b11011, 28, 24);
    f(op31, 23, 21), f(o0, 15);
    zrf(Rm, 16), zrf(Ra, 10), zrf(Rn, 5), zrf(Rd, 0);
  }

#define INSN(NAME, op54, op31, o0)                                      \
  void NAME(Register Rd, Register Rn, Register Rm, Register Ra) {       \
    data_processing(op54, op31, o0, Rd, Rn, Rm, Ra);                    \
  }

  INSN(maddw,  0b000, 0b000, 0);
  INSN(msubw,  0b000, 0b000, 1);
  INSN(madd,   0b100, 0b000, 0);
  INSN(msub,   0b100, 0b000, 1);
  INSN(smaddl, 0b100, 0b001, 0);
  INSN(smsubl, 0b100, 0b001, 1);
  INSN(umaddl, 0b100, 0b101, 0);
  INSN(umsubl, 0b100, 0b101, 1);

#undef INSN

#define INSN(NAME, op54, op31, o0)                                      \
  void NAME(Register Rd, Register Rn, Register Rm) {                    \
    data_processing(op54, op31, o0, Rd, Rn, Rm, as_Register(31));       \
  }

  INSN(smulh, 0b100, 0b010, 0);
  INSN(umulh, 0b100, 0b110, 0);

#undef INSN

  // Floating-point data-processing (1 source)
  void data_processing(unsigned type, unsigned opcode,
                       FloatRegister Vd, FloatRegister Vn) {
    starti;
    f(0b000, 31, 29);
    f(0b11110, 28, 24);
    f(type, 23, 22), f(1, 21), f(opcode, 20, 15), f(0b10000, 14, 10);
    rf(Vn, 5), rf(Vd, 0);
  }

#define INSN(NAME, type, opcode)                        \
  void NAME(FloatRegister Vd, FloatRegister Vn) {       \
    data_processing(type, opcode, Vd, Vn);              \
  }

  INSN(fmovs,  0b00, 0b000000);
  INSN(fabss,  0b00, 0b000001);
  INSN(fnegs,  0b00, 0b000010);
  INSN(fsqrts, 0b00, 0b000011);
  INSN(fcvts,  0b00, 0b000101);   // Single-precision to double-precision
  INSN(fcvths, 0b11, 0b000100);   // Half-precision to single-precision
  INSN(fcvtsh, 0b00, 0b000111);   // Single-precision to half-precision

  INSN(fmovd,  0b01, 0b000000);
  INSN(fabsd,  0b01, 0b000001);
  INSN(fnegd,  0b01, 0b000010);
  INSN(fsqrtd, 0b01, 0b000011);
  INSN(fcvtd,  0b01, 0b000100);   // Double-precision to single-precision

private:
  void _fcvt_narrow_extend(FloatRegister Vd, SIMD_Arrangement Ta,
                           FloatRegister Vn, SIMD_Arrangement Tb, bool do_extend) {
    assert((do_extend && (Tb >> 1) + 1 == (Ta >> 1))
           || (!do_extend && (Ta >> 1) + 1 == (Tb >> 1)), "Incompatible arrangement");
    starti;
    int op30 = (do_extend ? Tb : Ta) & 1;
    int op22 = ((do_extend ? Ta : Tb) >> 1) & 1;
    f(0, 31), f(op30, 30), f(0b0011100, 29, 23), f(op22, 22);
    f(0b100001011, 21, 13), f(do_extend ? 1 : 0, 12), f(0b10, 11, 10);
    rf(Vn, 5), rf(Vd, 0);
  }

public:
  void fcvtl(FloatRegister Vd, SIMD_Arrangement Ta, FloatRegister Vn,  SIMD_Arrangement Tb) {
    assert(Tb == T4H || Tb == T8H|| Tb == T2S || Tb == T4S, "invalid arrangement");
    _fcvt_narrow_extend(Vd, Ta, Vn, Tb, true);
  }

  void fcvtn(FloatRegister Vd, SIMD_Arrangement Ta, FloatRegister Vn,  SIMD_Arrangement Tb) {
    assert(Ta == T4H || Ta == T8H|| Ta == T2S || Ta == T4S, "invalid arrangement");
    _fcvt_narrow_extend(Vd, Ta, Vn, Tb, false);
  }

#undef INSN

  // Floating-point data-processing (2 source)
  void data_processing(unsigned op31, unsigned type, unsigned opcode,
--> --------------------

--> maximum size reached

--> --------------------

99%


¤ Dauer der Verarbeitung: 0.42 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung ist noch experimentell.