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 "v8globals.h"
13 #include "arm64/assembler-arm64.h"
14 #include "arm64/assembler-arm64-inl.h"
15 #include "arm64/macro-assembler-arm64.h"
16 #include "arm64/instrument-arm64.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 ASSERT(!code_object_.is_null());
46 void MacroAssembler::And(const Register& rd,
48 const Operand& operand) {
49 ASSERT(allow_macro_instructions_);
51 LogicalMacro(rd, rn, operand, AND);
55 void MacroAssembler::Ands(const Register& rd,
57 const Operand& operand) {
58 ASSERT(allow_macro_instructions_);
60 LogicalMacro(rd, rn, operand, ANDS);
64 void MacroAssembler::Tst(const Register& rn,
65 const Operand& operand) {
66 ASSERT(allow_macro_instructions_);
67 LogicalMacro(AppropriateZeroRegFor(rn), rn, operand, ANDS);
71 void MacroAssembler::Bic(const Register& rd,
73 const Operand& operand) {
74 ASSERT(allow_macro_instructions_);
76 LogicalMacro(rd, rn, operand, BIC);
80 void MacroAssembler::Bics(const Register& rd,
82 const Operand& operand) {
83 ASSERT(allow_macro_instructions_);
85 LogicalMacro(rd, rn, operand, BICS);
89 void MacroAssembler::Orr(const Register& rd,
91 const Operand& operand) {
92 ASSERT(allow_macro_instructions_);
94 LogicalMacro(rd, rn, operand, ORR);
98 void MacroAssembler::Orn(const Register& rd,
100 const Operand& operand) {
101 ASSERT(allow_macro_instructions_);
102 ASSERT(!rd.IsZero());
103 LogicalMacro(rd, rn, operand, ORN);
107 void MacroAssembler::Eor(const Register& rd,
109 const Operand& operand) {
110 ASSERT(allow_macro_instructions_);
111 ASSERT(!rd.IsZero());
112 LogicalMacro(rd, rn, operand, EOR);
116 void MacroAssembler::Eon(const Register& rd,
118 const Operand& operand) {
119 ASSERT(allow_macro_instructions_);
120 ASSERT(!rd.IsZero());
121 LogicalMacro(rd, rn, operand, EON);
125 void MacroAssembler::Ccmp(const Register& rn,
126 const Operand& operand,
129 ASSERT(allow_macro_instructions_);
130 if (operand.IsImmediate() && (operand.immediate() < 0)) {
131 ConditionalCompareMacro(rn, -operand.immediate(), nzcv, cond, CCMN);
133 ConditionalCompareMacro(rn, operand, nzcv, cond, CCMP);
138 void MacroAssembler::Ccmn(const Register& rn,
139 const Operand& operand,
142 ASSERT(allow_macro_instructions_);
143 if (operand.IsImmediate() && (operand.immediate() < 0)) {
144 ConditionalCompareMacro(rn, -operand.immediate(), nzcv, cond, CCMP);
146 ConditionalCompareMacro(rn, operand, nzcv, cond, CCMN);
151 void MacroAssembler::Add(const Register& rd,
153 const Operand& operand) {
154 ASSERT(allow_macro_instructions_);
155 if (operand.IsImmediate() && (operand.immediate() < 0)) {
156 AddSubMacro(rd, rn, -operand.immediate(), LeaveFlags, SUB);
158 AddSubMacro(rd, rn, operand, LeaveFlags, ADD);
162 void MacroAssembler::Adds(const Register& rd,
164 const Operand& operand) {
165 ASSERT(allow_macro_instructions_);
166 if (operand.IsImmediate() && (operand.immediate() < 0)) {
167 AddSubMacro(rd, rn, -operand.immediate(), SetFlags, SUB);
169 AddSubMacro(rd, rn, operand, SetFlags, ADD);
174 void MacroAssembler::Sub(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, ADD);
181 AddSubMacro(rd, rn, operand, LeaveFlags, SUB);
186 void MacroAssembler::Subs(const Register& rd,
188 const Operand& operand) {
189 ASSERT(allow_macro_instructions_);
190 if (operand.IsImmediate() && (operand.immediate() < 0)) {
191 AddSubMacro(rd, rn, -operand.immediate(), SetFlags, ADD);
193 AddSubMacro(rd, rn, operand, SetFlags, SUB);
198 void MacroAssembler::Cmn(const Register& rn, const Operand& operand) {
199 ASSERT(allow_macro_instructions_);
200 Adds(AppropriateZeroRegFor(rn), rn, operand);
204 void MacroAssembler::Cmp(const Register& rn, const Operand& operand) {
205 ASSERT(allow_macro_instructions_);
206 Subs(AppropriateZeroRegFor(rn), rn, operand);
210 void MacroAssembler::Neg(const Register& rd,
211 const Operand& operand) {
212 ASSERT(allow_macro_instructions_);
213 ASSERT(!rd.IsZero());
214 if (operand.IsImmediate()) {
215 Mov(rd, -operand.immediate());
217 Sub(rd, AppropriateZeroRegFor(rd), operand);
222 void MacroAssembler::Negs(const Register& rd,
223 const Operand& operand) {
224 ASSERT(allow_macro_instructions_);
225 Subs(rd, AppropriateZeroRegFor(rd), operand);
229 void MacroAssembler::Adc(const Register& rd,
231 const Operand& operand) {
232 ASSERT(allow_macro_instructions_);
233 ASSERT(!rd.IsZero());
234 AddSubWithCarryMacro(rd, rn, operand, LeaveFlags, ADC);
238 void MacroAssembler::Adcs(const Register& rd,
240 const Operand& operand) {
241 ASSERT(allow_macro_instructions_);
242 ASSERT(!rd.IsZero());
243 AddSubWithCarryMacro(rd, rn, operand, SetFlags, ADC);
247 void MacroAssembler::Sbc(const Register& rd,
249 const Operand& operand) {
250 ASSERT(allow_macro_instructions_);
251 ASSERT(!rd.IsZero());
252 AddSubWithCarryMacro(rd, rn, operand, LeaveFlags, SBC);
256 void MacroAssembler::Sbcs(const Register& rd,
258 const Operand& operand) {
259 ASSERT(allow_macro_instructions_);
260 ASSERT(!rd.IsZero());
261 AddSubWithCarryMacro(rd, rn, operand, SetFlags, SBC);
265 void MacroAssembler::Ngc(const Register& rd,
266 const Operand& operand) {
267 ASSERT(allow_macro_instructions_);
268 ASSERT(!rd.IsZero());
269 Register zr = AppropriateZeroRegFor(rd);
270 Sbc(rd, zr, operand);
274 void MacroAssembler::Ngcs(const Register& rd,
275 const Operand& operand) {
276 ASSERT(allow_macro_instructions_);
277 ASSERT(!rd.IsZero());
278 Register zr = AppropriateZeroRegFor(rd);
279 Sbcs(rd, zr, operand);
283 void MacroAssembler::Mvn(const Register& rd, uint64_t imm) {
284 ASSERT(allow_macro_instructions_);
285 ASSERT(!rd.IsZero());
290 #define DEFINE_FUNCTION(FN, REGTYPE, REG, OP) \
291 void MacroAssembler::FN(const REGTYPE REG, const MemOperand& addr) { \
292 ASSERT(allow_macro_instructions_); \
293 LoadStoreMacro(REG, addr, OP); \
295 LS_MACRO_LIST(DEFINE_FUNCTION)
296 #undef DEFINE_FUNCTION
299 void MacroAssembler::Asr(const Register& rd,
302 ASSERT(allow_macro_instructions_);
303 ASSERT(!rd.IsZero());
308 void MacroAssembler::Asr(const Register& rd,
310 const Register& rm) {
311 ASSERT(allow_macro_instructions_);
312 ASSERT(!rd.IsZero());
317 void MacroAssembler::B(Label* label) {
319 CheckVeneerPool(false, false);
323 void MacroAssembler::B(Condition cond, Label* label) {
324 ASSERT(allow_macro_instructions_);
329 void MacroAssembler::Bfi(const Register& rd,
333 ASSERT(allow_macro_instructions_);
334 ASSERT(!rd.IsZero());
335 bfi(rd, rn, lsb, width);
339 void MacroAssembler::Bfxil(const Register& rd,
343 ASSERT(allow_macro_instructions_);
344 ASSERT(!rd.IsZero());
345 bfxil(rd, rn, lsb, width);
349 void MacroAssembler::Bind(Label* label) {
350 ASSERT(allow_macro_instructions_);
355 void MacroAssembler::Bl(Label* label) {
356 ASSERT(allow_macro_instructions_);
361 void MacroAssembler::Blr(const Register& xn) {
362 ASSERT(allow_macro_instructions_);
363 ASSERT(!xn.IsZero());
368 void MacroAssembler::Br(const Register& xn) {
369 ASSERT(allow_macro_instructions_);
370 ASSERT(!xn.IsZero());
375 void MacroAssembler::Brk(int code) {
376 ASSERT(allow_macro_instructions_);
381 void MacroAssembler::Cinc(const Register& rd,
384 ASSERT(allow_macro_instructions_);
385 ASSERT(!rd.IsZero());
386 ASSERT((cond != al) && (cond != nv));
391 void MacroAssembler::Cinv(const Register& rd,
394 ASSERT(allow_macro_instructions_);
395 ASSERT(!rd.IsZero());
396 ASSERT((cond != al) && (cond != nv));
401 void MacroAssembler::Cls(const Register& rd, const Register& rn) {
402 ASSERT(allow_macro_instructions_);
403 ASSERT(!rd.IsZero());
408 void MacroAssembler::Clz(const Register& rd, const Register& rn) {
409 ASSERT(allow_macro_instructions_);
410 ASSERT(!rd.IsZero());
415 void MacroAssembler::Cneg(const Register& rd,
418 ASSERT(allow_macro_instructions_);
419 ASSERT(!rd.IsZero());
420 ASSERT((cond != al) && (cond != nv));
425 // Conditionally zero the destination register. Only X registers are supported
426 // due to the truncation side-effect when used on W registers.
427 void MacroAssembler::CzeroX(const Register& rd,
429 ASSERT(allow_macro_instructions_);
430 ASSERT(!rd.IsSP() && rd.Is64Bits());
431 ASSERT((cond != al) && (cond != nv));
432 csel(rd, xzr, rd, cond);
436 // Conditionally move a value into the destination register. Only X registers
437 // are supported due to the truncation side-effect when used on W registers.
438 void MacroAssembler::CmovX(const Register& rd,
441 ASSERT(allow_macro_instructions_);
443 ASSERT(rd.Is64Bits() && rn.Is64Bits());
444 ASSERT((cond != al) && (cond != nv));
446 csel(rd, rn, rd, cond);
451 void MacroAssembler::Cset(const Register& rd, Condition cond) {
452 ASSERT(allow_macro_instructions_);
453 ASSERT(!rd.IsZero());
454 ASSERT((cond != al) && (cond != nv));
459 void MacroAssembler::Csetm(const Register& rd, Condition cond) {
460 ASSERT(allow_macro_instructions_);
461 ASSERT(!rd.IsZero());
462 ASSERT((cond != al) && (cond != nv));
467 void MacroAssembler::Csinc(const Register& rd,
471 ASSERT(allow_macro_instructions_);
472 ASSERT(!rd.IsZero());
473 ASSERT((cond != al) && (cond != nv));
474 csinc(rd, rn, rm, cond);
478 void MacroAssembler::Csinv(const Register& rd,
482 ASSERT(allow_macro_instructions_);
483 ASSERT(!rd.IsZero());
484 ASSERT((cond != al) && (cond != nv));
485 csinv(rd, rn, rm, cond);
489 void MacroAssembler::Csneg(const Register& rd,
493 ASSERT(allow_macro_instructions_);
494 ASSERT(!rd.IsZero());
495 ASSERT((cond != al) && (cond != nv));
496 csneg(rd, rn, rm, cond);
500 void MacroAssembler::Dmb(BarrierDomain domain, BarrierType type) {
501 ASSERT(allow_macro_instructions_);
506 void MacroAssembler::Dsb(BarrierDomain domain, BarrierType type) {
507 ASSERT(allow_macro_instructions_);
512 void MacroAssembler::Debug(const char* message, uint32_t code, Instr params) {
513 ASSERT(allow_macro_instructions_);
514 debug(message, code, params);
518 void MacroAssembler::Extr(const Register& rd,
522 ASSERT(allow_macro_instructions_);
523 ASSERT(!rd.IsZero());
524 extr(rd, rn, rm, lsb);
528 void MacroAssembler::Fabs(const FPRegister& fd, const FPRegister& fn) {
529 ASSERT(allow_macro_instructions_);
534 void MacroAssembler::Fadd(const FPRegister& fd,
535 const FPRegister& fn,
536 const FPRegister& fm) {
537 ASSERT(allow_macro_instructions_);
542 void MacroAssembler::Fccmp(const FPRegister& fn,
543 const FPRegister& fm,
546 ASSERT(allow_macro_instructions_);
547 ASSERT((cond != al) && (cond != nv));
548 fccmp(fn, fm, nzcv, cond);
552 void MacroAssembler::Fcmp(const FPRegister& fn, const FPRegister& fm) {
553 ASSERT(allow_macro_instructions_);
558 void MacroAssembler::Fcmp(const FPRegister& fn, double value) {
559 ASSERT(allow_macro_instructions_);
561 UseScratchRegisterScope temps(this);
562 FPRegister tmp = temps.AcquireSameSizeAs(fn);
571 void MacroAssembler::Fcsel(const FPRegister& fd,
572 const FPRegister& fn,
573 const FPRegister& fm,
575 ASSERT(allow_macro_instructions_);
576 ASSERT((cond != al) && (cond != nv));
577 fcsel(fd, fn, fm, cond);
581 void MacroAssembler::Fcvt(const FPRegister& fd, const FPRegister& fn) {
582 ASSERT(allow_macro_instructions_);
587 void MacroAssembler::Fcvtas(const Register& rd, const FPRegister& fn) {
588 ASSERT(allow_macro_instructions_);
589 ASSERT(!rd.IsZero());
594 void MacroAssembler::Fcvtau(const Register& rd, const FPRegister& fn) {
595 ASSERT(allow_macro_instructions_);
596 ASSERT(!rd.IsZero());
601 void MacroAssembler::Fcvtms(const Register& rd, const FPRegister& fn) {
602 ASSERT(allow_macro_instructions_);
603 ASSERT(!rd.IsZero());
608 void MacroAssembler::Fcvtmu(const Register& rd, const FPRegister& fn) {
609 ASSERT(allow_macro_instructions_);
610 ASSERT(!rd.IsZero());
615 void MacroAssembler::Fcvtns(const Register& rd, const FPRegister& fn) {
616 ASSERT(allow_macro_instructions_);
617 ASSERT(!rd.IsZero());
622 void MacroAssembler::Fcvtnu(const Register& rd, const FPRegister& fn) {
623 ASSERT(allow_macro_instructions_);
624 ASSERT(!rd.IsZero());
629 void MacroAssembler::Fcvtzs(const Register& rd, const FPRegister& fn) {
630 ASSERT(allow_macro_instructions_);
631 ASSERT(!rd.IsZero());
634 void MacroAssembler::Fcvtzu(const Register& rd, const FPRegister& fn) {
635 ASSERT(allow_macro_instructions_);
636 ASSERT(!rd.IsZero());
641 void MacroAssembler::Fdiv(const FPRegister& fd,
642 const FPRegister& fn,
643 const FPRegister& fm) {
644 ASSERT(allow_macro_instructions_);
649 void MacroAssembler::Fmadd(const FPRegister& fd,
650 const FPRegister& fn,
651 const FPRegister& fm,
652 const FPRegister& fa) {
653 ASSERT(allow_macro_instructions_);
654 fmadd(fd, fn, fm, fa);
658 void MacroAssembler::Fmax(const FPRegister& fd,
659 const FPRegister& fn,
660 const FPRegister& fm) {
661 ASSERT(allow_macro_instructions_);
666 void MacroAssembler::Fmaxnm(const FPRegister& fd,
667 const FPRegister& fn,
668 const FPRegister& fm) {
669 ASSERT(allow_macro_instructions_);
674 void MacroAssembler::Fmin(const FPRegister& fd,
675 const FPRegister& fn,
676 const FPRegister& fm) {
677 ASSERT(allow_macro_instructions_);
682 void MacroAssembler::Fminnm(const FPRegister& fd,
683 const FPRegister& fn,
684 const FPRegister& fm) {
685 ASSERT(allow_macro_instructions_);
690 void MacroAssembler::Fmov(FPRegister fd, FPRegister fn) {
691 ASSERT(allow_macro_instructions_);
692 // Only emit an instruction if fd and fn are different, and they are both D
693 // registers. fmov(s0, s0) is not a no-op because it clears the top word of
694 // d0. Technically, fmov(d0, d0) is not a no-op either because it clears the
695 // top of q0, but FPRegister does not currently support Q registers.
696 if (!fd.Is(fn) || !fd.Is64Bits()) {
702 void MacroAssembler::Fmov(FPRegister fd, Register rn) {
703 ASSERT(allow_macro_instructions_);
708 void MacroAssembler::Fmov(FPRegister fd, double imm) {
709 ASSERT(allow_macro_instructions_);
711 Fmov(fd, static_cast<float>(imm));
715 ASSERT(fd.Is64Bits());
716 if (IsImmFP64(imm)) {
718 } else if ((imm == 0.0) && (copysign(1.0, imm) == 1.0)) {
721 UseScratchRegisterScope temps(this);
722 Register tmp = temps.AcquireX();
723 // TODO(all): Use Assembler::ldr(const FPRegister& ft, double imm).
724 Mov(tmp, double_to_rawbits(imm));
730 void MacroAssembler::Fmov(FPRegister fd, float imm) {
731 ASSERT(allow_macro_instructions_);
733 Fmov(fd, static_cast<double>(imm));
737 ASSERT(fd.Is32Bits());
738 if (IsImmFP32(imm)) {
740 } else if ((imm == 0.0) && (copysign(1.0, imm) == 1.0)) {
743 UseScratchRegisterScope temps(this);
744 Register tmp = temps.AcquireW();
745 // TODO(all): Use Assembler::ldr(const FPRegister& ft, float imm).
746 Mov(tmp, float_to_rawbits(imm));
752 void MacroAssembler::Fmov(Register rd, FPRegister fn) {
753 ASSERT(allow_macro_instructions_);
754 ASSERT(!rd.IsZero());
759 void MacroAssembler::Fmsub(const FPRegister& fd,
760 const FPRegister& fn,
761 const FPRegister& fm,
762 const FPRegister& fa) {
763 ASSERT(allow_macro_instructions_);
764 fmsub(fd, fn, fm, fa);
768 void MacroAssembler::Fmul(const FPRegister& fd,
769 const FPRegister& fn,
770 const FPRegister& fm) {
771 ASSERT(allow_macro_instructions_);
776 void MacroAssembler::Fneg(const FPRegister& fd, const FPRegister& fn) {
777 ASSERT(allow_macro_instructions_);
782 void MacroAssembler::Fnmadd(const FPRegister& fd,
783 const FPRegister& fn,
784 const FPRegister& fm,
785 const FPRegister& fa) {
786 ASSERT(allow_macro_instructions_);
787 fnmadd(fd, fn, fm, fa);
791 void MacroAssembler::Fnmsub(const FPRegister& fd,
792 const FPRegister& fn,
793 const FPRegister& fm,
794 const FPRegister& fa) {
795 ASSERT(allow_macro_instructions_);
796 fnmsub(fd, fn, fm, fa);
800 void MacroAssembler::Frinta(const FPRegister& fd, const FPRegister& fn) {
801 ASSERT(allow_macro_instructions_);
806 void MacroAssembler::Frintm(const FPRegister& fd, const FPRegister& fn) {
807 ASSERT(allow_macro_instructions_);
812 void MacroAssembler::Frintn(const FPRegister& fd, const FPRegister& fn) {
813 ASSERT(allow_macro_instructions_);
818 void MacroAssembler::Frintz(const FPRegister& fd, const FPRegister& fn) {
819 ASSERT(allow_macro_instructions_);
824 void MacroAssembler::Fsqrt(const FPRegister& fd, const FPRegister& fn) {
825 ASSERT(allow_macro_instructions_);
830 void MacroAssembler::Fsub(const FPRegister& fd,
831 const FPRegister& fn,
832 const FPRegister& fm) {
833 ASSERT(allow_macro_instructions_);
838 void MacroAssembler::Hint(SystemHint code) {
839 ASSERT(allow_macro_instructions_);
844 void MacroAssembler::Hlt(int code) {
845 ASSERT(allow_macro_instructions_);
850 void MacroAssembler::Isb() {
851 ASSERT(allow_macro_instructions_);
856 void MacroAssembler::Ldnp(const CPURegister& rt,
857 const CPURegister& rt2,
858 const MemOperand& src) {
859 ASSERT(allow_macro_instructions_);
860 ASSERT(!AreAliased(rt, rt2));
865 void MacroAssembler::Ldp(const CPURegister& rt,
866 const CPURegister& rt2,
867 const MemOperand& src) {
868 ASSERT(allow_macro_instructions_);
869 ASSERT(!AreAliased(rt, rt2));
874 void MacroAssembler::Ldpsw(const Register& rt,
876 const MemOperand& src) {
877 ASSERT(allow_macro_instructions_);
878 ASSERT(!rt.IsZero());
879 ASSERT(!rt2.IsZero());
884 void MacroAssembler::Ldr(const FPRegister& ft, double imm) {
885 ASSERT(allow_macro_instructions_);
890 void MacroAssembler::Ldr(const Register& rt, uint64_t imm) {
891 ASSERT(allow_macro_instructions_);
892 ASSERT(!rt.IsZero());
897 void MacroAssembler::Lsl(const Register& rd,
900 ASSERT(allow_macro_instructions_);
901 ASSERT(!rd.IsZero());
906 void MacroAssembler::Lsl(const Register& rd,
908 const Register& rm) {
909 ASSERT(allow_macro_instructions_);
910 ASSERT(!rd.IsZero());
915 void MacroAssembler::Lsr(const Register& rd,
918 ASSERT(allow_macro_instructions_);
919 ASSERT(!rd.IsZero());
924 void MacroAssembler::Lsr(const Register& rd,
926 const Register& rm) {
927 ASSERT(allow_macro_instructions_);
928 ASSERT(!rd.IsZero());
933 void MacroAssembler::Madd(const Register& rd,
936 const Register& ra) {
937 ASSERT(allow_macro_instructions_);
938 ASSERT(!rd.IsZero());
939 madd(rd, rn, rm, ra);
943 void MacroAssembler::Mneg(const Register& rd,
945 const Register& rm) {
946 ASSERT(allow_macro_instructions_);
947 ASSERT(!rd.IsZero());
952 void MacroAssembler::Mov(const Register& rd, const Register& rn) {
953 ASSERT(allow_macro_instructions_);
954 ASSERT(!rd.IsZero());
955 // Emit a register move only if the registers are distinct, or if they are
956 // not X registers. Note that mov(w0, w0) is not a no-op because it clears
957 // the top word of x0.
958 if (!rd.Is(rn) || !rd.Is64Bits()) {
959 Assembler::mov(rd, rn);
964 void MacroAssembler::Movk(const Register& rd, uint64_t imm, int shift) {
965 ASSERT(allow_macro_instructions_);
966 ASSERT(!rd.IsZero());
967 movk(rd, imm, shift);
971 void MacroAssembler::Mrs(const Register& rt, SystemRegister sysreg) {
972 ASSERT(allow_macro_instructions_);
973 ASSERT(!rt.IsZero());
978 void MacroAssembler::Msr(SystemRegister sysreg, const Register& rt) {
979 ASSERT(allow_macro_instructions_);
980 ASSERT(!rt.IsZero());
985 void MacroAssembler::Msub(const Register& rd,
988 const Register& ra) {
989 ASSERT(allow_macro_instructions_);
990 ASSERT(!rd.IsZero());
991 msub(rd, rn, rm, ra);
995 void MacroAssembler::Mul(const Register& rd,
997 const Register& rm) {
998 ASSERT(allow_macro_instructions_);
999 ASSERT(!rd.IsZero());
1004 void MacroAssembler::Rbit(const Register& rd, const Register& rn) {
1005 ASSERT(allow_macro_instructions_);
1006 ASSERT(!rd.IsZero());
1011 void MacroAssembler::Ret(const Register& xn) {
1012 ASSERT(allow_macro_instructions_);
1013 ASSERT(!xn.IsZero());
1015 CheckVeneerPool(false, false);
1019 void MacroAssembler::Rev(const Register& rd, const Register& rn) {
1020 ASSERT(allow_macro_instructions_);
1021 ASSERT(!rd.IsZero());
1026 void MacroAssembler::Rev16(const Register& rd, const Register& rn) {
1027 ASSERT(allow_macro_instructions_);
1028 ASSERT(!rd.IsZero());
1033 void MacroAssembler::Rev32(const Register& rd, const Register& rn) {
1034 ASSERT(allow_macro_instructions_);
1035 ASSERT(!rd.IsZero());
1040 void MacroAssembler::Ror(const Register& rd,
1043 ASSERT(allow_macro_instructions_);
1044 ASSERT(!rd.IsZero());
1049 void MacroAssembler::Ror(const Register& rd,
1051 const Register& rm) {
1052 ASSERT(allow_macro_instructions_);
1053 ASSERT(!rd.IsZero());
1058 void MacroAssembler::Sbfiz(const Register& rd,
1062 ASSERT(allow_macro_instructions_);
1063 ASSERT(!rd.IsZero());
1064 sbfiz(rd, rn, lsb, width);
1068 void MacroAssembler::Sbfx(const Register& rd,
1072 ASSERT(allow_macro_instructions_);
1073 ASSERT(!rd.IsZero());
1074 sbfx(rd, rn, lsb, width);
1078 void MacroAssembler::Scvtf(const FPRegister& fd,
1081 ASSERT(allow_macro_instructions_);
1082 scvtf(fd, rn, fbits);
1086 void MacroAssembler::Sdiv(const Register& rd,
1088 const Register& rm) {
1089 ASSERT(allow_macro_instructions_);
1090 ASSERT(!rd.IsZero());
1095 void MacroAssembler::Smaddl(const Register& rd,
1098 const Register& ra) {
1099 ASSERT(allow_macro_instructions_);
1100 ASSERT(!rd.IsZero());
1101 smaddl(rd, rn, rm, ra);
1105 void MacroAssembler::Smsubl(const Register& rd,
1108 const Register& ra) {
1109 ASSERT(allow_macro_instructions_);
1110 ASSERT(!rd.IsZero());
1111 smsubl(rd, rn, rm, ra);
1115 void MacroAssembler::Smull(const Register& rd,
1117 const Register& rm) {
1118 ASSERT(allow_macro_instructions_);
1119 ASSERT(!rd.IsZero());
1124 void MacroAssembler::Smulh(const Register& rd,
1126 const Register& rm) {
1127 ASSERT(allow_macro_instructions_);
1128 ASSERT(!rd.IsZero());
1133 void MacroAssembler::Stnp(const CPURegister& rt,
1134 const CPURegister& rt2,
1135 const MemOperand& dst) {
1136 ASSERT(allow_macro_instructions_);
1141 void MacroAssembler::Stp(const CPURegister& rt,
1142 const CPURegister& rt2,
1143 const MemOperand& dst) {
1144 ASSERT(allow_macro_instructions_);
1149 void MacroAssembler::Sxtb(const Register& rd, const Register& rn) {
1150 ASSERT(allow_macro_instructions_);
1151 ASSERT(!rd.IsZero());
1156 void MacroAssembler::Sxth(const Register& rd, const Register& rn) {
1157 ASSERT(allow_macro_instructions_);
1158 ASSERT(!rd.IsZero());
1163 void MacroAssembler::Sxtw(const Register& rd, const Register& rn) {
1164 ASSERT(allow_macro_instructions_);
1165 ASSERT(!rd.IsZero());
1170 void MacroAssembler::Ubfiz(const Register& rd,
1174 ASSERT(allow_macro_instructions_);
1175 ASSERT(!rd.IsZero());
1176 ubfiz(rd, rn, lsb, width);
1180 void MacroAssembler::Ubfx(const Register& rd,
1184 ASSERT(allow_macro_instructions_);
1185 ASSERT(!rd.IsZero());
1186 ubfx(rd, rn, lsb, width);
1190 void MacroAssembler::Ucvtf(const FPRegister& fd,
1193 ASSERT(allow_macro_instructions_);
1194 ucvtf(fd, rn, fbits);
1198 void MacroAssembler::Udiv(const Register& rd,
1200 const Register& rm) {
1201 ASSERT(allow_macro_instructions_);
1202 ASSERT(!rd.IsZero());
1207 void MacroAssembler::Umaddl(const Register& rd,
1210 const Register& ra) {
1211 ASSERT(allow_macro_instructions_);
1212 ASSERT(!rd.IsZero());
1213 umaddl(rd, rn, rm, ra);
1217 void MacroAssembler::Umsubl(const Register& rd,
1220 const Register& ra) {
1221 ASSERT(allow_macro_instructions_);
1222 ASSERT(!rd.IsZero());
1223 umsubl(rd, rn, rm, ra);
1227 void MacroAssembler::Uxtb(const Register& rd, const Register& rn) {
1228 ASSERT(allow_macro_instructions_);
1229 ASSERT(!rd.IsZero());
1234 void MacroAssembler::Uxth(const Register& rd, const Register& rn) {
1235 ASSERT(allow_macro_instructions_);
1236 ASSERT(!rd.IsZero());
1241 void MacroAssembler::Uxtw(const Register& rd, const Register& rn) {
1242 ASSERT(allow_macro_instructions_);
1243 ASSERT(!rd.IsZero());
1248 void MacroAssembler::BumpSystemStackPointer(const Operand& space) {
1249 ASSERT(!csp.Is(sp_));
1250 // TODO(jbramley): Several callers rely on this not using scratch registers,
1251 // so we use the assembler directly here. However, this means that large
1252 // immediate values of 'space' cannot be handled cleanly. (Only 24-bits
1253 // immediates or values of 'space' that can be encoded in one instruction are
1254 // accepted.) Once we implement our flexible scratch register idea, we could
1255 // greatly simplify this function.
1256 InstructionAccurateScope scope(this);
1257 if ((space.IsImmediate()) && !is_uint12(space.immediate())) {
1258 // The subtract instruction supports a 12-bit immediate, shifted left by
1259 // zero or 12 bits. So, in two instructions, we can subtract any immediate
1260 // between zero and (1 << 24) - 1.
1261 int64_t imm = space.immediate();
1262 ASSERT(is_uint24(imm));
1264 int64_t imm_top_12_bits = imm >> 12;
1265 sub(csp, StackPointer(), imm_top_12_bits << 12);
1266 imm -= imm_top_12_bits << 12;
1271 sub(csp, StackPointer(), space);
1276 void MacroAssembler::InitializeRootRegister() {
1277 ExternalReference roots_array_start =
1278 ExternalReference::roots_array_start(isolate());
1279 Mov(root, Operand(roots_array_start));
1283 void MacroAssembler::SmiTag(Register dst, Register src) {
1284 ASSERT(dst.Is64Bits() && src.Is64Bits());
1285 Lsl(dst, src, kSmiShift);
1289 void MacroAssembler::SmiTag(Register smi) { SmiTag(smi, smi); }
1292 void MacroAssembler::SmiUntag(Register dst, Register src) {
1293 ASSERT(dst.Is64Bits() && src.Is64Bits());
1294 if (FLAG_enable_slow_asserts) {
1297 Asr(dst, src, kSmiShift);
1301 void MacroAssembler::SmiUntag(Register smi) { SmiUntag(smi, smi); }
1304 void MacroAssembler::SmiUntagToDouble(FPRegister dst,
1307 ASSERT(dst.Is64Bits() && src.Is64Bits());
1308 if (FLAG_enable_slow_asserts && (mode == kNotSpeculativeUntag)) {
1311 Scvtf(dst, src, kSmiShift);
1315 void MacroAssembler::SmiUntagToFloat(FPRegister dst,
1318 ASSERT(dst.Is32Bits() && src.Is64Bits());
1319 if (FLAG_enable_slow_asserts && (mode == kNotSpeculativeUntag)) {
1322 Scvtf(dst, src, kSmiShift);
1326 void MacroAssembler::JumpIfSmi(Register value,
1328 Label* not_smi_label) {
1329 STATIC_ASSERT((kSmiTagSize == 1) && (kSmiTag == 0));
1330 // Check if the tag bit is set.
1332 Tbz(value, 0, smi_label);
1333 if (not_smi_label) {
1337 ASSERT(not_smi_label);
1338 Tbnz(value, 0, not_smi_label);
1343 void MacroAssembler::JumpIfNotSmi(Register value, Label* not_smi_label) {
1344 JumpIfSmi(value, NULL, not_smi_label);
1348 void MacroAssembler::JumpIfBothSmi(Register value1,
1350 Label* both_smi_label,
1351 Label* not_smi_label) {
1352 STATIC_ASSERT((kSmiTagSize == 1) && (kSmiTag == 0));
1353 UseScratchRegisterScope temps(this);
1354 Register tmp = temps.AcquireX();
1355 // Check if both tag bits are clear.
1356 Orr(tmp, value1, value2);
1357 JumpIfSmi(tmp, both_smi_label, not_smi_label);
1361 void MacroAssembler::JumpIfEitherSmi(Register value1,
1363 Label* either_smi_label,
1364 Label* not_smi_label) {
1365 STATIC_ASSERT((kSmiTagSize == 1) && (kSmiTag == 0));
1366 UseScratchRegisterScope temps(this);
1367 Register tmp = temps.AcquireX();
1368 // Check if either tag bit is clear.
1369 And(tmp, value1, value2);
1370 JumpIfSmi(tmp, either_smi_label, not_smi_label);
1374 void MacroAssembler::JumpIfEitherNotSmi(Register value1,
1376 Label* not_smi_label) {
1377 JumpIfBothSmi(value1, value2, NULL, not_smi_label);
1381 void MacroAssembler::JumpIfBothNotSmi(Register value1,
1383 Label* not_smi_label) {
1384 JumpIfEitherSmi(value1, value2, NULL, not_smi_label);
1388 void MacroAssembler::ObjectTag(Register tagged_obj, Register obj) {
1389 STATIC_ASSERT(kHeapObjectTag == 1);
1390 if (emit_debug_code()) {
1393 Abort(kObjectTagged);
1396 Orr(tagged_obj, obj, kHeapObjectTag);
1400 void MacroAssembler::ObjectUntag(Register untagged_obj, Register obj) {
1401 STATIC_ASSERT(kHeapObjectTag == 1);
1402 if (emit_debug_code()) {
1405 Abort(kObjectNotTagged);
1408 Bic(untagged_obj, obj, kHeapObjectTag);
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 if (unit_size == 0) return;
1493 ASSERT(IsPowerOf2(unit_size));
1495 const int shift = CountTrailingZeros(unit_size, kXRegSizeInBits);
1496 const Operand size(count, LSL, shift);
1498 if (size.IsZero()) {
1502 if (!csp.Is(StackPointer())) {
1503 BumpSystemStackPointer(size);
1506 Sub(StackPointer(), StackPointer(), size);
1510 void MacroAssembler::ClaimBySMI(const Register& count_smi, uint64_t unit_size) {
1511 ASSERT(unit_size == 0 || IsPowerOf2(unit_size));
1512 const int shift = CountTrailingZeros(unit_size, kXRegSizeInBits) - kSmiShift;
1513 const Operand size(count_smi,
1514 (shift >= 0) ? (LSL) : (LSR),
1515 (shift >= 0) ? (shift) : (-shift));
1517 if (size.IsZero()) {
1521 if (!csp.Is(StackPointer())) {
1522 BumpSystemStackPointer(size);
1525 Sub(StackPointer(), StackPointer(), size);
1529 void MacroAssembler::Drop(uint64_t count, uint64_t unit_size) {
1530 uint64_t size = count * unit_size;
1536 Add(StackPointer(), StackPointer(), size);
1538 if (csp.Is(StackPointer())) {
1539 ASSERT(size % 16 == 0);
1540 } else if (emit_debug_code()) {
1541 // It is safe to leave csp where it is when unwinding the JavaScript stack,
1542 // but if we keep it matching StackPointer, the simulator can detect memory
1543 // accesses in the now-free part of the stack.
1544 Mov(csp, StackPointer());
1549 void MacroAssembler::Drop(const Register& count, uint64_t unit_size) {
1550 if (unit_size == 0) return;
1551 ASSERT(IsPowerOf2(unit_size));
1553 const int shift = CountTrailingZeros(unit_size, kXRegSizeInBits);
1554 const Operand size(count, LSL, shift);
1556 if (size.IsZero()) {
1560 Add(StackPointer(), StackPointer(), size);
1562 if (!csp.Is(StackPointer()) && emit_debug_code()) {
1563 // It is safe to leave csp where it is when unwinding the JavaScript stack,
1564 // but if we keep it matching StackPointer, the simulator can detect memory
1565 // accesses in the now-free part of the stack.
1566 Mov(csp, StackPointer());
1571 void MacroAssembler::DropBySMI(const Register& count_smi, uint64_t unit_size) {
1572 ASSERT(unit_size == 0 || IsPowerOf2(unit_size));
1573 const int shift = CountTrailingZeros(unit_size, kXRegSizeInBits) - kSmiShift;
1574 const Operand size(count_smi,
1575 (shift >= 0) ? (LSL) : (LSR),
1576 (shift >= 0) ? (shift) : (-shift));
1578 if (size.IsZero()) {
1582 Add(StackPointer(), StackPointer(), size);
1584 if (!csp.Is(StackPointer()) && emit_debug_code()) {
1585 // It is safe to leave csp where it is when unwinding the JavaScript stack,
1586 // but if we keep it matching StackPointer, the simulator can detect memory
1587 // accesses in the now-free part of the stack.
1588 Mov(csp, StackPointer());
1593 void MacroAssembler::CompareAndBranch(const Register& lhs,
1597 if (rhs.IsImmediate() && (rhs.immediate() == 0) &&
1598 ((cond == eq) || (cond == ne))) {
1611 void MacroAssembler::TestAndBranchIfAnySet(const Register& reg,
1612 const uint64_t bit_pattern,
1614 int bits = reg.SizeInBits();
1615 ASSERT(CountSetBits(bit_pattern, bits) > 0);
1616 if (CountSetBits(bit_pattern, bits) == 1) {
1617 Tbnz(reg, MaskToBit(bit_pattern), label);
1619 Tst(reg, bit_pattern);
1625 void MacroAssembler::TestAndBranchIfAllClear(const Register& reg,
1626 const uint64_t bit_pattern,
1628 int bits = reg.SizeInBits();
1629 ASSERT(CountSetBits(bit_pattern, bits) > 0);
1630 if (CountSetBits(bit_pattern, bits) == 1) {
1631 Tbz(reg, MaskToBit(bit_pattern), label);
1633 Tst(reg, bit_pattern);
1639 void MacroAssembler::InlineData(uint64_t data) {
1640 ASSERT(is_uint16(data));
1641 InstructionAccurateScope scope(this, 1);
1646 void MacroAssembler::EnableInstrumentation() {
1647 InstructionAccurateScope scope(this, 1);
1648 movn(xzr, InstrumentStateEnable);
1652 void MacroAssembler::DisableInstrumentation() {
1653 InstructionAccurateScope scope(this, 1);
1654 movn(xzr, InstrumentStateDisable);
1658 void MacroAssembler::AnnotateInstrumentation(const char* marker_name) {
1659 ASSERT(strlen(marker_name) == 2);
1661 // We allow only printable characters in the marker names. Unprintable
1662 // characters are reserved for controlling features of the instrumentation.
1663 ASSERT(isprint(marker_name[0]) && isprint(marker_name[1]));
1665 InstructionAccurateScope scope(this, 1);
1666 movn(xzr, (marker_name[1] << 8) | marker_name[0]);
1669 } } // namespace v8::internal
1671 #endif // V8_ARM64_MACRO_ASSEMBLER_ARM64_INL_H_