| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 1994-2006 Sun Microsystems Inc. | |
| 2 // All Rights Reserved. | |
| 3 // | |
| 4 // Redistribution and use in source and binary forms, with or without | |
| 5 // modification, are permitted provided that the following conditions | |
| 6 // are met: | |
| 7 // | |
| 8 // - Redistributions of source code must retain the above copyright notice, | |
| 9 // this list of conditions and the following disclaimer. | |
| 10 // | |
| 11 // - Redistribution in binary form must reproduce the above copyright | |
| 12 // notice, this list of conditions and the following disclaimer in the | |
| 13 // documentation and/or other materials provided with the | |
| 14 // distribution. | |
| 15 // | |
| 16 // - Neither the name of Sun Microsystems or the names of contributors may | |
| 17 // be used to endorse or promote products derived from this software without | |
| 18 // specific prior written permission. | |
| 19 // | |
| 20 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| 21 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| 22 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
| 23 // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
| 24 // COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
| 25 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
| 26 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | |
| 27 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
| 28 // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | |
| 29 // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
| 30 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | |
| 31 // OF THE POSSIBILITY OF SUCH DAMAGE. | |
| 32 | |
| 33 // The original source code covered by the above license above has been | |
| 34 // modified significantly by Google Inc. | |
| 35 // Copyright 2010 the V8 project authors. All rights reserved. | |
| 36 | |
| 37 // A light-weight ARM Assembler | |
| 38 // Generates user mode instructions for the ARM architecture up to version 5 | |
| 39 | |
| 40 #ifndef V8_ARM_ASSEMBLER_THUMB2_H_ | |
| 41 #define V8_ARM_ASSEMBLER_THUMB2_H_ | |
| 42 #include <stdio.h> | |
| 43 #include "assembler.h" | |
| 44 #include "serialize.h" | |
| 45 | |
| 46 namespace v8 { | |
| 47 namespace internal { | |
| 48 | |
| 49 // CPU Registers. | |
| 50 // | |
| 51 // 1) We would prefer to use an enum, but enum values are assignment- | |
| 52 // compatible with int, which has caused code-generation bugs. | |
| 53 // | |
| 54 // 2) We would prefer to use a class instead of a struct but we don't like | |
| 55 // the register initialization to depend on the particular initialization | |
| 56 // order (which appears to be different on OS X, Linux, and Windows for the | |
| 57 // installed versions of C++ we tried). Using a struct permits C-style | |
| 58 // "initialization". Also, the Register objects cannot be const as this | |
| 59 // forces initialization stubs in MSVC, making us dependent on initialization | |
| 60 // order. | |
| 61 // | |
| 62 // 3) By not using an enum, we are possibly preventing the compiler from | |
| 63 // doing certain constant folds, which may significantly reduce the | |
| 64 // code generated for some assembly instructions (because they boil down | |
| 65 // to a few constants). If this is a problem, we could change the code | |
| 66 // such that we use an enum in optimized mode, and the struct in debug | |
| 67 // mode. This way we get the compile-time error checking in debug mode | |
| 68 // and best performance in optimized code. | |
| 69 // | |
| 70 // Core register | |
| 71 struct Register { | |
| 72 bool is_valid() const { return 0 <= code_ && code_ < 16; } | |
| 73 bool is(Register reg) const { return code_ == reg.code_; } | |
| 74 int code() const { | |
| 75 ASSERT(is_valid()); | |
| 76 return code_; | |
| 77 } | |
| 78 int bit() const { | |
| 79 ASSERT(is_valid()); | |
| 80 return 1 << code_; | |
| 81 } | |
| 82 | |
| 83 // Unfortunately we can't make this private in a struct. | |
| 84 int code_; | |
| 85 }; | |
| 86 | |
| 87 | |
| 88 extern Register no_reg; | |
| 89 extern Register r0; | |
| 90 extern Register r1; | |
| 91 extern Register r2; | |
| 92 extern Register r3; | |
| 93 extern Register r4; | |
| 94 extern Register r5; | |
| 95 extern Register r6; | |
| 96 extern Register r7; | |
| 97 extern Register r8; | |
| 98 extern Register r9; | |
| 99 extern Register r10; | |
| 100 extern Register fp; | |
| 101 extern Register ip; | |
| 102 extern Register sp; | |
| 103 extern Register lr; | |
| 104 extern Register pc; | |
| 105 | |
| 106 | |
| 107 // Single word VFP register. | |
| 108 struct SwVfpRegister { | |
| 109 bool is_valid() const { return 0 <= code_ && code_ < 32; } | |
| 110 bool is(SwVfpRegister reg) const { return code_ == reg.code_; } | |
| 111 int code() const { | |
| 112 ASSERT(is_valid()); | |
| 113 return code_; | |
| 114 } | |
| 115 int bit() const { | |
| 116 ASSERT(is_valid()); | |
| 117 return 1 << code_; | |
| 118 } | |
| 119 | |
| 120 int code_; | |
| 121 }; | |
| 122 | |
| 123 | |
| 124 // Double word VFP register. | |
| 125 struct DwVfpRegister { | |
| 126 // Supporting d0 to d15, can be later extended to d31. | |
| 127 bool is_valid() const { return 0 <= code_ && code_ < 16; } | |
| 128 bool is(DwVfpRegister reg) const { return code_ == reg.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 int code_; | |
| 139 }; | |
| 140 | |
| 141 | |
| 142 // Support for VFP registers s0 to s31 (d0 to d15). | |
| 143 // Note that "s(N):s(N+1)" is the same as "d(N/2)". | |
| 144 extern SwVfpRegister s0; | |
| 145 extern SwVfpRegister s1; | |
| 146 extern SwVfpRegister s2; | |
| 147 extern SwVfpRegister s3; | |
| 148 extern SwVfpRegister s4; | |
| 149 extern SwVfpRegister s5; | |
| 150 extern SwVfpRegister s6; | |
| 151 extern SwVfpRegister s7; | |
| 152 extern SwVfpRegister s8; | |
| 153 extern SwVfpRegister s9; | |
| 154 extern SwVfpRegister s10; | |
| 155 extern SwVfpRegister s11; | |
| 156 extern SwVfpRegister s12; | |
| 157 extern SwVfpRegister s13; | |
| 158 extern SwVfpRegister s14; | |
| 159 extern SwVfpRegister s15; | |
| 160 extern SwVfpRegister s16; | |
| 161 extern SwVfpRegister s17; | |
| 162 extern SwVfpRegister s18; | |
| 163 extern SwVfpRegister s19; | |
| 164 extern SwVfpRegister s20; | |
| 165 extern SwVfpRegister s21; | |
| 166 extern SwVfpRegister s22; | |
| 167 extern SwVfpRegister s23; | |
| 168 extern SwVfpRegister s24; | |
| 169 extern SwVfpRegister s25; | |
| 170 extern SwVfpRegister s26; | |
| 171 extern SwVfpRegister s27; | |
| 172 extern SwVfpRegister s28; | |
| 173 extern SwVfpRegister s29; | |
| 174 extern SwVfpRegister s30; | |
| 175 extern SwVfpRegister s31; | |
| 176 | |
| 177 extern DwVfpRegister d0; | |
| 178 extern DwVfpRegister d1; | |
| 179 extern DwVfpRegister d2; | |
| 180 extern DwVfpRegister d3; | |
| 181 extern DwVfpRegister d4; | |
| 182 extern DwVfpRegister d5; | |
| 183 extern DwVfpRegister d6; | |
| 184 extern DwVfpRegister d7; | |
| 185 extern DwVfpRegister d8; | |
| 186 extern DwVfpRegister d9; | |
| 187 extern DwVfpRegister d10; | |
| 188 extern DwVfpRegister d11; | |
| 189 extern DwVfpRegister d12; | |
| 190 extern DwVfpRegister d13; | |
| 191 extern DwVfpRegister d14; | |
| 192 extern DwVfpRegister d15; | |
| 193 | |
| 194 | |
| 195 // Coprocessor register | |
| 196 struct CRegister { | |
| 197 bool is_valid() const { return 0 <= code_ && code_ < 16; } | |
| 198 bool is(CRegister creg) const { return code_ == creg.code_; } | |
| 199 int code() const { | |
| 200 ASSERT(is_valid()); | |
| 201 return code_; | |
| 202 } | |
| 203 int bit() const { | |
| 204 ASSERT(is_valid()); | |
| 205 return 1 << code_; | |
| 206 } | |
| 207 | |
| 208 // Unfortunately we can't make this private in a struct. | |
| 209 int code_; | |
| 210 }; | |
| 211 | |
| 212 | |
| 213 extern CRegister no_creg; | |
| 214 extern CRegister cr0; | |
| 215 extern CRegister cr1; | |
| 216 extern CRegister cr2; | |
| 217 extern CRegister cr3; | |
| 218 extern CRegister cr4; | |
| 219 extern CRegister cr5; | |
| 220 extern CRegister cr6; | |
| 221 extern CRegister cr7; | |
| 222 extern CRegister cr8; | |
| 223 extern CRegister cr9; | |
| 224 extern CRegister cr10; | |
| 225 extern CRegister cr11; | |
| 226 extern CRegister cr12; | |
| 227 extern CRegister cr13; | |
| 228 extern CRegister cr14; | |
| 229 extern CRegister cr15; | |
| 230 | |
| 231 | |
| 232 // Coprocessor number | |
| 233 enum Coprocessor { | |
| 234 p0 = 0, | |
| 235 p1 = 1, | |
| 236 p2 = 2, | |
| 237 p3 = 3, | |
| 238 p4 = 4, | |
| 239 p5 = 5, | |
| 240 p6 = 6, | |
| 241 p7 = 7, | |
| 242 p8 = 8, | |
| 243 p9 = 9, | |
| 244 p10 = 10, | |
| 245 p11 = 11, | |
| 246 p12 = 12, | |
| 247 p13 = 13, | |
| 248 p14 = 14, | |
| 249 p15 = 15 | |
| 250 }; | |
| 251 | |
| 252 | |
| 253 // Condition field in instructions. | |
| 254 enum Condition { | |
| 255 eq = 0 << 28, // Z set equal. | |
| 256 ne = 1 << 28, // Z clear not equal. | |
| 257 nz = 1 << 28, // Z clear not zero. | |
| 258 cs = 2 << 28, // C set carry set. | |
| 259 hs = 2 << 28, // C set unsigned higher or same. | |
| 260 cc = 3 << 28, // C clear carry clear. | |
| 261 lo = 3 << 28, // C clear unsigned lower. | |
| 262 mi = 4 << 28, // N set negative. | |
| 263 pl = 5 << 28, // N clear positive or zero. | |
| 264 vs = 6 << 28, // V set overflow. | |
| 265 vc = 7 << 28, // V clear no overflow. | |
| 266 hi = 8 << 28, // C set, Z clear unsigned higher. | |
| 267 ls = 9 << 28, // C clear or Z set unsigned lower or same. | |
| 268 ge = 10 << 28, // N == V greater or equal. | |
| 269 lt = 11 << 28, // N != V less than. | |
| 270 gt = 12 << 28, // Z clear, N == V greater than. | |
| 271 le = 13 << 28, // Z set or N != V less then or equal | |
| 272 al = 14 << 28 // always. | |
| 273 }; | |
| 274 | |
| 275 | |
| 276 // Returns the equivalent of !cc. | |
| 277 INLINE(Condition NegateCondition(Condition cc)); | |
| 278 | |
| 279 | |
| 280 // Corresponds to transposing the operands of a comparison. | |
| 281 inline Condition ReverseCondition(Condition cc) { | |
| 282 switch (cc) { | |
| 283 case lo: | |
| 284 return hi; | |
| 285 case hi: | |
| 286 return lo; | |
| 287 case hs: | |
| 288 return ls; | |
| 289 case ls: | |
| 290 return hs; | |
| 291 case lt: | |
| 292 return gt; | |
| 293 case gt: | |
| 294 return lt; | |
| 295 case ge: | |
| 296 return le; | |
| 297 case le: | |
| 298 return ge; | |
| 299 default: | |
| 300 return cc; | |
| 301 }; | |
| 302 } | |
| 303 | |
| 304 | |
| 305 // Branch hints are not used on the ARM. They are defined so that they can | |
| 306 // appear in shared function signatures, but will be ignored in ARM | |
| 307 // implementations. | |
| 308 enum Hint { no_hint }; | |
| 309 | |
| 310 // Hints are not used on the arm. Negating is trivial. | |
| 311 inline Hint NegateHint(Hint ignored) { return no_hint; } | |
| 312 | |
| 313 | |
| 314 // ----------------------------------------------------------------------------- | |
| 315 // Addressing modes and instruction variants | |
| 316 | |
| 317 // Shifter operand shift operation | |
| 318 enum ShiftOp { | |
| 319 LSL = 0 << 5, | |
| 320 LSR = 1 << 5, | |
| 321 ASR = 2 << 5, | |
| 322 ROR = 3 << 5, | |
| 323 RRX = -1 | |
| 324 }; | |
| 325 | |
| 326 | |
| 327 // Condition code updating mode | |
| 328 enum SBit { | |
| 329 SetCC = 1 << 20, // set condition code | |
| 330 LeaveCC = 0 << 20 // leave condition code unchanged | |
| 331 }; | |
| 332 | |
| 333 | |
| 334 // Status register selection | |
| 335 enum SRegister { | |
| 336 CPSR = 0 << 22, | |
| 337 SPSR = 1 << 22 | |
| 338 }; | |
| 339 | |
| 340 | |
| 341 // Status register fields | |
| 342 enum SRegisterField { | |
| 343 CPSR_c = CPSR | 1 << 16, | |
| 344 CPSR_x = CPSR | 1 << 17, | |
| 345 CPSR_s = CPSR | 1 << 18, | |
| 346 CPSR_f = CPSR | 1 << 19, | |
| 347 SPSR_c = SPSR | 1 << 16, | |
| 348 SPSR_x = SPSR | 1 << 17, | |
| 349 SPSR_s = SPSR | 1 << 18, | |
| 350 SPSR_f = SPSR | 1 << 19 | |
| 351 }; | |
| 352 | |
| 353 // Status register field mask (or'ed SRegisterField enum values) | |
| 354 typedef uint32_t SRegisterFieldMask; | |
| 355 | |
| 356 | |
| 357 // Memory operand addressing mode | |
| 358 enum AddrMode { | |
| 359 // bit encoding P U W | |
| 360 Offset = (8|4|0) << 21, // offset (without writeback to base) | |
| 361 PreIndex = (8|4|1) << 21, // pre-indexed addressing with writeback | |
| 362 PostIndex = (0|4|0) << 21, // post-indexed addressing with writeback | |
| 363 NegOffset = (8|0|0) << 21, // negative offset (without writeback to base) | |
| 364 NegPreIndex = (8|0|1) << 21, // negative pre-indexed with writeback | |
| 365 NegPostIndex = (0|0|0) << 21 // negative post-indexed with writeback | |
| 366 }; | |
| 367 | |
| 368 | |
| 369 // Load/store multiple addressing mode | |
| 370 enum BlockAddrMode { | |
| 371 // bit encoding P U W | |
| 372 da = (0|0|0) << 21, // decrement after | |
| 373 ia = (0|4|0) << 21, // increment after | |
| 374 db = (8|0|0) << 21, // decrement before | |
| 375 ib = (8|4|0) << 21, // increment before | |
| 376 da_w = (0|0|1) << 21, // decrement after with writeback to base | |
| 377 ia_w = (0|4|1) << 21, // increment after with writeback to base | |
| 378 db_w = (8|0|1) << 21, // decrement before with writeback to base | |
| 379 ib_w = (8|4|1) << 21 // increment before with writeback to base | |
| 380 }; | |
| 381 | |
| 382 | |
| 383 // Coprocessor load/store operand size | |
| 384 enum LFlag { | |
| 385 Long = 1 << 22, // long load/store coprocessor | |
| 386 Short = 0 << 22 // short load/store coprocessor | |
| 387 }; | |
| 388 | |
| 389 | |
| 390 // ----------------------------------------------------------------------------- | |
| 391 // Machine instruction Operands | |
| 392 | |
| 393 // Class Operand represents a shifter operand in data processing instructions | |
| 394 class Operand BASE_EMBEDDED { | |
| 395 public: | |
| 396 // immediate | |
| 397 INLINE(explicit Operand(int32_t immediate, | |
| 398 RelocInfo::Mode rmode = RelocInfo::NONE)); | |
| 399 INLINE(explicit Operand(const ExternalReference& f)); | |
| 400 INLINE(explicit Operand(const char* s)); | |
| 401 explicit Operand(Handle<Object> handle); | |
| 402 INLINE(explicit Operand(Smi* value)); | |
| 403 | |
| 404 // rm | |
| 405 INLINE(explicit Operand(Register rm)); | |
| 406 | |
| 407 // rm <shift_op> shift_imm | |
| 408 explicit Operand(Register rm, ShiftOp shift_op, int shift_imm); | |
| 409 | |
| 410 // rm <shift_op> rs | |
| 411 explicit Operand(Register rm, ShiftOp shift_op, Register rs); | |
| 412 | |
| 413 // Return true if this is a register operand. | |
| 414 INLINE(bool is_reg() const); | |
| 415 | |
| 416 Register rm() const { return rm_; } | |
| 417 | |
| 418 private: | |
| 419 Register rm_; | |
| 420 Register rs_; | |
| 421 ShiftOp shift_op_; | |
| 422 int shift_imm_; // valid if rm_ != no_reg && rs_ == no_reg | |
| 423 int32_t imm32_; // valid if rm_ == no_reg | |
| 424 RelocInfo::Mode rmode_; | |
| 425 | |
| 426 friend class Assembler; | |
| 427 }; | |
| 428 | |
| 429 | |
| 430 // Class MemOperand represents a memory operand in load and store instructions | |
| 431 class MemOperand BASE_EMBEDDED { | |
| 432 public: | |
| 433 // [rn +/- offset] Offset/NegOffset | |
| 434 // [rn +/- offset]! PreIndex/NegPreIndex | |
| 435 // [rn], +/- offset PostIndex/NegPostIndex | |
| 436 // offset is any signed 32-bit value; offset is first loaded to register ip if | |
| 437 // it does not fit the addressing mode (12-bit unsigned and sign bit) | |
| 438 explicit MemOperand(Register rn, int32_t offset = 0, AddrMode am = Offset); | |
| 439 | |
| 440 // [rn +/- rm] Offset/NegOffset | |
| 441 // [rn +/- rm]! PreIndex/NegPreIndex | |
| 442 // [rn], +/- rm PostIndex/NegPostIndex | |
| 443 explicit MemOperand(Register rn, Register rm, AddrMode am = Offset); | |
| 444 | |
| 445 // [rn +/- rm <shift_op> shift_imm] Offset/NegOffset | |
| 446 // [rn +/- rm <shift_op> shift_imm]! PreIndex/NegPreIndex | |
| 447 // [rn], +/- rm <shift_op> shift_imm PostIndex/NegPostIndex | |
| 448 explicit MemOperand(Register rn, Register rm, | |
| 449 ShiftOp shift_op, int shift_imm, AddrMode am = Offset); | |
| 450 | |
| 451 private: | |
| 452 Register rn_; // base | |
| 453 Register rm_; // register offset | |
| 454 int32_t offset_; // valid if rm_ == no_reg | |
| 455 ShiftOp shift_op_; | |
| 456 int shift_imm_; // valid if rm_ != no_reg && rs_ == no_reg | |
| 457 AddrMode am_; // bits P, U, and W | |
| 458 | |
| 459 friend class Assembler; | |
| 460 }; | |
| 461 | |
| 462 // CpuFeatures keeps track of which features are supported by the target CPU. | |
| 463 // Supported features must be enabled by a Scope before use. | |
| 464 class CpuFeatures : public AllStatic { | |
| 465 public: | |
| 466 // Detect features of the target CPU. Set safe defaults if the serializer | |
| 467 // is enabled (snapshots must be portable). | |
| 468 static void Probe(); | |
| 469 | |
| 470 // Check whether a feature is supported by the target CPU. | |
| 471 static bool IsSupported(CpuFeature f) { | |
| 472 if (f == VFP3 && !FLAG_enable_vfp3) return false; | |
| 473 return (supported_ & (1u << f)) != 0; | |
| 474 } | |
| 475 | |
| 476 // Check whether a feature is currently enabled. | |
| 477 static bool IsEnabled(CpuFeature f) { | |
| 478 return (enabled_ & (1u << f)) != 0; | |
| 479 } | |
| 480 | |
| 481 // Enable a specified feature within a scope. | |
| 482 class Scope BASE_EMBEDDED { | |
| 483 #ifdef DEBUG | |
| 484 public: | |
| 485 explicit Scope(CpuFeature f) { | |
| 486 ASSERT(CpuFeatures::IsSupported(f)); | |
| 487 ASSERT(!Serializer::enabled() || | |
| 488 (found_by_runtime_probing_ & (1u << f)) == 0); | |
| 489 old_enabled_ = CpuFeatures::enabled_; | |
| 490 CpuFeatures::enabled_ |= 1u << f; | |
| 491 } | |
| 492 ~Scope() { CpuFeatures::enabled_ = old_enabled_; } | |
| 493 private: | |
| 494 unsigned old_enabled_; | |
| 495 #else | |
| 496 public: | |
| 497 explicit Scope(CpuFeature f) {} | |
| 498 #endif | |
| 499 }; | |
| 500 | |
| 501 private: | |
| 502 static unsigned supported_; | |
| 503 static unsigned enabled_; | |
| 504 static unsigned found_by_runtime_probing_; | |
| 505 }; | |
| 506 | |
| 507 | |
| 508 typedef int32_t Instr; | |
| 509 | |
| 510 | |
| 511 extern const Instr kMovLrPc; | |
| 512 extern const Instr kLdrPCPattern; | |
| 513 | |
| 514 | |
| 515 class Assembler : public Malloced { | |
| 516 public: | |
| 517 // Create an assembler. Instructions and relocation information are emitted | |
| 518 // into a buffer, with the instructions starting from the beginning and the | |
| 519 // relocation information starting from the end of the buffer. See CodeDesc | |
| 520 // for a detailed comment on the layout (globals.h). | |
| 521 // | |
| 522 // If the provided buffer is NULL, the assembler allocates and grows its own | |
| 523 // buffer, and buffer_size determines the initial buffer size. The buffer is | |
| 524 // owned by the assembler and deallocated upon destruction of the assembler. | |
| 525 // | |
| 526 // If the provided buffer is not NULL, the assembler uses the provided buffer | |
| 527 // for code generation and assumes its size to be buffer_size. If the buffer | |
| 528 // is too small, a fatal error occurs. No deallocation of the buffer is done | |
| 529 // upon destruction of the assembler. | |
| 530 Assembler(void* buffer, int buffer_size); | |
| 531 ~Assembler(); | |
| 532 | |
| 533 // GetCode emits any pending (non-emitted) code and fills the descriptor | |
| 534 // desc. GetCode() is idempotent; it returns the same result if no other | |
| 535 // Assembler functions are invoked in between GetCode() calls. | |
| 536 void GetCode(CodeDesc* desc); | |
| 537 | |
| 538 // Label operations & relative jumps (PPUM Appendix D) | |
| 539 // | |
| 540 // Takes a branch opcode (cc) and a label (L) and generates | |
| 541 // either a backward branch or a forward branch and links it | |
| 542 // to the label fixup chain. Usage: | |
| 543 // | |
| 544 // Label L; // unbound label | |
| 545 // j(cc, &L); // forward branch to unbound label | |
| 546 // bind(&L); // bind label to the current pc | |
| 547 // j(cc, &L); // backward branch to bound label | |
| 548 // bind(&L); // illegal: a label may be bound only once | |
| 549 // | |
| 550 // Note: The same Label can be used for forward and backward branches | |
| 551 // but it may be bound only once. | |
| 552 | |
| 553 void bind(Label* L); // binds an unbound label L to the current code position | |
| 554 | |
| 555 // Returns the branch offset to the given label from the current code position | |
| 556 // Links the label to the current position if it is still unbound | |
| 557 // Manages the jump elimination optimization if the second parameter is true. | |
| 558 int branch_offset(Label* L, bool jump_elimination_allowed); | |
| 559 | |
| 560 // Puts a labels target address at the given position. | |
| 561 // The high 8 bits are set to zero. | |
| 562 void label_at_put(Label* L, int at_offset); | |
| 563 | |
| 564 // Return the address in the constant pool of the code target address used by | |
| 565 // the branch/call instruction at pc. | |
| 566 INLINE(static Address target_address_address_at(Address pc)); | |
| 567 | |
| 568 // Read/Modify the code target address in the branch/call instruction at pc. | |
| 569 INLINE(static Address target_address_at(Address pc)); | |
| 570 INLINE(static void set_target_address_at(Address pc, Address target)); | |
| 571 | |
| 572 // This sets the branch destination (which is in the constant pool on ARM). | |
| 573 // This is for calls and branches within generated code. | |
| 574 inline static void set_target_at(Address constant_pool_entry, Address target); | |
| 575 | |
| 576 // This sets the branch destination (which is in the constant pool on ARM). | |
| 577 // This is for calls and branches to runtime code. | |
| 578 inline static void set_external_target_at(Address constant_pool_entry, | |
| 579 Address target) { | |
| 580 set_target_at(constant_pool_entry, target); | |
| 581 } | |
| 582 | |
| 583 // Here we are patching the address in the constant pool, not the actual call | |
| 584 // instruction. The address in the constant pool is the same size as a | |
| 585 // pointer. | |
| 586 static const int kCallTargetSize = kPointerSize; | |
| 587 static const int kExternalTargetSize = kPointerSize; | |
| 588 | |
| 589 // Size of an instruction. | |
| 590 static const int kInstrSize = sizeof(Instr); | |
| 591 | |
| 592 // Distance between the instruction referring to the address of the call | |
| 593 // target (ldr pc, [target addr in const pool]) and the return address | |
| 594 static const int kCallTargetAddressOffset = kInstrSize; | |
| 595 | |
| 596 // Distance between start of patched return sequence and the emitted address | |
| 597 // to jump to. | |
| 598 static const int kPatchReturnSequenceAddressOffset = kInstrSize; | |
| 599 | |
| 600 // Difference between address of current opcode and value read from pc | |
| 601 // register. | |
| 602 static const int kPcLoadDelta = 8; | |
| 603 | |
| 604 static const int kJSReturnSequenceLength = 4; | |
| 605 | |
| 606 // --------------------------------------------------------------------------- | |
| 607 // Code generation | |
| 608 | |
| 609 // Insert the smallest number of nop instructions | |
| 610 // possible to align the pc offset to a multiple | |
| 611 // of m. m must be a power of 2 (>= 4). | |
| 612 void Align(int m); | |
| 613 | |
| 614 // Branch instructions | |
| 615 void b(int branch_offset, Condition cond = al); | |
| 616 void bl(int branch_offset, Condition cond = al); | |
| 617 void blx(int branch_offset); // v5 and above | |
| 618 void blx(Register target, Condition cond = al); // v5 and above | |
| 619 void bx(Register target, Condition cond = al); // v5 and above, plus v4t | |
| 620 | |
| 621 // Convenience branch instructions using labels | |
| 622 void b(Label* L, Condition cond = al) { | |
| 623 b(branch_offset(L, cond == al), cond); | |
| 624 } | |
| 625 void b(Condition cond, Label* L) { b(branch_offset(L, cond == al), cond); } | |
| 626 void bl(Label* L, Condition cond = al) { bl(branch_offset(L, false), cond); } | |
| 627 void bl(Condition cond, Label* L) { bl(branch_offset(L, false), cond); } | |
| 628 void blx(Label* L) { blx(branch_offset(L, false)); } // v5 and above | |
| 629 | |
| 630 // Data-processing instructions | |
| 631 void ubfx(Register dst, Register src1, const Operand& src2, | |
| 632 const Operand& src3, Condition cond = al); | |
| 633 | |
| 634 void and_(Register dst, Register src1, const Operand& src2, | |
| 635 SBit s = LeaveCC, Condition cond = al); | |
| 636 | |
| 637 void eor(Register dst, Register src1, const Operand& src2, | |
| 638 SBit s = LeaveCC, Condition cond = al); | |
| 639 | |
| 640 void sub(Register dst, Register src1, const Operand& src2, | |
| 641 SBit s = LeaveCC, Condition cond = al); | |
| 642 void sub(Register dst, Register src1, Register src2, | |
| 643 SBit s = LeaveCC, Condition cond = al) { | |
| 644 sub(dst, src1, Operand(src2), s, cond); | |
| 645 } | |
| 646 | |
| 647 void rsb(Register dst, Register src1, const Operand& src2, | |
| 648 SBit s = LeaveCC, Condition cond = al); | |
| 649 | |
| 650 void add(Register dst, Register src1, const Operand& src2, | |
| 651 SBit s = LeaveCC, Condition cond = al); | |
| 652 | |
| 653 void adc(Register dst, Register src1, const Operand& src2, | |
| 654 SBit s = LeaveCC, Condition cond = al); | |
| 655 | |
| 656 void sbc(Register dst, Register src1, const Operand& src2, | |
| 657 SBit s = LeaveCC, Condition cond = al); | |
| 658 | |
| 659 void rsc(Register dst, Register src1, const Operand& src2, | |
| 660 SBit s = LeaveCC, Condition cond = al); | |
| 661 | |
| 662 void tst(Register src1, const Operand& src2, Condition cond = al); | |
| 663 void tst(Register src1, Register src2, Condition cond = al) { | |
| 664 tst(src1, Operand(src2), cond); | |
| 665 } | |
| 666 | |
| 667 void teq(Register src1, const Operand& src2, Condition cond = al); | |
| 668 | |
| 669 void cmp(Register src1, const Operand& src2, Condition cond = al); | |
| 670 void cmp(Register src1, Register src2, Condition cond = al) { | |
| 671 cmp(src1, Operand(src2), cond); | |
| 672 } | |
| 673 | |
| 674 void cmn(Register src1, const Operand& src2, Condition cond = al); | |
| 675 | |
| 676 void orr(Register dst, Register src1, const Operand& src2, | |
| 677 SBit s = LeaveCC, Condition cond = al); | |
| 678 void orr(Register dst, Register src1, Register src2, | |
| 679 SBit s = LeaveCC, Condition cond = al) { | |
| 680 orr(dst, src1, Operand(src2), s, cond); | |
| 681 } | |
| 682 | |
| 683 void mov(Register dst, const Operand& src, | |
| 684 SBit s = LeaveCC, Condition cond = al); | |
| 685 void mov(Register dst, Register src, SBit s = LeaveCC, Condition cond = al) { | |
| 686 mov(dst, Operand(src), s, cond); | |
| 687 } | |
| 688 | |
| 689 void bic(Register dst, Register src1, const Operand& src2, | |
| 690 SBit s = LeaveCC, Condition cond = al); | |
| 691 | |
| 692 void mvn(Register dst, const Operand& src, | |
| 693 SBit s = LeaveCC, Condition cond = al); | |
| 694 | |
| 695 // Multiply instructions | |
| 696 | |
| 697 void mla(Register dst, Register src1, Register src2, Register srcA, | |
| 698 SBit s = LeaveCC, Condition cond = al); | |
| 699 | |
| 700 void mul(Register dst, Register src1, Register src2, | |
| 701 SBit s = LeaveCC, Condition cond = al); | |
| 702 | |
| 703 void smlal(Register dstL, Register dstH, Register src1, Register src2, | |
| 704 SBit s = LeaveCC, Condition cond = al); | |
| 705 | |
| 706 void smull(Register dstL, Register dstH, Register src1, Register src2, | |
| 707 SBit s = LeaveCC, Condition cond = al); | |
| 708 | |
| 709 void umlal(Register dstL, Register dstH, Register src1, Register src2, | |
| 710 SBit s = LeaveCC, Condition cond = al); | |
| 711 | |
| 712 void umull(Register dstL, Register dstH, Register src1, Register src2, | |
| 713 SBit s = LeaveCC, Condition cond = al); | |
| 714 | |
| 715 // Miscellaneous arithmetic instructions | |
| 716 | |
| 717 void clz(Register dst, Register src, Condition cond = al); // v5 and above | |
| 718 | |
| 719 // Status register access instructions | |
| 720 | |
| 721 void mrs(Register dst, SRegister s, Condition cond = al); | |
| 722 void msr(SRegisterFieldMask fields, const Operand& src, Condition cond = al); | |
| 723 | |
| 724 // Load/Store instructions | |
| 725 void ldr(Register dst, const MemOperand& src, Condition cond = al); | |
| 726 void str(Register src, const MemOperand& dst, Condition cond = al); | |
| 727 void ldrb(Register dst, const MemOperand& src, Condition cond = al); | |
| 728 void strb(Register src, const MemOperand& dst, Condition cond = al); | |
| 729 void ldrh(Register dst, const MemOperand& src, Condition cond = al); | |
| 730 void strh(Register src, const MemOperand& dst, Condition cond = al); | |
| 731 void ldrsb(Register dst, const MemOperand& src, Condition cond = al); | |
| 732 void ldrsh(Register dst, const MemOperand& src, Condition cond = al); | |
| 733 | |
| 734 // Load/Store multiple instructions | |
| 735 void ldm(BlockAddrMode am, Register base, RegList dst, Condition cond = al); | |
| 736 void stm(BlockAddrMode am, Register base, RegList src, Condition cond = al); | |
| 737 | |
| 738 // Exception-generating instructions and debugging support | |
| 739 void stop(const char* msg); | |
| 740 | |
| 741 void bkpt(uint32_t imm16); // v5 and above | |
| 742 void swi(uint32_t imm24, Condition cond = al); | |
| 743 | |
| 744 // Coprocessor instructions | |
| 745 | |
| 746 void cdp(Coprocessor coproc, int opcode_1, | |
| 747 CRegister crd, CRegister crn, CRegister crm, | |
| 748 int opcode_2, Condition cond = al); | |
| 749 | |
| 750 void cdp2(Coprocessor coproc, int opcode_1, | |
| 751 CRegister crd, CRegister crn, CRegister crm, | |
| 752 int opcode_2); // v5 and above | |
| 753 | |
| 754 void mcr(Coprocessor coproc, int opcode_1, | |
| 755 Register rd, CRegister crn, CRegister crm, | |
| 756 int opcode_2 = 0, Condition cond = al); | |
| 757 | |
| 758 void mcr2(Coprocessor coproc, int opcode_1, | |
| 759 Register rd, CRegister crn, CRegister crm, | |
| 760 int opcode_2 = 0); // v5 and above | |
| 761 | |
| 762 void mrc(Coprocessor coproc, int opcode_1, | |
| 763 Register rd, CRegister crn, CRegister crm, | |
| 764 int opcode_2 = 0, Condition cond = al); | |
| 765 | |
| 766 void mrc2(Coprocessor coproc, int opcode_1, | |
| 767 Register rd, CRegister crn, CRegister crm, | |
| 768 int opcode_2 = 0); // v5 and above | |
| 769 | |
| 770 void ldc(Coprocessor coproc, CRegister crd, const MemOperand& src, | |
| 771 LFlag l = Short, Condition cond = al); | |
| 772 void ldc(Coprocessor coproc, CRegister crd, Register base, int option, | |
| 773 LFlag l = Short, Condition cond = al); | |
| 774 | |
| 775 void ldc2(Coprocessor coproc, CRegister crd, const MemOperand& src, | |
| 776 LFlag l = Short); // v5 and above | |
| 777 void ldc2(Coprocessor coproc, CRegister crd, Register base, int option, | |
| 778 LFlag l = Short); // v5 and above | |
| 779 | |
| 780 void stc(Coprocessor coproc, CRegister crd, const MemOperand& dst, | |
| 781 LFlag l = Short, Condition cond = al); | |
| 782 void stc(Coprocessor coproc, CRegister crd, Register base, int option, | |
| 783 LFlag l = Short, Condition cond = al); | |
| 784 | |
| 785 void stc2(Coprocessor coproc, CRegister crd, const MemOperand& dst, | |
| 786 LFlag l = Short); // v5 and above | |
| 787 void stc2(Coprocessor coproc, CRegister crd, Register base, int option, | |
| 788 LFlag l = Short); // v5 and above | |
| 789 | |
| 790 // Support for VFP. | |
| 791 // All these APIs support S0 to S31 and D0 to D15. | |
| 792 // Currently these APIs do not support extended D registers, i.e, D16 to D31. | |
| 793 // However, some simple modifications can allow | |
| 794 // these APIs to support D16 to D31. | |
| 795 | |
| 796 void vldr(const DwVfpRegister dst, | |
| 797 const Register base, | |
| 798 int offset, // Offset must be a multiple of 4. | |
| 799 const Condition cond = al); | |
| 800 void vstr(const DwVfpRegister src, | |
| 801 const Register base, | |
| 802 int offset, // Offset must be a multiple of 4. | |
| 803 const Condition cond = al); | |
| 804 void vmov(const DwVfpRegister dst, | |
| 805 const Register src1, | |
| 806 const Register src2, | |
| 807 const Condition cond = al); | |
| 808 void vmov(const Register dst1, | |
| 809 const Register dst2, | |
| 810 const DwVfpRegister src, | |
| 811 const Condition cond = al); | |
| 812 void vmov(const SwVfpRegister dst, | |
| 813 const Register src, | |
| 814 const Condition cond = al); | |
| 815 void vmov(const Register dst, | |
| 816 const SwVfpRegister src, | |
| 817 const Condition cond = al); | |
| 818 void vcvt(const DwVfpRegister dst, | |
| 819 const SwVfpRegister src, | |
| 820 const Condition cond = al); | |
| 821 void vcvt(const SwVfpRegister dst, | |
| 822 const DwVfpRegister src, | |
| 823 const Condition cond = al); | |
| 824 | |
| 825 void vadd(const DwVfpRegister dst, | |
| 826 const DwVfpRegister src1, | |
| 827 const DwVfpRegister src2, | |
| 828 const Condition cond = al); | |
| 829 void vsub(const DwVfpRegister dst, | |
| 830 const DwVfpRegister src1, | |
| 831 const DwVfpRegister src2, | |
| 832 const Condition cond = al); | |
| 833 void vmul(const DwVfpRegister dst, | |
| 834 const DwVfpRegister src1, | |
| 835 const DwVfpRegister src2, | |
| 836 const Condition cond = al); | |
| 837 void vdiv(const DwVfpRegister dst, | |
| 838 const DwVfpRegister src1, | |
| 839 const DwVfpRegister src2, | |
| 840 const Condition cond = al); | |
| 841 void vcmp(const DwVfpRegister src1, | |
| 842 const DwVfpRegister src2, | |
| 843 const SBit s = LeaveCC, | |
| 844 const Condition cond = al); | |
| 845 void vmrs(const Register dst, | |
| 846 const Condition cond = al); | |
| 847 | |
| 848 // Pseudo instructions | |
| 849 void nop() { mov(r0, Operand(r0)); } | |
| 850 | |
| 851 void push(Register src, Condition cond = al) { | |
| 852 str(src, MemOperand(sp, 4, NegPreIndex), cond); | |
| 853 } | |
| 854 | |
| 855 void pop(Register dst, Condition cond = al) { | |
| 856 ldr(dst, MemOperand(sp, 4, PostIndex), cond); | |
| 857 } | |
| 858 | |
| 859 void pop() { | |
| 860 add(sp, sp, Operand(kPointerSize)); | |
| 861 } | |
| 862 | |
| 863 // Jump unconditionally to given label. | |
| 864 void jmp(Label* L) { b(L, al); } | |
| 865 | |
| 866 // Check the code size generated from label to here. | |
| 867 int InstructionsGeneratedSince(Label* l) { | |
| 868 return (pc_offset() - l->pos()) / kInstrSize; | |
| 869 } | |
| 870 | |
| 871 // Check whether an immediate fits an addressing mode 1 instruction. | |
| 872 bool ImmediateFitsAddrMode1Instruction(int32_t imm32); | |
| 873 | |
| 874 // Postpone the generation of the constant pool for the specified number of | |
| 875 // instructions. | |
| 876 void BlockConstPoolFor(int instructions); | |
| 877 | |
| 878 // Debugging | |
| 879 | |
| 880 // Mark address of the ExitJSFrame code. | |
| 881 void RecordJSReturn(); | |
| 882 | |
| 883 // Record a comment relocation entry that can be used by a disassembler. | |
| 884 // Use --debug_code to enable. | |
| 885 void RecordComment(const char* msg); | |
| 886 | |
| 887 void RecordPosition(int pos); | |
| 888 void RecordStatementPosition(int pos); | |
| 889 void WriteRecordedPositions(); | |
| 890 | |
| 891 int pc_offset() const { return pc_ - buffer_; } | |
| 892 int current_position() const { return current_position_; } | |
| 893 int current_statement_position() const { return current_statement_position_; } | |
| 894 | |
| 895 protected: | |
| 896 int buffer_space() const { return reloc_info_writer.pos() - pc_; } | |
| 897 | |
| 898 // Read/patch instructions | |
| 899 static Instr instr_at(byte* pc) { return *reinterpret_cast<Instr*>(pc); } | |
| 900 void instr_at_put(byte* pc, Instr instr) { | |
| 901 *reinterpret_cast<Instr*>(pc) = instr; | |
| 902 } | |
| 903 Instr instr_at(int pos) { return *reinterpret_cast<Instr*>(buffer_ + pos); } | |
| 904 void instr_at_put(int pos, Instr instr) { | |
| 905 *reinterpret_cast<Instr*>(buffer_ + pos) = instr; | |
| 906 } | |
| 907 | |
| 908 // Decode branch instruction at pos and return branch target pos | |
| 909 int target_at(int pos); | |
| 910 | |
| 911 // Patch branch instruction at pos to branch to given branch target pos | |
| 912 void target_at_put(int pos, int target_pos); | |
| 913 | |
| 914 // Check if is time to emit a constant pool for pending reloc info entries | |
| 915 void CheckConstPool(bool force_emit, bool require_jump); | |
| 916 | |
| 917 // Block the emission of the constant pool before pc_offset | |
| 918 void BlockConstPoolBefore(int pc_offset) { | |
| 919 if (no_const_pool_before_ < pc_offset) no_const_pool_before_ = pc_offset; | |
| 920 } | |
| 921 | |
| 922 private: | |
| 923 // Code buffer: | |
| 924 // The buffer into which code and relocation info are generated. | |
| 925 byte* buffer_; | |
| 926 int buffer_size_; | |
| 927 // True if the assembler owns the buffer, false if buffer is external. | |
| 928 bool own_buffer_; | |
| 929 | |
| 930 // Buffer size and constant pool distance are checked together at regular | |
| 931 // intervals of kBufferCheckInterval emitted bytes | |
| 932 static const int kBufferCheckInterval = 1*KB/2; | |
| 933 int next_buffer_check_; // pc offset of next buffer check | |
| 934 | |
| 935 // Code generation | |
| 936 // The relocation writer's position is at least kGap bytes below the end of | |
| 937 // the generated instructions. This is so that multi-instruction sequences do | |
| 938 // not have to check for overflow. The same is true for writes of large | |
| 939 // relocation info entries. | |
| 940 static const int kGap = 32; | |
| 941 byte* pc_; // the program counter; moves forward | |
| 942 | |
| 943 // Constant pool generation | |
| 944 // Pools are emitted in the instruction stream, preferably after unconditional | |
| 945 // jumps or after returns from functions (in dead code locations). | |
| 946 // If a long code sequence does not contain unconditional jumps, it is | |
| 947 // necessary to emit the constant pool before the pool gets too far from the | |
| 948 // location it is accessed from. In this case, we emit a jump over the emitted | |
| 949 // constant pool. | |
| 950 // Constants in the pool may be addresses of functions that gets relocated; | |
| 951 // if so, a relocation info entry is associated to the constant pool entry. | |
| 952 | |
| 953 // Repeated checking whether the constant pool should be emitted is rather | |
| 954 // expensive. By default we only check again once a number of instructions | |
| 955 // has been generated. That also means that the sizing of the buffers is not | |
| 956 // an exact science, and that we rely on some slop to not overrun buffers. | |
| 957 static const int kCheckConstIntervalInst = 32; | |
| 958 static const int kCheckConstInterval = kCheckConstIntervalInst * kInstrSize; | |
| 959 | |
| 960 | |
| 961 // Pools are emitted after function return and in dead code at (more or less) | |
| 962 // regular intervals of kDistBetweenPools bytes | |
| 963 static const int kDistBetweenPools = 1*KB; | |
| 964 | |
| 965 // Constants in pools are accessed via pc relative addressing, which can | |
| 966 // reach +/-4KB thereby defining a maximum distance between the instruction | |
| 967 // and the accessed constant. We satisfy this constraint by limiting the | |
| 968 // distance between pools. | |
| 969 static const int kMaxDistBetweenPools = 4*KB - 2*kBufferCheckInterval; | |
| 970 | |
| 971 // Emission of the constant pool may be blocked in some code sequences | |
| 972 int no_const_pool_before_; // block emission before this pc offset | |
| 973 | |
| 974 // Keep track of the last emitted pool to guarantee a maximal distance | |
| 975 int last_const_pool_end_; // pc offset following the last constant pool | |
| 976 | |
| 977 // Relocation info generation | |
| 978 // Each relocation is encoded as a variable size value | |
| 979 static const int kMaxRelocSize = RelocInfoWriter::kMaxSize; | |
| 980 RelocInfoWriter reloc_info_writer; | |
| 981 // Relocation info records are also used during code generation as temporary | |
| 982 // containers for constants and code target addresses until they are emitted | |
| 983 // to the constant pool. These pending relocation info records are temporarily | |
| 984 // stored in a separate buffer until a constant pool is emitted. | |
| 985 // If every instruction in a long sequence is accessing the pool, we need one | |
| 986 // pending relocation entry per instruction. | |
| 987 static const int kMaxNumPRInfo = kMaxDistBetweenPools/kInstrSize; | |
| 988 RelocInfo prinfo_[kMaxNumPRInfo]; // the buffer of pending relocation info | |
| 989 int num_prinfo_; // number of pending reloc info entries in the buffer | |
| 990 | |
| 991 // The bound position, before this we cannot do instruction elimination. | |
| 992 int last_bound_pos_; | |
| 993 | |
| 994 // source position information | |
| 995 int current_position_; | |
| 996 int current_statement_position_; | |
| 997 int written_position_; | |
| 998 int written_statement_position_; | |
| 999 | |
| 1000 // Code emission | |
| 1001 inline void CheckBuffer(); | |
| 1002 void GrowBuffer(); | |
| 1003 inline void emit(Instr x); | |
| 1004 | |
| 1005 // Instruction generation | |
| 1006 void addrmod1(Instr instr, Register rn, Register rd, const Operand& x); | |
| 1007 void addrmod2(Instr instr, Register rd, const MemOperand& x); | |
| 1008 void addrmod3(Instr instr, Register rd, const MemOperand& x); | |
| 1009 void addrmod4(Instr instr, Register rn, RegList rl); | |
| 1010 void addrmod5(Instr instr, CRegister crd, const MemOperand& x); | |
| 1011 | |
| 1012 // Labels | |
| 1013 void print(Label* L); | |
| 1014 void bind_to(Label* L, int pos); | |
| 1015 void link_to(Label* L, Label* appendix); | |
| 1016 void next(Label* L); | |
| 1017 | |
| 1018 // Record reloc info for current pc_ | |
| 1019 void RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data = 0); | |
| 1020 | |
| 1021 friend class RegExpMacroAssemblerARM; | |
| 1022 friend class RelocInfo; | |
| 1023 friend class CodePatcher; | |
| 1024 }; | |
| 1025 | |
| 1026 } } // namespace v8::internal | |
| 1027 | |
| 1028 #endif // V8_ARM_ASSEMBLER_THUMB2_H_ | |
| OLD | NEW |