1 // Copyright 2013 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #ifndef V8_ARM64_MACRO_ASSEMBLER_ARM64_INL_H_
6 #define V8_ARM64_MACRO_ASSEMBLER_ARM64_INL_H_
10 #include "src/globals.h"
12 #include "src/arm64/assembler-arm64-inl.h"
13 #include "src/arm64/assembler-arm64.h"
14 #include "src/arm64/instrument-arm64.h"
15 #include "src/arm64/macro-assembler-arm64.h"
16 #include "src/base/bits.h"
23 MemOperand FieldMemOperand(Register object, int offset) {
24 return MemOperand(object, offset - kHeapObjectTag);
28 MemOperand UntagSmiFieldMemOperand(Register object, int offset) {
29 return UntagSmiMemOperand(object, offset - kHeapObjectTag);
33 MemOperand UntagSmiMemOperand(Register object, int offset) {
34 // Assumes that Smis are shifted by 32 bits and little endianness.
35 STATIC_ASSERT(kSmiShift == 32);
36 return MemOperand(object, offset + (kSmiShift / kBitsPerByte));
40 Handle<Object> MacroAssembler::CodeObject() {
41 DCHECK(!code_object_.is_null());
46 void MacroAssembler::And(const Register& rd,
48 const Operand& operand) {
49 DCHECK(allow_macro_instructions_);
51 LogicalMacro(rd, rn, operand, AND);
55 void MacroAssembler::Ands(const Register& rd,
57 const Operand& operand) {
58 DCHECK(allow_macro_instructions_);
60 LogicalMacro(rd, rn, operand, ANDS);
64 void MacroAssembler::Tst(const Register& rn,
65 const Operand& operand) {
66 DCHECK(allow_macro_instructions_);
67 LogicalMacro(AppropriateZeroRegFor(rn), rn, operand, ANDS);
71 void MacroAssembler::Bic(const Register& rd,
73 const Operand& operand) {
74 DCHECK(allow_macro_instructions_);
76 LogicalMacro(rd, rn, operand, BIC);
80 void MacroAssembler::Bics(const Register& rd,
82 const Operand& operand) {
83 DCHECK(allow_macro_instructions_);
85 LogicalMacro(rd, rn, operand, BICS);
89 void MacroAssembler::Orr(const Register& rd,
91 const Operand& operand) {
92 DCHECK(allow_macro_instructions_);
94 LogicalMacro(rd, rn, operand, ORR);
98 void MacroAssembler::Orn(const Register& rd,
100 const Operand& operand) {
101 DCHECK(allow_macro_instructions_);
102 DCHECK(!rd.IsZero());
103 LogicalMacro(rd, rn, operand, ORN);
107 void MacroAssembler::Eor(const Register& rd,
109 const Operand& operand) {
110 DCHECK(allow_macro_instructions_);
111 DCHECK(!rd.IsZero());
112 LogicalMacro(rd, rn, operand, EOR);
116 void MacroAssembler::Eon(const Register& rd,
118 const Operand& operand) {
119 DCHECK(allow_macro_instructions_);
120 DCHECK(!rd.IsZero());
121 LogicalMacro(rd, rn, operand, EON);
125 void MacroAssembler::Ccmp(const Register& rn,
126 const Operand& operand,
129 DCHECK(allow_macro_instructions_);
130 if (operand.IsImmediate() && (operand.ImmediateValue() < 0)) {
131 ConditionalCompareMacro(rn, -operand.ImmediateValue(), nzcv, cond, CCMN);
133 ConditionalCompareMacro(rn, operand, nzcv, cond, CCMP);
138 void MacroAssembler::Ccmn(const Register& rn,
139 const Operand& operand,
142 DCHECK(allow_macro_instructions_);
143 if (operand.IsImmediate() && (operand.ImmediateValue() < 0)) {
144 ConditionalCompareMacro(rn, -operand.ImmediateValue(), nzcv, cond, CCMP);
146 ConditionalCompareMacro(rn, operand, nzcv, cond, CCMN);
151 void MacroAssembler::Add(const Register& rd,
153 const Operand& operand) {
154 DCHECK(allow_macro_instructions_);
155 if (operand.IsImmediate() && (operand.ImmediateValue() < 0) &&
156 IsImmAddSub(-operand.ImmediateValue())) {
157 AddSubMacro(rd, rn, -operand.ImmediateValue(), LeaveFlags, SUB);
159 AddSubMacro(rd, rn, operand, LeaveFlags, ADD);
163 void MacroAssembler::Adds(const Register& rd,
165 const Operand& operand) {
166 DCHECK(allow_macro_instructions_);
167 if (operand.IsImmediate() && (operand.ImmediateValue() < 0) &&
168 IsImmAddSub(-operand.ImmediateValue())) {
169 AddSubMacro(rd, rn, -operand.ImmediateValue(), SetFlags, SUB);
171 AddSubMacro(rd, rn, operand, SetFlags, ADD);
176 void MacroAssembler::Sub(const Register& rd,
178 const Operand& operand) {
179 DCHECK(allow_macro_instructions_);
180 if (operand.IsImmediate() && (operand.ImmediateValue() < 0) &&
181 IsImmAddSub(-operand.ImmediateValue())) {
182 AddSubMacro(rd, rn, -operand.ImmediateValue(), LeaveFlags, ADD);
184 AddSubMacro(rd, rn, operand, LeaveFlags, SUB);
189 void MacroAssembler::Subs(const Register& rd,
191 const Operand& operand) {
192 DCHECK(allow_macro_instructions_);
193 if (operand.IsImmediate() && (operand.ImmediateValue() < 0) &&
194 IsImmAddSub(-operand.ImmediateValue())) {
195 AddSubMacro(rd, rn, -operand.ImmediateValue(), SetFlags, ADD);
197 AddSubMacro(rd, rn, operand, SetFlags, SUB);
202 void MacroAssembler::Cmn(const Register& rn, const Operand& operand) {
203 DCHECK(allow_macro_instructions_);
204 Adds(AppropriateZeroRegFor(rn), rn, operand);
208 void MacroAssembler::Cmp(const Register& rn, const Operand& operand) {
209 DCHECK(allow_macro_instructions_);
210 Subs(AppropriateZeroRegFor(rn), rn, operand);
214 void MacroAssembler::Neg(const Register& rd,
215 const Operand& operand) {
216 DCHECK(allow_macro_instructions_);
217 DCHECK(!rd.IsZero());
218 if (operand.IsImmediate()) {
219 Mov(rd, -operand.ImmediateValue());
221 Sub(rd, AppropriateZeroRegFor(rd), operand);
226 void MacroAssembler::Negs(const Register& rd,
227 const Operand& operand) {
228 DCHECK(allow_macro_instructions_);
229 Subs(rd, AppropriateZeroRegFor(rd), operand);
233 void MacroAssembler::Adc(const Register& rd,
235 const Operand& operand) {
236 DCHECK(allow_macro_instructions_);
237 DCHECK(!rd.IsZero());
238 AddSubWithCarryMacro(rd, rn, operand, LeaveFlags, ADC);
242 void MacroAssembler::Adcs(const Register& rd,
244 const Operand& operand) {
245 DCHECK(allow_macro_instructions_);
246 DCHECK(!rd.IsZero());
247 AddSubWithCarryMacro(rd, rn, operand, SetFlags, ADC);
251 void MacroAssembler::Sbc(const Register& rd,
253 const Operand& operand) {
254 DCHECK(allow_macro_instructions_);
255 DCHECK(!rd.IsZero());
256 AddSubWithCarryMacro(rd, rn, operand, LeaveFlags, SBC);
260 void MacroAssembler::Sbcs(const Register& rd,
262 const Operand& operand) {
263 DCHECK(allow_macro_instructions_);
264 DCHECK(!rd.IsZero());
265 AddSubWithCarryMacro(rd, rn, operand, SetFlags, SBC);
269 void MacroAssembler::Ngc(const Register& rd,
270 const Operand& operand) {
271 DCHECK(allow_macro_instructions_);
272 DCHECK(!rd.IsZero());
273 Register zr = AppropriateZeroRegFor(rd);
274 Sbc(rd, zr, operand);
278 void MacroAssembler::Ngcs(const Register& rd,
279 const Operand& operand) {
280 DCHECK(allow_macro_instructions_);
281 DCHECK(!rd.IsZero());
282 Register zr = AppropriateZeroRegFor(rd);
283 Sbcs(rd, zr, operand);
287 void MacroAssembler::Mvn(const Register& rd, uint64_t imm) {
288 DCHECK(allow_macro_instructions_);
289 DCHECK(!rd.IsZero());
294 #define DEFINE_FUNCTION(FN, REGTYPE, REG, OP) \
295 void MacroAssembler::FN(const REGTYPE REG, const MemOperand& addr) { \
296 DCHECK(allow_macro_instructions_); \
297 LoadStoreMacro(REG, addr, OP); \
299 LS_MACRO_LIST(DEFINE_FUNCTION)
300 #undef DEFINE_FUNCTION
303 #define DEFINE_FUNCTION(FN, REGTYPE, REG, REG2, OP) \
304 void MacroAssembler::FN(const REGTYPE REG, const REGTYPE REG2, \
305 const MemOperand& addr) { \
306 DCHECK(allow_macro_instructions_); \
307 LoadStorePairMacro(REG, REG2, addr, OP); \
309 LSPAIR_MACRO_LIST(DEFINE_FUNCTION)
310 #undef DEFINE_FUNCTION
313 void MacroAssembler::Asr(const Register& rd,
316 DCHECK(allow_macro_instructions_);
317 DCHECK(!rd.IsZero());
322 void MacroAssembler::Asr(const Register& rd,
324 const Register& rm) {
325 DCHECK(allow_macro_instructions_);
326 DCHECK(!rd.IsZero());
331 void MacroAssembler::B(Label* label) {
333 CheckVeneerPool(false, false);
337 void MacroAssembler::B(Condition cond, Label* label) {
338 DCHECK(allow_macro_instructions_);
343 void MacroAssembler::Bfi(const Register& rd,
347 DCHECK(allow_macro_instructions_);
348 DCHECK(!rd.IsZero());
349 bfi(rd, rn, lsb, width);
353 void MacroAssembler::Bfxil(const Register& rd,
357 DCHECK(allow_macro_instructions_);
358 DCHECK(!rd.IsZero());
359 bfxil(rd, rn, lsb, width);
363 void MacroAssembler::Bind(Label* label) {
364 DCHECK(allow_macro_instructions_);
369 void MacroAssembler::Bl(Label* label) {
370 DCHECK(allow_macro_instructions_);
375 void MacroAssembler::Blr(const Register& xn) {
376 DCHECK(allow_macro_instructions_);
377 DCHECK(!xn.IsZero());
382 void MacroAssembler::Br(const Register& xn) {
383 DCHECK(allow_macro_instructions_);
384 DCHECK(!xn.IsZero());
389 void MacroAssembler::Brk(int code) {
390 DCHECK(allow_macro_instructions_);
395 void MacroAssembler::Cinc(const Register& rd,
398 DCHECK(allow_macro_instructions_);
399 DCHECK(!rd.IsZero());
400 DCHECK((cond != al) && (cond != nv));
405 void MacroAssembler::Cinv(const Register& rd,
408 DCHECK(allow_macro_instructions_);
409 DCHECK(!rd.IsZero());
410 DCHECK((cond != al) && (cond != nv));
415 void MacroAssembler::Cls(const Register& rd, const Register& rn) {
416 DCHECK(allow_macro_instructions_);
417 DCHECK(!rd.IsZero());
422 void MacroAssembler::Clz(const Register& rd, const Register& rn) {
423 DCHECK(allow_macro_instructions_);
424 DCHECK(!rd.IsZero());
429 void MacroAssembler::Cneg(const Register& rd,
432 DCHECK(allow_macro_instructions_);
433 DCHECK(!rd.IsZero());
434 DCHECK((cond != al) && (cond != nv));
439 // Conditionally zero the destination register. Only X registers are supported
440 // due to the truncation side-effect when used on W registers.
441 void MacroAssembler::CzeroX(const Register& rd,
443 DCHECK(allow_macro_instructions_);
444 DCHECK(!rd.IsSP() && rd.Is64Bits());
445 DCHECK((cond != al) && (cond != nv));
446 csel(rd, xzr, rd, cond);
450 // Conditionally move a value into the destination register. Only X registers
451 // are supported due to the truncation side-effect when used on W registers.
452 void MacroAssembler::CmovX(const Register& rd,
455 DCHECK(allow_macro_instructions_);
457 DCHECK(rd.Is64Bits() && rn.Is64Bits());
458 DCHECK((cond != al) && (cond != nv));
460 csel(rd, rn, rd, cond);
465 void MacroAssembler::Cset(const Register& rd, Condition cond) {
466 DCHECK(allow_macro_instructions_);
467 DCHECK(!rd.IsZero());
468 DCHECK((cond != al) && (cond != nv));
473 void MacroAssembler::Csetm(const Register& rd, Condition cond) {
474 DCHECK(allow_macro_instructions_);
475 DCHECK(!rd.IsZero());
476 DCHECK((cond != al) && (cond != nv));
481 void MacroAssembler::Csinc(const Register& rd,
485 DCHECK(allow_macro_instructions_);
486 DCHECK(!rd.IsZero());
487 DCHECK((cond != al) && (cond != nv));
488 csinc(rd, rn, rm, cond);
492 void MacroAssembler::Csinv(const Register& rd,
496 DCHECK(allow_macro_instructions_);
497 DCHECK(!rd.IsZero());
498 DCHECK((cond != al) && (cond != nv));
499 csinv(rd, rn, rm, cond);
503 void MacroAssembler::Csneg(const Register& rd,
507 DCHECK(allow_macro_instructions_);
508 DCHECK(!rd.IsZero());
509 DCHECK((cond != al) && (cond != nv));
510 csneg(rd, rn, rm, cond);
514 void MacroAssembler::Dmb(BarrierDomain domain, BarrierType type) {
515 DCHECK(allow_macro_instructions_);
520 void MacroAssembler::Dsb(BarrierDomain domain, BarrierType type) {
521 DCHECK(allow_macro_instructions_);
526 void MacroAssembler::Debug(const char* message, uint32_t code, Instr params) {
527 DCHECK(allow_macro_instructions_);
528 debug(message, code, params);
532 void MacroAssembler::Extr(const Register& rd,
536 DCHECK(allow_macro_instructions_);
537 DCHECK(!rd.IsZero());
538 extr(rd, rn, rm, lsb);
542 void MacroAssembler::Fabs(const FPRegister& fd, const FPRegister& fn) {
543 DCHECK(allow_macro_instructions_);
548 void MacroAssembler::Fadd(const FPRegister& fd,
549 const FPRegister& fn,
550 const FPRegister& fm) {
551 DCHECK(allow_macro_instructions_);
556 void MacroAssembler::Fccmp(const FPRegister& fn,
557 const FPRegister& fm,
560 DCHECK(allow_macro_instructions_);
561 DCHECK((cond != al) && (cond != nv));
562 fccmp(fn, fm, nzcv, cond);
566 void MacroAssembler::Fcmp(const FPRegister& fn, const FPRegister& fm) {
567 DCHECK(allow_macro_instructions_);
572 void MacroAssembler::Fcmp(const FPRegister& fn, double value) {
573 DCHECK(allow_macro_instructions_);
575 UseScratchRegisterScope temps(this);
576 FPRegister tmp = temps.AcquireSameSizeAs(fn);
585 void MacroAssembler::Fcsel(const FPRegister& fd,
586 const FPRegister& fn,
587 const FPRegister& fm,
589 DCHECK(allow_macro_instructions_);
590 DCHECK((cond != al) && (cond != nv));
591 fcsel(fd, fn, fm, cond);
595 void MacroAssembler::Fcvt(const FPRegister& fd, const FPRegister& fn) {
596 DCHECK(allow_macro_instructions_);
601 void MacroAssembler::Fcvtas(const Register& rd, const FPRegister& fn) {
602 DCHECK(allow_macro_instructions_);
603 DCHECK(!rd.IsZero());
608 void MacroAssembler::Fcvtau(const Register& rd, const FPRegister& fn) {
609 DCHECK(allow_macro_instructions_);
610 DCHECK(!rd.IsZero());
615 void MacroAssembler::Fcvtms(const Register& rd, const FPRegister& fn) {
616 DCHECK(allow_macro_instructions_);
617 DCHECK(!rd.IsZero());
622 void MacroAssembler::Fcvtmu(const Register& rd, const FPRegister& fn) {
623 DCHECK(allow_macro_instructions_);
624 DCHECK(!rd.IsZero());
629 void MacroAssembler::Fcvtns(const Register& rd, const FPRegister& fn) {
630 DCHECK(allow_macro_instructions_);
631 DCHECK(!rd.IsZero());
636 void MacroAssembler::Fcvtnu(const Register& rd, const FPRegister& fn) {
637 DCHECK(allow_macro_instructions_);
638 DCHECK(!rd.IsZero());
643 void MacroAssembler::Fcvtzs(const Register& rd, const FPRegister& fn) {
644 DCHECK(allow_macro_instructions_);
645 DCHECK(!rd.IsZero());
648 void MacroAssembler::Fcvtzu(const Register& rd, const FPRegister& fn) {
649 DCHECK(allow_macro_instructions_);
650 DCHECK(!rd.IsZero());
655 void MacroAssembler::Fdiv(const FPRegister& fd,
656 const FPRegister& fn,
657 const FPRegister& fm) {
658 DCHECK(allow_macro_instructions_);
663 void MacroAssembler::Fmadd(const FPRegister& fd,
664 const FPRegister& fn,
665 const FPRegister& fm,
666 const FPRegister& fa) {
667 DCHECK(allow_macro_instructions_);
668 fmadd(fd, fn, fm, fa);
672 void MacroAssembler::Fmax(const FPRegister& fd,
673 const FPRegister& fn,
674 const FPRegister& fm) {
675 DCHECK(allow_macro_instructions_);
680 void MacroAssembler::Fmaxnm(const FPRegister& fd,
681 const FPRegister& fn,
682 const FPRegister& fm) {
683 DCHECK(allow_macro_instructions_);
688 void MacroAssembler::Fmin(const FPRegister& fd,
689 const FPRegister& fn,
690 const FPRegister& fm) {
691 DCHECK(allow_macro_instructions_);
696 void MacroAssembler::Fminnm(const FPRegister& fd,
697 const FPRegister& fn,
698 const FPRegister& fm) {
699 DCHECK(allow_macro_instructions_);
704 void MacroAssembler::Fmov(FPRegister fd, FPRegister fn) {
705 DCHECK(allow_macro_instructions_);
706 // Only emit an instruction if fd and fn are different, and they are both D
707 // registers. fmov(s0, s0) is not a no-op because it clears the top word of
708 // d0. Technically, fmov(d0, d0) is not a no-op either because it clears the
709 // top of q0, but FPRegister does not currently support Q registers.
710 if (!fd.Is(fn) || !fd.Is64Bits()) {
716 void MacroAssembler::Fmov(FPRegister fd, Register rn) {
717 DCHECK(allow_macro_instructions_);
722 void MacroAssembler::Fmov(FPRegister fd, double imm) {
723 DCHECK(allow_macro_instructions_);
725 Fmov(fd, static_cast<float>(imm));
729 DCHECK(fd.Is64Bits());
730 if (IsImmFP64(imm)) {
732 } else if ((imm == 0.0) && (copysign(1.0, imm) == 1.0)) {
740 void MacroAssembler::Fmov(FPRegister fd, float imm) {
741 DCHECK(allow_macro_instructions_);
743 Fmov(fd, static_cast<double>(imm));
747 DCHECK(fd.Is32Bits());
748 if (IsImmFP32(imm)) {
750 } else if ((imm == 0.0) && (copysign(1.0, imm) == 1.0)) {
753 UseScratchRegisterScope temps(this);
754 Register tmp = temps.AcquireW();
755 // TODO(all): Use Assembler::ldr(const FPRegister& ft, float imm).
756 Mov(tmp, float_to_rawbits(imm));
762 void MacroAssembler::Fmov(Register rd, FPRegister fn) {
763 DCHECK(allow_macro_instructions_);
764 DCHECK(!rd.IsZero());
769 void MacroAssembler::Fmsub(const FPRegister& fd,
770 const FPRegister& fn,
771 const FPRegister& fm,
772 const FPRegister& fa) {
773 DCHECK(allow_macro_instructions_);
774 fmsub(fd, fn, fm, fa);
778 void MacroAssembler::Fmul(const FPRegister& fd,
779 const FPRegister& fn,
780 const FPRegister& fm) {
781 DCHECK(allow_macro_instructions_);
786 void MacroAssembler::Fneg(const FPRegister& fd, const FPRegister& fn) {
787 DCHECK(allow_macro_instructions_);
792 void MacroAssembler::Fnmadd(const FPRegister& fd,
793 const FPRegister& fn,
794 const FPRegister& fm,
795 const FPRegister& fa) {
796 DCHECK(allow_macro_instructions_);
797 fnmadd(fd, fn, fm, fa);
801 void MacroAssembler::Fnmsub(const FPRegister& fd,
802 const FPRegister& fn,
803 const FPRegister& fm,
804 const FPRegister& fa) {
805 DCHECK(allow_macro_instructions_);
806 fnmsub(fd, fn, fm, fa);
810 void MacroAssembler::Frinta(const FPRegister& fd, const FPRegister& fn) {
811 DCHECK(allow_macro_instructions_);
816 void MacroAssembler::Frintm(const FPRegister& fd, const FPRegister& fn) {
817 DCHECK(allow_macro_instructions_);
822 void MacroAssembler::Frintn(const FPRegister& fd, const FPRegister& fn) {
823 DCHECK(allow_macro_instructions_);
828 void MacroAssembler::Frintp(const FPRegister& fd, const FPRegister& fn) {
829 DCHECK(allow_macro_instructions_);
834 void MacroAssembler::Frintz(const FPRegister& fd, const FPRegister& fn) {
835 DCHECK(allow_macro_instructions_);
840 void MacroAssembler::Fsqrt(const FPRegister& fd, const FPRegister& fn) {
841 DCHECK(allow_macro_instructions_);
846 void MacroAssembler::Fsub(const FPRegister& fd,
847 const FPRegister& fn,
848 const FPRegister& fm) {
849 DCHECK(allow_macro_instructions_);
854 void MacroAssembler::Hint(SystemHint code) {
855 DCHECK(allow_macro_instructions_);
860 void MacroAssembler::Hlt(int code) {
861 DCHECK(allow_macro_instructions_);
866 void MacroAssembler::Isb() {
867 DCHECK(allow_macro_instructions_);
872 void MacroAssembler::Ldr(const CPURegister& rt, const Immediate& imm) {
873 DCHECK(allow_macro_instructions_);
878 void MacroAssembler::Ldr(const CPURegister& rt, double imm) {
879 DCHECK(allow_macro_instructions_);
880 DCHECK(rt.Is64Bits());
881 ldr(rt, Immediate(double_to_rawbits(imm)));
885 void MacroAssembler::Lsl(const Register& rd,
888 DCHECK(allow_macro_instructions_);
889 DCHECK(!rd.IsZero());
894 void MacroAssembler::Lsl(const Register& rd,
896 const Register& rm) {
897 DCHECK(allow_macro_instructions_);
898 DCHECK(!rd.IsZero());
903 void MacroAssembler::Lsr(const Register& rd,
906 DCHECK(allow_macro_instructions_);
907 DCHECK(!rd.IsZero());
912 void MacroAssembler::Lsr(const Register& rd,
914 const Register& rm) {
915 DCHECK(allow_macro_instructions_);
916 DCHECK(!rd.IsZero());
921 void MacroAssembler::Madd(const Register& rd,
924 const Register& ra) {
925 DCHECK(allow_macro_instructions_);
926 DCHECK(!rd.IsZero());
927 madd(rd, rn, rm, ra);
931 void MacroAssembler::Mneg(const Register& rd,
933 const Register& rm) {
934 DCHECK(allow_macro_instructions_);
935 DCHECK(!rd.IsZero());
940 void MacroAssembler::Mov(const Register& rd, const Register& rn) {
941 DCHECK(allow_macro_instructions_);
942 DCHECK(!rd.IsZero());
943 // Emit a register move only if the registers are distinct, or if they are
944 // not X registers. Note that mov(w0, w0) is not a no-op because it clears
945 // the top word of x0.
946 if (!rd.Is(rn) || !rd.Is64Bits()) {
947 Assembler::mov(rd, rn);
952 void MacroAssembler::Movk(const Register& rd, uint64_t imm, int shift) {
953 DCHECK(allow_macro_instructions_);
954 DCHECK(!rd.IsZero());
955 movk(rd, imm, shift);
959 void MacroAssembler::Mrs(const Register& rt, SystemRegister sysreg) {
960 DCHECK(allow_macro_instructions_);
961 DCHECK(!rt.IsZero());
966 void MacroAssembler::Msr(SystemRegister sysreg, const Register& rt) {
967 DCHECK(allow_macro_instructions_);
972 void MacroAssembler::Msub(const Register& rd,
975 const Register& ra) {
976 DCHECK(allow_macro_instructions_);
977 DCHECK(!rd.IsZero());
978 msub(rd, rn, rm, ra);
982 void MacroAssembler::Mul(const Register& rd,
984 const Register& rm) {
985 DCHECK(allow_macro_instructions_);
986 DCHECK(!rd.IsZero());
991 void MacroAssembler::Rbit(const Register& rd, const Register& rn) {
992 DCHECK(allow_macro_instructions_);
993 DCHECK(!rd.IsZero());
998 void MacroAssembler::Ret(const Register& xn) {
999 DCHECK(allow_macro_instructions_);
1000 DCHECK(!xn.IsZero());
1002 CheckVeneerPool(false, false);
1006 void MacroAssembler::Rev(const Register& rd, const Register& rn) {
1007 DCHECK(allow_macro_instructions_);
1008 DCHECK(!rd.IsZero());
1013 void MacroAssembler::Rev16(const Register& rd, const Register& rn) {
1014 DCHECK(allow_macro_instructions_);
1015 DCHECK(!rd.IsZero());
1020 void MacroAssembler::Rev32(const Register& rd, const Register& rn) {
1021 DCHECK(allow_macro_instructions_);
1022 DCHECK(!rd.IsZero());
1027 void MacroAssembler::Ror(const Register& rd,
1030 DCHECK(allow_macro_instructions_);
1031 DCHECK(!rd.IsZero());
1036 void MacroAssembler::Ror(const Register& rd,
1038 const Register& rm) {
1039 DCHECK(allow_macro_instructions_);
1040 DCHECK(!rd.IsZero());
1045 void MacroAssembler::Sbfiz(const Register& rd,
1049 DCHECK(allow_macro_instructions_);
1050 DCHECK(!rd.IsZero());
1051 sbfiz(rd, rn, lsb, width);
1055 void MacroAssembler::Sbfx(const Register& rd,
1059 DCHECK(allow_macro_instructions_);
1060 DCHECK(!rd.IsZero());
1061 sbfx(rd, rn, lsb, width);
1065 void MacroAssembler::Scvtf(const FPRegister& fd,
1068 DCHECK(allow_macro_instructions_);
1069 scvtf(fd, rn, fbits);
1073 void MacroAssembler::Sdiv(const Register& rd,
1075 const Register& rm) {
1076 DCHECK(allow_macro_instructions_);
1077 DCHECK(!rd.IsZero());
1082 void MacroAssembler::Smaddl(const Register& rd,
1085 const Register& ra) {
1086 DCHECK(allow_macro_instructions_);
1087 DCHECK(!rd.IsZero());
1088 smaddl(rd, rn, rm, ra);
1092 void MacroAssembler::Smsubl(const Register& rd,
1095 const Register& ra) {
1096 DCHECK(allow_macro_instructions_);
1097 DCHECK(!rd.IsZero());
1098 smsubl(rd, rn, rm, ra);
1102 void MacroAssembler::Smull(const Register& rd,
1104 const Register& rm) {
1105 DCHECK(allow_macro_instructions_);
1106 DCHECK(!rd.IsZero());
1111 void MacroAssembler::Smulh(const Register& rd,
1113 const Register& rm) {
1114 DCHECK(allow_macro_instructions_);
1115 DCHECK(!rd.IsZero());
1120 void MacroAssembler::Umull(const Register& rd, const Register& rn,
1121 const Register& rm) {
1122 DCHECK(allow_macro_instructions_);
1123 DCHECK(!rd.IsZero());
1124 umaddl(rd, rn, rm, xzr);
1128 void MacroAssembler::Sxtb(const Register& rd, const Register& rn) {
1129 DCHECK(allow_macro_instructions_);
1130 DCHECK(!rd.IsZero());
1135 void MacroAssembler::Sxth(const Register& rd, const Register& rn) {
1136 DCHECK(allow_macro_instructions_);
1137 DCHECK(!rd.IsZero());
1142 void MacroAssembler::Sxtw(const Register& rd, const Register& rn) {
1143 DCHECK(allow_macro_instructions_);
1144 DCHECK(!rd.IsZero());
1149 void MacroAssembler::Ubfiz(const Register& rd,
1153 DCHECK(allow_macro_instructions_);
1154 DCHECK(!rd.IsZero());
1155 ubfiz(rd, rn, lsb, width);
1159 void MacroAssembler::Ubfx(const Register& rd,
1163 DCHECK(allow_macro_instructions_);
1164 DCHECK(!rd.IsZero());
1165 ubfx(rd, rn, lsb, width);
1169 void MacroAssembler::Ucvtf(const FPRegister& fd,
1172 DCHECK(allow_macro_instructions_);
1173 ucvtf(fd, rn, fbits);
1177 void MacroAssembler::Udiv(const Register& rd,
1179 const Register& rm) {
1180 DCHECK(allow_macro_instructions_);
1181 DCHECK(!rd.IsZero());
1186 void MacroAssembler::Umaddl(const Register& rd,
1189 const Register& ra) {
1190 DCHECK(allow_macro_instructions_);
1191 DCHECK(!rd.IsZero());
1192 umaddl(rd, rn, rm, ra);
1196 void MacroAssembler::Umsubl(const Register& rd,
1199 const Register& ra) {
1200 DCHECK(allow_macro_instructions_);
1201 DCHECK(!rd.IsZero());
1202 umsubl(rd, rn, rm, ra);
1206 void MacroAssembler::Uxtb(const Register& rd, const Register& rn) {
1207 DCHECK(allow_macro_instructions_);
1208 DCHECK(!rd.IsZero());
1213 void MacroAssembler::Uxth(const Register& rd, const Register& rn) {
1214 DCHECK(allow_macro_instructions_);
1215 DCHECK(!rd.IsZero());
1220 void MacroAssembler::Uxtw(const Register& rd, const Register& rn) {
1221 DCHECK(allow_macro_instructions_);
1222 DCHECK(!rd.IsZero());
1227 void MacroAssembler::BumpSystemStackPointer(const Operand& space) {
1228 DCHECK(!csp.Is(sp_));
1229 if (!TmpList()->IsEmpty()) {
1230 Sub(csp, StackPointer(), space);
1232 // TODO(jbramley): Several callers rely on this not using scratch
1233 // registers, so we use the assembler directly here. However, this means
1234 // that large immediate values of 'space' cannot be handled cleanly. (Only
1235 // 24-bits immediates or values of 'space' that can be encoded in one
1236 // instruction are accepted.) Once we implement our flexible scratch
1237 // register idea, we could greatly simplify this function.
1238 InstructionAccurateScope scope(this);
1239 DCHECK(space.IsImmediate());
1240 // Align to 16 bytes.
1241 uint64_t imm = RoundUp(space.ImmediateValue(), 0x10);
1242 DCHECK(is_uint24(imm));
1244 Register source = StackPointer();
1245 if (CpuFeatures::IsSupported(ALWAYS_ALIGN_CSP)) {
1246 bic(csp, source, 0xf);
1249 if (!is_uint12(imm)) {
1250 int64_t imm_top_12_bits = imm >> 12;
1251 sub(csp, source, imm_top_12_bits << 12);
1253 imm -= imm_top_12_bits << 12;
1256 sub(csp, source, imm);
1259 AssertStackConsistency();
1263 void MacroAssembler::SyncSystemStackPointer() {
1264 DCHECK(emit_debug_code());
1265 DCHECK(!csp.Is(sp_));
1266 { InstructionAccurateScope scope(this);
1267 mov(csp, StackPointer());
1269 AssertStackConsistency();
1273 void MacroAssembler::InitializeRootRegister() {
1274 ExternalReference roots_array_start =
1275 ExternalReference::roots_array_start(isolate());
1276 Mov(root, Operand(roots_array_start));
1280 void MacroAssembler::SmiTag(Register dst, Register src) {
1281 STATIC_ASSERT(kXRegSizeInBits ==
1282 static_cast<unsigned>(kSmiShift + kSmiValueSize));
1283 DCHECK(dst.Is64Bits() && src.Is64Bits());
1284 Lsl(dst, src, kSmiShift);
1288 void MacroAssembler::SmiTag(Register smi) { SmiTag(smi, smi); }
1291 void MacroAssembler::SmiUntag(Register dst, Register src) {
1292 STATIC_ASSERT(kXRegSizeInBits ==
1293 static_cast<unsigned>(kSmiShift + kSmiValueSize));
1294 DCHECK(dst.Is64Bits() && src.Is64Bits());
1295 if (FLAG_enable_slow_asserts) {
1298 Asr(dst, src, kSmiShift);
1302 void MacroAssembler::SmiUntag(Register smi) { SmiUntag(smi, smi); }
1305 void MacroAssembler::SmiUntagToDouble(FPRegister dst,
1308 DCHECK(dst.Is64Bits() && src.Is64Bits());
1309 if (FLAG_enable_slow_asserts && (mode == kNotSpeculativeUntag)) {
1312 Scvtf(dst, src, kSmiShift);
1316 void MacroAssembler::SmiUntagToFloat(FPRegister dst,
1319 DCHECK(dst.Is32Bits() && src.Is64Bits());
1320 if (FLAG_enable_slow_asserts && (mode == kNotSpeculativeUntag)) {
1323 Scvtf(dst, src, kSmiShift);
1327 void MacroAssembler::SmiTagAndPush(Register src) {
1328 STATIC_ASSERT((static_cast<unsigned>(kSmiShift) == kWRegSizeInBits) &&
1329 (static_cast<unsigned>(kSmiValueSize) == kWRegSizeInBits) &&
1335 void MacroAssembler::SmiTagAndPush(Register src1, Register src2) {
1336 STATIC_ASSERT((static_cast<unsigned>(kSmiShift) == kWRegSizeInBits) &&
1337 (static_cast<unsigned>(kSmiValueSize) == kWRegSizeInBits) &&
1339 Push(src1.W(), wzr, src2.W(), wzr);
1343 void MacroAssembler::JumpIfSmi(Register value,
1345 Label* not_smi_label) {
1346 STATIC_ASSERT((kSmiTagSize == 1) && (kSmiTag == 0));
1347 // Check if the tag bit is set.
1349 Tbz(value, 0, smi_label);
1350 if (not_smi_label) {
1354 DCHECK(not_smi_label);
1355 Tbnz(value, 0, not_smi_label);
1360 void MacroAssembler::JumpIfNotSmi(Register value, Label* not_smi_label) {
1361 JumpIfSmi(value, NULL, not_smi_label);
1365 void MacroAssembler::JumpIfBothSmi(Register value1,
1367 Label* both_smi_label,
1368 Label* not_smi_label) {
1369 STATIC_ASSERT((kSmiTagSize == 1) && (kSmiTag == 0));
1370 UseScratchRegisterScope temps(this);
1371 Register tmp = temps.AcquireX();
1372 // Check if both tag bits are clear.
1373 Orr(tmp, value1, value2);
1374 JumpIfSmi(tmp, both_smi_label, not_smi_label);
1378 void MacroAssembler::JumpIfEitherSmi(Register value1,
1380 Label* either_smi_label,
1381 Label* not_smi_label) {
1382 STATIC_ASSERT((kSmiTagSize == 1) && (kSmiTag == 0));
1383 UseScratchRegisterScope temps(this);
1384 Register tmp = temps.AcquireX();
1385 // Check if either tag bit is clear.
1386 And(tmp, value1, value2);
1387 JumpIfSmi(tmp, either_smi_label, not_smi_label);
1391 void MacroAssembler::JumpIfEitherNotSmi(Register value1,
1393 Label* not_smi_label) {
1394 JumpIfBothSmi(value1, value2, NULL, not_smi_label);
1398 void MacroAssembler::JumpIfBothNotSmi(Register value1,
1400 Label* not_smi_label) {
1401 JumpIfEitherSmi(value1, value2, NULL, not_smi_label);
1405 void MacroAssembler::ObjectTag(Register tagged_obj, Register obj) {
1406 STATIC_ASSERT(kHeapObjectTag == 1);
1407 if (emit_debug_code()) {
1410 Abort(kObjectTagged);
1413 Orr(tagged_obj, obj, kHeapObjectTag);
1417 void MacroAssembler::ObjectUntag(Register untagged_obj, Register obj) {
1418 STATIC_ASSERT(kHeapObjectTag == 1);
1419 if (emit_debug_code()) {
1422 Abort(kObjectNotTagged);
1425 Bic(untagged_obj, obj, kHeapObjectTag);
1429 void MacroAssembler::IsObjectNameType(Register object,
1432 CompareObjectType(object, type, type, LAST_NAME_TYPE);
1437 void MacroAssembler::IsObjectJSObjectType(Register heap_object,
1441 Ldr(map, FieldMemOperand(heap_object, HeapObject::kMapOffset));
1442 IsInstanceJSObjectType(map, scratch, fail);
1446 void MacroAssembler::IsInstanceJSObjectType(Register map,
1449 Ldrb(scratch, FieldMemOperand(map, Map::kInstanceTypeOffset));
1450 // If cmp result is lt, the following ccmp will clear all flags.
1451 // Z == 0, N == V implies gt condition.
1452 Cmp(scratch, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE);
1453 Ccmp(scratch, LAST_NONCALLABLE_SPEC_OBJECT_TYPE, NoFlag, ge);
1455 // If we didn't get a valid label object just fall through and leave the
1463 void MacroAssembler::IsObjectJSStringType(Register object,
1467 Ldr(type, FieldMemOperand(object, HeapObject::kMapOffset));
1468 Ldrb(type.W(), FieldMemOperand(type, Map::kInstanceTypeOffset));
1470 STATIC_ASSERT(kStringTag == 0);
1471 DCHECK((string != NULL) || (not_string != NULL));
1472 if (string == NULL) {
1473 TestAndBranchIfAnySet(type.W(), kIsNotStringMask, not_string);
1474 } else if (not_string == NULL) {
1475 TestAndBranchIfAllClear(type.W(), kIsNotStringMask, string);
1477 TestAndBranchIfAnySet(type.W(), kIsNotStringMask, not_string);
1483 void MacroAssembler::Push(Handle<Object> handle) {
1484 UseScratchRegisterScope temps(this);
1485 Register tmp = temps.AcquireX();
1486 Mov(tmp, Operand(handle));
1491 void MacroAssembler::Claim(uint64_t count, uint64_t unit_size) {
1492 uint64_t size = count * unit_size;
1498 if (csp.Is(StackPointer())) {
1499 DCHECK(size % 16 == 0);
1501 BumpSystemStackPointer(size);
1504 Sub(StackPointer(), StackPointer(), size);
1508 void MacroAssembler::Claim(const Register& count, uint64_t unit_size) {
1509 if (unit_size == 0) return;
1510 DCHECK(base::bits::IsPowerOfTwo64(unit_size));
1512 const int shift = CountTrailingZeros(unit_size, kXRegSizeInBits);
1513 const Operand size(count, LSL, shift);
1515 if (size.IsZero()) {
1519 if (!csp.Is(StackPointer())) {
1520 BumpSystemStackPointer(size);
1523 Sub(StackPointer(), StackPointer(), size);
1527 void MacroAssembler::ClaimBySMI(const Register& count_smi, uint64_t unit_size) {
1528 DCHECK(unit_size == 0 || base::bits::IsPowerOfTwo64(unit_size));
1529 const int shift = CountTrailingZeros(unit_size, kXRegSizeInBits) - kSmiShift;
1530 const Operand size(count_smi,
1531 (shift >= 0) ? (LSL) : (LSR),
1532 (shift >= 0) ? (shift) : (-shift));
1534 if (size.IsZero()) {
1538 if (!csp.Is(StackPointer())) {
1539 BumpSystemStackPointer(size);
1542 Sub(StackPointer(), StackPointer(), size);
1546 void MacroAssembler::Drop(uint64_t count, uint64_t unit_size) {
1547 uint64_t size = count * unit_size;
1553 Add(StackPointer(), StackPointer(), size);
1555 if (csp.Is(StackPointer())) {
1556 DCHECK(size % 16 == 0);
1557 } else if (emit_debug_code()) {
1558 // It is safe to leave csp where it is when unwinding the JavaScript stack,
1559 // but if we keep it matching StackPointer, the simulator can detect memory
1560 // accesses in the now-free part of the stack.
1561 SyncSystemStackPointer();
1566 void MacroAssembler::Drop(const Register& count, uint64_t unit_size) {
1567 if (unit_size == 0) return;
1568 DCHECK(base::bits::IsPowerOfTwo64(unit_size));
1570 const int shift = CountTrailingZeros(unit_size, kXRegSizeInBits);
1571 const Operand size(count, LSL, shift);
1573 if (size.IsZero()) {
1577 Add(StackPointer(), StackPointer(), size);
1579 if (!csp.Is(StackPointer()) && emit_debug_code()) {
1580 // It is safe to leave csp where it is when unwinding the JavaScript stack,
1581 // but if we keep it matching StackPointer, the simulator can detect memory
1582 // accesses in the now-free part of the stack.
1583 SyncSystemStackPointer();
1588 void MacroAssembler::DropBySMI(const Register& count_smi, uint64_t unit_size) {
1589 DCHECK(unit_size == 0 || base::bits::IsPowerOfTwo64(unit_size));
1590 const int shift = CountTrailingZeros(unit_size, kXRegSizeInBits) - kSmiShift;
1591 const Operand size(count_smi,
1592 (shift >= 0) ? (LSL) : (LSR),
1593 (shift >= 0) ? (shift) : (-shift));
1595 if (size.IsZero()) {
1599 Add(StackPointer(), StackPointer(), size);
1601 if (!csp.Is(StackPointer()) && emit_debug_code()) {
1602 // It is safe to leave csp where it is when unwinding the JavaScript stack,
1603 // but if we keep it matching StackPointer, the simulator can detect memory
1604 // accesses in the now-free part of the stack.
1605 SyncSystemStackPointer();
1610 void MacroAssembler::CompareAndBranch(const Register& lhs,
1614 if (rhs.IsImmediate() && (rhs.ImmediateValue() == 0) &&
1615 ((cond == eq) || (cond == ne))) {
1628 void MacroAssembler::TestAndBranchIfAnySet(const Register& reg,
1629 const uint64_t bit_pattern,
1631 int bits = reg.SizeInBits();
1632 DCHECK(CountSetBits(bit_pattern, bits) > 0);
1633 if (CountSetBits(bit_pattern, bits) == 1) {
1634 Tbnz(reg, MaskToBit(bit_pattern), label);
1636 Tst(reg, bit_pattern);
1642 void MacroAssembler::TestAndBranchIfAllClear(const Register& reg,
1643 const uint64_t bit_pattern,
1645 int bits = reg.SizeInBits();
1646 DCHECK(CountSetBits(bit_pattern, bits) > 0);
1647 if (CountSetBits(bit_pattern, bits) == 1) {
1648 Tbz(reg, MaskToBit(bit_pattern), label);
1650 Tst(reg, bit_pattern);
1656 void MacroAssembler::InlineData(uint64_t data) {
1657 DCHECK(is_uint16(data));
1658 InstructionAccurateScope scope(this, 1);
1663 void MacroAssembler::EnableInstrumentation() {
1664 InstructionAccurateScope scope(this, 1);
1665 movn(xzr, InstrumentStateEnable);
1669 void MacroAssembler::DisableInstrumentation() {
1670 InstructionAccurateScope scope(this, 1);
1671 movn(xzr, InstrumentStateDisable);
1675 void MacroAssembler::AnnotateInstrumentation(const char* marker_name) {
1676 DCHECK(strlen(marker_name) == 2);
1678 // We allow only printable characters in the marker names. Unprintable
1679 // characters are reserved for controlling features of the instrumentation.
1680 DCHECK(isprint(marker_name[0]) && isprint(marker_name[1]));
1682 InstructionAccurateScope scope(this, 1);
1683 movn(xzr, (marker_name[1] << 8) | marker_name[0]);
1686 } // namespace internal
1689 #endif // V8_ARM64_MACRO_ASSEMBLER_ARM64_INL_H_