• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4 //
5 // This is forked from Dart revision df52deea9f25690eb8b66c5995da92b70f7ac1fe
6 // Please update the (git) revision if we merge changes from Dart.
7 // https://code.google.com/p/dart/wiki/GettingTheSource
8 
9 #include "vm/globals.h"  // NOLINT
10 #if defined(TARGET_ARCH_ARM)
11 
12 #include "vm/assembler.h"
13 #include "vm/cpu.h"
14 #include "vm/longjump.h"
15 #include "vm/runtime_entry.h"
16 #include "vm/simulator.h"
17 #include "vm/stack_frame.h"
18 #include "vm/stub_code.h"
19 
20 // An extra check since we are assuming the existence of /proc/cpuinfo below.
21 #if !defined(USING_SIMULATOR) && !defined(__linux__) && !defined(ANDROID)
22 #error ARM cross-compile only supported on Linux
23 #endif
24 
25 namespace dart {
26 
27 DECLARE_FLAG(bool, allow_absolute_addresses);
28 DEFINE_FLAG(bool, print_stop_message, true, "Print stop message.");
29 DECLARE_FLAG(bool, inline_alloc);
30 
31 #if 0
32 // Moved to encodeImmRegOffsetEnc3 in IceAssemblerARM32.cpp
33 uint32_t Address::encoding3() const {
34   if (kind_ == Immediate) {
35     uint32_t offset = encoding_ & kOffset12Mask;
36     ASSERT(offset < 256);
37     return (encoding_ & ~kOffset12Mask) | B22 |
38            ((offset & 0xf0) << 4) | (offset & 0xf);
39   }
40   ASSERT(kind_ == IndexRegister);
41   return encoding_;
42 }
43 #endif
44 
vencoding() const45 uint32_t Address::vencoding() const {
46   ASSERT(kind_ == Immediate);
47   uint32_t offset = encoding_ & kOffset12Mask;
48   ASSERT(offset < (1 << 10));  // In the range 0 to +1020.
49   ASSERT(Utils::IsAligned(offset, 4));  // Multiple of 4.
50   int mode = encoding_ & ((8|4|1) << 21);
51   ASSERT((mode == Offset) || (mode == NegOffset));
52   uint32_t vencoding = (encoding_ & (0xf << kRnShift)) | (offset >> 2);
53   if (mode == Offset) {
54     vencoding |= 1 << 23;
55   }
56   return vencoding;
57 }
58 
59 
InitializeMemoryWithBreakpoints(uword data,intptr_t length)60 void Assembler::InitializeMemoryWithBreakpoints(uword data, intptr_t length) {
61   ASSERT(Utils::IsAligned(data, 4));
62   ASSERT(Utils::IsAligned(length, 4));
63   const uword end = data + length;
64   while (data < end) {
65     *reinterpret_cast<int32_t*>(data) = Instr::kBreakPointInstruction;
66     data += 4;
67   }
68 }
69 
70 
Emit(int32_t value)71 void Assembler::Emit(int32_t value) {
72   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
73   buffer_.Emit<int32_t>(value);
74 }
75 
76 #if 0
77 // Moved to ARM32::AssemblerARM32::emitType01()
78 void Assembler::EmitType01(Condition cond,
79                            int type,
80                            Opcode opcode,
81                            int set_cc,
82                            Register rn,
83                            Register rd,
84                            Operand o) {
85   ASSERT(rd != kNoRegister);
86   ASSERT(cond != kNoCondition);
87   int32_t encoding = static_cast<int32_t>(cond) << kConditionShift |
88                      type << kTypeShift |
89                      static_cast<int32_t>(opcode) << kOpcodeShift |
90                      set_cc << kSShift |
91                      static_cast<int32_t>(rn) << kRnShift |
92                      static_cast<int32_t>(rd) << kRdShift |
93                      o.encoding();
94   Emit(encoding);
95 }
96 
97 // Moved to ARM32::AssemblerARM32::emitType05()
98 void Assembler::EmitType5(Condition cond, int32_t offset, bool link) {
99   ASSERT(cond != kNoCondition);
100   int32_t encoding = static_cast<int32_t>(cond) << kConditionShift |
101                      5 << kTypeShift |
102                      (link ? 1 : 0) << kLinkShift;
103   Emit(Assembler::EncodeBranchOffset(offset, encoding));
104 }
105 
106 // Moved to ARM32::AssemblerARM32::emitMemOp()
107 void Assembler::EmitMemOp(Condition cond,
108                           bool load,
109                           bool byte,
110                           Register rd,
111                           Address ad) {
112   ASSERT(rd != kNoRegister);
113   ASSERT(cond != kNoCondition);
114   int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
115                      B26 | (ad.kind() == Address::Immediate ? 0 : B25) |
116                      (load ? L : 0) |
117                      (byte ? B : 0) |
118                      (static_cast<int32_t>(rd) << kRdShift) |
119                      ad.encoding();
120   Emit(encoding);
121 }
122 
123 // Moved to AssemblerARM32::emitMemOpEnc3();
124 void Assembler::EmitMemOpAddressMode3(Condition cond,
125                                       int32_t mode,
126                                       Register rd,
127                                       Address ad) {
128   ASSERT(rd != kNoRegister);
129   ASSERT(cond != kNoCondition);
130   int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
131                      mode |
132                      (static_cast<int32_t>(rd) << kRdShift) |
133                      ad.encoding3();
134   Emit(encoding);
135 }
136 
137 // Moved to ARM32::AssemblerARM32::emitMuliMemOp()
138 void Assembler::EmitMultiMemOp(Condition cond,
139                                BlockAddressMode am,
140                                bool load,
141                                Register base,
142                                RegList regs) {
143   ASSERT(base != kNoRegister);
144   ASSERT(cond != kNoCondition);
145   int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
146                      B27 |
147                      am |
148                      (load ? L : 0) |
149                      (static_cast<int32_t>(base) << kRnShift) |
150                      regs;
151   Emit(encoding);
152 }
153 #endif
154 
EmitShiftImmediate(Condition cond,Shift opcode,Register rd,Register rm,Operand o)155 void Assembler::EmitShiftImmediate(Condition cond,
156                                    Shift opcode,
157                                    Register rd,
158                                    Register rm,
159                                    Operand o) {
160   ASSERT(cond != kNoCondition);
161   ASSERT(o.type() == 1);
162   int32_t encoding = static_cast<int32_t>(cond) << kConditionShift |
163                      static_cast<int32_t>(MOV) << kOpcodeShift |
164                      static_cast<int32_t>(rd) << kRdShift |
165                      o.encoding() << kShiftImmShift |
166                      static_cast<int32_t>(opcode) << kShiftShift |
167                      static_cast<int32_t>(rm);
168   Emit(encoding);
169 }
170 
171 
EmitShiftRegister(Condition cond,Shift opcode,Register rd,Register rm,Operand o)172 void Assembler::EmitShiftRegister(Condition cond,
173                                   Shift opcode,
174                                   Register rd,
175                                   Register rm,
176                                   Operand o) {
177   ASSERT(cond != kNoCondition);
178   ASSERT(o.type() == 0);
179   int32_t encoding = static_cast<int32_t>(cond) << kConditionShift |
180                      static_cast<int32_t>(MOV) << kOpcodeShift |
181                      static_cast<int32_t>(rd) << kRdShift |
182                      o.encoding() << kShiftRegisterShift |
183                      static_cast<int32_t>(opcode) << kShiftShift |
184                      B4 |
185                      static_cast<int32_t>(rm);
186   Emit(encoding);
187 }
188 
189 
190 #if 0
191 // Moved to ARM32::AssemblerARM32::and_()
192 void Assembler::and_(Register rd, Register rn, Operand o, Condition cond) {
193   EmitType01(cond, o.type(), AND, 0, rn, rd, o);
194 }
195 
196 // Moved to ARM32::AssemberARM32::eor()
197 void Assembler::eor(Register rd, Register rn, Operand o, Condition cond) {
198   EmitType01(cond, o.type(), EOR, 0, rn, rd, o);
199 }
200 
201 // Moved to ARM32::AssemberARM32::sub()
202 void Assembler::sub(Register rd, Register rn, Operand o, Condition cond) {
203   EmitType01(cond, o.type(), SUB, 0, rn, rd, o);
204 }
205 
206 // Moved to ARM32::AssemberARM32::rsb()
207 void Assembler::rsb(Register rd, Register rn, Operand o, Condition cond) {
208   EmitType01(cond, o.type(), RSB, 0, rn, rd, o);
209 }
210 
211 // Moved to ARM32::AssemberARM32::rsb()
212 void Assembler::rsbs(Register rd, Register rn, Operand o, Condition cond) {
213   EmitType01(cond, o.type(), RSB, 1, rn, rd, o);
214 }
215 
216 // Moved to ARM32::AssemberARM32::add()
217 void Assembler::add(Register rd, Register rn, Operand o, Condition cond) {
218   EmitType01(cond, o.type(), ADD, 0, rn, rd, o);
219 }
220 
221 // Moved to ARM32::AssemberARM32::add()
222 void Assembler::adds(Register rd, Register rn, Operand o, Condition cond) {
223   EmitType01(cond, o.type(), ADD, 1, rn, rd, o);
224 }
225 
226 // Moved to ARM32::AssemberARM32::sub()
227 void Assembler::subs(Register rd, Register rn, Operand o, Condition cond) {
228   EmitType01(cond, o.type(), SUB, 1, rn, rd, o);
229 }
230 
231 // Moved to ARM32::AssemberARM32::adc()
232 void Assembler::adc(Register rd, Register rn, Operand o, Condition cond) {
233   EmitType01(cond, o.type(), ADC, 0, rn, rd, o);
234 }
235 
236 // Moved to ARM32::AssemberARM32::adc()
237 void Assembler::adcs(Register rd, Register rn, Operand o, Condition cond) {
238   EmitType01(cond, o.type(), ADC, 1, rn, rd, o);
239 }
240 #endif
241 
sbc(Register rd,Register rn,Operand o,Condition cond)242 void Assembler::sbc(Register rd, Register rn, Operand o, Condition cond) {
243   EmitType01(cond, o.type(), SBC, 0, rn, rd, o);
244 }
245 
246 
sbcs(Register rd,Register rn,Operand o,Condition cond)247 void Assembler::sbcs(Register rd, Register rn, Operand o, Condition cond) {
248   EmitType01(cond, o.type(), SBC, 1, rn, rd, o);
249 }
250 
251 #if 0
252 // Moved to ARM32::AssemblerARM32::rsc()f
253 void Assembler::rsc(Register rd, Register rn, Operand o, Condition cond) {
254   EmitType01(cond, o.type(), RSC, 0, rn, rd, o);
255 }
256 
257 // Moved to ARM32::AssemblerARM32::tst()
258 void Assembler::tst(Register rn, Operand o, Condition cond) {
259   EmitType01(cond, o.type(), TST, 1, rn, R0, o);
260 }
261 #endif
262 
teq(Register rn,Operand o,Condition cond)263 void Assembler::teq(Register rn, Operand o, Condition cond) {
264   EmitType01(cond, o.type(), TEQ, 1, rn, R0, o);
265 }
266 
267 #if 0
268 // Moved to ARM32::AssemblerARM32::cmp()
269 void Assembler::cmp(Register rn, Operand o, Condition cond) {
270   EmitType01(cond, o.type(), CMP, 1, rn, R0, o);
271 }
272 
273 // Moved to ARM32::AssemblerARM32::cmn()
274 void Assembler::cmn(Register rn, Operand o, Condition cond) {
275   EmitType01(cond, o.type(), CMN, 1, rn, R0, o);
276 }
277 
278 // Moved to ARM32::AssemberARM32::orr()
279 void Assembler::orr(Register rd, Register rn, Operand o, Condition cond) {
280   EmitType01(cond, o.type(), ORR, 0, rn, rd, o);
281 }
282 
283 // Moved to ARM32::AssemberARM32::orr()
284 void Assembler::orrs(Register rd, Register rn, Operand o, Condition cond) {
285   EmitType01(cond, o.type(), ORR, 1, rn, rd, o);
286 }
287 
288 // Moved to ARM32::AssemblerARM32::mov()
289 // TODO(kschimpf) other forms of move.
290 void Assembler::mov(Register rd, Operand o, Condition cond) {
291   EmitType01(cond, o.type(), MOV, 0, R0, rd, o);
292 }
293 #endif
294 
movs(Register rd,Operand o,Condition cond)295 void Assembler::movs(Register rd, Operand o, Condition cond) {
296   EmitType01(cond, o.type(), MOV, 1, R0, rd, o);
297 }
298 
299 
300 #if 0
301 // Moved to ARM32::AssemblerARM32::bic()
302 void Assembler::bic(Register rd, Register rn, Operand o, Condition cond) {
303   EmitType01(cond, o.type(), BIC, 0, rn, rd, o);
304 }
305 
306 // Moved to ARM32::AssemblerARM32::bic()
307 void Assembler::bics(Register rd, Register rn, Operand o, Condition cond) {
308   EmitType01(cond, o.type(), BIC, 1, rn, rd, o);
309 }
310 
311 // Moved to ARM32::AssemblerARM32::mvn()
312 void Assembler::mvn(Register rd, Operand o, Condition cond) {
313   EmitType01(cond, o.type(), MVN, 0, R0, rd, o);
314 }
315 
316 // Moved to ARM32::AssemblerARM32::mvn()
317 void Assembler::mvns(Register rd, Operand o, Condition cond) {
318   EmitType01(cond, o.type(), MVN, 1, R0, rd, o);
319 }
320 
321 // Moved to ARM32::AssemblerARM32::clz()
322 void Assembler::clz(Register rd, Register rm, Condition cond) {
323   ASSERT(rd != kNoRegister);
324   ASSERT(rm != kNoRegister);
325   ASSERT(cond != kNoCondition);
326   ASSERT(rd != PC);
327   ASSERT(rm != PC);
328   int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
329                      B24 | B22 | B21 | (0xf << 16) |
330                      (static_cast<int32_t>(rd) << kRdShift) |
331                      (0xf << 8) | B4 | static_cast<int32_t>(rm);
332   Emit(encoding);
333 }
334 
335 // Moved to ARM32::AssemblerARM32::movw()
336 void Assembler::movw(Register rd, uint16_t imm16, Condition cond) {
337   ASSERT(cond != kNoCondition);
338   int32_t encoding = static_cast<int32_t>(cond) << kConditionShift |
339                      B25 | B24 | ((imm16 >> 12) << 16) |
340                      static_cast<int32_t>(rd) << kRdShift | (imm16 & 0xfff);
341   Emit(encoding);
342 }
343 
344 
345 // Moved to ARM32::AssemblerARM32::movt()
346 void Assembler::movt(Register rd, uint16_t imm16, Condition cond) {
347   ASSERT(cond != kNoCondition);
348   int32_t encoding = static_cast<int32_t>(cond) << kConditionShift |
349                      B25 | B24 | B22 | ((imm16 >> 12) << 16) |
350                      static_cast<int32_t>(rd) << kRdShift | (imm16 & 0xfff);
351   Emit(encoding);
352 }
353 
354 // Moved to ARM32::AssemblerARM32::emitMulOp()
355 void Assembler::EmitMulOp(Condition cond, int32_t opcode,
356                           Register rd, Register rn,
357                           Register rm, Register rs) {
358   ASSERT(rd != kNoRegister);
359   ASSERT(rn != kNoRegister);
360   ASSERT(rm != kNoRegister);
361   ASSERT(rs != kNoRegister);
362   ASSERT(cond != kNoCondition);
363   int32_t encoding = opcode |
364       (static_cast<int32_t>(cond) << kConditionShift) |
365       (static_cast<int32_t>(rn) << kRnShift) |
366       (static_cast<int32_t>(rd) << kRdShift) |
367       (static_cast<int32_t>(rs) << kRsShift) |
368       B7 | B4 |
369       (static_cast<int32_t>(rm) << kRmShift);
370   Emit(encoding);
371 }
372 
373 // Moved to ARM32::AssemblerARM32::mul()
374 void Assembler::mul(Register rd, Register rn, Register rm, Condition cond) {
375   // Assembler registers rd, rn, rm are encoded as rn, rm, rs.
376   EmitMulOp(cond, 0, R0, rd, rn, rm);
377 }
378 #endif
379 
380 // Like mul, but sets condition flags.
muls(Register rd,Register rn,Register rm,Condition cond)381 void Assembler::muls(Register rd, Register rn, Register rm, Condition cond) {
382   EmitMulOp(cond, B20, R0, rd, rn, rm);
383 }
384 
385 #if 0
386 // Moved to ARM32::AssemblerARM32::mla()
387 void Assembler::mla(Register rd, Register rn,
388                     Register rm, Register ra, Condition cond) {
389   // rd <- ra + rn * rm.
390   // Assembler registers rd, rn, rm, ra are encoded as rn, rm, rs, rd.
391   EmitMulOp(cond, B21, ra, rd, rn, rm);
392 }
393 
394 // Moved to ARM32::AssemblerARM32::mla()
395 void Assembler::mls(Register rd, Register rn,
396                     Register rm, Register ra, Condition cond) {
397   // rd <- ra - rn * rm.
398   if (TargetCPUFeatures::arm_version() == ARMv7) {
399     // Assembler registers rd, rn, rm, ra are encoded as rn, rm, rs, rd.
400     EmitMulOp(cond, B22 | B21, ra, rd, rn, rm);
401   } else {
402     mul(IP, rn, rm, cond);
403     sub(rd, ra, Operand(IP), cond);
404   }
405 }
406 #endif
407 
smull(Register rd_lo,Register rd_hi,Register rn,Register rm,Condition cond)408 void Assembler::smull(Register rd_lo, Register rd_hi,
409                       Register rn, Register rm, Condition cond) {
410   // Assembler registers rd_lo, rd_hi, rn, rm are encoded as rd, rn, rm, rs.
411   EmitMulOp(cond, B23 | B22, rd_lo, rd_hi, rn, rm);
412 }
413 
414 #if 0
415 // Moved to ARM32::AssemblerARM32::umull()
416 void Assembler::umull(Register rd_lo, Register rd_hi,
417                       Register rn, Register rm, Condition cond) {
418   // Assembler registers rd_lo, rd_hi, rn, rm are encoded as rd, rn, rm, rs.
419   EmitMulOp(cond, B23, rd_lo, rd_hi, rn, rm);
420 }
421 #endif
422 
umlal(Register rd_lo,Register rd_hi,Register rn,Register rm,Condition cond)423 void Assembler::umlal(Register rd_lo, Register rd_hi,
424                       Register rn, Register rm, Condition cond) {
425   // Assembler registers rd_lo, rd_hi, rn, rm are encoded as rd, rn, rm, rs.
426   EmitMulOp(cond, B23 | B21, rd_lo, rd_hi, rn, rm);
427 }
428 
429 
umaal(Register rd_lo,Register rd_hi,Register rn,Register rm)430 void Assembler::umaal(Register rd_lo, Register rd_hi,
431                       Register rn, Register rm) {
432   ASSERT(rd_lo != IP);
433   ASSERT(rd_hi != IP);
434   ASSERT(rn != IP);
435   ASSERT(rm != IP);
436   if (TargetCPUFeatures::arm_version() != ARMv5TE) {
437     // Assembler registers rd_lo, rd_hi, rn, rm are encoded as rd, rn, rm, rs.
438     EmitMulOp(AL, B22, rd_lo, rd_hi, rn, rm);
439   } else {
440     mov(IP, Operand(0));
441     umlal(rd_lo, IP, rn, rm);
442     adds(rd_lo, rd_lo, Operand(rd_hi));
443     adc(rd_hi, IP, Operand(0));
444   }
445 }
446 
447 
448 #if 0
449 // Moved to ARM32::AssemblerARM32::emitDivOp()
450 void Assembler::EmitDivOp(Condition cond, int32_t opcode,
451                           Register rd, Register rn, Register rm) {
452   ASSERT(TargetCPUFeatures::integer_division_supported());
453   ASSERT(rd != kNoRegister);
454   ASSERT(rn != kNoRegister);
455   ASSERT(rm != kNoRegister);
456   ASSERT(cond != kNoCondition);
457   int32_t encoding = opcode |
458     (static_cast<int32_t>(cond) << kConditionShift) |
459     (static_cast<int32_t>(rn) << kDivRnShift) |
460     (static_cast<int32_t>(rd) << kDivRdShift) |
461       // TODO(kschimpf): Why not also: B15 | B14 | B13 | B12?
462     B26 | B25 | B24 | B20 | B4 |
463     (static_cast<int32_t>(rm) << kDivRmShift);
464   Emit(encoding);
465 }
466 
467 // Moved to ARM32::AssemblerARM32::sdiv()
468 void Assembler::sdiv(Register rd, Register rn, Register rm, Condition cond) {
469   EmitDivOp(cond, 0, rd, rn, rm);
470 }
471 
472 // Moved to ARM32::AssemblerARM32::udiv()
473 void Assembler::udiv(Register rd, Register rn, Register rm, Condition cond) {
474   EmitDivOp(cond, B21 , rd, rn, rm);
475 }
476 
477 // Moved to ARM32::AssemblerARM32::ldr()
478 void Assembler::ldr(Register rd, Address ad, Condition cond) {
479   EmitMemOp(cond, true, false, rd, ad);
480 }
481 
482 // Moved to ARM32::AssemblerARM32::str()
483 void Assembler::str(Register rd, Address ad, Condition cond) {
484   EmitMemOp(cond, false, false, rd, ad);
485 }
486 
487 // Moved to ARM32::AssemblerARM32::ldr()
488 void Assembler::ldrb(Register rd, Address ad, Condition cond) {
489   EmitMemOp(cond, true, true, rd, ad);
490 }
491 
492 // Moved to ARM32::AssemblerARM32::str()
493 void Assembler::strb(Register rd, Address ad, Condition cond) {
494   EmitMemOp(cond, false, true, rd, ad);
495 }
496 #endif
497 
ldrh(Register rd,Address ad,Condition cond)498 void Assembler::ldrh(Register rd, Address ad, Condition cond) {
499   EmitMemOpAddressMode3(cond, L | B7 | H | B4, rd, ad);
500 }
501 
502 
strh(Register rd,Address ad,Condition cond)503 void Assembler::strh(Register rd, Address ad, Condition cond) {
504   EmitMemOpAddressMode3(cond, B7 | H | B4, rd, ad);
505 }
506 
507 
ldrsb(Register rd,Address ad,Condition cond)508 void Assembler::ldrsb(Register rd, Address ad, Condition cond) {
509   EmitMemOpAddressMode3(cond, L | B7 | B6 | B4, rd, ad);
510 }
511 
512 
ldrsh(Register rd,Address ad,Condition cond)513 void Assembler::ldrsh(Register rd, Address ad, Condition cond) {
514   EmitMemOpAddressMode3(cond, L | B7 | B6 | H | B4, rd, ad);
515 }
516 
517 
ldrd(Register rd,Register rn,int32_t offset,Condition cond)518 void Assembler::ldrd(Register rd, Register rn, int32_t offset, Condition cond) {
519   ASSERT((rd % 2) == 0);
520   if (TargetCPUFeatures::arm_version() == ARMv5TE) {
521     const Register rd2 = static_cast<Register>(static_cast<int32_t>(rd) + 1);
522     ldr(rd, Address(rn, offset), cond);
523     ldr(rd2, Address(rn, offset + kWordSize), cond);
524   } else {
525     EmitMemOpAddressMode3(cond, B7 | B6 | B4, rd, Address(rn, offset));
526   }
527 }
528 
529 
strd(Register rd,Register rn,int32_t offset,Condition cond)530 void Assembler::strd(Register rd, Register rn, int32_t offset, Condition cond) {
531   ASSERT((rd % 2) == 0);
532   if (TargetCPUFeatures::arm_version() == ARMv5TE) {
533     const Register rd2 = static_cast<Register>(static_cast<int32_t>(rd) + 1);
534     str(rd, Address(rn, offset), cond);
535     str(rd2, Address(rn, offset + kWordSize), cond);
536   } else {
537     EmitMemOpAddressMode3(cond, B7 | B6 | B5 | B4, rd, Address(rn, offset));
538   }
539 }
540 
541 #if 0
542 // Folded into ARM32::AssemblerARM32::popList(), since it is its only
543 // use (and doesn't implement ARM STM instruction).
544 void Assembler::ldm(BlockAddressMode am, Register base, RegList regs,
545                     Condition cond) {
546   ASSERT(regs != 0);
547   EmitMultiMemOp(cond, am, true, base, regs);
548 }
549 
550 // Folded into ARM32::AssemblerARM32::pushList(), since it is its only
551 // use (and doesn't implement ARM STM instruction).
552 void Assembler::stm(BlockAddressMode am, Register base, RegList regs,
553                     Condition cond) {
554   ASSERT(regs != 0);
555   EmitMultiMemOp(cond, am, false, base, regs);
556 }
557 
558 // Moved to ARM::AssemblerARM32::ldrex();
559 void Assembler::ldrex(Register rt, Register rn, Condition cond) {
560   ASSERT(TargetCPUFeatures::arm_version() != ARMv5TE);
561   ASSERT(rn != kNoRegister);
562   ASSERT(rt != kNoRegister);
563   ASSERT(cond != kNoCondition);
564   int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
565                      B24 |
566                      B23 |
567                      L   |
568                      (static_cast<int32_t>(rn) << kLdExRnShift) |
569                      (static_cast<int32_t>(rt) << kLdExRtShift) |
570                      B11 | B10 | B9 | B8 | B7 | B4 | B3 | B2 | B1 | B0;
571   Emit(encoding);
572 }
573 
574 // Moved to ARM::AssemblerARM32::strex();
575 void Assembler::strex(Register rd, Register rt, Register rn, Condition cond) {
576   ASSERT(TargetCPUFeatures::arm_version() != ARMv5TE);
577   ASSERT(rn != kNoRegister);
578   ASSERT(rd != kNoRegister);
579   ASSERT(rt != kNoRegister);
580   ASSERT(cond != kNoCondition);
581   int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
582                      B24 |
583                      B23 |
584                      (static_cast<int32_t>(rn) << kStrExRnShift) |
585                      (static_cast<int32_t>(rd) << kStrExRdShift) |
586                      B11 | B10 | B9 | B8 | B7 | B4 |
587                      (static_cast<int32_t>(rt) << kStrExRtShift);
588   Emit(encoding);
589 }
590 #endif
591 
clrex()592 void Assembler::clrex() {
593   ASSERT(TargetCPUFeatures::arm_version() != ARMv5TE);
594   int32_t encoding = (kSpecialCondition << kConditionShift) |
595                      B26 | B24 | B22 | B21 | B20 | (0xff << 12) | B4 | 0xf;
596   Emit(encoding);
597 }
598 
599 #if 0
600 // Moved to ARM32::AssemblerARM32::nop().
601 void Assembler::nop(Condition cond) {
602   ASSERT(cond != kNoCondition);
603   int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
604                      B25 | B24 | B21 | (0xf << 12);
605   Emit(encoding);
606 }
607 
608 // Moved to ARM32::AssemblerARM32::vmovsr().
609 void Assembler::vmovsr(SRegister sn, Register rt, Condition cond) {
610   ASSERT(TargetCPUFeatures::vfp_supported());
611   ASSERT(sn != kNoSRegister);
612   ASSERT(rt != kNoRegister);
613   ASSERT(rt != SP);
614   ASSERT(rt != PC);
615   ASSERT(cond != kNoCondition);
616   int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
617                      B27 | B26 | B25 |
618                      ((static_cast<int32_t>(sn) >> 1)*B16) |
619                      (static_cast<int32_t>(rt)*B12) | B11 | B9 |
620                      ((static_cast<int32_t>(sn) & 1)*B7) | B4;
621   Emit(encoding);
622 }
623 
624 // Moved to ARM32::AssemblerARM32::vmovrs().
625 void Assembler::vmovrs(Register rt, SRegister sn, Condition cond) {
626   ASSERT(TargetCPUFeatures::vfp_supported());
627   ASSERT(sn != kNoSRegister);
628   ASSERT(rt != kNoRegister);
629   ASSERT(rt != SP);
630   ASSERT(rt != PC);
631   ASSERT(cond != kNoCondition);
632   int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
633                      B27 | B26 | B25 | B20 |
634                      ((static_cast<int32_t>(sn) >> 1)*B16) |
635                      (static_cast<int32_t>(rt)*B12) | B11 | B9 |
636                      ((static_cast<int32_t>(sn) & 1)*B7) | B4;
637   Emit(encoding);
638 }
639 #endif
640 
641 
vmovsrr(SRegister sm,Register rt,Register rt2,Condition cond)642 void Assembler::vmovsrr(SRegister sm, Register rt, Register rt2,
643                         Condition cond) {
644   ASSERT(TargetCPUFeatures::vfp_supported());
645   ASSERT(sm != kNoSRegister);
646   ASSERT(sm != S31);
647   ASSERT(rt != kNoRegister);
648   ASSERT(rt != SP);
649   ASSERT(rt != PC);
650   ASSERT(rt2 != kNoRegister);
651   ASSERT(rt2 != SP);
652   ASSERT(rt2 != PC);
653   ASSERT(cond != kNoCondition);
654   int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
655                      B27 | B26 | B22 |
656                      (static_cast<int32_t>(rt2)*B16) |
657                      (static_cast<int32_t>(rt)*B12) | B11 | B9 |
658                      ((static_cast<int32_t>(sm) & 1)*B5) | B4 |
659                      (static_cast<int32_t>(sm) >> 1);
660   Emit(encoding);
661 }
662 
663 
vmovrrs(Register rt,Register rt2,SRegister sm,Condition cond)664 void Assembler::vmovrrs(Register rt, Register rt2, SRegister sm,
665                         Condition cond) {
666   ASSERT(TargetCPUFeatures::vfp_supported());
667   ASSERT(sm != kNoSRegister);
668   ASSERT(sm != S31);
669   ASSERT(rt != kNoRegister);
670   ASSERT(rt != SP);
671   ASSERT(rt != PC);
672   ASSERT(rt2 != kNoRegister);
673   ASSERT(rt2 != SP);
674   ASSERT(rt2 != PC);
675   ASSERT(rt != rt2);
676   ASSERT(cond != kNoCondition);
677   int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
678                      B27 | B26 | B22 | B20 |
679                      (static_cast<int32_t>(rt2)*B16) |
680                      (static_cast<int32_t>(rt)*B12) | B11 | B9 |
681                      ((static_cast<int32_t>(sm) & 1)*B5) | B4 |
682                      (static_cast<int32_t>(sm) >> 1);
683   Emit(encoding);
684 }
685 
686 #if 0
687 // Moved to ARM32::AssemblerARM32::vmovdqir().
688 void Assembler::vmovdr(DRegister dn, int i, Register rt, Condition cond) {
689   ASSERT(TargetCPUFeatures::vfp_supported());
690   ASSERT((i == 0) || (i == 1));
691   ASSERT(rt != kNoRegister);
692   ASSERT(rt != SP);
693   ASSERT(rt != PC);
694   ASSERT(dn != kNoDRegister);
695   ASSERT(cond != kNoCondition);
696   int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
697                      B27 | B26 | B25 |
698                      (i*B21) |
699                      (static_cast<int32_t>(rt)*B12) | B11 | B9 | B8 |
700                      ((static_cast<int32_t>(dn) >> 4)*B7) |
701                      ((static_cast<int32_t>(dn) & 0xf)*B16) | B4;
702   Emit(encoding);
703 }
704 
705 // Moved to ARM32::AssemblerARM32::vmovdrr().
706 void Assembler::vmovdrr(DRegister dm, Register rt, Register rt2,
707                         Condition cond) {
708   ASSERT(TargetCPUFeatures::vfp_supported());
709   ASSERT(dm != kNoDRegister);
710   ASSERT(rt != kNoRegister);
711   ASSERT(rt != SP);
712   ASSERT(rt != PC);
713   ASSERT(rt2 != kNoRegister);
714   ASSERT(rt2 != SP);
715   ASSERT(rt2 != PC);
716   ASSERT(cond != kNoCondition);
717   int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
718                      B27 | B26 | B22 |
719                      (static_cast<int32_t>(rt2)*B16) |
720                      (static_cast<int32_t>(rt)*B12) | B11 | B9 | B8 |
721                      ((static_cast<int32_t>(dm) >> 4)*B5) | B4 |
722                      (static_cast<int32_t>(dm) & 0xf);
723   Emit(encoding);
724 }
725 
726 // Moved to ARM32::AssemblerARM32::vmovrrd().
727 void Assembler::vmovrrd(Register rt, Register rt2, DRegister dm,
728                         Condition cond) {
729   ASSERT(TargetCPUFeatures::vfp_supported());
730   ASSERT(dm != kNoDRegister);
731   ASSERT(rt != kNoRegister);
732   ASSERT(rt != SP);
733   ASSERT(rt != PC);
734   ASSERT(rt2 != kNoRegister);
735   ASSERT(rt2 != SP);
736   ASSERT(rt2 != PC);
737   ASSERT(rt != rt2);
738   ASSERT(cond != kNoCondition);
739   int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
740                      B27 | B26 | B22 | B20 |
741                      (static_cast<int32_t>(rt2)*B16) |
742                      (static_cast<int32_t>(rt)*B12) | B11 | B9 | B8 |
743                      ((static_cast<int32_t>(dm) >> 4)*B5) | B4 |
744                      (static_cast<int32_t>(dm) & 0xf);
745   Emit(encoding);
746 }
747 
748 // Moved to ARM32::AssemblerARM32::vldrs()
749 void Assembler::vldrs(SRegister sd, Address ad, Condition cond) {
750   ASSERT(TargetCPUFeatures::vfp_supported());
751   ASSERT(sd != kNoSRegister);
752   ASSERT(cond != kNoCondition);
753   int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
754                      B27 | B26 | B24 | B20 |
755                      ((static_cast<int32_t>(sd) & 1)*B22) |
756                      ((static_cast<int32_t>(sd) >> 1)*B12) |
757                      B11 | B9 | ad.vencoding();
758   Emit(encoding);
759 }
760 
761 // Moved to Arm32::AssemblerARM32::vstrs()
762 void Assembler::vstrs(SRegister sd, Address ad, Condition cond) {
763   ASSERT(TargetCPUFeatures::vfp_supported());
764   ASSERT(static_cast<Register>(ad.encoding_ & (0xf << kRnShift)) != PC);
765   ASSERT(sd != kNoSRegister);
766   ASSERT(cond != kNoCondition);
767   int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
768                      B27 | B26 | B24 |
769                      ((static_cast<int32_t>(sd) & 1)*B22) |
770                      ((static_cast<int32_t>(sd) >> 1)*B12) |
771                      B11 | B9 | ad.vencoding();
772   Emit(encoding);
773 }
774 
775 void Assembler::vldrd(DRegister dd, Address ad, Condition cond) {
776   ASSERT(TargetCPUFeatures::vfp_supported());
777   ASSERT(dd != kNoDRegister);
778   ASSERT(cond != kNoCondition);
779   int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
780                      B27 | B26 | B24 | B20 |
781                      ((static_cast<int32_t>(dd) >> 4)*B22) |
782                      ((static_cast<int32_t>(dd) & 0xf)*B12) |
783                      B11 | B9 | B8 | ad.vencoding();
784   Emit(encoding);
785 }
786 #endif
787 
vstrd(DRegister dd,Address ad,Condition cond)788 void Assembler::vstrd(DRegister dd, Address ad, Condition cond) {
789   ASSERT(TargetCPUFeatures::vfp_supported());
790   ASSERT(static_cast<Register>(ad.encoding_ & (0xf << kRnShift)) != PC);
791   ASSERT(dd != kNoDRegister);
792   ASSERT(cond != kNoCondition);
793   int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
794                      B27 | B26 | B24 |
795                      ((static_cast<int32_t>(dd) >> 4)*B22) |
796                      ((static_cast<int32_t>(dd) & 0xf)*B12) |
797                      B11 | B9 | B8 | ad.vencoding();
798   Emit(encoding);
799 }
800 
EmitMultiVSMemOp(Condition cond,BlockAddressMode am,bool load,Register base,SRegister start,uint32_t count)801 void Assembler::EmitMultiVSMemOp(Condition cond,
802                                 BlockAddressMode am,
803                                 bool load,
804                                 Register base,
805                                 SRegister start,
806                                 uint32_t count) {
807   ASSERT(TargetCPUFeatures::vfp_supported());
808   ASSERT(base != kNoRegister);
809   ASSERT(cond != kNoCondition);
810   ASSERT(start != kNoSRegister);
811   ASSERT(static_cast<int32_t>(start) + count <= kNumberOfSRegisters);
812 
813   int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
814                      B27 | B26 | B11 | B9 |
815                      am |
816                      (load ? L : 0) |
817                      (static_cast<int32_t>(base) << kRnShift) |
818                      ((static_cast<int32_t>(start) & 0x1) ? D : 0) |
819                      ((static_cast<int32_t>(start) >> 1) << 12) |
820                      count;
821   Emit(encoding);
822 }
823 
824 
EmitMultiVDMemOp(Condition cond,BlockAddressMode am,bool load,Register base,DRegister start,int32_t count)825 void Assembler::EmitMultiVDMemOp(Condition cond,
826                                 BlockAddressMode am,
827                                 bool load,
828                                 Register base,
829                                 DRegister start,
830                                 int32_t count) {
831   ASSERT(TargetCPUFeatures::vfp_supported());
832   ASSERT(base != kNoRegister);
833   ASSERT(cond != kNoCondition);
834   ASSERT(start != kNoDRegister);
835   ASSERT(static_cast<int32_t>(start) + count <= kNumberOfDRegisters);
836   const int armv5te = TargetCPUFeatures::arm_version() == ARMv5TE ? 1 : 0;
837 
838   int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
839                      B27 | B26 | B11 | B9 | B8 |
840                      am |
841                      (load ? L : 0) |
842                      (static_cast<int32_t>(base) << kRnShift) |
843                      ((static_cast<int32_t>(start) & 0x10) ? D : 0) |
844                      ((static_cast<int32_t>(start) & 0xf) << 12) |
845                      (count << 1) | armv5te;
846   Emit(encoding);
847 }
848 
849 
vldms(BlockAddressMode am,Register base,SRegister first,SRegister last,Condition cond)850 void Assembler::vldms(BlockAddressMode am, Register base,
851                       SRegister first, SRegister last, Condition cond) {
852   ASSERT((am == IA) || (am == IA_W) || (am == DB_W));
853   ASSERT(last > first);
854   EmitMultiVSMemOp(cond, am, true, base, first, last - first + 1);
855 }
856 
857 
vstms(BlockAddressMode am,Register base,SRegister first,SRegister last,Condition cond)858 void Assembler::vstms(BlockAddressMode am, Register base,
859                       SRegister first, SRegister last, Condition cond) {
860   ASSERT((am == IA) || (am == IA_W) || (am == DB_W));
861   ASSERT(last > first);
862   EmitMultiVSMemOp(cond, am, false, base, first, last - first + 1);
863 }
864 
865 
vldmd(BlockAddressMode am,Register base,DRegister first,intptr_t count,Condition cond)866 void Assembler::vldmd(BlockAddressMode am, Register base,
867                       DRegister first, intptr_t count, Condition cond) {
868   ASSERT((am == IA) || (am == IA_W) || (am == DB_W));
869   ASSERT(count <= 16);
870   ASSERT(first + count <= kNumberOfDRegisters);
871   EmitMultiVDMemOp(cond, am, true, base, first, count);
872 }
873 
874 
vstmd(BlockAddressMode am,Register base,DRegister first,intptr_t count,Condition cond)875 void Assembler::vstmd(BlockAddressMode am, Register base,
876                       DRegister first, intptr_t count, Condition cond) {
877   ASSERT((am == IA) || (am == IA_W) || (am == DB_W));
878   ASSERT(count <= 16);
879   ASSERT(first + count <= kNumberOfDRegisters);
880   EmitMultiVDMemOp(cond, am, false, base, first, count);
881 }
882 
883 #if 0
884 // Moved to ARM32::AssemblerARM32::emitVFPsss
885 void Assembler::EmitVFPsss(Condition cond, int32_t opcode,
886                            SRegister sd, SRegister sn, SRegister sm) {
887   ASSERT(TargetCPUFeatures::vfp_supported());
888   ASSERT(sd != kNoSRegister);
889   ASSERT(sn != kNoSRegister);
890   ASSERT(sm != kNoSRegister);
891   ASSERT(cond != kNoCondition);
892   int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
893                      B27 | B26 | B25 | B11 | B9 | opcode |
894                      ((static_cast<int32_t>(sd) & 1)*B22) |
895                      ((static_cast<int32_t>(sn) >> 1)*B16) |
896                      ((static_cast<int32_t>(sd) >> 1)*B12) |
897                      ((static_cast<int32_t>(sn) & 1)*B7) |
898                      ((static_cast<int32_t>(sm) & 1)*B5) |
899                      (static_cast<int32_t>(sm) >> 1);
900   Emit(encoding);
901 }
902 
903 // Moved to ARM32::AssemblerARM32::emitVFPddd
904 void Assembler::EmitVFPddd(Condition cond, int32_t opcode,
905                            DRegister dd, DRegister dn, DRegister dm) {
906   ASSERT(TargetCPUFeatures::vfp_supported());
907   ASSERT(dd != kNoDRegister);
908   ASSERT(dn != kNoDRegister);
909   ASSERT(dm != kNoDRegister);
910   ASSERT(cond != kNoCondition);
911   int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
912                      B27 | B26 | B25 | B11 | B9 | B8 | opcode |
913                      ((static_cast<int32_t>(dd) >> 4)*B22) |
914                      ((static_cast<int32_t>(dn) & 0xf)*B16) |
915                      ((static_cast<int32_t>(dd) & 0xf)*B12) |
916                      ((static_cast<int32_t>(dn) >> 4)*B7) |
917                      ((static_cast<int32_t>(dm) >> 4)*B5) |
918                      (static_cast<int32_t>(dm) & 0xf);
919   Emit(encoding);
920 }
921 
922 // Moved to Arm32::AssemblerARM32::vmovss()
923 void Assembler::vmovs(SRegister sd, SRegister sm, Condition cond) {
924   EmitVFPsss(cond, B23 | B21 | B20 | B6, sd, S0, sm);
925 }
926 
927 // Moved to Arm32::AssemblerARM32::vmovdd()
928 void Assembler::vmovd(DRegister dd, DRegister dm, Condition cond) {
929   EmitVFPddd(cond, B23 | B21 | B20 | B6, dd, D0, dm);
930 }
931 
932 // Moved to Arm32::AssemblerARM32::vmovs()
933 bool Assembler::vmovs(SRegister sd, float s_imm, Condition cond) {
934   if (TargetCPUFeatures::arm_version() != ARMv7) {
935     return false;
936   }
937   uint32_t imm32 = bit_cast<uint32_t, float>(s_imm);
938   if (((imm32 & ((1 << 19) - 1)) == 0) &&
939       ((((imm32 >> 25) & ((1 << 6) - 1)) == (1 << 5)) ||
940        (((imm32 >> 25) & ((1 << 6) - 1)) == ((1 << 5) -1)))) {
941     uint8_t imm8 = ((imm32 >> 31) << 7) | (((imm32 >> 29) & 1) << 6) |
942         ((imm32 >> 19) & ((1 << 6) -1));
943     EmitVFPsss(cond, B23 | B21 | B20 | ((imm8 >> 4)*B16) | (imm8 & 0xf),
944                sd, S0, S0);
945     return true;
946   }
947   return false;
948 }
949 
950 // Moved to Arm32::AssemblerARM32::vmovd()
951 bool Assembler::vmovd(DRegister dd, double d_imm, Condition cond) {
952   if (TargetCPUFeatures::arm_version() != ARMv7) {
953     return false;
954   }
955   uint64_t imm64 = bit_cast<uint64_t, double>(d_imm);
956   if (((imm64 & ((1LL << 48) - 1)) == 0) &&
957       ((((imm64 >> 54) & ((1 << 9) - 1)) == (1 << 8)) ||
958        (((imm64 >> 54) & ((1 << 9) - 1)) == ((1 << 8) -1)))) {
959     uint8_t imm8 = ((imm64 >> 63) << 7) | (((imm64 >> 61) & 1) << 6) |
960         ((imm64 >> 48) & ((1 << 6) -1));
961     EmitVFPddd(cond, B23 | B21 | B20 | ((imm8 >> 4)*B16) | B8 | (imm8 & 0xf),
962                dd, D0, D0);
963     return true;
964   }
965   return false;
966 }
967 
968 // Moved to Arm32::AssemblerARM32::vadds()
969 void Assembler::vadds(SRegister sd, SRegister sn, SRegister sm,
970                       Condition cond) {
971   EmitVFPsss(cond, B21 | B20, sd, sn, sm);
972 }
973 
974 // Moved to Arm32::AssemblerARM32::vaddd()
975 void Assembler::vaddd(DRegister dd, DRegister dn, DRegister dm,
976                       Condition cond) {
977   EmitVFPddd(cond, B21 | B20, dd, dn, dm);
978 }
979 
980 // Moved to Arm32::AssemblerARM32::vsubs()
981 void Assembler::vsubs(SRegister sd, SRegister sn, SRegister sm,
982                       Condition cond) {
983   EmitVFPsss(cond, B21 | B20 | B6, sd, sn, sm);
984 }
985 
986 // Moved to Arm32::AssemblerARM32::vsubd()
987 void Assembler::vsubd(DRegister dd, DRegister dn, DRegister dm,
988                       Condition cond) {
989   EmitVFPddd(cond, B21 | B20 | B6, dd, dn, dm);
990 }
991 
992 // Moved to Arm32::AssemblerARM32::vmuls()
993 void Assembler::vmuls(SRegister sd, SRegister sn, SRegister sm,
994                       Condition cond) {
995   EmitVFPsss(cond, B21, sd, sn, sm);
996 }
997 
998 // Moved to Arm32::AssemblerARM32::vmuld()
999 void Assembler::vmuld(DRegister dd, DRegister dn, DRegister dm,
1000                       Condition cond) {
1001   EmitVFPddd(cond, B21, dd, dn, dm);
1002 }
1003 
1004 // Moved to Arm32::AssemblerARM32::vmlas()
1005 void Assembler::vmlas(SRegister sd, SRegister sn, SRegister sm,
1006                       Condition cond) {
1007   EmitVFPsss(cond, 0, sd, sn, sm);
1008 }
1009 
1010 // Moved to Arm32::AssemblerARM32::vmlad()
1011 void Assembler::vmlad(DRegister dd, DRegister dn, DRegister dm,
1012                       Condition cond) {
1013   EmitVFPddd(cond, 0, dd, dn, dm);
1014 }
1015 
1016 // Moved to Arm32::AssemblerARM32::vmlss()
1017 void Assembler::vmlss(SRegister sd, SRegister sn, SRegister sm,
1018                       Condition cond) {
1019   EmitVFPsss(cond, B6, sd, sn, sm);
1020 }
1021 
1022 // Moved to Arm32::AssemblerARM32::vmlsd()
1023 void Assembler::vmlsd(DRegister dd, DRegister dn, DRegister dm,
1024                       Condition cond) {
1025   EmitVFPddd(cond, B6, dd, dn, dm);
1026 }
1027 
1028 // Moved to Arm32::AssemblerARM32::vdivs()
1029 void Assembler::vdivs(SRegister sd, SRegister sn, SRegister sm,
1030                       Condition cond) {
1031   EmitVFPsss(cond, B23, sd, sn, sm);
1032 }
1033 
1034 // Moved to Arm32::AssemblerARM32::vdivd()
1035 void Assembler::vdivd(DRegister dd, DRegister dn, DRegister dm,
1036                       Condition cond) {
1037   EmitVFPddd(cond, B23, dd, dn, dm);
1038 }
1039 
1040 // Moved to Arm32::AssemblerARM32::vabss().
1041 void Assembler::vabss(SRegister sd, SRegister sm, Condition cond) {
1042   EmitVFPsss(cond, B23 | B21 | B20 | B7 | B6, sd, S0, sm);
1043 }
1044 
1045 // Moved to Arm32::AssemblerARM32::vabsd().
1046 void Assembler::vabsd(DRegister dd, DRegister dm, Condition cond) {
1047   EmitVFPddd(cond, B23 | B21 | B20 | B7 | B6, dd, D0, dm);
1048 }
1049 #endif
1050 
vnegs(SRegister sd,SRegister sm,Condition cond)1051 void Assembler::vnegs(SRegister sd, SRegister sm, Condition cond) {
1052   EmitVFPsss(cond, B23 | B21 | B20 | B16 | B6, sd, S0, sm);
1053 }
1054 
1055 
vnegd(DRegister dd,DRegister dm,Condition cond)1056 void Assembler::vnegd(DRegister dd, DRegister dm, Condition cond) {
1057   EmitVFPddd(cond, B23 | B21 | B20 | B16 | B6, dd, D0, dm);
1058 }
1059 
1060 #if 0
1061 // Moved to ARM32::AssemblerARM32::vsqrts().
1062 void Assembler::vsqrts(SRegister sd, SRegister sm, Condition cond) {
1063   EmitVFPsss(cond, B23 | B21 | B20 | B16 | B7 | B6, sd, S0, sm);
1064 }
1065 
1066 // Moved to ARM32::AssemblerARM32::vsqrtd().
1067 void Assembler::vsqrtd(DRegister dd, DRegister dm, Condition cond) {
1068   EmitVFPddd(cond, B23 | B21 | B20 | B16 | B7 | B6, dd, D0, dm);
1069 }
1070 
1071 // Moved to ARM32::AssemblerARM32::emitVFPsd
1072 void Assembler::EmitVFPsd(Condition cond, int32_t opcode,
1073                           SRegister sd, DRegister dm) {
1074   ASSERT(TargetCPUFeatures::vfp_supported());
1075   ASSERT(sd != kNoSRegister);
1076   ASSERT(dm != kNoDRegister);
1077   ASSERT(cond != kNoCondition);
1078   int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1079                      B27 | B26 | B25 | B11 | B9 | opcode |
1080                      ((static_cast<int32_t>(sd) & 1)*B22) |
1081                      ((static_cast<int32_t>(sd) >> 1)*B12) |
1082                      ((static_cast<int32_t>(dm) >> 4)*B5) |
1083                      (static_cast<int32_t>(dm) & 0xf);
1084   Emit(encoding);
1085 }
1086 
1087 // Moved to ARM32::AssemblerARM32::emitVFPds
1088 void Assembler::EmitVFPds(Condition cond, int32_t opcode,
1089                           DRegister dd, SRegister sm) {
1090   ASSERT(TargetCPUFeatures::vfp_supported());
1091   ASSERT(dd != kNoDRegister);
1092   ASSERT(sm != kNoSRegister);
1093   ASSERT(cond != kNoCondition);
1094   int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1095                      B27 | B26 | B25 | B11 | B9 | opcode |
1096                      ((static_cast<int32_t>(dd) >> 4)*B22) |
1097                      ((static_cast<int32_t>(dd) & 0xf)*B12) |
1098                      ((static_cast<int32_t>(sm) & 1)*B5) |
1099                      (static_cast<int32_t>(sm) >> 1);
1100   Emit(encoding);
1101 }
1102 
1103 // Moved to ARM32::AssemblerARM32::vcvtsd().
1104 void Assembler::vcvtsd(SRegister sd, DRegister dm, Condition cond) {
1105   EmitVFPsd(cond, B23 | B21 | B20 | B18 | B17 | B16 | B8 | B7 | B6, sd, dm);
1106 }
1107 
1108 // Moved to ARM32::AssemblerARM32::vcvtds().
1109 void Assembler::vcvtds(DRegister dd, SRegister sm, Condition cond) {
1110   EmitVFPds(cond, B23 | B21 | B20 | B18 | B17 | B16 | B7 | B6, dd, sm);
1111 }
1112 
1113 // Moved to ARM32::AssemblerARM32::vcvtis()
1114 void Assembler::vcvtis(SRegister sd, SRegister sm, Condition cond) {
1115   EmitVFPsss(cond, B23 | B21 | B20 | B19 | B18 | B16 | B7 | B6, sd, S0, sm);
1116 }
1117 #endif
1118 
vcvtid(SRegister sd,DRegister dm,Condition cond)1119 void Assembler::vcvtid(SRegister sd, DRegister dm, Condition cond) {
1120   EmitVFPsd(cond, B23 | B21 | B20 | B19 | B18 | B16 | B8 | B7 | B6, sd, dm);
1121 }
1122 
1123 #if 0
1124 // Moved to ARM32::AssemblerARM32::vcvtsi()
1125 void Assembler::vcvtsi(SRegister sd, SRegister sm, Condition cond) {
1126   EmitVFPsss(cond, B23 | B21 | B20 | B19 | B7 | B6, sd, S0, sm);
1127 }
1128 
1129 // Moved to ARM32::AssemblerARM32::vcvtdi()
1130 void Assembler::vcvtdi(DRegister dd, SRegister sm, Condition cond) {
1131   EmitVFPds(cond, B23 | B21 | B20 | B19 | B8 | B7 | B6, dd, sm);
1132 }
1133 
1134 // Moved to ARM32::AssemblerARM32::vcvtus().
1135 void Assembler::vcvtus(SRegister sd, SRegister sm, Condition cond) {
1136   EmitVFPsss(cond, B23 | B21 | B20 | B19 | B18 | B7 | B6, sd, S0, sm);
1137 }
1138 
1139 // Moved to ARM32::AssemblerARM32::vcvtud().
1140 void Assembler::vcvtud(SRegister sd, DRegister dm, Condition cond) {
1141   EmitVFPsd(cond, B23 | B21 | B20 | B19 | B18 | B8 | B7 | B6, sd, dm);
1142 }
1143 
1144 // Moved to ARM32::AssemblerARM32::vcvtsu()
1145 void Assembler::vcvtsu(SRegister sd, SRegister sm, Condition cond) {
1146   EmitVFPsss(cond, B23 | B21 | B20 | B19 | B6, sd, S0, sm);
1147 }
1148 
1149 // Moved to ARM32::AssemblerARM32::vcvtdu()
1150 void Assembler::vcvtdu(DRegister dd, SRegister sm, Condition cond) {
1151   EmitVFPds(cond, B23 | B21 | B20 | B19 | B8 | B6, dd, sm);
1152 }
1153 
1154 // Moved to ARM23::AssemblerARM32::vcmps().
1155 void Assembler::vcmps(SRegister sd, SRegister sm, Condition cond) {
1156   EmitVFPsss(cond, B23 | B21 | B20 | B18 | B6, sd, S0, sm);
1157 }
1158 
1159 // Moved to ARM23::AssemblerARM32::vcmpd().
1160 void Assembler::vcmpd(DRegister dd, DRegister dm, Condition cond) {
1161   EmitVFPddd(cond, B23 | B21 | B20 | B18 | B6, dd, D0, dm);
1162 }
1163 
1164 // Moved to ARM23::AssemblerARM32::vcmpsz().
1165 void Assembler::vcmpsz(SRegister sd, Condition cond) {
1166   EmitVFPsss(cond, B23 | B21 | B20 | B18 | B16 | B6, sd, S0, S0);
1167 }
1168 
1169 // Moved to ARM23::AssemblerARM32::vcmpdz().
1170 void Assembler::vcmpdz(DRegister dd, Condition cond) {
1171   EmitVFPddd(cond, B23 | B21 | B20 | B18 | B16 | B6, dd, D0, D0);
1172 }
1173 
1174 // APSR_nzcv version moved to ARM32::AssemblerARM32::vmrsAPSR_nzcv()
1175 void Assembler::vmrs(Register rd, Condition cond) {
1176   ASSERT(TargetCPUFeatures::vfp_supported());
1177   ASSERT(cond != kNoCondition);
1178   int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1179                      B27 | B26 | B25 | B23 | B22 | B21 | B20 | B16 |
1180                      (static_cast<int32_t>(rd)*B12) |
1181                      B11 | B9 | B4;
1182   Emit(encoding);
1183 }
1184 #endif
1185 
vmstat(Condition cond)1186 void Assembler::vmstat(Condition cond) {
1187   vmrs(APSR, cond);
1188 }
1189 
1190 
ShiftOfOperandSize(OperandSize size)1191 static inline int ShiftOfOperandSize(OperandSize size) {
1192   switch (size) {
1193     case kByte:
1194     case kUnsignedByte:
1195       return 0;
1196     case kHalfword:
1197     case kUnsignedHalfword:
1198       return 1;
1199     case kWord:
1200     case kUnsignedWord:
1201       return 2;
1202     case kWordPair:
1203       return 3;
1204     case kSWord:
1205     case kDWord:
1206       return 0;
1207     default:
1208       UNREACHABLE();
1209       break;
1210   }
1211 
1212   UNREACHABLE();
1213   return -1;
1214 }
1215 
1216 #if 0
1217 // Moved to ARM32::AssemblerARM32::emitSIMDqqq()
1218 void Assembler::EmitSIMDqqq(int32_t opcode, OperandSize size,
1219                             QRegister qd, QRegister qn, QRegister qm) {
1220   ASSERT(TargetCPUFeatures::neon_supported());
1221   int sz = ShiftOfOperandSize(size);
1222   int32_t encoding =
1223       (static_cast<int32_t>(kSpecialCondition) << kConditionShift) |
1224       B25 | B6 |
1225       opcode | ((sz & 0x3) * B20) |
1226       ((static_cast<int32_t>(qd * 2) >> 4)*B22) |
1227       ((static_cast<int32_t>(qn * 2) & 0xf)*B16) |
1228       ((static_cast<int32_t>(qd * 2) & 0xf)*B12) |
1229       ((static_cast<int32_t>(qn * 2) >> 4)*B7) |
1230       ((static_cast<int32_t>(qm * 2) >> 4)*B5) |
1231       (static_cast<int32_t>(qm * 2) & 0xf);
1232   Emit(encoding);
1233 }
1234 #endif
1235 
EmitSIMDddd(int32_t opcode,OperandSize size,DRegister dd,DRegister dn,DRegister dm)1236 void Assembler::EmitSIMDddd(int32_t opcode, OperandSize size,
1237                             DRegister dd, DRegister dn, DRegister dm) {
1238   ASSERT(TargetCPUFeatures::neon_supported());
1239   int sz = ShiftOfOperandSize(size);
1240   int32_t encoding =
1241       (static_cast<int32_t>(kSpecialCondition) << kConditionShift) |
1242       B25 |
1243       opcode | ((sz & 0x3) * B20) |
1244       ((static_cast<int32_t>(dd) >> 4)*B22) |
1245       ((static_cast<int32_t>(dn) & 0xf)*B16) |
1246       ((static_cast<int32_t>(dd) & 0xf)*B12) |
1247       ((static_cast<int32_t>(dn) >> 4)*B7) |
1248       ((static_cast<int32_t>(dm) >> 4)*B5) |
1249       (static_cast<int32_t>(dm) & 0xf);
1250   Emit(encoding);
1251 }
1252 
1253 
vmovq(QRegister qd,QRegister qm)1254 void Assembler::vmovq(QRegister qd, QRegister qm) {
1255   EmitSIMDqqq(B21 | B8 | B4, kByte, qd, qm, qm);
1256 }
1257 
1258 #if 0
1259 // Moved to ARM32::AssemblerARM32::vaddqi().
1260 void Assembler::vaddqi(OperandSize sz,
1261                        QRegister qd, QRegister qn, QRegister qm) {
1262   EmitSIMDqqq(B11, sz, qd, qn, qm);
1263 }
1264 
1265 // Moved to ARM32::AssemblerARM32::vaddqf().
1266 void Assembler::vaddqs(QRegister qd, QRegister qn, QRegister qm) {
1267   EmitSIMDqqq(B11 | B10 | B8, kSWord, qd, qn, qm);
1268 }
1269 #endif
1270 
vsubqi(OperandSize sz,QRegister qd,QRegister qn,QRegister qm)1271 void Assembler::vsubqi(OperandSize sz,
1272                        QRegister qd, QRegister qn, QRegister qm) {
1273   EmitSIMDqqq(B24 | B11, sz, qd, qn, qm);
1274 }
1275 
1276 
vsubqs(QRegister qd,QRegister qn,QRegister qm)1277 void Assembler::vsubqs(QRegister qd, QRegister qn, QRegister qm) {
1278   EmitSIMDqqq(B21 | B11 | B10 | B8, kSWord, qd, qn, qm);
1279 }
1280 
1281 #if 0
1282 // Moved to ARM32::AssemblerARM32::vmulqi().
1283 void Assembler::vmulqi(OperandSize sz,
1284                        QRegister qd, QRegister qn, QRegister qm) {
1285   EmitSIMDqqq(B11 | B8 | B4, sz, qd, qn, qm);
1286 }
1287 
1288 // Moved to ARM32::AssemblerARM32::vmulqf().
1289 void Assembler::vmulqs(QRegister qd, QRegister qn, QRegister qm) {
1290   EmitSIMDqqq(B24 | B11 | B10 | B8 | B4, kSWord, qd, qn, qm);
1291 }
1292 
1293 // Moved to ARM32::AssemblerARM32::vshlqi().
1294 void Assembler::vshlqi(OperandSize sz,
1295                        QRegister qd, QRegister qm, QRegister qn) {
1296   EmitSIMDqqq(B25 | B10, sz, qd, qn, qm);
1297 }
1298 
1299 
1300 // Moved to ARM32::AssemblerARM32::vshlqu().
1301 void Assembler::vshlqu(OperandSize sz,
1302                        QRegister qd, QRegister qm, QRegister qn) {
1303   EmitSIMDqqq(B25 | B24 | B10, sz, qd, qn, qm);
1304 }
1305 
1306 // Moved to ARM32::AssemblerARM32::veorq()
1307 void Assembler::veorq(QRegister qd, QRegister qn, QRegister qm) {
1308   EmitSIMDqqq(B24 | B8 | B4, kByte, qd, qn, qm);
1309 }
1310 
1311 // Moved to ARM32::AssemblerARM32::vorrq()
1312 void Assembler::vorrq(QRegister qd, QRegister qn, QRegister qm) {
1313   EmitSIMDqqq(B21 | B8 | B4, kByte, qd, qn, qm);
1314 }
1315 #endif
1316 
vornq(QRegister qd,QRegister qn,QRegister qm)1317 void Assembler::vornq(QRegister qd, QRegister qn, QRegister qm) {
1318   EmitSIMDqqq(B21 | B20 | B8 | B4, kByte, qd, qn, qm);
1319 }
1320 
1321 #if 0
1322 // Moved to ARM32::AssemblerARM32::vandq()
1323 void Assembler::vandq(QRegister qd, QRegister qn, QRegister qm) {
1324   EmitSIMDqqq(B8 | B4, kByte, qd, qn, qm);
1325 }
1326 
1327 void Assembler::vmvnq(QRegister qd, QRegister qm) {
1328   EmitSIMDqqq(B25 | B24 | B23 | B10 | B8 | B7, kWordPair, qd, Q0, qm);
1329 }
1330 #endif
1331 
1332 
vminqs(QRegister qd,QRegister qn,QRegister qm)1333 void Assembler::vminqs(QRegister qd, QRegister qn, QRegister qm) {
1334   EmitSIMDqqq(B21 | B11 | B10 | B9 | B8, kSWord, qd, qn, qm);
1335 }
1336 
1337 
vmaxqs(QRegister qd,QRegister qn,QRegister qm)1338 void Assembler::vmaxqs(QRegister qd, QRegister qn, QRegister qm) {
1339   EmitSIMDqqq(B11 | B10 | B9 | B8, kSWord, qd, qn, qm);
1340 }
1341 
1342 #if 0
1343 // Moved to Arm32::AssemblerARM32::vabsq().
1344 void Assembler::vabsqs(QRegister qd, QRegister qm) {
1345   EmitSIMDqqq(B24 | B23 | B21 | B20 | B19 | B16 | B10 | B9 | B8, kSWord,
1346               qd, Q0, qm);
1347 }
1348 
1349 // Moved to Arm32::AssemblerARM32::vnegqs().
1350 void Assembler::vnegqs(QRegister qd, QRegister qm) {
1351   EmitSIMDqqq(B24 | B23 | B21 | B20 | B19 | B16 | B10 | B9 | B8 | B7, kSWord,
1352               qd, Q0, qm);
1353 }
1354 #endif
1355 
1356 
vrecpeqs(QRegister qd,QRegister qm)1357 void Assembler::vrecpeqs(QRegister qd, QRegister qm) {
1358   EmitSIMDqqq(B24 | B23 | B21 | B20 | B19 | B17 | B16 | B10 | B8, kSWord,
1359               qd, Q0, qm);
1360 }
1361 
1362 
vrecpsqs(QRegister qd,QRegister qn,QRegister qm)1363 void Assembler::vrecpsqs(QRegister qd, QRegister qn, QRegister qm) {
1364   EmitSIMDqqq(B11 | B10 | B9 | B8 | B4, kSWord, qd, qn, qm);
1365 }
1366 
1367 
vrsqrteqs(QRegister qd,QRegister qm)1368 void Assembler::vrsqrteqs(QRegister qd, QRegister qm) {
1369   EmitSIMDqqq(B24 | B23 | B21 | B20 | B19 | B17 | B16 | B10 | B8 | B7,
1370               kSWord, qd, Q0, qm);
1371 }
1372 
1373 
vrsqrtsqs(QRegister qd,QRegister qn,QRegister qm)1374 void Assembler::vrsqrtsqs(QRegister qd, QRegister qn, QRegister qm) {
1375   EmitSIMDqqq(B21 | B11 | B10 | B9 | B8 | B4, kSWord, qd, qn, qm);
1376 }
1377 
1378 
vdup(OperandSize sz,QRegister qd,DRegister dm,int idx)1379 void Assembler::vdup(OperandSize sz, QRegister qd, DRegister dm, int idx) {
1380   ASSERT((sz != kDWord) && (sz != kSWord) && (sz != kWordPair));
1381   int code = 0;
1382 
1383   switch (sz) {
1384     case kByte:
1385     case kUnsignedByte: {
1386       ASSERT((idx >= 0) && (idx < 8));
1387       code = 1 | (idx << 1);
1388       break;
1389     }
1390     case kHalfword:
1391     case kUnsignedHalfword: {
1392       ASSERT((idx >= 0) && (idx < 4));
1393       code = 2 | (idx << 2);
1394       break;
1395     }
1396     case kWord:
1397     case kUnsignedWord: {
1398       ASSERT((idx >= 0) && (idx < 2));
1399       code = 4 | (idx << 3);
1400       break;
1401     }
1402     default: {
1403       break;
1404     }
1405   }
1406 
1407   EmitSIMDddd(B24 | B23 | B11 | B10 | B6, kWordPair,
1408               static_cast<DRegister>(qd * 2),
1409               static_cast<DRegister>(code & 0xf),
1410               dm);
1411 }
1412 
1413 
vtbl(DRegister dd,DRegister dn,int len,DRegister dm)1414 void Assembler::vtbl(DRegister dd, DRegister dn, int len, DRegister dm) {
1415   ASSERT((len >= 1) && (len <= 4));
1416   EmitSIMDddd(B24 | B23 | B11 | ((len - 1) * B8), kWordPair, dd, dn, dm);
1417 }
1418 
1419 
vzipqw(QRegister qd,QRegister qm)1420 void Assembler::vzipqw(QRegister qd, QRegister qm) {
1421   EmitSIMDqqq(B24 | B23 | B21 | B20 | B19 | B17 | B8 | B7, kByte, qd, Q0, qm);
1422 }
1423 
1424 
1425 #if 0
1426 // Moved to Arm32::AssemblerARM32::vceqqi().
1427 void Assembler::vceqqi(OperandSize sz,
1428                       QRegister qd, QRegister qn, QRegister qm) {
1429   EmitSIMDqqq(B24 | B11 | B4, sz, qd, qn, qm);
1430 }
1431 
1432 // Moved to Arm32::AssemblerARM32::vceqqi().
1433 void Assembler::vceqqs(QRegister qd, QRegister qn, QRegister qm) {
1434   EmitSIMDqqq(B11 | B10 | B9, kSWord, qd, qn, qm);
1435 }
1436 
1437 // Moved to Arm32::AssemblerARM32::vcgeqi().
1438 void Assembler::vcgeqi(OperandSize sz,
1439                       QRegister qd, QRegister qn, QRegister qm) {
1440   EmitSIMDqqq(B9 | B8 | B4, sz, qd, qn, qm);
1441 }
1442 
1443 // Moved to Arm32::AssemblerARM32::vcugeqi().
1444 void Assembler::vcugeqi(OperandSize sz,
1445                       QRegister qd, QRegister qn, QRegister qm) {
1446   EmitSIMDqqq(B24 | B9 | B8 | B4, sz, qd, qn, qm);
1447 }
1448 
1449 // Moved to Arm32::AssemblerARM32::vcgeqs().
1450 void Assembler::vcgeqs(QRegister qd, QRegister qn, QRegister qm) {
1451   EmitSIMDqqq(B24 | B11 | B10 | B9, kSWord, qd, qn, qm);
1452 }
1453 
1454 // Moved to Arm32::AssemblerARM32::vcgtqi().
1455 void Assembler::vcgtqi(OperandSize sz,
1456                       QRegister qd, QRegister qn, QRegister qm) {
1457   EmitSIMDqqq(B9 | B8, sz, qd, qn, qm);
1458 }
1459 
1460 // Moved to Arm32::AssemblerARM32::vcugtqi().
1461 void Assembler::vcugtqi(OperandSize sz,
1462                       QRegister qd, QRegister qn, QRegister qm) {
1463   EmitSIMDqqq(B24 | B9 | B8, sz, qd, qn, qm);
1464 }
1465 
1466 // Moved to Arm32::AssemblerARM32::vcgtqs().
1467 void Assembler::vcgtqs(QRegister qd, QRegister qn, QRegister qm) {
1468   EmitSIMDqqq(B24 | B21 | B11 | B10 | B9, kSWord, qd, qn, qm);
1469 }
1470 
1471 // Moved to ARM32::AssemblerARM32::bkpt()
1472 void Assembler::bkpt(uint16_t imm16) {
1473   Emit(BkptEncoding(imm16));
1474 }
1475 #endif
1476 
1477 
b(Label * label,Condition cond)1478 void Assembler::b(Label* label, Condition cond) {
1479   EmitBranch(cond, label, false);
1480 }
1481 
1482 
1483 #if 0
1484 // Moved to ARM32::AssemblerARM32::bl()
1485 void Assembler::bl(Label* label, Condition cond) {
1486   EmitBranch(cond, label, true);
1487 }
1488 
1489 // Moved to ARM32::AssemblerARM32::bx()
1490 void Assembler::bx(Register rm, Condition cond) {
1491   ASSERT(rm != kNoRegister);
1492   ASSERT(cond != kNoCondition);
1493   int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1494                      B24 | B21 | (0xfff << 8) | B4 |
1495                      (static_cast<int32_t>(rm) << kRmShift);
1496   Emit(encoding);
1497 }
1498 
1499 // Moved to ARM32::AssemblerARM32::blx()
1500 void Assembler::blx(Register rm, Condition cond) {
1501   ASSERT(rm != kNoRegister);
1502   ASSERT(cond != kNoCondition);
1503   int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
1504                      B24 | B21 | (0xfff << 8) | B5 | B4 |
1505                      (static_cast<int32_t>(rm) << kRmShift);
1506   Emit(encoding);
1507 }
1508 #endif
1509 
1510 
MarkExceptionHandler(Label * label)1511 void Assembler::MarkExceptionHandler(Label* label) {
1512   EmitType01(AL, 1, TST, 1, PC, R0, Operand(0));
1513   Label l;
1514   b(&l);
1515   EmitBranch(AL, label, false);
1516   Bind(&l);
1517 }
1518 
1519 
Drop(intptr_t stack_elements)1520 void Assembler::Drop(intptr_t stack_elements) {
1521   ASSERT(stack_elements >= 0);
1522   if (stack_elements > 0) {
1523     AddImmediate(SP, SP, stack_elements * kWordSize);
1524   }
1525 }
1526 
1527 
FindImmediate(int32_t imm)1528 intptr_t Assembler::FindImmediate(int32_t imm) {
1529   return object_pool_wrapper_.FindImmediate(imm);
1530 }
1531 
1532 
1533 // Uses a code sequence that can easily be decoded.
LoadWordFromPoolOffset(Register rd,int32_t offset,Register pp,Condition cond)1534 void Assembler::LoadWordFromPoolOffset(Register rd,
1535                                        int32_t offset,
1536                                        Register pp,
1537                                        Condition cond) {
1538   ASSERT((pp != PP) || constant_pool_allowed());
1539   ASSERT(rd != pp);
1540   int32_t offset_mask = 0;
1541   if (Address::CanHoldLoadOffset(kWord, offset, &offset_mask)) {
1542     ldr(rd, Address(pp, offset), cond);
1543   } else {
1544     int32_t offset_hi = offset & ~offset_mask;  // signed
1545     uint32_t offset_lo = offset & offset_mask;  // unsigned
1546     // Inline a simplified version of AddImmediate(rd, pp, offset_hi).
1547     Operand o;
1548     if (Operand::CanHold(offset_hi, &o)) {
1549       add(rd, pp, o, cond);
1550     } else {
1551       LoadImmediate(rd, offset_hi, cond);
1552       add(rd, pp, Operand(rd), cond);
1553     }
1554     ldr(rd, Address(rd, offset_lo), cond);
1555   }
1556 }
1557 
CheckCodePointer()1558 void Assembler::CheckCodePointer() {
1559 #ifdef DEBUG
1560   Label cid_ok, instructions_ok;
1561   Push(R0);
1562   Push(IP);
1563   CompareClassId(CODE_REG, kCodeCid, R0);
1564   b(&cid_ok, EQ);
1565   bkpt(0);
1566   Bind(&cid_ok);
1567 
1568   const intptr_t offset = CodeSize() + Instr::kPCReadOffset +
1569       Instructions::HeaderSize() - kHeapObjectTag;
1570   mov(R0, Operand(PC));
1571   AddImmediate(R0, R0, -offset);
1572   ldr(IP, FieldAddress(CODE_REG, Code::saved_instructions_offset()));
1573   cmp(R0, Operand(IP));
1574   b(&instructions_ok, EQ);
1575   bkpt(1);
1576   Bind(&instructions_ok);
1577   Pop(IP);
1578   Pop(R0);
1579 #endif
1580 }
1581 
1582 
RestoreCodePointer()1583 void Assembler::RestoreCodePointer() {
1584   ldr(CODE_REG, Address(FP, kPcMarkerSlotFromFp * kWordSize));
1585   CheckCodePointer();
1586 }
1587 
1588 
LoadPoolPointer(Register reg)1589 void Assembler::LoadPoolPointer(Register reg) {
1590   // Load new pool pointer.
1591   CheckCodePointer();
1592   ldr(reg, FieldAddress(CODE_REG, Code::object_pool_offset()));
1593   set_constant_pool_allowed(reg == PP);
1594 }
1595 
1596 
LoadIsolate(Register rd)1597 void Assembler::LoadIsolate(Register rd) {
1598   ldr(rd, Address(THR, Thread::isolate_offset()));
1599 }
1600 
1601 
CanLoadFromObjectPool(const Object & object) const1602 bool Assembler::CanLoadFromObjectPool(const Object& object) const {
1603   ASSERT(!Thread::CanLoadFromThread(object));
1604   if (!constant_pool_allowed()) {
1605     return false;
1606   }
1607 
1608   ASSERT(object.IsNotTemporaryScopedHandle());
1609   ASSERT(object.IsOld());
1610   return true;
1611 }
1612 
1613 
LoadObjectHelper(Register rd,const Object & object,Condition cond,bool is_unique,Register pp)1614 void Assembler::LoadObjectHelper(Register rd,
1615                                  const Object& object,
1616                                  Condition cond,
1617                                  bool is_unique,
1618                                  Register pp) {
1619   // Load common VM constants from the thread. This works also in places where
1620   // no constant pool is set up (e.g. intrinsic code).
1621   if (Thread::CanLoadFromThread(object)) {
1622     // Load common VM constants from the thread. This works also in places where
1623     // no constant pool is set up (e.g. intrinsic code).
1624     ldr(rd, Address(THR, Thread::OffsetFromThread(object)), cond);
1625   } else if (object.IsSmi()) {
1626     // Relocation doesn't apply to Smis.
1627     LoadImmediate(rd, reinterpret_cast<int32_t>(object.raw()), cond);
1628   } else if (CanLoadFromObjectPool(object)) {
1629     // Make sure that class CallPattern is able to decode this load from the
1630     // object pool.
1631     const int32_t offset = ObjectPool::element_offset(
1632        is_unique ? object_pool_wrapper_.AddObject(object)
1633                  : object_pool_wrapper_.FindObject(object));
1634     LoadWordFromPoolOffset(rd, offset - kHeapObjectTag, pp, cond);
1635   } else {
1636     ASSERT(FLAG_allow_absolute_addresses);
1637     ASSERT(object.IsOld());
1638     // Make sure that class CallPattern is able to decode this load immediate.
1639     const int32_t object_raw = reinterpret_cast<int32_t>(object.raw());
1640     LoadImmediate(rd, object_raw, cond);
1641   }
1642 }
1643 
1644 
LoadObject(Register rd,const Object & object,Condition cond)1645 void Assembler::LoadObject(Register rd, const Object& object, Condition cond) {
1646   LoadObjectHelper(rd, object, cond, /* is_unique = */ false, PP);
1647 }
1648 
1649 
LoadUniqueObject(Register rd,const Object & object,Condition cond)1650 void Assembler::LoadUniqueObject(Register rd,
1651                                  const Object& object,
1652                                  Condition cond) {
1653   LoadObjectHelper(rd, object, cond, /* is_unique = */ true, PP);
1654 }
1655 
1656 
LoadFunctionFromCalleePool(Register dst,const Function & function,Register new_pp)1657 void Assembler::LoadFunctionFromCalleePool(Register dst,
1658                                            const Function& function,
1659                                            Register new_pp) {
1660   const int32_t offset =
1661       ObjectPool::element_offset(object_pool_wrapper_.FindObject(function));
1662   LoadWordFromPoolOffset(dst, offset - kHeapObjectTag, new_pp, AL);
1663 }
1664 
1665 
LoadNativeEntry(Register rd,const ExternalLabel * label,Patchability patchable,Condition cond)1666 void Assembler::LoadNativeEntry(Register rd,
1667                                 const ExternalLabel* label,
1668                                 Patchability patchable,
1669                                 Condition cond) {
1670   const int32_t offset = ObjectPool::element_offset(
1671       object_pool_wrapper_.FindNativeEntry(label, patchable));
1672   LoadWordFromPoolOffset(rd, offset - kHeapObjectTag, PP, cond);
1673 }
1674 
1675 
PushObject(const Object & object)1676 void Assembler::PushObject(const Object& object) {
1677   LoadObject(IP, object);
1678   Push(IP);
1679 }
1680 
1681 
CompareObject(Register rn,const Object & object)1682 void Assembler::CompareObject(Register rn, const Object& object) {
1683   ASSERT(rn != IP);
1684   if (object.IsSmi()) {
1685     CompareImmediate(rn, reinterpret_cast<int32_t>(object.raw()));
1686   } else {
1687     LoadObject(IP, object);
1688     cmp(rn, Operand(IP));
1689   }
1690 }
1691 
1692 
1693 // Preserves object and value registers.
StoreIntoObjectFilterNoSmi(Register object,Register value,Label * no_update)1694 void Assembler::StoreIntoObjectFilterNoSmi(Register object,
1695                                            Register value,
1696                                            Label* no_update) {
1697   COMPILE_ASSERT((kNewObjectAlignmentOffset == kWordSize) &&
1698                  (kOldObjectAlignmentOffset == 0));
1699 
1700   // Write-barrier triggers if the value is in the new space (has bit set) and
1701   // the object is in the old space (has bit cleared).
1702   // To check that, we compute value & ~object and skip the write barrier
1703   // if the bit is not set. We can't destroy the object.
1704   bic(IP, value, Operand(object));
1705   tst(IP, Operand(kNewObjectAlignmentOffset));
1706   b(no_update, EQ);
1707 }
1708 
1709 
1710 // Preserves object and value registers.
StoreIntoObjectFilter(Register object,Register value,Label * no_update)1711 void Assembler::StoreIntoObjectFilter(Register object,
1712                                       Register value,
1713                                       Label* no_update) {
1714   // For the value we are only interested in the new/old bit and the tag bit.
1715   // And the new bit with the tag bit. The resulting bit will be 0 for a Smi.
1716   and_(IP, value, Operand(value, LSL, kObjectAlignmentLog2 - 1));
1717   // And the result with the negated space bit of the object.
1718   bic(IP, IP, Operand(object));
1719   tst(IP, Operand(kNewObjectAlignmentOffset));
1720   b(no_update, EQ);
1721 }
1722 
1723 
GetVerifiedMemoryShadow()1724 Operand Assembler::GetVerifiedMemoryShadow() {
1725   Operand offset;
1726   if (!Operand::CanHold(VerifiedMemory::offset(), &offset)) {
1727     FATAL1("Offset 0x%" Px " not representable", VerifiedMemory::offset());
1728   }
1729   return offset;
1730 }
1731 
1732 
WriteShadowedField(Register base,intptr_t offset,Register value,Condition cond)1733 void Assembler::WriteShadowedField(Register base,
1734                                    intptr_t offset,
1735                                    Register value,
1736                                    Condition cond) {
1737   if (VerifiedMemory::enabled()) {
1738     ASSERT(base != value);
1739     Operand shadow(GetVerifiedMemoryShadow());
1740     add(base, base, shadow, cond);
1741     str(value, Address(base, offset), cond);
1742     sub(base, base, shadow, cond);
1743   }
1744   str(value, Address(base, offset), cond);
1745 }
1746 
1747 
WriteShadowedFieldPair(Register base,intptr_t offset,Register value_even,Register value_odd,Condition cond)1748 void Assembler::WriteShadowedFieldPair(Register base,
1749                                        intptr_t offset,
1750                                        Register value_even,
1751                                        Register value_odd,
1752                                        Condition cond) {
1753   ASSERT(value_odd == value_even + 1);
1754   if (VerifiedMemory::enabled()) {
1755     ASSERT(base != value_even);
1756     ASSERT(base != value_odd);
1757     Operand shadow(GetVerifiedMemoryShadow());
1758     add(base, base, shadow, cond);
1759     strd(value_even, base, offset, cond);
1760     sub(base, base, shadow, cond);
1761   }
1762   strd(value_even, base, offset, cond);
1763 }
1764 
1765 
UseRegister(Register reg,RegList * used)1766 Register UseRegister(Register reg, RegList* used) {
1767   ASSERT(reg != SP);
1768   ASSERT(reg != PC);
1769   ASSERT((*used & (1 << reg)) == 0);
1770   *used |= (1 << reg);
1771   return reg;
1772 }
1773 
1774 
AllocateRegister(RegList * used)1775 Register AllocateRegister(RegList* used) {
1776   const RegList free = ~*used;
1777   return (free == 0) ?
1778       kNoRegister :
1779       UseRegister(static_cast<Register>(Utils::CountTrailingZeros(free)), used);
1780 }
1781 
1782 
VerifiedWrite(const Address & address,Register new_value,FieldContent old_content)1783 void Assembler::VerifiedWrite(const Address& address,
1784                               Register new_value,
1785                               FieldContent old_content) {
1786 #if defined(DEBUG)
1787   ASSERT(address.mode() == Address::Offset ||
1788          address.mode() == Address::NegOffset);
1789   // Allocate temporary registers (and check for register collisions).
1790   RegList used = 0;
1791   UseRegister(new_value, &used);
1792   Register base = UseRegister(address.rn(), &used);
1793   if (address.rm() != kNoRegister) {
1794     UseRegister(address.rm(), &used);
1795   }
1796   Register old_value = AllocateRegister(&used);
1797   Register temp = AllocateRegister(&used);
1798   PushList(used);
1799   ldr(old_value, address);
1800   // First check that 'old_value' contains 'old_content'.
1801   // Smi test.
1802   tst(old_value, Operand(kHeapObjectTag));
1803   Label ok;
1804   switch (old_content) {
1805     case kOnlySmi:
1806       b(&ok, EQ);  // Smi is OK.
1807       Stop("Expected smi.");
1808       break;
1809     case kHeapObjectOrSmi:
1810       b(&ok, EQ);  // Smi is OK.
1811       // Non-smi case: Verify object pointer is word-aligned when untagged.
1812       COMPILE_ASSERT(kHeapObjectTag == 1);
1813       tst(old_value, Operand((kWordSize - 1) - kHeapObjectTag));
1814       b(&ok, EQ);
1815       Stop("Expected heap object or Smi");
1816       break;
1817     case kEmptyOrSmiOrNull:
1818       b(&ok, EQ);  // Smi is OK.
1819       // Non-smi case: Check for the special zap word or null.
1820       // Note: Cannot use CompareImmediate, since IP may be in use.
1821       LoadImmediate(temp, Heap::kZap32Bits);
1822       cmp(old_value, Operand(temp));
1823       b(&ok, EQ);
1824       LoadObject(temp, Object::null_object());
1825       cmp(old_value, Operand(temp));
1826       b(&ok, EQ);
1827       Stop("Expected zapped, Smi or null");
1828       break;
1829     default:
1830       UNREACHABLE();
1831   }
1832   Bind(&ok);
1833   if (VerifiedMemory::enabled()) {
1834     Operand shadow_offset(GetVerifiedMemoryShadow());
1835     // Adjust the address to shadow.
1836     add(base, base, shadow_offset);
1837     ldr(temp, address);
1838     cmp(old_value, Operand(temp));
1839     Label match;
1840     b(&match, EQ);
1841     Stop("Write barrier verification failed");
1842     Bind(&match);
1843     // Write new value in shadow.
1844     str(new_value, address);
1845     // Restore original address.
1846     sub(base, base, shadow_offset);
1847   }
1848   str(new_value, address);
1849   PopList(used);
1850 #else
1851   str(new_value, address);
1852 #endif  // DEBUG
1853 }
1854 
1855 
StoreIntoObject(Register object,const Address & dest,Register value,bool can_value_be_smi)1856 void Assembler::StoreIntoObject(Register object,
1857                                 const Address& dest,
1858                                 Register value,
1859                                 bool can_value_be_smi) {
1860   ASSERT(object != value);
1861   VerifiedWrite(dest, value, kHeapObjectOrSmi);
1862   Label done;
1863   if (can_value_be_smi) {
1864     StoreIntoObjectFilter(object, value, &done);
1865   } else {
1866     StoreIntoObjectFilterNoSmi(object, value, &done);
1867   }
1868   // A store buffer update is required.
1869   RegList regs = (1 << CODE_REG) | (1 << LR);
1870   if (value != R0) {
1871     regs |= (1 << R0);  // Preserve R0.
1872   }
1873   PushList(regs);
1874   if (object != R0) {
1875     mov(R0, Operand(object));
1876   }
1877   ldr(CODE_REG, Address(THR, Thread::update_store_buffer_code_offset()));
1878   ldr(LR, Address(THR, Thread::update_store_buffer_entry_point_offset()));
1879   blx(LR);
1880   PopList(regs);
1881   Bind(&done);
1882 }
1883 
1884 
StoreIntoObjectOffset(Register object,int32_t offset,Register value,bool can_value_be_smi)1885 void Assembler::StoreIntoObjectOffset(Register object,
1886                                       int32_t offset,
1887                                       Register value,
1888                                       bool can_value_be_smi) {
1889   int32_t ignored = 0;
1890   if (Address::CanHoldStoreOffset(kWord, offset - kHeapObjectTag, &ignored)) {
1891     StoreIntoObject(
1892         object, FieldAddress(object, offset), value, can_value_be_smi);
1893   } else {
1894     AddImmediate(IP, object, offset - kHeapObjectTag);
1895     StoreIntoObject(object, Address(IP), value, can_value_be_smi);
1896   }
1897 }
1898 
1899 
StoreIntoObjectNoBarrier(Register object,const Address & dest,Register value,FieldContent old_content)1900 void Assembler::StoreIntoObjectNoBarrier(Register object,
1901                                          const Address& dest,
1902                                          Register value,
1903                                          FieldContent old_content) {
1904   VerifiedWrite(dest, value, old_content);
1905 #if defined(DEBUG)
1906   Label done;
1907   StoreIntoObjectFilter(object, value, &done);
1908   Stop("Store buffer update is required");
1909   Bind(&done);
1910 #endif  // defined(DEBUG)
1911   // No store buffer update.
1912 }
1913 
1914 
StoreIntoObjectNoBarrierOffset(Register object,int32_t offset,Register value,FieldContent old_content)1915 void Assembler::StoreIntoObjectNoBarrierOffset(Register object,
1916                                                int32_t offset,
1917                                                Register value,
1918                                                FieldContent old_content) {
1919   int32_t ignored = 0;
1920   if (Address::CanHoldStoreOffset(kWord, offset - kHeapObjectTag, &ignored)) {
1921     StoreIntoObjectNoBarrier(object, FieldAddress(object, offset), value,
1922                              old_content);
1923   } else {
1924     AddImmediate(IP, object, offset - kHeapObjectTag);
1925     StoreIntoObjectNoBarrier(object, Address(IP), value, old_content);
1926   }
1927 }
1928 
1929 
StoreIntoObjectNoBarrier(Register object,const Address & dest,const Object & value,FieldContent old_content)1930 void Assembler::StoreIntoObjectNoBarrier(Register object,
1931                                          const Address& dest,
1932                                          const Object& value,
1933                                          FieldContent old_content) {
1934   ASSERT(value.IsSmi() || value.InVMHeap() ||
1935          (value.IsOld() && value.IsNotTemporaryScopedHandle()));
1936   // No store buffer update.
1937   LoadObject(IP, value);
1938   VerifiedWrite(dest, IP, old_content);
1939 }
1940 
1941 
StoreIntoObjectNoBarrierOffset(Register object,int32_t offset,const Object & value,FieldContent old_content)1942 void Assembler::StoreIntoObjectNoBarrierOffset(Register object,
1943                                                int32_t offset,
1944                                                const Object& value,
1945                                                FieldContent old_content) {
1946   int32_t ignored = 0;
1947   if (Address::CanHoldStoreOffset(kWord, offset - kHeapObjectTag, &ignored)) {
1948     StoreIntoObjectNoBarrier(object, FieldAddress(object, offset), value,
1949                              old_content);
1950   } else {
1951     AddImmediate(IP, object, offset - kHeapObjectTag);
1952     StoreIntoObjectNoBarrier(object, Address(IP), value, old_content);
1953   }
1954 }
1955 
1956 
InitializeFieldsNoBarrier(Register object,Register begin,Register end,Register value_even,Register value_odd)1957 void Assembler::InitializeFieldsNoBarrier(Register object,
1958                                           Register begin,
1959                                           Register end,
1960                                           Register value_even,
1961                                           Register value_odd) {
1962   ASSERT(value_odd == value_even + 1);
1963   Label init_loop;
1964   Bind(&init_loop);
1965   AddImmediate(begin, 2 * kWordSize);
1966   cmp(begin, Operand(end));
1967   WriteShadowedFieldPair(begin, -2 * kWordSize, value_even, value_odd, LS);
1968   b(&init_loop, CC);
1969   WriteShadowedField(begin, -2 * kWordSize, value_even, HI);
1970 #if defined(DEBUG)
1971   Label done;
1972   StoreIntoObjectFilter(object, value_even, &done);
1973   StoreIntoObjectFilter(object, value_odd, &done);
1974   Stop("Store buffer update is required");
1975   Bind(&done);
1976 #endif  // defined(DEBUG)
1977   // No store buffer update.
1978 }
1979 
1980 
InitializeFieldsNoBarrierUnrolled(Register object,Register base,intptr_t begin_offset,intptr_t end_offset,Register value_even,Register value_odd)1981 void Assembler::InitializeFieldsNoBarrierUnrolled(Register object,
1982                                                   Register base,
1983                                                   intptr_t begin_offset,
1984                                                   intptr_t end_offset,
1985                                                   Register value_even,
1986                                                   Register value_odd) {
1987   ASSERT(value_odd == value_even + 1);
1988   intptr_t current_offset = begin_offset;
1989   while (current_offset + kWordSize < end_offset) {
1990     WriteShadowedFieldPair(base, current_offset, value_even, value_odd);
1991     current_offset += 2*kWordSize;
1992   }
1993   while (current_offset < end_offset) {
1994     WriteShadowedField(base, current_offset, value_even);
1995     current_offset += kWordSize;
1996   }
1997 #if defined(DEBUG)
1998   Label done;
1999   StoreIntoObjectFilter(object, value_even, &done);
2000   StoreIntoObjectFilter(object, value_odd, &done);
2001   Stop("Store buffer update is required");
2002   Bind(&done);
2003 #endif  // defined(DEBUG)
2004   // No store buffer update.
2005 }
2006 
2007 
StoreIntoSmiField(const Address & dest,Register value)2008 void Assembler::StoreIntoSmiField(const Address& dest, Register value) {
2009 #if defined(DEBUG)
2010   Label done;
2011   tst(value, Operand(kHeapObjectTag));
2012   b(&done, EQ);
2013   Stop("New value must be Smi.");
2014   Bind(&done);
2015 #endif  // defined(DEBUG)
2016   VerifiedWrite(dest, value, kOnlySmi);
2017 }
2018 
2019 
LoadClassId(Register result,Register object,Condition cond)2020 void Assembler::LoadClassId(Register result, Register object, Condition cond) {
2021   ASSERT(RawObject::kClassIdTagPos == 16);
2022   ASSERT(RawObject::kClassIdTagSize == 16);
2023   const intptr_t class_id_offset = Object::tags_offset() +
2024       RawObject::kClassIdTagPos / kBitsPerByte;
2025   ldrh(result, FieldAddress(object, class_id_offset), cond);
2026 }
2027 
2028 
LoadClassById(Register result,Register class_id)2029 void Assembler::LoadClassById(Register result, Register class_id) {
2030   ASSERT(result != class_id);
2031   LoadIsolate(result);
2032   const intptr_t offset =
2033       Isolate::class_table_offset() + ClassTable::table_offset();
2034   LoadFromOffset(kWord, result, result, offset);
2035   ldr(result, Address(result, class_id, LSL, 2));
2036 }
2037 
2038 
LoadClass(Register result,Register object,Register scratch)2039 void Assembler::LoadClass(Register result, Register object, Register scratch) {
2040   ASSERT(scratch != result);
2041   LoadClassId(scratch, object);
2042   LoadClassById(result, scratch);
2043 }
2044 
2045 
CompareClassId(Register object,intptr_t class_id,Register scratch)2046 void Assembler::CompareClassId(Register object,
2047                                intptr_t class_id,
2048                                Register scratch) {
2049   LoadClassId(scratch, object);
2050   CompareImmediate(scratch, class_id);
2051 }
2052 
2053 
LoadClassIdMayBeSmi(Register result,Register object)2054 void Assembler::LoadClassIdMayBeSmi(Register result, Register object) {
2055   tst(object, Operand(kSmiTagMask));
2056   LoadClassId(result, object, NE);
2057   LoadImmediate(result, kSmiCid, EQ);
2058 }
2059 
2060 
LoadTaggedClassIdMayBeSmi(Register result,Register object)2061 void Assembler::LoadTaggedClassIdMayBeSmi(Register result, Register object) {
2062   LoadClassIdMayBeSmi(result, object);
2063   SmiTag(result);
2064 }
2065 
2066 
ComputeRange(Register result,Register value,Register scratch,Label * not_mint)2067 void Assembler::ComputeRange(Register result,
2068                              Register value,
2069                              Register scratch,
2070                              Label* not_mint) {
2071   const Register hi = TMP;
2072   const Register lo = scratch;
2073 
2074   Label done;
2075   mov(result, Operand(value, LSR, kBitsPerWord - 1));
2076   tst(value, Operand(kSmiTagMask));
2077   b(&done, EQ);
2078   CompareClassId(value, kMintCid, result);
2079   b(not_mint, NE);
2080   ldr(hi, FieldAddress(value, Mint::value_offset() + kWordSize));
2081   ldr(lo, FieldAddress(value, Mint::value_offset()));
2082   rsb(result, hi, Operand(ICData::kInt32RangeBit));
2083   cmp(hi, Operand(lo, ASR, kBitsPerWord - 1));
2084   b(&done, EQ);
2085   LoadImmediate(result, ICData::kUint32RangeBit);  // Uint32
2086   tst(hi, Operand(hi));
2087   LoadImmediate(result, ICData::kInt64RangeBit, NE);  // Int64
2088   Bind(&done);
2089 }
2090 
2091 
UpdateRangeFeedback(Register value,intptr_t index,Register ic_data,Register scratch1,Register scratch2,Label * miss)2092 void Assembler::UpdateRangeFeedback(Register value,
2093                                     intptr_t index,
2094                                     Register ic_data,
2095                                     Register scratch1,
2096                                     Register scratch2,
2097                                     Label* miss) {
2098   ASSERT(ICData::IsValidRangeFeedbackIndex(index));
2099   ComputeRange(scratch1, value, scratch2, miss);
2100   ldr(scratch2, FieldAddress(ic_data, ICData::state_bits_offset()));
2101   orr(scratch2,
2102       scratch2,
2103       Operand(scratch1, LSL, ICData::RangeFeedbackShift(index)));
2104   str(scratch2, FieldAddress(ic_data, ICData::state_bits_offset()));
2105 }
2106 
2107 #if 0
2108 // Moved to ::canEncodeBranchoffset() in IceAssemblerARM32.cpp.
2109 static bool CanEncodeBranchOffset(int32_t offset) {
2110   ASSERT(Utils::IsAligned(offset, 4));
2111   // Note: This check doesn't take advantage of the fact that offset>>2
2112   // is stored (allowing two more bits in address space).
2113   return Utils::IsInt(Utils::CountOneBits(kBranchOffsetMask), offset);
2114 }
2115 
2116 // Moved to ARM32::AssemblerARM32::encodeBranchOffset()
2117 int32_t Assembler::EncodeBranchOffset(int32_t offset, int32_t inst) {
2118   // The offset is off by 8 due to the way the ARM CPUs read PC.
2119   offset -= Instr::kPCReadOffset;
2120 
2121   if (!CanEncodeBranchOffset(offset)) {
2122     ASSERT(!use_far_branches());
2123     Thread::Current()->long_jump_base()->Jump(
2124         1, Object::branch_offset_error());
2125   }
2126 
2127   // Properly preserve only the bits supported in the instruction.
2128   offset >>= 2;
2129   offset &= kBranchOffsetMask;
2130   return (inst & ~kBranchOffsetMask) | offset;
2131 }
2132 
2133 // Moved to AssemberARM32::decodeBranchOffset()
2134 int Assembler::DecodeBranchOffset(int32_t inst) {
2135   // Sign-extend, left-shift by 2, then add 8.
2136   return ((((inst & kBranchOffsetMask) << 8) >> 6) + Instr::kPCReadOffset);
2137 }
2138 #endif
2139 
DecodeARMv7LoadImmediate(int32_t movt,int32_t movw)2140 static int32_t DecodeARMv7LoadImmediate(int32_t movt, int32_t movw) {
2141   int32_t offset = 0;
2142   offset |= (movt & 0xf0000) << 12;
2143   offset |= (movt & 0xfff) << 16;
2144   offset |= (movw & 0xf0000) >> 4;
2145   offset |= movw & 0xfff;
2146   return offset;
2147 }
2148 
2149 
DecodeARMv6LoadImmediate(int32_t mov,int32_t or1,int32_t or2,int32_t or3)2150 static int32_t DecodeARMv6LoadImmediate(int32_t mov, int32_t or1,
2151                                         int32_t or2, int32_t or3) {
2152   int32_t offset = 0;
2153   offset |= (mov & 0xff) << 24;
2154   offset |= (or1 & 0xff) << 16;
2155   offset |= (or2 & 0xff) << 8;
2156   offset |= (or3 & 0xff);
2157   return offset;
2158 }
2159 
2160 
2161 class PatchFarBranch : public AssemblerFixup {
2162  public:
PatchFarBranch()2163   PatchFarBranch() {}
2164 
Process(const MemoryRegion & region,intptr_t position)2165   void Process(const MemoryRegion& region, intptr_t position) {
2166     const ARMVersion version = TargetCPUFeatures::arm_version();
2167     if ((version == ARMv5TE) || (version == ARMv6)) {
2168       ProcessARMv6(region, position);
2169     } else {
2170       ASSERT(version == ARMv7);
2171       ProcessARMv7(region, position);
2172     }
2173   }
2174 
2175  private:
ProcessARMv6(const MemoryRegion & region,intptr_t position)2176   void ProcessARMv6(const MemoryRegion& region, intptr_t position) {
2177     const int32_t mov = region.Load<int32_t>(position);
2178     const int32_t or1 = region.Load<int32_t>(position + 1*Instr::kInstrSize);
2179     const int32_t or2 = region.Load<int32_t>(position + 2*Instr::kInstrSize);
2180     const int32_t or3 = region.Load<int32_t>(position + 3*Instr::kInstrSize);
2181     const int32_t bx = region.Load<int32_t>(position + 4*Instr::kInstrSize);
2182 
2183     if (((mov & 0xffffff00) == 0xe3a0c400) &&  // mov IP, (byte3 rot 4)
2184         ((or1 & 0xffffff00) == 0xe38cc800) &&  // orr IP, IP, (byte2 rot 8)
2185         ((or2 & 0xffffff00) == 0xe38ccc00) &&  // orr IP, IP, (byte1 rot 12)
2186         ((or3 & 0xffffff00) == 0xe38cc000)) {  // orr IP, IP, byte0
2187       const int32_t offset = DecodeARMv6LoadImmediate(mov, or1, or2, or3);
2188       const int32_t dest = region.start() + offset;
2189       const int32_t dest0 = (dest & 0x000000ff);
2190       const int32_t dest1 = (dest & 0x0000ff00) >> 8;
2191       const int32_t dest2 = (dest & 0x00ff0000) >> 16;
2192       const int32_t dest3 = (dest & 0xff000000) >> 24;
2193       const int32_t patched_mov = 0xe3a0c400 | dest3;
2194       const int32_t patched_or1 = 0xe38cc800 | dest2;
2195       const int32_t patched_or2 = 0xe38ccc00 | dest1;
2196       const int32_t patched_or3 = 0xe38cc000 | dest0;
2197 
2198       region.Store<int32_t>(position + 0 * Instr::kInstrSize, patched_mov);
2199       region.Store<int32_t>(position + 1 * Instr::kInstrSize, patched_or1);
2200       region.Store<int32_t>(position + 2 * Instr::kInstrSize, patched_or2);
2201       region.Store<int32_t>(position + 3 * Instr::kInstrSize, patched_or3);
2202       return;
2203     }
2204 
2205     // If the offset loading instructions aren't there, we must have replaced
2206     // the far branch with a near one, and so these instructions
2207     // should be NOPs.
2208     ASSERT((or1 == Instr::kNopInstruction) &&
2209            (or2 == Instr::kNopInstruction) &&
2210            (or3 == Instr::kNopInstruction) &&
2211            (bx == Instr::kNopInstruction));
2212   }
2213 
2214 
ProcessARMv7(const MemoryRegion & region,intptr_t position)2215   void ProcessARMv7(const MemoryRegion& region, intptr_t position) {
2216     const int32_t movw = region.Load<int32_t>(position);
2217     const int32_t movt = region.Load<int32_t>(position + Instr::kInstrSize);
2218     const int32_t bx = region.Load<int32_t>(position + 2 * Instr::kInstrSize);
2219 
2220     if (((movt & 0xfff0f000) == 0xe340c000) &&  // movt IP, high
2221         ((movw & 0xfff0f000) == 0xe300c000)) {   // movw IP, low
2222       const int32_t offset = DecodeARMv7LoadImmediate(movt, movw);
2223       const int32_t dest = region.start() + offset;
2224       const uint16_t dest_high = Utils::High16Bits(dest);
2225       const uint16_t dest_low = Utils::Low16Bits(dest);
2226       const int32_t patched_movt =
2227           0xe340c000 | ((dest_high >> 12) << 16) | (dest_high & 0xfff);
2228       const int32_t patched_movw =
2229           0xe300c000 | ((dest_low >> 12) << 16) | (dest_low & 0xfff);
2230 
2231       region.Store<int32_t>(position, patched_movw);
2232       region.Store<int32_t>(position + Instr::kInstrSize, patched_movt);
2233       return;
2234     }
2235 
2236     // If the offset loading instructions aren't there, we must have replaced
2237     // the far branch with a near one, and so these instructions
2238     // should be NOPs.
2239     ASSERT((movt == Instr::kNopInstruction) &&
2240            (bx == Instr::kNopInstruction));
2241   }
2242 
IsPointerOffset() const2243   virtual bool IsPointerOffset() const { return false; }
2244 };
2245 
2246 
EmitFarBranch(Condition cond,int32_t offset,bool link)2247 void Assembler::EmitFarBranch(Condition cond, int32_t offset, bool link) {
2248   buffer_.EmitFixup(new PatchFarBranch());
2249   LoadPatchableImmediate(IP, offset);
2250   if (link) {
2251     blx(IP, cond);
2252   } else {
2253     bx(IP, cond);
2254   }
2255 }
2256 
2257 
EmitBranch(Condition cond,Label * label,bool link)2258 void Assembler::EmitBranch(Condition cond, Label* label, bool link) {
2259   if (label->IsBound()) {
2260     const int32_t dest = label->Position() - buffer_.Size();
2261     if (use_far_branches() && !CanEncodeBranchOffset(dest)) {
2262       EmitFarBranch(cond, label->Position(), link);
2263     } else {
2264       EmitType5(cond, dest, link);
2265     }
2266   } else {
2267     const intptr_t position = buffer_.Size();
2268     if (use_far_branches()) {
2269       const int32_t dest = label->position_;
2270       EmitFarBranch(cond, dest, link);
2271     } else {
2272       // Use the offset field of the branch instruction for linking the sites.
2273       EmitType5(cond, label->position_, link);
2274     }
2275     label->LinkTo(position);
2276   }
2277 }
2278 
2279 
BindARMv6(Label * label)2280 void Assembler::BindARMv6(Label* label) {
2281   ASSERT(!label->IsBound());
2282   intptr_t bound_pc = buffer_.Size();
2283   while (label->IsLinked()) {
2284     const int32_t position = label->Position();
2285     int32_t dest = bound_pc - position;
2286     if (use_far_branches() && !CanEncodeBranchOffset(dest)) {
2287       // Far branches are enabled and we can't encode the branch offset.
2288 
2289       // Grab instructions that load the offset.
2290       const int32_t mov =
2291           buffer_.Load<int32_t>(position);
2292       const int32_t or1 =
2293           buffer_.Load<int32_t>(position + 1 * Instr::kInstrSize);
2294       const int32_t or2 =
2295           buffer_.Load<int32_t>(position + 2 * Instr::kInstrSize);
2296       const int32_t or3 =
2297           buffer_.Load<int32_t>(position + 3 * Instr::kInstrSize);
2298 
2299       // Change from relative to the branch to relative to the assembler
2300       // buffer.
2301       dest = buffer_.Size();
2302       const int32_t dest0 = (dest & 0x000000ff);
2303       const int32_t dest1 = (dest & 0x0000ff00) >> 8;
2304       const int32_t dest2 = (dest & 0x00ff0000) >> 16;
2305       const int32_t dest3 = (dest & 0xff000000) >> 24;
2306       const int32_t patched_mov = 0xe3a0c400 | dest3;
2307       const int32_t patched_or1 = 0xe38cc800 | dest2;
2308       const int32_t patched_or2 = 0xe38ccc00 | dest1;
2309       const int32_t patched_or3 = 0xe38cc000 | dest0;
2310 
2311       // Rewrite the instructions.
2312       buffer_.Store<int32_t>(position + 0 * Instr::kInstrSize, patched_mov);
2313       buffer_.Store<int32_t>(position + 1 * Instr::kInstrSize, patched_or1);
2314       buffer_.Store<int32_t>(position + 2 * Instr::kInstrSize, patched_or2);
2315       buffer_.Store<int32_t>(position + 3 * Instr::kInstrSize, patched_or3);
2316       label->position_ = DecodeARMv6LoadImmediate(mov, or1, or2, or3);
2317     } else if (use_far_branches() && CanEncodeBranchOffset(dest)) {
2318       // Grab instructions that load the offset, and the branch.
2319       const int32_t mov =
2320           buffer_.Load<int32_t>(position);
2321       const int32_t or1 =
2322           buffer_.Load<int32_t>(position + 1 * Instr::kInstrSize);
2323       const int32_t or2 =
2324           buffer_.Load<int32_t>(position + 2 * Instr::kInstrSize);
2325       const int32_t or3 =
2326           buffer_.Load<int32_t>(position + 3 * Instr::kInstrSize);
2327       const int32_t branch =
2328           buffer_.Load<int32_t>(position + 4 * Instr::kInstrSize);
2329 
2330       // Grab the branch condition, and encode the link bit.
2331       const int32_t cond = branch & 0xf0000000;
2332       const int32_t link = (branch & 0x20) << 19;
2333 
2334       // Encode the branch and the offset.
2335       const int32_t new_branch = cond | link | 0x0a000000;
2336       const int32_t encoded = EncodeBranchOffset(dest, new_branch);
2337 
2338       // Write the encoded branch instruction followed by two nops.
2339       buffer_.Store<int32_t>(position, encoded);
2340       buffer_.Store<int32_t>(position + 1 * Instr::kInstrSize,
2341           Instr::kNopInstruction);
2342       buffer_.Store<int32_t>(position + 2 * Instr::kInstrSize,
2343           Instr::kNopInstruction);
2344       buffer_.Store<int32_t>(position + 3 * Instr::kInstrSize,
2345           Instr::kNopInstruction);
2346       buffer_.Store<int32_t>(position + 4 * Instr::kInstrSize,
2347           Instr::kNopInstruction);
2348 
2349       label->position_ = DecodeARMv6LoadImmediate(mov, or1, or2, or3);
2350     } else {
2351       int32_t next = buffer_.Load<int32_t>(position);
2352       int32_t encoded = Assembler::EncodeBranchOffset(dest, next);
2353       buffer_.Store<int32_t>(position, encoded);
2354       label->position_ = Assembler::DecodeBranchOffset(next);
2355     }
2356   }
2357   label->BindTo(bound_pc);
2358 }
2359 
2360 #if 0
2361 // Moved to ARM32::AssemblerARM32::bind(Label* Label)
2362 // Note: Most of this code isn't needed because instruction selection has
2363 // already been handler
2364 void Assembler::BindARMv7(Label* label) {
2365   ASSERT(!label->IsBound());
2366   intptr_t bound_pc = buffer_.Size();
2367   while (label->IsLinked()) {
2368     const int32_t position = label->Position();
2369     int32_t dest = bound_pc - position;
2370     if (use_far_branches() && !CanEncodeBranchOffset(dest)) {
2371       // Far branches are enabled and we can't encode the branch offset.
2372 
2373       // Grab instructions that load the offset.
2374       const int32_t movw =
2375           buffer_.Load<int32_t>(position + 0 * Instr::kInstrSize);
2376       const int32_t movt =
2377           buffer_.Load<int32_t>(position + 1 * Instr::kInstrSize);
2378 
2379       // Change from relative to the branch to relative to the assembler
2380       // buffer.
2381       dest = buffer_.Size();
2382       const uint16_t dest_high = Utils::High16Bits(dest);
2383       const uint16_t dest_low = Utils::Low16Bits(dest);
2384       const int32_t patched_movt =
2385           0xe340c000 | ((dest_high >> 12) << 16) | (dest_high & 0xfff);
2386       const int32_t patched_movw =
2387           0xe300c000 | ((dest_low >> 12) << 16) | (dest_low & 0xfff);
2388 
2389       // Rewrite the instructions.
2390       buffer_.Store<int32_t>(position + 0 * Instr::kInstrSize, patched_movw);
2391       buffer_.Store<int32_t>(position + 1 * Instr::kInstrSize, patched_movt);
2392       label->position_ = DecodeARMv7LoadImmediate(movt, movw);
2393     } else if (use_far_branches() && CanEncodeBranchOffset(dest)) {
2394       // Far branches are enabled, but we can encode the branch offset.
2395 
2396       // Grab instructions that load the offset, and the branch.
2397       const int32_t movw =
2398           buffer_.Load<int32_t>(position + 0 * Instr::kInstrSize);
2399       const int32_t movt =
2400           buffer_.Load<int32_t>(position + 1 * Instr::kInstrSize);
2401       const int32_t branch =
2402           buffer_.Load<int32_t>(position + 2 * Instr::kInstrSize);
2403 
2404       // Grab the branch condition, and encode the link bit.
2405       const int32_t cond = branch & 0xf0000000;
2406       const int32_t link = (branch & 0x20) << 19;
2407 
2408       // Encode the branch and the offset.
2409       const int32_t new_branch = cond | link | 0x0a000000;
2410       const int32_t encoded = EncodeBranchOffset(dest, new_branch);
2411 
2412       // Write the encoded branch instruction followed by two nops.
2413       buffer_.Store<int32_t>(position + 0 * Instr::kInstrSize,
2414           encoded);
2415       buffer_.Store<int32_t>(position + 1 * Instr::kInstrSize,
2416           Instr::kNopInstruction);
2417       buffer_.Store<int32_t>(position + 2 * Instr::kInstrSize,
2418           Instr::kNopInstruction);
2419 
2420       label->position_ = DecodeARMv7LoadImmediate(movt, movw);
2421     } else {
2422       int32_t next = buffer_.Load<int32_t>(position);
2423       int32_t encoded = Assembler::EncodeBranchOffset(dest, next);
2424       buffer_.Store<int32_t>(position, encoded);
2425       label->position_ = Assembler::DecodeBranchOffset(next);
2426     }
2427   }
2428   label->BindTo(bound_pc);
2429 }
2430 #endif
2431 
2432 
Bind(Label * label)2433 void Assembler::Bind(Label* label) {
2434   const ARMVersion version = TargetCPUFeatures::arm_version();
2435   if ((version == ARMv5TE) || (version == ARMv6)) {
2436     BindARMv6(label);
2437   } else {
2438     ASSERT(version == ARMv7);
2439     BindARMv7(label);
2440   }
2441 }
2442 
2443 
OperandSizeFor(intptr_t cid)2444 OperandSize Address::OperandSizeFor(intptr_t cid) {
2445   switch (cid) {
2446     case kArrayCid:
2447     case kImmutableArrayCid:
2448       return kWord;
2449     case kOneByteStringCid:
2450     case kExternalOneByteStringCid:
2451       return kByte;
2452     case kTwoByteStringCid:
2453     case kExternalTwoByteStringCid:
2454       return kHalfword;
2455     case kTypedDataInt8ArrayCid:
2456       return kByte;
2457     case kTypedDataUint8ArrayCid:
2458     case kTypedDataUint8ClampedArrayCid:
2459     case kExternalTypedDataUint8ArrayCid:
2460     case kExternalTypedDataUint8ClampedArrayCid:
2461       return kUnsignedByte;
2462     case kTypedDataInt16ArrayCid:
2463       return kHalfword;
2464     case kTypedDataUint16ArrayCid:
2465       return kUnsignedHalfword;
2466     case kTypedDataInt32ArrayCid:
2467       return kWord;
2468     case kTypedDataUint32ArrayCid:
2469       return kUnsignedWord;
2470     case kTypedDataInt64ArrayCid:
2471     case kTypedDataUint64ArrayCid:
2472       UNREACHABLE();
2473       return kByte;
2474     case kTypedDataFloat32ArrayCid:
2475       return kSWord;
2476     case kTypedDataFloat64ArrayCid:
2477       return kDWord;
2478     case kTypedDataFloat32x4ArrayCid:
2479     case kTypedDataInt32x4ArrayCid:
2480     case kTypedDataFloat64x2ArrayCid:
2481       return kRegList;
2482     case kTypedDataInt8ArrayViewCid:
2483       UNREACHABLE();
2484       return kByte;
2485     default:
2486       UNREACHABLE();
2487       return kByte;
2488   }
2489 }
2490 
2491 
CanHoldLoadOffset(OperandSize size,int32_t offset,int32_t * offset_mask)2492 bool Address::CanHoldLoadOffset(OperandSize size,
2493                                 int32_t offset,
2494                                 int32_t* offset_mask) {
2495   switch (size) {
2496     case kByte:
2497     case kHalfword:
2498     case kUnsignedHalfword:
2499     case kWordPair: {
2500       *offset_mask = 0xff;
2501       return Utils::IsAbsoluteUint(8, offset);  // Addressing mode 3.
2502     }
2503     case kUnsignedByte:
2504     case kWord:
2505     case kUnsignedWord: {
2506       *offset_mask = 0xfff;
2507       return Utils::IsAbsoluteUint(12, offset);  // Addressing mode 2.
2508     }
2509     case kSWord:
2510     case kDWord: {
2511       *offset_mask = 0x3fc;  // Multiple of 4.
2512       // VFP addressing mode.
2513       return (Utils::IsAbsoluteUint(10, offset) && Utils::IsAligned(offset, 4));
2514     }
2515     case kRegList: {
2516       *offset_mask = 0x0;
2517       return offset == 0;
2518     }
2519     default: {
2520       UNREACHABLE();
2521       return false;
2522     }
2523   }
2524 }
2525 
2526 
CanHoldStoreOffset(OperandSize size,int32_t offset,int32_t * offset_mask)2527 bool Address::CanHoldStoreOffset(OperandSize size,
2528                                  int32_t offset,
2529                                  int32_t* offset_mask) {
2530   switch (size) {
2531     case kHalfword:
2532     case kUnsignedHalfword:
2533     case kWordPair: {
2534       *offset_mask = 0xff;
2535       return Utils::IsAbsoluteUint(8, offset);  // Addressing mode 3.
2536     }
2537     case kByte:
2538     case kUnsignedByte:
2539     case kWord:
2540     case kUnsignedWord: {
2541       *offset_mask = 0xfff;
2542       return Utils::IsAbsoluteUint(12, offset);  // Addressing mode 2.
2543     }
2544     case kSWord:
2545     case kDWord: {
2546       *offset_mask = 0x3fc;  // Multiple of 4.
2547       // VFP addressing mode.
2548       return (Utils::IsAbsoluteUint(10, offset) && Utils::IsAligned(offset, 4));
2549     }
2550     case kRegList: {
2551       *offset_mask = 0x0;
2552       return offset == 0;
2553     }
2554     default: {
2555       UNREACHABLE();
2556       return false;
2557     }
2558   }
2559 }
2560 
2561 
CanHoldImmediateOffset(bool is_load,intptr_t cid,int64_t offset)2562 bool Address::CanHoldImmediateOffset(
2563     bool is_load, intptr_t cid, int64_t offset) {
2564   int32_t offset_mask = 0;
2565   if (is_load) {
2566     return CanHoldLoadOffset(OperandSizeFor(cid), offset, &offset_mask);
2567   } else {
2568     return CanHoldStoreOffset(OperandSizeFor(cid), offset, &offset_mask);
2569   }
2570 }
2571 
2572 #if 0
2573 // Moved to ARM32::AssemblerARM32::push().
2574 void Assembler::Push(Register rd, Condition cond) {
2575   str(rd, Address(SP, -kWordSize, Address::PreIndex), cond);
2576 }
2577 
2578 // Moved to ARM32::AssemblerARM32::pop().
2579 void Assembler::Pop(Register rd, Condition cond) {
2580   ldr(rd, Address(SP, kWordSize, Address::PostIndex), cond);
2581 }
2582 
2583 // Moved to ARM32::AssemblerARM32::pushList().
2584 void Assembler::PushList(RegList regs, Condition cond) {
2585   stm(DB_W, SP, regs, cond);
2586 }
2587 
2588 // Moved to ARM32::AssemblerARM32::popList().
2589 void Assembler::PopList(RegList regs, Condition cond) {
2590   ldm(IA_W, SP, regs, cond);
2591 }
2592 #endif
2593 
MoveRegister(Register rd,Register rm,Condition cond)2594 void Assembler::MoveRegister(Register rd, Register rm, Condition cond) {
2595   if (rd != rm) {
2596     mov(rd, Operand(rm), cond);
2597   }
2598 }
2599 
2600 #if 0
2601 // Moved to ARM32::AssemblerARM32::lsl()
2602 void Assembler::Lsl(Register rd, Register rm, const Operand& shift_imm,
2603                     Condition cond) {
2604   ASSERT(shift_imm.type() == 1);
2605   ASSERT(shift_imm.encoding() != 0);  // Do not use Lsl if no shift is wanted.
2606   mov(rd, Operand(rm, LSL, shift_imm.encoding()), cond);
2607 }
2608 
2609 // Moved to ARM32::AssemblerARM32::lsl()
2610 void Assembler::Lsl(Register rd, Register rm, Register rs, Condition cond) {
2611   mov(rd, Operand(rm, LSL, rs), cond);
2612 }
2613 
2614 // Moved to ARM32::AssemblerARM32::lsr()
2615 void Assembler::Lsr(Register rd, Register rm, const Operand& shift_imm,
2616                     Condition cond) {
2617   ASSERT(shift_imm.type() == 1);
2618   uint32_t shift = shift_imm.encoding();
2619   ASSERT(shift != 0);  // Do not use Lsr if no shift is wanted.
2620   if (shift == 32) {
2621     shift = 0;  // Comply to UAL syntax.
2622   }
2623   mov(rd, Operand(rm, LSR, shift), cond);
2624 }
2625 
2626 // Moved to ARM32::AssemblerARM32::lsr()
2627 void Assembler::Lsr(Register rd, Register rm, Register rs, Condition cond) {
2628   mov(rd, Operand(rm, LSR, rs), cond);
2629 }
2630 
2631 // Moved to ARM32::AssemblerARM32::asr()
2632 void Assembler::Asr(Register rd, Register rm, const Operand& shift_imm,
2633                     Condition cond) {
2634   ASSERT(shift_imm.type() == 1);
2635   uint32_t shift = shift_imm.encoding();
2636   ASSERT(shift != 0);  // Do not use Asr if no shift is wanted.
2637   if (shift == 32) {
2638     shift = 0;  // Comply to UAL syntax.
2639   }
2640   mov(rd, Operand(rm, ASR, shift), cond);
2641 }
2642 #endif
2643 
Asrs(Register rd,Register rm,const Operand & shift_imm,Condition cond)2644 void Assembler::Asrs(Register rd, Register rm, const Operand& shift_imm,
2645                      Condition cond) {
2646   ASSERT(shift_imm.type() == 1);
2647   uint32_t shift = shift_imm.encoding();
2648   ASSERT(shift != 0);  // Do not use Asr if no shift is wanted.
2649   if (shift == 32) {
2650     shift = 0;  // Comply to UAL syntax.
2651   }
2652   movs(rd, Operand(rm, ASR, shift), cond);
2653 }
2654 
2655 #if 0
2656 // Moved to ARM32::AssemblerARM32::asr()
2657 void Assembler::Asr(Register rd, Register rm, Register rs, Condition cond) {
2658   mov(rd, Operand(rm, ASR, rs), cond);
2659 }
2660 #endif
2661 
Ror(Register rd,Register rm,const Operand & shift_imm,Condition cond)2662 void Assembler::Ror(Register rd, Register rm, const Operand& shift_imm,
2663                     Condition cond) {
2664   ASSERT(shift_imm.type() == 1);
2665   ASSERT(shift_imm.encoding() != 0);  // Use Rrx instruction.
2666   mov(rd, Operand(rm, ROR, shift_imm.encoding()), cond);
2667 }
2668 
2669 
Ror(Register rd,Register rm,Register rs,Condition cond)2670 void Assembler::Ror(Register rd, Register rm, Register rs, Condition cond) {
2671   mov(rd, Operand(rm, ROR, rs), cond);
2672 }
2673 
2674 
Rrx(Register rd,Register rm,Condition cond)2675 void Assembler::Rrx(Register rd, Register rm, Condition cond) {
2676   mov(rd, Operand(rm, ROR, 0), cond);
2677 }
2678 
2679 
SignFill(Register rd,Register rm,Condition cond)2680 void Assembler::SignFill(Register rd, Register rm, Condition cond) {
2681   Asr(rd, rm, Operand(31), cond);
2682 }
2683 
2684 
Vreciprocalqs(QRegister qd,QRegister qm)2685 void Assembler::Vreciprocalqs(QRegister qd, QRegister qm) {
2686   ASSERT(qm != QTMP);
2687   ASSERT(qd != QTMP);
2688 
2689   // Reciprocal estimate.
2690   vrecpeqs(qd, qm);
2691   // 2 Newton-Raphson steps.
2692   vrecpsqs(QTMP, qm, qd);
2693   vmulqs(qd, qd, QTMP);
2694   vrecpsqs(QTMP, qm, qd);
2695   vmulqs(qd, qd, QTMP);
2696 }
2697 
2698 
VreciprocalSqrtqs(QRegister qd,QRegister qm)2699 void Assembler::VreciprocalSqrtqs(QRegister qd, QRegister qm) {
2700   ASSERT(qm != QTMP);
2701   ASSERT(qd != QTMP);
2702 
2703   // Reciprocal square root estimate.
2704   vrsqrteqs(qd, qm);
2705   // 2 Newton-Raphson steps. xn+1 = xn * (3 - Q1*xn^2) / 2.
2706   // First step.
2707   vmulqs(QTMP, qd, qd);  // QTMP <- xn^2
2708   vrsqrtsqs(QTMP, qm, QTMP);  // QTMP <- (3 - Q1*QTMP) / 2.
2709   vmulqs(qd, qd, QTMP);  // xn+1 <- xn * QTMP
2710   // Second step.
2711   vmulqs(QTMP, qd, qd);
2712   vrsqrtsqs(QTMP, qm, QTMP);
2713   vmulqs(qd, qd, QTMP);
2714 }
2715 
2716 
Vsqrtqs(QRegister qd,QRegister qm,QRegister temp)2717 void Assembler::Vsqrtqs(QRegister qd, QRegister qm, QRegister temp) {
2718   ASSERT(temp != QTMP);
2719   ASSERT(qm != QTMP);
2720   ASSERT(qd != QTMP);
2721 
2722   if (temp != kNoQRegister) {
2723     vmovq(temp, qm);
2724     qm = temp;
2725   }
2726 
2727   VreciprocalSqrtqs(qd, qm);
2728   vmovq(qm, qd);
2729   Vreciprocalqs(qd, qm);
2730 }
2731 
2732 
Vdivqs(QRegister qd,QRegister qn,QRegister qm)2733 void Assembler::Vdivqs(QRegister qd, QRegister qn, QRegister qm) {
2734   ASSERT(qd != QTMP);
2735   ASSERT(qn != QTMP);
2736   ASSERT(qm != QTMP);
2737 
2738   Vreciprocalqs(qd, qm);
2739   vmulqs(qd, qn, qd);
2740 }
2741 
2742 
Branch(const StubEntry & stub_entry,Patchability patchable,Register pp,Condition cond)2743 void Assembler::Branch(const StubEntry& stub_entry,
2744                        Patchability patchable,
2745                        Register pp,
2746                        Condition cond) {
2747   const Code& target_code = Code::Handle(stub_entry.code());
2748   const int32_t offset = ObjectPool::element_offset(
2749       object_pool_wrapper_.FindObject(target_code, patchable));
2750   LoadWordFromPoolOffset(CODE_REG, offset - kHeapObjectTag, pp, cond);
2751   ldr(IP, FieldAddress(CODE_REG, Code::entry_point_offset()), cond);
2752   bx(IP, cond);
2753 }
2754 
2755 
BranchLink(const Code & target,Patchability patchable)2756 void Assembler::BranchLink(const Code& target, Patchability patchable) {
2757   // Make sure that class CallPattern is able to patch the label referred
2758   // to by this code sequence.
2759   // For added code robustness, use 'blx lr' in a patchable sequence and
2760   // use 'blx ip' in a non-patchable sequence (see other BranchLink flavors).
2761   const int32_t offset = ObjectPool::element_offset(
2762       object_pool_wrapper_.FindObject(target, patchable));
2763   LoadWordFromPoolOffset(CODE_REG, offset - kHeapObjectTag, PP, AL);
2764   ldr(LR, FieldAddress(CODE_REG, Code::entry_point_offset()));
2765   blx(LR);  // Use blx instruction so that the return branch prediction works.
2766 }
2767 
2768 
BranchLink(const StubEntry & stub_entry,Patchability patchable)2769 void Assembler::BranchLink(const StubEntry& stub_entry,
2770                            Patchability patchable) {
2771   const Code& code = Code::Handle(stub_entry.code());
2772   BranchLink(code, patchable);
2773 }
2774 
2775 
BranchLinkPatchable(const Code & target)2776 void Assembler::BranchLinkPatchable(const Code& target) {
2777   BranchLink(target, kPatchable);
2778 }
2779 
2780 
BranchLink(const ExternalLabel * label)2781 void Assembler::BranchLink(const ExternalLabel* label) {
2782   LoadImmediate(LR, label->address());  // Target address is never patched.
2783   blx(LR);  // Use blx instruction so that the return branch prediction works.
2784 }
2785 
2786 
BranchLinkPatchable(const StubEntry & stub_entry)2787 void Assembler::BranchLinkPatchable(const StubEntry& stub_entry) {
2788   BranchLinkPatchable(Code::Handle(stub_entry.code()));
2789 }
2790 
2791 
BranchLinkOffset(Register base,int32_t offset)2792 void Assembler::BranchLinkOffset(Register base, int32_t offset) {
2793   ASSERT(base != PC);
2794   ASSERT(base != IP);
2795   LoadFromOffset(kWord, IP, base, offset);
2796   blx(IP);  // Use blx instruction so that the return branch prediction works.
2797 }
2798 
2799 
LoadPatchableImmediate(Register rd,int32_t value,Condition cond)2800 void Assembler::LoadPatchableImmediate(
2801     Register rd, int32_t value, Condition cond) {
2802   const ARMVersion version = TargetCPUFeatures::arm_version();
2803   if ((version == ARMv5TE) || (version == ARMv6)) {
2804     // This sequence is patched in a few places, and should remain fixed.
2805     const uint32_t byte0 = (value & 0x000000ff);
2806     const uint32_t byte1 = (value & 0x0000ff00) >> 8;
2807     const uint32_t byte2 = (value & 0x00ff0000) >> 16;
2808     const uint32_t byte3 = (value & 0xff000000) >> 24;
2809     mov(rd, Operand(4, byte3), cond);
2810     orr(rd, rd, Operand(8, byte2), cond);
2811     orr(rd, rd, Operand(12, byte1), cond);
2812     orr(rd, rd, Operand(byte0), cond);
2813   } else {
2814     ASSERT(version == ARMv7);
2815     const uint16_t value_low = Utils::Low16Bits(value);
2816     const uint16_t value_high = Utils::High16Bits(value);
2817     movw(rd, value_low, cond);
2818     movt(rd, value_high, cond);
2819   }
2820 }
2821 
2822 
LoadDecodableImmediate(Register rd,int32_t value,Condition cond)2823 void Assembler::LoadDecodableImmediate(
2824     Register rd, int32_t value, Condition cond) {
2825   const ARMVersion version = TargetCPUFeatures::arm_version();
2826   if ((version == ARMv5TE) || (version == ARMv6)) {
2827     if (constant_pool_allowed()) {
2828       const int32_t offset = Array::element_offset(FindImmediate(value));
2829       LoadWordFromPoolOffset(rd, offset - kHeapObjectTag, PP, cond);
2830     } else {
2831       LoadPatchableImmediate(rd, value, cond);
2832     }
2833   } else {
2834     ASSERT(version == ARMv7);
2835     movw(rd, Utils::Low16Bits(value), cond);
2836     const uint16_t value_high = Utils::High16Bits(value);
2837     if (value_high != 0) {
2838       movt(rd, value_high, cond);
2839     }
2840   }
2841 }
2842 
2843 
LoadImmediate(Register rd,int32_t value,Condition cond)2844 void Assembler::LoadImmediate(Register rd, int32_t value, Condition cond) {
2845   Operand o;
2846   if (Operand::CanHold(value, &o)) {
2847     mov(rd, o, cond);
2848   } else if (Operand::CanHold(~value, &o)) {
2849     mvn(rd, o, cond);
2850   } else {
2851     LoadDecodableImmediate(rd, value, cond);
2852   }
2853 }
2854 
2855 
LoadSImmediate(SRegister sd,float value,Condition cond)2856 void Assembler::LoadSImmediate(SRegister sd, float value, Condition cond) {
2857   if (!vmovs(sd, value, cond)) {
2858     const DRegister dd = static_cast<DRegister>(sd >> 1);
2859     const int index = sd & 1;
2860     LoadImmediate(IP, bit_cast<int32_t, float>(value), cond);
2861     vmovdr(dd, index, IP, cond);
2862   }
2863 }
2864 
2865 
LoadDImmediate(DRegister dd,double value,Register scratch,Condition cond)2866 void Assembler::LoadDImmediate(DRegister dd,
2867                                double value,
2868                                Register scratch,
2869                                Condition cond) {
2870   ASSERT(scratch != PC);
2871   ASSERT(scratch != IP);
2872   if (!vmovd(dd, value, cond)) {
2873     // A scratch register and IP are needed to load an arbitrary double.
2874     ASSERT(scratch != kNoRegister);
2875     int64_t imm64 = bit_cast<int64_t, double>(value);
2876     LoadImmediate(IP, Utils::Low32Bits(imm64), cond);
2877     LoadImmediate(scratch, Utils::High32Bits(imm64), cond);
2878     vmovdrr(dd, IP, scratch, cond);
2879   }
2880 }
2881 
2882 
LoadFromOffset(OperandSize size,Register reg,Register base,int32_t offset,Condition cond)2883 void Assembler::LoadFromOffset(OperandSize size,
2884                                Register reg,
2885                                Register base,
2886                                int32_t offset,
2887                                Condition cond) {
2888   int32_t offset_mask = 0;
2889   if (!Address::CanHoldLoadOffset(size, offset, &offset_mask)) {
2890     ASSERT(base != IP);
2891     AddImmediate(IP, base, offset & ~offset_mask, cond);
2892     base = IP;
2893     offset = offset & offset_mask;
2894   }
2895   switch (size) {
2896     case kByte:
2897       ldrsb(reg, Address(base, offset), cond);
2898       break;
2899     case kUnsignedByte:
2900       ldrb(reg, Address(base, offset), cond);
2901       break;
2902     case kHalfword:
2903       ldrsh(reg, Address(base, offset), cond);
2904       break;
2905     case kUnsignedHalfword:
2906       ldrh(reg, Address(base, offset), cond);
2907       break;
2908     case kWord:
2909       ldr(reg, Address(base, offset), cond);
2910       break;
2911     case kWordPair:
2912       ldrd(reg, base, offset, cond);
2913       break;
2914     default:
2915       UNREACHABLE();
2916   }
2917 }
2918 
2919 
StoreToOffset(OperandSize size,Register reg,Register base,int32_t offset,Condition cond)2920 void Assembler::StoreToOffset(OperandSize size,
2921                               Register reg,
2922                               Register base,
2923                               int32_t offset,
2924                               Condition cond) {
2925   int32_t offset_mask = 0;
2926   if (!Address::CanHoldStoreOffset(size, offset, &offset_mask)) {
2927     ASSERT(reg != IP);
2928     ASSERT(base != IP);
2929     AddImmediate(IP, base, offset & ~offset_mask, cond);
2930     base = IP;
2931     offset = offset & offset_mask;
2932   }
2933   switch (size) {
2934     case kByte:
2935       strb(reg, Address(base, offset), cond);
2936       break;
2937     case kHalfword:
2938       strh(reg, Address(base, offset), cond);
2939       break;
2940     case kWord:
2941       str(reg, Address(base, offset), cond);
2942       break;
2943     case kWordPair:
2944       strd(reg, base, offset, cond);
2945       break;
2946     default:
2947       UNREACHABLE();
2948   }
2949 }
2950 
2951 
LoadSFromOffset(SRegister reg,Register base,int32_t offset,Condition cond)2952 void Assembler::LoadSFromOffset(SRegister reg,
2953                                 Register base,
2954                                 int32_t offset,
2955                                 Condition cond) {
2956   int32_t offset_mask = 0;
2957   if (!Address::CanHoldLoadOffset(kSWord, offset, &offset_mask)) {
2958     ASSERT(base != IP);
2959     AddImmediate(IP, base, offset & ~offset_mask, cond);
2960     base = IP;
2961     offset = offset & offset_mask;
2962   }
2963   vldrs(reg, Address(base, offset), cond);
2964 }
2965 
2966 
StoreSToOffset(SRegister reg,Register base,int32_t offset,Condition cond)2967 void Assembler::StoreSToOffset(SRegister reg,
2968                                Register base,
2969                                int32_t offset,
2970                                Condition cond) {
2971   int32_t offset_mask = 0;
2972   if (!Address::CanHoldStoreOffset(kSWord, offset, &offset_mask)) {
2973     ASSERT(base != IP);
2974     AddImmediate(IP, base, offset & ~offset_mask, cond);
2975     base = IP;
2976     offset = offset & offset_mask;
2977   }
2978   vstrs(reg, Address(base, offset), cond);
2979 }
2980 
2981 
LoadDFromOffset(DRegister reg,Register base,int32_t offset,Condition cond)2982 void Assembler::LoadDFromOffset(DRegister reg,
2983                                 Register base,
2984                                 int32_t offset,
2985                                 Condition cond) {
2986   int32_t offset_mask = 0;
2987   if (!Address::CanHoldLoadOffset(kDWord, offset, &offset_mask)) {
2988     ASSERT(base != IP);
2989     AddImmediate(IP, base, offset & ~offset_mask, cond);
2990     base = IP;
2991     offset = offset & offset_mask;
2992   }
2993   vldrd(reg, Address(base, offset), cond);
2994 }
2995 
2996 
StoreDToOffset(DRegister reg,Register base,int32_t offset,Condition cond)2997 void Assembler::StoreDToOffset(DRegister reg,
2998                                Register base,
2999                                int32_t offset,
3000                                Condition cond) {
3001   int32_t offset_mask = 0;
3002   if (!Address::CanHoldStoreOffset(kDWord, offset, &offset_mask)) {
3003     ASSERT(base != IP);
3004     AddImmediate(IP, base, offset & ~offset_mask, cond);
3005     base = IP;
3006     offset = offset & offset_mask;
3007   }
3008   vstrd(reg, Address(base, offset), cond);
3009 }
3010 
3011 
LoadMultipleDFromOffset(DRegister first,intptr_t count,Register base,int32_t offset)3012 void Assembler::LoadMultipleDFromOffset(DRegister first,
3013                                         intptr_t count,
3014                                         Register base,
3015                                         int32_t offset) {
3016   ASSERT(base != IP);
3017   AddImmediate(IP, base, offset);
3018   vldmd(IA, IP, first, count);
3019 }
3020 
StoreMultipleDToOffset(DRegister first,intptr_t count,Register base,int32_t offset)3021 void Assembler::StoreMultipleDToOffset(DRegister first,
3022                                        intptr_t count,
3023                                        Register base,
3024                                        int32_t offset) {
3025   ASSERT(base != IP);
3026   AddImmediate(IP, base, offset);
3027   vstmd(IA, IP, first, count);
3028 }
3029 
3030 
CopyDoubleField(Register dst,Register src,Register tmp1,Register tmp2,DRegister dtmp)3031 void Assembler::CopyDoubleField(
3032     Register dst, Register src, Register tmp1, Register tmp2, DRegister dtmp) {
3033   if (TargetCPUFeatures::vfp_supported()) {
3034     LoadDFromOffset(dtmp, src, Double::value_offset() - kHeapObjectTag);
3035     StoreDToOffset(dtmp, dst, Double::value_offset() - kHeapObjectTag);
3036   } else {
3037     LoadFromOffset(kWord, tmp1, src,
3038         Double::value_offset() - kHeapObjectTag);
3039     LoadFromOffset(kWord, tmp2, src,
3040         Double::value_offset() + kWordSize - kHeapObjectTag);
3041     StoreToOffset(kWord, tmp1, dst,
3042         Double::value_offset() - kHeapObjectTag);
3043     StoreToOffset(kWord, tmp2, dst,
3044         Double::value_offset() + kWordSize - kHeapObjectTag);
3045   }
3046 }
3047 
3048 
CopyFloat32x4Field(Register dst,Register src,Register tmp1,Register tmp2,DRegister dtmp)3049 void Assembler::CopyFloat32x4Field(
3050     Register dst, Register src, Register tmp1, Register tmp2, DRegister dtmp) {
3051   if (TargetCPUFeatures::neon_supported()) {
3052     LoadMultipleDFromOffset(dtmp, 2, src,
3053         Float32x4::value_offset() - kHeapObjectTag);
3054     StoreMultipleDToOffset(dtmp, 2, dst,
3055         Float32x4::value_offset() - kHeapObjectTag);
3056   } else {
3057     LoadFromOffset(kWord, tmp1, src,
3058         (Float32x4::value_offset() + 0 * kWordSize) - kHeapObjectTag);
3059     LoadFromOffset(kWord, tmp2, src,
3060         (Float32x4::value_offset() + 1 * kWordSize) - kHeapObjectTag);
3061     StoreToOffset(kWord, tmp1, dst,
3062         (Float32x4::value_offset() + 0 * kWordSize) - kHeapObjectTag);
3063     StoreToOffset(kWord, tmp2, dst,
3064         (Float32x4::value_offset() + 1 * kWordSize) - kHeapObjectTag);
3065 
3066     LoadFromOffset(kWord, tmp1, src,
3067         (Float32x4::value_offset() + 2 * kWordSize) - kHeapObjectTag);
3068     LoadFromOffset(kWord, tmp2, src,
3069         (Float32x4::value_offset() + 3 * kWordSize) - kHeapObjectTag);
3070     StoreToOffset(kWord, tmp1, dst,
3071         (Float32x4::value_offset() + 2 * kWordSize) - kHeapObjectTag);
3072     StoreToOffset(kWord, tmp2, dst,
3073         (Float32x4::value_offset() + 3 * kWordSize) - kHeapObjectTag);
3074   }
3075 }
3076 
3077 
CopyFloat64x2Field(Register dst,Register src,Register tmp1,Register tmp2,DRegister dtmp)3078 void Assembler::CopyFloat64x2Field(
3079     Register dst, Register src, Register tmp1, Register tmp2, DRegister dtmp) {
3080   if (TargetCPUFeatures::neon_supported()) {
3081     LoadMultipleDFromOffset(dtmp, 2, src,
3082         Float64x2::value_offset() - kHeapObjectTag);
3083     StoreMultipleDToOffset(dtmp, 2, dst,
3084         Float64x2::value_offset() - kHeapObjectTag);
3085   } else {
3086     LoadFromOffset(kWord, tmp1, src,
3087         (Float64x2::value_offset() + 0 * kWordSize) - kHeapObjectTag);
3088     LoadFromOffset(kWord, tmp2, src,
3089         (Float64x2::value_offset() + 1 * kWordSize) - kHeapObjectTag);
3090     StoreToOffset(kWord, tmp1, dst,
3091         (Float64x2::value_offset() + 0 * kWordSize) - kHeapObjectTag);
3092     StoreToOffset(kWord, tmp2, dst,
3093         (Float64x2::value_offset() + 1 * kWordSize) - kHeapObjectTag);
3094 
3095     LoadFromOffset(kWord, tmp1, src,
3096         (Float64x2::value_offset() + 2 * kWordSize) - kHeapObjectTag);
3097     LoadFromOffset(kWord, tmp2, src,
3098         (Float64x2::value_offset() + 3 * kWordSize) - kHeapObjectTag);
3099     StoreToOffset(kWord, tmp1, dst,
3100         (Float64x2::value_offset() + 2 * kWordSize) - kHeapObjectTag);
3101     StoreToOffset(kWord, tmp2, dst,
3102         (Float64x2::value_offset() + 3 * kWordSize) - kHeapObjectTag);
3103   }
3104 }
3105 
3106 
AddImmediate(Register rd,int32_t value,Condition cond)3107 void Assembler::AddImmediate(Register rd, int32_t value, Condition cond) {
3108   AddImmediate(rd, rd, value, cond);
3109 }
3110 
3111 
AddImmediate(Register rd,Register rn,int32_t value,Condition cond)3112 void Assembler::AddImmediate(Register rd, Register rn, int32_t value,
3113                              Condition cond) {
3114   if (value == 0) {
3115     if (rd != rn) {
3116       mov(rd, Operand(rn), cond);
3117     }
3118     return;
3119   }
3120   // We prefer to select the shorter code sequence rather than selecting add for
3121   // positive values and sub for negatives ones, which would slightly improve
3122   // the readability of generated code for some constants.
3123   Operand o;
3124   if (Operand::CanHold(value, &o)) {
3125     add(rd, rn, o, cond);
3126   } else if (Operand::CanHold(-value, &o)) {
3127     sub(rd, rn, o, cond);
3128   } else {
3129     ASSERT(rn != IP);
3130     if (Operand::CanHold(~value, &o)) {
3131       mvn(IP, o, cond);
3132       add(rd, rn, Operand(IP), cond);
3133     } else if (Operand::CanHold(~(-value), &o)) {
3134       mvn(IP, o, cond);
3135       sub(rd, rn, Operand(IP), cond);
3136     } else {
3137       LoadDecodableImmediate(IP, value, cond);
3138       add(rd, rn, Operand(IP), cond);
3139     }
3140   }
3141 }
3142 
3143 
AddImmediateSetFlags(Register rd,Register rn,int32_t value,Condition cond)3144 void Assembler::AddImmediateSetFlags(Register rd, Register rn, int32_t value,
3145                                      Condition cond) {
3146   Operand o;
3147   if (Operand::CanHold(value, &o)) {
3148     // Handles value == kMinInt32.
3149     adds(rd, rn, o, cond);
3150   } else if (Operand::CanHold(-value, &o)) {
3151     ASSERT(value != kMinInt32);  // Would cause erroneous overflow detection.
3152     subs(rd, rn, o, cond);
3153   } else {
3154     ASSERT(rn != IP);
3155     if (Operand::CanHold(~value, &o)) {
3156       mvn(IP, o, cond);
3157       adds(rd, rn, Operand(IP), cond);
3158     } else if (Operand::CanHold(~(-value), &o)) {
3159       ASSERT(value != kMinInt32);  // Would cause erroneous overflow detection.
3160       mvn(IP, o, cond);
3161       subs(rd, rn, Operand(IP), cond);
3162     } else {
3163       LoadDecodableImmediate(IP, value, cond);
3164       adds(rd, rn, Operand(IP), cond);
3165     }
3166   }
3167 }
3168 
3169 
SubImmediateSetFlags(Register rd,Register rn,int32_t value,Condition cond)3170 void Assembler::SubImmediateSetFlags(Register rd, Register rn, int32_t value,
3171                                     Condition cond) {
3172   Operand o;
3173   if (Operand::CanHold(value, &o)) {
3174     // Handles value == kMinInt32.
3175     subs(rd, rn, o, cond);
3176   } else if (Operand::CanHold(-value, &o)) {
3177     ASSERT(value != kMinInt32);  // Would cause erroneous overflow detection.
3178     adds(rd, rn, o, cond);
3179   } else {
3180     ASSERT(rn != IP);
3181     if (Operand::CanHold(~value, &o)) {
3182       mvn(IP, o, cond);
3183       subs(rd, rn, Operand(IP), cond);
3184     } else if (Operand::CanHold(~(-value), &o)) {
3185       ASSERT(value != kMinInt32);  // Would cause erroneous overflow detection.
3186       mvn(IP, o, cond);
3187       adds(rd, rn, Operand(IP), cond);
3188     } else {
3189       LoadDecodableImmediate(IP, value, cond);
3190       subs(rd, rn, Operand(IP), cond);
3191     }
3192   }
3193 }
3194 
3195 
AndImmediate(Register rd,Register rs,int32_t imm,Condition cond)3196 void Assembler::AndImmediate(Register rd, Register rs, int32_t imm,
3197                              Condition cond) {
3198   Operand o;
3199   if (Operand::CanHold(imm, &o)) {
3200     and_(rd, rs, Operand(o), cond);
3201   } else {
3202     LoadImmediate(TMP, imm, cond);
3203     and_(rd, rs, Operand(TMP), cond);
3204   }
3205 }
3206 
3207 
CompareImmediate(Register rn,int32_t value,Condition cond)3208 void Assembler::CompareImmediate(Register rn, int32_t value, Condition cond) {
3209   Operand o;
3210   if (Operand::CanHold(value, &o)) {
3211     cmp(rn, o, cond);
3212   } else {
3213     ASSERT(rn != IP);
3214     LoadImmediate(IP, value, cond);
3215     cmp(rn, Operand(IP), cond);
3216   }
3217 }
3218 
3219 
TestImmediate(Register rn,int32_t imm,Condition cond)3220 void Assembler::TestImmediate(Register rn, int32_t imm, Condition cond) {
3221   Operand o;
3222   if (Operand::CanHold(imm, &o)) {
3223     tst(rn, o, cond);
3224   } else {
3225     LoadImmediate(IP, imm);
3226     tst(rn, Operand(IP), cond);
3227   }
3228 }
3229 
IntegerDivide(Register result,Register left,Register right,DRegister tmpl,DRegister tmpr)3230 void Assembler::IntegerDivide(Register result, Register left, Register right,
3231                               DRegister tmpl, DRegister tmpr) {
3232   ASSERT(tmpl != tmpr);
3233   if (TargetCPUFeatures::integer_division_supported()) {
3234     sdiv(result, left, right);
3235   } else {
3236     ASSERT(TargetCPUFeatures::vfp_supported());
3237     SRegister stmpl = static_cast<SRegister>(2 * tmpl);
3238     SRegister stmpr = static_cast<SRegister>(2 * tmpr);
3239     vmovsr(stmpl, left);
3240     vcvtdi(tmpl, stmpl);  // left is in tmpl.
3241     vmovsr(stmpr, right);
3242     vcvtdi(tmpr, stmpr);  // right is in tmpr.
3243     vdivd(tmpr, tmpl, tmpr);
3244     vcvtid(stmpr, tmpr);
3245     vmovrs(result, stmpr);
3246   }
3247 }
3248 
3249 
NumRegsBelowFP(RegList regs)3250 static int NumRegsBelowFP(RegList regs) {
3251   int count = 0;
3252   for (int i = 0; i < FP; i++) {
3253     if ((regs & (1 << i)) != 0) {
3254       count++;
3255     }
3256   }
3257   return count;
3258 }
3259 
3260 
EnterFrame(RegList regs,intptr_t frame_size)3261 void Assembler::EnterFrame(RegList regs, intptr_t frame_size) {
3262   if (prologue_offset_ == -1) {
3263     prologue_offset_ = CodeSize();
3264   }
3265   PushList(regs);
3266   if ((regs & (1 << FP)) != 0) {
3267     // Set FP to the saved previous FP.
3268     add(FP, SP, Operand(4 * NumRegsBelowFP(regs)));
3269   }
3270   AddImmediate(SP, -frame_size);
3271 }
3272 
3273 
LeaveFrame(RegList regs)3274 void Assembler::LeaveFrame(RegList regs) {
3275   ASSERT((regs & (1 << PC)) == 0);  // Must not pop PC.
3276   if ((regs & (1 << FP)) != 0) {
3277     // Use FP to set SP.
3278     sub(SP, FP, Operand(4 * NumRegsBelowFP(regs)));
3279   }
3280   PopList(regs);
3281 }
3282 
3283 
Ret()3284 void Assembler::Ret() {
3285   bx(LR);
3286 }
3287 
3288 
ReserveAlignedFrameSpace(intptr_t frame_space)3289 void Assembler::ReserveAlignedFrameSpace(intptr_t frame_space) {
3290   // Reserve space for arguments and align frame before entering
3291   // the C++ world.
3292   AddImmediate(SP, -frame_space);
3293   if (OS::ActivationFrameAlignment() > 1) {
3294     bic(SP, SP, Operand(OS::ActivationFrameAlignment() - 1));
3295   }
3296 }
3297 
3298 
EnterCallRuntimeFrame(intptr_t frame_space)3299 void Assembler::EnterCallRuntimeFrame(intptr_t frame_space) {
3300   // Preserve volatile CPU registers and PP.
3301   EnterFrame(kDartVolatileCpuRegs | (1 << PP) | (1 << FP), 0);
3302   COMPILE_ASSERT((kDartVolatileCpuRegs & (1 << PP)) == 0);
3303 
3304   // Preserve all volatile FPU registers.
3305   if (TargetCPUFeatures::vfp_supported()) {
3306     DRegister firstv = EvenDRegisterOf(kDartFirstVolatileFpuReg);
3307     DRegister lastv = OddDRegisterOf(kDartLastVolatileFpuReg);
3308     if ((lastv - firstv + 1) >= 16) {
3309       DRegister mid = static_cast<DRegister>(firstv + 16);
3310       vstmd(DB_W, SP, mid, lastv - mid + 1);
3311       vstmd(DB_W, SP, firstv, 16);
3312     } else {
3313       vstmd(DB_W, SP, firstv, lastv - firstv + 1);
3314     }
3315   }
3316 
3317   LoadPoolPointer();
3318 
3319   ReserveAlignedFrameSpace(frame_space);
3320 }
3321 
3322 
LeaveCallRuntimeFrame()3323 void Assembler::LeaveCallRuntimeFrame() {
3324   // SP might have been modified to reserve space for arguments
3325   // and ensure proper alignment of the stack frame.
3326   // We need to restore it before restoring registers.
3327   const intptr_t kPushedFpuRegisterSize =
3328       TargetCPUFeatures::vfp_supported() ?
3329       kDartVolatileFpuRegCount * kFpuRegisterSize : 0;
3330 
3331   COMPILE_ASSERT(PP < FP);
3332   COMPILE_ASSERT((kDartVolatileCpuRegs & (1 << PP)) == 0);
3333   // kVolatileCpuRegCount +1 for PP, -1 because even though LR is volatile,
3334   // it is pushed ahead of FP.
3335   const intptr_t kPushedRegistersSize =
3336       kDartVolatileCpuRegCount * kWordSize + kPushedFpuRegisterSize;
3337   AddImmediate(SP, FP, -kPushedRegistersSize);
3338 
3339   // Restore all volatile FPU registers.
3340   if (TargetCPUFeatures::vfp_supported()) {
3341     DRegister firstv = EvenDRegisterOf(kDartFirstVolatileFpuReg);
3342     DRegister lastv = OddDRegisterOf(kDartLastVolatileFpuReg);
3343     if ((lastv - firstv + 1) >= 16) {
3344       DRegister mid = static_cast<DRegister>(firstv + 16);
3345       vldmd(IA_W, SP, firstv, 16);
3346       vldmd(IA_W, SP, mid, lastv - mid + 1);
3347     } else {
3348       vldmd(IA_W, SP, firstv, lastv - firstv + 1);
3349     }
3350   }
3351 
3352   // Restore volatile CPU registers.
3353   LeaveFrame(kDartVolatileCpuRegs | (1 << PP) | (1 << FP));
3354 }
3355 
3356 
CallRuntime(const RuntimeEntry & entry,intptr_t argument_count)3357 void Assembler::CallRuntime(const RuntimeEntry& entry,
3358                             intptr_t argument_count) {
3359   entry.Call(this, argument_count);
3360 }
3361 
3362 
EnterDartFrame(intptr_t frame_size)3363 void Assembler::EnterDartFrame(intptr_t frame_size) {
3364   ASSERT(!constant_pool_allowed());
3365 
3366   // Registers are pushed in descending order: R9 | R10 | R11 | R14.
3367   EnterFrame((1 << PP) | (1 << CODE_REG) | (1 << FP) | (1 << LR), 0);
3368 
3369   // Setup pool pointer for this dart function.
3370   LoadPoolPointer();
3371 
3372   // Reserve space for locals.
3373   AddImmediate(SP, -frame_size);
3374 }
3375 
3376 
3377 // On entry to a function compiled for OSR, the caller's frame pointer, the
3378 // stack locals, and any copied parameters are already in place.  The frame
3379 // pointer is already set up.  The PC marker is not correct for the
3380 // optimized function and there may be extra space for spill slots to
3381 // allocate. We must also set up the pool pointer for the function.
EnterOsrFrame(intptr_t extra_size)3382 void Assembler::EnterOsrFrame(intptr_t extra_size) {
3383   ASSERT(!constant_pool_allowed());
3384   Comment("EnterOsrFrame");
3385   RestoreCodePointer();
3386   LoadPoolPointer();
3387 
3388   AddImmediate(SP, -extra_size);
3389 }
3390 
3391 
LeaveDartFrame(RestorePP restore_pp)3392 void Assembler::LeaveDartFrame(RestorePP restore_pp) {
3393   if (restore_pp == kRestoreCallerPP) {
3394     ldr(PP, Address(FP, kSavedCallerPpSlotFromFp * kWordSize));
3395     set_constant_pool_allowed(false);
3396   }
3397   Drop(2);  // Drop saved PP, PC marker.
3398   LeaveFrame((1 << FP) | (1 << LR));
3399 }
3400 
3401 
EnterStubFrame()3402 void Assembler::EnterStubFrame() {
3403   EnterDartFrame(0);
3404 }
3405 
3406 
LeaveStubFrame()3407 void Assembler::LeaveStubFrame() {
3408   LeaveDartFrame();
3409 }
3410 
3411 
LoadAllocationStatsAddress(Register dest,intptr_t cid,bool inline_isolate)3412 void Assembler::LoadAllocationStatsAddress(Register dest,
3413                                            intptr_t cid,
3414                                            bool inline_isolate) {
3415   ASSERT(dest != kNoRegister);
3416   ASSERT(dest != TMP);
3417   ASSERT(cid > 0);
3418   const intptr_t class_offset = ClassTable::ClassOffsetFor(cid);
3419   if (inline_isolate) {
3420     ASSERT(FLAG_allow_absolute_addresses);
3421     ClassTable* class_table = Isolate::Current()->class_table();
3422     ClassHeapStats** table_ptr = class_table->TableAddressFor(cid);
3423     if (cid < kNumPredefinedCids) {
3424       LoadImmediate(dest, reinterpret_cast<uword>(*table_ptr) + class_offset);
3425     } else {
3426       LoadImmediate(dest, reinterpret_cast<uword>(table_ptr));
3427       ldr(dest, Address(dest, 0));
3428       AddImmediate(dest, class_offset);
3429     }
3430   } else {
3431     LoadIsolate(dest);
3432     intptr_t table_offset =
3433         Isolate::class_table_offset() + ClassTable::TableOffsetFor(cid);
3434     ldr(dest, Address(dest, table_offset));
3435     AddImmediate(dest, class_offset);
3436   }
3437 }
3438 
3439 
MaybeTraceAllocation(intptr_t cid,Register temp_reg,Label * trace,bool inline_isolate)3440 void Assembler::MaybeTraceAllocation(intptr_t cid,
3441                                      Register temp_reg,
3442                                      Label* trace,
3443                                      bool inline_isolate) {
3444   LoadAllocationStatsAddress(temp_reg, cid, inline_isolate);
3445   const uword state_offset = ClassHeapStats::state_offset();
3446   ldr(temp_reg, Address(temp_reg, state_offset));
3447   tst(temp_reg, Operand(ClassHeapStats::TraceAllocationMask()));
3448   b(trace, NE);
3449 }
3450 
3451 
IncrementAllocationStats(Register stats_addr_reg,intptr_t cid,Heap::Space space)3452 void Assembler::IncrementAllocationStats(Register stats_addr_reg,
3453                                          intptr_t cid,
3454                                          Heap::Space space) {
3455   ASSERT(stats_addr_reg != kNoRegister);
3456   ASSERT(stats_addr_reg != TMP);
3457   ASSERT(cid > 0);
3458   const uword count_field_offset = (space == Heap::kNew) ?
3459     ClassHeapStats::allocated_since_gc_new_space_offset() :
3460     ClassHeapStats::allocated_since_gc_old_space_offset();
3461   const Address& count_address = Address(stats_addr_reg, count_field_offset);
3462   ldr(TMP, count_address);
3463   AddImmediate(TMP, 1);
3464   str(TMP, count_address);
3465 }
3466 
3467 
IncrementAllocationStatsWithSize(Register stats_addr_reg,Register size_reg,Heap::Space space)3468 void Assembler::IncrementAllocationStatsWithSize(Register stats_addr_reg,
3469                                                  Register size_reg,
3470                                                  Heap::Space space) {
3471   ASSERT(stats_addr_reg != kNoRegister);
3472   ASSERT(stats_addr_reg != TMP);
3473   const uword count_field_offset = (space == Heap::kNew) ?
3474     ClassHeapStats::allocated_since_gc_new_space_offset() :
3475     ClassHeapStats::allocated_since_gc_old_space_offset();
3476   const uword size_field_offset = (space == Heap::kNew) ?
3477     ClassHeapStats::allocated_size_since_gc_new_space_offset() :
3478     ClassHeapStats::allocated_size_since_gc_old_space_offset();
3479   const Address& count_address = Address(stats_addr_reg, count_field_offset);
3480   const Address& size_address = Address(stats_addr_reg, size_field_offset);
3481   ldr(TMP, count_address);
3482   AddImmediate(TMP, 1);
3483   str(TMP, count_address);
3484   ldr(TMP, size_address);
3485   add(TMP, TMP, Operand(size_reg));
3486   str(TMP, size_address);
3487 }
3488 
3489 
TryAllocate(const Class & cls,Label * failure,Register instance_reg,Register temp_reg)3490 void Assembler::TryAllocate(const Class& cls,
3491                             Label* failure,
3492                             Register instance_reg,
3493                             Register temp_reg) {
3494   ASSERT(failure != NULL);
3495   if (FLAG_inline_alloc) {
3496     ASSERT(instance_reg != temp_reg);
3497     ASSERT(temp_reg != IP);
3498     const intptr_t instance_size = cls.instance_size();
3499     ASSERT(instance_size != 0);
3500     // If this allocation is traced, program will jump to failure path
3501     // (i.e. the allocation stub) which will allocate the object and trace the
3502     // allocation call site.
3503     MaybeTraceAllocation(cls.id(), temp_reg, failure,
3504                          /* inline_isolate = */ false);
3505     Heap::Space space = Heap::SpaceForAllocation(cls.id());
3506     ldr(temp_reg, Address(THR, Thread::heap_offset()));
3507     ldr(instance_reg, Address(temp_reg, Heap::TopOffset(space)));
3508     // TODO(koda): Protect against unsigned overflow here.
3509     AddImmediateSetFlags(instance_reg, instance_reg, instance_size);
3510 
3511     // instance_reg: potential next object start.
3512     ldr(IP, Address(temp_reg, Heap::EndOffset(space)));
3513     cmp(IP, Operand(instance_reg));
3514     // fail if heap end unsigned less than or equal to instance_reg.
3515     b(failure, LS);
3516 
3517     // Successfully allocated the object, now update top to point to
3518     // next object start and store the class in the class field of object.
3519     str(instance_reg, Address(temp_reg, Heap::TopOffset(space)));
3520 
3521     LoadAllocationStatsAddress(temp_reg, cls.id(),
3522                                /* inline_isolate = */ false);
3523 
3524     ASSERT(instance_size >= kHeapObjectTag);
3525     AddImmediate(instance_reg, -instance_size + kHeapObjectTag);
3526 
3527     uword tags = 0;
3528     tags = RawObject::SizeTag::update(instance_size, tags);
3529     ASSERT(cls.id() != kIllegalCid);
3530     tags = RawObject::ClassIdTag::update(cls.id(), tags);
3531     LoadImmediate(IP, tags);
3532     str(IP, FieldAddress(instance_reg, Object::tags_offset()));
3533 
3534     IncrementAllocationStats(temp_reg, cls.id(), space);
3535   } else {
3536     b(failure);
3537   }
3538 }
3539 
3540 
TryAllocateArray(intptr_t cid,intptr_t instance_size,Label * failure,Register instance,Register end_address,Register temp1,Register temp2)3541 void Assembler::TryAllocateArray(intptr_t cid,
3542                                  intptr_t instance_size,
3543                                  Label* failure,
3544                                  Register instance,
3545                                  Register end_address,
3546                                  Register temp1,
3547                                  Register temp2) {
3548   if (FLAG_inline_alloc) {
3549     // If this allocation is traced, program will jump to failure path
3550     // (i.e. the allocation stub) which will allocate the object and trace the
3551     // allocation call site.
3552     MaybeTraceAllocation(cid, temp1, failure, /* inline_isolate = */ false);
3553     Heap::Space space = Heap::SpaceForAllocation(cid);
3554     ldr(temp1, Address(THR, Thread::heap_offset()));
3555     // Potential new object start.
3556     ldr(instance, Address(temp1, Heap::TopOffset(space)));
3557     AddImmediateSetFlags(end_address, instance, instance_size);
3558     b(failure, CS);  // Branch if unsigned overflow.
3559 
3560     // Check if the allocation fits into the remaining space.
3561     // instance: potential new object start.
3562     // end_address: potential next object start.
3563     ldr(temp2, Address(temp1, Heap::EndOffset(space)));
3564     cmp(end_address, Operand(temp2));
3565     b(failure, CS);
3566 
3567     LoadAllocationStatsAddress(temp2, cid, /* inline_isolate = */ false);
3568 
3569     // Successfully allocated the object(s), now update top to point to
3570     // next object start and initialize the object.
3571     str(end_address, Address(temp1, Heap::TopOffset(space)));
3572     add(instance, instance, Operand(kHeapObjectTag));
3573 
3574     // Initialize the tags.
3575     // instance: new object start as a tagged pointer.
3576     uword tags = 0;
3577     tags = RawObject::ClassIdTag::update(cid, tags);
3578     tags = RawObject::SizeTag::update(instance_size, tags);
3579     LoadImmediate(temp1, tags);
3580     str(temp1, FieldAddress(instance, Array::tags_offset()));  // Store tags.
3581 
3582     LoadImmediate(temp1, instance_size);
3583     IncrementAllocationStatsWithSize(temp2, temp1, space);
3584   } else {
3585     b(failure);
3586   }
3587 }
3588 
3589 
Stop(const char * message)3590 void Assembler::Stop(const char* message) {
3591   if (FLAG_print_stop_message) {
3592     PushList((1 << R0) | (1 << IP) | (1 << LR));  // Preserve R0, IP, LR.
3593     LoadImmediate(R0, reinterpret_cast<int32_t>(message));
3594     // PrintStopMessage() preserves all registers.
3595     BranchLink(&StubCode::PrintStopMessage_entry()->label());
3596     PopList((1 << R0) | (1 << IP) | (1 << LR));  // Restore R0, IP, LR.
3597   }
3598   // Emit the message address before the svc instruction, so that we can
3599   // 'unstop' and continue execution in the simulator or jump to the next
3600   // instruction in gdb.
3601   Label stop;
3602   b(&stop);
3603   Emit(reinterpret_cast<int32_t>(message));
3604   Bind(&stop);
3605   bkpt(Instr::kStopMessageCode);
3606 }
3607 
3608 
ElementAddressForIntIndex(bool is_load,bool is_external,intptr_t cid,intptr_t index_scale,Register array,intptr_t index,Register temp)3609 Address Assembler::ElementAddressForIntIndex(bool is_load,
3610                                              bool is_external,
3611                                              intptr_t cid,
3612                                              intptr_t index_scale,
3613                                              Register array,
3614                                              intptr_t index,
3615                                              Register temp) {
3616   const int64_t offset_base =
3617       (is_external ? 0 : (Instance::DataOffsetFor(cid) - kHeapObjectTag));
3618   const int64_t offset = offset_base +
3619       static_cast<int64_t>(index) * index_scale;
3620   ASSERT(Utils::IsInt(32, offset));
3621 
3622   if (Address::CanHoldImmediateOffset(is_load, cid, offset)) {
3623     return Address(array, static_cast<int32_t>(offset));
3624   } else {
3625     ASSERT(Address::CanHoldImmediateOffset(is_load, cid, offset - offset_base));
3626     AddImmediate(temp, array, static_cast<int32_t>(offset_base));
3627     return Address(temp, static_cast<int32_t>(offset - offset_base));
3628   }
3629 }
3630 
3631 
ElementAddressForRegIndex(bool is_load,bool is_external,intptr_t cid,intptr_t index_scale,Register array,Register index)3632 Address Assembler::ElementAddressForRegIndex(bool is_load,
3633                                              bool is_external,
3634                                              intptr_t cid,
3635                                              intptr_t index_scale,
3636                                              Register array,
3637                                              Register index) {
3638   // Note that index is expected smi-tagged, (i.e, LSL 1) for all arrays.
3639   const intptr_t shift = Utils::ShiftForPowerOfTwo(index_scale) - kSmiTagShift;
3640   int32_t offset =
3641       is_external ? 0 : (Instance::DataOffsetFor(cid) - kHeapObjectTag);
3642   const OperandSize size = Address::OperandSizeFor(cid);
3643   ASSERT(array != IP);
3644   ASSERT(index != IP);
3645   const Register base = is_load ? IP : index;
3646   if ((offset != 0) ||
3647       (size == kSWord) || (size == kDWord) || (size == kRegList)) {
3648     if (shift < 0) {
3649       ASSERT(shift == -1);
3650       add(base, array, Operand(index, ASR, 1));
3651     } else {
3652       add(base, array, Operand(index, LSL, shift));
3653     }
3654   } else {
3655     if (shift < 0) {
3656       ASSERT(shift == -1);
3657       return Address(array, index, ASR, 1);
3658     } else {
3659       return Address(array, index, LSL, shift);
3660     }
3661   }
3662   int32_t offset_mask = 0;
3663   if ((is_load && !Address::CanHoldLoadOffset(size,
3664                                               offset,
3665                                               &offset_mask)) ||
3666       (!is_load && !Address::CanHoldStoreOffset(size,
3667                                                 offset,
3668                                                 &offset_mask))) {
3669     AddImmediate(base, offset & ~offset_mask);
3670     offset = offset & offset_mask;
3671   }
3672   return Address(base, offset);
3673 }
3674 
3675 
3676 static const char* cpu_reg_names[kNumberOfCpuRegisters] = {
3677   "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
3678   "r8", "ctx", "pp", "fp", "ip", "sp", "lr", "pc",
3679 };
3680 
3681 
RegisterName(Register reg)3682 const char* Assembler::RegisterName(Register reg) {
3683   ASSERT((0 <= reg) && (reg < kNumberOfCpuRegisters));
3684   return cpu_reg_names[reg];
3685 }
3686 
3687 
3688 static const char* fpu_reg_names[kNumberOfFpuRegisters] = {
3689   "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7",
3690 #if defined(VFPv3_D32)
3691   "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15",
3692 #endif
3693 };
3694 
3695 
FpuRegisterName(FpuRegister reg)3696 const char* Assembler::FpuRegisterName(FpuRegister reg) {
3697   ASSERT((0 <= reg) && (reg < kNumberOfFpuRegisters));
3698   return fpu_reg_names[reg];
3699 }
3700 
3701 }  // namespace dart
3702 
3703 #endif  // defined TARGET_ARCH_ARM
3704