Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2006-2008 the V8 project authors. All rights reserved. | |
|
Søren Thygesen Gjesse
2010/01/19 22:59:12
Please use the copyright header from src/mips/asse
Alexandre
2010/01/22 23:08:42
Changed the copyright.
On 2010/01/19 22:59:12, Sør
| |
| 2 // Redistribution and use in source and binary forms, with or without | |
| 3 // modification, are permitted provided that the following conditions are | |
| 4 // met: | |
| 5 // | |
| 6 // * Redistributions of source code must retain the Ugreater copyright | |
| 7 // notice, this list of conditions and the following disclaimer. | |
| 8 // * Redistributions in binary form must reproduce the Ugreater | |
| 9 // copyright notice, this list of conditions and the following | |
| 10 // disclaimer in the documentation and/or other materials provided | |
| 11 // with the distribution. | |
| 12 // * Neither the name of Google Inc. nor the names of its | |
| 13 // contributors may be used to endorse or promote products derived | |
| 14 // from this software without specific prior written permission. | |
| 15 // | |
| 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
| 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
| 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
| 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
| 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
| 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
| 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
| 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| 27 | |
| 28 | |
| 29 #ifndef V8_MIPS_ASSEMBLER_MIPS_H_ | |
| 30 #define V8_MIPS_ASSEMBLER_MIPS_H_ | |
| 31 | |
| 32 #include <stdio.h> | |
| 33 #include "assembler.h" | |
| 34 #include "constants-mips.h" | |
| 35 | |
| 36 using namespace assembler::mips; | |
| 37 | |
| 38 namespace v8 { | |
| 39 namespace internal { | |
| 40 | |
| 41 // CPU Registers. | |
| 42 // | |
| 43 // 1) We would prefer to use an enum, but enum values are assignment- | |
| 44 // compatible with int, which has caused code-generation bugs. | |
| 45 // | |
| 46 // 2) We would prefer to use a class instead of a struct but we don't like | |
| 47 // the register initialization to depend on the particular initialization | |
| 48 // order (which appears to be different on OS X, Linux, and Windows for the | |
| 49 // installed versions of C++ we tried). Using a struct permits C-style | |
| 50 // "initialization". Also, the Register objects cannot be const as this | |
| 51 // forces initialization stubs in MSVC, making us dependent on initialization | |
| 52 // order. | |
| 53 // | |
| 54 // 3) By not using an enum, we are possibly preventing the compiler from | |
| 55 // doing certain constant folds, which may significantly reduce the | |
| 56 // code generated for some assembly instructions (because they boil down | |
| 57 // to a few constants). If this is a problem, we could change the code | |
| 58 // such that we use an enum in optimized mode, and the struct in debug | |
| 59 // mode. This way we get the compile-time error checking in debug mode | |
| 60 // and best performance in optimized code. | |
| 61 | |
| 62 | |
| 63 // ----------------------------------------------------------------------------- | |
| 64 // Implementation of Register and CRegister | |
| 65 | |
| 66 // Core register | |
| 67 struct Register { | |
| 68 bool is_valid() const { | |
| 69 return 0 <= code_ && code_ < 32; } | |
|
antonm
2010/01/21 13:10:45
nit: I think v8 style would be { ... } on one line
Alexandre
2010/01/22 23:08:42
Style issue fixed.
On 2010/01/21 13:10:45, antonm
| |
| 70 bool is(Register reg) const { return code_ == reg.code_; } | |
| 71 // The byte-register distinction of ai32 has dissapeared. | |
| 72 bool is_byte_register() const { return false; } | |
| 73 int code() const { | |
| 74 ASSERT(is_valid()); | |
| 75 return code_; | |
| 76 } | |
| 77 int bit() const { | |
| 78 ASSERT(is_valid()); | |
| 79 return 1 << code_; | |
| 80 } | |
| 81 | |
| 82 // (unfortunately we can't make this private in a struct) | |
| 83 int code_; | |
| 84 }; | |
| 85 | |
| 86 extern const Register no_reg; | |
| 87 | |
| 88 extern const Register zero_reg; | |
| 89 extern const Register at; | |
| 90 extern const Register v0; | |
| 91 extern const Register v1; | |
| 92 extern const Register a0; | |
| 93 extern const Register a1; | |
| 94 extern const Register a2; | |
| 95 extern const Register a3; | |
| 96 extern const Register t0; | |
| 97 extern const Register t1; | |
| 98 extern const Register t2; | |
| 99 extern const Register t3; | |
| 100 extern const Register t4; | |
| 101 extern const Register t5; | |
| 102 extern const Register t6; | |
| 103 extern const Register t7; | |
| 104 extern const Register s0; | |
| 105 extern const Register s1; | |
| 106 extern const Register s2; | |
| 107 extern const Register s3; | |
| 108 extern const Register s4; | |
| 109 extern const Register s5; | |
| 110 extern const Register s6; | |
| 111 extern const Register s7; | |
| 112 extern const Register t8; | |
| 113 extern const Register t9; | |
| 114 extern const Register k0; | |
| 115 extern const Register k1; | |
| 116 extern const Register gp; | |
| 117 extern const Register sp; | |
| 118 extern const Register s8_fp; | |
| 119 extern const Register ra; | |
| 120 | |
| 121 int ToNumber(Register reg); | |
| 122 | |
| 123 Register ToRegister(int num); | |
| 124 | |
| 125 // Coprocessor register | |
| 126 struct CRegister { | |
| 127 bool is_valid() const { return 0 <= code_ && code_ < 32 ; } | |
| 128 bool is(CRegister creg) const { return code_ == creg.code_; } | |
| 129 int code() const { | |
| 130 ASSERT(is_valid()); | |
| 131 return code_; | |
| 132 } | |
| 133 int bit() const { | |
| 134 ASSERT(is_valid()); | |
| 135 return 1 << code_; | |
| 136 } | |
| 137 | |
| 138 // (unfortunately we can't make this private in a struct) | |
| 139 int code_; | |
| 140 }; | |
| 141 | |
| 142 extern const CRegister no_creg; | |
| 143 | |
| 144 extern const CRegister f0; | |
| 145 extern const CRegister f1; | |
| 146 extern const CRegister f2; | |
| 147 extern const CRegister f3; | |
| 148 extern const CRegister f4; | |
| 149 extern const CRegister f5; | |
| 150 extern const CRegister f6; | |
| 151 extern const CRegister f7; | |
| 152 extern const CRegister f8; | |
| 153 extern const CRegister f9; | |
| 154 extern const CRegister f10; | |
| 155 extern const CRegister f11; | |
| 156 extern const CRegister f12; // arg | |
| 157 extern const CRegister f13; | |
| 158 extern const CRegister f14; // arg | |
| 159 extern const CRegister f15; | |
| 160 extern const CRegister f16; | |
| 161 extern const CRegister f17; | |
| 162 extern const CRegister f18; | |
| 163 extern const CRegister f19; | |
| 164 extern const CRegister f20; | |
| 165 extern const CRegister f21; | |
| 166 extern const CRegister f22; | |
| 167 extern const CRegister f23; | |
| 168 extern const CRegister f24; | |
| 169 extern const CRegister f25; | |
| 170 extern const CRegister f26; | |
| 171 extern const CRegister f27; | |
| 172 extern const CRegister f28; | |
| 173 extern const CRegister f29; | |
| 174 extern const CRegister f30; | |
| 175 extern const CRegister f31; | |
| 176 | |
| 177 | |
| 178 // Returns the equivalent of !cc. | |
| 179 // Negation of the default no_condition (-1) results in a non-default | |
| 180 // no_condition value (-2). As long as tests for no_condition check | |
| 181 // for condition < 0, this will work as expected. | |
| 182 inline Condition NegateCondition(Condition cc); | |
| 183 | |
| 184 inline Condition ReverseCondition(Condition cc) { | |
| 185 switch (cc) { | |
| 186 case Uless: | |
| 187 return Ugreater; | |
| 188 case Ugreater: | |
| 189 return Uless; | |
| 190 case Ugreater_equal: | |
| 191 return Uless_equal; | |
| 192 case Uless_equal: | |
| 193 return Ugreater_equal; | |
| 194 case less: | |
| 195 return greater; | |
| 196 case greater: | |
| 197 return less; | |
| 198 case greater_equal: | |
| 199 return less_equal; | |
| 200 case less_equal: | |
| 201 return greater_equal; | |
| 202 default: | |
| 203 return cc; | |
| 204 }; | |
| 205 } | |
| 206 | |
| 207 | |
| 208 // TODO: Implement Hints or not ? Not used for arms. | |
| 209 // Some kind of hints seem to exist on MIPS. See SMRL 8.5.8 (cf also p234 bot) | |
| 210 enum Hint{ | |
| 211 no_hint = 0 | |
| 212 }; | |
| 213 inline Hint NegateHint(Hint hint) { | |
| 214 return no_hint; | |
| 215 } | |
| 216 | |
| 217 | |
| 218 // ----------------------------------------------------------------------------- | |
| 219 // Machine instruction Operands | |
| 220 | |
| 221 // Class Operand represents a shifter operand in data processing instructions | |
| 222 class Operand BASE_EMBEDDED { | |
| 223 public: | |
| 224 // immediate | |
| 225 INLINE(explicit Operand(int32_t immediate, | |
| 226 RelocInfo::Mode rmode = RelocInfo::NONE)); | |
| 227 INLINE(explicit Operand(const ExternalReference& f)); | |
| 228 INLINE(explicit Operand(const char* s)); | |
| 229 INLINE(explicit Operand(Object** opp)); | |
| 230 INLINE(explicit Operand(Context** cpp)); | |
| 231 explicit Operand(Handle<Object> handle); | |
| 232 INLINE(explicit Operand(Smi* value)); | |
| 233 | |
| 234 // reg | |
| 235 INLINE(explicit Operand(Register rm)); | |
| 236 | |
| 237 // Return true if this is a register operand. | |
| 238 INLINE(bool is_reg() const); | |
| 239 | |
| 240 Register rm() const { return rm_; } | |
| 241 | |
| 242 private: | |
| 243 Register rm_; | |
| 244 int32_t imm32_; // valid if rm_ == no_reg | |
| 245 RelocInfo::Mode rmode_; | |
| 246 | |
| 247 friend class Assembler; | |
| 248 }; | |
| 249 | |
| 250 | |
| 251 // On MIPS we have only one adressing mode with base_reg + offset for every kind | |
| 252 // Class MemOperand represents a memory operand in load and store instructions | |
|
antonm
2010/01/21 13:10:45
Usually all comments are terminated with a dot (he
Alexandre
2010/01/22 23:08:42
Style issue fixed.
On 2010/01/21 13:10:45, antonm
| |
| 253 class MemOperand : public Operand { | |
| 254 | |
| 255 public: | |
| 256 | |
| 257 explicit MemOperand(Register rn, int16_t offset = 0); | |
| 258 | |
| 259 private: | |
| 260 int16_t offset_; | |
| 261 | |
| 262 friend class Assembler; | |
| 263 }; | |
| 264 | |
| 265 | |
| 266 class Assembler : public Malloced { | |
| 267 public: | |
| 268 // Create an assembler. Instructions and relocation information are emitted | |
| 269 // into a buffer, with the instructions starting from the beginning and the | |
| 270 // relocation information starting from the end of the buffer. See CodeDesc | |
| 271 // for a detailed comment on the layout (globals.h). | |
| 272 // | |
| 273 // If the provided buffer is NULL, the assembler allocates and grows its own | |
| 274 // buffer, and buffer_size determines the initial buffer size. The buffer is | |
| 275 // owned by the assembler and deallocated upon destruction of the assembler. | |
| 276 // | |
| 277 // If the provided buffer is not NULL, the assembler uses the provided buffer | |
| 278 // for code generation and assumes its size to be buffer_size. If the buffer | |
| 279 // is too small, a fatal error occurs. No deallocation of the buffer is done | |
| 280 // upon destruction of the assembler. | |
| 281 Assembler(void* buffer, int buffer_size); | |
| 282 ~Assembler(); | |
| 283 | |
| 284 // GetCode emits any pending (non-emitted) code and fills the descriptor | |
| 285 // desc. GetCode() is idempotent; it returns the same result if no other | |
| 286 // Assembler functions are invoked in between GetCode() calls. | |
| 287 void GetCode(CodeDesc* desc); | |
| 288 | |
| 289 // Label operations & relative jumps (PPUM Appendix D) | |
| 290 // | |
| 291 // Takes a branch opcode (cc) and a label (L) and generates | |
| 292 // either a backward branch or a forward branch and links it | |
| 293 // to the label fixup chain. Usage: | |
| 294 // | |
| 295 // Label L; // unbound label | |
| 296 // j(cc, &L); // forward branch to unbound label | |
| 297 // bind(&L); // bind label to the current pc | |
| 298 // j(cc, &L); // backward branch to bound label | |
| 299 // bind(&L); // illegal: a label may be bound only once | |
| 300 // | |
| 301 // Note: The same Label can be used for forward and backward branches | |
| 302 // but it may be bound only once. | |
| 303 void bind(Label* L); // binds an unbound label L to the current code position | |
| 304 | |
| 305 // Returns the branch offset to the given label from the current code position | |
| 306 // Links the label to the current position if it is still unbound | |
| 307 // Manages the jump elimination optimization if the second parameter is true. | |
| 308 int32_t branch_offset(Label* L, bool jump_elimination_allowed); | |
| 309 | |
| 310 // Puts a labels target address at the given position. | |
| 311 // The high 8 bits are set to zero. | |
| 312 void label_at_put(Label* L, int at_offset); | |
| 313 | |
| 314 // Size of an instruction. | |
| 315 static const int kInstrSize = sizeof(Instr); | |
| 316 | |
| 317 // Difference between address of current opcode and target address offset. | |
| 318 static const int kBranchPCOffset = 4; | |
| 319 | |
| 320 // Read/Modify the code target address in the branch/call instruction at pc. | |
| 321 static Address target_address_at(Address pc); | |
| 322 static void set_target_address_at(Address pc, Address target); | |
| 323 | |
| 324 // This sets the branch destination (which gets loaded at the call address). | |
| 325 // This is for calls and branches within generated code. | |
| 326 inline static void set_target_at(Address instruction_payload, | |
| 327 Address target) { | |
| 328 set_target_address_at(instruction_payload, target); | |
| 329 } | |
| 330 | |
| 331 // This sets the branch destination (which is in the instruction on x86). | |
|
antonm
2010/01/21 13:10:45
x86?
Alexandre
2010/01/22 23:08:42
Fixed.
On 2010/01/21 13:10:45, antonm wrote:
| |
| 332 // This is for calls and branches to runtime code. | |
| 333 inline static void set_external_target_at(Address instruction_payload, | |
| 334 Address target) { | |
| 335 set_target_address_at(instruction_payload, target); | |
| 336 } | |
| 337 | |
| 338 static const int kCallTargetSize = 3 * kPointerSize; | |
| 339 static const int kExternalTargetSize = 3 * kPointerSize; | |
| 340 | |
| 341 // Distance between the instruction referring to the address of the call | |
| 342 // target and the return address | |
| 343 static const int kCallTargetAddressOffset = 4 * kInstrSize; | |
| 344 | |
| 345 // Distance between start of patched return sequence and the emitted address | |
| 346 // to jump to. | |
| 347 static const int kPatchReturnSequenceAddressOffset = kInstrSize; | |
| 348 | |
| 349 | |
| 350 // --------------------------------------------------------------------------- | |
| 351 // Code generation | |
| 352 | |
| 353 | |
| 354 // Insert the smallest number of nop instructions | |
| 355 // possible to align the pc offset to a multiple | |
| 356 // of m. m must be a power of 2 (>= 4). | |
| 357 void Align(int m); | |
| 358 | |
| 359 //------- Branch and jump instructions -------- | |
| 360 // We don't use likely variant of instructions | |
| 361 void b (int16_t offset); | |
| 362 void b (Label* L) { b(branch_offset(L, false)>>2); } | |
| 363 void bal (int16_t offset); | |
| 364 void bal (Label* L) { bal(branch_offset(L, false)>>2); } | |
| 365 | |
| 366 void beq (Register rs, Register rt, int16_t offset); | |
| 367 void beq (Register rs, Register rt, Label* L) {beq(rs,rt,branch_offset(L, fal se)>>2);} | |
| 368 // void beql (Register rs, Register rt, int16_t offset); | |
|
antonm
2010/01/21 13:10:45
maybe those commented out lines should be just rem
Alexandre
2010/01/22 23:08:42
I removed them. These likely variants of instructi
| |
| 369 void bgez (Register rs, int16_t offset); | |
| 370 void bgezal (Register rs, int16_t offset); | |
| 371 // void bgezall (Register rs, int16_t offset); | |
| 372 // void bgezl (Register rs, int16_t offset); | |
| 373 void bgtz (Register rs, int16_t offset); | |
| 374 // void bgtzl (Register rs, int16_t offset); | |
| 375 void blez (Register rs, int16_t offset); | |
| 376 // void blezl (Register rs, int16_t offset); | |
| 377 void bltz (Register rs, int16_t offset); | |
| 378 void bltzal (Register rs, int16_t offset); | |
| 379 // void bltzall (Register rs, int16_t offset); | |
| 380 void bne (Register rs, Register rt, int16_t offset); | |
| 381 void bne (Register rs, Register rt, Label* L) {bne(rs,rt,branch_offset(L, fal se)>>2);} | |
| 382 // void bnel (Register rs, Register rt, int16_t offset); | |
| 383 | |
| 384 // IMPORTANT NOTE: Never use the int16_t b(l)cond version with a branch offset | |
| 385 // IMPORTANT NOTE: instead of using the Label* version. See Twiki for infos. | |
| 386 // Emulated conditionnal branch instructions calling the right branch instruct ion | |
| 387 void bcond(Condition cond, int16_t offset, Register rs = zero_reg, | |
| 388 const Operand& rt = Operand(zero_reg), Register scratch = at); | |
| 389 void bcond(Condition cond, Label* L, Register rs = zero_reg, | |
| 390 const Operand& rt = Operand(zero_reg), Register scratch = at); | |
| 391 // conditionnal branch and link | |
| 392 void blcond(Condition cond, int16_t offset, Register rs = zero_reg, | |
| 393 const Operand& rt = Operand(zero_reg), Register scratch = at); | |
| 394 void blcond(Condition cond, Label* L, Register rs = zero_reg, | |
| 395 const Operand& rt = Operand(zero_reg), Register scratch = at); | |
| 396 | |
| 397 // Jump targets must be in the current 256 MB-aligned region. ie 28 bits. | |
| 398 void j (const Operand& target); | |
| 399 void jal (const Operand& target); | |
| 400 void jalr (Register rs, Register rd = ra); | |
| 401 void jalr (const Operand& rs, Register rd = ra); | |
| 402 void jalr_hb (const Operand& rs, Register rd = ra); | |
| 403 void jr (Register target); | |
| 404 void jr (const Operand& target); | |
| 405 void jr_hb(const Operand& target); | |
| 406 | |
| 407 // INLINE(void jalr (Register rs);) | |
| 408 // INLINE(void jalr_hb (Register rs);) | |
| 409 // INLINE(void jalr (Register rs) { jalr(ra, rs); }) | |
| 410 // INLINE(void jalr_hb (Register rs) { jalr_hb(ra, rs); }) | |
| 411 | |
| 412 // Automatically calls immediate or register j/jl versions. | |
| 413 void jcond(const Operand& target, Condition cond, Register rs, const Operand& rt); | |
| 414 void jalcond(const Operand& target, Condition cond, Register rs, const Operand & rt); | |
| 415 | |
| 416 | |
| 417 //-------Data-processing-instructions--------- | |
| 418 | |
| 419 // Arithmetic | |
| 420 void add(Register rd, Register rs, const Operand& rt); | |
| 421 void add(Register rd, Register rs, Register rt) {add(rd, rs, Operand(rt));} | |
| 422 void add(Register rd, const Operand& rt) { add(rd, rd, rt); } | |
| 423 void addi(Register rd, Register rs, const Operand& rt); | |
| 424 void addi(Register rd, Register rs, int32_t rt) {addi(rd, rs, Operand(rt));} | |
| 425 void addi(Register rd, const Operand& rt) { addi(rd, rd, rt); } | |
| 426 void addu(Register rd, Register rs, const Operand& rt); | |
| 427 void addu(Register rd, Register rs, Register rt) {addu(rd, rs, Operand(rt));} | |
| 428 void addu(Register rd, const Operand& rt) { addu(rd, rd, rt); } | |
| 429 void addiu(Register rd, Register rs, const Operand& rt); | |
| 430 void addiu(Register rd, Register rs, int32_t rt) {addiu(rd, rs, Operand(rt));} | |
| 431 void addiu(Register rd, const Operand& rt) { addiu(rd, rd, rt); } | |
| 432 | |
| 433 void sub(Register rd, Register rs, const Operand& rt); | |
| 434 void subu(Register rd, Register rs, const Operand& rt); | |
| 435 | |
| 436 void mult(Register rs, const Operand& rt); | |
| 437 void multu(Register rs, const Operand& rt); | |
| 438 void div(Register rs, const Operand& rt); | |
| 439 void divu(Register rs, const Operand& rt); | |
| 440 | |
| 441 void mul(Register rd, Register rs, const Operand& rt); | |
| 442 | |
| 443 // Logical | |
| 444 void and_(Register rd, Register rs, const Operand& rt); | |
| 445 void and_(Register rd, const Operand& rt) { and_(rd, rd, rt); } | |
| 446 void andi(Register rd, Register rs, const Operand& rt); | |
| 447 void andi(Register rd, const Operand& rt) { andi(rd, rd, rt); } | |
| 448 void or_(Register rd, Register rs, const Operand& rt); | |
| 449 void or_(Register rd, const Operand& rt) { or_(rd, rd, rt); } | |
| 450 void ori(Register rd, Register rs, const Operand& rt); | |
| 451 void ori(Register rd, Register rs, uint32_t rt) { ori(rd, rs, Operand(rt)); } | |
| 452 void ori(Register rd, const Operand& rt) { ori(rd, rd, rt); } | |
| 453 void xor_(Register rd, Register rs, const Operand& rt); | |
| 454 void xor_(Register rd, const Operand& rt) { xor_(rd, rd, rt); } | |
| 455 void xori(Register rd, Register rs, const Operand& rt); | |
| 456 void xori(Register rd, const Operand& rt) { xori(rd, rd, rt); } | |
| 457 void nor(Register rd, Register rs, const Operand& rt); | |
| 458 void nor(Register rd, const Operand& rt) { nor(rd, rd, rt); } | |
| 459 | |
| 460 // Shifts | |
| 461 void sll(Register rd, Register rt, uint16_t sa); | |
| 462 void sllv(Register rd, Register rt, Register rs); | |
| 463 void srl(Register rd, Register rt, uint16_t sa); | |
| 464 void srlv(Register rd, Register rt, Register rs); | |
| 465 void sra(Register rt, Register rd, uint16_t sa); | |
| 466 void srav(Register rt, Register rd, Register rs); | |
| 467 | |
| 468 | |
| 469 //------------Memory-instructions------------- | |
| 470 | |
| 471 void lb(Register rd, const MemOperand& rs); | |
| 472 void lbu(Register rd, const MemOperand& rs); | |
| 473 void lw(Register rd, const MemOperand& rs); | |
| 474 void sb(Register rd, const MemOperand& rs); | |
| 475 void sw(Register rd, const MemOperand& rs); | |
| 476 void lui(Register rd, uint16_t j); | |
| 477 | |
| 478 | |
| 479 //-------------Misc-instructions-------------- | |
| 480 | |
| 481 // Break / Trap instructions | |
| 482 void break_(uint32_t code); | |
| 483 void tge (Register rs, Register rt, uint16_t code); | |
| 484 void tgeu (Register rs, Register rt, uint16_t code); | |
| 485 void tlt (Register rs, Register rt, uint16_t code); | |
| 486 void tltu (Register rs, Register rt, uint16_t code); | |
| 487 void teq (Register rs, Register rt, uint16_t code); | |
| 488 void tne (Register rs, Register rt, uint16_t code); | |
| 489 | |
| 490 // Move from HI/LO register | |
| 491 void mfhi(Register rd); | |
| 492 void mflo(Register rd); | |
| 493 | |
| 494 // Set on less than | |
| 495 void slt (Register rd, Register rs, const Operand& rt); | |
| 496 void slt (Register rd, Register rs, Register rt) {slt(rd, rs, Operand(rt)); } | |
| 497 void sltu (Register rd, Register rs, const Operand& rt); | |
| 498 void sltu (Register rd, Register rs, Register rt) {sltu(rd, rs, Operand(rt));} | |
| 499 void slti (Register rd, Register rs, const Operand& rt); | |
| 500 void sltiu(Register rd, Register rs, const Operand& rt); | |
| 501 | |
| 502 | |
| 503 //--------Coprocessor-instructions---------------- | |
| 504 | |
| 505 // Load, store, and move | |
| 506 void lwc1(CRegister fd, const MemOperand& src); | |
| 507 void ldc1(CRegister fd, const MemOperand& src); | |
| 508 | |
| 509 void swc1(CRegister fs, const MemOperand& dst); | |
| 510 void sdc1(CRegister fs, const MemOperand& dst); | |
| 511 | |
| 512 void mtc1 (CRegister fs, Register rt); | |
| 513 void mthc1(CRegister fs, Register rt); | |
| 514 void mfc1 (CRegister fs, Register rt); | |
| 515 void mfhc1(CRegister fs, Register rt); | |
| 516 | |
| 517 // Conversion | |
| 518 void cvt_w_s(CRegister fd, CRegister fs); | |
| 519 void cvt_w_d(CRegister fd, CRegister fs); | |
| 520 | |
| 521 void cvt_l_s(CRegister fd, CRegister fs); | |
| 522 void cvt_l_d(CRegister fd, CRegister fs); | |
| 523 | |
| 524 void cvt_s_w(CRegister fd, CRegister fs); | |
| 525 void cvt_s_l(CRegister fd, CRegister fs); | |
| 526 void cvt_s_d(CRegister fd, CRegister fs); | |
| 527 | |
| 528 void cvt_d_w(CRegister fd, CRegister fs); | |
| 529 void cvt_d_l(CRegister fd, CRegister fs); | |
| 530 void cvt_d_s(CRegister fd, CRegister fs); | |
| 531 | |
| 532 // Conditions and branches | |
| 533 void c(C_Condition cond, SecondaryField fmt, | |
| 534 CRegister ft, CRegister fs, uint16_t cc = 0); | |
| 535 | |
| 536 void bc1f(int16_t offset, uint16_t cc = 0); | |
| 537 void bc1f(Label* L, uint16_t cc = 0) { bc1f(branch_offset(L, false)>>2, cc); } | |
| 538 void bc1t(int16_t offset, uint16_t cc = 0); | |
| 539 void bc1t(Label* L, uint16_t cc = 0) { bc1t(branch_offset(L, false)>>2, cc); } | |
| 540 | |
| 541 //------------Pseudo-instructions------------- | |
| 542 | |
| 543 void nop() { sll(zero_reg, zero_reg, 0); } | |
| 544 void mov(Register rd, Register rt) { or_(rd, rt, Operand(zero_reg)); } | |
| 545 // Move the logical ones complement of source to dest. | |
| 546 void movn(Register rd, Register rt); | |
| 547 | |
| 548 | |
| 549 // Push multiple registers on the stack. | |
| 550 // With multi_push, lower registers are pushed first on the stack. | |
| 551 // For example if you push t0, t1, s0, and ra you get: | |
| 552 // | | | |
| 553 // |-----------------------| | |
| 554 // | t0 | + | |
| 555 // |-----------------------| | | |
| 556 // | t1 | | | |
| 557 // |-----------------------| | | |
| 558 // | s0 | v | |
| 559 // |-----------------------| - | |
| 560 // | ra | | |
| 561 // |-----------------------| | |
| 562 // | | | |
| 563 void multi_push(RegList regs); | |
| 564 void multi_push_reversed(RegList regs); | |
| 565 void push(Register src) { | |
| 566 addiu(sp, Operand(-kPointerSize)); | |
| 567 sw(src, MemOperand(sp, 0)); | |
| 568 } | |
| 569 | |
| 570 void push(Register src, Condition cond, Register tst1, Register tst2) { | |
| 571 // Since we don't have conditionnal execution we use a branch. | |
| 572 bcond(cond, 3, tst1, Operand(tst2)); | |
| 573 nop(); | |
| 574 addiu(sp, sp, Operand(-kPointerSize)); | |
| 575 sw(src, MemOperand(sp, 0)); | |
| 576 } | |
| 577 | |
| 578 // Pops multiple values from the stack and load them in the | |
| 579 // registers specified in regs. Pop order is the opposite as in multi_push. | |
| 580 void multi_pop(RegList regs); | |
| 581 void multi_pop_reversed(RegList regs); | |
| 582 void pop(Register dst) { | |
| 583 lw(dst, MemOperand(sp, 0)); | |
| 584 addiu(sp, Operand(kPointerSize)); | |
| 585 } | |
| 586 void pop() { | |
| 587 add(sp, sp, Operand(kPointerSize)); | |
| 588 } | |
| 589 | |
| 590 // load uint32 in the rd register | |
| 591 void li(Register rd, Operand j, bool gen2instr = false); | |
| 592 void lrdi32(Register rd, Operand j) { li(rd, j); } | |
| 593 | |
| 594 // Exception-generating instructions and debugging support | |
| 595 void stop(const char* msg); | |
| 596 | |
| 597 // Jump unconditionally to given label. | |
| 598 // We NEED a nop in the branch delay slot, as it used by v8, for example in | |
| 599 // CodeGenerator::ProcessDeferred(). | |
| 600 // Use rather b(Label) for code generation. | |
| 601 void jmp(Label* L) { | |
| 602 bcond(cc_always, L); | |
| 603 nop(); | |
| 604 } | |
| 605 | |
| 606 | |
| 607 // Check the code size generated from label to here. | |
| 608 int InstructionsGeneratedSince(Label* l) { | |
| 609 return (pc_offset() - l->pos()) / kInstrSize; | |
| 610 } | |
| 611 | |
| 612 // Debugging | |
| 613 | |
| 614 // Mark address of the ExitJSFrame code. | |
| 615 void RecordJSReturn(); | |
| 616 | |
| 617 // Record a comment relocation entry that can be used by a disassembler. | |
| 618 // Use --debug_code to enable. | |
| 619 void RecordComment(const char* msg); | |
| 620 | |
| 621 void RecordPosition(int pos); | |
| 622 void RecordStatementPosition(int pos); | |
| 623 void WriteRecordedPositions(); | |
| 624 | |
| 625 int32_t pc_offset() const { return pc_ - buffer_; } | |
| 626 int32_t current_position() const { return current_position_; } | |
| 627 int32_t current_statement_position() const { return current_position_; } | |
| 628 | |
| 629 // Check if there is less than kGap bytes available in the buffer. | |
| 630 // If this is the case, we need to grow the buffer before emitting | |
| 631 // an instruction or relocation information. | |
| 632 inline bool overflow() const { return pc_ >= reloc_info_writer.pos() - kGap; } | |
| 633 | |
| 634 // Get the number of bytes available in the buffer. | |
| 635 inline int available_space() const { return reloc_info_writer.pos() - pc_; } | |
| 636 | |
| 637 protected: | |
| 638 int32_t buffer_space() const { return reloc_info_writer.pos() - pc_; } | |
| 639 | |
| 640 // Read/patch instructions | |
| 641 static Instr instr_at(byte* pc) { return *reinterpret_cast<Instr*>(pc); } | |
| 642 void instr_at_put(byte* pc, Instr instr) { | |
| 643 *reinterpret_cast<Instr*>(pc) = instr; | |
| 644 } | |
| 645 Instr instr_at(int pos) { return *reinterpret_cast<Instr*>(buffer_ + pos); } | |
| 646 void instr_at_put(int pos, Instr instr) { | |
| 647 *reinterpret_cast<Instr*>(buffer_ + pos) = instr; | |
| 648 } | |
| 649 | |
| 650 // Check if an instruction is a branch of some kind. | |
| 651 bool is_branch(Instr instr); | |
| 652 | |
| 653 // Decode branch instruction at pos and return branch target pos | |
| 654 int target_at(int32_t pos); | |
| 655 | |
| 656 // Patch branch instruction at pos to branch to given branch target pos | |
| 657 void target_at_put(int32_t pos, int32_t target_pos); | |
| 658 | |
| 659 private: | |
| 660 // Code buffer: | |
| 661 // The buffer into which code and relocation info are generated. | |
| 662 byte* buffer_; | |
| 663 int buffer_size_; | |
| 664 // True if the assembler owns the buffer, false if buffer is external. | |
| 665 bool own_buffer_; | |
| 666 | |
| 667 // Buffer size and constant pool distance are checked together at regular | |
| 668 // intervals of kBufferCheckInterval emitted bytes | |
| 669 static const int kBufferCheckInterval = 1*KB/2; | |
| 670 | |
| 671 // Code generation | |
| 672 // The relocation writer's position is at least kGap bytes Uless the end of | |
| 673 // the generated instructions. This is so that multi-instruction sequences do | |
| 674 // not have to check for overflow. The same is true for writes of large | |
| 675 // relocation info entries. | |
| 676 static const int kGap = 32; | |
| 677 byte* pc_; // the program counter; moves forward | |
| 678 | |
| 679 // Relocation information generation | |
| 680 // Each relocation is encoded as a variable size value | |
| 681 static const int kMaxRelocSize = RelocInfoWriter::kMaxSize; | |
| 682 RelocInfoWriter reloc_info_writer; | |
| 683 | |
| 684 // The bound position, before this we cannot do instruction elimination. | |
| 685 int last_bound_pos_; | |
| 686 | |
| 687 // source position information | |
| 688 int current_position_; | |
| 689 int current_statement_position_; | |
| 690 int written_position_; | |
| 691 int written_statement_position_; | |
| 692 | |
| 693 // Code emission | |
| 694 inline void CheckBuffer(); | |
| 695 void GrowBuffer(); | |
| 696 inline void emit(Instr x); | |
| 697 | |
| 698 // Instruction generation | |
| 699 // We have 3 different kind of encoding layout on MIPS. | |
| 700 // However due to many different types of objects encoded in the same fields | |
| 701 // we have quite a few aliases for each mode. | |
| 702 // Using the same structure to refer to Register and CRegister would spare a | |
| 703 // few aliases, but mixing both does not look clean to me. | |
| 704 // Anyway we could surely implement this differently. | |
| 705 | |
| 706 void instrmod1(Opcode opcode, | |
| 707 Register r1, | |
| 708 Register r2, | |
| 709 Register r3, | |
| 710 uint16_t sa = 0, | |
| 711 SecondaryField func = NULLSF); | |
| 712 | |
| 713 void instrmod1(Opcode opcode, | |
| 714 SecondaryField fmt, | |
| 715 CRegister ft, | |
| 716 CRegister fs, | |
| 717 CRegister fd, | |
| 718 SecondaryField func = NULLSF); | |
| 719 | |
| 720 void instrmod1(Opcode opcode, | |
| 721 SecondaryField fmt, | |
| 722 Register rt, | |
| 723 CRegister fs, | |
| 724 CRegister fd, | |
| 725 SecondaryField func = NULLSF); | |
| 726 | |
| 727 | |
| 728 void instrmod2(Opcode opcode, | |
| 729 Register r1, | |
| 730 Register r2, | |
| 731 int16_t j); | |
| 732 void instrmod2(Opcode opcode, | |
| 733 Register r1, | |
| 734 Register r2, | |
| 735 uint16_t j); | |
| 736 void instrmod2(Opcode opcode, | |
| 737 Register r1, | |
| 738 SecondaryField SF, | |
| 739 int16_t j); | |
| 740 void instrmod2(Opcode opcode, | |
| 741 Register r1, | |
| 742 SecondaryField SF, | |
| 743 uint16_t j); | |
| 744 | |
| 745 void instrmod2(Opcode opcode, | |
| 746 Register r1, | |
| 747 CRegister r2, | |
| 748 int16_t j); | |
| 749 | |
| 750 | |
| 751 void instrmod3(Opcode opcode, | |
| 752 Register r1, | |
| 753 uint32_t address); | |
| 754 | |
| 755 | |
| 756 // Labels | |
| 757 void print(Label* L); | |
| 758 void bind_to(Label* L, int pos); | |
| 759 void link_to(Label* L, Label* appendix); | |
| 760 void next(Label* L); | |
| 761 | |
| 762 // Record reloc info for current pc_ | |
| 763 void RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data = 0); | |
| 764 | |
| 765 friend class RegExpMacroAssemblerARM; | |
| 766 friend class RelocInfo; | |
| 767 friend class CodePatcher; | |
| 768 }; | |
| 769 | |
| 770 } } // namespace v8::internal | |
| 771 | |
| 772 #endif // V8_ARM_ASSEMBLER_ARM_H_ | |
| OLD | NEW |