aoqi@1: /* aoqi@1: * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. aoqi@1: * Copyright (c) 2015, 2016, Loongson Technology. All rights reserved. aoqi@1: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. aoqi@1: * aoqi@1: * This code is free software; you can redistribute it and/or modify it aoqi@1: * under the terms of the GNU General Public License version 2 only, as aoqi@1: * published by the Free Software Foundation. aoqi@1: * aoqi@1: * This code is distributed in the hope that it will be useful, but WITHOUT aoqi@1: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or aoqi@1: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License aoqi@1: * version 2 for more details (a copy is included in the LICENSE file that aoqi@1: * accompanied this code). aoqi@1: * aoqi@1: * You should have received a copy of the GNU General Public License version aoqi@1: * 2 along with this work; if not, write to the Free Software Foundation, aoqi@1: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. aoqi@1: * aoqi@1: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA aoqi@1: * or visit www.oracle.com if you need additional information or have any aoqi@1: * questions. aoqi@1: * aoqi@1: */ aoqi@1: aoqi@1: #ifndef CPU_MIPS_VM_ASSEMBLER_MIPS_HPP aoqi@1: #define CPU_MIPS_VM_ASSEMBLER_MIPS_HPP aoqi@1: aoqi@1: #include "asm/register.hpp" aoqi@1: aoqi@1: class BiasedLockingCounters; aoqi@1: aoqi@1: aoqi@1: // Note: A register location is represented via a Register, not aoqi@1: // via an address for efficiency & simplicity reasons. aoqi@1: aoqi@1: class ArrayAddress; aoqi@1: aoqi@1: class Address VALUE_OBJ_CLASS_SPEC { aoqi@1: aoqi@1: public: aoqi@1: enum ScaleFactor { aoqi@1: no_scale = -1, aoqi@1: times_1 = 0, aoqi@1: times_2 = 1, aoqi@1: times_4 = 2, aoqi@1: times_8 = 3, aoqi@1: times_ptr = LP64_ONLY(times_8) NOT_LP64(times_4) aoqi@1: }; aoqi@1: aoqi@1: static ScaleFactor times(int size) { aoqi@1: assert(size >= 1 && size <= 8 && is_power_of_2(size), "bad scale size"); aoqi@1: if (size == 8) return times_8; aoqi@1: if (size == 4) return times_4; aoqi@1: if (size == 2) return times_2; aoqi@1: return times_1; aoqi@1: } aoqi@1: aoqi@1: private: aoqi@1: Register _base; aoqi@1: Register _index; aoqi@1: ScaleFactor _scale; aoqi@1: int _disp; aoqi@1: RelocationHolder _rspec; aoqi@1: aoqi@1: // Easily misused constructors make them private aoqi@1: // %%% can we make these go away? aoqi@1: //FIXME aoqi aoqi@1: //NOT_LP64(Address(address loc, RelocationHolder spec);) aoqi@1: Address(address loc, RelocationHolder spec); aoqi@1: Address(int disp, address loc, relocInfo::relocType rtype); aoqi@1: Address(int disp, address loc, RelocationHolder spec); aoqi@1: aoqi@1: public: aoqi@1: aoqi@1: int disp() { return _disp; } aoqi@1: // creation aoqi@1: Address() aoqi@1: : _base(noreg), aoqi@1: _index(noreg), aoqi@1: _scale(no_scale), aoqi@1: _disp(0) { aoqi@1: } aoqi@1: aoqi@1: // No default displacement otherwise Register can be implicitly aoqi@1: // converted to 0(Register) which is quite a different animal. aoqi@1: aoqi@1: Address(Register base, int disp) aoqi@1: : _base(base), aoqi@1: _index(noreg), aoqi@1: _scale(no_scale), aoqi@1: _disp(disp) { aoqi@1: } aoqi@1: aoqi@1: Address(Register base) aoqi@1: : _base(base), aoqi@1: _index(noreg), aoqi@1: _scale(no_scale), aoqi@1: _disp(0) { aoqi@1: } aoqi@1: aoqi@1: Address(Register base, Register index, ScaleFactor scale, int disp = 0) aoqi@1: : _base (base), aoqi@1: _index(index), aoqi@1: _scale(scale), aoqi@1: _disp (disp) { aoqi@1: assert(!index->is_valid() == (scale == Address::no_scale), aoqi@1: "inconsistent address"); aoqi@1: } aoqi@1: aoqi@1: // The following two overloads are used in connection with the aoqi@1: // ByteSize type (see sizes.hpp). They simplify the use of aoqi@1: // ByteSize'd arguments in assembly code. Note that their equivalent aoqi@1: // for the optimized build are the member functions with int disp aoqi@1: // argument since ByteSize is mapped to an int type in that case. aoqi@1: // aoqi@1: // Note: DO NOT introduce similar overloaded functions for WordSize aoqi@1: // arguments as in the optimized mode, both ByteSize and WordSize aoqi@1: // are mapped to the same type and thus the compiler cannot make a aoqi@1: // distinction anymore (=> compiler errors). aoqi@1: aoqi@1: #ifdef ASSERT aoqi@1: Address(Register base, ByteSize disp) aoqi@1: : _base(base), aoqi@1: _index(noreg), aoqi@1: _scale(no_scale), aoqi@1: _disp(in_bytes(disp)) { aoqi@1: } aoqi@1: aoqi@1: Address(Register base, Register index, ScaleFactor scale, ByteSize disp) aoqi@1: : _base(base), aoqi@1: _index(index), aoqi@1: _scale(scale), aoqi@1: _disp(in_bytes(disp)) { aoqi@1: assert(!index->is_valid() == (scale == Address::no_scale), aoqi@1: "inconsistent address"); aoqi@1: } aoqi@1: #endif // ASSERT aoqi@1: aoqi@1: // accessors aoqi@1: bool uses(Register reg) const { return _base == reg || _index == reg; } aoqi@1: Register base() const { return _base; } aoqi@1: Register index() const { return _index; } aoqi@1: ScaleFactor scale() const { return _scale; } aoqi@1: int disp() const { return _disp; } aoqi@1: aoqi@1: // Convert the raw encoding form into the form expected by the constructor for aoqi@1: // Address. An index of 4 (rsp) corresponds to having no index, so convert aoqi@1: // that to noreg for the Address constructor. aoqi@1: //static Address make_raw(int base, int index, int scale, int disp); aoqi@1: aoqi@1: static Address make_array(ArrayAddress); aoqi@1: aoqi@1: /* aoqi@1: private: aoqi@1: bool base_needs_rex() const { aoqi@1: return _base != noreg && _base->encoding() >= 8; aoqi@1: } aoqi@1: aoqi@1: bool index_needs_rex() const { aoqi@1: return _index != noreg &&_index->encoding() >= 8; aoqi@1: } aoqi@1: aoqi@1: relocInfo::relocType reloc() const { return _rspec.type(); } aoqi@1: */ aoqi@1: friend class Assembler; aoqi@1: friend class MacroAssembler; aoqi@1: friend class LIR_Assembler; // base/index/scale/disp aoqi@1: }; aoqi@1: aoqi@1: aoqi@1: // Calling convention aoqi@1: class Argument VALUE_OBJ_CLASS_SPEC { aoqi@1: private: aoqi@1: int _number; aoqi@1: public: aoqi@1: enum { aoqi@1: #ifdef _LP64 aoqi@1: n_register_parameters = 8, // 8 integer registers used to pass parameters aoqi@1: n_float_register_parameters = 8 // 4 float registers used to pass parameters aoqi@1: #else aoqi@1: n_register_parameters = 4, // 4 integer registers used to pass parameters aoqi@1: n_float_register_parameters = 4 // 4 float registers used to pass parameters aoqi@1: #endif aoqi@1: }; aoqi@1: aoqi@1: Argument(int number):_number(number){ } aoqi@1: Argument successor() {return Argument(number() + 1);} aoqi@1: aoqi@1: int number()const {return _number;} aoqi@1: bool is_Register()const {return _number < n_register_parameters;} aoqi@1: bool is_FloatRegister()const {return _number < n_float_register_parameters;} aoqi@1: aoqi@1: Register as_Register()const { aoqi@1: assert(is_Register(), "must be a register argument"); aoqi@1: return ::as_Register(A0->encoding() + _number); aoqi@1: } aoqi@1: FloatRegister as_FloatRegister()const { aoqi@1: assert(is_FloatRegister(), "must be a float register argument"); aoqi@1: return ::as_FloatRegister(F12->encoding() + _number); aoqi@1: } aoqi@1: aoqi@1: Address as_caller_address()const {return Address(SP, (number() LP64_ONLY( -n_register_parameters)) * wordSize);} aoqi@1: }; aoqi@1: aoqi@1: aoqi@1: aoqi@1: // aoqi@1: // AddressLiteral has been split out from Address because operands of this type aoqi@1: // need to be treated specially on 32bit vs. 64bit platforms. By splitting it out aoqi@1: // the few instructions that need to deal with address literals are unique and the aoqi@1: // MacroAssembler does not have to implement every instruction in the Assembler aoqi@1: // in order to search for address literals that may need special handling depending aoqi@1: // on the instruction and the platform. As small step on the way to merging i486/amd64 aoqi@1: // directories. aoqi@1: // aoqi@1: class AddressLiteral VALUE_OBJ_CLASS_SPEC { aoqi@1: friend class ArrayAddress; aoqi@1: RelocationHolder _rspec; aoqi@1: // Typically we use AddressLiterals we want to use their rval aoqi@1: // However in some situations we want the lval (effect address) of the item. aoqi@1: // We provide a special factory for making those lvals. aoqi@1: bool _is_lval; aoqi@1: aoqi@1: // If the target is far we'll need to load the ea of this to aoqi@1: // a register to reach it. Otherwise if near we can do rip aoqi@1: // relative addressing. aoqi@1: aoqi@1: address _target; aoqi@1: aoqi@1: protected: aoqi@1: // creation aoqi@1: AddressLiteral() aoqi@1: : _is_lval(false), aoqi@1: _target(NULL) aoqi@1: {} aoqi@1: aoqi@1: public: aoqi@1: aoqi@1: AddressLiteral(address target, relocInfo::relocType rtype); aoqi@1: aoqi@1: AddressLiteral(address target, RelocationHolder const& rspec) aoqi@1: : _rspec(rspec), aoqi@1: _is_lval(false), aoqi@1: _target(target) aoqi@1: {} aoqi@1: #ifdef _LP64 aoqi@1: // 32-bit complains about a multiple declaration for int*. aoqi@1: AddressLiteral(intptr_t* addr, relocInfo::relocType rtype = relocInfo::none) aoqi@1: : _target((address) addr), aoqi@1: _rspec(rspec_from_rtype(rtype, (address) addr)) {} aoqi@1: #endif aoqi@1: aoqi@1: aoqi@1: AddressLiteral addr() { aoqi@1: AddressLiteral ret = *this; aoqi@1: ret._is_lval = true; aoqi@1: return ret; aoqi@1: } aoqi@1: aoqi@1: aoqi@1: private: aoqi@1: aoqi@1: address target() { return _target; } aoqi@1: bool is_lval() { return _is_lval; } aoqi@1: aoqi@1: relocInfo::relocType reloc() const { return _rspec.type(); } aoqi@1: const RelocationHolder& rspec() const { return _rspec; } aoqi@1: aoqi@1: friend class Assembler; aoqi@1: friend class MacroAssembler; aoqi@1: friend class Address; aoqi@1: friend class LIR_Assembler; aoqi@1: RelocationHolder rspec_from_rtype(relocInfo::relocType rtype, address addr) { aoqi@1: switch (rtype) { aoqi@1: case relocInfo::external_word_type: aoqi@1: return external_word_Relocation::spec(addr); aoqi@1: case relocInfo::internal_word_type: aoqi@1: return internal_word_Relocation::spec(addr); aoqi@1: case relocInfo::opt_virtual_call_type: aoqi@1: return opt_virtual_call_Relocation::spec(); aoqi@1: case relocInfo::static_call_type: aoqi@1: return static_call_Relocation::spec(); aoqi@1: case relocInfo::runtime_call_type: aoqi@1: return runtime_call_Relocation::spec(); aoqi@1: case relocInfo::poll_type: aoqi@1: case relocInfo::poll_return_type: aoqi@1: return Relocation::spec_simple(rtype); aoqi@1: case relocInfo::none: aoqi@1: case relocInfo::oop_type: aoqi@1: // Oops are a special case. Normally they would be their own section aoqi@1: // but in cases like icBuffer they are literals in the code stream that aoqi@1: // we don't have a section for. We use none so that we get a literal address aoqi@1: // which is always patchable. aoqi@1: return RelocationHolder(); aoqi@1: default: aoqi@1: ShouldNotReachHere(); aoqi@1: return RelocationHolder(); aoqi@1: } aoqi@1: } aoqi@1: aoqi@1: }; aoqi@1: aoqi@1: // Convience classes aoqi@1: class RuntimeAddress: public AddressLiteral { aoqi@1: aoqi@1: public: aoqi@1: aoqi@1: RuntimeAddress(address target) : AddressLiteral(target, relocInfo::runtime_call_type) {} aoqi@1: aoqi@1: }; aoqi@1: aoqi@1: class OopAddress: public AddressLiteral { aoqi@1: aoqi@1: public: aoqi@1: aoqi@1: OopAddress(address target) : AddressLiteral(target, relocInfo::oop_type){} aoqi@1: aoqi@1: }; aoqi@1: aoqi@1: class ExternalAddress: public AddressLiteral { aoqi@1: aoqi@1: public: aoqi@1: aoqi@1: ExternalAddress(address target) : AddressLiteral(target, relocInfo::external_word_type){} aoqi@1: aoqi@1: }; aoqi@1: aoqi@1: class InternalAddress: public AddressLiteral { aoqi@1: aoqi@1: public: aoqi@1: aoqi@1: InternalAddress(address target) : AddressLiteral(target, relocInfo::internal_word_type) {} aoqi@1: aoqi@1: }; aoqi@1: aoqi@1: // x86 can do array addressing as a single operation since disp can be an absolute aoqi@1: // address amd64 can't. We create a class that expresses the concept but does extra aoqi@1: // magic on amd64 to get the final result aoqi@1: aoqi@1: class ArrayAddress VALUE_OBJ_CLASS_SPEC { aoqi@1: private: aoqi@1: aoqi@1: AddressLiteral _base; aoqi@1: Address _index; aoqi@1: aoqi@1: public: aoqi@1: aoqi@1: ArrayAddress() {}; aoqi@1: ArrayAddress(AddressLiteral base, Address index): _base(base), _index(index) {}; aoqi@1: AddressLiteral base() { return _base; } aoqi@1: Address index() { return _index; } aoqi@1: aoqi@1: }; aoqi@1: aoqi@1: const int FPUStateSizeInWords = NOT_LP64(27) LP64_ONLY( 512 / wordSize); aoqi@1: aoqi@1: // The MIPS LOONGSON Assembler: Pure assembler doing NO optimizations on the instruction aoqi@1: // level ; i.e., what you write is what you get. The Assembler is generating code into aoqi@1: // a CodeBuffer. aoqi@1: aoqi@1: class Assembler : public AbstractAssembler { aoqi@1: friend class AbstractAssembler; // for the non-virtual hack aoqi@1: friend class LIR_Assembler; // as_Address() aoqi@1: friend class StubGenerator; aoqi@1: aoqi@1: public: aoqi@1: enum ops { aoqi@1: special_op = 0x00, aoqi@1: regimm_op = 0x01, aoqi@1: j_op = 0x02, aoqi@1: jal_op = 0x03, aoqi@1: beq_op = 0x04, aoqi@1: bne_op = 0x05, aoqi@1: blez_op = 0x06, aoqi@1: bgtz_op = 0x07, aoqi@1: addi_op = 0x08, aoqi@1: addiu_op = 0x09, aoqi@1: slti_op = 0x0a, aoqi@1: sltiu_op = 0x0b, aoqi@1: andi_op = 0x0c, aoqi@1: ori_op = 0x0d, aoqi@1: xori_op = 0x0e, aoqi@1: lui_op = 0x0f, aoqi@1: cop0_op = 0x10, aoqi@1: cop1_op = 0x11, aoqi@1: cop2_op = 0x12, aoqi@1: cop3_op = 0x13, aoqi@1: beql_op = 0x14, aoqi@1: bnel_op = 0x15, aoqi@1: blezl_op = 0x16, aoqi@1: bgtzl_op = 0x17, aoqi@1: daddi_op = 0x18, aoqi@1: daddiu_op = 0x19, aoqi@1: ldl_op = 0x1a, aoqi@1: ldr_op = 0x1b, aoqi@1: lb_op = 0x20, aoqi@1: lh_op = 0x21, aoqi@1: lwl_op = 0x22, aoqi@1: lw_op = 0x23, aoqi@1: lbu_op = 0x24, aoqi@1: lhu_op = 0x25, aoqi@1: lwr_op = 0x26, aoqi@1: lwu_op = 0x27, aoqi@1: sb_op = 0x28, aoqi@1: sh_op = 0x29, aoqi@1: swl_op = 0x2a, aoqi@1: sw_op = 0x2b, aoqi@1: sdl_op = 0x2c, aoqi@1: sdr_op = 0x2d, aoqi@1: swr_op = 0x2e, aoqi@1: cache_op = 0x2f, aoqi@1: ll_op = 0x30, aoqi@1: lwc1_op = 0x31, aoqi@1: lld_op = 0x34, aoqi@1: ldc1_op = 0x35, aoqi@1: ld_op = 0x37, aoqi@1: sc_op = 0x38, aoqi@1: swc1_op = 0x39, aoqi@1: scd_op = 0x3c, aoqi@1: sdc1_op = 0x3d, aoqi@1: sd_op = 0x3f aoqi@1: }; aoqi@1: aoqi@1: static const char *ops_name[]; aoqi@1: aoqi@1: //special family, the opcode is in low 6 bits. aoqi@1: enum special_ops { aoqi@1: sll_op = 0x00, aoqi@1: srl_op = 0x02, aoqi@1: sra_op = 0x03, aoqi@1: sllv_op = 0x04, aoqi@1: srlv_op = 0x06, aoqi@1: srav_op = 0x07, aoqi@1: jr_op = 0x08, aoqi@1: jalr_op = 0x09, aoqi@1: syscall_op = 0x0c, aoqi@1: break_op = 0x0d, aoqi@1: sync_op = 0x0f, aoqi@1: mfhi_op = 0x10, aoqi@1: mthi_op = 0x11, aoqi@1: mflo_op = 0x12, aoqi@1: mtlo_op = 0x13, aoqi@1: dsllv_op = 0x14, aoqi@1: dsrlv_op = 0x16, aoqi@1: dsrav_op = 0x17, aoqi@1: mult_op = 0x18, aoqi@1: multu_op = 0x19, aoqi@1: div_op = 0x1a, aoqi@1: divu_op = 0x1b, aoqi@1: dmult_op = 0x1c, aoqi@1: dmultu_op = 0x1d, aoqi@1: ddiv_op = 0x1e, aoqi@1: ddivu_op = 0x1f, aoqi@1: add_op = 0x20, aoqi@1: addu_op = 0x21, aoqi@1: sub_op = 0x22, aoqi@1: subu_op = 0x23, aoqi@1: and_op = 0x24, aoqi@1: or_op = 0x25, aoqi@1: xor_op = 0x26, aoqi@1: nor_op = 0x27, aoqi@1: slt_op = 0x2a, aoqi@1: sltu_op = 0x2b, aoqi@1: dadd_op = 0x2c, aoqi@1: daddu_op = 0x2d, aoqi@1: dsub_op = 0x2e, aoqi@1: dsubu_op = 0x2f, aoqi@1: tge_op = 0x30, aoqi@1: tgeu_op = 0x31, aoqi@1: tlt_op = 0x32, aoqi@1: tltu_op = 0x33, aoqi@1: teq_op = 0x34, aoqi@1: tne_op = 0x36, aoqi@1: dsll_op = 0x38, aoqi@1: dsrl_op = 0x3a, aoqi@1: dsra_op = 0x3b, aoqi@1: dsll32_op = 0x3c, aoqi@1: dsrl32_op = 0x3e, aoqi@1: dsra32_op = 0x3f aoqi@1: }; aoqi@1: aoqi@1: static const char* special_name[]; aoqi@1: aoqi@1: //regimm family, the opcode is in rt[16...20], 5 bits aoqi@1: enum regimm_ops { aoqi@1: bltz_op = 0x00, aoqi@1: bgez_op = 0x01, aoqi@1: bltzl_op = 0x02, aoqi@1: bgezl_op = 0x03, aoqi@1: tgei_op = 0x08, aoqi@1: tgeiu_op = 0x09, aoqi@1: tlti_op = 0x0a, aoqi@1: tltiu_op = 0x0b, aoqi@1: teqi_op = 0x0c, aoqi@1: tnei_op = 0x0e, aoqi@1: bltzal_op = 0x10, aoqi@1: bgezal_op = 0x11, aoqi@1: bltzall_op = 0x12, aoqi@1: bgezall_op = 0x13, aoqi@1: }; aoqi@1: aoqi@1: static const char* regimm_name[]; aoqi@1: aoqi@1: //copx family,the op in rs, 5 bits aoqi@1: enum cop_ops { aoqi@1: mf_op = 0x00, aoqi@1: dmf_op = 0x01, aoqi@1: cf_op = 0x02, aoqi@1: mt_op = 0x04, aoqi@1: dmt_op = 0x05, aoqi@1: ct_op = 0x06, aoqi@1: bc_op = 0x08, aoqi@1: single_fmt = 0x10, aoqi@1: double_fmt = 0x11, aoqi@1: word_fmt = 0x14, aoqi@1: long_fmt = 0x15 aoqi@1: }; aoqi@1: aoqi@1: enum bc_ops { aoqi@1: bcf_op = 0x00, aoqi@1: bct_op = 0x01, aoqi@1: bcfl_op = 0x02, aoqi@1: bctl_op = 0x03, aoqi@1: }; aoqi@1: aoqi@1: enum c_conds { aoqi@1: f_cond = 0x30, aoqi@1: un_cond = 0x31, aoqi@1: eq_cond = 0x32, aoqi@1: ueq_cond = 0x33, aoqi@1: olt_cond = 0x34, aoqi@1: ult_cond = 0x35, aoqi@1: ole_cond = 0x36, aoqi@1: ule_cond = 0x37, aoqi@1: sf_cond = 0x38, aoqi@1: ngle_cond = 0x39, aoqi@1: seq_cond = 0x3a, aoqi@1: ngl_cond = 0x3b, aoqi@1: lt_cond = 0x3c, aoqi@1: nge_cond = 0x3d, aoqi@1: le_cond = 0x3e, aoqi@1: ngt_cond = 0x3f aoqi@1: }; aoqi@1: aoqi@1: //low 6 bits of cp1 instruction aoqi@1: enum float_ops { aoqi@1: fadd_op = 0x00, aoqi@1: fsub_op = 0x01, aoqi@1: fmul_op = 0x02, aoqi@1: fdiv_op = 0x03, aoqi@1: fsqrt_op = 0x04, aoqi@1: fabs_op = 0x05, aoqi@1: fmov_op = 0x06, aoqi@1: fneg_op = 0x07, aoqi@1: froundl_op = 0x08, aoqi@1: ftruncl_op = 0x09, aoqi@1: fceill_op = 0x0a, aoqi@1: ffloorl_op = 0x0b, aoqi@1: froundw_op = 0x0c, aoqi@1: ftruncw_op = 0x0d, aoqi@1: fceilw_op = 0x0e, aoqi@1: ffloorw_op = 0x0f, aoqi@1: fcvts_op = 0x20, aoqi@1: fcvtd_op = 0x21, aoqi@1: fcvtw_op = 0x24, aoqi@1: fcvtl_op = 0x25, aoqi@1: fpll_op =0x2c, aoqi@1: fplu_op =0x2d, aoqi@1: fpul_op =0x2e, aoqi@1: fpuu_op =0x2f, aoqi@1: aoqi@1: }; aoqi@1: aoqi@1: /* 2013.10.16 Jin: merge from OpenJDK 8 */ aoqi@1: enum WhichOperand { aoqi@1: // input to locate_operand, and format code for relocations aoqi@1: imm_operand = 0, // embedded 32-bit|64-bit immediate operand aoqi@1: disp32_operand = 1, // embedded 32-bit displacement or address aoqi@1: call32_operand = 2, // embedded 32-bit self-relative displacement aoqi@1: #ifndef _LP64 aoqi@1: _WhichOperand_limit = 3 aoqi@1: #else aoqi@1: narrow_oop_operand = 3, // embedded 32-bit immediate narrow oop aoqi@1: _WhichOperand_limit = 4 aoqi@1: #endif aoqi@1: }; aoqi@1: aoqi@1: /* Godson3 extension */ aoqi@1: enum godson3_ops { aoqi@1: gsldx_op = (0x36 << 26) | 0x3, aoqi@1: gslwx_op = (0x36 << 26) | 0x2, aoqi@1: }; aoqi@1: aoqi@1: static const char* float_name[]; aoqi@1: aoqi@1: static int opcode(int insn) { return (insn>>26)&0x3f; } aoqi@1: static int rs(int insn) { return (insn>>21)&0x1f; } aoqi@1: static int rt(int insn) { return (insn>>16)&0x1f; } aoqi@1: static int rd(int insn) { return (insn>>11)&0x1f; } aoqi@1: static int sa(int insn) { return (insn>>6)&0x1f; } aoqi@1: static int special(int insn) { return insn&0x3f; } aoqi@1: static int imm_off(int insn) { return (short)low16(insn); } aoqi@1: aoqi@1: static int low (int x, int l) { return bitfield(x, 0, l); } aoqi@1: static int low16(int x) { return low(x, 16); } aoqi@1: static int low26(int x) { return low(x, 26); } aoqi@1: aoqi@1: protected: aoqi@1: //help methods for instruction ejection aoqi@1: aoqi@1: //I-Type (Immediate) aoqi@1: // 31 26 25 21 20 16 15 0 aoqi@1: //| opcode | rs | rt | immediat | aoqi@1: //| | | | | aoqi@1: // 6 5 5 16 aoqi@1: static int insn_ORRI(int op, int rs, int rt, int imm) { return (op<<26) | (rs<<21) | (rt<<16) | low16(imm); } aoqi@1: aoqi@1: //R-Type (Register) aoqi@1: // 31 26 25 21 20 16 15 11 10 6 5 0 aoqi@1: //| special | rs | rt | rd | 0 | opcode | aoqi@1: //| 0 0 0 0 0 0 | | | | 0 0 0 0 0 | | aoqi@1: // 6 5 5 5 5 6 aoqi@1: static int insn_RRRO(int rs, int rt, int rd, int op) { return (rs<<21) | (rt<<16) | (rd<<11) | op; } aoqi@1: static int insn_RRSO(int rt, int rd, int sa, int op) { return (rt<<16) | (rd<<11) | (sa<<6) | op; } aoqi@1: static int insn_RRCO(int rs, int rt, int code, int op) { return (rs<<21) | (rt<<16) | (code<<6) | op; } aoqi@1: aoqi@1: static int insn_COP0(int op, int rt, int rd) { return (cop0_op<<26) | (op<<21) | (rt<<16) | (rd<<11); } aoqi@1: static int insn_COP1(int op, int rt, int fs) { return (cop1_op<<26) | (op<<21) | (rt<<16) | (fs<<11); } aoqi@1: aoqi@1: static int insn_F3RO(int fmt, int ft, int fs, int fd, int func) { aoqi@1: return (cop1_op<<26) | (fmt<<21) | (ft<<16) | (fs<<11) | (fd<<6) | func; aoqi@1: } aoqi@1: aoqi@1: aoqi@1: //static int low (int x, int l) { return bitfield(x, 0, l); } aoqi@1: //static int low16(int x) { return low(x, 16); } aoqi@1: //static int low26(int x) { return low(x, 26); } aoqi@1: aoqi@1: static int high (int x, int l) { return bitfield(x, 32-l, l); } aoqi@1: static int high16(int x) { return high(x, 16); } aoqi@1: static int high6 (int x) { return high(x, 6); } aoqi@1: aoqi@1: //get the offset field of jump/branch instruction aoqi@1: int offset(address entry) { aoqi@1: assert(is_simm16((entry - pc() - 4) / 4), "change this code"); aoqi@1: if (!is_simm16((entry - pc() - 4) / 4)) { aoqi@1: tty->print_cr("!!! is_simm16: %x", (entry - pc() - 4) / 4); aoqi@1: } aoqi@1: return (entry - pc() - 4) / 4; aoqi@1: } aoqi@1: aoqi@1: aoqi@1: public: aoqi@1: using AbstractAssembler::offset; aoqi@1: aoqi@1: //sign expand with the sign bit is h aoqi@1: static int expand(int x, int h) { return -(x & (1<> 16) + ((x & 0x8000) != 0) ) & 0xffff; aoqi@1: } aoqi@1: aoqi@1: static int merge(int low, int high) { aoqi@1: return expand(low, 15) + (high<<16); aoqi@1: } aoqi@1: aoqi@1: #ifdef _LP64 aoqi@1: static intptr_t merge(intptr_t x0, intptr_t x16, intptr_t x32, intptr_t x48) { aoqi@1: return (x48 << 48) | (x32 << 32) | (x16 << 16) | x0; aoqi@1: /* aoqi@1: return ((intptr_t)(long_at(0) & 0xffff) << 48) aoqi@1: + expand((intptr_t)(long_at(4) & 0xffff) << 32, 47) aoqi@1: + expand((intptr_t)(long_at(12) & 0xffff) << 16, 31) aoqi@1: + expand((intptr_t)(long_at(20) & 0xffff), 15); aoqi@1: return expand(low, 15) + (high<<16); aoqi@1: */ aoqi@1: } aoqi@1: #endif aoqi@1: aoqi@1: // modified by spark 2005/08/18 aoqi@1: static bool is_simm (int x, int nbits) { return -( 1 << nbits-1 ) <= x && x < ( 1 << nbits-1 ); } aoqi@1: static bool is_simm16(int x) { return is_simm(x, 16); } aoqi@1: aoqi@1: // test if imm can be coded in a instruction with 16-bit imm/off aoqi@1: // by yjl 6/23/2005 aoqi@1: /*static bool fit_in_insn(int imm) { aoqi@1: return imm == (short)imm; aoqi@1: }*/ aoqi@1: aoqi@1: static bool fit_in_jal(int offset) { aoqi@1: return is_simm(offset, 26); aoqi@1: } aoqi@1: aoqi@1: aoqi@1: // test if entry can be filled in the jl/jal, aoqi@1: // must be used just before you emit jl/jal aoqi@1: // by yjl 6/27/2005 aoqi@1: bool fit_int_jal(address entry) { aoqi@1: return fit_in_jal(offset(entry)); aoqi@1: } aoqi@1: aoqi@1: bool fit_int_branch(address entry) { aoqi@1: return is_simm16(offset(entry)); aoqi@1: } aoqi@1: aoqi@1: protected: aoqi@1: #ifdef ASSERT aoqi@1: #define CHECK_DELAY aoqi@1: #endif aoqi@1: #ifdef CHECK_DELAY aoqi@1: enum Delay_state { no_delay, at_delay_slot, filling_delay_slot } delay_state; aoqi@1: #endif aoqi@1: aoqi@1: public: aoqi@1: void assert_not_delayed() { aoqi@1: #ifdef CHECK_DELAY aoqi@1: assert_not_delayed("next instruction should not be a delay slot"); aoqi@1: #endif aoqi@1: } aoqi@1: aoqi@1: void assert_not_delayed(const char* msg) { aoqi@1: #ifdef CHECK_DELAY aoqi@1: //guarantee( delay_state == no_delay, msg ); aoqi@1: //aoqi_test aoqi@1: if(delay_state != no_delay){ aoqi@1: tty->print_cr("%s:%d, pc: %lx", __func__, __LINE__, pc()); aoqi@1: } aoqi@1: assert(delay_state == no_delay, msg); aoqi@1: #endif aoqi@1: } aoqi@1: aoqi@1: protected: aoqi@1: // Delay slot helpers aoqi@1: // cti is called when emitting control-transfer instruction, aoqi@1: // BEFORE doing the emitting. aoqi@1: // Only effective when assertion-checking is enabled. aoqi@1: aoqi@1: // called when emitting cti with a delay slot, AFTER emitting aoqi@1: void has_delay_slot() { aoqi@1: #ifdef CHECK_DELAY aoqi@1: assert_not_delayed("just checking"); aoqi@1: delay_state = at_delay_slot; aoqi@1: #endif aoqi@1: } aoqi@1: aoqi@1: public: aoqi@1: Assembler* delayed() { aoqi@1: #ifdef CHECK_DELAY aoqi@1: guarantee( delay_state == at_delay_slot, "delayed instructition is not in delay slot"); aoqi@1: delay_state = filling_delay_slot; aoqi@1: #endif aoqi@1: return this; aoqi@1: } aoqi@1: aoqi@1: void flush() { aoqi@1: #ifdef CHECK_DELAY aoqi@1: guarantee( delay_state == no_delay, "ending code with a delay slot"); aoqi@1: #endif aoqi@1: AbstractAssembler::flush(); aoqi@1: } aoqi@1: aoqi@1: inline void emit_long(int); // shadows AbstractAssembler::emit_long aoqi@1: inline void emit_data(int x) { emit_long(x); } aoqi@1: inline void emit_data(int, RelocationHolder const&); aoqi@1: inline void emit_data(int, relocInfo::relocType rtype); aoqi@1: inline void check_delay(); aoqi@1: aoqi@1: aoqi@1: // Generic instructions aoqi@1: // Does 32bit or 64bit as needed for the platform. In some sense these aoqi@1: // belong in macro assembler but there is no need for both varieties to exist aoqi@1: aoqi@1: #ifndef _LP64 aoqi@1: void add(Register rd, Register rs, Register rt) { emit_long(insn_RRRO((int)rs->encoding(), (int)rt->encoding(), (int)rd->encoding(), add_op)); } aoqi@1: void addi(Register rt, Register rs, int imm) { emit_long(insn_ORRI(addi_op, (int)rs->encoding(), (int)rt->encoding(), imm)); } aoqi@1: void addiu(Register rt, Register rs, int imm) { emit_long(insn_ORRI(addiu_op, (int)rs->encoding(), (int)rt->encoding(), imm)); } aoqi@1: void addu(Register rd, Register rs, Register rt) { emit_long(insn_RRRO((int)rs->encoding(), (int)rt->encoding(), (int)rd->encoding(), addu_op)); } aoqi@1: #else aoqi@1: void add(Register rd, Register rs, Register rt) { dadd (rd, rs, rt); } aoqi@1: void add32(Register rd, Register rs, Register rt) { emit_long(insn_RRRO((int)rs->encoding(), (int)rt->encoding(), (int)rd->encoding(), add_op)); } aoqi@1: void addu32(Register rd, Register rs, Register rt) { emit_long(insn_RRRO((int)rs->encoding(), (int)rt->encoding(), (int)rd->encoding(), addu_op)); } aoqi@1: void addiu32(Register rt, Register rs, int imm) { emit_long(insn_ORRI(addiu_op, (int)rs->encoding(), (int)rt->encoding(), imm)); } aoqi@1: void addi(Register rt, Register rs, int imm) { daddi (rt, rs, imm);} aoqi@1: void addiu(Register rt, Register rs, int imm) { daddiu (rt, rs, imm);} aoqi@1: void addu(Register rd, Register rs, Register rt) { daddu (rd, rs, rt); } aoqi@1: #endif aoqi@1: aoqi@1: void andr(Register rd, Register rs, Register rt) { emit_long(insn_RRRO((int)rs->encoding(), (int)rt->encoding(), (int)rd->encoding(), and_op)); } aoqi@1: void andi(Register rt, Register rs, int imm) { emit_long(insn_ORRI(andi_op, (int)rs->encoding(), (int)rt->encoding(), imm)); } aoqi@1: aoqi@1: void beq (Register rs, Register rt, int off) { emit_long(insn_ORRI(beq_op, (int)rs->encoding(), (int)rt->encoding(), off)); has_delay_slot(); } aoqi@1: void beql (Register rs, Register rt, int off) { emit_long(insn_ORRI(beql_op, (int)rs->encoding(), (int)rt->encoding(), off)); has_delay_slot(); } aoqi@1: void bgez (Register rs, int off) { emit_long(insn_ORRI(regimm_op, (int)rs->encoding(), bgez_op, off)); has_delay_slot(); } aoqi@1: void bgezal (Register rs, int off) { emit_long(insn_ORRI(regimm_op, (int)rs->encoding(), bgezal_op, off)); has_delay_slot(); } aoqi@1: void bgezall(Register rs, int off) { emit_long(insn_ORRI(regimm_op, (int)rs->encoding(), bgezall_op, off)); has_delay_slot(); } aoqi@1: void bgezl (Register rs, int off) { emit_long(insn_ORRI(regimm_op, (int)rs->encoding(), bgezl_op, off)); has_delay_slot(); } aoqi@1: void bgtz (Register rs, int off) { emit_long(insn_ORRI(bgtz_op, (int)rs->encoding(), 0, off)); has_delay_slot(); } aoqi@1: void bgtzl (Register rs, int off) { emit_long(insn_ORRI(bgtzl_op, (int)rs->encoding(), 0, off)); has_delay_slot(); } aoqi@1: void blez (Register rs, int off) { emit_long(insn_ORRI(blez_op, (int)rs->encoding(), 0, off)); has_delay_slot(); } aoqi@1: void blezl (Register rs, int off) { emit_long(insn_ORRI(blezl_op, (int)rs->encoding(), 0, off)); has_delay_slot(); } aoqi@1: void bltz (Register rs, int off) { emit_long(insn_ORRI(regimm_op, (int)rs->encoding(), bltz_op, off)); has_delay_slot(); } aoqi@1: void bltzal (Register rs, int off) { emit_long(insn_ORRI(regimm_op, (int)rs->encoding(), bltzal_op, off)); has_delay_slot(); } aoqi@1: void bltzall(Register rs, int off) { emit_long(insn_ORRI(regimm_op, (int)rs->encoding(), bltzall_op, off)); has_delay_slot(); } aoqi@1: void bltzl (Register rs, int off) { emit_long(insn_ORRI(regimm_op, (int)rs->encoding(), bltzl_op, off)); has_delay_slot(); } aoqi@1: void bne (Register rs, Register rt, int off) { emit_long(insn_ORRI(bne_op, (int)rs->encoding(), (int)rt->encoding(), off)); has_delay_slot(); } aoqi@1: void bnel (Register rs, Register rt, int off) { emit_long(insn_ORRI(bnel_op, (int)rs->encoding(), (int)rt->encoding(), off)); has_delay_slot(); } aoqi@1: void brk (int code) { emit_long(break_op | (code<<16)); } aoqi@1: aoqi@1: void beq (Register rs, Register rt, address entry) { beq(rs, rt, offset(entry)); } aoqi@1: void beql (Register rs, Register rt, address entry) { beql(rs, rt, offset(entry));} aoqi@1: void bgez (Register rs, address entry) { bgez (rs, offset(entry)); } aoqi@1: void bgezal (Register rs, address entry) { bgezal (rs, offset(entry)); } aoqi@1: void bgezall(Register rs, address entry) { bgezall(rs, offset(entry)); } aoqi@1: void bgezl (Register rs, address entry) { bgezl (rs, offset(entry)); } aoqi@1: void bgtz (Register rs, address entry) { bgtz (rs, offset(entry)); } aoqi@1: void bgtzl (Register rs, address entry) { bgtzl (rs, offset(entry)); } aoqi@1: void blez (Register rs, address entry) { blez (rs, offset(entry)); } aoqi@1: void blezl (Register rs, address entry) { blezl (rs, offset(entry)); } aoqi@1: void bltz (Register rs, address entry) { bltz (rs, offset(entry)); } aoqi@1: void bltzal (Register rs, address entry) { bltzal (rs, offset(entry)); } aoqi@1: void bltzall(Register rs, address entry) { bltzall(rs, offset(entry)); } aoqi@1: void bltzl (Register rs, address entry) { bltzl (rs, offset(entry)); } aoqi@1: void bne (Register rs, Register rt, address entry) { bne(rs, rt, offset(entry)); } aoqi@1: void bnel (Register rs, Register rt, address entry) { bnel(rs, rt, offset(entry)); } aoqi@1: aoqi@1: void beq (Register rs, Register rt, Label& L) { beq(rs, rt, target(L)); } aoqi@1: void beql (Register rs, Register rt, Label& L) { beql(rs, rt, target(L)); } aoqi@1: void bgez (Register rs, Label& L){ bgez (rs, target(L)); } aoqi@1: void bgezal (Register rs, Label& L){ bgezal (rs, target(L)); } aoqi@1: void bgezall(Register rs, Label& L){ bgezall(rs, target(L)); } aoqi@1: void bgezl (Register rs, Label& L){ bgezl (rs, target(L)); } aoqi@1: void bgtz (Register rs, Label& L){ bgtz (rs, target(L)); } aoqi@1: void bgtzl (Register rs, Label& L){ bgtzl (rs, target(L)); } aoqi@1: void blez (Register rs, Label& L){ blez (rs, target(L)); } aoqi@1: void blezl (Register rs, Label& L){ blezl (rs, target(L)); } aoqi@1: void bltz (Register rs, Label& L){ bltz (rs, target(L)); } aoqi@1: void bltzal (Register rs, Label& L){ bltzal (rs, target(L)); } aoqi@1: void bltzall(Register rs, Label& L){ bltzall(rs, target(L)); } aoqi@1: void bltzl (Register rs, Label& L){ bltzl (rs, target(L)); } aoqi@1: void bne (Register rs, Register rt, Label& L){ bne(rs, rt, target(L)); } aoqi@1: void bnel (Register rs, Register rt, Label& L){ bnel(rs, rt, target(L)); } aoqi@1: aoqi@1: void dadd (Register rd, Register rs, Register rt) { emit_long(insn_RRRO((int)rs->encoding(), (int)rt->encoding(), (int)rd->encoding(), dadd_op)); } aoqi@1: void daddi (Register rt, Register rs, int imm) { emit_long(insn_ORRI(daddi_op, (int)rs->encoding(), (int)rt->encoding(), imm)); } aoqi@1: void daddiu(Register rt, Register rs, int imm) { emit_long(insn_ORRI(daddiu_op, (int)rs->encoding(), (int)rt->encoding(), imm)); } aoqi@1: void daddu (Register rd, Register rs, Register rt) { emit_long(insn_RRRO((int)rs->encoding(), (int)rt->encoding(), (int)rd->encoding(), daddu_op)); } aoqi@1: void ddiv (Register rs, Register rt) { emit_long(insn_RRRO((int)rs->encoding(), (int)rt->encoding(), 0, ddiv_op)); } aoqi@1: void ddivu (Register rs, Register rt) { emit_long(insn_RRRO((int)rs->encoding(), (int)rt->encoding(), 0, ddivu_op)); } aoqi@1: // Do mult and div need both 32-bit and 64-bit version? FIXME aoqi aoqi@1: //#ifndef _LP64 aoqi@1: #if 1 aoqi@1: void div (Register rs, Register rt) { emit_long(insn_RRRO((int)rs->encoding(), (int)rt->encoding(), 0, div_op)); } aoqi@1: void divu (Register rs, Register rt) { emit_long(insn_RRRO((int)rs->encoding(), (int)rt->encoding(), 0, divu_op)); } aoqi@1: #else aoqi@1: void div (Register rs, Register rt) { ddiv (rs, rt);} aoqi@1: void divu (Register rs, Register rt) { ddivu(rs, rt);} aoqi@1: #endif aoqi@1: void dmfc0 (Register rt, FloatRegister rd) { emit_long(insn_COP0(dmf_op, (int)rt->encoding(), (int)rd->encoding())); } aoqi@1: void dmtc0 (Register rt, FloatRegister rd) { emit_long(insn_COP0(dmt_op, (int)rt->encoding(), (int)rd->encoding())); } aoqi@1: void dmult (Register rs, Register rt) { emit_long(insn_RRRO((int)rs->encoding(), (int)rt->encoding(), 0, dmult_op)); } aoqi@1: void dmultu(Register rs, Register rt) { emit_long(insn_RRRO((int)rs->encoding(), (int)rt->encoding(), 0, dmultu_op)); } aoqi@1: void dsll (Register rd, Register rt , int sa) { emit_long(insn_RRSO((int)rt->encoding(), (int)rd->encoding(), sa, dsll_op)); } aoqi@1: void dsllv (Register rd, Register rt, Register rs) { emit_long(insn_RRRO((int)rs->encoding(), (int)rt->encoding(), (int)rd->encoding(), dsllv_op)); } aoqi@1: void dsll32(Register rd, Register rt , int sa) { emit_long(insn_RRSO((int)rt->encoding(), (int)rd->encoding(), sa, dsll32_op)); } aoqi@1: void dsra (Register rd, Register rt , int sa) { emit_long(insn_RRSO((int)rt->encoding(), (int)rd->encoding(), sa, dsra_op)); } aoqi@1: void dsrav (Register rd, Register rt, Register rs) { emit_long(insn_RRRO((int)rs->encoding(), (int)rt->encoding(), (int)rd->encoding(), dsrav_op)); } aoqi@1: void dsra32(Register rd, Register rt , int sa) { emit_long(insn_RRSO((int)rt->encoding(), (int)rd->encoding(), sa, dsra32_op)); } aoqi@1: void dsrl (Register rd, Register rt , int sa) { emit_long(insn_RRSO((int)rt->encoding(), (int)rd->encoding(), sa, dsrl_op)); } aoqi@1: void dsrlv (Register rd, Register rt, Register rs) { emit_long(insn_RRRO((int)rs->encoding(), (int)rt->encoding(), (int)rd->encoding(), dsrlv_op)); } aoqi@1: void dsrl32(Register rd, Register rt , int sa) { emit_long(insn_RRSO((int)rt->encoding(), (int)rd->encoding(), sa, dsrl32_op)); } aoqi@1: void dsub (Register rd, Register rs, Register rt) { emit_long(insn_RRRO((int)rs->encoding(), (int)rt->encoding(), (int)rd->encoding(), dsub_op)); } aoqi@1: void dsubu (Register rd, Register rs, Register rt) { emit_long(insn_RRRO((int)rs->encoding(), (int)rt->encoding(), (int)rd->encoding(), dsubu_op)); } aoqi@1: aoqi@1: void b(int off) { beq(R0, R0, off); } aoqi@1: void b(address entry) { b(offset(entry)); } aoqi@1: void b(Label& L) { b(target(L)); } aoqi@1: aoqi@1: void j(address entry); aoqi@1: void jal(address entry); aoqi@1: aoqi@1: void jalr(Register rd, Register rs) { emit_long( ((int)rs->encoding()<<21) | ((int)rd->encoding()<<11) | jalr_op); has_delay_slot(); } aoqi@1: void jalr(Register rs) { jalr(RA, rs); } aoqi@1: void jalr() { jalr(T9); } aoqi@1: aoqi@1: void jr(Register rs) { emit_long(((int)rs->encoding()<<21) | jr_op); has_delay_slot(); } aoqi@1: aoqi@1: void lb (Register rt, Register base, int off) { emit_long(insn_ORRI(lb_op, (int)base->encoding(), (int)rt->encoding(), off)); } aoqi@1: void lbu(Register rt, Register base, int off) { emit_long(insn_ORRI(lbu_op, (int)base->encoding(), (int)rt->encoding(), off)); } aoqi@1: void ld (Register rt, Register base, int off) { emit_long(insn_ORRI(ld_op, (int)base->encoding(), (int)rt->encoding(), off)); } aoqi@1: void ldl(Register rt, Register base, int off) { emit_long(insn_ORRI(ldl_op, (int)base->encoding(), (int)rt->encoding(), off)); } aoqi@1: void ldr(Register rt, Register base, int off) { emit_long(insn_ORRI(ldr_op, (int)base->encoding(), (int)rt->encoding(), off)); } aoqi@1: void lh (Register rt, Register base, int off) { emit_long(insn_ORRI(lh_op, (int)base->encoding(), (int)rt->encoding(), off)); } aoqi@1: void lhu(Register rt, Register base, int off) { emit_long(insn_ORRI(lhu_op, (int)base->encoding(), (int)rt->encoding(), off)); } aoqi@1: void ll (Register rt, Register base, int off) { emit_long(insn_ORRI(ll_op, (int)base->encoding(), (int)rt->encoding(), off)); } aoqi@1: void lld(Register rt, Register base, int off) { emit_long(insn_ORRI(lld_op, (int)base->encoding(), (int)rt->encoding(), off)); } aoqi@1: void lui(Register rt, int imm) { emit_long(insn_ORRI(lui_op, 0, (int)rt->encoding(), imm)); } aoqi@1: void lw (Register rt, Register base, int off) { emit_long(insn_ORRI(lw_op, (int)base->encoding(), (int)rt->encoding(), off)); } aoqi@1: void lwl(Register rt, Register base, int off) { emit_long(insn_ORRI(lwl_op, (int)base->encoding(), (int)rt->encoding(), off)); } aoqi@1: void lwr(Register rt, Register base, int off) { emit_long(insn_ORRI(lwr_op, (int)base->encoding(), (int)rt->encoding(), off)); } aoqi@1: void lwu(Register rt, Register base, int off) { emit_long(insn_ORRI(lwu_op, (int)base->encoding(), (int)rt->encoding(), off)); } aoqi@1: aoqi@1: void lb (Register rt, Address src); aoqi@1: void lbu(Register rt, Address src); aoqi@1: void ld (Register rt, Address src); aoqi@1: void ldl(Register rt, Address src); aoqi@1: void ldr(Register rt, Address src); aoqi@1: void lh (Register rt, Address src); aoqi@1: void lhu(Register rt, Address src); aoqi@1: void ll (Register rt, Address src); aoqi@1: void lld(Register rt, Address src); aoqi@1: void lw (Register rt, Address src); aoqi@1: void lwl(Register rt, Address src); aoqi@1: void lwr(Register rt, Address src); aoqi@1: void lwu(Register rt, Address src); aoqi@1: void lea(Register rt, Address src); aoqi@1: aoqi@1: void mfc0 (Register rt, Register rd) { emit_long(insn_COP0(mf_op, (int)rt->encoding(), (int)rd->encoding())); } aoqi@1: void mfhi (Register rd) { emit_long( ((int)rd->encoding()<<11) | mfhi_op ); } aoqi@1: void mflo (Register rd) { emit_long( ((int)rd->encoding()<<11) | mflo_op ); } aoqi@1: void mtc0 (Register rt, Register rd) { emit_long(insn_COP0(mt_op, (int)rt->encoding(), (int)rd->encoding())); } aoqi@1: void mthi (Register rs) { emit_long( ((int)rs->encoding()<<21) | mthi_op ); } aoqi@1: void mtlo (Register rs) { emit_long( ((int)rs->encoding()<<21) | mtlo_op ); } aoqi@1: // Do mult and div need both 32-bit and 64-bit version? FIXME aoqi aoqi@1: //#ifndef _LP64 aoqi@1: #if 1 aoqi@1: void mult (Register rs, Register rt) { emit_long(insn_RRRO((int)rs->encoding(), (int)rt->encoding(), 0, mult_op)); } aoqi@1: void multu(Register rs, Register rt) { emit_long(insn_RRRO((int)rs->encoding(), (int)rt->encoding(), 0, multu_op)); } aoqi@1: #else aoqi@1: void mult (Register rs, Register rt) { dmult (rs, rt); } aoqi@1: void multu(Register rs, Register rt) { dmultu (rs, rt); } aoqi@1: #endif aoqi@1: aoqi@1: void nor(Register rd, Register rs, Register rt) { emit_long(insn_RRRO((int)rs->encoding(), (int)rt->encoding(), (int)rd->encoding(), nor_op)); } aoqi@1: aoqi@1: void orr(Register rd, Register rs, Register rt) { emit_long(insn_RRRO((int)rs->encoding(), (int)rt->encoding(), (int)rd->encoding(), or_op)); } aoqi@1: void ori(Register rt, Register rs, int imm) { emit_long(insn_ORRI(ori_op, (int)rs->encoding(), (int)rt->encoding(), imm)); } aoqi@1: aoqi@1: void sb (Register rt, Register base, int off) { emit_long(insn_ORRI(sb_op, (int)base->encoding(), (int)rt->encoding(), off)); } aoqi@1: void sc (Register rt, Register base, int off) { emit_long(insn_ORRI(sc_op, (int)base->encoding(), (int)rt->encoding(), off)); } aoqi@1: void scd (Register rt, Register base, int off) { emit_long(insn_ORRI(scd_op, (int)base->encoding(), (int)rt->encoding(), off)); } aoqi@1: void sd (Register rt, Register base, int off) { emit_long(insn_ORRI(sd_op, (int)base->encoding(), (int)rt->encoding(), off)); } aoqi@1: void sdl (Register rt, Register base, int off) { emit_long(insn_ORRI(sdl_op, (int)base->encoding(), (int)rt->encoding(), off)); } aoqi@1: void sdr (Register rt, Register base, int off) { emit_long(insn_ORRI(sdr_op, (int)base->encoding(), (int)rt->encoding(), off)); } aoqi@1: void sh (Register rt, Register base, int off) { emit_long(insn_ORRI(sh_op, (int)base->encoding(), (int)rt->encoding(), off)); } aoqi@1: //#ifndef _LP64 aoqi@1: #if 1 aoqi@1: void sll (Register rd, Register rt , int sa) { emit_long(insn_RRSO((int)rt->encoding(), (int)rd->encoding(), sa, sll_op)); } aoqi@1: void sllv (Register rd, Register rt, Register rs) { emit_long(insn_RRRO((int)rs->encoding(), (int)rt->encoding(), (int)rd->encoding(), sllv_op)); } aoqi@1: #else aoqi@1: void sll (Register rd, Register rt , int sa) { dsll (rd, rt, sa);} aoqi@1: void sllv (Register rd, Register rt, Register rs) { dsllv (rd, rt, rs); } aoqi@1: #endif aoqi@1: void slt (Register rd, Register rs, Register rt) { emit_long(insn_RRRO((int)rs->encoding(), (int)rt->encoding(), (int)rd->encoding(), slt_op)); } aoqi@1: void slti (Register rt, Register rs, int imm) { emit_long(insn_ORRI(slti_op, (int)rs->encoding(), (int)rt->encoding(), imm)); } aoqi@1: void sltiu(Register rt, Register rs, int imm) { emit_long(insn_ORRI(sltiu_op, (int)rs->encoding(), (int)rt->encoding(), imm)); } aoqi@1: void sltu (Register rd, Register rs, Register rt) { emit_long(insn_RRRO((int)rs->encoding(), (int)rt->encoding(), (int)rd->encoding(), sltu_op)); } aoqi@1: //#ifndef _LP64 aoqi@1: #if 1 aoqi@1: void sra (Register rd, Register rt , int sa) { emit_long(insn_RRSO((int)rt->encoding(), (int)rd->encoding(), sa, sra_op)); } aoqi@1: void srav (Register rd, Register rt, Register rs) { emit_long(insn_RRRO((int)rs->encoding(), (int)rt->encoding(), (int)rd->encoding(), srav_op)); } aoqi@1: void srl (Register rd, Register rt , int sa) { emit_long(insn_RRSO((int)rt->encoding(), (int)rd->encoding(), sa, srl_op)); } aoqi@1: void srlv (Register rd, Register rt, Register rs) { emit_long(insn_RRRO((int)rs->encoding(), (int)rt->encoding(), (int)rd->encoding(), srlv_op)); } aoqi@1: #else aoqi@1: void sra (Register rd, Register rt , int sa) { dsra (rd, rt, sa); } aoqi@1: void srav (Register rd, Register rt, Register rs) { dsrav (rd, rt, rs); } aoqi@1: void srl (Register rd, Register rt , int sa) { dsrl (rd, rt, sa); } aoqi@1: void srlv (Register rd, Register rt, Register rs) { dsrlv (rd, rt, rs); } aoqi@1: #endif aoqi@1: #ifndef _LP64 aoqi@1: void sub (Register rd, Register rs, Register rt) { emit_long(insn_RRRO((int)rs->encoding(), (int)rt->encoding(), (int)rd->encoding(), sub_op)); } aoqi@1: void subu (Register rd, Register rs, Register rt) { emit_long(insn_RRRO((int)rs->encoding(), (int)rt->encoding(), (int)rd->encoding(), subu_op)); } aoqi@1: #else aoqi@1: void sub (Register rd, Register rs, Register rt) { dsub (rd, rs, rt); } aoqi@1: void subu (Register rd, Register rs, Register rt) { dsubu (rd, rs, rt); } aoqi@1: void subu32 (Register rd, Register rs, Register rt) { emit_long(insn_RRRO((int)rs->encoding(), (int)rt->encoding(), (int)rd->encoding(), subu_op)); } aoqi@1: #endif aoqi@1: void sw (Register rt, Register base, int off) { emit_long(insn_ORRI(sw_op, (int)base->encoding(), (int)rt->encoding(), off)); } aoqi@1: void swl (Register rt, Register base, int off) { emit_long(insn_ORRI(swl_op, (int)base->encoding(), (int)rt->encoding(), off)); } aoqi@1: void swr (Register rt, Register base, int off) { emit_long(insn_ORRI(swr_op, (int)base->encoding(), (int)rt->encoding(), off)); } aoqi@1: void sync () { emit_long(sync_op); } aoqi@1: void syscall(int code) { emit_long( (code<<6) | syscall_op ); } aoqi@1: aoqi@1: void sb(Register rt, Address dst); aoqi@1: void sc(Register rt, Address dst); aoqi@1: void scd(Register rt, Address dst); aoqi@1: void sd(Register rt, Address dst); aoqi@1: void sdl(Register rt, Address dst); aoqi@1: void sdr(Register rt, Address dst); aoqi@1: void sh(Register rt, Address dst); aoqi@1: void sw(Register rt, Address dst); aoqi@1: void swl(Register rt, Address dst); aoqi@1: void swr(Register rt, Address dst); aoqi@1: aoqi@1: void teq (Register rs, Register rt, int code) { emit_long(insn_RRCO((int)rs->encoding(), (int)rt->encoding(), code, teq_op)); } aoqi@1: void teqi (Register rs, int imm) { emit_long(insn_ORRI(regimm_op, (int)rs->encoding(), teqi_op, imm)); } aoqi@1: void tge (Register rs, Register rt, int code) { emit_long(insn_RRCO((int)rs->encoding(), (int)rt->encoding(), code, tge_op)); } aoqi@1: void tgei (Register rs, int imm) { emit_long(insn_ORRI(regimm_op, (int)rs->encoding(), tgei_op, imm)); } aoqi@1: void tgeiu(Register rs, int imm) { emit_long(insn_ORRI(regimm_op, (int)rs->encoding(), tgeiu_op, imm)); } aoqi@1: void tgeu (Register rs, Register rt, int code) { emit_long(insn_RRCO((int)rs->encoding(), (int)rt->encoding(), code, tgeu_op)); } aoqi@1: void tlt (Register rs, Register rt, int code) { emit_long(insn_RRCO((int)rs->encoding(), (int)rt->encoding(), code, tlt_op)); } aoqi@1: void tlti (Register rs, int imm) { emit_long(insn_ORRI(regimm_op, (int)rs->encoding(), tlti_op, imm)); } aoqi@1: void tltiu(Register rs, int imm) { emit_long(insn_ORRI(regimm_op, (int)rs->encoding(), tltiu_op, imm)); } aoqi@1: void tltu (Register rs, Register rt, int code) { emit_long(insn_RRCO((int)rs->encoding(), (int)rt->encoding(), code, tltu_op)); } aoqi@1: void tne (Register rs, Register rt, int code) { emit_long(insn_RRCO((int)rs->encoding(), (int)rt->encoding(), code, tne_op)); } aoqi@1: void tnei (Register rs, int imm) { emit_long(insn_ORRI(regimm_op, (int)rs->encoding(), tnei_op, imm)); } aoqi@1: aoqi@1: void xorr(Register rd, Register rs, Register rt) { emit_long(insn_RRRO((int)rs->encoding(), (int)rt->encoding(), (int)rd->encoding(), xor_op)); } aoqi@1: void xori(Register rt, Register rs, int imm) { emit_long(insn_ORRI(xori_op, (int)rs->encoding(), (int)rt->encoding(), imm)); } aoqi@1: aoqi@1: void nop() { emit_long(0); } aoqi@1: //float instructions for mips aoqi@1: void abs_s(FloatRegister fd, FloatRegister fs) { emit_long(insn_F3RO(single_fmt, 0, (int)fs->encoding(), (int)fd->encoding(), fabs_op));} aoqi@1: void abs_d(FloatRegister fd, FloatRegister fs) { emit_long(insn_F3RO(double_fmt, 0, (int)fs->encoding(), (int)fd->encoding(), fabs_op));} aoqi@1: void add_s(FloatRegister fd, FloatRegister fs, FloatRegister ft) { emit_long(insn_F3RO(single_fmt, (int)ft->encoding(), (int)fs->encoding(), (int)fd->encoding(), fadd_op));} aoqi@1: void add_d(FloatRegister fd, FloatRegister fs, FloatRegister ft) { emit_long(insn_F3RO(double_fmt, (int)ft->encoding(), (int)fs->encoding(), (int)fd->encoding(), fadd_op));} aoqi@1: aoqi@1: void bc1f (int off) { emit_long(insn_ORRI(cop1_op, bc_op, bcf_op, off)); has_delay_slot(); } aoqi@1: void bc1fl(int off) { emit_long(insn_ORRI(cop1_op, bc_op, bcfl_op, off)); has_delay_slot(); } aoqi@1: void bc1t (int off) { emit_long(insn_ORRI(cop1_op, bc_op, bct_op, off)); has_delay_slot(); } aoqi@1: void bc1tl(int off) { emit_long(insn_ORRI(cop1_op, bc_op, bctl_op, off)); has_delay_slot(); } aoqi@1: aoqi@1: void bc1f (address entry) { bc1f(offset(entry)); } aoqi@1: void bc1fl(address entry) { bc1fl(offset(entry)); } aoqi@1: void bc1t (address entry) { bc1t(offset(entry)); } aoqi@1: void bc1tl(address entry) { bc1tl(offset(entry)); } aoqi@1: aoqi@1: void bc1f (Label& L) { bc1f(target(L)); } aoqi@1: void bc1fl(Label& L) { bc1fl(target(L)); } aoqi@1: void bc1t (Label& L) { bc1t(target(L)); } aoqi@1: void bc1tl(Label& L) { bc1tl(target(L)); } aoqi@1: aoqi@1: void c_f_s (FloatRegister fs, FloatRegister ft) { emit_long(insn_F3RO(single_fmt, (int)ft->encoding(), (int)fs->encoding(), 0, f_cond)); } aoqi@1: void c_f_d (FloatRegister fs, FloatRegister ft) { emit_long(insn_F3RO(double_fmt, (int)ft->encoding(), (int)fs->encoding(), 0, f_cond)); } aoqi@1: void c_un_s (FloatRegister fs, FloatRegister ft) { emit_long(insn_F3RO(single_fmt, (int)ft->encoding(), (int)fs->encoding(), 0, un_cond)); } aoqi@1: void c_un_d (FloatRegister fs, FloatRegister ft) { emit_long(insn_F3RO(double_fmt, (int)ft->encoding(), (int)fs->encoding(), 0, un_cond)); } aoqi@1: void c_eq_s (FloatRegister fs, FloatRegister ft) { emit_long(insn_F3RO(single_fmt, (int)ft->encoding(), (int)fs->encoding(), 0, eq_cond)); } aoqi@1: void c_eq_d (FloatRegister fs, FloatRegister ft) { emit_long(insn_F3RO(double_fmt, (int)ft->encoding(), (int)fs->encoding(), 0, eq_cond)); } aoqi@1: void c_ueq_s (FloatRegister fs, FloatRegister ft) { emit_long(insn_F3RO(single_fmt, (int)ft->encoding(), (int)fs->encoding(), 0, ueq_cond)); } aoqi@1: void c_ueq_d (FloatRegister fs, FloatRegister ft) { emit_long(insn_F3RO(double_fmt, (int)ft->encoding(), (int)fs->encoding(), 0, ueq_cond)); } aoqi@1: void c_olt_s (FloatRegister fs, FloatRegister ft) { emit_long(insn_F3RO(single_fmt, (int)ft->encoding(), (int)fs->encoding(), 0, olt_cond)); } aoqi@1: void c_olt_d (FloatRegister fs, FloatRegister ft) { emit_long(insn_F3RO(double_fmt, (int)ft->encoding(), (int)fs->encoding(), 0, olt_cond)); } aoqi@1: void c_ult_s (FloatRegister fs, FloatRegister ft) { emit_long(insn_F3RO(single_fmt, (int)ft->encoding(), (int)fs->encoding(), 0, ult_cond)); } aoqi@1: void c_ult_d (FloatRegister fs, FloatRegister ft) { emit_long(insn_F3RO(double_fmt, (int)ft->encoding(), (int)fs->encoding(), 0, ult_cond)); } aoqi@1: void c_ole_s (FloatRegister fs, FloatRegister ft) { emit_long(insn_F3RO(single_fmt, (int)ft->encoding(), (int)fs->encoding(), 0, ole_cond)); } aoqi@1: void c_ole_d (FloatRegister fs, FloatRegister ft) { emit_long(insn_F3RO(double_fmt, (int)ft->encoding(), (int)fs->encoding(), 0, ole_cond)); } aoqi@1: void c_ule_s (FloatRegister fs, FloatRegister ft) { emit_long(insn_F3RO(single_fmt, (int)ft->encoding(), (int)fs->encoding(), 0, ule_cond)); } aoqi@1: void c_ule_d (FloatRegister fs, FloatRegister ft) { emit_long(insn_F3RO(double_fmt, (int)ft->encoding(), (int)fs->encoding(), 0, ule_cond)); } aoqi@1: void c_sf_s (FloatRegister fs, FloatRegister ft) { emit_long(insn_F3RO(single_fmt, (int)ft->encoding(), (int)fs->encoding(), 0, sf_cond)); } aoqi@1: void c_sf_d (FloatRegister fs, FloatRegister ft) { emit_long(insn_F3RO(double_fmt, (int)ft->encoding(), (int)fs->encoding(), 0, sf_cond)); } aoqi@1: void c_ngle_s(FloatRegister fs, FloatRegister ft) { emit_long(insn_F3RO(single_fmt, (int)ft->encoding(), (int)fs->encoding(), 0, ngle_cond)); } aoqi@1: void c_ngle_d(FloatRegister fs, FloatRegister ft) { emit_long(insn_F3RO(double_fmt, (int)ft->encoding(), (int)fs->encoding(), 0, ngle_cond)); } aoqi@1: void c_seq_s (FloatRegister fs, FloatRegister ft) { emit_long(insn_F3RO(single_fmt, (int)ft->encoding(), (int)fs->encoding(), 0, seq_cond)); } aoqi@1: void c_seq_d (FloatRegister fs, FloatRegister ft) { emit_long(insn_F3RO(double_fmt, (int)ft->encoding(), (int)fs->encoding(), 0, seq_cond)); } aoqi@1: void c_ngl_s (FloatRegister fs, FloatRegister ft) { emit_long(insn_F3RO(single_fmt, (int)ft->encoding(), (int)fs->encoding(), 0, ngl_cond)); } aoqi@1: void c_ngl_d (FloatRegister fs, FloatRegister ft) { emit_long(insn_F3RO(double_fmt, (int)ft->encoding(), (int)fs->encoding(), 0, ngl_cond)); } aoqi@1: void c_lt_s (FloatRegister fs, FloatRegister ft) { emit_long(insn_F3RO(single_fmt, (int)ft->encoding(), (int)fs->encoding(), 0, lt_cond)); } aoqi@1: void c_lt_d (FloatRegister fs, FloatRegister ft) { emit_long(insn_F3RO(double_fmt, (int)ft->encoding(), (int)fs->encoding(), 0, lt_cond)); } aoqi@1: void c_nge_s (FloatRegister fs, FloatRegister ft) { emit_long(insn_F3RO(single_fmt, (int)ft->encoding(), (int)fs->encoding(), 0, nge_cond)); } aoqi@1: void c_nge_d (FloatRegister fs, FloatRegister ft) { emit_long(insn_F3RO(double_fmt, (int)ft->encoding(), (int)fs->encoding(), 0, nge_cond)); } aoqi@1: void c_le_s (FloatRegister fs, FloatRegister ft) { emit_long(insn_F3RO(single_fmt, (int)ft->encoding(), (int)fs->encoding(), 0, le_cond)); } aoqi@1: void c_le_d (FloatRegister fs, FloatRegister ft) { emit_long(insn_F3RO(double_fmt, (int)ft->encoding(), (int)fs->encoding(), 0, le_cond)); } aoqi@1: void c_ngt_s (FloatRegister fs, FloatRegister ft) { emit_long(insn_F3RO(single_fmt, (int)ft->encoding(), (int)fs->encoding(), 0, ngt_cond)); } aoqi@1: void c_ngt_d (FloatRegister fs, FloatRegister ft) { emit_long(insn_F3RO(double_fmt, (int)ft->encoding(), (int)fs->encoding(), 0, ngt_cond)); } aoqi@1: aoqi@1: void ceil_l_s(FloatRegister fd, FloatRegister fs) { emit_long(insn_F3RO(single_fmt, 0, (int)fs->encoding(), (int)fd->encoding(), fceill_op)); } aoqi@1: void ceil_l_d(FloatRegister fd, FloatRegister fs) { emit_long(insn_F3RO(double_fmt, 0, (int)fs->encoding(), (int)fd->encoding(), fceill_op)); } aoqi@1: void ceil_w_s(FloatRegister fd, FloatRegister fs) { emit_long(insn_F3RO(single_fmt, 0, (int)fs->encoding(), (int)fd->encoding(), fceilw_op)); } aoqi@1: void ceil_w_d(FloatRegister fd, FloatRegister fs) { emit_long(insn_F3RO(double_fmt, 0, (int)fs->encoding(), (int)fd->encoding(), fceilw_op)); } aoqi@1: void cfc1(Register rt, FloatRegister fs) { emit_long(insn_COP1(cf_op, (int)rt->encoding(), (int)fs->encoding())); } aoqi@1: void ctc1(Register rt, FloatRegister fs) { emit_long(insn_COP1(ct_op, (int)rt->encoding(), (int)fs->encoding())); } aoqi@1: void cfc1(Register rt, int fs) { emit_long(insn_COP1(cf_op, (int)rt->encoding(), fs)); } aoqi@1: void ctc1(Register rt, int fs) { emit_long(insn_COP1(ct_op, (int)rt->encoding(), fs)); } aoqi@1: aoqi@1: void cvt_d_s(FloatRegister fd, FloatRegister fs) { emit_long(insn_F3RO(single_fmt, 0, (int)fs->encoding(), (int)fd->encoding(), fcvtd_op)); } aoqi@1: void cvt_d_w(FloatRegister fd, FloatRegister fs) { emit_long(insn_F3RO(word_fmt, 0, (int)fs->encoding(), (int)fd->encoding(), fcvtd_op)); } aoqi@1: void cvt_d_l(FloatRegister fd, FloatRegister fs) { emit_long(insn_F3RO(long_fmt, 0, (int)fs->encoding(), (int)fd->encoding(), fcvtd_op)); } aoqi@1: void cvt_l_s(FloatRegister fd, FloatRegister fs) { emit_long(insn_F3RO(single_fmt, 0, (int)fs->encoding(), (int)fd->encoding(), fcvtl_op)); } aoqi@1: void cvt_l_w(FloatRegister fd, FloatRegister fs) { emit_long(insn_F3RO(word_fmt, 0, (int)fs->encoding(), (int)fd->encoding(), fcvtl_op)); } aoqi@1: void cvt_l_d(FloatRegister fd, FloatRegister fs) { emit_long(insn_F3RO(double_fmt, 0, (int)fs->encoding(), (int)fd->encoding(), fcvtl_op)); } aoqi@1: void cvt_s_d(FloatRegister fd, FloatRegister fs) { emit_long(insn_F3RO(double_fmt, 0, (int)fs->encoding(), (int)fd->encoding(), fcvts_op)); } aoqi@1: void cvt_s_w(FloatRegister fd, FloatRegister fs) { emit_long(insn_F3RO(word_fmt, 0, (int)fs->encoding(), (int)fd->encoding(), fcvts_op)); } aoqi@1: void cvt_s_l(FloatRegister fd, FloatRegister fs) { emit_long(insn_F3RO(long_fmt, 0, (int)fs->encoding(), (int)fd->encoding(), fcvts_op)); } aoqi@1: void cvt_w_s(FloatRegister fd, FloatRegister fs) { emit_long(insn_F3RO(single_fmt, 0, (int)fs->encoding(), (int)fd->encoding(), fcvtw_op)); } aoqi@1: void cvt_w_d(FloatRegister fd, FloatRegister fs) { emit_long(insn_F3RO(double_fmt, 0, (int)fs->encoding(), (int)fd->encoding(), fcvtw_op)); } aoqi@1: void cvt_w_l(FloatRegister fd, FloatRegister fs) { emit_long(insn_F3RO(long_fmt, 0, (int)fs->encoding(), (int)fd->encoding(), fcvtw_op)); } aoqi@1: void pll(FloatRegister fd, FloatRegister fs, FloatRegister ft) { emit_long(insn_F3RO(long_fmt, (int)ft->encoding(), (int)fs->encoding(), (int)fd->encoding(), fpll_op)); } aoqi@1: void plu(FloatRegister fd, FloatRegister fs, FloatRegister ft) { emit_long(insn_F3RO(long_fmt, (int)ft->encoding(), (int)fs->encoding(), (int)fd->encoding(), fplu_op)); } aoqi@1: void pul(FloatRegister fd, FloatRegister fs, FloatRegister ft) { emit_long(insn_F3RO(long_fmt, (int)ft->encoding(), (int)fs->encoding(), (int)fd->encoding(), fpul_op)); } aoqi@1: void puu(FloatRegister fd, FloatRegister fs, FloatRegister ft) { emit_long(insn_F3RO(long_fmt, (int)ft->encoding(), (int)fs->encoding(), (int)fd->encoding(), fpuu_op)); } aoqi@1: aoqi@1: void div_s(FloatRegister fd, FloatRegister fs, FloatRegister ft) { emit_long(insn_F3RO(single_fmt, (int)ft->encoding(), (int)fs->encoding(), (int)fd->encoding(), fdiv_op)); } aoqi@1: void div_d(FloatRegister fd, FloatRegister fs, FloatRegister ft) { emit_long(insn_F3RO(double_fmt, (int)ft->encoding(), (int)fs->encoding(), (int)fd->encoding(), fdiv_op)); } aoqi@1: void dmfc1(Register rt, FloatRegister fs) { emit_long(insn_COP1(dmf_op, (int)rt->encoding(), (int)fs->encoding())); } aoqi@1: void dmtc1(Register rt, FloatRegister fs) { emit_long(insn_COP1(dmt_op, (int)rt->encoding(), (int)fs->encoding())); } aoqi@1: aoqi@1: void floor_l_s(FloatRegister fd, FloatRegister fs) { emit_long(insn_F3RO(single_fmt, 0, (int)fs->encoding(), (int)fd->encoding(), ffloorl_op)); } aoqi@1: void floor_l_d(FloatRegister fd, FloatRegister fs) { emit_long(insn_F3RO(double_fmt, 0, (int)fs->encoding(), (int)fd->encoding(), ffloorl_op)); } aoqi@1: void floor_w_s(FloatRegister fd, FloatRegister fs) { emit_long(insn_F3RO(single_fmt, 0, (int)fs->encoding(), (int)fd->encoding(), ffloorw_op)); } aoqi@1: void floor_w_d(FloatRegister fd, FloatRegister fs) { emit_long(insn_F3RO(double_fmt, 0, (int)fs->encoding(), (int)fd->encoding(), ffloorw_op)); } aoqi@1: aoqi@1: void ldc1(FloatRegister ft, Register base, int off) { emit_long(insn_ORRI(ldc1_op, (int)base->encoding(), (int)ft->encoding(), off)); } aoqi@1: void lwc1(FloatRegister ft, Register base, int off) { emit_long(insn_ORRI(lwc1_op, (int)base->encoding(), (int)ft->encoding(), off)); } aoqi@1: void ldc1(FloatRegister ft, Address src); aoqi@1: void lwc1(FloatRegister ft, Address src); aoqi@1: aoqi@1: void mfc1(Register rt, FloatRegister fs) { emit_long(insn_COP1(mf_op, (int)rt->encoding(), (int)fs->encoding())); } aoqi@1: void mov_s(FloatRegister fd, FloatRegister fs) { emit_long(insn_F3RO(single_fmt, 0, (int)fs->encoding(), (int)fd->encoding(), fmov_op)); } aoqi@1: void mov_d(FloatRegister fd, FloatRegister fs) { emit_long(insn_F3RO(double_fmt, 0, (int)fs->encoding(), (int)fd->encoding(), fmov_op)); } aoqi@1: void mtc1(Register rt, FloatRegister fs) { emit_long(insn_COP1(mt_op, (int)rt->encoding(), (int)fs->encoding())); } aoqi@1: void mul_s(FloatRegister fd, FloatRegister fs, FloatRegister ft) { emit_long(insn_F3RO(single_fmt, (int)ft->encoding(), (int)fs->encoding(), (int)fd->encoding(), fmul_op)); } aoqi@1: void mul_d(FloatRegister fd, FloatRegister fs, FloatRegister ft) { emit_long(insn_F3RO(double_fmt, (int)ft->encoding(), (int)fs->encoding(), (int)fd->encoding(), fmul_op)); } aoqi@1: aoqi@1: void neg_s(FloatRegister fd, FloatRegister fs) { emit_long(insn_F3RO(single_fmt, 0, (int)fs->encoding(), (int)fd->encoding(), fneg_op)); } aoqi@1: void neg_d(FloatRegister fd, FloatRegister fs) { emit_long(insn_F3RO(double_fmt, 0, (int)fs->encoding(), (int)fd->encoding(), fneg_op)); } aoqi@1: aoqi@1: void round_l_s(FloatRegister fd, FloatRegister fs) { emit_long(insn_F3RO(single_fmt, 0, (int)fs->encoding(), (int)fd->encoding(), froundl_op)); } aoqi@1: void round_l_d(FloatRegister fd, FloatRegister fs) { emit_long(insn_F3RO(double_fmt, 0, (int)fs->encoding(), (int)fd->encoding(), froundl_op)); } aoqi@1: void round_w_s(FloatRegister fd, FloatRegister fs) { emit_long(insn_F3RO(single_fmt, 0, (int)fs->encoding(), (int)fd->encoding(), froundw_op)); } aoqi@1: void round_w_d(FloatRegister fd, FloatRegister fs) { emit_long(insn_F3RO(double_fmt, 0, (int)fs->encoding(), (int)fd->encoding(), froundw_op)); } aoqi@1: aoqi@1: void sdc1(FloatRegister ft, Register base, int off) { emit_long(insn_ORRI(sdc1_op, (int)base->encoding(), (int)ft->encoding(), off)); } aoqi@1: void sdc1(FloatRegister ft, Address dst); aoqi@1: void sqrt_s(FloatRegister fd, FloatRegister fs) { emit_long(insn_F3RO(single_fmt, 0, (int)fs->encoding(), (int)fd->encoding(), fsqrt_op)); } aoqi@1: void sqrt_d(FloatRegister fd, FloatRegister fs) { emit_long(insn_F3RO(double_fmt, 0, (int)fs->encoding(), (int)fd->encoding(), fsqrt_op)); } aoqi@1: void sub_s(FloatRegister fd, FloatRegister fs, FloatRegister ft) { emit_long(insn_F3RO(single_fmt, (int)ft->encoding(), (int)fs->encoding(), (int)fd->encoding(), fsub_op)); } aoqi@1: void sub_d(FloatRegister fd, FloatRegister fs, FloatRegister ft) { emit_long(insn_F3RO(double_fmt, (int)ft->encoding(), (int)fs->encoding(), (int)fd->encoding(), fsub_op)); } aoqi@1: void swc1(FloatRegister ft, Register base, int off) { emit_long(insn_ORRI(swc1_op, (int)base->encoding(), (int)ft->encoding(), off)); } aoqi@1: void swc1(FloatRegister ft, Address dst); aoqi@1: aoqi@1: void trunc_l_s(FloatRegister fd, FloatRegister fs) { emit_long(insn_F3RO(single_fmt, 0, (int)fs->encoding(), (int)fd->encoding(), ftruncl_op)); } aoqi@1: void trunc_l_d(FloatRegister fd, FloatRegister fs) { emit_long(insn_F3RO(double_fmt, 0, (int)fs->encoding(), (int)fd->encoding(), ftruncl_op)); } aoqi@1: void trunc_w_s(FloatRegister fd, FloatRegister fs) { emit_long(insn_F3RO(single_fmt, 0, (int)fs->encoding(), (int)fd->encoding(), ftruncw_op)); } aoqi@1: void trunc_w_d(FloatRegister fd, FloatRegister fs) { emit_long(insn_F3RO(double_fmt, 0, (int)fs->encoding(), (int)fd->encoding(), ftruncw_op)); } aoqi@1: aoqi@1: void int3(); aoqi@1: static void print_instruction(int); aoqi@1: int patched_branch(int dest_pos, int inst, int inst_pos); aoqi@1: int branch_destination(int inst, int pos); aoqi@1: aoqi@1: /* Godson3 extension */ aoqi@1: void gsldx(Register rt, Register base, Register index, int off) { aoqi@1: assert(is_simm(off, 8), "gsldx: off exceeds 8 bits"); aoqi@1: emit_long(gsldx_op | ((int)base->encoding() << 21) | ((int)rt->encoding() << 16) | ((int)index->encoding() << 11) | (off << 3)); aoqi@1: } aoqi@1: aoqi@1: void gslwx(Register rt, Register base, Register index, int off) { aoqi@1: assert(is_simm(off, 8), "gslwx: off exceeds 8 bits"); aoqi@1: emit_long(gslwx_op | ((int)base->encoding() << 21) | ((int)rt->encoding() << 16) | ((int)index->encoding() << 11) | (off << 3)); aoqi@1: } aoqi@1: aoqi@1: public: aoqi@1: // Creation aoqi@1: Assembler(CodeBuffer* code) : AbstractAssembler(code) { aoqi@1: #ifdef CHECK_DELAY aoqi@1: delay_state = no_delay; aoqi@1: #endif aoqi@1: } aoqi@1: aoqi@1: // Decoding aoqi@1: static address locate_operand(address inst, WhichOperand which); aoqi@1: static address locate_next_instruction(address inst); aoqi@1: }; aoqi@1: aoqi@1: aoqi@1: // MacroAssembler extends Assembler by frequently used macros. aoqi@1: // aoqi@1: // Instructions for which a 'better' code sequence exists depending aoqi@1: // on arguments should also go in here. aoqi@1: aoqi@1: class MacroAssembler: public Assembler { aoqi@1: friend class LIR_Assembler; aoqi@1: friend class Runtime1; // as_Address() aoqi@1: aoqi@1: public: aoqi@1: static intptr_t i[32]; aoqi@1: static float f[32]; aoqi@1: static void print(outputStream *s); aoqi@1: aoqi@1: static int i_offset(unsigned int k); aoqi@1: static int f_offset(unsigned int k); aoqi@1: aoqi@1: static void save_registers(MacroAssembler *masm); aoqi@1: static void restore_registers(MacroAssembler *masm); aoqi@1: aoqi@1: protected: aoqi@1: aoqi@1: Address as_Address(AddressLiteral adr); aoqi@1: Address as_Address(ArrayAddress adr); aoqi@1: aoqi@1: // Support for VM calls aoqi@1: // aoqi@1: // This is the base routine called by the different versions of call_VM_leaf. The interpreter aoqi@1: // may customize this version by overriding it for its purposes (e.g., to save/restore aoqi@1: // additional registers when doing a VM call). aoqi@1: #ifdef CC_INTERP aoqi@1: // c++ interpreter never wants to use interp_masm version of call_VM aoqi@1: #define VIRTUAL aoqi@1: #else aoqi@1: #define VIRTUAL virtual aoqi@1: #endif aoqi@1: aoqi@1: VIRTUAL void call_VM_leaf_base( aoqi@1: address entry_point, // the entry point aoqi@1: int number_of_arguments // the number of arguments to pop after the call aoqi@1: ); aoqi@1: aoqi@1: // This is the base routine called by the different versions of call_VM. The interpreter aoqi@1: // may customize this version by overriding it for its purposes (e.g., to save/restore aoqi@1: // additional registers when doing a VM call). aoqi@1: // aoqi@1: // If no java_thread register is specified (noreg) than rdi will be used instead. call_VM_base aoqi@1: // returns the register which contains the thread upon return. If a thread register has been aoqi@1: // specified, the return value will correspond to that register. If no last_java_sp is specified aoqi@1: // (noreg) than rsp will be used instead. aoqi@1: VIRTUAL void call_VM_base( // returns the register containing the thread upon return aoqi@1: Register oop_result, // where an oop-result ends up if any; use noreg otherwise aoqi@1: Register java_thread, // the thread if computed before ; use noreg otherwise aoqi@1: Register last_java_sp, // to set up last_Java_frame in stubs; use noreg otherwise aoqi@1: address entry_point, // the entry point aoqi@1: int number_of_arguments, // the number of arguments (w/o thread) to pop after the call aoqi@1: bool check_exceptions // whether to check for pending exceptions after return aoqi@1: ); aoqi@1: aoqi@1: // These routines should emit JVMTI PopFrame and ForceEarlyReturn handling code. aoqi@1: // The implementation is only non-empty for the InterpreterMacroAssembler, aoqi@1: // as only the interpreter handles PopFrame and ForceEarlyReturn requests. aoqi@1: virtual void check_and_handle_popframe(Register java_thread); aoqi@1: virtual void check_and_handle_earlyret(Register java_thread); aoqi@1: aoqi@1: void call_VM_helper(Register oop_result, address entry_point, int number_of_arguments, bool check_exceptions = true); aoqi@1: aoqi@1: // helpers for FPU flag access aoqi@1: // tmp is a temporary register, if none is available use noreg aoqi@1: //void save_rax (Register tmp); aoqi@1: //void restore_rax(Register tmp); aoqi@1: aoqi@1: public: aoqi@1: MacroAssembler(CodeBuffer* code) : Assembler(code) {} aoqi@1: aoqi@1: // Support for NULL-checks aoqi@1: // aoqi@1: // Generates code that causes a NULL OS exception if the content of reg is NULL. aoqi@1: // If the accessed location is M[reg + offset] and the offset is known, provide the aoqi@1: // offset. No explicit code generation is needed if the offset is within a certain aoqi@1: // range (0 <= offset <= page_size). aoqi@1: // use "teq 83, reg" in mips now, by yjl 6/20/2005 aoqi@1: void null_check(Register reg, int offset = -1); aoqi@1: static bool needs_explicit_null_check(intptr_t offset); aoqi@1: aoqi@1: // Required platform-specific helpers for Label::patch_instructions. aoqi@1: // They _shadow_ the declarations in AbstractAssembler, which are undefined. aoqi@1: void pd_patch_instruction(address branch, address target); aoqi@1: aoqi@1: // Alignment aoqi@1: void align(int modulus); aoqi@1: aoqi@1: // Misc aoqi@1: //void fat_nop(); // 5 byte nop aoqi@1: aoqi@1: // Stack frame creation/removal aoqi@1: void enter(); aoqi@1: void leave(); aoqi@1: aoqi@1: // Support for getting the JavaThread pointer (i.e.; a reference to thread-local information) aoqi@1: // The pointer will be loaded into the thread register. aoqi@1: void get_thread(Register thread); aoqi@1: aoqi@1: aoqi@1: // Support for VM calls aoqi@1: // aoqi@1: // It is imperative that all calls into the VM are handled via the call_VM macros. aoqi@1: // They make sure that the stack linkage is setup correctly. call_VM's correspond aoqi@1: // to ENTRY/ENTRY_X entry points while call_VM_leaf's correspond to LEAF entry points. aoqi@1: aoqi@1: aoqi@1: void call_VM(Register oop_result, aoqi@1: address entry_point, aoqi@1: bool check_exceptions = true); aoqi@1: void call_VM(Register oop_result, aoqi@1: address entry_point, aoqi@1: Register arg_1, aoqi@1: bool check_exceptions = true); aoqi@1: void call_VM(Register oop_result, aoqi@1: address entry_point, aoqi@1: Register arg_1, Register arg_2, aoqi@1: bool check_exceptions = true); aoqi@1: void call_VM(Register oop_result, aoqi@1: address entry_point, aoqi@1: Register arg_1, Register arg_2, Register arg_3, aoqi@1: bool check_exceptions = true); aoqi@1: // Super call_VM calls - correspond to MacroAssembler::call_VM(_leaf) calls aoqi@1: void super_call_VM_leaf(address entry_point); aoqi@1: void super_call_VM_leaf(address entry_point, Register arg_1); aoqi@1: void super_call_VM_leaf(address entry_point, Register arg_1, Register arg_2); aoqi@1: void super_call_VM_leaf(address entry_point, aoqi@1: Register arg_1, Register arg_2, Register arg_3); aoqi@1: aoqi@1: // Overloadings with last_Java_sp aoqi@1: void call_VM(Register oop_result, aoqi@1: Register last_java_sp, aoqi@1: address entry_point, aoqi@1: int number_of_arguments = 0, aoqi@1: bool check_exceptions = true); aoqi@1: void call_VM(Register oop_result, aoqi@1: Register last_java_sp, aoqi@1: address entry_point, aoqi@1: Register arg_1, bool aoqi@1: check_exceptions = true); aoqi@1: void call_VM(Register oop_result, aoqi@1: Register last_java_sp, aoqi@1: address entry_point, aoqi@1: Register arg_1, Register arg_2, aoqi@1: bool check_exceptions = true); aoqi@1: void call_VM(Register oop_result, aoqi@1: Register last_java_sp, aoqi@1: address entry_point, aoqi@1: Register arg_1, Register arg_2, Register arg_3, aoqi@1: bool check_exceptions = true); aoqi@1: aoqi@1: void call_VM_leaf(address entry_point, aoqi@1: int number_of_arguments = 0); aoqi@1: void call_VM_leaf(address entry_point, aoqi@1: Register arg_1); aoqi@1: void call_VM_leaf(address entry_point, aoqi@1: Register arg_1, Register arg_2); aoqi@1: void call_VM_leaf(address entry_point, aoqi@1: Register arg_1, Register arg_2, Register arg_3); aoqi@1: aoqi@1: // last Java Frame (fills frame anchor) aoqi@1: void set_last_Java_frame(Register thread, aoqi@1: Register last_java_sp, aoqi@1: Register last_java_fp, aoqi@1: address last_java_pc); aoqi@1: aoqi@1: // thread in the default location (r15_thread on 64bit) aoqi@1: void set_last_Java_frame(Register last_java_sp, aoqi@1: Register last_java_fp, aoqi@1: address last_java_pc); aoqi@1: aoqi@1: void reset_last_Java_frame(Register thread, bool clear_fp, bool clear_pc); aoqi@1: aoqi@1: // thread in the default location (r15_thread on 64bit) aoqi@1: void reset_last_Java_frame(bool clear_fp, bool clear_pc); aoqi@1: aoqi@1: // Stores aoqi@1: void store_check(Register obj); // store check for obj - register is destroyed afterwards aoqi@1: void store_check(Register obj, Address dst); // same as above, dst is exact store location (reg. is destroyed) aoqi@1: aoqi@1: aoqi@1: void g1_write_barrier_pre(Register obj, aoqi@1: #ifndef _LP64 aoqi@1: Register thread, aoqi@1: #endif aoqi@1: Register tmp, aoqi@1: Register tmp2, aoqi@1: bool tosca_live); aoqi@1: void g1_write_barrier_post(Register store_addr, aoqi@1: Register new_val, aoqi@1: #ifndef _LP64 aoqi@1: Register thread, aoqi@1: #endif aoqi@1: Register tmp, aoqi@1: Register tmp2); aoqi@1: aoqi@1: aoqi@1: aoqi@1: // split store_check(Register obj) to enhance instruction interleaving aoqi@1: void store_check_part_1(Register obj); aoqi@1: void store_check_part_2(Register obj); aoqi@1: aoqi@1: // C 'boolean' to Java boolean: x == 0 ? 0 : 1 aoqi@1: void c2bool(Register x); aoqi@1: //add for compressedoops aoqi@1: void load_klass(Register dst, Register src); aoqi@1: void store_klass(Register dst, Register src); aoqi@1: void load_prototype_header(Register dst, Register src); aoqi@1: /* aoqi@1: // C++ bool manipulation aoqi@1: aoqi@1: void movbool(Register dst, Address src); aoqi@1: void movbool(Address dst, bool boolconst); aoqi@1: void movbool(Address dst, Register src); aoqi@1: void testbool(Register dst); aoqi@1: aoqi@1: // oop manipulations aoqi@1: void load_klass(Register dst, Register src); aoqi@1: void store_klass(Register dst, Register src); aoqi@1: aoqi@1: void load_prototype_header(Register dst, Register src);*/ aoqi@1: aoqi@1: #ifdef _LP64 aoqi@1: void store_klass_gap(Register dst, Register src); aoqi@1: aoqi@1: void load_heap_oop(Register dst, Address src); aoqi@1: void store_heap_oop(Address dst, Register src); aoqi@1: void encode_heap_oop(Register r); aoqi@1: void decode_heap_oop(Register r); aoqi@1: void encode_heap_oop_not_null(Register r); aoqi@1: void decode_heap_oop_not_null(Register r); aoqi@1: void encode_heap_oop_not_null(Register dst, Register src); aoqi@1: void decode_heap_oop_not_null(Register dst, Register src); aoqi@1: aoqi@1: void encode_klass_not_null(Register r); aoqi@1: void decode_klass_not_null(Register r); aoqi@1: void encode_klass_not_null(Register dst, Register src); aoqi@1: void decode_klass_not_null(Register dst, Register src); aoqi@1: aoqi@1: //void set_narrow_oop(Register dst, jobject obj); aoqi@1: aoqi@1: // Returns the byte size of the instructions generated by decode_klass_not_null() aoqi@1: // when compressed klass pointers are being used. aoqi@1: static int instr_size_for_decode_klass_not_null(); aoqi@1: aoqi@1: // if heap base register is used - reinit it with the correct value aoqi@1: void reinit_heapbase(); aoqi@1: DEBUG_ONLY(void verify_heapbase(const char* msg);) aoqi@1: aoqi@1: #endif // _LP64 aoqi@1: aoqi@1: void incrementl(Register reg, int value = 1); aoqi@1: aoqi@1: void decrementl(Register reg, int value = 1); aoqi@1: aoqi@1: /* aoqi@1: // Int division/remainder for Java aoqi@1: // (as idivl, but checks for special case as described in JVM spec.) aoqi@1: // returns idivl instruction offset for implicit exception handling aoqi@1: int corrected_idivl(Register reg); aoqi@1: aoqi@1: // Long division/remainder for Java aoqi@1: // (as idivq, but checks for special case as described in JVM spec.) aoqi@1: // returns idivq instruction offset for implicit exception handling aoqi@1: int corrected_idivq(Register reg); aoqi@1: */ aoqi@1: aoqi@1: void int3(); aoqi@1: /* aoqi@1: // Long operation macros for a 32bit cpu aoqi@1: // Long negation for Java aoqi@1: void lneg(Register hi, Register lo); aoqi@1: aoqi@1: // Long multiplication for Java aoqi@1: // (destroys contents of eax, ebx, ecx and edx) aoqi@1: void lmul(int x_rsp_offset, int y_rsp_offset); // rdx:rax = x * y aoqi@1: aoqi@1: // Long shifts for Java aoqi@1: // (semantics as described in JVM spec.) aoqi@1: void lshl(Register hi, Register lo); // hi:lo << (rcx & 0x3f) aoqi@1: void lshr(Register hi, Register lo, bool sign_extension = false); // hi:lo >> (rcx & 0x3f) aoqi@1: aoqi@1: // Long compare for Java aoqi@1: // (semantics as described in JVM spec.) aoqi@1: void lcmp2int(Register x_hi, Register x_lo, Register y_hi, Register y_lo); // x_hi = lcmp(x, y) aoqi@1: aoqi@1: aoqi@1: // misc aoqi@1: */ aoqi@1: // Sign extension aoqi@1: #ifdef _LP64 aoqi@1: void sign_extend_short(Register reg) { dsll32(reg, reg, 16); dsra32(reg, reg, 16); } aoqi@1: void sign_extend_byte(Register reg) { dsll32(reg, reg, 24); dsra32(reg, reg, 24); } aoqi@1: #else aoqi@1: void sign_extend_short(Register reg) { sll(reg, reg, 16); sra(reg, reg, 16); } aoqi@1: void sign_extend_byte(Register reg) { sll(reg, reg, 24); sra(reg, reg, 24); } aoqi@1: #endif aoqi@1: void rem_s(FloatRegister fd, FloatRegister fs, FloatRegister ft, FloatRegister tmp); aoqi@1: void rem_d(FloatRegister fd, FloatRegister fs, FloatRegister ft, FloatRegister tmp); aoqi@1: aoqi@1: // Inlined sin/cos generator for Java; must not use CPU instruction aoqi@1: // directly on Intel as it does not have high enough precision aoqi@1: // outside of the range [-pi/4, pi/4]. Extra argument indicate the aoqi@1: // number of FPU stack slots in use; all but the topmost will aoqi@1: // require saving if a slow case is necessary. Assumes argument is aoqi@1: // on FP TOS; result is on FP TOS. No cpu registers are changed by aoqi@1: // this code. aoqi@1: void trigfunc(char trig, int num_fpu_regs_in_use = 1); aoqi@1: /* aoqi@1: // branch to L if FPU flag C2 is set/not set aoqi@1: // tmp is a temporary register, if none is available use noreg aoqi@1: void jC2 (Register tmp, Label& L); aoqi@1: void jnC2(Register tmp, Label& L); aoqi@1: aoqi@1: // Pop ST (ffree & fincstp combined) aoqi@1: void fpop(); aoqi@1: aoqi@1: // pushes double TOS element of FPU stack on CPU stack; pops from FPU stack aoqi@1: void push_fTOS(); aoqi@1: aoqi@1: // pops double TOS element from CPU stack and pushes on FPU stack aoqi@1: void pop_fTOS(); aoqi@1: aoqi@1: void empty_FPU_stack(); aoqi@1: aoqi@1: void push_IU_state(); aoqi@1: void pop_IU_state(); aoqi@1: aoqi@1: void push_FPU_state(); aoqi@1: void pop_FPU_state(); aoqi@1: aoqi@1: void push_CPU_state(); aoqi@1: void pop_CPU_state(); aoqi@1: aoqi@1: // Round up to a power of two aoqi@1: void round_to(Register reg, int modulus); aoqi@1: aoqi@1: // Callee saved registers handling aoqi@1: void push_callee_saved_registers(); aoqi@1: void pop_callee_saved_registers(); aoqi@1: */ aoqi@1: // allocation aoqi@1: void eden_allocate( aoqi@1: Register obj, // result: pointer to object after successful allocation aoqi@1: Register var_size_in_bytes, // object size in bytes if unknown at compile time; invalid otherwise aoqi@1: int con_size_in_bytes, // object size in bytes if known at compile time aoqi@1: Register t1, // temp register aoqi@1: Register t2, aoqi@1: Label& slow_case // continuation point if fast allocation fails aoqi@1: ); aoqi@1: void tlab_allocate( aoqi@1: Register obj, // result: pointer to object after successful allocation aoqi@1: Register var_size_in_bytes, // object size in bytes if unknown at compile time; invalid otherwise aoqi@1: int con_size_in_bytes, // object size in bytes if known at compile time aoqi@1: Register t1, // temp register aoqi@1: Register t2, // temp register aoqi@1: Label& slow_case // continuation point if fast allocation fails aoqi@1: ); aoqi@1: void tlab_refill(Label& retry_tlab, Label& try_eden, Label& slow_case); aoqi@1: aoqi@1: //---- aoqi@1: // void set_word_if_not_zero(Register reg); // sets reg to 1 if not zero, otherwise 0 aoqi@1: aoqi@1: aoqi@1: // Debugging aoqi@1: aoqi@1: // only if +VerifyOops aoqi@1: void verify_oop(Register reg, const char* s = "broken oop"); aoqi@1: void verify_oop_addr(Address addr, const char * s = "broken oop addr"); aoqi@1: void verify_oop_subroutine(); aoqi@1: // TODO: verify method and klass metadata (compare against vptr?) aoqi@1: void _verify_method_ptr(Register reg, const char * msg, const char * file, int line) {} aoqi@1: void _verify_klass_ptr(Register reg, const char * msg, const char * file, int line){} aoqi@1: aoqi@1: #define verify_method_ptr(reg) _verify_method_ptr(reg, "broken method " #reg, __FILE__, __LINE__) aoqi@1: #define verify_klass_ptr(reg) _verify_klass_ptr(reg, "broken klass " #reg, __FILE__, __LINE__) aoqi@1: aoqi@1: // only if +VerifyFPU aoqi@1: void verify_FPU(int stack_depth, const char* s = "illegal FPU state"); aoqi@1: aoqi@1: // prints msg, dumps registers and stops execution aoqi@1: void stop(const char* msg); aoqi@1: aoqi@1: // prints msg and continues aoqi@1: void warn(const char* msg); aoqi@1: aoqi@1: static void debug(char* msg/*, RegistersForDebugging* regs*/); aoqi@1: static void debug32(int rdi, int rsi, int rbp, int rsp, int rbx, int rdx, int rcx, int rax, int eip, char* msg); aoqi@1: static void debug64(char* msg, int64_t pc, int64_t regs[]); aoqi@1: aoqi@1: void print_reg(Register reg); aoqi@1: void print_reg(FloatRegister reg); aoqi@1: //void os_breakpoint(); aoqi@1: aoqi@1: void untested() { stop("untested"); } aoqi@1: aoqi@1: void unimplemented(const char* what = "") { char* b = new char[1024]; jio_snprintf(b, sizeof(b), "unimplemented: %s", what); stop(b); } aoqi@1: aoqi@1: void should_not_reach_here() { stop("should not reach here"); } aoqi@1: aoqi@1: void print_CPU_state(); aoqi@1: aoqi@1: // Stack overflow checking aoqi@1: void bang_stack_with_offset(int offset) { aoqi@1: // stack grows down, caller passes positive offset aoqi@1: assert(offset > 0, "must bang with negative offset"); aoqi@1: if (offset <= 32768) { aoqi@1: sw(A0, SP, -offset); aoqi@1: } else { aoqi@1: #ifdef _LP64 aoqi@1: li(AT, offset); aoqi@1: dsub(AT, SP, AT); aoqi@1: #else aoqi@1: move(AT, offset); aoqi@1: sub(AT, SP, AT); aoqi@1: #endif aoqi@1: sw(A0, AT, 0); aoqi@1: } aoqi@1: } aoqi@1: aoqi@1: // Writes to stack successive pages until offset reached to check for aoqi@1: // stack overflow + shadow pages. Also, clobbers tmp aoqi@1: void bang_stack_size(Register size, Register tmp); aoqi@1: virtual RegisterOrConstant delayed_value_impl(intptr_t* delayed_value_addr, aoqi@1: Register tmp, aoqi@1: int offset); aoqi@1: aoqi@1: // Support for serializing memory accesses between threads aoqi@1: void serialize_memory(Register thread, Register tmp); aoqi@1: aoqi@1: //void verify_tlab(); aoqi@1: void verify_tlab(Register t1, Register t2); aoqi@1: aoqi@1: // Biased locking support aoqi@1: // lock_reg and obj_reg must be loaded up with the appropriate values. aoqi@1: // swap_reg must be rax, and is killed. aoqi@1: // tmp_reg is optional. If it is supplied (i.e., != noreg) it will aoqi@1: // be killed; if not supplied, push/pop will be used internally to aoqi@1: // allocate a temporary (inefficient, avoid if possible). aoqi@1: // Optional slow case is for implementations (interpreter and C1) which branch to aoqi@1: // slow case directly. Leaves condition codes set for C2's Fast_Lock node. aoqi@1: // Returns offset of first potentially-faulting instruction for null aoqi@1: // check info (currently consumed only by C1). If aoqi@1: // swap_reg_contains_mark is true then returns -1 as it is assumed aoqi@1: // the calling code has already passed any potential faults. aoqi@1: int biased_locking_enter(Register lock_reg, Register obj_reg, aoqi@1: Register swap_reg, Register tmp_reg, aoqi@1: bool swap_reg_contains_mark, aoqi@1: Label& done, Label* slow_case = NULL, aoqi@1: BiasedLockingCounters* counters = NULL); aoqi@1: void biased_locking_exit (Register obj_reg, Register temp_reg, Label& done); aoqi@1: aoqi@1: aoqi@1: // Calls aoqi@1: aoqi@1: void call(address entry); aoqi@1: void call(address entry, relocInfo::relocType rtype); aoqi@1: void call(address entry, RelocationHolder& rh); aoqi@1: // Emit the CompiledIC call idiom aoqi@1: void ic_call(address entry); aoqi@1: aoqi@1: void jmp(address entry); aoqi@1: void jmp(address entry, relocInfo::relocType rtype); aoqi@1: aoqi@1: // Argument ops aoqi@1: /*inline void store_int_argument(Register s, Argument& a); aoqi@1: inline void store_long_argument(Register s, Argument& a); aoqi@1: inline void store_float_argument(FloatRegister s, Argument& a); aoqi@1: inline void store_double_argument(FloatRegister s, Argument& a); aoqi@1: inline void store_ptr_argument(Register s, Argument& a);*/ aoqi@1: inline void store_int_argument(Register s, Argument &a) { aoqi@1: if(a.is_Register()) { aoqi@1: move(a.as_Register(), s); aoqi@1: } else { aoqi@1: sw(s, a.as_caller_address()); aoqi@1: } aoqi@1: } aoqi@1: aoqi@1: inline void store_long_argument(Register s, Argument &a) { aoqi@1: Argument a1 = a.successor(); aoqi@1: if(a.is_Register() && a1.is_Register()) { aoqi@1: move(a.as_Register(), s); aoqi@1: move(a.as_Register(), s); aoqi@1: } else { aoqi@1: sd(s, a.as_caller_address()); aoqi@1: } aoqi@1: } aoqi@1: aoqi@1: inline void store_float_argument(FloatRegister s, Argument &a) { aoqi@1: if(a.is_Register()) { aoqi@1: mov_s(a.as_FloatRegister(), s); aoqi@1: } else { aoqi@1: swc1(s, a.as_caller_address()); aoqi@1: } aoqi@1: } aoqi@1: inline void store_double_argument(FloatRegister s, Argument &a) { aoqi@1: if(a.is_Register()) { aoqi@1: mov_d(a.as_FloatRegister(), s); aoqi@1: } else { aoqi@1: sdc1(s, a.as_caller_address()); aoqi@1: } aoqi@1: } aoqi@1: aoqi@1: inline void store_ptr_argument(Register s, Argument &a) { aoqi@1: if(a.is_Register()) { aoqi@1: move(a.as_Register(), s); aoqi@1: } else { aoqi@1: st_ptr(s, a.as_caller_address()); aoqi@1: } aoqi@1: } aoqi@1: aoqi@1: // Load and store values by size and signed-ness aoqi@1: void load_sized_value(Register dst, Address src, size_t size_in_bytes, bool is_signed, Register dst2 = noreg); aoqi@1: void store_sized_value(Address dst, Register src, size_t size_in_bytes, Register src2 = noreg); aoqi@1: aoqi@1: // interface method calling aoqi@1: void lookup_interface_method(Register recv_klass, aoqi@1: Register intf_klass, aoqi@1: RegisterOrConstant itable_index, aoqi@1: Register method_result, aoqi@1: Register scan_temp, aoqi@1: Label& no_such_interface); aoqi@1: // virtual method calling aoqi@1: void lookup_virtual_method(Register recv_klass, aoqi@1: RegisterOrConstant vtable_index, aoqi@1: Register method_result); aoqi@1: aoqi@1: // ld_ptr will perform lw for 32 bit VMs and ld for 64 bit VMs aoqi@1: // st_ptr will perform sw for 32 bit VMs and sd for 64 bit VMs aoqi@1: inline void ld_ptr(Register rt, Address a){ aoqi@1: #ifdef _LP64 aoqi@1: ld(rt, a.base(), a.disp()); aoqi@1: #else aoqi@1: lw(rt, a.base(), a.disp()); aoqi@1: #endif aoqi@1: } aoqi@1: inline void ld_ptr(Register rt, Register base, int offset16){ aoqi@1: #ifdef _LP64 aoqi@1: ld(rt, base, offset16); aoqi@1: #else aoqi@1: lw(rt, base, offset16); aoqi@1: #endif aoqi@1: aoqi@1: } aoqi@1: inline void st_ptr(Register rt, Address a){ aoqi@1: #ifdef _LP64 aoqi@1: sd(rt, a.base(), a.disp()); aoqi@1: #else aoqi@1: sw(rt, a.base(), a.disp()); aoqi@1: #endif aoqi@1: } aoqi@1: inline void st_ptr(Register rt, Register base, int offset16) { aoqi@1: #ifdef _LP64 aoqi@1: sd(rt, base, offset16); aoqi@1: #else aoqi@1: sw(rt, base, offset16); aoqi@1: #endif aoqi@1: aoqi@1: } aoqi@1: aoqi@1: void ld_ptr(Register rt, Register offset, Register base); aoqi@1: void st_ptr(Register rt, Register offset, Register base); aoqi@1: aoqi@1: // ld_long will perform lw for 32 bit VMs and ld for 64 bit VMs aoqi@1: // st_long will perform sw for 32 bit VMs and sd for 64 bit VMs aoqi@1: inline void ld_long(Register rt, Register base, int offset16); aoqi@1: inline void st_long(Register rt, Register base, int offset16); aoqi@1: inline void ld_long(Register rt, Address a); aoqi@1: inline void st_long(Register rt, Address a); aoqi@1: aoqi@1: aoqi@1: void ld_long(Register rt, Register offset, Register base); aoqi@1: void st_long(Register rt, Register offset, Register base); aoqi@1: // Regular vs. d* versions aoqi@1: inline void addu_long(Register rd, Register rs, Register rt) { aoqi@1: #ifdef _LP64 aoqi@1: daddu(rd, rs, rt); aoqi@1: #else aoqi@1: addu(rd, rs, rt); aoqi@1: #endif aoqi@1: } aoqi@1: inline void addu_long(Register rd, Register rs, long imm32_64) { aoqi@1: #ifdef _LP64 aoqi@1: daddiu(rd, rs, imm32_64); aoqi@1: #else aoqi@1: addiu(rd, rs, imm32_64); aoqi@1: #endif aoqi@1: aoqi@1: } aoqi@1: aoqi@1: // Floating aoqi@1: public: aoqi@1: // swap the two byte of the low 16-bit halfword aoqi@1: // this directive will use AT, be sure the high 16-bit of reg is zero aoqi@1: // by yjl 6/28/2005 aoqi@1: void hswap(Register reg); aoqi@1: void huswap(Register reg); aoqi@1: aoqi@1: // convert big endian integer to little endian integer aoqi@1: // by yjl 6/29/2005 aoqi@1: void swap(Register reg); aoqi@1: aoqi@1: // implement the x86 instruction semantic aoqi@1: // if c_reg == *dest then *dest <= x_reg aoqi@1: // else c_reg <= *dest aoqi@1: // the AT indicate if xchg occurred, 1 for xchged, else 0 aoqi@1: // by yjl 6/28/2005 aoqi@1: void cmpxchg(Register x_reg, Address dest, Register c_reg); aoqi@1: #ifdef _LP64 aoqi@1: void cmpxchg32(Register x_reg, Address dest, Register c_reg); aoqi@1: #endif aoqi@1: void cmpxchg8(Register x_regLo, Register x_regHi, Address dest, Register c_regLo, Register c_regHi); aoqi@1: aoqi@1: aoqi@1: aoqi@1: void round_to(Register reg, int modulus) { aoqi@1: assert_different_registers(reg, AT); aoqi@1: increment(reg, modulus - 1); aoqi@1: move(AT, - modulus); aoqi@1: andr(reg, reg, AT); aoqi@1: } aoqi@1: aoqi@1: //pop & push, added by aoqi aoqi@1: #ifdef _LP64 aoqi@1: void extend_sign(Register rh, Register rl) { stop("extend_sign"); } aoqi@1: void neg(Register reg) { dsubu(reg, R0, reg); } aoqi@1: void push (Register reg) { sd (reg, SP, -8); daddi(SP, SP, -8); } aoqi@1: void push (FloatRegister reg) { sdc1(reg, SP, -8); daddi(SP, SP, -8); } aoqi@1: void pop (Register reg) { ld (reg, SP, 0); daddi(SP, SP, 8); } aoqi@1: void pop (FloatRegister reg) { ldc1(reg, SP, 0); daddi(SP, SP, 8); } aoqi@1: void pop () { daddi(SP, SP, 8); } aoqi@1: void pop2 () { daddi(SP, SP, 16); } aoqi@1: #else aoqi@1: void extend_sign(Register rh, Register rl) { sra(rh, rl, 31); } aoqi@1: void neg(Register reg) { subu(reg, R0, reg); } aoqi@1: void push (Register reg) { sw (reg, SP, -4); addi(SP, SP, -4); } aoqi@1: void push (FloatRegister reg) { swc1(reg, SP, -4); addi(SP, SP, -4); } aoqi@1: void pop (Register reg) { lw (reg, SP, 0); addi(SP, SP, 4); } aoqi@1: void pop (FloatRegister reg) { lwc1(reg, SP, 0); addi(SP, SP, 4); } aoqi@1: void pop () { addi(SP, SP, 4); } aoqi@1: void pop2 () { addi(SP, SP, 8); } aoqi@1: #endif aoqi@1: void push2(Register reg1, Register reg2); aoqi@1: void pop2 (Register reg1, Register reg2); aoqi@1: void dpush (Register reg) { sd (reg, SP, -8); daddi(SP, SP, -8); } aoqi@1: void dpop (Register reg) { ld (reg, SP, 0); daddi(SP, SP, 8); } aoqi@1: aoqi@1: /* branches may exceed 16-bit offset */ aoqi@1: void b_far(address entry); aoqi@1: void b_far(Label& L); aoqi@1: aoqi@1: void bne_far (Register rs, Register rt, address entry); aoqi@1: void bne_far (Register rs, Register rt, Label& L); aoqi@1: aoqi@1: void beq_far (Register rs, Register rt, address entry); aoqi@1: void beq_far (Register rs, Register rt, Label& L); aoqi@1: aoqi@1: //move an 32-bit immediate to Register aoqi@1: void move(Register reg, int imm32) { li32(reg, imm32); } aoqi@1: void li (Register rd, long imm); aoqi@1: void li (Register rd, address addr) { li(rd, (long)addr); } aoqi@1: //replace move(Register reg, int imm) aoqi@1: void li32(Register rd, int imm32); // sign-extends to 64 bits on mips64 aoqi@1: #ifdef _LP64 aoqi@1: void dli(Register rd, long imm) { li(rd, imm); } aoqi@1: void li64(Register rd, long imm); aoqi@1: void li48(Register rd, long imm); aoqi@1: #endif aoqi@1: aoqi@1: #ifdef _LP64 aoqi@1: void move(Register rd, Register rs) { dadd(rd, rs, R0); } aoqi@1: void move_u32(Register rd, Register rs) { addu32(rd, rs, R0); } aoqi@1: #else aoqi@1: void move(Register rd, Register rs) { add(rd, rs, R0); } aoqi@1: #endif aoqi@1: void dmove(Register rd, Register rs) { dadd(rd, rs, R0); } aoqi@1: aoqi@1: #ifdef _LP64 aoqi@1: void shl(Register reg, int sa) { dsll(reg, reg, sa); } aoqi@1: void shr(Register reg, int sa) { dsrl(reg, reg, sa); } aoqi@1: void sar(Register reg, int sa) { dsra(reg, reg, sa); } aoqi@1: #else aoqi@1: void shl(Register reg, int sa) { sll(reg, reg, sa); } aoqi@1: void shr(Register reg, int sa) { srl(reg, reg, sa); } aoqi@1: void sar(Register reg, int sa) { sra(reg, reg, sa); } aoqi@1: #endif aoqi@1: aoqi@1: #ifndef PRODUCT aoqi@1: static void pd_print_patched_instruction(address branch) { aoqi@1: jint stub_inst = *(jint*) branch; aoqi@1: print_instruction(stub_inst); aoqi@1: ::tty->print("%s", " (unresolved)"); aoqi@1: aoqi@1: } aoqi@1: #endif aoqi@1: aoqi@1: // the follow two might use AT register, be sure you have no meanful data in AT before you call them aoqi@1: // by yjl 6/23/2005 aoqi@1: void increment(Register reg, int imm); aoqi@1: void decrement(Register reg, int imm); aoqi@1: aoqi@1: //FIXME aoqi@1: void empty_FPU_stack(){/*need implemented*/}; aoqi@1: aoqi@1: //we need 2 fun to save and resotre general register aoqi@1: void pushad(); aoqi@1: void popad(); aoqi@1: aoqi@1: void load_two_bytes_from_at_bcp(Register reg, Register tmp, int offset); aoqi@1: void store_two_byts_to_at_bcp(Register reg, Register tmp, int offset); aoqi@1: // Test sub_klass against super_klass, with fast and slow paths. aoqi@1: aoqi@1: // The fast path produces a tri-state answer: yes / no / maybe-slow. aoqi@1: // One of the three labels can be NULL, meaning take the fall-through. aoqi@1: // If super_check_offset is -1, the value is loaded up from super_klass. aoqi@1: // No registers are killed, except temp_reg. aoqi@1: void check_klass_subtype_fast_path(Register sub_klass, aoqi@1: Register super_klass, aoqi@1: Register temp_reg, aoqi@1: Label* L_success, aoqi@1: Label* L_failure, aoqi@1: Label* L_slow_path, aoqi@1: RegisterOrConstant super_check_offset = RegisterOrConstant(-1)); aoqi@1: aoqi@1: // The rest of the type check; must be wired to a corresponding fast path. aoqi@1: // It does not repeat the fast path logic, so don't use it standalone. aoqi@1: // The temp_reg and temp2_reg can be noreg, if no temps are available. aoqi@1: // Updates the sub's secondary super cache as necessary. aoqi@1: // If set_cond_codes, condition codes will be Z on success, NZ on failure. aoqi@1: void check_klass_subtype_slow_path(Register sub_klass, aoqi@1: Register super_klass, aoqi@1: Register temp_reg, aoqi@1: Register temp2_reg, aoqi@1: Label* L_success, aoqi@1: Label* L_failure, aoqi@1: bool set_cond_codes = false); aoqi@1: aoqi@1: // Simplified, combined version, good for typical uses. aoqi@1: // Falls through on failure. aoqi@1: void check_klass_subtype(Register sub_klass, aoqi@1: Register super_klass, aoqi@1: Register temp_reg, aoqi@1: Label& L_success); aoqi@1: aoqi@1: // method handles (JSR 292) aoqi@1: Address argument_address(RegisterOrConstant arg_slot, int extra_slot_offset = 0); aoqi@1: aoqi@1: void get_vm_result (Register oop_result, Register thread); aoqi@1: void get_vm_result_2(Register metadata_result, Register thread); aoqi@1: #undef VIRTUAL aoqi@1: aoqi@1: }; aoqi@1: aoqi@1: /** aoqi@1: * class SkipIfEqual: aoqi@1: * aoqi@1: * Instantiating this class will result in assembly code being output that will aoqi@1: * jump around any code emitted between the creation of the instance and it's aoqi@1: * automatic destruction at the end of a scope block, depending on the value of aoqi@1: * the flag passed to the constructor, which will be checked at run-time. aoqi@1: */ aoqi@1: class SkipIfEqual { aoqi@1: private: aoqi@1: MacroAssembler* _masm; aoqi@1: Label _label; aoqi@1: aoqi@1: public: aoqi@1: SkipIfEqual(MacroAssembler*, const bool* flag_addr, bool value); aoqi@1: ~SkipIfEqual(); aoqi@1: }; aoqi@1: aoqi@1: #ifdef ASSERT aoqi@1: inline bool AbstractAssembler::pd_check_instruction_mark() { return true; } aoqi@1: #endif aoqi@1: aoqi@1: #endif // CPU_MIPS_VM_ASSEMBLER_MIPS_HPP