1 // Copyright 2013 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided
11 // with the distribution.
12 // * Neither the name of Google Inc. nor the names of its
13 // contributors may be used to endorse or promote products derived
14 // from this software without specific prior written permission.
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 #ifndef V8_ARM64_MACRO_ASSEMBLER_ARM64_INL_H_
29 #define V8_ARM64_MACRO_ASSEMBLER_ARM64_INL_H_
33 #include "v8globals.h"
36 #include "arm64/assembler-arm64.h"
37 #include "arm64/assembler-arm64-inl.h"
38 #include "arm64/macro-assembler-arm64.h"
39 #include "arm64/instrument-arm64.h"
46 MemOperand FieldMemOperand(Register object, int offset) {
47 return MemOperand(object, offset - kHeapObjectTag);
51 MemOperand UntagSmiFieldMemOperand(Register object, int offset) {
52 return UntagSmiMemOperand(object, offset - kHeapObjectTag);
56 MemOperand UntagSmiMemOperand(Register object, int offset) {
57 // Assumes that Smis are shifted by 32 bits and little endianness.
58 STATIC_ASSERT(kSmiShift == 32);
59 return MemOperand(object, offset + (kSmiShift / kBitsPerByte));
63 Handle<Object> MacroAssembler::CodeObject() {
64 ASSERT(!code_object_.is_null());
69 void MacroAssembler::And(const Register& rd,
71 const Operand& operand) {
72 ASSERT(allow_macro_instructions_);
74 LogicalMacro(rd, rn, operand, AND);
78 void MacroAssembler::Ands(const Register& rd,
80 const Operand& operand) {
81 ASSERT(allow_macro_instructions_);
83 LogicalMacro(rd, rn, operand, ANDS);
87 void MacroAssembler::Tst(const Register& rn,
88 const Operand& operand) {
89 ASSERT(allow_macro_instructions_);
90 LogicalMacro(AppropriateZeroRegFor(rn), rn, operand, ANDS);
94 void MacroAssembler::Bic(const Register& rd,
96 const Operand& operand) {
97 ASSERT(allow_macro_instructions_);
99 LogicalMacro(rd, rn, operand, BIC);
103 void MacroAssembler::Bics(const Register& rd,
105 const Operand& operand) {
106 ASSERT(allow_macro_instructions_);
107 ASSERT(!rd.IsZero());
108 LogicalMacro(rd, rn, operand, BICS);
112 void MacroAssembler::Orr(const Register& rd,
114 const Operand& operand) {
115 ASSERT(allow_macro_instructions_);
116 ASSERT(!rd.IsZero());
117 LogicalMacro(rd, rn, operand, ORR);
121 void MacroAssembler::Orn(const Register& rd,
123 const Operand& operand) {
124 ASSERT(allow_macro_instructions_);
125 ASSERT(!rd.IsZero());
126 LogicalMacro(rd, rn, operand, ORN);
130 void MacroAssembler::Eor(const Register& rd,
132 const Operand& operand) {
133 ASSERT(allow_macro_instructions_);
134 ASSERT(!rd.IsZero());
135 LogicalMacro(rd, rn, operand, EOR);
139 void MacroAssembler::Eon(const Register& rd,
141 const Operand& operand) {
142 ASSERT(allow_macro_instructions_);
143 ASSERT(!rd.IsZero());
144 LogicalMacro(rd, rn, operand, EON);
148 void MacroAssembler::Ccmp(const Register& rn,
149 const Operand& operand,
152 ASSERT(allow_macro_instructions_);
153 if (operand.IsImmediate() && (operand.immediate() < 0)) {
154 ConditionalCompareMacro(rn, -operand.immediate(), nzcv, cond, CCMN);
156 ConditionalCompareMacro(rn, operand, nzcv, cond, CCMP);
161 void MacroAssembler::Ccmn(const Register& rn,
162 const Operand& operand,
165 ASSERT(allow_macro_instructions_);
166 if (operand.IsImmediate() && (operand.immediate() < 0)) {
167 ConditionalCompareMacro(rn, -operand.immediate(), nzcv, cond, CCMP);
169 ConditionalCompareMacro(rn, operand, nzcv, cond, CCMN);
174 void MacroAssembler::Add(const Register& rd,
176 const Operand& operand) {
177 ASSERT(allow_macro_instructions_);
178 if (operand.IsImmediate() && (operand.immediate() < 0)) {
179 AddSubMacro(rd, rn, -operand.immediate(), LeaveFlags, SUB);
181 AddSubMacro(rd, rn, operand, LeaveFlags, ADD);
185 void MacroAssembler::Adds(const Register& rd,
187 const Operand& operand) {
188 ASSERT(allow_macro_instructions_);
189 if (operand.IsImmediate() && (operand.immediate() < 0)) {
190 AddSubMacro(rd, rn, -operand.immediate(), SetFlags, SUB);
192 AddSubMacro(rd, rn, operand, SetFlags, ADD);
197 void MacroAssembler::Sub(const Register& rd,
199 const Operand& operand) {
200 ASSERT(allow_macro_instructions_);
201 if (operand.IsImmediate() && (operand.immediate() < 0)) {
202 AddSubMacro(rd, rn, -operand.immediate(), LeaveFlags, ADD);
204 AddSubMacro(rd, rn, operand, LeaveFlags, SUB);
209 void MacroAssembler::Subs(const Register& rd,
211 const Operand& operand) {
212 ASSERT(allow_macro_instructions_);
213 if (operand.IsImmediate() && (operand.immediate() < 0)) {
214 AddSubMacro(rd, rn, -operand.immediate(), SetFlags, ADD);
216 AddSubMacro(rd, rn, operand, SetFlags, SUB);
221 void MacroAssembler::Cmn(const Register& rn, const Operand& operand) {
222 ASSERT(allow_macro_instructions_);
223 Adds(AppropriateZeroRegFor(rn), rn, operand);
227 void MacroAssembler::Cmp(const Register& rn, const Operand& operand) {
228 ASSERT(allow_macro_instructions_);
229 Subs(AppropriateZeroRegFor(rn), rn, operand);
233 void MacroAssembler::Neg(const Register& rd,
234 const Operand& operand) {
235 ASSERT(allow_macro_instructions_);
236 ASSERT(!rd.IsZero());
237 if (operand.IsImmediate()) {
238 Mov(rd, -operand.immediate());
240 Sub(rd, AppropriateZeroRegFor(rd), operand);
245 void MacroAssembler::Negs(const Register& rd,
246 const Operand& operand) {
247 ASSERT(allow_macro_instructions_);
248 Subs(rd, AppropriateZeroRegFor(rd), operand);
252 void MacroAssembler::Adc(const Register& rd,
254 const Operand& operand) {
255 ASSERT(allow_macro_instructions_);
256 ASSERT(!rd.IsZero());
257 AddSubWithCarryMacro(rd, rn, operand, LeaveFlags, ADC);
261 void MacroAssembler::Adcs(const Register& rd,
263 const Operand& operand) {
264 ASSERT(allow_macro_instructions_);
265 ASSERT(!rd.IsZero());
266 AddSubWithCarryMacro(rd, rn, operand, SetFlags, ADC);
270 void MacroAssembler::Sbc(const Register& rd,
272 const Operand& operand) {
273 ASSERT(allow_macro_instructions_);
274 ASSERT(!rd.IsZero());
275 AddSubWithCarryMacro(rd, rn, operand, LeaveFlags, SBC);
279 void MacroAssembler::Sbcs(const Register& rd,
281 const Operand& operand) {
282 ASSERT(allow_macro_instructions_);
283 ASSERT(!rd.IsZero());
284 AddSubWithCarryMacro(rd, rn, operand, SetFlags, SBC);
288 void MacroAssembler::Ngc(const Register& rd,
289 const Operand& operand) {
290 ASSERT(allow_macro_instructions_);
291 ASSERT(!rd.IsZero());
292 Register zr = AppropriateZeroRegFor(rd);
293 Sbc(rd, zr, operand);
297 void MacroAssembler::Ngcs(const Register& rd,
298 const Operand& operand) {
299 ASSERT(allow_macro_instructions_);
300 ASSERT(!rd.IsZero());
301 Register zr = AppropriateZeroRegFor(rd);
302 Sbcs(rd, zr, operand);
306 void MacroAssembler::Mvn(const Register& rd, uint64_t imm) {
307 ASSERT(allow_macro_instructions_);
308 ASSERT(!rd.IsZero());
313 #define DEFINE_FUNCTION(FN, REGTYPE, REG, OP) \
314 void MacroAssembler::FN(const REGTYPE REG, const MemOperand& addr) { \
315 ASSERT(allow_macro_instructions_); \
316 LoadStoreMacro(REG, addr, OP); \
318 LS_MACRO_LIST(DEFINE_FUNCTION)
319 #undef DEFINE_FUNCTION
322 void MacroAssembler::Adr(const Register& rd, Label* label) {
323 ASSERT(allow_macro_instructions_);
324 ASSERT(!rd.IsZero());
329 void MacroAssembler::Asr(const Register& rd,
332 ASSERT(allow_macro_instructions_);
333 ASSERT(!rd.IsZero());
338 void MacroAssembler::Asr(const Register& rd,
340 const Register& rm) {
341 ASSERT(allow_macro_instructions_);
342 ASSERT(!rd.IsZero());
347 void MacroAssembler::B(Label* label) {
349 CheckVeneerPool(false, false);
353 void MacroAssembler::B(Condition cond, Label* label) {
354 ASSERT(allow_macro_instructions_);
359 void MacroAssembler::Bfi(const Register& rd,
363 ASSERT(allow_macro_instructions_);
364 ASSERT(!rd.IsZero());
365 bfi(rd, rn, lsb, width);
369 void MacroAssembler::Bfxil(const Register& rd,
373 ASSERT(allow_macro_instructions_);
374 ASSERT(!rd.IsZero());
375 bfxil(rd, rn, lsb, width);
379 void MacroAssembler::Bind(Label* label) {
380 ASSERT(allow_macro_instructions_);
385 void MacroAssembler::Bl(Label* label) {
386 ASSERT(allow_macro_instructions_);
391 void MacroAssembler::Blr(const Register& xn) {
392 ASSERT(allow_macro_instructions_);
393 ASSERT(!xn.IsZero());
398 void MacroAssembler::Br(const Register& xn) {
399 ASSERT(allow_macro_instructions_);
400 ASSERT(!xn.IsZero());
405 void MacroAssembler::Brk(int code) {
406 ASSERT(allow_macro_instructions_);
411 void MacroAssembler::Cinc(const Register& rd,
414 ASSERT(allow_macro_instructions_);
415 ASSERT(!rd.IsZero());
416 ASSERT((cond != al) && (cond != nv));
421 void MacroAssembler::Cinv(const Register& rd,
424 ASSERT(allow_macro_instructions_);
425 ASSERT(!rd.IsZero());
426 ASSERT((cond != al) && (cond != nv));
431 void MacroAssembler::Cls(const Register& rd, const Register& rn) {
432 ASSERT(allow_macro_instructions_);
433 ASSERT(!rd.IsZero());
438 void MacroAssembler::Clz(const Register& rd, const Register& rn) {
439 ASSERT(allow_macro_instructions_);
440 ASSERT(!rd.IsZero());
445 void MacroAssembler::Cneg(const Register& rd,
448 ASSERT(allow_macro_instructions_);
449 ASSERT(!rd.IsZero());
450 ASSERT((cond != al) && (cond != nv));
455 // Conditionally zero the destination register. Only X registers are supported
456 // due to the truncation side-effect when used on W registers.
457 void MacroAssembler::CzeroX(const Register& rd,
459 ASSERT(allow_macro_instructions_);
460 ASSERT(!rd.IsSP() && rd.Is64Bits());
461 ASSERT((cond != al) && (cond != nv));
462 csel(rd, xzr, rd, cond);
466 // Conditionally move a value into the destination register. Only X registers
467 // are supported due to the truncation side-effect when used on W registers.
468 void MacroAssembler::CmovX(const Register& rd,
471 ASSERT(allow_macro_instructions_);
473 ASSERT(rd.Is64Bits() && rn.Is64Bits());
474 ASSERT((cond != al) && (cond != nv));
476 csel(rd, rn, rd, cond);
481 void MacroAssembler::Cset(const Register& rd, Condition cond) {
482 ASSERT(allow_macro_instructions_);
483 ASSERT(!rd.IsZero());
484 ASSERT((cond != al) && (cond != nv));
489 void MacroAssembler::Csetm(const Register& rd, Condition cond) {
490 ASSERT(allow_macro_instructions_);
491 ASSERT(!rd.IsZero());
492 ASSERT((cond != al) && (cond != nv));
497 void MacroAssembler::Csinc(const Register& rd,
501 ASSERT(allow_macro_instructions_);
502 ASSERT(!rd.IsZero());
503 ASSERT((cond != al) && (cond != nv));
504 csinc(rd, rn, rm, cond);
508 void MacroAssembler::Csinv(const Register& rd,
512 ASSERT(allow_macro_instructions_);
513 ASSERT(!rd.IsZero());
514 ASSERT((cond != al) && (cond != nv));
515 csinv(rd, rn, rm, cond);
519 void MacroAssembler::Csneg(const Register& rd,
523 ASSERT(allow_macro_instructions_);
524 ASSERT(!rd.IsZero());
525 ASSERT((cond != al) && (cond != nv));
526 csneg(rd, rn, rm, cond);
530 void MacroAssembler::Dmb(BarrierDomain domain, BarrierType type) {
531 ASSERT(allow_macro_instructions_);
536 void MacroAssembler::Dsb(BarrierDomain domain, BarrierType type) {
537 ASSERT(allow_macro_instructions_);
542 void MacroAssembler::Debug(const char* message, uint32_t code, Instr params) {
543 ASSERT(allow_macro_instructions_);
544 debug(message, code, params);
548 void MacroAssembler::Extr(const Register& rd,
552 ASSERT(allow_macro_instructions_);
553 ASSERT(!rd.IsZero());
554 extr(rd, rn, rm, lsb);
558 void MacroAssembler::Fabs(const FPRegister& fd, const FPRegister& fn) {
559 ASSERT(allow_macro_instructions_);
564 void MacroAssembler::Fadd(const FPRegister& fd,
565 const FPRegister& fn,
566 const FPRegister& fm) {
567 ASSERT(allow_macro_instructions_);
572 void MacroAssembler::Fccmp(const FPRegister& fn,
573 const FPRegister& fm,
576 ASSERT(allow_macro_instructions_);
577 ASSERT((cond != al) && (cond != nv));
578 fccmp(fn, fm, nzcv, cond);
582 void MacroAssembler::Fcmp(const FPRegister& fn, const FPRegister& fm) {
583 ASSERT(allow_macro_instructions_);
588 void MacroAssembler::Fcmp(const FPRegister& fn, double value) {
589 ASSERT(allow_macro_instructions_);
591 UseScratchRegisterScope temps(this);
592 FPRegister tmp = temps.AcquireSameSizeAs(fn);
601 void MacroAssembler::Fcsel(const FPRegister& fd,
602 const FPRegister& fn,
603 const FPRegister& fm,
605 ASSERT(allow_macro_instructions_);
606 ASSERT((cond != al) && (cond != nv));
607 fcsel(fd, fn, fm, cond);
611 void MacroAssembler::Fcvt(const FPRegister& fd, const FPRegister& fn) {
612 ASSERT(allow_macro_instructions_);
617 void MacroAssembler::Fcvtas(const Register& rd, const FPRegister& fn) {
618 ASSERT(allow_macro_instructions_);
619 ASSERT(!rd.IsZero());
624 void MacroAssembler::Fcvtau(const Register& rd, const FPRegister& fn) {
625 ASSERT(allow_macro_instructions_);
626 ASSERT(!rd.IsZero());
631 void MacroAssembler::Fcvtms(const Register& rd, const FPRegister& fn) {
632 ASSERT(allow_macro_instructions_);
633 ASSERT(!rd.IsZero());
638 void MacroAssembler::Fcvtmu(const Register& rd, const FPRegister& fn) {
639 ASSERT(allow_macro_instructions_);
640 ASSERT(!rd.IsZero());
645 void MacroAssembler::Fcvtns(const Register& rd, const FPRegister& fn) {
646 ASSERT(allow_macro_instructions_);
647 ASSERT(!rd.IsZero());
652 void MacroAssembler::Fcvtnu(const Register& rd, const FPRegister& fn) {
653 ASSERT(allow_macro_instructions_);
654 ASSERT(!rd.IsZero());
659 void MacroAssembler::Fcvtzs(const Register& rd, const FPRegister& fn) {
660 ASSERT(allow_macro_instructions_);
661 ASSERT(!rd.IsZero());
664 void MacroAssembler::Fcvtzu(const Register& rd, const FPRegister& fn) {
665 ASSERT(allow_macro_instructions_);
666 ASSERT(!rd.IsZero());
671 void MacroAssembler::Fdiv(const FPRegister& fd,
672 const FPRegister& fn,
673 const FPRegister& fm) {
674 ASSERT(allow_macro_instructions_);
679 void MacroAssembler::Fmadd(const FPRegister& fd,
680 const FPRegister& fn,
681 const FPRegister& fm,
682 const FPRegister& fa) {
683 ASSERT(allow_macro_instructions_);
684 fmadd(fd, fn, fm, fa);
688 void MacroAssembler::Fmax(const FPRegister& fd,
689 const FPRegister& fn,
690 const FPRegister& fm) {
691 ASSERT(allow_macro_instructions_);
696 void MacroAssembler::Fmaxnm(const FPRegister& fd,
697 const FPRegister& fn,
698 const FPRegister& fm) {
699 ASSERT(allow_macro_instructions_);
704 void MacroAssembler::Fmin(const FPRegister& fd,
705 const FPRegister& fn,
706 const FPRegister& fm) {
707 ASSERT(allow_macro_instructions_);
712 void MacroAssembler::Fminnm(const FPRegister& fd,
713 const FPRegister& fn,
714 const FPRegister& fm) {
715 ASSERT(allow_macro_instructions_);
720 void MacroAssembler::Fmov(FPRegister fd, FPRegister fn) {
721 ASSERT(allow_macro_instructions_);
722 // Only emit an instruction if fd and fn are different, and they are both D
723 // registers. fmov(s0, s0) is not a no-op because it clears the top word of
724 // d0. Technically, fmov(d0, d0) is not a no-op either because it clears the
725 // top of q0, but FPRegister does not currently support Q registers.
726 if (!fd.Is(fn) || !fd.Is64Bits()) {
732 void MacroAssembler::Fmov(FPRegister fd, Register rn) {
733 ASSERT(allow_macro_instructions_);
738 void MacroAssembler::Fmov(FPRegister fd, double imm) {
739 ASSERT(allow_macro_instructions_);
741 Fmov(fd, static_cast<float>(imm));
745 ASSERT(fd.Is64Bits());
746 if (IsImmFP64(imm)) {
748 } else if ((imm == 0.0) && (copysign(1.0, imm) == 1.0)) {
751 UseScratchRegisterScope temps(this);
752 Register tmp = temps.AcquireX();
753 // TODO(all): Use Assembler::ldr(const FPRegister& ft, double imm).
754 Mov(tmp, double_to_rawbits(imm));
760 void MacroAssembler::Fmov(FPRegister fd, float imm) {
761 ASSERT(allow_macro_instructions_);
763 Fmov(fd, static_cast<double>(imm));
767 ASSERT(fd.Is32Bits());
768 if (IsImmFP32(imm)) {
770 } else if ((imm == 0.0) && (copysign(1.0, imm) == 1.0)) {
773 UseScratchRegisterScope temps(this);
774 Register tmp = temps.AcquireW();
775 // TODO(all): Use Assembler::ldr(const FPRegister& ft, float imm).
776 Mov(tmp, float_to_rawbits(imm));
782 void MacroAssembler::Fmov(Register rd, FPRegister fn) {
783 ASSERT(allow_macro_instructions_);
784 ASSERT(!rd.IsZero());
789 void MacroAssembler::Fmsub(const FPRegister& fd,
790 const FPRegister& fn,
791 const FPRegister& fm,
792 const FPRegister& fa) {
793 ASSERT(allow_macro_instructions_);
794 fmsub(fd, fn, fm, fa);
798 void MacroAssembler::Fmul(const FPRegister& fd,
799 const FPRegister& fn,
800 const FPRegister& fm) {
801 ASSERT(allow_macro_instructions_);
806 void MacroAssembler::Fneg(const FPRegister& fd, const FPRegister& fn) {
807 ASSERT(allow_macro_instructions_);
812 void MacroAssembler::Fnmadd(const FPRegister& fd,
813 const FPRegister& fn,
814 const FPRegister& fm,
815 const FPRegister& fa) {
816 ASSERT(allow_macro_instructions_);
817 fnmadd(fd, fn, fm, fa);
821 void MacroAssembler::Fnmsub(const FPRegister& fd,
822 const FPRegister& fn,
823 const FPRegister& fm,
824 const FPRegister& fa) {
825 ASSERT(allow_macro_instructions_);
826 fnmsub(fd, fn, fm, fa);
830 void MacroAssembler::Frinta(const FPRegister& fd, const FPRegister& fn) {
831 ASSERT(allow_macro_instructions_);
836 void MacroAssembler::Frintn(const FPRegister& fd, const FPRegister& fn) {
837 ASSERT(allow_macro_instructions_);
842 void MacroAssembler::Frintz(const FPRegister& fd, const FPRegister& fn) {
843 ASSERT(allow_macro_instructions_);
848 void MacroAssembler::Fsqrt(const FPRegister& fd, const FPRegister& fn) {
849 ASSERT(allow_macro_instructions_);
854 void MacroAssembler::Fsub(const FPRegister& fd,
855 const FPRegister& fn,
856 const FPRegister& fm) {
857 ASSERT(allow_macro_instructions_);
862 void MacroAssembler::Hint(SystemHint code) {
863 ASSERT(allow_macro_instructions_);
868 void MacroAssembler::Hlt(int code) {
869 ASSERT(allow_macro_instructions_);
874 void MacroAssembler::Isb() {
875 ASSERT(allow_macro_instructions_);
880 void MacroAssembler::Ldnp(const CPURegister& rt,
881 const CPURegister& rt2,
882 const MemOperand& src) {
883 ASSERT(allow_macro_instructions_);
884 ASSERT(!AreAliased(rt, rt2));
889 void MacroAssembler::Ldp(const CPURegister& rt,
890 const CPURegister& rt2,
891 const MemOperand& src) {
892 ASSERT(allow_macro_instructions_);
893 ASSERT(!AreAliased(rt, rt2));
898 void MacroAssembler::Ldpsw(const Register& rt,
900 const MemOperand& src) {
901 ASSERT(allow_macro_instructions_);
902 ASSERT(!rt.IsZero());
903 ASSERT(!rt2.IsZero());
908 void MacroAssembler::Ldr(const FPRegister& ft, double imm) {
909 ASSERT(allow_macro_instructions_);
914 void MacroAssembler::Ldr(const Register& rt, uint64_t imm) {
915 ASSERT(allow_macro_instructions_);
916 ASSERT(!rt.IsZero());
921 void MacroAssembler::Lsl(const Register& rd,
924 ASSERT(allow_macro_instructions_);
925 ASSERT(!rd.IsZero());
930 void MacroAssembler::Lsl(const Register& rd,
932 const Register& rm) {
933 ASSERT(allow_macro_instructions_);
934 ASSERT(!rd.IsZero());
939 void MacroAssembler::Lsr(const Register& rd,
942 ASSERT(allow_macro_instructions_);
943 ASSERT(!rd.IsZero());
948 void MacroAssembler::Lsr(const Register& rd,
950 const Register& rm) {
951 ASSERT(allow_macro_instructions_);
952 ASSERT(!rd.IsZero());
957 void MacroAssembler::Madd(const Register& rd,
960 const Register& ra) {
961 ASSERT(allow_macro_instructions_);
962 ASSERT(!rd.IsZero());
963 madd(rd, rn, rm, ra);
967 void MacroAssembler::Mneg(const Register& rd,
969 const Register& rm) {
970 ASSERT(allow_macro_instructions_);
971 ASSERT(!rd.IsZero());
976 void MacroAssembler::Mov(const Register& rd, const Register& rn) {
977 ASSERT(allow_macro_instructions_);
978 ASSERT(!rd.IsZero());
979 // Emit a register move only if the registers are distinct, or if they are
980 // not X registers. Note that mov(w0, w0) is not a no-op because it clears
981 // the top word of x0.
982 if (!rd.Is(rn) || !rd.Is64Bits()) {
983 Assembler::mov(rd, rn);
988 void MacroAssembler::Movk(const Register& rd, uint64_t imm, int shift) {
989 ASSERT(allow_macro_instructions_);
990 ASSERT(!rd.IsZero());
991 movk(rd, imm, shift);
995 void MacroAssembler::Mrs(const Register& rt, SystemRegister sysreg) {
996 ASSERT(allow_macro_instructions_);
997 ASSERT(!rt.IsZero());
1002 void MacroAssembler::Msr(SystemRegister sysreg, const Register& rt) {
1003 ASSERT(allow_macro_instructions_);
1004 ASSERT(!rt.IsZero());
1009 void MacroAssembler::Msub(const Register& rd,
1012 const Register& ra) {
1013 ASSERT(allow_macro_instructions_);
1014 ASSERT(!rd.IsZero());
1015 msub(rd, rn, rm, ra);
1019 void MacroAssembler::Mul(const Register& rd,
1021 const Register& rm) {
1022 ASSERT(allow_macro_instructions_);
1023 ASSERT(!rd.IsZero());
1028 void MacroAssembler::Rbit(const Register& rd, const Register& rn) {
1029 ASSERT(allow_macro_instructions_);
1030 ASSERT(!rd.IsZero());
1035 void MacroAssembler::Ret(const Register& xn) {
1036 ASSERT(allow_macro_instructions_);
1037 ASSERT(!xn.IsZero());
1039 CheckVeneerPool(false, false);
1043 void MacroAssembler::Rev(const Register& rd, const Register& rn) {
1044 ASSERT(allow_macro_instructions_);
1045 ASSERT(!rd.IsZero());
1050 void MacroAssembler::Rev16(const Register& rd, const Register& rn) {
1051 ASSERT(allow_macro_instructions_);
1052 ASSERT(!rd.IsZero());
1057 void MacroAssembler::Rev32(const Register& rd, const Register& rn) {
1058 ASSERT(allow_macro_instructions_);
1059 ASSERT(!rd.IsZero());
1064 void MacroAssembler::Ror(const Register& rd,
1067 ASSERT(allow_macro_instructions_);
1068 ASSERT(!rd.IsZero());
1073 void MacroAssembler::Ror(const Register& rd,
1075 const Register& rm) {
1076 ASSERT(allow_macro_instructions_);
1077 ASSERT(!rd.IsZero());
1082 void MacroAssembler::Sbfiz(const Register& rd,
1086 ASSERT(allow_macro_instructions_);
1087 ASSERT(!rd.IsZero());
1088 sbfiz(rd, rn, lsb, width);
1092 void MacroAssembler::Sbfx(const Register& rd,
1096 ASSERT(allow_macro_instructions_);
1097 ASSERT(!rd.IsZero());
1098 sbfx(rd, rn, lsb, width);
1102 void MacroAssembler::Scvtf(const FPRegister& fd,
1105 ASSERT(allow_macro_instructions_);
1106 scvtf(fd, rn, fbits);
1110 void MacroAssembler::Sdiv(const Register& rd,
1112 const Register& rm) {
1113 ASSERT(allow_macro_instructions_);
1114 ASSERT(!rd.IsZero());
1119 void MacroAssembler::Smaddl(const Register& rd,
1122 const Register& ra) {
1123 ASSERT(allow_macro_instructions_);
1124 ASSERT(!rd.IsZero());
1125 smaddl(rd, rn, rm, ra);
1129 void MacroAssembler::Smsubl(const Register& rd,
1132 const Register& ra) {
1133 ASSERT(allow_macro_instructions_);
1134 ASSERT(!rd.IsZero());
1135 smsubl(rd, rn, rm, ra);
1139 void MacroAssembler::Smull(const Register& rd,
1141 const Register& rm) {
1142 ASSERT(allow_macro_instructions_);
1143 ASSERT(!rd.IsZero());
1148 void MacroAssembler::Smulh(const Register& rd,
1150 const Register& rm) {
1151 ASSERT(allow_macro_instructions_);
1152 ASSERT(!rd.IsZero());
1157 void MacroAssembler::Stnp(const CPURegister& rt,
1158 const CPURegister& rt2,
1159 const MemOperand& dst) {
1160 ASSERT(allow_macro_instructions_);
1165 void MacroAssembler::Stp(const CPURegister& rt,
1166 const CPURegister& rt2,
1167 const MemOperand& dst) {
1168 ASSERT(allow_macro_instructions_);
1173 void MacroAssembler::Sxtb(const Register& rd, const Register& rn) {
1174 ASSERT(allow_macro_instructions_);
1175 ASSERT(!rd.IsZero());
1180 void MacroAssembler::Sxth(const Register& rd, const Register& rn) {
1181 ASSERT(allow_macro_instructions_);
1182 ASSERT(!rd.IsZero());
1187 void MacroAssembler::Sxtw(const Register& rd, const Register& rn) {
1188 ASSERT(allow_macro_instructions_);
1189 ASSERT(!rd.IsZero());
1194 void MacroAssembler::Ubfiz(const Register& rd,
1198 ASSERT(allow_macro_instructions_);
1199 ASSERT(!rd.IsZero());
1200 ubfiz(rd, rn, lsb, width);
1204 void MacroAssembler::Ubfx(const Register& rd,
1208 ASSERT(allow_macro_instructions_);
1209 ASSERT(!rd.IsZero());
1210 ubfx(rd, rn, lsb, width);
1214 void MacroAssembler::Ucvtf(const FPRegister& fd,
1217 ASSERT(allow_macro_instructions_);
1218 ucvtf(fd, rn, fbits);
1222 void MacroAssembler::Udiv(const Register& rd,
1224 const Register& rm) {
1225 ASSERT(allow_macro_instructions_);
1226 ASSERT(!rd.IsZero());
1231 void MacroAssembler::Umaddl(const Register& rd,
1234 const Register& ra) {
1235 ASSERT(allow_macro_instructions_);
1236 ASSERT(!rd.IsZero());
1237 umaddl(rd, rn, rm, ra);
1241 void MacroAssembler::Umsubl(const Register& rd,
1244 const Register& ra) {
1245 ASSERT(allow_macro_instructions_);
1246 ASSERT(!rd.IsZero());
1247 umsubl(rd, rn, rm, ra);
1251 void MacroAssembler::Uxtb(const Register& rd, const Register& rn) {
1252 ASSERT(allow_macro_instructions_);
1253 ASSERT(!rd.IsZero());
1258 void MacroAssembler::Uxth(const Register& rd, const Register& rn) {
1259 ASSERT(allow_macro_instructions_);
1260 ASSERT(!rd.IsZero());
1265 void MacroAssembler::Uxtw(const Register& rd, const Register& rn) {
1266 ASSERT(allow_macro_instructions_);
1267 ASSERT(!rd.IsZero());
1272 void MacroAssembler::BumpSystemStackPointer(const Operand& space) {
1273 ASSERT(!csp.Is(sp_));
1274 // TODO(jbramley): Several callers rely on this not using scratch registers,
1275 // so we use the assembler directly here. However, this means that large
1276 // immediate values of 'space' cannot be handled cleanly. (Only 24-bits
1277 // immediates or values of 'space' that can be encoded in one instruction are
1278 // accepted.) Once we implement our flexible scratch register idea, we could
1279 // greatly simplify this function.
1280 InstructionAccurateScope scope(this);
1281 if ((space.IsImmediate()) && !is_uint12(space.immediate())) {
1282 // The subtract instruction supports a 12-bit immediate, shifted left by
1283 // zero or 12 bits. So, in two instructions, we can subtract any immediate
1284 // between zero and (1 << 24) - 1.
1285 int64_t imm = space.immediate();
1286 ASSERT(is_uint24(imm));
1288 int64_t imm_top_12_bits = imm >> 12;
1289 sub(csp, StackPointer(), imm_top_12_bits << 12);
1290 imm -= imm_top_12_bits << 12;
1295 sub(csp, StackPointer(), space);
1300 void MacroAssembler::InitializeRootRegister() {
1301 ExternalReference roots_array_start =
1302 ExternalReference::roots_array_start(isolate());
1303 Mov(root, Operand(roots_array_start));
1307 void MacroAssembler::SmiTag(Register dst, Register src) {
1308 ASSERT(dst.Is64Bits() && src.Is64Bits());
1309 Lsl(dst, src, kSmiShift);
1313 void MacroAssembler::SmiTag(Register smi) { SmiTag(smi, smi); }
1316 void MacroAssembler::SmiUntag(Register dst, Register src) {
1317 ASSERT(dst.Is64Bits() && src.Is64Bits());
1318 if (FLAG_enable_slow_asserts) {
1321 Asr(dst, src, kSmiShift);
1325 void MacroAssembler::SmiUntag(Register smi) { SmiUntag(smi, smi); }
1328 void MacroAssembler::SmiUntagToDouble(FPRegister dst,
1331 ASSERT(dst.Is64Bits() && src.Is64Bits());
1332 if (FLAG_enable_slow_asserts && (mode == kNotSpeculativeUntag)) {
1335 Scvtf(dst, src, kSmiShift);
1339 void MacroAssembler::SmiUntagToFloat(FPRegister dst,
1342 ASSERT(dst.Is32Bits() && src.Is64Bits());
1343 if (FLAG_enable_slow_asserts && (mode == kNotSpeculativeUntag)) {
1346 Scvtf(dst, src, kSmiShift);
1350 void MacroAssembler::JumpIfSmi(Register value,
1352 Label* not_smi_label) {
1353 STATIC_ASSERT((kSmiTagSize == 1) && (kSmiTag == 0));
1354 // Check if the tag bit is set.
1356 Tbz(value, 0, smi_label);
1357 if (not_smi_label) {
1361 ASSERT(not_smi_label);
1362 Tbnz(value, 0, not_smi_label);
1367 void MacroAssembler::JumpIfNotSmi(Register value, Label* not_smi_label) {
1368 JumpIfSmi(value, NULL, not_smi_label);
1372 void MacroAssembler::JumpIfBothSmi(Register value1,
1374 Label* both_smi_label,
1375 Label* not_smi_label) {
1376 STATIC_ASSERT((kSmiTagSize == 1) && (kSmiTag == 0));
1377 UseScratchRegisterScope temps(this);
1378 Register tmp = temps.AcquireX();
1379 // Check if both tag bits are clear.
1380 Orr(tmp, value1, value2);
1381 JumpIfSmi(tmp, both_smi_label, not_smi_label);
1385 void MacroAssembler::JumpIfEitherSmi(Register value1,
1387 Label* either_smi_label,
1388 Label* not_smi_label) {
1389 STATIC_ASSERT((kSmiTagSize == 1) && (kSmiTag == 0));
1390 UseScratchRegisterScope temps(this);
1391 Register tmp = temps.AcquireX();
1392 // Check if either tag bit is clear.
1393 And(tmp, value1, value2);
1394 JumpIfSmi(tmp, either_smi_label, not_smi_label);
1398 void MacroAssembler::JumpIfEitherNotSmi(Register value1,
1400 Label* not_smi_label) {
1401 JumpIfBothSmi(value1, value2, NULL, not_smi_label);
1405 void MacroAssembler::JumpIfBothNotSmi(Register value1,
1407 Label* not_smi_label) {
1408 JumpIfEitherSmi(value1, value2, NULL, not_smi_label);
1412 void MacroAssembler::IsObjectNameType(Register object,
1415 CompareObjectType(object, type, type, LAST_NAME_TYPE);
1420 void MacroAssembler::IsObjectJSObjectType(Register heap_object,
1424 Ldr(map, FieldMemOperand(heap_object, HeapObject::kMapOffset));
1425 IsInstanceJSObjectType(map, scratch, fail);
1429 void MacroAssembler::IsInstanceJSObjectType(Register map,
1432 Ldrb(scratch, FieldMemOperand(map, Map::kInstanceTypeOffset));
1433 // If cmp result is lt, the following ccmp will clear all flags.
1434 // Z == 0, N == V implies gt condition.
1435 Cmp(scratch, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE);
1436 Ccmp(scratch, LAST_NONCALLABLE_SPEC_OBJECT_TYPE, NoFlag, ge);
1438 // If we didn't get a valid label object just fall through and leave the
1446 void MacroAssembler::IsObjectJSStringType(Register object,
1450 Ldr(type, FieldMemOperand(object, HeapObject::kMapOffset));
1451 Ldrb(type.W(), FieldMemOperand(type, Map::kInstanceTypeOffset));
1453 STATIC_ASSERT(kStringTag == 0);
1454 ASSERT((string != NULL) || (not_string != NULL));
1455 if (string == NULL) {
1456 TestAndBranchIfAnySet(type.W(), kIsNotStringMask, not_string);
1457 } else if (not_string == NULL) {
1458 TestAndBranchIfAllClear(type.W(), kIsNotStringMask, string);
1460 TestAndBranchIfAnySet(type.W(), kIsNotStringMask, not_string);
1466 void MacroAssembler::Push(Handle<Object> handle) {
1467 UseScratchRegisterScope temps(this);
1468 Register tmp = temps.AcquireX();
1469 Mov(tmp, Operand(handle));
1474 void MacroAssembler::Claim(uint64_t count, uint64_t unit_size) {
1475 uint64_t size = count * unit_size;
1481 if (csp.Is(StackPointer())) {
1482 ASSERT(size % 16 == 0);
1484 BumpSystemStackPointer(size);
1487 Sub(StackPointer(), StackPointer(), size);
1491 void MacroAssembler::Claim(const Register& count, uint64_t unit_size) {
1492 ASSERT(IsPowerOf2(unit_size));
1494 if (unit_size == 0) {
1498 const int shift = CountTrailingZeros(unit_size, kXRegSizeInBits);
1499 const Operand size(count, LSL, shift);
1501 if (size.IsZero()) {
1505 if (!csp.Is(StackPointer())) {
1506 BumpSystemStackPointer(size);
1509 Sub(StackPointer(), StackPointer(), size);
1513 void MacroAssembler::ClaimBySMI(const Register& count_smi, uint64_t unit_size) {
1514 ASSERT(IsPowerOf2(unit_size));
1515 const int shift = CountTrailingZeros(unit_size, kXRegSizeInBits) - kSmiShift;
1516 const Operand size(count_smi,
1517 (shift >= 0) ? (LSL) : (LSR),
1518 (shift >= 0) ? (shift) : (-shift));
1520 if (size.IsZero()) {
1524 if (!csp.Is(StackPointer())) {
1525 BumpSystemStackPointer(size);
1528 Sub(StackPointer(), StackPointer(), size);
1532 void MacroAssembler::Drop(uint64_t count, uint64_t unit_size) {
1533 uint64_t size = count * unit_size;
1539 Add(StackPointer(), StackPointer(), size);
1541 if (csp.Is(StackPointer())) {
1542 ASSERT(size % 16 == 0);
1543 } else if (emit_debug_code()) {
1544 // It is safe to leave csp where it is when unwinding the JavaScript stack,
1545 // but if we keep it matching StackPointer, the simulator can detect memory
1546 // accesses in the now-free part of the stack.
1547 Mov(csp, StackPointer());
1552 void MacroAssembler::Drop(const Register& count, uint64_t unit_size) {
1553 ASSERT(IsPowerOf2(unit_size));
1555 if (unit_size == 0) {
1559 const int shift = CountTrailingZeros(unit_size, kXRegSizeInBits);
1560 const Operand size(count, LSL, shift);
1562 if (size.IsZero()) {
1566 Add(StackPointer(), StackPointer(), size);
1568 if (!csp.Is(StackPointer()) && emit_debug_code()) {
1569 // It is safe to leave csp where it is when unwinding the JavaScript stack,
1570 // but if we keep it matching StackPointer, the simulator can detect memory
1571 // accesses in the now-free part of the stack.
1572 Mov(csp, StackPointer());
1577 void MacroAssembler::DropBySMI(const Register& count_smi, uint64_t unit_size) {
1578 ASSERT(IsPowerOf2(unit_size));
1579 const int shift = CountTrailingZeros(unit_size, kXRegSizeInBits) - kSmiShift;
1580 const Operand size(count_smi,
1581 (shift >= 0) ? (LSL) : (LSR),
1582 (shift >= 0) ? (shift) : (-shift));
1584 if (size.IsZero()) {
1588 Add(StackPointer(), StackPointer(), size);
1590 if (!csp.Is(StackPointer()) && emit_debug_code()) {
1591 // It is safe to leave csp where it is when unwinding the JavaScript stack,
1592 // but if we keep it matching StackPointer, the simulator can detect memory
1593 // accesses in the now-free part of the stack.
1594 Mov(csp, StackPointer());
1599 void MacroAssembler::CompareAndBranch(const Register& lhs,
1603 if (rhs.IsImmediate() && (rhs.immediate() == 0) &&
1604 ((cond == eq) || (cond == ne))) {
1617 void MacroAssembler::TestAndBranchIfAnySet(const Register& reg,
1618 const uint64_t bit_pattern,
1620 int bits = reg.SizeInBits();
1621 ASSERT(CountSetBits(bit_pattern, bits) > 0);
1622 if (CountSetBits(bit_pattern, bits) == 1) {
1623 Tbnz(reg, MaskToBit(bit_pattern), label);
1625 Tst(reg, bit_pattern);
1631 void MacroAssembler::TestAndBranchIfAllClear(const Register& reg,
1632 const uint64_t bit_pattern,
1634 int bits = reg.SizeInBits();
1635 ASSERT(CountSetBits(bit_pattern, bits) > 0);
1636 if (CountSetBits(bit_pattern, bits) == 1) {
1637 Tbz(reg, MaskToBit(bit_pattern), label);
1639 Tst(reg, bit_pattern);
1645 void MacroAssembler::InlineData(uint64_t data) {
1646 ASSERT(is_uint16(data));
1647 InstructionAccurateScope scope(this, 1);
1652 void MacroAssembler::EnableInstrumentation() {
1653 InstructionAccurateScope scope(this, 1);
1654 movn(xzr, InstrumentStateEnable);
1658 void MacroAssembler::DisableInstrumentation() {
1659 InstructionAccurateScope scope(this, 1);
1660 movn(xzr, InstrumentStateDisable);
1664 void MacroAssembler::AnnotateInstrumentation(const char* marker_name) {
1665 ASSERT(strlen(marker_name) == 2);
1667 // We allow only printable characters in the marker names. Unprintable
1668 // characters are reserved for controlling features of the instrumentation.
1669 ASSERT(isprint(marker_name[0]) && isprint(marker_name[1]));
1671 InstructionAccurateScope scope(this, 1);
1672 movn(xzr, (marker_name[1] << 8) | marker_name[0]);
1675 } } // namespace v8::internal
1677 #endif // V8_ARM64_MACRO_ASSEMBLER_ARM64_INL_H_