JDK14/Java14源码在线阅读

//
// Copyright (c) 2008, 2018, 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 );
  }

};

%}

source %{
#define __ _masm.

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


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

// REQUIRED FUNCTIONALITY

// Indicate if the safepoint node needs the polling page as an input.
// Since ARM does not have absolute addressing, it does.
bool SafePointNode::needs_polling_address_input() {
  return true;
}

// emit an interrupt that is caught by the debugger (for debugging compiler)
void emit_break(CodeBuffer &cbuf) {
  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) {
  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();
  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 Compile::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;
  Compile::ConstantTable& constant_table = C->constant_table();
  MacroAssembler _masm(&cbuf);

  Register r = as_Register(ra_->get_encode(this));
  CodeSection* consts_section = __ code()->consts();
  int consts_size = consts_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->frame_size_in_bytes();
  assert((framesize & (StackAlignmentInBytes-1)) == 0, "frame size not aligned");
  int bangsize = C->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->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;
  MacroAssembler _masm(&cbuf);

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

  size_t framesize = C->frame_size_in_bytes();
  assert((framesize & (StackAlignmentInBytes-1)) == 0, "frame size not aligned");
  int bangsize = C->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->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->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.
    Compile::ConstantTable& constant_table = C->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->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 {
  MacroAssembler _masm(&cbuf);
  Compile* C = ra_->C;

  size_t framesize = C->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()) {
    // mov_slow here is usually one or two instruction
    __ mov_address(Rtemp, (address)os::get_polling_page());
    __ relocate(relocInfo::poll_return_type);
    __ ldr(Rtemp, Address(Rtemp));
  }
}

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();
}

int MachEpilogNode::safepoint_offset() const {
  assert( do_polling(), "no return for this epilog node");
  //  return MacroAssembler::size_of_sethi(os::get_polling_page());
  Unimplemented();
  return 0;
}

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

// 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 )

  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 {
  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 {
  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->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 {
  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) {
  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.
  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_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);
  // Add rules here.

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

const bool Matcher::has_predicated_vectors(void) {
  return false;
}

const int Matcher::float_pressure(int default_pressure_threshold) {
  return default_pressure_threshold;
}

int Matcher::regnum_to_fpu_offset(int regnum) {
  return regnum - 32; // The FP registers are in the second chunk
}

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

// 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;
}

const uint Matcher::vector_shift_count_ideal_reg(int size) {
  return vector_ideal_reg(size);
}

// 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);
}

// ARM doesn't support misaligned vectors store/load.
const bool Matcher::misaligned_vectors_ok() {
  return false;
}

// ARM doesn't support AES intrinsics
const bool Matcher::pass_original_key_for_aes() {
  return false;
}

const bool Matcher::convL2FSupported(void) {
  return false;
}

// 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;
}

const bool Matcher::isSimpleConstant64(jlong value) {
  // Will one (StoreL ConL) be cheaper than two (StoreI ConI)?.
  return false;
}

// No scaling for the parameter the ClearArray node.
const bool Matcher::init_array_count_is_in_bytes = true;

// Needs 2 CMOV's for longs.
const int Matcher::long_cmove_cost() { return 2; }

// CMOVF/CMOVD are expensive on ARM.
const int Matcher::float_cmove_cost() { return ConditionalMoveLimit; }

// Does the CPU require late expand (see block.cpp for description of late expand)?
const bool Matcher::require_postalloc_expand = false;

// Do we need to mask the count passed to shift instructions or does
// the cpu only look at the lower 5/6 bits anyway?
// FIXME: does this handle vector shifts as well?
const bool Matcher::need_masked_shift_count = true;

const bool Matcher::convi2l_type_required = true;

// No support for generic vector operands.
const bool Matcher::supports_generic_vector_operands  = false;

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

bool Matcher::is_generic_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 shifts on addressing modes, expecting them
// to be subsumed into complex addressing expressions or compute them
// into registers?
bool Matcher::clone_address_expressions(AddPNode* m, Matcher::MStack& mstack, VectorSet& address_visited) {
  return clone_base_plus_offset_address(m, mstack, address_visited);
}

void Compile::reshape_address(AddPNode* addp) {
}

bool Matcher::narrow_oop_use_complex_address() {
  NOT_LP64(ShouldNotCallThis());
  assert(UseCompressedOops, "only for compressed oops code");
  return false;
}

bool Matcher::narrow_klass_use_complex_address() {
  NOT_LP64(ShouldNotCallThis());
  assert(UseCompressedClassPointers, "only for compressed klass code");
  return false;
}

bool Matcher::const_oop_prefer_decode() {
  NOT_LP64(ShouldNotCallThis());
  return true;
}

bool Matcher::const_klass_prefer_decode() {
  NOT_LP64(ShouldNotCallThis());
  return true;
}

// Is it better to copy float constants, or load them directly from memory?
// Intel can load a float constant from a direct address, requiring no
// extra registers.  Most RISCs will have to materialize an address into a
// register first, so they would do better to copy the constant from stack.
const bool Matcher::rematerialize_float_constants = false;

// If CPU can load and store mis-aligned doubles directly then no fixup is
// needed.  Else we split the double into 2 integer pieces and move it
// piece-by-piece.  Only happens when passing doubles into C code as the
// Java calling convention forces doubles to be aligned.
const bool Matcher::misaligned_doubles_ok = false;

// No-op on ARM.
void Matcher::pd_implicit_null_fixup(MachNode *node, uint idx) {
}

// Advertise here if the CPU requires explicit rounding operations
// to implement the UseStrictFP mode.
const bool Matcher::strict_fp_requires_explicit_rounding = false;

// Are floats converted to double when stored to stack during deoptimization?
// ARM does not handle callee-save floats.
bool Matcher::float_in_double() {
  return false;
}

// Do ints take an entire long register or just half?
// Note that we if-def off of _LP64.
// The relevant question is how the int is callee-saved.  In _LP64
// the whole long is written but de-opt'ing will have to extract
// the relevant 32 bits, in not-_LP64 only the low 32 bits is written.
#ifdef _LP64
const bool Matcher::int_in_long = true;
#else
const bool Matcher::int_in_long = false;
#endif

// 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);
}

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());
    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());
    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 %{
    MacroAssembler _masm(&cbuf);
    __ mov(SP, Rmh_SP_save);
  %}

  enc_class Java_Dynamic_Call (method meth) %{
    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);
      }
    }
    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);
    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;
    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;
    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;
    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 nessecary 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 nessecary 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 %{
  // What direction does stack grow in (assumed to be same for native & Java)
  stack_direction(TOWARDS_LOW);

  // 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
  interpreter_method_oop_reg(R_Rmethod); // Method Oop Register when calling interpreter

  // 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 stack slots between incoming argument block and the start of
  // a new frame.  The PROLOG must add this many slots to the stack.  The
  // EPILOG must remove this many slots.
  // FP + LR
  in_preserve_stack_slots(2 * VMRegImpl::slots_per_word);

  // 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()));

  // Body of function which returns an OptoRegs array locating
  // arguments either in registers or in stack slots for calling
  // java
  calling_convention %{
    (void) SharedRuntime::java_calling_convention(sig_bt, regs, length, is_outgoing);

  %}

  // Body of function which returns an OptoRegs array locating
  // arguments either in registers or in stack slots for callin
  // C.
  c_calling_convention %{
    // This is obviously always outgoing
    (void) SharedRuntime::c_calling_convention(sig_bt, regs, /*regs2=*/NULL, length);
  %}

  // 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);
%}

operand immP_poll() %{
  predicate(n->get_ptr() != 0 && n->get_ptr() == (intptr_t)os::get_polling_page());
  match(ConP);

  // formats are generated automatically for constants and base registers
  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);
%}

operand interpreter_method_oop_regP(iRegP reg) %{
  constraint(ALLOC_IN_RC(Rmethod_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 operaion
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);
%}

// Polling Address
pipe_class loadConP_poll( iRegP dst, immP_poll src ) %{
    dst   : E(write);
    IALU  : R;
%}

// 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 loadConP_poll(iRegP dst, immP_poll src) %{
  match(Set dst src);
  ins_cost(DEFAULT_COST);
  format %{ "MOV_SLOW    $dst,$src\t!ptr" %}
  ins_encode %{
      __ mov_slow($dst$$Register, $src$$constant);
  %}
  ins_pipe(loadConP_poll);
%}

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);
  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);
%}

//----------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);
%}

//----------Conditional_store--------------------------------------------------
// Conditional-store of the updated heap-top.
// Used during allocation of the shared heap.
// Sets flags (EQ) on success.

// LoadP-locked.
instruct loadPLocked(iRegP dst, memoryex mem) %{
  match(Set dst (LoadPLocked mem));
  size(4);
  format %{ "LDREX  $dst,$mem" %}
  ins_encode %{
    __ ldrex($dst$$Register,$mem$$Address);
  %}
  ins_pipe(iload_mem);
%}

instruct storePConditional( memoryex heap_top_ptr, iRegP oldval, iRegP newval, iRegI tmp, flagsRegP pcc ) %{
  predicate(_kids[1]->_kids[0]->_leaf->Opcode() == Op_LoadPLocked); // only works in conjunction with a LoadPLocked node
  match(Set pcc (StorePConditional heap_top_ptr (Binary oldval newval)));
  effect( TEMP tmp );
  size(8);
  format %{ "STREX  $tmp,$newval,$heap_top_ptr\n\t"
            "CMP    $tmp, 0" %}
  ins_encode %{
    __ strex($tmp$$Register, $newval$$Register, $heap_top_ptr$$Address);
    __ cmp($tmp$$Register, 0);
  %}
  ins_pipe( long_memory_op );
%}

// Conditional-store of an intx value.
instruct storeXConditional( memoryex mem, iRegX oldval, iRegX newval, iRegX tmp, flagsReg icc ) %{
  match(Set icc (StoreIConditional mem (Binary oldval newval)));
  effect( TEMP tmp );
  size(28);
  format %{ "loop: \n\t"
            "LDREX    $tmp, $mem\t! If $oldval==[$mem] Then store $newval into [$mem], DOESN'T set $newval=[$mem] in any case\n\t"
            "XORS     $tmp,$tmp, $oldval\n\t"
            "STREX.eq $tmp, $newval, $mem\n\t"
            "CMP.eq   $tmp, 1 \n\t"
            "B.eq     loop \n\t"
            "TEQ      $tmp, 0\n\t"
            "membar   LoadStore|LoadLoad" %}
  ins_encode %{
    Label loop;
    __ bind(loop);
    __ ldrex($tmp$$Register, $mem$$Address);
    __ eors($tmp$$Register, $tmp$$Register, $oldval$$Register);
    __ strex($tmp$$Register, $newval$$Register, $mem$$Address, eq);
    __ cmp($tmp$$Register, 1, eq);
    __ b(loop, eq);
    __ teq($tmp$$Register, 0);
    // used by biased locking only. Requires a membar.
    __ membar(MacroAssembler::Membar_mask_bits(MacroAssembler::LoadStore | MacroAssembler::LoadLoad), noreg);
  %}
  ins_pipe( long_memory_op );
%}

// 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_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_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_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_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_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_imm_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);
  format %{ "MOVW$cmp  $dst,$src" %}
  ins_encode %{
    __ movw($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(ialu_imm);
%}

instruct cmovIL_imm_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);
  format %{ "MOVW$cmp  $dst,$src" %}
  ins_encode %{
    __ movw($dst$$Register, $src$$constant, (AsmCondition)($cmp$$cmpcode));
  %}
  ins_pipe(ialu_imm);
%}

instruct cmovIL_imm_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);
  format %{ "MOVW$cmp  $dst,$src" %}
  ins_encode %{
    __ movw($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_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_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_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);
  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);
  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);
  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: ned 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: ned 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_oop) %{
  match(TailCall jump_target method_oop );

  ins_cost(CALL_COST);
  format %{ "MOV    Rexception_pc, LR\n\t"
            "jump   $jump_target  \t! $method_oop holds method oop" %}
  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);

  size(4);
  // Use the following format syntax
  format %{ "ShouldNotReachHere" %}
  ins_encode %{
    __ udf(0xdead);
  %}
  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));
  predicate(!(UseBiasedLocking && !UseOptoBiasInlining));

  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 cmpFastLock_noBiasInline(flagsRegP pcc, iRegP object, iRegP box, iRegP scratch2,
                                  iRegP scratch, iRegP scratch3) %{
  match(Set pcc (FastLock object box));
  predicate(UseBiasedLocking && !UseOptoBiasInlining);

  effect(TEMP scratch, TEMP scratch2, TEMP scratch3);
  ins_cost(DEFAULT_COST*5);

  format %{ "FASTLOCK  $object, $box; KILL $scratch, $scratch2, $scratch3" %}
  ins_encode %{
    __ fast_lock($object$$Register, $box$$Register, $scratch$$Register, $scratch2$$Register, $scratch3$$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(),

/**代码未完, 请加载全部代码(NowJava.com).**/
展开阅读全文

关注时代Java

关注时代Java