• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017, VIXL authors
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
10 //     notice, this list of conditions and the following disclaimer in the
11 //     documentation and/or other materials provided with the distribution.
12 //   * Neither the name of ARM Limited nor the names of its contributors may
13 //     be used to endorse or promote products derived from this software
14 //     without 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
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 // POSSIBILITY OF SUCH DAMAGE.
27 
28 #include "aarch32/macro-assembler-aarch32.h"
29 
30 #define STRINGIFY(x) #x
31 #define TOSTRING(x) STRINGIFY(x)
32 
33 #define CONTEXT_SCOPE \
34   ContextScope context(this, __FILE__ ":" TOSTRING(__LINE__))
35 
36 namespace vixl {
37 namespace aarch32 {
38 
ExactAssemblyScopeWithoutPoolsCheck(MacroAssembler * masm,size_t size,SizePolicy size_policy)39 ExactAssemblyScopeWithoutPoolsCheck::ExactAssemblyScopeWithoutPoolsCheck(
40     MacroAssembler* masm, size_t size, SizePolicy size_policy)
41     : ExactAssemblyScope(masm,
42                          size,
43                          size_policy,
44                          ExactAssemblyScope::kIgnorePools) {}
45 
Open(MacroAssembler * masm)46 void UseScratchRegisterScope::Open(MacroAssembler* masm) {
47   VIXL_ASSERT(masm_ == NULL);
48   VIXL_ASSERT(masm != NULL);
49   masm_ = masm;
50 
51   old_available_ = masm_->GetScratchRegisterList()->GetList();
52   old_available_vfp_ = masm_->GetScratchVRegisterList()->GetList();
53 
54   parent_ = masm->GetCurrentScratchRegisterScope();
55   masm->SetCurrentScratchRegisterScope(this);
56 }
57 
58 
Close()59 void UseScratchRegisterScope::Close() {
60   if (masm_ != NULL) {
61     // Ensure that scopes nest perfectly, and do not outlive their parents.
62     // This is a run-time check because the order of destruction of objects in
63     // the _same_ scope is implementation-defined, and is likely to change in
64     // optimised builds.
65     VIXL_CHECK(masm_->GetCurrentScratchRegisterScope() == this);
66     masm_->SetCurrentScratchRegisterScope(parent_);
67 
68     masm_->GetScratchRegisterList()->SetList(old_available_);
69     masm_->GetScratchVRegisterList()->SetList(old_available_vfp_);
70 
71     masm_ = NULL;
72   }
73 }
74 
75 
IsAvailable(const Register & reg) const76 bool UseScratchRegisterScope::IsAvailable(const Register& reg) const {
77   VIXL_ASSERT(masm_ != NULL);
78   VIXL_ASSERT(reg.IsValid());
79   return masm_->GetScratchRegisterList()->Includes(reg);
80 }
81 
82 
IsAvailable(const VRegister & reg) const83 bool UseScratchRegisterScope::IsAvailable(const VRegister& reg) const {
84   VIXL_ASSERT(masm_ != NULL);
85   VIXL_ASSERT(reg.IsValid());
86   return masm_->GetScratchVRegisterList()->IncludesAllOf(reg);
87 }
88 
89 
Acquire()90 Register UseScratchRegisterScope::Acquire() {
91   VIXL_ASSERT(masm_ != NULL);
92   Register reg = masm_->GetScratchRegisterList()->GetFirstAvailableRegister();
93   VIXL_CHECK(reg.IsValid());
94   masm_->GetScratchRegisterList()->Remove(reg);
95   return reg;
96 }
97 
98 
AcquireV(unsigned size_in_bits)99 VRegister UseScratchRegisterScope::AcquireV(unsigned size_in_bits) {
100   switch (size_in_bits) {
101     case kSRegSizeInBits:
102       return AcquireS();
103     case kDRegSizeInBits:
104       return AcquireD();
105     case kQRegSizeInBits:
106       return AcquireQ();
107     default:
108       VIXL_UNREACHABLE();
109       return NoVReg;
110   }
111 }
112 
113 
AcquireQ()114 QRegister UseScratchRegisterScope::AcquireQ() {
115   VIXL_ASSERT(masm_ != NULL);
116   QRegister reg =
117       masm_->GetScratchVRegisterList()->GetFirstAvailableQRegister();
118   VIXL_CHECK(reg.IsValid());
119   masm_->GetScratchVRegisterList()->Remove(reg);
120   return reg;
121 }
122 
123 
AcquireD()124 DRegister UseScratchRegisterScope::AcquireD() {
125   VIXL_ASSERT(masm_ != NULL);
126   DRegister reg =
127       masm_->GetScratchVRegisterList()->GetFirstAvailableDRegister();
128   VIXL_CHECK(reg.IsValid());
129   masm_->GetScratchVRegisterList()->Remove(reg);
130   return reg;
131 }
132 
133 
AcquireS()134 SRegister UseScratchRegisterScope::AcquireS() {
135   VIXL_ASSERT(masm_ != NULL);
136   SRegister reg =
137       masm_->GetScratchVRegisterList()->GetFirstAvailableSRegister();
138   VIXL_CHECK(reg.IsValid());
139   masm_->GetScratchVRegisterList()->Remove(reg);
140   return reg;
141 }
142 
143 
Release(const Register & reg)144 void UseScratchRegisterScope::Release(const Register& reg) {
145   VIXL_ASSERT(masm_ != NULL);
146   VIXL_ASSERT(reg.IsValid());
147   VIXL_ASSERT(!masm_->GetScratchRegisterList()->Includes(reg));
148   masm_->GetScratchRegisterList()->Combine(reg);
149 }
150 
151 
Release(const VRegister & reg)152 void UseScratchRegisterScope::Release(const VRegister& reg) {
153   VIXL_ASSERT(masm_ != NULL);
154   VIXL_ASSERT(reg.IsValid());
155   VIXL_ASSERT(!masm_->GetScratchVRegisterList()->IncludesAliasOf(reg));
156   masm_->GetScratchVRegisterList()->Combine(reg);
157 }
158 
159 
Include(const RegisterList & list)160 void UseScratchRegisterScope::Include(const RegisterList& list) {
161   VIXL_ASSERT(masm_ != NULL);
162   RegisterList excluded_registers(sp, lr, pc);
163   uint32_t mask = list.GetList() & ~excluded_registers.GetList();
164   RegisterList* available = masm_->GetScratchRegisterList();
165   available->SetList(available->GetList() | mask);
166 }
167 
168 
Include(const VRegisterList & list)169 void UseScratchRegisterScope::Include(const VRegisterList& list) {
170   VIXL_ASSERT(masm_ != NULL);
171   VRegisterList* available = masm_->GetScratchVRegisterList();
172   available->SetList(available->GetList() | list.GetList());
173 }
174 
175 
Exclude(const RegisterList & list)176 void UseScratchRegisterScope::Exclude(const RegisterList& list) {
177   VIXL_ASSERT(masm_ != NULL);
178   RegisterList* available = masm_->GetScratchRegisterList();
179   available->SetList(available->GetList() & ~list.GetList());
180 }
181 
182 
Exclude(const VRegisterList & list)183 void UseScratchRegisterScope::Exclude(const VRegisterList& list) {
184   VIXL_ASSERT(masm_ != NULL);
185   VRegisterList* available = masm_->GetScratchVRegisterList();
186   available->SetList(available->GetList() & ~list.GetList());
187 }
188 
189 
Exclude(const Operand & operand)190 void UseScratchRegisterScope::Exclude(const Operand& operand) {
191   if (operand.IsImmediateShiftedRegister()) {
192     Exclude(operand.GetBaseRegister());
193   } else if (operand.IsRegisterShiftedRegister()) {
194     Exclude(operand.GetBaseRegister(), operand.GetShiftRegister());
195   } else {
196     VIXL_ASSERT(operand.IsImmediate());
197   }
198 }
199 
200 
ExcludeAll()201 void UseScratchRegisterScope::ExcludeAll() {
202   VIXL_ASSERT(masm_ != NULL);
203   masm_->GetScratchRegisterList()->SetList(0);
204   masm_->GetScratchVRegisterList()->SetList(0);
205 }
206 
207 
EnsureEmitPoolsFor(size_t size_arg)208 void MacroAssembler::EnsureEmitPoolsFor(size_t size_arg) {
209   // We skip the check when the pools are blocked.
210   if (ArePoolsBlocked()) return;
211 
212   VIXL_ASSERT(IsUint32(size_arg));
213   uint32_t size = static_cast<uint32_t>(size_arg);
214 
215   if (pool_manager_.MustEmit(GetCursorOffset(), size)) {
216     int32_t new_pc = pool_manager_.Emit(this, GetCursorOffset(), size);
217     VIXL_ASSERT(new_pc == GetCursorOffset());
218     USE(new_pc);
219   }
220 }
221 
222 
HandleOutOfBoundsImmediate(Condition cond,Register tmp,uint32_t imm)223 void MacroAssembler::HandleOutOfBoundsImmediate(Condition cond,
224                                                 Register tmp,
225                                                 uint32_t imm) {
226   if (IsUintN(16, imm)) {
227     CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
228     mov(cond, tmp, imm & 0xffff);
229     return;
230   }
231   if (IsUsingT32()) {
232     if (ImmediateT32::IsImmediateT32(~imm)) {
233       CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
234       mvn(cond, tmp, ~imm);
235       return;
236     }
237   } else {
238     if (ImmediateA32::IsImmediateA32(~imm)) {
239       CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
240       mvn(cond, tmp, ~imm);
241       return;
242     }
243   }
244   CodeBufferCheckScope scope(this, 2 * kMaxInstructionSizeInBytes);
245   mov(cond, tmp, imm & 0xffff);
246   movt(cond, tmp, imm >> 16);
247 }
248 
249 
MemOperandComputationHelper(Condition cond,Register scratch,Register base,uint32_t offset,uint32_t extra_offset_mask)250 MemOperand MacroAssembler::MemOperandComputationHelper(
251     Condition cond,
252     Register scratch,
253     Register base,
254     uint32_t offset,
255     uint32_t extra_offset_mask) {
256   VIXL_ASSERT(!AliasesAvailableScratchRegister(scratch));
257   VIXL_ASSERT(!AliasesAvailableScratchRegister(base));
258   VIXL_ASSERT(allow_macro_instructions_);
259   VIXL_ASSERT(OutsideITBlock());
260 
261   // Check for the simple pass-through case.
262   if ((offset & extra_offset_mask) == offset) return MemOperand(base, offset);
263 
264   MacroEmissionCheckScope guard(this);
265 #ifndef PANDA_BUILD
266   ITScope it_scope(this, &cond, guard);
267 #else
268   ITScope it_scope(allocator_, this, &cond, guard);
269 #endif
270 
271   uint32_t load_store_offset = offset & extra_offset_mask;
272   uint32_t add_offset = offset & ~extra_offset_mask;
273   if ((add_offset != 0) &&
274       (IsModifiedImmediate(offset) || IsModifiedImmediate(-offset))) {
275     load_store_offset = 0;
276     add_offset = offset;
277   }
278 
279   if (base.IsPC()) {
280     // Special handling for PC bases. We must read the PC in the first
281     // instruction (and only in that instruction), and we must also take care to
282     // keep the same address calculation as loads and stores. For T32, that
283     // means using something like ADR, which uses AlignDown(PC, 4).
284 
285     // We don't handle positive offsets from PC because the intention is not
286     // clear; does the user expect the offset from the current
287     // GetCursorOffset(), or to allow a certain amount of space after the
288     // instruction?
289     VIXL_ASSERT((offset & 0x80000000) != 0);
290     if (IsUsingT32()) {
291       // T32: make the first instruction "SUB (immediate, from PC)" -- an alias
292       // of ADR -- to get behaviour like loads and stores. This ADR can handle
293       // at least as much offset as the load_store_offset so it can replace it.
294 
295       uint32_t sub_pc_offset = (-offset) & 0xfff;
296       load_store_offset = (offset + sub_pc_offset) & extra_offset_mask;
297       add_offset = (offset + sub_pc_offset) & ~extra_offset_mask;
298 
299       ExactAssemblyScope scope(this, k32BitT32InstructionSizeInBytes);
300       sub(cond, scratch, base, sub_pc_offset);
301 
302       if (add_offset == 0) return MemOperand(scratch, load_store_offset);
303 
304       // The rest of the offset can be generated in the usual way.
305       base = scratch;
306     }
307     // A32 can use any SUB instruction, so we don't have to do anything special
308     // here except to ensure that we read the PC first.
309   }
310 
311   add(cond, scratch, base, add_offset);
312   return MemOperand(scratch, load_store_offset);
313 }
314 
315 
GetOffsetMask(InstructionType type,AddrMode addrmode)316 uint32_t MacroAssembler::GetOffsetMask(InstructionType type,
317                                        AddrMode addrmode) {
318   switch (type) {
319     case kLdr:
320     case kLdrb:
321     case kStr:
322     case kStrb:
323       if (IsUsingA32() || (addrmode == Offset)) {
324         return 0xfff;
325       } else {
326         return 0xff;
327       }
328     case kLdrsb:
329     case kLdrh:
330     case kLdrsh:
331     case kStrh:
332       if (IsUsingT32() && (addrmode == Offset)) {
333         return 0xfff;
334       } else {
335         return 0xff;
336       }
337     case kVldr:
338     case kVstr:
339       return 0x3fc;
340     case kLdrd:
341     case kStrd:
342       if (IsUsingA32()) {
343         return 0xff;
344       } else {
345         return 0x3fc;
346       }
347     default:
348       VIXL_UNREACHABLE();
349       return 0;
350   }
351 }
352 
353 
PrintfTrampolineRRRR(const char * format,uint32_t a,uint32_t b,uint32_t c,uint32_t d)354 HARDFLOAT void PrintfTrampolineRRRR(
355     const char* format, uint32_t a, uint32_t b, uint32_t c, uint32_t d) {
356   printf(format, a, b, c, d);
357 }
358 
359 
PrintfTrampolineRRRD(const char * format,uint32_t a,uint32_t b,uint32_t c,double d)360 HARDFLOAT void PrintfTrampolineRRRD(
361     const char* format, uint32_t a, uint32_t b, uint32_t c, double d) {
362   printf(format, a, b, c, d);
363 }
364 
365 
PrintfTrampolineRRDR(const char * format,uint32_t a,uint32_t b,double c,uint32_t d)366 HARDFLOAT void PrintfTrampolineRRDR(
367     const char* format, uint32_t a, uint32_t b, double c, uint32_t d) {
368   printf(format, a, b, c, d);
369 }
370 
371 
PrintfTrampolineRRDD(const char * format,uint32_t a,uint32_t b,double c,double d)372 HARDFLOAT void PrintfTrampolineRRDD(
373     const char* format, uint32_t a, uint32_t b, double c, double d) {
374   printf(format, a, b, c, d);
375 }
376 
377 
PrintfTrampolineRDRR(const char * format,uint32_t a,double b,uint32_t c,uint32_t d)378 HARDFLOAT void PrintfTrampolineRDRR(
379     const char* format, uint32_t a, double b, uint32_t c, uint32_t d) {
380   printf(format, a, b, c, d);
381 }
382 
383 
PrintfTrampolineRDRD(const char * format,uint32_t a,double b,uint32_t c,double d)384 HARDFLOAT void PrintfTrampolineRDRD(
385     const char* format, uint32_t a, double b, uint32_t c, double d) {
386   printf(format, a, b, c, d);
387 }
388 
389 
PrintfTrampolineRDDR(const char * format,uint32_t a,double b,double c,uint32_t d)390 HARDFLOAT void PrintfTrampolineRDDR(
391     const char* format, uint32_t a, double b, double c, uint32_t d) {
392   printf(format, a, b, c, d);
393 }
394 
395 
PrintfTrampolineRDDD(const char * format,uint32_t a,double b,double c,double d)396 HARDFLOAT void PrintfTrampolineRDDD(
397     const char* format, uint32_t a, double b, double c, double d) {
398   printf(format, a, b, c, d);
399 }
400 
401 
PrintfTrampolineDRRR(const char * format,double a,uint32_t b,uint32_t c,uint32_t d)402 HARDFLOAT void PrintfTrampolineDRRR(
403     const char* format, double a, uint32_t b, uint32_t c, uint32_t d) {
404   printf(format, a, b, c, d);
405 }
406 
407 
PrintfTrampolineDRRD(const char * format,double a,uint32_t b,uint32_t c,double d)408 HARDFLOAT void PrintfTrampolineDRRD(
409     const char* format, double a, uint32_t b, uint32_t c, double d) {
410   printf(format, a, b, c, d);
411 }
412 
413 
PrintfTrampolineDRDR(const char * format,double a,uint32_t b,double c,uint32_t d)414 HARDFLOAT void PrintfTrampolineDRDR(
415     const char* format, double a, uint32_t b, double c, uint32_t d) {
416   printf(format, a, b, c, d);
417 }
418 
419 
PrintfTrampolineDRDD(const char * format,double a,uint32_t b,double c,double d)420 HARDFLOAT void PrintfTrampolineDRDD(
421     const char* format, double a, uint32_t b, double c, double d) {
422   printf(format, a, b, c, d);
423 }
424 
425 
PrintfTrampolineDDRR(const char * format,double a,double b,uint32_t c,uint32_t d)426 HARDFLOAT void PrintfTrampolineDDRR(
427     const char* format, double a, double b, uint32_t c, uint32_t d) {
428   printf(format, a, b, c, d);
429 }
430 
431 
PrintfTrampolineDDRD(const char * format,double a,double b,uint32_t c,double d)432 HARDFLOAT void PrintfTrampolineDDRD(
433     const char* format, double a, double b, uint32_t c, double d) {
434   printf(format, a, b, c, d);
435 }
436 
437 
PrintfTrampolineDDDR(const char * format,double a,double b,double c,uint32_t d)438 HARDFLOAT void PrintfTrampolineDDDR(
439     const char* format, double a, double b, double c, uint32_t d) {
440   printf(format, a, b, c, d);
441 }
442 
443 
PrintfTrampolineDDDD(const char * format,double a,double b,double c,double d)444 HARDFLOAT void PrintfTrampolineDDDD(
445     const char* format, double a, double b, double c, double d) {
446   printf(format, a, b, c, d);
447 }
448 
449 
Printf(const char * format,CPURegister reg1,CPURegister reg2,CPURegister reg3,CPURegister reg4)450 void MacroAssembler::Printf(const char* format,
451                             CPURegister reg1,
452                             CPURegister reg2,
453                             CPURegister reg3,
454                             CPURegister reg4) {
455   // Exclude all registers from the available scratch registers, so
456   // that we are able to use ip below.
457   // TODO: Refactor this function to use UseScratchRegisterScope
458   // for temporary registers below.
459   UseScratchRegisterScope scratch(this);
460   scratch.ExcludeAll();
461   if (generate_simulator_code_) {
462     PushRegister(reg4);
463     PushRegister(reg3);
464     PushRegister(reg2);
465     PushRegister(reg1);
466     Push(RegisterList(r0, r1));
467 #ifndef PANDA_BUILD
468     StringLiteral* format_literal =
469         new StringLiteral(format, RawLiteral::kDeletedOnPlacementByPool);
470 #else
471     StringLiteral* format_literal = allocator_.New<StringLiteral>(
472         allocator_, format, RawLiteral::kDeletedOnPlacementByPool);
473 #endif
474 
475     Adr(r0, format_literal);
476     uint32_t args = (reg4.GetType() << 12) | (reg3.GetType() << 8) |
477                     (reg2.GetType() << 4) | reg1.GetType();
478     Mov(r1, args);
479     Hvc(kPrintfCode);
480     Pop(RegisterList(r0, r1));
481     int size = reg4.GetRegSizeInBytes() + reg3.GetRegSizeInBytes() +
482                reg2.GetRegSizeInBytes() + reg1.GetRegSizeInBytes();
483     Drop(size);
484   } else {
485     // Generate on a native platform => 32 bit environment.
486     // Preserve core registers r0-r3, r12, r14
487     const uint32_t saved_registers_mask =
488         kCallerSavedRegistersMask | (1 << r5.GetCode());
489     Push(RegisterList(saved_registers_mask));
490     // Push VFP registers.
491     Vpush(Untyped64, DRegisterList(d0, 8));
492     if (Has32DRegs()) Vpush(Untyped64, DRegisterList(d16, 16));
493     // Search one register which has been saved and which doesn't need to be
494     // printed.
495     RegisterList available_registers(kCallerSavedRegistersMask);
496     if (reg1.GetType() == CPURegister::kRRegister) {
497       available_registers.Remove(Register(reg1.GetCode()));
498     }
499     if (reg2.GetType() == CPURegister::kRRegister) {
500       available_registers.Remove(Register(reg2.GetCode()));
501     }
502     if (reg3.GetType() == CPURegister::kRRegister) {
503       available_registers.Remove(Register(reg3.GetCode()));
504     }
505     if (reg4.GetType() == CPURegister::kRRegister) {
506       available_registers.Remove(Register(reg4.GetCode()));
507     }
508     Register tmp = available_registers.GetFirstAvailableRegister();
509     VIXL_ASSERT(tmp.GetType() == CPURegister::kRRegister);
510     // Push the flags.
511     Mrs(tmp, APSR);
512     Push(tmp);
513     Vmrs(RegisterOrAPSR_nzcv(tmp.GetCode()), FPSCR);
514     Push(tmp);
515     // Push the registers to print on the stack.
516     PushRegister(reg4);
517     PushRegister(reg3);
518     PushRegister(reg2);
519     PushRegister(reg1);
520     int core_count = 1;
521     int vfp_count = 0;
522     uint32_t printf_type = 0;
523     // Pop the registers to print and store them into r1-r3 and/or d0-d3.
524     // Reg4 may stay into the stack if all the register to print are core
525     // registers.
526     PreparePrintfArgument(reg1, &core_count, &vfp_count, &printf_type);
527     PreparePrintfArgument(reg2, &core_count, &vfp_count, &printf_type);
528     PreparePrintfArgument(reg3, &core_count, &vfp_count, &printf_type);
529     PreparePrintfArgument(reg4, &core_count, &vfp_count, &printf_type);
530     // Ensure that the stack is aligned on 8 bytes.
531     And(r5, sp, 0x7);
532     if (core_count == 5) {
533       // One 32 bit argument (reg4) has been left on the stack =>  align the
534       // stack
535       // before the argument.
536       Pop(r0);
537       Sub(sp, sp, r5);
538       Push(r0);
539     } else {
540       Sub(sp, sp, r5);
541     }
542     // Select the right trampoline depending on the arguments.
543     uintptr_t address;
544     switch (printf_type) {
545       case 0:
546         address = reinterpret_cast<uintptr_t>(PrintfTrampolineRRRR);
547         break;
548       case 1:
549         address = reinterpret_cast<uintptr_t>(PrintfTrampolineDRRR);
550         break;
551       case 2:
552         address = reinterpret_cast<uintptr_t>(PrintfTrampolineRDRR);
553         break;
554       case 3:
555         address = reinterpret_cast<uintptr_t>(PrintfTrampolineDDRR);
556         break;
557       case 4:
558         address = reinterpret_cast<uintptr_t>(PrintfTrampolineRRDR);
559         break;
560       case 5:
561         address = reinterpret_cast<uintptr_t>(PrintfTrampolineDRDR);
562         break;
563       case 6:
564         address = reinterpret_cast<uintptr_t>(PrintfTrampolineRDDR);
565         break;
566       case 7:
567         address = reinterpret_cast<uintptr_t>(PrintfTrampolineDDDR);
568         break;
569       case 8:
570         address = reinterpret_cast<uintptr_t>(PrintfTrampolineRRRD);
571         break;
572       case 9:
573         address = reinterpret_cast<uintptr_t>(PrintfTrampolineDRRD);
574         break;
575       case 10:
576         address = reinterpret_cast<uintptr_t>(PrintfTrampolineRDRD);
577         break;
578       case 11:
579         address = reinterpret_cast<uintptr_t>(PrintfTrampolineDDRD);
580         break;
581       case 12:
582         address = reinterpret_cast<uintptr_t>(PrintfTrampolineRRDD);
583         break;
584       case 13:
585         address = reinterpret_cast<uintptr_t>(PrintfTrampolineDRDD);
586         break;
587       case 14:
588         address = reinterpret_cast<uintptr_t>(PrintfTrampolineRDDD);
589         break;
590       case 15:
591         address = reinterpret_cast<uintptr_t>(PrintfTrampolineDDDD);
592         break;
593       default:
594         VIXL_UNREACHABLE();
595         address = reinterpret_cast<uintptr_t>(PrintfTrampolineRRRR);
596         break;
597     }
598 #ifndef PANDA_BUILD
599     StringLiteral* format_literal =
600         new StringLiteral(format, RawLiteral::kDeletedOnPlacementByPool);
601 #else
602     StringLiteral* format_literal = allocator_.New<StringLiteral>(
603         allocator_, format, RawLiteral::kDeletedOnPlacementByPool);
604 #endif
605     Adr(r0, format_literal);
606     Mov(ip, Operand::From(address));
607     Blx(ip);
608     // If register reg4 was left on the stack => skip it.
609     if (core_count == 5) Drop(kRegSizeInBytes);
610     // Restore the stack as it was before alignment.
611     Add(sp, sp, r5);
612     // Restore the flags.
613     Pop(tmp);
614     Vmsr(FPSCR, tmp);
615     Pop(tmp);
616     Msr(APSR_nzcvqg, tmp);
617     // Restore the regsisters.
618     if (Has32DRegs()) Vpop(Untyped64, DRegisterList(d16, 16));
619     Vpop(Untyped64, DRegisterList(d0, 8));
620     Pop(RegisterList(saved_registers_mask));
621   }
622 }
623 
624 
PushRegister(CPURegister reg)625 void MacroAssembler::PushRegister(CPURegister reg) {
626   switch (reg.GetType()) {
627     case CPURegister::kNoRegister:
628       break;
629     case CPURegister::kRRegister:
630       Push(Register(reg.GetCode()));
631       break;
632     case CPURegister::kSRegister:
633       Vpush(Untyped32, SRegisterList(SRegister(reg.GetCode())));
634       break;
635     case CPURegister::kDRegister:
636       Vpush(Untyped64, DRegisterList(DRegister(reg.GetCode())));
637       break;
638     case CPURegister::kQRegister:
639       VIXL_UNIMPLEMENTED();
640       break;
641   }
642 }
643 
644 
PreparePrintfArgument(CPURegister reg,int * core_count,int * vfp_count,uint32_t * printf_type)645 void MacroAssembler::PreparePrintfArgument(CPURegister reg,
646                                            int* core_count,
647                                            int* vfp_count,
648                                            uint32_t* printf_type) {
649   switch (reg.GetType()) {
650     case CPURegister::kNoRegister:
651       break;
652     case CPURegister::kRRegister:
653       VIXL_ASSERT(*core_count <= 4);
654       if (*core_count < 4) Pop(Register(*core_count));
655       *core_count += 1;
656       break;
657     case CPURegister::kSRegister:
658       VIXL_ASSERT(*vfp_count < 4);
659       *printf_type |= 1 << (*core_count + *vfp_count - 1);
660       Vpop(Untyped32, SRegisterList(SRegister(*vfp_count * 2)));
661       Vcvt(F64, F32, DRegister(*vfp_count), SRegister(*vfp_count * 2));
662       *vfp_count += 1;
663       break;
664     case CPURegister::kDRegister:
665       VIXL_ASSERT(*vfp_count < 4);
666       *printf_type |= 1 << (*core_count + *vfp_count - 1);
667       Vpop(Untyped64, DRegisterList(DRegister(*vfp_count)));
668       *vfp_count += 1;
669       break;
670     case CPURegister::kQRegister:
671       VIXL_UNIMPLEMENTED();
672       break;
673   }
674 }
675 
676 
Delegate(InstructionType type,InstructionCondROp instruction,Condition cond,Register rn,const Operand & operand)677 void MacroAssembler::Delegate(InstructionType type,
678                               InstructionCondROp instruction,
679                               Condition cond,
680                               Register rn,
681                               const Operand& operand) {
682   VIXL_ASSERT((type == kMovt) || (type == kSxtb16) || (type == kTeq) ||
683               (type == kUxtb16));
684 
685   if (type == kMovt) {
686     VIXL_ABORT_WITH_MSG("`Movt` expects a 16-bit immediate.\n");
687   }
688 
689   // This delegate only supports teq with immediates.
690   CONTEXT_SCOPE;
691   if ((type == kTeq) && operand.IsImmediate()) {
692     UseScratchRegisterScope temps(this);
693     Register scratch = temps.Acquire();
694     HandleOutOfBoundsImmediate(cond, scratch, operand.GetImmediate());
695     CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
696     teq(cond, rn, scratch);
697     return;
698   }
699   Assembler::Delegate(type, instruction, cond, rn, operand);
700 }
701 
702 
Delegate(InstructionType type,InstructionCondSizeROp instruction,Condition cond,EncodingSize size,Register rn,const Operand & operand)703 void MacroAssembler::Delegate(InstructionType type,
704                               InstructionCondSizeROp instruction,
705                               Condition cond,
706                               EncodingSize size,
707                               Register rn,
708                               const Operand& operand) {
709   CONTEXT_SCOPE;
710   VIXL_ASSERT(size.IsBest());
711   VIXL_ASSERT((type == kCmn) || (type == kCmp) || (type == kMov) ||
712               (type == kMovs) || (type == kMvn) || (type == kMvns) ||
713               (type == kSxtb) || (type == kSxth) || (type == kTst) ||
714               (type == kUxtb) || (type == kUxth));
715   if (IsUsingT32() && operand.IsRegisterShiftedRegister()) {
716     VIXL_ASSERT((type != kMov) || (type != kMovs));
717     InstructionCondRROp shiftop = NULL;
718     switch (operand.GetShift().GetType()) {
719       case LSL:
720         shiftop = &Assembler::lsl;
721         break;
722       case LSR:
723         shiftop = &Assembler::lsr;
724         break;
725       case ASR:
726         shiftop = &Assembler::asr;
727         break;
728       case RRX:
729         // A RegisterShiftedRegister operand cannot have a shift of type RRX.
730         VIXL_UNREACHABLE();
731         break;
732       case ROR:
733         shiftop = &Assembler::ror;
734         break;
735       default:
736         VIXL_UNREACHABLE();
737     }
738     if (shiftop != NULL) {
739       UseScratchRegisterScope temps(this);
740       Register scratch = temps.Acquire();
741       CodeBufferCheckScope scope(this, 2 * kMaxInstructionSizeInBytes);
742       (this->*shiftop)(cond,
743                        scratch,
744                        operand.GetBaseRegister(),
745                        operand.GetShiftRegister());
746       (this->*instruction)(cond, size, rn, scratch);
747       return;
748     }
749   }
750   if (operand.IsImmediate()) {
751     uint32_t imm = operand.GetImmediate();
752     switch (type) {
753       case kMov:
754       case kMovs:
755         if (!rn.IsPC()) {
756           // Immediate is too large, but not using PC, so handle with mov{t}.
757           HandleOutOfBoundsImmediate(cond, rn, imm);
758           if (type == kMovs) {
759             CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
760             tst(cond, rn, rn);
761           }
762           return;
763         } else if (type == kMov) {
764           VIXL_ASSERT(IsUsingA32() || cond.Is(al));
765           // Immediate is too large and using PC, so handle using a temporary
766           // register.
767           UseScratchRegisterScope temps(this);
768           Register scratch = temps.Acquire();
769           HandleOutOfBoundsImmediate(al, scratch, imm);
770           CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
771           bx(cond, scratch);
772           return;
773         }
774         break;
775       case kCmn:
776       case kCmp:
777         if (IsUsingA32() || !rn.IsPC()) {
778           UseScratchRegisterScope temps(this);
779           Register scratch = temps.Acquire();
780           HandleOutOfBoundsImmediate(cond, scratch, imm);
781           CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
782           (this->*instruction)(cond, size, rn, scratch);
783           return;
784         }
785         break;
786       case kMvn:
787       case kMvns:
788         if (!rn.IsPC()) {
789           UseScratchRegisterScope temps(this);
790           Register scratch = temps.Acquire();
791           HandleOutOfBoundsImmediate(cond, scratch, imm);
792           CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
793           (this->*instruction)(cond, size, rn, scratch);
794           return;
795         }
796         break;
797       case kTst:
798         if (IsUsingA32() || !rn.IsPC()) {
799           UseScratchRegisterScope temps(this);
800           Register scratch = temps.Acquire();
801           HandleOutOfBoundsImmediate(cond, scratch, imm);
802           CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
803           (this->*instruction)(cond, size, rn, scratch);
804           return;
805         }
806         break;
807       default:  // kSxtb, Sxth, Uxtb, Uxth
808         break;
809     }
810   }
811   Assembler::Delegate(type, instruction, cond, size, rn, operand);
812 }
813 
814 
Delegate(InstructionType type,InstructionCondRROp instruction,Condition cond,Register rd,Register rn,const Operand & operand)815 void MacroAssembler::Delegate(InstructionType type,
816                               InstructionCondRROp instruction,
817                               Condition cond,
818                               Register rd,
819                               Register rn,
820                               const Operand& operand) {
821   if ((type == kSxtab) || (type == kSxtab16) || (type == kSxtah) ||
822       (type == kUxtab) || (type == kUxtab16) || (type == kUxtah) ||
823       (type == kPkhbt) || (type == kPkhtb)) {
824     UnimplementedDelegate(type);
825     return;
826   }
827 
828   // This delegate only handles the following instructions.
829   VIXL_ASSERT((type == kOrn) || (type == kOrns) || (type == kRsc) ||
830               (type == kRscs));
831   CONTEXT_SCOPE;
832 
833   // T32 does not support register shifted register operands, emulate it.
834   if (IsUsingT32() && operand.IsRegisterShiftedRegister()) {
835     InstructionCondRROp shiftop = NULL;
836     switch (operand.GetShift().GetType()) {
837       case LSL:
838         shiftop = &Assembler::lsl;
839         break;
840       case LSR:
841         shiftop = &Assembler::lsr;
842         break;
843       case ASR:
844         shiftop = &Assembler::asr;
845         break;
846       case RRX:
847         // A RegisterShiftedRegister operand cannot have a shift of type RRX.
848         VIXL_UNREACHABLE();
849         break;
850       case ROR:
851         shiftop = &Assembler::ror;
852         break;
853       default:
854         VIXL_UNREACHABLE();
855     }
856     if (shiftop != NULL) {
857       UseScratchRegisterScope temps(this);
858       Register rm = operand.GetBaseRegister();
859       Register rs = operand.GetShiftRegister();
860       // Try to use rd as a scratch register. We can do this if it aliases rs or
861       // rm (because we read them in the first instruction), but not rn.
862       if (!rd.Is(rn)) temps.Include(rd);
863       Register scratch = temps.Acquire();
864       // TODO: The scope length was measured empirically. We should analyse the
865       // worst-case size and add targetted tests.
866       CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
867       (this->*shiftop)(cond, scratch, rm, rs);
868       (this->*instruction)(cond, rd, rn, scratch);
869       return;
870     }
871   }
872 
873   // T32 does not have a Rsc instruction, negate the lhs input and turn it into
874   // an Adc. Adc and Rsc are equivalent using a bitwise NOT:
875   //   adc rd, rn, operand <-> rsc rd, NOT(rn), operand
876   if (IsUsingT32() && ((type == kRsc) || (type == kRscs))) {
877     // The RegisterShiftRegister case should have been handled above.
878     VIXL_ASSERT(!operand.IsRegisterShiftedRegister());
879     UseScratchRegisterScope temps(this);
880     // Try to use rd as a scratch register. We can do this if it aliases rn
881     // (because we read it in the first instruction), but not rm.
882     temps.Include(rd);
883     temps.Exclude(operand);
884     Register negated_rn = temps.Acquire();
885     {
886       CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
887       mvn(cond, negated_rn, rn);
888     }
889     if (type == kRsc) {
890       CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
891       adc(cond, rd, negated_rn, operand);
892       return;
893     }
894     // TODO: We shouldn't have to specify how much space the next instruction
895     // needs.
896     CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
897     adcs(cond, rd, negated_rn, operand);
898     return;
899   }
900 
901   if (operand.IsImmediate()) {
902     // If the immediate can be encoded when inverted, turn Orn into Orr.
903     // Otherwise rely on HandleOutOfBoundsImmediate to generate a series of
904     // mov.
905     int32_t imm = operand.GetSignedImmediate();
906     if (((type == kOrn) || (type == kOrns)) && IsModifiedImmediate(~imm)) {
907       CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
908       switch (type) {
909         case kOrn:
910           orr(cond, rd, rn, ~imm);
911           return;
912         case kOrns:
913           orrs(cond, rd, rn, ~imm);
914           return;
915         default:
916           VIXL_UNREACHABLE();
917           break;
918       }
919     }
920   }
921 
922   // A32 does not have a Orn instruction, negate the rhs input and turn it into
923   // a Orr.
924   if (IsUsingA32() && ((type == kOrn) || (type == kOrns))) {
925     // TODO: orn r0, r1, imm -> orr r0, r1, neg(imm) if doable
926     //  mvn r0, r2
927     //  orr r0, r1, r0
928     Register scratch;
929     UseScratchRegisterScope temps(this);
930     // Try to use rd as a scratch register. We can do this if it aliases rs or
931     // rm (because we read them in the first instruction), but not rn.
932     if (!rd.Is(rn)) temps.Include(rd);
933     scratch = temps.Acquire();
934     {
935       // TODO: We shouldn't have to specify how much space the next instruction
936       // needs.
937       CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
938       mvn(cond, scratch, operand);
939     }
940     if (type == kOrns) {
941       CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
942       orrs(cond, rd, rn, scratch);
943       return;
944     }
945     CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
946     orr(cond, rd, rn, scratch);
947     return;
948   }
949 
950   if (operand.IsImmediate()) {
951     UseScratchRegisterScope temps(this);
952     // Allow using the destination as a scratch register if possible.
953     if (!rd.Is(rn)) temps.Include(rd);
954     Register scratch = temps.Acquire();
955     int32_t imm = operand.GetSignedImmediate();
956     HandleOutOfBoundsImmediate(cond, scratch, imm);
957     CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
958     (this->*instruction)(cond, rd, rn, scratch);
959     return;
960   }
961   Assembler::Delegate(type, instruction, cond, rd, rn, operand);
962 }
963 
964 
Delegate(InstructionType type,InstructionCondSizeRL instruction,Condition cond,EncodingSize size,Register rd,Location * location)965 void MacroAssembler::Delegate(InstructionType type,
966                               InstructionCondSizeRL instruction,
967                               Condition cond,
968                               EncodingSize size,
969                               Register rd,
970                               Location* location) {
971   VIXL_ASSERT((type == kLdr) || (type == kAdr));
972 
973   CONTEXT_SCOPE;
974   VIXL_ASSERT(size.IsBest());
975 
976   if ((type == kLdr) && location->IsBound()) {
977     CodeBufferCheckScope scope(this, 5 * kMaxInstructionSizeInBytes);
978     UseScratchRegisterScope temps(this);
979     temps.Include(rd);
980     uint32_t mask = GetOffsetMask(type, Offset);
981     ldr(rd, MemOperandComputationHelper(cond, temps.Acquire(), location, mask));
982     return;
983   }
984 
985   Assembler::Delegate(type, instruction, cond, size, rd, location);
986 }
987 
988 
GenerateSplitInstruction(InstructionCondSizeRROp instruction,Condition cond,Register rd,Register rn,uint32_t imm,uint32_t mask)989 bool MacroAssembler::GenerateSplitInstruction(
990     InstructionCondSizeRROp instruction,
991     Condition cond,
992     Register rd,
993     Register rn,
994     uint32_t imm,
995     uint32_t mask) {
996   uint32_t high = imm & ~mask;
997   if (!IsModifiedImmediate(high) && !rn.IsPC()) return false;
998   // If high is a modified immediate, we can perform the operation with
999   // only 2 instructions.
1000   // Else, if rn is PC, we want to avoid moving PC into a temporary.
1001   // Therefore, we also use the pattern even if the second call may
1002   // generate 3 instructions.
1003   uint32_t low = imm & mask;
1004   CodeBufferCheckScope scope(this,
1005                              (rn.IsPC() ? 4 : 2) * kMaxInstructionSizeInBytes);
1006   (this->*instruction)(cond, Best, rd, rn, low);
1007   (this->*instruction)(cond, Best, rd, rd, high);
1008   return true;
1009 }
1010 
1011 
Delegate(InstructionType type,InstructionCondSizeRROp instruction,Condition cond,EncodingSize size,Register rd,Register rn,const Operand & operand)1012 void MacroAssembler::Delegate(InstructionType type,
1013                               InstructionCondSizeRROp instruction,
1014                               Condition cond,
1015                               EncodingSize size,
1016                               Register rd,
1017                               Register rn,
1018                               const Operand& operand) {
1019   VIXL_ASSERT(
1020       (type == kAdc) || (type == kAdcs) || (type == kAdd) || (type == kAdds) ||
1021       (type == kAnd) || (type == kAnds) || (type == kAsr) || (type == kAsrs) ||
1022       (type == kBic) || (type == kBics) || (type == kEor) || (type == kEors) ||
1023       (type == kLsl) || (type == kLsls) || (type == kLsr) || (type == kLsrs) ||
1024       (type == kOrr) || (type == kOrrs) || (type == kRor) || (type == kRors) ||
1025       (type == kRsb) || (type == kRsbs) || (type == kSbc) || (type == kSbcs) ||
1026       (type == kSub) || (type == kSubs));
1027 
1028   CONTEXT_SCOPE;
1029   VIXL_ASSERT(size.IsBest());
1030   if (IsUsingT32() && operand.IsRegisterShiftedRegister()) {
1031     InstructionCondRROp shiftop = NULL;
1032     switch (operand.GetShift().GetType()) {
1033       case LSL:
1034         shiftop = &Assembler::lsl;
1035         break;
1036       case LSR:
1037         shiftop = &Assembler::lsr;
1038         break;
1039       case ASR:
1040         shiftop = &Assembler::asr;
1041         break;
1042       case RRX:
1043         // A RegisterShiftedRegister operand cannot have a shift of type RRX.
1044         VIXL_UNREACHABLE();
1045         break;
1046       case ROR:
1047         shiftop = &Assembler::ror;
1048         break;
1049       default:
1050         VIXL_UNREACHABLE();
1051     }
1052     if (shiftop != NULL) {
1053       UseScratchRegisterScope temps(this);
1054       Register rm = operand.GetBaseRegister();
1055       Register rs = operand.GetShiftRegister();
1056       // Try to use rd as a scratch register. We can do this if it aliases rs or
1057       // rm (because we read them in the first instruction), but not rn.
1058       if (!rd.Is(rn)) temps.Include(rd);
1059       Register scratch = temps.Acquire();
1060       CodeBufferCheckScope scope(this, 2 * kMaxInstructionSizeInBytes);
1061       (this->*shiftop)(cond, scratch, rm, rs);
1062       (this->*instruction)(cond, size, rd, rn, scratch);
1063       return;
1064     }
1065   }
1066   if (operand.IsImmediate()) {
1067     int32_t imm = operand.GetSignedImmediate();
1068     if (ImmediateT32::IsImmediateT32(~imm)) {
1069       if (IsUsingT32()) {
1070         switch (type) {
1071           case kOrr:
1072             orn(cond, rd, rn, ~imm);
1073             return;
1074           case kOrrs:
1075             orns(cond, rd, rn, ~imm);
1076             return;
1077           default:
1078             break;
1079         }
1080       }
1081     }
1082     if (imm < 0) {
1083       InstructionCondSizeRROp asmcb = NULL;
1084       // Add and sub are equivalent using an arithmetic negation:
1085       //   add rd, rn, #imm <-> sub rd, rn, - #imm
1086       // Add and sub with carry are equivalent using a bitwise NOT:
1087       //   adc rd, rn, #imm <-> sbc rd, rn, NOT #imm
1088       switch (type) {
1089         case kAdd:
1090           asmcb = &Assembler::sub;
1091           imm = -imm;
1092           break;
1093         case kAdds:
1094           asmcb = &Assembler::subs;
1095           imm = -imm;
1096           break;
1097         case kSub:
1098           asmcb = &Assembler::add;
1099           imm = -imm;
1100           break;
1101         case kSubs:
1102           asmcb = &Assembler::adds;
1103           imm = -imm;
1104           break;
1105         case kAdc:
1106           asmcb = &Assembler::sbc;
1107           imm = ~imm;
1108           break;
1109         case kAdcs:
1110           asmcb = &Assembler::sbcs;
1111           imm = ~imm;
1112           break;
1113         case kSbc:
1114           asmcb = &Assembler::adc;
1115           imm = ~imm;
1116           break;
1117         case kSbcs:
1118           asmcb = &Assembler::adcs;
1119           imm = ~imm;
1120           break;
1121         default:
1122           break;
1123       }
1124       if (asmcb != NULL) {
1125         CodeBufferCheckScope scope(this, 4 * kMaxInstructionSizeInBytes);
1126         (this->*asmcb)(cond, size, rd, rn, Operand(imm));
1127         return;
1128       }
1129     }
1130 
1131     // When rn is PC, only handle negative offsets. The correct way to handle
1132     // positive offsets isn't clear; does the user want the offset from the
1133     // start of the macro, or from the end (to allow a certain amount of space)?
1134     // When type is Add or Sub, imm is always positive (imm < 0 has just been
1135     // handled and imm == 0 would have been generated without the need of a
1136     // delegate). Therefore, only add to PC is forbidden here.
1137     if ((((type == kAdd) && !rn.IsPC()) || (type == kSub)) &&
1138         (IsUsingA32() || (!rd.IsPC() && !rn.IsPC()))) {
1139       VIXL_ASSERT(imm > 0);
1140       // Try to break the constant into two modified immediates.
1141       // For T32 also try to break the constant into one imm12 and one modified
1142       // immediate. Count the trailing zeroes and get the biggest even value.
1143       int trailing_zeroes = CountTrailingZeros(imm) & ~1u;
1144       uint32_t mask = ((trailing_zeroes < 4) && IsUsingT32())
1145                           ? 0xfff
1146                           : (0xff << trailing_zeroes);
1147       if (GenerateSplitInstruction(instruction, cond, rd, rn, imm, mask)) {
1148         return;
1149       }
1150       InstructionCondSizeRROp asmcb = NULL;
1151       switch (type) {
1152         case kAdd:
1153           asmcb = &Assembler::sub;
1154           break;
1155         case kSub:
1156           asmcb = &Assembler::add;
1157           break;
1158         default:
1159           VIXL_UNREACHABLE();
1160       }
1161       if (GenerateSplitInstruction(asmcb, cond, rd, rn, -imm, mask)) {
1162         return;
1163       }
1164     }
1165 
1166     UseScratchRegisterScope temps(this);
1167     // Allow using the destination as a scratch register if possible.
1168     if (!rd.Is(rn)) temps.Include(rd);
1169     if (rn.IsPC()) {
1170       // If we're reading the PC, we need to do it in the first instruction,
1171       // otherwise we'll read the wrong value. We rely on this to handle the
1172       // long-range PC-relative MemOperands which can result from user-managed
1173       // literals.
1174 
1175       // Only handle negative offsets. The correct way to handle positive
1176       // offsets isn't clear; does the user want the offset from the start of
1177       // the macro, or from the end (to allow a certain amount of space)?
1178       bool offset_is_negative_or_zero = (imm <= 0);
1179       switch (type) {
1180         case kAdd:
1181         case kAdds:
1182           offset_is_negative_or_zero = (imm <= 0);
1183           break;
1184         case kSub:
1185         case kSubs:
1186           offset_is_negative_or_zero = (imm >= 0);
1187           break;
1188         case kAdc:
1189         case kAdcs:
1190           offset_is_negative_or_zero = (imm < 0);
1191           break;
1192         case kSbc:
1193         case kSbcs:
1194           offset_is_negative_or_zero = (imm > 0);
1195           break;
1196         default:
1197           break;
1198       }
1199       if (offset_is_negative_or_zero) {
1200         {
1201           rn = temps.Acquire();
1202           CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1203           mov(cond, rn, pc);
1204         }
1205         // Recurse rather than falling through, to try to get the immediate into
1206         // a single instruction.
1207         CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
1208         (this->*instruction)(cond, size, rd, rn, operand);
1209         return;
1210       }
1211     } else {
1212       Register scratch = temps.Acquire();
1213       // TODO: The scope length was measured empirically. We should analyse the
1214       // worst-case size and add targetted tests.
1215       CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
1216       mov(cond, scratch, operand.GetImmediate());
1217       (this->*instruction)(cond, size, rd, rn, scratch);
1218       return;
1219     }
1220   }
1221   Assembler::Delegate(type, instruction, cond, size, rd, rn, operand);
1222 }
1223 
1224 
Delegate(InstructionType type,InstructionRL instruction,Register rn,Location * location)1225 void MacroAssembler::Delegate(InstructionType type,
1226                               InstructionRL instruction,
1227                               Register rn,
1228                               Location* location) {
1229   VIXL_ASSERT((type == kCbz) || (type == kCbnz));
1230 
1231   CONTEXT_SCOPE;
1232   CodeBufferCheckScope scope(this, 2 * kMaxInstructionSizeInBytes);
1233   if (IsUsingA32()) {
1234     if (type == kCbz) {
1235       VIXL_ABORT_WITH_MSG("Cbz is only available for T32.\n");
1236     } else {
1237       VIXL_ABORT_WITH_MSG("Cbnz is only available for T32.\n");
1238     }
1239   } else if (rn.IsLow()) {
1240     switch (type) {
1241       case kCbnz: {
1242 #ifndef PANDA_BUILD
1243         Label done;
1244 #else
1245         Label done(allocator_);
1246 #endif
1247         cbz(rn, &done);
1248         b(location);
1249         Bind(&done);
1250         return;
1251       }
1252       case kCbz: {
1253 #ifndef PANDA_BUILD
1254         Label done;
1255 #else
1256         Label done(allocator_);
1257 #endif
1258         cbnz(rn, &done);
1259         b(location);
1260         Bind(&done);
1261         return;
1262       }
1263       default:
1264         break;
1265     }
1266   }
1267   Assembler::Delegate(type, instruction, rn, location);
1268 }
1269 
1270 
1271 template <typename T>
IsI64BitPattern(T imm)1272 static inline bool IsI64BitPattern(T imm) {
1273   for (T mask = 0xff << ((sizeof(T) - 1) * 8); mask != 0; mask >>= 8) {
1274     if (((imm & mask) != mask) && ((imm & mask) != 0)) return false;
1275   }
1276   return true;
1277 }
1278 
1279 
1280 template <typename T>
IsI8BitPattern(T imm)1281 static inline bool IsI8BitPattern(T imm) {
1282   uint8_t imm8 = imm & 0xff;
1283   for (unsigned rep = sizeof(T) - 1; rep > 0; rep--) {
1284     imm >>= 8;
1285     if ((imm & 0xff) != imm8) return false;
1286   }
1287   return true;
1288 }
1289 
1290 
CanBeInverted(uint32_t imm32)1291 static inline bool CanBeInverted(uint32_t imm32) {
1292   uint32_t fill8 = 0;
1293 
1294   if ((imm32 & 0xffffff00) == 0xffffff00) {
1295     //    11111111 11111111 11111111 abcdefgh
1296     return true;
1297   }
1298   if (((imm32 & 0xff) == 0) || ((imm32 & 0xff) == 0xff)) {
1299     fill8 = imm32 & 0xff;
1300     imm32 >>= 8;
1301     if ((imm32 >> 8) == 0xffff) {
1302       //    11111111 11111111 abcdefgh 00000000
1303       // or 11111111 11111111 abcdefgh 11111111
1304       return true;
1305     }
1306     if ((imm32 & 0xff) == fill8) {
1307       imm32 >>= 8;
1308       if ((imm32 >> 8) == 0xff) {
1309         //    11111111 abcdefgh 00000000 00000000
1310         // or 11111111 abcdefgh 11111111 11111111
1311         return true;
1312       }
1313       if ((fill8 == 0xff) && ((imm32 & 0xff) == 0xff)) {
1314         //    abcdefgh 11111111 11111111 11111111
1315         return true;
1316       }
1317     }
1318   }
1319   return false;
1320 }
1321 
1322 
1323 template <typename RES, typename T>
replicate(T imm)1324 static inline RES replicate(T imm) {
1325   VIXL_ASSERT((sizeof(RES) > sizeof(T)) &&
1326               (((sizeof(RES) / sizeof(T)) * sizeof(T)) == sizeof(RES)));
1327   RES res = imm;
1328   for (unsigned i = sizeof(RES) / sizeof(T) - 1; i > 0; i--) {
1329     res = (res << (sizeof(T) * 8)) | imm;
1330   }
1331   return res;
1332 }
1333 
1334 
Delegate(InstructionType type,InstructionCondDtSSop instruction,Condition cond,DataType dt,SRegister rd,const SOperand & operand)1335 void MacroAssembler::Delegate(InstructionType type,
1336                               InstructionCondDtSSop instruction,
1337                               Condition cond,
1338                               DataType dt,
1339                               SRegister rd,
1340                               const SOperand& operand) {
1341   CONTEXT_SCOPE;
1342   if (type == kVmov) {
1343     if (operand.IsImmediate() && dt.Is(F32)) {
1344       const NeonImmediate& neon_imm = operand.GetNeonImmediate();
1345       if (neon_imm.CanConvert<float>()) {
1346         // movw ip, imm16
1347         // movk ip, imm16
1348         // vmov s0, ip
1349         UseScratchRegisterScope temps(this);
1350         Register scratch = temps.Acquire();
1351         float f = neon_imm.GetImmediate<float>();
1352         // TODO: The scope length was measured empirically. We should analyse
1353         // the
1354         // worst-case size and add targetted tests.
1355         CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
1356         mov(cond, scratch, FloatToRawbits(f));
1357         vmov(cond, rd, scratch);
1358         return;
1359       }
1360     }
1361   }
1362   Assembler::Delegate(type, instruction, cond, dt, rd, operand);
1363 }
1364 
1365 
Delegate(InstructionType type,InstructionCondDtDDop instruction,Condition cond,DataType dt,DRegister rd,const DOperand & operand)1366 void MacroAssembler::Delegate(InstructionType type,
1367                               InstructionCondDtDDop instruction,
1368                               Condition cond,
1369                               DataType dt,
1370                               DRegister rd,
1371                               const DOperand& operand) {
1372   CONTEXT_SCOPE;
1373   if (type == kVmov) {
1374     if (operand.IsImmediate()) {
1375       const NeonImmediate& neon_imm = operand.GetNeonImmediate();
1376       switch (dt.GetValue()) {
1377         case I32:
1378           if (neon_imm.CanConvert<uint32_t>()) {
1379             uint32_t imm = neon_imm.GetImmediate<uint32_t>();
1380             // vmov.i32 d0, 0xabababab will translate into vmov.i8 d0, 0xab
1381             if (IsI8BitPattern(imm)) {
1382               CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1383               vmov(cond, I8, rd, imm & 0xff);
1384               return;
1385             }
1386             // vmov.i32 d0, 0xff0000ff will translate into
1387             // vmov.i64 d0, 0xff0000ffff0000ff
1388             if (IsI64BitPattern(imm)) {
1389               CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1390               vmov(cond, I64, rd, replicate<uint64_t>(imm));
1391               return;
1392             }
1393             // vmov.i32 d0, 0xffab0000 will translate into
1394             // vmvn.i32 d0, 0x0054ffff
1395             if (cond.Is(al) && CanBeInverted(imm)) {
1396               CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1397               vmvn(I32, rd, ~imm);
1398               return;
1399             }
1400           }
1401           break;
1402         case I16:
1403           if (neon_imm.CanConvert<uint16_t>()) {
1404             uint16_t imm = neon_imm.GetImmediate<uint16_t>();
1405             // vmov.i16 d0, 0xabab will translate into vmov.i8 d0, 0xab
1406             if (IsI8BitPattern(imm)) {
1407               CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1408               vmov(cond, I8, rd, imm & 0xff);
1409               return;
1410             }
1411           }
1412           break;
1413         case I64:
1414           if (neon_imm.CanConvert<uint64_t>()) {
1415             uint64_t imm = neon_imm.GetImmediate<uint64_t>();
1416             // vmov.i64 d0, -1 will translate into vmov.i8 d0, 0xff
1417             if (IsI8BitPattern(imm)) {
1418               CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1419               vmov(cond, I8, rd, imm & 0xff);
1420               return;
1421             }
1422             // mov ip, lo(imm64)
1423             // vdup d0, ip
1424             // vdup is prefered to 'vmov d0[0]' as d0[1] does not need to be
1425             // preserved
1426             {
1427               UseScratchRegisterScope temps(this);
1428               Register scratch = temps.Acquire();
1429               {
1430                 // TODO: The scope length was measured empirically. We should
1431                 // analyse the
1432                 // worst-case size and add targetted tests.
1433                 CodeBufferCheckScope scope(this,
1434                                            2 * kMaxInstructionSizeInBytes);
1435                 mov(cond, scratch, static_cast<uint32_t>(imm & 0xffffffff));
1436               }
1437               CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1438               vdup(cond, Untyped32, rd, scratch);
1439             }
1440             // mov ip, hi(imm64)
1441             // vmov d0[1], ip
1442             {
1443               UseScratchRegisterScope temps(this);
1444               Register scratch = temps.Acquire();
1445               {
1446                 // TODO: The scope length was measured empirically. We should
1447                 // analyse the
1448                 // worst-case size and add targetted tests.
1449                 CodeBufferCheckScope scope(this,
1450                                            2 * kMaxInstructionSizeInBytes);
1451                 mov(cond, scratch, static_cast<uint32_t>(imm >> 32));
1452               }
1453               CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1454               vmov(cond, Untyped32, DRegisterLane(rd, 1), scratch);
1455             }
1456             return;
1457           }
1458           break;
1459         default:
1460           break;
1461       }
1462       VIXL_ASSERT(!dt.Is(I8));  // I8 cases should have been handled already.
1463       if ((dt.Is(I16) || dt.Is(I32)) && neon_imm.CanConvert<uint32_t>()) {
1464         // mov ip, imm32
1465         // vdup.16 d0, ip
1466         UseScratchRegisterScope temps(this);
1467         Register scratch = temps.Acquire();
1468         {
1469           CodeBufferCheckScope scope(this, 2 * kMaxInstructionSizeInBytes);
1470           mov(cond, scratch, neon_imm.GetImmediate<uint32_t>());
1471         }
1472         DataTypeValue vdup_dt = Untyped32;
1473         switch (dt.GetValue()) {
1474           case I16:
1475             vdup_dt = Untyped16;
1476             break;
1477           case I32:
1478             vdup_dt = Untyped32;
1479             break;
1480           default:
1481             VIXL_UNREACHABLE();
1482         }
1483         CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1484         vdup(cond, vdup_dt, rd, scratch);
1485         return;
1486       }
1487       if (dt.Is(F32) && neon_imm.CanConvert<float>()) {
1488         float f = neon_imm.GetImmediate<float>();
1489         // Punt to vmov.i32
1490         // TODO: The scope length was guessed based on the double case below. We
1491         // should analyse the worst-case size and add targetted tests.
1492         CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
1493         vmov(cond, I32, rd, FloatToRawbits(f));
1494         return;
1495       }
1496       if (dt.Is(F64) && neon_imm.CanConvert<double>()) {
1497         // Punt to vmov.i64
1498         double d = neon_imm.GetImmediate<double>();
1499         // TODO: The scope length was measured empirically. We should analyse
1500         // the
1501         // worst-case size and add targetted tests.
1502         CodeBufferCheckScope scope(this, 6 * kMaxInstructionSizeInBytes);
1503         vmov(cond, I64, rd, DoubleToRawbits(d));
1504         return;
1505       }
1506     }
1507   }
1508   Assembler::Delegate(type, instruction, cond, dt, rd, operand);
1509 }
1510 
1511 
Delegate(InstructionType type,InstructionCondDtQQop instruction,Condition cond,DataType dt,QRegister rd,const QOperand & operand)1512 void MacroAssembler::Delegate(InstructionType type,
1513                               InstructionCondDtQQop instruction,
1514                               Condition cond,
1515                               DataType dt,
1516                               QRegister rd,
1517                               const QOperand& operand) {
1518   CONTEXT_SCOPE;
1519   if (type == kVmov) {
1520     if (operand.IsImmediate()) {
1521       const NeonImmediate& neon_imm = operand.GetNeonImmediate();
1522       switch (dt.GetValue()) {
1523         case I32:
1524           if (neon_imm.CanConvert<uint32_t>()) {
1525             uint32_t imm = neon_imm.GetImmediate<uint32_t>();
1526             // vmov.i32 d0, 0xabababab will translate into vmov.i8 d0, 0xab
1527             if (IsI8BitPattern(imm)) {
1528               CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1529               vmov(cond, I8, rd, imm & 0xff);
1530               return;
1531             }
1532             // vmov.i32 d0, 0xff0000ff will translate into
1533             // vmov.i64 d0, 0xff0000ffff0000ff
1534             if (IsI64BitPattern(imm)) {
1535               CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1536               vmov(cond, I64, rd, replicate<uint64_t>(imm));
1537               return;
1538             }
1539             // vmov.i32 d0, 0xffab0000 will translate into
1540             // vmvn.i32 d0, 0x0054ffff
1541             if (CanBeInverted(imm)) {
1542               CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1543               vmvn(cond, I32, rd, ~imm);
1544               return;
1545             }
1546           }
1547           break;
1548         case I16:
1549           if (neon_imm.CanConvert<uint16_t>()) {
1550             uint16_t imm = neon_imm.GetImmediate<uint16_t>();
1551             // vmov.i16 d0, 0xabab will translate into vmov.i8 d0, 0xab
1552             if (IsI8BitPattern(imm)) {
1553               CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1554               vmov(cond, I8, rd, imm & 0xff);
1555               return;
1556             }
1557           }
1558           break;
1559         case I64:
1560           if (neon_imm.CanConvert<uint64_t>()) {
1561             uint64_t imm = neon_imm.GetImmediate<uint64_t>();
1562             // vmov.i64 d0, -1 will translate into vmov.i8 d0, 0xff
1563             if (IsI8BitPattern(imm)) {
1564               CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1565               vmov(cond, I8, rd, imm & 0xff);
1566               return;
1567             }
1568             // mov ip, lo(imm64)
1569             // vdup q0, ip
1570             // vdup is prefered to 'vmov d0[0]' as d0[1-3] don't need to be
1571             // preserved
1572             {
1573               UseScratchRegisterScope temps(this);
1574               Register scratch = temps.Acquire();
1575               {
1576                 CodeBufferCheckScope scope(this,
1577                                            2 * kMaxInstructionSizeInBytes);
1578                 mov(cond, scratch, static_cast<uint32_t>(imm & 0xffffffff));
1579               }
1580               CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1581               vdup(cond, Untyped32, rd, scratch);
1582             }
1583             // mov ip, hi(imm64)
1584             // vmov.i32 d0[1], ip
1585             // vmov d1, d0
1586             {
1587               UseScratchRegisterScope temps(this);
1588               Register scratch = temps.Acquire();
1589               {
1590                 CodeBufferCheckScope scope(this,
1591                                            2 * kMaxInstructionSizeInBytes);
1592                 mov(cond, scratch, static_cast<uint32_t>(imm >> 32));
1593               }
1594               {
1595                 CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1596                 vmov(cond,
1597                      Untyped32,
1598                      DRegisterLane(rd.GetLowDRegister(), 1),
1599                      scratch);
1600               }
1601               CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1602               vmov(cond, F64, rd.GetHighDRegister(), rd.GetLowDRegister());
1603             }
1604             return;
1605           }
1606           break;
1607         default:
1608           break;
1609       }
1610       VIXL_ASSERT(!dt.Is(I8));  // I8 cases should have been handled already.
1611       if ((dt.Is(I16) || dt.Is(I32)) && neon_imm.CanConvert<uint32_t>()) {
1612         // mov ip, imm32
1613         // vdup.16 d0, ip
1614         UseScratchRegisterScope temps(this);
1615         Register scratch = temps.Acquire();
1616         {
1617           CodeBufferCheckScope scope(this, 2 * kMaxInstructionSizeInBytes);
1618           mov(cond, scratch, neon_imm.GetImmediate<uint32_t>());
1619         }
1620         DataTypeValue vdup_dt = Untyped32;
1621         switch (dt.GetValue()) {
1622           case I16:
1623             vdup_dt = Untyped16;
1624             break;
1625           case I32:
1626             vdup_dt = Untyped32;
1627             break;
1628           default:
1629             VIXL_UNREACHABLE();
1630         }
1631         CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1632         vdup(cond, vdup_dt, rd, scratch);
1633         return;
1634       }
1635       if (dt.Is(F32) && neon_imm.CanConvert<float>()) {
1636         // Punt to vmov.i64
1637         float f = neon_imm.GetImmediate<float>();
1638         CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
1639         vmov(cond, I32, rd, FloatToRawbits(f));
1640         return;
1641       }
1642       if (dt.Is(F64) && neon_imm.CanConvert<double>()) {
1643         // Use vmov to create the double in the low D register, then duplicate
1644         // it into the high D register.
1645         double d = neon_imm.GetImmediate<double>();
1646         CodeBufferCheckScope scope(this, 7 * kMaxInstructionSizeInBytes);
1647         vmov(cond, F64, rd.GetLowDRegister(), d);
1648         vmov(cond, F64, rd.GetHighDRegister(), rd.GetLowDRegister());
1649         return;
1650       }
1651     }
1652   }
1653   Assembler::Delegate(type, instruction, cond, dt, rd, operand);
1654 }
1655 
1656 
Delegate(InstructionType type,InstructionCondRL instruction,Condition cond,Register rt,Location * location)1657 void MacroAssembler::Delegate(InstructionType type,
1658                               InstructionCondRL instruction,
1659                               Condition cond,
1660                               Register rt,
1661                               Location* location) {
1662   VIXL_ASSERT((type == kLdrb) || (type == kLdrh) || (type == kLdrsb) ||
1663               (type == kLdrsh));
1664 
1665   CONTEXT_SCOPE;
1666 
1667   if (location->IsBound()) {
1668     CodeBufferCheckScope scope(this, 5 * kMaxInstructionSizeInBytes);
1669     UseScratchRegisterScope temps(this);
1670     temps.Include(rt);
1671     Register scratch = temps.Acquire();
1672     uint32_t mask = GetOffsetMask(type, Offset);
1673     switch (type) {
1674       case kLdrb:
1675         ldrb(rt, MemOperandComputationHelper(cond, scratch, location, mask));
1676         return;
1677       case kLdrh:
1678         ldrh(rt, MemOperandComputationHelper(cond, scratch, location, mask));
1679         return;
1680       case kLdrsb:
1681         ldrsb(rt, MemOperandComputationHelper(cond, scratch, location, mask));
1682         return;
1683       case kLdrsh:
1684         ldrsh(rt, MemOperandComputationHelper(cond, scratch, location, mask));
1685         return;
1686       default:
1687         VIXL_UNREACHABLE();
1688     }
1689     return;
1690   }
1691 
1692   Assembler::Delegate(type, instruction, cond, rt, location);
1693 }
1694 
1695 
Delegate(InstructionType type,InstructionCondRRL instruction,Condition cond,Register rt,Register rt2,Location * location)1696 void MacroAssembler::Delegate(InstructionType type,
1697                               InstructionCondRRL instruction,
1698                               Condition cond,
1699                               Register rt,
1700                               Register rt2,
1701                               Location* location) {
1702   VIXL_ASSERT(type == kLdrd);
1703 
1704   CONTEXT_SCOPE;
1705 
1706   if (location->IsBound()) {
1707     CodeBufferCheckScope scope(this, 6 * kMaxInstructionSizeInBytes);
1708     UseScratchRegisterScope temps(this);
1709     temps.Include(rt, rt2);
1710     Register scratch = temps.Acquire();
1711     uint32_t mask = GetOffsetMask(type, Offset);
1712     ldrd(rt, rt2, MemOperandComputationHelper(cond, scratch, location, mask));
1713     return;
1714   }
1715 
1716   Assembler::Delegate(type, instruction, cond, rt, rt2, location);
1717 }
1718 
1719 
Delegate(InstructionType type,InstructionCondSizeRMop instruction,Condition cond,EncodingSize size,Register rd,const MemOperand & operand)1720 void MacroAssembler::Delegate(InstructionType type,
1721                               InstructionCondSizeRMop instruction,
1722                               Condition cond,
1723                               EncodingSize size,
1724                               Register rd,
1725                               const MemOperand& operand) {
1726   CONTEXT_SCOPE;
1727   VIXL_ASSERT(size.IsBest());
1728   VIXL_ASSERT((type == kLdr) || (type == kLdrb) || (type == kLdrh) ||
1729               (type == kLdrsb) || (type == kLdrsh) || (type == kStr) ||
1730               (type == kStrb) || (type == kStrh));
1731   if (operand.IsImmediate()) {
1732     const Register& rn = operand.GetBaseRegister();
1733     AddrMode addrmode = operand.GetAddrMode();
1734     int32_t offset = operand.GetOffsetImmediate();
1735     uint32_t extra_offset_mask = GetOffsetMask(type, addrmode);
1736     // Try to maximize the offset used by the MemOperand (load_store_offset).
1737     // Add the part which can't be used by the MemOperand (add_offset).
1738     uint32_t load_store_offset = offset & extra_offset_mask;
1739     uint32_t add_offset = offset & ~extra_offset_mask;
1740     if ((add_offset != 0) &&
1741         (IsModifiedImmediate(offset) || IsModifiedImmediate(-offset))) {
1742       load_store_offset = 0;
1743       add_offset = offset;
1744     }
1745     switch (addrmode) {
1746       case PreIndex:
1747         // Avoid the unpredictable case 'str r0, [r0, imm]!'
1748         if (!rn.Is(rd)) {
1749           // Pre-Indexed case:
1750           // ldr r0, [r1, 12345]! will translate into
1751           //   add r1, r1, 12345
1752           //   ldr r0, [r1]
1753           {
1754             CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
1755             add(cond, rn, rn, add_offset);
1756           }
1757           {
1758             CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1759             (this->*instruction)(cond,
1760                                  size,
1761                                  rd,
1762                                  MemOperand(rn, load_store_offset, PreIndex));
1763           }
1764           return;
1765         }
1766         break;
1767       case Offset: {
1768         UseScratchRegisterScope temps(this);
1769         // Allow using the destination as a scratch register if possible.
1770         if ((type != kStr) && (type != kStrb) && (type != kStrh) &&
1771             !rd.Is(rn)) {
1772           temps.Include(rd);
1773         }
1774         Register scratch = temps.Acquire();
1775         // Offset case:
1776         // ldr r0, [r1, 12345] will translate into
1777         //   add r0, r1, 12345
1778         //   ldr r0, [r0]
1779         {
1780           CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
1781           add(cond, scratch, rn, add_offset);
1782         }
1783         {
1784           CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1785           (this->*instruction)(cond,
1786                                size,
1787                                rd,
1788                                MemOperand(scratch, load_store_offset));
1789         }
1790         return;
1791       }
1792       case PostIndex:
1793         // Avoid the unpredictable case 'ldr r0, [r0], imm'
1794         if (!rn.Is(rd)) {
1795           // Post-indexed case:
1796           // ldr r0. [r1], imm32 will translate into
1797           //   ldr r0, [r1]
1798           //   movw ip. imm32 & 0xffffffff
1799           //   movt ip, imm32 >> 16
1800           //   add r1, r1, ip
1801           {
1802             CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1803             (this->*instruction)(cond,
1804                                  size,
1805                                  rd,
1806                                  MemOperand(rn, load_store_offset, PostIndex));
1807           }
1808           {
1809             CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
1810             add(cond, rn, rn, add_offset);
1811           }
1812           return;
1813         }
1814         break;
1815     }
1816   } else if (operand.IsPlainRegister()) {
1817     const Register& rn = operand.GetBaseRegister();
1818     AddrMode addrmode = operand.GetAddrMode();
1819     const Register& rm = operand.GetOffsetRegister();
1820     if (rm.IsPC()) {
1821       VIXL_ABORT_WITH_MSG(
1822           "The MacroAssembler does not convert loads and stores with a PC "
1823           "offset register.\n");
1824     }
1825     if (rn.IsPC()) {
1826       if (addrmode == Offset) {
1827         if (IsUsingT32()) {
1828           VIXL_ABORT_WITH_MSG(
1829               "The MacroAssembler does not convert loads and stores with a PC "
1830               "base register for T32.\n");
1831         }
1832       } else {
1833         VIXL_ABORT_WITH_MSG(
1834             "The MacroAssembler does not convert loads and stores with a PC "
1835             "base register in pre-index or post-index mode.\n");
1836       }
1837     }
1838     switch (addrmode) {
1839       case PreIndex:
1840         // Avoid the unpredictable case 'str r0, [r0, imm]!'
1841         if (!rn.Is(rd)) {
1842           // Pre-Indexed case:
1843           // ldr r0, [r1, r2]! will translate into
1844           //   add r1, r1, r2
1845           //   ldr r0, [r1]
1846           {
1847             CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1848             if (operand.GetSign().IsPlus()) {
1849               add(cond, rn, rn, rm);
1850             } else {
1851               sub(cond, rn, rn, rm);
1852             }
1853           }
1854           {
1855             CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1856             (this->*instruction)(cond, size, rd, MemOperand(rn, Offset));
1857           }
1858           return;
1859         }
1860         break;
1861       case Offset: {
1862         UseScratchRegisterScope temps(this);
1863         // Allow using the destination as a scratch register if this is not a
1864         // store.
1865         // Avoid using PC as a temporary as this has side-effects.
1866         if ((type != kStr) && (type != kStrb) && (type != kStrh) &&
1867             !rd.IsPC()) {
1868           temps.Include(rd);
1869         }
1870         Register scratch = temps.Acquire();
1871         // Offset case:
1872         // ldr r0, [r1, r2] will translate into
1873         //   add r0, r1, r2
1874         //   ldr r0, [r0]
1875         {
1876           CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1877           if (operand.GetSign().IsPlus()) {
1878             add(cond, scratch, rn, rm);
1879           } else {
1880             sub(cond, scratch, rn, rm);
1881           }
1882         }
1883         {
1884           CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1885           (this->*instruction)(cond, size, rd, MemOperand(scratch, Offset));
1886         }
1887         return;
1888       }
1889       case PostIndex:
1890         // Avoid the unpredictable case 'ldr r0, [r0], imm'
1891         if (!rn.Is(rd)) {
1892           // Post-indexed case:
1893           // ldr r0. [r1], r2 will translate into
1894           //   ldr r0, [r1]
1895           //   add r1, r1, r2
1896           {
1897             CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1898             (this->*instruction)(cond, size, rd, MemOperand(rn, Offset));
1899           }
1900           {
1901             CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1902             if (operand.GetSign().IsPlus()) {
1903               add(cond, rn, rn, rm);
1904             } else {
1905               sub(cond, rn, rn, rm);
1906             }
1907           }
1908           return;
1909         }
1910         break;
1911     }
1912   }
1913   Assembler::Delegate(type, instruction, cond, size, rd, operand);
1914 }
1915 
1916 
Delegate(InstructionType type,InstructionCondRRMop instruction,Condition cond,Register rt,Register rt2,const MemOperand & operand)1917 void MacroAssembler::Delegate(InstructionType type,
1918                               InstructionCondRRMop instruction,
1919                               Condition cond,
1920                               Register rt,
1921                               Register rt2,
1922                               const MemOperand& operand) {
1923   if ((type == kLdaexd) || (type == kLdrexd) || (type == kStlex) ||
1924       (type == kStlexb) || (type == kStlexh) || (type == kStrex) ||
1925       (type == kStrexb) || (type == kStrexh)) {
1926     UnimplementedDelegate(type);
1927     return;
1928   }
1929 
1930   VIXL_ASSERT((type == kLdrd) || (type == kStrd));
1931 
1932   CONTEXT_SCOPE;
1933 
1934   // TODO: Should we allow these cases?
1935   if (IsUsingA32()) {
1936     // The first register needs to be even.
1937     if ((rt.GetCode() & 1) != 0) {
1938       UnimplementedDelegate(type);
1939       return;
1940     }
1941     // Registers need to be adjacent.
1942     if (((rt.GetCode() + 1) % kNumberOfRegisters) != rt2.GetCode()) {
1943       UnimplementedDelegate(type);
1944       return;
1945     }
1946     // LDRD lr, pc [...] is not allowed.
1947     if (rt.Is(lr)) {
1948       UnimplementedDelegate(type);
1949       return;
1950     }
1951   }
1952 
1953   if (operand.IsImmediate()) {
1954     const Register& rn = operand.GetBaseRegister();
1955     AddrMode addrmode = operand.GetAddrMode();
1956     int32_t offset = operand.GetOffsetImmediate();
1957     uint32_t extra_offset_mask = GetOffsetMask(type, addrmode);
1958     // Try to maximize the offset used by the MemOperand (load_store_offset).
1959     // Add the part which can't be used by the MemOperand (add_offset).
1960     uint32_t load_store_offset = offset & extra_offset_mask;
1961     uint32_t add_offset = offset & ~extra_offset_mask;
1962     if ((add_offset != 0) &&
1963         (IsModifiedImmediate(offset) || IsModifiedImmediate(-offset))) {
1964       load_store_offset = 0;
1965       add_offset = offset;
1966     }
1967     switch (addrmode) {
1968       case PreIndex: {
1969         // Allow using the destinations as a scratch registers if possible.
1970         UseScratchRegisterScope temps(this);
1971         if (type == kLdrd) {
1972           if (!rt.Is(rn)) temps.Include(rt);
1973           if (!rt2.Is(rn)) temps.Include(rt2);
1974         }
1975 
1976         // Pre-Indexed case:
1977         // ldrd r0, r1, [r2, 12345]! will translate into
1978         //   add r2, 12345
1979         //   ldrd r0, r1, [r2]
1980         {
1981           CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
1982           add(cond, rn, rn, add_offset);
1983         }
1984         {
1985           CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
1986           (this->*instruction)(cond,
1987                                rt,
1988                                rt2,
1989                                MemOperand(rn, load_store_offset, PreIndex));
1990         }
1991         return;
1992       }
1993       case Offset: {
1994         UseScratchRegisterScope temps(this);
1995         // Allow using the destinations as a scratch registers if possible.
1996         if (type == kLdrd) {
1997           if (!rt.Is(rn)) temps.Include(rt);
1998           if (!rt2.Is(rn)) temps.Include(rt2);
1999         }
2000         Register scratch = temps.Acquire();
2001         // Offset case:
2002         // ldrd r0, r1, [r2, 12345] will translate into
2003         //   add r0, r2, 12345
2004         //   ldrd r0, r1, [r0]
2005         {
2006           CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
2007           add(cond, scratch, rn, add_offset);
2008         }
2009         {
2010           CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
2011           (this->*instruction)(cond,
2012                                rt,
2013                                rt2,
2014                                MemOperand(scratch, load_store_offset));
2015         }
2016         return;
2017       }
2018       case PostIndex:
2019         // Avoid the unpredictable case 'ldrd r0, r1, [r0], imm'
2020         if (!rn.Is(rt) && !rn.Is(rt2)) {
2021           // Post-indexed case:
2022           // ldrd r0, r1, [r2], imm32 will translate into
2023           //   ldrd r0, r1, [r2]
2024           //   movw ip. imm32 & 0xffffffff
2025           //   movt ip, imm32 >> 16
2026           //   add r2, ip
2027           {
2028             CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
2029             (this->*instruction)(cond,
2030                                  rt,
2031                                  rt2,
2032                                  MemOperand(rn, load_store_offset, PostIndex));
2033           }
2034           {
2035             CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
2036             add(cond, rn, rn, add_offset);
2037           }
2038           return;
2039         }
2040         break;
2041     }
2042   }
2043   if (operand.IsPlainRegister()) {
2044     const Register& rn = operand.GetBaseRegister();
2045     const Register& rm = operand.GetOffsetRegister();
2046     AddrMode addrmode = operand.GetAddrMode();
2047     switch (addrmode) {
2048       case PreIndex:
2049         // ldrd r0, r1, [r2, r3]! will translate into
2050         //   add r2, r3
2051         //   ldrd r0, r1, [r2]
2052         {
2053           CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
2054           if (operand.GetSign().IsPlus()) {
2055             add(cond, rn, rn, rm);
2056           } else {
2057             sub(cond, rn, rn, rm);
2058           }
2059         }
2060         {
2061           CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
2062           (this->*instruction)(cond, rt, rt2, MemOperand(rn, Offset));
2063         }
2064         return;
2065       case PostIndex:
2066         // ldrd r0, r1, [r2], r3 will translate into
2067         //   ldrd r0, r1, [r2]
2068         //   add r2, r3
2069         {
2070           CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
2071           (this->*instruction)(cond, rt, rt2, MemOperand(rn, Offset));
2072         }
2073         {
2074           CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
2075           if (operand.GetSign().IsPlus()) {
2076             add(cond, rn, rn, rm);
2077           } else {
2078             sub(cond, rn, rn, rm);
2079           }
2080         }
2081         return;
2082       case Offset: {
2083         UseScratchRegisterScope temps(this);
2084         // Allow using the destinations as a scratch registers if possible.
2085         if (type == kLdrd) {
2086           if (!rt.Is(rn)) temps.Include(rt);
2087           if (!rt2.Is(rn)) temps.Include(rt2);
2088         }
2089         Register scratch = temps.Acquire();
2090         // Offset case:
2091         // ldrd r0, r1, [r2, r3] will translate into
2092         //   add r0, r2, r3
2093         //   ldrd r0, r1, [r0]
2094         {
2095           CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
2096           if (operand.GetSign().IsPlus()) {
2097             add(cond, scratch, rn, rm);
2098           } else {
2099             sub(cond, scratch, rn, rm);
2100           }
2101         }
2102         {
2103           CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
2104           (this->*instruction)(cond, rt, rt2, MemOperand(scratch, Offset));
2105         }
2106         return;
2107       }
2108     }
2109   }
2110   Assembler::Delegate(type, instruction, cond, rt, rt2, operand);
2111 }
2112 
2113 
Delegate(InstructionType type,InstructionCondDtSMop instruction,Condition cond,DataType dt,SRegister rd,const MemOperand & operand)2114 void MacroAssembler::Delegate(InstructionType type,
2115                               InstructionCondDtSMop instruction,
2116                               Condition cond,
2117                               DataType dt,
2118                               SRegister rd,
2119                               const MemOperand& operand) {
2120   CONTEXT_SCOPE;
2121   if (operand.IsImmediate()) {
2122     const Register& rn = operand.GetBaseRegister();
2123     AddrMode addrmode = operand.GetAddrMode();
2124     int32_t offset = operand.GetOffsetImmediate();
2125     VIXL_ASSERT(((offset > 0) && operand.GetSign().IsPlus()) ||
2126                 ((offset < 0) && operand.GetSign().IsMinus()) || (offset == 0));
2127     if (rn.IsPC()) {
2128       VIXL_ABORT_WITH_MSG(
2129           "The MacroAssembler does not convert vldr or vstr with a PC base "
2130           "register.\n");
2131     }
2132     switch (addrmode) {
2133       case PreIndex:
2134         // Pre-Indexed case:
2135         // vldr.32 s0, [r1, 12345]! will translate into
2136         //   add r1, 12345
2137         //   vldr.32 s0, [r1]
2138         if (offset != 0) {
2139           CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
2140           add(cond, rn, rn, offset);
2141         }
2142         {
2143           CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
2144           (this->*instruction)(cond, dt, rd, MemOperand(rn, Offset));
2145         }
2146         return;
2147       case Offset: {
2148         UseScratchRegisterScope temps(this);
2149         Register scratch = temps.Acquire();
2150         // Offset case:
2151         // vldr.32 s0, [r1, 12345] will translate into
2152         //   add ip, r1, 12345
2153         //   vldr.32 s0, [ip]
2154         {
2155           VIXL_ASSERT(offset != 0);
2156           CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
2157           add(cond, scratch, rn, offset);
2158         }
2159         {
2160           CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
2161           (this->*instruction)(cond, dt, rd, MemOperand(scratch, Offset));
2162         }
2163         return;
2164       }
2165       case PostIndex:
2166         // Post-indexed case:
2167         // vldr.32 s0, [r1], imm32 will translate into
2168         //   vldr.32 s0, [r1]
2169         //   movw ip. imm32 & 0xffffffff
2170         //   movt ip, imm32 >> 16
2171         //   add r1, ip
2172         {
2173           CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
2174           (this->*instruction)(cond, dt, rd, MemOperand(rn, Offset));
2175         }
2176         if (offset != 0) {
2177           CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
2178           add(cond, rn, rn, offset);
2179         }
2180         return;
2181     }
2182   }
2183   Assembler::Delegate(type, instruction, cond, dt, rd, operand);
2184 }
2185 
2186 
Delegate(InstructionType type,InstructionCondDtDMop instruction,Condition cond,DataType dt,DRegister rd,const MemOperand & operand)2187 void MacroAssembler::Delegate(InstructionType type,
2188                               InstructionCondDtDMop instruction,
2189                               Condition cond,
2190                               DataType dt,
2191                               DRegister rd,
2192                               const MemOperand& operand) {
2193   CONTEXT_SCOPE;
2194   if (operand.IsImmediate()) {
2195     const Register& rn = operand.GetBaseRegister();
2196     AddrMode addrmode = operand.GetAddrMode();
2197     int32_t offset = operand.GetOffsetImmediate();
2198     VIXL_ASSERT(((offset > 0) && operand.GetSign().IsPlus()) ||
2199                 ((offset < 0) && operand.GetSign().IsMinus()) || (offset == 0));
2200     if (rn.IsPC()) {
2201       VIXL_ABORT_WITH_MSG(
2202           "The MacroAssembler does not convert vldr or vstr with a PC base "
2203           "register.\n");
2204     }
2205     switch (addrmode) {
2206       case PreIndex:
2207         // Pre-Indexed case:
2208         // vldr.64 d0, [r1, 12345]! will translate into
2209         //   add r1, 12345
2210         //   vldr.64 d0, [r1]
2211         if (offset != 0) {
2212           CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
2213           add(cond, rn, rn, offset);
2214         }
2215         {
2216           CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
2217           (this->*instruction)(cond, dt, rd, MemOperand(rn, Offset));
2218         }
2219         return;
2220       case Offset: {
2221         UseScratchRegisterScope temps(this);
2222         Register scratch = temps.Acquire();
2223         // Offset case:
2224         // vldr.64 d0, [r1, 12345] will translate into
2225         //   add ip, r1, 12345
2226         //   vldr.32 s0, [ip]
2227         {
2228           VIXL_ASSERT(offset != 0);
2229           CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
2230           add(cond, scratch, rn, offset);
2231         }
2232         {
2233           CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
2234           (this->*instruction)(cond, dt, rd, MemOperand(scratch, Offset));
2235         }
2236         return;
2237       }
2238       case PostIndex:
2239         // Post-indexed case:
2240         // vldr.64 d0. [r1], imm32 will translate into
2241         //   vldr.64 d0, [r1]
2242         //   movw ip. imm32 & 0xffffffff
2243         //   movt ip, imm32 >> 16
2244         //   add r1, ip
2245         {
2246           CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
2247           (this->*instruction)(cond, dt, rd, MemOperand(rn, Offset));
2248         }
2249         if (offset != 0) {
2250           CodeBufferCheckScope scope(this, 3 * kMaxInstructionSizeInBytes);
2251           add(cond, rn, rn, offset);
2252         }
2253         return;
2254     }
2255   }
2256   Assembler::Delegate(type, instruction, cond, dt, rd, operand);
2257 }
2258 
2259 
Delegate(InstructionType type,InstructionCondMsrOp instruction,Condition cond,MaskedSpecialRegister spec_reg,const Operand & operand)2260 void MacroAssembler::Delegate(InstructionType type,
2261                               InstructionCondMsrOp instruction,
2262                               Condition cond,
2263                               MaskedSpecialRegister spec_reg,
2264                               const Operand& operand) {
2265   USE(type);
2266   VIXL_ASSERT(type == kMsr);
2267   if (operand.IsImmediate()) {
2268     UseScratchRegisterScope temps(this);
2269     Register scratch = temps.Acquire();
2270     {
2271       CodeBufferCheckScope scope(this, 2 * kMaxInstructionSizeInBytes);
2272       mov(cond, scratch, operand);
2273     }
2274     CodeBufferCheckScope scope(this, kMaxInstructionSizeInBytes);
2275     msr(cond, spec_reg, scratch);
2276     return;
2277   }
2278   Assembler::Delegate(type, instruction, cond, spec_reg, operand);
2279 }
2280 
2281 
Delegate(InstructionType type,InstructionCondDtDL instruction,Condition cond,DataType dt,DRegister rd,Location * location)2282 void MacroAssembler::Delegate(InstructionType type,
2283                               InstructionCondDtDL instruction,
2284                               Condition cond,
2285                               DataType dt,
2286                               DRegister rd,
2287                               Location* location) {
2288   VIXL_ASSERT(type == kVldr);
2289 
2290   CONTEXT_SCOPE;
2291 
2292   if (location->IsBound()) {
2293     CodeBufferCheckScope scope(this, 5 * kMaxInstructionSizeInBytes);
2294     UseScratchRegisterScope temps(this);
2295     Register scratch = temps.Acquire();
2296     uint32_t mask = GetOffsetMask(type, Offset);
2297     vldr(dt, rd, MemOperandComputationHelper(cond, scratch, location, mask));
2298     return;
2299   }
2300 
2301   Assembler::Delegate(type, instruction, cond, dt, rd, location);
2302 }
2303 
2304 
Delegate(InstructionType type,InstructionCondDtSL instruction,Condition cond,DataType dt,SRegister rd,Location * location)2305 void MacroAssembler::Delegate(InstructionType type,
2306                               InstructionCondDtSL instruction,
2307                               Condition cond,
2308                               DataType dt,
2309                               SRegister rd,
2310                               Location* location) {
2311   VIXL_ASSERT(type == kVldr);
2312 
2313   CONTEXT_SCOPE;
2314 
2315   if (location->IsBound()) {
2316     CodeBufferCheckScope scope(this, 5 * kMaxInstructionSizeInBytes);
2317     UseScratchRegisterScope temps(this);
2318     Register scratch = temps.Acquire();
2319     uint32_t mask = GetOffsetMask(type, Offset);
2320     vldr(dt, rd, MemOperandComputationHelper(cond, scratch, location, mask));
2321     return;
2322   }
2323 
2324   Assembler::Delegate(type, instruction, cond, dt, rd, location);
2325 }
2326 
2327 
2328 #undef CONTEXT_SCOPE
2329 #undef TOSTRING
2330 #undef STRINGIFY
2331 
2332 // Start of generated code.
2333 // End of generated code.
2334 }  // namespace aarch32
2335 }  // namespace vixl
2336