1/* 2 * Copyright (C) 2008 Apple Inc. 3 * Copyright (C) 2009, 2010 University of Szeged 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions 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 distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 16 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 18 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 19 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 22 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 23 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28#ifndef MacroAssemblerARM_h 29#define MacroAssemblerARM_h 30 31#if ENABLE(ASSEMBLER) && CPU(ARM_TRADITIONAL) 32 33#include "ARMAssembler.h" 34#include "AbstractMacroAssembler.h" 35 36namespace JSC { 37 38class MacroAssemblerARM : public AbstractMacroAssembler<ARMAssembler> { 39 static const int DoubleConditionMask = 0x0f; 40 static const int DoubleConditionBitSpecial = 0x10; 41 COMPILE_ASSERT(!(DoubleConditionBitSpecial & DoubleConditionMask), DoubleConditionBitSpecial_should_not_interfere_with_ARMAssembler_Condition_codes); 42public: 43 typedef ARMRegisters::FPRegisterID FPRegisterID; 44 45 enum Condition { 46 Equal = ARMAssembler::EQ, 47 NotEqual = ARMAssembler::NE, 48 Above = ARMAssembler::HI, 49 AboveOrEqual = ARMAssembler::CS, 50 Below = ARMAssembler::CC, 51 BelowOrEqual = ARMAssembler::LS, 52 GreaterThan = ARMAssembler::GT, 53 GreaterThanOrEqual = ARMAssembler::GE, 54 LessThan = ARMAssembler::LT, 55 LessThanOrEqual = ARMAssembler::LE, 56 Overflow = ARMAssembler::VS, 57 Signed = ARMAssembler::MI, 58 Zero = ARMAssembler::EQ, 59 NonZero = ARMAssembler::NE 60 }; 61 62 enum DoubleCondition { 63 // These conditions will only evaluate to true if the comparison is ordered - i.e. neither operand is NaN. 64 DoubleEqual = ARMAssembler::EQ, 65 DoubleNotEqual = ARMAssembler::NE | DoubleConditionBitSpecial, 66 DoubleGreaterThan = ARMAssembler::GT, 67 DoubleGreaterThanOrEqual = ARMAssembler::GE, 68 DoubleLessThan = ARMAssembler::CC, 69 DoubleLessThanOrEqual = ARMAssembler::LS, 70 // If either operand is NaN, these conditions always evaluate to true. 71 DoubleEqualOrUnordered = ARMAssembler::EQ | DoubleConditionBitSpecial, 72 DoubleNotEqualOrUnordered = ARMAssembler::NE, 73 DoubleGreaterThanOrUnordered = ARMAssembler::HI, 74 DoubleGreaterThanOrEqualOrUnordered = ARMAssembler::CS, 75 DoubleLessThanOrUnordered = ARMAssembler::LT, 76 DoubleLessThanOrEqualOrUnordered = ARMAssembler::LE, 77 }; 78 79 static const RegisterID stackPointerRegister = ARMRegisters::sp; 80 static const RegisterID linkRegister = ARMRegisters::lr; 81 82 static const Scale ScalePtr = TimesFour; 83 84 void add32(RegisterID src, RegisterID dest) 85 { 86 m_assembler.adds_r(dest, dest, src); 87 } 88 89 void add32(TrustedImm32 imm, Address address) 90 { 91 load32(address, ARMRegisters::S1); 92 add32(imm, ARMRegisters::S1); 93 store32(ARMRegisters::S1, address); 94 } 95 96 void add32(TrustedImm32 imm, RegisterID dest) 97 { 98 m_assembler.adds_r(dest, dest, m_assembler.getImm(imm.m_value, ARMRegisters::S0)); 99 } 100 101 void add32(Address src, RegisterID dest) 102 { 103 load32(src, ARMRegisters::S1); 104 add32(ARMRegisters::S1, dest); 105 } 106 107 void and32(RegisterID src, RegisterID dest) 108 { 109 m_assembler.ands_r(dest, dest, src); 110 } 111 112 void and32(TrustedImm32 imm, RegisterID dest) 113 { 114 ARMWord w = m_assembler.getImm(imm.m_value, ARMRegisters::S0, true); 115 if (w & ARMAssembler::OP2_INV_IMM) 116 m_assembler.bics_r(dest, dest, w & ~ARMAssembler::OP2_INV_IMM); 117 else 118 m_assembler.ands_r(dest, dest, w); 119 } 120 121 void lshift32(RegisterID shift_amount, RegisterID dest) 122 { 123 ARMWord w = ARMAssembler::getOp2(0x1f); 124 ASSERT(w != ARMAssembler::INVALID_IMM); 125 m_assembler.and_r(ARMRegisters::S0, shift_amount, w); 126 127 m_assembler.movs_r(dest, m_assembler.lsl_r(dest, ARMRegisters::S0)); 128 } 129 130 void lshift32(TrustedImm32 imm, RegisterID dest) 131 { 132 m_assembler.movs_r(dest, m_assembler.lsl(dest, imm.m_value & 0x1f)); 133 } 134 135 void mul32(RegisterID src, RegisterID dest) 136 { 137 if (src == dest) { 138 move(src, ARMRegisters::S0); 139 src = ARMRegisters::S0; 140 } 141 m_assembler.muls_r(dest, dest, src); 142 } 143 144 void mul32(TrustedImm32 imm, RegisterID src, RegisterID dest) 145 { 146 move(imm, ARMRegisters::S0); 147 m_assembler.muls_r(dest, src, ARMRegisters::S0); 148 } 149 150 void neg32(RegisterID srcDest) 151 { 152 m_assembler.rsbs_r(srcDest, srcDest, ARMAssembler::getOp2(0)); 153 } 154 155 void not32(RegisterID dest) 156 { 157 m_assembler.mvns_r(dest, dest); 158 } 159 160 void or32(RegisterID src, RegisterID dest) 161 { 162 m_assembler.orrs_r(dest, dest, src); 163 } 164 165 void or32(TrustedImm32 imm, RegisterID dest) 166 { 167 m_assembler.orrs_r(dest, dest, m_assembler.getImm(imm.m_value, ARMRegisters::S0)); 168 } 169 170 void rshift32(RegisterID shift_amount, RegisterID dest) 171 { 172 ARMWord w = ARMAssembler::getOp2(0x1f); 173 ASSERT(w != ARMAssembler::INVALID_IMM); 174 m_assembler.and_r(ARMRegisters::S0, shift_amount, w); 175 176 m_assembler.movs_r(dest, m_assembler.asr_r(dest, ARMRegisters::S0)); 177 } 178 179 void rshift32(TrustedImm32 imm, RegisterID dest) 180 { 181 m_assembler.movs_r(dest, m_assembler.asr(dest, imm.m_value & 0x1f)); 182 } 183 184 void urshift32(RegisterID shift_amount, RegisterID dest) 185 { 186 ARMWord w = ARMAssembler::getOp2(0x1f); 187 ASSERT(w != ARMAssembler::INVALID_IMM); 188 m_assembler.and_r(ARMRegisters::S0, shift_amount, w); 189 190 m_assembler.movs_r(dest, m_assembler.lsr_r(dest, ARMRegisters::S0)); 191 } 192 193 void urshift32(TrustedImm32 imm, RegisterID dest) 194 { 195 m_assembler.movs_r(dest, m_assembler.lsr(dest, imm.m_value & 0x1f)); 196 } 197 198 void sub32(RegisterID src, RegisterID dest) 199 { 200 m_assembler.subs_r(dest, dest, src); 201 } 202 203 void sub32(TrustedImm32 imm, RegisterID dest) 204 { 205 m_assembler.subs_r(dest, dest, m_assembler.getImm(imm.m_value, ARMRegisters::S0)); 206 } 207 208 void sub32(TrustedImm32 imm, Address address) 209 { 210 load32(address, ARMRegisters::S1); 211 sub32(imm, ARMRegisters::S1); 212 store32(ARMRegisters::S1, address); 213 } 214 215 void sub32(Address src, RegisterID dest) 216 { 217 load32(src, ARMRegisters::S1); 218 sub32(ARMRegisters::S1, dest); 219 } 220 221 void xor32(RegisterID src, RegisterID dest) 222 { 223 m_assembler.eors_r(dest, dest, src); 224 } 225 226 void xor32(TrustedImm32 imm, RegisterID dest) 227 { 228 m_assembler.eors_r(dest, dest, m_assembler.getImm(imm.m_value, ARMRegisters::S0)); 229 } 230 231 void countLeadingZeros32(RegisterID src, RegisterID dest) 232 { 233#if WTF_ARM_ARCH_AT_LEAST(5) 234 m_assembler.clz_r(dest, src); 235#else 236 UNUSED_PARAM(src); 237 UNUSED_PARAM(dest); 238 ASSERT_NOT_REACHED(); 239#endif 240 } 241 242 void load8(ImplicitAddress address, RegisterID dest) 243 { 244 m_assembler.dataTransfer32(true, dest, address.base, address.offset, true); 245 } 246 247 void load32(ImplicitAddress address, RegisterID dest) 248 { 249 m_assembler.dataTransfer32(true, dest, address.base, address.offset); 250 } 251 252 void load32(BaseIndex address, RegisterID dest) 253 { 254 m_assembler.baseIndexTransfer32(true, dest, address.base, address.index, static_cast<int>(address.scale), address.offset); 255 } 256 257#if CPU(ARMV5_OR_LOWER) 258 void load32WithUnalignedHalfWords(BaseIndex address, RegisterID dest); 259#else 260 void load32WithUnalignedHalfWords(BaseIndex address, RegisterID dest) 261 { 262 load32(address, dest); 263 } 264#endif 265 266 DataLabel32 load32WithAddressOffsetPatch(Address address, RegisterID dest) 267 { 268 DataLabel32 dataLabel(this); 269 m_assembler.ldr_un_imm(ARMRegisters::S0, 0); 270 m_assembler.dtr_ur(true, dest, address.base, ARMRegisters::S0); 271 return dataLabel; 272 } 273 274 void load16(BaseIndex address, RegisterID dest) 275 { 276 m_assembler.add_r(ARMRegisters::S1, address.base, m_assembler.lsl(address.index, address.scale)); 277 load16(Address(ARMRegisters::S1, address.offset), dest); 278 } 279 280 void load16(ImplicitAddress address, RegisterID dest) 281 { 282 if (address.offset >= 0) 283 m_assembler.ldrh_u(dest, address.base, m_assembler.getOffsetForHalfwordDataTransfer(address.offset, ARMRegisters::S0)); 284 else 285 m_assembler.ldrh_d(dest, address.base, m_assembler.getOffsetForHalfwordDataTransfer(-address.offset, ARMRegisters::S0)); 286 } 287 288 DataLabel32 store32WithAddressOffsetPatch(RegisterID src, Address address) 289 { 290 DataLabel32 dataLabel(this); 291 m_assembler.ldr_un_imm(ARMRegisters::S0, 0); 292 m_assembler.dtr_ur(false, src, address.base, ARMRegisters::S0); 293 return dataLabel; 294 } 295 296 void store32(RegisterID src, ImplicitAddress address) 297 { 298 m_assembler.dataTransfer32(false, src, address.base, address.offset); 299 } 300 301 void store32(RegisterID src, BaseIndex address) 302 { 303 m_assembler.baseIndexTransfer32(false, src, address.base, address.index, static_cast<int>(address.scale), address.offset); 304 } 305 306 void store32(TrustedImm32 imm, ImplicitAddress address) 307 { 308 if (imm.m_isPointer) 309 m_assembler.ldr_un_imm(ARMRegisters::S1, imm.m_value); 310 else 311 move(imm, ARMRegisters::S1); 312 store32(ARMRegisters::S1, address); 313 } 314 315 void store32(RegisterID src, void* address) 316 { 317 m_assembler.ldr_un_imm(ARMRegisters::S0, reinterpret_cast<ARMWord>(address)); 318 m_assembler.dtr_u(false, src, ARMRegisters::S0, 0); 319 } 320 321 void store32(TrustedImm32 imm, void* address) 322 { 323 m_assembler.ldr_un_imm(ARMRegisters::S0, reinterpret_cast<ARMWord>(address)); 324 if (imm.m_isPointer) 325 m_assembler.ldr_un_imm(ARMRegisters::S1, imm.m_value); 326 else 327 m_assembler.moveImm(imm.m_value, ARMRegisters::S1); 328 m_assembler.dtr_u(false, ARMRegisters::S1, ARMRegisters::S0, 0); 329 } 330 331 void pop(RegisterID dest) 332 { 333 m_assembler.pop_r(dest); 334 } 335 336 void push(RegisterID src) 337 { 338 m_assembler.push_r(src); 339 } 340 341 void push(Address address) 342 { 343 load32(address, ARMRegisters::S1); 344 push(ARMRegisters::S1); 345 } 346 347 void push(TrustedImm32 imm) 348 { 349 move(imm, ARMRegisters::S0); 350 push(ARMRegisters::S0); 351 } 352 353 void move(TrustedImm32 imm, RegisterID dest) 354 { 355 if (imm.m_isPointer) 356 m_assembler.ldr_un_imm(dest, imm.m_value); 357 else 358 m_assembler.moveImm(imm.m_value, dest); 359 } 360 361 void move(RegisterID src, RegisterID dest) 362 { 363 m_assembler.mov_r(dest, src); 364 } 365 366 void move(TrustedImmPtr imm, RegisterID dest) 367 { 368 move(TrustedImm32(imm), dest); 369 } 370 371 void swap(RegisterID reg1, RegisterID reg2) 372 { 373 m_assembler.mov_r(ARMRegisters::S0, reg1); 374 m_assembler.mov_r(reg1, reg2); 375 m_assembler.mov_r(reg2, ARMRegisters::S0); 376 } 377 378 void signExtend32ToPtr(RegisterID src, RegisterID dest) 379 { 380 if (src != dest) 381 move(src, dest); 382 } 383 384 void zeroExtend32ToPtr(RegisterID src, RegisterID dest) 385 { 386 if (src != dest) 387 move(src, dest); 388 } 389 390 Jump branch8(Condition cond, Address left, TrustedImm32 right) 391 { 392 load8(left, ARMRegisters::S1); 393 return branch32(cond, ARMRegisters::S1, right); 394 } 395 396 Jump branch32(Condition cond, RegisterID left, RegisterID right, int useConstantPool = 0) 397 { 398 m_assembler.cmp_r(left, right); 399 return Jump(m_assembler.jmp(ARMCondition(cond), useConstantPool)); 400 } 401 402 Jump branch32(Condition cond, RegisterID left, TrustedImm32 right, int useConstantPool = 0) 403 { 404 if (right.m_isPointer) { 405 m_assembler.ldr_un_imm(ARMRegisters::S0, right.m_value); 406 m_assembler.cmp_r(left, ARMRegisters::S0); 407 } else { 408 ARMWord tmp = m_assembler.getOp2(-right.m_value); 409 if (tmp != ARMAssembler::INVALID_IMM) 410 m_assembler.cmn_r(left, tmp); 411 else 412 m_assembler.cmp_r(left, m_assembler.getImm(right.m_value, ARMRegisters::S0)); 413 } 414 return Jump(m_assembler.jmp(ARMCondition(cond), useConstantPool)); 415 } 416 417 Jump branch32(Condition cond, RegisterID left, Address right) 418 { 419 load32(right, ARMRegisters::S1); 420 return branch32(cond, left, ARMRegisters::S1); 421 } 422 423 Jump branch32(Condition cond, Address left, RegisterID right) 424 { 425 load32(left, ARMRegisters::S1); 426 return branch32(cond, ARMRegisters::S1, right); 427 } 428 429 Jump branch32(Condition cond, Address left, TrustedImm32 right) 430 { 431 load32(left, ARMRegisters::S1); 432 return branch32(cond, ARMRegisters::S1, right); 433 } 434 435 Jump branch32(Condition cond, BaseIndex left, TrustedImm32 right) 436 { 437 load32(left, ARMRegisters::S1); 438 return branch32(cond, ARMRegisters::S1, right); 439 } 440 441 Jump branch32WithUnalignedHalfWords(Condition cond, BaseIndex left, TrustedImm32 right) 442 { 443 load32WithUnalignedHalfWords(left, ARMRegisters::S1); 444 return branch32(cond, ARMRegisters::S1, right); 445 } 446 447 Jump branch16(Condition cond, BaseIndex left, RegisterID right) 448 { 449 UNUSED_PARAM(cond); 450 UNUSED_PARAM(left); 451 UNUSED_PARAM(right); 452 ASSERT_NOT_REACHED(); 453 return jump(); 454 } 455 456 Jump branch16(Condition cond, BaseIndex left, TrustedImm32 right) 457 { 458 load16(left, ARMRegisters::S0); 459 move(right, ARMRegisters::S1); 460 m_assembler.cmp_r(ARMRegisters::S0, ARMRegisters::S1); 461 return m_assembler.jmp(ARMCondition(cond)); 462 } 463 464 Jump branchTest8(Condition cond, Address address, TrustedImm32 mask = TrustedImm32(-1)) 465 { 466 load8(address, ARMRegisters::S1); 467 return branchTest32(cond, ARMRegisters::S1, mask); 468 } 469 470 Jump branchTest32(Condition cond, RegisterID reg, RegisterID mask) 471 { 472 ASSERT((cond == Zero) || (cond == NonZero)); 473 m_assembler.tst_r(reg, mask); 474 return Jump(m_assembler.jmp(ARMCondition(cond))); 475 } 476 477 Jump branchTest32(Condition cond, RegisterID reg, TrustedImm32 mask = TrustedImm32(-1)) 478 { 479 ASSERT((cond == Zero) || (cond == NonZero)); 480 ARMWord w = m_assembler.getImm(mask.m_value, ARMRegisters::S0, true); 481 if (w & ARMAssembler::OP2_INV_IMM) 482 m_assembler.bics_r(ARMRegisters::S0, reg, w & ~ARMAssembler::OP2_INV_IMM); 483 else 484 m_assembler.tst_r(reg, w); 485 return Jump(m_assembler.jmp(ARMCondition(cond))); 486 } 487 488 Jump branchTest32(Condition cond, Address address, TrustedImm32 mask = TrustedImm32(-1)) 489 { 490 load32(address, ARMRegisters::S1); 491 return branchTest32(cond, ARMRegisters::S1, mask); 492 } 493 494 Jump branchTest32(Condition cond, BaseIndex address, TrustedImm32 mask = TrustedImm32(-1)) 495 { 496 load32(address, ARMRegisters::S1); 497 return branchTest32(cond, ARMRegisters::S1, mask); 498 } 499 500 Jump jump() 501 { 502 return Jump(m_assembler.jmp()); 503 } 504 505 void jump(RegisterID target) 506 { 507 m_assembler.bx(target); 508 } 509 510 void jump(Address address) 511 { 512 load32(address, ARMRegisters::pc); 513 } 514 515 Jump branchAdd32(Condition cond, RegisterID src, RegisterID dest) 516 { 517 ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); 518 add32(src, dest); 519 return Jump(m_assembler.jmp(ARMCondition(cond))); 520 } 521 522 Jump branchAdd32(Condition cond, TrustedImm32 imm, RegisterID dest) 523 { 524 ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); 525 add32(imm, dest); 526 return Jump(m_assembler.jmp(ARMCondition(cond))); 527 } 528 529 void mull32(RegisterID src1, RegisterID src2, RegisterID dest) 530 { 531 if (src1 == dest) { 532 move(src1, ARMRegisters::S0); 533 src1 = ARMRegisters::S0; 534 } 535 m_assembler.mull_r(ARMRegisters::S1, dest, src2, src1); 536 m_assembler.cmp_r(ARMRegisters::S1, m_assembler.asr(dest, 31)); 537 } 538 539 Jump branchMul32(Condition cond, RegisterID src, RegisterID dest) 540 { 541 ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); 542 if (cond == Overflow) { 543 mull32(src, dest, dest); 544 cond = NonZero; 545 } 546 else 547 mul32(src, dest); 548 return Jump(m_assembler.jmp(ARMCondition(cond))); 549 } 550 551 Jump branchMul32(Condition cond, TrustedImm32 imm, RegisterID src, RegisterID dest) 552 { 553 ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); 554 if (cond == Overflow) { 555 move(imm, ARMRegisters::S0); 556 mull32(ARMRegisters::S0, src, dest); 557 cond = NonZero; 558 } 559 else 560 mul32(imm, src, dest); 561 return Jump(m_assembler.jmp(ARMCondition(cond))); 562 } 563 564 Jump branchSub32(Condition cond, RegisterID src, RegisterID dest) 565 { 566 ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); 567 sub32(src, dest); 568 return Jump(m_assembler.jmp(ARMCondition(cond))); 569 } 570 571 Jump branchSub32(Condition cond, TrustedImm32 imm, RegisterID dest) 572 { 573 ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); 574 sub32(imm, dest); 575 return Jump(m_assembler.jmp(ARMCondition(cond))); 576 } 577 578 Jump branchNeg32(Condition cond, RegisterID srcDest) 579 { 580 ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); 581 neg32(srcDest); 582 return Jump(m_assembler.jmp(ARMCondition(cond))); 583 } 584 585 Jump branchOr32(Condition cond, RegisterID src, RegisterID dest) 586 { 587 ASSERT((cond == Signed) || (cond == Zero) || (cond == NonZero)); 588 or32(src, dest); 589 return Jump(m_assembler.jmp(ARMCondition(cond))); 590 } 591 592 void breakpoint() 593 { 594 m_assembler.bkpt(0); 595 } 596 597 Call nearCall() 598 { 599#if WTF_ARM_ARCH_AT_LEAST(5) 600 ensureSpace(2 * sizeof(ARMWord), sizeof(ARMWord)); 601 m_assembler.loadBranchTarget(ARMRegisters::S1, ARMAssembler::AL, true); 602 return Call(m_assembler.blx(ARMRegisters::S1), Call::LinkableNear); 603#else 604 prepareCall(); 605 return Call(m_assembler.jmp(ARMAssembler::AL, true), Call::LinkableNear); 606#endif 607 } 608 609 Call call(RegisterID target) 610 { 611 return Call(m_assembler.blx(target), Call::None); 612 } 613 614 void call(Address address) 615 { 616 call32(address.base, address.offset); 617 } 618 619 void ret() 620 { 621 m_assembler.bx(linkRegister); 622 } 623 624 void set32Compare32(Condition cond, RegisterID left, RegisterID right, RegisterID dest) 625 { 626 m_assembler.cmp_r(left, right); 627 m_assembler.mov_r(dest, ARMAssembler::getOp2(0)); 628 m_assembler.mov_r(dest, ARMAssembler::getOp2(1), ARMCondition(cond)); 629 } 630 631 void set32Compare32(Condition cond, RegisterID left, TrustedImm32 right, RegisterID dest) 632 { 633 m_assembler.cmp_r(left, m_assembler.getImm(right.m_value, ARMRegisters::S0)); 634 m_assembler.mov_r(dest, ARMAssembler::getOp2(0)); 635 m_assembler.mov_r(dest, ARMAssembler::getOp2(1), ARMCondition(cond)); 636 } 637 638 void set8Compare32(Condition cond, RegisterID left, RegisterID right, RegisterID dest) 639 { 640 // ARM doesn't have byte registers 641 set32Compare32(cond, left, right, dest); 642 } 643 644 void set8Compare32(Condition cond, Address left, RegisterID right, RegisterID dest) 645 { 646 // ARM doesn't have byte registers 647 load32(left, ARMRegisters::S1); 648 set32Compare32(cond, ARMRegisters::S1, right, dest); 649 } 650 651 void set8Compare32(Condition cond, RegisterID left, TrustedImm32 right, RegisterID dest) 652 { 653 // ARM doesn't have byte registers 654 set32Compare32(cond, left, right, dest); 655 } 656 657 void set32Test32(Condition cond, RegisterID reg, TrustedImm32 mask, RegisterID dest) 658 { 659 if (mask.m_value == -1) 660 m_assembler.cmp_r(0, reg); 661 else 662 m_assembler.tst_r(reg, m_assembler.getImm(mask.m_value, ARMRegisters::S0)); 663 m_assembler.mov_r(dest, ARMAssembler::getOp2(0)); 664 m_assembler.mov_r(dest, ARMAssembler::getOp2(1), ARMCondition(cond)); 665 } 666 667 void set32Test32(Condition cond, Address address, TrustedImm32 mask, RegisterID dest) 668 { 669 load32(address, ARMRegisters::S1); 670 set32Test32(cond, ARMRegisters::S1, mask, dest); 671 } 672 673 void set32Test8(Condition cond, Address address, TrustedImm32 mask, RegisterID dest) 674 { 675 load8(address, ARMRegisters::S1); 676 set32Test32(cond, ARMRegisters::S1, mask, dest); 677 } 678 679 void add32(TrustedImm32 imm, RegisterID src, RegisterID dest) 680 { 681 m_assembler.add_r(dest, src, m_assembler.getImm(imm.m_value, ARMRegisters::S0)); 682 } 683 684 void add32(TrustedImm32 imm, AbsoluteAddress address) 685 { 686 m_assembler.ldr_un_imm(ARMRegisters::S1, reinterpret_cast<ARMWord>(address.m_ptr)); 687 m_assembler.dtr_u(true, ARMRegisters::S1, ARMRegisters::S1, 0); 688 add32(imm, ARMRegisters::S1); 689 m_assembler.ldr_un_imm(ARMRegisters::S0, reinterpret_cast<ARMWord>(address.m_ptr)); 690 m_assembler.dtr_u(false, ARMRegisters::S1, ARMRegisters::S0, 0); 691 } 692 693 void sub32(TrustedImm32 imm, AbsoluteAddress address) 694 { 695 m_assembler.ldr_un_imm(ARMRegisters::S1, reinterpret_cast<ARMWord>(address.m_ptr)); 696 m_assembler.dtr_u(true, ARMRegisters::S1, ARMRegisters::S1, 0); 697 sub32(imm, ARMRegisters::S1); 698 m_assembler.ldr_un_imm(ARMRegisters::S0, reinterpret_cast<ARMWord>(address.m_ptr)); 699 m_assembler.dtr_u(false, ARMRegisters::S1, ARMRegisters::S0, 0); 700 } 701 702 void load32(const void* address, RegisterID dest) 703 { 704 m_assembler.ldr_un_imm(ARMRegisters::S0, reinterpret_cast<ARMWord>(address)); 705 m_assembler.dtr_u(true, dest, ARMRegisters::S0, 0); 706 } 707 708 Jump branch32(Condition cond, AbsoluteAddress left, RegisterID right) 709 { 710 load32(left.m_ptr, ARMRegisters::S1); 711 return branch32(cond, ARMRegisters::S1, right); 712 } 713 714 Jump branch32(Condition cond, AbsoluteAddress left, TrustedImm32 right) 715 { 716 load32(left.m_ptr, ARMRegisters::S1); 717 return branch32(cond, ARMRegisters::S1, right); 718 } 719 720 void relativeTableJump(RegisterID index, int scale) 721 { 722 ASSERT(scale >= 0 && scale <= 31); 723 m_assembler.add_r(ARMRegisters::pc, ARMRegisters::pc, m_assembler.lsl(index, scale)); 724 725 // NOP the default prefetching 726 m_assembler.mov_r(ARMRegisters::r0, ARMRegisters::r0); 727 } 728 729 Call call() 730 { 731#if WTF_ARM_ARCH_AT_LEAST(5) 732 ensureSpace(2 * sizeof(ARMWord), sizeof(ARMWord)); 733 m_assembler.loadBranchTarget(ARMRegisters::S1, ARMAssembler::AL, true); 734 return Call(m_assembler.blx(ARMRegisters::S1), Call::Linkable); 735#else 736 prepareCall(); 737 return Call(m_assembler.jmp(ARMAssembler::AL, true), Call::Linkable); 738#endif 739 } 740 741 Call tailRecursiveCall() 742 { 743 return Call::fromTailJump(jump()); 744 } 745 746 Call makeTailRecursiveCall(Jump oldJump) 747 { 748 return Call::fromTailJump(oldJump); 749 } 750 751 DataLabelPtr moveWithPatch(TrustedImmPtr initialValue, RegisterID dest) 752 { 753 DataLabelPtr dataLabel(this); 754 m_assembler.ldr_un_imm(dest, reinterpret_cast<ARMWord>(initialValue.m_value)); 755 return dataLabel; 756 } 757 758 Jump branchPtrWithPatch(Condition cond, RegisterID left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0)) 759 { 760 dataLabel = moveWithPatch(initialRightValue, ARMRegisters::S1); 761 Jump jump = branch32(cond, left, ARMRegisters::S1, true); 762 return jump; 763 } 764 765 Jump branchPtrWithPatch(Condition cond, Address left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0)) 766 { 767 load32(left, ARMRegisters::S1); 768 dataLabel = moveWithPatch(initialRightValue, ARMRegisters::S0); 769 Jump jump = branch32(cond, ARMRegisters::S0, ARMRegisters::S1, true); 770 return jump; 771 } 772 773 DataLabelPtr storePtrWithPatch(TrustedImmPtr initialValue, ImplicitAddress address) 774 { 775 DataLabelPtr dataLabel = moveWithPatch(initialValue, ARMRegisters::S1); 776 store32(ARMRegisters::S1, address); 777 return dataLabel; 778 } 779 780 DataLabelPtr storePtrWithPatch(ImplicitAddress address) 781 { 782 return storePtrWithPatch(TrustedImmPtr(0), address); 783 } 784 785 // Floating point operators 786 bool supportsFloatingPoint() const 787 { 788 return s_isVFPPresent; 789 } 790 791 bool supportsFloatingPointTruncate() const 792 { 793 return s_isVFPPresent; 794 } 795 796 bool supportsFloatingPointSqrt() const 797 { 798 return s_isVFPPresent; 799 } 800 801 void loadDouble(ImplicitAddress address, FPRegisterID dest) 802 { 803 m_assembler.doubleTransfer(true, dest, address.base, address.offset); 804 } 805 806 void loadDouble(const void* address, FPRegisterID dest) 807 { 808 m_assembler.ldr_un_imm(ARMRegisters::S0, (ARMWord)address); 809 m_assembler.fdtr_u(true, dest, ARMRegisters::S0, 0); 810 } 811 812 void storeDouble(FPRegisterID src, ImplicitAddress address) 813 { 814 m_assembler.doubleTransfer(false, src, address.base, address.offset); 815 } 816 817 void addDouble(FPRegisterID src, FPRegisterID dest) 818 { 819 m_assembler.vadd_f64_r(dest, dest, src); 820 } 821 822 void addDouble(Address src, FPRegisterID dest) 823 { 824 loadDouble(src, ARMRegisters::SD0); 825 addDouble(ARMRegisters::SD0, dest); 826 } 827 828 void divDouble(FPRegisterID src, FPRegisterID dest) 829 { 830 m_assembler.vdiv_f64_r(dest, dest, src); 831 } 832 833 void divDouble(Address src, FPRegisterID dest) 834 { 835 ASSERT_NOT_REACHED(); // Untested 836 loadDouble(src, ARMRegisters::SD0); 837 divDouble(ARMRegisters::SD0, dest); 838 } 839 840 void subDouble(FPRegisterID src, FPRegisterID dest) 841 { 842 m_assembler.vsub_f64_r(dest, dest, src); 843 } 844 845 void subDouble(Address src, FPRegisterID dest) 846 { 847 loadDouble(src, ARMRegisters::SD0); 848 subDouble(ARMRegisters::SD0, dest); 849 } 850 851 void mulDouble(FPRegisterID src, FPRegisterID dest) 852 { 853 m_assembler.vmul_f64_r(dest, dest, src); 854 } 855 856 void mulDouble(Address src, FPRegisterID dest) 857 { 858 loadDouble(src, ARMRegisters::SD0); 859 mulDouble(ARMRegisters::SD0, dest); 860 } 861 862 void sqrtDouble(FPRegisterID src, FPRegisterID dest) 863 { 864 m_assembler.vsqrt_f64_r(dest, src); 865 } 866 867 void convertInt32ToDouble(RegisterID src, FPRegisterID dest) 868 { 869 m_assembler.vmov_vfp_r(dest << 1, src); 870 m_assembler.vcvt_f64_s32_r(dest, dest << 1); 871 } 872 873 void convertInt32ToDouble(Address src, FPRegisterID dest) 874 { 875 ASSERT_NOT_REACHED(); // Untested 876 // flds does not worth the effort here 877 load32(src, ARMRegisters::S1); 878 convertInt32ToDouble(ARMRegisters::S1, dest); 879 } 880 881 void convertInt32ToDouble(AbsoluteAddress src, FPRegisterID dest) 882 { 883 ASSERT_NOT_REACHED(); // Untested 884 // flds does not worth the effort here 885 m_assembler.ldr_un_imm(ARMRegisters::S1, (ARMWord)src.m_ptr); 886 m_assembler.dtr_u(true, ARMRegisters::S1, ARMRegisters::S1, 0); 887 convertInt32ToDouble(ARMRegisters::S1, dest); 888 } 889 890 Jump branchDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right) 891 { 892 m_assembler.vcmp_f64_r(left, right); 893 m_assembler.vmrs_apsr(); 894 if (cond & DoubleConditionBitSpecial) 895 m_assembler.cmp_r(ARMRegisters::S0, ARMRegisters::S0, ARMAssembler::VS); 896 return Jump(m_assembler.jmp(static_cast<ARMAssembler::Condition>(cond & ~DoubleConditionMask))); 897 } 898 899 // Truncates 'src' to an integer, and places the resulting 'dest'. 900 // If the result is not representable as a 32 bit value, branch. 901 // May also branch for some values that are representable in 32 bits 902 // (specifically, in this case, INT_MIN and INT_MAX). 903 Jump branchTruncateDoubleToInt32(FPRegisterID src, RegisterID dest) 904 { 905 m_assembler.vcvtr_s32_f64_r(ARMRegisters::SD0 << 1, src); 906 // If VCVTR.S32.F64 can't fit the result into a 32-bit 907 // integer, it saturates at INT_MAX or INT_MIN. Testing this is 908 // probably quicker than testing FPSCR for exception. 909 m_assembler.vmov_arm_r(dest, ARMRegisters::SD0 << 1); 910 m_assembler.sub_r(ARMRegisters::S0, dest, ARMAssembler::getOp2(0x80000000)); 911 m_assembler.cmn_r(ARMRegisters::S0, ARMAssembler::getOp2(1), ARMCondition(NotEqual)); 912 return Jump(m_assembler.jmp(ARMCondition(Equal))); 913 } 914 915 // Convert 'src' to an integer, and places the resulting 'dest'. 916 // If the result is not representable as a 32 bit value, branch. 917 // May also branch for some values that are representable in 32 bits 918 // (specifically, in this case, 0). 919 void branchConvertDoubleToInt32(FPRegisterID src, RegisterID dest, JumpList& failureCases, FPRegisterID fpTemp) 920 { 921 m_assembler.vcvt_s32_f64_r(ARMRegisters::SD0 << 1, src); 922 m_assembler.vmov_arm_r(dest, ARMRegisters::SD0 << 1); 923 924 // Convert the integer result back to float & compare to the original value - if not equal or unordered (NaN) then jump. 925 m_assembler.vcvt_f64_s32_r(ARMRegisters::SD0, ARMRegisters::SD0 << 1); 926 failureCases.append(branchDouble(DoubleNotEqualOrUnordered, src, ARMRegisters::SD0)); 927 928 // If the result is zero, it might have been -0.0, and 0.0 equals to -0.0 929 failureCases.append(branchTest32(Zero, dest)); 930 } 931 932 Jump branchDoubleNonZero(FPRegisterID reg, FPRegisterID scratch) 933 { 934 m_assembler.mov_r(ARMRegisters::S0, ARMAssembler::getOp2(0)); 935 convertInt32ToDouble(ARMRegisters::S0, scratch); 936 return branchDouble(DoubleNotEqual, reg, scratch); 937 } 938 939 Jump branchDoubleZeroOrNaN(FPRegisterID reg, FPRegisterID scratch) 940 { 941 m_assembler.mov_r(ARMRegisters::S0, ARMAssembler::getOp2(0)); 942 convertInt32ToDouble(ARMRegisters::S0, scratch); 943 return branchDouble(DoubleEqualOrUnordered, reg, scratch); 944 } 945 946protected: 947 ARMAssembler::Condition ARMCondition(Condition cond) 948 { 949 return static_cast<ARMAssembler::Condition>(cond); 950 } 951 952 void ensureSpace(int insnSpace, int constSpace) 953 { 954 m_assembler.ensureSpace(insnSpace, constSpace); 955 } 956 957 int sizeOfConstantPool() 958 { 959 return m_assembler.sizeOfConstantPool(); 960 } 961 962 void prepareCall() 963 { 964#if WTF_ARM_ARCH_VERSION < 5 965 ensureSpace(2 * sizeof(ARMWord), sizeof(ARMWord)); 966 967 m_assembler.mov_r(linkRegister, ARMRegisters::pc); 968#endif 969 } 970 971 void call32(RegisterID base, int32_t offset) 972 { 973#if WTF_ARM_ARCH_AT_LEAST(5) 974 int targetReg = ARMRegisters::S1; 975#else 976 int targetReg = ARMRegisters::pc; 977#endif 978 int tmpReg = ARMRegisters::S1; 979 980 if (base == ARMRegisters::sp) 981 offset += 4; 982 983 if (offset >= 0) { 984 if (offset <= 0xfff) { 985 prepareCall(); 986 m_assembler.dtr_u(true, targetReg, base, offset); 987 } else if (offset <= 0xfffff) { 988 m_assembler.add_r(tmpReg, base, ARMAssembler::OP2_IMM | (offset >> 12) | (10 << 8)); 989 prepareCall(); 990 m_assembler.dtr_u(true, targetReg, tmpReg, offset & 0xfff); 991 } else { 992 m_assembler.moveImm(offset, tmpReg); 993 prepareCall(); 994 m_assembler.dtr_ur(true, targetReg, base, tmpReg); 995 } 996 } else { 997 offset = -offset; 998 if (offset <= 0xfff) { 999 prepareCall(); 1000 m_assembler.dtr_d(true, targetReg, base, offset); 1001 } else if (offset <= 0xfffff) { 1002 m_assembler.sub_r(tmpReg, base, ARMAssembler::OP2_IMM | (offset >> 12) | (10 << 8)); 1003 prepareCall(); 1004 m_assembler.dtr_d(true, targetReg, tmpReg, offset & 0xfff); 1005 } else { 1006 m_assembler.moveImm(offset, tmpReg); 1007 prepareCall(); 1008 m_assembler.dtr_dr(true, targetReg, base, tmpReg); 1009 } 1010 } 1011#if WTF_ARM_ARCH_AT_LEAST(5) 1012 m_assembler.blx(targetReg); 1013#endif 1014 } 1015 1016private: 1017 friend class LinkBuffer; 1018 friend class RepatchBuffer; 1019 1020 static void linkCall(void* code, Call call, FunctionPtr function) 1021 { 1022 ARMAssembler::linkCall(code, call.m_jmp, function.value()); 1023 } 1024 1025 static void repatchCall(CodeLocationCall call, CodeLocationLabel destination) 1026 { 1027 ARMAssembler::relinkCall(call.dataLocation(), destination.executableAddress()); 1028 } 1029 1030 static void repatchCall(CodeLocationCall call, FunctionPtr destination) 1031 { 1032 ARMAssembler::relinkCall(call.dataLocation(), destination.executableAddress()); 1033 } 1034 1035 static const bool s_isVFPPresent; 1036}; 1037 1038} 1039 1040#endif // ENABLE(ASSEMBLER) && CPU(ARM_TRADITIONAL) 1041 1042#endif // MacroAssemblerARM_h 1043