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