Quellcode-Bibliothek
© Kompilation durch diese Firma
[Weder Korrektheit noch Funktionsfähigkeit der Software werden zugesichert.]
Datei:
Sprache: Unknown
/*
* Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#include "precompiled.hpp"
#include "asm/assembler.hpp"
#include "asm/assembler.inline.hpp"
#include "gc/shared/cardTableBarrierSet.hpp"
#include "gc/shared/collectedHeap.inline.hpp"
#include "interpreter/interpreter.hpp"
#include "memory/resourceArea.hpp"
#include "prims/methodHandles.hpp"
#include "runtime/objectMonitor.hpp"
#include "runtime/os.hpp"
#include "runtime/sharedRuntime.hpp"
#include "runtime/stubRoutines.hpp"
#include "runtime/vm_version.hpp"
#include "utilities/macros.hpp"
#ifdef PRODUCT
#define BLOCK_COMMENT(str) /* nothing */
#define STOP(error) stop(error)
#else
#define BLOCK_COMMENT(str) block_comment(str)
#define STOP(error) block_comment(error); stop(error)
#endif
#define BIND(label) bind(label); BLOCK_COMMENT(#label ":")
// Implementation of AddressLiteral
// A 2-D table for managing compressed displacement(disp8) on EVEX enabled platforms.
unsigned char tuple_table[Assembler::EVEX_ETUP + 1][Assembler::AVX_512bit + 1] = {
// -----------------Table 4.5 -------------------- //
16, 32, 64, // EVEX_FV(0)
4, 4, 4, // EVEX_FV(1) - with Evex.b
16, 32, 64, // EVEX_FV(2) - with Evex.w
8, 8, 8, // EVEX_FV(3) - with Evex.w and Evex.b
8, 16, 32, // EVEX_HV(0)
4, 4, 4, // EVEX_HV(1) - with Evex.b
// -----------------Table 4.6 -------------------- //
16, 32, 64, // EVEX_FVM(0)
1, 1, 1, // EVEX_T1S(0)
2, 2, 2, // EVEX_T1S(1)
4, 4, 4, // EVEX_T1S(2)
8, 8, 8, // EVEX_T1S(3)
4, 4, 4, // EVEX_T1F(0)
8, 8, 8, // EVEX_T1F(1)
8, 8, 8, // EVEX_T2(0)
0, 16, 16, // EVEX_T2(1)
0, 16, 16, // EVEX_T4(0)
0, 0, 32, // EVEX_T4(1)
0, 0, 32, // EVEX_T8(0)
8, 16, 32, // EVEX_HVM(0)
4, 8, 16, // EVEX_QVM(0)
2, 4, 8, // EVEX_OVM(0)
16, 16, 16, // EVEX_M128(0)
8, 32, 64, // EVEX_DUP(0)
0, 0, 0 // EVEX_NTUP
};
AddressLiteral::AddressLiteral(address target, relocInfo::relocType rtype) {
_is_lval = false;
_target = target;
switch (rtype) {
case relocInfo::oop_type:
case relocInfo::metadata_type:
// Oops are a special case. Normally they would be their own section
// but in cases like icBuffer they are literals in the code stream that
// we don't have a section for. We use none so that we get a literal address
// which is always patchable.
break;
case relocInfo::external_word_type:
_rspec = external_word_Relocation::spec(target);
break;
case relocInfo::internal_word_type:
_rspec = internal_word_Relocation::spec(target);
break;
case relocInfo::opt_virtual_call_type:
_rspec = opt_virtual_call_Relocation::spec();
break;
case relocInfo::static_call_type:
_rspec = static_call_Relocation::spec();
break;
case relocInfo::runtime_call_type:
_rspec = runtime_call_Relocation::spec();
break;
case relocInfo::poll_type:
case relocInfo::poll_return_type:
_rspec = Relocation::spec_simple(rtype);
break;
case relocInfo::none:
break;
default:
ShouldNotReachHere();
break;
}
}
// Implementation of Address
#ifdef _LP64
Address Address::make_array(ArrayAddress adr) {
// Not implementable on 64bit machines
// Should have been handled higher up the call chain.
ShouldNotReachHere();
return Address();
}
// exceedingly dangerous constructor
Address::Address(int disp, address loc, relocInfo::relocType rtype) {
_base = noreg;
_index = noreg;
_scale = no_scale;
_disp = disp;
_xmmindex = xnoreg;
_isxmmindex = false;
switch (rtype) {
case relocInfo::external_word_type:
_rspec = external_word_Relocation::spec(loc);
break;
case relocInfo::internal_word_type:
_rspec = internal_word_Relocation::spec(loc);
break;
case relocInfo::runtime_call_type:
// HMM
_rspec = runtime_call_Relocation::spec();
break;
case relocInfo::poll_type:
case relocInfo::poll_return_type:
_rspec = Relocation::spec_simple(rtype);
break;
case relocInfo::none:
break;
default:
ShouldNotReachHere();
}
}
#else // LP64
Address Address::make_array(ArrayAddress adr) {
AddressLiteral base = adr.base();
Address index = adr.index();
assert(index._disp == 0, "must not have disp"); // maybe it can?
Address array(index._base, index._index, index._scale, (intptr_t) base.target());
array._rspec = base._rspec;
return array;
}
// exceedingly dangerous constructor
Address::Address(address loc, RelocationHolder spec) {
_base = noreg;
_index = noreg;
_scale = no_scale;
_disp = (intptr_t) loc;
_rspec = spec;
_xmmindex = xnoreg;
_isxmmindex = false;
}
#endif // _LP64
// Convert the raw encoding form into the form expected by the constructor for
// Address. An index of 4 (rsp) corresponds to having no index, so convert
// that to noreg for the Address constructor.
Address Address::make_raw(int base, int index, int scale, int disp, relocInfo::relocType disp_reloc) {
RelocationHolder rspec = RelocationHolder::none;
if (disp_reloc != relocInfo::none) {
rspec = Relocation::spec_simple(disp_reloc);
}
bool valid_index = index != rsp->encoding();
if (valid_index) {
Address madr(as_Register(base), as_Register(index), (Address::ScaleFactor)scale, in_ByteSize(disp));
madr._rspec = rspec;
return madr;
} else {
Address madr(as_Register(base), noreg, Address::no_scale, in_ByteSize(disp));
madr._rspec = rspec;
return madr;
}
}
// Implementation of Assembler
int AbstractAssembler::code_fill_byte() {
return (u_char)'\xF4'; // hlt
}
void Assembler::init_attributes(void) {
_legacy_mode_bw = (VM_Version::supports_avx512bw() == false);
_legacy_mode_dq = (VM_Version::supports_avx512dq() == false);
_legacy_mode_vl = (VM_Version::supports_avx512vl() == false);
_legacy_mode_vlbw = (VM_Version::supports_avx512vlbw() == false);
NOT_LP64(_is_managed = false;)
_attributes = NULL;
}
void Assembler::membar(Membar_mask_bits order_constraint) {
// We only have to handle StoreLoad
if (order_constraint & StoreLoad) {
// All usable chips support "locked" instructions which suffice
// as barriers, and are much faster than the alternative of
// using cpuid instruction. We use here a locked add [esp-C],0.
// This is conveniently otherwise a no-op except for blowing
// flags, and introducing a false dependency on target memory
// location. We can't do anything with flags, but we can avoid
// memory dependencies in the current method by locked-adding
// somewhere else on the stack. Doing [esp+C] will collide with
// something on stack in current method, hence we go for [esp-C].
// It is convenient since it is almost always in data cache, for
// any small C. We need to step back from SP to avoid data
// dependencies with other things on below SP (callee-saves, for
// example). Without a clear way to figure out the minimal safe
// distance from SP, it makes sense to step back the complete
// cache line, as this will also avoid possible second-order effects
// with locked ops against the cache line. Our choice of offset
// is bounded by x86 operand encoding, which should stay within
// [-128; +127] to have the 8-byte displacement encoding.
//
// Any change to this code may need to revisit other places in
// the code where this idiom is used, in particular the
// orderAccess code.
int offset = -VM_Version::L1_line_size();
if (offset < -128) {
offset = -128;
}
lock();
addl(Address(rsp, offset), 0);// Assert the lock# signal here
}
}
// make this go away someday
void Assembler::emit_data(jint data, relocInfo::relocType rtype, int format) {
if (rtype == relocInfo::none)
emit_int32(data);
else
emit_data(data, Relocation::spec_simple(rtype), format);
}
void Assembler::emit_data(jint data, RelocationHolder const& rspec, int format) {
assert(imm_operand == 0, "default format must be immediate in this file");
assert(inst_mark() != NULL, "must be inside InstructionMark");
if (rspec.type() != relocInfo::none) {
#ifdef ASSERT
check_relocation(rspec, format);
#endif
// Do not use AbstractAssembler::relocate, which is not intended for
// embedded words. Instead, relocate to the enclosing instruction.
// hack. call32 is too wide for mask so use disp32
if (format == call32_operand)
code_section()->relocate(inst_mark(), rspec, disp32_operand);
else
code_section()->relocate(inst_mark(), rspec, format);
}
emit_int32(data);
}
static int encode(Register r) {
int enc = r->encoding();
if (enc >= 8) {
enc -= 8;
}
return enc;
}
void Assembler::emit_arith_b(int op1, int op2, Register dst, int imm8) {
assert(dst->has_byte_register(), "must have byte register");
assert(isByte(op1) && isByte(op2), "wrong opcode");
assert(isByte(imm8), "not a byte");
assert((op1 & 0x01) == 0, "should be 8bit operation");
emit_int24(op1, (op2 | encode(dst)), imm8);
}
void Assembler::emit_arith(int op1, int op2, Register dst, int32_t imm32) {
assert(isByte(op1) && isByte(op2), "wrong opcode");
assert(op1 == 0x81, "Unexpected opcode");
if (is8bit(imm32)) {
emit_int24(op1 | 0x02, // set sign bit
op2 | encode(dst),
imm32 & 0xFF);
} else if (dst == rax) {
switch (op2) {
case 0xD0: emit_int8(0x15); break; // adc
case 0xC0: emit_int8(0x05); break; // add
case 0xE0: emit_int8(0x25); break; // and
case 0xF8: emit_int8(0x3D); break; // cmp
case 0xC8: emit_int8(0x0D); break; // or
case 0xD8: emit_int8(0x1D); break; // sbb
case 0xE8: emit_int8(0x2D); break; // sub
case 0xF0: emit_int8(0x35); break; // xor
default: ShouldNotReachHere();
}
emit_int32(imm32);
} else {
emit_int16(op1, (op2 | encode(dst)));
emit_int32(imm32);
}
}
// Force generation of a 4 byte immediate value even if it fits into 8bit
void Assembler::emit_arith_imm32(int op1, int op2, Register dst, int32_t imm32) {
assert(isByte(op1) && isByte(op2), "wrong opcode");
assert((op1 & 0x01) == 1, "should be 32bit operation");
assert((op1 & 0x02) == 0, "sign-extension bit should not be set");
emit_int16(op1, (op2 | encode(dst)));
emit_int32(imm32);
}
// immediate-to-memory forms
void Assembler::emit_arith_operand(int op1, Register rm, Address adr, int32_t imm32) {
assert((op1 & 0x01) == 1, "should be 32bit operation");
assert((op1 & 0x02) == 0, "sign-extension bit should not be set");
if (is8bit(imm32)) {
emit_int8(op1 | 0x02); // set sign bit
emit_operand(rm, adr, 1);
emit_int8(imm32 & 0xFF);
} else {
emit_int8(op1);
emit_operand(rm, adr, 4);
emit_int32(imm32);
}
}
void Assembler::emit_arith_operand_imm32(int op1, Register rm, Address adr, int32_t imm32) {
assert(op1 == 0x81, "unexpected opcode");
emit_int8(op1);
emit_operand(rm, adr, 4);
emit_int32(imm32);
}
void Assembler::emit_arith(int op1, int op2, Register dst, Register src) {
assert(isByte(op1) && isByte(op2), "wrong opcode");
emit_int16(op1, (op2 | encode(dst) << 3 | encode(src)));
}
bool Assembler::query_compressed_disp_byte(int disp, bool is_evex_inst, int vector_len,
int cur_tuple_type, int in_size_in_bits, int cur_encoding) {
int mod_idx = 0;
// We will test if the displacement fits the compressed format and if so
// apply the compression to the displacement iff the result is8bit.
if (VM_Version::supports_evex() && is_evex_inst) {
switch (cur_tuple_type) {
case EVEX_FV:
if ((cur_encoding & VEX_W) == VEX_W) {
mod_idx = ((cur_encoding & EVEX_Rb) == EVEX_Rb) ? 3 : 2;
} else {
mod_idx = ((cur_encoding & EVEX_Rb) == EVEX_Rb) ? 1 : 0;
}
break;
case EVEX_HV:
mod_idx = ((cur_encoding & EVEX_Rb) == EVEX_Rb) ? 1 : 0;
break;
case EVEX_FVM:
break;
case EVEX_T1S:
switch (in_size_in_bits) {
case EVEX_8bit:
break;
case EVEX_16bit:
mod_idx = 1;
break;
case EVEX_32bit:
mod_idx = 2;
break;
case EVEX_64bit:
mod_idx = 3;
break;
}
break;
case EVEX_T1F:
case EVEX_T2:
case EVEX_T4:
mod_idx = (in_size_in_bits == EVEX_64bit) ? 1 : 0;
break;
case EVEX_T8:
break;
case EVEX_HVM:
break;
case EVEX_QVM:
break;
case EVEX_OVM:
break;
case EVEX_M128:
break;
case EVEX_DUP:
break;
default:
assert(0, "no valid evex tuple_table entry");
break;
}
if (vector_len >= AVX_128bit && vector_len <= AVX_512bit) {
int disp_factor = tuple_table[cur_tuple_type + mod_idx][vector_len];
if ((disp % disp_factor) == 0) {
int new_disp = disp / disp_factor;
if ((-0x80 <= new_disp && new_disp < 0x80)) {
disp = new_disp;
}
} else {
return false;
}
}
}
return (-0x80 <= disp && disp < 0x80);
}
bool Assembler::emit_compressed_disp_byte(int &disp) {
int mod_idx = 0;
// We will test if the displacement fits the compressed format and if so
// apply the compression to the displacement iff the result is8bit.
if (VM_Version::supports_evex() && _attributes && _attributes->is_evex_instruction()) {
int evex_encoding = _attributes->get_evex_encoding();
int tuple_type = _attributes->get_tuple_type();
switch (tuple_type) {
case EVEX_FV:
if ((evex_encoding & VEX_W) == VEX_W) {
mod_idx = ((evex_encoding & EVEX_Rb) == EVEX_Rb) ? 3 : 2;
} else {
mod_idx = ((evex_encoding & EVEX_Rb) == EVEX_Rb) ? 1 : 0;
}
break;
case EVEX_HV:
mod_idx = ((evex_encoding & EVEX_Rb) == EVEX_Rb) ? 1 : 0;
break;
case EVEX_FVM:
break;
case EVEX_T1S:
switch (_attributes->get_input_size()) {
case EVEX_8bit:
break;
case EVEX_16bit:
mod_idx = 1;
break;
case EVEX_32bit:
mod_idx = 2;
break;
case EVEX_64bit:
mod_idx = 3;
break;
}
break;
case EVEX_T1F:
case EVEX_T2:
case EVEX_T4:
mod_idx = (_attributes->get_input_size() == EVEX_64bit) ? 1 : 0;
break;
case EVEX_T8:
break;
case EVEX_HVM:
break;
case EVEX_QVM:
break;
case EVEX_OVM:
break;
case EVEX_M128:
break;
case EVEX_DUP:
break;
default:
assert(0, "no valid evex tuple_table entry");
break;
}
int vector_len = _attributes->get_vector_len();
if (vector_len >= AVX_128bit && vector_len <= AVX_512bit) {
int disp_factor = tuple_table[tuple_type + mod_idx][vector_len];
if ((disp % disp_factor) == 0) {
int new_disp = disp / disp_factor;
if (is8bit(new_disp)) {
disp = new_disp;
}
} else {
return false;
}
}
}
return is8bit(disp);
}
static bool is_valid_encoding(int reg_enc) {
return reg_enc >= 0;
}
static int raw_encode(Register reg) {
assert(reg == noreg || reg->is_valid(), "sanity");
int reg_enc = reg->raw_encoding();
assert(reg_enc == -1 || is_valid_encoding(reg_enc), "sanity");
return reg_enc;
}
static int raw_encode(XMMRegister xmmreg) {
assert(xmmreg == xnoreg || xmmreg->is_valid(), "sanity");
int xmmreg_enc = xmmreg->raw_encoding();
assert(xmmreg_enc == -1 || is_valid_encoding(xmmreg_enc), "sanity");
return xmmreg_enc;
}
static int raw_encode(KRegister kreg) {
assert(kreg == knoreg || kreg->is_valid(), "sanity");
int kreg_enc = kreg->raw_encoding();
assert(kreg_enc == -1 || is_valid_encoding(kreg_enc), "sanity");
return kreg_enc;
}
static int modrm_encoding(int mod, int dst_enc, int src_enc) {
return (mod & 3) << 6 | (dst_enc & 7) << 3 | (src_enc & 7);
}
static int sib_encoding(Address::ScaleFactor scale, int index_enc, int base_enc) {
return (scale & 3) << 6 | (index_enc & 7) << 3 | (base_enc & 7);
}
inline void Assembler::emit_modrm(int mod, int dst_enc, int src_enc) {
assert((mod & 3) != 0b11, "forbidden");
int modrm = modrm_encoding(mod, dst_enc, src_enc);
emit_int8(modrm);
}
inline void Assembler::emit_modrm_disp8(int mod, int dst_enc, int src_enc,
int disp) {
int modrm = modrm_encoding(mod, dst_enc, src_enc);
emit_int16(modrm, disp & 0xFF);
}
inline void Assembler::emit_modrm_sib(int mod, int dst_enc, int src_enc,
Address::ScaleFactor scale, int index_enc, int base_enc) {
int modrm = modrm_encoding(mod, dst_enc, src_enc);
int sib = sib_encoding(scale, index_enc, base_enc);
emit_int16(modrm, sib);
}
inline void Assembler::emit_modrm_sib_disp8(int mod, int dst_enc, int src_enc,
Address::ScaleFactor scale, int index_enc, int base_enc,
int disp) {
int modrm = modrm_encoding(mod, dst_enc, src_enc);
int sib = sib_encoding(scale, index_enc, base_enc);
emit_int24(modrm, sib, disp & 0xFF);
}
void Assembler::emit_operand_helper(int reg_enc, int base_enc, int index_enc,
Address::ScaleFactor scale, int disp,
RelocationHolder const& rspec,
int post_addr_length) {
bool no_relocation = (rspec.type() == relocInfo::none);
if (is_valid_encoding(base_enc)) {
if (is_valid_encoding(index_enc)) {
assert(scale != Address::no_scale, "inconsistent address");
// [base + index*scale + disp]
if (disp == 0 && no_relocation &&
base_enc != rbp->encoding() LP64_ONLY(&& base_enc != r13->encoding())) {
// [base + index*scale]
// [00 reg 100][ss index base]
emit_modrm_sib(0b00, reg_enc, 0b100,
scale, index_enc, base_enc);
} else if (emit_compressed_disp_byte(disp) && no_relocation) {
// [base + index*scale + imm8]
// [01 reg 100][ss index base] imm8
emit_modrm_sib_disp8(0b01, reg_enc, 0b100,
scale, index_enc, base_enc,
disp);
} else {
// [base + index*scale + disp32]
// [10 reg 100][ss index base] disp32
emit_modrm_sib(0b10, reg_enc, 0b100,
scale, index_enc, base_enc);
emit_data(disp, rspec, disp32_operand);
}
} else if (base_enc == rsp->encoding() LP64_ONLY(|| base_enc == r12->encoding())) {
// [rsp + disp]
if (disp == 0 && no_relocation) {
// [rsp]
// [00 reg 100][00 100 100]
emit_modrm_sib(0b00, reg_enc, 0b100,
Address::times_1, 0b100, 0b100);
} else if (emit_compressed_disp_byte(disp) && no_relocation) {
// [rsp + imm8]
// [01 reg 100][00 100 100] disp8
emit_modrm_sib_disp8(0b01, reg_enc, 0b100,
Address::times_1, 0b100, 0b100,
disp);
} else {
// [rsp + imm32]
// [10 reg 100][00 100 100] disp32
emit_modrm_sib(0b10, reg_enc, 0b100,
Address::times_1, 0b100, 0b100);
emit_data(disp, rspec, disp32_operand);
}
} else {
// [base + disp]
assert(base_enc != rsp->encoding() LP64_ONLY(&& base_enc != r12->encoding()), "illegal addressing mode");
if (disp == 0 && no_relocation &&
base_enc != rbp->encoding() LP64_ONLY(&& base_enc != r13->encoding())) {
// [base]
// [00 reg base]
emit_modrm(0, reg_enc, base_enc);
} else if (emit_compressed_disp_byte(disp) && no_relocation) {
// [base + disp8]
// [01 reg base] disp8
emit_modrm_disp8(0b01, reg_enc, base_enc,
disp);
} else {
// [base + disp32]
// [10 reg base] disp32
emit_modrm(0b10, reg_enc, base_enc);
emit_data(disp, rspec, disp32_operand);
}
}
} else {
if (is_valid_encoding(index_enc)) {
assert(scale != Address::no_scale, "inconsistent address");
// base == noreg
// [index*scale + disp]
// [00 reg 100][ss index 101] disp32
emit_modrm_sib(0b00, reg_enc, 0b100,
scale, index_enc, 0b101 /* no base */);
emit_data(disp, rspec, disp32_operand);
} else if (!no_relocation) {
// base == noreg, index == noreg
// [disp] (64bit) RIP-RELATIVE (32bit) abs
// [00 reg 101] disp32
emit_modrm(0b00, reg_enc, 0b101 /* no base */);
// Note that the RIP-rel. correction applies to the generated
// disp field, but _not_ to the target address in the rspec.
// disp was created by converting the target address minus the pc
// at the start of the instruction. That needs more correction here.
// intptr_t disp = target - next_ip;
assert(inst_mark() != NULL, "must be inside InstructionMark");
address next_ip = pc() + sizeof(int32_t) + post_addr_length;
int64_t adjusted = disp;
// Do rip-rel adjustment for 64bit
LP64_ONLY(adjusted -= (next_ip - inst_mark()));
assert(is_simm32(adjusted),
"must be 32bit offset (RIP relative address)");
emit_data((int32_t) adjusted, rspec, disp32_operand);
} else {
// base == noreg, index == noreg, no_relocation == true
// 32bit never did this, did everything as the rip-rel/disp code above
// [disp] ABSOLUTE
// [00 reg 100][00 100 101] disp32
emit_modrm_sib(0b00, reg_enc, 0b100 /* no base */,
Address::times_1, 0b100, 0b101);
emit_data(disp, rspec, disp32_operand);
}
}
}
void Assembler::emit_operand(Register reg, Register base, Register index,
Address::ScaleFactor scale, int disp,
RelocationHolder const& rspec,
int post_addr_length) {
assert(!index->is_valid() || index != rsp, "illegal addressing mode");
emit_operand_helper(raw_encode(reg), raw_encode(base), raw_encode(index),
scale, disp, rspec, post_addr_length);
}
void Assembler::emit_operand(XMMRegister xmmreg, Register base, Register index,
Address::ScaleFactor scale, int disp,
RelocationHolder const& rspec,
int post_addr_length) {
assert(!index->is_valid() || index != rsp, "illegal addressing mode");
assert(xmmreg->encoding() < 16 || UseAVX > 2, "not supported");
emit_operand_helper(raw_encode(xmmreg), raw_encode(base), raw_encode(index),
scale, disp, rspec, post_addr_length);
}
void Assembler::emit_operand(XMMRegister xmmreg, Register base, XMMRegister xmmindex,
Address::ScaleFactor scale, int disp,
RelocationHolder const& rspec,
int post_addr_length) {
assert(xmmreg->encoding() < 16 || UseAVX > 2, "not supported");
assert(xmmindex->encoding() < 16 || UseAVX > 2, "not supported");
emit_operand_helper(raw_encode(xmmreg), raw_encode(base), raw_encode(xmmindex),
scale, disp, rspec, post_addr_length);
}
void Assembler::emit_operand(KRegister kreg, Address adr,
int post_addr_length) {
emit_operand(kreg, adr._base, adr._index, adr._scale, adr._disp,
adr._rspec,
post_addr_length);
}
void Assembler::emit_operand(KRegister kreg, Register base, Register index,
Address::ScaleFactor scale, int disp,
RelocationHolder const& rspec,
int post_addr_length) {
assert(!index->is_valid() || index != rsp, "illegal addressing mode");
emit_operand_helper(raw_encode(kreg), raw_encode(base), raw_encode(index),
scale, disp, rspec, post_addr_length);
}
// Secret local extension to Assembler::WhichOperand:
#define end_pc_operand (_WhichOperand_limit)
address Assembler::locate_operand(address inst, WhichOperand which) {
// Decode the given instruction, and return the address of
// an embedded 32-bit operand word.
// If "which" is disp32_operand, selects the displacement portion
// of an effective address specifier.
// If "which" is imm64_operand, selects the trailing immediate constant.
// If "which" is call32_operand, selects the displacement of a call or jump.
// Caller is responsible for ensuring that there is such an operand,
// and that it is 32/64 bits wide.
// If "which" is end_pc_operand, find the end of the instruction.
address ip = inst;
bool is_64bit = false;
debug_only(bool has_disp32 = false);
int tail_size = 0; // other random bytes (#32, #16, etc.) at end of insn
again_after_prefix:
switch (0xFF & *ip++) {
// These convenience macros generate groups of "case" labels for the switch.
#define REP4(x) (x)+0: case (x)+1: case (x)+2: case (x)+3
#define REP8(x) (x)+0: case (x)+1: case (x)+2: case (x)+3: \
case (x)+4: case (x)+5: case (x)+6: case (x)+7
#define REP16(x) REP8((x)+0): \
case REP8((x)+8)
case CS_segment:
case SS_segment:
case DS_segment:
case ES_segment:
case FS_segment:
case GS_segment:
// Seems dubious
LP64_ONLY(assert(false, "shouldn't have that prefix"));
assert(ip == inst+1, "only one prefix allowed");
goto again_after_prefix;
case 0x67:
case REX:
case REX_B:
case REX_X:
case REX_XB:
case REX_R:
case REX_RB:
case REX_RX:
case REX_RXB:
NOT_LP64(assert(false, "64bit prefixes"));
goto again_after_prefix;
case REX_W:
case REX_WB:
case REX_WX:
case REX_WXB:
case REX_WR:
case REX_WRB:
case REX_WRX:
case REX_WRXB:
NOT_LP64(assert(false, "64bit prefixes"));
is_64bit = true;
goto again_after_prefix;
case 0xFF: // pushq a; decl a; incl a; call a; jmp a
case 0x88: // movb a, r
case 0x89: // movl a, r
case 0x8A: // movb r, a
case 0x8B: // movl r, a
case 0x8F: // popl a
debug_only(has_disp32 = true);
break;
case 0x68: // pushq #32
if (which == end_pc_operand) {
return ip + 4;
}
assert(which == imm_operand && !is_64bit, "pushl has no disp32 or 64bit immediate");
return ip; // not produced by emit_operand
case 0x66: // movw ... (size prefix)
again_after_size_prefix2:
switch (0xFF & *ip++) {
case REX:
case REX_B:
case REX_X:
case REX_XB:
case REX_R:
case REX_RB:
case REX_RX:
case REX_RXB:
case REX_W:
case REX_WB:
case REX_WX:
case REX_WXB:
case REX_WR:
case REX_WRB:
case REX_WRX:
case REX_WRXB:
NOT_LP64(assert(false, "64bit prefix found"));
goto again_after_size_prefix2;
case 0x8B: // movw r, a
case 0x89: // movw a, r
debug_only(has_disp32 = true);
break;
case 0xC7: // movw a, #16
debug_only(has_disp32 = true);
tail_size = 2; // the imm16
break;
case 0x0F: // several SSE/SSE2 variants
ip--; // reparse the 0x0F
goto again_after_prefix;
default:
ShouldNotReachHere();
}
break;
case REP8(0xB8): // movl/q r, #32/#64(oop?)
if (which == end_pc_operand) return ip + (is_64bit ? 8 : 4);
// these asserts are somewhat nonsensical
#ifndef _LP64
assert(which == imm_operand || which == disp32_operand,
"which %d is_64_bit %d ip " INTPTR_FORMAT, which, is_64bit, p2i(ip));
#else
assert((which == call32_operand || which == imm_operand) && is_64bit ||
which == narrow_oop_operand && !is_64bit,
"which %d is_64_bit %d ip " INTPTR_FORMAT, which, is_64bit, p2i(ip));
#endif // _LP64
return ip;
case 0x69: // imul r, a, #32
case 0xC7: // movl a, #32(oop?)
tail_size = 4;
debug_only(has_disp32 = true); // has both kinds of operands!
break;
case 0x0F: // movx..., etc.
switch (0xFF & *ip++) {
case 0x3A: // pcmpestri
tail_size = 1;
case 0x38: // ptest, pmovzxbw
ip++; // skip opcode
debug_only(has_disp32 = true); // has both kinds of operands!
break;
case 0x70: // pshufd r, r/a, #8
debug_only(has_disp32 = true); // has both kinds of operands!
case 0x73: // psrldq r, #8
tail_size = 1;
break;
case 0x10: // movups
case 0x11: // movups
case 0x12: // movlps
case 0x28: // movaps
case 0x2E: // ucomiss
case 0x2F: // comiss
case 0x54: // andps
case 0x55: // andnps
case 0x56: // orps
case 0x57: // xorps
case 0x58: // addpd
case 0x59: // mulpd
case 0x6E: // movd
case 0x7E: // movd
case 0x6F: // movdq
case 0x7F: // movdq
case 0xAE: // ldmxcsr, stmxcsr, fxrstor, fxsave, clflush
case 0xFE: // paddd
debug_only(has_disp32 = true);
break;
case 0xAD: // shrd r, a, %cl
case 0xAF: // imul r, a
case 0xBE: // movsbl r, a (movsxb)
case 0xBF: // movswl r, a (movsxw)
case 0xB6: // movzbl r, a (movzxb)
case 0xB7: // movzwl r, a (movzxw)
case REP16(0x40): // cmovl cc, r, a
case 0xB0: // cmpxchgb
case 0xB1: // cmpxchg
case 0xC1: // xaddl
case 0xC7: // cmpxchg8
case REP16(0x90): // setcc a
debug_only(has_disp32 = true);
// fall out of the switch to decode the address
break;
case 0xC4: // pinsrw r, a, #8
debug_only(has_disp32 = true);
case 0xC5: // pextrw r, r, #8
tail_size = 1; // the imm8
break;
case 0xAC: // shrd r, a, #8
debug_only(has_disp32 = true);
tail_size = 1; // the imm8
break;
case REP16(0x80): // jcc rdisp32
if (which == end_pc_operand) return ip + 4;
assert(which == call32_operand, "jcc has no disp32 or imm");
return ip;
default:
ShouldNotReachHere();
}
break;
case 0x81: // addl a, #32; addl r, #32
// also: orl, adcl, sbbl, andl, subl, xorl, cmpl
// on 32bit in the case of cmpl, the imm might be an oop
tail_size = 4;
debug_only(has_disp32 = true); // has both kinds of operands!
break;
case 0x83: // addl a, #8; addl r, #8
// also: orl, adcl, sbbl, andl, subl, xorl, cmpl
debug_only(has_disp32 = true); // has both kinds of operands!
tail_size = 1;
break;
case 0x15: // adc rax, #32
case 0x05: // add rax, #32
case 0x25: // and rax, #32
case 0x3D: // cmp rax, #32
case 0x0D: // or rax, #32
case 0x1D: // sbb rax, #32
case 0x2D: // sub rax, #32
case 0x35: // xor rax, #32
return which == end_pc_operand ? ip + 4 : ip;
case 0x9B:
switch (0xFF & *ip++) {
case 0xD9: // fnstcw a
debug_only(has_disp32 = true);
break;
default:
ShouldNotReachHere();
}
break;
case REP4(0x00): // addb a, r; addl a, r; addb r, a; addl r, a
case REP4(0x10): // adc...
case REP4(0x20): // and...
case REP4(0x30): // xor...
case REP4(0x08): // or...
case REP4(0x18): // sbb...
case REP4(0x28): // sub...
case 0xF7: // mull a
case 0x8D: // lea r, a
case 0x87: // xchg r, a
case REP4(0x38): // cmp...
case 0x85: // test r, a
debug_only(has_disp32 = true); // has both kinds of operands!
break;
case 0xA8: // testb rax, #8
return which == end_pc_operand ? ip + 1 : ip;
case 0xA9: // testl/testq rax, #32
return which == end_pc_operand ? ip + 4 : ip;
case 0xC1: // sal a, #8; sar a, #8; shl a, #8; shr a, #8
case 0xC6: // movb a, #8
case 0x80: // cmpb a, #8
case 0x6B: // imul r, a, #8
debug_only(has_disp32 = true); // has both kinds of operands!
tail_size = 1; // the imm8
break;
case 0xC4: // VEX_3bytes
case 0xC5: // VEX_2bytes
assert((UseAVX > 0), "shouldn't have VEX prefix");
assert(ip == inst+1, "no prefixes allowed");
// C4 and C5 are also used as opcodes for PINSRW and PEXTRW instructions
// but they have prefix 0x0F and processed when 0x0F processed above.
//
// In 32-bit mode the VEX first byte C4 and C5 alias onto LDS and LES
// instructions (these instructions are not supported in 64-bit mode).
// To distinguish them bits [7:6] are set in the VEX second byte since
// ModRM byte can not be of the form 11xxxxxx in 32-bit mode. To set
// those VEX bits REX and vvvv bits are inverted.
//
// Fortunately C2 doesn't generate these instructions so we don't need
// to check for them in product version.
// Check second byte
NOT_LP64(assert((0xC0 & *ip) == 0xC0, "shouldn't have LDS and LES instructions"));
int vex_opcode;
// First byte
if ((0xFF & *inst) == VEX_3bytes) {
vex_opcode = VEX_OPCODE_MASK & *ip;
ip++; // third byte
is_64bit = ((VEX_W & *ip) == VEX_W);
} else {
vex_opcode = VEX_OPCODE_0F;
}
ip++; // opcode
// To find the end of instruction (which == end_pc_operand).
switch (vex_opcode) {
case VEX_OPCODE_0F:
switch (0xFF & *ip) {
case 0x70: // pshufd r, r/a, #8
case 0x71: // ps[rl|ra|ll]w r, #8
case 0x72: // ps[rl|ra|ll]d r, #8
case 0x73: // ps[rl|ra|ll]q r, #8
case 0xC2: // cmp[ps|pd|ss|sd] r, r, r/a, #8
case 0xC4: // pinsrw r, r, r/a, #8
case 0xC5: // pextrw r/a, r, #8
case 0xC6: // shufp[s|d] r, r, r/a, #8
tail_size = 1; // the imm8
break;
}
break;
case VEX_OPCODE_0F_3A:
tail_size = 1;
break;
}
ip++; // skip opcode
debug_only(has_disp32 = true); // has both kinds of operands!
break;
case 0x62: // EVEX_4bytes
assert(VM_Version::supports_evex(), "shouldn't have EVEX prefix");
assert(ip == inst+1, "no prefixes allowed");
// no EVEX collisions, all instructions that have 0x62 opcodes
// have EVEX versions and are subopcodes of 0x66
ip++; // skip P0 and examine W in P1
is_64bit = ((VEX_W & *ip) == VEX_W);
ip++; // move to P2
ip++; // skip P2, move to opcode
// To find the end of instruction (which == end_pc_operand).
switch (0xFF & *ip) {
case 0x22: // pinsrd r, r/a, #8
case 0x61: // pcmpestri r, r/a, #8
case 0x70: // pshufd r, r/a, #8
case 0x73: // psrldq r, #8
case 0x1f: // evpcmpd/evpcmpq
case 0x3f: // evpcmpb/evpcmpw
tail_size = 1; // the imm8
break;
default:
break;
}
ip++; // skip opcode
debug_only(has_disp32 = true); // has both kinds of operands!
break;
case 0xD1: // sal a, 1; sar a, 1; shl a, 1; shr a, 1
case 0xD3: // sal a, %cl; sar a, %cl; shl a, %cl; shr a, %cl
case 0xD9: // fld_s a; fst_s a; fstp_s a; fldcw a
case 0xDD: // fld_d a; fst_d a; fstp_d a
case 0xDB: // fild_s a; fistp_s a; fld_x a; fstp_x a
case 0xDF: // fild_d a; fistp_d a
case 0xD8: // fadd_s a; fsubr_s a; fmul_s a; fdivr_s a; fcomp_s a
case 0xDC: // fadd_d a; fsubr_d a; fmul_d a; fdivr_d a; fcomp_d a
case 0xDE: // faddp_d a; fsubrp_d a; fmulp_d a; fdivrp_d a; fcompp_d a
debug_only(has_disp32 = true);
break;
case 0xE8: // call rdisp32
case 0xE9: // jmp rdisp32
if (which == end_pc_operand) return ip + 4;
assert(which == call32_operand, "call has no disp32 or imm");
return ip;
case 0xF0: // Lock
goto again_after_prefix;
case 0xF3: // For SSE
case 0xF2: // For SSE2
switch (0xFF & *ip++) {
case REX:
case REX_B:
case REX_X:
case REX_XB:
case REX_R:
case REX_RB:
case REX_RX:
case REX_RXB:
case REX_W:
case REX_WB:
case REX_WX:
case REX_WXB:
case REX_WR:
case REX_WRB:
case REX_WRX:
case REX_WRXB:
NOT_LP64(assert(false, "found 64bit prefix"));
ip++;
default:
ip++;
}
debug_only(has_disp32 = true); // has both kinds of operands!
break;
default:
ShouldNotReachHere();
#undef REP8
#undef REP16
}
assert(which != call32_operand, "instruction is not a call, jmp, or jcc");
#ifdef _LP64
assert(which != imm_operand, "instruction is not a movq reg, imm64");
#else
// assert(which != imm_operand || has_imm32, "instruction has no imm32 field");
assert(which != imm_operand || has_disp32, "instruction has no imm32 field");
#endif // LP64
assert(which != disp32_operand || has_disp32, "instruction has no disp32 field");
// parse the output of emit_operand
int op2 = 0xFF & *ip++;
int base = op2 & 0x07;
int op3 = -1;
const int b100 = 4;
const int b101 = 5;
if (base == b100 && (op2 >> 6) != 3) {
op3 = 0xFF & *ip++;
base = op3 & 0x07; // refetch the base
}
// now ip points at the disp (if any)
switch (op2 >> 6) {
case 0:
// [00 reg 100][ss index base]
// [00 reg 100][00 100 esp]
// [00 reg base]
// [00 reg 100][ss index 101][disp32]
// [00 reg 101] [disp32]
if (base == b101) {
if (which == disp32_operand)
return ip; // caller wants the disp32
ip += 4; // skip the disp32
}
break;
case 1:
// [01 reg 100][ss index base][disp8]
// [01 reg 100][00 100 esp][disp8]
// [01 reg base] [disp8]
ip += 1; // skip the disp8
break;
case 2:
// [10 reg 100][ss index base][disp32]
// [10 reg 100][00 100 esp][disp32]
// [10 reg base] [disp32]
if (which == disp32_operand)
return ip; // caller wants the disp32
ip += 4; // skip the disp32
break;
case 3:
// [11 reg base] (not a memory addressing mode)
break;
}
if (which == end_pc_operand) {
return ip + tail_size;
}
#ifdef _LP64
assert(which == narrow_oop_operand && !is_64bit, "instruction is not a movl adr, imm32");
#else
assert(which == imm_operand, "instruction has only an imm field");
#endif // LP64
return ip;
}
address Assembler::locate_next_instruction(address inst) {
// Secretly share code with locate_operand:
return locate_operand(inst, end_pc_operand);
}
#ifdef ASSERT
void Assembler::check_relocation(RelocationHolder const& rspec, int format) {
address inst = inst_mark();
assert(inst != NULL && inst < pc(), "must point to beginning of instruction");
address opnd;
Relocation* r = rspec.reloc();
if (r->type() == relocInfo::none) {
return;
} else if (r->is_call() || format == call32_operand) {
// assert(format == imm32_operand, "cannot specify a nonzero format");
opnd = locate_operand(inst, call32_operand);
} else if (r->is_data()) {
assert(format == imm_operand || format == disp32_operand
LP64_ONLY(|| format == narrow_oop_operand), "format ok");
opnd = locate_operand(inst, (WhichOperand)format);
} else {
assert(format == imm_operand, "cannot specify a format");
return;
}
assert(opnd == pc(), "must put operand where relocs can find it");
}
#endif // ASSERT
void Assembler::emit_operand(Register reg, Address adr, int post_addr_length) {
emit_operand(reg, adr._base, adr._index, adr._scale, adr._disp, adr._rspec, post_addr_length);
}
void Assembler::emit_operand(XMMRegister reg, Address adr, int post_addr_length) {
if (adr.isxmmindex()) {
emit_operand(reg, adr._base, adr._xmmindex, adr._scale, adr._disp, adr._rspec, post_addr_length);
} else {
emit_operand(reg, adr._base, adr._index, adr._scale, adr._disp, adr._rspec, post_addr_length);
}
}
// Now the Assembler instructions (identical for 32/64 bits)
void Assembler::adcl(Address dst, int32_t imm32) {
InstructionMark im(this);
prefix(dst);
emit_arith_operand(0x81, rdx, dst, imm32);
}
void Assembler::adcl(Address dst, Register src) {
InstructionMark im(this);
prefix(dst, src);
emit_int8(0x11);
emit_operand(src, dst, 0);
}
void Assembler::adcl(Register dst, int32_t imm32) {
prefix(dst);
emit_arith(0x81, 0xD0, dst, imm32);
}
void Assembler::adcl(Register dst, Address src) {
InstructionMark im(this);
prefix(src, dst);
emit_int8(0x13);
emit_operand(dst, src, 0);
}
void Assembler::adcl(Register dst, Register src) {
(void) prefix_and_encode(dst->encoding(), src->encoding());
emit_arith(0x13, 0xC0, dst, src);
}
void Assembler::addl(Address dst, int32_t imm32) {
InstructionMark im(this);
prefix(dst);
emit_arith_operand(0x81, rax, dst, imm32);
}
void Assembler::addb(Address dst, int imm8) {
InstructionMark im(this);
prefix(dst);
emit_int8((unsigned char)0x80);
emit_operand(rax, dst, 1);
emit_int8(imm8);
}
void Assembler::addw(Register dst, Register src) {
emit_int8(0x66);
(void)prefix_and_encode(dst->encoding(), src->encoding());
emit_arith(0x03, 0xC0, dst, src);
}
void Assembler::addw(Address dst, int imm16) {
InstructionMark im(this);
emit_int8(0x66);
prefix(dst);
emit_int8((unsigned char)0x81);
emit_operand(rax, dst, 2);
emit_int16(imm16);
}
void Assembler::addl(Address dst, Register src) {
InstructionMark im(this);
prefix(dst, src);
emit_int8(0x01);
emit_operand(src, dst, 0);
}
void Assembler::addl(Register dst, int32_t imm32) {
prefix(dst);
emit_arith(0x81, 0xC0, dst, imm32);
}
void Assembler::addl(Register dst, Address src) {
InstructionMark im(this);
prefix(src, dst);
emit_int8(0x03);
emit_operand(dst, src, 0);
}
void Assembler::addl(Register dst, Register src) {
(void) prefix_and_encode(dst->encoding(), src->encoding());
emit_arith(0x03, 0xC0, dst, src);
}
void Assembler::addr_nop_4() {
assert(UseAddressNop, "no CPU support");
// 4 bytes: NOP DWORD PTR [EAX+0]
emit_int32(0x0F,
0x1F,
0x40, // emit_rm(cbuf, 0x1, EAX_enc, EAX_enc);
0); // 8-bits offset (1 byte)
}
void Assembler::addr_nop_5() {
assert(UseAddressNop, "no CPU support");
// 5 bytes: NOP DWORD PTR [EAX+EAX*0+0] 8-bits offset
emit_int32(0x0F,
0x1F,
0x44, // emit_rm(cbuf, 0x1, EAX_enc, 0x4);
0x00); // emit_rm(cbuf, 0x0, EAX_enc, EAX_enc);
emit_int8(0); // 8-bits offset (1 byte)
}
void Assembler::addr_nop_7() {
assert(UseAddressNop, "no CPU support");
// 7 bytes: NOP DWORD PTR [EAX+0] 32-bits offset
emit_int24(0x0F,
0x1F,
(unsigned char)0x80);
// emit_rm(cbuf, 0x2, EAX_enc, EAX_enc);
emit_int32(0); // 32-bits offset (4 bytes)
}
void Assembler::addr_nop_8() {
assert(UseAddressNop, "no CPU support");
// 8 bytes: NOP DWORD PTR [EAX+EAX*0+0] 32-bits offset
emit_int32(0x0F,
0x1F,
(unsigned char)0x84,
// emit_rm(cbuf, 0x2, EAX_enc, 0x4);
0x00); // emit_rm(cbuf, 0x0, EAX_enc, EAX_enc);
emit_int32(0); // 32-bits offset (4 bytes)
}
void Assembler::addsd(XMMRegister dst, XMMRegister src) {
NOT_LP64(assert(VM_Version::supports_sse2(), ""));
InstructionAttr attributes(AVX_128bit, /* rex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
attributes.set_rex_vex_w_reverted();
int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_F2, VEX_OPCODE_0F, &attributes);
emit_int16(0x58, (0xC0 | encode));
}
void Assembler::addsd(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 */ false);
attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_64bit);
attributes.set_rex_vex_w_reverted();
simd_prefix(dst, dst, src, VEX_SIMD_F2, VEX_OPCODE_0F, &attributes);
emit_int8(0x58);
emit_operand(dst, src, 0);
}
void Assembler::addss(XMMRegister dst, XMMRegister src) {
NOT_LP64(assert(VM_Version::supports_sse(), ""));
InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_F3, VEX_OPCODE_0F, &attributes);
emit_int16(0x58, (0xC0 | encode));
}
void Assembler::addss(XMMRegister dst, Address src) {
NOT_LP64(assert(VM_Version::supports_sse(), ""));
InstructionMark im(this);
InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_32bit);
simd_prefix(dst, dst, src, VEX_SIMD_F3, VEX_OPCODE_0F, &attributes);
emit_int8(0x58);
emit_operand(dst, src, 0);
}
void Assembler::aesdec(XMMRegister dst, Address src) {
assert(VM_Version::supports_aes(), "");
InstructionMark im(this);
InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false);
simd_prefix(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes);
emit_int8((unsigned char)0xDE);
emit_operand(dst, src, 0);
}
void Assembler::aesdec(XMMRegister dst, XMMRegister src) {
assert(VM_Version::supports_aes(), "");
InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false);
int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes);
emit_int16((unsigned char)0xDE, (0xC0 | encode));
}
void Assembler::vaesdec(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) {
assert(VM_Version::supports_avx512_vaes(), "");
InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
attributes.set_is_evex_instruction();
int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes);
emit_int16((unsigned char)0xDE, (0xC0 | encode));
}
void Assembler::aesdeclast(XMMRegister dst, Address src) {
assert(VM_Version::supports_aes(), "");
InstructionMark im(this);
InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false);
simd_prefix(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes);
emit_int8((unsigned char)0xDF);
emit_operand(dst, src, 0);
}
void Assembler::aesdeclast(XMMRegister dst, XMMRegister src) {
assert(VM_Version::supports_aes(), "");
InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false);
int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes);
emit_int16((unsigned char)0xDF, (0xC0 | encode));
}
void Assembler::vaesdeclast(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) {
assert(VM_Version::supports_avx512_vaes(), "");
InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
attributes.set_is_evex_instruction();
int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes);
emit_int16((unsigned char)0xDF, (0xC0 | encode));
}
void Assembler::aesenc(XMMRegister dst, Address src) {
assert(VM_Version::supports_aes(), "");
InstructionMark im(this);
InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false);
simd_prefix(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes);
emit_int8((unsigned char)0xDC);
emit_operand(dst, src, 0);
}
void Assembler::aesenc(XMMRegister dst, XMMRegister src) {
assert(VM_Version::supports_aes(), "");
InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false);
int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes);
emit_int16((unsigned char)0xDC, 0xC0 | encode);
}
void Assembler::vaesenc(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) {
assert(VM_Version::supports_avx512_vaes(), "requires vaes support/enabling");
InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
attributes.set_is_evex_instruction();
int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes);
emit_int16((unsigned char)0xDC, (0xC0 | encode));
}
void Assembler::aesenclast(XMMRegister dst, Address src) {
assert(VM_Version::supports_aes(), "");
InstructionMark im(this);
InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false);
simd_prefix(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes);
emit_int8((unsigned char)0xDD);
emit_operand(dst, src, 0);
}
void Assembler::aesenclast(XMMRegister dst, XMMRegister src) {
assert(VM_Version::supports_aes(), "");
InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false);
int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes);
emit_int16((unsigned char)0xDD, (0xC0 | encode));
}
void Assembler::vaesenclast(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) {
assert(VM_Version::supports_avx512_vaes(), "requires vaes support/enabling");
InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
attributes.set_is_evex_instruction();
int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes);
emit_int16((unsigned char)0xDD, (0xC0 | encode));
}
void Assembler::andb(Address dst, Register src) {
InstructionMark im(this);
prefix(dst, src, true);
emit_int8(0x20);
emit_operand(src, dst, 0);
}
void Assembler::andw(Register dst, Register src) {
(void)prefix_and_encode(dst->encoding(), src->encoding());
emit_arith(0x23, 0xC0, dst, src);
}
void Assembler::andl(Address dst, int32_t imm32) {
InstructionMark im(this);
prefix(dst);
emit_arith_operand(0x81, as_Register(4), dst, imm32);
}
void Assembler::andl(Register dst, int32_t imm32) {
prefix(dst);
emit_arith(0x81, 0xE0, dst, imm32);
}
void Assembler::andl(Address dst, Register src) {
InstructionMark im(this);
prefix(dst, src);
emit_int8(0x21);
emit_operand(src, dst, 0);
}
void Assembler::andl(Register dst, Address src) {
InstructionMark im(this);
prefix(src, dst);
emit_int8(0x23);
emit_operand(dst, src, 0);
}
void Assembler::andl(Register dst, Register src) {
(void) prefix_and_encode(dst->encoding(), src->encoding());
emit_arith(0x23, 0xC0, dst, src);
}
void Assembler::andnl(Register dst, Register src1, Register src2) {
assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported");
InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false);
int encode = vex_prefix_and_encode(dst->encoding(), src1->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes);
emit_int16((unsigned char)0xF2, (0xC0 | encode));
}
void Assembler::andnl(Register dst, Register src1, Address src2) {
assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported");
InstructionMark im(this);
InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false);
vex_prefix(src2, src1->encoding(), dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes);
emit_int8((unsigned char)0xF2);
emit_operand(dst, src2, 0);
}
void Assembler::bsfl(Register dst, Register src) {
int encode = prefix_and_encode(dst->encoding(), src->encoding());
emit_int24(0x0F,
(unsigned char)0xBC,
0xC0 | encode);
}
void Assembler::bsrl(Register dst, Register src) {
int encode = prefix_and_encode(dst->encoding(), src->encoding());
emit_int24(0x0F,
(unsigned char)0xBD,
0xC0 | encode);
}
void Assembler::bswapl(Register reg) { // bswap
int encode = prefix_and_encode(reg->encoding());
emit_int16(0x0F, (0xC8 | encode));
}
void Assembler::blsil(Register dst, Register src) {
assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported");
InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false);
int encode = vex_prefix_and_encode(rbx->encoding(), dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes);
emit_int16((unsigned char)0xF3, (0xC0 | encode));
}
void Assembler::blsil(Register dst, Address src) {
assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported");
InstructionMark im(this);
InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false);
vex_prefix(src, dst->encoding(), rbx->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes);
emit_int8((unsigned char)0xF3);
emit_operand(rbx, src, 0);
}
void Assembler::blsmskl(Register dst, Register src) {
assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported");
InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false);
int encode = vex_prefix_and_encode(rdx->encoding(), dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes);
emit_int16((unsigned char)0xF3,
0xC0 | encode);
}
void Assembler::blsmskl(Register dst, Address src) {
assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported");
InstructionMark im(this);
InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false);
vex_prefix(src, dst->encoding(), rdx->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes);
emit_int8((unsigned char)0xF3);
emit_operand(rdx, src, 0);
}
void Assembler::blsrl(Register dst, Register src) {
assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported");
InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false);
int encode = vex_prefix_and_encode(rcx->encoding(), dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes);
emit_int16((unsigned char)0xF3, (0xC0 | encode));
}
void Assembler::blsrl(Register dst, Address src) {
assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported");
InstructionMark im(this);
InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false);
vex_prefix(src, dst->encoding(), rcx->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes);
emit_int8((unsigned char)0xF3);
emit_operand(rcx, src, 0);
}
void Assembler::call(Label& L, relocInfo::relocType rtype) {
// suspect disp32 is always good
int operand = LP64_ONLY(disp32_operand) NOT_LP64(imm_operand);
if (L.is_bound()) {
const int long_size = 5;
int offs = (int)( target(L) - pc() );
assert(offs <= 0, "assembler error");
InstructionMark im(this);
// 1110 1000 #32-bit disp
emit_int8((unsigned char)0xE8);
emit_data(offs - long_size, rtype, operand);
} else {
InstructionMark im(this);
// 1110 1000 #32-bit disp
L.add_patch_at(code(), locator());
emit_int8((unsigned char)0xE8);
emit_data(int(0), rtype, operand);
}
}
void Assembler::call(Register dst) {
int encode = prefix_and_encode(dst->encoding());
emit_int16((unsigned char)0xFF, (0xD0 | encode));
}
void Assembler::call(Address adr) {
InstructionMark im(this);
prefix(adr);
emit_int8((unsigned char)0xFF);
emit_operand(rdx, adr, 0);
}
void Assembler::call_literal(address entry, RelocationHolder const& rspec) {
InstructionMark im(this);
emit_int8((unsigned char)0xE8);
intptr_t disp = entry - (pc() + sizeof(int32_t));
// Entry is NULL in case of a scratch emit.
assert(entry == NULL || is_simm32(disp), "disp=" INTPTR_FORMAT " must be 32bit offset (call2)", disp);
// Technically, should use call32_operand, but this format is
// implied by the fact that we're emitting a call instruction.
int operand = LP64_ONLY(disp32_operand) NOT_LP64(call32_operand);
emit_data((int) disp, rspec, operand);
}
void Assembler::cdql() {
emit_int8((unsigned char)0x99);
}
void Assembler::cld() {
emit_int8((unsigned char)0xFC);
}
void Assembler::cmovl(Condition cc, Register dst, Register src) {
NOT_LP64(guarantee(VM_Version::supports_cmov(), "illegal instruction"));
int encode = prefix_and_encode(dst->encoding(), src->encoding());
emit_int24(0x0F,
0x40 | cc,
0xC0 | encode);
}
void Assembler::cmovl(Condition cc, Register dst, Address src) {
InstructionMark im(this);
NOT_LP64(guarantee(VM_Version::supports_cmov(), "illegal instruction"));
prefix(src, dst);
emit_int16(0x0F, (0x40 | cc));
emit_operand(dst, src, 0);
}
void Assembler::cmpb(Address dst, int imm8) {
InstructionMark im(this);
prefix(dst);
emit_int8((unsigned char)0x80);
emit_operand(rdi, dst, 1);
emit_int8(imm8);
}
void Assembler::cmpl(Address dst, int32_t imm32) {
InstructionMark im(this);
prefix(dst);
emit_arith_operand(0x81, as_Register(7), dst, imm32);
}
void Assembler::cmpl(Register dst, int32_t imm32) {
prefix(dst);
emit_arith(0x81, 0xF8, dst, imm32);
}
void Assembler::cmpl(Register dst, Register src) {
(void) prefix_and_encode(dst->encoding(), src->encoding());
emit_arith(0x3B, 0xC0, dst, src);
}
void Assembler::cmpl(Register dst, Address src) {
InstructionMark im(this);
prefix(src, dst);
emit_int8(0x3B);
emit_operand(dst, src, 0);
}
void Assembler::cmpl_imm32(Address dst, int32_t imm32) {
InstructionMark im(this);
prefix(dst);
emit_arith_operand_imm32(0x81, as_Register(7), dst, imm32);
}
void Assembler::cmpw(Address dst, int imm16) {
InstructionMark im(this);
assert(!dst.base_needs_rex() && !dst.index_needs_rex(), "no extended registers");
emit_int16(0x66, (unsigned char)0x81);
emit_operand(rdi, dst, 2);
emit_int16(imm16);
}
// The 32-bit cmpxchg compares the value at adr with the contents of rax,
// and stores reg into adr if so; otherwise, the value at adr is loaded into rax,.
// The ZF is set if the compared values were equal, and cleared otherwise.
void Assembler::cmpxchgl(Register reg, Address adr) { // cmpxchg
InstructionMark im(this);
prefix(adr, reg);
emit_int16(0x0F, (unsigned char)0xB1);
emit_operand(reg, adr, 0);
}
void Assembler::cmpxchgw(Register reg, Address adr) { // cmpxchg
InstructionMark im(this);
size_prefix();
prefix(adr, reg);
emit_int16(0x0F, (unsigned char)0xB1);
emit_operand(reg, adr, 0);
}
// The 8-bit cmpxchg compares the value at adr with the contents of rax,
// and stores reg into adr if so; otherwise, the value at adr is loaded into rax,.
// The ZF is set if the compared values were equal, and cleared otherwise.
void Assembler::cmpxchgb(Register reg, Address adr) { // cmpxchg
InstructionMark im(this);
prefix(adr, reg, true);
emit_int16(0x0F, (unsigned char)0xB0);
emit_operand(reg, adr, 0);
}
void Assembler::comisd(XMMRegister dst, Address src) {
// NOTE: dbx seems to decode this as comiss even though the
// 0x66 is there. Strangely ucomisd comes out correct
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 */ false);;
attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_64bit);
attributes.set_rex_vex_w_reverted();
simd_prefix(dst, xnoreg, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes);
emit_int8(0x2F);
emit_operand(dst, src, 0);
}
void Assembler::comisd(XMMRegister dst, XMMRegister src) {
NOT_LP64(assert(VM_Version::supports_sse2(), ""));
InstructionAttr attributes(AVX_128bit, /* rex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
attributes.set_rex_vex_w_reverted();
int encode = simd_prefix_and_encode(dst, xnoreg, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes);
emit_int16(0x2F, (0xC0 | encode));
}
void Assembler::comiss(XMMRegister dst, Address src) {
NOT_LP64(assert(VM_Version::supports_sse(), ""));
InstructionMark im(this);
InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_32bit);
simd_prefix(dst, xnoreg, src, VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes);
emit_int8(0x2F);
emit_operand(dst, src, 0);
}
void Assembler::comiss(XMMRegister dst, XMMRegister src) {
NOT_LP64(assert(VM_Version::supports_sse(), ""));
InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);
int encode = simd_prefix_and_encode(dst, xnoreg, src, VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes);
emit_int16(0x2F, (0xC0 | encode));
}
void Assembler::cpuid() {
emit_int16(0x0F, (unsigned char)0xA2);
}
// Opcode / Instruction Op / En 64 - Bit Mode Compat / Leg Mode Description Implemented
// F2 0F 38 F0 / r CRC32 r32, r / m8 RM Valid Valid Accumulate CRC32 on r / m8. v
// F2 REX 0F 38 F0 / r CRC32 r32, r / m8* RM Valid N.E. Accumulate CRC32 on r / m8. -
// F2 REX.W 0F 38 F0 / r CRC32 r64, r / m8 RM Valid N.E. Accumulate CRC32 on r / m8. -
//
// F2 0F 38 F1 / r CRC32 r32, r / m16 RM Valid Valid Accumulate CRC32 on r / m16. v
//
// F2 0F 38 F1 / r CRC32 r32, r / m32 RM Valid Valid Accumulate CRC32 on r / m32. v
//
// F2 REX.W 0F 38 F1 / r CRC32 r64, r / m64 RM Valid N.E. Accumulate CRC32 on r / m64. v
void Assembler::crc32(Register crc, Register v, int8_t sizeInBytes) {
assert(VM_Version::supports_sse4_2(), "");
int8_t w = 0x01;
Prefix p = Prefix_EMPTY;
emit_int8((unsigned char)0xF2);
switch (sizeInBytes) {
case 1:
w = 0;
break;
case 2:
case 4:
break;
LP64_ONLY(case 8:)
// This instruction is not valid in 32 bits
// Note:
// http://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf
//
// Page B - 72 Vol. 2C says
// qwreg2 to qwreg 1111 0010 : 0100 1R0B : 0000 1111 : 0011 1000 : 1111 0000 : 11 qwreg1 qwreg2
// mem64 to qwreg 1111 0010 : 0100 1R0B : 0000 1111 : 0011 1000 : 1111 0000 : mod qwreg r / m
// F0!!!
// while 3 - 208 Vol. 2A
// F2 REX.W 0F 38 F1 / r CRC32 r64, r / m64 RM Valid N.E.Accumulate CRC32 on r / m64.
//
// the 0 on a last bit is reserved for a different flavor of this instruction :
// F2 REX.W 0F 38 F0 / r CRC32 r64, r / m8 RM Valid N.E.Accumulate CRC32 on r / m8.
p = REX_W;
break;
default:
assert(0, "Unsupported value for a sizeInBytes argument");
break;
}
LP64_ONLY(prefix(crc, v, p);)
emit_int32(0x0F,
0x38,
0xF0 | w,
0xC0 | ((crc->encoding() & 0x7) << 3) | (v->encoding() & 7));
}
void Assembler::crc32(Register crc, Address adr, int8_t sizeInBytes) {
assert(VM_Version::supports_sse4_2(), "");
InstructionMark im(this);
int8_t w = 0x01;
Prefix p = Prefix_EMPTY;
emit_int8((int8_t)0xF2);
switch (sizeInBytes) {
case 1:
w = 0;
break;
case 2:
case 4:
break;
LP64_ONLY(case 8:)
// This instruction is not valid in 32 bits
p = REX_W;
break;
default:
assert(0, "Unsupported value for a sizeInBytes argument");
break;
--> --------------------
--> maximum size reached
--> --------------------
[ zur Elbe Produktseite wechseln0.240Quellennavigators
Analyse erneut starten
]
|
|