1 // Copyright 2013, ARM Limited 2 // All rights reserved. 3 // 4 // Redistribution and use in source and binary forms, with or without 5 // modification, are permitted provided that the following conditions are met: 6 // 7 // * Redistributions of source code must retain the above copyright notice, 8 // this list of conditions and the following disclaimer. 9 // * Redistributions in binary form must reproduce the above copyright notice, 10 // this list of conditions and the following disclaimer in the documentation 11 // and/or other materials provided with the distribution. 12 // * Neither the name of ARM Limited nor the names of its contributors may be 13 // used to endorse or promote products derived from this software without 14 // specific prior written permission. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND 17 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 20 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 // OR TORT (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 #include "a64/macro-assembler-a64.h" 28 namespace vixl { 29 30 void MacroAssembler::B(Label* label, BranchType type, Register reg, int bit) { 31 VIXL_ASSERT((reg.Is(NoReg) || (type >= kBranchTypeFirstUsingReg)) && 32 ((bit == -1) || (type >= kBranchTypeFirstUsingBit))); 33 if (kBranchTypeFirstCondition <= type && type <= kBranchTypeLastCondition) { 34 B(static_cast<Condition>(type), label); 35 } else { 36 switch (type) { 37 case always: B(label); break; 38 case never: break; 39 case reg_zero: Cbz(reg, label); break; 40 case reg_not_zero: Cbnz(reg, label); break; 41 case reg_bit_clear: Tbz(reg, bit, label); break; 42 case reg_bit_set: Tbnz(reg, bit, label); break; 43 default: 44 VIXL_UNREACHABLE(); 45 } 46 } 47 } 48 49 void MacroAssembler::And(const Register& rd, 50 const Register& rn, 51 const Operand& operand) { 52 VIXL_ASSERT(allow_macro_instructions_); 53 LogicalMacro(rd, rn, operand, AND); 54 } 55 56 57 void MacroAssembler::Ands(const Register& rd, 58 const Register& rn, 59 const Operand& operand) { 60 VIXL_ASSERT(allow_macro_instructions_); 61 LogicalMacro(rd, rn, operand, ANDS); 62 } 63 64 65 void MacroAssembler::Tst(const Register& rn, 66 const Operand& operand) { 67 VIXL_ASSERT(allow_macro_instructions_); 68 Ands(AppropriateZeroRegFor(rn), rn, operand); 69 } 70 71 72 void MacroAssembler::Bic(const Register& rd, 73 const Register& rn, 74 const Operand& operand) { 75 VIXL_ASSERT(allow_macro_instructions_); 76 LogicalMacro(rd, rn, operand, BIC); 77 } 78 79 80 void MacroAssembler::Bics(const Register& rd, 81 const Register& rn, 82 const Operand& operand) { 83 VIXL_ASSERT(allow_macro_instructions_); 84 LogicalMacro(rd, rn, operand, BICS); 85 } 86 87 88 void MacroAssembler::Orr(const Register& rd, 89 const Register& rn, 90 const Operand& operand) { 91 VIXL_ASSERT(allow_macro_instructions_); 92 LogicalMacro(rd, rn, operand, ORR); 93 } 94 95 96 void MacroAssembler::Orn(const Register& rd, 97 const Register& rn, 98 const Operand& operand) { 99 VIXL_ASSERT(allow_macro_instructions_); 100 LogicalMacro(rd, rn, operand, ORN); 101 } 102 103 104 void MacroAssembler::Eor(const Register& rd, 105 const Register& rn, 106 const Operand& operand) { 107 VIXL_ASSERT(allow_macro_instructions_); 108 LogicalMacro(rd, rn, operand, EOR); 109 } 110 111 112 void MacroAssembler::Eon(const Register& rd, 113 const Register& rn, 114 const Operand& operand) { 115 VIXL_ASSERT(allow_macro_instructions_); 116 LogicalMacro(rd, rn, operand, EON); 117 } 118 119 120 void MacroAssembler::LogicalMacro(const Register& rd, 121 const Register& rn, 122 const Operand& operand, 123 LogicalOp op) { 124 UseScratchRegisterScope temps(this); 125 126 if (operand.IsImmediate()) { 127 int64_t immediate = operand.immediate(); 128 unsigned reg_size = rd.size(); 129 VIXL_ASSERT(rd.Is64Bits() || is_uint32(immediate)); 130 131 // If the operation is NOT, invert the operation and immediate. 132 if ((op & NOT) == NOT) { 133 op = static_cast<LogicalOp>(op & ~NOT); 134 immediate = ~immediate; 135 if (rd.Is32Bits()) { 136 immediate &= kWRegMask; 137 } 138 } 139 140 // Special cases for all set or all clear immediates. 141 if (immediate == 0) { 142 switch (op) { 143 case AND: 144 Mov(rd, 0); 145 return; 146 case ORR: // Fall through. 147 case EOR: 148 Mov(rd, rn); 149 return; 150 case ANDS: // Fall through. 151 case BICS: 152 break; 153 default: 154 VIXL_UNREACHABLE(); 155 } 156 } else if ((rd.Is64Bits() && (immediate == -1)) || 157 (rd.Is32Bits() && (immediate == 0xffffffff))) { 158 switch (op) { 159 case AND: 160 Mov(rd, rn); 161 return; 162 case ORR: 163 Mov(rd, immediate); 164 return; 165 case EOR: 166 Mvn(rd, rn); 167 return; 168 case ANDS: // Fall through. 169 case BICS: 170 break; 171 default: 172 VIXL_UNREACHABLE(); 173 } 174 } 175 176 unsigned n, imm_s, imm_r; 177 if (IsImmLogical(immediate, reg_size, &n, &imm_s, &imm_r)) { 178 // Immediate can be encoded in the instruction. 179 LogicalImmediate(rd, rn, n, imm_s, imm_r, op); 180 } else { 181 // Immediate can't be encoded: synthesize using move immediate. 182 Register temp = temps.AcquireSameSizeAs(rn); 183 Mov(temp, immediate); 184 if (rd.Is(sp)) { 185 // If rd is the stack pointer we cannot use it as the destination 186 // register so we use the temp register as an intermediate again. 187 Logical(temp, rn, Operand(temp), op); 188 Mov(sp, temp); 189 } else { 190 Logical(rd, rn, Operand(temp), op); 191 } 192 } 193 } else if (operand.IsExtendedRegister()) { 194 VIXL_ASSERT(operand.reg().size() <= rd.size()); 195 // Add/sub extended supports shift <= 4. We want to support exactly the 196 // same modes here. 197 VIXL_ASSERT(operand.shift_amount() <= 4); 198 VIXL_ASSERT(operand.reg().Is64Bits() || 199 ((operand.extend() != UXTX) && (operand.extend() != SXTX))); 200 201 temps.Exclude(operand.reg()); 202 Register temp = temps.AcquireSameSizeAs(rn); 203 EmitExtendShift(temp, operand.reg(), operand.extend(), 204 operand.shift_amount()); 205 Logical(rd, rn, Operand(temp), op); 206 } else { 207 // The operand can be encoded in the instruction. 208 VIXL_ASSERT(operand.IsShiftedRegister()); 209 Logical(rd, rn, operand, op); 210 } 211 } 212 213 214 void MacroAssembler::Mov(const Register& rd, 215 const Operand& operand, 216 DiscardMoveMode discard_mode) { 217 VIXL_ASSERT(allow_macro_instructions_); 218 if (operand.IsImmediate()) { 219 // Call the macro assembler for generic immediates. 220 Mov(rd, operand.immediate()); 221 } else if (operand.IsShiftedRegister() && (operand.shift_amount() != 0)) { 222 // Emit a shift instruction if moving a shifted register. This operation 223 // could also be achieved using an orr instruction (like orn used by Mvn), 224 // but using a shift instruction makes the disassembly clearer. 225 EmitShift(rd, operand.reg(), operand.shift(), operand.shift_amount()); 226 } else if (operand.IsExtendedRegister()) { 227 // Emit an extend instruction if moving an extended register. This handles 228 // extend with post-shift operations, too. 229 EmitExtendShift(rd, operand.reg(), operand.extend(), 230 operand.shift_amount()); 231 } else { 232 // Otherwise, emit a register move only if the registers are distinct, or 233 // if they are not X registers. 234 // 235 // Note that mov(w0, w0) is not a no-op because it clears the top word of 236 // x0. A flag is provided (kDiscardForSameWReg) if a move between the same W 237 // registers is not required to clear the top word of the X register. In 238 // this case, the instruction is discarded. 239 // 240 // If the sp is an operand, add #0 is emitted, otherwise, orr #0. 241 if (!rd.Is(operand.reg()) || (rd.Is32Bits() && 242 (discard_mode == kDontDiscardForSameWReg))) { 243 mov(rd, operand.reg()); 244 } 245 } 246 } 247 248 249 void MacroAssembler::Mvn(const Register& rd, const Operand& operand) { 250 VIXL_ASSERT(allow_macro_instructions_); 251 if (operand.IsImmediate()) { 252 // Call the macro assembler for generic immediates. 253 Mvn(rd, operand.immediate()); 254 } else if (operand.IsExtendedRegister()) { 255 UseScratchRegisterScope temps(this); 256 temps.Exclude(operand.reg()); 257 258 // Emit two instructions for the extend case. This differs from Mov, as 259 // the extend and invert can't be achieved in one instruction. 260 Register temp = temps.AcquireSameSizeAs(rd); 261 EmitExtendShift(temp, operand.reg(), operand.extend(), 262 operand.shift_amount()); 263 mvn(rd, Operand(temp)); 264 } else { 265 // Otherwise, register and shifted register cases can be handled by the 266 // assembler directly, using orn. 267 mvn(rd, operand); 268 } 269 } 270 271 272 void MacroAssembler::Mov(const Register& rd, uint64_t imm) { 273 VIXL_ASSERT(allow_macro_instructions_); 274 VIXL_ASSERT(is_uint32(imm) || is_int32(imm) || rd.Is64Bits()); 275 276 // Immediates on Aarch64 can be produced using an initial value, and zero to 277 // three move keep operations. 278 // 279 // Initial values can be generated with: 280 // 1. 64-bit move zero (movz). 281 // 2. 32-bit move inverted (movn). 282 // 3. 64-bit move inverted. 283 // 4. 32-bit orr immediate. 284 // 5. 64-bit orr immediate. 285 // Move-keep may then be used to modify each of the 16-bit half words. 286 // 287 // The code below supports all five initial value generators, and 288 // applying move-keep operations to move-zero and move-inverted initial 289 // values. 290 291 unsigned reg_size = rd.size(); 292 unsigned n, imm_s, imm_r; 293 if (IsImmMovz(imm, reg_size) && !rd.IsSP()) { 294 // Immediate can be represented in a move zero instruction. Movz can't 295 // write to the stack pointer. 296 movz(rd, imm); 297 } else if (IsImmMovn(imm, reg_size) && !rd.IsSP()) { 298 // Immediate can be represented in a move negative instruction. Movn can't 299 // write to the stack pointer. 300 movn(rd, rd.Is64Bits() ? ~imm : (~imm & kWRegMask)); 301 } else if (IsImmLogical(imm, reg_size, &n, &imm_s, &imm_r)) { 302 // Immediate can be represented in a logical orr instruction. 303 VIXL_ASSERT(!rd.IsZero()); 304 LogicalImmediate(rd, AppropriateZeroRegFor(rd), n, imm_s, imm_r, ORR); 305 } else { 306 // Generic immediate case. Imm will be represented by 307 // [imm3, imm2, imm1, imm0], where each imm is 16 bits. 308 // A move-zero or move-inverted is generated for the first non-zero or 309 // non-0xffff immX, and a move-keep for subsequent non-zero immX. 310 311 uint64_t ignored_halfword = 0; 312 bool invert_move = false; 313 // If the number of 0xffff halfwords is greater than the number of 0x0000 314 // halfwords, it's more efficient to use move-inverted. 315 if (CountClearHalfWords(~imm, reg_size) > 316 CountClearHalfWords(imm, reg_size)) { 317 ignored_halfword = 0xffff; 318 invert_move = true; 319 } 320 321 // Mov instructions can't move values into the stack pointer, so set up a 322 // temporary register, if needed. 323 UseScratchRegisterScope temps(this); 324 Register temp = rd.IsSP() ? temps.AcquireSameSizeAs(rd) : rd; 325 326 // Iterate through the halfwords. Use movn/movz for the first non-ignored 327 // halfword, and movk for subsequent halfwords. 328 VIXL_ASSERT((reg_size % 16) == 0); 329 bool first_mov_done = false; 330 for (unsigned i = 0; i < (temp.size() / 16); i++) { 331 uint64_t imm16 = (imm >> (16 * i)) & 0xffff; 332 if (imm16 != ignored_halfword) { 333 if (!first_mov_done) { 334 if (invert_move) { 335 movn(temp, ~imm16 & 0xffff, 16 * i); 336 } else { 337 movz(temp, imm16, 16 * i); 338 } 339 first_mov_done = true; 340 } else { 341 // Construct a wider constant. 342 movk(temp, imm16, 16 * i); 343 } 344 } 345 } 346 347 VIXL_ASSERT(first_mov_done); 348 349 // Move the temporary if the original destination register was the stack 350 // pointer. 351 if (rd.IsSP()) { 352 mov(rd, temp); 353 } 354 } 355 } 356 357 358 unsigned MacroAssembler::CountClearHalfWords(uint64_t imm, unsigned reg_size) { 359 VIXL_ASSERT((reg_size % 8) == 0); 360 int count = 0; 361 for (unsigned i = 0; i < (reg_size / 16); i++) { 362 if ((imm & 0xffff) == 0) { 363 count++; 364 } 365 imm >>= 16; 366 } 367 return count; 368 } 369 370 371 // The movn instruction can generate immediates containing an arbitrary 16-bit 372 // value, with remaining bits set, eg. 0x00001234, 0x0000123400000000. 373 bool MacroAssembler::IsImmMovz(uint64_t imm, unsigned reg_size) { 374 VIXL_ASSERT((reg_size == kXRegSize) || (reg_size == kWRegSize)); 375 return CountClearHalfWords(imm, reg_size) >= ((reg_size / 16) - 1); 376 } 377 378 379 // The movn instruction can generate immediates containing an arbitrary 16-bit 380 // value, with remaining bits set, eg. 0xffff1234, 0xffff1234ffffffff. 381 bool MacroAssembler::IsImmMovn(uint64_t imm, unsigned reg_size) { 382 return IsImmMovz(~imm, reg_size); 383 } 384 385 386 void MacroAssembler::Ccmp(const Register& rn, 387 const Operand& operand, 388 StatusFlags nzcv, 389 Condition cond) { 390 VIXL_ASSERT(allow_macro_instructions_); 391 if (operand.IsImmediate() && (operand.immediate() < 0)) { 392 ConditionalCompareMacro(rn, -operand.immediate(), nzcv, cond, CCMN); 393 } else { 394 ConditionalCompareMacro(rn, operand, nzcv, cond, CCMP); 395 } 396 } 397 398 399 void MacroAssembler::Ccmn(const Register& rn, 400 const Operand& operand, 401 StatusFlags nzcv, 402 Condition cond) { 403 VIXL_ASSERT(allow_macro_instructions_); 404 if (operand.IsImmediate() && (operand.immediate() < 0)) { 405 ConditionalCompareMacro(rn, -operand.immediate(), nzcv, cond, CCMP); 406 } else { 407 ConditionalCompareMacro(rn, operand, nzcv, cond, CCMN); 408 } 409 } 410 411 412 void MacroAssembler::ConditionalCompareMacro(const Register& rn, 413 const Operand& operand, 414 StatusFlags nzcv, 415 Condition cond, 416 ConditionalCompareOp op) { 417 VIXL_ASSERT((cond != al) && (cond != nv)); 418 if ((operand.IsShiftedRegister() && (operand.shift_amount() == 0)) || 419 (operand.IsImmediate() && IsImmConditionalCompare(operand.immediate()))) { 420 // The immediate can be encoded in the instruction, or the operand is an 421 // unshifted register: call the assembler. 422 ConditionalCompare(rn, operand, nzcv, cond, op); 423 } else { 424 UseScratchRegisterScope temps(this); 425 // The operand isn't directly supported by the instruction: perform the 426 // operation on a temporary register. 427 Register temp = temps.AcquireSameSizeAs(rn); 428 Mov(temp, operand); 429 ConditionalCompare(rn, temp, nzcv, cond, op); 430 } 431 } 432 433 434 void MacroAssembler::Csel(const Register& rd, 435 const Register& rn, 436 const Operand& operand, 437 Condition cond) { 438 VIXL_ASSERT(allow_macro_instructions_); 439 VIXL_ASSERT(!rd.IsZero()); 440 VIXL_ASSERT(!rn.IsZero()); 441 VIXL_ASSERT((cond != al) && (cond != nv)); 442 if (operand.IsImmediate()) { 443 // Immediate argument. Handle special cases of 0, 1 and -1 using zero 444 // register. 445 int64_t imm = operand.immediate(); 446 Register zr = AppropriateZeroRegFor(rn); 447 if (imm == 0) { 448 csel(rd, rn, zr, cond); 449 } else if (imm == 1) { 450 csinc(rd, rn, zr, cond); 451 } else if (imm == -1) { 452 csinv(rd, rn, zr, cond); 453 } else { 454 UseScratchRegisterScope temps(this); 455 Register temp = temps.AcquireSameSizeAs(rn); 456 Mov(temp, operand.immediate()); 457 csel(rd, rn, temp, cond); 458 } 459 } else if (operand.IsShiftedRegister() && (operand.shift_amount() == 0)) { 460 // Unshifted register argument. 461 csel(rd, rn, operand.reg(), cond); 462 } else { 463 // All other arguments. 464 UseScratchRegisterScope temps(this); 465 Register temp = temps.AcquireSameSizeAs(rn); 466 Mov(temp, operand); 467 csel(rd, rn, temp, cond); 468 } 469 } 470 471 472 void MacroAssembler::Add(const Register& rd, 473 const Register& rn, 474 const Operand& operand) { 475 VIXL_ASSERT(allow_macro_instructions_); 476 if (operand.IsImmediate() && (operand.immediate() < 0)) { 477 AddSubMacro(rd, rn, -operand.immediate(), LeaveFlags, SUB); 478 } else { 479 AddSubMacro(rd, rn, operand, LeaveFlags, ADD); 480 } 481 } 482 483 484 void MacroAssembler::Adds(const Register& rd, 485 const Register& rn, 486 const Operand& operand) { 487 VIXL_ASSERT(allow_macro_instructions_); 488 if (operand.IsImmediate() && (operand.immediate() < 0)) { 489 AddSubMacro(rd, rn, -operand.immediate(), SetFlags, SUB); 490 } else { 491 AddSubMacro(rd, rn, operand, SetFlags, ADD); 492 } 493 } 494 495 496 void MacroAssembler::Sub(const Register& rd, 497 const Register& rn, 498 const Operand& operand) { 499 VIXL_ASSERT(allow_macro_instructions_); 500 if (operand.IsImmediate() && (operand.immediate() < 0)) { 501 AddSubMacro(rd, rn, -operand.immediate(), LeaveFlags, ADD); 502 } else { 503 AddSubMacro(rd, rn, operand, LeaveFlags, SUB); 504 } 505 } 506 507 508 void MacroAssembler::Subs(const Register& rd, 509 const Register& rn, 510 const Operand& operand) { 511 VIXL_ASSERT(allow_macro_instructions_); 512 if (operand.IsImmediate() && (operand.immediate() < 0)) { 513 AddSubMacro(rd, rn, -operand.immediate(), SetFlags, ADD); 514 } else { 515 AddSubMacro(rd, rn, operand, SetFlags, SUB); 516 } 517 } 518 519 520 void MacroAssembler::Cmn(const Register& rn, const Operand& operand) { 521 VIXL_ASSERT(allow_macro_instructions_); 522 Adds(AppropriateZeroRegFor(rn), rn, operand); 523 } 524 525 526 void MacroAssembler::Cmp(const Register& rn, const Operand& operand) { 527 VIXL_ASSERT(allow_macro_instructions_); 528 Subs(AppropriateZeroRegFor(rn), rn, operand); 529 } 530 531 532 void MacroAssembler::Fcmp(const FPRegister& fn, double value) { 533 VIXL_ASSERT(allow_macro_instructions_); 534 if (value != 0.0) { 535 UseScratchRegisterScope temps(this); 536 FPRegister tmp = temps.AcquireSameSizeAs(fn); 537 Fmov(tmp, value); 538 fcmp(fn, tmp); 539 } else { 540 fcmp(fn, value); 541 } 542 } 543 544 545 void MacroAssembler::Fmov(FPRegister fd, double imm) { 546 VIXL_ASSERT(allow_macro_instructions_); 547 if (fd.Is32Bits()) { 548 Fmov(fd, static_cast<float>(imm)); 549 return; 550 } 551 552 VIXL_ASSERT(fd.Is64Bits()); 553 if (IsImmFP64(imm)) { 554 fmov(fd, imm); 555 } else if ((imm == 0.0) && (copysign(1.0, imm) == 1.0)) { 556 fmov(fd, xzr); 557 } else { 558 ldr(fd, imm); 559 } 560 } 561 562 563 void MacroAssembler::Fmov(FPRegister fd, float imm) { 564 VIXL_ASSERT(allow_macro_instructions_); 565 if (fd.Is64Bits()) { 566 Fmov(fd, static_cast<double>(imm)); 567 return; 568 } 569 570 VIXL_ASSERT(fd.Is32Bits()); 571 if (IsImmFP32(imm)) { 572 fmov(fd, imm); 573 } else if ((imm == 0.0) && (copysign(1.0, imm) == 1.0)) { 574 fmov(fd, wzr); 575 } else { 576 ldr(fd, imm); 577 } 578 } 579 580 581 582 void MacroAssembler::Neg(const Register& rd, 583 const Operand& operand) { 584 VIXL_ASSERT(allow_macro_instructions_); 585 if (operand.IsImmediate()) { 586 Mov(rd, -operand.immediate()); 587 } else { 588 Sub(rd, AppropriateZeroRegFor(rd), operand); 589 } 590 } 591 592 593 void MacroAssembler::Negs(const Register& rd, 594 const Operand& operand) { 595 VIXL_ASSERT(allow_macro_instructions_); 596 Subs(rd, AppropriateZeroRegFor(rd), operand); 597 } 598 599 600 void MacroAssembler::AddSubMacro(const Register& rd, 601 const Register& rn, 602 const Operand& operand, 603 FlagsUpdate S, 604 AddSubOp op) { 605 if (operand.IsZero() && rd.Is(rn) && rd.Is64Bits() && rn.Is64Bits() && 606 (S == LeaveFlags)) { 607 // The instruction would be a nop. Avoid generating useless code. 608 return; 609 } 610 611 if ((operand.IsImmediate() && !IsImmAddSub(operand.immediate())) || 612 (rn.IsZero() && !operand.IsShiftedRegister()) || 613 (operand.IsShiftedRegister() && (operand.shift() == ROR))) { 614 UseScratchRegisterScope temps(this); 615 Register temp = temps.AcquireSameSizeAs(rn); 616 Mov(temp, operand); 617 AddSub(rd, rn, temp, S, op); 618 } else { 619 AddSub(rd, rn, operand, S, op); 620 } 621 } 622 623 624 void MacroAssembler::Adc(const Register& rd, 625 const Register& rn, 626 const Operand& operand) { 627 VIXL_ASSERT(allow_macro_instructions_); 628 AddSubWithCarryMacro(rd, rn, operand, LeaveFlags, ADC); 629 } 630 631 632 void MacroAssembler::Adcs(const Register& rd, 633 const Register& rn, 634 const Operand& operand) { 635 VIXL_ASSERT(allow_macro_instructions_); 636 AddSubWithCarryMacro(rd, rn, operand, SetFlags, ADC); 637 } 638 639 640 void MacroAssembler::Sbc(const Register& rd, 641 const Register& rn, 642 const Operand& operand) { 643 VIXL_ASSERT(allow_macro_instructions_); 644 AddSubWithCarryMacro(rd, rn, operand, LeaveFlags, SBC); 645 } 646 647 648 void MacroAssembler::Sbcs(const Register& rd, 649 const Register& rn, 650 const Operand& operand) { 651 VIXL_ASSERT(allow_macro_instructions_); 652 AddSubWithCarryMacro(rd, rn, operand, SetFlags, SBC); 653 } 654 655 656 void MacroAssembler::Ngc(const Register& rd, 657 const Operand& operand) { 658 VIXL_ASSERT(allow_macro_instructions_); 659 Register zr = AppropriateZeroRegFor(rd); 660 Sbc(rd, zr, operand); 661 } 662 663 664 void MacroAssembler::Ngcs(const Register& rd, 665 const Operand& operand) { 666 VIXL_ASSERT(allow_macro_instructions_); 667 Register zr = AppropriateZeroRegFor(rd); 668 Sbcs(rd, zr, operand); 669 } 670 671 672 void MacroAssembler::AddSubWithCarryMacro(const Register& rd, 673 const Register& rn, 674 const Operand& operand, 675 FlagsUpdate S, 676 AddSubWithCarryOp op) { 677 VIXL_ASSERT(rd.size() == rn.size()); 678 UseScratchRegisterScope temps(this); 679 680 if (operand.IsImmediate() || 681 (operand.IsShiftedRegister() && (operand.shift() == ROR))) { 682 // Add/sub with carry (immediate or ROR shifted register.) 683 Register temp = temps.AcquireSameSizeAs(rn); 684 Mov(temp, operand); 685 AddSubWithCarry(rd, rn, Operand(temp), S, op); 686 } else if (operand.IsShiftedRegister() && (operand.shift_amount() != 0)) { 687 // Add/sub with carry (shifted register). 688 VIXL_ASSERT(operand.reg().size() == rd.size()); 689 VIXL_ASSERT(operand.shift() != ROR); 690 VIXL_ASSERT(is_uintn(rd.size() == kXRegSize ? kXRegSizeLog2 : kWRegSizeLog2, 691 operand.shift_amount())); 692 temps.Exclude(operand.reg()); 693 Register temp = temps.AcquireSameSizeAs(rn); 694 EmitShift(temp, operand.reg(), operand.shift(), operand.shift_amount()); 695 AddSubWithCarry(rd, rn, Operand(temp), S, op); 696 } else if (operand.IsExtendedRegister()) { 697 // Add/sub with carry (extended register). 698 VIXL_ASSERT(operand.reg().size() <= rd.size()); 699 // Add/sub extended supports a shift <= 4. We want to support exactly the 700 // same modes. 701 VIXL_ASSERT(operand.shift_amount() <= 4); 702 VIXL_ASSERT(operand.reg().Is64Bits() || 703 ((operand.extend() != UXTX) && (operand.extend() != SXTX))); 704 temps.Exclude(operand.reg()); 705 Register temp = temps.AcquireSameSizeAs(rn); 706 EmitExtendShift(temp, operand.reg(), operand.extend(), 707 operand.shift_amount()); 708 AddSubWithCarry(rd, rn, Operand(temp), S, op); 709 } else { 710 // The addressing mode is directly supported by the instruction. 711 AddSubWithCarry(rd, rn, operand, S, op); 712 } 713 } 714 715 716 #define DEFINE_FUNCTION(FN, REGTYPE, REG, OP) \ 717 void MacroAssembler::FN(const REGTYPE REG, const MemOperand& addr) { \ 718 LoadStoreMacro(REG, addr, OP); \ 719 } 720 LS_MACRO_LIST(DEFINE_FUNCTION) 721 #undef DEFINE_FUNCTION 722 723 void MacroAssembler::LoadStoreMacro(const CPURegister& rt, 724 const MemOperand& addr, 725 LoadStoreOp op) { 726 int64_t offset = addr.offset(); 727 LSDataSize size = CalcLSDataSize(op); 728 729 // Check if an immediate offset fits in the immediate field of the 730 // appropriate instruction. If not, emit two instructions to perform 731 // the operation. 732 if (addr.IsImmediateOffset() && !IsImmLSScaled(offset, size) && 733 !IsImmLSUnscaled(offset)) { 734 // Immediate offset that can't be encoded using unsigned or unscaled 735 // addressing modes. 736 UseScratchRegisterScope temps(this); 737 Register temp = temps.AcquireSameSizeAs(addr.base()); 738 Mov(temp, addr.offset()); 739 LoadStore(rt, MemOperand(addr.base(), temp), op); 740 } else if (addr.IsPostIndex() && !IsImmLSUnscaled(offset)) { 741 // Post-index beyond unscaled addressing range. 742 LoadStore(rt, MemOperand(addr.base()), op); 743 Add(addr.base(), addr.base(), Operand(offset)); 744 } else if (addr.IsPreIndex() && !IsImmLSUnscaled(offset)) { 745 // Pre-index beyond unscaled addressing range. 746 Add(addr.base(), addr.base(), Operand(offset)); 747 LoadStore(rt, MemOperand(addr.base()), op); 748 } else { 749 // Encodable in one load/store instruction. 750 LoadStore(rt, addr, op); 751 } 752 } 753 754 755 void MacroAssembler::Push(const CPURegister& src0, const CPURegister& src1, 756 const CPURegister& src2, const CPURegister& src3) { 757 VIXL_ASSERT(allow_macro_instructions_); 758 VIXL_ASSERT(AreSameSizeAndType(src0, src1, src2, src3)); 759 VIXL_ASSERT(src0.IsValid()); 760 761 int count = 1 + src1.IsValid() + src2.IsValid() + src3.IsValid(); 762 int size = src0.SizeInBytes(); 763 764 PrepareForPush(count, size); 765 PushHelper(count, size, src0, src1, src2, src3); 766 } 767 768 769 void MacroAssembler::Pop(const CPURegister& dst0, const CPURegister& dst1, 770 const CPURegister& dst2, const CPURegister& dst3) { 771 // It is not valid to pop into the same register more than once in one 772 // instruction, not even into the zero register. 773 VIXL_ASSERT(allow_macro_instructions_); 774 VIXL_ASSERT(!AreAliased(dst0, dst1, dst2, dst3)); 775 VIXL_ASSERT(AreSameSizeAndType(dst0, dst1, dst2, dst3)); 776 VIXL_ASSERT(dst0.IsValid()); 777 778 int count = 1 + dst1.IsValid() + dst2.IsValid() + dst3.IsValid(); 779 int size = dst0.SizeInBytes(); 780 781 PrepareForPop(count, size); 782 PopHelper(count, size, dst0, dst1, dst2, dst3); 783 } 784 785 786 void MacroAssembler::PushCPURegList(CPURegList registers) { 787 int size = registers.RegisterSizeInBytes(); 788 789 PrepareForPush(registers.Count(), size); 790 // Push up to four registers at a time because if the current stack pointer is 791 // sp and reg_size is 32, registers must be pushed in blocks of four in order 792 // to maintain the 16-byte alignment for sp. 793 VIXL_ASSERT(allow_macro_instructions_); 794 while (!registers.IsEmpty()) { 795 int count_before = registers.Count(); 796 const CPURegister& src0 = registers.PopHighestIndex(); 797 const CPURegister& src1 = registers.PopHighestIndex(); 798 const CPURegister& src2 = registers.PopHighestIndex(); 799 const CPURegister& src3 = registers.PopHighestIndex(); 800 int count = count_before - registers.Count(); 801 PushHelper(count, size, src0, src1, src2, src3); 802 } 803 } 804 805 806 void MacroAssembler::PopCPURegList(CPURegList registers) { 807 int size = registers.RegisterSizeInBytes(); 808 809 PrepareForPop(registers.Count(), size); 810 // Pop up to four registers at a time because if the current stack pointer is 811 // sp and reg_size is 32, registers must be pushed in blocks of four in order 812 // to maintain the 16-byte alignment for sp. 813 VIXL_ASSERT(allow_macro_instructions_); 814 while (!registers.IsEmpty()) { 815 int count_before = registers.Count(); 816 const CPURegister& dst0 = registers.PopLowestIndex(); 817 const CPURegister& dst1 = registers.PopLowestIndex(); 818 const CPURegister& dst2 = registers.PopLowestIndex(); 819 const CPURegister& dst3 = registers.PopLowestIndex(); 820 int count = count_before - registers.Count(); 821 PopHelper(count, size, dst0, dst1, dst2, dst3); 822 } 823 } 824 825 826 void MacroAssembler::PushMultipleTimes(int count, Register src) { 827 VIXL_ASSERT(allow_macro_instructions_); 828 int size = src.SizeInBytes(); 829 830 PrepareForPush(count, size); 831 // Push up to four registers at a time if possible because if the current 832 // stack pointer is sp and the register size is 32, registers must be pushed 833 // in blocks of four in order to maintain the 16-byte alignment for sp. 834 while (count >= 4) { 835 PushHelper(4, size, src, src, src, src); 836 count -= 4; 837 } 838 if (count >= 2) { 839 PushHelper(2, size, src, src, NoReg, NoReg); 840 count -= 2; 841 } 842 if (count == 1) { 843 PushHelper(1, size, src, NoReg, NoReg, NoReg); 844 count -= 1; 845 } 846 VIXL_ASSERT(count == 0); 847 } 848 849 850 void MacroAssembler::PushHelper(int count, int size, 851 const CPURegister& src0, 852 const CPURegister& src1, 853 const CPURegister& src2, 854 const CPURegister& src3) { 855 // Ensure that we don't unintentionally modify scratch or debug registers. 856 InstructionAccurateScope scope(this); 857 858 VIXL_ASSERT(AreSameSizeAndType(src0, src1, src2, src3)); 859 VIXL_ASSERT(size == src0.SizeInBytes()); 860 861 // When pushing multiple registers, the store order is chosen such that 862 // Push(a, b) is equivalent to Push(a) followed by Push(b). 863 switch (count) { 864 case 1: 865 VIXL_ASSERT(src1.IsNone() && src2.IsNone() && src3.IsNone()); 866 str(src0, MemOperand(StackPointer(), -1 * size, PreIndex)); 867 break; 868 case 2: 869 VIXL_ASSERT(src2.IsNone() && src3.IsNone()); 870 stp(src1, src0, MemOperand(StackPointer(), -2 * size, PreIndex)); 871 break; 872 case 3: 873 VIXL_ASSERT(src3.IsNone()); 874 stp(src2, src1, MemOperand(StackPointer(), -3 * size, PreIndex)); 875 str(src0, MemOperand(StackPointer(), 2 * size)); 876 break; 877 case 4: 878 // Skip over 4 * size, then fill in the gap. This allows four W registers 879 // to be pushed using sp, whilst maintaining 16-byte alignment for sp at 880 // all times. 881 stp(src3, src2, MemOperand(StackPointer(), -4 * size, PreIndex)); 882 stp(src1, src0, MemOperand(StackPointer(), 2 * size)); 883 break; 884 default: 885 VIXL_UNREACHABLE(); 886 } 887 } 888 889 890 void MacroAssembler::PopHelper(int count, int size, 891 const CPURegister& dst0, 892 const CPURegister& dst1, 893 const CPURegister& dst2, 894 const CPURegister& dst3) { 895 // Ensure that we don't unintentionally modify scratch or debug registers. 896 InstructionAccurateScope scope(this); 897 898 VIXL_ASSERT(AreSameSizeAndType(dst0, dst1, dst2, dst3)); 899 VIXL_ASSERT(size == dst0.SizeInBytes()); 900 901 // When popping multiple registers, the load order is chosen such that 902 // Pop(a, b) is equivalent to Pop(a) followed by Pop(b). 903 switch (count) { 904 case 1: 905 VIXL_ASSERT(dst1.IsNone() && dst2.IsNone() && dst3.IsNone()); 906 ldr(dst0, MemOperand(StackPointer(), 1 * size, PostIndex)); 907 break; 908 case 2: 909 VIXL_ASSERT(dst2.IsNone() && dst3.IsNone()); 910 ldp(dst0, dst1, MemOperand(StackPointer(), 2 * size, PostIndex)); 911 break; 912 case 3: 913 VIXL_ASSERT(dst3.IsNone()); 914 ldr(dst2, MemOperand(StackPointer(), 2 * size)); 915 ldp(dst0, dst1, MemOperand(StackPointer(), 3 * size, PostIndex)); 916 break; 917 case 4: 918 // Load the higher addresses first, then load the lower addresses and skip 919 // the whole block in the second instruction. This allows four W registers 920 // to be popped using sp, whilst maintaining 16-byte alignment for sp at 921 // all times. 922 ldp(dst2, dst3, MemOperand(StackPointer(), 2 * size)); 923 ldp(dst0, dst1, MemOperand(StackPointer(), 4 * size, PostIndex)); 924 break; 925 default: 926 VIXL_UNREACHABLE(); 927 } 928 } 929 930 931 void MacroAssembler::PrepareForPush(int count, int size) { 932 if (sp.Is(StackPointer())) { 933 // If the current stack pointer is sp, then it must be aligned to 16 bytes 934 // on entry and the total size of the specified registers must also be a 935 // multiple of 16 bytes. 936 VIXL_ASSERT((count * size) % 16 == 0); 937 } else { 938 // Even if the current stack pointer is not the system stack pointer (sp), 939 // the system stack pointer will still be modified in order to comply with 940 // ABI rules about accessing memory below the system stack pointer. 941 BumpSystemStackPointer(count * size); 942 } 943 } 944 945 946 void MacroAssembler::PrepareForPop(int count, int size) { 947 USE(count); 948 USE(size); 949 if (sp.Is(StackPointer())) { 950 // If the current stack pointer is sp, then it must be aligned to 16 bytes 951 // on entry and the total size of the specified registers must also be a 952 // multiple of 16 bytes. 953 VIXL_ASSERT((count * size) % 16 == 0); 954 } 955 } 956 957 void MacroAssembler::Poke(const Register& src, const Operand& offset) { 958 VIXL_ASSERT(allow_macro_instructions_); 959 if (offset.IsImmediate()) { 960 VIXL_ASSERT(offset.immediate() >= 0); 961 } 962 963 Str(src, MemOperand(StackPointer(), offset)); 964 } 965 966 967 void MacroAssembler::Peek(const Register& dst, const Operand& offset) { 968 VIXL_ASSERT(allow_macro_instructions_); 969 if (offset.IsImmediate()) { 970 VIXL_ASSERT(offset.immediate() >= 0); 971 } 972 973 Ldr(dst, MemOperand(StackPointer(), offset)); 974 } 975 976 977 void MacroAssembler::Claim(const Operand& size) { 978 VIXL_ASSERT(allow_macro_instructions_); 979 980 if (size.IsZero()) { 981 return; 982 } 983 984 if (size.IsImmediate()) { 985 VIXL_ASSERT(size.immediate() > 0); 986 if (sp.Is(StackPointer())) { 987 VIXL_ASSERT((size.immediate() % 16) == 0); 988 } 989 } 990 991 if (!sp.Is(StackPointer())) { 992 BumpSystemStackPointer(size); 993 } 994 995 Sub(StackPointer(), StackPointer(), size); 996 } 997 998 999 void MacroAssembler::Drop(const Operand& size) { 1000 VIXL_ASSERT(allow_macro_instructions_); 1001 1002 if (size.IsZero()) { 1003 return; 1004 } 1005 1006 if (size.IsImmediate()) { 1007 VIXL_ASSERT(size.immediate() > 0); 1008 if (sp.Is(StackPointer())) { 1009 VIXL_ASSERT((size.immediate() % 16) == 0); 1010 } 1011 } 1012 1013 Add(StackPointer(), StackPointer(), size); 1014 } 1015 1016 1017 void MacroAssembler::PushCalleeSavedRegisters() { 1018 // Ensure that the macro-assembler doesn't use any scratch registers. 1019 InstructionAccurateScope scope(this); 1020 1021 // This method must not be called unless the current stack pointer is sp. 1022 VIXL_ASSERT(sp.Is(StackPointer())); 1023 1024 MemOperand tos(sp, -2 * kXRegSizeInBytes, PreIndex); 1025 1026 stp(x29, x30, tos); 1027 stp(x27, x28, tos); 1028 stp(x25, x26, tos); 1029 stp(x23, x24, tos); 1030 stp(x21, x22, tos); 1031 stp(x19, x20, tos); 1032 1033 stp(d14, d15, tos); 1034 stp(d12, d13, tos); 1035 stp(d10, d11, tos); 1036 stp(d8, d9, tos); 1037 } 1038 1039 1040 void MacroAssembler::PopCalleeSavedRegisters() { 1041 // Ensure that the macro-assembler doesn't use any scratch registers. 1042 InstructionAccurateScope scope(this); 1043 1044 // This method must not be called unless the current stack pointer is sp. 1045 VIXL_ASSERT(sp.Is(StackPointer())); 1046 1047 MemOperand tos(sp, 2 * kXRegSizeInBytes, PostIndex); 1048 1049 ldp(d8, d9, tos); 1050 ldp(d10, d11, tos); 1051 ldp(d12, d13, tos); 1052 ldp(d14, d15, tos); 1053 1054 ldp(x19, x20, tos); 1055 ldp(x21, x22, tos); 1056 ldp(x23, x24, tos); 1057 ldp(x25, x26, tos); 1058 ldp(x27, x28, tos); 1059 ldp(x29, x30, tos); 1060 } 1061 1062 void MacroAssembler::BumpSystemStackPointer(const Operand& space) { 1063 VIXL_ASSERT(!sp.Is(StackPointer())); 1064 // TODO: Several callers rely on this not using scratch registers, so we use 1065 // the assembler directly here. However, this means that large immediate 1066 // values of 'space' cannot be handled. 1067 InstructionAccurateScope scope(this); 1068 sub(sp, StackPointer(), space); 1069 } 1070 1071 1072 // This is the main Printf implementation. All callee-saved registers are 1073 // preserved, but NZCV and the caller-saved registers may be clobbered. 1074 void MacroAssembler::PrintfNoPreserve(const char * format, 1075 const CPURegister& arg0, 1076 const CPURegister& arg1, 1077 const CPURegister& arg2, 1078 const CPURegister& arg3) { 1079 // We cannot handle a caller-saved stack pointer. It doesn't make much sense 1080 // in most cases anyway, so this restriction shouldn't be too serious. 1081 VIXL_ASSERT(!kCallerSaved.IncludesAliasOf(StackPointer())); 1082 1083 // The provided arguments, and their proper PCS registers. 1084 CPURegister args[kPrintfMaxArgCount] = {arg0, arg1, arg2, arg3}; 1085 CPURegister pcs[kPrintfMaxArgCount]; 1086 1087 int arg_count = kPrintfMaxArgCount; 1088 1089 // The PCS varargs registers for printf. Note that x0 is used for the printf 1090 // format string. 1091 static const CPURegList kPCSVarargs = 1092 CPURegList(CPURegister::kRegister, kXRegSize, 1, arg_count); 1093 static const CPURegList kPCSVarargsFP = 1094 CPURegList(CPURegister::kFPRegister, kDRegSize, 0, arg_count - 1); 1095 1096 // We can use caller-saved registers as scratch values, except for the 1097 // arguments and the PCS registers where they might need to go. 1098 UseScratchRegisterScope temps(this); 1099 temps.Include(kCallerSaved); 1100 temps.Include(kCallerSavedFP); 1101 temps.Exclude(kPCSVarargs); 1102 temps.Exclude(kPCSVarargsFP); 1103 temps.Exclude(arg0, arg1, arg2, arg3); 1104 1105 // Copies of the arg lists that we can iterate through. 1106 CPURegList pcs_varargs = kPCSVarargs; 1107 CPURegList pcs_varargs_fp = kPCSVarargsFP; 1108 1109 // Place the arguments. There are lots of clever tricks and optimizations we 1110 // could use here, but Printf is a debug tool so instead we just try to keep 1111 // it simple: Move each input that isn't already in the right place to a 1112 // scratch register, then move everything back. 1113 for (unsigned i = 0; i < kPrintfMaxArgCount; i++) { 1114 // Work out the proper PCS register for this argument. 1115 if (args[i].IsRegister()) { 1116 pcs[i] = pcs_varargs.PopLowestIndex().X(); 1117 // We might only need a W register here. We need to know the size of the 1118 // argument so we can properly encode it for the simulator call. 1119 if (args[i].Is32Bits()) pcs[i] = pcs[i].W(); 1120 } else if (args[i].IsFPRegister()) { 1121 // In C, floats are always cast to doubles for varargs calls. 1122 pcs[i] = pcs_varargs_fp.PopLowestIndex().D(); 1123 } else { 1124 VIXL_ASSERT(args[i].IsNone()); 1125 arg_count = i; 1126 break; 1127 } 1128 1129 // If the argument is already in the right place, leave it where it is. 1130 if (args[i].Aliases(pcs[i])) continue; 1131 1132 // Otherwise, if the argument is in a PCS argument register, allocate an 1133 // appropriate scratch register and then move it out of the way. 1134 if (kPCSVarargs.IncludesAliasOf(args[i]) || 1135 kPCSVarargsFP.IncludesAliasOf(args[i])) { 1136 if (args[i].IsRegister()) { 1137 Register old_arg = Register(args[i]); 1138 Register new_arg = temps.AcquireSameSizeAs(old_arg); 1139 Mov(new_arg, old_arg); 1140 args[i] = new_arg; 1141 } else { 1142 FPRegister old_arg = FPRegister(args[i]); 1143 FPRegister new_arg = temps.AcquireSameSizeAs(old_arg); 1144 Fmov(new_arg, old_arg); 1145 args[i] = new_arg; 1146 } 1147 } 1148 } 1149 1150 // Do a second pass to move values into their final positions and perform any 1151 // conversions that may be required. 1152 for (int i = 0; i < arg_count; i++) { 1153 VIXL_ASSERT(pcs[i].type() == args[i].type()); 1154 if (pcs[i].IsRegister()) { 1155 Mov(Register(pcs[i]), Register(args[i]), kDiscardForSameWReg); 1156 } else { 1157 VIXL_ASSERT(pcs[i].IsFPRegister()); 1158 if (pcs[i].size() == args[i].size()) { 1159 Fmov(FPRegister(pcs[i]), FPRegister(args[i])); 1160 } else { 1161 Fcvt(FPRegister(pcs[i]), FPRegister(args[i])); 1162 } 1163 } 1164 } 1165 1166 // Load the format string into x0, as per the procedure-call standard. 1167 // 1168 // To make the code as portable as possible, the format string is encoded 1169 // directly in the instruction stream. It might be cleaner to encode it in a 1170 // literal pool, but since Printf is usually used for debugging, it is 1171 // beneficial for it to be minimally dependent on other features. 1172 temps.Exclude(x0); 1173 Label format_address; 1174 Adr(x0, &format_address); 1175 1176 // Emit the format string directly in the instruction stream. 1177 { BlockLiteralPoolScope scope(this); 1178 Label after_data; 1179 B(&after_data); 1180 Bind(&format_address); 1181 EmitStringData(format); 1182 Unreachable(); 1183 Bind(&after_data); 1184 } 1185 1186 // We don't pass any arguments on the stack, but we still need to align the C 1187 // stack pointer to a 16-byte boundary for PCS compliance. 1188 if (!sp.Is(StackPointer())) { 1189 Bic(sp, StackPointer(), 0xf); 1190 } 1191 1192 // Actually call printf. This part needs special handling for the simulator, 1193 // since the system printf function will use a different instruction set and 1194 // the procedure-call standard will not be compatible. 1195 #ifdef USE_SIMULATOR 1196 { InstructionAccurateScope scope(this, kPrintfLength / kInstructionSize); 1197 hlt(kPrintfOpcode); 1198 dc32(arg_count); // kPrintfArgCountOffset 1199 1200 // Determine the argument pattern. 1201 uint32_t arg_pattern_list = 0; 1202 for (int i = 0; i < arg_count; i++) { 1203 uint32_t arg_pattern; 1204 if (pcs[i].IsRegister()) { 1205 arg_pattern = pcs[i].Is32Bits() ? kPrintfArgW : kPrintfArgX; 1206 } else { 1207 VIXL_ASSERT(pcs[i].Is64Bits()); 1208 arg_pattern = kPrintfArgD; 1209 } 1210 VIXL_ASSERT(arg_pattern < (1 << kPrintfArgPatternBits)); 1211 arg_pattern_list |= (arg_pattern << (kPrintfArgPatternBits * i)); 1212 } 1213 dc32(arg_pattern_list); // kPrintfArgPatternListOffset 1214 } 1215 #else 1216 Register tmp = temps.AcquireX(); 1217 Mov(tmp, reinterpret_cast<uintptr_t>(printf)); 1218 Blr(tmp); 1219 #endif 1220 } 1221 1222 1223 void MacroAssembler::Printf(const char * format, 1224 CPURegister arg0, 1225 CPURegister arg1, 1226 CPURegister arg2, 1227 CPURegister arg3) { 1228 // We can only print sp if it is the current stack pointer. 1229 if (!sp.Is(StackPointer())) { 1230 VIXL_ASSERT(!sp.Aliases(arg0)); 1231 VIXL_ASSERT(!sp.Aliases(arg1)); 1232 VIXL_ASSERT(!sp.Aliases(arg2)); 1233 VIXL_ASSERT(!sp.Aliases(arg3)); 1234 } 1235 1236 // Make sure that the macro assembler doesn't try to use any of our arguments 1237 // as scratch registers. 1238 UseScratchRegisterScope exclude_all(this); 1239 exclude_all.ExcludeAll(); 1240 1241 // Preserve all caller-saved registers as well as NZCV. 1242 // If sp is the stack pointer, PushCPURegList asserts that the size of each 1243 // list is a multiple of 16 bytes. 1244 PushCPURegList(kCallerSaved); 1245 PushCPURegList(kCallerSavedFP); 1246 1247 { UseScratchRegisterScope temps(this); 1248 // We can use caller-saved registers as scratch values (except for argN). 1249 temps.Include(kCallerSaved); 1250 temps.Include(kCallerSavedFP); 1251 temps.Exclude(arg0, arg1, arg2, arg3); 1252 1253 // If any of the arguments are the current stack pointer, allocate a new 1254 // register for them, and adjust the value to compensate for pushing the 1255 // caller-saved registers. 1256 bool arg0_sp = StackPointer().Aliases(arg0); 1257 bool arg1_sp = StackPointer().Aliases(arg1); 1258 bool arg2_sp = StackPointer().Aliases(arg2); 1259 bool arg3_sp = StackPointer().Aliases(arg3); 1260 if (arg0_sp || arg1_sp || arg2_sp || arg3_sp) { 1261 // Allocate a register to hold the original stack pointer value, to pass 1262 // to PrintfNoPreserve as an argument. 1263 Register arg_sp = temps.AcquireX(); 1264 Add(arg_sp, StackPointer(), 1265 kCallerSaved.TotalSizeInBytes() + kCallerSavedFP.TotalSizeInBytes()); 1266 if (arg0_sp) arg0 = Register(arg_sp.code(), arg0.size()); 1267 if (arg1_sp) arg1 = Register(arg_sp.code(), arg1.size()); 1268 if (arg2_sp) arg2 = Register(arg_sp.code(), arg2.size()); 1269 if (arg3_sp) arg3 = Register(arg_sp.code(), arg3.size()); 1270 } 1271 1272 // Preserve NZCV. 1273 Register tmp = temps.AcquireX(); 1274 Mrs(tmp, NZCV); 1275 Push(tmp, xzr); 1276 temps.Release(tmp); 1277 1278 PrintfNoPreserve(format, arg0, arg1, arg2, arg3); 1279 1280 // Restore NZCV. 1281 tmp = temps.AcquireX(); 1282 Pop(xzr, tmp); 1283 Msr(NZCV, tmp); 1284 temps.Release(tmp); 1285 } 1286 1287 PopCPURegList(kCallerSavedFP); 1288 PopCPURegList(kCallerSaved); 1289 } 1290 1291 void MacroAssembler::Trace(TraceParameters parameters, TraceCommand command) { 1292 VIXL_ASSERT(allow_macro_instructions_); 1293 1294 #ifdef USE_SIMULATOR 1295 // The arguments to the trace pseudo instruction need to be contiguous in 1296 // memory, so make sure we don't try to emit a literal pool. 1297 InstructionAccurateScope scope(this, kTraceLength / kInstructionSize); 1298 1299 Label start; 1300 bind(&start); 1301 1302 // Refer to instructions-a64.h for a description of the marker and its 1303 // arguments. 1304 hlt(kTraceOpcode); 1305 1306 VIXL_ASSERT(SizeOfCodeGeneratedSince(&start) == kTraceParamsOffset); 1307 dc32(parameters); 1308 1309 VIXL_ASSERT(SizeOfCodeGeneratedSince(&start) == kTraceCommandOffset); 1310 dc32(command); 1311 #else 1312 // Emit nothing on real hardware. 1313 USE(parameters); 1314 USE(command); 1315 #endif 1316 } 1317 1318 1319 void MacroAssembler::Log(TraceParameters parameters) { 1320 VIXL_ASSERT(allow_macro_instructions_); 1321 1322 #ifdef USE_SIMULATOR 1323 // The arguments to the log pseudo instruction need to be contiguous in 1324 // memory, so make sure we don't try to emit a literal pool. 1325 InstructionAccurateScope scope(this, kLogLength / kInstructionSize); 1326 1327 Label start; 1328 bind(&start); 1329 1330 // Refer to instructions-a64.h for a description of the marker and its 1331 // arguments. 1332 hlt(kLogOpcode); 1333 1334 VIXL_ASSERT(SizeOfCodeGeneratedSince(&start) == kLogParamsOffset); 1335 dc32(parameters); 1336 #else 1337 // Emit nothing on real hardware. 1338 USE(parameters); 1339 #endif 1340 } 1341 1342 1343 void MacroAssembler::EnableInstrumentation() { 1344 VIXL_ASSERT(!isprint(InstrumentStateEnable)); 1345 InstructionAccurateScope scope(this, 1); 1346 movn(xzr, InstrumentStateEnable); 1347 } 1348 1349 1350 void MacroAssembler::DisableInstrumentation() { 1351 VIXL_ASSERT(!isprint(InstrumentStateDisable)); 1352 InstructionAccurateScope scope(this, 1); 1353 movn(xzr, InstrumentStateDisable); 1354 } 1355 1356 1357 void MacroAssembler::AnnotateInstrumentation(const char* marker_name) { 1358 VIXL_ASSERT(strlen(marker_name) == 2); 1359 1360 // We allow only printable characters in the marker names. Unprintable 1361 // characters are reserved for controlling features of the instrumentation. 1362 VIXL_ASSERT(isprint(marker_name[0]) && isprint(marker_name[1])); 1363 1364 InstructionAccurateScope scope(this, 1); 1365 movn(xzr, (marker_name[1] << 8) | marker_name[0]); 1366 } 1367 1368 1369 UseScratchRegisterScope::~UseScratchRegisterScope() { 1370 available_->set_list(old_available_); 1371 availablefp_->set_list(old_availablefp_); 1372 } 1373 1374 1375 bool UseScratchRegisterScope::IsAvailable(const CPURegister& reg) const { 1376 return available_->IncludesAliasOf(reg) || availablefp_->IncludesAliasOf(reg); 1377 } 1378 1379 1380 Register UseScratchRegisterScope::AcquireSameSizeAs(const Register& reg) { 1381 int code = AcquireNextAvailable(available_).code(); 1382 return Register(code, reg.SizeInBits()); 1383 } 1384 1385 1386 FPRegister UseScratchRegisterScope::AcquireSameSizeAs(const FPRegister& reg) { 1387 int code = AcquireNextAvailable(availablefp_).code(); 1388 return FPRegister(code, reg.SizeInBits()); 1389 } 1390 1391 1392 void UseScratchRegisterScope::Release(const CPURegister& reg) { 1393 if (reg.IsRegister()) { 1394 ReleaseByCode(available_, reg.code()); 1395 } else if (reg.IsFPRegister()) { 1396 ReleaseByCode(availablefp_, reg.code()); 1397 } else { 1398 VIXL_ASSERT(reg.IsNone()); 1399 } 1400 } 1401 1402 1403 void UseScratchRegisterScope::Include(const CPURegList& list) { 1404 if (list.type() == CPURegister::kRegister) { 1405 // Make sure that neither sp nor xzr are included the list. 1406 IncludeByRegList(available_, list.list() & ~(xzr.Bit() | sp.Bit())); 1407 } else { 1408 VIXL_ASSERT(list.type() == CPURegister::kFPRegister); 1409 IncludeByRegList(availablefp_, list.list()); 1410 } 1411 } 1412 1413 1414 void UseScratchRegisterScope::Include(const Register& reg1, 1415 const Register& reg2, 1416 const Register& reg3, 1417 const Register& reg4) { 1418 RegList include = reg1.Bit() | reg2.Bit() | reg3.Bit() | reg4.Bit(); 1419 // Make sure that neither sp nor xzr are included the list. 1420 include &= ~(xzr.Bit() | sp.Bit()); 1421 1422 IncludeByRegList(available_, include); 1423 } 1424 1425 1426 void UseScratchRegisterScope::Include(const FPRegister& reg1, 1427 const FPRegister& reg2, 1428 const FPRegister& reg3, 1429 const FPRegister& reg4) { 1430 RegList include = reg1.Bit() | reg2.Bit() | reg3.Bit() | reg4.Bit(); 1431 IncludeByRegList(availablefp_, include); 1432 } 1433 1434 1435 void UseScratchRegisterScope::Exclude(const CPURegList& list) { 1436 if (list.type() == CPURegister::kRegister) { 1437 ExcludeByRegList(available_, list.list()); 1438 } else { 1439 VIXL_ASSERT(list.type() == CPURegister::kFPRegister); 1440 ExcludeByRegList(availablefp_, list.list()); 1441 } 1442 } 1443 1444 1445 void UseScratchRegisterScope::Exclude(const Register& reg1, 1446 const Register& reg2, 1447 const Register& reg3, 1448 const Register& reg4) { 1449 RegList exclude = reg1.Bit() | reg2.Bit() | reg3.Bit() | reg4.Bit(); 1450 ExcludeByRegList(available_, exclude); 1451 } 1452 1453 1454 void UseScratchRegisterScope::Exclude(const FPRegister& reg1, 1455 const FPRegister& reg2, 1456 const FPRegister& reg3, 1457 const FPRegister& reg4) { 1458 RegList excludefp = reg1.Bit() | reg2.Bit() | reg3.Bit() | reg4.Bit(); 1459 ExcludeByRegList(availablefp_, excludefp); 1460 } 1461 1462 1463 void UseScratchRegisterScope::Exclude(const CPURegister& reg1, 1464 const CPURegister& reg2, 1465 const CPURegister& reg3, 1466 const CPURegister& reg4) { 1467 RegList exclude = 0; 1468 RegList excludefp = 0; 1469 1470 const CPURegister regs[] = {reg1, reg2, reg3, reg4}; 1471 1472 for (unsigned i = 0; i < (sizeof(regs) / sizeof(regs[0])); i++) { 1473 if (regs[i].IsRegister()) { 1474 exclude |= regs[i].Bit(); 1475 } else if (regs[i].IsFPRegister()) { 1476 excludefp |= regs[i].Bit(); 1477 } else { 1478 VIXL_ASSERT(regs[i].IsNone()); 1479 } 1480 } 1481 1482 ExcludeByRegList(available_, exclude); 1483 ExcludeByRegList(availablefp_, excludefp); 1484 } 1485 1486 1487 void UseScratchRegisterScope::ExcludeAll() { 1488 ExcludeByRegList(available_, available_->list()); 1489 ExcludeByRegList(availablefp_, availablefp_->list()); 1490 } 1491 1492 1493 CPURegister UseScratchRegisterScope::AcquireNextAvailable( 1494 CPURegList* available) { 1495 VIXL_CHECK(!available->IsEmpty()); 1496 CPURegister result = available->PopLowestIndex(); 1497 VIXL_ASSERT(!AreAliased(result, xzr, sp)); 1498 return result; 1499 } 1500 1501 1502 void UseScratchRegisterScope::ReleaseByCode(CPURegList* available, int code) { 1503 ReleaseByRegList(available, static_cast<RegList>(1) << code); 1504 } 1505 1506 1507 void UseScratchRegisterScope::ReleaseByRegList(CPURegList* available, 1508 RegList regs) { 1509 available->set_list(available->list() | regs); 1510 } 1511 1512 1513 void UseScratchRegisterScope::IncludeByRegList(CPURegList* available, 1514 RegList regs) { 1515 available->set_list(available->list() | regs); 1516 } 1517 1518 1519 void UseScratchRegisterScope::ExcludeByRegList(CPURegList* available, 1520 RegList exclude) { 1521 available->set_list(available->list() & ~exclude); 1522 } 1523 1524 } // namespace vixl 1525