blob: f4b13a0764774597dab76aab2ec538ec74c46be3 [file] [log] [blame]
armvixlad96eda2013-06-14 11:42:37 +01001// Copyright 2013, ARM Limited
2// All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions are met:
6//
7// * Redistributions of source code must retain the above copyright notice,
8// this list of conditions and the following disclaimer.
9// * Redistributions in binary form must reproduce the above copyright notice,
10// this list of conditions and the following disclaimer in the documentation
11// and/or other materials provided with the distribution.
12// * Neither the name of ARM Limited nor the names of its contributors may be
13// used to endorse or promote products derived from this software without
14// specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND
17// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
20// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
27#ifndef VIXL_A64_MACRO_ASSEMBLER_A64_H_
28#define VIXL_A64_MACRO_ASSEMBLER_A64_H_
29
30#include "globals.h"
31#include "a64/assembler-a64.h"
32#include "a64/debugger-a64.h"
33
34
35#define LS_MACRO_LIST(V) \
36 V(Ldrb, Register&, rt, LDRB_w) \
37 V(Strb, Register&, rt, STRB_w) \
38 V(Ldrsb, Register&, rt, rt.Is64Bits() ? LDRSB_x : LDRSB_w) \
39 V(Ldrh, Register&, rt, LDRH_w) \
40 V(Strh, Register&, rt, STRH_w) \
41 V(Ldrsh, Register&, rt, rt.Is64Bits() ? LDRSH_x : LDRSH_w) \
42 V(Ldr, CPURegister&, rt, LoadOpFor(rt)) \
43 V(Str, CPURegister&, rt, StoreOpFor(rt)) \
44 V(Ldrsw, Register&, rt, LDRSW_x)
45
46namespace vixl {
47
48class MacroAssembler : public Assembler {
49 public:
50 MacroAssembler(byte * buffer, unsigned buffer_size)
51 : Assembler(buffer, buffer_size),
52#ifdef DEBUG
53 allow_macro_instructions_(true),
54#endif
55 sp_(sp), tmp0_(ip0), tmp1_(ip1), fptmp0_(d31) {}
56
57 // Logical macros.
58 void And(const Register& rd,
59 const Register& rn,
60 const Operand& operand,
61 FlagsUpdate S = LeaveFlags);
62 void Bic(const Register& rd,
63 const Register& rn,
64 const Operand& operand,
65 FlagsUpdate S = LeaveFlags);
66 void Orr(const Register& rd,
67 const Register& rn,
68 const Operand& operand);
69 void Orn(const Register& rd,
70 const Register& rn,
71 const Operand& operand);
72 void Eor(const Register& rd,
73 const Register& rn,
74 const Operand& operand);
75 void Eon(const Register& rd,
76 const Register& rn,
77 const Operand& operand);
78 void Tst(const Register& rn, const Operand& operand);
79 void LogicalMacro(const Register& rd,
80 const Register& rn,
81 const Operand& operand,
82 LogicalOp op);
83
84 // Add and sub macros.
85 void Add(const Register& rd,
86 const Register& rn,
87 const Operand& operand,
88 FlagsUpdate S = LeaveFlags);
89 void Sub(const Register& rd,
90 const Register& rn,
91 const Operand& operand,
92 FlagsUpdate S = LeaveFlags);
93 void Cmn(const Register& rn, const Operand& operand);
94 void Cmp(const Register& rn, const Operand& operand);
95 void Neg(const Register& rd,
96 const Operand& operand,
97 FlagsUpdate S = LeaveFlags);
98 void AddSubMacro(const Register& rd,
99 const Register& rn,
100 const Operand& operand,
101 FlagsUpdate S,
102 AddSubOp op);
103
104 // Add/sub with carry macros.
105 void Adc(const Register& rd,
106 const Register& rn,
107 const Operand& operand,
108 FlagsUpdate S = LeaveFlags);
109 void Sbc(const Register& rd,
110 const Register& rn,
111 const Operand& operand,
112 FlagsUpdate S = LeaveFlags);
113 void Ngc(const Register& rd,
114 const Operand& operand,
115 FlagsUpdate S = LeaveFlags);
116 void AddSubWithCarryMacro(const Register& rd,
117 const Register& rn,
118 const Operand& operand,
119 FlagsUpdate S,
120 AddSubWithCarryOp op);
121
122 // Move macros.
123 void Mov(const Register& rd, uint64_t imm);
124 void Mov(const Register& rd, const Operand& operand);
125 void Mvn(const Register& rd, uint64_t imm) {
126 Mov(rd, ~imm);
127 };
128 void Mvn(const Register& rd, const Operand& operand);
129 bool IsImmMovn(uint64_t imm, unsigned reg_size);
130 bool IsImmMovz(uint64_t imm, unsigned reg_size);
131
132 // Conditional compare macros.
133 void Ccmp(const Register& rn,
134 const Operand& operand,
135 StatusFlags nzcv,
136 Condition cond);
137 void Ccmn(const Register& rn,
138 const Operand& operand,
139 StatusFlags nzcv,
140 Condition cond);
141 void ConditionalCompareMacro(const Register& rn,
142 const Operand& operand,
143 StatusFlags nzcv,
144 Condition cond,
145 ConditionalCompareOp op);
146
147 // Load/store macros.
148#define DECLARE_FUNCTION(FN, REGTYPE, REG, OP) \
149 void FN(const REGTYPE REG, const MemOperand& addr);
150 LS_MACRO_LIST(DECLARE_FUNCTION)
151#undef DECLARE_FUNCTION
152
153 void LoadStoreMacro(const CPURegister& rt,
154 const MemOperand& addr,
155 LoadStoreOp op);
156
157 // Push or pop up to 4 registers of the same width to or from the stack,
158 // using the current stack pointer as set by SetStackPointer.
159 //
160 // If an argument register is 'NoReg', all further arguments are also assumed
161 // to be 'NoReg', and are thus not pushed or popped.
162 //
163 // Arguments are ordered such that "Push(a, b);" is functionally equivalent
164 // to "Push(a); Push(b);".
165 //
166 // It is valid to push the same register more than once, and there is no
167 // restriction on the order in which registers are specified.
168 //
169 // It is not valid to pop into the same register more than once in one
170 // operation, not even into the zero register.
171 //
172 // If the current stack pointer (as set by SetStackPointer) is sp, then it
173 // must be aligned to 16 bytes on entry and the total size of the specified
174 // registers must also be a multiple of 16 bytes.
175 //
176 // Even if the current stack pointer is not the system stack pointer (sp),
177 // Push (and derived methods) will still modify the system stack pointer in
178 // order to comply with ABI rules about accessing memory below the system
179 // stack pointer.
180 //
181 // Other than the registers passed into Pop, the stack pointer and (possibly)
182 // the system stack pointer, these methods do not modify any other registers.
183 // Scratch registers such as Tmp0() and Tmp1() are preserved.
184 void Push(const CPURegister& src0, const CPURegister& src1 = NoReg,
185 const CPURegister& src2 = NoReg, const CPURegister& src3 = NoReg);
186 void Pop(const CPURegister& dst0, const CPURegister& dst1 = NoReg,
187 const CPURegister& dst2 = NoReg, const CPURegister& dst3 = NoReg);
188
189 // Alternative forms of Push and Pop, taking a RegList or CPURegList that
190 // specifies the registers that are to be pushed or popped. Higher-numbered
191 // registers are associated with higher memory addresses (as in the A32 push
192 // and pop instructions).
193 //
194 // (Push|Pop)SizeRegList allow you to specify the register size as a
195 // parameter. Only kXRegSize, kWRegSize, kDRegSize and kSRegSize are
196 // supported.
197 //
198 // Otherwise, (Push|Pop)(CPU|X|W|D|S)RegList is preferred.
199 void PushCPURegList(CPURegList registers);
200 void PopCPURegList(CPURegList registers);
201
202 void PushSizeRegList(RegList registers, unsigned reg_size,
203 CPURegister::RegisterType type = CPURegister::kRegister) {
204 PushCPURegList(CPURegList(type, reg_size, registers));
205 }
206 void PopSizeRegList(RegList registers, unsigned reg_size,
207 CPURegister::RegisterType type = CPURegister::kRegister) {
208 PopCPURegList(CPURegList(type, reg_size, registers));
209 }
210 void PushXRegList(RegList regs) {
211 PushSizeRegList(regs, kXRegSize);
212 }
213 void PopXRegList(RegList regs) {
214 PopSizeRegList(regs, kXRegSize);
215 }
216 void PushWRegList(RegList regs) {
217 PushSizeRegList(regs, kWRegSize);
218 }
219 void PopWRegList(RegList regs) {
220 PopSizeRegList(regs, kWRegSize);
221 }
222 inline void PushDRegList(RegList regs) {
223 PushSizeRegList(regs, kDRegSize, CPURegister::kFPRegister);
224 }
225 inline void PopDRegList(RegList regs) {
226 PopSizeRegList(regs, kDRegSize, CPURegister::kFPRegister);
227 }
228 inline void PushSRegList(RegList regs) {
229 PushSizeRegList(regs, kSRegSize, CPURegister::kFPRegister);
230 }
231 inline void PopSRegList(RegList regs) {
232 PopSizeRegList(regs, kSRegSize, CPURegister::kFPRegister);
233 }
234
235 // Push the specified register 'count' times.
236 void PushMultipleTimes(int count, Register src);
237
238 // Poke 'src' onto the stack. The offset is in bytes.
239 //
240 // If the current stack pointer (as set by SetStackPointer) is sp, then sp
241 // must be aligned to 16 bytes.
242 void Poke(const Register& src, const Operand& offset);
243
244 // Peek at a value on the stack, and put it in 'dst'. The offset is in bytes.
245 //
246 // If the current stack pointer (as set by SetStackPointer) is sp, then sp
247 // must be aligned to 16 bytes.
248 void Peek(const Register& dst, const Operand& offset);
249
250 // Claim or drop stack space without actually accessing memory.
251 //
252 // If the current stack pointer (as set by SetStackPointer) is sp, then it
253 // must be aligned to 16 bytes and the size claimed or dropped must be a
254 // multiple of 16 bytes.
255 void Claim(const Operand& size);
256 void Drop(const Operand& size);
257
258 // Preserve the callee-saved registers (as defined by AAPCS64).
259 //
260 // Higher-numbered registers are pushed before lower-numbered registers, and
261 // thus get higher addresses.
262 // Floating-point registers are pushed before general-purpose registers, and
263 // thus get higher addresses.
264 //
265 // This method must not be called unless StackPointer() is sp, and it is
266 // aligned to 16 bytes.
267 void PushCalleeSavedRegisters();
268
269 // Restore the callee-saved registers (as defined by AAPCS64).
270 //
271 // Higher-numbered registers are popped after lower-numbered registers, and
272 // thus come from higher addresses.
273 // Floating-point registers are popped after general-purpose registers, and
274 // thus come from higher addresses.
275 //
276 // This method must not be called unless StackPointer() is sp, and it is
277 // aligned to 16 bytes.
278 void PopCalleeSavedRegisters();
279
280 // Remaining instructions are simple pass-through calls to the assembler.
281 void Adr(const Register& rd, Label* label) {
282 ASSERT(allow_macro_instructions_);
283 ASSERT(!rd.IsZero());
284 adr(rd, label);
285 }
286 void Asr(const Register& rd, const Register& rn, unsigned shift) {
287 ASSERT(allow_macro_instructions_);
288 ASSERT(!rd.IsZero());
289 ASSERT(!rn.IsZero());
290 asr(rd, rn, shift);
291 }
292 void Asr(const Register& rd, const Register& rn, const Register& rm) {
293 ASSERT(allow_macro_instructions_);
294 ASSERT(!rd.IsZero());
295 ASSERT(!rn.IsZero());
296 ASSERT(!rm.IsZero());
297 asrv(rd, rn, rm);
298 }
299 void B(Label* label, Condition cond = al) {
300 ASSERT(allow_macro_instructions_);
301 b(label, cond);
302 }
303 void Bfi(const Register& rd,
304 const Register& rn,
305 unsigned lsb,
306 unsigned width) {
307 ASSERT(allow_macro_instructions_);
308 ASSERT(!rd.IsZero());
309 ASSERT(!rn.IsZero());
310 bfi(rd, rn, lsb, width);
311 }
312 void Bfxil(const Register& rd,
313 const Register& rn,
314 unsigned lsb,
315 unsigned width) {
316 ASSERT(allow_macro_instructions_);
317 ASSERT(!rd.IsZero());
318 ASSERT(!rn.IsZero());
319 bfxil(rd, rn, lsb, width);
320 }
321 void Bind(Label* label) {
322 ASSERT(allow_macro_instructions_);
323 bind(label);
324 }
325 void Bl(Label* label) {
326 ASSERT(allow_macro_instructions_);
327 bl(label);
328 }
329 void Blr(const Register& xn) {
330 ASSERT(allow_macro_instructions_);
331 ASSERT(!xn.IsZero());
332 blr(xn);
333 }
334 void Br(const Register& xn) {
335 ASSERT(allow_macro_instructions_);
336 ASSERT(!xn.IsZero());
337 br(xn);
338 }
339 void Brk(int code = 0) {
340 ASSERT(allow_macro_instructions_);
341 brk(code);
342 }
343 void Cbnz(const Register& rt, Label* label) {
344 ASSERT(allow_macro_instructions_);
345 ASSERT(!rt.IsZero());
346 cbnz(rt, label);
347 }
348 void Cbz(const Register& rt, Label* label) {
349 ASSERT(allow_macro_instructions_);
350 ASSERT(!rt.IsZero());
351 cbz(rt, label);
352 }
353 void Cinc(const Register& rd, const Register& rn, Condition cond) {
354 ASSERT(allow_macro_instructions_);
355 ASSERT(!rd.IsZero());
356 ASSERT(!rn.IsZero());
357 cinc(rd, rn, cond);
358 }
359 void Cinv(const Register& rd, const Register& rn, Condition cond) {
360 ASSERT(allow_macro_instructions_);
361 ASSERT(!rd.IsZero());
362 ASSERT(!rn.IsZero());
363 cinv(rd, rn, cond);
364 }
365 void Cls(const Register& rd, const Register& rn) {
366 ASSERT(allow_macro_instructions_);
367 ASSERT(!rd.IsZero());
368 ASSERT(!rn.IsZero());
369 cls(rd, rn);
370 }
371 void Clz(const Register& rd, const Register& rn) {
372 ASSERT(allow_macro_instructions_);
373 ASSERT(!rd.IsZero());
374 ASSERT(!rn.IsZero());
375 clz(rd, rn);
376 }
377 void Cneg(const Register& rd, const Register& rn, Condition cond) {
378 ASSERT(allow_macro_instructions_);
379 ASSERT(!rd.IsZero());
380 ASSERT(!rn.IsZero());
381 cneg(rd, rn, cond);
382 }
383 void Csel(const Register& rd,
384 const Register& rn,
385 const Register& rm,
386 Condition cond) {
387 ASSERT(allow_macro_instructions_);
388 ASSERT(!rd.IsZero());
389 ASSERT(!rn.IsZero());
390 ASSERT(!rm.IsZero());
391 csel(rd, rn, rm, cond);
392 }
393 void Cset(const Register& rd, Condition cond) {
394 ASSERT(allow_macro_instructions_);
395 ASSERT(!rd.IsZero());
396 cset(rd, cond);
397 }
398 void Csetm(const Register& rd, Condition cond) {
399 ASSERT(allow_macro_instructions_);
400 ASSERT(!rd.IsZero());
401 csetm(rd, cond);
402 }
403 void Csinc(const Register& rd,
404 const Register& rn,
405 const Register& rm,
406 Condition cond) {
407 ASSERT(allow_macro_instructions_);
408 ASSERT(!rd.IsZero());
409 ASSERT(!rn.IsZero());
410 ASSERT(!rm.IsZero());
411 csinc(rd, rn, rm, cond);
412 }
413 void Csinv(const Register& rd,
414 const Register& rn,
415 const Register& rm,
416 Condition cond) {
417 ASSERT(allow_macro_instructions_);
418 ASSERT(!rd.IsZero());
419 ASSERT(!rn.IsZero());
420 ASSERT(!rm.IsZero());
421 csinv(rd, rn, rm, cond);
422 }
423 void Csneg(const Register& rd,
424 const Register& rn,
425 const Register& rm,
426 Condition cond) {
427 ASSERT(allow_macro_instructions_);
428 ASSERT(!rd.IsZero());
429 ASSERT(!rn.IsZero());
430 ASSERT(!rm.IsZero());
431 csneg(rd, rn, rm, cond);
432 }
433 void Extr(const Register& rd,
434 const Register& rn,
435 const Register& rm,
436 unsigned lsb) {
437 ASSERT(allow_macro_instructions_);
438 ASSERT(!rd.IsZero());
439 ASSERT(!rn.IsZero());
440 ASSERT(!rm.IsZero());
441 extr(rd, rn, rm, lsb);
442 }
443 void Fabs(const FPRegister& fd, const FPRegister& fn) {
444 ASSERT(allow_macro_instructions_);
445 fabs(fd, fn);
446 }
447 void Fadd(const FPRegister& fd, const FPRegister& fn, const FPRegister& fm) {
448 ASSERT(allow_macro_instructions_);
449 fadd(fd, fn, fm);
450 }
451 void Fccmp(const FPRegister& fn,
452 const FPRegister& fm,
453 StatusFlags nzcv,
454 Condition cond) {
455 ASSERT(allow_macro_instructions_);
456 fccmp(fn, fm, nzcv, cond);
457 }
458 void Fcmp(const FPRegister& fn, const FPRegister& fm) {
459 ASSERT(allow_macro_instructions_);
460 fcmp(fn, fm);
461 }
462 void Fcmp(const FPRegister& fn, double value) {
463 ASSERT(allow_macro_instructions_);
464 if (value != 0.0) {
465 FPRegister tmp = AppropriateTempFor(fn);
466 Fmov(tmp, value);
467 fcmp(fn, tmp);
468 } else {
469 fcmp(fn, value);
470 }
471 }
472 void Fcsel(const FPRegister& fd,
473 const FPRegister& fn,
474 const FPRegister& fm,
475 Condition cond) {
476 ASSERT(allow_macro_instructions_);
477 fcsel(fd, fn, fm, cond);
478 }
479 void Fcvtms(const Register& rd, const FPRegister& fn) {
480 ASSERT(allow_macro_instructions_);
481 ASSERT(!rd.IsZero());
482 fcvtms(rd, fn);
483 }
484 void Fcvtmu(const Register& rd, const FPRegister& fn) {
485 ASSERT(allow_macro_instructions_);
486 ASSERT(!rd.IsZero());
487 fcvtmu(rd, fn);
488 }
489 void Fcvtns(const Register& rd, const FPRegister& fn) {
490 ASSERT(allow_macro_instructions_);
491 ASSERT(!rd.IsZero());
492 fcvtns(rd, fn);
493 }
494 void Fcvtnu(const Register& rd, const FPRegister& fn) {
495 ASSERT(allow_macro_instructions_);
496 ASSERT(!rd.IsZero());
497 fcvtnu(rd, fn);
498 }
499 void Fcvtzs(const Register& rd, const FPRegister& fn) {
500 ASSERT(allow_macro_instructions_);
501 ASSERT(!rd.IsZero());
502 fcvtzs(rd, fn);
503 }
504 void Fcvtzu(const Register& rd, const FPRegister& fn) {
505 ASSERT(allow_macro_instructions_);
506 ASSERT(!rd.IsZero());
507 fcvtzu(rd, fn);
508 }
509 void Fdiv(const FPRegister& fd, const FPRegister& fn, const FPRegister& fm) {
510 ASSERT(allow_macro_instructions_);
511 fdiv(fd, fn, fm);
512 }
513 void Fmax(const FPRegister& fd, const FPRegister& fn, const FPRegister& fm) {
514 ASSERT(allow_macro_instructions_);
515 fmax(fd, fn, fm);
516 }
517 void Fmin(const FPRegister& fd, const FPRegister& fn, const FPRegister& fm) {
518 ASSERT(allow_macro_instructions_);
519 fmin(fd, fn, fm);
520 }
521 void Fmov(FPRegister fd, FPRegister fn) {
522 ASSERT(allow_macro_instructions_);
523 // Only emit an instruction if fd and fn are different, and they are both D
524 // registers. fmov(s0, s0) is not a no-op because it clears the top word of
525 // d0. Technically, fmov(d0, d0) is not a no-op either because it clears
526 // the top of q0, but FPRegister does not currently support Q registers.
527 if (!fd.Is(fn) || !fd.Is64Bits()) {
528 fmov(fd, fn);
529 }
530 }
531 void Fmov(FPRegister fd, Register rn) {
532 ASSERT(allow_macro_instructions_);
533 ASSERT(!rn.IsZero());
534 fmov(fd, rn);
535 }
536 void Fmov(FPRegister fd, double imm) {
537 ASSERT(allow_macro_instructions_);
538 fmov(fd, imm);
539 }
540 void Fmov(Register rd, FPRegister fn) {
541 ASSERT(allow_macro_instructions_);
542 ASSERT(!rd.IsZero());
543 fmov(rd, fn);
544 }
545 void Fmul(const FPRegister& fd, const FPRegister& fn, const FPRegister& fm) {
546 ASSERT(allow_macro_instructions_);
547 fmul(fd, fn, fm);
548 }
549 void Fmsub(const FPRegister& fd,
550 const FPRegister& fn,
551 const FPRegister& fm,
552 const FPRegister& fa) {
553 ASSERT(allow_macro_instructions_);
554 fmsub(fd, fn, fm, fa);
555 }
556 void Fneg(const FPRegister& fd, const FPRegister& fn) {
557 ASSERT(allow_macro_instructions_);
558 fneg(fd, fn);
559 }
560 void Frintn(const FPRegister& fd, const FPRegister& fn) {
561 ASSERT(allow_macro_instructions_);
562 frintn(fd, fn);
563 }
564 void Frintz(const FPRegister& fd, const FPRegister& fn) {
565 ASSERT(allow_macro_instructions_);
566 frintz(fd, fn);
567 }
568 void Fsqrt(const FPRegister& fd, const FPRegister& fn) {
569 ASSERT(allow_macro_instructions_);
570 fsqrt(fd, fn);
571 }
572 void Fcvt(const FPRegister& fd, const FPRegister& fn) {
573 ASSERT(allow_macro_instructions_);
574 fcvt(fd, fn);
575 }
576 void Fsub(const FPRegister& fd, const FPRegister& fn, const FPRegister& fm) {
577 ASSERT(allow_macro_instructions_);
578 fsub(fd, fn, fm);
579 }
580 void Hint(SystemHint code) {
581 ASSERT(allow_macro_instructions_);
582 hint(code);
583 }
584 void Hlt(int code) {
585 ASSERT(allow_macro_instructions_);
586 hlt(code);
587 }
588 void Ldnp(const CPURegister& rt,
589 const CPURegister& rt2,
590 const MemOperand& src) {
591 ASSERT(allow_macro_instructions_);
592 ldnp(rt, rt2, src);
593 }
594 void Ldp(const CPURegister& rt,
595 const CPURegister& rt2,
596 const MemOperand& src) {
597 ASSERT(allow_macro_instructions_);
598 ldp(rt, rt2, src);
599 }
600 void Ldpsw(const Register& rt, const Register& rt2, const MemOperand& src) {
601 ASSERT(allow_macro_instructions_);
602 ldpsw(rt, rt2, src);
603 }
604 void Ldr(const FPRegister& ft, double imm) {
605 ASSERT(allow_macro_instructions_);
606 ldr(ft, imm);
607 }
608 void Ldr(const Register& rt, uint64_t imm) {
609 ASSERT(allow_macro_instructions_);
610 ASSERT(!rt.IsZero());
611 ldr(rt, imm);
612 }
613 void Lsl(const Register& rd, const Register& rn, unsigned shift) {
614 ASSERT(allow_macro_instructions_);
615 ASSERT(!rd.IsZero());
616 ASSERT(!rn.IsZero());
617 lsl(rd, rn, shift);
618 }
619 void Lsl(const Register& rd, const Register& rn, const Register& rm) {
620 ASSERT(allow_macro_instructions_);
621 ASSERT(!rd.IsZero());
622 ASSERT(!rn.IsZero());
623 ASSERT(!rm.IsZero());
624 lslv(rd, rn, rm);
625 }
626 void Lsr(const Register& rd, const Register& rn, unsigned shift) {
627 ASSERT(allow_macro_instructions_);
628 ASSERT(!rd.IsZero());
629 ASSERT(!rn.IsZero());
630 lsr(rd, rn, shift);
631 }
632 void Lsr(const Register& rd, const Register& rn, const Register& rm) {
633 ASSERT(allow_macro_instructions_);
634 ASSERT(!rd.IsZero());
635 ASSERT(!rn.IsZero());
636 ASSERT(!rm.IsZero());
637 lsrv(rd, rn, rm);
638 }
639 void Madd(const Register& rd,
640 const Register& rn,
641 const Register& rm,
642 const Register& ra) {
643 ASSERT(allow_macro_instructions_);
644 ASSERT(!rd.IsZero());
645 ASSERT(!rn.IsZero());
646 ASSERT(!rm.IsZero());
647 ASSERT(!ra.IsZero());
648 madd(rd, rn, rm, ra);
649 }
650 void Mneg(const Register& rd, const Register& rn, const Register& rm) {
651 ASSERT(allow_macro_instructions_);
652 ASSERT(!rd.IsZero());
653 ASSERT(!rn.IsZero());
654 ASSERT(!rm.IsZero());
655 mneg(rd, rn, rm);
656 }
657 void Mov(const Register& rd, const Register& rn) {
658 ASSERT(allow_macro_instructions_);
659 mov(rd, rn);
660 }
661 void Mrs(const Register& rt, SystemRegister sysreg) {
662 ASSERT(allow_macro_instructions_);
663 ASSERT(!rt.IsZero());
664 mrs(rt, sysreg);
665 }
666 void Msr(SystemRegister sysreg, const Register& rt) {
667 ASSERT(allow_macro_instructions_);
668 ASSERT(!rt.IsZero());
669 msr(sysreg, rt);
670 }
671 void Msub(const Register& rd,
672 const Register& rn,
673 const Register& rm,
674 const Register& ra) {
675 ASSERT(allow_macro_instructions_);
676 ASSERT(!rd.IsZero());
677 ASSERT(!rn.IsZero());
678 ASSERT(!rm.IsZero());
679 ASSERT(!ra.IsZero());
680 msub(rd, rn, rm, ra);
681 }
682 void Mul(const Register& rd, const Register& rn, const Register& rm) {
683 ASSERT(allow_macro_instructions_);
684 ASSERT(!rd.IsZero());
685 ASSERT(!rn.IsZero());
686 ASSERT(!rm.IsZero());
687 mul(rd, rn, rm);
688 }
689 void Nop() {
690 ASSERT(allow_macro_instructions_);
691 nop();
692 }
693 void Rbit(const Register& rd, const Register& rn) {
694 ASSERT(allow_macro_instructions_);
695 ASSERT(!rd.IsZero());
696 ASSERT(!rn.IsZero());
697 rbit(rd, rn);
698 }
699 void Ret(const Register& xn = lr) {
700 ASSERT(allow_macro_instructions_);
701 ASSERT(!xn.IsZero());
702 ret(xn);
703 }
704 void Rev(const Register& rd, const Register& rn) {
705 ASSERT(allow_macro_instructions_);
706 ASSERT(!rd.IsZero());
707 ASSERT(!rn.IsZero());
708 rev(rd, rn);
709 }
710 void Rev16(const Register& rd, const Register& rn) {
711 ASSERT(allow_macro_instructions_);
712 ASSERT(!rd.IsZero());
713 ASSERT(!rn.IsZero());
714 rev16(rd, rn);
715 }
716 void Rev32(const Register& rd, const Register& rn) {
717 ASSERT(allow_macro_instructions_);
718 ASSERT(!rd.IsZero());
719 ASSERT(!rn.IsZero());
720 rev32(rd, rn);
721 }
722 void Ror(const Register& rd, const Register& rs, unsigned shift) {
723 ASSERT(allow_macro_instructions_);
724 ASSERT(!rd.IsZero());
725 ASSERT(!rs.IsZero());
726 ror(rd, rs, shift);
727 }
728 void Ror(const Register& rd, const Register& rn, const Register& rm) {
729 ASSERT(allow_macro_instructions_);
730 ASSERT(!rd.IsZero());
731 ASSERT(!rn.IsZero());
732 ASSERT(!rm.IsZero());
733 rorv(rd, rn, rm);
734 }
735 void Sbfiz(const Register& rd,
736 const Register& rn,
737 unsigned lsb,
738 unsigned width) {
739 ASSERT(allow_macro_instructions_);
740 ASSERT(!rd.IsZero());
741 ASSERT(!rn.IsZero());
742 sbfiz(rd, rn, lsb, width);
743 }
744 void Sbfx(const Register& rd,
745 const Register& rn,
746 unsigned lsb,
747 unsigned width) {
748 ASSERT(allow_macro_instructions_);
749 ASSERT(!rd.IsZero());
750 ASSERT(!rn.IsZero());
751 sbfx(rd, rn, lsb, width);
752 }
753 void Scvtf(const FPRegister& fd, const Register& rn, unsigned fbits = 0) {
754 ASSERT(allow_macro_instructions_);
755 ASSERT(!rn.IsZero());
756 scvtf(fd, rn, fbits);
757 }
758 void Sdiv(const Register& rd, const Register& rn, const Register& rm) {
759 ASSERT(allow_macro_instructions_);
760 ASSERT(!rd.IsZero());
761 ASSERT(!rn.IsZero());
762 ASSERT(!rm.IsZero());
763 sdiv(rd, rn, rm);
764 }
765 void Smaddl(const Register& rd,
766 const Register& rn,
767 const Register& rm,
768 const Register& ra) {
769 ASSERT(allow_macro_instructions_);
770 ASSERT(!rd.IsZero());
771 ASSERT(!rn.IsZero());
772 ASSERT(!rm.IsZero());
773 ASSERT(!ra.IsZero());
774 smaddl(rd, rn, rm, ra);
775 }
776 void Smsubl(const Register& rd,
777 const Register& rn,
778 const Register& rm,
779 const Register& ra) {
780 ASSERT(allow_macro_instructions_);
781 ASSERT(!rd.IsZero());
782 ASSERT(!rn.IsZero());
783 ASSERT(!rm.IsZero());
784 ASSERT(!ra.IsZero());
785 smsubl(rd, rn, rm, ra);
786 }
787 void Smull(const Register& rd, const Register& rn, const Register& rm) {
788 ASSERT(allow_macro_instructions_);
789 ASSERT(!rd.IsZero());
790 ASSERT(!rn.IsZero());
791 ASSERT(!rm.IsZero());
792 smull(rd, rn, rm);
793 }
794 void Smulh(const Register& xd, const Register& xn, const Register& xm) {
795 ASSERT(allow_macro_instructions_);
796 ASSERT(!xd.IsZero());
797 ASSERT(!xn.IsZero());
798 ASSERT(!xm.IsZero());
799 smulh(xd, xn, xm);
800 }
801 void Stnp(const CPURegister& rt,
802 const CPURegister& rt2,
803 const MemOperand& dst) {
804 ASSERT(allow_macro_instructions_);
805 stnp(rt, rt2, dst);
806 }
807 void Stp(const CPURegister& rt,
808 const CPURegister& rt2,
809 const MemOperand& dst) {
810 ASSERT(allow_macro_instructions_);
811 stp(rt, rt2, dst);
812 }
813 void Sxtb(const Register& rd, const Register& rn) {
814 ASSERT(allow_macro_instructions_);
815 ASSERT(!rd.IsZero());
816 ASSERT(!rn.IsZero());
817 sxtb(rd, rn);
818 }
819 void Sxth(const Register& rd, const Register& rn) {
820 ASSERT(allow_macro_instructions_);
821 ASSERT(!rd.IsZero());
822 ASSERT(!rn.IsZero());
823 sxth(rd, rn);
824 }
825 void Sxtw(const Register& rd, const Register& rn) {
826 ASSERT(allow_macro_instructions_);
827 ASSERT(!rd.IsZero());
828 ASSERT(!rn.IsZero());
829 sxtw(rd, rn);
830 }
831 void Tbnz(const Register& rt, unsigned bit_pos, Label* label) {
832 ASSERT(allow_macro_instructions_);
833 ASSERT(!rt.IsZero());
834 tbnz(rt, bit_pos, label);
835 }
836 void Tbz(const Register& rt, unsigned bit_pos, Label* label) {
837 ASSERT(allow_macro_instructions_);
838 ASSERT(!rt.IsZero());
839 tbz(rt, bit_pos, label);
840 }
841 void Ubfiz(const Register& rd,
842 const Register& rn,
843 unsigned lsb,
844 unsigned width) {
845 ASSERT(allow_macro_instructions_);
846 ASSERT(!rd.IsZero());
847 ASSERT(!rn.IsZero());
848 ubfiz(rd, rn, lsb, width);
849 }
850 void Ubfx(const Register& rd,
851 const Register& rn,
852 unsigned lsb,
853 unsigned width) {
854 ASSERT(allow_macro_instructions_);
855 ASSERT(!rd.IsZero());
856 ASSERT(!rn.IsZero());
857 ubfx(rd, rn, lsb, width);
858 }
859 void Ucvtf(const FPRegister& fd, const Register& rn, unsigned fbits = 0) {
860 ASSERT(allow_macro_instructions_);
861 ASSERT(!rn.IsZero());
862 ucvtf(fd, rn, fbits);
863 }
864 void Udiv(const Register& rd, const Register& rn, const Register& rm) {
865 ASSERT(allow_macro_instructions_);
866 ASSERT(!rd.IsZero());
867 ASSERT(!rn.IsZero());
868 ASSERT(!rm.IsZero());
869 udiv(rd, rn, rm);
870 }
871 void Umaddl(const Register& rd,
872 const Register& rn,
873 const Register& rm,
874 const Register& ra) {
875 ASSERT(allow_macro_instructions_);
876 ASSERT(!rd.IsZero());
877 ASSERT(!rn.IsZero());
878 ASSERT(!rm.IsZero());
879 ASSERT(!ra.IsZero());
880 umaddl(rd, rn, rm, ra);
881 }
882 void Umsubl(const Register& rd,
883 const Register& rn,
884 const Register& rm,
885 const Register& ra) {
886 ASSERT(allow_macro_instructions_);
887 ASSERT(!rd.IsZero());
888 ASSERT(!rn.IsZero());
889 ASSERT(!rm.IsZero());
890 ASSERT(!ra.IsZero());
891 umsubl(rd, rn, rm, ra);
892 }
893 void Unreachable() {
894 ASSERT(allow_macro_instructions_);
895#ifdef USE_SIMULATOR
896 hlt(kUnreachableOpcode);
897#else
898 // Branch to 0 to generate a segfault.
899 // lr - kInstructionSize is the address of the offending instruction.
900 blr(xzr);
901#endif
902 }
903 void Uxtb(const Register& rd, const Register& rn) {
904 ASSERT(allow_macro_instructions_);
905 ASSERT(!rd.IsZero());
906 ASSERT(!rn.IsZero());
907 uxtb(rd, rn);
908 }
909 void Uxth(const Register& rd, const Register& rn) {
910 ASSERT(allow_macro_instructions_);
911 ASSERT(!rd.IsZero());
912 ASSERT(!rn.IsZero());
913 uxth(rd, rn);
914 }
915 void Uxtw(const Register& rd, const Register& rn) {
916 ASSERT(allow_macro_instructions_);
917 ASSERT(!rd.IsZero());
918 ASSERT(!rn.IsZero());
919 uxtw(rd, rn);
920 }
921
922 // Push the system stack pointer (sp) down to allow the same to be done to
923 // the current stack pointer (according to StackPointer()). This must be
924 // called _before_ accessing the memory.
925 //
926 // This is necessary when pushing or otherwise adding things to the stack, to
927 // satisfy the AAPCS64 constraint that the memory below the system stack
928 // pointer is not accessed.
929 //
930 // This method asserts that StackPointer() is not sp, since the call does
931 // not make sense in that context.
932 //
933 // TODO: This method can only accept values of 'space' that can be encoded in
934 // one instruction. Refer to the implementation for details.
935 void BumpSystemStackPointer(const Operand& space);
936
937#if DEBUG
938 void SetAllowMacroInstructions(bool value) {
939 allow_macro_instructions_ = value;
940 }
941
942 bool AllowMacroInstructions() const {
943 return allow_macro_instructions_;
944 }
945#endif
946
947 // Set the current stack pointer, but don't generate any code.
948 // Note that this does not directly affect LastStackPointer().
949 void SetStackPointer(const Register& stack_pointer) {
950 ASSERT(!AreAliased(stack_pointer, Tmp0(), Tmp1()));
951 sp_ = stack_pointer;
952 }
953
954 // Return the current stack pointer, as set by SetStackPointer.
955 const Register& StackPointer() const {
956 return sp_;
957 }
958
959 // Set the registers used internally by the MacroAssembler as scratch
960 // registers. These registers are used to implement behaviours which are not
961 // directly supported by A64, and where an intermediate result is required.
962 //
963 // Both tmp0 and tmp1 may be set to any X register except for xzr, sp,
964 // and StackPointer(). Also, they must not be the same register (though they
965 // may both be NoReg).
966 //
967 // It is valid to set either or both of these registers to NoReg if you don't
968 // want the MacroAssembler to use any scratch registers. In a debug build, the
969 // Assembler will assert that any registers it uses are valid. Be aware that
970 // this check is not present in release builds. If this is a problem, use the
971 // Assembler directly.
972 void SetScratchRegisters(const Register& tmp0, const Register& tmp1) {
973 ASSERT(!AreAliased(xzr, sp, tmp0, tmp1));
974 ASSERT(!AreAliased(StackPointer(), tmp0, tmp1));
975 tmp0_ = tmp0;
976 tmp1_ = tmp1;
977 }
978
979 const Register& Tmp0() const {
980 return tmp0_;
981 }
982
983 const Register& Tmp1() const {
984 return tmp1_;
985 }
986
987 void SetFPScratchRegister(const FPRegister& fptmp0) {
988 fptmp0_ = fptmp0;
989 }
990
991 const FPRegister& FPTmp0() const {
992 return fptmp0_;
993 }
994
995 const Register AppropriateTempFor(
996 const Register& target,
997 const CPURegister& forbidden = NoCPUReg) const {
998 Register candidate = forbidden.Is(Tmp0()) ? Tmp1() : Tmp0();
999 ASSERT(!candidate.Is(target));
1000 return Register(candidate.code(), target.size());
1001 }
1002
1003 const FPRegister AppropriateTempFor(
1004 const FPRegister& target,
1005 const CPURegister& forbidden = NoCPUReg) const {
1006 USE(forbidden);
1007 FPRegister candidate = FPTmp0();
1008 ASSERT(!candidate.Is(forbidden));
1009 ASSERT(!candidate.Is(target));
1010 return FPRegister(candidate.code(), target.size());
1011 }
1012
1013 // Like printf, but print at run-time from generated code.
1014 //
1015 // The caller must ensure that arguments for floating-point placeholders
1016 // (such as %e, %f or %g) are FPRegisters, and that arguments for integer
1017 // placeholders are Registers.
1018 //
1019 // A maximum of four arguments may be given to any single Printf call. The
1020 // arguments must be of the same type, but they do not need to have the same
1021 // size.
1022 //
1023 // The following registers cannot be printed:
1024 // Tmp0(), Tmp1(), StackPointer(), sp.
1025 //
1026 // This function automatically preserves caller-saved registers so that
1027 // calling code can use Printf at any point without having to worry about
1028 // corruption. The preservation mechanism generates a lot of code. If this is
1029 // a problem, preserve the important registers manually and then call
1030 // PrintfNoPreserve. Callee-saved registers are not used by Printf, and are
1031 // implicitly preserved.
1032 //
1033 // This function assumes (and asserts) that the current stack pointer is
1034 // callee-saved, not caller-saved. This is most likely the case anyway, as a
1035 // caller-saved stack pointer doesn't make a lot of sense.
1036 void Printf(const char * format,
1037 const CPURegister& arg0 = NoCPUReg,
1038 const CPURegister& arg1 = NoCPUReg,
1039 const CPURegister& arg2 = NoCPUReg,
1040 const CPURegister& arg3 = NoCPUReg);
1041
1042 // Like Printf, but don't preserve any caller-saved registers, not even 'lr'.
1043 //
1044 // The return code from the system printf call will be returned in x0.
1045 void PrintfNoPreserve(const char * format,
1046 const CPURegister& arg0 = NoCPUReg,
1047 const CPURegister& arg1 = NoCPUReg,
1048 const CPURegister& arg2 = NoCPUReg,
1049 const CPURegister& arg3 = NoCPUReg);
1050
1051 // Trace control when running the debug simulator.
1052 //
1053 // For example:
1054 //
1055 // __ Trace(LOG_REGS, TRACE_ENABLE);
1056 // Will add registers to the trace if it wasn't already the case.
1057 //
1058 // __ Trace(LOG_DISASM, TRACE_DISABLE);
1059 // Will stop logging disassembly. It has no effect if the disassembly wasn't
1060 // already being logged.
1061 void Trace(TraceParameters parameters, TraceCommand command);
1062
1063 // Log the requested data independently of what is being traced.
1064 //
1065 // For example:
1066 //
1067 // __ Log(LOG_FLAGS)
1068 // Will output the flags.
1069 void Log(TraceParameters paramters);
1070
1071 private:
1072 // The actual Push and Pop implementations. These don't generate any code
1073 // other than that required for the push or pop. This allows
1074 // (Push|Pop)CPURegList to bundle together setup code for a large block of
1075 // registers.
1076 //
1077 // Note that size is per register, and is specified in bytes.
1078 void PushHelper(int count, int size,
1079 const CPURegister& src0, const CPURegister& src1,
1080 const CPURegister& src2, const CPURegister& src3);
1081 void PopHelper(int count, int size,
1082 const CPURegister& dst0, const CPURegister& dst1,
1083 const CPURegister& dst2, const CPURegister& dst3);
1084
1085 // Perform necessary maintenance operations before a push or pop.
1086 //
1087 // Note that size is per register, and is specified in bytes.
1088 void PrepareForPush(int count, int size);
1089 void PrepareForPop(int count, int size);
1090
1091#if DEBUG
1092 // Tell whether any of the macro instruction can be used. When false the
1093 // MacroAssembler will assert if a method which can emit a variable number
1094 // of instructions is called.
1095 bool allow_macro_instructions_;
1096#endif
1097
1098 // The register to use as a stack pointer for stack operations.
1099 Register sp_;
1100
1101 // Scratch registers used internally by the MacroAssembler.
1102 Register tmp0_;
1103 Register tmp1_;
1104 FPRegister fptmp0_;
1105};
1106
1107
1108// Use this scope when you need a one-to-one mapping between methods and
1109// instructions. This scope prevents the MacroAssembler from being called and
1110// literal pools from being emitted. It also asserts the number of instructions
1111// emitted is what you specified when creating the scope.
1112class InstructionAccurateScope {
1113 public:
1114 explicit InstructionAccurateScope(MacroAssembler* masm)
1115 : masm_(masm), size_(0) {
1116 masm_->BlockLiteralPool();
1117#ifdef DEBUG
1118 old_allow_macro_instructions_ = masm_->AllowMacroInstructions();
1119 masm_->SetAllowMacroInstructions(false);
1120#endif
1121 }
1122
1123 InstructionAccurateScope(MacroAssembler* masm, int count)
1124 : masm_(masm), size_(count * kInstructionSize) {
1125 masm_->BlockLiteralPool();
1126#ifdef DEBUG
1127 masm_->bind(&start_);
1128 old_allow_macro_instructions_ = masm_->AllowMacroInstructions();
1129 masm_->SetAllowMacroInstructions(false);
1130#endif
1131 }
1132
1133 ~InstructionAccurateScope() {
1134 masm_->ReleaseLiteralPool();
1135#ifdef DEBUG
1136 if (start_.IsBound()) {
1137 ASSERT(masm_->SizeOfCodeGeneratedSince(&start_) == size_);
1138 }
1139 masm_->SetAllowMacroInstructions(old_allow_macro_instructions_);
1140#endif
1141 }
1142
1143 private:
1144 MacroAssembler* masm_;
1145 uint64_t size_;
1146#ifdef DEBUG
1147 Label start_;
1148 bool old_allow_macro_instructions_;
1149#endif
1150};
1151
1152
1153} // namespace vixl
1154
1155#endif // VIXL_A64_MACRO_ASSEMBLER_A64_H_