1 /* 2 * Copyright (C) 2009 Apple Inc. 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 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #ifndef MacroAssemblerARMv7_h 27 #define MacroAssemblerARMv7_h 28 29 #include <wtf/Platform.h> 30 31 #if ENABLE(ASSEMBLER) 32 33 #include "ARMv7Assembler.h" 34 #include "AbstractMacroAssembler.h" 35 36 namespace JSC { 37 38 class MacroAssemblerARMv7 : public AbstractMacroAssembler<ARMv7Assembler> { 39 // FIXME: switch dataTempRegister & addressTempRegister, or possibly use r7? 40 // - dTR is likely used more than aTR, and we'll get better instruction 41 // encoding if it's in the low 8 registers. 42 static const ARM::RegisterID dataTempRegister = ARM::ip; 43 static const RegisterID addressTempRegister = ARM::r3; 44 static const FPRegisterID fpTempRegister = ARM::d7; 45 46 struct ArmAddress { 47 enum AddressType { 48 HasOffset, 49 HasIndex, 50 } type; 51 RegisterID base; 52 union { 53 int32_t offset; 54 struct { 55 RegisterID index; 56 Scale scale; 57 }; 58 } u; 59 60 explicit ArmAddress(RegisterID base, int32_t offset = 0) typeArmAddress61 : type(HasOffset) 62 , base(base) 63 { 64 u.offset = offset; 65 } 66 67 explicit ArmAddress(RegisterID base, RegisterID index, Scale scale = TimesOne) typeArmAddress68 : type(HasIndex) 69 , base(base) 70 { 71 u.index = index; 72 u.scale = scale; 73 } 74 }; 75 76 public: 77 78 static const Scale ScalePtr = TimesFour; 79 80 enum Condition { 81 Equal = ARMv7Assembler::ConditionEQ, 82 NotEqual = ARMv7Assembler::ConditionNE, 83 Above = ARMv7Assembler::ConditionHI, 84 AboveOrEqual = ARMv7Assembler::ConditionHS, 85 Below = ARMv7Assembler::ConditionLO, 86 BelowOrEqual = ARMv7Assembler::ConditionLS, 87 GreaterThan = ARMv7Assembler::ConditionGT, 88 GreaterThanOrEqual = ARMv7Assembler::ConditionGE, 89 LessThan = ARMv7Assembler::ConditionLT, 90 LessThanOrEqual = ARMv7Assembler::ConditionLE, 91 Overflow = ARMv7Assembler::ConditionVS, 92 Signed = ARMv7Assembler::ConditionMI, 93 Zero = ARMv7Assembler::ConditionEQ, 94 NonZero = ARMv7Assembler::ConditionNE 95 }; 96 97 enum DoubleCondition { 98 DoubleEqual = ARMv7Assembler::ConditionEQ, 99 DoubleGreaterThan = ARMv7Assembler::ConditionGT, 100 DoubleGreaterThanOrEqual = ARMv7Assembler::ConditionGE, 101 DoubleLessThan = ARMv7Assembler::ConditionLO, 102 DoubleLessThanOrEqual = ARMv7Assembler::ConditionLS, 103 }; 104 105 static const RegisterID stackPointerRegister = ARM::sp; 106 static const RegisterID linkRegister = ARM::lr; 107 108 // Integer arithmetic operations: 109 // 110 // Operations are typically two operand - operation(source, srcDst) 111 // For many operations the source may be an Imm32, the srcDst operand 112 // may often be a memory location (explictly described using an Address 113 // object). 114 add32(RegisterID src,RegisterID dest)115 void add32(RegisterID src, RegisterID dest) 116 { 117 m_assembler.add(dest, dest, src); 118 } 119 add32(Imm32 imm,RegisterID dest)120 void add32(Imm32 imm, RegisterID dest) 121 { 122 add32(imm, dest, dest); 123 } 124 add32(Imm32 imm,RegisterID src,RegisterID dest)125 void add32(Imm32 imm, RegisterID src, RegisterID dest) 126 { 127 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value); 128 if (armImm.isValid()) 129 m_assembler.add(dest, src, armImm); 130 else { 131 move(imm, dataTempRegister); 132 m_assembler.add(dest, src, dataTempRegister); 133 } 134 } 135 add32(Imm32 imm,Address address)136 void add32(Imm32 imm, Address address) 137 { 138 load32(address, dataTempRegister); 139 140 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value); 141 if (armImm.isValid()) 142 m_assembler.add(dataTempRegister, dataTempRegister, armImm); 143 else { 144 // Hrrrm, since dataTempRegister holds the data loaded, 145 // use addressTempRegister to hold the immediate. 146 move(imm, addressTempRegister); 147 m_assembler.add(dataTempRegister, dataTempRegister, addressTempRegister); 148 } 149 150 store32(dataTempRegister, address); 151 } 152 add32(Address src,RegisterID dest)153 void add32(Address src, RegisterID dest) 154 { 155 load32(src, dataTempRegister); 156 add32(dataTempRegister, dest); 157 } 158 add32(Imm32 imm,AbsoluteAddress address)159 void add32(Imm32 imm, AbsoluteAddress address) 160 { 161 load32(address.m_ptr, dataTempRegister); 162 163 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value); 164 if (armImm.isValid()) 165 m_assembler.add(dataTempRegister, dataTempRegister, armImm); 166 else { 167 // Hrrrm, since dataTempRegister holds the data loaded, 168 // use addressTempRegister to hold the immediate. 169 move(imm, addressTempRegister); 170 m_assembler.add(dataTempRegister, dataTempRegister, addressTempRegister); 171 } 172 173 store32(dataTempRegister, address.m_ptr); 174 } 175 and32(RegisterID src,RegisterID dest)176 void and32(RegisterID src, RegisterID dest) 177 { 178 m_assembler.ARM_and(dest, dest, src); 179 } 180 and32(Imm32 imm,RegisterID dest)181 void and32(Imm32 imm, RegisterID dest) 182 { 183 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value); 184 if (armImm.isValid()) 185 m_assembler.ARM_and(dest, dest, armImm); 186 else { 187 move(imm, dataTempRegister); 188 m_assembler.ARM_and(dest, dest, dataTempRegister); 189 } 190 } 191 lshift32(Imm32 imm,RegisterID dest)192 void lshift32(Imm32 imm, RegisterID dest) 193 { 194 m_assembler.lsl(dest, dest, imm.m_value); 195 } 196 lshift32(RegisterID shift_amount,RegisterID dest)197 void lshift32(RegisterID shift_amount, RegisterID dest) 198 { 199 m_assembler.lsl(dest, dest, shift_amount); 200 } 201 mul32(RegisterID src,RegisterID dest)202 void mul32(RegisterID src, RegisterID dest) 203 { 204 m_assembler.smull(dest, dataTempRegister, dest, src); 205 } 206 mul32(Imm32 imm,RegisterID src,RegisterID dest)207 void mul32(Imm32 imm, RegisterID src, RegisterID dest) 208 { 209 move(imm, dataTempRegister); 210 m_assembler.smull(dest, dataTempRegister, src, dataTempRegister); 211 } 212 not32(RegisterID srcDest)213 void not32(RegisterID srcDest) 214 { 215 m_assembler.mvn(srcDest, srcDest); 216 } 217 or32(RegisterID src,RegisterID dest)218 void or32(RegisterID src, RegisterID dest) 219 { 220 m_assembler.orr(dest, dest, src); 221 } 222 or32(Imm32 imm,RegisterID dest)223 void or32(Imm32 imm, RegisterID dest) 224 { 225 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value); 226 if (armImm.isValid()) 227 m_assembler.orr(dest, dest, armImm); 228 else { 229 move(imm, dataTempRegister); 230 m_assembler.orr(dest, dest, dataTempRegister); 231 } 232 } 233 rshift32(RegisterID shift_amount,RegisterID dest)234 void rshift32(RegisterID shift_amount, RegisterID dest) 235 { 236 m_assembler.asr(dest, dest, shift_amount); 237 } 238 rshift32(Imm32 imm,RegisterID dest)239 void rshift32(Imm32 imm, RegisterID dest) 240 { 241 m_assembler.asr(dest, dest, imm.m_value); 242 } 243 sub32(RegisterID src,RegisterID dest)244 void sub32(RegisterID src, RegisterID dest) 245 { 246 m_assembler.sub(dest, dest, src); 247 } 248 sub32(Imm32 imm,RegisterID dest)249 void sub32(Imm32 imm, RegisterID dest) 250 { 251 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value); 252 if (armImm.isValid()) 253 m_assembler.sub(dest, dest, armImm); 254 else { 255 move(imm, dataTempRegister); 256 m_assembler.sub(dest, dest, dataTempRegister); 257 } 258 } 259 sub32(Imm32 imm,Address address)260 void sub32(Imm32 imm, Address address) 261 { 262 load32(address, dataTempRegister); 263 264 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value); 265 if (armImm.isValid()) 266 m_assembler.sub(dataTempRegister, dataTempRegister, armImm); 267 else { 268 // Hrrrm, since dataTempRegister holds the data loaded, 269 // use addressTempRegister to hold the immediate. 270 move(imm, addressTempRegister); 271 m_assembler.sub(dataTempRegister, dataTempRegister, addressTempRegister); 272 } 273 274 store32(dataTempRegister, address); 275 } 276 sub32(Address src,RegisterID dest)277 void sub32(Address src, RegisterID dest) 278 { 279 load32(src, dataTempRegister); 280 sub32(dataTempRegister, dest); 281 } 282 sub32(Imm32 imm,AbsoluteAddress address)283 void sub32(Imm32 imm, AbsoluteAddress address) 284 { 285 load32(address.m_ptr, dataTempRegister); 286 287 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value); 288 if (armImm.isValid()) 289 m_assembler.sub(dataTempRegister, dataTempRegister, armImm); 290 else { 291 // Hrrrm, since dataTempRegister holds the data loaded, 292 // use addressTempRegister to hold the immediate. 293 move(imm, addressTempRegister); 294 m_assembler.sub(dataTempRegister, dataTempRegister, addressTempRegister); 295 } 296 297 store32(dataTempRegister, address.m_ptr); 298 } 299 xor32(RegisterID src,RegisterID dest)300 void xor32(RegisterID src, RegisterID dest) 301 { 302 m_assembler.eor(dest, dest, src); 303 } 304 xor32(Imm32 imm,RegisterID dest)305 void xor32(Imm32 imm, RegisterID dest) 306 { 307 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value); 308 if (armImm.isValid()) 309 m_assembler.eor(dest, dest, armImm); 310 else { 311 move(imm, dataTempRegister); 312 m_assembler.eor(dest, dest, dataTempRegister); 313 } 314 } 315 316 317 // Memory access operations: 318 // 319 // Loads are of the form load(address, destination) and stores of the form 320 // store(source, address). The source for a store may be an Imm32. Address 321 // operand objects to loads and store will be implicitly constructed if a 322 // register is passed. 323 324 private: load32(ArmAddress address,RegisterID dest)325 void load32(ArmAddress address, RegisterID dest) 326 { 327 if (address.type == ArmAddress::HasIndex) 328 m_assembler.ldr(dest, address.base, address.u.index, address.u.scale); 329 else if (address.u.offset >= 0) { 330 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.u.offset); 331 ASSERT(armImm.isValid()); 332 m_assembler.ldr(dest, address.base, armImm); 333 } else { 334 ASSERT(address.u.offset >= -255); 335 m_assembler.ldr(dest, address.base, address.u.offset, true, false); 336 } 337 } 338 load16(ArmAddress address,RegisterID dest)339 void load16(ArmAddress address, RegisterID dest) 340 { 341 if (address.type == ArmAddress::HasIndex) 342 m_assembler.ldrh(dest, address.base, address.u.index, address.u.scale); 343 else if (address.u.offset >= 0) { 344 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.u.offset); 345 ASSERT(armImm.isValid()); 346 m_assembler.ldrh(dest, address.base, armImm); 347 } else { 348 ASSERT(address.u.offset >= -255); 349 m_assembler.ldrh(dest, address.base, address.u.offset, true, false); 350 } 351 } 352 store32(RegisterID src,ArmAddress address)353 void store32(RegisterID src, ArmAddress address) 354 { 355 if (address.type == ArmAddress::HasIndex) 356 m_assembler.str(src, address.base, address.u.index, address.u.scale); 357 else if (address.u.offset >= 0) { 358 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.u.offset); 359 ASSERT(armImm.isValid()); 360 m_assembler.str(src, address.base, armImm); 361 } else { 362 ASSERT(address.u.offset >= -255); 363 m_assembler.str(src, address.base, address.u.offset, true, false); 364 } 365 } 366 367 public: load32(ImplicitAddress address,RegisterID dest)368 void load32(ImplicitAddress address, RegisterID dest) 369 { 370 load32(setupArmAddress(address), dest); 371 } 372 load32(BaseIndex address,RegisterID dest)373 void load32(BaseIndex address, RegisterID dest) 374 { 375 load32(setupArmAddress(address), dest); 376 } 377 load32(void * address,RegisterID dest)378 void load32(void* address, RegisterID dest) 379 { 380 move(ImmPtr(address), addressTempRegister); 381 m_assembler.ldr(dest, addressTempRegister, ARMThumbImmediate::makeUInt16(0)); 382 } 383 load32WithAddressOffsetPatch(Address address,RegisterID dest)384 DataLabel32 load32WithAddressOffsetPatch(Address address, RegisterID dest) 385 { 386 DataLabel32 label = moveWithPatch(Imm32(address.offset), dataTempRegister); 387 load32(ArmAddress(address.base, dataTempRegister), dest); 388 return label; 389 } 390 loadPtrWithPatchToLEA(Address address,RegisterID dest)391 Label loadPtrWithPatchToLEA(Address address, RegisterID dest) 392 { 393 Label label(this); 394 moveFixedWidthEncoding(Imm32(address.offset), dataTempRegister); 395 load32(ArmAddress(address.base, dataTempRegister), dest); 396 return label; 397 } 398 load16(BaseIndex address,RegisterID dest)399 void load16(BaseIndex address, RegisterID dest) 400 { 401 m_assembler.ldrh(dest, makeBaseIndexBase(address), address.index, address.scale); 402 } 403 store32WithAddressOffsetPatch(RegisterID src,Address address)404 DataLabel32 store32WithAddressOffsetPatch(RegisterID src, Address address) 405 { 406 DataLabel32 label = moveWithPatch(Imm32(address.offset), dataTempRegister); 407 store32(src, ArmAddress(address.base, dataTempRegister)); 408 return label; 409 } 410 store32(RegisterID src,ImplicitAddress address)411 void store32(RegisterID src, ImplicitAddress address) 412 { 413 store32(src, setupArmAddress(address)); 414 } 415 store32(RegisterID src,BaseIndex address)416 void store32(RegisterID src, BaseIndex address) 417 { 418 store32(src, setupArmAddress(address)); 419 } 420 store32(Imm32 imm,ImplicitAddress address)421 void store32(Imm32 imm, ImplicitAddress address) 422 { 423 move(imm, dataTempRegister); 424 store32(dataTempRegister, setupArmAddress(address)); 425 } 426 store32(RegisterID src,void * address)427 void store32(RegisterID src, void* address) 428 { 429 move(ImmPtr(address), addressTempRegister); 430 m_assembler.str(src, addressTempRegister, ARMThumbImmediate::makeUInt16(0)); 431 } 432 store32(Imm32 imm,void * address)433 void store32(Imm32 imm, void* address) 434 { 435 move(imm, dataTempRegister); 436 store32(dataTempRegister, address); 437 } 438 439 440 // Floating-point operations: 441 supportsFloatingPoint()442 bool supportsFloatingPoint() const { return true; } 443 // On x86(_64) the MacroAssembler provides an interface to truncate a double to an integer. 444 // If a value is not representable as an integer, and possibly for some values that are, 445 // (on x86 INT_MIN, since this is indistinguishable from results for out-of-range/NaN input) 446 // a branch will be taken. It is not clear whether this interface will be well suited to 447 // other platforms. On ARMv7 the hardware truncation operation produces multiple possible 448 // failure values (saturates to INT_MIN & INT_MAX, NaN reulsts in a value of 0). This is a 449 // temporary solution while we work out what this interface should be. Either we need to 450 // decide to make this interface work on all platforms, rework the interface to make it more 451 // generic, or decide that the MacroAssembler cannot practically be used to abstracted these 452 // operations, and make clients go directly to the m_assembler to plant truncation instructions. 453 // In short, FIXME:. supportsFloatingPointTruncate()454 bool supportsFloatingPointTruncate() const { return false; } 455 loadDouble(ImplicitAddress address,FPRegisterID dest)456 void loadDouble(ImplicitAddress address, FPRegisterID dest) 457 { 458 RegisterID base = address.base; 459 int32_t offset = address.offset; 460 461 // Arm vfp addresses can be offset by a 9-bit ones-comp immediate, left shifted by 2. 462 if ((offset & 3) || (offset > (255 * 4)) || (offset < -(255 * 4))) { 463 add32(Imm32(offset), base, addressTempRegister); 464 base = addressTempRegister; 465 offset = 0; 466 } 467 468 m_assembler.vldr(dest, base, offset); 469 } 470 storeDouble(FPRegisterID src,ImplicitAddress address)471 void storeDouble(FPRegisterID src, ImplicitAddress address) 472 { 473 RegisterID base = address.base; 474 int32_t offset = address.offset; 475 476 // Arm vfp addresses can be offset by a 9-bit ones-comp immediate, left shifted by 2. 477 if ((offset & 3) || (offset > (255 * 4)) || (offset < -(255 * 4))) { 478 add32(Imm32(offset), base, addressTempRegister); 479 base = addressTempRegister; 480 offset = 0; 481 } 482 483 m_assembler.vstr(src, base, offset); 484 } 485 addDouble(FPRegisterID src,FPRegisterID dest)486 void addDouble(FPRegisterID src, FPRegisterID dest) 487 { 488 m_assembler.vadd_F64(dest, dest, src); 489 } 490 addDouble(Address src,FPRegisterID dest)491 void addDouble(Address src, FPRegisterID dest) 492 { 493 loadDouble(src, fpTempRegister); 494 addDouble(fpTempRegister, dest); 495 } 496 subDouble(FPRegisterID src,FPRegisterID dest)497 void subDouble(FPRegisterID src, FPRegisterID dest) 498 { 499 m_assembler.vsub_F64(dest, dest, src); 500 } 501 subDouble(Address src,FPRegisterID dest)502 void subDouble(Address src, FPRegisterID dest) 503 { 504 loadDouble(src, fpTempRegister); 505 subDouble(fpTempRegister, dest); 506 } 507 mulDouble(FPRegisterID src,FPRegisterID dest)508 void mulDouble(FPRegisterID src, FPRegisterID dest) 509 { 510 m_assembler.vmul_F64(dest, dest, src); 511 } 512 mulDouble(Address src,FPRegisterID dest)513 void mulDouble(Address src, FPRegisterID dest) 514 { 515 loadDouble(src, fpTempRegister); 516 mulDouble(fpTempRegister, dest); 517 } 518 convertInt32ToDouble(RegisterID src,FPRegisterID dest)519 void convertInt32ToDouble(RegisterID src, FPRegisterID dest) 520 { 521 m_assembler.vmov(fpTempRegister, src); 522 m_assembler.vcvt_F64_S32(dest, fpTempRegister); 523 } 524 branchDouble(DoubleCondition cond,FPRegisterID left,FPRegisterID right)525 Jump branchDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right) 526 { 527 m_assembler.vcmp_F64(left, right); 528 m_assembler.vmrs_APSR_nzcv_FPSCR(); 529 return makeBranch(cond); 530 } 531 branchTruncateDoubleToInt32(FPRegisterID,RegisterID)532 Jump branchTruncateDoubleToInt32(FPRegisterID, RegisterID) 533 { 534 ASSERT_NOT_REACHED(); 535 } 536 537 538 // Stack manipulation operations: 539 // 540 // The ABI is assumed to provide a stack abstraction to memory, 541 // containing machine word sized units of data. Push and pop 542 // operations add and remove a single register sized unit of data 543 // to or from the stack. Peek and poke operations read or write 544 // values on the stack, without moving the current stack position. 545 pop(RegisterID dest)546 void pop(RegisterID dest) 547 { 548 // store postindexed with writeback 549 m_assembler.ldr(dest, ARM::sp, sizeof(void*), false, true); 550 } 551 push(RegisterID src)552 void push(RegisterID src) 553 { 554 // store preindexed with writeback 555 m_assembler.str(src, ARM::sp, -sizeof(void*), true, true); 556 } 557 push(Address address)558 void push(Address address) 559 { 560 load32(address, dataTempRegister); 561 push(dataTempRegister); 562 } 563 push(Imm32 imm)564 void push(Imm32 imm) 565 { 566 move(imm, dataTempRegister); 567 push(dataTempRegister); 568 } 569 570 // Register move operations: 571 // 572 // Move values in registers. 573 move(Imm32 imm,RegisterID dest)574 void move(Imm32 imm, RegisterID dest) 575 { 576 uint32_t value = imm.m_value; 577 578 if (imm.m_isPointer) 579 moveFixedWidthEncoding(imm, dest); 580 else { 581 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(value); 582 583 if (armImm.isValid()) 584 m_assembler.mov(dest, armImm); 585 else if ((armImm = ARMThumbImmediate::makeEncodedImm(~value)).isValid()) 586 m_assembler.mvn(dest, armImm); 587 else { 588 m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(value)); 589 if (value & 0xffff0000) 590 m_assembler.movt(dest, ARMThumbImmediate::makeUInt16(value >> 16)); 591 } 592 } 593 } 594 move(RegisterID src,RegisterID dest)595 void move(RegisterID src, RegisterID dest) 596 { 597 m_assembler.mov(dest, src); 598 } 599 move(ImmPtr imm,RegisterID dest)600 void move(ImmPtr imm, RegisterID dest) 601 { 602 move(Imm32(imm), dest); 603 } 604 swap(RegisterID reg1,RegisterID reg2)605 void swap(RegisterID reg1, RegisterID reg2) 606 { 607 move(reg1, dataTempRegister); 608 move(reg2, reg1); 609 move(dataTempRegister, reg2); 610 } 611 signExtend32ToPtr(RegisterID src,RegisterID dest)612 void signExtend32ToPtr(RegisterID src, RegisterID dest) 613 { 614 if (src != dest) 615 move(src, dest); 616 } 617 zeroExtend32ToPtr(RegisterID src,RegisterID dest)618 void zeroExtend32ToPtr(RegisterID src, RegisterID dest) 619 { 620 if (src != dest) 621 move(src, dest); 622 } 623 624 625 // Forwards / external control flow operations: 626 // 627 // This set of jump and conditional branch operations return a Jump 628 // object which may linked at a later point, allow forwards jump, 629 // or jumps that will require external linkage (after the code has been 630 // relocated). 631 // 632 // For branches, signed <, >, <= and >= are denoted as l, g, le, and ge 633 // respecitvely, for unsigned comparisons the names b, a, be, and ae are 634 // used (representing the names 'below' and 'above'). 635 // 636 // Operands to the comparision are provided in the expected order, e.g. 637 // jle32(reg1, Imm32(5)) will branch if the value held in reg1, when 638 // treated as a signed 32bit value, is less than or equal to 5. 639 // 640 // jz and jnz test whether the first operand is equal to zero, and take 641 // an optional second operand of a mask under which to perform the test. 642 private: 643 644 // Should we be using TEQ for equal/not-equal? compare32(RegisterID left,Imm32 right)645 void compare32(RegisterID left, Imm32 right) 646 { 647 int32_t imm = right.m_value; 648 if (!imm) 649 m_assembler.tst(left, left); 650 else { 651 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm); 652 if (armImm.isValid()) 653 m_assembler.cmp(left, armImm); 654 if ((armImm = ARMThumbImmediate::makeEncodedImm(-imm)).isValid()) 655 m_assembler.cmn(left, armImm); 656 else { 657 move(Imm32(imm), dataTempRegister); 658 m_assembler.cmp(left, dataTempRegister); 659 } 660 } 661 } 662 test32(RegisterID reg,Imm32 mask)663 void test32(RegisterID reg, Imm32 mask) 664 { 665 int32_t imm = mask.m_value; 666 667 if (imm == -1) 668 m_assembler.tst(reg, reg); 669 else { 670 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm); 671 if (armImm.isValid()) 672 m_assembler.tst(reg, armImm); 673 else { 674 move(mask, dataTempRegister); 675 m_assembler.tst(reg, dataTempRegister); 676 } 677 } 678 } 679 680 public: branch32(Condition cond,RegisterID left,RegisterID right)681 Jump branch32(Condition cond, RegisterID left, RegisterID right) 682 { 683 m_assembler.cmp(left, right); 684 return Jump(makeBranch(cond)); 685 } 686 branch32(Condition cond,RegisterID left,Imm32 right)687 Jump branch32(Condition cond, RegisterID left, Imm32 right) 688 { 689 compare32(left, right); 690 return Jump(makeBranch(cond)); 691 } 692 branch32(Condition cond,RegisterID left,Address right)693 Jump branch32(Condition cond, RegisterID left, Address right) 694 { 695 load32(right, dataTempRegister); 696 return branch32(cond, left, dataTempRegister); 697 } 698 branch32(Condition cond,Address left,RegisterID right)699 Jump branch32(Condition cond, Address left, RegisterID right) 700 { 701 load32(left, dataTempRegister); 702 return branch32(cond, dataTempRegister, right); 703 } 704 branch32(Condition cond,Address left,Imm32 right)705 Jump branch32(Condition cond, Address left, Imm32 right) 706 { 707 // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/ 708 load32(left, addressTempRegister); 709 return branch32(cond, addressTempRegister, right); 710 } 711 branch32(Condition cond,BaseIndex left,Imm32 right)712 Jump branch32(Condition cond, BaseIndex left, Imm32 right) 713 { 714 // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/ 715 load32(left, addressTempRegister); 716 return branch32(cond, addressTempRegister, right); 717 } 718 branch32(Condition cond,AbsoluteAddress left,RegisterID right)719 Jump branch32(Condition cond, AbsoluteAddress left, RegisterID right) 720 { 721 load32(left.m_ptr, dataTempRegister); 722 return branch32(cond, dataTempRegister, right); 723 } 724 branch32(Condition cond,AbsoluteAddress left,Imm32 right)725 Jump branch32(Condition cond, AbsoluteAddress left, Imm32 right) 726 { 727 // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/ 728 load32(left.m_ptr, addressTempRegister); 729 return branch32(cond, addressTempRegister, right); 730 } 731 branch16(Condition cond,BaseIndex left,RegisterID right)732 Jump branch16(Condition cond, BaseIndex left, RegisterID right) 733 { 734 load16(left, dataTempRegister); 735 m_assembler.lsl(addressTempRegister, right, 16); 736 m_assembler.lsl(dataTempRegister, dataTempRegister, 16); 737 return branch32(cond, dataTempRegister, addressTempRegister); 738 } 739 branch16(Condition cond,BaseIndex left,Imm32 right)740 Jump branch16(Condition cond, BaseIndex left, Imm32 right) 741 { 742 // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/ 743 load16(left, addressTempRegister); 744 m_assembler.lsl(addressTempRegister, addressTempRegister, 16); 745 return branch32(cond, addressTempRegister, Imm32(right.m_value << 16)); 746 } 747 branchTest32(Condition cond,RegisterID reg,RegisterID mask)748 Jump branchTest32(Condition cond, RegisterID reg, RegisterID mask) 749 { 750 ASSERT((cond == Zero) || (cond == NonZero)); 751 m_assembler.tst(reg, mask); 752 return Jump(makeBranch(cond)); 753 } 754 755 Jump branchTest32(Condition cond, RegisterID reg, Imm32 mask = Imm32(-1)) 756 { 757 ASSERT((cond == Zero) || (cond == NonZero)); 758 test32(reg, mask); 759 return Jump(makeBranch(cond)); 760 } 761 762 Jump branchTest32(Condition cond, Address address, Imm32 mask = Imm32(-1)) 763 { 764 ASSERT((cond == Zero) || (cond == NonZero)); 765 // use addressTempRegister incase the branchTest32 we call uses dataTempRegister. :-/ 766 load32(address, addressTempRegister); 767 return branchTest32(cond, addressTempRegister, mask); 768 } 769 770 Jump branchTest32(Condition cond, BaseIndex address, Imm32 mask = Imm32(-1)) 771 { 772 ASSERT((cond == Zero) || (cond == NonZero)); 773 // use addressTempRegister incase the branchTest32 we call uses dataTempRegister. :-/ 774 load32(address, addressTempRegister); 775 return branchTest32(cond, addressTempRegister, mask); 776 } 777 jump()778 Jump jump() 779 { 780 return Jump(makeJump()); 781 } 782 jump(RegisterID target)783 void jump(RegisterID target) 784 { 785 m_assembler.bx(target); 786 } 787 788 // Address is a memory location containing the address to jump to jump(Address address)789 void jump(Address address) 790 { 791 load32(address, dataTempRegister); 792 m_assembler.bx(dataTempRegister); 793 } 794 795 796 // Arithmetic control flow operations: 797 // 798 // This set of conditional branch operations branch based 799 // on the result of an arithmetic operation. The operation 800 // is performed as normal, storing the result. 801 // 802 // * jz operations branch if the result is zero. 803 // * jo operations branch if the (signed) arithmetic 804 // operation caused an overflow to occur. 805 branchAdd32(Condition cond,RegisterID src,RegisterID dest)806 Jump branchAdd32(Condition cond, RegisterID src, RegisterID dest) 807 { 808 ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); 809 m_assembler.add_S(dest, dest, src); 810 return Jump(makeBranch(cond)); 811 } 812 branchAdd32(Condition cond,Imm32 imm,RegisterID dest)813 Jump branchAdd32(Condition cond, Imm32 imm, RegisterID dest) 814 { 815 ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); 816 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value); 817 if (armImm.isValid()) 818 m_assembler.add_S(dest, dest, armImm); 819 else { 820 move(imm, dataTempRegister); 821 m_assembler.add_S(dest, dest, dataTempRegister); 822 } 823 return Jump(makeBranch(cond)); 824 } 825 branchMul32(Condition cond,RegisterID src,RegisterID dest)826 Jump branchMul32(Condition cond, RegisterID src, RegisterID dest) 827 { 828 ASSERT(cond == Overflow); 829 m_assembler.smull(dest, dataTempRegister, dest, src); 830 m_assembler.asr(addressTempRegister, dest, 31); 831 return branch32(NotEqual, addressTempRegister, dataTempRegister); 832 } 833 branchMul32(Condition cond,Imm32 imm,RegisterID src,RegisterID dest)834 Jump branchMul32(Condition cond, Imm32 imm, RegisterID src, RegisterID dest) 835 { 836 ASSERT(cond == Overflow); 837 move(imm, dataTempRegister); 838 m_assembler.smull(dest, dataTempRegister, src, dataTempRegister); 839 m_assembler.asr(addressTempRegister, dest, 31); 840 return branch32(NotEqual, addressTempRegister, dataTempRegister); 841 } 842 branchSub32(Condition cond,RegisterID src,RegisterID dest)843 Jump branchSub32(Condition cond, RegisterID src, RegisterID dest) 844 { 845 ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); 846 m_assembler.sub_S(dest, dest, src); 847 return Jump(makeBranch(cond)); 848 } 849 branchSub32(Condition cond,Imm32 imm,RegisterID dest)850 Jump branchSub32(Condition cond, Imm32 imm, RegisterID dest) 851 { 852 ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); 853 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value); 854 if (armImm.isValid()) 855 m_assembler.sub_S(dest, dest, armImm); 856 else { 857 move(imm, dataTempRegister); 858 m_assembler.sub_S(dest, dest, dataTempRegister); 859 } 860 return Jump(makeBranch(cond)); 861 } 862 863 864 // Miscellaneous operations: 865 breakpoint()866 void breakpoint() 867 { 868 m_assembler.bkpt(); 869 } 870 nearCall()871 Call nearCall() 872 { 873 moveFixedWidthEncoding(Imm32(0), dataTempRegister); 874 return Call(m_assembler.blx(dataTempRegister), Call::LinkableNear); 875 } 876 call()877 Call call() 878 { 879 moveFixedWidthEncoding(Imm32(0), dataTempRegister); 880 return Call(m_assembler.blx(dataTempRegister), Call::Linkable); 881 } 882 call(RegisterID target)883 Call call(RegisterID target) 884 { 885 return Call(m_assembler.blx(target), Call::None); 886 } 887 call(Address address)888 Call call(Address address) 889 { 890 load32(address, dataTempRegister); 891 return Call(m_assembler.blx(dataTempRegister), Call::None); 892 } 893 ret()894 void ret() 895 { 896 m_assembler.bx(linkRegister); 897 } 898 set32(Condition cond,RegisterID left,RegisterID right,RegisterID dest)899 void set32(Condition cond, RegisterID left, RegisterID right, RegisterID dest) 900 { 901 m_assembler.cmp(left, right); 902 m_assembler.it(armV7Condition(cond), false); 903 m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(1)); 904 m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0)); 905 } 906 set32(Condition cond,RegisterID left,Imm32 right,RegisterID dest)907 void set32(Condition cond, RegisterID left, Imm32 right, RegisterID dest) 908 { 909 compare32(left, right); 910 m_assembler.it(armV7Condition(cond), false); 911 m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(1)); 912 m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0)); 913 } 914 915 // FIXME: 916 // The mask should be optional... paerhaps the argument order should be 917 // dest-src, operations always have a dest? ... possibly not true, considering 918 // asm ops like test, or pseudo ops like pop(). setTest32(Condition cond,Address address,Imm32 mask,RegisterID dest)919 void setTest32(Condition cond, Address address, Imm32 mask, RegisterID dest) 920 { 921 load32(address, dataTempRegister); 922 test32(dataTempRegister, mask); 923 m_assembler.it(armV7Condition(cond), false); 924 m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(1)); 925 m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0)); 926 } 927 928 moveWithPatch(Imm32 imm,RegisterID dst)929 DataLabel32 moveWithPatch(Imm32 imm, RegisterID dst) 930 { 931 moveFixedWidthEncoding(imm, dst); 932 return DataLabel32(this); 933 } 934 moveWithPatch(ImmPtr imm,RegisterID dst)935 DataLabelPtr moveWithPatch(ImmPtr imm, RegisterID dst) 936 { 937 moveFixedWidthEncoding(Imm32(imm), dst); 938 return DataLabelPtr(this); 939 } 940 941 Jump branchPtrWithPatch(Condition cond, RegisterID left, DataLabelPtr& dataLabel, ImmPtr initialRightValue = ImmPtr(0)) 942 { 943 dataLabel = moveWithPatch(initialRightValue, dataTempRegister); 944 return branch32(cond, left, dataTempRegister); 945 } 946 947 Jump branchPtrWithPatch(Condition cond, Address left, DataLabelPtr& dataLabel, ImmPtr initialRightValue = ImmPtr(0)) 948 { 949 load32(left, addressTempRegister); 950 dataLabel = moveWithPatch(initialRightValue, dataTempRegister); 951 return branch32(cond, addressTempRegister, dataTempRegister); 952 } 953 storePtrWithPatch(ImmPtr initialValue,ImplicitAddress address)954 DataLabelPtr storePtrWithPatch(ImmPtr initialValue, ImplicitAddress address) 955 { 956 DataLabelPtr label = moveWithPatch(initialValue, dataTempRegister); 957 store32(dataTempRegister, address); 958 return label; 959 } storePtrWithPatch(ImplicitAddress address)960 DataLabelPtr storePtrWithPatch(ImplicitAddress address) { return storePtrWithPatch(ImmPtr(0), address); } 961 962 tailRecursiveCall()963 Call tailRecursiveCall() 964 { 965 // Like a normal call, but don't link. 966 moveFixedWidthEncoding(Imm32(0), dataTempRegister); 967 return Call(m_assembler.bx(dataTempRegister), Call::Linkable); 968 } 969 makeTailRecursiveCall(Jump oldJump)970 Call makeTailRecursiveCall(Jump oldJump) 971 { 972 oldJump.link(this); 973 return tailRecursiveCall(); 974 } 975 976 977 protected: makeJump()978 ARMv7Assembler::JmpSrc makeJump() 979 { 980 return m_assembler.b(); 981 } 982 makeBranch(ARMv7Assembler::Condition cond)983 ARMv7Assembler::JmpSrc makeBranch(ARMv7Assembler::Condition cond) 984 { 985 m_assembler.it(cond); 986 return m_assembler.b(); 987 } makeBranch(Condition cond)988 ARMv7Assembler::JmpSrc makeBranch(Condition cond) { return makeBranch(armV7Condition(cond)); } makeBranch(DoubleCondition cond)989 ARMv7Assembler::JmpSrc makeBranch(DoubleCondition cond) { return makeBranch(armV7Condition(cond)); } 990 setupArmAddress(BaseIndex address)991 ArmAddress setupArmAddress(BaseIndex address) 992 { 993 if (address.offset) { 994 ARMThumbImmediate imm = ARMThumbImmediate::makeUInt12OrEncodedImm(address.offset); 995 if (imm.isValid()) 996 m_assembler.add(addressTempRegister, address.base, imm); 997 else { 998 move(Imm32(address.offset), addressTempRegister); 999 m_assembler.add(addressTempRegister, addressTempRegister, address.base); 1000 } 1001 1002 return ArmAddress(addressTempRegister, address.index, address.scale); 1003 } else 1004 return ArmAddress(address.base, address.index, address.scale); 1005 } 1006 setupArmAddress(Address address)1007 ArmAddress setupArmAddress(Address address) 1008 { 1009 if ((address.offset >= -0xff) && (address.offset <= 0xfff)) 1010 return ArmAddress(address.base, address.offset); 1011 1012 move(Imm32(address.offset), addressTempRegister); 1013 return ArmAddress(address.base, addressTempRegister); 1014 } 1015 setupArmAddress(ImplicitAddress address)1016 ArmAddress setupArmAddress(ImplicitAddress address) 1017 { 1018 if ((address.offset >= -0xff) && (address.offset <= 0xfff)) 1019 return ArmAddress(address.base, address.offset); 1020 1021 move(Imm32(address.offset), addressTempRegister); 1022 return ArmAddress(address.base, addressTempRegister); 1023 } 1024 makeBaseIndexBase(BaseIndex address)1025 RegisterID makeBaseIndexBase(BaseIndex address) 1026 { 1027 if (!address.offset) 1028 return address.base; 1029 1030 ARMThumbImmediate imm = ARMThumbImmediate::makeUInt12OrEncodedImm(address.offset); 1031 if (imm.isValid()) 1032 m_assembler.add(addressTempRegister, address.base, imm); 1033 else { 1034 move(Imm32(address.offset), addressTempRegister); 1035 m_assembler.add(addressTempRegister, addressTempRegister, address.base); 1036 } 1037 1038 return addressTempRegister; 1039 } 1040 moveFixedWidthEncoding(Imm32 imm,RegisterID dst)1041 DataLabel32 moveFixedWidthEncoding(Imm32 imm, RegisterID dst) 1042 { 1043 uint32_t value = imm.m_value; 1044 m_assembler.movT3(dst, ARMThumbImmediate::makeUInt16(value & 0xffff)); 1045 m_assembler.movt(dst, ARMThumbImmediate::makeUInt16(value >> 16)); 1046 } 1047 armV7Condition(Condition cond)1048 ARMv7Assembler::Condition armV7Condition(Condition cond) 1049 { 1050 return static_cast<ARMv7Assembler::Condition>(cond); 1051 } 1052 armV7Condition(DoubleCondition cond)1053 ARMv7Assembler::Condition armV7Condition(DoubleCondition cond) 1054 { 1055 return static_cast<ARMv7Assembler::Condition>(cond); 1056 } 1057 1058 private: 1059 friend class LinkBuffer; 1060 friend class RepatchBuffer; 1061 linkCall(void * code,Call call,FunctionPtr function)1062 static void linkCall(void* code, Call call, FunctionPtr function) 1063 { 1064 ARMv7Assembler::linkCall(code, call.m_jmp, function.value()); 1065 } 1066 repatchCall(CodeLocationCall call,CodeLocationLabel destination)1067 static void repatchCall(CodeLocationCall call, CodeLocationLabel destination) 1068 { 1069 ARMv7Assembler::relinkCall(call.dataLocation(), destination.executableAddress()); 1070 } 1071 repatchCall(CodeLocationCall call,FunctionPtr destination)1072 static void repatchCall(CodeLocationCall call, FunctionPtr destination) 1073 { 1074 ARMv7Assembler::relinkCall(call.dataLocation(), destination.executableAddress()); 1075 } 1076 }; 1077 1078 } // namespace JSC 1079 1080 #endif // ENABLE(ASSEMBLER) 1081 1082 #endif // MacroAssemblerARMv7_h 1083