/* * 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. *
*/
#ifdef _LP64 // Symbolically name the register arguments used by the c calling convention. // Windows is different from linux/solaris. So much for standards...
// Symbolically name the register arguments used by the Java calling convention. // We have control over the convention for java so we can do what we please. // What pleases us is to offset the java calling convention so that when // we call a suitable jni method the arguments are lined up and we don't // have to do little shuffling. A suitable jni method is non-static and a // small number of arguments (two fewer args on windows) // // |-------------------------------------------------------| // | c_rarg0 c_rarg1 c_rarg2 c_rarg3 c_rarg4 c_rarg5 | // |-------------------------------------------------------| // | rcx rdx r8 r9 rdi* rsi* | windows (* not a c_rarg) // | rdi rsi rdx rcx r8 r9 | solaris/linux // |-------------------------------------------------------| // | j_rarg5 j_rarg0 j_rarg1 j_rarg2 j_rarg3 j_rarg4 | // |-------------------------------------------------------|
#else // rscratch1 will appear in 32bit code that is dead but of course must compile // Using noreg ensures if the dead code is incorrectly live and executed it // will cause an assertion failure #define rscratch1 noreg #define rscratch2 noreg
#endif// _LP64
// JSR 292 // On x86, the SP does not have to be saved when invoking method handle intrinsics // or compiled lambda forms. We indicate that by setting rbp_mh_SP_save to noreg.
constexpr Register rbp_mh_SP_save = noreg;
// Address is an abstraction used to represent a memory location // using any of the amd64 addressing modes with one object. // // Note: A register location is represented via a Register, not // via an address for efficiency & simplicity reasons.
// Easily misused constructors make them private // %%% can we make these go away?
NOT_LP64(Address(address loc, RelocationHolder spec);)
Address(int disp, address loc, relocInfo::relocType rtype);
Address(int disp, address loc, RelocationHolder spec);
// The following overloads are used in connection with the // ByteSize type (see sizes.hpp). They simplify the use of // ByteSize'd arguments in assembly code.
// 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. static Address make_raw(int base, int index, int scale, int disp, relocInfo::relocType disp_reloc);
// // AddressLiteral has been split out from Address because operands of this type // need to be treated specially on 32bit vs. 64bit platforms. By splitting it out // the few instructions that need to deal with address literals are unique and the // MacroAssembler does not have to implement every instruction in the Assembler // in order to search for address literals that may need special handling depending // on the instruction and the platform. As small step on the way to merging i486/amd64 // directories. // class AddressLiteral { friendclass ArrayAddress;
RelocationHolder _rspec; // Typically we use AddressLiterals we want to use their rval // However in some situations we want the lval (effect address) of the item. // We provide a special factory for making those lvals. bool _is_lval;
// If the target is far we'll need to load the ea of this to // a register to reach it. Otherwise if near we can do rip // relative addressing.
class ExternalAddress: public AddressLiteral { private: static relocInfo::relocType reloc_for_target(address target) { // Sometimes ExternalAddress is used for values which aren't // exactly addresses, like the card table base. // external_word_type can't be used for values in the first page // so just skip the reloc in that case. return external_word_Relocation::can_be_relocated(target) ? relocInfo::external_word_type : relocInfo::none;
}
// x86 can do array addressing as a single operation since disp can be an absolute // address amd64 can't. We create a class that expresses the concept but does extra // magic on amd64 to get the final result
// 64-bit reflect the fxsave size which is 512 bytes and the new xsave area on EVEX which is another 2176 bytes // See fxsave and xsave(EVEX enabled) documentation for layout constint FPUStateSizeInWords = NOT_LP64(27) LP64_ONLY(2688 / wordSize);
// The Intel x86/Amd64 Assembler: Pure assembler doing NO optimizations on the instruction // level (e.g. mov rax, 0 is not translated into xor rax, rax!); i.e., what you write // is what you get. The Assembler is generating code into a CodeBuffer.
class Assembler : public AbstractAssembler { friendclass AbstractAssembler; // for the non-virtual hack friendclass LIR_Assembler; // as_Address() friendclass StubGenerator;
// Comparison predicates for integral types & FP types when using SSE enum ComparisonPredicate {
eq = 0,
lt = 1,
le = 2,
_false = 3,
neq = 4,
nlt = 5,
nle = 6,
_true = 7
};
// Comparison predicates for FP types when using AVX // O means ordered. U is unordered. When using ordered, any NaN comparison is false. Otherwise, it is true. // S means signaling. Q means non-signaling. When signaling is true, instruction signals #IA on NaN. enum ComparisonPredicateFP {
EQ_OQ = 0,
LT_OS = 1,
LE_OS = 2,
UNORD_Q = 3,
NEQ_UQ = 4,
NLT_US = 5,
NLE_US = 6,
ORD_Q = 7,
EQ_UQ = 8,
NGE_US = 9,
NGT_US = 0xA,
FALSE_OQ = 0XB,
NEQ_OQ = 0xC,
GE_OS = 0xD,
GT_OS = 0xE,
TRUE_UQ = 0xF,
EQ_OS = 0x10,
LT_OQ = 0x11,
LE_OQ = 0x12,
UNORD_S = 0x13,
NEQ_US = 0x14,
NLT_UQ = 0x15,
NLE_UQ = 0x16,
ORD_S = 0x17,
EQ_US = 0x18,
NGE_UQ = 0x19,
NGT_UQ = 0x1A,
FALSE_OS = 0x1B,
NEQ_OS = 0x1C,
GE_OQ = 0x1D,
GT_OQ = 0x1E,
TRUE_US =0x1F
};
enum Width {
B = 0,
W = 1,
D = 2,
Q = 3
};
//---< calculate length of instruction >--- // As instruction size can't be found out easily on x86/x64, // we just use '4' for len and maxlen. // instruction must start at passed address staticunsignedint instr_len(unsignedchar *instr) { return 4; }
//---< longest instructions >--- // Max instruction length is not specified in architecture documentation. // We could use a "safe enough" estimate (15), but just default to // instruction length guess from above. staticunsignedint instr_maxlen() { return 4; }
// NOTE: The general philopsophy of the declarations here is that 64bit versions // of instructions are freely declared without the need for wrapping them an ifdef. // (Some dangerous instructions are ifdef's out of inappropriate jvm's.) // In the .cpp file the implementations are wrapped so that they are dropped out // of the resulting jvm. This is done mostly to keep the footprint of MINIMAL // to the size it was prior to merging up the 32bit and 64bit assemblers. // // This does mean you'll get a linker/runtime error if you use a 64bit only instruction // in a 32bit vm. This is somewhat unfortunate but keeps the ifdef noise down.
int prefix_and_encode(int reg_enc, bool byteinst = false); int prefix_and_encode(int dst_enc, int src_enc) { return prefix_and_encode(dst_enc, false, src_enc, false);
} int prefix_and_encode(int dst_enc, bool dst_is_byte, int src_enc, bool src_is_byte);
// Some prefixq variants always emit exactly one prefix byte, so besides a // prefix-emitting method we provide a method to get the prefix byte to emit, // which can then be folded into a byte stream.
int8_t get_prefixq(Address adr);
int8_t get_prefixq(Address adr, Register reg);
// Helper functions for groups of instructions void emit_arith_b(int op1, int op2, Register dst, int imm8);
void emit_arith(int op1, int op2, Register dst, int32_t imm32); // Force generation of a 4 byte immediate value even if it fits into 8bit void emit_arith_imm32(int op1, int op2, Register dst, int32_t imm32); void emit_arith(int op1, int op2, Register dst, Register src);
bool emit_compressed_disp_byte(int &disp);
void emit_modrm(int mod, int dst_enc, int src_enc); void emit_modrm_disp8(int mod, int dst_enc, int src_enc, int disp); void emit_modrm_sib(int mod, int dst_enc, int src_enc,
Address::ScaleFactor scale, int index_enc, int base_enc); void emit_modrm_sib_disp8(int mod, int dst_enc, int src_enc,
Address::ScaleFactor scale, int index_enc, int base_enc, int disp);
void emit_operand_helper(int reg_enc, int base_enc, int index_enc, Address::ScaleFactor scale, int disp,
RelocationHolder const& rspec, int post_addr_length);
void emit_operand(Register reg, Register base, Register index, Address::ScaleFactor scale, int disp,
RelocationHolder const& rspec, int post_addr_length);
void emit_operand(Register reg, Register base, XMMRegister index, Address::ScaleFactor scale, int disp,
RelocationHolder const& rspec, int post_addr_length);
void emit_operand(XMMRegister xreg, Register base, XMMRegister xindex, Address::ScaleFactor scale, int disp,
RelocationHolder const& rspec, int post_addr_length);
void emit_operand(Register reg, Address adr, int post_addr_length);
void emit_operand(XMMRegister reg, Register base, Register index, Address::ScaleFactor scale, int disp,
RelocationHolder const& rspec, int post_addr_length);
void emit_operand_helper(KRegister kreg, int base_enc, int index_enc, Address::ScaleFactor scale, int disp,
RelocationHolder const& rspec, int post_addr_length);
void emit_operand(KRegister kreg, Address adr, int post_addr_length);
void emit_operand(KRegister kreg, Register base, Register index, Address::ScaleFactor scale, int disp,
RelocationHolder const& rspec, int post_addr_length);
void emit_operand(XMMRegister reg, Address adr, int post_addr_length);
// These are all easily abused and hence protected
// 32BIT ONLY SECTION #ifndef _LP64 // Make these disappear in 64bit mode since they would never be correct void cmp_literal32(Register src1, int32_t imm32, RelocationHolder const& rspec); // 32BIT ONLY void cmp_literal32(Address src1, int32_t imm32, RelocationHolder const& rspec); // 32BIT ONLY
// These are unique in that we are ensured by the caller that the 32bit // relative in these instructions will always be able to reach the potentially // 64bit address described by entry. Since they can take a 64bit address they // don't have the 32 suffix like the other instructions in this class.
// Avoid using directly section // Instructions in this section are actually usable by anyone without danger // of failure but have performance issues that are addressed my enhanced // instructions which will do the proper thing base on the particular cpu. // We protect them because we don't trust you...
// Don't use next inc() and dec() methods directly. INC & DEC instructions // could cause a partial flag stall since they don't set CF flag. // Use MacroAssembler::decrement() & MacroAssembler::increment() methods // which call inc() & dec() or add() & sub() in accordance with // the product flag UseIncDec value.
// New cpus require use of movsd and movss to avoid partial register stall // when loading from memory. But for old Opteron use movlpd instead of movsd. // The selection is done in MacroAssembler::movdbl() and movflt().
// New cpus require use of movaps and movapd to avoid partial register stall // when moving between registers. void movaps(XMMRegister dst, XMMRegister src); void movapd(XMMRegister dst, XMMRegister src);
// Utilities staticbool 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);
// Generic instructions // Does 32bit or 64bit as needed for the platform. In some sense these // belong in macro assembler but there is no need for both varieties to exist
// Convert Packed Signed Doubleword Integers to Packed Double-Precision Floating-Point Value void cvtdq2pd(XMMRegister dst, XMMRegister src); void vcvtdq2pd(XMMRegister dst, XMMRegister src, int vector_len);
// Convert Halffloat to Single Precision Floating-Point value void vcvtps2ph(XMMRegister dst, XMMRegister src, int imm8, int vector_len); void vcvtph2ps(XMMRegister dst, XMMRegister src, int vector_len); void evcvtps2ph(Address dst, KRegister mask, XMMRegister src, int imm8, int vector_len); void vcvtps2ph(Address dst, XMMRegister src, int imm8, int vector_len); void vcvtph2ps(XMMRegister dst, Address src, int vector_len);
// Convert Packed Signed Doubleword Integers to Packed Single-Precision Floating-Point Value void cvtdq2ps(XMMRegister dst, XMMRegister src); void vcvtdq2ps(XMMRegister dst, XMMRegister src, int vector_len);
// Convert Scalar Single-Precision Floating-Point Value to Scalar Double-Precision Floating-Point Value void cvtss2sd(XMMRegister dst, XMMRegister src); void cvtss2sd(XMMRegister dst, Address src);
// Convert with Truncation Scalar Single-Precision Floating-Point Value to Doubleword Integer void cvttss2sil(Register dst, XMMRegister src); void cvttss2siq(Register dst, XMMRegister src); void cvtss2sil(Register dst, XMMRegister src);
// Convert vector double to int void cvttpd2dq(XMMRegister dst, XMMRegister src);
// Convert vector float and double void vcvtps2pd(XMMRegister dst, XMMRegister src, int vector_len); void vcvtpd2ps(XMMRegister dst, XMMRegister src, int vector_len);
// Convert vector float to int/long void vcvtps2dq(XMMRegister dst, XMMRegister src, int vector_len); void vcvttps2dq(XMMRegister dst, XMMRegister src, int vector_len); void evcvttps2qq(XMMRegister dst, XMMRegister src, int vector_len);
// Convert vector long to vector FP void evcvtqq2ps(XMMRegister dst, XMMRegister src, int vector_len); void evcvtqq2pd(XMMRegister dst, XMMRegister src, int vector_len);
// Convert vector double to long void evcvtpd2qq(XMMRegister dst, XMMRegister src, int vector_len); void evcvttpd2qq(XMMRegister dst, XMMRegister src, int vector_len);
// Convert vector double to int void vcvttpd2dq(XMMRegister dst, XMMRegister src, int vector_len);
// Evex casts with truncation void evpmovwb(XMMRegister dst, XMMRegister src, int vector_len); void evpmovdw(XMMRegister dst, XMMRegister src, int vector_len); void evpmovdb(XMMRegister dst, XMMRegister src, int vector_len); void evpmovqd(XMMRegister dst, XMMRegister src, int vector_len); void evpmovqb(XMMRegister dst, XMMRegister src, int vector_len); void evpmovqw(XMMRegister dst, XMMRegister src, int vector_len);
// Evex casts with signed saturation void evpmovsqd(XMMRegister dst, XMMRegister src, int vector_len);
//Abs of packed Integer values void pabsb(XMMRegister dst, XMMRegister src); void pabsw(XMMRegister dst, XMMRegister src); void pabsd(XMMRegister dst, XMMRegister src); void vpabsb(XMMRegister dst, XMMRegister src, int vector_len); void vpabsw(XMMRegister dst, XMMRegister src, int vector_len); void vpabsd(XMMRegister dst, XMMRegister src, int vector_len); void evpabsq(XMMRegister dst, XMMRegister src, int vector_len);
// jcc is the generic conditional branch generator to run- // time routines, jcc is used for branches to labels. jcc // takes a branch opcode (cc) and a label (L) and generates // either a backward branch or a forward branch and links it // to the label fixup chain. Usage: // // Label L; // unbound label // jcc(cc, L); // forward branch to unbound label // bind(L); // bind label to the current pc // jcc(cc, L); // backward branch to bound label // bind(L); // illegal: a label may be bound only once // // Note: The same Label can be used for forward and backward branches // but it may be bound only once.
// Conditional jump to a 8-bit offset to L. // WARNING: be very careful using this for forward jumps. If the label is // not bound within an 8-bit offset of this instruction, a run-time error // will occur.
// Use macro to record file and line number. #define jccb(cc, L) jccb_0(cc, L, __FILE__, __LINE__)
void jccb_0(Condition cc, Label& L, constchar* file, int line);
// Unconditional 8-bit offset jump to L. // WARNING: be very careful using this for forward jumps. If the label is // not bound within an 8-bit offset of this instruction, a run-time error // will occur.
// Use macro to record file and line number. #define jmpb(L) jmpb_0(L, __FILE__, __LINE__)
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.