1 /* 2 * Copyright (C) 2008 Apple Inc. 3 * Copyright (C) 2009 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 #include <wtf/Platform.h> 32 33 #if ENABLE(ASSEMBLER) && PLATFORM(ARM) 34 35 #include "ARMAssembler.h" 36 #include "AbstractMacroAssembler.h" 37 38 namespace JSC { 39 40 class MacroAssemblerARM : public AbstractMacroAssembler<ARMAssembler> { 41 public: 42 enum Condition { 43 Equal = ARMAssembler::EQ, 44 NotEqual = ARMAssembler::NE, 45 Above = ARMAssembler::HI, 46 AboveOrEqual = ARMAssembler::CS, 47 Below = ARMAssembler::CC, 48 BelowOrEqual = ARMAssembler::LS, 49 GreaterThan = ARMAssembler::GT, 50 GreaterThanOrEqual = ARMAssembler::GE, 51 LessThan = ARMAssembler::LT, 52 LessThanOrEqual = ARMAssembler::LE, 53 Overflow = ARMAssembler::VS, 54 Signed = ARMAssembler::MI, 55 Zero = ARMAssembler::EQ, 56 NonZero = ARMAssembler::NE 57 }; 58 59 enum DoubleCondition { 60 DoubleEqual = ARMAssembler::EQ, 61 DoubleGreaterThan = ARMAssembler::GT, 62 DoubleGreaterThanOrEqual = ARMAssembler::GE, 63 DoubleLessThan = ARMAssembler::LT, 64 DoubleLessThanOrEqual = ARMAssembler::LE, 65 }; 66 67 static const RegisterID stackPointerRegister = ARM::sp; 68 69 static const Scale ScalePtr = TimesFour; 70 add32(RegisterID src,RegisterID dest)71 void add32(RegisterID src, RegisterID dest) 72 { 73 m_assembler.adds_r(dest, dest, src); 74 } 75 add32(Imm32 imm,Address address)76 void add32(Imm32 imm, Address address) 77 { 78 load32(address, ARM::S1); 79 add32(imm, ARM::S1); 80 store32(ARM::S1, address); 81 } 82 add32(Imm32 imm,RegisterID dest)83 void add32(Imm32 imm, RegisterID dest) 84 { 85 m_assembler.adds_r(dest, dest, m_assembler.getImm(imm.m_value, ARM::S0)); 86 } 87 add32(Address src,RegisterID dest)88 void add32(Address src, RegisterID dest) 89 { 90 load32(src, ARM::S1); 91 add32(ARM::S1, dest); 92 } 93 and32(RegisterID src,RegisterID dest)94 void and32(RegisterID src, RegisterID dest) 95 { 96 m_assembler.ands_r(dest, dest, src); 97 } 98 and32(Imm32 imm,RegisterID dest)99 void and32(Imm32 imm, RegisterID dest) 100 { 101 ARMWord w = m_assembler.getImm(imm.m_value, ARM::S0, true); 102 if (w & ARMAssembler::OP2_INV_IMM) 103 m_assembler.bics_r(dest, dest, w & ~ARMAssembler::OP2_INV_IMM); 104 else 105 m_assembler.ands_r(dest, dest, w); 106 } 107 lshift32(Imm32 imm,RegisterID dest)108 void lshift32(Imm32 imm, RegisterID dest) 109 { 110 m_assembler.movs_r(dest, m_assembler.lsl(dest, imm.m_value & 0x1f)); 111 } 112 lshift32(RegisterID shift_amount,RegisterID dest)113 void lshift32(RegisterID shift_amount, RegisterID dest) 114 { 115 m_assembler.movs_r(dest, m_assembler.lsl_r(dest, shift_amount)); 116 } 117 mul32(RegisterID src,RegisterID dest)118 void mul32(RegisterID src, RegisterID dest) 119 { 120 if (src == dest) { 121 move(src, ARM::S0); 122 src = ARM::S0; 123 } 124 m_assembler.muls_r(dest, dest, src); 125 } 126 mul32(Imm32 imm,RegisterID src,RegisterID dest)127 void mul32(Imm32 imm, RegisterID src, RegisterID dest) 128 { 129 move(imm, ARM::S0); 130 m_assembler.muls_r(dest, src, ARM::S0); 131 } 132 not32(RegisterID dest)133 void not32(RegisterID dest) 134 { 135 m_assembler.mvns_r(dest, dest); 136 } 137 or32(RegisterID src,RegisterID dest)138 void or32(RegisterID src, RegisterID dest) 139 { 140 m_assembler.orrs_r(dest, dest, src); 141 } 142 or32(Imm32 imm,RegisterID dest)143 void or32(Imm32 imm, RegisterID dest) 144 { 145 m_assembler.orrs_r(dest, dest, m_assembler.getImm(imm.m_value, ARM::S0)); 146 } 147 rshift32(RegisterID shift_amount,RegisterID dest)148 void rshift32(RegisterID shift_amount, RegisterID dest) 149 { 150 m_assembler.movs_r(dest, m_assembler.asr_r(dest, shift_amount)); 151 } 152 rshift32(Imm32 imm,RegisterID dest)153 void rshift32(Imm32 imm, RegisterID dest) 154 { 155 m_assembler.movs_r(dest, m_assembler.asr(dest, imm.m_value & 0x1f)); 156 } 157 sub32(RegisterID src,RegisterID dest)158 void sub32(RegisterID src, RegisterID dest) 159 { 160 m_assembler.subs_r(dest, dest, src); 161 } 162 sub32(Imm32 imm,RegisterID dest)163 void sub32(Imm32 imm, RegisterID dest) 164 { 165 m_assembler.subs_r(dest, dest, m_assembler.getImm(imm.m_value, ARM::S0)); 166 } 167 sub32(Imm32 imm,Address address)168 void sub32(Imm32 imm, Address address) 169 { 170 load32(address, ARM::S1); 171 sub32(imm, ARM::S1); 172 store32(ARM::S1, address); 173 } 174 sub32(Address src,RegisterID dest)175 void sub32(Address src, RegisterID dest) 176 { 177 load32(src, ARM::S1); 178 sub32(ARM::S1, dest); 179 } 180 xor32(RegisterID src,RegisterID dest)181 void xor32(RegisterID src, RegisterID dest) 182 { 183 m_assembler.eors_r(dest, dest, src); 184 } 185 xor32(Imm32 imm,RegisterID dest)186 void xor32(Imm32 imm, RegisterID dest) 187 { 188 m_assembler.eors_r(dest, dest, m_assembler.getImm(imm.m_value, ARM::S0)); 189 } 190 load32(ImplicitAddress address,RegisterID dest)191 void load32(ImplicitAddress address, RegisterID dest) 192 { 193 m_assembler.dataTransfer32(true, dest, address.base, address.offset); 194 } 195 load32(BaseIndex address,RegisterID dest)196 void load32(BaseIndex address, RegisterID dest) 197 { 198 m_assembler.baseIndexTransfer32(true, dest, address.base, address.index, static_cast<int>(address.scale), address.offset); 199 } 200 load32WithAddressOffsetPatch(Address address,RegisterID dest)201 DataLabel32 load32WithAddressOffsetPatch(Address address, RegisterID dest) 202 { 203 DataLabel32 dataLabel(this); 204 m_assembler.ldr_un_imm(ARM::S0, 0); 205 m_assembler.dtr_ur(true, dest, address.base, ARM::S0); 206 return dataLabel; 207 } 208 loadPtrWithPatchToLEA(Address address,RegisterID dest)209 Label loadPtrWithPatchToLEA(Address address, RegisterID dest) 210 { 211 Label label(this); 212 load32(address, dest); 213 return label; 214 } 215 load16(BaseIndex address,RegisterID dest)216 void load16(BaseIndex address, RegisterID dest) 217 { 218 m_assembler.add_r(ARM::S0, address.base, m_assembler.lsl(address.index, address.scale)); 219 if (address.offset>=0) 220 m_assembler.ldrh_u(dest, ARM::S0, ARMAssembler::getOp2Byte(address.offset)); 221 else 222 m_assembler.ldrh_d(dest, ARM::S0, ARMAssembler::getOp2Byte(-address.offset)); 223 } 224 store32WithAddressOffsetPatch(RegisterID src,Address address)225 DataLabel32 store32WithAddressOffsetPatch(RegisterID src, Address address) 226 { 227 DataLabel32 dataLabel(this); 228 m_assembler.ldr_un_imm(ARM::S0, 0); 229 m_assembler.dtr_ur(false, src, address.base, ARM::S0); 230 return dataLabel; 231 } 232 store32(RegisterID src,ImplicitAddress address)233 void store32(RegisterID src, ImplicitAddress address) 234 { 235 m_assembler.dataTransfer32(false, src, address.base, address.offset); 236 } 237 store32(RegisterID src,BaseIndex address)238 void store32(RegisterID src, BaseIndex address) 239 { 240 m_assembler.baseIndexTransfer32(false, src, address.base, address.index, static_cast<int>(address.scale), address.offset); 241 } 242 store32(Imm32 imm,ImplicitAddress address)243 void store32(Imm32 imm, ImplicitAddress address) 244 { 245 if (imm.m_isPointer) 246 m_assembler.ldr_un_imm(ARM::S1, imm.m_value); 247 else 248 move(imm, ARM::S1); 249 store32(ARM::S1, address); 250 } 251 store32(RegisterID src,void * address)252 void store32(RegisterID src, void* address) 253 { 254 m_assembler.ldr_un_imm(ARM::S0, reinterpret_cast<ARMWord>(address)); 255 m_assembler.dtr_u(false, src, ARM::S0, 0); 256 } 257 store32(Imm32 imm,void * address)258 void store32(Imm32 imm, void* address) 259 { 260 m_assembler.ldr_un_imm(ARM::S0, reinterpret_cast<ARMWord>(address)); 261 if (imm.m_isPointer) 262 m_assembler.ldr_un_imm(ARM::S1, imm.m_value); 263 else 264 m_assembler.moveImm(imm.m_value, ARM::S1); 265 m_assembler.dtr_u(false, ARM::S1, ARM::S0, 0); 266 } 267 pop(RegisterID dest)268 void pop(RegisterID dest) 269 { 270 m_assembler.pop_r(dest); 271 } 272 push(RegisterID src)273 void push(RegisterID src) 274 { 275 m_assembler.push_r(src); 276 } 277 push(Address address)278 void push(Address address) 279 { 280 load32(address, ARM::S1); 281 push(ARM::S1); 282 } 283 push(Imm32 imm)284 void push(Imm32 imm) 285 { 286 move(imm, ARM::S0); 287 push(ARM::S0); 288 } 289 move(Imm32 imm,RegisterID dest)290 void move(Imm32 imm, RegisterID dest) 291 { 292 if (imm.m_isPointer) 293 m_assembler.ldr_un_imm(dest, imm.m_value); 294 else 295 m_assembler.moveImm(imm.m_value, dest); 296 } 297 move(RegisterID src,RegisterID dest)298 void move(RegisterID src, RegisterID dest) 299 { 300 m_assembler.mov_r(dest, src); 301 } 302 move(ImmPtr imm,RegisterID dest)303 void move(ImmPtr imm, RegisterID dest) 304 { 305 move(Imm32(imm), dest); 306 } 307 swap(RegisterID reg1,RegisterID reg2)308 void swap(RegisterID reg1, RegisterID reg2) 309 { 310 m_assembler.mov_r(ARM::S0, reg1); 311 m_assembler.mov_r(reg1, reg2); 312 m_assembler.mov_r(reg2, ARM::S0); 313 } 314 signExtend32ToPtr(RegisterID src,RegisterID dest)315 void signExtend32ToPtr(RegisterID src, RegisterID dest) 316 { 317 if (src != dest) 318 move(src, dest); 319 } 320 zeroExtend32ToPtr(RegisterID src,RegisterID dest)321 void zeroExtend32ToPtr(RegisterID src, RegisterID dest) 322 { 323 if (src != dest) 324 move(src, dest); 325 } 326 branch32(Condition cond,RegisterID left,RegisterID right)327 Jump branch32(Condition cond, RegisterID left, RegisterID right) 328 { 329 m_assembler.cmp_r(left, right); 330 return Jump(m_assembler.jmp(ARMCondition(cond))); 331 } 332 branch32(Condition cond,RegisterID left,Imm32 right)333 Jump branch32(Condition cond, RegisterID left, Imm32 right) 334 { 335 if (right.m_isPointer) { 336 m_assembler.ldr_un_imm(ARM::S0, right.m_value); 337 m_assembler.cmp_r(left, ARM::S0); 338 } else 339 m_assembler.cmp_r(left, m_assembler.getImm(right.m_value, ARM::S0)); 340 return Jump(m_assembler.jmp(ARMCondition(cond))); 341 } 342 branch32(Condition cond,RegisterID left,Address right)343 Jump branch32(Condition cond, RegisterID left, Address right) 344 { 345 load32(right, ARM::S1); 346 return branch32(cond, left, ARM::S1); 347 } 348 branch32(Condition cond,Address left,RegisterID right)349 Jump branch32(Condition cond, Address left, RegisterID right) 350 { 351 load32(left, ARM::S1); 352 return branch32(cond, ARM::S1, right); 353 } 354 branch32(Condition cond,Address left,Imm32 right)355 Jump branch32(Condition cond, Address left, Imm32 right) 356 { 357 load32(left, ARM::S1); 358 return branch32(cond, ARM::S1, right); 359 } 360 branch32(Condition cond,BaseIndex left,Imm32 right)361 Jump branch32(Condition cond, BaseIndex left, Imm32 right) 362 { 363 load32(left, ARM::S1); 364 return branch32(cond, ARM::S1, right); 365 } 366 branch16(Condition cond,BaseIndex left,RegisterID right)367 Jump branch16(Condition cond, BaseIndex left, RegisterID right) 368 { 369 UNUSED_PARAM(cond); 370 UNUSED_PARAM(left); 371 UNUSED_PARAM(right); 372 ASSERT_NOT_REACHED(); 373 return jump(); 374 } 375 branch16(Condition cond,BaseIndex left,Imm32 right)376 Jump branch16(Condition cond, BaseIndex left, Imm32 right) 377 { 378 load16(left, ARM::S0); 379 move(right, ARM::S1); 380 m_assembler.cmp_r(ARM::S0, ARM::S1); 381 return m_assembler.jmp(ARMCondition(cond)); 382 } 383 branchTest32(Condition cond,RegisterID reg,RegisterID mask)384 Jump branchTest32(Condition cond, RegisterID reg, RegisterID mask) 385 { 386 ASSERT((cond == Zero) || (cond == NonZero)); 387 m_assembler.tst_r(reg, mask); 388 return Jump(m_assembler.jmp(ARMCondition(cond))); 389 } 390 391 Jump branchTest32(Condition cond, RegisterID reg, Imm32 mask = Imm32(-1)) 392 { 393 ASSERT((cond == Zero) || (cond == NonZero)); 394 ARMWord w = m_assembler.getImm(mask.m_value, ARM::S0, true); 395 if (w & ARMAssembler::OP2_INV_IMM) 396 m_assembler.bics_r(ARM::S0, reg, w & ~ARMAssembler::OP2_INV_IMM); 397 else 398 m_assembler.tst_r(reg, w); 399 return Jump(m_assembler.jmp(ARMCondition(cond))); 400 } 401 402 Jump branchTest32(Condition cond, Address address, Imm32 mask = Imm32(-1)) 403 { 404 load32(address, ARM::S1); 405 return branchTest32(cond, ARM::S1, mask); 406 } 407 408 Jump branchTest32(Condition cond, BaseIndex address, Imm32 mask = Imm32(-1)) 409 { 410 load32(address, ARM::S1); 411 return branchTest32(cond, ARM::S1, mask); 412 } 413 jump()414 Jump jump() 415 { 416 return Jump(m_assembler.jmp()); 417 } 418 jump(RegisterID target)419 void jump(RegisterID target) 420 { 421 move(target, ARM::pc); 422 } 423 jump(Address address)424 void jump(Address address) 425 { 426 load32(address, ARM::pc); 427 } 428 branchAdd32(Condition cond,RegisterID src,RegisterID dest)429 Jump branchAdd32(Condition cond, RegisterID src, RegisterID dest) 430 { 431 ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); 432 add32(src, dest); 433 return Jump(m_assembler.jmp(ARMCondition(cond))); 434 } 435 branchAdd32(Condition cond,Imm32 imm,RegisterID dest)436 Jump branchAdd32(Condition cond, Imm32 imm, RegisterID dest) 437 { 438 ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); 439 add32(imm, dest); 440 return Jump(m_assembler.jmp(ARMCondition(cond))); 441 } 442 mull32(RegisterID src1,RegisterID src2,RegisterID dest)443 void mull32(RegisterID src1, RegisterID src2, RegisterID dest) 444 { 445 if (src1 == dest) { 446 move(src1, ARM::S0); 447 src1 = ARM::S0; 448 } 449 m_assembler.mull_r(ARM::S1, dest, src2, src1); 450 m_assembler.cmp_r(ARM::S1, m_assembler.asr(dest, 31)); 451 } 452 branchMul32(Condition cond,RegisterID src,RegisterID dest)453 Jump branchMul32(Condition cond, RegisterID src, RegisterID dest) 454 { 455 ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); 456 if (cond == Overflow) { 457 mull32(src, dest, dest); 458 cond = NonZero; 459 } 460 else 461 mul32(src, dest); 462 return Jump(m_assembler.jmp(ARMCondition(cond))); 463 } 464 branchMul32(Condition cond,Imm32 imm,RegisterID src,RegisterID dest)465 Jump branchMul32(Condition cond, Imm32 imm, RegisterID src, RegisterID dest) 466 { 467 ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); 468 if (cond == Overflow) { 469 move(imm, ARM::S0); 470 mull32(ARM::S0, src, dest); 471 cond = NonZero; 472 } 473 else 474 mul32(imm, src, dest); 475 return Jump(m_assembler.jmp(ARMCondition(cond))); 476 } 477 branchSub32(Condition cond,RegisterID src,RegisterID dest)478 Jump branchSub32(Condition cond, RegisterID src, RegisterID dest) 479 { 480 ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); 481 sub32(src, dest); 482 return Jump(m_assembler.jmp(ARMCondition(cond))); 483 } 484 branchSub32(Condition cond,Imm32 imm,RegisterID dest)485 Jump branchSub32(Condition cond, Imm32 imm, RegisterID dest) 486 { 487 ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); 488 sub32(imm, dest); 489 return Jump(m_assembler.jmp(ARMCondition(cond))); 490 } 491 breakpoint()492 void breakpoint() 493 { 494 m_assembler.bkpt(0); 495 } 496 nearCall()497 Call nearCall() 498 { 499 prepareCall(); 500 return Call(m_assembler.jmp(), Call::LinkableNear); 501 } 502 call(RegisterID target)503 Call call(RegisterID target) 504 { 505 prepareCall(); 506 move(ARM::pc, target); 507 JmpSrc jmpSrc; 508 return Call(jmpSrc, Call::None); 509 } 510 call(Address address)511 void call(Address address) 512 { 513 call32(address.base, address.offset); 514 } 515 ret()516 void ret() 517 { 518 pop(ARM::pc); 519 } 520 set32(Condition cond,RegisterID left,RegisterID right,RegisterID dest)521 void set32(Condition cond, RegisterID left, RegisterID right, RegisterID dest) 522 { 523 m_assembler.cmp_r(left, right); 524 m_assembler.mov_r(dest, ARMAssembler::getOp2(0)); 525 m_assembler.mov_r(dest, ARMAssembler::getOp2(1), ARMCondition(cond)); 526 } 527 set32(Condition cond,RegisterID left,Imm32 right,RegisterID dest)528 void set32(Condition cond, RegisterID left, Imm32 right, RegisterID dest) 529 { 530 m_assembler.cmp_r(left, m_assembler.getImm(right.m_value, ARM::S0)); 531 m_assembler.mov_r(dest, ARMAssembler::getOp2(0)); 532 m_assembler.mov_r(dest, ARMAssembler::getOp2(1), ARMCondition(cond)); 533 } 534 setTest32(Condition cond,Address address,Imm32 mask,RegisterID dest)535 void setTest32(Condition cond, Address address, Imm32 mask, RegisterID dest) 536 { 537 load32(address, ARM::S1); 538 if (mask.m_value == -1) 539 m_assembler.cmp_r(0, ARM::S1); 540 else 541 m_assembler.tst_r(ARM::S1, m_assembler.getImm(mask.m_value, ARM::S0)); 542 m_assembler.mov_r(dest, ARMAssembler::getOp2(0)); 543 m_assembler.mov_r(dest, ARMAssembler::getOp2(1), ARMCondition(cond)); 544 } 545 add32(Imm32 imm,RegisterID src,RegisterID dest)546 void add32(Imm32 imm, RegisterID src, RegisterID dest) 547 { 548 m_assembler.add_r(dest, src, m_assembler.getImm(imm.m_value, ARM::S0)); 549 } 550 add32(Imm32 imm,AbsoluteAddress address)551 void add32(Imm32 imm, AbsoluteAddress address) 552 { 553 m_assembler.ldr_un_imm(ARM::S1, reinterpret_cast<ARMWord>(address.m_ptr)); 554 m_assembler.dtr_u(true, ARM::S1, ARM::S1, 0); 555 add32(imm, ARM::S1); 556 m_assembler.ldr_un_imm(ARM::S0, reinterpret_cast<ARMWord>(address.m_ptr)); 557 m_assembler.dtr_u(false, ARM::S1, ARM::S0, 0); 558 } 559 sub32(Imm32 imm,AbsoluteAddress address)560 void sub32(Imm32 imm, AbsoluteAddress address) 561 { 562 m_assembler.ldr_un_imm(ARM::S1, reinterpret_cast<ARMWord>(address.m_ptr)); 563 m_assembler.dtr_u(true, ARM::S1, ARM::S1, 0); 564 sub32(imm, ARM::S1); 565 m_assembler.ldr_un_imm(ARM::S0, reinterpret_cast<ARMWord>(address.m_ptr)); 566 m_assembler.dtr_u(false, ARM::S1, ARM::S0, 0); 567 } 568 load32(void * address,RegisterID dest)569 void load32(void* address, RegisterID dest) 570 { 571 m_assembler.ldr_un_imm(ARM::S0, reinterpret_cast<ARMWord>(address)); 572 m_assembler.dtr_u(true, dest, ARM::S0, 0); 573 } 574 branch32(Condition cond,AbsoluteAddress left,RegisterID right)575 Jump branch32(Condition cond, AbsoluteAddress left, RegisterID right) 576 { 577 load32(left.m_ptr, ARM::S1); 578 return branch32(cond, ARM::S1, right); 579 } 580 branch32(Condition cond,AbsoluteAddress left,Imm32 right)581 Jump branch32(Condition cond, AbsoluteAddress left, Imm32 right) 582 { 583 load32(left.m_ptr, ARM::S1); 584 return branch32(cond, ARM::S1, right); 585 } 586 call()587 Call call() 588 { 589 prepareCall(); 590 return Call(m_assembler.jmp(), Call::Linkable); 591 } 592 tailRecursiveCall()593 Call tailRecursiveCall() 594 { 595 return Call::fromTailJump(jump()); 596 } 597 makeTailRecursiveCall(Jump oldJump)598 Call makeTailRecursiveCall(Jump oldJump) 599 { 600 return Call::fromTailJump(oldJump); 601 } 602 moveWithPatch(ImmPtr initialValue,RegisterID dest)603 DataLabelPtr moveWithPatch(ImmPtr initialValue, RegisterID dest) 604 { 605 DataLabelPtr dataLabel(this); 606 m_assembler.ldr_un_imm(dest, reinterpret_cast<ARMWord>(initialValue.m_value)); 607 return dataLabel; 608 } 609 610 Jump branchPtrWithPatch(Condition cond, RegisterID left, DataLabelPtr& dataLabel, ImmPtr initialRightValue = ImmPtr(0)) 611 { 612 dataLabel = moveWithPatch(initialRightValue, ARM::S1); 613 Jump jump = branch32(cond, left, ARM::S1); 614 jump.enableLatePatch(); 615 return jump; 616 } 617 618 Jump branchPtrWithPatch(Condition cond, Address left, DataLabelPtr& dataLabel, ImmPtr initialRightValue = ImmPtr(0)) 619 { 620 load32(left, ARM::S1); 621 dataLabel = moveWithPatch(initialRightValue, ARM::S0); 622 Jump jump = branch32(cond, ARM::S0, ARM::S1); 623 jump.enableLatePatch(); 624 return jump; 625 } 626 storePtrWithPatch(ImmPtr initialValue,ImplicitAddress address)627 DataLabelPtr storePtrWithPatch(ImmPtr initialValue, ImplicitAddress address) 628 { 629 DataLabelPtr dataLabel = moveWithPatch(initialValue, ARM::S1); 630 store32(ARM::S1, address); 631 return dataLabel; 632 } 633 storePtrWithPatch(ImplicitAddress address)634 DataLabelPtr storePtrWithPatch(ImplicitAddress address) 635 { 636 return storePtrWithPatch(ImmPtr(0), address); 637 } 638 639 // Floating point operators supportsFloatingPoint()640 bool supportsFloatingPoint() const 641 { 642 // FIXME: should be a dynamic test: VFP, FPA, or nothing 643 return false; 644 } 645 supportsFloatingPointTruncate()646 bool supportsFloatingPointTruncate() const 647 { 648 return false; 649 } 650 loadDouble(ImplicitAddress address,FPRegisterID dest)651 void loadDouble(ImplicitAddress address, FPRegisterID dest) 652 { 653 m_assembler.doubleTransfer(true, dest, address.base, address.offset); 654 } 655 storeDouble(FPRegisterID src,ImplicitAddress address)656 void storeDouble(FPRegisterID src, ImplicitAddress address) 657 { 658 m_assembler.doubleTransfer(false, src, address.base, address.offset); 659 } 660 addDouble(FPRegisterID src,FPRegisterID dest)661 void addDouble(FPRegisterID src, FPRegisterID dest) 662 { 663 m_assembler.faddd_r(dest, dest, src); 664 } 665 addDouble(Address src,FPRegisterID dest)666 void addDouble(Address src, FPRegisterID dest) 667 { 668 loadDouble(src, ARM::SD0); 669 addDouble(ARM::SD0, dest); 670 } 671 subDouble(FPRegisterID src,FPRegisterID dest)672 void subDouble(FPRegisterID src, FPRegisterID dest) 673 { 674 m_assembler.fsubd_r(dest, dest, src); 675 } 676 subDouble(Address src,FPRegisterID dest)677 void subDouble(Address src, FPRegisterID dest) 678 { 679 loadDouble(src, ARM::SD0); 680 subDouble(ARM::SD0, dest); 681 } 682 mulDouble(FPRegisterID src,FPRegisterID dest)683 void mulDouble(FPRegisterID src, FPRegisterID dest) 684 { 685 m_assembler.fmuld_r(dest, dest, src); 686 } 687 mulDouble(Address src,FPRegisterID dest)688 void mulDouble(Address src, FPRegisterID dest) 689 { 690 loadDouble(src, ARM::SD0); 691 mulDouble(ARM::SD0, dest); 692 } 693 convertInt32ToDouble(RegisterID src,FPRegisterID dest)694 void convertInt32ToDouble(RegisterID src, FPRegisterID dest) 695 { 696 m_assembler.fmsr_r(dest, src); 697 m_assembler.fsitod_r(dest, dest); 698 } 699 branchDouble(DoubleCondition cond,FPRegisterID left,FPRegisterID right)700 Jump branchDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right) 701 { 702 m_assembler.fcmpd_r(left, right); 703 m_assembler.fmstat(); 704 return Jump(m_assembler.jmp(static_cast<ARMAssembler::Condition>(cond))); 705 } 706 707 // Truncates 'src' to an integer, and places the resulting 'dest'. 708 // If the result is not representable as a 32 bit value, branch. 709 // May also branch for some values that are representable in 32 bits 710 // (specifically, in this case, INT_MIN). branchTruncateDoubleToInt32(FPRegisterID src,RegisterID dest)711 Jump branchTruncateDoubleToInt32(FPRegisterID src, RegisterID dest) 712 { 713 UNUSED_PARAM(src); 714 UNUSED_PARAM(dest); 715 ASSERT_NOT_REACHED(); 716 return jump(); 717 } 718 719 protected: ARMCondition(Condition cond)720 ARMAssembler::Condition ARMCondition(Condition cond) 721 { 722 return static_cast<ARMAssembler::Condition>(cond); 723 } 724 prepareCall()725 void prepareCall() 726 { 727 m_assembler.ensureSpace(3 * sizeof(ARMWord), sizeof(ARMWord)); 728 729 // S0 might be used for parameter passing 730 m_assembler.add_r(ARM::S1, ARM::pc, ARMAssembler::OP2_IMM | 0x4); 731 m_assembler.push_r(ARM::S1); 732 } 733 call32(RegisterID base,int32_t offset)734 void call32(RegisterID base, int32_t offset) 735 { 736 if (base == ARM::sp) 737 offset += 4; 738 739 if (offset >= 0) { 740 if (offset <= 0xfff) { 741 prepareCall(); 742 m_assembler.dtr_u(true, ARM::pc, base, offset); 743 } else if (offset <= 0xfffff) { 744 m_assembler.add_r(ARM::S0, base, ARMAssembler::OP2_IMM | (offset >> 12) | (10 << 8)); 745 prepareCall(); 746 m_assembler.dtr_u(true, ARM::pc, ARM::S0, offset & 0xfff); 747 } else { 748 ARMWord reg = m_assembler.getImm(offset, ARM::S0); 749 prepareCall(); 750 m_assembler.dtr_ur(true, ARM::pc, base, reg); 751 } 752 } else { 753 offset = -offset; 754 if (offset <= 0xfff) { 755 prepareCall(); 756 m_assembler.dtr_d(true, ARM::pc, base, offset); 757 } else if (offset <= 0xfffff) { 758 m_assembler.sub_r(ARM::S0, base, ARMAssembler::OP2_IMM | (offset >> 12) | (10 << 8)); 759 prepareCall(); 760 m_assembler.dtr_d(true, ARM::pc, ARM::S0, offset & 0xfff); 761 } else { 762 ARMWord reg = m_assembler.getImm(offset, ARM::S0); 763 prepareCall(); 764 m_assembler.dtr_dr(true, ARM::pc, base, reg); 765 } 766 } 767 } 768 769 private: 770 friend class LinkBuffer; 771 friend class RepatchBuffer; 772 linkCall(void * code,Call call,FunctionPtr function)773 static void linkCall(void* code, Call call, FunctionPtr function) 774 { 775 ARMAssembler::linkCall(code, call.m_jmp, function.value()); 776 } 777 repatchCall(CodeLocationCall call,CodeLocationLabel destination)778 static void repatchCall(CodeLocationCall call, CodeLocationLabel destination) 779 { 780 ARMAssembler::relinkCall(call.dataLocation(), destination.executableAddress()); 781 } 782 repatchCall(CodeLocationCall call,FunctionPtr destination)783 static void repatchCall(CodeLocationCall call, FunctionPtr destination) 784 { 785 ARMAssembler::relinkCall(call.dataLocation(), destination.executableAddress()); 786 } 787 788 }; 789 790 } 791 792 #endif 793 794 #endif // MacroAssemblerARM_h 795