From 795bf9f6d16d89f65076d4b37dddb309a91ce6ea Mon Sep 17 00:00:00 2001 From: Anton Seoane Ampudia Date: Thu, 30 Oct 2025 11:31:29 +0000 Subject: [PATCH] 8351159: Remaining cleanups in cpu/x86 after 32-bit x86 removal Reviewed-by: stefank, kvn --- .../cpu/x86/abstractInterpreter_x86.cpp | 26 - src/hotspot/cpu/x86/assembler_x86.cpp | 2 - src/hotspot/cpu/x86/c2_globals_x86.hpp | 12 +- src/hotspot/cpu/x86/c2_init_x86.cpp | 8 - src/hotspot/cpu/x86/compiledIC_x86.cpp | 3 +- src/hotspot/cpu/x86/compressedKlass_x86.cpp | 4 - src/hotspot/cpu/x86/copy_x86.hpp | 201 +- src/hotspot/cpu/x86/frame_x86.cpp | 21 +- src/hotspot/cpu/x86/frame_x86.hpp | 8 +- src/hotspot/cpu/x86/frame_x86.inline.hpp | 2 - src/hotspot/cpu/x86/interp_masm_x86.cpp | 4 +- src/hotspot/cpu/x86/jniTypes_x86.hpp | 28 +- .../cpu/x86/jvmciCodeInstaller_x86.cpp | 8 - src/hotspot/cpu/x86/methodHandles_x86.cpp | 4 - src/hotspot/cpu/x86/relocInfo_x86.cpp | 14 - src/hotspot/cpu/x86/relocInfo_x86.hpp | 6 +- src/hotspot/cpu/x86/vm_version_x86.cpp | 2 - src/hotspot/cpu/x86/x86.ad | 14670 ++++++++++++++- src/hotspot/cpu/x86/x86_64.ad | 14735 ---------------- .../os_cpu/bsd_x86/atomicAccess_bsd_x86.hpp | 48 - .../os_cpu/bsd_x86/globals_bsd_x86.hpp | 12 +- .../os_cpu/bsd_x86/orderAccess_bsd_x86.hpp | 6 +- src/hotspot/os_cpu/bsd_x86/os_bsd_x86.cpp | 421 +- .../os_cpu/bsd_x86/os_bsd_x86.inline.hpp | 9 +- .../bsd_x86/prefetch_bsd_x86.inline.hpp | 8 +- .../linux_x86/atomicAccess_linux_x86.hpp | 49 - .../os_cpu/linux_x86/globals_linux_x86.hpp | 17 +- .../linux_x86/orderAccess_linux_x86.hpp | 14 +- src/hotspot/os_cpu/linux_x86/os_linux_x86.cpp | 176 +- .../os_cpu/linux_x86/os_linux_x86.inline.hpp | 9 +- .../linux_x86/prefetch_linux_x86.inline.hpp | 8 +- .../os_cpu/windows_x86/os_windows_x86.cpp | 2 - 32 files changed, 14782 insertions(+), 15755 deletions(-) delete mode 100644 src/hotspot/cpu/x86/x86_64.ad diff --git a/src/hotspot/cpu/x86/abstractInterpreter_x86.cpp b/src/hotspot/cpu/x86/abstractInterpreter_x86.cpp index 6680b8c4c03..c112182fdee 100644 --- a/src/hotspot/cpu/x86/abstractInterpreter_x86.cpp +++ b/src/hotspot/cpu/x86/abstractInterpreter_x86.cpp @@ -120,27 +120,6 @@ void AbstractInterpreter::layout_activation(Method* method, method->method_holder()->java_mirror(); } -#ifndef _LP64 -int AbstractInterpreter::BasicType_as_index(BasicType type) { - int i = 0; - switch (type) { - case T_BOOLEAN: i = 0; break; - case T_CHAR : i = 1; break; - case T_BYTE : i = 2; break; - case T_SHORT : i = 3; break; - case T_INT : // fall through - case T_LONG : // fall through - case T_VOID : i = 4; break; - case T_FLOAT : i = 5; break; // have to treat float and double separately for SSE - case T_DOUBLE : i = 6; break; - case T_OBJECT : // fall through - case T_ARRAY : i = 7; break; - default : ShouldNotReachHere(); - } - assert(0 <= i && i < AbstractInterpreter::number_of_result_handlers, "index out of bounds"); - return i; -} -#else int AbstractInterpreter::BasicType_as_index(BasicType type) { int i = 0; switch (type) { @@ -161,7 +140,6 @@ int AbstractInterpreter::BasicType_as_index(BasicType type) { "index out of bounds"); return i; } -#endif // _LP64 // How much stack a method activation needs in words. int AbstractInterpreter::size_top_interpreter_activation(Method* method) { @@ -173,11 +151,7 @@ int AbstractInterpreter::size_top_interpreter_activation(Method* method) { const int overhead_size = -(frame::interpreter_frame_initial_sp_offset) + entry_size; -#ifndef _LP64 - const int stub_code = 4; // see generate_call_stub -#else const int stub_code = frame::entry_frame_after_call_words; -#endif const int method_stack = (method->max_locals() + method->max_stack()) * Interpreter::stackElementWords; diff --git a/src/hotspot/cpu/x86/assembler_x86.cpp b/src/hotspot/cpu/x86/assembler_x86.cpp index fd62e9358bf..e3ba0ebb56a 100644 --- a/src/hotspot/cpu/x86/assembler_x86.cpp +++ b/src/hotspot/cpu/x86/assembler_x86.cpp @@ -2935,7 +2935,6 @@ void Assembler::mov(Register dst, Register src) { } void Assembler::movapd(XMMRegister dst, Address src) { - NOT_LP64(assert(VM_Version::supports_sse2(), "")); InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* rex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); @@ -8071,7 +8070,6 @@ void Assembler::vandps(XMMRegister dst, XMMRegister nds, Address src, int vector } void Assembler::orpd(XMMRegister dst, XMMRegister src) { - NOT_LP64(assert(VM_Version::supports_sse2(), "")); InstructionAttr attributes(AVX_128bit, /* rex_w */ !_legacy_mode_dq, /* legacy_mode */ _legacy_mode_dq, /* no_mask_reg */ true, /* uses_vl */ true); attributes.set_rex_vex_w_reverted(); int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); diff --git a/src/hotspot/cpu/x86/c2_globals_x86.hpp b/src/hotspot/cpu/x86/c2_globals_x86.hpp index afd46a6fb08..3f616cb4578 100644 --- a/src/hotspot/cpu/x86/c2_globals_x86.hpp +++ b/src/hotspot/cpu/x86/c2_globals_x86.hpp @@ -45,21 +45,13 @@ define_pd_global(intx, ConditionalMoveLimit, 3); define_pd_global(intx, FreqInlineSize, 325); define_pd_global(intx, MinJumpTableSize, 10); define_pd_global(intx, LoopPercentProfileLimit, 10); -#ifdef AMD64 define_pd_global(intx, InteriorEntryAlignment, 16); -define_pd_global(size_t, NewSizeThreadIncrease, ScaleForWordSize(4*K)); +define_pd_global(size_t, NewSizeThreadIncrease, ScaleForWordSize(4*K)); define_pd_global(intx, LoopUnrollLimit, 60); // InitialCodeCacheSize derived from specjbb2000 run. define_pd_global(size_t, InitialCodeCacheSize, 2496*K); // Integral multiple of CodeCacheExpansionSize define_pd_global(size_t, CodeCacheExpansionSize, 64*K); -#else -define_pd_global(intx, InteriorEntryAlignment, 4); -define_pd_global(size_t, NewSizeThreadIncrease, 4*K); -define_pd_global(intx, LoopUnrollLimit, 50); // Design center runs on 1.3.1 -// InitialCodeCacheSize derived from specjbb2000 run. -define_pd_global(size_t, InitialCodeCacheSize, 2304*K); // Integral multiple of CodeCacheExpansionSize -define_pd_global(size_t, CodeCacheExpansionSize, 32*K); -#endif // AMD64 + define_pd_global(intx, RegisterCostAreaRatio, 16000); // Peephole and CISC spilling both break the graph, and so makes the diff --git a/src/hotspot/cpu/x86/c2_init_x86.cpp b/src/hotspot/cpu/x86/c2_init_x86.cpp index b286c3a34f2..4d8db39bb0c 100644 --- a/src/hotspot/cpu/x86/c2_init_x86.cpp +++ b/src/hotspot/cpu/x86/c2_init_x86.cpp @@ -33,14 +33,6 @@ extern void reg_mask_init(); void Compile::pd_compiler2_init() { guarantee(CodeEntryAlignment >= InteriorEntryAlignment, "" ); - // QQQ presumably all 64bit cpu's support this. Seems like the ifdef could - // simply be left out. -#ifndef AMD64 - if (!VM_Version::supports_cmov()) { - ConditionalMoveLimit = 0; - } -#endif // AMD64 - if (UseAVX < 3) { int delta = XMMRegister::max_slots_per_register * XMMRegister::number_of_registers; int bottom = ConcreteRegisterImpl::max_fpr; diff --git a/src/hotspot/cpu/x86/compiledIC_x86.cpp b/src/hotspot/cpu/x86/compiledIC_x86.cpp index 53ad9aeec91..ae5521ce170 100644 --- a/src/hotspot/cpu/x86/compiledIC_x86.cpp +++ b/src/hotspot/cpu/x86/compiledIC_x86.cpp @@ -61,8 +61,7 @@ address CompiledDirectCall::emit_to_interp_stub(MacroAssembler *masm, address ma #undef __ int CompiledDirectCall::to_interp_stub_size() { - return NOT_LP64(10) // movl; jmp - LP64_ONLY(15); // movq (1+1+8); jmp (1+4) + return 15; // movq (1+1+8); jmp (1+4) } int CompiledDirectCall::to_trampoline_stub_size() { diff --git a/src/hotspot/cpu/x86/compressedKlass_x86.cpp b/src/hotspot/cpu/x86/compressedKlass_x86.cpp index e88b7a3d4e1..1151a6200ce 100644 --- a/src/hotspot/cpu/x86/compressedKlass_x86.cpp +++ b/src/hotspot/cpu/x86/compressedKlass_x86.cpp @@ -23,8 +23,6 @@ * */ -#ifdef _LP64 - #include "memory/metaspace.hpp" #include "oops/compressedKlass.hpp" #include "utilities/globalDefinitions.hpp" @@ -54,5 +52,3 @@ char* CompressedKlassPointers::reserve_address_space_for_compressed_classes(size return result; } - -#endif // _LP64 diff --git a/src/hotspot/cpu/x86/copy_x86.hpp b/src/hotspot/cpu/x86/copy_x86.hpp index 1798e74eb06..a110af3d00a 100644 --- a/src/hotspot/cpu/x86/copy_x86.hpp +++ b/src/hotspot/cpu/x86/copy_x86.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, 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 @@ -28,19 +28,11 @@ #include OS_CPU_HEADER(copy) static void pd_fill_to_words(HeapWord* tohw, size_t count, juint value) { -#ifdef AMD64 julong* to = (julong*) tohw; julong v = ((julong) value << 32) | value; while (count-- > 0) { *to++ = v; } -#else - juint* to = (juint*)tohw; - count *= HeapWordSize / BytesPerInt; - while (count-- > 0) { - *to++ = value; - } -#endif // AMD64 } static void pd_fill_to_aligned_words(HeapWord* tohw, size_t count, juint value) { @@ -60,52 +52,10 @@ static void pd_zero_to_bytes(void* to, size_t count) { } static void pd_conjoint_words(const HeapWord* from, HeapWord* to, size_t count) { -#if defined AMD64 || defined _WINDOWS (void)memmove(to, from, count * HeapWordSize); -#else - // Includes a zero-count check. - intx temp = 0; - __asm__ volatile(" testl %6,%6 ;" - " jz 7f ;" - " cmpl %4,%5 ;" - " leal -4(%4,%6,4),%3;" - " jbe 1f ;" - " cmpl %7,%5 ;" - " jbe 4f ;" - "1: cmpl $32,%6 ;" - " ja 3f ;" - " subl %4,%1 ;" - "2: movl (%4),%3 ;" - " movl %7,(%5,%4,1) ;" - " addl $4,%0 ;" - " subl $1,%2 ;" - " jnz 2b ;" - " jmp 7f ;" - "3: rep; smovl ;" - " jmp 7f ;" - "4: cmpl $32,%2 ;" - " movl %7,%0 ;" - " leal -4(%5,%6,4),%1;" - " ja 6f ;" - " subl %4,%1 ;" - "5: movl (%4),%3 ;" - " movl %7,(%5,%4,1) ;" - " subl $4,%0 ;" - " subl $1,%2 ;" - " jnz 5b ;" - " jmp 7f ;" - "6: std ;" - " rep; smovl ;" - " cld ;" - "7: nop " - : "=S" (from), "=D" (to), "=c" (count), "=r" (temp) - : "0" (from), "1" (to), "2" (count), "3" (temp) - : "memory", "flags"); -#endif // AMD64 } static void pd_disjoint_words(const HeapWord* from, HeapWord* to, size_t count) { -#ifdef AMD64 switch (count) { case 8: to[7] = from[7]; case 7: to[6] = from[6]; @@ -120,39 +70,10 @@ static void pd_disjoint_words(const HeapWord* from, HeapWord* to, size_t count) (void)memcpy(to, from, count * HeapWordSize); break; } -#else -#if defined _WINDOWS - (void)memcpy(to, from, count * HeapWordSize); -#else - // Includes a zero-count check. - intx temp = 0; - __asm__ volatile(" testl %6,%6 ;" - " jz 3f ;" - " cmpl $32,%6 ;" - " ja 2f ;" - " subl %4,%1 ;" - "1: movl (%4),%3 ;" - " movl %7,(%5,%4,1);" - " addl $4,%0 ;" - " subl $1,%2 ;" - " jnz 1b ;" - " jmp 3f ;" - "2: rep; smovl ;" - "3: nop " - : "=S" (from), "=D" (to), "=c" (count), "=r" (temp) - : "0" (from), "1" (to), "2" (count), "3" (temp) - : "memory", "cc"); -#endif // _WINDOWS -#endif // AMD64 } static void pd_disjoint_words_atomic(const HeapWord* from, HeapWord* to, size_t count) { -#ifdef AMD64 shared_disjoint_words_atomic(from, to, count); -#else - // pd_disjoint_words is word-atomic in this implementation. - pd_disjoint_words(from, to, count); -#endif // AMD64 } static void pd_aligned_conjoint_words(const HeapWord* from, HeapWord* to, size_t count) { @@ -164,82 +85,7 @@ static void pd_aligned_disjoint_words(const HeapWord* from, HeapWord* to, size_t } static void pd_conjoint_bytes(const void* from, void* to, size_t count) { -#if defined AMD64 || defined _WINDOWS (void)memmove(to, from, count); -#else - // Includes a zero-count check. - intx temp = 0; - __asm__ volatile(" testl %6,%6 ;" - " jz 13f ;" - " cmpl %4,%5 ;" - " leal -1(%4,%6),%3 ;" - " jbe 1f ;" - " cmpl %7,%5 ;" - " jbe 8f ;" - "1: cmpl $3,%6 ;" - " jbe 6f ;" - " movl %6,%3 ;" - " movl $4,%2 ;" - " subl %4,%2 ;" - " andl $3,%2 ;" - " jz 2f ;" - " subl %6,%3 ;" - " rep; smovb ;" - "2: movl %7,%2 ;" - " shrl $2,%2 ;" - " jz 5f ;" - " cmpl $32,%2 ;" - " ja 4f ;" - " subl %4,%1 ;" - "3: movl (%4),%%edx ;" - " movl %%edx,(%5,%4,1);" - " addl $4,%0 ;" - " subl $1,%2 ;" - " jnz 3b ;" - " addl %4,%1 ;" - " jmp 5f ;" - "4: rep; smovl ;" - "5: movl %7,%2 ;" - " andl $3,%2 ;" - " jz 13f ;" - "6: xorl %7,%3 ;" - "7: movb (%4,%7,1),%%dl ;" - " movb %%dl,(%5,%7,1) ;" - " addl $1,%3 ;" - " subl $1,%2 ;" - " jnz 7b ;" - " jmp 13f ;" - "8: std ;" - " cmpl $12,%2 ;" - " ja 9f ;" - " movl %7,%0 ;" - " leal -1(%6,%5),%1 ;" - " jmp 11f ;" - "9: xchgl %3,%2 ;" - " movl %6,%0 ;" - " addl $1,%2 ;" - " leal -1(%7,%5),%1 ;" - " andl $3,%2 ;" - " jz 10f ;" - " subl %6,%3 ;" - " rep; smovb ;" - "10: movl %7,%2 ;" - " subl $3,%0 ;" - " shrl $2,%2 ;" - " subl $3,%1 ;" - " rep; smovl ;" - " andl $3,%3 ;" - " jz 12f ;" - " movl %7,%2 ;" - " addl $3,%0 ;" - " addl $3,%1 ;" - "11: rep; smovb ;" - "12: cld ;" - "13: nop ;" - : "=S" (from), "=D" (to), "=c" (count), "=r" (temp) - : "0" (from), "1" (to), "2" (count), "3" (temp) - : "memory", "flags", "%edx"); -#endif // AMD64 } static void pd_conjoint_bytes_atomic(const void* from, void* to, size_t count) { @@ -253,49 +99,16 @@ static void pd_conjoint_jshorts_atomic(const jshort* from, jshort* to, size_t co } static void pd_conjoint_jints_atomic(const jint* from, jint* to, size_t count) { -#ifdef AMD64 _Copy_conjoint_jints_atomic(from, to, count); -#else - assert(HeapWordSize == BytesPerInt, "heapwords and jints must be the same size"); - // pd_conjoint_words is word-atomic in this implementation. - pd_conjoint_words((const HeapWord*)from, (HeapWord*)to, count); -#endif // AMD64 } static void pd_conjoint_jlongs_atomic(const jlong* from, jlong* to, size_t count) { -#ifdef AMD64 _Copy_conjoint_jlongs_atomic(from, to, count); -#else - // Guarantee use of fild/fistp or xmm regs via some asm code, because compilers won't. - if (from > to) { - while (count-- > 0) { - __asm__ volatile("fildll (%0); fistpll (%1)" - : - : "r" (from), "r" (to) - : "memory" ); - ++from; - ++to; - } - } else { - while (count-- > 0) { - __asm__ volatile("fildll (%0,%2,8); fistpll (%1,%2,8)" - : - : "r" (from), "r" (to), "r" (count) - : "memory" ); - } - } -#endif // AMD64 } static void pd_conjoint_oops_atomic(const oop* from, oop* to, size_t count) { -#ifdef AMD64 assert(BytesPerLong == BytesPerOop, "jlongs and oops must be the same size"); _Copy_conjoint_jlongs_atomic((const jlong*)from, (jlong*)to, count); -#else - assert(HeapWordSize == BytesPerOop, "heapwords and oops must be the same size"); - // pd_conjoint_words is word-atomic in this implementation. - pd_conjoint_words((const HeapWord*)from, (HeapWord*)to, count); -#endif // AMD64 } static void pd_arrayof_conjoint_bytes(const HeapWord* from, HeapWord* to, size_t count) { @@ -307,28 +120,16 @@ static void pd_arrayof_conjoint_jshorts(const HeapWord* from, HeapWord* to, size } static void pd_arrayof_conjoint_jints(const HeapWord* from, HeapWord* to, size_t count) { -#ifdef AMD64 _Copy_arrayof_conjoint_jints(from, to, count); -#else - pd_conjoint_jints_atomic((const jint*)from, (jint*)to, count); -#endif // AMD64 } static void pd_arrayof_conjoint_jlongs(const HeapWord* from, HeapWord* to, size_t count) { -#ifdef AMD64 _Copy_arrayof_conjoint_jlongs(from, to, count); -#else - pd_conjoint_jlongs_atomic((const jlong*)from, (jlong*)to, count); -#endif // AMD64 } static void pd_arrayof_conjoint_oops(const HeapWord* from, HeapWord* to, size_t count) { -#ifdef AMD64 assert(BytesPerLong == BytesPerOop, "jlongs and oops must be the same size"); _Copy_arrayof_conjoint_jlongs(from, to, count); -#else - pd_conjoint_oops_atomic((const oop*)from, (oop*)to, count); -#endif // AMD64 } #endif // _WINDOWS diff --git a/src/hotspot/cpu/x86/frame_x86.cpp b/src/hotspot/cpu/x86/frame_x86.cpp index 5f52f2fabf2..1ff28516307 100644 --- a/src/hotspot/cpu/x86/frame_x86.cpp +++ b/src/hotspot/cpu/x86/frame_x86.cpp @@ -536,14 +536,9 @@ BasicType frame::interpreter_frame_result(oop* oop_result, jvalue* value_result) // then ST0 is saved before EAX/EDX. See the note in generate_native_result tos_addr = (intptr_t*)sp(); if (type == T_FLOAT || type == T_DOUBLE) { - // QQQ seems like this code is equivalent on the two platforms -#ifdef AMD64 // This is times two because we do a push(ltos) after pushing XMM0 // and that takes two interpreter stack slots. tos_addr += 2 * Interpreter::stackElementWords; -#else - tos_addr += 2; -#endif // AMD64 } } else { tos_addr = (intptr_t*)interpreter_frame_tos_address(); @@ -569,19 +564,7 @@ BasicType frame::interpreter_frame_result(oop* oop_result, jvalue* value_result) case T_SHORT : value_result->s = *(jshort*)tos_addr; break; case T_INT : value_result->i = *(jint*)tos_addr; break; case T_LONG : value_result->j = *(jlong*)tos_addr; break; - case T_FLOAT : { -#ifdef AMD64 - value_result->f = *(jfloat*)tos_addr; -#else - if (method->is_native()) { - jdouble d = *(jdouble*)tos_addr; // Result was in ST0 so need to convert to jfloat - value_result->f = (jfloat)d; - } else { - value_result->f = *(jfloat*)tos_addr; - } -#endif // AMD64 - break; - } + case T_FLOAT : value_result->f = *(jfloat*)tos_addr; break; case T_DOUBLE : value_result->d = *(jdouble*)tos_addr; break; case T_VOID : /* Nothing to do */ break; default : ShouldNotReachHere(); @@ -611,7 +594,6 @@ void frame::describe_pd(FrameValues& values, int frame_no) { DESCRIBE_FP_OFFSET(interpreter_frame_locals); DESCRIBE_FP_OFFSET(interpreter_frame_bcp); DESCRIBE_FP_OFFSET(interpreter_frame_initial_sp); -#ifdef AMD64 } else if (is_entry_frame()) { // This could be more descriptive if we use the enum in // stubGenerator to map to real names but it's most important to @@ -619,7 +601,6 @@ void frame::describe_pd(FrameValues& values, int frame_no) { for (int i = 0; i < entry_frame_after_call_words; i++) { values.describe(frame_no, fp() - i, err_msg("call_stub word fp - %d", i)); } -#endif // AMD64 } if (is_java_frame() || Continuation::is_continuation_enterSpecial(*this)) { diff --git a/src/hotspot/cpu/x86/frame_x86.hpp b/src/hotspot/cpu/x86/frame_x86.hpp index 19f37c42cf4..2d382c7e5e5 100644 --- a/src/hotspot/cpu/x86/frame_x86.hpp +++ b/src/hotspot/cpu/x86/frame_x86.hpp @@ -80,8 +80,7 @@ interpreter_frame_monitor_block_bottom_offset = interpreter_frame_initial_sp_offset, // Entry frames -#ifdef AMD64 -#ifdef _WIN64 +#ifdef _WINDOWS entry_frame_after_call_words = 28, entry_frame_call_wrapper_offset = 2, @@ -91,10 +90,7 @@ entry_frame_call_wrapper_offset = -6, arg_reg_save_area_bytes = 0, -#endif // _WIN64 -#else - entry_frame_call_wrapper_offset = 2, -#endif // AMD64 +#endif // _WINDOWS // size, in words, of frame metadata (e.g. pc and link) metadata_words = sender_sp_offset, diff --git a/src/hotspot/cpu/x86/frame_x86.inline.hpp b/src/hotspot/cpu/x86/frame_x86.inline.hpp index ca51fe66786..dcd766545d3 100644 --- a/src/hotspot/cpu/x86/frame_x86.inline.hpp +++ b/src/hotspot/cpu/x86/frame_x86.inline.hpp @@ -483,7 +483,6 @@ void frame::update_map_with_saved_link(RegisterMapT* map, intptr_t** link_addr) // we don't have to always save EBP/RBP on entry and exit to c2 compiled // code, on entry will be enough. map->set_location(rbp->as_VMReg(), (address) link_addr); -#ifdef AMD64 // this is weird "H" ought to be at a higher address however the // oopMaps seems to have the "H" regs at the same address and the // vanilla register. @@ -491,6 +490,5 @@ void frame::update_map_with_saved_link(RegisterMapT* map, intptr_t** link_addr) if (true) { map->set_location(rbp->as_VMReg()->next(), (address) link_addr); } -#endif // AMD64 } #endif // CPU_X86_FRAME_X86_INLINE_HPP diff --git a/src/hotspot/cpu/x86/interp_masm_x86.cpp b/src/hotspot/cpu/x86/interp_masm_x86.cpp index a6b4efbe4f2..9720be17892 100644 --- a/src/hotspot/cpu/x86/interp_masm_x86.cpp +++ b/src/hotspot/cpu/x86/interp_masm_x86.cpp @@ -518,8 +518,8 @@ void InterpreterMacroAssembler::load_resolved_klass_at_index(Register klass, void InterpreterMacroAssembler::gen_subtype_check(Register Rsub_klass, Label& ok_is_subtype) { assert(Rsub_klass != rax, "rax holds superklass"); - LP64_ONLY(assert(Rsub_klass != r14, "r14 holds locals");) - LP64_ONLY(assert(Rsub_klass != r13, "r13 holds bcp");) + assert(Rsub_klass != r14, "r14 holds locals"); + assert(Rsub_klass != r13, "r13 holds bcp"); assert(Rsub_klass != rcx, "rcx holds 2ndary super array length"); assert(Rsub_klass != rdi, "rdi holds 2ndary super array scan ptr"); diff --git a/src/hotspot/cpu/x86/jniTypes_x86.hpp b/src/hotspot/cpu/x86/jniTypes_x86.hpp index 5c925474796..a3a6c27b994 100644 --- a/src/hotspot/cpu/x86/jniTypes_x86.hpp +++ b/src/hotspot/cpu/x86/jniTypes_x86.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2025, 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 @@ -42,22 +42,12 @@ class JNITypes : AllStatic { // reverse the argument list constructed by JavaCallArguments (see // javaCalls.hpp). -private: - -#ifndef AMD64 - // 32bit Helper routines. - static inline void put_int2r(jint *from, intptr_t *to) { *(jint *)(to++) = from[1]; - *(jint *)(to ) = from[0]; } - static inline void put_int2r(jint *from, intptr_t *to, int& pos) { put_int2r(from, to + pos); pos += 2; } -#endif // AMD64 - public: // Ints are stored in native format in one JavaCallArgument slot at *to. static inline void put_int(jint from, intptr_t *to) { *(jint *)(to + 0 ) = from; } static inline void put_int(jint from, intptr_t *to, int& pos) { *(jint *)(to + pos++) = from; } static inline void put_int(jint *from, intptr_t *to, int& pos) { *(jint *)(to + pos++) = *from; } -#ifdef AMD64 // Longs are stored in native format in one JavaCallArgument slot at // *(to+1). static inline void put_long(jlong from, intptr_t *to) { @@ -73,13 +63,6 @@ public: *(jlong*) (to + 1 + pos) = *from; pos += 2; } -#else - // Longs are stored in big-endian word format in two JavaCallArgument slots at *to. - // The high half is in *to and the low half in *(to+1). - static inline void put_long(jlong from, intptr_t *to) { put_int2r((jint *)&from, to); } - static inline void put_long(jlong from, intptr_t *to, int& pos) { put_int2r((jint *)&from, to, pos); } - static inline void put_long(jlong *from, intptr_t *to, int& pos) { put_int2r((jint *) from, to, pos); } -#endif // AMD64 // Oops are stored in native format in one JavaCallArgument slot at *to. static inline void put_obj(const Handle& from_handle, intptr_t *to, int& pos) { *(to + pos++) = (intptr_t)from_handle.raw_value(); } @@ -91,7 +74,6 @@ public: static inline void put_float(jfloat *from, intptr_t *to, int& pos) { *(jfloat *)(to + pos++) = *from; } #undef _JNI_SLOT_OFFSET -#ifdef AMD64 #define _JNI_SLOT_OFFSET 1 // Doubles are stored in native word format in one JavaCallArgument // slot at *(to+1). @@ -108,14 +90,6 @@ public: *(jdouble*) (to + 1 + pos) = *from; pos += 2; } -#else -#define _JNI_SLOT_OFFSET 0 - // Doubles are stored in big-endian word format in two JavaCallArgument slots at *to. - // The high half is in *to and the low half in *(to+1). - static inline void put_double(jdouble from, intptr_t *to) { put_int2r((jint *)&from, to); } - static inline void put_double(jdouble from, intptr_t *to, int& pos) { put_int2r((jint *)&from, to, pos); } - static inline void put_double(jdouble *from, intptr_t *to, int& pos) { put_int2r((jint *) from, to, pos); } -#endif // AMD64 // The get_xxx routines, on the other hand, actually _do_ fetch diff --git a/src/hotspot/cpu/x86/jvmciCodeInstaller_x86.cpp b/src/hotspot/cpu/x86/jvmciCodeInstaller_x86.cpp index 9e6a4789dc2..b9a66907e3b 100644 --- a/src/hotspot/cpu/x86/jvmciCodeInstaller_x86.cpp +++ b/src/hotspot/cpu/x86/jvmciCodeInstaller_x86.cpp @@ -77,14 +77,10 @@ void CodeInstaller::pd_patch_OopConstant(int pc_offset, Handle& obj, bool compre address pc = _instructions->start() + pc_offset; jobject value = JNIHandles::make_local(obj()); if (compressed) { -#ifdef _LP64 address operand = Assembler::locate_operand(pc, Assembler::narrow_oop_operand); int oop_index = _oop_recorder->find_index(value); _instructions->relocate(pc, oop_Relocation::spec(oop_index), Assembler::narrow_oop_operand); JVMCI_event_3("relocating (narrow oop constant) at " PTR_FORMAT "/" PTR_FORMAT, p2i(pc), p2i(operand)); -#else - JVMCI_ERROR("compressed oop on 32bit"); -#endif } else { address operand = Assembler::locate_operand(pc, Assembler::imm_operand); *((jobject*) operand) = value; @@ -96,13 +92,9 @@ void CodeInstaller::pd_patch_OopConstant(int pc_offset, Handle& obj, bool compre void CodeInstaller::pd_patch_MetaspaceConstant(int pc_offset, HotSpotCompiledCodeStream* stream, u1 tag, JVMCI_TRAPS) { address pc = _instructions->start() + pc_offset; if (tag == PATCH_NARROW_KLASS) { -#ifdef _LP64 address operand = Assembler::locate_operand(pc, Assembler::narrow_oop_operand); *((narrowKlass*) operand) = record_narrow_metadata_reference(_instructions, operand, stream, tag, JVMCI_CHECK); JVMCI_event_3("relocating (narrow metaspace constant) at " PTR_FORMAT "/" PTR_FORMAT, p2i(pc), p2i(operand)); -#else - JVMCI_ERROR("compressed Klass* on 32bit"); -#endif } else { address operand = Assembler::locate_operand(pc, Assembler::imm_operand); *((void**) operand) = record_metadata_reference(_instructions, operand, stream, tag, JVMCI_CHECK); diff --git a/src/hotspot/cpu/x86/methodHandles_x86.cpp b/src/hotspot/cpu/x86/methodHandles_x86.cpp index b921a157a52..54376c6ad9a 100644 --- a/src/hotspot/cpu/x86/methodHandles_x86.cpp +++ b/src/hotspot/cpu/x86/methodHandles_x86.cpp @@ -561,7 +561,6 @@ void trace_method_handle_stub(const char* adaptername, for (int i = 0; i < saved_regs_count; i++) { Register r = as_Register(i); // The registers are stored in reverse order on the stack (by pusha). -#ifdef AMD64 int num_regs = UseAPX ? 32 : 16; assert(Register::available_gp_registers() == num_regs, "sanity"); if (r == rsp) { @@ -570,9 +569,6 @@ void trace_method_handle_stub(const char* adaptername, } else { ls.print("%3s=" PTR_FORMAT, r->name(), saved_regs[((saved_regs_count - 1) - i)]); } -#else - ls.print("%3s=" PTR_FORMAT, r->name(), saved_regs[((saved_regs_count - 1) - i)]); -#endif if ((i + 1) % 4 == 0) { ls.cr(); } else { diff --git a/src/hotspot/cpu/x86/relocInfo_x86.cpp b/src/hotspot/cpu/x86/relocInfo_x86.cpp index a447c5aca9d..6ab2d9f77a3 100644 --- a/src/hotspot/cpu/x86/relocInfo_x86.cpp +++ b/src/hotspot/cpu/x86/relocInfo_x86.cpp @@ -36,7 +36,6 @@ void Relocation::pd_set_data_value(address x, bool verify_only) { -#ifdef AMD64 typedef Assembler::WhichOperand WhichOperand; WhichOperand which = (WhichOperand) format(); // that is, disp32 or imm, call32, narrow oop assert(which == Assembler::disp32_operand || @@ -76,13 +75,6 @@ void Relocation::pd_set_data_value(address x, bool verify_only) { *(int32_t*) disp = checked_cast(x - next_ip); } } -#else - if (verify_only) { - guarantee(*pd_address_in_code() == x, "instructions must match"); - } else { - *pd_address_in_code() = x; - } -#endif // AMD64 } @@ -150,22 +142,17 @@ address* Relocation::pd_address_in_code() { assert(is_data(), "must be a DataRelocation"); typedef Assembler::WhichOperand WhichOperand; WhichOperand which = (WhichOperand) format(); // that is, disp32 or imm/imm32 -#ifdef AMD64 assert(which == Assembler::disp32_operand || which == Assembler::call32_operand || which == Assembler::imm_operand, "format unpacks ok"); // The "address" in the code is a displacement can't return it as // and address* since it is really a jint* guarantee(which == Assembler::imm_operand, "must be immediate operand"); -#else - assert(which == Assembler::disp32_operand || which == Assembler::imm_operand, "format unpacks ok"); -#endif // AMD64 return (address*) Assembler::locate_operand(addr(), which); } address Relocation::pd_get_address_from_code() { -#ifdef AMD64 // All embedded Intel addresses are stored in 32-bit words. // Since the addr points at the start of the instruction, // we must parse the instruction a bit to find the embedded word. @@ -182,7 +169,6 @@ address Relocation::pd_get_address_from_code() { address a = next_ip + *(int32_t*) disp; return a; } -#endif // AMD64 return *pd_address_in_code(); } diff --git a/src/hotspot/cpu/x86/relocInfo_x86.hpp b/src/hotspot/cpu/x86/relocInfo_x86.hpp index d3f213a6686..79b9ef10905 100644 --- a/src/hotspot/cpu/x86/relocInfo_x86.hpp +++ b/src/hotspot/cpu/x86/relocInfo_x86.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, 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 @@ -32,12 +32,8 @@ offset_unit = 1, // Encodes Assembler::disp32_operand vs. Assembler::imm32_operand. -#ifndef AMD64 - format_width = 1 -#else // vs Assembler::narrow_oop_operand and ZGC barrier encodings. format_width = 3 -#endif }; public: diff --git a/src/hotspot/cpu/x86/vm_version_x86.cpp b/src/hotspot/cpu/x86/vm_version_x86.cpp index 213e988a581..4961aed61c3 100644 --- a/src/hotspot/cpu/x86/vm_version_x86.cpp +++ b/src/hotspot/cpu/x86/vm_version_x86.cpp @@ -1260,13 +1260,11 @@ void VM_Version::get_processor_features() { // Kyber Intrinsics // Currently we only have them for AVX512 -#ifdef _LP64 if (supports_evex() && supports_avx512bw()) { if (FLAG_IS_DEFAULT(UseKyberIntrinsics)) { UseKyberIntrinsics = true; } } else -#endif if (UseKyberIntrinsics) { warning("Intrinsics for ML-KEM are not available on this CPU."); FLAG_SET_DEFAULT(UseKyberIntrinsics, false); diff --git a/src/hotspot/cpu/x86/x86.ad b/src/hotspot/cpu/x86/x86.ad index efe0482e095..2f19e76baf2 100644 --- a/src/hotspot/cpu/x86/x86.ad +++ b/src/hotspot/cpu/x86/x86.ad @@ -22,7 +22,7 @@ // // -// X86 Common Architecture Description File +// X86 AMD64 Architecture Description File //----------REGISTER DEFINITION BLOCK------------------------------------------ // This information is used by the matcher and the register allocator to @@ -59,6 +59,166 @@ register %{ // // The encoding number is the actual bit-pattern placed into the opcodes. +// General Registers +// R8-R15 must be encoded with REX. (RSP, RBP, RSI, RDI need REX when +// used as byte registers) + +// Previously set RBX, RSI, and RDI as save-on-entry for java code +// Turn off SOE in java-code due to frequent use of uncommon-traps. +// Now that allocator is better, turn on RSI and RDI as SOE registers. + +reg_def RAX (SOC, SOC, Op_RegI, 0, rax->as_VMReg()); +reg_def RAX_H(SOC, SOC, Op_RegI, 0, rax->as_VMReg()->next()); + +reg_def RCX (SOC, SOC, Op_RegI, 1, rcx->as_VMReg()); +reg_def RCX_H(SOC, SOC, Op_RegI, 1, rcx->as_VMReg()->next()); + +reg_def RDX (SOC, SOC, Op_RegI, 2, rdx->as_VMReg()); +reg_def RDX_H(SOC, SOC, Op_RegI, 2, rdx->as_VMReg()->next()); + +reg_def RBX (SOC, SOE, Op_RegI, 3, rbx->as_VMReg()); +reg_def RBX_H(SOC, SOE, Op_RegI, 3, rbx->as_VMReg()->next()); + +reg_def RSP (NS, NS, Op_RegI, 4, rsp->as_VMReg()); +reg_def RSP_H(NS, NS, Op_RegI, 4, rsp->as_VMReg()->next()); + +// now that adapter frames are gone RBP is always saved and restored by the prolog/epilog code +reg_def RBP (NS, SOE, Op_RegI, 5, rbp->as_VMReg()); +reg_def RBP_H(NS, SOE, Op_RegI, 5, rbp->as_VMReg()->next()); + +#ifdef _WIN64 + +reg_def RSI (SOC, SOE, Op_RegI, 6, rsi->as_VMReg()); +reg_def RSI_H(SOC, SOE, Op_RegI, 6, rsi->as_VMReg()->next()); + +reg_def RDI (SOC, SOE, Op_RegI, 7, rdi->as_VMReg()); +reg_def RDI_H(SOC, SOE, Op_RegI, 7, rdi->as_VMReg()->next()); + +#else + +reg_def RSI (SOC, SOC, Op_RegI, 6, rsi->as_VMReg()); +reg_def RSI_H(SOC, SOC, Op_RegI, 6, rsi->as_VMReg()->next()); + +reg_def RDI (SOC, SOC, Op_RegI, 7, rdi->as_VMReg()); +reg_def RDI_H(SOC, SOC, Op_RegI, 7, rdi->as_VMReg()->next()); + +#endif + +reg_def R8 (SOC, SOC, Op_RegI, 8, r8->as_VMReg()); +reg_def R8_H (SOC, SOC, Op_RegI, 8, r8->as_VMReg()->next()); + +reg_def R9 (SOC, SOC, Op_RegI, 9, r9->as_VMReg()); +reg_def R9_H (SOC, SOC, Op_RegI, 9, r9->as_VMReg()->next()); + +reg_def R10 (SOC, SOC, Op_RegI, 10, r10->as_VMReg()); +reg_def R10_H(SOC, SOC, Op_RegI, 10, r10->as_VMReg()->next()); + +reg_def R11 (SOC, SOC, Op_RegI, 11, r11->as_VMReg()); +reg_def R11_H(SOC, SOC, Op_RegI, 11, r11->as_VMReg()->next()); + +reg_def R12 (SOC, SOE, Op_RegI, 12, r12->as_VMReg()); +reg_def R12_H(SOC, SOE, Op_RegI, 12, r12->as_VMReg()->next()); + +reg_def R13 (SOC, SOE, Op_RegI, 13, r13->as_VMReg()); +reg_def R13_H(SOC, SOE, Op_RegI, 13, r13->as_VMReg()->next()); + +reg_def R14 (SOC, SOE, Op_RegI, 14, r14->as_VMReg()); +reg_def R14_H(SOC, SOE, Op_RegI, 14, r14->as_VMReg()->next()); + +reg_def R15 (SOC, SOE, Op_RegI, 15, r15->as_VMReg()); +reg_def R15_H(SOC, SOE, Op_RegI, 15, r15->as_VMReg()->next()); + +reg_def R16 (SOC, SOC, Op_RegI, 16, r16->as_VMReg()); +reg_def R16_H(SOC, SOC, Op_RegI, 16, r16->as_VMReg()->next()); + +reg_def R17 (SOC, SOC, Op_RegI, 17, r17->as_VMReg()); +reg_def R17_H(SOC, SOC, Op_RegI, 17, r17->as_VMReg()->next()); + +reg_def R18 (SOC, SOC, Op_RegI, 18, r18->as_VMReg()); +reg_def R18_H(SOC, SOC, Op_RegI, 18, r18->as_VMReg()->next()); + +reg_def R19 (SOC, SOC, Op_RegI, 19, r19->as_VMReg()); +reg_def R19_H(SOC, SOC, Op_RegI, 19, r19->as_VMReg()->next()); + +reg_def R20 (SOC, SOC, Op_RegI, 20, r20->as_VMReg()); +reg_def R20_H(SOC, SOC, Op_RegI, 20, r20->as_VMReg()->next()); + +reg_def R21 (SOC, SOC, Op_RegI, 21, r21->as_VMReg()); +reg_def R21_H(SOC, SOC, Op_RegI, 21, r21->as_VMReg()->next()); + +reg_def R22 (SOC, SOC, Op_RegI, 22, r22->as_VMReg()); +reg_def R22_H(SOC, SOC, Op_RegI, 22, r22->as_VMReg()->next()); + +reg_def R23 (SOC, SOC, Op_RegI, 23, r23->as_VMReg()); +reg_def R23_H(SOC, SOC, Op_RegI, 23, r23->as_VMReg()->next()); + +reg_def R24 (SOC, SOC, Op_RegI, 24, r24->as_VMReg()); +reg_def R24_H(SOC, SOC, Op_RegI, 24, r24->as_VMReg()->next()); + +reg_def R25 (SOC, SOC, Op_RegI, 25, r25->as_VMReg()); +reg_def R25_H(SOC, SOC, Op_RegI, 25, r25->as_VMReg()->next()); + +reg_def R26 (SOC, SOC, Op_RegI, 26, r26->as_VMReg()); +reg_def R26_H(SOC, SOC, Op_RegI, 26, r26->as_VMReg()->next()); + +reg_def R27 (SOC, SOC, Op_RegI, 27, r27->as_VMReg()); +reg_def R27_H(SOC, SOC, Op_RegI, 27, r27->as_VMReg()->next()); + +reg_def R28 (SOC, SOC, Op_RegI, 28, r28->as_VMReg()); +reg_def R28_H(SOC, SOC, Op_RegI, 28, r28->as_VMReg()->next()); + +reg_def R29 (SOC, SOC, Op_RegI, 29, r29->as_VMReg()); +reg_def R29_H(SOC, SOC, Op_RegI, 29, r29->as_VMReg()->next()); + +reg_def R30 (SOC, SOC, Op_RegI, 30, r30->as_VMReg()); +reg_def R30_H(SOC, SOC, Op_RegI, 30, r30->as_VMReg()->next()); + +reg_def R31 (SOC, SOC, Op_RegI, 31, r31->as_VMReg()); +reg_def R31_H(SOC, SOC, Op_RegI, 31, r31->as_VMReg()->next()); + +// Floating Point Registers + +// Specify priority of register selection within phases of register +// allocation. Highest priority is first. A useful heuristic is to +// give registers a low priority when they are required by machine +// instructions, like EAX and EDX on I486, and choose no-save registers +// before save-on-call, & save-on-call before save-on-entry. Registers +// which participate in fixed calling sequences should come last. +// Registers which are used as pairs must fall on an even boundary. + +alloc_class chunk0(R10, R10_H, + R11, R11_H, + R8, R8_H, + R9, R9_H, + R12, R12_H, + RCX, RCX_H, + RBX, RBX_H, + RDI, RDI_H, + RDX, RDX_H, + RSI, RSI_H, + RAX, RAX_H, + RBP, RBP_H, + R13, R13_H, + R14, R14_H, + R15, R15_H, + R16, R16_H, + R17, R17_H, + R18, R18_H, + R19, R19_H, + R20, R20_H, + R21, R21_H, + R22, R22_H, + R23, R23_H, + R24, R24_H, + R25, R25_H, + R26, R26_H, + R27, R27_H, + R28, R28_H, + R29, R29_H, + R30, R30_H, + R31, R31_H, + RSP, RSP_H); + // XMM registers. 512-bit registers or 8 words each, labeled (a)-p. // Word a in each register holds a Float, words ab hold a Double. // The whole registers are used in SSE4.2 version intrinsics, @@ -643,6 +803,198 @@ reg_def K7 (SOC, SOC, Op_RegI, 7, k7->as_VMReg()); reg_def K7_H (SOC, SOC, Op_RegI, 7, k7->as_VMReg()->next()); +//----------Architecture Description Register Classes-------------------------- +// Several register classes are automatically defined based upon information in +// this architecture description. +// 1) reg_class inline_cache_reg ( /* as def'd in frame section */ ) +// 2) reg_class stack_slots( /* one chunk of stack-based "registers" */ ) +// + +// Empty register class. +reg_class no_reg(); + +// Class for all pointer/long registers including APX extended GPRs. +reg_class all_reg(RAX, RAX_H, + RDX, RDX_H, + RBP, RBP_H, + RDI, RDI_H, + RSI, RSI_H, + RCX, RCX_H, + RBX, RBX_H, + RSP, RSP_H, + R8, R8_H, + R9, R9_H, + R10, R10_H, + R11, R11_H, + R12, R12_H, + R13, R13_H, + R14, R14_H, + R15, R15_H, + R16, R16_H, + R17, R17_H, + R18, R18_H, + R19, R19_H, + R20, R20_H, + R21, R21_H, + R22, R22_H, + R23, R23_H, + R24, R24_H, + R25, R25_H, + R26, R26_H, + R27, R27_H, + R28, R28_H, + R29, R29_H, + R30, R30_H, + R31, R31_H); + +// Class for all int registers including APX extended GPRs. +reg_class all_int_reg(RAX + RDX, + RBP, + RDI, + RSI, + RCX, + RBX, + R8, + R9, + R10, + R11, + R12, + R13, + R14, + R16, + R17, + R18, + R19, + R20, + R21, + R22, + R23, + R24, + R25, + R26, + R27, + R28, + R29, + R30, + R31); + +// Class for all pointer registers +reg_class any_reg %{ + return _ANY_REG_mask; +%} + +// Class for all pointer registers (excluding RSP) +reg_class ptr_reg %{ + return _PTR_REG_mask; +%} + +// Class for all pointer registers (excluding RSP and RBP) +reg_class ptr_reg_no_rbp %{ + return _PTR_REG_NO_RBP_mask; +%} + +// Class for all pointer registers (excluding RAX and RSP) +reg_class ptr_no_rax_reg %{ + return _PTR_NO_RAX_REG_mask; +%} + +// Class for all pointer registers (excluding RAX, RBX, and RSP) +reg_class ptr_no_rax_rbx_reg %{ + return _PTR_NO_RAX_RBX_REG_mask; +%} + +// Class for all long registers (excluding RSP) +reg_class long_reg %{ + return _LONG_REG_mask; +%} + +// Class for all long registers (excluding RAX, RDX and RSP) +reg_class long_no_rax_rdx_reg %{ + return _LONG_NO_RAX_RDX_REG_mask; +%} + +// Class for all long registers (excluding RCX and RSP) +reg_class long_no_rcx_reg %{ + return _LONG_NO_RCX_REG_mask; +%} + +// Class for all long registers (excluding RBP and R13) +reg_class long_no_rbp_r13_reg %{ + return _LONG_NO_RBP_R13_REG_mask; +%} + +// Class for all int registers (excluding RSP) +reg_class int_reg %{ + return _INT_REG_mask; +%} + +// Class for all int registers (excluding RAX, RDX, and RSP) +reg_class int_no_rax_rdx_reg %{ + return _INT_NO_RAX_RDX_REG_mask; +%} + +// Class for all int registers (excluding RCX and RSP) +reg_class int_no_rcx_reg %{ + return _INT_NO_RCX_REG_mask; +%} + +// Class for all int registers (excluding RBP and R13) +reg_class int_no_rbp_r13_reg %{ + return _INT_NO_RBP_R13_REG_mask; +%} + +// Singleton class for RAX pointer register +reg_class ptr_rax_reg(RAX, RAX_H); + +// Singleton class for RBX pointer register +reg_class ptr_rbx_reg(RBX, RBX_H); + +// Singleton class for RSI pointer register +reg_class ptr_rsi_reg(RSI, RSI_H); + +// Singleton class for RBP pointer register +reg_class ptr_rbp_reg(RBP, RBP_H); + +// Singleton class for RDI pointer register +reg_class ptr_rdi_reg(RDI, RDI_H); + +// Singleton class for stack pointer +reg_class ptr_rsp_reg(RSP, RSP_H); + +// Singleton class for TLS pointer +reg_class ptr_r15_reg(R15, R15_H); + +// Singleton class for RAX long register +reg_class long_rax_reg(RAX, RAX_H); + +// Singleton class for RCX long register +reg_class long_rcx_reg(RCX, RCX_H); + +// Singleton class for RDX long register +reg_class long_rdx_reg(RDX, RDX_H); + +// Singleton class for R11 long register +reg_class long_r11_reg(R11, R11_H); + +// Singleton class for RAX int register +reg_class int_rax_reg(RAX); + +// Singleton class for RBX int register +reg_class int_rbx_reg(RBX); + +// Singleton class for RCX int register +reg_class int_rcx_reg(RCX); + +// Singleton class for RDX int register +reg_class int_rdx_reg(RDX); + +// Singleton class for RDI int register +reg_class int_rdi_reg(RDI); + +// Singleton class for instruction pointer +// reg_class ip_reg(RIP); + alloc_class chunk1(XMM0, XMM0b, XMM0c, XMM0d, XMM0e, XMM0f, XMM0g, XMM0h, XMM0i, XMM0j, XMM0k, XMM0l, XMM0m, XMM0n, XMM0o, XMM0p, XMM1, XMM1b, XMM1c, XMM1d, XMM1e, XMM1f, XMM1g, XMM1h, XMM1i, XMM1j, XMM1k, XMM1l, XMM1m, XMM1n, XMM1o, XMM1p, XMM2, XMM2b, XMM2c, XMM2d, XMM2e, XMM2f, XMM2g, XMM2h, XMM2i, XMM2j, XMM2k, XMM2l, XMM2m, XMM2n, XMM2o, XMM2p, @@ -703,7 +1055,6 @@ reg_class vectmask_reg_K7(K7, K7_H); // flags allocation class should be last. alloc_class chunk3(RFLAGS); - // Singleton class for condition codes reg_class int_flags(RFLAGS); @@ -1093,6 +1444,7 @@ reg_class_dynamic vectorz_reg (vectorz_reg_evex, vectorz_reg_legacy, %{ VM_Ver reg_class_dynamic vectorz_reg_vl(vectorz_reg_evex, vectorz_reg_legacy, %{ VM_Version::supports_evex() && VM_Version::supports_avx512vl() %} ); reg_class xmm0_reg(XMM0, XMM0b, XMM0c, XMM0d); + %} @@ -1100,6 +1452,1287 @@ reg_class xmm0_reg(XMM0, XMM0b, XMM0c, XMM0d); // This is a block of C++ code which provides values, functions, and // definitions necessary in the rest of the architecture description +source_hpp %{ + +#include "peephole_x86_64.hpp" + +bool castLL_is_imm32(const Node* n); + +%} + +source %{ + +bool castLL_is_imm32(const Node* n) { + assert(n->is_CastLL(), "must be a CastLL"); + const TypeLong* t = n->bottom_type()->is_long(); + return (t->_lo == min_jlong || Assembler::is_simm32(t->_lo)) && (t->_hi == max_jlong || Assembler::is_simm32(t->_hi)); +} + +%} + +// Register masks +source_hpp %{ + +extern RegMask _ANY_REG_mask; +extern RegMask _PTR_REG_mask; +extern RegMask _PTR_REG_NO_RBP_mask; +extern RegMask _PTR_NO_RAX_REG_mask; +extern RegMask _PTR_NO_RAX_RBX_REG_mask; +extern RegMask _LONG_REG_mask; +extern RegMask _LONG_NO_RAX_RDX_REG_mask; +extern RegMask _LONG_NO_RCX_REG_mask; +extern RegMask _LONG_NO_RBP_R13_REG_mask; +extern RegMask _INT_REG_mask; +extern RegMask _INT_NO_RAX_RDX_REG_mask; +extern RegMask _INT_NO_RCX_REG_mask; +extern RegMask _INT_NO_RBP_R13_REG_mask; +extern RegMask _FLOAT_REG_mask; + +extern RegMask _STACK_OR_PTR_REG_mask; +extern RegMask _STACK_OR_LONG_REG_mask; +extern RegMask _STACK_OR_INT_REG_mask; + +inline const RegMask& STACK_OR_PTR_REG_mask() { return _STACK_OR_PTR_REG_mask; } +inline const RegMask& STACK_OR_LONG_REG_mask() { return _STACK_OR_LONG_REG_mask; } +inline const RegMask& STACK_OR_INT_REG_mask() { return _STACK_OR_INT_REG_mask; } + +%} + +source %{ +#define RELOC_IMM64 Assembler::imm_operand +#define RELOC_DISP32 Assembler::disp32_operand + +#define __ masm-> + +RegMask _ANY_REG_mask; +RegMask _PTR_REG_mask; +RegMask _PTR_REG_NO_RBP_mask; +RegMask _PTR_NO_RAX_REG_mask; +RegMask _PTR_NO_RAX_RBX_REG_mask; +RegMask _LONG_REG_mask; +RegMask _LONG_NO_RAX_RDX_REG_mask; +RegMask _LONG_NO_RCX_REG_mask; +RegMask _LONG_NO_RBP_R13_REG_mask; +RegMask _INT_REG_mask; +RegMask _INT_NO_RAX_RDX_REG_mask; +RegMask _INT_NO_RCX_REG_mask; +RegMask _INT_NO_RBP_R13_REG_mask; +RegMask _FLOAT_REG_mask; +RegMask _STACK_OR_PTR_REG_mask; +RegMask _STACK_OR_LONG_REG_mask; +RegMask _STACK_OR_INT_REG_mask; + +static bool need_r12_heapbase() { + return UseCompressedOops; +} + +void reg_mask_init() { + constexpr Register egprs[] = {r16, r17, r18, r19, r20, r21, r22, r23, r24, r25, r26, r27, r28, r29, r30, r31}; + + // _ALL_REG_mask is generated by adlc from the all_reg register class below. + // We derive a number of subsets from it. + _ANY_REG_mask.assignFrom(_ALL_REG_mask); + + if (PreserveFramePointer) { + _ANY_REG_mask.remove(OptoReg::as_OptoReg(rbp->as_VMReg())); + _ANY_REG_mask.remove(OptoReg::as_OptoReg(rbp->as_VMReg()->next())); + } + if (need_r12_heapbase()) { + _ANY_REG_mask.remove(OptoReg::as_OptoReg(r12->as_VMReg())); + _ANY_REG_mask.remove(OptoReg::as_OptoReg(r12->as_VMReg()->next())); + } + + _PTR_REG_mask.assignFrom(_ANY_REG_mask); + _PTR_REG_mask.remove(OptoReg::as_OptoReg(rsp->as_VMReg())); + _PTR_REG_mask.remove(OptoReg::as_OptoReg(rsp->as_VMReg()->next())); + _PTR_REG_mask.remove(OptoReg::as_OptoReg(r15->as_VMReg())); + _PTR_REG_mask.remove(OptoReg::as_OptoReg(r15->as_VMReg()->next())); + if (!UseAPX) { + for (uint i = 0; i < sizeof(egprs)/sizeof(Register); i++) { + _PTR_REG_mask.remove(OptoReg::as_OptoReg(egprs[i]->as_VMReg())); + _PTR_REG_mask.remove(OptoReg::as_OptoReg(egprs[i]->as_VMReg()->next())); + } + } + + _STACK_OR_PTR_REG_mask.assignFrom(_PTR_REG_mask); + _STACK_OR_PTR_REG_mask.or_with(STACK_OR_STACK_SLOTS_mask()); + + _PTR_REG_NO_RBP_mask.assignFrom(_PTR_REG_mask); + _PTR_REG_NO_RBP_mask.remove(OptoReg::as_OptoReg(rbp->as_VMReg())); + _PTR_REG_NO_RBP_mask.remove(OptoReg::as_OptoReg(rbp->as_VMReg()->next())); + + _PTR_NO_RAX_REG_mask.assignFrom(_PTR_REG_mask); + _PTR_NO_RAX_REG_mask.remove(OptoReg::as_OptoReg(rax->as_VMReg())); + _PTR_NO_RAX_REG_mask.remove(OptoReg::as_OptoReg(rax->as_VMReg()->next())); + + _PTR_NO_RAX_RBX_REG_mask.assignFrom(_PTR_NO_RAX_REG_mask); + _PTR_NO_RAX_RBX_REG_mask.remove(OptoReg::as_OptoReg(rbx->as_VMReg())); + _PTR_NO_RAX_RBX_REG_mask.remove(OptoReg::as_OptoReg(rbx->as_VMReg()->next())); + + + _LONG_REG_mask.assignFrom(_PTR_REG_mask); + _STACK_OR_LONG_REG_mask.assignFrom(_LONG_REG_mask); + _STACK_OR_LONG_REG_mask.or_with(STACK_OR_STACK_SLOTS_mask()); + + _LONG_NO_RAX_RDX_REG_mask.assignFrom(_LONG_REG_mask); + _LONG_NO_RAX_RDX_REG_mask.remove(OptoReg::as_OptoReg(rax->as_VMReg())); + _LONG_NO_RAX_RDX_REG_mask.remove(OptoReg::as_OptoReg(rax->as_VMReg()->next())); + _LONG_NO_RAX_RDX_REG_mask.remove(OptoReg::as_OptoReg(rdx->as_VMReg())); + _LONG_NO_RAX_RDX_REG_mask.remove(OptoReg::as_OptoReg(rdx->as_VMReg()->next())); + + _LONG_NO_RCX_REG_mask.assignFrom(_LONG_REG_mask); + _LONG_NO_RCX_REG_mask.remove(OptoReg::as_OptoReg(rcx->as_VMReg())); + _LONG_NO_RCX_REG_mask.remove(OptoReg::as_OptoReg(rcx->as_VMReg()->next())); + + _LONG_NO_RBP_R13_REG_mask.assignFrom(_LONG_REG_mask); + _LONG_NO_RBP_R13_REG_mask.remove(OptoReg::as_OptoReg(rbp->as_VMReg())); + _LONG_NO_RBP_R13_REG_mask.remove(OptoReg::as_OptoReg(rbp->as_VMReg()->next())); + _LONG_NO_RBP_R13_REG_mask.remove(OptoReg::as_OptoReg(r13->as_VMReg())); + _LONG_NO_RBP_R13_REG_mask.remove(OptoReg::as_OptoReg(r13->as_VMReg()->next())); + + _INT_REG_mask.assignFrom(_ALL_INT_REG_mask); + if (!UseAPX) { + for (uint i = 0; i < sizeof(egprs)/sizeof(Register); i++) { + _INT_REG_mask.remove(OptoReg::as_OptoReg(egprs[i]->as_VMReg())); + } + } + + if (PreserveFramePointer) { + _INT_REG_mask.remove(OptoReg::as_OptoReg(rbp->as_VMReg())); + } + if (need_r12_heapbase()) { + _INT_REG_mask.remove(OptoReg::as_OptoReg(r12->as_VMReg())); + } + + _STACK_OR_INT_REG_mask.assignFrom(_INT_REG_mask); + _STACK_OR_INT_REG_mask.or_with(STACK_OR_STACK_SLOTS_mask()); + + _INT_NO_RAX_RDX_REG_mask.assignFrom(_INT_REG_mask); + _INT_NO_RAX_RDX_REG_mask.remove(OptoReg::as_OptoReg(rax->as_VMReg())); + _INT_NO_RAX_RDX_REG_mask.remove(OptoReg::as_OptoReg(rdx->as_VMReg())); + + _INT_NO_RCX_REG_mask.assignFrom(_INT_REG_mask); + _INT_NO_RCX_REG_mask.remove(OptoReg::as_OptoReg(rcx->as_VMReg())); + + _INT_NO_RBP_R13_REG_mask.assignFrom(_INT_REG_mask); + _INT_NO_RBP_R13_REG_mask.remove(OptoReg::as_OptoReg(rbp->as_VMReg())); + _INT_NO_RBP_R13_REG_mask.remove(OptoReg::as_OptoReg(r13->as_VMReg())); + + // _FLOAT_REG_LEGACY_mask/_FLOAT_REG_EVEX_mask is generated by adlc + // from the float_reg_legacy/float_reg_evex register class. + _FLOAT_REG_mask.assignFrom(VM_Version::supports_evex() ? _FLOAT_REG_EVEX_mask : _FLOAT_REG_LEGACY_mask); +} + +static bool generate_vzeroupper(Compile* C) { + return (VM_Version::supports_vzeroupper() && (C->max_vector_size() > 16 || C->clear_upper_avx() == true)) ? true: false; // Generate vzeroupper +} + +static int clear_avx_size() { + return generate_vzeroupper(Compile::current()) ? 3: 0; // vzeroupper +} + +// !!!!! Special hack to get all types of calls to specify the byte offset +// from the start of the call to the point where the return address +// will point. +int MachCallStaticJavaNode::ret_addr_offset() +{ + int offset = 5; // 5 bytes from start of call to where return address points + offset += clear_avx_size(); + return offset; +} + +int MachCallDynamicJavaNode::ret_addr_offset() +{ + int offset = 15; // 15 bytes from start of call to where return address points + offset += clear_avx_size(); + return offset; +} + +int MachCallRuntimeNode::ret_addr_offset() { + int offset = 13; // movq r10,#addr; callq (r10) + if (this->ideal_Opcode() != Op_CallLeafVector) { + offset += clear_avx_size(); + } + return offset; +} +// +// Compute padding required for nodes which need alignment +// + +// The address of the call instruction needs to be 4-byte aligned to +// ensure that it does not span a cache line so that it can be patched. +int CallStaticJavaDirectNode::compute_padding(int current_offset) const +{ + current_offset += clear_avx_size(); // skip vzeroupper + current_offset += 1; // skip call opcode byte + return align_up(current_offset, alignment_required()) - current_offset; +} + +// The address of the call instruction needs to be 4-byte aligned to +// ensure that it does not span a cache line so that it can be patched. +int CallDynamicJavaDirectNode::compute_padding(int current_offset) const +{ + current_offset += clear_avx_size(); // skip vzeroupper + current_offset += 11; // skip movq instruction + call opcode byte + return align_up(current_offset, alignment_required()) - current_offset; +} + +// This could be in MacroAssembler but it's fairly C2 specific +static void emit_cmpfp_fixup(MacroAssembler* masm) { + Label exit; + __ jccb(Assembler::noParity, exit); + __ pushf(); + // + // comiss/ucomiss instructions set ZF,PF,CF flags and + // zero OF,AF,SF for NaN values. + // Fixup flags by zeroing ZF,PF so that compare of NaN + // values returns 'less than' result (CF is set). + // Leave the rest of flags unchanged. + // + // 7 6 5 4 3 2 1 0 + // |S|Z|r|A|r|P|r|C| (r - reserved bit) + // 0 0 1 0 1 0 1 1 (0x2B) + // + __ andq(Address(rsp, 0), 0xffffff2b); + __ popf(); + __ bind(exit); +} + +static void emit_cmpfp3(MacroAssembler* masm, Register dst) { + Label done; + __ movl(dst, -1); + __ jcc(Assembler::parity, done); + __ jcc(Assembler::below, done); + __ setcc(Assembler::notEqual, dst); + __ bind(done); +} + +// Math.min() # Math.max() +// -------------------------- +// ucomis[s/d] # +// ja -> b # a +// jp -> NaN # NaN +// jb -> a # b +// je # +// |-jz -> a | b # a & b +// | -> a # +static void emit_fp_min_max(MacroAssembler* masm, XMMRegister dst, + XMMRegister a, XMMRegister b, + XMMRegister xmmt, Register rt, + bool min, bool single) { + + Label nan, zero, below, above, done; + + if (single) + __ ucomiss(a, b); + else + __ ucomisd(a, b); + + if (dst->encoding() != (min ? b : a)->encoding()) + __ jccb(Assembler::above, above); // CF=0 & ZF=0 + else + __ jccb(Assembler::above, done); + + __ jccb(Assembler::parity, nan); // PF=1 + __ jccb(Assembler::below, below); // CF=1 + + // equal + __ vpxor(xmmt, xmmt, xmmt, Assembler::AVX_128bit); + if (single) { + __ ucomiss(a, xmmt); + __ jccb(Assembler::equal, zero); + + __ movflt(dst, a); + __ jmp(done); + } + else { + __ ucomisd(a, xmmt); + __ jccb(Assembler::equal, zero); + + __ movdbl(dst, a); + __ jmp(done); + } + + __ bind(zero); + if (min) + __ vpor(dst, a, b, Assembler::AVX_128bit); + else + __ vpand(dst, a, b, Assembler::AVX_128bit); + + __ jmp(done); + + __ bind(above); + if (single) + __ movflt(dst, min ? b : a); + else + __ movdbl(dst, min ? b : a); + + __ jmp(done); + + __ bind(nan); + if (single) { + __ movl(rt, 0x7fc00000); // Float.NaN + __ movdl(dst, rt); + } + else { + __ mov64(rt, 0x7ff8000000000000L); // Double.NaN + __ movdq(dst, rt); + } + __ jmp(done); + + __ bind(below); + if (single) + __ movflt(dst, min ? a : b); + else + __ movdbl(dst, min ? a : b); + + __ bind(done); +} + +//============================================================================= +const RegMask& MachConstantBaseNode::_out_RegMask = RegMask::EMPTY; + +int ConstantTable::calculate_table_base_offset() const { + return 0; // absolute addressing, no offset +} + +bool MachConstantBaseNode::requires_postalloc_expand() const { return false; } +void MachConstantBaseNode::postalloc_expand(GrowableArray *nodes, PhaseRegAlloc *ra_) { + ShouldNotReachHere(); +} + +void MachConstantBaseNode::emit(C2_MacroAssembler* masm, PhaseRegAlloc* ra_) const { + // Empty encoding +} + +uint MachConstantBaseNode::size(PhaseRegAlloc* ra_) const { + return 0; +} + +#ifndef PRODUCT +void MachConstantBaseNode::format(PhaseRegAlloc* ra_, outputStream* st) const { + st->print("# MachConstantBaseNode (empty encoding)"); +} +#endif + + +//============================================================================= +#ifndef PRODUCT +void MachPrologNode::format(PhaseRegAlloc* ra_, outputStream* st) const { + Compile* C = ra_->C; + + int framesize = C->output()->frame_size_in_bytes(); + int bangsize = C->output()->bang_size_in_bytes(); + assert((framesize & (StackAlignmentInBytes-1)) == 0, "frame size not aligned"); + // Remove wordSize for return addr which is already pushed. + framesize -= wordSize; + + if (C->output()->need_stack_bang(bangsize)) { + framesize -= wordSize; + st->print("# stack bang (%d bytes)", bangsize); + st->print("\n\t"); + st->print("pushq rbp\t# Save rbp"); + if (PreserveFramePointer) { + st->print("\n\t"); + st->print("movq rbp, rsp\t# Save the caller's SP into rbp"); + } + if (framesize) { + st->print("\n\t"); + st->print("subq rsp, #%d\t# Create frame",framesize); + } + } else { + st->print("subq rsp, #%d\t# Create frame",framesize); + st->print("\n\t"); + framesize -= wordSize; + st->print("movq [rsp + #%d], rbp\t# Save rbp",framesize); + if (PreserveFramePointer) { + st->print("\n\t"); + st->print("movq rbp, rsp\t# Save the caller's SP into rbp"); + if (framesize > 0) { + st->print("\n\t"); + st->print("addq rbp, #%d", framesize); + } + } + } + + if (VerifyStackAtCalls) { + st->print("\n\t"); + framesize -= wordSize; + st->print("movq [rsp + #%d], 0xbadb100d\t# Majik cookie for stack depth check",framesize); +#ifdef ASSERT + st->print("\n\t"); + st->print("# stack alignment check"); +#endif + } + if (C->stub_function() != nullptr) { + st->print("\n\t"); + st->print("cmpl [r15_thread + #disarmed_guard_value_offset], #disarmed_guard_value\t"); + st->print("\n\t"); + st->print("je fast_entry\t"); + st->print("\n\t"); + st->print("call #nmethod_entry_barrier_stub\t"); + st->print("\n\tfast_entry:"); + } + st->cr(); +} +#endif + +void MachPrologNode::emit(C2_MacroAssembler *masm, PhaseRegAlloc *ra_) const { + Compile* C = ra_->C; + + int framesize = C->output()->frame_size_in_bytes(); + int bangsize = C->output()->bang_size_in_bytes(); + + if (C->clinit_barrier_on_entry()) { + assert(VM_Version::supports_fast_class_init_checks(), "sanity"); + assert(!C->method()->holder()->is_not_initialized(), "initialization should have been started"); + + Label L_skip_barrier; + Register klass = rscratch1; + + __ mov_metadata(klass, C->method()->holder()->constant_encoding()); + __ clinit_barrier(klass, &L_skip_barrier /*L_fast_path*/); + + __ jump(RuntimeAddress(SharedRuntime::get_handle_wrong_method_stub())); // slow path + + __ bind(L_skip_barrier); + } + + __ verified_entry(framesize, C->output()->need_stack_bang(bangsize)?bangsize:0, false, C->stub_function() != nullptr); + + C->output()->set_frame_complete(__ offset()); + + if (C->has_mach_constant_base_node()) { + // NOTE: We set the table base offset here because users might be + // emitted before MachConstantBaseNode. + ConstantTable& constant_table = C->output()->constant_table(); + constant_table.set_table_base_offset(constant_table.calculate_table_base_offset()); + } +} + +uint MachPrologNode::size(PhaseRegAlloc* ra_) const +{ + return MachNode::size(ra_); // too many variables; just compute it + // the hard way +} + +int MachPrologNode::reloc() const +{ + return 0; // a large enough number +} + +//============================================================================= +#ifndef PRODUCT +void MachEpilogNode::format(PhaseRegAlloc* ra_, outputStream* st) const +{ + Compile* C = ra_->C; + if (generate_vzeroupper(C)) { + st->print("vzeroupper"); + st->cr(); st->print("\t"); + } + + int framesize = C->output()->frame_size_in_bytes(); + assert((framesize & (StackAlignmentInBytes-1)) == 0, "frame size not aligned"); + // Remove word for return adr already pushed + // and RBP + framesize -= 2*wordSize; + + if (framesize) { + st->print_cr("addq rsp, %d\t# Destroy frame", framesize); + st->print("\t"); + } + + st->print_cr("popq rbp"); + if (do_polling() && C->is_method_compilation()) { + st->print("\t"); + st->print_cr("cmpq rsp, poll_offset[r15_thread] \n\t" + "ja #safepoint_stub\t" + "# Safepoint: poll for GC"); + } +} +#endif + +void MachEpilogNode::emit(C2_MacroAssembler* masm, PhaseRegAlloc* ra_) const +{ + Compile* C = ra_->C; + + if (generate_vzeroupper(C)) { + // Clear upper bits of YMM registers when current compiled code uses + // wide vectors to avoid AVX <-> SSE transition penalty during call. + __ vzeroupper(); + } + + int framesize = C->output()->frame_size_in_bytes(); + assert((framesize & (StackAlignmentInBytes-1)) == 0, "frame size not aligned"); + // Remove word for return adr already pushed + // and RBP + framesize -= 2*wordSize; + + // Note that VerifyStackAtCalls' Majik cookie does not change the frame size popped here + + if (framesize) { + __ addq(rsp, framesize); + } + + __ popq(rbp); + + if (StackReservedPages > 0 && C->has_reserved_stack_access()) { + __ reserved_stack_check(); + } + + if (do_polling() && C->is_method_compilation()) { + Label dummy_label; + Label* code_stub = &dummy_label; + if (!C->output()->in_scratch_emit_size()) { + C2SafepointPollStub* stub = new (C->comp_arena()) C2SafepointPollStub(__ offset()); + C->output()->add_stub(stub); + code_stub = &stub->entry(); + } + __ relocate(relocInfo::poll_return_type); + __ safepoint_poll(*code_stub, true /* at_return */, true /* in_nmethod */); + } +} + +uint MachEpilogNode::size(PhaseRegAlloc* ra_) const +{ + return MachNode::size(ra_); // too many variables; just compute it + // the hard way +} + +int MachEpilogNode::reloc() const +{ + return 2; // a large enough number +} + +const Pipeline* MachEpilogNode::pipeline() const +{ + return MachNode::pipeline_class(); +} + +//============================================================================= + +enum RC { + rc_bad, + rc_int, + rc_kreg, + 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; + + if (r->is_KRegister()) return rc_kreg; + + assert(r->is_XMMRegister(), "must be"); + return rc_float; +} + +// Next two methods are shared by 32- and 64-bit VM. They are defined in x86.ad. +static void vec_mov_helper(C2_MacroAssembler *masm, int src_lo, int dst_lo, + int src_hi, int dst_hi, uint ireg, outputStream* st); + +void vec_spill_helper(C2_MacroAssembler *masm, bool is_load, + int stack_offset, int reg, uint ireg, outputStream* st); + +static void vec_stack_to_stack_helper(C2_MacroAssembler *masm, int src_offset, + int dst_offset, uint ireg, outputStream* st) { + if (masm) { + switch (ireg) { + case Op_VecS: + __ movq(Address(rsp, -8), rax); + __ movl(rax, Address(rsp, src_offset)); + __ movl(Address(rsp, dst_offset), rax); + __ movq(rax, Address(rsp, -8)); + break; + case Op_VecD: + __ pushq(Address(rsp, src_offset)); + __ popq (Address(rsp, dst_offset)); + break; + case Op_VecX: + __ pushq(Address(rsp, src_offset)); + __ popq (Address(rsp, dst_offset)); + __ pushq(Address(rsp, src_offset+8)); + __ popq (Address(rsp, dst_offset+8)); + break; + case Op_VecY: + __ vmovdqu(Address(rsp, -32), xmm0); + __ vmovdqu(xmm0, Address(rsp, src_offset)); + __ vmovdqu(Address(rsp, dst_offset), xmm0); + __ vmovdqu(xmm0, Address(rsp, -32)); + break; + case Op_VecZ: + __ evmovdquq(Address(rsp, -64), xmm0, 2); + __ evmovdquq(xmm0, Address(rsp, src_offset), 2); + __ evmovdquq(Address(rsp, dst_offset), xmm0, 2); + __ evmovdquq(xmm0, Address(rsp, -64), 2); + break; + default: + ShouldNotReachHere(); + } +#ifndef PRODUCT + } else { + switch (ireg) { + case Op_VecS: + st->print("movq [rsp - #8], rax\t# 32-bit mem-mem spill\n\t" + "movl rax, [rsp + #%d]\n\t" + "movl [rsp + #%d], rax\n\t" + "movq rax, [rsp - #8]", + src_offset, dst_offset); + break; + case Op_VecD: + st->print("pushq [rsp + #%d]\t# 64-bit mem-mem spill\n\t" + "popq [rsp + #%d]", + src_offset, dst_offset); + break; + case Op_VecX: + st->print("pushq [rsp + #%d]\t# 128-bit mem-mem spill\n\t" + "popq [rsp + #%d]\n\t" + "pushq [rsp + #%d]\n\t" + "popq [rsp + #%d]", + src_offset, dst_offset, src_offset+8, dst_offset+8); + break; + case Op_VecY: + st->print("vmovdqu [rsp - #32], xmm0\t# 256-bit mem-mem spill\n\t" + "vmovdqu xmm0, [rsp + #%d]\n\t" + "vmovdqu [rsp + #%d], xmm0\n\t" + "vmovdqu xmm0, [rsp - #32]", + src_offset, dst_offset); + break; + case Op_VecZ: + st->print("vmovdqu [rsp - #64], xmm0\t# 512-bit mem-mem spill\n\t" + "vmovdqu xmm0, [rsp + #%d]\n\t" + "vmovdqu [rsp + #%d], xmm0\n\t" + "vmovdqu xmm0, [rsp - #64]", + src_offset, dst_offset); + break; + default: + ShouldNotReachHere(); + } +#endif + } +} + +uint MachSpillCopyNode::implementation(C2_MacroAssembler* masm, + PhaseRegAlloc* ra_, + bool do_size, + outputStream* st) const { + assert(masm != nullptr || st != nullptr, "sanity"); + // 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" ); + + if (src_first == dst_first && src_second == dst_second) { + // Self copy, no move + return 0; + } + if (bottom_type()->isa_vect() != nullptr && bottom_type()->isa_vectmask() == nullptr) { + uint ireg = ideal_reg(); + assert((src_first_rc != rc_int && dst_first_rc != rc_int), "sanity"); + assert((ireg == Op_VecS || ireg == Op_VecD || ireg == Op_VecX || ireg == Op_VecY || ireg == Op_VecZ ), "sanity"); + if( src_first_rc == rc_stack && dst_first_rc == rc_stack ) { + // mem -> mem + int src_offset = ra_->reg2offset(src_first); + int dst_offset = ra_->reg2offset(dst_first); + vec_stack_to_stack_helper(masm, src_offset, dst_offset, ireg, st); + } else if (src_first_rc == rc_float && dst_first_rc == rc_float ) { + vec_mov_helper(masm, src_first, dst_first, src_second, dst_second, ireg, st); + } else if (src_first_rc == rc_float && dst_first_rc == rc_stack ) { + int stack_offset = ra_->reg2offset(dst_first); + vec_spill_helper(masm, false, stack_offset, src_first, ireg, st); + } else if (src_first_rc == rc_stack && dst_first_rc == rc_float ) { + int stack_offset = ra_->reg2offset(src_first); + vec_spill_helper(masm, true, stack_offset, dst_first, ireg, st); + } else { + ShouldNotReachHere(); + } + return 0; + } + if (src_first_rc == rc_stack) { + // mem -> + if (dst_first_rc == rc_stack) { + // mem -> mem + assert(src_second != dst_first, "overlap"); + if ((src_first & 1) == 0 && src_first + 1 == src_second && + (dst_first & 1) == 0 && dst_first + 1 == dst_second) { + // 64-bit + int src_offset = ra_->reg2offset(src_first); + int dst_offset = ra_->reg2offset(dst_first); + if (masm) { + __ pushq(Address(rsp, src_offset)); + __ popq (Address(rsp, dst_offset)); +#ifndef PRODUCT + } else { + st->print("pushq [rsp + #%d]\t# 64-bit mem-mem spill\n\t" + "popq [rsp + #%d]", + src_offset, dst_offset); +#endif + } + } else { + // 32-bit + assert(!((src_first & 1) == 0 && src_first + 1 == src_second), "no transform"); + assert(!((dst_first & 1) == 0 && dst_first + 1 == dst_second), "no transform"); + // No pushl/popl, so: + int src_offset = ra_->reg2offset(src_first); + int dst_offset = ra_->reg2offset(dst_first); + if (masm) { + __ movq(Address(rsp, -8), rax); + __ movl(rax, Address(rsp, src_offset)); + __ movl(Address(rsp, dst_offset), rax); + __ movq(rax, Address(rsp, -8)); +#ifndef PRODUCT + } else { + st->print("movq [rsp - #8], rax\t# 32-bit mem-mem spill\n\t" + "movl rax, [rsp + #%d]\n\t" + "movl [rsp + #%d], rax\n\t" + "movq rax, [rsp - #8]", + src_offset, dst_offset); +#endif + } + } + return 0; + } else if (dst_first_rc == rc_int) { + // mem -> gpr + if ((src_first & 1) == 0 && src_first + 1 == src_second && + (dst_first & 1) == 0 && dst_first + 1 == dst_second) { + // 64-bit + int offset = ra_->reg2offset(src_first); + if (masm) { + __ movq(as_Register(Matcher::_regEncode[dst_first]), Address(rsp, offset)); +#ifndef PRODUCT + } else { + st->print("movq %s, [rsp + #%d]\t# spill", + Matcher::regName[dst_first], + offset); +#endif + } + } else { + // 32-bit + assert(!((src_first & 1) == 0 && src_first + 1 == src_second), "no transform"); + assert(!((dst_first & 1) == 0 && dst_first + 1 == dst_second), "no transform"); + int offset = ra_->reg2offset(src_first); + if (masm) { + __ movl(as_Register(Matcher::_regEncode[dst_first]), Address(rsp, offset)); +#ifndef PRODUCT + } else { + st->print("movl %s, [rsp + #%d]\t# spill", + Matcher::regName[dst_first], + offset); +#endif + } + } + return 0; + } else if (dst_first_rc == rc_float) { + // mem-> xmm + if ((src_first & 1) == 0 && src_first + 1 == src_second && + (dst_first & 1) == 0 && dst_first + 1 == dst_second) { + // 64-bit + int offset = ra_->reg2offset(src_first); + if (masm) { + __ movdbl( as_XMMRegister(Matcher::_regEncode[dst_first]), Address(rsp, offset)); +#ifndef PRODUCT + } else { + st->print("%s %s, [rsp + #%d]\t# spill", + UseXmmLoadAndClearUpper ? "movsd " : "movlpd", + Matcher::regName[dst_first], + offset); +#endif + } + } else { + // 32-bit + assert(!((src_first & 1) == 0 && src_first + 1 == src_second), "no transform"); + assert(!((dst_first & 1) == 0 && dst_first + 1 == dst_second), "no transform"); + int offset = ra_->reg2offset(src_first); + if (masm) { + __ movflt( as_XMMRegister(Matcher::_regEncode[dst_first]), Address(rsp, offset)); +#ifndef PRODUCT + } else { + st->print("movss %s, [rsp + #%d]\t# spill", + Matcher::regName[dst_first], + offset); +#endif + } + } + return 0; + } else if (dst_first_rc == rc_kreg) { + // mem -> kreg + if ((src_first & 1) == 0 && src_first + 1 == src_second && + (dst_first & 1) == 0 && dst_first + 1 == dst_second) { + // 64-bit + int offset = ra_->reg2offset(src_first); + if (masm) { + __ kmov(as_KRegister(Matcher::_regEncode[dst_first]), Address(rsp, offset)); +#ifndef PRODUCT + } else { + st->print("kmovq %s, [rsp + #%d]\t# spill", + Matcher::regName[dst_first], + offset); +#endif + } + } + return 0; + } + } else if (src_first_rc == rc_int) { + // gpr -> + if (dst_first_rc == rc_stack) { + // gpr -> mem + if ((src_first & 1) == 0 && src_first + 1 == src_second && + (dst_first & 1) == 0 && dst_first + 1 == dst_second) { + // 64-bit + int offset = ra_->reg2offset(dst_first); + if (masm) { + __ movq(Address(rsp, offset), as_Register(Matcher::_regEncode[src_first])); +#ifndef PRODUCT + } else { + st->print("movq [rsp + #%d], %s\t# spill", + offset, + Matcher::regName[src_first]); +#endif + } + } else { + // 32-bit + assert(!((src_first & 1) == 0 && src_first + 1 == src_second), "no transform"); + assert(!((dst_first & 1) == 0 && dst_first + 1 == dst_second), "no transform"); + int offset = ra_->reg2offset(dst_first); + if (masm) { + __ movl(Address(rsp, offset), as_Register(Matcher::_regEncode[src_first])); +#ifndef PRODUCT + } else { + st->print("movl [rsp + #%d], %s\t# spill", + offset, + Matcher::regName[src_first]); +#endif + } + } + return 0; + } else if (dst_first_rc == rc_int) { + // gpr -> gpr + if ((src_first & 1) == 0 && src_first + 1 == src_second && + (dst_first & 1) == 0 && dst_first + 1 == dst_second) { + // 64-bit + if (masm) { + __ movq(as_Register(Matcher::_regEncode[dst_first]), + as_Register(Matcher::_regEncode[src_first])); +#ifndef PRODUCT + } else { + st->print("movq %s, %s\t# spill", + Matcher::regName[dst_first], + Matcher::regName[src_first]); +#endif + } + return 0; + } else { + // 32-bit + assert(!((src_first & 1) == 0 && src_first + 1 == src_second), "no transform"); + assert(!((dst_first & 1) == 0 && dst_first + 1 == dst_second), "no transform"); + if (masm) { + __ movl(as_Register(Matcher::_regEncode[dst_first]), + as_Register(Matcher::_regEncode[src_first])); +#ifndef PRODUCT + } else { + st->print("movl %s, %s\t# spill", + Matcher::regName[dst_first], + Matcher::regName[src_first]); +#endif + } + return 0; + } + } else if (dst_first_rc == rc_float) { + // gpr -> xmm + if ((src_first & 1) == 0 && src_first + 1 == src_second && + (dst_first & 1) == 0 && dst_first + 1 == dst_second) { + // 64-bit + if (masm) { + __ movdq( as_XMMRegister(Matcher::_regEncode[dst_first]), as_Register(Matcher::_regEncode[src_first])); +#ifndef PRODUCT + } else { + st->print("movdq %s, %s\t# spill", + Matcher::regName[dst_first], + Matcher::regName[src_first]); +#endif + } + } else { + // 32-bit + assert(!((src_first & 1) == 0 && src_first + 1 == src_second), "no transform"); + assert(!((dst_first & 1) == 0 && dst_first + 1 == dst_second), "no transform"); + if (masm) { + __ movdl( as_XMMRegister(Matcher::_regEncode[dst_first]), as_Register(Matcher::_regEncode[src_first])); +#ifndef PRODUCT + } else { + st->print("movdl %s, %s\t# spill", + Matcher::regName[dst_first], + Matcher::regName[src_first]); +#endif + } + } + return 0; + } else if (dst_first_rc == rc_kreg) { + if ((src_first & 1) == 0 && src_first + 1 == src_second && + (dst_first & 1) == 0 && dst_first + 1 == dst_second) { + // 64-bit + if (masm) { + __ kmov(as_KRegister(Matcher::_regEncode[dst_first]), as_Register(Matcher::_regEncode[src_first])); + #ifndef PRODUCT + } else { + st->print("kmovq %s, %s\t# spill", + Matcher::regName[dst_first], + Matcher::regName[src_first]); + #endif + } + } + Unimplemented(); + return 0; + } + } else if (src_first_rc == rc_float) { + // xmm -> + if (dst_first_rc == rc_stack) { + // xmm -> mem + if ((src_first & 1) == 0 && src_first + 1 == src_second && + (dst_first & 1) == 0 && dst_first + 1 == dst_second) { + // 64-bit + int offset = ra_->reg2offset(dst_first); + if (masm) { + __ movdbl( Address(rsp, offset), as_XMMRegister(Matcher::_regEncode[src_first])); +#ifndef PRODUCT + } else { + st->print("movsd [rsp + #%d], %s\t# spill", + offset, + Matcher::regName[src_first]); +#endif + } + } else { + // 32-bit + assert(!((src_first & 1) == 0 && src_first + 1 == src_second), "no transform"); + assert(!((dst_first & 1) == 0 && dst_first + 1 == dst_second), "no transform"); + int offset = ra_->reg2offset(dst_first); + if (masm) { + __ movflt(Address(rsp, offset), as_XMMRegister(Matcher::_regEncode[src_first])); +#ifndef PRODUCT + } else { + st->print("movss [rsp + #%d], %s\t# spill", + offset, + Matcher::regName[src_first]); +#endif + } + } + return 0; + } else if (dst_first_rc == rc_int) { + // xmm -> gpr + if ((src_first & 1) == 0 && src_first + 1 == src_second && + (dst_first & 1) == 0 && dst_first + 1 == dst_second) { + // 64-bit + if (masm) { + __ movdq( as_Register(Matcher::_regEncode[dst_first]), as_XMMRegister(Matcher::_regEncode[src_first])); +#ifndef PRODUCT + } else { + st->print("movdq %s, %s\t# spill", + Matcher::regName[dst_first], + Matcher::regName[src_first]); +#endif + } + } else { + // 32-bit + assert(!((src_first & 1) == 0 && src_first + 1 == src_second), "no transform"); + assert(!((dst_first & 1) == 0 && dst_first + 1 == dst_second), "no transform"); + if (masm) { + __ movdl( as_Register(Matcher::_regEncode[dst_first]), as_XMMRegister(Matcher::_regEncode[src_first])); +#ifndef PRODUCT + } else { + st->print("movdl %s, %s\t# spill", + Matcher::regName[dst_first], + Matcher::regName[src_first]); +#endif + } + } + return 0; + } else if (dst_first_rc == rc_float) { + // xmm -> xmm + if ((src_first & 1) == 0 && src_first + 1 == src_second && + (dst_first & 1) == 0 && dst_first + 1 == dst_second) { + // 64-bit + if (masm) { + __ movdbl( as_XMMRegister(Matcher::_regEncode[dst_first]), as_XMMRegister(Matcher::_regEncode[src_first])); +#ifndef PRODUCT + } else { + st->print("%s %s, %s\t# spill", + UseXmmRegToRegMoveAll ? "movapd" : "movsd ", + Matcher::regName[dst_first], + Matcher::regName[src_first]); +#endif + } + } else { + // 32-bit + assert(!((src_first & 1) == 0 && src_first + 1 == src_second), "no transform"); + assert(!((dst_first & 1) == 0 && dst_first + 1 == dst_second), "no transform"); + if (masm) { + __ movflt( as_XMMRegister(Matcher::_regEncode[dst_first]), as_XMMRegister(Matcher::_regEncode[src_first])); +#ifndef PRODUCT + } else { + st->print("%s %s, %s\t# spill", + UseXmmRegToRegMoveAll ? "movaps" : "movss ", + Matcher::regName[dst_first], + Matcher::regName[src_first]); +#endif + } + } + return 0; + } else if (dst_first_rc == rc_kreg) { + assert(false, "Illegal spilling"); + return 0; + } + } else if (src_first_rc == rc_kreg) { + if (dst_first_rc == rc_stack) { + // mem -> kreg + if ((src_first & 1) == 0 && src_first + 1 == src_second && + (dst_first & 1) == 0 && dst_first + 1 == dst_second) { + // 64-bit + int offset = ra_->reg2offset(dst_first); + if (masm) { + __ kmov(Address(rsp, offset), as_KRegister(Matcher::_regEncode[src_first])); +#ifndef PRODUCT + } else { + st->print("kmovq [rsp + #%d] , %s\t# spill", + offset, + Matcher::regName[src_first]); +#endif + } + } + return 0; + } else if (dst_first_rc == rc_int) { + if ((src_first & 1) == 0 && src_first + 1 == src_second && + (dst_first & 1) == 0 && dst_first + 1 == dst_second) { + // 64-bit + if (masm) { + __ kmov(as_Register(Matcher::_regEncode[dst_first]), as_KRegister(Matcher::_regEncode[src_first])); +#ifndef PRODUCT + } else { + st->print("kmovq %s, %s\t# spill", + Matcher::regName[dst_first], + Matcher::regName[src_first]); +#endif + } + } + Unimplemented(); + return 0; + } else if (dst_first_rc == rc_kreg) { + if ((src_first & 1) == 0 && src_first + 1 == src_second && + (dst_first & 1) == 0 && dst_first + 1 == dst_second) { + // 64-bit + if (masm) { + __ kmov(as_KRegister(Matcher::_regEncode[dst_first]), as_KRegister(Matcher::_regEncode[src_first])); +#ifndef PRODUCT + } else { + st->print("kmovq %s, %s\t# spill", + Matcher::regName[dst_first], + Matcher::regName[src_first]); +#endif + } + } + return 0; + } else if (dst_first_rc == rc_float) { + assert(false, "Illegal spill"); + return 0; + } + } + + assert(0," foo "); + Unimplemented(); + return 0; +} + +#ifndef PRODUCT +void MachSpillCopyNode::format(PhaseRegAlloc *ra_, outputStream* st) const { + implementation(nullptr, ra_, false, st); +} +#endif + +void MachSpillCopyNode::emit(C2_MacroAssembler *masm, PhaseRegAlloc *ra_) const { + implementation(masm, ra_, false, nullptr); +} + +uint MachSpillCopyNode::size(PhaseRegAlloc *ra_) const { + return MachNode::size(ra_); +} + +//============================================================================= +#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("leaq %s, [rsp + #%d]\t# box lock", + Matcher::regName[reg], offset); +} +#endif + +void BoxLockNode::emit(C2_MacroAssembler* masm, PhaseRegAlloc* ra_) const +{ + int offset = ra_->reg2offset(in_RegMask(0).find_first_elem()); + int reg = ra_->get_encode(this); + + __ lea(as_Register(reg), Address(rsp, offset)); +} + +uint BoxLockNode::size(PhaseRegAlloc *ra_) const +{ + int offset = ra_->reg2offset(in_RegMask(0).find_first_elem()); + if (ra_->get_encode(this) > 15) { + return (offset < 0x80) ? 6 : 9; // REX2 + } else { + return (offset < 0x80) ? 5 : 8; // REX + } +} + +//============================================================================= +#ifndef PRODUCT +void MachUEPNode::format(PhaseRegAlloc* ra_, outputStream* st) const +{ + if (UseCompressedClassPointers) { + st->print_cr("movl rscratch1, [j_rarg0 + oopDesc::klass_offset_in_bytes()]\t# compressed klass"); + st->print_cr("\tcmpl rscratch1, [rax + CompiledICData::speculated_klass_offset()]\t # Inline cache check"); + } else { + st->print_cr("movq rscratch1, [j_rarg0 + oopDesc::klass_offset_in_bytes()]\t# compressed klass"); + st->print_cr("\tcmpq rscratch1, [rax + CompiledICData::speculated_klass_offset()]\t # Inline cache check"); + } + st->print_cr("\tjne SharedRuntime::_ic_miss_stub"); +} +#endif + +void MachUEPNode::emit(C2_MacroAssembler* masm, PhaseRegAlloc* ra_) const +{ + __ ic_check(InteriorEntryAlignment); +} + +uint MachUEPNode::size(PhaseRegAlloc* ra_) const +{ + return MachNode::size(ra_); // too many variables; just compute it + // the hard way +} + + +//============================================================================= + +bool Matcher::supports_vector_calling_convention(void) { + return EnableVectorSupport; +} + +OptoRegPair Matcher::vector_return_value(uint ideal_reg) { + assert(EnableVectorSupport, "sanity"); + int lo = XMM0_num; + int hi = XMM0b_num; + if (ideal_reg == Op_VecX) hi = XMM0d_num; + else if (ideal_reg == Op_VecY) hi = XMM0h_num; + else if (ideal_reg == Op_VecZ) hi = XMM0p_num; + return OptoRegPair(hi, lo); +} + +// 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 86 a branch displacement is calculated relative to address + // of a next instruction. + offset -= br_size; + + // the short version of jmpConUCF2 contains multiple branches, + // making the reach slightly less + if (rule == jmpConUCF2_rule) + return (-126 <= offset && offset <= 125); + return (-128 <= offset && offset <= 127); +} + +// 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) +{ + return + reg == RDI_num || reg == RDI_H_num || + reg == RSI_num || reg == RSI_H_num || + reg == RDX_num || reg == RDX_H_num || + reg == RCX_num || reg == RCX_H_num || + reg == R8_num || reg == R8_H_num || + reg == R9_num || reg == R9_H_num || + reg == R12_num || reg == R12_H_num || + reg == XMM0_num || reg == XMM0b_num || + reg == XMM1_num || reg == XMM1b_num || + reg == XMM2_num || reg == XMM2b_num || + reg == XMM3_num || reg == XMM3b_num || + reg == XMM4_num || reg == XMM4b_num || + reg == XMM5_num || reg == XMM5b_num || + reg == XMM6_num || reg == XMM6b_num || + reg == XMM7_num || reg == XMM7b_num; +} + +bool Matcher::is_spillable_arg(int reg) +{ + return can_be_java_arg(reg); +} + +uint Matcher::int_pressure_limit() +{ + return (INTPRESSURE == -1) ? _INT_REG_mask.size() : INTPRESSURE; +} + +uint Matcher::float_pressure_limit() +{ + // After experiment around with different values, the following default threshold + // works best for LCM's register pressure scheduling on x64. + uint dec_count = VM_Version::supports_evex() ? 4 : 2; + uint default_float_pressure_threshold = _FLOAT_REG_mask.size() - dec_count; + return (FLOATPRESSURE == -1) ? default_float_pressure_threshold : FLOATPRESSURE; +} + +bool Matcher::use_asm_for_ldiv_by_con( jlong divisor ) { + // In 64 bit mode a code which use multiply when + // devisor is constant is faster than hardware + // DIV instruction (it uses MulHiL). + return false; +} + +// Register for DIVI projection of divmodI +const RegMask& Matcher::divI_proj_mask() { + return INT_RAX_REG_mask(); +} + +// Register for MODI projection of divmodI +const RegMask& Matcher::modI_proj_mask() { + return INT_RDX_REG_mask(); +} + +// Register for DIVL projection of divmodL +const RegMask& Matcher::divL_proj_mask() { + return LONG_RAX_REG_mask(); +} + +// Register for MODL projection of divmodL +const RegMask& Matcher::modL_proj_mask() { + return LONG_RDX_REG_mask(); +} + +%} + source_hpp %{ // Header information of the source block. // Method declarations/definitions which are used outside @@ -2708,7 +4341,206 @@ static inline jlong high_bit_set(BasicType bt) { %} +//----------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 cdql_enc(no_rax_rdx_RegI div) + %{ + // Full implementation of Java idiv and irem; checks for + // special case as described in JVM spec., p.243 & p.271. + // + // normal case special case + // + // input : rax: dividend min_int + // reg: divisor -1 + // + // output: rax: quotient (= rax idiv reg) min_int + // rdx: remainder (= rax irem reg) 0 + // + // Code sequnce: + // + // 0: 3d 00 00 00 80 cmp $0x80000000,%eax + // 5: 75 07/08 jne e + // 7: 33 d2 xor %edx,%edx + // [div >= 8 -> offset + 1] + // [REX_B] + // 9: 83 f9 ff cmp $0xffffffffffffffff,$div + // c: 74 03/04 je 11 + // 000000000000000e : + // e: 99 cltd + // [div >= 8 -> offset + 1] + // [REX_B] + // f: f7 f9 idiv $div + // 0000000000000011 : + Label normal; + Label done; + + // cmp $0x80000000,%eax + __ cmpl(as_Register(RAX_enc), 0x80000000); + + // jne e + __ jccb(Assembler::notEqual, normal); + + // xor %edx,%edx + __ xorl(as_Register(RDX_enc), as_Register(RDX_enc)); + + // cmp $0xffffffffffffffff,%ecx + __ cmpl($div$$Register, -1); + + // je 11 + __ jccb(Assembler::equal, done); + + // + // cltd + __ bind(normal); + __ cdql(); + + // idivl + // + __ idivl($div$$Register); + __ bind(done); + %} + + enc_class cdqq_enc(no_rax_rdx_RegL div) + %{ + // Full implementation of Java ldiv and lrem; checks for + // special case as described in JVM spec., p.243 & p.271. + // + // normal case special case + // + // input : rax: dividend min_long + // reg: divisor -1 + // + // output: rax: quotient (= rax idiv reg) min_long + // rdx: remainder (= rax irem reg) 0 + // + // Code sequnce: + // + // 0: 48 ba 00 00 00 00 00 mov $0x8000000000000000,%rdx + // 7: 00 00 80 + // a: 48 39 d0 cmp %rdx,%rax + // d: 75 08 jne 17 + // f: 33 d2 xor %edx,%edx + // 11: 48 83 f9 ff cmp $0xffffffffffffffff,$div + // 15: 74 05 je 1c + // 0000000000000017 : + // 17: 48 99 cqto + // 19: 48 f7 f9 idiv $div + // 000000000000001c : + Label normal; + Label done; + + // mov $0x8000000000000000,%rdx + __ mov64(as_Register(RDX_enc), 0x8000000000000000); + + // cmp %rdx,%rax + __ cmpq(as_Register(RAX_enc), as_Register(RDX_enc)); + + // jne 17 + __ jccb(Assembler::notEqual, normal); + + // xor %edx,%edx + __ xorl(as_Register(RDX_enc), as_Register(RDX_enc)); + + // cmp $0xffffffffffffffff,$div + __ cmpq($div$$Register, -1); + + // je 1e + __ jccb(Assembler::equal, done); + + // + // cqto + __ bind(normal); + __ cdqq(); + + // idivq (note: must be emitted by the user of this rule) + // + __ idivq($div$$Register); + __ bind(done); + %} + + enc_class clear_avx %{ + DEBUG_ONLY(int off0 = __ offset()); + if (generate_vzeroupper(Compile::current())) { + // Clear upper bits of YMM registers to avoid AVX <-> SSE transition penalty + // Clear upper bits of YMM registers when current compiled code uses + // wide vectors to avoid AVX <-> SSE transition penalty during call. + __ vzeroupper(); + } + DEBUG_ONLY(int off1 = __ offset()); + assert(off1 - off0 == clear_avx_size(), "correct size prediction"); + %} + + enc_class Java_To_Runtime(method meth) %{ + __ lea(r10, RuntimeAddress((address)$meth$$method)); + __ call(r10); + __ post_call_nop(); + %} + + enc_class Java_Static_Call(method meth) + %{ + // JAVA STATIC CALL + // CALL to fixup routine. Fixup routine uses ScopeDesc info to + // determine who we intended to call. + if (!_method) { + __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, $meth$$method))); + } else if (_method->intrinsic_id() == vmIntrinsicID::_ensureMaterializedForStackWalk) { + // The NOP here is purely to ensure that eliding a call to + // JVM_EnsureMaterializedForStackWalk doesn't change the code size. + __ addr_nop_5(); + __ block_comment("call JVM_EnsureMaterializedForStackWalk (elided)"); + } else { + int method_index = resolved_method_index(masm); + RelocationHolder rspec = _optimized_virtual ? opt_virtual_call_Relocation::spec(method_index) + : static_call_Relocation::spec(method_index); + address mark = __ pc(); + int call_offset = __ offset(); + __ call(AddressLiteral(CAST_FROM_FN_PTR(address, $meth$$method), rspec)); + if (CodeBuffer::supports_shared_stubs() && _method->can_be_statically_bound()) { + // Calls of the same statically bound method can share + // a stub to the interpreter. + __ code()->shared_stub_to_interp_for(_method, call_offset); + } else { + // Emit stubs for static call. + address stub = CompiledDirectCall::emit_to_interp_stub(masm, mark); + __ clear_inst_mark(); + if (stub == nullptr) { + ciEnv::current()->record_failure("CodeCache is full"); + return; + } + } + } + __ post_call_nop(); + %} + + enc_class Java_Dynamic_Call(method meth) %{ + __ ic_call((address)$meth$$method, resolved_method_index(masm)); + __ post_call_nop(); + %} enc_class call_epilog %{ if (VerifyStackAtCalls) { @@ -2725,6 +4557,1501 @@ encode %{ %} +//----------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 OptoReg::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, even 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 +// | +--------+----> OptoReg::stack0(), even aligned +// | | pad1 | 11 pad to align new SP +// | +--------+ +// | | | 10 +// | | spills | 9 spills +// V | | 8 (pad0 slot for callee) +// -----------+--------+----> Matcher::_out_arg_limit, unaligned +// ^ | out | 7 +// | | args | 6 Holes in outgoing args owned by CALLEE +// Owned by +--------+ +// CALLEE | new out| 6 Empty on Intel, window on Sparc +// | new |preserve| Must be even-aligned. +// | SP-+--------+----> Matcher::_new_SP, even aligned +// | | | +// +// Note 1: Only region 8-11 is determined by the allocator. Region 0-5 is +// known from SELF's arguments and the Java calling convention. +// Region 6-7 is determined per call site. +// Note 2: If the calling convention leaves holes in the incoming argument +// area, those holes are owned by SELF. Holes in the outgoing area +// are owned by the CALLEE. Holes should not be necessary in the +// incoming area, as the Java calling convention is completely under +// the control of the AD file. Doubles can be sorted and packed to +// avoid holes. Holes in the outgoing arguments may be necessary for +// varargs C calling conventions. +// Note 3: Region 0-3 is even aligned, with pad2 as needed. Region 3-5 is +// even aligned with pad0 as needed. +// Region 6 is even aligned. Region 6-7 is NOT even aligned; +// region 6-11 is even aligned; it may be padded out more so that +// the region from SP to FP meets the minimum stack alignment. +// Note 4: For I2C adapters, the incoming FP may not meet the minimum stack +// alignment. Region 11, pad1, may be dynamically extended so that +// SP meets the minimum alignment. + +frame +%{ + // These three registers define part of the calling convention + // between compiled code and the interpreter. + inline_cache_reg(RAX); // Inline Cache Register + + // Optional: name the operand used by cisc-spilling to access + // [stack_pointer + offset] + cisc_spilling_operand_name(indOffset32); + + // Number of stack slots consumed by locking an object + sync_stack_slots(2); + + // Compiled code's Frame Pointer + frame_pointer(RSP); + + // Interpreter stores its frame pointer in a register which is + // stored to the stack by I2CAdaptors. + // I2CAdaptors convert from interpreted java to compiled java. + interpreter_frame_pointer(RBP); + + // Stack alignment requirement + stack_alignment(StackAlignmentInBytes); // Alignment size in bytes (128-bit -> 16 bytes) + + // Number of outgoing stack slots killed above the out_preserve_stack_slots + // for calls to C. Supports the var-args backing area for register parms. + varargs_C_out_slots_killed(frame::arg_reg_save_area_bytes/BytesPerInt); + + // 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 - 2 + + align_up((Compile::current()->in_preserve_stack_slots() + + Compile::current()->fixed_slots()), + stack_alignment_in_slots())); + + // Location of compiled Java return values. Same as C for now. + return_value + %{ + assert(ideal_reg >= Op_RegI && ideal_reg <= Op_RegL, + "only return normal values"); + + static const int lo[Op_RegL + 1] = { + 0, + 0, + RAX_num, // Op_RegN + RAX_num, // Op_RegI + RAX_num, // Op_RegP + XMM0_num, // Op_RegF + XMM0_num, // Op_RegD + RAX_num // Op_RegL + }; + static const int hi[Op_RegL + 1] = { + 0, + 0, + OptoReg::Bad, // Op_RegN + OptoReg::Bad, // Op_RegI + RAX_H_num, // Op_RegP + OptoReg::Bad, // Op_RegF + XMM0b_num, // Op_RegD + RAX_H_num // Op_RegL + }; + // Excluded flags and vector registers. + assert(ARRAY_SIZE(hi) == _last_machine_leaf - 8, "missing type"); + return OptoRegPair(hi[ideal_reg], lo[ideal_reg]); + %} +%} + +//----------ATTRIBUTES--------------------------------------------------------- +//----------Operand Attributes------------------------------------------------- +op_attrib op_cost(0); // Required cost attribute + +//----------Instruction Attributes--------------------------------------------- +ins_attrib ins_cost(100); // Required cost attribute +ins_attrib ins_size(8); // 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? +ins_attrib ins_alignment(1); // Required alignment attribute (must + // be a power of 2) specifies the + // alignment that some part of the + // instruction (not necessarily the + // start) requires. If > 1, a + // compute_padding() function must be + // provided for the instruction + +// Whether this node is expanded during code emission into a sequence of +// instructions and the first instruction can perform an implicit null check. +ins_attrib ins_is_late_expanded_null_check_candidate(false); + +//----------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 +operand immI() +%{ + match(ConI); + + op_cost(10); + format %{ %} + interface(CONST_INTER); +%} + +// Constant for test vs zero +operand immI_0() +%{ + predicate(n->get_int() == 0); + match(ConI); + + op_cost(0); + format %{ %} + interface(CONST_INTER); +%} + +// Constant for increment +operand immI_1() +%{ + predicate(n->get_int() == 1); + match(ConI); + + op_cost(0); + format %{ %} + interface(CONST_INTER); +%} + +// Constant for decrement +operand immI_M1() +%{ + predicate(n->get_int() == -1); + match(ConI); + + op_cost(0); + format %{ %} + interface(CONST_INTER); +%} + +operand immI_2() +%{ + predicate(n->get_int() == 2); + match(ConI); + + op_cost(0); + format %{ %} + interface(CONST_INTER); +%} + +operand immI_4() +%{ + predicate(n->get_int() == 4); + match(ConI); + + op_cost(0); + format %{ %} + interface(CONST_INTER); +%} + +operand immI_8() +%{ + predicate(n->get_int() == 8); + match(ConI); + + op_cost(0); + format %{ %} + interface(CONST_INTER); +%} + +// Valid scale values for addressing modes +operand immI2() +%{ + predicate(0 <= n->get_int() && (n->get_int() <= 3)); + match(ConI); + + format %{ %} + interface(CONST_INTER); +%} + +operand immU7() +%{ + predicate((0 <= n->get_int()) && (n->get_int() <= 0x7F)); + match(ConI); + + op_cost(5); + format %{ %} + interface(CONST_INTER); +%} + +operand immI8() +%{ + predicate((-0x80 <= n->get_int()) && (n->get_int() < 0x80)); + match(ConI); + + op_cost(5); + format %{ %} + interface(CONST_INTER); +%} + +operand immU8() +%{ + predicate((0 <= n->get_int()) && (n->get_int() <= 255)); + match(ConI); + + op_cost(5); + format %{ %} + interface(CONST_INTER); +%} + +operand immI16() +%{ + predicate((-32768 <= n->get_int()) && (n->get_int() <= 32767)); + match(ConI); + + op_cost(10); + format %{ %} + interface(CONST_INTER); +%} + +// Int Immediate non-negative +operand immU31() +%{ + predicate(n->get_int() >= 0); + match(ConI); + + op_cost(0); + format %{ %} + interface(CONST_INTER); +%} + +// Pointer Immediate +operand immP() +%{ + match(ConP); + + op_cost(10); + format %{ %} + interface(CONST_INTER); +%} + +// Null Pointer Immediate +operand immP0() +%{ + predicate(n->get_ptr() == 0); + match(ConP); + + op_cost(5); + 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(5); + format %{ %} + interface(CONST_INTER); +%} + +operand immP31() +%{ + predicate(n->as_Type()->type()->reloc() == relocInfo::none + && (n->get_ptr() >> 31) == 0); + match(ConP); + + op_cost(5); + format %{ %} + interface(CONST_INTER); +%} + + +// Long Immediate +operand immL() +%{ + match(ConL); + + op_cost(20); + format %{ %} + interface(CONST_INTER); +%} + +// Long Immediate 8-bit +operand immL8() +%{ + predicate(-0x80L <= n->get_long() && n->get_long() < 0x80L); + match(ConL); + + op_cost(5); + format %{ %} + interface(CONST_INTER); +%} + +// Long Immediate 32-bit unsigned +operand immUL32() +%{ + predicate(n->get_long() == (unsigned int) (n->get_long())); + match(ConL); + + op_cost(10); + format %{ %} + interface(CONST_INTER); +%} + +// Long Immediate 32-bit signed +operand immL32() +%{ + predicate(n->get_long() == (int) (n->get_long())); + match(ConL); + + op_cost(15); + format %{ %} + interface(CONST_INTER); +%} + +operand immL_Pow2() +%{ + predicate(is_power_of_2((julong)n->get_long())); + match(ConL); + + op_cost(15); + format %{ %} + interface(CONST_INTER); +%} + +operand immL_NotPow2() +%{ + predicate(is_power_of_2((julong)~n->get_long())); + match(ConL); + + op_cost(15); + format %{ %} + interface(CONST_INTER); +%} + +// Long Immediate zero +operand immL0() +%{ + predicate(n->get_long() == 0L); + match(ConL); + + op_cost(10); + format %{ %} + interface(CONST_INTER); +%} + +// Constant for increment +operand immL1() +%{ + predicate(n->get_long() == 1); + match(ConL); + + format %{ %} + interface(CONST_INTER); +%} + +// Constant for decrement +operand immL_M1() +%{ + predicate(n->get_long() == -1); + match(ConL); + + format %{ %} + interface(CONST_INTER); +%} + +// Long Immediate: low 32-bit mask +operand immL_32bits() +%{ + predicate(n->get_long() == 0xFFFFFFFFL); + match(ConL); + op_cost(20); + + format %{ %} + interface(CONST_INTER); +%} + +// Int Immediate: 2^n-1, positive +operand immI_Pow2M1() +%{ + predicate((n->get_int() > 0) + && is_power_of_2((juint)n->get_int() + 1)); + match(ConI); + + op_cost(20); + format %{ %} + interface(CONST_INTER); +%} + +// Float Immediate zero +operand immF0() +%{ + predicate(jint_cast(n->getf()) == 0); + match(ConF); + + op_cost(5); + format %{ %} + interface(CONST_INTER); +%} + +// Float Immediate +operand immF() +%{ + match(ConF); + + op_cost(15); + format %{ %} + interface(CONST_INTER); +%} + +// Half Float Immediate +operand immH() +%{ + match(ConH); + + op_cost(15); + format %{ %} + interface(CONST_INTER); +%} + +// Double Immediate zero +operand immD0() +%{ + predicate(jlong_cast(n->getd()) == 0); + match(ConD); + + op_cost(5); + format %{ %} + interface(CONST_INTER); +%} + +// Double Immediate +operand immD() +%{ + match(ConD); + + op_cost(15); + format %{ %} + interface(CONST_INTER); +%} + +// Immediates for special shifts (sign extend) + +// Constants for increment +operand immI_16() +%{ + predicate(n->get_int() == 16); + match(ConI); + + format %{ %} + interface(CONST_INTER); +%} + +operand immI_24() +%{ + predicate(n->get_int() == 24); + match(ConI); + + format %{ %} + interface(CONST_INTER); +%} + +// Constant for byte-wide masking +operand immI_255() +%{ + predicate(n->get_int() == 255); + match(ConI); + + format %{ %} + interface(CONST_INTER); +%} + +// Constant for short-wide masking +operand immI_65535() +%{ + predicate(n->get_int() == 65535); + match(ConI); + + format %{ %} + interface(CONST_INTER); +%} + +// Constant for byte-wide masking +operand immL_255() +%{ + predicate(n->get_long() == 255); + match(ConL); + + format %{ %} + interface(CONST_INTER); +%} + +// Constant for short-wide masking +operand immL_65535() +%{ + predicate(n->get_long() == 65535); + match(ConL); + + format %{ %} + interface(CONST_INTER); +%} + +operand kReg() +%{ + constraint(ALLOC_IN_RC(vectmask_reg)); + match(RegVectMask); + format %{%} + interface(REG_INTER); +%} + +// Register Operands +// Integer Register +operand rRegI() +%{ + constraint(ALLOC_IN_RC(int_reg)); + match(RegI); + + match(rax_RegI); + match(rbx_RegI); + match(rcx_RegI); + match(rdx_RegI); + match(rdi_RegI); + + format %{ %} + interface(REG_INTER); +%} + +// Special Registers +operand rax_RegI() +%{ + constraint(ALLOC_IN_RC(int_rax_reg)); + match(RegI); + match(rRegI); + + format %{ "RAX" %} + interface(REG_INTER); +%} + +// Special Registers +operand rbx_RegI() +%{ + constraint(ALLOC_IN_RC(int_rbx_reg)); + match(RegI); + match(rRegI); + + format %{ "RBX" %} + interface(REG_INTER); +%} + +operand rcx_RegI() +%{ + constraint(ALLOC_IN_RC(int_rcx_reg)); + match(RegI); + match(rRegI); + + format %{ "RCX" %} + interface(REG_INTER); +%} + +operand rdx_RegI() +%{ + constraint(ALLOC_IN_RC(int_rdx_reg)); + match(RegI); + match(rRegI); + + format %{ "RDX" %} + interface(REG_INTER); +%} + +operand rdi_RegI() +%{ + constraint(ALLOC_IN_RC(int_rdi_reg)); + match(RegI); + match(rRegI); + + format %{ "RDI" %} + interface(REG_INTER); +%} + +operand no_rax_rdx_RegI() +%{ + constraint(ALLOC_IN_RC(int_no_rax_rdx_reg)); + match(RegI); + match(rbx_RegI); + match(rcx_RegI); + match(rdi_RegI); + + format %{ %} + interface(REG_INTER); +%} + +operand no_rbp_r13_RegI() +%{ + constraint(ALLOC_IN_RC(int_no_rbp_r13_reg)); + match(RegI); + match(rRegI); + match(rax_RegI); + match(rbx_RegI); + match(rcx_RegI); + match(rdx_RegI); + match(rdi_RegI); + + format %{ %} + interface(REG_INTER); +%} + +// Pointer Register +operand any_RegP() +%{ + constraint(ALLOC_IN_RC(any_reg)); + match(RegP); + match(rax_RegP); + match(rbx_RegP); + match(rdi_RegP); + match(rsi_RegP); + match(rbp_RegP); + match(r15_RegP); + match(rRegP); + + format %{ %} + interface(REG_INTER); +%} + +operand rRegP() +%{ + constraint(ALLOC_IN_RC(ptr_reg)); + match(RegP); + match(rax_RegP); + match(rbx_RegP); + match(rdi_RegP); + match(rsi_RegP); + match(rbp_RegP); // See Q&A below about + match(r15_RegP); // r15_RegP and rbp_RegP. + + format %{ %} + interface(REG_INTER); +%} + +operand rRegN() %{ + constraint(ALLOC_IN_RC(int_reg)); + match(RegN); + + format %{ %} + interface(REG_INTER); +%} + +// Question: Why is r15_RegP (the read-only TLS register) a match for rRegP? +// Answer: Operand match rules govern the DFA as it processes instruction inputs. +// It's fine for an instruction input that expects rRegP to match a r15_RegP. +// The output of an instruction is controlled by the allocator, which respects +// register class masks, not match rules. Unless an instruction mentions +// r15_RegP or any_RegP explicitly as its output, r15 will not be considered +// by the allocator as an input. +// The same logic applies to rbp_RegP being a match for rRegP: If PreserveFramePointer==true, +// the RBP is used as a proper frame pointer and is not included in ptr_reg. As a +// result, RBP is not included in the output of the instruction either. + +// This operand is not allowed to use RBP even if +// RBP is not used to hold the frame pointer. +operand no_rbp_RegP() +%{ + constraint(ALLOC_IN_RC(ptr_reg_no_rbp)); + match(RegP); + match(rbx_RegP); + match(rsi_RegP); + match(rdi_RegP); + + format %{ %} + interface(REG_INTER); +%} + +// Special Registers +// Return a pointer value +operand rax_RegP() +%{ + constraint(ALLOC_IN_RC(ptr_rax_reg)); + match(RegP); + match(rRegP); + + format %{ %} + interface(REG_INTER); +%} + +// Special Registers +// Return a compressed pointer value +operand rax_RegN() +%{ + constraint(ALLOC_IN_RC(int_rax_reg)); + match(RegN); + match(rRegN); + + format %{ %} + interface(REG_INTER); +%} + +// Used in AtomicAdd +operand rbx_RegP() +%{ + constraint(ALLOC_IN_RC(ptr_rbx_reg)); + match(RegP); + match(rRegP); + + format %{ %} + interface(REG_INTER); +%} + +operand rsi_RegP() +%{ + constraint(ALLOC_IN_RC(ptr_rsi_reg)); + match(RegP); + match(rRegP); + + format %{ %} + interface(REG_INTER); +%} + +operand rbp_RegP() +%{ + constraint(ALLOC_IN_RC(ptr_rbp_reg)); + match(RegP); + match(rRegP); + + format %{ %} + interface(REG_INTER); +%} + +// Used in rep stosq +operand rdi_RegP() +%{ + constraint(ALLOC_IN_RC(ptr_rdi_reg)); + match(RegP); + match(rRegP); + + format %{ %} + interface(REG_INTER); +%} + +operand r15_RegP() +%{ + constraint(ALLOC_IN_RC(ptr_r15_reg)); + match(RegP); + match(rRegP); + + format %{ %} + interface(REG_INTER); +%} + +operand rRegL() +%{ + constraint(ALLOC_IN_RC(long_reg)); + match(RegL); + match(rax_RegL); + match(rdx_RegL); + + format %{ %} + interface(REG_INTER); +%} + +// Special Registers +operand no_rax_rdx_RegL() +%{ + constraint(ALLOC_IN_RC(long_no_rax_rdx_reg)); + match(RegL); + match(rRegL); + + format %{ %} + interface(REG_INTER); +%} + +operand rax_RegL() +%{ + constraint(ALLOC_IN_RC(long_rax_reg)); + match(RegL); + match(rRegL); + + format %{ "RAX" %} + interface(REG_INTER); +%} + +operand rcx_RegL() +%{ + constraint(ALLOC_IN_RC(long_rcx_reg)); + match(RegL); + match(rRegL); + + format %{ %} + interface(REG_INTER); +%} + +operand rdx_RegL() +%{ + constraint(ALLOC_IN_RC(long_rdx_reg)); + match(RegL); + match(rRegL); + + format %{ %} + interface(REG_INTER); +%} + +operand r11_RegL() +%{ + constraint(ALLOC_IN_RC(long_r11_reg)); + match(RegL); + match(rRegL); + + format %{ %} + interface(REG_INTER); +%} + +operand no_rbp_r13_RegL() +%{ + constraint(ALLOC_IN_RC(long_no_rbp_r13_reg)); + match(RegL); + match(rRegL); + match(rax_RegL); + match(rcx_RegL); + match(rdx_RegL); + + format %{ %} + interface(REG_INTER); +%} + +// Flags register, used as output of compare instructions +operand rFlagsReg() +%{ + constraint(ALLOC_IN_RC(int_flags)); + match(RegFlags); + + format %{ "RFLAGS" %} + interface(REG_INTER); +%} + +// Flags register, used as output of FLOATING POINT compare instructions +operand rFlagsRegU() +%{ + constraint(ALLOC_IN_RC(int_flags)); + match(RegFlags); + + format %{ "RFLAGS_U" %} + interface(REG_INTER); +%} + +operand rFlagsRegUCF() %{ + constraint(ALLOC_IN_RC(int_flags)); + match(RegFlags); + predicate(false); + + format %{ "RFLAGS_U_CF" %} + interface(REG_INTER); +%} + +// Float register operands +operand regF() %{ + constraint(ALLOC_IN_RC(float_reg)); + match(RegF); + + format %{ %} + interface(REG_INTER); +%} + +// Float register operands +operand legRegF() %{ + constraint(ALLOC_IN_RC(float_reg_legacy)); + match(RegF); + + format %{ %} + interface(REG_INTER); +%} + +// Float register operands +operand vlRegF() %{ + constraint(ALLOC_IN_RC(float_reg_vl)); + match(RegF); + + format %{ %} + interface(REG_INTER); +%} + +// Double register operands +operand regD() %{ + constraint(ALLOC_IN_RC(double_reg)); + match(RegD); + + format %{ %} + interface(REG_INTER); +%} + +// Double register operands +operand legRegD() %{ + constraint(ALLOC_IN_RC(double_reg_legacy)); + match(RegD); + + format %{ %} + interface(REG_INTER); +%} + +// Double register operands +operand vlRegD() %{ + constraint(ALLOC_IN_RC(double_reg_vl)); + match(RegD); + + format %{ %} + interface(REG_INTER); +%} + +//----------Memory Operands---------------------------------------------------- +// Direct Memory Operand +// operand direct(immP addr) +// %{ +// match(addr); + +// format %{ "[$addr]" %} +// interface(MEMORY_INTER) %{ +// base(0xFFFFFFFF); +// index(0x4); +// scale(0x0); +// disp($addr); +// %} +// %} + +// Indirect Memory Operand +operand indirect(any_RegP reg) +%{ + constraint(ALLOC_IN_RC(ptr_reg)); + match(reg); + + format %{ "[$reg]" %} + interface(MEMORY_INTER) %{ + base($reg); + index(0x4); + scale(0x0); + disp(0x0); + %} +%} + +// Indirect Memory Plus Short Offset Operand +operand indOffset8(any_RegP reg, immL8 off) +%{ + constraint(ALLOC_IN_RC(ptr_reg)); + match(AddP reg off); + + format %{ "[$reg + $off (8-bit)]" %} + interface(MEMORY_INTER) %{ + base($reg); + index(0x4); + scale(0x0); + disp($off); + %} +%} + +// Indirect Memory Plus Long Offset Operand +operand indOffset32(any_RegP reg, immL32 off) +%{ + constraint(ALLOC_IN_RC(ptr_reg)); + match(AddP reg off); + + format %{ "[$reg + $off (32-bit)]" %} + interface(MEMORY_INTER) %{ + base($reg); + index(0x4); + scale(0x0); + disp($off); + %} +%} + +// Indirect Memory Plus Index Register Plus Offset Operand +operand indIndexOffset(any_RegP reg, rRegL lreg, immL32 off) +%{ + constraint(ALLOC_IN_RC(ptr_reg)); + match(AddP (AddP reg lreg) off); + + op_cost(10); + format %{"[$reg + $off + $lreg]" %} + interface(MEMORY_INTER) %{ + base($reg); + index($lreg); + scale(0x0); + disp($off); + %} +%} + +// Indirect Memory Plus Index Register Plus Offset Operand +operand indIndex(any_RegP reg, rRegL lreg) +%{ + constraint(ALLOC_IN_RC(ptr_reg)); + match(AddP reg lreg); + + op_cost(10); + format %{"[$reg + $lreg]" %} + interface(MEMORY_INTER) %{ + base($reg); + index($lreg); + scale(0x0); + disp(0x0); + %} +%} + +// Indirect Memory Times Scale Plus Index Register +operand indIndexScale(any_RegP reg, rRegL lreg, immI2 scale) +%{ + constraint(ALLOC_IN_RC(ptr_reg)); + match(AddP reg (LShiftL lreg scale)); + + op_cost(10); + format %{"[$reg + $lreg << $scale]" %} + interface(MEMORY_INTER) %{ + base($reg); + index($lreg); + scale($scale); + disp(0x0); + %} +%} + +operand indPosIndexScale(any_RegP reg, rRegI idx, immI2 scale) +%{ + constraint(ALLOC_IN_RC(ptr_reg)); + predicate(n->in(3)->in(1)->as_Type()->type()->is_long()->_lo >= 0); + match(AddP reg (LShiftL (ConvI2L idx) scale)); + + op_cost(10); + format %{"[$reg + pos $idx << $scale]" %} + interface(MEMORY_INTER) %{ + base($reg); + index($idx); + scale($scale); + disp(0x0); + %} +%} + +// Indirect Memory Times Scale Plus Index Register Plus Offset Operand +operand indIndexScaleOffset(any_RegP reg, immL32 off, rRegL lreg, immI2 scale) +%{ + constraint(ALLOC_IN_RC(ptr_reg)); + match(AddP (AddP reg (LShiftL lreg scale)) off); + + op_cost(10); + format %{"[$reg + $off + $lreg << $scale]" %} + interface(MEMORY_INTER) %{ + base($reg); + index($lreg); + scale($scale); + disp($off); + %} +%} + +// Indirect Memory Plus Positive Index Register Plus Offset Operand +operand indPosIndexOffset(any_RegP reg, immL32 off, rRegI idx) +%{ + constraint(ALLOC_IN_RC(ptr_reg)); + predicate(n->in(2)->in(3)->as_Type()->type()->is_long()->_lo >= 0); + match(AddP (AddP reg (ConvI2L idx)) off); + + op_cost(10); + format %{"[$reg + $off + $idx]" %} + interface(MEMORY_INTER) %{ + base($reg); + index($idx); + scale(0x0); + disp($off); + %} +%} + +// Indirect Memory Times Scale Plus Positive Index Register Plus Offset Operand +operand indPosIndexScaleOffset(any_RegP reg, immL32 off, rRegI idx, immI2 scale) +%{ + constraint(ALLOC_IN_RC(ptr_reg)); + predicate(n->in(2)->in(3)->in(1)->as_Type()->type()->is_long()->_lo >= 0); + match(AddP (AddP reg (LShiftL (ConvI2L idx) scale)) off); + + op_cost(10); + format %{"[$reg + $off + $idx << $scale]" %} + interface(MEMORY_INTER) %{ + base($reg); + index($idx); + scale($scale); + disp($off); + %} +%} + +// Indirect Narrow Oop Plus Offset Operand +// Note: x86 architecture doesn't support "scale * index + offset" without a base +// we can't free r12 even with CompressedOops::base() == nullptr. +operand indCompressedOopOffset(rRegN reg, immL32 off) %{ + predicate(UseCompressedOops && (CompressedOops::shift() == Address::times_8)); + constraint(ALLOC_IN_RC(ptr_reg)); + match(AddP (DecodeN reg) off); + + op_cost(10); + format %{"[R12 + $reg << 3 + $off] (compressed oop addressing)" %} + interface(MEMORY_INTER) %{ + base(0xc); // R12 + index($reg); + scale(0x3); + disp($off); + %} +%} + +// Indirect Memory Operand +operand indirectNarrow(rRegN reg) +%{ + predicate(CompressedOops::shift() == 0); + constraint(ALLOC_IN_RC(ptr_reg)); + match(DecodeN reg); + + format %{ "[$reg]" %} + interface(MEMORY_INTER) %{ + base($reg); + index(0x4); + scale(0x0); + disp(0x0); + %} +%} + +// Indirect Memory Plus Short Offset Operand +operand indOffset8Narrow(rRegN reg, immL8 off) +%{ + predicate(CompressedOops::shift() == 0); + constraint(ALLOC_IN_RC(ptr_reg)); + match(AddP (DecodeN reg) off); + + format %{ "[$reg + $off (8-bit)]" %} + interface(MEMORY_INTER) %{ + base($reg); + index(0x4); + scale(0x0); + disp($off); + %} +%} + +// Indirect Memory Plus Long Offset Operand +operand indOffset32Narrow(rRegN reg, immL32 off) +%{ + predicate(CompressedOops::shift() == 0); + constraint(ALLOC_IN_RC(ptr_reg)); + match(AddP (DecodeN reg) off); + + format %{ "[$reg + $off (32-bit)]" %} + interface(MEMORY_INTER) %{ + base($reg); + index(0x4); + scale(0x0); + disp($off); + %} +%} + +// Indirect Memory Plus Index Register Plus Offset Operand +operand indIndexOffsetNarrow(rRegN reg, rRegL lreg, immL32 off) +%{ + predicate(CompressedOops::shift() == 0); + constraint(ALLOC_IN_RC(ptr_reg)); + match(AddP (AddP (DecodeN reg) lreg) off); + + op_cost(10); + format %{"[$reg + $off + $lreg]" %} + interface(MEMORY_INTER) %{ + base($reg); + index($lreg); + scale(0x0); + disp($off); + %} +%} + +// Indirect Memory Plus Index Register Plus Offset Operand +operand indIndexNarrow(rRegN reg, rRegL lreg) +%{ + predicate(CompressedOops::shift() == 0); + constraint(ALLOC_IN_RC(ptr_reg)); + match(AddP (DecodeN reg) lreg); + + op_cost(10); + format %{"[$reg + $lreg]" %} + interface(MEMORY_INTER) %{ + base($reg); + index($lreg); + scale(0x0); + disp(0x0); + %} +%} + +// Indirect Memory Times Scale Plus Index Register +operand indIndexScaleNarrow(rRegN reg, rRegL lreg, immI2 scale) +%{ + predicate(CompressedOops::shift() == 0); + constraint(ALLOC_IN_RC(ptr_reg)); + match(AddP (DecodeN reg) (LShiftL lreg scale)); + + op_cost(10); + format %{"[$reg + $lreg << $scale]" %} + interface(MEMORY_INTER) %{ + base($reg); + index($lreg); + scale($scale); + disp(0x0); + %} +%} + +// Indirect Memory Times Scale Plus Index Register Plus Offset Operand +operand indIndexScaleOffsetNarrow(rRegN reg, immL32 off, rRegL lreg, immI2 scale) +%{ + predicate(CompressedOops::shift() == 0); + constraint(ALLOC_IN_RC(ptr_reg)); + match(AddP (AddP (DecodeN reg) (LShiftL lreg scale)) off); + + op_cost(10); + format %{"[$reg + $off + $lreg << $scale]" %} + interface(MEMORY_INTER) %{ + base($reg); + index($lreg); + scale($scale); + disp($off); + %} +%} + +// Indirect Memory Times Plus Positive Index Register Plus Offset Operand +operand indPosIndexOffsetNarrow(rRegN reg, immL32 off, rRegI idx) +%{ + constraint(ALLOC_IN_RC(ptr_reg)); + predicate(CompressedOops::shift() == 0 && n->in(2)->in(3)->as_Type()->type()->is_long()->_lo >= 0); + match(AddP (AddP (DecodeN reg) (ConvI2L idx)) off); + + op_cost(10); + format %{"[$reg + $off + $idx]" %} + interface(MEMORY_INTER) %{ + base($reg); + index($idx); + scale(0x0); + disp($off); + %} +%} + +// Indirect Memory Times Scale Plus Positive Index Register Plus Offset Operand +operand indPosIndexScaleOffsetNarrow(rRegN reg, immL32 off, rRegI idx, immI2 scale) +%{ + constraint(ALLOC_IN_RC(ptr_reg)); + predicate(CompressedOops::shift() == 0 && n->in(2)->in(3)->in(1)->as_Type()->type()->is_long()->_lo >= 0); + match(AddP (AddP (DecodeN reg) (LShiftL (ConvI2L idx) scale)) off); + + op_cost(10); + format %{"[$reg + $off + $idx << $scale]" %} + interface(MEMORY_INTER) %{ + base($reg); + index($idx); + scale($scale); + disp($off); + %} +%} + +//----------Special Memory Operands-------------------------------------------- +// Stack Slot Operand - This operand is used for loading and storing temporary +// values on the stack where a match requires a value to +// flow through memory. +operand stackSlotP(sRegP reg) +%{ + constraint(ALLOC_IN_RC(stack_slots)); + // No match rule because this operand is only generated in matching + + format %{ "[$reg]" %} + interface(MEMORY_INTER) %{ + base(0x4); // RSP + index(0x4); // No Index + scale(0x0); // No Scale + disp($reg); // Stack Offset + %} +%} + +operand stackSlotI(sRegI reg) +%{ + constraint(ALLOC_IN_RC(stack_slots)); + // No match rule because this operand is only generated in matching + + format %{ "[$reg]" %} + interface(MEMORY_INTER) %{ + base(0x4); // RSP + index(0x4); // No Index + scale(0x0); // No Scale + disp($reg); // Stack Offset + %} +%} + +operand stackSlotF(sRegF reg) +%{ + constraint(ALLOC_IN_RC(stack_slots)); + // No match rule because this operand is only generated in matching + + format %{ "[$reg]" %} + interface(MEMORY_INTER) %{ + base(0x4); // RSP + index(0x4); // No Index + scale(0x0); // No Scale + disp($reg); // Stack Offset + %} +%} + +operand stackSlotD(sRegD reg) +%{ + constraint(ALLOC_IN_RC(stack_slots)); + // No match rule because this operand is only generated in matching + + format %{ "[$reg]" %} + interface(MEMORY_INTER) %{ + base(0x4); // RSP + index(0x4); // No Index + scale(0x0); // No Scale + disp($reg); // Stack Offset + %} +%} +operand stackSlotL(sRegL reg) +%{ + constraint(ALLOC_IN_RC(stack_slots)); + // No match rule because this operand is only generated in matching + + format %{ "[$reg]" %} + interface(MEMORY_INTER) %{ + base(0x4); // RSP + index(0x4); // No Index + scale(0x0); // No Scale + disp($reg); // Stack Offset + %} +%} + +//----------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. + +// Comparison Code +operand cmpOp() +%{ + match(Bool); + + format %{ "" %} + interface(COND_INTER) %{ + equal(0x4, "e"); + not_equal(0x5, "ne"); + less(0xC, "l"); + greater_equal(0xD, "ge"); + less_equal(0xE, "le"); + greater(0xF, "g"); + overflow(0x0, "o"); + no_overflow(0x1, "no"); + %} +%} + +// Comparison Code, unsigned compare. Used by FP also, with +// C2 (unordered) turned into GT or LT already. The other bits +// C0 and C3 are turned into Carry & Zero flags. +operand cmpOpU() +%{ + match(Bool); + + format %{ "" %} + interface(COND_INTER) %{ + equal(0x4, "e"); + not_equal(0x5, "ne"); + less(0x2, "b"); + greater_equal(0x3, "ae"); + less_equal(0x6, "be"); + greater(0x7, "a"); + overflow(0x0, "o"); + no_overflow(0x1, "no"); + %} +%} + + +// Floating comparisons that don't require any fixup for the unordered case, +// If both inputs of the comparison are the same, ZF is always set so we +// don't need to use cmpOpUCF2 for eq/ne +operand cmpOpUCF() %{ + match(Bool); + predicate(n->as_Bool()->_test._test == BoolTest::lt || + n->as_Bool()->_test._test == BoolTest::ge || + n->as_Bool()->_test._test == BoolTest::le || + n->as_Bool()->_test._test == BoolTest::gt || + n->in(1)->in(1) == n->in(1)->in(2)); + format %{ "" %} + interface(COND_INTER) %{ + equal(0xb, "np"); + not_equal(0xa, "p"); + less(0x2, "b"); + greater_equal(0x3, "ae"); + less_equal(0x6, "be"); + greater(0x7, "a"); + overflow(0x0, "o"); + no_overflow(0x1, "no"); + %} +%} + + +// Floating comparisons that can be fixed up with extra conditional jumps +operand cmpOpUCF2() %{ + match(Bool); + predicate((n->as_Bool()->_test._test == BoolTest::ne || + n->as_Bool()->_test._test == BoolTest::eq) && + n->in(1)->in(1) != n->in(1)->in(2)); + format %{ "" %} + interface(COND_INTER) %{ + equal(0x4, "e"); + not_equal(0x5, "ne"); + less(0x2, "b"); + greater_equal(0x3, "ae"); + less_equal(0x6, "be"); + greater(0x7, "a"); + overflow(0x0, "o"); + no_overflow(0x1, "no"); + %} +%} + // Operands for bound floating pointer register arguments operand rxmm0() %{ constraint(ALLOC_IN_RC(xmm0_reg)); @@ -2733,11 +6060,6 @@ operand rxmm0() %{ interface(REG_INTER); %} -//----------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. - // Vectors // Dummy generic vector class. Should be used for all vector operands. @@ -2860,7 +6182,503 @@ operand legVecZ() %{ interface(REG_INTER); %} -// INSTRUCTIONS -- Platform independent definitions (same for 32- and 64-bit) +//----------OPERAND CLASSES---------------------------------------------------- +// Operand Classes are groups of operands that are used as 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 memory(indirect, indOffset8, indOffset32, indIndexOffset, indIndex, + indIndexScale, indPosIndexScale, indIndexScaleOffset, indPosIndexOffset, indPosIndexScaleOffset, + indCompressedOopOffset, + indirectNarrow, indOffset8Narrow, indOffset32Narrow, + indIndexOffsetNarrow, indIndexNarrow, indIndexScaleNarrow, + indIndexScaleOffsetNarrow, indPosIndexOffsetNarrow, indPosIndexScaleOffsetNarrow); + +//----------PIPELINE----------------------------------------------------------- +// Rules which define the behavior of the target architectures pipeline. +pipeline %{ + +//----------ATTRIBUTES--------------------------------------------------------- +attributes %{ + variable_size_instructions; // Fixed size instructions + max_instructions_per_bundle = 3; // Up to 3 instructions per bundle + instruction_unit_size = 1; // An instruction is 1 bytes long + instruction_fetch_unit_size = 16; // The processor fetches one line + instruction_fetch_units = 1; // of 16 bytes +%} + +//----------RESOURCES---------------------------------------------------------- +// Resources are the functional units available to the machine + +// Generic P2/P3 pipeline +// 3 decoders, only D0 handles big operands; a "bundle" is the limit of +// 3 instructions decoded per cycle. +// 2 load/store ops per cycle, 1 branch, 1 FPU, +// 3 ALU op, only ALU0 handles mul instructions. +resources( D0, D1, D2, DECODE = D0 | D1 | D2, + MS0, MS1, MS2, MEM = MS0 | MS1 | MS2, + BR, FPU, + ALU0, ALU1, ALU2, ALU = ALU0 | ALU1 | ALU2); + +//----------PIPELINE DESCRIPTION----------------------------------------------- +// Pipeline Description specifies the stages in the machine's pipeline + +// Generic P2/P3 pipeline +pipe_desc(S0, S1, S2, S3, S4, S5); + +//----------PIPELINE CLASSES--------------------------------------------------- +// Pipeline Classes describe the stages in which input and output are +// referenced by the hardware pipeline. + +// Naming convention: ialu or fpu +// Then: _reg +// Then: _reg if there is a 2nd register +// Then: _long if it's a pair of instructions implementing a long +// Then: _fat if it requires the big decoder +// Or: _mem if it requires the big decoder and a memory unit. + +// Integer ALU reg operation +pipe_class ialu_reg(rRegI dst) +%{ + single_instruction; + dst : S4(write); + dst : S3(read); + DECODE : S0; // any decoder + ALU : S3; // any alu +%} + +// Long ALU reg operation +pipe_class ialu_reg_long(rRegL dst) +%{ + instruction_count(2); + dst : S4(write); + dst : S3(read); + DECODE : S0(2); // any 2 decoders + ALU : S3(2); // both alus +%} + +// Integer ALU reg operation using big decoder +pipe_class ialu_reg_fat(rRegI dst) +%{ + single_instruction; + dst : S4(write); + dst : S3(read); + D0 : S0; // big decoder only + ALU : S3; // any alu +%} + +// Integer ALU reg-reg operation +pipe_class ialu_reg_reg(rRegI dst, rRegI src) +%{ + single_instruction; + dst : S4(write); + src : S3(read); + DECODE : S0; // any decoder + ALU : S3; // any alu +%} + +// Integer ALU reg-reg operation +pipe_class ialu_reg_reg_fat(rRegI dst, memory src) +%{ + single_instruction; + dst : S4(write); + src : S3(read); + D0 : S0; // big decoder only + ALU : S3; // any alu +%} + +// Integer ALU reg-mem operation +pipe_class ialu_reg_mem(rRegI dst, memory mem) +%{ + single_instruction; + dst : S5(write); + mem : S3(read); + D0 : S0; // big decoder only + ALU : S4; // any alu + MEM : S3; // any mem +%} + +// Integer mem operation (prefetch) +pipe_class ialu_mem(memory mem) +%{ + single_instruction; + mem : S3(read); + D0 : S0; // big decoder only + MEM : S3; // any mem +%} + +// Integer Store to Memory +pipe_class ialu_mem_reg(memory mem, rRegI src) +%{ + single_instruction; + mem : S3(read); + src : S5(read); + D0 : S0; // big decoder only + ALU : S4; // any alu + MEM : S3; +%} + +// // Long Store to Memory +// pipe_class ialu_mem_long_reg(memory mem, rRegL src) +// %{ +// instruction_count(2); +// mem : S3(read); +// src : S5(read); +// D0 : S0(2); // big decoder only; twice +// ALU : S4(2); // any 2 alus +// MEM : S3(2); // Both mems +// %} + +// Integer Store to Memory +pipe_class ialu_mem_imm(memory mem) +%{ + single_instruction; + mem : S3(read); + D0 : S0; // big decoder only + ALU : S4; // any alu + MEM : S3; +%} + +// Integer ALU0 reg-reg operation +pipe_class ialu_reg_reg_alu0(rRegI dst, rRegI src) +%{ + single_instruction; + dst : S4(write); + src : S3(read); + D0 : S0; // Big decoder only + ALU0 : S3; // only alu0 +%} + +// Integer ALU0 reg-mem operation +pipe_class ialu_reg_mem_alu0(rRegI dst, memory mem) +%{ + single_instruction; + dst : S5(write); + mem : S3(read); + D0 : S0; // big decoder only + ALU0 : S4; // ALU0 only + MEM : S3; // any mem +%} + +// Integer ALU reg-reg operation +pipe_class ialu_cr_reg_reg(rFlagsReg cr, rRegI src1, rRegI src2) +%{ + single_instruction; + cr : S4(write); + src1 : S3(read); + src2 : S3(read); + DECODE : S0; // any decoder + ALU : S3; // any alu +%} + +// Integer ALU reg-imm operation +pipe_class ialu_cr_reg_imm(rFlagsReg cr, rRegI src1) +%{ + single_instruction; + cr : S4(write); + src1 : S3(read); + DECODE : S0; // any decoder + ALU : S3; // any alu +%} + +// Integer ALU reg-mem operation +pipe_class ialu_cr_reg_mem(rFlagsReg cr, rRegI src1, memory src2) +%{ + single_instruction; + cr : S4(write); + src1 : S3(read); + src2 : S3(read); + D0 : S0; // big decoder only + ALU : S4; // any alu + MEM : S3; +%} + +// Conditional move reg-reg +pipe_class pipe_cmplt( rRegI p, rRegI q, rRegI y) +%{ + instruction_count(4); + y : S4(read); + q : S3(read); + p : S3(read); + DECODE : S0(4); // any decoder +%} + +// Conditional move reg-reg +pipe_class pipe_cmov_reg( rRegI dst, rRegI src, rFlagsReg cr) +%{ + single_instruction; + dst : S4(write); + src : S3(read); + cr : S3(read); + DECODE : S0; // any decoder +%} + +// Conditional move reg-mem +pipe_class pipe_cmov_mem( rFlagsReg cr, rRegI dst, memory src) +%{ + single_instruction; + dst : S4(write); + src : S3(read); + cr : S3(read); + DECODE : S0; // any decoder + MEM : S3; +%} + +// Conditional move reg-reg long +pipe_class pipe_cmov_reg_long( rFlagsReg cr, rRegL dst, rRegL src) +%{ + single_instruction; + dst : S4(write); + src : S3(read); + cr : S3(read); + DECODE : S0(2); // any 2 decoders +%} + +// Float reg-reg operation +pipe_class fpu_reg(regD dst) +%{ + instruction_count(2); + dst : S3(read); + DECODE : S0(2); // any 2 decoders + FPU : S3; +%} + +// Float reg-reg operation +pipe_class fpu_reg_reg(regD dst, regD src) +%{ + instruction_count(2); + dst : S4(write); + src : S3(read); + DECODE : S0(2); // any 2 decoders + FPU : S3; +%} + +// Float reg-reg operation +pipe_class fpu_reg_reg_reg(regD dst, regD src1, regD src2) +%{ + instruction_count(3); + dst : S4(write); + src1 : S3(read); + src2 : S3(read); + DECODE : S0(3); // any 3 decoders + FPU : S3(2); +%} + +// Float reg-reg operation +pipe_class fpu_reg_reg_reg_reg(regD dst, regD src1, regD src2, regD src3) +%{ + instruction_count(4); + dst : S4(write); + src1 : S3(read); + src2 : S3(read); + src3 : S3(read); + DECODE : S0(4); // any 3 decoders + FPU : S3(2); +%} + +// Float reg-reg operation +pipe_class fpu_reg_mem_reg_reg(regD dst, memory src1, regD src2, regD src3) +%{ + instruction_count(4); + dst : S4(write); + src1 : S3(read); + src2 : S3(read); + src3 : S3(read); + DECODE : S1(3); // any 3 decoders + D0 : S0; // Big decoder only + FPU : S3(2); + MEM : S3; +%} + +// Float reg-mem operation +pipe_class fpu_reg_mem(regD dst, memory mem) +%{ + instruction_count(2); + dst : S5(write); + mem : S3(read); + D0 : S0; // big decoder only + DECODE : S1; // any decoder for FPU POP + FPU : S4; + MEM : S3; // any mem +%} + +// Float reg-mem operation +pipe_class fpu_reg_reg_mem(regD dst, regD src1, memory mem) +%{ + instruction_count(3); + dst : S5(write); + src1 : S3(read); + mem : S3(read); + D0 : S0; // big decoder only + DECODE : S1(2); // any decoder for FPU POP + FPU : S4; + MEM : S3; // any mem +%} + +// Float mem-reg operation +pipe_class fpu_mem_reg(memory mem, regD src) +%{ + instruction_count(2); + src : S5(read); + mem : S3(read); + DECODE : S0; // any decoder for FPU PUSH + D0 : S1; // big decoder only + FPU : S4; + MEM : S3; // any mem +%} + +pipe_class fpu_mem_reg_reg(memory mem, regD src1, regD src2) +%{ + instruction_count(3); + src1 : S3(read); + src2 : S3(read); + mem : S3(read); + DECODE : S0(2); // any decoder for FPU PUSH + D0 : S1; // big decoder only + FPU : S4; + MEM : S3; // any mem +%} + +pipe_class fpu_mem_reg_mem(memory mem, regD src1, memory src2) +%{ + instruction_count(3); + src1 : S3(read); + src2 : S3(read); + mem : S4(read); + DECODE : S0; // any decoder for FPU PUSH + D0 : S0(2); // big decoder only + FPU : S4; + MEM : S3(2); // any mem +%} + +pipe_class fpu_mem_mem(memory dst, memory src1) +%{ + instruction_count(2); + src1 : S3(read); + dst : S4(read); + D0 : S0(2); // big decoder only + MEM : S3(2); // any mem +%} + +pipe_class fpu_mem_mem_mem(memory dst, memory src1, memory src2) +%{ + instruction_count(3); + src1 : S3(read); + src2 : S3(read); + dst : S4(read); + D0 : S0(3); // big decoder only + FPU : S4; + MEM : S3(3); // any mem +%} + +pipe_class fpu_mem_reg_con(memory mem, regD src1) +%{ + instruction_count(3); + src1 : S4(read); + mem : S4(read); + DECODE : S0; // any decoder for FPU PUSH + D0 : S0(2); // big decoder only + FPU : S4; + MEM : S3(2); // any mem +%} + +// Float load constant +pipe_class fpu_reg_con(regD dst) +%{ + instruction_count(2); + dst : S5(write); + D0 : S0; // big decoder only for the load + DECODE : S1; // any decoder for FPU POP + FPU : S4; + MEM : S3; // any mem +%} + +// Float load constant +pipe_class fpu_reg_reg_con(regD dst, regD src) +%{ + instruction_count(3); + dst : S5(write); + src : S3(read); + D0 : S0; // big decoder only for the load + DECODE : S1(2); // any decoder for FPU POP + FPU : S4; + MEM : S3; // any mem +%} + +// UnConditional branch +pipe_class pipe_jmp(label labl) +%{ + single_instruction; + BR : S3; +%} + +// Conditional branch +pipe_class pipe_jcc(cmpOp cmp, rFlagsReg cr, label labl) +%{ + single_instruction; + cr : S1(read); + BR : S3; +%} + +// Allocation idiom +pipe_class pipe_cmpxchg(rRegP dst, rRegP heap_ptr) +%{ + instruction_count(1); force_serialization; + fixed_latency(6); + heap_ptr : S3(read); + DECODE : S0(3); + D0 : S2; + MEM : S3; + ALU : S3(2); + dst : S5(write); + BR : S5; +%} + +// Generic big/slow expanded idiom +pipe_class pipe_slow() +%{ + instruction_count(10); multiple_bundles; force_serialization; + fixed_latency(100); + D0 : S0(2); + MEM : S3(2); +%} + +// The real do-nothing guy +pipe_class empty() +%{ + instruction_count(0); +%} + +// Define the class for the Nop node +define +%{ + MachNop = empty; +%} + +%} + +//----------INSTRUCTIONS------------------------------------------------------- +// +// match -- States which machine-independent subtree may be replaced +// by this instruction. +// ins_cost -- The estimated cost of this instruction is used by instruction +// selection to identify a minimum cost tree of machine +// instructions that matches a tree of machine-independent +// instructions. +// format -- A string providing the disassembly for this instruction. +// The value of an instruction's operand may be inserted +// by referring to it with a '$' prefix. +// opcode -- Three instruction opcodes may be provided. These are referred +// to within an encode class as $primary, $secondary, and $tertiary +// rrspectively. The primary opcode is commonly used to +// indicate the type of machine instruction, while secondary +// and tertiary are often used for prefix options or addressing +// modes. +// ins_encode -- A list of encode classes with parameters. The encode class +// name must have been defined in an 'enc_class' specification +// in the encode section of the architecture description. // ============================================================================ @@ -2878,6 +6696,10516 @@ instruct ShouldNotReachHere() %{ // ============================================================================ +// Dummy reg-to-reg vector moves. Removed during post-selection cleanup. +// Load Float +instruct MoveF2VL(vlRegF dst, regF src) %{ + match(Set dst src); + format %{ "movss $dst,$src\t! load float (4 bytes)" %} + ins_encode %{ + ShouldNotReachHere(); + %} + ins_pipe( fpu_reg_reg ); +%} + +// Load Float +instruct MoveF2LEG(legRegF dst, regF src) %{ + match(Set dst src); + format %{ "movss $dst,$src\t# if src != dst load float (4 bytes)" %} + ins_encode %{ + ShouldNotReachHere(); + %} + ins_pipe( fpu_reg_reg ); +%} + +// Load Float +instruct MoveVL2F(regF dst, vlRegF src) %{ + match(Set dst src); + format %{ "movss $dst,$src\t! load float (4 bytes)" %} + ins_encode %{ + ShouldNotReachHere(); + %} + ins_pipe( fpu_reg_reg ); +%} + +// Load Float +instruct MoveLEG2F(regF dst, legRegF src) %{ + match(Set dst src); + format %{ "movss $dst,$src\t# if src != dst load float (4 bytes)" %} + ins_encode %{ + ShouldNotReachHere(); + %} + ins_pipe( fpu_reg_reg ); +%} + +// Load Double +instruct MoveD2VL(vlRegD dst, regD src) %{ + match(Set dst src); + format %{ "movsd $dst,$src\t! load double (8 bytes)" %} + ins_encode %{ + ShouldNotReachHere(); + %} + ins_pipe( fpu_reg_reg ); +%} + +// Load Double +instruct MoveD2LEG(legRegD dst, regD src) %{ + match(Set dst src); + format %{ "movsd $dst,$src\t# if src != dst load double (8 bytes)" %} + ins_encode %{ + ShouldNotReachHere(); + %} + ins_pipe( fpu_reg_reg ); +%} + +// Load Double +instruct MoveVL2D(regD dst, vlRegD src) %{ + match(Set dst src); + format %{ "movsd $dst,$src\t! load double (8 bytes)" %} + ins_encode %{ + ShouldNotReachHere(); + %} + ins_pipe( fpu_reg_reg ); +%} + +// Load Double +instruct MoveLEG2D(regD dst, legRegD src) %{ + match(Set dst src); + format %{ "movsd $dst,$src\t# if src != dst load double (8 bytes)" %} + ins_encode %{ + ShouldNotReachHere(); + %} + ins_pipe( fpu_reg_reg ); +%} + +//----------Load/Store/Move Instructions--------------------------------------- +//----------Load Instructions-------------------------------------------------- + +// Load Byte (8 bit signed) +instruct loadB(rRegI dst, memory mem) +%{ + match(Set dst (LoadB mem)); + + ins_cost(125); + format %{ "movsbl $dst, $mem\t# byte" %} + + ins_encode %{ + __ movsbl($dst$$Register, $mem$$Address); + %} + + ins_pipe(ialu_reg_mem); +%} + +// Load Byte (8 bit signed) into Long Register +instruct loadB2L(rRegL dst, memory mem) +%{ + match(Set dst (ConvI2L (LoadB mem))); + + ins_cost(125); + format %{ "movsbq $dst, $mem\t# byte -> long" %} + + ins_encode %{ + __ movsbq($dst$$Register, $mem$$Address); + %} + + ins_pipe(ialu_reg_mem); +%} + +// Load Unsigned Byte (8 bit UNsigned) +instruct loadUB(rRegI dst, memory mem) +%{ + match(Set dst (LoadUB mem)); + + ins_cost(125); + format %{ "movzbl $dst, $mem\t# ubyte" %} + + ins_encode %{ + __ movzbl($dst$$Register, $mem$$Address); + %} + + ins_pipe(ialu_reg_mem); +%} + +// Load Unsigned Byte (8 bit UNsigned) into Long Register +instruct loadUB2L(rRegL dst, memory mem) +%{ + match(Set dst (ConvI2L (LoadUB mem))); + + ins_cost(125); + format %{ "movzbq $dst, $mem\t# ubyte -> long" %} + + ins_encode %{ + __ movzbq($dst$$Register, $mem$$Address); + %} + + ins_pipe(ialu_reg_mem); +%} + +// Load Unsigned Byte (8 bit UNsigned) with 32-bit mask into Long Register +instruct loadUB2L_immI(rRegL dst, memory mem, immI mask, rFlagsReg cr) %{ + match(Set dst (ConvI2L (AndI (LoadUB mem) mask))); + effect(KILL cr); + + format %{ "movzbq $dst, $mem\t# ubyte & 32-bit mask -> long\n\t" + "andl $dst, right_n_bits($mask, 8)" %} + ins_encode %{ + Register Rdst = $dst$$Register; + __ movzbq(Rdst, $mem$$Address); + __ andl(Rdst, $mask$$constant & right_n_bits(8)); + %} + ins_pipe(ialu_reg_mem); +%} + +// Load Short (16 bit signed) +instruct loadS(rRegI dst, memory mem) +%{ + match(Set dst (LoadS mem)); + + ins_cost(125); + format %{ "movswl $dst, $mem\t# short" %} + + ins_encode %{ + __ movswl($dst$$Register, $mem$$Address); + %} + + ins_pipe(ialu_reg_mem); +%} + +// Load Short (16 bit signed) to Byte (8 bit signed) +instruct loadS2B(rRegI dst, memory mem, immI_24 twentyfour) %{ + match(Set dst (RShiftI (LShiftI (LoadS mem) twentyfour) twentyfour)); + + ins_cost(125); + format %{ "movsbl $dst, $mem\t# short -> byte" %} + ins_encode %{ + __ movsbl($dst$$Register, $mem$$Address); + %} + ins_pipe(ialu_reg_mem); +%} + +// Load Short (16 bit signed) into Long Register +instruct loadS2L(rRegL dst, memory mem) +%{ + match(Set dst (ConvI2L (LoadS mem))); + + ins_cost(125); + format %{ "movswq $dst, $mem\t# short -> long" %} + + ins_encode %{ + __ movswq($dst$$Register, $mem$$Address); + %} + + ins_pipe(ialu_reg_mem); +%} + +// Load Unsigned Short/Char (16 bit UNsigned) +instruct loadUS(rRegI dst, memory mem) +%{ + match(Set dst (LoadUS mem)); + + ins_cost(125); + format %{ "movzwl $dst, $mem\t# ushort/char" %} + + ins_encode %{ + __ movzwl($dst$$Register, $mem$$Address); + %} + + ins_pipe(ialu_reg_mem); +%} + +// Load Unsigned Short/Char (16 bit UNsigned) to Byte (8 bit signed) +instruct loadUS2B(rRegI dst, memory mem, immI_24 twentyfour) %{ + match(Set dst (RShiftI (LShiftI (LoadUS mem) twentyfour) twentyfour)); + + ins_cost(125); + format %{ "movsbl $dst, $mem\t# ushort -> byte" %} + ins_encode %{ + __ movsbl($dst$$Register, $mem$$Address); + %} + ins_pipe(ialu_reg_mem); +%} + +// Load Unsigned Short/Char (16 bit UNsigned) into Long Register +instruct loadUS2L(rRegL dst, memory mem) +%{ + match(Set dst (ConvI2L (LoadUS mem))); + + ins_cost(125); + format %{ "movzwq $dst, $mem\t# ushort/char -> long" %} + + ins_encode %{ + __ movzwq($dst$$Register, $mem$$Address); + %} + + ins_pipe(ialu_reg_mem); +%} + +// Load Unsigned Short/Char (16 bit UNsigned) with mask 0xFF into Long Register +instruct loadUS2L_immI_255(rRegL dst, memory mem, immI_255 mask) %{ + match(Set dst (ConvI2L (AndI (LoadUS mem) mask))); + + format %{ "movzbq $dst, $mem\t# ushort/char & 0xFF -> long" %} + ins_encode %{ + __ movzbq($dst$$Register, $mem$$Address); + %} + ins_pipe(ialu_reg_mem); +%} + +// Load Unsigned Short/Char (16 bit UNsigned) with 32-bit mask into Long Register +instruct loadUS2L_immI(rRegL dst, memory mem, immI mask, rFlagsReg cr) %{ + match(Set dst (ConvI2L (AndI (LoadUS mem) mask))); + effect(KILL cr); + + format %{ "movzwq $dst, $mem\t# ushort/char & 32-bit mask -> long\n\t" + "andl $dst, right_n_bits($mask, 16)" %} + ins_encode %{ + Register Rdst = $dst$$Register; + __ movzwq(Rdst, $mem$$Address); + __ andl(Rdst, $mask$$constant & right_n_bits(16)); + %} + ins_pipe(ialu_reg_mem); +%} + +// Load Integer +instruct loadI(rRegI dst, memory mem) +%{ + match(Set dst (LoadI mem)); + + ins_cost(125); + format %{ "movl $dst, $mem\t# int" %} + + ins_encode %{ + __ movl($dst$$Register, $mem$$Address); + %} + + ins_pipe(ialu_reg_mem); +%} + +// Load Integer (32 bit signed) to Byte (8 bit signed) +instruct loadI2B(rRegI dst, memory mem, immI_24 twentyfour) %{ + match(Set dst (RShiftI (LShiftI (LoadI mem) twentyfour) twentyfour)); + + ins_cost(125); + format %{ "movsbl $dst, $mem\t# int -> byte" %} + ins_encode %{ + __ movsbl($dst$$Register, $mem$$Address); + %} + ins_pipe(ialu_reg_mem); +%} + +// Load Integer (32 bit signed) to Unsigned Byte (8 bit UNsigned) +instruct loadI2UB(rRegI dst, memory mem, immI_255 mask) %{ + match(Set dst (AndI (LoadI mem) mask)); + + ins_cost(125); + format %{ "movzbl $dst, $mem\t# int -> ubyte" %} + ins_encode %{ + __ movzbl($dst$$Register, $mem$$Address); + %} + ins_pipe(ialu_reg_mem); +%} + +// Load Integer (32 bit signed) to Short (16 bit signed) +instruct loadI2S(rRegI dst, memory mem, immI_16 sixteen) %{ + match(Set dst (RShiftI (LShiftI (LoadI mem) sixteen) sixteen)); + + ins_cost(125); + format %{ "movswl $dst, $mem\t# int -> short" %} + ins_encode %{ + __ movswl($dst$$Register, $mem$$Address); + %} + ins_pipe(ialu_reg_mem); +%} + +// Load Integer (32 bit signed) to Unsigned Short/Char (16 bit UNsigned) +instruct loadI2US(rRegI dst, memory mem, immI_65535 mask) %{ + match(Set dst (AndI (LoadI mem) mask)); + + ins_cost(125); + format %{ "movzwl $dst, $mem\t# int -> ushort/char" %} + ins_encode %{ + __ movzwl($dst$$Register, $mem$$Address); + %} + ins_pipe(ialu_reg_mem); +%} + +// Load Integer into Long Register +instruct loadI2L(rRegL dst, memory mem) +%{ + match(Set dst (ConvI2L (LoadI mem))); + + ins_cost(125); + format %{ "movslq $dst, $mem\t# int -> long" %} + + ins_encode %{ + __ movslq($dst$$Register, $mem$$Address); + %} + + ins_pipe(ialu_reg_mem); +%} + +// Load Integer with mask 0xFF into Long Register +instruct loadI2L_immI_255(rRegL dst, memory mem, immI_255 mask) %{ + match(Set dst (ConvI2L (AndI (LoadI mem) mask))); + + format %{ "movzbq $dst, $mem\t# int & 0xFF -> long" %} + ins_encode %{ + __ movzbq($dst$$Register, $mem$$Address); + %} + ins_pipe(ialu_reg_mem); +%} + +// Load Integer with mask 0xFFFF into Long Register +instruct loadI2L_immI_65535(rRegL dst, memory mem, immI_65535 mask) %{ + match(Set dst (ConvI2L (AndI (LoadI mem) mask))); + + format %{ "movzwq $dst, $mem\t# int & 0xFFFF -> long" %} + ins_encode %{ + __ movzwq($dst$$Register, $mem$$Address); + %} + ins_pipe(ialu_reg_mem); +%} + +// Load Integer with a 31-bit mask into Long Register +instruct loadI2L_immU31(rRegL dst, memory mem, immU31 mask, rFlagsReg cr) %{ + match(Set dst (ConvI2L (AndI (LoadI mem) mask))); + effect(KILL cr); + + format %{ "movl $dst, $mem\t# int & 31-bit mask -> long\n\t" + "andl $dst, $mask" %} + ins_encode %{ + Register Rdst = $dst$$Register; + __ movl(Rdst, $mem$$Address); + __ andl(Rdst, $mask$$constant); + %} + ins_pipe(ialu_reg_mem); +%} + +// Load Unsigned Integer into Long Register +instruct loadUI2L(rRegL dst, memory mem, immL_32bits mask) +%{ + match(Set dst (AndL (ConvI2L (LoadI mem)) mask)); + + ins_cost(125); + format %{ "movl $dst, $mem\t# uint -> long" %} + + ins_encode %{ + __ movl($dst$$Register, $mem$$Address); + %} + + ins_pipe(ialu_reg_mem); +%} + +// Load Long +instruct loadL(rRegL dst, memory mem) +%{ + match(Set dst (LoadL mem)); + + ins_cost(125); + format %{ "movq $dst, $mem\t# long" %} + + ins_encode %{ + __ movq($dst$$Register, $mem$$Address); + %} + + ins_pipe(ialu_reg_mem); // XXX +%} + +// Load Range +instruct loadRange(rRegI dst, memory mem) +%{ + match(Set dst (LoadRange mem)); + + ins_cost(125); // XXX + format %{ "movl $dst, $mem\t# range" %} + ins_encode %{ + __ movl($dst$$Register, $mem$$Address); + %} + ins_pipe(ialu_reg_mem); +%} + +// Load Pointer +instruct loadP(rRegP dst, memory mem) +%{ + match(Set dst (LoadP mem)); + predicate(n->as_Load()->barrier_data() == 0); + + ins_cost(125); // XXX + format %{ "movq $dst, $mem\t# ptr" %} + ins_encode %{ + __ movq($dst$$Register, $mem$$Address); + %} + ins_pipe(ialu_reg_mem); // XXX +%} + +// Load Compressed Pointer +instruct loadN(rRegN dst, memory mem) +%{ + predicate(n->as_Load()->barrier_data() == 0); + match(Set dst (LoadN mem)); + + ins_cost(125); // XXX + format %{ "movl $dst, $mem\t# compressed ptr" %} + ins_encode %{ + __ movl($dst$$Register, $mem$$Address); + %} + ins_pipe(ialu_reg_mem); // XXX +%} + + +// Load Klass Pointer +instruct loadKlass(rRegP dst, memory mem) +%{ + match(Set dst (LoadKlass mem)); + + ins_cost(125); // XXX + format %{ "movq $dst, $mem\t# class" %} + ins_encode %{ + __ movq($dst$$Register, $mem$$Address); + %} + ins_pipe(ialu_reg_mem); // XXX +%} + +// Load narrow Klass Pointer +instruct loadNKlass(rRegN dst, memory mem) +%{ + predicate(!UseCompactObjectHeaders); + match(Set dst (LoadNKlass mem)); + + ins_cost(125); // XXX + format %{ "movl $dst, $mem\t# compressed klass ptr" %} + ins_encode %{ + __ movl($dst$$Register, $mem$$Address); + %} + ins_pipe(ialu_reg_mem); // XXX +%} + +instruct loadNKlassCompactHeaders(rRegN dst, memory mem, rFlagsReg cr) +%{ + predicate(UseCompactObjectHeaders); + match(Set dst (LoadNKlass mem)); + effect(KILL cr); + ins_cost(125); + format %{ + "movl $dst, $mem\t# compressed klass ptr, shifted\n\t" + "shrl $dst, markWord::klass_shift_at_offset" + %} + ins_encode %{ + if (UseAPX) { + __ eshrl($dst$$Register, $mem$$Address, markWord::klass_shift_at_offset, false); + } + else { + __ movl($dst$$Register, $mem$$Address); + __ shrl($dst$$Register, markWord::klass_shift_at_offset); + } + %} + ins_pipe(ialu_reg_mem); +%} + +// Load Float +instruct loadF(regF dst, memory mem) +%{ + match(Set dst (LoadF mem)); + + ins_cost(145); // XXX + format %{ "movss $dst, $mem\t# float" %} + ins_encode %{ + __ movflt($dst$$XMMRegister, $mem$$Address); + %} + ins_pipe(pipe_slow); // XXX +%} + +// Load Double +instruct loadD_partial(regD dst, memory mem) +%{ + predicate(!UseXmmLoadAndClearUpper); + match(Set dst (LoadD mem)); + + ins_cost(145); // XXX + format %{ "movlpd $dst, $mem\t# double" %} + ins_encode %{ + __ movdbl($dst$$XMMRegister, $mem$$Address); + %} + ins_pipe(pipe_slow); // XXX +%} + +instruct loadD(regD dst, memory mem) +%{ + predicate(UseXmmLoadAndClearUpper); + match(Set dst (LoadD mem)); + + ins_cost(145); // XXX + format %{ "movsd $dst, $mem\t# double" %} + ins_encode %{ + __ movdbl($dst$$XMMRegister, $mem$$Address); + %} + ins_pipe(pipe_slow); // XXX +%} + +// max = java.lang.Math.max(float a, float b) +instruct maxF_avx10_reg(regF dst, regF a, regF b) %{ + predicate(VM_Version::supports_avx10_2()); + match(Set dst (MaxF a b)); + format %{ "maxF $dst, $a, $b" %} + ins_encode %{ + __ eminmaxss($dst$$XMMRegister, $a$$XMMRegister, $b$$XMMRegister, AVX10_MINMAX_MAX_COMPARE_SIGN); + %} + ins_pipe( pipe_slow ); +%} + +// max = java.lang.Math.max(float a, float b) +instruct maxF_reg(legRegF dst, legRegF a, legRegF b, legRegF tmp, legRegF atmp, legRegF btmp) %{ + predicate(!VM_Version::supports_avx10_2() && UseAVX > 0 && !VLoopReductions::is_reduction(n)); + match(Set dst (MaxF a b)); + effect(USE a, USE b, TEMP tmp, TEMP atmp, TEMP btmp); + format %{ "maxF $dst, $a, $b \t! using $tmp, $atmp and $btmp as TEMP" %} + ins_encode %{ + __ vminmax_fp(Op_MaxV, T_FLOAT, $dst$$XMMRegister, $a$$XMMRegister, $b$$XMMRegister, $tmp$$XMMRegister, $atmp$$XMMRegister, $btmp$$XMMRegister, Assembler::AVX_128bit); + %} + ins_pipe( pipe_slow ); +%} + +instruct maxF_reduction_reg(legRegF dst, legRegF a, legRegF b, legRegF xtmp, rRegI rtmp, rFlagsReg cr) %{ + predicate(!VM_Version::supports_avx10_2() && UseAVX > 0 && VLoopReductions::is_reduction(n)); + match(Set dst (MaxF a b)); + effect(USE a, USE b, TEMP xtmp, TEMP rtmp, KILL cr); + + format %{ "maxF_reduction $dst, $a, $b \t!using $xtmp and $rtmp as TEMP" %} + ins_encode %{ + emit_fp_min_max(masm, $dst$$XMMRegister, $a$$XMMRegister, $b$$XMMRegister, $xtmp$$XMMRegister, $rtmp$$Register, + false /*min*/, true /*single*/); + %} + ins_pipe( pipe_slow ); +%} + +// max = java.lang.Math.max(double a, double b) +instruct maxD_avx10_reg(regD dst, regD a, regD b) %{ + predicate(VM_Version::supports_avx10_2()); + match(Set dst (MaxD a b)); + format %{ "maxD $dst, $a, $b" %} + ins_encode %{ + __ eminmaxsd($dst$$XMMRegister, $a$$XMMRegister, $b$$XMMRegister, AVX10_MINMAX_MAX_COMPARE_SIGN); + %} + ins_pipe( pipe_slow ); +%} + +// max = java.lang.Math.max(double a, double b) +instruct maxD_reg(legRegD dst, legRegD a, legRegD b, legRegD tmp, legRegD atmp, legRegD btmp) %{ + predicate(!VM_Version::supports_avx10_2() && UseAVX > 0 && !VLoopReductions::is_reduction(n)); + match(Set dst (MaxD a b)); + effect(USE a, USE b, TEMP atmp, TEMP btmp, TEMP tmp); + format %{ "maxD $dst, $a, $b \t! using $tmp, $atmp and $btmp as TEMP" %} + ins_encode %{ + __ vminmax_fp(Op_MaxV, T_DOUBLE, $dst$$XMMRegister, $a$$XMMRegister, $b$$XMMRegister, $tmp$$XMMRegister, $atmp$$XMMRegister, $btmp$$XMMRegister, Assembler::AVX_128bit); + %} + ins_pipe( pipe_slow ); +%} + +instruct maxD_reduction_reg(legRegD dst, legRegD a, legRegD b, legRegD xtmp, rRegL rtmp, rFlagsReg cr) %{ + predicate(!VM_Version::supports_avx10_2() && UseAVX > 0 && VLoopReductions::is_reduction(n)); + match(Set dst (MaxD a b)); + effect(USE a, USE b, TEMP xtmp, TEMP rtmp, KILL cr); + + format %{ "maxD_reduction $dst, $a, $b \t! using $xtmp and $rtmp as TEMP" %} + ins_encode %{ + emit_fp_min_max(masm, $dst$$XMMRegister, $a$$XMMRegister, $b$$XMMRegister, $xtmp$$XMMRegister, $rtmp$$Register, + false /*min*/, false /*single*/); + %} + ins_pipe( pipe_slow ); +%} + +// max = java.lang.Math.min(float a, float b) +instruct minF_avx10_reg(regF dst, regF a, regF b) %{ + predicate(VM_Version::supports_avx10_2()); + match(Set dst (MinF a b)); + format %{ "minF $dst, $a, $b" %} + ins_encode %{ + __ eminmaxss($dst$$XMMRegister, $a$$XMMRegister, $b$$XMMRegister, AVX10_MINMAX_MIN_COMPARE_SIGN); + %} + ins_pipe( pipe_slow ); +%} + +// min = java.lang.Math.min(float a, float b) +instruct minF_reg(legRegF dst, legRegF a, legRegF b, legRegF tmp, legRegF atmp, legRegF btmp) %{ + predicate(!VM_Version::supports_avx10_2() && UseAVX > 0 && !VLoopReductions::is_reduction(n)); + match(Set dst (MinF a b)); + effect(USE a, USE b, TEMP tmp, TEMP atmp, TEMP btmp); + format %{ "minF $dst, $a, $b \t! using $tmp, $atmp and $btmp as TEMP" %} + ins_encode %{ + __ vminmax_fp(Op_MinV, T_FLOAT, $dst$$XMMRegister, $a$$XMMRegister, $b$$XMMRegister, $tmp$$XMMRegister, $atmp$$XMMRegister, $btmp$$XMMRegister, Assembler::AVX_128bit); + %} + ins_pipe( pipe_slow ); +%} + +instruct minF_reduction_reg(legRegF dst, legRegF a, legRegF b, legRegF xtmp, rRegI rtmp, rFlagsReg cr) %{ + predicate(!VM_Version::supports_avx10_2() && UseAVX > 0 && VLoopReductions::is_reduction(n)); + match(Set dst (MinF a b)); + effect(USE a, USE b, TEMP xtmp, TEMP rtmp, KILL cr); + + format %{ "minF_reduction $dst, $a, $b \t! using $xtmp and $rtmp as TEMP" %} + ins_encode %{ + emit_fp_min_max(masm, $dst$$XMMRegister, $a$$XMMRegister, $b$$XMMRegister, $xtmp$$XMMRegister, $rtmp$$Register, + true /*min*/, true /*single*/); + %} + ins_pipe( pipe_slow ); +%} + +// max = java.lang.Math.min(double a, double b) +instruct minD_avx10_reg(regD dst, regD a, regD b) %{ + predicate(VM_Version::supports_avx10_2()); + match(Set dst (MinD a b)); + format %{ "minD $dst, $a, $b" %} + ins_encode %{ + __ eminmaxsd($dst$$XMMRegister, $a$$XMMRegister, $b$$XMMRegister, AVX10_MINMAX_MIN_COMPARE_SIGN); + %} + ins_pipe( pipe_slow ); +%} + +// min = java.lang.Math.min(double a, double b) +instruct minD_reg(legRegD dst, legRegD a, legRegD b, legRegD tmp, legRegD atmp, legRegD btmp) %{ + predicate(!VM_Version::supports_avx10_2() && UseAVX > 0 && !VLoopReductions::is_reduction(n)); + match(Set dst (MinD a b)); + effect(USE a, USE b, TEMP tmp, TEMP atmp, TEMP btmp); + format %{ "minD $dst, $a, $b \t! using $tmp, $atmp and $btmp as TEMP" %} + ins_encode %{ + __ vminmax_fp(Op_MinV, T_DOUBLE, $dst$$XMMRegister, $a$$XMMRegister, $b$$XMMRegister, $tmp$$XMMRegister, $atmp$$XMMRegister, $btmp$$XMMRegister, Assembler::AVX_128bit); + %} + ins_pipe( pipe_slow ); +%} + +instruct minD_reduction_reg(legRegD dst, legRegD a, legRegD b, legRegD xtmp, rRegL rtmp, rFlagsReg cr) %{ + predicate(!VM_Version::supports_avx10_2() && UseAVX > 0 && VLoopReductions::is_reduction(n)); + match(Set dst (MinD a b)); + effect(USE a, USE b, TEMP xtmp, TEMP rtmp, KILL cr); + + format %{ "maxD_reduction $dst, $a, $b \t! using $xtmp and $rtmp as TEMP" %} + ins_encode %{ + emit_fp_min_max(masm, $dst$$XMMRegister, $a$$XMMRegister, $b$$XMMRegister, $xtmp$$XMMRegister, $rtmp$$Register, + true /*min*/, false /*single*/); + %} + ins_pipe( pipe_slow ); +%} + +// Load Effective Address +instruct leaP8(rRegP dst, indOffset8 mem) +%{ + match(Set dst mem); + + ins_cost(110); // XXX + format %{ "leaq $dst, $mem\t# ptr 8" %} + ins_encode %{ + __ leaq($dst$$Register, $mem$$Address); + %} + ins_pipe(ialu_reg_reg_fat); +%} + +instruct leaP32(rRegP dst, indOffset32 mem) +%{ + match(Set dst mem); + + ins_cost(110); + format %{ "leaq $dst, $mem\t# ptr 32" %} + ins_encode %{ + __ leaq($dst$$Register, $mem$$Address); + %} + ins_pipe(ialu_reg_reg_fat); +%} + +instruct leaPIdxOff(rRegP dst, indIndexOffset mem) +%{ + match(Set dst mem); + + ins_cost(110); + format %{ "leaq $dst, $mem\t# ptr idxoff" %} + ins_encode %{ + __ leaq($dst$$Register, $mem$$Address); + %} + ins_pipe(ialu_reg_reg_fat); +%} + +instruct leaPIdxScale(rRegP dst, indIndexScale mem) +%{ + match(Set dst mem); + + ins_cost(110); + format %{ "leaq $dst, $mem\t# ptr idxscale" %} + ins_encode %{ + __ leaq($dst$$Register, $mem$$Address); + %} + ins_pipe(ialu_reg_reg_fat); +%} + +instruct leaPPosIdxScale(rRegP dst, indPosIndexScale mem) +%{ + match(Set dst mem); + + ins_cost(110); + format %{ "leaq $dst, $mem\t# ptr idxscale" %} + ins_encode %{ + __ leaq($dst$$Register, $mem$$Address); + %} + ins_pipe(ialu_reg_reg_fat); +%} + +instruct leaPIdxScaleOff(rRegP dst, indIndexScaleOffset mem) +%{ + match(Set dst mem); + + ins_cost(110); + format %{ "leaq $dst, $mem\t# ptr idxscaleoff" %} + ins_encode %{ + __ leaq($dst$$Register, $mem$$Address); + %} + ins_pipe(ialu_reg_reg_fat); +%} + +instruct leaPPosIdxOff(rRegP dst, indPosIndexOffset mem) +%{ + match(Set dst mem); + + ins_cost(110); + format %{ "leaq $dst, $mem\t# ptr posidxoff" %} + ins_encode %{ + __ leaq($dst$$Register, $mem$$Address); + %} + ins_pipe(ialu_reg_reg_fat); +%} + +instruct leaPPosIdxScaleOff(rRegP dst, indPosIndexScaleOffset mem) +%{ + match(Set dst mem); + + ins_cost(110); + format %{ "leaq $dst, $mem\t# ptr posidxscaleoff" %} + ins_encode %{ + __ leaq($dst$$Register, $mem$$Address); + %} + ins_pipe(ialu_reg_reg_fat); +%} + +// Load Effective Address which uses Narrow (32-bits) oop +instruct leaPCompressedOopOffset(rRegP dst, indCompressedOopOffset mem) +%{ + predicate(UseCompressedOops && (CompressedOops::shift() != 0)); + match(Set dst mem); + + ins_cost(110); + format %{ "leaq $dst, $mem\t# ptr compressedoopoff32" %} + ins_encode %{ + __ leaq($dst$$Register, $mem$$Address); + %} + ins_pipe(ialu_reg_reg_fat); +%} + +instruct leaP8Narrow(rRegP dst, indOffset8Narrow mem) +%{ + predicate(CompressedOops::shift() == 0); + match(Set dst mem); + + ins_cost(110); // XXX + format %{ "leaq $dst, $mem\t# ptr off8narrow" %} + ins_encode %{ + __ leaq($dst$$Register, $mem$$Address); + %} + ins_pipe(ialu_reg_reg_fat); +%} + +instruct leaP32Narrow(rRegP dst, indOffset32Narrow mem) +%{ + predicate(CompressedOops::shift() == 0); + match(Set dst mem); + + ins_cost(110); + format %{ "leaq $dst, $mem\t# ptr off32narrow" %} + ins_encode %{ + __ leaq($dst$$Register, $mem$$Address); + %} + ins_pipe(ialu_reg_reg_fat); +%} + +instruct leaPIdxOffNarrow(rRegP dst, indIndexOffsetNarrow mem) +%{ + predicate(CompressedOops::shift() == 0); + match(Set dst mem); + + ins_cost(110); + format %{ "leaq $dst, $mem\t# ptr idxoffnarrow" %} + ins_encode %{ + __ leaq($dst$$Register, $mem$$Address); + %} + ins_pipe(ialu_reg_reg_fat); +%} + +instruct leaPIdxScaleNarrow(rRegP dst, indIndexScaleNarrow mem) +%{ + predicate(CompressedOops::shift() == 0); + match(Set dst mem); + + ins_cost(110); + format %{ "leaq $dst, $mem\t# ptr idxscalenarrow" %} + ins_encode %{ + __ leaq($dst$$Register, $mem$$Address); + %} + ins_pipe(ialu_reg_reg_fat); +%} + +instruct leaPIdxScaleOffNarrow(rRegP dst, indIndexScaleOffsetNarrow mem) +%{ + predicate(CompressedOops::shift() == 0); + match(Set dst mem); + + ins_cost(110); + format %{ "leaq $dst, $mem\t# ptr idxscaleoffnarrow" %} + ins_encode %{ + __ leaq($dst$$Register, $mem$$Address); + %} + ins_pipe(ialu_reg_reg_fat); +%} + +instruct leaPPosIdxOffNarrow(rRegP dst, indPosIndexOffsetNarrow mem) +%{ + predicate(CompressedOops::shift() == 0); + match(Set dst mem); + + ins_cost(110); + format %{ "leaq $dst, $mem\t# ptr posidxoffnarrow" %} + ins_encode %{ + __ leaq($dst$$Register, $mem$$Address); + %} + ins_pipe(ialu_reg_reg_fat); +%} + +instruct leaPPosIdxScaleOffNarrow(rRegP dst, indPosIndexScaleOffsetNarrow mem) +%{ + predicate(CompressedOops::shift() == 0); + match(Set dst mem); + + ins_cost(110); + format %{ "leaq $dst, $mem\t# ptr posidxscaleoffnarrow" %} + ins_encode %{ + __ leaq($dst$$Register, $mem$$Address); + %} + ins_pipe(ialu_reg_reg_fat); +%} + +instruct loadConI(rRegI dst, immI src) +%{ + match(Set dst src); + + format %{ "movl $dst, $src\t# int" %} + ins_encode %{ + __ movl($dst$$Register, $src$$constant); + %} + ins_pipe(ialu_reg_fat); // XXX +%} + +instruct loadConI0(rRegI dst, immI_0 src, rFlagsReg cr) +%{ + match(Set dst src); + effect(KILL cr); + + ins_cost(50); + format %{ "xorl $dst, $dst\t# int" %} + ins_encode %{ + __ xorl($dst$$Register, $dst$$Register); + %} + ins_pipe(ialu_reg); +%} + +instruct loadConL(rRegL dst, immL src) +%{ + match(Set dst src); + + ins_cost(150); + format %{ "movq $dst, $src\t# long" %} + ins_encode %{ + __ mov64($dst$$Register, $src$$constant); + %} + ins_pipe(ialu_reg); +%} + +instruct loadConL0(rRegL dst, immL0 src, rFlagsReg cr) +%{ + match(Set dst src); + effect(KILL cr); + + ins_cost(50); + format %{ "xorl $dst, $dst\t# long" %} + ins_encode %{ + __ xorl($dst$$Register, $dst$$Register); + %} + ins_pipe(ialu_reg); // XXX +%} + +instruct loadConUL32(rRegL dst, immUL32 src) +%{ + match(Set dst src); + + ins_cost(60); + format %{ "movl $dst, $src\t# long (unsigned 32-bit)" %} + ins_encode %{ + __ movl($dst$$Register, $src$$constant); + %} + ins_pipe(ialu_reg); +%} + +instruct loadConL32(rRegL dst, immL32 src) +%{ + match(Set dst src); + + ins_cost(70); + format %{ "movq $dst, $src\t# long (32-bit)" %} + ins_encode %{ + __ movq($dst$$Register, $src$$constant); + %} + ins_pipe(ialu_reg); +%} + +instruct loadConP(rRegP dst, immP con) %{ + match(Set dst con); + + format %{ "movq $dst, $con\t# ptr" %} + ins_encode %{ + __ mov64($dst$$Register, $con$$constant, $con->constant_reloc(), RELOC_IMM64); + %} + ins_pipe(ialu_reg_fat); // XXX +%} + +instruct loadConP0(rRegP dst, immP0 src, rFlagsReg cr) +%{ + match(Set dst src); + effect(KILL cr); + + ins_cost(50); + format %{ "xorl $dst, $dst\t# ptr" %} + ins_encode %{ + __ xorl($dst$$Register, $dst$$Register); + %} + ins_pipe(ialu_reg); +%} + +instruct loadConP31(rRegP dst, immP31 src, rFlagsReg cr) +%{ + match(Set dst src); + effect(KILL cr); + + ins_cost(60); + format %{ "movl $dst, $src\t# ptr (positive 32-bit)" %} + ins_encode %{ + __ movl($dst$$Register, $src$$constant); + %} + ins_pipe(ialu_reg); +%} + +instruct loadConF(regF dst, immF con) %{ + match(Set dst con); + ins_cost(125); + format %{ "movss $dst, [$constantaddress]\t# load from constant table: float=$con" %} + ins_encode %{ + __ movflt($dst$$XMMRegister, $constantaddress($con)); + %} + ins_pipe(pipe_slow); +%} + +instruct loadConH(regF dst, immH con) %{ + match(Set dst con); + ins_cost(125); + format %{ "movss $dst, [$constantaddress]\t# load from constant table: halffloat=$con" %} + ins_encode %{ + __ movflt($dst$$XMMRegister, $constantaddress($con)); + %} + ins_pipe(pipe_slow); +%} + +instruct loadConN0(rRegN dst, immN0 src, rFlagsReg cr) %{ + match(Set dst src); + effect(KILL cr); + format %{ "xorq $dst, $src\t# compressed null pointer" %} + ins_encode %{ + __ xorq($dst$$Register, $dst$$Register); + %} + ins_pipe(ialu_reg); +%} + +instruct loadConN(rRegN dst, immN src) %{ + match(Set dst src); + + ins_cost(125); + format %{ "movl $dst, $src\t# compressed ptr" %} + ins_encode %{ + address con = (address)$src$$constant; + if (con == nullptr) { + ShouldNotReachHere(); + } else { + __ set_narrow_oop($dst$$Register, (jobject)$src$$constant); + } + %} + ins_pipe(ialu_reg_fat); // XXX +%} + +instruct loadConNKlass(rRegN dst, immNKlass src) %{ + match(Set dst src); + + ins_cost(125); + format %{ "movl $dst, $src\t# compressed klass ptr" %} + ins_encode %{ + address con = (address)$src$$constant; + if (con == nullptr) { + ShouldNotReachHere(); + } else { + __ set_narrow_klass($dst$$Register, (Klass*)$src$$constant); + } + %} + ins_pipe(ialu_reg_fat); // XXX +%} + +instruct loadConF0(regF dst, immF0 src) +%{ + match(Set dst src); + ins_cost(100); + + format %{ "xorps $dst, $dst\t# float 0.0" %} + ins_encode %{ + __ xorps($dst$$XMMRegister, $dst$$XMMRegister); + %} + ins_pipe(pipe_slow); +%} + +// Use the same format since predicate() can not be used here. +instruct loadConD(regD dst, immD con) %{ + match(Set dst con); + ins_cost(125); + format %{ "movsd $dst, [$constantaddress]\t# load from constant table: double=$con" %} + ins_encode %{ + __ movdbl($dst$$XMMRegister, $constantaddress($con)); + %} + ins_pipe(pipe_slow); +%} + +instruct loadConD0(regD dst, immD0 src) +%{ + match(Set dst src); + ins_cost(100); + + format %{ "xorpd $dst, $dst\t# double 0.0" %} + ins_encode %{ + __ xorpd($dst$$XMMRegister, $dst$$XMMRegister); + %} + ins_pipe(pipe_slow); +%} + +instruct loadSSI(rRegI dst, stackSlotI src) +%{ + match(Set dst src); + + ins_cost(125); + format %{ "movl $dst, $src\t# int stk" %} + ins_encode %{ + __ movl($dst$$Register, $src$$Address); + %} + ins_pipe(ialu_reg_mem); +%} + +instruct loadSSL(rRegL dst, stackSlotL src) +%{ + match(Set dst src); + + ins_cost(125); + format %{ "movq $dst, $src\t# long stk" %} + ins_encode %{ + __ movq($dst$$Register, $src$$Address); + %} + ins_pipe(ialu_reg_mem); +%} + +instruct loadSSP(rRegP dst, stackSlotP src) +%{ + match(Set dst src); + + ins_cost(125); + format %{ "movq $dst, $src\t# ptr stk" %} + ins_encode %{ + __ movq($dst$$Register, $src$$Address); + %} + ins_pipe(ialu_reg_mem); +%} + +instruct loadSSF(regF dst, stackSlotF src) +%{ + match(Set dst src); + + ins_cost(125); + format %{ "movss $dst, $src\t# float stk" %} + ins_encode %{ + __ movflt($dst$$XMMRegister, Address(rsp, $src$$disp)); + %} + ins_pipe(pipe_slow); // XXX +%} + +// Use the same format since predicate() can not be used here. +instruct loadSSD(regD dst, stackSlotD src) +%{ + match(Set dst src); + + ins_cost(125); + format %{ "movsd $dst, $src\t# double stk" %} + ins_encode %{ + __ movdbl($dst$$XMMRegister, Address(rsp, $src$$disp)); + %} + ins_pipe(pipe_slow); // XXX +%} + +// Prefetch instructions for allocation. +// Must be safe to execute with invalid address (cannot fault). + +instruct prefetchAlloc( memory mem ) %{ + predicate(AllocatePrefetchInstr==3); + match(PrefetchAllocation mem); + ins_cost(125); + + format %{ "PREFETCHW $mem\t# Prefetch allocation into level 1 cache and mark modified" %} + ins_encode %{ + __ prefetchw($mem$$Address); + %} + ins_pipe(ialu_mem); +%} + +instruct prefetchAllocNTA( memory mem ) %{ + predicate(AllocatePrefetchInstr==0); + match(PrefetchAllocation mem); + ins_cost(125); + + format %{ "PREFETCHNTA $mem\t# Prefetch allocation to non-temporal cache for write" %} + ins_encode %{ + __ prefetchnta($mem$$Address); + %} + ins_pipe(ialu_mem); +%} + +instruct prefetchAllocT0( memory mem ) %{ + predicate(AllocatePrefetchInstr==1); + match(PrefetchAllocation mem); + ins_cost(125); + + format %{ "PREFETCHT0 $mem\t# Prefetch allocation to level 1 and 2 caches for write" %} + ins_encode %{ + __ prefetcht0($mem$$Address); + %} + ins_pipe(ialu_mem); +%} + +instruct prefetchAllocT2( memory mem ) %{ + predicate(AllocatePrefetchInstr==2); + match(PrefetchAllocation mem); + ins_cost(125); + + format %{ "PREFETCHT2 $mem\t# Prefetch allocation to level 2 cache for write" %} + ins_encode %{ + __ prefetcht2($mem$$Address); + %} + ins_pipe(ialu_mem); +%} + +//----------Store Instructions------------------------------------------------- + +// Store Byte +instruct storeB(memory mem, rRegI src) +%{ + match(Set mem (StoreB mem src)); + + ins_cost(125); // XXX + format %{ "movb $mem, $src\t# byte" %} + ins_encode %{ + __ movb($mem$$Address, $src$$Register); + %} + ins_pipe(ialu_mem_reg); +%} + +// Store Char/Short +instruct storeC(memory mem, rRegI src) +%{ + match(Set mem (StoreC mem src)); + + ins_cost(125); // XXX + format %{ "movw $mem, $src\t# char/short" %} + ins_encode %{ + __ movw($mem$$Address, $src$$Register); + %} + ins_pipe(ialu_mem_reg); +%} + +// Store Integer +instruct storeI(memory mem, rRegI src) +%{ + match(Set mem (StoreI mem src)); + + ins_cost(125); // XXX + format %{ "movl $mem, $src\t# int" %} + ins_encode %{ + __ movl($mem$$Address, $src$$Register); + %} + ins_pipe(ialu_mem_reg); +%} + +// Store Long +instruct storeL(memory mem, rRegL src) +%{ + match(Set mem (StoreL mem src)); + + ins_cost(125); // XXX + format %{ "movq $mem, $src\t# long" %} + ins_encode %{ + __ movq($mem$$Address, $src$$Register); + %} + ins_pipe(ialu_mem_reg); // XXX +%} + +// Store Pointer +instruct storeP(memory mem, any_RegP src) +%{ + predicate(n->as_Store()->barrier_data() == 0); + match(Set mem (StoreP mem src)); + + ins_cost(125); // XXX + format %{ "movq $mem, $src\t# ptr" %} + ins_encode %{ + __ movq($mem$$Address, $src$$Register); + %} + ins_pipe(ialu_mem_reg); +%} + +instruct storeImmP0(memory mem, immP0 zero) +%{ + predicate(UseCompressedOops && (CompressedOops::base() == nullptr) && n->as_Store()->barrier_data() == 0); + match(Set mem (StoreP mem zero)); + + ins_cost(125); // XXX + format %{ "movq $mem, R12\t# ptr (R12_heapbase==0)" %} + ins_encode %{ + __ movq($mem$$Address, r12); + %} + ins_pipe(ialu_mem_reg); +%} + +// Store Null Pointer, mark word, or other simple pointer constant. +instruct storeImmP(memory mem, immP31 src) +%{ + predicate(n->as_Store()->barrier_data() == 0); + match(Set mem (StoreP mem src)); + + ins_cost(150); // XXX + format %{ "movq $mem, $src\t# ptr" %} + ins_encode %{ + __ movq($mem$$Address, $src$$constant); + %} + ins_pipe(ialu_mem_imm); +%} + +// Store Compressed Pointer +instruct storeN(memory mem, rRegN src) +%{ + predicate(n->as_Store()->barrier_data() == 0); + match(Set mem (StoreN mem src)); + + ins_cost(125); // XXX + format %{ "movl $mem, $src\t# compressed ptr" %} + ins_encode %{ + __ movl($mem$$Address, $src$$Register); + %} + ins_pipe(ialu_mem_reg); +%} + +instruct storeNKlass(memory mem, rRegN src) +%{ + match(Set mem (StoreNKlass mem src)); + + ins_cost(125); // XXX + format %{ "movl $mem, $src\t# compressed klass ptr" %} + ins_encode %{ + __ movl($mem$$Address, $src$$Register); + %} + ins_pipe(ialu_mem_reg); +%} + +instruct storeImmN0(memory mem, immN0 zero) +%{ + predicate(CompressedOops::base() == nullptr && n->as_Store()->barrier_data() == 0); + match(Set mem (StoreN mem zero)); + + ins_cost(125); // XXX + format %{ "movl $mem, R12\t# compressed ptr (R12_heapbase==0)" %} + ins_encode %{ + __ movl($mem$$Address, r12); + %} + ins_pipe(ialu_mem_reg); +%} + +instruct storeImmN(memory mem, immN src) +%{ + predicate(n->as_Store()->barrier_data() == 0); + match(Set mem (StoreN mem src)); + + ins_cost(150); // XXX + format %{ "movl $mem, $src\t# compressed ptr" %} + ins_encode %{ + address con = (address)$src$$constant; + if (con == nullptr) { + __ movl($mem$$Address, 0); + } else { + __ set_narrow_oop($mem$$Address, (jobject)$src$$constant); + } + %} + ins_pipe(ialu_mem_imm); +%} + +instruct storeImmNKlass(memory mem, immNKlass src) +%{ + match(Set mem (StoreNKlass mem src)); + + ins_cost(150); // XXX + format %{ "movl $mem, $src\t# compressed klass ptr" %} + ins_encode %{ + __ set_narrow_klass($mem$$Address, (Klass*)$src$$constant); + %} + ins_pipe(ialu_mem_imm); +%} + +// Store Integer Immediate +instruct storeImmI0(memory mem, immI_0 zero) +%{ + predicate(UseCompressedOops && (CompressedOops::base() == nullptr)); + match(Set mem (StoreI mem zero)); + + ins_cost(125); // XXX + format %{ "movl $mem, R12\t# int (R12_heapbase==0)" %} + ins_encode %{ + __ movl($mem$$Address, r12); + %} + ins_pipe(ialu_mem_reg); +%} + +instruct storeImmI(memory mem, immI src) +%{ + match(Set mem (StoreI mem src)); + + ins_cost(150); + format %{ "movl $mem, $src\t# int" %} + ins_encode %{ + __ movl($mem$$Address, $src$$constant); + %} + ins_pipe(ialu_mem_imm); +%} + +// Store Long Immediate +instruct storeImmL0(memory mem, immL0 zero) +%{ + predicate(UseCompressedOops && (CompressedOops::base() == nullptr)); + match(Set mem (StoreL mem zero)); + + ins_cost(125); // XXX + format %{ "movq $mem, R12\t# long (R12_heapbase==0)" %} + ins_encode %{ + __ movq($mem$$Address, r12); + %} + ins_pipe(ialu_mem_reg); +%} + +instruct storeImmL(memory mem, immL32 src) +%{ + match(Set mem (StoreL mem src)); + + ins_cost(150); + format %{ "movq $mem, $src\t# long" %} + ins_encode %{ + __ movq($mem$$Address, $src$$constant); + %} + ins_pipe(ialu_mem_imm); +%} + +// Store Short/Char Immediate +instruct storeImmC0(memory mem, immI_0 zero) +%{ + predicate(UseCompressedOops && (CompressedOops::base() == nullptr)); + match(Set mem (StoreC mem zero)); + + ins_cost(125); // XXX + format %{ "movw $mem, R12\t# short/char (R12_heapbase==0)" %} + ins_encode %{ + __ movw($mem$$Address, r12); + %} + ins_pipe(ialu_mem_reg); +%} + +instruct storeImmI16(memory mem, immI16 src) +%{ + predicate(UseStoreImmI16); + match(Set mem (StoreC mem src)); + + ins_cost(150); + format %{ "movw $mem, $src\t# short/char" %} + ins_encode %{ + __ movw($mem$$Address, $src$$constant); + %} + ins_pipe(ialu_mem_imm); +%} + +// Store Byte Immediate +instruct storeImmB0(memory mem, immI_0 zero) +%{ + predicate(UseCompressedOops && (CompressedOops::base() == nullptr)); + match(Set mem (StoreB mem zero)); + + ins_cost(125); // XXX + format %{ "movb $mem, R12\t# short/char (R12_heapbase==0)" %} + ins_encode %{ + __ movb($mem$$Address, r12); + %} + ins_pipe(ialu_mem_reg); +%} + +instruct storeImmB(memory mem, immI8 src) +%{ + match(Set mem (StoreB mem src)); + + ins_cost(150); // XXX + format %{ "movb $mem, $src\t# byte" %} + ins_encode %{ + __ movb($mem$$Address, $src$$constant); + %} + ins_pipe(ialu_mem_imm); +%} + +// Store Float +instruct storeF(memory mem, regF src) +%{ + match(Set mem (StoreF mem src)); + + ins_cost(95); // XXX + format %{ "movss $mem, $src\t# float" %} + ins_encode %{ + __ movflt($mem$$Address, $src$$XMMRegister); + %} + ins_pipe(pipe_slow); // XXX +%} + +// Store immediate Float value (it is faster than store from XMM register) +instruct storeF0(memory mem, immF0 zero) +%{ + predicate(UseCompressedOops && (CompressedOops::base() == nullptr)); + match(Set mem (StoreF mem zero)); + + ins_cost(25); // XXX + format %{ "movl $mem, R12\t# float 0. (R12_heapbase==0)" %} + ins_encode %{ + __ movl($mem$$Address, r12); + %} + ins_pipe(ialu_mem_reg); +%} + +instruct storeF_imm(memory mem, immF src) +%{ + match(Set mem (StoreF mem src)); + + ins_cost(50); + format %{ "movl $mem, $src\t# float" %} + ins_encode %{ + __ movl($mem$$Address, jint_cast($src$$constant)); + %} + ins_pipe(ialu_mem_imm); +%} + +// Store Double +instruct storeD(memory mem, regD src) +%{ + match(Set mem (StoreD mem src)); + + ins_cost(95); // XXX + format %{ "movsd $mem, $src\t# double" %} + ins_encode %{ + __ movdbl($mem$$Address, $src$$XMMRegister); + %} + ins_pipe(pipe_slow); // XXX +%} + +// Store immediate double 0.0 (it is faster than store from XMM register) +instruct storeD0_imm(memory mem, immD0 src) +%{ + predicate(!UseCompressedOops || (CompressedOops::base() != nullptr)); + match(Set mem (StoreD mem src)); + + ins_cost(50); + format %{ "movq $mem, $src\t# double 0." %} + ins_encode %{ + __ movq($mem$$Address, $src$$constant); + %} + ins_pipe(ialu_mem_imm); +%} + +instruct storeD0(memory mem, immD0 zero) +%{ + predicate(UseCompressedOops && (CompressedOops::base() == nullptr)); + match(Set mem (StoreD mem zero)); + + ins_cost(25); // XXX + format %{ "movq $mem, R12\t# double 0. (R12_heapbase==0)" %} + ins_encode %{ + __ movq($mem$$Address, r12); + %} + ins_pipe(ialu_mem_reg); +%} + +instruct storeSSI(stackSlotI dst, rRegI src) +%{ + match(Set dst src); + + ins_cost(100); + format %{ "movl $dst, $src\t# int stk" %} + ins_encode %{ + __ movl($dst$$Address, $src$$Register); + %} + ins_pipe( ialu_mem_reg ); +%} + +instruct storeSSL(stackSlotL dst, rRegL src) +%{ + match(Set dst src); + + ins_cost(100); + format %{ "movq $dst, $src\t# long stk" %} + ins_encode %{ + __ movq($dst$$Address, $src$$Register); + %} + ins_pipe(ialu_mem_reg); +%} + +instruct storeSSP(stackSlotP dst, rRegP src) +%{ + match(Set dst src); + + ins_cost(100); + format %{ "movq $dst, $src\t# ptr stk" %} + ins_encode %{ + __ movq($dst$$Address, $src$$Register); + %} + ins_pipe(ialu_mem_reg); +%} + +instruct storeSSF(stackSlotF dst, regF src) +%{ + match(Set dst src); + + ins_cost(95); // XXX + format %{ "movss $dst, $src\t# float stk" %} + ins_encode %{ + __ movflt(Address(rsp, $dst$$disp), $src$$XMMRegister); + %} + ins_pipe(pipe_slow); // XXX +%} + +instruct storeSSD(stackSlotD dst, regD src) +%{ + match(Set dst src); + + ins_cost(95); // XXX + format %{ "movsd $dst, $src\t# double stk" %} + ins_encode %{ + __ movdbl(Address(rsp, $dst$$disp), $src$$XMMRegister); + %} + ins_pipe(pipe_slow); // XXX +%} + +instruct cacheWB(indirect addr) +%{ + predicate(VM_Version::supports_data_cache_line_flush()); + match(CacheWB addr); + + ins_cost(100); + format %{"cache wb $addr" %} + ins_encode %{ + assert($addr->index_position() < 0, "should be"); + assert($addr$$disp == 0, "should be"); + __ cache_wb(Address($addr$$base$$Register, 0)); + %} + ins_pipe(pipe_slow); // XXX +%} + +instruct cacheWBPreSync() +%{ + predicate(VM_Version::supports_data_cache_line_flush()); + match(CacheWBPreSync); + + ins_cost(100); + format %{"cache wb presync" %} + ins_encode %{ + __ cache_wbsync(true); + %} + ins_pipe(pipe_slow); // XXX +%} + +instruct cacheWBPostSync() +%{ + predicate(VM_Version::supports_data_cache_line_flush()); + match(CacheWBPostSync); + + ins_cost(100); + format %{"cache wb postsync" %} + ins_encode %{ + __ cache_wbsync(false); + %} + ins_pipe(pipe_slow); // XXX +%} + +//----------BSWAP Instructions------------------------------------------------- +instruct bytes_reverse_int(rRegI dst) %{ + match(Set dst (ReverseBytesI dst)); + + format %{ "bswapl $dst" %} + ins_encode %{ + __ bswapl($dst$$Register); + %} + ins_pipe( ialu_reg ); +%} + +instruct bytes_reverse_long(rRegL dst) %{ + match(Set dst (ReverseBytesL dst)); + + format %{ "bswapq $dst" %} + ins_encode %{ + __ bswapq($dst$$Register); + %} + ins_pipe( ialu_reg); +%} + +instruct bytes_reverse_unsigned_short(rRegI dst, rFlagsReg cr) %{ + match(Set dst (ReverseBytesUS dst)); + effect(KILL cr); + + format %{ "bswapl $dst\n\t" + "shrl $dst,16\n\t" %} + ins_encode %{ + __ bswapl($dst$$Register); + __ shrl($dst$$Register, 16); + %} + ins_pipe( ialu_reg ); +%} + +instruct bytes_reverse_short(rRegI dst, rFlagsReg cr) %{ + match(Set dst (ReverseBytesS dst)); + effect(KILL cr); + + format %{ "bswapl $dst\n\t" + "sar $dst,16\n\t" %} + ins_encode %{ + __ bswapl($dst$$Register); + __ sarl($dst$$Register, 16); + %} + ins_pipe( ialu_reg ); +%} + +//---------- Zeros Count Instructions ------------------------------------------ + +instruct countLeadingZerosI(rRegI dst, rRegI src, rFlagsReg cr) %{ + predicate(UseCountLeadingZerosInstruction); + match(Set dst (CountLeadingZerosI src)); + effect(KILL cr); + + format %{ "lzcntl $dst, $src\t# count leading zeros (int)" %} + ins_encode %{ + __ lzcntl($dst$$Register, $src$$Register); + %} + ins_pipe(ialu_reg); +%} + +instruct countLeadingZerosI_mem(rRegI dst, memory src, rFlagsReg cr) %{ + predicate(UseCountLeadingZerosInstruction); + match(Set dst (CountLeadingZerosI (LoadI src))); + effect(KILL cr); + ins_cost(175); + format %{ "lzcntl $dst, $src\t# count leading zeros (int)" %} + ins_encode %{ + __ lzcntl($dst$$Register, $src$$Address); + %} + ins_pipe(ialu_reg_mem); +%} + +instruct countLeadingZerosI_bsr(rRegI dst, rRegI src, rFlagsReg cr) %{ + predicate(!UseCountLeadingZerosInstruction); + match(Set dst (CountLeadingZerosI src)); + effect(KILL cr); + + format %{ "bsrl $dst, $src\t# count leading zeros (int)\n\t" + "jnz skip\n\t" + "movl $dst, -1\n" + "skip:\n\t" + "negl $dst\n\t" + "addl $dst, 31" %} + ins_encode %{ + Register Rdst = $dst$$Register; + Register Rsrc = $src$$Register; + Label skip; + __ bsrl(Rdst, Rsrc); + __ jccb(Assembler::notZero, skip); + __ movl(Rdst, -1); + __ bind(skip); + __ negl(Rdst); + __ addl(Rdst, BitsPerInt - 1); + %} + ins_pipe(ialu_reg); +%} + +instruct countLeadingZerosL(rRegI dst, rRegL src, rFlagsReg cr) %{ + predicate(UseCountLeadingZerosInstruction); + match(Set dst (CountLeadingZerosL src)); + effect(KILL cr); + + format %{ "lzcntq $dst, $src\t# count leading zeros (long)" %} + ins_encode %{ + __ lzcntq($dst$$Register, $src$$Register); + %} + ins_pipe(ialu_reg); +%} + +instruct countLeadingZerosL_mem(rRegI dst, memory src, rFlagsReg cr) %{ + predicate(UseCountLeadingZerosInstruction); + match(Set dst (CountLeadingZerosL (LoadL src))); + effect(KILL cr); + ins_cost(175); + format %{ "lzcntq $dst, $src\t# count leading zeros (long)" %} + ins_encode %{ + __ lzcntq($dst$$Register, $src$$Address); + %} + ins_pipe(ialu_reg_mem); +%} + +instruct countLeadingZerosL_bsr(rRegI dst, rRegL src, rFlagsReg cr) %{ + predicate(!UseCountLeadingZerosInstruction); + match(Set dst (CountLeadingZerosL src)); + effect(KILL cr); + + format %{ "bsrq $dst, $src\t# count leading zeros (long)\n\t" + "jnz skip\n\t" + "movl $dst, -1\n" + "skip:\n\t" + "negl $dst\n\t" + "addl $dst, 63" %} + ins_encode %{ + Register Rdst = $dst$$Register; + Register Rsrc = $src$$Register; + Label skip; + __ bsrq(Rdst, Rsrc); + __ jccb(Assembler::notZero, skip); + __ movl(Rdst, -1); + __ bind(skip); + __ negl(Rdst); + __ addl(Rdst, BitsPerLong - 1); + %} + ins_pipe(ialu_reg); +%} + +instruct countTrailingZerosI(rRegI dst, rRegI src, rFlagsReg cr) %{ + predicate(UseCountTrailingZerosInstruction); + match(Set dst (CountTrailingZerosI src)); + effect(KILL cr); + + format %{ "tzcntl $dst, $src\t# count trailing zeros (int)" %} + ins_encode %{ + __ tzcntl($dst$$Register, $src$$Register); + %} + ins_pipe(ialu_reg); +%} + +instruct countTrailingZerosI_mem(rRegI dst, memory src, rFlagsReg cr) %{ + predicate(UseCountTrailingZerosInstruction); + match(Set dst (CountTrailingZerosI (LoadI src))); + effect(KILL cr); + ins_cost(175); + format %{ "tzcntl $dst, $src\t# count trailing zeros (int)" %} + ins_encode %{ + __ tzcntl($dst$$Register, $src$$Address); + %} + ins_pipe(ialu_reg_mem); +%} + +instruct countTrailingZerosI_bsf(rRegI dst, rRegI src, rFlagsReg cr) %{ + predicate(!UseCountTrailingZerosInstruction); + match(Set dst (CountTrailingZerosI src)); + effect(KILL cr); + + format %{ "bsfl $dst, $src\t# count trailing zeros (int)\n\t" + "jnz done\n\t" + "movl $dst, 32\n" + "done:" %} + ins_encode %{ + Register Rdst = $dst$$Register; + Label done; + __ bsfl(Rdst, $src$$Register); + __ jccb(Assembler::notZero, done); + __ movl(Rdst, BitsPerInt); + __ bind(done); + %} + ins_pipe(ialu_reg); +%} + +instruct countTrailingZerosL(rRegI dst, rRegL src, rFlagsReg cr) %{ + predicate(UseCountTrailingZerosInstruction); + match(Set dst (CountTrailingZerosL src)); + effect(KILL cr); + + format %{ "tzcntq $dst, $src\t# count trailing zeros (long)" %} + ins_encode %{ + __ tzcntq($dst$$Register, $src$$Register); + %} + ins_pipe(ialu_reg); +%} + +instruct countTrailingZerosL_mem(rRegI dst, memory src, rFlagsReg cr) %{ + predicate(UseCountTrailingZerosInstruction); + match(Set dst (CountTrailingZerosL (LoadL src))); + effect(KILL cr); + ins_cost(175); + format %{ "tzcntq $dst, $src\t# count trailing zeros (long)" %} + ins_encode %{ + __ tzcntq($dst$$Register, $src$$Address); + %} + ins_pipe(ialu_reg_mem); +%} + +instruct countTrailingZerosL_bsf(rRegI dst, rRegL src, rFlagsReg cr) %{ + predicate(!UseCountTrailingZerosInstruction); + match(Set dst (CountTrailingZerosL src)); + effect(KILL cr); + + format %{ "bsfq $dst, $src\t# count trailing zeros (long)\n\t" + "jnz done\n\t" + "movl $dst, 64\n" + "done:" %} + ins_encode %{ + Register Rdst = $dst$$Register; + Label done; + __ bsfq(Rdst, $src$$Register); + __ jccb(Assembler::notZero, done); + __ movl(Rdst, BitsPerLong); + __ bind(done); + %} + ins_pipe(ialu_reg); +%} + +//--------------- Reverse Operation Instructions ---------------- +instruct bytes_reversebit_int(rRegI dst, rRegI src, rRegI rtmp, rFlagsReg cr) %{ + predicate(!VM_Version::supports_gfni()); + match(Set dst (ReverseI src)); + effect(TEMP dst, TEMP rtmp, KILL cr); + format %{ "reverse_int $dst $src\t! using $rtmp as TEMP" %} + ins_encode %{ + __ reverseI($dst$$Register, $src$$Register, xnoreg, xnoreg, $rtmp$$Register); + %} + ins_pipe( ialu_reg ); +%} + +instruct bytes_reversebit_int_gfni(rRegI dst, rRegI src, vlRegF xtmp1, vlRegF xtmp2, rRegL rtmp, rFlagsReg cr) %{ + predicate(VM_Version::supports_gfni()); + match(Set dst (ReverseI src)); + effect(TEMP dst, TEMP xtmp1, TEMP xtmp2, TEMP rtmp, KILL cr); + format %{ "reverse_int $dst $src\t! using $rtmp, $xtmp1 and $xtmp2 as TEMP" %} + ins_encode %{ + __ reverseI($dst$$Register, $src$$Register, $xtmp1$$XMMRegister, $xtmp2$$XMMRegister, $rtmp$$Register); + %} + ins_pipe( ialu_reg ); +%} + +instruct bytes_reversebit_long(rRegL dst, rRegL src, rRegL rtmp1, rRegL rtmp2, rFlagsReg cr) %{ + predicate(!VM_Version::supports_gfni()); + match(Set dst (ReverseL src)); + effect(TEMP dst, TEMP rtmp1, TEMP rtmp2, KILL cr); + format %{ "reverse_long $dst $src\t! using $rtmp1 and $rtmp2 as TEMP" %} + ins_encode %{ + __ reverseL($dst$$Register, $src$$Register, xnoreg, xnoreg, $rtmp1$$Register, $rtmp2$$Register); + %} + ins_pipe( ialu_reg ); +%} + +instruct bytes_reversebit_long_gfni(rRegL dst, rRegL src, vlRegD xtmp1, vlRegD xtmp2, rRegL rtmp, rFlagsReg cr) %{ + predicate(VM_Version::supports_gfni()); + match(Set dst (ReverseL src)); + effect(TEMP dst, TEMP xtmp1, TEMP xtmp2, TEMP rtmp, KILL cr); + format %{ "reverse_long $dst $src\t! using $rtmp, $xtmp1 and $xtmp2 as TEMP" %} + ins_encode %{ + __ reverseL($dst$$Register, $src$$Register, $xtmp1$$XMMRegister, $xtmp2$$XMMRegister, $rtmp$$Register, noreg); + %} + ins_pipe( ialu_reg ); +%} + +//---------- Population Count Instructions ------------------------------------- + +instruct popCountI(rRegI dst, rRegI src, rFlagsReg cr) %{ + predicate(UsePopCountInstruction); + match(Set dst (PopCountI src)); + effect(KILL cr); + + format %{ "popcnt $dst, $src" %} + ins_encode %{ + __ popcntl($dst$$Register, $src$$Register); + %} + ins_pipe(ialu_reg); +%} + +instruct popCountI_mem(rRegI dst, memory mem, rFlagsReg cr) %{ + predicate(UsePopCountInstruction); + match(Set dst (PopCountI (LoadI mem))); + effect(KILL cr); + + format %{ "popcnt $dst, $mem" %} + ins_encode %{ + __ popcntl($dst$$Register, $mem$$Address); + %} + ins_pipe(ialu_reg); +%} + +// Note: Long.bitCount(long) returns an int. +instruct popCountL(rRegI dst, rRegL src, rFlagsReg cr) %{ + predicate(UsePopCountInstruction); + match(Set dst (PopCountL src)); + effect(KILL cr); + + format %{ "popcnt $dst, $src" %} + ins_encode %{ + __ popcntq($dst$$Register, $src$$Register); + %} + ins_pipe(ialu_reg); +%} + +// Note: Long.bitCount(long) returns an int. +instruct popCountL_mem(rRegI dst, memory mem, rFlagsReg cr) %{ + predicate(UsePopCountInstruction); + match(Set dst (PopCountL (LoadL mem))); + effect(KILL cr); + + format %{ "popcnt $dst, $mem" %} + ins_encode %{ + __ popcntq($dst$$Register, $mem$$Address); + %} + ins_pipe(ialu_reg); +%} + + +//----------MemBar Instructions----------------------------------------------- +// Memory barrier flavors + +instruct membar_acquire() +%{ + match(MemBarAcquire); + match(LoadFence); + ins_cost(0); + + size(0); + format %{ "MEMBAR-acquire ! (empty encoding)" %} + ins_encode(); + ins_pipe(empty); +%} + +instruct membar_acquire_lock() +%{ + match(MemBarAcquireLock); + ins_cost(0); + + size(0); + format %{ "MEMBAR-acquire (prior CMPXCHG in FastLock so empty encoding)" %} + ins_encode(); + ins_pipe(empty); +%} + +instruct membar_release() +%{ + match(MemBarRelease); + match(StoreFence); + ins_cost(0); + + size(0); + format %{ "MEMBAR-release ! (empty encoding)" %} + ins_encode(); + ins_pipe(empty); +%} + +instruct membar_release_lock() +%{ + match(MemBarReleaseLock); + ins_cost(0); + + size(0); + format %{ "MEMBAR-release (a FastUnlock follows so empty encoding)" %} + ins_encode(); + ins_pipe(empty); +%} + +instruct membar_volatile(rFlagsReg cr) %{ + match(MemBarVolatile); + effect(KILL cr); + ins_cost(400); + + format %{ + $$template + $$emit$$"lock addl [rsp + #0], 0\t! membar_volatile" + %} + ins_encode %{ + __ membar(Assembler::StoreLoad); + %} + ins_pipe(pipe_slow); +%} + +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); +%} + +instruct membar_storestore() %{ + match(MemBarStoreStore); + match(StoreStoreFence); + ins_cost(0); + + size(0); + format %{ "MEMBAR-storestore (empty encoding)" %} + ins_encode( ); + ins_pipe(empty); +%} + +//----------Move Instructions-------------------------------------------------- + +instruct castX2P(rRegP dst, rRegL src) +%{ + match(Set dst (CastX2P src)); + + format %{ "movq $dst, $src\t# long->ptr" %} + ins_encode %{ + if ($dst$$reg != $src$$reg) { + __ movptr($dst$$Register, $src$$Register); + } + %} + ins_pipe(ialu_reg_reg); // XXX +%} + +instruct castP2X(rRegL dst, rRegP src) +%{ + match(Set dst (CastP2X src)); + + format %{ "movq $dst, $src\t# ptr -> long" %} + ins_encode %{ + if ($dst$$reg != $src$$reg) { + __ movptr($dst$$Register, $src$$Register); + } + %} + ins_pipe(ialu_reg_reg); // XXX +%} + +// Convert oop into int for vectors alignment masking +instruct convP2I(rRegI dst, rRegP src) +%{ + match(Set dst (ConvL2I (CastP2X src))); + + format %{ "movl $dst, $src\t# ptr -> int" %} + ins_encode %{ + __ movl($dst$$Register, $src$$Register); + %} + ins_pipe(ialu_reg_reg); // XXX +%} + +// Convert compressed oop into int for vectors alignment masking +// in case of 32bit oops (heap < 4Gb). +instruct convN2I(rRegI dst, rRegN src) +%{ + predicate(CompressedOops::shift() == 0); + match(Set dst (ConvL2I (CastP2X (DecodeN src)))); + + format %{ "movl $dst, $src\t# compressed ptr -> int" %} + ins_encode %{ + __ movl($dst$$Register, $src$$Register); + %} + ins_pipe(ialu_reg_reg); // XXX +%} + +// Convert oop pointer into compressed form +instruct encodeHeapOop(rRegN dst, rRegP src, rFlagsReg cr) %{ + predicate(n->bottom_type()->make_ptr()->ptr() != TypePtr::NotNull); + match(Set dst (EncodeP src)); + effect(KILL cr); + format %{ "encode_heap_oop $dst,$src" %} + ins_encode %{ + Register s = $src$$Register; + Register d = $dst$$Register; + if (s != d) { + __ movq(d, s); + } + __ encode_heap_oop(d); + %} + ins_pipe(ialu_reg_long); +%} + +instruct encodeHeapOop_not_null(rRegN dst, rRegP src, rFlagsReg cr) %{ + predicate(n->bottom_type()->make_ptr()->ptr() == TypePtr::NotNull); + match(Set dst (EncodeP src)); + effect(KILL cr); + format %{ "encode_heap_oop_not_null $dst,$src" %} + ins_encode %{ + __ encode_heap_oop_not_null($dst$$Register, $src$$Register); + %} + ins_pipe(ialu_reg_long); +%} + +instruct decodeHeapOop(rRegP dst, rRegN src, rFlagsReg cr) %{ + predicate(n->bottom_type()->is_ptr()->ptr() != TypePtr::NotNull && + n->bottom_type()->is_ptr()->ptr() != TypePtr::Constant); + match(Set dst (DecodeN src)); + effect(KILL cr); + format %{ "decode_heap_oop $dst,$src" %} + ins_encode %{ + Register s = $src$$Register; + Register d = $dst$$Register; + if (s != d) { + __ movq(d, s); + } + __ decode_heap_oop(d); + %} + ins_pipe(ialu_reg_long); +%} + +instruct decodeHeapOop_not_null(rRegP dst, rRegN src, rFlagsReg cr) %{ + predicate(n->bottom_type()->is_ptr()->ptr() == TypePtr::NotNull || + n->bottom_type()->is_ptr()->ptr() == TypePtr::Constant); + match(Set dst (DecodeN src)); + effect(KILL cr); + format %{ "decode_heap_oop_not_null $dst,$src" %} + ins_encode %{ + Register s = $src$$Register; + Register d = $dst$$Register; + if (s != d) { + __ decode_heap_oop_not_null(d, s); + } else { + __ decode_heap_oop_not_null(d); + } + %} + ins_pipe(ialu_reg_long); +%} + +instruct encodeKlass_not_null(rRegN dst, rRegP src, rFlagsReg cr) %{ + match(Set dst (EncodePKlass src)); + effect(TEMP dst, KILL cr); + format %{ "encode_and_move_klass_not_null $dst,$src" %} + ins_encode %{ + __ encode_and_move_klass_not_null($dst$$Register, $src$$Register); + %} + ins_pipe(ialu_reg_long); +%} + +instruct decodeKlass_not_null(rRegP dst, rRegN src, rFlagsReg cr) %{ + match(Set dst (DecodeNKlass src)); + effect(TEMP dst, KILL cr); + format %{ "decode_and_move_klass_not_null $dst,$src" %} + ins_encode %{ + __ decode_and_move_klass_not_null($dst$$Register, $src$$Register); + %} + ins_pipe(ialu_reg_long); +%} + +//----------Conditional Move--------------------------------------------------- +// Jump +// dummy instruction for generating temp registers +instruct jumpXtnd_offset(rRegL switch_val, immI2 shift, rRegI dest) %{ + match(Jump (LShiftL switch_val shift)); + ins_cost(350); + predicate(false); + effect(TEMP dest); + + format %{ "leaq $dest, [$constantaddress]\n\t" + "jmp [$dest + $switch_val << $shift]\n\t" %} + ins_encode %{ + // We could use jump(ArrayAddress) except that the macro assembler needs to use r10 + // to do that and the compiler is using that register as one it can allocate. + // So we build it all by hand. + // Address index(noreg, switch_reg, (Address::ScaleFactor)$shift$$constant); + // ArrayAddress dispatch(table, index); + Address dispatch($dest$$Register, $switch_val$$Register, (Address::ScaleFactor) $shift$$constant); + __ lea($dest$$Register, $constantaddress); + __ jmp(dispatch); + %} + ins_pipe(pipe_jmp); +%} + +instruct jumpXtnd_addr(rRegL switch_val, immI2 shift, immL32 offset, rRegI dest) %{ + match(Jump (AddL (LShiftL switch_val shift) offset)); + ins_cost(350); + effect(TEMP dest); + + format %{ "leaq $dest, [$constantaddress]\n\t" + "jmp [$dest + $switch_val << $shift + $offset]\n\t" %} + ins_encode %{ + // We could use jump(ArrayAddress) except that the macro assembler needs to use r10 + // to do that and the compiler is using that register as one it can allocate. + // So we build it all by hand. + // Address index(noreg, switch_reg, (Address::ScaleFactor) $shift$$constant, (int) $offset$$constant); + // ArrayAddress dispatch(table, index); + Address dispatch($dest$$Register, $switch_val$$Register, (Address::ScaleFactor) $shift$$constant, (int) $offset$$constant); + __ lea($dest$$Register, $constantaddress); + __ jmp(dispatch); + %} + ins_pipe(pipe_jmp); +%} + +instruct jumpXtnd(rRegL switch_val, rRegI dest) %{ + match(Jump switch_val); + ins_cost(350); + effect(TEMP dest); + + format %{ "leaq $dest, [$constantaddress]\n\t" + "jmp [$dest + $switch_val]\n\t" %} + ins_encode %{ + // We could use jump(ArrayAddress) except that the macro assembler needs to use r10 + // to do that and the compiler is using that register as one it can allocate. + // So we build it all by hand. + // Address index(noreg, switch_reg, Address::times_1); + // ArrayAddress dispatch(table, index); + Address dispatch($dest$$Register, $switch_val$$Register, Address::times_1); + __ lea($dest$$Register, $constantaddress); + __ jmp(dispatch); + %} + ins_pipe(pipe_jmp); +%} + +// Conditional move +instruct cmovI_imm_01(rRegI dst, immI_1 src, rFlagsReg cr, cmpOp cop) +%{ + predicate(n->in(2)->in(2)->is_Con() && n->in(2)->in(2)->get_int() == 0); + match(Set dst (CMoveI (Binary cop cr) (Binary src dst))); + + ins_cost(100); // XXX + format %{ "setbn$cop $dst\t# signed, int" %} + ins_encode %{ + Assembler::Condition cond = (Assembler::Condition)($cop$$cmpcode); + __ setb(MacroAssembler::negate_condition(cond), $dst$$Register); + %} + ins_pipe(ialu_reg); +%} + +instruct cmovI_reg(rRegI dst, rRegI src, rFlagsReg cr, cmpOp cop) +%{ + predicate(!UseAPX); + match(Set dst (CMoveI (Binary cop cr) (Binary dst src))); + + ins_cost(200); // XXX + format %{ "cmovl$cop $dst, $src\t# signed, int" %} + ins_encode %{ + __ cmovl((Assembler::Condition)($cop$$cmpcode), $dst$$Register, $src$$Register); + %} + ins_pipe(pipe_cmov_reg); +%} + +instruct cmovI_reg_ndd(rRegI dst, rRegI src1, rRegI src2, rFlagsReg cr, cmpOp cop) +%{ + predicate(UseAPX); + match(Set dst (CMoveI (Binary cop cr) (Binary src1 src2))); + + ins_cost(200); + format %{ "ecmovl$cop $dst, $src1, $src2\t# signed, int ndd" %} + ins_encode %{ + __ ecmovl((Assembler::Condition)($cop$$cmpcode), $dst$$Register, $src1$$Register, $src2$$Register); + %} + ins_pipe(pipe_cmov_reg); +%} + +instruct cmovI_imm_01U(rRegI dst, immI_1 src, rFlagsRegU cr, cmpOpU cop) +%{ + predicate(n->in(2)->in(2)->is_Con() && n->in(2)->in(2)->get_int() == 0); + match(Set dst (CMoveI (Binary cop cr) (Binary src dst))); + + ins_cost(100); // XXX + format %{ "setbn$cop $dst\t# unsigned, int" %} + ins_encode %{ + Assembler::Condition cond = (Assembler::Condition)($cop$$cmpcode); + __ setb(MacroAssembler::negate_condition(cond), $dst$$Register); + %} + ins_pipe(ialu_reg); +%} + +instruct cmovI_regU(cmpOpU cop, rFlagsRegU cr, rRegI dst, rRegI src) %{ + predicate(!UseAPX); + match(Set dst (CMoveI (Binary cop cr) (Binary dst src))); + + ins_cost(200); // XXX + format %{ "cmovl$cop $dst, $src\t# unsigned, int" %} + ins_encode %{ + __ cmovl((Assembler::Condition)($cop$$cmpcode), $dst$$Register, $src$$Register); + %} + ins_pipe(pipe_cmov_reg); +%} + +instruct cmovI_regU_ndd(rRegI dst, cmpOpU cop, rFlagsRegU cr, rRegI src1, rRegI src2) %{ + predicate(UseAPX); + match(Set dst (CMoveI (Binary cop cr) (Binary src1 src2))); + + ins_cost(200); + format %{ "ecmovl$cop $dst, $src1, $src2\t# unsigned, int ndd" %} + ins_encode %{ + __ ecmovl((Assembler::Condition)($cop$$cmpcode), $dst$$Register, $src1$$Register, $src2$$Register); + %} + ins_pipe(pipe_cmov_reg); +%} + +instruct cmovI_imm_01UCF(rRegI dst, immI_1 src, rFlagsRegUCF cr, cmpOpUCF cop) +%{ + predicate(n->in(2)->in(2)->is_Con() && n->in(2)->in(2)->get_int() == 0); + match(Set dst (CMoveI (Binary cop cr) (Binary src dst))); + + ins_cost(100); // XXX + format %{ "setbn$cop $dst\t# unsigned, int" %} + ins_encode %{ + Assembler::Condition cond = (Assembler::Condition)($cop$$cmpcode); + __ setb(MacroAssembler::negate_condition(cond), $dst$$Register); + %} + ins_pipe(ialu_reg); +%} + +instruct cmovI_regUCF(cmpOpUCF cop, rFlagsRegUCF cr, rRegI dst, rRegI src) %{ + predicate(!UseAPX); + match(Set dst (CMoveI (Binary cop cr) (Binary dst src))); + ins_cost(200); + expand %{ + cmovI_regU(cop, cr, dst, src); + %} +%} + +instruct cmovI_regUCF_ndd(rRegI dst, cmpOpUCF cop, rFlagsRegUCF cr, rRegI src1, rRegI src2) %{ + predicate(UseAPX); + match(Set dst (CMoveI (Binary cop cr) (Binary src1 src2))); + ins_cost(200); + format %{ "ecmovl$cop $dst, $src1, $src2\t# unsigned, int ndd" %} + ins_encode %{ + __ ecmovl((Assembler::Condition)($cop$$cmpcode), $dst$$Register, $src1$$Register, $src2$$Register); + %} + ins_pipe(pipe_cmov_reg); +%} + +instruct cmovI_regUCF2_ne(cmpOpUCF2 cop, rFlagsRegUCF cr, rRegI dst, rRegI src) %{ + predicate(!UseAPX && n->in(1)->in(1)->as_Bool()->_test._test == BoolTest::ne); + match(Set dst (CMoveI (Binary cop cr) (Binary dst src))); + + ins_cost(200); // XXX + format %{ "cmovpl $dst, $src\n\t" + "cmovnel $dst, $src" %} + ins_encode %{ + __ cmovl(Assembler::parity, $dst$$Register, $src$$Register); + __ cmovl(Assembler::notEqual, $dst$$Register, $src$$Register); + %} + ins_pipe(pipe_cmov_reg); +%} + +instruct cmovI_regUCF2_ne_ndd(cmpOpUCF2 cop, rFlagsRegUCF cr, rRegI dst, rRegI src1, rRegI src2) %{ + predicate(UseAPX && n->in(1)->in(1)->as_Bool()->_test._test == BoolTest::ne); + match(Set dst (CMoveI (Binary cop cr) (Binary src1 src2))); + effect(TEMP dst); + + ins_cost(200); + format %{ "ecmovpl $dst, $src1, $src2\n\t" + "cmovnel $dst, $src2" %} + ins_encode %{ + __ ecmovl(Assembler::parity, $dst$$Register, $src1$$Register, $src2$$Register); + __ cmovl(Assembler::notEqual, $dst$$Register, $src2$$Register); + %} + ins_pipe(pipe_cmov_reg); +%} + +// Since (x == y) == !(x != y), we can flip the sense of the test by flipping the +// inputs of the CMove +instruct cmovI_regUCF2_eq(cmpOpUCF2 cop, rFlagsRegUCF cr, rRegI dst, rRegI src) %{ + predicate(!UseAPX && n->in(1)->in(1)->as_Bool()->_test._test == BoolTest::eq); + match(Set dst (CMoveI (Binary cop cr) (Binary src dst))); + effect(TEMP dst); + + ins_cost(200); // XXX + format %{ "cmovpl $dst, $src\n\t" + "cmovnel $dst, $src" %} + ins_encode %{ + __ cmovl(Assembler::parity, $dst$$Register, $src$$Register); + __ cmovl(Assembler::notEqual, $dst$$Register, $src$$Register); + %} + ins_pipe(pipe_cmov_reg); +%} + +// We need this special handling for only eq / neq comparison since NaN == NaN is false, +// and parity flag bit is set if any of the operand is a NaN. +instruct cmovI_regUCF2_eq_ndd(cmpOpUCF2 cop, rFlagsRegUCF cr, rRegI dst, rRegI src1, rRegI src2) %{ + predicate(UseAPX && n->in(1)->in(1)->as_Bool()->_test._test == BoolTest::eq); + match(Set dst (CMoveI (Binary cop cr) (Binary src2 src1))); + effect(TEMP dst); + + ins_cost(200); + format %{ "ecmovpl $dst, $src1, $src2\n\t" + "cmovnel $dst, $src2" %} + ins_encode %{ + __ ecmovl(Assembler::parity, $dst$$Register, $src1$$Register, $src2$$Register); + __ cmovl(Assembler::notEqual, $dst$$Register, $src2$$Register); + %} + ins_pipe(pipe_cmov_reg); +%} + +// Conditional move +instruct cmovI_mem(cmpOp cop, rFlagsReg cr, rRegI dst, memory src) %{ + predicate(!UseAPX); + match(Set dst (CMoveI (Binary cop cr) (Binary dst (LoadI src)))); + + ins_cost(250); // XXX + format %{ "cmovl$cop $dst, $src\t# signed, int" %} + ins_encode %{ + __ cmovl((Assembler::Condition)($cop$$cmpcode), $dst$$Register, $src$$Address); + %} + ins_pipe(pipe_cmov_mem); +%} + +// Conditional move +instruct cmovI_rReg_rReg_mem_ndd(rRegI dst, cmpOp cop, rFlagsReg cr, rRegI src1, memory src2) +%{ + predicate(UseAPX); + match(Set dst (CMoveI (Binary cop cr) (Binary src1 (LoadI src2)))); + + ins_cost(250); + format %{ "ecmovl$cop $dst, $src1, $src2\t# signed, int ndd" %} + ins_encode %{ + __ ecmovl((Assembler::Condition)($cop$$cmpcode), $dst$$Register, $src1$$Register, $src2$$Address); + %} + ins_pipe(pipe_cmov_mem); +%} + +// Conditional move +instruct cmovI_memU(cmpOpU cop, rFlagsRegU cr, rRegI dst, memory src) +%{ + predicate(!UseAPX); + match(Set dst (CMoveI (Binary cop cr) (Binary dst (LoadI src)))); + + ins_cost(250); // XXX + format %{ "cmovl$cop $dst, $src\t# unsigned, int" %} + ins_encode %{ + __ cmovl((Assembler::Condition)($cop$$cmpcode), $dst$$Register, $src$$Address); + %} + ins_pipe(pipe_cmov_mem); +%} + +instruct cmovI_memUCF(cmpOpUCF cop, rFlagsRegUCF cr, rRegI dst, memory src) %{ + predicate(!UseAPX); + match(Set dst (CMoveI (Binary cop cr) (Binary dst (LoadI src)))); + ins_cost(250); + expand %{ + cmovI_memU(cop, cr, dst, src); + %} +%} + +instruct cmovI_rReg_rReg_memU_ndd(rRegI dst, cmpOpU cop, rFlagsRegU cr, rRegI src1, memory src2) +%{ + predicate(UseAPX); + match(Set dst (CMoveI (Binary cop cr) (Binary src1 (LoadI src2)))); + + ins_cost(250); + format %{ "ecmovl$cop $dst, $src1, $src2\t# unsigned, int ndd" %} + ins_encode %{ + __ ecmovl((Assembler::Condition)($cop$$cmpcode), $dst$$Register, $src1$$Register, $src2$$Address); + %} + ins_pipe(pipe_cmov_mem); +%} + +instruct cmovI_rReg_rReg_memUCF_ndd(rRegI dst, cmpOpUCF cop, rFlagsRegUCF cr, rRegI src1, memory src2) +%{ + predicate(UseAPX); + match(Set dst (CMoveI (Binary cop cr) (Binary src1 (LoadI src2)))); + ins_cost(250); + format %{ "ecmovl$cop $dst, $src1, $src2\t# unsigned, int ndd" %} + ins_encode %{ + __ ecmovl((Assembler::Condition)($cop$$cmpcode), $dst$$Register, $src1$$Register, $src2$$Address); + %} + ins_pipe(pipe_cmov_mem); +%} + +// Conditional move +instruct cmovN_reg(rRegN dst, rRegN src, rFlagsReg cr, cmpOp cop) +%{ + predicate(!UseAPX); + match(Set dst (CMoveN (Binary cop cr) (Binary dst src))); + + ins_cost(200); // XXX + format %{ "cmovl$cop $dst, $src\t# signed, compressed ptr" %} + ins_encode %{ + __ cmovl((Assembler::Condition)($cop$$cmpcode), $dst$$Register, $src$$Register); + %} + ins_pipe(pipe_cmov_reg); +%} + +// Conditional move ndd +instruct cmovN_reg_ndd(rRegN dst, rRegN src1, rRegN src2, rFlagsReg cr, cmpOp cop) +%{ + predicate(UseAPX); + match(Set dst (CMoveN (Binary cop cr) (Binary src1 src2))); + + ins_cost(200); + format %{ "ecmovl$cop $dst, $src1, $src2\t# signed, compressed ptr ndd" %} + ins_encode %{ + __ ecmovl((Assembler::Condition)($cop$$cmpcode), $dst$$Register, $src1$$Register, $src2$$Register); + %} + ins_pipe(pipe_cmov_reg); +%} + +// Conditional move +instruct cmovN_regU(cmpOpU cop, rFlagsRegU cr, rRegN dst, rRegN src) +%{ + predicate(!UseAPX); + match(Set dst (CMoveN (Binary cop cr) (Binary dst src))); + + ins_cost(200); // XXX + format %{ "cmovl$cop $dst, $src\t# unsigned, compressed ptr" %} + ins_encode %{ + __ cmovl((Assembler::Condition)($cop$$cmpcode), $dst$$Register, $src$$Register); + %} + ins_pipe(pipe_cmov_reg); +%} + +instruct cmovN_regUCF(cmpOpUCF cop, rFlagsRegUCF cr, rRegN dst, rRegN src) %{ + predicate(!UseAPX); + match(Set dst (CMoveN (Binary cop cr) (Binary dst src))); + ins_cost(200); + expand %{ + cmovN_regU(cop, cr, dst, src); + %} +%} + +// Conditional move ndd +instruct cmovN_regU_ndd(rRegN dst, cmpOpU cop, rFlagsRegU cr, rRegN src1, rRegN src2) +%{ + predicate(UseAPX); + match(Set dst (CMoveN (Binary cop cr) (Binary src1 src2))); + + ins_cost(200); + format %{ "ecmovl$cop $dst, $src1, $src2\t# unsigned, compressed ptr ndd" %} + ins_encode %{ + __ ecmovl((Assembler::Condition)($cop$$cmpcode), $dst$$Register, $src1$$Register, $src2$$Register); + %} + ins_pipe(pipe_cmov_reg); +%} + +instruct cmovN_regUCF_ndd(rRegN dst, cmpOpUCF cop, rFlagsRegUCF cr, rRegN src1, rRegN src2) %{ + predicate(UseAPX); + match(Set dst (CMoveN (Binary cop cr) (Binary src1 src2))); + ins_cost(200); + format %{ "ecmovl$cop $dst, $src1, $src2\t# unsigned, compressed ptr ndd" %} + ins_encode %{ + __ ecmovl((Assembler::Condition)($cop$$cmpcode), $dst$$Register, $src1$$Register, $src2$$Register); + %} + ins_pipe(pipe_cmov_reg); +%} + +instruct cmovN_regUCF2_ne(cmpOpUCF2 cop, rFlagsRegUCF cr, rRegN dst, rRegN src) %{ + predicate(n->in(1)->in(1)->as_Bool()->_test._test == BoolTest::ne); + match(Set dst (CMoveN (Binary cop cr) (Binary dst src))); + + ins_cost(200); // XXX + format %{ "cmovpl $dst, $src\n\t" + "cmovnel $dst, $src" %} + ins_encode %{ + __ cmovl(Assembler::parity, $dst$$Register, $src$$Register); + __ cmovl(Assembler::notEqual, $dst$$Register, $src$$Register); + %} + ins_pipe(pipe_cmov_reg); +%} + +// Since (x == y) == !(x != y), we can flip the sense of the test by flipping the +// inputs of the CMove +instruct cmovN_regUCF2_eq(cmpOpUCF2 cop, rFlagsRegUCF cr, rRegN dst, rRegN src) %{ + predicate(n->in(1)->in(1)->as_Bool()->_test._test == BoolTest::eq); + match(Set dst (CMoveN (Binary cop cr) (Binary src dst))); + + ins_cost(200); // XXX + format %{ "cmovpl $dst, $src\n\t" + "cmovnel $dst, $src" %} + ins_encode %{ + __ cmovl(Assembler::parity, $dst$$Register, $src$$Register); + __ cmovl(Assembler::notEqual, $dst$$Register, $src$$Register); + %} + ins_pipe(pipe_cmov_reg); +%} + +// Conditional move +instruct cmovP_reg(rRegP dst, rRegP src, rFlagsReg cr, cmpOp cop) +%{ + predicate(!UseAPX); + match(Set dst (CMoveP (Binary cop cr) (Binary dst src))); + + ins_cost(200); // XXX + format %{ "cmovq$cop $dst, $src\t# signed, ptr" %} + ins_encode %{ + __ cmovq((Assembler::Condition)($cop$$cmpcode), $dst$$Register, $src$$Register); + %} + ins_pipe(pipe_cmov_reg); // XXX +%} + +// Conditional move ndd +instruct cmovP_reg_ndd(rRegP dst, rRegP src1, rRegP src2, rFlagsReg cr, cmpOp cop) +%{ + predicate(UseAPX); + match(Set dst (CMoveP (Binary cop cr) (Binary src1 src2))); + + ins_cost(200); + format %{ "ecmovq$cop $dst, $src1, $src2\t# signed, ptr ndd" %} + ins_encode %{ + __ ecmovq((Assembler::Condition)($cop$$cmpcode), $dst$$Register, $src1$$Register, $src2$$Register); + %} + ins_pipe(pipe_cmov_reg); +%} + +// Conditional move +instruct cmovP_regU(cmpOpU cop, rFlagsRegU cr, rRegP dst, rRegP src) +%{ + predicate(!UseAPX); + match(Set dst (CMoveP (Binary cop cr) (Binary dst src))); + + ins_cost(200); // XXX + format %{ "cmovq$cop $dst, $src\t# unsigned, ptr" %} + ins_encode %{ + __ cmovq((Assembler::Condition)($cop$$cmpcode), $dst$$Register, $src$$Register); + %} + ins_pipe(pipe_cmov_reg); // XXX +%} + +// Conditional move ndd +instruct cmovP_regU_ndd(rRegP dst, cmpOpU cop, rFlagsRegU cr, rRegP src1, rRegP src2) +%{ + predicate(UseAPX); + match(Set dst (CMoveP (Binary cop cr) (Binary src1 src2))); + + ins_cost(200); + format %{ "ecmovq$cop $dst, $src1, $src2\t# unsigned, ptr ndd" %} + ins_encode %{ + __ ecmovq((Assembler::Condition)($cop$$cmpcode), $dst$$Register, $src1$$Register, $src2$$Register); + %} + ins_pipe(pipe_cmov_reg); +%} + +instruct cmovP_regUCF(cmpOpUCF cop, rFlagsRegUCF cr, rRegP dst, rRegP src) %{ + predicate(!UseAPX); + match(Set dst (CMoveP (Binary cop cr) (Binary dst src))); + ins_cost(200); + expand %{ + cmovP_regU(cop, cr, dst, src); + %} +%} + +instruct cmovP_regUCF_ndd(rRegP dst, cmpOpUCF cop, rFlagsRegUCF cr, rRegP src1, rRegP src2) %{ + predicate(UseAPX); + match(Set dst (CMoveP (Binary cop cr) (Binary src1 src2))); + ins_cost(200); + format %{ "ecmovq$cop $dst, $src1, $src2\t# unsigned, ptr ndd" %} + ins_encode %{ + __ ecmovq((Assembler::Condition)($cop$$cmpcode), $dst$$Register, $src1$$Register, $src2$$Register); + %} + ins_pipe(pipe_cmov_reg); +%} + +instruct cmovP_regUCF2_ne(cmpOpUCF2 cop, rFlagsRegUCF cr, rRegP dst, rRegP src) %{ + predicate(!UseAPX && n->in(1)->in(1)->as_Bool()->_test._test == BoolTest::ne); + match(Set dst (CMoveP (Binary cop cr) (Binary dst src))); + + ins_cost(200); // XXX + format %{ "cmovpq $dst, $src\n\t" + "cmovneq $dst, $src" %} + ins_encode %{ + __ cmovq(Assembler::parity, $dst$$Register, $src$$Register); + __ cmovq(Assembler::notEqual, $dst$$Register, $src$$Register); + %} + ins_pipe(pipe_cmov_reg); +%} + +instruct cmovP_regUCF2_ne_ndd(cmpOpUCF2 cop, rFlagsRegUCF cr, rRegP dst, rRegP src1, rRegP src2) %{ + predicate(UseAPX && n->in(1)->in(1)->as_Bool()->_test._test == BoolTest::ne); + match(Set dst (CMoveP (Binary cop cr) (Binary src1 src2))); + effect(TEMP dst); + + ins_cost(200); + format %{ "ecmovpq $dst, $src1, $src2\n\t" + "cmovneq $dst, $src2" %} + ins_encode %{ + __ ecmovq(Assembler::parity, $dst$$Register, $src1$$Register, $src2$$Register); + __ cmovq(Assembler::notEqual, $dst$$Register, $src2$$Register); + %} + ins_pipe(pipe_cmov_reg); +%} + +// Since (x == y) == !(x != y), we can flip the sense of the test by flipping the +// inputs of the CMove +instruct cmovP_regUCF2_eq(cmpOpUCF2 cop, rFlagsRegUCF cr, rRegP dst, rRegP src) %{ + predicate(!UseAPX && n->in(1)->in(1)->as_Bool()->_test._test == BoolTest::eq); + match(Set dst (CMoveP (Binary cop cr) (Binary src dst))); + + ins_cost(200); // XXX + format %{ "cmovpq $dst, $src\n\t" + "cmovneq $dst, $src" %} + ins_encode %{ + __ cmovq(Assembler::parity, $dst$$Register, $src$$Register); + __ cmovq(Assembler::notEqual, $dst$$Register, $src$$Register); + %} + ins_pipe(pipe_cmov_reg); +%} + +instruct cmovP_regUCF2_eq_ndd(cmpOpUCF2 cop, rFlagsRegUCF cr, rRegP dst, rRegP src1, rRegP src2) %{ + predicate(UseAPX && n->in(1)->in(1)->as_Bool()->_test._test == BoolTest::eq); + match(Set dst (CMoveP (Binary cop cr) (Binary src2 src1))); + effect(TEMP dst); + + ins_cost(200); + format %{ "ecmovpq $dst, $src1, $src2\n\t" + "cmovneq $dst, $src2" %} + ins_encode %{ + __ ecmovq(Assembler::parity, $dst$$Register, $src1$$Register, $src2$$Register); + __ cmovq(Assembler::notEqual, $dst$$Register, $src2$$Register); + %} + ins_pipe(pipe_cmov_reg); +%} + +instruct cmovL_imm_01(rRegL dst, immL1 src, rFlagsReg cr, cmpOp cop) +%{ + predicate(n->in(2)->in(2)->is_Con() && n->in(2)->in(2)->get_long() == 0); + match(Set dst (CMoveL (Binary cop cr) (Binary src dst))); + + ins_cost(100); // XXX + format %{ "setbn$cop $dst\t# signed, long" %} + ins_encode %{ + Assembler::Condition cond = (Assembler::Condition)($cop$$cmpcode); + __ setb(MacroAssembler::negate_condition(cond), $dst$$Register); + %} + ins_pipe(ialu_reg); +%} + +instruct cmovL_reg(cmpOp cop, rFlagsReg cr, rRegL dst, rRegL src) +%{ + predicate(!UseAPX); + match(Set dst (CMoveL (Binary cop cr) (Binary dst src))); + + ins_cost(200); // XXX + format %{ "cmovq$cop $dst, $src\t# signed, long" %} + ins_encode %{ + __ cmovq((Assembler::Condition)($cop$$cmpcode), $dst$$Register, $src$$Register); + %} + ins_pipe(pipe_cmov_reg); // XXX +%} + +instruct cmovL_reg_ndd(rRegL dst, cmpOp cop, rFlagsReg cr, rRegL src1, rRegL src2) +%{ + predicate(UseAPX); + match(Set dst (CMoveL (Binary cop cr) (Binary src1 src2))); + + ins_cost(200); + format %{ "ecmovq$cop $dst, $src1, $src2\t# signed, long ndd" %} + ins_encode %{ + __ ecmovq((Assembler::Condition)($cop$$cmpcode), $dst$$Register, $src1$$Register, $src2$$Register); + %} + ins_pipe(pipe_cmov_reg); +%} + +instruct cmovL_mem(cmpOp cop, rFlagsReg cr, rRegL dst, memory src) +%{ + predicate(!UseAPX); + match(Set dst (CMoveL (Binary cop cr) (Binary dst (LoadL src)))); + + ins_cost(200); // XXX + format %{ "cmovq$cop $dst, $src\t# signed, long" %} + ins_encode %{ + __ cmovq((Assembler::Condition)($cop$$cmpcode), $dst$$Register, $src$$Address); + %} + ins_pipe(pipe_cmov_mem); // XXX +%} + +instruct cmovL_rReg_rReg_mem_ndd(rRegL dst, cmpOp cop, rFlagsReg cr, rRegL src1, memory src2) +%{ + predicate(UseAPX); + match(Set dst (CMoveL (Binary cop cr) (Binary src1 (LoadL src2)))); + + ins_cost(200); + format %{ "ecmovq$cop $dst, $src1, $src2\t# signed, long ndd" %} + ins_encode %{ + __ ecmovq((Assembler::Condition)($cop$$cmpcode), $dst$$Register, $src1$$Register, $src2$$Address); + %} + ins_pipe(pipe_cmov_mem); +%} + +instruct cmovL_imm_01U(rRegL dst, immL1 src, rFlagsRegU cr, cmpOpU cop) +%{ + predicate(n->in(2)->in(2)->is_Con() && n->in(2)->in(2)->get_long() == 0); + match(Set dst (CMoveL (Binary cop cr) (Binary src dst))); + + ins_cost(100); // XXX + format %{ "setbn$cop $dst\t# unsigned, long" %} + ins_encode %{ + Assembler::Condition cond = (Assembler::Condition)($cop$$cmpcode); + __ setb(MacroAssembler::negate_condition(cond), $dst$$Register); + %} + ins_pipe(ialu_reg); +%} + +instruct cmovL_regU(cmpOpU cop, rFlagsRegU cr, rRegL dst, rRegL src) +%{ + predicate(!UseAPX); + match(Set dst (CMoveL (Binary cop cr) (Binary dst src))); + + ins_cost(200); // XXX + format %{ "cmovq$cop $dst, $src\t# unsigned, long" %} + ins_encode %{ + __ cmovq((Assembler::Condition)($cop$$cmpcode), $dst$$Register, $src$$Register); + %} + ins_pipe(pipe_cmov_reg); // XXX +%} + +instruct cmovL_regU_ndd(rRegL dst, cmpOpU cop, rFlagsRegU cr, rRegL src1, rRegL src2) +%{ + predicate(UseAPX); + match(Set dst (CMoveL (Binary cop cr) (Binary src1 src2))); + + ins_cost(200); + format %{ "ecmovq$cop $dst, $src1, $src2\t# unsigned, long ndd" %} + ins_encode %{ + __ ecmovq((Assembler::Condition)($cop$$cmpcode), $dst$$Register, $src1$$Register, $src2$$Register); + %} + ins_pipe(pipe_cmov_reg); +%} + +instruct cmovL_imm_01UCF(rRegL dst, immL1 src, rFlagsRegUCF cr, cmpOpUCF cop) +%{ + predicate(n->in(2)->in(2)->is_Con() && n->in(2)->in(2)->get_long() == 0); + match(Set dst (CMoveL (Binary cop cr) (Binary src dst))); + + ins_cost(100); // XXX + format %{ "setbn$cop $dst\t# unsigned, long" %} + ins_encode %{ + Assembler::Condition cond = (Assembler::Condition)($cop$$cmpcode); + __ setb(MacroAssembler::negate_condition(cond), $dst$$Register); + %} + ins_pipe(ialu_reg); +%} + +instruct cmovL_regUCF(cmpOpUCF cop, rFlagsRegUCF cr, rRegL dst, rRegL src) %{ + predicate(!UseAPX); + match(Set dst (CMoveL (Binary cop cr) (Binary dst src))); + ins_cost(200); + expand %{ + cmovL_regU(cop, cr, dst, src); + %} +%} + +instruct cmovL_regUCF_ndd(rRegL dst, cmpOpUCF cop, rFlagsRegUCF cr, rRegL src1, rRegL src2) +%{ + predicate(UseAPX); + match(Set dst (CMoveL (Binary cop cr) (Binary src1 src2))); + ins_cost(200); + format %{ "ecmovq$cop $dst, $src1, $src2\t# unsigned, long ndd" %} + ins_encode %{ + __ ecmovq((Assembler::Condition)($cop$$cmpcode), $dst$$Register, $src1$$Register, $src2$$Register); + %} + ins_pipe(pipe_cmov_reg); +%} + +instruct cmovL_regUCF2_ne(cmpOpUCF2 cop, rFlagsRegUCF cr, rRegL dst, rRegL src) %{ + predicate(!UseAPX && n->in(1)->in(1)->as_Bool()->_test._test == BoolTest::ne); + match(Set dst (CMoveL (Binary cop cr) (Binary dst src))); + + ins_cost(200); // XXX + format %{ "cmovpq $dst, $src\n\t" + "cmovneq $dst, $src" %} + ins_encode %{ + __ cmovq(Assembler::parity, $dst$$Register, $src$$Register); + __ cmovq(Assembler::notEqual, $dst$$Register, $src$$Register); + %} + ins_pipe(pipe_cmov_reg); +%} + +instruct cmovL_regUCF2_ne_ndd(cmpOpUCF2 cop, rFlagsRegUCF cr, rRegL dst, rRegL src1, rRegL src2) %{ + predicate(UseAPX && n->in(1)->in(1)->as_Bool()->_test._test == BoolTest::ne); + match(Set dst (CMoveL (Binary cop cr) (Binary src1 src2))); + effect(TEMP dst); + + ins_cost(200); + format %{ "ecmovpq $dst, $src1, $src2\n\t" + "cmovneq $dst, $src2" %} + ins_encode %{ + __ ecmovq(Assembler::parity, $dst$$Register, $src1$$Register, $src2$$Register); + __ cmovq(Assembler::notEqual, $dst$$Register, $src2$$Register); + %} + ins_pipe(pipe_cmov_reg); +%} + +// Since (x == y) == !(x != y), we can flip the sense of the test by flipping the +// inputs of the CMove +instruct cmovL_regUCF2_eq(cmpOpUCF2 cop, rFlagsRegUCF cr, rRegL dst, rRegL src) %{ + predicate(!UseAPX && n->in(1)->in(1)->as_Bool()->_test._test == BoolTest::eq); + match(Set dst (CMoveL (Binary cop cr) (Binary src dst))); + + ins_cost(200); // XXX + format %{ "cmovpq $dst, $src\n\t" + "cmovneq $dst, $src" %} + ins_encode %{ + __ cmovq(Assembler::parity, $dst$$Register, $src$$Register); + __ cmovq(Assembler::notEqual, $dst$$Register, $src$$Register); + %} + ins_pipe(pipe_cmov_reg); +%} + +instruct cmovL_regUCF2_eq_ndd(cmpOpUCF2 cop, rFlagsRegUCF cr, rRegL dst, rRegL src1, rRegL src2) %{ + predicate(UseAPX && n->in(1)->in(1)->as_Bool()->_test._test == BoolTest::eq); + match(Set dst (CMoveL (Binary cop cr) (Binary src2 src1))); + effect(TEMP dst); + + ins_cost(200); + format %{ "ecmovpq $dst, $src1, $src2\n\t" + "cmovneq $dst, $src2" %} + ins_encode %{ + __ ecmovq(Assembler::parity, $dst$$Register, $src1$$Register, $src2$$Register); + __ cmovq(Assembler::notEqual, $dst$$Register, $src2$$Register); + %} + ins_pipe(pipe_cmov_reg); +%} + +instruct cmovL_memU(cmpOpU cop, rFlagsRegU cr, rRegL dst, memory src) +%{ + predicate(!UseAPX); + match(Set dst (CMoveL (Binary cop cr) (Binary dst (LoadL src)))); + + ins_cost(200); // XXX + format %{ "cmovq$cop $dst, $src\t# unsigned, long" %} + ins_encode %{ + __ cmovq((Assembler::Condition)($cop$$cmpcode), $dst$$Register, $src$$Address); + %} + ins_pipe(pipe_cmov_mem); // XXX +%} + +instruct cmovL_memUCF(cmpOpUCF cop, rFlagsRegUCF cr, rRegL dst, memory src) %{ + predicate(!UseAPX); + match(Set dst (CMoveL (Binary cop cr) (Binary dst (LoadL src)))); + ins_cost(200); + expand %{ + cmovL_memU(cop, cr, dst, src); + %} +%} + +instruct cmovL_rReg_rReg_memU_ndd(rRegL dst, cmpOpU cop, rFlagsRegU cr, rRegL src1, memory src2) +%{ + predicate(UseAPX); + match(Set dst (CMoveL (Binary cop cr) (Binary src1 (LoadL src2)))); + + ins_cost(200); + format %{ "ecmovq$cop $dst, $src1, $src2\t# unsigned, long ndd" %} + ins_encode %{ + __ ecmovq((Assembler::Condition)($cop$$cmpcode), $dst$$Register, $src1$$Register, $src2$$Address); + %} + ins_pipe(pipe_cmov_mem); +%} + +instruct cmovL_rReg_rReg_memUCF_ndd(rRegL dst, cmpOpUCF cop, rFlagsRegUCF cr, rRegL src1, memory src2) +%{ + predicate(UseAPX); + match(Set dst (CMoveL (Binary cop cr) (Binary src1 (LoadL src2)))); + ins_cost(200); + format %{ "ecmovq$cop $dst, $src1, $src2\t# unsigned, long ndd" %} + ins_encode %{ + __ ecmovq((Assembler::Condition)($cop$$cmpcode), $dst$$Register, $src1$$Register, $src2$$Address); + %} + ins_pipe(pipe_cmov_mem); +%} + +instruct cmovF_reg(cmpOp cop, rFlagsReg cr, regF dst, regF src) +%{ + match(Set dst (CMoveF (Binary cop cr) (Binary dst src))); + + ins_cost(200); // XXX + format %{ "jn$cop skip\t# signed cmove float\n\t" + "movss $dst, $src\n" + "skip:" %} + ins_encode %{ + Label Lskip; + // Invert sense of branch from sense of CMOV + __ jccb((Assembler::Condition)($cop$$cmpcode^1), Lskip); + __ movflt($dst$$XMMRegister, $src$$XMMRegister); + __ bind(Lskip); + %} + ins_pipe(pipe_slow); +%} + +instruct cmovF_regU(cmpOpU cop, rFlagsRegU cr, regF dst, regF src) +%{ + match(Set dst (CMoveF (Binary cop cr) (Binary dst src))); + + ins_cost(200); // XXX + format %{ "jn$cop skip\t# unsigned cmove float\n\t" + "movss $dst, $src\n" + "skip:" %} + ins_encode %{ + Label Lskip; + // Invert sense of branch from sense of CMOV + __ jccb((Assembler::Condition)($cop$$cmpcode^1), Lskip); + __ movflt($dst$$XMMRegister, $src$$XMMRegister); + __ bind(Lskip); + %} + ins_pipe(pipe_slow); +%} + +instruct cmovF_regUCF(cmpOpUCF cop, rFlagsRegUCF cr, regF dst, regF src) %{ + match(Set dst (CMoveF (Binary cop cr) (Binary dst src))); + ins_cost(200); + expand %{ + cmovF_regU(cop, cr, dst, src); + %} +%} + +instruct cmovD_reg(cmpOp cop, rFlagsReg cr, regD dst, regD src) +%{ + match(Set dst (CMoveD (Binary cop cr) (Binary dst src))); + + ins_cost(200); // XXX + format %{ "jn$cop skip\t# signed cmove double\n\t" + "movsd $dst, $src\n" + "skip:" %} + ins_encode %{ + Label Lskip; + // Invert sense of branch from sense of CMOV + __ jccb((Assembler::Condition)($cop$$cmpcode^1), Lskip); + __ movdbl($dst$$XMMRegister, $src$$XMMRegister); + __ bind(Lskip); + %} + ins_pipe(pipe_slow); +%} + +instruct cmovD_regU(cmpOpU cop, rFlagsRegU cr, regD dst, regD src) +%{ + match(Set dst (CMoveD (Binary cop cr) (Binary dst src))); + + ins_cost(200); // XXX + format %{ "jn$cop skip\t# unsigned cmove double\n\t" + "movsd $dst, $src\n" + "skip:" %} + ins_encode %{ + Label Lskip; + // Invert sense of branch from sense of CMOV + __ jccb((Assembler::Condition)($cop$$cmpcode^1), Lskip); + __ movdbl($dst$$XMMRegister, $src$$XMMRegister); + __ bind(Lskip); + %} + ins_pipe(pipe_slow); +%} + +instruct cmovD_regUCF(cmpOpUCF cop, rFlagsRegUCF cr, regD dst, regD src) %{ + match(Set dst (CMoveD (Binary cop cr) (Binary dst src))); + ins_cost(200); + expand %{ + cmovD_regU(cop, cr, dst, src); + %} +%} + +//----------Arithmetic Instructions-------------------------------------------- +//----------Addition Instructions---------------------------------------------- + +instruct addI_rReg(rRegI dst, rRegI src, rFlagsReg cr) +%{ + predicate(!UseAPX); + match(Set dst (AddI dst src)); + effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); + format %{ "addl $dst, $src\t# int" %} + ins_encode %{ + __ addl($dst$$Register, $src$$Register); + %} + ins_pipe(ialu_reg_reg); +%} + +instruct addI_rReg_ndd(rRegI dst, rRegI src1, rRegI src2, rFlagsReg cr) +%{ + predicate(UseAPX); + match(Set dst (AddI src1 src2)); + effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); + + format %{ "eaddl $dst, $src1, $src2\t# int ndd" %} + ins_encode %{ + __ eaddl($dst$$Register, $src1$$Register, $src2$$Register, false); + %} + ins_pipe(ialu_reg_reg); +%} + +instruct addI_rReg_imm(rRegI dst, immI src, rFlagsReg cr) +%{ + predicate(!UseAPX); + match(Set dst (AddI dst src)); + effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); + + format %{ "addl $dst, $src\t# int" %} + ins_encode %{ + __ addl($dst$$Register, $src$$constant); + %} + ins_pipe( ialu_reg ); +%} + +instruct addI_rReg_rReg_imm_ndd(rRegI dst, rRegI src1, immI src2, rFlagsReg cr) +%{ + predicate(UseAPX); + match(Set dst (AddI src1 src2)); + effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); + + format %{ "eaddl $dst, $src1, $src2\t# int ndd" %} + ins_encode %{ + __ eaddl($dst$$Register, $src1$$Register, $src2$$constant, false); + %} + ins_pipe( ialu_reg ); +%} + +instruct addI_rReg_mem_imm_ndd(rRegI dst, memory src1, immI src2, rFlagsReg cr) +%{ + predicate(UseAPX); + match(Set dst (AddI (LoadI src1) src2)); + effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); + + format %{ "eaddl $dst, $src1, $src2\t# int ndd" %} + ins_encode %{ + __ eaddl($dst$$Register, $src1$$Address, $src2$$constant, false); + %} + ins_pipe( ialu_reg ); +%} + +instruct addI_rReg_mem(rRegI dst, memory src, rFlagsReg cr) +%{ + predicate(!UseAPX); + match(Set dst (AddI dst (LoadI src))); + effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); + + ins_cost(150); // XXX + format %{ "addl $dst, $src\t# int" %} + ins_encode %{ + __ addl($dst$$Register, $src$$Address); + %} + ins_pipe(ialu_reg_mem); +%} + +instruct addI_rReg_rReg_mem_ndd(rRegI dst, rRegI src1, memory src2, rFlagsReg cr) +%{ + predicate(UseAPX); + match(Set dst (AddI src1 (LoadI src2))); + effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); + + ins_cost(150); + format %{ "eaddl $dst, $src1, $src2\t# int ndd" %} + ins_encode %{ + __ eaddl($dst$$Register, $src1$$Register, $src2$$Address, false); + %} + ins_pipe(ialu_reg_mem); +%} + +instruct addI_mem_rReg(memory dst, rRegI src, rFlagsReg cr) +%{ + match(Set dst (StoreI dst (AddI (LoadI dst) src))); + effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); + + ins_cost(150); // XXX + format %{ "addl $dst, $src\t# int" %} + ins_encode %{ + __ addl($dst$$Address, $src$$Register); + %} + ins_pipe(ialu_mem_reg); +%} + +instruct addI_mem_imm(memory dst, immI src, rFlagsReg cr) +%{ + match(Set dst (StoreI dst (AddI (LoadI dst) src))); + effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); + + + ins_cost(125); // XXX + format %{ "addl $dst, $src\t# int" %} + ins_encode %{ + __ addl($dst$$Address, $src$$constant); + %} + ins_pipe(ialu_mem_imm); +%} + +instruct incI_rReg(rRegI dst, immI_1 src, rFlagsReg cr) +%{ + predicate(!UseAPX && UseIncDec); + match(Set dst (AddI dst src)); + effect(KILL cr); + + format %{ "incl $dst\t# int" %} + ins_encode %{ + __ incrementl($dst$$Register); + %} + ins_pipe(ialu_reg); +%} + +instruct incI_rReg_ndd(rRegI dst, rRegI src, immI_1 val, rFlagsReg cr) +%{ + predicate(UseAPX && UseIncDec); + match(Set dst (AddI src val)); + effect(KILL cr); + + format %{ "eincl $dst, $src\t# int ndd" %} + ins_encode %{ + __ eincl($dst$$Register, $src$$Register, false); + %} + ins_pipe(ialu_reg); +%} + +instruct incI_rReg_mem_ndd(rRegI dst, memory src, immI_1 val, rFlagsReg cr) +%{ + predicate(UseAPX && UseIncDec); + match(Set dst (AddI (LoadI src) val)); + effect(KILL cr); + + format %{ "eincl $dst, $src\t# int ndd" %} + ins_encode %{ + __ eincl($dst$$Register, $src$$Address, false); + %} + ins_pipe(ialu_reg); +%} + +instruct incI_mem(memory dst, immI_1 src, rFlagsReg cr) +%{ + predicate(UseIncDec); + match(Set dst (StoreI dst (AddI (LoadI dst) src))); + effect(KILL cr); + + ins_cost(125); // XXX + format %{ "incl $dst\t# int" %} + ins_encode %{ + __ incrementl($dst$$Address); + %} + ins_pipe(ialu_mem_imm); +%} + +// XXX why does that use AddI +instruct decI_rReg(rRegI dst, immI_M1 src, rFlagsReg cr) +%{ + predicate(!UseAPX && UseIncDec); + match(Set dst (AddI dst src)); + effect(KILL cr); + + format %{ "decl $dst\t# int" %} + ins_encode %{ + __ decrementl($dst$$Register); + %} + ins_pipe(ialu_reg); +%} + +instruct decI_rReg_ndd(rRegI dst, rRegI src, immI_M1 val, rFlagsReg cr) +%{ + predicate(UseAPX && UseIncDec); + match(Set dst (AddI src val)); + effect(KILL cr); + + format %{ "edecl $dst, $src\t# int ndd" %} + ins_encode %{ + __ edecl($dst$$Register, $src$$Register, false); + %} + ins_pipe(ialu_reg); +%} + +instruct decI_rReg_mem_ndd(rRegI dst, memory src, immI_M1 val, rFlagsReg cr) +%{ + predicate(UseAPX && UseIncDec); + match(Set dst (AddI (LoadI src) val)); + effect(KILL cr); + + format %{ "edecl $dst, $src\t# int ndd" %} + ins_encode %{ + __ edecl($dst$$Register, $src$$Address, false); + %} + ins_pipe(ialu_reg); +%} + +// XXX why does that use AddI +instruct decI_mem(memory dst, immI_M1 src, rFlagsReg cr) +%{ + predicate(UseIncDec); + match(Set dst (StoreI dst (AddI (LoadI dst) src))); + effect(KILL cr); + + ins_cost(125); // XXX + format %{ "decl $dst\t# int" %} + ins_encode %{ + __ decrementl($dst$$Address); + %} + ins_pipe(ialu_mem_imm); +%} + +instruct leaI_rReg_immI2_immI(rRegI dst, rRegI index, immI2 scale, immI disp) +%{ + predicate(VM_Version::supports_fast_2op_lea()); + match(Set dst (AddI (LShiftI index scale) disp)); + + format %{ "leal $dst, [$index << $scale + $disp]\t# int" %} + ins_encode %{ + Address::ScaleFactor scale = static_cast($scale$$constant); + __ leal($dst$$Register, Address(noreg, $index$$Register, scale, $disp$$constant)); + %} + ins_pipe(ialu_reg_reg); +%} + +instruct leaI_rReg_rReg_immI(rRegI dst, rRegI base, rRegI index, immI disp) +%{ + predicate(VM_Version::supports_fast_3op_lea()); + match(Set dst (AddI (AddI base index) disp)); + + format %{ "leal $dst, [$base + $index + $disp]\t# int" %} + ins_encode %{ + __ leal($dst$$Register, Address($base$$Register, $index$$Register, Address::times_1, $disp$$constant)); + %} + ins_pipe(ialu_reg_reg); +%} + +instruct leaI_rReg_rReg_immI2(rRegI dst, no_rbp_r13_RegI base, rRegI index, immI2 scale) +%{ + predicate(VM_Version::supports_fast_2op_lea()); + match(Set dst (AddI base (LShiftI index scale))); + + format %{ "leal $dst, [$base + $index << $scale]\t# int" %} + ins_encode %{ + Address::ScaleFactor scale = static_cast($scale$$constant); + __ leal($dst$$Register, Address($base$$Register, $index$$Register, scale)); + %} + ins_pipe(ialu_reg_reg); +%} + +instruct leaI_rReg_rReg_immI2_immI(rRegI dst, rRegI base, rRegI index, immI2 scale, immI disp) +%{ + predicate(VM_Version::supports_fast_3op_lea()); + match(Set dst (AddI (AddI base (LShiftI index scale)) disp)); + + format %{ "leal $dst, [$base + $index << $scale + $disp]\t# int" %} + ins_encode %{ + Address::ScaleFactor scale = static_cast($scale$$constant); + __ leal($dst$$Register, Address($base$$Register, $index$$Register, scale, $disp$$constant)); + %} + ins_pipe(ialu_reg_reg); +%} + +instruct addL_rReg(rRegL dst, rRegL src, rFlagsReg cr) +%{ + predicate(!UseAPX); + match(Set dst (AddL dst src)); + effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); + + format %{ "addq $dst, $src\t# long" %} + ins_encode %{ + __ addq($dst$$Register, $src$$Register); + %} + ins_pipe(ialu_reg_reg); +%} + +instruct addL_rReg_ndd(rRegL dst, rRegL src1, rRegL src2, rFlagsReg cr) +%{ + predicate(UseAPX); + match(Set dst (AddL src1 src2)); + effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); + + format %{ "eaddq $dst, $src1, $src2\t# long ndd" %} + ins_encode %{ + __ eaddq($dst$$Register, $src1$$Register, $src2$$Register, false); + %} + ins_pipe(ialu_reg_reg); +%} + +instruct addL_rReg_imm(rRegL dst, immL32 src, rFlagsReg cr) +%{ + predicate(!UseAPX); + match(Set dst (AddL dst src)); + effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); + + format %{ "addq $dst, $src\t# long" %} + ins_encode %{ + __ addq($dst$$Register, $src$$constant); + %} + ins_pipe( ialu_reg ); +%} + +instruct addL_rReg_rReg_imm_ndd(rRegL dst, rRegL src1, immL32 src2, rFlagsReg cr) +%{ + predicate(UseAPX); + match(Set dst (AddL src1 src2)); + effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); + + format %{ "eaddq $dst, $src1, $src2\t# long ndd" %} + ins_encode %{ + __ eaddq($dst$$Register, $src1$$Register, $src2$$constant, false); + %} + ins_pipe( ialu_reg ); +%} + +instruct addL_rReg_mem_imm_ndd(rRegL dst, memory src1, immL32 src2, rFlagsReg cr) +%{ + predicate(UseAPX); + match(Set dst (AddL (LoadL src1) src2)); + effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); + + format %{ "eaddq $dst, $src1, $src2\t# long ndd" %} + ins_encode %{ + __ eaddq($dst$$Register, $src1$$Address, $src2$$constant, false); + %} + ins_pipe( ialu_reg ); +%} + +instruct addL_rReg_mem(rRegL dst, memory src, rFlagsReg cr) +%{ + predicate(!UseAPX); + match(Set dst (AddL dst (LoadL src))); + effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); + + ins_cost(150); // XXX + format %{ "addq $dst, $src\t# long" %} + ins_encode %{ + __ addq($dst$$Register, $src$$Address); + %} + ins_pipe(ialu_reg_mem); +%} + +instruct addL_rReg_rReg_mem_ndd(rRegL dst, rRegL src1, memory src2, rFlagsReg cr) +%{ + predicate(UseAPX); + match(Set dst (AddL src1 (LoadL src2))); + effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); + + ins_cost(150); + format %{ "eaddq $dst, $src1, $src2\t# long ndd" %} + ins_encode %{ + __ eaddq($dst$$Register, $src1$$Register, $src2$$Address, false); + %} + ins_pipe(ialu_reg_mem); +%} + +instruct addL_mem_rReg(memory dst, rRegL src, rFlagsReg cr) +%{ + match(Set dst (StoreL dst (AddL (LoadL dst) src))); + effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); + + ins_cost(150); // XXX + format %{ "addq $dst, $src\t# long" %} + ins_encode %{ + __ addq($dst$$Address, $src$$Register); + %} + ins_pipe(ialu_mem_reg); +%} + +instruct addL_mem_imm(memory dst, immL32 src, rFlagsReg cr) +%{ + match(Set dst (StoreL dst (AddL (LoadL dst) src))); + effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); + + ins_cost(125); // XXX + format %{ "addq $dst, $src\t# long" %} + ins_encode %{ + __ addq($dst$$Address, $src$$constant); + %} + ins_pipe(ialu_mem_imm); +%} + +instruct incL_rReg(rRegL dst, immL1 src, rFlagsReg cr) +%{ + predicate(!UseAPX && UseIncDec); + match(Set dst (AddL dst src)); + effect(KILL cr); + + format %{ "incq $dst\t# long" %} + ins_encode %{ + __ incrementq($dst$$Register); + %} + ins_pipe(ialu_reg); +%} + +instruct incL_rReg_ndd(rRegL dst, rRegI src, immL1 val, rFlagsReg cr) +%{ + predicate(UseAPX && UseIncDec); + match(Set dst (AddL src val)); + effect(KILL cr); + + format %{ "eincq $dst, $src\t# long ndd" %} + ins_encode %{ + __ eincq($dst$$Register, $src$$Register, false); + %} + ins_pipe(ialu_reg); +%} + +instruct incL_rReg_mem_ndd(rRegL dst, memory src, immL1 val, rFlagsReg cr) +%{ + predicate(UseAPX && UseIncDec); + match(Set dst (AddL (LoadL src) val)); + effect(KILL cr); + + format %{ "eincq $dst, $src\t# long ndd" %} + ins_encode %{ + __ eincq($dst$$Register, $src$$Address, false); + %} + ins_pipe(ialu_reg); +%} + +instruct incL_mem(memory dst, immL1 src, rFlagsReg cr) +%{ + predicate(UseIncDec); + match(Set dst (StoreL dst (AddL (LoadL dst) src))); + effect(KILL cr); + + ins_cost(125); // XXX + format %{ "incq $dst\t# long" %} + ins_encode %{ + __ incrementq($dst$$Address); + %} + ins_pipe(ialu_mem_imm); +%} + +// XXX why does that use AddL +instruct decL_rReg(rRegL dst, immL_M1 src, rFlagsReg cr) +%{ + predicate(!UseAPX && UseIncDec); + match(Set dst (AddL dst src)); + effect(KILL cr); + + format %{ "decq $dst\t# long" %} + ins_encode %{ + __ decrementq($dst$$Register); + %} + ins_pipe(ialu_reg); +%} + +instruct decL_rReg_ndd(rRegL dst, rRegL src, immL_M1 val, rFlagsReg cr) +%{ + predicate(UseAPX && UseIncDec); + match(Set dst (AddL src val)); + effect(KILL cr); + + format %{ "edecq $dst, $src\t# long ndd" %} + ins_encode %{ + __ edecq($dst$$Register, $src$$Register, false); + %} + ins_pipe(ialu_reg); +%} + +instruct decL_rReg_mem_ndd(rRegL dst, memory src, immL_M1 val, rFlagsReg cr) +%{ + predicate(UseAPX && UseIncDec); + match(Set dst (AddL (LoadL src) val)); + effect(KILL cr); + + format %{ "edecq $dst, $src\t# long ndd" %} + ins_encode %{ + __ edecq($dst$$Register, $src$$Address, false); + %} + ins_pipe(ialu_reg); +%} + +// XXX why does that use AddL +instruct decL_mem(memory dst, immL_M1 src, rFlagsReg cr) +%{ + predicate(UseIncDec); + match(Set dst (StoreL dst (AddL (LoadL dst) src))); + effect(KILL cr); + + ins_cost(125); // XXX + format %{ "decq $dst\t# long" %} + ins_encode %{ + __ decrementq($dst$$Address); + %} + ins_pipe(ialu_mem_imm); +%} + +instruct leaL_rReg_immI2_immL32(rRegL dst, rRegL index, immI2 scale, immL32 disp) +%{ + predicate(VM_Version::supports_fast_2op_lea()); + match(Set dst (AddL (LShiftL index scale) disp)); + + format %{ "leaq $dst, [$index << $scale + $disp]\t# long" %} + ins_encode %{ + Address::ScaleFactor scale = static_cast($scale$$constant); + __ leaq($dst$$Register, Address(noreg, $index$$Register, scale, $disp$$constant)); + %} + ins_pipe(ialu_reg_reg); +%} + +instruct leaL_rReg_rReg_immL32(rRegL dst, rRegL base, rRegL index, immL32 disp) +%{ + predicate(VM_Version::supports_fast_3op_lea()); + match(Set dst (AddL (AddL base index) disp)); + + format %{ "leaq $dst, [$base + $index + $disp]\t# long" %} + ins_encode %{ + __ leaq($dst$$Register, Address($base$$Register, $index$$Register, Address::times_1, $disp$$constant)); + %} + ins_pipe(ialu_reg_reg); +%} + +instruct leaL_rReg_rReg_immI2(rRegL dst, no_rbp_r13_RegL base, rRegL index, immI2 scale) +%{ + predicate(VM_Version::supports_fast_2op_lea()); + match(Set dst (AddL base (LShiftL index scale))); + + format %{ "leaq $dst, [$base + $index << $scale]\t# long" %} + ins_encode %{ + Address::ScaleFactor scale = static_cast($scale$$constant); + __ leaq($dst$$Register, Address($base$$Register, $index$$Register, scale)); + %} + ins_pipe(ialu_reg_reg); +%} + +instruct leaL_rReg_rReg_immI2_immL32(rRegL dst, rRegL base, rRegL index, immI2 scale, immL32 disp) +%{ + predicate(VM_Version::supports_fast_3op_lea()); + match(Set dst (AddL (AddL base (LShiftL index scale)) disp)); + + format %{ "leaq $dst, [$base + $index << $scale + $disp]\t# long" %} + ins_encode %{ + Address::ScaleFactor scale = static_cast($scale$$constant); + __ leaq($dst$$Register, Address($base$$Register, $index$$Register, scale, $disp$$constant)); + %} + ins_pipe(ialu_reg_reg); +%} + +instruct addP_rReg(rRegP dst, rRegL src, rFlagsReg cr) +%{ + match(Set dst (AddP dst src)); + effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); + + format %{ "addq $dst, $src\t# ptr" %} + ins_encode %{ + __ addq($dst$$Register, $src$$Register); + %} + ins_pipe(ialu_reg_reg); +%} + +instruct addP_rReg_imm(rRegP dst, immL32 src, rFlagsReg cr) +%{ + match(Set dst (AddP dst src)); + effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); + + format %{ "addq $dst, $src\t# ptr" %} + ins_encode %{ + __ addq($dst$$Register, $src$$constant); + %} + ins_pipe( ialu_reg ); +%} + +// XXX addP mem ops ???? + +instruct checkCastPP(rRegP dst) +%{ + match(Set dst (CheckCastPP dst)); + + size(0); + format %{ "# checkcastPP of $dst" %} + ins_encode(/* empty encoding */); + ins_pipe(empty); +%} + +instruct castPP(rRegP dst) +%{ + match(Set dst (CastPP dst)); + + size(0); + format %{ "# castPP of $dst" %} + ins_encode(/* empty encoding */); + ins_pipe(empty); +%} + +instruct castII(rRegI dst) +%{ + predicate(VerifyConstraintCasts == 0); + match(Set dst (CastII dst)); + + size(0); + format %{ "# castII of $dst" %} + ins_encode(/* empty encoding */); + ins_cost(0); + ins_pipe(empty); +%} + +instruct castII_checked(rRegI dst, rFlagsReg cr) +%{ + predicate(VerifyConstraintCasts > 0); + match(Set dst (CastII dst)); + + effect(KILL cr); + format %{ "# cast_checked_II $dst" %} + ins_encode %{ + __ verify_int_in_range(_idx, bottom_type()->is_int(), $dst$$Register); + %} + ins_pipe(pipe_slow); +%} + +instruct castLL(rRegL dst) +%{ + predicate(VerifyConstraintCasts == 0); + match(Set dst (CastLL dst)); + + size(0); + format %{ "# castLL of $dst" %} + ins_encode(/* empty encoding */); + ins_cost(0); + ins_pipe(empty); +%} + +instruct castLL_checked_L32(rRegL dst, rFlagsReg cr) +%{ + predicate(VerifyConstraintCasts > 0 && castLL_is_imm32(n)); + match(Set dst (CastLL dst)); + + effect(KILL cr); + format %{ "# cast_checked_LL $dst" %} + ins_encode %{ + __ verify_long_in_range(_idx, bottom_type()->is_long(), $dst$$Register, noreg); + %} + ins_pipe(pipe_slow); +%} + +instruct castLL_checked(rRegL dst, rRegL tmp, rFlagsReg cr) +%{ + predicate(VerifyConstraintCasts > 0 && !castLL_is_imm32(n)); + match(Set dst (CastLL dst)); + + effect(KILL cr, TEMP tmp); + format %{ "# cast_checked_LL $dst\tusing $tmp as TEMP" %} + ins_encode %{ + __ verify_long_in_range(_idx, bottom_type()->is_long(), $dst$$Register, $tmp$$Register); + %} + ins_pipe(pipe_slow); +%} + +instruct castFF(regF dst) +%{ + match(Set dst (CastFF dst)); + + size(0); + format %{ "# castFF of $dst" %} + ins_encode(/* empty encoding */); + ins_cost(0); + ins_pipe(empty); +%} + +instruct castHH(regF dst) +%{ + match(Set dst (CastHH dst)); + + size(0); + format %{ "# castHH of $dst" %} + ins_encode(/* empty encoding */); + ins_cost(0); + ins_pipe(empty); +%} + +instruct castDD(regD dst) +%{ + match(Set dst (CastDD dst)); + + size(0); + format %{ "# castDD of $dst" %} + ins_encode(/* empty encoding */); + ins_cost(0); + ins_pipe(empty); +%} + +// XXX No flag versions for CompareAndSwap{P,I,L} because matcher can't match them +instruct compareAndSwapP(rRegI res, + memory mem_ptr, + rax_RegP oldval, rRegP newval, + rFlagsReg cr) +%{ + predicate(n->as_LoadStore()->barrier_data() == 0); + match(Set res (CompareAndSwapP mem_ptr (Binary oldval newval))); + match(Set res (WeakCompareAndSwapP mem_ptr (Binary oldval newval))); + effect(KILL cr, KILL oldval); + + format %{ "cmpxchgq $mem_ptr,$newval\t# " + "If rax == $mem_ptr then store $newval into $mem_ptr\n\t" + "setcc $res \t# emits sete + movzbl or setzue for APX" %} + ins_encode %{ + __ lock(); + __ cmpxchgq($newval$$Register, $mem_ptr$$Address); + __ setcc(Assembler::equal, $res$$Register); + %} + ins_pipe( pipe_cmpxchg ); +%} + +instruct compareAndSwapL(rRegI res, + memory mem_ptr, + rax_RegL oldval, rRegL newval, + rFlagsReg cr) +%{ + match(Set res (CompareAndSwapL mem_ptr (Binary oldval newval))); + match(Set res (WeakCompareAndSwapL mem_ptr (Binary oldval newval))); + effect(KILL cr, KILL oldval); + + format %{ "cmpxchgq $mem_ptr,$newval\t# " + "If rax == $mem_ptr then store $newval into $mem_ptr\n\t" + "setcc $res \t# emits sete + movzbl or setzue for APX" %} + ins_encode %{ + __ lock(); + __ cmpxchgq($newval$$Register, $mem_ptr$$Address); + __ setcc(Assembler::equal, $res$$Register); + %} + ins_pipe( pipe_cmpxchg ); +%} + +instruct compareAndSwapI(rRegI res, + memory mem_ptr, + rax_RegI oldval, rRegI newval, + rFlagsReg cr) +%{ + match(Set res (CompareAndSwapI mem_ptr (Binary oldval newval))); + match(Set res (WeakCompareAndSwapI mem_ptr (Binary oldval newval))); + effect(KILL cr, KILL oldval); + + format %{ "cmpxchgl $mem_ptr,$newval\t# " + "If rax == $mem_ptr then store $newval into $mem_ptr\n\t" + "setcc $res \t# emits sete + movzbl or setzue for APX" %} + ins_encode %{ + __ lock(); + __ cmpxchgl($newval$$Register, $mem_ptr$$Address); + __ setcc(Assembler::equal, $res$$Register); + %} + ins_pipe( pipe_cmpxchg ); +%} + +instruct compareAndSwapB(rRegI res, + memory mem_ptr, + rax_RegI oldval, rRegI newval, + rFlagsReg cr) +%{ + match(Set res (CompareAndSwapB mem_ptr (Binary oldval newval))); + match(Set res (WeakCompareAndSwapB mem_ptr (Binary oldval newval))); + effect(KILL cr, KILL oldval); + + format %{ "cmpxchgb $mem_ptr,$newval\t# " + "If rax == $mem_ptr then store $newval into $mem_ptr\n\t" + "setcc $res \t# emits sete + movzbl or setzue for APX" %} + ins_encode %{ + __ lock(); + __ cmpxchgb($newval$$Register, $mem_ptr$$Address); + __ setcc(Assembler::equal, $res$$Register); + %} + ins_pipe( pipe_cmpxchg ); +%} + +instruct compareAndSwapS(rRegI res, + memory mem_ptr, + rax_RegI oldval, rRegI newval, + rFlagsReg cr) +%{ + match(Set res (CompareAndSwapS mem_ptr (Binary oldval newval))); + match(Set res (WeakCompareAndSwapS mem_ptr (Binary oldval newval))); + effect(KILL cr, KILL oldval); + + format %{ "cmpxchgw $mem_ptr,$newval\t# " + "If rax == $mem_ptr then store $newval into $mem_ptr\n\t" + "setcc $res \t# emits sete + movzbl or setzue for APX" %} + ins_encode %{ + __ lock(); + __ cmpxchgw($newval$$Register, $mem_ptr$$Address); + __ setcc(Assembler::equal, $res$$Register); + %} + ins_pipe( pipe_cmpxchg ); +%} + +instruct compareAndSwapN(rRegI res, + memory mem_ptr, + rax_RegN oldval, rRegN newval, + rFlagsReg cr) %{ + predicate(n->as_LoadStore()->barrier_data() == 0); + match(Set res (CompareAndSwapN mem_ptr (Binary oldval newval))); + match(Set res (WeakCompareAndSwapN mem_ptr (Binary oldval newval))); + effect(KILL cr, KILL oldval); + + format %{ "cmpxchgl $mem_ptr,$newval\t# " + "If rax == $mem_ptr then store $newval into $mem_ptr\n\t" + "setcc $res \t# emits sete + movzbl or setzue for APX" %} + ins_encode %{ + __ lock(); + __ cmpxchgl($newval$$Register, $mem_ptr$$Address); + __ setcc(Assembler::equal, $res$$Register); + %} + ins_pipe( pipe_cmpxchg ); +%} + +instruct compareAndExchangeB( + memory mem_ptr, + rax_RegI oldval, rRegI newval, + rFlagsReg cr) +%{ + match(Set oldval (CompareAndExchangeB mem_ptr (Binary oldval newval))); + effect(KILL cr); + + format %{ "cmpxchgb $mem_ptr,$newval\t# " + "If rax == $mem_ptr then store $newval into $mem_ptr\n\t" %} + ins_encode %{ + __ lock(); + __ cmpxchgb($newval$$Register, $mem_ptr$$Address); + %} + ins_pipe( pipe_cmpxchg ); +%} + +instruct compareAndExchangeS( + memory mem_ptr, + rax_RegI oldval, rRegI newval, + rFlagsReg cr) +%{ + match(Set oldval (CompareAndExchangeS mem_ptr (Binary oldval newval))); + effect(KILL cr); + + format %{ "cmpxchgw $mem_ptr,$newval\t# " + "If rax == $mem_ptr then store $newval into $mem_ptr\n\t" %} + ins_encode %{ + __ lock(); + __ cmpxchgw($newval$$Register, $mem_ptr$$Address); + %} + ins_pipe( pipe_cmpxchg ); +%} + +instruct compareAndExchangeI( + memory mem_ptr, + rax_RegI oldval, rRegI newval, + rFlagsReg cr) +%{ + match(Set oldval (CompareAndExchangeI mem_ptr (Binary oldval newval))); + effect(KILL cr); + + format %{ "cmpxchgl $mem_ptr,$newval\t# " + "If rax == $mem_ptr then store $newval into $mem_ptr\n\t" %} + ins_encode %{ + __ lock(); + __ cmpxchgl($newval$$Register, $mem_ptr$$Address); + %} + ins_pipe( pipe_cmpxchg ); +%} + +instruct compareAndExchangeL( + memory mem_ptr, + rax_RegL oldval, rRegL newval, + rFlagsReg cr) +%{ + match(Set oldval (CompareAndExchangeL mem_ptr (Binary oldval newval))); + effect(KILL cr); + + format %{ "cmpxchgq $mem_ptr,$newval\t# " + "If rax == $mem_ptr then store $newval into $mem_ptr\n\t" %} + ins_encode %{ + __ lock(); + __ cmpxchgq($newval$$Register, $mem_ptr$$Address); + %} + ins_pipe( pipe_cmpxchg ); +%} + +instruct compareAndExchangeN( + memory mem_ptr, + rax_RegN oldval, rRegN newval, + rFlagsReg cr) %{ + predicate(n->as_LoadStore()->barrier_data() == 0); + match(Set oldval (CompareAndExchangeN mem_ptr (Binary oldval newval))); + effect(KILL cr); + + format %{ "cmpxchgl $mem_ptr,$newval\t# " + "If rax == $mem_ptr then store $newval into $mem_ptr\n\t" %} + ins_encode %{ + __ lock(); + __ cmpxchgl($newval$$Register, $mem_ptr$$Address); + %} + ins_pipe( pipe_cmpxchg ); +%} + +instruct compareAndExchangeP( + memory mem_ptr, + rax_RegP oldval, rRegP newval, + rFlagsReg cr) +%{ + predicate(n->as_LoadStore()->barrier_data() == 0); + match(Set oldval (CompareAndExchangeP mem_ptr (Binary oldval newval))); + effect(KILL cr); + + format %{ "cmpxchgq $mem_ptr,$newval\t# " + "If rax == $mem_ptr then store $newval into $mem_ptr\n\t" %} + ins_encode %{ + __ lock(); + __ cmpxchgq($newval$$Register, $mem_ptr$$Address); + %} + ins_pipe( pipe_cmpxchg ); +%} + +instruct xaddB_reg_no_res(memory mem, Universe dummy, rRegI add, rFlagsReg cr) %{ + predicate(n->as_LoadStore()->result_not_used()); + match(Set dummy (GetAndAddB mem add)); + effect(KILL cr); + format %{ "addb_lock $mem, $add" %} + ins_encode %{ + __ lock(); + __ addb($mem$$Address, $add$$Register); + %} + ins_pipe(pipe_cmpxchg); +%} + +instruct xaddB_imm_no_res(memory mem, Universe dummy, immI add, rFlagsReg cr) %{ + predicate(n->as_LoadStore()->result_not_used()); + match(Set dummy (GetAndAddB mem add)); + effect(KILL cr); + format %{ "addb_lock $mem, $add" %} + ins_encode %{ + __ lock(); + __ addb($mem$$Address, $add$$constant); + %} + ins_pipe(pipe_cmpxchg); +%} + +instruct xaddB(memory mem, rRegI newval, rFlagsReg cr) %{ + predicate(!n->as_LoadStore()->result_not_used()); + match(Set newval (GetAndAddB mem newval)); + effect(KILL cr); + format %{ "xaddb_lock $mem, $newval" %} + ins_encode %{ + __ lock(); + __ xaddb($mem$$Address, $newval$$Register); + %} + ins_pipe(pipe_cmpxchg); +%} + +instruct xaddS_reg_no_res(memory mem, Universe dummy, rRegI add, rFlagsReg cr) %{ + predicate(n->as_LoadStore()->result_not_used()); + match(Set dummy (GetAndAddS mem add)); + effect(KILL cr); + format %{ "addw_lock $mem, $add" %} + ins_encode %{ + __ lock(); + __ addw($mem$$Address, $add$$Register); + %} + ins_pipe(pipe_cmpxchg); +%} + +instruct xaddS_imm_no_res(memory mem, Universe dummy, immI add, rFlagsReg cr) %{ + predicate(UseStoreImmI16 && n->as_LoadStore()->result_not_used()); + match(Set dummy (GetAndAddS mem add)); + effect(KILL cr); + format %{ "addw_lock $mem, $add" %} + ins_encode %{ + __ lock(); + __ addw($mem$$Address, $add$$constant); + %} + ins_pipe(pipe_cmpxchg); +%} + +instruct xaddS(memory mem, rRegI newval, rFlagsReg cr) %{ + predicate(!n->as_LoadStore()->result_not_used()); + match(Set newval (GetAndAddS mem newval)); + effect(KILL cr); + format %{ "xaddw_lock $mem, $newval" %} + ins_encode %{ + __ lock(); + __ xaddw($mem$$Address, $newval$$Register); + %} + ins_pipe(pipe_cmpxchg); +%} + +instruct xaddI_reg_no_res(memory mem, Universe dummy, rRegI add, rFlagsReg cr) %{ + predicate(n->as_LoadStore()->result_not_used()); + match(Set dummy (GetAndAddI mem add)); + effect(KILL cr); + format %{ "addl_lock $mem, $add" %} + ins_encode %{ + __ lock(); + __ addl($mem$$Address, $add$$Register); + %} + ins_pipe(pipe_cmpxchg); +%} + +instruct xaddI_imm_no_res(memory mem, Universe dummy, immI add, rFlagsReg cr) %{ + predicate(n->as_LoadStore()->result_not_used()); + match(Set dummy (GetAndAddI mem add)); + effect(KILL cr); + format %{ "addl_lock $mem, $add" %} + ins_encode %{ + __ lock(); + __ addl($mem$$Address, $add$$constant); + %} + ins_pipe(pipe_cmpxchg); +%} + +instruct xaddI(memory mem, rRegI newval, rFlagsReg cr) %{ + predicate(!n->as_LoadStore()->result_not_used()); + match(Set newval (GetAndAddI mem newval)); + effect(KILL cr); + format %{ "xaddl_lock $mem, $newval" %} + ins_encode %{ + __ lock(); + __ xaddl($mem$$Address, $newval$$Register); + %} + ins_pipe(pipe_cmpxchg); +%} + +instruct xaddL_reg_no_res(memory mem, Universe dummy, rRegL add, rFlagsReg cr) %{ + predicate(n->as_LoadStore()->result_not_used()); + match(Set dummy (GetAndAddL mem add)); + effect(KILL cr); + format %{ "addq_lock $mem, $add" %} + ins_encode %{ + __ lock(); + __ addq($mem$$Address, $add$$Register); + %} + ins_pipe(pipe_cmpxchg); +%} + +instruct xaddL_imm_no_res(memory mem, Universe dummy, immL32 add, rFlagsReg cr) %{ + predicate(n->as_LoadStore()->result_not_used()); + match(Set dummy (GetAndAddL mem add)); + effect(KILL cr); + format %{ "addq_lock $mem, $add" %} + ins_encode %{ + __ lock(); + __ addq($mem$$Address, $add$$constant); + %} + ins_pipe(pipe_cmpxchg); +%} + +instruct xaddL(memory mem, rRegL newval, rFlagsReg cr) %{ + predicate(!n->as_LoadStore()->result_not_used()); + match(Set newval (GetAndAddL mem newval)); + effect(KILL cr); + format %{ "xaddq_lock $mem, $newval" %} + ins_encode %{ + __ lock(); + __ xaddq($mem$$Address, $newval$$Register); + %} + ins_pipe(pipe_cmpxchg); +%} + +instruct xchgB( memory mem, rRegI newval) %{ + match(Set newval (GetAndSetB mem newval)); + format %{ "XCHGB $newval,[$mem]" %} + ins_encode %{ + __ xchgb($newval$$Register, $mem$$Address); + %} + ins_pipe( pipe_cmpxchg ); +%} + +instruct xchgS( memory mem, rRegI newval) %{ + match(Set newval (GetAndSetS mem newval)); + format %{ "XCHGW $newval,[$mem]" %} + ins_encode %{ + __ xchgw($newval$$Register, $mem$$Address); + %} + ins_pipe( pipe_cmpxchg ); +%} + +instruct xchgI( memory mem, rRegI newval) %{ + match(Set newval (GetAndSetI mem newval)); + format %{ "XCHGL $newval,[$mem]" %} + ins_encode %{ + __ xchgl($newval$$Register, $mem$$Address); + %} + ins_pipe( pipe_cmpxchg ); +%} + +instruct xchgL( memory mem, rRegL newval) %{ + match(Set newval (GetAndSetL mem newval)); + format %{ "XCHGL $newval,[$mem]" %} + ins_encode %{ + __ xchgq($newval$$Register, $mem$$Address); + %} + ins_pipe( pipe_cmpxchg ); +%} + +instruct xchgP( memory mem, rRegP newval) %{ + match(Set newval (GetAndSetP mem newval)); + predicate(n->as_LoadStore()->barrier_data() == 0); + format %{ "XCHGQ $newval,[$mem]" %} + ins_encode %{ + __ xchgq($newval$$Register, $mem$$Address); + %} + ins_pipe( pipe_cmpxchg ); +%} + +instruct xchgN( memory mem, rRegN newval) %{ + predicate(n->as_LoadStore()->barrier_data() == 0); + match(Set newval (GetAndSetN mem newval)); + format %{ "XCHGL $newval,$mem]" %} + ins_encode %{ + __ xchgl($newval$$Register, $mem$$Address); + %} + ins_pipe( pipe_cmpxchg ); +%} + +//----------Abs Instructions------------------------------------------- + +// Integer Absolute Instructions +instruct absI_rReg(rRegI dst, rRegI src, rFlagsReg cr) +%{ + match(Set dst (AbsI src)); + effect(TEMP dst, KILL cr); + format %{ "xorl $dst, $dst\t# abs int\n\t" + "subl $dst, $src\n\t" + "cmovll $dst, $src" %} + ins_encode %{ + __ xorl($dst$$Register, $dst$$Register); + __ subl($dst$$Register, $src$$Register); + __ cmovl(Assembler::less, $dst$$Register, $src$$Register); + %} + + ins_pipe(ialu_reg_reg); +%} + +// Long Absolute Instructions +instruct absL_rReg(rRegL dst, rRegL src, rFlagsReg cr) +%{ + match(Set dst (AbsL src)); + effect(TEMP dst, KILL cr); + format %{ "xorl $dst, $dst\t# abs long\n\t" + "subq $dst, $src\n\t" + "cmovlq $dst, $src" %} + ins_encode %{ + __ xorl($dst$$Register, $dst$$Register); + __ subq($dst$$Register, $src$$Register); + __ cmovq(Assembler::less, $dst$$Register, $src$$Register); + %} + + ins_pipe(ialu_reg_reg); +%} + +//----------Subtraction Instructions------------------------------------------- + +// Integer Subtraction Instructions +instruct subI_rReg(rRegI dst, rRegI src, rFlagsReg cr) +%{ + predicate(!UseAPX); + match(Set dst (SubI dst src)); + effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); + + format %{ "subl $dst, $src\t# int" %} + ins_encode %{ + __ subl($dst$$Register, $src$$Register); + %} + ins_pipe(ialu_reg_reg); +%} + +instruct subI_rReg_ndd(rRegI dst, rRegI src1, rRegI src2, rFlagsReg cr) +%{ + predicate(UseAPX); + match(Set dst (SubI src1 src2)); + effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); + + format %{ "esubl $dst, $src1, $src2\t# int ndd" %} + ins_encode %{ + __ esubl($dst$$Register, $src1$$Register, $src2$$Register, false); + %} + ins_pipe(ialu_reg_reg); +%} + +instruct subI_rReg_rReg_imm_ndd(rRegI dst, rRegI src1, immI src2, rFlagsReg cr) +%{ + predicate(UseAPX); + match(Set dst (SubI src1 src2)); + effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); + + format %{ "esubl $dst, $src1, $src2\t# int ndd" %} + ins_encode %{ + __ esubl($dst$$Register, $src1$$Register, $src2$$constant, false); + %} + ins_pipe(ialu_reg_reg); +%} + +instruct subI_rReg_mem_imm_ndd(rRegI dst, memory src1, immI src2, rFlagsReg cr) +%{ + predicate(UseAPX); + match(Set dst (SubI (LoadI src1) src2)); + effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); + + format %{ "esubl $dst, $src1, $src2\t# int ndd" %} + ins_encode %{ + __ esubl($dst$$Register, $src1$$Address, $src2$$constant, false); + %} + ins_pipe(ialu_reg_reg); +%} + +instruct subI_rReg_mem(rRegI dst, memory src, rFlagsReg cr) +%{ + predicate(!UseAPX); + match(Set dst (SubI dst (LoadI src))); + effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); + + ins_cost(150); + format %{ "subl $dst, $src\t# int" %} + ins_encode %{ + __ subl($dst$$Register, $src$$Address); + %} + ins_pipe(ialu_reg_mem); +%} + +instruct subI_rReg_rReg_mem_ndd(rRegI dst, rRegI src1, memory src2, rFlagsReg cr) +%{ + predicate(UseAPX); + match(Set dst (SubI src1 (LoadI src2))); + effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); + + ins_cost(150); + format %{ "esubl $dst, $src1, $src2\t# int ndd" %} + ins_encode %{ + __ esubl($dst$$Register, $src1$$Register, $src2$$Address, false); + %} + ins_pipe(ialu_reg_mem); +%} + +instruct subI_rReg_mem_rReg_ndd(rRegI dst, memory src1, rRegI src2, rFlagsReg cr) +%{ + predicate(UseAPX); + match(Set dst (SubI (LoadI src1) src2)); + effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); + + ins_cost(150); + format %{ "esubl $dst, $src1, $src2\t# int ndd" %} + ins_encode %{ + __ esubl($dst$$Register, $src1$$Address, $src2$$Register, false); + %} + ins_pipe(ialu_reg_mem); +%} + +instruct subI_mem_rReg(memory dst, rRegI src, rFlagsReg cr) +%{ + match(Set dst (StoreI dst (SubI (LoadI dst) src))); + effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); + + ins_cost(150); + format %{ "subl $dst, $src\t# int" %} + ins_encode %{ + __ subl($dst$$Address, $src$$Register); + %} + ins_pipe(ialu_mem_reg); +%} + +instruct subL_rReg(rRegL dst, rRegL src, rFlagsReg cr) +%{ + predicate(!UseAPX); + match(Set dst (SubL dst src)); + effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); + + format %{ "subq $dst, $src\t# long" %} + ins_encode %{ + __ subq($dst$$Register, $src$$Register); + %} + ins_pipe(ialu_reg_reg); +%} + +instruct subL_rReg_ndd(rRegL dst, rRegL src1, rRegL src2, rFlagsReg cr) +%{ + predicate(UseAPX); + match(Set dst (SubL src1 src2)); + effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); + + format %{ "esubq $dst, $src1, $src2\t# long ndd" %} + ins_encode %{ + __ esubq($dst$$Register, $src1$$Register, $src2$$Register, false); + %} + ins_pipe(ialu_reg_reg); +%} + +instruct subL_rReg_rReg_imm_ndd(rRegL dst, rRegL src1, immL32 src2, rFlagsReg cr) +%{ + predicate(UseAPX); + match(Set dst (SubL src1 src2)); + effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); + + format %{ "esubq $dst, $src1, $src2\t# long ndd" %} + ins_encode %{ + __ esubq($dst$$Register, $src1$$Register, $src2$$constant, false); + %} + ins_pipe(ialu_reg_reg); +%} + +instruct subL_rReg_mem_imm_ndd(rRegL dst, memory src1, immL32 src2, rFlagsReg cr) +%{ + predicate(UseAPX); + match(Set dst (SubL (LoadL src1) src2)); + effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); + + format %{ "esubq $dst, $src1, $src2\t# long ndd" %} + ins_encode %{ + __ esubq($dst$$Register, $src1$$Address, $src2$$constant, false); + %} + ins_pipe(ialu_reg_reg); +%} + +instruct subL_rReg_mem(rRegL dst, memory src, rFlagsReg cr) +%{ + predicate(!UseAPX); + match(Set dst (SubL dst (LoadL src))); + effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); + + ins_cost(150); + format %{ "subq $dst, $src\t# long" %} + ins_encode %{ + __ subq($dst$$Register, $src$$Address); + %} + ins_pipe(ialu_reg_mem); +%} + +instruct subL_rReg_rReg_mem_ndd(rRegL dst, rRegL src1, memory src2, rFlagsReg cr) +%{ + predicate(UseAPX); + match(Set dst (SubL src1 (LoadL src2))); + effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); + + ins_cost(150); + format %{ "esubq $dst, $src1, $src2\t# long ndd" %} + ins_encode %{ + __ esubq($dst$$Register, $src1$$Register, $src2$$Address, false); + %} + ins_pipe(ialu_reg_mem); +%} + +instruct subL_rReg_mem_rReg_ndd(rRegL dst, memory src1, rRegL src2, rFlagsReg cr) +%{ + predicate(UseAPX); + match(Set dst (SubL (LoadL src1) src2)); + effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); + + ins_cost(150); + format %{ "esubq $dst, $src1, $src2\t# long ndd" %} + ins_encode %{ + __ esubq($dst$$Register, $src1$$Address, $src2$$Register, false); + %} + ins_pipe(ialu_reg_mem); +%} + +instruct subL_mem_rReg(memory dst, rRegL src, rFlagsReg cr) +%{ + match(Set dst (StoreL dst (SubL (LoadL dst) src))); + effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); + + ins_cost(150); + format %{ "subq $dst, $src\t# long" %} + ins_encode %{ + __ subq($dst$$Address, $src$$Register); + %} + ins_pipe(ialu_mem_reg); +%} + +// Subtract from a pointer +// XXX hmpf??? +instruct subP_rReg(rRegP dst, rRegI src, immI_0 zero, rFlagsReg cr) +%{ + match(Set dst (AddP dst (SubI zero src))); + effect(KILL cr); + + format %{ "subq $dst, $src\t# ptr - int" %} + ins_encode %{ + __ subq($dst$$Register, $src$$Register); + %} + ins_pipe(ialu_reg_reg); +%} + +instruct negI_rReg(rRegI dst, immI_0 zero, rFlagsReg cr) +%{ + predicate(!UseAPX); + match(Set dst (SubI zero dst)); + effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag); + + format %{ "negl $dst\t# int" %} + ins_encode %{ + __ negl($dst$$Register); + %} + ins_pipe(ialu_reg); +%} + +instruct negI_rReg_ndd(rRegI dst, rRegI src, immI_0 zero, rFlagsReg cr) +%{ + predicate(UseAPX); + match(Set dst (SubI zero src)); + effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag); + + format %{ "enegl $dst, $src\t# int ndd" %} + ins_encode %{ + __ enegl($dst$$Register, $src$$Register, false); + %} + ins_pipe(ialu_reg); +%} + +instruct negI_rReg_2(rRegI dst, rFlagsReg cr) +%{ + predicate(!UseAPX); + match(Set dst (NegI dst)); + effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag); + + format %{ "negl $dst\t# int" %} + ins_encode %{ + __ negl($dst$$Register); + %} + ins_pipe(ialu_reg); +%} + +instruct negI_rReg_2_ndd(rRegI dst, rRegI src, rFlagsReg cr) +%{ + predicate(UseAPX); + match(Set dst (NegI src)); + effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag); + + format %{ "enegl $dst, $src\t# int ndd" %} + ins_encode %{ + __ enegl($dst$$Register, $src$$Register, false); + %} + ins_pipe(ialu_reg); +%} + +instruct negI_mem(memory dst, immI_0 zero, rFlagsReg cr) +%{ + match(Set dst (StoreI dst (SubI zero (LoadI dst)))); + effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag); + + format %{ "negl $dst\t# int" %} + ins_encode %{ + __ negl($dst$$Address); + %} + ins_pipe(ialu_reg); +%} + +instruct negL_rReg(rRegL dst, immL0 zero, rFlagsReg cr) +%{ + predicate(!UseAPX); + match(Set dst (SubL zero dst)); + effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag); + + format %{ "negq $dst\t# long" %} + ins_encode %{ + __ negq($dst$$Register); + %} + ins_pipe(ialu_reg); +%} + +instruct negL_rReg_ndd(rRegL dst, rRegL src, immL0 zero, rFlagsReg cr) +%{ + predicate(UseAPX); + match(Set dst (SubL zero src)); + effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag); + + format %{ "enegq $dst, $src\t# long ndd" %} + ins_encode %{ + __ enegq($dst$$Register, $src$$Register, false); + %} + ins_pipe(ialu_reg); +%} + +instruct negL_rReg_2(rRegL dst, rFlagsReg cr) +%{ + predicate(!UseAPX); + match(Set dst (NegL dst)); + effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag); + + format %{ "negq $dst\t# int" %} + ins_encode %{ + __ negq($dst$$Register); + %} + ins_pipe(ialu_reg); +%} + +instruct negL_rReg_2_ndd(rRegL dst, rRegL src, rFlagsReg cr) +%{ + predicate(UseAPX); + match(Set dst (NegL src)); + effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag); + + format %{ "enegq $dst, $src\t# long ndd" %} + ins_encode %{ + __ enegq($dst$$Register, $src$$Register, false); + %} + ins_pipe(ialu_reg); +%} + +instruct negL_mem(memory dst, immL0 zero, rFlagsReg cr) +%{ + match(Set dst (StoreL dst (SubL zero (LoadL dst)))); + effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag); + + format %{ "negq $dst\t# long" %} + ins_encode %{ + __ negq($dst$$Address); + %} + ins_pipe(ialu_reg); +%} + +//----------Multiplication/Division Instructions------------------------------- +// Integer Multiplication Instructions +// Multiply Register + +instruct mulI_rReg(rRegI dst, rRegI src, rFlagsReg cr) +%{ + predicate(!UseAPX); + match(Set dst (MulI dst src)); + effect(KILL cr); + + ins_cost(300); + format %{ "imull $dst, $src\t# int" %} + ins_encode %{ + __ imull($dst$$Register, $src$$Register); + %} + ins_pipe(ialu_reg_reg_alu0); +%} + +instruct mulI_rReg_ndd(rRegI dst, rRegI src1, rRegI src2, rFlagsReg cr) +%{ + predicate(UseAPX); + match(Set dst (MulI src1 src2)); + effect(KILL cr); + + ins_cost(300); + format %{ "eimull $dst, $src1, $src2\t# int ndd" %} + ins_encode %{ + __ eimull($dst$$Register, $src1$$Register, $src2$$Register, false); + %} + ins_pipe(ialu_reg_reg_alu0); +%} + +instruct mulI_rReg_imm(rRegI dst, rRegI src, immI imm, rFlagsReg cr) +%{ + match(Set dst (MulI src imm)); + effect(KILL cr); + + ins_cost(300); + format %{ "imull $dst, $src, $imm\t# int" %} + ins_encode %{ + __ imull($dst$$Register, $src$$Register, $imm$$constant); + %} + ins_pipe(ialu_reg_reg_alu0); +%} + +instruct mulI_mem(rRegI dst, memory src, rFlagsReg cr) +%{ + predicate(!UseAPX); + match(Set dst (MulI dst (LoadI src))); + effect(KILL cr); + + ins_cost(350); + format %{ "imull $dst, $src\t# int" %} + ins_encode %{ + __ imull($dst$$Register, $src$$Address); + %} + ins_pipe(ialu_reg_mem_alu0); +%} + +instruct mulI_rReg_rReg_mem_ndd(rRegI dst, rRegI src1, memory src2, rFlagsReg cr) +%{ + predicate(UseAPX); + match(Set dst (MulI src1 (LoadI src2))); + effect(KILL cr); + + ins_cost(350); + format %{ "eimull $dst, $src1, $src2\t# int ndd" %} + ins_encode %{ + __ eimull($dst$$Register, $src1$$Register, $src2$$Address, false); + %} + ins_pipe(ialu_reg_mem_alu0); +%} + +instruct mulI_mem_imm(rRegI dst, memory src, immI imm, rFlagsReg cr) +%{ + match(Set dst (MulI (LoadI src) imm)); + effect(KILL cr); + + ins_cost(300); + format %{ "imull $dst, $src, $imm\t# int" %} + ins_encode %{ + __ imull($dst$$Register, $src$$Address, $imm$$constant); + %} + ins_pipe(ialu_reg_mem_alu0); +%} + +instruct mulAddS2I_rReg(rRegI dst, rRegI src1, rRegI src2, rRegI src3, rFlagsReg cr) +%{ + match(Set dst (MulAddS2I (Binary dst src1) (Binary src2 src3))); + effect(KILL cr, KILL src2); + + expand %{ mulI_rReg(dst, src1, cr); + mulI_rReg(src2, src3, cr); + addI_rReg(dst, src2, cr); %} +%} + +instruct mulL_rReg(rRegL dst, rRegL src, rFlagsReg cr) +%{ + predicate(!UseAPX); + match(Set dst (MulL dst src)); + effect(KILL cr); + + ins_cost(300); + format %{ "imulq $dst, $src\t# long" %} + ins_encode %{ + __ imulq($dst$$Register, $src$$Register); + %} + ins_pipe(ialu_reg_reg_alu0); +%} + +instruct mulL_rReg_ndd(rRegL dst, rRegL src1, rRegL src2, rFlagsReg cr) +%{ + predicate(UseAPX); + match(Set dst (MulL src1 src2)); + effect(KILL cr); + + ins_cost(300); + format %{ "eimulq $dst, $src1, $src2\t# long ndd" %} + ins_encode %{ + __ eimulq($dst$$Register, $src1$$Register, $src2$$Register, false); + %} + ins_pipe(ialu_reg_reg_alu0); +%} + +instruct mulL_rReg_imm(rRegL dst, rRegL src, immL32 imm, rFlagsReg cr) +%{ + match(Set dst (MulL src imm)); + effect(KILL cr); + + ins_cost(300); + format %{ "imulq $dst, $src, $imm\t# long" %} + ins_encode %{ + __ imulq($dst$$Register, $src$$Register, $imm$$constant); + %} + ins_pipe(ialu_reg_reg_alu0); +%} + +instruct mulL_mem(rRegL dst, memory src, rFlagsReg cr) +%{ + predicate(!UseAPX); + match(Set dst (MulL dst (LoadL src))); + effect(KILL cr); + + ins_cost(350); + format %{ "imulq $dst, $src\t# long" %} + ins_encode %{ + __ imulq($dst$$Register, $src$$Address); + %} + ins_pipe(ialu_reg_mem_alu0); +%} + +instruct mulL_rReg_rReg_mem_ndd(rRegL dst, rRegL src1, memory src2, rFlagsReg cr) +%{ + predicate(UseAPX); + match(Set dst (MulL src1 (LoadL src2))); + effect(KILL cr); + + ins_cost(350); + format %{ "eimulq $dst, $src1, $src2 \t# long" %} + ins_encode %{ + __ eimulq($dst$$Register, $src1$$Register, $src2$$Address, false); + %} + ins_pipe(ialu_reg_mem_alu0); +%} + +instruct mulL_mem_imm(rRegL dst, memory src, immL32 imm, rFlagsReg cr) +%{ + match(Set dst (MulL (LoadL src) imm)); + effect(KILL cr); + + ins_cost(300); + format %{ "imulq $dst, $src, $imm\t# long" %} + ins_encode %{ + __ imulq($dst$$Register, $src$$Address, $imm$$constant); + %} + ins_pipe(ialu_reg_mem_alu0); +%} + +instruct mulHiL_rReg(rdx_RegL dst, rRegL src, rax_RegL rax, rFlagsReg cr) +%{ + match(Set dst (MulHiL src rax)); + effect(USE_KILL rax, KILL cr); + + ins_cost(300); + format %{ "imulq RDX:RAX, RAX, $src\t# mulhi" %} + ins_encode %{ + __ imulq($src$$Register); + %} + ins_pipe(ialu_reg_reg_alu0); +%} + +instruct umulHiL_rReg(rdx_RegL dst, rRegL src, rax_RegL rax, rFlagsReg cr) +%{ + match(Set dst (UMulHiL src rax)); + effect(USE_KILL rax, KILL cr); + + ins_cost(300); + format %{ "mulq RDX:RAX, RAX, $src\t# umulhi" %} + ins_encode %{ + __ mulq($src$$Register); + %} + ins_pipe(ialu_reg_reg_alu0); +%} + +instruct divI_rReg(rax_RegI rax, rdx_RegI rdx, no_rax_rdx_RegI div, + rFlagsReg cr) +%{ + match(Set rax (DivI rax div)); + effect(KILL rdx, KILL cr); + + ins_cost(30*100+10*100); // XXX + format %{ "cmpl rax, 0x80000000\t# idiv\n\t" + "jne,s normal\n\t" + "xorl rdx, rdx\n\t" + "cmpl $div, -1\n\t" + "je,s done\n" + "normal: cdql\n\t" + "idivl $div\n" + "done:" %} + ins_encode(cdql_enc(div)); + ins_pipe(ialu_reg_reg_alu0); +%} + +instruct divL_rReg(rax_RegL rax, rdx_RegL rdx, no_rax_rdx_RegL div, + rFlagsReg cr) +%{ + match(Set rax (DivL rax div)); + effect(KILL rdx, KILL cr); + + ins_cost(30*100+10*100); // XXX + format %{ "movq rdx, 0x8000000000000000\t# ldiv\n\t" + "cmpq rax, rdx\n\t" + "jne,s normal\n\t" + "xorl rdx, rdx\n\t" + "cmpq $div, -1\n\t" + "je,s done\n" + "normal: cdqq\n\t" + "idivq $div\n" + "done:" %} + ins_encode(cdqq_enc(div)); + ins_pipe(ialu_reg_reg_alu0); +%} + +instruct udivI_rReg(rax_RegI rax, rdx_RegI rdx, no_rax_rdx_RegI div, rFlagsReg cr) +%{ + match(Set rax (UDivI rax div)); + effect(KILL rdx, KILL cr); + + ins_cost(300); + format %{ "udivl $rax,$rax,$div\t# UDivI\n" %} + ins_encode %{ + __ udivI($rax$$Register, $div$$Register, $rdx$$Register); + %} + ins_pipe(ialu_reg_reg_alu0); +%} + +instruct udivL_rReg(rax_RegL rax, rdx_RegL rdx, no_rax_rdx_RegL div, rFlagsReg cr) +%{ + match(Set rax (UDivL rax div)); + effect(KILL rdx, KILL cr); + + ins_cost(300); + format %{ "udivq $rax,$rax,$div\t# UDivL\n" %} + ins_encode %{ + __ udivL($rax$$Register, $div$$Register, $rdx$$Register); + %} + ins_pipe(ialu_reg_reg_alu0); +%} + +// Integer DIVMOD with Register, both quotient and mod results +instruct divModI_rReg_divmod(rax_RegI rax, rdx_RegI rdx, no_rax_rdx_RegI div, + rFlagsReg cr) +%{ + match(DivModI rax div); + effect(KILL cr); + + ins_cost(30*100+10*100); // XXX + format %{ "cmpl rax, 0x80000000\t# idiv\n\t" + "jne,s normal\n\t" + "xorl rdx, rdx\n\t" + "cmpl $div, -1\n\t" + "je,s done\n" + "normal: cdql\n\t" + "idivl $div\n" + "done:" %} + ins_encode(cdql_enc(div)); + ins_pipe(pipe_slow); +%} + +// Long DIVMOD with Register, both quotient and mod results +instruct divModL_rReg_divmod(rax_RegL rax, rdx_RegL rdx, no_rax_rdx_RegL div, + rFlagsReg cr) +%{ + match(DivModL rax div); + effect(KILL cr); + + ins_cost(30*100+10*100); // XXX + format %{ "movq rdx, 0x8000000000000000\t# ldiv\n\t" + "cmpq rax, rdx\n\t" + "jne,s normal\n\t" + "xorl rdx, rdx\n\t" + "cmpq $div, -1\n\t" + "je,s done\n" + "normal: cdqq\n\t" + "idivq $div\n" + "done:" %} + ins_encode(cdqq_enc(div)); + ins_pipe(pipe_slow); +%} + +// Unsigned integer DIVMOD with Register, both quotient and mod results +instruct udivModI_rReg_divmod(rax_RegI rax, no_rax_rdx_RegI tmp, rdx_RegI rdx, + no_rax_rdx_RegI div, rFlagsReg cr) +%{ + match(UDivModI rax div); + effect(TEMP tmp, KILL cr); + + ins_cost(300); + format %{ "udivl $rax,$rax,$div\t# begin UDivModI\n\t" + "umodl $rdx,$rax,$div\t! using $tmp as TEMP # end UDivModI\n" + %} + ins_encode %{ + __ udivmodI($rax$$Register, $div$$Register, $rdx$$Register, $tmp$$Register); + %} + ins_pipe(pipe_slow); +%} + +// Unsigned long DIVMOD with Register, both quotient and mod results +instruct udivModL_rReg_divmod(rax_RegL rax, no_rax_rdx_RegL tmp, rdx_RegL rdx, + no_rax_rdx_RegL div, rFlagsReg cr) +%{ + match(UDivModL rax div); + effect(TEMP tmp, KILL cr); + + ins_cost(300); + format %{ "udivq $rax,$rax,$div\t# begin UDivModL\n\t" + "umodq $rdx,$rax,$div\t! using $tmp as TEMP # end UDivModL\n" + %} + ins_encode %{ + __ udivmodL($rax$$Register, $div$$Register, $rdx$$Register, $tmp$$Register); + %} + ins_pipe(pipe_slow); +%} + +instruct modI_rReg(rdx_RegI rdx, rax_RegI rax, no_rax_rdx_RegI div, + rFlagsReg cr) +%{ + match(Set rdx (ModI rax div)); + effect(KILL rax, KILL cr); + + ins_cost(300); // XXX + format %{ "cmpl rax, 0x80000000\t# irem\n\t" + "jne,s normal\n\t" + "xorl rdx, rdx\n\t" + "cmpl $div, -1\n\t" + "je,s done\n" + "normal: cdql\n\t" + "idivl $div\n" + "done:" %} + ins_encode(cdql_enc(div)); + ins_pipe(ialu_reg_reg_alu0); +%} + +instruct modL_rReg(rdx_RegL rdx, rax_RegL rax, no_rax_rdx_RegL div, + rFlagsReg cr) +%{ + match(Set rdx (ModL rax div)); + effect(KILL rax, KILL cr); + + ins_cost(300); // XXX + format %{ "movq rdx, 0x8000000000000000\t# lrem\n\t" + "cmpq rax, rdx\n\t" + "jne,s normal\n\t" + "xorl rdx, rdx\n\t" + "cmpq $div, -1\n\t" + "je,s done\n" + "normal: cdqq\n\t" + "idivq $div\n" + "done:" %} + ins_encode(cdqq_enc(div)); + ins_pipe(ialu_reg_reg_alu0); +%} + +instruct umodI_rReg(rdx_RegI rdx, rax_RegI rax, no_rax_rdx_RegI div, rFlagsReg cr) +%{ + match(Set rdx (UModI rax div)); + effect(KILL rax, KILL cr); + + ins_cost(300); + format %{ "umodl $rdx,$rax,$div\t# UModI\n" %} + ins_encode %{ + __ umodI($rax$$Register, $div$$Register, $rdx$$Register); + %} + ins_pipe(ialu_reg_reg_alu0); +%} + +instruct umodL_rReg(rdx_RegL rdx, rax_RegL rax, no_rax_rdx_RegL div, rFlagsReg cr) +%{ + match(Set rdx (UModL rax div)); + effect(KILL rax, KILL cr); + + ins_cost(300); + format %{ "umodq $rdx,$rax,$div\t# UModL\n" %} + ins_encode %{ + __ umodL($rax$$Register, $div$$Register, $rdx$$Register); + %} + ins_pipe(ialu_reg_reg_alu0); +%} + +// Integer Shift Instructions +// Shift Left by one, two, three +instruct salI_rReg_immI2(rRegI dst, immI2 shift, rFlagsReg cr) +%{ + predicate(!UseAPX); + match(Set dst (LShiftI dst shift)); + effect(KILL cr); + + format %{ "sall $dst, $shift" %} + ins_encode %{ + __ sall($dst$$Register, $shift$$constant); + %} + ins_pipe(ialu_reg); +%} + +// Shift Left by one, two, three +instruct salI_rReg_immI2_ndd(rRegI dst, rRegI src, immI2 shift, rFlagsReg cr) +%{ + predicate(UseAPX); + match(Set dst (LShiftI src shift)); + effect(KILL cr); + + format %{ "esall $dst, $src, $shift\t# int(ndd)" %} + ins_encode %{ + __ esall($dst$$Register, $src$$Register, $shift$$constant, false); + %} + ins_pipe(ialu_reg); +%} + +// Shift Left by 8-bit immediate +instruct salI_rReg_imm(rRegI dst, immI8 shift, rFlagsReg cr) +%{ + predicate(!UseAPX); + match(Set dst (LShiftI dst shift)); + effect(KILL cr); + + format %{ "sall $dst, $shift" %} + ins_encode %{ + __ sall($dst$$Register, $shift$$constant); + %} + ins_pipe(ialu_reg); +%} + +// Shift Left by 8-bit immediate +instruct salI_rReg_imm_ndd(rRegI dst, rRegI src, immI8 shift, rFlagsReg cr) +%{ + predicate(UseAPX); + match(Set dst (LShiftI src shift)); + effect(KILL cr); + + format %{ "esall $dst, $src, $shift\t# int (ndd)" %} + ins_encode %{ + __ esall($dst$$Register, $src$$Register, $shift$$constant, false); + %} + ins_pipe(ialu_reg); +%} + +instruct salI_rReg_mem_imm_ndd(rRegI dst, memory src, immI8 shift, rFlagsReg cr) +%{ + predicate(UseAPX); + match(Set dst (LShiftI (LoadI src) shift)); + effect(KILL cr); + + format %{ "esall $dst, $src, $shift\t# int (ndd)" %} + ins_encode %{ + __ esall($dst$$Register, $src$$Address, $shift$$constant, false); + %} + ins_pipe(ialu_reg); +%} + +// Shift Left by 8-bit immediate +instruct salI_mem_imm(memory dst, immI8 shift, rFlagsReg cr) +%{ + match(Set dst (StoreI dst (LShiftI (LoadI dst) shift))); + effect(KILL cr); + + format %{ "sall $dst, $shift" %} + ins_encode %{ + __ sall($dst$$Address, $shift$$constant); + %} + ins_pipe(ialu_mem_imm); +%} + +// Shift Left by variable +instruct salI_rReg_CL(rRegI dst, rcx_RegI shift, rFlagsReg cr) +%{ + predicate(!VM_Version::supports_bmi2()); + match(Set dst (LShiftI dst shift)); + effect(KILL cr); + + format %{ "sall $dst, $shift" %} + ins_encode %{ + __ sall($dst$$Register); + %} + ins_pipe(ialu_reg_reg); +%} + +// Shift Left by variable +instruct salI_mem_CL(memory dst, rcx_RegI shift, rFlagsReg cr) +%{ + predicate(!VM_Version::supports_bmi2()); + match(Set dst (StoreI dst (LShiftI (LoadI dst) shift))); + effect(KILL cr); + + format %{ "sall $dst, $shift" %} + ins_encode %{ + __ sall($dst$$Address); + %} + ins_pipe(ialu_mem_reg); +%} + +instruct salI_rReg_rReg(rRegI dst, rRegI src, rRegI shift) +%{ + predicate(VM_Version::supports_bmi2()); + match(Set dst (LShiftI src shift)); + + format %{ "shlxl $dst, $src, $shift" %} + ins_encode %{ + __ shlxl($dst$$Register, $src$$Register, $shift$$Register); + %} + ins_pipe(ialu_reg_reg); +%} + +instruct salI_mem_rReg(rRegI dst, memory src, rRegI shift) +%{ + predicate(VM_Version::supports_bmi2()); + match(Set dst (LShiftI (LoadI src) shift)); + ins_cost(175); + format %{ "shlxl $dst, $src, $shift" %} + ins_encode %{ + __ shlxl($dst$$Register, $src$$Address, $shift$$Register); + %} + ins_pipe(ialu_reg_mem); +%} + +// Arithmetic Shift Right by 8-bit immediate +instruct sarI_rReg_imm(rRegI dst, immI8 shift, rFlagsReg cr) +%{ + predicate(!UseAPX); + match(Set dst (RShiftI dst shift)); + effect(KILL cr); + + format %{ "sarl $dst, $shift" %} + ins_encode %{ + __ sarl($dst$$Register, $shift$$constant); + %} + ins_pipe(ialu_mem_imm); +%} + +// Arithmetic Shift Right by 8-bit immediate +instruct sarI_rReg_imm_ndd(rRegI dst, rRegI src, immI8 shift, rFlagsReg cr) +%{ + predicate(UseAPX); + match(Set dst (RShiftI src shift)); + effect(KILL cr); + + format %{ "esarl $dst, $src, $shift\t# int (ndd)" %} + ins_encode %{ + __ esarl($dst$$Register, $src$$Register, $shift$$constant, false); + %} + ins_pipe(ialu_mem_imm); +%} + +instruct sarI_rReg_mem_imm_ndd(rRegI dst, memory src, immI8 shift, rFlagsReg cr) +%{ + predicate(UseAPX); + match(Set dst (RShiftI (LoadI src) shift)); + effect(KILL cr); + + format %{ "esarl $dst, $src, $shift\t# int (ndd)" %} + ins_encode %{ + __ esarl($dst$$Register, $src$$Address, $shift$$constant, false); + %} + ins_pipe(ialu_mem_imm); +%} + +// Arithmetic Shift Right by 8-bit immediate +instruct sarI_mem_imm(memory dst, immI8 shift, rFlagsReg cr) +%{ + match(Set dst (StoreI dst (RShiftI (LoadI dst) shift))); + effect(KILL cr); + + format %{ "sarl $dst, $shift" %} + ins_encode %{ + __ sarl($dst$$Address, $shift$$constant); + %} + ins_pipe(ialu_mem_imm); +%} + +// Arithmetic Shift Right by variable +instruct sarI_rReg_CL(rRegI dst, rcx_RegI shift, rFlagsReg cr) +%{ + predicate(!VM_Version::supports_bmi2()); + match(Set dst (RShiftI dst shift)); + effect(KILL cr); + + format %{ "sarl $dst, $shift" %} + ins_encode %{ + __ sarl($dst$$Register); + %} + ins_pipe(ialu_reg_reg); +%} + +// Arithmetic Shift Right by variable +instruct sarI_mem_CL(memory dst, rcx_RegI shift, rFlagsReg cr) +%{ + predicate(!VM_Version::supports_bmi2()); + match(Set dst (StoreI dst (RShiftI (LoadI dst) shift))); + effect(KILL cr); + + format %{ "sarl $dst, $shift" %} + ins_encode %{ + __ sarl($dst$$Address); + %} + ins_pipe(ialu_mem_reg); +%} + +instruct sarI_rReg_rReg(rRegI dst, rRegI src, rRegI shift) +%{ + predicate(VM_Version::supports_bmi2()); + match(Set dst (RShiftI src shift)); + + format %{ "sarxl $dst, $src, $shift" %} + ins_encode %{ + __ sarxl($dst$$Register, $src$$Register, $shift$$Register); + %} + ins_pipe(ialu_reg_reg); +%} + +instruct sarI_mem_rReg(rRegI dst, memory src, rRegI shift) +%{ + predicate(VM_Version::supports_bmi2()); + match(Set dst (RShiftI (LoadI src) shift)); + ins_cost(175); + format %{ "sarxl $dst, $src, $shift" %} + ins_encode %{ + __ sarxl($dst$$Register, $src$$Address, $shift$$Register); + %} + ins_pipe(ialu_reg_mem); +%} + +// Logical Shift Right by 8-bit immediate +instruct shrI_rReg_imm(rRegI dst, immI8 shift, rFlagsReg cr) +%{ + predicate(!UseAPX); + match(Set dst (URShiftI dst shift)); + effect(KILL cr); + + format %{ "shrl $dst, $shift" %} + ins_encode %{ + __ shrl($dst$$Register, $shift$$constant); + %} + ins_pipe(ialu_reg); +%} + +// Logical Shift Right by 8-bit immediate +instruct shrI_rReg_imm_ndd(rRegI dst, rRegI src, immI8 shift, rFlagsReg cr) +%{ + predicate(UseAPX); + match(Set dst (URShiftI src shift)); + effect(KILL cr); + + format %{ "eshrl $dst, $src, $shift\t # int (ndd)" %} + ins_encode %{ + __ eshrl($dst$$Register, $src$$Register, $shift$$constant, false); + %} + ins_pipe(ialu_reg); +%} + +instruct shrI_rReg_mem_imm_ndd(rRegI dst, memory src, immI8 shift, rFlagsReg cr) +%{ + predicate(UseAPX); + match(Set dst (URShiftI (LoadI src) shift)); + effect(KILL cr); + + format %{ "eshrl $dst, $src, $shift\t # int (ndd)" %} + ins_encode %{ + __ eshrl($dst$$Register, $src$$Address, $shift$$constant, false); + %} + ins_pipe(ialu_reg); +%} + +// Logical Shift Right by 8-bit immediate +instruct shrI_mem_imm(memory dst, immI8 shift, rFlagsReg cr) +%{ + match(Set dst (StoreI dst (URShiftI (LoadI dst) shift))); + effect(KILL cr); + + format %{ "shrl $dst, $shift" %} + ins_encode %{ + __ shrl($dst$$Address, $shift$$constant); + %} + ins_pipe(ialu_mem_imm); +%} + +// Logical Shift Right by variable +instruct shrI_rReg_CL(rRegI dst, rcx_RegI shift, rFlagsReg cr) +%{ + predicate(!VM_Version::supports_bmi2()); + match(Set dst (URShiftI dst shift)); + effect(KILL cr); + + format %{ "shrl $dst, $shift" %} + ins_encode %{ + __ shrl($dst$$Register); + %} + ins_pipe(ialu_reg_reg); +%} + +// Logical Shift Right by variable +instruct shrI_mem_CL(memory dst, rcx_RegI shift, rFlagsReg cr) +%{ + predicate(!VM_Version::supports_bmi2()); + match(Set dst (StoreI dst (URShiftI (LoadI dst) shift))); + effect(KILL cr); + + format %{ "shrl $dst, $shift" %} + ins_encode %{ + __ shrl($dst$$Address); + %} + ins_pipe(ialu_mem_reg); +%} + +instruct shrI_rReg_rReg(rRegI dst, rRegI src, rRegI shift) +%{ + predicate(VM_Version::supports_bmi2()); + match(Set dst (URShiftI src shift)); + + format %{ "shrxl $dst, $src, $shift" %} + ins_encode %{ + __ shrxl($dst$$Register, $src$$Register, $shift$$Register); + %} + ins_pipe(ialu_reg_reg); +%} + +instruct shrI_mem_rReg(rRegI dst, memory src, rRegI shift) +%{ + predicate(VM_Version::supports_bmi2()); + match(Set dst (URShiftI (LoadI src) shift)); + ins_cost(175); + format %{ "shrxl $dst, $src, $shift" %} + ins_encode %{ + __ shrxl($dst$$Register, $src$$Address, $shift$$Register); + %} + ins_pipe(ialu_reg_mem); +%} + +// Long Shift Instructions +// Shift Left by one, two, three +instruct salL_rReg_immI2(rRegL dst, immI2 shift, rFlagsReg cr) +%{ + predicate(!UseAPX); + match(Set dst (LShiftL dst shift)); + effect(KILL cr); + + format %{ "salq $dst, $shift" %} + ins_encode %{ + __ salq($dst$$Register, $shift$$constant); + %} + ins_pipe(ialu_reg); +%} + +// Shift Left by one, two, three +instruct salL_rReg_immI2_ndd(rRegL dst, rRegL src, immI2 shift, rFlagsReg cr) +%{ + predicate(UseAPX); + match(Set dst (LShiftL src shift)); + effect(KILL cr); + + format %{ "esalq $dst, $src, $shift\t# long (ndd)" %} + ins_encode %{ + __ esalq($dst$$Register, $src$$Register, $shift$$constant, false); + %} + ins_pipe(ialu_reg); +%} + +// Shift Left by 8-bit immediate +instruct salL_rReg_imm(rRegL dst, immI8 shift, rFlagsReg cr) +%{ + predicate(!UseAPX); + match(Set dst (LShiftL dst shift)); + effect(KILL cr); + + format %{ "salq $dst, $shift" %} + ins_encode %{ + __ salq($dst$$Register, $shift$$constant); + %} + ins_pipe(ialu_reg); +%} + +// Shift Left by 8-bit immediate +instruct salL_rReg_imm_ndd(rRegL dst, rRegL src, immI8 shift, rFlagsReg cr) +%{ + predicate(UseAPX); + match(Set dst (LShiftL src shift)); + effect(KILL cr); + + format %{ "esalq $dst, $src, $shift\t# long (ndd)" %} + ins_encode %{ + __ esalq($dst$$Register, $src$$Register, $shift$$constant, false); + %} + ins_pipe(ialu_reg); +%} + +instruct salL_rReg_mem_imm_ndd(rRegL dst, memory src, immI8 shift, rFlagsReg cr) +%{ + predicate(UseAPX); + match(Set dst (LShiftL (LoadL src) shift)); + effect(KILL cr); + + format %{ "esalq $dst, $src, $shift\t# long (ndd)" %} + ins_encode %{ + __ esalq($dst$$Register, $src$$Address, $shift$$constant, false); + %} + ins_pipe(ialu_reg); +%} + +// Shift Left by 8-bit immediate +instruct salL_mem_imm(memory dst, immI8 shift, rFlagsReg cr) +%{ + match(Set dst (StoreL dst (LShiftL (LoadL dst) shift))); + effect(KILL cr); + + format %{ "salq $dst, $shift" %} + ins_encode %{ + __ salq($dst$$Address, $shift$$constant); + %} + ins_pipe(ialu_mem_imm); +%} + +// Shift Left by variable +instruct salL_rReg_CL(rRegL dst, rcx_RegI shift, rFlagsReg cr) +%{ + predicate(!VM_Version::supports_bmi2()); + match(Set dst (LShiftL dst shift)); + effect(KILL cr); + + format %{ "salq $dst, $shift" %} + ins_encode %{ + __ salq($dst$$Register); + %} + ins_pipe(ialu_reg_reg); +%} + +// Shift Left by variable +instruct salL_mem_CL(memory dst, rcx_RegI shift, rFlagsReg cr) +%{ + predicate(!VM_Version::supports_bmi2()); + match(Set dst (StoreL dst (LShiftL (LoadL dst) shift))); + effect(KILL cr); + + format %{ "salq $dst, $shift" %} + ins_encode %{ + __ salq($dst$$Address); + %} + ins_pipe(ialu_mem_reg); +%} + +instruct salL_rReg_rReg(rRegL dst, rRegL src, rRegI shift) +%{ + predicate(VM_Version::supports_bmi2()); + match(Set dst (LShiftL src shift)); + + format %{ "shlxq $dst, $src, $shift" %} + ins_encode %{ + __ shlxq($dst$$Register, $src$$Register, $shift$$Register); + %} + ins_pipe(ialu_reg_reg); +%} + +instruct salL_mem_rReg(rRegL dst, memory src, rRegI shift) +%{ + predicate(VM_Version::supports_bmi2()); + match(Set dst (LShiftL (LoadL src) shift)); + ins_cost(175); + format %{ "shlxq $dst, $src, $shift" %} + ins_encode %{ + __ shlxq($dst$$Register, $src$$Address, $shift$$Register); + %} + ins_pipe(ialu_reg_mem); +%} + +// Arithmetic Shift Right by 8-bit immediate +instruct sarL_rReg_imm(rRegL dst, immI shift, rFlagsReg cr) +%{ + predicate(!UseAPX); + match(Set dst (RShiftL dst shift)); + effect(KILL cr); + + format %{ "sarq $dst, $shift" %} + ins_encode %{ + __ sarq($dst$$Register, (unsigned char)($shift$$constant & 0x3F)); + %} + ins_pipe(ialu_mem_imm); +%} + +// Arithmetic Shift Right by 8-bit immediate +instruct sarL_rReg_imm_ndd(rRegL dst, rRegL src, immI shift, rFlagsReg cr) +%{ + predicate(UseAPX); + match(Set dst (RShiftL src shift)); + effect(KILL cr); + + format %{ "esarq $dst, $src, $shift\t# long (ndd)" %} + ins_encode %{ + __ esarq($dst$$Register, $src$$Register, (unsigned char)($shift$$constant & 0x3F), false); + %} + ins_pipe(ialu_mem_imm); +%} + +instruct sarL_rReg_mem_imm_ndd(rRegL dst, memory src, immI shift, rFlagsReg cr) +%{ + predicate(UseAPX); + match(Set dst (RShiftL (LoadL src) shift)); + effect(KILL cr); + + format %{ "esarq $dst, $src, $shift\t# long (ndd)" %} + ins_encode %{ + __ esarq($dst$$Register, $src$$Address, (unsigned char)($shift$$constant & 0x3F), false); + %} + ins_pipe(ialu_mem_imm); +%} + +// Arithmetic Shift Right by 8-bit immediate +instruct sarL_mem_imm(memory dst, immI shift, rFlagsReg cr) +%{ + match(Set dst (StoreL dst (RShiftL (LoadL dst) shift))); + effect(KILL cr); + + format %{ "sarq $dst, $shift" %} + ins_encode %{ + __ sarq($dst$$Address, (unsigned char)($shift$$constant & 0x3F)); + %} + ins_pipe(ialu_mem_imm); +%} + +// Arithmetic Shift Right by variable +instruct sarL_rReg_CL(rRegL dst, rcx_RegI shift, rFlagsReg cr) +%{ + predicate(!VM_Version::supports_bmi2()); + match(Set dst (RShiftL dst shift)); + effect(KILL cr); + + format %{ "sarq $dst, $shift" %} + ins_encode %{ + __ sarq($dst$$Register); + %} + ins_pipe(ialu_reg_reg); +%} + +// Arithmetic Shift Right by variable +instruct sarL_mem_CL(memory dst, rcx_RegI shift, rFlagsReg cr) +%{ + predicate(!VM_Version::supports_bmi2()); + match(Set dst (StoreL dst (RShiftL (LoadL dst) shift))); + effect(KILL cr); + + format %{ "sarq $dst, $shift" %} + ins_encode %{ + __ sarq($dst$$Address); + %} + ins_pipe(ialu_mem_reg); +%} + +instruct sarL_rReg_rReg(rRegL dst, rRegL src, rRegI shift) +%{ + predicate(VM_Version::supports_bmi2()); + match(Set dst (RShiftL src shift)); + + format %{ "sarxq $dst, $src, $shift" %} + ins_encode %{ + __ sarxq($dst$$Register, $src$$Register, $shift$$Register); + %} + ins_pipe(ialu_reg_reg); +%} + +instruct sarL_mem_rReg(rRegL dst, memory src, rRegI shift) +%{ + predicate(VM_Version::supports_bmi2()); + match(Set dst (RShiftL (LoadL src) shift)); + ins_cost(175); + format %{ "sarxq $dst, $src, $shift" %} + ins_encode %{ + __ sarxq($dst$$Register, $src$$Address, $shift$$Register); + %} + ins_pipe(ialu_reg_mem); +%} + +// Logical Shift Right by 8-bit immediate +instruct shrL_rReg_imm(rRegL dst, immI8 shift, rFlagsReg cr) +%{ + predicate(!UseAPX); + match(Set dst (URShiftL dst shift)); + effect(KILL cr); + + format %{ "shrq $dst, $shift" %} + ins_encode %{ + __ shrq($dst$$Register, $shift$$constant); + %} + ins_pipe(ialu_reg); +%} + +// Logical Shift Right by 8-bit immediate +instruct shrL_rReg_imm_ndd(rRegL dst, rRegL src, immI8 shift, rFlagsReg cr) +%{ + predicate(UseAPX); + match(Set dst (URShiftL src shift)); + effect(KILL cr); + + format %{ "eshrq $dst, $src, $shift\t# long (ndd)" %} + ins_encode %{ + __ eshrq($dst$$Register, $src$$Register, $shift$$constant, false); + %} + ins_pipe(ialu_reg); +%} + +instruct shrL_rReg_mem_imm_ndd(rRegL dst, memory src, immI8 shift, rFlagsReg cr) +%{ + predicate(UseAPX); + match(Set dst (URShiftL (LoadL src) shift)); + effect(KILL cr); + + format %{ "eshrq $dst, $src, $shift\t# long (ndd)" %} + ins_encode %{ + __ eshrq($dst$$Register, $src$$Address, $shift$$constant, false); + %} + ins_pipe(ialu_reg); +%} + +// Logical Shift Right by 8-bit immediate +instruct shrL_mem_imm(memory dst, immI8 shift, rFlagsReg cr) +%{ + match(Set dst (StoreL dst (URShiftL (LoadL dst) shift))); + effect(KILL cr); + + format %{ "shrq $dst, $shift" %} + ins_encode %{ + __ shrq($dst$$Address, $shift$$constant); + %} + ins_pipe(ialu_mem_imm); +%} + +// Logical Shift Right by variable +instruct shrL_rReg_CL(rRegL dst, rcx_RegI shift, rFlagsReg cr) +%{ + predicate(!VM_Version::supports_bmi2()); + match(Set dst (URShiftL dst shift)); + effect(KILL cr); + + format %{ "shrq $dst, $shift" %} + ins_encode %{ + __ shrq($dst$$Register); + %} + ins_pipe(ialu_reg_reg); +%} + +// Logical Shift Right by variable +instruct shrL_mem_CL(memory dst, rcx_RegI shift, rFlagsReg cr) +%{ + predicate(!VM_Version::supports_bmi2()); + match(Set dst (StoreL dst (URShiftL (LoadL dst) shift))); + effect(KILL cr); + + format %{ "shrq $dst, $shift" %} + ins_encode %{ + __ shrq($dst$$Address); + %} + ins_pipe(ialu_mem_reg); +%} + +instruct shrL_rReg_rReg(rRegL dst, rRegL src, rRegI shift) +%{ + predicate(VM_Version::supports_bmi2()); + match(Set dst (URShiftL src shift)); + + format %{ "shrxq $dst, $src, $shift" %} + ins_encode %{ + __ shrxq($dst$$Register, $src$$Register, $shift$$Register); + %} + ins_pipe(ialu_reg_reg); +%} + +instruct shrL_mem_rReg(rRegL dst, memory src, rRegI shift) +%{ + predicate(VM_Version::supports_bmi2()); + match(Set dst (URShiftL (LoadL src) shift)); + ins_cost(175); + format %{ "shrxq $dst, $src, $shift" %} + ins_encode %{ + __ shrxq($dst$$Register, $src$$Address, $shift$$Register); + %} + ins_pipe(ialu_reg_mem); +%} + +// Logical Shift Right by 24, followed by Arithmetic Shift Left by 24. +// This idiom is used by the compiler for the i2b bytecode. +instruct i2b(rRegI dst, rRegI src, immI_24 twentyfour) +%{ + match(Set dst (RShiftI (LShiftI src twentyfour) twentyfour)); + + format %{ "movsbl $dst, $src\t# i2b" %} + ins_encode %{ + __ movsbl($dst$$Register, $src$$Register); + %} + ins_pipe(ialu_reg_reg); +%} + +// Logical Shift Right by 16, followed by Arithmetic Shift Left by 16. +// This idiom is used by the compiler the i2s bytecode. +instruct i2s(rRegI dst, rRegI src, immI_16 sixteen) +%{ + match(Set dst (RShiftI (LShiftI src sixteen) sixteen)); + + format %{ "movswl $dst, $src\t# i2s" %} + ins_encode %{ + __ movswl($dst$$Register, $src$$Register); + %} + ins_pipe(ialu_reg_reg); +%} + +// ROL/ROR instructions + +// Rotate left by constant. +instruct rolI_immI8_legacy(rRegI dst, immI8 shift, rFlagsReg cr) +%{ + predicate(!VM_Version::supports_bmi2() && n->bottom_type()->basic_type() == T_INT); + match(Set dst (RotateLeft dst shift)); + effect(KILL cr); + format %{ "roll $dst, $shift" %} + ins_encode %{ + __ roll($dst$$Register, $shift$$constant); + %} + ins_pipe(ialu_reg); +%} + +instruct rolI_immI8(rRegI dst, rRegI src, immI8 shift) +%{ + predicate(!UseAPX && VM_Version::supports_bmi2() && n->bottom_type()->basic_type() == T_INT); + match(Set dst (RotateLeft src shift)); + format %{ "rolxl $dst, $src, $shift" %} + ins_encode %{ + int shift = 32 - ($shift$$constant & 31); + __ rorxl($dst$$Register, $src$$Register, shift); + %} + ins_pipe(ialu_reg_reg); +%} + +instruct rolI_mem_immI8(rRegI dst, memory src, immI8 shift) +%{ + predicate(VM_Version::supports_bmi2() && n->bottom_type()->basic_type() == T_INT); + match(Set dst (RotateLeft (LoadI src) shift)); + ins_cost(175); + format %{ "rolxl $dst, $src, $shift" %} + ins_encode %{ + int shift = 32 - ($shift$$constant & 31); + __ rorxl($dst$$Register, $src$$Address, shift); + %} + ins_pipe(ialu_reg_mem); +%} + +// Rotate Left by variable +instruct rolI_rReg_Var(rRegI dst, rcx_RegI shift, rFlagsReg cr) +%{ + predicate(!UseAPX && n->bottom_type()->basic_type() == T_INT); + match(Set dst (RotateLeft dst shift)); + effect(KILL cr); + format %{ "roll $dst, $shift" %} + ins_encode %{ + __ roll($dst$$Register); + %} + ins_pipe(ialu_reg_reg); +%} + +// Rotate Left by variable +instruct rolI_rReg_Var_ndd(rRegI dst, rRegI src, rcx_RegI shift, rFlagsReg cr) +%{ + predicate(UseAPX && n->bottom_type()->basic_type() == T_INT); + match(Set dst (RotateLeft src shift)); + effect(KILL cr); + + format %{ "eroll $dst, $src, $shift\t# rotate left (int ndd)" %} + ins_encode %{ + __ eroll($dst$$Register, $src$$Register, false); + %} + ins_pipe(ialu_reg_reg); +%} + +// Rotate Right by constant. +instruct rorI_immI8_legacy(rRegI dst, immI8 shift, rFlagsReg cr) +%{ + predicate(!VM_Version::supports_bmi2() && n->bottom_type()->basic_type() == T_INT); + match(Set dst (RotateRight dst shift)); + effect(KILL cr); + format %{ "rorl $dst, $shift" %} + ins_encode %{ + __ rorl($dst$$Register, $shift$$constant); + %} + ins_pipe(ialu_reg); +%} + +// Rotate Right by constant. +instruct rorI_immI8(rRegI dst, rRegI src, immI8 shift) +%{ + predicate(!UseAPX && VM_Version::supports_bmi2() && n->bottom_type()->basic_type() == T_INT); + match(Set dst (RotateRight src shift)); + format %{ "rorxl $dst, $src, $shift" %} + ins_encode %{ + __ rorxl($dst$$Register, $src$$Register, $shift$$constant); + %} + ins_pipe(ialu_reg_reg); +%} + +instruct rorI_mem_immI8(rRegI dst, memory src, immI8 shift) +%{ + predicate(VM_Version::supports_bmi2() && n->bottom_type()->basic_type() == T_INT); + match(Set dst (RotateRight (LoadI src) shift)); + ins_cost(175); + format %{ "rorxl $dst, $src, $shift" %} + ins_encode %{ + __ rorxl($dst$$Register, $src$$Address, $shift$$constant); + %} + ins_pipe(ialu_reg_mem); +%} + +// Rotate Right by variable +instruct rorI_rReg_Var(rRegI dst, rcx_RegI shift, rFlagsReg cr) +%{ + predicate(!UseAPX && n->bottom_type()->basic_type() == T_INT); + match(Set dst (RotateRight dst shift)); + effect(KILL cr); + format %{ "rorl $dst, $shift" %} + ins_encode %{ + __ rorl($dst$$Register); + %} + ins_pipe(ialu_reg_reg); +%} + +// Rotate Right by variable +instruct rorI_rReg_Var_ndd(rRegI dst, rRegI src, rcx_RegI shift, rFlagsReg cr) +%{ + predicate(UseAPX && n->bottom_type()->basic_type() == T_INT); + match(Set dst (RotateRight src shift)); + effect(KILL cr); + + format %{ "erorl $dst, $src, $shift\t# rotate right(int ndd)" %} + ins_encode %{ + __ erorl($dst$$Register, $src$$Register, false); + %} + ins_pipe(ialu_reg_reg); +%} + +// Rotate Left by constant. +instruct rolL_immI8_legacy(rRegL dst, immI8 shift, rFlagsReg cr) +%{ + predicate(!VM_Version::supports_bmi2() && n->bottom_type()->basic_type() == T_LONG); + match(Set dst (RotateLeft dst shift)); + effect(KILL cr); + format %{ "rolq $dst, $shift" %} + ins_encode %{ + __ rolq($dst$$Register, $shift$$constant); + %} + ins_pipe(ialu_reg); +%} + +instruct rolL_immI8(rRegL dst, rRegL src, immI8 shift) +%{ + predicate(!UseAPX && VM_Version::supports_bmi2() && n->bottom_type()->basic_type() == T_LONG); + match(Set dst (RotateLeft src shift)); + format %{ "rolxq $dst, $src, $shift" %} + ins_encode %{ + int shift = 64 - ($shift$$constant & 63); + __ rorxq($dst$$Register, $src$$Register, shift); + %} + ins_pipe(ialu_reg_reg); +%} + +instruct rolL_mem_immI8(rRegL dst, memory src, immI8 shift) +%{ + predicate(VM_Version::supports_bmi2() && n->bottom_type()->basic_type() == T_LONG); + match(Set dst (RotateLeft (LoadL src) shift)); + ins_cost(175); + format %{ "rolxq $dst, $src, $shift" %} + ins_encode %{ + int shift = 64 - ($shift$$constant & 63); + __ rorxq($dst$$Register, $src$$Address, shift); + %} + ins_pipe(ialu_reg_mem); +%} + +// Rotate Left by variable +instruct rolL_rReg_Var(rRegL dst, rcx_RegI shift, rFlagsReg cr) +%{ + predicate(!UseAPX && n->bottom_type()->basic_type() == T_LONG); + match(Set dst (RotateLeft dst shift)); + effect(KILL cr); + format %{ "rolq $dst, $shift" %} + ins_encode %{ + __ rolq($dst$$Register); + %} + ins_pipe(ialu_reg_reg); +%} + +// Rotate Left by variable +instruct rolL_rReg_Var_ndd(rRegL dst, rRegL src, rcx_RegI shift, rFlagsReg cr) +%{ + predicate(UseAPX && n->bottom_type()->basic_type() == T_LONG); + match(Set dst (RotateLeft src shift)); + effect(KILL cr); + + format %{ "erolq $dst, $src, $shift\t# rotate left(long ndd)" %} + ins_encode %{ + __ erolq($dst$$Register, $src$$Register, false); + %} + ins_pipe(ialu_reg_reg); +%} + +// Rotate Right by constant. +instruct rorL_immI8_legacy(rRegL dst, immI8 shift, rFlagsReg cr) +%{ + predicate(!VM_Version::supports_bmi2() && n->bottom_type()->basic_type() == T_LONG); + match(Set dst (RotateRight dst shift)); + effect(KILL cr); + format %{ "rorq $dst, $shift" %} + ins_encode %{ + __ rorq($dst$$Register, $shift$$constant); + %} + ins_pipe(ialu_reg); +%} + +// Rotate Right by constant +instruct rorL_immI8(rRegL dst, rRegL src, immI8 shift) +%{ + predicate(VM_Version::supports_bmi2() && n->bottom_type()->basic_type() == T_LONG); + match(Set dst (RotateRight src shift)); + format %{ "rorxq $dst, $src, $shift" %} + ins_encode %{ + __ rorxq($dst$$Register, $src$$Register, $shift$$constant); + %} + ins_pipe(ialu_reg_reg); +%} + +instruct rorL_mem_immI8(rRegL dst, memory src, immI8 shift) +%{ + predicate(VM_Version::supports_bmi2() && n->bottom_type()->basic_type() == T_LONG); + match(Set dst (RotateRight (LoadL src) shift)); + ins_cost(175); + format %{ "rorxq $dst, $src, $shift" %} + ins_encode %{ + __ rorxq($dst$$Register, $src$$Address, $shift$$constant); + %} + ins_pipe(ialu_reg_mem); +%} + +// Rotate Right by variable +instruct rorL_rReg_Var(rRegL dst, rcx_RegI shift, rFlagsReg cr) +%{ + predicate(!UseAPX && n->bottom_type()->basic_type() == T_LONG); + match(Set dst (RotateRight dst shift)); + effect(KILL cr); + format %{ "rorq $dst, $shift" %} + ins_encode %{ + __ rorq($dst$$Register); + %} + ins_pipe(ialu_reg_reg); +%} + +// Rotate Right by variable +instruct rorL_rReg_Var_ndd(rRegL dst, rRegL src, rcx_RegI shift, rFlagsReg cr) +%{ + predicate(UseAPX && n->bottom_type()->basic_type() == T_LONG); + match(Set dst (RotateRight src shift)); + effect(KILL cr); + + format %{ "erorq $dst, $src, $shift\t# rotate right(long ndd)" %} + ins_encode %{ + __ erorq($dst$$Register, $src$$Register, false); + %} + ins_pipe(ialu_reg_reg); +%} + +//----------------------------- CompressBits/ExpandBits ------------------------ + +instruct compressBitsL_reg(rRegL dst, rRegL src, rRegL mask) %{ + predicate(n->bottom_type()->isa_long()); + match(Set dst (CompressBits src mask)); + format %{ "pextq $dst, $src, $mask\t! parallel bit extract" %} + ins_encode %{ + __ pextq($dst$$Register, $src$$Register, $mask$$Register); + %} + ins_pipe( pipe_slow ); +%} + +instruct expandBitsL_reg(rRegL dst, rRegL src, rRegL mask) %{ + predicate(n->bottom_type()->isa_long()); + match(Set dst (ExpandBits src mask)); + format %{ "pdepq $dst, $src, $mask\t! parallel bit deposit" %} + ins_encode %{ + __ pdepq($dst$$Register, $src$$Register, $mask$$Register); + %} + ins_pipe( pipe_slow ); +%} + +instruct compressBitsL_mem(rRegL dst, rRegL src, memory mask) %{ + predicate(n->bottom_type()->isa_long()); + match(Set dst (CompressBits src (LoadL mask))); + format %{ "pextq $dst, $src, $mask\t! parallel bit extract" %} + ins_encode %{ + __ pextq($dst$$Register, $src$$Register, $mask$$Address); + %} + ins_pipe( pipe_slow ); +%} + +instruct expandBitsL_mem(rRegL dst, rRegL src, memory mask) %{ + predicate(n->bottom_type()->isa_long()); + match(Set dst (ExpandBits src (LoadL mask))); + format %{ "pdepq $dst, $src, $mask\t! parallel bit deposit" %} + ins_encode %{ + __ pdepq($dst$$Register, $src$$Register, $mask$$Address); + %} + ins_pipe( pipe_slow ); +%} + + +// Logical Instructions + +// Integer Logical Instructions + +// And Instructions +// And Register with Register +instruct andI_rReg(rRegI dst, rRegI src, rFlagsReg cr) +%{ + predicate(!UseAPX); + match(Set dst (AndI dst src)); + effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); + + format %{ "andl $dst, $src\t# int" %} + ins_encode %{ + __ andl($dst$$Register, $src$$Register); + %} + ins_pipe(ialu_reg_reg); +%} + +// And Register with Register using New Data Destination (NDD) +instruct andI_rReg_ndd(rRegI dst, rRegI src1, rRegI src2, rFlagsReg cr) +%{ + predicate(UseAPX); + match(Set dst (AndI src1 src2)); + effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); + + format %{ "eandl $dst, $src1, $src2\t# int ndd" %} + ins_encode %{ + __ eandl($dst$$Register, $src1$$Register, $src2$$Register, false); + + %} + ins_pipe(ialu_reg_reg); +%} + +// And Register with Immediate 255 +instruct andI_rReg_imm255(rRegI dst, rRegI src, immI_255 mask) +%{ + match(Set dst (AndI src mask)); + + format %{ "movzbl $dst, $src\t# int & 0xFF" %} + ins_encode %{ + __ movzbl($dst$$Register, $src$$Register); + %} + ins_pipe(ialu_reg); +%} + +// And Register with Immediate 255 and promote to long +instruct andI2L_rReg_imm255(rRegL dst, rRegI src, immI_255 mask) +%{ + match(Set dst (ConvI2L (AndI src mask))); + + format %{ "movzbl $dst, $src\t# int & 0xFF -> long" %} + ins_encode %{ + __ movzbl($dst$$Register, $src$$Register); + %} + ins_pipe(ialu_reg); +%} + +// And Register with Immediate 65535 +instruct andI_rReg_imm65535(rRegI dst, rRegI src, immI_65535 mask) +%{ + match(Set dst (AndI src mask)); + + format %{ "movzwl $dst, $src\t# int & 0xFFFF" %} + ins_encode %{ + __ movzwl($dst$$Register, $src$$Register); + %} + ins_pipe(ialu_reg); +%} + +// And Register with Immediate 65535 and promote to long +instruct andI2L_rReg_imm65535(rRegL dst, rRegI src, immI_65535 mask) +%{ + match(Set dst (ConvI2L (AndI src mask))); + + format %{ "movzwl $dst, $src\t# int & 0xFFFF -> long" %} + ins_encode %{ + __ movzwl($dst$$Register, $src$$Register); + %} + ins_pipe(ialu_reg); +%} + +// Can skip int2long conversions after AND with small bitmask +instruct convI2LAndI_reg_immIbitmask(rRegL dst, rRegI src, immI_Pow2M1 mask, rRegI tmp, rFlagsReg cr) +%{ + predicate(VM_Version::supports_bmi2()); + ins_cost(125); + effect(TEMP tmp, KILL cr); + match(Set dst (ConvI2L (AndI src mask))); + format %{ "bzhiq $dst, $src, $mask \t# using $tmp as TEMP, int & immI_Pow2M1 -> long" %} + ins_encode %{ + __ movl($tmp$$Register, exact_log2($mask$$constant + 1)); + __ bzhiq($dst$$Register, $src$$Register, $tmp$$Register); + %} + ins_pipe(ialu_reg_reg); +%} + +// And Register with Immediate +instruct andI_rReg_imm(rRegI dst, immI src, rFlagsReg cr) +%{ + predicate(!UseAPX); + match(Set dst (AndI dst src)); + effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); + + format %{ "andl $dst, $src\t# int" %} + ins_encode %{ + __ andl($dst$$Register, $src$$constant); + %} + ins_pipe(ialu_reg); +%} + +instruct andI_rReg_rReg_imm_ndd(rRegI dst, rRegI src1, immI src2, rFlagsReg cr) +%{ + predicate(UseAPX); + match(Set dst (AndI src1 src2)); + effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); + + format %{ "eandl $dst, $src1, $src2\t# int ndd" %} + ins_encode %{ + __ eandl($dst$$Register, $src1$$Register, $src2$$constant, false); + %} + ins_pipe(ialu_reg); +%} + +instruct andI_rReg_mem_imm_ndd(rRegI dst, memory src1, immI src2, rFlagsReg cr) +%{ + predicate(UseAPX); + match(Set dst (AndI (LoadI src1) src2)); + effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); + + format %{ "eandl $dst, $src1, $src2\t# int ndd" %} + ins_encode %{ + __ eandl($dst$$Register, $src1$$Address, $src2$$constant, false); + %} + ins_pipe(ialu_reg); +%} + +// And Register with Memory +instruct andI_rReg_mem(rRegI dst, memory src, rFlagsReg cr) +%{ + predicate(!UseAPX); + match(Set dst (AndI dst (LoadI src))); + effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); + + ins_cost(150); + format %{ "andl $dst, $src\t# int" %} + ins_encode %{ + __ andl($dst$$Register, $src$$Address); + %} + ins_pipe(ialu_reg_mem); +%} + +instruct andI_rReg_rReg_mem_ndd(rRegI dst, rRegI src1, memory src2, rFlagsReg cr) +%{ + predicate(UseAPX); + match(Set dst (AndI src1 (LoadI src2))); + effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); + + ins_cost(150); + format %{ "eandl $dst, $src1, $src2\t# int ndd" %} + ins_encode %{ + __ eandl($dst$$Register, $src1$$Register, $src2$$Address, false); + %} + ins_pipe(ialu_reg_mem); +%} + +// And Memory with Register +instruct andB_mem_rReg(memory dst, rRegI src, rFlagsReg cr) +%{ + match(Set dst (StoreB dst (AndI (LoadB dst) src))); + effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); + + ins_cost(150); + format %{ "andb $dst, $src\t# byte" %} + ins_encode %{ + __ andb($dst$$Address, $src$$Register); + %} + ins_pipe(ialu_mem_reg); +%} + +instruct andI_mem_rReg(memory dst, rRegI src, rFlagsReg cr) +%{ + match(Set dst (StoreI dst (AndI (LoadI dst) src))); + effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); + + ins_cost(150); + format %{ "andl $dst, $src\t# int" %} + ins_encode %{ + __ andl($dst$$Address, $src$$Register); + %} + ins_pipe(ialu_mem_reg); +%} + +// And Memory with Immediate +instruct andI_mem_imm(memory dst, immI src, rFlagsReg cr) +%{ + match(Set dst (StoreI dst (AndI (LoadI dst) src))); + effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); + + ins_cost(125); + format %{ "andl $dst, $src\t# int" %} + ins_encode %{ + __ andl($dst$$Address, $src$$constant); + %} + ins_pipe(ialu_mem_imm); +%} + +// BMI1 instructions +instruct andnI_rReg_rReg_mem(rRegI dst, rRegI src1, memory src2, immI_M1 minus_1, rFlagsReg cr) %{ + match(Set dst (AndI (XorI src1 minus_1) (LoadI src2))); + predicate(UseBMI1Instructions); + effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); + + ins_cost(125); + format %{ "andnl $dst, $src1, $src2" %} + + ins_encode %{ + __ andnl($dst$$Register, $src1$$Register, $src2$$Address); + %} + ins_pipe(ialu_reg_mem); +%} + +instruct andnI_rReg_rReg_rReg(rRegI dst, rRegI src1, rRegI src2, immI_M1 minus_1, rFlagsReg cr) %{ + match(Set dst (AndI (XorI src1 minus_1) src2)); + predicate(UseBMI1Instructions); + effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); + + format %{ "andnl $dst, $src1, $src2" %} + + ins_encode %{ + __ andnl($dst$$Register, $src1$$Register, $src2$$Register); + %} + ins_pipe(ialu_reg); +%} + +instruct blsiI_rReg_rReg(rRegI dst, rRegI src, immI_0 imm_zero, rFlagsReg cr) %{ + match(Set dst (AndI (SubI imm_zero src) src)); + predicate(UseBMI1Instructions); + effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_clears_overflow_flag); + + format %{ "blsil $dst, $src" %} + + ins_encode %{ + __ blsil($dst$$Register, $src$$Register); + %} + ins_pipe(ialu_reg); +%} + +instruct blsiI_rReg_mem(rRegI dst, memory src, immI_0 imm_zero, rFlagsReg cr) %{ + match(Set dst (AndI (SubI imm_zero (LoadI src) ) (LoadI src) )); + predicate(UseBMI1Instructions); + effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_clears_overflow_flag); + + ins_cost(125); + format %{ "blsil $dst, $src" %} + + ins_encode %{ + __ blsil($dst$$Register, $src$$Address); + %} + ins_pipe(ialu_reg_mem); +%} + +instruct blsmskI_rReg_mem(rRegI dst, memory src, immI_M1 minus_1, rFlagsReg cr) +%{ + match(Set dst (XorI (AddI (LoadI src) minus_1) (LoadI src) ) ); + predicate(UseBMI1Instructions); + effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_clears_zero_flag, PD::Flag_clears_overflow_flag); + + ins_cost(125); + format %{ "blsmskl $dst, $src" %} + + ins_encode %{ + __ blsmskl($dst$$Register, $src$$Address); + %} + ins_pipe(ialu_reg_mem); +%} + +instruct blsmskI_rReg_rReg(rRegI dst, rRegI src, immI_M1 minus_1, rFlagsReg cr) +%{ + match(Set dst (XorI (AddI src minus_1) src)); + predicate(UseBMI1Instructions); + effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_clears_zero_flag, PD::Flag_clears_overflow_flag); + + format %{ "blsmskl $dst, $src" %} + + ins_encode %{ + __ blsmskl($dst$$Register, $src$$Register); + %} + + ins_pipe(ialu_reg); +%} + +instruct blsrI_rReg_rReg(rRegI dst, rRegI src, immI_M1 minus_1, rFlagsReg cr) +%{ + match(Set dst (AndI (AddI src minus_1) src) ); + predicate(UseBMI1Instructions); + effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_clears_overflow_flag); + + format %{ "blsrl $dst, $src" %} + + ins_encode %{ + __ blsrl($dst$$Register, $src$$Register); + %} + + ins_pipe(ialu_reg_mem); +%} + +instruct blsrI_rReg_mem(rRegI dst, memory src, immI_M1 minus_1, rFlagsReg cr) +%{ + match(Set dst (AndI (AddI (LoadI src) minus_1) (LoadI src) ) ); + predicate(UseBMI1Instructions); + effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_clears_overflow_flag); + + ins_cost(125); + format %{ "blsrl $dst, $src" %} + + ins_encode %{ + __ blsrl($dst$$Register, $src$$Address); + %} + + ins_pipe(ialu_reg); +%} + +// Or Instructions +// Or Register with Register +instruct orI_rReg(rRegI dst, rRegI src, rFlagsReg cr) +%{ + predicate(!UseAPX); + match(Set dst (OrI dst src)); + effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); + + format %{ "orl $dst, $src\t# int" %} + ins_encode %{ + __ orl($dst$$Register, $src$$Register); + %} + ins_pipe(ialu_reg_reg); +%} + +// Or Register with Register using New Data Destination (NDD) +instruct orI_rReg_ndd(rRegI dst, rRegI src1, rRegI src2, rFlagsReg cr) +%{ + predicate(UseAPX); + match(Set dst (OrI src1 src2)); + effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); + + format %{ "eorl $dst, $src1, $src2\t# int ndd" %} + ins_encode %{ + __ eorl($dst$$Register, $src1$$Register, $src2$$Register, false); + %} + ins_pipe(ialu_reg_reg); +%} + +// Or Register with Immediate +instruct orI_rReg_imm(rRegI dst, immI src, rFlagsReg cr) +%{ + predicate(!UseAPX); + match(Set dst (OrI dst src)); + effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); + + format %{ "orl $dst, $src\t# int" %} + ins_encode %{ + __ orl($dst$$Register, $src$$constant); + %} + ins_pipe(ialu_reg); +%} + +instruct orI_rReg_rReg_imm_ndd(rRegI dst, rRegI src1, immI src2, rFlagsReg cr) +%{ + predicate(UseAPX); + match(Set dst (OrI src1 src2)); + effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); + + format %{ "eorl $dst, $src1, $src2\t# int ndd" %} + ins_encode %{ + __ eorl($dst$$Register, $src1$$Register, $src2$$constant, false); + %} + ins_pipe(ialu_reg); +%} + +instruct orI_rReg_imm_rReg_ndd(rRegI dst, immI src1, rRegI src2, rFlagsReg cr) +%{ + predicate(UseAPX); + match(Set dst (OrI src1 src2)); + effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); + + format %{ "eorl $dst, $src2, $src1\t# int ndd" %} + ins_encode %{ + __ eorl($dst$$Register, $src2$$Register, $src1$$constant, false); + %} + ins_pipe(ialu_reg); +%} + +instruct orI_rReg_mem_imm_ndd(rRegI dst, memory src1, immI src2, rFlagsReg cr) +%{ + predicate(UseAPX); + match(Set dst (OrI (LoadI src1) src2)); + effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); + + format %{ "eorl $dst, $src1, $src2\t# int ndd" %} + ins_encode %{ + __ eorl($dst$$Register, $src1$$Address, $src2$$constant, false); + %} + ins_pipe(ialu_reg); +%} + +// Or Register with Memory +instruct orI_rReg_mem(rRegI dst, memory src, rFlagsReg cr) +%{ + predicate(!UseAPX); + match(Set dst (OrI dst (LoadI src))); + effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); + + ins_cost(150); + format %{ "orl $dst, $src\t# int" %} + ins_encode %{ + __ orl($dst$$Register, $src$$Address); + %} + ins_pipe(ialu_reg_mem); +%} + +instruct orI_rReg_rReg_mem_ndd(rRegI dst, rRegI src1, memory src2, rFlagsReg cr) +%{ + predicate(UseAPX); + match(Set dst (OrI src1 (LoadI src2))); + effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); + + ins_cost(150); + format %{ "eorl $dst, $src1, $src2\t# int ndd" %} + ins_encode %{ + __ eorl($dst$$Register, $src1$$Register, $src2$$Address, false); + %} + ins_pipe(ialu_reg_mem); +%} + +// Or Memory with Register +instruct orB_mem_rReg(memory dst, rRegI src, rFlagsReg cr) +%{ + match(Set dst (StoreB dst (OrI (LoadB dst) src))); + effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); + + ins_cost(150); + format %{ "orb $dst, $src\t# byte" %} + ins_encode %{ + __ orb($dst$$Address, $src$$Register); + %} + ins_pipe(ialu_mem_reg); +%} + +instruct orI_mem_rReg(memory dst, rRegI src, rFlagsReg cr) +%{ + match(Set dst (StoreI dst (OrI (LoadI dst) src))); + effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); + + ins_cost(150); + format %{ "orl $dst, $src\t# int" %} + ins_encode %{ + __ orl($dst$$Address, $src$$Register); + %} + ins_pipe(ialu_mem_reg); +%} + +// Or Memory with Immediate +instruct orI_mem_imm(memory dst, immI src, rFlagsReg cr) +%{ + match(Set dst (StoreI dst (OrI (LoadI dst) src))); + effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); + + ins_cost(125); + format %{ "orl $dst, $src\t# int" %} + ins_encode %{ + __ orl($dst$$Address, $src$$constant); + %} + ins_pipe(ialu_mem_imm); +%} + +// Xor Instructions +// Xor Register with Register +instruct xorI_rReg(rRegI dst, rRegI src, rFlagsReg cr) +%{ + predicate(!UseAPX); + match(Set dst (XorI dst src)); + effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); + + format %{ "xorl $dst, $src\t# int" %} + ins_encode %{ + __ xorl($dst$$Register, $src$$Register); + %} + ins_pipe(ialu_reg_reg); +%} + +// Xor Register with Register using New Data Destination (NDD) +instruct xorI_rReg_ndd(rRegI dst, rRegI src1, rRegI src2, rFlagsReg cr) +%{ + predicate(UseAPX); + match(Set dst (XorI src1 src2)); + effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); + + format %{ "exorl $dst, $src1, $src2\t# int ndd" %} + ins_encode %{ + __ exorl($dst$$Register, $src1$$Register, $src2$$Register, false); + %} + ins_pipe(ialu_reg_reg); +%} + +// Xor Register with Immediate -1 +instruct xorI_rReg_im1(rRegI dst, immI_M1 imm) +%{ + predicate(!UseAPX); + match(Set dst (XorI dst imm)); + + format %{ "notl $dst" %} + ins_encode %{ + __ notl($dst$$Register); + %} + ins_pipe(ialu_reg); +%} + +instruct xorI_rReg_im1_ndd(rRegI dst, rRegI src, immI_M1 imm) +%{ + match(Set dst (XorI src imm)); + predicate(UseAPX); + + format %{ "enotl $dst, $src" %} + ins_encode %{ + __ enotl($dst$$Register, $src$$Register); + %} + ins_pipe(ialu_reg); +%} + +// Xor Register with Immediate +instruct xorI_rReg_imm(rRegI dst, immI src, rFlagsReg cr) +%{ + // Strict predicate check to make selection of xorI_rReg_im1 cost agnostic if immI src is -1. + predicate(!UseAPX && n->in(2)->bottom_type()->is_int()->get_con() != -1); + match(Set dst (XorI dst src)); + effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); + + format %{ "xorl $dst, $src\t# int" %} + ins_encode %{ + __ xorl($dst$$Register, $src$$constant); + %} + ins_pipe(ialu_reg); +%} + +instruct xorI_rReg_rReg_imm_ndd(rRegI dst, rRegI src1, immI src2, rFlagsReg cr) +%{ + // Strict predicate check to make selection of xorI_rReg_im1_ndd cost agnostic if immI src2 is -1. + predicate(UseAPX && n->in(2)->bottom_type()->is_int()->get_con() != -1); + match(Set dst (XorI src1 src2)); + effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); + + format %{ "exorl $dst, $src1, $src2\t# int ndd" %} + ins_encode %{ + __ exorl($dst$$Register, $src1$$Register, $src2$$constant, false); + %} + ins_pipe(ialu_reg); +%} + +// Xor Memory with Immediate +instruct xorI_rReg_mem_imm_ndd(rRegI dst, memory src1, immI src2, rFlagsReg cr) +%{ + predicate(UseAPX); + match(Set dst (XorI (LoadI src1) src2)); + effect(KILL cr); + ins_cost(150); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); + + format %{ "exorl $dst, $src1, $src2\t# int ndd" %} + ins_encode %{ + __ exorl($dst$$Register, $src1$$Address, $src2$$constant, false); + %} + ins_pipe(ialu_reg); +%} + +// Xor Register with Memory +instruct xorI_rReg_mem(rRegI dst, memory src, rFlagsReg cr) +%{ + predicate(!UseAPX); + match(Set dst (XorI dst (LoadI src))); + effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); + + ins_cost(150); + format %{ "xorl $dst, $src\t# int" %} + ins_encode %{ + __ xorl($dst$$Register, $src$$Address); + %} + ins_pipe(ialu_reg_mem); +%} + +instruct xorI_rReg_rReg_mem_ndd(rRegI dst, rRegI src1, memory src2, rFlagsReg cr) +%{ + predicate(UseAPX); + match(Set dst (XorI src1 (LoadI src2))); + effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); + + ins_cost(150); + format %{ "exorl $dst, $src1, $src2\t# int ndd" %} + ins_encode %{ + __ exorl($dst$$Register, $src1$$Register, $src2$$Address, false); + %} + ins_pipe(ialu_reg_mem); +%} + +// Xor Memory with Register +instruct xorB_mem_rReg(memory dst, rRegI src, rFlagsReg cr) +%{ + match(Set dst (StoreB dst (XorI (LoadB dst) src))); + effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); + + ins_cost(150); + format %{ "xorb $dst, $src\t# byte" %} + ins_encode %{ + __ xorb($dst$$Address, $src$$Register); + %} + ins_pipe(ialu_mem_reg); +%} + +instruct xorI_mem_rReg(memory dst, rRegI src, rFlagsReg cr) +%{ + match(Set dst (StoreI dst (XorI (LoadI dst) src))); + effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); + + ins_cost(150); + format %{ "xorl $dst, $src\t# int" %} + ins_encode %{ + __ xorl($dst$$Address, $src$$Register); + %} + ins_pipe(ialu_mem_reg); +%} + +// Xor Memory with Immediate +instruct xorI_mem_imm(memory dst, immI src, rFlagsReg cr) +%{ + match(Set dst (StoreI dst (XorI (LoadI dst) src))); + effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); + + ins_cost(125); + format %{ "xorl $dst, $src\t# int" %} + ins_encode %{ + __ xorl($dst$$Address, $src$$constant); + %} + ins_pipe(ialu_mem_imm); +%} + + +// Long Logical Instructions + +// And Instructions +// And Register with Register +instruct andL_rReg(rRegL dst, rRegL src, rFlagsReg cr) +%{ + predicate(!UseAPX); + match(Set dst (AndL dst src)); + effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); + + format %{ "andq $dst, $src\t# long" %} + ins_encode %{ + __ andq($dst$$Register, $src$$Register); + %} + ins_pipe(ialu_reg_reg); +%} + +// And Register with Register using New Data Destination (NDD) +instruct andL_rReg_ndd(rRegL dst, rRegL src1, rRegL src2, rFlagsReg cr) +%{ + predicate(UseAPX); + match(Set dst (AndL src1 src2)); + effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); + + format %{ "eandq $dst, $src1, $src2\t# long ndd" %} + ins_encode %{ + __ eandq($dst$$Register, $src1$$Register, $src2$$Register, false); + + %} + ins_pipe(ialu_reg_reg); +%} + +// And Register with Immediate 255 +instruct andL_rReg_imm255(rRegL dst, rRegL src, immL_255 mask) +%{ + match(Set dst (AndL src mask)); + + format %{ "movzbl $dst, $src\t# long & 0xFF" %} + ins_encode %{ + // movzbl zeroes out the upper 32-bit and does not need REX.W + __ movzbl($dst$$Register, $src$$Register); + %} + ins_pipe(ialu_reg); +%} + +// And Register with Immediate 65535 +instruct andL_rReg_imm65535(rRegL dst, rRegL src, immL_65535 mask) +%{ + match(Set dst (AndL src mask)); + + format %{ "movzwl $dst, $src\t# long & 0xFFFF" %} + ins_encode %{ + // movzwl zeroes out the upper 32-bit and does not need REX.W + __ movzwl($dst$$Register, $src$$Register); + %} + ins_pipe(ialu_reg); +%} + +// And Register with Immediate +instruct andL_rReg_imm(rRegL dst, immL32 src, rFlagsReg cr) +%{ + predicate(!UseAPX); + match(Set dst (AndL dst src)); + effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); + + format %{ "andq $dst, $src\t# long" %} + ins_encode %{ + __ andq($dst$$Register, $src$$constant); + %} + ins_pipe(ialu_reg); +%} + +instruct andL_rReg_rReg_imm_ndd(rRegL dst, rRegL src1, immL32 src2, rFlagsReg cr) +%{ + predicate(UseAPX); + match(Set dst (AndL src1 src2)); + effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); + + format %{ "eandq $dst, $src1, $src2\t# long ndd" %} + ins_encode %{ + __ eandq($dst$$Register, $src1$$Register, $src2$$constant, false); + %} + ins_pipe(ialu_reg); +%} + +instruct andL_rReg_mem_imm_ndd(rRegL dst, memory src1, immL32 src2, rFlagsReg cr) +%{ + predicate(UseAPX); + match(Set dst (AndL (LoadL src1) src2)); + effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); + + format %{ "eandq $dst, $src1, $src2\t# long ndd" %} + ins_encode %{ + __ eandq($dst$$Register, $src1$$Address, $src2$$constant, false); + %} + ins_pipe(ialu_reg); +%} + +// And Register with Memory +instruct andL_rReg_mem(rRegL dst, memory src, rFlagsReg cr) +%{ + predicate(!UseAPX); + match(Set dst (AndL dst (LoadL src))); + effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); + + ins_cost(150); + format %{ "andq $dst, $src\t# long" %} + ins_encode %{ + __ andq($dst$$Register, $src$$Address); + %} + ins_pipe(ialu_reg_mem); +%} + +instruct andL_rReg_rReg_mem_ndd(rRegL dst, rRegL src1, memory src2, rFlagsReg cr) +%{ + predicate(UseAPX); + match(Set dst (AndL src1 (LoadL src2))); + effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); + + ins_cost(150); + format %{ "eandq $dst, $src1, $src2\t# long ndd" %} + ins_encode %{ + __ eandq($dst$$Register, $src1$$Register, $src2$$Address, false); + %} + ins_pipe(ialu_reg_mem); +%} + +// And Memory with Register +instruct andL_mem_rReg(memory dst, rRegL src, rFlagsReg cr) +%{ + match(Set dst (StoreL dst (AndL (LoadL dst) src))); + effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); + + ins_cost(150); + format %{ "andq $dst, $src\t# long" %} + ins_encode %{ + __ andq($dst$$Address, $src$$Register); + %} + ins_pipe(ialu_mem_reg); +%} + +// And Memory with Immediate +instruct andL_mem_imm(memory dst, immL32 src, rFlagsReg cr) +%{ + match(Set dst (StoreL dst (AndL (LoadL dst) src))); + effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); + + ins_cost(125); + format %{ "andq $dst, $src\t# long" %} + ins_encode %{ + __ andq($dst$$Address, $src$$constant); + %} + ins_pipe(ialu_mem_imm); +%} + +instruct btrL_mem_imm(memory dst, immL_NotPow2 con, rFlagsReg cr) +%{ + // con should be a pure 64-bit immediate given that not(con) is a power of 2 + // because AND/OR works well enough for 8/32-bit values. + predicate(log2i_graceful(~n->in(3)->in(2)->get_long()) > 30); + + match(Set dst (StoreL dst (AndL (LoadL dst) con))); + effect(KILL cr); + + ins_cost(125); + format %{ "btrq $dst, log2(not($con))\t# long" %} + ins_encode %{ + __ btrq($dst$$Address, log2i_exact((julong)~$con$$constant)); + %} + ins_pipe(ialu_mem_imm); +%} + +// BMI1 instructions +instruct andnL_rReg_rReg_mem(rRegL dst, rRegL src1, memory src2, immL_M1 minus_1, rFlagsReg cr) %{ + match(Set dst (AndL (XorL src1 minus_1) (LoadL src2))); + predicate(UseBMI1Instructions); + effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); + + ins_cost(125); + format %{ "andnq $dst, $src1, $src2" %} + + ins_encode %{ + __ andnq($dst$$Register, $src1$$Register, $src2$$Address); + %} + ins_pipe(ialu_reg_mem); +%} + +instruct andnL_rReg_rReg_rReg(rRegL dst, rRegL src1, rRegL src2, immL_M1 minus_1, rFlagsReg cr) %{ + match(Set dst (AndL (XorL src1 minus_1) src2)); + predicate(UseBMI1Instructions); + effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); + + format %{ "andnq $dst, $src1, $src2" %} + + ins_encode %{ + __ andnq($dst$$Register, $src1$$Register, $src2$$Register); + %} + ins_pipe(ialu_reg_mem); +%} + +instruct blsiL_rReg_rReg(rRegL dst, rRegL src, immL0 imm_zero, rFlagsReg cr) %{ + match(Set dst (AndL (SubL imm_zero src) src)); + predicate(UseBMI1Instructions); + effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_clears_overflow_flag); + + format %{ "blsiq $dst, $src" %} + + ins_encode %{ + __ blsiq($dst$$Register, $src$$Register); + %} + ins_pipe(ialu_reg); +%} + +instruct blsiL_rReg_mem(rRegL dst, memory src, immL0 imm_zero, rFlagsReg cr) %{ + match(Set dst (AndL (SubL imm_zero (LoadL src) ) (LoadL src) )); + predicate(UseBMI1Instructions); + effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_clears_overflow_flag); + + ins_cost(125); + format %{ "blsiq $dst, $src" %} + + ins_encode %{ + __ blsiq($dst$$Register, $src$$Address); + %} + ins_pipe(ialu_reg_mem); +%} + +instruct blsmskL_rReg_mem(rRegL dst, memory src, immL_M1 minus_1, rFlagsReg cr) +%{ + match(Set dst (XorL (AddL (LoadL src) minus_1) (LoadL src) ) ); + predicate(UseBMI1Instructions); + effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_clears_zero_flag, PD::Flag_clears_overflow_flag); + + ins_cost(125); + format %{ "blsmskq $dst, $src" %} + + ins_encode %{ + __ blsmskq($dst$$Register, $src$$Address); + %} + ins_pipe(ialu_reg_mem); +%} + +instruct blsmskL_rReg_rReg(rRegL dst, rRegL src, immL_M1 minus_1, rFlagsReg cr) +%{ + match(Set dst (XorL (AddL src minus_1) src)); + predicate(UseBMI1Instructions); + effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_clears_zero_flag, PD::Flag_clears_overflow_flag); + + format %{ "blsmskq $dst, $src" %} + + ins_encode %{ + __ blsmskq($dst$$Register, $src$$Register); + %} + + ins_pipe(ialu_reg); +%} + +instruct blsrL_rReg_rReg(rRegL dst, rRegL src, immL_M1 minus_1, rFlagsReg cr) +%{ + match(Set dst (AndL (AddL src minus_1) src) ); + predicate(UseBMI1Instructions); + effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_clears_overflow_flag); + + format %{ "blsrq $dst, $src" %} + + ins_encode %{ + __ blsrq($dst$$Register, $src$$Register); + %} + + ins_pipe(ialu_reg); +%} + +instruct blsrL_rReg_mem(rRegL dst, memory src, immL_M1 minus_1, rFlagsReg cr) +%{ + match(Set dst (AndL (AddL (LoadL src) minus_1) (LoadL src)) ); + predicate(UseBMI1Instructions); + effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_clears_overflow_flag); + + ins_cost(125); + format %{ "blsrq $dst, $src" %} + + ins_encode %{ + __ blsrq($dst$$Register, $src$$Address); + %} + + ins_pipe(ialu_reg); +%} + +// Or Instructions +// Or Register with Register +instruct orL_rReg(rRegL dst, rRegL src, rFlagsReg cr) +%{ + predicate(!UseAPX); + match(Set dst (OrL dst src)); + effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); + + format %{ "orq $dst, $src\t# long" %} + ins_encode %{ + __ orq($dst$$Register, $src$$Register); + %} + ins_pipe(ialu_reg_reg); +%} + +// Or Register with Register using New Data Destination (NDD) +instruct orL_rReg_ndd(rRegL dst, rRegL src1, rRegL src2, rFlagsReg cr) +%{ + predicate(UseAPX); + match(Set dst (OrL src1 src2)); + effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); + + format %{ "eorq $dst, $src1, $src2\t# long ndd" %} + ins_encode %{ + __ eorq($dst$$Register, $src1$$Register, $src2$$Register, false); + + %} + ins_pipe(ialu_reg_reg); +%} + +// Use any_RegP to match R15 (TLS register) without spilling. +instruct orL_rReg_castP2X(rRegL dst, any_RegP src, rFlagsReg cr) %{ + match(Set dst (OrL dst (CastP2X src))); + effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); + + format %{ "orq $dst, $src\t# long" %} + ins_encode %{ + __ orq($dst$$Register, $src$$Register); + %} + ins_pipe(ialu_reg_reg); +%} + +instruct orL_rReg_castP2X_ndd(rRegL dst, any_RegP src1, any_RegP src2, rFlagsReg cr) %{ + match(Set dst (OrL src1 (CastP2X src2))); + effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); + + format %{ "eorq $dst, $src1, $src2\t# long ndd" %} + ins_encode %{ + __ eorq($dst$$Register, $src1$$Register, $src2$$Register, false); + %} + ins_pipe(ialu_reg_reg); +%} + +// Or Register with Immediate +instruct orL_rReg_imm(rRegL dst, immL32 src, rFlagsReg cr) +%{ + predicate(!UseAPX); + match(Set dst (OrL dst src)); + effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); + + format %{ "orq $dst, $src\t# long" %} + ins_encode %{ + __ orq($dst$$Register, $src$$constant); + %} + ins_pipe(ialu_reg); +%} + +instruct orL_rReg_rReg_imm_ndd(rRegL dst, rRegL src1, immL32 src2, rFlagsReg cr) +%{ + predicate(UseAPX); + match(Set dst (OrL src1 src2)); + effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); + + format %{ "eorq $dst, $src1, $src2\t# long ndd" %} + ins_encode %{ + __ eorq($dst$$Register, $src1$$Register, $src2$$constant, false); + %} + ins_pipe(ialu_reg); +%} + +instruct orL_rReg_imm_rReg_ndd(rRegL dst, immL32 src1, rRegL src2, rFlagsReg cr) +%{ + predicate(UseAPX); + match(Set dst (OrL src1 src2)); + effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); + + format %{ "eorq $dst, $src2, $src1\t# long ndd" %} + ins_encode %{ + __ eorq($dst$$Register, $src2$$Register, $src1$$constant, false); + %} + ins_pipe(ialu_reg); +%} + +// Or Memory with Immediate +instruct orL_rReg_mem_imm_ndd(rRegL dst, memory src1, immL32 src2, rFlagsReg cr) +%{ + predicate(UseAPX); + match(Set dst (OrL (LoadL src1) src2)); + effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); + + format %{ "eorq $dst, $src1, $src2\t# long ndd" %} + ins_encode %{ + __ eorq($dst$$Register, $src1$$Address, $src2$$constant, false); + %} + ins_pipe(ialu_reg); +%} + +// Or Register with Memory +instruct orL_rReg_mem(rRegL dst, memory src, rFlagsReg cr) +%{ + predicate(!UseAPX); + match(Set dst (OrL dst (LoadL src))); + effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); + + ins_cost(150); + format %{ "orq $dst, $src\t# long" %} + ins_encode %{ + __ orq($dst$$Register, $src$$Address); + %} + ins_pipe(ialu_reg_mem); +%} + +instruct orL_rReg_rReg_mem_ndd(rRegL dst, rRegL src1, memory src2, rFlagsReg cr) +%{ + predicate(UseAPX); + match(Set dst (OrL src1 (LoadL src2))); + effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); + + ins_cost(150); + format %{ "eorq $dst, $src1, $src2\t# long ndd" %} + ins_encode %{ + __ eorq($dst$$Register, $src1$$Register, $src2$$Address, false); + %} + ins_pipe(ialu_reg_mem); +%} + +// Or Memory with Register +instruct orL_mem_rReg(memory dst, rRegL src, rFlagsReg cr) +%{ + match(Set dst (StoreL dst (OrL (LoadL dst) src))); + effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); + + ins_cost(150); + format %{ "orq $dst, $src\t# long" %} + ins_encode %{ + __ orq($dst$$Address, $src$$Register); + %} + ins_pipe(ialu_mem_reg); +%} + +// Or Memory with Immediate +instruct orL_mem_imm(memory dst, immL32 src, rFlagsReg cr) +%{ + match(Set dst (StoreL dst (OrL (LoadL dst) src))); + effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); + + ins_cost(125); + format %{ "orq $dst, $src\t# long" %} + ins_encode %{ + __ orq($dst$$Address, $src$$constant); + %} + ins_pipe(ialu_mem_imm); +%} + +instruct btsL_mem_imm(memory dst, immL_Pow2 con, rFlagsReg cr) +%{ + // con should be a pure 64-bit power of 2 immediate + // because AND/OR works well enough for 8/32-bit values. + predicate(log2i_graceful(n->in(3)->in(2)->get_long()) > 31); + + match(Set dst (StoreL dst (OrL (LoadL dst) con))); + effect(KILL cr); + + ins_cost(125); + format %{ "btsq $dst, log2($con)\t# long" %} + ins_encode %{ + __ btsq($dst$$Address, log2i_exact((julong)$con$$constant)); + %} + ins_pipe(ialu_mem_imm); +%} + +// Xor Instructions +// Xor Register with Register +instruct xorL_rReg(rRegL dst, rRegL src, rFlagsReg cr) +%{ + predicate(!UseAPX); + match(Set dst (XorL dst src)); + effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); + + format %{ "xorq $dst, $src\t# long" %} + ins_encode %{ + __ xorq($dst$$Register, $src$$Register); + %} + ins_pipe(ialu_reg_reg); +%} + +// Xor Register with Register using New Data Destination (NDD) +instruct xorL_rReg_ndd(rRegL dst, rRegL src1, rRegL src2, rFlagsReg cr) +%{ + predicate(UseAPX); + match(Set dst (XorL src1 src2)); + effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); + + format %{ "exorq $dst, $src1, $src2\t# long ndd" %} + ins_encode %{ + __ exorq($dst$$Register, $src1$$Register, $src2$$Register, false); + %} + ins_pipe(ialu_reg_reg); +%} + +// Xor Register with Immediate -1 +instruct xorL_rReg_im1(rRegL dst, immL_M1 imm) +%{ + predicate(!UseAPX); + match(Set dst (XorL dst imm)); + + format %{ "notq $dst" %} + ins_encode %{ + __ notq($dst$$Register); + %} + ins_pipe(ialu_reg); +%} + +instruct xorL_rReg_im1_ndd(rRegL dst,rRegL src, immL_M1 imm) +%{ + predicate(UseAPX); + match(Set dst (XorL src imm)); + + format %{ "enotq $dst, $src" %} + ins_encode %{ + __ enotq($dst$$Register, $src$$Register); + %} + ins_pipe(ialu_reg); +%} + +// Xor Register with Immediate +instruct xorL_rReg_imm(rRegL dst, immL32 src, rFlagsReg cr) +%{ + // Strict predicate check to make selection of xorL_rReg_im1 cost agnostic if immL32 src is -1. + predicate(!UseAPX && n->in(2)->bottom_type()->is_long()->get_con() != -1L); + match(Set dst (XorL dst src)); + effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); + + format %{ "xorq $dst, $src\t# long" %} + ins_encode %{ + __ xorq($dst$$Register, $src$$constant); + %} + ins_pipe(ialu_reg); +%} + +instruct xorL_rReg_rReg_imm(rRegL dst, rRegL src1, immL32 src2, rFlagsReg cr) +%{ + // Strict predicate check to make selection of xorL_rReg_im1_ndd cost agnostic if immL32 src2 is -1. + predicate(UseAPX && n->in(2)->bottom_type()->is_long()->get_con() != -1L); + match(Set dst (XorL src1 src2)); + effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); + + format %{ "exorq $dst, $src1, $src2\t# long ndd" %} + ins_encode %{ + __ exorq($dst$$Register, $src1$$Register, $src2$$constant, false); + %} + ins_pipe(ialu_reg); +%} + +// Xor Memory with Immediate +instruct xorL_rReg_mem_imm(rRegL dst, memory src1, immL32 src2, rFlagsReg cr) +%{ + predicate(UseAPX); + match(Set dst (XorL (LoadL src1) src2)); + effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); + ins_cost(150); + + format %{ "exorq $dst, $src1, $src2\t# long ndd" %} + ins_encode %{ + __ exorq($dst$$Register, $src1$$Address, $src2$$constant, false); + %} + ins_pipe(ialu_reg); +%} + +// Xor Register with Memory +instruct xorL_rReg_mem(rRegL dst, memory src, rFlagsReg cr) +%{ + predicate(!UseAPX); + match(Set dst (XorL dst (LoadL src))); + effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); + + ins_cost(150); + format %{ "xorq $dst, $src\t# long" %} + ins_encode %{ + __ xorq($dst$$Register, $src$$Address); + %} + ins_pipe(ialu_reg_mem); +%} + +instruct xorL_rReg_rReg_mem_ndd(rRegL dst, rRegL src1, memory src2, rFlagsReg cr) +%{ + predicate(UseAPX); + match(Set dst (XorL src1 (LoadL src2))); + effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); + + ins_cost(150); + format %{ "exorq $dst, $src1, $src2\t# long ndd" %} + ins_encode %{ + __ exorq($dst$$Register, $src1$$Register, $src2$$Address, false); + %} + ins_pipe(ialu_reg_mem); +%} + +// Xor Memory with Register +instruct xorL_mem_rReg(memory dst, rRegL src, rFlagsReg cr) +%{ + match(Set dst (StoreL dst (XorL (LoadL dst) src))); + effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); + + ins_cost(150); + format %{ "xorq $dst, $src\t# long" %} + ins_encode %{ + __ xorq($dst$$Address, $src$$Register); + %} + ins_pipe(ialu_mem_reg); +%} + +// Xor Memory with Immediate +instruct xorL_mem_imm(memory dst, immL32 src, rFlagsReg cr) +%{ + match(Set dst (StoreL dst (XorL (LoadL dst) src))); + effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); + + ins_cost(125); + format %{ "xorq $dst, $src\t# long" %} + ins_encode %{ + __ xorq($dst$$Address, $src$$constant); + %} + ins_pipe(ialu_mem_imm); +%} + +instruct cmpLTMask(rRegI dst, rRegI p, rRegI q, rFlagsReg cr) +%{ + match(Set dst (CmpLTMask p q)); + effect(KILL cr); + + ins_cost(400); + format %{ "cmpl $p, $q\t# cmpLTMask\n\t" + "setcc $dst \t# emits setlt + movzbl or setzul for APX" + "negl $dst" %} + ins_encode %{ + __ cmpl($p$$Register, $q$$Register); + __ setcc(Assembler::less, $dst$$Register); + __ negl($dst$$Register); + %} + ins_pipe(pipe_slow); +%} + +instruct cmpLTMask0(rRegI dst, immI_0 zero, rFlagsReg cr) +%{ + match(Set dst (CmpLTMask dst zero)); + effect(KILL cr); + + ins_cost(100); + format %{ "sarl $dst, #31\t# cmpLTMask0" %} + ins_encode %{ + __ sarl($dst$$Register, 31); + %} + ins_pipe(ialu_reg); +%} + +/* Better to save a register than avoid a branch */ +instruct cadd_cmpLTMask(rRegI p, rRegI q, rRegI y, rFlagsReg cr) +%{ + match(Set p (AddI (AndI (CmpLTMask p q) y) (SubI p q))); + effect(KILL cr); + ins_cost(300); + format %{ "subl $p,$q\t# cadd_cmpLTMask\n\t" + "jge done\n\t" + "addl $p,$y\n" + "done: " %} + ins_encode %{ + Register Rp = $p$$Register; + Register Rq = $q$$Register; + Register Ry = $y$$Register; + Label done; + __ subl(Rp, Rq); + __ jccb(Assembler::greaterEqual, done); + __ addl(Rp, Ry); + __ bind(done); + %} + ins_pipe(pipe_cmplt); +%} + +/* Better to save a register than avoid a branch */ +instruct and_cmpLTMask(rRegI p, rRegI q, rRegI y, rFlagsReg cr) +%{ + match(Set y (AndI (CmpLTMask p q) y)); + effect(KILL cr); + + ins_cost(300); + + format %{ "cmpl $p, $q\t# and_cmpLTMask\n\t" + "jlt done\n\t" + "xorl $y, $y\n" + "done: " %} + ins_encode %{ + Register Rp = $p$$Register; + Register Rq = $q$$Register; + Register Ry = $y$$Register; + Label done; + __ cmpl(Rp, Rq); + __ jccb(Assembler::less, done); + __ xorl(Ry, Ry); + __ bind(done); + %} + ins_pipe(pipe_cmplt); +%} + + +//---------- FP Instructions------------------------------------------------ + +// Really expensive, avoid +instruct cmpF_cc_reg(rFlagsRegU cr, regF src1, regF src2) +%{ + match(Set cr (CmpF src1 src2)); + + ins_cost(500); + format %{ "ucomiss $src1, $src2\n\t" + "jnp,s exit\n\t" + "pushfq\t# saw NaN, set CF\n\t" + "andq [rsp], #0xffffff2b\n\t" + "popfq\n" + "exit:" %} + ins_encode %{ + __ ucomiss($src1$$XMMRegister, $src2$$XMMRegister); + emit_cmpfp_fixup(masm); + %} + ins_pipe(pipe_slow); +%} + +instruct cmpF_cc_reg_CF(rFlagsRegUCF cr, regF src1, regF src2) %{ + match(Set cr (CmpF src1 src2)); + + ins_cost(100); + format %{ "ucomiss $src1, $src2" %} + ins_encode %{ + __ ucomiss($src1$$XMMRegister, $src2$$XMMRegister); + %} + ins_pipe(pipe_slow); +%} + +instruct cmpF_cc_memCF(rFlagsRegUCF cr, regF src1, memory src2) %{ + match(Set cr (CmpF src1 (LoadF src2))); + + ins_cost(100); + format %{ "ucomiss $src1, $src2" %} + ins_encode %{ + __ ucomiss($src1$$XMMRegister, $src2$$Address); + %} + ins_pipe(pipe_slow); +%} + +instruct cmpF_cc_immCF(rFlagsRegUCF cr, regF src, immF con) %{ + match(Set cr (CmpF src con)); + ins_cost(100); + format %{ "ucomiss $src, [$constantaddress]\t# load from constant table: float=$con" %} + ins_encode %{ + __ ucomiss($src$$XMMRegister, $constantaddress($con)); + %} + ins_pipe(pipe_slow); +%} + +// Really expensive, avoid +instruct cmpD_cc_reg(rFlagsRegU cr, regD src1, regD src2) +%{ + match(Set cr (CmpD src1 src2)); + + ins_cost(500); + format %{ "ucomisd $src1, $src2\n\t" + "jnp,s exit\n\t" + "pushfq\t# saw NaN, set CF\n\t" + "andq [rsp], #0xffffff2b\n\t" + "popfq\n" + "exit:" %} + ins_encode %{ + __ ucomisd($src1$$XMMRegister, $src2$$XMMRegister); + emit_cmpfp_fixup(masm); + %} + ins_pipe(pipe_slow); +%} + +instruct cmpD_cc_reg_CF(rFlagsRegUCF cr, regD src1, regD src2) %{ + match(Set cr (CmpD src1 src2)); + + ins_cost(100); + format %{ "ucomisd $src1, $src2 test" %} + ins_encode %{ + __ ucomisd($src1$$XMMRegister, $src2$$XMMRegister); + %} + ins_pipe(pipe_slow); +%} + +instruct cmpD_cc_memCF(rFlagsRegUCF cr, regD src1, memory src2) %{ + match(Set cr (CmpD src1 (LoadD src2))); + + ins_cost(100); + format %{ "ucomisd $src1, $src2" %} + ins_encode %{ + __ ucomisd($src1$$XMMRegister, $src2$$Address); + %} + ins_pipe(pipe_slow); +%} + +instruct cmpD_cc_immCF(rFlagsRegUCF cr, regD src, immD con) %{ + match(Set cr (CmpD src con)); + ins_cost(100); + format %{ "ucomisd $src, [$constantaddress]\t# load from constant table: double=$con" %} + ins_encode %{ + __ ucomisd($src$$XMMRegister, $constantaddress($con)); + %} + ins_pipe(pipe_slow); +%} + +// Compare into -1,0,1 +instruct cmpF_reg(rRegI dst, regF src1, regF src2, rFlagsReg cr) +%{ + match(Set dst (CmpF3 src1 src2)); + effect(KILL cr); + + ins_cost(275); + format %{ "ucomiss $src1, $src2\n\t" + "movl $dst, #-1\n\t" + "jp,s done\n\t" + "jb,s done\n\t" + "setne $dst\n\t" + "movzbl $dst, $dst\n" + "done:" %} + ins_encode %{ + __ ucomiss($src1$$XMMRegister, $src2$$XMMRegister); + emit_cmpfp3(masm, $dst$$Register); + %} + ins_pipe(pipe_slow); +%} + +// Compare into -1,0,1 +instruct cmpF_mem(rRegI dst, regF src1, memory src2, rFlagsReg cr) +%{ + match(Set dst (CmpF3 src1 (LoadF src2))); + effect(KILL cr); + + ins_cost(275); + format %{ "ucomiss $src1, $src2\n\t" + "movl $dst, #-1\n\t" + "jp,s done\n\t" + "jb,s done\n\t" + "setne $dst\n\t" + "movzbl $dst, $dst\n" + "done:" %} + ins_encode %{ + __ ucomiss($src1$$XMMRegister, $src2$$Address); + emit_cmpfp3(masm, $dst$$Register); + %} + ins_pipe(pipe_slow); +%} + +// Compare into -1,0,1 +instruct cmpF_imm(rRegI dst, regF src, immF con, rFlagsReg cr) %{ + match(Set dst (CmpF3 src con)); + effect(KILL cr); + + ins_cost(275); + format %{ "ucomiss $src, [$constantaddress]\t# load from constant table: float=$con\n\t" + "movl $dst, #-1\n\t" + "jp,s done\n\t" + "jb,s done\n\t" + "setne $dst\n\t" + "movzbl $dst, $dst\n" + "done:" %} + ins_encode %{ + __ ucomiss($src$$XMMRegister, $constantaddress($con)); + emit_cmpfp3(masm, $dst$$Register); + %} + ins_pipe(pipe_slow); +%} + +// Compare into -1,0,1 +instruct cmpD_reg(rRegI dst, regD src1, regD src2, rFlagsReg cr) +%{ + match(Set dst (CmpD3 src1 src2)); + effect(KILL cr); + + ins_cost(275); + format %{ "ucomisd $src1, $src2\n\t" + "movl $dst, #-1\n\t" + "jp,s done\n\t" + "jb,s done\n\t" + "setne $dst\n\t" + "movzbl $dst, $dst\n" + "done:" %} + ins_encode %{ + __ ucomisd($src1$$XMMRegister, $src2$$XMMRegister); + emit_cmpfp3(masm, $dst$$Register); + %} + ins_pipe(pipe_slow); +%} + +// Compare into -1,0,1 +instruct cmpD_mem(rRegI dst, regD src1, memory src2, rFlagsReg cr) +%{ + match(Set dst (CmpD3 src1 (LoadD src2))); + effect(KILL cr); + + ins_cost(275); + format %{ "ucomisd $src1, $src2\n\t" + "movl $dst, #-1\n\t" + "jp,s done\n\t" + "jb,s done\n\t" + "setne $dst\n\t" + "movzbl $dst, $dst\n" + "done:" %} + ins_encode %{ + __ ucomisd($src1$$XMMRegister, $src2$$Address); + emit_cmpfp3(masm, $dst$$Register); + %} + ins_pipe(pipe_slow); +%} + +// Compare into -1,0,1 +instruct cmpD_imm(rRegI dst, regD src, immD con, rFlagsReg cr) %{ + match(Set dst (CmpD3 src con)); + effect(KILL cr); + + ins_cost(275); + format %{ "ucomisd $src, [$constantaddress]\t# load from constant table: double=$con\n\t" + "movl $dst, #-1\n\t" + "jp,s done\n\t" + "jb,s done\n\t" + "setne $dst\n\t" + "movzbl $dst, $dst\n" + "done:" %} + ins_encode %{ + __ ucomisd($src$$XMMRegister, $constantaddress($con)); + emit_cmpfp3(masm, $dst$$Register); + %} + ins_pipe(pipe_slow); +%} + +//----------Arithmetic Conversion Instructions--------------------------------- + +instruct convF2D_reg_reg(regD dst, regF src) +%{ + match(Set dst (ConvF2D src)); + + format %{ "cvtss2sd $dst, $src" %} + ins_encode %{ + __ cvtss2sd ($dst$$XMMRegister, $src$$XMMRegister); + %} + ins_pipe(pipe_slow); // XXX +%} + +instruct convF2D_reg_mem(regD dst, memory src) +%{ + predicate(UseAVX == 0); + match(Set dst (ConvF2D (LoadF src))); + + format %{ "cvtss2sd $dst, $src" %} + ins_encode %{ + __ cvtss2sd ($dst$$XMMRegister, $src$$Address); + %} + ins_pipe(pipe_slow); // XXX +%} + +instruct convD2F_reg_reg(regF dst, regD src) +%{ + match(Set dst (ConvD2F src)); + + format %{ "cvtsd2ss $dst, $src" %} + ins_encode %{ + __ cvtsd2ss ($dst$$XMMRegister, $src$$XMMRegister); + %} + ins_pipe(pipe_slow); // XXX +%} + +instruct convD2F_reg_mem(regF dst, memory src) +%{ + predicate(UseAVX == 0); + match(Set dst (ConvD2F (LoadD src))); + + format %{ "cvtsd2ss $dst, $src" %} + ins_encode %{ + __ cvtsd2ss ($dst$$XMMRegister, $src$$Address); + %} + ins_pipe(pipe_slow); // XXX +%} + +// XXX do mem variants +instruct convF2I_reg_reg(rRegI dst, regF src, rFlagsReg cr) +%{ + predicate(!VM_Version::supports_avx10_2()); + match(Set dst (ConvF2I src)); + effect(KILL cr); + format %{ "convert_f2i $dst, $src" %} + ins_encode %{ + __ convertF2I(T_INT, T_FLOAT, $dst$$Register, $src$$XMMRegister); + %} + ins_pipe(pipe_slow); +%} + +instruct convF2I_reg_reg_avx10(rRegI dst, regF src) +%{ + predicate(VM_Version::supports_avx10_2()); + match(Set dst (ConvF2I src)); + format %{ "evcvttss2sisl $dst, $src" %} + ins_encode %{ + __ evcvttss2sisl($dst$$Register, $src$$XMMRegister); + %} + ins_pipe(pipe_slow); +%} + +instruct convF2I_reg_mem_avx10(rRegI dst, memory src) +%{ + predicate(VM_Version::supports_avx10_2()); + match(Set dst (ConvF2I (LoadF src))); + format %{ "evcvttss2sisl $dst, $src" %} + ins_encode %{ + __ evcvttss2sisl($dst$$Register, $src$$Address); + %} + ins_pipe(pipe_slow); +%} + +instruct convF2L_reg_reg(rRegL dst, regF src, rFlagsReg cr) +%{ + predicate(!VM_Version::supports_avx10_2()); + match(Set dst (ConvF2L src)); + effect(KILL cr); + format %{ "convert_f2l $dst, $src"%} + ins_encode %{ + __ convertF2I(T_LONG, T_FLOAT, $dst$$Register, $src$$XMMRegister); + %} + ins_pipe(pipe_slow); +%} + +instruct convF2L_reg_reg_avx10(rRegL dst, regF src) +%{ + predicate(VM_Version::supports_avx10_2()); + match(Set dst (ConvF2L src)); + format %{ "evcvttss2sisq $dst, $src" %} + ins_encode %{ + __ evcvttss2sisq($dst$$Register, $src$$XMMRegister); + %} + ins_pipe(pipe_slow); +%} + +instruct convF2L_reg_mem_avx10(rRegL dst, memory src) +%{ + predicate(VM_Version::supports_avx10_2()); + match(Set dst (ConvF2L (LoadF src))); + format %{ "evcvttss2sisq $dst, $src" %} + ins_encode %{ + __ evcvttss2sisq($dst$$Register, $src$$Address); + %} + ins_pipe(pipe_slow); +%} + +instruct convD2I_reg_reg(rRegI dst, regD src, rFlagsReg cr) +%{ + predicate(!VM_Version::supports_avx10_2()); + match(Set dst (ConvD2I src)); + effect(KILL cr); + format %{ "convert_d2i $dst, $src"%} + ins_encode %{ + __ convertF2I(T_INT, T_DOUBLE, $dst$$Register, $src$$XMMRegister); + %} + ins_pipe(pipe_slow); +%} + +instruct convD2I_reg_reg_avx10(rRegI dst, regD src) +%{ + predicate(VM_Version::supports_avx10_2()); + match(Set dst (ConvD2I src)); + format %{ "evcvttsd2sisl $dst, $src" %} + ins_encode %{ + __ evcvttsd2sisl($dst$$Register, $src$$XMMRegister); + %} + ins_pipe(pipe_slow); +%} + +instruct convD2I_reg_mem_avx10(rRegI dst, memory src) +%{ + predicate(VM_Version::supports_avx10_2()); + match(Set dst (ConvD2I (LoadD src))); + format %{ "evcvttsd2sisl $dst, $src" %} + ins_encode %{ + __ evcvttsd2sisl($dst$$Register, $src$$Address); + %} + ins_pipe(pipe_slow); +%} + +instruct convD2L_reg_reg(rRegL dst, regD src, rFlagsReg cr) +%{ + predicate(!VM_Version::supports_avx10_2()); + match(Set dst (ConvD2L src)); + effect(KILL cr); + format %{ "convert_d2l $dst, $src"%} + ins_encode %{ + __ convertF2I(T_LONG, T_DOUBLE, $dst$$Register, $src$$XMMRegister); + %} + ins_pipe(pipe_slow); +%} + +instruct convD2L_reg_reg_avx10(rRegL dst, regD src) +%{ + predicate(VM_Version::supports_avx10_2()); + match(Set dst (ConvD2L src)); + format %{ "evcvttsd2sisq $dst, $src" %} + ins_encode %{ + __ evcvttsd2sisq($dst$$Register, $src$$XMMRegister); + %} + ins_pipe(pipe_slow); +%} + +instruct convD2L_reg_mem_avx10(rRegL dst, memory src) +%{ + predicate(VM_Version::supports_avx10_2()); + match(Set dst (ConvD2L (LoadD src))); + format %{ "evcvttsd2sisq $dst, $src" %} + ins_encode %{ + __ evcvttsd2sisq($dst$$Register, $src$$Address); + %} + ins_pipe(pipe_slow); +%} + +instruct round_double_reg(rRegL dst, regD src, rRegL rtmp, rcx_RegL rcx, rFlagsReg cr) +%{ + match(Set dst (RoundD src)); + effect(TEMP dst, TEMP rtmp, TEMP rcx, KILL cr); + format %{ "round_double $dst,$src \t! using $rtmp and $rcx as TEMP"%} + ins_encode %{ + __ round_double($dst$$Register, $src$$XMMRegister, $rtmp$$Register, $rcx$$Register); + %} + ins_pipe(pipe_slow); +%} + +instruct round_float_reg(rRegI dst, regF src, rRegL rtmp, rcx_RegL rcx, rFlagsReg cr) +%{ + match(Set dst (RoundF src)); + effect(TEMP dst, TEMP rtmp, TEMP rcx, KILL cr); + format %{ "round_float $dst,$src" %} + ins_encode %{ + __ round_float($dst$$Register, $src$$XMMRegister, $rtmp$$Register, $rcx$$Register); + %} + ins_pipe(pipe_slow); +%} + +instruct convI2F_reg_reg(vlRegF dst, rRegI src) +%{ + predicate(!UseXmmI2F); + match(Set dst (ConvI2F src)); + + format %{ "cvtsi2ssl $dst, $src\t# i2f" %} + ins_encode %{ + if (UseAVX > 0) { + __ pxor($dst$$XMMRegister, $dst$$XMMRegister); + } + __ cvtsi2ssl ($dst$$XMMRegister, $src$$Register); + %} + ins_pipe(pipe_slow); // XXX +%} + +instruct convI2F_reg_mem(regF dst, memory src) +%{ + predicate(UseAVX == 0); + match(Set dst (ConvI2F (LoadI src))); + + format %{ "cvtsi2ssl $dst, $src\t# i2f" %} + ins_encode %{ + __ cvtsi2ssl ($dst$$XMMRegister, $src$$Address); + %} + ins_pipe(pipe_slow); // XXX +%} + +instruct convI2D_reg_reg(vlRegD dst, rRegI src) +%{ + predicate(!UseXmmI2D); + match(Set dst (ConvI2D src)); + + format %{ "cvtsi2sdl $dst, $src\t# i2d" %} + ins_encode %{ + if (UseAVX > 0) { + __ pxor($dst$$XMMRegister, $dst$$XMMRegister); + } + __ cvtsi2sdl ($dst$$XMMRegister, $src$$Register); + %} + ins_pipe(pipe_slow); // XXX +%} + +instruct convI2D_reg_mem(regD dst, memory src) +%{ + predicate(UseAVX == 0); + match(Set dst (ConvI2D (LoadI src))); + + format %{ "cvtsi2sdl $dst, $src\t# i2d" %} + ins_encode %{ + __ cvtsi2sdl ($dst$$XMMRegister, $src$$Address); + %} + ins_pipe(pipe_slow); // XXX +%} + +instruct convXI2F_reg(regF dst, rRegI src) +%{ + predicate(UseXmmI2F); + match(Set dst (ConvI2F src)); + + format %{ "movdl $dst, $src\n\t" + "cvtdq2psl $dst, $dst\t# i2f" %} + ins_encode %{ + __ movdl($dst$$XMMRegister, $src$$Register); + __ cvtdq2ps($dst$$XMMRegister, $dst$$XMMRegister); + %} + ins_pipe(pipe_slow); // XXX +%} + +instruct convXI2D_reg(regD dst, rRegI src) +%{ + predicate(UseXmmI2D); + match(Set dst (ConvI2D src)); + + format %{ "movdl $dst, $src\n\t" + "cvtdq2pdl $dst, $dst\t# i2d" %} + ins_encode %{ + __ movdl($dst$$XMMRegister, $src$$Register); + __ cvtdq2pd($dst$$XMMRegister, $dst$$XMMRegister); + %} + ins_pipe(pipe_slow); // XXX +%} + +instruct convL2F_reg_reg(vlRegF dst, rRegL src) +%{ + match(Set dst (ConvL2F src)); + + format %{ "cvtsi2ssq $dst, $src\t# l2f" %} + ins_encode %{ + if (UseAVX > 0) { + __ pxor($dst$$XMMRegister, $dst$$XMMRegister); + } + __ cvtsi2ssq ($dst$$XMMRegister, $src$$Register); + %} + ins_pipe(pipe_slow); // XXX +%} + +instruct convL2F_reg_mem(regF dst, memory src) +%{ + predicate(UseAVX == 0); + match(Set dst (ConvL2F (LoadL src))); + + format %{ "cvtsi2ssq $dst, $src\t# l2f" %} + ins_encode %{ + __ cvtsi2ssq ($dst$$XMMRegister, $src$$Address); + %} + ins_pipe(pipe_slow); // XXX +%} + +instruct convL2D_reg_reg(vlRegD dst, rRegL src) +%{ + match(Set dst (ConvL2D src)); + + format %{ "cvtsi2sdq $dst, $src\t# l2d" %} + ins_encode %{ + if (UseAVX > 0) { + __ pxor($dst$$XMMRegister, $dst$$XMMRegister); + } + __ cvtsi2sdq ($dst$$XMMRegister, $src$$Register); + %} + ins_pipe(pipe_slow); // XXX +%} + +instruct convL2D_reg_mem(regD dst, memory src) +%{ + predicate(UseAVX == 0); + match(Set dst (ConvL2D (LoadL src))); + + format %{ "cvtsi2sdq $dst, $src\t# l2d" %} + ins_encode %{ + __ cvtsi2sdq ($dst$$XMMRegister, $src$$Address); + %} + ins_pipe(pipe_slow); // XXX +%} + +instruct convI2L_reg_reg(rRegL dst, rRegI src) +%{ + match(Set dst (ConvI2L src)); + + ins_cost(125); + format %{ "movslq $dst, $src\t# i2l" %} + ins_encode %{ + __ movslq($dst$$Register, $src$$Register); + %} + ins_pipe(ialu_reg_reg); +%} + +// Zero-extend convert int to long +instruct convI2L_reg_reg_zex(rRegL dst, rRegI src, immL_32bits mask) +%{ + match(Set dst (AndL (ConvI2L src) mask)); + + format %{ "movl $dst, $src\t# i2l zero-extend\n\t" %} + ins_encode %{ + if ($dst$$reg != $src$$reg) { + __ movl($dst$$Register, $src$$Register); + } + %} + ins_pipe(ialu_reg_reg); +%} + +// Zero-extend convert int to long +instruct convI2L_reg_mem_zex(rRegL dst, memory src, immL_32bits mask) +%{ + match(Set dst (AndL (ConvI2L (LoadI src)) mask)); + + format %{ "movl $dst, $src\t# i2l zero-extend\n\t" %} + ins_encode %{ + __ movl($dst$$Register, $src$$Address); + %} + ins_pipe(ialu_reg_mem); +%} + +instruct zerox_long_reg_reg(rRegL dst, rRegL src, immL_32bits mask) +%{ + match(Set dst (AndL src mask)); + + format %{ "movl $dst, $src\t# zero-extend long" %} + ins_encode %{ + __ movl($dst$$Register, $src$$Register); + %} + ins_pipe(ialu_reg_reg); +%} + +instruct convL2I_reg_reg(rRegI dst, rRegL src) +%{ + match(Set dst (ConvL2I src)); + + format %{ "movl $dst, $src\t# l2i" %} + ins_encode %{ + __ movl($dst$$Register, $src$$Register); + %} + ins_pipe(ialu_reg_reg); +%} + + +instruct MoveF2I_stack_reg(rRegI dst, stackSlotF src) %{ + match(Set dst (MoveF2I src)); + effect(DEF dst, USE src); + + ins_cost(125); + format %{ "movl $dst, $src\t# MoveF2I_stack_reg" %} + ins_encode %{ + __ movl($dst$$Register, Address(rsp, $src$$disp)); + %} + ins_pipe(ialu_reg_mem); +%} + +instruct MoveI2F_stack_reg(regF dst, stackSlotI src) %{ + match(Set dst (MoveI2F src)); + effect(DEF dst, USE src); + + ins_cost(125); + format %{ "movss $dst, $src\t# MoveI2F_stack_reg" %} + ins_encode %{ + __ movflt($dst$$XMMRegister, Address(rsp, $src$$disp)); + %} + ins_pipe(pipe_slow); +%} + +instruct MoveD2L_stack_reg(rRegL dst, stackSlotD src) %{ + match(Set dst (MoveD2L src)); + effect(DEF dst, USE src); + + ins_cost(125); + format %{ "movq $dst, $src\t# MoveD2L_stack_reg" %} + ins_encode %{ + __ movq($dst$$Register, Address(rsp, $src$$disp)); + %} + ins_pipe(ialu_reg_mem); +%} + +instruct MoveL2D_stack_reg_partial(regD dst, stackSlotL src) %{ + predicate(!UseXmmLoadAndClearUpper); + match(Set dst (MoveL2D src)); + effect(DEF dst, USE src); + + ins_cost(125); + format %{ "movlpd $dst, $src\t# MoveL2D_stack_reg" %} + ins_encode %{ + __ movdbl($dst$$XMMRegister, Address(rsp, $src$$disp)); + %} + ins_pipe(pipe_slow); +%} + +instruct MoveL2D_stack_reg(regD dst, stackSlotL src) %{ + predicate(UseXmmLoadAndClearUpper); + match(Set dst (MoveL2D src)); + effect(DEF dst, USE src); + + ins_cost(125); + format %{ "movsd $dst, $src\t# MoveL2D_stack_reg" %} + ins_encode %{ + __ movdbl($dst$$XMMRegister, Address(rsp, $src$$disp)); + %} + ins_pipe(pipe_slow); +%} + + +instruct MoveF2I_reg_stack(stackSlotI dst, regF src) %{ + match(Set dst (MoveF2I src)); + effect(DEF dst, USE src); + + ins_cost(95); // XXX + format %{ "movss $dst, $src\t# MoveF2I_reg_stack" %} + ins_encode %{ + __ movflt(Address(rsp, $dst$$disp), $src$$XMMRegister); + %} + ins_pipe(pipe_slow); +%} + +instruct MoveI2F_reg_stack(stackSlotF dst, rRegI src) %{ + match(Set dst (MoveI2F src)); + effect(DEF dst, USE src); + + ins_cost(100); + format %{ "movl $dst, $src\t# MoveI2F_reg_stack" %} + ins_encode %{ + __ movl(Address(rsp, $dst$$disp), $src$$Register); + %} + ins_pipe( ialu_mem_reg ); +%} + +instruct MoveD2L_reg_stack(stackSlotL dst, regD src) %{ + match(Set dst (MoveD2L src)); + effect(DEF dst, USE src); + + ins_cost(95); // XXX + format %{ "movsd $dst, $src\t# MoveL2D_reg_stack" %} + ins_encode %{ + __ movdbl(Address(rsp, $dst$$disp), $src$$XMMRegister); + %} + ins_pipe(pipe_slow); +%} + +instruct MoveL2D_reg_stack(stackSlotD dst, rRegL src) %{ + match(Set dst (MoveL2D src)); + effect(DEF dst, USE src); + + ins_cost(100); + format %{ "movq $dst, $src\t# MoveL2D_reg_stack" %} + ins_encode %{ + __ movq(Address(rsp, $dst$$disp), $src$$Register); + %} + ins_pipe(ialu_mem_reg); +%} + +instruct MoveF2I_reg_reg(rRegI dst, regF src) %{ + match(Set dst (MoveF2I src)); + effect(DEF dst, USE src); + ins_cost(85); + format %{ "movd $dst,$src\t# MoveF2I" %} + ins_encode %{ + __ movdl($dst$$Register, $src$$XMMRegister); + %} + ins_pipe( pipe_slow ); +%} + +instruct MoveD2L_reg_reg(rRegL dst, regD src) %{ + match(Set dst (MoveD2L src)); + effect(DEF dst, USE src); + ins_cost(85); + format %{ "movd $dst,$src\t# MoveD2L" %} + ins_encode %{ + __ movdq($dst$$Register, $src$$XMMRegister); + %} + ins_pipe( pipe_slow ); +%} + +instruct MoveI2F_reg_reg(regF dst, rRegI src) %{ + match(Set dst (MoveI2F src)); + effect(DEF dst, USE src); + ins_cost(100); + format %{ "movd $dst,$src\t# MoveI2F" %} + ins_encode %{ + __ movdl($dst$$XMMRegister, $src$$Register); + %} + ins_pipe( pipe_slow ); +%} + +instruct MoveL2D_reg_reg(regD dst, rRegL src) %{ + match(Set dst (MoveL2D src)); + effect(DEF dst, USE src); + ins_cost(100); + format %{ "movd $dst,$src\t# MoveL2D" %} + ins_encode %{ + __ movdq($dst$$XMMRegister, $src$$Register); + %} + ins_pipe( pipe_slow ); +%} + +// Fast clearing of an array +// Small non-constant lenght ClearArray for non-AVX512 targets. +instruct rep_stos(rcx_RegL cnt, rdi_RegP base, regD tmp, rax_RegI zero, + Universe dummy, rFlagsReg cr) +%{ + predicate(!((ClearArrayNode*)n)->is_large() && (UseAVX <= 2)); + match(Set dummy (ClearArray cnt base)); + effect(USE_KILL cnt, USE_KILL base, TEMP tmp, KILL zero, KILL cr); + + format %{ $$template + $$emit$$"xorq rax, rax\t# ClearArray:\n\t" + $$emit$$"cmp InitArrayShortSize,rcx\n\t" + $$emit$$"jg LARGE\n\t" + $$emit$$"dec rcx\n\t" + $$emit$$"js DONE\t# Zero length\n\t" + $$emit$$"mov rax,(rdi,rcx,8)\t# LOOP\n\t" + $$emit$$"dec rcx\n\t" + $$emit$$"jge LOOP\n\t" + $$emit$$"jmp DONE\n\t" + $$emit$$"# LARGE:\n\t" + if (UseFastStosb) { + $$emit$$"shlq rcx,3\t# Convert doublewords to bytes\n\t" + $$emit$$"rep stosb\t# Store rax to *rdi++ while rcx--\n\t" + } else if (UseXMMForObjInit) { + $$emit$$"mov rdi,rax\n\t" + $$emit$$"vpxor ymm0,ymm0,ymm0\n\t" + $$emit$$"jmpq L_zero_64_bytes\n\t" + $$emit$$"# L_loop:\t# 64-byte LOOP\n\t" + $$emit$$"vmovdqu ymm0,(rax)\n\t" + $$emit$$"vmovdqu ymm0,0x20(rax)\n\t" + $$emit$$"add 0x40,rax\n\t" + $$emit$$"# L_zero_64_bytes:\n\t" + $$emit$$"sub 0x8,rcx\n\t" + $$emit$$"jge L_loop\n\t" + $$emit$$"add 0x4,rcx\n\t" + $$emit$$"jl L_tail\n\t" + $$emit$$"vmovdqu ymm0,(rax)\n\t" + $$emit$$"add 0x20,rax\n\t" + $$emit$$"sub 0x4,rcx\n\t" + $$emit$$"# L_tail:\t# Clearing tail bytes\n\t" + $$emit$$"add 0x4,rcx\n\t" + $$emit$$"jle L_end\n\t" + $$emit$$"dec rcx\n\t" + $$emit$$"# L_sloop:\t# 8-byte short loop\n\t" + $$emit$$"vmovq xmm0,(rax)\n\t" + $$emit$$"add 0x8,rax\n\t" + $$emit$$"dec rcx\n\t" + $$emit$$"jge L_sloop\n\t" + $$emit$$"# L_end:\n\t" + } else { + $$emit$$"rep stosq\t# Store rax to *rdi++ while rcx--\n\t" + } + $$emit$$"# DONE" + %} + ins_encode %{ + __ clear_mem($base$$Register, $cnt$$Register, $zero$$Register, + $tmp$$XMMRegister, false, knoreg); + %} + ins_pipe(pipe_slow); +%} + +// Small non-constant length ClearArray for AVX512 targets. +instruct rep_stos_evex(rcx_RegL cnt, rdi_RegP base, legRegD tmp, kReg ktmp, rax_RegI zero, + Universe dummy, rFlagsReg cr) +%{ + predicate(!((ClearArrayNode*)n)->is_large() && (UseAVX > 2)); + match(Set dummy (ClearArray cnt base)); + ins_cost(125); + effect(USE_KILL cnt, USE_KILL base, TEMP tmp, TEMP ktmp, KILL zero, KILL cr); + + format %{ $$template + $$emit$$"xorq rax, rax\t# ClearArray:\n\t" + $$emit$$"cmp InitArrayShortSize,rcx\n\t" + $$emit$$"jg LARGE\n\t" + $$emit$$"dec rcx\n\t" + $$emit$$"js DONE\t# Zero length\n\t" + $$emit$$"mov rax,(rdi,rcx,8)\t# LOOP\n\t" + $$emit$$"dec rcx\n\t" + $$emit$$"jge LOOP\n\t" + $$emit$$"jmp DONE\n\t" + $$emit$$"# LARGE:\n\t" + if (UseFastStosb) { + $$emit$$"shlq rcx,3\t# Convert doublewords to bytes\n\t" + $$emit$$"rep stosb\t# Store rax to *rdi++ while rcx--\n\t" + } else if (UseXMMForObjInit) { + $$emit$$"mov rdi,rax\n\t" + $$emit$$"vpxor ymm0,ymm0,ymm0\n\t" + $$emit$$"jmpq L_zero_64_bytes\n\t" + $$emit$$"# L_loop:\t# 64-byte LOOP\n\t" + $$emit$$"vmovdqu ymm0,(rax)\n\t" + $$emit$$"vmovdqu ymm0,0x20(rax)\n\t" + $$emit$$"add 0x40,rax\n\t" + $$emit$$"# L_zero_64_bytes:\n\t" + $$emit$$"sub 0x8,rcx\n\t" + $$emit$$"jge L_loop\n\t" + $$emit$$"add 0x4,rcx\n\t" + $$emit$$"jl L_tail\n\t" + $$emit$$"vmovdqu ymm0,(rax)\n\t" + $$emit$$"add 0x20,rax\n\t" + $$emit$$"sub 0x4,rcx\n\t" + $$emit$$"# L_tail:\t# Clearing tail bytes\n\t" + $$emit$$"add 0x4,rcx\n\t" + $$emit$$"jle L_end\n\t" + $$emit$$"dec rcx\n\t" + $$emit$$"# L_sloop:\t# 8-byte short loop\n\t" + $$emit$$"vmovq xmm0,(rax)\n\t" + $$emit$$"add 0x8,rax\n\t" + $$emit$$"dec rcx\n\t" + $$emit$$"jge L_sloop\n\t" + $$emit$$"# L_end:\n\t" + } else { + $$emit$$"rep stosq\t# Store rax to *rdi++ while rcx--\n\t" + } + $$emit$$"# DONE" + %} + ins_encode %{ + __ clear_mem($base$$Register, $cnt$$Register, $zero$$Register, + $tmp$$XMMRegister, false, $ktmp$$KRegister); + %} + ins_pipe(pipe_slow); +%} + +// Large non-constant length ClearArray for non-AVX512 targets. +instruct rep_stos_large(rcx_RegL cnt, rdi_RegP base, regD tmp, rax_RegI zero, + Universe dummy, rFlagsReg cr) +%{ + predicate((UseAVX <=2) && ((ClearArrayNode*)n)->is_large()); + match(Set dummy (ClearArray cnt base)); + effect(USE_KILL cnt, USE_KILL base, TEMP tmp, KILL zero, KILL cr); + + format %{ $$template + if (UseFastStosb) { + $$emit$$"xorq rax, rax\t# ClearArray:\n\t" + $$emit$$"shlq rcx,3\t# Convert doublewords to bytes\n\t" + $$emit$$"rep stosb\t# Store rax to *rdi++ while rcx--" + } else if (UseXMMForObjInit) { + $$emit$$"mov rdi,rax\t# ClearArray:\n\t" + $$emit$$"vpxor ymm0,ymm0,ymm0\n\t" + $$emit$$"jmpq L_zero_64_bytes\n\t" + $$emit$$"# L_loop:\t# 64-byte LOOP\n\t" + $$emit$$"vmovdqu ymm0,(rax)\n\t" + $$emit$$"vmovdqu ymm0,0x20(rax)\n\t" + $$emit$$"add 0x40,rax\n\t" + $$emit$$"# L_zero_64_bytes:\n\t" + $$emit$$"sub 0x8,rcx\n\t" + $$emit$$"jge L_loop\n\t" + $$emit$$"add 0x4,rcx\n\t" + $$emit$$"jl L_tail\n\t" + $$emit$$"vmovdqu ymm0,(rax)\n\t" + $$emit$$"add 0x20,rax\n\t" + $$emit$$"sub 0x4,rcx\n\t" + $$emit$$"# L_tail:\t# Clearing tail bytes\n\t" + $$emit$$"add 0x4,rcx\n\t" + $$emit$$"jle L_end\n\t" + $$emit$$"dec rcx\n\t" + $$emit$$"# L_sloop:\t# 8-byte short loop\n\t" + $$emit$$"vmovq xmm0,(rax)\n\t" + $$emit$$"add 0x8,rax\n\t" + $$emit$$"dec rcx\n\t" + $$emit$$"jge L_sloop\n\t" + $$emit$$"# L_end:\n\t" + } else { + $$emit$$"xorq rax, rax\t# ClearArray:\n\t" + $$emit$$"rep stosq\t# Store rax to *rdi++ while rcx--" + } + %} + ins_encode %{ + __ clear_mem($base$$Register, $cnt$$Register, $zero$$Register, + $tmp$$XMMRegister, true, knoreg); + %} + ins_pipe(pipe_slow); +%} + +// Large non-constant length ClearArray for AVX512 targets. +instruct rep_stos_large_evex(rcx_RegL cnt, rdi_RegP base, legRegD tmp, kReg ktmp, rax_RegI zero, + Universe dummy, rFlagsReg cr) +%{ + predicate((UseAVX > 2) && ((ClearArrayNode*)n)->is_large()); + match(Set dummy (ClearArray cnt base)); + effect(USE_KILL cnt, USE_KILL base, TEMP tmp, TEMP ktmp, KILL zero, KILL cr); + + format %{ $$template + if (UseFastStosb) { + $$emit$$"xorq rax, rax\t# ClearArray:\n\t" + $$emit$$"shlq rcx,3\t# Convert doublewords to bytes\n\t" + $$emit$$"rep stosb\t# Store rax to *rdi++ while rcx--" + } else if (UseXMMForObjInit) { + $$emit$$"mov rdi,rax\t# ClearArray:\n\t" + $$emit$$"vpxor ymm0,ymm0,ymm0\n\t" + $$emit$$"jmpq L_zero_64_bytes\n\t" + $$emit$$"# L_loop:\t# 64-byte LOOP\n\t" + $$emit$$"vmovdqu ymm0,(rax)\n\t" + $$emit$$"vmovdqu ymm0,0x20(rax)\n\t" + $$emit$$"add 0x40,rax\n\t" + $$emit$$"# L_zero_64_bytes:\n\t" + $$emit$$"sub 0x8,rcx\n\t" + $$emit$$"jge L_loop\n\t" + $$emit$$"add 0x4,rcx\n\t" + $$emit$$"jl L_tail\n\t" + $$emit$$"vmovdqu ymm0,(rax)\n\t" + $$emit$$"add 0x20,rax\n\t" + $$emit$$"sub 0x4,rcx\n\t" + $$emit$$"# L_tail:\t# Clearing tail bytes\n\t" + $$emit$$"add 0x4,rcx\n\t" + $$emit$$"jle L_end\n\t" + $$emit$$"dec rcx\n\t" + $$emit$$"# L_sloop:\t# 8-byte short loop\n\t" + $$emit$$"vmovq xmm0,(rax)\n\t" + $$emit$$"add 0x8,rax\n\t" + $$emit$$"dec rcx\n\t" + $$emit$$"jge L_sloop\n\t" + $$emit$$"# L_end:\n\t" + } else { + $$emit$$"xorq rax, rax\t# ClearArray:\n\t" + $$emit$$"rep stosq\t# Store rax to *rdi++ while rcx--" + } + %} + ins_encode %{ + __ clear_mem($base$$Register, $cnt$$Register, $zero$$Register, + $tmp$$XMMRegister, true, $ktmp$$KRegister); + %} + ins_pipe(pipe_slow); +%} + +// Small constant length ClearArray for AVX512 targets. +instruct rep_stos_im(immL cnt, rRegP base, regD tmp, rRegI zero, kReg ktmp, Universe dummy, rFlagsReg cr) +%{ + predicate(!((ClearArrayNode*)n)->is_large() && (MaxVectorSize >= 32) && VM_Version::supports_avx512vl()); + match(Set dummy (ClearArray cnt base)); + ins_cost(100); + effect(TEMP tmp, TEMP zero, TEMP ktmp, KILL cr); + format %{ "clear_mem_imm $base , $cnt \n\t" %} + ins_encode %{ + __ clear_mem($base$$Register, $cnt$$constant, $zero$$Register, $tmp$$XMMRegister, $ktmp$$KRegister); + %} + ins_pipe(pipe_slow); +%} + +instruct string_compareL(rdi_RegP str1, rcx_RegI cnt1, rsi_RegP str2, rdx_RegI cnt2, + rax_RegI result, legRegD tmp1, rFlagsReg cr) +%{ + predicate(!VM_Version::supports_avx512vlbw() && ((StrCompNode*)n)->encoding() == StrIntrinsicNode::LL); + match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2))); + effect(TEMP tmp1, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL cr); + + format %{ "String Compare byte[] $str1,$cnt1,$str2,$cnt2 -> $result // KILL $tmp1" %} + ins_encode %{ + __ string_compare($str1$$Register, $str2$$Register, + $cnt1$$Register, $cnt2$$Register, $result$$Register, + $tmp1$$XMMRegister, StrIntrinsicNode::LL, knoreg); + %} + ins_pipe( pipe_slow ); +%} + +instruct string_compareL_evex(rdi_RegP str1, rcx_RegI cnt1, rsi_RegP str2, rdx_RegI cnt2, + rax_RegI result, legRegD tmp1, kReg ktmp, rFlagsReg cr) +%{ + predicate(VM_Version::supports_avx512vlbw() && ((StrCompNode*)n)->encoding() == StrIntrinsicNode::LL); + match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2))); + effect(TEMP tmp1, TEMP ktmp, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL cr); + + format %{ "String Compare byte[] $str1,$cnt1,$str2,$cnt2 -> $result // KILL $tmp1" %} + ins_encode %{ + __ string_compare($str1$$Register, $str2$$Register, + $cnt1$$Register, $cnt2$$Register, $result$$Register, + $tmp1$$XMMRegister, StrIntrinsicNode::LL, $ktmp$$KRegister); + %} + ins_pipe( pipe_slow ); +%} + +instruct string_compareU(rdi_RegP str1, rcx_RegI cnt1, rsi_RegP str2, rdx_RegI cnt2, + rax_RegI result, legRegD tmp1, rFlagsReg cr) +%{ + predicate(!VM_Version::supports_avx512vlbw() && ((StrCompNode*)n)->encoding() == StrIntrinsicNode::UU); + match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2))); + effect(TEMP tmp1, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL cr); + + format %{ "String Compare char[] $str1,$cnt1,$str2,$cnt2 -> $result // KILL $tmp1" %} + ins_encode %{ + __ string_compare($str1$$Register, $str2$$Register, + $cnt1$$Register, $cnt2$$Register, $result$$Register, + $tmp1$$XMMRegister, StrIntrinsicNode::UU, knoreg); + %} + ins_pipe( pipe_slow ); +%} + +instruct string_compareU_evex(rdi_RegP str1, rcx_RegI cnt1, rsi_RegP str2, rdx_RegI cnt2, + rax_RegI result, legRegD tmp1, kReg ktmp, rFlagsReg cr) +%{ + predicate(VM_Version::supports_avx512vlbw() && ((StrCompNode*)n)->encoding() == StrIntrinsicNode::UU); + match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2))); + effect(TEMP tmp1, TEMP ktmp, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL cr); + + format %{ "String Compare char[] $str1,$cnt1,$str2,$cnt2 -> $result // KILL $tmp1" %} + ins_encode %{ + __ string_compare($str1$$Register, $str2$$Register, + $cnt1$$Register, $cnt2$$Register, $result$$Register, + $tmp1$$XMMRegister, StrIntrinsicNode::UU, $ktmp$$KRegister); + %} + ins_pipe( pipe_slow ); +%} + +instruct string_compareLU(rdi_RegP str1, rcx_RegI cnt1, rsi_RegP str2, rdx_RegI cnt2, + rax_RegI result, legRegD tmp1, rFlagsReg cr) +%{ + predicate(!VM_Version::supports_avx512vlbw() && ((StrCompNode*)n)->encoding() == StrIntrinsicNode::LU); + match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2))); + effect(TEMP tmp1, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL cr); + + format %{ "String Compare byte[] $str1,$cnt1,$str2,$cnt2 -> $result // KILL $tmp1" %} + ins_encode %{ + __ string_compare($str1$$Register, $str2$$Register, + $cnt1$$Register, $cnt2$$Register, $result$$Register, + $tmp1$$XMMRegister, StrIntrinsicNode::LU, knoreg); + %} + ins_pipe( pipe_slow ); +%} + +instruct string_compareLU_evex(rdi_RegP str1, rcx_RegI cnt1, rsi_RegP str2, rdx_RegI cnt2, + rax_RegI result, legRegD tmp1, kReg ktmp, rFlagsReg cr) +%{ + predicate(VM_Version::supports_avx512vlbw() && ((StrCompNode*)n)->encoding() == StrIntrinsicNode::LU); + match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2))); + effect(TEMP tmp1, TEMP ktmp, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL cr); + + format %{ "String Compare byte[] $str1,$cnt1,$str2,$cnt2 -> $result // KILL $tmp1" %} + ins_encode %{ + __ string_compare($str1$$Register, $str2$$Register, + $cnt1$$Register, $cnt2$$Register, $result$$Register, + $tmp1$$XMMRegister, StrIntrinsicNode::LU, $ktmp$$KRegister); + %} + ins_pipe( pipe_slow ); +%} + +instruct string_compareUL(rsi_RegP str1, rdx_RegI cnt1, rdi_RegP str2, rcx_RegI cnt2, + rax_RegI result, legRegD tmp1, rFlagsReg cr) +%{ + predicate(!VM_Version::supports_avx512vlbw() && ((StrCompNode*)n)->encoding() == StrIntrinsicNode::UL); + match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2))); + effect(TEMP tmp1, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL cr); + + format %{ "String Compare byte[] $str1,$cnt1,$str2,$cnt2 -> $result // KILL $tmp1" %} + ins_encode %{ + __ string_compare($str2$$Register, $str1$$Register, + $cnt2$$Register, $cnt1$$Register, $result$$Register, + $tmp1$$XMMRegister, StrIntrinsicNode::UL, knoreg); + %} + ins_pipe( pipe_slow ); +%} + +instruct string_compareUL_evex(rsi_RegP str1, rdx_RegI cnt1, rdi_RegP str2, rcx_RegI cnt2, + rax_RegI result, legRegD tmp1, kReg ktmp, rFlagsReg cr) +%{ + predicate(VM_Version::supports_avx512vlbw() && ((StrCompNode*)n)->encoding() == StrIntrinsicNode::UL); + match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2))); + effect(TEMP tmp1, TEMP ktmp, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL cr); + + format %{ "String Compare byte[] $str1,$cnt1,$str2,$cnt2 -> $result // KILL $tmp1" %} + ins_encode %{ + __ string_compare($str2$$Register, $str1$$Register, + $cnt2$$Register, $cnt1$$Register, $result$$Register, + $tmp1$$XMMRegister, StrIntrinsicNode::UL, $ktmp$$KRegister); + %} + ins_pipe( pipe_slow ); +%} + +// fast search of substring with known size. +instruct string_indexof_conL(rdi_RegP str1, rdx_RegI cnt1, rsi_RegP str2, immI int_cnt2, + rbx_RegI result, legRegD tmp_vec, rax_RegI cnt2, rcx_RegI tmp, rFlagsReg cr) +%{ + predicate(UseSSE42Intrinsics && (((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::LL)); + match(Set result (StrIndexOf (Binary str1 cnt1) (Binary str2 int_cnt2))); + effect(TEMP tmp_vec, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, KILL cnt2, KILL tmp, KILL cr); + + format %{ "String IndexOf byte[] $str1,$cnt1,$str2,$int_cnt2 -> $result // KILL $tmp_vec, $cnt1, $cnt2, $tmp" %} + ins_encode %{ + int icnt2 = (int)$int_cnt2$$constant; + if (icnt2 >= 16) { + // IndexOf for constant substrings with size >= 16 elements + // which don't need to be loaded through stack. + __ string_indexofC8($str1$$Register, $str2$$Register, + $cnt1$$Register, $cnt2$$Register, + icnt2, $result$$Register, + $tmp_vec$$XMMRegister, $tmp$$Register, StrIntrinsicNode::LL); + } else { + // Small strings are loaded through stack if they cross page boundary. + __ string_indexof($str1$$Register, $str2$$Register, + $cnt1$$Register, $cnt2$$Register, + icnt2, $result$$Register, + $tmp_vec$$XMMRegister, $tmp$$Register, StrIntrinsicNode::LL); + } + %} + ins_pipe( pipe_slow ); +%} + +// fast search of substring with known size. +instruct string_indexof_conU(rdi_RegP str1, rdx_RegI cnt1, rsi_RegP str2, immI int_cnt2, + rbx_RegI result, legRegD tmp_vec, rax_RegI cnt2, rcx_RegI tmp, rFlagsReg cr) +%{ + predicate(UseSSE42Intrinsics && (((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::UU)); + match(Set result (StrIndexOf (Binary str1 cnt1) (Binary str2 int_cnt2))); + effect(TEMP tmp_vec, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, KILL cnt2, KILL tmp, KILL cr); + + format %{ "String IndexOf char[] $str1,$cnt1,$str2,$int_cnt2 -> $result // KILL $tmp_vec, $cnt1, $cnt2, $tmp" %} + ins_encode %{ + int icnt2 = (int)$int_cnt2$$constant; + if (icnt2 >= 8) { + // IndexOf for constant substrings with size >= 8 elements + // which don't need to be loaded through stack. + __ string_indexofC8($str1$$Register, $str2$$Register, + $cnt1$$Register, $cnt2$$Register, + icnt2, $result$$Register, + $tmp_vec$$XMMRegister, $tmp$$Register, StrIntrinsicNode::UU); + } else { + // Small strings are loaded through stack if they cross page boundary. + __ string_indexof($str1$$Register, $str2$$Register, + $cnt1$$Register, $cnt2$$Register, + icnt2, $result$$Register, + $tmp_vec$$XMMRegister, $tmp$$Register, StrIntrinsicNode::UU); + } + %} + ins_pipe( pipe_slow ); +%} + +// fast search of substring with known size. +instruct string_indexof_conUL(rdi_RegP str1, rdx_RegI cnt1, rsi_RegP str2, immI int_cnt2, + rbx_RegI result, legRegD tmp_vec, rax_RegI cnt2, rcx_RegI tmp, rFlagsReg cr) +%{ + predicate(UseSSE42Intrinsics && (((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::UL)); + match(Set result (StrIndexOf (Binary str1 cnt1) (Binary str2 int_cnt2))); + effect(TEMP tmp_vec, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, KILL cnt2, KILL tmp, KILL cr); + + format %{ "String IndexOf char[] $str1,$cnt1,$str2,$int_cnt2 -> $result // KILL $tmp_vec, $cnt1, $cnt2, $tmp" %} + ins_encode %{ + int icnt2 = (int)$int_cnt2$$constant; + if (icnt2 >= 8) { + // IndexOf for constant substrings with size >= 8 elements + // which don't need to be loaded through stack. + __ string_indexofC8($str1$$Register, $str2$$Register, + $cnt1$$Register, $cnt2$$Register, + icnt2, $result$$Register, + $tmp_vec$$XMMRegister, $tmp$$Register, StrIntrinsicNode::UL); + } else { + // Small strings are loaded through stack if they cross page boundary. + __ string_indexof($str1$$Register, $str2$$Register, + $cnt1$$Register, $cnt2$$Register, + icnt2, $result$$Register, + $tmp_vec$$XMMRegister, $tmp$$Register, StrIntrinsicNode::UL); + } + %} + ins_pipe( pipe_slow ); +%} + +instruct string_indexofL(rdi_RegP str1, rdx_RegI cnt1, rsi_RegP str2, rax_RegI cnt2, + rbx_RegI result, legRegD tmp_vec, rcx_RegI tmp, rFlagsReg cr) +%{ + predicate(UseSSE42Intrinsics && (((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::LL)); + match(Set result (StrIndexOf (Binary str1 cnt1) (Binary str2 cnt2))); + effect(TEMP tmp_vec, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL tmp, KILL cr); + + format %{ "String IndexOf byte[] $str1,$cnt1,$str2,$cnt2 -> $result // KILL all" %} + ins_encode %{ + __ string_indexof($str1$$Register, $str2$$Register, + $cnt1$$Register, $cnt2$$Register, + (-1), $result$$Register, + $tmp_vec$$XMMRegister, $tmp$$Register, StrIntrinsicNode::LL); + %} + ins_pipe( pipe_slow ); +%} + +instruct string_indexofU(rdi_RegP str1, rdx_RegI cnt1, rsi_RegP str2, rax_RegI cnt2, + rbx_RegI result, legRegD tmp_vec, rcx_RegI tmp, rFlagsReg cr) +%{ + predicate(UseSSE42Intrinsics && (((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::UU)); + match(Set result (StrIndexOf (Binary str1 cnt1) (Binary str2 cnt2))); + effect(TEMP tmp_vec, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL tmp, KILL cr); + + format %{ "String IndexOf char[] $str1,$cnt1,$str2,$cnt2 -> $result // KILL all" %} + ins_encode %{ + __ string_indexof($str1$$Register, $str2$$Register, + $cnt1$$Register, $cnt2$$Register, + (-1), $result$$Register, + $tmp_vec$$XMMRegister, $tmp$$Register, StrIntrinsicNode::UU); + %} + ins_pipe( pipe_slow ); +%} + +instruct string_indexofUL(rdi_RegP str1, rdx_RegI cnt1, rsi_RegP str2, rax_RegI cnt2, + rbx_RegI result, legRegD tmp_vec, rcx_RegI tmp, rFlagsReg cr) +%{ + predicate(UseSSE42Intrinsics && (((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::UL)); + match(Set result (StrIndexOf (Binary str1 cnt1) (Binary str2 cnt2))); + effect(TEMP tmp_vec, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL tmp, KILL cr); + + format %{ "String IndexOf char[] $str1,$cnt1,$str2,$cnt2 -> $result // KILL all" %} + ins_encode %{ + __ string_indexof($str1$$Register, $str2$$Register, + $cnt1$$Register, $cnt2$$Register, + (-1), $result$$Register, + $tmp_vec$$XMMRegister, $tmp$$Register, StrIntrinsicNode::UL); + %} + ins_pipe( pipe_slow ); +%} + +instruct string_indexof_char(rdi_RegP str1, rdx_RegI cnt1, rax_RegI ch, + rbx_RegI result, legRegD tmp_vec1, legRegD tmp_vec2, legRegD tmp_vec3, rcx_RegI tmp, rFlagsReg cr) +%{ + predicate(UseSSE42Intrinsics && (((StrIndexOfCharNode*)n)->encoding() == StrIntrinsicNode::U)); + match(Set result (StrIndexOfChar (Binary str1 cnt1) ch)); + effect(TEMP tmp_vec1, TEMP tmp_vec2, TEMP tmp_vec3, USE_KILL str1, USE_KILL cnt1, USE_KILL ch, TEMP tmp, KILL cr); + format %{ "StringUTF16 IndexOf char[] $str1,$cnt1,$ch -> $result // KILL all" %} + ins_encode %{ + __ string_indexof_char($str1$$Register, $cnt1$$Register, $ch$$Register, $result$$Register, + $tmp_vec1$$XMMRegister, $tmp_vec2$$XMMRegister, $tmp_vec3$$XMMRegister, $tmp$$Register); + %} + ins_pipe( pipe_slow ); +%} + +instruct stringL_indexof_char(rdi_RegP str1, rdx_RegI cnt1, rax_RegI ch, + rbx_RegI result, legRegD tmp_vec1, legRegD tmp_vec2, legRegD tmp_vec3, rcx_RegI tmp, rFlagsReg cr) +%{ + predicate(UseSSE42Intrinsics && (((StrIndexOfCharNode*)n)->encoding() == StrIntrinsicNode::L)); + match(Set result (StrIndexOfChar (Binary str1 cnt1) ch)); + effect(TEMP tmp_vec1, TEMP tmp_vec2, TEMP tmp_vec3, USE_KILL str1, USE_KILL cnt1, USE_KILL ch, TEMP tmp, KILL cr); + format %{ "StringLatin1 IndexOf char[] $str1,$cnt1,$ch -> $result // KILL all" %} + ins_encode %{ + __ stringL_indexof_char($str1$$Register, $cnt1$$Register, $ch$$Register, $result$$Register, + $tmp_vec1$$XMMRegister, $tmp_vec2$$XMMRegister, $tmp_vec3$$XMMRegister, $tmp$$Register); + %} + ins_pipe( pipe_slow ); +%} + +// fast string equals +instruct string_equals(rdi_RegP str1, rsi_RegP str2, rcx_RegI cnt, rax_RegI result, + legRegD tmp1, legRegD tmp2, rbx_RegI tmp3, rFlagsReg cr) +%{ + predicate(!VM_Version::supports_avx512vlbw()); + match(Set result (StrEquals (Binary str1 str2) cnt)); + effect(TEMP tmp1, TEMP tmp2, USE_KILL str1, USE_KILL str2, USE_KILL cnt, KILL tmp3, KILL cr); + + format %{ "String Equals $str1,$str2,$cnt -> $result // KILL $tmp1, $tmp2, $tmp3" %} + ins_encode %{ + __ arrays_equals(false, $str1$$Register, $str2$$Register, + $cnt$$Register, $result$$Register, $tmp3$$Register, + $tmp1$$XMMRegister, $tmp2$$XMMRegister, false /* char */, knoreg); + %} + ins_pipe( pipe_slow ); +%} + +instruct string_equals_evex(rdi_RegP str1, rsi_RegP str2, rcx_RegI cnt, rax_RegI result, + legRegD tmp1, legRegD tmp2, kReg ktmp, rbx_RegI tmp3, rFlagsReg cr) +%{ + predicate(VM_Version::supports_avx512vlbw()); + match(Set result (StrEquals (Binary str1 str2) cnt)); + effect(TEMP tmp1, TEMP tmp2, TEMP ktmp, USE_KILL str1, USE_KILL str2, USE_KILL cnt, KILL tmp3, KILL cr); + + format %{ "String Equals $str1,$str2,$cnt -> $result // KILL $tmp1, $tmp2, $tmp3" %} + ins_encode %{ + __ arrays_equals(false, $str1$$Register, $str2$$Register, + $cnt$$Register, $result$$Register, $tmp3$$Register, + $tmp1$$XMMRegister, $tmp2$$XMMRegister, false /* char */, $ktmp$$KRegister); + %} + ins_pipe( pipe_slow ); +%} + +// fast array equals +instruct array_equalsB(rdi_RegP ary1, rsi_RegP ary2, rax_RegI result, + legRegD tmp1, legRegD tmp2, rcx_RegI tmp3, rbx_RegI tmp4, rFlagsReg cr) +%{ + predicate(!VM_Version::supports_avx512vlbw() && ((AryEqNode*)n)->encoding() == StrIntrinsicNode::LL); + match(Set result (AryEq ary1 ary2)); + effect(TEMP tmp1, TEMP tmp2, USE_KILL ary1, USE_KILL ary2, KILL tmp3, KILL tmp4, KILL cr); + + format %{ "Array Equals byte[] $ary1,$ary2 -> $result // KILL $tmp1, $tmp2, $tmp3, $tmp4" %} + ins_encode %{ + __ arrays_equals(true, $ary1$$Register, $ary2$$Register, + $tmp3$$Register, $result$$Register, $tmp4$$Register, + $tmp1$$XMMRegister, $tmp2$$XMMRegister, false /* char */, knoreg); + %} + ins_pipe( pipe_slow ); +%} + +instruct array_equalsB_evex(rdi_RegP ary1, rsi_RegP ary2, rax_RegI result, + legRegD tmp1, legRegD tmp2, kReg ktmp, rcx_RegI tmp3, rbx_RegI tmp4, rFlagsReg cr) +%{ + predicate(VM_Version::supports_avx512vlbw() && ((AryEqNode*)n)->encoding() == StrIntrinsicNode::LL); + match(Set result (AryEq ary1 ary2)); + effect(TEMP tmp1, TEMP tmp2, TEMP ktmp, USE_KILL ary1, USE_KILL ary2, KILL tmp3, KILL tmp4, KILL cr); + + format %{ "Array Equals byte[] $ary1,$ary2 -> $result // KILL $tmp1, $tmp2, $tmp3, $tmp4" %} + ins_encode %{ + __ arrays_equals(true, $ary1$$Register, $ary2$$Register, + $tmp3$$Register, $result$$Register, $tmp4$$Register, + $tmp1$$XMMRegister, $tmp2$$XMMRegister, false /* char */, $ktmp$$KRegister); + %} + ins_pipe( pipe_slow ); +%} + +instruct array_equalsC(rdi_RegP ary1, rsi_RegP ary2, rax_RegI result, + legRegD tmp1, legRegD tmp2, rcx_RegI tmp3, rbx_RegI tmp4, rFlagsReg cr) +%{ + predicate(!VM_Version::supports_avx512vlbw() && ((AryEqNode*)n)->encoding() == StrIntrinsicNode::UU); + match(Set result (AryEq ary1 ary2)); + effect(TEMP tmp1, TEMP tmp2, USE_KILL ary1, USE_KILL ary2, KILL tmp3, KILL tmp4, KILL cr); + + format %{ "Array Equals char[] $ary1,$ary2 -> $result // KILL $tmp1, $tmp2, $tmp3, $tmp4" %} + ins_encode %{ + __ arrays_equals(true, $ary1$$Register, $ary2$$Register, + $tmp3$$Register, $result$$Register, $tmp4$$Register, + $tmp1$$XMMRegister, $tmp2$$XMMRegister, true /* char */, knoreg); + %} + ins_pipe( pipe_slow ); +%} + +instruct array_equalsC_evex(rdi_RegP ary1, rsi_RegP ary2, rax_RegI result, + legRegD tmp1, legRegD tmp2, kReg ktmp, rcx_RegI tmp3, rbx_RegI tmp4, rFlagsReg cr) +%{ + predicate(VM_Version::supports_avx512vlbw() && ((AryEqNode*)n)->encoding() == StrIntrinsicNode::UU); + match(Set result (AryEq ary1 ary2)); + effect(TEMP tmp1, TEMP tmp2, TEMP ktmp, USE_KILL ary1, USE_KILL ary2, KILL tmp3, KILL tmp4, KILL cr); + + format %{ "Array Equals char[] $ary1,$ary2 -> $result // KILL $tmp1, $tmp2, $tmp3, $tmp4" %} + ins_encode %{ + __ arrays_equals(true, $ary1$$Register, $ary2$$Register, + $tmp3$$Register, $result$$Register, $tmp4$$Register, + $tmp1$$XMMRegister, $tmp2$$XMMRegister, true /* char */, $ktmp$$KRegister); + %} + ins_pipe( pipe_slow ); +%} + +instruct arrays_hashcode(rdi_RegP ary1, rdx_RegI cnt1, rbx_RegI result, immU8 basic_type, + legRegD tmp_vec1, legRegD tmp_vec2, legRegD tmp_vec3, legRegD tmp_vec4, + legRegD tmp_vec5, legRegD tmp_vec6, legRegD tmp_vec7, legRegD tmp_vec8, + legRegD tmp_vec9, legRegD tmp_vec10, legRegD tmp_vec11, legRegD tmp_vec12, + legRegD tmp_vec13, rRegI tmp1, rRegI tmp2, rRegI tmp3, rFlagsReg cr) +%{ + predicate(UseAVX >= 2); + match(Set result (VectorizedHashCode (Binary ary1 cnt1) (Binary result basic_type))); + effect(TEMP tmp_vec1, TEMP tmp_vec2, TEMP tmp_vec3, TEMP tmp_vec4, TEMP tmp_vec5, TEMP tmp_vec6, + TEMP tmp_vec7, TEMP tmp_vec8, TEMP tmp_vec9, TEMP tmp_vec10, TEMP tmp_vec11, TEMP tmp_vec12, + TEMP tmp_vec13, TEMP tmp1, TEMP tmp2, TEMP tmp3, USE_KILL ary1, USE_KILL cnt1, + USE basic_type, KILL cr); + + format %{ "Array HashCode array[] $ary1,$cnt1,$result,$basic_type -> $result // KILL all" %} + ins_encode %{ + __ arrays_hashcode($ary1$$Register, $cnt1$$Register, $result$$Register, + $tmp1$$Register, $tmp2$$Register, $tmp3$$Register, + $tmp_vec1$$XMMRegister, $tmp_vec2$$XMMRegister, $tmp_vec3$$XMMRegister, + $tmp_vec4$$XMMRegister, $tmp_vec5$$XMMRegister, $tmp_vec6$$XMMRegister, + $tmp_vec7$$XMMRegister, $tmp_vec8$$XMMRegister, $tmp_vec9$$XMMRegister, + $tmp_vec10$$XMMRegister, $tmp_vec11$$XMMRegister, $tmp_vec12$$XMMRegister, + $tmp_vec13$$XMMRegister, (BasicType)$basic_type$$constant); + %} + ins_pipe( pipe_slow ); +%} + +instruct count_positives(rsi_RegP ary1, rcx_RegI len, rax_RegI result, + legRegD tmp1, legRegD tmp2, rbx_RegI tmp3, rFlagsReg cr,) +%{ + predicate(!VM_Version::supports_avx512vlbw() || !VM_Version::supports_bmi2()); + match(Set result (CountPositives ary1 len)); + effect(TEMP tmp1, TEMP tmp2, USE_KILL ary1, USE_KILL len, KILL tmp3, KILL cr); + + format %{ "countPositives byte[] $ary1,$len -> $result // KILL $tmp1, $tmp2, $tmp3" %} + ins_encode %{ + __ count_positives($ary1$$Register, $len$$Register, + $result$$Register, $tmp3$$Register, + $tmp1$$XMMRegister, $tmp2$$XMMRegister, knoreg, knoreg); + %} + ins_pipe( pipe_slow ); +%} + +instruct count_positives_evex(rsi_RegP ary1, rcx_RegI len, rax_RegI result, + legRegD tmp1, legRegD tmp2, kReg ktmp1, kReg ktmp2, rbx_RegI tmp3, rFlagsReg cr,) +%{ + predicate(VM_Version::supports_avx512vlbw() && VM_Version::supports_bmi2()); + match(Set result (CountPositives ary1 len)); + effect(TEMP tmp1, TEMP tmp2, TEMP ktmp1, TEMP ktmp2, USE_KILL ary1, USE_KILL len, KILL tmp3, KILL cr); + + format %{ "countPositives byte[] $ary1,$len -> $result // KILL $tmp1, $tmp2, $tmp3" %} + ins_encode %{ + __ count_positives($ary1$$Register, $len$$Register, + $result$$Register, $tmp3$$Register, + $tmp1$$XMMRegister, $tmp2$$XMMRegister, $ktmp1$$KRegister, $ktmp2$$KRegister); + %} + ins_pipe( pipe_slow ); +%} + +// fast char[] to byte[] compression +instruct string_compress(rsi_RegP src, rdi_RegP dst, rdx_RegI len, legRegD tmp1, legRegD tmp2, legRegD tmp3, + legRegD tmp4, rcx_RegI tmp5, rax_RegI result, rFlagsReg cr) %{ + predicate(!VM_Version::supports_avx512vlbw() || !VM_Version::supports_bmi2()); + match(Set result (StrCompressedCopy src (Binary dst len))); + effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, USE_KILL src, USE_KILL dst, + USE_KILL len, KILL tmp5, KILL cr); + + format %{ "String Compress $src,$dst -> $result // KILL RAX, RCX, RDX" %} + ins_encode %{ + __ char_array_compress($src$$Register, $dst$$Register, $len$$Register, + $tmp1$$XMMRegister, $tmp2$$XMMRegister, $tmp3$$XMMRegister, + $tmp4$$XMMRegister, $tmp5$$Register, $result$$Register, + knoreg, knoreg); + %} + ins_pipe( pipe_slow ); +%} + +instruct string_compress_evex(rsi_RegP src, rdi_RegP dst, rdx_RegI len, legRegD tmp1, legRegD tmp2, legRegD tmp3, + legRegD tmp4, kReg ktmp1, kReg ktmp2, rcx_RegI tmp5, rax_RegI result, rFlagsReg cr) %{ + predicate(VM_Version::supports_avx512vlbw() && VM_Version::supports_bmi2()); + match(Set result (StrCompressedCopy src (Binary dst len))); + effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, TEMP ktmp1, TEMP ktmp2, USE_KILL src, USE_KILL dst, + USE_KILL len, KILL tmp5, KILL cr); + + format %{ "String Compress $src,$dst -> $result // KILL RAX, RCX, RDX" %} + ins_encode %{ + __ char_array_compress($src$$Register, $dst$$Register, $len$$Register, + $tmp1$$XMMRegister, $tmp2$$XMMRegister, $tmp3$$XMMRegister, + $tmp4$$XMMRegister, $tmp5$$Register, $result$$Register, + $ktmp1$$KRegister, $ktmp2$$KRegister); + %} + ins_pipe( pipe_slow ); +%} +// fast byte[] to char[] inflation +instruct string_inflate(Universe dummy, rsi_RegP src, rdi_RegP dst, rdx_RegI len, + legRegD tmp1, rcx_RegI tmp2, rFlagsReg cr) %{ + predicate(!VM_Version::supports_avx512vlbw() || !VM_Version::supports_bmi2()); + match(Set dummy (StrInflatedCopy src (Binary dst len))); + effect(TEMP tmp1, TEMP tmp2, USE_KILL src, USE_KILL dst, USE_KILL len, KILL cr); + + format %{ "String Inflate $src,$dst // KILL $tmp1, $tmp2" %} + ins_encode %{ + __ byte_array_inflate($src$$Register, $dst$$Register, $len$$Register, + $tmp1$$XMMRegister, $tmp2$$Register, knoreg); + %} + ins_pipe( pipe_slow ); +%} + +instruct string_inflate_evex(Universe dummy, rsi_RegP src, rdi_RegP dst, rdx_RegI len, + legRegD tmp1, kReg ktmp, rcx_RegI tmp2, rFlagsReg cr) %{ + predicate(VM_Version::supports_avx512vlbw() && VM_Version::supports_bmi2()); + match(Set dummy (StrInflatedCopy src (Binary dst len))); + effect(TEMP tmp1, TEMP tmp2, TEMP ktmp, USE_KILL src, USE_KILL dst, USE_KILL len, KILL cr); + + format %{ "String Inflate $src,$dst // KILL $tmp1, $tmp2" %} + ins_encode %{ + __ byte_array_inflate($src$$Register, $dst$$Register, $len$$Register, + $tmp1$$XMMRegister, $tmp2$$Register, $ktmp$$KRegister); + %} + ins_pipe( pipe_slow ); +%} + +// encode char[] to byte[] in ISO_8859_1 +instruct encode_iso_array(rsi_RegP src, rdi_RegP dst, rdx_RegI len, + legRegD tmp1, legRegD tmp2, legRegD tmp3, legRegD tmp4, + rcx_RegI tmp5, rax_RegI result, rFlagsReg cr) %{ + predicate(!((EncodeISOArrayNode*)n)->is_ascii()); + match(Set result (EncodeISOArray src (Binary dst len))); + effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, USE_KILL src, USE_KILL dst, USE_KILL len, KILL tmp5, KILL cr); + + format %{ "Encode iso array $src,$dst,$len -> $result // KILL RCX, RDX, $tmp1, $tmp2, $tmp3, $tmp4, RSI, RDI " %} + ins_encode %{ + __ encode_iso_array($src$$Register, $dst$$Register, $len$$Register, + $tmp1$$XMMRegister, $tmp2$$XMMRegister, $tmp3$$XMMRegister, + $tmp4$$XMMRegister, $tmp5$$Register, $result$$Register, false); + %} + ins_pipe( pipe_slow ); +%} + +// encode char[] to byte[] in ASCII +instruct encode_ascii_array(rsi_RegP src, rdi_RegP dst, rdx_RegI len, + legRegD tmp1, legRegD tmp2, legRegD tmp3, legRegD tmp4, + rcx_RegI tmp5, rax_RegI result, rFlagsReg cr) %{ + predicate(((EncodeISOArrayNode*)n)->is_ascii()); + match(Set result (EncodeISOArray src (Binary dst len))); + effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, USE_KILL src, USE_KILL dst, USE_KILL len, KILL tmp5, KILL cr); + + format %{ "Encode ascii array $src,$dst,$len -> $result // KILL RCX, RDX, $tmp1, $tmp2, $tmp3, $tmp4, RSI, RDI " %} + ins_encode %{ + __ encode_iso_array($src$$Register, $dst$$Register, $len$$Register, + $tmp1$$XMMRegister, $tmp2$$XMMRegister, $tmp3$$XMMRegister, + $tmp4$$XMMRegister, $tmp5$$Register, $result$$Register, true); + %} + ins_pipe( pipe_slow ); +%} + +//----------Overflow Math Instructions----------------------------------------- + +instruct overflowAddI_rReg(rFlagsReg cr, rax_RegI op1, rRegI op2) +%{ + match(Set cr (OverflowAddI op1 op2)); + effect(DEF cr, USE_KILL op1, USE op2); + + format %{ "addl $op1, $op2\t# overflow check int" %} + + ins_encode %{ + __ addl($op1$$Register, $op2$$Register); + %} + ins_pipe(ialu_reg_reg); +%} + +instruct overflowAddI_rReg_imm(rFlagsReg cr, rax_RegI op1, immI op2) +%{ + match(Set cr (OverflowAddI op1 op2)); + effect(DEF cr, USE_KILL op1, USE op2); + + format %{ "addl $op1, $op2\t# overflow check int" %} + + ins_encode %{ + __ addl($op1$$Register, $op2$$constant); + %} + ins_pipe(ialu_reg_reg); +%} + +instruct overflowAddL_rReg(rFlagsReg cr, rax_RegL op1, rRegL op2) +%{ + match(Set cr (OverflowAddL op1 op2)); + effect(DEF cr, USE_KILL op1, USE op2); + + format %{ "addq $op1, $op2\t# overflow check long" %} + ins_encode %{ + __ addq($op1$$Register, $op2$$Register); + %} + ins_pipe(ialu_reg_reg); +%} + +instruct overflowAddL_rReg_imm(rFlagsReg cr, rax_RegL op1, immL32 op2) +%{ + match(Set cr (OverflowAddL op1 op2)); + effect(DEF cr, USE_KILL op1, USE op2); + + format %{ "addq $op1, $op2\t# overflow check long" %} + ins_encode %{ + __ addq($op1$$Register, $op2$$constant); + %} + ins_pipe(ialu_reg_reg); +%} + +instruct overflowSubI_rReg(rFlagsReg cr, rRegI op1, rRegI op2) +%{ + match(Set cr (OverflowSubI op1 op2)); + + format %{ "cmpl $op1, $op2\t# overflow check int" %} + ins_encode %{ + __ cmpl($op1$$Register, $op2$$Register); + %} + ins_pipe(ialu_reg_reg); +%} + +instruct overflowSubI_rReg_imm(rFlagsReg cr, rRegI op1, immI op2) +%{ + match(Set cr (OverflowSubI op1 op2)); + + format %{ "cmpl $op1, $op2\t# overflow check int" %} + ins_encode %{ + __ cmpl($op1$$Register, $op2$$constant); + %} + ins_pipe(ialu_reg_reg); +%} + +instruct overflowSubL_rReg(rFlagsReg cr, rRegL op1, rRegL op2) +%{ + match(Set cr (OverflowSubL op1 op2)); + + format %{ "cmpq $op1, $op2\t# overflow check long" %} + ins_encode %{ + __ cmpq($op1$$Register, $op2$$Register); + %} + ins_pipe(ialu_reg_reg); +%} + +instruct overflowSubL_rReg_imm(rFlagsReg cr, rRegL op1, immL32 op2) +%{ + match(Set cr (OverflowSubL op1 op2)); + + format %{ "cmpq $op1, $op2\t# overflow check long" %} + ins_encode %{ + __ cmpq($op1$$Register, $op2$$constant); + %} + ins_pipe(ialu_reg_reg); +%} + +instruct overflowNegI_rReg(rFlagsReg cr, immI_0 zero, rax_RegI op2) +%{ + match(Set cr (OverflowSubI zero op2)); + effect(DEF cr, USE_KILL op2); + + format %{ "negl $op2\t# overflow check int" %} + ins_encode %{ + __ negl($op2$$Register); + %} + ins_pipe(ialu_reg_reg); +%} + +instruct overflowNegL_rReg(rFlagsReg cr, immL0 zero, rax_RegL op2) +%{ + match(Set cr (OverflowSubL zero op2)); + effect(DEF cr, USE_KILL op2); + + format %{ "negq $op2\t# overflow check long" %} + ins_encode %{ + __ negq($op2$$Register); + %} + ins_pipe(ialu_reg_reg); +%} + +instruct overflowMulI_rReg(rFlagsReg cr, rax_RegI op1, rRegI op2) +%{ + match(Set cr (OverflowMulI op1 op2)); + effect(DEF cr, USE_KILL op1, USE op2); + + format %{ "imull $op1, $op2\t# overflow check int" %} + ins_encode %{ + __ imull($op1$$Register, $op2$$Register); + %} + ins_pipe(ialu_reg_reg_alu0); +%} + +instruct overflowMulI_rReg_imm(rFlagsReg cr, rRegI op1, immI op2, rRegI tmp) +%{ + match(Set cr (OverflowMulI op1 op2)); + effect(DEF cr, TEMP tmp, USE op1, USE op2); + + format %{ "imull $tmp, $op1, $op2\t# overflow check int" %} + ins_encode %{ + __ imull($tmp$$Register, $op1$$Register, $op2$$constant); + %} + ins_pipe(ialu_reg_reg_alu0); +%} + +instruct overflowMulL_rReg(rFlagsReg cr, rax_RegL op1, rRegL op2) +%{ + match(Set cr (OverflowMulL op1 op2)); + effect(DEF cr, USE_KILL op1, USE op2); + + format %{ "imulq $op1, $op2\t# overflow check long" %} + ins_encode %{ + __ imulq($op1$$Register, $op2$$Register); + %} + ins_pipe(ialu_reg_reg_alu0); +%} + +instruct overflowMulL_rReg_imm(rFlagsReg cr, rRegL op1, immL32 op2, rRegL tmp) +%{ + match(Set cr (OverflowMulL op1 op2)); + effect(DEF cr, TEMP tmp, USE op1, USE op2); + + format %{ "imulq $tmp, $op1, $op2\t# overflow check long" %} + ins_encode %{ + __ imulq($tmp$$Register, $op1$$Register, $op2$$constant); + %} + ins_pipe(ialu_reg_reg_alu0); +%} + + +//----------Control Flow Instructions------------------------------------------ +// Signed compare Instructions + +// XXX more variants!! +instruct compI_rReg(rFlagsReg cr, rRegI op1, rRegI op2) +%{ + match(Set cr (CmpI op1 op2)); + effect(DEF cr, USE op1, USE op2); + + format %{ "cmpl $op1, $op2" %} + ins_encode %{ + __ cmpl($op1$$Register, $op2$$Register); + %} + ins_pipe(ialu_cr_reg_reg); +%} + +instruct compI_rReg_imm(rFlagsReg cr, rRegI op1, immI op2) +%{ + match(Set cr (CmpI op1 op2)); + + format %{ "cmpl $op1, $op2" %} + ins_encode %{ + __ cmpl($op1$$Register, $op2$$constant); + %} + ins_pipe(ialu_cr_reg_imm); +%} + +instruct compI_rReg_mem(rFlagsReg cr, rRegI op1, memory op2) +%{ + match(Set cr (CmpI op1 (LoadI op2))); + + ins_cost(500); // XXX + format %{ "cmpl $op1, $op2" %} + ins_encode %{ + __ cmpl($op1$$Register, $op2$$Address); + %} + ins_pipe(ialu_cr_reg_mem); +%} + +instruct testI_reg(rFlagsReg cr, rRegI src, immI_0 zero) +%{ + match(Set cr (CmpI src zero)); + + format %{ "testl $src, $src" %} + ins_encode %{ + __ testl($src$$Register, $src$$Register); + %} + ins_pipe(ialu_cr_reg_imm); +%} + +instruct testI_reg_imm(rFlagsReg cr, rRegI src, immI con, immI_0 zero) +%{ + match(Set cr (CmpI (AndI src con) zero)); + + format %{ "testl $src, $con" %} + ins_encode %{ + __ testl($src$$Register, $con$$constant); + %} + ins_pipe(ialu_cr_reg_imm); +%} + +instruct testI_reg_reg(rFlagsReg cr, rRegI src1, rRegI src2, immI_0 zero) +%{ + match(Set cr (CmpI (AndI src1 src2) zero)); + + format %{ "testl $src1, $src2" %} + ins_encode %{ + __ testl($src1$$Register, $src2$$Register); + %} + ins_pipe(ialu_cr_reg_imm); +%} + +instruct testI_reg_mem(rFlagsReg cr, rRegI src, memory mem, immI_0 zero) +%{ + match(Set cr (CmpI (AndI src (LoadI mem)) zero)); + + format %{ "testl $src, $mem" %} + ins_encode %{ + __ testl($src$$Register, $mem$$Address); + %} + ins_pipe(ialu_cr_reg_mem); +%} + +// Unsigned compare Instructions; really, same as signed except they +// produce an rFlagsRegU instead of rFlagsReg. +instruct compU_rReg(rFlagsRegU cr, rRegI op1, rRegI op2) +%{ + match(Set cr (CmpU op1 op2)); + + format %{ "cmpl $op1, $op2\t# unsigned" %} + ins_encode %{ + __ cmpl($op1$$Register, $op2$$Register); + %} + ins_pipe(ialu_cr_reg_reg); +%} + +instruct compU_rReg_imm(rFlagsRegU cr, rRegI op1, immI op2) +%{ + match(Set cr (CmpU op1 op2)); + + format %{ "cmpl $op1, $op2\t# unsigned" %} + ins_encode %{ + __ cmpl($op1$$Register, $op2$$constant); + %} + ins_pipe(ialu_cr_reg_imm); +%} + +instruct compU_rReg_mem(rFlagsRegU cr, rRegI op1, memory op2) +%{ + match(Set cr (CmpU op1 (LoadI op2))); + + ins_cost(500); // XXX + format %{ "cmpl $op1, $op2\t# unsigned" %} + ins_encode %{ + __ cmpl($op1$$Register, $op2$$Address); + %} + ins_pipe(ialu_cr_reg_mem); +%} + +instruct testU_reg(rFlagsRegU cr, rRegI src, immI_0 zero) +%{ + match(Set cr (CmpU src zero)); + + format %{ "testl $src, $src\t# unsigned" %} + ins_encode %{ + __ testl($src$$Register, $src$$Register); + %} + ins_pipe(ialu_cr_reg_imm); +%} + +instruct compP_rReg(rFlagsRegU cr, rRegP op1, rRegP op2) +%{ + match(Set cr (CmpP op1 op2)); + + format %{ "cmpq $op1, $op2\t# ptr" %} + ins_encode %{ + __ cmpq($op1$$Register, $op2$$Register); + %} + ins_pipe(ialu_cr_reg_reg); +%} + +instruct compP_rReg_mem(rFlagsRegU cr, rRegP op1, memory op2) +%{ + match(Set cr (CmpP op1 (LoadP op2))); + predicate(n->in(2)->as_Load()->barrier_data() == 0); + + ins_cost(500); // XXX + format %{ "cmpq $op1, $op2\t# ptr" %} + ins_encode %{ + __ cmpq($op1$$Register, $op2$$Address); + %} + ins_pipe(ialu_cr_reg_mem); +%} + +// XXX this is generalized by compP_rReg_mem??? +// Compare raw pointer (used in out-of-heap check). +// Only works because non-oop pointers must be raw pointers +// and raw pointers have no anti-dependencies. +instruct compP_mem_rReg(rFlagsRegU cr, rRegP op1, memory op2) +%{ + predicate(n->in(2)->in(2)->bottom_type()->reloc() == relocInfo::none && + n->in(2)->as_Load()->barrier_data() == 0); + match(Set cr (CmpP op1 (LoadP op2))); + + format %{ "cmpq $op1, $op2\t# raw ptr" %} + ins_encode %{ + __ cmpq($op1$$Register, $op2$$Address); + %} + ins_pipe(ialu_cr_reg_mem); +%} + +// This will generate a signed flags result. This should be OK since +// any compare to a zero should be eq/neq. +instruct testP_reg(rFlagsReg cr, rRegP src, immP0 zero) +%{ + match(Set cr (CmpP src zero)); + + format %{ "testq $src, $src\t# ptr" %} + ins_encode %{ + __ testq($src$$Register, $src$$Register); + %} + ins_pipe(ialu_cr_reg_imm); +%} + +// This will generate a signed flags result. This should be OK since +// any compare to a zero should be eq/neq. +instruct testP_mem(rFlagsReg cr, memory op, immP0 zero) +%{ + predicate((!UseCompressedOops || (CompressedOops::base() != nullptr)) && + n->in(1)->as_Load()->barrier_data() == 0); + match(Set cr (CmpP (LoadP op) zero)); + + ins_cost(500); // XXX + format %{ "testq $op, 0xffffffffffffffff\t# ptr" %} + ins_encode %{ + __ testq($op$$Address, 0xFFFFFFFF); + %} + ins_pipe(ialu_cr_reg_imm); +%} + +instruct testP_mem_reg0(rFlagsReg cr, memory mem, immP0 zero) +%{ + predicate(UseCompressedOops && (CompressedOops::base() == nullptr) && + n->in(1)->as_Load()->barrier_data() == 0); + match(Set cr (CmpP (LoadP mem) zero)); + + format %{ "cmpq R12, $mem\t# ptr (R12_heapbase==0)" %} + ins_encode %{ + __ cmpq(r12, $mem$$Address); + %} + ins_pipe(ialu_cr_reg_mem); +%} + +instruct compN_rReg(rFlagsRegU cr, rRegN op1, rRegN op2) +%{ + match(Set cr (CmpN op1 op2)); + + format %{ "cmpl $op1, $op2\t# compressed ptr" %} + ins_encode %{ __ cmpl($op1$$Register, $op2$$Register); %} + ins_pipe(ialu_cr_reg_reg); +%} + +instruct compN_rReg_mem(rFlagsRegU cr, rRegN src, memory mem) +%{ + predicate(n->in(2)->as_Load()->barrier_data() == 0); + match(Set cr (CmpN src (LoadN mem))); + + format %{ "cmpl $src, $mem\t# compressed ptr" %} + ins_encode %{ + __ cmpl($src$$Register, $mem$$Address); + %} + ins_pipe(ialu_cr_reg_mem); +%} + +instruct compN_rReg_imm(rFlagsRegU cr, rRegN op1, immN op2) %{ + match(Set cr (CmpN op1 op2)); + + format %{ "cmpl $op1, $op2\t# compressed ptr" %} + ins_encode %{ + __ cmp_narrow_oop($op1$$Register, (jobject)$op2$$constant); + %} + ins_pipe(ialu_cr_reg_imm); +%} + +instruct compN_mem_imm(rFlagsRegU cr, memory mem, immN src) +%{ + predicate(n->in(2)->as_Load()->barrier_data() == 0); + match(Set cr (CmpN src (LoadN mem))); + + format %{ "cmpl $mem, $src\t# compressed ptr" %} + ins_encode %{ + __ cmp_narrow_oop($mem$$Address, (jobject)$src$$constant); + %} + ins_pipe(ialu_cr_reg_mem); +%} + +instruct compN_rReg_imm_klass(rFlagsRegU cr, rRegN op1, immNKlass op2) %{ + match(Set cr (CmpN op1 op2)); + + format %{ "cmpl $op1, $op2\t# compressed klass ptr" %} + ins_encode %{ + __ cmp_narrow_klass($op1$$Register, (Klass*)$op2$$constant); + %} + ins_pipe(ialu_cr_reg_imm); +%} + +instruct compN_mem_imm_klass(rFlagsRegU cr, memory mem, immNKlass src) +%{ + predicate(!UseCompactObjectHeaders); + match(Set cr (CmpN src (LoadNKlass mem))); + + format %{ "cmpl $mem, $src\t# compressed klass ptr" %} + ins_encode %{ + __ cmp_narrow_klass($mem$$Address, (Klass*)$src$$constant); + %} + ins_pipe(ialu_cr_reg_mem); +%} + +instruct testN_reg(rFlagsReg cr, rRegN src, immN0 zero) %{ + match(Set cr (CmpN src zero)); + + format %{ "testl $src, $src\t# compressed ptr" %} + ins_encode %{ __ testl($src$$Register, $src$$Register); %} + ins_pipe(ialu_cr_reg_imm); +%} + +instruct testN_mem(rFlagsReg cr, memory mem, immN0 zero) +%{ + predicate(CompressedOops::base() != nullptr && + n->in(1)->as_Load()->barrier_data() == 0); + match(Set cr (CmpN (LoadN mem) zero)); + + ins_cost(500); // XXX + format %{ "testl $mem, 0xffffffff\t# compressed ptr" %} + ins_encode %{ + __ cmpl($mem$$Address, (int)0xFFFFFFFF); + %} + ins_pipe(ialu_cr_reg_mem); +%} + +instruct testN_mem_reg0(rFlagsReg cr, memory mem, immN0 zero) +%{ + predicate(CompressedOops::base() == nullptr && + n->in(1)->as_Load()->barrier_data() == 0); + match(Set cr (CmpN (LoadN mem) zero)); + + format %{ "cmpl R12, $mem\t# compressed ptr (R12_heapbase==0)" %} + ins_encode %{ + __ cmpl(r12, $mem$$Address); + %} + ins_pipe(ialu_cr_reg_mem); +%} + +// Yanked all unsigned pointer compare operations. +// Pointer compares are done with CmpP which is already unsigned. + +instruct compL_rReg(rFlagsReg cr, rRegL op1, rRegL op2) +%{ + match(Set cr (CmpL op1 op2)); + + format %{ "cmpq $op1, $op2" %} + ins_encode %{ + __ cmpq($op1$$Register, $op2$$Register); + %} + ins_pipe(ialu_cr_reg_reg); +%} + +instruct compL_rReg_imm(rFlagsReg cr, rRegL op1, immL32 op2) +%{ + match(Set cr (CmpL op1 op2)); + + format %{ "cmpq $op1, $op2" %} + ins_encode %{ + __ cmpq($op1$$Register, $op2$$constant); + %} + ins_pipe(ialu_cr_reg_imm); +%} + +instruct compL_rReg_mem(rFlagsReg cr, rRegL op1, memory op2) +%{ + match(Set cr (CmpL op1 (LoadL op2))); + + format %{ "cmpq $op1, $op2" %} + ins_encode %{ + __ cmpq($op1$$Register, $op2$$Address); + %} + ins_pipe(ialu_cr_reg_mem); +%} + +instruct testL_reg(rFlagsReg cr, rRegL src, immL0 zero) +%{ + match(Set cr (CmpL src zero)); + + format %{ "testq $src, $src" %} + ins_encode %{ + __ testq($src$$Register, $src$$Register); + %} + ins_pipe(ialu_cr_reg_imm); +%} + +instruct testL_reg_imm(rFlagsReg cr, rRegL src, immL32 con, immL0 zero) +%{ + match(Set cr (CmpL (AndL src con) zero)); + + format %{ "testq $src, $con\t# long" %} + ins_encode %{ + __ testq($src$$Register, $con$$constant); + %} + ins_pipe(ialu_cr_reg_imm); +%} + +instruct testL_reg_reg(rFlagsReg cr, rRegL src1, rRegL src2, immL0 zero) +%{ + match(Set cr (CmpL (AndL src1 src2) zero)); + + format %{ "testq $src1, $src2\t# long" %} + ins_encode %{ + __ testq($src1$$Register, $src2$$Register); + %} + ins_pipe(ialu_cr_reg_imm); +%} + +instruct testL_reg_mem(rFlagsReg cr, rRegL src, memory mem, immL0 zero) +%{ + match(Set cr (CmpL (AndL src (LoadL mem)) zero)); + + format %{ "testq $src, $mem" %} + ins_encode %{ + __ testq($src$$Register, $mem$$Address); + %} + ins_pipe(ialu_cr_reg_mem); +%} + +instruct testL_reg_mem2(rFlagsReg cr, rRegP src, memory mem, immL0 zero) +%{ + match(Set cr (CmpL (AndL (CastP2X src) (LoadL mem)) zero)); + + format %{ "testq $src, $mem" %} + ins_encode %{ + __ testq($src$$Register, $mem$$Address); + %} + ins_pipe(ialu_cr_reg_mem); +%} + +// Manifest a CmpU result in an integer register. Very painful. +// This is the test to avoid. +instruct cmpU3_reg_reg(rRegI dst, rRegI src1, rRegI src2, rFlagsReg flags) +%{ + match(Set dst (CmpU3 src1 src2)); + effect(KILL flags); + + ins_cost(275); // XXX + format %{ "cmpl $src1, $src2\t# CmpL3\n\t" + "movl $dst, -1\n\t" + "jb,u done\n\t" + "setcc $dst \t# emits setne + movzbl or setzune for APX" + "done:" %} + ins_encode %{ + Label done; + __ cmpl($src1$$Register, $src2$$Register); + __ movl($dst$$Register, -1); + __ jccb(Assembler::below, done); + __ setcc(Assembler::notZero, $dst$$Register); + __ bind(done); + %} + ins_pipe(pipe_slow); +%} + +// Manifest a CmpL result in an integer register. Very painful. +// This is the test to avoid. +instruct cmpL3_reg_reg(rRegI dst, rRegL src1, rRegL src2, rFlagsReg flags) +%{ + match(Set dst (CmpL3 src1 src2)); + effect(KILL flags); + + ins_cost(275); // XXX + format %{ "cmpq $src1, $src2\t# CmpL3\n\t" + "movl $dst, -1\n\t" + "jl,s done\n\t" + "setcc $dst \t# emits setne + movzbl or setzune for APX" + "done:" %} + ins_encode %{ + Label done; + __ cmpq($src1$$Register, $src2$$Register); + __ movl($dst$$Register, -1); + __ jccb(Assembler::less, done); + __ setcc(Assembler::notZero, $dst$$Register); + __ bind(done); + %} + ins_pipe(pipe_slow); +%} + +// Manifest a CmpUL result in an integer register. Very painful. +// This is the test to avoid. +instruct cmpUL3_reg_reg(rRegI dst, rRegL src1, rRegL src2, rFlagsReg flags) +%{ + match(Set dst (CmpUL3 src1 src2)); + effect(KILL flags); + + ins_cost(275); // XXX + format %{ "cmpq $src1, $src2\t# CmpL3\n\t" + "movl $dst, -1\n\t" + "jb,u done\n\t" + "setcc $dst \t# emits setne + movzbl or setzune for APX" + "done:" %} + ins_encode %{ + Label done; + __ cmpq($src1$$Register, $src2$$Register); + __ movl($dst$$Register, -1); + __ jccb(Assembler::below, done); + __ setcc(Assembler::notZero, $dst$$Register); + __ bind(done); + %} + ins_pipe(pipe_slow); +%} + +// Unsigned long compare Instructions; really, same as signed long except they +// produce an rFlagsRegU instead of rFlagsReg. +instruct compUL_rReg(rFlagsRegU cr, rRegL op1, rRegL op2) +%{ + match(Set cr (CmpUL op1 op2)); + + format %{ "cmpq $op1, $op2\t# unsigned" %} + ins_encode %{ + __ cmpq($op1$$Register, $op2$$Register); + %} + ins_pipe(ialu_cr_reg_reg); +%} + +instruct compUL_rReg_imm(rFlagsRegU cr, rRegL op1, immL32 op2) +%{ + match(Set cr (CmpUL op1 op2)); + + format %{ "cmpq $op1, $op2\t# unsigned" %} + ins_encode %{ + __ cmpq($op1$$Register, $op2$$constant); + %} + ins_pipe(ialu_cr_reg_imm); +%} + +instruct compUL_rReg_mem(rFlagsRegU cr, rRegL op1, memory op2) +%{ + match(Set cr (CmpUL op1 (LoadL op2))); + + format %{ "cmpq $op1, $op2\t# unsigned" %} + ins_encode %{ + __ cmpq($op1$$Register, $op2$$Address); + %} + ins_pipe(ialu_cr_reg_mem); +%} + +instruct testUL_reg(rFlagsRegU cr, rRegL src, immL0 zero) +%{ + match(Set cr (CmpUL src zero)); + + format %{ "testq $src, $src\t# unsigned" %} + ins_encode %{ + __ testq($src$$Register, $src$$Register); + %} + ins_pipe(ialu_cr_reg_imm); +%} + +instruct compB_mem_imm(rFlagsReg cr, memory mem, immI8 imm) +%{ + match(Set cr (CmpI (LoadB mem) imm)); + + ins_cost(125); + format %{ "cmpb $mem, $imm" %} + ins_encode %{ __ cmpb($mem$$Address, $imm$$constant); %} + ins_pipe(ialu_cr_reg_mem); +%} + +instruct testUB_mem_imm(rFlagsReg cr, memory mem, immU7 imm, immI_0 zero) +%{ + match(Set cr (CmpI (AndI (LoadUB mem) imm) zero)); + + ins_cost(125); + format %{ "testb $mem, $imm\t# ubyte" %} + ins_encode %{ __ testb($mem$$Address, $imm$$constant); %} + ins_pipe(ialu_cr_reg_mem); +%} + +instruct testB_mem_imm(rFlagsReg cr, memory mem, immI8 imm, immI_0 zero) +%{ + match(Set cr (CmpI (AndI (LoadB mem) imm) zero)); + + ins_cost(125); + format %{ "testb $mem, $imm\t# byte" %} + ins_encode %{ __ testb($mem$$Address, $imm$$constant); %} + ins_pipe(ialu_cr_reg_mem); +%} + +//----------Max and Min-------------------------------------------------------- +// Min Instructions + +instruct cmovI_reg_g(rRegI dst, rRegI src, rFlagsReg cr) +%{ + predicate(!UseAPX); + effect(USE_DEF dst, USE src, USE cr); + + format %{ "cmovlgt $dst, $src\t# min" %} + ins_encode %{ + __ cmovl(Assembler::greater, $dst$$Register, $src$$Register); + %} + ins_pipe(pipe_cmov_reg); +%} + +instruct cmovI_reg_g_ndd(rRegI dst, rRegI src1, rRegI src2, rFlagsReg cr) +%{ + predicate(UseAPX); + effect(DEF dst, USE src1, USE src2, USE cr); + + format %{ "ecmovlgt $dst, $src1, $src2\t# min ndd" %} + ins_encode %{ + __ ecmovl(Assembler::greater, $dst$$Register, $src1$$Register, $src2$$Register); + %} + ins_pipe(pipe_cmov_reg); +%} + +instruct minI_rReg(rRegI dst, rRegI src) +%{ + predicate(!UseAPX); + match(Set dst (MinI dst src)); + + ins_cost(200); + expand %{ + rFlagsReg cr; + compI_rReg(cr, dst, src); + cmovI_reg_g(dst, src, cr); + %} +%} + +instruct minI_rReg_ndd(rRegI dst, rRegI src1, rRegI src2) +%{ + predicate(UseAPX); + match(Set dst (MinI src1 src2)); + effect(DEF dst, USE src1, USE src2); + + ins_cost(200); + expand %{ + rFlagsReg cr; + compI_rReg(cr, src1, src2); + cmovI_reg_g_ndd(dst, src1, src2, cr); + %} +%} + +instruct cmovI_reg_l(rRegI dst, rRegI src, rFlagsReg cr) +%{ + predicate(!UseAPX); + effect(USE_DEF dst, USE src, USE cr); + + format %{ "cmovllt $dst, $src\t# max" %} + ins_encode %{ + __ cmovl(Assembler::less, $dst$$Register, $src$$Register); + %} + ins_pipe(pipe_cmov_reg); +%} + +instruct cmovI_reg_l_ndd(rRegI dst, rRegI src1, rRegI src2, rFlagsReg cr) +%{ + predicate(UseAPX); + effect(DEF dst, USE src1, USE src2, USE cr); + + format %{ "ecmovllt $dst, $src1, $src2\t# max ndd" %} + ins_encode %{ + __ ecmovl(Assembler::less, $dst$$Register, $src1$$Register, $src2$$Register); + %} + ins_pipe(pipe_cmov_reg); +%} + +instruct maxI_rReg(rRegI dst, rRegI src) +%{ + predicate(!UseAPX); + match(Set dst (MaxI dst src)); + + ins_cost(200); + expand %{ + rFlagsReg cr; + compI_rReg(cr, dst, src); + cmovI_reg_l(dst, src, cr); + %} +%} + +instruct maxI_rReg_ndd(rRegI dst, rRegI src1, rRegI src2) +%{ + predicate(UseAPX); + match(Set dst (MaxI src1 src2)); + effect(DEF dst, USE src1, USE src2); + + ins_cost(200); + expand %{ + rFlagsReg cr; + compI_rReg(cr, src1, src2); + cmovI_reg_l_ndd(dst, src1, src2, cr); + %} +%} + +// ============================================================================ +// Branch Instructions + +// Jump Direct - Label defines a relative address from JMP+1 +instruct jmpDir(label labl) +%{ + match(Goto); + effect(USE labl); + + ins_cost(300); + format %{ "jmp $labl" %} + size(5); + ins_encode %{ + Label* L = $labl$$label; + __ jmp(*L, false); // Always long jump + %} + ins_pipe(pipe_jmp); +%} + +// Jump Direct Conditional - Label defines a relative address from Jcc+1 +instruct jmpCon(cmpOp cop, rFlagsReg cr, label labl) +%{ + match(If cop cr); + effect(USE labl); + + ins_cost(300); + format %{ "j$cop $labl" %} + size(6); + ins_encode %{ + Label* L = $labl$$label; + __ jcc((Assembler::Condition)($cop$$cmpcode), *L, false); // Always long jump + %} + ins_pipe(pipe_jcc); +%} + +// Jump Direct Conditional - Label defines a relative address from Jcc+1 +instruct jmpLoopEnd(cmpOp cop, rFlagsReg cr, label labl) +%{ + match(CountedLoopEnd cop cr); + effect(USE labl); + + ins_cost(300); + format %{ "j$cop $labl\t# loop end" %} + size(6); + ins_encode %{ + Label* L = $labl$$label; + __ jcc((Assembler::Condition)($cop$$cmpcode), *L, false); // Always long jump + %} + ins_pipe(pipe_jcc); +%} + +// Jump Direct Conditional - using unsigned comparison +instruct jmpConU(cmpOpU cop, rFlagsRegU cmp, label labl) %{ + match(If cop cmp); + effect(USE labl); + + ins_cost(300); + format %{ "j$cop,u $labl" %} + size(6); + ins_encode %{ + Label* L = $labl$$label; + __ jcc((Assembler::Condition)($cop$$cmpcode), *L, false); // Always long jump + %} + ins_pipe(pipe_jcc); +%} + +instruct jmpConUCF(cmpOpUCF cop, rFlagsRegUCF cmp, label labl) %{ + match(If cop cmp); + effect(USE labl); + + ins_cost(200); + format %{ "j$cop,u $labl" %} + size(6); + ins_encode %{ + Label* L = $labl$$label; + __ jcc((Assembler::Condition)($cop$$cmpcode), *L, false); // Always long jump + %} + ins_pipe(pipe_jcc); +%} + +instruct jmpConUCF2(cmpOpUCF2 cop, rFlagsRegUCF cmp, label labl) %{ + match(If cop cmp); + effect(USE labl); + + ins_cost(200); + format %{ $$template + if ($cop$$cmpcode == Assembler::notEqual) { + $$emit$$"jp,u $labl\n\t" + $$emit$$"j$cop,u $labl" + } else { + $$emit$$"jp,u done\n\t" + $$emit$$"j$cop,u $labl\n\t" + $$emit$$"done:" + } + %} + ins_encode %{ + Label* l = $labl$$label; + if ($cop$$cmpcode == Assembler::notEqual) { + __ jcc(Assembler::parity, *l, false); + __ jcc(Assembler::notEqual, *l, false); + } else if ($cop$$cmpcode == Assembler::equal) { + Label done; + __ jccb(Assembler::parity, done); + __ jcc(Assembler::equal, *l, false); + __ bind(done); + } else { + ShouldNotReachHere(); + } + %} + ins_pipe(pipe_jcc); +%} + +// ============================================================================ +// 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 NZ for a miss or zero for a hit. The +// encoding ALSO sets flags. + +instruct partialSubtypeCheck(rdi_RegP result, + rsi_RegP sub, rax_RegP super, rcx_RegI rcx, + rFlagsReg cr) +%{ + match(Set result (PartialSubtypeCheck sub super)); + predicate(!UseSecondarySupersTable); + effect(KILL rcx, KILL cr); + + ins_cost(1100); // slightly larger than the next version + format %{ "movq rdi, [$sub + in_bytes(Klass::secondary_supers_offset())]\n\t" + "movl rcx, [rdi + Array::length_offset_in_bytes()]\t# length to scan\n\t" + "addq rdi, Array::base_offset_in_bytes()\t# Skip to start of data; set NZ in case count is zero\n\t" + "repne scasq\t# Scan *rdi++ for a match with rax while rcx--\n\t" + "jne,s miss\t\t# Missed: rdi not-zero\n\t" + "movq [$sub + in_bytes(Klass::secondary_super_cache_offset())], $super\t# Hit: update cache\n\t" + "xorq $result, $result\t\t Hit: rdi zero\n\t" + "miss:\t" %} + + ins_encode %{ + Label miss; + // NB: Callers may assume that, when $result is a valid register, + // check_klass_subtype_slow_path_linear sets it to a nonzero + // value. + __ check_klass_subtype_slow_path_linear($sub$$Register, $super$$Register, + $rcx$$Register, $result$$Register, + nullptr, &miss, + /*set_cond_codes:*/ true); + __ xorptr($result$$Register, $result$$Register); + __ bind(miss); + %} + + ins_pipe(pipe_slow); +%} + +// ============================================================================ +// Two versions of hashtable-based partialSubtypeCheck, both used when +// we need to search for a super class in the secondary supers array. +// The first is used when we don't know _a priori_ the class being +// searched for. The second, far more common, is used when we do know: +// this is used for instanceof, checkcast, and any case where C2 can +// determine it by constant propagation. + +instruct partialSubtypeCheckVarSuper(rsi_RegP sub, rax_RegP super, rdi_RegP result, + rdx_RegL temp1, rcx_RegL temp2, rbx_RegP temp3, r11_RegL temp4, + rFlagsReg cr) +%{ + match(Set result (PartialSubtypeCheck sub super)); + predicate(UseSecondarySupersTable); + effect(KILL cr, TEMP temp1, TEMP temp2, TEMP temp3, TEMP temp4); + + ins_cost(1000); + format %{ "partialSubtypeCheck $result, $sub, $super" %} + + ins_encode %{ + __ lookup_secondary_supers_table_var($sub$$Register, $super$$Register, $temp1$$Register, $temp2$$Register, + $temp3$$Register, $temp4$$Register, $result$$Register); + %} + + ins_pipe(pipe_slow); +%} + +instruct partialSubtypeCheckConstSuper(rsi_RegP sub, rax_RegP super_reg, immP super_con, rdi_RegP result, + rdx_RegL temp1, rcx_RegL temp2, rbx_RegP temp3, r11_RegL temp4, + rFlagsReg cr) +%{ + match(Set result (PartialSubtypeCheck sub (Binary super_reg super_con))); + predicate(UseSecondarySupersTable); + effect(KILL cr, TEMP temp1, TEMP temp2, TEMP temp3, TEMP temp4); + + ins_cost(700); // smaller than the next version + format %{ "partialSubtypeCheck $result, $sub, $super_reg, $super_con" %} + + ins_encode %{ + u1 super_klass_slot = ((Klass*)$super_con$$constant)->hash_slot(); + if (InlineSecondarySupersTest) { + __ lookup_secondary_supers_table_const($sub$$Register, $super_reg$$Register, $temp1$$Register, $temp2$$Register, + $temp3$$Register, $temp4$$Register, $result$$Register, + super_klass_slot); + } else { + __ call(RuntimeAddress(StubRoutines::lookup_secondary_supers_table_stub(super_klass_slot))); + } + %} + + ins_pipe(pipe_slow); +%} + +// ============================================================================ +// Branch Instructions -- short offset versions +// +// These instructions are used to replace jumps of a long offset (the default +// match) with jumps of a shorter offset. These instructions are all tagged +// with the ins_short_branch attribute, which causes the ADLC to suppress the +// match rules in general matching. Instead, the ADLC generates a conversion +// method in the MachNode which can be used to do in-place replacement of the +// long variant with the shorter variant. The compiler will determine if a +// branch can be taken by the is_short_branch_offset() predicate in the machine +// specific code section of the file. + +// Jump Direct - Label defines a relative address from JMP+1 +instruct jmpDir_short(label labl) %{ + match(Goto); + effect(USE labl); + + ins_cost(300); + format %{ "jmp,s $labl" %} + size(2); + ins_encode %{ + Label* L = $labl$$label; + __ jmpb(*L); + %} + ins_pipe(pipe_jmp); + ins_short_branch(1); +%} + +// Jump Direct Conditional - Label defines a relative address from Jcc+1 +instruct jmpCon_short(cmpOp cop, rFlagsReg cr, label labl) %{ + match(If cop cr); + effect(USE labl); + + ins_cost(300); + format %{ "j$cop,s $labl" %} + size(2); + ins_encode %{ + Label* L = $labl$$label; + __ jccb((Assembler::Condition)($cop$$cmpcode), *L); + %} + ins_pipe(pipe_jcc); + ins_short_branch(1); +%} + +// Jump Direct Conditional - Label defines a relative address from Jcc+1 +instruct jmpLoopEnd_short(cmpOp cop, rFlagsReg cr, label labl) %{ + match(CountedLoopEnd cop cr); + effect(USE labl); + + ins_cost(300); + format %{ "j$cop,s $labl\t# loop end" %} + size(2); + ins_encode %{ + Label* L = $labl$$label; + __ jccb((Assembler::Condition)($cop$$cmpcode), *L); + %} + ins_pipe(pipe_jcc); + ins_short_branch(1); +%} + +// Jump Direct Conditional - using unsigned comparison +instruct jmpConU_short(cmpOpU cop, rFlagsRegU cmp, label labl) %{ + match(If cop cmp); + effect(USE labl); + + ins_cost(300); + format %{ "j$cop,us $labl" %} + size(2); + ins_encode %{ + Label* L = $labl$$label; + __ jccb((Assembler::Condition)($cop$$cmpcode), *L); + %} + ins_pipe(pipe_jcc); + ins_short_branch(1); +%} + +instruct jmpConUCF_short(cmpOpUCF cop, rFlagsRegUCF cmp, label labl) %{ + match(If cop cmp); + effect(USE labl); + + ins_cost(300); + format %{ "j$cop,us $labl" %} + size(2); + ins_encode %{ + Label* L = $labl$$label; + __ jccb((Assembler::Condition)($cop$$cmpcode), *L); + %} + ins_pipe(pipe_jcc); + ins_short_branch(1); +%} + +instruct jmpConUCF2_short(cmpOpUCF2 cop, rFlagsRegUCF cmp, label labl) %{ + match(If cop cmp); + effect(USE labl); + + ins_cost(300); + format %{ $$template + if ($cop$$cmpcode == Assembler::notEqual) { + $$emit$$"jp,u,s $labl\n\t" + $$emit$$"j$cop,u,s $labl" + } else { + $$emit$$"jp,u,s done\n\t" + $$emit$$"j$cop,u,s $labl\n\t" + $$emit$$"done:" + } + %} + size(4); + ins_encode %{ + Label* l = $labl$$label; + if ($cop$$cmpcode == Assembler::notEqual) { + __ jccb(Assembler::parity, *l); + __ jccb(Assembler::notEqual, *l); + } else if ($cop$$cmpcode == Assembler::equal) { + Label done; + __ jccb(Assembler::parity, done); + __ jccb(Assembler::equal, *l); + __ bind(done); + } else { + ShouldNotReachHere(); + } + %} + ins_pipe(pipe_jcc); + ins_short_branch(1); +%} + +// ============================================================================ +// inlined locking and unlocking + +instruct cmpFastLockLightweight(rFlagsReg cr, rRegP object, rbx_RegP box, rax_RegI rax_reg, rRegP tmp) %{ + match(Set cr (FastLock object box)); + effect(TEMP rax_reg, TEMP tmp, USE_KILL box); + ins_cost(300); + format %{ "fastlock $object,$box\t! kills $box,$rax_reg,$tmp" %} + ins_encode %{ + __ fast_lock_lightweight($object$$Register, $box$$Register, $rax_reg$$Register, $tmp$$Register, r15_thread); + %} + ins_pipe(pipe_slow); +%} + +instruct cmpFastUnlockLightweight(rFlagsReg cr, rRegP object, rax_RegP rax_reg, rRegP tmp) %{ + match(Set cr (FastUnlock object rax_reg)); + effect(TEMP tmp, USE_KILL rax_reg); + ins_cost(300); + format %{ "fastunlock $object,$rax_reg\t! kills $rax_reg,$tmp" %} + ins_encode %{ + __ fast_unlock_lightweight($object$$Register, $rax_reg$$Register, $tmp$$Register, r15_thread); + %} + ins_pipe(pipe_slow); +%} + + +// ============================================================================ +// Safepoint Instructions +instruct safePoint_poll_tls(rFlagsReg cr, rRegP poll) +%{ + match(SafePoint poll); + effect(KILL cr, USE poll); + + format %{ "testl rax, [$poll]\t" + "# Safepoint: poll for GC" %} + ins_cost(125); + ins_encode %{ + __ relocate(relocInfo::poll_type); + address pre_pc = __ pc(); + __ testl(rax, Address($poll$$Register, 0)); + assert(nativeInstruction_at(pre_pc)->is_safepoint_poll(), "must emit test %%eax [reg]"); + %} + ins_pipe(ialu_reg_mem); +%} + +instruct mask_all_evexL(kReg dst, rRegL src) %{ + match(Set dst (MaskAll src)); + format %{ "mask_all_evexL $dst, $src \t! mask all operation" %} + ins_encode %{ + int mask_len = Matcher::vector_length(this); + __ vector_maskall_operation($dst$$KRegister, $src$$Register, mask_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct mask_all_evexI_GT32(kReg dst, rRegI src, rRegL tmp) %{ + predicate(Matcher::vector_length(n) > 32); + match(Set dst (MaskAll src)); + effect(TEMP tmp); + format %{ "mask_all_evexI_GT32 $dst, $src \t! using $tmp as TEMP" %} + ins_encode %{ + int mask_len = Matcher::vector_length(this); + __ movslq($tmp$$Register, $src$$Register); + __ vector_maskall_operation($dst$$KRegister, $tmp$$Register, mask_len); + %} + ins_pipe( pipe_slow ); +%} + +// ============================================================================ +// Procedure Call/Return Instructions +// Call Java Static Instruction +// Note: If this code changes, the corresponding ret_addr_offset() and +// compute_padding() functions will have to be adjusted. +instruct CallStaticJavaDirect(method meth) %{ + match(CallStaticJava); + effect(USE meth); + + ins_cost(300); + format %{ "call,static " %} + opcode(0xE8); /* E8 cd */ + ins_encode(clear_avx, Java_Static_Call(meth), call_epilog); + ins_pipe(pipe_slow); + ins_alignment(4); +%} + +// Call Java Dynamic Instruction +// Note: If this code changes, the corresponding ret_addr_offset() and +// compute_padding() functions will have to be adjusted. +instruct CallDynamicJavaDirect(method meth) +%{ + match(CallDynamicJava); + effect(USE meth); + + ins_cost(300); + format %{ "movq rax, #Universe::non_oop_word()\n\t" + "call,dynamic " %} + ins_encode(clear_avx, Java_Dynamic_Call(meth), call_epilog); + ins_pipe(pipe_slow); + ins_alignment(4); +%} + +// Call Runtime Instruction +instruct CallRuntimeDirect(method meth) +%{ + match(CallRuntime); + effect(USE meth); + + ins_cost(300); + format %{ "call,runtime " %} + ins_encode(clear_avx, Java_To_Runtime(meth)); + ins_pipe(pipe_slow); +%} + +// Call runtime without safepoint +instruct CallLeafDirect(method meth) +%{ + match(CallLeaf); + effect(USE meth); + + ins_cost(300); + format %{ "call_leaf,runtime " %} + ins_encode(clear_avx, Java_To_Runtime(meth)); + ins_pipe(pipe_slow); +%} + +// Call runtime without safepoint and with vector arguments +instruct CallLeafDirectVector(method meth) +%{ + match(CallLeafVector); + effect(USE meth); + + ins_cost(300); + format %{ "call_leaf,vector " %} + ins_encode(Java_To_Runtime(meth)); + ins_pipe(pipe_slow); +%} + +// Call runtime without safepoint +instruct CallLeafNoFPDirect(method meth) +%{ + match(CallLeafNoFP); + effect(USE meth); + + ins_cost(300); + format %{ "call_leaf_nofp,runtime " %} + ins_encode(clear_avx, Java_To_Runtime(meth)); + ins_pipe(pipe_slow); +%} + +// Return Instruction +// Remove the return address & jump to it. +// Notice: We always emit a nop after a ret to make sure there is room +// for safepoint patching +instruct Ret() +%{ + match(Return); + + format %{ "ret" %} + ins_encode %{ + __ ret(0); + %} + ins_pipe(pipe_jmp); +%} + +// 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. +// Don't use rbp for 'jump_target' because a MachEpilogNode has already been +// emitted just above the TailCall which has reset rbp to the caller state. +instruct TailCalljmpInd(no_rbp_RegP jump_target, rbx_RegP method_ptr) +%{ + match(TailCall jump_target method_ptr); + + ins_cost(300); + format %{ "jmp $jump_target\t# rbx holds method" %} + ins_encode %{ + __ jmp($jump_target$$Register); + %} + ins_pipe(pipe_jmp); +%} + +// Tail Jump; remove the return address; jump to target. +// TailCall above leaves the return address around. +instruct tailjmpInd(no_rbp_RegP jump_target, rax_RegP ex_oop) +%{ + match(TailJump jump_target ex_oop); + + ins_cost(300); + format %{ "popq rdx\t# pop return address\n\t" + "jmp $jump_target" %} + ins_encode %{ + __ popq(as_Register(RDX_enc)); + __ jmp($jump_target$$Register); + %} + ins_pipe(pipe_jmp); +%} + +// Forward exception. +instruct ForwardExceptionjmp() +%{ + match(ForwardException); + + format %{ "jmp forward_exception_stub" %} + ins_encode %{ + __ jump(RuntimeAddress(StubRoutines::forward_exception_entry()), noreg); + %} + ins_pipe(pipe_jmp); +%} + +// 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(rax_RegP ex_oop) +%{ + match(Set ex_oop (CreateEx)); + + size(0); + // use the following format syntax + format %{ "# exception oop is in rax; 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); + + // use the following format syntax + format %{ "jmp rethrow_stub" %} + ins_encode %{ + __ jump(RuntimeAddress(OptoRuntime::rethrow_stub()), noreg); + %} + ins_pipe(pipe_jmp); +%} + +// ============================================================================ +// This name is KNOWN by the ADLC and cannot be changed. +// The ADLC forces a 'TypeRawPtr::BOTTOM' output type +// for this guy. +instruct tlsLoadP(r15_RegP dst) %{ + match(Set dst (ThreadLocal)); + effect(DEF dst); + + size(0); + format %{ "# TLS is in R15" %} + ins_encode( /*empty encoding*/ ); + ins_pipe(ialu_reg_reg); +%} + instruct addF_reg(regF dst, regF src) %{ predicate(UseAVX == 0); match(Set dst (AddF dst src)); @@ -10939,3 +25267,329 @@ instruct vector_minmax_HF_reg(vec dst, vec src1, vec src2, kReg ktmp, vec xtmp1, %} ins_pipe( pipe_slow ); %} + +//----------PEEPHOLE RULES----------------------------------------------------- +// These must follow all instruction definitions as they use the names +// defined in the instructions definitions. +// +// peeppredicate ( rule_predicate ); +// // the predicate unless which the peephole rule will be ignored +// +// peepmatch ( root_instr_name [preceding_instruction]* ); +// +// peepprocedure ( procedure_name ); +// // provide a procedure name to perform the optimization, the procedure should +// // reside in the architecture dependent peephole file, the method has the +// // signature of MachNode* (Block*, int, PhaseRegAlloc*, (MachNode*)(*)(), int...) +// // with the arguments being the basic block, the current node index inside the +// // block, the register allocator, the functions upon invoked return a new node +// // defined in peepreplace, and the rules of the nodes appearing in the +// // corresponding peepmatch, the function return true if successful, else +// // return false +// +// peepconstraint %{ +// (instruction_number.operand_name relational_op instruction_number.operand_name +// [, ...] ); +// // instruction numbers are zero-based using left to right order in peepmatch +// +// peepreplace ( instr_name ( [instruction_number.operand_name]* ) ); +// // provide an instruction_number.operand_name for each operand that appears +// // in the replacement instruction's match rule +// +// ---------VM FLAGS--------------------------------------------------------- +// +// All peephole optimizations can be turned off using -XX:-OptoPeephole +// +// Each peephole rule is given an identifying number starting with zero and +// increasing by one in the order seen by the parser. An individual peephole +// can be enabled, and all others disabled, by using -XX:OptoPeepholeAt=# +// on the command-line. +// +// ---------CURRENT LIMITATIONS---------------------------------------------- +// +// Only transformations inside a basic block (do we need more for peephole) +// +// ---------EXAMPLE---------------------------------------------------------- +// +// // pertinent parts of existing instructions in architecture description +// instruct movI(rRegI dst, rRegI src) +// %{ +// match(Set dst (CopyI src)); +// %} +// +// instruct incI_rReg(rRegI dst, immI_1 src, rFlagsReg cr) +// %{ +// match(Set dst (AddI dst src)); +// effect(KILL cr); +// %} +// +// instruct leaI_rReg_immI(rRegI dst, immI_1 src) +// %{ +// match(Set dst (AddI dst src)); +// %} +// +// 1. Simple replacement +// - Only match adjacent instructions in same basic block +// - Only equality constraints +// - Only constraints between operands, not (0.dest_reg == RAX_enc) +// - Only one replacement instruction +// +// // Change (inc mov) to lea +// peephole %{ +// // lea should only be emitted when beneficial +// peeppredicate( VM_Version::supports_fast_2op_lea() ); +// // increment preceded by register-register move +// peepmatch ( incI_rReg movI ); +// // require that the destination register of the increment +// // match the destination register of the move +// peepconstraint ( 0.dst == 1.dst ); +// // construct a replacement instruction that sets +// // the destination to ( move's source register + one ) +// peepreplace ( leaI_rReg_immI( 0.dst 1.src 0.src ) ); +// %} +// +// 2. Procedural replacement +// - More flexible finding relevent nodes +// - More flexible constraints +// - More flexible transformations +// - May utilise architecture-dependent API more effectively +// - Currently only one replacement instruction due to adlc parsing capabilities +// +// // Change (inc mov) to lea +// peephole %{ +// // lea should only be emitted when beneficial +// peeppredicate( VM_Version::supports_fast_2op_lea() ); +// // the rule numbers of these nodes inside are passed into the function below +// peepmatch ( incI_rReg movI ); +// // the method that takes the responsibility of transformation +// peepprocedure ( inc_mov_to_lea ); +// // the replacement is a leaI_rReg_immI, a lambda upon invoked creating this +// // node is passed into the function above +// peepreplace ( leaI_rReg_immI() ); +// %} + +// These instructions is not matched by the matcher but used by the peephole +instruct leaI_rReg_rReg_peep(rRegI dst, rRegI src1, rRegI src2) +%{ + predicate(false); + match(Set dst (AddI src1 src2)); + format %{ "leal $dst, [$src1 + $src2]" %} + ins_encode %{ + Register dst = $dst$$Register; + Register src1 = $src1$$Register; + Register src2 = $src2$$Register; + if (src1 != rbp && src1 != r13) { + __ leal(dst, Address(src1, src2, Address::times_1)); + } else { + assert(src2 != rbp && src2 != r13, ""); + __ leal(dst, Address(src2, src1, Address::times_1)); + } + %} + ins_pipe(ialu_reg_reg); +%} + +instruct leaI_rReg_immI_peep(rRegI dst, rRegI src1, immI src2) +%{ + predicate(false); + match(Set dst (AddI src1 src2)); + format %{ "leal $dst, [$src1 + $src2]" %} + ins_encode %{ + __ leal($dst$$Register, Address($src1$$Register, $src2$$constant)); + %} + ins_pipe(ialu_reg_reg); +%} + +instruct leaI_rReg_immI2_peep(rRegI dst, rRegI src, immI2 shift) +%{ + predicate(false); + match(Set dst (LShiftI src shift)); + format %{ "leal $dst, [$src << $shift]" %} + ins_encode %{ + Address::ScaleFactor scale = static_cast($shift$$constant); + Register src = $src$$Register; + if (scale == Address::times_2 && src != rbp && src != r13) { + __ leal($dst$$Register, Address(src, src, Address::times_1)); + } else { + __ leal($dst$$Register, Address(noreg, src, scale)); + } + %} + ins_pipe(ialu_reg_reg); +%} + +instruct leaL_rReg_rReg_peep(rRegL dst, rRegL src1, rRegL src2) +%{ + predicate(false); + match(Set dst (AddL src1 src2)); + format %{ "leaq $dst, [$src1 + $src2]" %} + ins_encode %{ + Register dst = $dst$$Register; + Register src1 = $src1$$Register; + Register src2 = $src2$$Register; + if (src1 != rbp && src1 != r13) { + __ leaq(dst, Address(src1, src2, Address::times_1)); + } else { + assert(src2 != rbp && src2 != r13, ""); + __ leaq(dst, Address(src2, src1, Address::times_1)); + } + %} + ins_pipe(ialu_reg_reg); +%} + +instruct leaL_rReg_immL32_peep(rRegL dst, rRegL src1, immL32 src2) +%{ + predicate(false); + match(Set dst (AddL src1 src2)); + format %{ "leaq $dst, [$src1 + $src2]" %} + ins_encode %{ + __ leaq($dst$$Register, Address($src1$$Register, $src2$$constant)); + %} + ins_pipe(ialu_reg_reg); +%} + +instruct leaL_rReg_immI2_peep(rRegL dst, rRegL src, immI2 shift) +%{ + predicate(false); + match(Set dst (LShiftL src shift)); + format %{ "leaq $dst, [$src << $shift]" %} + ins_encode %{ + Address::ScaleFactor scale = static_cast($shift$$constant); + Register src = $src$$Register; + if (scale == Address::times_2 && src != rbp && src != r13) { + __ leaq($dst$$Register, Address(src, src, Address::times_1)); + } else { + __ leaq($dst$$Register, Address(noreg, src, scale)); + } + %} + ins_pipe(ialu_reg_reg); +%} + +// These peephole rules replace mov + I pairs (where I is one of {add, inc, dec, +// sal}) with lea instructions. The {add, sal} rules are beneficial in +// processors with at least partial ALU support for lea +// (supports_fast_2op_lea()), whereas the {inc, dec} rules are only generally +// beneficial for processors with full ALU support +// (VM_Version::supports_fast_3op_lea()) and Intel Cascade Lake. + +peephole +%{ + peeppredicate(VM_Version::supports_fast_2op_lea()); + peepmatch (addI_rReg); + peepprocedure (lea_coalesce_reg); + peepreplace (leaI_rReg_rReg_peep()); +%} + +peephole +%{ + peeppredicate(VM_Version::supports_fast_2op_lea()); + peepmatch (addI_rReg_imm); + peepprocedure (lea_coalesce_imm); + peepreplace (leaI_rReg_immI_peep()); +%} + +peephole +%{ + peeppredicate(VM_Version::supports_fast_3op_lea() || + VM_Version::is_intel_cascade_lake()); + peepmatch (incI_rReg); + peepprocedure (lea_coalesce_imm); + peepreplace (leaI_rReg_immI_peep()); +%} + +peephole +%{ + peeppredicate(VM_Version::supports_fast_3op_lea() || + VM_Version::is_intel_cascade_lake()); + peepmatch (decI_rReg); + peepprocedure (lea_coalesce_imm); + peepreplace (leaI_rReg_immI_peep()); +%} + +peephole +%{ + peeppredicate(VM_Version::supports_fast_2op_lea()); + peepmatch (salI_rReg_immI2); + peepprocedure (lea_coalesce_imm); + peepreplace (leaI_rReg_immI2_peep()); +%} + +peephole +%{ + peeppredicate(VM_Version::supports_fast_2op_lea()); + peepmatch (addL_rReg); + peepprocedure (lea_coalesce_reg); + peepreplace (leaL_rReg_rReg_peep()); +%} + +peephole +%{ + peeppredicate(VM_Version::supports_fast_2op_lea()); + peepmatch (addL_rReg_imm); + peepprocedure (lea_coalesce_imm); + peepreplace (leaL_rReg_immL32_peep()); +%} + +peephole +%{ + peeppredicate(VM_Version::supports_fast_3op_lea() || + VM_Version::is_intel_cascade_lake()); + peepmatch (incL_rReg); + peepprocedure (lea_coalesce_imm); + peepreplace (leaL_rReg_immL32_peep()); +%} + +peephole +%{ + peeppredicate(VM_Version::supports_fast_3op_lea() || + VM_Version::is_intel_cascade_lake()); + peepmatch (decL_rReg); + peepprocedure (lea_coalesce_imm); + peepreplace (leaL_rReg_immL32_peep()); +%} + +peephole +%{ + peeppredicate(VM_Version::supports_fast_2op_lea()); + peepmatch (salL_rReg_immI2); + peepprocedure (lea_coalesce_imm); + peepreplace (leaL_rReg_immI2_peep()); +%} + +peephole +%{ + peepmatch (leaPCompressedOopOffset); + peepprocedure (lea_remove_redundant); +%} + +peephole +%{ + peepmatch (leaP8Narrow); + peepprocedure (lea_remove_redundant); +%} + +peephole +%{ + peepmatch (leaP32Narrow); + peepprocedure (lea_remove_redundant); +%} + +// These peephole rules matches instructions which set flags and are followed by a testI/L_reg +// The test instruction is redudanent in case the downstream instuctions (like JCC or CMOV) only use flags that are already set by the previous instruction + +//int variant +peephole +%{ + peepmatch (testI_reg); + peepprocedure (test_may_remove); +%} + +//long variant +peephole +%{ + peepmatch (testL_reg); + peepprocedure (test_may_remove); +%} + + +//----------SMARTSPILL RULES--------------------------------------------------- +// These must follow all instruction definitions as they use the names +// defined in the instructions definitions. diff --git a/src/hotspot/cpu/x86/x86_64.ad b/src/hotspot/cpu/x86/x86_64.ad deleted file mode 100644 index 62306b562d6..00000000000 --- a/src/hotspot/cpu/x86/x86_64.ad +++ /dev/null @@ -1,14735 +0,0 @@ -// -// Copyright (c) 2003, 2025, 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. -// -// - -// AMD64 Architecture Description File - -//----------REGISTER DEFINITION BLOCK------------------------------------------ -// This information is used by the matcher and the register allocator to -// describe individual registers and classes of registers within the target -// architecture. - -register %{ -//----------Architecture Description Register Definitions---------------------- -// General Registers -// "reg_def" name ( register save type, C convention save type, -// ideal register type, encoding ); -// Register Save Types: -// -// NS = No-Save: The register allocator assumes that these registers -// can be used without saving upon entry to the method, & -// that they do not need to be saved at call sites. -// -// SOC = Save-On-Call: The register allocator assumes that these registers -// can be used without saving upon entry to the method, -// but that they must be saved at call sites. -// -// SOE = Save-On-Entry: The register allocator assumes that these registers -// must be saved before using them upon entry to the -// method, but they do not need to be saved at call -// sites. -// -// AS = Always-Save: The register allocator assumes that these registers -// must be saved before using them upon entry to the -// method, & that they must be saved at call sites. -// -// Ideal Register Type is used to determine how to save & restore a -// register. Op_RegI will get spilled with LoadI/StoreI, Op_RegP will get -// spilled with LoadP/StoreP. If the register supports both, use Op_RegI. -// -// The encoding number is the actual bit-pattern placed into the opcodes. - -// General Registers -// R8-R15 must be encoded with REX. (RSP, RBP, RSI, RDI need REX when -// used as byte registers) - -// Previously set RBX, RSI, and RDI as save-on-entry for java code -// Turn off SOE in java-code due to frequent use of uncommon-traps. -// Now that allocator is better, turn on RSI and RDI as SOE registers. - -reg_def RAX (SOC, SOC, Op_RegI, 0, rax->as_VMReg()); -reg_def RAX_H(SOC, SOC, Op_RegI, 0, rax->as_VMReg()->next()); - -reg_def RCX (SOC, SOC, Op_RegI, 1, rcx->as_VMReg()); -reg_def RCX_H(SOC, SOC, Op_RegI, 1, rcx->as_VMReg()->next()); - -reg_def RDX (SOC, SOC, Op_RegI, 2, rdx->as_VMReg()); -reg_def RDX_H(SOC, SOC, Op_RegI, 2, rdx->as_VMReg()->next()); - -reg_def RBX (SOC, SOE, Op_RegI, 3, rbx->as_VMReg()); -reg_def RBX_H(SOC, SOE, Op_RegI, 3, rbx->as_VMReg()->next()); - -reg_def RSP (NS, NS, Op_RegI, 4, rsp->as_VMReg()); -reg_def RSP_H(NS, NS, Op_RegI, 4, rsp->as_VMReg()->next()); - -// now that adapter frames are gone RBP is always saved and restored by the prolog/epilog code -reg_def RBP (NS, SOE, Op_RegI, 5, rbp->as_VMReg()); -reg_def RBP_H(NS, SOE, Op_RegI, 5, rbp->as_VMReg()->next()); - -#ifdef _WIN64 - -reg_def RSI (SOC, SOE, Op_RegI, 6, rsi->as_VMReg()); -reg_def RSI_H(SOC, SOE, Op_RegI, 6, rsi->as_VMReg()->next()); - -reg_def RDI (SOC, SOE, Op_RegI, 7, rdi->as_VMReg()); -reg_def RDI_H(SOC, SOE, Op_RegI, 7, rdi->as_VMReg()->next()); - -#else - -reg_def RSI (SOC, SOC, Op_RegI, 6, rsi->as_VMReg()); -reg_def RSI_H(SOC, SOC, Op_RegI, 6, rsi->as_VMReg()->next()); - -reg_def RDI (SOC, SOC, Op_RegI, 7, rdi->as_VMReg()); -reg_def RDI_H(SOC, SOC, Op_RegI, 7, rdi->as_VMReg()->next()); - -#endif - -reg_def R8 (SOC, SOC, Op_RegI, 8, r8->as_VMReg()); -reg_def R8_H (SOC, SOC, Op_RegI, 8, r8->as_VMReg()->next()); - -reg_def R9 (SOC, SOC, Op_RegI, 9, r9->as_VMReg()); -reg_def R9_H (SOC, SOC, Op_RegI, 9, r9->as_VMReg()->next()); - -reg_def R10 (SOC, SOC, Op_RegI, 10, r10->as_VMReg()); -reg_def R10_H(SOC, SOC, Op_RegI, 10, r10->as_VMReg()->next()); - -reg_def R11 (SOC, SOC, Op_RegI, 11, r11->as_VMReg()); -reg_def R11_H(SOC, SOC, Op_RegI, 11, r11->as_VMReg()->next()); - -reg_def R12 (SOC, SOE, Op_RegI, 12, r12->as_VMReg()); -reg_def R12_H(SOC, SOE, Op_RegI, 12, r12->as_VMReg()->next()); - -reg_def R13 (SOC, SOE, Op_RegI, 13, r13->as_VMReg()); -reg_def R13_H(SOC, SOE, Op_RegI, 13, r13->as_VMReg()->next()); - -reg_def R14 (SOC, SOE, Op_RegI, 14, r14->as_VMReg()); -reg_def R14_H(SOC, SOE, Op_RegI, 14, r14->as_VMReg()->next()); - -reg_def R15 (SOC, SOE, Op_RegI, 15, r15->as_VMReg()); -reg_def R15_H(SOC, SOE, Op_RegI, 15, r15->as_VMReg()->next()); - -reg_def R16 (SOC, SOC, Op_RegI, 16, r16->as_VMReg()); -reg_def R16_H(SOC, SOC, Op_RegI, 16, r16->as_VMReg()->next()); - -reg_def R17 (SOC, SOC, Op_RegI, 17, r17->as_VMReg()); -reg_def R17_H(SOC, SOC, Op_RegI, 17, r17->as_VMReg()->next()); - -reg_def R18 (SOC, SOC, Op_RegI, 18, r18->as_VMReg()); -reg_def R18_H(SOC, SOC, Op_RegI, 18, r18->as_VMReg()->next()); - -reg_def R19 (SOC, SOC, Op_RegI, 19, r19->as_VMReg()); -reg_def R19_H(SOC, SOC, Op_RegI, 19, r19->as_VMReg()->next()); - -reg_def R20 (SOC, SOC, Op_RegI, 20, r20->as_VMReg()); -reg_def R20_H(SOC, SOC, Op_RegI, 20, r20->as_VMReg()->next()); - -reg_def R21 (SOC, SOC, Op_RegI, 21, r21->as_VMReg()); -reg_def R21_H(SOC, SOC, Op_RegI, 21, r21->as_VMReg()->next()); - -reg_def R22 (SOC, SOC, Op_RegI, 22, r22->as_VMReg()); -reg_def R22_H(SOC, SOC, Op_RegI, 22, r22->as_VMReg()->next()); - -reg_def R23 (SOC, SOC, Op_RegI, 23, r23->as_VMReg()); -reg_def R23_H(SOC, SOC, Op_RegI, 23, r23->as_VMReg()->next()); - -reg_def R24 (SOC, SOC, Op_RegI, 24, r24->as_VMReg()); -reg_def R24_H(SOC, SOC, Op_RegI, 24, r24->as_VMReg()->next()); - -reg_def R25 (SOC, SOC, Op_RegI, 25, r25->as_VMReg()); -reg_def R25_H(SOC, SOC, Op_RegI, 25, r25->as_VMReg()->next()); - -reg_def R26 (SOC, SOC, Op_RegI, 26, r26->as_VMReg()); -reg_def R26_H(SOC, SOC, Op_RegI, 26, r26->as_VMReg()->next()); - -reg_def R27 (SOC, SOC, Op_RegI, 27, r27->as_VMReg()); -reg_def R27_H(SOC, SOC, Op_RegI, 27, r27->as_VMReg()->next()); - -reg_def R28 (SOC, SOC, Op_RegI, 28, r28->as_VMReg()); -reg_def R28_H(SOC, SOC, Op_RegI, 28, r28->as_VMReg()->next()); - -reg_def R29 (SOC, SOC, Op_RegI, 29, r29->as_VMReg()); -reg_def R29_H(SOC, SOC, Op_RegI, 29, r29->as_VMReg()->next()); - -reg_def R30 (SOC, SOC, Op_RegI, 30, r30->as_VMReg()); -reg_def R30_H(SOC, SOC, Op_RegI, 30, r30->as_VMReg()->next()); - -reg_def R31 (SOC, SOC, Op_RegI, 31, r31->as_VMReg()); -reg_def R31_H(SOC, SOC, Op_RegI, 31, r31->as_VMReg()->next()); - -// Floating Point Registers - -// Specify priority of register selection within phases of register -// allocation. Highest priority is first. A useful heuristic is to -// give registers a low priority when they are required by machine -// instructions, like EAX and EDX on I486, and choose no-save registers -// before save-on-call, & save-on-call before save-on-entry. Registers -// which participate in fixed calling sequences should come last. -// Registers which are used as pairs must fall on an even boundary. - -alloc_class chunk0(R10, R10_H, - R11, R11_H, - R8, R8_H, - R9, R9_H, - R12, R12_H, - RCX, RCX_H, - RBX, RBX_H, - RDI, RDI_H, - RDX, RDX_H, - RSI, RSI_H, - RAX, RAX_H, - RBP, RBP_H, - R13, R13_H, - R14, R14_H, - R15, R15_H, - R16, R16_H, - R17, R17_H, - R18, R18_H, - R19, R19_H, - R20, R20_H, - R21, R21_H, - R22, R22_H, - R23, R23_H, - R24, R24_H, - R25, R25_H, - R26, R26_H, - R27, R27_H, - R28, R28_H, - R29, R29_H, - R30, R30_H, - R31, R31_H, - RSP, RSP_H); - - -//----------Architecture Description Register Classes-------------------------- -// Several register classes are automatically defined based upon information in -// this architecture description. -// 1) reg_class inline_cache_reg ( /* as def'd in frame section */ ) -// 2) reg_class stack_slots( /* one chunk of stack-based "registers" */ ) -// - -// Empty register class. -reg_class no_reg(); - -// Class for all pointer/long registers including APX extended GPRs. -reg_class all_reg(RAX, RAX_H, - RDX, RDX_H, - RBP, RBP_H, - RDI, RDI_H, - RSI, RSI_H, - RCX, RCX_H, - RBX, RBX_H, - RSP, RSP_H, - R8, R8_H, - R9, R9_H, - R10, R10_H, - R11, R11_H, - R12, R12_H, - R13, R13_H, - R14, R14_H, - R15, R15_H, - R16, R16_H, - R17, R17_H, - R18, R18_H, - R19, R19_H, - R20, R20_H, - R21, R21_H, - R22, R22_H, - R23, R23_H, - R24, R24_H, - R25, R25_H, - R26, R26_H, - R27, R27_H, - R28, R28_H, - R29, R29_H, - R30, R30_H, - R31, R31_H); - -// Class for all int registers including APX extended GPRs. -reg_class all_int_reg(RAX - RDX, - RBP, - RDI, - RSI, - RCX, - RBX, - R8, - R9, - R10, - R11, - R12, - R13, - R14, - R16, - R17, - R18, - R19, - R20, - R21, - R22, - R23, - R24, - R25, - R26, - R27, - R28, - R29, - R30, - R31); - -// Class for all pointer registers -reg_class any_reg %{ - return _ANY_REG_mask; -%} - -// Class for all pointer registers (excluding RSP) -reg_class ptr_reg %{ - return _PTR_REG_mask; -%} - -// Class for all pointer registers (excluding RSP and RBP) -reg_class ptr_reg_no_rbp %{ - return _PTR_REG_NO_RBP_mask; -%} - -// Class for all pointer registers (excluding RAX and RSP) -reg_class ptr_no_rax_reg %{ - return _PTR_NO_RAX_REG_mask; -%} - -// Class for all pointer registers (excluding RAX, RBX, and RSP) -reg_class ptr_no_rax_rbx_reg %{ - return _PTR_NO_RAX_RBX_REG_mask; -%} - -// Class for all long registers (excluding RSP) -reg_class long_reg %{ - return _LONG_REG_mask; -%} - -// Class for all long registers (excluding RAX, RDX and RSP) -reg_class long_no_rax_rdx_reg %{ - return _LONG_NO_RAX_RDX_REG_mask; -%} - -// Class for all long registers (excluding RCX and RSP) -reg_class long_no_rcx_reg %{ - return _LONG_NO_RCX_REG_mask; -%} - -// Class for all long registers (excluding RBP and R13) -reg_class long_no_rbp_r13_reg %{ - return _LONG_NO_RBP_R13_REG_mask; -%} - -// Class for all int registers (excluding RSP) -reg_class int_reg %{ - return _INT_REG_mask; -%} - -// Class for all int registers (excluding RAX, RDX, and RSP) -reg_class int_no_rax_rdx_reg %{ - return _INT_NO_RAX_RDX_REG_mask; -%} - -// Class for all int registers (excluding RCX and RSP) -reg_class int_no_rcx_reg %{ - return _INT_NO_RCX_REG_mask; -%} - -// Class for all int registers (excluding RBP and R13) -reg_class int_no_rbp_r13_reg %{ - return _INT_NO_RBP_R13_REG_mask; -%} - -// Singleton class for RAX pointer register -reg_class ptr_rax_reg(RAX, RAX_H); - -// Singleton class for RBX pointer register -reg_class ptr_rbx_reg(RBX, RBX_H); - -// Singleton class for RSI pointer register -reg_class ptr_rsi_reg(RSI, RSI_H); - -// Singleton class for RBP pointer register -reg_class ptr_rbp_reg(RBP, RBP_H); - -// Singleton class for RDI pointer register -reg_class ptr_rdi_reg(RDI, RDI_H); - -// Singleton class for stack pointer -reg_class ptr_rsp_reg(RSP, RSP_H); - -// Singleton class for TLS pointer -reg_class ptr_r15_reg(R15, R15_H); - -// Singleton class for RAX long register -reg_class long_rax_reg(RAX, RAX_H); - -// Singleton class for RCX long register -reg_class long_rcx_reg(RCX, RCX_H); - -// Singleton class for RDX long register -reg_class long_rdx_reg(RDX, RDX_H); - -// Singleton class for R11 long register -reg_class long_r11_reg(R11, R11_H); - -// Singleton class for RAX int register -reg_class int_rax_reg(RAX); - -// Singleton class for RBX int register -reg_class int_rbx_reg(RBX); - -// Singleton class for RCX int register -reg_class int_rcx_reg(RCX); - -// Singleton class for RDX int register -reg_class int_rdx_reg(RDX); - -// Singleton class for RDI int register -reg_class int_rdi_reg(RDI); - -// Singleton class for instruction pointer -// reg_class ip_reg(RIP); - -%} - -//----------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 %{ - -#include "peephole_x86_64.hpp" - -bool castLL_is_imm32(const Node* n); - -%} - -source %{ - -bool castLL_is_imm32(const Node* n) { - assert(n->is_CastLL(), "must be a CastLL"); - const TypeLong* t = n->bottom_type()->is_long(); - return (t->_lo == min_jlong || Assembler::is_simm32(t->_lo)) && (t->_hi == max_jlong || Assembler::is_simm32(t->_hi)); -} - -%} - -// Register masks -source_hpp %{ - -extern RegMask _ANY_REG_mask; -extern RegMask _PTR_REG_mask; -extern RegMask _PTR_REG_NO_RBP_mask; -extern RegMask _PTR_NO_RAX_REG_mask; -extern RegMask _PTR_NO_RAX_RBX_REG_mask; -extern RegMask _LONG_REG_mask; -extern RegMask _LONG_NO_RAX_RDX_REG_mask; -extern RegMask _LONG_NO_RCX_REG_mask; -extern RegMask _LONG_NO_RBP_R13_REG_mask; -extern RegMask _INT_REG_mask; -extern RegMask _INT_NO_RAX_RDX_REG_mask; -extern RegMask _INT_NO_RCX_REG_mask; -extern RegMask _INT_NO_RBP_R13_REG_mask; -extern RegMask _FLOAT_REG_mask; - -extern RegMask _STACK_OR_PTR_REG_mask; -extern RegMask _STACK_OR_LONG_REG_mask; -extern RegMask _STACK_OR_INT_REG_mask; - -inline const RegMask& STACK_OR_PTR_REG_mask() { return _STACK_OR_PTR_REG_mask; } -inline const RegMask& STACK_OR_LONG_REG_mask() { return _STACK_OR_LONG_REG_mask; } -inline const RegMask& STACK_OR_INT_REG_mask() { return _STACK_OR_INT_REG_mask; } - -%} - -source %{ -#define RELOC_IMM64 Assembler::imm_operand -#define RELOC_DISP32 Assembler::disp32_operand - -#define __ masm-> - -RegMask _ANY_REG_mask; -RegMask _PTR_REG_mask; -RegMask _PTR_REG_NO_RBP_mask; -RegMask _PTR_NO_RAX_REG_mask; -RegMask _PTR_NO_RAX_RBX_REG_mask; -RegMask _LONG_REG_mask; -RegMask _LONG_NO_RAX_RDX_REG_mask; -RegMask _LONG_NO_RCX_REG_mask; -RegMask _LONG_NO_RBP_R13_REG_mask; -RegMask _INT_REG_mask; -RegMask _INT_NO_RAX_RDX_REG_mask; -RegMask _INT_NO_RCX_REG_mask; -RegMask _INT_NO_RBP_R13_REG_mask; -RegMask _FLOAT_REG_mask; -RegMask _STACK_OR_PTR_REG_mask; -RegMask _STACK_OR_LONG_REG_mask; -RegMask _STACK_OR_INT_REG_mask; - -static bool need_r12_heapbase() { - return UseCompressedOops; -} - -void reg_mask_init() { - constexpr Register egprs[] = {r16, r17, r18, r19, r20, r21, r22, r23, r24, r25, r26, r27, r28, r29, r30, r31}; - - // _ALL_REG_mask is generated by adlc from the all_reg register class below. - // We derive a number of subsets from it. - _ANY_REG_mask.assignFrom(_ALL_REG_mask); - - if (PreserveFramePointer) { - _ANY_REG_mask.remove(OptoReg::as_OptoReg(rbp->as_VMReg())); - _ANY_REG_mask.remove(OptoReg::as_OptoReg(rbp->as_VMReg()->next())); - } - if (need_r12_heapbase()) { - _ANY_REG_mask.remove(OptoReg::as_OptoReg(r12->as_VMReg())); - _ANY_REG_mask.remove(OptoReg::as_OptoReg(r12->as_VMReg()->next())); - } - - _PTR_REG_mask.assignFrom(_ANY_REG_mask); - _PTR_REG_mask.remove(OptoReg::as_OptoReg(rsp->as_VMReg())); - _PTR_REG_mask.remove(OptoReg::as_OptoReg(rsp->as_VMReg()->next())); - _PTR_REG_mask.remove(OptoReg::as_OptoReg(r15->as_VMReg())); - _PTR_REG_mask.remove(OptoReg::as_OptoReg(r15->as_VMReg()->next())); - if (!UseAPX) { - for (uint i = 0; i < sizeof(egprs)/sizeof(Register); i++) { - _PTR_REG_mask.remove(OptoReg::as_OptoReg(egprs[i]->as_VMReg())); - _PTR_REG_mask.remove(OptoReg::as_OptoReg(egprs[i]->as_VMReg()->next())); - } - } - - _STACK_OR_PTR_REG_mask.assignFrom(_PTR_REG_mask); - _STACK_OR_PTR_REG_mask.or_with(STACK_OR_STACK_SLOTS_mask()); - - _PTR_REG_NO_RBP_mask.assignFrom(_PTR_REG_mask); - _PTR_REG_NO_RBP_mask.remove(OptoReg::as_OptoReg(rbp->as_VMReg())); - _PTR_REG_NO_RBP_mask.remove(OptoReg::as_OptoReg(rbp->as_VMReg()->next())); - - _PTR_NO_RAX_REG_mask.assignFrom(_PTR_REG_mask); - _PTR_NO_RAX_REG_mask.remove(OptoReg::as_OptoReg(rax->as_VMReg())); - _PTR_NO_RAX_REG_mask.remove(OptoReg::as_OptoReg(rax->as_VMReg()->next())); - - _PTR_NO_RAX_RBX_REG_mask.assignFrom(_PTR_NO_RAX_REG_mask); - _PTR_NO_RAX_RBX_REG_mask.remove(OptoReg::as_OptoReg(rbx->as_VMReg())); - _PTR_NO_RAX_RBX_REG_mask.remove(OptoReg::as_OptoReg(rbx->as_VMReg()->next())); - - - _LONG_REG_mask.assignFrom(_PTR_REG_mask); - _STACK_OR_LONG_REG_mask.assignFrom(_LONG_REG_mask); - _STACK_OR_LONG_REG_mask.or_with(STACK_OR_STACK_SLOTS_mask()); - - _LONG_NO_RAX_RDX_REG_mask.assignFrom(_LONG_REG_mask); - _LONG_NO_RAX_RDX_REG_mask.remove(OptoReg::as_OptoReg(rax->as_VMReg())); - _LONG_NO_RAX_RDX_REG_mask.remove(OptoReg::as_OptoReg(rax->as_VMReg()->next())); - _LONG_NO_RAX_RDX_REG_mask.remove(OptoReg::as_OptoReg(rdx->as_VMReg())); - _LONG_NO_RAX_RDX_REG_mask.remove(OptoReg::as_OptoReg(rdx->as_VMReg()->next())); - - _LONG_NO_RCX_REG_mask.assignFrom(_LONG_REG_mask); - _LONG_NO_RCX_REG_mask.remove(OptoReg::as_OptoReg(rcx->as_VMReg())); - _LONG_NO_RCX_REG_mask.remove(OptoReg::as_OptoReg(rcx->as_VMReg()->next())); - - _LONG_NO_RBP_R13_REG_mask.assignFrom(_LONG_REG_mask); - _LONG_NO_RBP_R13_REG_mask.remove(OptoReg::as_OptoReg(rbp->as_VMReg())); - _LONG_NO_RBP_R13_REG_mask.remove(OptoReg::as_OptoReg(rbp->as_VMReg()->next())); - _LONG_NO_RBP_R13_REG_mask.remove(OptoReg::as_OptoReg(r13->as_VMReg())); - _LONG_NO_RBP_R13_REG_mask.remove(OptoReg::as_OptoReg(r13->as_VMReg()->next())); - - _INT_REG_mask.assignFrom(_ALL_INT_REG_mask); - if (!UseAPX) { - for (uint i = 0; i < sizeof(egprs)/sizeof(Register); i++) { - _INT_REG_mask.remove(OptoReg::as_OptoReg(egprs[i]->as_VMReg())); - } - } - - if (PreserveFramePointer) { - _INT_REG_mask.remove(OptoReg::as_OptoReg(rbp->as_VMReg())); - } - if (need_r12_heapbase()) { - _INT_REG_mask.remove(OptoReg::as_OptoReg(r12->as_VMReg())); - } - - _STACK_OR_INT_REG_mask.assignFrom(_INT_REG_mask); - _STACK_OR_INT_REG_mask.or_with(STACK_OR_STACK_SLOTS_mask()); - - _INT_NO_RAX_RDX_REG_mask.assignFrom(_INT_REG_mask); - _INT_NO_RAX_RDX_REG_mask.remove(OptoReg::as_OptoReg(rax->as_VMReg())); - _INT_NO_RAX_RDX_REG_mask.remove(OptoReg::as_OptoReg(rdx->as_VMReg())); - - _INT_NO_RCX_REG_mask.assignFrom(_INT_REG_mask); - _INT_NO_RCX_REG_mask.remove(OptoReg::as_OptoReg(rcx->as_VMReg())); - - _INT_NO_RBP_R13_REG_mask.assignFrom(_INT_REG_mask); - _INT_NO_RBP_R13_REG_mask.remove(OptoReg::as_OptoReg(rbp->as_VMReg())); - _INT_NO_RBP_R13_REG_mask.remove(OptoReg::as_OptoReg(r13->as_VMReg())); - - // _FLOAT_REG_LEGACY_mask/_FLOAT_REG_EVEX_mask is generated by adlc - // from the float_reg_legacy/float_reg_evex register class. - _FLOAT_REG_mask.assignFrom(VM_Version::supports_evex() ? _FLOAT_REG_EVEX_mask : _FLOAT_REG_LEGACY_mask); -} - -static bool generate_vzeroupper(Compile* C) { - return (VM_Version::supports_vzeroupper() && (C->max_vector_size() > 16 || C->clear_upper_avx() == true)) ? true: false; // Generate vzeroupper -} - -static int clear_avx_size() { - return generate_vzeroupper(Compile::current()) ? 3: 0; // vzeroupper -} - -// !!!!! Special hack to get all types of calls to specify the byte offset -// from the start of the call to the point where the return address -// will point. -int MachCallStaticJavaNode::ret_addr_offset() -{ - int offset = 5; // 5 bytes from start of call to where return address points - offset += clear_avx_size(); - return offset; -} - -int MachCallDynamicJavaNode::ret_addr_offset() -{ - int offset = 15; // 15 bytes from start of call to where return address points - offset += clear_avx_size(); - return offset; -} - -int MachCallRuntimeNode::ret_addr_offset() { - int offset = 13; // movq r10,#addr; callq (r10) - if (this->ideal_Opcode() != Op_CallLeafVector) { - offset += clear_avx_size(); - } - return offset; -} -// -// Compute padding required for nodes which need alignment -// - -// The address of the call instruction needs to be 4-byte aligned to -// ensure that it does not span a cache line so that it can be patched. -int CallStaticJavaDirectNode::compute_padding(int current_offset) const -{ - current_offset += clear_avx_size(); // skip vzeroupper - current_offset += 1; // skip call opcode byte - return align_up(current_offset, alignment_required()) - current_offset; -} - -// The address of the call instruction needs to be 4-byte aligned to -// ensure that it does not span a cache line so that it can be patched. -int CallDynamicJavaDirectNode::compute_padding(int current_offset) const -{ - current_offset += clear_avx_size(); // skip vzeroupper - current_offset += 11; // skip movq instruction + call opcode byte - return align_up(current_offset, alignment_required()) - current_offset; -} - -// This could be in MacroAssembler but it's fairly C2 specific -static void emit_cmpfp_fixup(MacroAssembler* masm) { - Label exit; - __ jccb(Assembler::noParity, exit); - __ pushf(); - // - // comiss/ucomiss instructions set ZF,PF,CF flags and - // zero OF,AF,SF for NaN values. - // Fixup flags by zeroing ZF,PF so that compare of NaN - // values returns 'less than' result (CF is set). - // Leave the rest of flags unchanged. - // - // 7 6 5 4 3 2 1 0 - // |S|Z|r|A|r|P|r|C| (r - reserved bit) - // 0 0 1 0 1 0 1 1 (0x2B) - // - __ andq(Address(rsp, 0), 0xffffff2b); - __ popf(); - __ bind(exit); -} - -static void emit_cmpfp3(MacroAssembler* masm, Register dst) { - Label done; - __ movl(dst, -1); - __ jcc(Assembler::parity, done); - __ jcc(Assembler::below, done); - __ setcc(Assembler::notEqual, dst); - __ bind(done); -} - -// Math.min() # Math.max() -// -------------------------- -// ucomis[s/d] # -// ja -> b # a -// jp -> NaN # NaN -// jb -> a # b -// je # -// |-jz -> a | b # a & b -// | -> a # -static void emit_fp_min_max(MacroAssembler* masm, XMMRegister dst, - XMMRegister a, XMMRegister b, - XMMRegister xmmt, Register rt, - bool min, bool single) { - - Label nan, zero, below, above, done; - - if (single) - __ ucomiss(a, b); - else - __ ucomisd(a, b); - - if (dst->encoding() != (min ? b : a)->encoding()) - __ jccb(Assembler::above, above); // CF=0 & ZF=0 - else - __ jccb(Assembler::above, done); - - __ jccb(Assembler::parity, nan); // PF=1 - __ jccb(Assembler::below, below); // CF=1 - - // equal - __ vpxor(xmmt, xmmt, xmmt, Assembler::AVX_128bit); - if (single) { - __ ucomiss(a, xmmt); - __ jccb(Assembler::equal, zero); - - __ movflt(dst, a); - __ jmp(done); - } - else { - __ ucomisd(a, xmmt); - __ jccb(Assembler::equal, zero); - - __ movdbl(dst, a); - __ jmp(done); - } - - __ bind(zero); - if (min) - __ vpor(dst, a, b, Assembler::AVX_128bit); - else - __ vpand(dst, a, b, Assembler::AVX_128bit); - - __ jmp(done); - - __ bind(above); - if (single) - __ movflt(dst, min ? b : a); - else - __ movdbl(dst, min ? b : a); - - __ jmp(done); - - __ bind(nan); - if (single) { - __ movl(rt, 0x7fc00000); // Float.NaN - __ movdl(dst, rt); - } - else { - __ mov64(rt, 0x7ff8000000000000L); // Double.NaN - __ movdq(dst, rt); - } - __ jmp(done); - - __ bind(below); - if (single) - __ movflt(dst, min ? a : b); - else - __ movdbl(dst, min ? a : b); - - __ bind(done); -} - -//============================================================================= -const RegMask& MachConstantBaseNode::_out_RegMask = RegMask::EMPTY; - -int ConstantTable::calculate_table_base_offset() const { - return 0; // absolute addressing, no offset -} - -bool MachConstantBaseNode::requires_postalloc_expand() const { return false; } -void MachConstantBaseNode::postalloc_expand(GrowableArray *nodes, PhaseRegAlloc *ra_) { - ShouldNotReachHere(); -} - -void MachConstantBaseNode::emit(C2_MacroAssembler* masm, PhaseRegAlloc* ra_) const { - // Empty encoding -} - -uint MachConstantBaseNode::size(PhaseRegAlloc* ra_) const { - return 0; -} - -#ifndef PRODUCT -void MachConstantBaseNode::format(PhaseRegAlloc* ra_, outputStream* st) const { - st->print("# MachConstantBaseNode (empty encoding)"); -} -#endif - - -//============================================================================= -#ifndef PRODUCT -void MachPrologNode::format(PhaseRegAlloc* ra_, outputStream* st) const { - Compile* C = ra_->C; - - int framesize = C->output()->frame_size_in_bytes(); - int bangsize = C->output()->bang_size_in_bytes(); - assert((framesize & (StackAlignmentInBytes-1)) == 0, "frame size not aligned"); - // Remove wordSize for return addr which is already pushed. - framesize -= wordSize; - - if (C->output()->need_stack_bang(bangsize)) { - framesize -= wordSize; - st->print("# stack bang (%d bytes)", bangsize); - st->print("\n\t"); - st->print("pushq rbp\t# Save rbp"); - if (PreserveFramePointer) { - st->print("\n\t"); - st->print("movq rbp, rsp\t# Save the caller's SP into rbp"); - } - if (framesize) { - st->print("\n\t"); - st->print("subq rsp, #%d\t# Create frame",framesize); - } - } else { - st->print("subq rsp, #%d\t# Create frame",framesize); - st->print("\n\t"); - framesize -= wordSize; - st->print("movq [rsp + #%d], rbp\t# Save rbp",framesize); - if (PreserveFramePointer) { - st->print("\n\t"); - st->print("movq rbp, rsp\t# Save the caller's SP into rbp"); - if (framesize > 0) { - st->print("\n\t"); - st->print("addq rbp, #%d", framesize); - } - } - } - - if (VerifyStackAtCalls) { - st->print("\n\t"); - framesize -= wordSize; - st->print("movq [rsp + #%d], 0xbadb100d\t# Majik cookie for stack depth check",framesize); -#ifdef ASSERT - st->print("\n\t"); - st->print("# stack alignment check"); -#endif - } - if (C->stub_function() != nullptr) { - st->print("\n\t"); - st->print("cmpl [r15_thread + #disarmed_guard_value_offset], #disarmed_guard_value\t"); - st->print("\n\t"); - st->print("je fast_entry\t"); - st->print("\n\t"); - st->print("call #nmethod_entry_barrier_stub\t"); - st->print("\n\tfast_entry:"); - } - st->cr(); -} -#endif - -void MachPrologNode::emit(C2_MacroAssembler *masm, PhaseRegAlloc *ra_) const { - Compile* C = ra_->C; - - int framesize = C->output()->frame_size_in_bytes(); - int bangsize = C->output()->bang_size_in_bytes(); - - if (C->clinit_barrier_on_entry()) { - assert(VM_Version::supports_fast_class_init_checks(), "sanity"); - assert(!C->method()->holder()->is_not_initialized(), "initialization should have been started"); - - Label L_skip_barrier; - Register klass = rscratch1; - - __ mov_metadata(klass, C->method()->holder()->constant_encoding()); - __ clinit_barrier(klass, &L_skip_barrier /*L_fast_path*/); - - __ jump(RuntimeAddress(SharedRuntime::get_handle_wrong_method_stub())); // slow path - - __ bind(L_skip_barrier); - } - - __ verified_entry(framesize, C->output()->need_stack_bang(bangsize)?bangsize:0, false, C->stub_function() != nullptr); - - C->output()->set_frame_complete(__ offset()); - - if (C->has_mach_constant_base_node()) { - // NOTE: We set the table base offset here because users might be - // emitted before MachConstantBaseNode. - ConstantTable& constant_table = C->output()->constant_table(); - constant_table.set_table_base_offset(constant_table.calculate_table_base_offset()); - } -} - -uint MachPrologNode::size(PhaseRegAlloc* ra_) const -{ - return MachNode::size(ra_); // too many variables; just compute it - // the hard way -} - -int MachPrologNode::reloc() const -{ - return 0; // a large enough number -} - -//============================================================================= -#ifndef PRODUCT -void MachEpilogNode::format(PhaseRegAlloc* ra_, outputStream* st) const -{ - Compile* C = ra_->C; - if (generate_vzeroupper(C)) { - st->print("vzeroupper"); - st->cr(); st->print("\t"); - } - - int framesize = C->output()->frame_size_in_bytes(); - assert((framesize & (StackAlignmentInBytes-1)) == 0, "frame size not aligned"); - // Remove word for return adr already pushed - // and RBP - framesize -= 2*wordSize; - - if (framesize) { - st->print_cr("addq rsp, %d\t# Destroy frame", framesize); - st->print("\t"); - } - - st->print_cr("popq rbp"); - if (do_polling() && C->is_method_compilation()) { - st->print("\t"); - st->print_cr("cmpq rsp, poll_offset[r15_thread] \n\t" - "ja #safepoint_stub\t" - "# Safepoint: poll for GC"); - } -} -#endif - -void MachEpilogNode::emit(C2_MacroAssembler* masm, PhaseRegAlloc* ra_) const -{ - Compile* C = ra_->C; - - if (generate_vzeroupper(C)) { - // Clear upper bits of YMM registers when current compiled code uses - // wide vectors to avoid AVX <-> SSE transition penalty during call. - __ vzeroupper(); - } - - int framesize = C->output()->frame_size_in_bytes(); - assert((framesize & (StackAlignmentInBytes-1)) == 0, "frame size not aligned"); - // Remove word for return adr already pushed - // and RBP - framesize -= 2*wordSize; - - // Note that VerifyStackAtCalls' Majik cookie does not change the frame size popped here - - if (framesize) { - __ addq(rsp, framesize); - } - - __ popq(rbp); - - if (StackReservedPages > 0 && C->has_reserved_stack_access()) { - __ reserved_stack_check(); - } - - if (do_polling() && C->is_method_compilation()) { - Label dummy_label; - Label* code_stub = &dummy_label; - if (!C->output()->in_scratch_emit_size()) { - C2SafepointPollStub* stub = new (C->comp_arena()) C2SafepointPollStub(__ offset()); - C->output()->add_stub(stub); - code_stub = &stub->entry(); - } - __ relocate(relocInfo::poll_return_type); - __ safepoint_poll(*code_stub, true /* at_return */, true /* in_nmethod */); - } -} - -uint MachEpilogNode::size(PhaseRegAlloc* ra_) const -{ - return MachNode::size(ra_); // too many variables; just compute it - // the hard way -} - -int MachEpilogNode::reloc() const -{ - return 2; // a large enough number -} - -const Pipeline* MachEpilogNode::pipeline() const -{ - return MachNode::pipeline_class(); -} - -//============================================================================= - -enum RC { - rc_bad, - rc_int, - rc_kreg, - 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; - - if (r->is_KRegister()) return rc_kreg; - - assert(r->is_XMMRegister(), "must be"); - return rc_float; -} - -// Next two methods are shared by 32- and 64-bit VM. They are defined in x86.ad. -static void vec_mov_helper(C2_MacroAssembler *masm, int src_lo, int dst_lo, - int src_hi, int dst_hi, uint ireg, outputStream* st); - -void vec_spill_helper(C2_MacroAssembler *masm, bool is_load, - int stack_offset, int reg, uint ireg, outputStream* st); - -static void vec_stack_to_stack_helper(C2_MacroAssembler *masm, int src_offset, - int dst_offset, uint ireg, outputStream* st) { - if (masm) { - switch (ireg) { - case Op_VecS: - __ movq(Address(rsp, -8), rax); - __ movl(rax, Address(rsp, src_offset)); - __ movl(Address(rsp, dst_offset), rax); - __ movq(rax, Address(rsp, -8)); - break; - case Op_VecD: - __ pushq(Address(rsp, src_offset)); - __ popq (Address(rsp, dst_offset)); - break; - case Op_VecX: - __ pushq(Address(rsp, src_offset)); - __ popq (Address(rsp, dst_offset)); - __ pushq(Address(rsp, src_offset+8)); - __ popq (Address(rsp, dst_offset+8)); - break; - case Op_VecY: - __ vmovdqu(Address(rsp, -32), xmm0); - __ vmovdqu(xmm0, Address(rsp, src_offset)); - __ vmovdqu(Address(rsp, dst_offset), xmm0); - __ vmovdqu(xmm0, Address(rsp, -32)); - break; - case Op_VecZ: - __ evmovdquq(Address(rsp, -64), xmm0, 2); - __ evmovdquq(xmm0, Address(rsp, src_offset), 2); - __ evmovdquq(Address(rsp, dst_offset), xmm0, 2); - __ evmovdquq(xmm0, Address(rsp, -64), 2); - break; - default: - ShouldNotReachHere(); - } -#ifndef PRODUCT - } else { - switch (ireg) { - case Op_VecS: - st->print("movq [rsp - #8], rax\t# 32-bit mem-mem spill\n\t" - "movl rax, [rsp + #%d]\n\t" - "movl [rsp + #%d], rax\n\t" - "movq rax, [rsp - #8]", - src_offset, dst_offset); - break; - case Op_VecD: - st->print("pushq [rsp + #%d]\t# 64-bit mem-mem spill\n\t" - "popq [rsp + #%d]", - src_offset, dst_offset); - break; - case Op_VecX: - st->print("pushq [rsp + #%d]\t# 128-bit mem-mem spill\n\t" - "popq [rsp + #%d]\n\t" - "pushq [rsp + #%d]\n\t" - "popq [rsp + #%d]", - src_offset, dst_offset, src_offset+8, dst_offset+8); - break; - case Op_VecY: - st->print("vmovdqu [rsp - #32], xmm0\t# 256-bit mem-mem spill\n\t" - "vmovdqu xmm0, [rsp + #%d]\n\t" - "vmovdqu [rsp + #%d], xmm0\n\t" - "vmovdqu xmm0, [rsp - #32]", - src_offset, dst_offset); - break; - case Op_VecZ: - st->print("vmovdqu [rsp - #64], xmm0\t# 512-bit mem-mem spill\n\t" - "vmovdqu xmm0, [rsp + #%d]\n\t" - "vmovdqu [rsp + #%d], xmm0\n\t" - "vmovdqu xmm0, [rsp - #64]", - src_offset, dst_offset); - break; - default: - ShouldNotReachHere(); - } -#endif - } -} - -uint MachSpillCopyNode::implementation(C2_MacroAssembler* masm, - PhaseRegAlloc* ra_, - bool do_size, - outputStream* st) const { - assert(masm != nullptr || st != nullptr, "sanity"); - // 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" ); - - if (src_first == dst_first && src_second == dst_second) { - // Self copy, no move - return 0; - } - if (bottom_type()->isa_vect() != nullptr && bottom_type()->isa_vectmask() == nullptr) { - uint ireg = ideal_reg(); - assert((src_first_rc != rc_int && dst_first_rc != rc_int), "sanity"); - assert((ireg == Op_VecS || ireg == Op_VecD || ireg == Op_VecX || ireg == Op_VecY || ireg == Op_VecZ ), "sanity"); - if( src_first_rc == rc_stack && dst_first_rc == rc_stack ) { - // mem -> mem - int src_offset = ra_->reg2offset(src_first); - int dst_offset = ra_->reg2offset(dst_first); - vec_stack_to_stack_helper(masm, src_offset, dst_offset, ireg, st); - } else if (src_first_rc == rc_float && dst_first_rc == rc_float ) { - vec_mov_helper(masm, src_first, dst_first, src_second, dst_second, ireg, st); - } else if (src_first_rc == rc_float && dst_first_rc == rc_stack ) { - int stack_offset = ra_->reg2offset(dst_first); - vec_spill_helper(masm, false, stack_offset, src_first, ireg, st); - } else if (src_first_rc == rc_stack && dst_first_rc == rc_float ) { - int stack_offset = ra_->reg2offset(src_first); - vec_spill_helper(masm, true, stack_offset, dst_first, ireg, st); - } else { - ShouldNotReachHere(); - } - return 0; - } - if (src_first_rc == rc_stack) { - // mem -> - if (dst_first_rc == rc_stack) { - // mem -> mem - assert(src_second != dst_first, "overlap"); - if ((src_first & 1) == 0 && src_first + 1 == src_second && - (dst_first & 1) == 0 && dst_first + 1 == dst_second) { - // 64-bit - int src_offset = ra_->reg2offset(src_first); - int dst_offset = ra_->reg2offset(dst_first); - if (masm) { - __ pushq(Address(rsp, src_offset)); - __ popq (Address(rsp, dst_offset)); -#ifndef PRODUCT - } else { - st->print("pushq [rsp + #%d]\t# 64-bit mem-mem spill\n\t" - "popq [rsp + #%d]", - src_offset, dst_offset); -#endif - } - } else { - // 32-bit - assert(!((src_first & 1) == 0 && src_first + 1 == src_second), "no transform"); - assert(!((dst_first & 1) == 0 && dst_first + 1 == dst_second), "no transform"); - // No pushl/popl, so: - int src_offset = ra_->reg2offset(src_first); - int dst_offset = ra_->reg2offset(dst_first); - if (masm) { - __ movq(Address(rsp, -8), rax); - __ movl(rax, Address(rsp, src_offset)); - __ movl(Address(rsp, dst_offset), rax); - __ movq(rax, Address(rsp, -8)); -#ifndef PRODUCT - } else { - st->print("movq [rsp - #8], rax\t# 32-bit mem-mem spill\n\t" - "movl rax, [rsp + #%d]\n\t" - "movl [rsp + #%d], rax\n\t" - "movq rax, [rsp - #8]", - src_offset, dst_offset); -#endif - } - } - return 0; - } else if (dst_first_rc == rc_int) { - // mem -> gpr - if ((src_first & 1) == 0 && src_first + 1 == src_second && - (dst_first & 1) == 0 && dst_first + 1 == dst_second) { - // 64-bit - int offset = ra_->reg2offset(src_first); - if (masm) { - __ movq(as_Register(Matcher::_regEncode[dst_first]), Address(rsp, offset)); -#ifndef PRODUCT - } else { - st->print("movq %s, [rsp + #%d]\t# spill", - Matcher::regName[dst_first], - offset); -#endif - } - } else { - // 32-bit - assert(!((src_first & 1) == 0 && src_first + 1 == src_second), "no transform"); - assert(!((dst_first & 1) == 0 && dst_first + 1 == dst_second), "no transform"); - int offset = ra_->reg2offset(src_first); - if (masm) { - __ movl(as_Register(Matcher::_regEncode[dst_first]), Address(rsp, offset)); -#ifndef PRODUCT - } else { - st->print("movl %s, [rsp + #%d]\t# spill", - Matcher::regName[dst_first], - offset); -#endif - } - } - return 0; - } else if (dst_first_rc == rc_float) { - // mem-> xmm - if ((src_first & 1) == 0 && src_first + 1 == src_second && - (dst_first & 1) == 0 && dst_first + 1 == dst_second) { - // 64-bit - int offset = ra_->reg2offset(src_first); - if (masm) { - __ movdbl( as_XMMRegister(Matcher::_regEncode[dst_first]), Address(rsp, offset)); -#ifndef PRODUCT - } else { - st->print("%s %s, [rsp + #%d]\t# spill", - UseXmmLoadAndClearUpper ? "movsd " : "movlpd", - Matcher::regName[dst_first], - offset); -#endif - } - } else { - // 32-bit - assert(!((src_first & 1) == 0 && src_first + 1 == src_second), "no transform"); - assert(!((dst_first & 1) == 0 && dst_first + 1 == dst_second), "no transform"); - int offset = ra_->reg2offset(src_first); - if (masm) { - __ movflt( as_XMMRegister(Matcher::_regEncode[dst_first]), Address(rsp, offset)); -#ifndef PRODUCT - } else { - st->print("movss %s, [rsp + #%d]\t# spill", - Matcher::regName[dst_first], - offset); -#endif - } - } - return 0; - } else if (dst_first_rc == rc_kreg) { - // mem -> kreg - if ((src_first & 1) == 0 && src_first + 1 == src_second && - (dst_first & 1) == 0 && dst_first + 1 == dst_second) { - // 64-bit - int offset = ra_->reg2offset(src_first); - if (masm) { - __ kmov(as_KRegister(Matcher::_regEncode[dst_first]), Address(rsp, offset)); -#ifndef PRODUCT - } else { - st->print("kmovq %s, [rsp + #%d]\t# spill", - Matcher::regName[dst_first], - offset); -#endif - } - } - return 0; - } - } else if (src_first_rc == rc_int) { - // gpr -> - if (dst_first_rc == rc_stack) { - // gpr -> mem - if ((src_first & 1) == 0 && src_first + 1 == src_second && - (dst_first & 1) == 0 && dst_first + 1 == dst_second) { - // 64-bit - int offset = ra_->reg2offset(dst_first); - if (masm) { - __ movq(Address(rsp, offset), as_Register(Matcher::_regEncode[src_first])); -#ifndef PRODUCT - } else { - st->print("movq [rsp + #%d], %s\t# spill", - offset, - Matcher::regName[src_first]); -#endif - } - } else { - // 32-bit - assert(!((src_first & 1) == 0 && src_first + 1 == src_second), "no transform"); - assert(!((dst_first & 1) == 0 && dst_first + 1 == dst_second), "no transform"); - int offset = ra_->reg2offset(dst_first); - if (masm) { - __ movl(Address(rsp, offset), as_Register(Matcher::_regEncode[src_first])); -#ifndef PRODUCT - } else { - st->print("movl [rsp + #%d], %s\t# spill", - offset, - Matcher::regName[src_first]); -#endif - } - } - return 0; - } else if (dst_first_rc == rc_int) { - // gpr -> gpr - if ((src_first & 1) == 0 && src_first + 1 == src_second && - (dst_first & 1) == 0 && dst_first + 1 == dst_second) { - // 64-bit - if (masm) { - __ movq(as_Register(Matcher::_regEncode[dst_first]), - as_Register(Matcher::_regEncode[src_first])); -#ifndef PRODUCT - } else { - st->print("movq %s, %s\t# spill", - Matcher::regName[dst_first], - Matcher::regName[src_first]); -#endif - } - return 0; - } else { - // 32-bit - assert(!((src_first & 1) == 0 && src_first + 1 == src_second), "no transform"); - assert(!((dst_first & 1) == 0 && dst_first + 1 == dst_second), "no transform"); - if (masm) { - __ movl(as_Register(Matcher::_regEncode[dst_first]), - as_Register(Matcher::_regEncode[src_first])); -#ifndef PRODUCT - } else { - st->print("movl %s, %s\t# spill", - Matcher::regName[dst_first], - Matcher::regName[src_first]); -#endif - } - return 0; - } - } else if (dst_first_rc == rc_float) { - // gpr -> xmm - if ((src_first & 1) == 0 && src_first + 1 == src_second && - (dst_first & 1) == 0 && dst_first + 1 == dst_second) { - // 64-bit - if (masm) { - __ movdq( as_XMMRegister(Matcher::_regEncode[dst_first]), as_Register(Matcher::_regEncode[src_first])); -#ifndef PRODUCT - } else { - st->print("movdq %s, %s\t# spill", - Matcher::regName[dst_first], - Matcher::regName[src_first]); -#endif - } - } else { - // 32-bit - assert(!((src_first & 1) == 0 && src_first + 1 == src_second), "no transform"); - assert(!((dst_first & 1) == 0 && dst_first + 1 == dst_second), "no transform"); - if (masm) { - __ movdl( as_XMMRegister(Matcher::_regEncode[dst_first]), as_Register(Matcher::_regEncode[src_first])); -#ifndef PRODUCT - } else { - st->print("movdl %s, %s\t# spill", - Matcher::regName[dst_first], - Matcher::regName[src_first]); -#endif - } - } - return 0; - } else if (dst_first_rc == rc_kreg) { - if ((src_first & 1) == 0 && src_first + 1 == src_second && - (dst_first & 1) == 0 && dst_first + 1 == dst_second) { - // 64-bit - if (masm) { - __ kmov(as_KRegister(Matcher::_regEncode[dst_first]), as_Register(Matcher::_regEncode[src_first])); - #ifndef PRODUCT - } else { - st->print("kmovq %s, %s\t# spill", - Matcher::regName[dst_first], - Matcher::regName[src_first]); - #endif - } - } - Unimplemented(); - return 0; - } - } else if (src_first_rc == rc_float) { - // xmm -> - if (dst_first_rc == rc_stack) { - // xmm -> mem - if ((src_first & 1) == 0 && src_first + 1 == src_second && - (dst_first & 1) == 0 && dst_first + 1 == dst_second) { - // 64-bit - int offset = ra_->reg2offset(dst_first); - if (masm) { - __ movdbl( Address(rsp, offset), as_XMMRegister(Matcher::_regEncode[src_first])); -#ifndef PRODUCT - } else { - st->print("movsd [rsp + #%d], %s\t# spill", - offset, - Matcher::regName[src_first]); -#endif - } - } else { - // 32-bit - assert(!((src_first & 1) == 0 && src_first + 1 == src_second), "no transform"); - assert(!((dst_first & 1) == 0 && dst_first + 1 == dst_second), "no transform"); - int offset = ra_->reg2offset(dst_first); - if (masm) { - __ movflt(Address(rsp, offset), as_XMMRegister(Matcher::_regEncode[src_first])); -#ifndef PRODUCT - } else { - st->print("movss [rsp + #%d], %s\t# spill", - offset, - Matcher::regName[src_first]); -#endif - } - } - return 0; - } else if (dst_first_rc == rc_int) { - // xmm -> gpr - if ((src_first & 1) == 0 && src_first + 1 == src_second && - (dst_first & 1) == 0 && dst_first + 1 == dst_second) { - // 64-bit - if (masm) { - __ movdq( as_Register(Matcher::_regEncode[dst_first]), as_XMMRegister(Matcher::_regEncode[src_first])); -#ifndef PRODUCT - } else { - st->print("movdq %s, %s\t# spill", - Matcher::regName[dst_first], - Matcher::regName[src_first]); -#endif - } - } else { - // 32-bit - assert(!((src_first & 1) == 0 && src_first + 1 == src_second), "no transform"); - assert(!((dst_first & 1) == 0 && dst_first + 1 == dst_second), "no transform"); - if (masm) { - __ movdl( as_Register(Matcher::_regEncode[dst_first]), as_XMMRegister(Matcher::_regEncode[src_first])); -#ifndef PRODUCT - } else { - st->print("movdl %s, %s\t# spill", - Matcher::regName[dst_first], - Matcher::regName[src_first]); -#endif - } - } - return 0; - } else if (dst_first_rc == rc_float) { - // xmm -> xmm - if ((src_first & 1) == 0 && src_first + 1 == src_second && - (dst_first & 1) == 0 && dst_first + 1 == dst_second) { - // 64-bit - if (masm) { - __ movdbl( as_XMMRegister(Matcher::_regEncode[dst_first]), as_XMMRegister(Matcher::_regEncode[src_first])); -#ifndef PRODUCT - } else { - st->print("%s %s, %s\t# spill", - UseXmmRegToRegMoveAll ? "movapd" : "movsd ", - Matcher::regName[dst_first], - Matcher::regName[src_first]); -#endif - } - } else { - // 32-bit - assert(!((src_first & 1) == 0 && src_first + 1 == src_second), "no transform"); - assert(!((dst_first & 1) == 0 && dst_first + 1 == dst_second), "no transform"); - if (masm) { - __ movflt( as_XMMRegister(Matcher::_regEncode[dst_first]), as_XMMRegister(Matcher::_regEncode[src_first])); -#ifndef PRODUCT - } else { - st->print("%s %s, %s\t# spill", - UseXmmRegToRegMoveAll ? "movaps" : "movss ", - Matcher::regName[dst_first], - Matcher::regName[src_first]); -#endif - } - } - return 0; - } else if (dst_first_rc == rc_kreg) { - assert(false, "Illegal spilling"); - return 0; - } - } else if (src_first_rc == rc_kreg) { - if (dst_first_rc == rc_stack) { - // mem -> kreg - if ((src_first & 1) == 0 && src_first + 1 == src_second && - (dst_first & 1) == 0 && dst_first + 1 == dst_second) { - // 64-bit - int offset = ra_->reg2offset(dst_first); - if (masm) { - __ kmov(Address(rsp, offset), as_KRegister(Matcher::_regEncode[src_first])); -#ifndef PRODUCT - } else { - st->print("kmovq [rsp + #%d] , %s\t# spill", - offset, - Matcher::regName[src_first]); -#endif - } - } - return 0; - } else if (dst_first_rc == rc_int) { - if ((src_first & 1) == 0 && src_first + 1 == src_second && - (dst_first & 1) == 0 && dst_first + 1 == dst_second) { - // 64-bit - if (masm) { - __ kmov(as_Register(Matcher::_regEncode[dst_first]), as_KRegister(Matcher::_regEncode[src_first])); -#ifndef PRODUCT - } else { - st->print("kmovq %s, %s\t# spill", - Matcher::regName[dst_first], - Matcher::regName[src_first]); -#endif - } - } - Unimplemented(); - return 0; - } else if (dst_first_rc == rc_kreg) { - if ((src_first & 1) == 0 && src_first + 1 == src_second && - (dst_first & 1) == 0 && dst_first + 1 == dst_second) { - // 64-bit - if (masm) { - __ kmov(as_KRegister(Matcher::_regEncode[dst_first]), as_KRegister(Matcher::_regEncode[src_first])); -#ifndef PRODUCT - } else { - st->print("kmovq %s, %s\t# spill", - Matcher::regName[dst_first], - Matcher::regName[src_first]); -#endif - } - } - return 0; - } else if (dst_first_rc == rc_float) { - assert(false, "Illegal spill"); - return 0; - } - } - - assert(0," foo "); - Unimplemented(); - return 0; -} - -#ifndef PRODUCT -void MachSpillCopyNode::format(PhaseRegAlloc *ra_, outputStream* st) const { - implementation(nullptr, ra_, false, st); -} -#endif - -void MachSpillCopyNode::emit(C2_MacroAssembler *masm, PhaseRegAlloc *ra_) const { - implementation(masm, ra_, false, nullptr); -} - -uint MachSpillCopyNode::size(PhaseRegAlloc *ra_) const { - return MachNode::size(ra_); -} - -//============================================================================= -#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("leaq %s, [rsp + #%d]\t# box lock", - Matcher::regName[reg], offset); -} -#endif - -void BoxLockNode::emit(C2_MacroAssembler* masm, PhaseRegAlloc* ra_) const -{ - int offset = ra_->reg2offset(in_RegMask(0).find_first_elem()); - int reg = ra_->get_encode(this); - - __ lea(as_Register(reg), Address(rsp, offset)); -} - -uint BoxLockNode::size(PhaseRegAlloc *ra_) const -{ - int offset = ra_->reg2offset(in_RegMask(0).find_first_elem()); - if (ra_->get_encode(this) > 15) { - return (offset < 0x80) ? 6 : 9; // REX2 - } else { - return (offset < 0x80) ? 5 : 8; // REX - } -} - -//============================================================================= -#ifndef PRODUCT -void MachUEPNode::format(PhaseRegAlloc* ra_, outputStream* st) const -{ - if (UseCompressedClassPointers) { - st->print_cr("movl rscratch1, [j_rarg0 + oopDesc::klass_offset_in_bytes()]\t# compressed klass"); - st->print_cr("\tcmpl rscratch1, [rax + CompiledICData::speculated_klass_offset()]\t # Inline cache check"); - } else { - st->print_cr("movq rscratch1, [j_rarg0 + oopDesc::klass_offset_in_bytes()]\t# compressed klass"); - st->print_cr("\tcmpq rscratch1, [rax + CompiledICData::speculated_klass_offset()]\t # Inline cache check"); - } - st->print_cr("\tjne SharedRuntime::_ic_miss_stub"); -} -#endif - -void MachUEPNode::emit(C2_MacroAssembler* masm, PhaseRegAlloc* ra_) const -{ - __ ic_check(InteriorEntryAlignment); -} - -uint MachUEPNode::size(PhaseRegAlloc* ra_) const -{ - return MachNode::size(ra_); // too many variables; just compute it - // the hard way -} - - -//============================================================================= - -bool Matcher::supports_vector_calling_convention(void) { - return EnableVectorSupport; -} - -OptoRegPair Matcher::vector_return_value(uint ideal_reg) { - assert(EnableVectorSupport, "sanity"); - int lo = XMM0_num; - int hi = XMM0b_num; - if (ideal_reg == Op_VecX) hi = XMM0d_num; - else if (ideal_reg == Op_VecY) hi = XMM0h_num; - else if (ideal_reg == Op_VecZ) hi = XMM0p_num; - return OptoRegPair(hi, lo); -} - -// 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 86 a branch displacement is calculated relative to address - // of a next instruction. - offset -= br_size; - - // the short version of jmpConUCF2 contains multiple branches, - // making the reach slightly less - if (rule == jmpConUCF2_rule) - return (-126 <= offset && offset <= 125); - return (-128 <= offset && offset <= 127); -} - -// 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) -{ - return - reg == RDI_num || reg == RDI_H_num || - reg == RSI_num || reg == RSI_H_num || - reg == RDX_num || reg == RDX_H_num || - reg == RCX_num || reg == RCX_H_num || - reg == R8_num || reg == R8_H_num || - reg == R9_num || reg == R9_H_num || - reg == R12_num || reg == R12_H_num || - reg == XMM0_num || reg == XMM0b_num || - reg == XMM1_num || reg == XMM1b_num || - reg == XMM2_num || reg == XMM2b_num || - reg == XMM3_num || reg == XMM3b_num || - reg == XMM4_num || reg == XMM4b_num || - reg == XMM5_num || reg == XMM5b_num || - reg == XMM6_num || reg == XMM6b_num || - reg == XMM7_num || reg == XMM7b_num; -} - -bool Matcher::is_spillable_arg(int reg) -{ - return can_be_java_arg(reg); -} - -uint Matcher::int_pressure_limit() -{ - return (INTPRESSURE == -1) ? _INT_REG_mask.size() : INTPRESSURE; -} - -uint Matcher::float_pressure_limit() -{ - // After experiment around with different values, the following default threshold - // works best for LCM's register pressure scheduling on x64. - uint dec_count = VM_Version::supports_evex() ? 4 : 2; - uint default_float_pressure_threshold = _FLOAT_REG_mask.size() - dec_count; - return (FLOATPRESSURE == -1) ? default_float_pressure_threshold : FLOATPRESSURE; -} - -bool Matcher::use_asm_for_ldiv_by_con( jlong divisor ) { - // In 64 bit mode a code which use multiply when - // devisor is constant is faster than hardware - // DIV instruction (it uses MulHiL). - return false; -} - -// Register for DIVI projection of divmodI -const RegMask& Matcher::divI_proj_mask() { - return INT_RAX_REG_mask(); -} - -// Register for MODI projection of divmodI -const RegMask& Matcher::modI_proj_mask() { - return INT_RDX_REG_mask(); -} - -// Register for DIVL projection of divmodL -const RegMask& Matcher::divL_proj_mask() { - return LONG_RAX_REG_mask(); -} - -// Register for MODL projection of divmodL -const RegMask& Matcher::modL_proj_mask() { - return LONG_RDX_REG_mask(); -} - -%} - -//----------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 cdql_enc(no_rax_rdx_RegI div) - %{ - // Full implementation of Java idiv and irem; checks for - // special case as described in JVM spec., p.243 & p.271. - // - // normal case special case - // - // input : rax: dividend min_int - // reg: divisor -1 - // - // output: rax: quotient (= rax idiv reg) min_int - // rdx: remainder (= rax irem reg) 0 - // - // Code sequnce: - // - // 0: 3d 00 00 00 80 cmp $0x80000000,%eax - // 5: 75 07/08 jne e - // 7: 33 d2 xor %edx,%edx - // [div >= 8 -> offset + 1] - // [REX_B] - // 9: 83 f9 ff cmp $0xffffffffffffffff,$div - // c: 74 03/04 je 11 - // 000000000000000e : - // e: 99 cltd - // [div >= 8 -> offset + 1] - // [REX_B] - // f: f7 f9 idiv $div - // 0000000000000011 : - Label normal; - Label done; - - // cmp $0x80000000,%eax - __ cmpl(as_Register(RAX_enc), 0x80000000); - - // jne e - __ jccb(Assembler::notEqual, normal); - - // xor %edx,%edx - __ xorl(as_Register(RDX_enc), as_Register(RDX_enc)); - - // cmp $0xffffffffffffffff,%ecx - __ cmpl($div$$Register, -1); - - // je 11 - __ jccb(Assembler::equal, done); - - // - // cltd - __ bind(normal); - __ cdql(); - - // idivl - // - __ idivl($div$$Register); - __ bind(done); - %} - - enc_class cdqq_enc(no_rax_rdx_RegL div) - %{ - // Full implementation of Java ldiv and lrem; checks for - // special case as described in JVM spec., p.243 & p.271. - // - // normal case special case - // - // input : rax: dividend min_long - // reg: divisor -1 - // - // output: rax: quotient (= rax idiv reg) min_long - // rdx: remainder (= rax irem reg) 0 - // - // Code sequnce: - // - // 0: 48 ba 00 00 00 00 00 mov $0x8000000000000000,%rdx - // 7: 00 00 80 - // a: 48 39 d0 cmp %rdx,%rax - // d: 75 08 jne 17 - // f: 33 d2 xor %edx,%edx - // 11: 48 83 f9 ff cmp $0xffffffffffffffff,$div - // 15: 74 05 je 1c - // 0000000000000017 : - // 17: 48 99 cqto - // 19: 48 f7 f9 idiv $div - // 000000000000001c : - Label normal; - Label done; - - // mov $0x8000000000000000,%rdx - __ mov64(as_Register(RDX_enc), 0x8000000000000000); - - // cmp %rdx,%rax - __ cmpq(as_Register(RAX_enc), as_Register(RDX_enc)); - - // jne 17 - __ jccb(Assembler::notEqual, normal); - - // xor %edx,%edx - __ xorl(as_Register(RDX_enc), as_Register(RDX_enc)); - - // cmp $0xffffffffffffffff,$div - __ cmpq($div$$Register, -1); - - // je 1e - __ jccb(Assembler::equal, done); - - // - // cqto - __ bind(normal); - __ cdqq(); - - // idivq (note: must be emitted by the user of this rule) - // - __ idivq($div$$Register); - __ bind(done); - %} - - enc_class clear_avx %{ - DEBUG_ONLY(int off0 = __ offset()); - if (generate_vzeroupper(Compile::current())) { - // Clear upper bits of YMM registers to avoid AVX <-> SSE transition penalty - // Clear upper bits of YMM registers when current compiled code uses - // wide vectors to avoid AVX <-> SSE transition penalty during call. - __ vzeroupper(); - } - DEBUG_ONLY(int off1 = __ offset()); - assert(off1 - off0 == clear_avx_size(), "correct size prediction"); - %} - - enc_class Java_To_Runtime(method meth) %{ - __ lea(r10, RuntimeAddress((address)$meth$$method)); - __ call(r10); - __ post_call_nop(); - %} - - enc_class Java_Static_Call(method meth) - %{ - // JAVA STATIC CALL - // CALL to fixup routine. Fixup routine uses ScopeDesc info to - // determine who we intended to call. - if (!_method) { - __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, $meth$$method))); - } else if (_method->intrinsic_id() == vmIntrinsicID::_ensureMaterializedForStackWalk) { - // The NOP here is purely to ensure that eliding a call to - // JVM_EnsureMaterializedForStackWalk doesn't change the code size. - __ addr_nop_5(); - __ block_comment("call JVM_EnsureMaterializedForStackWalk (elided)"); - } else { - int method_index = resolved_method_index(masm); - RelocationHolder rspec = _optimized_virtual ? opt_virtual_call_Relocation::spec(method_index) - : static_call_Relocation::spec(method_index); - address mark = __ pc(); - int call_offset = __ offset(); - __ call(AddressLiteral(CAST_FROM_FN_PTR(address, $meth$$method), rspec)); - if (CodeBuffer::supports_shared_stubs() && _method->can_be_statically_bound()) { - // Calls of the same statically bound method can share - // a stub to the interpreter. - __ code()->shared_stub_to_interp_for(_method, call_offset); - } else { - // Emit stubs for static call. - address stub = CompiledDirectCall::emit_to_interp_stub(masm, mark); - __ clear_inst_mark(); - if (stub == nullptr) { - ciEnv::current()->record_failure("CodeCache is full"); - return; - } - } - } - __ post_call_nop(); - %} - - enc_class Java_Dynamic_Call(method meth) %{ - __ ic_call((address)$meth$$method, resolved_method_index(masm)); - __ post_call_nop(); - %} - -%} - - - -//----------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 OptoReg::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, even 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 -// | +--------+----> OptoReg::stack0(), even aligned -// | | pad1 | 11 pad to align new SP -// | +--------+ -// | | | 10 -// | | spills | 9 spills -// V | | 8 (pad0 slot for callee) -// -----------+--------+----> Matcher::_out_arg_limit, unaligned -// ^ | out | 7 -// | | args | 6 Holes in outgoing args owned by CALLEE -// Owned by +--------+ -// CALLEE | new out| 6 Empty on Intel, window on Sparc -// | new |preserve| Must be even-aligned. -// | SP-+--------+----> Matcher::_new_SP, even aligned -// | | | -// -// Note 1: Only region 8-11 is determined by the allocator. Region 0-5 is -// known from SELF's arguments and the Java calling convention. -// Region 6-7 is determined per call site. -// Note 2: If the calling convention leaves holes in the incoming argument -// area, those holes are owned by SELF. Holes in the outgoing area -// are owned by the CALLEE. Holes should not be necessary in the -// incoming area, as the Java calling convention is completely under -// the control of the AD file. Doubles can be sorted and packed to -// avoid holes. Holes in the outgoing arguments may be necessary for -// varargs C calling conventions. -// Note 3: Region 0-3 is even aligned, with pad2 as needed. Region 3-5 is -// even aligned with pad0 as needed. -// Region 6 is even aligned. Region 6-7 is NOT even aligned; -// region 6-11 is even aligned; it may be padded out more so that -// the region from SP to FP meets the minimum stack alignment. -// Note 4: For I2C adapters, the incoming FP may not meet the minimum stack -// alignment. Region 11, pad1, may be dynamically extended so that -// SP meets the minimum alignment. - -frame -%{ - // These three registers define part of the calling convention - // between compiled code and the interpreter. - inline_cache_reg(RAX); // Inline Cache Register - - // Optional: name the operand used by cisc-spilling to access - // [stack_pointer + offset] - cisc_spilling_operand_name(indOffset32); - - // Number of stack slots consumed by locking an object - sync_stack_slots(2); - - // Compiled code's Frame Pointer - frame_pointer(RSP); - - // Interpreter stores its frame pointer in a register which is - // stored to the stack by I2CAdaptors. - // I2CAdaptors convert from interpreted java to compiled java. - interpreter_frame_pointer(RBP); - - // Stack alignment requirement - stack_alignment(StackAlignmentInBytes); // Alignment size in bytes (128-bit -> 16 bytes) - - // Number of outgoing stack slots killed above the out_preserve_stack_slots - // for calls to C. Supports the var-args backing area for register parms. - varargs_C_out_slots_killed(frame::arg_reg_save_area_bytes/BytesPerInt); - - // 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 - 2 + - align_up((Compile::current()->in_preserve_stack_slots() + - Compile::current()->fixed_slots()), - stack_alignment_in_slots())); - - // Location of compiled Java return values. Same as C for now. - return_value - %{ - assert(ideal_reg >= Op_RegI && ideal_reg <= Op_RegL, - "only return normal values"); - - static const int lo[Op_RegL + 1] = { - 0, - 0, - RAX_num, // Op_RegN - RAX_num, // Op_RegI - RAX_num, // Op_RegP - XMM0_num, // Op_RegF - XMM0_num, // Op_RegD - RAX_num // Op_RegL - }; - static const int hi[Op_RegL + 1] = { - 0, - 0, - OptoReg::Bad, // Op_RegN - OptoReg::Bad, // Op_RegI - RAX_H_num, // Op_RegP - OptoReg::Bad, // Op_RegF - XMM0b_num, // Op_RegD - RAX_H_num // Op_RegL - }; - // Excluded flags and vector registers. - assert(ARRAY_SIZE(hi) == _last_machine_leaf - 8, "missing type"); - return OptoRegPair(hi[ideal_reg], lo[ideal_reg]); - %} -%} - -//----------ATTRIBUTES--------------------------------------------------------- -//----------Operand Attributes------------------------------------------------- -op_attrib op_cost(0); // Required cost attribute - -//----------Instruction Attributes--------------------------------------------- -ins_attrib ins_cost(100); // Required cost attribute -ins_attrib ins_size(8); // 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? -ins_attrib ins_alignment(1); // Required alignment attribute (must - // be a power of 2) specifies the - // alignment that some part of the - // instruction (not necessarily the - // start) requires. If > 1, a - // compute_padding() function must be - // provided for the instruction - -// Whether this node is expanded during code emission into a sequence of -// instructions and the first instruction can perform an implicit null check. -ins_attrib ins_is_late_expanded_null_check_candidate(false); - -//----------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 -operand immI() -%{ - match(ConI); - - op_cost(10); - format %{ %} - interface(CONST_INTER); -%} - -// Constant for test vs zero -operand immI_0() -%{ - predicate(n->get_int() == 0); - match(ConI); - - op_cost(0); - format %{ %} - interface(CONST_INTER); -%} - -// Constant for increment -operand immI_1() -%{ - predicate(n->get_int() == 1); - match(ConI); - - op_cost(0); - format %{ %} - interface(CONST_INTER); -%} - -// Constant for decrement -operand immI_M1() -%{ - predicate(n->get_int() == -1); - match(ConI); - - op_cost(0); - format %{ %} - interface(CONST_INTER); -%} - -operand immI_2() -%{ - predicate(n->get_int() == 2); - match(ConI); - - op_cost(0); - format %{ %} - interface(CONST_INTER); -%} - -operand immI_4() -%{ - predicate(n->get_int() == 4); - match(ConI); - - op_cost(0); - format %{ %} - interface(CONST_INTER); -%} - -operand immI_8() -%{ - predicate(n->get_int() == 8); - match(ConI); - - op_cost(0); - format %{ %} - interface(CONST_INTER); -%} - -// Valid scale values for addressing modes -operand immI2() -%{ - predicate(0 <= n->get_int() && (n->get_int() <= 3)); - match(ConI); - - format %{ %} - interface(CONST_INTER); -%} - -operand immU7() -%{ - predicate((0 <= n->get_int()) && (n->get_int() <= 0x7F)); - match(ConI); - - op_cost(5); - format %{ %} - interface(CONST_INTER); -%} - -operand immI8() -%{ - predicate((-0x80 <= n->get_int()) && (n->get_int() < 0x80)); - match(ConI); - - op_cost(5); - format %{ %} - interface(CONST_INTER); -%} - -operand immU8() -%{ - predicate((0 <= n->get_int()) && (n->get_int() <= 255)); - match(ConI); - - op_cost(5); - format %{ %} - interface(CONST_INTER); -%} - -operand immI16() -%{ - predicate((-32768 <= n->get_int()) && (n->get_int() <= 32767)); - match(ConI); - - op_cost(10); - format %{ %} - interface(CONST_INTER); -%} - -// Int Immediate non-negative -operand immU31() -%{ - predicate(n->get_int() >= 0); - match(ConI); - - op_cost(0); - format %{ %} - interface(CONST_INTER); -%} - -// Pointer Immediate -operand immP() -%{ - match(ConP); - - op_cost(10); - format %{ %} - interface(CONST_INTER); -%} - -// Null Pointer Immediate -operand immP0() -%{ - predicate(n->get_ptr() == 0); - match(ConP); - - op_cost(5); - 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(5); - format %{ %} - interface(CONST_INTER); -%} - -operand immP31() -%{ - predicate(n->as_Type()->type()->reloc() == relocInfo::none - && (n->get_ptr() >> 31) == 0); - match(ConP); - - op_cost(5); - format %{ %} - interface(CONST_INTER); -%} - - -// Long Immediate -operand immL() -%{ - match(ConL); - - op_cost(20); - format %{ %} - interface(CONST_INTER); -%} - -// Long Immediate 8-bit -operand immL8() -%{ - predicate(-0x80L <= n->get_long() && n->get_long() < 0x80L); - match(ConL); - - op_cost(5); - format %{ %} - interface(CONST_INTER); -%} - -// Long Immediate 32-bit unsigned -operand immUL32() -%{ - predicate(n->get_long() == (unsigned int) (n->get_long())); - match(ConL); - - op_cost(10); - format %{ %} - interface(CONST_INTER); -%} - -// Long Immediate 32-bit signed -operand immL32() -%{ - predicate(n->get_long() == (int) (n->get_long())); - match(ConL); - - op_cost(15); - format %{ %} - interface(CONST_INTER); -%} - -operand immL_Pow2() -%{ - predicate(is_power_of_2((julong)n->get_long())); - match(ConL); - - op_cost(15); - format %{ %} - interface(CONST_INTER); -%} - -operand immL_NotPow2() -%{ - predicate(is_power_of_2((julong)~n->get_long())); - match(ConL); - - op_cost(15); - format %{ %} - interface(CONST_INTER); -%} - -// Long Immediate zero -operand immL0() -%{ - predicate(n->get_long() == 0L); - match(ConL); - - op_cost(10); - format %{ %} - interface(CONST_INTER); -%} - -// Constant for increment -operand immL1() -%{ - predicate(n->get_long() == 1); - match(ConL); - - format %{ %} - interface(CONST_INTER); -%} - -// Constant for decrement -operand immL_M1() -%{ - predicate(n->get_long() == -1); - match(ConL); - - format %{ %} - interface(CONST_INTER); -%} - -// Long Immediate: low 32-bit mask -operand immL_32bits() -%{ - predicate(n->get_long() == 0xFFFFFFFFL); - match(ConL); - op_cost(20); - - format %{ %} - interface(CONST_INTER); -%} - -// Int Immediate: 2^n-1, positive -operand immI_Pow2M1() -%{ - predicate((n->get_int() > 0) - && is_power_of_2((juint)n->get_int() + 1)); - match(ConI); - - op_cost(20); - format %{ %} - interface(CONST_INTER); -%} - -// Float Immediate zero -operand immF0() -%{ - predicate(jint_cast(n->getf()) == 0); - match(ConF); - - op_cost(5); - format %{ %} - interface(CONST_INTER); -%} - -// Float Immediate -operand immF() -%{ - match(ConF); - - op_cost(15); - format %{ %} - interface(CONST_INTER); -%} - -// Half Float Immediate -operand immH() -%{ - match(ConH); - - op_cost(15); - format %{ %} - interface(CONST_INTER); -%} - -// Double Immediate zero -operand immD0() -%{ - predicate(jlong_cast(n->getd()) == 0); - match(ConD); - - op_cost(5); - format %{ %} - interface(CONST_INTER); -%} - -// Double Immediate -operand immD() -%{ - match(ConD); - - op_cost(15); - format %{ %} - interface(CONST_INTER); -%} - -// Immediates for special shifts (sign extend) - -// Constants for increment -operand immI_16() -%{ - predicate(n->get_int() == 16); - match(ConI); - - format %{ %} - interface(CONST_INTER); -%} - -operand immI_24() -%{ - predicate(n->get_int() == 24); - match(ConI); - - format %{ %} - interface(CONST_INTER); -%} - -// Constant for byte-wide masking -operand immI_255() -%{ - predicate(n->get_int() == 255); - match(ConI); - - format %{ %} - interface(CONST_INTER); -%} - -// Constant for short-wide masking -operand immI_65535() -%{ - predicate(n->get_int() == 65535); - match(ConI); - - format %{ %} - interface(CONST_INTER); -%} - -// Constant for byte-wide masking -operand immL_255() -%{ - predicate(n->get_long() == 255); - match(ConL); - - format %{ %} - interface(CONST_INTER); -%} - -// Constant for short-wide masking -operand immL_65535() -%{ - predicate(n->get_long() == 65535); - match(ConL); - - format %{ %} - interface(CONST_INTER); -%} - -operand kReg() -%{ - constraint(ALLOC_IN_RC(vectmask_reg)); - match(RegVectMask); - format %{%} - interface(REG_INTER); -%} - -// Register Operands -// Integer Register -operand rRegI() -%{ - constraint(ALLOC_IN_RC(int_reg)); - match(RegI); - - match(rax_RegI); - match(rbx_RegI); - match(rcx_RegI); - match(rdx_RegI); - match(rdi_RegI); - - format %{ %} - interface(REG_INTER); -%} - -// Special Registers -operand rax_RegI() -%{ - constraint(ALLOC_IN_RC(int_rax_reg)); - match(RegI); - match(rRegI); - - format %{ "RAX" %} - interface(REG_INTER); -%} - -// Special Registers -operand rbx_RegI() -%{ - constraint(ALLOC_IN_RC(int_rbx_reg)); - match(RegI); - match(rRegI); - - format %{ "RBX" %} - interface(REG_INTER); -%} - -operand rcx_RegI() -%{ - constraint(ALLOC_IN_RC(int_rcx_reg)); - match(RegI); - match(rRegI); - - format %{ "RCX" %} - interface(REG_INTER); -%} - -operand rdx_RegI() -%{ - constraint(ALLOC_IN_RC(int_rdx_reg)); - match(RegI); - match(rRegI); - - format %{ "RDX" %} - interface(REG_INTER); -%} - -operand rdi_RegI() -%{ - constraint(ALLOC_IN_RC(int_rdi_reg)); - match(RegI); - match(rRegI); - - format %{ "RDI" %} - interface(REG_INTER); -%} - -operand no_rax_rdx_RegI() -%{ - constraint(ALLOC_IN_RC(int_no_rax_rdx_reg)); - match(RegI); - match(rbx_RegI); - match(rcx_RegI); - match(rdi_RegI); - - format %{ %} - interface(REG_INTER); -%} - -operand no_rbp_r13_RegI() -%{ - constraint(ALLOC_IN_RC(int_no_rbp_r13_reg)); - match(RegI); - match(rRegI); - match(rax_RegI); - match(rbx_RegI); - match(rcx_RegI); - match(rdx_RegI); - match(rdi_RegI); - - format %{ %} - interface(REG_INTER); -%} - -// Pointer Register -operand any_RegP() -%{ - constraint(ALLOC_IN_RC(any_reg)); - match(RegP); - match(rax_RegP); - match(rbx_RegP); - match(rdi_RegP); - match(rsi_RegP); - match(rbp_RegP); - match(r15_RegP); - match(rRegP); - - format %{ %} - interface(REG_INTER); -%} - -operand rRegP() -%{ - constraint(ALLOC_IN_RC(ptr_reg)); - match(RegP); - match(rax_RegP); - match(rbx_RegP); - match(rdi_RegP); - match(rsi_RegP); - match(rbp_RegP); // See Q&A below about - match(r15_RegP); // r15_RegP and rbp_RegP. - - format %{ %} - interface(REG_INTER); -%} - -operand rRegN() %{ - constraint(ALLOC_IN_RC(int_reg)); - match(RegN); - - format %{ %} - interface(REG_INTER); -%} - -// Question: Why is r15_RegP (the read-only TLS register) a match for rRegP? -// Answer: Operand match rules govern the DFA as it processes instruction inputs. -// It's fine for an instruction input that expects rRegP to match a r15_RegP. -// The output of an instruction is controlled by the allocator, which respects -// register class masks, not match rules. Unless an instruction mentions -// r15_RegP or any_RegP explicitly as its output, r15 will not be considered -// by the allocator as an input. -// The same logic applies to rbp_RegP being a match for rRegP: If PreserveFramePointer==true, -// the RBP is used as a proper frame pointer and is not included in ptr_reg. As a -// result, RBP is not included in the output of the instruction either. - -// This operand is not allowed to use RBP even if -// RBP is not used to hold the frame pointer. -operand no_rbp_RegP() -%{ - constraint(ALLOC_IN_RC(ptr_reg_no_rbp)); - match(RegP); - match(rbx_RegP); - match(rsi_RegP); - match(rdi_RegP); - - format %{ %} - interface(REG_INTER); -%} - -// Special Registers -// Return a pointer value -operand rax_RegP() -%{ - constraint(ALLOC_IN_RC(ptr_rax_reg)); - match(RegP); - match(rRegP); - - format %{ %} - interface(REG_INTER); -%} - -// Special Registers -// Return a compressed pointer value -operand rax_RegN() -%{ - constraint(ALLOC_IN_RC(int_rax_reg)); - match(RegN); - match(rRegN); - - format %{ %} - interface(REG_INTER); -%} - -// Used in AtomicAdd -operand rbx_RegP() -%{ - constraint(ALLOC_IN_RC(ptr_rbx_reg)); - match(RegP); - match(rRegP); - - format %{ %} - interface(REG_INTER); -%} - -operand rsi_RegP() -%{ - constraint(ALLOC_IN_RC(ptr_rsi_reg)); - match(RegP); - match(rRegP); - - format %{ %} - interface(REG_INTER); -%} - -operand rbp_RegP() -%{ - constraint(ALLOC_IN_RC(ptr_rbp_reg)); - match(RegP); - match(rRegP); - - format %{ %} - interface(REG_INTER); -%} - -// Used in rep stosq -operand rdi_RegP() -%{ - constraint(ALLOC_IN_RC(ptr_rdi_reg)); - match(RegP); - match(rRegP); - - format %{ %} - interface(REG_INTER); -%} - -operand r15_RegP() -%{ - constraint(ALLOC_IN_RC(ptr_r15_reg)); - match(RegP); - match(rRegP); - - format %{ %} - interface(REG_INTER); -%} - -operand rRegL() -%{ - constraint(ALLOC_IN_RC(long_reg)); - match(RegL); - match(rax_RegL); - match(rdx_RegL); - - format %{ %} - interface(REG_INTER); -%} - -// Special Registers -operand no_rax_rdx_RegL() -%{ - constraint(ALLOC_IN_RC(long_no_rax_rdx_reg)); - match(RegL); - match(rRegL); - - format %{ %} - interface(REG_INTER); -%} - -operand rax_RegL() -%{ - constraint(ALLOC_IN_RC(long_rax_reg)); - match(RegL); - match(rRegL); - - format %{ "RAX" %} - interface(REG_INTER); -%} - -operand rcx_RegL() -%{ - constraint(ALLOC_IN_RC(long_rcx_reg)); - match(RegL); - match(rRegL); - - format %{ %} - interface(REG_INTER); -%} - -operand rdx_RegL() -%{ - constraint(ALLOC_IN_RC(long_rdx_reg)); - match(RegL); - match(rRegL); - - format %{ %} - interface(REG_INTER); -%} - -operand r11_RegL() -%{ - constraint(ALLOC_IN_RC(long_r11_reg)); - match(RegL); - match(rRegL); - - format %{ %} - interface(REG_INTER); -%} - -operand no_rbp_r13_RegL() -%{ - constraint(ALLOC_IN_RC(long_no_rbp_r13_reg)); - match(RegL); - match(rRegL); - match(rax_RegL); - match(rcx_RegL); - match(rdx_RegL); - - format %{ %} - interface(REG_INTER); -%} - -// Flags register, used as output of compare instructions -operand rFlagsReg() -%{ - constraint(ALLOC_IN_RC(int_flags)); - match(RegFlags); - - format %{ "RFLAGS" %} - interface(REG_INTER); -%} - -// Flags register, used as output of FLOATING POINT compare instructions -operand rFlagsRegU() -%{ - constraint(ALLOC_IN_RC(int_flags)); - match(RegFlags); - - format %{ "RFLAGS_U" %} - interface(REG_INTER); -%} - -operand rFlagsRegUCF() %{ - constraint(ALLOC_IN_RC(int_flags)); - match(RegFlags); - predicate(false); - - format %{ "RFLAGS_U_CF" %} - interface(REG_INTER); -%} - -// Float register operands -operand regF() %{ - constraint(ALLOC_IN_RC(float_reg)); - match(RegF); - - format %{ %} - interface(REG_INTER); -%} - -// Float register operands -operand legRegF() %{ - constraint(ALLOC_IN_RC(float_reg_legacy)); - match(RegF); - - format %{ %} - interface(REG_INTER); -%} - -// Float register operands -operand vlRegF() %{ - constraint(ALLOC_IN_RC(float_reg_vl)); - match(RegF); - - format %{ %} - interface(REG_INTER); -%} - -// Double register operands -operand regD() %{ - constraint(ALLOC_IN_RC(double_reg)); - match(RegD); - - format %{ %} - interface(REG_INTER); -%} - -// Double register operands -operand legRegD() %{ - constraint(ALLOC_IN_RC(double_reg_legacy)); - match(RegD); - - format %{ %} - interface(REG_INTER); -%} - -// Double register operands -operand vlRegD() %{ - constraint(ALLOC_IN_RC(double_reg_vl)); - match(RegD); - - format %{ %} - interface(REG_INTER); -%} - -//----------Memory Operands---------------------------------------------------- -// Direct Memory Operand -// operand direct(immP addr) -// %{ -// match(addr); - -// format %{ "[$addr]" %} -// interface(MEMORY_INTER) %{ -// base(0xFFFFFFFF); -// index(0x4); -// scale(0x0); -// disp($addr); -// %} -// %} - -// Indirect Memory Operand -operand indirect(any_RegP reg) -%{ - constraint(ALLOC_IN_RC(ptr_reg)); - match(reg); - - format %{ "[$reg]" %} - interface(MEMORY_INTER) %{ - base($reg); - index(0x4); - scale(0x0); - disp(0x0); - %} -%} - -// Indirect Memory Plus Short Offset Operand -operand indOffset8(any_RegP reg, immL8 off) -%{ - constraint(ALLOC_IN_RC(ptr_reg)); - match(AddP reg off); - - format %{ "[$reg + $off (8-bit)]" %} - interface(MEMORY_INTER) %{ - base($reg); - index(0x4); - scale(0x0); - disp($off); - %} -%} - -// Indirect Memory Plus Long Offset Operand -operand indOffset32(any_RegP reg, immL32 off) -%{ - constraint(ALLOC_IN_RC(ptr_reg)); - match(AddP reg off); - - format %{ "[$reg + $off (32-bit)]" %} - interface(MEMORY_INTER) %{ - base($reg); - index(0x4); - scale(0x0); - disp($off); - %} -%} - -// Indirect Memory Plus Index Register Plus Offset Operand -operand indIndexOffset(any_RegP reg, rRegL lreg, immL32 off) -%{ - constraint(ALLOC_IN_RC(ptr_reg)); - match(AddP (AddP reg lreg) off); - - op_cost(10); - format %{"[$reg + $off + $lreg]" %} - interface(MEMORY_INTER) %{ - base($reg); - index($lreg); - scale(0x0); - disp($off); - %} -%} - -// Indirect Memory Plus Index Register Plus Offset Operand -operand indIndex(any_RegP reg, rRegL lreg) -%{ - constraint(ALLOC_IN_RC(ptr_reg)); - match(AddP reg lreg); - - op_cost(10); - format %{"[$reg + $lreg]" %} - interface(MEMORY_INTER) %{ - base($reg); - index($lreg); - scale(0x0); - disp(0x0); - %} -%} - -// Indirect Memory Times Scale Plus Index Register -operand indIndexScale(any_RegP reg, rRegL lreg, immI2 scale) -%{ - constraint(ALLOC_IN_RC(ptr_reg)); - match(AddP reg (LShiftL lreg scale)); - - op_cost(10); - format %{"[$reg + $lreg << $scale]" %} - interface(MEMORY_INTER) %{ - base($reg); - index($lreg); - scale($scale); - disp(0x0); - %} -%} - -operand indPosIndexScale(any_RegP reg, rRegI idx, immI2 scale) -%{ - constraint(ALLOC_IN_RC(ptr_reg)); - predicate(n->in(3)->in(1)->as_Type()->type()->is_long()->_lo >= 0); - match(AddP reg (LShiftL (ConvI2L idx) scale)); - - op_cost(10); - format %{"[$reg + pos $idx << $scale]" %} - interface(MEMORY_INTER) %{ - base($reg); - index($idx); - scale($scale); - disp(0x0); - %} -%} - -// Indirect Memory Times Scale Plus Index Register Plus Offset Operand -operand indIndexScaleOffset(any_RegP reg, immL32 off, rRegL lreg, immI2 scale) -%{ - constraint(ALLOC_IN_RC(ptr_reg)); - match(AddP (AddP reg (LShiftL lreg scale)) off); - - op_cost(10); - format %{"[$reg + $off + $lreg << $scale]" %} - interface(MEMORY_INTER) %{ - base($reg); - index($lreg); - scale($scale); - disp($off); - %} -%} - -// Indirect Memory Plus Positive Index Register Plus Offset Operand -operand indPosIndexOffset(any_RegP reg, immL32 off, rRegI idx) -%{ - constraint(ALLOC_IN_RC(ptr_reg)); - predicate(n->in(2)->in(3)->as_Type()->type()->is_long()->_lo >= 0); - match(AddP (AddP reg (ConvI2L idx)) off); - - op_cost(10); - format %{"[$reg + $off + $idx]" %} - interface(MEMORY_INTER) %{ - base($reg); - index($idx); - scale(0x0); - disp($off); - %} -%} - -// Indirect Memory Times Scale Plus Positive Index Register Plus Offset Operand -operand indPosIndexScaleOffset(any_RegP reg, immL32 off, rRegI idx, immI2 scale) -%{ - constraint(ALLOC_IN_RC(ptr_reg)); - predicate(n->in(2)->in(3)->in(1)->as_Type()->type()->is_long()->_lo >= 0); - match(AddP (AddP reg (LShiftL (ConvI2L idx) scale)) off); - - op_cost(10); - format %{"[$reg + $off + $idx << $scale]" %} - interface(MEMORY_INTER) %{ - base($reg); - index($idx); - scale($scale); - disp($off); - %} -%} - -// Indirect Narrow Oop Plus Offset Operand -// Note: x86 architecture doesn't support "scale * index + offset" without a base -// we can't free r12 even with CompressedOops::base() == nullptr. -operand indCompressedOopOffset(rRegN reg, immL32 off) %{ - predicate(UseCompressedOops && (CompressedOops::shift() == Address::times_8)); - constraint(ALLOC_IN_RC(ptr_reg)); - match(AddP (DecodeN reg) off); - - op_cost(10); - format %{"[R12 + $reg << 3 + $off] (compressed oop addressing)" %} - interface(MEMORY_INTER) %{ - base(0xc); // R12 - index($reg); - scale(0x3); - disp($off); - %} -%} - -// Indirect Memory Operand -operand indirectNarrow(rRegN reg) -%{ - predicate(CompressedOops::shift() == 0); - constraint(ALLOC_IN_RC(ptr_reg)); - match(DecodeN reg); - - format %{ "[$reg]" %} - interface(MEMORY_INTER) %{ - base($reg); - index(0x4); - scale(0x0); - disp(0x0); - %} -%} - -// Indirect Memory Plus Short Offset Operand -operand indOffset8Narrow(rRegN reg, immL8 off) -%{ - predicate(CompressedOops::shift() == 0); - constraint(ALLOC_IN_RC(ptr_reg)); - match(AddP (DecodeN reg) off); - - format %{ "[$reg + $off (8-bit)]" %} - interface(MEMORY_INTER) %{ - base($reg); - index(0x4); - scale(0x0); - disp($off); - %} -%} - -// Indirect Memory Plus Long Offset Operand -operand indOffset32Narrow(rRegN reg, immL32 off) -%{ - predicate(CompressedOops::shift() == 0); - constraint(ALLOC_IN_RC(ptr_reg)); - match(AddP (DecodeN reg) off); - - format %{ "[$reg + $off (32-bit)]" %} - interface(MEMORY_INTER) %{ - base($reg); - index(0x4); - scale(0x0); - disp($off); - %} -%} - -// Indirect Memory Plus Index Register Plus Offset Operand -operand indIndexOffsetNarrow(rRegN reg, rRegL lreg, immL32 off) -%{ - predicate(CompressedOops::shift() == 0); - constraint(ALLOC_IN_RC(ptr_reg)); - match(AddP (AddP (DecodeN reg) lreg) off); - - op_cost(10); - format %{"[$reg + $off + $lreg]" %} - interface(MEMORY_INTER) %{ - base($reg); - index($lreg); - scale(0x0); - disp($off); - %} -%} - -// Indirect Memory Plus Index Register Plus Offset Operand -operand indIndexNarrow(rRegN reg, rRegL lreg) -%{ - predicate(CompressedOops::shift() == 0); - constraint(ALLOC_IN_RC(ptr_reg)); - match(AddP (DecodeN reg) lreg); - - op_cost(10); - format %{"[$reg + $lreg]" %} - interface(MEMORY_INTER) %{ - base($reg); - index($lreg); - scale(0x0); - disp(0x0); - %} -%} - -// Indirect Memory Times Scale Plus Index Register -operand indIndexScaleNarrow(rRegN reg, rRegL lreg, immI2 scale) -%{ - predicate(CompressedOops::shift() == 0); - constraint(ALLOC_IN_RC(ptr_reg)); - match(AddP (DecodeN reg) (LShiftL lreg scale)); - - op_cost(10); - format %{"[$reg + $lreg << $scale]" %} - interface(MEMORY_INTER) %{ - base($reg); - index($lreg); - scale($scale); - disp(0x0); - %} -%} - -// Indirect Memory Times Scale Plus Index Register Plus Offset Operand -operand indIndexScaleOffsetNarrow(rRegN reg, immL32 off, rRegL lreg, immI2 scale) -%{ - predicate(CompressedOops::shift() == 0); - constraint(ALLOC_IN_RC(ptr_reg)); - match(AddP (AddP (DecodeN reg) (LShiftL lreg scale)) off); - - op_cost(10); - format %{"[$reg + $off + $lreg << $scale]" %} - interface(MEMORY_INTER) %{ - base($reg); - index($lreg); - scale($scale); - disp($off); - %} -%} - -// Indirect Memory Times Plus Positive Index Register Plus Offset Operand -operand indPosIndexOffsetNarrow(rRegN reg, immL32 off, rRegI idx) -%{ - constraint(ALLOC_IN_RC(ptr_reg)); - predicate(CompressedOops::shift() == 0 && n->in(2)->in(3)->as_Type()->type()->is_long()->_lo >= 0); - match(AddP (AddP (DecodeN reg) (ConvI2L idx)) off); - - op_cost(10); - format %{"[$reg + $off + $idx]" %} - interface(MEMORY_INTER) %{ - base($reg); - index($idx); - scale(0x0); - disp($off); - %} -%} - -// Indirect Memory Times Scale Plus Positive Index Register Plus Offset Operand -operand indPosIndexScaleOffsetNarrow(rRegN reg, immL32 off, rRegI idx, immI2 scale) -%{ - constraint(ALLOC_IN_RC(ptr_reg)); - predicate(CompressedOops::shift() == 0 && n->in(2)->in(3)->in(1)->as_Type()->type()->is_long()->_lo >= 0); - match(AddP (AddP (DecodeN reg) (LShiftL (ConvI2L idx) scale)) off); - - op_cost(10); - format %{"[$reg + $off + $idx << $scale]" %} - interface(MEMORY_INTER) %{ - base($reg); - index($idx); - scale($scale); - disp($off); - %} -%} - -//----------Special Memory Operands-------------------------------------------- -// Stack Slot Operand - This operand is used for loading and storing temporary -// values on the stack where a match requires a value to -// flow through memory. -operand stackSlotP(sRegP reg) -%{ - constraint(ALLOC_IN_RC(stack_slots)); - // No match rule because this operand is only generated in matching - - format %{ "[$reg]" %} - interface(MEMORY_INTER) %{ - base(0x4); // RSP - index(0x4); // No Index - scale(0x0); // No Scale - disp($reg); // Stack Offset - %} -%} - -operand stackSlotI(sRegI reg) -%{ - constraint(ALLOC_IN_RC(stack_slots)); - // No match rule because this operand is only generated in matching - - format %{ "[$reg]" %} - interface(MEMORY_INTER) %{ - base(0x4); // RSP - index(0x4); // No Index - scale(0x0); // No Scale - disp($reg); // Stack Offset - %} -%} - -operand stackSlotF(sRegF reg) -%{ - constraint(ALLOC_IN_RC(stack_slots)); - // No match rule because this operand is only generated in matching - - format %{ "[$reg]" %} - interface(MEMORY_INTER) %{ - base(0x4); // RSP - index(0x4); // No Index - scale(0x0); // No Scale - disp($reg); // Stack Offset - %} -%} - -operand stackSlotD(sRegD reg) -%{ - constraint(ALLOC_IN_RC(stack_slots)); - // No match rule because this operand is only generated in matching - - format %{ "[$reg]" %} - interface(MEMORY_INTER) %{ - base(0x4); // RSP - index(0x4); // No Index - scale(0x0); // No Scale - disp($reg); // Stack Offset - %} -%} -operand stackSlotL(sRegL reg) -%{ - constraint(ALLOC_IN_RC(stack_slots)); - // No match rule because this operand is only generated in matching - - format %{ "[$reg]" %} - interface(MEMORY_INTER) %{ - base(0x4); // RSP - index(0x4); // No Index - scale(0x0); // No Scale - disp($reg); // Stack Offset - %} -%} - -//----------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. - -// Comparison Code -operand cmpOp() -%{ - match(Bool); - - format %{ "" %} - interface(COND_INTER) %{ - equal(0x4, "e"); - not_equal(0x5, "ne"); - less(0xC, "l"); - greater_equal(0xD, "ge"); - less_equal(0xE, "le"); - greater(0xF, "g"); - overflow(0x0, "o"); - no_overflow(0x1, "no"); - %} -%} - -// Comparison Code, unsigned compare. Used by FP also, with -// C2 (unordered) turned into GT or LT already. The other bits -// C0 and C3 are turned into Carry & Zero flags. -operand cmpOpU() -%{ - match(Bool); - - format %{ "" %} - interface(COND_INTER) %{ - equal(0x4, "e"); - not_equal(0x5, "ne"); - less(0x2, "b"); - greater_equal(0x3, "ae"); - less_equal(0x6, "be"); - greater(0x7, "a"); - overflow(0x0, "o"); - no_overflow(0x1, "no"); - %} -%} - - -// Floating comparisons that don't require any fixup for the unordered case, -// If both inputs of the comparison are the same, ZF is always set so we -// don't need to use cmpOpUCF2 for eq/ne -operand cmpOpUCF() %{ - match(Bool); - predicate(n->as_Bool()->_test._test == BoolTest::lt || - n->as_Bool()->_test._test == BoolTest::ge || - n->as_Bool()->_test._test == BoolTest::le || - n->as_Bool()->_test._test == BoolTest::gt || - n->in(1)->in(1) == n->in(1)->in(2)); - format %{ "" %} - interface(COND_INTER) %{ - equal(0xb, "np"); - not_equal(0xa, "p"); - less(0x2, "b"); - greater_equal(0x3, "ae"); - less_equal(0x6, "be"); - greater(0x7, "a"); - overflow(0x0, "o"); - no_overflow(0x1, "no"); - %} -%} - - -// Floating comparisons that can be fixed up with extra conditional jumps -operand cmpOpUCF2() %{ - match(Bool); - predicate((n->as_Bool()->_test._test == BoolTest::ne || - n->as_Bool()->_test._test == BoolTest::eq) && - n->in(1)->in(1) != n->in(1)->in(2)); - format %{ "" %} - interface(COND_INTER) %{ - equal(0x4, "e"); - not_equal(0x5, "ne"); - less(0x2, "b"); - greater_equal(0x3, "ae"); - less_equal(0x6, "be"); - greater(0x7, "a"); - overflow(0x0, "o"); - no_overflow(0x1, "no"); - %} -%} - -//----------OPERAND CLASSES---------------------------------------------------- -// Operand Classes are groups of operands that are used as 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 memory(indirect, indOffset8, indOffset32, indIndexOffset, indIndex, - indIndexScale, indPosIndexScale, indIndexScaleOffset, indPosIndexOffset, indPosIndexScaleOffset, - indCompressedOopOffset, - indirectNarrow, indOffset8Narrow, indOffset32Narrow, - indIndexOffsetNarrow, indIndexNarrow, indIndexScaleNarrow, - indIndexScaleOffsetNarrow, indPosIndexOffsetNarrow, indPosIndexScaleOffsetNarrow); - -//----------PIPELINE----------------------------------------------------------- -// Rules which define the behavior of the target architectures pipeline. -pipeline %{ - -//----------ATTRIBUTES--------------------------------------------------------- -attributes %{ - variable_size_instructions; // Fixed size instructions - max_instructions_per_bundle = 3; // Up to 3 instructions per bundle - instruction_unit_size = 1; // An instruction is 1 bytes long - instruction_fetch_unit_size = 16; // The processor fetches one line - instruction_fetch_units = 1; // of 16 bytes -%} - -//----------RESOURCES---------------------------------------------------------- -// Resources are the functional units available to the machine - -// Generic P2/P3 pipeline -// 3 decoders, only D0 handles big operands; a "bundle" is the limit of -// 3 instructions decoded per cycle. -// 2 load/store ops per cycle, 1 branch, 1 FPU, -// 3 ALU op, only ALU0 handles mul instructions. -resources( D0, D1, D2, DECODE = D0 | D1 | D2, - MS0, MS1, MS2, MEM = MS0 | MS1 | MS2, - BR, FPU, - ALU0, ALU1, ALU2, ALU = ALU0 | ALU1 | ALU2); - -//----------PIPELINE DESCRIPTION----------------------------------------------- -// Pipeline Description specifies the stages in the machine's pipeline - -// Generic P2/P3 pipeline -pipe_desc(S0, S1, S2, S3, S4, S5); - -//----------PIPELINE CLASSES--------------------------------------------------- -// Pipeline Classes describe the stages in which input and output are -// referenced by the hardware pipeline. - -// Naming convention: ialu or fpu -// Then: _reg -// Then: _reg if there is a 2nd register -// Then: _long if it's a pair of instructions implementing a long -// Then: _fat if it requires the big decoder -// Or: _mem if it requires the big decoder and a memory unit. - -// Integer ALU reg operation -pipe_class ialu_reg(rRegI dst) -%{ - single_instruction; - dst : S4(write); - dst : S3(read); - DECODE : S0; // any decoder - ALU : S3; // any alu -%} - -// Long ALU reg operation -pipe_class ialu_reg_long(rRegL dst) -%{ - instruction_count(2); - dst : S4(write); - dst : S3(read); - DECODE : S0(2); // any 2 decoders - ALU : S3(2); // both alus -%} - -// Integer ALU reg operation using big decoder -pipe_class ialu_reg_fat(rRegI dst) -%{ - single_instruction; - dst : S4(write); - dst : S3(read); - D0 : S0; // big decoder only - ALU : S3; // any alu -%} - -// Integer ALU reg-reg operation -pipe_class ialu_reg_reg(rRegI dst, rRegI src) -%{ - single_instruction; - dst : S4(write); - src : S3(read); - DECODE : S0; // any decoder - ALU : S3; // any alu -%} - -// Integer ALU reg-reg operation -pipe_class ialu_reg_reg_fat(rRegI dst, memory src) -%{ - single_instruction; - dst : S4(write); - src : S3(read); - D0 : S0; // big decoder only - ALU : S3; // any alu -%} - -// Integer ALU reg-mem operation -pipe_class ialu_reg_mem(rRegI dst, memory mem) -%{ - single_instruction; - dst : S5(write); - mem : S3(read); - D0 : S0; // big decoder only - ALU : S4; // any alu - MEM : S3; // any mem -%} - -// Integer mem operation (prefetch) -pipe_class ialu_mem(memory mem) -%{ - single_instruction; - mem : S3(read); - D0 : S0; // big decoder only - MEM : S3; // any mem -%} - -// Integer Store to Memory -pipe_class ialu_mem_reg(memory mem, rRegI src) -%{ - single_instruction; - mem : S3(read); - src : S5(read); - D0 : S0; // big decoder only - ALU : S4; // any alu - MEM : S3; -%} - -// // Long Store to Memory -// pipe_class ialu_mem_long_reg(memory mem, rRegL src) -// %{ -// instruction_count(2); -// mem : S3(read); -// src : S5(read); -// D0 : S0(2); // big decoder only; twice -// ALU : S4(2); // any 2 alus -// MEM : S3(2); // Both mems -// %} - -// Integer Store to Memory -pipe_class ialu_mem_imm(memory mem) -%{ - single_instruction; - mem : S3(read); - D0 : S0; // big decoder only - ALU : S4; // any alu - MEM : S3; -%} - -// Integer ALU0 reg-reg operation -pipe_class ialu_reg_reg_alu0(rRegI dst, rRegI src) -%{ - single_instruction; - dst : S4(write); - src : S3(read); - D0 : S0; // Big decoder only - ALU0 : S3; // only alu0 -%} - -// Integer ALU0 reg-mem operation -pipe_class ialu_reg_mem_alu0(rRegI dst, memory mem) -%{ - single_instruction; - dst : S5(write); - mem : S3(read); - D0 : S0; // big decoder only - ALU0 : S4; // ALU0 only - MEM : S3; // any mem -%} - -// Integer ALU reg-reg operation -pipe_class ialu_cr_reg_reg(rFlagsReg cr, rRegI src1, rRegI src2) -%{ - single_instruction; - cr : S4(write); - src1 : S3(read); - src2 : S3(read); - DECODE : S0; // any decoder - ALU : S3; // any alu -%} - -// Integer ALU reg-imm operation -pipe_class ialu_cr_reg_imm(rFlagsReg cr, rRegI src1) -%{ - single_instruction; - cr : S4(write); - src1 : S3(read); - DECODE : S0; // any decoder - ALU : S3; // any alu -%} - -// Integer ALU reg-mem operation -pipe_class ialu_cr_reg_mem(rFlagsReg cr, rRegI src1, memory src2) -%{ - single_instruction; - cr : S4(write); - src1 : S3(read); - src2 : S3(read); - D0 : S0; // big decoder only - ALU : S4; // any alu - MEM : S3; -%} - -// Conditional move reg-reg -pipe_class pipe_cmplt( rRegI p, rRegI q, rRegI y) -%{ - instruction_count(4); - y : S4(read); - q : S3(read); - p : S3(read); - DECODE : S0(4); // any decoder -%} - -// Conditional move reg-reg -pipe_class pipe_cmov_reg( rRegI dst, rRegI src, rFlagsReg cr) -%{ - single_instruction; - dst : S4(write); - src : S3(read); - cr : S3(read); - DECODE : S0; // any decoder -%} - -// Conditional move reg-mem -pipe_class pipe_cmov_mem( rFlagsReg cr, rRegI dst, memory src) -%{ - single_instruction; - dst : S4(write); - src : S3(read); - cr : S3(read); - DECODE : S0; // any decoder - MEM : S3; -%} - -// Conditional move reg-reg long -pipe_class pipe_cmov_reg_long( rFlagsReg cr, rRegL dst, rRegL src) -%{ - single_instruction; - dst : S4(write); - src : S3(read); - cr : S3(read); - DECODE : S0(2); // any 2 decoders -%} - -// Float reg-reg operation -pipe_class fpu_reg(regD dst) -%{ - instruction_count(2); - dst : S3(read); - DECODE : S0(2); // any 2 decoders - FPU : S3; -%} - -// Float reg-reg operation -pipe_class fpu_reg_reg(regD dst, regD src) -%{ - instruction_count(2); - dst : S4(write); - src : S3(read); - DECODE : S0(2); // any 2 decoders - FPU : S3; -%} - -// Float reg-reg operation -pipe_class fpu_reg_reg_reg(regD dst, regD src1, regD src2) -%{ - instruction_count(3); - dst : S4(write); - src1 : S3(read); - src2 : S3(read); - DECODE : S0(3); // any 3 decoders - FPU : S3(2); -%} - -// Float reg-reg operation -pipe_class fpu_reg_reg_reg_reg(regD dst, regD src1, regD src2, regD src3) -%{ - instruction_count(4); - dst : S4(write); - src1 : S3(read); - src2 : S3(read); - src3 : S3(read); - DECODE : S0(4); // any 3 decoders - FPU : S3(2); -%} - -// Float reg-reg operation -pipe_class fpu_reg_mem_reg_reg(regD dst, memory src1, regD src2, regD src3) -%{ - instruction_count(4); - dst : S4(write); - src1 : S3(read); - src2 : S3(read); - src3 : S3(read); - DECODE : S1(3); // any 3 decoders - D0 : S0; // Big decoder only - FPU : S3(2); - MEM : S3; -%} - -// Float reg-mem operation -pipe_class fpu_reg_mem(regD dst, memory mem) -%{ - instruction_count(2); - dst : S5(write); - mem : S3(read); - D0 : S0; // big decoder only - DECODE : S1; // any decoder for FPU POP - FPU : S4; - MEM : S3; // any mem -%} - -// Float reg-mem operation -pipe_class fpu_reg_reg_mem(regD dst, regD src1, memory mem) -%{ - instruction_count(3); - dst : S5(write); - src1 : S3(read); - mem : S3(read); - D0 : S0; // big decoder only - DECODE : S1(2); // any decoder for FPU POP - FPU : S4; - MEM : S3; // any mem -%} - -// Float mem-reg operation -pipe_class fpu_mem_reg(memory mem, regD src) -%{ - instruction_count(2); - src : S5(read); - mem : S3(read); - DECODE : S0; // any decoder for FPU PUSH - D0 : S1; // big decoder only - FPU : S4; - MEM : S3; // any mem -%} - -pipe_class fpu_mem_reg_reg(memory mem, regD src1, regD src2) -%{ - instruction_count(3); - src1 : S3(read); - src2 : S3(read); - mem : S3(read); - DECODE : S0(2); // any decoder for FPU PUSH - D0 : S1; // big decoder only - FPU : S4; - MEM : S3; // any mem -%} - -pipe_class fpu_mem_reg_mem(memory mem, regD src1, memory src2) -%{ - instruction_count(3); - src1 : S3(read); - src2 : S3(read); - mem : S4(read); - DECODE : S0; // any decoder for FPU PUSH - D0 : S0(2); // big decoder only - FPU : S4; - MEM : S3(2); // any mem -%} - -pipe_class fpu_mem_mem(memory dst, memory src1) -%{ - instruction_count(2); - src1 : S3(read); - dst : S4(read); - D0 : S0(2); // big decoder only - MEM : S3(2); // any mem -%} - -pipe_class fpu_mem_mem_mem(memory dst, memory src1, memory src2) -%{ - instruction_count(3); - src1 : S3(read); - src2 : S3(read); - dst : S4(read); - D0 : S0(3); // big decoder only - FPU : S4; - MEM : S3(3); // any mem -%} - -pipe_class fpu_mem_reg_con(memory mem, regD src1) -%{ - instruction_count(3); - src1 : S4(read); - mem : S4(read); - DECODE : S0; // any decoder for FPU PUSH - D0 : S0(2); // big decoder only - FPU : S4; - MEM : S3(2); // any mem -%} - -// Float load constant -pipe_class fpu_reg_con(regD dst) -%{ - instruction_count(2); - dst : S5(write); - D0 : S0; // big decoder only for the load - DECODE : S1; // any decoder for FPU POP - FPU : S4; - MEM : S3; // any mem -%} - -// Float load constant -pipe_class fpu_reg_reg_con(regD dst, regD src) -%{ - instruction_count(3); - dst : S5(write); - src : S3(read); - D0 : S0; // big decoder only for the load - DECODE : S1(2); // any decoder for FPU POP - FPU : S4; - MEM : S3; // any mem -%} - -// UnConditional branch -pipe_class pipe_jmp(label labl) -%{ - single_instruction; - BR : S3; -%} - -// Conditional branch -pipe_class pipe_jcc(cmpOp cmp, rFlagsReg cr, label labl) -%{ - single_instruction; - cr : S1(read); - BR : S3; -%} - -// Allocation idiom -pipe_class pipe_cmpxchg(rRegP dst, rRegP heap_ptr) -%{ - instruction_count(1); force_serialization; - fixed_latency(6); - heap_ptr : S3(read); - DECODE : S0(3); - D0 : S2; - MEM : S3; - ALU : S3(2); - dst : S5(write); - BR : S5; -%} - -// Generic big/slow expanded idiom -pipe_class pipe_slow() -%{ - instruction_count(10); multiple_bundles; force_serialization; - fixed_latency(100); - D0 : S0(2); - MEM : S3(2); -%} - -// The real do-nothing guy -pipe_class empty() -%{ - instruction_count(0); -%} - -// Define the class for the Nop node -define -%{ - MachNop = empty; -%} - -%} - -//----------INSTRUCTIONS------------------------------------------------------- -// -// match -- States which machine-independent subtree may be replaced -// by this instruction. -// ins_cost -- The estimated cost of this instruction is used by instruction -// selection to identify a minimum cost tree of machine -// instructions that matches a tree of machine-independent -// instructions. -// format -- A string providing the disassembly for this instruction. -// The value of an instruction's operand may be inserted -// by referring to it with a '$' prefix. -// opcode -- Three instruction opcodes may be provided. These are referred -// to within an encode class as $primary, $secondary, and $tertiary -// rrspectively. The primary opcode is commonly used to -// indicate the type of machine instruction, while secondary -// and tertiary are often used for prefix options or addressing -// modes. -// ins_encode -- A list of encode classes with parameters. The encode class -// name must have been defined in an 'enc_class' specification -// in the encode section of the architecture description. - -// Dummy reg-to-reg vector moves. Removed during post-selection cleanup. -// Load Float -instruct MoveF2VL(vlRegF dst, regF src) %{ - match(Set dst src); - format %{ "movss $dst,$src\t! load float (4 bytes)" %} - ins_encode %{ - ShouldNotReachHere(); - %} - ins_pipe( fpu_reg_reg ); -%} - -// Load Float -instruct MoveF2LEG(legRegF dst, regF src) %{ - match(Set dst src); - format %{ "movss $dst,$src\t# if src != dst load float (4 bytes)" %} - ins_encode %{ - ShouldNotReachHere(); - %} - ins_pipe( fpu_reg_reg ); -%} - -// Load Float -instruct MoveVL2F(regF dst, vlRegF src) %{ - match(Set dst src); - format %{ "movss $dst,$src\t! load float (4 bytes)" %} - ins_encode %{ - ShouldNotReachHere(); - %} - ins_pipe( fpu_reg_reg ); -%} - -// Load Float -instruct MoveLEG2F(regF dst, legRegF src) %{ - match(Set dst src); - format %{ "movss $dst,$src\t# if src != dst load float (4 bytes)" %} - ins_encode %{ - ShouldNotReachHere(); - %} - ins_pipe( fpu_reg_reg ); -%} - -// Load Double -instruct MoveD2VL(vlRegD dst, regD src) %{ - match(Set dst src); - format %{ "movsd $dst,$src\t! load double (8 bytes)" %} - ins_encode %{ - ShouldNotReachHere(); - %} - ins_pipe( fpu_reg_reg ); -%} - -// Load Double -instruct MoveD2LEG(legRegD dst, regD src) %{ - match(Set dst src); - format %{ "movsd $dst,$src\t# if src != dst load double (8 bytes)" %} - ins_encode %{ - ShouldNotReachHere(); - %} - ins_pipe( fpu_reg_reg ); -%} - -// Load Double -instruct MoveVL2D(regD dst, vlRegD src) %{ - match(Set dst src); - format %{ "movsd $dst,$src\t! load double (8 bytes)" %} - ins_encode %{ - ShouldNotReachHere(); - %} - ins_pipe( fpu_reg_reg ); -%} - -// Load Double -instruct MoveLEG2D(regD dst, legRegD src) %{ - match(Set dst src); - format %{ "movsd $dst,$src\t# if src != dst load double (8 bytes)" %} - ins_encode %{ - ShouldNotReachHere(); - %} - ins_pipe( fpu_reg_reg ); -%} - -//----------Load/Store/Move Instructions--------------------------------------- -//----------Load Instructions-------------------------------------------------- - -// Load Byte (8 bit signed) -instruct loadB(rRegI dst, memory mem) -%{ - match(Set dst (LoadB mem)); - - ins_cost(125); - format %{ "movsbl $dst, $mem\t# byte" %} - - ins_encode %{ - __ movsbl($dst$$Register, $mem$$Address); - %} - - ins_pipe(ialu_reg_mem); -%} - -// Load Byte (8 bit signed) into Long Register -instruct loadB2L(rRegL dst, memory mem) -%{ - match(Set dst (ConvI2L (LoadB mem))); - - ins_cost(125); - format %{ "movsbq $dst, $mem\t# byte -> long" %} - - ins_encode %{ - __ movsbq($dst$$Register, $mem$$Address); - %} - - ins_pipe(ialu_reg_mem); -%} - -// Load Unsigned Byte (8 bit UNsigned) -instruct loadUB(rRegI dst, memory mem) -%{ - match(Set dst (LoadUB mem)); - - ins_cost(125); - format %{ "movzbl $dst, $mem\t# ubyte" %} - - ins_encode %{ - __ movzbl($dst$$Register, $mem$$Address); - %} - - ins_pipe(ialu_reg_mem); -%} - -// Load Unsigned Byte (8 bit UNsigned) into Long Register -instruct loadUB2L(rRegL dst, memory mem) -%{ - match(Set dst (ConvI2L (LoadUB mem))); - - ins_cost(125); - format %{ "movzbq $dst, $mem\t# ubyte -> long" %} - - ins_encode %{ - __ movzbq($dst$$Register, $mem$$Address); - %} - - ins_pipe(ialu_reg_mem); -%} - -// Load Unsigned Byte (8 bit UNsigned) with 32-bit mask into Long Register -instruct loadUB2L_immI(rRegL dst, memory mem, immI mask, rFlagsReg cr) %{ - match(Set dst (ConvI2L (AndI (LoadUB mem) mask))); - effect(KILL cr); - - format %{ "movzbq $dst, $mem\t# ubyte & 32-bit mask -> long\n\t" - "andl $dst, right_n_bits($mask, 8)" %} - ins_encode %{ - Register Rdst = $dst$$Register; - __ movzbq(Rdst, $mem$$Address); - __ andl(Rdst, $mask$$constant & right_n_bits(8)); - %} - ins_pipe(ialu_reg_mem); -%} - -// Load Short (16 bit signed) -instruct loadS(rRegI dst, memory mem) -%{ - match(Set dst (LoadS mem)); - - ins_cost(125); - format %{ "movswl $dst, $mem\t# short" %} - - ins_encode %{ - __ movswl($dst$$Register, $mem$$Address); - %} - - ins_pipe(ialu_reg_mem); -%} - -// Load Short (16 bit signed) to Byte (8 bit signed) -instruct loadS2B(rRegI dst, memory mem, immI_24 twentyfour) %{ - match(Set dst (RShiftI (LShiftI (LoadS mem) twentyfour) twentyfour)); - - ins_cost(125); - format %{ "movsbl $dst, $mem\t# short -> byte" %} - ins_encode %{ - __ movsbl($dst$$Register, $mem$$Address); - %} - ins_pipe(ialu_reg_mem); -%} - -// Load Short (16 bit signed) into Long Register -instruct loadS2L(rRegL dst, memory mem) -%{ - match(Set dst (ConvI2L (LoadS mem))); - - ins_cost(125); - format %{ "movswq $dst, $mem\t# short -> long" %} - - ins_encode %{ - __ movswq($dst$$Register, $mem$$Address); - %} - - ins_pipe(ialu_reg_mem); -%} - -// Load Unsigned Short/Char (16 bit UNsigned) -instruct loadUS(rRegI dst, memory mem) -%{ - match(Set dst (LoadUS mem)); - - ins_cost(125); - format %{ "movzwl $dst, $mem\t# ushort/char" %} - - ins_encode %{ - __ movzwl($dst$$Register, $mem$$Address); - %} - - ins_pipe(ialu_reg_mem); -%} - -// Load Unsigned Short/Char (16 bit UNsigned) to Byte (8 bit signed) -instruct loadUS2B(rRegI dst, memory mem, immI_24 twentyfour) %{ - match(Set dst (RShiftI (LShiftI (LoadUS mem) twentyfour) twentyfour)); - - ins_cost(125); - format %{ "movsbl $dst, $mem\t# ushort -> byte" %} - ins_encode %{ - __ movsbl($dst$$Register, $mem$$Address); - %} - ins_pipe(ialu_reg_mem); -%} - -// Load Unsigned Short/Char (16 bit UNsigned) into Long Register -instruct loadUS2L(rRegL dst, memory mem) -%{ - match(Set dst (ConvI2L (LoadUS mem))); - - ins_cost(125); - format %{ "movzwq $dst, $mem\t# ushort/char -> long" %} - - ins_encode %{ - __ movzwq($dst$$Register, $mem$$Address); - %} - - ins_pipe(ialu_reg_mem); -%} - -// Load Unsigned Short/Char (16 bit UNsigned) with mask 0xFF into Long Register -instruct loadUS2L_immI_255(rRegL dst, memory mem, immI_255 mask) %{ - match(Set dst (ConvI2L (AndI (LoadUS mem) mask))); - - format %{ "movzbq $dst, $mem\t# ushort/char & 0xFF -> long" %} - ins_encode %{ - __ movzbq($dst$$Register, $mem$$Address); - %} - ins_pipe(ialu_reg_mem); -%} - -// Load Unsigned Short/Char (16 bit UNsigned) with 32-bit mask into Long Register -instruct loadUS2L_immI(rRegL dst, memory mem, immI mask, rFlagsReg cr) %{ - match(Set dst (ConvI2L (AndI (LoadUS mem) mask))); - effect(KILL cr); - - format %{ "movzwq $dst, $mem\t# ushort/char & 32-bit mask -> long\n\t" - "andl $dst, right_n_bits($mask, 16)" %} - ins_encode %{ - Register Rdst = $dst$$Register; - __ movzwq(Rdst, $mem$$Address); - __ andl(Rdst, $mask$$constant & right_n_bits(16)); - %} - ins_pipe(ialu_reg_mem); -%} - -// Load Integer -instruct loadI(rRegI dst, memory mem) -%{ - match(Set dst (LoadI mem)); - - ins_cost(125); - format %{ "movl $dst, $mem\t# int" %} - - ins_encode %{ - __ movl($dst$$Register, $mem$$Address); - %} - - ins_pipe(ialu_reg_mem); -%} - -// Load Integer (32 bit signed) to Byte (8 bit signed) -instruct loadI2B(rRegI dst, memory mem, immI_24 twentyfour) %{ - match(Set dst (RShiftI (LShiftI (LoadI mem) twentyfour) twentyfour)); - - ins_cost(125); - format %{ "movsbl $dst, $mem\t# int -> byte" %} - ins_encode %{ - __ movsbl($dst$$Register, $mem$$Address); - %} - ins_pipe(ialu_reg_mem); -%} - -// Load Integer (32 bit signed) to Unsigned Byte (8 bit UNsigned) -instruct loadI2UB(rRegI dst, memory mem, immI_255 mask) %{ - match(Set dst (AndI (LoadI mem) mask)); - - ins_cost(125); - format %{ "movzbl $dst, $mem\t# int -> ubyte" %} - ins_encode %{ - __ movzbl($dst$$Register, $mem$$Address); - %} - ins_pipe(ialu_reg_mem); -%} - -// Load Integer (32 bit signed) to Short (16 bit signed) -instruct loadI2S(rRegI dst, memory mem, immI_16 sixteen) %{ - match(Set dst (RShiftI (LShiftI (LoadI mem) sixteen) sixteen)); - - ins_cost(125); - format %{ "movswl $dst, $mem\t# int -> short" %} - ins_encode %{ - __ movswl($dst$$Register, $mem$$Address); - %} - ins_pipe(ialu_reg_mem); -%} - -// Load Integer (32 bit signed) to Unsigned Short/Char (16 bit UNsigned) -instruct loadI2US(rRegI dst, memory mem, immI_65535 mask) %{ - match(Set dst (AndI (LoadI mem) mask)); - - ins_cost(125); - format %{ "movzwl $dst, $mem\t# int -> ushort/char" %} - ins_encode %{ - __ movzwl($dst$$Register, $mem$$Address); - %} - ins_pipe(ialu_reg_mem); -%} - -// Load Integer into Long Register -instruct loadI2L(rRegL dst, memory mem) -%{ - match(Set dst (ConvI2L (LoadI mem))); - - ins_cost(125); - format %{ "movslq $dst, $mem\t# int -> long" %} - - ins_encode %{ - __ movslq($dst$$Register, $mem$$Address); - %} - - ins_pipe(ialu_reg_mem); -%} - -// Load Integer with mask 0xFF into Long Register -instruct loadI2L_immI_255(rRegL dst, memory mem, immI_255 mask) %{ - match(Set dst (ConvI2L (AndI (LoadI mem) mask))); - - format %{ "movzbq $dst, $mem\t# int & 0xFF -> long" %} - ins_encode %{ - __ movzbq($dst$$Register, $mem$$Address); - %} - ins_pipe(ialu_reg_mem); -%} - -// Load Integer with mask 0xFFFF into Long Register -instruct loadI2L_immI_65535(rRegL dst, memory mem, immI_65535 mask) %{ - match(Set dst (ConvI2L (AndI (LoadI mem) mask))); - - format %{ "movzwq $dst, $mem\t# int & 0xFFFF -> long" %} - ins_encode %{ - __ movzwq($dst$$Register, $mem$$Address); - %} - ins_pipe(ialu_reg_mem); -%} - -// Load Integer with a 31-bit mask into Long Register -instruct loadI2L_immU31(rRegL dst, memory mem, immU31 mask, rFlagsReg cr) %{ - match(Set dst (ConvI2L (AndI (LoadI mem) mask))); - effect(KILL cr); - - format %{ "movl $dst, $mem\t# int & 31-bit mask -> long\n\t" - "andl $dst, $mask" %} - ins_encode %{ - Register Rdst = $dst$$Register; - __ movl(Rdst, $mem$$Address); - __ andl(Rdst, $mask$$constant); - %} - ins_pipe(ialu_reg_mem); -%} - -// Load Unsigned Integer into Long Register -instruct loadUI2L(rRegL dst, memory mem, immL_32bits mask) -%{ - match(Set dst (AndL (ConvI2L (LoadI mem)) mask)); - - ins_cost(125); - format %{ "movl $dst, $mem\t# uint -> long" %} - - ins_encode %{ - __ movl($dst$$Register, $mem$$Address); - %} - - ins_pipe(ialu_reg_mem); -%} - -// Load Long -instruct loadL(rRegL dst, memory mem) -%{ - match(Set dst (LoadL mem)); - - ins_cost(125); - format %{ "movq $dst, $mem\t# long" %} - - ins_encode %{ - __ movq($dst$$Register, $mem$$Address); - %} - - ins_pipe(ialu_reg_mem); // XXX -%} - -// Load Range -instruct loadRange(rRegI dst, memory mem) -%{ - match(Set dst (LoadRange mem)); - - ins_cost(125); // XXX - format %{ "movl $dst, $mem\t# range" %} - ins_encode %{ - __ movl($dst$$Register, $mem$$Address); - %} - ins_pipe(ialu_reg_mem); -%} - -// Load Pointer -instruct loadP(rRegP dst, memory mem) -%{ - match(Set dst (LoadP mem)); - predicate(n->as_Load()->barrier_data() == 0); - - ins_cost(125); // XXX - format %{ "movq $dst, $mem\t# ptr" %} - ins_encode %{ - __ movq($dst$$Register, $mem$$Address); - %} - ins_pipe(ialu_reg_mem); // XXX -%} - -// Load Compressed Pointer -instruct loadN(rRegN dst, memory mem) -%{ - predicate(n->as_Load()->barrier_data() == 0); - match(Set dst (LoadN mem)); - - ins_cost(125); // XXX - format %{ "movl $dst, $mem\t# compressed ptr" %} - ins_encode %{ - __ movl($dst$$Register, $mem$$Address); - %} - ins_pipe(ialu_reg_mem); // XXX -%} - - -// Load Klass Pointer -instruct loadKlass(rRegP dst, memory mem) -%{ - match(Set dst (LoadKlass mem)); - - ins_cost(125); // XXX - format %{ "movq $dst, $mem\t# class" %} - ins_encode %{ - __ movq($dst$$Register, $mem$$Address); - %} - ins_pipe(ialu_reg_mem); // XXX -%} - -// Load narrow Klass Pointer -instruct loadNKlass(rRegN dst, memory mem) -%{ - predicate(!UseCompactObjectHeaders); - match(Set dst (LoadNKlass mem)); - - ins_cost(125); // XXX - format %{ "movl $dst, $mem\t# compressed klass ptr" %} - ins_encode %{ - __ movl($dst$$Register, $mem$$Address); - %} - ins_pipe(ialu_reg_mem); // XXX -%} - -instruct loadNKlassCompactHeaders(rRegN dst, memory mem, rFlagsReg cr) -%{ - predicate(UseCompactObjectHeaders); - match(Set dst (LoadNKlass mem)); - effect(KILL cr); - ins_cost(125); - format %{ - "movl $dst, $mem\t# compressed klass ptr, shifted\n\t" - "shrl $dst, markWord::klass_shift_at_offset" - %} - ins_encode %{ - if (UseAPX) { - __ eshrl($dst$$Register, $mem$$Address, markWord::klass_shift_at_offset, false); - } - else { - __ movl($dst$$Register, $mem$$Address); - __ shrl($dst$$Register, markWord::klass_shift_at_offset); - } - %} - ins_pipe(ialu_reg_mem); -%} - -// Load Float -instruct loadF(regF dst, memory mem) -%{ - match(Set dst (LoadF mem)); - - ins_cost(145); // XXX - format %{ "movss $dst, $mem\t# float" %} - ins_encode %{ - __ movflt($dst$$XMMRegister, $mem$$Address); - %} - ins_pipe(pipe_slow); // XXX -%} - -// Load Double -instruct loadD_partial(regD dst, memory mem) -%{ - predicate(!UseXmmLoadAndClearUpper); - match(Set dst (LoadD mem)); - - ins_cost(145); // XXX - format %{ "movlpd $dst, $mem\t# double" %} - ins_encode %{ - __ movdbl($dst$$XMMRegister, $mem$$Address); - %} - ins_pipe(pipe_slow); // XXX -%} - -instruct loadD(regD dst, memory mem) -%{ - predicate(UseXmmLoadAndClearUpper); - match(Set dst (LoadD mem)); - - ins_cost(145); // XXX - format %{ "movsd $dst, $mem\t# double" %} - ins_encode %{ - __ movdbl($dst$$XMMRegister, $mem$$Address); - %} - ins_pipe(pipe_slow); // XXX -%} - -// max = java.lang.Math.max(float a, float b) -instruct maxF_avx10_reg(regF dst, regF a, regF b) %{ - predicate(VM_Version::supports_avx10_2()); - match(Set dst (MaxF a b)); - format %{ "maxF $dst, $a, $b" %} - ins_encode %{ - __ eminmaxss($dst$$XMMRegister, $a$$XMMRegister, $b$$XMMRegister, AVX10_MINMAX_MAX_COMPARE_SIGN); - %} - ins_pipe( pipe_slow ); -%} - -// max = java.lang.Math.max(float a, float b) -instruct maxF_reg(legRegF dst, legRegF a, legRegF b, legRegF tmp, legRegF atmp, legRegF btmp) %{ - predicate(!VM_Version::supports_avx10_2() && UseAVX > 0 && !VLoopReductions::is_reduction(n)); - match(Set dst (MaxF a b)); - effect(USE a, USE b, TEMP tmp, TEMP atmp, TEMP btmp); - format %{ "maxF $dst, $a, $b \t! using $tmp, $atmp and $btmp as TEMP" %} - ins_encode %{ - __ vminmax_fp(Op_MaxV, T_FLOAT, $dst$$XMMRegister, $a$$XMMRegister, $b$$XMMRegister, $tmp$$XMMRegister, $atmp$$XMMRegister, $btmp$$XMMRegister, Assembler::AVX_128bit); - %} - ins_pipe( pipe_slow ); -%} - -instruct maxF_reduction_reg(legRegF dst, legRegF a, legRegF b, legRegF xtmp, rRegI rtmp, rFlagsReg cr) %{ - predicate(!VM_Version::supports_avx10_2() && UseAVX > 0 && VLoopReductions::is_reduction(n)); - match(Set dst (MaxF a b)); - effect(USE a, USE b, TEMP xtmp, TEMP rtmp, KILL cr); - - format %{ "maxF_reduction $dst, $a, $b \t!using $xtmp and $rtmp as TEMP" %} - ins_encode %{ - emit_fp_min_max(masm, $dst$$XMMRegister, $a$$XMMRegister, $b$$XMMRegister, $xtmp$$XMMRegister, $rtmp$$Register, - false /*min*/, true /*single*/); - %} - ins_pipe( pipe_slow ); -%} - -// max = java.lang.Math.max(double a, double b) -instruct maxD_avx10_reg(regD dst, regD a, regD b) %{ - predicate(VM_Version::supports_avx10_2()); - match(Set dst (MaxD a b)); - format %{ "maxD $dst, $a, $b" %} - ins_encode %{ - __ eminmaxsd($dst$$XMMRegister, $a$$XMMRegister, $b$$XMMRegister, AVX10_MINMAX_MAX_COMPARE_SIGN); - %} - ins_pipe( pipe_slow ); -%} - -// max = java.lang.Math.max(double a, double b) -instruct maxD_reg(legRegD dst, legRegD a, legRegD b, legRegD tmp, legRegD atmp, legRegD btmp) %{ - predicate(!VM_Version::supports_avx10_2() && UseAVX > 0 && !VLoopReductions::is_reduction(n)); - match(Set dst (MaxD a b)); - effect(USE a, USE b, TEMP atmp, TEMP btmp, TEMP tmp); - format %{ "maxD $dst, $a, $b \t! using $tmp, $atmp and $btmp as TEMP" %} - ins_encode %{ - __ vminmax_fp(Op_MaxV, T_DOUBLE, $dst$$XMMRegister, $a$$XMMRegister, $b$$XMMRegister, $tmp$$XMMRegister, $atmp$$XMMRegister, $btmp$$XMMRegister, Assembler::AVX_128bit); - %} - ins_pipe( pipe_slow ); -%} - -instruct maxD_reduction_reg(legRegD dst, legRegD a, legRegD b, legRegD xtmp, rRegL rtmp, rFlagsReg cr) %{ - predicate(!VM_Version::supports_avx10_2() && UseAVX > 0 && VLoopReductions::is_reduction(n)); - match(Set dst (MaxD a b)); - effect(USE a, USE b, TEMP xtmp, TEMP rtmp, KILL cr); - - format %{ "maxD_reduction $dst, $a, $b \t! using $xtmp and $rtmp as TEMP" %} - ins_encode %{ - emit_fp_min_max(masm, $dst$$XMMRegister, $a$$XMMRegister, $b$$XMMRegister, $xtmp$$XMMRegister, $rtmp$$Register, - false /*min*/, false /*single*/); - %} - ins_pipe( pipe_slow ); -%} - -// max = java.lang.Math.min(float a, float b) -instruct minF_avx10_reg(regF dst, regF a, regF b) %{ - predicate(VM_Version::supports_avx10_2()); - match(Set dst (MinF a b)); - format %{ "minF $dst, $a, $b" %} - ins_encode %{ - __ eminmaxss($dst$$XMMRegister, $a$$XMMRegister, $b$$XMMRegister, AVX10_MINMAX_MIN_COMPARE_SIGN); - %} - ins_pipe( pipe_slow ); -%} - -// min = java.lang.Math.min(float a, float b) -instruct minF_reg(legRegF dst, legRegF a, legRegF b, legRegF tmp, legRegF atmp, legRegF btmp) %{ - predicate(!VM_Version::supports_avx10_2() && UseAVX > 0 && !VLoopReductions::is_reduction(n)); - match(Set dst (MinF a b)); - effect(USE a, USE b, TEMP tmp, TEMP atmp, TEMP btmp); - format %{ "minF $dst, $a, $b \t! using $tmp, $atmp and $btmp as TEMP" %} - ins_encode %{ - __ vminmax_fp(Op_MinV, T_FLOAT, $dst$$XMMRegister, $a$$XMMRegister, $b$$XMMRegister, $tmp$$XMMRegister, $atmp$$XMMRegister, $btmp$$XMMRegister, Assembler::AVX_128bit); - %} - ins_pipe( pipe_slow ); -%} - -instruct minF_reduction_reg(legRegF dst, legRegF a, legRegF b, legRegF xtmp, rRegI rtmp, rFlagsReg cr) %{ - predicate(!VM_Version::supports_avx10_2() && UseAVX > 0 && VLoopReductions::is_reduction(n)); - match(Set dst (MinF a b)); - effect(USE a, USE b, TEMP xtmp, TEMP rtmp, KILL cr); - - format %{ "minF_reduction $dst, $a, $b \t! using $xtmp and $rtmp as TEMP" %} - ins_encode %{ - emit_fp_min_max(masm, $dst$$XMMRegister, $a$$XMMRegister, $b$$XMMRegister, $xtmp$$XMMRegister, $rtmp$$Register, - true /*min*/, true /*single*/); - %} - ins_pipe( pipe_slow ); -%} - -// max = java.lang.Math.min(double a, double b) -instruct minD_avx10_reg(regD dst, regD a, regD b) %{ - predicate(VM_Version::supports_avx10_2()); - match(Set dst (MinD a b)); - format %{ "minD $dst, $a, $b" %} - ins_encode %{ - __ eminmaxsd($dst$$XMMRegister, $a$$XMMRegister, $b$$XMMRegister, AVX10_MINMAX_MIN_COMPARE_SIGN); - %} - ins_pipe( pipe_slow ); -%} - -// min = java.lang.Math.min(double a, double b) -instruct minD_reg(legRegD dst, legRegD a, legRegD b, legRegD tmp, legRegD atmp, legRegD btmp) %{ - predicate(!VM_Version::supports_avx10_2() && UseAVX > 0 && !VLoopReductions::is_reduction(n)); - match(Set dst (MinD a b)); - effect(USE a, USE b, TEMP tmp, TEMP atmp, TEMP btmp); - format %{ "minD $dst, $a, $b \t! using $tmp, $atmp and $btmp as TEMP" %} - ins_encode %{ - __ vminmax_fp(Op_MinV, T_DOUBLE, $dst$$XMMRegister, $a$$XMMRegister, $b$$XMMRegister, $tmp$$XMMRegister, $atmp$$XMMRegister, $btmp$$XMMRegister, Assembler::AVX_128bit); - %} - ins_pipe( pipe_slow ); -%} - -instruct minD_reduction_reg(legRegD dst, legRegD a, legRegD b, legRegD xtmp, rRegL rtmp, rFlagsReg cr) %{ - predicate(!VM_Version::supports_avx10_2() && UseAVX > 0 && VLoopReductions::is_reduction(n)); - match(Set dst (MinD a b)); - effect(USE a, USE b, TEMP xtmp, TEMP rtmp, KILL cr); - - format %{ "maxD_reduction $dst, $a, $b \t! using $xtmp and $rtmp as TEMP" %} - ins_encode %{ - emit_fp_min_max(masm, $dst$$XMMRegister, $a$$XMMRegister, $b$$XMMRegister, $xtmp$$XMMRegister, $rtmp$$Register, - true /*min*/, false /*single*/); - %} - ins_pipe( pipe_slow ); -%} - -// Load Effective Address -instruct leaP8(rRegP dst, indOffset8 mem) -%{ - match(Set dst mem); - - ins_cost(110); // XXX - format %{ "leaq $dst, $mem\t# ptr 8" %} - ins_encode %{ - __ leaq($dst$$Register, $mem$$Address); - %} - ins_pipe(ialu_reg_reg_fat); -%} - -instruct leaP32(rRegP dst, indOffset32 mem) -%{ - match(Set dst mem); - - ins_cost(110); - format %{ "leaq $dst, $mem\t# ptr 32" %} - ins_encode %{ - __ leaq($dst$$Register, $mem$$Address); - %} - ins_pipe(ialu_reg_reg_fat); -%} - -instruct leaPIdxOff(rRegP dst, indIndexOffset mem) -%{ - match(Set dst mem); - - ins_cost(110); - format %{ "leaq $dst, $mem\t# ptr idxoff" %} - ins_encode %{ - __ leaq($dst$$Register, $mem$$Address); - %} - ins_pipe(ialu_reg_reg_fat); -%} - -instruct leaPIdxScale(rRegP dst, indIndexScale mem) -%{ - match(Set dst mem); - - ins_cost(110); - format %{ "leaq $dst, $mem\t# ptr idxscale" %} - ins_encode %{ - __ leaq($dst$$Register, $mem$$Address); - %} - ins_pipe(ialu_reg_reg_fat); -%} - -instruct leaPPosIdxScale(rRegP dst, indPosIndexScale mem) -%{ - match(Set dst mem); - - ins_cost(110); - format %{ "leaq $dst, $mem\t# ptr idxscale" %} - ins_encode %{ - __ leaq($dst$$Register, $mem$$Address); - %} - ins_pipe(ialu_reg_reg_fat); -%} - -instruct leaPIdxScaleOff(rRegP dst, indIndexScaleOffset mem) -%{ - match(Set dst mem); - - ins_cost(110); - format %{ "leaq $dst, $mem\t# ptr idxscaleoff" %} - ins_encode %{ - __ leaq($dst$$Register, $mem$$Address); - %} - ins_pipe(ialu_reg_reg_fat); -%} - -instruct leaPPosIdxOff(rRegP dst, indPosIndexOffset mem) -%{ - match(Set dst mem); - - ins_cost(110); - format %{ "leaq $dst, $mem\t# ptr posidxoff" %} - ins_encode %{ - __ leaq($dst$$Register, $mem$$Address); - %} - ins_pipe(ialu_reg_reg_fat); -%} - -instruct leaPPosIdxScaleOff(rRegP dst, indPosIndexScaleOffset mem) -%{ - match(Set dst mem); - - ins_cost(110); - format %{ "leaq $dst, $mem\t# ptr posidxscaleoff" %} - ins_encode %{ - __ leaq($dst$$Register, $mem$$Address); - %} - ins_pipe(ialu_reg_reg_fat); -%} - -// Load Effective Address which uses Narrow (32-bits) oop -instruct leaPCompressedOopOffset(rRegP dst, indCompressedOopOffset mem) -%{ - predicate(UseCompressedOops && (CompressedOops::shift() != 0)); - match(Set dst mem); - - ins_cost(110); - format %{ "leaq $dst, $mem\t# ptr compressedoopoff32" %} - ins_encode %{ - __ leaq($dst$$Register, $mem$$Address); - %} - ins_pipe(ialu_reg_reg_fat); -%} - -instruct leaP8Narrow(rRegP dst, indOffset8Narrow mem) -%{ - predicate(CompressedOops::shift() == 0); - match(Set dst mem); - - ins_cost(110); // XXX - format %{ "leaq $dst, $mem\t# ptr off8narrow" %} - ins_encode %{ - __ leaq($dst$$Register, $mem$$Address); - %} - ins_pipe(ialu_reg_reg_fat); -%} - -instruct leaP32Narrow(rRegP dst, indOffset32Narrow mem) -%{ - predicate(CompressedOops::shift() == 0); - match(Set dst mem); - - ins_cost(110); - format %{ "leaq $dst, $mem\t# ptr off32narrow" %} - ins_encode %{ - __ leaq($dst$$Register, $mem$$Address); - %} - ins_pipe(ialu_reg_reg_fat); -%} - -instruct leaPIdxOffNarrow(rRegP dst, indIndexOffsetNarrow mem) -%{ - predicate(CompressedOops::shift() == 0); - match(Set dst mem); - - ins_cost(110); - format %{ "leaq $dst, $mem\t# ptr idxoffnarrow" %} - ins_encode %{ - __ leaq($dst$$Register, $mem$$Address); - %} - ins_pipe(ialu_reg_reg_fat); -%} - -instruct leaPIdxScaleNarrow(rRegP dst, indIndexScaleNarrow mem) -%{ - predicate(CompressedOops::shift() == 0); - match(Set dst mem); - - ins_cost(110); - format %{ "leaq $dst, $mem\t# ptr idxscalenarrow" %} - ins_encode %{ - __ leaq($dst$$Register, $mem$$Address); - %} - ins_pipe(ialu_reg_reg_fat); -%} - -instruct leaPIdxScaleOffNarrow(rRegP dst, indIndexScaleOffsetNarrow mem) -%{ - predicate(CompressedOops::shift() == 0); - match(Set dst mem); - - ins_cost(110); - format %{ "leaq $dst, $mem\t# ptr idxscaleoffnarrow" %} - ins_encode %{ - __ leaq($dst$$Register, $mem$$Address); - %} - ins_pipe(ialu_reg_reg_fat); -%} - -instruct leaPPosIdxOffNarrow(rRegP dst, indPosIndexOffsetNarrow mem) -%{ - predicate(CompressedOops::shift() == 0); - match(Set dst mem); - - ins_cost(110); - format %{ "leaq $dst, $mem\t# ptr posidxoffnarrow" %} - ins_encode %{ - __ leaq($dst$$Register, $mem$$Address); - %} - ins_pipe(ialu_reg_reg_fat); -%} - -instruct leaPPosIdxScaleOffNarrow(rRegP dst, indPosIndexScaleOffsetNarrow mem) -%{ - predicate(CompressedOops::shift() == 0); - match(Set dst mem); - - ins_cost(110); - format %{ "leaq $dst, $mem\t# ptr posidxscaleoffnarrow" %} - ins_encode %{ - __ leaq($dst$$Register, $mem$$Address); - %} - ins_pipe(ialu_reg_reg_fat); -%} - -instruct loadConI(rRegI dst, immI src) -%{ - match(Set dst src); - - format %{ "movl $dst, $src\t# int" %} - ins_encode %{ - __ movl($dst$$Register, $src$$constant); - %} - ins_pipe(ialu_reg_fat); // XXX -%} - -instruct loadConI0(rRegI dst, immI_0 src, rFlagsReg cr) -%{ - match(Set dst src); - effect(KILL cr); - - ins_cost(50); - format %{ "xorl $dst, $dst\t# int" %} - ins_encode %{ - __ xorl($dst$$Register, $dst$$Register); - %} - ins_pipe(ialu_reg); -%} - -instruct loadConL(rRegL dst, immL src) -%{ - match(Set dst src); - - ins_cost(150); - format %{ "movq $dst, $src\t# long" %} - ins_encode %{ - __ mov64($dst$$Register, $src$$constant); - %} - ins_pipe(ialu_reg); -%} - -instruct loadConL0(rRegL dst, immL0 src, rFlagsReg cr) -%{ - match(Set dst src); - effect(KILL cr); - - ins_cost(50); - format %{ "xorl $dst, $dst\t# long" %} - ins_encode %{ - __ xorl($dst$$Register, $dst$$Register); - %} - ins_pipe(ialu_reg); // XXX -%} - -instruct loadConUL32(rRegL dst, immUL32 src) -%{ - match(Set dst src); - - ins_cost(60); - format %{ "movl $dst, $src\t# long (unsigned 32-bit)" %} - ins_encode %{ - __ movl($dst$$Register, $src$$constant); - %} - ins_pipe(ialu_reg); -%} - -instruct loadConL32(rRegL dst, immL32 src) -%{ - match(Set dst src); - - ins_cost(70); - format %{ "movq $dst, $src\t# long (32-bit)" %} - ins_encode %{ - __ movq($dst$$Register, $src$$constant); - %} - ins_pipe(ialu_reg); -%} - -instruct loadConP(rRegP dst, immP con) %{ - match(Set dst con); - - format %{ "movq $dst, $con\t# ptr" %} - ins_encode %{ - __ mov64($dst$$Register, $con$$constant, $con->constant_reloc(), RELOC_IMM64); - %} - ins_pipe(ialu_reg_fat); // XXX -%} - -instruct loadConP0(rRegP dst, immP0 src, rFlagsReg cr) -%{ - match(Set dst src); - effect(KILL cr); - - ins_cost(50); - format %{ "xorl $dst, $dst\t# ptr" %} - ins_encode %{ - __ xorl($dst$$Register, $dst$$Register); - %} - ins_pipe(ialu_reg); -%} - -instruct loadConP31(rRegP dst, immP31 src, rFlagsReg cr) -%{ - match(Set dst src); - effect(KILL cr); - - ins_cost(60); - format %{ "movl $dst, $src\t# ptr (positive 32-bit)" %} - ins_encode %{ - __ movl($dst$$Register, $src$$constant); - %} - ins_pipe(ialu_reg); -%} - -instruct loadConF(regF dst, immF con) %{ - match(Set dst con); - ins_cost(125); - format %{ "movss $dst, [$constantaddress]\t# load from constant table: float=$con" %} - ins_encode %{ - __ movflt($dst$$XMMRegister, $constantaddress($con)); - %} - ins_pipe(pipe_slow); -%} - -instruct loadConH(regF dst, immH con) %{ - match(Set dst con); - ins_cost(125); - format %{ "movss $dst, [$constantaddress]\t# load from constant table: halffloat=$con" %} - ins_encode %{ - __ movflt($dst$$XMMRegister, $constantaddress($con)); - %} - ins_pipe(pipe_slow); -%} - -instruct loadConN0(rRegN dst, immN0 src, rFlagsReg cr) %{ - match(Set dst src); - effect(KILL cr); - format %{ "xorq $dst, $src\t# compressed null pointer" %} - ins_encode %{ - __ xorq($dst$$Register, $dst$$Register); - %} - ins_pipe(ialu_reg); -%} - -instruct loadConN(rRegN dst, immN src) %{ - match(Set dst src); - - ins_cost(125); - format %{ "movl $dst, $src\t# compressed ptr" %} - ins_encode %{ - address con = (address)$src$$constant; - if (con == nullptr) { - ShouldNotReachHere(); - } else { - __ set_narrow_oop($dst$$Register, (jobject)$src$$constant); - } - %} - ins_pipe(ialu_reg_fat); // XXX -%} - -instruct loadConNKlass(rRegN dst, immNKlass src) %{ - match(Set dst src); - - ins_cost(125); - format %{ "movl $dst, $src\t# compressed klass ptr" %} - ins_encode %{ - address con = (address)$src$$constant; - if (con == nullptr) { - ShouldNotReachHere(); - } else { - __ set_narrow_klass($dst$$Register, (Klass*)$src$$constant); - } - %} - ins_pipe(ialu_reg_fat); // XXX -%} - -instruct loadConF0(regF dst, immF0 src) -%{ - match(Set dst src); - ins_cost(100); - - format %{ "xorps $dst, $dst\t# float 0.0" %} - ins_encode %{ - __ xorps($dst$$XMMRegister, $dst$$XMMRegister); - %} - ins_pipe(pipe_slow); -%} - -// Use the same format since predicate() can not be used here. -instruct loadConD(regD dst, immD con) %{ - match(Set dst con); - ins_cost(125); - format %{ "movsd $dst, [$constantaddress]\t# load from constant table: double=$con" %} - ins_encode %{ - __ movdbl($dst$$XMMRegister, $constantaddress($con)); - %} - ins_pipe(pipe_slow); -%} - -instruct loadConD0(regD dst, immD0 src) -%{ - match(Set dst src); - ins_cost(100); - - format %{ "xorpd $dst, $dst\t# double 0.0" %} - ins_encode %{ - __ xorpd($dst$$XMMRegister, $dst$$XMMRegister); - %} - ins_pipe(pipe_slow); -%} - -instruct loadSSI(rRegI dst, stackSlotI src) -%{ - match(Set dst src); - - ins_cost(125); - format %{ "movl $dst, $src\t# int stk" %} - ins_encode %{ - __ movl($dst$$Register, $src$$Address); - %} - ins_pipe(ialu_reg_mem); -%} - -instruct loadSSL(rRegL dst, stackSlotL src) -%{ - match(Set dst src); - - ins_cost(125); - format %{ "movq $dst, $src\t# long stk" %} - ins_encode %{ - __ movq($dst$$Register, $src$$Address); - %} - ins_pipe(ialu_reg_mem); -%} - -instruct loadSSP(rRegP dst, stackSlotP src) -%{ - match(Set dst src); - - ins_cost(125); - format %{ "movq $dst, $src\t# ptr stk" %} - ins_encode %{ - __ movq($dst$$Register, $src$$Address); - %} - ins_pipe(ialu_reg_mem); -%} - -instruct loadSSF(regF dst, stackSlotF src) -%{ - match(Set dst src); - - ins_cost(125); - format %{ "movss $dst, $src\t# float stk" %} - ins_encode %{ - __ movflt($dst$$XMMRegister, Address(rsp, $src$$disp)); - %} - ins_pipe(pipe_slow); // XXX -%} - -// Use the same format since predicate() can not be used here. -instruct loadSSD(regD dst, stackSlotD src) -%{ - match(Set dst src); - - ins_cost(125); - format %{ "movsd $dst, $src\t# double stk" %} - ins_encode %{ - __ movdbl($dst$$XMMRegister, Address(rsp, $src$$disp)); - %} - ins_pipe(pipe_slow); // XXX -%} - -// Prefetch instructions for allocation. -// Must be safe to execute with invalid address (cannot fault). - -instruct prefetchAlloc( memory mem ) %{ - predicate(AllocatePrefetchInstr==3); - match(PrefetchAllocation mem); - ins_cost(125); - - format %{ "PREFETCHW $mem\t# Prefetch allocation into level 1 cache and mark modified" %} - ins_encode %{ - __ prefetchw($mem$$Address); - %} - ins_pipe(ialu_mem); -%} - -instruct prefetchAllocNTA( memory mem ) %{ - predicate(AllocatePrefetchInstr==0); - match(PrefetchAllocation mem); - ins_cost(125); - - format %{ "PREFETCHNTA $mem\t# Prefetch allocation to non-temporal cache for write" %} - ins_encode %{ - __ prefetchnta($mem$$Address); - %} - ins_pipe(ialu_mem); -%} - -instruct prefetchAllocT0( memory mem ) %{ - predicate(AllocatePrefetchInstr==1); - match(PrefetchAllocation mem); - ins_cost(125); - - format %{ "PREFETCHT0 $mem\t# Prefetch allocation to level 1 and 2 caches for write" %} - ins_encode %{ - __ prefetcht0($mem$$Address); - %} - ins_pipe(ialu_mem); -%} - -instruct prefetchAllocT2( memory mem ) %{ - predicate(AllocatePrefetchInstr==2); - match(PrefetchAllocation mem); - ins_cost(125); - - format %{ "PREFETCHT2 $mem\t# Prefetch allocation to level 2 cache for write" %} - ins_encode %{ - __ prefetcht2($mem$$Address); - %} - ins_pipe(ialu_mem); -%} - -//----------Store Instructions------------------------------------------------- - -// Store Byte -instruct storeB(memory mem, rRegI src) -%{ - match(Set mem (StoreB mem src)); - - ins_cost(125); // XXX - format %{ "movb $mem, $src\t# byte" %} - ins_encode %{ - __ movb($mem$$Address, $src$$Register); - %} - ins_pipe(ialu_mem_reg); -%} - -// Store Char/Short -instruct storeC(memory mem, rRegI src) -%{ - match(Set mem (StoreC mem src)); - - ins_cost(125); // XXX - format %{ "movw $mem, $src\t# char/short" %} - ins_encode %{ - __ movw($mem$$Address, $src$$Register); - %} - ins_pipe(ialu_mem_reg); -%} - -// Store Integer -instruct storeI(memory mem, rRegI src) -%{ - match(Set mem (StoreI mem src)); - - ins_cost(125); // XXX - format %{ "movl $mem, $src\t# int" %} - ins_encode %{ - __ movl($mem$$Address, $src$$Register); - %} - ins_pipe(ialu_mem_reg); -%} - -// Store Long -instruct storeL(memory mem, rRegL src) -%{ - match(Set mem (StoreL mem src)); - - ins_cost(125); // XXX - format %{ "movq $mem, $src\t# long" %} - ins_encode %{ - __ movq($mem$$Address, $src$$Register); - %} - ins_pipe(ialu_mem_reg); // XXX -%} - -// Store Pointer -instruct storeP(memory mem, any_RegP src) -%{ - predicate(n->as_Store()->barrier_data() == 0); - match(Set mem (StoreP mem src)); - - ins_cost(125); // XXX - format %{ "movq $mem, $src\t# ptr" %} - ins_encode %{ - __ movq($mem$$Address, $src$$Register); - %} - ins_pipe(ialu_mem_reg); -%} - -instruct storeImmP0(memory mem, immP0 zero) -%{ - predicate(UseCompressedOops && (CompressedOops::base() == nullptr) && n->as_Store()->barrier_data() == 0); - match(Set mem (StoreP mem zero)); - - ins_cost(125); // XXX - format %{ "movq $mem, R12\t# ptr (R12_heapbase==0)" %} - ins_encode %{ - __ movq($mem$$Address, r12); - %} - ins_pipe(ialu_mem_reg); -%} - -// Store Null Pointer, mark word, or other simple pointer constant. -instruct storeImmP(memory mem, immP31 src) -%{ - predicate(n->as_Store()->barrier_data() == 0); - match(Set mem (StoreP mem src)); - - ins_cost(150); // XXX - format %{ "movq $mem, $src\t# ptr" %} - ins_encode %{ - __ movq($mem$$Address, $src$$constant); - %} - ins_pipe(ialu_mem_imm); -%} - -// Store Compressed Pointer -instruct storeN(memory mem, rRegN src) -%{ - predicate(n->as_Store()->barrier_data() == 0); - match(Set mem (StoreN mem src)); - - ins_cost(125); // XXX - format %{ "movl $mem, $src\t# compressed ptr" %} - ins_encode %{ - __ movl($mem$$Address, $src$$Register); - %} - ins_pipe(ialu_mem_reg); -%} - -instruct storeNKlass(memory mem, rRegN src) -%{ - match(Set mem (StoreNKlass mem src)); - - ins_cost(125); // XXX - format %{ "movl $mem, $src\t# compressed klass ptr" %} - ins_encode %{ - __ movl($mem$$Address, $src$$Register); - %} - ins_pipe(ialu_mem_reg); -%} - -instruct storeImmN0(memory mem, immN0 zero) -%{ - predicate(CompressedOops::base() == nullptr && n->as_Store()->barrier_data() == 0); - match(Set mem (StoreN mem zero)); - - ins_cost(125); // XXX - format %{ "movl $mem, R12\t# compressed ptr (R12_heapbase==0)" %} - ins_encode %{ - __ movl($mem$$Address, r12); - %} - ins_pipe(ialu_mem_reg); -%} - -instruct storeImmN(memory mem, immN src) -%{ - predicate(n->as_Store()->barrier_data() == 0); - match(Set mem (StoreN mem src)); - - ins_cost(150); // XXX - format %{ "movl $mem, $src\t# compressed ptr" %} - ins_encode %{ - address con = (address)$src$$constant; - if (con == nullptr) { - __ movl($mem$$Address, 0); - } else { - __ set_narrow_oop($mem$$Address, (jobject)$src$$constant); - } - %} - ins_pipe(ialu_mem_imm); -%} - -instruct storeImmNKlass(memory mem, immNKlass src) -%{ - match(Set mem (StoreNKlass mem src)); - - ins_cost(150); // XXX - format %{ "movl $mem, $src\t# compressed klass ptr" %} - ins_encode %{ - __ set_narrow_klass($mem$$Address, (Klass*)$src$$constant); - %} - ins_pipe(ialu_mem_imm); -%} - -// Store Integer Immediate -instruct storeImmI0(memory mem, immI_0 zero) -%{ - predicate(UseCompressedOops && (CompressedOops::base() == nullptr)); - match(Set mem (StoreI mem zero)); - - ins_cost(125); // XXX - format %{ "movl $mem, R12\t# int (R12_heapbase==0)" %} - ins_encode %{ - __ movl($mem$$Address, r12); - %} - ins_pipe(ialu_mem_reg); -%} - -instruct storeImmI(memory mem, immI src) -%{ - match(Set mem (StoreI mem src)); - - ins_cost(150); - format %{ "movl $mem, $src\t# int" %} - ins_encode %{ - __ movl($mem$$Address, $src$$constant); - %} - ins_pipe(ialu_mem_imm); -%} - -// Store Long Immediate -instruct storeImmL0(memory mem, immL0 zero) -%{ - predicate(UseCompressedOops && (CompressedOops::base() == nullptr)); - match(Set mem (StoreL mem zero)); - - ins_cost(125); // XXX - format %{ "movq $mem, R12\t# long (R12_heapbase==0)" %} - ins_encode %{ - __ movq($mem$$Address, r12); - %} - ins_pipe(ialu_mem_reg); -%} - -instruct storeImmL(memory mem, immL32 src) -%{ - match(Set mem (StoreL mem src)); - - ins_cost(150); - format %{ "movq $mem, $src\t# long" %} - ins_encode %{ - __ movq($mem$$Address, $src$$constant); - %} - ins_pipe(ialu_mem_imm); -%} - -// Store Short/Char Immediate -instruct storeImmC0(memory mem, immI_0 zero) -%{ - predicate(UseCompressedOops && (CompressedOops::base() == nullptr)); - match(Set mem (StoreC mem zero)); - - ins_cost(125); // XXX - format %{ "movw $mem, R12\t# short/char (R12_heapbase==0)" %} - ins_encode %{ - __ movw($mem$$Address, r12); - %} - ins_pipe(ialu_mem_reg); -%} - -instruct storeImmI16(memory mem, immI16 src) -%{ - predicate(UseStoreImmI16); - match(Set mem (StoreC mem src)); - - ins_cost(150); - format %{ "movw $mem, $src\t# short/char" %} - ins_encode %{ - __ movw($mem$$Address, $src$$constant); - %} - ins_pipe(ialu_mem_imm); -%} - -// Store Byte Immediate -instruct storeImmB0(memory mem, immI_0 zero) -%{ - predicate(UseCompressedOops && (CompressedOops::base() == nullptr)); - match(Set mem (StoreB mem zero)); - - ins_cost(125); // XXX - format %{ "movb $mem, R12\t# short/char (R12_heapbase==0)" %} - ins_encode %{ - __ movb($mem$$Address, r12); - %} - ins_pipe(ialu_mem_reg); -%} - -instruct storeImmB(memory mem, immI8 src) -%{ - match(Set mem (StoreB mem src)); - - ins_cost(150); // XXX - format %{ "movb $mem, $src\t# byte" %} - ins_encode %{ - __ movb($mem$$Address, $src$$constant); - %} - ins_pipe(ialu_mem_imm); -%} - -// Store Float -instruct storeF(memory mem, regF src) -%{ - match(Set mem (StoreF mem src)); - - ins_cost(95); // XXX - format %{ "movss $mem, $src\t# float" %} - ins_encode %{ - __ movflt($mem$$Address, $src$$XMMRegister); - %} - ins_pipe(pipe_slow); // XXX -%} - -// Store immediate Float value (it is faster than store from XMM register) -instruct storeF0(memory mem, immF0 zero) -%{ - predicate(UseCompressedOops && (CompressedOops::base() == nullptr)); - match(Set mem (StoreF mem zero)); - - ins_cost(25); // XXX - format %{ "movl $mem, R12\t# float 0. (R12_heapbase==0)" %} - ins_encode %{ - __ movl($mem$$Address, r12); - %} - ins_pipe(ialu_mem_reg); -%} - -instruct storeF_imm(memory mem, immF src) -%{ - match(Set mem (StoreF mem src)); - - ins_cost(50); - format %{ "movl $mem, $src\t# float" %} - ins_encode %{ - __ movl($mem$$Address, jint_cast($src$$constant)); - %} - ins_pipe(ialu_mem_imm); -%} - -// Store Double -instruct storeD(memory mem, regD src) -%{ - match(Set mem (StoreD mem src)); - - ins_cost(95); // XXX - format %{ "movsd $mem, $src\t# double" %} - ins_encode %{ - __ movdbl($mem$$Address, $src$$XMMRegister); - %} - ins_pipe(pipe_slow); // XXX -%} - -// Store immediate double 0.0 (it is faster than store from XMM register) -instruct storeD0_imm(memory mem, immD0 src) -%{ - predicate(!UseCompressedOops || (CompressedOops::base() != nullptr)); - match(Set mem (StoreD mem src)); - - ins_cost(50); - format %{ "movq $mem, $src\t# double 0." %} - ins_encode %{ - __ movq($mem$$Address, $src$$constant); - %} - ins_pipe(ialu_mem_imm); -%} - -instruct storeD0(memory mem, immD0 zero) -%{ - predicate(UseCompressedOops && (CompressedOops::base() == nullptr)); - match(Set mem (StoreD mem zero)); - - ins_cost(25); // XXX - format %{ "movq $mem, R12\t# double 0. (R12_heapbase==0)" %} - ins_encode %{ - __ movq($mem$$Address, r12); - %} - ins_pipe(ialu_mem_reg); -%} - -instruct storeSSI(stackSlotI dst, rRegI src) -%{ - match(Set dst src); - - ins_cost(100); - format %{ "movl $dst, $src\t# int stk" %} - ins_encode %{ - __ movl($dst$$Address, $src$$Register); - %} - ins_pipe( ialu_mem_reg ); -%} - -instruct storeSSL(stackSlotL dst, rRegL src) -%{ - match(Set dst src); - - ins_cost(100); - format %{ "movq $dst, $src\t# long stk" %} - ins_encode %{ - __ movq($dst$$Address, $src$$Register); - %} - ins_pipe(ialu_mem_reg); -%} - -instruct storeSSP(stackSlotP dst, rRegP src) -%{ - match(Set dst src); - - ins_cost(100); - format %{ "movq $dst, $src\t# ptr stk" %} - ins_encode %{ - __ movq($dst$$Address, $src$$Register); - %} - ins_pipe(ialu_mem_reg); -%} - -instruct storeSSF(stackSlotF dst, regF src) -%{ - match(Set dst src); - - ins_cost(95); // XXX - format %{ "movss $dst, $src\t# float stk" %} - ins_encode %{ - __ movflt(Address(rsp, $dst$$disp), $src$$XMMRegister); - %} - ins_pipe(pipe_slow); // XXX -%} - -instruct storeSSD(stackSlotD dst, regD src) -%{ - match(Set dst src); - - ins_cost(95); // XXX - format %{ "movsd $dst, $src\t# double stk" %} - ins_encode %{ - __ movdbl(Address(rsp, $dst$$disp), $src$$XMMRegister); - %} - ins_pipe(pipe_slow); // XXX -%} - -instruct cacheWB(indirect addr) -%{ - predicate(VM_Version::supports_data_cache_line_flush()); - match(CacheWB addr); - - ins_cost(100); - format %{"cache wb $addr" %} - ins_encode %{ - assert($addr->index_position() < 0, "should be"); - assert($addr$$disp == 0, "should be"); - __ cache_wb(Address($addr$$base$$Register, 0)); - %} - ins_pipe(pipe_slow); // XXX -%} - -instruct cacheWBPreSync() -%{ - predicate(VM_Version::supports_data_cache_line_flush()); - match(CacheWBPreSync); - - ins_cost(100); - format %{"cache wb presync" %} - ins_encode %{ - __ cache_wbsync(true); - %} - ins_pipe(pipe_slow); // XXX -%} - -instruct cacheWBPostSync() -%{ - predicate(VM_Version::supports_data_cache_line_flush()); - match(CacheWBPostSync); - - ins_cost(100); - format %{"cache wb postsync" %} - ins_encode %{ - __ cache_wbsync(false); - %} - ins_pipe(pipe_slow); // XXX -%} - -//----------BSWAP Instructions------------------------------------------------- -instruct bytes_reverse_int(rRegI dst) %{ - match(Set dst (ReverseBytesI dst)); - - format %{ "bswapl $dst" %} - ins_encode %{ - __ bswapl($dst$$Register); - %} - ins_pipe( ialu_reg ); -%} - -instruct bytes_reverse_long(rRegL dst) %{ - match(Set dst (ReverseBytesL dst)); - - format %{ "bswapq $dst" %} - ins_encode %{ - __ bswapq($dst$$Register); - %} - ins_pipe( ialu_reg); -%} - -instruct bytes_reverse_unsigned_short(rRegI dst, rFlagsReg cr) %{ - match(Set dst (ReverseBytesUS dst)); - effect(KILL cr); - - format %{ "bswapl $dst\n\t" - "shrl $dst,16\n\t" %} - ins_encode %{ - __ bswapl($dst$$Register); - __ shrl($dst$$Register, 16); - %} - ins_pipe( ialu_reg ); -%} - -instruct bytes_reverse_short(rRegI dst, rFlagsReg cr) %{ - match(Set dst (ReverseBytesS dst)); - effect(KILL cr); - - format %{ "bswapl $dst\n\t" - "sar $dst,16\n\t" %} - ins_encode %{ - __ bswapl($dst$$Register); - __ sarl($dst$$Register, 16); - %} - ins_pipe( ialu_reg ); -%} - -//---------- Zeros Count Instructions ------------------------------------------ - -instruct countLeadingZerosI(rRegI dst, rRegI src, rFlagsReg cr) %{ - predicate(UseCountLeadingZerosInstruction); - match(Set dst (CountLeadingZerosI src)); - effect(KILL cr); - - format %{ "lzcntl $dst, $src\t# count leading zeros (int)" %} - ins_encode %{ - __ lzcntl($dst$$Register, $src$$Register); - %} - ins_pipe(ialu_reg); -%} - -instruct countLeadingZerosI_mem(rRegI dst, memory src, rFlagsReg cr) %{ - predicate(UseCountLeadingZerosInstruction); - match(Set dst (CountLeadingZerosI (LoadI src))); - effect(KILL cr); - ins_cost(175); - format %{ "lzcntl $dst, $src\t# count leading zeros (int)" %} - ins_encode %{ - __ lzcntl($dst$$Register, $src$$Address); - %} - ins_pipe(ialu_reg_mem); -%} - -instruct countLeadingZerosI_bsr(rRegI dst, rRegI src, rFlagsReg cr) %{ - predicate(!UseCountLeadingZerosInstruction); - match(Set dst (CountLeadingZerosI src)); - effect(KILL cr); - - format %{ "bsrl $dst, $src\t# count leading zeros (int)\n\t" - "jnz skip\n\t" - "movl $dst, -1\n" - "skip:\n\t" - "negl $dst\n\t" - "addl $dst, 31" %} - ins_encode %{ - Register Rdst = $dst$$Register; - Register Rsrc = $src$$Register; - Label skip; - __ bsrl(Rdst, Rsrc); - __ jccb(Assembler::notZero, skip); - __ movl(Rdst, -1); - __ bind(skip); - __ negl(Rdst); - __ addl(Rdst, BitsPerInt - 1); - %} - ins_pipe(ialu_reg); -%} - -instruct countLeadingZerosL(rRegI dst, rRegL src, rFlagsReg cr) %{ - predicate(UseCountLeadingZerosInstruction); - match(Set dst (CountLeadingZerosL src)); - effect(KILL cr); - - format %{ "lzcntq $dst, $src\t# count leading zeros (long)" %} - ins_encode %{ - __ lzcntq($dst$$Register, $src$$Register); - %} - ins_pipe(ialu_reg); -%} - -instruct countLeadingZerosL_mem(rRegI dst, memory src, rFlagsReg cr) %{ - predicate(UseCountLeadingZerosInstruction); - match(Set dst (CountLeadingZerosL (LoadL src))); - effect(KILL cr); - ins_cost(175); - format %{ "lzcntq $dst, $src\t# count leading zeros (long)" %} - ins_encode %{ - __ lzcntq($dst$$Register, $src$$Address); - %} - ins_pipe(ialu_reg_mem); -%} - -instruct countLeadingZerosL_bsr(rRegI dst, rRegL src, rFlagsReg cr) %{ - predicate(!UseCountLeadingZerosInstruction); - match(Set dst (CountLeadingZerosL src)); - effect(KILL cr); - - format %{ "bsrq $dst, $src\t# count leading zeros (long)\n\t" - "jnz skip\n\t" - "movl $dst, -1\n" - "skip:\n\t" - "negl $dst\n\t" - "addl $dst, 63" %} - ins_encode %{ - Register Rdst = $dst$$Register; - Register Rsrc = $src$$Register; - Label skip; - __ bsrq(Rdst, Rsrc); - __ jccb(Assembler::notZero, skip); - __ movl(Rdst, -1); - __ bind(skip); - __ negl(Rdst); - __ addl(Rdst, BitsPerLong - 1); - %} - ins_pipe(ialu_reg); -%} - -instruct countTrailingZerosI(rRegI dst, rRegI src, rFlagsReg cr) %{ - predicate(UseCountTrailingZerosInstruction); - match(Set dst (CountTrailingZerosI src)); - effect(KILL cr); - - format %{ "tzcntl $dst, $src\t# count trailing zeros (int)" %} - ins_encode %{ - __ tzcntl($dst$$Register, $src$$Register); - %} - ins_pipe(ialu_reg); -%} - -instruct countTrailingZerosI_mem(rRegI dst, memory src, rFlagsReg cr) %{ - predicate(UseCountTrailingZerosInstruction); - match(Set dst (CountTrailingZerosI (LoadI src))); - effect(KILL cr); - ins_cost(175); - format %{ "tzcntl $dst, $src\t# count trailing zeros (int)" %} - ins_encode %{ - __ tzcntl($dst$$Register, $src$$Address); - %} - ins_pipe(ialu_reg_mem); -%} - -instruct countTrailingZerosI_bsf(rRegI dst, rRegI src, rFlagsReg cr) %{ - predicate(!UseCountTrailingZerosInstruction); - match(Set dst (CountTrailingZerosI src)); - effect(KILL cr); - - format %{ "bsfl $dst, $src\t# count trailing zeros (int)\n\t" - "jnz done\n\t" - "movl $dst, 32\n" - "done:" %} - ins_encode %{ - Register Rdst = $dst$$Register; - Label done; - __ bsfl(Rdst, $src$$Register); - __ jccb(Assembler::notZero, done); - __ movl(Rdst, BitsPerInt); - __ bind(done); - %} - ins_pipe(ialu_reg); -%} - -instruct countTrailingZerosL(rRegI dst, rRegL src, rFlagsReg cr) %{ - predicate(UseCountTrailingZerosInstruction); - match(Set dst (CountTrailingZerosL src)); - effect(KILL cr); - - format %{ "tzcntq $dst, $src\t# count trailing zeros (long)" %} - ins_encode %{ - __ tzcntq($dst$$Register, $src$$Register); - %} - ins_pipe(ialu_reg); -%} - -instruct countTrailingZerosL_mem(rRegI dst, memory src, rFlagsReg cr) %{ - predicate(UseCountTrailingZerosInstruction); - match(Set dst (CountTrailingZerosL (LoadL src))); - effect(KILL cr); - ins_cost(175); - format %{ "tzcntq $dst, $src\t# count trailing zeros (long)" %} - ins_encode %{ - __ tzcntq($dst$$Register, $src$$Address); - %} - ins_pipe(ialu_reg_mem); -%} - -instruct countTrailingZerosL_bsf(rRegI dst, rRegL src, rFlagsReg cr) %{ - predicate(!UseCountTrailingZerosInstruction); - match(Set dst (CountTrailingZerosL src)); - effect(KILL cr); - - format %{ "bsfq $dst, $src\t# count trailing zeros (long)\n\t" - "jnz done\n\t" - "movl $dst, 64\n" - "done:" %} - ins_encode %{ - Register Rdst = $dst$$Register; - Label done; - __ bsfq(Rdst, $src$$Register); - __ jccb(Assembler::notZero, done); - __ movl(Rdst, BitsPerLong); - __ bind(done); - %} - ins_pipe(ialu_reg); -%} - -//--------------- Reverse Operation Instructions ---------------- -instruct bytes_reversebit_int(rRegI dst, rRegI src, rRegI rtmp, rFlagsReg cr) %{ - predicate(!VM_Version::supports_gfni()); - match(Set dst (ReverseI src)); - effect(TEMP dst, TEMP rtmp, KILL cr); - format %{ "reverse_int $dst $src\t! using $rtmp as TEMP" %} - ins_encode %{ - __ reverseI($dst$$Register, $src$$Register, xnoreg, xnoreg, $rtmp$$Register); - %} - ins_pipe( ialu_reg ); -%} - -instruct bytes_reversebit_int_gfni(rRegI dst, rRegI src, vlRegF xtmp1, vlRegF xtmp2, rRegL rtmp, rFlagsReg cr) %{ - predicate(VM_Version::supports_gfni()); - match(Set dst (ReverseI src)); - effect(TEMP dst, TEMP xtmp1, TEMP xtmp2, TEMP rtmp, KILL cr); - format %{ "reverse_int $dst $src\t! using $rtmp, $xtmp1 and $xtmp2 as TEMP" %} - ins_encode %{ - __ reverseI($dst$$Register, $src$$Register, $xtmp1$$XMMRegister, $xtmp2$$XMMRegister, $rtmp$$Register); - %} - ins_pipe( ialu_reg ); -%} - -instruct bytes_reversebit_long(rRegL dst, rRegL src, rRegL rtmp1, rRegL rtmp2, rFlagsReg cr) %{ - predicate(!VM_Version::supports_gfni()); - match(Set dst (ReverseL src)); - effect(TEMP dst, TEMP rtmp1, TEMP rtmp2, KILL cr); - format %{ "reverse_long $dst $src\t! using $rtmp1 and $rtmp2 as TEMP" %} - ins_encode %{ - __ reverseL($dst$$Register, $src$$Register, xnoreg, xnoreg, $rtmp1$$Register, $rtmp2$$Register); - %} - ins_pipe( ialu_reg ); -%} - -instruct bytes_reversebit_long_gfni(rRegL dst, rRegL src, vlRegD xtmp1, vlRegD xtmp2, rRegL rtmp, rFlagsReg cr) %{ - predicate(VM_Version::supports_gfni()); - match(Set dst (ReverseL src)); - effect(TEMP dst, TEMP xtmp1, TEMP xtmp2, TEMP rtmp, KILL cr); - format %{ "reverse_long $dst $src\t! using $rtmp, $xtmp1 and $xtmp2 as TEMP" %} - ins_encode %{ - __ reverseL($dst$$Register, $src$$Register, $xtmp1$$XMMRegister, $xtmp2$$XMMRegister, $rtmp$$Register, noreg); - %} - ins_pipe( ialu_reg ); -%} - -//---------- Population Count Instructions ------------------------------------- - -instruct popCountI(rRegI dst, rRegI src, rFlagsReg cr) %{ - predicate(UsePopCountInstruction); - match(Set dst (PopCountI src)); - effect(KILL cr); - - format %{ "popcnt $dst, $src" %} - ins_encode %{ - __ popcntl($dst$$Register, $src$$Register); - %} - ins_pipe(ialu_reg); -%} - -instruct popCountI_mem(rRegI dst, memory mem, rFlagsReg cr) %{ - predicate(UsePopCountInstruction); - match(Set dst (PopCountI (LoadI mem))); - effect(KILL cr); - - format %{ "popcnt $dst, $mem" %} - ins_encode %{ - __ popcntl($dst$$Register, $mem$$Address); - %} - ins_pipe(ialu_reg); -%} - -// Note: Long.bitCount(long) returns an int. -instruct popCountL(rRegI dst, rRegL src, rFlagsReg cr) %{ - predicate(UsePopCountInstruction); - match(Set dst (PopCountL src)); - effect(KILL cr); - - format %{ "popcnt $dst, $src" %} - ins_encode %{ - __ popcntq($dst$$Register, $src$$Register); - %} - ins_pipe(ialu_reg); -%} - -// Note: Long.bitCount(long) returns an int. -instruct popCountL_mem(rRegI dst, memory mem, rFlagsReg cr) %{ - predicate(UsePopCountInstruction); - match(Set dst (PopCountL (LoadL mem))); - effect(KILL cr); - - format %{ "popcnt $dst, $mem" %} - ins_encode %{ - __ popcntq($dst$$Register, $mem$$Address); - %} - ins_pipe(ialu_reg); -%} - - -//----------MemBar Instructions----------------------------------------------- -// Memory barrier flavors - -instruct membar_acquire() -%{ - match(MemBarAcquire); - match(LoadFence); - ins_cost(0); - - size(0); - format %{ "MEMBAR-acquire ! (empty encoding)" %} - ins_encode(); - ins_pipe(empty); -%} - -instruct membar_acquire_lock() -%{ - match(MemBarAcquireLock); - ins_cost(0); - - size(0); - format %{ "MEMBAR-acquire (prior CMPXCHG in FastLock so empty encoding)" %} - ins_encode(); - ins_pipe(empty); -%} - -instruct membar_release() -%{ - match(MemBarRelease); - match(StoreFence); - ins_cost(0); - - size(0); - format %{ "MEMBAR-release ! (empty encoding)" %} - ins_encode(); - ins_pipe(empty); -%} - -instruct membar_release_lock() -%{ - match(MemBarReleaseLock); - ins_cost(0); - - size(0); - format %{ "MEMBAR-release (a FastUnlock follows so empty encoding)" %} - ins_encode(); - ins_pipe(empty); -%} - -instruct membar_volatile(rFlagsReg cr) %{ - match(MemBarVolatile); - effect(KILL cr); - ins_cost(400); - - format %{ - $$template - $$emit$$"lock addl [rsp + #0], 0\t! membar_volatile" - %} - ins_encode %{ - __ membar(Assembler::StoreLoad); - %} - ins_pipe(pipe_slow); -%} - -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); -%} - -instruct membar_storestore() %{ - match(MemBarStoreStore); - match(StoreStoreFence); - ins_cost(0); - - size(0); - format %{ "MEMBAR-storestore (empty encoding)" %} - ins_encode( ); - ins_pipe(empty); -%} - -//----------Move Instructions-------------------------------------------------- - -instruct castX2P(rRegP dst, rRegL src) -%{ - match(Set dst (CastX2P src)); - - format %{ "movq $dst, $src\t# long->ptr" %} - ins_encode %{ - if ($dst$$reg != $src$$reg) { - __ movptr($dst$$Register, $src$$Register); - } - %} - ins_pipe(ialu_reg_reg); // XXX -%} - -instruct castP2X(rRegL dst, rRegP src) -%{ - match(Set dst (CastP2X src)); - - format %{ "movq $dst, $src\t# ptr -> long" %} - ins_encode %{ - if ($dst$$reg != $src$$reg) { - __ movptr($dst$$Register, $src$$Register); - } - %} - ins_pipe(ialu_reg_reg); // XXX -%} - -// Convert oop into int for vectors alignment masking -instruct convP2I(rRegI dst, rRegP src) -%{ - match(Set dst (ConvL2I (CastP2X src))); - - format %{ "movl $dst, $src\t# ptr -> int" %} - ins_encode %{ - __ movl($dst$$Register, $src$$Register); - %} - ins_pipe(ialu_reg_reg); // XXX -%} - -// Convert compressed oop into int for vectors alignment masking -// in case of 32bit oops (heap < 4Gb). -instruct convN2I(rRegI dst, rRegN src) -%{ - predicate(CompressedOops::shift() == 0); - match(Set dst (ConvL2I (CastP2X (DecodeN src)))); - - format %{ "movl $dst, $src\t# compressed ptr -> int" %} - ins_encode %{ - __ movl($dst$$Register, $src$$Register); - %} - ins_pipe(ialu_reg_reg); // XXX -%} - -// Convert oop pointer into compressed form -instruct encodeHeapOop(rRegN dst, rRegP src, rFlagsReg cr) %{ - predicate(n->bottom_type()->make_ptr()->ptr() != TypePtr::NotNull); - match(Set dst (EncodeP src)); - effect(KILL cr); - format %{ "encode_heap_oop $dst,$src" %} - ins_encode %{ - Register s = $src$$Register; - Register d = $dst$$Register; - if (s != d) { - __ movq(d, s); - } - __ encode_heap_oop(d); - %} - ins_pipe(ialu_reg_long); -%} - -instruct encodeHeapOop_not_null(rRegN dst, rRegP src, rFlagsReg cr) %{ - predicate(n->bottom_type()->make_ptr()->ptr() == TypePtr::NotNull); - match(Set dst (EncodeP src)); - effect(KILL cr); - format %{ "encode_heap_oop_not_null $dst,$src" %} - ins_encode %{ - __ encode_heap_oop_not_null($dst$$Register, $src$$Register); - %} - ins_pipe(ialu_reg_long); -%} - -instruct decodeHeapOop(rRegP dst, rRegN src, rFlagsReg cr) %{ - predicate(n->bottom_type()->is_ptr()->ptr() != TypePtr::NotNull && - n->bottom_type()->is_ptr()->ptr() != TypePtr::Constant); - match(Set dst (DecodeN src)); - effect(KILL cr); - format %{ "decode_heap_oop $dst,$src" %} - ins_encode %{ - Register s = $src$$Register; - Register d = $dst$$Register; - if (s != d) { - __ movq(d, s); - } - __ decode_heap_oop(d); - %} - ins_pipe(ialu_reg_long); -%} - -instruct decodeHeapOop_not_null(rRegP dst, rRegN src, rFlagsReg cr) %{ - predicate(n->bottom_type()->is_ptr()->ptr() == TypePtr::NotNull || - n->bottom_type()->is_ptr()->ptr() == TypePtr::Constant); - match(Set dst (DecodeN src)); - effect(KILL cr); - format %{ "decode_heap_oop_not_null $dst,$src" %} - ins_encode %{ - Register s = $src$$Register; - Register d = $dst$$Register; - if (s != d) { - __ decode_heap_oop_not_null(d, s); - } else { - __ decode_heap_oop_not_null(d); - } - %} - ins_pipe(ialu_reg_long); -%} - -instruct encodeKlass_not_null(rRegN dst, rRegP src, rFlagsReg cr) %{ - match(Set dst (EncodePKlass src)); - effect(TEMP dst, KILL cr); - format %{ "encode_and_move_klass_not_null $dst,$src" %} - ins_encode %{ - __ encode_and_move_klass_not_null($dst$$Register, $src$$Register); - %} - ins_pipe(ialu_reg_long); -%} - -instruct decodeKlass_not_null(rRegP dst, rRegN src, rFlagsReg cr) %{ - match(Set dst (DecodeNKlass src)); - effect(TEMP dst, KILL cr); - format %{ "decode_and_move_klass_not_null $dst,$src" %} - ins_encode %{ - __ decode_and_move_klass_not_null($dst$$Register, $src$$Register); - %} - ins_pipe(ialu_reg_long); -%} - -//----------Conditional Move--------------------------------------------------- -// Jump -// dummy instruction for generating temp registers -instruct jumpXtnd_offset(rRegL switch_val, immI2 shift, rRegI dest) %{ - match(Jump (LShiftL switch_val shift)); - ins_cost(350); - predicate(false); - effect(TEMP dest); - - format %{ "leaq $dest, [$constantaddress]\n\t" - "jmp [$dest + $switch_val << $shift]\n\t" %} - ins_encode %{ - // We could use jump(ArrayAddress) except that the macro assembler needs to use r10 - // to do that and the compiler is using that register as one it can allocate. - // So we build it all by hand. - // Address index(noreg, switch_reg, (Address::ScaleFactor)$shift$$constant); - // ArrayAddress dispatch(table, index); - Address dispatch($dest$$Register, $switch_val$$Register, (Address::ScaleFactor) $shift$$constant); - __ lea($dest$$Register, $constantaddress); - __ jmp(dispatch); - %} - ins_pipe(pipe_jmp); -%} - -instruct jumpXtnd_addr(rRegL switch_val, immI2 shift, immL32 offset, rRegI dest) %{ - match(Jump (AddL (LShiftL switch_val shift) offset)); - ins_cost(350); - effect(TEMP dest); - - format %{ "leaq $dest, [$constantaddress]\n\t" - "jmp [$dest + $switch_val << $shift + $offset]\n\t" %} - ins_encode %{ - // We could use jump(ArrayAddress) except that the macro assembler needs to use r10 - // to do that and the compiler is using that register as one it can allocate. - // So we build it all by hand. - // Address index(noreg, switch_reg, (Address::ScaleFactor) $shift$$constant, (int) $offset$$constant); - // ArrayAddress dispatch(table, index); - Address dispatch($dest$$Register, $switch_val$$Register, (Address::ScaleFactor) $shift$$constant, (int) $offset$$constant); - __ lea($dest$$Register, $constantaddress); - __ jmp(dispatch); - %} - ins_pipe(pipe_jmp); -%} - -instruct jumpXtnd(rRegL switch_val, rRegI dest) %{ - match(Jump switch_val); - ins_cost(350); - effect(TEMP dest); - - format %{ "leaq $dest, [$constantaddress]\n\t" - "jmp [$dest + $switch_val]\n\t" %} - ins_encode %{ - // We could use jump(ArrayAddress) except that the macro assembler needs to use r10 - // to do that and the compiler is using that register as one it can allocate. - // So we build it all by hand. - // Address index(noreg, switch_reg, Address::times_1); - // ArrayAddress dispatch(table, index); - Address dispatch($dest$$Register, $switch_val$$Register, Address::times_1); - __ lea($dest$$Register, $constantaddress); - __ jmp(dispatch); - %} - ins_pipe(pipe_jmp); -%} - -// Conditional move -instruct cmovI_imm_01(rRegI dst, immI_1 src, rFlagsReg cr, cmpOp cop) -%{ - predicate(n->in(2)->in(2)->is_Con() && n->in(2)->in(2)->get_int() == 0); - match(Set dst (CMoveI (Binary cop cr) (Binary src dst))); - - ins_cost(100); // XXX - format %{ "setbn$cop $dst\t# signed, int" %} - ins_encode %{ - Assembler::Condition cond = (Assembler::Condition)($cop$$cmpcode); - __ setb(MacroAssembler::negate_condition(cond), $dst$$Register); - %} - ins_pipe(ialu_reg); -%} - -instruct cmovI_reg(rRegI dst, rRegI src, rFlagsReg cr, cmpOp cop) -%{ - predicate(!UseAPX); - match(Set dst (CMoveI (Binary cop cr) (Binary dst src))); - - ins_cost(200); // XXX - format %{ "cmovl$cop $dst, $src\t# signed, int" %} - ins_encode %{ - __ cmovl((Assembler::Condition)($cop$$cmpcode), $dst$$Register, $src$$Register); - %} - ins_pipe(pipe_cmov_reg); -%} - -instruct cmovI_reg_ndd(rRegI dst, rRegI src1, rRegI src2, rFlagsReg cr, cmpOp cop) -%{ - predicate(UseAPX); - match(Set dst (CMoveI (Binary cop cr) (Binary src1 src2))); - - ins_cost(200); - format %{ "ecmovl$cop $dst, $src1, $src2\t# signed, int ndd" %} - ins_encode %{ - __ ecmovl((Assembler::Condition)($cop$$cmpcode), $dst$$Register, $src1$$Register, $src2$$Register); - %} - ins_pipe(pipe_cmov_reg); -%} - -instruct cmovI_imm_01U(rRegI dst, immI_1 src, rFlagsRegU cr, cmpOpU cop) -%{ - predicate(n->in(2)->in(2)->is_Con() && n->in(2)->in(2)->get_int() == 0); - match(Set dst (CMoveI (Binary cop cr) (Binary src dst))); - - ins_cost(100); // XXX - format %{ "setbn$cop $dst\t# unsigned, int" %} - ins_encode %{ - Assembler::Condition cond = (Assembler::Condition)($cop$$cmpcode); - __ setb(MacroAssembler::negate_condition(cond), $dst$$Register); - %} - ins_pipe(ialu_reg); -%} - -instruct cmovI_regU(cmpOpU cop, rFlagsRegU cr, rRegI dst, rRegI src) %{ - predicate(!UseAPX); - match(Set dst (CMoveI (Binary cop cr) (Binary dst src))); - - ins_cost(200); // XXX - format %{ "cmovl$cop $dst, $src\t# unsigned, int" %} - ins_encode %{ - __ cmovl((Assembler::Condition)($cop$$cmpcode), $dst$$Register, $src$$Register); - %} - ins_pipe(pipe_cmov_reg); -%} - -instruct cmovI_regU_ndd(rRegI dst, cmpOpU cop, rFlagsRegU cr, rRegI src1, rRegI src2) %{ - predicate(UseAPX); - match(Set dst (CMoveI (Binary cop cr) (Binary src1 src2))); - - ins_cost(200); - format %{ "ecmovl$cop $dst, $src1, $src2\t# unsigned, int ndd" %} - ins_encode %{ - __ ecmovl((Assembler::Condition)($cop$$cmpcode), $dst$$Register, $src1$$Register, $src2$$Register); - %} - ins_pipe(pipe_cmov_reg); -%} - -instruct cmovI_imm_01UCF(rRegI dst, immI_1 src, rFlagsRegUCF cr, cmpOpUCF cop) -%{ - predicate(n->in(2)->in(2)->is_Con() && n->in(2)->in(2)->get_int() == 0); - match(Set dst (CMoveI (Binary cop cr) (Binary src dst))); - - ins_cost(100); // XXX - format %{ "setbn$cop $dst\t# unsigned, int" %} - ins_encode %{ - Assembler::Condition cond = (Assembler::Condition)($cop$$cmpcode); - __ setb(MacroAssembler::negate_condition(cond), $dst$$Register); - %} - ins_pipe(ialu_reg); -%} - -instruct cmovI_regUCF(cmpOpUCF cop, rFlagsRegUCF cr, rRegI dst, rRegI src) %{ - predicate(!UseAPX); - match(Set dst (CMoveI (Binary cop cr) (Binary dst src))); - ins_cost(200); - expand %{ - cmovI_regU(cop, cr, dst, src); - %} -%} - -instruct cmovI_regUCF_ndd(rRegI dst, cmpOpUCF cop, rFlagsRegUCF cr, rRegI src1, rRegI src2) %{ - predicate(UseAPX); - match(Set dst (CMoveI (Binary cop cr) (Binary src1 src2))); - ins_cost(200); - format %{ "ecmovl$cop $dst, $src1, $src2\t# unsigned, int ndd" %} - ins_encode %{ - __ ecmovl((Assembler::Condition)($cop$$cmpcode), $dst$$Register, $src1$$Register, $src2$$Register); - %} - ins_pipe(pipe_cmov_reg); -%} - -instruct cmovI_regUCF2_ne(cmpOpUCF2 cop, rFlagsRegUCF cr, rRegI dst, rRegI src) %{ - predicate(!UseAPX && n->in(1)->in(1)->as_Bool()->_test._test == BoolTest::ne); - match(Set dst (CMoveI (Binary cop cr) (Binary dst src))); - - ins_cost(200); // XXX - format %{ "cmovpl $dst, $src\n\t" - "cmovnel $dst, $src" %} - ins_encode %{ - __ cmovl(Assembler::parity, $dst$$Register, $src$$Register); - __ cmovl(Assembler::notEqual, $dst$$Register, $src$$Register); - %} - ins_pipe(pipe_cmov_reg); -%} - -instruct cmovI_regUCF2_ne_ndd(cmpOpUCF2 cop, rFlagsRegUCF cr, rRegI dst, rRegI src1, rRegI src2) %{ - predicate(UseAPX && n->in(1)->in(1)->as_Bool()->_test._test == BoolTest::ne); - match(Set dst (CMoveI (Binary cop cr) (Binary src1 src2))); - effect(TEMP dst); - - ins_cost(200); - format %{ "ecmovpl $dst, $src1, $src2\n\t" - "cmovnel $dst, $src2" %} - ins_encode %{ - __ ecmovl(Assembler::parity, $dst$$Register, $src1$$Register, $src2$$Register); - __ cmovl(Assembler::notEqual, $dst$$Register, $src2$$Register); - %} - ins_pipe(pipe_cmov_reg); -%} - -// Since (x == y) == !(x != y), we can flip the sense of the test by flipping the -// inputs of the CMove -instruct cmovI_regUCF2_eq(cmpOpUCF2 cop, rFlagsRegUCF cr, rRegI dst, rRegI src) %{ - predicate(!UseAPX && n->in(1)->in(1)->as_Bool()->_test._test == BoolTest::eq); - match(Set dst (CMoveI (Binary cop cr) (Binary src dst))); - effect(TEMP dst); - - ins_cost(200); // XXX - format %{ "cmovpl $dst, $src\n\t" - "cmovnel $dst, $src" %} - ins_encode %{ - __ cmovl(Assembler::parity, $dst$$Register, $src$$Register); - __ cmovl(Assembler::notEqual, $dst$$Register, $src$$Register); - %} - ins_pipe(pipe_cmov_reg); -%} - -// We need this special handling for only eq / neq comparison since NaN == NaN is false, -// and parity flag bit is set if any of the operand is a NaN. -instruct cmovI_regUCF2_eq_ndd(cmpOpUCF2 cop, rFlagsRegUCF cr, rRegI dst, rRegI src1, rRegI src2) %{ - predicate(UseAPX && n->in(1)->in(1)->as_Bool()->_test._test == BoolTest::eq); - match(Set dst (CMoveI (Binary cop cr) (Binary src2 src1))); - effect(TEMP dst); - - ins_cost(200); - format %{ "ecmovpl $dst, $src1, $src2\n\t" - "cmovnel $dst, $src2" %} - ins_encode %{ - __ ecmovl(Assembler::parity, $dst$$Register, $src1$$Register, $src2$$Register); - __ cmovl(Assembler::notEqual, $dst$$Register, $src2$$Register); - %} - ins_pipe(pipe_cmov_reg); -%} - -// Conditional move -instruct cmovI_mem(cmpOp cop, rFlagsReg cr, rRegI dst, memory src) %{ - predicate(!UseAPX); - match(Set dst (CMoveI (Binary cop cr) (Binary dst (LoadI src)))); - - ins_cost(250); // XXX - format %{ "cmovl$cop $dst, $src\t# signed, int" %} - ins_encode %{ - __ cmovl((Assembler::Condition)($cop$$cmpcode), $dst$$Register, $src$$Address); - %} - ins_pipe(pipe_cmov_mem); -%} - -// Conditional move -instruct cmovI_rReg_rReg_mem_ndd(rRegI dst, cmpOp cop, rFlagsReg cr, rRegI src1, memory src2) -%{ - predicate(UseAPX); - match(Set dst (CMoveI (Binary cop cr) (Binary src1 (LoadI src2)))); - - ins_cost(250); - format %{ "ecmovl$cop $dst, $src1, $src2\t# signed, int ndd" %} - ins_encode %{ - __ ecmovl((Assembler::Condition)($cop$$cmpcode), $dst$$Register, $src1$$Register, $src2$$Address); - %} - ins_pipe(pipe_cmov_mem); -%} - -// Conditional move -instruct cmovI_memU(cmpOpU cop, rFlagsRegU cr, rRegI dst, memory src) -%{ - predicate(!UseAPX); - match(Set dst (CMoveI (Binary cop cr) (Binary dst (LoadI src)))); - - ins_cost(250); // XXX - format %{ "cmovl$cop $dst, $src\t# unsigned, int" %} - ins_encode %{ - __ cmovl((Assembler::Condition)($cop$$cmpcode), $dst$$Register, $src$$Address); - %} - ins_pipe(pipe_cmov_mem); -%} - -instruct cmovI_memUCF(cmpOpUCF cop, rFlagsRegUCF cr, rRegI dst, memory src) %{ - predicate(!UseAPX); - match(Set dst (CMoveI (Binary cop cr) (Binary dst (LoadI src)))); - ins_cost(250); - expand %{ - cmovI_memU(cop, cr, dst, src); - %} -%} - -instruct cmovI_rReg_rReg_memU_ndd(rRegI dst, cmpOpU cop, rFlagsRegU cr, rRegI src1, memory src2) -%{ - predicate(UseAPX); - match(Set dst (CMoveI (Binary cop cr) (Binary src1 (LoadI src2)))); - - ins_cost(250); - format %{ "ecmovl$cop $dst, $src1, $src2\t# unsigned, int ndd" %} - ins_encode %{ - __ ecmovl((Assembler::Condition)($cop$$cmpcode), $dst$$Register, $src1$$Register, $src2$$Address); - %} - ins_pipe(pipe_cmov_mem); -%} - -instruct cmovI_rReg_rReg_memUCF_ndd(rRegI dst, cmpOpUCF cop, rFlagsRegUCF cr, rRegI src1, memory src2) -%{ - predicate(UseAPX); - match(Set dst (CMoveI (Binary cop cr) (Binary src1 (LoadI src2)))); - ins_cost(250); - format %{ "ecmovl$cop $dst, $src1, $src2\t# unsigned, int ndd" %} - ins_encode %{ - __ ecmovl((Assembler::Condition)($cop$$cmpcode), $dst$$Register, $src1$$Register, $src2$$Address); - %} - ins_pipe(pipe_cmov_mem); -%} - -// Conditional move -instruct cmovN_reg(rRegN dst, rRegN src, rFlagsReg cr, cmpOp cop) -%{ - predicate(!UseAPX); - match(Set dst (CMoveN (Binary cop cr) (Binary dst src))); - - ins_cost(200); // XXX - format %{ "cmovl$cop $dst, $src\t# signed, compressed ptr" %} - ins_encode %{ - __ cmovl((Assembler::Condition)($cop$$cmpcode), $dst$$Register, $src$$Register); - %} - ins_pipe(pipe_cmov_reg); -%} - -// Conditional move ndd -instruct cmovN_reg_ndd(rRegN dst, rRegN src1, rRegN src2, rFlagsReg cr, cmpOp cop) -%{ - predicate(UseAPX); - match(Set dst (CMoveN (Binary cop cr) (Binary src1 src2))); - - ins_cost(200); - format %{ "ecmovl$cop $dst, $src1, $src2\t# signed, compressed ptr ndd" %} - ins_encode %{ - __ ecmovl((Assembler::Condition)($cop$$cmpcode), $dst$$Register, $src1$$Register, $src2$$Register); - %} - ins_pipe(pipe_cmov_reg); -%} - -// Conditional move -instruct cmovN_regU(cmpOpU cop, rFlagsRegU cr, rRegN dst, rRegN src) -%{ - predicate(!UseAPX); - match(Set dst (CMoveN (Binary cop cr) (Binary dst src))); - - ins_cost(200); // XXX - format %{ "cmovl$cop $dst, $src\t# unsigned, compressed ptr" %} - ins_encode %{ - __ cmovl((Assembler::Condition)($cop$$cmpcode), $dst$$Register, $src$$Register); - %} - ins_pipe(pipe_cmov_reg); -%} - -instruct cmovN_regUCF(cmpOpUCF cop, rFlagsRegUCF cr, rRegN dst, rRegN src) %{ - predicate(!UseAPX); - match(Set dst (CMoveN (Binary cop cr) (Binary dst src))); - ins_cost(200); - expand %{ - cmovN_regU(cop, cr, dst, src); - %} -%} - -// Conditional move ndd -instruct cmovN_regU_ndd(rRegN dst, cmpOpU cop, rFlagsRegU cr, rRegN src1, rRegN src2) -%{ - predicate(UseAPX); - match(Set dst (CMoveN (Binary cop cr) (Binary src1 src2))); - - ins_cost(200); - format %{ "ecmovl$cop $dst, $src1, $src2\t# unsigned, compressed ptr ndd" %} - ins_encode %{ - __ ecmovl((Assembler::Condition)($cop$$cmpcode), $dst$$Register, $src1$$Register, $src2$$Register); - %} - ins_pipe(pipe_cmov_reg); -%} - -instruct cmovN_regUCF_ndd(rRegN dst, cmpOpUCF cop, rFlagsRegUCF cr, rRegN src1, rRegN src2) %{ - predicate(UseAPX); - match(Set dst (CMoveN (Binary cop cr) (Binary src1 src2))); - ins_cost(200); - format %{ "ecmovl$cop $dst, $src1, $src2\t# unsigned, compressed ptr ndd" %} - ins_encode %{ - __ ecmovl((Assembler::Condition)($cop$$cmpcode), $dst$$Register, $src1$$Register, $src2$$Register); - %} - ins_pipe(pipe_cmov_reg); -%} - -instruct cmovN_regUCF2_ne(cmpOpUCF2 cop, rFlagsRegUCF cr, rRegN dst, rRegN src) %{ - predicate(n->in(1)->in(1)->as_Bool()->_test._test == BoolTest::ne); - match(Set dst (CMoveN (Binary cop cr) (Binary dst src))); - - ins_cost(200); // XXX - format %{ "cmovpl $dst, $src\n\t" - "cmovnel $dst, $src" %} - ins_encode %{ - __ cmovl(Assembler::parity, $dst$$Register, $src$$Register); - __ cmovl(Assembler::notEqual, $dst$$Register, $src$$Register); - %} - ins_pipe(pipe_cmov_reg); -%} - -// Since (x == y) == !(x != y), we can flip the sense of the test by flipping the -// inputs of the CMove -instruct cmovN_regUCF2_eq(cmpOpUCF2 cop, rFlagsRegUCF cr, rRegN dst, rRegN src) %{ - predicate(n->in(1)->in(1)->as_Bool()->_test._test == BoolTest::eq); - match(Set dst (CMoveN (Binary cop cr) (Binary src dst))); - - ins_cost(200); // XXX - format %{ "cmovpl $dst, $src\n\t" - "cmovnel $dst, $src" %} - ins_encode %{ - __ cmovl(Assembler::parity, $dst$$Register, $src$$Register); - __ cmovl(Assembler::notEqual, $dst$$Register, $src$$Register); - %} - ins_pipe(pipe_cmov_reg); -%} - -// Conditional move -instruct cmovP_reg(rRegP dst, rRegP src, rFlagsReg cr, cmpOp cop) -%{ - predicate(!UseAPX); - match(Set dst (CMoveP (Binary cop cr) (Binary dst src))); - - ins_cost(200); // XXX - format %{ "cmovq$cop $dst, $src\t# signed, ptr" %} - ins_encode %{ - __ cmovq((Assembler::Condition)($cop$$cmpcode), $dst$$Register, $src$$Register); - %} - ins_pipe(pipe_cmov_reg); // XXX -%} - -// Conditional move ndd -instruct cmovP_reg_ndd(rRegP dst, rRegP src1, rRegP src2, rFlagsReg cr, cmpOp cop) -%{ - predicate(UseAPX); - match(Set dst (CMoveP (Binary cop cr) (Binary src1 src2))); - - ins_cost(200); - format %{ "ecmovq$cop $dst, $src1, $src2\t# signed, ptr ndd" %} - ins_encode %{ - __ ecmovq((Assembler::Condition)($cop$$cmpcode), $dst$$Register, $src1$$Register, $src2$$Register); - %} - ins_pipe(pipe_cmov_reg); -%} - -// Conditional move -instruct cmovP_regU(cmpOpU cop, rFlagsRegU cr, rRegP dst, rRegP src) -%{ - predicate(!UseAPX); - match(Set dst (CMoveP (Binary cop cr) (Binary dst src))); - - ins_cost(200); // XXX - format %{ "cmovq$cop $dst, $src\t# unsigned, ptr" %} - ins_encode %{ - __ cmovq((Assembler::Condition)($cop$$cmpcode), $dst$$Register, $src$$Register); - %} - ins_pipe(pipe_cmov_reg); // XXX -%} - -// Conditional move ndd -instruct cmovP_regU_ndd(rRegP dst, cmpOpU cop, rFlagsRegU cr, rRegP src1, rRegP src2) -%{ - predicate(UseAPX); - match(Set dst (CMoveP (Binary cop cr) (Binary src1 src2))); - - ins_cost(200); - format %{ "ecmovq$cop $dst, $src1, $src2\t# unsigned, ptr ndd" %} - ins_encode %{ - __ ecmovq((Assembler::Condition)($cop$$cmpcode), $dst$$Register, $src1$$Register, $src2$$Register); - %} - ins_pipe(pipe_cmov_reg); -%} - -instruct cmovP_regUCF(cmpOpUCF cop, rFlagsRegUCF cr, rRegP dst, rRegP src) %{ - predicate(!UseAPX); - match(Set dst (CMoveP (Binary cop cr) (Binary dst src))); - ins_cost(200); - expand %{ - cmovP_regU(cop, cr, dst, src); - %} -%} - -instruct cmovP_regUCF_ndd(rRegP dst, cmpOpUCF cop, rFlagsRegUCF cr, rRegP src1, rRegP src2) %{ - predicate(UseAPX); - match(Set dst (CMoveP (Binary cop cr) (Binary src1 src2))); - ins_cost(200); - format %{ "ecmovq$cop $dst, $src1, $src2\t# unsigned, ptr ndd" %} - ins_encode %{ - __ ecmovq((Assembler::Condition)($cop$$cmpcode), $dst$$Register, $src1$$Register, $src2$$Register); - %} - ins_pipe(pipe_cmov_reg); -%} - -instruct cmovP_regUCF2_ne(cmpOpUCF2 cop, rFlagsRegUCF cr, rRegP dst, rRegP src) %{ - predicate(!UseAPX && n->in(1)->in(1)->as_Bool()->_test._test == BoolTest::ne); - match(Set dst (CMoveP (Binary cop cr) (Binary dst src))); - - ins_cost(200); // XXX - format %{ "cmovpq $dst, $src\n\t" - "cmovneq $dst, $src" %} - ins_encode %{ - __ cmovq(Assembler::parity, $dst$$Register, $src$$Register); - __ cmovq(Assembler::notEqual, $dst$$Register, $src$$Register); - %} - ins_pipe(pipe_cmov_reg); -%} - -instruct cmovP_regUCF2_ne_ndd(cmpOpUCF2 cop, rFlagsRegUCF cr, rRegP dst, rRegP src1, rRegP src2) %{ - predicate(UseAPX && n->in(1)->in(1)->as_Bool()->_test._test == BoolTest::ne); - match(Set dst (CMoveP (Binary cop cr) (Binary src1 src2))); - effect(TEMP dst); - - ins_cost(200); - format %{ "ecmovpq $dst, $src1, $src2\n\t" - "cmovneq $dst, $src2" %} - ins_encode %{ - __ ecmovq(Assembler::parity, $dst$$Register, $src1$$Register, $src2$$Register); - __ cmovq(Assembler::notEqual, $dst$$Register, $src2$$Register); - %} - ins_pipe(pipe_cmov_reg); -%} - -// Since (x == y) == !(x != y), we can flip the sense of the test by flipping the -// inputs of the CMove -instruct cmovP_regUCF2_eq(cmpOpUCF2 cop, rFlagsRegUCF cr, rRegP dst, rRegP src) %{ - predicate(!UseAPX && n->in(1)->in(1)->as_Bool()->_test._test == BoolTest::eq); - match(Set dst (CMoveP (Binary cop cr) (Binary src dst))); - - ins_cost(200); // XXX - format %{ "cmovpq $dst, $src\n\t" - "cmovneq $dst, $src" %} - ins_encode %{ - __ cmovq(Assembler::parity, $dst$$Register, $src$$Register); - __ cmovq(Assembler::notEqual, $dst$$Register, $src$$Register); - %} - ins_pipe(pipe_cmov_reg); -%} - -instruct cmovP_regUCF2_eq_ndd(cmpOpUCF2 cop, rFlagsRegUCF cr, rRegP dst, rRegP src1, rRegP src2) %{ - predicate(UseAPX && n->in(1)->in(1)->as_Bool()->_test._test == BoolTest::eq); - match(Set dst (CMoveP (Binary cop cr) (Binary src2 src1))); - effect(TEMP dst); - - ins_cost(200); - format %{ "ecmovpq $dst, $src1, $src2\n\t" - "cmovneq $dst, $src2" %} - ins_encode %{ - __ ecmovq(Assembler::parity, $dst$$Register, $src1$$Register, $src2$$Register); - __ cmovq(Assembler::notEqual, $dst$$Register, $src2$$Register); - %} - ins_pipe(pipe_cmov_reg); -%} - -instruct cmovL_imm_01(rRegL dst, immL1 src, rFlagsReg cr, cmpOp cop) -%{ - predicate(n->in(2)->in(2)->is_Con() && n->in(2)->in(2)->get_long() == 0); - match(Set dst (CMoveL (Binary cop cr) (Binary src dst))); - - ins_cost(100); // XXX - format %{ "setbn$cop $dst\t# signed, long" %} - ins_encode %{ - Assembler::Condition cond = (Assembler::Condition)($cop$$cmpcode); - __ setb(MacroAssembler::negate_condition(cond), $dst$$Register); - %} - ins_pipe(ialu_reg); -%} - -instruct cmovL_reg(cmpOp cop, rFlagsReg cr, rRegL dst, rRegL src) -%{ - predicate(!UseAPX); - match(Set dst (CMoveL (Binary cop cr) (Binary dst src))); - - ins_cost(200); // XXX - format %{ "cmovq$cop $dst, $src\t# signed, long" %} - ins_encode %{ - __ cmovq((Assembler::Condition)($cop$$cmpcode), $dst$$Register, $src$$Register); - %} - ins_pipe(pipe_cmov_reg); // XXX -%} - -instruct cmovL_reg_ndd(rRegL dst, cmpOp cop, rFlagsReg cr, rRegL src1, rRegL src2) -%{ - predicate(UseAPX); - match(Set dst (CMoveL (Binary cop cr) (Binary src1 src2))); - - ins_cost(200); - format %{ "ecmovq$cop $dst, $src1, $src2\t# signed, long ndd" %} - ins_encode %{ - __ ecmovq((Assembler::Condition)($cop$$cmpcode), $dst$$Register, $src1$$Register, $src2$$Register); - %} - ins_pipe(pipe_cmov_reg); -%} - -instruct cmovL_mem(cmpOp cop, rFlagsReg cr, rRegL dst, memory src) -%{ - predicate(!UseAPX); - match(Set dst (CMoveL (Binary cop cr) (Binary dst (LoadL src)))); - - ins_cost(200); // XXX - format %{ "cmovq$cop $dst, $src\t# signed, long" %} - ins_encode %{ - __ cmovq((Assembler::Condition)($cop$$cmpcode), $dst$$Register, $src$$Address); - %} - ins_pipe(pipe_cmov_mem); // XXX -%} - -instruct cmovL_rReg_rReg_mem_ndd(rRegL dst, cmpOp cop, rFlagsReg cr, rRegL src1, memory src2) -%{ - predicate(UseAPX); - match(Set dst (CMoveL (Binary cop cr) (Binary src1 (LoadL src2)))); - - ins_cost(200); - format %{ "ecmovq$cop $dst, $src1, $src2\t# signed, long ndd" %} - ins_encode %{ - __ ecmovq((Assembler::Condition)($cop$$cmpcode), $dst$$Register, $src1$$Register, $src2$$Address); - %} - ins_pipe(pipe_cmov_mem); -%} - -instruct cmovL_imm_01U(rRegL dst, immL1 src, rFlagsRegU cr, cmpOpU cop) -%{ - predicate(n->in(2)->in(2)->is_Con() && n->in(2)->in(2)->get_long() == 0); - match(Set dst (CMoveL (Binary cop cr) (Binary src dst))); - - ins_cost(100); // XXX - format %{ "setbn$cop $dst\t# unsigned, long" %} - ins_encode %{ - Assembler::Condition cond = (Assembler::Condition)($cop$$cmpcode); - __ setb(MacroAssembler::negate_condition(cond), $dst$$Register); - %} - ins_pipe(ialu_reg); -%} - -instruct cmovL_regU(cmpOpU cop, rFlagsRegU cr, rRegL dst, rRegL src) -%{ - predicate(!UseAPX); - match(Set dst (CMoveL (Binary cop cr) (Binary dst src))); - - ins_cost(200); // XXX - format %{ "cmovq$cop $dst, $src\t# unsigned, long" %} - ins_encode %{ - __ cmovq((Assembler::Condition)($cop$$cmpcode), $dst$$Register, $src$$Register); - %} - ins_pipe(pipe_cmov_reg); // XXX -%} - -instruct cmovL_regU_ndd(rRegL dst, cmpOpU cop, rFlagsRegU cr, rRegL src1, rRegL src2) -%{ - predicate(UseAPX); - match(Set dst (CMoveL (Binary cop cr) (Binary src1 src2))); - - ins_cost(200); - format %{ "ecmovq$cop $dst, $src1, $src2\t# unsigned, long ndd" %} - ins_encode %{ - __ ecmovq((Assembler::Condition)($cop$$cmpcode), $dst$$Register, $src1$$Register, $src2$$Register); - %} - ins_pipe(pipe_cmov_reg); -%} - -instruct cmovL_imm_01UCF(rRegL dst, immL1 src, rFlagsRegUCF cr, cmpOpUCF cop) -%{ - predicate(n->in(2)->in(2)->is_Con() && n->in(2)->in(2)->get_long() == 0); - match(Set dst (CMoveL (Binary cop cr) (Binary src dst))); - - ins_cost(100); // XXX - format %{ "setbn$cop $dst\t# unsigned, long" %} - ins_encode %{ - Assembler::Condition cond = (Assembler::Condition)($cop$$cmpcode); - __ setb(MacroAssembler::negate_condition(cond), $dst$$Register); - %} - ins_pipe(ialu_reg); -%} - -instruct cmovL_regUCF(cmpOpUCF cop, rFlagsRegUCF cr, rRegL dst, rRegL src) %{ - predicate(!UseAPX); - match(Set dst (CMoveL (Binary cop cr) (Binary dst src))); - ins_cost(200); - expand %{ - cmovL_regU(cop, cr, dst, src); - %} -%} - -instruct cmovL_regUCF_ndd(rRegL dst, cmpOpUCF cop, rFlagsRegUCF cr, rRegL src1, rRegL src2) -%{ - predicate(UseAPX); - match(Set dst (CMoveL (Binary cop cr) (Binary src1 src2))); - ins_cost(200); - format %{ "ecmovq$cop $dst, $src1, $src2\t# unsigned, long ndd" %} - ins_encode %{ - __ ecmovq((Assembler::Condition)($cop$$cmpcode), $dst$$Register, $src1$$Register, $src2$$Register); - %} - ins_pipe(pipe_cmov_reg); -%} - -instruct cmovL_regUCF2_ne(cmpOpUCF2 cop, rFlagsRegUCF cr, rRegL dst, rRegL src) %{ - predicate(!UseAPX && n->in(1)->in(1)->as_Bool()->_test._test == BoolTest::ne); - match(Set dst (CMoveL (Binary cop cr) (Binary dst src))); - - ins_cost(200); // XXX - format %{ "cmovpq $dst, $src\n\t" - "cmovneq $dst, $src" %} - ins_encode %{ - __ cmovq(Assembler::parity, $dst$$Register, $src$$Register); - __ cmovq(Assembler::notEqual, $dst$$Register, $src$$Register); - %} - ins_pipe(pipe_cmov_reg); -%} - -instruct cmovL_regUCF2_ne_ndd(cmpOpUCF2 cop, rFlagsRegUCF cr, rRegL dst, rRegL src1, rRegL src2) %{ - predicate(UseAPX && n->in(1)->in(1)->as_Bool()->_test._test == BoolTest::ne); - match(Set dst (CMoveL (Binary cop cr) (Binary src1 src2))); - effect(TEMP dst); - - ins_cost(200); - format %{ "ecmovpq $dst, $src1, $src2\n\t" - "cmovneq $dst, $src2" %} - ins_encode %{ - __ ecmovq(Assembler::parity, $dst$$Register, $src1$$Register, $src2$$Register); - __ cmovq(Assembler::notEqual, $dst$$Register, $src2$$Register); - %} - ins_pipe(pipe_cmov_reg); -%} - -// Since (x == y) == !(x != y), we can flip the sense of the test by flipping the -// inputs of the CMove -instruct cmovL_regUCF2_eq(cmpOpUCF2 cop, rFlagsRegUCF cr, rRegL dst, rRegL src) %{ - predicate(!UseAPX && n->in(1)->in(1)->as_Bool()->_test._test == BoolTest::eq); - match(Set dst (CMoveL (Binary cop cr) (Binary src dst))); - - ins_cost(200); // XXX - format %{ "cmovpq $dst, $src\n\t" - "cmovneq $dst, $src" %} - ins_encode %{ - __ cmovq(Assembler::parity, $dst$$Register, $src$$Register); - __ cmovq(Assembler::notEqual, $dst$$Register, $src$$Register); - %} - ins_pipe(pipe_cmov_reg); -%} - -instruct cmovL_regUCF2_eq_ndd(cmpOpUCF2 cop, rFlagsRegUCF cr, rRegL dst, rRegL src1, rRegL src2) %{ - predicate(UseAPX && n->in(1)->in(1)->as_Bool()->_test._test == BoolTest::eq); - match(Set dst (CMoveL (Binary cop cr) (Binary src2 src1))); - effect(TEMP dst); - - ins_cost(200); - format %{ "ecmovpq $dst, $src1, $src2\n\t" - "cmovneq $dst, $src2" %} - ins_encode %{ - __ ecmovq(Assembler::parity, $dst$$Register, $src1$$Register, $src2$$Register); - __ cmovq(Assembler::notEqual, $dst$$Register, $src2$$Register); - %} - ins_pipe(pipe_cmov_reg); -%} - -instruct cmovL_memU(cmpOpU cop, rFlagsRegU cr, rRegL dst, memory src) -%{ - predicate(!UseAPX); - match(Set dst (CMoveL (Binary cop cr) (Binary dst (LoadL src)))); - - ins_cost(200); // XXX - format %{ "cmovq$cop $dst, $src\t# unsigned, long" %} - ins_encode %{ - __ cmovq((Assembler::Condition)($cop$$cmpcode), $dst$$Register, $src$$Address); - %} - ins_pipe(pipe_cmov_mem); // XXX -%} - -instruct cmovL_memUCF(cmpOpUCF cop, rFlagsRegUCF cr, rRegL dst, memory src) %{ - predicate(!UseAPX); - match(Set dst (CMoveL (Binary cop cr) (Binary dst (LoadL src)))); - ins_cost(200); - expand %{ - cmovL_memU(cop, cr, dst, src); - %} -%} - -instruct cmovL_rReg_rReg_memU_ndd(rRegL dst, cmpOpU cop, rFlagsRegU cr, rRegL src1, memory src2) -%{ - predicate(UseAPX); - match(Set dst (CMoveL (Binary cop cr) (Binary src1 (LoadL src2)))); - - ins_cost(200); - format %{ "ecmovq$cop $dst, $src1, $src2\t# unsigned, long ndd" %} - ins_encode %{ - __ ecmovq((Assembler::Condition)($cop$$cmpcode), $dst$$Register, $src1$$Register, $src2$$Address); - %} - ins_pipe(pipe_cmov_mem); -%} - -instruct cmovL_rReg_rReg_memUCF_ndd(rRegL dst, cmpOpUCF cop, rFlagsRegUCF cr, rRegL src1, memory src2) -%{ - predicate(UseAPX); - match(Set dst (CMoveL (Binary cop cr) (Binary src1 (LoadL src2)))); - ins_cost(200); - format %{ "ecmovq$cop $dst, $src1, $src2\t# unsigned, long ndd" %} - ins_encode %{ - __ ecmovq((Assembler::Condition)($cop$$cmpcode), $dst$$Register, $src1$$Register, $src2$$Address); - %} - ins_pipe(pipe_cmov_mem); -%} - -instruct cmovF_reg(cmpOp cop, rFlagsReg cr, regF dst, regF src) -%{ - match(Set dst (CMoveF (Binary cop cr) (Binary dst src))); - - ins_cost(200); // XXX - format %{ "jn$cop skip\t# signed cmove float\n\t" - "movss $dst, $src\n" - "skip:" %} - ins_encode %{ - Label Lskip; - // Invert sense of branch from sense of CMOV - __ jccb((Assembler::Condition)($cop$$cmpcode^1), Lskip); - __ movflt($dst$$XMMRegister, $src$$XMMRegister); - __ bind(Lskip); - %} - ins_pipe(pipe_slow); -%} - -instruct cmovF_regU(cmpOpU cop, rFlagsRegU cr, regF dst, regF src) -%{ - match(Set dst (CMoveF (Binary cop cr) (Binary dst src))); - - ins_cost(200); // XXX - format %{ "jn$cop skip\t# unsigned cmove float\n\t" - "movss $dst, $src\n" - "skip:" %} - ins_encode %{ - Label Lskip; - // Invert sense of branch from sense of CMOV - __ jccb((Assembler::Condition)($cop$$cmpcode^1), Lskip); - __ movflt($dst$$XMMRegister, $src$$XMMRegister); - __ bind(Lskip); - %} - ins_pipe(pipe_slow); -%} - -instruct cmovF_regUCF(cmpOpUCF cop, rFlagsRegUCF cr, regF dst, regF src) %{ - match(Set dst (CMoveF (Binary cop cr) (Binary dst src))); - ins_cost(200); - expand %{ - cmovF_regU(cop, cr, dst, src); - %} -%} - -instruct cmovD_reg(cmpOp cop, rFlagsReg cr, regD dst, regD src) -%{ - match(Set dst (CMoveD (Binary cop cr) (Binary dst src))); - - ins_cost(200); // XXX - format %{ "jn$cop skip\t# signed cmove double\n\t" - "movsd $dst, $src\n" - "skip:" %} - ins_encode %{ - Label Lskip; - // Invert sense of branch from sense of CMOV - __ jccb((Assembler::Condition)($cop$$cmpcode^1), Lskip); - __ movdbl($dst$$XMMRegister, $src$$XMMRegister); - __ bind(Lskip); - %} - ins_pipe(pipe_slow); -%} - -instruct cmovD_regU(cmpOpU cop, rFlagsRegU cr, regD dst, regD src) -%{ - match(Set dst (CMoveD (Binary cop cr) (Binary dst src))); - - ins_cost(200); // XXX - format %{ "jn$cop skip\t# unsigned cmove double\n\t" - "movsd $dst, $src\n" - "skip:" %} - ins_encode %{ - Label Lskip; - // Invert sense of branch from sense of CMOV - __ jccb((Assembler::Condition)($cop$$cmpcode^1), Lskip); - __ movdbl($dst$$XMMRegister, $src$$XMMRegister); - __ bind(Lskip); - %} - ins_pipe(pipe_slow); -%} - -instruct cmovD_regUCF(cmpOpUCF cop, rFlagsRegUCF cr, regD dst, regD src) %{ - match(Set dst (CMoveD (Binary cop cr) (Binary dst src))); - ins_cost(200); - expand %{ - cmovD_regU(cop, cr, dst, src); - %} -%} - -//----------Arithmetic Instructions-------------------------------------------- -//----------Addition Instructions---------------------------------------------- - -instruct addI_rReg(rRegI dst, rRegI src, rFlagsReg cr) -%{ - predicate(!UseAPX); - match(Set dst (AddI dst src)); - effect(KILL cr); - flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); - format %{ "addl $dst, $src\t# int" %} - ins_encode %{ - __ addl($dst$$Register, $src$$Register); - %} - ins_pipe(ialu_reg_reg); -%} - -instruct addI_rReg_ndd(rRegI dst, rRegI src1, rRegI src2, rFlagsReg cr) -%{ - predicate(UseAPX); - match(Set dst (AddI src1 src2)); - effect(KILL cr); - flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); - - format %{ "eaddl $dst, $src1, $src2\t# int ndd" %} - ins_encode %{ - __ eaddl($dst$$Register, $src1$$Register, $src2$$Register, false); - %} - ins_pipe(ialu_reg_reg); -%} - -instruct addI_rReg_imm(rRegI dst, immI src, rFlagsReg cr) -%{ - predicate(!UseAPX); - match(Set dst (AddI dst src)); - effect(KILL cr); - flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); - - format %{ "addl $dst, $src\t# int" %} - ins_encode %{ - __ addl($dst$$Register, $src$$constant); - %} - ins_pipe( ialu_reg ); -%} - -instruct addI_rReg_rReg_imm_ndd(rRegI dst, rRegI src1, immI src2, rFlagsReg cr) -%{ - predicate(UseAPX); - match(Set dst (AddI src1 src2)); - effect(KILL cr); - flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); - - format %{ "eaddl $dst, $src1, $src2\t# int ndd" %} - ins_encode %{ - __ eaddl($dst$$Register, $src1$$Register, $src2$$constant, false); - %} - ins_pipe( ialu_reg ); -%} - -instruct addI_rReg_mem_imm_ndd(rRegI dst, memory src1, immI src2, rFlagsReg cr) -%{ - predicate(UseAPX); - match(Set dst (AddI (LoadI src1) src2)); - effect(KILL cr); - flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); - - format %{ "eaddl $dst, $src1, $src2\t# int ndd" %} - ins_encode %{ - __ eaddl($dst$$Register, $src1$$Address, $src2$$constant, false); - %} - ins_pipe( ialu_reg ); -%} - -instruct addI_rReg_mem(rRegI dst, memory src, rFlagsReg cr) -%{ - predicate(!UseAPX); - match(Set dst (AddI dst (LoadI src))); - effect(KILL cr); - flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); - - ins_cost(150); // XXX - format %{ "addl $dst, $src\t# int" %} - ins_encode %{ - __ addl($dst$$Register, $src$$Address); - %} - ins_pipe(ialu_reg_mem); -%} - -instruct addI_rReg_rReg_mem_ndd(rRegI dst, rRegI src1, memory src2, rFlagsReg cr) -%{ - predicate(UseAPX); - match(Set dst (AddI src1 (LoadI src2))); - effect(KILL cr); - flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); - - ins_cost(150); - format %{ "eaddl $dst, $src1, $src2\t# int ndd" %} - ins_encode %{ - __ eaddl($dst$$Register, $src1$$Register, $src2$$Address, false); - %} - ins_pipe(ialu_reg_mem); -%} - -instruct addI_mem_rReg(memory dst, rRegI src, rFlagsReg cr) -%{ - match(Set dst (StoreI dst (AddI (LoadI dst) src))); - effect(KILL cr); - flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); - - ins_cost(150); // XXX - format %{ "addl $dst, $src\t# int" %} - ins_encode %{ - __ addl($dst$$Address, $src$$Register); - %} - ins_pipe(ialu_mem_reg); -%} - -instruct addI_mem_imm(memory dst, immI src, rFlagsReg cr) -%{ - match(Set dst (StoreI dst (AddI (LoadI dst) src))); - effect(KILL cr); - flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); - - - ins_cost(125); // XXX - format %{ "addl $dst, $src\t# int" %} - ins_encode %{ - __ addl($dst$$Address, $src$$constant); - %} - ins_pipe(ialu_mem_imm); -%} - -instruct incI_rReg(rRegI dst, immI_1 src, rFlagsReg cr) -%{ - predicate(!UseAPX && UseIncDec); - match(Set dst (AddI dst src)); - effect(KILL cr); - - format %{ "incl $dst\t# int" %} - ins_encode %{ - __ incrementl($dst$$Register); - %} - ins_pipe(ialu_reg); -%} - -instruct incI_rReg_ndd(rRegI dst, rRegI src, immI_1 val, rFlagsReg cr) -%{ - predicate(UseAPX && UseIncDec); - match(Set dst (AddI src val)); - effect(KILL cr); - - format %{ "eincl $dst, $src\t# int ndd" %} - ins_encode %{ - __ eincl($dst$$Register, $src$$Register, false); - %} - ins_pipe(ialu_reg); -%} - -instruct incI_rReg_mem_ndd(rRegI dst, memory src, immI_1 val, rFlagsReg cr) -%{ - predicate(UseAPX && UseIncDec); - match(Set dst (AddI (LoadI src) val)); - effect(KILL cr); - - format %{ "eincl $dst, $src\t# int ndd" %} - ins_encode %{ - __ eincl($dst$$Register, $src$$Address, false); - %} - ins_pipe(ialu_reg); -%} - -instruct incI_mem(memory dst, immI_1 src, rFlagsReg cr) -%{ - predicate(UseIncDec); - match(Set dst (StoreI dst (AddI (LoadI dst) src))); - effect(KILL cr); - - ins_cost(125); // XXX - format %{ "incl $dst\t# int" %} - ins_encode %{ - __ incrementl($dst$$Address); - %} - ins_pipe(ialu_mem_imm); -%} - -// XXX why does that use AddI -instruct decI_rReg(rRegI dst, immI_M1 src, rFlagsReg cr) -%{ - predicate(!UseAPX && UseIncDec); - match(Set dst (AddI dst src)); - effect(KILL cr); - - format %{ "decl $dst\t# int" %} - ins_encode %{ - __ decrementl($dst$$Register); - %} - ins_pipe(ialu_reg); -%} - -instruct decI_rReg_ndd(rRegI dst, rRegI src, immI_M1 val, rFlagsReg cr) -%{ - predicate(UseAPX && UseIncDec); - match(Set dst (AddI src val)); - effect(KILL cr); - - format %{ "edecl $dst, $src\t# int ndd" %} - ins_encode %{ - __ edecl($dst$$Register, $src$$Register, false); - %} - ins_pipe(ialu_reg); -%} - -instruct decI_rReg_mem_ndd(rRegI dst, memory src, immI_M1 val, rFlagsReg cr) -%{ - predicate(UseAPX && UseIncDec); - match(Set dst (AddI (LoadI src) val)); - effect(KILL cr); - - format %{ "edecl $dst, $src\t# int ndd" %} - ins_encode %{ - __ edecl($dst$$Register, $src$$Address, false); - %} - ins_pipe(ialu_reg); -%} - -// XXX why does that use AddI -instruct decI_mem(memory dst, immI_M1 src, rFlagsReg cr) -%{ - predicate(UseIncDec); - match(Set dst (StoreI dst (AddI (LoadI dst) src))); - effect(KILL cr); - - ins_cost(125); // XXX - format %{ "decl $dst\t# int" %} - ins_encode %{ - __ decrementl($dst$$Address); - %} - ins_pipe(ialu_mem_imm); -%} - -instruct leaI_rReg_immI2_immI(rRegI dst, rRegI index, immI2 scale, immI disp) -%{ - predicate(VM_Version::supports_fast_2op_lea()); - match(Set dst (AddI (LShiftI index scale) disp)); - - format %{ "leal $dst, [$index << $scale + $disp]\t# int" %} - ins_encode %{ - Address::ScaleFactor scale = static_cast($scale$$constant); - __ leal($dst$$Register, Address(noreg, $index$$Register, scale, $disp$$constant)); - %} - ins_pipe(ialu_reg_reg); -%} - -instruct leaI_rReg_rReg_immI(rRegI dst, rRegI base, rRegI index, immI disp) -%{ - predicate(VM_Version::supports_fast_3op_lea()); - match(Set dst (AddI (AddI base index) disp)); - - format %{ "leal $dst, [$base + $index + $disp]\t# int" %} - ins_encode %{ - __ leal($dst$$Register, Address($base$$Register, $index$$Register, Address::times_1, $disp$$constant)); - %} - ins_pipe(ialu_reg_reg); -%} - -instruct leaI_rReg_rReg_immI2(rRegI dst, no_rbp_r13_RegI base, rRegI index, immI2 scale) -%{ - predicate(VM_Version::supports_fast_2op_lea()); - match(Set dst (AddI base (LShiftI index scale))); - - format %{ "leal $dst, [$base + $index << $scale]\t# int" %} - ins_encode %{ - Address::ScaleFactor scale = static_cast($scale$$constant); - __ leal($dst$$Register, Address($base$$Register, $index$$Register, scale)); - %} - ins_pipe(ialu_reg_reg); -%} - -instruct leaI_rReg_rReg_immI2_immI(rRegI dst, rRegI base, rRegI index, immI2 scale, immI disp) -%{ - predicate(VM_Version::supports_fast_3op_lea()); - match(Set dst (AddI (AddI base (LShiftI index scale)) disp)); - - format %{ "leal $dst, [$base + $index << $scale + $disp]\t# int" %} - ins_encode %{ - Address::ScaleFactor scale = static_cast($scale$$constant); - __ leal($dst$$Register, Address($base$$Register, $index$$Register, scale, $disp$$constant)); - %} - ins_pipe(ialu_reg_reg); -%} - -instruct addL_rReg(rRegL dst, rRegL src, rFlagsReg cr) -%{ - predicate(!UseAPX); - match(Set dst (AddL dst src)); - effect(KILL cr); - flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); - - format %{ "addq $dst, $src\t# long" %} - ins_encode %{ - __ addq($dst$$Register, $src$$Register); - %} - ins_pipe(ialu_reg_reg); -%} - -instruct addL_rReg_ndd(rRegL dst, rRegL src1, rRegL src2, rFlagsReg cr) -%{ - predicate(UseAPX); - match(Set dst (AddL src1 src2)); - effect(KILL cr); - flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); - - format %{ "eaddq $dst, $src1, $src2\t# long ndd" %} - ins_encode %{ - __ eaddq($dst$$Register, $src1$$Register, $src2$$Register, false); - %} - ins_pipe(ialu_reg_reg); -%} - -instruct addL_rReg_imm(rRegL dst, immL32 src, rFlagsReg cr) -%{ - predicate(!UseAPX); - match(Set dst (AddL dst src)); - effect(KILL cr); - flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); - - format %{ "addq $dst, $src\t# long" %} - ins_encode %{ - __ addq($dst$$Register, $src$$constant); - %} - ins_pipe( ialu_reg ); -%} - -instruct addL_rReg_rReg_imm_ndd(rRegL dst, rRegL src1, immL32 src2, rFlagsReg cr) -%{ - predicate(UseAPX); - match(Set dst (AddL src1 src2)); - effect(KILL cr); - flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); - - format %{ "eaddq $dst, $src1, $src2\t# long ndd" %} - ins_encode %{ - __ eaddq($dst$$Register, $src1$$Register, $src2$$constant, false); - %} - ins_pipe( ialu_reg ); -%} - -instruct addL_rReg_mem_imm_ndd(rRegL dst, memory src1, immL32 src2, rFlagsReg cr) -%{ - predicate(UseAPX); - match(Set dst (AddL (LoadL src1) src2)); - effect(KILL cr); - flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); - - format %{ "eaddq $dst, $src1, $src2\t# long ndd" %} - ins_encode %{ - __ eaddq($dst$$Register, $src1$$Address, $src2$$constant, false); - %} - ins_pipe( ialu_reg ); -%} - -instruct addL_rReg_mem(rRegL dst, memory src, rFlagsReg cr) -%{ - predicate(!UseAPX); - match(Set dst (AddL dst (LoadL src))); - effect(KILL cr); - flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); - - ins_cost(150); // XXX - format %{ "addq $dst, $src\t# long" %} - ins_encode %{ - __ addq($dst$$Register, $src$$Address); - %} - ins_pipe(ialu_reg_mem); -%} - -instruct addL_rReg_rReg_mem_ndd(rRegL dst, rRegL src1, memory src2, rFlagsReg cr) -%{ - predicate(UseAPX); - match(Set dst (AddL src1 (LoadL src2))); - effect(KILL cr); - flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); - - ins_cost(150); - format %{ "eaddq $dst, $src1, $src2\t# long ndd" %} - ins_encode %{ - __ eaddq($dst$$Register, $src1$$Register, $src2$$Address, false); - %} - ins_pipe(ialu_reg_mem); -%} - -instruct addL_mem_rReg(memory dst, rRegL src, rFlagsReg cr) -%{ - match(Set dst (StoreL dst (AddL (LoadL dst) src))); - effect(KILL cr); - flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); - - ins_cost(150); // XXX - format %{ "addq $dst, $src\t# long" %} - ins_encode %{ - __ addq($dst$$Address, $src$$Register); - %} - ins_pipe(ialu_mem_reg); -%} - -instruct addL_mem_imm(memory dst, immL32 src, rFlagsReg cr) -%{ - match(Set dst (StoreL dst (AddL (LoadL dst) src))); - effect(KILL cr); - flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); - - ins_cost(125); // XXX - format %{ "addq $dst, $src\t# long" %} - ins_encode %{ - __ addq($dst$$Address, $src$$constant); - %} - ins_pipe(ialu_mem_imm); -%} - -instruct incL_rReg(rRegL dst, immL1 src, rFlagsReg cr) -%{ - predicate(!UseAPX && UseIncDec); - match(Set dst (AddL dst src)); - effect(KILL cr); - - format %{ "incq $dst\t# long" %} - ins_encode %{ - __ incrementq($dst$$Register); - %} - ins_pipe(ialu_reg); -%} - -instruct incL_rReg_ndd(rRegL dst, rRegI src, immL1 val, rFlagsReg cr) -%{ - predicate(UseAPX && UseIncDec); - match(Set dst (AddL src val)); - effect(KILL cr); - - format %{ "eincq $dst, $src\t# long ndd" %} - ins_encode %{ - __ eincq($dst$$Register, $src$$Register, false); - %} - ins_pipe(ialu_reg); -%} - -instruct incL_rReg_mem_ndd(rRegL dst, memory src, immL1 val, rFlagsReg cr) -%{ - predicate(UseAPX && UseIncDec); - match(Set dst (AddL (LoadL src) val)); - effect(KILL cr); - - format %{ "eincq $dst, $src\t# long ndd" %} - ins_encode %{ - __ eincq($dst$$Register, $src$$Address, false); - %} - ins_pipe(ialu_reg); -%} - -instruct incL_mem(memory dst, immL1 src, rFlagsReg cr) -%{ - predicate(UseIncDec); - match(Set dst (StoreL dst (AddL (LoadL dst) src))); - effect(KILL cr); - - ins_cost(125); // XXX - format %{ "incq $dst\t# long" %} - ins_encode %{ - __ incrementq($dst$$Address); - %} - ins_pipe(ialu_mem_imm); -%} - -// XXX why does that use AddL -instruct decL_rReg(rRegL dst, immL_M1 src, rFlagsReg cr) -%{ - predicate(!UseAPX && UseIncDec); - match(Set dst (AddL dst src)); - effect(KILL cr); - - format %{ "decq $dst\t# long" %} - ins_encode %{ - __ decrementq($dst$$Register); - %} - ins_pipe(ialu_reg); -%} - -instruct decL_rReg_ndd(rRegL dst, rRegL src, immL_M1 val, rFlagsReg cr) -%{ - predicate(UseAPX && UseIncDec); - match(Set dst (AddL src val)); - effect(KILL cr); - - format %{ "edecq $dst, $src\t# long ndd" %} - ins_encode %{ - __ edecq($dst$$Register, $src$$Register, false); - %} - ins_pipe(ialu_reg); -%} - -instruct decL_rReg_mem_ndd(rRegL dst, memory src, immL_M1 val, rFlagsReg cr) -%{ - predicate(UseAPX && UseIncDec); - match(Set dst (AddL (LoadL src) val)); - effect(KILL cr); - - format %{ "edecq $dst, $src\t# long ndd" %} - ins_encode %{ - __ edecq($dst$$Register, $src$$Address, false); - %} - ins_pipe(ialu_reg); -%} - -// XXX why does that use AddL -instruct decL_mem(memory dst, immL_M1 src, rFlagsReg cr) -%{ - predicate(UseIncDec); - match(Set dst (StoreL dst (AddL (LoadL dst) src))); - effect(KILL cr); - - ins_cost(125); // XXX - format %{ "decq $dst\t# long" %} - ins_encode %{ - __ decrementq($dst$$Address); - %} - ins_pipe(ialu_mem_imm); -%} - -instruct leaL_rReg_immI2_immL32(rRegL dst, rRegL index, immI2 scale, immL32 disp) -%{ - predicate(VM_Version::supports_fast_2op_lea()); - match(Set dst (AddL (LShiftL index scale) disp)); - - format %{ "leaq $dst, [$index << $scale + $disp]\t# long" %} - ins_encode %{ - Address::ScaleFactor scale = static_cast($scale$$constant); - __ leaq($dst$$Register, Address(noreg, $index$$Register, scale, $disp$$constant)); - %} - ins_pipe(ialu_reg_reg); -%} - -instruct leaL_rReg_rReg_immL32(rRegL dst, rRegL base, rRegL index, immL32 disp) -%{ - predicate(VM_Version::supports_fast_3op_lea()); - match(Set dst (AddL (AddL base index) disp)); - - format %{ "leaq $dst, [$base + $index + $disp]\t# long" %} - ins_encode %{ - __ leaq($dst$$Register, Address($base$$Register, $index$$Register, Address::times_1, $disp$$constant)); - %} - ins_pipe(ialu_reg_reg); -%} - -instruct leaL_rReg_rReg_immI2(rRegL dst, no_rbp_r13_RegL base, rRegL index, immI2 scale) -%{ - predicate(VM_Version::supports_fast_2op_lea()); - match(Set dst (AddL base (LShiftL index scale))); - - format %{ "leaq $dst, [$base + $index << $scale]\t# long" %} - ins_encode %{ - Address::ScaleFactor scale = static_cast($scale$$constant); - __ leaq($dst$$Register, Address($base$$Register, $index$$Register, scale)); - %} - ins_pipe(ialu_reg_reg); -%} - -instruct leaL_rReg_rReg_immI2_immL32(rRegL dst, rRegL base, rRegL index, immI2 scale, immL32 disp) -%{ - predicate(VM_Version::supports_fast_3op_lea()); - match(Set dst (AddL (AddL base (LShiftL index scale)) disp)); - - format %{ "leaq $dst, [$base + $index << $scale + $disp]\t# long" %} - ins_encode %{ - Address::ScaleFactor scale = static_cast($scale$$constant); - __ leaq($dst$$Register, Address($base$$Register, $index$$Register, scale, $disp$$constant)); - %} - ins_pipe(ialu_reg_reg); -%} - -instruct addP_rReg(rRegP dst, rRegL src, rFlagsReg cr) -%{ - match(Set dst (AddP dst src)); - effect(KILL cr); - flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); - - format %{ "addq $dst, $src\t# ptr" %} - ins_encode %{ - __ addq($dst$$Register, $src$$Register); - %} - ins_pipe(ialu_reg_reg); -%} - -instruct addP_rReg_imm(rRegP dst, immL32 src, rFlagsReg cr) -%{ - match(Set dst (AddP dst src)); - effect(KILL cr); - flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); - - format %{ "addq $dst, $src\t# ptr" %} - ins_encode %{ - __ addq($dst$$Register, $src$$constant); - %} - ins_pipe( ialu_reg ); -%} - -// XXX addP mem ops ???? - -instruct checkCastPP(rRegP dst) -%{ - match(Set dst (CheckCastPP dst)); - - size(0); - format %{ "# checkcastPP of $dst" %} - ins_encode(/* empty encoding */); - ins_pipe(empty); -%} - -instruct castPP(rRegP dst) -%{ - match(Set dst (CastPP dst)); - - size(0); - format %{ "# castPP of $dst" %} - ins_encode(/* empty encoding */); - ins_pipe(empty); -%} - -instruct castII(rRegI dst) -%{ - predicate(VerifyConstraintCasts == 0); - match(Set dst (CastII dst)); - - size(0); - format %{ "# castII of $dst" %} - ins_encode(/* empty encoding */); - ins_cost(0); - ins_pipe(empty); -%} - -instruct castII_checked(rRegI dst, rFlagsReg cr) -%{ - predicate(VerifyConstraintCasts > 0); - match(Set dst (CastII dst)); - - effect(KILL cr); - format %{ "# cast_checked_II $dst" %} - ins_encode %{ - __ verify_int_in_range(_idx, bottom_type()->is_int(), $dst$$Register); - %} - ins_pipe(pipe_slow); -%} - -instruct castLL(rRegL dst) -%{ - predicate(VerifyConstraintCasts == 0); - match(Set dst (CastLL dst)); - - size(0); - format %{ "# castLL of $dst" %} - ins_encode(/* empty encoding */); - ins_cost(0); - ins_pipe(empty); -%} - -instruct castLL_checked_L32(rRegL dst, rFlagsReg cr) -%{ - predicate(VerifyConstraintCasts > 0 && castLL_is_imm32(n)); - match(Set dst (CastLL dst)); - - effect(KILL cr); - format %{ "# cast_checked_LL $dst" %} - ins_encode %{ - __ verify_long_in_range(_idx, bottom_type()->is_long(), $dst$$Register, noreg); - %} - ins_pipe(pipe_slow); -%} - -instruct castLL_checked(rRegL dst, rRegL tmp, rFlagsReg cr) -%{ - predicate(VerifyConstraintCasts > 0 && !castLL_is_imm32(n)); - match(Set dst (CastLL dst)); - - effect(KILL cr, TEMP tmp); - format %{ "# cast_checked_LL $dst\tusing $tmp as TEMP" %} - ins_encode %{ - __ verify_long_in_range(_idx, bottom_type()->is_long(), $dst$$Register, $tmp$$Register); - %} - ins_pipe(pipe_slow); -%} - -instruct castFF(regF dst) -%{ - match(Set dst (CastFF dst)); - - size(0); - format %{ "# castFF of $dst" %} - ins_encode(/* empty encoding */); - ins_cost(0); - ins_pipe(empty); -%} - -instruct castHH(regF dst) -%{ - match(Set dst (CastHH dst)); - - size(0); - format %{ "# castHH of $dst" %} - ins_encode(/* empty encoding */); - ins_cost(0); - ins_pipe(empty); -%} - -instruct castDD(regD dst) -%{ - match(Set dst (CastDD dst)); - - size(0); - format %{ "# castDD of $dst" %} - ins_encode(/* empty encoding */); - ins_cost(0); - ins_pipe(empty); -%} - -// XXX No flag versions for CompareAndSwap{P,I,L} because matcher can't match them -instruct compareAndSwapP(rRegI res, - memory mem_ptr, - rax_RegP oldval, rRegP newval, - rFlagsReg cr) -%{ - predicate(n->as_LoadStore()->barrier_data() == 0); - match(Set res (CompareAndSwapP mem_ptr (Binary oldval newval))); - match(Set res (WeakCompareAndSwapP mem_ptr (Binary oldval newval))); - effect(KILL cr, KILL oldval); - - format %{ "cmpxchgq $mem_ptr,$newval\t# " - "If rax == $mem_ptr then store $newval into $mem_ptr\n\t" - "setcc $res \t# emits sete + movzbl or setzue for APX" %} - ins_encode %{ - __ lock(); - __ cmpxchgq($newval$$Register, $mem_ptr$$Address); - __ setcc(Assembler::equal, $res$$Register); - %} - ins_pipe( pipe_cmpxchg ); -%} - -instruct compareAndSwapL(rRegI res, - memory mem_ptr, - rax_RegL oldval, rRegL newval, - rFlagsReg cr) -%{ - match(Set res (CompareAndSwapL mem_ptr (Binary oldval newval))); - match(Set res (WeakCompareAndSwapL mem_ptr (Binary oldval newval))); - effect(KILL cr, KILL oldval); - - format %{ "cmpxchgq $mem_ptr,$newval\t# " - "If rax == $mem_ptr then store $newval into $mem_ptr\n\t" - "setcc $res \t# emits sete + movzbl or setzue for APX" %} - ins_encode %{ - __ lock(); - __ cmpxchgq($newval$$Register, $mem_ptr$$Address); - __ setcc(Assembler::equal, $res$$Register); - %} - ins_pipe( pipe_cmpxchg ); -%} - -instruct compareAndSwapI(rRegI res, - memory mem_ptr, - rax_RegI oldval, rRegI newval, - rFlagsReg cr) -%{ - match(Set res (CompareAndSwapI mem_ptr (Binary oldval newval))); - match(Set res (WeakCompareAndSwapI mem_ptr (Binary oldval newval))); - effect(KILL cr, KILL oldval); - - format %{ "cmpxchgl $mem_ptr,$newval\t# " - "If rax == $mem_ptr then store $newval into $mem_ptr\n\t" - "setcc $res \t# emits sete + movzbl or setzue for APX" %} - ins_encode %{ - __ lock(); - __ cmpxchgl($newval$$Register, $mem_ptr$$Address); - __ setcc(Assembler::equal, $res$$Register); - %} - ins_pipe( pipe_cmpxchg ); -%} - -instruct compareAndSwapB(rRegI res, - memory mem_ptr, - rax_RegI oldval, rRegI newval, - rFlagsReg cr) -%{ - match(Set res (CompareAndSwapB mem_ptr (Binary oldval newval))); - match(Set res (WeakCompareAndSwapB mem_ptr (Binary oldval newval))); - effect(KILL cr, KILL oldval); - - format %{ "cmpxchgb $mem_ptr,$newval\t# " - "If rax == $mem_ptr then store $newval into $mem_ptr\n\t" - "setcc $res \t# emits sete + movzbl or setzue for APX" %} - ins_encode %{ - __ lock(); - __ cmpxchgb($newval$$Register, $mem_ptr$$Address); - __ setcc(Assembler::equal, $res$$Register); - %} - ins_pipe( pipe_cmpxchg ); -%} - -instruct compareAndSwapS(rRegI res, - memory mem_ptr, - rax_RegI oldval, rRegI newval, - rFlagsReg cr) -%{ - match(Set res (CompareAndSwapS mem_ptr (Binary oldval newval))); - match(Set res (WeakCompareAndSwapS mem_ptr (Binary oldval newval))); - effect(KILL cr, KILL oldval); - - format %{ "cmpxchgw $mem_ptr,$newval\t# " - "If rax == $mem_ptr then store $newval into $mem_ptr\n\t" - "setcc $res \t# emits sete + movzbl or setzue for APX" %} - ins_encode %{ - __ lock(); - __ cmpxchgw($newval$$Register, $mem_ptr$$Address); - __ setcc(Assembler::equal, $res$$Register); - %} - ins_pipe( pipe_cmpxchg ); -%} - -instruct compareAndSwapN(rRegI res, - memory mem_ptr, - rax_RegN oldval, rRegN newval, - rFlagsReg cr) %{ - predicate(n->as_LoadStore()->barrier_data() == 0); - match(Set res (CompareAndSwapN mem_ptr (Binary oldval newval))); - match(Set res (WeakCompareAndSwapN mem_ptr (Binary oldval newval))); - effect(KILL cr, KILL oldval); - - format %{ "cmpxchgl $mem_ptr,$newval\t# " - "If rax == $mem_ptr then store $newval into $mem_ptr\n\t" - "setcc $res \t# emits sete + movzbl or setzue for APX" %} - ins_encode %{ - __ lock(); - __ cmpxchgl($newval$$Register, $mem_ptr$$Address); - __ setcc(Assembler::equal, $res$$Register); - %} - ins_pipe( pipe_cmpxchg ); -%} - -instruct compareAndExchangeB( - memory mem_ptr, - rax_RegI oldval, rRegI newval, - rFlagsReg cr) -%{ - match(Set oldval (CompareAndExchangeB mem_ptr (Binary oldval newval))); - effect(KILL cr); - - format %{ "cmpxchgb $mem_ptr,$newval\t# " - "If rax == $mem_ptr then store $newval into $mem_ptr\n\t" %} - ins_encode %{ - __ lock(); - __ cmpxchgb($newval$$Register, $mem_ptr$$Address); - %} - ins_pipe( pipe_cmpxchg ); -%} - -instruct compareAndExchangeS( - memory mem_ptr, - rax_RegI oldval, rRegI newval, - rFlagsReg cr) -%{ - match(Set oldval (CompareAndExchangeS mem_ptr (Binary oldval newval))); - effect(KILL cr); - - format %{ "cmpxchgw $mem_ptr,$newval\t# " - "If rax == $mem_ptr then store $newval into $mem_ptr\n\t" %} - ins_encode %{ - __ lock(); - __ cmpxchgw($newval$$Register, $mem_ptr$$Address); - %} - ins_pipe( pipe_cmpxchg ); -%} - -instruct compareAndExchangeI( - memory mem_ptr, - rax_RegI oldval, rRegI newval, - rFlagsReg cr) -%{ - match(Set oldval (CompareAndExchangeI mem_ptr (Binary oldval newval))); - effect(KILL cr); - - format %{ "cmpxchgl $mem_ptr,$newval\t# " - "If rax == $mem_ptr then store $newval into $mem_ptr\n\t" %} - ins_encode %{ - __ lock(); - __ cmpxchgl($newval$$Register, $mem_ptr$$Address); - %} - ins_pipe( pipe_cmpxchg ); -%} - -instruct compareAndExchangeL( - memory mem_ptr, - rax_RegL oldval, rRegL newval, - rFlagsReg cr) -%{ - match(Set oldval (CompareAndExchangeL mem_ptr (Binary oldval newval))); - effect(KILL cr); - - format %{ "cmpxchgq $mem_ptr,$newval\t# " - "If rax == $mem_ptr then store $newval into $mem_ptr\n\t" %} - ins_encode %{ - __ lock(); - __ cmpxchgq($newval$$Register, $mem_ptr$$Address); - %} - ins_pipe( pipe_cmpxchg ); -%} - -instruct compareAndExchangeN( - memory mem_ptr, - rax_RegN oldval, rRegN newval, - rFlagsReg cr) %{ - predicate(n->as_LoadStore()->barrier_data() == 0); - match(Set oldval (CompareAndExchangeN mem_ptr (Binary oldval newval))); - effect(KILL cr); - - format %{ "cmpxchgl $mem_ptr,$newval\t# " - "If rax == $mem_ptr then store $newval into $mem_ptr\n\t" %} - ins_encode %{ - __ lock(); - __ cmpxchgl($newval$$Register, $mem_ptr$$Address); - %} - ins_pipe( pipe_cmpxchg ); -%} - -instruct compareAndExchangeP( - memory mem_ptr, - rax_RegP oldval, rRegP newval, - rFlagsReg cr) -%{ - predicate(n->as_LoadStore()->barrier_data() == 0); - match(Set oldval (CompareAndExchangeP mem_ptr (Binary oldval newval))); - effect(KILL cr); - - format %{ "cmpxchgq $mem_ptr,$newval\t# " - "If rax == $mem_ptr then store $newval into $mem_ptr\n\t" %} - ins_encode %{ - __ lock(); - __ cmpxchgq($newval$$Register, $mem_ptr$$Address); - %} - ins_pipe( pipe_cmpxchg ); -%} - -instruct xaddB_reg_no_res(memory mem, Universe dummy, rRegI add, rFlagsReg cr) %{ - predicate(n->as_LoadStore()->result_not_used()); - match(Set dummy (GetAndAddB mem add)); - effect(KILL cr); - format %{ "addb_lock $mem, $add" %} - ins_encode %{ - __ lock(); - __ addb($mem$$Address, $add$$Register); - %} - ins_pipe(pipe_cmpxchg); -%} - -instruct xaddB_imm_no_res(memory mem, Universe dummy, immI add, rFlagsReg cr) %{ - predicate(n->as_LoadStore()->result_not_used()); - match(Set dummy (GetAndAddB mem add)); - effect(KILL cr); - format %{ "addb_lock $mem, $add" %} - ins_encode %{ - __ lock(); - __ addb($mem$$Address, $add$$constant); - %} - ins_pipe(pipe_cmpxchg); -%} - -instruct xaddB(memory mem, rRegI newval, rFlagsReg cr) %{ - predicate(!n->as_LoadStore()->result_not_used()); - match(Set newval (GetAndAddB mem newval)); - effect(KILL cr); - format %{ "xaddb_lock $mem, $newval" %} - ins_encode %{ - __ lock(); - __ xaddb($mem$$Address, $newval$$Register); - %} - ins_pipe(pipe_cmpxchg); -%} - -instruct xaddS_reg_no_res(memory mem, Universe dummy, rRegI add, rFlagsReg cr) %{ - predicate(n->as_LoadStore()->result_not_used()); - match(Set dummy (GetAndAddS mem add)); - effect(KILL cr); - format %{ "addw_lock $mem, $add" %} - ins_encode %{ - __ lock(); - __ addw($mem$$Address, $add$$Register); - %} - ins_pipe(pipe_cmpxchg); -%} - -instruct xaddS_imm_no_res(memory mem, Universe dummy, immI add, rFlagsReg cr) %{ - predicate(UseStoreImmI16 && n->as_LoadStore()->result_not_used()); - match(Set dummy (GetAndAddS mem add)); - effect(KILL cr); - format %{ "addw_lock $mem, $add" %} - ins_encode %{ - __ lock(); - __ addw($mem$$Address, $add$$constant); - %} - ins_pipe(pipe_cmpxchg); -%} - -instruct xaddS(memory mem, rRegI newval, rFlagsReg cr) %{ - predicate(!n->as_LoadStore()->result_not_used()); - match(Set newval (GetAndAddS mem newval)); - effect(KILL cr); - format %{ "xaddw_lock $mem, $newval" %} - ins_encode %{ - __ lock(); - __ xaddw($mem$$Address, $newval$$Register); - %} - ins_pipe(pipe_cmpxchg); -%} - -instruct xaddI_reg_no_res(memory mem, Universe dummy, rRegI add, rFlagsReg cr) %{ - predicate(n->as_LoadStore()->result_not_used()); - match(Set dummy (GetAndAddI mem add)); - effect(KILL cr); - format %{ "addl_lock $mem, $add" %} - ins_encode %{ - __ lock(); - __ addl($mem$$Address, $add$$Register); - %} - ins_pipe(pipe_cmpxchg); -%} - -instruct xaddI_imm_no_res(memory mem, Universe dummy, immI add, rFlagsReg cr) %{ - predicate(n->as_LoadStore()->result_not_used()); - match(Set dummy (GetAndAddI mem add)); - effect(KILL cr); - format %{ "addl_lock $mem, $add" %} - ins_encode %{ - __ lock(); - __ addl($mem$$Address, $add$$constant); - %} - ins_pipe(pipe_cmpxchg); -%} - -instruct xaddI(memory mem, rRegI newval, rFlagsReg cr) %{ - predicate(!n->as_LoadStore()->result_not_used()); - match(Set newval (GetAndAddI mem newval)); - effect(KILL cr); - format %{ "xaddl_lock $mem, $newval" %} - ins_encode %{ - __ lock(); - __ xaddl($mem$$Address, $newval$$Register); - %} - ins_pipe(pipe_cmpxchg); -%} - -instruct xaddL_reg_no_res(memory mem, Universe dummy, rRegL add, rFlagsReg cr) %{ - predicate(n->as_LoadStore()->result_not_used()); - match(Set dummy (GetAndAddL mem add)); - effect(KILL cr); - format %{ "addq_lock $mem, $add" %} - ins_encode %{ - __ lock(); - __ addq($mem$$Address, $add$$Register); - %} - ins_pipe(pipe_cmpxchg); -%} - -instruct xaddL_imm_no_res(memory mem, Universe dummy, immL32 add, rFlagsReg cr) %{ - predicate(n->as_LoadStore()->result_not_used()); - match(Set dummy (GetAndAddL mem add)); - effect(KILL cr); - format %{ "addq_lock $mem, $add" %} - ins_encode %{ - __ lock(); - __ addq($mem$$Address, $add$$constant); - %} - ins_pipe(pipe_cmpxchg); -%} - -instruct xaddL(memory mem, rRegL newval, rFlagsReg cr) %{ - predicate(!n->as_LoadStore()->result_not_used()); - match(Set newval (GetAndAddL mem newval)); - effect(KILL cr); - format %{ "xaddq_lock $mem, $newval" %} - ins_encode %{ - __ lock(); - __ xaddq($mem$$Address, $newval$$Register); - %} - ins_pipe(pipe_cmpxchg); -%} - -instruct xchgB( memory mem, rRegI newval) %{ - match(Set newval (GetAndSetB mem newval)); - format %{ "XCHGB $newval,[$mem]" %} - ins_encode %{ - __ xchgb($newval$$Register, $mem$$Address); - %} - ins_pipe( pipe_cmpxchg ); -%} - -instruct xchgS( memory mem, rRegI newval) %{ - match(Set newval (GetAndSetS mem newval)); - format %{ "XCHGW $newval,[$mem]" %} - ins_encode %{ - __ xchgw($newval$$Register, $mem$$Address); - %} - ins_pipe( pipe_cmpxchg ); -%} - -instruct xchgI( memory mem, rRegI newval) %{ - match(Set newval (GetAndSetI mem newval)); - format %{ "XCHGL $newval,[$mem]" %} - ins_encode %{ - __ xchgl($newval$$Register, $mem$$Address); - %} - ins_pipe( pipe_cmpxchg ); -%} - -instruct xchgL( memory mem, rRegL newval) %{ - match(Set newval (GetAndSetL mem newval)); - format %{ "XCHGL $newval,[$mem]" %} - ins_encode %{ - __ xchgq($newval$$Register, $mem$$Address); - %} - ins_pipe( pipe_cmpxchg ); -%} - -instruct xchgP( memory mem, rRegP newval) %{ - match(Set newval (GetAndSetP mem newval)); - predicate(n->as_LoadStore()->barrier_data() == 0); - format %{ "XCHGQ $newval,[$mem]" %} - ins_encode %{ - __ xchgq($newval$$Register, $mem$$Address); - %} - ins_pipe( pipe_cmpxchg ); -%} - -instruct xchgN( memory mem, rRegN newval) %{ - predicate(n->as_LoadStore()->barrier_data() == 0); - match(Set newval (GetAndSetN mem newval)); - format %{ "XCHGL $newval,$mem]" %} - ins_encode %{ - __ xchgl($newval$$Register, $mem$$Address); - %} - ins_pipe( pipe_cmpxchg ); -%} - -//----------Abs Instructions------------------------------------------- - -// Integer Absolute Instructions -instruct absI_rReg(rRegI dst, rRegI src, rFlagsReg cr) -%{ - match(Set dst (AbsI src)); - effect(TEMP dst, KILL cr); - format %{ "xorl $dst, $dst\t# abs int\n\t" - "subl $dst, $src\n\t" - "cmovll $dst, $src" %} - ins_encode %{ - __ xorl($dst$$Register, $dst$$Register); - __ subl($dst$$Register, $src$$Register); - __ cmovl(Assembler::less, $dst$$Register, $src$$Register); - %} - - ins_pipe(ialu_reg_reg); -%} - -// Long Absolute Instructions -instruct absL_rReg(rRegL dst, rRegL src, rFlagsReg cr) -%{ - match(Set dst (AbsL src)); - effect(TEMP dst, KILL cr); - format %{ "xorl $dst, $dst\t# abs long\n\t" - "subq $dst, $src\n\t" - "cmovlq $dst, $src" %} - ins_encode %{ - __ xorl($dst$$Register, $dst$$Register); - __ subq($dst$$Register, $src$$Register); - __ cmovq(Assembler::less, $dst$$Register, $src$$Register); - %} - - ins_pipe(ialu_reg_reg); -%} - -//----------Subtraction Instructions------------------------------------------- - -// Integer Subtraction Instructions -instruct subI_rReg(rRegI dst, rRegI src, rFlagsReg cr) -%{ - predicate(!UseAPX); - match(Set dst (SubI dst src)); - effect(KILL cr); - flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); - - format %{ "subl $dst, $src\t# int" %} - ins_encode %{ - __ subl($dst$$Register, $src$$Register); - %} - ins_pipe(ialu_reg_reg); -%} - -instruct subI_rReg_ndd(rRegI dst, rRegI src1, rRegI src2, rFlagsReg cr) -%{ - predicate(UseAPX); - match(Set dst (SubI src1 src2)); - effect(KILL cr); - flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); - - format %{ "esubl $dst, $src1, $src2\t# int ndd" %} - ins_encode %{ - __ esubl($dst$$Register, $src1$$Register, $src2$$Register, false); - %} - ins_pipe(ialu_reg_reg); -%} - -instruct subI_rReg_rReg_imm_ndd(rRegI dst, rRegI src1, immI src2, rFlagsReg cr) -%{ - predicate(UseAPX); - match(Set dst (SubI src1 src2)); - effect(KILL cr); - flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); - - format %{ "esubl $dst, $src1, $src2\t# int ndd" %} - ins_encode %{ - __ esubl($dst$$Register, $src1$$Register, $src2$$constant, false); - %} - ins_pipe(ialu_reg_reg); -%} - -instruct subI_rReg_mem_imm_ndd(rRegI dst, memory src1, immI src2, rFlagsReg cr) -%{ - predicate(UseAPX); - match(Set dst (SubI (LoadI src1) src2)); - effect(KILL cr); - flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); - - format %{ "esubl $dst, $src1, $src2\t# int ndd" %} - ins_encode %{ - __ esubl($dst$$Register, $src1$$Address, $src2$$constant, false); - %} - ins_pipe(ialu_reg_reg); -%} - -instruct subI_rReg_mem(rRegI dst, memory src, rFlagsReg cr) -%{ - predicate(!UseAPX); - match(Set dst (SubI dst (LoadI src))); - effect(KILL cr); - flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); - - ins_cost(150); - format %{ "subl $dst, $src\t# int" %} - ins_encode %{ - __ subl($dst$$Register, $src$$Address); - %} - ins_pipe(ialu_reg_mem); -%} - -instruct subI_rReg_rReg_mem_ndd(rRegI dst, rRegI src1, memory src2, rFlagsReg cr) -%{ - predicate(UseAPX); - match(Set dst (SubI src1 (LoadI src2))); - effect(KILL cr); - flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); - - ins_cost(150); - format %{ "esubl $dst, $src1, $src2\t# int ndd" %} - ins_encode %{ - __ esubl($dst$$Register, $src1$$Register, $src2$$Address, false); - %} - ins_pipe(ialu_reg_mem); -%} - -instruct subI_rReg_mem_rReg_ndd(rRegI dst, memory src1, rRegI src2, rFlagsReg cr) -%{ - predicate(UseAPX); - match(Set dst (SubI (LoadI src1) src2)); - effect(KILL cr); - flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); - - ins_cost(150); - format %{ "esubl $dst, $src1, $src2\t# int ndd" %} - ins_encode %{ - __ esubl($dst$$Register, $src1$$Address, $src2$$Register, false); - %} - ins_pipe(ialu_reg_mem); -%} - -instruct subI_mem_rReg(memory dst, rRegI src, rFlagsReg cr) -%{ - match(Set dst (StoreI dst (SubI (LoadI dst) src))); - effect(KILL cr); - flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); - - ins_cost(150); - format %{ "subl $dst, $src\t# int" %} - ins_encode %{ - __ subl($dst$$Address, $src$$Register); - %} - ins_pipe(ialu_mem_reg); -%} - -instruct subL_rReg(rRegL dst, rRegL src, rFlagsReg cr) -%{ - predicate(!UseAPX); - match(Set dst (SubL dst src)); - effect(KILL cr); - flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); - - format %{ "subq $dst, $src\t# long" %} - ins_encode %{ - __ subq($dst$$Register, $src$$Register); - %} - ins_pipe(ialu_reg_reg); -%} - -instruct subL_rReg_ndd(rRegL dst, rRegL src1, rRegL src2, rFlagsReg cr) -%{ - predicate(UseAPX); - match(Set dst (SubL src1 src2)); - effect(KILL cr); - flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); - - format %{ "esubq $dst, $src1, $src2\t# long ndd" %} - ins_encode %{ - __ esubq($dst$$Register, $src1$$Register, $src2$$Register, false); - %} - ins_pipe(ialu_reg_reg); -%} - -instruct subL_rReg_rReg_imm_ndd(rRegL dst, rRegL src1, immL32 src2, rFlagsReg cr) -%{ - predicate(UseAPX); - match(Set dst (SubL src1 src2)); - effect(KILL cr); - flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); - - format %{ "esubq $dst, $src1, $src2\t# long ndd" %} - ins_encode %{ - __ esubq($dst$$Register, $src1$$Register, $src2$$constant, false); - %} - ins_pipe(ialu_reg_reg); -%} - -instruct subL_rReg_mem_imm_ndd(rRegL dst, memory src1, immL32 src2, rFlagsReg cr) -%{ - predicate(UseAPX); - match(Set dst (SubL (LoadL src1) src2)); - effect(KILL cr); - flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); - - format %{ "esubq $dst, $src1, $src2\t# long ndd" %} - ins_encode %{ - __ esubq($dst$$Register, $src1$$Address, $src2$$constant, false); - %} - ins_pipe(ialu_reg_reg); -%} - -instruct subL_rReg_mem(rRegL dst, memory src, rFlagsReg cr) -%{ - predicate(!UseAPX); - match(Set dst (SubL dst (LoadL src))); - effect(KILL cr); - flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); - - ins_cost(150); - format %{ "subq $dst, $src\t# long" %} - ins_encode %{ - __ subq($dst$$Register, $src$$Address); - %} - ins_pipe(ialu_reg_mem); -%} - -instruct subL_rReg_rReg_mem_ndd(rRegL dst, rRegL src1, memory src2, rFlagsReg cr) -%{ - predicate(UseAPX); - match(Set dst (SubL src1 (LoadL src2))); - effect(KILL cr); - flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); - - ins_cost(150); - format %{ "esubq $dst, $src1, $src2\t# long ndd" %} - ins_encode %{ - __ esubq($dst$$Register, $src1$$Register, $src2$$Address, false); - %} - ins_pipe(ialu_reg_mem); -%} - -instruct subL_rReg_mem_rReg_ndd(rRegL dst, memory src1, rRegL src2, rFlagsReg cr) -%{ - predicate(UseAPX); - match(Set dst (SubL (LoadL src1) src2)); - effect(KILL cr); - flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); - - ins_cost(150); - format %{ "esubq $dst, $src1, $src2\t# long ndd" %} - ins_encode %{ - __ esubq($dst$$Register, $src1$$Address, $src2$$Register, false); - %} - ins_pipe(ialu_reg_mem); -%} - -instruct subL_mem_rReg(memory dst, rRegL src, rFlagsReg cr) -%{ - match(Set dst (StoreL dst (SubL (LoadL dst) src))); - effect(KILL cr); - flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); - - ins_cost(150); - format %{ "subq $dst, $src\t# long" %} - ins_encode %{ - __ subq($dst$$Address, $src$$Register); - %} - ins_pipe(ialu_mem_reg); -%} - -// Subtract from a pointer -// XXX hmpf??? -instruct subP_rReg(rRegP dst, rRegI src, immI_0 zero, rFlagsReg cr) -%{ - match(Set dst (AddP dst (SubI zero src))); - effect(KILL cr); - - format %{ "subq $dst, $src\t# ptr - int" %} - ins_encode %{ - __ subq($dst$$Register, $src$$Register); - %} - ins_pipe(ialu_reg_reg); -%} - -instruct negI_rReg(rRegI dst, immI_0 zero, rFlagsReg cr) -%{ - predicate(!UseAPX); - match(Set dst (SubI zero dst)); - effect(KILL cr); - flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag); - - format %{ "negl $dst\t# int" %} - ins_encode %{ - __ negl($dst$$Register); - %} - ins_pipe(ialu_reg); -%} - -instruct negI_rReg_ndd(rRegI dst, rRegI src, immI_0 zero, rFlagsReg cr) -%{ - predicate(UseAPX); - match(Set dst (SubI zero src)); - effect(KILL cr); - flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag); - - format %{ "enegl $dst, $src\t# int ndd" %} - ins_encode %{ - __ enegl($dst$$Register, $src$$Register, false); - %} - ins_pipe(ialu_reg); -%} - -instruct negI_rReg_2(rRegI dst, rFlagsReg cr) -%{ - predicate(!UseAPX); - match(Set dst (NegI dst)); - effect(KILL cr); - flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag); - - format %{ "negl $dst\t# int" %} - ins_encode %{ - __ negl($dst$$Register); - %} - ins_pipe(ialu_reg); -%} - -instruct negI_rReg_2_ndd(rRegI dst, rRegI src, rFlagsReg cr) -%{ - predicate(UseAPX); - match(Set dst (NegI src)); - effect(KILL cr); - flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag); - - format %{ "enegl $dst, $src\t# int ndd" %} - ins_encode %{ - __ enegl($dst$$Register, $src$$Register, false); - %} - ins_pipe(ialu_reg); -%} - -instruct negI_mem(memory dst, immI_0 zero, rFlagsReg cr) -%{ - match(Set dst (StoreI dst (SubI zero (LoadI dst)))); - effect(KILL cr); - flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag); - - format %{ "negl $dst\t# int" %} - ins_encode %{ - __ negl($dst$$Address); - %} - ins_pipe(ialu_reg); -%} - -instruct negL_rReg(rRegL dst, immL0 zero, rFlagsReg cr) -%{ - predicate(!UseAPX); - match(Set dst (SubL zero dst)); - effect(KILL cr); - flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag); - - format %{ "negq $dst\t# long" %} - ins_encode %{ - __ negq($dst$$Register); - %} - ins_pipe(ialu_reg); -%} - -instruct negL_rReg_ndd(rRegL dst, rRegL src, immL0 zero, rFlagsReg cr) -%{ - predicate(UseAPX); - match(Set dst (SubL zero src)); - effect(KILL cr); - flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag); - - format %{ "enegq $dst, $src\t# long ndd" %} - ins_encode %{ - __ enegq($dst$$Register, $src$$Register, false); - %} - ins_pipe(ialu_reg); -%} - -instruct negL_rReg_2(rRegL dst, rFlagsReg cr) -%{ - predicate(!UseAPX); - match(Set dst (NegL dst)); - effect(KILL cr); - flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag); - - format %{ "negq $dst\t# int" %} - ins_encode %{ - __ negq($dst$$Register); - %} - ins_pipe(ialu_reg); -%} - -instruct negL_rReg_2_ndd(rRegL dst, rRegL src, rFlagsReg cr) -%{ - predicate(UseAPX); - match(Set dst (NegL src)); - effect(KILL cr); - flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag); - - format %{ "enegq $dst, $src\t# long ndd" %} - ins_encode %{ - __ enegq($dst$$Register, $src$$Register, false); - %} - ins_pipe(ialu_reg); -%} - -instruct negL_mem(memory dst, immL0 zero, rFlagsReg cr) -%{ - match(Set dst (StoreL dst (SubL zero (LoadL dst)))); - effect(KILL cr); - flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag); - - format %{ "negq $dst\t# long" %} - ins_encode %{ - __ negq($dst$$Address); - %} - ins_pipe(ialu_reg); -%} - -//----------Multiplication/Division Instructions------------------------------- -// Integer Multiplication Instructions -// Multiply Register - -instruct mulI_rReg(rRegI dst, rRegI src, rFlagsReg cr) -%{ - predicate(!UseAPX); - match(Set dst (MulI dst src)); - effect(KILL cr); - - ins_cost(300); - format %{ "imull $dst, $src\t# int" %} - ins_encode %{ - __ imull($dst$$Register, $src$$Register); - %} - ins_pipe(ialu_reg_reg_alu0); -%} - -instruct mulI_rReg_ndd(rRegI dst, rRegI src1, rRegI src2, rFlagsReg cr) -%{ - predicate(UseAPX); - match(Set dst (MulI src1 src2)); - effect(KILL cr); - - ins_cost(300); - format %{ "eimull $dst, $src1, $src2\t# int ndd" %} - ins_encode %{ - __ eimull($dst$$Register, $src1$$Register, $src2$$Register, false); - %} - ins_pipe(ialu_reg_reg_alu0); -%} - -instruct mulI_rReg_imm(rRegI dst, rRegI src, immI imm, rFlagsReg cr) -%{ - match(Set dst (MulI src imm)); - effect(KILL cr); - - ins_cost(300); - format %{ "imull $dst, $src, $imm\t# int" %} - ins_encode %{ - __ imull($dst$$Register, $src$$Register, $imm$$constant); - %} - ins_pipe(ialu_reg_reg_alu0); -%} - -instruct mulI_mem(rRegI dst, memory src, rFlagsReg cr) -%{ - predicate(!UseAPX); - match(Set dst (MulI dst (LoadI src))); - effect(KILL cr); - - ins_cost(350); - format %{ "imull $dst, $src\t# int" %} - ins_encode %{ - __ imull($dst$$Register, $src$$Address); - %} - ins_pipe(ialu_reg_mem_alu0); -%} - -instruct mulI_rReg_rReg_mem_ndd(rRegI dst, rRegI src1, memory src2, rFlagsReg cr) -%{ - predicate(UseAPX); - match(Set dst (MulI src1 (LoadI src2))); - effect(KILL cr); - - ins_cost(350); - format %{ "eimull $dst, $src1, $src2\t# int ndd" %} - ins_encode %{ - __ eimull($dst$$Register, $src1$$Register, $src2$$Address, false); - %} - ins_pipe(ialu_reg_mem_alu0); -%} - -instruct mulI_mem_imm(rRegI dst, memory src, immI imm, rFlagsReg cr) -%{ - match(Set dst (MulI (LoadI src) imm)); - effect(KILL cr); - - ins_cost(300); - format %{ "imull $dst, $src, $imm\t# int" %} - ins_encode %{ - __ imull($dst$$Register, $src$$Address, $imm$$constant); - %} - ins_pipe(ialu_reg_mem_alu0); -%} - -instruct mulAddS2I_rReg(rRegI dst, rRegI src1, rRegI src2, rRegI src3, rFlagsReg cr) -%{ - match(Set dst (MulAddS2I (Binary dst src1) (Binary src2 src3))); - effect(KILL cr, KILL src2); - - expand %{ mulI_rReg(dst, src1, cr); - mulI_rReg(src2, src3, cr); - addI_rReg(dst, src2, cr); %} -%} - -instruct mulL_rReg(rRegL dst, rRegL src, rFlagsReg cr) -%{ - predicate(!UseAPX); - match(Set dst (MulL dst src)); - effect(KILL cr); - - ins_cost(300); - format %{ "imulq $dst, $src\t# long" %} - ins_encode %{ - __ imulq($dst$$Register, $src$$Register); - %} - ins_pipe(ialu_reg_reg_alu0); -%} - -instruct mulL_rReg_ndd(rRegL dst, rRegL src1, rRegL src2, rFlagsReg cr) -%{ - predicate(UseAPX); - match(Set dst (MulL src1 src2)); - effect(KILL cr); - - ins_cost(300); - format %{ "eimulq $dst, $src1, $src2\t# long ndd" %} - ins_encode %{ - __ eimulq($dst$$Register, $src1$$Register, $src2$$Register, false); - %} - ins_pipe(ialu_reg_reg_alu0); -%} - -instruct mulL_rReg_imm(rRegL dst, rRegL src, immL32 imm, rFlagsReg cr) -%{ - match(Set dst (MulL src imm)); - effect(KILL cr); - - ins_cost(300); - format %{ "imulq $dst, $src, $imm\t# long" %} - ins_encode %{ - __ imulq($dst$$Register, $src$$Register, $imm$$constant); - %} - ins_pipe(ialu_reg_reg_alu0); -%} - -instruct mulL_mem(rRegL dst, memory src, rFlagsReg cr) -%{ - predicate(!UseAPX); - match(Set dst (MulL dst (LoadL src))); - effect(KILL cr); - - ins_cost(350); - format %{ "imulq $dst, $src\t# long" %} - ins_encode %{ - __ imulq($dst$$Register, $src$$Address); - %} - ins_pipe(ialu_reg_mem_alu0); -%} - -instruct mulL_rReg_rReg_mem_ndd(rRegL dst, rRegL src1, memory src2, rFlagsReg cr) -%{ - predicate(UseAPX); - match(Set dst (MulL src1 (LoadL src2))); - effect(KILL cr); - - ins_cost(350); - format %{ "eimulq $dst, $src1, $src2 \t# long" %} - ins_encode %{ - __ eimulq($dst$$Register, $src1$$Register, $src2$$Address, false); - %} - ins_pipe(ialu_reg_mem_alu0); -%} - -instruct mulL_mem_imm(rRegL dst, memory src, immL32 imm, rFlagsReg cr) -%{ - match(Set dst (MulL (LoadL src) imm)); - effect(KILL cr); - - ins_cost(300); - format %{ "imulq $dst, $src, $imm\t# long" %} - ins_encode %{ - __ imulq($dst$$Register, $src$$Address, $imm$$constant); - %} - ins_pipe(ialu_reg_mem_alu0); -%} - -instruct mulHiL_rReg(rdx_RegL dst, rRegL src, rax_RegL rax, rFlagsReg cr) -%{ - match(Set dst (MulHiL src rax)); - effect(USE_KILL rax, KILL cr); - - ins_cost(300); - format %{ "imulq RDX:RAX, RAX, $src\t# mulhi" %} - ins_encode %{ - __ imulq($src$$Register); - %} - ins_pipe(ialu_reg_reg_alu0); -%} - -instruct umulHiL_rReg(rdx_RegL dst, rRegL src, rax_RegL rax, rFlagsReg cr) -%{ - match(Set dst (UMulHiL src rax)); - effect(USE_KILL rax, KILL cr); - - ins_cost(300); - format %{ "mulq RDX:RAX, RAX, $src\t# umulhi" %} - ins_encode %{ - __ mulq($src$$Register); - %} - ins_pipe(ialu_reg_reg_alu0); -%} - -instruct divI_rReg(rax_RegI rax, rdx_RegI rdx, no_rax_rdx_RegI div, - rFlagsReg cr) -%{ - match(Set rax (DivI rax div)); - effect(KILL rdx, KILL cr); - - ins_cost(30*100+10*100); // XXX - format %{ "cmpl rax, 0x80000000\t# idiv\n\t" - "jne,s normal\n\t" - "xorl rdx, rdx\n\t" - "cmpl $div, -1\n\t" - "je,s done\n" - "normal: cdql\n\t" - "idivl $div\n" - "done:" %} - ins_encode(cdql_enc(div)); - ins_pipe(ialu_reg_reg_alu0); -%} - -instruct divL_rReg(rax_RegL rax, rdx_RegL rdx, no_rax_rdx_RegL div, - rFlagsReg cr) -%{ - match(Set rax (DivL rax div)); - effect(KILL rdx, KILL cr); - - ins_cost(30*100+10*100); // XXX - format %{ "movq rdx, 0x8000000000000000\t# ldiv\n\t" - "cmpq rax, rdx\n\t" - "jne,s normal\n\t" - "xorl rdx, rdx\n\t" - "cmpq $div, -1\n\t" - "je,s done\n" - "normal: cdqq\n\t" - "idivq $div\n" - "done:" %} - ins_encode(cdqq_enc(div)); - ins_pipe(ialu_reg_reg_alu0); -%} - -instruct udivI_rReg(rax_RegI rax, rdx_RegI rdx, no_rax_rdx_RegI div, rFlagsReg cr) -%{ - match(Set rax (UDivI rax div)); - effect(KILL rdx, KILL cr); - - ins_cost(300); - format %{ "udivl $rax,$rax,$div\t# UDivI\n" %} - ins_encode %{ - __ udivI($rax$$Register, $div$$Register, $rdx$$Register); - %} - ins_pipe(ialu_reg_reg_alu0); -%} - -instruct udivL_rReg(rax_RegL rax, rdx_RegL rdx, no_rax_rdx_RegL div, rFlagsReg cr) -%{ - match(Set rax (UDivL rax div)); - effect(KILL rdx, KILL cr); - - ins_cost(300); - format %{ "udivq $rax,$rax,$div\t# UDivL\n" %} - ins_encode %{ - __ udivL($rax$$Register, $div$$Register, $rdx$$Register); - %} - ins_pipe(ialu_reg_reg_alu0); -%} - -// Integer DIVMOD with Register, both quotient and mod results -instruct divModI_rReg_divmod(rax_RegI rax, rdx_RegI rdx, no_rax_rdx_RegI div, - rFlagsReg cr) -%{ - match(DivModI rax div); - effect(KILL cr); - - ins_cost(30*100+10*100); // XXX - format %{ "cmpl rax, 0x80000000\t# idiv\n\t" - "jne,s normal\n\t" - "xorl rdx, rdx\n\t" - "cmpl $div, -1\n\t" - "je,s done\n" - "normal: cdql\n\t" - "idivl $div\n" - "done:" %} - ins_encode(cdql_enc(div)); - ins_pipe(pipe_slow); -%} - -// Long DIVMOD with Register, both quotient and mod results -instruct divModL_rReg_divmod(rax_RegL rax, rdx_RegL rdx, no_rax_rdx_RegL div, - rFlagsReg cr) -%{ - match(DivModL rax div); - effect(KILL cr); - - ins_cost(30*100+10*100); // XXX - format %{ "movq rdx, 0x8000000000000000\t# ldiv\n\t" - "cmpq rax, rdx\n\t" - "jne,s normal\n\t" - "xorl rdx, rdx\n\t" - "cmpq $div, -1\n\t" - "je,s done\n" - "normal: cdqq\n\t" - "idivq $div\n" - "done:" %} - ins_encode(cdqq_enc(div)); - ins_pipe(pipe_slow); -%} - -// Unsigned integer DIVMOD with Register, both quotient and mod results -instruct udivModI_rReg_divmod(rax_RegI rax, no_rax_rdx_RegI tmp, rdx_RegI rdx, - no_rax_rdx_RegI div, rFlagsReg cr) -%{ - match(UDivModI rax div); - effect(TEMP tmp, KILL cr); - - ins_cost(300); - format %{ "udivl $rax,$rax,$div\t# begin UDivModI\n\t" - "umodl $rdx,$rax,$div\t! using $tmp as TEMP # end UDivModI\n" - %} - ins_encode %{ - __ udivmodI($rax$$Register, $div$$Register, $rdx$$Register, $tmp$$Register); - %} - ins_pipe(pipe_slow); -%} - -// Unsigned long DIVMOD with Register, both quotient and mod results -instruct udivModL_rReg_divmod(rax_RegL rax, no_rax_rdx_RegL tmp, rdx_RegL rdx, - no_rax_rdx_RegL div, rFlagsReg cr) -%{ - match(UDivModL rax div); - effect(TEMP tmp, KILL cr); - - ins_cost(300); - format %{ "udivq $rax,$rax,$div\t# begin UDivModL\n\t" - "umodq $rdx,$rax,$div\t! using $tmp as TEMP # end UDivModL\n" - %} - ins_encode %{ - __ udivmodL($rax$$Register, $div$$Register, $rdx$$Register, $tmp$$Register); - %} - ins_pipe(pipe_slow); -%} - -instruct modI_rReg(rdx_RegI rdx, rax_RegI rax, no_rax_rdx_RegI div, - rFlagsReg cr) -%{ - match(Set rdx (ModI rax div)); - effect(KILL rax, KILL cr); - - ins_cost(300); // XXX - format %{ "cmpl rax, 0x80000000\t# irem\n\t" - "jne,s normal\n\t" - "xorl rdx, rdx\n\t" - "cmpl $div, -1\n\t" - "je,s done\n" - "normal: cdql\n\t" - "idivl $div\n" - "done:" %} - ins_encode(cdql_enc(div)); - ins_pipe(ialu_reg_reg_alu0); -%} - -instruct modL_rReg(rdx_RegL rdx, rax_RegL rax, no_rax_rdx_RegL div, - rFlagsReg cr) -%{ - match(Set rdx (ModL rax div)); - effect(KILL rax, KILL cr); - - ins_cost(300); // XXX - format %{ "movq rdx, 0x8000000000000000\t# lrem\n\t" - "cmpq rax, rdx\n\t" - "jne,s normal\n\t" - "xorl rdx, rdx\n\t" - "cmpq $div, -1\n\t" - "je,s done\n" - "normal: cdqq\n\t" - "idivq $div\n" - "done:" %} - ins_encode(cdqq_enc(div)); - ins_pipe(ialu_reg_reg_alu0); -%} - -instruct umodI_rReg(rdx_RegI rdx, rax_RegI rax, no_rax_rdx_RegI div, rFlagsReg cr) -%{ - match(Set rdx (UModI rax div)); - effect(KILL rax, KILL cr); - - ins_cost(300); - format %{ "umodl $rdx,$rax,$div\t# UModI\n" %} - ins_encode %{ - __ umodI($rax$$Register, $div$$Register, $rdx$$Register); - %} - ins_pipe(ialu_reg_reg_alu0); -%} - -instruct umodL_rReg(rdx_RegL rdx, rax_RegL rax, no_rax_rdx_RegL div, rFlagsReg cr) -%{ - match(Set rdx (UModL rax div)); - effect(KILL rax, KILL cr); - - ins_cost(300); - format %{ "umodq $rdx,$rax,$div\t# UModL\n" %} - ins_encode %{ - __ umodL($rax$$Register, $div$$Register, $rdx$$Register); - %} - ins_pipe(ialu_reg_reg_alu0); -%} - -// Integer Shift Instructions -// Shift Left by one, two, three -instruct salI_rReg_immI2(rRegI dst, immI2 shift, rFlagsReg cr) -%{ - predicate(!UseAPX); - match(Set dst (LShiftI dst shift)); - effect(KILL cr); - - format %{ "sall $dst, $shift" %} - ins_encode %{ - __ sall($dst$$Register, $shift$$constant); - %} - ins_pipe(ialu_reg); -%} - -// Shift Left by one, two, three -instruct salI_rReg_immI2_ndd(rRegI dst, rRegI src, immI2 shift, rFlagsReg cr) -%{ - predicate(UseAPX); - match(Set dst (LShiftI src shift)); - effect(KILL cr); - - format %{ "esall $dst, $src, $shift\t# int(ndd)" %} - ins_encode %{ - __ esall($dst$$Register, $src$$Register, $shift$$constant, false); - %} - ins_pipe(ialu_reg); -%} - -// Shift Left by 8-bit immediate -instruct salI_rReg_imm(rRegI dst, immI8 shift, rFlagsReg cr) -%{ - predicate(!UseAPX); - match(Set dst (LShiftI dst shift)); - effect(KILL cr); - - format %{ "sall $dst, $shift" %} - ins_encode %{ - __ sall($dst$$Register, $shift$$constant); - %} - ins_pipe(ialu_reg); -%} - -// Shift Left by 8-bit immediate -instruct salI_rReg_imm_ndd(rRegI dst, rRegI src, immI8 shift, rFlagsReg cr) -%{ - predicate(UseAPX); - match(Set dst (LShiftI src shift)); - effect(KILL cr); - - format %{ "esall $dst, $src, $shift\t# int (ndd)" %} - ins_encode %{ - __ esall($dst$$Register, $src$$Register, $shift$$constant, false); - %} - ins_pipe(ialu_reg); -%} - -instruct salI_rReg_mem_imm_ndd(rRegI dst, memory src, immI8 shift, rFlagsReg cr) -%{ - predicate(UseAPX); - match(Set dst (LShiftI (LoadI src) shift)); - effect(KILL cr); - - format %{ "esall $dst, $src, $shift\t# int (ndd)" %} - ins_encode %{ - __ esall($dst$$Register, $src$$Address, $shift$$constant, false); - %} - ins_pipe(ialu_reg); -%} - -// Shift Left by 8-bit immediate -instruct salI_mem_imm(memory dst, immI8 shift, rFlagsReg cr) -%{ - match(Set dst (StoreI dst (LShiftI (LoadI dst) shift))); - effect(KILL cr); - - format %{ "sall $dst, $shift" %} - ins_encode %{ - __ sall($dst$$Address, $shift$$constant); - %} - ins_pipe(ialu_mem_imm); -%} - -// Shift Left by variable -instruct salI_rReg_CL(rRegI dst, rcx_RegI shift, rFlagsReg cr) -%{ - predicate(!VM_Version::supports_bmi2()); - match(Set dst (LShiftI dst shift)); - effect(KILL cr); - - format %{ "sall $dst, $shift" %} - ins_encode %{ - __ sall($dst$$Register); - %} - ins_pipe(ialu_reg_reg); -%} - -// Shift Left by variable -instruct salI_mem_CL(memory dst, rcx_RegI shift, rFlagsReg cr) -%{ - predicate(!VM_Version::supports_bmi2()); - match(Set dst (StoreI dst (LShiftI (LoadI dst) shift))); - effect(KILL cr); - - format %{ "sall $dst, $shift" %} - ins_encode %{ - __ sall($dst$$Address); - %} - ins_pipe(ialu_mem_reg); -%} - -instruct salI_rReg_rReg(rRegI dst, rRegI src, rRegI shift) -%{ - predicate(VM_Version::supports_bmi2()); - match(Set dst (LShiftI src shift)); - - format %{ "shlxl $dst, $src, $shift" %} - ins_encode %{ - __ shlxl($dst$$Register, $src$$Register, $shift$$Register); - %} - ins_pipe(ialu_reg_reg); -%} - -instruct salI_mem_rReg(rRegI dst, memory src, rRegI shift) -%{ - predicate(VM_Version::supports_bmi2()); - match(Set dst (LShiftI (LoadI src) shift)); - ins_cost(175); - format %{ "shlxl $dst, $src, $shift" %} - ins_encode %{ - __ shlxl($dst$$Register, $src$$Address, $shift$$Register); - %} - ins_pipe(ialu_reg_mem); -%} - -// Arithmetic Shift Right by 8-bit immediate -instruct sarI_rReg_imm(rRegI dst, immI8 shift, rFlagsReg cr) -%{ - predicate(!UseAPX); - match(Set dst (RShiftI dst shift)); - effect(KILL cr); - - format %{ "sarl $dst, $shift" %} - ins_encode %{ - __ sarl($dst$$Register, $shift$$constant); - %} - ins_pipe(ialu_mem_imm); -%} - -// Arithmetic Shift Right by 8-bit immediate -instruct sarI_rReg_imm_ndd(rRegI dst, rRegI src, immI8 shift, rFlagsReg cr) -%{ - predicate(UseAPX); - match(Set dst (RShiftI src shift)); - effect(KILL cr); - - format %{ "esarl $dst, $src, $shift\t# int (ndd)" %} - ins_encode %{ - __ esarl($dst$$Register, $src$$Register, $shift$$constant, false); - %} - ins_pipe(ialu_mem_imm); -%} - -instruct sarI_rReg_mem_imm_ndd(rRegI dst, memory src, immI8 shift, rFlagsReg cr) -%{ - predicate(UseAPX); - match(Set dst (RShiftI (LoadI src) shift)); - effect(KILL cr); - - format %{ "esarl $dst, $src, $shift\t# int (ndd)" %} - ins_encode %{ - __ esarl($dst$$Register, $src$$Address, $shift$$constant, false); - %} - ins_pipe(ialu_mem_imm); -%} - -// Arithmetic Shift Right by 8-bit immediate -instruct sarI_mem_imm(memory dst, immI8 shift, rFlagsReg cr) -%{ - match(Set dst (StoreI dst (RShiftI (LoadI dst) shift))); - effect(KILL cr); - - format %{ "sarl $dst, $shift" %} - ins_encode %{ - __ sarl($dst$$Address, $shift$$constant); - %} - ins_pipe(ialu_mem_imm); -%} - -// Arithmetic Shift Right by variable -instruct sarI_rReg_CL(rRegI dst, rcx_RegI shift, rFlagsReg cr) -%{ - predicate(!VM_Version::supports_bmi2()); - match(Set dst (RShiftI dst shift)); - effect(KILL cr); - - format %{ "sarl $dst, $shift" %} - ins_encode %{ - __ sarl($dst$$Register); - %} - ins_pipe(ialu_reg_reg); -%} - -// Arithmetic Shift Right by variable -instruct sarI_mem_CL(memory dst, rcx_RegI shift, rFlagsReg cr) -%{ - predicate(!VM_Version::supports_bmi2()); - match(Set dst (StoreI dst (RShiftI (LoadI dst) shift))); - effect(KILL cr); - - format %{ "sarl $dst, $shift" %} - ins_encode %{ - __ sarl($dst$$Address); - %} - ins_pipe(ialu_mem_reg); -%} - -instruct sarI_rReg_rReg(rRegI dst, rRegI src, rRegI shift) -%{ - predicate(VM_Version::supports_bmi2()); - match(Set dst (RShiftI src shift)); - - format %{ "sarxl $dst, $src, $shift" %} - ins_encode %{ - __ sarxl($dst$$Register, $src$$Register, $shift$$Register); - %} - ins_pipe(ialu_reg_reg); -%} - -instruct sarI_mem_rReg(rRegI dst, memory src, rRegI shift) -%{ - predicate(VM_Version::supports_bmi2()); - match(Set dst (RShiftI (LoadI src) shift)); - ins_cost(175); - format %{ "sarxl $dst, $src, $shift" %} - ins_encode %{ - __ sarxl($dst$$Register, $src$$Address, $shift$$Register); - %} - ins_pipe(ialu_reg_mem); -%} - -// Logical Shift Right by 8-bit immediate -instruct shrI_rReg_imm(rRegI dst, immI8 shift, rFlagsReg cr) -%{ - predicate(!UseAPX); - match(Set dst (URShiftI dst shift)); - effect(KILL cr); - - format %{ "shrl $dst, $shift" %} - ins_encode %{ - __ shrl($dst$$Register, $shift$$constant); - %} - ins_pipe(ialu_reg); -%} - -// Logical Shift Right by 8-bit immediate -instruct shrI_rReg_imm_ndd(rRegI dst, rRegI src, immI8 shift, rFlagsReg cr) -%{ - predicate(UseAPX); - match(Set dst (URShiftI src shift)); - effect(KILL cr); - - format %{ "eshrl $dst, $src, $shift\t # int (ndd)" %} - ins_encode %{ - __ eshrl($dst$$Register, $src$$Register, $shift$$constant, false); - %} - ins_pipe(ialu_reg); -%} - -instruct shrI_rReg_mem_imm_ndd(rRegI dst, memory src, immI8 shift, rFlagsReg cr) -%{ - predicate(UseAPX); - match(Set dst (URShiftI (LoadI src) shift)); - effect(KILL cr); - - format %{ "eshrl $dst, $src, $shift\t # int (ndd)" %} - ins_encode %{ - __ eshrl($dst$$Register, $src$$Address, $shift$$constant, false); - %} - ins_pipe(ialu_reg); -%} - -// Logical Shift Right by 8-bit immediate -instruct shrI_mem_imm(memory dst, immI8 shift, rFlagsReg cr) -%{ - match(Set dst (StoreI dst (URShiftI (LoadI dst) shift))); - effect(KILL cr); - - format %{ "shrl $dst, $shift" %} - ins_encode %{ - __ shrl($dst$$Address, $shift$$constant); - %} - ins_pipe(ialu_mem_imm); -%} - -// Logical Shift Right by variable -instruct shrI_rReg_CL(rRegI dst, rcx_RegI shift, rFlagsReg cr) -%{ - predicate(!VM_Version::supports_bmi2()); - match(Set dst (URShiftI dst shift)); - effect(KILL cr); - - format %{ "shrl $dst, $shift" %} - ins_encode %{ - __ shrl($dst$$Register); - %} - ins_pipe(ialu_reg_reg); -%} - -// Logical Shift Right by variable -instruct shrI_mem_CL(memory dst, rcx_RegI shift, rFlagsReg cr) -%{ - predicate(!VM_Version::supports_bmi2()); - match(Set dst (StoreI dst (URShiftI (LoadI dst) shift))); - effect(KILL cr); - - format %{ "shrl $dst, $shift" %} - ins_encode %{ - __ shrl($dst$$Address); - %} - ins_pipe(ialu_mem_reg); -%} - -instruct shrI_rReg_rReg(rRegI dst, rRegI src, rRegI shift) -%{ - predicate(VM_Version::supports_bmi2()); - match(Set dst (URShiftI src shift)); - - format %{ "shrxl $dst, $src, $shift" %} - ins_encode %{ - __ shrxl($dst$$Register, $src$$Register, $shift$$Register); - %} - ins_pipe(ialu_reg_reg); -%} - -instruct shrI_mem_rReg(rRegI dst, memory src, rRegI shift) -%{ - predicate(VM_Version::supports_bmi2()); - match(Set dst (URShiftI (LoadI src) shift)); - ins_cost(175); - format %{ "shrxl $dst, $src, $shift" %} - ins_encode %{ - __ shrxl($dst$$Register, $src$$Address, $shift$$Register); - %} - ins_pipe(ialu_reg_mem); -%} - -// Long Shift Instructions -// Shift Left by one, two, three -instruct salL_rReg_immI2(rRegL dst, immI2 shift, rFlagsReg cr) -%{ - predicate(!UseAPX); - match(Set dst (LShiftL dst shift)); - effect(KILL cr); - - format %{ "salq $dst, $shift" %} - ins_encode %{ - __ salq($dst$$Register, $shift$$constant); - %} - ins_pipe(ialu_reg); -%} - -// Shift Left by one, two, three -instruct salL_rReg_immI2_ndd(rRegL dst, rRegL src, immI2 shift, rFlagsReg cr) -%{ - predicate(UseAPX); - match(Set dst (LShiftL src shift)); - effect(KILL cr); - - format %{ "esalq $dst, $src, $shift\t# long (ndd)" %} - ins_encode %{ - __ esalq($dst$$Register, $src$$Register, $shift$$constant, false); - %} - ins_pipe(ialu_reg); -%} - -// Shift Left by 8-bit immediate -instruct salL_rReg_imm(rRegL dst, immI8 shift, rFlagsReg cr) -%{ - predicate(!UseAPX); - match(Set dst (LShiftL dst shift)); - effect(KILL cr); - - format %{ "salq $dst, $shift" %} - ins_encode %{ - __ salq($dst$$Register, $shift$$constant); - %} - ins_pipe(ialu_reg); -%} - -// Shift Left by 8-bit immediate -instruct salL_rReg_imm_ndd(rRegL dst, rRegL src, immI8 shift, rFlagsReg cr) -%{ - predicate(UseAPX); - match(Set dst (LShiftL src shift)); - effect(KILL cr); - - format %{ "esalq $dst, $src, $shift\t# long (ndd)" %} - ins_encode %{ - __ esalq($dst$$Register, $src$$Register, $shift$$constant, false); - %} - ins_pipe(ialu_reg); -%} - -instruct salL_rReg_mem_imm_ndd(rRegL dst, memory src, immI8 shift, rFlagsReg cr) -%{ - predicate(UseAPX); - match(Set dst (LShiftL (LoadL src) shift)); - effect(KILL cr); - - format %{ "esalq $dst, $src, $shift\t# long (ndd)" %} - ins_encode %{ - __ esalq($dst$$Register, $src$$Address, $shift$$constant, false); - %} - ins_pipe(ialu_reg); -%} - -// Shift Left by 8-bit immediate -instruct salL_mem_imm(memory dst, immI8 shift, rFlagsReg cr) -%{ - match(Set dst (StoreL dst (LShiftL (LoadL dst) shift))); - effect(KILL cr); - - format %{ "salq $dst, $shift" %} - ins_encode %{ - __ salq($dst$$Address, $shift$$constant); - %} - ins_pipe(ialu_mem_imm); -%} - -// Shift Left by variable -instruct salL_rReg_CL(rRegL dst, rcx_RegI shift, rFlagsReg cr) -%{ - predicate(!VM_Version::supports_bmi2()); - match(Set dst (LShiftL dst shift)); - effect(KILL cr); - - format %{ "salq $dst, $shift" %} - ins_encode %{ - __ salq($dst$$Register); - %} - ins_pipe(ialu_reg_reg); -%} - -// Shift Left by variable -instruct salL_mem_CL(memory dst, rcx_RegI shift, rFlagsReg cr) -%{ - predicate(!VM_Version::supports_bmi2()); - match(Set dst (StoreL dst (LShiftL (LoadL dst) shift))); - effect(KILL cr); - - format %{ "salq $dst, $shift" %} - ins_encode %{ - __ salq($dst$$Address); - %} - ins_pipe(ialu_mem_reg); -%} - -instruct salL_rReg_rReg(rRegL dst, rRegL src, rRegI shift) -%{ - predicate(VM_Version::supports_bmi2()); - match(Set dst (LShiftL src shift)); - - format %{ "shlxq $dst, $src, $shift" %} - ins_encode %{ - __ shlxq($dst$$Register, $src$$Register, $shift$$Register); - %} - ins_pipe(ialu_reg_reg); -%} - -instruct salL_mem_rReg(rRegL dst, memory src, rRegI shift) -%{ - predicate(VM_Version::supports_bmi2()); - match(Set dst (LShiftL (LoadL src) shift)); - ins_cost(175); - format %{ "shlxq $dst, $src, $shift" %} - ins_encode %{ - __ shlxq($dst$$Register, $src$$Address, $shift$$Register); - %} - ins_pipe(ialu_reg_mem); -%} - -// Arithmetic Shift Right by 8-bit immediate -instruct sarL_rReg_imm(rRegL dst, immI shift, rFlagsReg cr) -%{ - predicate(!UseAPX); - match(Set dst (RShiftL dst shift)); - effect(KILL cr); - - format %{ "sarq $dst, $shift" %} - ins_encode %{ - __ sarq($dst$$Register, (unsigned char)($shift$$constant & 0x3F)); - %} - ins_pipe(ialu_mem_imm); -%} - -// Arithmetic Shift Right by 8-bit immediate -instruct sarL_rReg_imm_ndd(rRegL dst, rRegL src, immI shift, rFlagsReg cr) -%{ - predicate(UseAPX); - match(Set dst (RShiftL src shift)); - effect(KILL cr); - - format %{ "esarq $dst, $src, $shift\t# long (ndd)" %} - ins_encode %{ - __ esarq($dst$$Register, $src$$Register, (unsigned char)($shift$$constant & 0x3F), false); - %} - ins_pipe(ialu_mem_imm); -%} - -instruct sarL_rReg_mem_imm_ndd(rRegL dst, memory src, immI shift, rFlagsReg cr) -%{ - predicate(UseAPX); - match(Set dst (RShiftL (LoadL src) shift)); - effect(KILL cr); - - format %{ "esarq $dst, $src, $shift\t# long (ndd)" %} - ins_encode %{ - __ esarq($dst$$Register, $src$$Address, (unsigned char)($shift$$constant & 0x3F), false); - %} - ins_pipe(ialu_mem_imm); -%} - -// Arithmetic Shift Right by 8-bit immediate -instruct sarL_mem_imm(memory dst, immI shift, rFlagsReg cr) -%{ - match(Set dst (StoreL dst (RShiftL (LoadL dst) shift))); - effect(KILL cr); - - format %{ "sarq $dst, $shift" %} - ins_encode %{ - __ sarq($dst$$Address, (unsigned char)($shift$$constant & 0x3F)); - %} - ins_pipe(ialu_mem_imm); -%} - -// Arithmetic Shift Right by variable -instruct sarL_rReg_CL(rRegL dst, rcx_RegI shift, rFlagsReg cr) -%{ - predicate(!VM_Version::supports_bmi2()); - match(Set dst (RShiftL dst shift)); - effect(KILL cr); - - format %{ "sarq $dst, $shift" %} - ins_encode %{ - __ sarq($dst$$Register); - %} - ins_pipe(ialu_reg_reg); -%} - -// Arithmetic Shift Right by variable -instruct sarL_mem_CL(memory dst, rcx_RegI shift, rFlagsReg cr) -%{ - predicate(!VM_Version::supports_bmi2()); - match(Set dst (StoreL dst (RShiftL (LoadL dst) shift))); - effect(KILL cr); - - format %{ "sarq $dst, $shift" %} - ins_encode %{ - __ sarq($dst$$Address); - %} - ins_pipe(ialu_mem_reg); -%} - -instruct sarL_rReg_rReg(rRegL dst, rRegL src, rRegI shift) -%{ - predicate(VM_Version::supports_bmi2()); - match(Set dst (RShiftL src shift)); - - format %{ "sarxq $dst, $src, $shift" %} - ins_encode %{ - __ sarxq($dst$$Register, $src$$Register, $shift$$Register); - %} - ins_pipe(ialu_reg_reg); -%} - -instruct sarL_mem_rReg(rRegL dst, memory src, rRegI shift) -%{ - predicate(VM_Version::supports_bmi2()); - match(Set dst (RShiftL (LoadL src) shift)); - ins_cost(175); - format %{ "sarxq $dst, $src, $shift" %} - ins_encode %{ - __ sarxq($dst$$Register, $src$$Address, $shift$$Register); - %} - ins_pipe(ialu_reg_mem); -%} - -// Logical Shift Right by 8-bit immediate -instruct shrL_rReg_imm(rRegL dst, immI8 shift, rFlagsReg cr) -%{ - predicate(!UseAPX); - match(Set dst (URShiftL dst shift)); - effect(KILL cr); - - format %{ "shrq $dst, $shift" %} - ins_encode %{ - __ shrq($dst$$Register, $shift$$constant); - %} - ins_pipe(ialu_reg); -%} - -// Logical Shift Right by 8-bit immediate -instruct shrL_rReg_imm_ndd(rRegL dst, rRegL src, immI8 shift, rFlagsReg cr) -%{ - predicate(UseAPX); - match(Set dst (URShiftL src shift)); - effect(KILL cr); - - format %{ "eshrq $dst, $src, $shift\t# long (ndd)" %} - ins_encode %{ - __ eshrq($dst$$Register, $src$$Register, $shift$$constant, false); - %} - ins_pipe(ialu_reg); -%} - -instruct shrL_rReg_mem_imm_ndd(rRegL dst, memory src, immI8 shift, rFlagsReg cr) -%{ - predicate(UseAPX); - match(Set dst (URShiftL (LoadL src) shift)); - effect(KILL cr); - - format %{ "eshrq $dst, $src, $shift\t# long (ndd)" %} - ins_encode %{ - __ eshrq($dst$$Register, $src$$Address, $shift$$constant, false); - %} - ins_pipe(ialu_reg); -%} - -// Logical Shift Right by 8-bit immediate -instruct shrL_mem_imm(memory dst, immI8 shift, rFlagsReg cr) -%{ - match(Set dst (StoreL dst (URShiftL (LoadL dst) shift))); - effect(KILL cr); - - format %{ "shrq $dst, $shift" %} - ins_encode %{ - __ shrq($dst$$Address, $shift$$constant); - %} - ins_pipe(ialu_mem_imm); -%} - -// Logical Shift Right by variable -instruct shrL_rReg_CL(rRegL dst, rcx_RegI shift, rFlagsReg cr) -%{ - predicate(!VM_Version::supports_bmi2()); - match(Set dst (URShiftL dst shift)); - effect(KILL cr); - - format %{ "shrq $dst, $shift" %} - ins_encode %{ - __ shrq($dst$$Register); - %} - ins_pipe(ialu_reg_reg); -%} - -// Logical Shift Right by variable -instruct shrL_mem_CL(memory dst, rcx_RegI shift, rFlagsReg cr) -%{ - predicate(!VM_Version::supports_bmi2()); - match(Set dst (StoreL dst (URShiftL (LoadL dst) shift))); - effect(KILL cr); - - format %{ "shrq $dst, $shift" %} - ins_encode %{ - __ shrq($dst$$Address); - %} - ins_pipe(ialu_mem_reg); -%} - -instruct shrL_rReg_rReg(rRegL dst, rRegL src, rRegI shift) -%{ - predicate(VM_Version::supports_bmi2()); - match(Set dst (URShiftL src shift)); - - format %{ "shrxq $dst, $src, $shift" %} - ins_encode %{ - __ shrxq($dst$$Register, $src$$Register, $shift$$Register); - %} - ins_pipe(ialu_reg_reg); -%} - -instruct shrL_mem_rReg(rRegL dst, memory src, rRegI shift) -%{ - predicate(VM_Version::supports_bmi2()); - match(Set dst (URShiftL (LoadL src) shift)); - ins_cost(175); - format %{ "shrxq $dst, $src, $shift" %} - ins_encode %{ - __ shrxq($dst$$Register, $src$$Address, $shift$$Register); - %} - ins_pipe(ialu_reg_mem); -%} - -// Logical Shift Right by 24, followed by Arithmetic Shift Left by 24. -// This idiom is used by the compiler for the i2b bytecode. -instruct i2b(rRegI dst, rRegI src, immI_24 twentyfour) -%{ - match(Set dst (RShiftI (LShiftI src twentyfour) twentyfour)); - - format %{ "movsbl $dst, $src\t# i2b" %} - ins_encode %{ - __ movsbl($dst$$Register, $src$$Register); - %} - ins_pipe(ialu_reg_reg); -%} - -// Logical Shift Right by 16, followed by Arithmetic Shift Left by 16. -// This idiom is used by the compiler the i2s bytecode. -instruct i2s(rRegI dst, rRegI src, immI_16 sixteen) -%{ - match(Set dst (RShiftI (LShiftI src sixteen) sixteen)); - - format %{ "movswl $dst, $src\t# i2s" %} - ins_encode %{ - __ movswl($dst$$Register, $src$$Register); - %} - ins_pipe(ialu_reg_reg); -%} - -// ROL/ROR instructions - -// Rotate left by constant. -instruct rolI_immI8_legacy(rRegI dst, immI8 shift, rFlagsReg cr) -%{ - predicate(!VM_Version::supports_bmi2() && n->bottom_type()->basic_type() == T_INT); - match(Set dst (RotateLeft dst shift)); - effect(KILL cr); - format %{ "roll $dst, $shift" %} - ins_encode %{ - __ roll($dst$$Register, $shift$$constant); - %} - ins_pipe(ialu_reg); -%} - -instruct rolI_immI8(rRegI dst, rRegI src, immI8 shift) -%{ - predicate(!UseAPX && VM_Version::supports_bmi2() && n->bottom_type()->basic_type() == T_INT); - match(Set dst (RotateLeft src shift)); - format %{ "rolxl $dst, $src, $shift" %} - ins_encode %{ - int shift = 32 - ($shift$$constant & 31); - __ rorxl($dst$$Register, $src$$Register, shift); - %} - ins_pipe(ialu_reg_reg); -%} - -instruct rolI_mem_immI8(rRegI dst, memory src, immI8 shift) -%{ - predicate(VM_Version::supports_bmi2() && n->bottom_type()->basic_type() == T_INT); - match(Set dst (RotateLeft (LoadI src) shift)); - ins_cost(175); - format %{ "rolxl $dst, $src, $shift" %} - ins_encode %{ - int shift = 32 - ($shift$$constant & 31); - __ rorxl($dst$$Register, $src$$Address, shift); - %} - ins_pipe(ialu_reg_mem); -%} - -// Rotate Left by variable -instruct rolI_rReg_Var(rRegI dst, rcx_RegI shift, rFlagsReg cr) -%{ - predicate(!UseAPX && n->bottom_type()->basic_type() == T_INT); - match(Set dst (RotateLeft dst shift)); - effect(KILL cr); - format %{ "roll $dst, $shift" %} - ins_encode %{ - __ roll($dst$$Register); - %} - ins_pipe(ialu_reg_reg); -%} - -// Rotate Left by variable -instruct rolI_rReg_Var_ndd(rRegI dst, rRegI src, rcx_RegI shift, rFlagsReg cr) -%{ - predicate(UseAPX && n->bottom_type()->basic_type() == T_INT); - match(Set dst (RotateLeft src shift)); - effect(KILL cr); - - format %{ "eroll $dst, $src, $shift\t# rotate left (int ndd)" %} - ins_encode %{ - __ eroll($dst$$Register, $src$$Register, false); - %} - ins_pipe(ialu_reg_reg); -%} - -// Rotate Right by constant. -instruct rorI_immI8_legacy(rRegI dst, immI8 shift, rFlagsReg cr) -%{ - predicate(!VM_Version::supports_bmi2() && n->bottom_type()->basic_type() == T_INT); - match(Set dst (RotateRight dst shift)); - effect(KILL cr); - format %{ "rorl $dst, $shift" %} - ins_encode %{ - __ rorl($dst$$Register, $shift$$constant); - %} - ins_pipe(ialu_reg); -%} - -// Rotate Right by constant. -instruct rorI_immI8(rRegI dst, rRegI src, immI8 shift) -%{ - predicate(!UseAPX && VM_Version::supports_bmi2() && n->bottom_type()->basic_type() == T_INT); - match(Set dst (RotateRight src shift)); - format %{ "rorxl $dst, $src, $shift" %} - ins_encode %{ - __ rorxl($dst$$Register, $src$$Register, $shift$$constant); - %} - ins_pipe(ialu_reg_reg); -%} - -instruct rorI_mem_immI8(rRegI dst, memory src, immI8 shift) -%{ - predicate(VM_Version::supports_bmi2() && n->bottom_type()->basic_type() == T_INT); - match(Set dst (RotateRight (LoadI src) shift)); - ins_cost(175); - format %{ "rorxl $dst, $src, $shift" %} - ins_encode %{ - __ rorxl($dst$$Register, $src$$Address, $shift$$constant); - %} - ins_pipe(ialu_reg_mem); -%} - -// Rotate Right by variable -instruct rorI_rReg_Var(rRegI dst, rcx_RegI shift, rFlagsReg cr) -%{ - predicate(!UseAPX && n->bottom_type()->basic_type() == T_INT); - match(Set dst (RotateRight dst shift)); - effect(KILL cr); - format %{ "rorl $dst, $shift" %} - ins_encode %{ - __ rorl($dst$$Register); - %} - ins_pipe(ialu_reg_reg); -%} - -// Rotate Right by variable -instruct rorI_rReg_Var_ndd(rRegI dst, rRegI src, rcx_RegI shift, rFlagsReg cr) -%{ - predicate(UseAPX && n->bottom_type()->basic_type() == T_INT); - match(Set dst (RotateRight src shift)); - effect(KILL cr); - - format %{ "erorl $dst, $src, $shift\t# rotate right(int ndd)" %} - ins_encode %{ - __ erorl($dst$$Register, $src$$Register, false); - %} - ins_pipe(ialu_reg_reg); -%} - -// Rotate Left by constant. -instruct rolL_immI8_legacy(rRegL dst, immI8 shift, rFlagsReg cr) -%{ - predicate(!VM_Version::supports_bmi2() && n->bottom_type()->basic_type() == T_LONG); - match(Set dst (RotateLeft dst shift)); - effect(KILL cr); - format %{ "rolq $dst, $shift" %} - ins_encode %{ - __ rolq($dst$$Register, $shift$$constant); - %} - ins_pipe(ialu_reg); -%} - -instruct rolL_immI8(rRegL dst, rRegL src, immI8 shift) -%{ - predicate(!UseAPX && VM_Version::supports_bmi2() && n->bottom_type()->basic_type() == T_LONG); - match(Set dst (RotateLeft src shift)); - format %{ "rolxq $dst, $src, $shift" %} - ins_encode %{ - int shift = 64 - ($shift$$constant & 63); - __ rorxq($dst$$Register, $src$$Register, shift); - %} - ins_pipe(ialu_reg_reg); -%} - -instruct rolL_mem_immI8(rRegL dst, memory src, immI8 shift) -%{ - predicate(VM_Version::supports_bmi2() && n->bottom_type()->basic_type() == T_LONG); - match(Set dst (RotateLeft (LoadL src) shift)); - ins_cost(175); - format %{ "rolxq $dst, $src, $shift" %} - ins_encode %{ - int shift = 64 - ($shift$$constant & 63); - __ rorxq($dst$$Register, $src$$Address, shift); - %} - ins_pipe(ialu_reg_mem); -%} - -// Rotate Left by variable -instruct rolL_rReg_Var(rRegL dst, rcx_RegI shift, rFlagsReg cr) -%{ - predicate(!UseAPX && n->bottom_type()->basic_type() == T_LONG); - match(Set dst (RotateLeft dst shift)); - effect(KILL cr); - format %{ "rolq $dst, $shift" %} - ins_encode %{ - __ rolq($dst$$Register); - %} - ins_pipe(ialu_reg_reg); -%} - -// Rotate Left by variable -instruct rolL_rReg_Var_ndd(rRegL dst, rRegL src, rcx_RegI shift, rFlagsReg cr) -%{ - predicate(UseAPX && n->bottom_type()->basic_type() == T_LONG); - match(Set dst (RotateLeft src shift)); - effect(KILL cr); - - format %{ "erolq $dst, $src, $shift\t# rotate left(long ndd)" %} - ins_encode %{ - __ erolq($dst$$Register, $src$$Register, false); - %} - ins_pipe(ialu_reg_reg); -%} - -// Rotate Right by constant. -instruct rorL_immI8_legacy(rRegL dst, immI8 shift, rFlagsReg cr) -%{ - predicate(!VM_Version::supports_bmi2() && n->bottom_type()->basic_type() == T_LONG); - match(Set dst (RotateRight dst shift)); - effect(KILL cr); - format %{ "rorq $dst, $shift" %} - ins_encode %{ - __ rorq($dst$$Register, $shift$$constant); - %} - ins_pipe(ialu_reg); -%} - -// Rotate Right by constant -instruct rorL_immI8(rRegL dst, rRegL src, immI8 shift) -%{ - predicate(VM_Version::supports_bmi2() && n->bottom_type()->basic_type() == T_LONG); - match(Set dst (RotateRight src shift)); - format %{ "rorxq $dst, $src, $shift" %} - ins_encode %{ - __ rorxq($dst$$Register, $src$$Register, $shift$$constant); - %} - ins_pipe(ialu_reg_reg); -%} - -instruct rorL_mem_immI8(rRegL dst, memory src, immI8 shift) -%{ - predicate(VM_Version::supports_bmi2() && n->bottom_type()->basic_type() == T_LONG); - match(Set dst (RotateRight (LoadL src) shift)); - ins_cost(175); - format %{ "rorxq $dst, $src, $shift" %} - ins_encode %{ - __ rorxq($dst$$Register, $src$$Address, $shift$$constant); - %} - ins_pipe(ialu_reg_mem); -%} - -// Rotate Right by variable -instruct rorL_rReg_Var(rRegL dst, rcx_RegI shift, rFlagsReg cr) -%{ - predicate(!UseAPX && n->bottom_type()->basic_type() == T_LONG); - match(Set dst (RotateRight dst shift)); - effect(KILL cr); - format %{ "rorq $dst, $shift" %} - ins_encode %{ - __ rorq($dst$$Register); - %} - ins_pipe(ialu_reg_reg); -%} - -// Rotate Right by variable -instruct rorL_rReg_Var_ndd(rRegL dst, rRegL src, rcx_RegI shift, rFlagsReg cr) -%{ - predicate(UseAPX && n->bottom_type()->basic_type() == T_LONG); - match(Set dst (RotateRight src shift)); - effect(KILL cr); - - format %{ "erorq $dst, $src, $shift\t# rotate right(long ndd)" %} - ins_encode %{ - __ erorq($dst$$Register, $src$$Register, false); - %} - ins_pipe(ialu_reg_reg); -%} - -//----------------------------- CompressBits/ExpandBits ------------------------ - -instruct compressBitsL_reg(rRegL dst, rRegL src, rRegL mask) %{ - predicate(n->bottom_type()->isa_long()); - match(Set dst (CompressBits src mask)); - format %{ "pextq $dst, $src, $mask\t! parallel bit extract" %} - ins_encode %{ - __ pextq($dst$$Register, $src$$Register, $mask$$Register); - %} - ins_pipe( pipe_slow ); -%} - -instruct expandBitsL_reg(rRegL dst, rRegL src, rRegL mask) %{ - predicate(n->bottom_type()->isa_long()); - match(Set dst (ExpandBits src mask)); - format %{ "pdepq $dst, $src, $mask\t! parallel bit deposit" %} - ins_encode %{ - __ pdepq($dst$$Register, $src$$Register, $mask$$Register); - %} - ins_pipe( pipe_slow ); -%} - -instruct compressBitsL_mem(rRegL dst, rRegL src, memory mask) %{ - predicate(n->bottom_type()->isa_long()); - match(Set dst (CompressBits src (LoadL mask))); - format %{ "pextq $dst, $src, $mask\t! parallel bit extract" %} - ins_encode %{ - __ pextq($dst$$Register, $src$$Register, $mask$$Address); - %} - ins_pipe( pipe_slow ); -%} - -instruct expandBitsL_mem(rRegL dst, rRegL src, memory mask) %{ - predicate(n->bottom_type()->isa_long()); - match(Set dst (ExpandBits src (LoadL mask))); - format %{ "pdepq $dst, $src, $mask\t! parallel bit deposit" %} - ins_encode %{ - __ pdepq($dst$$Register, $src$$Register, $mask$$Address); - %} - ins_pipe( pipe_slow ); -%} - - -// Logical Instructions - -// Integer Logical Instructions - -// And Instructions -// And Register with Register -instruct andI_rReg(rRegI dst, rRegI src, rFlagsReg cr) -%{ - predicate(!UseAPX); - match(Set dst (AndI dst src)); - effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); - - format %{ "andl $dst, $src\t# int" %} - ins_encode %{ - __ andl($dst$$Register, $src$$Register); - %} - ins_pipe(ialu_reg_reg); -%} - -// And Register with Register using New Data Destination (NDD) -instruct andI_rReg_ndd(rRegI dst, rRegI src1, rRegI src2, rFlagsReg cr) -%{ - predicate(UseAPX); - match(Set dst (AndI src1 src2)); - effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); - - format %{ "eandl $dst, $src1, $src2\t# int ndd" %} - ins_encode %{ - __ eandl($dst$$Register, $src1$$Register, $src2$$Register, false); - - %} - ins_pipe(ialu_reg_reg); -%} - -// And Register with Immediate 255 -instruct andI_rReg_imm255(rRegI dst, rRegI src, immI_255 mask) -%{ - match(Set dst (AndI src mask)); - - format %{ "movzbl $dst, $src\t# int & 0xFF" %} - ins_encode %{ - __ movzbl($dst$$Register, $src$$Register); - %} - ins_pipe(ialu_reg); -%} - -// And Register with Immediate 255 and promote to long -instruct andI2L_rReg_imm255(rRegL dst, rRegI src, immI_255 mask) -%{ - match(Set dst (ConvI2L (AndI src mask))); - - format %{ "movzbl $dst, $src\t# int & 0xFF -> long" %} - ins_encode %{ - __ movzbl($dst$$Register, $src$$Register); - %} - ins_pipe(ialu_reg); -%} - -// And Register with Immediate 65535 -instruct andI_rReg_imm65535(rRegI dst, rRegI src, immI_65535 mask) -%{ - match(Set dst (AndI src mask)); - - format %{ "movzwl $dst, $src\t# int & 0xFFFF" %} - ins_encode %{ - __ movzwl($dst$$Register, $src$$Register); - %} - ins_pipe(ialu_reg); -%} - -// And Register with Immediate 65535 and promote to long -instruct andI2L_rReg_imm65535(rRegL dst, rRegI src, immI_65535 mask) -%{ - match(Set dst (ConvI2L (AndI src mask))); - - format %{ "movzwl $dst, $src\t# int & 0xFFFF -> long" %} - ins_encode %{ - __ movzwl($dst$$Register, $src$$Register); - %} - ins_pipe(ialu_reg); -%} - -// Can skip int2long conversions after AND with small bitmask -instruct convI2LAndI_reg_immIbitmask(rRegL dst, rRegI src, immI_Pow2M1 mask, rRegI tmp, rFlagsReg cr) -%{ - predicate(VM_Version::supports_bmi2()); - ins_cost(125); - effect(TEMP tmp, KILL cr); - match(Set dst (ConvI2L (AndI src mask))); - format %{ "bzhiq $dst, $src, $mask \t# using $tmp as TEMP, int & immI_Pow2M1 -> long" %} - ins_encode %{ - __ movl($tmp$$Register, exact_log2($mask$$constant + 1)); - __ bzhiq($dst$$Register, $src$$Register, $tmp$$Register); - %} - ins_pipe(ialu_reg_reg); -%} - -// And Register with Immediate -instruct andI_rReg_imm(rRegI dst, immI src, rFlagsReg cr) -%{ - predicate(!UseAPX); - match(Set dst (AndI dst src)); - effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); - - format %{ "andl $dst, $src\t# int" %} - ins_encode %{ - __ andl($dst$$Register, $src$$constant); - %} - ins_pipe(ialu_reg); -%} - -instruct andI_rReg_rReg_imm_ndd(rRegI dst, rRegI src1, immI src2, rFlagsReg cr) -%{ - predicate(UseAPX); - match(Set dst (AndI src1 src2)); - effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); - - format %{ "eandl $dst, $src1, $src2\t# int ndd" %} - ins_encode %{ - __ eandl($dst$$Register, $src1$$Register, $src2$$constant, false); - %} - ins_pipe(ialu_reg); -%} - -instruct andI_rReg_mem_imm_ndd(rRegI dst, memory src1, immI src2, rFlagsReg cr) -%{ - predicate(UseAPX); - match(Set dst (AndI (LoadI src1) src2)); - effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); - - format %{ "eandl $dst, $src1, $src2\t# int ndd" %} - ins_encode %{ - __ eandl($dst$$Register, $src1$$Address, $src2$$constant, false); - %} - ins_pipe(ialu_reg); -%} - -// And Register with Memory -instruct andI_rReg_mem(rRegI dst, memory src, rFlagsReg cr) -%{ - predicate(!UseAPX); - match(Set dst (AndI dst (LoadI src))); - effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); - - ins_cost(150); - format %{ "andl $dst, $src\t# int" %} - ins_encode %{ - __ andl($dst$$Register, $src$$Address); - %} - ins_pipe(ialu_reg_mem); -%} - -instruct andI_rReg_rReg_mem_ndd(rRegI dst, rRegI src1, memory src2, rFlagsReg cr) -%{ - predicate(UseAPX); - match(Set dst (AndI src1 (LoadI src2))); - effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); - - ins_cost(150); - format %{ "eandl $dst, $src1, $src2\t# int ndd" %} - ins_encode %{ - __ eandl($dst$$Register, $src1$$Register, $src2$$Address, false); - %} - ins_pipe(ialu_reg_mem); -%} - -// And Memory with Register -instruct andB_mem_rReg(memory dst, rRegI src, rFlagsReg cr) -%{ - match(Set dst (StoreB dst (AndI (LoadB dst) src))); - effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); - - ins_cost(150); - format %{ "andb $dst, $src\t# byte" %} - ins_encode %{ - __ andb($dst$$Address, $src$$Register); - %} - ins_pipe(ialu_mem_reg); -%} - -instruct andI_mem_rReg(memory dst, rRegI src, rFlagsReg cr) -%{ - match(Set dst (StoreI dst (AndI (LoadI dst) src))); - effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); - - ins_cost(150); - format %{ "andl $dst, $src\t# int" %} - ins_encode %{ - __ andl($dst$$Address, $src$$Register); - %} - ins_pipe(ialu_mem_reg); -%} - -// And Memory with Immediate -instruct andI_mem_imm(memory dst, immI src, rFlagsReg cr) -%{ - match(Set dst (StoreI dst (AndI (LoadI dst) src))); - effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); - - ins_cost(125); - format %{ "andl $dst, $src\t# int" %} - ins_encode %{ - __ andl($dst$$Address, $src$$constant); - %} - ins_pipe(ialu_mem_imm); -%} - -// BMI1 instructions -instruct andnI_rReg_rReg_mem(rRegI dst, rRegI src1, memory src2, immI_M1 minus_1, rFlagsReg cr) %{ - match(Set dst (AndI (XorI src1 minus_1) (LoadI src2))); - predicate(UseBMI1Instructions); - effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); - - ins_cost(125); - format %{ "andnl $dst, $src1, $src2" %} - - ins_encode %{ - __ andnl($dst$$Register, $src1$$Register, $src2$$Address); - %} - ins_pipe(ialu_reg_mem); -%} - -instruct andnI_rReg_rReg_rReg(rRegI dst, rRegI src1, rRegI src2, immI_M1 minus_1, rFlagsReg cr) %{ - match(Set dst (AndI (XorI src1 minus_1) src2)); - predicate(UseBMI1Instructions); - effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); - - format %{ "andnl $dst, $src1, $src2" %} - - ins_encode %{ - __ andnl($dst$$Register, $src1$$Register, $src2$$Register); - %} - ins_pipe(ialu_reg); -%} - -instruct blsiI_rReg_rReg(rRegI dst, rRegI src, immI_0 imm_zero, rFlagsReg cr) %{ - match(Set dst (AndI (SubI imm_zero src) src)); - predicate(UseBMI1Instructions); - effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_clears_overflow_flag); - - format %{ "blsil $dst, $src" %} - - ins_encode %{ - __ blsil($dst$$Register, $src$$Register); - %} - ins_pipe(ialu_reg); -%} - -instruct blsiI_rReg_mem(rRegI dst, memory src, immI_0 imm_zero, rFlagsReg cr) %{ - match(Set dst (AndI (SubI imm_zero (LoadI src) ) (LoadI src) )); - predicate(UseBMI1Instructions); - effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_clears_overflow_flag); - - ins_cost(125); - format %{ "blsil $dst, $src" %} - - ins_encode %{ - __ blsil($dst$$Register, $src$$Address); - %} - ins_pipe(ialu_reg_mem); -%} - -instruct blsmskI_rReg_mem(rRegI dst, memory src, immI_M1 minus_1, rFlagsReg cr) -%{ - match(Set dst (XorI (AddI (LoadI src) minus_1) (LoadI src) ) ); - predicate(UseBMI1Instructions); - effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_clears_zero_flag, PD::Flag_clears_overflow_flag); - - ins_cost(125); - format %{ "blsmskl $dst, $src" %} - - ins_encode %{ - __ blsmskl($dst$$Register, $src$$Address); - %} - ins_pipe(ialu_reg_mem); -%} - -instruct blsmskI_rReg_rReg(rRegI dst, rRegI src, immI_M1 minus_1, rFlagsReg cr) -%{ - match(Set dst (XorI (AddI src minus_1) src)); - predicate(UseBMI1Instructions); - effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_clears_zero_flag, PD::Flag_clears_overflow_flag); - - format %{ "blsmskl $dst, $src" %} - - ins_encode %{ - __ blsmskl($dst$$Register, $src$$Register); - %} - - ins_pipe(ialu_reg); -%} - -instruct blsrI_rReg_rReg(rRegI dst, rRegI src, immI_M1 minus_1, rFlagsReg cr) -%{ - match(Set dst (AndI (AddI src minus_1) src) ); - predicate(UseBMI1Instructions); - effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_clears_overflow_flag); - - format %{ "blsrl $dst, $src" %} - - ins_encode %{ - __ blsrl($dst$$Register, $src$$Register); - %} - - ins_pipe(ialu_reg_mem); -%} - -instruct blsrI_rReg_mem(rRegI dst, memory src, immI_M1 minus_1, rFlagsReg cr) -%{ - match(Set dst (AndI (AddI (LoadI src) minus_1) (LoadI src) ) ); - predicate(UseBMI1Instructions); - effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_clears_overflow_flag); - - ins_cost(125); - format %{ "blsrl $dst, $src" %} - - ins_encode %{ - __ blsrl($dst$$Register, $src$$Address); - %} - - ins_pipe(ialu_reg); -%} - -// Or Instructions -// Or Register with Register -instruct orI_rReg(rRegI dst, rRegI src, rFlagsReg cr) -%{ - predicate(!UseAPX); - match(Set dst (OrI dst src)); - effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); - - format %{ "orl $dst, $src\t# int" %} - ins_encode %{ - __ orl($dst$$Register, $src$$Register); - %} - ins_pipe(ialu_reg_reg); -%} - -// Or Register with Register using New Data Destination (NDD) -instruct orI_rReg_ndd(rRegI dst, rRegI src1, rRegI src2, rFlagsReg cr) -%{ - predicate(UseAPX); - match(Set dst (OrI src1 src2)); - effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); - - format %{ "eorl $dst, $src1, $src2\t# int ndd" %} - ins_encode %{ - __ eorl($dst$$Register, $src1$$Register, $src2$$Register, false); - %} - ins_pipe(ialu_reg_reg); -%} - -// Or Register with Immediate -instruct orI_rReg_imm(rRegI dst, immI src, rFlagsReg cr) -%{ - predicate(!UseAPX); - match(Set dst (OrI dst src)); - effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); - - format %{ "orl $dst, $src\t# int" %} - ins_encode %{ - __ orl($dst$$Register, $src$$constant); - %} - ins_pipe(ialu_reg); -%} - -instruct orI_rReg_rReg_imm_ndd(rRegI dst, rRegI src1, immI src2, rFlagsReg cr) -%{ - predicate(UseAPX); - match(Set dst (OrI src1 src2)); - effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); - - format %{ "eorl $dst, $src1, $src2\t# int ndd" %} - ins_encode %{ - __ eorl($dst$$Register, $src1$$Register, $src2$$constant, false); - %} - ins_pipe(ialu_reg); -%} - -instruct orI_rReg_imm_rReg_ndd(rRegI dst, immI src1, rRegI src2, rFlagsReg cr) -%{ - predicate(UseAPX); - match(Set dst (OrI src1 src2)); - effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); - - format %{ "eorl $dst, $src2, $src1\t# int ndd" %} - ins_encode %{ - __ eorl($dst$$Register, $src2$$Register, $src1$$constant, false); - %} - ins_pipe(ialu_reg); -%} - -instruct orI_rReg_mem_imm_ndd(rRegI dst, memory src1, immI src2, rFlagsReg cr) -%{ - predicate(UseAPX); - match(Set dst (OrI (LoadI src1) src2)); - effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); - - format %{ "eorl $dst, $src1, $src2\t# int ndd" %} - ins_encode %{ - __ eorl($dst$$Register, $src1$$Address, $src2$$constant, false); - %} - ins_pipe(ialu_reg); -%} - -// Or Register with Memory -instruct orI_rReg_mem(rRegI dst, memory src, rFlagsReg cr) -%{ - predicate(!UseAPX); - match(Set dst (OrI dst (LoadI src))); - effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); - - ins_cost(150); - format %{ "orl $dst, $src\t# int" %} - ins_encode %{ - __ orl($dst$$Register, $src$$Address); - %} - ins_pipe(ialu_reg_mem); -%} - -instruct orI_rReg_rReg_mem_ndd(rRegI dst, rRegI src1, memory src2, rFlagsReg cr) -%{ - predicate(UseAPX); - match(Set dst (OrI src1 (LoadI src2))); - effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); - - ins_cost(150); - format %{ "eorl $dst, $src1, $src2\t# int ndd" %} - ins_encode %{ - __ eorl($dst$$Register, $src1$$Register, $src2$$Address, false); - %} - ins_pipe(ialu_reg_mem); -%} - -// Or Memory with Register -instruct orB_mem_rReg(memory dst, rRegI src, rFlagsReg cr) -%{ - match(Set dst (StoreB dst (OrI (LoadB dst) src))); - effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); - - ins_cost(150); - format %{ "orb $dst, $src\t# byte" %} - ins_encode %{ - __ orb($dst$$Address, $src$$Register); - %} - ins_pipe(ialu_mem_reg); -%} - -instruct orI_mem_rReg(memory dst, rRegI src, rFlagsReg cr) -%{ - match(Set dst (StoreI dst (OrI (LoadI dst) src))); - effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); - - ins_cost(150); - format %{ "orl $dst, $src\t# int" %} - ins_encode %{ - __ orl($dst$$Address, $src$$Register); - %} - ins_pipe(ialu_mem_reg); -%} - -// Or Memory with Immediate -instruct orI_mem_imm(memory dst, immI src, rFlagsReg cr) -%{ - match(Set dst (StoreI dst (OrI (LoadI dst) src))); - effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); - - ins_cost(125); - format %{ "orl $dst, $src\t# int" %} - ins_encode %{ - __ orl($dst$$Address, $src$$constant); - %} - ins_pipe(ialu_mem_imm); -%} - -// Xor Instructions -// Xor Register with Register -instruct xorI_rReg(rRegI dst, rRegI src, rFlagsReg cr) -%{ - predicate(!UseAPX); - match(Set dst (XorI dst src)); - effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); - - format %{ "xorl $dst, $src\t# int" %} - ins_encode %{ - __ xorl($dst$$Register, $src$$Register); - %} - ins_pipe(ialu_reg_reg); -%} - -// Xor Register with Register using New Data Destination (NDD) -instruct xorI_rReg_ndd(rRegI dst, rRegI src1, rRegI src2, rFlagsReg cr) -%{ - predicate(UseAPX); - match(Set dst (XorI src1 src2)); - effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); - - format %{ "exorl $dst, $src1, $src2\t# int ndd" %} - ins_encode %{ - __ exorl($dst$$Register, $src1$$Register, $src2$$Register, false); - %} - ins_pipe(ialu_reg_reg); -%} - -// Xor Register with Immediate -1 -instruct xorI_rReg_im1(rRegI dst, immI_M1 imm) -%{ - predicate(!UseAPX); - match(Set dst (XorI dst imm)); - - format %{ "notl $dst" %} - ins_encode %{ - __ notl($dst$$Register); - %} - ins_pipe(ialu_reg); -%} - -instruct xorI_rReg_im1_ndd(rRegI dst, rRegI src, immI_M1 imm) -%{ - match(Set dst (XorI src imm)); - predicate(UseAPX); - - format %{ "enotl $dst, $src" %} - ins_encode %{ - __ enotl($dst$$Register, $src$$Register); - %} - ins_pipe(ialu_reg); -%} - -// Xor Register with Immediate -instruct xorI_rReg_imm(rRegI dst, immI src, rFlagsReg cr) -%{ - // Strict predicate check to make selection of xorI_rReg_im1 cost agnostic if immI src is -1. - predicate(!UseAPX && n->in(2)->bottom_type()->is_int()->get_con() != -1); - match(Set dst (XorI dst src)); - effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); - - format %{ "xorl $dst, $src\t# int" %} - ins_encode %{ - __ xorl($dst$$Register, $src$$constant); - %} - ins_pipe(ialu_reg); -%} - -instruct xorI_rReg_rReg_imm_ndd(rRegI dst, rRegI src1, immI src2, rFlagsReg cr) -%{ - // Strict predicate check to make selection of xorI_rReg_im1_ndd cost agnostic if immI src2 is -1. - predicate(UseAPX && n->in(2)->bottom_type()->is_int()->get_con() != -1); - match(Set dst (XorI src1 src2)); - effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); - - format %{ "exorl $dst, $src1, $src2\t# int ndd" %} - ins_encode %{ - __ exorl($dst$$Register, $src1$$Register, $src2$$constant, false); - %} - ins_pipe(ialu_reg); -%} - -// Xor Memory with Immediate -instruct xorI_rReg_mem_imm_ndd(rRegI dst, memory src1, immI src2, rFlagsReg cr) -%{ - predicate(UseAPX); - match(Set dst (XorI (LoadI src1) src2)); - effect(KILL cr); - ins_cost(150); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); - - format %{ "exorl $dst, $src1, $src2\t# int ndd" %} - ins_encode %{ - __ exorl($dst$$Register, $src1$$Address, $src2$$constant, false); - %} - ins_pipe(ialu_reg); -%} - -// Xor Register with Memory -instruct xorI_rReg_mem(rRegI dst, memory src, rFlagsReg cr) -%{ - predicate(!UseAPX); - match(Set dst (XorI dst (LoadI src))); - effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); - - ins_cost(150); - format %{ "xorl $dst, $src\t# int" %} - ins_encode %{ - __ xorl($dst$$Register, $src$$Address); - %} - ins_pipe(ialu_reg_mem); -%} - -instruct xorI_rReg_rReg_mem_ndd(rRegI dst, rRegI src1, memory src2, rFlagsReg cr) -%{ - predicate(UseAPX); - match(Set dst (XorI src1 (LoadI src2))); - effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); - - ins_cost(150); - format %{ "exorl $dst, $src1, $src2\t# int ndd" %} - ins_encode %{ - __ exorl($dst$$Register, $src1$$Register, $src2$$Address, false); - %} - ins_pipe(ialu_reg_mem); -%} - -// Xor Memory with Register -instruct xorB_mem_rReg(memory dst, rRegI src, rFlagsReg cr) -%{ - match(Set dst (StoreB dst (XorI (LoadB dst) src))); - effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); - - ins_cost(150); - format %{ "xorb $dst, $src\t# byte" %} - ins_encode %{ - __ xorb($dst$$Address, $src$$Register); - %} - ins_pipe(ialu_mem_reg); -%} - -instruct xorI_mem_rReg(memory dst, rRegI src, rFlagsReg cr) -%{ - match(Set dst (StoreI dst (XorI (LoadI dst) src))); - effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); - - ins_cost(150); - format %{ "xorl $dst, $src\t# int" %} - ins_encode %{ - __ xorl($dst$$Address, $src$$Register); - %} - ins_pipe(ialu_mem_reg); -%} - -// Xor Memory with Immediate -instruct xorI_mem_imm(memory dst, immI src, rFlagsReg cr) -%{ - match(Set dst (StoreI dst (XorI (LoadI dst) src))); - effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); - - ins_cost(125); - format %{ "xorl $dst, $src\t# int" %} - ins_encode %{ - __ xorl($dst$$Address, $src$$constant); - %} - ins_pipe(ialu_mem_imm); -%} - - -// Long Logical Instructions - -// And Instructions -// And Register with Register -instruct andL_rReg(rRegL dst, rRegL src, rFlagsReg cr) -%{ - predicate(!UseAPX); - match(Set dst (AndL dst src)); - effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); - - format %{ "andq $dst, $src\t# long" %} - ins_encode %{ - __ andq($dst$$Register, $src$$Register); - %} - ins_pipe(ialu_reg_reg); -%} - -// And Register with Register using New Data Destination (NDD) -instruct andL_rReg_ndd(rRegL dst, rRegL src1, rRegL src2, rFlagsReg cr) -%{ - predicate(UseAPX); - match(Set dst (AndL src1 src2)); - effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); - - format %{ "eandq $dst, $src1, $src2\t# long ndd" %} - ins_encode %{ - __ eandq($dst$$Register, $src1$$Register, $src2$$Register, false); - - %} - ins_pipe(ialu_reg_reg); -%} - -// And Register with Immediate 255 -instruct andL_rReg_imm255(rRegL dst, rRegL src, immL_255 mask) -%{ - match(Set dst (AndL src mask)); - - format %{ "movzbl $dst, $src\t# long & 0xFF" %} - ins_encode %{ - // movzbl zeroes out the upper 32-bit and does not need REX.W - __ movzbl($dst$$Register, $src$$Register); - %} - ins_pipe(ialu_reg); -%} - -// And Register with Immediate 65535 -instruct andL_rReg_imm65535(rRegL dst, rRegL src, immL_65535 mask) -%{ - match(Set dst (AndL src mask)); - - format %{ "movzwl $dst, $src\t# long & 0xFFFF" %} - ins_encode %{ - // movzwl zeroes out the upper 32-bit and does not need REX.W - __ movzwl($dst$$Register, $src$$Register); - %} - ins_pipe(ialu_reg); -%} - -// And Register with Immediate -instruct andL_rReg_imm(rRegL dst, immL32 src, rFlagsReg cr) -%{ - predicate(!UseAPX); - match(Set dst (AndL dst src)); - effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); - - format %{ "andq $dst, $src\t# long" %} - ins_encode %{ - __ andq($dst$$Register, $src$$constant); - %} - ins_pipe(ialu_reg); -%} - -instruct andL_rReg_rReg_imm_ndd(rRegL dst, rRegL src1, immL32 src2, rFlagsReg cr) -%{ - predicate(UseAPX); - match(Set dst (AndL src1 src2)); - effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); - - format %{ "eandq $dst, $src1, $src2\t# long ndd" %} - ins_encode %{ - __ eandq($dst$$Register, $src1$$Register, $src2$$constant, false); - %} - ins_pipe(ialu_reg); -%} - -instruct andL_rReg_mem_imm_ndd(rRegL dst, memory src1, immL32 src2, rFlagsReg cr) -%{ - predicate(UseAPX); - match(Set dst (AndL (LoadL src1) src2)); - effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); - - format %{ "eandq $dst, $src1, $src2\t# long ndd" %} - ins_encode %{ - __ eandq($dst$$Register, $src1$$Address, $src2$$constant, false); - %} - ins_pipe(ialu_reg); -%} - -// And Register with Memory -instruct andL_rReg_mem(rRegL dst, memory src, rFlagsReg cr) -%{ - predicate(!UseAPX); - match(Set dst (AndL dst (LoadL src))); - effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); - - ins_cost(150); - format %{ "andq $dst, $src\t# long" %} - ins_encode %{ - __ andq($dst$$Register, $src$$Address); - %} - ins_pipe(ialu_reg_mem); -%} - -instruct andL_rReg_rReg_mem_ndd(rRegL dst, rRegL src1, memory src2, rFlagsReg cr) -%{ - predicate(UseAPX); - match(Set dst (AndL src1 (LoadL src2))); - effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); - - ins_cost(150); - format %{ "eandq $dst, $src1, $src2\t# long ndd" %} - ins_encode %{ - __ eandq($dst$$Register, $src1$$Register, $src2$$Address, false); - %} - ins_pipe(ialu_reg_mem); -%} - -// And Memory with Register -instruct andL_mem_rReg(memory dst, rRegL src, rFlagsReg cr) -%{ - match(Set dst (StoreL dst (AndL (LoadL dst) src))); - effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); - - ins_cost(150); - format %{ "andq $dst, $src\t# long" %} - ins_encode %{ - __ andq($dst$$Address, $src$$Register); - %} - ins_pipe(ialu_mem_reg); -%} - -// And Memory with Immediate -instruct andL_mem_imm(memory dst, immL32 src, rFlagsReg cr) -%{ - match(Set dst (StoreL dst (AndL (LoadL dst) src))); - effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); - - ins_cost(125); - format %{ "andq $dst, $src\t# long" %} - ins_encode %{ - __ andq($dst$$Address, $src$$constant); - %} - ins_pipe(ialu_mem_imm); -%} - -instruct btrL_mem_imm(memory dst, immL_NotPow2 con, rFlagsReg cr) -%{ - // con should be a pure 64-bit immediate given that not(con) is a power of 2 - // because AND/OR works well enough for 8/32-bit values. - predicate(log2i_graceful(~n->in(3)->in(2)->get_long()) > 30); - - match(Set dst (StoreL dst (AndL (LoadL dst) con))); - effect(KILL cr); - - ins_cost(125); - format %{ "btrq $dst, log2(not($con))\t# long" %} - ins_encode %{ - __ btrq($dst$$Address, log2i_exact((julong)~$con$$constant)); - %} - ins_pipe(ialu_mem_imm); -%} - -// BMI1 instructions -instruct andnL_rReg_rReg_mem(rRegL dst, rRegL src1, memory src2, immL_M1 minus_1, rFlagsReg cr) %{ - match(Set dst (AndL (XorL src1 minus_1) (LoadL src2))); - predicate(UseBMI1Instructions); - effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); - - ins_cost(125); - format %{ "andnq $dst, $src1, $src2" %} - - ins_encode %{ - __ andnq($dst$$Register, $src1$$Register, $src2$$Address); - %} - ins_pipe(ialu_reg_mem); -%} - -instruct andnL_rReg_rReg_rReg(rRegL dst, rRegL src1, rRegL src2, immL_M1 minus_1, rFlagsReg cr) %{ - match(Set dst (AndL (XorL src1 minus_1) src2)); - predicate(UseBMI1Instructions); - effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); - - format %{ "andnq $dst, $src1, $src2" %} - - ins_encode %{ - __ andnq($dst$$Register, $src1$$Register, $src2$$Register); - %} - ins_pipe(ialu_reg_mem); -%} - -instruct blsiL_rReg_rReg(rRegL dst, rRegL src, immL0 imm_zero, rFlagsReg cr) %{ - match(Set dst (AndL (SubL imm_zero src) src)); - predicate(UseBMI1Instructions); - effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_clears_overflow_flag); - - format %{ "blsiq $dst, $src" %} - - ins_encode %{ - __ blsiq($dst$$Register, $src$$Register); - %} - ins_pipe(ialu_reg); -%} - -instruct blsiL_rReg_mem(rRegL dst, memory src, immL0 imm_zero, rFlagsReg cr) %{ - match(Set dst (AndL (SubL imm_zero (LoadL src) ) (LoadL src) )); - predicate(UseBMI1Instructions); - effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_clears_overflow_flag); - - ins_cost(125); - format %{ "blsiq $dst, $src" %} - - ins_encode %{ - __ blsiq($dst$$Register, $src$$Address); - %} - ins_pipe(ialu_reg_mem); -%} - -instruct blsmskL_rReg_mem(rRegL dst, memory src, immL_M1 minus_1, rFlagsReg cr) -%{ - match(Set dst (XorL (AddL (LoadL src) minus_1) (LoadL src) ) ); - predicate(UseBMI1Instructions); - effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_clears_zero_flag, PD::Flag_clears_overflow_flag); - - ins_cost(125); - format %{ "blsmskq $dst, $src" %} - - ins_encode %{ - __ blsmskq($dst$$Register, $src$$Address); - %} - ins_pipe(ialu_reg_mem); -%} - -instruct blsmskL_rReg_rReg(rRegL dst, rRegL src, immL_M1 minus_1, rFlagsReg cr) -%{ - match(Set dst (XorL (AddL src minus_1) src)); - predicate(UseBMI1Instructions); - effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_clears_zero_flag, PD::Flag_clears_overflow_flag); - - format %{ "blsmskq $dst, $src" %} - - ins_encode %{ - __ blsmskq($dst$$Register, $src$$Register); - %} - - ins_pipe(ialu_reg); -%} - -instruct blsrL_rReg_rReg(rRegL dst, rRegL src, immL_M1 minus_1, rFlagsReg cr) -%{ - match(Set dst (AndL (AddL src minus_1) src) ); - predicate(UseBMI1Instructions); - effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_clears_overflow_flag); - - format %{ "blsrq $dst, $src" %} - - ins_encode %{ - __ blsrq($dst$$Register, $src$$Register); - %} - - ins_pipe(ialu_reg); -%} - -instruct blsrL_rReg_mem(rRegL dst, memory src, immL_M1 minus_1, rFlagsReg cr) -%{ - match(Set dst (AndL (AddL (LoadL src) minus_1) (LoadL src)) ); - predicate(UseBMI1Instructions); - effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_clears_overflow_flag); - - ins_cost(125); - format %{ "blsrq $dst, $src" %} - - ins_encode %{ - __ blsrq($dst$$Register, $src$$Address); - %} - - ins_pipe(ialu_reg); -%} - -// Or Instructions -// Or Register with Register -instruct orL_rReg(rRegL dst, rRegL src, rFlagsReg cr) -%{ - predicate(!UseAPX); - match(Set dst (OrL dst src)); - effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); - - format %{ "orq $dst, $src\t# long" %} - ins_encode %{ - __ orq($dst$$Register, $src$$Register); - %} - ins_pipe(ialu_reg_reg); -%} - -// Or Register with Register using New Data Destination (NDD) -instruct orL_rReg_ndd(rRegL dst, rRegL src1, rRegL src2, rFlagsReg cr) -%{ - predicate(UseAPX); - match(Set dst (OrL src1 src2)); - effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); - - format %{ "eorq $dst, $src1, $src2\t# long ndd" %} - ins_encode %{ - __ eorq($dst$$Register, $src1$$Register, $src2$$Register, false); - - %} - ins_pipe(ialu_reg_reg); -%} - -// Use any_RegP to match R15 (TLS register) without spilling. -instruct orL_rReg_castP2X(rRegL dst, any_RegP src, rFlagsReg cr) %{ - match(Set dst (OrL dst (CastP2X src))); - effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); - - format %{ "orq $dst, $src\t# long" %} - ins_encode %{ - __ orq($dst$$Register, $src$$Register); - %} - ins_pipe(ialu_reg_reg); -%} - -instruct orL_rReg_castP2X_ndd(rRegL dst, any_RegP src1, any_RegP src2, rFlagsReg cr) %{ - match(Set dst (OrL src1 (CastP2X src2))); - effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); - - format %{ "eorq $dst, $src1, $src2\t# long ndd" %} - ins_encode %{ - __ eorq($dst$$Register, $src1$$Register, $src2$$Register, false); - %} - ins_pipe(ialu_reg_reg); -%} - -// Or Register with Immediate -instruct orL_rReg_imm(rRegL dst, immL32 src, rFlagsReg cr) -%{ - predicate(!UseAPX); - match(Set dst (OrL dst src)); - effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); - - format %{ "orq $dst, $src\t# long" %} - ins_encode %{ - __ orq($dst$$Register, $src$$constant); - %} - ins_pipe(ialu_reg); -%} - -instruct orL_rReg_rReg_imm_ndd(rRegL dst, rRegL src1, immL32 src2, rFlagsReg cr) -%{ - predicate(UseAPX); - match(Set dst (OrL src1 src2)); - effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); - - format %{ "eorq $dst, $src1, $src2\t# long ndd" %} - ins_encode %{ - __ eorq($dst$$Register, $src1$$Register, $src2$$constant, false); - %} - ins_pipe(ialu_reg); -%} - -instruct orL_rReg_imm_rReg_ndd(rRegL dst, immL32 src1, rRegL src2, rFlagsReg cr) -%{ - predicate(UseAPX); - match(Set dst (OrL src1 src2)); - effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); - - format %{ "eorq $dst, $src2, $src1\t# long ndd" %} - ins_encode %{ - __ eorq($dst$$Register, $src2$$Register, $src1$$constant, false); - %} - ins_pipe(ialu_reg); -%} - -// Or Memory with Immediate -instruct orL_rReg_mem_imm_ndd(rRegL dst, memory src1, immL32 src2, rFlagsReg cr) -%{ - predicate(UseAPX); - match(Set dst (OrL (LoadL src1) src2)); - effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); - - format %{ "eorq $dst, $src1, $src2\t# long ndd" %} - ins_encode %{ - __ eorq($dst$$Register, $src1$$Address, $src2$$constant, false); - %} - ins_pipe(ialu_reg); -%} - -// Or Register with Memory -instruct orL_rReg_mem(rRegL dst, memory src, rFlagsReg cr) -%{ - predicate(!UseAPX); - match(Set dst (OrL dst (LoadL src))); - effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); - - ins_cost(150); - format %{ "orq $dst, $src\t# long" %} - ins_encode %{ - __ orq($dst$$Register, $src$$Address); - %} - ins_pipe(ialu_reg_mem); -%} - -instruct orL_rReg_rReg_mem_ndd(rRegL dst, rRegL src1, memory src2, rFlagsReg cr) -%{ - predicate(UseAPX); - match(Set dst (OrL src1 (LoadL src2))); - effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); - - ins_cost(150); - format %{ "eorq $dst, $src1, $src2\t# long ndd" %} - ins_encode %{ - __ eorq($dst$$Register, $src1$$Register, $src2$$Address, false); - %} - ins_pipe(ialu_reg_mem); -%} - -// Or Memory with Register -instruct orL_mem_rReg(memory dst, rRegL src, rFlagsReg cr) -%{ - match(Set dst (StoreL dst (OrL (LoadL dst) src))); - effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); - - ins_cost(150); - format %{ "orq $dst, $src\t# long" %} - ins_encode %{ - __ orq($dst$$Address, $src$$Register); - %} - ins_pipe(ialu_mem_reg); -%} - -// Or Memory with Immediate -instruct orL_mem_imm(memory dst, immL32 src, rFlagsReg cr) -%{ - match(Set dst (StoreL dst (OrL (LoadL dst) src))); - effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); - - ins_cost(125); - format %{ "orq $dst, $src\t# long" %} - ins_encode %{ - __ orq($dst$$Address, $src$$constant); - %} - ins_pipe(ialu_mem_imm); -%} - -instruct btsL_mem_imm(memory dst, immL_Pow2 con, rFlagsReg cr) -%{ - // con should be a pure 64-bit power of 2 immediate - // because AND/OR works well enough for 8/32-bit values. - predicate(log2i_graceful(n->in(3)->in(2)->get_long()) > 31); - - match(Set dst (StoreL dst (OrL (LoadL dst) con))); - effect(KILL cr); - - ins_cost(125); - format %{ "btsq $dst, log2($con)\t# long" %} - ins_encode %{ - __ btsq($dst$$Address, log2i_exact((julong)$con$$constant)); - %} - ins_pipe(ialu_mem_imm); -%} - -// Xor Instructions -// Xor Register with Register -instruct xorL_rReg(rRegL dst, rRegL src, rFlagsReg cr) -%{ - predicate(!UseAPX); - match(Set dst (XorL dst src)); - effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); - - format %{ "xorq $dst, $src\t# long" %} - ins_encode %{ - __ xorq($dst$$Register, $src$$Register); - %} - ins_pipe(ialu_reg_reg); -%} - -// Xor Register with Register using New Data Destination (NDD) -instruct xorL_rReg_ndd(rRegL dst, rRegL src1, rRegL src2, rFlagsReg cr) -%{ - predicate(UseAPX); - match(Set dst (XorL src1 src2)); - effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); - - format %{ "exorq $dst, $src1, $src2\t# long ndd" %} - ins_encode %{ - __ exorq($dst$$Register, $src1$$Register, $src2$$Register, false); - %} - ins_pipe(ialu_reg_reg); -%} - -// Xor Register with Immediate -1 -instruct xorL_rReg_im1(rRegL dst, immL_M1 imm) -%{ - predicate(!UseAPX); - match(Set dst (XorL dst imm)); - - format %{ "notq $dst" %} - ins_encode %{ - __ notq($dst$$Register); - %} - ins_pipe(ialu_reg); -%} - -instruct xorL_rReg_im1_ndd(rRegL dst,rRegL src, immL_M1 imm) -%{ - predicate(UseAPX); - match(Set dst (XorL src imm)); - - format %{ "enotq $dst, $src" %} - ins_encode %{ - __ enotq($dst$$Register, $src$$Register); - %} - ins_pipe(ialu_reg); -%} - -// Xor Register with Immediate -instruct xorL_rReg_imm(rRegL dst, immL32 src, rFlagsReg cr) -%{ - // Strict predicate check to make selection of xorL_rReg_im1 cost agnostic if immL32 src is -1. - predicate(!UseAPX && n->in(2)->bottom_type()->is_long()->get_con() != -1L); - match(Set dst (XorL dst src)); - effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); - - format %{ "xorq $dst, $src\t# long" %} - ins_encode %{ - __ xorq($dst$$Register, $src$$constant); - %} - ins_pipe(ialu_reg); -%} - -instruct xorL_rReg_rReg_imm(rRegL dst, rRegL src1, immL32 src2, rFlagsReg cr) -%{ - // Strict predicate check to make selection of xorL_rReg_im1_ndd cost agnostic if immL32 src2 is -1. - predicate(UseAPX && n->in(2)->bottom_type()->is_long()->get_con() != -1L); - match(Set dst (XorL src1 src2)); - effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); - - format %{ "exorq $dst, $src1, $src2\t# long ndd" %} - ins_encode %{ - __ exorq($dst$$Register, $src1$$Register, $src2$$constant, false); - %} - ins_pipe(ialu_reg); -%} - -// Xor Memory with Immediate -instruct xorL_rReg_mem_imm(rRegL dst, memory src1, immL32 src2, rFlagsReg cr) -%{ - predicate(UseAPX); - match(Set dst (XorL (LoadL src1) src2)); - effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); - ins_cost(150); - - format %{ "exorq $dst, $src1, $src2\t# long ndd" %} - ins_encode %{ - __ exorq($dst$$Register, $src1$$Address, $src2$$constant, false); - %} - ins_pipe(ialu_reg); -%} - -// Xor Register with Memory -instruct xorL_rReg_mem(rRegL dst, memory src, rFlagsReg cr) -%{ - predicate(!UseAPX); - match(Set dst (XorL dst (LoadL src))); - effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); - - ins_cost(150); - format %{ "xorq $dst, $src\t# long" %} - ins_encode %{ - __ xorq($dst$$Register, $src$$Address); - %} - ins_pipe(ialu_reg_mem); -%} - -instruct xorL_rReg_rReg_mem_ndd(rRegL dst, rRegL src1, memory src2, rFlagsReg cr) -%{ - predicate(UseAPX); - match(Set dst (XorL src1 (LoadL src2))); - effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); - - ins_cost(150); - format %{ "exorq $dst, $src1, $src2\t# long ndd" %} - ins_encode %{ - __ exorq($dst$$Register, $src1$$Register, $src2$$Address, false); - %} - ins_pipe(ialu_reg_mem); -%} - -// Xor Memory with Register -instruct xorL_mem_rReg(memory dst, rRegL src, rFlagsReg cr) -%{ - match(Set dst (StoreL dst (XorL (LoadL dst) src))); - effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); - - ins_cost(150); - format %{ "xorq $dst, $src\t# long" %} - ins_encode %{ - __ xorq($dst$$Address, $src$$Register); - %} - ins_pipe(ialu_mem_reg); -%} - -// Xor Memory with Immediate -instruct xorL_mem_imm(memory dst, immL32 src, rFlagsReg cr) -%{ - match(Set dst (StoreL dst (XorL (LoadL dst) src))); - effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); - - ins_cost(125); - format %{ "xorq $dst, $src\t# long" %} - ins_encode %{ - __ xorq($dst$$Address, $src$$constant); - %} - ins_pipe(ialu_mem_imm); -%} - -instruct cmpLTMask(rRegI dst, rRegI p, rRegI q, rFlagsReg cr) -%{ - match(Set dst (CmpLTMask p q)); - effect(KILL cr); - - ins_cost(400); - format %{ "cmpl $p, $q\t# cmpLTMask\n\t" - "setcc $dst \t# emits setlt + movzbl or setzul for APX" - "negl $dst" %} - ins_encode %{ - __ cmpl($p$$Register, $q$$Register); - __ setcc(Assembler::less, $dst$$Register); - __ negl($dst$$Register); - %} - ins_pipe(pipe_slow); -%} - -instruct cmpLTMask0(rRegI dst, immI_0 zero, rFlagsReg cr) -%{ - match(Set dst (CmpLTMask dst zero)); - effect(KILL cr); - - ins_cost(100); - format %{ "sarl $dst, #31\t# cmpLTMask0" %} - ins_encode %{ - __ sarl($dst$$Register, 31); - %} - ins_pipe(ialu_reg); -%} - -/* Better to save a register than avoid a branch */ -instruct cadd_cmpLTMask(rRegI p, rRegI q, rRegI y, rFlagsReg cr) -%{ - match(Set p (AddI (AndI (CmpLTMask p q) y) (SubI p q))); - effect(KILL cr); - ins_cost(300); - format %{ "subl $p,$q\t# cadd_cmpLTMask\n\t" - "jge done\n\t" - "addl $p,$y\n" - "done: " %} - ins_encode %{ - Register Rp = $p$$Register; - Register Rq = $q$$Register; - Register Ry = $y$$Register; - Label done; - __ subl(Rp, Rq); - __ jccb(Assembler::greaterEqual, done); - __ addl(Rp, Ry); - __ bind(done); - %} - ins_pipe(pipe_cmplt); -%} - -/* Better to save a register than avoid a branch */ -instruct and_cmpLTMask(rRegI p, rRegI q, rRegI y, rFlagsReg cr) -%{ - match(Set y (AndI (CmpLTMask p q) y)); - effect(KILL cr); - - ins_cost(300); - - format %{ "cmpl $p, $q\t# and_cmpLTMask\n\t" - "jlt done\n\t" - "xorl $y, $y\n" - "done: " %} - ins_encode %{ - Register Rp = $p$$Register; - Register Rq = $q$$Register; - Register Ry = $y$$Register; - Label done; - __ cmpl(Rp, Rq); - __ jccb(Assembler::less, done); - __ xorl(Ry, Ry); - __ bind(done); - %} - ins_pipe(pipe_cmplt); -%} - - -//---------- FP Instructions------------------------------------------------ - -// Really expensive, avoid -instruct cmpF_cc_reg(rFlagsRegU cr, regF src1, regF src2) -%{ - match(Set cr (CmpF src1 src2)); - - ins_cost(500); - format %{ "ucomiss $src1, $src2\n\t" - "jnp,s exit\n\t" - "pushfq\t# saw NaN, set CF\n\t" - "andq [rsp], #0xffffff2b\n\t" - "popfq\n" - "exit:" %} - ins_encode %{ - __ ucomiss($src1$$XMMRegister, $src2$$XMMRegister); - emit_cmpfp_fixup(masm); - %} - ins_pipe(pipe_slow); -%} - -instruct cmpF_cc_reg_CF(rFlagsRegUCF cr, regF src1, regF src2) %{ - match(Set cr (CmpF src1 src2)); - - ins_cost(100); - format %{ "ucomiss $src1, $src2" %} - ins_encode %{ - __ ucomiss($src1$$XMMRegister, $src2$$XMMRegister); - %} - ins_pipe(pipe_slow); -%} - -instruct cmpF_cc_memCF(rFlagsRegUCF cr, regF src1, memory src2) %{ - match(Set cr (CmpF src1 (LoadF src2))); - - ins_cost(100); - format %{ "ucomiss $src1, $src2" %} - ins_encode %{ - __ ucomiss($src1$$XMMRegister, $src2$$Address); - %} - ins_pipe(pipe_slow); -%} - -instruct cmpF_cc_immCF(rFlagsRegUCF cr, regF src, immF con) %{ - match(Set cr (CmpF src con)); - ins_cost(100); - format %{ "ucomiss $src, [$constantaddress]\t# load from constant table: float=$con" %} - ins_encode %{ - __ ucomiss($src$$XMMRegister, $constantaddress($con)); - %} - ins_pipe(pipe_slow); -%} - -// Really expensive, avoid -instruct cmpD_cc_reg(rFlagsRegU cr, regD src1, regD src2) -%{ - match(Set cr (CmpD src1 src2)); - - ins_cost(500); - format %{ "ucomisd $src1, $src2\n\t" - "jnp,s exit\n\t" - "pushfq\t# saw NaN, set CF\n\t" - "andq [rsp], #0xffffff2b\n\t" - "popfq\n" - "exit:" %} - ins_encode %{ - __ ucomisd($src1$$XMMRegister, $src2$$XMMRegister); - emit_cmpfp_fixup(masm); - %} - ins_pipe(pipe_slow); -%} - -instruct cmpD_cc_reg_CF(rFlagsRegUCF cr, regD src1, regD src2) %{ - match(Set cr (CmpD src1 src2)); - - ins_cost(100); - format %{ "ucomisd $src1, $src2 test" %} - ins_encode %{ - __ ucomisd($src1$$XMMRegister, $src2$$XMMRegister); - %} - ins_pipe(pipe_slow); -%} - -instruct cmpD_cc_memCF(rFlagsRegUCF cr, regD src1, memory src2) %{ - match(Set cr (CmpD src1 (LoadD src2))); - - ins_cost(100); - format %{ "ucomisd $src1, $src2" %} - ins_encode %{ - __ ucomisd($src1$$XMMRegister, $src2$$Address); - %} - ins_pipe(pipe_slow); -%} - -instruct cmpD_cc_immCF(rFlagsRegUCF cr, regD src, immD con) %{ - match(Set cr (CmpD src con)); - ins_cost(100); - format %{ "ucomisd $src, [$constantaddress]\t# load from constant table: double=$con" %} - ins_encode %{ - __ ucomisd($src$$XMMRegister, $constantaddress($con)); - %} - ins_pipe(pipe_slow); -%} - -// Compare into -1,0,1 -instruct cmpF_reg(rRegI dst, regF src1, regF src2, rFlagsReg cr) -%{ - match(Set dst (CmpF3 src1 src2)); - effect(KILL cr); - - ins_cost(275); - format %{ "ucomiss $src1, $src2\n\t" - "movl $dst, #-1\n\t" - "jp,s done\n\t" - "jb,s done\n\t" - "setne $dst\n\t" - "movzbl $dst, $dst\n" - "done:" %} - ins_encode %{ - __ ucomiss($src1$$XMMRegister, $src2$$XMMRegister); - emit_cmpfp3(masm, $dst$$Register); - %} - ins_pipe(pipe_slow); -%} - -// Compare into -1,0,1 -instruct cmpF_mem(rRegI dst, regF src1, memory src2, rFlagsReg cr) -%{ - match(Set dst (CmpF3 src1 (LoadF src2))); - effect(KILL cr); - - ins_cost(275); - format %{ "ucomiss $src1, $src2\n\t" - "movl $dst, #-1\n\t" - "jp,s done\n\t" - "jb,s done\n\t" - "setne $dst\n\t" - "movzbl $dst, $dst\n" - "done:" %} - ins_encode %{ - __ ucomiss($src1$$XMMRegister, $src2$$Address); - emit_cmpfp3(masm, $dst$$Register); - %} - ins_pipe(pipe_slow); -%} - -// Compare into -1,0,1 -instruct cmpF_imm(rRegI dst, regF src, immF con, rFlagsReg cr) %{ - match(Set dst (CmpF3 src con)); - effect(KILL cr); - - ins_cost(275); - format %{ "ucomiss $src, [$constantaddress]\t# load from constant table: float=$con\n\t" - "movl $dst, #-1\n\t" - "jp,s done\n\t" - "jb,s done\n\t" - "setne $dst\n\t" - "movzbl $dst, $dst\n" - "done:" %} - ins_encode %{ - __ ucomiss($src$$XMMRegister, $constantaddress($con)); - emit_cmpfp3(masm, $dst$$Register); - %} - ins_pipe(pipe_slow); -%} - -// Compare into -1,0,1 -instruct cmpD_reg(rRegI dst, regD src1, regD src2, rFlagsReg cr) -%{ - match(Set dst (CmpD3 src1 src2)); - effect(KILL cr); - - ins_cost(275); - format %{ "ucomisd $src1, $src2\n\t" - "movl $dst, #-1\n\t" - "jp,s done\n\t" - "jb,s done\n\t" - "setne $dst\n\t" - "movzbl $dst, $dst\n" - "done:" %} - ins_encode %{ - __ ucomisd($src1$$XMMRegister, $src2$$XMMRegister); - emit_cmpfp3(masm, $dst$$Register); - %} - ins_pipe(pipe_slow); -%} - -// Compare into -1,0,1 -instruct cmpD_mem(rRegI dst, regD src1, memory src2, rFlagsReg cr) -%{ - match(Set dst (CmpD3 src1 (LoadD src2))); - effect(KILL cr); - - ins_cost(275); - format %{ "ucomisd $src1, $src2\n\t" - "movl $dst, #-1\n\t" - "jp,s done\n\t" - "jb,s done\n\t" - "setne $dst\n\t" - "movzbl $dst, $dst\n" - "done:" %} - ins_encode %{ - __ ucomisd($src1$$XMMRegister, $src2$$Address); - emit_cmpfp3(masm, $dst$$Register); - %} - ins_pipe(pipe_slow); -%} - -// Compare into -1,0,1 -instruct cmpD_imm(rRegI dst, regD src, immD con, rFlagsReg cr) %{ - match(Set dst (CmpD3 src con)); - effect(KILL cr); - - ins_cost(275); - format %{ "ucomisd $src, [$constantaddress]\t# load from constant table: double=$con\n\t" - "movl $dst, #-1\n\t" - "jp,s done\n\t" - "jb,s done\n\t" - "setne $dst\n\t" - "movzbl $dst, $dst\n" - "done:" %} - ins_encode %{ - __ ucomisd($src$$XMMRegister, $constantaddress($con)); - emit_cmpfp3(masm, $dst$$Register); - %} - ins_pipe(pipe_slow); -%} - -//----------Arithmetic Conversion Instructions--------------------------------- - -instruct convF2D_reg_reg(regD dst, regF src) -%{ - match(Set dst (ConvF2D src)); - - format %{ "cvtss2sd $dst, $src" %} - ins_encode %{ - __ cvtss2sd ($dst$$XMMRegister, $src$$XMMRegister); - %} - ins_pipe(pipe_slow); // XXX -%} - -instruct convF2D_reg_mem(regD dst, memory src) -%{ - predicate(UseAVX == 0); - match(Set dst (ConvF2D (LoadF src))); - - format %{ "cvtss2sd $dst, $src" %} - ins_encode %{ - __ cvtss2sd ($dst$$XMMRegister, $src$$Address); - %} - ins_pipe(pipe_slow); // XXX -%} - -instruct convD2F_reg_reg(regF dst, regD src) -%{ - match(Set dst (ConvD2F src)); - - format %{ "cvtsd2ss $dst, $src" %} - ins_encode %{ - __ cvtsd2ss ($dst$$XMMRegister, $src$$XMMRegister); - %} - ins_pipe(pipe_slow); // XXX -%} - -instruct convD2F_reg_mem(regF dst, memory src) -%{ - predicate(UseAVX == 0); - match(Set dst (ConvD2F (LoadD src))); - - format %{ "cvtsd2ss $dst, $src" %} - ins_encode %{ - __ cvtsd2ss ($dst$$XMMRegister, $src$$Address); - %} - ins_pipe(pipe_slow); // XXX -%} - -// XXX do mem variants -instruct convF2I_reg_reg(rRegI dst, regF src, rFlagsReg cr) -%{ - predicate(!VM_Version::supports_avx10_2()); - match(Set dst (ConvF2I src)); - effect(KILL cr); - format %{ "convert_f2i $dst, $src" %} - ins_encode %{ - __ convertF2I(T_INT, T_FLOAT, $dst$$Register, $src$$XMMRegister); - %} - ins_pipe(pipe_slow); -%} - -instruct convF2I_reg_reg_avx10(rRegI dst, regF src) -%{ - predicate(VM_Version::supports_avx10_2()); - match(Set dst (ConvF2I src)); - format %{ "evcvttss2sisl $dst, $src" %} - ins_encode %{ - __ evcvttss2sisl($dst$$Register, $src$$XMMRegister); - %} - ins_pipe(pipe_slow); -%} - -instruct convF2I_reg_mem_avx10(rRegI dst, memory src) -%{ - predicate(VM_Version::supports_avx10_2()); - match(Set dst (ConvF2I (LoadF src))); - format %{ "evcvttss2sisl $dst, $src" %} - ins_encode %{ - __ evcvttss2sisl($dst$$Register, $src$$Address); - %} - ins_pipe(pipe_slow); -%} - -instruct convF2L_reg_reg(rRegL dst, regF src, rFlagsReg cr) -%{ - predicate(!VM_Version::supports_avx10_2()); - match(Set dst (ConvF2L src)); - effect(KILL cr); - format %{ "convert_f2l $dst, $src"%} - ins_encode %{ - __ convertF2I(T_LONG, T_FLOAT, $dst$$Register, $src$$XMMRegister); - %} - ins_pipe(pipe_slow); -%} - -instruct convF2L_reg_reg_avx10(rRegL dst, regF src) -%{ - predicate(VM_Version::supports_avx10_2()); - match(Set dst (ConvF2L src)); - format %{ "evcvttss2sisq $dst, $src" %} - ins_encode %{ - __ evcvttss2sisq($dst$$Register, $src$$XMMRegister); - %} - ins_pipe(pipe_slow); -%} - -instruct convF2L_reg_mem_avx10(rRegL dst, memory src) -%{ - predicate(VM_Version::supports_avx10_2()); - match(Set dst (ConvF2L (LoadF src))); - format %{ "evcvttss2sisq $dst, $src" %} - ins_encode %{ - __ evcvttss2sisq($dst$$Register, $src$$Address); - %} - ins_pipe(pipe_slow); -%} - -instruct convD2I_reg_reg(rRegI dst, regD src, rFlagsReg cr) -%{ - predicate(!VM_Version::supports_avx10_2()); - match(Set dst (ConvD2I src)); - effect(KILL cr); - format %{ "convert_d2i $dst, $src"%} - ins_encode %{ - __ convertF2I(T_INT, T_DOUBLE, $dst$$Register, $src$$XMMRegister); - %} - ins_pipe(pipe_slow); -%} - -instruct convD2I_reg_reg_avx10(rRegI dst, regD src) -%{ - predicate(VM_Version::supports_avx10_2()); - match(Set dst (ConvD2I src)); - format %{ "evcvttsd2sisl $dst, $src" %} - ins_encode %{ - __ evcvttsd2sisl($dst$$Register, $src$$XMMRegister); - %} - ins_pipe(pipe_slow); -%} - -instruct convD2I_reg_mem_avx10(rRegI dst, memory src) -%{ - predicate(VM_Version::supports_avx10_2()); - match(Set dst (ConvD2I (LoadD src))); - format %{ "evcvttsd2sisl $dst, $src" %} - ins_encode %{ - __ evcvttsd2sisl($dst$$Register, $src$$Address); - %} - ins_pipe(pipe_slow); -%} - -instruct convD2L_reg_reg(rRegL dst, regD src, rFlagsReg cr) -%{ - predicate(!VM_Version::supports_avx10_2()); - match(Set dst (ConvD2L src)); - effect(KILL cr); - format %{ "convert_d2l $dst, $src"%} - ins_encode %{ - __ convertF2I(T_LONG, T_DOUBLE, $dst$$Register, $src$$XMMRegister); - %} - ins_pipe(pipe_slow); -%} - -instruct convD2L_reg_reg_avx10(rRegL dst, regD src) -%{ - predicate(VM_Version::supports_avx10_2()); - match(Set dst (ConvD2L src)); - format %{ "evcvttsd2sisq $dst, $src" %} - ins_encode %{ - __ evcvttsd2sisq($dst$$Register, $src$$XMMRegister); - %} - ins_pipe(pipe_slow); -%} - -instruct convD2L_reg_mem_avx10(rRegL dst, memory src) -%{ - predicate(VM_Version::supports_avx10_2()); - match(Set dst (ConvD2L (LoadD src))); - format %{ "evcvttsd2sisq $dst, $src" %} - ins_encode %{ - __ evcvttsd2sisq($dst$$Register, $src$$Address); - %} - ins_pipe(pipe_slow); -%} - -instruct round_double_reg(rRegL dst, regD src, rRegL rtmp, rcx_RegL rcx, rFlagsReg cr) -%{ - match(Set dst (RoundD src)); - effect(TEMP dst, TEMP rtmp, TEMP rcx, KILL cr); - format %{ "round_double $dst,$src \t! using $rtmp and $rcx as TEMP"%} - ins_encode %{ - __ round_double($dst$$Register, $src$$XMMRegister, $rtmp$$Register, $rcx$$Register); - %} - ins_pipe(pipe_slow); -%} - -instruct round_float_reg(rRegI dst, regF src, rRegL rtmp, rcx_RegL rcx, rFlagsReg cr) -%{ - match(Set dst (RoundF src)); - effect(TEMP dst, TEMP rtmp, TEMP rcx, KILL cr); - format %{ "round_float $dst,$src" %} - ins_encode %{ - __ round_float($dst$$Register, $src$$XMMRegister, $rtmp$$Register, $rcx$$Register); - %} - ins_pipe(pipe_slow); -%} - -instruct convI2F_reg_reg(vlRegF dst, rRegI src) -%{ - predicate(!UseXmmI2F); - match(Set dst (ConvI2F src)); - - format %{ "cvtsi2ssl $dst, $src\t# i2f" %} - ins_encode %{ - if (UseAVX > 0) { - __ pxor($dst$$XMMRegister, $dst$$XMMRegister); - } - __ cvtsi2ssl ($dst$$XMMRegister, $src$$Register); - %} - ins_pipe(pipe_slow); // XXX -%} - -instruct convI2F_reg_mem(regF dst, memory src) -%{ - predicate(UseAVX == 0); - match(Set dst (ConvI2F (LoadI src))); - - format %{ "cvtsi2ssl $dst, $src\t# i2f" %} - ins_encode %{ - __ cvtsi2ssl ($dst$$XMMRegister, $src$$Address); - %} - ins_pipe(pipe_slow); // XXX -%} - -instruct convI2D_reg_reg(vlRegD dst, rRegI src) -%{ - predicate(!UseXmmI2D); - match(Set dst (ConvI2D src)); - - format %{ "cvtsi2sdl $dst, $src\t# i2d" %} - ins_encode %{ - if (UseAVX > 0) { - __ pxor($dst$$XMMRegister, $dst$$XMMRegister); - } - __ cvtsi2sdl ($dst$$XMMRegister, $src$$Register); - %} - ins_pipe(pipe_slow); // XXX -%} - -instruct convI2D_reg_mem(regD dst, memory src) -%{ - predicate(UseAVX == 0); - match(Set dst (ConvI2D (LoadI src))); - - format %{ "cvtsi2sdl $dst, $src\t# i2d" %} - ins_encode %{ - __ cvtsi2sdl ($dst$$XMMRegister, $src$$Address); - %} - ins_pipe(pipe_slow); // XXX -%} - -instruct convXI2F_reg(regF dst, rRegI src) -%{ - predicate(UseXmmI2F); - match(Set dst (ConvI2F src)); - - format %{ "movdl $dst, $src\n\t" - "cvtdq2psl $dst, $dst\t# i2f" %} - ins_encode %{ - __ movdl($dst$$XMMRegister, $src$$Register); - __ cvtdq2ps($dst$$XMMRegister, $dst$$XMMRegister); - %} - ins_pipe(pipe_slow); // XXX -%} - -instruct convXI2D_reg(regD dst, rRegI src) -%{ - predicate(UseXmmI2D); - match(Set dst (ConvI2D src)); - - format %{ "movdl $dst, $src\n\t" - "cvtdq2pdl $dst, $dst\t# i2d" %} - ins_encode %{ - __ movdl($dst$$XMMRegister, $src$$Register); - __ cvtdq2pd($dst$$XMMRegister, $dst$$XMMRegister); - %} - ins_pipe(pipe_slow); // XXX -%} - -instruct convL2F_reg_reg(vlRegF dst, rRegL src) -%{ - match(Set dst (ConvL2F src)); - - format %{ "cvtsi2ssq $dst, $src\t# l2f" %} - ins_encode %{ - if (UseAVX > 0) { - __ pxor($dst$$XMMRegister, $dst$$XMMRegister); - } - __ cvtsi2ssq ($dst$$XMMRegister, $src$$Register); - %} - ins_pipe(pipe_slow); // XXX -%} - -instruct convL2F_reg_mem(regF dst, memory src) -%{ - predicate(UseAVX == 0); - match(Set dst (ConvL2F (LoadL src))); - - format %{ "cvtsi2ssq $dst, $src\t# l2f" %} - ins_encode %{ - __ cvtsi2ssq ($dst$$XMMRegister, $src$$Address); - %} - ins_pipe(pipe_slow); // XXX -%} - -instruct convL2D_reg_reg(vlRegD dst, rRegL src) -%{ - match(Set dst (ConvL2D src)); - - format %{ "cvtsi2sdq $dst, $src\t# l2d" %} - ins_encode %{ - if (UseAVX > 0) { - __ pxor($dst$$XMMRegister, $dst$$XMMRegister); - } - __ cvtsi2sdq ($dst$$XMMRegister, $src$$Register); - %} - ins_pipe(pipe_slow); // XXX -%} - -instruct convL2D_reg_mem(regD dst, memory src) -%{ - predicate(UseAVX == 0); - match(Set dst (ConvL2D (LoadL src))); - - format %{ "cvtsi2sdq $dst, $src\t# l2d" %} - ins_encode %{ - __ cvtsi2sdq ($dst$$XMMRegister, $src$$Address); - %} - ins_pipe(pipe_slow); // XXX -%} - -instruct convI2L_reg_reg(rRegL dst, rRegI src) -%{ - match(Set dst (ConvI2L src)); - - ins_cost(125); - format %{ "movslq $dst, $src\t# i2l" %} - ins_encode %{ - __ movslq($dst$$Register, $src$$Register); - %} - ins_pipe(ialu_reg_reg); -%} - -// Zero-extend convert int to long -instruct convI2L_reg_reg_zex(rRegL dst, rRegI src, immL_32bits mask) -%{ - match(Set dst (AndL (ConvI2L src) mask)); - - format %{ "movl $dst, $src\t# i2l zero-extend\n\t" %} - ins_encode %{ - if ($dst$$reg != $src$$reg) { - __ movl($dst$$Register, $src$$Register); - } - %} - ins_pipe(ialu_reg_reg); -%} - -// Zero-extend convert int to long -instruct convI2L_reg_mem_zex(rRegL dst, memory src, immL_32bits mask) -%{ - match(Set dst (AndL (ConvI2L (LoadI src)) mask)); - - format %{ "movl $dst, $src\t# i2l zero-extend\n\t" %} - ins_encode %{ - __ movl($dst$$Register, $src$$Address); - %} - ins_pipe(ialu_reg_mem); -%} - -instruct zerox_long_reg_reg(rRegL dst, rRegL src, immL_32bits mask) -%{ - match(Set dst (AndL src mask)); - - format %{ "movl $dst, $src\t# zero-extend long" %} - ins_encode %{ - __ movl($dst$$Register, $src$$Register); - %} - ins_pipe(ialu_reg_reg); -%} - -instruct convL2I_reg_reg(rRegI dst, rRegL src) -%{ - match(Set dst (ConvL2I src)); - - format %{ "movl $dst, $src\t# l2i" %} - ins_encode %{ - __ movl($dst$$Register, $src$$Register); - %} - ins_pipe(ialu_reg_reg); -%} - - -instruct MoveF2I_stack_reg(rRegI dst, stackSlotF src) %{ - match(Set dst (MoveF2I src)); - effect(DEF dst, USE src); - - ins_cost(125); - format %{ "movl $dst, $src\t# MoveF2I_stack_reg" %} - ins_encode %{ - __ movl($dst$$Register, Address(rsp, $src$$disp)); - %} - ins_pipe(ialu_reg_mem); -%} - -instruct MoveI2F_stack_reg(regF dst, stackSlotI src) %{ - match(Set dst (MoveI2F src)); - effect(DEF dst, USE src); - - ins_cost(125); - format %{ "movss $dst, $src\t# MoveI2F_stack_reg" %} - ins_encode %{ - __ movflt($dst$$XMMRegister, Address(rsp, $src$$disp)); - %} - ins_pipe(pipe_slow); -%} - -instruct MoveD2L_stack_reg(rRegL dst, stackSlotD src) %{ - match(Set dst (MoveD2L src)); - effect(DEF dst, USE src); - - ins_cost(125); - format %{ "movq $dst, $src\t# MoveD2L_stack_reg" %} - ins_encode %{ - __ movq($dst$$Register, Address(rsp, $src$$disp)); - %} - ins_pipe(ialu_reg_mem); -%} - -instruct MoveL2D_stack_reg_partial(regD dst, stackSlotL src) %{ - predicate(!UseXmmLoadAndClearUpper); - match(Set dst (MoveL2D src)); - effect(DEF dst, USE src); - - ins_cost(125); - format %{ "movlpd $dst, $src\t# MoveL2D_stack_reg" %} - ins_encode %{ - __ movdbl($dst$$XMMRegister, Address(rsp, $src$$disp)); - %} - ins_pipe(pipe_slow); -%} - -instruct MoveL2D_stack_reg(regD dst, stackSlotL src) %{ - predicate(UseXmmLoadAndClearUpper); - match(Set dst (MoveL2D src)); - effect(DEF dst, USE src); - - ins_cost(125); - format %{ "movsd $dst, $src\t# MoveL2D_stack_reg" %} - ins_encode %{ - __ movdbl($dst$$XMMRegister, Address(rsp, $src$$disp)); - %} - ins_pipe(pipe_slow); -%} - - -instruct MoveF2I_reg_stack(stackSlotI dst, regF src) %{ - match(Set dst (MoveF2I src)); - effect(DEF dst, USE src); - - ins_cost(95); // XXX - format %{ "movss $dst, $src\t# MoveF2I_reg_stack" %} - ins_encode %{ - __ movflt(Address(rsp, $dst$$disp), $src$$XMMRegister); - %} - ins_pipe(pipe_slow); -%} - -instruct MoveI2F_reg_stack(stackSlotF dst, rRegI src) %{ - match(Set dst (MoveI2F src)); - effect(DEF dst, USE src); - - ins_cost(100); - format %{ "movl $dst, $src\t# MoveI2F_reg_stack" %} - ins_encode %{ - __ movl(Address(rsp, $dst$$disp), $src$$Register); - %} - ins_pipe( ialu_mem_reg ); -%} - -instruct MoveD2L_reg_stack(stackSlotL dst, regD src) %{ - match(Set dst (MoveD2L src)); - effect(DEF dst, USE src); - - ins_cost(95); // XXX - format %{ "movsd $dst, $src\t# MoveL2D_reg_stack" %} - ins_encode %{ - __ movdbl(Address(rsp, $dst$$disp), $src$$XMMRegister); - %} - ins_pipe(pipe_slow); -%} - -instruct MoveL2D_reg_stack(stackSlotD dst, rRegL src) %{ - match(Set dst (MoveL2D src)); - effect(DEF dst, USE src); - - ins_cost(100); - format %{ "movq $dst, $src\t# MoveL2D_reg_stack" %} - ins_encode %{ - __ movq(Address(rsp, $dst$$disp), $src$$Register); - %} - ins_pipe(ialu_mem_reg); -%} - -instruct MoveF2I_reg_reg(rRegI dst, regF src) %{ - match(Set dst (MoveF2I src)); - effect(DEF dst, USE src); - ins_cost(85); - format %{ "movd $dst,$src\t# MoveF2I" %} - ins_encode %{ - __ movdl($dst$$Register, $src$$XMMRegister); - %} - ins_pipe( pipe_slow ); -%} - -instruct MoveD2L_reg_reg(rRegL dst, regD src) %{ - match(Set dst (MoveD2L src)); - effect(DEF dst, USE src); - ins_cost(85); - format %{ "movd $dst,$src\t# MoveD2L" %} - ins_encode %{ - __ movdq($dst$$Register, $src$$XMMRegister); - %} - ins_pipe( pipe_slow ); -%} - -instruct MoveI2F_reg_reg(regF dst, rRegI src) %{ - match(Set dst (MoveI2F src)); - effect(DEF dst, USE src); - ins_cost(100); - format %{ "movd $dst,$src\t# MoveI2F" %} - ins_encode %{ - __ movdl($dst$$XMMRegister, $src$$Register); - %} - ins_pipe( pipe_slow ); -%} - -instruct MoveL2D_reg_reg(regD dst, rRegL src) %{ - match(Set dst (MoveL2D src)); - effect(DEF dst, USE src); - ins_cost(100); - format %{ "movd $dst,$src\t# MoveL2D" %} - ins_encode %{ - __ movdq($dst$$XMMRegister, $src$$Register); - %} - ins_pipe( pipe_slow ); -%} - -// Fast clearing of an array -// Small non-constant lenght ClearArray for non-AVX512 targets. -instruct rep_stos(rcx_RegL cnt, rdi_RegP base, regD tmp, rax_RegI zero, - Universe dummy, rFlagsReg cr) -%{ - predicate(!((ClearArrayNode*)n)->is_large() && (UseAVX <= 2)); - match(Set dummy (ClearArray cnt base)); - effect(USE_KILL cnt, USE_KILL base, TEMP tmp, KILL zero, KILL cr); - - format %{ $$template - $$emit$$"xorq rax, rax\t# ClearArray:\n\t" - $$emit$$"cmp InitArrayShortSize,rcx\n\t" - $$emit$$"jg LARGE\n\t" - $$emit$$"dec rcx\n\t" - $$emit$$"js DONE\t# Zero length\n\t" - $$emit$$"mov rax,(rdi,rcx,8)\t# LOOP\n\t" - $$emit$$"dec rcx\n\t" - $$emit$$"jge LOOP\n\t" - $$emit$$"jmp DONE\n\t" - $$emit$$"# LARGE:\n\t" - if (UseFastStosb) { - $$emit$$"shlq rcx,3\t# Convert doublewords to bytes\n\t" - $$emit$$"rep stosb\t# Store rax to *rdi++ while rcx--\n\t" - } else if (UseXMMForObjInit) { - $$emit$$"mov rdi,rax\n\t" - $$emit$$"vpxor ymm0,ymm0,ymm0\n\t" - $$emit$$"jmpq L_zero_64_bytes\n\t" - $$emit$$"# L_loop:\t# 64-byte LOOP\n\t" - $$emit$$"vmovdqu ymm0,(rax)\n\t" - $$emit$$"vmovdqu ymm0,0x20(rax)\n\t" - $$emit$$"add 0x40,rax\n\t" - $$emit$$"# L_zero_64_bytes:\n\t" - $$emit$$"sub 0x8,rcx\n\t" - $$emit$$"jge L_loop\n\t" - $$emit$$"add 0x4,rcx\n\t" - $$emit$$"jl L_tail\n\t" - $$emit$$"vmovdqu ymm0,(rax)\n\t" - $$emit$$"add 0x20,rax\n\t" - $$emit$$"sub 0x4,rcx\n\t" - $$emit$$"# L_tail:\t# Clearing tail bytes\n\t" - $$emit$$"add 0x4,rcx\n\t" - $$emit$$"jle L_end\n\t" - $$emit$$"dec rcx\n\t" - $$emit$$"# L_sloop:\t# 8-byte short loop\n\t" - $$emit$$"vmovq xmm0,(rax)\n\t" - $$emit$$"add 0x8,rax\n\t" - $$emit$$"dec rcx\n\t" - $$emit$$"jge L_sloop\n\t" - $$emit$$"# L_end:\n\t" - } else { - $$emit$$"rep stosq\t# Store rax to *rdi++ while rcx--\n\t" - } - $$emit$$"# DONE" - %} - ins_encode %{ - __ clear_mem($base$$Register, $cnt$$Register, $zero$$Register, - $tmp$$XMMRegister, false, knoreg); - %} - ins_pipe(pipe_slow); -%} - -// Small non-constant length ClearArray for AVX512 targets. -instruct rep_stos_evex(rcx_RegL cnt, rdi_RegP base, legRegD tmp, kReg ktmp, rax_RegI zero, - Universe dummy, rFlagsReg cr) -%{ - predicate(!((ClearArrayNode*)n)->is_large() && (UseAVX > 2)); - match(Set dummy (ClearArray cnt base)); - ins_cost(125); - effect(USE_KILL cnt, USE_KILL base, TEMP tmp, TEMP ktmp, KILL zero, KILL cr); - - format %{ $$template - $$emit$$"xorq rax, rax\t# ClearArray:\n\t" - $$emit$$"cmp InitArrayShortSize,rcx\n\t" - $$emit$$"jg LARGE\n\t" - $$emit$$"dec rcx\n\t" - $$emit$$"js DONE\t# Zero length\n\t" - $$emit$$"mov rax,(rdi,rcx,8)\t# LOOP\n\t" - $$emit$$"dec rcx\n\t" - $$emit$$"jge LOOP\n\t" - $$emit$$"jmp DONE\n\t" - $$emit$$"# LARGE:\n\t" - if (UseFastStosb) { - $$emit$$"shlq rcx,3\t# Convert doublewords to bytes\n\t" - $$emit$$"rep stosb\t# Store rax to *rdi++ while rcx--\n\t" - } else if (UseXMMForObjInit) { - $$emit$$"mov rdi,rax\n\t" - $$emit$$"vpxor ymm0,ymm0,ymm0\n\t" - $$emit$$"jmpq L_zero_64_bytes\n\t" - $$emit$$"# L_loop:\t# 64-byte LOOP\n\t" - $$emit$$"vmovdqu ymm0,(rax)\n\t" - $$emit$$"vmovdqu ymm0,0x20(rax)\n\t" - $$emit$$"add 0x40,rax\n\t" - $$emit$$"# L_zero_64_bytes:\n\t" - $$emit$$"sub 0x8,rcx\n\t" - $$emit$$"jge L_loop\n\t" - $$emit$$"add 0x4,rcx\n\t" - $$emit$$"jl L_tail\n\t" - $$emit$$"vmovdqu ymm0,(rax)\n\t" - $$emit$$"add 0x20,rax\n\t" - $$emit$$"sub 0x4,rcx\n\t" - $$emit$$"# L_tail:\t# Clearing tail bytes\n\t" - $$emit$$"add 0x4,rcx\n\t" - $$emit$$"jle L_end\n\t" - $$emit$$"dec rcx\n\t" - $$emit$$"# L_sloop:\t# 8-byte short loop\n\t" - $$emit$$"vmovq xmm0,(rax)\n\t" - $$emit$$"add 0x8,rax\n\t" - $$emit$$"dec rcx\n\t" - $$emit$$"jge L_sloop\n\t" - $$emit$$"# L_end:\n\t" - } else { - $$emit$$"rep stosq\t# Store rax to *rdi++ while rcx--\n\t" - } - $$emit$$"# DONE" - %} - ins_encode %{ - __ clear_mem($base$$Register, $cnt$$Register, $zero$$Register, - $tmp$$XMMRegister, false, $ktmp$$KRegister); - %} - ins_pipe(pipe_slow); -%} - -// Large non-constant length ClearArray for non-AVX512 targets. -instruct rep_stos_large(rcx_RegL cnt, rdi_RegP base, regD tmp, rax_RegI zero, - Universe dummy, rFlagsReg cr) -%{ - predicate((UseAVX <=2) && ((ClearArrayNode*)n)->is_large()); - match(Set dummy (ClearArray cnt base)); - effect(USE_KILL cnt, USE_KILL base, TEMP tmp, KILL zero, KILL cr); - - format %{ $$template - if (UseFastStosb) { - $$emit$$"xorq rax, rax\t# ClearArray:\n\t" - $$emit$$"shlq rcx,3\t# Convert doublewords to bytes\n\t" - $$emit$$"rep stosb\t# Store rax to *rdi++ while rcx--" - } else if (UseXMMForObjInit) { - $$emit$$"mov rdi,rax\t# ClearArray:\n\t" - $$emit$$"vpxor ymm0,ymm0,ymm0\n\t" - $$emit$$"jmpq L_zero_64_bytes\n\t" - $$emit$$"# L_loop:\t# 64-byte LOOP\n\t" - $$emit$$"vmovdqu ymm0,(rax)\n\t" - $$emit$$"vmovdqu ymm0,0x20(rax)\n\t" - $$emit$$"add 0x40,rax\n\t" - $$emit$$"# L_zero_64_bytes:\n\t" - $$emit$$"sub 0x8,rcx\n\t" - $$emit$$"jge L_loop\n\t" - $$emit$$"add 0x4,rcx\n\t" - $$emit$$"jl L_tail\n\t" - $$emit$$"vmovdqu ymm0,(rax)\n\t" - $$emit$$"add 0x20,rax\n\t" - $$emit$$"sub 0x4,rcx\n\t" - $$emit$$"# L_tail:\t# Clearing tail bytes\n\t" - $$emit$$"add 0x4,rcx\n\t" - $$emit$$"jle L_end\n\t" - $$emit$$"dec rcx\n\t" - $$emit$$"# L_sloop:\t# 8-byte short loop\n\t" - $$emit$$"vmovq xmm0,(rax)\n\t" - $$emit$$"add 0x8,rax\n\t" - $$emit$$"dec rcx\n\t" - $$emit$$"jge L_sloop\n\t" - $$emit$$"# L_end:\n\t" - } else { - $$emit$$"xorq rax, rax\t# ClearArray:\n\t" - $$emit$$"rep stosq\t# Store rax to *rdi++ while rcx--" - } - %} - ins_encode %{ - __ clear_mem($base$$Register, $cnt$$Register, $zero$$Register, - $tmp$$XMMRegister, true, knoreg); - %} - ins_pipe(pipe_slow); -%} - -// Large non-constant length ClearArray for AVX512 targets. -instruct rep_stos_large_evex(rcx_RegL cnt, rdi_RegP base, legRegD tmp, kReg ktmp, rax_RegI zero, - Universe dummy, rFlagsReg cr) -%{ - predicate((UseAVX > 2) && ((ClearArrayNode*)n)->is_large()); - match(Set dummy (ClearArray cnt base)); - effect(USE_KILL cnt, USE_KILL base, TEMP tmp, TEMP ktmp, KILL zero, KILL cr); - - format %{ $$template - if (UseFastStosb) { - $$emit$$"xorq rax, rax\t# ClearArray:\n\t" - $$emit$$"shlq rcx,3\t# Convert doublewords to bytes\n\t" - $$emit$$"rep stosb\t# Store rax to *rdi++ while rcx--" - } else if (UseXMMForObjInit) { - $$emit$$"mov rdi,rax\t# ClearArray:\n\t" - $$emit$$"vpxor ymm0,ymm0,ymm0\n\t" - $$emit$$"jmpq L_zero_64_bytes\n\t" - $$emit$$"# L_loop:\t# 64-byte LOOP\n\t" - $$emit$$"vmovdqu ymm0,(rax)\n\t" - $$emit$$"vmovdqu ymm0,0x20(rax)\n\t" - $$emit$$"add 0x40,rax\n\t" - $$emit$$"# L_zero_64_bytes:\n\t" - $$emit$$"sub 0x8,rcx\n\t" - $$emit$$"jge L_loop\n\t" - $$emit$$"add 0x4,rcx\n\t" - $$emit$$"jl L_tail\n\t" - $$emit$$"vmovdqu ymm0,(rax)\n\t" - $$emit$$"add 0x20,rax\n\t" - $$emit$$"sub 0x4,rcx\n\t" - $$emit$$"# L_tail:\t# Clearing tail bytes\n\t" - $$emit$$"add 0x4,rcx\n\t" - $$emit$$"jle L_end\n\t" - $$emit$$"dec rcx\n\t" - $$emit$$"# L_sloop:\t# 8-byte short loop\n\t" - $$emit$$"vmovq xmm0,(rax)\n\t" - $$emit$$"add 0x8,rax\n\t" - $$emit$$"dec rcx\n\t" - $$emit$$"jge L_sloop\n\t" - $$emit$$"# L_end:\n\t" - } else { - $$emit$$"xorq rax, rax\t# ClearArray:\n\t" - $$emit$$"rep stosq\t# Store rax to *rdi++ while rcx--" - } - %} - ins_encode %{ - __ clear_mem($base$$Register, $cnt$$Register, $zero$$Register, - $tmp$$XMMRegister, true, $ktmp$$KRegister); - %} - ins_pipe(pipe_slow); -%} - -// Small constant length ClearArray for AVX512 targets. -instruct rep_stos_im(immL cnt, rRegP base, regD tmp, rRegI zero, kReg ktmp, Universe dummy, rFlagsReg cr) -%{ - predicate(!((ClearArrayNode*)n)->is_large() && (MaxVectorSize >= 32) && VM_Version::supports_avx512vl()); - match(Set dummy (ClearArray cnt base)); - ins_cost(100); - effect(TEMP tmp, TEMP zero, TEMP ktmp, KILL cr); - format %{ "clear_mem_imm $base , $cnt \n\t" %} - ins_encode %{ - __ clear_mem($base$$Register, $cnt$$constant, $zero$$Register, $tmp$$XMMRegister, $ktmp$$KRegister); - %} - ins_pipe(pipe_slow); -%} - -instruct string_compareL(rdi_RegP str1, rcx_RegI cnt1, rsi_RegP str2, rdx_RegI cnt2, - rax_RegI result, legRegD tmp1, rFlagsReg cr) -%{ - predicate(!VM_Version::supports_avx512vlbw() && ((StrCompNode*)n)->encoding() == StrIntrinsicNode::LL); - match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2))); - effect(TEMP tmp1, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL cr); - - format %{ "String Compare byte[] $str1,$cnt1,$str2,$cnt2 -> $result // KILL $tmp1" %} - ins_encode %{ - __ string_compare($str1$$Register, $str2$$Register, - $cnt1$$Register, $cnt2$$Register, $result$$Register, - $tmp1$$XMMRegister, StrIntrinsicNode::LL, knoreg); - %} - ins_pipe( pipe_slow ); -%} - -instruct string_compareL_evex(rdi_RegP str1, rcx_RegI cnt1, rsi_RegP str2, rdx_RegI cnt2, - rax_RegI result, legRegD tmp1, kReg ktmp, rFlagsReg cr) -%{ - predicate(VM_Version::supports_avx512vlbw() && ((StrCompNode*)n)->encoding() == StrIntrinsicNode::LL); - match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2))); - effect(TEMP tmp1, TEMP ktmp, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL cr); - - format %{ "String Compare byte[] $str1,$cnt1,$str2,$cnt2 -> $result // KILL $tmp1" %} - ins_encode %{ - __ string_compare($str1$$Register, $str2$$Register, - $cnt1$$Register, $cnt2$$Register, $result$$Register, - $tmp1$$XMMRegister, StrIntrinsicNode::LL, $ktmp$$KRegister); - %} - ins_pipe( pipe_slow ); -%} - -instruct string_compareU(rdi_RegP str1, rcx_RegI cnt1, rsi_RegP str2, rdx_RegI cnt2, - rax_RegI result, legRegD tmp1, rFlagsReg cr) -%{ - predicate(!VM_Version::supports_avx512vlbw() && ((StrCompNode*)n)->encoding() == StrIntrinsicNode::UU); - match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2))); - effect(TEMP tmp1, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL cr); - - format %{ "String Compare char[] $str1,$cnt1,$str2,$cnt2 -> $result // KILL $tmp1" %} - ins_encode %{ - __ string_compare($str1$$Register, $str2$$Register, - $cnt1$$Register, $cnt2$$Register, $result$$Register, - $tmp1$$XMMRegister, StrIntrinsicNode::UU, knoreg); - %} - ins_pipe( pipe_slow ); -%} - -instruct string_compareU_evex(rdi_RegP str1, rcx_RegI cnt1, rsi_RegP str2, rdx_RegI cnt2, - rax_RegI result, legRegD tmp1, kReg ktmp, rFlagsReg cr) -%{ - predicate(VM_Version::supports_avx512vlbw() && ((StrCompNode*)n)->encoding() == StrIntrinsicNode::UU); - match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2))); - effect(TEMP tmp1, TEMP ktmp, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL cr); - - format %{ "String Compare char[] $str1,$cnt1,$str2,$cnt2 -> $result // KILL $tmp1" %} - ins_encode %{ - __ string_compare($str1$$Register, $str2$$Register, - $cnt1$$Register, $cnt2$$Register, $result$$Register, - $tmp1$$XMMRegister, StrIntrinsicNode::UU, $ktmp$$KRegister); - %} - ins_pipe( pipe_slow ); -%} - -instruct string_compareLU(rdi_RegP str1, rcx_RegI cnt1, rsi_RegP str2, rdx_RegI cnt2, - rax_RegI result, legRegD tmp1, rFlagsReg cr) -%{ - predicate(!VM_Version::supports_avx512vlbw() && ((StrCompNode*)n)->encoding() == StrIntrinsicNode::LU); - match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2))); - effect(TEMP tmp1, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL cr); - - format %{ "String Compare byte[] $str1,$cnt1,$str2,$cnt2 -> $result // KILL $tmp1" %} - ins_encode %{ - __ string_compare($str1$$Register, $str2$$Register, - $cnt1$$Register, $cnt2$$Register, $result$$Register, - $tmp1$$XMMRegister, StrIntrinsicNode::LU, knoreg); - %} - ins_pipe( pipe_slow ); -%} - -instruct string_compareLU_evex(rdi_RegP str1, rcx_RegI cnt1, rsi_RegP str2, rdx_RegI cnt2, - rax_RegI result, legRegD tmp1, kReg ktmp, rFlagsReg cr) -%{ - predicate(VM_Version::supports_avx512vlbw() && ((StrCompNode*)n)->encoding() == StrIntrinsicNode::LU); - match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2))); - effect(TEMP tmp1, TEMP ktmp, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL cr); - - format %{ "String Compare byte[] $str1,$cnt1,$str2,$cnt2 -> $result // KILL $tmp1" %} - ins_encode %{ - __ string_compare($str1$$Register, $str2$$Register, - $cnt1$$Register, $cnt2$$Register, $result$$Register, - $tmp1$$XMMRegister, StrIntrinsicNode::LU, $ktmp$$KRegister); - %} - ins_pipe( pipe_slow ); -%} - -instruct string_compareUL(rsi_RegP str1, rdx_RegI cnt1, rdi_RegP str2, rcx_RegI cnt2, - rax_RegI result, legRegD tmp1, rFlagsReg cr) -%{ - predicate(!VM_Version::supports_avx512vlbw() && ((StrCompNode*)n)->encoding() == StrIntrinsicNode::UL); - match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2))); - effect(TEMP tmp1, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL cr); - - format %{ "String Compare byte[] $str1,$cnt1,$str2,$cnt2 -> $result // KILL $tmp1" %} - ins_encode %{ - __ string_compare($str2$$Register, $str1$$Register, - $cnt2$$Register, $cnt1$$Register, $result$$Register, - $tmp1$$XMMRegister, StrIntrinsicNode::UL, knoreg); - %} - ins_pipe( pipe_slow ); -%} - -instruct string_compareUL_evex(rsi_RegP str1, rdx_RegI cnt1, rdi_RegP str2, rcx_RegI cnt2, - rax_RegI result, legRegD tmp1, kReg ktmp, rFlagsReg cr) -%{ - predicate(VM_Version::supports_avx512vlbw() && ((StrCompNode*)n)->encoding() == StrIntrinsicNode::UL); - match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2))); - effect(TEMP tmp1, TEMP ktmp, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL cr); - - format %{ "String Compare byte[] $str1,$cnt1,$str2,$cnt2 -> $result // KILL $tmp1" %} - ins_encode %{ - __ string_compare($str2$$Register, $str1$$Register, - $cnt2$$Register, $cnt1$$Register, $result$$Register, - $tmp1$$XMMRegister, StrIntrinsicNode::UL, $ktmp$$KRegister); - %} - ins_pipe( pipe_slow ); -%} - -// fast search of substring with known size. -instruct string_indexof_conL(rdi_RegP str1, rdx_RegI cnt1, rsi_RegP str2, immI int_cnt2, - rbx_RegI result, legRegD tmp_vec, rax_RegI cnt2, rcx_RegI tmp, rFlagsReg cr) -%{ - predicate(UseSSE42Intrinsics && (((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::LL)); - match(Set result (StrIndexOf (Binary str1 cnt1) (Binary str2 int_cnt2))); - effect(TEMP tmp_vec, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, KILL cnt2, KILL tmp, KILL cr); - - format %{ "String IndexOf byte[] $str1,$cnt1,$str2,$int_cnt2 -> $result // KILL $tmp_vec, $cnt1, $cnt2, $tmp" %} - ins_encode %{ - int icnt2 = (int)$int_cnt2$$constant; - if (icnt2 >= 16) { - // IndexOf for constant substrings with size >= 16 elements - // which don't need to be loaded through stack. - __ string_indexofC8($str1$$Register, $str2$$Register, - $cnt1$$Register, $cnt2$$Register, - icnt2, $result$$Register, - $tmp_vec$$XMMRegister, $tmp$$Register, StrIntrinsicNode::LL); - } else { - // Small strings are loaded through stack if they cross page boundary. - __ string_indexof($str1$$Register, $str2$$Register, - $cnt1$$Register, $cnt2$$Register, - icnt2, $result$$Register, - $tmp_vec$$XMMRegister, $tmp$$Register, StrIntrinsicNode::LL); - } - %} - ins_pipe( pipe_slow ); -%} - -// fast search of substring with known size. -instruct string_indexof_conU(rdi_RegP str1, rdx_RegI cnt1, rsi_RegP str2, immI int_cnt2, - rbx_RegI result, legRegD tmp_vec, rax_RegI cnt2, rcx_RegI tmp, rFlagsReg cr) -%{ - predicate(UseSSE42Intrinsics && (((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::UU)); - match(Set result (StrIndexOf (Binary str1 cnt1) (Binary str2 int_cnt2))); - effect(TEMP tmp_vec, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, KILL cnt2, KILL tmp, KILL cr); - - format %{ "String IndexOf char[] $str1,$cnt1,$str2,$int_cnt2 -> $result // KILL $tmp_vec, $cnt1, $cnt2, $tmp" %} - ins_encode %{ - int icnt2 = (int)$int_cnt2$$constant; - if (icnt2 >= 8) { - // IndexOf for constant substrings with size >= 8 elements - // which don't need to be loaded through stack. - __ string_indexofC8($str1$$Register, $str2$$Register, - $cnt1$$Register, $cnt2$$Register, - icnt2, $result$$Register, - $tmp_vec$$XMMRegister, $tmp$$Register, StrIntrinsicNode::UU); - } else { - // Small strings are loaded through stack if they cross page boundary. - __ string_indexof($str1$$Register, $str2$$Register, - $cnt1$$Register, $cnt2$$Register, - icnt2, $result$$Register, - $tmp_vec$$XMMRegister, $tmp$$Register, StrIntrinsicNode::UU); - } - %} - ins_pipe( pipe_slow ); -%} - -// fast search of substring with known size. -instruct string_indexof_conUL(rdi_RegP str1, rdx_RegI cnt1, rsi_RegP str2, immI int_cnt2, - rbx_RegI result, legRegD tmp_vec, rax_RegI cnt2, rcx_RegI tmp, rFlagsReg cr) -%{ - predicate(UseSSE42Intrinsics && (((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::UL)); - match(Set result (StrIndexOf (Binary str1 cnt1) (Binary str2 int_cnt2))); - effect(TEMP tmp_vec, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, KILL cnt2, KILL tmp, KILL cr); - - format %{ "String IndexOf char[] $str1,$cnt1,$str2,$int_cnt2 -> $result // KILL $tmp_vec, $cnt1, $cnt2, $tmp" %} - ins_encode %{ - int icnt2 = (int)$int_cnt2$$constant; - if (icnt2 >= 8) { - // IndexOf for constant substrings with size >= 8 elements - // which don't need to be loaded through stack. - __ string_indexofC8($str1$$Register, $str2$$Register, - $cnt1$$Register, $cnt2$$Register, - icnt2, $result$$Register, - $tmp_vec$$XMMRegister, $tmp$$Register, StrIntrinsicNode::UL); - } else { - // Small strings are loaded through stack if they cross page boundary. - __ string_indexof($str1$$Register, $str2$$Register, - $cnt1$$Register, $cnt2$$Register, - icnt2, $result$$Register, - $tmp_vec$$XMMRegister, $tmp$$Register, StrIntrinsicNode::UL); - } - %} - ins_pipe( pipe_slow ); -%} - -instruct string_indexofL(rdi_RegP str1, rdx_RegI cnt1, rsi_RegP str2, rax_RegI cnt2, - rbx_RegI result, legRegD tmp_vec, rcx_RegI tmp, rFlagsReg cr) -%{ - predicate(UseSSE42Intrinsics && (((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::LL)); - match(Set result (StrIndexOf (Binary str1 cnt1) (Binary str2 cnt2))); - effect(TEMP tmp_vec, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL tmp, KILL cr); - - format %{ "String IndexOf byte[] $str1,$cnt1,$str2,$cnt2 -> $result // KILL all" %} - ins_encode %{ - __ string_indexof($str1$$Register, $str2$$Register, - $cnt1$$Register, $cnt2$$Register, - (-1), $result$$Register, - $tmp_vec$$XMMRegister, $tmp$$Register, StrIntrinsicNode::LL); - %} - ins_pipe( pipe_slow ); -%} - -instruct string_indexofU(rdi_RegP str1, rdx_RegI cnt1, rsi_RegP str2, rax_RegI cnt2, - rbx_RegI result, legRegD tmp_vec, rcx_RegI tmp, rFlagsReg cr) -%{ - predicate(UseSSE42Intrinsics && (((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::UU)); - match(Set result (StrIndexOf (Binary str1 cnt1) (Binary str2 cnt2))); - effect(TEMP tmp_vec, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL tmp, KILL cr); - - format %{ "String IndexOf char[] $str1,$cnt1,$str2,$cnt2 -> $result // KILL all" %} - ins_encode %{ - __ string_indexof($str1$$Register, $str2$$Register, - $cnt1$$Register, $cnt2$$Register, - (-1), $result$$Register, - $tmp_vec$$XMMRegister, $tmp$$Register, StrIntrinsicNode::UU); - %} - ins_pipe( pipe_slow ); -%} - -instruct string_indexofUL(rdi_RegP str1, rdx_RegI cnt1, rsi_RegP str2, rax_RegI cnt2, - rbx_RegI result, legRegD tmp_vec, rcx_RegI tmp, rFlagsReg cr) -%{ - predicate(UseSSE42Intrinsics && (((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::UL)); - match(Set result (StrIndexOf (Binary str1 cnt1) (Binary str2 cnt2))); - effect(TEMP tmp_vec, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL tmp, KILL cr); - - format %{ "String IndexOf char[] $str1,$cnt1,$str2,$cnt2 -> $result // KILL all" %} - ins_encode %{ - __ string_indexof($str1$$Register, $str2$$Register, - $cnt1$$Register, $cnt2$$Register, - (-1), $result$$Register, - $tmp_vec$$XMMRegister, $tmp$$Register, StrIntrinsicNode::UL); - %} - ins_pipe( pipe_slow ); -%} - -instruct string_indexof_char(rdi_RegP str1, rdx_RegI cnt1, rax_RegI ch, - rbx_RegI result, legRegD tmp_vec1, legRegD tmp_vec2, legRegD tmp_vec3, rcx_RegI tmp, rFlagsReg cr) -%{ - predicate(UseSSE42Intrinsics && (((StrIndexOfCharNode*)n)->encoding() == StrIntrinsicNode::U)); - match(Set result (StrIndexOfChar (Binary str1 cnt1) ch)); - effect(TEMP tmp_vec1, TEMP tmp_vec2, TEMP tmp_vec3, USE_KILL str1, USE_KILL cnt1, USE_KILL ch, TEMP tmp, KILL cr); - format %{ "StringUTF16 IndexOf char[] $str1,$cnt1,$ch -> $result // KILL all" %} - ins_encode %{ - __ string_indexof_char($str1$$Register, $cnt1$$Register, $ch$$Register, $result$$Register, - $tmp_vec1$$XMMRegister, $tmp_vec2$$XMMRegister, $tmp_vec3$$XMMRegister, $tmp$$Register); - %} - ins_pipe( pipe_slow ); -%} - -instruct stringL_indexof_char(rdi_RegP str1, rdx_RegI cnt1, rax_RegI ch, - rbx_RegI result, legRegD tmp_vec1, legRegD tmp_vec2, legRegD tmp_vec3, rcx_RegI tmp, rFlagsReg cr) -%{ - predicate(UseSSE42Intrinsics && (((StrIndexOfCharNode*)n)->encoding() == StrIntrinsicNode::L)); - match(Set result (StrIndexOfChar (Binary str1 cnt1) ch)); - effect(TEMP tmp_vec1, TEMP tmp_vec2, TEMP tmp_vec3, USE_KILL str1, USE_KILL cnt1, USE_KILL ch, TEMP tmp, KILL cr); - format %{ "StringLatin1 IndexOf char[] $str1,$cnt1,$ch -> $result // KILL all" %} - ins_encode %{ - __ stringL_indexof_char($str1$$Register, $cnt1$$Register, $ch$$Register, $result$$Register, - $tmp_vec1$$XMMRegister, $tmp_vec2$$XMMRegister, $tmp_vec3$$XMMRegister, $tmp$$Register); - %} - ins_pipe( pipe_slow ); -%} - -// fast string equals -instruct string_equals(rdi_RegP str1, rsi_RegP str2, rcx_RegI cnt, rax_RegI result, - legRegD tmp1, legRegD tmp2, rbx_RegI tmp3, rFlagsReg cr) -%{ - predicate(!VM_Version::supports_avx512vlbw()); - match(Set result (StrEquals (Binary str1 str2) cnt)); - effect(TEMP tmp1, TEMP tmp2, USE_KILL str1, USE_KILL str2, USE_KILL cnt, KILL tmp3, KILL cr); - - format %{ "String Equals $str1,$str2,$cnt -> $result // KILL $tmp1, $tmp2, $tmp3" %} - ins_encode %{ - __ arrays_equals(false, $str1$$Register, $str2$$Register, - $cnt$$Register, $result$$Register, $tmp3$$Register, - $tmp1$$XMMRegister, $tmp2$$XMMRegister, false /* char */, knoreg); - %} - ins_pipe( pipe_slow ); -%} - -instruct string_equals_evex(rdi_RegP str1, rsi_RegP str2, rcx_RegI cnt, rax_RegI result, - legRegD tmp1, legRegD tmp2, kReg ktmp, rbx_RegI tmp3, rFlagsReg cr) -%{ - predicate(VM_Version::supports_avx512vlbw()); - match(Set result (StrEquals (Binary str1 str2) cnt)); - effect(TEMP tmp1, TEMP tmp2, TEMP ktmp, USE_KILL str1, USE_KILL str2, USE_KILL cnt, KILL tmp3, KILL cr); - - format %{ "String Equals $str1,$str2,$cnt -> $result // KILL $tmp1, $tmp2, $tmp3" %} - ins_encode %{ - __ arrays_equals(false, $str1$$Register, $str2$$Register, - $cnt$$Register, $result$$Register, $tmp3$$Register, - $tmp1$$XMMRegister, $tmp2$$XMMRegister, false /* char */, $ktmp$$KRegister); - %} - ins_pipe( pipe_slow ); -%} - -// fast array equals -instruct array_equalsB(rdi_RegP ary1, rsi_RegP ary2, rax_RegI result, - legRegD tmp1, legRegD tmp2, rcx_RegI tmp3, rbx_RegI tmp4, rFlagsReg cr) -%{ - predicate(!VM_Version::supports_avx512vlbw() && ((AryEqNode*)n)->encoding() == StrIntrinsicNode::LL); - match(Set result (AryEq ary1 ary2)); - effect(TEMP tmp1, TEMP tmp2, USE_KILL ary1, USE_KILL ary2, KILL tmp3, KILL tmp4, KILL cr); - - format %{ "Array Equals byte[] $ary1,$ary2 -> $result // KILL $tmp1, $tmp2, $tmp3, $tmp4" %} - ins_encode %{ - __ arrays_equals(true, $ary1$$Register, $ary2$$Register, - $tmp3$$Register, $result$$Register, $tmp4$$Register, - $tmp1$$XMMRegister, $tmp2$$XMMRegister, false /* char */, knoreg); - %} - ins_pipe( pipe_slow ); -%} - -instruct array_equalsB_evex(rdi_RegP ary1, rsi_RegP ary2, rax_RegI result, - legRegD tmp1, legRegD tmp2, kReg ktmp, rcx_RegI tmp3, rbx_RegI tmp4, rFlagsReg cr) -%{ - predicate(VM_Version::supports_avx512vlbw() && ((AryEqNode*)n)->encoding() == StrIntrinsicNode::LL); - match(Set result (AryEq ary1 ary2)); - effect(TEMP tmp1, TEMP tmp2, TEMP ktmp, USE_KILL ary1, USE_KILL ary2, KILL tmp3, KILL tmp4, KILL cr); - - format %{ "Array Equals byte[] $ary1,$ary2 -> $result // KILL $tmp1, $tmp2, $tmp3, $tmp4" %} - ins_encode %{ - __ arrays_equals(true, $ary1$$Register, $ary2$$Register, - $tmp3$$Register, $result$$Register, $tmp4$$Register, - $tmp1$$XMMRegister, $tmp2$$XMMRegister, false /* char */, $ktmp$$KRegister); - %} - ins_pipe( pipe_slow ); -%} - -instruct array_equalsC(rdi_RegP ary1, rsi_RegP ary2, rax_RegI result, - legRegD tmp1, legRegD tmp2, rcx_RegI tmp3, rbx_RegI tmp4, rFlagsReg cr) -%{ - predicate(!VM_Version::supports_avx512vlbw() && ((AryEqNode*)n)->encoding() == StrIntrinsicNode::UU); - match(Set result (AryEq ary1 ary2)); - effect(TEMP tmp1, TEMP tmp2, USE_KILL ary1, USE_KILL ary2, KILL tmp3, KILL tmp4, KILL cr); - - format %{ "Array Equals char[] $ary1,$ary2 -> $result // KILL $tmp1, $tmp2, $tmp3, $tmp4" %} - ins_encode %{ - __ arrays_equals(true, $ary1$$Register, $ary2$$Register, - $tmp3$$Register, $result$$Register, $tmp4$$Register, - $tmp1$$XMMRegister, $tmp2$$XMMRegister, true /* char */, knoreg); - %} - ins_pipe( pipe_slow ); -%} - -instruct array_equalsC_evex(rdi_RegP ary1, rsi_RegP ary2, rax_RegI result, - legRegD tmp1, legRegD tmp2, kReg ktmp, rcx_RegI tmp3, rbx_RegI tmp4, rFlagsReg cr) -%{ - predicate(VM_Version::supports_avx512vlbw() && ((AryEqNode*)n)->encoding() == StrIntrinsicNode::UU); - match(Set result (AryEq ary1 ary2)); - effect(TEMP tmp1, TEMP tmp2, TEMP ktmp, USE_KILL ary1, USE_KILL ary2, KILL tmp3, KILL tmp4, KILL cr); - - format %{ "Array Equals char[] $ary1,$ary2 -> $result // KILL $tmp1, $tmp2, $tmp3, $tmp4" %} - ins_encode %{ - __ arrays_equals(true, $ary1$$Register, $ary2$$Register, - $tmp3$$Register, $result$$Register, $tmp4$$Register, - $tmp1$$XMMRegister, $tmp2$$XMMRegister, true /* char */, $ktmp$$KRegister); - %} - ins_pipe( pipe_slow ); -%} - -instruct arrays_hashcode(rdi_RegP ary1, rdx_RegI cnt1, rbx_RegI result, immU8 basic_type, - legRegD tmp_vec1, legRegD tmp_vec2, legRegD tmp_vec3, legRegD tmp_vec4, - legRegD tmp_vec5, legRegD tmp_vec6, legRegD tmp_vec7, legRegD tmp_vec8, - legRegD tmp_vec9, legRegD tmp_vec10, legRegD tmp_vec11, legRegD tmp_vec12, - legRegD tmp_vec13, rRegI tmp1, rRegI tmp2, rRegI tmp3, rFlagsReg cr) -%{ - predicate(UseAVX >= 2); - match(Set result (VectorizedHashCode (Binary ary1 cnt1) (Binary result basic_type))); - effect(TEMP tmp_vec1, TEMP tmp_vec2, TEMP tmp_vec3, TEMP tmp_vec4, TEMP tmp_vec5, TEMP tmp_vec6, - TEMP tmp_vec7, TEMP tmp_vec8, TEMP tmp_vec9, TEMP tmp_vec10, TEMP tmp_vec11, TEMP tmp_vec12, - TEMP tmp_vec13, TEMP tmp1, TEMP tmp2, TEMP tmp3, USE_KILL ary1, USE_KILL cnt1, - USE basic_type, KILL cr); - - format %{ "Array HashCode array[] $ary1,$cnt1,$result,$basic_type -> $result // KILL all" %} - ins_encode %{ - __ arrays_hashcode($ary1$$Register, $cnt1$$Register, $result$$Register, - $tmp1$$Register, $tmp2$$Register, $tmp3$$Register, - $tmp_vec1$$XMMRegister, $tmp_vec2$$XMMRegister, $tmp_vec3$$XMMRegister, - $tmp_vec4$$XMMRegister, $tmp_vec5$$XMMRegister, $tmp_vec6$$XMMRegister, - $tmp_vec7$$XMMRegister, $tmp_vec8$$XMMRegister, $tmp_vec9$$XMMRegister, - $tmp_vec10$$XMMRegister, $tmp_vec11$$XMMRegister, $tmp_vec12$$XMMRegister, - $tmp_vec13$$XMMRegister, (BasicType)$basic_type$$constant); - %} - ins_pipe( pipe_slow ); -%} - -instruct count_positives(rsi_RegP ary1, rcx_RegI len, rax_RegI result, - legRegD tmp1, legRegD tmp2, rbx_RegI tmp3, rFlagsReg cr,) -%{ - predicate(!VM_Version::supports_avx512vlbw() || !VM_Version::supports_bmi2()); - match(Set result (CountPositives ary1 len)); - effect(TEMP tmp1, TEMP tmp2, USE_KILL ary1, USE_KILL len, KILL tmp3, KILL cr); - - format %{ "countPositives byte[] $ary1,$len -> $result // KILL $tmp1, $tmp2, $tmp3" %} - ins_encode %{ - __ count_positives($ary1$$Register, $len$$Register, - $result$$Register, $tmp3$$Register, - $tmp1$$XMMRegister, $tmp2$$XMMRegister, knoreg, knoreg); - %} - ins_pipe( pipe_slow ); -%} - -instruct count_positives_evex(rsi_RegP ary1, rcx_RegI len, rax_RegI result, - legRegD tmp1, legRegD tmp2, kReg ktmp1, kReg ktmp2, rbx_RegI tmp3, rFlagsReg cr,) -%{ - predicate(VM_Version::supports_avx512vlbw() && VM_Version::supports_bmi2()); - match(Set result (CountPositives ary1 len)); - effect(TEMP tmp1, TEMP tmp2, TEMP ktmp1, TEMP ktmp2, USE_KILL ary1, USE_KILL len, KILL tmp3, KILL cr); - - format %{ "countPositives byte[] $ary1,$len -> $result // KILL $tmp1, $tmp2, $tmp3" %} - ins_encode %{ - __ count_positives($ary1$$Register, $len$$Register, - $result$$Register, $tmp3$$Register, - $tmp1$$XMMRegister, $tmp2$$XMMRegister, $ktmp1$$KRegister, $ktmp2$$KRegister); - %} - ins_pipe( pipe_slow ); -%} - -// fast char[] to byte[] compression -instruct string_compress(rsi_RegP src, rdi_RegP dst, rdx_RegI len, legRegD tmp1, legRegD tmp2, legRegD tmp3, - legRegD tmp4, rcx_RegI tmp5, rax_RegI result, rFlagsReg cr) %{ - predicate(!VM_Version::supports_avx512vlbw() || !VM_Version::supports_bmi2()); - match(Set result (StrCompressedCopy src (Binary dst len))); - effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, USE_KILL src, USE_KILL dst, - USE_KILL len, KILL tmp5, KILL cr); - - format %{ "String Compress $src,$dst -> $result // KILL RAX, RCX, RDX" %} - ins_encode %{ - __ char_array_compress($src$$Register, $dst$$Register, $len$$Register, - $tmp1$$XMMRegister, $tmp2$$XMMRegister, $tmp3$$XMMRegister, - $tmp4$$XMMRegister, $tmp5$$Register, $result$$Register, - knoreg, knoreg); - %} - ins_pipe( pipe_slow ); -%} - -instruct string_compress_evex(rsi_RegP src, rdi_RegP dst, rdx_RegI len, legRegD tmp1, legRegD tmp2, legRegD tmp3, - legRegD tmp4, kReg ktmp1, kReg ktmp2, rcx_RegI tmp5, rax_RegI result, rFlagsReg cr) %{ - predicate(VM_Version::supports_avx512vlbw() && VM_Version::supports_bmi2()); - match(Set result (StrCompressedCopy src (Binary dst len))); - effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, TEMP ktmp1, TEMP ktmp2, USE_KILL src, USE_KILL dst, - USE_KILL len, KILL tmp5, KILL cr); - - format %{ "String Compress $src,$dst -> $result // KILL RAX, RCX, RDX" %} - ins_encode %{ - __ char_array_compress($src$$Register, $dst$$Register, $len$$Register, - $tmp1$$XMMRegister, $tmp2$$XMMRegister, $tmp3$$XMMRegister, - $tmp4$$XMMRegister, $tmp5$$Register, $result$$Register, - $ktmp1$$KRegister, $ktmp2$$KRegister); - %} - ins_pipe( pipe_slow ); -%} -// fast byte[] to char[] inflation -instruct string_inflate(Universe dummy, rsi_RegP src, rdi_RegP dst, rdx_RegI len, - legRegD tmp1, rcx_RegI tmp2, rFlagsReg cr) %{ - predicate(!VM_Version::supports_avx512vlbw() || !VM_Version::supports_bmi2()); - match(Set dummy (StrInflatedCopy src (Binary dst len))); - effect(TEMP tmp1, TEMP tmp2, USE_KILL src, USE_KILL dst, USE_KILL len, KILL cr); - - format %{ "String Inflate $src,$dst // KILL $tmp1, $tmp2" %} - ins_encode %{ - __ byte_array_inflate($src$$Register, $dst$$Register, $len$$Register, - $tmp1$$XMMRegister, $tmp2$$Register, knoreg); - %} - ins_pipe( pipe_slow ); -%} - -instruct string_inflate_evex(Universe dummy, rsi_RegP src, rdi_RegP dst, rdx_RegI len, - legRegD tmp1, kReg ktmp, rcx_RegI tmp2, rFlagsReg cr) %{ - predicate(VM_Version::supports_avx512vlbw() && VM_Version::supports_bmi2()); - match(Set dummy (StrInflatedCopy src (Binary dst len))); - effect(TEMP tmp1, TEMP tmp2, TEMP ktmp, USE_KILL src, USE_KILL dst, USE_KILL len, KILL cr); - - format %{ "String Inflate $src,$dst // KILL $tmp1, $tmp2" %} - ins_encode %{ - __ byte_array_inflate($src$$Register, $dst$$Register, $len$$Register, - $tmp1$$XMMRegister, $tmp2$$Register, $ktmp$$KRegister); - %} - ins_pipe( pipe_slow ); -%} - -// encode char[] to byte[] in ISO_8859_1 -instruct encode_iso_array(rsi_RegP src, rdi_RegP dst, rdx_RegI len, - legRegD tmp1, legRegD tmp2, legRegD tmp3, legRegD tmp4, - rcx_RegI tmp5, rax_RegI result, rFlagsReg cr) %{ - predicate(!((EncodeISOArrayNode*)n)->is_ascii()); - match(Set result (EncodeISOArray src (Binary dst len))); - effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, USE_KILL src, USE_KILL dst, USE_KILL len, KILL tmp5, KILL cr); - - format %{ "Encode iso array $src,$dst,$len -> $result // KILL RCX, RDX, $tmp1, $tmp2, $tmp3, $tmp4, RSI, RDI " %} - ins_encode %{ - __ encode_iso_array($src$$Register, $dst$$Register, $len$$Register, - $tmp1$$XMMRegister, $tmp2$$XMMRegister, $tmp3$$XMMRegister, - $tmp4$$XMMRegister, $tmp5$$Register, $result$$Register, false); - %} - ins_pipe( pipe_slow ); -%} - -// encode char[] to byte[] in ASCII -instruct encode_ascii_array(rsi_RegP src, rdi_RegP dst, rdx_RegI len, - legRegD tmp1, legRegD tmp2, legRegD tmp3, legRegD tmp4, - rcx_RegI tmp5, rax_RegI result, rFlagsReg cr) %{ - predicate(((EncodeISOArrayNode*)n)->is_ascii()); - match(Set result (EncodeISOArray src (Binary dst len))); - effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, USE_KILL src, USE_KILL dst, USE_KILL len, KILL tmp5, KILL cr); - - format %{ "Encode ascii array $src,$dst,$len -> $result // KILL RCX, RDX, $tmp1, $tmp2, $tmp3, $tmp4, RSI, RDI " %} - ins_encode %{ - __ encode_iso_array($src$$Register, $dst$$Register, $len$$Register, - $tmp1$$XMMRegister, $tmp2$$XMMRegister, $tmp3$$XMMRegister, - $tmp4$$XMMRegister, $tmp5$$Register, $result$$Register, true); - %} - ins_pipe( pipe_slow ); -%} - -//----------Overflow Math Instructions----------------------------------------- - -instruct overflowAddI_rReg(rFlagsReg cr, rax_RegI op1, rRegI op2) -%{ - match(Set cr (OverflowAddI op1 op2)); - effect(DEF cr, USE_KILL op1, USE op2); - - format %{ "addl $op1, $op2\t# overflow check int" %} - - ins_encode %{ - __ addl($op1$$Register, $op2$$Register); - %} - ins_pipe(ialu_reg_reg); -%} - -instruct overflowAddI_rReg_imm(rFlagsReg cr, rax_RegI op1, immI op2) -%{ - match(Set cr (OverflowAddI op1 op2)); - effect(DEF cr, USE_KILL op1, USE op2); - - format %{ "addl $op1, $op2\t# overflow check int" %} - - ins_encode %{ - __ addl($op1$$Register, $op2$$constant); - %} - ins_pipe(ialu_reg_reg); -%} - -instruct overflowAddL_rReg(rFlagsReg cr, rax_RegL op1, rRegL op2) -%{ - match(Set cr (OverflowAddL op1 op2)); - effect(DEF cr, USE_KILL op1, USE op2); - - format %{ "addq $op1, $op2\t# overflow check long" %} - ins_encode %{ - __ addq($op1$$Register, $op2$$Register); - %} - ins_pipe(ialu_reg_reg); -%} - -instruct overflowAddL_rReg_imm(rFlagsReg cr, rax_RegL op1, immL32 op2) -%{ - match(Set cr (OverflowAddL op1 op2)); - effect(DEF cr, USE_KILL op1, USE op2); - - format %{ "addq $op1, $op2\t# overflow check long" %} - ins_encode %{ - __ addq($op1$$Register, $op2$$constant); - %} - ins_pipe(ialu_reg_reg); -%} - -instruct overflowSubI_rReg(rFlagsReg cr, rRegI op1, rRegI op2) -%{ - match(Set cr (OverflowSubI op1 op2)); - - format %{ "cmpl $op1, $op2\t# overflow check int" %} - ins_encode %{ - __ cmpl($op1$$Register, $op2$$Register); - %} - ins_pipe(ialu_reg_reg); -%} - -instruct overflowSubI_rReg_imm(rFlagsReg cr, rRegI op1, immI op2) -%{ - match(Set cr (OverflowSubI op1 op2)); - - format %{ "cmpl $op1, $op2\t# overflow check int" %} - ins_encode %{ - __ cmpl($op1$$Register, $op2$$constant); - %} - ins_pipe(ialu_reg_reg); -%} - -instruct overflowSubL_rReg(rFlagsReg cr, rRegL op1, rRegL op2) -%{ - match(Set cr (OverflowSubL op1 op2)); - - format %{ "cmpq $op1, $op2\t# overflow check long" %} - ins_encode %{ - __ cmpq($op1$$Register, $op2$$Register); - %} - ins_pipe(ialu_reg_reg); -%} - -instruct overflowSubL_rReg_imm(rFlagsReg cr, rRegL op1, immL32 op2) -%{ - match(Set cr (OverflowSubL op1 op2)); - - format %{ "cmpq $op1, $op2\t# overflow check long" %} - ins_encode %{ - __ cmpq($op1$$Register, $op2$$constant); - %} - ins_pipe(ialu_reg_reg); -%} - -instruct overflowNegI_rReg(rFlagsReg cr, immI_0 zero, rax_RegI op2) -%{ - match(Set cr (OverflowSubI zero op2)); - effect(DEF cr, USE_KILL op2); - - format %{ "negl $op2\t# overflow check int" %} - ins_encode %{ - __ negl($op2$$Register); - %} - ins_pipe(ialu_reg_reg); -%} - -instruct overflowNegL_rReg(rFlagsReg cr, immL0 zero, rax_RegL op2) -%{ - match(Set cr (OverflowSubL zero op2)); - effect(DEF cr, USE_KILL op2); - - format %{ "negq $op2\t# overflow check long" %} - ins_encode %{ - __ negq($op2$$Register); - %} - ins_pipe(ialu_reg_reg); -%} - -instruct overflowMulI_rReg(rFlagsReg cr, rax_RegI op1, rRegI op2) -%{ - match(Set cr (OverflowMulI op1 op2)); - effect(DEF cr, USE_KILL op1, USE op2); - - format %{ "imull $op1, $op2\t# overflow check int" %} - ins_encode %{ - __ imull($op1$$Register, $op2$$Register); - %} - ins_pipe(ialu_reg_reg_alu0); -%} - -instruct overflowMulI_rReg_imm(rFlagsReg cr, rRegI op1, immI op2, rRegI tmp) -%{ - match(Set cr (OverflowMulI op1 op2)); - effect(DEF cr, TEMP tmp, USE op1, USE op2); - - format %{ "imull $tmp, $op1, $op2\t# overflow check int" %} - ins_encode %{ - __ imull($tmp$$Register, $op1$$Register, $op2$$constant); - %} - ins_pipe(ialu_reg_reg_alu0); -%} - -instruct overflowMulL_rReg(rFlagsReg cr, rax_RegL op1, rRegL op2) -%{ - match(Set cr (OverflowMulL op1 op2)); - effect(DEF cr, USE_KILL op1, USE op2); - - format %{ "imulq $op1, $op2\t# overflow check long" %} - ins_encode %{ - __ imulq($op1$$Register, $op2$$Register); - %} - ins_pipe(ialu_reg_reg_alu0); -%} - -instruct overflowMulL_rReg_imm(rFlagsReg cr, rRegL op1, immL32 op2, rRegL tmp) -%{ - match(Set cr (OverflowMulL op1 op2)); - effect(DEF cr, TEMP tmp, USE op1, USE op2); - - format %{ "imulq $tmp, $op1, $op2\t# overflow check long" %} - ins_encode %{ - __ imulq($tmp$$Register, $op1$$Register, $op2$$constant); - %} - ins_pipe(ialu_reg_reg_alu0); -%} - - -//----------Control Flow Instructions------------------------------------------ -// Signed compare Instructions - -// XXX more variants!! -instruct compI_rReg(rFlagsReg cr, rRegI op1, rRegI op2) -%{ - match(Set cr (CmpI op1 op2)); - effect(DEF cr, USE op1, USE op2); - - format %{ "cmpl $op1, $op2" %} - ins_encode %{ - __ cmpl($op1$$Register, $op2$$Register); - %} - ins_pipe(ialu_cr_reg_reg); -%} - -instruct compI_rReg_imm(rFlagsReg cr, rRegI op1, immI op2) -%{ - match(Set cr (CmpI op1 op2)); - - format %{ "cmpl $op1, $op2" %} - ins_encode %{ - __ cmpl($op1$$Register, $op2$$constant); - %} - ins_pipe(ialu_cr_reg_imm); -%} - -instruct compI_rReg_mem(rFlagsReg cr, rRegI op1, memory op2) -%{ - match(Set cr (CmpI op1 (LoadI op2))); - - ins_cost(500); // XXX - format %{ "cmpl $op1, $op2" %} - ins_encode %{ - __ cmpl($op1$$Register, $op2$$Address); - %} - ins_pipe(ialu_cr_reg_mem); -%} - -instruct testI_reg(rFlagsReg cr, rRegI src, immI_0 zero) -%{ - match(Set cr (CmpI src zero)); - - format %{ "testl $src, $src" %} - ins_encode %{ - __ testl($src$$Register, $src$$Register); - %} - ins_pipe(ialu_cr_reg_imm); -%} - -instruct testI_reg_imm(rFlagsReg cr, rRegI src, immI con, immI_0 zero) -%{ - match(Set cr (CmpI (AndI src con) zero)); - - format %{ "testl $src, $con" %} - ins_encode %{ - __ testl($src$$Register, $con$$constant); - %} - ins_pipe(ialu_cr_reg_imm); -%} - -instruct testI_reg_reg(rFlagsReg cr, rRegI src1, rRegI src2, immI_0 zero) -%{ - match(Set cr (CmpI (AndI src1 src2) zero)); - - format %{ "testl $src1, $src2" %} - ins_encode %{ - __ testl($src1$$Register, $src2$$Register); - %} - ins_pipe(ialu_cr_reg_imm); -%} - -instruct testI_reg_mem(rFlagsReg cr, rRegI src, memory mem, immI_0 zero) -%{ - match(Set cr (CmpI (AndI src (LoadI mem)) zero)); - - format %{ "testl $src, $mem" %} - ins_encode %{ - __ testl($src$$Register, $mem$$Address); - %} - ins_pipe(ialu_cr_reg_mem); -%} - -// Unsigned compare Instructions; really, same as signed except they -// produce an rFlagsRegU instead of rFlagsReg. -instruct compU_rReg(rFlagsRegU cr, rRegI op1, rRegI op2) -%{ - match(Set cr (CmpU op1 op2)); - - format %{ "cmpl $op1, $op2\t# unsigned" %} - ins_encode %{ - __ cmpl($op1$$Register, $op2$$Register); - %} - ins_pipe(ialu_cr_reg_reg); -%} - -instruct compU_rReg_imm(rFlagsRegU cr, rRegI op1, immI op2) -%{ - match(Set cr (CmpU op1 op2)); - - format %{ "cmpl $op1, $op2\t# unsigned" %} - ins_encode %{ - __ cmpl($op1$$Register, $op2$$constant); - %} - ins_pipe(ialu_cr_reg_imm); -%} - -instruct compU_rReg_mem(rFlagsRegU cr, rRegI op1, memory op2) -%{ - match(Set cr (CmpU op1 (LoadI op2))); - - ins_cost(500); // XXX - format %{ "cmpl $op1, $op2\t# unsigned" %} - ins_encode %{ - __ cmpl($op1$$Register, $op2$$Address); - %} - ins_pipe(ialu_cr_reg_mem); -%} - -instruct testU_reg(rFlagsRegU cr, rRegI src, immI_0 zero) -%{ - match(Set cr (CmpU src zero)); - - format %{ "testl $src, $src\t# unsigned" %} - ins_encode %{ - __ testl($src$$Register, $src$$Register); - %} - ins_pipe(ialu_cr_reg_imm); -%} - -instruct compP_rReg(rFlagsRegU cr, rRegP op1, rRegP op2) -%{ - match(Set cr (CmpP op1 op2)); - - format %{ "cmpq $op1, $op2\t# ptr" %} - ins_encode %{ - __ cmpq($op1$$Register, $op2$$Register); - %} - ins_pipe(ialu_cr_reg_reg); -%} - -instruct compP_rReg_mem(rFlagsRegU cr, rRegP op1, memory op2) -%{ - match(Set cr (CmpP op1 (LoadP op2))); - predicate(n->in(2)->as_Load()->barrier_data() == 0); - - ins_cost(500); // XXX - format %{ "cmpq $op1, $op2\t# ptr" %} - ins_encode %{ - __ cmpq($op1$$Register, $op2$$Address); - %} - ins_pipe(ialu_cr_reg_mem); -%} - -// XXX this is generalized by compP_rReg_mem??? -// Compare raw pointer (used in out-of-heap check). -// Only works because non-oop pointers must be raw pointers -// and raw pointers have no anti-dependencies. -instruct compP_mem_rReg(rFlagsRegU cr, rRegP op1, memory op2) -%{ - predicate(n->in(2)->in(2)->bottom_type()->reloc() == relocInfo::none && - n->in(2)->as_Load()->barrier_data() == 0); - match(Set cr (CmpP op1 (LoadP op2))); - - format %{ "cmpq $op1, $op2\t# raw ptr" %} - ins_encode %{ - __ cmpq($op1$$Register, $op2$$Address); - %} - ins_pipe(ialu_cr_reg_mem); -%} - -// This will generate a signed flags result. This should be OK since -// any compare to a zero should be eq/neq. -instruct testP_reg(rFlagsReg cr, rRegP src, immP0 zero) -%{ - match(Set cr (CmpP src zero)); - - format %{ "testq $src, $src\t# ptr" %} - ins_encode %{ - __ testq($src$$Register, $src$$Register); - %} - ins_pipe(ialu_cr_reg_imm); -%} - -// This will generate a signed flags result. This should be OK since -// any compare to a zero should be eq/neq. -instruct testP_mem(rFlagsReg cr, memory op, immP0 zero) -%{ - predicate((!UseCompressedOops || (CompressedOops::base() != nullptr)) && - n->in(1)->as_Load()->barrier_data() == 0); - match(Set cr (CmpP (LoadP op) zero)); - - ins_cost(500); // XXX - format %{ "testq $op, 0xffffffffffffffff\t# ptr" %} - ins_encode %{ - __ testq($op$$Address, 0xFFFFFFFF); - %} - ins_pipe(ialu_cr_reg_imm); -%} - -instruct testP_mem_reg0(rFlagsReg cr, memory mem, immP0 zero) -%{ - predicate(UseCompressedOops && (CompressedOops::base() == nullptr) && - n->in(1)->as_Load()->barrier_data() == 0); - match(Set cr (CmpP (LoadP mem) zero)); - - format %{ "cmpq R12, $mem\t# ptr (R12_heapbase==0)" %} - ins_encode %{ - __ cmpq(r12, $mem$$Address); - %} - ins_pipe(ialu_cr_reg_mem); -%} - -instruct compN_rReg(rFlagsRegU cr, rRegN op1, rRegN op2) -%{ - match(Set cr (CmpN op1 op2)); - - format %{ "cmpl $op1, $op2\t# compressed ptr" %} - ins_encode %{ __ cmpl($op1$$Register, $op2$$Register); %} - ins_pipe(ialu_cr_reg_reg); -%} - -instruct compN_rReg_mem(rFlagsRegU cr, rRegN src, memory mem) -%{ - predicate(n->in(2)->as_Load()->barrier_data() == 0); - match(Set cr (CmpN src (LoadN mem))); - - format %{ "cmpl $src, $mem\t# compressed ptr" %} - ins_encode %{ - __ cmpl($src$$Register, $mem$$Address); - %} - ins_pipe(ialu_cr_reg_mem); -%} - -instruct compN_rReg_imm(rFlagsRegU cr, rRegN op1, immN op2) %{ - match(Set cr (CmpN op1 op2)); - - format %{ "cmpl $op1, $op2\t# compressed ptr" %} - ins_encode %{ - __ cmp_narrow_oop($op1$$Register, (jobject)$op2$$constant); - %} - ins_pipe(ialu_cr_reg_imm); -%} - -instruct compN_mem_imm(rFlagsRegU cr, memory mem, immN src) -%{ - predicate(n->in(2)->as_Load()->barrier_data() == 0); - match(Set cr (CmpN src (LoadN mem))); - - format %{ "cmpl $mem, $src\t# compressed ptr" %} - ins_encode %{ - __ cmp_narrow_oop($mem$$Address, (jobject)$src$$constant); - %} - ins_pipe(ialu_cr_reg_mem); -%} - -instruct compN_rReg_imm_klass(rFlagsRegU cr, rRegN op1, immNKlass op2) %{ - match(Set cr (CmpN op1 op2)); - - format %{ "cmpl $op1, $op2\t# compressed klass ptr" %} - ins_encode %{ - __ cmp_narrow_klass($op1$$Register, (Klass*)$op2$$constant); - %} - ins_pipe(ialu_cr_reg_imm); -%} - -instruct compN_mem_imm_klass(rFlagsRegU cr, memory mem, immNKlass src) -%{ - predicate(!UseCompactObjectHeaders); - match(Set cr (CmpN src (LoadNKlass mem))); - - format %{ "cmpl $mem, $src\t# compressed klass ptr" %} - ins_encode %{ - __ cmp_narrow_klass($mem$$Address, (Klass*)$src$$constant); - %} - ins_pipe(ialu_cr_reg_mem); -%} - -instruct testN_reg(rFlagsReg cr, rRegN src, immN0 zero) %{ - match(Set cr (CmpN src zero)); - - format %{ "testl $src, $src\t# compressed ptr" %} - ins_encode %{ __ testl($src$$Register, $src$$Register); %} - ins_pipe(ialu_cr_reg_imm); -%} - -instruct testN_mem(rFlagsReg cr, memory mem, immN0 zero) -%{ - predicate(CompressedOops::base() != nullptr && - n->in(1)->as_Load()->barrier_data() == 0); - match(Set cr (CmpN (LoadN mem) zero)); - - ins_cost(500); // XXX - format %{ "testl $mem, 0xffffffff\t# compressed ptr" %} - ins_encode %{ - __ cmpl($mem$$Address, (int)0xFFFFFFFF); - %} - ins_pipe(ialu_cr_reg_mem); -%} - -instruct testN_mem_reg0(rFlagsReg cr, memory mem, immN0 zero) -%{ - predicate(CompressedOops::base() == nullptr && - n->in(1)->as_Load()->barrier_data() == 0); - match(Set cr (CmpN (LoadN mem) zero)); - - format %{ "cmpl R12, $mem\t# compressed ptr (R12_heapbase==0)" %} - ins_encode %{ - __ cmpl(r12, $mem$$Address); - %} - ins_pipe(ialu_cr_reg_mem); -%} - -// Yanked all unsigned pointer compare operations. -// Pointer compares are done with CmpP which is already unsigned. - -instruct compL_rReg(rFlagsReg cr, rRegL op1, rRegL op2) -%{ - match(Set cr (CmpL op1 op2)); - - format %{ "cmpq $op1, $op2" %} - ins_encode %{ - __ cmpq($op1$$Register, $op2$$Register); - %} - ins_pipe(ialu_cr_reg_reg); -%} - -instruct compL_rReg_imm(rFlagsReg cr, rRegL op1, immL32 op2) -%{ - match(Set cr (CmpL op1 op2)); - - format %{ "cmpq $op1, $op2" %} - ins_encode %{ - __ cmpq($op1$$Register, $op2$$constant); - %} - ins_pipe(ialu_cr_reg_imm); -%} - -instruct compL_rReg_mem(rFlagsReg cr, rRegL op1, memory op2) -%{ - match(Set cr (CmpL op1 (LoadL op2))); - - format %{ "cmpq $op1, $op2" %} - ins_encode %{ - __ cmpq($op1$$Register, $op2$$Address); - %} - ins_pipe(ialu_cr_reg_mem); -%} - -instruct testL_reg(rFlagsReg cr, rRegL src, immL0 zero) -%{ - match(Set cr (CmpL src zero)); - - format %{ "testq $src, $src" %} - ins_encode %{ - __ testq($src$$Register, $src$$Register); - %} - ins_pipe(ialu_cr_reg_imm); -%} - -instruct testL_reg_imm(rFlagsReg cr, rRegL src, immL32 con, immL0 zero) -%{ - match(Set cr (CmpL (AndL src con) zero)); - - format %{ "testq $src, $con\t# long" %} - ins_encode %{ - __ testq($src$$Register, $con$$constant); - %} - ins_pipe(ialu_cr_reg_imm); -%} - -instruct testL_reg_reg(rFlagsReg cr, rRegL src1, rRegL src2, immL0 zero) -%{ - match(Set cr (CmpL (AndL src1 src2) zero)); - - format %{ "testq $src1, $src2\t# long" %} - ins_encode %{ - __ testq($src1$$Register, $src2$$Register); - %} - ins_pipe(ialu_cr_reg_imm); -%} - -instruct testL_reg_mem(rFlagsReg cr, rRegL src, memory mem, immL0 zero) -%{ - match(Set cr (CmpL (AndL src (LoadL mem)) zero)); - - format %{ "testq $src, $mem" %} - ins_encode %{ - __ testq($src$$Register, $mem$$Address); - %} - ins_pipe(ialu_cr_reg_mem); -%} - -instruct testL_reg_mem2(rFlagsReg cr, rRegP src, memory mem, immL0 zero) -%{ - match(Set cr (CmpL (AndL (CastP2X src) (LoadL mem)) zero)); - - format %{ "testq $src, $mem" %} - ins_encode %{ - __ testq($src$$Register, $mem$$Address); - %} - ins_pipe(ialu_cr_reg_mem); -%} - -// Manifest a CmpU result in an integer register. Very painful. -// This is the test to avoid. -instruct cmpU3_reg_reg(rRegI dst, rRegI src1, rRegI src2, rFlagsReg flags) -%{ - match(Set dst (CmpU3 src1 src2)); - effect(KILL flags); - - ins_cost(275); // XXX - format %{ "cmpl $src1, $src2\t# CmpL3\n\t" - "movl $dst, -1\n\t" - "jb,u done\n\t" - "setcc $dst \t# emits setne + movzbl or setzune for APX" - "done:" %} - ins_encode %{ - Label done; - __ cmpl($src1$$Register, $src2$$Register); - __ movl($dst$$Register, -1); - __ jccb(Assembler::below, done); - __ setcc(Assembler::notZero, $dst$$Register); - __ bind(done); - %} - ins_pipe(pipe_slow); -%} - -// Manifest a CmpL result in an integer register. Very painful. -// This is the test to avoid. -instruct cmpL3_reg_reg(rRegI dst, rRegL src1, rRegL src2, rFlagsReg flags) -%{ - match(Set dst (CmpL3 src1 src2)); - effect(KILL flags); - - ins_cost(275); // XXX - format %{ "cmpq $src1, $src2\t# CmpL3\n\t" - "movl $dst, -1\n\t" - "jl,s done\n\t" - "setcc $dst \t# emits setne + movzbl or setzune for APX" - "done:" %} - ins_encode %{ - Label done; - __ cmpq($src1$$Register, $src2$$Register); - __ movl($dst$$Register, -1); - __ jccb(Assembler::less, done); - __ setcc(Assembler::notZero, $dst$$Register); - __ bind(done); - %} - ins_pipe(pipe_slow); -%} - -// Manifest a CmpUL result in an integer register. Very painful. -// This is the test to avoid. -instruct cmpUL3_reg_reg(rRegI dst, rRegL src1, rRegL src2, rFlagsReg flags) -%{ - match(Set dst (CmpUL3 src1 src2)); - effect(KILL flags); - - ins_cost(275); // XXX - format %{ "cmpq $src1, $src2\t# CmpL3\n\t" - "movl $dst, -1\n\t" - "jb,u done\n\t" - "setcc $dst \t# emits setne + movzbl or setzune for APX" - "done:" %} - ins_encode %{ - Label done; - __ cmpq($src1$$Register, $src2$$Register); - __ movl($dst$$Register, -1); - __ jccb(Assembler::below, done); - __ setcc(Assembler::notZero, $dst$$Register); - __ bind(done); - %} - ins_pipe(pipe_slow); -%} - -// Unsigned long compare Instructions; really, same as signed long except they -// produce an rFlagsRegU instead of rFlagsReg. -instruct compUL_rReg(rFlagsRegU cr, rRegL op1, rRegL op2) -%{ - match(Set cr (CmpUL op1 op2)); - - format %{ "cmpq $op1, $op2\t# unsigned" %} - ins_encode %{ - __ cmpq($op1$$Register, $op2$$Register); - %} - ins_pipe(ialu_cr_reg_reg); -%} - -instruct compUL_rReg_imm(rFlagsRegU cr, rRegL op1, immL32 op2) -%{ - match(Set cr (CmpUL op1 op2)); - - format %{ "cmpq $op1, $op2\t# unsigned" %} - ins_encode %{ - __ cmpq($op1$$Register, $op2$$constant); - %} - ins_pipe(ialu_cr_reg_imm); -%} - -instruct compUL_rReg_mem(rFlagsRegU cr, rRegL op1, memory op2) -%{ - match(Set cr (CmpUL op1 (LoadL op2))); - - format %{ "cmpq $op1, $op2\t# unsigned" %} - ins_encode %{ - __ cmpq($op1$$Register, $op2$$Address); - %} - ins_pipe(ialu_cr_reg_mem); -%} - -instruct testUL_reg(rFlagsRegU cr, rRegL src, immL0 zero) -%{ - match(Set cr (CmpUL src zero)); - - format %{ "testq $src, $src\t# unsigned" %} - ins_encode %{ - __ testq($src$$Register, $src$$Register); - %} - ins_pipe(ialu_cr_reg_imm); -%} - -instruct compB_mem_imm(rFlagsReg cr, memory mem, immI8 imm) -%{ - match(Set cr (CmpI (LoadB mem) imm)); - - ins_cost(125); - format %{ "cmpb $mem, $imm" %} - ins_encode %{ __ cmpb($mem$$Address, $imm$$constant); %} - ins_pipe(ialu_cr_reg_mem); -%} - -instruct testUB_mem_imm(rFlagsReg cr, memory mem, immU7 imm, immI_0 zero) -%{ - match(Set cr (CmpI (AndI (LoadUB mem) imm) zero)); - - ins_cost(125); - format %{ "testb $mem, $imm\t# ubyte" %} - ins_encode %{ __ testb($mem$$Address, $imm$$constant); %} - ins_pipe(ialu_cr_reg_mem); -%} - -instruct testB_mem_imm(rFlagsReg cr, memory mem, immI8 imm, immI_0 zero) -%{ - match(Set cr (CmpI (AndI (LoadB mem) imm) zero)); - - ins_cost(125); - format %{ "testb $mem, $imm\t# byte" %} - ins_encode %{ __ testb($mem$$Address, $imm$$constant); %} - ins_pipe(ialu_cr_reg_mem); -%} - -//----------Max and Min-------------------------------------------------------- -// Min Instructions - -instruct cmovI_reg_g(rRegI dst, rRegI src, rFlagsReg cr) -%{ - predicate(!UseAPX); - effect(USE_DEF dst, USE src, USE cr); - - format %{ "cmovlgt $dst, $src\t# min" %} - ins_encode %{ - __ cmovl(Assembler::greater, $dst$$Register, $src$$Register); - %} - ins_pipe(pipe_cmov_reg); -%} - -instruct cmovI_reg_g_ndd(rRegI dst, rRegI src1, rRegI src2, rFlagsReg cr) -%{ - predicate(UseAPX); - effect(DEF dst, USE src1, USE src2, USE cr); - - format %{ "ecmovlgt $dst, $src1, $src2\t# min ndd" %} - ins_encode %{ - __ ecmovl(Assembler::greater, $dst$$Register, $src1$$Register, $src2$$Register); - %} - ins_pipe(pipe_cmov_reg); -%} - -instruct minI_rReg(rRegI dst, rRegI src) -%{ - predicate(!UseAPX); - match(Set dst (MinI dst src)); - - ins_cost(200); - expand %{ - rFlagsReg cr; - compI_rReg(cr, dst, src); - cmovI_reg_g(dst, src, cr); - %} -%} - -instruct minI_rReg_ndd(rRegI dst, rRegI src1, rRegI src2) -%{ - predicate(UseAPX); - match(Set dst (MinI src1 src2)); - effect(DEF dst, USE src1, USE src2); - - ins_cost(200); - expand %{ - rFlagsReg cr; - compI_rReg(cr, src1, src2); - cmovI_reg_g_ndd(dst, src1, src2, cr); - %} -%} - -instruct cmovI_reg_l(rRegI dst, rRegI src, rFlagsReg cr) -%{ - predicate(!UseAPX); - effect(USE_DEF dst, USE src, USE cr); - - format %{ "cmovllt $dst, $src\t# max" %} - ins_encode %{ - __ cmovl(Assembler::less, $dst$$Register, $src$$Register); - %} - ins_pipe(pipe_cmov_reg); -%} - -instruct cmovI_reg_l_ndd(rRegI dst, rRegI src1, rRegI src2, rFlagsReg cr) -%{ - predicate(UseAPX); - effect(DEF dst, USE src1, USE src2, USE cr); - - format %{ "ecmovllt $dst, $src1, $src2\t# max ndd" %} - ins_encode %{ - __ ecmovl(Assembler::less, $dst$$Register, $src1$$Register, $src2$$Register); - %} - ins_pipe(pipe_cmov_reg); -%} - -instruct maxI_rReg(rRegI dst, rRegI src) -%{ - predicate(!UseAPX); - match(Set dst (MaxI dst src)); - - ins_cost(200); - expand %{ - rFlagsReg cr; - compI_rReg(cr, dst, src); - cmovI_reg_l(dst, src, cr); - %} -%} - -instruct maxI_rReg_ndd(rRegI dst, rRegI src1, rRegI src2) -%{ - predicate(UseAPX); - match(Set dst (MaxI src1 src2)); - effect(DEF dst, USE src1, USE src2); - - ins_cost(200); - expand %{ - rFlagsReg cr; - compI_rReg(cr, src1, src2); - cmovI_reg_l_ndd(dst, src1, src2, cr); - %} -%} - -// ============================================================================ -// Branch Instructions - -// Jump Direct - Label defines a relative address from JMP+1 -instruct jmpDir(label labl) -%{ - match(Goto); - effect(USE labl); - - ins_cost(300); - format %{ "jmp $labl" %} - size(5); - ins_encode %{ - Label* L = $labl$$label; - __ jmp(*L, false); // Always long jump - %} - ins_pipe(pipe_jmp); -%} - -// Jump Direct Conditional - Label defines a relative address from Jcc+1 -instruct jmpCon(cmpOp cop, rFlagsReg cr, label labl) -%{ - match(If cop cr); - effect(USE labl); - - ins_cost(300); - format %{ "j$cop $labl" %} - size(6); - ins_encode %{ - Label* L = $labl$$label; - __ jcc((Assembler::Condition)($cop$$cmpcode), *L, false); // Always long jump - %} - ins_pipe(pipe_jcc); -%} - -// Jump Direct Conditional - Label defines a relative address from Jcc+1 -instruct jmpLoopEnd(cmpOp cop, rFlagsReg cr, label labl) -%{ - match(CountedLoopEnd cop cr); - effect(USE labl); - - ins_cost(300); - format %{ "j$cop $labl\t# loop end" %} - size(6); - ins_encode %{ - Label* L = $labl$$label; - __ jcc((Assembler::Condition)($cop$$cmpcode), *L, false); // Always long jump - %} - ins_pipe(pipe_jcc); -%} - -// Jump Direct Conditional - using unsigned comparison -instruct jmpConU(cmpOpU cop, rFlagsRegU cmp, label labl) %{ - match(If cop cmp); - effect(USE labl); - - ins_cost(300); - format %{ "j$cop,u $labl" %} - size(6); - ins_encode %{ - Label* L = $labl$$label; - __ jcc((Assembler::Condition)($cop$$cmpcode), *L, false); // Always long jump - %} - ins_pipe(pipe_jcc); -%} - -instruct jmpConUCF(cmpOpUCF cop, rFlagsRegUCF cmp, label labl) %{ - match(If cop cmp); - effect(USE labl); - - ins_cost(200); - format %{ "j$cop,u $labl" %} - size(6); - ins_encode %{ - Label* L = $labl$$label; - __ jcc((Assembler::Condition)($cop$$cmpcode), *L, false); // Always long jump - %} - ins_pipe(pipe_jcc); -%} - -instruct jmpConUCF2(cmpOpUCF2 cop, rFlagsRegUCF cmp, label labl) %{ - match(If cop cmp); - effect(USE labl); - - ins_cost(200); - format %{ $$template - if ($cop$$cmpcode == Assembler::notEqual) { - $$emit$$"jp,u $labl\n\t" - $$emit$$"j$cop,u $labl" - } else { - $$emit$$"jp,u done\n\t" - $$emit$$"j$cop,u $labl\n\t" - $$emit$$"done:" - } - %} - ins_encode %{ - Label* l = $labl$$label; - if ($cop$$cmpcode == Assembler::notEqual) { - __ jcc(Assembler::parity, *l, false); - __ jcc(Assembler::notEqual, *l, false); - } else if ($cop$$cmpcode == Assembler::equal) { - Label done; - __ jccb(Assembler::parity, done); - __ jcc(Assembler::equal, *l, false); - __ bind(done); - } else { - ShouldNotReachHere(); - } - %} - ins_pipe(pipe_jcc); -%} - -// ============================================================================ -// 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 NZ for a miss or zero for a hit. The -// encoding ALSO sets flags. - -instruct partialSubtypeCheck(rdi_RegP result, - rsi_RegP sub, rax_RegP super, rcx_RegI rcx, - rFlagsReg cr) -%{ - match(Set result (PartialSubtypeCheck sub super)); - predicate(!UseSecondarySupersTable); - effect(KILL rcx, KILL cr); - - ins_cost(1100); // slightly larger than the next version - format %{ "movq rdi, [$sub + in_bytes(Klass::secondary_supers_offset())]\n\t" - "movl rcx, [rdi + Array::length_offset_in_bytes()]\t# length to scan\n\t" - "addq rdi, Array::base_offset_in_bytes()\t# Skip to start of data; set NZ in case count is zero\n\t" - "repne scasq\t# Scan *rdi++ for a match with rax while rcx--\n\t" - "jne,s miss\t\t# Missed: rdi not-zero\n\t" - "movq [$sub + in_bytes(Klass::secondary_super_cache_offset())], $super\t# Hit: update cache\n\t" - "xorq $result, $result\t\t Hit: rdi zero\n\t" - "miss:\t" %} - - ins_encode %{ - Label miss; - // NB: Callers may assume that, when $result is a valid register, - // check_klass_subtype_slow_path_linear sets it to a nonzero - // value. - __ check_klass_subtype_slow_path_linear($sub$$Register, $super$$Register, - $rcx$$Register, $result$$Register, - nullptr, &miss, - /*set_cond_codes:*/ true); - __ xorptr($result$$Register, $result$$Register); - __ bind(miss); - %} - - ins_pipe(pipe_slow); -%} - -// ============================================================================ -// Two versions of hashtable-based partialSubtypeCheck, both used when -// we need to search for a super class in the secondary supers array. -// The first is used when we don't know _a priori_ the class being -// searched for. The second, far more common, is used when we do know: -// this is used for instanceof, checkcast, and any case where C2 can -// determine it by constant propagation. - -instruct partialSubtypeCheckVarSuper(rsi_RegP sub, rax_RegP super, rdi_RegP result, - rdx_RegL temp1, rcx_RegL temp2, rbx_RegP temp3, r11_RegL temp4, - rFlagsReg cr) -%{ - match(Set result (PartialSubtypeCheck sub super)); - predicate(UseSecondarySupersTable); - effect(KILL cr, TEMP temp1, TEMP temp2, TEMP temp3, TEMP temp4); - - ins_cost(1000); - format %{ "partialSubtypeCheck $result, $sub, $super" %} - - ins_encode %{ - __ lookup_secondary_supers_table_var($sub$$Register, $super$$Register, $temp1$$Register, $temp2$$Register, - $temp3$$Register, $temp4$$Register, $result$$Register); - %} - - ins_pipe(pipe_slow); -%} - -instruct partialSubtypeCheckConstSuper(rsi_RegP sub, rax_RegP super_reg, immP super_con, rdi_RegP result, - rdx_RegL temp1, rcx_RegL temp2, rbx_RegP temp3, r11_RegL temp4, - rFlagsReg cr) -%{ - match(Set result (PartialSubtypeCheck sub (Binary super_reg super_con))); - predicate(UseSecondarySupersTable); - effect(KILL cr, TEMP temp1, TEMP temp2, TEMP temp3, TEMP temp4); - - ins_cost(700); // smaller than the next version - format %{ "partialSubtypeCheck $result, $sub, $super_reg, $super_con" %} - - ins_encode %{ - u1 super_klass_slot = ((Klass*)$super_con$$constant)->hash_slot(); - if (InlineSecondarySupersTest) { - __ lookup_secondary_supers_table_const($sub$$Register, $super_reg$$Register, $temp1$$Register, $temp2$$Register, - $temp3$$Register, $temp4$$Register, $result$$Register, - super_klass_slot); - } else { - __ call(RuntimeAddress(StubRoutines::lookup_secondary_supers_table_stub(super_klass_slot))); - } - %} - - ins_pipe(pipe_slow); -%} - -// ============================================================================ -// Branch Instructions -- short offset versions -// -// These instructions are used to replace jumps of a long offset (the default -// match) with jumps of a shorter offset. These instructions are all tagged -// with the ins_short_branch attribute, which causes the ADLC to suppress the -// match rules in general matching. Instead, the ADLC generates a conversion -// method in the MachNode which can be used to do in-place replacement of the -// long variant with the shorter variant. The compiler will determine if a -// branch can be taken by the is_short_branch_offset() predicate in the machine -// specific code section of the file. - -// Jump Direct - Label defines a relative address from JMP+1 -instruct jmpDir_short(label labl) %{ - match(Goto); - effect(USE labl); - - ins_cost(300); - format %{ "jmp,s $labl" %} - size(2); - ins_encode %{ - Label* L = $labl$$label; - __ jmpb(*L); - %} - ins_pipe(pipe_jmp); - ins_short_branch(1); -%} - -// Jump Direct Conditional - Label defines a relative address from Jcc+1 -instruct jmpCon_short(cmpOp cop, rFlagsReg cr, label labl) %{ - match(If cop cr); - effect(USE labl); - - ins_cost(300); - format %{ "j$cop,s $labl" %} - size(2); - ins_encode %{ - Label* L = $labl$$label; - __ jccb((Assembler::Condition)($cop$$cmpcode), *L); - %} - ins_pipe(pipe_jcc); - ins_short_branch(1); -%} - -// Jump Direct Conditional - Label defines a relative address from Jcc+1 -instruct jmpLoopEnd_short(cmpOp cop, rFlagsReg cr, label labl) %{ - match(CountedLoopEnd cop cr); - effect(USE labl); - - ins_cost(300); - format %{ "j$cop,s $labl\t# loop end" %} - size(2); - ins_encode %{ - Label* L = $labl$$label; - __ jccb((Assembler::Condition)($cop$$cmpcode), *L); - %} - ins_pipe(pipe_jcc); - ins_short_branch(1); -%} - -// Jump Direct Conditional - using unsigned comparison -instruct jmpConU_short(cmpOpU cop, rFlagsRegU cmp, label labl) %{ - match(If cop cmp); - effect(USE labl); - - ins_cost(300); - format %{ "j$cop,us $labl" %} - size(2); - ins_encode %{ - Label* L = $labl$$label; - __ jccb((Assembler::Condition)($cop$$cmpcode), *L); - %} - ins_pipe(pipe_jcc); - ins_short_branch(1); -%} - -instruct jmpConUCF_short(cmpOpUCF cop, rFlagsRegUCF cmp, label labl) %{ - match(If cop cmp); - effect(USE labl); - - ins_cost(300); - format %{ "j$cop,us $labl" %} - size(2); - ins_encode %{ - Label* L = $labl$$label; - __ jccb((Assembler::Condition)($cop$$cmpcode), *L); - %} - ins_pipe(pipe_jcc); - ins_short_branch(1); -%} - -instruct jmpConUCF2_short(cmpOpUCF2 cop, rFlagsRegUCF cmp, label labl) %{ - match(If cop cmp); - effect(USE labl); - - ins_cost(300); - format %{ $$template - if ($cop$$cmpcode == Assembler::notEqual) { - $$emit$$"jp,u,s $labl\n\t" - $$emit$$"j$cop,u,s $labl" - } else { - $$emit$$"jp,u,s done\n\t" - $$emit$$"j$cop,u,s $labl\n\t" - $$emit$$"done:" - } - %} - size(4); - ins_encode %{ - Label* l = $labl$$label; - if ($cop$$cmpcode == Assembler::notEqual) { - __ jccb(Assembler::parity, *l); - __ jccb(Assembler::notEqual, *l); - } else if ($cop$$cmpcode == Assembler::equal) { - Label done; - __ jccb(Assembler::parity, done); - __ jccb(Assembler::equal, *l); - __ bind(done); - } else { - ShouldNotReachHere(); - } - %} - ins_pipe(pipe_jcc); - ins_short_branch(1); -%} - -// ============================================================================ -// inlined locking and unlocking - -instruct cmpFastLockLightweight(rFlagsReg cr, rRegP object, rbx_RegP box, rax_RegI rax_reg, rRegP tmp) %{ - match(Set cr (FastLock object box)); - effect(TEMP rax_reg, TEMP tmp, USE_KILL box); - ins_cost(300); - format %{ "fastlock $object,$box\t! kills $box,$rax_reg,$tmp" %} - ins_encode %{ - __ fast_lock_lightweight($object$$Register, $box$$Register, $rax_reg$$Register, $tmp$$Register, r15_thread); - %} - ins_pipe(pipe_slow); -%} - -instruct cmpFastUnlockLightweight(rFlagsReg cr, rRegP object, rax_RegP rax_reg, rRegP tmp) %{ - match(Set cr (FastUnlock object rax_reg)); - effect(TEMP tmp, USE_KILL rax_reg); - ins_cost(300); - format %{ "fastunlock $object,$rax_reg\t! kills $rax_reg,$tmp" %} - ins_encode %{ - __ fast_unlock_lightweight($object$$Register, $rax_reg$$Register, $tmp$$Register, r15_thread); - %} - ins_pipe(pipe_slow); -%} - - -// ============================================================================ -// Safepoint Instructions -instruct safePoint_poll_tls(rFlagsReg cr, rRegP poll) -%{ - match(SafePoint poll); - effect(KILL cr, USE poll); - - format %{ "testl rax, [$poll]\t" - "# Safepoint: poll for GC" %} - ins_cost(125); - ins_encode %{ - __ relocate(relocInfo::poll_type); - address pre_pc = __ pc(); - __ testl(rax, Address($poll$$Register, 0)); - assert(nativeInstruction_at(pre_pc)->is_safepoint_poll(), "must emit test %%eax [reg]"); - %} - ins_pipe(ialu_reg_mem); -%} - -instruct mask_all_evexL(kReg dst, rRegL src) %{ - match(Set dst (MaskAll src)); - format %{ "mask_all_evexL $dst, $src \t! mask all operation" %} - ins_encode %{ - int mask_len = Matcher::vector_length(this); - __ vector_maskall_operation($dst$$KRegister, $src$$Register, mask_len); - %} - ins_pipe( pipe_slow ); -%} - -instruct mask_all_evexI_GT32(kReg dst, rRegI src, rRegL tmp) %{ - predicate(Matcher::vector_length(n) > 32); - match(Set dst (MaskAll src)); - effect(TEMP tmp); - format %{ "mask_all_evexI_GT32 $dst, $src \t! using $tmp as TEMP" %} - ins_encode %{ - int mask_len = Matcher::vector_length(this); - __ movslq($tmp$$Register, $src$$Register); - __ vector_maskall_operation($dst$$KRegister, $tmp$$Register, mask_len); - %} - ins_pipe( pipe_slow ); -%} - -// ============================================================================ -// Procedure Call/Return Instructions -// Call Java Static Instruction -// Note: If this code changes, the corresponding ret_addr_offset() and -// compute_padding() functions will have to be adjusted. -instruct CallStaticJavaDirect(method meth) %{ - match(CallStaticJava); - effect(USE meth); - - ins_cost(300); - format %{ "call,static " %} - opcode(0xE8); /* E8 cd */ - ins_encode(clear_avx, Java_Static_Call(meth), call_epilog); - ins_pipe(pipe_slow); - ins_alignment(4); -%} - -// Call Java Dynamic Instruction -// Note: If this code changes, the corresponding ret_addr_offset() and -// compute_padding() functions will have to be adjusted. -instruct CallDynamicJavaDirect(method meth) -%{ - match(CallDynamicJava); - effect(USE meth); - - ins_cost(300); - format %{ "movq rax, #Universe::non_oop_word()\n\t" - "call,dynamic " %} - ins_encode(clear_avx, Java_Dynamic_Call(meth), call_epilog); - ins_pipe(pipe_slow); - ins_alignment(4); -%} - -// Call Runtime Instruction -instruct CallRuntimeDirect(method meth) -%{ - match(CallRuntime); - effect(USE meth); - - ins_cost(300); - format %{ "call,runtime " %} - ins_encode(clear_avx, Java_To_Runtime(meth)); - ins_pipe(pipe_slow); -%} - -// Call runtime without safepoint -instruct CallLeafDirect(method meth) -%{ - match(CallLeaf); - effect(USE meth); - - ins_cost(300); - format %{ "call_leaf,runtime " %} - ins_encode(clear_avx, Java_To_Runtime(meth)); - ins_pipe(pipe_slow); -%} - -// Call runtime without safepoint and with vector arguments -instruct CallLeafDirectVector(method meth) -%{ - match(CallLeafVector); - effect(USE meth); - - ins_cost(300); - format %{ "call_leaf,vector " %} - ins_encode(Java_To_Runtime(meth)); - ins_pipe(pipe_slow); -%} - -// Call runtime without safepoint -instruct CallLeafNoFPDirect(method meth) -%{ - match(CallLeafNoFP); - effect(USE meth); - - ins_cost(300); - format %{ "call_leaf_nofp,runtime " %} - ins_encode(clear_avx, Java_To_Runtime(meth)); - ins_pipe(pipe_slow); -%} - -// Return Instruction -// Remove the return address & jump to it. -// Notice: We always emit a nop after a ret to make sure there is room -// for safepoint patching -instruct Ret() -%{ - match(Return); - - format %{ "ret" %} - ins_encode %{ - __ ret(0); - %} - ins_pipe(pipe_jmp); -%} - -// 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. -// Don't use rbp for 'jump_target' because a MachEpilogNode has already been -// emitted just above the TailCall which has reset rbp to the caller state. -instruct TailCalljmpInd(no_rbp_RegP jump_target, rbx_RegP method_ptr) -%{ - match(TailCall jump_target method_ptr); - - ins_cost(300); - format %{ "jmp $jump_target\t# rbx holds method" %} - ins_encode %{ - __ jmp($jump_target$$Register); - %} - ins_pipe(pipe_jmp); -%} - -// Tail Jump; remove the return address; jump to target. -// TailCall above leaves the return address around. -instruct tailjmpInd(no_rbp_RegP jump_target, rax_RegP ex_oop) -%{ - match(TailJump jump_target ex_oop); - - ins_cost(300); - format %{ "popq rdx\t# pop return address\n\t" - "jmp $jump_target" %} - ins_encode %{ - __ popq(as_Register(RDX_enc)); - __ jmp($jump_target$$Register); - %} - ins_pipe(pipe_jmp); -%} - -// Forward exception. -instruct ForwardExceptionjmp() -%{ - match(ForwardException); - - format %{ "jmp forward_exception_stub" %} - ins_encode %{ - __ jump(RuntimeAddress(StubRoutines::forward_exception_entry()), noreg); - %} - ins_pipe(pipe_jmp); -%} - -// 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(rax_RegP ex_oop) -%{ - match(Set ex_oop (CreateEx)); - - size(0); - // use the following format syntax - format %{ "# exception oop is in rax; 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); - - // use the following format syntax - format %{ "jmp rethrow_stub" %} - ins_encode %{ - __ jump(RuntimeAddress(OptoRuntime::rethrow_stub()), noreg); - %} - ins_pipe(pipe_jmp); -%} - -// ============================================================================ -// This name is KNOWN by the ADLC and cannot be changed. -// The ADLC forces a 'TypeRawPtr::BOTTOM' output type -// for this guy. -instruct tlsLoadP(r15_RegP dst) %{ - match(Set dst (ThreadLocal)); - effect(DEF dst); - - size(0); - format %{ "# TLS is in R15" %} - ins_encode( /*empty encoding*/ ); - ins_pipe(ialu_reg_reg); -%} - - -//----------PEEPHOLE RULES----------------------------------------------------- -// These must follow all instruction definitions as they use the names -// defined in the instructions definitions. -// -// peeppredicate ( rule_predicate ); -// // the predicate unless which the peephole rule will be ignored -// -// peepmatch ( root_instr_name [preceding_instruction]* ); -// -// peepprocedure ( procedure_name ); -// // provide a procedure name to perform the optimization, the procedure should -// // reside in the architecture dependent peephole file, the method has the -// // signature of MachNode* (Block*, int, PhaseRegAlloc*, (MachNode*)(*)(), int...) -// // with the arguments being the basic block, the current node index inside the -// // block, the register allocator, the functions upon invoked return a new node -// // defined in peepreplace, and the rules of the nodes appearing in the -// // corresponding peepmatch, the function return true if successful, else -// // return false -// -// peepconstraint %{ -// (instruction_number.operand_name relational_op instruction_number.operand_name -// [, ...] ); -// // instruction numbers are zero-based using left to right order in peepmatch -// -// peepreplace ( instr_name ( [instruction_number.operand_name]* ) ); -// // provide an instruction_number.operand_name for each operand that appears -// // in the replacement instruction's match rule -// -// ---------VM FLAGS--------------------------------------------------------- -// -// All peephole optimizations can be turned off using -XX:-OptoPeephole -// -// Each peephole rule is given an identifying number starting with zero and -// increasing by one in the order seen by the parser. An individual peephole -// can be enabled, and all others disabled, by using -XX:OptoPeepholeAt=# -// on the command-line. -// -// ---------CURRENT LIMITATIONS---------------------------------------------- -// -// Only transformations inside a basic block (do we need more for peephole) -// -// ---------EXAMPLE---------------------------------------------------------- -// -// // pertinent parts of existing instructions in architecture description -// instruct movI(rRegI dst, rRegI src) -// %{ -// match(Set dst (CopyI src)); -// %} -// -// instruct incI_rReg(rRegI dst, immI_1 src, rFlagsReg cr) -// %{ -// match(Set dst (AddI dst src)); -// effect(KILL cr); -// %} -// -// instruct leaI_rReg_immI(rRegI dst, immI_1 src) -// %{ -// match(Set dst (AddI dst src)); -// %} -// -// 1. Simple replacement -// - Only match adjacent instructions in same basic block -// - Only equality constraints -// - Only constraints between operands, not (0.dest_reg == RAX_enc) -// - Only one replacement instruction -// -// // Change (inc mov) to lea -// peephole %{ -// // lea should only be emitted when beneficial -// peeppredicate( VM_Version::supports_fast_2op_lea() ); -// // increment preceded by register-register move -// peepmatch ( incI_rReg movI ); -// // require that the destination register of the increment -// // match the destination register of the move -// peepconstraint ( 0.dst == 1.dst ); -// // construct a replacement instruction that sets -// // the destination to ( move's source register + one ) -// peepreplace ( leaI_rReg_immI( 0.dst 1.src 0.src ) ); -// %} -// -// 2. Procedural replacement -// - More flexible finding relevent nodes -// - More flexible constraints -// - More flexible transformations -// - May utilise architecture-dependent API more effectively -// - Currently only one replacement instruction due to adlc parsing capabilities -// -// // Change (inc mov) to lea -// peephole %{ -// // lea should only be emitted when beneficial -// peeppredicate( VM_Version::supports_fast_2op_lea() ); -// // the rule numbers of these nodes inside are passed into the function below -// peepmatch ( incI_rReg movI ); -// // the method that takes the responsibility of transformation -// peepprocedure ( inc_mov_to_lea ); -// // the replacement is a leaI_rReg_immI, a lambda upon invoked creating this -// // node is passed into the function above -// peepreplace ( leaI_rReg_immI() ); -// %} - -// These instructions is not matched by the matcher but used by the peephole -instruct leaI_rReg_rReg_peep(rRegI dst, rRegI src1, rRegI src2) -%{ - predicate(false); - match(Set dst (AddI src1 src2)); - format %{ "leal $dst, [$src1 + $src2]" %} - ins_encode %{ - Register dst = $dst$$Register; - Register src1 = $src1$$Register; - Register src2 = $src2$$Register; - if (src1 != rbp && src1 != r13) { - __ leal(dst, Address(src1, src2, Address::times_1)); - } else { - assert(src2 != rbp && src2 != r13, ""); - __ leal(dst, Address(src2, src1, Address::times_1)); - } - %} - ins_pipe(ialu_reg_reg); -%} - -instruct leaI_rReg_immI_peep(rRegI dst, rRegI src1, immI src2) -%{ - predicate(false); - match(Set dst (AddI src1 src2)); - format %{ "leal $dst, [$src1 + $src2]" %} - ins_encode %{ - __ leal($dst$$Register, Address($src1$$Register, $src2$$constant)); - %} - ins_pipe(ialu_reg_reg); -%} - -instruct leaI_rReg_immI2_peep(rRegI dst, rRegI src, immI2 shift) -%{ - predicate(false); - match(Set dst (LShiftI src shift)); - format %{ "leal $dst, [$src << $shift]" %} - ins_encode %{ - Address::ScaleFactor scale = static_cast($shift$$constant); - Register src = $src$$Register; - if (scale == Address::times_2 && src != rbp && src != r13) { - __ leal($dst$$Register, Address(src, src, Address::times_1)); - } else { - __ leal($dst$$Register, Address(noreg, src, scale)); - } - %} - ins_pipe(ialu_reg_reg); -%} - -instruct leaL_rReg_rReg_peep(rRegL dst, rRegL src1, rRegL src2) -%{ - predicate(false); - match(Set dst (AddL src1 src2)); - format %{ "leaq $dst, [$src1 + $src2]" %} - ins_encode %{ - Register dst = $dst$$Register; - Register src1 = $src1$$Register; - Register src2 = $src2$$Register; - if (src1 != rbp && src1 != r13) { - __ leaq(dst, Address(src1, src2, Address::times_1)); - } else { - assert(src2 != rbp && src2 != r13, ""); - __ leaq(dst, Address(src2, src1, Address::times_1)); - } - %} - ins_pipe(ialu_reg_reg); -%} - -instruct leaL_rReg_immL32_peep(rRegL dst, rRegL src1, immL32 src2) -%{ - predicate(false); - match(Set dst (AddL src1 src2)); - format %{ "leaq $dst, [$src1 + $src2]" %} - ins_encode %{ - __ leaq($dst$$Register, Address($src1$$Register, $src2$$constant)); - %} - ins_pipe(ialu_reg_reg); -%} - -instruct leaL_rReg_immI2_peep(rRegL dst, rRegL src, immI2 shift) -%{ - predicate(false); - match(Set dst (LShiftL src shift)); - format %{ "leaq $dst, [$src << $shift]" %} - ins_encode %{ - Address::ScaleFactor scale = static_cast($shift$$constant); - Register src = $src$$Register; - if (scale == Address::times_2 && src != rbp && src != r13) { - __ leaq($dst$$Register, Address(src, src, Address::times_1)); - } else { - __ leaq($dst$$Register, Address(noreg, src, scale)); - } - %} - ins_pipe(ialu_reg_reg); -%} - -// These peephole rules replace mov + I pairs (where I is one of {add, inc, dec, -// sal}) with lea instructions. The {add, sal} rules are beneficial in -// processors with at least partial ALU support for lea -// (supports_fast_2op_lea()), whereas the {inc, dec} rules are only generally -// beneficial for processors with full ALU support -// (VM_Version::supports_fast_3op_lea()) and Intel Cascade Lake. - -peephole -%{ - peeppredicate(VM_Version::supports_fast_2op_lea()); - peepmatch (addI_rReg); - peepprocedure (lea_coalesce_reg); - peepreplace (leaI_rReg_rReg_peep()); -%} - -peephole -%{ - peeppredicate(VM_Version::supports_fast_2op_lea()); - peepmatch (addI_rReg_imm); - peepprocedure (lea_coalesce_imm); - peepreplace (leaI_rReg_immI_peep()); -%} - -peephole -%{ - peeppredicate(VM_Version::supports_fast_3op_lea() || - VM_Version::is_intel_cascade_lake()); - peepmatch (incI_rReg); - peepprocedure (lea_coalesce_imm); - peepreplace (leaI_rReg_immI_peep()); -%} - -peephole -%{ - peeppredicate(VM_Version::supports_fast_3op_lea() || - VM_Version::is_intel_cascade_lake()); - peepmatch (decI_rReg); - peepprocedure (lea_coalesce_imm); - peepreplace (leaI_rReg_immI_peep()); -%} - -peephole -%{ - peeppredicate(VM_Version::supports_fast_2op_lea()); - peepmatch (salI_rReg_immI2); - peepprocedure (lea_coalesce_imm); - peepreplace (leaI_rReg_immI2_peep()); -%} - -peephole -%{ - peeppredicate(VM_Version::supports_fast_2op_lea()); - peepmatch (addL_rReg); - peepprocedure (lea_coalesce_reg); - peepreplace (leaL_rReg_rReg_peep()); -%} - -peephole -%{ - peeppredicate(VM_Version::supports_fast_2op_lea()); - peepmatch (addL_rReg_imm); - peepprocedure (lea_coalesce_imm); - peepreplace (leaL_rReg_immL32_peep()); -%} - -peephole -%{ - peeppredicate(VM_Version::supports_fast_3op_lea() || - VM_Version::is_intel_cascade_lake()); - peepmatch (incL_rReg); - peepprocedure (lea_coalesce_imm); - peepreplace (leaL_rReg_immL32_peep()); -%} - -peephole -%{ - peeppredicate(VM_Version::supports_fast_3op_lea() || - VM_Version::is_intel_cascade_lake()); - peepmatch (decL_rReg); - peepprocedure (lea_coalesce_imm); - peepreplace (leaL_rReg_immL32_peep()); -%} - -peephole -%{ - peeppredicate(VM_Version::supports_fast_2op_lea()); - peepmatch (salL_rReg_immI2); - peepprocedure (lea_coalesce_imm); - peepreplace (leaL_rReg_immI2_peep()); -%} - -peephole -%{ - peepmatch (leaPCompressedOopOffset); - peepprocedure (lea_remove_redundant); -%} - -peephole -%{ - peepmatch (leaP8Narrow); - peepprocedure (lea_remove_redundant); -%} - -peephole -%{ - peepmatch (leaP32Narrow); - peepprocedure (lea_remove_redundant); -%} - -// These peephole rules matches instructions which set flags and are followed by a testI/L_reg -// The test instruction is redudanent in case the downstream instuctions (like JCC or CMOV) only use flags that are already set by the previous instruction - -//int variant -peephole -%{ - peepmatch (testI_reg); - peepprocedure (test_may_remove); -%} - -//long variant -peephole -%{ - peepmatch (testL_reg); - peepprocedure (test_may_remove); -%} - - -//----------SMARTSPILL RULES--------------------------------------------------- -// These must follow all instruction definitions as they use the names -// defined in the instructions definitions. diff --git a/src/hotspot/os_cpu/bsd_x86/atomicAccess_bsd_x86.hpp b/src/hotspot/os_cpu/bsd_x86/atomicAccess_bsd_x86.hpp index 975580fbd71..1024c6b1418 100644 --- a/src/hotspot/os_cpu/bsd_x86/atomicAccess_bsd_x86.hpp +++ b/src/hotspot/os_cpu/bsd_x86/atomicAccess_bsd_x86.hpp @@ -93,7 +93,6 @@ inline T AtomicAccess::PlatformCmpxchg<4>::operator()(T volatile* dest, return exchange_value; } -#ifdef AMD64 template<> template inline D AtomicAccess::PlatformAdd<8>::fetch_then_add(D volatile* dest, I add_value, @@ -135,51 +134,6 @@ inline T AtomicAccess::PlatformCmpxchg<8>::operator()(T volatile* dest, return exchange_value; } -#else // !AMD64 - -extern "C" { - // defined in bsd_x86.s - int64_t _Atomic_cmpxchg_long(int64_t, volatile int64_t*, int64_t); - void _Atomic_move_long(const volatile int64_t* src, volatile int64_t* dst); -} - -template<> -template -inline T AtomicAccess::PlatformCmpxchg<8>::operator()(T volatile* dest, - T compare_value, - T exchange_value, - atomic_memory_order /* order */) const { - STATIC_ASSERT(8 == sizeof(T)); - return cmpxchg_using_helper(_Atomic_cmpxchg_long, dest, compare_value, exchange_value); -} - -// No direct support for 8-byte xchg; emulate using cmpxchg. -template<> -struct AtomicAccess::PlatformXchg<8> : AtomicAccess::XchgUsingCmpxchg<8> {}; - -// No direct support for 8-byte add; emulate using cmpxchg. -template<> -struct AtomicAccess::PlatformAdd<8> : AtomicAccess::AddUsingCmpxchg<8> {}; - -template<> -template -inline T AtomicAccess::PlatformLoad<8>::operator()(T const volatile* src) const { - STATIC_ASSERT(8 == sizeof(T)); - volatile int64_t dest; - _Atomic_move_long(reinterpret_cast(src), reinterpret_cast(&dest)); - return PrimitiveConversions::cast(dest); -} - -template<> -template -inline void AtomicAccess::PlatformStore<8>::operator()(T volatile* dest, - T store_value) const { - STATIC_ASSERT(8 == sizeof(T)); - _Atomic_move_long(reinterpret_cast(&store_value), reinterpret_cast(dest)); -} - -#endif // AMD64 - template<> struct AtomicAccess::PlatformOrderedStore<1, RELEASE_X_FENCE> { @@ -216,7 +170,6 @@ struct AtomicAccess::PlatformOrderedStore<4, RELEASE_X_FENCE> } }; -#ifdef AMD64 template<> struct AtomicAccess::PlatformOrderedStore<8, RELEASE_X_FENCE> { @@ -228,6 +181,5 @@ struct AtomicAccess::PlatformOrderedStore<8, RELEASE_X_FENCE> : "memory"); } }; -#endif // AMD64 #endif // OS_CPU_BSD_X86_ATOMICACCESS_BSD_X86_HPP diff --git a/src/hotspot/os_cpu/bsd_x86/globals_bsd_x86.hpp b/src/hotspot/os_cpu/bsd_x86/globals_bsd_x86.hpp index f67bb15c69e..1625f313b29 100644 --- a/src/hotspot/os_cpu/bsd_x86/globals_bsd_x86.hpp +++ b/src/hotspot/os_cpu/bsd_x86/globals_bsd_x86.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, 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 @@ -29,19 +29,9 @@ // Sets the default values for platform dependent flags used by the runtime system. // (see globals.hpp) // -#ifdef AMD64 define_pd_global(intx, CompilerThreadStackSize, 1024); define_pd_global(intx, ThreadStackSize, 1024); // 0 => use system default define_pd_global(intx, VMThreadStackSize, 1024); -#else -define_pd_global(intx, CompilerThreadStackSize, 512); -// ThreadStackSize 320 allows a couple of test cases to run while -// keeping the number of threads that can be created high. System -// default ThreadStackSize appears to be 512 which is too big. -define_pd_global(intx, ThreadStackSize, 320); -define_pd_global(intx, VMThreadStackSize, 512); -#endif // AMD64 - define_pd_global(size_t, JVMInvokeMethodSlack, 8192); diff --git a/src/hotspot/os_cpu/bsd_x86/orderAccess_bsd_x86.hpp b/src/hotspot/os_cpu/bsd_x86/orderAccess_bsd_x86.hpp index 90e2574abf2..f980c341c8f 100644 --- a/src/hotspot/os_cpu/bsd_x86/orderAccess_bsd_x86.hpp +++ b/src/hotspot/os_cpu/bsd_x86/orderAccess_bsd_x86.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, 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 @@ -51,11 +51,7 @@ inline void OrderAccess::release() { compiler_barrier(); } inline void OrderAccess::fence() { // always use locked addl since mfence is sometimes expensive -#ifdef AMD64 __asm__ volatile ("lock; addl $0,0(%%rsp)" : : : "cc", "memory"); -#else - __asm__ volatile ("lock; addl $0,0(%%esp)" : : : "cc", "memory"); -#endif compiler_barrier(); } diff --git a/src/hotspot/os_cpu/bsd_x86/os_bsd_x86.cpp b/src/hotspot/os_cpu/bsd_x86/os_bsd_x86.cpp index ecc2e5a7f00..420e7b4cd8d 100644 --- a/src/hotspot/os_cpu/bsd_x86/os_bsd_x86.cpp +++ b/src/hotspot/os_cpu/bsd_x86/os_bsd_x86.cpp @@ -86,56 +86,34 @@ # define OS_X_10_9_0_KERNEL_MAJOR_VERSION 13 #endif -#ifdef AMD64 #define SPELL_REG_SP "rsp" #define SPELL_REG_FP "rbp" #define REG_BCP context_r13 -#else -#define SPELL_REG_SP "esp" -#define SPELL_REG_FP "ebp" -#endif // AMD64 #ifdef __FreeBSD__ # define context_trapno uc_mcontext.mc_trapno -# ifdef AMD64 -# define context_pc uc_mcontext.mc_rip -# define context_sp uc_mcontext.mc_rsp -# define context_fp uc_mcontext.mc_rbp -# define context_rip uc_mcontext.mc_rip -# define context_rsp uc_mcontext.mc_rsp -# define context_rbp uc_mcontext.mc_rbp -# define context_rax uc_mcontext.mc_rax -# define context_rbx uc_mcontext.mc_rbx -# define context_rcx uc_mcontext.mc_rcx -# define context_rdx uc_mcontext.mc_rdx -# define context_rsi uc_mcontext.mc_rsi -# define context_rdi uc_mcontext.mc_rdi -# define context_r8 uc_mcontext.mc_r8 -# define context_r9 uc_mcontext.mc_r9 -# define context_r10 uc_mcontext.mc_r10 -# define context_r11 uc_mcontext.mc_r11 -# define context_r12 uc_mcontext.mc_r12 -# define context_r13 uc_mcontext.mc_r13 -# define context_r14 uc_mcontext.mc_r14 -# define context_r15 uc_mcontext.mc_r15 -# define context_flags uc_mcontext.mc_flags -# define context_err uc_mcontext.mc_err -# else -# define context_pc uc_mcontext.mc_eip -# define context_sp uc_mcontext.mc_esp -# define context_fp uc_mcontext.mc_ebp -# define context_eip uc_mcontext.mc_eip -# define context_esp uc_mcontext.mc_esp -# define context_eax uc_mcontext.mc_eax -# define context_ebx uc_mcontext.mc_ebx -# define context_ecx uc_mcontext.mc_ecx -# define context_edx uc_mcontext.mc_edx -# define context_ebp uc_mcontext.mc_ebp -# define context_esi uc_mcontext.mc_esi -# define context_edi uc_mcontext.mc_edi -# define context_eflags uc_mcontext.mc_eflags -# define context_trapno uc_mcontext.mc_trapno -# endif +# define context_pc uc_mcontext.mc_rip +# define context_sp uc_mcontext.mc_rsp +# define context_fp uc_mcontext.mc_rbp +# define context_rip uc_mcontext.mc_rip +# define context_rsp uc_mcontext.mc_rsp +# define context_rbp uc_mcontext.mc_rbp +# define context_rax uc_mcontext.mc_rax +# define context_rbx uc_mcontext.mc_rbx +# define context_rcx uc_mcontext.mc_rcx +# define context_rdx uc_mcontext.mc_rdx +# define context_rsi uc_mcontext.mc_rsi +# define context_rdi uc_mcontext.mc_rdi +# define context_r8 uc_mcontext.mc_r8 +# define context_r9 uc_mcontext.mc_r9 +# define context_r10 uc_mcontext.mc_r10 +# define context_r11 uc_mcontext.mc_r11 +# define context_r12 uc_mcontext.mc_r12 +# define context_r13 uc_mcontext.mc_r13 +# define context_r14 uc_mcontext.mc_r14 +# define context_r15 uc_mcontext.mc_r15 +# define context_flags uc_mcontext.mc_flags +# define context_err uc_mcontext.mc_err #endif #ifdef __APPLE__ @@ -146,133 +124,82 @@ #define DU3_PREFIX(s, m) s ## . ## m # endif -# ifdef AMD64 -# define context_pc context_rip -# define context_sp context_rsp -# define context_fp context_rbp -# define context_rip uc_mcontext->DU3_PREFIX(ss,rip) -# define context_rsp uc_mcontext->DU3_PREFIX(ss,rsp) -# define context_rax uc_mcontext->DU3_PREFIX(ss,rax) -# define context_rbx uc_mcontext->DU3_PREFIX(ss,rbx) -# define context_rcx uc_mcontext->DU3_PREFIX(ss,rcx) -# define context_rdx uc_mcontext->DU3_PREFIX(ss,rdx) -# define context_rbp uc_mcontext->DU3_PREFIX(ss,rbp) -# define context_rsi uc_mcontext->DU3_PREFIX(ss,rsi) -# define context_rdi uc_mcontext->DU3_PREFIX(ss,rdi) -# define context_r8 uc_mcontext->DU3_PREFIX(ss,r8) -# define context_r9 uc_mcontext->DU3_PREFIX(ss,r9) -# define context_r10 uc_mcontext->DU3_PREFIX(ss,r10) -# define context_r11 uc_mcontext->DU3_PREFIX(ss,r11) -# define context_r12 uc_mcontext->DU3_PREFIX(ss,r12) -# define context_r13 uc_mcontext->DU3_PREFIX(ss,r13) -# define context_r14 uc_mcontext->DU3_PREFIX(ss,r14) -# define context_r15 uc_mcontext->DU3_PREFIX(ss,r15) -# define context_flags uc_mcontext->DU3_PREFIX(ss,rflags) -# define context_trapno uc_mcontext->DU3_PREFIX(es,trapno) -# define context_err uc_mcontext->DU3_PREFIX(es,err) -# else -# define context_pc context_eip -# define context_sp context_esp -# define context_fp context_ebp -# define context_eip uc_mcontext->DU3_PREFIX(ss,eip) -# define context_esp uc_mcontext->DU3_PREFIX(ss,esp) -# define context_eax uc_mcontext->DU3_PREFIX(ss,eax) -# define context_ebx uc_mcontext->DU3_PREFIX(ss,ebx) -# define context_ecx uc_mcontext->DU3_PREFIX(ss,ecx) -# define context_edx uc_mcontext->DU3_PREFIX(ss,edx) -# define context_ebp uc_mcontext->DU3_PREFIX(ss,ebp) -# define context_esi uc_mcontext->DU3_PREFIX(ss,esi) -# define context_edi uc_mcontext->DU3_PREFIX(ss,edi) -# define context_eflags uc_mcontext->DU3_PREFIX(ss,eflags) -# define context_trapno uc_mcontext->DU3_PREFIX(es,trapno) -# endif +# define context_pc context_rip +# define context_sp context_rsp +# define context_fp context_rbp +# define context_rip uc_mcontext->DU3_PREFIX(ss,rip) +# define context_rsp uc_mcontext->DU3_PREFIX(ss,rsp) +# define context_rax uc_mcontext->DU3_PREFIX(ss,rax) +# define context_rbx uc_mcontext->DU3_PREFIX(ss,rbx) +# define context_rcx uc_mcontext->DU3_PREFIX(ss,rcx) +# define context_rdx uc_mcontext->DU3_PREFIX(ss,rdx) +# define context_rbp uc_mcontext->DU3_PREFIX(ss,rbp) +# define context_rsi uc_mcontext->DU3_PREFIX(ss,rsi) +# define context_rdi uc_mcontext->DU3_PREFIX(ss,rdi) +# define context_r8 uc_mcontext->DU3_PREFIX(ss,r8) +# define context_r9 uc_mcontext->DU3_PREFIX(ss,r9) +# define context_r10 uc_mcontext->DU3_PREFIX(ss,r10) +# define context_r11 uc_mcontext->DU3_PREFIX(ss,r11) +# define context_r12 uc_mcontext->DU3_PREFIX(ss,r12) +# define context_r13 uc_mcontext->DU3_PREFIX(ss,r13) +# define context_r14 uc_mcontext->DU3_PREFIX(ss,r14) +# define context_r15 uc_mcontext->DU3_PREFIX(ss,r15) +# define context_flags uc_mcontext->DU3_PREFIX(ss,rflags) +# define context_trapno uc_mcontext->DU3_PREFIX(es,trapno) +# define context_err uc_mcontext->DU3_PREFIX(es,err) #endif #ifdef __OpenBSD__ # define context_trapno sc_trapno -# ifdef AMD64 -# define context_pc sc_rip -# define context_sp sc_rsp -# define context_fp sc_rbp -# define context_rip sc_rip -# define context_rsp sc_rsp -# define context_rbp sc_rbp -# define context_rax sc_rax -# define context_rbx sc_rbx -# define context_rcx sc_rcx -# define context_rdx sc_rdx -# define context_rsi sc_rsi -# define context_rdi sc_rdi -# define context_r8 sc_r8 -# define context_r9 sc_r9 -# define context_r10 sc_r10 -# define context_r11 sc_r11 -# define context_r12 sc_r12 -# define context_r13 sc_r13 -# define context_r14 sc_r14 -# define context_r15 sc_r15 -# define context_flags sc_rflags -# define context_err sc_err -# else -# define context_pc sc_eip -# define context_sp sc_esp -# define context_fp sc_ebp -# define context_eip sc_eip -# define context_esp sc_esp -# define context_eax sc_eax -# define context_ebx sc_ebx -# define context_ecx sc_ecx -# define context_edx sc_edx -# define context_ebp sc_ebp -# define context_esi sc_esi -# define context_edi sc_edi -# define context_eflags sc_eflags -# define context_trapno sc_trapno -# endif +# define context_pc sc_rip +# define context_sp sc_rsp +# define context_fp sc_rbp +# define context_rip sc_rip +# define context_rsp sc_rsp +# define context_rbp sc_rbp +# define context_rax sc_rax +# define context_rbx sc_rbx +# define context_rcx sc_rcx +# define context_rdx sc_rdx +# define context_rsi sc_rsi +# define context_rdi sc_rdi +# define context_r8 sc_r8 +# define context_r9 sc_r9 +# define context_r10 sc_r10 +# define context_r11 sc_r11 +# define context_r12 sc_r12 +# define context_r13 sc_r13 +# define context_r14 sc_r14 +# define context_r15 sc_r15 +# define context_flags sc_rflags +# define context_err sc_err #endif #ifdef __NetBSD__ # define context_trapno uc_mcontext.__gregs[_REG_TRAPNO] -# ifdef AMD64 -# define __register_t __greg_t -# define context_pc uc_mcontext.__gregs[_REG_RIP] -# define context_sp uc_mcontext.__gregs[_REG_URSP] -# define context_fp uc_mcontext.__gregs[_REG_RBP] -# define context_rip uc_mcontext.__gregs[_REG_RIP] -# define context_rsp uc_mcontext.__gregs[_REG_URSP] -# define context_rax uc_mcontext.__gregs[_REG_RAX] -# define context_rbx uc_mcontext.__gregs[_REG_RBX] -# define context_rcx uc_mcontext.__gregs[_REG_RCX] -# define context_rdx uc_mcontext.__gregs[_REG_RDX] -# define context_rbp uc_mcontext.__gregs[_REG_RBP] -# define context_rsi uc_mcontext.__gregs[_REG_RSI] -# define context_rdi uc_mcontext.__gregs[_REG_RDI] -# define context_r8 uc_mcontext.__gregs[_REG_R8] -# define context_r9 uc_mcontext.__gregs[_REG_R9] -# define context_r10 uc_mcontext.__gregs[_REG_R10] -# define context_r11 uc_mcontext.__gregs[_REG_R11] -# define context_r12 uc_mcontext.__gregs[_REG_R12] -# define context_r13 uc_mcontext.__gregs[_REG_R13] -# define context_r14 uc_mcontext.__gregs[_REG_R14] -# define context_r15 uc_mcontext.__gregs[_REG_R15] -# define context_flags uc_mcontext.__gregs[_REG_RFL] -# define context_err uc_mcontext.__gregs[_REG_ERR] -# else -# define context_pc uc_mcontext.__gregs[_REG_EIP] -# define context_sp uc_mcontext.__gregs[_REG_UESP] -# define context_fp uc_mcontext.__gregs[_REG_EBP] -# define context_eip uc_mcontext.__gregs[_REG_EIP] -# define context_esp uc_mcontext.__gregs[_REG_UESP] -# define context_eax uc_mcontext.__gregs[_REG_EAX] -# define context_ebx uc_mcontext.__gregs[_REG_EBX] -# define context_ecx uc_mcontext.__gregs[_REG_ECX] -# define context_edx uc_mcontext.__gregs[_REG_EDX] -# define context_ebp uc_mcontext.__gregs[_REG_EBP] -# define context_esi uc_mcontext.__gregs[_REG_ESI] -# define context_edi uc_mcontext.__gregs[_REG_EDI] -# define context_eflags uc_mcontext.__gregs[_REG_EFL] -# define context_trapno uc_mcontext.__gregs[_REG_TRAPNO] -# endif +# define __register_t __greg_t +# define context_pc uc_mcontext.__gregs[_REG_RIP] +# define context_sp uc_mcontext.__gregs[_REG_URSP] +# define context_fp uc_mcontext.__gregs[_REG_RBP] +# define context_rip uc_mcontext.__gregs[_REG_RIP] +# define context_rsp uc_mcontext.__gregs[_REG_URSP] +# define context_rax uc_mcontext.__gregs[_REG_RAX] +# define context_rbx uc_mcontext.__gregs[_REG_RBX] +# define context_rcx uc_mcontext.__gregs[_REG_RCX] +# define context_rdx uc_mcontext.__gregs[_REG_RDX] +# define context_rbp uc_mcontext.__gregs[_REG_RBP] +# define context_rsi uc_mcontext.__gregs[_REG_RSI] +# define context_rdi uc_mcontext.__gregs[_REG_RDI] +# define context_r8 uc_mcontext.__gregs[_REG_R8] +# define context_r9 uc_mcontext.__gregs[_REG_R9] +# define context_r10 uc_mcontext.__gregs[_REG_R10] +# define context_r11 uc_mcontext.__gregs[_REG_R11] +# define context_r12 uc_mcontext.__gregs[_REG_R12] +# define context_r13 uc_mcontext.__gregs[_REG_R13] +# define context_r14 uc_mcontext.__gregs[_REG_R14] +# define context_r15 uc_mcontext.__gregs[_REG_R15] +# define context_flags uc_mcontext.__gregs[_REG_RFL] +# define context_err uc_mcontext.__gregs[_REG_ERR] #endif address os::current_stack_pointer() { @@ -468,13 +395,11 @@ bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info, } stub = SharedRuntime::handle_unsafe_access(thread, next_pc); } - } else -#ifdef AMD64 - if (sig == SIGFPE && - (info->si_code == FPE_INTDIV || info->si_code == FPE_FLTDIV - // Workaround for macOS ARM incorrectly reporting FPE_FLTINV for "div by 0" - // instead of the expected FPE_FLTDIV when running x86_64 binary under Rosetta emulation - MACOS_ONLY(|| (VM_Version::is_cpu_emulated() && info->si_code == FPE_FLTINV)))) { + } else if (sig == SIGFPE && + (info->si_code == FPE_INTDIV || info->si_code == FPE_FLTDIV + // Workaround for macOS ARM incorrectly reporting FPE_FLTINV for "div by 0" + // instead of the expected FPE_FLTDIV when running x86_64 binary under Rosetta emulation + MACOS_ONLY(|| (VM_Version::is_cpu_emulated() && info->si_code == FPE_FLTINV)))) { stub = SharedRuntime:: continuation_for_implicit_exception(thread, @@ -502,34 +427,6 @@ bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info, fatal("please update this code."); } #endif /* __APPLE__ */ - -#else - if (sig == SIGFPE /* && info->si_code == FPE_INTDIV */) { - // HACK: si_code does not work on bsd 2.2.12-20!!! - int op = pc[0]; - if (op == 0xDB) { - // FIST - // TODO: The encoding of D2I in x86_32.ad can cause an exception - // prior to the fist instruction if there was an invalid operation - // pending. We want to dismiss that exception. From the win_32 - // side it also seems that if it really was the fist causing - // the exception that we do the d2i by hand with different - // rounding. Seems kind of weird. - // NOTE: that we take the exception at the NEXT floating point instruction. - assert(pc[0] == 0xDB, "not a FIST opcode"); - assert(pc[1] == 0x14, "not a FIST opcode"); - assert(pc[2] == 0x24, "not a FIST opcode"); - return true; - } else if (op == 0xF7) { - // IDIV - stub = SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::IMPLICIT_DIVIDE_BY_ZERO); - } else { - // TODO: handle more cases if we are using other x86 instructions - // that can generate SIGFPE signal on bsd. - tty->print_cr("unknown opcode 0x%X with SIGFPE.", op); - fatal("please update this code."); - } -#endif // AMD64 } else if ((sig == SIGSEGV || sig == SIGBUS) && MacroAssembler::uses_implicit_null_check(info->si_addr)) { // Determination of interpreter/vtable stub/compiled code null exception @@ -556,81 +453,6 @@ bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info, } } -#ifndef AMD64 - // Execution protection violation - // - // This should be kept as the last step in the triage. We don't - // have a dedicated trap number for a no-execute fault, so be - // conservative and allow other handlers the first shot. - // - // Note: We don't test that info->si_code == SEGV_ACCERR here. - // this si_code is so generic that it is almost meaningless; and - // the si_code for this condition may change in the future. - // Furthermore, a false-positive should be harmless. - if (UnguardOnExecutionViolation > 0 && - stub == nullptr && - (sig == SIGSEGV || sig == SIGBUS) && - uc->context_trapno == trap_page_fault) { - size_t page_size = os::vm_page_size(); - address addr = (address) info->si_addr; - address pc = os::Posix::ucontext_get_pc(uc); - // Make sure the pc and the faulting address are sane. - // - // If an instruction spans a page boundary, and the page containing - // the beginning of the instruction is executable but the following - // page is not, the pc and the faulting address might be slightly - // different - we still want to unguard the 2nd page in this case. - // - // 15 bytes seems to be a (very) safe value for max instruction size. - bool pc_is_near_addr = - (pointer_delta((void*) addr, (void*) pc, sizeof(char)) < 15); - bool instr_spans_page_boundary = - (align_down((intptr_t) pc ^ (intptr_t) addr, - (intptr_t) page_size) > 0); - - if (pc == addr || (pc_is_near_addr && instr_spans_page_boundary)) { - static volatile address last_addr = - (address) os::non_memory_address_word(); - - // In conservative mode, don't unguard unless the address is in the VM - if (addr != last_addr && - (UnguardOnExecutionViolation > 1 || os::address_is_in_vm(addr))) { - - // Set memory to RWX and retry - address page_start = align_down(addr, page_size); - bool res = os::protect_memory((char*) page_start, page_size, - os::MEM_PROT_RWX); - - log_debug(os)("Execution protection violation " - "at " INTPTR_FORMAT - ", unguarding " INTPTR_FORMAT ": %s, errno=%d", p2i(addr), - p2i(page_start), (res ? "success" : "failed"), errno); - stub = pc; - - // Set last_addr so if we fault again at the same address, we don't end - // up in an endless loop. - // - // There are two potential complications here. Two threads trapping at - // the same address at the same time could cause one of the threads to - // think it already unguarded, and abort the VM. Likely very rare. - // - // The other race involves two threads alternately trapping at - // different addresses and failing to unguard the page, resulting in - // an endless loop. This condition is probably even more unlikely than - // the first. - // - // Although both cases could be avoided by using locks or thread local - // last_addr, these solutions are unnecessary complication: this - // handler is a best-effort safety net, not a complete solution. It is - // disabled by default and should only be used as a workaround in case - // we missed any no-execute-unsafe VM code. - - last_addr = addr; - } - } - } -#endif // !AMD64 - if (stub != nullptr) { // save all thread context in case we need to restore it if (thread != nullptr) thread->set_saved_exception_pc(pc); @@ -646,10 +468,6 @@ bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info, extern "C" void fixcw(); void os::Bsd::init_thread_fpu_state(void) { -#ifndef AMD64 - // Set fpu to 53 bit precision. This happens too early to use a stub. - fixcw(); -#endif // !AMD64 } juint os::cpu_microcode_revision() { @@ -671,26 +489,12 @@ juint os::cpu_microcode_revision() { // HotSpot guard pages is added later. size_t os::_compiler_thread_min_stack_allowed = 48 * K; size_t os::_java_thread_min_stack_allowed = 48 * K; -#ifdef _LP64 size_t os::_vm_internal_thread_min_stack_allowed = 64 * K; -#else -size_t os::_vm_internal_thread_min_stack_allowed = (48 DEBUG_ONLY(+ 4)) * K; -#endif // _LP64 - -#ifndef AMD64 -#ifdef __GNUC__ -#define GET_GS() ({int gs; __asm__ volatile("movw %%gs, %w0":"=q"(gs)); gs&0xffff;}) -#endif -#endif // AMD64 // return default stack size for thr_type size_t os::Posix::default_stack_size(os::ThreadType thr_type) { // default stack size (compiler thread needs larger stack) -#ifdef AMD64 size_t s = (thr_type == os::compiler_thread ? 4 * M : 1 * M); -#else - size_t s = (thr_type == os::compiler_thread ? 2 * M : 512 * K); -#endif // AMD64 return s; } @@ -803,7 +607,6 @@ void os::print_context(outputStream *st, const void *context) { const ucontext_t *uc = (const ucontext_t*)context; st->print_cr("Registers:"); -#ifdef AMD64 st->print( "RAX=" INTPTR_FORMAT, (intptr_t)uc->context_rax); st->print(", RBX=" INTPTR_FORMAT, (intptr_t)uc->context_rbx); st->print(", RCX=" INTPTR_FORMAT, (intptr_t)uc->context_rcx); @@ -829,26 +632,12 @@ void os::print_context(outputStream *st, const void *context) { st->print(", ERR=" INTPTR_FORMAT, (intptr_t)uc->context_err); st->cr(); st->print(" TRAPNO=" INTPTR_FORMAT, (intptr_t)uc->context_trapno); -#else - st->print( "EAX=" INTPTR_FORMAT, (intptr_t)uc->context_eax); - st->print(", EBX=" INTPTR_FORMAT, (intptr_t)uc->context_ebx); - st->print(", ECX=" INTPTR_FORMAT, (intptr_t)uc->context_ecx); - st->print(", EDX=" INTPTR_FORMAT, (intptr_t)uc->context_edx); - st->cr(); - st->print( "ESP=" INTPTR_FORMAT, (intptr_t)uc->context_esp); - st->print(", EBP=" INTPTR_FORMAT, (intptr_t)uc->context_ebp); - st->print(", ESI=" INTPTR_FORMAT, (intptr_t)uc->context_esi); - st->print(", EDI=" INTPTR_FORMAT, (intptr_t)uc->context_edi); - st->cr(); - st->print( "EIP=" INTPTR_FORMAT, (intptr_t)uc->context_eip); - st->print(", EFLAGS=" INTPTR_FORMAT, (intptr_t)uc->context_eflags); -#endif // AMD64 st->cr(); st->cr(); } void os::print_register_info(outputStream *st, const void *context, int& continuation) { - const int register_count = AMD64_ONLY(16) NOT_AMD64(8); + const int register_count = 16; int n = continuation; assert(n >= 0 && n <= register_count, "Invalid continuation value"); if (context == nullptr || n == register_count) { @@ -861,7 +650,6 @@ void os::print_register_info(outputStream *st, const void *context, int& continu continuation = n + 1; # define CASE_PRINT_REG(n, str, id) case n: st->print(str); print_location(st, uc->context_##id); switch (n) { -#ifdef AMD64 CASE_PRINT_REG( 0, "RAX=", rax); break; CASE_PRINT_REG( 1, "RBX=", rbx); break; CASE_PRINT_REG( 2, "RCX=", rcx); break; @@ -878,28 +666,13 @@ void os::print_register_info(outputStream *st, const void *context, int& continu CASE_PRINT_REG(13, "R13=", r13); break; CASE_PRINT_REG(14, "R14=", r14); break; CASE_PRINT_REG(15, "R15=", r15); break; -#else - CASE_PRINT_REG(0, "EAX=", eax); break; - CASE_PRINT_REG(1, "EBX=", ebx); break; - CASE_PRINT_REG(2, "ECX=", ecx); break; - CASE_PRINT_REG(3, "EDX=", edx); break; - CASE_PRINT_REG(4, "ESP=", esp); break; - CASE_PRINT_REG(5, "EBP=", ebp); break; - CASE_PRINT_REG(6, "ESI=", esi); break; - CASE_PRINT_REG(7, "EDI=", edi); break; -#endif // AMD64 - } + } # undef CASE_PRINT_REG ++n; } } void os::setup_fpu() { -#ifndef AMD64 - address fpu_cntrl = StubRoutines::addr_fpu_cntrl_wrd_std(); - __asm__ volatile ( "fldcw (%0)" : - : "r" (fpu_cntrl) : "memory"); -#endif // !AMD64 } #ifndef PRODUCT diff --git a/src/hotspot/os_cpu/bsd_x86/os_bsd_x86.inline.hpp b/src/hotspot/os_cpu/bsd_x86/os_bsd_x86.inline.hpp index 5398a642d84..fa4b76c4d3d 100644 --- a/src/hotspot/os_cpu/bsd_x86/os_bsd_x86.inline.hpp +++ b/src/hotspot/os_cpu/bsd_x86/os_bsd_x86.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2025, 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 @@ -39,18 +39,11 @@ inline size_t os::cds_core_region_alignment() { // See http://www.technovelty.org/code/c/reading-rdtsc.htl for details inline jlong os::rdtsc() { -#ifndef AMD64 - // 64 bit result in edx:eax - uint64_t res; - __asm__ __volatile__ ("rdtsc" : "=A" (res)); - return (jlong)res; -#else uint64_t res; uint32_t ts1, ts2; __asm__ __volatile__ ("rdtsc" : "=a" (ts1), "=d" (ts2)); res = ((uint64_t)ts1 | (uint64_t)ts2 << 32); return (jlong)res; -#endif // AMD64 } #endif // OS_CPU_BSD_X86_OS_BSD_X86_INLINE_HPP diff --git a/src/hotspot/os_cpu/bsd_x86/prefetch_bsd_x86.inline.hpp b/src/hotspot/os_cpu/bsd_x86/prefetch_bsd_x86.inline.hpp index cb0db2f360c..52cc405e211 100644 --- a/src/hotspot/os_cpu/bsd_x86/prefetch_bsd_x86.inline.hpp +++ b/src/hotspot/os_cpu/bsd_x86/prefetch_bsd_x86.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, 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 @@ -29,19 +29,13 @@ inline void Prefetch::read (const void *loc, intx interval) { -#ifdef AMD64 __asm__ ("prefetcht0 (%0,%1,1)" : : "r" (loc), "r" (interval)); -#endif // AMD64 } inline void Prefetch::write(void *loc, intx interval) { -#ifdef AMD64 - // Do not use the 3dnow prefetchw instruction. It isn't supported on em64t. // __asm__ ("prefetchw (%0,%1,1)" : : "r" (loc), "r" (interval)); __asm__ ("prefetcht0 (%0,%1,1)" : : "r" (loc), "r" (interval)); - -#endif // AMD64 } #endif // OS_CPU_BSD_X86_PREFETCH_BSD_X86_INLINE_HPP diff --git a/src/hotspot/os_cpu/linux_x86/atomicAccess_linux_x86.hpp b/src/hotspot/os_cpu/linux_x86/atomicAccess_linux_x86.hpp index c9af982525d..dd91444d0a3 100644 --- a/src/hotspot/os_cpu/linux_x86/atomicAccess_linux_x86.hpp +++ b/src/hotspot/os_cpu/linux_x86/atomicAccess_linux_x86.hpp @@ -93,8 +93,6 @@ inline T AtomicAccess::PlatformCmpxchg<4>::operator()(T volatile* dest, return exchange_value; } -#ifdef AMD64 - template<> template inline D AtomicAccess::PlatformAdd<8>::fetch_then_add(D volatile* dest, I add_value, @@ -135,51 +133,6 @@ inline T AtomicAccess::PlatformCmpxchg<8>::operator()(T volatile* dest, return exchange_value; } -#else // !AMD64 - -extern "C" { - // defined in linux_x86.s - int64_t _Atomic_cmpxchg_long(int64_t, volatile int64_t*, int64_t); - void _Atomic_move_long(const volatile int64_t* src, volatile int64_t* dst); -} - -template<> -template -inline T AtomicAccess::PlatformCmpxchg<8>::operator()(T volatile* dest, - T compare_value, - T exchange_value, - atomic_memory_order order) const { - STATIC_ASSERT(8 == sizeof(T)); - return cmpxchg_using_helper(_Atomic_cmpxchg_long, dest, compare_value, exchange_value); -} - -// No direct support for 8-byte xchg; emulate using cmpxchg. -template<> -struct AtomicAccess::PlatformXchg<8> : AtomicAccess::XchgUsingCmpxchg<8> {}; - -// No direct support for 8-byte add; emulate using cmpxchg. -template<> -struct AtomicAccess::PlatformAdd<8> : AtomicAccess::AddUsingCmpxchg<8> {}; - -template<> -template -inline T AtomicAccess::PlatformLoad<8>::operator()(T const volatile* src) const { - STATIC_ASSERT(8 == sizeof(T)); - volatile int64_t dest; - _Atomic_move_long(reinterpret_cast(src), reinterpret_cast(&dest)); - return PrimitiveConversions::cast(dest); -} - -template<> -template -inline void AtomicAccess::PlatformStore<8>::operator()(T volatile* dest, - T store_value) const { - STATIC_ASSERT(8 == sizeof(T)); - _Atomic_move_long(reinterpret_cast(&store_value), reinterpret_cast(dest)); -} - -#endif // AMD64 - template<> struct AtomicAccess::PlatformOrderedStore<1, RELEASE_X_FENCE> { @@ -216,7 +169,6 @@ struct AtomicAccess::PlatformOrderedStore<4, RELEASE_X_FENCE> } }; -#ifdef AMD64 template<> struct AtomicAccess::PlatformOrderedStore<8, RELEASE_X_FENCE> { @@ -228,6 +180,5 @@ struct AtomicAccess::PlatformOrderedStore<8, RELEASE_X_FENCE> : "memory"); } }; -#endif // AMD64 #endif // OS_CPU_LINUX_X86_ATOMICACCESS_LINUX_X86_HPP diff --git a/src/hotspot/os_cpu/linux_x86/globals_linux_x86.hpp b/src/hotspot/os_cpu/linux_x86/globals_linux_x86.hpp index 97a5732d00a..e48538ecc7c 100644 --- a/src/hotspot/os_cpu/linux_x86/globals_linux_x86.hpp +++ b/src/hotspot/os_cpu/linux_x86/globals_linux_x86.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, 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 @@ -28,24 +28,9 @@ // Sets the default values for platform dependent flags used by the runtime system. // (see globals.hpp) -#ifdef AMD64 define_pd_global(intx, CompilerThreadStackSize, 1024); define_pd_global(intx, ThreadStackSize, 1024); // 0 => use system default define_pd_global(intx, VMThreadStackSize, 1024); -#else -// Some tests in debug VM mode run out of compile thread stack. -// Observed on some x86_32 VarHandles tests during escape analysis. -#ifdef ASSERT -define_pd_global(intx, CompilerThreadStackSize, 768); -#else -define_pd_global(intx, CompilerThreadStackSize, 512); -#endif -// ThreadStackSize 320 allows a couple of test cases to run while -// keeping the number of threads that can be created high. System -// default ThreadStackSize appears to be 512 which is too big. -define_pd_global(intx, ThreadStackSize, 320); -define_pd_global(intx, VMThreadStackSize, 512); -#endif // AMD64 define_pd_global(size_t, JVMInvokeMethodSlack, 8192); diff --git a/src/hotspot/os_cpu/linux_x86/orderAccess_linux_x86.hpp b/src/hotspot/os_cpu/linux_x86/orderAccess_linux_x86.hpp index a22f547c071..0c6aaacb502 100644 --- a/src/hotspot/os_cpu/linux_x86/orderAccess_linux_x86.hpp +++ b/src/hotspot/os_cpu/linux_x86/orderAccess_linux_x86.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, 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 @@ -46,12 +46,8 @@ inline void OrderAccess::acquire() { compiler_barrier(); } inline void OrderAccess::release() { compiler_barrier(); } inline void OrderAccess::fence() { - // always use locked addl since mfence is sometimes expensive -#ifdef AMD64 + // always use locked addl since mfence is sometimes expensive __asm__ volatile ("lock; addl $0,0(%%rsp)" : : : "cc", "memory"); -#else - __asm__ volatile ("lock; addl $0,0(%%esp)" : : : "cc", "memory"); -#endif compiler_barrier(); } @@ -60,13 +56,7 @@ inline void OrderAccess::cross_modify_fence_impl() { __asm__ volatile (".byte 0x0f, 0x01, 0xe8\n\t" : : :); //serialize } else { int idx = 0; -#ifdef AMD64 __asm__ volatile ("cpuid " : "+a" (idx) : : "ebx", "ecx", "edx", "memory"); -#else - // On some x86 systems EBX is a reserved register that cannot be - // clobbered, so we must protect it around the CPUID. - __asm__ volatile ("xchg %%esi, %%ebx; cpuid; xchg %%esi, %%ebx " : "+a" (idx) : : "esi", "ecx", "edx", "memory"); -#endif } } diff --git a/src/hotspot/os_cpu/linux_x86/os_linux_x86.cpp b/src/hotspot/os_cpu/linux_x86/os_linux_x86.cpp index ff7fce234c4..a7f4e5ef688 100644 --- a/src/hotspot/os_cpu/linux_x86/os_linux_x86.cpp +++ b/src/hotspot/os_cpu/linux_x86/os_linux_x86.cpp @@ -72,24 +72,13 @@ # include # include # include -#ifndef AMD64 -# include -#endif -#ifdef AMD64 #define REG_SP REG_RSP #define REG_PC REG_RIP #define REG_FP REG_RBP #define REG_BCP REG_R13 #define SPELL_REG_SP "rsp" #define SPELL_REG_FP "rbp" -#else -#define REG_SP REG_UESP -#define REG_PC REG_EIP -#define REG_FP REG_EBP -#define SPELL_REG_SP "esp" -#define SPELL_REG_FP "ebp" -#endif // AMD64 address os::current_stack_pointer() { return (address)__builtin_frame_address(0); @@ -281,43 +270,14 @@ bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info, } stub = SharedRuntime::handle_unsafe_access(thread, next_pc); } - } else -#ifdef AMD64 - if (sig == SIGFPE && - (info->si_code == FPE_INTDIV || info->si_code == FPE_FLTDIV)) { + } else if (sig == SIGFPE && + (info->si_code == FPE_INTDIV || info->si_code == FPE_FLTDIV)) { stub = SharedRuntime:: continuation_for_implicit_exception(thread, pc, SharedRuntime:: IMPLICIT_DIVIDE_BY_ZERO); -#else - if (sig == SIGFPE /* && info->si_code == FPE_INTDIV */) { - // HACK: si_code does not work on linux 2.2.12-20!!! - int op = pc[0]; - if (op == 0xDB) { - // FIST - // TODO: The encoding of D2I in x86_32.ad can cause an exception - // prior to the fist instruction if there was an invalid operation - // pending. We want to dismiss that exception. From the win_32 - // side it also seems that if it really was the fist causing - // the exception that we do the d2i by hand with different - // rounding. Seems kind of weird. - // NOTE: that we take the exception at the NEXT floating point instruction. - assert(pc[0] == 0xDB, "not a FIST opcode"); - assert(pc[1] == 0x14, "not a FIST opcode"); - assert(pc[2] == 0x24, "not a FIST opcode"); - return true; - } else if (op == 0xF7) { - // IDIV - stub = SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::IMPLICIT_DIVIDE_BY_ZERO); - } else { - // TODO: handle more cases if we are using other x86 instructions - // that can generate SIGFPE signal on linux. - tty->print_cr("unknown opcode 0x%X with SIGFPE.", op); - fatal("please update this code."); - } -#endif // AMD64 } else if (sig == SIGSEGV && MacroAssembler::uses_implicit_null_check(info->si_addr)) { // Determination of interpreter/vtable stub/compiled code null exception @@ -344,81 +304,6 @@ bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info, } } -#ifndef AMD64 - // Execution protection violation - // - // This should be kept as the last step in the triage. We don't - // have a dedicated trap number for a no-execute fault, so be - // conservative and allow other handlers the first shot. - // - // Note: We don't test that info->si_code == SEGV_ACCERR here. - // this si_code is so generic that it is almost meaningless; and - // the si_code for this condition may change in the future. - // Furthermore, a false-positive should be harmless. - if (UnguardOnExecutionViolation > 0 && - stub == nullptr && - (sig == SIGSEGV || sig == SIGBUS) && - uc->uc_mcontext.gregs[REG_TRAPNO] == trap_page_fault) { - size_t page_size = os::vm_page_size(); - address addr = (address) info->si_addr; - address pc = os::Posix::ucontext_get_pc(uc); - // Make sure the pc and the faulting address are sane. - // - // If an instruction spans a page boundary, and the page containing - // the beginning of the instruction is executable but the following - // page is not, the pc and the faulting address might be slightly - // different - we still want to unguard the 2nd page in this case. - // - // 15 bytes seems to be a (very) safe value for max instruction size. - bool pc_is_near_addr = - (pointer_delta((void*) addr, (void*) pc, sizeof(char)) < 15); - bool instr_spans_page_boundary = - (align_down((intptr_t) pc ^ (intptr_t) addr, - (intptr_t) page_size) > 0); - - if (pc == addr || (pc_is_near_addr && instr_spans_page_boundary)) { - static volatile address last_addr = - (address) os::non_memory_address_word(); - - // In conservative mode, don't unguard unless the address is in the VM - if (addr != last_addr && - (UnguardOnExecutionViolation > 1 || os::address_is_in_vm(addr))) { - - // Set memory to RWX and retry - address page_start = align_down(addr, page_size); - bool res = os::protect_memory((char*) page_start, page_size, - os::MEM_PROT_RWX); - - log_debug(os)("Execution protection violation " - "at " INTPTR_FORMAT - ", unguarding " INTPTR_FORMAT ": %s, errno=%d", p2i(addr), - p2i(page_start), (res ? "success" : "failed"), errno); - stub = pc; - - // Set last_addr so if we fault again at the same address, we don't end - // up in an endless loop. - // - // There are two potential complications here. Two threads trapping at - // the same address at the same time could cause one of the threads to - // think it already unguarded, and abort the VM. Likely very rare. - // - // The other race involves two threads alternately trapping at - // different addresses and failing to unguard the page, resulting in - // an endless loop. This condition is probably even more unlikely than - // the first. - // - // Although both cases could be avoided by using locks or thread local - // last_addr, these solutions are unnecessary complication: this - // handler is a best-effort safety net, not a complete solution. It is - // disabled by default and should only be used as a workaround in case - // we missed any no-execute-unsafe VM code. - - last_addr = addr; - } - } - } -#endif // !AMD64 - if (stub != nullptr) { // save all thread context in case we need to restore it if (thread != nullptr) thread->set_saved_exception_pc(pc); @@ -431,26 +316,13 @@ bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info, } void os::Linux::init_thread_fpu_state(void) { -#ifndef AMD64 - // set fpu to 53 bit precision - set_fpu_control_word(0x27f); -#endif // !AMD64 } int os::Linux::get_fpu_control_word(void) { -#ifdef AMD64 return 0; -#else - int fpu_control; - _FPU_GETCW(fpu_control); - return fpu_control & 0xffff; -#endif // AMD64 } void os::Linux::set_fpu_control_word(int fpu_control) { -#ifndef AMD64 - _FPU_SETCW(fpu_control); -#endif // !AMD64 } juint os::cpu_microcode_revision() { @@ -496,20 +368,12 @@ juint os::cpu_microcode_revision() { // HotSpot guard pages is added later. size_t os::_compiler_thread_min_stack_allowed = 48 * K; size_t os::_java_thread_min_stack_allowed = 40 * K; -#ifdef _LP64 size_t os::_vm_internal_thread_min_stack_allowed = 64 * K; -#else -size_t os::_vm_internal_thread_min_stack_allowed = (48 DEBUG_ONLY(+ 4)) * K; -#endif // _LP64 // return default stack size for thr_type size_t os::Posix::default_stack_size(os::ThreadType thr_type) { // default stack size (compiler thread needs larger stack) -#ifdef AMD64 size_t s = (thr_type == os::compiler_thread ? 4 * M : 1 * M); -#else - size_t s = (thr_type == os::compiler_thread ? 2 * M : 512 * K); -#endif // AMD64 return s; } @@ -522,7 +386,6 @@ void os::print_context(outputStream *st, const void *context) { const ucontext_t *uc = (const ucontext_t*)context; st->print_cr("Registers:"); -#ifdef AMD64 st->print( "RAX=" INTPTR_FORMAT, (intptr_t)uc->uc_mcontext.gregs[REG_RAX]); st->print(", RBX=" INTPTR_FORMAT, (intptr_t)uc->uc_mcontext.gregs[REG_RBX]); st->print(", RCX=" INTPTR_FORMAT, (intptr_t)uc->uc_mcontext.gregs[REG_RCX]); @@ -564,27 +427,12 @@ void os::print_context(outputStream *st, const void *context) { } st->print(" MXCSR=" UINT32_FORMAT_X_0, uc->uc_mcontext.fpregs->mxcsr); } -#else - st->print( "EAX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_EAX]); - st->print(", EBX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_EBX]); - st->print(", ECX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_ECX]); - st->print(", EDX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_EDX]); - st->cr(); - st->print( "ESP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_UESP]); - st->print(", EBP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_EBP]); - st->print(", ESI=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_ESI]); - st->print(", EDI=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_EDI]); - st->cr(); - st->print( "EIP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_EIP]); - st->print(", EFLAGS=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_EFL]); - st->print(", CR2=" UINT64_FORMAT_X_0, (uint64_t)uc->uc_mcontext.cr2); -#endif // AMD64 st->cr(); st->cr(); } void os::print_register_info(outputStream *st, const void *context, int& continuation) { - const int register_count = AMD64_ONLY(16) NOT_AMD64(8); + const int register_count = 16; int n = continuation; assert(n >= 0 && n <= register_count, "Invalid continuation value"); if (context == nullptr || n == register_count) { @@ -597,7 +445,6 @@ void os::print_register_info(outputStream *st, const void *context, int& continu continuation = n + 1; # define CASE_PRINT_REG(n, str, id) case n: st->print(str); print_location(st, uc->uc_mcontext.gregs[REG_##id]); switch (n) { -#ifdef AMD64 CASE_PRINT_REG( 0, "RAX=", RAX); break; CASE_PRINT_REG( 1, "RBX=", RBX); break; CASE_PRINT_REG( 2, "RCX=", RCX); break; @@ -614,16 +461,6 @@ void os::print_register_info(outputStream *st, const void *context, int& continu CASE_PRINT_REG(13, "R13=", R13); break; CASE_PRINT_REG(14, "R14=", R14); break; CASE_PRINT_REG(15, "R15=", R15); break; -#else - CASE_PRINT_REG(0, "EAX=", EAX); break; - CASE_PRINT_REG(1, "EBX=", EBX); break; - CASE_PRINT_REG(2, "ECX=", ECX); break; - CASE_PRINT_REG(3, "EDX=", EDX); break; - CASE_PRINT_REG(4, "ESP=", ESP); break; - CASE_PRINT_REG(5, "EBP=", EBP); break; - CASE_PRINT_REG(6, "ESI=", ESI); break; - CASE_PRINT_REG(7, "EDI=", EDI); break; -#endif // AMD64 } # undef CASE_PRINT_REG ++n; @@ -631,18 +468,11 @@ void os::print_register_info(outputStream *st, const void *context, int& continu } void os::setup_fpu() { -#ifndef AMD64 - address fpu_cntrl = StubRoutines::x86::addr_fpu_cntrl_wrd_std(); - __asm__ volatile ( "fldcw (%0)" : - : "r" (fpu_cntrl) : "memory"); -#endif // !AMD64 } #ifndef PRODUCT void os::verify_stack_alignment() { -#ifdef AMD64 assert(((intptr_t)os::current_stack_pointer() & (StackAlignmentInBytes-1)) == 0, "incorrect stack alignment"); -#endif } #endif diff --git a/src/hotspot/os_cpu/linux_x86/os_linux_x86.inline.hpp b/src/hotspot/os_cpu/linux_x86/os_linux_x86.inline.hpp index 535f318cfbd..11c6c77644e 100644 --- a/src/hotspot/os_cpu/linux_x86/os_linux_x86.inline.hpp +++ b/src/hotspot/os_cpu/linux_x86/os_linux_x86.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2025, 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 @@ -29,18 +29,11 @@ // See http://www.technovelty.org/code/c/reading-rdtsc.htl for details inline jlong os::rdtsc() { -#ifndef AMD64 - // 64 bit result in edx:eax - uint64_t res; - __asm__ __volatile__ ("rdtsc" : "=A" (res)); - return (jlong)res; -#else uint64_t res; uint32_t ts1, ts2; __asm__ __volatile__ ("rdtsc" : "=a" (ts1), "=d" (ts2)); res = ((uint64_t)ts1 | (uint64_t)ts2 << 32); return (jlong)res; -#endif // AMD64 } #endif // OS_CPU_LINUX_X86_OS_LINUX_X86_INLINE_HPP diff --git a/src/hotspot/os_cpu/linux_x86/prefetch_linux_x86.inline.hpp b/src/hotspot/os_cpu/linux_x86/prefetch_linux_x86.inline.hpp index cf60c2cbd6b..bb4302e1ddb 100644 --- a/src/hotspot/os_cpu/linux_x86/prefetch_linux_x86.inline.hpp +++ b/src/hotspot/os_cpu/linux_x86/prefetch_linux_x86.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, 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 @@ -29,19 +29,13 @@ inline void Prefetch::read (const void *loc, intx interval) { -#ifdef AMD64 __asm__ ("prefetcht0 (%0,%1,1)" : : "r" (loc), "r" (interval)); -#endif // AMD64 } inline void Prefetch::write(void *loc, intx interval) { -#ifdef AMD64 - // Do not use the 3dnow prefetchw instruction. It isn't supported on em64t. // __asm__ ("prefetchw (%0,%1,1)" : : "r" (loc), "r" (interval)); __asm__ ("prefetcht0 (%0,%1,1)" : : "r" (loc), "r" (interval)); - -#endif // AMD64 } #endif // OS_CPU_LINUX_X86_PREFETCH_LINUX_X86_INLINE_HPP diff --git a/src/hotspot/os_cpu/windows_x86/os_windows_x86.cpp b/src/hotspot/os_cpu/windows_x86/os_windows_x86.cpp index c688848c790..e3291d3a6ca 100644 --- a/src/hotspot/os_cpu/windows_x86/os_windows_x86.cpp +++ b/src/hotspot/os_cpu/windows_x86/os_windows_x86.cpp @@ -162,7 +162,6 @@ bool os::win32::register_code_area(char *low, char *high) { return true; } -#if defined(_M_AMD64) //----------------------------------------------------------------------------- bool handle_FLT_exception(struct _EXCEPTION_POINTERS* exceptionInfo) { // handle exception caused by native method modifying control word @@ -197,7 +196,6 @@ bool handle_FLT_exception(struct _EXCEPTION_POINTERS* exceptionInfo) { return false; } -#endif address os::fetch_frame_from_context(const void* ucVoid, intptr_t** ret_sp, intptr_t** ret_fp) {