Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  arm.ad   Sprache: unbekannt

 
Spracherkennung für: .ad vermutete Sprache: Unknown {[0] [0] [0]} [Methode: Schwerpunktbildung, einfache Gewichte, sechs Dimensionen]

//
// Copyright (c) 2008, 2022, 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.
//

// ARM Architecture Description File

//----------DEFINITION BLOCK---------------------------------------------------
// Define name --> value mappings to inform the ADLC of an integer valued name
// Current support includes integer values in the range [0, 0x7FFFFFFF]
// Format:
//        int_def  <name>         ( <int_value>, <expression>);
// Generated Code in ad_<arch>.hpp
//        #define  <name>   (<expression>)
//        // value == <int_value>
// Generated code in ad_<arch>.cpp adlc_verification()
//        assert( <name> == <int_value>, "Expect (<expression>) to equal <int_value>");
//
definitions %{
// The default cost (of an ALU instruction).
  int_def DEFAULT_COST      (    100,     100);
  int_def HUGE_COST         (1000000, 1000000);

// Memory refs are twice as expensive as run-of-the-mill.
  int_def MEMORY_REF_COST   (    200, DEFAULT_COST * 2);

// Branches are even more expensive.
  int_def BRANCH_COST       (    300, DEFAULT_COST * 3);
  int_def CALL_COST         (    300, DEFAULT_COST * 3);
%}


//----------SOURCE BLOCK-------------------------------------------------------
// This is a block of C++ code which provides values, functions, and
// definitions necessary in the rest of the architecture description
source_hpp %{
// Header information of the source block.
// Method declarations/definitions which are used outside
// the ad-scope can conveniently be defined here.
//
// To keep related declarations/definitions/uses close together,
// we switch between source %{ }% and source_hpp %{ }% freely as needed.

// Does destination need to be loaded in a register then passed to a
// branch instruction?
extern bool maybe_far_call(const CallNode *n);
extern bool maybe_far_call(const MachCallNode *n);
static inline bool cache_reachable() {
  return MacroAssembler::_cache_fully_reachable();
}

#define ldr_32 ldr
#define str_32 str
#define tst_32 tst
#define teq_32 teq
#if 1
extern bool PrintOptoAssembly;
#endif

class c2 {
public:
  static OptoRegPair return_value(int ideal_reg);
};

class CallStubImpl {

  //--------------------------------------------------------------
  //---<  Used for optimization in Compile::Shorten_branches  >---
  //--------------------------------------------------------------

 public:
  // Size of call trampoline stub.
  static uint size_call_trampoline() {
    return 0; // no call trampolines on this platform
  }

  // number of relocations needed by a call trampoline stub
  static uint reloc_call_trampoline() {
    return 0; // no call trampolines on this platform
  }
};

class HandlerImpl {

 public:

  static int emit_exception_handler(CodeBuffer &cbuf);
  static int emit_deopt_handler(CodeBuffer& cbuf);

  static uint size_exception_handler() {
    return ( 3 * 4 );
  }


  static uint size_deopt_handler() {
    return ( 9 * 4 );
  }

};

class Node::PD {
public:
  enum NodeFlags {
    _last_flag = Node::_last_flag
  };
};

// Assert that the given node is not a var shift.
bool assert_not_var_shift(const Node *n);
%}

source %{

// Assert that the given node is not a var shift.
bool assert_not_var_shift(const Node *n) {
  assert(!n->as_ShiftV()->is_var_shift(), "illegal var shift");
  return true;
}

#define __ _masm.

static FloatRegister reg_to_FloatRegister_object(int register_encoding);
static Register reg_to_register_object(int register_encoding);

void PhaseOutput::pd_perform_mach_node_analysis() {
}

int MachNode::pd_alignment_required() const {
  return 1;
}

int MachNode::compute_padding(int current_offset) const {
  return 0;
}

// ****************************************************************************

// REQUIRED FUNCTIONALITY

// emit an interrupt that is caught by the debugger (for debugging compiler)
void emit_break(CodeBuffer &cbuf) {
  C2_MacroAssembler _masm(&cbuf);
  __ breakpoint();
}

#ifndef PRODUCT
void MachBreakpointNode::format( PhaseRegAlloc *, outputStream *st ) const {
  st->print("TA");
}
#endif

void MachBreakpointNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
  emit_break(cbuf);
}

uint MachBreakpointNode::size(PhaseRegAlloc *ra_) const {
  return MachNode::size(ra_);
}


void emit_nop(CodeBuffer &cbuf) {
  C2_MacroAssembler _masm(&cbuf);
  __ nop();
}


void emit_call_reloc(CodeBuffer &cbuf, const MachCallNode *n, MachOper *m, RelocationHolder const& rspec) {
  int ret_addr_offset0 = n->as_MachCall()->ret_addr_offset();
  int call_site_offset = cbuf.insts()->mark_off();
  C2_MacroAssembler _masm(&cbuf);
  __ set_inst_mark(); // needed in emit_to_interp_stub() to locate the call
  address target = (address)m->method();
  assert(n->as_MachCall()->entry_point() == target, "sanity");
  assert(maybe_far_call(n) == !__ reachable_from_cache(target), "sanity");
  assert(cache_reachable() == __ cache_fully_reachable(), "sanity");

  assert(target != NULL, "need real address");

  int ret_addr_offset = -1;
  if (rspec.type() == relocInfo::runtime_call_type) {
    __ call(target, rspec);
    ret_addr_offset = __ offset();
  } else {
    // scratches Rtemp
    ret_addr_offset = __ patchable_call(target, rspec, true);
  }
  assert(ret_addr_offset - call_site_offset == ret_addr_offset0, "fix ret_addr_offset()");
}

//=============================================================================
// REQUIRED FUNCTIONALITY for encoding
void emit_lo(CodeBuffer &cbuf, int val) {  }
void emit_hi(CodeBuffer &cbuf, int val) {  }


//=============================================================================
const RegMask& MachConstantBaseNode::_out_RegMask = PTR_REG_mask();

int ConstantTable::calculate_table_base_offset() const {
  int offset = -(size() / 2);
  // flds, fldd: 8-bit  offset multiplied by 4: +/- 1024
  // ldr, ldrb : 12-bit offset:                 +/- 4096
  if (!Assembler::is_simm10(offset)) {
    offset = Assembler::min_simm10;
  }
  return offset;
}

bool MachConstantBaseNode::requires_postalloc_expand() const { return false; }
void MachConstantBaseNode::postalloc_expand(GrowableArray <Node *> *nodes, PhaseRegAlloc *ra_) {
  ShouldNotReachHere();
}

void MachConstantBaseNode::emit(CodeBuffer& cbuf, PhaseRegAlloc* ra_) const {
  Compile* C = ra_->C;
  ConstantTable& constant_table = C->output()->constant_table();
  C2_MacroAssembler _masm(&cbuf);

  Register r = as_Register(ra_->get_encode(this));
  CodeSection* consts_section = __ code()->consts();
  CodeSection* insts_section = __ code()->insts();
  // constants section size is aligned according to the align_at_start settings of the next section
  int consts_size = insts_section->align_at_start(consts_section->size());
  assert(constant_table.size() == consts_size, "must be: %d == %d", constant_table.size(), consts_size);

  // Materialize the constant table base.
  address baseaddr = consts_section->start() + -(constant_table.table_base_offset());
  RelocationHolder rspec = internal_word_Relocation::spec(baseaddr);
  __ mov_address(r, baseaddr, rspec);
}

uint MachConstantBaseNode::size(PhaseRegAlloc*) const {
  return 8;
}

#ifndef PRODUCT
void MachConstantBaseNode::format(PhaseRegAlloc* ra_, outputStream* st) const {
  char reg[128];
  ra_->dump_register(this, reg);
  st->print("MOV_SLOW    &constanttable,%s\t! constant table base", reg);
}
#endif

#ifndef PRODUCT
void MachPrologNode::format( PhaseRegAlloc *ra_, outputStream *st ) const {
  Compile* C = ra_->C;

  for (int i = 0; i < OptoPrologueNops; i++) {
    st->print_cr("NOP"); st->print("\t");
  }

  size_t framesize = C->output()->frame_size_in_bytes();
  assert((framesize & (StackAlignmentInBytes-1)) == 0, "frame size not aligned");
  int bangsize = C->output()->bang_size_in_bytes();
  // Remove two words for return addr and rbp,
  framesize -= 2*wordSize;
  bangsize -= 2*wordSize;

  // Calls to C2R adapters often do not accept exceptional returns.
  // We require that their callers must bang for them.  But be careful, because
  // some VM calls (such as call site linkage) can use several kilobytes of
  // stack.  But the stack safety zone should account for that.
  // See bugs 4446381, 4468289, 4497237.
  if (C->output()->need_stack_bang(bangsize)) {
    st->print_cr("! stack bang (%d bytes)", bangsize); st->print("\t");
  }
  st->print_cr("PUSH   R_FP|R_LR_LR"); st->print("\t");
  if (framesize != 0) {
    st->print   ("SUB    R_SP, R_SP, " SIZE_FORMAT,framesize);
  }
}
#endif

void MachPrologNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
  Compile* C = ra_->C;
  C2_MacroAssembler _masm(&cbuf);

  for (int i = 0; i < OptoPrologueNops; i++) {
    __ nop();
  }

  size_t framesize = C->output()->frame_size_in_bytes();
  assert((framesize & (StackAlignmentInBytes-1)) == 0, "frame size not aligned");
  int bangsize = C->output()->bang_size_in_bytes();
  // Remove two words for return addr and fp,
  framesize -= 2*wordSize;
  bangsize -= 2*wordSize;

  // Calls to C2R adapters often do not accept exceptional returns.
  // We require that their callers must bang for them.  But be careful, because
  // some VM calls (such as call site linkage) can use several kilobytes of
  // stack.  But the stack safety zone should account for that.
  // See bugs 4446381, 4468289, 4497237.
  if (C->output()->need_stack_bang(bangsize)) {
    __ arm_stack_overflow_check(bangsize, Rtemp);
  }

  __ raw_push(FP, LR);
  if (framesize != 0) {
    __ sub_slow(SP, SP, framesize);
  }

  // offset from scratch buffer is not valid
  if (strcmp(cbuf.name(), "Compile::Fill_buffer") == 0) {
    C->output()->set_frame_complete( __ offset() );
  }

  if (C->has_mach_constant_base_node()) {
    // NOTE: We set the table base offset here because users might be
    // emitted before MachConstantBaseNode.
    ConstantTable& constant_table = C->output()->constant_table();
    constant_table.set_table_base_offset(constant_table.calculate_table_base_offset());
  }
}

uint MachPrologNode::size(PhaseRegAlloc *ra_) const {
  return MachNode::size(ra_);
}

int MachPrologNode::reloc() const {
  return 10; // a large enough number
}

//=============================================================================
#ifndef PRODUCT
void MachEpilogNode::format( PhaseRegAlloc *ra_, outputStream *st ) const {
  Compile* C = ra_->C;

  size_t framesize = C->output()->frame_size_in_bytes();
  framesize -= 2*wordSize;

  if (framesize != 0) {
    st->print("ADD    R_SP, R_SP, " SIZE_FORMAT "\n\t",framesize);
  }
  st->print("POP    R_FP|R_LR_LR");

  if (do_polling() && ra_->C->is_method_compilation()) {
    st->print("\n\t");
    st->print("MOV    Rtemp, #PollAddr\t! Load Polling address\n\t");
    st->print("LDR    Rtemp,[Rtemp]\t!Poll for Safepointing");
  }
}
#endif

void MachEpilogNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
  C2_MacroAssembler _masm(&cbuf);
  Compile* C = ra_->C;

  size_t framesize = C->output()->frame_size_in_bytes();
  framesize -= 2*wordSize;
  if (framesize != 0) {
    __ add_slow(SP, SP, framesize);
  }
  __ raw_pop(FP, LR);

  // If this does safepoint polling, then do it here
  if (do_polling() && ra_->C->is_method_compilation()) {
    __ read_polling_page(Rtemp, relocInfo::poll_return_type);
  }
}

uint MachEpilogNode::size(PhaseRegAlloc *ra_) const {
  return MachNode::size(ra_);
}

int MachEpilogNode::reloc() const {
  return 16; // a large enough number
}

const Pipeline * MachEpilogNode::pipeline() const {
  return MachNode::pipeline_class();
}

//=============================================================================

// Figure out which register class each belongs in: rc_int, rc_float, rc_stack
enum RC { rc_bad, rc_int, rc_float, rc_stack };
static enum RC rc_class( OptoReg::Name reg ) {
  if (!OptoReg::is_valid(reg)) return rc_bad;
  if (OptoReg::is_stack(reg)) return rc_stack;
  VMReg r = OptoReg::as_VMReg(reg);
  if (r->is_Register()) return rc_int;
  assert(r->is_FloatRegister(), "must be");
  return rc_float;
}

static inline bool is_iRegLd_memhd(OptoReg::Name src_first, OptoReg::Name src_second, int offset) {
  int rlo = Matcher::_regEncode[src_first];
  int rhi = Matcher::_regEncode[src_second];
  if (!((rlo&1)==0 && (rlo+1 == rhi))) {
    tty->print_cr("CAUGHT BAD LDRD/STRD");
  }
  return (rlo&1)==0 && (rlo+1 == rhi) && is_memoryHD(offset);
}

uint MachSpillCopyNode::implementation( CodeBuffer *cbuf,
                                        PhaseRegAlloc *ra_,
                                        bool do_size,
                                        outputStream* st ) const {
  // Get registers to move
  OptoReg::Name src_second = ra_->get_reg_second(in(1));
  OptoReg::Name src_first = ra_->get_reg_first(in(1));
  OptoReg::Name dst_second = ra_->get_reg_second(this );
  OptoReg::Name dst_first = ra_->get_reg_first(this );

  enum RC src_second_rc = rc_class(src_second);
  enum RC src_first_rc = rc_class(src_first);
  enum RC dst_second_rc = rc_class(dst_second);
  enum RC dst_first_rc = rc_class(dst_first);

  assert( OptoReg::is_valid(src_first) && OptoReg::is_valid(dst_first), "must move at least 1 register" );

  // Generate spill code!
  int size = 0;

  if (src_first == dst_first && src_second == dst_second)
    return size;            // Self copy, no move

#ifdef TODO
  if (bottom_type()->isa_vect() != NULL) {
  }
#endif

  // Shared code does not expect instruction set capability based bailouts here.
  // Handle offset unreachable bailout with minimal change in shared code.
  // Bailout only for real instruction emit.
  // This requires a single comment change in shared code. ( see output.cpp "Normal" instruction case )

  C2_MacroAssembler _masm(cbuf);

  // --------------------------------------
  // Check for mem-mem move.  Load into unused float registers and fall into
  // the float-store case.
  if (src_first_rc == rc_stack && dst_first_rc == rc_stack) {
    int offset = ra_->reg2offset(src_first);
    if (cbuf && !is_memoryfp(offset)) {
      ra_->C->record_method_not_compilable("unable to handle large constant offsets");
      return 0;
    } else {
      if (src_second_rc != rc_bad) {
        assert((src_first&1)==0 && src_first+1 == src_second, "pair of registers must be aligned/contiguous");
        src_first     = OptoReg::Name(R_mem_copy_lo_num);
        src_second    = OptoReg::Name(R_mem_copy_hi_num);
        src_first_rc  = rc_float;
        src_second_rc = rc_float;
        if (cbuf) {
          __ ldr_double(Rmemcopy, Address(SP, offset));
        } else if (!do_size) {
          st->print(LDR_DOUBLE "   R_%s,[R_SP + #%d]\t! spill",OptoReg::regname(src_first),offset);
        }
      } else {
        src_first     = OptoReg::Name(R_mem_copy_lo_num);
        src_first_rc  = rc_float;
        if (cbuf) {
          __ ldr_float(Rmemcopy, Address(SP, offset));
        } else if (!do_size) {
          st->print(LDR_FLOAT "   R_%s,[R_SP + #%d]\t! spill",OptoReg::regname(src_first),offset);
        }
      }
      size += 4;
    }
  }

  if (src_second_rc == rc_stack && dst_second_rc == rc_stack) {
    Unimplemented();
  }

  // --------------------------------------
  // Check for integer reg-reg copy
  if (src_first_rc == rc_int && dst_first_rc == rc_int) {
    // Else normal reg-reg copy
    assert( src_second != dst_first, "smashed second before evacuating it" );
    if (cbuf) {
      __ mov(reg_to_register_object(Matcher::_regEncode[dst_first]), reg_to_register_object(Matcher::_regEncode[src_first]));
#ifndef PRODUCT
    } else if (!do_size) {
      st->print("MOV    R_%s, R_%s\t# spill",
                Matcher::regName[dst_first],
                Matcher::regName[src_first]);
#endif
    }
    size += 4;
  }

  // Check for integer store
  if (src_first_rc == rc_int && dst_first_rc == rc_stack) {
    int offset = ra_->reg2offset(dst_first);
    if (cbuf && !is_memoryI(offset)) {
      ra_->C->record_method_not_compilable("unable to handle large constant offsets");
      return 0;
    } else {
      if (src_second_rc != rc_bad && is_iRegLd_memhd(src_first, src_second, offset)) {
        assert((src_first&1)==0 && src_first+1 == src_second, "pair of registers must be aligned/contiguous");
        if (cbuf) {
          __ str_64(reg_to_register_object(Matcher::_regEncode[src_first]), Address(SP, offset));
#ifndef PRODUCT
        } else if (!do_size) {
          if (size != 0) st->print("\n\t");
          st->print(STR_64 "   R_%s,[R_SP + #%d]\t! spill",OptoReg::regname(src_first), offset);
#endif
        }
        return size + 4;
      } else {
        if (cbuf) {
          __ str_32(reg_to_register_object(Matcher::_regEncode[src_first]), Address(SP, offset));
#ifndef PRODUCT
        } else if (!do_size) {
          if (size != 0) st->print("\n\t");
          st->print(STR_32 "   R_%s,[R_SP + #%d]\t! spill",OptoReg::regname(src_first), offset);
#endif
        }
      }
    }
    size += 4;
  }

  // Check for integer load
  if (dst_first_rc == rc_int && src_first_rc == rc_stack) {
    int offset = ra_->reg2offset(src_first);
    if (cbuf && !is_memoryI(offset)) {
      ra_->C->record_method_not_compilable("unable to handle large constant offsets");
      return 0;
    } else {
      if (src_second_rc != rc_bad && is_iRegLd_memhd(dst_first, dst_second, offset)) {
        assert((src_first&1)==0 && src_first+1 == src_second, "pair of registers must be aligned/contiguous");
        if (cbuf) {
          __ ldr_64(reg_to_register_object(Matcher::_regEncode[dst_first]), Address(SP, offset));
#ifndef PRODUCT
        } else if (!do_size) {
          if (size != 0) st->print("\n\t");
          st->print(LDR_64 "   R_%s,[R_SP + #%d]\t! spill",OptoReg::regname(dst_first), offset);
#endif
        }
        return size + 4;
      } else {
        if (cbuf) {
          __ ldr_32(reg_to_register_object(Matcher::_regEncode[dst_first]), Address(SP, offset));
#ifndef PRODUCT
        } else if (!do_size) {
          if (size != 0) st->print("\n\t");
          st->print(LDR_32 "   R_%s,[R_SP + #%d]\t! spill",OptoReg::regname(dst_first), offset);
#endif
        }
      }
    }
    size += 4;
  }

  // Check for float reg-reg copy
  if (src_first_rc == rc_float && dst_first_rc == rc_float) {
    if (src_second_rc != rc_bad) {
      assert((src_first&1)==0 && src_first+1 == src_second && (dst_first&1)==0 && dst_first+1 == dst_second, "pairs of registers must be aligned/contiguous");
      if (cbuf) {
      __ mov_double(reg_to_FloatRegister_object(Matcher::_regEncode[dst_first]), reg_to_FloatRegister_object(Matcher::_regEncode[src_first]));
#ifndef PRODUCT
      } else if (!do_size) {
        st->print(MOV_DOUBLE "    R_%s, R_%s\t# spill",
                  Matcher::regName[dst_first],
                  Matcher::regName[src_first]);
#endif
      }
      return 4;
    }
    if (cbuf) {
      __ mov_float(reg_to_FloatRegister_object(Matcher::_regEncode[dst_first]), reg_to_FloatRegister_object(Matcher::_regEncode[src_first]));
#ifndef PRODUCT
    } else if (!do_size) {
      st->print(MOV_FLOAT "    R_%s, R_%s\t# spill",
                Matcher::regName[dst_first],
                Matcher::regName[src_first]);
#endif
    }
    size = 4;
  }

  // Check for float store
  if (src_first_rc == rc_float && dst_first_rc == rc_stack) {
    int offset = ra_->reg2offset(dst_first);
    if (cbuf && !is_memoryfp(offset)) {
      ra_->C->record_method_not_compilable("unable to handle large constant offsets");
      return 0;
    } else {
      // Further check for aligned-adjacent pair, so we can use a double store
      if (src_second_rc != rc_bad) {
        assert((src_first&1)==0 && src_first+1 == src_second && (dst_first&1)==0 && dst_first+1 == dst_second, "pairs of registers and stack slots must be aligned/contiguous");
        if (cbuf) {
          __ str_double(reg_to_FloatRegister_object(Matcher::_regEncode[src_first]), Address(SP, offset));
#ifndef PRODUCT
        } else if (!do_size) {
          if (size != 0) st->print("\n\t");
          st->print(STR_DOUBLE "   R_%s,[R_SP + #%d]\t! spill",OptoReg::regname(src_first),offset);
#endif
        }
        return size + 4;
      } else {
        if (cbuf) {
          __ str_float(reg_to_FloatRegister_object(Matcher::_regEncode[src_first]), Address(SP, offset));
#ifndef PRODUCT
        } else if (!do_size) {
          if (size != 0) st->print("\n\t");
          st->print(STR_FLOAT "   R_%s,[R_SP + #%d]\t! spill",OptoReg::regname(src_first),offset);
#endif
        }
      }
    }
    size += 4;
  }

  // Check for float load
  if (dst_first_rc == rc_float && src_first_rc == rc_stack) {
    int offset = ra_->reg2offset(src_first);
    if (cbuf && !is_memoryfp(offset)) {
      ra_->C->record_method_not_compilable("unable to handle large constant offsets");
      return 0;
    } else {
      // Further check for aligned-adjacent pair, so we can use a double store
      if (src_second_rc != rc_bad) {
        assert((src_first&1)==0 && src_first+1 == src_second && (dst_first&1)==0 && dst_first+1 == dst_second, "pairs of registers and stack slots must be aligned/contiguous");
        if (cbuf) {
          __ ldr_double(reg_to_FloatRegister_object(Matcher::_regEncode[dst_first]), Address(SP, offset));
#ifndef PRODUCT
        } else if (!do_size) {
          if (size != 0) st->print("\n\t");
          st->print(LDR_DOUBLE "   R_%s,[R_SP + #%d]\t! spill",OptoReg::regname(dst_first),offset);
#endif
        }
        return size + 4;
      } else {
        if (cbuf) {
          __ ldr_float(reg_to_FloatRegister_object(Matcher::_regEncode[dst_first]), Address(SP, offset));
#ifndef PRODUCT
        } else if (!do_size) {
          if (size != 0) st->print("\n\t");
          st->print(LDR_FLOAT "   R_%s,[R_SP + #%d]\t! spill",OptoReg::regname(dst_first),offset);
#endif
        }
      }
    }
    size += 4;
  }

  // check for int reg -> float reg move
  if (src_first_rc == rc_int && dst_first_rc == rc_float) {
    // Further check for aligned-adjacent pair, so we can use a single instruction
    if (src_second_rc != rc_bad) {
      assert((dst_first&1)==0 && dst_first+1 == dst_second, "pairs of registers must be aligned/contiguous");
      assert((src_first&1)==0 && src_first+1 == src_second, "pairs of registers must be aligned/contiguous");
      assert(src_second_rc == rc_int && dst_second_rc == rc_float, "unsupported");
      if (cbuf) {
        __ fmdrr(reg_to_FloatRegister_object(Matcher::_regEncode[dst_first]), reg_to_register_object(Matcher::_regEncode[src_first]), reg_to_register_object(Matcher::_regEncode[src_second]));
#ifndef PRODUCT
      } else if (!do_size) {
        if (size != 0) st->print("\n\t");
        st->print("FMDRR   R_%s, R_%s, R_%s\t! spill",OptoReg::regname(dst_first), OptoReg::regname(src_first), OptoReg::regname(src_second));
#endif
      }
      return size + 4;
    } else {
      if (cbuf) {
        __ fmsr(reg_to_FloatRegister_object(Matcher::_regEncode[dst_first]), reg_to_register_object(Matcher::_regEncode[src_first]));
#ifndef PRODUCT
      } else if (!do_size) {
        if (size != 0) st->print("\n\t");
        st->print(FMSR "   R_%s, R_%s\t! spill",OptoReg::regname(dst_first), OptoReg::regname(src_first));
#endif
      }
      size += 4;
    }
  }

  // check for float reg -> int reg move
  if (src_first_rc == rc_float && dst_first_rc == rc_int) {
    // Further check for aligned-adjacent pair, so we can use a single instruction
    if (src_second_rc != rc_bad) {
      assert((src_first&1)==0 && src_first+1 == src_second, "pairs of registers must be aligned/contiguous");
      assert((dst_first&1)==0 && dst_first+1 == dst_second, "pairs of registers must be aligned/contiguous");
      assert(src_second_rc == rc_float && dst_second_rc == rc_int, "unsupported");
      if (cbuf) {
        __ fmrrd(reg_to_register_object(Matcher::_regEncode[dst_first]), reg_to_register_object(Matcher::_regEncode[dst_second]), reg_to_FloatRegister_object(Matcher::_regEncode[src_first]));
#ifndef PRODUCT
      } else if (!do_size) {
        if (size != 0) st->print("\n\t");
        st->print("FMRRD   R_%s, R_%s, R_%s\t! spill",OptoReg::regname(dst_first), OptoReg::regname(dst_second), OptoReg::regname(src_first));
#endif
      }
      return size + 4;
    } else {
      if (cbuf) {
        __ fmrs(reg_to_register_object(Matcher::_regEncode[dst_first]), reg_to_FloatRegister_object(Matcher::_regEncode[src_first]));
#ifndef PRODUCT
      } else if (!do_size) {
        if (size != 0) st->print("\n\t");
        st->print(FMRS "   R_%s, R_%s\t! spill",OptoReg::regname(dst_first), OptoReg::regname(src_first));
#endif
      }
      size += 4;
    }
  }

  // --------------------------------------------------------------------
  // Check for hi bits still needing moving.  Only happens for misaligned
  // arguments to native calls.
  if (src_second == dst_second)
    return size;               // Self copy; no move
  assert( src_second_rc != rc_bad && dst_second_rc != rc_bad, "src_second & dst_second cannot be Bad" );

  // Check for integer reg-reg copy.  Hi bits are stuck up in the top
  // 32-bits of a 64-bit register, but are needed in low bits of another
  // register (else it's a hi-bits-to-hi-bits copy which should have
  // happened already as part of a 64-bit move)
  if (src_second_rc == rc_int && dst_second_rc == rc_int) {
    if (cbuf) {
      __ mov(reg_to_register_object(Matcher::_regEncode[dst_second]), reg_to_register_object(Matcher::_regEncode[src_second]));
#ifndef PRODUCT
    } else if (!do_size) {
      if (size != 0) st->print("\n\t");
      st->print("MOV    R_%s, R_%s\t# spill high",
                Matcher::regName[dst_second],
                Matcher::regName[src_second]);
#endif
    }
    return size+4;
  }

  // Check for high word integer store
  if (src_second_rc == rc_int && dst_second_rc == rc_stack) {
    int offset = ra_->reg2offset(dst_second);

    if (cbuf && !is_memoryP(offset)) {
      ra_->C->record_method_not_compilable("unable to handle large constant offsets");
      return 0;
    } else {
      if (cbuf) {
        __ str(reg_to_register_object(Matcher::_regEncode[src_second]), Address(SP, offset));
#ifndef PRODUCT
      } else if (!do_size) {
        if (size != 0) st->print("\n\t");
        st->print("STR   R_%s,[R_SP + #%d]\t! spill",OptoReg::regname(src_second), offset);
#endif
      }
    }
    return size + 4;
  }

  // Check for high word integer load
  if (dst_second_rc == rc_int && src_second_rc == rc_stack) {
    int offset = ra_->reg2offset(src_second);
    if (cbuf && !is_memoryP(offset)) {
      ra_->C->record_method_not_compilable("unable to handle large constant offsets");
      return 0;
    } else {
      if (cbuf) {
        __ ldr(reg_to_register_object(Matcher::_regEncode[dst_second]), Address(SP, offset));
#ifndef PRODUCT
      } else if (!do_size) {
        if (size != 0) st->print("\n\t");
        st->print("LDR   R_%s,[R_SP + #%d]\t! spill",OptoReg::regname(dst_second), offset);
#endif
      }
    }
    return size + 4;
  }

  Unimplemented();
  return 0; // Mute compiler
}

#ifndef PRODUCT
void MachSpillCopyNode::format( PhaseRegAlloc *ra_, outputStream *st ) const {
  implementation( NULL, ra_, false, st );
}
#endif

void MachSpillCopyNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
  implementation( &cbuf, ra_, false, NULL );
}

uint MachSpillCopyNode::size(PhaseRegAlloc *ra_) const {
  return implementation( NULL, ra_, true, NULL );
}

//=============================================================================
#ifndef PRODUCT
void MachNopNode::format( PhaseRegAlloc *, outputStream *st ) const {
  st->print("NOP \t# %d bytes pad for loops and calls", 4 * _count);
}
#endif

void MachNopNode::emit(CodeBuffer &cbuf, PhaseRegAlloc * ) const {
  C2_MacroAssembler _masm(&cbuf);
  for(int i = 0; i < _count; i += 1) {
    __ nop();
  }
}

uint MachNopNode::size(PhaseRegAlloc *ra_) const {
  return 4 * _count;
}


//=============================================================================
#ifndef PRODUCT
void BoxLockNode::format( PhaseRegAlloc *ra_, outputStream *st ) const {
  int offset = ra_->reg2offset(in_RegMask(0).find_first_elem());
  int reg = ra_->get_reg_first(this);
  st->print("ADD    %s,R_SP+#%d",Matcher::regName[reg], offset);
}
#endif

void BoxLockNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
  C2_MacroAssembler _masm(&cbuf);
  int offset = ra_->reg2offset(in_RegMask(0).find_first_elem());
  int reg = ra_->get_encode(this);
  Register dst = reg_to_register_object(reg);

  if (is_aimm(offset)) {
    __ add(dst, SP, offset);
  } else {
    __ mov_slow(dst, offset);
    __ add(dst, SP, dst);
  }
}

uint BoxLockNode::size(PhaseRegAlloc *ra_) const {
  // BoxLockNode is not a MachNode, so we can't just call MachNode::size(ra_)
  assert(ra_ == ra_->C->regalloc(), "sanity");
  return ra_->C->output()->scratch_emit_size(this);
}

//=============================================================================
#ifndef PRODUCT
#define R_RTEMP "R_R12"
void MachUEPNode::format( PhaseRegAlloc *ra_, outputStream *st ) const {
  st->print_cr("\nUEP:");
  if (UseCompressedClassPointers) {
    st->print_cr("\tLDR_w " R_RTEMP ",[R_R0 + oopDesc::klass_offset_in_bytes]\t! Inline cache check");
    st->print_cr("\tdecode_klass " R_RTEMP);
  } else {
    st->print_cr("\tLDR   " R_RTEMP ",[R_R0 + oopDesc::klass_offset_in_bytes]\t! Inline cache check");
  }
  st->print_cr("\tCMP   " R_RTEMP ",R_R8" );
  st->print   ("\tB.NE  SharedRuntime::handle_ic_miss_stub");
}
#endif

void MachUEPNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
  C2_MacroAssembler _masm(&cbuf);
  Register iCache  = reg_to_register_object(Matcher::inline_cache_reg_encode());
  assert(iCache == Ricklass, "should be");
  Register receiver = R0;

  __ load_klass(Rtemp, receiver);
  __ cmp(Rtemp, iCache);
  __ jump(SharedRuntime::get_ic_miss_stub(), relocInfo::runtime_call_type, noreg, ne);
}

uint MachUEPNode::size(PhaseRegAlloc *ra_) const {
  return MachNode::size(ra_);
}


//=============================================================================

// Emit exception handler code.
int HandlerImpl::emit_exception_handler(CodeBuffer& cbuf) {
  C2_MacroAssembler _masm(&cbuf);

  address base = __ start_a_stub(size_exception_handler());
  if (base == NULL) {
    ciEnv::current()->record_failure("CodeCache is full");
    return 0;  // CodeBuffer::expand failed
  }

  int offset = __ offset();

  // OK to trash LR, because exception blob will kill it
  __ jump(OptoRuntime::exception_blob()->entry_point(), relocInfo::runtime_call_type, LR_tmp);

  assert(__ offset() - offset <= (int) size_exception_handler(), "overflow");

  __ end_a_stub();

  return offset;
}

int HandlerImpl::emit_deopt_handler(CodeBuffer& cbuf) {
  // Can't use any of the current frame's registers as we may have deopted
  // at a poll and everything can be live.
  C2_MacroAssembler _masm(&cbuf);

  address base = __ start_a_stub(size_deopt_handler());
  if (base == NULL) {
    ciEnv::current()->record_failure("CodeCache is full");
    return 0;  // CodeBuffer::expand failed
  }

  int offset = __ offset();
  address deopt_pc = __ pc();

  __ sub(SP, SP, wordSize); // make room for saved PC
  __ push(LR); // save LR that may be live when we get here
  __ mov_relative_address(LR, deopt_pc);
  __ str(LR, Address(SP, wordSize)); // save deopt PC
  __ pop(LR); // restore LR
  __ jump(SharedRuntime::deopt_blob()->unpack(), relocInfo::runtime_call_type, noreg);

  assert(__ offset() - offset <= (int) size_deopt_handler(), "overflow");

  __ end_a_stub();
  return offset;
}

const bool Matcher::match_rule_supported(int opcode) {
  if (!has_match_rule(opcode))
    return false;

  switch (opcode) {
  case Op_PopCountI:
  case Op_PopCountL:
    if (!UsePopCountInstruction)
      return false;
    break;
  case Op_LShiftCntV:
  case Op_RShiftCntV:
  case Op_AddVB:
  case Op_AddVS:
  case Op_AddVI:
  case Op_AddVL:
  case Op_SubVB:
  case Op_SubVS:
  case Op_SubVI:
  case Op_SubVL:
  case Op_MulVS:
  case Op_MulVI:
  case Op_LShiftVB:
  case Op_LShiftVS:
  case Op_LShiftVI:
  case Op_LShiftVL:
  case Op_RShiftVB:
  case Op_RShiftVS:
  case Op_RShiftVI:
  case Op_RShiftVL:
  case Op_URShiftVB:
  case Op_URShiftVS:
  case Op_URShiftVI:
  case Op_URShiftVL:
  case Op_AndV:
  case Op_OrV:
  case Op_XorV:
    return VM_Version::has_simd();
  case Op_LoadVector:
  case Op_StoreVector:
  case Op_AddVF:
  case Op_SubVF:
  case Op_MulVF:
    return VM_Version::has_vfp() || VM_Version::has_simd();
  case Op_AddVD:
  case Op_SubVD:
  case Op_MulVD:
  case Op_DivVF:
  case Op_DivVD:
    return VM_Version::has_vfp();
  }

  return true;  // Per default match rules are supported.
}

const bool Matcher::match_rule_supported_superword(int opcode, int vlen, BasicType bt) {
  return match_rule_supported_vector(opcode, vlen, bt);
}

const bool Matcher::match_rule_supported_vector(int opcode, int vlen, BasicType bt) {

  // TODO
  // identify extra cases that we might want to provide match rules for
  // e.g. Op_ vector nodes and other intrinsics while guarding with vlen
  bool ret_value = match_rule_supported(opcode) && vector_size_supported(bt, vlen);
  // Add rules here.

  return ret_value;  // Per default match rules are supported.
}

const bool Matcher::match_rule_supported_vector_masked(int opcode, int vlen, BasicType bt) {
  return false;
}

const bool Matcher::vector_needs_partial_operations(Node* node, const TypeVect* vt) {
  return false;
}

const RegMask* Matcher::predicate_reg_mask(void) {
  return NULL;
}

const TypeVectMask* Matcher::predicate_reg_type(const Type* elemTy, int length) {
  return NULL;
}

// Vector calling convention not yet implemented.
const bool Matcher::supports_vector_calling_convention(void) {
  return false;
}

OptoRegPair Matcher::vector_return_value(uint ideal_reg) {
  Unimplemented();
  return OptoRegPair(0, 0);
}

// Vector width in bytes
const int Matcher::vector_width_in_bytes(BasicType bt) {
  return MaxVectorSize;
}

const int Matcher::scalable_vector_reg_size(const BasicType bt) {
  return -1;
}

// Vector ideal reg corresponding to specified size in bytes
const uint Matcher::vector_ideal_reg(int size) {
  assert(MaxVectorSize >= size, "");
  switch(size) {
    case  8: return Op_VecD;
    case 16: return Op_VecX;
  }
  ShouldNotReachHere();
  return 0;
}

// Limits on vector size (number of elements) loaded into vector.
const int Matcher::max_vector_size(const BasicType bt) {
  assert(is_java_primitive(bt), "only primitive type vectors");
  return vector_width_in_bytes(bt)/type2aelembytes(bt);
}

const int Matcher::min_vector_size(const BasicType bt) {
  assert(is_java_primitive(bt), "only primitive type vectors");
  return 8/type2aelembytes(bt);
}

// Is this branch offset short enough that a short branch can be used?
//
// NOTE: If the platform does not provide any short branch variants, then
//       this method should return false for offset 0.
bool Matcher::is_short_branch_offset(int rule, int br_size, int offset) {
  // The passed offset is relative to address of the branch.
  // On ARM a branch displacement is calculated relative to address
  // of the branch + 8.
  //
  // offset -= 8;
  // return (Assembler::is_simm24(offset));
  return false;
}

MachOper* Matcher::pd_specialize_generic_vector_operand(MachOper* original_opnd, uint ideal_reg, bool is_temp) {
  ShouldNotReachHere(); // generic vector operands not supported
  return NULL;
}

bool Matcher::is_reg2reg_move(MachNode* m) {
  ShouldNotReachHere();  // generic vector operands not supported
  return false;
}

bool Matcher::is_generic_vector(MachOper* opnd)  {
  ShouldNotReachHere();  // generic vector operands not supported
  return false;
}

// Should the matcher clone input 'm' of node 'n'?
bool Matcher::pd_clone_node(Node* n, Node* m, Matcher::MStack& mstack) {
  if (is_vshift_con_pattern(n, m)) { // ShiftV src (ShiftCntV con)
    mstack.push(m, Visit);           // m = ShiftCntV
    return true;
  }
  return false;
}

// Should the Matcher clone shifts on addressing modes, expecting them
// to be subsumed into complex addressing expressions or compute them
// into registers?
bool Matcher::pd_clone_address_expressions(AddPNode* m, Matcher::MStack& mstack, VectorSet& address_visited) {
  return clone_base_plus_offset_address(m, mstack, address_visited);
}

// Return whether or not this register is ever used as an argument.  This
// function is used on startup to build the trampoline stubs in generateOptoStub.
// Registers not mentioned will be killed by the VM call in the trampoline, and
// arguments in those registers not be available to the callee.
bool Matcher::can_be_java_arg( int reg ) {
  if (reg == R_R0_num ||
      reg == R_R1_num ||
      reg == R_R2_num ||
      reg == R_R3_num) return true;

  if (reg >= R_S0_num &&
      reg <= R_S13_num) return true;
  return false;
}

bool Matcher::is_spillable_arg( int reg ) {
  return can_be_java_arg(reg);
}

uint Matcher::int_pressure_limit()
{
  return (INTPRESSURE == -1) ? 12 : INTPRESSURE;
}

uint Matcher::float_pressure_limit()
{
  return (FLOATPRESSURE == -1) ? 30 : FLOATPRESSURE;
}

bool Matcher::use_asm_for_ldiv_by_con( jlong divisor ) {
  return false;
}

// Register for DIVI projection of divmodI
RegMask Matcher::divI_proj_mask() {
  ShouldNotReachHere();
  return RegMask();
}

// Register for MODI projection of divmodI
RegMask Matcher::modI_proj_mask() {
  ShouldNotReachHere();
  return RegMask();
}

// Register for DIVL projection of divmodL
RegMask Matcher::divL_proj_mask() {
  ShouldNotReachHere();
  return RegMask();
}

// Register for MODL projection of divmodL
RegMask Matcher::modL_proj_mask() {
  ShouldNotReachHere();
  return RegMask();
}

const RegMask Matcher::method_handle_invoke_SP_save_mask() {
  return FP_REGP_mask();
}

bool maybe_far_call(const CallNode *n) {
  return !MacroAssembler::_reachable_from_cache(n->as_Call()->entry_point());
}

bool maybe_far_call(const MachCallNode *n) {
  return !MacroAssembler::_reachable_from_cache(n->as_MachCall()->entry_point());
}

%}

//----------ENCODING BLOCK-----------------------------------------------------
// This block specifies the encoding classes used by the compiler to output
// byte streams.  Encoding classes are parameterized macros used by
// Machine Instruction Nodes in order to generate the bit encoding of the
// instruction.  Operands specify their base encoding interface with the
// interface keyword.  There are currently supported four interfaces,
// REG_INTER, CONST_INTER, MEMORY_INTER, & COND_INTER.  REG_INTER causes an
// operand to generate a function which returns its register number when
// queried.   CONST_INTER causes an operand to generate a function which
// returns the value of the constant when queried.  MEMORY_INTER causes an
// operand to generate four functions which return the Base Register, the
// Index Register, the Scale Value, and the Offset Value of the operand when
// queried.  COND_INTER causes an operand to generate six functions which
// return the encoding code (ie - encoding bits for the instruction)
// associated with each basic boolean condition for a conditional instruction.
//
// Instructions specify two basic values for encoding.  Again, a function
// is available to check if the constant displacement is an oop. They use the
// ins_encode keyword to specify their encoding classes (which must be
// a sequence of enc_class names, and their parameters, specified in
// the encoding block), and they use the
// opcode keyword to specify, in order, their primary, secondary, and
// tertiary opcode.  Only the opcode sections which a particular instruction
// needs for encoding need to be specified.
encode %{
  enc_class call_epilog %{
    // nothing
  %}

  enc_class Java_To_Runtime (method meth) %{
    // CALL directly to the runtime
    emit_call_reloc(cbuf, as_MachCall(), $meth, runtime_call_Relocation::spec());
  %}

  enc_class Java_Static_Call (method meth) %{
    // CALL to fixup routine.  Fixup routine uses ScopeDesc info to determine
    // who we intended to call.

    if ( !_method) {
      emit_call_reloc(cbuf, as_MachCall(), $meth, runtime_call_Relocation::spec());
    } else {
      int method_index = resolved_method_index(cbuf);
      RelocationHolder rspec = _optimized_virtual ? opt_virtual_call_Relocation::spec(method_index)
                                                  : static_call_Relocation::spec(method_index);
      emit_call_reloc(cbuf, as_MachCall(), $meth, rspec);

      // Emit stubs for static call.
      address stub = CompiledStaticCall::emit_to_interp_stub(cbuf);
      if (stub == NULL) {
        ciEnv::current()->record_failure("CodeCache is full");
        return;
      }
    }
  %}

  enc_class save_last_PC %{
    // preserve mark
    address mark = cbuf.insts()->mark();
    debug_only(int off0 = cbuf.insts_size());
    C2_MacroAssembler _masm(&cbuf);
    int ret_addr_offset = as_MachCall()->ret_addr_offset();
    __ adr(LR, mark + ret_addr_offset);
    __ str(LR, Address(Rthread, JavaThread::last_Java_pc_offset()));
    debug_only(int off1 = cbuf.insts_size());
    assert(off1 - off0 == 2 * Assembler::InstructionSize, "correct size prediction");
    // restore mark
    cbuf.insts()->set_mark(mark);
  %}

  enc_class preserve_SP %{
    // preserve mark
    address mark = cbuf.insts()->mark();
    debug_only(int off0 = cbuf.insts_size());
    C2_MacroAssembler _masm(&cbuf);
    // FP is preserved across all calls, even compiled calls.
    // Use it to preserve SP in places where the callee might change the SP.
    __ mov(Rmh_SP_save, SP);
    debug_only(int off1 = cbuf.insts_size());
    assert(off1 - off0 == 4, "correct size prediction");
    // restore mark
    cbuf.insts()->set_mark(mark);
  %}

  enc_class restore_SP %{
    C2_MacroAssembler _masm(&cbuf);
    __ mov(SP, Rmh_SP_save);
  %}

  enc_class Java_Dynamic_Call (method meth) %{
    C2_MacroAssembler _masm(&cbuf);
    Register R8_ic_reg = reg_to_register_object(Matcher::inline_cache_reg_encode());
    assert(R8_ic_reg == Ricklass, "should be");
    __ set_inst_mark();
    __ movw(R8_ic_reg, ((unsigned int)Universe::non_oop_word()) & 0xffff);
    __ movt(R8_ic_reg, ((unsigned int)Universe::non_oop_word()) >> 16);
    address  virtual_call_oop_addr = __ inst_mark();
    // CALL to fixup routine.  Fixup routine uses ScopeDesc info to determine
    // who we intended to call.
    int method_index = resolved_method_index(cbuf);
    __ relocate(virtual_call_Relocation::spec(virtual_call_oop_addr, method_index));
    emit_call_reloc(cbuf, as_MachCall(), $meth, RelocationHolder::none);
  %}

  enc_class LdReplImmI(immI src, regD dst, iRegI tmp, int cnt, int wth) %{
    // FIXME: load from constant table?
    // Load a constant replicated "count" times with width "width"
    int count = $cnt$$constant;
    int width = $wth$$constant;
    assert(count*width == 4, "sanity");
    int val = $src$$constant;
    if (width < 4) {
      int bit_width = width * 8;
      val &= (((int)1) << bit_width) - 1; // mask off sign bits
      for (int i = 0; i < count - 1; i++) {
        val |= (val << bit_width);
      }
    }
    C2_MacroAssembler _masm(&cbuf);

    if (val == -1) {
      __ mvn($tmp$$Register, 0);
    } else if (val == 0) {
      __ mov($tmp$$Register, 0);
    } else {
      __ movw($tmp$$Register, val & 0xffff);
      __ movt($tmp$$Register, (unsigned int)val >> 16);
    }
    __ fmdrr($dst$$FloatRegister, $tmp$$Register, $tmp$$Register);
  %}

  enc_class LdReplImmF(immF src, regD dst, iRegI tmp) %{
    // Replicate float con 2 times and pack into vector (8 bytes) in regD.
    float fval = $src$$constant;
    int val = *((int*)&fval);
    C2_MacroAssembler _masm(&cbuf);

    if (val == -1) {
      __ mvn($tmp$$Register, 0);
    } else if (val == 0) {
      __ mov($tmp$$Register, 0);
    } else {
      __ movw($tmp$$Register, val & 0xffff);
      __ movt($tmp$$Register, (unsigned int)val >> 16);
    }
    __ fmdrr($dst$$FloatRegister, $tmp$$Register, $tmp$$Register);
  %}

  enc_class enc_String_Compare(R0RegP str1, R1RegP str2, R2RegI cnt1, R3RegI cnt2, iRegI result, iRegI tmp1, iRegI tmp2) %{
    Label Ldone, Lloop;
    C2_MacroAssembler _masm(&cbuf);

    Register   str1_reg = $str1$$Register;
    Register   str2_reg = $str2$$Register;
    Register   cnt1_reg = $cnt1$$Register; // int
    Register   cnt2_reg = $cnt2$$Register; // int
    Register   tmp1_reg = $tmp1$$Register;
    Register   tmp2_reg = $tmp2$$Register;
    Register result_reg = $result$$Register;

    assert_different_registers(str1_reg, str2_reg, cnt1_reg, cnt2_reg, tmp1_reg, tmp2_reg);

    // Compute the minimum of the string lengths(str1_reg) and the
    // difference of the string lengths (stack)

    // See if the lengths are different, and calculate min in str1_reg.
    // Stash diff in tmp2 in case we need it for a tie-breaker.
    __ subs_32(tmp2_reg, cnt1_reg, cnt2_reg);
    __ mov(cnt1_reg, AsmOperand(cnt1_reg, lsl, exact_log2(sizeof(jchar)))); // scale the limit
    __ mov(cnt1_reg, AsmOperand(cnt2_reg, lsl, exact_log2(sizeof(jchar))), pl); // scale the limit

    // reallocate cnt1_reg, cnt2_reg, result_reg
    // Note:  limit_reg holds the string length pre-scaled by 2
    Register limit_reg = cnt1_reg;
    Register  chr2_reg = cnt2_reg;
    Register  chr1_reg = tmp1_reg;
    // str{12} are the base pointers

    // Is the minimum length zero?
    __ cmp_32(limit_reg, 0);
    if (result_reg != tmp2_reg) {
      __ mov(result_reg, tmp2_reg, eq);
    }
    __ b(Ldone, eq);

    // Load first characters
    __ ldrh(chr1_reg, Address(str1_reg, 0));
    __ ldrh(chr2_reg, Address(str2_reg, 0));

    // Compare first characters
    __ subs(chr1_reg, chr1_reg, chr2_reg);
    if (result_reg != chr1_reg) {
      __ mov(result_reg, chr1_reg, ne);
    }
    __ b(Ldone, ne);

    {
      // Check after comparing first character to see if strings are equivalent
      // Check if the strings start at same location
      __ cmp(str1_reg, str2_reg);
      // Check if the length difference is zero
      __ cond_cmp(tmp2_reg, 0, eq);
      __ mov(result_reg, 0, eq); // result is zero
      __ b(Ldone, eq);
      // Strings might not be equal
    }

    __ subs(chr1_reg, limit_reg, 1 * sizeof(jchar));
    if (result_reg != tmp2_reg) {
      __ mov(result_reg, tmp2_reg, eq);
    }
    __ b(Ldone, eq);

    // Shift str1_reg and str2_reg to the end of the arrays, negate limit
    __ add(str1_reg, str1_reg, limit_reg);
    __ add(str2_reg, str2_reg, limit_reg);
    __ neg(limit_reg, chr1_reg);  // limit = -(limit-2)

    // Compare the rest of the characters
    __ bind(Lloop);
    __ ldrh(chr1_reg, Address(str1_reg, limit_reg));
    __ ldrh(chr2_reg, Address(str2_reg, limit_reg));
    __ subs(chr1_reg, chr1_reg, chr2_reg);
    if (result_reg != chr1_reg) {
      __ mov(result_reg, chr1_reg, ne);
    }
    __ b(Ldone, ne);

    __ adds(limit_reg, limit_reg, sizeof(jchar));
    __ b(Lloop, ne);

    // If strings are equal up to min length, return the length difference.
    if (result_reg != tmp2_reg) {
      __ mov(result_reg, tmp2_reg);
    }

    // Otherwise, return the difference between the first mismatched chars.
    __ bind(Ldone);
  %}

  enc_class enc_String_Equals(R0RegP str1, R1RegP str2, R2RegI cnt, iRegI result, iRegI tmp1, iRegI tmp2) %{
    Label Lchar, Lchar_loop, Ldone, Lequal;
    C2_MacroAssembler _masm(&cbuf);

    Register   str1_reg = $str1$$Register;
    Register   str2_reg = $str2$$Register;
    Register    cnt_reg = $cnt$$Register; // int
    Register   tmp1_reg = $tmp1$$Register;
    Register   tmp2_reg = $tmp2$$Register;
    Register result_reg = $result$$Register;

    assert_different_registers(str1_reg, str2_reg, cnt_reg, tmp1_reg, tmp2_reg, result_reg);

    __ cmp(str1_reg, str2_reg); //same char[] ?
    __ b(Lequal, eq);

    __ cbz_32(cnt_reg, Lequal); // count == 0

    //rename registers
    Register limit_reg = cnt_reg;
    Register  chr1_reg = tmp1_reg;
    Register  chr2_reg = tmp2_reg;

    __ logical_shift_left(limit_reg, limit_reg, exact_log2(sizeof(jchar)));

    //check for alignment and position the pointers to the ends
    __ orr(chr1_reg, str1_reg, str2_reg);
    __ tst(chr1_reg, 0x3);

    // notZero means at least one not 4-byte aligned.
    // We could optimize the case when both arrays are not aligned
    // but it is not frequent case and it requires additional checks.
    __ b(Lchar, ne);

    // Compare char[] arrays aligned to 4 bytes.
    __ char_arrays_equals(str1_reg, str2_reg, limit_reg, result_reg,
                          chr1_reg, chr2_reg, Ldone);

    __ b(Lequal); // equal

    // char by char compare
    __ bind(Lchar);
    __ mov(result_reg, 0);
    __ add(str1_reg, limit_reg, str1_reg);
    __ add(str2_reg, limit_reg, str2_reg);
    __ neg(limit_reg, limit_reg); //negate count

    // Lchar_loop
    __ bind(Lchar_loop);
    __ ldrh(chr1_reg, Address(str1_reg, limit_reg));
    __ ldrh(chr2_reg, Address(str2_reg, limit_reg));
    __ cmp(chr1_reg, chr2_reg);
    __ b(Ldone, ne);
    __ adds(limit_reg, limit_reg, sizeof(jchar));
    __ b(Lchar_loop, ne);

    __ bind(Lequal);
    __ mov(result_reg, 1);  //equal

    __ bind(Ldone);
  %}

  enc_class enc_Array_Equals(R0RegP ary1, R1RegP ary2, iRegI tmp1, iRegI tmp2, iRegI tmp3, iRegI result) %{
    Label Ldone, Lloop, Lequal;
    C2_MacroAssembler _masm(&cbuf);

    Register   ary1_reg = $ary1$$Register;
    Register   ary2_reg = $ary2$$Register;
    Register   tmp1_reg = $tmp1$$Register;
    Register   tmp2_reg = $tmp2$$Register;
    Register   tmp3_reg = $tmp3$$Register;
    Register result_reg = $result$$Register;

    assert_different_registers(ary1_reg, ary2_reg, tmp1_reg, tmp2_reg, tmp3_reg, result_reg);

    int length_offset  = arrayOopDesc::length_offset_in_bytes();
    int base_offset    = arrayOopDesc::base_offset_in_bytes(T_CHAR);

    // return true if the same array
    __ teq(ary1_reg, ary2_reg);
    __ mov(result_reg, 1, eq);
    __ b(Ldone, eq); // equal

    __ tst(ary1_reg, ary1_reg);
    __ mov(result_reg, 0, eq);
    __ b(Ldone, eq);    // not equal

    __ tst(ary2_reg, ary2_reg);
    __ mov(result_reg, 0, eq);
    __ b(Ldone, eq);    // not equal

    //load the lengths of arrays
    __ ldr_s32(tmp1_reg, Address(ary1_reg, length_offset)); // int
    __ ldr_s32(tmp2_reg, Address(ary2_reg, length_offset)); // int

    // return false if the two arrays are not equal length
    __ teq_32(tmp1_reg, tmp2_reg);
    __ mov(result_reg, 0, ne);
    __ b(Ldone, ne);    // not equal

    __ tst(tmp1_reg, tmp1_reg);
    __ mov(result_reg, 1, eq);
    __ b(Ldone, eq);    // zero-length arrays are equal

    // load array addresses
    __ add(ary1_reg, ary1_reg, base_offset);
    __ add(ary2_reg, ary2_reg, base_offset);

    // renaming registers
    Register chr1_reg  =  tmp3_reg;   // for characters in ary1
    Register chr2_reg  =  tmp2_reg;   // for characters in ary2
    Register limit_reg =  tmp1_reg;   // length

    // set byte count
    __ logical_shift_left_32(limit_reg, limit_reg, exact_log2(sizeof(jchar)));

    // Compare char[] arrays aligned to 4 bytes.
    __ char_arrays_equals(ary1_reg, ary2_reg, limit_reg, result_reg,
                          chr1_reg, chr2_reg, Ldone);
    __ bind(Lequal);
    __ mov(result_reg, 1);  //equal

    __ bind(Ldone);
    %}
%}

//----------FRAME--------------------------------------------------------------
// Definition of frame structure and management information.
//
//  S T A C K   L A Y O U T    Allocators stack-slot number
//                             |   (to get allocators register number
//  G  Owned by    |        |  v    add VMRegImpl::stack0)
//  r   CALLER     |        |
//  o     |        +--------+      pad to even-align allocators stack-slot
//  w     V        |  pad0  |        numbers; owned by CALLER
//  t   -----------+--------+----> Matcher::_in_arg_limit, unaligned
//  h     ^        |   in   |  5
//        |        |  args  |  4   Holes in incoming args owned by SELF
//  |     |        |        |  3
//  |     |        +--------+
//  V     |        | old out|      Empty on Intel, window on Sparc
//        |    old |preserve|      Must be even aligned.
//        |     SP-+--------+----> Matcher::_old_SP, 8 (or 16 in LP64)-byte aligned
//        |        |   in   |  3   area for Intel ret address
//     Owned by    |preserve|      Empty on Sparc.
//       SELF      +--------+
//        |        |  pad2  |  2   pad to align old SP
//        |        +--------+  1
//        |        | locks  |  0
//        |        +--------+----> VMRegImpl::stack0, 8 (or 16 in LP64)-byte aligned
//        |        |  pad1  | 11   pad to align new SP
//        |        +--------+
//        |        |        | 10
//        |        | spills |  9   spills
//        V        |        |  8   (pad0 slot for callee)
//      -----------+--------+----> Matcher::_out_arg_limit, unaligned
//        ^        |  out   |  7
//        |        |  args  |  6   Holes in outgoing args owned by CALLEE
//     Owned by    +--------+
//      CALLEE     | new out|  6   Empty on Intel, window on Sparc
//        |    new |preserve|      Must be even-aligned.
//        |     SP-+--------+----> Matcher::_new_SP, even aligned
//        |        |        |
//
// Note 1: Only region 8-11 is determined by the allocator.  Region 0-5 is
//         known from SELF's arguments and the Java calling convention.
//         Region 6-7 is determined per call site.
// Note 2: If the calling convention leaves holes in the incoming argument
//         area, those holes are owned by SELF.  Holes in the outgoing area
//         are owned by the CALLEE.  Holes should not be necessary in the
//         incoming area, as the Java calling convention is completely under
//         the control of the AD file.  Doubles can be sorted and packed to
//         avoid holes.  Holes in the outgoing arguments may be necessary for
//         varargs C calling conventions.
// Note 3: Region 0-3 is even aligned, with pad2 as needed.  Region 3-5 is
//         even aligned with pad0 as needed.
//         Region 6 is even aligned.  Region 6-7 is NOT even aligned;
//         region 6-11 is even aligned; it may be padded out more so that
//         the region from SP to FP meets the minimum stack alignment.

frame %{
  // These two registers define part of the calling convention
  // between compiled code and the interpreter.
  inline_cache_reg(R_Ricklass);          // Inline Cache Register or Method* for I2C

  // Optional: name the operand used by cisc-spilling to access [stack_pointer + offset]
  cisc_spilling_operand_name(indOffset);

  // Number of stack slots consumed by a Monitor enter
  sync_stack_slots(1 * VMRegImpl::slots_per_word);

  // Compiled code's Frame Pointer
  frame_pointer(R_R13);

  // Stack alignment requirement
  stack_alignment(StackAlignmentInBytes);
  //  LP64: Alignment size in bytes (128-bit -> 16 bytes)
  // !LP64: Alignment size in bytes (64-bit  ->  8 bytes)

  // Number of outgoing stack slots killed above the out_preserve_stack_slots
  // for calls to C.  Supports the var-args backing area for register parms.
  // ADLC doesn't support parsing expressions, so I folded the math by hand.
  varargs_C_out_slots_killed( 0);

  // The after-PROLOG location of the return address.  Location of
  // return address specifies a type (REG or STACK) and a number
  // representing the register number (i.e. - use a register name) or
  // stack slot.
  // Ret Addr is on stack in slot 0 if no locks or verification or alignment.
  // Otherwise, it is above the locks and verification slot and alignment word
  return_addr(STACK - 1*VMRegImpl::slots_per_word +
              align_up((Compile::current()->in_preserve_stack_slots() +
                        Compile::current()->fixed_slots()),
                       stack_alignment_in_slots()));

  // Location of compiled Java return values.  Same as C
  return_value %{
    return c2::return_value(ideal_reg);
  %}

%}

//----------ATTRIBUTES---------------------------------------------------------
//----------Instruction Attributes---------------------------------------------
ins_attrib ins_cost(DEFAULT_COST); // Required cost attribute
ins_attrib ins_size(32);           // Required size attribute (in bits)
ins_attrib ins_short_branch(0);    // Required flag: is this instruction a
                                   // non-matching short branch variant of some
                                                            // long branch?

//----------OPERANDS-----------------------------------------------------------
// Operand definitions must precede instruction definitions for correct parsing
// in the ADLC because operands constitute user defined types which are used in
// instruction definitions.

//----------Simple Operands----------------------------------------------------
// Immediate Operands
// Integer Immediate: 32-bit
operand immI() %{
  match(ConI);

  op_cost(0);
  // formats are generated automatically for constants and base registers
  format %{ %}
  interface(CONST_INTER);
%}

// Integer Immediate: 8-bit unsigned - for VMOV
operand immU8() %{
  predicate(0 <= n->get_int() && (n->get_int() <= 255));
  match(ConI);
  op_cost(0);

  format %{ %}
  interface(CONST_INTER);
%}

// Integer Immediate: 16-bit
operand immI16() %{
  predicate((n->get_int() >> 16) == 0 && VM_Version::supports_movw());
  match(ConI);
  op_cost(0);

  format %{ %}
  interface(CONST_INTER);
%}

// Integer Immediate: offset for half and double word loads and stores
operand immIHD() %{
  predicate(is_memoryHD(n->get_int()));
  match(ConI);
  op_cost(0);
  format %{ %}
  interface(CONST_INTER);
%}

// Integer Immediate: offset for fp loads and stores
operand immIFP() %{
  predicate(is_memoryfp(n->get_int()) && ((n->get_int() & 3) == 0));
  match(ConI);
  op_cost(0);

  format %{ %}
  interface(CONST_INTER);
%}

// Valid scale values for addressing modes and shifts
operand immU5() %{
  predicate(0 <= n->get_int() && (n->get_int() <= 31));
  match(ConI);
  op_cost(0);

  format %{ %}
  interface(CONST_INTER);
%}

// Integer Immediate: 6-bit
operand immU6Big() %{
  predicate(n->get_int() >= 32 && n->get_int() <= 63);
  match(ConI);
  op_cost(0);
  format %{ %}
  interface(CONST_INTER);
%}

// Integer Immediate: 0-bit
operand immI0() %{
  predicate(n->get_int() == 0);
  match(ConI);
  op_cost(0);

  format %{ %}
  interface(CONST_INTER);
%}

// Integer Immediate: the value 1
operand immI_1() %{
  predicate(n->get_int() == 1);
  match(ConI);
  op_cost(0);

  format %{ %}
  interface(CONST_INTER);
%}

// Integer Immediate: the value 2
operand immI_2() %{
  predicate(n->get_int() == 2);
  match(ConI);
  op_cost(0);

  format %{ %}
  interface(CONST_INTER);
%}

// Integer Immediate: the value 3
operand immI_3() %{
  predicate(n->get_int() == 3);
  match(ConI);
  op_cost(0);

  format %{ %}
  interface(CONST_INTER);
%}

// Integer Immediate: the value 4
operand immI_4() %{
  predicate(n->get_int() == 4);
  match(ConI);
  op_cost(0);

  format %{ %}
  interface(CONST_INTER);
%}

// Integer Immediate: the value 8
operand immI_8() %{
  predicate(n->get_int() == 8);
  match(ConI);
  op_cost(0);

  format %{ %}
  interface(CONST_INTER);
%}

// Int Immediate non-negative
operand immU31()
%{
  predicate(n->get_int() >= 0);
  match(ConI);

  op_cost(0);
  format %{ %}
  interface(CONST_INTER);
%}

// Integer Immediate: the values 32-63
operand immI_32_63() %{
  predicate(n->get_int() >= 32 && n->get_int() <= 63);
  match(ConI);
  op_cost(0);

  format %{ %}
  interface(CONST_INTER);
%}

// Immediates for special shifts (sign extend)

// Integer Immediate: the value 16
operand immI_16() %{
  predicate(n->get_int() == 16);
  match(ConI);
  op_cost(0);

  format %{ %}
  interface(CONST_INTER);
%}

// Integer Immediate: the value 24
operand immI_24() %{
  predicate(n->get_int() == 24);
  match(ConI);
  op_cost(0);

  format %{ %}
  interface(CONST_INTER);
%}

// Integer Immediate: the value 255
operand immI_255() %{
  predicate( n->get_int() == 255 );
  match(ConI);
  op_cost(0);

  format %{ %}
  interface(CONST_INTER);
%}

// Integer Immediate: the value 65535
operand immI_65535() %{
  predicate(n->get_int() == 65535);
  match(ConI);
  op_cost(0);

  format %{ %}
  interface(CONST_INTER);
%}

// Integer Immediates for arithmetic instructions

operand aimmI() %{
  predicate(is_aimm(n->get_int()));
  match(ConI);
  op_cost(0);

  format %{ %}
  interface(CONST_INTER);
%}

operand aimmIneg() %{
  predicate(is_aimm(-n->get_int()));
  match(ConI);
  op_cost(0);

  format %{ %}
  interface(CONST_INTER);
%}

operand aimmU31() %{
  predicate((0 <= n->get_int()) && is_aimm(n->get_int()));
  match(ConI);
  op_cost(0);

  format %{ %}
  interface(CONST_INTER);
%}

// Integer Immediates for logical instructions

operand limmI() %{
  predicate(is_limmI(n->get_int()));
  match(ConI);
  op_cost(0);

  format %{ %}
  interface(CONST_INTER);
%}

operand limmIlow8() %{
  predicate(is_limmI_low(n->get_int(), 8));
  match(ConI);
  op_cost(0);

  format %{ %}
  interface(CONST_INTER);
%}

operand limmU31() %{
  predicate(0 <= n->get_int() && is_limmI(n->get_int()));
  match(ConI);
  op_cost(0);

  format %{ %}
  interface(CONST_INTER);
%}

operand limmIn() %{
  predicate(is_limmI(~n->get_int()));
  match(ConI);
  op_cost(0);

  format %{ %}
  interface(CONST_INTER);
%}


// Long Immediate: the value FF
operand immL_FF() %{
  predicate( n->get_long() == 0xFFL );
  match(ConL);
  op_cost(0);

  format %{ %}
  interface(CONST_INTER);
%}

// Long Immediate: the value FFFF
operand immL_FFFF() %{
  predicate( n->get_long() == 0xFFFFL );
  match(ConL);
  op_cost(0);

  format %{ %}
  interface(CONST_INTER);
%}

// Pointer Immediate: 32 or 64-bit
operand immP() %{
  match(ConP);

  op_cost(5);
  // formats are generated automatically for constants and base registers
  format %{ %}
  interface(CONST_INTER);
%}

operand immP0() %{
  predicate(n->get_ptr() == 0);
  match(ConP);
  op_cost(0);

  format %{ %}
  interface(CONST_INTER);
%}

// Pointer Immediate
operand immN()
%{
  match(ConN);

  op_cost(10);
  format %{ %}
  interface(CONST_INTER);
%}

operand immNKlass()
%{
  match(ConNKlass);

  op_cost(10);
  format %{ %}
  interface(CONST_INTER);
%}

// NULL Pointer Immediate
operand immN0()
%{
  predicate(n->get_narrowcon() == 0);
  match(ConN);

  op_cost(0);
  format %{ %}
  interface(CONST_INTER);
%}

operand immL() %{
  match(ConL);
  op_cost(40);
  // formats are generated automatically for constants and base registers
  format %{ %}
  interface(CONST_INTER);
%}

operand immL0() %{
  predicate(n->get_long() == 0L);
  match(ConL);
  op_cost(0);
  // formats are generated automatically for constants and base registers
  format %{ %}
  interface(CONST_INTER);
%}

// Long Immediate: 16-bit
operand immL16() %{
  predicate(n->get_long() >= 0 && n->get_long() < (1<<16)  && VM_Version::supports_movw());
  match(ConL);
  op_cost(0);

  format %{ %}
  interface(CONST_INTER);
%}

// Long Immediate: low 32-bit mask
operand immL_32bits() %{
  predicate(n->get_long() == 0xFFFFFFFFL);
  match(ConL);
  op_cost(0);

  format %{ %}
  interface(CONST_INTER);
%}

// Double Immediate
operand immD() %{
  match(ConD);

  op_cost(40);
  format %{ %}
  interface(CONST_INTER);
%}

// Double Immediate: +0.0d.
operand immD0() %{
  predicate(jlong_cast(n->getd()) == 0);

  match(ConD);
  op_cost(0);
  format %{ %}
  interface(CONST_INTER);
%}

operand imm8D() %{
  predicate(Assembler::double_num(n->getd()).can_be_imm8());
  match(ConD);

  op_cost(0);
  format %{ %}
  interface(CONST_INTER);
%}

// Float Immediate
operand immF() %{
  match(ConF);

  op_cost(20);
  format %{ %}
  interface(CONST_INTER);
%}

// Float Immediate: +0.0f
operand immF0() %{
  predicate(jint_cast(n->getf()) == 0);
  match(ConF);

  op_cost(0);
  format %{ %}
  interface(CONST_INTER);
%}

// Float Immediate: encoded as 8 bits
operand imm8F() %{
  predicate(Assembler::float_num(n->getf()).can_be_imm8());
  match(ConF);

  op_cost(0);
  format %{ %}
  interface(CONST_INTER);
%}

// Integer Register Operands
// Integer Register
operand iRegI() %{
  constraint(ALLOC_IN_RC(int_reg));
  match(RegI);
  match(R0RegI);
  match(R1RegI);
  match(R2RegI);
  match(R3RegI);
  match(R12RegI);

  format %{ %}
  interface(REG_INTER);
%}

// Pointer Register
operand iRegP() %{
  constraint(ALLOC_IN_RC(ptr_reg));
  match(RegP);
  match(R0RegP);
  match(R1RegP);
  match(R2RegP);
  match(RExceptionRegP);
  match(R8RegP);
  match(R9RegP);
  match(RthreadRegP); // FIXME: move to sp_ptr_RegP?
  match(R12RegP);
  match(LRRegP);

  match(sp_ptr_RegP);
  match(store_ptr_RegP);

  format %{ %}
  interface(REG_INTER);
%}

// GPRs + Rthread + SP
operand sp_ptr_RegP() %{
  constraint(ALLOC_IN_RC(sp_ptr_reg));
  match(RegP);
  match(iRegP);
  match(SPRegP); // FIXME: check cost

  format %{ %}
  interface(REG_INTER);
%}


operand R0RegP() %{
  constraint(ALLOC_IN_RC(R0_regP));
  match(iRegP);

  format %{ %}
  interface(REG_INTER);
%}

operand R1RegP() %{
  constraint(ALLOC_IN_RC(R1_regP));
  match(iRegP);

  format %{ %}
  interface(REG_INTER);
%}

operand R8RegP() %{
  constraint(ALLOC_IN_RC(R8_regP));
  match(iRegP);

  format %{ %}
  interface(REG_INTER);
%}

operand R9RegP() %{
  constraint(ALLOC_IN_RC(R9_regP));
  match(iRegP);

  format %{ %}
  interface(REG_INTER);
%}

operand R12RegP() %{
  constraint(ALLOC_IN_RC(R12_regP));
  match(iRegP);

  format %{ %}
  interface(REG_INTER);
%}

operand R2RegP() %{
  constraint(ALLOC_IN_RC(R2_regP));
  match(iRegP);

  format %{ %}
  interface(REG_INTER);
%}

operand RExceptionRegP() %{
  constraint(ALLOC_IN_RC(Rexception_regP));
  match(iRegP);

  format %{ %}
  interface(REG_INTER);
%}

operand RthreadRegP() %{
  constraint(ALLOC_IN_RC(Rthread_regP));
  match(iRegP);

  format %{ %}
  interface(REG_INTER);
%}

operand IPRegP() %{
  constraint(ALLOC_IN_RC(IP_regP));
  match(iRegP);

  format %{ %}
  interface(REG_INTER);
%}

operand SPRegP() %{
  constraint(ALLOC_IN_RC(SP_regP));
  match(iRegP);

  format %{ %}
  interface(REG_INTER);
%}

operand LRRegP() %{
  constraint(ALLOC_IN_RC(LR_regP));
  match(iRegP);

  format %{ %}
  interface(REG_INTER);
%}

operand R0RegI() %{
  constraint(ALLOC_IN_RC(R0_regI));
  match(iRegI);

  format %{ %}
  interface(REG_INTER);
%}

operand R1RegI() %{
  constraint(ALLOC_IN_RC(R1_regI));
  match(iRegI);

  format %{ %}
  interface(REG_INTER);
%}

operand R2RegI() %{
  constraint(ALLOC_IN_RC(R2_regI));
  match(iRegI);

  format %{ %}
  interface(REG_INTER);
%}

operand R3RegI() %{
  constraint(ALLOC_IN_RC(R3_regI));
  match(iRegI);

  format %{ %}
  interface(REG_INTER);
%}

operand R12RegI() %{
  constraint(ALLOC_IN_RC(R12_regI));
  match(iRegI);

  format %{ %}
  interface(REG_INTER);
%}

// Long Register
operand iRegL() %{
  constraint(ALLOC_IN_RC(long_reg));
  match(RegL);
  match(R0R1RegL);
  match(R2R3RegL);
//match(iRegLex);

  format %{ %}
  interface(REG_INTER);
%}

operand iRegLd() %{
  constraint(ALLOC_IN_RC(long_reg_align));
  match(iRegL); // FIXME: allows unaligned R11/R12?

  format %{ %}
  interface(REG_INTER);
%}

// first long arg, or return value
operand R0R1RegL() %{
  constraint(ALLOC_IN_RC(R0R1_regL));
  match(iRegL);

  format %{ %}
  interface(REG_INTER);
%}

operand R2R3RegL() %{
  constraint(ALLOC_IN_RC(R2R3_regL));
  match(iRegL);

  format %{ %}
  interface(REG_INTER);
%}

// Condition Code Flag Register
operand flagsReg() %{
  constraint(ALLOC_IN_RC(int_flags));
  match(RegFlags);

  format %{ "apsr" %}
  interface(REG_INTER);
%}

// Result of compare to 0 (TST)
operand flagsReg_EQNELTGE() %{
  constraint(ALLOC_IN_RC(int_flags));
  match(RegFlags);

  format %{ "apsr_EQNELTGE" %}
  interface(REG_INTER);
%}

// Condition Code Register, unsigned comparisons.
operand flagsRegU() %{
  constraint(ALLOC_IN_RC(int_flags));
  match(RegFlags);
#ifdef TODO
  match(RegFlagsP);
#endif

  format %{ "apsr_U" %}
  interface(REG_INTER);
%}

// Condition Code Register, pointer comparisons.
operand flagsRegP() %{
  constraint(ALLOC_IN_RC(int_flags));
  match(RegFlags);

  format %{ "apsr_P" %}
  interface(REG_INTER);
%}

// Condition Code Register, long comparisons.
operand flagsRegL_LTGE() %{
  constraint(ALLOC_IN_RC(int_flags));
  match(RegFlags);

  format %{ "apsr_L_LTGE" %}
  interface(REG_INTER);
%}

operand flagsRegL_EQNE() %{
  constraint(ALLOC_IN_RC(int_flags));
  match(RegFlags);

  format %{ "apsr_L_EQNE" %}
  interface(REG_INTER);
%}

operand flagsRegL_LEGT() %{
  constraint(ALLOC_IN_RC(int_flags));
  match(RegFlags);

  format %{ "apsr_L_LEGT" %}
  interface(REG_INTER);
%}

operand flagsRegUL_LTGE() %{
  constraint(ALLOC_IN_RC(int_flags));
  match(RegFlags);

  format %{ "apsr_UL_LTGE" %}
  interface(REG_INTER);
%}

operand flagsRegUL_EQNE() %{
  constraint(ALLOC_IN_RC(int_flags));
  match(RegFlags);

  format %{ "apsr_UL_EQNE" %}
  interface(REG_INTER);
%}

operand flagsRegUL_LEGT() %{
  constraint(ALLOC_IN_RC(int_flags));
  match(RegFlags);

  format %{ "apsr_UL_LEGT" %}
  interface(REG_INTER);
%}

// Condition Code Register, floating comparisons, unordered same as "less".
operand flagsRegF() %{
  constraint(ALLOC_IN_RC(float_flags));
  match(RegFlags);

  format %{ "fpscr_F" %}
  interface(REG_INTER);
%}

// Vectors
operand vecD() %{
  constraint(ALLOC_IN_RC(actual_dflt_reg));
  match(VecD);

  format %{ %}
  interface(REG_INTER);
%}

operand vecX() %{
  constraint(ALLOC_IN_RC(vectorx_reg));
  match(VecX);

  format %{ %}
  interface(REG_INTER);
%}

operand regD() %{
  constraint(ALLOC_IN_RC(actual_dflt_reg));
  match(RegD);
  match(regD_low);

  format %{ %}
  interface(REG_INTER);
%}

operand regF() %{
  constraint(ALLOC_IN_RC(sflt_reg));
  match(RegF);

  format %{ %}
  interface(REG_INTER);
%}

operand regD_low() %{
  constraint(ALLOC_IN_RC(dflt_low_reg));
  match(RegD);

  format %{ %}
  interface(REG_INTER);
%}

// Special Registers

// Method Register
operand inline_cache_regP(iRegP reg) %{
  constraint(ALLOC_IN_RC(Ricklass_regP));
  match(reg);
  format %{ %}
  interface(REG_INTER);
%}

//----------Complex Operands---------------------------------------------------
// Indirect Memory Reference
operand indirect(sp_ptr_RegP reg) %{
  constraint(ALLOC_IN_RC(sp_ptr_reg));
  match(reg);

  op_cost(100);
  format %{ "[$reg]" %}
  interface(MEMORY_INTER) %{
    base($reg);
    index(0xf); // PC => no index
    scale(0x0);
    disp(0x0);
  %}
%}


// Indirect with Offset in ]-4096, 4096[
operand indOffset12(sp_ptr_RegP reg, immI12 offset) %{
  constraint(ALLOC_IN_RC(sp_ptr_reg));
  match(AddP reg offset);

  op_cost(100);
  format %{ "[$reg + $offset]" %}
  interface(MEMORY_INTER) %{
    base($reg);
    index(0xf); // PC => no index
    scale(0x0);
    disp($offset);
  %}
%}

// Indirect with offset for float load/store
operand indOffsetFP(sp_ptr_RegP reg, immIFP offset) %{
  constraint(ALLOC_IN_RC(sp_ptr_reg));
  match(AddP reg offset);

  op_cost(100);
  format %{ "[$reg + $offset]" %}
  interface(MEMORY_INTER) %{
    base($reg);
    index(0xf); // PC => no index
    scale(0x0);
    disp($offset);
  %}
%}

// Indirect with Offset for half and double words
operand indOffsetHD(sp_ptr_RegP reg, immIHD offset) %{
  constraint(ALLOC_IN_RC(sp_ptr_reg));
  match(AddP reg offset);

  op_cost(100);
  format %{ "[$reg + $offset]" %}
  interface(MEMORY_INTER) %{
    base($reg);
    index(0xf); // PC => no index
    scale(0x0);
    disp($offset);
  %}
%}

// Indirect with Offset and Offset+4 in ]-1024, 1024[
operand indOffsetFPx2(sp_ptr_RegP reg, immX10x2 offset) %{
  constraint(ALLOC_IN_RC(sp_ptr_reg));
  match(AddP reg offset);

  op_cost(100);
  format %{ "[$reg + $offset]" %}
  interface(MEMORY_INTER) %{
    base($reg);
    index(0xf); // PC => no index
    scale(0x0);
    disp($offset);
  %}
%}

// Indirect with Offset and Offset+4 in ]-4096, 4096[
operand indOffset12x2(sp_ptr_RegP reg, immI12x2 offset) %{
  constraint(ALLOC_IN_RC(sp_ptr_reg));
  match(AddP reg offset);

  op_cost(100);
  format %{ "[$reg + $offset]" %}
  interface(MEMORY_INTER) %{
    base($reg);
    index(0xf); // PC => no index
    scale(0x0);
    disp($offset);
  %}
%}

// Indirect with Register Index
operand indIndex(iRegP addr, iRegX index) %{
  constraint(ALLOC_IN_RC(ptr_reg));
  match(AddP addr index);

  op_cost(100);
  format %{ "[$addr + $index]" %}
  interface(MEMORY_INTER) %{
    base($addr);
    index($index);
    scale(0x0);
    disp(0x0);
  %}
%}

// Indirect Memory Times Scale Plus Index Register
operand indIndexScale(iRegP addr, iRegX index, immU5 scale) %{
  constraint(ALLOC_IN_RC(ptr_reg));
  match(AddP addr (LShiftX index scale));

  op_cost(100);
  format %{"[$addr + $index << $scale]" %}
  interface(MEMORY_INTER) %{
    base($addr);
    index($index);
    scale($scale);
    disp(0x0);
  %}
%}

// Operands for expressing Control Flow
// NOTE:  Label is a predefined operand which should not be redefined in
//        the AD file.  It is generically handled within the ADLC.

//----------Conditional Branch Operands----------------------------------------
// Comparison Op  - This is the operation of the comparison, and is limited to
//                  the following set of codes:
//                  L (<), LE (<=), G (>), GE (>=), E (==), NE (!=)
//
// Other attributes of the comparison, such as unsignedness, are specified
// by the comparison instruction that sets a condition code flags register.
// That result is represented by a flags operand whose subtype is appropriate
// to the unsignedness (etc.) of the comparison.
//
// Later, the instruction which matches both the Comparison Op (a Bool) and
// the flags (produced by the Cmp) specifies the coding of the comparison op
// by matching a specific subtype of Bool operand below, such as cmpOpU.

operand cmpOp() %{
  match(Bool);

  format %{ "" %}
  interface(COND_INTER) %{
    equal(0x0);
    not_equal(0x1);
    less(0xb);
    greater_equal(0xa);
    less_equal(0xd);
    greater(0xc);
    overflow(0x0); // unsupported/unimplemented
    no_overflow(0x0); // unsupported/unimplemented
  %}
%}

// integer comparison with 0, signed
operand cmpOp0() %{
  match(Bool);

  format %{ "" %}
  interface(COND_INTER) %{
    equal(0x0);
    not_equal(0x1);
    less(0x4);
    greater_equal(0x5);
    less_equal(0xd); // unsupported
    greater(0xc); // unsupported
    overflow(0x0); // unsupported/unimplemented
    no_overflow(0x0); // unsupported/unimplemented
  %}
%}

// Comparison Op, unsigned
operand cmpOpU() %{
  match(Bool);

  format %{ "u" %}
  interface(COND_INTER) %{
    equal(0x0);
    not_equal(0x1);
    less(0x3);
    greater_equal(0x2);
    less_equal(0x9);
    greater(0x8);
    overflow(0x0); // unsupported/unimplemented
    no_overflow(0x0); // unsupported/unimplemented
  %}
%}

// Comparison Op, pointer (same as unsigned)
operand cmpOpP() %{
  match(Bool);

  format %{ "p" %}
  interface(COND_INTER) %{
    equal(0x0);
    not_equal(0x1);
    less(0x3);
    greater_equal(0x2);
    less_equal(0x9);
    greater(0x8);
    overflow(0x0); // unsupported/unimplemented
    no_overflow(0x0); // unsupported/unimplemented
  %}
%}

operand cmpOpL() %{
  match(Bool);

  format %{ "L" %}
  interface(COND_INTER) %{
    equal(0x0);
    not_equal(0x1);
    less(0xb);
    greater_equal(0xa);
    less_equal(0xd);
    greater(0xc);
    overflow(0x0); // unsupported/unimplemented
    no_overflow(0x0); // unsupported/unimplemented
  %}
%}

operand cmpOpL_commute() %{
  match(Bool);

  format %{ "L" %}
  interface(COND_INTER) %{
    equal(0x0);
    not_equal(0x1);
    less(0xc);
    greater_equal(0xd);
    less_equal(0xa);
    greater(0xb);
    overflow(0x0); // unsupported/unimplemented
    no_overflow(0x0); // unsupported/unimplemented
  %}
%}

operand cmpOpUL() %{
  match(Bool);

  format %{ "UL" %}
  interface(COND_INTER) %{
    equal(0x0);
    not_equal(0x1);
    less(0x3);
    greater_equal(0x2);
    less_equal(0x9);
    greater(0x8);
    overflow(0x0); // unsupported/unimplemented
    no_overflow(0x0); // unsupported/unimplemented
  %}
%}

operand cmpOpUL_commute() %{
  match(Bool);

  format %{ "UL" %}
  interface(COND_INTER) %{
    equal(0x0);
    not_equal(0x1);
    less(0x8);
    greater_equal(0x9);
    less_equal(0x2);
    greater(0x3);
    overflow(0x0); // unsupported/unimplemented
    no_overflow(0x0); // unsupported/unimplemented
  %}
%}


//----------OPERAND CLASSES----------------------------------------------------
// Operand Classes are groups of operands that are used to simplify
// instruction definitions by not requiring the AD writer to specify separate
// instructions for every form of operand when the instruction accepts
// multiple operand types with the same basic encoding and format.  The classic
// case of this is memory operands.

opclass memoryI ( indirect, indOffset12, indIndex, indIndexScale );
opclass memoryP ( indirect, indOffset12, indIndex, indIndexScale );
opclass memoryF ( indirect, indOffsetFP );
opclass memoryF2 ( indirect, indOffsetFPx2 );
opclass memoryD ( indirect, indOffsetFP );
opclass memoryfp( indirect, indOffsetFP );
opclass memoryB ( indirect, indIndex, indOffsetHD );
opclass memoryS ( indirect, indIndex, indOffsetHD );
opclass memoryL ( indirect, indIndex, indOffsetHD );

opclass memoryScaledI(indIndexScale);
opclass memoryScaledP(indIndexScale);

// when ldrex/strex is used:
opclass memoryex ( indirect );
opclass indIndexMemory( indIndex );
opclass memorylong ( indirect, indOffset12x2 );
opclass memoryvld ( indirect /* , write back mode not implemented */ );

//----------PIPELINE-----------------------------------------------------------
pipeline %{

//----------ATTRIBUTES---------------------------------------------------------
attributes %{
  fixed_size_instructions;           // Fixed size instructions
  max_instructions_per_bundle = 4;   // Up to 4 instructions per bundle
  instruction_unit_size = 4;         // An instruction is 4 bytes long
  instruction_fetch_unit_size = 16;  // The processor fetches one line
  instruction_fetch_units = 1;       // of 16 bytes

  // List of nop instructions
  nops( Nop_A0, Nop_A1, Nop_MS, Nop_FA, Nop_BR );
%}

//----------RESOURCES----------------------------------------------------------
// Resources are the functional units available to the machine
resources(A0, A1, MS, BR, FA, FM, IDIV, FDIV, IALU = A0 | A1);

//----------PIPELINE DESCRIPTION-----------------------------------------------
// Pipeline Description specifies the stages in the machine's pipeline

pipe_desc(A, P, F, B, I, J, S, R, E, C, M, W, X, T, D);

//----------PIPELINE CLASSES---------------------------------------------------
// Pipeline Classes describe the stages in which input and output are
// referenced by the hardware pipeline.

// Integer ALU reg-reg operation
pipe_class ialu_reg_reg(iRegI dst, iRegI src1, iRegI src2) %{
    single_instruction;
    dst   : E(write);
    src1  : R(read);
    src2  : R(read);
    IALU  : R;
%}

// Integer ALU reg-reg long operation
pipe_class ialu_reg_reg_2(iRegL dst, iRegL src1, iRegL src2) %{
    instruction_count(2);
    dst   : E(write);
    src1  : R(read);
    src2  : R(read);
    IALU  : R;
    IALU  : R;
%}

// Integer ALU reg-reg long dependent operation
pipe_class ialu_reg_reg_2_dep(iRegL dst, iRegL src1, iRegL src2, flagsReg cr) %{
    instruction_count(1); multiple_bundles;
    dst   : E(write);
    src1  : R(read);
    src2  : R(read);
    cr    : E(write);
    IALU  : R(2);
%}

// Integer ALU reg-imm operation
pipe_class ialu_reg_imm(iRegI dst, iRegI src1) %{
    single_instruction;
    dst   : E(write);
    src1  : R(read);
    IALU  : R;
%}

// Integer ALU reg-reg operation with condition code
pipe_class ialu_cc_reg_reg(iRegI dst, iRegI src1, iRegI src2, flagsReg cr) %{
    single_instruction;
    dst   : E(write);
    cr    : E(write);
    src1  : R(read);
    src2  : R(read);
    IALU  : R;
%}

// Integer ALU zero-reg operation
pipe_class ialu_zero_reg(iRegI dst, immI0 zero, iRegI src2) %{
    single_instruction;
    dst   : E(write);
    src2  : R(read);
    IALU  : R;
%}

// Integer ALU zero-reg operation with condition code only
pipe_class ialu_cconly_zero_reg(flagsReg cr, iRegI src) %{
    single_instruction;
    cr    : E(write);
    src   : R(read);
    IALU  : R;
%}

// Integer ALU reg-reg operation with condition code only
pipe_class ialu_cconly_reg_reg(flagsReg cr, iRegI src1, iRegI src2) %{
    single_instruction;
    cr    : E(write);
    src1  : R(read);
    src2  : R(read);
    IALU  : R;
%}

// Integer ALU reg-imm operation with condition code only
pipe_class ialu_cconly_reg_imm(flagsReg cr, iRegI src1) %{
    single_instruction;
    cr    : E(write);
    src1  : R(read);
    IALU  : R;
%}

// Integer ALU reg-reg-zero operation with condition code only
pipe_class ialu_cconly_reg_reg_zero(flagsReg cr, iRegI src1, iRegI src2, immI0 zero) %{
    single_instruction;
    cr    : E(write);
    src1  : R(read);
    src2  : R(read);
    IALU  : R;
%}

// Integer ALU reg-imm-zero operation with condition code only
pipe_class ialu_cconly_reg_imm_zero(flagsReg cr, iRegI src1, immI0 zero) %{
    single_instruction;
    cr    : E(write);
    src1  : R(read);
    IALU  : R;
%}

// Integer ALU reg-reg operation with condition code, src1 modified
pipe_class ialu_cc_rwreg_reg(flagsReg cr, iRegI src1, iRegI src2) %{
    single_instruction;
    cr    : E(write);
    src1  : E(write);
    src1  : R(read);
    src2  : R(read);
    IALU  : R;
%}

pipe_class cmpL_reg(iRegI dst, iRegL src1, iRegL src2, flagsReg cr ) %{
    multiple_bundles;
    dst   : E(write)+4;
    cr    : E(write);
    src1  : R(read);
    src2  : R(read);
    IALU  : R(3);
    BR    : R(2);
%}

// Integer ALU operation
pipe_class ialu_none(iRegI dst) %{
    single_instruction;
    dst   : E(write);
    IALU  : R;
%}

// Integer ALU reg operation
pipe_class ialu_reg(iRegI dst, iRegI src) %{
    single_instruction; may_have_no_code;
    dst   : E(write);
    src   : R(read);
    IALU  : R;
%}

// Integer ALU reg conditional operation
// This instruction has a 1 cycle stall, and cannot execute
// in the same cycle as the instruction setting the condition
// code. We kludge this by pretending to read the condition code
// 1 cycle earlier, and by marking the functional units as busy
// for 2 cycles with the result available 1 cycle later than
// is really the case.
pipe_class ialu_reg_flags( iRegI op2_out, iRegI op2_in, iRegI op1, flagsReg cr ) %{
    single_instruction;
    op2_out : C(write);
    op1     : R(read);
    cr      : R(read);       // This is really E, with a 1 cycle stall
    BR      : R(2);
    MS      : R(2);
%}

// Integer ALU reg operation
pipe_class ialu_move_reg_L_to_I(iRegI dst, iRegL src) %{
    single_instruction; may_have_no_code;
    dst   : E(write);
    src   : R(read);
    IALU  : R;
%}
pipe_class ialu_move_reg_I_to_L(iRegL dst, iRegI src) %{
    single_instruction; may_have_no_code;
    dst   : E(write);
    src   : R(read);
    IALU  : R;
%}

// Two integer ALU reg operations
pipe_class ialu_reg_2(iRegL dst, iRegL src) %{
    instruction_count(2);
    dst   : E(write);
    src   : R(read);
    A0    : R;
    A1    : R;
%}

// Two integer ALU reg operations
pipe_class ialu_move_reg_L_to_L(iRegL dst, iRegL src) %{
    instruction_count(2); may_have_no_code;
    dst   : E(write);
    src   : R(read);
    A0    : R;
    A1    : R;
%}

// Integer ALU imm operation
pipe_class ialu_imm(iRegI dst) %{
    single_instruction;
    dst   : E(write);
    IALU  : R;
%}

pipe_class ialu_imm_n(iRegI dst) %{
    single_instruction;
    dst   : E(write);
    IALU  : R;
%}

// Integer ALU reg-reg with carry operation
pipe_class ialu_reg_reg_cy(iRegI dst, iRegI src1, iRegI src2, iRegI cy) %{
    single_instruction;
    dst   : E(write);
    src1  : R(read);
    src2  : R(read);
    IALU  : R;
%}

// Integer ALU cc operation
pipe_class ialu_cc(iRegI dst, flagsReg cc) %{
    single_instruction;
    dst   : E(write);
    cc    : R(read);
    IALU  : R;
%}

// Integer ALU cc / second IALU operation
pipe_class ialu_reg_ialu( iRegI dst, iRegI src ) %{
    instruction_count(1); multiple_bundles;
    dst   : E(write)+1;
    src   : R(read);
    IALU  : R;
%}

// Integer ALU cc / second IALU operation
pipe_class ialu_reg_reg_ialu( iRegI dst, iRegI p, iRegI q ) %{
    instruction_count(1); multiple_bundles;
    dst   : E(write)+1;
    p     : R(read);
    q     : R(read);
    IALU  : R;
%}

// Integer ALU hi-lo-reg operation
pipe_class ialu_hi_lo_reg(iRegI dst, immI src) %{
    instruction_count(1); multiple_bundles;
    dst   : E(write)+1;
    IALU  : R(2);
%}

// Long Constant
pipe_class loadConL( iRegL dst, immL src ) %{
    instruction_count(2); multiple_bundles;
    dst   : E(write)+1;
    IALU  : R(2);
    IALU  : R(2);
%}

// Pointer Constant
pipe_class loadConP( iRegP dst, immP src ) %{
    instruction_count(0); multiple_bundles;
    fixed_latency(6);
%}

// Long Constant small
pipe_class loadConLlo( iRegL dst, immL src ) %{
    instruction_count(2);
    dst   : E(write);
    IALU  : R;
    IALU  : R;
%}

// [PHH] This is wrong for 64-bit.  See LdImmF/D.
pipe_class loadConFD(regF dst, immF src, iRegP tmp) %{
    instruction_count(1); multiple_bundles;
    src   : R(read);
    dst   : M(write)+1;
    IALU  : R;
    MS    : E;
%}

// Integer ALU nop operation
pipe_class ialu_nop() %{
    single_instruction;
    IALU  : R;
%}

// Integer ALU nop operation
pipe_class ialu_nop_A0() %{
    single_instruction;
    A0    : R;
%}

// Integer ALU nop operation
pipe_class ialu_nop_A1() %{
    single_instruction;
    A1    : R;
%}

// Integer Multiply reg-reg operation
pipe_class imul_reg_reg(iRegI dst, iRegI src1, iRegI src2) %{
    single_instruction;
    dst   : E(write);
    src1  : R(read);
    src2  : R(read);
    MS    : R(5);
%}

pipe_class mulL_reg_reg(iRegL dst, iRegL src1, iRegL src2) %{
    single_instruction;
    dst   : E(write)+4;
    src1  : R(read);
    src2  : R(read);
    MS    : R(6);
%}

// Integer Divide reg-reg
pipe_class sdiv_reg_reg(iRegI dst, iRegI src1, iRegI src2, iRegI temp, flagsReg cr) %{
    instruction_count(1); multiple_bundles;
    dst   : E(write);
    temp  : E(write);
    src1  : R(read);
    src2  : R(read);
    temp  : R(read);
    MS    : R(38);
%}

// Long Divide
pipe_class divL_reg_reg(iRegL dst, iRegL src1, iRegL src2) %{
    dst  : E(write)+71;
    src1 : R(read);
    src2 : R(read)+1;
    MS   : R(70);
%}

// Floating Point Add Float
pipe_class faddF_reg_reg(regF dst, regF src1, regF src2) %{
    single_instruction;
    dst   : X(write);
    src1  : E(read);
    src2  : E(read);
    FA    : R;
%}

// Floating Point Add Double
pipe_class faddD_reg_reg(regD dst, regD src1, regD src2) %{
    single_instruction;
    dst   : X(write);
    src1  : E(read);
    src2  : E(read);
    FA    : R;
%}

// Floating Point Conditional Move based on integer flags
pipe_class int_conditional_float_move (cmpOp cmp, flagsReg cr, regF dst, regF src) %{
    single_instruction;
    dst   : X(write);
    src   : E(read);
    cr    : R(read);
    FA    : R(2);
    BR    : R(2);
%}

// Floating Point Conditional Move based on integer flags
pipe_class int_conditional_double_move (cmpOp cmp, flagsReg cr, regD dst, regD src) %{
    single_instruction;
    dst   : X(write);
    src   : E(read);
    cr    : R(read);
    FA    : R(2);
    BR    : R(2);
%}

// Floating Point Multiply Float
pipe_class fmulF_reg_reg(regF dst, regF src1, regF src2) %{
    single_instruction;
    dst   : X(write);
    src1  : E(read);
    src2  : E(read);
    FM    : R;
%}

// Floating Point Multiply Double
pipe_class fmulD_reg_reg(regD dst, regD src1, regD src2) %{
    single_instruction;
    dst   : X(write);
    src1  : E(read);
    src2  : E(read);
    FM    : R;
%}

// Floating Point Divide Float
pipe_class fdivF_reg_reg(regF dst, regF src1, regF src2) %{
    single_instruction;
    dst   : X(write);
    src1  : E(read);
    src2  : E(read);
    FM    : R;
    FDIV  : C(14);
%}

// Floating Point Divide Double
pipe_class fdivD_reg_reg(regD dst, regD src1, regD src2) %{
    single_instruction;
    dst   : X(write);
    src1  : E(read);
    src2  : E(read);
    FM    : R;
    FDIV  : C(17);
%}

// Floating Point Move/Negate/Abs Float
pipe_class faddF_reg(regF dst, regF src) %{
    single_instruction;
    dst   : W(write);
    src   : E(read);
    FA    : R(1);
%}

// Floating Point Move/Negate/Abs Double
pipe_class faddD_reg(regD dst, regD src) %{
    single_instruction;
    dst   : W(write);
    src   : E(read);
    FA    : R;
%}

// Floating Point Convert F->D
pipe_class fcvtF2D(regD dst, regF src) %{
    single_instruction;
    dst   : X(write);
    src   : E(read);
    FA    : R;
%}

// Floating Point Convert I->D
pipe_class fcvtI2D(regD dst, regF src) %{
    single_instruction;
    dst   : X(write);
    src   : E(read);
    FA    : R;
%}

// Floating Point Convert LHi->D
pipe_class fcvtLHi2D(regD dst, regD src) %{
    single_instruction;
    dst   : X(write);
    src   : E(read);
    FA    : R;
%}

// Floating Point Convert L->D
pipe_class fcvtL2D(regD dst, iRegL src) %{
    single_instruction;
    dst   : X(write);
    src   : E(read);
    FA    : R;
%}

// Floating Point Convert L->F
pipe_class fcvtL2F(regF dst, iRegL src) %{
    single_instruction;
    dst   : X(write);
    src   : E(read);
    FA    : R;
%}

// Floating Point Convert D->F
pipe_class fcvtD2F(regD dst, regF src) %{
    single_instruction;
    dst   : X(write);
    src   : E(read);
    FA    : R;
%}

// Floating Point Convert I->L
pipe_class fcvtI2L(regD dst, regF src) %{
    single_instruction;
    dst   : X(write);
    src   : E(read);
    FA    : R;
%}

// Floating Point Convert D->F
pipe_class fcvtD2I(iRegI dst, regD src, flagsReg cr) %{
    instruction_count(1); multiple_bundles;
    dst   : X(write)+6;
    src   : E(read);
    FA    : R;
%}

// Floating Point Convert D->L
pipe_class fcvtD2L(regD dst, regD src, flagsReg cr) %{
    instruction_count(1); multiple_bundles;
    dst   : X(write)+6;
    src   : E(read);
    FA    : R;
%}

// Floating Point Convert F->I
pipe_class fcvtF2I(regF dst, regF src, flagsReg cr) %{
    instruction_count(1); multiple_bundles;
    dst   : X(write)+6;
    src   : E(read);
    FA    : R;
%}

// Floating Point Convert F->L
pipe_class fcvtF2L(regD dst, regF src, flagsReg cr) %{
    instruction_count(1); multiple_bundles;
    dst   : X(write)+6;
    src   : E(read);
    FA    : R;
%}

// Floating Point Convert I->F
pipe_class fcvtI2F(regF dst, regF src) %{
    single_instruction;
    dst   : X(write);
    src   : E(read);
    FA    : R;
%}

// Floating Point Compare
pipe_class faddF_fcc_reg_reg_zero(flagsRegF cr, regF src1, regF src2, immI0 zero) %{
    single_instruction;
    cr    : X(write);
    src1  : E(read);
    src2  : E(read);
    FA    : R;
%}

// Floating Point Compare
pipe_class faddD_fcc_reg_reg_zero(flagsRegF cr, regD src1, regD src2, immI0 zero) %{
    single_instruction;
    cr    : X(write);
    src1  : E(read);
    src2  : E(read);
    FA    : R;
%}

// Floating Add Nop
pipe_class fadd_nop() %{
    single_instruction;
    FA  : R;
%}

// Integer Store to Memory
pipe_class istore_mem_reg(memoryI mem, iRegI src) %{
    single_instruction;
    mem   : R(read);
    src   : C(read);
    MS    : R;
%}

// Integer Store to Memory
pipe_class istore_mem_spORreg(memoryI mem, sp_ptr_RegP src) %{
    single_instruction;
    mem   : R(read);
    src   : C(read);
    MS    : R;
%}

// Float Store
pipe_class fstoreF_mem_reg(memoryF mem, RegF src) %{
    single_instruction;
    mem : R(read);
    src : C(read);
    MS  : R;
%}

// Float Store
pipe_class fstoreF_mem_zero(memoryF mem, immF0 src) %{
    single_instruction;
    mem : R(read);
    MS  : R;
%}

// Double Store
pipe_class fstoreD_mem_reg(memoryD mem, RegD src) %{
    instruction_count(1);
    mem : R(read);
    src : C(read);
    MS  : R;
%}

// Double Store
pipe_class fstoreD_mem_zero(memoryD mem, immD0 src) %{
    single_instruction;
    mem : R(read);
    MS  : R;
%}

// Integer Load (when sign bit propagation not needed)
pipe_class iload_mem(iRegI dst, memoryI mem) %{
    single_instruction;
    mem : R(read);
    dst : C(write);
    MS  : R;
%}

// Integer Load (when sign bit propagation or masking is needed)
pipe_class iload_mask_mem(iRegI dst, memoryI mem) %{
    single_instruction;
    mem : R(read);
    dst : M(write);
    MS  : R;
%}

// Float Load
pipe_class floadF_mem(regF dst, memoryF mem) %{
    single_instruction;
    mem : R(read);
    dst : M(write);
    MS  : R;
%}

// Float Load
pipe_class floadD_mem(regD dst, memoryD mem) %{
    instruction_count(1); multiple_bundles; // Again, unaligned argument is only multiple case
    mem : R(read);
    dst : M(write);
    MS  : R;
%}

// Memory Nop
pipe_class mem_nop() %{
    single_instruction;
    MS  : R;
%}

pipe_class sethi(iRegP dst, immI src) %{
    single_instruction;
    dst  : E(write);
    IALU : R;
%}

pipe_class loadPollP(iRegP poll) %{
    single_instruction;
    poll : R(read);
    MS   : R;
%}

pipe_class br(Universe br, label labl) %{
    single_instruction_with_delay_slot;
    BR  : R;
%}

pipe_class br_cc(Universe br, cmpOp cmp, flagsReg cr, label labl) %{
    single_instruction_with_delay_slot;
    cr    : E(read);
    BR    : R;
%}

pipe_class br_reg(Universe br, cmpOp cmp, iRegI op1, label labl) %{
    single_instruction_with_delay_slot;
    op1 : E(read);
    BR  : R;
    MS  : R;
%}

pipe_class br_nop() %{
    single_instruction;
    BR  : R;
%}

pipe_class simple_call(method meth) %{
    instruction_count(2); multiple_bundles; force_serialization;
    fixed_latency(100);
    BR  : R(1);
    MS  : R(1);
    A0  : R(1);
%}

pipe_class compiled_call(method meth) %{
    instruction_count(1); multiple_bundles; force_serialization;
    fixed_latency(100);
    MS  : R(1);
%}

pipe_class call(method meth) %{
    instruction_count(0); multiple_bundles; force_serialization;
    fixed_latency(100);
%}

pipe_class tail_call(Universe ignore, label labl) %{
    single_instruction; has_delay_slot;
    fixed_latency(100);
    BR  : R(1);
    MS  : R(1);
%}

pipe_class ret(Universe ignore) %{
    single_instruction; has_delay_slot;
    BR  : R(1);
    MS  : R(1);
%}

// The real do-nothing guy
pipe_class empty( ) %{
    instruction_count(0);
%}

pipe_class long_memory_op() %{
    instruction_count(0); multiple_bundles; force_serialization;
    fixed_latency(25);
    MS  : R(1);
%}

// Check-cast
pipe_class partial_subtype_check_pipe(Universe ignore, iRegP array, iRegP match ) %{
    array : R(read);
    match  : R(read);
    IALU   : R(2);
    BR     : R(2);
    MS     : R;
%}

// Convert FPU flags into +1,0,-1
pipe_class floating_cmp( iRegI dst, regF src1, regF src2 ) %{
    src1  : E(read);
    src2  : E(read);
    dst   : E(write);
    FA    : R;
    MS    : R(2);
    BR    : R(2);
%}

// Compare for p < q, and conditionally add y
pipe_class cadd_cmpltmask( iRegI p, iRegI q, iRegI y ) %{
    p     : E(read);
    q     : E(read);
    y     : E(read);
    IALU  : R(3)
%}

// Perform a compare, then move conditionally in a branch delay slot.
pipe_class min_max( iRegI src2, iRegI srcdst ) %{
    src2   : E(read);
    srcdst : E(read);
    IALU   : R;
    BR     : R;
%}

// Define the class for the Nop node
define %{
   MachNop = ialu_nop;
%}

%}

//----------INSTRUCTIONS-------------------------------------------------------

//------------Special Nop instructions for bundling - no match rules-----------
// Nop using the A0 functional unit
instruct Nop_A0() %{
  ins_pipe(ialu_nop_A0);
%}

// Nop using the A1 functional unit
instruct Nop_A1( ) %{
  ins_pipe(ialu_nop_A1);
%}

// Nop using the memory functional unit
instruct Nop_MS( ) %{
  ins_pipe(mem_nop);
%}

// Nop using the floating add functional unit
instruct Nop_FA( ) %{
  ins_pipe(fadd_nop);
%}

// Nop using the branch functional unit
instruct Nop_BR( ) %{
  ins_pipe(br_nop);
%}

//----------Load/Store/Move Instructions---------------------------------------
//----------Load Instructions--------------------------------------------------
// Load Byte (8bit signed)
instruct loadB(iRegI dst, memoryB mem) %{
  match(Set dst (LoadB mem));
  ins_cost(MEMORY_REF_COST);

  size(4);
  format %{ "LDRSB   $dst,$mem\t! byte -> int" %}
  ins_encode %{
    __ ldrsb($dst$$Register, $mem$$Address);
  %}
  ins_pipe(iload_mask_mem);
%}

// Load Byte (8bit signed) into a Long Register
instruct loadB2L(iRegL dst, memoryB mem) %{
  match(Set dst (ConvI2L (LoadB mem)));
  ins_cost(MEMORY_REF_COST);

  size(8);
  format %{ "LDRSB $dst.lo,$mem\t! byte -> long\n\t"
            "ASR   $dst.hi,$dst.lo,31" %}
  ins_encode %{
    __ ldrsb($dst$$Register, $mem$$Address);
    __ mov($dst$$Register->successor(), AsmOperand($dst$$Register, asr, 31));
  %}
  ins_pipe(iload_mask_mem);
%}

// Load Unsigned Byte (8bit UNsigned) into an int reg
instruct loadUB(iRegI dst, memoryB mem) %{
  match(Set dst (LoadUB mem));
  ins_cost(MEMORY_REF_COST);

  size(4);
  format %{ "LDRB   $dst,$mem\t! ubyte -> int" %}
  ins_encode %{
    __ ldrb($dst$$Register, $mem$$Address);
  %}
  ins_pipe(iload_mem);
%}

// Load Unsigned Byte (8bit UNsigned) into a Long Register
instruct loadUB2L(iRegL dst, memoryB mem) %{
  match(Set dst (ConvI2L (LoadUB mem)));
  ins_cost(MEMORY_REF_COST);

  size(8);
  format %{ "LDRB  $dst.lo,$mem\t! ubyte -> long\n\t"
            "MOV   $dst.hi,0" %}
  ins_encode %{
    __ ldrb($dst$$Register, $mem$$Address);
    __ mov($dst$$Register->successor(), 0);
  %}
  ins_pipe(iload_mem);
%}

// Load Unsigned Byte (8 bit UNsigned) with immediate mask into Long Register
instruct loadUB2L_limmI(iRegL dst, memoryB mem, limmIlow8 mask) %{
  match(Set dst (ConvI2L (AndI (LoadUB mem) mask)));

  ins_cost(MEMORY_REF_COST + 2*DEFAULT_COST);
  size(12);
  format %{ "LDRB  $dst.lo,$mem\t! ubyte -> long\n\t"
            "MOV   $dst.hi,0\n\t"
            "AND  $dst.lo,$dst.lo,$mask" %}
  ins_encode %{
    __ ldrb($dst$$Register, $mem$$Address);
    __ mov($dst$$Register->successor(), 0);
    __ andr($dst$$Register, $dst$$Register, limmI_low($mask$$constant, 8));
  %}
  ins_pipe(iload_mem);
%}

// Load Short (16bit signed)

instruct loadS(iRegI dst, memoryS mem) %{
  match(Set dst (LoadS mem));
  ins_cost(MEMORY_REF_COST);

  size(4);
  format %{ "LDRSH   $dst,$mem\t! short" %}
  ins_encode %{
    __ ldrsh($dst$$Register, $mem$$Address);
  %}
  ins_pipe(iload_mask_mem);
%}

// Load Short (16 bit signed) to Byte (8 bit signed)
instruct loadS2B(iRegI dst, memoryS mem, immI_24 twentyfour) %{
  match(Set dst (RShiftI (LShiftI (LoadS mem) twentyfour) twentyfour));
  ins_cost(MEMORY_REF_COST);

  size(4);

  format %{ "LDRSB   $dst,$mem\t! short -> byte" %}
  ins_encode %{
    __ ldrsb($dst$$Register, $mem$$Address);
  %}
  ins_pipe(iload_mask_mem);
%}

// Load Short (16bit signed) into a Long Register
instruct loadS2L(iRegL dst, memoryS mem) %{
  match(Set dst (ConvI2L (LoadS mem)));
  ins_cost(MEMORY_REF_COST);

  size(8);
  format %{ "LDRSH $dst.lo,$mem\t! short -> long\n\t"
            "ASR   $dst.hi,$dst.lo,31" %}
  ins_encode %{
    __ ldrsh($dst$$Register, $mem$$Address);
    __ mov($dst$$Register->successor(), AsmOperand($dst$$Register, asr, 31));
  %}
  ins_pipe(iload_mask_mem);
%}

// Load Unsigned Short/Char (16bit UNsigned)


instruct loadUS(iRegI dst, memoryS mem) %{
  match(Set dst (LoadUS mem));
  ins_cost(MEMORY_REF_COST);

  size(4);
  format %{ "LDRH   $dst,$mem\t! ushort/char" %}
  ins_encode %{
    __ ldrh($dst$$Register, $mem$$Address);
  %}
  ins_pipe(iload_mem);
%}

// Load Unsigned Short/Char (16 bit UNsigned) to Byte (8 bit signed)
instruct loadUS2B(iRegI dst, memoryB mem, immI_24 twentyfour) %{
  match(Set dst (RShiftI (LShiftI (LoadUS mem) twentyfour) twentyfour));
  ins_cost(MEMORY_REF_COST);

  size(4);
  format %{ "LDRSB   $dst,$mem\t! ushort -> byte" %}
  ins_encode %{
    __ ldrsb($dst$$Register, $mem$$Address);
  %}
  ins_pipe(iload_mask_mem);
%}

// Load Unsigned Short/Char (16bit UNsigned) into a Long Register
instruct loadUS2L(iRegL dst, memoryS mem) %{
  match(Set dst (ConvI2L (LoadUS mem)));
  ins_cost(MEMORY_REF_COST);

  size(8);
  format %{ "LDRH  $dst.lo,$mem\t! short -> long\n\t"
            "MOV   $dst.hi, 0" %}
  ins_encode %{
    __ ldrh($dst$$Register, $mem$$Address);
    __ mov($dst$$Register->successor(), 0);
  %}
  ins_pipe(iload_mem);
%}

// Load Unsigned Short/Char (16bit UNsigned) with mask 0xFF into a Long Register
instruct loadUS2L_immI_255(iRegL dst, memoryB mem, immI_255 mask) %{
  match(Set dst (ConvI2L (AndI (LoadUS mem) mask)));
  ins_cost(MEMORY_REF_COST);

  size(8);
  format %{ "LDRB  $dst.lo,$mem\t! \n\t"
            "MOV   $dst.hi, 0" %}
  ins_encode %{
    __ ldrb($dst$$Register, $mem$$Address);
    __ mov($dst$$Register->successor(), 0);
  %}
  ins_pipe(iload_mem);
%}

// Load Unsigned Short/Char (16bit UNsigned) with a immediate mask into a Long Register
instruct loadUS2L_limmI(iRegL dst, memoryS mem, limmI mask) %{
  match(Set dst (ConvI2L (AndI (LoadUS mem) mask)));
  ins_cost(MEMORY_REF_COST + 2*DEFAULT_COST);

  size(12);
  format %{ "LDRH   $dst,$mem\t! ushort/char & mask -> long\n\t"
            "MOV    $dst.hi, 0\n\t"
            "AND    $dst,$dst,$mask" %}
  ins_encode %{
    __ ldrh($dst$$Register, $mem$$Address);
    __ mov($dst$$Register->successor(), 0);
    __ andr($dst$$Register, $dst$$Register, $mask$$constant);
  %}
  ins_pipe(iload_mem);
%}

// Load Integer


instruct loadI(iRegI dst, memoryI mem) %{
  match(Set dst (LoadI mem));
  ins_cost(MEMORY_REF_COST);

  size(4);
  format %{ "ldr_s32 $dst,$mem\t! int" %}
  ins_encode %{
    __ ldr_s32($dst$$Register, $mem$$Address);
  %}
  ins_pipe(iload_mem);
%}

// Load Integer to Byte (8 bit signed)
instruct loadI2B(iRegI dst, memoryS mem, immI_24 twentyfour) %{
  match(Set dst (RShiftI (LShiftI (LoadI mem) twentyfour) twentyfour));
  ins_cost(MEMORY_REF_COST);

  size(4);

  format %{ "LDRSB   $dst,$mem\t! int -> byte" %}
  ins_encode %{
    __ ldrsb($dst$$Register, $mem$$Address);
  %}
  ins_pipe(iload_mask_mem);
%}

// Load Integer to Unsigned Byte (8 bit UNsigned)
instruct loadI2UB(iRegI dst, memoryB mem, immI_255 mask) %{
  match(Set dst (AndI (LoadI mem) mask));
  ins_cost(MEMORY_REF_COST);

  size(4);

  format %{ "LDRB   $dst,$mem\t! int -> ubyte" %}
  ins_encode %{
    __ ldrb($dst$$Register, $mem$$Address);
  %}
  ins_pipe(iload_mask_mem);
%}

// Load Integer to Short (16 bit signed)
instruct loadI2S(iRegI dst, memoryS mem, immI_16 sixteen) %{
  match(Set dst (RShiftI (LShiftI (LoadI mem) sixteen) sixteen));
  ins_cost(MEMORY_REF_COST);

  size(4);
  format %{ "LDRSH   $dst,$mem\t! int -> short" %}
  ins_encode %{
    __ ldrsh($dst$$Register, $mem$$Address);
  %}
  ins_pipe(iload_mask_mem);
%}

// Load Integer to Unsigned Short (16 bit UNsigned)
instruct loadI2US(iRegI dst, memoryS mem, immI_65535 mask) %{
  match(Set dst (AndI (LoadI mem) mask));
  ins_cost(MEMORY_REF_COST);

  size(4);
  format %{ "LDRH   $dst,$mem\t! int -> ushort/char" %}
  ins_encode %{
    __ ldrh($dst$$Register, $mem$$Address);
  %}
  ins_pipe(iload_mask_mem);
%}

// Load Integer into a Long Register
instruct loadI2L(iRegL dst, memoryI mem) %{
  match(Set dst (ConvI2L (LoadI mem)));
  ins_cost(MEMORY_REF_COST);

  size(8);
  format %{ "LDR   $dst.lo,$mem\t! int -> long\n\t"
            "ASR   $dst.hi,$dst.lo,31\t! int->long" %}
  ins_encode %{
    __ ldr($dst$$Register, $mem$$Address);
    __ mov($dst$$Register->successor(), AsmOperand($dst$$Register, asr, 31));
  %}
  ins_pipe(iload_mask_mem);
%}

// Load Integer with mask 0xFF into a Long Register
instruct loadI2L_immI_255(iRegL dst, memoryB mem, immI_255 mask) %{
  match(Set dst (ConvI2L (AndI (LoadI mem) mask)));
  ins_cost(MEMORY_REF_COST);

  size(8);
  format %{ "LDRB   $dst.lo,$mem\t! int & 0xFF -> long\n\t"
            "MOV    $dst.hi, 0" %}
  ins_encode %{
    __ ldrb($dst$$Register, $mem$$Address);
    __ mov($dst$$Register->successor(), 0);
  %}
  ins_pipe(iload_mem);
%}

// Load Integer with mask 0xFFFF into a Long Register
instruct loadI2L_immI_65535(iRegL dst, memoryS mem, immI_65535 mask) %{
  match(Set dst (ConvI2L (AndI (LoadI mem) mask)));
  ins_cost(MEMORY_REF_COST);

  size(8);
  format %{ "LDRH   $dst,$mem\t! int & 0xFFFF -> long\n\t"
            "MOV    $dst.hi, 0" %}
  ins_encode %{
    __ ldrh($dst$$Register, $mem$$Address);
    __ mov($dst$$Register->successor(), 0);
  %}
  ins_pipe(iload_mask_mem);
%}

// Load Integer with a 31-bit immediate mask into a Long Register
instruct loadI2L_limmU31(iRegL dst, memoryI mem, limmU31 mask) %{
  match(Set dst (ConvI2L (AndI (LoadI mem) mask)));
  ins_cost(MEMORY_REF_COST + 2*DEFAULT_COST);

  size(12);
  format %{ "LDR   $dst.lo,$mem\t! int -> long\n\t"
            "MOV    $dst.hi, 0\n\t"
            "AND   $dst,$dst,$mask" %}

  ins_encode %{
    __ ldr($dst$$Register, $mem$$Address);
    __ mov($dst$$Register->successor(), 0);
    __ andr($dst$$Register, $dst$$Register, $mask$$constant);
  %}
  ins_pipe(iload_mem);
%}

// Load Integer with a 31-bit mask into a Long Register
// FIXME: use iRegI mask, remove tmp?
instruct loadI2L_immU31(iRegL dst, memoryI mem, immU31 mask, iRegI tmp) %{
  match(Set dst (ConvI2L (AndI (LoadI mem) mask)));
  effect(TEMP dst, TEMP tmp);

  ins_cost(MEMORY_REF_COST + 4*DEFAULT_COST);
  size(20);
  format %{ "LDR      $mem,$dst\t! int & 31-bit mask -> long\n\t"
            "MOV      $dst.hi, 0\n\t"
            "MOV_SLOW $tmp,$mask\n\t"
            "AND      $dst,$tmp,$dst" %}
  ins_encode %{
    __ ldr($dst$$Register, $mem$$Address);
    __ mov($dst$$Register->successor(), 0);
    __ mov_slow($tmp$$Register, $mask$$constant);
    __ andr($dst$$Register, $dst$$Register, $tmp$$Register);
  %}
  ins_pipe(iload_mem);
%}

// Load Unsigned Integer into a Long Register
instruct loadUI2L(iRegL dst, memoryI mem, immL_32bits mask) %{
  match(Set dst (AndL (ConvI2L (LoadI mem)) mask));
  ins_cost(MEMORY_REF_COST);

  size(8);
  format %{ "LDR   $dst.lo,$mem\t! uint -> long\n\t"
            "MOV   $dst.hi,0" %}
  ins_encode %{
    __ ldr($dst$$Register, $mem$$Address);
    __ mov($dst$$Register->successor(), 0);
  %}
  ins_pipe(iload_mem);
%}

// Load Long


instruct loadL(iRegLd dst, memoryL mem ) %{
  predicate(!((LoadLNode*)n)->require_atomic_access());
  match(Set dst (LoadL mem));
  effect(TEMP dst);
  ins_cost(MEMORY_REF_COST);

  size(4);
  format %{ "ldr_64  $dst,$mem\t! long" %}
  ins_encode %{
    __ ldr_64($dst$$Register, $mem$$Address);
  %}
  ins_pipe(iload_mem);
%}

instruct loadL_2instr(iRegL dst, memorylong mem ) %{
  predicate(!((LoadLNode*)n)->require_atomic_access());
  match(Set dst (LoadL mem));
  ins_cost(MEMORY_REF_COST + DEFAULT_COST);

  size(8);
  format %{ "LDR    $dst.lo,$mem \t! long order of instrs reversed if $dst.lo == base($mem)\n\t"
            "LDR    $dst.hi,$mem+4 or $mem" %}
  ins_encode %{
    Address Amemlo = Address::make_raw($mem$$base, $mem$$index, $mem$$scale, $mem$$disp, relocInfo::none);
    Address Amemhi = Address::make_raw($mem$$base, $mem$$index, $mem$$scale, $mem$$disp + 4, relocInfo::none);

    if ($dst$$Register == reg_to_register_object($mem$$base)) {
      __ ldr($dst$$Register->successor(), Amemhi);
      __ ldr($dst$$Register, Amemlo);
    } else {
      __ ldr($dst$$Register, Amemlo);
      __ ldr($dst$$Register->successor(), Amemhi);
    }
  %}
  ins_pipe(iload_mem);
%}

instruct loadL_volatile(iRegL dst, indirect mem ) %{
  predicate(((LoadLNode*)n)->require_atomic_access());
  match(Set dst (LoadL mem));
  ins_cost(MEMORY_REF_COST);

  size(4);
  format %{ "LDMIA    $dst,$mem\t! long" %}
  ins_encode %{
    // FIXME: why is ldmia considered atomic?  Should be ldrexd
    RegisterSet set($dst$$Register);
    set = set | reg_to_register_object($dst$$reg + 1);
    __ ldmia(reg_to_register_object($mem$$base), set);
  %}
  ins_pipe(iload_mem);
%}

instruct loadL_volatile_fp(iRegL dst, memoryD mem ) %{
  predicate(((LoadLNode*)n)->require_atomic_access());
  match(Set dst (LoadL mem));
  ins_cost(MEMORY_REF_COST);

  size(8);
  format %{ "FLDD      S14, $mem"
            "FMRRD    $dst, S14\t! long \n't" %}
  ins_encode %{
    __ fldd(S14, $mem$$Address);
    __ fmrrd($dst$$Register, $dst$$Register->successor(), S14);
  %}
  ins_pipe(iload_mem);
%}

instruct loadL_unaligned(iRegL dst, memorylong mem ) %{
  match(Set dst (LoadL_unaligned mem));
  ins_cost(MEMORY_REF_COST);

  size(8);
  format %{ "LDR    $dst.lo,$mem\t! long order of instrs reversed if $dst.lo == base($mem)\n\t"
            "LDR    $dst.hi,$mem+4" %}
  ins_encode %{
    Address Amemlo = Address::make_raw($mem$$base, $mem$$index, $mem$$scale, $mem$$disp, relocInfo::none);
    Address Amemhi = Address::make_raw($mem$$base, $mem$$index, $mem$$scale, $mem$$disp + 4, relocInfo::none);

    if ($dst$$Register == reg_to_register_object($mem$$base)) {
      __ ldr($dst$$Register->successor(), Amemhi);
      __ ldr($dst$$Register, Amemlo);
    } else {
      __ ldr($dst$$Register, Amemlo);
      __ ldr($dst$$Register->successor(), Amemhi);
    }
  %}
  ins_pipe(iload_mem);
%}

// Load Range
instruct loadRange(iRegI dst, memoryI mem) %{
  match(Set dst (LoadRange mem));
  ins_cost(MEMORY_REF_COST);

  size(4);
  format %{ "LDR_u32 $dst,$mem\t! range" %}
  ins_encode %{
    __ ldr_u32($dst$$Register, $mem$$Address);
  %}
  ins_pipe(iload_mem);
%}

// Load Pointer


instruct loadP(iRegP dst, memoryP mem) %{
  match(Set dst (LoadP mem));
  ins_cost(MEMORY_REF_COST);
  size(4);

  format %{ "LDR   $dst,$mem\t! ptr" %}
  ins_encode %{
    __ ldr($dst$$Register, $mem$$Address);
  %}
  ins_pipe(iload_mem);
%}

#ifdef XXX
// FIXME XXXX
//instruct loadSP(iRegP dst, memoryP mem) %{
instruct loadSP(SPRegP dst, memoryP mem, iRegP tmp) %{
  match(Set dst (LoadP mem));
  effect(TEMP tmp);
  ins_cost(MEMORY_REF_COST+1);
  size(8);

  format %{ "LDR   $tmp,$mem\t! ptr\n\t"
            "MOV   $dst,$tmp\t! ptr" %}
  ins_encode %{
    __ ldr($tmp$$Register, $mem$$Address);
    __ mov($dst$$Register, $tmp$$Register);
  %}
  ins_pipe(iload_mem);
%}
#endif

#ifdef _LP64
// Load Compressed Pointer

// XXX This variant shouldn't be necessary if 6217251 is implemented
instruct loadNoff(iRegN dst, memoryScaledI mem, aimmX off, iRegP tmp) %{
  match(Set dst (LoadN (AddP mem off)));
  ins_cost(MEMORY_REF_COST + DEFAULT_COST); // assume shift/sign-extend is free
  effect(TEMP tmp);
  size(4 * 2);

  format %{ "ldr_u32 $dst,$mem+$off\t! compressed ptr temp=$tmp" %}
  ins_encode %{
    Register base = reg_to_register_object($mem$$base);
    __ add($tmp$$Register, base, $off$$constant);
    Address nmem = Address::make_raw($tmp$$reg, $mem$$index, $mem$$scale, $mem$$disp, relocInfo::none);
    __ ldr_u32($dst$$Register, nmem);
  %}
  ins_pipe(iload_mem);
%}

instruct loadN(iRegN dst, memoryI mem) %{
  match(Set dst (LoadN mem));
  ins_cost(MEMORY_REF_COST);
  size(4);

  format %{ "ldr_u32 $dst,$mem\t! compressed ptr" %}
  ins_encode %{
    __ ldr_u32($dst$$Register, $mem$$Address);
  %}
  ins_pipe(iload_mem);
%}
#endif

// Load Klass Pointer
instruct loadKlass(iRegP dst, memoryI mem) %{
  match(Set dst (LoadKlass mem));
  ins_cost(MEMORY_REF_COST);
  size(4);

  format %{ "LDR   $dst,$mem\t! klass ptr" %}
  ins_encode %{
    __ ldr($dst$$Register, $mem$$Address);
  %}
  ins_pipe(iload_mem);
%}

#ifdef _LP64
// Load narrow Klass Pointer
instruct loadNKlass(iRegN dst, memoryI mem) %{
  match(Set dst (LoadNKlass mem));
  ins_cost(MEMORY_REF_COST);
  size(4);

  format %{ "ldr_u32 $dst,$mem\t! compressed klass ptr" %}
  ins_encode %{
    __ ldr_u32($dst$$Register, $mem$$Address);
  %}
  ins_pipe(iload_mem);
%}
#endif


instruct loadD(regD dst, memoryD mem) %{
  match(Set dst (LoadD mem));
  ins_cost(MEMORY_REF_COST);

  size(4);
  // FIXME: needs to be atomic, but  ARMv7 A.R.M. guarantees
  // only LDREXD and STREXD are 64-bit single-copy atomic
  format %{ "FLDD   $dst,$mem" %}
  ins_encode %{
    __ ldr_double($dst$$FloatRegister, $mem$$Address);
  %}
  ins_pipe(floadD_mem);
%}

// Load Double - UNaligned
instruct loadD_unaligned(regD_low dst, memoryF2 mem ) %{
  match(Set dst (LoadD_unaligned mem));
  ins_cost(MEMORY_REF_COST*2+DEFAULT_COST);
  size(8);
  format %{ "FLDS    $dst.lo,$mem\t! misaligned double\n"
          "\tFLDS    $dst.hi,$mem+4\t!" %}
  ins_encode %{
    Address Amemlo = Address::make_raw($mem$$base, $mem$$index, $mem$$scale, $mem$$disp, relocInfo::none);
    Address Amemhi = Address::make_raw($mem$$base, $mem$$index, $mem$$scale, $mem$$disp + 4, relocInfo::none);
      __ flds($dst$$FloatRegister, Amemlo);
      __ flds($dst$$FloatRegister->successor(), Amemhi);
  %}
  ins_pipe(iload_mem);
%}


instruct loadF(regF dst, memoryF mem) %{
  match(Set dst (LoadF mem));

  ins_cost(MEMORY_REF_COST);
  size(4);
  format %{ "FLDS    $dst,$mem" %}
  ins_encode %{
    __ ldr_float($dst$$FloatRegister, $mem$$Address);
  %}
  ins_pipe(floadF_mem);
%}


// // Load Constant
instruct loadConI( iRegI dst, immI src ) %{
  match(Set dst src);
  ins_cost(DEFAULT_COST * 3/2);
  format %{ "MOV_SLOW    $dst, $src" %}
  ins_encode %{
    __ mov_slow($dst$$Register, $src$$constant);
  %}
  ins_pipe(ialu_hi_lo_reg);
%}

instruct loadConIMov( iRegI dst, immIMov src ) %{
  match(Set dst src);
  size(4);
  format %{ "MOV    $dst, $src" %}
  ins_encode %{
    __ mov($dst$$Register, $src$$constant);
  %}
  ins_pipe(ialu_imm);
%}

instruct loadConIMovn( iRegI dst, immIRotn src ) %{
  match(Set dst src);
  size(4);
  format %{ "MVN    $dst, ~$src" %}
  ins_encode %{
    __ mvn($dst$$Register, ~$src$$constant);
  %}
  ins_pipe(ialu_imm_n);
%}

instruct loadConI16( iRegI dst, immI16 src ) %{
  match(Set dst src);
  size(4);
  format %{ "MOVW    $dst, $src" %}
  ins_encode %{
    __ movw($dst$$Register, $src$$constant);
  %}
  ins_pipe(ialu_imm_n);
%}

instruct loadConP(iRegP dst, immP src) %{
  match(Set dst src);
  ins_cost(DEFAULT_COST * 3/2);
  format %{ "MOV_SLOW    $dst,$src\t!ptr" %}
  ins_encode %{
    relocInfo::relocType constant_reloc = _opnds[1]->constant_reloc();
    intptr_t val = $src$$constant;
    if (constant_reloc == relocInfo::oop_type) {
      __ mov_oop($dst$$Register, (jobject)val);
    } else if (constant_reloc == relocInfo::metadata_type) {
      __ mov_metadata($dst$$Register, (Metadata*)val);
    } else {
      __ mov_slow($dst$$Register, val);
    }
  %}
  ins_pipe(loadConP);
%}


instruct loadConL(iRegL dst, immL src) %{
  match(Set dst src);
  ins_cost(DEFAULT_COST * 4);
  format %{ "MOV_SLOW   $dst.lo, $src & 0x0FFFFFFFFL \t! long\n\t"
            "MOV_SLOW   $dst.hi, $src >> 32" %}
  ins_encode %{
    __ mov_slow(reg_to_register_object($dst$$reg), $src$$constant & 0x0FFFFFFFFL);
    __ mov_slow(reg_to_register_object($dst$$reg + 1), ((julong)($src$$constant)) >> 32);
  %}
  ins_pipe(loadConL);
%}

instruct loadConL16( iRegL dst, immL16 src ) %{
  match(Set dst src);
  ins_cost(DEFAULT_COST * 2);

  size(8);
  format %{ "MOVW    $dst.lo, $src \n\t"
            "MOVW    $dst.hi, 0 \n\t" %}
  ins_encode %{
    __ movw($dst$$Register, $src$$constant);
    __ movw($dst$$Register->successor(), 0);
  %}
  ins_pipe(ialu_imm);
%}

instruct loadConF_imm8(regF dst, imm8F src) %{
  match(Set dst src);
  ins_cost(DEFAULT_COST);
  size(4);

  format %{ "FCONSTS      $dst, $src"%}

  ins_encode %{
    __ fconsts($dst$$FloatRegister, Assembler::float_num($src$$constant).imm8());
  %}
  ins_pipe(loadConFD); // FIXME
%}


instruct loadConF(regF dst, immF src, iRegI tmp) %{
  match(Set dst src);
  ins_cost(DEFAULT_COST * 2);
  effect(TEMP tmp);
  size(3*4);

  format %{ "MOV_SLOW  $tmp, $src\n\t"
            "FMSR      $dst, $tmp"%}

  ins_encode %{
    // FIXME revisit once 6961697 is in
    union {
      jfloat f;
      int i;
    } v;
    v.f = $src$$constant;
    __ mov_slow($tmp$$Register, v.i);
    __ fmsr($dst$$FloatRegister, $tmp$$Register);
  %}
  ins_pipe(loadConFD); // FIXME
%}

instruct loadConD_imm8(regD dst, imm8D src) %{
  match(Set dst src);
  ins_cost(DEFAULT_COST);
  size(4);

  format %{ "FCONSTD      $dst, $src"%}

  ins_encode %{
    __ fconstd($dst$$FloatRegister, Assembler::double_num($src$$constant).imm8());
  %}
  ins_pipe(loadConFD); // FIXME
%}

instruct loadConD(regD dst, immD src, iRegP tmp) %{
  match(Set dst src);
  effect(TEMP tmp);
  ins_cost(MEMORY_REF_COST);
  format %{ "FLDD  $dst, [$constanttablebase + $constantoffset]\t! load from constant table: double=$src" %}

  ins_encode %{
    Register r = $constanttablebase;
    int offset  = $constantoffset($src);
    if (!is_memoryD(offset)) {                // can't use a predicate
                                              // in load constant instructs
      __ add_slow($tmp$$Register, r, offset);
      r = $tmp$$Register;
      offset = 0;
    }
    __ ldr_double($dst$$FloatRegister, Address(r, offset));
  %}
  ins_pipe(loadConFD);
%}

// Prefetch instructions.
// Must be safe to execute with invalid address (cannot fault).

instruct prefetchAlloc_mp( memoryP mem ) %{
  predicate(VM_Version::has_multiprocessing_extensions());
  match( PrefetchAllocation mem );
  ins_cost(MEMORY_REF_COST);
  size(4);

  format %{ "PLDW $mem\t! Prefetch allocation" %}
  ins_encode %{
    __ pldw($mem$$Address);
  %}
  ins_pipe(iload_mem);
%}

instruct prefetchAlloc_sp( memoryP mem ) %{
  predicate(!VM_Version::has_multiprocessing_extensions());
  match( PrefetchAllocation mem );
  ins_cost(MEMORY_REF_COST);
  size(4);

  format %{ "PLD $mem\t! Prefetch allocation" %}
  ins_encode %{
    __ pld($mem$$Address);
  %}
  ins_pipe(iload_mem);
%}


//----------Store Instructions-------------------------------------------------
// Store Byte
instruct storeB(memoryB mem, store_RegI src) %{
  match(Set mem (StoreB mem src));
  ins_cost(MEMORY_REF_COST);

  size(4);
  format %{ "STRB    $src,$mem\t! byte" %}
  ins_encode %{
    __ strb($src$$Register, $mem$$Address);
  %}
  ins_pipe(istore_mem_reg);
%}

instruct storeCM(memoryB mem, store_RegI src) %{
  match(Set mem (StoreCM mem src));
  ins_cost(MEMORY_REF_COST);

  size(4);
  format %{ "STRB    $src,$mem\t! CMS card-mark byte" %}
  ins_encode %{
    __ strb($src$$Register, $mem$$Address);
  %}
  ins_pipe(istore_mem_reg);
%}

// Store Char/Short


instruct storeC(memoryS mem, store_RegI src) %{
  match(Set mem (StoreC mem src));
  ins_cost(MEMORY_REF_COST);

  size(4);
  format %{ "STRH    $src,$mem\t! short" %}
  ins_encode %{
    __ strh($src$$Register, $mem$$Address);
  %}
  ins_pipe(istore_mem_reg);
%}

// Store Integer


instruct storeI(memoryI mem, store_RegI src) %{
  match(Set mem (StoreI mem src));
  ins_cost(MEMORY_REF_COST);

  size(4);
  format %{ "str_32 $src,$mem" %}
  ins_encode %{
    __ str_32($src$$Register, $mem$$Address);
  %}
  ins_pipe(istore_mem_reg);
%}

// Store Long


instruct storeL(memoryL mem, store_RegLd src) %{
  predicate(!((StoreLNode*)n)->require_atomic_access());
  match(Set mem (StoreL mem src));
  ins_cost(MEMORY_REF_COST);

  size(4);
  format %{ "str_64  $src,$mem\t! long\n\t" %}

  ins_encode %{
    __ str_64($src$$Register, $mem$$Address);
  %}
  ins_pipe(istore_mem_reg);
%}

instruct storeL_2instr(memorylong mem, iRegL src) %{
  predicate(!((StoreLNode*)n)->require_atomic_access());
  match(Set mem (StoreL mem src));
  ins_cost(MEMORY_REF_COST + DEFAULT_COST);

  size(8);
  format %{ "STR    $src.lo,$mem\t! long\n\t"
            "STR    $src.hi,$mem+4" %}

  ins_encode %{
    Address Amemlo = Address::make_raw($mem$$base, $mem$$index, $mem$$scale, $mem$$disp, relocInfo::none);
    Address Amemhi = Address::make_raw($mem$$base, $mem$$index, $mem$$scale, $mem$$disp + 4, relocInfo::none);
    __ str($src$$Register, Amemlo);
    __ str($src$$Register->successor(), Amemhi);
  %}
  ins_pipe(istore_mem_reg);
%}

instruct storeL_volatile(indirect mem, iRegL src) %{
  predicate(((StoreLNode*)n)->require_atomic_access());
  match(Set mem (StoreL mem src));
  ins_cost(MEMORY_REF_COST);
  size(4);
  format %{ "STMIA    $src,$mem\t! long" %}
  ins_encode %{
    // FIXME: why is stmia considered atomic?  Should be strexd
    RegisterSet set($src$$Register);
    set = set | reg_to_register_object($src$$reg + 1);
    __ stmia(reg_to_register_object($mem$$base), set);
  %}
  ins_pipe(istore_mem_reg);
%}

instruct storeL_volatile_fp(memoryD mem, iRegL src) %{
  predicate(((StoreLNode*)n)->require_atomic_access());
  match(Set mem (StoreL mem src));
  ins_cost(MEMORY_REF_COST);
  size(8);
  format %{ "FMDRR    S14, $src\t! long \n\t"
            "FSTD     S14, $mem" %}
  ins_encode %{
    __ fmdrr(S14, $src$$Register, $src$$Register->successor());
    __ fstd(S14, $mem$$Address);
  %}
  ins_pipe(istore_mem_reg);
%}

#ifdef XXX
// Move SP Pointer
//instruct movSP(sp_ptr_RegP dst, SPRegP src) %{
//instruct movSP(iRegP dst, SPRegP src) %{
instruct movSP(store_ptr_RegP dst, SPRegP src) %{
  match(Set dst src);
//predicate(!_kids[1]->_leaf->is_Proj() || _kids[1]->_leaf->as_Proj()->_con == TypeFunc::FramePtr);
  ins_cost(MEMORY_REF_COST);
  size(4);

  format %{ "MOV    $dst,$src\t! SP ptr\n\t" %}
  ins_encode %{
    assert(false, "XXX1 got here");
    __ mov($dst$$Register, SP);
    __ mov($dst$$Register, $src$$Register);
  %}
  ins_pipe(ialu_reg);
%}
#endif


// Store Pointer


instruct storeP(memoryP mem, store_ptr_RegP src) %{
  match(Set mem (StoreP mem src));
  ins_cost(MEMORY_REF_COST);
  size(4);

  format %{ "STR    $src,$mem\t! ptr" %}
  ins_encode %{
    __ str($src$$Register, $mem$$Address);
  %}
  ins_pipe(istore_mem_spORreg);
%}


#ifdef _LP64
// Store Compressed Pointer


instruct storeN(memoryI mem, store_RegN src) %{
  match(Set mem (StoreN mem src));
  ins_cost(MEMORY_REF_COST);
  size(4);

  format %{ "str_32 $src,$mem\t! compressed ptr" %}
  ins_encode %{
    __ str_32($src$$Register, $mem$$Address);
  %}
  ins_pipe(istore_mem_reg);
%}


// Store Compressed Klass Pointer
instruct storeNKlass(memoryI mem, store_RegN src) %{
  match(Set mem (StoreNKlass mem src));
  ins_cost(MEMORY_REF_COST);
  size(4);

  format %{ "str_32 $src,$mem\t! compressed klass ptr" %}
  ins_encode %{
    __ str_32($src$$Register, $mem$$Address);
  %}
  ins_pipe(istore_mem_reg);
%}
#endif

// Store Double


instruct storeD(memoryD mem, regD src) %{
  match(Set mem (StoreD mem src));
  ins_cost(MEMORY_REF_COST);

  size(4);
  // FIXME: needs to be atomic, but  ARMv7 A.R.M. guarantees
  // only LDREXD and STREXD are 64-bit single-copy atomic
  format %{ "FSTD   $src,$mem" %}
  ins_encode %{
    __ str_double($src$$FloatRegister, $mem$$Address);
  %}
  ins_pipe(fstoreD_mem_reg);
%}


// Store Float


instruct storeF( memoryF mem, regF src) %{
  match(Set mem (StoreF mem src));
  ins_cost(MEMORY_REF_COST);

  size(4);
  format %{ "FSTS    $src,$mem" %}
  ins_encode %{
    __ str_float($src$$FloatRegister, $mem$$Address);
  %}
  ins_pipe(fstoreF_mem_reg);
%}


//----------MemBar Instructions-----------------------------------------------
// Memory barrier flavors

// pattern-match out unnecessary membars
instruct membar_storestore() %{
  match(MemBarStoreStore);
  match(StoreStoreFence);
  ins_cost(4*MEMORY_REF_COST);

  size(4);
  format %{ "MEMBAR-storestore" %}
  ins_encode %{
    __ membar(MacroAssembler::Membar_mask_bits(MacroAssembler::StoreStore), noreg);
  %}
  ins_pipe(long_memory_op);
%}

instruct membar_acquire() %{
  match(MemBarAcquire);
  match(LoadFence);
  ins_cost(4*MEMORY_REF_COST);

  size(4);
  format %{ "MEMBAR-acquire" %}
  ins_encode %{
    __ membar(MacroAssembler::Membar_mask_bits(MacroAssembler::LoadLoad | MacroAssembler::LoadStore), noreg);
  %}
  ins_pipe(long_memory_op);
%}

instruct membar_acquire_lock() %{
  match(MemBarAcquireLock);
  ins_cost(0);

  size(0);
  format %{ "!MEMBAR-acquire (CAS in prior FastLock so empty encoding)" %}
  ins_encode( );
  ins_pipe(empty);
%}

instruct membar_release() %{
  match(MemBarRelease);
  match(StoreFence);
  ins_cost(4*MEMORY_REF_COST);

  size(4);
  format %{ "MEMBAR-release" %}
  ins_encode %{
    __ membar(MacroAssembler::Membar_mask_bits(MacroAssembler::StoreStore | MacroAssembler::LoadStore), noreg);
  %}
  ins_pipe(long_memory_op);
%}

instruct membar_release_lock() %{
  match(MemBarReleaseLock);
  ins_cost(0);

  size(0);
  format %{ "!MEMBAR-release (CAS in succeeding FastUnlock so empty encoding)" %}
  ins_encode( );
  ins_pipe(empty);
%}

instruct membar_volatile() %{
  match(MemBarVolatile);
  ins_cost(4*MEMORY_REF_COST);

  size(4);
  format %{ "MEMBAR-volatile" %}
  ins_encode %{
    __ membar(MacroAssembler::StoreLoad, noreg);
  %}
  ins_pipe(long_memory_op);
%}

instruct unnecessary_membar_volatile() %{
  match(MemBarVolatile);
  predicate(Matcher::post_store_load_barrier(n));
  ins_cost(0);

  size(0);
  format %{ "!MEMBAR-volatile (unnecessary so empty encoding)" %}
  ins_encode( );
  ins_pipe(empty);
%}

//----------Register Move Instructions-----------------------------------------
// instruct roundDouble_nop(regD dst) %{
//   match(Set dst (RoundDouble dst));
//   ins_pipe(empty);
// %}


// instruct roundFloat_nop(regF dst) %{
//   match(Set dst (RoundFloat dst));
//   ins_pipe(empty);
// %}



// Cast Index to Pointer for unsafe natives
instruct castX2P(iRegX src, iRegP dst) %{
  match(Set dst (CastX2P src));

  format %{ "MOV    $dst,$src\t! IntX->Ptr if $dst != $src" %}
  ins_encode %{
    if ($dst$$Register !=  $src$$Register) {
      __ mov($dst$$Register, $src$$Register);
    }
  %}
  ins_pipe(ialu_reg);
%}

// Cast Pointer to Index for unsafe natives
instruct castP2X(iRegP src, iRegX dst) %{
  match(Set dst (CastP2X src));

  format %{ "MOV    $dst,$src\t! Ptr->IntX if $dst != $src" %}
  ins_encode %{
    if ($dst$$Register !=  $src$$Register) {
      __ mov($dst$$Register, $src$$Register);
    }
  %}
  ins_pipe(ialu_reg);
%}

//----------Conditional Move---------------------------------------------------
// Conditional move
instruct cmovIP_reg(cmpOpP cmp, flagsRegP pcc, iRegI dst, iRegI src) %{
  match(Set dst (CMoveI (Binary cmp pcc) (Binary dst src)));
  ins_cost(150);
  size(4);
  format %{ "MOV$cmp  $dst,$src\t! int" %}
  ins_encode %{
    __ mov($dst$$Register, $src$$Register, (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(ialu_reg);
%}


instruct cmovIP_immMov(cmpOpP cmp, flagsRegP pcc, iRegI dst, immIMov src) %{
  match(Set dst (CMoveI (Binary cmp pcc) (Binary dst src)));
  ins_cost(140);
  size(4);
  format %{ "MOV$cmp  $dst,$src" %}
  ins_encode %{
    __ mov($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(ialu_imm);
%}

instruct cmovIP_imm16(cmpOpP cmp, flagsRegP pcc, iRegI dst, immI16 src) %{
  match(Set dst (CMoveI (Binary cmp pcc) (Binary dst src)));
  ins_cost(140);
  size(4);
  format %{ "MOVw$cmp  $dst,$src" %}
  ins_encode %{
    __ movw($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(ialu_imm);
%}

instruct cmovI_reg(cmpOp cmp, flagsReg icc, iRegI dst, iRegI src) %{
  match(Set dst (CMoveI (Binary cmp icc) (Binary dst src)));
  ins_cost(150);
  size(4);
  format %{ "MOV$cmp  $dst,$src" %}
  ins_encode %{
    __ mov($dst$$Register, $src$$Register, (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(ialu_reg);
%}


instruct cmovI_immMov(cmpOp cmp, flagsReg icc, iRegI dst, immIMov src) %{
  match(Set dst (CMoveI (Binary cmp icc) (Binary dst src)));
  ins_cost(140);
  size(4);
  format %{ "MOV$cmp  $dst,$src" %}
  ins_encode %{
    __ mov($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(ialu_imm);
%}

instruct cmovII_imm16(cmpOp cmp, flagsReg icc, iRegI dst, immI16 src) %{
  match(Set dst (CMoveI (Binary cmp icc) (Binary dst src)));
  ins_cost(140);
  size(4);
  format %{ "MOVw$cmp  $dst,$src" %}
  ins_encode %{
    __ movw($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(ialu_imm);
%}

instruct cmovII_reg_EQNELTGE(cmpOp0 cmp, flagsReg_EQNELTGE icc, iRegI dst, iRegI src) %{
  match(Set dst (CMoveI (Binary cmp icc) (Binary dst src)));
  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq ||
            _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne ||
            _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt ||
            _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge);
  ins_cost(150);
  size(4);
  format %{ "MOV$cmp  $dst,$src" %}
  ins_encode %{
    __ mov($dst$$Register, $src$$Register, (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(ialu_reg);
%}

instruct cmovII_immMov_EQNELTGE(cmpOp0 cmp, flagsReg_EQNELTGE icc, iRegI dst, immIMov src) %{
  match(Set dst (CMoveI (Binary cmp icc) (Binary dst src)));
  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq ||
            _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne ||
            _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt ||
            _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge);
  ins_cost(140);
  size(4);
  format %{ "MOV$cmp  $dst,$src" %}
  ins_encode %{
    __ mov($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(ialu_imm);
%}

instruct cmovII_imm16_EQNELTGE(cmpOp0 cmp, flagsReg_EQNELTGE icc, iRegI dst, immI16 src) %{
  match(Set dst (CMoveI (Binary cmp icc) (Binary dst src)));
  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq ||
            _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne ||
            _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt ||
            _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge);
  ins_cost(140);
  size(4);
  format %{ "MOVW$cmp  $dst,$src" %}
  ins_encode %{
    __ movw($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(ialu_imm);
%}

instruct cmovIIu_reg(cmpOpU cmp, flagsRegU icc, iRegI dst, iRegI src) %{
  match(Set dst (CMoveI (Binary cmp icc) (Binary dst src)));
  ins_cost(150);
  size(4);
  format %{ "MOV$cmp  $dst,$src" %}
  ins_encode %{
    __ mov($dst$$Register, $src$$Register, (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(ialu_reg);
%}

instruct cmovIIu_immMov(cmpOpU cmp, flagsRegU icc, iRegI dst, immIMov src) %{
  match(Set dst (CMoveI (Binary cmp icc) (Binary dst src)));
  ins_cost(140);
  size(4);
  format %{ "MOV$cmp  $dst,$src" %}
  ins_encode %{
    __ mov($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(ialu_imm);
%}

instruct cmovIIu_imm16(cmpOpU cmp, flagsRegU icc, iRegI dst, immI16 src) %{
  match(Set dst (CMoveI (Binary cmp icc) (Binary dst src)));
  ins_cost(140);
  size(4);
  format %{ "MOVW$cmp  $dst,$src" %}
  ins_encode %{
    __ movw($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(ialu_imm);
%}

// Conditional move
instruct cmovPP_reg(cmpOpP cmp, flagsRegP pcc, iRegP dst, iRegP src) %{
  match(Set dst (CMoveP (Binary cmp pcc) (Binary dst src)));
  ins_cost(150);
  size(4);
  format %{ "MOV$cmp  $dst,$src" %}
  ins_encode %{
    __ mov($dst$$Register, $src$$Register, (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(ialu_reg);
%}

instruct cmovPP_imm(cmpOpP cmp, flagsRegP pcc, iRegP dst, immP0 src) %{
  match(Set dst (CMoveP (Binary cmp pcc) (Binary dst src)));
  ins_cost(140);
  size(4);
  format %{ "MOV$cmp  $dst,$src" %}
  ins_encode %{
    __ mov($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(ialu_imm);
%}

// This instruction also works with CmpN so we don't need cmovPN_reg.
instruct cmovPI_reg(cmpOp cmp, flagsReg icc, iRegP dst, iRegP src) %{
  match(Set dst (CMoveP (Binary cmp icc) (Binary dst src)));
  ins_cost(150);

  size(4);
  format %{ "MOV$cmp  $dst,$src\t! ptr" %}
  ins_encode %{
    __ mov($dst$$Register, $src$$Register, (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(ialu_reg);
%}

instruct cmovPI_reg_EQNELTGE(cmpOp0 cmp, flagsReg_EQNELTGE icc, iRegP dst, iRegP src) %{
  match(Set dst (CMoveP (Binary cmp icc) (Binary dst src)));
  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq ||
            _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne ||
            _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt ||
            _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge);
  ins_cost(150);

  size(4);
  format %{ "MOV$cmp  $dst,$src\t! ptr" %}
  ins_encode %{
    __ mov($dst$$Register, $src$$Register, (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(ialu_reg);
%}

instruct cmovPIu_reg(cmpOpU cmp, flagsRegU icc, iRegP dst, iRegP src) %{
  match(Set dst (CMoveP (Binary cmp icc) (Binary dst src)));
  ins_cost(150);

  size(4);
  format %{ "MOV$cmp  $dst,$src\t! ptr" %}
  ins_encode %{
    __ mov($dst$$Register, $src$$Register, (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(ialu_reg);
%}

instruct cmovPI_imm(cmpOp cmp, flagsReg icc, iRegP dst, immP0 src) %{
  match(Set dst (CMoveP (Binary cmp icc) (Binary dst src)));
  ins_cost(140);

  size(4);
  format %{ "MOV$cmp  $dst,$src\t! ptr" %}
  ins_encode %{
    __ mov($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(ialu_imm);
%}

instruct cmovPI_imm_EQNELTGE(cmpOp0 cmp, flagsReg_EQNELTGE icc, iRegP dst, immP0 src) %{
  match(Set dst (CMoveP (Binary cmp icc) (Binary dst src)));
  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq ||
            _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne ||
            _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt ||
            _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge);
  ins_cost(140);

  size(4);
  format %{ "MOV$cmp  $dst,$src\t! ptr" %}
  ins_encode %{
    __ mov($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(ialu_imm);
%}

instruct cmovPIu_imm(cmpOpU cmp, flagsRegU icc, iRegP dst, immP0 src) %{
  match(Set dst (CMoveP (Binary cmp icc) (Binary dst src)));
  ins_cost(140);

  size(4);
  format %{ "MOV$cmp  $dst,$src\t! ptr" %}
  ins_encode %{
    __ mov($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(ialu_imm);
%}


// Conditional move
instruct cmovFP_reg(cmpOpP cmp, flagsRegP pcc, regF dst, regF src) %{
  match(Set dst (CMoveF (Binary cmp pcc) (Binary dst src)));
  ins_cost(150);
  size(4);
  format %{ "FCPYS$cmp $dst,$src" %}
  ins_encode %{
    __ fcpys($dst$$FloatRegister, $src$$FloatRegister, (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(int_conditional_float_move);
%}

instruct cmovFI_reg(cmpOp cmp, flagsReg icc, regF dst, regF src) %{
  match(Set dst (CMoveF (Binary cmp icc) (Binary dst src)));
  ins_cost(150);

  size(4);
  format %{ "FCPYS$cmp $dst,$src" %}
  ins_encode %{
    __ fcpys($dst$$FloatRegister, $src$$FloatRegister, (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(int_conditional_float_move);
%}

instruct cmovFI_reg_EQNELTGE(cmpOp0 cmp, flagsReg_EQNELTGE icc, regF dst, regF src) %{
  match(Set dst (CMoveF (Binary cmp icc) (Binary dst src)));
  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq ||
            _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne ||
            _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt ||
            _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge);
  ins_cost(150);

  size(4);
  format %{ "FCPYS$cmp $dst,$src" %}
  ins_encode %{
    __ fcpys($dst$$FloatRegister, $src$$FloatRegister, (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(int_conditional_float_move);
%}

instruct cmovFIu_reg(cmpOpU cmp, flagsRegU icc, regF dst, regF src) %{
  match(Set dst (CMoveF (Binary cmp icc) (Binary dst src)));
  ins_cost(150);

  size(4);
  format %{ "FCPYS$cmp $dst,$src" %}
  ins_encode %{
    __ fcpys($dst$$FloatRegister, $src$$FloatRegister, (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(int_conditional_float_move);
%}

// Conditional move
instruct cmovDP_reg(cmpOpP cmp, flagsRegP pcc, regD dst, regD src) %{
  match(Set dst (CMoveD (Binary cmp pcc) (Binary dst src)));
  ins_cost(150);
  size(4);
  format %{ "FCPYD$cmp $dst,$src" %}
  ins_encode %{
    __ fcpyd($dst$$FloatRegister, $src$$FloatRegister, (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(int_conditional_double_move);
%}

instruct cmovDI_reg(cmpOp cmp, flagsReg icc, regD dst, regD src) %{
  match(Set dst (CMoveD (Binary cmp icc) (Binary dst src)));
  ins_cost(150);

  size(4);
  format %{ "FCPYD$cmp $dst,$src" %}
  ins_encode %{
    __ fcpyd($dst$$FloatRegister, $src$$FloatRegister, (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(int_conditional_double_move);
%}

instruct cmovDI_reg_EQNELTGE(cmpOp0 cmp, flagsReg_EQNELTGE icc, regD dst, regD src) %{
  match(Set dst (CMoveD (Binary cmp icc) (Binary dst src)));
  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge);
  ins_cost(150);

  size(4);
  format %{ "FCPYD$cmp $dst,$src" %}
  ins_encode %{
    __ fcpyd($dst$$FloatRegister, $src$$FloatRegister, (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(int_conditional_double_move);
%}

instruct cmovDIu_reg(cmpOpU cmp, flagsRegU icc, regD dst, regD src) %{
  match(Set dst (CMoveD (Binary cmp icc) (Binary dst src)));
  ins_cost(150);

  size(4);
  format %{ "FCPYD$cmp $dst,$src" %}
  ins_encode %{
    __ fcpyd($dst$$FloatRegister, $src$$FloatRegister, (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(int_conditional_double_move);
%}

// Conditional move
instruct cmovLP_reg(cmpOpP cmp, flagsRegP pcc, iRegL dst, iRegL src) %{
  match(Set dst (CMoveL (Binary cmp pcc) (Binary dst src)));
  ins_cost(150);

  size(8);
  format %{ "MOV$cmp  $dst.lo,$src.lo\t! long\n\t"
            "MOV$cmp  $dst.hi,$src.hi" %}
  ins_encode %{
    __ mov($dst$$Register, $src$$Register, (AsmCondition)($cmp$$cmpcode));
    __ mov($dst$$Register->successor(), $src$$Register->successor(), (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(ialu_reg);
%}

// TODO: try immLRot2 instead, (0, $con$$constant) becomes
// (hi($con$$constant), lo($con$$constant)) becomes
instruct cmovLP_immRot(cmpOpP cmp, flagsRegP pcc, iRegL dst, immLlowRot src) %{
  match(Set dst (CMoveL (Binary cmp pcc) (Binary dst src)));
  ins_cost(140);

  size(8);
  format %{ "MOV$cmp  $dst.lo,$src\t! long\n\t"
            "MOV$cmp  $dst.hi,0" %}
  ins_encode %{
    __ mov($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
    __ mov($dst$$Register->successor(), 0, (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(ialu_imm);
%}

instruct cmovLP_imm16(cmpOpP cmp, flagsRegP pcc, iRegL dst, immL16 src) %{
  match(Set dst (CMoveL (Binary cmp pcc) (Binary dst src)));
  ins_cost(140);

  size(8);
  format %{ "MOV$cmp  $dst.lo,$src\t! long\n\t"
            "MOV$cmp  $dst.hi,0" %}
  ins_encode %{
    __ movw($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
    __ mov($dst$$Register->successor(), 0, (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(ialu_imm);
%}

instruct cmovLI_reg(cmpOp cmp, flagsReg icc, iRegL dst, iRegL src) %{
  match(Set dst (CMoveL (Binary cmp icc) (Binary dst src)));
  ins_cost(150);

  size(8);
  format %{ "MOV$cmp  $dst.lo,$src.lo\t! long\n\t"
            "MOV$cmp  $dst.hi,$src.hi" %}
  ins_encode %{
    __ mov($dst$$Register, $src$$Register, (AsmCondition)($cmp$$cmpcode));
    __ mov($dst$$Register->successor(), $src$$Register->successor(), (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(ialu_reg);
%}

instruct cmovLI_reg_EQNELTGE(cmpOp0 cmp, flagsReg_EQNELTGE icc, iRegL dst, iRegL src) %{
  match(Set dst (CMoveL (Binary cmp icc) (Binary dst src)));
  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq ||
            _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne ||
            _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt ||
            _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge);
  ins_cost(150);

  size(8);
  format %{ "MOV$cmp  $dst.lo,$src.lo\t! long\n\t"
            "MOV$cmp  $dst.hi,$src.hi" %}
  ins_encode %{
    __ mov($dst$$Register, $src$$Register, (AsmCondition)($cmp$$cmpcode));
    __ mov($dst$$Register->successor(), $src$$Register->successor(), (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(ialu_reg);
%}

// TODO: try immLRot2 instead, (0, $con$$constant) becomes
// (hi($con$$constant), lo($con$$constant)) becomes
instruct cmovLI_immRot(cmpOp cmp, flagsReg icc, iRegL dst, immLlowRot src) %{
  match(Set dst (CMoveL (Binary cmp icc) (Binary dst src)));
  ins_cost(140);

  size(8);
  format %{ "MOV$cmp  $dst.lo,$src\t! long\n\t"
            "MOV$cmp  $dst.hi,0" %}
  ins_encode %{
    __ mov($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
    __ mov($dst$$Register->successor(), 0, (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(ialu_imm);
%}

// TODO: try immLRot2 instead, (0, $con$$constant) becomes
// (hi($con$$constant), lo($con$$constant)) becomes
instruct cmovLI_immRot_EQNELTGE(cmpOp0 cmp, flagsReg_EQNELTGE icc, iRegL dst, immLlowRot src) %{
  match(Set dst (CMoveL (Binary cmp icc) (Binary dst src)));
  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq ||
            _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne ||
            _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt ||
            _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge);
  ins_cost(140);

  size(8);
  format %{ "MOV$cmp  $dst.lo,$src\t! long\n\t"
            "MOV$cmp  $dst.hi,0" %}
  ins_encode %{
    __ mov($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
    __ mov($dst$$Register->successor(), 0, (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(ialu_imm);
%}

instruct cmovLI_imm16(cmpOp cmp, flagsReg icc, iRegL dst, immL16 src) %{
  match(Set dst (CMoveL (Binary cmp icc) (Binary dst src)));
  ins_cost(140);

  size(8);
  format %{ "MOV$cmp  $dst.lo,$src\t! long\n\t"
            "MOV$cmp  $dst.hi,0" %}
  ins_encode %{
    __ movw($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
    __ movw($dst$$Register->successor(), 0, (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(ialu_imm);
%}

instruct cmovLI_imm16_EQNELTGE(cmpOp0 cmp, flagsReg_EQNELTGE icc, iRegL dst, immL16 src) %{
  match(Set dst (CMoveL (Binary cmp icc) (Binary dst src)));
  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq ||
            _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne ||
            _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt ||
            _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge);
  ins_cost(140);

  size(8);
  format %{ "MOV$cmp  $dst.lo,$src\t! long\n\t"
            "MOV$cmp  $dst.hi,0" %}
  ins_encode %{
    __ movw($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
    __ movw($dst$$Register->successor(), 0, (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(ialu_imm);
%}

instruct cmovLIu_reg(cmpOpU cmp, flagsRegU icc, iRegL dst, iRegL src) %{
  match(Set dst (CMoveL (Binary cmp icc) (Binary dst src)));
  ins_cost(150);

  size(8);
  format %{ "MOV$cmp  $dst.lo,$src.lo\t! long\n\t"
            "MOV$cmp  $dst.hi,$src.hi" %}
  ins_encode %{
    __ mov($dst$$Register, $src$$Register, (AsmCondition)($cmp$$cmpcode));
    __ mov($dst$$Register->successor(), $src$$Register->successor(), (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(ialu_reg);
%}


//----------OS and Locking Instructions----------------------------------------

// This name is KNOWN by the ADLC and cannot be changed.
// The ADLC forces a 'TypeRawPtr::BOTTOM' output type
// for this guy.
instruct tlsLoadP(RthreadRegP dst) %{
  match(Set dst (ThreadLocal));

  size(0);
  ins_cost(0);
  format %{ "! TLS is in $dst" %}
  ins_encode( /*empty encoding*/ );
  ins_pipe(ialu_none);
%}

instruct checkCastPP( iRegP dst ) %{
  match(Set dst (CheckCastPP dst));

  size(0);
  format %{ "! checkcastPP of $dst" %}
  ins_encode( /*empty encoding*/ );
  ins_pipe(empty);
%}


instruct castPP( iRegP dst ) %{
  match(Set dst (CastPP dst));
  format %{ "! castPP of $dst" %}
  ins_encode( /*empty encoding*/ );
  ins_pipe(empty);
%}

instruct castII( iRegI dst ) %{
  match(Set dst (CastII dst));
  format %{ "! castII of $dst" %}
  ins_encode( /*empty encoding*/ );
  ins_cost(0);
  ins_pipe(empty);
%}

instruct castLL( iRegL dst ) %{
  match(Set dst (CastLL dst));
  format %{ "! castLL of $dst" %}
  ins_encode( /*empty encoding*/ );
  ins_cost(0);
  ins_pipe(empty);
%}

instruct castFF( regF dst ) %{
  match(Set dst (CastFF dst));
  format %{ "! castFF of $dst" %}
  ins_encode( /*empty encoding*/ );
  ins_cost(0);
  ins_pipe(empty);
%}

instruct castDD( regD dst ) %{
  match(Set dst (CastDD dst));
  format %{ "! castDD of $dst" %}
  ins_encode( /*empty encoding*/ );
  ins_cost(0);
  ins_pipe(empty);
%}

instruct castVVD( vecD dst ) %{
  match(Set dst (CastVV dst));
  format %{ "! castVV of $dst" %}
  ins_encode( /*empty encoding*/ );
  ins_cost(0);
  ins_pipe(empty);
%}

instruct castVVX( vecX dst ) %{
  match(Set dst (CastVV dst));
  format %{ "! castVV of $dst" %}
  ins_encode( /*empty encoding*/ );
  ins_cost(0);
  ins_pipe(empty);
%}


//----------Arithmetic Instructions--------------------------------------------
// Addition Instructions
// Register Addition
instruct addI_reg_reg(iRegI dst, iRegI src1, iRegI src2) %{
  match(Set dst (AddI src1 src2));

  size(4);
  format %{ "add_32 $dst,$src1,$src2\t! int" %}
  ins_encode %{
    __ add_32($dst$$Register, $src1$$Register, $src2$$Register);
  %}
  ins_pipe(ialu_reg_reg);
%}

instruct addshlI_reg_reg_reg(iRegI dst, iRegI src1, iRegI src2, iRegI src3) %{
  match(Set dst (AddI (LShiftI src1 src2) src3));

  size(4);
  format %{ "add_32 $dst,$src3,$src1<<$src2\t! int" %}
  ins_encode %{
    __ add_32($dst$$Register, $src3$$Register, AsmOperand($src1$$Register, lsl, $src2$$Register));
  %}
  ins_pipe(ialu_reg_reg);
%}


instruct addshlI_reg_imm_reg(iRegI dst, iRegI src1, immU5 src2, iRegI src3) %{
  match(Set dst (AddI (LShiftI src1 src2) src3));

  size(4);
  format %{ "add_32 $dst,$src3,$src1<<$src2\t! int" %}
  ins_encode %{
    __ add_32($dst$$Register, $src3$$Register, AsmOperand($src1$$Register, lsl, $src2$$constant));
  %}
  ins_pipe(ialu_reg_reg);
%}

instruct addsarI_reg_reg_reg(iRegI dst, iRegI src1, iRegI src2, iRegI src3) %{
  match(Set dst (AddI (RShiftI src1 src2) src3));

  size(4);
  format %{ "add_32 $dst,$src3,$src1>>$src2\t! int" %}
  ins_encode %{
    __ add_32($dst$$Register, $src3$$Register, AsmOperand($src1$$Register, asr, $src2$$Register));
  %}
  ins_pipe(ialu_reg_reg);
%}

instruct addsarI_reg_imm_reg(iRegI dst, iRegI src1, immU5 src2, iRegI src3) %{
  match(Set dst (AddI (RShiftI src1 src2) src3));

  size(4);
  format %{ "add_32 $dst,$src3,$src1>>$src2\t! int" %}
  ins_encode %{
    __ add_32($dst$$Register, $src3$$Register, AsmOperand($src1$$Register, asr, $src2$$constant));
  %}
  ins_pipe(ialu_reg_reg);
%}

instruct addshrI_reg_reg_reg(iRegI dst, iRegI src1, iRegI src2, iRegI src3) %{
  match(Set dst (AddI (URShiftI src1 src2) src3));

  size(4);
  format %{ "add_32 $dst,$src3,$src1>>>$src2\t! int" %}
  ins_encode %{
    __ add_32($dst$$Register, $src3$$Register, AsmOperand($src1$$Register, lsr, $src2$$Register));
  %}
  ins_pipe(ialu_reg_reg);
%}

instruct addshrI_reg_imm_reg(iRegI dst, iRegI src1, immU5 src2, iRegI src3) %{
  match(Set dst (AddI (URShiftI src1 src2) src3));

  size(4);
  format %{ "add_32 $dst,$src3,$src1>>>$src2\t! int" %}
  ins_encode %{
    __ add_32($dst$$Register, $src3$$Register, AsmOperand($src1$$Register, lsr, $src2$$constant));
  %}
  ins_pipe(ialu_reg_reg);
%}

// Immediate Addition
instruct addI_reg_aimmI(iRegI dst, iRegI src1, aimmI src2) %{
  match(Set dst (AddI src1 src2));

  size(4);
  format %{ "add_32 $dst,$src1,$src2\t! int" %}
  ins_encode %{
    __ add_32($dst$$Register, $src1$$Register, $src2$$constant);
  %}
  ins_pipe(ialu_reg_imm);
%}

// Pointer Register Addition
instruct addP_reg_reg(iRegP dst, iRegP src1, iRegX src2) %{
  match(Set dst (AddP src1 src2));

  size(4);
  format %{ "ADD    $dst,$src1,$src2\t! ptr" %}
  ins_encode %{
    __ add($dst$$Register, $src1$$Register, $src2$$Register);
  %}
  ins_pipe(ialu_reg_reg);
%}


// shifted iRegX operand
operand shiftedX(iRegX src2, shimmX src3) %{
//constraint(ALLOC_IN_RC(sp_ptr_reg));
  match(LShiftX src2 src3);

  op_cost(1);
  format %{ "$src2 << $src3" %}
  interface(MEMORY_INTER) %{
    base($src2);
    index(0xff);
    scale($src3);
    disp(0x0);
  %}
%}

instruct addshlP_reg_reg_imm(iRegP dst, iRegP src1, shiftedX src2) %{
  match(Set dst (AddP src1 src2));

  ins_cost(DEFAULT_COST * 3/2);
  size(4);
  format %{ "ADD    $dst,$src1,$src2\t! ptr" %}
  ins_encode %{
    Register base = reg_to_register_object($src2$$base);
    __ add($dst$$Register, $src1$$Register, AsmOperand(base, lsl, $src2$$scale));
  %}
  ins_pipe(ialu_reg_reg);
%}

// Pointer Immediate Addition
instruct addP_reg_aimmX(iRegP dst, iRegP src1, aimmX src2) %{
  match(Set dst (AddP src1 src2));

  size(4);
  format %{ "ADD    $dst,$src1,$src2\t! ptr" %}
  ins_encode %{
    __ add($dst$$Register, $src1$$Register, $src2$$constant);
  %}
  ins_pipe(ialu_reg_imm);
%}

// Long Addition
instruct addL_reg_reg(iRegL dst, iRegL src1, iRegL src2, flagsReg ccr) %{
  match(Set dst (AddL src1 src2));
  effect(KILL ccr);
  size(8);
  format %{ "ADDS    $dst.lo,$src1.lo,$src2.lo\t! long\n\t"
            "ADC     $dst.hi,$src1.hi,$src2.hi" %}
  ins_encode %{
    __ adds($dst$$Register, $src1$$Register, $src2$$Register);
    __ adc($dst$$Register->successor(), $src1$$Register->successor(), $src2$$Register->successor());
  %}
  ins_pipe(ialu_reg_reg);
%}

// TODO

// TODO: try immLRot2 instead, (0, $con$$constant) becomes
// (hi($con$$constant), lo($con$$constant)) becomes
instruct addL_reg_immRot(iRegL dst, iRegL src1, immLlowRot con, flagsReg ccr) %{
  match(Set dst (AddL src1 con));
  effect(KILL ccr);
  size(8);
  format %{ "ADDS    $dst.lo,$src1.lo,$con\t! long\n\t"
            "ADC     $dst.hi,$src1.hi,0" %}
  ins_encode %{
    __ adds($dst$$Register, $src1$$Register, $con$$constant);
    __ adc($dst$$Register->successor(), $src1$$Register->successor(), 0);
  %}
  ins_pipe(ialu_reg_imm);
%}

// No flag versions for CompareAndSwap{P,I,L} because matcher can't match them

instruct compareAndSwapL_bool(memoryex mem, iRegL oldval, iRegLd newval, iRegI res, iRegLd tmp, flagsReg ccr ) %{
  match(Set res (CompareAndSwapL mem (Binary oldval newval)));
  effect( KILL ccr, TEMP tmp);
  size(32);
  format %{ "loop: \n\t"
            "LDREXD   $tmp, $mem\t! If $oldval==[$mem] Then store $newval into [$mem]\n\t"
            "CMP      $tmp.lo, $oldval.lo\n\t"
            "CMP.eq   $tmp.hi, $oldval.hi\n\t"
            "STREXD.eq $tmp, $newval, $mem\n\t"
            "MOV.ne   $tmp, 0 \n\t"
            "XORS.eq  $tmp,$tmp, 1 \n\t"
            "B.eq     loop \n\t"
            "MOV      $res, $tmp" %}
  ins_encode %{
    Label loop;
    __ bind(loop);
    __ ldrexd($tmp$$Register, $mem$$Address);
    __ cmp($tmp$$Register, $oldval$$Register);
    __ cmp($tmp$$Register->successor(), $oldval$$Register->successor(), eq);
    __ strexd($tmp$$Register, $newval$$Register, $mem$$Address, eq);
    __ mov($tmp$$Register, 0, ne);
    __ eors($tmp$$Register, $tmp$$Register, 1, eq);
    __ b(loop, eq);
    __ mov($res$$Register, $tmp$$Register);
  %}
  ins_pipe( long_memory_op );
%}


instruct compareAndSwapI_bool(memoryex mem, iRegI oldval, iRegI newval, iRegI res, iRegI tmp, flagsReg ccr ) %{
  match(Set res (CompareAndSwapI mem (Binary oldval newval)));
  effect( KILL ccr, TEMP tmp);
  size(28);
  format %{ "loop: \n\t"
            "LDREX    $tmp, $mem\t! If $oldval==[$mem] Then store $newval into [$mem]\n\t"
            "CMP      $tmp, $oldval\n\t"
            "STREX.eq $tmp, $newval, $mem\n\t"
            "MOV.ne   $tmp, 0 \n\t"
            "XORS.eq  $tmp,$tmp, 1 \n\t"
            "B.eq     loop \n\t"
            "MOV      $res, $tmp" %}

  ins_encode %{
    Label loop;
    __ bind(loop);
    __ ldrex($tmp$$Register,$mem$$Address);
    __ cmp($tmp$$Register, $oldval$$Register);
    __ strex($tmp$$Register, $newval$$Register, $mem$$Address, eq);
    __ mov($tmp$$Register, 0, ne);
    __ eors($tmp$$Register, $tmp$$Register, 1, eq);
    __ b(loop, eq);
    __ mov($res$$Register, $tmp$$Register);
  %}
  ins_pipe( long_memory_op );
%}

instruct compareAndSwapP_bool(memoryex mem, iRegP oldval, iRegP newval, iRegI res, iRegI tmp, flagsReg ccr ) %{
  match(Set res (CompareAndSwapP mem (Binary oldval newval)));
  effect( KILL ccr, TEMP tmp);
  size(28);
  format %{ "loop: \n\t"
            "LDREX    $tmp, $mem\t! If $oldval==[$mem] Then store $newval into [$mem]\n\t"
            "CMP      $tmp, $oldval\n\t"
            "STREX.eq $tmp, $newval, $mem\n\t"
            "MOV.ne   $tmp, 0 \n\t"
            "EORS.eq  $tmp,$tmp, 1 \n\t"
            "B.eq     loop \n\t"
            "MOV      $res, $tmp" %}

  ins_encode %{
    Label loop;
    __ bind(loop);
    __ ldrex($tmp$$Register,$mem$$Address);
    __ cmp($tmp$$Register, $oldval$$Register);
    __ strex($tmp$$Register, $newval$$Register, $mem$$Address, eq);
    __ mov($tmp$$Register, 0, ne);
    __ eors($tmp$$Register, $tmp$$Register, 1, eq);
    __ b(loop, eq);
    __ mov($res$$Register, $tmp$$Register);
  %}
  ins_pipe( long_memory_op );
%}

instruct xaddI_aimmI_no_res(memoryex mem, aimmI add, Universe dummy, iRegI tmp1, iRegI tmp2, flagsReg ccr) %{
  predicate(n->as_LoadStore()->result_not_used());
  match(Set dummy (GetAndAddI mem add));
  effect(KILL ccr, TEMP tmp1, TEMP tmp2);
  size(20);
  format %{ "loop: \n\t"
            "LDREX    $tmp1, $mem\n\t"
            "ADD      $tmp1, $tmp1, $add\n\t"
            "STREX    $tmp2, $tmp1, $mem\n\t"
            "CMP      $tmp2, 0 \n\t"
            "B.ne     loop \n\t" %}

  ins_encode %{
    Label loop;
    __ bind(loop);
    __ ldrex($tmp1$$Register,$mem$$Address);
    __ add($tmp1$$Register, $tmp1$$Register, $add$$constant);
    __ strex($tmp2$$Register, $tmp1$$Register, $mem$$Address);
    __ cmp($tmp2$$Register, 0);
    __ b(loop, ne);
  %}
  ins_pipe( long_memory_op );
%}

instruct xaddI_reg_no_res(memoryex mem, iRegI add, Universe dummy, iRegI tmp1, iRegI tmp2, flagsReg ccr) %{
  predicate(n->as_LoadStore()->result_not_used());
  match(Set dummy (GetAndAddI mem add));
  effect(KILL ccr, TEMP tmp1, TEMP tmp2);
  size(20);
  format %{ "loop: \n\t"
            "LDREX    $tmp1, $mem\n\t"
            "ADD      $tmp1, $tmp1, $add\n\t"
            "STREX    $tmp2, $tmp1, $mem\n\t"
            "CMP      $tmp2, 0 \n\t"
            "B.ne     loop \n\t" %}

  ins_encode %{
    Label loop;
    __ bind(loop);
    __ ldrex($tmp1$$Register,$mem$$Address);
    __ add($tmp1$$Register, $tmp1$$Register, $add$$Register);
    __ strex($tmp2$$Register, $tmp1$$Register, $mem$$Address);
    __ cmp($tmp2$$Register, 0);
    __ b(loop, ne);
  %}
  ins_pipe( long_memory_op );
%}

instruct xaddI_aimmI(memoryex mem, aimmI add, iRegI res, iRegI tmp1, iRegI tmp2, flagsReg ccr) %{
  match(Set res (GetAndAddI mem add));
  effect(KILL ccr, TEMP tmp1, TEMP tmp2, TEMP res);
  size(20);
  format %{ "loop: \n\t"
            "LDREX    $res, $mem\n\t"
            "ADD      $tmp1, $res, $add\n\t"
            "STREX    $tmp2, $tmp1, $mem\n\t"
            "CMP      $tmp2, 0 \n\t"
            "B.ne     loop \n\t" %}

  ins_encode %{
    Label loop;
    __ bind(loop);
    __ ldrex($res$$Register,$mem$$Address);
    __ add($tmp1$$Register, $res$$Register, $add$$constant);
    __ strex($tmp2$$Register, $tmp1$$Register, $mem$$Address);
    __ cmp($tmp2$$Register, 0);
    __ b(loop, ne);
  %}
  ins_pipe( long_memory_op );
%}

instruct xaddI_reg(memoryex mem, iRegI add, iRegI res, iRegI tmp1, iRegI tmp2, flagsReg ccr) %{
  match(Set res (GetAndAddI mem add));
  effect(KILL ccr, TEMP tmp1, TEMP tmp2, TEMP res);
  size(20);
  format %{ "loop: \n\t"
            "LDREX    $res, $mem\n\t"
            "ADD      $tmp1, $res, $add\n\t"
            "STREX    $tmp2, $tmp1, $mem\n\t"
            "CMP      $tmp2, 0 \n\t"
            "B.ne     loop \n\t" %}

  ins_encode %{
    Label loop;
    __ bind(loop);
    __ ldrex($res$$Register,$mem$$Address);
    __ add($tmp1$$Register, $res$$Register, $add$$Register);
    __ strex($tmp2$$Register, $tmp1$$Register, $mem$$Address);
    __ cmp($tmp2$$Register, 0);
    __ b(loop, ne);
  %}
  ins_pipe( long_memory_op );
%}

instruct xaddL_reg_no_res(memoryex mem, iRegL add, Universe dummy, iRegLd tmp1, iRegI tmp2, flagsReg ccr) %{
  predicate(n->as_LoadStore()->result_not_used());
  match(Set dummy (GetAndAddL mem add));
  effect( KILL ccr, TEMP tmp1, TEMP tmp2);
  size(24);
  format %{ "loop: \n\t"
            "LDREXD   $tmp1, $mem\n\t"
            "ADDS     $tmp1.lo, $tmp1.lo, $add.lo\n\t"
            "ADC      $tmp1.hi, $tmp1.hi, $add.hi\n\t"
            "STREXD   $tmp2, $tmp1, $mem\n\t"
            "CMP      $tmp2, 0 \n\t"
            "B.ne     loop \n\t" %}

  ins_encode %{
    Label loop;
    __ bind(loop);
    __ ldrexd($tmp1$$Register, $mem$$Address);
    __ adds($tmp1$$Register, $tmp1$$Register, $add$$Register);
    __ adc($tmp1$$Register->successor(), $tmp1$$Register->successor(), $add$$Register->successor());
    __ strexd($tmp2$$Register, $tmp1$$Register, $mem$$Address);
    __ cmp($tmp2$$Register, 0);
    __ b(loop, ne);
  %}
  ins_pipe( long_memory_op );
%}

// TODO: try immLRot2 instead, (0, $con$$constant) becomes
// (hi($con$$constant), lo($con$$constant)) becomes
instruct xaddL_immRot_no_res(memoryex mem, immLlowRot add, Universe dummy, iRegLd tmp1, iRegI tmp2, flagsReg ccr) %{
  predicate(n->as_LoadStore()->result_not_used());
  match(Set dummy (GetAndAddL mem add));
  effect( KILL ccr, TEMP tmp1, TEMP tmp2);
  size(24);
  format %{ "loop: \n\t"
            "LDREXD   $tmp1, $mem\n\t"
            "ADDS     $tmp1.lo, $tmp1.lo, $add\n\t"
            "ADC      $tmp1.hi, $tmp1.hi, 0\n\t"
            "STREXD   $tmp2, $tmp1, $mem\n\t"
            "CMP      $tmp2, 0 \n\t"
            "B.ne     loop \n\t" %}

  ins_encode %{
    Label loop;
    __ bind(loop);
    __ ldrexd($tmp1$$Register, $mem$$Address);
    __ adds($tmp1$$Register, $tmp1$$Register, $add$$constant);
    __ adc($tmp1$$Register->successor(), $tmp1$$Register->successor(), 0);
    __ strexd($tmp2$$Register, $tmp1$$Register, $mem$$Address);
    __ cmp($tmp2$$Register, 0);
    __ b(loop, ne);
  %}
  ins_pipe( long_memory_op );
%}

instruct xaddL_reg(memoryex mem, iRegL add, iRegLd res, iRegLd tmp1, iRegI tmp2, flagsReg ccr) %{
  match(Set res (GetAndAddL mem add));
  effect( KILL ccr, TEMP tmp1, TEMP tmp2, TEMP res);
  size(24);
  format %{ "loop: \n\t"
            "LDREXD   $res, $mem\n\t"
            "ADDS     $tmp1.lo, $res.lo, $add.lo\n\t"
            "ADC      $tmp1.hi, $res.hi, $add.hi\n\t"
            "STREXD   $tmp2, $tmp1, $mem\n\t"
            "CMP      $tmp2, 0 \n\t"
            "B.ne     loop \n\t" %}

  ins_encode %{
    Label loop;
    __ bind(loop);
    __ ldrexd($res$$Register, $mem$$Address);
    __ adds($tmp1$$Register, $res$$Register, $add$$Register);
    __ adc($tmp1$$Register->successor(), $res$$Register->successor(), $add$$Register->successor());
    __ strexd($tmp2$$Register, $tmp1$$Register, $mem$$Address);
    __ cmp($tmp2$$Register, 0);
    __ b(loop, ne);
  %}
  ins_pipe( long_memory_op );
%}

// TODO: try immLRot2 instead, (0, $con$$constant) becomes
// (hi($con$$constant), lo($con$$constant)) becomes
instruct xaddL_immRot(memoryex mem, immLlowRot add, iRegLd res, iRegLd tmp1, iRegI tmp2, flagsReg ccr) %{
  match(Set res (GetAndAddL mem add));
  effect( KILL ccr, TEMP tmp1, TEMP tmp2, TEMP res);
  size(24);
  format %{ "loop: \n\t"
            "LDREXD   $res, $mem\n\t"
            "ADDS     $tmp1.lo, $res.lo, $add\n\t"
            "ADC      $tmp1.hi, $res.hi, 0\n\t"
            "STREXD   $tmp2, $tmp1, $mem\n\t"
            "CMP      $tmp2, 0 \n\t"
            "B.ne     loop \n\t" %}

  ins_encode %{
    Label loop;
    __ bind(loop);
    __ ldrexd($res$$Register, $mem$$Address);
    __ adds($tmp1$$Register, $res$$Register, $add$$constant);
    __ adc($tmp1$$Register->successor(), $res$$Register->successor(), 0);
    __ strexd($tmp2$$Register, $tmp1$$Register, $mem$$Address);
    __ cmp($tmp2$$Register, 0);
    __ b(loop, ne);
  %}
  ins_pipe( long_memory_op );
%}

instruct xchgI(memoryex mem, iRegI newval, iRegI res, iRegI tmp, flagsReg ccr) %{
  match(Set res (GetAndSetI mem newval));
  effect(KILL ccr, TEMP tmp, TEMP res);
  size(16);
  format %{ "loop: \n\t"
            "LDREX    $res, $mem\n\t"
            "STREX    $tmp, $newval, $mem\n\t"
            "CMP      $tmp, 0 \n\t"
            "B.ne     loop \n\t" %}

  ins_encode %{
    Label loop;
    __ bind(loop);
    __ ldrex($res$$Register,$mem$$Address);
    __ strex($tmp$$Register, $newval$$Register, $mem$$Address);
    __ cmp($tmp$$Register, 0);
    __ b(loop, ne);
  %}
  ins_pipe( long_memory_op );
%}

instruct xchgL(memoryex mem, iRegLd newval, iRegLd res, iRegI tmp, flagsReg ccr) %{
  match(Set res (GetAndSetL mem newval));
  effect( KILL ccr, TEMP tmp, TEMP res);
  size(16);
  format %{ "loop: \n\t"
            "LDREXD   $res, $mem\n\t"
            "STREXD   $tmp, $newval, $mem\n\t"
            "CMP      $tmp, 0 \n\t"
            "B.ne     loop \n\t" %}

  ins_encode %{
    Label loop;
    __ bind(loop);
    __ ldrexd($res$$Register, $mem$$Address);
    __ strexd($tmp$$Register, $newval$$Register, $mem$$Address);
    __ cmp($tmp$$Register, 0);
    __ b(loop, ne);
  %}
  ins_pipe( long_memory_op );
%}

instruct xchgP(memoryex mem, iRegP newval, iRegP res, iRegI tmp, flagsReg ccr) %{
  match(Set res (GetAndSetP mem newval));
  effect(KILL ccr, TEMP tmp, TEMP res);
  size(16);
  format %{ "loop: \n\t"
            "LDREX    $res, $mem\n\t"
            "STREX    $tmp, $newval, $mem\n\t"
            "CMP      $tmp, 0 \n\t"
            "B.ne     loop \n\t" %}

  ins_encode %{
    Label loop;
    __ bind(loop);
    __ ldrex($res$$Register,$mem$$Address);
    __ strex($tmp$$Register, $newval$$Register, $mem$$Address);
    __ cmp($tmp$$Register, 0);
    __ b(loop, ne);
  %}
  ins_pipe( long_memory_op );
%}

//---------------------
// Subtraction Instructions
// Register Subtraction
instruct subI_reg_reg(iRegI dst, iRegI src1, iRegI src2) %{
  match(Set dst (SubI src1 src2));

  size(4);
  format %{ "sub_32 $dst,$src1,$src2\t! int" %}
  ins_encode %{
    __ sub_32($dst$$Register, $src1$$Register, $src2$$Register);
  %}
  ins_pipe(ialu_reg_reg);
%}

instruct subshlI_reg_reg_reg(iRegI dst, iRegI src1, iRegI src2, iRegI src3) %{
  match(Set dst (SubI src1 (LShiftI src2 src3)));

  size(4);
  format %{ "SUB    $dst,$src1,$src2<<$src3" %}
  ins_encode %{
    __ sub($dst$$Register, $src1$$Register, AsmOperand($src2$$Register, lsl, $src3$$Register));
  %}
  ins_pipe(ialu_reg_reg);
%}

instruct subshlI_reg_reg_imm(iRegI dst, iRegI src1, iRegI src2, immU5 src3) %{
  match(Set dst (SubI src1 (LShiftI src2 src3)));

  size(4);
  format %{ "sub_32 $dst,$src1,$src2<<$src3\t! int" %}
  ins_encode %{
    __ sub_32($dst$$Register, $src1$$Register, AsmOperand($src2$$Register, lsl, $src3$$constant));
  %}
  ins_pipe(ialu_reg_reg);
%}

instruct subsarI_reg_reg_reg(iRegI dst, iRegI src1, iRegI src2, iRegI src3) %{
  match(Set dst (SubI src1 (RShiftI src2 src3)));

  size(4);
  format %{ "SUB    $dst,$src1,$src2>>$src3" %}
  ins_encode %{
    __ sub($dst$$Register, $src1$$Register, AsmOperand($src2$$Register, asr, $src3$$Register));
  %}
  ins_pipe(ialu_reg_reg);
%}

instruct subsarI_reg_reg_imm(iRegI dst, iRegI src1, iRegI src2, immU5 src3) %{
  match(Set dst (SubI src1 (RShiftI src2 src3)));

  size(4);
  format %{ "sub_32 $dst,$src1,$src2>>$src3\t! int" %}
  ins_encode %{
    __ sub_32($dst$$Register, $src1$$Register, AsmOperand($src2$$Register, asr, $src3$$constant));
  %}
  ins_pipe(ialu_reg_reg);
%}

instruct subshrI_reg_reg_reg(iRegI dst, iRegI src1, iRegI src2, iRegI src3) %{
  match(Set dst (SubI src1 (URShiftI src2 src3)));

  size(4);
  format %{ "SUB    $dst,$src1,$src2>>>$src3" %}
  ins_encode %{
    __ sub($dst$$Register, $src1$$Register, AsmOperand($src2$$Register, lsr, $src3$$Register));
  %}
  ins_pipe(ialu_reg_reg);
%}

instruct subshrI_reg_reg_imm(iRegI dst, iRegI src1, iRegI src2, immU5 src3) %{
  match(Set dst (SubI src1 (URShiftI src2 src3)));

  size(4);
  format %{ "sub_32 $dst,$src1,$src2>>>$src3\t! int" %}
  ins_encode %{
    __ sub_32($dst$$Register, $src1$$Register, AsmOperand($src2$$Register, lsr, $src3$$constant));
  %}
  ins_pipe(ialu_reg_reg);
%}

instruct rsbshlI_reg_reg_reg(iRegI dst, iRegI src1, iRegI src2, iRegI src3) %{
  match(Set dst (SubI (LShiftI src1 src2) src3));

  size(4);
  format %{ "RSB    $dst,$src3,$src1<<$src2" %}
  ins_encode %{
    __ rsb($dst$$Register, $src3$$Register, AsmOperand($src1$$Register, lsl, $src2$$Register));
  %}
  ins_pipe(ialu_reg_reg);
%}

instruct rsbshlI_reg_imm_reg(iRegI dst, iRegI src1, immU5 src2, iRegI src3) %{
  match(Set dst (SubI (LShiftI src1 src2) src3));

  size(4);
  format %{ "RSB    $dst,$src3,$src1<<$src2" %}
  ins_encode %{
    __ rsb($dst$$Register, $src3$$Register, AsmOperand($src1$$Register, lsl, $src2$$constant));
  %}
  ins_pipe(ialu_reg_reg);
%}

instruct rsbsarI_reg_reg_reg(iRegI dst, iRegI src1, iRegI src2, iRegI src3) %{
  match(Set dst (SubI (RShiftI src1 src2) src3));

  size(4);
  format %{ "RSB    $dst,$src3,$src1>>$src2" %}
  ins_encode %{
    __ rsb($dst$$Register, $src3$$Register, AsmOperand($src1$$Register, asr, $src2$$Register));
  %}
  ins_pipe(ialu_reg_reg);
%}

instruct rsbsarI_reg_imm_reg(iRegI dst, iRegI src1, immU5 src2, iRegI src3) %{
  match(Set dst (SubI (RShiftI src1 src2) src3));

  size(4);
  format %{ "RSB    $dst,$src3,$src1>>$src2" %}
  ins_encode %{
    __ rsb($dst$$Register, $src3$$Register, AsmOperand($src1$$Register, asr, $src2$$constant));
  %}
  ins_pipe(ialu_reg_reg);
%}

instruct rsbshrI_reg_reg_reg(iRegI dst, iRegI src1, iRegI src2, iRegI src3) %{
  match(Set dst (SubI (URShiftI src1 src2) src3));

  size(4);
  format %{ "RSB    $dst,$src3,$src1>>>$src2" %}
  ins_encode %{
    __ rsb($dst$$Register, $src3$$Register, AsmOperand($src1$$Register, lsr, $src2$$Register));
  %}
  ins_pipe(ialu_reg_reg);
%}

instruct rsbshrI_reg_imm_reg(iRegI dst, iRegI src1, immU5 src2, iRegI src3) %{
  match(Set dst (SubI (URShiftI src1 src2) src3));

  size(4);
  format %{ "RSB    $dst,$src3,$src1>>>$src2" %}
  ins_encode %{
    __ rsb($dst$$Register, $src3$$Register, AsmOperand($src1$$Register, lsr, $src2$$constant));
  %}
  ins_pipe(ialu_reg_reg);
%}

// Immediate Subtraction
instruct subI_reg_aimmI(iRegI dst, iRegI src1, aimmI src2) %{
  match(Set dst (SubI src1 src2));

  size(4);
  format %{ "sub_32 $dst,$src1,$src2\t! int" %}
  ins_encode %{
    __ sub_32($dst$$Register, $src1$$Register, $src2$$constant);
  %}
  ins_pipe(ialu_reg_imm);
%}

instruct subI_reg_immRotneg(iRegI dst, iRegI src1, aimmIneg src2) %{
  match(Set dst (AddI src1 src2));

  size(4);
  format %{ "sub_32 $dst,$src1,-($src2)\t! int" %}
  ins_encode %{
    __ sub_32($dst$$Register, $src1$$Register, -$src2$$constant);
  %}
  ins_pipe(ialu_reg_imm);
%}

instruct subI_immRot_reg(iRegI dst, immIRot src1, iRegI src2) %{
  match(Set dst (SubI src1 src2));

  size(4);
  format %{ "RSB    $dst,$src2,src1" %}
  ins_encode %{
    __ rsb($dst$$Register, $src2$$Register, $src1$$constant);
  %}
  ins_pipe(ialu_zero_reg);
%}

// Register Subtraction
instruct subL_reg_reg(iRegL dst, iRegL src1, iRegL src2, flagsReg icc ) %{
  match(Set dst (SubL src1 src2));
  effect (KILL icc);

  size(8);
  format %{ "SUBS   $dst.lo,$src1.lo,$src2.lo\t! long\n\t"
            "SBC    $dst.hi,$src1.hi,$src2.hi" %}
  ins_encode %{
    __ subs($dst$$Register, $src1$$Register, $src2$$Register);
    __ sbc($dst$$Register->successor(), $src1$$Register->successor(), $src2$$Register->successor());
  %}
  ins_pipe(ialu_reg_reg);
%}

// TODO

// Immediate Subtraction
// TODO: try immLRot2 instead, (0, $con$$constant) becomes
// (hi($con$$constant), lo($con$$constant)) becomes
instruct subL_reg_immRot(iRegL dst, iRegL src1, immLlowRot con, flagsReg icc) %{
  match(Set dst (SubL src1 con));
  effect (KILL icc);

  size(8);
  format %{ "SUB    $dst.lo,$src1.lo,$con\t! long\n\t"
            "SBC    $dst.hi,$src1.hi,0" %}
  ins_encode %{
    __ subs($dst$$Register, $src1$$Register, $con$$constant);
    __ sbc($dst$$Register->successor(), $src1$$Register->successor(), 0);
  %}
  ins_pipe(ialu_reg_imm);
%}

// Long negation
instruct negL_reg_reg(iRegL dst, immL0 zero, iRegL src2, flagsReg icc) %{
  match(Set dst (SubL zero src2));
  effect (KILL icc);

  size(8);
  format %{ "RSBS   $dst.lo,$src2.lo,0\t! long\n\t"
            "RSC    $dst.hi,$src2.hi,0" %}
  ins_encode %{
    __ rsbs($dst$$Register, $src2$$Register, 0);
    __ rsc($dst$$Register->successor(), $src2$$Register->successor(), 0);
  %}
  ins_pipe(ialu_zero_reg);
%}

// Multiplication Instructions
// Integer Multiplication
// Register Multiplication
instruct mulI_reg_reg(iRegI dst, iRegI src1, iRegI src2) %{
  match(Set dst (MulI src1 src2));

  size(4);
  format %{ "mul_32 $dst,$src1,$src2" %}
  ins_encode %{
    __ mul_32($dst$$Register, $src1$$Register, $src2$$Register);
  %}
  ins_pipe(imul_reg_reg);
%}

instruct mulL_lo1_hi2(iRegL dst, iRegL src1, iRegL src2) %{
  effect(DEF dst, USE src1, USE src2);
  size(4);
  format %{ "MUL  $dst.hi,$src1.lo,$src2.hi\t! long" %}
  ins_encode %{
    __ mul($dst$$Register->successor(), $src1$$Register, $src2$$Register->successor());
  %}
  ins_pipe(imul_reg_reg);
%}

instruct mulL_hi1_lo2(iRegL dst, iRegL src1, iRegL src2) %{
  effect(USE_DEF dst, USE src1, USE src2);
  size(8);
  format %{ "MLA  $dst.hi,$src1.hi,$src2.lo,$dst.hi\t! long\n\t"
            "MOV  $dst.lo, 0"%}
  ins_encode %{
    __ mla($dst$$Register->successor(), $src1$$Register->successor(), $src2$$Register, $dst$$Register->successor());
    __ mov($dst$$Register, 0);
  %}
  ins_pipe(imul_reg_reg);
%}

instruct mulL_lo1_lo2(iRegL dst, iRegL src1, iRegL src2) %{
  effect(USE_DEF dst, USE src1, USE src2);
  size(4);
  format %{ "UMLAL  $dst.lo,$dst.hi,$src1,$src2\t! long" %}
  ins_encode %{
    __ umlal($dst$$Register, $dst$$Register->successor(), $src1$$Register, $src2$$Register);
  %}
  ins_pipe(imul_reg_reg);
%}

instruct mulL_reg_reg(iRegL dst, iRegL src1, iRegL src2) %{
  match(Set dst (MulL src1 src2));

  expand %{
    mulL_lo1_hi2(dst, src1, src2);
    mulL_hi1_lo2(dst, src1, src2);
    mulL_lo1_lo2(dst, src1, src2);
  %}
%}

// Integer Division
// Register Division
instruct divI_reg_reg(R1RegI dst, R0RegI src1, R2RegI src2, LRRegP lr, flagsReg ccr) %{
  match(Set dst (DivI src1 src2));
  effect( KILL ccr, KILL src1, KILL src2, KILL lr);
  ins_cost((2+71)*DEFAULT_COST);

  format %{ "DIV   $dst,$src1,$src2 ! call to StubRoutines::Arm::idiv_irem_entry()" %}
  ins_encode %{
    __ call(StubRoutines::Arm::idiv_irem_entry(), relocInfo::runtime_call_type);
  %}
  ins_pipe(sdiv_reg_reg);
%}

// Register Long Division
instruct divL_reg_reg(R0R1RegL dst, R2R3RegL src1, R0R1RegL src2) %{
  match(Set dst (DivL src1 src2));
  effect(CALL);
  ins_cost(DEFAULT_COST*71);
  format %{ "DIVL  $src1,$src2,$dst\t! long ! call to SharedRuntime::ldiv" %}
  ins_encode %{
    address target = CAST_FROM_FN_PTR(address, SharedRuntime::ldiv);
    __ call(target, relocInfo::runtime_call_type);
  %}
  ins_pipe(divL_reg_reg);
%}

// Integer Remainder
// Register Remainder
instruct modI_reg_reg(R0RegI dst, R0RegI src1, R2RegI src2, R1RegI temp, LRRegP lr, flagsReg ccr ) %{
  match(Set dst (ModI src1 src2));
  effect( KILL ccr, KILL temp, KILL src2, KILL lr);

  format %{ "MODI   $dst,$src1,$src2\t ! call to StubRoutines::Arm::idiv_irem_entry" %}
  ins_encode %{
    __ call(StubRoutines::Arm::idiv_irem_entry(), relocInfo::runtime_call_type);
  %}
  ins_pipe(sdiv_reg_reg);
%}

// Register Long Remainder
instruct modL_reg_reg(R0R1RegL dst, R2R3RegL src1, R0R1RegL src2) %{
  match(Set dst (ModL src1 src2));
  effect(CALL);
  ins_cost(MEMORY_REF_COST); // FIXME
  format %{ "modL    $dst,$src1,$src2\t ! call to SharedRuntime::lrem" %}
  ins_encode %{
    address target = CAST_FROM_FN_PTR(address, SharedRuntime::lrem);
    __ call(target, relocInfo::runtime_call_type);
  %}
  ins_pipe(divL_reg_reg);
%}

// Integer Shift Instructions

// Register Shift Left
instruct shlI_reg_reg(iRegI dst, iRegI src1, iRegI src2) %{
  match(Set dst (LShiftI src1 src2));

  size(4);
  format %{ "LSL  $dst,$src1,$src2 \n\t" %}
  ins_encode %{
    __ mov($dst$$Register, AsmOperand($src1$$Register, lsl, $src2$$Register));
  %}
  ins_pipe(ialu_reg_reg);
%}

// Register Shift Left Immediate
instruct shlI_reg_imm5(iRegI dst, iRegI src1, immU5 src2) %{
  match(Set dst (LShiftI src1 src2));

  size(4);
  format %{ "LSL    $dst,$src1,$src2\t! int" %}
  ins_encode %{
    __ logical_shift_left($dst$$Register, $src1$$Register, $src2$$constant);
  %}
  ins_pipe(ialu_reg_imm);
%}

instruct shlL_reg_reg_merge_hi(iRegL dst, iRegL src1, iRegI src2) %{
  effect(USE_DEF dst, USE src1, USE src2);
  size(4);
  format %{"OR  $dst.hi,$dst.hi,($src1.hi << $src2)"  %}
  ins_encode %{
    __ orr($dst$$Register->successor(), $dst$$Register->successor(), AsmOperand($src1$$Register->successor(), lsl, $src2$$Register));
  %}
  ins_pipe(ialu_reg_reg);
%}

instruct shlL_reg_reg_merge_lo(iRegL dst, iRegL src1, iRegI src2) %{
  effect(USE_DEF dst, USE src1, USE src2);
  size(4);
  format %{ "LSL  $dst.lo,$src1.lo,$src2 \n\t" %}
  ins_encode %{
    __ mov($dst$$Register, AsmOperand($src1$$Register, lsl, $src2$$Register));
  %}
  ins_pipe(ialu_reg_reg);
%}

instruct shlL_reg_reg_overlap(iRegL dst, iRegL src1, iRegI src2, flagsReg ccr) %{
  effect(DEF dst, USE src1, USE src2, KILL ccr);
  size(16);
  format %{ "SUBS  $dst.hi,$src2,32 \n\t"
            "LSLpl $dst.hi,$src1.lo,$dst.hi \n\t"
            "RSBmi $dst.hi,$dst.hi,0 \n\t"
            "LSRmi $dst.hi,$src1.lo,$dst.hi" %}

  ins_encode %{
    // $src1$$Register and $dst$$Register->successor() can't be the same
    __ subs($dst$$Register->successor(), $src2$$Register, 32);
    __ mov($dst$$Register->successor(), AsmOperand($src1$$Register, lsl, $dst$$Register->successor()), pl);
    __ rsb($dst$$Register->successor(), $dst$$Register->successor(), 0, mi);
    __ mov($dst$$Register->successor(), AsmOperand($src1$$Register, lsr, $dst$$Register->successor()), mi);
  %}
  ins_pipe(ialu_reg_reg);
%}

instruct shlL_reg_reg(iRegL dst, iRegL src1, iRegI src2) %{
  match(Set dst (LShiftL src1 src2));

  expand %{
    flagsReg ccr;
    shlL_reg_reg_overlap(dst, src1, src2, ccr);
    shlL_reg_reg_merge_hi(dst, src1, src2);
    shlL_reg_reg_merge_lo(dst, src1, src2);
  %}
%}

// Register Shift Left Immediate
instruct shlL_reg_imm6(iRegL dst, iRegL src1, immU6Big src2) %{
  match(Set dst (LShiftL src1 src2));

  size(8);
  format %{ "LSL   $dst.hi,$src1.lo,$src2-32\t! or mov if $src2==32\n\t"
            "MOV   $dst.lo, 0" %}
  ins_encode %{
    if ($src2$$constant == 32) {
      __ mov($dst$$Register->successor(), $src1$$Register);
    } else {
      __ mov($dst$$Register->successor(), AsmOperand($src1$$Register, lsl, $src2$$constant-32));
    }
    __ mov($dst$$Register, 0);
  %}
  ins_pipe(ialu_reg_imm);
%}

instruct shlL_reg_imm5(iRegL dst, iRegL src1, immU5 src2) %{
  match(Set dst (LShiftL src1 src2));

  size(12);
  format %{ "LSL   $dst.hi,$src1.lo,$src2\n\t"
            "OR    $dst.hi, $dst.hi, $src1.lo >> 32-$src2\n\t"
            "LSL   $dst.lo,$src1.lo,$src2" %}
  ins_encode %{
    // The order of the following 3 instructions matters: src1.lo and
    // dst.hi can't overlap but src.hi and dst.hi can.
    __ mov($dst$$Register->successor(), AsmOperand($src1$$Register->successor(), lsl, $src2$$constant));
    __ orr($dst$$Register->successor(), $dst$$Register->successor(), AsmOperand($src1$$Register, lsr, 32-$src2$$constant));
    __ mov($dst$$Register, AsmOperand($src1$$Register, lsl, $src2$$constant));
  %}
  ins_pipe(ialu_reg_imm);
%}

// Register Arithmetic Shift Right
instruct sarI_reg_reg(iRegI dst, iRegI src1, iRegI src2) %{
  match(Set dst (RShiftI src1 src2));
  size(4);
  format %{ "ASR    $dst,$src1,$src2\t! int" %}
  ins_encode %{
    __ mov($dst$$Register, AsmOperand($src1$$Register, asr, $src2$$Register));
  %}
  ins_pipe(ialu_reg_reg);
%}

// Register Arithmetic Shift Right Immediate
instruct sarI_reg_imm5(iRegI dst, iRegI src1, immU5 src2) %{
  match(Set dst (RShiftI src1 src2));

  size(4);
  format %{ "ASR    $dst,$src1,$src2" %}
  ins_encode %{
    __ mov($dst$$Register, AsmOperand($src1$$Register, asr, $src2$$constant));
  %}
  ins_pipe(ialu_reg_imm);
%}

// Register Shift Right Arithmetic Long
instruct sarL_reg_reg_merge_lo(iRegL dst, iRegL src1, iRegI src2) %{
  effect(USE_DEF dst, USE src1, USE src2);
  size(4);
  format %{ "OR  $dst.lo,$dst.lo,($src1.lo >> $src2)"  %}
  ins_encode %{
    __ orr($dst$$Register, $dst$$Register, AsmOperand($src1$$Register, lsr, $src2$$Register));
  %}
  ins_pipe(ialu_reg_reg);
%}

instruct sarL_reg_reg_merge_hi(iRegL dst, iRegL src1, iRegI src2) %{
  effect(USE_DEF dst, USE src1, USE src2);
  size(4);
  format %{ "ASR  $dst.hi,$src1.hi,$src2 \n\t" %}
  ins_encode %{
    __ mov($dst$$Register->successor(), AsmOperand($src1$$Register->successor(), asr, $src2$$Register));
  %}
  ins_pipe(ialu_reg_reg);
%}

instruct sarL_reg_reg_overlap(iRegL dst, iRegL src1, iRegI src2, flagsReg ccr) %{
  effect(DEF dst, USE src1, USE src2, KILL ccr);
  size(16);
  format %{ "SUBS  $dst.lo,$src2,32 \n\t"
            "ASRpl $dst.lo,$src1.hi,$dst.lo \n\t"
            "RSBmi $dst.lo,$dst.lo,0 \n\t"
            "LSLmi $dst.lo,$src1.hi,$dst.lo" %}

  ins_encode %{
    // $src1$$Register->successor() and $dst$$Register can't be the same
    __ subs($dst$$Register, $src2$$Register, 32);
    __ mov($dst$$Register, AsmOperand($src1$$Register->successor(), asr, $dst$$Register), pl);
    __ rsb($dst$$Register, $dst$$Register, 0, mi);
    __ mov($dst$$Register, AsmOperand($src1$$Register->successor(), lsl, $dst$$Register), mi);
  %}
  ins_pipe(ialu_reg_reg);
%}

instruct sarL_reg_reg(iRegL dst, iRegL src1, iRegI src2) %{
  match(Set dst (RShiftL src1 src2));

  expand %{
    flagsReg ccr;
    sarL_reg_reg_overlap(dst, src1, src2, ccr);
    sarL_reg_reg_merge_lo(dst, src1, src2);
    sarL_reg_reg_merge_hi(dst, src1, src2);
  %}
%}

// Register Shift Left Immediate
instruct sarL_reg_imm6(iRegL dst, iRegL src1, immU6Big src2) %{
  match(Set dst (RShiftL src1 src2));

  size(8);
  format %{ "ASR   $dst.lo,$src1.hi,$src2-32\t! or mov if $src2==32\n\t"
            "ASR   $dst.hi,$src1.hi, $src2" %}
  ins_encode %{
    if ($src2$$constant == 32) {
      __ mov($dst$$Register, $src1$$Register->successor());
    } else{
      __ mov($dst$$Register, AsmOperand($src1$$Register->successor(), asr, $src2$$constant-32));
    }
    __ mov($dst$$Register->successor(), AsmOperand($src1$$Register->successor(), asr, 0));
  %}

  ins_pipe(ialu_reg_imm);
%}

instruct sarL_reg_imm5(iRegL dst, iRegL src1, immU5 src2) %{
  match(Set dst (RShiftL src1 src2));
  size(12);
  format %{ "LSR   $dst.lo,$src1.lo,$src2\n\t"
            "OR    $dst.lo, $dst.lo, $src1.hi << 32-$src2\n\t"
            "ASR   $dst.hi,$src1.hi,$src2" %}
  ins_encode %{
    // The order of the following 3 instructions matters: src1.lo and
    // dst.hi can't overlap but src.hi and dst.hi can.
    __ mov($dst$$Register, AsmOperand($src1$$Register, lsr, $src2$$constant));
    __ orr($dst$$Register, $dst$$Register, AsmOperand($src1$$Register->successor(), lsl, 32-$src2$$constant));
    __ mov($dst$$Register->successor(), AsmOperand($src1$$Register->successor(), asr, $src2$$constant));
  %}
  ins_pipe(ialu_reg_imm);
%}

// Register Shift Right
instruct shrI_reg_reg(iRegI dst, iRegI src1, iRegI src2) %{
  match(Set dst (URShiftI src1 src2));
  size(4);
  format %{ "LSR    $dst,$src1,$src2\t! int" %}
  ins_encode %{
    __ mov($dst$$Register, AsmOperand($src1$$Register, lsr, $src2$$Register));
  %}
  ins_pipe(ialu_reg_reg);
%}

// Register Shift Right Immediate
instruct shrI_reg_imm5(iRegI dst, iRegI src1, immU5 src2) %{
  match(Set dst (URShiftI src1 src2));

  size(4);
  format %{ "LSR    $dst,$src1,$src2" %}
  ins_encode %{
    __ mov($dst$$Register, AsmOperand($src1$$Register, lsr, $src2$$constant));
  %}
  ins_pipe(ialu_reg_imm);
%}

// Register Shift Right
instruct shrL_reg_reg_merge_lo(iRegL dst, iRegL src1, iRegI src2) %{
  effect(USE_DEF dst, USE src1, USE src2);
  size(4);
  format %{ "OR   $dst.lo,$dst,($src1.lo >>> $src2)"  %}
  ins_encode %{
    __ orr($dst$$Register, $dst$$Register, AsmOperand($src1$$Register, lsr, $src2$$Register));
  %}
  ins_pipe(ialu_reg_reg);
%}

instruct shrL_reg_reg_merge_hi(iRegL dst, iRegL src1, iRegI src2) %{
  effect(USE_DEF dst, USE src1, USE src2);
  size(4);
  format %{ "LSR  $dst.hi,$src1.hi,$src2 \n\t" %}
  ins_encode %{
    __ mov($dst$$Register->successor(), AsmOperand($src1$$Register->successor(), lsr, $src2$$Register));
  %}
  ins_pipe(ialu_reg_reg);
%}

instruct shrL_reg_reg_overlap(iRegL dst, iRegL src1, iRegI src2, flagsReg ccr) %{
  effect(DEF dst, USE src1, USE src2, KILL ccr);
  size(16);
  format %{ "SUBS  $dst,$src2,32 \n\t"
            "LSRpl $dst,$src1.hi,$dst \n\t"
            "RSBmi $dst,$dst,0 \n\t"
            "LSLmi $dst,$src1.hi,$dst" %}

  ins_encode %{
    // $src1$$Register->successor() and $dst$$Register can't be the same
    __ subs($dst$$Register, $src2$$Register, 32);
    __ mov($dst$$Register, AsmOperand($src1$$Register->successor(), lsr, $dst$$Register), pl);
    __ rsb($dst$$Register, $dst$$Register, 0, mi);
    __ mov($dst$$Register, AsmOperand($src1$$Register->successor(), lsl, $dst$$Register), mi);
  %}
  ins_pipe(ialu_reg_reg);
%}

instruct shrL_reg_reg(iRegL dst, iRegL src1, iRegI src2) %{
  match(Set dst (URShiftL src1 src2));

  expand %{
    flagsReg ccr;
    shrL_reg_reg_overlap(dst, src1, src2, ccr);
    shrL_reg_reg_merge_lo(dst, src1, src2);
    shrL_reg_reg_merge_hi(dst, src1, src2);
  %}
%}

// Register Shift Right Immediate
instruct shrL_reg_imm6(iRegL dst, iRegL src1, immU6Big src2) %{
  match(Set dst (URShiftL src1 src2));

  size(8);
  format %{ "LSR   $dst.lo,$src1.hi,$src2-32\t! or mov if $src2==32\n\t"
            "MOV   $dst.hi, 0" %}
  ins_encode %{
    if ($src2$$constant == 32) {
      __ mov($dst$$Register, $src1$$Register->successor());
    } else {
      __ mov($dst$$Register, AsmOperand($src1$$Register->successor(), lsr, $src2$$constant-32));
    }
    __ mov($dst$$Register->successor(), 0);
  %}

  ins_pipe(ialu_reg_imm);
%}

instruct shrL_reg_imm5(iRegL dst, iRegL src1, immU5 src2) %{
  match(Set dst (URShiftL src1 src2));

  size(12);
  format %{ "LSR   $dst.lo,$src1.lo,$src2\n\t"
            "OR    $dst.lo, $dst.lo, $src1.hi << 32-$src2\n\t"
            "LSR   $dst.hi,$src1.hi,$src2" %}
  ins_encode %{
    // The order of the following 3 instructions matters: src1.lo and
    // dst.hi can't overlap but src.hi and dst.hi can.
    __ mov($dst$$Register, AsmOperand($src1$$Register, lsr, $src2$$constant));
    __ orr($dst$$Register, $dst$$Register, AsmOperand($src1$$Register->successor(), lsl, 32-$src2$$constant));
    __ mov($dst$$Register->successor(), AsmOperand($src1$$Register->successor(), lsr, $src2$$constant));
  %}
  ins_pipe(ialu_reg_imm);
%}


instruct shrP_reg_imm5(iRegX dst, iRegP src1, immU5 src2) %{
  match(Set dst (URShiftI (CastP2X src1) src2));
  size(4);
  format %{ "LSR    $dst,$src1,$src2\t! Cast ptr $src1 to int and shift" %}
  ins_encode %{
    __ logical_shift_right($dst$$Register, $src1$$Register, $src2$$constant);
  %}
  ins_pipe(ialu_reg_imm);
%}

//----------Floating Point Arithmetic Instructions-----------------------------

//  Add float single precision
instruct addF_reg_reg(regF dst, regF src1, regF src2) %{
  match(Set dst (AddF src1 src2));

  size(4);
  format %{ "FADDS  $dst,$src1,$src2" %}
  ins_encode %{
    __ add_float($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister);
  %}

  ins_pipe(faddF_reg_reg);
%}

//  Add float double precision
instruct addD_reg_reg(regD dst, regD src1, regD src2) %{
  match(Set dst (AddD src1 src2));

  size(4);
  format %{ "FADDD  $dst,$src1,$src2" %}
  ins_encode %{
    __ add_double($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister);
  %}

  ins_pipe(faddD_reg_reg);
%}

//  Sub float single precision
instruct subF_reg_reg(regF dst, regF src1, regF src2) %{
  match(Set dst (SubF src1 src2));

  size(4);
  format %{ "FSUBS  $dst,$src1,$src2" %}
  ins_encode %{
    __ sub_float($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister);
  %}
  ins_pipe(faddF_reg_reg);
%}

//  Sub float double precision
instruct subD_reg_reg(regD dst, regD src1, regD src2) %{
  match(Set dst (SubD src1 src2));

  size(4);
  format %{ "FSUBD  $dst,$src1,$src2" %}
  ins_encode %{
    __ sub_double($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister);
  %}
  ins_pipe(faddD_reg_reg);
%}

//  Mul float single precision
instruct mulF_reg_reg(regF dst, regF src1, regF src2) %{
  match(Set dst (MulF src1 src2));

  size(4);
  format %{ "FMULS  $dst,$src1,$src2" %}
  ins_encode %{
    __ mul_float($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister);
  %}

  ins_pipe(fmulF_reg_reg);
%}

//  Mul float double precision
instruct mulD_reg_reg(regD dst, regD src1, regD src2) %{
  match(Set dst (MulD src1 src2));

  size(4);
  format %{ "FMULD  $dst,$src1,$src2" %}
  ins_encode %{
    __ mul_double($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister);
  %}

  ins_pipe(fmulD_reg_reg);
%}

//  Div float single precision
instruct divF_reg_reg(regF dst, regF src1, regF src2) %{
  match(Set dst (DivF src1 src2));

  size(4);
  format %{ "FDIVS  $dst,$src1,$src2" %}
  ins_encode %{
    __ div_float($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister);
  %}

  ins_pipe(fdivF_reg_reg);
%}

//  Div float double precision
instruct divD_reg_reg(regD dst, regD src1, regD src2) %{
  match(Set dst (DivD src1 src2));

  size(4);
  format %{ "FDIVD  $dst,$src1,$src2" %}
  ins_encode %{
    __ div_double($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister);
  %}

  ins_pipe(fdivD_reg_reg);
%}

//  Absolute float double precision
instruct absD_reg(regD dst, regD src) %{
  match(Set dst (AbsD src));

  size(4);
  format %{ "FABSd  $dst,$src" %}
  ins_encode %{
    __ abs_double($dst$$FloatRegister, $src$$FloatRegister);
  %}
  ins_pipe(faddD_reg);
%}

//  Absolute float single precision
instruct absF_reg(regF dst, regF src) %{
  match(Set dst (AbsF src));
  format %{ "FABSs  $dst,$src" %}
  ins_encode %{
    __ abs_float($dst$$FloatRegister, $src$$FloatRegister);
  %}
  ins_pipe(faddF_reg);
%}

instruct negF_reg(regF dst, regF src) %{
  match(Set dst (NegF src));

  size(4);
  format %{ "FNEGs  $dst,$src" %}
  ins_encode %{
    __ neg_float($dst$$FloatRegister, $src$$FloatRegister);
  %}
  ins_pipe(faddF_reg);
%}

instruct negD_reg(regD dst, regD src) %{
  match(Set dst (NegD src));

  format %{ "FNEGd  $dst,$src" %}
  ins_encode %{
    __ neg_double($dst$$FloatRegister, $src$$FloatRegister);
  %}
  ins_pipe(faddD_reg);
%}

//  Sqrt float double precision
instruct sqrtF_reg_reg(regF dst, regF src) %{
  match(Set dst (ConvD2F (SqrtD (ConvF2D src))));

  size(4);
  format %{ "FSQRTS $dst,$src" %}
  ins_encode %{
    __ sqrt_float($dst$$FloatRegister, $src$$FloatRegister);
  %}
  ins_pipe(fdivF_reg_reg);
%}

//  Sqrt float double precision
instruct sqrtD_reg_reg(regD dst, regD src) %{
  match(Set dst (SqrtD src));

  size(4);
  format %{ "FSQRTD $dst,$src" %}
  ins_encode %{
    __ sqrt_double($dst$$FloatRegister, $src$$FloatRegister);
  %}
  ins_pipe(fdivD_reg_reg);
%}

//----------Logical Instructions-----------------------------------------------
// And Instructions
// Register And
instruct andI_reg_reg(iRegI dst, iRegI src1, iRegI src2) %{
  match(Set dst (AndI src1 src2));

  size(4);
  format %{ "and_32 $dst,$src1,$src2" %}
  ins_encode %{
    __ and_32($dst$$Register, $src1$$Register, $src2$$Register);
  %}
  ins_pipe(ialu_reg_reg);
%}

instruct andshlI_reg_reg_reg(iRegI dst, iRegI src1, iRegI src2, iRegI src3) %{
  match(Set dst (AndI src1 (LShiftI src2 src3)));

  size(4);
  format %{ "AND    $dst,$src1,$src2<<$src3" %}
  ins_encode %{
    __ andr($dst$$Register, $src1$$Register, AsmOperand($src2$$Register, lsl, $src3$$Register));
  %}
  ins_pipe(ialu_reg_reg);
%}

instruct andshlI_reg_reg_imm(iRegI dst, iRegI src1, iRegI src2, immU5 src3) %{
  match(Set dst (AndI src1 (LShiftI src2 src3)));

  size(4);
  format %{ "and_32 $dst,$src1,$src2<<$src3" %}
  ins_encode %{
    __ and_32($dst$$Register, $src1$$Register, AsmOperand($src2$$Register, lsl, $src3$$constant));
  %}
  ins_pipe(ialu_reg_reg);
%}

instruct andsarI_reg_reg_reg(iRegI dst, iRegI src1, iRegI src2, iRegI src3) %{
  match(Set dst (AndI src1 (RShiftI src2 src3)));

  size(4);
  format %{ "AND    $dst,$src1,$src2>>$src3" %}
  ins_encode %{
    __ andr($dst$$Register, $src1$$Register, AsmOperand($src2$$Register, asr, $src3$$Register));
  %}
  ins_pipe(ialu_reg_reg);
%}

instruct andsarI_reg_reg_imm(iRegI dst, iRegI src1, iRegI src2, immU5 src3) %{
  match(Set dst (AndI src1 (RShiftI src2 src3)));

  size(4);
  format %{ "and_32 $dst,$src1,$src2>>$src3" %}
  ins_encode %{
    __ and_32($dst$$Register, $src1$$Register, AsmOperand($src2$$Register, asr, $src3$$constant));
  %}
  ins_pipe(ialu_reg_reg);
%}

instruct andshrI_reg_reg_reg(iRegI dst, iRegI src1, iRegI src2, iRegI src3) %{
  match(Set dst (AndI src1 (URShiftI src2 src3)));

  size(4);
  format %{ "AND    $dst,$src1,$src2>>>$src3" %}
  ins_encode %{
    __ andr($dst$$Register, $src1$$Register, AsmOperand($src2$$Register, lsr, $src3$$Register));
  %}
  ins_pipe(ialu_reg_reg);
%}

instruct andshrI_reg_reg_imm(iRegI dst, iRegI src1, iRegI src2, immU5 src3) %{
  match(Set dst (AndI src1 (URShiftI src2 src3)));

  size(4);
  format %{ "and_32 $dst,$src1,$src2>>>$src3" %}
  ins_encode %{
    __ and_32($dst$$Register, $src1$$Register, AsmOperand($src2$$Register, lsr, $src3$$constant));
  %}
  ins_pipe(ialu_reg_reg);
%}

// Immediate And
instruct andI_reg_limm(iRegI dst, iRegI src1, limmI src2) %{
  match(Set dst (AndI src1 src2));

  size(4);
  format %{ "and_32 $dst,$src1,$src2\t! int" %}
  ins_encode %{
    __ and_32($dst$$Register, $src1$$Register, $src2$$constant);
  %}
  ins_pipe(ialu_reg_imm);
%}

instruct andI_reg_limmn(iRegI dst, iRegI src1, limmIn src2) %{
  match(Set dst (AndI src1 src2));

  size(4);
  format %{ "bic    $dst,$src1,~$src2\t! int" %}
  ins_encode %{
    __ bic($dst$$Register, $src1$$Register, ~$src2$$constant);
  %}
  ins_pipe(ialu_reg_imm);
%}

// Register And Long
instruct andL_reg_reg(iRegL dst, iRegL src1, iRegL src2) %{
  match(Set dst (AndL src1 src2));

  ins_cost(DEFAULT_COST);
  size(8);
  format %{ "AND    $dst,$src1,$src2\t! long" %}
  ins_encode %{
    __ andr($dst$$Register, $src1$$Register, $src2$$Register);
    __ andr($dst$$Register->successor(), $src1$$Register->successor(), $src2$$Register->successor());
  %}
  ins_pipe(ialu_reg_reg);
%}

// TODO: try immLRot2 instead, (0, $con$$constant) becomes
// (hi($con$$constant), lo($con$$constant)) becomes
instruct andL_reg_immRot(iRegL dst, iRegL src1, immLlowRot con) %{
  match(Set dst (AndL src1 con));
  ins_cost(DEFAULT_COST);
  size(8);
  format %{ "AND    $dst,$src1,$con\t! long" %}
  ins_encode %{
    __ andr($dst$$Register, $src1$$Register, $con$$constant);
    __ andr($dst$$Register->successor(), $src1$$Register->successor(), 0);
  %}
  ins_pipe(ialu_reg_imm);
%}

// Or Instructions
// Register Or
instruct orI_reg_reg(iRegI dst, iRegI src1, iRegI src2) %{
  match(Set dst (OrI src1 src2));

  size(4);
  format %{ "orr_32 $dst,$src1,$src2\t! int" %}
  ins_encode %{
    __ orr_32($dst$$Register, $src1$$Register, $src2$$Register);
  %}
  ins_pipe(ialu_reg_reg);
%}

instruct orshlI_reg_reg_reg(iRegI dst, iRegI src1, iRegI src2, iRegI src3) %{
  match(Set dst (OrI src1 (LShiftI src2 src3)));

  size(4);
  format %{ "OR    $dst,$src1,$src2<<$src3" %}
  ins_encode %{
    __ orr($dst$$Register, $src1$$Register, AsmOperand($src2$$Register, lsl, $src3$$Register));
  %}
  ins_pipe(ialu_reg_reg);
%}

instruct orshlI_reg_reg_imm(iRegI dst, iRegI src1, iRegI src2, immU5 src3) %{
  match(Set dst (OrI src1 (LShiftI src2 src3)));

  size(4);
  format %{ "orr_32 $dst,$src1,$src2<<$src3" %}
  ins_encode %{
    __ orr_32($dst$$Register, $src1$$Register, AsmOperand($src2$$Register, lsl, $src3$$constant));
  %}
  ins_pipe(ialu_reg_reg);
%}

instruct orsarI_reg_reg_reg(iRegI dst, iRegI src1, iRegI src2, iRegI src3) %{
  match(Set dst (OrI src1 (RShiftI src2 src3)));

  size(4);
  format %{ "OR    $dst,$src1,$src2>>$src3" %}
  ins_encode %{
    __ orr($dst$$Register, $src1$$Register, AsmOperand($src2$$Register, asr, $src3$$Register));
  %}
  ins_pipe(ialu_reg_reg);
%}

instruct orsarI_reg_reg_imm(iRegI dst, iRegI src1, iRegI src2, immU5 src3) %{
  match(Set dst (OrI src1 (RShiftI src2 src3)));

  size(4);
  format %{ "orr_32 $dst,$src1,$src2>>$src3" %}
  ins_encode %{
    __ orr_32($dst$$Register, $src1$$Register, AsmOperand($src2$$Register, asr, $src3$$constant));
  %}
  ins_pipe(ialu_reg_reg);
%}

instruct orshrI_reg_reg_reg(iRegI dst, iRegI src1, iRegI src2, iRegI src3) %{
  match(Set dst (OrI src1 (URShiftI src2 src3)));

  size(4);
  format %{ "OR    $dst,$src1,$src2>>>$src3" %}
  ins_encode %{
    __ orr($dst$$Register, $src1$$Register, AsmOperand($src2$$Register, lsr, $src3$$Register));
  %}
  ins_pipe(ialu_reg_reg);
%}

instruct orshrI_reg_reg_imm(iRegI dst, iRegI src1, iRegI src2, immU5 src3) %{
  match(Set dst (OrI src1 (URShiftI src2 src3)));

  size(4);
  format %{ "orr_32 $dst,$src1,$src2>>>$src3" %}
  ins_encode %{
    __ orr_32($dst$$Register, $src1$$Register, AsmOperand($src2$$Register, lsr, $src3$$constant));
  %}
  ins_pipe(ialu_reg_reg);
%}

// Immediate Or
instruct orI_reg_limm(iRegI dst, iRegI src1, limmI src2) %{
  match(Set dst (OrI src1 src2));

  size(4);
  format %{ "orr_32  $dst,$src1,$src2" %}
  ins_encode %{
    __ orr_32($dst$$Register, $src1$$Register, $src2$$constant);
  %}
  ins_pipe(ialu_reg_imm);
%}
// TODO: orn_32 with limmIn

// Register Or Long
instruct orL_reg_reg(iRegL dst, iRegL src1, iRegL src2) %{
  match(Set dst (OrL src1 src2));

  ins_cost(DEFAULT_COST);
  size(8);
  format %{ "OR     $dst.lo,$src1.lo,$src2.lo\t! long\n\t"
            "OR     $dst.hi,$src1.hi,$src2.hi" %}
  ins_encode %{
    __ orr($dst$$Register, $src1$$Register, $src2$$Register);
    __ orr($dst$$Register->successor(), $src1$$Register->successor(), $src2$$Register->successor());
  %}
  ins_pipe(ialu_reg_reg);
%}

// TODO: try immLRot2 instead, (0, $con$$constant) becomes
// (hi($con$$constant), lo($con$$constant)) becomes
instruct orL_reg_immRot(iRegL dst, iRegL src1, immLlowRot con) %{
  match(Set dst (OrL src1 con));
  ins_cost(DEFAULT_COST);
  size(8);
  format %{ "OR     $dst.lo,$src1.lo,$con\t! long\n\t"
            "OR     $dst.hi,$src1.hi,$con" %}
  ins_encode %{
    __ orr($dst$$Register, $src1$$Register, $con$$constant);
    __ orr($dst$$Register->successor(), $src1$$Register->successor(), 0);
  %}
  ins_pipe(ialu_reg_imm);
%}

#ifdef TODO
// Use SPRegP to match Rthread (TLS register) without spilling.
// Use store_ptr_RegP to match Rthread (TLS register) without spilling.
// Use sp_ptr_RegP to match Rthread (TLS register) without spilling.
instruct orI_reg_castP2X(iRegI dst, iRegI src1, sp_ptr_RegP src2) %{
  match(Set dst (OrI src1 (CastP2X src2)));
  size(4);
  format %{ "OR     $dst,$src1,$src2" %}
  ins_encode %{
    __ orr($dst$$Register, $src1$$Register, $src2$$Register);
  %}
  ins_pipe(ialu_reg_reg);
%}
#endif

// Xor Instructions
// Register Xor
instruct xorI_reg_reg(iRegI dst, iRegI src1, iRegI src2) %{
  match(Set dst (XorI src1 src2));

  size(4);
  format %{ "eor_32 $dst,$src1,$src2" %}
  ins_encode %{
    __ eor_32($dst$$Register, $src1$$Register, $src2$$Register);
  %}
  ins_pipe(ialu_reg_reg);
%}

instruct xorshlI_reg_reg_reg(iRegI dst, iRegI src1, iRegI src2, iRegI src3) %{
  match(Set dst (XorI src1 (LShiftI src2 src3)));

  size(4);
  format %{ "XOR    $dst,$src1,$src2<<$src3" %}
  ins_encode %{
    __ eor($dst$$Register, $src1$$Register, AsmOperand($src2$$Register, lsl, $src3$$Register));
  %}
  ins_pipe(ialu_reg_reg);
%}

instruct xorshlI_reg_reg_imm(iRegI dst, iRegI src1, iRegI src2, immU5 src3) %{
  match(Set dst (XorI src1 (LShiftI src2 src3)));

  size(4);
  format %{ "eor_32 $dst,$src1,$src2<<$src3" %}
  ins_encode %{
    __ eor_32($dst$$Register, $src1$$Register, AsmOperand($src2$$Register, lsl, $src3$$constant));
  %}
  ins_pipe(ialu_reg_reg);
%}

instruct xorsarI_reg_reg_reg(iRegI dst, iRegI src1, iRegI src2, iRegI src3) %{
  match(Set dst (XorI src1 (RShiftI src2 src3)));

  size(4);
  format %{ "XOR    $dst,$src1,$src2>>$src3" %}
  ins_encode %{
    __ eor($dst$$Register, $src1$$Register, AsmOperand($src2$$Register, asr, $src3$$Register));
  %}
  ins_pipe(ialu_reg_reg);
%}

instruct xorsarI_reg_reg_imm(iRegI dst, iRegI src1, iRegI src2, immU5 src3) %{
  match(Set dst (XorI src1 (RShiftI src2 src3)));

  size(4);
  format %{ "eor_32 $dst,$src1,$src2>>$src3" %}
  ins_encode %{
    __ eor_32($dst$$Register, $src1$$Register, AsmOperand($src2$$Register, asr, $src3$$constant));
  %}
  ins_pipe(ialu_reg_reg);
%}

instruct xorshrI_reg_reg_reg(iRegI dst, iRegI src1, iRegI src2, iRegI src3) %{
  match(Set dst (XorI src1 (URShiftI src2 src3)));

  size(4);
  format %{ "XOR    $dst,$src1,$src2>>>$src3" %}
  ins_encode %{
    __ eor($dst$$Register, $src1$$Register, AsmOperand($src2$$Register, lsr, $src3$$Register));
  %}
  ins_pipe(ialu_reg_reg);
%}

instruct xorshrI_reg_reg_imm(iRegI dst, iRegI src1, iRegI src2, immU5 src3) %{
  match(Set dst (XorI src1 (URShiftI src2 src3)));

  size(4);
  format %{ "eor_32 $dst,$src1,$src2>>>$src3" %}
  ins_encode %{
    __ eor_32($dst$$Register, $src1$$Register, AsmOperand($src2$$Register, lsr, $src3$$constant));
  %}
  ins_pipe(ialu_reg_reg);
%}

// Immediate Xor
instruct xorI_reg_imm(iRegI dst, iRegI src1, limmI src2) %{
  match(Set dst (XorI src1 src2));

  size(4);
  format %{ "eor_32 $dst,$src1,$src2" %}
  ins_encode %{
    __ eor_32($dst$$Register, $src1$$Register, $src2$$constant);
  %}
  ins_pipe(ialu_reg_imm);
%}

// Register Xor Long
instruct xorL_reg_reg(iRegL dst, iRegL src1, iRegL src2) %{
  match(Set dst (XorL src1 src2));
  ins_cost(DEFAULT_COST);
  size(8);
  format %{ "XOR     $dst.hi,$src1.hi,$src2.hi\t! long\n\t"
            "XOR     $dst.lo,$src1.lo,$src2.lo\t! long" %}
  ins_encode %{
    __ eor($dst$$Register, $src1$$Register, $src2$$Register);
    __ eor($dst$$Register->successor(), $src1$$Register->successor(), $src2$$Register->successor());
  %}
  ins_pipe(ialu_reg_reg);
%}

// TODO: try immLRot2 instead, (0, $con$$constant) becomes
// (hi($con$$constant), lo($con$$constant)) becomes
instruct xorL_reg_immRot(iRegL dst, iRegL src1, immLlowRot con) %{
  match(Set dst (XorL src1 con));
  ins_cost(DEFAULT_COST);
  size(8);
  format %{ "XOR     $dst.hi,$src1.hi,$con\t! long\n\t"
            "XOR     $dst.lo,$src1.lo,0\t! long" %}
  ins_encode %{
    __ eor($dst$$Register, $src1$$Register, $con$$constant);
    __ eor($dst$$Register->successor(), $src1$$Register->successor(), 0);
  %}
  ins_pipe(ialu_reg_imm);
%}

//----------Convert to Boolean-------------------------------------------------
instruct convI2B( iRegI dst, iRegI src, flagsReg ccr ) %{
  match(Set dst (Conv2B src));
  effect(KILL ccr);
  size(12);
  ins_cost(DEFAULT_COST*2);
  format %{ "TST    $src,$src \n\t"
            "MOV    $dst, 0   \n\t"
            "MOV.ne $dst, 1" %}
  ins_encode %{ // FIXME: can do better?
    __ tst($src$$Register, $src$$Register);
    __ mov($dst$$Register, 0);
    __ mov($dst$$Register, 1, ne);
  %}
  ins_pipe(ialu_reg_ialu);
%}

instruct convP2B( iRegI dst, iRegP src, flagsReg ccr ) %{
  match(Set dst (Conv2B src));
  effect(KILL ccr);
  size(12);
  ins_cost(DEFAULT_COST*2);
  format %{ "TST    $src,$src \n\t"
            "MOV    $dst, 0   \n\t"
            "MOV.ne $dst, 1" %}
  ins_encode %{
    __ tst($src$$Register, $src$$Register);
    __ mov($dst$$Register, 0);
    __ mov($dst$$Register, 1, ne);
  %}
  ins_pipe(ialu_reg_ialu);
%}

instruct cmpLTMask_reg_reg( iRegI dst, iRegI p, iRegI q, flagsReg ccr ) %{
  match(Set dst (CmpLTMask p q));
  effect( KILL ccr );
  ins_cost(DEFAULT_COST*3);
  format %{ "CMP    $p,$q\n\t"
            "MOV    $dst, #0\n\t"
            "MOV.lt $dst, #-1" %}
  ins_encode %{
    __ cmp($p$$Register, $q$$Register);
    __ mov($dst$$Register, 0);
    __ mvn($dst$$Register, 0, lt);
  %}
  ins_pipe(ialu_reg_reg_ialu);
%}

instruct cmpLTMask_reg_imm( iRegI dst, iRegI p, aimmI q, flagsReg ccr ) %{
  match(Set dst (CmpLTMask p q));
  effect( KILL ccr );
  ins_cost(DEFAULT_COST*3);
  format %{ "CMP    $p,$q\n\t"
            "MOV    $dst, #0\n\t"
            "MOV.lt $dst, #-1" %}
  ins_encode %{
    __ cmp($p$$Register, $q$$constant);
    __ mov($dst$$Register, 0);
    __ mvn($dst$$Register, 0, lt);
  %}
  ins_pipe(ialu_reg_reg_ialu);
%}

instruct cadd_cmpLTMask3( iRegI p, iRegI q, iRegI y, iRegI z, flagsReg ccr ) %{
  match(Set z (AddI (AndI (CmpLTMask p q) y) z));
  effect( KILL ccr );
  ins_cost(DEFAULT_COST*2);
  format %{ "CMP    $p,$q\n\t"
            "ADD.lt $z,$y,$z" %}
  ins_encode %{
    __ cmp($p$$Register, $q$$Register);
    __ add($z$$Register, $y$$Register, $z$$Register, lt);
  %}
  ins_pipe( cadd_cmpltmask );
%}

// FIXME: remove unused "dst"
instruct cadd_cmpLTMask4( iRegI dst, iRegI p, aimmI q, iRegI y, iRegI z, flagsReg ccr ) %{
  match(Set z (AddI (AndI (CmpLTMask p q) y) z));
  effect( KILL ccr );
  ins_cost(DEFAULT_COST*2);
  format %{ "CMP    $p,$q\n\t"
            "ADD.lt $z,$y,$z" %}
  ins_encode %{
    __ cmp($p$$Register, $q$$constant);
    __ add($z$$Register, $y$$Register, $z$$Register, lt);
  %}
  ins_pipe( cadd_cmpltmask );
%}

instruct cadd_cmpLTMask( iRegI p, iRegI q, iRegI y, flagsReg ccr ) %{
  match(Set p (AddI (AndI (CmpLTMask p q) y) (SubI p q)));
  effect( KILL ccr );
  ins_cost(DEFAULT_COST*2);
  format %{ "SUBS   $p,$p,$q\n\t"
            "ADD.lt $p,$y,$p" %}
  ins_encode %{
    __ subs($p$$Register, $p$$Register, $q$$Register);
    __ add($p$$Register, $y$$Register, $p$$Register, lt);
  %}
  ins_pipe( cadd_cmpltmask );
%}

//----------Arithmetic Conversion Instructions---------------------------------
// The conversions operations are all Alpha sorted.  Please keep it that way!

instruct convD2F_reg(regF dst, regD src) %{
  match(Set dst (ConvD2F src));
  size(4);
  format %{ "FCVTSD  $dst,$src" %}
  ins_encode %{
    __ convert_d2f($dst$$FloatRegister, $src$$FloatRegister);
  %}
  ins_pipe(fcvtD2F);
%}

// Convert a double to an int in a float register.
// If the double is a NAN, stuff a zero in instead.

instruct convD2I_reg_reg(iRegI dst, regD src, regF tmp) %{
  match(Set dst (ConvD2I src));
  effect( TEMP tmp );
  ins_cost(DEFAULT_COST*2 + MEMORY_REF_COST*2 + BRANCH_COST); // FIXME
  format %{ "FTOSIZD  $tmp,$src\n\t"
            "FMRS     $dst, $tmp" %}
  ins_encode %{
    __ ftosizd($tmp$$FloatRegister, $src$$FloatRegister);
    __ fmrs($dst$$Register, $tmp$$FloatRegister);
  %}
  ins_pipe(fcvtD2I);
%}

// Convert a double to a long in a double register.
// If the double is a NAN, stuff a zero in instead.

// Double to Long conversion
instruct convD2L_reg(R0R1RegL dst, regD src) %{
  match(Set dst (ConvD2L src));
  effect(CALL);
  ins_cost(MEMORY_REF_COST); // FIXME
  format %{ "convD2L    $dst,$src\t ! call to SharedRuntime::d2l" %}
  ins_encode %{
#ifndef __ABI_HARD__
    __ fmrrd($dst$$Register, $dst$$Register->successor(), $src$$FloatRegister);
#else
    if ($src$$FloatRegister != D0) {
      __ mov_double(D0, $src$$FloatRegister);
    }
#endif
    address target = CAST_FROM_FN_PTR(address, SharedRuntime::d2l);
    __ call(target, relocInfo::runtime_call_type);
  %}
  ins_pipe(fcvtD2L);
%}

instruct convF2D_reg(regD dst, regF src) %{
  match(Set dst (ConvF2D src));
  size(4);
  format %{ "FCVTDS  $dst,$src" %}
  ins_encode %{
    __ convert_f2d($dst$$FloatRegister, $src$$FloatRegister);
  %}
  ins_pipe(fcvtF2D);
%}

instruct convF2I_reg_reg(iRegI dst, regF src, regF tmp) %{
  match(Set dst (ConvF2I src));
  effect( TEMP tmp );
  ins_cost(DEFAULT_COST*2 + MEMORY_REF_COST*2 + BRANCH_COST); // FIXME
  size(8);
  format %{ "FTOSIZS  $tmp,$src\n\t"
            "FMRS     $dst, $tmp" %}
  ins_encode %{
    __ ftosizs($tmp$$FloatRegister, $src$$FloatRegister);
    __ fmrs($dst$$Register, $tmp$$FloatRegister);
  %}
  ins_pipe(fcvtF2I);
%}

// Float to Long conversion
instruct convF2L_reg(R0R1RegL dst, regF src, R0RegI arg1) %{
  match(Set dst (ConvF2L src));
  ins_cost(DEFAULT_COST*2 + MEMORY_REF_COST*2 + BRANCH_COST); // FIXME
  effect(CALL);
  format %{ "convF2L  $dst,$src\t! call to SharedRuntime::f2l" %}
  ins_encode %{
#ifndef __ABI_HARD__
    __ fmrs($arg1$$Register, $src$$FloatRegister);
#else
    if($src$$FloatRegister != S0) {
      __ mov_float(S0, $src$$FloatRegister);
    }
#endif
    address target = CAST_FROM_FN_PTR(address, SharedRuntime::f2l);
    __ call(target, relocInfo::runtime_call_type);
  %}
  ins_pipe(fcvtF2L);
%}

instruct convI2D_reg_reg(iRegI src, regD_low dst) %{
  match(Set dst (ConvI2D src));
  ins_cost(DEFAULT_COST + MEMORY_REF_COST); // FIXME
  size(8);
  format %{ "FMSR     $dst,$src \n\t"
            "FSITOD   $dst $dst"%}
  ins_encode %{
      __ fmsr($dst$$FloatRegister, $src$$Register);
      __ fsitod($dst$$FloatRegister, $dst$$FloatRegister);
  %}
  ins_pipe(fcvtI2D);
%}

instruct convI2F_reg_reg( regF dst, iRegI src ) %{
  match(Set dst (ConvI2F src));
  ins_cost(DEFAULT_COST + MEMORY_REF_COST); // FIXME
  size(8);
  format %{ "FMSR     $dst,$src \n\t"
            "FSITOS   $dst, $dst"%}
  ins_encode %{
      __ fmsr($dst$$FloatRegister, $src$$Register);
      __ fsitos($dst$$FloatRegister, $dst$$FloatRegister);
  %}
  ins_pipe(fcvtI2F);
%}

instruct convI2L_reg(iRegL dst, iRegI src) %{
  match(Set dst (ConvI2L src));
  size(8);
  format %{ "MOV    $dst.lo, $src \n\t"
            "ASR    $dst.hi,$src,31\t! int->long" %}
  ins_encode %{
    __ mov($dst$$Register, $src$$Register);
    __ mov($dst$$Register->successor(), AsmOperand($src$$Register, asr, 31));
  %}
  ins_pipe(ialu_reg_reg);
%}

// Zero-extend convert int to long
instruct convI2L_reg_zex(iRegL dst, iRegI src, immL_32bits mask ) %{
  match(Set dst (AndL (ConvI2L src) mask) );
  size(8);
  format %{ "MOV    $dst.lo,$src.lo\t! zero-extend int to long\n\t"
            "MOV    $dst.hi, 0"%}
  ins_encode %{
    __ mov($dst$$Register, $src$$Register);
    __ mov($dst$$Register->successor(), 0);
  %}
  ins_pipe(ialu_reg_reg);
%}

// Zero-extend long
instruct zerox_long(iRegL dst, iRegL src, immL_32bits mask ) %{
  match(Set dst (AndL src mask) );
  size(8);
  format %{ "MOV    $dst.lo,$src.lo\t! zero-extend long\n\t"
            "MOV    $dst.hi, 0"%}
  ins_encode %{
    __ mov($dst$$Register, $src$$Register);
    __ mov($dst$$Register->successor(), 0);
  %}
  ins_pipe(ialu_reg_reg);
%}

instruct MoveF2I_reg_reg(iRegI dst, regF src) %{
  match(Set dst (MoveF2I src));
  effect(DEF dst, USE src);
  ins_cost(MEMORY_REF_COST); // FIXME

  size(4);
  format %{ "FMRS   $dst,$src\t! MoveF2I" %}
  ins_encode %{
    __ fmrs($dst$$Register, $src$$FloatRegister);
  %}
  ins_pipe(iload_mem); // FIXME
%}

instruct MoveI2F_reg_reg(regF dst, iRegI src) %{
  match(Set dst (MoveI2F src));
  ins_cost(MEMORY_REF_COST); // FIXME

  size(4);
  format %{ "FMSR   $dst,$src\t! MoveI2F" %}
  ins_encode %{
    __ fmsr($dst$$FloatRegister, $src$$Register);
  %}
  ins_pipe(iload_mem); // FIXME
%}

instruct MoveD2L_reg_reg(iRegL dst, regD src) %{
  match(Set dst (MoveD2L src));
  effect(DEF dst, USE src);
  ins_cost(MEMORY_REF_COST); // FIXME

  size(4);
  format %{ "FMRRD    $dst,$src\t! MoveD2L" %}
  ins_encode %{
    __ fmrrd($dst$$Register, $dst$$Register->successor(), $src$$FloatRegister);
  %}
  ins_pipe(iload_mem); // FIXME
%}

instruct MoveL2D_reg_reg(regD dst, iRegL src) %{
  match(Set dst (MoveL2D src));
  effect(DEF dst, USE src);
  ins_cost(MEMORY_REF_COST); // FIXME

  size(4);
  format %{ "FMDRR   $dst,$src\t! MoveL2D" %}
  ins_encode %{
    __ fmdrr($dst$$FloatRegister, $src$$Register, $src$$Register->successor());
  %}
  ins_pipe(ialu_reg_reg); // FIXME
%}

//-----------
// Long to Double conversion

// Magic constant, 0x43300000
instruct loadConI_x43300000(iRegI dst) %{
  effect(DEF dst);
  size(8);
  format %{ "MOV_SLOW  $dst,0x43300000\t! 2^52" %}
  ins_encode %{
    __ mov_slow($dst$$Register, 0x43300000);
  %}
  ins_pipe(ialu_none);
%}

// Magic constant, 0x41f00000
instruct loadConI_x41f00000(iRegI dst) %{
  effect(DEF dst);
  size(8);
  format %{ "MOV_SLOW  $dst, 0x41f00000\t! 2^32" %}
  ins_encode %{
    __ mov_slow($dst$$Register, 0x41f00000);
  %}
  ins_pipe(ialu_none);
%}

instruct loadConI_x0(iRegI dst) %{
  effect(DEF dst);
  size(4);
  format %{ "MOV  $dst, 0x0\t! 0" %}
  ins_encode %{
    __ mov($dst$$Register, 0);
  %}
  ins_pipe(ialu_none);
%}

// Construct a double from two float halves
instruct regDHi_regDLo_to_regD(regD_low dst, regD_low src1, regD_low src2) %{
  effect(DEF dst, USE src1, USE src2);
  size(8);
  format %{ "FCPYS  $dst.hi,$src1.hi\n\t"
            "FCPYS  $dst.lo,$src2.lo" %}
  ins_encode %{
    __ fcpys($dst$$FloatRegister->successor(), $src1$$FloatRegister->successor());
    __ fcpys($dst$$FloatRegister, $src2$$FloatRegister);
  %}
  ins_pipe(faddD_reg_reg);
%}

// Convert integer in high half of a double register (in the lower half of
// the double register file) to double
instruct convI2D_regDHi_regD(regD dst, regD_low src) %{
  effect(DEF dst, USE src);
  size(4);
  format %{ "FSITOD  $dst,$src" %}
  ins_encode %{
    __ fsitod($dst$$FloatRegister, $src$$FloatRegister->successor());
  %}
  ins_pipe(fcvtLHi2D);
%}

// Add float double precision
instruct addD_regD_regD(regD dst, regD src1, regD src2) %{
  effect(DEF dst, USE src1, USE src2);
  size(4);
  format %{ "FADDD  $dst,$src1,$src2" %}
  ins_encode %{
    __ add_double($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister);
  %}
  ins_pipe(faddD_reg_reg);
%}

// Sub float double precision
instruct subD_regD_regD(regD dst, regD src1, regD src2) %{
  effect(DEF dst, USE src1, USE src2);
  size(4);
  format %{ "FSUBD  $dst,$src1,$src2" %}
  ins_encode %{
    __ sub_double($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister);
  %}
  ins_pipe(faddD_reg_reg);
%}

// Mul float double precision
instruct mulD_regD_regD(regD dst, regD src1, regD src2) %{
  effect(DEF dst, USE src1, USE src2);
  size(4);
  format %{ "FMULD  $dst,$src1,$src2" %}
  ins_encode %{
    __ mul_double($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister);
  %}
  ins_pipe(fmulD_reg_reg);
%}

instruct regL_to_regD(regD dst, iRegL src) %{
  // No match rule to avoid chain rule match.
  effect(DEF dst, USE src);
  ins_cost(MEMORY_REF_COST);
  size(4);
  format %{ "FMDRR   $dst,$src\t! regL to regD" %}
  ins_encode %{
    __ fmdrr($dst$$FloatRegister, $src$$Register, $src$$Register->successor());
  %}
  ins_pipe(ialu_reg_reg); // FIXME
%}

instruct regI_regI_to_regD(regD dst, iRegI src1, iRegI src2) %{
  // No match rule to avoid chain rule match.
  effect(DEF dst, USE src1, USE src2);
  ins_cost(MEMORY_REF_COST);
  size(4);
  format %{ "FMDRR   $dst,$src1,$src2\t! regI,regI to regD" %}
  ins_encode %{
    __ fmdrr($dst$$FloatRegister, $src1$$Register, $src2$$Register);
  %}
  ins_pipe(ialu_reg_reg); // FIXME
%}

instruct convL2D_reg_slow_fxtof(regD dst, iRegL src) %{
  match(Set dst (ConvL2D src));
  ins_cost(DEFAULT_COST*8 + MEMORY_REF_COST*6); // FIXME

  expand %{
    regD_low   tmpsrc;
    iRegI      ix43300000;
    iRegI      ix41f00000;
    iRegI      ix0;
    regD_low   dx43300000;
    regD       dx41f00000;
    regD       tmp1;
    regD_low   tmp2;
    regD       tmp3;
    regD       tmp4;

    regL_to_regD(tmpsrc, src);

    loadConI_x43300000(ix43300000);
    loadConI_x41f00000(ix41f00000);
    loadConI_x0(ix0);

    regI_regI_to_regD(dx43300000, ix0, ix43300000);
    regI_regI_to_regD(dx41f00000, ix0, ix41f00000);

    convI2D_regDHi_regD(tmp1, tmpsrc);
    regDHi_regDLo_to_regD(tmp2, dx43300000, tmpsrc);
    subD_regD_regD(tmp3, tmp2, dx43300000);
    mulD_regD_regD(tmp4, tmp1, dx41f00000);
    addD_regD_regD(dst, tmp3, tmp4);
  %}
%}

instruct convL2I_reg(iRegI dst, iRegL src) %{
  match(Set dst (ConvL2I src));
  size(4);
  format %{ "MOV    $dst,$src.lo\t! long->int" %}
  ins_encode %{
    __ mov($dst$$Register, $src$$Register);
  %}
  ins_pipe(ialu_move_reg_I_to_L);
%}

// Register Shift Right Immediate
instruct shrL_reg_imm6_L2I(iRegI dst, iRegL src, immI_32_63 cnt) %{
  match(Set dst (ConvL2I (RShiftL src cnt)));
  size(4);
  format %{ "ASR    $dst,$src.hi,($cnt - 32)\t! long->int or mov if $cnt==32" %}
  ins_encode %{
    if ($cnt$$constant == 32) {
      __ mov($dst$$Register, $src$$Register->successor());
    } else {
      __ mov($dst$$Register, AsmOperand($src$$Register->successor(), asr, $cnt$$constant - 32));
    }
  %}
  ins_pipe(ialu_reg_imm);
%}


//----------Control Flow Instructions------------------------------------------
// Compare Instructions
// Compare Integers
instruct compI_iReg(flagsReg icc, iRegI op1, iRegI op2) %{
  match(Set icc (CmpI op1 op2));
  effect( DEF icc, USE op1, USE op2 );

  size(4);
  format %{ "cmp_32 $op1,$op2\t! int" %}
  ins_encode %{
    __ cmp_32($op1$$Register, $op2$$Register);
  %}
  ins_pipe(ialu_cconly_reg_reg);
%}

#ifdef _LP64
// Compare compressed pointers
instruct compN_reg2(flagsRegU icc, iRegN op1, iRegN op2) %{
  match(Set icc (CmpN op1 op2));
  effect( DEF icc, USE op1, USE op2 );

  size(4);
  format %{ "cmp_32 $op1,$op2\t! int" %}
  ins_encode %{
    __ cmp_32($op1$$Register, $op2$$Register);
  %}
  ins_pipe(ialu_cconly_reg_reg);
%}
#endif

instruct compU_iReg(flagsRegU icc, iRegI op1, iRegI op2) %{
  match(Set icc (CmpU op1 op2));

  size(4);
  format %{ "cmp_32 $op1,$op2\t! unsigned int" %}
  ins_encode %{
    __ cmp_32($op1$$Register, $op2$$Register);
  %}
  ins_pipe(ialu_cconly_reg_reg);
%}

instruct compI_iReg_immneg(flagsReg icc, iRegI op1, aimmIneg op2) %{
  match(Set icc (CmpI op1 op2));
  effect( DEF icc, USE op1 );

  size(4);
  format %{ "cmn_32 $op1,-$op2\t! int" %}
  ins_encode %{
    __ cmn_32($op1$$Register, -$op2$$constant);
  %}
  ins_pipe(ialu_cconly_reg_imm);
%}

instruct compI_iReg_imm(flagsReg icc, iRegI op1, aimmI op2) %{
  match(Set icc (CmpI op1 op2));
  effect( DEF icc, USE op1 );

  size(4);
  format %{ "cmp_32 $op1,$op2\t! int" %}
  ins_encode %{
    __ cmp_32($op1$$Register, $op2$$constant);
  %}
  ins_pipe(ialu_cconly_reg_imm);
%}

instruct testI_reg_reg( flagsReg_EQNELTGE icc, iRegI op1, iRegI op2, immI0 zero ) %{
  match(Set icc (CmpI (AndI op1 op2) zero));
  size(4);
  format %{ "tst_32 $op2,$op1" %}

  ins_encode %{
    __ tst_32($op1$$Register, $op2$$Register);
  %}
  ins_pipe(ialu_cconly_reg_reg_zero);
%}

instruct testshlI_reg_reg_reg( flagsReg_EQNELTGE icc, iRegI op1, iRegI op2, iRegI op3, immI0 zero ) %{
  match(Set icc (CmpI (AndI op1 (LShiftI op2 op3)) zero));
  size(4);
  format %{ "TST   $op2,$op1<<$op3" %}

  ins_encode %{
    __ tst($op1$$Register, AsmOperand($op2$$Register, lsl, $op3$$Register));
  %}
  ins_pipe(ialu_cconly_reg_reg_zero);
%}

instruct testshlI_reg_reg_imm( flagsReg_EQNELTGE icc, iRegI op1, iRegI op2, immU5 op3, immI0 zero ) %{
  match(Set icc (CmpI (AndI op1 (LShiftI op2 op3)) zero));
  size(4);
  format %{ "tst_32 $op2,$op1<<$op3" %}

  ins_encode %{
    __ tst_32($op1$$Register, AsmOperand($op2$$Register, lsl, $op3$$constant));
  %}
  ins_pipe(ialu_cconly_reg_reg_zero);
%}

instruct testsarI_reg_reg_reg( flagsReg_EQNELTGE icc, iRegI op1, iRegI op2, iRegI op3, immI0 zero ) %{
  match(Set icc (CmpI (AndI op1 (RShiftI op2 op3)) zero));
  size(4);
  format %{ "TST   $op2,$op1<<$op3" %}

  ins_encode %{
    __ tst($op1$$Register, AsmOperand($op2$$Register, asr, $op3$$Register));
  %}
  ins_pipe(ialu_cconly_reg_reg_zero);
%}

instruct testsarI_reg_reg_imm( flagsReg_EQNELTGE icc, iRegI op1, iRegI op2, immU5 op3, immI0 zero ) %{
  match(Set icc (CmpI (AndI op1 (RShiftI op2 op3)) zero));
  size(4);
  format %{ "tst_32 $op2,$op1<<$op3" %}

  ins_encode %{
    __ tst_32($op1$$Register, AsmOperand($op2$$Register, asr, $op3$$constant));
  %}
  ins_pipe(ialu_cconly_reg_reg_zero);
%}

instruct testshrI_reg_reg_reg( flagsReg_EQNELTGE icc, iRegI op1, iRegI op2, iRegI op3, immI0 zero ) %{
  match(Set icc (CmpI (AndI op1 (URShiftI op2 op3)) zero));
  size(4);
  format %{ "TST   $op2,$op1<<$op3" %}

  ins_encode %{
    __ tst($op1$$Register, AsmOperand($op2$$Register, lsr, $op3$$Register));
  %}
  ins_pipe(ialu_cconly_reg_reg_zero);
%}

instruct testshrI_reg_reg_imm( flagsReg_EQNELTGE icc, iRegI op1, iRegI op2, immU5 op3, immI0 zero ) %{
  match(Set icc (CmpI (AndI op1 (URShiftI op2 op3)) zero));
  size(4);
  format %{ "tst_32 $op2,$op1<<$op3" %}

  ins_encode %{
    __ tst_32($op1$$Register, AsmOperand($op2$$Register, lsr, $op3$$constant));
  %}
  ins_pipe(ialu_cconly_reg_reg_zero);
%}

instruct testI_reg_imm( flagsReg_EQNELTGE icc, iRegI op1, limmI op2, immI0 zero ) %{
  match(Set icc (CmpI (AndI op1 op2) zero));
  size(4);
  format %{ "tst_32 $op2,$op1" %}

  ins_encode %{
    __ tst_32($op1$$Register, $op2$$constant);
  %}
  ins_pipe(ialu_cconly_reg_imm_zero);
%}

instruct compL_reg_reg_LTGE(flagsRegL_LTGE xcc, iRegL op1, iRegL op2, iRegL tmp) %{
  match(Set xcc (CmpL op1 op2));
  effect( DEF xcc, USE op1, USE op2, TEMP tmp );

  size(8);
  format %{ "SUBS    $tmp,$op1.low,$op2.low\t\t! long\n\t"
            "SBCS    $tmp,$op1.hi,$op2.hi" %}
  ins_encode %{
    __ subs($tmp$$Register, $op1$$Register, $op2$$Register);
    __ sbcs($tmp$$Register->successor(), $op1$$Register->successor(), $op2$$Register->successor());
  %}
  ins_pipe(ialu_cconly_reg_reg);
%}

instruct compUL_reg_reg_LTGE(flagsRegUL_LTGE xcc, iRegL op1, iRegL op2, iRegL tmp) %{
  match(Set xcc (CmpUL op1 op2));
  effect(DEF xcc, USE op1, USE op2, TEMP tmp);

  size(8);
  format %{ "SUBS    $tmp,$op1.low,$op2.low\t\t! unsigned long\n\t"
            "SBCS    $tmp,$op1.hi,$op2.hi" %}
  ins_encode %{
    __ subs($tmp$$Register, $op1$$Register, $op2$$Register);
    __ sbcs($tmp$$Register->successor(), $op1$$Register->successor(), $op2$$Register->successor());
  %}
  ins_pipe(ialu_cconly_reg_reg);
%}

instruct compL_reg_reg_EQNE(flagsRegL_EQNE xcc, iRegL op1, iRegL op2) %{
  match(Set xcc (CmpL op1 op2));
  effect( DEF xcc, USE op1, USE op2 );

  size(8);
  format %{ "TEQ    $op1.hi,$op2.hi\t\t! long\n\t"
            "TEQ.eq $op1.lo,$op2.lo" %}
  ins_encode %{
    __ teq($op1$$Register->successor(), $op2$$Register->successor());
    __ teq($op1$$Register, $op2$$Register, eq);
  %}
  ins_pipe(ialu_cconly_reg_reg);
%}

instruct compL_reg_reg_LEGT(flagsRegL_LEGT xcc, iRegL op1, iRegL op2, iRegL tmp) %{
  match(Set xcc (CmpL op1 op2));
  effect( DEF xcc, USE op1, USE op2, TEMP tmp );

  size(8);
  format %{ "SUBS    $tmp,$op2.low,$op1.low\t\t! long\n\t"
            "SBCS    $tmp,$op2.hi,$op1.hi" %}
  ins_encode %{
    __ subs($tmp$$Register, $op2$$Register, $op1$$Register);
    __ sbcs($tmp$$Register->successor(), $op2$$Register->successor(), $op1$$Register->successor());
  %}
  ins_pipe(ialu_cconly_reg_reg);
%}

// TODO: try immLRot2 instead, (0, $con$$constant) becomes
// (hi($con$$constant), lo($con$$constant)) becomes
instruct compL_reg_con_LTGE(flagsRegL_LTGE xcc, iRegL op1, immLlowRot con, iRegL tmp) %{
  match(Set xcc (CmpL op1 con));
  effect( DEF xcc, USE op1, USE con, TEMP tmp );

  size(8);
  format %{ "SUBS    $tmp,$op1.low,$con\t\t! long\n\t"
            "SBCS    $tmp,$op1.hi,0" %}
  ins_encode %{
    __ subs($tmp$$Register, $op1$$Register, $con$$constant);
    __ sbcs($tmp$$Register->successor(), $op1$$Register->successor(), 0);
  %}

  ins_pipe(ialu_cconly_reg_reg);
%}

// TODO: try immLRot2 instead, (0, $con$$constant) becomes
// (hi($con$$constant), lo($con$$constant)) becomes
instruct compL_reg_con_EQNE(flagsRegL_EQNE xcc, iRegL op1, immLlowRot con) %{
  match(Set xcc (CmpL op1 con));
  effect( DEF xcc, USE op1, USE con );

  size(8);
  format %{ "TEQ    $op1.hi,0\t\t! long\n\t"
            "TEQ.eq $op1.lo,$con" %}
  ins_encode %{
    __ teq($op1$$Register->successor(), 0);
    __ teq($op1$$Register, $con$$constant, eq);
  %}

  ins_pipe(ialu_cconly_reg_reg);
%}

// TODO: try immLRot2 instead, (0, $con$$constant) becomes
// (hi($con$$constant), lo($con$$constant)) becomes
instruct compL_reg_con_LEGT(flagsRegL_LEGT xcc, iRegL op1, immLlowRot con, iRegL tmp) %{
  match(Set xcc (CmpL op1 con));
  effect( DEF xcc, USE op1, USE con, TEMP tmp );

  size(8);
  format %{ "RSBS    $tmp,$op1.low,$con\t\t! long\n\t"
            "RSCS    $tmp,$op1.hi,0" %}
  ins_encode %{
    __ rsbs($tmp$$Register, $op1$$Register, $con$$constant);
    __ rscs($tmp$$Register->successor(), $op1$$Register->successor(), 0);
  %}

  ins_pipe(ialu_cconly_reg_reg);
%}

instruct compUL_reg_reg_EQNE(flagsRegUL_EQNE xcc, iRegL op1, iRegL op2) %{
  match(Set xcc (CmpUL op1 op2));
  effect(DEF xcc, USE op1, USE op2);

  size(8);
  format %{ "TEQ    $op1.hi,$op2.hi\t\t! unsigned long\n\t"
            "TEQ.eq $op1.lo,$op2.lo" %}
  ins_encode %{
    __ teq($op1$$Register->successor(), $op2$$Register->successor());
    __ teq($op1$$Register, $op2$$Register, eq);
  %}
  ins_pipe(ialu_cconly_reg_reg);
%}

instruct compUL_reg_reg_LEGT(flagsRegUL_LEGT xcc, iRegL op1, iRegL op2, iRegL tmp) %{
  match(Set xcc (CmpUL op1 op2));
  effect(DEF xcc, USE op1, USE op2, TEMP tmp);

  size(8);
  format %{ "SUBS    $tmp,$op2.low,$op1.low\t\t! unsigned long\n\t"
            "SBCS    $tmp,$op2.hi,$op1.hi" %}
  ins_encode %{
    __ subs($tmp$$Register, $op2$$Register, $op1$$Register);
    __ sbcs($tmp$$Register->successor(), $op2$$Register->successor(), $op1$$Register->successor());
  %}
  ins_pipe(ialu_cconly_reg_reg);
%}

// TODO: try immLRot2 instead, (0, $con$$constant) becomes
// (hi($con$$constant), lo($con$$constant)) becomes
instruct compUL_reg_con_LTGE(flagsRegUL_LTGE xcc, iRegL op1, immLlowRot con, iRegL tmp) %{
  match(Set xcc (CmpUL op1 con));
  effect(DEF xcc, USE op1, USE con, TEMP tmp);

  size(8);
  format %{ "SUBS    $tmp,$op1.low,$con\t\t! unsigned long\n\t"
            "SBCS    $tmp,$op1.hi,0" %}
  ins_encode %{
    __ subs($tmp$$Register, $op1$$Register, $con$$constant);
    __ sbcs($tmp$$Register->successor(), $op1$$Register->successor(), 0);
  %}

  ins_pipe(ialu_cconly_reg_reg);
%}

// TODO: try immLRot2 instead, (0, $con$$constant) becomes
// (hi($con$$constant), lo($con$$constant)) becomes
instruct compUL_reg_con_EQNE(flagsRegUL_EQNE xcc, iRegL op1, immLlowRot con) %{
  match(Set xcc (CmpUL op1 con));
  effect(DEF xcc, USE op1, USE con);

  size(8);
  format %{ "TEQ    $op1.hi,0\t\t! unsigned long\n\t"
            "TEQ.eq $op1.lo,$con" %}
  ins_encode %{
    __ teq($op1$$Register->successor(), 0);
    __ teq($op1$$Register, $con$$constant, eq);
  %}

  ins_pipe(ialu_cconly_reg_reg);
%}

// TODO: try immLRot2 instead, (0, $con$$constant) becomes
// (hi($con$$constant), lo($con$$constant)) becomes
instruct compUL_reg_con_LEGT(flagsRegUL_LEGT xcc, iRegL op1, immLlowRot con, iRegL tmp) %{
  match(Set xcc (CmpUL op1 con));
  effect(DEF xcc, USE op1, USE con, TEMP tmp);

  size(8);
  format %{ "RSBS    $tmp,$op1.low,$con\t\t! unsigned long\n\t"
            "RSCS    $tmp,$op1.hi,0" %}
  ins_encode %{
    __ rsbs($tmp$$Register, $op1$$Register, $con$$constant);
    __ rscs($tmp$$Register->successor(), $op1$$Register->successor(), 0);
  %}

  ins_pipe(ialu_cconly_reg_reg);
%}

/* instruct testL_reg_reg(flagsRegL xcc, iRegL op1, iRegL op2, immL0 zero) %{ */
/*   match(Set xcc (CmpL (AndL op1 op2) zero)); */
/*   ins_encode %{ */
/*     __ stop("testL_reg_reg unimplemented"); */
/*   %} */
/*   ins_pipe(ialu_cconly_reg_reg); */
/* %} */

/* // useful for checking the alignment of a pointer: */
/* instruct testL_reg_con(flagsRegL xcc, iRegL op1, immLlowRot con, immL0 zero) %{ */
/*   match(Set xcc (CmpL (AndL op1 con) zero)); */
/*   ins_encode %{ */
/*     __ stop("testL_reg_con unimplemented"); */
/*   %} */
/*   ins_pipe(ialu_cconly_reg_reg); */
/* %} */

instruct compU_iReg_imm(flagsRegU icc, iRegI op1, aimmU31 op2 ) %{
  match(Set icc (CmpU op1 op2));

  size(4);
  format %{ "cmp_32 $op1,$op2\t! unsigned" %}
  ins_encode %{
    __ cmp_32($op1$$Register, $op2$$constant);
  %}
  ins_pipe(ialu_cconly_reg_imm);
%}

// Compare Pointers
instruct compP_iRegP(flagsRegP pcc, iRegP op1, iRegP op2 ) %{
  match(Set pcc (CmpP op1 op2));

  size(4);
  format %{ "CMP    $op1,$op2\t! ptr" %}
  ins_encode %{
    __ cmp($op1$$Register, $op2$$Register);
  %}
  ins_pipe(ialu_cconly_reg_reg);
%}

instruct compP_iRegP_imm(flagsRegP pcc, iRegP op1, aimmP op2 ) %{
  match(Set pcc (CmpP op1 op2));

  size(4);
  format %{ "CMP    $op1,$op2\t! ptr" %}
  ins_encode %{
    assert($op2$$constant == 0 || _opnds[2]->constant_reloc() == relocInfo::none, "reloc in cmp?");
    __ cmp($op1$$Register, $op2$$constant);
  %}
  ins_pipe(ialu_cconly_reg_imm);
%}

//----------Max and Min--------------------------------------------------------
// Min Instructions
// Conditional move for min
instruct cmovI_reg_lt( iRegI op2, iRegI op1, flagsReg icc ) %{
  effect( USE_DEF op2, USE op1, USE icc );

  size(4);
  format %{ "MOV.lt  $op2,$op1\t! min" %}
  ins_encode %{
    __ mov($op2$$Register, $op1$$Register, lt);
  %}
  ins_pipe(ialu_reg_flags);
%}

// Min Register with Register.
instruct minI_eReg(iRegI op1, iRegI op2) %{
  match(Set op2 (MinI op1 op2));
  ins_cost(DEFAULT_COST*2);
  expand %{
    flagsReg icc;
    compI_iReg(icc,op1,op2);
    cmovI_reg_lt(op2,op1,icc);
  %}
%}

// Max Instructions
// Conditional move for max
instruct cmovI_reg_gt( iRegI op2, iRegI op1, flagsReg icc ) %{
  effect( USE_DEF op2, USE op1, USE icc );
  format %{ "MOV.gt  $op2,$op1\t! max" %}
  ins_encode %{
    __ mov($op2$$Register, $op1$$Register, gt);
  %}
  ins_pipe(ialu_reg_flags);
%}

// Max Register with Register
instruct maxI_eReg(iRegI op1, iRegI op2) %{
  match(Set op2 (MaxI op1 op2));
  ins_cost(DEFAULT_COST*2);
  expand %{
    flagsReg icc;
    compI_iReg(icc,op1,op2);
    cmovI_reg_gt(op2,op1,icc);
  %}
%}


//----------Float Compares----------------------------------------------------
// Compare floating, generate condition code
instruct cmpF_cc(flagsRegF fcc, flagsReg icc, regF src1, regF src2) %{
  match(Set icc (CmpF src1 src2));
  effect(KILL fcc);

  size(8);
  format %{ "FCMPs  $src1,$src2\n\t"
            "FMSTAT" %}
  ins_encode %{
    __ fcmps($src1$$FloatRegister, $src2$$FloatRegister);
    __ fmstat();
  %}
  ins_pipe(faddF_fcc_reg_reg_zero);
%}

instruct cmpF0_cc(flagsRegF fcc, flagsReg icc, regF src1, immF0 src2) %{
  match(Set icc (CmpF src1 src2));
  effect(KILL fcc);

  size(8);
  format %{ "FCMPs  $src1,$src2\n\t"
            "FMSTAT" %}
  ins_encode %{
    __ fcmpzs($src1$$FloatRegister);
    __ fmstat();
  %}
  ins_pipe(faddF_fcc_reg_reg_zero);
%}

instruct cmpD_cc(flagsRegF fcc, flagsReg icc, regD src1, regD src2) %{
  match(Set icc (CmpD src1 src2));
  effect(KILL fcc);

  size(8);
  format %{ "FCMPd  $src1,$src2 \n\t"
            "FMSTAT" %}
  ins_encode %{
    __ fcmpd($src1$$FloatRegister, $src2$$FloatRegister);
    __ fmstat();
  %}
  ins_pipe(faddD_fcc_reg_reg_zero);
%}

instruct cmpD0_cc(flagsRegF fcc, flagsReg icc, regD src1, immD0 src2) %{
  match(Set icc (CmpD src1 src2));
  effect(KILL fcc);

  size(8);
  format %{ "FCMPZd  $src1,$src2 \n\t"
            "FMSTAT" %}
  ins_encode %{
    __ fcmpzd($src1$$FloatRegister);
    __ fmstat();
  %}
  ins_pipe(faddD_fcc_reg_reg_zero);
%}

// Compare floating, generate -1,0,1
instruct cmpF_reg(iRegI dst, regF src1, regF src2, flagsRegF fcc) %{
  match(Set dst (CmpF3 src1 src2));
  effect(KILL fcc);
  ins_cost(DEFAULT_COST*3+BRANCH_COST*3); // FIXME
  size(20);
  // same number of instructions as code using conditional moves but
  // doesn't kill integer condition register
  format %{ "FCMPs  $dst,$src1,$src2 \n\t"
            "VMRS   $dst, FPSCR \n\t"
            "OR     $dst, $dst, 0x08000000 \n\t"
            "EOR    $dst, $dst, $dst << 3 \n\t"
            "MOV    $dst, $dst >> 30" %}
  ins_encode %{
    __ fcmps($src1$$FloatRegister, $src2$$FloatRegister);
    __ floating_cmp($dst$$Register);
  %}
  ins_pipe( floating_cmp );
%}

instruct cmpF0_reg(iRegI dst, regF src1, immF0 src2, flagsRegF fcc) %{
  match(Set dst (CmpF3 src1 src2));
  effect(KILL fcc);
  ins_cost(DEFAULT_COST*3+BRANCH_COST*3); // FIXME
  size(20);
  // same number of instructions as code using conditional moves but
  // doesn't kill integer condition register
  format %{ "FCMPZs $dst,$src1,$src2 \n\t"
            "VMRS   $dst, FPSCR \n\t"
            "OR     $dst, $dst, 0x08000000 \n\t"
            "EOR    $dst, $dst, $dst << 3 \n\t"
            "MOV    $dst, $dst >> 30" %}
  ins_encode %{
    __ fcmpzs($src1$$FloatRegister);
    __ floating_cmp($dst$$Register);
  %}
  ins_pipe( floating_cmp );
%}

instruct cmpD_reg(iRegI dst, regD src1, regD src2, flagsRegF fcc) %{
  match(Set dst (CmpD3 src1 src2));
  effect(KILL fcc);
  ins_cost(DEFAULT_COST*3+BRANCH_COST*3); // FIXME
  size(20);
  // same number of instructions as code using conditional moves but
  // doesn't kill integer condition register
  format %{ "FCMPd  $dst,$src1,$src2 \n\t"
            "VMRS   $dst, FPSCR \n\t"
            "OR     $dst, $dst, 0x08000000 \n\t"
            "EOR    $dst, $dst, $dst << 3 \n\t"
            "MOV    $dst, $dst >> 30" %}
  ins_encode %{
    __ fcmpd($src1$$FloatRegister, $src2$$FloatRegister);
    __ floating_cmp($dst$$Register);
  %}
  ins_pipe( floating_cmp );
%}

instruct cmpD0_reg(iRegI dst, regD src1, immD0 src2, flagsRegF fcc) %{
  match(Set dst (CmpD3 src1 src2));
  effect(KILL fcc);
  ins_cost(DEFAULT_COST*3+BRANCH_COST*3); // FIXME
  size(20);
  // same number of instructions as code using conditional moves but
  // doesn't kill integer condition register
  format %{ "FCMPZd $dst,$src1,$src2 \n\t"
            "VMRS   $dst, FPSCR \n\t"
            "OR     $dst, $dst, 0x08000000 \n\t"
            "EOR    $dst, $dst, $dst << 3 \n\t"
            "MOV    $dst, $dst >> 30" %}
  ins_encode %{
    __ fcmpzd($src1$$FloatRegister);
    __ floating_cmp($dst$$Register);
  %}
  ins_pipe( floating_cmp );
%}

//----------Branches---------------------------------------------------------
// Jump
// (compare 'operand indIndex' and 'instruct addP_reg_reg' above)
// FIXME
instruct jumpXtnd(iRegX switch_val, iRegP tmp) %{
  match(Jump switch_val);
  effect(TEMP tmp);
  ins_cost(350);
  format %{  "ADD    $tmp, $constanttablebase, $switch_val\n\t"
             "LDR    $tmp,[$tmp + $constantoffset]\n\t"
             "BX     $tmp" %}
  size(20);
  ins_encode %{
    Register table_reg;
    Register label_reg = $tmp$$Register;
    if (constant_offset() == 0) {
      table_reg = $constanttablebase;
      __ ldr(label_reg, Address(table_reg, $switch_val$$Register));
    } else {
      table_reg = $tmp$$Register;
      int offset = $constantoffset;
      if (is_memoryP(offset)) {
        __ add(table_reg, $constanttablebase, $switch_val$$Register);
        __ ldr(label_reg, Address(table_reg, offset));
      } else {
        __ mov_slow(table_reg, $constantoffset);
        __ add(table_reg, $constanttablebase, table_reg);
        __ ldr(label_reg, Address(table_reg, $switch_val$$Register));
      }
    }
    __ jump(label_reg); // ldr + b better than ldr to PC for branch predictor?
    //    __ ldr(PC, Address($table$$Register, $switch_val$$Register));
  %}
  ins_pipe(ialu_reg_reg);
%}

// // Direct Branch.
instruct branch(label labl) %{
  match(Goto);
  effect(USE labl);

  size(4);
  ins_cost(BRANCH_COST);
  format %{ "B     $labl" %}
  ins_encode %{
    __ b(*($labl$$label));
  %}
  ins_pipe(br);
%}

// Conditional Direct Branch
instruct branchCon(cmpOp cmp, flagsReg icc, label labl) %{
  match(If cmp icc);
  effect(USE labl);

  size(4);
  ins_cost(BRANCH_COST);
  format %{ "B$cmp   $icc,$labl" %}
  ins_encode %{
    __ b(*($labl$$label), (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(br_cc);
%}

#ifdef ARM
instruct branchCon_EQNELTGE(cmpOp0 cmp, flagsReg_EQNELTGE icc, label labl) %{
  match(If cmp icc);
  effect(USE labl);
  predicate( _kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq || _kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne || _kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge);

  size(4);
  ins_cost(BRANCH_COST);
  format %{ "B$cmp   $icc,$labl" %}
  ins_encode %{
    __ b(*($labl$$label), (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(br_cc);
%}
#endif


instruct branchConU(cmpOpU cmp, flagsRegU icc, label labl) %{
  match(If cmp icc);
  effect(USE labl);

  size(4);
  ins_cost(BRANCH_COST);
  format %{ "B$cmp  $icc,$labl" %}
  ins_encode %{
    __ b(*($labl$$label), (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(br_cc);
%}

instruct branchConP(cmpOpP cmp, flagsRegP pcc, label labl) %{
  match(If cmp pcc);
  effect(USE labl);

  size(4);
  ins_cost(BRANCH_COST);
  format %{ "B$cmp  $pcc,$labl" %}
  ins_encode %{
    __ b(*($labl$$label), (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(br_cc);
%}

instruct branchConL_LTGE(cmpOpL cmp, flagsRegL_LTGE xcc, label labl) %{
  match(If cmp xcc);
  effect(USE labl);
  predicate( _kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge );

  size(4);
  ins_cost(BRANCH_COST);
  format %{ "B$cmp  $xcc,$labl" %}
  ins_encode %{
    __ b(*($labl$$label), (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(br_cc);
%}

instruct branchConL_EQNE(cmpOpL cmp, flagsRegL_EQNE xcc, label labl) %{
  match(If cmp xcc);
  effect(USE labl);
  predicate( _kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq || _kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne );

  size(4);
  ins_cost(BRANCH_COST);
  format %{ "B$cmp  $xcc,$labl" %}
  ins_encode %{
    __ b(*($labl$$label), (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(br_cc);
%}

instruct branchConL_LEGT(cmpOpL_commute cmp, flagsRegL_LEGT xcc, label labl) %{
  match(If cmp xcc);
  effect(USE labl);
  predicate( _kids[0]->_leaf->as_Bool()->_test._test == BoolTest::gt || _kids[0]->_leaf->as_Bool()->_test._test == BoolTest::le );

  size(4);
  ins_cost(BRANCH_COST);
  format %{ "B$cmp  $xcc,$labl" %}
  ins_encode %{
    __ b(*($labl$$label), (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(br_cc);
%}

instruct branchConUL_LTGE(cmpOpUL cmp, flagsRegUL_LTGE xcc, label labl) %{
  match(If cmp xcc);
  effect(USE labl);
  predicate(_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge);

  size(4);
  ins_cost(BRANCH_COST);
  format %{ "B$cmp  $xcc,$labl" %}
  ins_encode %{
    __ b(*($labl$$label), (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(br_cc);
%}

instruct branchConUL_EQNE(cmpOpUL cmp, flagsRegUL_EQNE xcc, label labl) %{
  match(If cmp xcc);
  effect(USE labl);
  predicate(_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq || _kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne);

  size(4);
  ins_cost(BRANCH_COST);
  format %{ "B$cmp  $xcc,$labl" %}
  ins_encode %{
    __ b(*($labl$$label), (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(br_cc);
%}

instruct branchConUL_LEGT(cmpOpUL_commute cmp, flagsRegUL_LEGT xcc, label labl) %{
  match(If cmp xcc);
  effect(USE labl);
  predicate(_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::gt || _kids[0]->_leaf->as_Bool()->_test._test == BoolTest::le);

  size(4);
  ins_cost(BRANCH_COST);
  format %{ "B$cmp  $xcc,$labl" %}
  ins_encode %{
    __ b(*($labl$$label), (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(br_cc);
%}

instruct branchLoopEnd(cmpOp cmp, flagsReg icc, label labl) %{
  match(CountedLoopEnd cmp icc);
  effect(USE labl);

  size(4);
  ins_cost(BRANCH_COST);
  format %{ "B$cmp   $icc,$labl\t! Loop end" %}
  ins_encode %{
    __ b(*($labl$$label), (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(br_cc);
%}

// instruct branchLoopEndU(cmpOpU cmp, flagsRegU icc, label labl) %{
//   match(CountedLoopEnd cmp icc);
//   ins_pipe(br_cc);
// %}

// ============================================================================
// Long Compare
//
// Currently we hold longs in 2 registers.  Comparing such values efficiently
// is tricky.  The flavor of compare used depends on whether we are testing
// for LT, LE, or EQ.  For a simple LT test we can check just the sign bit.
// The GE test is the negated LT test.  The LE test can be had by commuting
// the operands (yielding a GE test) and then negating; negate again for the
// GT test.  The EQ test is done by ORcc'ing the high and low halves, and the
// NE test is negated from that.

// Due to a shortcoming in the ADLC, it mixes up expressions like:
// (foo (CmpI (CmpL X Y) 0)) and (bar (CmpI (CmpL X 0L) 0)).  Note the
// difference between 'Y' and '0L'.  The tree-matches for the CmpI sections
// are collapsed internally in the ADLC's dfa-gen code.  The match for
// (CmpI (CmpL X Y) 0) is silently replaced with (CmpI (CmpL X 0L) 0) and the
// foo match ends up with the wrong leaf.  One fix is to not match both
// reg-reg and reg-zero forms of long-compare.  This is unfortunate because
// both forms beat the trinary form of long-compare and both are very useful
// on Intel which has so few registers.

// instruct branchCon_long(cmpOp cmp, flagsRegL xcc, label labl) %{
//   match(If cmp xcc);
//   ins_pipe(br_cc);
// %}

// Manifest a CmpL3 result in an integer register.  Very painful.
// This is the test to avoid.
instruct cmpL3_reg_reg(iRegI dst, iRegL src1, iRegL src2, flagsReg ccr ) %{
  match(Set dst (CmpL3 src1 src2) );
  effect( KILL ccr );
  ins_cost(6*DEFAULT_COST); // FIXME
  size(32);
  format %{
      "CMP    $src1.hi, $src2.hi\t\t! long\n"
    "\tMOV.gt $dst, 1\n"
    "\tmvn.lt $dst, 0\n"
    "\tB.ne   done\n"
    "\tSUBS   $dst, $src1.lo, $src2.lo\n"
    "\tMOV.hi $dst, 1\n"
    "\tmvn.lo $dst, 0\n"
    "done:"     %}
  ins_encode %{
    Label done;
    __ cmp($src1$$Register->successor(), $src2$$Register->successor());
    __ mov($dst$$Register, 1, gt);
    __ mvn($dst$$Register, 0, lt);
    __ b(done, ne);
    __ subs($dst$$Register, $src1$$Register, $src2$$Register);
    __ mov($dst$$Register, 1, hi);
    __ mvn($dst$$Register, 0, lo);
    __ bind(done);
  %}
  ins_pipe(cmpL_reg);
%}

// Conditional move
instruct cmovLL_reg_LTGE(cmpOpL cmp, flagsRegL_LTGE xcc, iRegL dst, iRegL src) %{
  match(Set dst (CMoveL (Binary cmp xcc) (Binary dst src)));
  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge);

  ins_cost(150);
  size(8);
  format %{ "MOV$cmp  $dst.lo,$src.lo\t! long\n\t"
            "MOV$cmp  $dst,$src.hi" %}
  ins_encode %{
    __ mov($dst$$Register, $src$$Register, (AsmCondition)($cmp$$cmpcode));
    __ mov($dst$$Register->successor(), $src$$Register->successor(), (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(ialu_reg);
%}

instruct cmovLL_reg_LTGE_U(cmpOpUL cmp, flagsRegUL_LTGE xcc, iRegL dst, iRegL src) %{
  match(Set dst (CMoveL (Binary cmp xcc) (Binary dst src)));
  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge);

  ins_cost(150);
  size(8);
  format %{ "MOV$cmp  $dst.lo,$src.lo\t! long\n\t"
            "MOV$cmp  $dst,$src.hi" %}
  ins_encode %{
    __ mov($dst$$Register, $src$$Register, (AsmCondition)($cmp$$cmpcode));
    __ mov($dst$$Register->successor(), $src$$Register->successor(), (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(ialu_reg);
%}

instruct cmovLL_reg_EQNE(cmpOpL cmp, flagsRegL_EQNE xcc, iRegL dst, iRegL src) %{
  match(Set dst (CMoveL (Binary cmp xcc) (Binary dst src)));
  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne);

  ins_cost(150);
  size(8);
  format %{ "MOV$cmp  $dst.lo,$src.lo\t! long\n\t"
            "MOV$cmp  $dst,$src.hi" %}
  ins_encode %{
    __ mov($dst$$Register, $src$$Register, (AsmCondition)($cmp$$cmpcode));
    __ mov($dst$$Register->successor(), $src$$Register->successor(), (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(ialu_reg);
%}

instruct cmovLL_reg_LEGT(cmpOpL_commute cmp, flagsRegL_LEGT xcc, iRegL dst, iRegL src) %{
  match(Set dst (CMoveL (Binary cmp xcc) (Binary dst src)));
  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::le || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::gt);

  ins_cost(150);
  size(8);
  format %{ "MOV$cmp  $dst.lo,$src.lo\t! long\n\t"
            "MOV$cmp  $dst,$src.hi" %}
  ins_encode %{
    __ mov($dst$$Register, $src$$Register, (AsmCondition)($cmp$$cmpcode));
    __ mov($dst$$Register->successor(), $src$$Register->successor(), (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(ialu_reg);
%}

instruct cmovLL_reg_LEGT_U(cmpOpUL_commute cmp, flagsRegUL_LEGT xcc, iRegL dst, iRegL src) %{
  match(Set dst (CMoveL (Binary cmp xcc) (Binary dst src)));
  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::le || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::gt);

  ins_cost(150);
  size(8);
  format %{ "MOV$cmp  $dst.lo,$src.lo\t! long\n\t"
            "MOV$cmp  $dst,$src.hi" %}
  ins_encode %{
    __ mov($dst$$Register, $src$$Register, (AsmCondition)($cmp$$cmpcode));
    __ mov($dst$$Register->successor(), $src$$Register->successor(), (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(ialu_reg);
%}

instruct cmovLL_imm_LTGE(cmpOpL cmp, flagsRegL_LTGE xcc, iRegL dst, immL0 src) %{
  match(Set dst (CMoveL (Binary cmp xcc) (Binary dst src)));
  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge);
  ins_cost(140);
  size(8);
  format %{ "MOV$cmp  $dst.lo,0\t! long\n\t"
            "MOV$cmp  $dst,0" %}
  ins_encode %{
    __ mov($dst$$Register, 0, (AsmCondition)($cmp$$cmpcode));
    __ mov($dst$$Register->successor(), 0, (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(ialu_imm);
%}

instruct cmovLL_imm_LTGE_U(cmpOpUL cmp, flagsRegUL_LTGE xcc, iRegL dst, immL0 src) %{
  match(Set dst (CMoveL (Binary cmp xcc) (Binary dst src)));
  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge);
  ins_cost(140);
  size(8);
  format %{ "MOV$cmp  $dst.lo,0\t! long\n\t"
            "MOV$cmp  $dst,0" %}
  ins_encode %{
    __ mov($dst$$Register, 0, (AsmCondition)($cmp$$cmpcode));
    __ mov($dst$$Register->successor(), 0, (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(ialu_imm);
%}

instruct cmovLL_imm_EQNE(cmpOpL cmp, flagsRegL_EQNE xcc, iRegL dst, immL0 src) %{
  match(Set dst (CMoveL (Binary cmp xcc) (Binary dst src)));
  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne);
  ins_cost(140);
  size(8);
  format %{ "MOV$cmp  $dst.lo,0\t! long\n\t"
            "MOV$cmp  $dst,0" %}
  ins_encode %{
    __ mov($dst$$Register, 0, (AsmCondition)($cmp$$cmpcode));
    __ mov($dst$$Register->successor(), 0, (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(ialu_imm);
%}

instruct cmovLL_imm_LEGT(cmpOpL_commute cmp, flagsRegL_LEGT xcc, iRegL dst, immL0 src) %{
  match(Set dst (CMoveL (Binary cmp xcc) (Binary dst src)));
  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::le || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::gt);
  ins_cost(140);
  size(8);
  format %{ "MOV$cmp  $dst.lo,0\t! long\n\t"
            "MOV$cmp  $dst,0" %}
  ins_encode %{
    __ mov($dst$$Register, 0, (AsmCondition)($cmp$$cmpcode));
    __ mov($dst$$Register->successor(), 0, (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(ialu_imm);
%}

instruct cmovIL_reg_LTGE(cmpOpL cmp, flagsRegL_LTGE xcc, iRegI dst, iRegI src) %{
  match(Set dst (CMoveI (Binary cmp xcc) (Binary dst src)));
  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge);

  ins_cost(150);
  size(4);
  format %{ "MOV$cmp  $dst,$src" %}
  ins_encode %{
    __ mov($dst$$Register, $src$$Register, (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(ialu_reg);
%}

instruct cmovIL_reg_LTGE_U(cmpOpUL cmp, flagsRegUL_LTGE xcc, iRegI dst, iRegI src) %{
  match(Set dst (CMoveI (Binary cmp xcc) (Binary dst src)));
  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge);

  ins_cost(150);
  size(4);
  format %{ "MOV$cmp  $dst,$src" %}
  ins_encode %{
    __ mov($dst$$Register, $src$$Register, (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(ialu_reg);
%}

instruct cmovIL_reg_EQNE(cmpOpL cmp, flagsRegL_EQNE xcc, iRegI dst, iRegI src) %{
  match(Set dst (CMoveI (Binary cmp xcc) (Binary dst src)));
  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne);

  ins_cost(150);
  size(4);
  format %{ "MOV$cmp  $dst,$src" %}
  ins_encode %{
    __ mov($dst$$Register, $src$$Register, (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(ialu_reg);
%}

instruct cmovIL_reg_EQNE_U(cmpOpUL cmp, flagsRegUL_EQNE xcc, iRegI dst, iRegI src) %{
  match(Set dst (CMoveI (Binary cmp xcc) (Binary dst src)));
  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne);

  ins_cost(150);
  size(4);
  format %{ "MOV$cmp  $dst,$src" %}
  ins_encode %{
   __ mov($dst$$Register, $src$$Register, (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(ialu_reg);
%}

instruct cmovIL_reg_LEGT(cmpOpL_commute cmp, flagsRegL_LEGT xcc, iRegI dst, iRegI src) %{
  match(Set dst (CMoveI (Binary cmp xcc) (Binary dst src)));
  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::le || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::gt);

  ins_cost(150);
  size(4);
  format %{ "MOV$cmp  $dst,$src" %}
  ins_encode %{
    __ mov($dst$$Register, $src$$Register, (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(ialu_reg);
%}

instruct cmovIL_reg_LEGT_U(cmpOpUL_commute cmp, flagsRegUL_LEGT xcc, iRegI dst, iRegI src) %{
  match(Set dst (CMoveI (Binary cmp xcc) (Binary dst src)));
  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::le || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::gt);

  ins_cost(150);
  size(4);
  format %{ "MOV$cmp  $dst,$src" %}
  ins_encode %{
    __ mov($dst$$Register, $src$$Register, (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(ialu_reg);
%}

instruct cmovIL_imm16_LTGE(cmpOpL cmp, flagsRegL_LTGE xcc, iRegI dst, immI16 src) %{
  match(Set dst (CMoveI (Binary cmp xcc) (Binary dst src)));
  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge);

  ins_cost(140);
  size(4);
  format %{ "MOVW$cmp  $dst,$src" %}
  ins_encode %{
    __ movw($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(ialu_imm);
%}

instruct cmovIL_imm16_LTGE_U(cmpOpUL cmp, flagsRegUL_LTGE xcc, iRegI dst, immI16 src) %{
  match(Set dst (CMoveI (Binary cmp xcc) (Binary dst src)));
  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge);

  ins_cost(140);
  size(4);
  format %{ "MOVW$cmp  $dst,$src" %}
  ins_encode %{
    __ movw($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(ialu_imm);
%}

instruct cmovIL_imm16_EQNE(cmpOpL cmp, flagsRegL_EQNE xcc, iRegI dst, immI16 src) %{
  match(Set dst (CMoveI (Binary cmp xcc) (Binary dst src)));
  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne);

  ins_cost(140);
  size(4);
  format %{ "MOVW$cmp  $dst,$src" %}
  ins_encode %{
    __ movw($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(ialu_imm);
%}

instruct cmovIL_imm16_EQNE_U(cmpOpUL cmp, flagsRegUL_EQNE xcc, iRegI dst, immI16 src) %{
  match(Set dst (CMoveI (Binary cmp xcc) (Binary dst src)));
  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne);

  ins_cost(140);
  size(4);
  format %{ "MOVW$cmp  $dst,$src" %}
  ins_encode %{
    __ movw($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(ialu_imm);
%}

instruct cmovIL_imm16_LEGT(cmpOpL_commute cmp, flagsRegL_LEGT xcc, iRegI dst, immI16 src) %{
  match(Set dst (CMoveI (Binary cmp xcc) (Binary dst src)));
  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::le || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::gt);

  ins_cost(140);
  size(4);
  format %{ "MOVW$cmp  $dst,$src" %}
  ins_encode %{
    __ movw($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(ialu_imm);
%}

instruct cmovIL_imm16_LEGT_U(cmpOpUL_commute cmp, flagsRegUL_LEGT xcc, iRegI dst, immI16 src) %{
  match(Set dst (CMoveI (Binary cmp xcc) (Binary dst src)));
  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::le || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::gt);

  ins_cost(140);
  size(4);
  format %{ "MOVW$cmp  $dst,$src" %}
  ins_encode %{
    __ movw($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(ialu_imm);
%}

instruct cmovIL_immMov_LTGE(cmpOpL cmp, flagsRegL_LTGE xcc, iRegI dst, immIMov src) %{
  match(Set dst (CMoveI (Binary cmp xcc) (Binary dst src)));
  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge);

  ins_cost(140);
  size(4);
  format %{ "MOV$cmp  $dst,$src" %}
  ins_encode %{
    __ mov($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(ialu_imm);
%}

instruct cmovIL_immMov_LTGE_U(cmpOpUL cmp, flagsRegUL_LTGE xcc, iRegI dst, immIMov src) %{
  match(Set dst (CMoveI (Binary cmp xcc) (Binary dst src)));
  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge);

  ins_cost(140);
  size(4);
  format %{ "MOV$cmp  $dst,$src" %}
  ins_encode %{
    __ mov($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(ialu_imm);
%}

instruct cmovIL_immMov_EQNE(cmpOpL cmp, flagsRegL_EQNE xcc, iRegI dst, immIMov src) %{
  match(Set dst (CMoveI (Binary cmp xcc) (Binary dst src)));
  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne);

  ins_cost(140);
  size(4);
  format %{ "MOV$cmp  $dst,$src" %}
  ins_encode %{
    __ mov($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(ialu_imm);
%}

instruct cmovIL_immMov_EQNE_U(cmpOpUL cmp, flagsRegUL_EQNE xcc, iRegI dst, immIMov src) %{
  match(Set dst (CMoveI (Binary cmp xcc) (Binary dst src)));
  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne);

  ins_cost(140);
  size(4);
  format %{ "MOV$cmp  $dst,$src" %}
  ins_encode %{
    __ mov($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(ialu_imm);
%}

instruct cmovIL_immMov_LEGT(cmpOpL_commute cmp, flagsRegL_LEGT xcc, iRegI dst, immIMov src) %{
  match(Set dst (CMoveI (Binary cmp xcc) (Binary dst src)));
  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::le || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::gt);

  ins_cost(140);
  size(4);
  format %{ "MOV$cmp  $dst,$src" %}
  ins_encode %{
    __ mov($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(ialu_imm);
%}

instruct cmovIL_immMov_LEGT_U(cmpOpUL_commute cmp, flagsRegUL_LEGT xcc, iRegI dst, immIMov src) %{
  match(Set dst (CMoveI (Binary cmp xcc) (Binary dst src)));
  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::le || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::gt);

  ins_cost(140);
  size(4);
  format %{ "MOV$cmp  $dst,$src" %}
  ins_encode %{
    __ mov($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(ialu_imm);
%}

instruct cmovPL_reg_LTGE(cmpOpL cmp, flagsRegL_LTGE xcc, iRegP dst, iRegP src) %{
  match(Set dst (CMoveP (Binary cmp xcc) (Binary dst src)));
  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge);

  ins_cost(150);
  size(4);
  format %{ "MOV$cmp  $dst,$src" %}
  ins_encode %{
    __ mov($dst$$Register, $src$$Register, (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(ialu_reg);
%}

instruct cmovPL_reg_LTGE_U(cmpOpUL cmp, flagsRegUL_LTGE xcc, iRegP dst, iRegP src) %{
  match(Set dst (CMoveP (Binary cmp xcc) (Binary dst src)));
  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge);

  ins_cost(150);
  size(4);
  format %{ "MOV$cmp  $dst,$src" %}
  ins_encode %{
    __ mov($dst$$Register, $src$$Register, (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(ialu_reg);
%}

instruct cmovPL_reg_EQNE(cmpOpL cmp, flagsRegL_EQNE xcc, iRegP dst, iRegP src) %{
  match(Set dst (CMoveP (Binary cmp xcc) (Binary dst src)));
  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne);

  ins_cost(150);
  size(4);
  format %{ "MOV$cmp  $dst,$src" %}
  ins_encode %{
    __ mov($dst$$Register, $src$$Register, (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(ialu_reg);
%}

instruct cmovPL_reg_EQNE_U(cmpOpUL cmp, flagsRegUL_EQNE xcc, iRegP dst, iRegP src) %{
  match(Set dst (CMoveP (Binary cmp xcc) (Binary dst src)));
  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne);

  ins_cost(150);
  size(4);
  format %{ "MOV$cmp  $dst,$src" %}
  ins_encode %{
    __ mov($dst$$Register, $src$$Register, (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(ialu_reg);
%}

instruct cmovPL_reg_LEGT(cmpOpL_commute cmp, flagsRegL_LEGT xcc, iRegP dst, iRegP src) %{
  match(Set dst (CMoveP (Binary cmp xcc) (Binary dst src)));
  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::le || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::gt);

  ins_cost(150);
  size(4);
  format %{ "MOV$cmp  $dst,$src" %}
  ins_encode %{
    __ mov($dst$$Register, $src$$Register, (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(ialu_reg);
%}

instruct cmovPL_reg_LEGT_U(cmpOpUL_commute cmp, flagsRegUL_LEGT xcc, iRegP dst, iRegP src) %{
  match(Set dst (CMoveP (Binary cmp xcc) (Binary dst src)));
  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::le || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::gt);

  ins_cost(150);
  size(4);
  format %{ "MOV$cmp  $dst,$src" %}
  ins_encode %{
    __ mov($dst$$Register, $src$$Register, (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(ialu_reg);
%}

instruct cmovPL_imm_LTGE(cmpOpL cmp, flagsRegL_LTGE xcc, iRegP dst, immP0 src) %{
  match(Set dst (CMoveP (Binary cmp xcc) (Binary dst src)));
  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge);

  ins_cost(140);
  size(4);
  format %{ "MOVW$cmp  $dst,$src" %}
  ins_encode %{
    __ movw($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(ialu_imm);
%}

instruct cmovPL_imm_LTGE_U(cmpOpUL cmp, flagsRegUL_LTGE xcc, iRegP dst, immP0 src) %{
  match(Set dst (CMoveP (Binary cmp xcc) (Binary dst src)));
  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge);

  ins_cost(140);
  size(4);
  format %{ "MOVW$cmp  $dst,$src" %}
  ins_encode %{
    __ movw($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(ialu_imm);
%}

instruct cmovPL_imm_EQNE(cmpOpL cmp, flagsRegL_EQNE xcc, iRegP dst, immP0 src) %{
  match(Set dst (CMoveP (Binary cmp xcc) (Binary dst src)));
  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne);

  ins_cost(140);
  size(4);
  format %{ "MOVW$cmp  $dst,$src" %}
  ins_encode %{
    __ movw($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(ialu_imm);
%}

instruct cmovPL_imm_EQNE_U(cmpOpUL cmp, flagsRegUL_EQNE xcc, iRegP dst, immP0 src) %{
  match(Set dst (CMoveP (Binary cmp xcc) (Binary dst src)));
  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne);

  ins_cost(140);
  size(4);
  format %{ "MOVW$cmp  $dst,$src" %}
  ins_encode %{
    __ movw($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(ialu_imm);
%}

instruct cmovPL_imm_LEGT(cmpOpL_commute cmp, flagsRegL_LEGT xcc, iRegP dst, immP0 src) %{
  match(Set dst (CMoveP (Binary cmp xcc) (Binary dst src)));
  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::le || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::gt);

  ins_cost(140);
  size(4);
  format %{ "MOVW$cmp  $dst,$src" %}
  ins_encode %{
    __ movw($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(ialu_imm);
%}

instruct cmovPL_imm_LEGT_U(cmpOpUL_commute cmp, flagsRegUL_LEGT xcc, iRegP dst, immP0 src) %{
  match(Set dst (CMoveP (Binary cmp xcc) (Binary dst src)));
  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::le || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::gt);

  ins_cost(140);
  size(4);
  format %{ "MOVW$cmp  $dst,$src" %}
  ins_encode %{
    __ movw($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(ialu_imm);
%}

instruct cmovFL_reg_LTGE(cmpOpL cmp, flagsRegL_LTGE xcc, regF dst, regF src) %{
  match(Set dst (CMoveF (Binary cmp xcc) (Binary dst src)));
  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge);
  ins_cost(150);
  size(4);
  format %{ "FCPYS$cmp $dst,$src" %}
  ins_encode %{
    __ fcpys($dst$$FloatRegister, $src$$FloatRegister, (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(int_conditional_float_move);
%}

instruct cmovFL_reg_EQNE(cmpOpL cmp, flagsRegL_EQNE xcc, regF dst, regF src) %{
  match(Set dst (CMoveF (Binary cmp xcc) (Binary dst src)));
  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne);
  ins_cost(150);
  size(4);
  format %{ "FCPYS$cmp $dst,$src" %}
  ins_encode %{
    __ fcpys($dst$$FloatRegister, $src$$FloatRegister, (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(int_conditional_float_move);
%}

instruct cmovFL_reg_LEGT(cmpOpL_commute cmp, flagsRegL_LEGT xcc, regF dst, regF src) %{
  match(Set dst (CMoveF (Binary cmp xcc) (Binary dst src)));
  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::le || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::gt);
  ins_cost(150);
  size(4);
  format %{ "FCPYS$cmp $dst,$src" %}
  ins_encode %{
    __ fcpys($dst$$FloatRegister, $src$$FloatRegister, (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(int_conditional_float_move);
%}

instruct cmovDL_reg_LTGE(cmpOpL cmp, flagsRegL_LTGE xcc, regD dst, regD src) %{
  match(Set dst (CMoveD (Binary cmp xcc) (Binary dst src)));
  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::lt || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ge);

  ins_cost(150);
  size(4);
  format %{ "FCPYD$cmp $dst,$src" %}
  ins_encode %{
    __ fcpyd($dst$$FloatRegister, $src$$FloatRegister, (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(int_conditional_float_move);
%}

instruct cmovDL_reg_EQNE(cmpOpL cmp, flagsRegL_EQNE xcc, regD dst, regD src) %{
  match(Set dst (CMoveD (Binary cmp xcc) (Binary dst src)));
  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::eq || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne);

  ins_cost(150);
  size(4);
  format %{ "FCPYD$cmp $dst,$src" %}
  ins_encode %{
    __ fcpyd($dst$$FloatRegister, $src$$FloatRegister, (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(int_conditional_float_move);
%}

instruct cmovDL_reg_LEGT(cmpOpL_commute cmp, flagsRegL_LEGT xcc, regD dst, regD src) %{
  match(Set dst (CMoveD (Binary cmp xcc) (Binary dst src)));
  predicate(_kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::le || _kids[0]->_kids[0]->_leaf->as_Bool()->_test._test == BoolTest::gt);

  ins_cost(150);
  size(4);
  format %{ "FCPYD$cmp $dst,$src" %}
  ins_encode %{
    __ fcpyd($dst$$FloatRegister, $src$$FloatRegister, (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(int_conditional_float_move);
%}

// ============================================================================
// Safepoint Instruction
// rather than KILL R12, it would be better to use any reg as
// TEMP. Can't do that at this point because it crashes the compiler
instruct safePoint_poll(iRegP poll, R12RegI tmp, flagsReg icc) %{
  match(SafePoint poll);
  effect(USE poll, KILL tmp, KILL icc);

  size(4);
  format %{ "LDR   $tmp,[$poll]\t! Safepoint: poll for GC" %}
  ins_encode %{
    __ relocate(relocInfo::poll_type);
    __ ldr($tmp$$Register, Address($poll$$Register));
  %}
  ins_pipe(loadPollP);
%}


// ============================================================================
// Call Instructions
// Call Java Static Instruction
instruct CallStaticJavaDirect( method meth ) %{
  match(CallStaticJava);
  predicate(! ((CallStaticJavaNode*)n)->is_method_handle_invoke());
  effect(USE meth);

  ins_cost(CALL_COST);
  format %{ "CALL,static ==> " %}
  ins_encode( Java_Static_Call( meth ), call_epilog );
  ins_pipe(simple_call);
%}

// Call Java Static Instruction (method handle version)
instruct CallStaticJavaHandle( method meth ) %{
  match(CallStaticJava);
  predicate(((CallStaticJavaNode*)n)->is_method_handle_invoke());
  effect(USE meth);
  // FP is saved by all callees (for interpreter stack correction).
  // We use it here for a similar purpose, in {preserve,restore}_FP.

  ins_cost(CALL_COST);
  format %{ "CALL,static/MethodHandle ==> " %}
  ins_encode( preserve_SP, Java_Static_Call( meth ), restore_SP, call_epilog );
  ins_pipe(simple_call);
%}

// Call Java Dynamic Instruction
instruct CallDynamicJavaDirect( method meth ) %{
  match(CallDynamicJava);
  effect(USE meth);

  ins_cost(CALL_COST);
  format %{ "MOV_OOP    (empty),R_R8\n\t"
            "CALL,dynamic  ; NOP ==> " %}
  ins_encode( Java_Dynamic_Call( meth ), call_epilog );
  ins_pipe(call);
%}

// Call Runtime Instruction
instruct CallRuntimeDirect(method meth) %{
  match(CallRuntime);
  effect(USE meth);
  ins_cost(CALL_COST);
  format %{ "CALL,runtime" %}
  ins_encode( Java_To_Runtime( meth ),
              call_epilog );
  ins_pipe(simple_call);
%}

// Call runtime without safepoint - same as CallRuntime
instruct CallLeafDirect(method meth) %{
  match(CallLeaf);
  effect(USE meth);
  ins_cost(CALL_COST);
  format %{ "CALL,runtime leaf" %}
  // TODO: need save_last_PC here?
  ins_encode( Java_To_Runtime( meth ),
              call_epilog );
  ins_pipe(simple_call);
%}

// Call runtime without safepoint - same as CallLeaf
instruct CallLeafNoFPDirect(method meth) %{
  match(CallLeafNoFP);
  effect(USE meth);
  ins_cost(CALL_COST);
  format %{ "CALL,runtime leaf nofp" %}
  // TODO: need save_last_PC here?
  ins_encode( Java_To_Runtime( meth ),
              call_epilog );
  ins_pipe(simple_call);
%}

// Tail Call; Jump from runtime stub to Java code.
// Also known as an 'interprocedural jump'.
// Target of jump will eventually return to caller.
// TailJump below removes the return address.
instruct TailCalljmpInd(IPRegP jump_target, inline_cache_regP method_ptr) %{
  match(TailCall jump_target method_ptr);

  ins_cost(CALL_COST);
  format %{ "MOV    Rexception_pc, LR\n\t"
            "jump   $jump_target  \t! $method_ptr holds method" %}
  ins_encode %{
    __ mov(Rexception_pc, LR);   // this is used only to call
                                 // StubRoutines::forward_exception_entry()
                                 // which expects PC of exception in
                                 // R5. FIXME?
    __ jump($jump_target$$Register);
  %}
  ins_pipe(tail_call);
%}


// Return Instruction
instruct Ret() %{
  match(Return);

  format %{ "ret LR" %}

  ins_encode %{
    __ ret(LR);
  %}

  ins_pipe(br);
%}


// Tail Jump; remove the return address; jump to target.
// TailCall above leaves the return address around.
// TailJump is used in only one place, the rethrow_Java stub (fancy_jump=2).
// ex_oop (Exception Oop) is needed in %o0 at the jump. As there would be a
// "restore" before this instruction (in Epilogue), we need to materialize it
// in %i0.
instruct tailjmpInd(IPRegP jump_target, RExceptionRegP ex_oop) %{
  match( TailJump jump_target ex_oop );
  ins_cost(CALL_COST);
  format %{ "MOV    Rexception_pc, LR\n\t"
            "jump   $jump_target \t! $ex_oop holds exc. oop" %}
  ins_encode %{
    __ mov(Rexception_pc, LR);
    __ jump($jump_target$$Register);
  %}
  ins_pipe(tail_call);
%}

// Create exception oop: created by stack-crawling runtime code.
// Created exception is now available to this handler, and is setup
// just prior to jumping to this handler.  No code emitted.
instruct CreateException( RExceptionRegP ex_oop )
%{
  match(Set ex_oop (CreateEx));
  ins_cost(0);

  size(0);
  // use the following format syntax
  format %{ "! exception oop is in Rexception_obj; no code emitted" %}
  ins_encode();
  ins_pipe(empty);
%}


// Rethrow exception:
// The exception oop will come in the first argument position.
// Then JUMP (not call) to the rethrow stub code.
instruct RethrowException()
%{
  match(Rethrow);
  ins_cost(CALL_COST);

  // use the following format syntax
  format %{ "b    rethrow_stub" %}
  ins_encode %{
    Register scratch = R1_tmp;
    assert_different_registers(scratch, c_rarg0, LR);
    __ jump(OptoRuntime::rethrow_stub(), relocInfo::runtime_call_type, scratch);
  %}
  ins_pipe(tail_call);
%}


// Die now
instruct ShouldNotReachHere( )
%{
  match(Halt);
  ins_cost(CALL_COST);

  // Use the following format syntax
  format %{ "ShouldNotReachHere" %}
  ins_encode %{
    if (is_reachable()) {
      __ stop(_halt_reason);
    }
  %}
  ins_pipe(tail_call);
%}

// ============================================================================
// The 2nd slow-half of a subtype check.  Scan the subklass's 2ndary superklass
// array for an instance of the superklass.  Set a hidden internal cache on a
// hit (cache is checked with exposed code in gen_subtype_check()).  Return
// not zero for a miss or zero for a hit.  The encoding ALSO sets flags.
instruct partialSubtypeCheck( R0RegP index, R1RegP sub, R2RegP super, flagsRegP pcc, LRRegP lr ) %{
  match(Set index (PartialSubtypeCheck sub super));
  effect( KILL pcc, KILL lr );
  ins_cost(DEFAULT_COST*10);
  format %{ "CALL   PartialSubtypeCheck" %}
  ins_encode %{
    __ call(StubRoutines::Arm::partial_subtype_check(), relocInfo::runtime_call_type);
  %}
  ins_pipe(partial_subtype_check_pipe);
%}

/* instruct partialSubtypeCheck_vs_zero( flagsRegP pcc, o1RegP sub, o2RegP super, immP0 zero, o0RegP idx, o7RegP o7 ) %{ */
/*   match(Set pcc (CmpP (PartialSubtypeCheck sub super) zero)); */
/*   ins_pipe(partial_subtype_check_pipe); */
/* %} */


// ============================================================================
// inlined locking and unlocking

instruct cmpFastLock(flagsRegP pcc, iRegP object, iRegP box, iRegP scratch2, iRegP scratch )
%{
  match(Set pcc (FastLock object box));

  effect(TEMP scratch, TEMP scratch2);
  ins_cost(DEFAULT_COST*3);

  format %{ "FASTLOCK  $object, $box; KILL $scratch, $scratch2" %}
  ins_encode %{
    __ fast_lock($object$$Register, $box$$Register, $scratch$$Register, $scratch2$$Register);
  %}
  ins_pipe(long_memory_op);
%}

instruct cmpFastUnlock(flagsRegP pcc, iRegP object, iRegP box, iRegP scratch2, iRegP scratch ) %{
  match(Set pcc (FastUnlock object box));
  effect(TEMP scratch, TEMP scratch2);
  ins_cost(100);

  format %{ "FASTUNLOCK  $object, $box; KILL $scratch, $scratch2" %}
  ins_encode %{
    __ fast_unlock($object$$Register, $box$$Register, $scratch$$Register, $scratch2$$Register);
  %}
  ins_pipe(long_memory_op);
%}

// Count and Base registers are fixed because the allocator cannot
// kill unknown registers.  The encodings are generic.
instruct clear_array(iRegX cnt, iRegP base, iRegI temp, iRegX zero, Universe dummy, flagsReg cpsr) %{
  match(Set dummy (ClearArray cnt base));
  effect(TEMP temp, TEMP zero, KILL cpsr);
  ins_cost(300);
  format %{ "MOV    $zero,0\n"
      "        MOV    $temp,$cnt\n"
      "loop:   SUBS   $temp,$temp,4\t! Count down a dword of bytes\n"
      "        STR.ge $zero,[$base+$temp]\t! delay slot"
      "        B.gt   loop\t\t! Clearing loop\n" %}
  ins_encode %{
    __ mov($zero$$Register, 0);
    __ mov($temp$$Register, $cnt$$Register);
    Label(loop);
    __ bind(loop);
    __ subs($temp$$Register, $temp$$Register, 4);
    __ str($zero$$Register, Address($base$$Register, $temp$$Register), ge);
    __ b(loop, gt);
  %}
  ins_pipe(long_memory_op);
%}

#ifdef XXX
// FIXME: Why R0/R1/R2/R3?
instruct string_compare(R0RegP str1, R1RegP str2, R2RegI cnt1, R3RegI cnt2, iRegI result,
                        iRegI tmp1, iRegI tmp2, flagsReg ccr) %{
  predicate(!CompactStrings);
  match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2)));
  effect(USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL ccr, TEMP tmp1, TEMP tmp2);
  ins_cost(300);
  format %{ "String Compare $str1,$cnt1,$str2,$cnt2 -> $result   // TEMP $tmp1, $tmp2" %}
  ins_encode( enc_String_Compare(str1, str2, cnt1, cnt2, result, tmp1, tmp2) );

  ins_pipe(long_memory_op);
%}

// FIXME: Why R0/R1/R2?
instruct string_equals(R0RegP str1, R1RegP str2, R2RegI cnt, iRegI result, iRegI tmp1, iRegI tmp2,
                       flagsReg ccr) %{
  predicate(!CompactStrings);
  match(Set result (StrEquals (Binary str1 str2) cnt));
  effect(USE_KILL str1, USE_KILL str2, USE_KILL cnt, TEMP tmp1, TEMP tmp2, TEMP result, KILL ccr);

  ins_cost(300);
  format %{ "String Equals $str1,$str2,$cnt -> $result   // TEMP $tmp1, $tmp2" %}
  ins_encode( enc_String_Equals(str1, str2, cnt, result, tmp1, tmp2) );
  ins_pipe(long_memory_op);
%}

// FIXME: Why R0/R1?
instruct array_equals(R0RegP ary1, R1RegP ary2, iRegI tmp1, iRegI tmp2, iRegI tmp3, iRegI result,
                      flagsReg ccr) %{
  predicate(((AryEqNode*)n)->encoding() == StrIntrinsicNode::UU);
  match(Set result (AryEq ary1 ary2));
  effect(USE_KILL ary1, USE_KILL ary2, TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP result, KILL ccr);

  ins_cost(300);
  format %{ "Array Equals $ary1,$ary2 -> $result   // TEMP $tmp1,$tmp2,$tmp3" %}
  ins_encode( enc_Array_Equals(ary1, ary2, tmp1, tmp2, tmp3, result));
  ins_pipe(long_memory_op);
%}
#endif

//---------- Zeros Count Instructions ------------------------------------------

instruct countLeadingZerosI(iRegI dst, iRegI src) %{
  match(Set dst (CountLeadingZerosI src));
  size(4);
  format %{ "CLZ_32 $dst,$src" %}
  ins_encode %{
    __ clz_32($dst$$Register, $src$$Register);
  %}
  ins_pipe(ialu_reg);
%}

instruct countLeadingZerosL(iRegI dst, iRegL src, iRegI tmp, flagsReg ccr) %{
  match(Set dst (CountLeadingZerosL src));
  effect(TEMP tmp, TEMP dst, KILL ccr);
  size(16);
  format %{ "CLZ    $dst,$src.hi\n\t"
            "TEQ    $dst,32\n\t"
            "CLZ.eq $tmp,$src.lo\n\t"
            "ADD.eq $dst, $dst, $tmp\n\t" %}
  ins_encode %{
    __ clz($dst$$Register, $src$$Register->successor());
    __ teq($dst$$Register, 32);
    __ clz($tmp$$Register, $src$$Register, eq);
    __ add($dst$$Register, $dst$$Register, $tmp$$Register, eq);
  %}
  ins_pipe(ialu_reg);
%}

instruct countTrailingZerosI(iRegI dst, iRegI src, iRegI tmp) %{
  match(Set dst (CountTrailingZerosI src));
  effect(TEMP tmp);
  size(8);
  format %{ "RBIT_32 $tmp, $src\n\t"
            "CLZ_32  $dst,$tmp" %}
  ins_encode %{
    __ rbit_32($tmp$$Register, $src$$Register);
    __ clz_32($dst$$Register, $tmp$$Register);
  %}
  ins_pipe(ialu_reg);
%}

instruct countTrailingZerosL(iRegI dst, iRegL src, iRegI tmp, flagsReg ccr) %{
  match(Set dst (CountTrailingZerosL src));
  effect(TEMP tmp, TEMP dst, KILL ccr);
  size(24);
  format %{ "RBIT   $tmp,$src.lo\n\t"
            "CLZ    $dst,$tmp\n\t"
            "TEQ    $dst,32\n\t"
            "RBIT   $tmp,$src.hi\n\t"
            "CLZ.eq $tmp,$tmp\n\t"
            "ADD.eq $dst,$dst,$tmp\n\t" %}
  ins_encode %{
    __ rbit($tmp$$Register, $src$$Register);
    __ clz($dst$$Register, $tmp$$Register);
    __ teq($dst$$Register, 32);
    __ rbit($tmp$$Register, $src$$Register->successor());
    __ clz($tmp$$Register, $tmp$$Register, eq);
    __ add($dst$$Register, $dst$$Register, $tmp$$Register, eq);
  %}
  ins_pipe(ialu_reg);
%}


//---------- Population Count Instructions -------------------------------------

instruct popCountI(iRegI dst, iRegI src, regD_low tmp) %{
  predicate(UsePopCountInstruction);
  match(Set dst (PopCountI src));
  effect(TEMP tmp);

  format %{ "FMSR       $tmp,$src\n\t"
            "VCNT.8     $tmp,$tmp\n\t"
            "VPADDL.U8  $tmp,$tmp\n\t"
            "VPADDL.U16 $tmp,$tmp\n\t"
            "FMRS       $dst,$tmp" %}
  size(20);

  ins_encode %{
    __ fmsr($tmp$$FloatRegister, $src$$Register);
    __ vcnt($tmp$$FloatRegister, $tmp$$FloatRegister);
    __ vpaddl($tmp$$FloatRegister, $tmp$$FloatRegister, 8, 0);
    __ vpaddl($tmp$$FloatRegister, $tmp$$FloatRegister, 16, 0);
    __ fmrs($dst$$Register, $tmp$$FloatRegister);
  %}
  ins_pipe(ialu_reg); // FIXME
%}

// Note: Long.bitCount(long) returns an int.
instruct popCountL(iRegI dst, iRegL src, regD_low tmp) %{
  predicate(UsePopCountInstruction);
  match(Set dst (PopCountL src));
  effect(TEMP tmp);

  format %{ "FMDRR       $tmp,$src.lo,$src.hi\n\t"
            "VCNT.8      $tmp,$tmp\n\t"
            "VPADDL.U8   $tmp,$tmp\n\t"
            "VPADDL.U16  $tmp,$tmp\n\t"
            "VPADDL.U32  $tmp,$tmp\n\t"
            "FMRS        $dst,$tmp" %}

  size(32);

  ins_encode %{
    __ fmdrr($tmp$$FloatRegister, $src$$Register, $src$$Register->successor());
    __ vcnt($tmp$$FloatRegister, $tmp$$FloatRegister);
    __ vpaddl($tmp$$FloatRegister, $tmp$$FloatRegister, 8, 0);
    __ vpaddl($tmp$$FloatRegister, $tmp$$FloatRegister, 16, 0);
    __ vpaddl($tmp$$FloatRegister, $tmp$$FloatRegister, 32, 0);
    __ fmrs($dst$$Register, $tmp$$FloatRegister);
  %}
  ins_pipe(ialu_reg);
%}


// ============================================================================
//------------Bytes reverse--------------------------------------------------

instruct bytes_reverse_int(iRegI dst, iRegI src) %{
  match(Set dst (ReverseBytesI src));

  size(4);
  format %{ "REV32 $dst,$src" %}
  ins_encode %{
    __ rev($dst$$Register, $src$$Register);
  %}
  ins_pipe( iload_mem ); // FIXME
%}

instruct bytes_reverse_long(iRegL dst, iRegL src) %{
  match(Set dst (ReverseBytesL src));
  effect(TEMP dst);
  size(8);
  format %{ "REV $dst.lo,$src.lo\n\t"
            "REV $dst.hi,$src.hi" %}
  ins_encode %{
    __ rev($dst$$Register, $src$$Register->successor());
    __ rev($dst$$Register->successor(), $src$$Register);
  %}
  ins_pipe( iload_mem ); // FIXME
%}

instruct bytes_reverse_unsigned_short(iRegI dst, iRegI src) %{
  match(Set dst (ReverseBytesUS src));
  size(4);
  format %{ "REV16 $dst,$src" %}
  ins_encode %{
    __ rev16($dst$$Register, $src$$Register);
  %}
  ins_pipe( iload_mem ); // FIXME
%}

instruct bytes_reverse_short(iRegI dst, iRegI src) %{
  match(Set dst (ReverseBytesS src));
  size(4);
  format %{ "REVSH $dst,$src" %}
  ins_encode %{
    __ revsh($dst$$Register, $src$$Register);
  %}
  ins_pipe( iload_mem ); // FIXME
%}


// ====================VECTOR INSTRUCTIONS=====================================

// Load Aligned Packed values into a Double Register
instruct loadV8(vecD dst, memoryD mem) %{
  predicate(n->as_LoadVector()->memory_size() == 8);
  match(Set dst (LoadVector mem));
  ins_cost(MEMORY_REF_COST);
  size(4);
  format %{ "FLDD   $mem,$dst\t! load vector (8 bytes)" %}
  ins_encode %{
    __ ldr_double($dst$$FloatRegister, $mem$$Address);
  %}
  ins_pipe(floadD_mem);
%}

// Load Aligned Packed values into a Double Register Pair
instruct loadV16(vecX dst, memoryvld mem) %{
  predicate(n->as_LoadVector()->memory_size() == 16);
  match(Set dst (LoadVector mem));
  ins_cost(MEMORY_REF_COST);
  size(4);
  format %{ "VLD1   $mem,$dst.Q\t! load vector (16 bytes)" %}
  ins_encode %{
    __ vld1($dst$$FloatRegister, $mem$$Address, MacroAssembler::VELEM_SIZE_16, 128);
  %}
  ins_pipe(floadD_mem); // FIXME
%}

// Store Vector in Double register to memory
instruct storeV8(memoryD mem, vecD src) %{
  predicate(n->as_StoreVector()->memory_size() == 8);
  match(Set mem (StoreVector mem src));
  ins_cost(MEMORY_REF_COST);
  size(4);
  format %{ "FSTD   $src,$mem\t! store vector (8 bytes)" %}
  ins_encode %{
    __ str_double($src$$FloatRegister, $mem$$Address);
  %}
  ins_pipe(fstoreD_mem_reg);
%}

// Store Vector in Double Register Pair to memory
instruct storeV16(memoryvld mem, vecX src) %{
  predicate(n->as_StoreVector()->memory_size() == 16);
  match(Set mem (StoreVector mem src));
  ins_cost(MEMORY_REF_COST);
  size(4);
  format %{ "VST1   $src,$mem\t! store vector (16 bytes)" %}
  ins_encode %{
    __ vst1($src$$FloatRegister, $mem$$Address, MacroAssembler::VELEM_SIZE_16, 128);
  %}
  ins_pipe(fstoreD_mem_reg); // FIXME
%}

// Replicate scalar to packed byte values in Double register
instruct Repl8B_reg(vecD dst, iRegI src, iRegI tmp) %{
  predicate(n->as_Vector()->length() == 8);
  match(Set dst (ReplicateB src));
  ins_cost(DEFAULT_COST*4);
  effect(TEMP tmp);
  size(16);

  // FIXME: could use PKH instruction instead?
  format %{ "LSL      $tmp, $src, 24 \n\t"
            "OR       $tmp, $tmp, ($tmp >> 8) \n\t"
            "OR       $tmp, $tmp, ($tmp >> 16) \n\t"
            "FMDRR    $dst,$tmp,$tmp\t" %}
  ins_encode %{
    __ mov($tmp$$Register, AsmOperand($src$$Register, lsl, 24));
    __ orr($tmp$$Register, $tmp$$Register, AsmOperand($tmp$$Register, lsr, 8));
    __ orr($tmp$$Register, $tmp$$Register, AsmOperand($tmp$$Register, lsr, 16));
    __ fmdrr($dst$$FloatRegister, $tmp$$Register, $tmp$$Register);
  %}
  ins_pipe(ialu_reg); // FIXME
%}

// Replicate scalar to packed byte values in Double register
instruct Repl8B_reg_simd(vecD dst, iRegI src) %{
  predicate(n->as_Vector()->length_in_bytes() == 8 && VM_Version::has_simd());
  match(Set dst (ReplicateB src));
  size(4);

  format %{ "VDUP.8 $dst,$src\t" %}
  ins_encode %{
    bool quad = false;
    __ vdupI($dst$$FloatRegister, $src$$Register,
             MacroAssembler::VELEM_SIZE_8, quad);
  %}
  ins_pipe(ialu_reg); // FIXME
%}

// Replicate scalar to packed byte values in Double register pair
instruct Repl16B_reg(vecX dst, iRegI src) %{
  predicate(n->as_Vector()->length_in_bytes() == 16);
  match(Set dst (ReplicateB src));
  size(4);

  format %{ "VDUP.8 $dst.Q,$src\t" %}
  ins_encode %{
    bool quad = true;
    __ vdupI($dst$$FloatRegister, $src$$Register,
             MacroAssembler::VELEM_SIZE_8, quad);
  %}
  ins_pipe(ialu_reg); // FIXME
%}

// Replicate scalar constant to packed byte values in Double register
instruct Repl8B_immI(vecD dst, immI src, iRegI tmp) %{
  predicate(n->as_Vector()->length() == 8);
  match(Set dst (ReplicateB src));
  ins_cost(DEFAULT_COST*2);
  effect(TEMP tmp);
  size(12);

  format %{ "MOV      $tmp, Repl4($src))\n\t"
            "FMDRR    $dst,$tmp,$tmp\t" %}
  ins_encode( LdReplImmI(src, dst, tmp, (4), (1)) );
  ins_pipe(loadConFD); // FIXME
%}

// Replicate scalar constant to packed byte values in Double register
// TODO: support negative constants with MVNI?
instruct Repl8B_immU8(vecD dst, immU8 src) %{
  predicate(n->as_Vector()->length_in_bytes() == 8 && VM_Version::has_simd());
  match(Set dst (ReplicateB src));
  size(4);

  format %{ "VMOV.U8  $dst,$src" %}
  ins_encode %{
    bool quad = false;
    __ vmovI($dst$$FloatRegister, $src$$constant,
             MacroAssembler::VELEM_SIZE_8, quad);
  %}
  ins_pipe(loadConFD); // FIXME
%}

// Replicate scalar constant to packed byte values in Double register pair
instruct Repl16B_immU8(vecX dst, immU8 src) %{
  predicate(n->as_Vector()->length_in_bytes() == 16 && VM_Version::has_simd());
  match(Set dst (ReplicateB src));
  size(4);

  format %{ "VMOV.U8  $dst.Q,$src" %}
  ins_encode %{
    bool quad = true;
    __ vmovI($dst$$FloatRegister, $src$$constant,
             MacroAssembler::VELEM_SIZE_8, quad);
  %}
  ins_pipe(loadConFD); // FIXME
%}

// Replicate scalar to packed short/char values into Double register
instruct Repl4S_reg(vecD dst, iRegI src, iRegI tmp) %{
  predicate(n->as_Vector()->length() == 4);
  match(Set dst (ReplicateS src));
  ins_cost(DEFAULT_COST*3);
  effect(TEMP tmp);
  size(12);

  // FIXME: could use PKH instruction instead?
  format %{ "LSL      $tmp, $src, 16 \n\t"
            "OR       $tmp, $tmp, ($tmp >> 16) \n\t"
            "FMDRR    $dst,$tmp,$tmp\t" %}
  ins_encode %{
    __ mov($tmp$$Register, AsmOperand($src$$Register, lsl, 16));
    __ orr($tmp$$Register, $tmp$$Register, AsmOperand($tmp$$Register, lsr, 16));
    __ fmdrr($dst$$FloatRegister, $tmp$$Register, $tmp$$Register);
  %}
  ins_pipe(ialu_reg); // FIXME
%}

// Replicate scalar to packed byte values in Double register
instruct Repl4S_reg_simd(vecD dst, iRegI src) %{
  predicate(n->as_Vector()->length_in_bytes() == 8 && VM_Version::has_simd());
  match(Set dst (ReplicateS src));
  size(4);

  format %{ "VDUP.16 $dst,$src\t" %}
  ins_encode %{
    bool quad = false;
    __ vdupI($dst$$FloatRegister, $src$$Register,
             MacroAssembler::VELEM_SIZE_16, quad);
  %}
  ins_pipe(ialu_reg); // FIXME
%}

// Replicate scalar to packed byte values in Double register pair
instruct Repl8S_reg(vecX dst, iRegI src) %{
  predicate(n->as_Vector()->length_in_bytes() == 16 && VM_Version::has_simd());
  match(Set dst (ReplicateS src));
  size(4);

  format %{ "VDUP.16 $dst.Q,$src\t" %}
  ins_encode %{
    bool quad = true;
    __ vdupI($dst$$FloatRegister, $src$$Register,
             MacroAssembler::VELEM_SIZE_16, quad);
  %}
  ins_pipe(ialu_reg); // FIXME
%}


// Replicate scalar constant to packed short/char values in Double register
instruct Repl4S_immI(vecD dst, immI src, iRegP tmp) %{
  predicate(n->as_Vector()->length() == 4);
  match(Set dst (ReplicateS src));
  effect(TEMP tmp);
  size(12);
  ins_cost(DEFAULT_COST*4); // FIXME

  format %{ "MOV      $tmp, Repl2($src))\n\t"
            "FMDRR    $dst,$tmp,$tmp\t" %}
  ins_encode( LdReplImmI(src, dst, tmp, (2), (2)) );
  ins_pipe(loadConFD); // FIXME
%}

// Replicate scalar constant to packed byte values in Double register
instruct Repl4S_immU8(vecD dst, immU8 src) %{
  predicate(n->as_Vector()->length_in_bytes() == 8 && VM_Version::has_simd());
  match(Set dst (ReplicateS src));
  size(4);

  format %{ "VMOV.U16  $dst,$src" %}
  ins_encode %{
    bool quad = false;
    __ vmovI($dst$$FloatRegister, $src$$constant,
             MacroAssembler::VELEM_SIZE_16, quad);
  %}
  ins_pipe(loadConFD); // FIXME
%}

// Replicate scalar constant to packed byte values in Double register pair
instruct Repl8S_immU8(vecX dst, immU8 src) %{
  predicate(n->as_Vector()->length_in_bytes() == 16 && VM_Version::has_simd());
  match(Set dst (ReplicateS src));
  size(4);

  format %{ "VMOV.U16  $dst.Q,$src" %}
  ins_encode %{
    bool quad = true;
    __ vmovI($dst$$FloatRegister, $src$$constant,
             MacroAssembler::VELEM_SIZE_16, quad);
  %}
  ins_pipe(loadConFD); // FIXME
%}

// Replicate scalar to packed int values in Double register
instruct Repl2I_reg(vecD dst, iRegI src) %{
  predicate(n->as_Vector()->length() == 2);
  match(Set dst (ReplicateI src));
  size(4);

  format %{ "FMDRR    $dst,$src,$src\t" %}
  ins_encode %{
    __ fmdrr($dst$$FloatRegister, $src$$Register, $src$$Register);
  %}
  ins_pipe(ialu_reg); // FIXME
%}

// Replicate scalar to packed int values in Double register pair
instruct Repl4I_reg(vecX dst, iRegI src) %{
  predicate(n->as_Vector()->length() == 4);
  match(Set dst (ReplicateI src));
  ins_cost(DEFAULT_COST*2);
  size(8);

  format %{ "FMDRR    $dst.lo,$src,$src\n\t"
            "FMDRR    $dst.hi,$src,$src" %}

  ins_encode %{
    __ fmdrr($dst$$FloatRegister, $src$$Register, $src$$Register);
    __ fmdrr($dst$$FloatRegister->successor()->successor(),
             $src$$Register, $src$$Register);
  %}
  ins_pipe(ialu_reg); // FIXME
%}

// Replicate scalar to packed int values in Double register
instruct Repl2I_reg_simd(vecD dst, iRegI src) %{
  predicate(n->as_Vector()->length_in_bytes() == 8 && VM_Version::has_simd());
  match(Set dst (ReplicateI src));
  size(4);

  format %{ "VDUP.32 $dst.D,$src\t" %}
  ins_encode %{
    bool quad = false;
    __ vdupI($dst$$FloatRegister, $src$$Register,
             MacroAssembler::VELEM_SIZE_32, quad);
  %}
  ins_pipe(ialu_reg); // FIXME
%}

// Replicate scalar to packed int values in Double register pair
instruct Repl4I_reg_simd(vecX dst, iRegI src) %{
  predicate(n->as_Vector()->length_in_bytes() == 16 && VM_Version::has_simd());
  match(Set dst (ReplicateI src));
  size(4);

  format %{ "VDUP.32 $dst.Q,$src\t" %}
  ins_encode %{
    bool quad = true;
    __ vdupI($dst$$FloatRegister, $src$$Register,
             MacroAssembler::VELEM_SIZE_32, quad);
  %}
  ins_pipe(ialu_reg); // FIXME
%}


// Replicate scalar zero constant to packed int values in Double register
instruct Repl2I_immI(vecD dst, immI src, iRegI tmp) %{
  predicate(n->as_Vector()->length() == 2);
  match(Set dst (ReplicateI src));
  effect(TEMP tmp);
  size(12);
  ins_cost(DEFAULT_COST*4); // FIXME

  format %{ "MOV      $tmp, Repl1($src))\n\t"
            "FMDRR    $dst,$tmp,$tmp\t" %}
  ins_encode( LdReplImmI(src, dst, tmp, (1), (4)) );
  ins_pipe(loadConFD); // FIXME
%}

// Replicate scalar constant to packed byte values in Double register
instruct Repl2I_immU8(vecD dst, immU8 src) %{
  predicate(n->as_Vector()->length_in_bytes() == 8 && VM_Version::has_simd());
  match(Set dst (ReplicateI src));
  size(4);

  format %{ "VMOV.I32  $dst.D,$src" %}
  ins_encode %{
    bool quad = false;
    __ vmovI($dst$$FloatRegister, $src$$constant,
             MacroAssembler::VELEM_SIZE_32, quad);
  %}
  ins_pipe(loadConFD); // FIXME
%}

// Replicate scalar constant to packed byte values in Double register pair
instruct Repl4I_immU8(vecX dst, immU8 src) %{
  predicate(n->as_Vector()->length_in_bytes() == 16 && VM_Version::has_simd());
  match(Set dst (ReplicateI src));
  size(4);

  format %{ "VMOV.I32  $dst.Q,$src" %}
  ins_encode %{
    bool quad = true;
    __ vmovI($dst$$FloatRegister, $src$$constant,
             MacroAssembler::VELEM_SIZE_32, quad);
  %}
  ins_pipe(loadConFD); // FIXME
%}

// Replicate scalar to packed byte values in Double register pair
instruct Repl2L_reg(vecX dst, iRegL src) %{
  predicate(n->as_Vector()->length() == 2);
  match(Set dst (ReplicateL src));
  size(8);
  ins_cost(DEFAULT_COST*2); // FIXME

  format %{ "FMDRR $dst.D,$src.lo,$src.hi\t\n"
            "FMDRR $dst.D.next,$src.lo,$src.hi" %}
  ins_encode %{
    __ fmdrr($dst$$FloatRegister, $src$$Register, $src$$Register->successor());
    __ fmdrr($dst$$FloatRegister->successor()->successor(),
             $src$$Register, $src$$Register->successor());
  %}
  ins_pipe(ialu_reg); // FIXME
%}


// Replicate scalar to packed float values in Double register
instruct Repl2F_regI(vecD dst, iRegI src) %{
  predicate(n->as_Vector()->length() == 2);
  match(Set dst (ReplicateF src));
  size(4);

  format %{ "FMDRR    $dst.D,$src,$src\t" %}
  ins_encode %{
    __ fmdrr($dst$$FloatRegister, $src$$Register, $src$$Register);
  %}
  ins_pipe(ialu_reg); // FIXME
%}

// Replicate scalar to packed float values in Double register
instruct Repl2F_reg_vfp(vecD dst, regF src) %{
  predicate(n->as_Vector()->length() == 2);
  match(Set dst (ReplicateF src));
  size(4*2);
  ins_cost(DEFAULT_COST*2); // FIXME

  expand %{
    iRegI tmp;
    MoveF2I_reg_reg(tmp, src);
    Repl2F_regI(dst,tmp);
  %}
%}

// Replicate scalar to packed float values in Double register
instruct Repl2F_reg_simd(vecD dst, regF src) %{
  predicate(n->as_Vector()->length_in_bytes() == 8 && VM_Version::has_simd());
  match(Set dst (ReplicateF src));
  size(4);
  ins_cost(DEFAULT_COST); // FIXME

  format %{ "VDUP.32  $dst.D,$src.D\t" %}
  ins_encode %{
    bool quad = false;
    __ vdupF($dst$$FloatRegister, $src$$FloatRegister, quad);
  %}
  ins_pipe(ialu_reg); // FIXME
%}

// Replicate scalar to packed float values in Double register pair
instruct Repl4F_reg(vecX dst, regF src, iRegI tmp) %{
  predicate(n->as_Vector()->length() == 4);
  match(Set dst (ReplicateF src));
  effect(TEMP tmp);
  size(4*3);
  ins_cost(DEFAULT_COST*3); // FIXME

  format %{ "FMRS     $tmp,$src\n\t"
            "FMDRR    $dst.D,$tmp,$tmp\n\t"
            "FMDRR    $dst.D.next,$tmp,$tmp\t" %}
  ins_encode %{
    __ fmrs($tmp$$Register, $src$$FloatRegister);
    __ fmdrr($dst$$FloatRegister, $tmp$$Register, $tmp$$Register);
    __ fmdrr($dst$$FloatRegister->successor()->successor(),
             $tmp$$Register, $tmp$$Register);
  %}
  ins_pipe(ialu_reg); // FIXME
%}

// Replicate scalar to packed float values in Double register pair
instruct Repl4F_reg_simd(vecX dst, regF src) %{
  predicate(n->as_Vector()->length_in_bytes() == 16 && VM_Version::has_simd());
  match(Set dst (ReplicateF src));
  size(4);
  ins_cost(DEFAULT_COST); // FIXME

  format %{ "VDUP.32  $dst.Q,$src.D\t" %}
  ins_encode %{
    bool quad = true;
    __ vdupF($dst$$FloatRegister, $src$$FloatRegister, quad);
  %}
  ins_pipe(ialu_reg); // FIXME
%}

// Replicate scalar zero constant to packed float values in Double register
instruct Repl2F_immI(vecD dst, immF src, iRegI tmp) %{
  predicate(n->as_Vector()->length() == 2);
  match(Set dst (ReplicateF src));
  effect(TEMP tmp);
  size(12);
  ins_cost(DEFAULT_COST*4); // FIXME

  format %{ "MOV      $tmp, Repl1($src))\n\t"
            "FMDRR    $dst,$tmp,$tmp\t" %}
  ins_encode( LdReplImmF(src, dst, tmp) );
  ins_pipe(loadConFD); // FIXME
%}

// Replicate scalar to packed double float values in Double register pair
instruct Repl2D_reg(vecX dst, regD src) %{
  predicate(n->as_Vector()->length() == 2);
  match(Set dst (ReplicateD src));
  size(4*2);
  ins_cost(DEFAULT_COST*2); // FIXME

  format %{ "FCPYD    $dst.D.a,$src\n\t"
            "FCPYD    $dst.D.b,$src\t" %}
  ins_encode %{
    FloatRegister dsta = $dst$$FloatRegister;
    FloatRegister src = $src$$FloatRegister;
    __ fcpyd(dsta, src);
    FloatRegister dstb = dsta->successor()->successor();
    __ fcpyd(dstb, src);
  %}
  ins_pipe(ialu_reg); // FIXME
%}

// ====================VECTOR ARITHMETIC=======================================

// --------------------------------- ADD --------------------------------------

// Bytes vector add
instruct vadd8B_reg(vecD dst, vecD src1, vecD src2) %{
  predicate(n->as_Vector()->length() == 8);
  match(Set dst (AddVB src1 src2));
  format %{ "VADD.I8 $dst,$src1,$src2\t! add packed8B" %}
  size(4);
  ins_encode %{
    bool quad = false;
    __ vaddI($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
             MacroAssembler::VELEM_SIZE_8, quad);
  %}
  ins_pipe( ialu_reg_reg ); // FIXME
%}

instruct vadd16B_reg(vecX dst, vecX src1, vecX src2) %{
  predicate(n->as_Vector()->length() == 16);
  match(Set dst (AddVB src1 src2));
  size(4);
  format %{ "VADD.I8 $dst.Q,$src1.Q,$src2.Q\t! add packed16B" %}
  ins_encode %{
    bool quad = true;
    __ vaddI($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
             MacroAssembler::VELEM_SIZE_8, quad);
  %}
  ins_pipe( ialu_reg_reg ); // FIXME
%}

// Shorts/Chars vector add
instruct vadd4S_reg(vecD dst, vecD src1, vecD src2) %{
  predicate(n->as_Vector()->length() == 4);
  match(Set dst (AddVS src1 src2));
  size(4);
  format %{ "VADD.I16 $dst,$src1,$src2\t! add packed4S" %}
  ins_encode %{
    bool quad = false;
    __ vaddI($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
             MacroAssembler::VELEM_SIZE_16, quad);
  %}
  ins_pipe( ialu_reg_reg ); // FIXME
%}

instruct vadd8S_reg(vecX dst, vecX src1, vecX src2) %{
  predicate(n->as_Vector()->length() == 8);
  match(Set dst (AddVS src1 src2));
  size(4);
  format %{ "VADD.I16 $dst.Q,$src1.Q,$src2.Q\t! add packed8S" %}
  ins_encode %{
    bool quad = true;
    __ vaddI($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
             MacroAssembler::VELEM_SIZE_16, quad);
  %}
  ins_pipe( ialu_reg_reg ); // FIXME
%}

// Integers vector add
instruct vadd2I_reg(vecD dst, vecD src1, vecD src2) %{
  predicate(n->as_Vector()->length() == 2);
  match(Set dst (AddVI src1 src2));
  size(4);
  format %{ "VADD.I32 $dst.D,$src1.D,$src2.D\t! add packed2I" %}
  ins_encode %{
    bool quad = false;
    __ vaddI($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
             MacroAssembler::VELEM_SIZE_32, quad);
  %}
  ins_pipe( ialu_reg_reg ); // FIXME
%}

instruct vadd4I_reg(vecX dst, vecX src1, vecX src2) %{
  predicate(n->as_Vector()->length() == 4);
  match(Set dst (AddVI src1 src2));
  size(4);
  format %{ "VADD.I32 $dst.Q,$src1.Q,$src2.Q\t! add packed4I" %}
  ins_encode %{
    bool quad = true;
    __ vaddI($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
             MacroAssembler::VELEM_SIZE_32, quad);
  %}
  ins_pipe( ialu_reg_reg ); // FIXME
%}

// Longs vector add
instruct vadd2L_reg(vecX dst, vecX src1, vecX src2) %{
  predicate(n->as_Vector()->length() == 2);
  match(Set dst (AddVL src1 src2));
  size(4);
  format %{ "VADD.I64 $dst.Q,$src1.Q,$src2.Q\t! add packed2L" %}
  ins_encode %{
    bool quad = true;
    __ vaddI($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
             MacroAssembler::VELEM_SIZE_64, quad);
  %}
  ins_pipe( ialu_reg_reg ); // FIXME
%}

// Floats vector add
instruct vadd2F_reg(vecD dst, vecD src1, vecD src2) %{
  predicate(n->as_Vector()->length() == 2 && VM_Version::simd_math_is_compliant());
  match(Set dst (AddVF src1 src2));
  size(4);
  format %{ "VADD.F32 $dst,$src1,$src2\t! add packed2F" %}
  ins_encode %{
    bool quad = false;
    __ vaddF($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
             MacroAssembler::VFA_SIZE_F32, quad);
  %}
  ins_pipe( faddD_reg_reg ); // FIXME
%}

instruct vadd2F_reg_vfp(vecD dst, vecD src1, vecD src2) %{
  predicate(n->as_Vector()->length() == 2 && !VM_Version::simd_math_is_compliant());
  match(Set dst (AddVF src1 src2));
  ins_cost(DEFAULT_COST*2); // FIXME

  size(4*2);
  format %{ "FADDS  $dst.a,$src1.a,$src2.a\n\t"
            "FADDS  $dst.b,$src1.b,$src2.b" %}
  ins_encode %{
    __ add_float($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister);
    __ add_float($dst$$FloatRegister->successor(),
             $src1$$FloatRegister->successor(),
             $src2$$FloatRegister->successor());
  %}

  ins_pipe(faddF_reg_reg); // FIXME
%}

instruct vadd4F_reg_simd(vecX dst, vecX src1, vecX src2) %{
  predicate(n->as_Vector()->length() == 4 && VM_Version::simd_math_is_compliant());
  match(Set dst (AddVF src1 src2));
  size(4);
  format %{ "VADD.F32 $dst.Q,$src1.Q,$src2.Q\t! add packed4F" %}
  ins_encode %{
    bool quad = true;
    __ vaddF($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
             MacroAssembler::VFA_SIZE_F32, quad);
  %}
  ins_pipe( faddD_reg_reg ); // FIXME
%}

instruct vadd4F_reg_vfp(vecX dst, vecX src1, vecX src2) %{
  predicate(n->as_Vector()->length() == 4 && !VM_Version::simd_math_is_compliant());
  match(Set dst (AddVF src1 src2));
  size(4*4);
  ins_cost(DEFAULT_COST*4); // FIXME

  format %{ "FADDS  $dst.a,$src1.a,$src2.a\n\t"
            "FADDS  $dst.b,$src1.b,$src2.b\n\t"
            "FADDS  $dst.c,$src1.c,$src2.c\n\t"
            "FADDS  $dst.d,$src1.d,$src2.d" %}

  ins_encode %{
    FloatRegister dsta = $dst$$FloatRegister;
    FloatRegister src1a = $src1$$FloatRegister;
    FloatRegister src2a = $src2$$FloatRegister;
    __ add_float(dsta, src1a, src2a);
    FloatRegister dstb = dsta->successor();
    FloatRegister src1b = src1a->successor();
    FloatRegister src2b = src2a->successor();
    __ add_float(dstb, src1b, src2b);
    FloatRegister dstc = dstb->successor();
    FloatRegister src1c = src1b->successor();
    FloatRegister src2c = src2b->successor();
    __ add_float(dstc, src1c, src2c);
    FloatRegister dstd = dstc->successor();
    FloatRegister src1d = src1c->successor();
    FloatRegister src2d = src2c->successor();
    __ add_float(dstd, src1d, src2d);
  %}

  ins_pipe(faddF_reg_reg); // FIXME
%}

instruct vadd2D_reg_vfp(vecX dst, vecX src1, vecX src2) %{
  predicate(n->as_Vector()->length() == 2);
  match(Set dst (AddVD src1 src2));
  size(4*2);
  ins_cost(DEFAULT_COST*2); // FIXME

  format %{ "FADDD  $dst.a,$src1.a,$src2.a\n\t"
            "FADDD  $dst.b,$src1.b,$src2.b" %}

  ins_encode %{
    FloatRegister dsta = $dst$$FloatRegister;
    FloatRegister src1a = $src1$$FloatRegister;
    FloatRegister src2a = $src2$$FloatRegister;
    __ add_double(dsta, src1a, src2a);
    FloatRegister dstb = dsta->successor()->successor();
    FloatRegister src1b = src1a->successor()->successor();
    FloatRegister src2b = src2a->successor()->successor();
    __ add_double(dstb, src1b, src2b);
  %}

  ins_pipe(faddF_reg_reg); // FIXME
%}


// Bytes vector sub
instruct vsub8B_reg(vecD dst, vecD src1, vecD src2) %{
  predicate(n->as_Vector()->length() == 8);
  match(Set dst (SubVB src1 src2));
  size(4);
  format %{ "VSUB.I8 $dst,$src1,$src2\t! sub packed8B" %}
  ins_encode %{
    bool quad = false;
    __ vsubI($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
             MacroAssembler::VELEM_SIZE_8, quad);
  %}
  ins_pipe( ialu_reg_reg ); // FIXME
%}

instruct vsub16B_reg(vecX dst, vecX src1, vecX src2) %{
  predicate(n->as_Vector()->length() == 16);
  match(Set dst (SubVB src1 src2));
  size(4);
  format %{ "VSUB.I8 $dst.Q,$src1.Q,$src2.Q\t! sub packed16B" %}
  ins_encode %{
    bool quad = true;
    __ vsubI($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
             MacroAssembler::VELEM_SIZE_8, quad);
  %}
  ins_pipe( ialu_reg_reg ); // FIXME
%}

// Shorts/Chars vector sub
instruct vsub4S_reg(vecD dst, vecD src1, vecD src2) %{
  predicate(n->as_Vector()->length() == 4);
  match(Set dst (SubVS src1 src2));
  size(4);
  format %{ "VSUB.I16 $dst,$src1,$src2\t! sub packed4S" %}
  ins_encode %{
    bool quad = false;
    __ vsubI($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
             MacroAssembler::VELEM_SIZE_16, quad);
  %}
  ins_pipe( ialu_reg_reg ); // FIXME
%}

instruct vsub16S_reg(vecX dst, vecX src1, vecX src2) %{
  predicate(n->as_Vector()->length() == 8);
  match(Set dst (SubVS src1 src2));
  size(4);
  format %{ "VSUB.I16 $dst.Q,$src1.Q,$src2.Q\t! sub packed8S" %}
  ins_encode %{
    bool quad = true;
    __ vsubI($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
             MacroAssembler::VELEM_SIZE_16, quad);
  %}
  ins_pipe( ialu_reg_reg ); // FIXME
%}

// Integers vector sub
instruct vsub2I_reg(vecD dst, vecD src1, vecD src2) %{
  predicate(n->as_Vector()->length() == 2);
  match(Set dst (SubVI src1 src2));
  size(4);
  format %{ "VSUB.I32 $dst,$src1,$src2\t! sub packed2I" %}
  ins_encode %{
    bool quad = false;
    __ vsubI($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
             MacroAssembler::VELEM_SIZE_32, quad);
  %}
  ins_pipe( ialu_reg_reg ); // FIXME
%}

instruct vsub4I_reg(vecX dst, vecX src1, vecX src2) %{
  predicate(n->as_Vector()->length() == 4);
  match(Set dst (SubVI src1 src2));
  size(4);
  format %{ "VSUB.I32 $dst.Q,$src1.Q,$src2.Q\t! sub packed4I" %}
  ins_encode %{
    bool quad = true;
    __ vsubI($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
             MacroAssembler::VELEM_SIZE_32, quad);
  %}
  ins_pipe( ialu_reg_reg ); // FIXME
%}

// Longs vector sub
instruct vsub2L_reg(vecX dst, vecX src1, vecX src2) %{
  predicate(n->as_Vector()->length() == 2);
  match(Set dst (SubVL src1 src2));
  size(4);
  format %{ "VSUB.I64 $dst.Q,$src1.Q,$src2.Q\t! sub packed2L" %}
  ins_encode %{
    bool quad = true;
    __ vsubI($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
             MacroAssembler::VELEM_SIZE_64, quad);
  %}
  ins_pipe( ialu_reg_reg ); // FIXME
%}

// Floats vector sub
instruct vsub2F_reg(vecD dst, vecD src1, vecD src2) %{
  predicate(n->as_Vector()->length() == 2 && VM_Version::simd_math_is_compliant());
  match(Set dst (SubVF src1 src2));
  size(4);
  format %{ "VSUB.F32 $dst,$src1,$src2\t! sub packed2F" %}
  ins_encode %{
    bool quad = false;
    __ vsubF($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
             MacroAssembler::VFA_SIZE_F32, quad);
  %}
  ins_pipe( faddF_reg_reg ); // FIXME
%}

instruct vsub2F_reg_vfp(vecD dst, vecD src1, vecD src2) %{
  predicate(n->as_Vector()->length() == 2 && !VM_Version::simd_math_is_compliant());
  match(Set dst (SubVF src1 src2));
  size(4*2);
  ins_cost(DEFAULT_COST*2); // FIXME

  format %{ "FSUBS  $dst.a,$src1.a,$src2.a\n\t"
            "FSUBS  $dst.b,$src1.b,$src2.b" %}

  ins_encode %{
    FloatRegister dsta = $dst$$FloatRegister;
    FloatRegister src1a = $src1$$FloatRegister;
    FloatRegister src2a = $src2$$FloatRegister;
    __ sub_float(dsta, src1a, src2a);
    FloatRegister dstb = dsta->successor();
    FloatRegister src1b = src1a->successor();
    FloatRegister src2b = src2a->successor();
    __ sub_float(dstb, src1b, src2b);
  %}

  ins_pipe(faddF_reg_reg); // FIXME
%}


instruct vsub4F_reg(vecX dst, vecX src1, vecX src2) %{
  predicate(n->as_Vector()->length() == 4 && VM_Version::simd_math_is_compliant());
  match(Set dst (SubVF src1 src2));
  size(4);
  format %{ "VSUB.F32 $dst.Q,$src1.Q,$src2.Q\t! sub packed4F" %}
  ins_encode %{
    bool quad = true;
    __ vsubF($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
             MacroAssembler::VFA_SIZE_F32, quad);
  %}
  ins_pipe( faddF_reg_reg ); // FIXME
%}

instruct vsub4F_reg_vfp(vecX dst, vecX src1, vecX src2) %{
  predicate(n->as_Vector()->length() == 4 && !VM_Version::simd_math_is_compliant());
  match(Set dst (SubVF src1 src2));
  size(4*4);
  ins_cost(DEFAULT_COST*4); // FIXME

  format %{ "FSUBS  $dst.a,$src1.a,$src2.a\n\t"
            "FSUBS  $dst.b,$src1.b,$src2.b\n\t"
            "FSUBS  $dst.c,$src1.c,$src2.c\n\t"
            "FSUBS  $dst.d,$src1.d,$src2.d" %}

  ins_encode %{
    FloatRegister dsta = $dst$$FloatRegister;
    FloatRegister src1a = $src1$$FloatRegister;
    FloatRegister src2a = $src2$$FloatRegister;
    __ sub_float(dsta, src1a, src2a);
    FloatRegister dstb = dsta->successor();
    FloatRegister src1b = src1a->successor();
    FloatRegister src2b = src2a->successor();
    __ sub_float(dstb, src1b, src2b);
    FloatRegister dstc = dstb->successor();
    FloatRegister src1c = src1b->successor();
    FloatRegister src2c = src2b->successor();
    __ sub_float(dstc, src1c, src2c);
    FloatRegister dstd = dstc->successor();
    FloatRegister src1d = src1c->successor();
    FloatRegister src2d = src2c->successor();
    __ sub_float(dstd, src1d, src2d);
  %}

  ins_pipe(faddF_reg_reg); // FIXME
%}

instruct vsub2D_reg_vfp(vecX dst, vecX src1, vecX src2) %{
  predicate(n->as_Vector()->length() == 2);
  match(Set dst (SubVD src1 src2));
  size(4*2);
  ins_cost(DEFAULT_COST*2); // FIXME

  format %{ "FSUBD  $dst.a,$src1.a,$src2.a\n\t"
            "FSUBD  $dst.b,$src1.b,$src2.b" %}

  ins_encode %{
    FloatRegister dsta = $dst$$FloatRegister;
    FloatRegister src1a = $src1$$FloatRegister;
    FloatRegister src2a = $src2$$FloatRegister;
    __ sub_double(dsta, src1a, src2a);
    FloatRegister dstb = dsta->successor()->successor();
    FloatRegister src1b = src1a->successor()->successor();
    FloatRegister src2b = src2a->successor()->successor();
    __ sub_double(dstb, src1b, src2b);
  %}

  ins_pipe(faddF_reg_reg); // FIXME
%}

// Shorts/Chars vector mul
instruct vmul4S_reg(vecD dst, vecD src1, vecD src2) %{
  predicate(n->as_Vector()->length() == 4);
  match(Set dst (MulVS src1 src2));
  size(4);
  format %{ "VMUL.I16 $dst,$src1,$src2\t! mul packed4S" %}
  ins_encode %{
    __ vmulI($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
             MacroAssembler::VELEM_SIZE_16, 0);
  %}
  ins_pipe( ialu_reg_reg ); // FIXME
%}

instruct vmul8S_reg(vecX dst, vecX src1, vecX src2) %{
  predicate(n->as_Vector()->length() == 8);
  match(Set dst (MulVS src1 src2));
  size(4);
  format %{ "VMUL.I16 $dst.Q,$src1.Q,$src2.Q\t! mul packed8S" %}
  ins_encode %{
    __ vmulI($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
             MacroAssembler::VELEM_SIZE_16, 1);
  %}
  ins_pipe( ialu_reg_reg ); // FIXME
%}

// Integers vector mul
instruct vmul2I_reg(vecD dst, vecD src1, vecD src2) %{
  predicate(n->as_Vector()->length() == 2);
  match(Set dst (MulVI src1 src2));
  size(4);
  format %{ "VMUL.I32 $dst,$src1,$src2\t! mul packed2I" %}
  ins_encode %{
    __ vmulI($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
             MacroAssembler::VELEM_SIZE_32, 0);
  %}
  ins_pipe( ialu_reg_reg ); // FIXME
%}

instruct vmul4I_reg(vecX dst, vecX src1, vecX src2) %{
  predicate(n->as_Vector()->length() == 4);
  match(Set dst (MulVI src1 src2));
  size(4);
  format %{ "VMUL.I32 $dst.Q,$src1.Q,$src2.Q\t! mul packed4I" %}
  ins_encode %{
    __ vmulI($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
             MacroAssembler::VELEM_SIZE_32, 1);
  %}
  ins_pipe( ialu_reg_reg ); // FIXME
%}

// Floats vector mul
instruct vmul2F_reg(vecD dst, vecD src1, vecD src2) %{
  predicate(n->as_Vector()->length() == 2 && VM_Version::simd_math_is_compliant());
  match(Set dst (MulVF src1 src2));
  size(4);
  format %{ "VMUL.F32 $dst,$src1,$src2\t! mul packed2F" %}
  ins_encode %{
    __ vmulF($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
             MacroAssembler::VFA_SIZE_F32, 0);
  %}
  ins_pipe( fmulF_reg_reg ); // FIXME
%}

instruct vmul2F_reg_vfp(vecD dst, vecD src1, vecD src2) %{
  predicate(n->as_Vector()->length() == 2 && !VM_Version::simd_math_is_compliant());
  match(Set dst (MulVF src1 src2));
  size(4*2);
  ins_cost(DEFAULT_COST*2); // FIXME

  format %{ "FMULS  $dst.a,$src1.a,$src2.a\n\t"
            "FMULS  $dst.b,$src1.b,$src2.b" %}
  ins_encode %{
    __ mul_float($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister);
    __ mul_float($dst$$FloatRegister->successor(),
             $src1$$FloatRegister->successor(),
             $src2$$FloatRegister->successor());
  %}

  ins_pipe(fmulF_reg_reg); // FIXME
%}

instruct vmul4F_reg(vecX dst, vecX src1, vecX src2) %{
  predicate(n->as_Vector()->length() == 4 && VM_Version::simd_math_is_compliant());
  match(Set dst (MulVF src1 src2));
  size(4);
  format %{ "VMUL.F32 $dst.Q,$src1.Q,$src2.Q\t! mul packed4F" %}
  ins_encode %{
    __ vmulF($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
             MacroAssembler::VFA_SIZE_F32, 1);
  %}
  ins_pipe( fmulF_reg_reg ); // FIXME
%}

instruct vmul4F_reg_vfp(vecX dst, vecX src1, vecX src2) %{
  predicate(n->as_Vector()->length() == 4 && !VM_Version::simd_math_is_compliant());
  match(Set dst (MulVF src1 src2));
  size(4*4);
  ins_cost(DEFAULT_COST*4); // FIXME

  format %{ "FMULS  $dst.a,$src1.a,$src2.a\n\t"
            "FMULS  $dst.b,$src1.b,$src2.b\n\t"
            "FMULS  $dst.c,$src1.c,$src2.c\n\t"
            "FMULS  $dst.d,$src1.d,$src2.d" %}

  ins_encode %{
    FloatRegister dsta = $dst$$FloatRegister;
    FloatRegister src1a = $src1$$FloatRegister;
    FloatRegister src2a = $src2$$FloatRegister;
    __ mul_float(dsta, src1a, src2a);
    FloatRegister dstb = dsta->successor();
    FloatRegister src1b = src1a->successor();
    FloatRegister src2b = src2a->successor();
    __ mul_float(dstb, src1b, src2b);
    FloatRegister dstc = dstb->successor();
    FloatRegister src1c = src1b->successor();
    FloatRegister src2c = src2b->successor();
    __ mul_float(dstc, src1c, src2c);
    FloatRegister dstd = dstc->successor();
    FloatRegister src1d = src1c->successor();
    FloatRegister src2d = src2c->successor();
    __ mul_float(dstd, src1d, src2d);
  %}

  ins_pipe(fmulF_reg_reg); // FIXME
%}

instruct vmul2D_reg_vfp(vecX dst, vecX src1, vecX src2) %{
  predicate(n->as_Vector()->length() == 2);
  match(Set dst (MulVD src1 src2));
  size(4*2);
  ins_cost(DEFAULT_COST*2); // FIXME

  format %{ "FMULD  $dst.D.a,$src1.D.a,$src2.D.a\n\t"
            "FMULD  $dst.D.b,$src1.D.b,$src2.D.b" %}
  ins_encode %{
    FloatRegister dsta = $dst$$FloatRegister;
    FloatRegister src1a = $src1$$FloatRegister;
    FloatRegister src2a = $src2$$FloatRegister;
    __ mul_double(dsta, src1a, src2a);
    FloatRegister dstb = dsta->successor()->successor();
    FloatRegister src1b = src1a->successor()->successor();
    FloatRegister src2b = src2a->successor()->successor();
    __ mul_double(dstb, src1b, src2b);
  %}

  ins_pipe(fmulD_reg_reg); // FIXME
%}


// Floats vector div
instruct vdiv2F_reg_vfp(vecD dst, vecD src1, vecD src2) %{
  predicate(n->as_Vector()->length() == 2);
  match(Set dst (DivVF src1 src2));
  size(4*2);
  ins_cost(DEFAULT_COST*2); // FIXME

  format %{ "FDIVS  $dst.a,$src1.a,$src2.a\n\t"
            "FDIVS  $dst.b,$src1.b,$src2.b" %}
  ins_encode %{
    __ div_float($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister);
    __ div_float($dst$$FloatRegister->successor(),
             $src1$$FloatRegister->successor(),
             $src2$$FloatRegister->successor());
  %}

  ins_pipe(fdivF_reg_reg); // FIXME
%}

instruct vdiv4F_reg_vfp(vecX dst, vecX src1, vecX src2) %{
  predicate(n->as_Vector()->length() == 4);
  match(Set dst (DivVF src1 src2));
  size(4*4);
  ins_cost(DEFAULT_COST*4); // FIXME

  format %{ "FDIVS  $dst.a,$src1.a,$src2.a\n\t"
            "FDIVS  $dst.b,$src1.b,$src2.b\n\t"
            "FDIVS  $dst.c,$src1.c,$src2.c\n\t"
            "FDIVS  $dst.d,$src1.d,$src2.d" %}

  ins_encode %{
    FloatRegister dsta = $dst$$FloatRegister;
    FloatRegister src1a = $src1$$FloatRegister;
    FloatRegister src2a = $src2$$FloatRegister;
    __ div_float(dsta, src1a, src2a);
    FloatRegister dstb = dsta->successor();
    FloatRegister src1b = src1a->successor();
    FloatRegister src2b = src2a->successor();
    __ div_float(dstb, src1b, src2b);
    FloatRegister dstc = dstb->successor();
    FloatRegister src1c = src1b->successor();
    FloatRegister src2c = src2b->successor();
    __ div_float(dstc, src1c, src2c);
    FloatRegister dstd = dstc->successor();
    FloatRegister src1d = src1c->successor();
    FloatRegister src2d = src2c->successor();
    __ div_float(dstd, src1d, src2d);
  %}

  ins_pipe(fdivF_reg_reg); // FIXME
%}

instruct vdiv2D_reg_vfp(vecX dst, vecX src1, vecX src2) %{
  predicate(n->as_Vector()->length() == 2);
  match(Set dst (DivVD src1 src2));
  size(4*2);
  ins_cost(DEFAULT_COST*2); // FIXME

  format %{ "FDIVD  $dst.D.a,$src1.D.a,$src2.D.a\n\t"
            "FDIVD  $dst.D.b,$src1.D.b,$src2.D.b" %}
  ins_encode %{
    FloatRegister dsta = $dst$$FloatRegister;
    FloatRegister src1a = $src1$$FloatRegister;
    FloatRegister src2a = $src2$$FloatRegister;
    __ div_double(dsta, src1a, src2a);
    FloatRegister dstb = dsta->successor()->successor();
    FloatRegister src1b = src1a->successor()->successor();
    FloatRegister src2b = src2a->successor()->successor();
    __ div_double(dstb, src1b, src2b);
  %}

  ins_pipe(fdivD_reg_reg); // FIXME
%}

// --------------------------------- NEG --------------------------------------

instruct vneg8B_reg(vecD dst, vecD src) %{
  predicate(n->as_Vector()->length_in_bytes() == 8);
  effect(DEF dst, USE src);
  size(4);
  ins_cost(DEFAULT_COST); // FIXME
  format %{ "VNEG.S8 $dst.D,$src.D\t! neg packed8B" %}
  ins_encode %{
    bool quad = false;
    __ vnegI($dst$$FloatRegister, $src$$FloatRegister,
              MacroAssembler::VELEM_SIZE_8, quad);
  %}
  ins_pipe( ialu_reg_reg ); // FIXME
%}

instruct vneg16B_reg(vecX dst, vecX src) %{
  predicate(n->as_Vector()->length_in_bytes() == 16);
  effect(DEF dst, USE src);
  size(4);
  ins_cost(DEFAULT_COST); // FIXME
  format %{ "VNEG.S8 $dst.Q,$src.Q\t! neg0 packed16B" %}
  ins_encode %{
    bool _float = false;
    bool quad = true;
    __ vnegI($dst$$FloatRegister, $src$$FloatRegister,
              MacroAssembler::VELEM_SIZE_8, quad);
  %}
  ins_pipe( ialu_reg_reg ); // FIXME
%}

// ------------------------------ ShiftCount ----------------------------------

instruct vslcntD(vecD dst, iRegI cnt) %{
  predicate(n->as_Vector()->length_in_bytes() == 8 && VM_Version::has_simd());
  match(Set dst (LShiftCntV cnt));
  size(4);
  ins_cost(DEFAULT_COST); // FIXME
  expand %{
    Repl8B_reg_simd(dst, cnt);
  %}
%}

instruct vslcntX(vecX dst, iRegI cnt) %{
  predicate(n->as_Vector()->length_in_bytes() == 16 && VM_Version::has_simd());
  match(Set dst (LShiftCntV cnt));
  size(4);
  ins_cost(DEFAULT_COST); // FIXME
  expand %{
    Repl16B_reg(dst, cnt);
  %}
%}

// Low bits of vector "shift" elements are used, so it
// doesn't matter if we treat it as ints or bytes here.
instruct vsrcntD(vecD dst, iRegI cnt) %{
  predicate(n->as_Vector()->length_in_bytes() == 8 && VM_Version::has_simd());
  match(Set dst (RShiftCntV cnt));
  size(4*2);
  ins_cost(DEFAULT_COST*2); // FIXME

  format %{ "VDUP.8 $dst.D,$cnt\n\t"
            "VNEG.S8 $dst.D,$dst.D\t! neg packed8B" %}
  ins_encode %{
    bool quad = false;
    __ vdupI($dst$$FloatRegister, $cnt$$Register,
             MacroAssembler::VELEM_SIZE_8, quad);
    __ vnegI($dst$$FloatRegister, $dst$$FloatRegister,
              MacroAssembler::VELEM_SIZE_8, quad);
  %}
  ins_pipe( ialu_reg_reg ); // FIXME
%}

instruct vsrcntX(vecX dst, iRegI cnt) %{
  predicate(n->as_Vector()->length_in_bytes() == 16 && VM_Version::has_simd());
  match(Set dst (RShiftCntV cnt));
  size(4*2);
  ins_cost(DEFAULT_COST*2); // FIXME
  format %{ "VDUP.8 $dst.Q,$cnt\n\t"
            "VNEG.S8 $dst.Q,$dst.Q\t! neg packed16B" %}
  ins_encode %{
    bool quad = true;
    __ vdupI($dst$$FloatRegister, $cnt$$Register,
             MacroAssembler::VELEM_SIZE_8, quad);
    __ vnegI($dst$$FloatRegister, $dst$$FloatRegister,
              MacroAssembler::VELEM_SIZE_8, quad);
  %}
  ins_pipe( ialu_reg_reg ); // FIXME
%}

// ------------------------------ LogicalShift --------------------------------

// Byte vector logical left/right shift based on sign
instruct vsh8B_reg(vecD dst, vecD src, vecD shift) %{
  predicate(n->as_Vector()->length() == 8);
  effect(DEF dst, USE src, USE shift);
  size(4);
  ins_cost(DEFAULT_COST); // FIXME
  format %{
    "VSHL.U8 $dst.D,$src.D,$shift.D\t! logical left/right shift packed8B"
  %}
  ins_encode %{
    bool quad = false;
    __ vshlUI($dst$$FloatRegister, $shift$$FloatRegister, $src$$FloatRegister,
              MacroAssembler::VELEM_SIZE_8, quad);
  %}
  ins_pipe( ialu_reg_reg ); // FIXME
%}

instruct vsh16B_reg(vecX dst, vecX src, vecX shift) %{
  predicate(n->as_Vector()->length() == 16);
  effect(DEF dst, USE src, USE shift);
  size(4);
  ins_cost(DEFAULT_COST); // FIXME
  format %{
    "VSHL.U8 $dst.Q,$src.Q,$shift.Q\t! logical left/right shift packed16B"
  %}
  ins_encode %{
    bool quad = true;
    __ vshlUI($dst$$FloatRegister, $shift$$FloatRegister, $src$$FloatRegister,
              MacroAssembler::VELEM_SIZE_8, quad);
  %}
  ins_pipe( ialu_reg_reg ); // FIXME
%}

// Shorts/Char vector logical left/right shift based on sign
instruct vsh4S_reg(vecD dst, vecD src, vecD shift) %{
  predicate(n->as_Vector()->length() == 4);
  effect(DEF dst, USE src, USE shift);
  size(4);
  ins_cost(DEFAULT_COST); // FIXME
  format %{
    "VSHL.U16 $dst.D,$src.D,$shift.D\t! logical left/right shift packed4S"
  %}
  ins_encode %{
    bool quad = false;
    __ vshlUI($dst$$FloatRegister, $shift$$FloatRegister, $src$$FloatRegister,
              MacroAssembler::VELEM_SIZE_16, quad);
  %}
  ins_pipe( ialu_reg_reg ); // FIXME
%}

instruct vsh8S_reg(vecX dst, vecX src, vecX shift) %{
  predicate(n->as_Vector()->length() == 8);
  effect(DEF dst, USE src, USE shift);
  size(4);
  ins_cost(DEFAULT_COST); // FIXME
  format %{
    "VSHL.U16 $dst.Q,$src.Q,$shift.Q\t! logical left/right shift packed8S"
  %}
  ins_encode %{
    bool quad = true;
    __ vshlUI($dst$$FloatRegister, $shift$$FloatRegister, $src$$FloatRegister,
              MacroAssembler::VELEM_SIZE_16, quad);
  %}
  ins_pipe( ialu_reg_reg ); // FIXME
%}

// Integers vector logical left/right shift based on sign
instruct vsh2I_reg(vecD dst, vecD src, vecD shift) %{
  predicate(n->as_Vector()->length() == 2);
  effect(DEF dst, USE src, USE shift);
  size(4);
  ins_cost(DEFAULT_COST); // FIXME
  format %{
    "VSHL.U32 $dst.D,$src.D,$shift.D\t! logical left/right shift packed2I"
  %}
  ins_encode %{
    bool quad = false;
    __ vshlUI($dst$$FloatRegister, $shift$$FloatRegister, $src$$FloatRegister,
              MacroAssembler::VELEM_SIZE_32, quad);
  %}
  ins_pipe( ialu_reg_reg ); // FIXME
%}

instruct vsh4I_reg(vecX dst, vecX src, vecX shift) %{
  predicate(n->as_Vector()->length() == 4);
  effect(DEF dst, USE src, USE shift);
  size(4);
  ins_cost(DEFAULT_COST); // FIXME
  format %{
    "VSHL.U32 $dst.Q,$src.Q,$shift.Q\t! logical left/right shift packed4I"
  %}
  ins_encode %{
    bool quad = true;
    __ vshlUI($dst$$FloatRegister, $shift$$FloatRegister, $src$$FloatRegister,
              MacroAssembler::VELEM_SIZE_32, quad);
  %}
  ins_pipe( ialu_reg_reg ); // FIXME
%}

// Longs vector logical left/right shift based on sign
instruct vsh2L_reg(vecX dst, vecX src, vecX shift) %{
  predicate(n->as_Vector()->length() == 2);
  effect(DEF dst, USE src, USE shift);
  size(4);
  ins_cost(DEFAULT_COST); // FIXME
  format %{
    "VSHL.U64 $dst.Q,$src.Q,$shift.Q\t! logical left/right shift packed2L"
  %}
  ins_encode %{
    bool quad = true;
    __ vshlUI($dst$$FloatRegister, $shift$$FloatRegister, $src$$FloatRegister,
              MacroAssembler::VELEM_SIZE_64, quad);
  %}
  ins_pipe( ialu_reg_reg ); // FIXME
%}

// ------------------------------ LogicalLeftShift ----------------------------

// Byte vector logical left shift
instruct vsl8B_reg(vecD dst, vecD src, vecD shift) %{
  predicate(n->as_Vector()->length() == 8);
  match(Set dst (LShiftVB src shift));
  size(4*1);
  ins_cost(DEFAULT_COST*1); // FIXME
  expand %{
    vsh8B_reg(dst, src, shift);
  %}
%}

instruct vsl16B_reg(vecX dst, vecX src, vecX shift) %{
  predicate(n->as_Vector()->length() == 16);
  match(Set dst (LShiftVB src shift));
  size(4*1);
  ins_cost(DEFAULT_COST*1); // FIXME
  expand %{
    vsh16B_reg(dst, src, shift);
  %}
%}

instruct vsl8B_immI(vecD dst, vecD src, immI shift) %{
  predicate(n->as_Vector()->length() == 8 && assert_not_var_shift(n));
  match(Set dst (LShiftVB src (LShiftCntV shift)));
  size(4);
  ins_cost(DEFAULT_COST); // FIXME
  format %{
    "VSHL.I8 $dst.D,$src.D,$shift\t! logical left shift packed8B"
  %}
  ins_encode %{
    bool quad = false;
    __ vshli($dst$$FloatRegister, $src$$FloatRegister, 8, $shift$$constant,
             quad);
  %}
  ins_pipe( ialu_reg_reg ); // FIXME
%}

instruct vsl16B_immI(vecX dst, vecX src, immI shift) %{
  predicate(n->as_Vector()->length() == 16 && assert_not_var_shift(n));
  match(Set dst (LShiftVB src (LShiftCntV shift)));
  size(4);
  ins_cost(DEFAULT_COST); // FIXME
  format %{
    "VSHL.I8 $dst.Q,$src.Q,$shift\t! logical left shift packed16B"
  %}
  ins_encode %{
    bool quad = true;
    __ vshli($dst$$FloatRegister, $src$$FloatRegister, 8, $shift$$constant,
             quad);
  %}
  ins_pipe( ialu_reg_reg ); // FIXME
%}

// Shorts/Chars vector logical left shift
instruct vsl4S_reg(vecD dst, vecD src, vecD shift) %{
  predicate(n->as_Vector()->length() == 4);
  match(Set dst (LShiftVS src shift));
  size(4*1);
  ins_cost(DEFAULT_COST*1); // FIXME
  expand %{
    vsh4S_reg(dst, src, shift);
  %}
%}

instruct vsl8S_reg(vecX dst, vecX src, vecX shift) %{
  predicate(n->as_Vector()->length() == 8);
  match(Set dst (LShiftVS src shift));
  size(4*1);
  ins_cost(DEFAULT_COST*1); // FIXME
  expand %{
    vsh8S_reg(dst, src, shift);
  %}
%}

instruct vsl4S_immI(vecD dst, vecD src, immI shift) %{
  predicate(n->as_Vector()->length() == 4 && assert_not_var_shift(n));
  match(Set dst (LShiftVS src (LShiftCntV shift)));
  size(4);
  ins_cost(DEFAULT_COST); // FIXME
  format %{
    "VSHL.I16 $dst.D,$src.D,$shift\t! logical left shift packed4S"
  %}
  ins_encode %{
    bool quad = false;
    __ vshli($dst$$FloatRegister, $src$$FloatRegister, 16, $shift$$constant,
             quad);
  %}
  ins_pipe( ialu_reg_reg ); // FIXME
%}

instruct vsl8S_immI(vecX dst, vecX src, immI shift) %{
  predicate(n->as_Vector()->length() == 8 && assert_not_var_shift(n));
  match(Set dst (LShiftVS src shift));
  size(4);
  ins_cost(DEFAULT_COST); // FIXME
  format %{
    "VSHL.I16 $dst.Q,$src.Q,$shift\t! logical left shift packed8S"
  %}
  ins_encode %{
    bool quad = true;
    __ vshli($dst$$FloatRegister, $src$$FloatRegister, 16, $shift$$constant,
             quad);
  %}
  ins_pipe( ialu_reg_reg ); // FIXME
%}

// Integers vector logical left shift
instruct vsl2I_reg(vecD dst, vecD src, vecD shift) %{
  predicate(n->as_Vector()->length() == 2 && VM_Version::has_simd());
  match(Set dst (LShiftVI src shift));
  size(4*1);
  ins_cost(DEFAULT_COST*1); // FIXME
  expand %{
    vsh2I_reg(dst, src, shift);
  %}
%}

instruct vsl4I_reg(vecX dst, vecX src, vecX shift) %{
  predicate(n->as_Vector()->length() == 4 && VM_Version::has_simd());
  match(Set dst (LShiftVI src shift));
  size(4*1);
  ins_cost(DEFAULT_COST*1); // FIXME
  expand %{
    vsh4I_reg(dst, src, shift);
  %}
%}

instruct vsl2I_immI(vecD dst, vecD src, immI shift) %{
  predicate(n->as_Vector()->length() == 2 &&
            VM_Version::has_simd() &&
            assert_not_var_shift(n));
  match(Set dst (LShiftVI src (LShiftCntV shift)));
  size(4);
  ins_cost(DEFAULT_COST); // FIXME
  format %{
    "VSHL.I32 $dst.D,$src.D,$shift\t! logical left shift packed2I"
  %}
  ins_encode %{
    bool quad = false;
    __ vshli($dst$$FloatRegister, $src$$FloatRegister, 32, $shift$$constant,
             quad);
  %}
  ins_pipe( ialu_reg_reg ); // FIXME
%}

instruct vsl4I_immI(vecX dst, vecX src, immI shift) %{
  predicate(n->as_Vector()->length() == 4 &&
            VM_Version::has_simd() &&
            assert_not_var_shift(n));
  match(Set dst (LShiftVI src (LShiftCntV shift)));
  size(4);
  ins_cost(DEFAULT_COST); // FIXME
  format %{
    "VSHL.I32 $dst.Q,$src.Q,$shift\t! logical left shift packed4I"
  %}
  ins_encode %{
    bool quad = true;
    __ vshli($dst$$FloatRegister, $src$$FloatRegister, 32, $shift$$constant,
             quad);
  %}
  ins_pipe( ialu_reg_reg ); // FIXME
%}

// Longs vector logical left shift
instruct vsl2L_reg(vecX dst, vecX src, vecX shift) %{
  predicate(n->as_Vector()->length() == 2);
  match(Set dst (LShiftVL src shift));
  size(4*1);
  ins_cost(DEFAULT_COST*1); // FIXME
  expand %{
    vsh2L_reg(dst, src, shift);
  %}
%}

instruct vsl2L_immI(vecX dst, vecX src, immI shift) %{
  predicate(n->as_Vector()->length() == 2 && assert_not_var_shift(n));
  match(Set dst (LShiftVL src (LShiftCntV shift)));
  size(4);
  ins_cost(DEFAULT_COST); // FIXME
  format %{
    "VSHL.I64 $dst.Q,$src.Q,$shift\t! logical left shift packed2L"
  %}
  ins_encode %{
    bool quad = true;
    __ vshli($dst$$FloatRegister, $src$$FloatRegister, 64, $shift$$constant,
             quad);
  %}
  ins_pipe( ialu_reg_reg ); // FIXME
%}

// ----------------------- LogicalRightShift -----------------------------------

// Bytes/Shorts vector logical right shift produces incorrect Java result
// for negative data because java code convert short value into int with
// sign extension before a shift.

// Right shift with vector shift count on aarch32 SIMD is implemented as left
// shift by negative shift count value.
//
// Method is_var_shift() denotes that vector shift count is a variable shift:
// 1) for this case, vector shift count should be negated before conducting
//    right shifts. E.g., vsrl4S_reg_var rule.
// 2) for the opposite case, vector shift count is generated via RShiftCntV
//    rules and is already negated there. Hence, no negation is needed.
//    E.g., vsrl4S_reg rule.

// Chars vector logical right shift
instruct vsrl4S_reg(vecD dst, vecD src, vecD shift) %{
  predicate(n->as_Vector()->length() == 4 && !n->as_ShiftV()->is_var_shift());
  match(Set dst (URShiftVS src shift));
  size(4);
  ins_cost(DEFAULT_COST);
  expand %{
    vsh4S_reg(dst, src, shift);
  %}
%}

instruct vsrl4S_reg_var(vecD dst, vecD src, vecD shift, vecD tmp) %{
  predicate(n->as_Vector()->length() == 4 && n->as_ShiftV()->is_var_shift());
  match(Set dst (URShiftVS src shift));
  effect(TEMP tmp);
  size(4*2);
  ins_cost(DEFAULT_COST*2);
  format %{
    "VNEG.S8 $tmp.D,$shift.D\n\t! neg packed8B"
    "VSHL.U16 $dst.D,$src.D,$tmp.D\t! logical right shift packed4S"
  %}
  ins_encode %{
    bool quad = false;
    __ vnegI($tmp$$FloatRegister, $shift$$FloatRegister,
             MacroAssembler::VELEM_SIZE_8, quad);
    __ vshlUI($dst$$FloatRegister, $tmp$$FloatRegister, $src$$FloatRegister,
              MacroAssembler::VELEM_SIZE_16, quad);
  %}
  ins_pipe(ialu_reg_reg);
%}

instruct vsrl8S_reg(vecX dst, vecX src, vecX shift) %{
  predicate(n->as_Vector()->length() == 8 && !n->as_ShiftV()->is_var_shift());
  match(Set dst (URShiftVS src shift));
  size(4);
  ins_cost(DEFAULT_COST);
  expand %{
    vsh8S_reg(dst, src, shift);
  %}
%}

instruct vsrl8S_reg_var(vecX dst, vecX src, vecX shift, vecX tmp) %{
  predicate(n->as_Vector()->length() == 8 && n->as_ShiftV()->is_var_shift());
  match(Set dst (URShiftVS src shift));
  effect(TEMP tmp);
  size(4*2);
  ins_cost(DEFAULT_COST*2);
  format %{
    "VNEG.S8 $tmp.Q,$shift.Q\n\t! neg packed16B"
    "VSHL.U16 $dst.Q,$src.Q,$tmp.Q\t! logical right shift packed8S"
  %}
  ins_encode %{
    bool quad = true;
    __ vnegI($tmp$$FloatRegister, $shift$$FloatRegister,
             MacroAssembler::VELEM_SIZE_8, quad);
    __ vshlUI($dst$$FloatRegister, $tmp$$FloatRegister, $src$$FloatRegister,
              MacroAssembler::VELEM_SIZE_16, quad);
  %}
  ins_pipe(ialu_reg_reg);
%}

instruct vsrl4S_immI(vecD dst, vecD src, immI shift) %{
  predicate(n->as_Vector()->length() == 4 && assert_not_var_shift(n));
  match(Set dst (URShiftVS src (RShiftCntV shift)));
  size(4);
  ins_cost(DEFAULT_COST); // FIXME
  format %{
    "VSHR.U16 $dst.D,$src.D,$shift\t! logical right shift packed4S"
  %}
  ins_encode %{
    bool quad = false;
    __ vshrUI($dst$$FloatRegister, $src$$FloatRegister, 16, $shift$$constant,
             quad);
  %}
  ins_pipe( ialu_reg_reg ); // FIXME
%}

instruct vsrl8S_immI(vecX dst, vecX src, immI shift) %{
  predicate(n->as_Vector()->length() == 8 && assert_not_var_shift(n));
  match(Set dst (URShiftVS src (RShiftCntV shift)));
  size(4);
  ins_cost(DEFAULT_COST); // FIXME
  format %{
    "VSHR.U16 $dst.Q,$src.Q,$shift\t! logical right shift packed8S"
  %}
  ins_encode %{
    bool quad = true;
    __ vshrUI($dst$$FloatRegister, $src$$FloatRegister, 16, $shift$$constant,
             quad);
  %}
  ins_pipe( ialu_reg_reg ); // FIXME
%}

// Integers vector logical right shift
instruct vsrl2I_reg(vecD dst, vecD src, vecD shift) %{
  predicate(n->as_Vector()->length() == 2 &&
            VM_Version::has_simd() &&
            !n->as_ShiftV()->is_var_shift());
  match(Set dst (URShiftVI src shift));
  size(4);
  ins_cost(DEFAULT_COST);
  expand %{
    vsh2I_reg(dst, src, shift);
  %}
%}

instruct vsrl2I_reg_var(vecD dst, vecD src, vecD shift, vecD tmp) %{
  predicate(n->as_Vector()->length() == 2 &&
            VM_Version::has_simd() &&
            n->as_ShiftV()->is_var_shift());
  match(Set dst (URShiftVI src shift));
  effect(TEMP tmp);
  size(4*2);
  ins_cost(DEFAULT_COST*2);
  format %{
    "VNEG.S8 $tmp.D,$shift.D\n\t! neg packed8B"
    "VSHL.U32 $dst.D,$src.D,$tmp.D\t! logical right shift packed2I"
  %}
  ins_encode %{
    bool quad = false;
    __ vnegI($tmp$$FloatRegister, $shift$$FloatRegister,
             MacroAssembler::VELEM_SIZE_8, quad);
    __ vshlUI($dst$$FloatRegister, $tmp$$FloatRegister, $src$$FloatRegister,
              MacroAssembler::VELEM_SIZE_32, quad);
  %}
  ins_pipe(ialu_reg_reg);
%}

instruct vsrl4I_reg(vecX dst, vecX src, vecX shift) %{
  predicate(n->as_Vector()->length() == 4 &&
            VM_Version::has_simd() &&
            !n->as_ShiftV()->is_var_shift());
  match(Set dst (URShiftVI src shift));
  size(4);
  ins_cost(DEFAULT_COST);
  expand %{
    vsh4I_reg(dst, src, shift);
  %}
%}

instruct vsrl4I_reg_var(vecX dst, vecX src, vecX shift, vecX tmp) %{
  predicate(n->as_Vector()->length() == 4 &&
            VM_Version::has_simd() &&
            n->as_ShiftV()->is_var_shift());
  match(Set dst (URShiftVI src shift));
  effect(TEMP tmp);
  size(4*2);
  ins_cost(DEFAULT_COST*2);
  format %{
    "VNEG.S8 $tmp.Q,$shift.Q\n\t! neg packed16B"
    "VSHL.U32 $dst.Q,$src.Q,$tmp.Q\t! logical right shift packed4I"
  %}
  ins_encode %{
    bool quad = true;
    __ vnegI($tmp$$FloatRegister, $shift$$FloatRegister,
             MacroAssembler::VELEM_SIZE_8, quad);
    __ vshlUI($dst$$FloatRegister, $tmp$$FloatRegister, $src$$FloatRegister,
              MacroAssembler::VELEM_SIZE_32, quad);
  %}
  ins_pipe(ialu_reg_reg);
%}

instruct vsrl2I_immI(vecD dst, vecD src, immI shift) %{
  predicate(n->as_Vector()->length() == 2 &&
            VM_Version::has_simd() &&
            assert_not_var_shift(n));
  match(Set dst (URShiftVI src (RShiftCntV shift)));
  size(4);
  ins_cost(DEFAULT_COST); // FIXME
  format %{
    "VSHR.U32 $dst.D,$src.D,$shift\t! logical right shift packed2I"
  %}
  ins_encode %{
    bool quad = false;
    __ vshrUI($dst$$FloatRegister, $src$$FloatRegister, 32, $shift$$constant,
             quad);
  %}
  ins_pipe( ialu_reg_reg ); // FIXME
%}

instruct vsrl4I_immI(vecX dst, vecX src, immI shift) %{
  predicate(n->as_Vector()->length() == 4 &&
            VM_Version::has_simd() &&
            assert_not_var_shift(n));
  match(Set dst (URShiftVI src (RShiftCntV shift)));
  size(4);
  ins_cost(DEFAULT_COST); // FIXME
  format %{
    "VSHR.U32 $dst.Q,$src.Q,$shift\t! logical right shift packed4I"
  %}
  ins_encode %{
    bool quad = true;
    __ vshrUI($dst$$FloatRegister, $src$$FloatRegister, 32, $shift$$constant,
             quad);
  %}
  ins_pipe( ialu_reg_reg ); // FIXME
%}

// Longs vector logical right shift
instruct vsrl2L_reg(vecX dst, vecX src, vecX shift) %{
  predicate(n->as_Vector()->length() == 2 && !n->as_ShiftV()->is_var_shift());
  match(Set dst (URShiftVL src shift));
  size(4);
  ins_cost(DEFAULT_COST);
  expand %{
    vsh2L_reg(dst, src, shift);
  %}
%}

instruct vsrl2L_reg_var(vecX dst, vecX src, vecX shift, vecX tmp) %{
  predicate(n->as_Vector()->length() == 2 && n->as_ShiftV()->is_var_shift());
  match(Set dst (URShiftVL src shift));
  effect(TEMP tmp, DEF dst, USE src, USE shift);
  size(4*2);
  ins_cost(DEFAULT_COST*2);
  format %{
    "VNEG.S8 $tmp.Q,$shift.Q\n\t! neg packed16B"
    "VSHL.U64 $dst.Q,$src.Q,$tmp.Q\t! logical right shift packed2L"
  %}
  ins_encode %{
    bool quad = true;
    __ vnegI($tmp$$FloatRegister, $shift$$FloatRegister,
             MacroAssembler::VELEM_SIZE_8, quad);
    __ vshlUI($dst$$FloatRegister, $tmp$$FloatRegister, $src$$FloatRegister,
              MacroAssembler::VELEM_SIZE_64, quad);
  %}
  ins_pipe(ialu_reg_reg);
%}

instruct vsrl2L_immI(vecX dst, vecX src, immI shift) %{
  predicate(n->as_Vector()->length() == 2 && assert_not_var_shift(n));
  match(Set dst (URShiftVL src (RShiftCntV shift)));
  size(4);
  ins_cost(DEFAULT_COST); // FIXME
  format %{
    "VSHR.U64 $dst.Q,$src.Q,$shift\t! logical right shift packed2L"
  %}
  ins_encode %{
    bool quad = true;
    __ vshrUI($dst$$FloatRegister, $src$$FloatRegister, 64, $shift$$constant,
             quad);
  %}
  ins_pipe( ialu_reg_reg ); // FIXME
%}

// ------------------- ArithmeticRightShift -----------------------------------

// Bytes vector arithmetic left/right shift based on sign
instruct vsha8B_reg(vecD dst, vecD src, vecD shift) %{
  predicate(n->as_Vector()->length() == 8);
  effect(DEF dst, USE src, USE shift);
  size(4);
  ins_cost(DEFAULT_COST); // FIXME
  format %{
    "VSHL.S8 $dst.D,$src.D,$shift.D\t! arithmetic right shift packed8B"
  %}
  ins_encode %{
    bool quad = false;
    __ vshlSI($dst$$FloatRegister, $shift$$FloatRegister, $src$$FloatRegister,
              MacroAssembler::VELEM_SIZE_8, quad);
  %}
  ins_pipe( ialu_reg_reg ); // FIXME
%}

instruct vsha16B_reg(vecX dst, vecX src, vecX shift) %{
  predicate(n->as_Vector()->length() == 16);
  effect(DEF dst, USE src, USE shift);
  size(4);
  ins_cost(DEFAULT_COST); // FIXME
  format %{
    "VSHL.S8 $dst.Q,$src.Q,$shift.Q\t! arithmetic right shift packed16B"
  %}
  ins_encode %{
    bool quad = true;
    __ vshlSI($dst$$FloatRegister, $shift$$FloatRegister, $src$$FloatRegister,
              MacroAssembler::VELEM_SIZE_8, quad);
  %}
  ins_pipe( ialu_reg_reg ); // FIXME
%}

// Shorts vector arithmetic left/right shift based on sign
instruct vsha4S_reg(vecD dst, vecD src, vecD shift) %{
  predicate(n->as_Vector()->length() == 4);
  effect(DEF dst, USE src, USE shift);
  size(4);
  ins_cost(DEFAULT_COST); // FIXME
  format %{
    "VSHL.S16 $dst.D,$src.D,$shift.D\t! arithmetic right shift packed4S"
  %}
  ins_encode %{
    bool quad = false;
    __ vshlSI($dst$$FloatRegister, $shift$$FloatRegister, $src$$FloatRegister,
              MacroAssembler::VELEM_SIZE_16, quad);
  %}
  ins_pipe( ialu_reg_reg ); // FIXME
%}

instruct vsha8S_reg(vecX dst, vecX src, vecX shift) %{
  predicate(n->as_Vector()->length() == 8);
  effect(DEF dst, USE src, USE shift);
  size(4);
  ins_cost(DEFAULT_COST); // FIXME
  format %{
    "VSHL.S16 $dst.Q,$src.Q,$shift.Q\t! arithmetic right shift packed8S"
  %}
  ins_encode %{
    bool quad = true;
    __ vshlSI($dst$$FloatRegister, $shift$$FloatRegister, $src$$FloatRegister,
              MacroAssembler::VELEM_SIZE_16, quad);
  %}
  ins_pipe( ialu_reg_reg ); // FIXME
%}

// Integers vector arithmetic left/right shift based on sign
instruct vsha2I_reg(vecD dst, vecD src, vecD shift) %{
  predicate(n->as_Vector()->length() == 2);
  effect(DEF dst, USE src, USE shift);
  size(4);
  ins_cost(DEFAULT_COST); // FIXME
  format %{
    "VSHL.S32 $dst.D,$src.D,$shift.D\t! arithmetic right shift packed2I"
  %}
  ins_encode %{
    bool quad = false;
    __ vshlSI($dst$$FloatRegister, $shift$$FloatRegister, $src$$FloatRegister,
              MacroAssembler::VELEM_SIZE_32, quad);
  %}
  ins_pipe( ialu_reg_reg ); // FIXME
%}

instruct vsha4I_reg(vecX dst, vecX src, vecX shift) %{
  predicate(n->as_Vector()->length() == 4);
  effect(DEF dst, USE src, USE shift);
  size(4);
  ins_cost(DEFAULT_COST); // FIXME
  format %{
    "VSHL.S32 $dst.Q,$src.Q,$shift.Q\t! arithmetic right shift packed4I"
  %}
  ins_encode %{
    bool quad = true;
    __ vshlSI($dst$$FloatRegister, $shift$$FloatRegister, $src$$FloatRegister,
              MacroAssembler::VELEM_SIZE_32, quad);
  %}
  ins_pipe( ialu_reg_reg ); // FIXME
%}

// Longs vector arithmetic left/right shift based on sign
instruct vsha2L_reg(vecX dst, vecX src, vecX shift) %{
  predicate(n->as_Vector()->length() == 2);
  effect(DEF dst, USE src, USE shift);
  size(4);
  ins_cost(DEFAULT_COST); // FIXME
  format %{
    "VSHL.S64 $dst.Q,$src.Q,$shift.Q\t! arithmetic right shift packed2L"
  %}
  ins_encode %{
    bool quad = true;
    __ vshlSI($dst$$FloatRegister, $shift$$FloatRegister, $src$$FloatRegister,
              MacroAssembler::VELEM_SIZE_64, quad);
  %}
  ins_pipe( ialu_reg_reg ); // FIXME
%}

// Byte vector arithmetic right shift
instruct vsra8B_reg(vecD dst, vecD src, vecD shift) %{
  predicate(n->as_Vector()->length() == 8 && !n->as_ShiftV()->is_var_shift());
  match(Set dst (RShiftVB src shift));
  size(4);
  ins_cost(DEFAULT_COST); // FIXME
  expand %{
    vsha8B_reg(dst, src, shift);
  %}
%}

instruct vsra8B_reg_var(vecD dst, vecD src, vecD shift, vecD tmp) %{
  predicate(n->as_Vector()->length() == 8 && n->as_ShiftV()->is_var_shift());
  match(Set dst (RShiftVB src shift));
  effect(TEMP tmp);
  size(4*2);
  ins_cost(DEFAULT_COST*2);
  format %{
    "VNEG.S8 $tmp.D,$shift.D\n\t! neg packed8B"
    "VSHL.S8 $dst.D,$src.D,$tmp.D\t! arithmetic right shift packed8B"
  %}
  ins_encode %{
    bool quad = false;
    __ vnegI($tmp$$FloatRegister, $shift$$FloatRegister,
             MacroAssembler::VELEM_SIZE_8, quad);
    __ vshlSI($dst$$FloatRegister, $tmp$$FloatRegister, $src$$FloatRegister,
              MacroAssembler::VELEM_SIZE_8, quad);
  %}
  ins_pipe(ialu_reg_reg);
%}

instruct vsra16B_reg(vecX dst, vecX src, vecX shift) %{
  predicate(n->as_Vector()->length() == 16 && !n->as_ShiftV()->is_var_shift());
  match(Set dst (RShiftVB src shift));
  size(4);
  ins_cost(DEFAULT_COST); // FIXME
  expand %{
    vsha16B_reg(dst, src, shift);
  %}
%}

instruct vsra16B_reg_var(vecX dst, vecX src, vecX shift, vecX tmp) %{
  predicate(n->as_Vector()->length() == 16 && n->as_ShiftV()->is_var_shift());
  match(Set dst (RShiftVB src shift));
  effect(TEMP tmp);
  size(4*2);
  ins_cost(DEFAULT_COST*2);
  format %{
    "VNEG.S8 $tmp.Q,$shift.Q\n\t! neg packed16B"
    "VSHL.S8 $dst.Q,$src.Q,$tmp.Q\t! arithmetic right shift packed16B"
  %}
  ins_encode %{
    bool quad = true;
    __ vnegI($tmp$$FloatRegister, $shift$$FloatRegister,
             MacroAssembler::VELEM_SIZE_8, quad);
    __ vshlSI($dst$$FloatRegister, $tmp$$FloatRegister, $src$$FloatRegister,
              MacroAssembler::VELEM_SIZE_8, quad);
  %}
  ins_pipe(ialu_reg_reg);
%}

instruct vsra8B_immI(vecD dst, vecD src, immI shift) %{
  predicate(n->as_Vector()->length() == 8 && assert_not_var_shift(n));
  match(Set dst (RShiftVB src (RShiftCntV shift)));
  size(4);
  ins_cost(DEFAULT_COST); // FIXME
  format %{
    "VSHR.S8 $dst.D,$src.D,$shift\t! arithmetic right shift packed8B"
  %}
  ins_encode %{
    bool quad = false;
    __ vshrSI($dst$$FloatRegister, $src$$FloatRegister, 8, $shift$$constant,
             quad);
  %}
  ins_pipe( ialu_reg_reg ); // FIXME
%}

instruct vsra16B_immI(vecX dst, vecX src, immI shift) %{
  predicate(n->as_Vector()->length() == 16 && assert_not_var_shift(n));
  match(Set dst (RShiftVB src (RShiftCntV shift)));
  size(4);
  ins_cost(DEFAULT_COST); // FIXME
  format %{
    "VSHR.S8 $dst.Q,$src.Q,$shift\t! arithmetic right shift packed16B"
  %}
  ins_encode %{
    bool quad = true;
    __ vshrSI($dst$$FloatRegister, $src$$FloatRegister, 8, $shift$$constant,
             quad);
  %}
  ins_pipe( ialu_reg_reg ); // FIXME
%}

// Shorts vector arithmetic right shift
instruct vsra4S_reg(vecD dst, vecD src, vecD shift) %{
  predicate(n->as_Vector()->length() == 4 && !n->as_ShiftV()->is_var_shift());
  match(Set dst (RShiftVS src shift));
  size(4);
  ins_cost(DEFAULT_COST); // FIXME
  expand %{
    vsha4S_reg(dst, src, shift);
  %}
%}

instruct vsra4S_reg_var(vecD dst, vecD src, vecD shift, vecD tmp) %{
  predicate(n->as_Vector()->length() == 4 && n->as_ShiftV()->is_var_shift());
  match(Set dst (RShiftVS src shift));
  effect(TEMP tmp);
  size(4*2);
  ins_cost(DEFAULT_COST*2);
  format %{
    "VNEG.S8 $tmp.D,$shift.D\n\t! neg packed8B"
    "VSHL.S16 $dst.D,$src.D,$tmp.D\t! arithmetic right shift packed4S"
  %}
  ins_encode %{
    bool quad = false;
    __ vnegI($tmp$$FloatRegister, $shift$$FloatRegister,
             MacroAssembler::VELEM_SIZE_8, quad);
    __ vshlSI($dst$$FloatRegister, $tmp$$FloatRegister, $src$$FloatRegister,
              MacroAssembler::VELEM_SIZE_16, quad);
  %}
  ins_pipe(ialu_reg_reg);
%}

instruct vsra8S_reg(vecX dst, vecX src, vecX shift) %{
  predicate(n->as_Vector()->length() == 8 && !n->as_ShiftV()->is_var_shift());
  match(Set dst (RShiftVS src shift));
  size(4);
  ins_cost(DEFAULT_COST); // FIXME
  expand %{
    vsha8S_reg(dst, src, shift);
  %}
%}

instruct vsra8S_reg_var(vecX dst, vecX src, vecX shift, vecX tmp) %{
  predicate(n->as_Vector()->length() == 8 && n->as_ShiftV()->is_var_shift());
  match(Set dst (RShiftVS src shift));
  effect(TEMP tmp);
  size(4*2);
  ins_cost(DEFAULT_COST*2);
  format %{
    "VNEG.S8 $tmp.Q,$shift.Q\n\t! neg packed16B"
    "VSHL.S16 $dst.Q,$src.Q,$tmp.Q\t! arithmetic right shift packed8S"
  %}
  ins_encode %{
    bool quad = true;
    __ vnegI($tmp$$FloatRegister, $shift$$FloatRegister,
             MacroAssembler::VELEM_SIZE_8, quad);
    __ vshlSI($dst$$FloatRegister, $tmp$$FloatRegister, $src$$FloatRegister,
              MacroAssembler::VELEM_SIZE_16, quad);
  %}
  ins_pipe(ialu_reg_reg);
%}

instruct vsra4S_immI(vecD dst, vecD src, immI shift) %{
  predicate(n->as_Vector()->length() == 4 && assert_not_var_shift(n));
  match(Set dst (RShiftVS src (RShiftCntV shift)));
  size(4);
  ins_cost(DEFAULT_COST); // FIXME
  format %{
    "VSHR.S16 $dst.D,$src.D,$shift\t! arithmetic right shift packed4S"
  %}
  ins_encode %{
    bool quad = false;
    __ vshrSI($dst$$FloatRegister, $src$$FloatRegister, 16, $shift$$constant,
             quad);
  %}
  ins_pipe( ialu_reg_reg ); // FIXME
%}

instruct vsra8S_immI(vecX dst, vecX src, immI shift) %{
  predicate(n->as_Vector()->length() == 8 && assert_not_var_shift(n));
  match(Set dst (RShiftVS src (RShiftCntV shift)));
  size(4);
  ins_cost(DEFAULT_COST); // FIXME
  format %{
    "VSHR.S16 $dst.Q,$src.Q,$shift\t! arithmetic right shift packed8S"
  %}
  ins_encode %{
    bool quad = true;
    __ vshrSI($dst$$FloatRegister, $src$$FloatRegister, 16, $shift$$constant,
             quad);
  %}
  ins_pipe( ialu_reg_reg ); // FIXME
%}

// Integers vector arithmetic right shift
instruct vsra2I_reg(vecD dst, vecD src, vecD shift) %{
  predicate(n->as_Vector()->length() == 2 && !n->as_ShiftV()->is_var_shift());
  match(Set dst (RShiftVI src shift));
  size(4);
  ins_cost(DEFAULT_COST); // FIXME
  expand %{
    vsha2I_reg(dst, src, shift);
  %}
%}

instruct vsra2I_reg_var(vecD dst, vecD src, vecD shift, vecD tmp) %{
  predicate(n->as_Vector()->length() == 2 && n->as_ShiftV()->is_var_shift());
  match(Set dst (RShiftVI src shift));
  effect(TEMP tmp);
  size(4*2);
  ins_cost(DEFAULT_COST*2);
  format %{
    "VNEG.S8 $tmp.D,$shift.D\n\t! neg packed8B"
    "VSHL.S32 $dst.D,$src.D,$tmp.D\t! arithmetic right shift packed2I"
  %}
  ins_encode %{
    bool quad = false;
    __ vnegI($tmp$$FloatRegister, $shift$$FloatRegister,
             MacroAssembler::VELEM_SIZE_8, quad);
    __ vshlSI($dst$$FloatRegister, $tmp$$FloatRegister, $src$$FloatRegister,
              MacroAssembler::VELEM_SIZE_32, quad);
  %}
  ins_pipe(ialu_reg_reg);
%}

instruct vsra4I_reg(vecX dst, vecX src, vecX shift) %{
  predicate(n->as_Vector()->length() == 4 && !n->as_ShiftV()->is_var_shift());
  match(Set dst (RShiftVI src shift));
  size(4);
  ins_cost(DEFAULT_COST); // FIXME
  expand %{
    vsha4I_reg(dst, src, shift);
  %}
%}

instruct vsra4I_reg_var(vecX dst, vecX src, vecX shift, vecX tmp) %{
  predicate(n->as_Vector()->length() == 4 && n->as_ShiftV()->is_var_shift());
  match(Set dst (RShiftVI src shift));
  effect(TEMP tmp);
  size(4*2);
  ins_cost(DEFAULT_COST*2);
  format %{
    "VNEG.S8 $tmp.Q,$shift.Q\n\t! neg packed16B"
    "VSHL.S32 $dst.Q,$src.Q,$tmp.Q\t! arithmetic right shift packed4I"
  %}
  ins_encode %{
    bool quad = true;
    __ vnegI($tmp$$FloatRegister, $shift$$FloatRegister,
             MacroAssembler::VELEM_SIZE_8, quad);
    __ vshlSI($dst$$FloatRegister, $tmp$$FloatRegister, $src$$FloatRegister,
              MacroAssembler::VELEM_SIZE_32, quad);
  %}
  ins_pipe(ialu_reg_reg);
%}

instruct vsra2I_immI(vecD dst, vecD src, immI shift) %{
  predicate(n->as_Vector()->length() == 2 && assert_not_var_shift(n));
  match(Set dst (RShiftVI src (RShiftCntV shift)));
  size(4);
  ins_cost(DEFAULT_COST); // FIXME
  format %{
    "VSHR.S32 $dst.D,$src.D,$shift\t! arithmetic right shift packed2I"
  %}
  ins_encode %{
    bool quad = false;
    __ vshrSI($dst$$FloatRegister, $src$$FloatRegister, 32, $shift$$constant,
             quad);
  %}
  ins_pipe( ialu_reg_reg ); // FIXME
%}

instruct vsra4I_immI(vecX dst, vecX src, immI shift) %{
  predicate(n->as_Vector()->length() == 4 && assert_not_var_shift(n));
  match(Set dst (RShiftVI src (RShiftCntV shift)));
  size(4);
  ins_cost(DEFAULT_COST); // FIXME
  format %{
    "VSHR.S32 $dst.Q,$src.Q,$shift\t! arithmetic right shift packed4I"
  %}
  ins_encode %{
    bool quad = true;
    __ vshrSI($dst$$FloatRegister, $src$$FloatRegister, 32, $shift$$constant,
             quad);
  %}
  ins_pipe( ialu_reg_reg ); // FIXME
%}

// Longs vector arithmetic right shift
instruct vsra2L_reg(vecX dst, vecX src, vecX shift) %{
  predicate(n->as_Vector()->length() == 2 && !n->as_ShiftV()->is_var_shift());
  match(Set dst (RShiftVL src shift));
  size(4);
  ins_cost(DEFAULT_COST); // FIXME
  expand %{
    vsha2L_reg(dst, src, shift);
  %}
%}

instruct vsra2L_reg_var(vecX dst, vecX src, vecX shift, vecX tmp) %{
  predicate(n->as_Vector()->length() == 2 && n->as_ShiftV()->is_var_shift());
  match(Set dst (RShiftVL src shift));
  effect(TEMP tmp);
  size(4*2);
  ins_cost(DEFAULT_COST*2);
  format %{
    "VNEG.S8 $tmp.Q,$shift.Q\n\t! neg packed16B"
    "VSHL.S64 $dst.Q,$src.Q,$tmp.Q\t! arithmetic right shift packed2L"
  %}
  ins_encode %{
    bool quad = true;
    __ vnegI($tmp$$FloatRegister, $shift$$FloatRegister,
             MacroAssembler::VELEM_SIZE_8, quad);
    __ vshlSI($dst$$FloatRegister, $tmp$$FloatRegister, $src$$FloatRegister,
              MacroAssembler::VELEM_SIZE_64, quad);
  %}
  ins_pipe(ialu_reg_reg);
%}

instruct vsra2L_immI(vecX dst, vecX src, immI shift) %{
  predicate(n->as_Vector()->length() == 2 && assert_not_var_shift(n));
  match(Set dst (RShiftVL src (RShiftCntV shift)));
  size(4);
  ins_cost(DEFAULT_COST); // FIXME
  format %{
    "VSHR.S64 $dst.Q,$src.Q,$shift\t! arithmetic right shift packed2L"
  %}
  ins_encode %{
    bool quad = true;
    __ vshrSI($dst$$FloatRegister, $src$$FloatRegister, 64, $shift$$constant,
             quad);
  %}
  ins_pipe( ialu_reg_reg ); // FIXME
%}

// --------------------------------- AND --------------------------------------

instruct vandD(vecD dst, vecD src1, vecD src2) %{
  predicate(n->as_Vector()->length_in_bytes() == 8);
  match(Set dst (AndV src1 src2));
  format %{ "VAND    $dst.D,$src1.D,$src2.D\t! and vectors (8 bytes)" %}
  ins_encode %{
    bool quad = false;
    __ vandI($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
             quad);
  %}
  ins_pipe( ialu_reg_reg ); // FIXME
%}

instruct vandX(vecX dst, vecX src1, vecX src2) %{
  predicate(n->as_Vector()->length_in_bytes() == 16);
  match(Set dst (AndV src1 src2));
  format %{ "VAND    $dst.Q,$src1.Q,$src2.Q\t! and vectors (16 bytes)" %}
  ins_encode %{
    bool quad = true;
    __ vandI($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
             quad);
  %}
  ins_pipe( ialu_reg_reg ); // FIXME
%}

// --------------------------------- OR ---------------------------------------

instruct vorD(vecD dst, vecD src1, vecD src2) %{
  predicate(n->as_Vector()->length_in_bytes() == 8);
  match(Set dst (OrV src1 src2));
  format %{ "VOR     $dst.D,$src1.D,$src2.D\t! and vectors (8 bytes)" %}
  ins_encode %{
    bool quad = false;
    __ vorI($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
            quad);
  %}
  ins_pipe( ialu_reg_reg ); // FIXME
%}

instruct vorX(vecX dst, vecX src1, vecX src2) %{
  predicate(n->as_Vector()->length_in_bytes() == 16);
  match(Set dst (OrV src1 src2));
  format %{ "VOR     $dst.Q,$src1.Q,$src2.Q\t! and vectors (16 bytes)" %}
  ins_encode %{
    bool quad = true;
    __ vorI($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
            quad);
  %}
  ins_pipe( ialu_reg_reg ); // FIXME
%}

// --------------------------------- XOR --------------------------------------

instruct vxorD(vecD dst, vecD src1, vecD src2) %{
  predicate(n->as_Vector()->length_in_bytes() == 8);
  match(Set dst (XorV src1 src2));
  format %{ "VXOR    $dst.D,$src1.D,$src2.D\t! and vectors (8 bytes)" %}
  ins_encode %{
    bool quad = false;
    __ vxorI($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
             quad);
  %}
  ins_pipe( ialu_reg_reg ); // FIXME
%}

instruct vxorX(vecX dst, vecX src1, vecX src2) %{
  predicate(n->as_Vector()->length_in_bytes() == 16);
  match(Set dst (XorV src1 src2));
  format %{ "VXOR    $dst.Q,$src1.Q,$src2.Q\t! and vectors (16 bytes)" %}
  ins_encode %{
    bool quad = true;
    __ vxorI($dst$$FloatRegister, $src1$$FloatRegister, $src2$$FloatRegister,
             quad);
  %}
  ins_pipe( ialu_reg_reg ); // FIXME
%}


//----------PEEPHOLE RULES-----------------------------------------------------
// These must follow all instruction definitions as they use the names
// defined in the instructions definitions.
//
// peepmatch ( root_instr_name [preceding_instruction]* );
//
// peepconstraint %{
// (instruction_number.operand_name relational_op instruction_number.operand_name
//  [, ...] );
// // instruction numbers are zero-based using left to right order in peepmatch
//
// peepreplace ( instr_name  ( [instruction_number.operand_name]* ) );
// // provide an instruction_number.operand_name for each operand that appears
// // in the replacement instruction's match rule
//
// ---------VM FLAGS---------------------------------------------------------
//
// All peephole optimizations can be turned off using -XX:-OptoPeephole
//
// Each peephole rule is given an identifying number starting with zero and
// increasing by one in the order seen by the parser.  An individual peephole
// can be enabled, and all others disabled, by using -XX:OptoPeepholeAt=#
// on the command-line.
//
// ---------CURRENT LIMITATIONS----------------------------------------------
//
// Only match adjacent instructions in same basic block
// Only equality constraints
// Only constraints between operands, not (0.dest_reg == EAX_enc)
// Only one replacement instruction
//
// ---------EXAMPLE----------------------------------------------------------
//
// // pertinent parts of existing instructions in architecture description
// instruct movI(eRegI dst, eRegI src) %{
//   match(Set dst (CopyI src));
// %}
//
// instruct incI_eReg(eRegI dst, immI1 src, eFlagsReg cr) %{
//   match(Set dst (AddI dst src));
//   effect(KILL cr);
// %}
//
// // Change (inc mov) to lea
// peephole %{
//   // increment preceded by register-register move
//   peepmatch ( incI_eReg movI );
//   // require that the destination register of the increment
//   // match the destination register of the move
//   peepconstraint ( 0.dst == 1.dst );
//   // construct a replacement instruction that sets
//   // the destination to ( move's source register + one )
//   peepreplace ( incI_eReg_immI1( 0.dst 1.src 0.src ) );
// %}
//

// // Change load of spilled value to only a spill
// instruct storeI(memory mem, eRegI src) %{
//   match(Set mem (StoreI mem src));
// %}
//
// instruct loadI(eRegI dst, memory mem) %{
//   match(Set dst (LoadI mem));
// %}
//
// peephole %{
//   peepmatch ( loadI storeI );
//   peepconstraint ( 1.src == 0.dst, 1.mem == 0.mem );
//   peepreplace ( storeI( 1.mem 1.mem 1.src ) );
// %}

//----------SMARTSPILL RULES---------------------------------------------------
// These must follow all instruction definitions as they use the names
// defined in the instructions definitions.
//
// ARM will probably not have any of these rules due to RISC instruction set.

//----------PIPELINE-----------------------------------------------------------
// Rules which define the behavior of the target architectures pipeline.

[Seitenstruktur0.256Druckenetwas mehr zur Ethik2026-04-25]

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge