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