1/* 2 * Copyright (C) 2009, 2010 University of Szeged 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY UNIVERSITY OF SZEGED ``AS IS'' AND ANY 15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL UNIVERSITY OF SZEGED OR 18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27#ifndef ARMAssembler_h 28#define ARMAssembler_h 29 30#if ENABLE(ASSEMBLER) && CPU(ARM_TRADITIONAL) 31 32#include "AssemblerBufferWithConstantPool.h" 33#include "JITCompilationEffort.h" 34#include <wtf/Assertions.h> 35namespace JSC { 36 37 typedef uint32_t ARMWord; 38 39 namespace ARMRegisters { 40 typedef enum { 41 r0 = 0, 42 r1, 43 r2, 44 r3, S0 = r3, /* Same as thumb assembler. */ 45 r4, 46 r5, 47 r6, 48 r7, 49 r8, 50 r9, 51 r10, 52 r11, 53 r12, S1 = r12, 54 r13, sp = r13, 55 r14, lr = r14, 56 r15, pc = r15 57 } RegisterID; 58 59 typedef enum { 60 d0, 61 d1, 62 d2, 63 d3, 64 d4, 65 d5, 66 d6, 67 d7, SD0 = d7, /* Same as thumb assembler. */ 68 d8, 69 d9, 70 d10, 71 d11, 72 d12, 73 d13, 74 d14, 75 d15, 76 d16, 77 d17, 78 d18, 79 d19, 80 d20, 81 d21, 82 d22, 83 d23, 84 d24, 85 d25, 86 d26, 87 d27, 88 d28, 89 d29, 90 d30, 91 d31 92 } FPRegisterID; 93 94 } // namespace ARMRegisters 95 96 class ARMAssembler { 97 public: 98 typedef ARMRegisters::RegisterID RegisterID; 99 typedef ARMRegisters::FPRegisterID FPRegisterID; 100 typedef AssemblerBufferWithConstantPool<2048, 4, 4, ARMAssembler> ARMBuffer; 101 typedef SegmentedVector<AssemblerLabel, 64> Jumps; 102 103 ARMAssembler() 104 : m_indexOfTailOfLastWatchpoint(1) 105 { 106 } 107 108 // ARM conditional constants 109 typedef enum { 110 EQ = 0x00000000, // Zero / Equal. 111 NE = 0x10000000, // Non-zero / Not equal. 112 CS = 0x20000000, // Unsigned higher or same. 113 CC = 0x30000000, // Unsigned lower. 114 MI = 0x40000000, // Negative. 115 PL = 0x50000000, // Positive or zero. 116 VS = 0x60000000, // Overflowed. 117 VC = 0x70000000, // Not overflowed. 118 HI = 0x80000000, // Unsigned higher. 119 LS = 0x90000000, // Unsigned lower or same. 120 GE = 0xa0000000, // Signed greater than or equal. 121 LT = 0xb0000000, // Signed less than. 122 GT = 0xc0000000, // Signed greater than. 123 LE = 0xd0000000, // Signed less than or equal. 124 AL = 0xe0000000 // Unconditional / Always execute. 125 } Condition; 126 127 // ARM instruction constants 128 enum { 129 AND = (0x0 << 21), 130 EOR = (0x1 << 21), 131 SUB = (0x2 << 21), 132 RSB = (0x3 << 21), 133 ADD = (0x4 << 21), 134 ADC = (0x5 << 21), 135 SBC = (0x6 << 21), 136 RSC = (0x7 << 21), 137 TST = (0x8 << 21), 138 TEQ = (0x9 << 21), 139 CMP = (0xa << 21), 140 CMN = (0xb << 21), 141 ORR = (0xc << 21), 142 MOV = (0xd << 21), 143 BIC = (0xe << 21), 144 MVN = (0xf << 21), 145 MUL = 0x00000090, 146 MULL = 0x00c00090, 147 VMOV_F64 = 0x0eb00b40, 148 VADD_F64 = 0x0e300b00, 149 VDIV_F64 = 0x0e800b00, 150 VSUB_F64 = 0x0e300b40, 151 VMUL_F64 = 0x0e200b00, 152 VCMP_F64 = 0x0eb40b40, 153 VSQRT_F64 = 0x0eb10bc0, 154 VABS_F64 = 0x0eb00bc0, 155 VNEG_F64 = 0x0eb10b40, 156 STMDB = 0x09200000, 157 LDMIA = 0x08b00000, 158 B = 0x0a000000, 159 BL = 0x0b000000, 160 BX = 0x012fff10, 161 VMOV_VFP64 = 0x0c400a10, 162 VMOV_ARM64 = 0x0c500a10, 163 VMOV_VFP32 = 0x0e000a10, 164 VMOV_ARM32 = 0x0e100a10, 165 VCVT_F64_S32 = 0x0eb80bc0, 166 VCVT_S32_F64 = 0x0ebd0bc0, 167 VCVT_U32_F64 = 0x0ebc0bc0, 168 VCVT_F32_F64 = 0x0eb70bc0, 169 VCVT_F64_F32 = 0x0eb70ac0, 170 VMRS_APSR = 0x0ef1fa10, 171 CLZ = 0x016f0f10, 172 BKPT = 0xe1200070, 173 BLX = 0x012fff30, 174#if WTF_ARM_ARCH_AT_LEAST(7) 175 MOVW = 0x03000000, 176 MOVT = 0x03400000, 177#endif 178 NOP = 0xe1a00000, 179 }; 180 181 enum { 182 Op2Immediate = (1 << 25), 183 ImmediateForHalfWordTransfer = (1 << 22), 184 Op2InvertedImmediate = (1 << 26), 185 SetConditionalCodes = (1 << 20), 186 Op2IsRegisterArgument = (1 << 25), 187 // Data transfer flags. 188 DataTransferUp = (1 << 23), 189 DataTransferWriteBack = (1 << 21), 190 DataTransferPostUpdate = (1 << 24), 191 DataTransferLoad = (1 << 20), 192 ByteDataTransfer = (1 << 22), 193 }; 194 195 enum DataTransferTypeA { 196 LoadUint32 = 0x05000000 | DataTransferLoad, 197 LoadUint8 = 0x05400000 | DataTransferLoad, 198 StoreUint32 = 0x05000000, 199 StoreUint8 = 0x05400000, 200 }; 201 202 enum DataTransferTypeB { 203 LoadUint16 = 0x010000b0 | DataTransferLoad, 204 LoadInt16 = 0x010000f0 | DataTransferLoad, 205 LoadInt8 = 0x010000d0 | DataTransferLoad, 206 StoreUint16 = 0x010000b0, 207 }; 208 209 enum DataTransferTypeFloat { 210 LoadFloat = 0x0d000a00 | DataTransferLoad, 211 LoadDouble = 0x0d000b00 | DataTransferLoad, 212 StoreFloat = 0x0d000a00, 213 StoreDouble = 0x0d000b00, 214 }; 215 216 // Masks of ARM instructions 217 enum { 218 BranchOffsetMask = 0x00ffffff, 219 ConditionalFieldMask = 0xf0000000, 220 DataTransferOffsetMask = 0xfff, 221 }; 222 223 enum { 224 MinimumBranchOffsetDistance = -0x00800000, 225 MaximumBranchOffsetDistance = 0x007fffff, 226 }; 227 228 enum { 229 padForAlign8 = 0x00, 230 padForAlign16 = 0x0000, 231 padForAlign32 = 0xe12fff7f // 'bkpt 0xffff' instruction. 232 }; 233 234 static const ARMWord InvalidImmediate = 0xf0000000; 235 static const ARMWord InvalidBranchTarget = 0xffffffff; 236 static const int DefaultPrefetchOffset = 2; 237 238 static const ARMWord BlxInstructionMask = 0x012fff30; 239 static const ARMWord LdrOrAddInstructionMask = 0x0ff00000; 240 static const ARMWord LdrPcImmediateInstructionMask = 0x0f7f0000; 241 242 static const ARMWord AddImmediateInstruction = 0x02800000; 243 static const ARMWord BlxInstruction = 0x012fff30; 244 static const ARMWord LdrImmediateInstruction = 0x05900000; 245 static const ARMWord LdrPcImmediateInstruction = 0x051f0000; 246 247 // Instruction formating 248 249 void emitInstruction(ARMWord op, int rd, int rn, ARMWord op2) 250 { 251 ASSERT(((op2 & ~Op2Immediate) <= 0xfff) || (((op2 & ~ImmediateForHalfWordTransfer) <= 0xfff))); 252 m_buffer.putInt(op | RN(rn) | RD(rd) | op2); 253 } 254 255 void emitDoublePrecisionInstruction(ARMWord op, int dd, int dn, int dm) 256 { 257 ASSERT((dd >= 0 && dd <= 31) && (dn >= 0 && dn <= 31) && (dm >= 0 && dm <= 31)); 258 m_buffer.putInt(op | ((dd & 0xf) << 12) | ((dd & 0x10) << (22 - 4)) 259 | ((dn & 0xf) << 16) | ((dn & 0x10) << (7 - 4)) 260 | (dm & 0xf) | ((dm & 0x10) << (5 - 4))); 261 } 262 263 void emitSinglePrecisionInstruction(ARMWord op, int sd, int sn, int sm) 264 { 265 ASSERT((sd >= 0 && sd <= 31) && (sn >= 0 && sn <= 31) && (sm >= 0 && sm <= 31)); 266 m_buffer.putInt(op | ((sd >> 1) << 12) | ((sd & 0x1) << 22) 267 | ((sn >> 1) << 16) | ((sn & 0x1) << 7) 268 | (sm >> 1) | ((sm & 0x1) << 5)); 269 } 270 271 void bitAnd(int rd, int rn, ARMWord op2, Condition cc = AL) 272 { 273 emitInstruction(toARMWord(cc) | AND, rd, rn, op2); 274 } 275 276 void bitAnds(int rd, int rn, ARMWord op2, Condition cc = AL) 277 { 278 emitInstruction(toARMWord(cc) | AND | SetConditionalCodes, rd, rn, op2); 279 } 280 281 void eor(int rd, int rn, ARMWord op2, Condition cc = AL) 282 { 283 emitInstruction(toARMWord(cc) | EOR, rd, rn, op2); 284 } 285 286 void eors(int rd, int rn, ARMWord op2, Condition cc = AL) 287 { 288 emitInstruction(toARMWord(cc) | EOR | SetConditionalCodes, rd, rn, op2); 289 } 290 291 void sub(int rd, int rn, ARMWord op2, Condition cc = AL) 292 { 293 emitInstruction(toARMWord(cc) | SUB, rd, rn, op2); 294 } 295 296 void subs(int rd, int rn, ARMWord op2, Condition cc = AL) 297 { 298 emitInstruction(toARMWord(cc) | SUB | SetConditionalCodes, rd, rn, op2); 299 } 300 301 void rsb(int rd, int rn, ARMWord op2, Condition cc = AL) 302 { 303 emitInstruction(toARMWord(cc) | RSB, rd, rn, op2); 304 } 305 306 void rsbs(int rd, int rn, ARMWord op2, Condition cc = AL) 307 { 308 emitInstruction(toARMWord(cc) | RSB | SetConditionalCodes, rd, rn, op2); 309 } 310 311 void add(int rd, int rn, ARMWord op2, Condition cc = AL) 312 { 313 emitInstruction(toARMWord(cc) | ADD, rd, rn, op2); 314 } 315 316 void adds(int rd, int rn, ARMWord op2, Condition cc = AL) 317 { 318 emitInstruction(toARMWord(cc) | ADD | SetConditionalCodes, rd, rn, op2); 319 } 320 321 void adc(int rd, int rn, ARMWord op2, Condition cc = AL) 322 { 323 emitInstruction(toARMWord(cc) | ADC, rd, rn, op2); 324 } 325 326 void adcs(int rd, int rn, ARMWord op2, Condition cc = AL) 327 { 328 emitInstruction(toARMWord(cc) | ADC | SetConditionalCodes, rd, rn, op2); 329 } 330 331 void sbc(int rd, int rn, ARMWord op2, Condition cc = AL) 332 { 333 emitInstruction(toARMWord(cc) | SBC, rd, rn, op2); 334 } 335 336 void sbcs(int rd, int rn, ARMWord op2, Condition cc = AL) 337 { 338 emitInstruction(toARMWord(cc) | SBC | SetConditionalCodes, rd, rn, op2); 339 } 340 341 void rsc(int rd, int rn, ARMWord op2, Condition cc = AL) 342 { 343 emitInstruction(toARMWord(cc) | RSC, rd, rn, op2); 344 } 345 346 void rscs(int rd, int rn, ARMWord op2, Condition cc = AL) 347 { 348 emitInstruction(toARMWord(cc) | RSC | SetConditionalCodes, rd, rn, op2); 349 } 350 351 void tst(int rn, ARMWord op2, Condition cc = AL) 352 { 353 emitInstruction(toARMWord(cc) | TST | SetConditionalCodes, 0, rn, op2); 354 } 355 356 void teq(int rn, ARMWord op2, Condition cc = AL) 357 { 358 emitInstruction(toARMWord(cc) | TEQ | SetConditionalCodes, 0, rn, op2); 359 } 360 361 void cmp(int rn, ARMWord op2, Condition cc = AL) 362 { 363 emitInstruction(toARMWord(cc) | CMP | SetConditionalCodes, 0, rn, op2); 364 } 365 366 void cmn(int rn, ARMWord op2, Condition cc = AL) 367 { 368 emitInstruction(toARMWord(cc) | CMN | SetConditionalCodes, 0, rn, op2); 369 } 370 371 void orr(int rd, int rn, ARMWord op2, Condition cc = AL) 372 { 373 emitInstruction(toARMWord(cc) | ORR, rd, rn, op2); 374 } 375 376 void orrs(int rd, int rn, ARMWord op2, Condition cc = AL) 377 { 378 emitInstruction(toARMWord(cc) | ORR | SetConditionalCodes, rd, rn, op2); 379 } 380 381 void mov(int rd, ARMWord op2, Condition cc = AL) 382 { 383 emitInstruction(toARMWord(cc) | MOV, rd, ARMRegisters::r0, op2); 384 } 385 386#if WTF_ARM_ARCH_AT_LEAST(7) 387 void movw(int rd, ARMWord op2, Condition cc = AL) 388 { 389 ASSERT((op2 | 0xf0fff) == 0xf0fff); 390 m_buffer.putInt(toARMWord(cc) | MOVW | RD(rd) | op2); 391 } 392 393 void movt(int rd, ARMWord op2, Condition cc = AL) 394 { 395 ASSERT((op2 | 0xf0fff) == 0xf0fff); 396 m_buffer.putInt(toARMWord(cc) | MOVT | RD(rd) | op2); 397 } 398#endif 399 400 void movs(int rd, ARMWord op2, Condition cc = AL) 401 { 402 emitInstruction(toARMWord(cc) | MOV | SetConditionalCodes, rd, ARMRegisters::r0, op2); 403 } 404 405 void bic(int rd, int rn, ARMWord op2, Condition cc = AL) 406 { 407 emitInstruction(toARMWord(cc) | BIC, rd, rn, op2); 408 } 409 410 void bics(int rd, int rn, ARMWord op2, Condition cc = AL) 411 { 412 emitInstruction(toARMWord(cc) | BIC | SetConditionalCodes, rd, rn, op2); 413 } 414 415 void mvn(int rd, ARMWord op2, Condition cc = AL) 416 { 417 emitInstruction(toARMWord(cc) | MVN, rd, ARMRegisters::r0, op2); 418 } 419 420 void mvns(int rd, ARMWord op2, Condition cc = AL) 421 { 422 emitInstruction(toARMWord(cc) | MVN | SetConditionalCodes, rd, ARMRegisters::r0, op2); 423 } 424 425 void mul(int rd, int rn, int rm, Condition cc = AL) 426 { 427 m_buffer.putInt(toARMWord(cc) | MUL | RN(rd) | RS(rn) | RM(rm)); 428 } 429 430 void muls(int rd, int rn, int rm, Condition cc = AL) 431 { 432 m_buffer.putInt(toARMWord(cc) | MUL | SetConditionalCodes | RN(rd) | RS(rn) | RM(rm)); 433 } 434 435 void mull(int rdhi, int rdlo, int rn, int rm, Condition cc = AL) 436 { 437 m_buffer.putInt(toARMWord(cc) | MULL | RN(rdhi) | RD(rdlo) | RS(rn) | RM(rm)); 438 } 439 440 void vmov_f64(int dd, int dm, Condition cc = AL) 441 { 442 emitDoublePrecisionInstruction(toARMWord(cc) | VMOV_F64, dd, 0, dm); 443 } 444 445 void vadd_f64(int dd, int dn, int dm, Condition cc = AL) 446 { 447 emitDoublePrecisionInstruction(toARMWord(cc) | VADD_F64, dd, dn, dm); 448 } 449 450 void vdiv_f64(int dd, int dn, int dm, Condition cc = AL) 451 { 452 emitDoublePrecisionInstruction(toARMWord(cc) | VDIV_F64, dd, dn, dm); 453 } 454 455 void vsub_f64(int dd, int dn, int dm, Condition cc = AL) 456 { 457 emitDoublePrecisionInstruction(toARMWord(cc) | VSUB_F64, dd, dn, dm); 458 } 459 460 void vmul_f64(int dd, int dn, int dm, Condition cc = AL) 461 { 462 emitDoublePrecisionInstruction(toARMWord(cc) | VMUL_F64, dd, dn, dm); 463 } 464 465 void vcmp_f64(int dd, int dm, Condition cc = AL) 466 { 467 emitDoublePrecisionInstruction(toARMWord(cc) | VCMP_F64, dd, 0, dm); 468 } 469 470 void vsqrt_f64(int dd, int dm, Condition cc = AL) 471 { 472 emitDoublePrecisionInstruction(toARMWord(cc) | VSQRT_F64, dd, 0, dm); 473 } 474 475 void vabs_f64(int dd, int dm, Condition cc = AL) 476 { 477 emitDoublePrecisionInstruction(toARMWord(cc) | VABS_F64, dd, 0, dm); 478 } 479 480 void vneg_f64(int dd, int dm, Condition cc = AL) 481 { 482 emitDoublePrecisionInstruction(toARMWord(cc) | VNEG_F64, dd, 0, dm); 483 } 484 485 void ldrImmediate(int rd, ARMWord imm, Condition cc = AL) 486 { 487 m_buffer.putIntWithConstantInt(toARMWord(cc) | LoadUint32 | DataTransferUp | RN(ARMRegisters::pc) | RD(rd), imm, true); 488 } 489 490 void ldrUniqueImmediate(int rd, ARMWord imm, Condition cc = AL) 491 { 492 m_buffer.putIntWithConstantInt(toARMWord(cc) | LoadUint32 | DataTransferUp | RN(ARMRegisters::pc) | RD(rd), imm); 493 } 494 495 void dtrUp(DataTransferTypeA transferType, int rd, int rb, ARMWord op2, Condition cc = AL) 496 { 497 emitInstruction(toARMWord(cc) | transferType | DataTransferUp, rd, rb, op2); 498 } 499 500 void dtrUpRegister(DataTransferTypeA transferType, int rd, int rb, int rm, Condition cc = AL) 501 { 502 emitInstruction(toARMWord(cc) | transferType | DataTransferUp | Op2IsRegisterArgument, rd, rb, rm); 503 } 504 505 void dtrDown(DataTransferTypeA transferType, int rd, int rb, ARMWord op2, Condition cc = AL) 506 { 507 emitInstruction(toARMWord(cc) | transferType, rd, rb, op2); 508 } 509 510 void dtrDownRegister(DataTransferTypeA transferType, int rd, int rb, int rm, Condition cc = AL) 511 { 512 emitInstruction(toARMWord(cc) | transferType | Op2IsRegisterArgument, rd, rb, rm); 513 } 514 515 void halfDtrUp(DataTransferTypeB transferType, int rd, int rb, ARMWord op2, Condition cc = AL) 516 { 517 emitInstruction(toARMWord(cc) | transferType | DataTransferUp, rd, rb, op2); 518 } 519 520 void halfDtrUpRegister(DataTransferTypeB transferType, int rd, int rn, int rm, Condition cc = AL) 521 { 522 emitInstruction(toARMWord(cc) | transferType | DataTransferUp, rd, rn, rm); 523 } 524 525 void halfDtrDown(DataTransferTypeB transferType, int rd, int rb, ARMWord op2, Condition cc = AL) 526 { 527 emitInstruction(toARMWord(cc) | transferType, rd, rb, op2); 528 } 529 530 void halfDtrDownRegister(DataTransferTypeB transferType, int rd, int rn, int rm, Condition cc = AL) 531 { 532 emitInstruction(toARMWord(cc) | transferType, rd, rn, rm); 533 } 534 535 void doubleDtrUp(DataTransferTypeFloat type, int rd, int rb, ARMWord op2, Condition cc = AL) 536 { 537 ASSERT(op2 <= 0xff && rd <= 15); 538 /* Only d0-d15 and s0, s2, s4 ... s30 are supported. */ 539 m_buffer.putInt(toARMWord(cc) | DataTransferUp | type | (rd << 12) | RN(rb) | op2); 540 } 541 542 void doubleDtrDown(DataTransferTypeFloat type, int rd, int rb, ARMWord op2, Condition cc = AL) 543 { 544 ASSERT(op2 <= 0xff && rd <= 15); 545 /* Only d0-d15 and s0, s2, s4 ... s30 are supported. */ 546 m_buffer.putInt(toARMWord(cc) | type | (rd << 12) | RN(rb) | op2); 547 } 548 549 void push(int reg, Condition cc = AL) 550 { 551 ASSERT(ARMWord(reg) <= 0xf); 552 m_buffer.putInt(toARMWord(cc) | StoreUint32 | DataTransferWriteBack | RN(ARMRegisters::sp) | RD(reg) | 0x4); 553 } 554 555 void pop(int reg, Condition cc = AL) 556 { 557 ASSERT(ARMWord(reg) <= 0xf); 558 m_buffer.putInt(toARMWord(cc) | (LoadUint32 ^ DataTransferPostUpdate) | DataTransferUp | RN(ARMRegisters::sp) | RD(reg) | 0x4); 559 } 560 561 inline void poke(int reg, Condition cc = AL) 562 { 563 dtrDown(StoreUint32, ARMRegisters::sp, 0, reg, cc); 564 } 565 566 inline void peek(int reg, Condition cc = AL) 567 { 568 dtrUp(LoadUint32, reg, ARMRegisters::sp, 0, cc); 569 } 570 571 void vmov_vfp64(int sm, int rt, int rt2, Condition cc = AL) 572 { 573 ASSERT(rt != rt2); 574 m_buffer.putInt(toARMWord(cc) | VMOV_VFP64 | RN(rt2) | RD(rt) | (sm & 0xf) | ((sm & 0x10) << (5 - 4))); 575 } 576 577 void vmov_arm64(int rt, int rt2, int sm, Condition cc = AL) 578 { 579 ASSERT(rt != rt2); 580 m_buffer.putInt(toARMWord(cc) | VMOV_ARM64 | RN(rt2) | RD(rt) | (sm & 0xf) | ((sm & 0x10) << (5 - 4))); 581 } 582 583 void vmov_vfp32(int sn, int rt, Condition cc = AL) 584 { 585 ASSERT(rt <= 15); 586 emitSinglePrecisionInstruction(toARMWord(cc) | VMOV_VFP32, rt << 1, sn, 0); 587 } 588 589 void vmov_arm32(int rt, int sn, Condition cc = AL) 590 { 591 ASSERT(rt <= 15); 592 emitSinglePrecisionInstruction(toARMWord(cc) | VMOV_ARM32, rt << 1, sn, 0); 593 } 594 595 void vcvt_f64_s32(int dd, int sm, Condition cc = AL) 596 { 597 ASSERT(!(sm & 0x1)); // sm must be divisible by 2 598 emitDoublePrecisionInstruction(toARMWord(cc) | VCVT_F64_S32, dd, 0, (sm >> 1)); 599 } 600 601 void vcvt_s32_f64(int sd, int dm, Condition cc = AL) 602 { 603 ASSERT(!(sd & 0x1)); // sd must be divisible by 2 604 emitDoublePrecisionInstruction(toARMWord(cc) | VCVT_S32_F64, (sd >> 1), 0, dm); 605 } 606 607 void vcvt_u32_f64(int sd, int dm, Condition cc = AL) 608 { 609 ASSERT(!(sd & 0x1)); // sd must be divisible by 2 610 emitDoublePrecisionInstruction(toARMWord(cc) | VCVT_U32_F64, (sd >> 1), 0, dm); 611 } 612 613 void vcvt_f64_f32(int dd, int sm, Condition cc = AL) 614 { 615 ASSERT(dd <= 15 && sm <= 15); 616 emitDoublePrecisionInstruction(toARMWord(cc) | VCVT_F64_F32, dd, 0, sm); 617 } 618 619 void vcvt_f32_f64(int dd, int sm, Condition cc = AL) 620 { 621 ASSERT(dd <= 15 && sm <= 15); 622 emitDoublePrecisionInstruction(toARMWord(cc) | VCVT_F32_F64, dd, 0, sm); 623 } 624 625 void vmrs_apsr(Condition cc = AL) 626 { 627 m_buffer.putInt(toARMWord(cc) | VMRS_APSR); 628 } 629 630 void clz(int rd, int rm, Condition cc = AL) 631 { 632 m_buffer.putInt(toARMWord(cc) | CLZ | RD(rd) | RM(rm)); 633 } 634 635 void bkpt(ARMWord value) 636 { 637 m_buffer.putInt(BKPT | ((value & 0xff0) << 4) | (value & 0xf)); 638 } 639 640 void nop() 641 { 642 m_buffer.putInt(NOP); 643 } 644 645 void bx(int rm, Condition cc = AL) 646 { 647 emitInstruction(toARMWord(cc) | BX, 0, 0, RM(rm)); 648 } 649 650 AssemblerLabel blx(int rm, Condition cc = AL) 651 { 652 emitInstruction(toARMWord(cc) | BLX, 0, 0, RM(rm)); 653 return m_buffer.label(); 654 } 655 656 static ARMWord lsl(int reg, ARMWord value) 657 { 658 ASSERT(reg <= ARMRegisters::pc); 659 ASSERT(value <= 0x1f); 660 return reg | (value << 7) | 0x00; 661 } 662 663 static ARMWord lsr(int reg, ARMWord value) 664 { 665 ASSERT(reg <= ARMRegisters::pc); 666 ASSERT(value <= 0x1f); 667 return reg | (value << 7) | 0x20; 668 } 669 670 static ARMWord asr(int reg, ARMWord value) 671 { 672 ASSERT(reg <= ARMRegisters::pc); 673 ASSERT(value <= 0x1f); 674 return reg | (value << 7) | 0x40; 675 } 676 677 static ARMWord lslRegister(int reg, int shiftReg) 678 { 679 ASSERT(reg <= ARMRegisters::pc); 680 ASSERT(shiftReg <= ARMRegisters::pc); 681 return reg | (shiftReg << 8) | 0x10; 682 } 683 684 static ARMWord lsrRegister(int reg, int shiftReg) 685 { 686 ASSERT(reg <= ARMRegisters::pc); 687 ASSERT(shiftReg <= ARMRegisters::pc); 688 return reg | (shiftReg << 8) | 0x30; 689 } 690 691 static ARMWord asrRegister(int reg, int shiftReg) 692 { 693 ASSERT(reg <= ARMRegisters::pc); 694 ASSERT(shiftReg <= ARMRegisters::pc); 695 return reg | (shiftReg << 8) | 0x50; 696 } 697 698 // General helpers 699 700 size_t codeSize() const 701 { 702 return m_buffer.codeSize(); 703 } 704 705 void ensureSpace(int insnSpace, int constSpace) 706 { 707 m_buffer.ensureSpace(insnSpace, constSpace); 708 } 709 710 int sizeOfConstantPool() 711 { 712 return m_buffer.sizeOfConstantPool(); 713 } 714 715 AssemblerLabel labelIgnoringWatchpoints() 716 { 717 m_buffer.ensureSpaceForAnyInstruction(); 718 return m_buffer.label(); 719 } 720 721 AssemblerLabel labelForWatchpoint() 722 { 723 m_buffer.ensureSpaceForAnyInstruction(maxJumpReplacementSize() / sizeof(ARMWord)); 724 AssemblerLabel result = m_buffer.label(); 725 if (result.m_offset != (m_indexOfTailOfLastWatchpoint - maxJumpReplacementSize())) 726 result = label(); 727 m_indexOfTailOfLastWatchpoint = result.m_offset + maxJumpReplacementSize(); 728 return label(); 729 } 730 731 AssemblerLabel label() 732 { 733 AssemblerLabel result = labelIgnoringWatchpoints(); 734 while (result.m_offset + 1 < m_indexOfTailOfLastWatchpoint) { 735 nop(); 736 // The available number of instructions are ensured by labelForWatchpoint. 737 result = m_buffer.label(); 738 } 739 return result; 740 } 741 742 AssemblerLabel align(int alignment) 743 { 744 while (!m_buffer.isAligned(alignment)) 745 mov(ARMRegisters::r0, ARMRegisters::r0); 746 747 return label(); 748 } 749 750 AssemblerLabel loadBranchTarget(int rd, Condition cc = AL, int useConstantPool = 0) 751 { 752 ensureSpace(sizeof(ARMWord), sizeof(ARMWord)); 753 m_jumps.append(m_buffer.codeSize() | (useConstantPool & 0x1)); 754 ldrUniqueImmediate(rd, InvalidBranchTarget, cc); 755 return m_buffer.label(); 756 } 757 758 AssemblerLabel jmp(Condition cc = AL, int useConstantPool = 0) 759 { 760 return loadBranchTarget(ARMRegisters::pc, cc, useConstantPool); 761 } 762 763 PassRefPtr<ExecutableMemoryHandle> executableCopy(VM&, void* ownerUID, JITCompilationEffort); 764 765 unsigned debugOffset() { return m_buffer.debugOffset(); } 766 767 // DFG assembly helpers for moving data between fp and registers. 768 void vmov(RegisterID rd1, RegisterID rd2, FPRegisterID rn) 769 { 770 vmov_arm64(rd1, rd2, rn); 771 } 772 773 void vmov(FPRegisterID rd, RegisterID rn1, RegisterID rn2) 774 { 775 vmov_vfp64(rd, rn1, rn2); 776 } 777 778 // Patching helpers 779 780 static ARMWord* getLdrImmAddress(ARMWord* insn) 781 { 782 // Check for call 783 if ((*insn & LdrPcImmediateInstructionMask) != LdrPcImmediateInstruction) { 784 // Must be BLX 785 ASSERT((*insn & BlxInstructionMask) == BlxInstruction); 786 insn--; 787 } 788 789 // Must be an ldr ..., [pc +/- imm] 790 ASSERT((*insn & LdrPcImmediateInstructionMask) == LdrPcImmediateInstruction); 791 792 ARMWord addr = reinterpret_cast<ARMWord>(insn) + DefaultPrefetchOffset * sizeof(ARMWord); 793 if (*insn & DataTransferUp) 794 return reinterpret_cast<ARMWord*>(addr + (*insn & DataTransferOffsetMask)); 795 return reinterpret_cast<ARMWord*>(addr - (*insn & DataTransferOffsetMask)); 796 } 797 798 static ARMWord* getLdrImmAddressOnPool(ARMWord* insn, uint32_t* constPool) 799 { 800 // Must be an ldr ..., [pc +/- imm] 801 ASSERT((*insn & LdrPcImmediateInstructionMask) == LdrPcImmediateInstruction); 802 803 if (*insn & 0x1) 804 return reinterpret_cast<ARMWord*>(constPool + ((*insn & DataTransferOffsetMask) >> 1)); 805 return getLdrImmAddress(insn); 806 } 807 808 static void patchPointerInternal(intptr_t from, void* to) 809 { 810 ARMWord* insn = reinterpret_cast<ARMWord*>(from); 811 ARMWord* addr = getLdrImmAddress(insn); 812 *addr = reinterpret_cast<ARMWord>(to); 813 } 814 815 static ARMWord patchConstantPoolLoad(ARMWord load, ARMWord value) 816 { 817 value = (value << 1) + 1; 818 ASSERT(!(value & ~DataTransferOffsetMask)); 819 return (load & ~DataTransferOffsetMask) | value; 820 } 821 822 static void patchConstantPoolLoad(void* loadAddr, void* constPoolAddr); 823 824 // Read pointers 825 static void* readPointer(void* from) 826 { 827 ARMWord* instruction = reinterpret_cast<ARMWord*>(from); 828 ARMWord* address = getLdrImmAddress(instruction); 829 return *reinterpret_cast<void**>(address); 830 } 831 832 // Patch pointers 833 834 static void linkPointer(void* code, AssemblerLabel from, void* to) 835 { 836 patchPointerInternal(reinterpret_cast<intptr_t>(code) + from.m_offset, to); 837 } 838 839 static void repatchInt32(void* where, int32_t to) 840 { 841 patchPointerInternal(reinterpret_cast<intptr_t>(where), reinterpret_cast<void*>(to)); 842 } 843 844 static void repatchCompact(void* where, int32_t value) 845 { 846 ARMWord* instruction = reinterpret_cast<ARMWord*>(where); 847 ASSERT((*instruction & 0x0f700000) == LoadUint32); 848 if (value >= 0) 849 *instruction = (*instruction & 0xff7ff000) | DataTransferUp | value; 850 else 851 *instruction = (*instruction & 0xff7ff000) | -value; 852 cacheFlush(instruction, sizeof(ARMWord)); 853 } 854 855 static void repatchPointer(void* from, void* to) 856 { 857 patchPointerInternal(reinterpret_cast<intptr_t>(from), to); 858 } 859 860 // Linkers 861 static intptr_t getAbsoluteJumpAddress(void* base, int offset = 0) 862 { 863 return reinterpret_cast<intptr_t>(base) + offset - sizeof(ARMWord); 864 } 865 866 void linkJump(AssemblerLabel from, AssemblerLabel to) 867 { 868 ARMWord* insn = reinterpret_cast<ARMWord*>(getAbsoluteJumpAddress(m_buffer.data(), from.m_offset)); 869 ARMWord* addr = getLdrImmAddressOnPool(insn, m_buffer.poolAddress()); 870 *addr = toARMWord(to.m_offset); 871 } 872 873 static void linkJump(void* code, AssemblerLabel from, void* to) 874 { 875 patchPointerInternal(getAbsoluteJumpAddress(code, from.m_offset), to); 876 } 877 878 static void relinkJump(void* from, void* to) 879 { 880 patchPointerInternal(getAbsoluteJumpAddress(from), to); 881 } 882 883 static void linkCall(void* code, AssemblerLabel from, void* to) 884 { 885 patchPointerInternal(getAbsoluteJumpAddress(code, from.m_offset), to); 886 } 887 888 static void relinkCall(void* from, void* to) 889 { 890 patchPointerInternal(getAbsoluteJumpAddress(from), to); 891 } 892 893 static void* readCallTarget(void* from) 894 { 895 return reinterpret_cast<void*>(readPointer(reinterpret_cast<void*>(getAbsoluteJumpAddress(from)))); 896 } 897 898 static void replaceWithJump(void* instructionStart, void* to) 899 { 900 ARMWord* instruction = reinterpret_cast<ARMWord*>(instructionStart); 901 intptr_t difference = reinterpret_cast<intptr_t>(to) - (reinterpret_cast<intptr_t>(instruction) + DefaultPrefetchOffset * sizeof(ARMWord)); 902 903 if (!(difference & 1)) { 904 difference >>= 2; 905 if ((difference <= MaximumBranchOffsetDistance && difference >= MinimumBranchOffsetDistance)) { 906 // Direct branch. 907 instruction[0] = B | AL | (difference & BranchOffsetMask); 908 cacheFlush(instruction, sizeof(ARMWord)); 909 return; 910 } 911 } 912 913 // Load target. 914 instruction[0] = LoadUint32 | AL | RN(ARMRegisters::pc) | RD(ARMRegisters::pc) | 4; 915 instruction[1] = reinterpret_cast<ARMWord>(to); 916 cacheFlush(instruction, sizeof(ARMWord) * 2); 917 } 918 919 static ptrdiff_t maxJumpReplacementSize() 920 { 921 return sizeof(ARMWord) * 2; 922 } 923 924 static void replaceWithLoad(void* instructionStart) 925 { 926 ARMWord* instruction = reinterpret_cast<ARMWord*>(instructionStart); 927 cacheFlush(instruction, sizeof(ARMWord)); 928 929 ASSERT((*instruction & LdrOrAddInstructionMask) == AddImmediateInstruction || (*instruction & LdrOrAddInstructionMask) == LdrImmediateInstruction); 930 if ((*instruction & LdrOrAddInstructionMask) == AddImmediateInstruction) { 931 *instruction = (*instruction & ~LdrOrAddInstructionMask) | LdrImmediateInstruction; 932 cacheFlush(instruction, sizeof(ARMWord)); 933 } 934 } 935 936 static void replaceWithAddressComputation(void* instructionStart) 937 { 938 ARMWord* instruction = reinterpret_cast<ARMWord*>(instructionStart); 939 cacheFlush(instruction, sizeof(ARMWord)); 940 941 ASSERT((*instruction & LdrOrAddInstructionMask) == AddImmediateInstruction || (*instruction & LdrOrAddInstructionMask) == LdrImmediateInstruction); 942 if ((*instruction & LdrOrAddInstructionMask) == LdrImmediateInstruction) { 943 *instruction = (*instruction & ~LdrOrAddInstructionMask) | AddImmediateInstruction; 944 cacheFlush(instruction, sizeof(ARMWord)); 945 } 946 } 947 948 static void revertBranchPtrWithPatch(void* instructionStart, RegisterID rn, ARMWord imm) 949 { 950 ARMWord* instruction = reinterpret_cast<ARMWord*>(instructionStart); 951 952 ASSERT((instruction[2] & LdrPcImmediateInstructionMask) == LdrPcImmediateInstruction); 953 instruction[0] = toARMWord(AL) | ((instruction[2] & 0x0fff0fff) + sizeof(ARMWord)) | RD(ARMRegisters::S1); 954 *getLdrImmAddress(instruction) = imm; 955 instruction[1] = toARMWord(AL) | CMP | SetConditionalCodes | RN(rn) | RM(ARMRegisters::S1); 956 cacheFlush(instruction, 2 * sizeof(ARMWord)); 957 } 958 959 // Address operations 960 961 static void* getRelocatedAddress(void* code, AssemblerLabel label) 962 { 963 return reinterpret_cast<void*>(reinterpret_cast<char*>(code) + label.m_offset); 964 } 965 966 // Address differences 967 968 static int getDifferenceBetweenLabels(AssemblerLabel a, AssemblerLabel b) 969 { 970 return b.m_offset - a.m_offset; 971 } 972 973 static unsigned getCallReturnOffset(AssemblerLabel call) 974 { 975 return call.m_offset; 976 } 977 978 // Handle immediates 979 980 static ARMWord getOp2(ARMWord imm); 981 982 // Fast case if imm is known to be between 0 and 0xff 983 static ARMWord getOp2Byte(ARMWord imm) 984 { 985 ASSERT(imm <= 0xff); 986 return Op2Immediate | imm; 987 } 988 989 static ARMWord getOp2Half(ARMWord imm) 990 { 991 ASSERT(imm <= 0xff); 992 return ImmediateForHalfWordTransfer | (imm & 0x0f) | ((imm & 0xf0) << 4); 993 } 994 995#if WTF_ARM_ARCH_AT_LEAST(7) 996 static ARMWord getImm16Op2(ARMWord imm) 997 { 998 if (imm <= 0xffff) 999 return (imm & 0xf000) << 4 | (imm & 0xfff); 1000 return InvalidImmediate; 1001 } 1002#endif 1003 ARMWord getImm(ARMWord imm, int tmpReg, bool invert = false); 1004 void moveImm(ARMWord imm, int dest); 1005 ARMWord encodeComplexImm(ARMWord imm, int dest); 1006 1007 // Memory load/store helpers 1008 1009 void dataTransfer32(DataTransferTypeA, RegisterID srcDst, RegisterID base, int32_t offset); 1010 void baseIndexTransfer32(DataTransferTypeA, RegisterID srcDst, RegisterID base, RegisterID index, int scale, int32_t offset); 1011 void dataTransfer16(DataTransferTypeB, RegisterID srcDst, RegisterID base, int32_t offset); 1012 void baseIndexTransfer16(DataTransferTypeB, RegisterID srcDst, RegisterID base, RegisterID index, int scale, int32_t offset); 1013 void dataTransferFloat(DataTransferTypeFloat, FPRegisterID srcDst, RegisterID base, int32_t offset); 1014 void baseIndexTransferFloat(DataTransferTypeFloat, FPRegisterID srcDst, RegisterID base, RegisterID index, int scale, int32_t offset); 1015 1016 // Constant pool hnadlers 1017 1018 static ARMWord placeConstantPoolBarrier(int offset) 1019 { 1020 offset = (offset - sizeof(ARMWord)) >> 2; 1021 ASSERT((offset <= MaximumBranchOffsetDistance && offset >= MinimumBranchOffsetDistance)); 1022 return AL | B | (offset & BranchOffsetMask); 1023 } 1024 1025#if OS(LINUX) && COMPILER(GCC) 1026 static inline void linuxPageFlush(uintptr_t begin, uintptr_t end) 1027 { 1028 asm volatile( 1029 "push {r7}\n" 1030 "mov r0, %0\n" 1031 "mov r1, %1\n" 1032 "mov r7, #0xf0000\n" 1033 "add r7, r7, #0x2\n" 1034 "mov r2, #0x0\n" 1035 "svc 0x0\n" 1036 "pop {r7}\n" 1037 : 1038 : "r" (begin), "r" (end) 1039 : "r0", "r1", "r2"); 1040 } 1041#endif 1042 1043#if OS(LINUX) && COMPILER(RVCT) 1044 static __asm void cacheFlush(void* code, size_t); 1045#else 1046 static void cacheFlush(void* code, size_t size) 1047 { 1048#if OS(LINUX) && COMPILER(GCC) 1049 size_t page = pageSize(); 1050 uintptr_t current = reinterpret_cast<uintptr_t>(code); 1051 uintptr_t end = current + size; 1052 uintptr_t firstPageEnd = (current & ~(page - 1)) + page; 1053 1054 if (end <= firstPageEnd) { 1055 linuxPageFlush(current, end); 1056 return; 1057 } 1058 1059 linuxPageFlush(current, firstPageEnd); 1060 1061 for (current = firstPageEnd; current + page < end; current += page) 1062 linuxPageFlush(current, current + page); 1063 1064 linuxPageFlush(current, end); 1065#elif OS(WINCE) 1066 CacheRangeFlush(code, size, CACHE_SYNC_ALL); 1067#elif OS(QNX) && ENABLE(ASSEMBLER_WX_EXCLUSIVE) 1068 UNUSED_PARAM(code); 1069 UNUSED_PARAM(size); 1070#elif OS(QNX) 1071 msync(code, size, MS_INVALIDATE_ICACHE); 1072#else 1073#error "The cacheFlush support is missing on this platform." 1074#endif 1075 } 1076#endif 1077 1078 private: 1079 static ARMWord RM(int reg) 1080 { 1081 ASSERT(reg <= ARMRegisters::pc); 1082 return reg; 1083 } 1084 1085 static ARMWord RS(int reg) 1086 { 1087 ASSERT(reg <= ARMRegisters::pc); 1088 return reg << 8; 1089 } 1090 1091 static ARMWord RD(int reg) 1092 { 1093 ASSERT(reg <= ARMRegisters::pc); 1094 return reg << 12; 1095 } 1096 1097 static ARMWord RN(int reg) 1098 { 1099 ASSERT(reg <= ARMRegisters::pc); 1100 return reg << 16; 1101 } 1102 1103 static ARMWord getConditionalField(ARMWord i) 1104 { 1105 return i & ConditionalFieldMask; 1106 } 1107 1108 static ARMWord toARMWord(Condition cc) 1109 { 1110 return static_cast<ARMWord>(cc); 1111 } 1112 1113 static ARMWord toARMWord(uint32_t u) 1114 { 1115 return static_cast<ARMWord>(u); 1116 } 1117 1118 int genInt(int reg, ARMWord imm, bool positive); 1119 1120 ARMBuffer m_buffer; 1121 Jumps m_jumps; 1122 uint32_t m_indexOfTailOfLastWatchpoint; 1123 }; 1124 1125} // namespace JSC 1126 1127#endif // ENABLE(ASSEMBLER) && CPU(ARM_TRADITIONAL) 1128 1129#endif // ARMAssembler_h 1130