1 // Copyright (c) 1994-2006 Sun Microsystems Inc.
2 // All Rights Reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 //
8 // - Redistributions of source code must retain the above copyright notice,
9 // this list of conditions and the following disclaimer.
10 //
11 // - Redistribution in binary form must reproduce the above copyright
12 // notice, this list of conditions and the following disclaimer in the
13 // documentation and/or other materials provided with the
14 // distribution.
15 //
16 // - Neither the name of Sun Microsystems or the names of contributors may
17 // be used to endorse or promote products derived from this software without
18 // specific prior written permission.
19 //
20 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 // COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29 // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
31 // OF THE POSSIBILITY OF SUCH DAMAGE.
32
33 // The original source code covered by the above license above has been
34 // modified significantly by Google Inc.
35 // Copyright 2011 the V8 project authors. All rights reserved.
36
37 #include "v8.h"
38
39 #if defined(V8_TARGET_ARCH_ARM)
40
41 #include "arm/assembler-arm-inl.h"
42 #include "serialize.h"
43
44 namespace v8 {
45 namespace internal {
46
47 #ifdef DEBUG
48 bool CpuFeatures::initialized_ = false;
49 #endif
50 unsigned CpuFeatures::supported_ = 0;
51 unsigned CpuFeatures::found_by_runtime_probing_ = 0;
52
53
54 // Get the CPU features enabled by the build. For cross compilation the
55 // preprocessor symbols CAN_USE_ARMV7_INSTRUCTIONS and CAN_USE_VFP_INSTRUCTIONS
56 // can be defined to enable ARMv7 and VFPv3 instructions when building the
57 // snapshot.
CpuFeaturesImpliedByCompiler()58 static uint64_t CpuFeaturesImpliedByCompiler() {
59 uint64_t answer = 0;
60 #ifdef CAN_USE_ARMV7_INSTRUCTIONS
61 answer |= 1u << ARMv7;
62 #endif // def CAN_USE_ARMV7_INSTRUCTIONS
63 #ifdef CAN_USE_VFP_INSTRUCTIONS
64 answer |= 1u << VFP3 | 1u << ARMv7;
65 #endif // def CAN_USE_VFP_INSTRUCTIONS
66
67 #ifdef __arm__
68 // If the compiler is allowed to use VFP then we can use VFP too in our code
69 // generation even when generating snapshots. ARMv7 and hardware floating
70 // point support implies VFPv3, see ARM DDI 0406B, page A1-6.
71 #if defined(CAN_USE_ARMV7_INSTRUCTIONS) && defined(__VFP_FP__) \
72 && !defined(__SOFTFP__)
73 answer |= 1u << VFP3 | 1u << ARMv7;
74 #endif // defined(CAN_USE_ARMV7_INSTRUCTIONS) && defined(__VFP_FP__)
75 // && !defined(__SOFTFP__)
76 #endif // def __arm__
77
78 return answer;
79 }
80
81
Probe()82 void CpuFeatures::Probe() {
83 unsigned standard_features = (OS::CpuFeaturesImpliedByPlatform() |
84 CpuFeaturesImpliedByCompiler());
85 ASSERT(supported_ == 0 || supported_ == standard_features);
86 #ifdef DEBUG
87 initialized_ = true;
88 #endif
89
90 // Get the features implied by the OS and the compiler settings. This is the
91 // minimal set of features which is also alowed for generated code in the
92 // snapshot.
93 supported_ |= standard_features;
94
95 if (Serializer::enabled()) {
96 // No probing for features if we might serialize (generate snapshot).
97 return;
98 }
99
100 #ifndef __arm__
101 // For the simulator=arm build, use VFP when FLAG_enable_vfp3 is
102 // enabled. VFPv3 implies ARMv7, see ARM DDI 0406B, page A1-6.
103 if (FLAG_enable_vfp3) {
104 supported_ |= 1u << VFP3 | 1u << ARMv7;
105 }
106 // For the simulator=arm build, use ARMv7 when FLAG_enable_armv7 is enabled
107 if (FLAG_enable_armv7) {
108 supported_ |= 1u << ARMv7;
109 }
110 #else // def __arm__
111 // Probe for additional features not already known to be available.
112 if (!IsSupported(VFP3) && OS::ArmCpuHasFeature(VFP3)) {
113 // This implementation also sets the VFP flags if runtime
114 // detection of VFP returns true. VFPv3 implies ARMv7, see ARM DDI
115 // 0406B, page A1-6.
116 supported_ |= 1u << VFP3 | 1u << ARMv7;
117 found_by_runtime_probing_ |= 1u << VFP3 | 1u << ARMv7;
118 }
119
120 if (!IsSupported(ARMv7) && OS::ArmCpuHasFeature(ARMv7)) {
121 supported_ |= 1u << ARMv7;
122 found_by_runtime_probing_ |= 1u << ARMv7;
123 }
124 #endif
125 }
126
127
128 // -----------------------------------------------------------------------------
129 // Implementation of RelocInfo
130
131 const int RelocInfo::kApplyMask = 0;
132
133
IsCodedSpecially()134 bool RelocInfo::IsCodedSpecially() {
135 // The deserializer needs to know whether a pointer is specially coded. Being
136 // specially coded on ARM means that it is a movw/movt instruction. We don't
137 // generate those yet.
138 return false;
139 }
140
141
PatchCode(byte * instructions,int instruction_count)142 void RelocInfo::PatchCode(byte* instructions, int instruction_count) {
143 // Patch the code at the current address with the supplied instructions.
144 Instr* pc = reinterpret_cast<Instr*>(pc_);
145 Instr* instr = reinterpret_cast<Instr*>(instructions);
146 for (int i = 0; i < instruction_count; i++) {
147 *(pc + i) = *(instr + i);
148 }
149
150 // Indicate that code has changed.
151 CPU::FlushICache(pc_, instruction_count * Assembler::kInstrSize);
152 }
153
154
155 // Patch the code at the current PC with a call to the target address.
156 // Additional guard instructions can be added if required.
PatchCodeWithCall(Address target,int guard_bytes)157 void RelocInfo::PatchCodeWithCall(Address target, int guard_bytes) {
158 // Patch the code at the current address with a call to the target.
159 UNIMPLEMENTED();
160 }
161
162
163 // -----------------------------------------------------------------------------
164 // Implementation of Operand and MemOperand
165 // See assembler-arm-inl.h for inlined constructors
166
Operand(Handle<Object> handle)167 Operand::Operand(Handle<Object> handle) {
168 rm_ = no_reg;
169 // Verify all Objects referred by code are NOT in new space.
170 Object* obj = *handle;
171 ASSERT(!HEAP->InNewSpace(obj));
172 if (obj->IsHeapObject()) {
173 imm32_ = reinterpret_cast<intptr_t>(handle.location());
174 rmode_ = RelocInfo::EMBEDDED_OBJECT;
175 } else {
176 // no relocation needed
177 imm32_ = reinterpret_cast<intptr_t>(obj);
178 rmode_ = RelocInfo::NONE;
179 }
180 }
181
182
Operand(Register rm,ShiftOp shift_op,int shift_imm)183 Operand::Operand(Register rm, ShiftOp shift_op, int shift_imm) {
184 ASSERT(is_uint5(shift_imm));
185 ASSERT(shift_op != ROR || shift_imm != 0); // use RRX if you mean it
186 rm_ = rm;
187 rs_ = no_reg;
188 shift_op_ = shift_op;
189 shift_imm_ = shift_imm & 31;
190 if (shift_op == RRX) {
191 // encoded as ROR with shift_imm == 0
192 ASSERT(shift_imm == 0);
193 shift_op_ = ROR;
194 shift_imm_ = 0;
195 }
196 }
197
198
Operand(Register rm,ShiftOp shift_op,Register rs)199 Operand::Operand(Register rm, ShiftOp shift_op, Register rs) {
200 ASSERT(shift_op != RRX);
201 rm_ = rm;
202 rs_ = no_reg;
203 shift_op_ = shift_op;
204 rs_ = rs;
205 }
206
207
MemOperand(Register rn,int32_t offset,AddrMode am)208 MemOperand::MemOperand(Register rn, int32_t offset, AddrMode am) {
209 rn_ = rn;
210 rm_ = no_reg;
211 offset_ = offset;
212 am_ = am;
213 }
214
MemOperand(Register rn,Register rm,AddrMode am)215 MemOperand::MemOperand(Register rn, Register rm, AddrMode am) {
216 rn_ = rn;
217 rm_ = rm;
218 shift_op_ = LSL;
219 shift_imm_ = 0;
220 am_ = am;
221 }
222
223
MemOperand(Register rn,Register rm,ShiftOp shift_op,int shift_imm,AddrMode am)224 MemOperand::MemOperand(Register rn, Register rm,
225 ShiftOp shift_op, int shift_imm, AddrMode am) {
226 ASSERT(is_uint5(shift_imm));
227 rn_ = rn;
228 rm_ = rm;
229 shift_op_ = shift_op;
230 shift_imm_ = shift_imm & 31;
231 am_ = am;
232 }
233
234
235 // -----------------------------------------------------------------------------
236 // Specific instructions, constants, and masks.
237
238 // add(sp, sp, 4) instruction (aka Pop())
239 const Instr kPopInstruction =
240 al | PostIndex | 4 | LeaveCC | I | kRegister_sp_Code * B16 |
241 kRegister_sp_Code * B12;
242 // str(r, MemOperand(sp, 4, NegPreIndex), al) instruction (aka push(r))
243 // register r is not encoded.
244 const Instr kPushRegPattern =
245 al | B26 | 4 | NegPreIndex | kRegister_sp_Code * B16;
246 // ldr(r, MemOperand(sp, 4, PostIndex), al) instruction (aka pop(r))
247 // register r is not encoded.
248 const Instr kPopRegPattern =
249 al | B26 | L | 4 | PostIndex | kRegister_sp_Code * B16;
250 // mov lr, pc
251 const Instr kMovLrPc = al | MOV | kRegister_pc_Code | kRegister_lr_Code * B12;
252 // ldr rd, [pc, #offset]
253 const Instr kLdrPCMask = kCondMask | 15 * B24 | 7 * B20 | 15 * B16;
254 const Instr kLdrPCPattern = al | 5 * B24 | L | kRegister_pc_Code * B16;
255 // blxcc rm
256 const Instr kBlxRegMask =
257 15 * B24 | 15 * B20 | 15 * B16 | 15 * B12 | 15 * B8 | 15 * B4;
258 const Instr kBlxRegPattern =
259 B24 | B21 | 15 * B16 | 15 * B12 | 15 * B8 | BLX;
260 const Instr kBlxIp = al | kBlxRegPattern | ip.code();
261 const Instr kMovMvnMask = 0x6d * B21 | 0xf * B16;
262 const Instr kMovMvnPattern = 0xd * B21;
263 const Instr kMovMvnFlip = B22;
264 const Instr kMovLeaveCCMask = 0xdff * B16;
265 const Instr kMovLeaveCCPattern = 0x1a0 * B16;
266 const Instr kMovwMask = 0xff * B20;
267 const Instr kMovwPattern = 0x30 * B20;
268 const Instr kMovwLeaveCCFlip = 0x5 * B21;
269 const Instr kCmpCmnMask = 0xdd * B20 | 0xf * B12;
270 const Instr kCmpCmnPattern = 0x15 * B20;
271 const Instr kCmpCmnFlip = B21;
272 const Instr kAddSubFlip = 0x6 * B21;
273 const Instr kAndBicFlip = 0xe * B21;
274
275 // A mask for the Rd register for push, pop, ldr, str instructions.
276 const Instr kLdrRegFpOffsetPattern =
277 al | B26 | L | Offset | kRegister_fp_Code * B16;
278 const Instr kStrRegFpOffsetPattern =
279 al | B26 | Offset | kRegister_fp_Code * B16;
280 const Instr kLdrRegFpNegOffsetPattern =
281 al | B26 | L | NegOffset | kRegister_fp_Code * B16;
282 const Instr kStrRegFpNegOffsetPattern =
283 al | B26 | NegOffset | kRegister_fp_Code * B16;
284 const Instr kLdrStrInstrTypeMask = 0xffff0000;
285 const Instr kLdrStrInstrArgumentMask = 0x0000ffff;
286 const Instr kLdrStrOffsetMask = 0x00000fff;
287
288
289 // Spare buffer.
290 static const int kMinimalBufferSize = 4*KB;
291
292
Assembler(Isolate * arg_isolate,void * buffer,int buffer_size)293 Assembler::Assembler(Isolate* arg_isolate, void* buffer, int buffer_size)
294 : AssemblerBase(arg_isolate),
295 positions_recorder_(this),
296 emit_debug_code_(FLAG_debug_code) {
297 if (buffer == NULL) {
298 // Do our own buffer management.
299 if (buffer_size <= kMinimalBufferSize) {
300 buffer_size = kMinimalBufferSize;
301
302 if (isolate()->assembler_spare_buffer() != NULL) {
303 buffer = isolate()->assembler_spare_buffer();
304 isolate()->set_assembler_spare_buffer(NULL);
305 }
306 }
307 if (buffer == NULL) {
308 buffer_ = NewArray<byte>(buffer_size);
309 } else {
310 buffer_ = static_cast<byte*>(buffer);
311 }
312 buffer_size_ = buffer_size;
313 own_buffer_ = true;
314
315 } else {
316 // Use externally provided buffer instead.
317 ASSERT(buffer_size > 0);
318 buffer_ = static_cast<byte*>(buffer);
319 buffer_size_ = buffer_size;
320 own_buffer_ = false;
321 }
322
323 // Set up buffer pointers.
324 ASSERT(buffer_ != NULL);
325 pc_ = buffer_;
326 reloc_info_writer.Reposition(buffer_ + buffer_size, pc_);
327 num_pending_reloc_info_ = 0;
328 next_buffer_check_ = 0;
329 const_pool_blocked_nesting_ = 0;
330 no_const_pool_before_ = 0;
331 first_const_pool_use_ = -1;
332 last_bound_pos_ = 0;
333 ClearRecordedAstId();
334 }
335
336
~Assembler()337 Assembler::~Assembler() {
338 ASSERT(const_pool_blocked_nesting_ == 0);
339 if (own_buffer_) {
340 if (isolate()->assembler_spare_buffer() == NULL &&
341 buffer_size_ == kMinimalBufferSize) {
342 isolate()->set_assembler_spare_buffer(buffer_);
343 } else {
344 DeleteArray(buffer_);
345 }
346 }
347 }
348
349
GetCode(CodeDesc * desc)350 void Assembler::GetCode(CodeDesc* desc) {
351 // Emit constant pool if necessary.
352 CheckConstPool(true, false);
353 ASSERT(num_pending_reloc_info_ == 0);
354
355 // Set up code descriptor.
356 desc->buffer = buffer_;
357 desc->buffer_size = buffer_size_;
358 desc->instr_size = pc_offset();
359 desc->reloc_size = (buffer_ + buffer_size_) - reloc_info_writer.pos();
360 }
361
362
Align(int m)363 void Assembler::Align(int m) {
364 ASSERT(m >= 4 && IsPowerOf2(m));
365 while ((pc_offset() & (m - 1)) != 0) {
366 nop();
367 }
368 }
369
370
CodeTargetAlign()371 void Assembler::CodeTargetAlign() {
372 // Preferred alignment of jump targets on some ARM chips.
373 Align(8);
374 }
375
376
GetCondition(Instr instr)377 Condition Assembler::GetCondition(Instr instr) {
378 return Instruction::ConditionField(instr);
379 }
380
381
IsBranch(Instr instr)382 bool Assembler::IsBranch(Instr instr) {
383 return (instr & (B27 | B25)) == (B27 | B25);
384 }
385
386
GetBranchOffset(Instr instr)387 int Assembler::GetBranchOffset(Instr instr) {
388 ASSERT(IsBranch(instr));
389 // Take the jump offset in the lower 24 bits, sign extend it and multiply it
390 // with 4 to get the offset in bytes.
391 return ((instr & kImm24Mask) << 8) >> 6;
392 }
393
394
IsLdrRegisterImmediate(Instr instr)395 bool Assembler::IsLdrRegisterImmediate(Instr instr) {
396 return (instr & (B27 | B26 | B25 | B22 | B20)) == (B26 | B20);
397 }
398
399
GetLdrRegisterImmediateOffset(Instr instr)400 int Assembler::GetLdrRegisterImmediateOffset(Instr instr) {
401 ASSERT(IsLdrRegisterImmediate(instr));
402 bool positive = (instr & B23) == B23;
403 int offset = instr & kOff12Mask; // Zero extended offset.
404 return positive ? offset : -offset;
405 }
406
407
SetLdrRegisterImmediateOffset(Instr instr,int offset)408 Instr Assembler::SetLdrRegisterImmediateOffset(Instr instr, int offset) {
409 ASSERT(IsLdrRegisterImmediate(instr));
410 bool positive = offset >= 0;
411 if (!positive) offset = -offset;
412 ASSERT(is_uint12(offset));
413 // Set bit indicating whether the offset should be added.
414 instr = (instr & ~B23) | (positive ? B23 : 0);
415 // Set the actual offset.
416 return (instr & ~kOff12Mask) | offset;
417 }
418
419
IsStrRegisterImmediate(Instr instr)420 bool Assembler::IsStrRegisterImmediate(Instr instr) {
421 return (instr & (B27 | B26 | B25 | B22 | B20)) == B26;
422 }
423
424
SetStrRegisterImmediateOffset(Instr instr,int offset)425 Instr Assembler::SetStrRegisterImmediateOffset(Instr instr, int offset) {
426 ASSERT(IsStrRegisterImmediate(instr));
427 bool positive = offset >= 0;
428 if (!positive) offset = -offset;
429 ASSERT(is_uint12(offset));
430 // Set bit indicating whether the offset should be added.
431 instr = (instr & ~B23) | (positive ? B23 : 0);
432 // Set the actual offset.
433 return (instr & ~kOff12Mask) | offset;
434 }
435
436
IsAddRegisterImmediate(Instr instr)437 bool Assembler::IsAddRegisterImmediate(Instr instr) {
438 return (instr & (B27 | B26 | B25 | B24 | B23 | B22 | B21)) == (B25 | B23);
439 }
440
441
SetAddRegisterImmediateOffset(Instr instr,int offset)442 Instr Assembler::SetAddRegisterImmediateOffset(Instr instr, int offset) {
443 ASSERT(IsAddRegisterImmediate(instr));
444 ASSERT(offset >= 0);
445 ASSERT(is_uint12(offset));
446 // Set the offset.
447 return (instr & ~kOff12Mask) | offset;
448 }
449
450
GetRd(Instr instr)451 Register Assembler::GetRd(Instr instr) {
452 Register reg;
453 reg.code_ = Instruction::RdValue(instr);
454 return reg;
455 }
456
457
GetRn(Instr instr)458 Register Assembler::GetRn(Instr instr) {
459 Register reg;
460 reg.code_ = Instruction::RnValue(instr);
461 return reg;
462 }
463
464
GetRm(Instr instr)465 Register Assembler::GetRm(Instr instr) {
466 Register reg;
467 reg.code_ = Instruction::RmValue(instr);
468 return reg;
469 }
470
471
IsPush(Instr instr)472 bool Assembler::IsPush(Instr instr) {
473 return ((instr & ~kRdMask) == kPushRegPattern);
474 }
475
476
IsPop(Instr instr)477 bool Assembler::IsPop(Instr instr) {
478 return ((instr & ~kRdMask) == kPopRegPattern);
479 }
480
481
IsStrRegFpOffset(Instr instr)482 bool Assembler::IsStrRegFpOffset(Instr instr) {
483 return ((instr & kLdrStrInstrTypeMask) == kStrRegFpOffsetPattern);
484 }
485
486
IsLdrRegFpOffset(Instr instr)487 bool Assembler::IsLdrRegFpOffset(Instr instr) {
488 return ((instr & kLdrStrInstrTypeMask) == kLdrRegFpOffsetPattern);
489 }
490
491
IsStrRegFpNegOffset(Instr instr)492 bool Assembler::IsStrRegFpNegOffset(Instr instr) {
493 return ((instr & kLdrStrInstrTypeMask) == kStrRegFpNegOffsetPattern);
494 }
495
496
IsLdrRegFpNegOffset(Instr instr)497 bool Assembler::IsLdrRegFpNegOffset(Instr instr) {
498 return ((instr & kLdrStrInstrTypeMask) == kLdrRegFpNegOffsetPattern);
499 }
500
501
IsLdrPcImmediateOffset(Instr instr)502 bool Assembler::IsLdrPcImmediateOffset(Instr instr) {
503 // Check the instruction is indeed a
504 // ldr<cond> <Rd>, [pc +/- offset_12].
505 return (instr & (kLdrPCMask & ~kCondMask)) == 0x051f0000;
506 }
507
508
IsTstImmediate(Instr instr)509 bool Assembler::IsTstImmediate(Instr instr) {
510 return (instr & (B27 | B26 | I | kOpCodeMask | S | kRdMask)) ==
511 (I | TST | S);
512 }
513
514
IsCmpRegister(Instr instr)515 bool Assembler::IsCmpRegister(Instr instr) {
516 return (instr & (B27 | B26 | I | kOpCodeMask | S | kRdMask | B4)) ==
517 (CMP | S);
518 }
519
520
IsCmpImmediate(Instr instr)521 bool Assembler::IsCmpImmediate(Instr instr) {
522 return (instr & (B27 | B26 | I | kOpCodeMask | S | kRdMask)) ==
523 (I | CMP | S);
524 }
525
526
GetCmpImmediateRegister(Instr instr)527 Register Assembler::GetCmpImmediateRegister(Instr instr) {
528 ASSERT(IsCmpImmediate(instr));
529 return GetRn(instr);
530 }
531
532
GetCmpImmediateRawImmediate(Instr instr)533 int Assembler::GetCmpImmediateRawImmediate(Instr instr) {
534 ASSERT(IsCmpImmediate(instr));
535 return instr & kOff12Mask;
536 }
537
538 // Labels refer to positions in the (to be) generated code.
539 // There are bound, linked, and unused labels.
540 //
541 // Bound labels refer to known positions in the already
542 // generated code. pos() is the position the label refers to.
543 //
544 // Linked labels refer to unknown positions in the code
545 // to be generated; pos() is the position of the last
546 // instruction using the label.
547
548
549 // The link chain is terminated by a negative code position (must be aligned)
550 const int kEndOfChain = -4;
551
552
target_at(int pos)553 int Assembler::target_at(int pos) {
554 Instr instr = instr_at(pos);
555 if ((instr & ~kImm24Mask) == 0) {
556 // Emitted label constant, not part of a branch.
557 return instr - (Code::kHeaderSize - kHeapObjectTag);
558 }
559 ASSERT((instr & 7*B25) == 5*B25); // b, bl, or blx imm24
560 int imm26 = ((instr & kImm24Mask) << 8) >> 6;
561 if ((Instruction::ConditionField(instr) == kSpecialCondition) &&
562 ((instr & B24) != 0)) {
563 // blx uses bit 24 to encode bit 2 of imm26
564 imm26 += 2;
565 }
566 return pos + kPcLoadDelta + imm26;
567 }
568
569
target_at_put(int pos,int target_pos)570 void Assembler::target_at_put(int pos, int target_pos) {
571 Instr instr = instr_at(pos);
572 if ((instr & ~kImm24Mask) == 0) {
573 ASSERT(target_pos == kEndOfChain || target_pos >= 0);
574 // Emitted label constant, not part of a branch.
575 // Make label relative to Code* of generated Code object.
576 instr_at_put(pos, target_pos + (Code::kHeaderSize - kHeapObjectTag));
577 return;
578 }
579 int imm26 = target_pos - (pos + kPcLoadDelta);
580 ASSERT((instr & 7*B25) == 5*B25); // b, bl, or blx imm24
581 if (Instruction::ConditionField(instr) == kSpecialCondition) {
582 // blx uses bit 24 to encode bit 2 of imm26
583 ASSERT((imm26 & 1) == 0);
584 instr = (instr & ~(B24 | kImm24Mask)) | ((imm26 & 2) >> 1)*B24;
585 } else {
586 ASSERT((imm26 & 3) == 0);
587 instr &= ~kImm24Mask;
588 }
589 int imm24 = imm26 >> 2;
590 ASSERT(is_int24(imm24));
591 instr_at_put(pos, instr | (imm24 & kImm24Mask));
592 }
593
594
print(Label * L)595 void Assembler::print(Label* L) {
596 if (L->is_unused()) {
597 PrintF("unused label\n");
598 } else if (L->is_bound()) {
599 PrintF("bound label to %d\n", L->pos());
600 } else if (L->is_linked()) {
601 Label l = *L;
602 PrintF("unbound label");
603 while (l.is_linked()) {
604 PrintF("@ %d ", l.pos());
605 Instr instr = instr_at(l.pos());
606 if ((instr & ~kImm24Mask) == 0) {
607 PrintF("value\n");
608 } else {
609 ASSERT((instr & 7*B25) == 5*B25); // b, bl, or blx
610 Condition cond = Instruction::ConditionField(instr);
611 const char* b;
612 const char* c;
613 if (cond == kSpecialCondition) {
614 b = "blx";
615 c = "";
616 } else {
617 if ((instr & B24) != 0)
618 b = "bl";
619 else
620 b = "b";
621
622 switch (cond) {
623 case eq: c = "eq"; break;
624 case ne: c = "ne"; break;
625 case hs: c = "hs"; break;
626 case lo: c = "lo"; break;
627 case mi: c = "mi"; break;
628 case pl: c = "pl"; break;
629 case vs: c = "vs"; break;
630 case vc: c = "vc"; break;
631 case hi: c = "hi"; break;
632 case ls: c = "ls"; break;
633 case ge: c = "ge"; break;
634 case lt: c = "lt"; break;
635 case gt: c = "gt"; break;
636 case le: c = "le"; break;
637 case al: c = ""; break;
638 default:
639 c = "";
640 UNREACHABLE();
641 }
642 }
643 PrintF("%s%s\n", b, c);
644 }
645 next(&l);
646 }
647 } else {
648 PrintF("label in inconsistent state (pos = %d)\n", L->pos_);
649 }
650 }
651
652
bind_to(Label * L,int pos)653 void Assembler::bind_to(Label* L, int pos) {
654 ASSERT(0 <= pos && pos <= pc_offset()); // must have a valid binding position
655 while (L->is_linked()) {
656 int fixup_pos = L->pos();
657 next(L); // call next before overwriting link with target at fixup_pos
658 target_at_put(fixup_pos, pos);
659 }
660 L->bind_to(pos);
661
662 // Keep track of the last bound label so we don't eliminate any instructions
663 // before a bound label.
664 if (pos > last_bound_pos_)
665 last_bound_pos_ = pos;
666 }
667
668
link_to(Label * L,Label * appendix)669 void Assembler::link_to(Label* L, Label* appendix) {
670 if (appendix->is_linked()) {
671 if (L->is_linked()) {
672 // Append appendix to L's list.
673 int fixup_pos;
674 int link = L->pos();
675 do {
676 fixup_pos = link;
677 link = target_at(fixup_pos);
678 } while (link > 0);
679 ASSERT(link == kEndOfChain);
680 target_at_put(fixup_pos, appendix->pos());
681 } else {
682 // L is empty, simply use appendix.
683 *L = *appendix;
684 }
685 }
686 appendix->Unuse(); // appendix should not be used anymore
687 }
688
689
bind(Label * L)690 void Assembler::bind(Label* L) {
691 ASSERT(!L->is_bound()); // label can only be bound once
692 bind_to(L, pc_offset());
693 }
694
695
next(Label * L)696 void Assembler::next(Label* L) {
697 ASSERT(L->is_linked());
698 int link = target_at(L->pos());
699 if (link == kEndOfChain) {
700 L->Unuse();
701 } else {
702 ASSERT(link >= 0);
703 L->link_to(link);
704 }
705 }
706
707
EncodeMovwImmediate(uint32_t immediate)708 static Instr EncodeMovwImmediate(uint32_t immediate) {
709 ASSERT(immediate < 0x10000);
710 return ((immediate & 0xf000) << 4) | (immediate & 0xfff);
711 }
712
713
714 // Low-level code emission routines depending on the addressing mode.
715 // If this returns true then you have to use the rotate_imm and immed_8
716 // that it returns, because it may have already changed the instruction
717 // to match them!
fits_shifter(uint32_t imm32,uint32_t * rotate_imm,uint32_t * immed_8,Instr * instr)718 static bool fits_shifter(uint32_t imm32,
719 uint32_t* rotate_imm,
720 uint32_t* immed_8,
721 Instr* instr) {
722 // imm32 must be unsigned.
723 for (int rot = 0; rot < 16; rot++) {
724 uint32_t imm8 = (imm32 << 2*rot) | (imm32 >> (32 - 2*rot));
725 if ((imm8 <= 0xff)) {
726 *rotate_imm = rot;
727 *immed_8 = imm8;
728 return true;
729 }
730 }
731 // If the opcode is one with a complementary version and the complementary
732 // immediate fits, change the opcode.
733 if (instr != NULL) {
734 if ((*instr & kMovMvnMask) == kMovMvnPattern) {
735 if (fits_shifter(~imm32, rotate_imm, immed_8, NULL)) {
736 *instr ^= kMovMvnFlip;
737 return true;
738 } else if ((*instr & kMovLeaveCCMask) == kMovLeaveCCPattern) {
739 if (CpuFeatures::IsSupported(ARMv7)) {
740 if (imm32 < 0x10000) {
741 *instr ^= kMovwLeaveCCFlip;
742 *instr |= EncodeMovwImmediate(imm32);
743 *rotate_imm = *immed_8 = 0; // Not used for movw.
744 return true;
745 }
746 }
747 }
748 } else if ((*instr & kCmpCmnMask) == kCmpCmnPattern) {
749 if (fits_shifter(-imm32, rotate_imm, immed_8, NULL)) {
750 *instr ^= kCmpCmnFlip;
751 return true;
752 }
753 } else {
754 Instr alu_insn = (*instr & kALUMask);
755 if (alu_insn == ADD ||
756 alu_insn == SUB) {
757 if (fits_shifter(-imm32, rotate_imm, immed_8, NULL)) {
758 *instr ^= kAddSubFlip;
759 return true;
760 }
761 } else if (alu_insn == AND ||
762 alu_insn == BIC) {
763 if (fits_shifter(~imm32, rotate_imm, immed_8, NULL)) {
764 *instr ^= kAndBicFlip;
765 return true;
766 }
767 }
768 }
769 }
770 return false;
771 }
772
773
774 // We have to use the temporary register for things that can be relocated even
775 // if they can be encoded in the ARM's 12 bits of immediate-offset instruction
776 // space. There is no guarantee that the relocated location can be similarly
777 // encoded.
must_use_constant_pool() const778 bool Operand::must_use_constant_pool() const {
779 if (rmode_ == RelocInfo::EXTERNAL_REFERENCE) {
780 #ifdef DEBUG
781 if (!Serializer::enabled()) {
782 Serializer::TooLateToEnableNow();
783 }
784 #endif // def DEBUG
785 return Serializer::enabled();
786 } else if (rmode_ == RelocInfo::NONE) {
787 return false;
788 }
789 return true;
790 }
791
792
is_single_instruction(Instr instr) const793 bool Operand::is_single_instruction(Instr instr) const {
794 if (rm_.is_valid()) return true;
795 uint32_t dummy1, dummy2;
796 if (must_use_constant_pool() ||
797 !fits_shifter(imm32_, &dummy1, &dummy2, &instr)) {
798 // The immediate operand cannot be encoded as a shifter operand, or use of
799 // constant pool is required. For a mov instruction not setting the
800 // condition code additional instruction conventions can be used.
801 if ((instr & ~kCondMask) == 13*B21) { // mov, S not set
802 if (must_use_constant_pool() ||
803 !CpuFeatures::IsSupported(ARMv7)) {
804 // mov instruction will be an ldr from constant pool (one instruction).
805 return true;
806 } else {
807 // mov instruction will be a mov or movw followed by movt (two
808 // instructions).
809 return false;
810 }
811 } else {
812 // If this is not a mov or mvn instruction there will always an additional
813 // instructions - either mov or ldr. The mov might actually be two
814 // instructions mov or movw followed by movt so including the actual
815 // instruction two or three instructions will be generated.
816 return false;
817 }
818 } else {
819 // No use of constant pool and the immediate operand can be encoded as a
820 // shifter operand.
821 return true;
822 }
823 }
824
825
addrmod1(Instr instr,Register rn,Register rd,const Operand & x)826 void Assembler::addrmod1(Instr instr,
827 Register rn,
828 Register rd,
829 const Operand& x) {
830 CheckBuffer();
831 ASSERT((instr & ~(kCondMask | kOpCodeMask | S)) == 0);
832 if (!x.rm_.is_valid()) {
833 // Immediate.
834 uint32_t rotate_imm;
835 uint32_t immed_8;
836 if (x.must_use_constant_pool() ||
837 !fits_shifter(x.imm32_, &rotate_imm, &immed_8, &instr)) {
838 // The immediate operand cannot be encoded as a shifter operand, so load
839 // it first to register ip and change the original instruction to use ip.
840 // However, if the original instruction is a 'mov rd, x' (not setting the
841 // condition code), then replace it with a 'ldr rd, [pc]'.
842 CHECK(!rn.is(ip)); // rn should never be ip, or will be trashed
843 Condition cond = Instruction::ConditionField(instr);
844 if ((instr & ~kCondMask) == 13*B21) { // mov, S not set
845 if (x.must_use_constant_pool() ||
846 !CpuFeatures::IsSupported(ARMv7)) {
847 RecordRelocInfo(x.rmode_, x.imm32_);
848 ldr(rd, MemOperand(pc, 0), cond);
849 } else {
850 // Will probably use movw, will certainly not use constant pool.
851 mov(rd, Operand(x.imm32_ & 0xffff), LeaveCC, cond);
852 movt(rd, static_cast<uint32_t>(x.imm32_) >> 16, cond);
853 }
854 } else {
855 // If this is not a mov or mvn instruction we may still be able to avoid
856 // a constant pool entry by using mvn or movw.
857 if (!x.must_use_constant_pool() &&
858 (instr & kMovMvnMask) != kMovMvnPattern) {
859 mov(ip, x, LeaveCC, cond);
860 } else {
861 RecordRelocInfo(x.rmode_, x.imm32_);
862 ldr(ip, MemOperand(pc, 0), cond);
863 }
864 addrmod1(instr, rn, rd, Operand(ip));
865 }
866 return;
867 }
868 instr |= I | rotate_imm*B8 | immed_8;
869 } else if (!x.rs_.is_valid()) {
870 // Immediate shift.
871 instr |= x.shift_imm_*B7 | x.shift_op_ | x.rm_.code();
872 } else {
873 // Register shift.
874 ASSERT(!rn.is(pc) && !rd.is(pc) && !x.rm_.is(pc) && !x.rs_.is(pc));
875 instr |= x.rs_.code()*B8 | x.shift_op_ | B4 | x.rm_.code();
876 }
877 emit(instr | rn.code()*B16 | rd.code()*B12);
878 if (rn.is(pc) || x.rm_.is(pc)) {
879 // Block constant pool emission for one instruction after reading pc.
880 BlockConstPoolFor(1);
881 }
882 }
883
884
addrmod2(Instr instr,Register rd,const MemOperand & x)885 void Assembler::addrmod2(Instr instr, Register rd, const MemOperand& x) {
886 ASSERT((instr & ~(kCondMask | B | L)) == B26);
887 int am = x.am_;
888 if (!x.rm_.is_valid()) {
889 // Immediate offset.
890 int offset_12 = x.offset_;
891 if (offset_12 < 0) {
892 offset_12 = -offset_12;
893 am ^= U;
894 }
895 if (!is_uint12(offset_12)) {
896 // Immediate offset cannot be encoded, load it first to register ip
897 // rn (and rd in a load) should never be ip, or will be trashed.
898 ASSERT(!x.rn_.is(ip) && ((instr & L) == L || !rd.is(ip)));
899 mov(ip, Operand(x.offset_), LeaveCC, Instruction::ConditionField(instr));
900 addrmod2(instr, rd, MemOperand(x.rn_, ip, x.am_));
901 return;
902 }
903 ASSERT(offset_12 >= 0); // no masking needed
904 instr |= offset_12;
905 } else {
906 // Register offset (shift_imm_ and shift_op_ are 0) or scaled
907 // register offset the constructors make sure than both shift_imm_
908 // and shift_op_ are initialized.
909 ASSERT(!x.rm_.is(pc));
910 instr |= B25 | x.shift_imm_*B7 | x.shift_op_ | x.rm_.code();
911 }
912 ASSERT((am & (P|W)) == P || !x.rn_.is(pc)); // no pc base with writeback
913 emit(instr | am | x.rn_.code()*B16 | rd.code()*B12);
914 }
915
916
addrmod3(Instr instr,Register rd,const MemOperand & x)917 void Assembler::addrmod3(Instr instr, Register rd, const MemOperand& x) {
918 ASSERT((instr & ~(kCondMask | L | S6 | H)) == (B4 | B7));
919 ASSERT(x.rn_.is_valid());
920 int am = x.am_;
921 if (!x.rm_.is_valid()) {
922 // Immediate offset.
923 int offset_8 = x.offset_;
924 if (offset_8 < 0) {
925 offset_8 = -offset_8;
926 am ^= U;
927 }
928 if (!is_uint8(offset_8)) {
929 // Immediate offset cannot be encoded, load it first to register ip
930 // rn (and rd in a load) should never be ip, or will be trashed.
931 ASSERT(!x.rn_.is(ip) && ((instr & L) == L || !rd.is(ip)));
932 mov(ip, Operand(x.offset_), LeaveCC, Instruction::ConditionField(instr));
933 addrmod3(instr, rd, MemOperand(x.rn_, ip, x.am_));
934 return;
935 }
936 ASSERT(offset_8 >= 0); // no masking needed
937 instr |= B | (offset_8 >> 4)*B8 | (offset_8 & 0xf);
938 } else if (x.shift_imm_ != 0) {
939 // Scaled register offset not supported, load index first
940 // rn (and rd in a load) should never be ip, or will be trashed.
941 ASSERT(!x.rn_.is(ip) && ((instr & L) == L || !rd.is(ip)));
942 mov(ip, Operand(x.rm_, x.shift_op_, x.shift_imm_), LeaveCC,
943 Instruction::ConditionField(instr));
944 addrmod3(instr, rd, MemOperand(x.rn_, ip, x.am_));
945 return;
946 } else {
947 // Register offset.
948 ASSERT((am & (P|W)) == P || !x.rm_.is(pc)); // no pc index with writeback
949 instr |= x.rm_.code();
950 }
951 ASSERT((am & (P|W)) == P || !x.rn_.is(pc)); // no pc base with writeback
952 emit(instr | am | x.rn_.code()*B16 | rd.code()*B12);
953 }
954
955
addrmod4(Instr instr,Register rn,RegList rl)956 void Assembler::addrmod4(Instr instr, Register rn, RegList rl) {
957 ASSERT((instr & ~(kCondMask | P | U | W | L)) == B27);
958 ASSERT(rl != 0);
959 ASSERT(!rn.is(pc));
960 emit(instr | rn.code()*B16 | rl);
961 }
962
963
addrmod5(Instr instr,CRegister crd,const MemOperand & x)964 void Assembler::addrmod5(Instr instr, CRegister crd, const MemOperand& x) {
965 // Unindexed addressing is not encoded by this function.
966 ASSERT_EQ((B27 | B26),
967 (instr & ~(kCondMask | kCoprocessorMask | P | U | N | W | L)));
968 ASSERT(x.rn_.is_valid() && !x.rm_.is_valid());
969 int am = x.am_;
970 int offset_8 = x.offset_;
971 ASSERT((offset_8 & 3) == 0); // offset must be an aligned word offset
972 offset_8 >>= 2;
973 if (offset_8 < 0) {
974 offset_8 = -offset_8;
975 am ^= U;
976 }
977 ASSERT(is_uint8(offset_8)); // unsigned word offset must fit in a byte
978 ASSERT((am & (P|W)) == P || !x.rn_.is(pc)); // no pc base with writeback
979
980 // Post-indexed addressing requires W == 1; different than in addrmod2/3.
981 if ((am & P) == 0)
982 am |= W;
983
984 ASSERT(offset_8 >= 0); // no masking needed
985 emit(instr | am | x.rn_.code()*B16 | crd.code()*B12 | offset_8);
986 }
987
988
branch_offset(Label * L,bool jump_elimination_allowed)989 int Assembler::branch_offset(Label* L, bool jump_elimination_allowed) {
990 int target_pos;
991 if (L->is_bound()) {
992 target_pos = L->pos();
993 } else {
994 if (L->is_linked()) {
995 target_pos = L->pos(); // L's link
996 } else {
997 target_pos = kEndOfChain;
998 }
999 L->link_to(pc_offset());
1000 }
1001
1002 // Block the emission of the constant pool, since the branch instruction must
1003 // be emitted at the pc offset recorded by the label.
1004 BlockConstPoolFor(1);
1005 return target_pos - (pc_offset() + kPcLoadDelta);
1006 }
1007
1008
label_at_put(Label * L,int at_offset)1009 void Assembler::label_at_put(Label* L, int at_offset) {
1010 int target_pos;
1011 if (L->is_bound()) {
1012 target_pos = L->pos();
1013 } else {
1014 if (L->is_linked()) {
1015 target_pos = L->pos(); // L's link
1016 } else {
1017 target_pos = kEndOfChain;
1018 }
1019 L->link_to(at_offset);
1020 instr_at_put(at_offset, target_pos + (Code::kHeaderSize - kHeapObjectTag));
1021 }
1022 }
1023
1024
1025 // Branch instructions.
b(int branch_offset,Condition cond)1026 void Assembler::b(int branch_offset, Condition cond) {
1027 ASSERT((branch_offset & 3) == 0);
1028 int imm24 = branch_offset >> 2;
1029 ASSERT(is_int24(imm24));
1030 emit(cond | B27 | B25 | (imm24 & kImm24Mask));
1031
1032 if (cond == al) {
1033 // Dead code is a good location to emit the constant pool.
1034 CheckConstPool(false, false);
1035 }
1036 }
1037
1038
bl(int branch_offset,Condition cond)1039 void Assembler::bl(int branch_offset, Condition cond) {
1040 positions_recorder()->WriteRecordedPositions();
1041 ASSERT((branch_offset & 3) == 0);
1042 int imm24 = branch_offset >> 2;
1043 ASSERT(is_int24(imm24));
1044 emit(cond | B27 | B25 | B24 | (imm24 & kImm24Mask));
1045 }
1046
1047
blx(int branch_offset)1048 void Assembler::blx(int branch_offset) { // v5 and above
1049 positions_recorder()->WriteRecordedPositions();
1050 ASSERT((branch_offset & 1) == 0);
1051 int h = ((branch_offset & 2) >> 1)*B24;
1052 int imm24 = branch_offset >> 2;
1053 ASSERT(is_int24(imm24));
1054 emit(kSpecialCondition | B27 | B25 | h | (imm24 & kImm24Mask));
1055 }
1056
1057
blx(Register target,Condition cond)1058 void Assembler::blx(Register target, Condition cond) { // v5 and above
1059 positions_recorder()->WriteRecordedPositions();
1060 ASSERT(!target.is(pc));
1061 emit(cond | B24 | B21 | 15*B16 | 15*B12 | 15*B8 | BLX | target.code());
1062 }
1063
1064
bx(Register target,Condition cond)1065 void Assembler::bx(Register target, Condition cond) { // v5 and above, plus v4t
1066 positions_recorder()->WriteRecordedPositions();
1067 ASSERT(!target.is(pc)); // use of pc is actually allowed, but discouraged
1068 emit(cond | B24 | B21 | 15*B16 | 15*B12 | 15*B8 | BX | target.code());
1069 }
1070
1071
1072 // Data-processing instructions.
1073
and_(Register dst,Register src1,const Operand & src2,SBit s,Condition cond)1074 void Assembler::and_(Register dst, Register src1, const Operand& src2,
1075 SBit s, Condition cond) {
1076 addrmod1(cond | AND | s, src1, dst, src2);
1077 }
1078
1079
eor(Register dst,Register src1,const Operand & src2,SBit s,Condition cond)1080 void Assembler::eor(Register dst, Register src1, const Operand& src2,
1081 SBit s, Condition cond) {
1082 addrmod1(cond | EOR | s, src1, dst, src2);
1083 }
1084
1085
sub(Register dst,Register src1,const Operand & src2,SBit s,Condition cond)1086 void Assembler::sub(Register dst, Register src1, const Operand& src2,
1087 SBit s, Condition cond) {
1088 addrmod1(cond | SUB | s, src1, dst, src2);
1089 }
1090
1091
rsb(Register dst,Register src1,const Operand & src2,SBit s,Condition cond)1092 void Assembler::rsb(Register dst, Register src1, const Operand& src2,
1093 SBit s, Condition cond) {
1094 addrmod1(cond | RSB | s, src1, dst, src2);
1095 }
1096
1097
add(Register dst,Register src1,const Operand & src2,SBit s,Condition cond)1098 void Assembler::add(Register dst, Register src1, const Operand& src2,
1099 SBit s, Condition cond) {
1100 addrmod1(cond | ADD | s, src1, dst, src2);
1101 }
1102
1103
adc(Register dst,Register src1,const Operand & src2,SBit s,Condition cond)1104 void Assembler::adc(Register dst, Register src1, const Operand& src2,
1105 SBit s, Condition cond) {
1106 addrmod1(cond | ADC | s, src1, dst, src2);
1107 }
1108
1109
sbc(Register dst,Register src1,const Operand & src2,SBit s,Condition cond)1110 void Assembler::sbc(Register dst, Register src1, const Operand& src2,
1111 SBit s, Condition cond) {
1112 addrmod1(cond | SBC | s, src1, dst, src2);
1113 }
1114
1115
rsc(Register dst,Register src1,const Operand & src2,SBit s,Condition cond)1116 void Assembler::rsc(Register dst, Register src1, const Operand& src2,
1117 SBit s, Condition cond) {
1118 addrmod1(cond | RSC | s, src1, dst, src2);
1119 }
1120
1121
tst(Register src1,const Operand & src2,Condition cond)1122 void Assembler::tst(Register src1, const Operand& src2, Condition cond) {
1123 addrmod1(cond | TST | S, src1, r0, src2);
1124 }
1125
1126
teq(Register src1,const Operand & src2,Condition cond)1127 void Assembler::teq(Register src1, const Operand& src2, Condition cond) {
1128 addrmod1(cond | TEQ | S, src1, r0, src2);
1129 }
1130
1131
cmp(Register src1,const Operand & src2,Condition cond)1132 void Assembler::cmp(Register src1, const Operand& src2, Condition cond) {
1133 addrmod1(cond | CMP | S, src1, r0, src2);
1134 }
1135
1136
cmp_raw_immediate(Register src,int raw_immediate,Condition cond)1137 void Assembler::cmp_raw_immediate(
1138 Register src, int raw_immediate, Condition cond) {
1139 ASSERT(is_uint12(raw_immediate));
1140 emit(cond | I | CMP | S | src.code() << 16 | raw_immediate);
1141 }
1142
1143
cmn(Register src1,const Operand & src2,Condition cond)1144 void Assembler::cmn(Register src1, const Operand& src2, Condition cond) {
1145 addrmod1(cond | CMN | S, src1, r0, src2);
1146 }
1147
1148
orr(Register dst,Register src1,const Operand & src2,SBit s,Condition cond)1149 void Assembler::orr(Register dst, Register src1, const Operand& src2,
1150 SBit s, Condition cond) {
1151 addrmod1(cond | ORR | s, src1, dst, src2);
1152 }
1153
1154
mov(Register dst,const Operand & src,SBit s,Condition cond)1155 void Assembler::mov(Register dst, const Operand& src, SBit s, Condition cond) {
1156 if (dst.is(pc)) {
1157 positions_recorder()->WriteRecordedPositions();
1158 }
1159 // Don't allow nop instructions in the form mov rn, rn to be generated using
1160 // the mov instruction. They must be generated using nop(int/NopMarkerTypes)
1161 // or MarkCode(int/NopMarkerTypes) pseudo instructions.
1162 ASSERT(!(src.is_reg() && src.rm().is(dst) && s == LeaveCC && cond == al));
1163 addrmod1(cond | MOV | s, r0, dst, src);
1164 }
1165
1166
movw(Register reg,uint32_t immediate,Condition cond)1167 void Assembler::movw(Register reg, uint32_t immediate, Condition cond) {
1168 ASSERT(immediate < 0x10000);
1169 mov(reg, Operand(immediate), LeaveCC, cond);
1170 }
1171
1172
movt(Register reg,uint32_t immediate,Condition cond)1173 void Assembler::movt(Register reg, uint32_t immediate, Condition cond) {
1174 emit(cond | 0x34*B20 | reg.code()*B12 | EncodeMovwImmediate(immediate));
1175 }
1176
1177
bic(Register dst,Register src1,const Operand & src2,SBit s,Condition cond)1178 void Assembler::bic(Register dst, Register src1, const Operand& src2,
1179 SBit s, Condition cond) {
1180 addrmod1(cond | BIC | s, src1, dst, src2);
1181 }
1182
1183
mvn(Register dst,const Operand & src,SBit s,Condition cond)1184 void Assembler::mvn(Register dst, const Operand& src, SBit s, Condition cond) {
1185 addrmod1(cond | MVN | s, r0, dst, src);
1186 }
1187
1188
1189 // Multiply instructions.
mla(Register dst,Register src1,Register src2,Register srcA,SBit s,Condition cond)1190 void Assembler::mla(Register dst, Register src1, Register src2, Register srcA,
1191 SBit s, Condition cond) {
1192 ASSERT(!dst.is(pc) && !src1.is(pc) && !src2.is(pc) && !srcA.is(pc));
1193 emit(cond | A | s | dst.code()*B16 | srcA.code()*B12 |
1194 src2.code()*B8 | B7 | B4 | src1.code());
1195 }
1196
1197
mul(Register dst,Register src1,Register src2,SBit s,Condition cond)1198 void Assembler::mul(Register dst, Register src1, Register src2,
1199 SBit s, Condition cond) {
1200 ASSERT(!dst.is(pc) && !src1.is(pc) && !src2.is(pc));
1201 // dst goes in bits 16-19 for this instruction!
1202 emit(cond | s | dst.code()*B16 | src2.code()*B8 | B7 | B4 | src1.code());
1203 }
1204
1205
smlal(Register dstL,Register dstH,Register src1,Register src2,SBit s,Condition cond)1206 void Assembler::smlal(Register dstL,
1207 Register dstH,
1208 Register src1,
1209 Register src2,
1210 SBit s,
1211 Condition cond) {
1212 ASSERT(!dstL.is(pc) && !dstH.is(pc) && !src1.is(pc) && !src2.is(pc));
1213 ASSERT(!dstL.is(dstH));
1214 emit(cond | B23 | B22 | A | s | dstH.code()*B16 | dstL.code()*B12 |
1215 src2.code()*B8 | B7 | B4 | src1.code());
1216 }
1217
1218
smull(Register dstL,Register dstH,Register src1,Register src2,SBit s,Condition cond)1219 void Assembler::smull(Register dstL,
1220 Register dstH,
1221 Register src1,
1222 Register src2,
1223 SBit s,
1224 Condition cond) {
1225 ASSERT(!dstL.is(pc) && !dstH.is(pc) && !src1.is(pc) && !src2.is(pc));
1226 ASSERT(!dstL.is(dstH));
1227 emit(cond | B23 | B22 | s | dstH.code()*B16 | dstL.code()*B12 |
1228 src2.code()*B8 | B7 | B4 | src1.code());
1229 }
1230
1231
umlal(Register dstL,Register dstH,Register src1,Register src2,SBit s,Condition cond)1232 void Assembler::umlal(Register dstL,
1233 Register dstH,
1234 Register src1,
1235 Register src2,
1236 SBit s,
1237 Condition cond) {
1238 ASSERT(!dstL.is(pc) && !dstH.is(pc) && !src1.is(pc) && !src2.is(pc));
1239 ASSERT(!dstL.is(dstH));
1240 emit(cond | B23 | A | s | dstH.code()*B16 | dstL.code()*B12 |
1241 src2.code()*B8 | B7 | B4 | src1.code());
1242 }
1243
1244
umull(Register dstL,Register dstH,Register src1,Register src2,SBit s,Condition cond)1245 void Assembler::umull(Register dstL,
1246 Register dstH,
1247 Register src1,
1248 Register src2,
1249 SBit s,
1250 Condition cond) {
1251 ASSERT(!dstL.is(pc) && !dstH.is(pc) && !src1.is(pc) && !src2.is(pc));
1252 ASSERT(!dstL.is(dstH));
1253 emit(cond | B23 | s | dstH.code()*B16 | dstL.code()*B12 |
1254 src2.code()*B8 | B7 | B4 | src1.code());
1255 }
1256
1257
1258 // Miscellaneous arithmetic instructions.
clz(Register dst,Register src,Condition cond)1259 void Assembler::clz(Register dst, Register src, Condition cond) {
1260 // v5 and above.
1261 ASSERT(!dst.is(pc) && !src.is(pc));
1262 emit(cond | B24 | B22 | B21 | 15*B16 | dst.code()*B12 |
1263 15*B8 | CLZ | src.code());
1264 }
1265
1266
1267 // Saturating instructions.
1268
1269 // Unsigned saturate.
usat(Register dst,int satpos,const Operand & src,Condition cond)1270 void Assembler::usat(Register dst,
1271 int satpos,
1272 const Operand& src,
1273 Condition cond) {
1274 // v6 and above.
1275 ASSERT(CpuFeatures::IsSupported(ARMv7));
1276 ASSERT(!dst.is(pc) && !src.rm_.is(pc));
1277 ASSERT((satpos >= 0) && (satpos <= 31));
1278 ASSERT((src.shift_op_ == ASR) || (src.shift_op_ == LSL));
1279 ASSERT(src.rs_.is(no_reg));
1280
1281 int sh = 0;
1282 if (src.shift_op_ == ASR) {
1283 sh = 1;
1284 }
1285
1286 emit(cond | 0x6*B24 | 0xe*B20 | satpos*B16 | dst.code()*B12 |
1287 src.shift_imm_*B7 | sh*B6 | 0x1*B4 | src.rm_.code());
1288 }
1289
1290
1291 // Bitfield manipulation instructions.
1292
1293 // Unsigned bit field extract.
1294 // Extracts #width adjacent bits from position #lsb in a register, and
1295 // writes them to the low bits of a destination register.
1296 // ubfx dst, src, #lsb, #width
ubfx(Register dst,Register src,int lsb,int width,Condition cond)1297 void Assembler::ubfx(Register dst,
1298 Register src,
1299 int lsb,
1300 int width,
1301 Condition cond) {
1302 // v7 and above.
1303 ASSERT(CpuFeatures::IsSupported(ARMv7));
1304 ASSERT(!dst.is(pc) && !src.is(pc));
1305 ASSERT((lsb >= 0) && (lsb <= 31));
1306 ASSERT((width >= 1) && (width <= (32 - lsb)));
1307 emit(cond | 0xf*B23 | B22 | B21 | (width - 1)*B16 | dst.code()*B12 |
1308 lsb*B7 | B6 | B4 | src.code());
1309 }
1310
1311
1312 // Signed bit field extract.
1313 // Extracts #width adjacent bits from position #lsb in a register, and
1314 // writes them to the low bits of a destination register. The extracted
1315 // value is sign extended to fill the destination register.
1316 // sbfx dst, src, #lsb, #width
sbfx(Register dst,Register src,int lsb,int width,Condition cond)1317 void Assembler::sbfx(Register dst,
1318 Register src,
1319 int lsb,
1320 int width,
1321 Condition cond) {
1322 // v7 and above.
1323 ASSERT(CpuFeatures::IsSupported(ARMv7));
1324 ASSERT(!dst.is(pc) && !src.is(pc));
1325 ASSERT((lsb >= 0) && (lsb <= 31));
1326 ASSERT((width >= 1) && (width <= (32 - lsb)));
1327 emit(cond | 0xf*B23 | B21 | (width - 1)*B16 | dst.code()*B12 |
1328 lsb*B7 | B6 | B4 | src.code());
1329 }
1330
1331
1332 // Bit field clear.
1333 // Sets #width adjacent bits at position #lsb in the destination register
1334 // to zero, preserving the value of the other bits.
1335 // bfc dst, #lsb, #width
bfc(Register dst,int lsb,int width,Condition cond)1336 void Assembler::bfc(Register dst, int lsb, int width, Condition cond) {
1337 // v7 and above.
1338 ASSERT(CpuFeatures::IsSupported(ARMv7));
1339 ASSERT(!dst.is(pc));
1340 ASSERT((lsb >= 0) && (lsb <= 31));
1341 ASSERT((width >= 1) && (width <= (32 - lsb)));
1342 int msb = lsb + width - 1;
1343 emit(cond | 0x1f*B22 | msb*B16 | dst.code()*B12 | lsb*B7 | B4 | 0xf);
1344 }
1345
1346
1347 // Bit field insert.
1348 // Inserts #width adjacent bits from the low bits of the source register
1349 // into position #lsb of the destination register.
1350 // bfi dst, src, #lsb, #width
bfi(Register dst,Register src,int lsb,int width,Condition cond)1351 void Assembler::bfi(Register dst,
1352 Register src,
1353 int lsb,
1354 int width,
1355 Condition cond) {
1356 // v7 and above.
1357 ASSERT(CpuFeatures::IsSupported(ARMv7));
1358 ASSERT(!dst.is(pc) && !src.is(pc));
1359 ASSERT((lsb >= 0) && (lsb <= 31));
1360 ASSERT((width >= 1) && (width <= (32 - lsb)));
1361 int msb = lsb + width - 1;
1362 emit(cond | 0x1f*B22 | msb*B16 | dst.code()*B12 | lsb*B7 | B4 |
1363 src.code());
1364 }
1365
1366
1367 // Status register access instructions.
mrs(Register dst,SRegister s,Condition cond)1368 void Assembler::mrs(Register dst, SRegister s, Condition cond) {
1369 ASSERT(!dst.is(pc));
1370 emit(cond | B24 | s | 15*B16 | dst.code()*B12);
1371 }
1372
1373
msr(SRegisterFieldMask fields,const Operand & src,Condition cond)1374 void Assembler::msr(SRegisterFieldMask fields, const Operand& src,
1375 Condition cond) {
1376 ASSERT(fields >= B16 && fields < B20); // at least one field set
1377 Instr instr;
1378 if (!src.rm_.is_valid()) {
1379 // Immediate.
1380 uint32_t rotate_imm;
1381 uint32_t immed_8;
1382 if (src.must_use_constant_pool() ||
1383 !fits_shifter(src.imm32_, &rotate_imm, &immed_8, NULL)) {
1384 // Immediate operand cannot be encoded, load it first to register ip.
1385 RecordRelocInfo(src.rmode_, src.imm32_);
1386 ldr(ip, MemOperand(pc, 0), cond);
1387 msr(fields, Operand(ip), cond);
1388 return;
1389 }
1390 instr = I | rotate_imm*B8 | immed_8;
1391 } else {
1392 ASSERT(!src.rs_.is_valid() && src.shift_imm_ == 0); // only rm allowed
1393 instr = src.rm_.code();
1394 }
1395 emit(cond | instr | B24 | B21 | fields | 15*B12);
1396 }
1397
1398
1399 // Load/Store instructions.
ldr(Register dst,const MemOperand & src,Condition cond)1400 void Assembler::ldr(Register dst, const MemOperand& src, Condition cond) {
1401 if (dst.is(pc)) {
1402 positions_recorder()->WriteRecordedPositions();
1403 }
1404 addrmod2(cond | B26 | L, dst, src);
1405 }
1406
1407
str(Register src,const MemOperand & dst,Condition cond)1408 void Assembler::str(Register src, const MemOperand& dst, Condition cond) {
1409 addrmod2(cond | B26, src, dst);
1410 }
1411
1412
ldrb(Register dst,const MemOperand & src,Condition cond)1413 void Assembler::ldrb(Register dst, const MemOperand& src, Condition cond) {
1414 addrmod2(cond | B26 | B | L, dst, src);
1415 }
1416
1417
strb(Register src,const MemOperand & dst,Condition cond)1418 void Assembler::strb(Register src, const MemOperand& dst, Condition cond) {
1419 addrmod2(cond | B26 | B, src, dst);
1420 }
1421
1422
ldrh(Register dst,const MemOperand & src,Condition cond)1423 void Assembler::ldrh(Register dst, const MemOperand& src, Condition cond) {
1424 addrmod3(cond | L | B7 | H | B4, dst, src);
1425 }
1426
1427
strh(Register src,const MemOperand & dst,Condition cond)1428 void Assembler::strh(Register src, const MemOperand& dst, Condition cond) {
1429 addrmod3(cond | B7 | H | B4, src, dst);
1430 }
1431
1432
ldrsb(Register dst,const MemOperand & src,Condition cond)1433 void Assembler::ldrsb(Register dst, const MemOperand& src, Condition cond) {
1434 addrmod3(cond | L | B7 | S6 | B4, dst, src);
1435 }
1436
1437
ldrsh(Register dst,const MemOperand & src,Condition cond)1438 void Assembler::ldrsh(Register dst, const MemOperand& src, Condition cond) {
1439 addrmod3(cond | L | B7 | S6 | H | B4, dst, src);
1440 }
1441
1442
ldrd(Register dst1,Register dst2,const MemOperand & src,Condition cond)1443 void Assembler::ldrd(Register dst1, Register dst2,
1444 const MemOperand& src, Condition cond) {
1445 ASSERT(CpuFeatures::IsEnabled(ARMv7));
1446 ASSERT(src.rm().is(no_reg));
1447 ASSERT(!dst1.is(lr)); // r14.
1448 ASSERT_EQ(0, dst1.code() % 2);
1449 ASSERT_EQ(dst1.code() + 1, dst2.code());
1450 addrmod3(cond | B7 | B6 | B4, dst1, src);
1451 }
1452
1453
strd(Register src1,Register src2,const MemOperand & dst,Condition cond)1454 void Assembler::strd(Register src1, Register src2,
1455 const MemOperand& dst, Condition cond) {
1456 ASSERT(dst.rm().is(no_reg));
1457 ASSERT(!src1.is(lr)); // r14.
1458 ASSERT_EQ(0, src1.code() % 2);
1459 ASSERT_EQ(src1.code() + 1, src2.code());
1460 ASSERT(CpuFeatures::IsEnabled(ARMv7));
1461 addrmod3(cond | B7 | B6 | B5 | B4, src1, dst);
1462 }
1463
1464 // Load/Store multiple instructions.
ldm(BlockAddrMode am,Register base,RegList dst,Condition cond)1465 void Assembler::ldm(BlockAddrMode am,
1466 Register base,
1467 RegList dst,
1468 Condition cond) {
1469 // ABI stack constraint: ldmxx base, {..sp..} base != sp is not restartable.
1470 ASSERT(base.is(sp) || (dst & sp.bit()) == 0);
1471
1472 addrmod4(cond | B27 | am | L, base, dst);
1473
1474 // Emit the constant pool after a function return implemented by ldm ..{..pc}.
1475 if (cond == al && (dst & pc.bit()) != 0) {
1476 // There is a slight chance that the ldm instruction was actually a call,
1477 // in which case it would be wrong to return into the constant pool; we
1478 // recognize this case by checking if the emission of the pool was blocked
1479 // at the pc of the ldm instruction by a mov lr, pc instruction; if this is
1480 // the case, we emit a jump over the pool.
1481 CheckConstPool(true, no_const_pool_before_ == pc_offset() - kInstrSize);
1482 }
1483 }
1484
1485
stm(BlockAddrMode am,Register base,RegList src,Condition cond)1486 void Assembler::stm(BlockAddrMode am,
1487 Register base,
1488 RegList src,
1489 Condition cond) {
1490 addrmod4(cond | B27 | am, base, src);
1491 }
1492
1493
1494 // Exception-generating instructions and debugging support.
1495 // Stops with a non-negative code less than kNumOfWatchedStops support
1496 // enabling/disabling and a counter feature. See simulator-arm.h .
stop(const char * msg,Condition cond,int32_t code)1497 void Assembler::stop(const char* msg, Condition cond, int32_t code) {
1498 #ifndef __arm__
1499 ASSERT(code >= kDefaultStopCode);
1500 {
1501 // The Simulator will handle the stop instruction and get the message
1502 // address. It expects to find the address just after the svc instruction.
1503 BlockConstPoolScope block_const_pool(this);
1504 if (code >= 0) {
1505 svc(kStopCode + code, cond);
1506 } else {
1507 svc(kStopCode + kMaxStopCode, cond);
1508 }
1509 emit(reinterpret_cast<Instr>(msg));
1510 }
1511 #else // def __arm__
1512 #ifdef CAN_USE_ARMV5_INSTRUCTIONS
1513 if (cond != al) {
1514 Label skip;
1515 b(&skip, NegateCondition(cond));
1516 bkpt(0);
1517 bind(&skip);
1518 } else {
1519 bkpt(0);
1520 }
1521 #else // ndef CAN_USE_ARMV5_INSTRUCTIONS
1522 svc(0x9f0001, cond);
1523 #endif // ndef CAN_USE_ARMV5_INSTRUCTIONS
1524 #endif // def __arm__
1525 }
1526
1527
bkpt(uint32_t imm16)1528 void Assembler::bkpt(uint32_t imm16) { // v5 and above
1529 ASSERT(is_uint16(imm16));
1530 emit(al | B24 | B21 | (imm16 >> 4)*B8 | BKPT | (imm16 & 0xf));
1531 }
1532
1533
svc(uint32_t imm24,Condition cond)1534 void Assembler::svc(uint32_t imm24, Condition cond) {
1535 ASSERT(is_uint24(imm24));
1536 emit(cond | 15*B24 | imm24);
1537 }
1538
1539
1540 // Coprocessor instructions.
cdp(Coprocessor coproc,int opcode_1,CRegister crd,CRegister crn,CRegister crm,int opcode_2,Condition cond)1541 void Assembler::cdp(Coprocessor coproc,
1542 int opcode_1,
1543 CRegister crd,
1544 CRegister crn,
1545 CRegister crm,
1546 int opcode_2,
1547 Condition cond) {
1548 ASSERT(is_uint4(opcode_1) && is_uint3(opcode_2));
1549 emit(cond | B27 | B26 | B25 | (opcode_1 & 15)*B20 | crn.code()*B16 |
1550 crd.code()*B12 | coproc*B8 | (opcode_2 & 7)*B5 | crm.code());
1551 }
1552
1553
cdp2(Coprocessor coproc,int opcode_1,CRegister crd,CRegister crn,CRegister crm,int opcode_2)1554 void Assembler::cdp2(Coprocessor coproc,
1555 int opcode_1,
1556 CRegister crd,
1557 CRegister crn,
1558 CRegister crm,
1559 int opcode_2) { // v5 and above
1560 cdp(coproc, opcode_1, crd, crn, crm, opcode_2, kSpecialCondition);
1561 }
1562
1563
mcr(Coprocessor coproc,int opcode_1,Register rd,CRegister crn,CRegister crm,int opcode_2,Condition cond)1564 void Assembler::mcr(Coprocessor coproc,
1565 int opcode_1,
1566 Register rd,
1567 CRegister crn,
1568 CRegister crm,
1569 int opcode_2,
1570 Condition cond) {
1571 ASSERT(is_uint3(opcode_1) && is_uint3(opcode_2));
1572 emit(cond | B27 | B26 | B25 | (opcode_1 & 7)*B21 | crn.code()*B16 |
1573 rd.code()*B12 | coproc*B8 | (opcode_2 & 7)*B5 | B4 | crm.code());
1574 }
1575
1576
mcr2(Coprocessor coproc,int opcode_1,Register rd,CRegister crn,CRegister crm,int opcode_2)1577 void Assembler::mcr2(Coprocessor coproc,
1578 int opcode_1,
1579 Register rd,
1580 CRegister crn,
1581 CRegister crm,
1582 int opcode_2) { // v5 and above
1583 mcr(coproc, opcode_1, rd, crn, crm, opcode_2, kSpecialCondition);
1584 }
1585
1586
mrc(Coprocessor coproc,int opcode_1,Register rd,CRegister crn,CRegister crm,int opcode_2,Condition cond)1587 void Assembler::mrc(Coprocessor coproc,
1588 int opcode_1,
1589 Register rd,
1590 CRegister crn,
1591 CRegister crm,
1592 int opcode_2,
1593 Condition cond) {
1594 ASSERT(is_uint3(opcode_1) && is_uint3(opcode_2));
1595 emit(cond | B27 | B26 | B25 | (opcode_1 & 7)*B21 | L | crn.code()*B16 |
1596 rd.code()*B12 | coproc*B8 | (opcode_2 & 7)*B5 | B4 | crm.code());
1597 }
1598
1599
mrc2(Coprocessor coproc,int opcode_1,Register rd,CRegister crn,CRegister crm,int opcode_2)1600 void Assembler::mrc2(Coprocessor coproc,
1601 int opcode_1,
1602 Register rd,
1603 CRegister crn,
1604 CRegister crm,
1605 int opcode_2) { // v5 and above
1606 mrc(coproc, opcode_1, rd, crn, crm, opcode_2, kSpecialCondition);
1607 }
1608
1609
ldc(Coprocessor coproc,CRegister crd,const MemOperand & src,LFlag l,Condition cond)1610 void Assembler::ldc(Coprocessor coproc,
1611 CRegister crd,
1612 const MemOperand& src,
1613 LFlag l,
1614 Condition cond) {
1615 addrmod5(cond | B27 | B26 | l | L | coproc*B8, crd, src);
1616 }
1617
1618
ldc(Coprocessor coproc,CRegister crd,Register rn,int option,LFlag l,Condition cond)1619 void Assembler::ldc(Coprocessor coproc,
1620 CRegister crd,
1621 Register rn,
1622 int option,
1623 LFlag l,
1624 Condition cond) {
1625 // Unindexed addressing.
1626 ASSERT(is_uint8(option));
1627 emit(cond | B27 | B26 | U | l | L | rn.code()*B16 | crd.code()*B12 |
1628 coproc*B8 | (option & 255));
1629 }
1630
1631
ldc2(Coprocessor coproc,CRegister crd,const MemOperand & src,LFlag l)1632 void Assembler::ldc2(Coprocessor coproc,
1633 CRegister crd,
1634 const MemOperand& src,
1635 LFlag l) { // v5 and above
1636 ldc(coproc, crd, src, l, kSpecialCondition);
1637 }
1638
1639
ldc2(Coprocessor coproc,CRegister crd,Register rn,int option,LFlag l)1640 void Assembler::ldc2(Coprocessor coproc,
1641 CRegister crd,
1642 Register rn,
1643 int option,
1644 LFlag l) { // v5 and above
1645 ldc(coproc, crd, rn, option, l, kSpecialCondition);
1646 }
1647
1648
1649 // Support for VFP.
1650
vldr(const DwVfpRegister dst,const Register base,int offset,const Condition cond)1651 void Assembler::vldr(const DwVfpRegister dst,
1652 const Register base,
1653 int offset,
1654 const Condition cond) {
1655 // Ddst = MEM(Rbase + offset).
1656 // Instruction details available in ARM DDI 0406A, A8-628.
1657 // cond(31-28) | 1101(27-24)| U001(23-20) | Rbase(19-16) |
1658 // Vdst(15-12) | 1011(11-8) | offset
1659 ASSERT(CpuFeatures::IsEnabled(VFP3));
1660 int u = 1;
1661 if (offset < 0) {
1662 offset = -offset;
1663 u = 0;
1664 }
1665
1666 ASSERT(offset >= 0);
1667 if ((offset % 4) == 0 && (offset / 4) < 256) {
1668 emit(cond | u*B23 | 0xD1*B20 | base.code()*B16 | dst.code()*B12 |
1669 0xB*B8 | ((offset / 4) & 255));
1670 } else {
1671 // Larger offsets must be handled by computing the correct address
1672 // in the ip register.
1673 ASSERT(!base.is(ip));
1674 if (u == 1) {
1675 add(ip, base, Operand(offset));
1676 } else {
1677 sub(ip, base, Operand(offset));
1678 }
1679 emit(cond | 0xD1*B20 | ip.code()*B16 | dst.code()*B12 | 0xB*B8);
1680 }
1681 }
1682
1683
vldr(const DwVfpRegister dst,const MemOperand & operand,const Condition cond)1684 void Assembler::vldr(const DwVfpRegister dst,
1685 const MemOperand& operand,
1686 const Condition cond) {
1687 ASSERT(!operand.rm().is_valid());
1688 ASSERT(operand.am_ == Offset);
1689 vldr(dst, operand.rn(), operand.offset(), cond);
1690 }
1691
1692
vldr(const SwVfpRegister dst,const Register base,int offset,const Condition cond)1693 void Assembler::vldr(const SwVfpRegister dst,
1694 const Register base,
1695 int offset,
1696 const Condition cond) {
1697 // Sdst = MEM(Rbase + offset).
1698 // Instruction details available in ARM DDI 0406A, A8-628.
1699 // cond(31-28) | 1101(27-24)| U001(23-20) | Rbase(19-16) |
1700 // Vdst(15-12) | 1010(11-8) | offset
1701 ASSERT(CpuFeatures::IsEnabled(VFP3));
1702 int u = 1;
1703 if (offset < 0) {
1704 offset = -offset;
1705 u = 0;
1706 }
1707 int sd, d;
1708 dst.split_code(&sd, &d);
1709 ASSERT(offset >= 0);
1710
1711 if ((offset % 4) == 0 && (offset / 4) < 256) {
1712 emit(cond | u*B23 | d*B22 | 0xD1*B20 | base.code()*B16 | sd*B12 |
1713 0xA*B8 | ((offset / 4) & 255));
1714 } else {
1715 // Larger offsets must be handled by computing the correct address
1716 // in the ip register.
1717 ASSERT(!base.is(ip));
1718 if (u == 1) {
1719 add(ip, base, Operand(offset));
1720 } else {
1721 sub(ip, base, Operand(offset));
1722 }
1723 emit(cond | d*B22 | 0xD1*B20 | ip.code()*B16 | sd*B12 | 0xA*B8);
1724 }
1725 }
1726
1727
vldr(const SwVfpRegister dst,const MemOperand & operand,const Condition cond)1728 void Assembler::vldr(const SwVfpRegister dst,
1729 const MemOperand& operand,
1730 const Condition cond) {
1731 ASSERT(!operand.rm().is_valid());
1732 ASSERT(operand.am_ == Offset);
1733 vldr(dst, operand.rn(), operand.offset(), cond);
1734 }
1735
1736
vstr(const DwVfpRegister src,const Register base,int offset,const Condition cond)1737 void Assembler::vstr(const DwVfpRegister src,
1738 const Register base,
1739 int offset,
1740 const Condition cond) {
1741 // MEM(Rbase + offset) = Dsrc.
1742 // Instruction details available in ARM DDI 0406A, A8-786.
1743 // cond(31-28) | 1101(27-24)| U000(23-20) | | Rbase(19-16) |
1744 // Vsrc(15-12) | 1011(11-8) | (offset/4)
1745 ASSERT(CpuFeatures::IsEnabled(VFP3));
1746 int u = 1;
1747 if (offset < 0) {
1748 offset = -offset;
1749 u = 0;
1750 }
1751 ASSERT(offset >= 0);
1752 if ((offset % 4) == 0 && (offset / 4) < 256) {
1753 emit(cond | u*B23 | 0xD0*B20 | base.code()*B16 | src.code()*B12 |
1754 0xB*B8 | ((offset / 4) & 255));
1755 } else {
1756 // Larger offsets must be handled by computing the correct address
1757 // in the ip register.
1758 ASSERT(!base.is(ip));
1759 if (u == 1) {
1760 add(ip, base, Operand(offset));
1761 } else {
1762 sub(ip, base, Operand(offset));
1763 }
1764 emit(cond | 0xD0*B20 | ip.code()*B16 | src.code()*B12 | 0xB*B8);
1765 }
1766 }
1767
1768
vstr(const DwVfpRegister src,const MemOperand & operand,const Condition cond)1769 void Assembler::vstr(const DwVfpRegister src,
1770 const MemOperand& operand,
1771 const Condition cond) {
1772 ASSERT(!operand.rm().is_valid());
1773 ASSERT(operand.am_ == Offset);
1774 vstr(src, operand.rn(), operand.offset(), cond);
1775 }
1776
1777
vstr(const SwVfpRegister src,const Register base,int offset,const Condition cond)1778 void Assembler::vstr(const SwVfpRegister src,
1779 const Register base,
1780 int offset,
1781 const Condition cond) {
1782 // MEM(Rbase + offset) = SSrc.
1783 // Instruction details available in ARM DDI 0406A, A8-786.
1784 // cond(31-28) | 1101(27-24)| U000(23-20) | Rbase(19-16) |
1785 // Vdst(15-12) | 1010(11-8) | (offset/4)
1786 ASSERT(CpuFeatures::IsEnabled(VFP3));
1787 int u = 1;
1788 if (offset < 0) {
1789 offset = -offset;
1790 u = 0;
1791 }
1792 int sd, d;
1793 src.split_code(&sd, &d);
1794 ASSERT(offset >= 0);
1795 if ((offset % 4) == 0 && (offset / 4) < 256) {
1796 emit(cond | u*B23 | d*B22 | 0xD0*B20 | base.code()*B16 | sd*B12 |
1797 0xA*B8 | ((offset / 4) & 255));
1798 } else {
1799 // Larger offsets must be handled by computing the correct address
1800 // in the ip register.
1801 ASSERT(!base.is(ip));
1802 if (u == 1) {
1803 add(ip, base, Operand(offset));
1804 } else {
1805 sub(ip, base, Operand(offset));
1806 }
1807 emit(cond | d*B22 | 0xD0*B20 | ip.code()*B16 | sd*B12 | 0xA*B8);
1808 }
1809 }
1810
1811
vstr(const SwVfpRegister src,const MemOperand & operand,const Condition cond)1812 void Assembler::vstr(const SwVfpRegister src,
1813 const MemOperand& operand,
1814 const Condition cond) {
1815 ASSERT(!operand.rm().is_valid());
1816 ASSERT(operand.am_ == Offset);
1817 vldr(src, operand.rn(), operand.offset(), cond);
1818 }
1819
1820
vldm(BlockAddrMode am,Register base,DwVfpRegister first,DwVfpRegister last,Condition cond)1821 void Assembler::vldm(BlockAddrMode am,
1822 Register base,
1823 DwVfpRegister first,
1824 DwVfpRegister last,
1825 Condition cond) {
1826 // Instruction details available in ARM DDI 0406A, A8-626.
1827 // cond(31-28) | 110(27-25)| PUDW1(24-20) | Rbase(19-16) |
1828 // first(15-12) | 1010(11-8) | (count * 2)
1829 ASSERT(CpuFeatures::IsEnabled(VFP3));
1830 ASSERT_LE(first.code(), last.code());
1831 ASSERT(am == ia || am == ia_w || am == db_w);
1832 ASSERT(!base.is(pc));
1833
1834 int sd, d;
1835 first.split_code(&sd, &d);
1836 int count = last.code() - first.code() + 1;
1837 emit(cond | B27 | B26 | am | d*B22 | B20 | base.code()*B16 | sd*B12 |
1838 0xB*B8 | count*2);
1839 }
1840
1841
vstm(BlockAddrMode am,Register base,DwVfpRegister first,DwVfpRegister last,Condition cond)1842 void Assembler::vstm(BlockAddrMode am,
1843 Register base,
1844 DwVfpRegister first,
1845 DwVfpRegister last,
1846 Condition cond) {
1847 // Instruction details available in ARM DDI 0406A, A8-784.
1848 // cond(31-28) | 110(27-25)| PUDW0(24-20) | Rbase(19-16) |
1849 // first(15-12) | 1011(11-8) | (count * 2)
1850 ASSERT(CpuFeatures::IsEnabled(VFP3));
1851 ASSERT_LE(first.code(), last.code());
1852 ASSERT(am == ia || am == ia_w || am == db_w);
1853 ASSERT(!base.is(pc));
1854
1855 int sd, d;
1856 first.split_code(&sd, &d);
1857 int count = last.code() - first.code() + 1;
1858 emit(cond | B27 | B26 | am | d*B22 | base.code()*B16 | sd*B12 |
1859 0xB*B8 | count*2);
1860 }
1861
vldm(BlockAddrMode am,Register base,SwVfpRegister first,SwVfpRegister last,Condition cond)1862 void Assembler::vldm(BlockAddrMode am,
1863 Register base,
1864 SwVfpRegister first,
1865 SwVfpRegister last,
1866 Condition cond) {
1867 // Instruction details available in ARM DDI 0406A, A8-626.
1868 // cond(31-28) | 110(27-25)| PUDW1(24-20) | Rbase(19-16) |
1869 // first(15-12) | 1010(11-8) | (count/2)
1870 ASSERT(CpuFeatures::IsEnabled(VFP3));
1871 ASSERT_LE(first.code(), last.code());
1872 ASSERT(am == ia || am == ia_w || am == db_w);
1873 ASSERT(!base.is(pc));
1874
1875 int sd, d;
1876 first.split_code(&sd, &d);
1877 int count = last.code() - first.code() + 1;
1878 emit(cond | B27 | B26 | am | d*B22 | B20 | base.code()*B16 | sd*B12 |
1879 0xA*B8 | count);
1880 }
1881
1882
vstm(BlockAddrMode am,Register base,SwVfpRegister first,SwVfpRegister last,Condition cond)1883 void Assembler::vstm(BlockAddrMode am,
1884 Register base,
1885 SwVfpRegister first,
1886 SwVfpRegister last,
1887 Condition cond) {
1888 // Instruction details available in ARM DDI 0406A, A8-784.
1889 // cond(31-28) | 110(27-25)| PUDW0(24-20) | Rbase(19-16) |
1890 // first(15-12) | 1011(11-8) | (count/2)
1891 ASSERT(CpuFeatures::IsEnabled(VFP3));
1892 ASSERT_LE(first.code(), last.code());
1893 ASSERT(am == ia || am == ia_w || am == db_w);
1894 ASSERT(!base.is(pc));
1895
1896 int sd, d;
1897 first.split_code(&sd, &d);
1898 int count = last.code() - first.code() + 1;
1899 emit(cond | B27 | B26 | am | d*B22 | base.code()*B16 | sd*B12 |
1900 0xA*B8 | count);
1901 }
1902
DoubleAsTwoUInt32(double d,uint32_t * lo,uint32_t * hi)1903 static void DoubleAsTwoUInt32(double d, uint32_t* lo, uint32_t* hi) {
1904 uint64_t i;
1905 memcpy(&i, &d, 8);
1906
1907 *lo = i & 0xffffffff;
1908 *hi = i >> 32;
1909 }
1910
1911 // Only works for little endian floating point formats.
1912 // We don't support VFP on the mixed endian floating point platform.
FitsVMOVDoubleImmediate(double d,uint32_t * encoding)1913 static bool FitsVMOVDoubleImmediate(double d, uint32_t *encoding) {
1914 ASSERT(CpuFeatures::IsEnabled(VFP3));
1915
1916 // VMOV can accept an immediate of the form:
1917 //
1918 // +/- m * 2^(-n) where 16 <= m <= 31 and 0 <= n <= 7
1919 //
1920 // The immediate is encoded using an 8-bit quantity, comprised of two
1921 // 4-bit fields. For an 8-bit immediate of the form:
1922 //
1923 // [abcdefgh]
1924 //
1925 // where a is the MSB and h is the LSB, an immediate 64-bit double can be
1926 // created of the form:
1927 //
1928 // [aBbbbbbb,bbcdefgh,00000000,00000000,
1929 // 00000000,00000000,00000000,00000000]
1930 //
1931 // where B = ~b.
1932 //
1933
1934 uint32_t lo, hi;
1935 DoubleAsTwoUInt32(d, &lo, &hi);
1936
1937 // The most obvious constraint is the long block of zeroes.
1938 if ((lo != 0) || ((hi & 0xffff) != 0)) {
1939 return false;
1940 }
1941
1942 // Bits 62:55 must be all clear or all set.
1943 if (((hi & 0x3fc00000) != 0) && ((hi & 0x3fc00000) != 0x3fc00000)) {
1944 return false;
1945 }
1946
1947 // Bit 63 must be NOT bit 62.
1948 if (((hi ^ (hi << 1)) & (0x40000000)) == 0) {
1949 return false;
1950 }
1951
1952 // Create the encoded immediate in the form:
1953 // [00000000,0000abcd,00000000,0000efgh]
1954 *encoding = (hi >> 16) & 0xf; // Low nybble.
1955 *encoding |= (hi >> 4) & 0x70000; // Low three bits of the high nybble.
1956 *encoding |= (hi >> 12) & 0x80000; // Top bit of the high nybble.
1957
1958 return true;
1959 }
1960
1961
vmov(const DwVfpRegister dst,double imm,const Condition cond)1962 void Assembler::vmov(const DwVfpRegister dst,
1963 double imm,
1964 const Condition cond) {
1965 // Dd = immediate
1966 // Instruction details available in ARM DDI 0406B, A8-640.
1967 ASSERT(CpuFeatures::IsEnabled(VFP3));
1968
1969 uint32_t enc;
1970 if (FitsVMOVDoubleImmediate(imm, &enc)) {
1971 // The double can be encoded in the instruction.
1972 emit(cond | 0xE*B24 | 0xB*B20 | dst.code()*B12 | 0xB*B8 | enc);
1973 } else {
1974 // Synthesise the double from ARM immediates. This could be implemented
1975 // using vldr from a constant pool.
1976 uint32_t lo, hi;
1977 DoubleAsTwoUInt32(imm, &lo, &hi);
1978
1979 if (lo == hi) {
1980 // If the lo and hi parts of the double are equal, the literal is easier
1981 // to create. This is the case with 0.0.
1982 mov(ip, Operand(lo));
1983 vmov(dst, ip, ip);
1984 } else {
1985 // Move the low part of the double into the lower of the corresponsing S
1986 // registers of D register dst.
1987 mov(ip, Operand(lo));
1988 vmov(dst.low(), ip, cond);
1989
1990 // Move the high part of the double into the higher of the corresponsing S
1991 // registers of D register dst.
1992 mov(ip, Operand(hi));
1993 vmov(dst.high(), ip, cond);
1994 }
1995 }
1996 }
1997
1998
vmov(const SwVfpRegister dst,const SwVfpRegister src,const Condition cond)1999 void Assembler::vmov(const SwVfpRegister dst,
2000 const SwVfpRegister src,
2001 const Condition cond) {
2002 // Sd = Sm
2003 // Instruction details available in ARM DDI 0406B, A8-642.
2004 ASSERT(CpuFeatures::IsEnabled(VFP3));
2005 int sd, d, sm, m;
2006 dst.split_code(&sd, &d);
2007 src.split_code(&sm, &m);
2008 emit(cond | 0xE*B24 | d*B22 | 0xB*B20 | sd*B12 | 0xA*B8 | B6 | m*B5 | sm);
2009 }
2010
2011
vmov(const DwVfpRegister dst,const DwVfpRegister src,const Condition cond)2012 void Assembler::vmov(const DwVfpRegister dst,
2013 const DwVfpRegister src,
2014 const Condition cond) {
2015 // Dd = Dm
2016 // Instruction details available in ARM DDI 0406B, A8-642.
2017 ASSERT(CpuFeatures::IsEnabled(VFP3));
2018 emit(cond | 0xE*B24 | 0xB*B20 |
2019 dst.code()*B12 | 0x5*B9 | B8 | B6 | src.code());
2020 }
2021
2022
vmov(const DwVfpRegister dst,const Register src1,const Register src2,const Condition cond)2023 void Assembler::vmov(const DwVfpRegister dst,
2024 const Register src1,
2025 const Register src2,
2026 const Condition cond) {
2027 // Dm = <Rt,Rt2>.
2028 // Instruction details available in ARM DDI 0406A, A8-646.
2029 // cond(31-28) | 1100(27-24)| 010(23-21) | op=0(20) | Rt2(19-16) |
2030 // Rt(15-12) | 1011(11-8) | 00(7-6) | M(5) | 1(4) | Vm
2031 ASSERT(CpuFeatures::IsEnabled(VFP3));
2032 ASSERT(!src1.is(pc) && !src2.is(pc));
2033 emit(cond | 0xC*B24 | B22 | src2.code()*B16 |
2034 src1.code()*B12 | 0xB*B8 | B4 | dst.code());
2035 }
2036
2037
vmov(const Register dst1,const Register dst2,const DwVfpRegister src,const Condition cond)2038 void Assembler::vmov(const Register dst1,
2039 const Register dst2,
2040 const DwVfpRegister src,
2041 const Condition cond) {
2042 // <Rt,Rt2> = Dm.
2043 // Instruction details available in ARM DDI 0406A, A8-646.
2044 // cond(31-28) | 1100(27-24)| 010(23-21) | op=1(20) | Rt2(19-16) |
2045 // Rt(15-12) | 1011(11-8) | 00(7-6) | M(5) | 1(4) | Vm
2046 ASSERT(CpuFeatures::IsEnabled(VFP3));
2047 ASSERT(!dst1.is(pc) && !dst2.is(pc));
2048 emit(cond | 0xC*B24 | B22 | B20 | dst2.code()*B16 |
2049 dst1.code()*B12 | 0xB*B8 | B4 | src.code());
2050 }
2051
2052
vmov(const SwVfpRegister dst,const Register src,const Condition cond)2053 void Assembler::vmov(const SwVfpRegister dst,
2054 const Register src,
2055 const Condition cond) {
2056 // Sn = Rt.
2057 // Instruction details available in ARM DDI 0406A, A8-642.
2058 // cond(31-28) | 1110(27-24)| 000(23-21) | op=0(20) | Vn(19-16) |
2059 // Rt(15-12) | 1010(11-8) | N(7)=0 | 00(6-5) | 1(4) | 0000(3-0)
2060 ASSERT(CpuFeatures::IsEnabled(VFP3));
2061 ASSERT(!src.is(pc));
2062 int sn, n;
2063 dst.split_code(&sn, &n);
2064 emit(cond | 0xE*B24 | sn*B16 | src.code()*B12 | 0xA*B8 | n*B7 | B4);
2065 }
2066
2067
vmov(const Register dst,const SwVfpRegister src,const Condition cond)2068 void Assembler::vmov(const Register dst,
2069 const SwVfpRegister src,
2070 const Condition cond) {
2071 // Rt = Sn.
2072 // Instruction details available in ARM DDI 0406A, A8-642.
2073 // cond(31-28) | 1110(27-24)| 000(23-21) | op=1(20) | Vn(19-16) |
2074 // Rt(15-12) | 1010(11-8) | N(7)=0 | 00(6-5) | 1(4) | 0000(3-0)
2075 ASSERT(CpuFeatures::IsEnabled(VFP3));
2076 ASSERT(!dst.is(pc));
2077 int sn, n;
2078 src.split_code(&sn, &n);
2079 emit(cond | 0xE*B24 | B20 | sn*B16 | dst.code()*B12 | 0xA*B8 | n*B7 | B4);
2080 }
2081
2082
2083 // Type of data to read from or write to VFP register.
2084 // Used as specifier in generic vcvt instruction.
2085 enum VFPType { S32, U32, F32, F64 };
2086
2087
IsSignedVFPType(VFPType type)2088 static bool IsSignedVFPType(VFPType type) {
2089 switch (type) {
2090 case S32:
2091 return true;
2092 case U32:
2093 return false;
2094 default:
2095 UNREACHABLE();
2096 return false;
2097 }
2098 }
2099
2100
IsIntegerVFPType(VFPType type)2101 static bool IsIntegerVFPType(VFPType type) {
2102 switch (type) {
2103 case S32:
2104 case U32:
2105 return true;
2106 case F32:
2107 case F64:
2108 return false;
2109 default:
2110 UNREACHABLE();
2111 return false;
2112 }
2113 }
2114
2115
IsDoubleVFPType(VFPType type)2116 static bool IsDoubleVFPType(VFPType type) {
2117 switch (type) {
2118 case F32:
2119 return false;
2120 case F64:
2121 return true;
2122 default:
2123 UNREACHABLE();
2124 return false;
2125 }
2126 }
2127
2128
2129 // Split five bit reg_code based on size of reg_type.
2130 // 32-bit register codes are Vm:M
2131 // 64-bit register codes are M:Vm
2132 // where Vm is four bits, and M is a single bit.
SplitRegCode(VFPType reg_type,int reg_code,int * vm,int * m)2133 static void SplitRegCode(VFPType reg_type,
2134 int reg_code,
2135 int* vm,
2136 int* m) {
2137 ASSERT((reg_code >= 0) && (reg_code <= 31));
2138 if (IsIntegerVFPType(reg_type) || !IsDoubleVFPType(reg_type)) {
2139 // 32 bit type.
2140 *m = reg_code & 0x1;
2141 *vm = reg_code >> 1;
2142 } else {
2143 // 64 bit type.
2144 *m = (reg_code & 0x10) >> 4;
2145 *vm = reg_code & 0x0F;
2146 }
2147 }
2148
2149
2150 // Encode vcvt.src_type.dst_type instruction.
EncodeVCVT(const VFPType dst_type,const int dst_code,const VFPType src_type,const int src_code,VFPConversionMode mode,const Condition cond)2151 static Instr EncodeVCVT(const VFPType dst_type,
2152 const int dst_code,
2153 const VFPType src_type,
2154 const int src_code,
2155 VFPConversionMode mode,
2156 const Condition cond) {
2157 ASSERT(src_type != dst_type);
2158 int D, Vd, M, Vm;
2159 SplitRegCode(src_type, src_code, &Vm, &M);
2160 SplitRegCode(dst_type, dst_code, &Vd, &D);
2161
2162 if (IsIntegerVFPType(dst_type) || IsIntegerVFPType(src_type)) {
2163 // Conversion between IEEE floating point and 32-bit integer.
2164 // Instruction details available in ARM DDI 0406B, A8.6.295.
2165 // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 1(19) | opc2(18-16) |
2166 // Vd(15-12) | 101(11-9) | sz(8) | op(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
2167 ASSERT(!IsIntegerVFPType(dst_type) || !IsIntegerVFPType(src_type));
2168
2169 int sz, opc2, op;
2170
2171 if (IsIntegerVFPType(dst_type)) {
2172 opc2 = IsSignedVFPType(dst_type) ? 0x5 : 0x4;
2173 sz = IsDoubleVFPType(src_type) ? 0x1 : 0x0;
2174 op = mode;
2175 } else {
2176 ASSERT(IsIntegerVFPType(src_type));
2177 opc2 = 0x0;
2178 sz = IsDoubleVFPType(dst_type) ? 0x1 : 0x0;
2179 op = IsSignedVFPType(src_type) ? 0x1 : 0x0;
2180 }
2181
2182 return (cond | 0xE*B24 | B23 | D*B22 | 0x3*B20 | B19 | opc2*B16 |
2183 Vd*B12 | 0x5*B9 | sz*B8 | op*B7 | B6 | M*B5 | Vm);
2184 } else {
2185 // Conversion between IEEE double and single precision.
2186 // Instruction details available in ARM DDI 0406B, A8.6.298.
2187 // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 0111(19-16) |
2188 // Vd(15-12) | 101(11-9) | sz(8) | 1(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
2189 int sz = IsDoubleVFPType(src_type) ? 0x1 : 0x0;
2190 return (cond | 0xE*B24 | B23 | D*B22 | 0x3*B20 | 0x7*B16 |
2191 Vd*B12 | 0x5*B9 | sz*B8 | B7 | B6 | M*B5 | Vm);
2192 }
2193 }
2194
2195
vcvt_f64_s32(const DwVfpRegister dst,const SwVfpRegister src,VFPConversionMode mode,const Condition cond)2196 void Assembler::vcvt_f64_s32(const DwVfpRegister dst,
2197 const SwVfpRegister src,
2198 VFPConversionMode mode,
2199 const Condition cond) {
2200 ASSERT(CpuFeatures::IsEnabled(VFP3));
2201 emit(EncodeVCVT(F64, dst.code(), S32, src.code(), mode, cond));
2202 }
2203
2204
vcvt_f32_s32(const SwVfpRegister dst,const SwVfpRegister src,VFPConversionMode mode,const Condition cond)2205 void Assembler::vcvt_f32_s32(const SwVfpRegister dst,
2206 const SwVfpRegister src,
2207 VFPConversionMode mode,
2208 const Condition cond) {
2209 ASSERT(CpuFeatures::IsEnabled(VFP3));
2210 emit(EncodeVCVT(F32, dst.code(), S32, src.code(), mode, cond));
2211 }
2212
2213
vcvt_f64_u32(const DwVfpRegister dst,const SwVfpRegister src,VFPConversionMode mode,const Condition cond)2214 void Assembler::vcvt_f64_u32(const DwVfpRegister dst,
2215 const SwVfpRegister src,
2216 VFPConversionMode mode,
2217 const Condition cond) {
2218 ASSERT(CpuFeatures::IsEnabled(VFP3));
2219 emit(EncodeVCVT(F64, dst.code(), U32, src.code(), mode, cond));
2220 }
2221
2222
vcvt_s32_f64(const SwVfpRegister dst,const DwVfpRegister src,VFPConversionMode mode,const Condition cond)2223 void Assembler::vcvt_s32_f64(const SwVfpRegister dst,
2224 const DwVfpRegister src,
2225 VFPConversionMode mode,
2226 const Condition cond) {
2227 ASSERT(CpuFeatures::IsEnabled(VFP3));
2228 emit(EncodeVCVT(S32, dst.code(), F64, src.code(), mode, cond));
2229 }
2230
2231
vcvt_u32_f64(const SwVfpRegister dst,const DwVfpRegister src,VFPConversionMode mode,const Condition cond)2232 void Assembler::vcvt_u32_f64(const SwVfpRegister dst,
2233 const DwVfpRegister src,
2234 VFPConversionMode mode,
2235 const Condition cond) {
2236 ASSERT(CpuFeatures::IsEnabled(VFP3));
2237 emit(EncodeVCVT(U32, dst.code(), F64, src.code(), mode, cond));
2238 }
2239
2240
vcvt_f64_f32(const DwVfpRegister dst,const SwVfpRegister src,VFPConversionMode mode,const Condition cond)2241 void Assembler::vcvt_f64_f32(const DwVfpRegister dst,
2242 const SwVfpRegister src,
2243 VFPConversionMode mode,
2244 const Condition cond) {
2245 ASSERT(CpuFeatures::IsEnabled(VFP3));
2246 emit(EncodeVCVT(F64, dst.code(), F32, src.code(), mode, cond));
2247 }
2248
2249
vcvt_f32_f64(const SwVfpRegister dst,const DwVfpRegister src,VFPConversionMode mode,const Condition cond)2250 void Assembler::vcvt_f32_f64(const SwVfpRegister dst,
2251 const DwVfpRegister src,
2252 VFPConversionMode mode,
2253 const Condition cond) {
2254 ASSERT(CpuFeatures::IsEnabled(VFP3));
2255 emit(EncodeVCVT(F32, dst.code(), F64, src.code(), mode, cond));
2256 }
2257
2258
vneg(const DwVfpRegister dst,const DwVfpRegister src,const Condition cond)2259 void Assembler::vneg(const DwVfpRegister dst,
2260 const DwVfpRegister src,
2261 const Condition cond) {
2262 emit(cond | 0xE*B24 | 0xB*B20 | B16 | dst.code()*B12 |
2263 0x5*B9 | B8 | B6 | src.code());
2264 }
2265
2266
vabs(const DwVfpRegister dst,const DwVfpRegister src,const Condition cond)2267 void Assembler::vabs(const DwVfpRegister dst,
2268 const DwVfpRegister src,
2269 const Condition cond) {
2270 emit(cond | 0xE*B24 | 0xB*B20 | dst.code()*B12 |
2271 0x5*B9 | B8 | 0x3*B6 | src.code());
2272 }
2273
2274
vadd(const DwVfpRegister dst,const DwVfpRegister src1,const DwVfpRegister src2,const Condition cond)2275 void Assembler::vadd(const DwVfpRegister dst,
2276 const DwVfpRegister src1,
2277 const DwVfpRegister src2,
2278 const Condition cond) {
2279 // Dd = vadd(Dn, Dm) double precision floating point addition.
2280 // Dd = D:Vd; Dm=M:Vm; Dn=N:Vm.
2281 // Instruction details available in ARM DDI 0406A, A8-536.
2282 // cond(31-28) | 11100(27-23)| D=?(22) | 11(21-20) | Vn(19-16) |
2283 // Vd(15-12) | 101(11-9) | sz(8)=1 | N(7)=0 | 0(6) | M=?(5) | 0(4) | Vm(3-0)
2284 ASSERT(CpuFeatures::IsEnabled(VFP3));
2285 emit(cond | 0xE*B24 | 0x3*B20 | src1.code()*B16 |
2286 dst.code()*B12 | 0x5*B9 | B8 | src2.code());
2287 }
2288
2289
vsub(const DwVfpRegister dst,const DwVfpRegister src1,const DwVfpRegister src2,const Condition cond)2290 void Assembler::vsub(const DwVfpRegister dst,
2291 const DwVfpRegister src1,
2292 const DwVfpRegister src2,
2293 const Condition cond) {
2294 // Dd = vsub(Dn, Dm) double precision floating point subtraction.
2295 // Dd = D:Vd; Dm=M:Vm; Dn=N:Vm.
2296 // Instruction details available in ARM DDI 0406A, A8-784.
2297 // cond(31-28) | 11100(27-23)| D=?(22) | 11(21-20) | Vn(19-16) |
2298 // Vd(15-12) | 101(11-9) | sz(8)=1 | N(7)=0 | 1(6) | M=?(5) | 0(4) | Vm(3-0)
2299 ASSERT(CpuFeatures::IsEnabled(VFP3));
2300 emit(cond | 0xE*B24 | 0x3*B20 | src1.code()*B16 |
2301 dst.code()*B12 | 0x5*B9 | B8 | B6 | src2.code());
2302 }
2303
2304
vmul(const DwVfpRegister dst,const DwVfpRegister src1,const DwVfpRegister src2,const Condition cond)2305 void Assembler::vmul(const DwVfpRegister dst,
2306 const DwVfpRegister src1,
2307 const DwVfpRegister src2,
2308 const Condition cond) {
2309 // Dd = vmul(Dn, Dm) double precision floating point multiplication.
2310 // Dd = D:Vd; Dm=M:Vm; Dn=N:Vm.
2311 // Instruction details available in ARM DDI 0406A, A8-784.
2312 // cond(31-28) | 11100(27-23)| D=?(22) | 10(21-20) | Vn(19-16) |
2313 // Vd(15-12) | 101(11-9) | sz(8)=1 | N(7)=0 | 0(6) | M=?(5) | 0(4) | Vm(3-0)
2314 ASSERT(CpuFeatures::IsEnabled(VFP3));
2315 emit(cond | 0xE*B24 | 0x2*B20 | src1.code()*B16 |
2316 dst.code()*B12 | 0x5*B9 | B8 | src2.code());
2317 }
2318
2319
vdiv(const DwVfpRegister dst,const DwVfpRegister src1,const DwVfpRegister src2,const Condition cond)2320 void Assembler::vdiv(const DwVfpRegister dst,
2321 const DwVfpRegister src1,
2322 const DwVfpRegister src2,
2323 const Condition cond) {
2324 // Dd = vdiv(Dn, Dm) double precision floating point division.
2325 // Dd = D:Vd; Dm=M:Vm; Dn=N:Vm.
2326 // Instruction details available in ARM DDI 0406A, A8-584.
2327 // cond(31-28) | 11101(27-23)| D=?(22) | 00(21-20) | Vn(19-16) |
2328 // Vd(15-12) | 101(11-9) | sz(8)=1 | N(7)=? | 0(6) | M=?(5) | 0(4) | Vm(3-0)
2329 ASSERT(CpuFeatures::IsEnabled(VFP3));
2330 emit(cond | 0xE*B24 | B23 | src1.code()*B16 |
2331 dst.code()*B12 | 0x5*B9 | B8 | src2.code());
2332 }
2333
2334
vcmp(const DwVfpRegister src1,const DwVfpRegister src2,const Condition cond)2335 void Assembler::vcmp(const DwVfpRegister src1,
2336 const DwVfpRegister src2,
2337 const Condition cond) {
2338 // vcmp(Dd, Dm) double precision floating point comparison.
2339 // Instruction details available in ARM DDI 0406A, A8-570.
2340 // cond(31-28) | 11101 (27-23)| D=?(22) | 11 (21-20) | 0100 (19-16) |
2341 // Vd(15-12) | 101(11-9) | sz(8)=1 | E(7)=0 | 1(6) | M(5)=? | 0(4) | Vm(3-0)
2342 ASSERT(CpuFeatures::IsEnabled(VFP3));
2343 emit(cond | 0xE*B24 |B23 | 0x3*B20 | B18 |
2344 src1.code()*B12 | 0x5*B9 | B8 | B6 | src2.code());
2345 }
2346
2347
vcmp(const DwVfpRegister src1,const double src2,const Condition cond)2348 void Assembler::vcmp(const DwVfpRegister src1,
2349 const double src2,
2350 const Condition cond) {
2351 // vcmp(Dd, Dm) double precision floating point comparison.
2352 // Instruction details available in ARM DDI 0406A, A8-570.
2353 // cond(31-28) | 11101 (27-23)| D=?(22) | 11 (21-20) | 0101 (19-16) |
2354 // Vd(15-12) | 101(11-9) | sz(8)=1 | E(7)=0 | 1(6) | M(5)=? | 0(4) | 0000(3-0)
2355 ASSERT(CpuFeatures::IsEnabled(VFP3));
2356 ASSERT(src2 == 0.0);
2357 emit(cond | 0xE*B24 |B23 | 0x3*B20 | B18 | B16 |
2358 src1.code()*B12 | 0x5*B9 | B8 | B6);
2359 }
2360
2361
vmsr(Register dst,Condition cond)2362 void Assembler::vmsr(Register dst, Condition cond) {
2363 // Instruction details available in ARM DDI 0406A, A8-652.
2364 // cond(31-28) | 1110 (27-24) | 1110(23-20)| 0001 (19-16) |
2365 // Rt(15-12) | 1010 (11-8) | 0(7) | 00 (6-5) | 1(4) | 0000(3-0)
2366 ASSERT(CpuFeatures::IsEnabled(VFP3));
2367 emit(cond | 0xE*B24 | 0xE*B20 | B16 |
2368 dst.code()*B12 | 0xA*B8 | B4);
2369 }
2370
2371
vmrs(Register dst,Condition cond)2372 void Assembler::vmrs(Register dst, Condition cond) {
2373 // Instruction details available in ARM DDI 0406A, A8-652.
2374 // cond(31-28) | 1110 (27-24) | 1111(23-20)| 0001 (19-16) |
2375 // Rt(15-12) | 1010 (11-8) | 0(7) | 00 (6-5) | 1(4) | 0000(3-0)
2376 ASSERT(CpuFeatures::IsEnabled(VFP3));
2377 emit(cond | 0xE*B24 | 0xF*B20 | B16 |
2378 dst.code()*B12 | 0xA*B8 | B4);
2379 }
2380
2381
vsqrt(const DwVfpRegister dst,const DwVfpRegister src,const Condition cond)2382 void Assembler::vsqrt(const DwVfpRegister dst,
2383 const DwVfpRegister src,
2384 const Condition cond) {
2385 // cond(31-28) | 11101 (27-23)| D=?(22) | 11 (21-20) | 0001 (19-16) |
2386 // Vd(15-12) | 101(11-9) | sz(8)=1 | 11 (7-6) | M(5)=? | 0(4) | Vm(3-0)
2387 ASSERT(CpuFeatures::IsEnabled(VFP3));
2388 emit(cond | 0xE*B24 | B23 | 0x3*B20 | B16 |
2389 dst.code()*B12 | 0x5*B9 | B8 | 3*B6 | src.code());
2390 }
2391
2392
2393 // Pseudo instructions.
nop(int type)2394 void Assembler::nop(int type) {
2395 // This is mov rx, rx.
2396 ASSERT(0 <= type && type <= 14); // mov pc, pc is not a nop.
2397 emit(al | 13*B21 | type*B12 | type);
2398 }
2399
2400
IsNop(Instr instr,int type)2401 bool Assembler::IsNop(Instr instr, int type) {
2402 // Check for mov rx, rx where x = type.
2403 ASSERT(0 <= type && type <= 14); // mov pc, pc is not a nop.
2404 return instr == (al | 13*B21 | type*B12 | type);
2405 }
2406
2407
ImmediateFitsAddrMode1Instruction(int32_t imm32)2408 bool Assembler::ImmediateFitsAddrMode1Instruction(int32_t imm32) {
2409 uint32_t dummy1;
2410 uint32_t dummy2;
2411 return fits_shifter(imm32, &dummy1, &dummy2, NULL);
2412 }
2413
2414
2415 // Debugging.
RecordJSReturn()2416 void Assembler::RecordJSReturn() {
2417 positions_recorder()->WriteRecordedPositions();
2418 CheckBuffer();
2419 RecordRelocInfo(RelocInfo::JS_RETURN);
2420 }
2421
2422
RecordDebugBreakSlot()2423 void Assembler::RecordDebugBreakSlot() {
2424 positions_recorder()->WriteRecordedPositions();
2425 CheckBuffer();
2426 RecordRelocInfo(RelocInfo::DEBUG_BREAK_SLOT);
2427 }
2428
2429
RecordComment(const char * msg)2430 void Assembler::RecordComment(const char* msg) {
2431 if (FLAG_code_comments) {
2432 CheckBuffer();
2433 RecordRelocInfo(RelocInfo::COMMENT, reinterpret_cast<intptr_t>(msg));
2434 }
2435 }
2436
2437
GrowBuffer()2438 void Assembler::GrowBuffer() {
2439 if (!own_buffer_) FATAL("external code buffer is too small");
2440
2441 // Compute new buffer size.
2442 CodeDesc desc; // the new buffer
2443 if (buffer_size_ < 4*KB) {
2444 desc.buffer_size = 4*KB;
2445 } else if (buffer_size_ < 1*MB) {
2446 desc.buffer_size = 2*buffer_size_;
2447 } else {
2448 desc.buffer_size = buffer_size_ + 1*MB;
2449 }
2450 CHECK_GT(desc.buffer_size, 0); // no overflow
2451
2452 // Set up new buffer.
2453 desc.buffer = NewArray<byte>(desc.buffer_size);
2454
2455 desc.instr_size = pc_offset();
2456 desc.reloc_size = (buffer_ + buffer_size_) - reloc_info_writer.pos();
2457
2458 // Copy the data.
2459 int pc_delta = desc.buffer - buffer_;
2460 int rc_delta = (desc.buffer + desc.buffer_size) - (buffer_ + buffer_size_);
2461 memmove(desc.buffer, buffer_, desc.instr_size);
2462 memmove(reloc_info_writer.pos() + rc_delta,
2463 reloc_info_writer.pos(), desc.reloc_size);
2464
2465 // Switch buffers.
2466 DeleteArray(buffer_);
2467 buffer_ = desc.buffer;
2468 buffer_size_ = desc.buffer_size;
2469 pc_ += pc_delta;
2470 reloc_info_writer.Reposition(reloc_info_writer.pos() + rc_delta,
2471 reloc_info_writer.last_pc() + pc_delta);
2472
2473 // None of our relocation types are pc relative pointing outside the code
2474 // buffer nor pc absolute pointing inside the code buffer, so there is no need
2475 // to relocate any emitted relocation entries.
2476
2477 // Relocate pending relocation entries.
2478 for (int i = 0; i < num_pending_reloc_info_; i++) {
2479 RelocInfo& rinfo = pending_reloc_info_[i];
2480 ASSERT(rinfo.rmode() != RelocInfo::COMMENT &&
2481 rinfo.rmode() != RelocInfo::POSITION);
2482 if (rinfo.rmode() != RelocInfo::JS_RETURN) {
2483 rinfo.set_pc(rinfo.pc() + pc_delta);
2484 }
2485 }
2486 }
2487
2488
db(uint8_t data)2489 void Assembler::db(uint8_t data) {
2490 // No relocation info should be pending while using db. db is used
2491 // to write pure data with no pointers and the constant pool should
2492 // be emitted before using db.
2493 ASSERT(num_pending_reloc_info_ == 0);
2494 CheckBuffer();
2495 *reinterpret_cast<uint8_t*>(pc_) = data;
2496 pc_ += sizeof(uint8_t);
2497 }
2498
2499
dd(uint32_t data)2500 void Assembler::dd(uint32_t data) {
2501 // No relocation info should be pending while using dd. dd is used
2502 // to write pure data with no pointers and the constant pool should
2503 // be emitted before using dd.
2504 ASSERT(num_pending_reloc_info_ == 0);
2505 CheckBuffer();
2506 *reinterpret_cast<uint32_t*>(pc_) = data;
2507 pc_ += sizeof(uint32_t);
2508 }
2509
2510
RecordRelocInfo(RelocInfo::Mode rmode,intptr_t data)2511 void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) {
2512 // We do not try to reuse pool constants.
2513 RelocInfo rinfo(pc_, rmode, data, NULL);
2514 if (rmode >= RelocInfo::JS_RETURN && rmode <= RelocInfo::DEBUG_BREAK_SLOT) {
2515 // Adjust code for new modes.
2516 ASSERT(RelocInfo::IsDebugBreakSlot(rmode)
2517 || RelocInfo::IsJSReturn(rmode)
2518 || RelocInfo::IsComment(rmode)
2519 || RelocInfo::IsPosition(rmode));
2520 // These modes do not need an entry in the constant pool.
2521 } else {
2522 ASSERT(num_pending_reloc_info_ < kMaxNumPendingRelocInfo);
2523 if (num_pending_reloc_info_ == 0) {
2524 first_const_pool_use_ = pc_offset();
2525 }
2526 pending_reloc_info_[num_pending_reloc_info_++] = rinfo;
2527 // Make sure the constant pool is not emitted in place of the next
2528 // instruction for which we just recorded relocation info.
2529 BlockConstPoolFor(1);
2530 }
2531 if (rinfo.rmode() != RelocInfo::NONE) {
2532 // Don't record external references unless the heap will be serialized.
2533 if (rmode == RelocInfo::EXTERNAL_REFERENCE) {
2534 #ifdef DEBUG
2535 if (!Serializer::enabled()) {
2536 Serializer::TooLateToEnableNow();
2537 }
2538 #endif
2539 if (!Serializer::enabled() && !emit_debug_code()) {
2540 return;
2541 }
2542 }
2543 ASSERT(buffer_space() >= kMaxRelocSize); // too late to grow buffer here
2544 if (rmode == RelocInfo::CODE_TARGET_WITH_ID) {
2545 RelocInfo reloc_info_with_ast_id(pc_, rmode, RecordedAstId(), NULL);
2546 ClearRecordedAstId();
2547 reloc_info_writer.Write(&reloc_info_with_ast_id);
2548 } else {
2549 reloc_info_writer.Write(&rinfo);
2550 }
2551 }
2552 }
2553
2554
BlockConstPoolFor(int instructions)2555 void Assembler::BlockConstPoolFor(int instructions) {
2556 int pc_limit = pc_offset() + instructions * kInstrSize;
2557 if (no_const_pool_before_ < pc_limit) {
2558 // If there are some pending entries, the constant pool cannot be blocked
2559 // further than first_const_pool_use_ + kMaxDistToPool
2560 ASSERT((num_pending_reloc_info_ == 0) ||
2561 (pc_limit < (first_const_pool_use_ + kMaxDistToPool)));
2562 no_const_pool_before_ = pc_limit;
2563 }
2564
2565 if (next_buffer_check_ < no_const_pool_before_) {
2566 next_buffer_check_ = no_const_pool_before_;
2567 }
2568 }
2569
2570
CheckConstPool(bool force_emit,bool require_jump)2571 void Assembler::CheckConstPool(bool force_emit, bool require_jump) {
2572 // Some short sequence of instruction mustn't be broken up by constant pool
2573 // emission, such sequences are protected by calls to BlockConstPoolFor and
2574 // BlockConstPoolScope.
2575 if (is_const_pool_blocked()) {
2576 // Something is wrong if emission is forced and blocked at the same time.
2577 ASSERT(!force_emit);
2578 return;
2579 }
2580
2581 // There is nothing to do if there are no pending constant pool entries.
2582 if (num_pending_reloc_info_ == 0) {
2583 // Calculate the offset of the next check.
2584 next_buffer_check_ = pc_offset() + kCheckPoolInterval;
2585 return;
2586 }
2587
2588 // We emit a constant pool when:
2589 // * requested to do so by parameter force_emit (e.g. after each function).
2590 // * the distance to the first instruction accessing the constant pool is
2591 // kAvgDistToPool or more.
2592 // * no jump is required and the distance to the first instruction accessing
2593 // the constant pool is at least kMaxDistToPool / 2.
2594 ASSERT(first_const_pool_use_ >= 0);
2595 int dist = pc_offset() - first_const_pool_use_;
2596 if (!force_emit && dist < kAvgDistToPool &&
2597 (require_jump || (dist < (kMaxDistToPool / 2)))) {
2598 return;
2599 }
2600
2601 // Check that the code buffer is large enough before emitting the constant
2602 // pool (include the jump over the pool and the constant pool marker and
2603 // the gap to the relocation information).
2604 int jump_instr = require_jump ? kInstrSize : 0;
2605 int needed_space = jump_instr + kInstrSize +
2606 num_pending_reloc_info_ * kInstrSize + kGap;
2607 while (buffer_space() <= needed_space) GrowBuffer();
2608
2609 {
2610 // Block recursive calls to CheckConstPool.
2611 BlockConstPoolScope block_const_pool(this);
2612
2613 // Emit jump over constant pool if necessary.
2614 Label after_pool;
2615 if (require_jump) {
2616 b(&after_pool);
2617 }
2618
2619 RecordComment("[ Constant Pool");
2620
2621 // Put down constant pool marker "Undefined instruction" as specified by
2622 // A5.6 (ARMv7) Instruction set encoding.
2623 emit(kConstantPoolMarker | num_pending_reloc_info_);
2624
2625 // Emit constant pool entries.
2626 for (int i = 0; i < num_pending_reloc_info_; i++) {
2627 RelocInfo& rinfo = pending_reloc_info_[i];
2628 ASSERT(rinfo.rmode() != RelocInfo::COMMENT &&
2629 rinfo.rmode() != RelocInfo::POSITION &&
2630 rinfo.rmode() != RelocInfo::STATEMENT_POSITION);
2631
2632 Instr instr = instr_at(rinfo.pc());
2633 // Instruction to patch must be 'ldr rd, [pc, #offset]' with offset == 0.
2634 ASSERT(IsLdrPcImmediateOffset(instr) &&
2635 GetLdrRegisterImmediateOffset(instr) == 0);
2636
2637 int delta = pc_ - rinfo.pc() - kPcLoadDelta;
2638 // 0 is the smallest delta:
2639 // ldr rd, [pc, #0]
2640 // constant pool marker
2641 // data
2642 ASSERT(is_uint12(delta));
2643
2644 instr_at_put(rinfo.pc(), SetLdrRegisterImmediateOffset(instr, delta));
2645 emit(rinfo.data());
2646 }
2647
2648 num_pending_reloc_info_ = 0;
2649 first_const_pool_use_ = -1;
2650
2651 RecordComment("]");
2652
2653 if (after_pool.is_linked()) {
2654 bind(&after_pool);
2655 }
2656 }
2657
2658 // Since a constant pool was just emitted, move the check offset forward by
2659 // the standard interval.
2660 next_buffer_check_ = pc_offset() + kCheckPoolInterval;
2661 }
2662
2663
2664 } } // namespace v8::internal
2665
2666 #endif // V8_TARGET_ARCH_ARM
2667