Tue, 28 Jun 2016 16:34:47 +0800
[Code Reorganization] Moved fast_lock and fast_unlock from mips_64.ad to MacroAssembler.
aoqi@1 | 1 | /* |
aoqi@1 | 2 | * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. |
aoqi@1 | 3 | * Copyright (c) 2015, 2016, Loongson Technology. All rights reserved. |
aoqi@1 | 4 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
aoqi@1 | 5 | * |
aoqi@1 | 6 | * This code is free software; you can redistribute it and/or modify it |
aoqi@1 | 7 | * under the terms of the GNU General Public License version 2 only, as |
aoqi@1 | 8 | * published by the Free Software Foundation. |
aoqi@1 | 9 | * |
aoqi@1 | 10 | * This code is distributed in the hope that it will be useful, but WITHOUT |
aoqi@1 | 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
aoqi@1 | 12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
aoqi@1 | 13 | * version 2 for more details (a copy is included in the LICENSE file that |
aoqi@1 | 14 | * accompanied this code). |
aoqi@1 | 15 | * |
aoqi@1 | 16 | * You should have received a copy of the GNU General Public License version |
aoqi@1 | 17 | * 2 along with this work; if not, write to the Free Software Foundation, |
aoqi@1 | 18 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
aoqi@1 | 19 | * |
aoqi@1 | 20 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
aoqi@1 | 21 | * or visit www.oracle.com if you need additional information or have any |
aoqi@1 | 22 | * questions. |
aoqi@1 | 23 | * |
aoqi@1 | 24 | */ |
aoqi@1 | 25 | |
aoqi@1 | 26 | #ifndef CPU_MIPS_VM_ASSEMBLER_MIPS_HPP |
aoqi@1 | 27 | #define CPU_MIPS_VM_ASSEMBLER_MIPS_HPP |
aoqi@1 | 28 | |
aoqi@1 | 29 | #include "asm/register.hpp" |
aoqi@1 | 30 | |
aoqi@1 | 31 | class BiasedLockingCounters; |
aoqi@1 | 32 | |
aoqi@1 | 33 | |
aoqi@1 | 34 | // Note: A register location is represented via a Register, not |
aoqi@1 | 35 | // via an address for efficiency & simplicity reasons. |
aoqi@1 | 36 | |
aoqi@1 | 37 | class ArrayAddress; |
aoqi@1 | 38 | |
aoqi@1 | 39 | class Address VALUE_OBJ_CLASS_SPEC { |
aoqi@1 | 40 | |
aoqi@1 | 41 | public: |
aoqi@1 | 42 | enum ScaleFactor { |
aoqi@1 | 43 | no_scale = -1, |
aoqi@1 | 44 | times_1 = 0, |
aoqi@1 | 45 | times_2 = 1, |
aoqi@1 | 46 | times_4 = 2, |
aoqi@1 | 47 | times_8 = 3, |
aoqi@1 | 48 | times_ptr = LP64_ONLY(times_8) NOT_LP64(times_4) |
aoqi@1 | 49 | }; |
aoqi@1 | 50 | |
aoqi@1 | 51 | static ScaleFactor times(int size) { |
aoqi@1 | 52 | assert(size >= 1 && size <= 8 && is_power_of_2(size), "bad scale size"); |
aoqi@1 | 53 | if (size == 8) return times_8; |
aoqi@1 | 54 | if (size == 4) return times_4; |
aoqi@1 | 55 | if (size == 2) return times_2; |
aoqi@1 | 56 | return times_1; |
aoqi@1 | 57 | } |
aoqi@1 | 58 | |
aoqi@1 | 59 | private: |
aoqi@1 | 60 | Register _base; |
aoqi@1 | 61 | Register _index; |
aoqi@1 | 62 | ScaleFactor _scale; |
aoqi@1 | 63 | int _disp; |
aoqi@1 | 64 | RelocationHolder _rspec; |
aoqi@1 | 65 | |
aoqi@1 | 66 | // Easily misused constructors make them private |
aoqi@1 | 67 | // %%% can we make these go away? |
aoqi@1 | 68 | //FIXME aoqi |
aoqi@1 | 69 | //NOT_LP64(Address(address loc, RelocationHolder spec);) |
aoqi@1 | 70 | Address(address loc, RelocationHolder spec); |
aoqi@1 | 71 | Address(int disp, address loc, relocInfo::relocType rtype); |
aoqi@1 | 72 | Address(int disp, address loc, RelocationHolder spec); |
aoqi@1 | 73 | |
aoqi@1 | 74 | public: |
aoqi@1 | 75 | |
aoqi@1 | 76 | int disp() { return _disp; } |
aoqi@1 | 77 | // creation |
aoqi@1 | 78 | Address() |
aoqi@1 | 79 | : _base(noreg), |
aoqi@1 | 80 | _index(noreg), |
aoqi@1 | 81 | _scale(no_scale), |
aoqi@1 | 82 | _disp(0) { |
aoqi@1 | 83 | } |
aoqi@1 | 84 | |
aoqi@1 | 85 | // No default displacement otherwise Register can be implicitly |
aoqi@1 | 86 | // converted to 0(Register) which is quite a different animal. |
aoqi@1 | 87 | |
aoqi@1 | 88 | Address(Register base, int disp) |
aoqi@1 | 89 | : _base(base), |
aoqi@1 | 90 | _index(noreg), |
aoqi@1 | 91 | _scale(no_scale), |
aoqi@1 | 92 | _disp(disp) { |
aoqi@1 | 93 | } |
aoqi@1 | 94 | |
aoqi@1 | 95 | Address(Register base) |
aoqi@1 | 96 | : _base(base), |
aoqi@1 | 97 | _index(noreg), |
aoqi@1 | 98 | _scale(no_scale), |
aoqi@1 | 99 | _disp(0) { |
aoqi@1 | 100 | } |
aoqi@1 | 101 | |
aoqi@1 | 102 | Address(Register base, Register index, ScaleFactor scale, int disp = 0) |
aoqi@1 | 103 | : _base (base), |
aoqi@1 | 104 | _index(index), |
aoqi@1 | 105 | _scale(scale), |
aoqi@1 | 106 | _disp (disp) { |
aoqi@1 | 107 | assert(!index->is_valid() == (scale == Address::no_scale), |
aoqi@1 | 108 | "inconsistent address"); |
aoqi@1 | 109 | } |
aoqi@1 | 110 | |
aoqi@1 | 111 | // The following two overloads are used in connection with the |
aoqi@1 | 112 | // ByteSize type (see sizes.hpp). They simplify the use of |
aoqi@1 | 113 | // ByteSize'd arguments in assembly code. Note that their equivalent |
aoqi@1 | 114 | // for the optimized build are the member functions with int disp |
aoqi@1 | 115 | // argument since ByteSize is mapped to an int type in that case. |
aoqi@1 | 116 | // |
aoqi@1 | 117 | // Note: DO NOT introduce similar overloaded functions for WordSize |
aoqi@1 | 118 | // arguments as in the optimized mode, both ByteSize and WordSize |
aoqi@1 | 119 | // are mapped to the same type and thus the compiler cannot make a |
aoqi@1 | 120 | // distinction anymore (=> compiler errors). |
aoqi@1 | 121 | |
aoqi@1 | 122 | #ifdef ASSERT |
aoqi@1 | 123 | Address(Register base, ByteSize disp) |
aoqi@1 | 124 | : _base(base), |
aoqi@1 | 125 | _index(noreg), |
aoqi@1 | 126 | _scale(no_scale), |
aoqi@1 | 127 | _disp(in_bytes(disp)) { |
aoqi@1 | 128 | } |
aoqi@1 | 129 | |
aoqi@1 | 130 | Address(Register base, Register index, ScaleFactor scale, ByteSize disp) |
aoqi@1 | 131 | : _base(base), |
aoqi@1 | 132 | _index(index), |
aoqi@1 | 133 | _scale(scale), |
aoqi@1 | 134 | _disp(in_bytes(disp)) { |
aoqi@1 | 135 | assert(!index->is_valid() == (scale == Address::no_scale), |
aoqi@1 | 136 | "inconsistent address"); |
aoqi@1 | 137 | } |
aoqi@1 | 138 | #endif // ASSERT |
aoqi@1 | 139 | |
aoqi@1 | 140 | // accessors |
aoqi@1 | 141 | bool uses(Register reg) const { return _base == reg || _index == reg; } |
aoqi@1 | 142 | Register base() const { return _base; } |
aoqi@1 | 143 | Register index() const { return _index; } |
aoqi@1 | 144 | ScaleFactor scale() const { return _scale; } |
aoqi@1 | 145 | int disp() const { return _disp; } |
aoqi@1 | 146 | |
aoqi@1 | 147 | // Convert the raw encoding form into the form expected by the constructor for |
aoqi@1 | 148 | // Address. An index of 4 (rsp) corresponds to having no index, so convert |
aoqi@1 | 149 | // that to noreg for the Address constructor. |
aoqi@1 | 150 | //static Address make_raw(int base, int index, int scale, int disp); |
aoqi@1 | 151 | |
aoqi@1 | 152 | static Address make_array(ArrayAddress); |
aoqi@1 | 153 | |
aoqi@1 | 154 | /* |
aoqi@1 | 155 | private: |
aoqi@1 | 156 | bool base_needs_rex() const { |
aoqi@1 | 157 | return _base != noreg && _base->encoding() >= 8; |
aoqi@1 | 158 | } |
aoqi@1 | 159 | |
aoqi@1 | 160 | bool index_needs_rex() const { |
aoqi@1 | 161 | return _index != noreg &&_index->encoding() >= 8; |
aoqi@1 | 162 | } |
aoqi@1 | 163 | |
aoqi@1 | 164 | relocInfo::relocType reloc() const { return _rspec.type(); } |
aoqi@1 | 165 | */ |
aoqi@1 | 166 | friend class Assembler; |
aoqi@1 | 167 | friend class MacroAssembler; |
aoqi@1 | 168 | friend class LIR_Assembler; // base/index/scale/disp |
aoqi@1 | 169 | }; |
aoqi@1 | 170 | |
aoqi@1 | 171 | |
aoqi@1 | 172 | // Calling convention |
aoqi@1 | 173 | class Argument VALUE_OBJ_CLASS_SPEC { |
aoqi@1 | 174 | private: |
aoqi@1 | 175 | int _number; |
aoqi@1 | 176 | public: |
aoqi@1 | 177 | enum { |
aoqi@1 | 178 | #ifdef _LP64 |
aoqi@1 | 179 | n_register_parameters = 8, // 8 integer registers used to pass parameters |
aoqi@1 | 180 | n_float_register_parameters = 8 // 4 float registers used to pass parameters |
aoqi@1 | 181 | #else |
aoqi@1 | 182 | n_register_parameters = 4, // 4 integer registers used to pass parameters |
aoqi@1 | 183 | n_float_register_parameters = 4 // 4 float registers used to pass parameters |
aoqi@1 | 184 | #endif |
aoqi@1 | 185 | }; |
aoqi@1 | 186 | |
aoqi@1 | 187 | Argument(int number):_number(number){ } |
aoqi@1 | 188 | Argument successor() {return Argument(number() + 1);} |
aoqi@1 | 189 | |
aoqi@1 | 190 | int number()const {return _number;} |
aoqi@1 | 191 | bool is_Register()const {return _number < n_register_parameters;} |
aoqi@1 | 192 | bool is_FloatRegister()const {return _number < n_float_register_parameters;} |
aoqi@1 | 193 | |
aoqi@1 | 194 | Register as_Register()const { |
aoqi@1 | 195 | assert(is_Register(), "must be a register argument"); |
aoqi@1 | 196 | return ::as_Register(A0->encoding() + _number); |
aoqi@1 | 197 | } |
aoqi@1 | 198 | FloatRegister as_FloatRegister()const { |
aoqi@1 | 199 | assert(is_FloatRegister(), "must be a float register argument"); |
aoqi@1 | 200 | return ::as_FloatRegister(F12->encoding() + _number); |
aoqi@1 | 201 | } |
aoqi@1 | 202 | |
aoqi@1 | 203 | Address as_caller_address()const {return Address(SP, (number() LP64_ONLY( -n_register_parameters)) * wordSize);} |
aoqi@1 | 204 | }; |
aoqi@1 | 205 | |
aoqi@1 | 206 | |
aoqi@1 | 207 | |
aoqi@1 | 208 | // |
aoqi@1 | 209 | // AddressLiteral has been split out from Address because operands of this type |
aoqi@1 | 210 | // need to be treated specially on 32bit vs. 64bit platforms. By splitting it out |
aoqi@1 | 211 | // the few instructions that need to deal with address literals are unique and the |
aoqi@1 | 212 | // MacroAssembler does not have to implement every instruction in the Assembler |
aoqi@1 | 213 | // in order to search for address literals that may need special handling depending |
aoqi@1 | 214 | // on the instruction and the platform. As small step on the way to merging i486/amd64 |
aoqi@1 | 215 | // directories. |
aoqi@1 | 216 | // |
aoqi@1 | 217 | class AddressLiteral VALUE_OBJ_CLASS_SPEC { |
aoqi@1 | 218 | friend class ArrayAddress; |
aoqi@1 | 219 | RelocationHolder _rspec; |
aoqi@1 | 220 | // Typically we use AddressLiterals we want to use their rval |
aoqi@1 | 221 | // However in some situations we want the lval (effect address) of the item. |
aoqi@1 | 222 | // We provide a special factory for making those lvals. |
aoqi@1 | 223 | bool _is_lval; |
aoqi@1 | 224 | |
aoqi@1 | 225 | // If the target is far we'll need to load the ea of this to |
aoqi@1 | 226 | // a register to reach it. Otherwise if near we can do rip |
aoqi@1 | 227 | // relative addressing. |
aoqi@1 | 228 | |
aoqi@1 | 229 | address _target; |
aoqi@1 | 230 | |
aoqi@1 | 231 | protected: |
aoqi@1 | 232 | // creation |
aoqi@1 | 233 | AddressLiteral() |
aoqi@1 | 234 | : _is_lval(false), |
aoqi@1 | 235 | _target(NULL) |
aoqi@1 | 236 | {} |
aoqi@1 | 237 | |
aoqi@1 | 238 | public: |
aoqi@1 | 239 | |
aoqi@1 | 240 | AddressLiteral(address target, relocInfo::relocType rtype); |
aoqi@1 | 241 | |
aoqi@1 | 242 | AddressLiteral(address target, RelocationHolder const& rspec) |
aoqi@1 | 243 | : _rspec(rspec), |
aoqi@1 | 244 | _is_lval(false), |
aoqi@1 | 245 | _target(target) |
aoqi@1 | 246 | {} |
aoqi@1 | 247 | #ifdef _LP64 |
aoqi@1 | 248 | // 32-bit complains about a multiple declaration for int*. |
aoqi@1 | 249 | AddressLiteral(intptr_t* addr, relocInfo::relocType rtype = relocInfo::none) |
aoqi@1 | 250 | : _target((address) addr), |
aoqi@1 | 251 | _rspec(rspec_from_rtype(rtype, (address) addr)) {} |
aoqi@1 | 252 | #endif |
aoqi@1 | 253 | |
aoqi@1 | 254 | |
aoqi@1 | 255 | AddressLiteral addr() { |
aoqi@1 | 256 | AddressLiteral ret = *this; |
aoqi@1 | 257 | ret._is_lval = true; |
aoqi@1 | 258 | return ret; |
aoqi@1 | 259 | } |
aoqi@1 | 260 | |
aoqi@1 | 261 | |
aoqi@1 | 262 | private: |
aoqi@1 | 263 | |
aoqi@1 | 264 | address target() { return _target; } |
aoqi@1 | 265 | bool is_lval() { return _is_lval; } |
aoqi@1 | 266 | |
aoqi@1 | 267 | relocInfo::relocType reloc() const { return _rspec.type(); } |
aoqi@1 | 268 | const RelocationHolder& rspec() const { return _rspec; } |
aoqi@1 | 269 | |
aoqi@1 | 270 | friend class Assembler; |
aoqi@1 | 271 | friend class MacroAssembler; |
aoqi@1 | 272 | friend class Address; |
aoqi@1 | 273 | friend class LIR_Assembler; |
aoqi@1 | 274 | RelocationHolder rspec_from_rtype(relocInfo::relocType rtype, address addr) { |
aoqi@1 | 275 | switch (rtype) { |
aoqi@1 | 276 | case relocInfo::external_word_type: |
aoqi@1 | 277 | return external_word_Relocation::spec(addr); |
aoqi@1 | 278 | case relocInfo::internal_word_type: |
aoqi@1 | 279 | return internal_word_Relocation::spec(addr); |
aoqi@1 | 280 | case relocInfo::opt_virtual_call_type: |
aoqi@1 | 281 | return opt_virtual_call_Relocation::spec(); |
aoqi@1 | 282 | case relocInfo::static_call_type: |
aoqi@1 | 283 | return static_call_Relocation::spec(); |
aoqi@1 | 284 | case relocInfo::runtime_call_type: |
aoqi@1 | 285 | return runtime_call_Relocation::spec(); |
aoqi@1 | 286 | case relocInfo::poll_type: |
aoqi@1 | 287 | case relocInfo::poll_return_type: |
aoqi@1 | 288 | return Relocation::spec_simple(rtype); |
aoqi@1 | 289 | case relocInfo::none: |
aoqi@1 | 290 | case relocInfo::oop_type: |
aoqi@1 | 291 | // Oops are a special case. Normally they would be their own section |
aoqi@1 | 292 | // but in cases like icBuffer they are literals in the code stream that |
aoqi@1 | 293 | // we don't have a section for. We use none so that we get a literal address |
aoqi@1 | 294 | // which is always patchable. |
aoqi@1 | 295 | return RelocationHolder(); |
aoqi@1 | 296 | default: |
aoqi@1 | 297 | ShouldNotReachHere(); |
aoqi@1 | 298 | return RelocationHolder(); |
aoqi@1 | 299 | } |
aoqi@1 | 300 | } |
aoqi@1 | 301 | |
aoqi@1 | 302 | }; |
aoqi@1 | 303 | |
aoqi@1 | 304 | // Convience classes |
aoqi@1 | 305 | class RuntimeAddress: public AddressLiteral { |
aoqi@1 | 306 | |
aoqi@1 | 307 | public: |
aoqi@1 | 308 | |
aoqi@1 | 309 | RuntimeAddress(address target) : AddressLiteral(target, relocInfo::runtime_call_type) {} |
aoqi@1 | 310 | |
aoqi@1 | 311 | }; |
aoqi@1 | 312 | |
aoqi@1 | 313 | class OopAddress: public AddressLiteral { |
aoqi@1 | 314 | |
aoqi@1 | 315 | public: |
aoqi@1 | 316 | |
aoqi@1 | 317 | OopAddress(address target) : AddressLiteral(target, relocInfo::oop_type){} |
aoqi@1 | 318 | |
aoqi@1 | 319 | }; |
aoqi@1 | 320 | |
aoqi@1 | 321 | class ExternalAddress: public AddressLiteral { |
aoqi@1 | 322 | |
aoqi@1 | 323 | public: |
aoqi@1 | 324 | |
aoqi@1 | 325 | ExternalAddress(address target) : AddressLiteral(target, relocInfo::external_word_type){} |
aoqi@1 | 326 | |
aoqi@1 | 327 | }; |
aoqi@1 | 328 | |
aoqi@1 | 329 | class InternalAddress: public AddressLiteral { |
aoqi@1 | 330 | |
aoqi@1 | 331 | public: |
aoqi@1 | 332 | |
aoqi@1 | 333 | InternalAddress(address target) : AddressLiteral(target, relocInfo::internal_word_type) {} |
aoqi@1 | 334 | |
aoqi@1 | 335 | }; |
aoqi@1 | 336 | |
aoqi@1 | 337 | // x86 can do array addressing as a single operation since disp can be an absolute |
aoqi@1 | 338 | // address amd64 can't. We create a class that expresses the concept but does extra |
aoqi@1 | 339 | // magic on amd64 to get the final result |
aoqi@1 | 340 | |
aoqi@1 | 341 | class ArrayAddress VALUE_OBJ_CLASS_SPEC { |
aoqi@1 | 342 | private: |
aoqi@1 | 343 | |
aoqi@1 | 344 | AddressLiteral _base; |
aoqi@1 | 345 | Address _index; |
aoqi@1 | 346 | |
aoqi@1 | 347 | public: |
aoqi@1 | 348 | |
aoqi@1 | 349 | ArrayAddress() {}; |
aoqi@1 | 350 | ArrayAddress(AddressLiteral base, Address index): _base(base), _index(index) {}; |
aoqi@1 | 351 | AddressLiteral base() { return _base; } |
aoqi@1 | 352 | Address index() { return _index; } |
aoqi@1 | 353 | |
aoqi@1 | 354 | }; |
aoqi@1 | 355 | |
aoqi@1 | 356 | const int FPUStateSizeInWords = NOT_LP64(27) LP64_ONLY( 512 / wordSize); |
aoqi@1 | 357 | |
aoqi@1 | 358 | // The MIPS LOONGSON Assembler: Pure assembler doing NO optimizations on the instruction |
aoqi@1 | 359 | // level ; i.e., what you write is what you get. The Assembler is generating code into |
aoqi@1 | 360 | // a CodeBuffer. |
aoqi@1 | 361 | |
aoqi@1 | 362 | class Assembler : public AbstractAssembler { |
aoqi@1 | 363 | friend class AbstractAssembler; // for the non-virtual hack |
aoqi@1 | 364 | friend class LIR_Assembler; // as_Address() |
aoqi@1 | 365 | friend class StubGenerator; |
aoqi@1 | 366 | |
aoqi@1 | 367 | public: |
aoqi@1 | 368 | enum ops { |
aoqi@1 | 369 | special_op = 0x00, |
aoqi@1 | 370 | regimm_op = 0x01, |
aoqi@1 | 371 | j_op = 0x02, |
aoqi@1 | 372 | jal_op = 0x03, |
aoqi@1 | 373 | beq_op = 0x04, |
aoqi@1 | 374 | bne_op = 0x05, |
aoqi@1 | 375 | blez_op = 0x06, |
aoqi@1 | 376 | bgtz_op = 0x07, |
aoqi@1 | 377 | addi_op = 0x08, |
aoqi@1 | 378 | addiu_op = 0x09, |
aoqi@1 | 379 | slti_op = 0x0a, |
aoqi@1 | 380 | sltiu_op = 0x0b, |
aoqi@1 | 381 | andi_op = 0x0c, |
aoqi@1 | 382 | ori_op = 0x0d, |
aoqi@1 | 383 | xori_op = 0x0e, |
aoqi@1 | 384 | lui_op = 0x0f, |
aoqi@1 | 385 | cop0_op = 0x10, |
aoqi@1 | 386 | cop1_op = 0x11, |
aoqi@1 | 387 | cop2_op = 0x12, |
aoqi@1 | 388 | cop3_op = 0x13, |
aoqi@1 | 389 | beql_op = 0x14, |
aoqi@1 | 390 | bnel_op = 0x15, |
aoqi@1 | 391 | blezl_op = 0x16, |
aoqi@1 | 392 | bgtzl_op = 0x17, |
aoqi@1 | 393 | daddi_op = 0x18, |
aoqi@1 | 394 | daddiu_op = 0x19, |
aoqi@1 | 395 | ldl_op = 0x1a, |
aoqi@1 | 396 | ldr_op = 0x1b, |
aoqi@1 | 397 | lb_op = 0x20, |
aoqi@1 | 398 | lh_op = 0x21, |
aoqi@1 | 399 | lwl_op = 0x22, |
aoqi@1 | 400 | lw_op = 0x23, |
aoqi@1 | 401 | lbu_op = 0x24, |
aoqi@1 | 402 | lhu_op = 0x25, |
aoqi@1 | 403 | lwr_op = 0x26, |
aoqi@1 | 404 | lwu_op = 0x27, |
aoqi@1 | 405 | sb_op = 0x28, |
aoqi@1 | 406 | sh_op = 0x29, |
aoqi@1 | 407 | swl_op = 0x2a, |
aoqi@1 | 408 | sw_op = 0x2b, |
aoqi@1 | 409 | sdl_op = 0x2c, |
aoqi@1 | 410 | sdr_op = 0x2d, |
aoqi@1 | 411 | swr_op = 0x2e, |
aoqi@1 | 412 | cache_op = 0x2f, |
aoqi@1 | 413 | ll_op = 0x30, |
aoqi@1 | 414 | lwc1_op = 0x31, |
aoqi@1 | 415 | lld_op = 0x34, |
aoqi@1 | 416 | ldc1_op = 0x35, |
aoqi@1 | 417 | ld_op = 0x37, |
aoqi@1 | 418 | sc_op = 0x38, |
aoqi@1 | 419 | swc1_op = 0x39, |
aoqi@1 | 420 | scd_op = 0x3c, |
aoqi@1 | 421 | sdc1_op = 0x3d, |
aoqi@1 | 422 | sd_op = 0x3f |
aoqi@1 | 423 | }; |
aoqi@1 | 424 | |
aoqi@1 | 425 | static const char *ops_name[]; |
aoqi@1 | 426 | |
aoqi@1 | 427 | //special family, the opcode is in low 6 bits. |
aoqi@1 | 428 | enum special_ops { |
aoqi@1 | 429 | sll_op = 0x00, |
aoqi@1 | 430 | srl_op = 0x02, |
aoqi@1 | 431 | sra_op = 0x03, |
aoqi@1 | 432 | sllv_op = 0x04, |
aoqi@1 | 433 | srlv_op = 0x06, |
aoqi@1 | 434 | srav_op = 0x07, |
aoqi@1 | 435 | jr_op = 0x08, |
aoqi@1 | 436 | jalr_op = 0x09, |
aoqi@1 | 437 | syscall_op = 0x0c, |
aoqi@1 | 438 | break_op = 0x0d, |
aoqi@1 | 439 | sync_op = 0x0f, |
aoqi@1 | 440 | mfhi_op = 0x10, |
aoqi@1 | 441 | mthi_op = 0x11, |
aoqi@1 | 442 | mflo_op = 0x12, |
aoqi@1 | 443 | mtlo_op = 0x13, |
aoqi@1 | 444 | dsllv_op = 0x14, |
aoqi@1 | 445 | dsrlv_op = 0x16, |
aoqi@1 | 446 | dsrav_op = 0x17, |
aoqi@1 | 447 | mult_op = 0x18, |
aoqi@1 | 448 | multu_op = 0x19, |
aoqi@1 | 449 | div_op = 0x1a, |
aoqi@1 | 450 | divu_op = 0x1b, |
aoqi@1 | 451 | dmult_op = 0x1c, |
aoqi@1 | 452 | dmultu_op = 0x1d, |
aoqi@1 | 453 | ddiv_op = 0x1e, |
aoqi@1 | 454 | ddivu_op = 0x1f, |
aoqi@1 | 455 | add_op = 0x20, |
aoqi@1 | 456 | addu_op = 0x21, |
aoqi@1 | 457 | sub_op = 0x22, |
aoqi@1 | 458 | subu_op = 0x23, |
aoqi@1 | 459 | and_op = 0x24, |
aoqi@1 | 460 | or_op = 0x25, |
aoqi@1 | 461 | xor_op = 0x26, |
aoqi@1 | 462 | nor_op = 0x27, |
aoqi@1 | 463 | slt_op = 0x2a, |
aoqi@1 | 464 | sltu_op = 0x2b, |
aoqi@1 | 465 | dadd_op = 0x2c, |
aoqi@1 | 466 | daddu_op = 0x2d, |
aoqi@1 | 467 | dsub_op = 0x2e, |
aoqi@1 | 468 | dsubu_op = 0x2f, |
aoqi@1 | 469 | tge_op = 0x30, |
aoqi@1 | 470 | tgeu_op = 0x31, |
aoqi@1 | 471 | tlt_op = 0x32, |
aoqi@1 | 472 | tltu_op = 0x33, |
aoqi@1 | 473 | teq_op = 0x34, |
aoqi@1 | 474 | tne_op = 0x36, |
aoqi@1 | 475 | dsll_op = 0x38, |
aoqi@1 | 476 | dsrl_op = 0x3a, |
aoqi@1 | 477 | dsra_op = 0x3b, |
aoqi@1 | 478 | dsll32_op = 0x3c, |
aoqi@1 | 479 | dsrl32_op = 0x3e, |
aoqi@1 | 480 | dsra32_op = 0x3f |
aoqi@1 | 481 | }; |
aoqi@1 | 482 | |
aoqi@1 | 483 | static const char* special_name[]; |
aoqi@1 | 484 | |
aoqi@1 | 485 | //regimm family, the opcode is in rt[16...20], 5 bits |
aoqi@1 | 486 | enum regimm_ops { |
aoqi@1 | 487 | bltz_op = 0x00, |
aoqi@1 | 488 | bgez_op = 0x01, |
aoqi@1 | 489 | bltzl_op = 0x02, |
aoqi@1 | 490 | bgezl_op = 0x03, |
aoqi@1 | 491 | tgei_op = 0x08, |
aoqi@1 | 492 | tgeiu_op = 0x09, |
aoqi@1 | 493 | tlti_op = 0x0a, |
aoqi@1 | 494 | tltiu_op = 0x0b, |
aoqi@1 | 495 | teqi_op = 0x0c, |
aoqi@1 | 496 | tnei_op = 0x0e, |
aoqi@1 | 497 | bltzal_op = 0x10, |
aoqi@1 | 498 | bgezal_op = 0x11, |
aoqi@1 | 499 | bltzall_op = 0x12, |
aoqi@1 | 500 | bgezall_op = 0x13, |
aoqi@1 | 501 | }; |
aoqi@1 | 502 | |
aoqi@1 | 503 | static const char* regimm_name[]; |
aoqi@1 | 504 | |
aoqi@1 | 505 | //copx family,the op in rs, 5 bits |
aoqi@1 | 506 | enum cop_ops { |
aoqi@1 | 507 | mf_op = 0x00, |
aoqi@1 | 508 | dmf_op = 0x01, |
aoqi@1 | 509 | cf_op = 0x02, |
aoqi@1 | 510 | mt_op = 0x04, |
aoqi@1 | 511 | dmt_op = 0x05, |
aoqi@1 | 512 | ct_op = 0x06, |
aoqi@1 | 513 | bc_op = 0x08, |
aoqi@1 | 514 | single_fmt = 0x10, |
aoqi@1 | 515 | double_fmt = 0x11, |
aoqi@1 | 516 | word_fmt = 0x14, |
aoqi@1 | 517 | long_fmt = 0x15 |
aoqi@1 | 518 | }; |
aoqi@1 | 519 | |
aoqi@1 | 520 | enum bc_ops { |
aoqi@1 | 521 | bcf_op = 0x00, |
aoqi@1 | 522 | bct_op = 0x01, |
aoqi@1 | 523 | bcfl_op = 0x02, |
aoqi@1 | 524 | bctl_op = 0x03, |
aoqi@1 | 525 | }; |
aoqi@1 | 526 | |
aoqi@1 | 527 | enum c_conds { |
aoqi@1 | 528 | f_cond = 0x30, |
aoqi@1 | 529 | un_cond = 0x31, |
aoqi@1 | 530 | eq_cond = 0x32, |
aoqi@1 | 531 | ueq_cond = 0x33, |
aoqi@1 | 532 | olt_cond = 0x34, |
aoqi@1 | 533 | ult_cond = 0x35, |
aoqi@1 | 534 | ole_cond = 0x36, |
aoqi@1 | 535 | ule_cond = 0x37, |
aoqi@1 | 536 | sf_cond = 0x38, |
aoqi@1 | 537 | ngle_cond = 0x39, |
aoqi@1 | 538 | seq_cond = 0x3a, |
aoqi@1 | 539 | ngl_cond = 0x3b, |
aoqi@1 | 540 | lt_cond = 0x3c, |
aoqi@1 | 541 | nge_cond = 0x3d, |
aoqi@1 | 542 | le_cond = 0x3e, |
aoqi@1 | 543 | ngt_cond = 0x3f |
aoqi@1 | 544 | }; |
aoqi@1 | 545 | |
aoqi@1 | 546 | //low 6 bits of cp1 instruction |
aoqi@1 | 547 | enum float_ops { |
aoqi@1 | 548 | fadd_op = 0x00, |
aoqi@1 | 549 | fsub_op = 0x01, |
aoqi@1 | 550 | fmul_op = 0x02, |
aoqi@1 | 551 | fdiv_op = 0x03, |
aoqi@1 | 552 | fsqrt_op = 0x04, |
aoqi@1 | 553 | fabs_op = 0x05, |
aoqi@1 | 554 | fmov_op = 0x06, |
aoqi@1 | 555 | fneg_op = 0x07, |
aoqi@1 | 556 | froundl_op = 0x08, |
aoqi@1 | 557 | ftruncl_op = 0x09, |
aoqi@1 | 558 | fceill_op = 0x0a, |
aoqi@1 | 559 | ffloorl_op = 0x0b, |
aoqi@1 | 560 | froundw_op = 0x0c, |
aoqi@1 | 561 | ftruncw_op = 0x0d, |
aoqi@1 | 562 | fceilw_op = 0x0e, |
aoqi@1 | 563 | ffloorw_op = 0x0f, |
aoqi@1 | 564 | fcvts_op = 0x20, |
aoqi@1 | 565 | fcvtd_op = 0x21, |
aoqi@1 | 566 | fcvtw_op = 0x24, |
aoqi@1 | 567 | fcvtl_op = 0x25, |
aoqi@1 | 568 | fpll_op =0x2c, |
aoqi@1 | 569 | fplu_op =0x2d, |
aoqi@1 | 570 | fpul_op =0x2e, |
aoqi@1 | 571 | fpuu_op =0x2f, |
aoqi@1 | 572 | |
aoqi@1 | 573 | }; |
aoqi@1 | 574 | |
aoqi@1 | 575 | /* 2013.10.16 Jin: merge from OpenJDK 8 */ |
aoqi@1 | 576 | enum WhichOperand { |
aoqi@1 | 577 | // input to locate_operand, and format code for relocations |
aoqi@1 | 578 | imm_operand = 0, // embedded 32-bit|64-bit immediate operand |
aoqi@1 | 579 | disp32_operand = 1, // embedded 32-bit displacement or address |
aoqi@1 | 580 | call32_operand = 2, // embedded 32-bit self-relative displacement |
aoqi@1 | 581 | #ifndef _LP64 |
aoqi@1 | 582 | _WhichOperand_limit = 3 |
aoqi@1 | 583 | #else |
aoqi@1 | 584 | narrow_oop_operand = 3, // embedded 32-bit immediate narrow oop |
aoqi@1 | 585 | _WhichOperand_limit = 4 |
aoqi@1 | 586 | #endif |
aoqi@1 | 587 | }; |
aoqi@1 | 588 | |
aoqi@1 | 589 | /* Godson3 extension */ |
aoqi@1 | 590 | enum godson3_ops { |
aoqi@1 | 591 | gsldx_op = (0x36 << 26) | 0x3, |
aoqi@1 | 592 | gslwx_op = (0x36 << 26) | 0x2, |
aoqi@1 | 593 | }; |
aoqi@1 | 594 | |
aoqi@1 | 595 | static const char* float_name[]; |
aoqi@1 | 596 | |
aoqi@1 | 597 | static int opcode(int insn) { return (insn>>26)&0x3f; } |
aoqi@1 | 598 | static int rs(int insn) { return (insn>>21)&0x1f; } |
aoqi@1 | 599 | static int rt(int insn) { return (insn>>16)&0x1f; } |
aoqi@1 | 600 | static int rd(int insn) { return (insn>>11)&0x1f; } |
aoqi@1 | 601 | static int sa(int insn) { return (insn>>6)&0x1f; } |
aoqi@1 | 602 | static int special(int insn) { return insn&0x3f; } |
aoqi@1 | 603 | static int imm_off(int insn) { return (short)low16(insn); } |
aoqi@1 | 604 | |
aoqi@1 | 605 | static int low (int x, int l) { return bitfield(x, 0, l); } |
aoqi@1 | 606 | static int low16(int x) { return low(x, 16); } |
aoqi@1 | 607 | static int low26(int x) { return low(x, 26); } |
aoqi@1 | 608 | |
aoqi@1 | 609 | protected: |
aoqi@1 | 610 | //help methods for instruction ejection |
aoqi@1 | 611 | |
aoqi@1 | 612 | //I-Type (Immediate) |
aoqi@1 | 613 | // 31 26 25 21 20 16 15 0 |
aoqi@1 | 614 | //| opcode | rs | rt | immediat | |
aoqi@1 | 615 | //| | | | | |
aoqi@1 | 616 | // 6 5 5 16 |
aoqi@1 | 617 | static int insn_ORRI(int op, int rs, int rt, int imm) { return (op<<26) | (rs<<21) | (rt<<16) | low16(imm); } |
aoqi@1 | 618 | |
aoqi@1 | 619 | //R-Type (Register) |
aoqi@1 | 620 | // 31 26 25 21 20 16 15 11 10 6 5 0 |
aoqi@1 | 621 | //| special | rs | rt | rd | 0 | opcode | |
aoqi@1 | 622 | //| 0 0 0 0 0 0 | | | | 0 0 0 0 0 | | |
aoqi@1 | 623 | // 6 5 5 5 5 6 |
aoqi@1 | 624 | static int insn_RRRO(int rs, int rt, int rd, int op) { return (rs<<21) | (rt<<16) | (rd<<11) | op; } |
aoqi@1 | 625 | static int insn_RRSO(int rt, int rd, int sa, int op) { return (rt<<16) | (rd<<11) | (sa<<6) | op; } |
aoqi@1 | 626 | static int insn_RRCO(int rs, int rt, int code, int op) { return (rs<<21) | (rt<<16) | (code<<6) | op; } |
aoqi@1 | 627 | |
aoqi@1 | 628 | static int insn_COP0(int op, int rt, int rd) { return (cop0_op<<26) | (op<<21) | (rt<<16) | (rd<<11); } |
aoqi@1 | 629 | static int insn_COP1(int op, int rt, int fs) { return (cop1_op<<26) | (op<<21) | (rt<<16) | (fs<<11); } |
aoqi@1 | 630 | |
aoqi@1 | 631 | static int insn_F3RO(int fmt, int ft, int fs, int fd, int func) { |
aoqi@1 | 632 | return (cop1_op<<26) | (fmt<<21) | (ft<<16) | (fs<<11) | (fd<<6) | func; |
aoqi@1 | 633 | } |
aoqi@1 | 634 | |
aoqi@1 | 635 | |
aoqi@1 | 636 | //static int low (int x, int l) { return bitfield(x, 0, l); } |
aoqi@1 | 637 | //static int low16(int x) { return low(x, 16); } |
aoqi@1 | 638 | //static int low26(int x) { return low(x, 26); } |
aoqi@1 | 639 | |
aoqi@1 | 640 | static int high (int x, int l) { return bitfield(x, 32-l, l); } |
aoqi@1 | 641 | static int high16(int x) { return high(x, 16); } |
aoqi@1 | 642 | static int high6 (int x) { return high(x, 6); } |
aoqi@1 | 643 | |
aoqi@1 | 644 | //get the offset field of jump/branch instruction |
aoqi@1 | 645 | int offset(address entry) { |
aoqi@1 | 646 | assert(is_simm16((entry - pc() - 4) / 4), "change this code"); |
aoqi@1 | 647 | if (!is_simm16((entry - pc() - 4) / 4)) { |
aoqi@1 | 648 | tty->print_cr("!!! is_simm16: %x", (entry - pc() - 4) / 4); |
aoqi@1 | 649 | } |
aoqi@1 | 650 | return (entry - pc() - 4) / 4; |
aoqi@1 | 651 | } |
aoqi@1 | 652 | |
aoqi@1 | 653 | |
aoqi@1 | 654 | public: |
aoqi@1 | 655 | using AbstractAssembler::offset; |
aoqi@1 | 656 | |
aoqi@1 | 657 | //sign expand with the sign bit is h |
aoqi@1 | 658 | static int expand(int x, int h) { return -(x & (1<<h)) | x; } |
aoqi@1 | 659 | |
aoqi@1 | 660 | // mips lui/addiu is both sign extended, so if you wan't to use off32/imm32, you have to use the follow three |
aoqi@1 | 661 | // by yjl 6/22/2005 |
aoqi@1 | 662 | static int split_low(int x) { |
aoqi@1 | 663 | return (x & 0xffff); |
aoqi@1 | 664 | } |
aoqi@1 | 665 | |
aoqi@1 | 666 | static int split_high(int x) { |
aoqi@1 | 667 | return ( (x >> 16) + ((x & 0x8000) != 0) ) & 0xffff; |
aoqi@1 | 668 | } |
aoqi@1 | 669 | |
aoqi@1 | 670 | static int merge(int low, int high) { |
aoqi@1 | 671 | return expand(low, 15) + (high<<16); |
aoqi@1 | 672 | } |
aoqi@1 | 673 | |
aoqi@1 | 674 | #ifdef _LP64 |
aoqi@1 | 675 | static intptr_t merge(intptr_t x0, intptr_t x16, intptr_t x32, intptr_t x48) { |
aoqi@1 | 676 | return (x48 << 48) | (x32 << 32) | (x16 << 16) | x0; |
aoqi@1 | 677 | /* |
aoqi@1 | 678 | return ((intptr_t)(long_at(0) & 0xffff) << 48) |
aoqi@1 | 679 | + expand((intptr_t)(long_at(4) & 0xffff) << 32, 47) |
aoqi@1 | 680 | + expand((intptr_t)(long_at(12) & 0xffff) << 16, 31) |
aoqi@1 | 681 | + expand((intptr_t)(long_at(20) & 0xffff), 15); |
aoqi@1 | 682 | return expand(low, 15) + (high<<16); |
aoqi@1 | 683 | */ |
aoqi@1 | 684 | } |
aoqi@1 | 685 | #endif |
aoqi@1 | 686 | |
aoqi@1 | 687 | // modified by spark 2005/08/18 |
aoqi@1 | 688 | static bool is_simm (int x, int nbits) { return -( 1 << nbits-1 ) <= x && x < ( 1 << nbits-1 ); } |
aoqi@1 | 689 | static bool is_simm16(int x) { return is_simm(x, 16); } |
aoqi@1 | 690 | |
aoqi@1 | 691 | // test if imm can be coded in a instruction with 16-bit imm/off |
aoqi@1 | 692 | // by yjl 6/23/2005 |
aoqi@1 | 693 | /*static bool fit_in_insn(int imm) { |
aoqi@1 | 694 | return imm == (short)imm; |
aoqi@1 | 695 | }*/ |
aoqi@1 | 696 | |
aoqi@1 | 697 | static bool fit_in_jal(int offset) { |
aoqi@1 | 698 | return is_simm(offset, 26); |
aoqi@1 | 699 | } |
aoqi@1 | 700 | |
aoqi@1 | 701 | |
aoqi@1 | 702 | // test if entry can be filled in the jl/jal, |
aoqi@1 | 703 | // must be used just before you emit jl/jal |
aoqi@1 | 704 | // by yjl 6/27/2005 |
aoqi@1 | 705 | bool fit_int_jal(address entry) { |
aoqi@1 | 706 | return fit_in_jal(offset(entry)); |
aoqi@1 | 707 | } |
aoqi@1 | 708 | |
aoqi@1 | 709 | bool fit_int_branch(address entry) { |
aoqi@1 | 710 | return is_simm16(offset(entry)); |
aoqi@1 | 711 | } |
aoqi@1 | 712 | |
aoqi@1 | 713 | protected: |
aoqi@1 | 714 | #ifdef ASSERT |
aoqi@1 | 715 | #define CHECK_DELAY |
aoqi@1 | 716 | #endif |
aoqi@1 | 717 | #ifdef CHECK_DELAY |
aoqi@1 | 718 | enum Delay_state { no_delay, at_delay_slot, filling_delay_slot } delay_state; |
aoqi@1 | 719 | #endif |
aoqi@1 | 720 | |
aoqi@1 | 721 | public: |
aoqi@1 | 722 | void assert_not_delayed() { |
aoqi@1 | 723 | #ifdef CHECK_DELAY |
aoqi@1 | 724 | assert_not_delayed("next instruction should not be a delay slot"); |
aoqi@1 | 725 | #endif |
aoqi@1 | 726 | } |
aoqi@1 | 727 | |
aoqi@1 | 728 | void assert_not_delayed(const char* msg) { |
aoqi@1 | 729 | #ifdef CHECK_DELAY |
aoqi@1 | 730 | //guarantee( delay_state == no_delay, msg ); |
aoqi@1 | 731 | //aoqi_test |
aoqi@1 | 732 | if(delay_state != no_delay){ |
aoqi@1 | 733 | tty->print_cr("%s:%d, pc: %lx", __func__, __LINE__, pc()); |
aoqi@1 | 734 | } |
aoqi@1 | 735 | assert(delay_state == no_delay, msg); |
aoqi@1 | 736 | #endif |
aoqi@1 | 737 | } |
aoqi@1 | 738 | |
aoqi@1 | 739 | protected: |
aoqi@1 | 740 | // Delay slot helpers |
aoqi@1 | 741 | // cti is called when emitting control-transfer instruction, |
aoqi@1 | 742 | // BEFORE doing the emitting. |
aoqi@1 | 743 | // Only effective when assertion-checking is enabled. |
aoqi@1 | 744 | |
aoqi@1 | 745 | // called when emitting cti with a delay slot, AFTER emitting |
aoqi@1 | 746 | void has_delay_slot() { |
aoqi@1 | 747 | #ifdef CHECK_DELAY |
aoqi@1 | 748 | assert_not_delayed("just checking"); |
aoqi@1 | 749 | delay_state = at_delay_slot; |
aoqi@1 | 750 | #endif |
aoqi@1 | 751 | } |
aoqi@1 | 752 | |
aoqi@1 | 753 | public: |
aoqi@1 | 754 | Assembler* delayed() { |
aoqi@1 | 755 | #ifdef CHECK_DELAY |
aoqi@1 | 756 | guarantee( delay_state == at_delay_slot, "delayed instructition is not in delay slot"); |
aoqi@1 | 757 | delay_state = filling_delay_slot; |
aoqi@1 | 758 | #endif |
aoqi@1 | 759 | return this; |
aoqi@1 | 760 | } |
aoqi@1 | 761 | |
aoqi@1 | 762 | void flush() { |
aoqi@1 | 763 | #ifdef CHECK_DELAY |
aoqi@1 | 764 | guarantee( delay_state == no_delay, "ending code with a delay slot"); |
aoqi@1 | 765 | #endif |
aoqi@1 | 766 | AbstractAssembler::flush(); |
aoqi@1 | 767 | } |
aoqi@1 | 768 | |
aoqi@1 | 769 | inline void emit_long(int); // shadows AbstractAssembler::emit_long |
aoqi@1 | 770 | inline void emit_data(int x) { emit_long(x); } |
aoqi@1 | 771 | inline void emit_data(int, RelocationHolder const&); |
aoqi@1 | 772 | inline void emit_data(int, relocInfo::relocType rtype); |
aoqi@1 | 773 | inline void check_delay(); |
aoqi@1 | 774 | |
aoqi@1 | 775 | |
aoqi@1 | 776 | // Generic instructions |
aoqi@1 | 777 | // Does 32bit or 64bit as needed for the platform. In some sense these |
aoqi@1 | 778 | // belong in macro assembler but there is no need for both varieties to exist |
aoqi@1 | 779 | |
aoqi@1 | 780 | #ifndef _LP64 |
aoqi@1 | 781 | 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 | 782 | void addi(Register rt, Register rs, int imm) { emit_long(insn_ORRI(addi_op, (int)rs->encoding(), (int)rt->encoding(), imm)); } |
aoqi@1 | 783 | void addiu(Register rt, Register rs, int imm) { emit_long(insn_ORRI(addiu_op, (int)rs->encoding(), (int)rt->encoding(), imm)); } |
aoqi@1 | 784 | 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 | 785 | #else |
aoqi@1 | 786 | void add(Register rd, Register rs, Register rt) { dadd (rd, rs, rt); } |
aoqi@1 | 787 | 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 | 788 | 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 | 789 | void addiu32(Register rt, Register rs, int imm) { emit_long(insn_ORRI(addiu_op, (int)rs->encoding(), (int)rt->encoding(), imm)); } |
aoqi@1 | 790 | void addi(Register rt, Register rs, int imm) { daddi (rt, rs, imm);} |
aoqi@1 | 791 | void addiu(Register rt, Register rs, int imm) { daddiu (rt, rs, imm);} |
aoqi@1 | 792 | void addu(Register rd, Register rs, Register rt) { daddu (rd, rs, rt); } |
aoqi@1 | 793 | #endif |
aoqi@1 | 794 | |
aoqi@1 | 795 | 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 | 796 | void andi(Register rt, Register rs, int imm) { emit_long(insn_ORRI(andi_op, (int)rs->encoding(), (int)rt->encoding(), imm)); } |
aoqi@1 | 797 | |
aoqi@1 | 798 | 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 | 799 | 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 | 800 | void bgez (Register rs, int off) { emit_long(insn_ORRI(regimm_op, (int)rs->encoding(), bgez_op, off)); has_delay_slot(); } |
aoqi@1 | 801 | void bgezal (Register rs, int off) { emit_long(insn_ORRI(regimm_op, (int)rs->encoding(), bgezal_op, off)); has_delay_slot(); } |
aoqi@1 | 802 | void bgezall(Register rs, int off) { emit_long(insn_ORRI(regimm_op, (int)rs->encoding(), bgezall_op, off)); has_delay_slot(); } |
aoqi@1 | 803 | void bgezl (Register rs, int off) { emit_long(insn_ORRI(regimm_op, (int)rs->encoding(), bgezl_op, off)); has_delay_slot(); } |
aoqi@1 | 804 | void bgtz (Register rs, int off) { emit_long(insn_ORRI(bgtz_op, (int)rs->encoding(), 0, off)); has_delay_slot(); } |
aoqi@1 | 805 | void bgtzl (Register rs, int off) { emit_long(insn_ORRI(bgtzl_op, (int)rs->encoding(), 0, off)); has_delay_slot(); } |
aoqi@1 | 806 | void blez (Register rs, int off) { emit_long(insn_ORRI(blez_op, (int)rs->encoding(), 0, off)); has_delay_slot(); } |
aoqi@1 | 807 | void blezl (Register rs, int off) { emit_long(insn_ORRI(blezl_op, (int)rs->encoding(), 0, off)); has_delay_slot(); } |
aoqi@1 | 808 | void bltz (Register rs, int off) { emit_long(insn_ORRI(regimm_op, (int)rs->encoding(), bltz_op, off)); has_delay_slot(); } |
aoqi@1 | 809 | void bltzal (Register rs, int off) { emit_long(insn_ORRI(regimm_op, (int)rs->encoding(), bltzal_op, off)); has_delay_slot(); } |
aoqi@1 | 810 | void bltzall(Register rs, int off) { emit_long(insn_ORRI(regimm_op, (int)rs->encoding(), bltzall_op, off)); has_delay_slot(); } |
aoqi@1 | 811 | void bltzl (Register rs, int off) { emit_long(insn_ORRI(regimm_op, (int)rs->encoding(), bltzl_op, off)); has_delay_slot(); } |
aoqi@1 | 812 | 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 | 813 | 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 | 814 | void brk (int code) { emit_long(break_op | (code<<16)); } |
aoqi@1 | 815 | |
aoqi@1 | 816 | void beq (Register rs, Register rt, address entry) { beq(rs, rt, offset(entry)); } |
aoqi@1 | 817 | void beql (Register rs, Register rt, address entry) { beql(rs, rt, offset(entry));} |
aoqi@1 | 818 | void bgez (Register rs, address entry) { bgez (rs, offset(entry)); } |
aoqi@1 | 819 | void bgezal (Register rs, address entry) { bgezal (rs, offset(entry)); } |
aoqi@1 | 820 | void bgezall(Register rs, address entry) { bgezall(rs, offset(entry)); } |
aoqi@1 | 821 | void bgezl (Register rs, address entry) { bgezl (rs, offset(entry)); } |
aoqi@1 | 822 | void bgtz (Register rs, address entry) { bgtz (rs, offset(entry)); } |
aoqi@1 | 823 | void bgtzl (Register rs, address entry) { bgtzl (rs, offset(entry)); } |
aoqi@1 | 824 | void blez (Register rs, address entry) { blez (rs, offset(entry)); } |
aoqi@1 | 825 | void blezl (Register rs, address entry) { blezl (rs, offset(entry)); } |
aoqi@1 | 826 | void bltz (Register rs, address entry) { bltz (rs, offset(entry)); } |
aoqi@1 | 827 | void bltzal (Register rs, address entry) { bltzal (rs, offset(entry)); } |
aoqi@1 | 828 | void bltzall(Register rs, address entry) { bltzall(rs, offset(entry)); } |
aoqi@1 | 829 | void bltzl (Register rs, address entry) { bltzl (rs, offset(entry)); } |
aoqi@1 | 830 | void bne (Register rs, Register rt, address entry) { bne(rs, rt, offset(entry)); } |
aoqi@1 | 831 | void bnel (Register rs, Register rt, address entry) { bnel(rs, rt, offset(entry)); } |
aoqi@1 | 832 | |
aoqi@1 | 833 | void beq (Register rs, Register rt, Label& L) { beq(rs, rt, target(L)); } |
aoqi@1 | 834 | void beql (Register rs, Register rt, Label& L) { beql(rs, rt, target(L)); } |
aoqi@1 | 835 | void bgez (Register rs, Label& L){ bgez (rs, target(L)); } |
aoqi@1 | 836 | void bgezal (Register rs, Label& L){ bgezal (rs, target(L)); } |
aoqi@1 | 837 | void bgezall(Register rs, Label& L){ bgezall(rs, target(L)); } |
aoqi@1 | 838 | void bgezl (Register rs, Label& L){ bgezl (rs, target(L)); } |
aoqi@1 | 839 | void bgtz (Register rs, Label& L){ bgtz (rs, target(L)); } |
aoqi@1 | 840 | void bgtzl (Register rs, Label& L){ bgtzl (rs, target(L)); } |
aoqi@1 | 841 | void blez (Register rs, Label& L){ blez (rs, target(L)); } |
aoqi@1 | 842 | void blezl (Register rs, Label& L){ blezl (rs, target(L)); } |
aoqi@1 | 843 | void bltz (Register rs, Label& L){ bltz (rs, target(L)); } |
aoqi@1 | 844 | void bltzal (Register rs, Label& L){ bltzal (rs, target(L)); } |
aoqi@1 | 845 | void bltzall(Register rs, Label& L){ bltzall(rs, target(L)); } |
aoqi@1 | 846 | void bltzl (Register rs, Label& L){ bltzl (rs, target(L)); } |
aoqi@1 | 847 | void bne (Register rs, Register rt, Label& L){ bne(rs, rt, target(L)); } |
aoqi@1 | 848 | void bnel (Register rs, Register rt, Label& L){ bnel(rs, rt, target(L)); } |
aoqi@1 | 849 | |
aoqi@1 | 850 | 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 | 851 | void daddi (Register rt, Register rs, int imm) { emit_long(insn_ORRI(daddi_op, (int)rs->encoding(), (int)rt->encoding(), imm)); } |
aoqi@1 | 852 | void daddiu(Register rt, Register rs, int imm) { emit_long(insn_ORRI(daddiu_op, (int)rs->encoding(), (int)rt->encoding(), imm)); } |
aoqi@1 | 853 | 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 | 854 | void ddiv (Register rs, Register rt) { emit_long(insn_RRRO((int)rs->encoding(), (int)rt->encoding(), 0, ddiv_op)); } |
aoqi@1 | 855 | void ddivu (Register rs, Register rt) { emit_long(insn_RRRO((int)rs->encoding(), (int)rt->encoding(), 0, ddivu_op)); } |
aoqi@1 | 856 | // Do mult and div need both 32-bit and 64-bit version? FIXME aoqi |
aoqi@1 | 857 | //#ifndef _LP64 |
aoqi@1 | 858 | #if 1 |
aoqi@1 | 859 | void div (Register rs, Register rt) { emit_long(insn_RRRO((int)rs->encoding(), (int)rt->encoding(), 0, div_op)); } |
aoqi@1 | 860 | void divu (Register rs, Register rt) { emit_long(insn_RRRO((int)rs->encoding(), (int)rt->encoding(), 0, divu_op)); } |
aoqi@1 | 861 | #else |
aoqi@1 | 862 | void div (Register rs, Register rt) { ddiv (rs, rt);} |
aoqi@1 | 863 | void divu (Register rs, Register rt) { ddivu(rs, rt);} |
aoqi@1 | 864 | #endif |
aoqi@1 | 865 | void dmfc0 (Register rt, FloatRegister rd) { emit_long(insn_COP0(dmf_op, (int)rt->encoding(), (int)rd->encoding())); } |
aoqi@1 | 866 | void dmtc0 (Register rt, FloatRegister rd) { emit_long(insn_COP0(dmt_op, (int)rt->encoding(), (int)rd->encoding())); } |
aoqi@1 | 867 | void dmult (Register rs, Register rt) { emit_long(insn_RRRO((int)rs->encoding(), (int)rt->encoding(), 0, dmult_op)); } |
aoqi@1 | 868 | void dmultu(Register rs, Register rt) { emit_long(insn_RRRO((int)rs->encoding(), (int)rt->encoding(), 0, dmultu_op)); } |
aoqi@1 | 869 | void dsll (Register rd, Register rt , int sa) { emit_long(insn_RRSO((int)rt->encoding(), (int)rd->encoding(), sa, dsll_op)); } |
aoqi@1 | 870 | 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 | 871 | void dsll32(Register rd, Register rt , int sa) { emit_long(insn_RRSO((int)rt->encoding(), (int)rd->encoding(), sa, dsll32_op)); } |
aoqi@1 | 872 | void dsra (Register rd, Register rt , int sa) { emit_long(insn_RRSO((int)rt->encoding(), (int)rd->encoding(), sa, dsra_op)); } |
aoqi@1 | 873 | 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 | 874 | void dsra32(Register rd, Register rt , int sa) { emit_long(insn_RRSO((int)rt->encoding(), (int)rd->encoding(), sa, dsra32_op)); } |
aoqi@1 | 875 | void dsrl (Register rd, Register rt , int sa) { emit_long(insn_RRSO((int)rt->encoding(), (int)rd->encoding(), sa, dsrl_op)); } |
aoqi@1 | 876 | 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 | 877 | void dsrl32(Register rd, Register rt , int sa) { emit_long(insn_RRSO((int)rt->encoding(), (int)rd->encoding(), sa, dsrl32_op)); } |
aoqi@1 | 878 | 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 | 879 | 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 | 880 | |
aoqi@1 | 881 | void b(int off) { beq(R0, R0, off); } |
aoqi@1 | 882 | void b(address entry) { b(offset(entry)); } |
aoqi@1 | 883 | void b(Label& L) { b(target(L)); } |
aoqi@1 | 884 | |
aoqi@1 | 885 | void j(address entry); |
aoqi@1 | 886 | void jal(address entry); |
aoqi@1 | 887 | |
aoqi@1 | 888 | void jalr(Register rd, Register rs) { emit_long( ((int)rs->encoding()<<21) | ((int)rd->encoding()<<11) | jalr_op); has_delay_slot(); } |
aoqi@1 | 889 | void jalr(Register rs) { jalr(RA, rs); } |
aoqi@1 | 890 | void jalr() { jalr(T9); } |
aoqi@1 | 891 | |
aoqi@1 | 892 | void jr(Register rs) { emit_long(((int)rs->encoding()<<21) | jr_op); has_delay_slot(); } |
aoqi@1 | 893 | |
aoqi@1 | 894 | void lb (Register rt, Register base, int off) { emit_long(insn_ORRI(lb_op, (int)base->encoding(), (int)rt->encoding(), off)); } |
aoqi@1 | 895 | void lbu(Register rt, Register base, int off) { emit_long(insn_ORRI(lbu_op, (int)base->encoding(), (int)rt->encoding(), off)); } |
aoqi@1 | 896 | void ld (Register rt, Register base, int off) { emit_long(insn_ORRI(ld_op, (int)base->encoding(), (int)rt->encoding(), off)); } |
aoqi@1 | 897 | void ldl(Register rt, Register base, int off) { emit_long(insn_ORRI(ldl_op, (int)base->encoding(), (int)rt->encoding(), off)); } |
aoqi@1 | 898 | void ldr(Register rt, Register base, int off) { emit_long(insn_ORRI(ldr_op, (int)base->encoding(), (int)rt->encoding(), off)); } |
aoqi@1 | 899 | void lh (Register rt, Register base, int off) { emit_long(insn_ORRI(lh_op, (int)base->encoding(), (int)rt->encoding(), off)); } |
aoqi@1 | 900 | void lhu(Register rt, Register base, int off) { emit_long(insn_ORRI(lhu_op, (int)base->encoding(), (int)rt->encoding(), off)); } |
aoqi@1 | 901 | void ll (Register rt, Register base, int off) { emit_long(insn_ORRI(ll_op, (int)base->encoding(), (int)rt->encoding(), off)); } |
aoqi@1 | 902 | void lld(Register rt, Register base, int off) { emit_long(insn_ORRI(lld_op, (int)base->encoding(), (int)rt->encoding(), off)); } |
aoqi@1 | 903 | void lui(Register rt, int imm) { emit_long(insn_ORRI(lui_op, 0, (int)rt->encoding(), imm)); } |
aoqi@1 | 904 | void lw (Register rt, Register base, int off) { emit_long(insn_ORRI(lw_op, (int)base->encoding(), (int)rt->encoding(), off)); } |
aoqi@1 | 905 | void lwl(Register rt, Register base, int off) { emit_long(insn_ORRI(lwl_op, (int)base->encoding(), (int)rt->encoding(), off)); } |
aoqi@1 | 906 | void lwr(Register rt, Register base, int off) { emit_long(insn_ORRI(lwr_op, (int)base->encoding(), (int)rt->encoding(), off)); } |
aoqi@1 | 907 | void lwu(Register rt, Register base, int off) { emit_long(insn_ORRI(lwu_op, (int)base->encoding(), (int)rt->encoding(), off)); } |
aoqi@1 | 908 | |
aoqi@1 | 909 | void lb (Register rt, Address src); |
aoqi@1 | 910 | void lbu(Register rt, Address src); |
aoqi@1 | 911 | void ld (Register rt, Address src); |
aoqi@1 | 912 | void ldl(Register rt, Address src); |
aoqi@1 | 913 | void ldr(Register rt, Address src); |
aoqi@1 | 914 | void lh (Register rt, Address src); |
aoqi@1 | 915 | void lhu(Register rt, Address src); |
aoqi@1 | 916 | void ll (Register rt, Address src); |
aoqi@1 | 917 | void lld(Register rt, Address src); |
aoqi@1 | 918 | void lw (Register rt, Address src); |
aoqi@1 | 919 | void lwl(Register rt, Address src); |
aoqi@1 | 920 | void lwr(Register rt, Address src); |
aoqi@1 | 921 | void lwu(Register rt, Address src); |
aoqi@1 | 922 | void lea(Register rt, Address src); |
aoqi@1 | 923 | |
aoqi@1 | 924 | void mfc0 (Register rt, Register rd) { emit_long(insn_COP0(mf_op, (int)rt->encoding(), (int)rd->encoding())); } |
aoqi@1 | 925 | void mfhi (Register rd) { emit_long( ((int)rd->encoding()<<11) | mfhi_op ); } |
aoqi@1 | 926 | void mflo (Register rd) { emit_long( ((int)rd->encoding()<<11) | mflo_op ); } |
aoqi@1 | 927 | void mtc0 (Register rt, Register rd) { emit_long(insn_COP0(mt_op, (int)rt->encoding(), (int)rd->encoding())); } |
aoqi@1 | 928 | void mthi (Register rs) { emit_long( ((int)rs->encoding()<<21) | mthi_op ); } |
aoqi@1 | 929 | void mtlo (Register rs) { emit_long( ((int)rs->encoding()<<21) | mtlo_op ); } |
aoqi@1 | 930 | // Do mult and div need both 32-bit and 64-bit version? FIXME aoqi |
aoqi@1 | 931 | //#ifndef _LP64 |
aoqi@1 | 932 | #if 1 |
aoqi@1 | 933 | void mult (Register rs, Register rt) { emit_long(insn_RRRO((int)rs->encoding(), (int)rt->encoding(), 0, mult_op)); } |
aoqi@1 | 934 | void multu(Register rs, Register rt) { emit_long(insn_RRRO((int)rs->encoding(), (int)rt->encoding(), 0, multu_op)); } |
aoqi@1 | 935 | #else |
aoqi@1 | 936 | void mult (Register rs, Register rt) { dmult (rs, rt); } |
aoqi@1 | 937 | void multu(Register rs, Register rt) { dmultu (rs, rt); } |
aoqi@1 | 938 | #endif |
aoqi@1 | 939 | |
aoqi@1 | 940 | 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 | 941 | |
aoqi@1 | 942 | 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 | 943 | void ori(Register rt, Register rs, int imm) { emit_long(insn_ORRI(ori_op, (int)rs->encoding(), (int)rt->encoding(), imm)); } |
aoqi@1 | 944 | |
aoqi@1 | 945 | void sb (Register rt, Register base, int off) { emit_long(insn_ORRI(sb_op, (int)base->encoding(), (int)rt->encoding(), off)); } |
aoqi@1 | 946 | void sc (Register rt, Register base, int off) { emit_long(insn_ORRI(sc_op, (int)base->encoding(), (int)rt->encoding(), off)); } |
aoqi@1 | 947 | void scd (Register rt, Register base, int off) { emit_long(insn_ORRI(scd_op, (int)base->encoding(), (int)rt->encoding(), off)); } |
aoqi@1 | 948 | void sd (Register rt, Register base, int off) { emit_long(insn_ORRI(sd_op, (int)base->encoding(), (int)rt->encoding(), off)); } |
aoqi@1 | 949 | void sdl (Register rt, Register base, int off) { emit_long(insn_ORRI(sdl_op, (int)base->encoding(), (int)rt->encoding(), off)); } |
aoqi@1 | 950 | void sdr (Register rt, Register base, int off) { emit_long(insn_ORRI(sdr_op, (int)base->encoding(), (int)rt->encoding(), off)); } |
aoqi@1 | 951 | void sh (Register rt, Register base, int off) { emit_long(insn_ORRI(sh_op, (int)base->encoding(), (int)rt->encoding(), off)); } |
aoqi@1 | 952 | //#ifndef _LP64 |
aoqi@1 | 953 | #if 1 |
aoqi@1 | 954 | void sll (Register rd, Register rt , int sa) { emit_long(insn_RRSO((int)rt->encoding(), (int)rd->encoding(), sa, sll_op)); } |
aoqi@1 | 955 | 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 | 956 | #else |
aoqi@1 | 957 | void sll (Register rd, Register rt , int sa) { dsll (rd, rt, sa);} |
aoqi@1 | 958 | void sllv (Register rd, Register rt, Register rs) { dsllv (rd, rt, rs); } |
aoqi@1 | 959 | #endif |
aoqi@1 | 960 | 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 | 961 | void slti (Register rt, Register rs, int imm) { emit_long(insn_ORRI(slti_op, (int)rs->encoding(), (int)rt->encoding(), imm)); } |
aoqi@1 | 962 | void sltiu(Register rt, Register rs, int imm) { emit_long(insn_ORRI(sltiu_op, (int)rs->encoding(), (int)rt->encoding(), imm)); } |
aoqi@1 | 963 | 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 | 964 | //#ifndef _LP64 |
aoqi@1 | 965 | #if 1 |
aoqi@1 | 966 | void sra (Register rd, Register rt , int sa) { emit_long(insn_RRSO((int)rt->encoding(), (int)rd->encoding(), sa, sra_op)); } |
aoqi@1 | 967 | 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 | 968 | void srl (Register rd, Register rt , int sa) { emit_long(insn_RRSO((int)rt->encoding(), (int)rd->encoding(), sa, srl_op)); } |
aoqi@1 | 969 | 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 | 970 | #else |
aoqi@1 | 971 | void sra (Register rd, Register rt , int sa) { dsra (rd, rt, sa); } |
aoqi@1 | 972 | void srav (Register rd, Register rt, Register rs) { dsrav (rd, rt, rs); } |
aoqi@1 | 973 | void srl (Register rd, Register rt , int sa) { dsrl (rd, rt, sa); } |
aoqi@1 | 974 | void srlv (Register rd, Register rt, Register rs) { dsrlv (rd, rt, rs); } |
aoqi@1 | 975 | #endif |
aoqi@1 | 976 | #ifndef _LP64 |
aoqi@1 | 977 | 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 | 978 | 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 | 979 | #else |
aoqi@1 | 980 | void sub (Register rd, Register rs, Register rt) { dsub (rd, rs, rt); } |
aoqi@1 | 981 | void subu (Register rd, Register rs, Register rt) { dsubu (rd, rs, rt); } |
aoqi@1 | 982 | 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 | 983 | #endif |
aoqi@1 | 984 | void sw (Register rt, Register base, int off) { emit_long(insn_ORRI(sw_op, (int)base->encoding(), (int)rt->encoding(), off)); } |
aoqi@1 | 985 | void swl (Register rt, Register base, int off) { emit_long(insn_ORRI(swl_op, (int)base->encoding(), (int)rt->encoding(), off)); } |
aoqi@1 | 986 | void swr (Register rt, Register base, int off) { emit_long(insn_ORRI(swr_op, (int)base->encoding(), (int)rt->encoding(), off)); } |
aoqi@1 | 987 | void sync () { emit_long(sync_op); } |
aoqi@1 | 988 | void syscall(int code) { emit_long( (code<<6) | syscall_op ); } |
aoqi@1 | 989 | |
aoqi@1 | 990 | void sb(Register rt, Address dst); |
aoqi@1 | 991 | void sc(Register rt, Address dst); |
aoqi@1 | 992 | void scd(Register rt, Address dst); |
aoqi@1 | 993 | void sd(Register rt, Address dst); |
aoqi@1 | 994 | void sdl(Register rt, Address dst); |
aoqi@1 | 995 | void sdr(Register rt, Address dst); |
aoqi@1 | 996 | void sh(Register rt, Address dst); |
aoqi@1 | 997 | void sw(Register rt, Address dst); |
aoqi@1 | 998 | void swl(Register rt, Address dst); |
aoqi@1 | 999 | void swr(Register rt, Address dst); |
aoqi@1 | 1000 | |
aoqi@1 | 1001 | void teq (Register rs, Register rt, int code) { emit_long(insn_RRCO((int)rs->encoding(), (int)rt->encoding(), code, teq_op)); } |
aoqi@1 | 1002 | void teqi (Register rs, int imm) { emit_long(insn_ORRI(regimm_op, (int)rs->encoding(), teqi_op, imm)); } |
aoqi@1 | 1003 | void tge (Register rs, Register rt, int code) { emit_long(insn_RRCO((int)rs->encoding(), (int)rt->encoding(), code, tge_op)); } |
aoqi@1 | 1004 | void tgei (Register rs, int imm) { emit_long(insn_ORRI(regimm_op, (int)rs->encoding(), tgei_op, imm)); } |
aoqi@1 | 1005 | void tgeiu(Register rs, int imm) { emit_long(insn_ORRI(regimm_op, (int)rs->encoding(), tgeiu_op, imm)); } |
aoqi@1 | 1006 | void tgeu (Register rs, Register rt, int code) { emit_long(insn_RRCO((int)rs->encoding(), (int)rt->encoding(), code, tgeu_op)); } |
aoqi@1 | 1007 | void tlt (Register rs, Register rt, int code) { emit_long(insn_RRCO((int)rs->encoding(), (int)rt->encoding(), code, tlt_op)); } |
aoqi@1 | 1008 | void tlti (Register rs, int imm) { emit_long(insn_ORRI(regimm_op, (int)rs->encoding(), tlti_op, imm)); } |
aoqi@1 | 1009 | void tltiu(Register rs, int imm) { emit_long(insn_ORRI(regimm_op, (int)rs->encoding(), tltiu_op, imm)); } |
aoqi@1 | 1010 | void tltu (Register rs, Register rt, int code) { emit_long(insn_RRCO((int)rs->encoding(), (int)rt->encoding(), code, tltu_op)); } |
aoqi@1 | 1011 | void tne (Register rs, Register rt, int code) { emit_long(insn_RRCO((int)rs->encoding(), (int)rt->encoding(), code, tne_op)); } |
aoqi@1 | 1012 | void tnei (Register rs, int imm) { emit_long(insn_ORRI(regimm_op, (int)rs->encoding(), tnei_op, imm)); } |
aoqi@1 | 1013 | |
aoqi@1 | 1014 | 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 | 1015 | void xori(Register rt, Register rs, int imm) { emit_long(insn_ORRI(xori_op, (int)rs->encoding(), (int)rt->encoding(), imm)); } |
aoqi@1 | 1016 | |
aoqi@1 | 1017 | void nop() { emit_long(0); } |
aoqi@1 | 1018 | //float instructions for mips |
aoqi@1 | 1019 | void abs_s(FloatRegister fd, FloatRegister fs) { emit_long(insn_F3RO(single_fmt, 0, (int)fs->encoding(), (int)fd->encoding(), fabs_op));} |
aoqi@1 | 1020 | void abs_d(FloatRegister fd, FloatRegister fs) { emit_long(insn_F3RO(double_fmt, 0, (int)fs->encoding(), (int)fd->encoding(), fabs_op));} |
aoqi@1 | 1021 | 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 | 1022 | 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 | 1023 | |
aoqi@1 | 1024 | void bc1f (int off) { emit_long(insn_ORRI(cop1_op, bc_op, bcf_op, off)); has_delay_slot(); } |
aoqi@1 | 1025 | void bc1fl(int off) { emit_long(insn_ORRI(cop1_op, bc_op, bcfl_op, off)); has_delay_slot(); } |
aoqi@1 | 1026 | void bc1t (int off) { emit_long(insn_ORRI(cop1_op, bc_op, bct_op, off)); has_delay_slot(); } |
aoqi@1 | 1027 | void bc1tl(int off) { emit_long(insn_ORRI(cop1_op, bc_op, bctl_op, off)); has_delay_slot(); } |
aoqi@1 | 1028 | |
aoqi@1 | 1029 | void bc1f (address entry) { bc1f(offset(entry)); } |
aoqi@1 | 1030 | void bc1fl(address entry) { bc1fl(offset(entry)); } |
aoqi@1 | 1031 | void bc1t (address entry) { bc1t(offset(entry)); } |
aoqi@1 | 1032 | void bc1tl(address entry) { bc1tl(offset(entry)); } |
aoqi@1 | 1033 | |
aoqi@1 | 1034 | void bc1f (Label& L) { bc1f(target(L)); } |
aoqi@1 | 1035 | void bc1fl(Label& L) { bc1fl(target(L)); } |
aoqi@1 | 1036 | void bc1t (Label& L) { bc1t(target(L)); } |
aoqi@1 | 1037 | void bc1tl(Label& L) { bc1tl(target(L)); } |
aoqi@1 | 1038 | |
aoqi@1 | 1039 | 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 | 1040 | 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 | 1041 | 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 | 1042 | 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 | 1043 | 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 | 1044 | 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 | 1045 | 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 | 1046 | 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 | 1047 | 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 | 1048 | 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 | 1049 | 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 | 1050 | 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 | 1051 | 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 | 1052 | 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 | 1053 | 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 | 1054 | 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 | 1055 | 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 | 1056 | 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 | 1057 | 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 | 1058 | 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 | 1059 | 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 | 1060 | 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 | 1061 | 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 | 1062 | 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 | 1063 | 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 | 1064 | 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 | 1065 | 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 | 1066 | 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 | 1067 | 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 | 1068 | 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 | 1069 | 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 | 1070 | 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 | 1071 | |
aoqi@1 | 1072 | 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 | 1073 | 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 | 1074 | 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 | 1075 | 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 | 1076 | void cfc1(Register rt, FloatRegister fs) { emit_long(insn_COP1(cf_op, (int)rt->encoding(), (int)fs->encoding())); } |
aoqi@1 | 1077 | void ctc1(Register rt, FloatRegister fs) { emit_long(insn_COP1(ct_op, (int)rt->encoding(), (int)fs->encoding())); } |
aoqi@1 | 1078 | void cfc1(Register rt, int fs) { emit_long(insn_COP1(cf_op, (int)rt->encoding(), fs)); } |
aoqi@1 | 1079 | void ctc1(Register rt, int fs) { emit_long(insn_COP1(ct_op, (int)rt->encoding(), fs)); } |
aoqi@1 | 1080 | |
aoqi@1 | 1081 | 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 | 1082 | 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 | 1083 | 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 | 1084 | 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 | 1085 | 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 | 1086 | 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 | 1087 | 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 | 1088 | 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 | 1089 | 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 | 1090 | 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 | 1091 | 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 | 1092 | 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 | 1093 | 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 | 1094 | 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 | 1095 | 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 | 1096 | 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 | 1097 | |
aoqi@1 | 1098 | 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 | 1099 | 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 | 1100 | void dmfc1(Register rt, FloatRegister fs) { emit_long(insn_COP1(dmf_op, (int)rt->encoding(), (int)fs->encoding())); } |
aoqi@1 | 1101 | void dmtc1(Register rt, FloatRegister fs) { emit_long(insn_COP1(dmt_op, (int)rt->encoding(), (int)fs->encoding())); } |
aoqi@1 | 1102 | |
aoqi@1 | 1103 | 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 | 1104 | 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 | 1105 | 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 | 1106 | 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 | 1107 | |
aoqi@1 | 1108 | void ldc1(FloatRegister ft, Register base, int off) { emit_long(insn_ORRI(ldc1_op, (int)base->encoding(), (int)ft->encoding(), off)); } |
aoqi@1 | 1109 | void lwc1(FloatRegister ft, Register base, int off) { emit_long(insn_ORRI(lwc1_op, (int)base->encoding(), (int)ft->encoding(), off)); } |
aoqi@1 | 1110 | void ldc1(FloatRegister ft, Address src); |
aoqi@1 | 1111 | void lwc1(FloatRegister ft, Address src); |
aoqi@1 | 1112 | |
aoqi@1 | 1113 | void mfc1(Register rt, FloatRegister fs) { emit_long(insn_COP1(mf_op, (int)rt->encoding(), (int)fs->encoding())); } |
aoqi@1 | 1114 | void mov_s(FloatRegister fd, FloatRegister fs) { emit_long(insn_F3RO(single_fmt, 0, (int)fs->encoding(), (int)fd->encoding(), fmov_op)); } |
aoqi@1 | 1115 | void mov_d(FloatRegister fd, FloatRegister fs) { emit_long(insn_F3RO(double_fmt, 0, (int)fs->encoding(), (int)fd->encoding(), fmov_op)); } |
aoqi@1 | 1116 | void mtc1(Register rt, FloatRegister fs) { emit_long(insn_COP1(mt_op, (int)rt->encoding(), (int)fs->encoding())); } |
aoqi@1 | 1117 | 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 | 1118 | 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 | 1119 | |
aoqi@1 | 1120 | void neg_s(FloatRegister fd, FloatRegister fs) { emit_long(insn_F3RO(single_fmt, 0, (int)fs->encoding(), (int)fd->encoding(), fneg_op)); } |
aoqi@1 | 1121 | void neg_d(FloatRegister fd, FloatRegister fs) { emit_long(insn_F3RO(double_fmt, 0, (int)fs->encoding(), (int)fd->encoding(), fneg_op)); } |
aoqi@1 | 1122 | |
aoqi@1 | 1123 | 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 | 1124 | 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 | 1125 | 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 | 1126 | 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 | 1127 | |
aoqi@1 | 1128 | void sdc1(FloatRegister ft, Register base, int off) { emit_long(insn_ORRI(sdc1_op, (int)base->encoding(), (int)ft->encoding(), off)); } |
aoqi@1 | 1129 | void sdc1(FloatRegister ft, Address dst); |
aoqi@1 | 1130 | void sqrt_s(FloatRegister fd, FloatRegister fs) { emit_long(insn_F3RO(single_fmt, 0, (int)fs->encoding(), (int)fd->encoding(), fsqrt_op)); } |
aoqi@1 | 1131 | void sqrt_d(FloatRegister fd, FloatRegister fs) { emit_long(insn_F3RO(double_fmt, 0, (int)fs->encoding(), (int)fd->encoding(), fsqrt_op)); } |
aoqi@1 | 1132 | 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 | 1133 | 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 | 1134 | void swc1(FloatRegister ft, Register base, int off) { emit_long(insn_ORRI(swc1_op, (int)base->encoding(), (int)ft->encoding(), off)); } |
aoqi@1 | 1135 | void swc1(FloatRegister ft, Address dst); |
aoqi@1 | 1136 | |
aoqi@1 | 1137 | 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 | 1138 | 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 | 1139 | 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 | 1140 | 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 | 1141 | |
aoqi@1 | 1142 | void int3(); |
aoqi@1 | 1143 | static void print_instruction(int); |
aoqi@1 | 1144 | int patched_branch(int dest_pos, int inst, int inst_pos); |
aoqi@1 | 1145 | int branch_destination(int inst, int pos); |
aoqi@1 | 1146 | |
aoqi@1 | 1147 | /* Godson3 extension */ |
aoqi@1 | 1148 | void gsldx(Register rt, Register base, Register index, int off) { |
aoqi@1 | 1149 | assert(is_simm(off, 8), "gsldx: off exceeds 8 bits"); |
aoqi@1 | 1150 | emit_long(gsldx_op | ((int)base->encoding() << 21) | ((int)rt->encoding() << 16) | ((int)index->encoding() << 11) | (off << 3)); |
aoqi@1 | 1151 | } |
aoqi@1 | 1152 | |
aoqi@1 | 1153 | void gslwx(Register rt, Register base, Register index, int off) { |
aoqi@1 | 1154 | assert(is_simm(off, 8), "gslwx: off exceeds 8 bits"); |
aoqi@1 | 1155 | emit_long(gslwx_op | ((int)base->encoding() << 21) | ((int)rt->encoding() << 16) | ((int)index->encoding() << 11) | (off << 3)); |
aoqi@1 | 1156 | } |
aoqi@1 | 1157 | |
aoqi@1 | 1158 | public: |
aoqi@1 | 1159 | // Creation |
aoqi@1 | 1160 | Assembler(CodeBuffer* code) : AbstractAssembler(code) { |
aoqi@1 | 1161 | #ifdef CHECK_DELAY |
aoqi@1 | 1162 | delay_state = no_delay; |
aoqi@1 | 1163 | #endif |
aoqi@1 | 1164 | } |
aoqi@1 | 1165 | |
aoqi@1 | 1166 | // Decoding |
aoqi@1 | 1167 | static address locate_operand(address inst, WhichOperand which); |
aoqi@1 | 1168 | static address locate_next_instruction(address inst); |
aoqi@1 | 1169 | }; |
aoqi@1 | 1170 | |
aoqi@1 | 1171 | |
aoqi@1 | 1172 | // MacroAssembler extends Assembler by frequently used macros. |
aoqi@1 | 1173 | // |
aoqi@1 | 1174 | // Instructions for which a 'better' code sequence exists depending |
aoqi@1 | 1175 | // on arguments should also go in here. |
aoqi@1 | 1176 | |
aoqi@1 | 1177 | class MacroAssembler: public Assembler { |
aoqi@1 | 1178 | friend class LIR_Assembler; |
aoqi@1 | 1179 | friend class Runtime1; // as_Address() |
aoqi@1 | 1180 | |
aoqi@1 | 1181 | public: |
aoqi@1 | 1182 | static intptr_t i[32]; |
aoqi@1 | 1183 | static float f[32]; |
aoqi@1 | 1184 | static void print(outputStream *s); |
aoqi@1 | 1185 | |
aoqi@1 | 1186 | static int i_offset(unsigned int k); |
aoqi@1 | 1187 | static int f_offset(unsigned int k); |
aoqi@1 | 1188 | |
aoqi@1 | 1189 | static void save_registers(MacroAssembler *masm); |
aoqi@1 | 1190 | static void restore_registers(MacroAssembler *masm); |
aoqi@1 | 1191 | |
aoqi@1 | 1192 | protected: |
aoqi@1 | 1193 | |
aoqi@1 | 1194 | Address as_Address(AddressLiteral adr); |
aoqi@1 | 1195 | Address as_Address(ArrayAddress adr); |
aoqi@1 | 1196 | |
aoqi@1 | 1197 | // Support for VM calls |
aoqi@1 | 1198 | // |
aoqi@1 | 1199 | // This is the base routine called by the different versions of call_VM_leaf. The interpreter |
aoqi@1 | 1200 | // may customize this version by overriding it for its purposes (e.g., to save/restore |
aoqi@1 | 1201 | // additional registers when doing a VM call). |
aoqi@1 | 1202 | #ifdef CC_INTERP |
aoqi@1 | 1203 | // c++ interpreter never wants to use interp_masm version of call_VM |
aoqi@1 | 1204 | #define VIRTUAL |
aoqi@1 | 1205 | #else |
aoqi@1 | 1206 | #define VIRTUAL virtual |
aoqi@1 | 1207 | #endif |
aoqi@1 | 1208 | |
aoqi@1 | 1209 | VIRTUAL void call_VM_leaf_base( |
aoqi@1 | 1210 | address entry_point, // the entry point |
aoqi@1 | 1211 | int number_of_arguments // the number of arguments to pop after the call |
aoqi@1 | 1212 | ); |
aoqi@1 | 1213 | |
aoqi@1 | 1214 | // This is the base routine called by the different versions of call_VM. The interpreter |
aoqi@1 | 1215 | // may customize this version by overriding it for its purposes (e.g., to save/restore |
aoqi@1 | 1216 | // additional registers when doing a VM call). |
aoqi@1 | 1217 | // |
aoqi@1 | 1218 | // If no java_thread register is specified (noreg) than rdi will be used instead. call_VM_base |
aoqi@1 | 1219 | // returns the register which contains the thread upon return. If a thread register has been |
aoqi@1 | 1220 | // specified, the return value will correspond to that register. If no last_java_sp is specified |
aoqi@1 | 1221 | // (noreg) than rsp will be used instead. |
aoqi@1 | 1222 | VIRTUAL void call_VM_base( // returns the register containing the thread upon return |
aoqi@1 | 1223 | Register oop_result, // where an oop-result ends up if any; use noreg otherwise |
aoqi@1 | 1224 | Register java_thread, // the thread if computed before ; use noreg otherwise |
aoqi@1 | 1225 | Register last_java_sp, // to set up last_Java_frame in stubs; use noreg otherwise |
aoqi@1 | 1226 | address entry_point, // the entry point |
aoqi@1 | 1227 | int number_of_arguments, // the number of arguments (w/o thread) to pop after the call |
aoqi@1 | 1228 | bool check_exceptions // whether to check for pending exceptions after return |
aoqi@1 | 1229 | ); |
aoqi@1 | 1230 | |
aoqi@1 | 1231 | // These routines should emit JVMTI PopFrame and ForceEarlyReturn handling code. |
aoqi@1 | 1232 | // The implementation is only non-empty for the InterpreterMacroAssembler, |
aoqi@1 | 1233 | // as only the interpreter handles PopFrame and ForceEarlyReturn requests. |
aoqi@1 | 1234 | virtual void check_and_handle_popframe(Register java_thread); |
aoqi@1 | 1235 | virtual void check_and_handle_earlyret(Register java_thread); |
aoqi@1 | 1236 | |
aoqi@1 | 1237 | void call_VM_helper(Register oop_result, address entry_point, int number_of_arguments, bool check_exceptions = true); |
aoqi@1 | 1238 | |
aoqi@1 | 1239 | // helpers for FPU flag access |
aoqi@1 | 1240 | // tmp is a temporary register, if none is available use noreg |
aoqi@1 | 1241 | //void save_rax (Register tmp); |
aoqi@1 | 1242 | //void restore_rax(Register tmp); |
aoqi@1 | 1243 | |
aoqi@1 | 1244 | public: |
aoqi@1 | 1245 | MacroAssembler(CodeBuffer* code) : Assembler(code) {} |
aoqi@1 | 1246 | |
aoqi@1 | 1247 | // Support for NULL-checks |
aoqi@1 | 1248 | // |
aoqi@1 | 1249 | // Generates code that causes a NULL OS exception if the content of reg is NULL. |
aoqi@1 | 1250 | // If the accessed location is M[reg + offset] and the offset is known, provide the |
aoqi@1 | 1251 | // offset. No explicit code generation is needed if the offset is within a certain |
aoqi@1 | 1252 | // range (0 <= offset <= page_size). |
aoqi@1 | 1253 | // use "teq 83, reg" in mips now, by yjl 6/20/2005 |
aoqi@1 | 1254 | void null_check(Register reg, int offset = -1); |
aoqi@1 | 1255 | static bool needs_explicit_null_check(intptr_t offset); |
aoqi@1 | 1256 | |
aoqi@1 | 1257 | // Required platform-specific helpers for Label::patch_instructions. |
aoqi@1 | 1258 | // They _shadow_ the declarations in AbstractAssembler, which are undefined. |
aoqi@1 | 1259 | void pd_patch_instruction(address branch, address target); |
aoqi@1 | 1260 | |
aoqi@1 | 1261 | // Alignment |
aoqi@1 | 1262 | void align(int modulus); |
aoqi@1 | 1263 | |
aoqi@1 | 1264 | // Misc |
aoqi@1 | 1265 | //void fat_nop(); // 5 byte nop |
aoqi@1 | 1266 | |
aoqi@1 | 1267 | // Stack frame creation/removal |
aoqi@1 | 1268 | void enter(); |
aoqi@1 | 1269 | void leave(); |
aoqi@1 | 1270 | |
aoqi@1 | 1271 | // Support for getting the JavaThread pointer (i.e.; a reference to thread-local information) |
aoqi@1 | 1272 | // The pointer will be loaded into the thread register. |
aoqi@1 | 1273 | void get_thread(Register thread); |
aoqi@1 | 1274 | |
aoqi@1 | 1275 | |
aoqi@1 | 1276 | // Support for VM calls |
aoqi@1 | 1277 | // |
aoqi@1 | 1278 | // It is imperative that all calls into the VM are handled via the call_VM macros. |
aoqi@1 | 1279 | // They make sure that the stack linkage is setup correctly. call_VM's correspond |
aoqi@1 | 1280 | // to ENTRY/ENTRY_X entry points while call_VM_leaf's correspond to LEAF entry points. |
aoqi@1 | 1281 | |
aoqi@1 | 1282 | |
aoqi@1 | 1283 | void call_VM(Register oop_result, |
aoqi@1 | 1284 | address entry_point, |
aoqi@1 | 1285 | bool check_exceptions = true); |
aoqi@1 | 1286 | void call_VM(Register oop_result, |
aoqi@1 | 1287 | address entry_point, |
aoqi@1 | 1288 | Register arg_1, |
aoqi@1 | 1289 | bool check_exceptions = true); |
aoqi@1 | 1290 | void call_VM(Register oop_result, |
aoqi@1 | 1291 | address entry_point, |
aoqi@1 | 1292 | Register arg_1, Register arg_2, |
aoqi@1 | 1293 | bool check_exceptions = true); |
aoqi@1 | 1294 | void call_VM(Register oop_result, |
aoqi@1 | 1295 | address entry_point, |
aoqi@1 | 1296 | Register arg_1, Register arg_2, Register arg_3, |
aoqi@1 | 1297 | bool check_exceptions = true); |
aoqi@1 | 1298 | // Super call_VM calls - correspond to MacroAssembler::call_VM(_leaf) calls |
aoqi@1 | 1299 | void super_call_VM_leaf(address entry_point); |
aoqi@1 | 1300 | void super_call_VM_leaf(address entry_point, Register arg_1); |
aoqi@1 | 1301 | void super_call_VM_leaf(address entry_point, Register arg_1, Register arg_2); |
aoqi@1 | 1302 | void super_call_VM_leaf(address entry_point, |
aoqi@1 | 1303 | Register arg_1, Register arg_2, Register arg_3); |
aoqi@1 | 1304 | |
aoqi@1 | 1305 | // Overloadings with last_Java_sp |
aoqi@1 | 1306 | void call_VM(Register oop_result, |
aoqi@1 | 1307 | Register last_java_sp, |
aoqi@1 | 1308 | address entry_point, |
aoqi@1 | 1309 | int number_of_arguments = 0, |
aoqi@1 | 1310 | bool check_exceptions = true); |
aoqi@1 | 1311 | void call_VM(Register oop_result, |
aoqi@1 | 1312 | Register last_java_sp, |
aoqi@1 | 1313 | address entry_point, |
aoqi@1 | 1314 | Register arg_1, bool |
aoqi@1 | 1315 | check_exceptions = true); |
aoqi@1 | 1316 | void call_VM(Register oop_result, |
aoqi@1 | 1317 | Register last_java_sp, |
aoqi@1 | 1318 | address entry_point, |
aoqi@1 | 1319 | Register arg_1, Register arg_2, |
aoqi@1 | 1320 | bool check_exceptions = true); |
aoqi@1 | 1321 | void call_VM(Register oop_result, |
aoqi@1 | 1322 | Register last_java_sp, |
aoqi@1 | 1323 | address entry_point, |
aoqi@1 | 1324 | Register arg_1, Register arg_2, Register arg_3, |
aoqi@1 | 1325 | bool check_exceptions = true); |
aoqi@1 | 1326 | |
aoqi@1 | 1327 | void call_VM_leaf(address entry_point, |
aoqi@1 | 1328 | int number_of_arguments = 0); |
aoqi@1 | 1329 | void call_VM_leaf(address entry_point, |
aoqi@1 | 1330 | Register arg_1); |
aoqi@1 | 1331 | void call_VM_leaf(address entry_point, |
aoqi@1 | 1332 | Register arg_1, Register arg_2); |
aoqi@1 | 1333 | void call_VM_leaf(address entry_point, |
aoqi@1 | 1334 | Register arg_1, Register arg_2, Register arg_3); |
aoqi@1 | 1335 | |
aoqi@1 | 1336 | // last Java Frame (fills frame anchor) |
aoqi@1 | 1337 | void set_last_Java_frame(Register thread, |
aoqi@1 | 1338 | Register last_java_sp, |
aoqi@1 | 1339 | Register last_java_fp, |
aoqi@1 | 1340 | address last_java_pc); |
aoqi@1 | 1341 | |
aoqi@1 | 1342 | // thread in the default location (r15_thread on 64bit) |
aoqi@1 | 1343 | void set_last_Java_frame(Register last_java_sp, |
aoqi@1 | 1344 | Register last_java_fp, |
aoqi@1 | 1345 | address last_java_pc); |
aoqi@1 | 1346 | |
aoqi@1 | 1347 | void reset_last_Java_frame(Register thread, bool clear_fp, bool clear_pc); |
aoqi@1 | 1348 | |
aoqi@1 | 1349 | // thread in the default location (r15_thread on 64bit) |
aoqi@1 | 1350 | void reset_last_Java_frame(bool clear_fp, bool clear_pc); |
aoqi@1 | 1351 | |
aoqi@1 | 1352 | // Stores |
aoqi@1 | 1353 | void store_check(Register obj); // store check for obj - register is destroyed afterwards |
aoqi@1 | 1354 | void store_check(Register obj, Address dst); // same as above, dst is exact store location (reg. is destroyed) |
aoqi@1 | 1355 | |
aoqi@1 | 1356 | |
aoqi@1 | 1357 | void g1_write_barrier_pre(Register obj, |
aoqi@1 | 1358 | #ifndef _LP64 |
aoqi@1 | 1359 | Register thread, |
aoqi@1 | 1360 | #endif |
aoqi@1 | 1361 | Register tmp, |
aoqi@1 | 1362 | Register tmp2, |
aoqi@1 | 1363 | bool tosca_live); |
aoqi@1 | 1364 | void g1_write_barrier_post(Register store_addr, |
aoqi@1 | 1365 | Register new_val, |
aoqi@1 | 1366 | #ifndef _LP64 |
aoqi@1 | 1367 | Register thread, |
aoqi@1 | 1368 | #endif |
aoqi@1 | 1369 | Register tmp, |
aoqi@1 | 1370 | Register tmp2); |
aoqi@1 | 1371 | |
aoqi@1 | 1372 | |
aoqi@1 | 1373 | |
aoqi@1 | 1374 | // split store_check(Register obj) to enhance instruction interleaving |
aoqi@1 | 1375 | void store_check_part_1(Register obj); |
aoqi@1 | 1376 | void store_check_part_2(Register obj); |
aoqi@1 | 1377 | |
aoqi@1 | 1378 | // C 'boolean' to Java boolean: x == 0 ? 0 : 1 |
aoqi@1 | 1379 | void c2bool(Register x); |
aoqi@1 | 1380 | //add for compressedoops |
aoqi@1 | 1381 | void load_klass(Register dst, Register src); |
aoqi@1 | 1382 | void store_klass(Register dst, Register src); |
aoqi@1 | 1383 | void load_prototype_header(Register dst, Register src); |
aoqi@1 | 1384 | /* |
aoqi@1 | 1385 | // C++ bool manipulation |
aoqi@1 | 1386 | |
aoqi@1 | 1387 | void movbool(Register dst, Address src); |
aoqi@1 | 1388 | void movbool(Address dst, bool boolconst); |
aoqi@1 | 1389 | void movbool(Address dst, Register src); |
aoqi@1 | 1390 | void testbool(Register dst); |
aoqi@1 | 1391 | |
aoqi@1 | 1392 | // oop manipulations |
aoqi@1 | 1393 | void load_klass(Register dst, Register src); |
aoqi@1 | 1394 | void store_klass(Register dst, Register src); |
aoqi@1 | 1395 | |
aoqi@1 | 1396 | void load_prototype_header(Register dst, Register src);*/ |
aoqi@1 | 1397 | |
aoqi@1 | 1398 | #ifdef _LP64 |
aoqi@1 | 1399 | void store_klass_gap(Register dst, Register src); |
aoqi@1 | 1400 | |
aoqi@1 | 1401 | void load_heap_oop(Register dst, Address src); |
aoqi@1 | 1402 | void store_heap_oop(Address dst, Register src); |
aoqi@1 | 1403 | void encode_heap_oop(Register r); |
aoqi@1 | 1404 | void decode_heap_oop(Register r); |
aoqi@1 | 1405 | void encode_heap_oop_not_null(Register r); |
aoqi@1 | 1406 | void decode_heap_oop_not_null(Register r); |
aoqi@1 | 1407 | void encode_heap_oop_not_null(Register dst, Register src); |
aoqi@1 | 1408 | void decode_heap_oop_not_null(Register dst, Register src); |
aoqi@1 | 1409 | |
aoqi@1 | 1410 | void encode_klass_not_null(Register r); |
aoqi@1 | 1411 | void decode_klass_not_null(Register r); |
aoqi@1 | 1412 | void encode_klass_not_null(Register dst, Register src); |
aoqi@1 | 1413 | void decode_klass_not_null(Register dst, Register src); |
aoqi@1 | 1414 | |
aoqi@1 | 1415 | //void set_narrow_oop(Register dst, jobject obj); |
aoqi@1 | 1416 | |
aoqi@1 | 1417 | // Returns the byte size of the instructions generated by decode_klass_not_null() |
aoqi@1 | 1418 | // when compressed klass pointers are being used. |
aoqi@1 | 1419 | static int instr_size_for_decode_klass_not_null(); |
aoqi@1 | 1420 | |
aoqi@1 | 1421 | // if heap base register is used - reinit it with the correct value |
aoqi@1 | 1422 | void reinit_heapbase(); |
aoqi@1 | 1423 | DEBUG_ONLY(void verify_heapbase(const char* msg);) |
aoqi@1 | 1424 | |
aoqi@1 | 1425 | #endif // _LP64 |
aoqi@1 | 1426 | |
aoqi@1 | 1427 | void incrementl(Register reg, int value = 1); |
aoqi@1 | 1428 | |
aoqi@1 | 1429 | void decrementl(Register reg, int value = 1); |
aoqi@1 | 1430 | |
aoqi@1 | 1431 | /* |
aoqi@1 | 1432 | // Int division/remainder for Java |
aoqi@1 | 1433 | // (as idivl, but checks for special case as described in JVM spec.) |
aoqi@1 | 1434 | // returns idivl instruction offset for implicit exception handling |
aoqi@1 | 1435 | int corrected_idivl(Register reg); |
aoqi@1 | 1436 | |
aoqi@1 | 1437 | // Long division/remainder for Java |
aoqi@1 | 1438 | // (as idivq, but checks for special case as described in JVM spec.) |
aoqi@1 | 1439 | // returns idivq instruction offset for implicit exception handling |
aoqi@1 | 1440 | int corrected_idivq(Register reg); |
aoqi@1 | 1441 | */ |
aoqi@1 | 1442 | |
aoqi@1 | 1443 | void int3(); |
aoqi@1 | 1444 | /* |
aoqi@1 | 1445 | // Long operation macros for a 32bit cpu |
aoqi@1 | 1446 | // Long negation for Java |
aoqi@1 | 1447 | void lneg(Register hi, Register lo); |
aoqi@1 | 1448 | |
aoqi@1 | 1449 | // Long multiplication for Java |
aoqi@1 | 1450 | // (destroys contents of eax, ebx, ecx and edx) |
aoqi@1 | 1451 | void lmul(int x_rsp_offset, int y_rsp_offset); // rdx:rax = x * y |
aoqi@1 | 1452 | |
aoqi@1 | 1453 | // Long shifts for Java |
aoqi@1 | 1454 | // (semantics as described in JVM spec.) |
aoqi@1 | 1455 | void lshl(Register hi, Register lo); // hi:lo << (rcx & 0x3f) |
aoqi@1 | 1456 | void lshr(Register hi, Register lo, bool sign_extension = false); // hi:lo >> (rcx & 0x3f) |
aoqi@1 | 1457 | |
aoqi@1 | 1458 | // Long compare for Java |
aoqi@1 | 1459 | // (semantics as described in JVM spec.) |
aoqi@1 | 1460 | void lcmp2int(Register x_hi, Register x_lo, Register y_hi, Register y_lo); // x_hi = lcmp(x, y) |
aoqi@1 | 1461 | |
aoqi@1 | 1462 | |
aoqi@1 | 1463 | // misc |
aoqi@1 | 1464 | */ |
aoqi@1 | 1465 | // Sign extension |
aoqi@1 | 1466 | #ifdef _LP64 |
aoqi@1 | 1467 | void sign_extend_short(Register reg) { dsll32(reg, reg, 16); dsra32(reg, reg, 16); } |
aoqi@1 | 1468 | void sign_extend_byte(Register reg) { dsll32(reg, reg, 24); dsra32(reg, reg, 24); } |
aoqi@1 | 1469 | #else |
aoqi@1 | 1470 | void sign_extend_short(Register reg) { sll(reg, reg, 16); sra(reg, reg, 16); } |
aoqi@1 | 1471 | void sign_extend_byte(Register reg) { sll(reg, reg, 24); sra(reg, reg, 24); } |
aoqi@1 | 1472 | #endif |
aoqi@1 | 1473 | void rem_s(FloatRegister fd, FloatRegister fs, FloatRegister ft, FloatRegister tmp); |
aoqi@1 | 1474 | void rem_d(FloatRegister fd, FloatRegister fs, FloatRegister ft, FloatRegister tmp); |
aoqi@1 | 1475 | |
aoqi@1 | 1476 | // Inlined sin/cos generator for Java; must not use CPU instruction |
aoqi@1 | 1477 | // directly on Intel as it does not have high enough precision |
aoqi@1 | 1478 | // outside of the range [-pi/4, pi/4]. Extra argument indicate the |
aoqi@1 | 1479 | // number of FPU stack slots in use; all but the topmost will |
aoqi@1 | 1480 | // require saving if a slow case is necessary. Assumes argument is |
aoqi@1 | 1481 | // on FP TOS; result is on FP TOS. No cpu registers are changed by |
aoqi@1 | 1482 | // this code. |
aoqi@1 | 1483 | void trigfunc(char trig, int num_fpu_regs_in_use = 1); |
aoqi@1 | 1484 | /* |
aoqi@1 | 1485 | // branch to L if FPU flag C2 is set/not set |
aoqi@1 | 1486 | // tmp is a temporary register, if none is available use noreg |
aoqi@1 | 1487 | void jC2 (Register tmp, Label& L); |
aoqi@1 | 1488 | void jnC2(Register tmp, Label& L); |
aoqi@1 | 1489 | |
aoqi@1 | 1490 | // Pop ST (ffree & fincstp combined) |
aoqi@1 | 1491 | void fpop(); |
aoqi@1 | 1492 | |
aoqi@1 | 1493 | // pushes double TOS element of FPU stack on CPU stack; pops from FPU stack |
aoqi@1 | 1494 | void push_fTOS(); |
aoqi@1 | 1495 | |
aoqi@1 | 1496 | // pops double TOS element from CPU stack and pushes on FPU stack |
aoqi@1 | 1497 | void pop_fTOS(); |
aoqi@1 | 1498 | |
aoqi@1 | 1499 | void empty_FPU_stack(); |
aoqi@1 | 1500 | |
aoqi@1 | 1501 | void push_IU_state(); |
aoqi@1 | 1502 | void pop_IU_state(); |
aoqi@1 | 1503 | |
aoqi@1 | 1504 | void push_FPU_state(); |
aoqi@1 | 1505 | void pop_FPU_state(); |
aoqi@1 | 1506 | |
aoqi@1 | 1507 | void push_CPU_state(); |
aoqi@1 | 1508 | void pop_CPU_state(); |
aoqi@1 | 1509 | |
aoqi@1 | 1510 | // Round up to a power of two |
aoqi@1 | 1511 | void round_to(Register reg, int modulus); |
aoqi@1 | 1512 | |
aoqi@1 | 1513 | // Callee saved registers handling |
aoqi@1 | 1514 | void push_callee_saved_registers(); |
aoqi@1 | 1515 | void pop_callee_saved_registers(); |
aoqi@1 | 1516 | */ |
aoqi@1 | 1517 | // allocation |
aoqi@1 | 1518 | void eden_allocate( |
aoqi@1 | 1519 | Register obj, // result: pointer to object after successful allocation |
aoqi@1 | 1520 | Register var_size_in_bytes, // object size in bytes if unknown at compile time; invalid otherwise |
aoqi@1 | 1521 | int con_size_in_bytes, // object size in bytes if known at compile time |
aoqi@1 | 1522 | Register t1, // temp register |
aoqi@1 | 1523 | Register t2, |
aoqi@1 | 1524 | Label& slow_case // continuation point if fast allocation fails |
aoqi@1 | 1525 | ); |
aoqi@1 | 1526 | void tlab_allocate( |
aoqi@1 | 1527 | Register obj, // result: pointer to object after successful allocation |
aoqi@1 | 1528 | Register var_size_in_bytes, // object size in bytes if unknown at compile time; invalid otherwise |
aoqi@1 | 1529 | int con_size_in_bytes, // object size in bytes if known at compile time |
aoqi@1 | 1530 | Register t1, // temp register |
aoqi@1 | 1531 | Register t2, // temp register |
aoqi@1 | 1532 | Label& slow_case // continuation point if fast allocation fails |
aoqi@1 | 1533 | ); |
aoqi@1 | 1534 | void tlab_refill(Label& retry_tlab, Label& try_eden, Label& slow_case); |
aoqi@1 | 1535 | |
aoqi@1 | 1536 | //---- |
aoqi@1 | 1537 | // void set_word_if_not_zero(Register reg); // sets reg to 1 if not zero, otherwise 0 |
aoqi@1 | 1538 | |
aoqi@1 | 1539 | |
aoqi@1 | 1540 | // Debugging |
aoqi@1 | 1541 | |
aoqi@1 | 1542 | // only if +VerifyOops |
aoqi@1 | 1543 | void verify_oop(Register reg, const char* s = "broken oop"); |
aoqi@1 | 1544 | void verify_oop_addr(Address addr, const char * s = "broken oop addr"); |
aoqi@1 | 1545 | void verify_oop_subroutine(); |
aoqi@1 | 1546 | // TODO: verify method and klass metadata (compare against vptr?) |
aoqi@1 | 1547 | void _verify_method_ptr(Register reg, const char * msg, const char * file, int line) {} |
aoqi@1 | 1548 | void _verify_klass_ptr(Register reg, const char * msg, const char * file, int line){} |
aoqi@1 | 1549 | |
aoqi@1 | 1550 | #define verify_method_ptr(reg) _verify_method_ptr(reg, "broken method " #reg, __FILE__, __LINE__) |
aoqi@1 | 1551 | #define verify_klass_ptr(reg) _verify_klass_ptr(reg, "broken klass " #reg, __FILE__, __LINE__) |
aoqi@1 | 1552 | |
aoqi@1 | 1553 | // only if +VerifyFPU |
aoqi@1 | 1554 | void verify_FPU(int stack_depth, const char* s = "illegal FPU state"); |
aoqi@1 | 1555 | |
aoqi@1 | 1556 | // prints msg, dumps registers and stops execution |
aoqi@1 | 1557 | void stop(const char* msg); |
aoqi@1 | 1558 | |
aoqi@1 | 1559 | // prints msg and continues |
aoqi@1 | 1560 | void warn(const char* msg); |
aoqi@1 | 1561 | |
aoqi@1 | 1562 | static void debug(char* msg/*, RegistersForDebugging* regs*/); |
aoqi@1 | 1563 | 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 | 1564 | static void debug64(char* msg, int64_t pc, int64_t regs[]); |
aoqi@1 | 1565 | |
aoqi@1 | 1566 | void print_reg(Register reg); |
aoqi@1 | 1567 | void print_reg(FloatRegister reg); |
aoqi@1 | 1568 | //void os_breakpoint(); |
aoqi@1 | 1569 | |
aoqi@1 | 1570 | void untested() { stop("untested"); } |
aoqi@1 | 1571 | |
aoqi@1 | 1572 | void unimplemented(const char* what = "") { char* b = new char[1024]; jio_snprintf(b, sizeof(b), "unimplemented: %s", what); stop(b); } |
aoqi@1 | 1573 | |
aoqi@1 | 1574 | void should_not_reach_here() { stop("should not reach here"); } |
aoqi@1 | 1575 | |
aoqi@1 | 1576 | void print_CPU_state(); |
aoqi@1 | 1577 | |
aoqi@1 | 1578 | // Stack overflow checking |
aoqi@1 | 1579 | void bang_stack_with_offset(int offset) { |
aoqi@1 | 1580 | // stack grows down, caller passes positive offset |
aoqi@1 | 1581 | assert(offset > 0, "must bang with negative offset"); |
aoqi@1 | 1582 | if (offset <= 32768) { |
aoqi@1 | 1583 | sw(A0, SP, -offset); |
aoqi@1 | 1584 | } else { |
aoqi@1 | 1585 | #ifdef _LP64 |
aoqi@1 | 1586 | li(AT, offset); |
aoqi@1 | 1587 | dsub(AT, SP, AT); |
aoqi@1 | 1588 | #else |
aoqi@1 | 1589 | move(AT, offset); |
aoqi@1 | 1590 | sub(AT, SP, AT); |
aoqi@1 | 1591 | #endif |
aoqi@1 | 1592 | sw(A0, AT, 0); |
aoqi@1 | 1593 | } |
aoqi@1 | 1594 | } |
aoqi@1 | 1595 | |
aoqi@1 | 1596 | // Writes to stack successive pages until offset reached to check for |
aoqi@1 | 1597 | // stack overflow + shadow pages. Also, clobbers tmp |
aoqi@1 | 1598 | void bang_stack_size(Register size, Register tmp); |
aoqi@1 | 1599 | virtual RegisterOrConstant delayed_value_impl(intptr_t* delayed_value_addr, |
aoqi@1 | 1600 | Register tmp, |
aoqi@1 | 1601 | int offset); |
aoqi@1 | 1602 | |
aoqi@1 | 1603 | // Support for serializing memory accesses between threads |
aoqi@1 | 1604 | void serialize_memory(Register thread, Register tmp); |
aoqi@1 | 1605 | |
aoqi@1 | 1606 | //void verify_tlab(); |
aoqi@1 | 1607 | void verify_tlab(Register t1, Register t2); |
aoqi@1 | 1608 | |
aoqi@1 | 1609 | // Biased locking support |
aoqi@1 | 1610 | // lock_reg and obj_reg must be loaded up with the appropriate values. |
aoqi@1 | 1611 | // swap_reg must be rax, and is killed. |
aoqi@1 | 1612 | // tmp_reg is optional. If it is supplied (i.e., != noreg) it will |
aoqi@1 | 1613 | // be killed; if not supplied, push/pop will be used internally to |
aoqi@1 | 1614 | // allocate a temporary (inefficient, avoid if possible). |
aoqi@1 | 1615 | // Optional slow case is for implementations (interpreter and C1) which branch to |
aoqi@1 | 1616 | // slow case directly. Leaves condition codes set for C2's Fast_Lock node. |
aoqi@1 | 1617 | // Returns offset of first potentially-faulting instruction for null |
aoqi@1 | 1618 | // check info (currently consumed only by C1). If |
aoqi@1 | 1619 | // swap_reg_contains_mark is true then returns -1 as it is assumed |
aoqi@1 | 1620 | // the calling code has already passed any potential faults. |
aoqi@1 | 1621 | int biased_locking_enter(Register lock_reg, Register obj_reg, |
aoqi@1 | 1622 | Register swap_reg, Register tmp_reg, |
aoqi@1 | 1623 | bool swap_reg_contains_mark, |
aoqi@1 | 1624 | Label& done, Label* slow_case = NULL, |
aoqi@1 | 1625 | BiasedLockingCounters* counters = NULL); |
aoqi@1 | 1626 | void biased_locking_exit (Register obj_reg, Register temp_reg, Label& done); |
aoqi@1 | 1627 | |
aoqi@1 | 1628 | |
aoqi@1 | 1629 | // Calls |
aoqi@1 | 1630 | |
aoqi@1 | 1631 | void call(address entry); |
aoqi@1 | 1632 | void call(address entry, relocInfo::relocType rtype); |
aoqi@1 | 1633 | void call(address entry, RelocationHolder& rh); |
aoqi@1 | 1634 | // Emit the CompiledIC call idiom |
aoqi@1 | 1635 | void ic_call(address entry); |
aoqi@1 | 1636 | |
aoqi@1 | 1637 | void jmp(address entry); |
aoqi@1 | 1638 | void jmp(address entry, relocInfo::relocType rtype); |
aoqi@1 | 1639 | |
aoqi@1 | 1640 | // Argument ops |
aoqi@1 | 1641 | /*inline void store_int_argument(Register s, Argument& a); |
aoqi@1 | 1642 | inline void store_long_argument(Register s, Argument& a); |
aoqi@1 | 1643 | inline void store_float_argument(FloatRegister s, Argument& a); |
aoqi@1 | 1644 | inline void store_double_argument(FloatRegister s, Argument& a); |
aoqi@1 | 1645 | inline void store_ptr_argument(Register s, Argument& a);*/ |
aoqi@1 | 1646 | inline void store_int_argument(Register s, Argument &a) { |
aoqi@1 | 1647 | if(a.is_Register()) { |
aoqi@1 | 1648 | move(a.as_Register(), s); |
aoqi@1 | 1649 | } else { |
aoqi@1 | 1650 | sw(s, a.as_caller_address()); |
aoqi@1 | 1651 | } |
aoqi@1 | 1652 | } |
aoqi@1 | 1653 | |
aoqi@1 | 1654 | inline void store_long_argument(Register s, Argument &a) { |
aoqi@1 | 1655 | Argument a1 = a.successor(); |
aoqi@1 | 1656 | if(a.is_Register() && a1.is_Register()) { |
aoqi@1 | 1657 | move(a.as_Register(), s); |
aoqi@1 | 1658 | move(a.as_Register(), s); |
aoqi@1 | 1659 | } else { |
aoqi@1 | 1660 | sd(s, a.as_caller_address()); |
aoqi@1 | 1661 | } |
aoqi@1 | 1662 | } |
aoqi@1 | 1663 | |
aoqi@1 | 1664 | inline void store_float_argument(FloatRegister s, Argument &a) { |
aoqi@1 | 1665 | if(a.is_Register()) { |
aoqi@1 | 1666 | mov_s(a.as_FloatRegister(), s); |
aoqi@1 | 1667 | } else { |
aoqi@1 | 1668 | swc1(s, a.as_caller_address()); |
aoqi@1 | 1669 | } |
aoqi@1 | 1670 | } |
aoqi@1 | 1671 | inline void store_double_argument(FloatRegister s, Argument &a) { |
aoqi@1 | 1672 | if(a.is_Register()) { |
aoqi@1 | 1673 | mov_d(a.as_FloatRegister(), s); |
aoqi@1 | 1674 | } else { |
aoqi@1 | 1675 | sdc1(s, a.as_caller_address()); |
aoqi@1 | 1676 | } |
aoqi@1 | 1677 | } |
aoqi@1 | 1678 | |
aoqi@1 | 1679 | inline void store_ptr_argument(Register s, Argument &a) { |
aoqi@1 | 1680 | if(a.is_Register()) { |
aoqi@1 | 1681 | move(a.as_Register(), s); |
aoqi@1 | 1682 | } else { |
aoqi@1 | 1683 | st_ptr(s, a.as_caller_address()); |
aoqi@1 | 1684 | } |
aoqi@1 | 1685 | } |
aoqi@1 | 1686 | |
aoqi@1 | 1687 | // Load and store values by size and signed-ness |
aoqi@1 | 1688 | void load_sized_value(Register dst, Address src, size_t size_in_bytes, bool is_signed, Register dst2 = noreg); |
aoqi@1 | 1689 | void store_sized_value(Address dst, Register src, size_t size_in_bytes, Register src2 = noreg); |
aoqi@1 | 1690 | |
aoqi@1 | 1691 | // interface method calling |
aoqi@1 | 1692 | void lookup_interface_method(Register recv_klass, |
aoqi@1 | 1693 | Register intf_klass, |
aoqi@1 | 1694 | RegisterOrConstant itable_index, |
aoqi@1 | 1695 | Register method_result, |
aoqi@1 | 1696 | Register scan_temp, |
aoqi@1 | 1697 | Label& no_such_interface); |
aoqi@1 | 1698 | // virtual method calling |
aoqi@1 | 1699 | void lookup_virtual_method(Register recv_klass, |
aoqi@1 | 1700 | RegisterOrConstant vtable_index, |
aoqi@1 | 1701 | Register method_result); |
aoqi@1 | 1702 | |
aoqi@1 | 1703 | // ld_ptr will perform lw for 32 bit VMs and ld for 64 bit VMs |
aoqi@1 | 1704 | // st_ptr will perform sw for 32 bit VMs and sd for 64 bit VMs |
aoqi@1 | 1705 | inline void ld_ptr(Register rt, Address a){ |
aoqi@1 | 1706 | #ifdef _LP64 |
aoqi@1 | 1707 | ld(rt, a.base(), a.disp()); |
aoqi@1 | 1708 | #else |
aoqi@1 | 1709 | lw(rt, a.base(), a.disp()); |
aoqi@1 | 1710 | #endif |
aoqi@1 | 1711 | } |
aoqi@1 | 1712 | inline void ld_ptr(Register rt, Register base, int offset16){ |
aoqi@1 | 1713 | #ifdef _LP64 |
aoqi@1 | 1714 | ld(rt, base, offset16); |
aoqi@1 | 1715 | #else |
aoqi@1 | 1716 | lw(rt, base, offset16); |
aoqi@1 | 1717 | #endif |
aoqi@1 | 1718 | |
aoqi@1 | 1719 | } |
aoqi@1 | 1720 | inline void st_ptr(Register rt, Address a){ |
aoqi@1 | 1721 | #ifdef _LP64 |
aoqi@1 | 1722 | sd(rt, a.base(), a.disp()); |
aoqi@1 | 1723 | #else |
aoqi@1 | 1724 | sw(rt, a.base(), a.disp()); |
aoqi@1 | 1725 | #endif |
aoqi@1 | 1726 | } |
aoqi@1 | 1727 | inline void st_ptr(Register rt, Register base, int offset16) { |
aoqi@1 | 1728 | #ifdef _LP64 |
aoqi@1 | 1729 | sd(rt, base, offset16); |
aoqi@1 | 1730 | #else |
aoqi@1 | 1731 | sw(rt, base, offset16); |
aoqi@1 | 1732 | #endif |
aoqi@1 | 1733 | |
aoqi@1 | 1734 | } |
aoqi@1 | 1735 | |
aoqi@1 | 1736 | void ld_ptr(Register rt, Register offset, Register base); |
aoqi@1 | 1737 | void st_ptr(Register rt, Register offset, Register base); |
aoqi@1 | 1738 | |
aoqi@1 | 1739 | // ld_long will perform lw for 32 bit VMs and ld for 64 bit VMs |
aoqi@1 | 1740 | // st_long will perform sw for 32 bit VMs and sd for 64 bit VMs |
aoqi@1 | 1741 | inline void ld_long(Register rt, Register base, int offset16); |
aoqi@1 | 1742 | inline void st_long(Register rt, Register base, int offset16); |
aoqi@1 | 1743 | inline void ld_long(Register rt, Address a); |
aoqi@1 | 1744 | inline void st_long(Register rt, Address a); |
aoqi@1 | 1745 | |
aoqi@1 | 1746 | |
aoqi@1 | 1747 | void ld_long(Register rt, Register offset, Register base); |
aoqi@1 | 1748 | void st_long(Register rt, Register offset, Register base); |
aoqi@1 | 1749 | // Regular vs. d* versions |
aoqi@1 | 1750 | inline void addu_long(Register rd, Register rs, Register rt) { |
aoqi@1 | 1751 | #ifdef _LP64 |
aoqi@1 | 1752 | daddu(rd, rs, rt); |
aoqi@1 | 1753 | #else |
aoqi@1 | 1754 | addu(rd, rs, rt); |
aoqi@1 | 1755 | #endif |
aoqi@1 | 1756 | } |
aoqi@1 | 1757 | inline void addu_long(Register rd, Register rs, long imm32_64) { |
aoqi@1 | 1758 | #ifdef _LP64 |
aoqi@1 | 1759 | daddiu(rd, rs, imm32_64); |
aoqi@1 | 1760 | #else |
aoqi@1 | 1761 | addiu(rd, rs, imm32_64); |
aoqi@1 | 1762 | #endif |
aoqi@1 | 1763 | |
aoqi@1 | 1764 | } |
aoqi@1 | 1765 | |
aoqi@1 | 1766 | // Floating |
aoqi@1 | 1767 | public: |
aoqi@1 | 1768 | // swap the two byte of the low 16-bit halfword |
aoqi@1 | 1769 | // this directive will use AT, be sure the high 16-bit of reg is zero |
aoqi@1 | 1770 | // by yjl 6/28/2005 |
aoqi@1 | 1771 | void hswap(Register reg); |
aoqi@1 | 1772 | void huswap(Register reg); |
aoqi@1 | 1773 | |
aoqi@1 | 1774 | // convert big endian integer to little endian integer |
aoqi@1 | 1775 | // by yjl 6/29/2005 |
aoqi@1 | 1776 | void swap(Register reg); |
aoqi@1 | 1777 | |
aoqi@1 | 1778 | // implement the x86 instruction semantic |
aoqi@1 | 1779 | // if c_reg == *dest then *dest <= x_reg |
aoqi@1 | 1780 | // else c_reg <= *dest |
aoqi@1 | 1781 | // the AT indicate if xchg occurred, 1 for xchged, else 0 |
aoqi@1 | 1782 | // by yjl 6/28/2005 |
aoqi@1 | 1783 | void cmpxchg(Register x_reg, Address dest, Register c_reg); |
aoqi@1 | 1784 | #ifdef _LP64 |
aoqi@1 | 1785 | void cmpxchg32(Register x_reg, Address dest, Register c_reg); |
aoqi@1 | 1786 | #endif |
aoqi@1 | 1787 | void cmpxchg8(Register x_regLo, Register x_regHi, Address dest, Register c_regLo, Register c_regHi); |
aoqi@1 | 1788 | |
aoqi@1 | 1789 | |
aoqi@1 | 1790 | |
aoqi@1 | 1791 | void round_to(Register reg, int modulus) { |
aoqi@1 | 1792 | assert_different_registers(reg, AT); |
aoqi@1 | 1793 | increment(reg, modulus - 1); |
aoqi@1 | 1794 | move(AT, - modulus); |
aoqi@1 | 1795 | andr(reg, reg, AT); |
aoqi@1 | 1796 | } |
aoqi@1 | 1797 | |
aoqi@1 | 1798 | //pop & push, added by aoqi |
aoqi@1 | 1799 | #ifdef _LP64 |
aoqi@1 | 1800 | void extend_sign(Register rh, Register rl) { stop("extend_sign"); } |
aoqi@1 | 1801 | void neg(Register reg) { dsubu(reg, R0, reg); } |
aoqi@1 | 1802 | void push (Register reg) { sd (reg, SP, -8); daddi(SP, SP, -8); } |
aoqi@1 | 1803 | void push (FloatRegister reg) { sdc1(reg, SP, -8); daddi(SP, SP, -8); } |
aoqi@1 | 1804 | void pop (Register reg) { ld (reg, SP, 0); daddi(SP, SP, 8); } |
aoqi@1 | 1805 | void pop (FloatRegister reg) { ldc1(reg, SP, 0); daddi(SP, SP, 8); } |
aoqi@1 | 1806 | void pop () { daddi(SP, SP, 8); } |
aoqi@1 | 1807 | void pop2 () { daddi(SP, SP, 16); } |
aoqi@1 | 1808 | #else |
aoqi@1 | 1809 | void extend_sign(Register rh, Register rl) { sra(rh, rl, 31); } |
aoqi@1 | 1810 | void neg(Register reg) { subu(reg, R0, reg); } |
aoqi@1 | 1811 | void push (Register reg) { sw (reg, SP, -4); addi(SP, SP, -4); } |
aoqi@1 | 1812 | void push (FloatRegister reg) { swc1(reg, SP, -4); addi(SP, SP, -4); } |
aoqi@1 | 1813 | void pop (Register reg) { lw (reg, SP, 0); addi(SP, SP, 4); } |
aoqi@1 | 1814 | void pop (FloatRegister reg) { lwc1(reg, SP, 0); addi(SP, SP, 4); } |
aoqi@1 | 1815 | void pop () { addi(SP, SP, 4); } |
aoqi@1 | 1816 | void pop2 () { addi(SP, SP, 8); } |
aoqi@1 | 1817 | #endif |
aoqi@1 | 1818 | void push2(Register reg1, Register reg2); |
aoqi@1 | 1819 | void pop2 (Register reg1, Register reg2); |
aoqi@1 | 1820 | void dpush (Register reg) { sd (reg, SP, -8); daddi(SP, SP, -8); } |
aoqi@1 | 1821 | void dpop (Register reg) { ld (reg, SP, 0); daddi(SP, SP, 8); } |
aoqi@1 | 1822 | |
aoqi@1 | 1823 | /* branches may exceed 16-bit offset */ |
aoqi@1 | 1824 | void b_far(address entry); |
aoqi@1 | 1825 | void b_far(Label& L); |
aoqi@1 | 1826 | |
aoqi@1 | 1827 | void bne_far (Register rs, Register rt, address entry); |
aoqi@1 | 1828 | void bne_far (Register rs, Register rt, Label& L); |
aoqi@1 | 1829 | |
aoqi@1 | 1830 | void beq_far (Register rs, Register rt, address entry); |
aoqi@1 | 1831 | void beq_far (Register rs, Register rt, Label& L); |
aoqi@1 | 1832 | |
aoqi@1 | 1833 | //move an 32-bit immediate to Register |
aoqi@1 | 1834 | void move(Register reg, int imm32) { li32(reg, imm32); } |
aoqi@1 | 1835 | void li (Register rd, long imm); |
aoqi@1 | 1836 | void li (Register rd, address addr) { li(rd, (long)addr); } |
aoqi@1 | 1837 | //replace move(Register reg, int imm) |
aoqi@1 | 1838 | void li32(Register rd, int imm32); // sign-extends to 64 bits on mips64 |
aoqi@1 | 1839 | #ifdef _LP64 |
aoqi@1 | 1840 | void dli(Register rd, long imm) { li(rd, imm); } |
aoqi@1 | 1841 | void li64(Register rd, long imm); |
aoqi@1 | 1842 | void li48(Register rd, long imm); |
aoqi@1 | 1843 | #endif |
aoqi@1 | 1844 | |
aoqi@1 | 1845 | #ifdef _LP64 |
aoqi@1 | 1846 | void move(Register rd, Register rs) { dadd(rd, rs, R0); } |
aoqi@1 | 1847 | void move_u32(Register rd, Register rs) { addu32(rd, rs, R0); } |
aoqi@1 | 1848 | #else |
aoqi@1 | 1849 | void move(Register rd, Register rs) { add(rd, rs, R0); } |
aoqi@1 | 1850 | #endif |
aoqi@1 | 1851 | void dmove(Register rd, Register rs) { dadd(rd, rs, R0); } |
aoqi@1 | 1852 | |
aoqi@1 | 1853 | #ifdef _LP64 |
aoqi@1 | 1854 | void shl(Register reg, int sa) { dsll(reg, reg, sa); } |
aoqi@1 | 1855 | void shr(Register reg, int sa) { dsrl(reg, reg, sa); } |
aoqi@1 | 1856 | void sar(Register reg, int sa) { dsra(reg, reg, sa); } |
aoqi@1 | 1857 | #else |
aoqi@1 | 1858 | void shl(Register reg, int sa) { sll(reg, reg, sa); } |
aoqi@1 | 1859 | void shr(Register reg, int sa) { srl(reg, reg, sa); } |
aoqi@1 | 1860 | void sar(Register reg, int sa) { sra(reg, reg, sa); } |
aoqi@1 | 1861 | #endif |
aoqi@1 | 1862 | |
aoqi@1 | 1863 | #ifndef PRODUCT |
aoqi@1 | 1864 | static void pd_print_patched_instruction(address branch) { |
aoqi@1 | 1865 | jint stub_inst = *(jint*) branch; |
aoqi@1 | 1866 | print_instruction(stub_inst); |
aoqi@1 | 1867 | ::tty->print("%s", " (unresolved)"); |
aoqi@1 | 1868 | |
aoqi@1 | 1869 | } |
aoqi@1 | 1870 | #endif |
aoqi@1 | 1871 | |
aoqi@1 | 1872 | // the follow two might use AT register, be sure you have no meanful data in AT before you call them |
aoqi@1 | 1873 | // by yjl 6/23/2005 |
aoqi@1 | 1874 | void increment(Register reg, int imm); |
aoqi@1 | 1875 | void decrement(Register reg, int imm); |
aoqi@1 | 1876 | |
aoqi@1 | 1877 | //FIXME |
aoqi@1 | 1878 | void empty_FPU_stack(){/*need implemented*/}; |
aoqi@1 | 1879 | |
aoqi@1 | 1880 | //we need 2 fun to save and resotre general register |
aoqi@1 | 1881 | void pushad(); |
aoqi@1 | 1882 | void popad(); |
aoqi@1 | 1883 | |
aoqi@1 | 1884 | // Test sub_klass against super_klass, with fast and slow paths. |
aoqi@1 | 1885 | |
aoqi@1 | 1886 | // The fast path produces a tri-state answer: yes / no / maybe-slow. |
aoqi@1 | 1887 | // One of the three labels can be NULL, meaning take the fall-through. |
aoqi@1 | 1888 | // If super_check_offset is -1, the value is loaded up from super_klass. |
aoqi@1 | 1889 | // No registers are killed, except temp_reg. |
aoqi@1 | 1890 | void check_klass_subtype_fast_path(Register sub_klass, |
aoqi@1 | 1891 | Register super_klass, |
aoqi@1 | 1892 | Register temp_reg, |
aoqi@1 | 1893 | Label* L_success, |
aoqi@1 | 1894 | Label* L_failure, |
aoqi@1 | 1895 | Label* L_slow_path, |
aoqi@1 | 1896 | RegisterOrConstant super_check_offset = RegisterOrConstant(-1)); |
aoqi@1 | 1897 | |
aoqi@1 | 1898 | // The rest of the type check; must be wired to a corresponding fast path. |
aoqi@1 | 1899 | // It does not repeat the fast path logic, so don't use it standalone. |
aoqi@1 | 1900 | // The temp_reg and temp2_reg can be noreg, if no temps are available. |
aoqi@1 | 1901 | // Updates the sub's secondary super cache as necessary. |
aoqi@1 | 1902 | // If set_cond_codes, condition codes will be Z on success, NZ on failure. |
aoqi@1 | 1903 | void check_klass_subtype_slow_path(Register sub_klass, |
aoqi@1 | 1904 | Register super_klass, |
aoqi@1 | 1905 | Register temp_reg, |
aoqi@1 | 1906 | Register temp2_reg, |
aoqi@1 | 1907 | Label* L_success, |
aoqi@1 | 1908 | Label* L_failure, |
aoqi@1 | 1909 | bool set_cond_codes = false); |
aoqi@1 | 1910 | |
aoqi@1 | 1911 | // Simplified, combined version, good for typical uses. |
aoqi@1 | 1912 | // Falls through on failure. |
aoqi@1 | 1913 | void check_klass_subtype(Register sub_klass, |
aoqi@1 | 1914 | Register super_klass, |
aoqi@1 | 1915 | Register temp_reg, |
aoqi@1 | 1916 | Label& L_success); |
aoqi@1 | 1917 | |
aoqi@1 | 1918 | // method handles (JSR 292) |
aoqi@1 | 1919 | Address argument_address(RegisterOrConstant arg_slot, int extra_slot_offset = 0); |
aoqi@1 | 1920 | |
aoqi@1 | 1921 | void get_vm_result (Register oop_result, Register thread); |
aoqi@1 | 1922 | void get_vm_result_2(Register metadata_result, Register thread); |
aoqi@1 | 1923 | #undef VIRTUAL |
aoqi@29 | 1924 | void atomic_inc32(address counter_addr, int inc, Register tmp_reg1, Register tmp_reg2); |
aoqi@1 | 1925 | |
aoqi@30 | 1926 | void fast_lock(Register obj, Register box, Register tmp, Register scr); |
aoqi@30 | 1927 | void fast_unlock(Register obj, Register box, Register tmp); |
aoqi@1 | 1928 | }; |
aoqi@1 | 1929 | |
aoqi@1 | 1930 | /** |
aoqi@1 | 1931 | * class SkipIfEqual: |
aoqi@1 | 1932 | * |
aoqi@1 | 1933 | * Instantiating this class will result in assembly code being output that will |
aoqi@1 | 1934 | * jump around any code emitted between the creation of the instance and it's |
aoqi@1 | 1935 | * automatic destruction at the end of a scope block, depending on the value of |
aoqi@1 | 1936 | * the flag passed to the constructor, which will be checked at run-time. |
aoqi@1 | 1937 | */ |
aoqi@1 | 1938 | class SkipIfEqual { |
aoqi@1 | 1939 | private: |
aoqi@1 | 1940 | MacroAssembler* _masm; |
aoqi@1 | 1941 | Label _label; |
aoqi@1 | 1942 | |
aoqi@1 | 1943 | public: |
aoqi@1 | 1944 | SkipIfEqual(MacroAssembler*, const bool* flag_addr, bool value); |
aoqi@1 | 1945 | ~SkipIfEqual(); |
aoqi@1 | 1946 | }; |
aoqi@1 | 1947 | |
aoqi@1 | 1948 | #ifdef ASSERT |
aoqi@1 | 1949 | inline bool AbstractAssembler::pd_check_instruction_mark() { return true; } |
aoqi@1 | 1950 | #endif |
aoqi@1 | 1951 | |
aoqi@1 | 1952 | #endif // CPU_MIPS_VM_ASSEMBLER_MIPS_HPP |