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 2012 the V8 project authors. All rights reserved.
36
37 #include "src/arm/assembler-arm.h"
38
39 #if V8_TARGET_ARCH_ARM
40
41 #include "src/arm/assembler-arm-inl.h"
42 #include "src/assembler-inl.h"
43 #include "src/base/bits.h"
44 #include "src/base/cpu.h"
45 #include "src/code-stubs.h"
46 #include "src/deoptimizer.h"
47 #include "src/macro-assembler.h"
48 #include "src/objects-inl.h"
49
50 namespace v8 {
51 namespace internal {
52
53 static const unsigned kArmv6 = 0u;
54 static const unsigned kArmv7 = kArmv6 | (1u << ARMv7);
55 static const unsigned kArmv7WithSudiv = kArmv7 | (1u << ARMv7_SUDIV);
56 static const unsigned kArmv8 = kArmv7WithSudiv | (1u << ARMv8);
57
CpuFeaturesFromCommandLine()58 static unsigned CpuFeaturesFromCommandLine() {
59 unsigned result;
60 if (strcmp(FLAG_arm_arch, "armv8") == 0) {
61 result = kArmv8;
62 } else if (strcmp(FLAG_arm_arch, "armv7+sudiv") == 0) {
63 result = kArmv7WithSudiv;
64 } else if (strcmp(FLAG_arm_arch, "armv7") == 0) {
65 result = kArmv7;
66 } else if (strcmp(FLAG_arm_arch, "armv6") == 0) {
67 result = kArmv6;
68 } else {
69 fprintf(stderr, "Error: unrecognised value for --arm-arch ('%s').\n",
70 FLAG_arm_arch);
71 fprintf(stderr,
72 "Supported values are: armv8\n"
73 " armv7+sudiv\n"
74 " armv7\n"
75 " armv6\n");
76 FATAL("arm-arch");
77 }
78
79 // If any of the old (deprecated) flags are specified, print a warning, but
80 // otherwise try to respect them for now.
81 // TODO(jbramley): When all the old bots have been updated, remove this.
82 if (FLAG_enable_armv7.has_value || FLAG_enable_vfp3.has_value ||
83 FLAG_enable_32dregs.has_value || FLAG_enable_neon.has_value ||
84 FLAG_enable_sudiv.has_value || FLAG_enable_armv8.has_value) {
85 // As an approximation of the old behaviour, set the default values from the
86 // arm_arch setting, then apply the flags over the top.
87 bool enable_armv7 = (result & (1u << ARMv7)) != 0;
88 bool enable_vfp3 = (result & (1u << ARMv7)) != 0;
89 bool enable_32dregs = (result & (1u << ARMv7)) != 0;
90 bool enable_neon = (result & (1u << ARMv7)) != 0;
91 bool enable_sudiv = (result & (1u << ARMv7_SUDIV)) != 0;
92 bool enable_armv8 = (result & (1u << ARMv8)) != 0;
93 if (FLAG_enable_armv7.has_value) {
94 fprintf(stderr,
95 "Warning: --enable_armv7 is deprecated. "
96 "Use --arm_arch instead.\n");
97 enable_armv7 = FLAG_enable_armv7.value;
98 }
99 if (FLAG_enable_vfp3.has_value) {
100 fprintf(stderr,
101 "Warning: --enable_vfp3 is deprecated. "
102 "Use --arm_arch instead.\n");
103 enable_vfp3 = FLAG_enable_vfp3.value;
104 }
105 if (FLAG_enable_32dregs.has_value) {
106 fprintf(stderr,
107 "Warning: --enable_32dregs is deprecated. "
108 "Use --arm_arch instead.\n");
109 enable_32dregs = FLAG_enable_32dregs.value;
110 }
111 if (FLAG_enable_neon.has_value) {
112 fprintf(stderr,
113 "Warning: --enable_neon is deprecated. "
114 "Use --arm_arch instead.\n");
115 enable_neon = FLAG_enable_neon.value;
116 }
117 if (FLAG_enable_sudiv.has_value) {
118 fprintf(stderr,
119 "Warning: --enable_sudiv is deprecated. "
120 "Use --arm_arch instead.\n");
121 enable_sudiv = FLAG_enable_sudiv.value;
122 }
123 if (FLAG_enable_armv8.has_value) {
124 fprintf(stderr,
125 "Warning: --enable_armv8 is deprecated. "
126 "Use --arm_arch instead.\n");
127 enable_armv8 = FLAG_enable_armv8.value;
128 }
129 // Emulate the old implications.
130 if (enable_armv8) {
131 enable_vfp3 = true;
132 enable_neon = true;
133 enable_32dregs = true;
134 enable_sudiv = true;
135 }
136 // Select the best available configuration.
137 if (enable_armv7 && enable_vfp3 && enable_32dregs && enable_neon) {
138 if (enable_sudiv) {
139 if (enable_armv8) {
140 result = kArmv8;
141 } else {
142 result = kArmv7WithSudiv;
143 }
144 } else {
145 result = kArmv7;
146 }
147 } else {
148 result = kArmv6;
149 }
150 }
151 return result;
152 }
153
154 // Get the CPU features enabled by the build.
155 // For cross compilation the preprocessor symbols such as
156 // CAN_USE_ARMV7_INSTRUCTIONS and CAN_USE_VFP3_INSTRUCTIONS can be used to
157 // enable ARMv7 and VFPv3 instructions when building the snapshot. However,
158 // these flags should be consistent with a supported ARM configuration:
159 // "armv6": ARMv6 + VFPv2
160 // "armv7": ARMv7 + VFPv3-D32 + NEON
161 // "armv7+sudiv": ARMv7 + VFPv4-D32 + NEON + SUDIV
162 // "armv8": ARMv8 (+ all of the above)
CpuFeaturesFromCompiler()163 static constexpr unsigned CpuFeaturesFromCompiler() {
164 // TODO(jbramley): Once the build flags are simplified, these tests should
165 // also be simplified.
166
167 // Check *architectural* implications.
168 #if defined(CAN_USE_ARMV8_INSTRUCTIONS) && !defined(CAN_USE_ARMV7_INSTRUCTIONS)
169 #error "CAN_USE_ARMV8_INSTRUCTIONS should imply CAN_USE_ARMV7_INSTRUCTIONS"
170 #endif
171 #if defined(CAN_USE_ARMV8_INSTRUCTIONS) && !defined(CAN_USE_SUDIV)
172 #error "CAN_USE_ARMV8_INSTRUCTIONS should imply CAN_USE_SUDIV"
173 #endif
174 #if defined(CAN_USE_ARMV7_INSTRUCTIONS) != defined(CAN_USE_VFP3_INSTRUCTIONS)
175 // V8 requires VFP, and all ARMv7 devices with VFP have VFPv3. Similarly,
176 // VFPv3 isn't available before ARMv7.
177 #error "CAN_USE_ARMV7_INSTRUCTIONS should match CAN_USE_VFP3_INSTRUCTIONS"
178 #endif
179 #if defined(CAN_USE_NEON) && !defined(CAN_USE_ARMV7_INSTRUCTIONS)
180 #error "CAN_USE_NEON should imply CAN_USE_ARMV7_INSTRUCTIONS"
181 #endif
182
183 // Find compiler-implied features.
184 #if defined(CAN_USE_ARMV8_INSTRUCTIONS) && \
185 defined(CAN_USE_ARMV7_INSTRUCTIONS) && defined(CAN_USE_SUDIV) && \
186 defined(CAN_USE_NEON) && defined(CAN_USE_VFP3_INSTRUCTIONS)
187 return kArmv8;
188 #elif defined(CAN_USE_ARMV7_INSTRUCTIONS) && defined(CAN_USE_SUDIV) && \
189 defined(CAN_USE_NEON) && defined(CAN_USE_VFP3_INSTRUCTIONS)
190 return kArmv7WithSudiv;
191 #elif defined(CAN_USE_ARMV7_INSTRUCTIONS) && defined(CAN_USE_NEON) && \
192 defined(CAN_USE_VFP3_INSTRUCTIONS)
193 return kArmv7;
194 #else
195 return kArmv6;
196 #endif
197 }
198
199
ProbeImpl(bool cross_compile)200 void CpuFeatures::ProbeImpl(bool cross_compile) {
201 dcache_line_size_ = 64;
202
203 unsigned command_line = CpuFeaturesFromCommandLine();
204 // Only use statically determined features for cross compile (snapshot).
205 if (cross_compile) {
206 supported_ |= command_line & CpuFeaturesFromCompiler();
207 return;
208 }
209
210 #ifndef __arm__
211 // For the simulator build, use whatever the flags specify.
212 supported_ |= command_line;
213
214 #else // __arm__
215 // Probe for additional features at runtime.
216 base::CPU cpu;
217 // Runtime detection is slightly fuzzy, and some inferences are necessary.
218 unsigned runtime = kArmv6;
219 // NEON and VFPv3 imply at least ARMv7-A.
220 if (cpu.has_neon() && cpu.has_vfp3_d32()) {
221 DCHECK(cpu.has_vfp3());
222 runtime |= kArmv7;
223 if (cpu.has_idiva()) {
224 runtime |= kArmv7WithSudiv;
225 if (cpu.architecture() >= 8) {
226 runtime |= kArmv8;
227 }
228 }
229 }
230
231 // Use the best of the features found by CPU detection and those inferred from
232 // the build system. In both cases, restrict available features using the
233 // command-line. Note that the command-line flags are very permissive (kArmv8)
234 // by default.
235 supported_ |= command_line & CpuFeaturesFromCompiler();
236 supported_ |= command_line & runtime;
237
238 // Additional tuning options.
239
240 // ARM Cortex-A9 and Cortex-A5 have 32 byte cachelines.
241 if (cpu.implementer() == base::CPU::ARM &&
242 (cpu.part() == base::CPU::ARM_CORTEX_A5 ||
243 cpu.part() == base::CPU::ARM_CORTEX_A9)) {
244 dcache_line_size_ = 32;
245 }
246 #endif
247
248 DCHECK_IMPLIES(IsSupported(ARMv7_SUDIV), IsSupported(ARMv7));
249 DCHECK_IMPLIES(IsSupported(ARMv8), IsSupported(ARMv7_SUDIV));
250 }
251
252
PrintTarget()253 void CpuFeatures::PrintTarget() {
254 const char* arm_arch = nullptr;
255 const char* arm_target_type = "";
256 const char* arm_no_probe = "";
257 const char* arm_fpu = "";
258 const char* arm_thumb = "";
259 const char* arm_float_abi = nullptr;
260
261 #if !defined __arm__
262 arm_target_type = " simulator";
263 #endif
264
265 #if defined ARM_TEST_NO_FEATURE_PROBE
266 arm_no_probe = " noprobe";
267 #endif
268
269 #if defined CAN_USE_ARMV8_INSTRUCTIONS
270 arm_arch = "arm v8";
271 #elif defined CAN_USE_ARMV7_INSTRUCTIONS
272 arm_arch = "arm v7";
273 #else
274 arm_arch = "arm v6";
275 #endif
276
277 #if defined CAN_USE_NEON
278 arm_fpu = " neon";
279 #elif defined CAN_USE_VFP3_INSTRUCTIONS
280 # if defined CAN_USE_VFP32DREGS
281 arm_fpu = " vfp3";
282 # else
283 arm_fpu = " vfp3-d16";
284 # endif
285 #else
286 arm_fpu = " vfp2";
287 #endif
288
289 #ifdef __arm__
290 arm_float_abi = base::OS::ArmUsingHardFloat() ? "hard" : "softfp";
291 #elif USE_EABI_HARDFLOAT
292 arm_float_abi = "hard";
293 #else
294 arm_float_abi = "softfp";
295 #endif
296
297 #if defined __arm__ && (defined __thumb__) || (defined __thumb2__)
298 arm_thumb = " thumb";
299 #endif
300
301 printf("target%s%s %s%s%s %s\n",
302 arm_target_type, arm_no_probe, arm_arch, arm_fpu, arm_thumb,
303 arm_float_abi);
304 }
305
306
PrintFeatures()307 void CpuFeatures::PrintFeatures() {
308 printf("ARMv8=%d ARMv7=%d VFPv3=%d VFP32DREGS=%d NEON=%d SUDIV=%d",
309 CpuFeatures::IsSupported(ARMv8), CpuFeatures::IsSupported(ARMv7),
310 CpuFeatures::IsSupported(VFPv3), CpuFeatures::IsSupported(VFP32DREGS),
311 CpuFeatures::IsSupported(NEON), CpuFeatures::IsSupported(SUDIV));
312 #ifdef __arm__
313 bool eabi_hardfloat = base::OS::ArmUsingHardFloat();
314 #elif USE_EABI_HARDFLOAT
315 bool eabi_hardfloat = true;
316 #else
317 bool eabi_hardfloat = false;
318 #endif
319 printf(" USE_EABI_HARDFLOAT=%d\n", eabi_hardfloat);
320 }
321
322
323 // -----------------------------------------------------------------------------
324 // Implementation of RelocInfo
325
326 // static
327 const int RelocInfo::kApplyMask =
328 RelocInfo::ModeMask(RelocInfo::RELATIVE_CODE_TARGET);
329
IsCodedSpecially()330 bool RelocInfo::IsCodedSpecially() {
331 // The deserializer needs to know whether a pointer is specially coded. Being
332 // specially coded on ARM means that it is a movw/movt instruction. We don't
333 // generate those for relocatable pointers.
334 return false;
335 }
336
IsInConstantPool()337 bool RelocInfo::IsInConstantPool() {
338 return Assembler::is_constant_pool_load(pc_);
339 }
340
GetDeoptimizationId(Isolate * isolate,DeoptimizeKind kind)341 int RelocInfo::GetDeoptimizationId(Isolate* isolate, DeoptimizeKind kind) {
342 DCHECK(IsRuntimeEntry(rmode_));
343 return Deoptimizer::GetDeoptimizationId(isolate, target_address(), kind);
344 }
345
set_js_to_wasm_address(Address address,ICacheFlushMode icache_flush_mode)346 void RelocInfo::set_js_to_wasm_address(Address address,
347 ICacheFlushMode icache_flush_mode) {
348 DCHECK_EQ(rmode_, JS_TO_WASM_CALL);
349 Assembler::set_target_address_at(pc_, constant_pool_, address,
350 icache_flush_mode);
351 }
352
js_to_wasm_address() const353 Address RelocInfo::js_to_wasm_address() const {
354 DCHECK_EQ(rmode_, JS_TO_WASM_CALL);
355 return Assembler::target_address_at(pc_, constant_pool_);
356 }
357
wasm_call_tag() const358 uint32_t RelocInfo::wasm_call_tag() const {
359 DCHECK(rmode_ == WASM_CALL || rmode_ == WASM_STUB_CALL);
360 return static_cast<uint32_t>(
361 Assembler::target_address_at(pc_, constant_pool_));
362 }
363
364 // -----------------------------------------------------------------------------
365 // Implementation of Operand and MemOperand
366 // See assembler-arm-inl.h for inlined constructors
367
Operand(Handle<HeapObject> handle)368 Operand::Operand(Handle<HeapObject> handle) {
369 rm_ = no_reg;
370 value_.immediate = static_cast<intptr_t>(handle.address());
371 rmode_ = RelocInfo::EMBEDDED_OBJECT;
372 }
373
374
Operand(Register rm,ShiftOp shift_op,int shift_imm)375 Operand::Operand(Register rm, ShiftOp shift_op, int shift_imm) {
376 DCHECK(is_uint5(shift_imm));
377
378 rm_ = rm;
379 rs_ = no_reg;
380 shift_op_ = shift_op;
381 shift_imm_ = shift_imm & 31;
382
383 if ((shift_op == ROR) && (shift_imm == 0)) {
384 // ROR #0 is functionally equivalent to LSL #0 and this allow us to encode
385 // RRX as ROR #0 (See below).
386 shift_op = LSL;
387 } else if (shift_op == RRX) {
388 // encoded as ROR with shift_imm == 0
389 DCHECK_EQ(shift_imm, 0);
390 shift_op_ = ROR;
391 shift_imm_ = 0;
392 }
393 }
394
395
Operand(Register rm,ShiftOp shift_op,Register rs)396 Operand::Operand(Register rm, ShiftOp shift_op, Register rs) {
397 DCHECK(shift_op != RRX);
398 rm_ = rm;
399 rs_ = no_reg;
400 shift_op_ = shift_op;
401 rs_ = rs;
402 }
403
EmbeddedNumber(double value)404 Operand Operand::EmbeddedNumber(double value) {
405 int32_t smi;
406 if (DoubleToSmiInteger(value, &smi)) return Operand(Smi::FromInt(smi));
407 Operand result(0, RelocInfo::EMBEDDED_OBJECT);
408 result.is_heap_object_request_ = true;
409 result.value_.heap_object_request = HeapObjectRequest(value);
410 return result;
411 }
412
EmbeddedCode(CodeStub * stub)413 Operand Operand::EmbeddedCode(CodeStub* stub) {
414 Operand result(0, RelocInfo::CODE_TARGET);
415 result.is_heap_object_request_ = true;
416 result.value_.heap_object_request = HeapObjectRequest(stub);
417 return result;
418 }
419
MemOperand(Register rn,int32_t offset,AddrMode am)420 MemOperand::MemOperand(Register rn, int32_t offset, AddrMode am)
421 : rn_(rn), rm_(no_reg), offset_(offset), am_(am) {
422 // Accesses below the stack pointer are not safe, and are prohibited by the
423 // ABI. We can check obvious violations here.
424 if (rn == sp) {
425 if (am == Offset) DCHECK_LE(0, offset);
426 if (am == NegOffset) DCHECK_GE(0, offset);
427 }
428 }
429
MemOperand(Register rn,Register rm,AddrMode am)430 MemOperand::MemOperand(Register rn, Register rm, AddrMode am)
431 : rn_(rn), rm_(rm), shift_op_(LSL), shift_imm_(0), am_(am) {}
432
MemOperand(Register rn,Register rm,ShiftOp shift_op,int shift_imm,AddrMode am)433 MemOperand::MemOperand(Register rn, Register rm, ShiftOp shift_op,
434 int shift_imm, AddrMode am)
435 : rn_(rn),
436 rm_(rm),
437 shift_op_(shift_op),
438 shift_imm_(shift_imm & 31),
439 am_(am) {
440 DCHECK(is_uint5(shift_imm));
441 }
442
NeonMemOperand(Register rn,AddrMode am,int align)443 NeonMemOperand::NeonMemOperand(Register rn, AddrMode am, int align)
444 : rn_(rn), rm_(am == Offset ? pc : sp) {
445 DCHECK((am == Offset) || (am == PostIndex));
446 SetAlignment(align);
447 }
448
NeonMemOperand(Register rn,Register rm,int align)449 NeonMemOperand::NeonMemOperand(Register rn, Register rm, int align)
450 : rn_(rn), rm_(rm) {
451 SetAlignment(align);
452 }
453
SetAlignment(int align)454 void NeonMemOperand::SetAlignment(int align) {
455 switch (align) {
456 case 0:
457 align_ = 0;
458 break;
459 case 64:
460 align_ = 1;
461 break;
462 case 128:
463 align_ = 2;
464 break;
465 case 256:
466 align_ = 3;
467 break;
468 default:
469 UNREACHABLE();
470 break;
471 }
472 }
473
AllocateAndInstallRequestedHeapObjects(Isolate * isolate)474 void Assembler::AllocateAndInstallRequestedHeapObjects(Isolate* isolate) {
475 for (auto& request : heap_object_requests_) {
476 Handle<HeapObject> object;
477 switch (request.kind()) {
478 case HeapObjectRequest::kHeapNumber:
479 object =
480 isolate->factory()->NewHeapNumber(request.heap_number(), TENURED);
481 break;
482 case HeapObjectRequest::kCodeStub:
483 request.code_stub()->set_isolate(isolate);
484 object = request.code_stub()->GetCode();
485 break;
486 }
487 Address pc = reinterpret_cast<Address>(buffer_) + request.offset();
488 Memory<Address>(constant_pool_entry_address(pc, 0 /* unused */)) =
489 object.address();
490 }
491 }
492
493 // -----------------------------------------------------------------------------
494 // Specific instructions, constants, and masks.
495
496 // str(r, MemOperand(sp, 4, NegPreIndex), al) instruction (aka push(r))
497 // register r is not encoded.
498 const Instr kPushRegPattern = al | B26 | 4 | NegPreIndex | sp.code() * B16;
499 // ldr(r, MemOperand(sp, 4, PostIndex), al) instruction (aka pop(r))
500 // register r is not encoded.
501 const Instr kPopRegPattern = al | B26 | L | 4 | PostIndex | sp.code() * B16;
502 // ldr rd, [pc, #offset]
503 const Instr kLdrPCImmedMask = 15 * B24 | 7 * B20 | 15 * B16;
504 const Instr kLdrPCImmedPattern = 5 * B24 | L | pc.code() * B16;
505 // vldr dd, [pc, #offset]
506 const Instr kVldrDPCMask = 15 * B24 | 3 * B20 | 15 * B16 | 15 * B8;
507 const Instr kVldrDPCPattern = 13 * B24 | L | pc.code() * B16 | 11 * B8;
508 // blxcc rm
509 const Instr kBlxRegMask =
510 15 * B24 | 15 * B20 | 15 * B16 | 15 * B12 | 15 * B8 | 15 * B4;
511 const Instr kBlxRegPattern =
512 B24 | B21 | 15 * B16 | 15 * B12 | 15 * B8 | BLX;
513 const Instr kBlxIp = al | kBlxRegPattern | ip.code();
514 const Instr kMovMvnMask = 0x6D * B21 | 0xF * B16;
515 const Instr kMovMvnPattern = 0xD * B21;
516 const Instr kMovMvnFlip = B22;
517 const Instr kMovLeaveCCMask = 0xDFF * B16;
518 const Instr kMovLeaveCCPattern = 0x1A0 * B16;
519 const Instr kMovwPattern = 0x30 * B20;
520 const Instr kMovtPattern = 0x34 * B20;
521 const Instr kMovwLeaveCCFlip = 0x5 * B21;
522 const Instr kMovImmedMask = 0x7F * B21;
523 const Instr kMovImmedPattern = 0x1D * B21;
524 const Instr kOrrImmedMask = 0x7F * B21;
525 const Instr kOrrImmedPattern = 0x1C * B21;
526 const Instr kCmpCmnMask = 0xDD * B20 | 0xF * B12;
527 const Instr kCmpCmnPattern = 0x15 * B20;
528 const Instr kCmpCmnFlip = B21;
529 const Instr kAddSubFlip = 0x6 * B21;
530 const Instr kAndBicFlip = 0xE * B21;
531
532 // A mask for the Rd register for push, pop, ldr, str instructions.
533 const Instr kLdrRegFpOffsetPattern = al | B26 | L | Offset | fp.code() * B16;
534 const Instr kStrRegFpOffsetPattern = al | B26 | Offset | fp.code() * B16;
535 const Instr kLdrRegFpNegOffsetPattern =
536 al | B26 | L | NegOffset | fp.code() * B16;
537 const Instr kStrRegFpNegOffsetPattern = al | B26 | NegOffset | fp.code() * B16;
538 const Instr kLdrStrInstrTypeMask = 0xFFFF0000;
539
Assembler(const AssemblerOptions & options,void * buffer,int buffer_size)540 Assembler::Assembler(const AssemblerOptions& options, void* buffer,
541 int buffer_size)
542 : AssemblerBase(options, buffer, buffer_size),
543 pending_32_bit_constants_(),
544 pending_64_bit_constants_(),
545 scratch_register_list_(ip.bit()) {
546 pending_32_bit_constants_.reserve(kMinNumPendingConstants);
547 pending_64_bit_constants_.reserve(kMinNumPendingConstants);
548 reloc_info_writer.Reposition(buffer_ + buffer_size_, pc_);
549 next_buffer_check_ = 0;
550 const_pool_blocked_nesting_ = 0;
551 no_const_pool_before_ = 0;
552 first_const_pool_32_use_ = -1;
553 first_const_pool_64_use_ = -1;
554 last_bound_pos_ = 0;
555 if (CpuFeatures::IsSupported(VFP32DREGS)) {
556 // Register objects tend to be abstracted and survive between scopes, so
557 // it's awkward to use CpuFeatures::VFP32DREGS with CpuFeatureScope. To make
558 // its use consistent with other features, we always enable it if we can.
559 EnableCpuFeature(VFP32DREGS);
560 // Make sure we pick two D registers which alias a Q register. This way, we
561 // can use a Q as a scratch if NEON is supported.
562 scratch_vfp_register_list_ = d14.ToVfpRegList() | d15.ToVfpRegList();
563 } else {
564 // When VFP32DREGS is not supported, d15 become allocatable. Therefore we
565 // cannot use it as a scratch.
566 scratch_vfp_register_list_ = d14.ToVfpRegList();
567 }
568 }
569
~Assembler()570 Assembler::~Assembler() {
571 DCHECK_EQ(const_pool_blocked_nesting_, 0);
572 }
573
GetCode(Isolate * isolate,CodeDesc * desc)574 void Assembler::GetCode(Isolate* isolate, CodeDesc* desc) {
575 // Emit constant pool if necessary.
576 int constant_pool_offset = 0;
577 CheckConstPool(true, false);
578 DCHECK(pending_32_bit_constants_.empty());
579 DCHECK(pending_64_bit_constants_.empty());
580
581 AllocateAndInstallRequestedHeapObjects(isolate);
582
583 // Set up code descriptor.
584 desc->buffer = buffer_;
585 desc->buffer_size = buffer_size_;
586 desc->instr_size = pc_offset();
587 desc->reloc_size = (buffer_ + buffer_size_) - reloc_info_writer.pos();
588 desc->constant_pool_size =
589 (constant_pool_offset ? desc->instr_size - constant_pool_offset : 0);
590 desc->origin = this;
591 desc->unwinding_info_size = 0;
592 desc->unwinding_info = nullptr;
593 }
594
595
Align(int m)596 void Assembler::Align(int m) {
597 DCHECK(m >= 4 && base::bits::IsPowerOfTwo(m));
598 DCHECK_EQ(pc_offset() & (kInstrSize - 1), 0);
599 while ((pc_offset() & (m - 1)) != 0) {
600 nop();
601 }
602 }
603
604
CodeTargetAlign()605 void Assembler::CodeTargetAlign() {
606 // Preferred alignment of jump targets on some ARM chips.
607 Align(8);
608 }
609
610
GetCondition(Instr instr)611 Condition Assembler::GetCondition(Instr instr) {
612 return Instruction::ConditionField(instr);
613 }
614
IsLdrRegisterImmediate(Instr instr)615 bool Assembler::IsLdrRegisterImmediate(Instr instr) {
616 return (instr & (B27 | B26 | B25 | B22 | B20)) == (B26 | B20);
617 }
618
619
IsVldrDRegisterImmediate(Instr instr)620 bool Assembler::IsVldrDRegisterImmediate(Instr instr) {
621 return (instr & (15 * B24 | 3 * B20 | 15 * B8)) == (13 * B24 | B20 | 11 * B8);
622 }
623
624
GetLdrRegisterImmediateOffset(Instr instr)625 int Assembler::GetLdrRegisterImmediateOffset(Instr instr) {
626 DCHECK(IsLdrRegisterImmediate(instr));
627 bool positive = (instr & B23) == B23;
628 int offset = instr & kOff12Mask; // Zero extended offset.
629 return positive ? offset : -offset;
630 }
631
632
GetVldrDRegisterImmediateOffset(Instr instr)633 int Assembler::GetVldrDRegisterImmediateOffset(Instr instr) {
634 DCHECK(IsVldrDRegisterImmediate(instr));
635 bool positive = (instr & B23) == B23;
636 int offset = instr & kOff8Mask; // Zero extended offset.
637 offset <<= 2;
638 return positive ? offset : -offset;
639 }
640
641
SetLdrRegisterImmediateOffset(Instr instr,int offset)642 Instr Assembler::SetLdrRegisterImmediateOffset(Instr instr, int offset) {
643 DCHECK(IsLdrRegisterImmediate(instr));
644 bool positive = offset >= 0;
645 if (!positive) offset = -offset;
646 DCHECK(is_uint12(offset));
647 // Set bit indicating whether the offset should be added.
648 instr = (instr & ~B23) | (positive ? B23 : 0);
649 // Set the actual offset.
650 return (instr & ~kOff12Mask) | offset;
651 }
652
653
SetVldrDRegisterImmediateOffset(Instr instr,int offset)654 Instr Assembler::SetVldrDRegisterImmediateOffset(Instr instr, int offset) {
655 DCHECK(IsVldrDRegisterImmediate(instr));
656 DCHECK((offset & ~3) == offset); // Must be 64-bit aligned.
657 bool positive = offset >= 0;
658 if (!positive) offset = -offset;
659 DCHECK(is_uint10(offset));
660 // Set bit indicating whether the offset should be added.
661 instr = (instr & ~B23) | (positive ? B23 : 0);
662 // Set the actual offset. Its bottom 2 bits are zero.
663 return (instr & ~kOff8Mask) | (offset >> 2);
664 }
665
666
IsStrRegisterImmediate(Instr instr)667 bool Assembler::IsStrRegisterImmediate(Instr instr) {
668 return (instr & (B27 | B26 | B25 | B22 | B20)) == B26;
669 }
670
671
SetStrRegisterImmediateOffset(Instr instr,int offset)672 Instr Assembler::SetStrRegisterImmediateOffset(Instr instr, int offset) {
673 DCHECK(IsStrRegisterImmediate(instr));
674 bool positive = offset >= 0;
675 if (!positive) offset = -offset;
676 DCHECK(is_uint12(offset));
677 // Set bit indicating whether the offset should be added.
678 instr = (instr & ~B23) | (positive ? B23 : 0);
679 // Set the actual offset.
680 return (instr & ~kOff12Mask) | offset;
681 }
682
683
IsAddRegisterImmediate(Instr instr)684 bool Assembler::IsAddRegisterImmediate(Instr instr) {
685 return (instr & (B27 | B26 | B25 | B24 | B23 | B22 | B21)) == (B25 | B23);
686 }
687
688
SetAddRegisterImmediateOffset(Instr instr,int offset)689 Instr Assembler::SetAddRegisterImmediateOffset(Instr instr, int offset) {
690 DCHECK(IsAddRegisterImmediate(instr));
691 DCHECK_GE(offset, 0);
692 DCHECK(is_uint12(offset));
693 // Set the offset.
694 return (instr & ~kOff12Mask) | offset;
695 }
696
697
GetRd(Instr instr)698 Register Assembler::GetRd(Instr instr) {
699 return Register::from_code(Instruction::RdValue(instr));
700 }
701
702
GetRn(Instr instr)703 Register Assembler::GetRn(Instr instr) {
704 return Register::from_code(Instruction::RnValue(instr));
705 }
706
707
GetRm(Instr instr)708 Register Assembler::GetRm(Instr instr) {
709 return Register::from_code(Instruction::RmValue(instr));
710 }
711
712
IsPush(Instr instr)713 bool Assembler::IsPush(Instr instr) {
714 return ((instr & ~kRdMask) == kPushRegPattern);
715 }
716
717
IsPop(Instr instr)718 bool Assembler::IsPop(Instr instr) {
719 return ((instr & ~kRdMask) == kPopRegPattern);
720 }
721
722
IsStrRegFpOffset(Instr instr)723 bool Assembler::IsStrRegFpOffset(Instr instr) {
724 return ((instr & kLdrStrInstrTypeMask) == kStrRegFpOffsetPattern);
725 }
726
727
IsLdrRegFpOffset(Instr instr)728 bool Assembler::IsLdrRegFpOffset(Instr instr) {
729 return ((instr & kLdrStrInstrTypeMask) == kLdrRegFpOffsetPattern);
730 }
731
732
IsStrRegFpNegOffset(Instr instr)733 bool Assembler::IsStrRegFpNegOffset(Instr instr) {
734 return ((instr & kLdrStrInstrTypeMask) == kStrRegFpNegOffsetPattern);
735 }
736
737
IsLdrRegFpNegOffset(Instr instr)738 bool Assembler::IsLdrRegFpNegOffset(Instr instr) {
739 return ((instr & kLdrStrInstrTypeMask) == kLdrRegFpNegOffsetPattern);
740 }
741
742
IsLdrPcImmediateOffset(Instr instr)743 bool Assembler::IsLdrPcImmediateOffset(Instr instr) {
744 // Check the instruction is indeed a
745 // ldr<cond> <Rd>, [pc +/- offset_12].
746 return (instr & kLdrPCImmedMask) == kLdrPCImmedPattern;
747 }
748
749
IsVldrDPcImmediateOffset(Instr instr)750 bool Assembler::IsVldrDPcImmediateOffset(Instr instr) {
751 // Check the instruction is indeed a
752 // vldr<cond> <Dd>, [pc +/- offset_10].
753 return (instr & kVldrDPCMask) == kVldrDPCPattern;
754 }
755
756
IsBlxReg(Instr instr)757 bool Assembler::IsBlxReg(Instr instr) {
758 // Check the instruction is indeed a
759 // blxcc <Rm>
760 return (instr & kBlxRegMask) == kBlxRegPattern;
761 }
762
763
IsBlxIp(Instr instr)764 bool Assembler::IsBlxIp(Instr instr) {
765 // Check the instruction is indeed a
766 // blx ip
767 return instr == kBlxIp;
768 }
769
770
IsTstImmediate(Instr instr)771 bool Assembler::IsTstImmediate(Instr instr) {
772 return (instr & (B27 | B26 | I | kOpCodeMask | S | kRdMask)) ==
773 (I | TST | S);
774 }
775
776
IsCmpRegister(Instr instr)777 bool Assembler::IsCmpRegister(Instr instr) {
778 return (instr & (B27 | B26 | I | kOpCodeMask | S | kRdMask | B4)) ==
779 (CMP | S);
780 }
781
782
IsCmpImmediate(Instr instr)783 bool Assembler::IsCmpImmediate(Instr instr) {
784 return (instr & (B27 | B26 | I | kOpCodeMask | S | kRdMask)) ==
785 (I | CMP | S);
786 }
787
788
GetCmpImmediateRegister(Instr instr)789 Register Assembler::GetCmpImmediateRegister(Instr instr) {
790 DCHECK(IsCmpImmediate(instr));
791 return GetRn(instr);
792 }
793
794
GetCmpImmediateRawImmediate(Instr instr)795 int Assembler::GetCmpImmediateRawImmediate(Instr instr) {
796 DCHECK(IsCmpImmediate(instr));
797 return instr & kOff12Mask;
798 }
799
800
801 // Labels refer to positions in the (to be) generated code.
802 // There are bound, linked, and unused labels.
803 //
804 // Bound labels refer to known positions in the already
805 // generated code. pos() is the position the label refers to.
806 //
807 // Linked labels refer to unknown positions in the code
808 // to be generated; pos() is the position of the last
809 // instruction using the label.
810 //
811 // The linked labels form a link chain by making the branch offset
812 // in the instruction steam to point to the previous branch
813 // instruction using the same label.
814 //
815 // The link chain is terminated by a branch offset pointing to the
816 // same position.
817
818
target_at(int pos)819 int Assembler::target_at(int pos) {
820 Instr instr = instr_at(pos);
821 if (is_uint24(instr)) {
822 // Emitted link to a label, not part of a branch.
823 return instr;
824 }
825 DCHECK_EQ(5 * B25, instr & 7 * B25); // b, bl, or blx imm24
826 int imm26 = ((instr & kImm24Mask) << 8) >> 6;
827 if ((Instruction::ConditionField(instr) == kSpecialCondition) &&
828 ((instr & B24) != 0)) {
829 // blx uses bit 24 to encode bit 2 of imm26
830 imm26 += 2;
831 }
832 return pos + Instruction::kPcLoadDelta + imm26;
833 }
834
835
target_at_put(int pos,int target_pos)836 void Assembler::target_at_put(int pos, int target_pos) {
837 Instr instr = instr_at(pos);
838 if (is_uint24(instr)) {
839 DCHECK(target_pos == pos || target_pos >= 0);
840 // Emitted link to a label, not part of a branch.
841 // Load the position of the label relative to the generated code object
842 // pointer in a register.
843
844 // The existing code must be a single 24-bit label chain link, followed by
845 // nops encoding the destination register. See mov_label_offset.
846
847 // Extract the destination register from the first nop instructions.
848 Register dst =
849 Register::from_code(Instruction::RmValue(instr_at(pos + kInstrSize)));
850 // In addition to the 24-bit label chain link, we expect to find one nop for
851 // ARMv7 and above, or two nops for ARMv6. See mov_label_offset.
852 DCHECK(IsNop(instr_at(pos + kInstrSize), dst.code()));
853 if (!CpuFeatures::IsSupported(ARMv7)) {
854 DCHECK(IsNop(instr_at(pos + 2 * kInstrSize), dst.code()));
855 }
856
857 // Here are the instructions we need to emit:
858 // For ARMv7: target24 => target16_1:target16_0
859 // movw dst, #target16_0
860 // movt dst, #target16_1
861 // For ARMv6: target24 => target8_2:target8_1:target8_0
862 // mov dst, #target8_0
863 // orr dst, dst, #target8_1 << 8
864 // orr dst, dst, #target8_2 << 16
865
866 uint32_t target24 = target_pos + (Code::kHeaderSize - kHeapObjectTag);
867 DCHECK(is_uint24(target24));
868 if (is_uint8(target24)) {
869 // If the target fits in a byte then only patch with a mov
870 // instruction.
871 PatchingAssembler patcher(options(),
872 reinterpret_cast<byte*>(buffer_ + pos), 1);
873 patcher.mov(dst, Operand(target24));
874 } else {
875 uint16_t target16_0 = target24 & kImm16Mask;
876 uint16_t target16_1 = target24 >> 16;
877 if (CpuFeatures::IsSupported(ARMv7)) {
878 // Patch with movw/movt.
879 if (target16_1 == 0) {
880 PatchingAssembler patcher(options(),
881 reinterpret_cast<byte*>(buffer_ + pos), 1);
882 CpuFeatureScope scope(&patcher, ARMv7);
883 patcher.movw(dst, target16_0);
884 } else {
885 PatchingAssembler patcher(options(),
886 reinterpret_cast<byte*>(buffer_ + pos), 2);
887 CpuFeatureScope scope(&patcher, ARMv7);
888 patcher.movw(dst, target16_0);
889 patcher.movt(dst, target16_1);
890 }
891 } else {
892 // Patch with a sequence of mov/orr/orr instructions.
893 uint8_t target8_0 = target16_0 & kImm8Mask;
894 uint8_t target8_1 = target16_0 >> 8;
895 uint8_t target8_2 = target16_1 & kImm8Mask;
896 if (target8_2 == 0) {
897 PatchingAssembler patcher(options(),
898 reinterpret_cast<byte*>(buffer_ + pos), 2);
899 patcher.mov(dst, Operand(target8_0));
900 patcher.orr(dst, dst, Operand(target8_1 << 8));
901 } else {
902 PatchingAssembler patcher(options(),
903 reinterpret_cast<byte*>(buffer_ + pos), 3);
904 patcher.mov(dst, Operand(target8_0));
905 patcher.orr(dst, dst, Operand(target8_1 << 8));
906 patcher.orr(dst, dst, Operand(target8_2 << 16));
907 }
908 }
909 }
910 return;
911 }
912 int imm26 = target_pos - (pos + Instruction::kPcLoadDelta);
913 DCHECK_EQ(5 * B25, instr & 7 * B25); // b, bl, or blx imm24
914 if (Instruction::ConditionField(instr) == kSpecialCondition) {
915 // blx uses bit 24 to encode bit 2 of imm26
916 DCHECK_EQ(0, imm26 & 1);
917 instr = (instr & ~(B24 | kImm24Mask)) | ((imm26 & 2) >> 1) * B24;
918 } else {
919 DCHECK_EQ(0, imm26 & 3);
920 instr &= ~kImm24Mask;
921 }
922 int imm24 = imm26 >> 2;
923 DCHECK(is_int24(imm24));
924 instr_at_put(pos, instr | (imm24 & kImm24Mask));
925 }
926
print(const Label * L)927 void Assembler::print(const Label* L) {
928 if (L->is_unused()) {
929 PrintF("unused label\n");
930 } else if (L->is_bound()) {
931 PrintF("bound label to %d\n", L->pos());
932 } else if (L->is_linked()) {
933 Label l;
934 l.link_to(L->pos());
935 PrintF("unbound label");
936 while (l.is_linked()) {
937 PrintF("@ %d ", l.pos());
938 Instr instr = instr_at(l.pos());
939 if ((instr & ~kImm24Mask) == 0) {
940 PrintF("value\n");
941 } else {
942 DCHECK_EQ(instr & 7 * B25, 5 * B25); // b, bl, or blx
943 Condition cond = Instruction::ConditionField(instr);
944 const char* b;
945 const char* c;
946 if (cond == kSpecialCondition) {
947 b = "blx";
948 c = "";
949 } else {
950 if ((instr & B24) != 0)
951 b = "bl";
952 else
953 b = "b";
954
955 switch (cond) {
956 case eq: c = "eq"; break;
957 case ne: c = "ne"; break;
958 case hs: c = "hs"; break;
959 case lo: c = "lo"; break;
960 case mi: c = "mi"; break;
961 case pl: c = "pl"; break;
962 case vs: c = "vs"; break;
963 case vc: c = "vc"; break;
964 case hi: c = "hi"; break;
965 case ls: c = "ls"; break;
966 case ge: c = "ge"; break;
967 case lt: c = "lt"; break;
968 case gt: c = "gt"; break;
969 case le: c = "le"; break;
970 case al: c = ""; break;
971 default:
972 c = "";
973 UNREACHABLE();
974 }
975 }
976 PrintF("%s%s\n", b, c);
977 }
978 next(&l);
979 }
980 } else {
981 PrintF("label in inconsistent state (pos = %d)\n", L->pos_);
982 }
983 }
984
985
bind_to(Label * L,int pos)986 void Assembler::bind_to(Label* L, int pos) {
987 DCHECK(0 <= pos && pos <= pc_offset()); // must have a valid binding position
988 while (L->is_linked()) {
989 int fixup_pos = L->pos();
990 next(L); // call next before overwriting link with target at fixup_pos
991 target_at_put(fixup_pos, pos);
992 }
993 L->bind_to(pos);
994
995 // Keep track of the last bound label so we don't eliminate any instructions
996 // before a bound label.
997 if (pos > last_bound_pos_)
998 last_bound_pos_ = pos;
999 }
1000
1001
bind(Label * L)1002 void Assembler::bind(Label* L) {
1003 DCHECK(!L->is_bound()); // label can only be bound once
1004 bind_to(L, pc_offset());
1005 }
1006
1007
next(Label * L)1008 void Assembler::next(Label* L) {
1009 DCHECK(L->is_linked());
1010 int link = target_at(L->pos());
1011 if (link == L->pos()) {
1012 // Branch target points to the same instruction. This is the end of the link
1013 // chain.
1014 L->Unuse();
1015 } else {
1016 DCHECK_GE(link, 0);
1017 L->link_to(link);
1018 }
1019 }
1020
1021 namespace {
1022
1023 // Low-level code emission routines depending on the addressing mode.
1024 // If this returns true then you have to use the rotate_imm and immed_8
1025 // that it returns, because it may have already changed the instruction
1026 // to match them!
FitsShifter(uint32_t imm32,uint32_t * rotate_imm,uint32_t * immed_8,Instr * instr)1027 bool FitsShifter(uint32_t imm32, uint32_t* rotate_imm, uint32_t* immed_8,
1028 Instr* instr) {
1029 // imm32 must be unsigned.
1030 for (int rot = 0; rot < 16; rot++) {
1031 uint32_t imm8 = base::bits::RotateLeft32(imm32, 2 * rot);
1032 if ((imm8 <= 0xFF)) {
1033 *rotate_imm = rot;
1034 *immed_8 = imm8;
1035 return true;
1036 }
1037 }
1038 // If the opcode is one with a complementary version and the complementary
1039 // immediate fits, change the opcode.
1040 if (instr != nullptr) {
1041 if ((*instr & kMovMvnMask) == kMovMvnPattern) {
1042 if (FitsShifter(~imm32, rotate_imm, immed_8, nullptr)) {
1043 *instr ^= kMovMvnFlip;
1044 return true;
1045 } else if ((*instr & kMovLeaveCCMask) == kMovLeaveCCPattern) {
1046 if (CpuFeatures::IsSupported(ARMv7)) {
1047 if (imm32 < 0x10000) {
1048 *instr ^= kMovwLeaveCCFlip;
1049 *instr |= Assembler::EncodeMovwImmediate(imm32);
1050 *rotate_imm = *immed_8 = 0; // Not used for movw.
1051 return true;
1052 }
1053 }
1054 }
1055 } else if ((*instr & kCmpCmnMask) == kCmpCmnPattern) {
1056 if (FitsShifter(-static_cast<int>(imm32), rotate_imm, immed_8, nullptr)) {
1057 *instr ^= kCmpCmnFlip;
1058 return true;
1059 }
1060 } else {
1061 Instr alu_insn = (*instr & kALUMask);
1062 if (alu_insn == ADD ||
1063 alu_insn == SUB) {
1064 if (FitsShifter(-static_cast<int>(imm32), rotate_imm, immed_8,
1065 nullptr)) {
1066 *instr ^= kAddSubFlip;
1067 return true;
1068 }
1069 } else if (alu_insn == AND ||
1070 alu_insn == BIC) {
1071 if (FitsShifter(~imm32, rotate_imm, immed_8, nullptr)) {
1072 *instr ^= kAndBicFlip;
1073 return true;
1074 }
1075 }
1076 }
1077 }
1078 return false;
1079 }
1080
1081 // We have to use the temporary register for things that can be relocated even
1082 // if they can be encoded in the ARM's 12 bits of immediate-offset instruction
1083 // space. There is no guarantee that the relocated location can be similarly
1084 // encoded.
MustOutputRelocInfo(RelocInfo::Mode rmode,const Assembler * assembler)1085 bool MustOutputRelocInfo(RelocInfo::Mode rmode, const Assembler* assembler) {
1086 if (RelocInfo::IsOnlyForSerializer(rmode)) {
1087 if (assembler->predictable_code_size()) return true;
1088 return assembler->options().record_reloc_info_for_serialization;
1089 } else if (RelocInfo::IsNone(rmode)) {
1090 return false;
1091 }
1092 return true;
1093 }
1094
UseMovImmediateLoad(const Operand & x,const Assembler * assembler)1095 bool UseMovImmediateLoad(const Operand& x, const Assembler* assembler) {
1096 DCHECK_NOT_NULL(assembler);
1097 if (x.MustOutputRelocInfo(assembler)) {
1098 // Prefer constant pool if data is likely to be patched.
1099 return false;
1100 } else {
1101 // Otherwise, use immediate load if movw / movt is available.
1102 return CpuFeatures::IsSupported(ARMv7);
1103 }
1104 }
1105
1106 } // namespace
1107
MustOutputRelocInfo(const Assembler * assembler) const1108 bool Operand::MustOutputRelocInfo(const Assembler* assembler) const {
1109 return v8::internal::MustOutputRelocInfo(rmode_, assembler);
1110 }
1111
InstructionsRequired(const Assembler * assembler,Instr instr) const1112 int Operand::InstructionsRequired(const Assembler* assembler,
1113 Instr instr) const {
1114 DCHECK_NOT_NULL(assembler);
1115 if (rm_.is_valid()) return 1;
1116 uint32_t dummy1, dummy2;
1117 if (MustOutputRelocInfo(assembler) ||
1118 !FitsShifter(immediate(), &dummy1, &dummy2, &instr)) {
1119 // The immediate operand cannot be encoded as a shifter operand, or use of
1120 // constant pool is required. First account for the instructions required
1121 // for the constant pool or immediate load
1122 int instructions;
1123 if (UseMovImmediateLoad(*this, assembler)) {
1124 DCHECK(CpuFeatures::IsSupported(ARMv7));
1125 // A movw / movt immediate load.
1126 instructions = 2;
1127 } else {
1128 // A small constant pool load.
1129 instructions = 1;
1130 }
1131 if ((instr & ~kCondMask) != 13 * B21) { // mov, S not set
1132 // For a mov or mvn instruction which doesn't set the condition
1133 // code, the constant pool or immediate load is enough, otherwise we need
1134 // to account for the actual instruction being requested.
1135 instructions += 1;
1136 }
1137 return instructions;
1138 } else {
1139 // No use of constant pool and the immediate operand can be encoded as a
1140 // shifter operand.
1141 return 1;
1142 }
1143 }
1144
Move32BitImmediate(Register rd,const Operand & x,Condition cond)1145 void Assembler::Move32BitImmediate(Register rd, const Operand& x,
1146 Condition cond) {
1147 if (UseMovImmediateLoad(x, this)) {
1148 CpuFeatureScope scope(this, ARMv7);
1149 // UseMovImmediateLoad should return false when we need to output
1150 // relocation info, since we prefer the constant pool for values that
1151 // can be patched.
1152 DCHECK(!x.MustOutputRelocInfo(this));
1153 UseScratchRegisterScope temps(this);
1154 // Re-use the destination register as a scratch if possible.
1155 Register target = rd != pc ? rd : temps.Acquire();
1156 uint32_t imm32 = static_cast<uint32_t>(x.immediate());
1157 movw(target, imm32 & 0xFFFF, cond);
1158 movt(target, imm32 >> 16, cond);
1159 if (target.code() != rd.code()) {
1160 mov(rd, target, LeaveCC, cond);
1161 }
1162 } else {
1163 int32_t immediate;
1164 if (x.IsHeapObjectRequest()) {
1165 RequestHeapObject(x.heap_object_request());
1166 immediate = 0;
1167 } else {
1168 immediate = x.immediate();
1169 }
1170 ConstantPoolAddEntry(pc_offset(), x.rmode_, immediate);
1171 ldr_pcrel(rd, 0, cond);
1172 }
1173 }
1174
AddrMode1(Instr instr,Register rd,Register rn,const Operand & x)1175 void Assembler::AddrMode1(Instr instr, Register rd, Register rn,
1176 const Operand& x) {
1177 CheckBuffer();
1178 uint32_t opcode = instr & kOpCodeMask;
1179 bool set_flags = (instr & S) != 0;
1180 DCHECK((opcode == ADC) || (opcode == ADD) || (opcode == AND) ||
1181 (opcode == BIC) || (opcode == EOR) || (opcode == ORR) ||
1182 (opcode == RSB) || (opcode == RSC) || (opcode == SBC) ||
1183 (opcode == SUB) || (opcode == CMN) || (opcode == CMP) ||
1184 (opcode == TEQ) || (opcode == TST) || (opcode == MOV) ||
1185 (opcode == MVN));
1186 // For comparison instructions, rd is not defined.
1187 DCHECK(rd.is_valid() || (opcode == CMN) || (opcode == CMP) ||
1188 (opcode == TEQ) || (opcode == TST));
1189 // For move instructions, rn is not defined.
1190 DCHECK(rn.is_valid() || (opcode == MOV) || (opcode == MVN));
1191 DCHECK(rd.is_valid() || rn.is_valid());
1192 DCHECK_EQ(instr & ~(kCondMask | kOpCodeMask | S), 0);
1193 if (!AddrMode1TryEncodeOperand(&instr, x)) {
1194 DCHECK(x.IsImmediate());
1195 // Upon failure to encode, the opcode should not have changed.
1196 DCHECK(opcode == (instr & kOpCodeMask));
1197 UseScratchRegisterScope temps(this);
1198 Condition cond = Instruction::ConditionField(instr);
1199 if ((opcode == MOV) && !set_flags) {
1200 // Generate a sequence of mov instructions or a load from the constant
1201 // pool only for a MOV instruction which does not set the flags.
1202 DCHECK(!rn.is_valid());
1203 Move32BitImmediate(rd, x, cond);
1204 } else if ((opcode == ADD) && !set_flags && (rd == rn) &&
1205 !temps.CanAcquire()) {
1206 // Split the operation into a sequence of additions if we cannot use a
1207 // scratch register. In this case, we cannot re-use rn and the assembler
1208 // does not have any scratch registers to spare.
1209 uint32_t imm = x.immediate();
1210 do {
1211 // The immediate encoding format is composed of 8 bits of data and 4
1212 // bits encoding a rotation. Each of the 16 possible rotations accounts
1213 // for a rotation by an even number.
1214 // 4 bits -> 16 rotations possible
1215 // -> 16 rotations of 2 bits each fits in a 32-bit value.
1216 // This means that finding the even number of trailing zeroes of the
1217 // immediate allows us to more efficiently split it:
1218 int trailing_zeroes = base::bits::CountTrailingZeros(imm) & ~1u;
1219 uint32_t mask = (0xFF << trailing_zeroes);
1220 add(rd, rd, Operand(imm & mask), LeaveCC, cond);
1221 imm = imm & ~mask;
1222 } while (!ImmediateFitsAddrMode1Instruction(imm));
1223 add(rd, rd, Operand(imm), LeaveCC, cond);
1224 } else {
1225 // The immediate operand cannot be encoded as a shifter operand, so load
1226 // it first to a scratch register and change the original instruction to
1227 // use it.
1228 // Re-use the destination register if possible.
1229 Register scratch =
1230 (rd.is_valid() && rd != rn && rd != pc) ? rd : temps.Acquire();
1231 mov(scratch, x, LeaveCC, cond);
1232 AddrMode1(instr, rd, rn, Operand(scratch));
1233 }
1234 return;
1235 }
1236 if (!rd.is_valid()) {
1237 // Emit a comparison instruction.
1238 emit(instr | rn.code() * B16);
1239 } else if (!rn.is_valid()) {
1240 // Emit a move instruction. If the operand is a register-shifted register,
1241 // then prevent the destination from being PC as this is unpredictable.
1242 DCHECK(!x.IsRegisterShiftedRegister() || rd != pc);
1243 emit(instr | rd.code() * B12);
1244 } else {
1245 emit(instr | rn.code() * B16 | rd.code() * B12);
1246 }
1247 if (rn == pc || x.rm_ == pc) {
1248 // Block constant pool emission for one instruction after reading pc.
1249 BlockConstPoolFor(1);
1250 }
1251 }
1252
AddrMode1TryEncodeOperand(Instr * instr,const Operand & x)1253 bool Assembler::AddrMode1TryEncodeOperand(Instr* instr, const Operand& x) {
1254 if (x.IsImmediate()) {
1255 // Immediate.
1256 uint32_t rotate_imm;
1257 uint32_t immed_8;
1258 if (x.MustOutputRelocInfo(this) ||
1259 !FitsShifter(x.immediate(), &rotate_imm, &immed_8, instr)) {
1260 // Let the caller handle generating multiple instructions.
1261 return false;
1262 }
1263 *instr |= I | rotate_imm * B8 | immed_8;
1264 } else if (x.IsImmediateShiftedRegister()) {
1265 *instr |= x.shift_imm_ * B7 | x.shift_op_ | x.rm_.code();
1266 } else {
1267 DCHECK(x.IsRegisterShiftedRegister());
1268 // It is unpredictable to use the PC in this case.
1269 DCHECK(x.rm_ != pc && x.rs_ != pc);
1270 *instr |= x.rs_.code() * B8 | x.shift_op_ | B4 | x.rm_.code();
1271 }
1272
1273 return true;
1274 }
1275
AddrMode2(Instr instr,Register rd,const MemOperand & x)1276 void Assembler::AddrMode2(Instr instr, Register rd, const MemOperand& x) {
1277 DCHECK((instr & ~(kCondMask | B | L)) == B26);
1278 // This method does not handle pc-relative addresses. ldr_pcrel() should be
1279 // used instead.
1280 DCHECK(x.rn_ != pc);
1281 int am = x.am_;
1282 if (!x.rm_.is_valid()) {
1283 // Immediate offset.
1284 int offset_12 = x.offset_;
1285 if (offset_12 < 0) {
1286 offset_12 = -offset_12;
1287 am ^= U;
1288 }
1289 if (!is_uint12(offset_12)) {
1290 // Immediate offset cannot be encoded, load it first to a scratch
1291 // register.
1292 UseScratchRegisterScope temps(this);
1293 // Allow re-using rd for load instructions if possible.
1294 bool is_load = (instr & L) == L;
1295 Register scratch =
1296 (is_load && rd != x.rn_ && rd != pc) ? rd : temps.Acquire();
1297 mov(scratch, Operand(x.offset_), LeaveCC,
1298 Instruction::ConditionField(instr));
1299 AddrMode2(instr, rd, MemOperand(x.rn_, scratch, x.am_));
1300 return;
1301 }
1302 DCHECK_GE(offset_12, 0); // no masking needed
1303 instr |= offset_12;
1304 } else {
1305 // Register offset (shift_imm_ and shift_op_ are 0) or scaled
1306 // register offset the constructors make sure than both shift_imm_
1307 // and shift_op_ are initialized.
1308 DCHECK(x.rm_ != pc);
1309 instr |= B25 | x.shift_imm_*B7 | x.shift_op_ | x.rm_.code();
1310 }
1311 DCHECK((am & (P | W)) == P || x.rn_ != pc); // no pc base with writeback
1312 emit(instr | am | x.rn_.code()*B16 | rd.code()*B12);
1313 }
1314
AddrMode3(Instr instr,Register rd,const MemOperand & x)1315 void Assembler::AddrMode3(Instr instr, Register rd, const MemOperand& x) {
1316 DCHECK((instr & ~(kCondMask | L | S6 | H)) == (B4 | B7));
1317 DCHECK(x.rn_.is_valid());
1318 // This method does not handle pc-relative addresses. ldr_pcrel() should be
1319 // used instead.
1320 DCHECK(x.rn_ != pc);
1321 int am = x.am_;
1322 bool is_load = (instr & L) == L;
1323 if (!x.rm_.is_valid()) {
1324 // Immediate offset.
1325 int offset_8 = x.offset_;
1326 if (offset_8 < 0) {
1327 offset_8 = -offset_8;
1328 am ^= U;
1329 }
1330 if (!is_uint8(offset_8)) {
1331 // Immediate offset cannot be encoded, load it first to a scratch
1332 // register.
1333 UseScratchRegisterScope temps(this);
1334 // Allow re-using rd for load instructions if possible.
1335 Register scratch =
1336 (is_load && rd != x.rn_ && rd != pc) ? rd : temps.Acquire();
1337 mov(scratch, Operand(x.offset_), LeaveCC,
1338 Instruction::ConditionField(instr));
1339 AddrMode3(instr, rd, MemOperand(x.rn_, scratch, x.am_));
1340 return;
1341 }
1342 DCHECK_GE(offset_8, 0); // no masking needed
1343 instr |= B | (offset_8 >> 4) * B8 | (offset_8 & 0xF);
1344 } else if (x.shift_imm_ != 0) {
1345 // Scaled register offsets are not supported, compute the offset separately
1346 // to a scratch register.
1347 UseScratchRegisterScope temps(this);
1348 // Allow re-using rd for load instructions if possible.
1349 Register scratch =
1350 (is_load && rd != x.rn_ && rd != pc) ? rd : temps.Acquire();
1351 mov(scratch, Operand(x.rm_, x.shift_op_, x.shift_imm_), LeaveCC,
1352 Instruction::ConditionField(instr));
1353 AddrMode3(instr, rd, MemOperand(x.rn_, scratch, x.am_));
1354 return;
1355 } else {
1356 // Register offset.
1357 DCHECK((am & (P | W)) == P || x.rm_ != pc); // no pc index with writeback
1358 instr |= x.rm_.code();
1359 }
1360 DCHECK((am & (P | W)) == P || x.rn_ != pc); // no pc base with writeback
1361 emit(instr | am | x.rn_.code()*B16 | rd.code()*B12);
1362 }
1363
AddrMode4(Instr instr,Register rn,RegList rl)1364 void Assembler::AddrMode4(Instr instr, Register rn, RegList rl) {
1365 DCHECK((instr & ~(kCondMask | P | U | W | L)) == B27);
1366 DCHECK_NE(rl, 0);
1367 DCHECK(rn != pc);
1368 emit(instr | rn.code()*B16 | rl);
1369 }
1370
AddrMode5(Instr instr,CRegister crd,const MemOperand & x)1371 void Assembler::AddrMode5(Instr instr, CRegister crd, const MemOperand& x) {
1372 // Unindexed addressing is not encoded by this function.
1373 DCHECK_EQ((B27 | B26),
1374 (instr & ~(kCondMask | kCoprocessorMask | P | U | N | W | L)));
1375 DCHECK(x.rn_.is_valid() && !x.rm_.is_valid());
1376 int am = x.am_;
1377 int offset_8 = x.offset_;
1378 DCHECK_EQ(offset_8 & 3, 0); // offset must be an aligned word offset
1379 offset_8 >>= 2;
1380 if (offset_8 < 0) {
1381 offset_8 = -offset_8;
1382 am ^= U;
1383 }
1384 DCHECK(is_uint8(offset_8)); // unsigned word offset must fit in a byte
1385 DCHECK((am & (P | W)) == P || x.rn_ != pc); // no pc base with writeback
1386
1387 // Post-indexed addressing requires W == 1; different than in AddrMode2/3.
1388 if ((am & P) == 0)
1389 am |= W;
1390
1391 DCHECK_GE(offset_8, 0); // no masking needed
1392 emit(instr | am | x.rn_.code()*B16 | crd.code()*B12 | offset_8);
1393 }
1394
1395
branch_offset(Label * L)1396 int Assembler::branch_offset(Label* L) {
1397 int target_pos;
1398 if (L->is_bound()) {
1399 target_pos = L->pos();
1400 } else {
1401 if (L->is_linked()) {
1402 // Point to previous instruction that uses the link.
1403 target_pos = L->pos();
1404 } else {
1405 // First entry of the link chain points to itself.
1406 target_pos = pc_offset();
1407 }
1408 L->link_to(pc_offset());
1409 }
1410
1411 // Block the emission of the constant pool, since the branch instruction must
1412 // be emitted at the pc offset recorded by the label.
1413 if (!is_const_pool_blocked()) BlockConstPoolFor(1);
1414
1415 return target_pos - (pc_offset() + Instruction::kPcLoadDelta);
1416 }
1417
1418
1419 // Branch instructions.
b(int branch_offset,Condition cond,RelocInfo::Mode rmode)1420 void Assembler::b(int branch_offset, Condition cond, RelocInfo::Mode rmode) {
1421 RecordRelocInfo(rmode);
1422 DCHECK_EQ(branch_offset & 3, 0);
1423 int imm24 = branch_offset >> 2;
1424 const bool b_imm_check = is_int24(imm24);
1425 CHECK(b_imm_check);
1426 emit(cond | B27 | B25 | (imm24 & kImm24Mask));
1427
1428 if (cond == al) {
1429 // Dead code is a good location to emit the constant pool.
1430 CheckConstPool(false, false);
1431 }
1432 }
1433
bl(int branch_offset,Condition cond,RelocInfo::Mode rmode)1434 void Assembler::bl(int branch_offset, Condition cond, RelocInfo::Mode rmode) {
1435 RecordRelocInfo(rmode);
1436 DCHECK_EQ(branch_offset & 3, 0);
1437 int imm24 = branch_offset >> 2;
1438 const bool bl_imm_check = is_int24(imm24);
1439 CHECK(bl_imm_check);
1440 emit(cond | B27 | B25 | B24 | (imm24 & kImm24Mask));
1441 }
1442
blx(int branch_offset)1443 void Assembler::blx(int branch_offset) {
1444 DCHECK_EQ(branch_offset & 1, 0);
1445 int h = ((branch_offset & 2) >> 1)*B24;
1446 int imm24 = branch_offset >> 2;
1447 const bool blx_imm_check = is_int24(imm24);
1448 CHECK(blx_imm_check);
1449 emit(kSpecialCondition | B27 | B25 | h | (imm24 & kImm24Mask));
1450 }
1451
blx(Register target,Condition cond)1452 void Assembler::blx(Register target, Condition cond) {
1453 DCHECK(target != pc);
1454 emit(cond | B24 | B21 | 15*B16 | 15*B12 | 15*B8 | BLX | target.code());
1455 }
1456
bx(Register target,Condition cond)1457 void Assembler::bx(Register target, Condition cond) {
1458 DCHECK(target != pc); // use of pc is actually allowed, but discouraged
1459 emit(cond | B24 | B21 | 15*B16 | 15*B12 | 15*B8 | BX | target.code());
1460 }
1461
1462
b(Label * L,Condition cond)1463 void Assembler::b(Label* L, Condition cond) {
1464 CheckBuffer();
1465 b(branch_offset(L), cond);
1466 }
1467
1468
bl(Label * L,Condition cond)1469 void Assembler::bl(Label* L, Condition cond) {
1470 CheckBuffer();
1471 bl(branch_offset(L), cond);
1472 }
1473
1474
blx(Label * L)1475 void Assembler::blx(Label* L) {
1476 CheckBuffer();
1477 blx(branch_offset(L));
1478 }
1479
1480
1481 // Data-processing instructions.
1482
and_(Register dst,Register src1,const Operand & src2,SBit s,Condition cond)1483 void Assembler::and_(Register dst, Register src1, const Operand& src2,
1484 SBit s, Condition cond) {
1485 AddrMode1(cond | AND | s, dst, src1, src2);
1486 }
1487
and_(Register dst,Register src1,Register src2,SBit s,Condition cond)1488 void Assembler::and_(Register dst, Register src1, Register src2, SBit s,
1489 Condition cond) {
1490 and_(dst, src1, Operand(src2), s, cond);
1491 }
1492
eor(Register dst,Register src1,const Operand & src2,SBit s,Condition cond)1493 void Assembler::eor(Register dst, Register src1, const Operand& src2,
1494 SBit s, Condition cond) {
1495 AddrMode1(cond | EOR | s, dst, src1, src2);
1496 }
1497
1498
sub(Register dst,Register src1,const Operand & src2,SBit s,Condition cond)1499 void Assembler::sub(Register dst, Register src1, const Operand& src2,
1500 SBit s, Condition cond) {
1501 AddrMode1(cond | SUB | s, dst, src1, src2);
1502 }
1503
sub(Register dst,Register src1,Register src2,SBit s,Condition cond)1504 void Assembler::sub(Register dst, Register src1, Register src2, SBit s,
1505 Condition cond) {
1506 sub(dst, src1, Operand(src2), s, cond);
1507 }
1508
rsb(Register dst,Register src1,const Operand & src2,SBit s,Condition cond)1509 void Assembler::rsb(Register dst, Register src1, const Operand& src2,
1510 SBit s, Condition cond) {
1511 AddrMode1(cond | RSB | s, dst, src1, src2);
1512 }
1513
1514
add(Register dst,Register src1,const Operand & src2,SBit s,Condition cond)1515 void Assembler::add(Register dst, Register src1, const Operand& src2,
1516 SBit s, Condition cond) {
1517 AddrMode1(cond | ADD | s, dst, src1, src2);
1518 }
1519
add(Register dst,Register src1,Register src2,SBit s,Condition cond)1520 void Assembler::add(Register dst, Register src1, Register src2, SBit s,
1521 Condition cond) {
1522 add(dst, src1, Operand(src2), s, cond);
1523 }
1524
adc(Register dst,Register src1,const Operand & src2,SBit s,Condition cond)1525 void Assembler::adc(Register dst, Register src1, const Operand& src2,
1526 SBit s, Condition cond) {
1527 AddrMode1(cond | ADC | s, dst, src1, src2);
1528 }
1529
1530
sbc(Register dst,Register src1,const Operand & src2,SBit s,Condition cond)1531 void Assembler::sbc(Register dst, Register src1, const Operand& src2,
1532 SBit s, Condition cond) {
1533 AddrMode1(cond | SBC | s, dst, src1, src2);
1534 }
1535
1536
rsc(Register dst,Register src1,const Operand & src2,SBit s,Condition cond)1537 void Assembler::rsc(Register dst, Register src1, const Operand& src2,
1538 SBit s, Condition cond) {
1539 AddrMode1(cond | RSC | s, dst, src1, src2);
1540 }
1541
1542
tst(Register src1,const Operand & src2,Condition cond)1543 void Assembler::tst(Register src1, const Operand& src2, Condition cond) {
1544 AddrMode1(cond | TST | S, no_reg, src1, src2);
1545 }
1546
tst(Register src1,Register src2,Condition cond)1547 void Assembler::tst(Register src1, Register src2, Condition cond) {
1548 tst(src1, Operand(src2), cond);
1549 }
1550
teq(Register src1,const Operand & src2,Condition cond)1551 void Assembler::teq(Register src1, const Operand& src2, Condition cond) {
1552 AddrMode1(cond | TEQ | S, no_reg, src1, src2);
1553 }
1554
1555
cmp(Register src1,const Operand & src2,Condition cond)1556 void Assembler::cmp(Register src1, const Operand& src2, Condition cond) {
1557 AddrMode1(cond | CMP | S, no_reg, src1, src2);
1558 }
1559
cmp(Register src1,Register src2,Condition cond)1560 void Assembler::cmp(Register src1, Register src2, Condition cond) {
1561 cmp(src1, Operand(src2), cond);
1562 }
1563
cmp_raw_immediate(Register src,int raw_immediate,Condition cond)1564 void Assembler::cmp_raw_immediate(
1565 Register src, int raw_immediate, Condition cond) {
1566 DCHECK(is_uint12(raw_immediate));
1567 emit(cond | I | CMP | S | src.code() << 16 | raw_immediate);
1568 }
1569
1570
cmn(Register src1,const Operand & src2,Condition cond)1571 void Assembler::cmn(Register src1, const Operand& src2, Condition cond) {
1572 AddrMode1(cond | CMN | S, no_reg, src1, src2);
1573 }
1574
1575
orr(Register dst,Register src1,const Operand & src2,SBit s,Condition cond)1576 void Assembler::orr(Register dst, Register src1, const Operand& src2,
1577 SBit s, Condition cond) {
1578 AddrMode1(cond | ORR | s, dst, src1, src2);
1579 }
1580
orr(Register dst,Register src1,Register src2,SBit s,Condition cond)1581 void Assembler::orr(Register dst, Register src1, Register src2, SBit s,
1582 Condition cond) {
1583 orr(dst, src1, Operand(src2), s, cond);
1584 }
1585
mov(Register dst,const Operand & src,SBit s,Condition cond)1586 void Assembler::mov(Register dst, const Operand& src, SBit s, Condition cond) {
1587 // Don't allow nop instructions in the form mov rn, rn to be generated using
1588 // the mov instruction. They must be generated using nop(int/NopMarkerTypes).
1589 DCHECK(!(src.IsRegister() && src.rm() == dst && s == LeaveCC && cond == al));
1590 AddrMode1(cond | MOV | s, dst, no_reg, src);
1591 }
1592
mov(Register dst,Register src,SBit s,Condition cond)1593 void Assembler::mov(Register dst, Register src, SBit s, Condition cond) {
1594 mov(dst, Operand(src), s, cond);
1595 }
1596
mov_label_offset(Register dst,Label * label)1597 void Assembler::mov_label_offset(Register dst, Label* label) {
1598 if (label->is_bound()) {
1599 mov(dst, Operand(label->pos() + (Code::kHeaderSize - kHeapObjectTag)));
1600 } else {
1601 // Emit the link to the label in the code stream followed by extra nop
1602 // instructions.
1603 // If the label is not linked, then start a new link chain by linking it to
1604 // itself, emitting pc_offset().
1605 int link = label->is_linked() ? label->pos() : pc_offset();
1606 label->link_to(pc_offset());
1607
1608 // When the label is bound, these instructions will be patched with a
1609 // sequence of movw/movt or mov/orr/orr instructions. They will load the
1610 // destination register with the position of the label from the beginning
1611 // of the code.
1612 //
1613 // The link will be extracted from the first instruction and the destination
1614 // register from the second.
1615 // For ARMv7:
1616 // link
1617 // mov dst, dst
1618 // For ARMv6:
1619 // link
1620 // mov dst, dst
1621 // mov dst, dst
1622 //
1623 // When the label gets bound: target_at extracts the link and target_at_put
1624 // patches the instructions.
1625 CHECK(is_uint24(link));
1626 BlockConstPoolScope block_const_pool(this);
1627 emit(link);
1628 nop(dst.code());
1629 if (!CpuFeatures::IsSupported(ARMv7)) {
1630 nop(dst.code());
1631 }
1632 }
1633 }
1634
1635
movw(Register reg,uint32_t immediate,Condition cond)1636 void Assembler::movw(Register reg, uint32_t immediate, Condition cond) {
1637 DCHECK(IsEnabled(ARMv7));
1638 emit(cond | 0x30*B20 | reg.code()*B12 | EncodeMovwImmediate(immediate));
1639 }
1640
1641
movt(Register reg,uint32_t immediate,Condition cond)1642 void Assembler::movt(Register reg, uint32_t immediate, Condition cond) {
1643 DCHECK(IsEnabled(ARMv7));
1644 emit(cond | 0x34*B20 | reg.code()*B12 | EncodeMovwImmediate(immediate));
1645 }
1646
1647
bic(Register dst,Register src1,const Operand & src2,SBit s,Condition cond)1648 void Assembler::bic(Register dst, Register src1, const Operand& src2,
1649 SBit s, Condition cond) {
1650 AddrMode1(cond | BIC | s, dst, src1, src2);
1651 }
1652
1653
mvn(Register dst,const Operand & src,SBit s,Condition cond)1654 void Assembler::mvn(Register dst, const Operand& src, SBit s, Condition cond) {
1655 AddrMode1(cond | MVN | s, dst, no_reg, src);
1656 }
1657
asr(Register dst,Register src1,const Operand & src2,SBit s,Condition cond)1658 void Assembler::asr(Register dst, Register src1, const Operand& src2, SBit s,
1659 Condition cond) {
1660 if (src2.IsRegister()) {
1661 mov(dst, Operand(src1, ASR, src2.rm()), s, cond);
1662 } else {
1663 mov(dst, Operand(src1, ASR, src2.immediate()), s, cond);
1664 }
1665 }
1666
lsl(Register dst,Register src1,const Operand & src2,SBit s,Condition cond)1667 void Assembler::lsl(Register dst, Register src1, const Operand& src2, SBit s,
1668 Condition cond) {
1669 if (src2.IsRegister()) {
1670 mov(dst, Operand(src1, LSL, src2.rm()), s, cond);
1671 } else {
1672 mov(dst, Operand(src1, LSL, src2.immediate()), s, cond);
1673 }
1674 }
1675
lsr(Register dst,Register src1,const Operand & src2,SBit s,Condition cond)1676 void Assembler::lsr(Register dst, Register src1, const Operand& src2, SBit s,
1677 Condition cond) {
1678 if (src2.IsRegister()) {
1679 mov(dst, Operand(src1, LSR, src2.rm()), s, cond);
1680 } else {
1681 mov(dst, Operand(src1, LSR, src2.immediate()), s, cond);
1682 }
1683 }
1684
1685 // Multiply instructions.
mla(Register dst,Register src1,Register src2,Register srcA,SBit s,Condition cond)1686 void Assembler::mla(Register dst, Register src1, Register src2, Register srcA,
1687 SBit s, Condition cond) {
1688 DCHECK(dst != pc && src1 != pc && src2 != pc && srcA != pc);
1689 emit(cond | A | s | dst.code()*B16 | srcA.code()*B12 |
1690 src2.code()*B8 | B7 | B4 | src1.code());
1691 }
1692
1693
mls(Register dst,Register src1,Register src2,Register srcA,Condition cond)1694 void Assembler::mls(Register dst, Register src1, Register src2, Register srcA,
1695 Condition cond) {
1696 DCHECK(dst != pc && src1 != pc && src2 != pc && srcA != pc);
1697 DCHECK(IsEnabled(ARMv7));
1698 emit(cond | B22 | B21 | dst.code()*B16 | srcA.code()*B12 |
1699 src2.code()*B8 | B7 | B4 | src1.code());
1700 }
1701
1702
sdiv(Register dst,Register src1,Register src2,Condition cond)1703 void Assembler::sdiv(Register dst, Register src1, Register src2,
1704 Condition cond) {
1705 DCHECK(dst != pc && src1 != pc && src2 != pc);
1706 DCHECK(IsEnabled(SUDIV));
1707 emit(cond | B26 | B25 | B24 | B20 | dst.code() * B16 | 0xF * B12 |
1708 src2.code() * B8 | B4 | src1.code());
1709 }
1710
1711
udiv(Register dst,Register src1,Register src2,Condition cond)1712 void Assembler::udiv(Register dst, Register src1, Register src2,
1713 Condition cond) {
1714 DCHECK(dst != pc && src1 != pc && src2 != pc);
1715 DCHECK(IsEnabled(SUDIV));
1716 emit(cond | B26 | B25 | B24 | B21 | B20 | dst.code() * B16 | 0xF * B12 |
1717 src2.code() * B8 | B4 | src1.code());
1718 }
1719
1720
mul(Register dst,Register src1,Register src2,SBit s,Condition cond)1721 void Assembler::mul(Register dst, Register src1, Register src2, SBit s,
1722 Condition cond) {
1723 DCHECK(dst != pc && src1 != pc && src2 != pc);
1724 // dst goes in bits 16-19 for this instruction!
1725 emit(cond | s | dst.code() * B16 | src2.code() * B8 | B7 | B4 | src1.code());
1726 }
1727
1728
smmla(Register dst,Register src1,Register src2,Register srcA,Condition cond)1729 void Assembler::smmla(Register dst, Register src1, Register src2, Register srcA,
1730 Condition cond) {
1731 DCHECK(dst != pc && src1 != pc && src2 != pc && srcA != pc);
1732 emit(cond | B26 | B25 | B24 | B22 | B20 | dst.code() * B16 |
1733 srcA.code() * B12 | src2.code() * B8 | B4 | src1.code());
1734 }
1735
1736
smmul(Register dst,Register src1,Register src2,Condition cond)1737 void Assembler::smmul(Register dst, Register src1, Register src2,
1738 Condition cond) {
1739 DCHECK(dst != pc && src1 != pc && src2 != pc);
1740 emit(cond | B26 | B25 | B24 | B22 | B20 | dst.code() * B16 | 0xF * B12 |
1741 src2.code() * B8 | B4 | src1.code());
1742 }
1743
1744
smlal(Register dstL,Register dstH,Register src1,Register src2,SBit s,Condition cond)1745 void Assembler::smlal(Register dstL,
1746 Register dstH,
1747 Register src1,
1748 Register src2,
1749 SBit s,
1750 Condition cond) {
1751 DCHECK(dstL != pc && dstH != pc && src1 != pc && src2 != pc);
1752 DCHECK(dstL != dstH);
1753 emit(cond | B23 | B22 | A | s | dstH.code()*B16 | dstL.code()*B12 |
1754 src2.code()*B8 | B7 | B4 | src1.code());
1755 }
1756
1757
smull(Register dstL,Register dstH,Register src1,Register src2,SBit s,Condition cond)1758 void Assembler::smull(Register dstL,
1759 Register dstH,
1760 Register src1,
1761 Register src2,
1762 SBit s,
1763 Condition cond) {
1764 DCHECK(dstL != pc && dstH != pc && src1 != pc && src2 != pc);
1765 DCHECK(dstL != dstH);
1766 emit(cond | B23 | B22 | s | dstH.code()*B16 | dstL.code()*B12 |
1767 src2.code()*B8 | B7 | B4 | src1.code());
1768 }
1769
1770
umlal(Register dstL,Register dstH,Register src1,Register src2,SBit s,Condition cond)1771 void Assembler::umlal(Register dstL,
1772 Register dstH,
1773 Register src1,
1774 Register src2,
1775 SBit s,
1776 Condition cond) {
1777 DCHECK(dstL != pc && dstH != pc && src1 != pc && src2 != pc);
1778 DCHECK(dstL != dstH);
1779 emit(cond | B23 | A | s | dstH.code()*B16 | dstL.code()*B12 |
1780 src2.code()*B8 | B7 | B4 | src1.code());
1781 }
1782
1783
umull(Register dstL,Register dstH,Register src1,Register src2,SBit s,Condition cond)1784 void Assembler::umull(Register dstL,
1785 Register dstH,
1786 Register src1,
1787 Register src2,
1788 SBit s,
1789 Condition cond) {
1790 DCHECK(dstL != pc && dstH != pc && src1 != pc && src2 != pc);
1791 DCHECK(dstL != dstH);
1792 emit(cond | B23 | s | dstH.code()*B16 | dstL.code()*B12 |
1793 src2.code()*B8 | B7 | B4 | src1.code());
1794 }
1795
1796
1797 // Miscellaneous arithmetic instructions.
clz(Register dst,Register src,Condition cond)1798 void Assembler::clz(Register dst, Register src, Condition cond) {
1799 DCHECK(dst != pc && src != pc);
1800 emit(cond | B24 | B22 | B21 | 15*B16 | dst.code()*B12 |
1801 15*B8 | CLZ | src.code());
1802 }
1803
1804
1805 // Saturating instructions.
1806
1807 // Unsigned saturate.
usat(Register dst,int satpos,const Operand & src,Condition cond)1808 void Assembler::usat(Register dst,
1809 int satpos,
1810 const Operand& src,
1811 Condition cond) {
1812 DCHECK(dst != pc && src.rm_ != pc);
1813 DCHECK((satpos >= 0) && (satpos <= 31));
1814 DCHECK(src.IsImmediateShiftedRegister());
1815 DCHECK((src.shift_op_ == ASR) || (src.shift_op_ == LSL));
1816
1817 int sh = 0;
1818 if (src.shift_op_ == ASR) {
1819 sh = 1;
1820 }
1821
1822 emit(cond | 0x6 * B24 | 0xE * B20 | satpos * B16 | dst.code() * B12 |
1823 src.shift_imm_ * B7 | sh * B6 | 0x1 * B4 | src.rm_.code());
1824 }
1825
1826
1827 // Bitfield manipulation instructions.
1828
1829 // Unsigned bit field extract.
1830 // Extracts #width adjacent bits from position #lsb in a register, and
1831 // writes them to the low bits of a destination register.
1832 // ubfx dst, src, #lsb, #width
ubfx(Register dst,Register src,int lsb,int width,Condition cond)1833 void Assembler::ubfx(Register dst,
1834 Register src,
1835 int lsb,
1836 int width,
1837 Condition cond) {
1838 DCHECK(IsEnabled(ARMv7));
1839 DCHECK(dst != pc && src != pc);
1840 DCHECK((lsb >= 0) && (lsb <= 31));
1841 DCHECK((width >= 1) && (width <= (32 - lsb)));
1842 emit(cond | 0xF * B23 | B22 | B21 | (width - 1) * B16 | dst.code() * B12 |
1843 lsb * B7 | B6 | B4 | src.code());
1844 }
1845
1846
1847 // Signed bit field extract.
1848 // Extracts #width adjacent bits from position #lsb in a register, and
1849 // writes them to the low bits of a destination register. The extracted
1850 // value is sign extended to fill the destination register.
1851 // sbfx dst, src, #lsb, #width
sbfx(Register dst,Register src,int lsb,int width,Condition cond)1852 void Assembler::sbfx(Register dst,
1853 Register src,
1854 int lsb,
1855 int width,
1856 Condition cond) {
1857 DCHECK(IsEnabled(ARMv7));
1858 DCHECK(dst != pc && src != pc);
1859 DCHECK((lsb >= 0) && (lsb <= 31));
1860 DCHECK((width >= 1) && (width <= (32 - lsb)));
1861 emit(cond | 0xF * B23 | B21 | (width - 1) * B16 | dst.code() * B12 |
1862 lsb * B7 | B6 | B4 | src.code());
1863 }
1864
1865
1866 // Bit field clear.
1867 // Sets #width adjacent bits at position #lsb in the destination register
1868 // to zero, preserving the value of the other bits.
1869 // bfc dst, #lsb, #width
bfc(Register dst,int lsb,int width,Condition cond)1870 void Assembler::bfc(Register dst, int lsb, int width, Condition cond) {
1871 DCHECK(IsEnabled(ARMv7));
1872 DCHECK(dst != pc);
1873 DCHECK((lsb >= 0) && (lsb <= 31));
1874 DCHECK((width >= 1) && (width <= (32 - lsb)));
1875 int msb = lsb + width - 1;
1876 emit(cond | 0x1F * B22 | msb * B16 | dst.code() * B12 | lsb * B7 | B4 | 0xF);
1877 }
1878
1879
1880 // Bit field insert.
1881 // Inserts #width adjacent bits from the low bits of the source register
1882 // into position #lsb of the destination register.
1883 // bfi dst, src, #lsb, #width
bfi(Register dst,Register src,int lsb,int width,Condition cond)1884 void Assembler::bfi(Register dst,
1885 Register src,
1886 int lsb,
1887 int width,
1888 Condition cond) {
1889 DCHECK(IsEnabled(ARMv7));
1890 DCHECK(dst != pc && src != pc);
1891 DCHECK((lsb >= 0) && (lsb <= 31));
1892 DCHECK((width >= 1) && (width <= (32 - lsb)));
1893 int msb = lsb + width - 1;
1894 emit(cond | 0x1F * B22 | msb * B16 | dst.code() * B12 | lsb * B7 | B4 |
1895 src.code());
1896 }
1897
1898
pkhbt(Register dst,Register src1,const Operand & src2,Condition cond)1899 void Assembler::pkhbt(Register dst,
1900 Register src1,
1901 const Operand& src2,
1902 Condition cond ) {
1903 // Instruction details available in ARM DDI 0406C.b, A8.8.125.
1904 // cond(31-28) | 01101000(27-20) | Rn(19-16) |
1905 // Rd(15-12) | imm5(11-7) | 0(6) | 01(5-4) | Rm(3-0)
1906 DCHECK(dst != pc);
1907 DCHECK(src1 != pc);
1908 DCHECK(src2.IsImmediateShiftedRegister());
1909 DCHECK(src2.rm() != pc);
1910 DCHECK((src2.shift_imm_ >= 0) && (src2.shift_imm_ <= 31));
1911 DCHECK(src2.shift_op() == LSL);
1912 emit(cond | 0x68*B20 | src1.code()*B16 | dst.code()*B12 |
1913 src2.shift_imm_*B7 | B4 | src2.rm().code());
1914 }
1915
1916
pkhtb(Register dst,Register src1,const Operand & src2,Condition cond)1917 void Assembler::pkhtb(Register dst,
1918 Register src1,
1919 const Operand& src2,
1920 Condition cond) {
1921 // Instruction details available in ARM DDI 0406C.b, A8.8.125.
1922 // cond(31-28) | 01101000(27-20) | Rn(19-16) |
1923 // Rd(15-12) | imm5(11-7) | 1(6) | 01(5-4) | Rm(3-0)
1924 DCHECK(dst != pc);
1925 DCHECK(src1 != pc);
1926 DCHECK(src2.IsImmediateShiftedRegister());
1927 DCHECK(src2.rm() != pc);
1928 DCHECK((src2.shift_imm_ >= 1) && (src2.shift_imm_ <= 32));
1929 DCHECK(src2.shift_op() == ASR);
1930 int asr = (src2.shift_imm_ == 32) ? 0 : src2.shift_imm_;
1931 emit(cond | 0x68*B20 | src1.code()*B16 | dst.code()*B12 |
1932 asr*B7 | B6 | B4 | src2.rm().code());
1933 }
1934
1935
sxtb(Register dst,Register src,int rotate,Condition cond)1936 void Assembler::sxtb(Register dst, Register src, int rotate, Condition cond) {
1937 // Instruction details available in ARM DDI 0406C.b, A8.8.233.
1938 // cond(31-28) | 01101010(27-20) | 1111(19-16) |
1939 // Rd(15-12) | rotate(11-10) | 00(9-8)| 0111(7-4) | Rm(3-0)
1940 DCHECK(dst != pc);
1941 DCHECK(src != pc);
1942 DCHECK(rotate == 0 || rotate == 8 || rotate == 16 || rotate == 24);
1943 emit(cond | 0x6A * B20 | 0xF * B16 | dst.code() * B12 |
1944 ((rotate >> 1) & 0xC) * B8 | 7 * B4 | src.code());
1945 }
1946
1947
sxtab(Register dst,Register src1,Register src2,int rotate,Condition cond)1948 void Assembler::sxtab(Register dst, Register src1, Register src2, int rotate,
1949 Condition cond) {
1950 // Instruction details available in ARM DDI 0406C.b, A8.8.233.
1951 // cond(31-28) | 01101010(27-20) | Rn(19-16) |
1952 // Rd(15-12) | rotate(11-10) | 00(9-8)| 0111(7-4) | Rm(3-0)
1953 DCHECK(dst != pc);
1954 DCHECK(src1 != pc);
1955 DCHECK(src2 != pc);
1956 DCHECK(rotate == 0 || rotate == 8 || rotate == 16 || rotate == 24);
1957 emit(cond | 0x6A * B20 | src1.code() * B16 | dst.code() * B12 |
1958 ((rotate >> 1) & 0xC) * B8 | 7 * B4 | src2.code());
1959 }
1960
1961
sxth(Register dst,Register src,int rotate,Condition cond)1962 void Assembler::sxth(Register dst, Register src, int rotate, Condition cond) {
1963 // Instruction details available in ARM DDI 0406C.b, A8.8.235.
1964 // cond(31-28) | 01101011(27-20) | 1111(19-16) |
1965 // Rd(15-12) | rotate(11-10) | 00(9-8)| 0111(7-4) | Rm(3-0)
1966 DCHECK(dst != pc);
1967 DCHECK(src != pc);
1968 DCHECK(rotate == 0 || rotate == 8 || rotate == 16 || rotate == 24);
1969 emit(cond | 0x6B * B20 | 0xF * B16 | dst.code() * B12 |
1970 ((rotate >> 1) & 0xC) * B8 | 7 * B4 | src.code());
1971 }
1972
1973
sxtah(Register dst,Register src1,Register src2,int rotate,Condition cond)1974 void Assembler::sxtah(Register dst, Register src1, Register src2, int rotate,
1975 Condition cond) {
1976 // Instruction details available in ARM DDI 0406C.b, A8.8.235.
1977 // cond(31-28) | 01101011(27-20) | Rn(19-16) |
1978 // Rd(15-12) | rotate(11-10) | 00(9-8)| 0111(7-4) | Rm(3-0)
1979 DCHECK(dst != pc);
1980 DCHECK(src1 != pc);
1981 DCHECK(src2 != pc);
1982 DCHECK(rotate == 0 || rotate == 8 || rotate == 16 || rotate == 24);
1983 emit(cond | 0x6B * B20 | src1.code() * B16 | dst.code() * B12 |
1984 ((rotate >> 1) & 0xC) * B8 | 7 * B4 | src2.code());
1985 }
1986
1987
uxtb(Register dst,Register src,int rotate,Condition cond)1988 void Assembler::uxtb(Register dst, Register src, int rotate, Condition cond) {
1989 // Instruction details available in ARM DDI 0406C.b, A8.8.274.
1990 // cond(31-28) | 01101110(27-20) | 1111(19-16) |
1991 // Rd(15-12) | rotate(11-10) | 00(9-8)| 0111(7-4) | Rm(3-0)
1992 DCHECK(dst != pc);
1993 DCHECK(src != pc);
1994 DCHECK(rotate == 0 || rotate == 8 || rotate == 16 || rotate == 24);
1995 emit(cond | 0x6E * B20 | 0xF * B16 | dst.code() * B12 |
1996 ((rotate >> 1) & 0xC) * B8 | 7 * B4 | src.code());
1997 }
1998
1999
uxtab(Register dst,Register src1,Register src2,int rotate,Condition cond)2000 void Assembler::uxtab(Register dst, Register src1, Register src2, int rotate,
2001 Condition cond) {
2002 // Instruction details available in ARM DDI 0406C.b, A8.8.271.
2003 // cond(31-28) | 01101110(27-20) | Rn(19-16) |
2004 // Rd(15-12) | rotate(11-10) | 00(9-8)| 0111(7-4) | Rm(3-0)
2005 DCHECK(dst != pc);
2006 DCHECK(src1 != pc);
2007 DCHECK(src2 != pc);
2008 DCHECK(rotate == 0 || rotate == 8 || rotate == 16 || rotate == 24);
2009 emit(cond | 0x6E * B20 | src1.code() * B16 | dst.code() * B12 |
2010 ((rotate >> 1) & 0xC) * B8 | 7 * B4 | src2.code());
2011 }
2012
2013
uxtb16(Register dst,Register src,int rotate,Condition cond)2014 void Assembler::uxtb16(Register dst, Register src, int rotate, Condition cond) {
2015 // Instruction details available in ARM DDI 0406C.b, A8.8.275.
2016 // cond(31-28) | 01101100(27-20) | 1111(19-16) |
2017 // Rd(15-12) | rotate(11-10) | 00(9-8)| 0111(7-4) | Rm(3-0)
2018 DCHECK(dst != pc);
2019 DCHECK(src != pc);
2020 DCHECK(rotate == 0 || rotate == 8 || rotate == 16 || rotate == 24);
2021 emit(cond | 0x6C * B20 | 0xF * B16 | dst.code() * B12 |
2022 ((rotate >> 1) & 0xC) * B8 | 7 * B4 | src.code());
2023 }
2024
2025
uxth(Register dst,Register src,int rotate,Condition cond)2026 void Assembler::uxth(Register dst, Register src, int rotate, Condition cond) {
2027 // Instruction details available in ARM DDI 0406C.b, A8.8.276.
2028 // cond(31-28) | 01101111(27-20) | 1111(19-16) |
2029 // Rd(15-12) | rotate(11-10) | 00(9-8)| 0111(7-4) | Rm(3-0)
2030 DCHECK(dst != pc);
2031 DCHECK(src != pc);
2032 DCHECK(rotate == 0 || rotate == 8 || rotate == 16 || rotate == 24);
2033 emit(cond | 0x6F * B20 | 0xF * B16 | dst.code() * B12 |
2034 ((rotate >> 1) & 0xC) * B8 | 7 * B4 | src.code());
2035 }
2036
2037
uxtah(Register dst,Register src1,Register src2,int rotate,Condition cond)2038 void Assembler::uxtah(Register dst, Register src1, Register src2, int rotate,
2039 Condition cond) {
2040 // Instruction details available in ARM DDI 0406C.b, A8.8.273.
2041 // cond(31-28) | 01101111(27-20) | Rn(19-16) |
2042 // Rd(15-12) | rotate(11-10) | 00(9-8)| 0111(7-4) | Rm(3-0)
2043 DCHECK(dst != pc);
2044 DCHECK(src1 != pc);
2045 DCHECK(src2 != pc);
2046 DCHECK(rotate == 0 || rotate == 8 || rotate == 16 || rotate == 24);
2047 emit(cond | 0x6F * B20 | src1.code() * B16 | dst.code() * B12 |
2048 ((rotate >> 1) & 0xC) * B8 | 7 * B4 | src2.code());
2049 }
2050
2051
rbit(Register dst,Register src,Condition cond)2052 void Assembler::rbit(Register dst, Register src, Condition cond) {
2053 // Instruction details available in ARM DDI 0406C.b, A8.8.144.
2054 // cond(31-28) | 011011111111(27-16) | Rd(15-12) | 11110011(11-4) | Rm(3-0)
2055 DCHECK(IsEnabled(ARMv7));
2056 DCHECK(dst != pc);
2057 DCHECK(src != pc);
2058 emit(cond | 0x6FF * B16 | dst.code() * B12 | 0xF3 * B4 | src.code());
2059 }
2060
rev(Register dst,Register src,Condition cond)2061 void Assembler::rev(Register dst, Register src, Condition cond) {
2062 // Instruction details available in ARM DDI 0406C.b, A8.8.144.
2063 // cond(31-28) | 011010111111(27-16) | Rd(15-12) | 11110011(11-4) | Rm(3-0)
2064 DCHECK(dst != pc);
2065 DCHECK(src != pc);
2066 emit(cond | 0x6BF * B16 | dst.code() * B12 | 0xF3 * B4 | src.code());
2067 }
2068
2069 // Status register access instructions.
mrs(Register dst,SRegister s,Condition cond)2070 void Assembler::mrs(Register dst, SRegister s, Condition cond) {
2071 DCHECK(dst != pc);
2072 emit(cond | B24 | s | 15*B16 | dst.code()*B12);
2073 }
2074
2075
msr(SRegisterFieldMask fields,const Operand & src,Condition cond)2076 void Assembler::msr(SRegisterFieldMask fields, const Operand& src,
2077 Condition cond) {
2078 DCHECK_NE(fields & 0x000F0000, 0); // At least one field must be set.
2079 DCHECK(((fields & 0xFFF0FFFF) == CPSR) || ((fields & 0xFFF0FFFF) == SPSR));
2080 Instr instr;
2081 if (src.IsImmediate()) {
2082 // Immediate.
2083 uint32_t rotate_imm;
2084 uint32_t immed_8;
2085 if (src.MustOutputRelocInfo(this) ||
2086 !FitsShifter(src.immediate(), &rotate_imm, &immed_8, nullptr)) {
2087 UseScratchRegisterScope temps(this);
2088 Register scratch = temps.Acquire();
2089 // Immediate operand cannot be encoded, load it first to a scratch
2090 // register.
2091 Move32BitImmediate(scratch, src);
2092 msr(fields, Operand(scratch), cond);
2093 return;
2094 }
2095 instr = I | rotate_imm*B8 | immed_8;
2096 } else {
2097 DCHECK(src.IsRegister()); // Only rm is allowed.
2098 instr = src.rm_.code();
2099 }
2100 emit(cond | instr | B24 | B21 | fields | 15*B12);
2101 }
2102
2103
2104 // Load/Store instructions.
ldr(Register dst,const MemOperand & src,Condition cond)2105 void Assembler::ldr(Register dst, const MemOperand& src, Condition cond) {
2106 AddrMode2(cond | B26 | L, dst, src);
2107 }
2108
2109
str(Register src,const MemOperand & dst,Condition cond)2110 void Assembler::str(Register src, const MemOperand& dst, Condition cond) {
2111 AddrMode2(cond | B26, src, dst);
2112 }
2113
2114
ldrb(Register dst,const MemOperand & src,Condition cond)2115 void Assembler::ldrb(Register dst, const MemOperand& src, Condition cond) {
2116 AddrMode2(cond | B26 | B | L, dst, src);
2117 }
2118
2119
strb(Register src,const MemOperand & dst,Condition cond)2120 void Assembler::strb(Register src, const MemOperand& dst, Condition cond) {
2121 AddrMode2(cond | B26 | B, src, dst);
2122 }
2123
2124
ldrh(Register dst,const MemOperand & src,Condition cond)2125 void Assembler::ldrh(Register dst, const MemOperand& src, Condition cond) {
2126 AddrMode3(cond | L | B7 | H | B4, dst, src);
2127 }
2128
2129
strh(Register src,const MemOperand & dst,Condition cond)2130 void Assembler::strh(Register src, const MemOperand& dst, Condition cond) {
2131 AddrMode3(cond | B7 | H | B4, src, dst);
2132 }
2133
2134
ldrsb(Register dst,const MemOperand & src,Condition cond)2135 void Assembler::ldrsb(Register dst, const MemOperand& src, Condition cond) {
2136 AddrMode3(cond | L | B7 | S6 | B4, dst, src);
2137 }
2138
2139
ldrsh(Register dst,const MemOperand & src,Condition cond)2140 void Assembler::ldrsh(Register dst, const MemOperand& src, Condition cond) {
2141 AddrMode3(cond | L | B7 | S6 | H | B4, dst, src);
2142 }
2143
2144
ldrd(Register dst1,Register dst2,const MemOperand & src,Condition cond)2145 void Assembler::ldrd(Register dst1, Register dst2,
2146 const MemOperand& src, Condition cond) {
2147 DCHECK(src.rm() == no_reg);
2148 DCHECK(dst1 != lr); // r14.
2149 DCHECK_EQ(0, dst1.code() % 2);
2150 DCHECK_EQ(dst1.code() + 1, dst2.code());
2151 AddrMode3(cond | B7 | B6 | B4, dst1, src);
2152 }
2153
2154
strd(Register src1,Register src2,const MemOperand & dst,Condition cond)2155 void Assembler::strd(Register src1, Register src2,
2156 const MemOperand& dst, Condition cond) {
2157 DCHECK(dst.rm() == no_reg);
2158 DCHECK(src1 != lr); // r14.
2159 DCHECK_EQ(0, src1.code() % 2);
2160 DCHECK_EQ(src1.code() + 1, src2.code());
2161 AddrMode3(cond | B7 | B6 | B5 | B4, src1, dst);
2162 }
2163
ldr_pcrel(Register dst,int imm12,Condition cond)2164 void Assembler::ldr_pcrel(Register dst, int imm12, Condition cond) {
2165 AddrMode am = Offset;
2166 if (imm12 < 0) {
2167 imm12 = -imm12;
2168 am = NegOffset;
2169 }
2170 DCHECK(is_uint12(imm12));
2171 emit(cond | B26 | am | L | pc.code() * B16 | dst.code() * B12 | imm12);
2172 }
2173
2174 // Load/Store exclusive instructions.
ldrex(Register dst,Register src,Condition cond)2175 void Assembler::ldrex(Register dst, Register src, Condition cond) {
2176 // Instruction details available in ARM DDI 0406C.b, A8.8.75.
2177 // cond(31-28) | 00011001(27-20) | Rn(19-16) | Rt(15-12) | 111110011111(11-0)
2178 DCHECK(dst != pc);
2179 DCHECK(src != pc);
2180 emit(cond | B24 | B23 | B20 | src.code() * B16 | dst.code() * B12 | 0xF9F);
2181 }
2182
strex(Register src1,Register src2,Register dst,Condition cond)2183 void Assembler::strex(Register src1, Register src2, Register dst,
2184 Condition cond) {
2185 // Instruction details available in ARM DDI 0406C.b, A8.8.212.
2186 // cond(31-28) | 00011000(27-20) | Rn(19-16) | Rd(15-12) | 11111001(11-4) |
2187 // Rt(3-0)
2188 DCHECK(dst != pc);
2189 DCHECK(src1 != pc);
2190 DCHECK(src2 != pc);
2191 DCHECK(src1 != dst);
2192 DCHECK(src1 != src2);
2193 emit(cond | B24 | B23 | dst.code() * B16 | src1.code() * B12 | 0xF9 * B4 |
2194 src2.code());
2195 }
2196
ldrexb(Register dst,Register src,Condition cond)2197 void Assembler::ldrexb(Register dst, Register src, Condition cond) {
2198 // Instruction details available in ARM DDI 0406C.b, A8.8.76.
2199 // cond(31-28) | 00011101(27-20) | Rn(19-16) | Rt(15-12) | 111110011111(11-0)
2200 DCHECK(dst != pc);
2201 DCHECK(src != pc);
2202 emit(cond | B24 | B23 | B22 | B20 | src.code() * B16 | dst.code() * B12 |
2203 0xF9F);
2204 }
2205
strexb(Register src1,Register src2,Register dst,Condition cond)2206 void Assembler::strexb(Register src1, Register src2, Register dst,
2207 Condition cond) {
2208 // Instruction details available in ARM DDI 0406C.b, A8.8.213.
2209 // cond(31-28) | 00011100(27-20) | Rn(19-16) | Rd(15-12) | 11111001(11-4) |
2210 // Rt(3-0)
2211 DCHECK(dst != pc);
2212 DCHECK(src1 != pc);
2213 DCHECK(src2 != pc);
2214 DCHECK(src1 != dst);
2215 DCHECK(src1 != src2);
2216 emit(cond | B24 | B23 | B22 | dst.code() * B16 | src1.code() * B12 |
2217 0xF9 * B4 | src2.code());
2218 }
2219
ldrexh(Register dst,Register src,Condition cond)2220 void Assembler::ldrexh(Register dst, Register src, Condition cond) {
2221 // Instruction details available in ARM DDI 0406C.b, A8.8.78.
2222 // cond(31-28) | 00011111(27-20) | Rn(19-16) | Rt(15-12) | 111110011111(11-0)
2223 DCHECK(dst != pc);
2224 DCHECK(src != pc);
2225 emit(cond | B24 | B23 | B22 | B21 | B20 | src.code() * B16 |
2226 dst.code() * B12 | 0xF9F);
2227 }
2228
strexh(Register src1,Register src2,Register dst,Condition cond)2229 void Assembler::strexh(Register src1, Register src2, Register dst,
2230 Condition cond) {
2231 // Instruction details available in ARM DDI 0406C.b, A8.8.215.
2232 // cond(31-28) | 00011110(27-20) | Rn(19-16) | Rd(15-12) | 11111001(11-4) |
2233 // Rt(3-0)
2234 DCHECK(dst != pc);
2235 DCHECK(src1 != pc);
2236 DCHECK(src2 != pc);
2237 DCHECK(src1 != dst);
2238 DCHECK(src1 != src2);
2239 emit(cond | B24 | B23 | B22 | B21 | dst.code() * B16 | src1.code() * B12 |
2240 0xF9 * B4 | src2.code());
2241 }
2242
ldrexd(Register dst1,Register dst2,Register src,Condition cond)2243 void Assembler::ldrexd(Register dst1, Register dst2, Register src,
2244 Condition cond) {
2245 // cond(31-28) | 00011011(27-20) | Rn(19-16) | Rt(15-12) | 111110011111(11-0)
2246 DCHECK(dst1 != lr); // r14.
2247 // The pair of destination registers is restricted to being an even-numbered
2248 // register and the odd-numbered register that immediately follows it.
2249 DCHECK_EQ(0, dst1.code() % 2);
2250 DCHECK_EQ(dst1.code() + 1, dst2.code());
2251 emit(cond | B24 | B23 | B21 | B20 | src.code() * B16 | dst1.code() * B12 |
2252 0xF9F);
2253 }
2254
strexd(Register res,Register src1,Register src2,Register dst,Condition cond)2255 void Assembler::strexd(Register res, Register src1, Register src2, Register dst,
2256 Condition cond) {
2257 // cond(31-28) | 00011010(27-20) | Rn(19-16) | Rt(15-12) | 111110011111(11-0)
2258 DCHECK(src1 != lr); // r14.
2259 // The pair of source registers is restricted to being an even-numbered
2260 // register and the odd-numbered register that immediately follows it.
2261 DCHECK_EQ(0, src1.code() % 2);
2262 DCHECK_EQ(src1.code() + 1, src2.code());
2263 emit(cond | B24 | B23 | B21 | dst.code() * B16 | res.code() * B12 |
2264 0xF9 * B4 | src1.code());
2265 }
2266
2267 // Preload instructions.
pld(const MemOperand & address)2268 void Assembler::pld(const MemOperand& address) {
2269 // Instruction details available in ARM DDI 0406C.b, A8.8.128.
2270 // 1111(31-28) | 0111(27-24) | U(23) | R(22) | 01(21-20) | Rn(19-16) |
2271 // 1111(15-12) | imm5(11-07) | type(6-5) | 0(4)| Rm(3-0) |
2272 DCHECK(address.rm() == no_reg);
2273 DCHECK(address.am() == Offset);
2274 int U = B23;
2275 int offset = address.offset();
2276 if (offset < 0) {
2277 offset = -offset;
2278 U = 0;
2279 }
2280 DCHECK_LT(offset, 4096);
2281 emit(kSpecialCondition | B26 | B24 | U | B22 | B20 |
2282 address.rn().code() * B16 | 0xF * B12 | offset);
2283 }
2284
2285
2286 // Load/Store multiple instructions.
ldm(BlockAddrMode am,Register base,RegList dst,Condition cond)2287 void Assembler::ldm(BlockAddrMode am,
2288 Register base,
2289 RegList dst,
2290 Condition cond) {
2291 // ABI stack constraint: ldmxx base, {..sp..} base != sp is not restartable.
2292 DCHECK(base == sp || (dst & sp.bit()) == 0);
2293
2294 AddrMode4(cond | B27 | am | L, base, dst);
2295
2296 // Emit the constant pool after a function return implemented by ldm ..{..pc}.
2297 if (cond == al && (dst & pc.bit()) != 0) {
2298 // There is a slight chance that the ldm instruction was actually a call,
2299 // in which case it would be wrong to return into the constant pool; we
2300 // recognize this case by checking if the emission of the pool was blocked
2301 // at the pc of the ldm instruction by a mov lr, pc instruction; if this is
2302 // the case, we emit a jump over the pool.
2303 CheckConstPool(true, no_const_pool_before_ == pc_offset() - kInstrSize);
2304 }
2305 }
2306
2307
stm(BlockAddrMode am,Register base,RegList src,Condition cond)2308 void Assembler::stm(BlockAddrMode am,
2309 Register base,
2310 RegList src,
2311 Condition cond) {
2312 AddrMode4(cond | B27 | am, base, src);
2313 }
2314
2315
2316 // Exception-generating instructions and debugging support.
2317 // Stops with a non-negative code less than kNumOfWatchedStops support
2318 // enabling/disabling and a counter feature. See simulator-arm.h .
stop(const char * msg,Condition cond,int32_t code)2319 void Assembler::stop(const char* msg, Condition cond, int32_t code) {
2320 #ifndef __arm__
2321 DCHECK_GE(code, kDefaultStopCode);
2322 {
2323 BlockConstPoolScope block_const_pool(this);
2324 if (code >= 0) {
2325 svc(kStopCode + code, cond);
2326 } else {
2327 svc(kStopCode + kMaxStopCode, cond);
2328 }
2329 }
2330 #else // def __arm__
2331 if (cond != al) {
2332 Label skip;
2333 b(&skip, NegateCondition(cond));
2334 bkpt(0);
2335 bind(&skip);
2336 } else {
2337 bkpt(0);
2338 }
2339 #endif // def __arm__
2340 }
2341
bkpt(uint32_t imm16)2342 void Assembler::bkpt(uint32_t imm16) {
2343 DCHECK(is_uint16(imm16));
2344 emit(al | B24 | B21 | (imm16 >> 4) * B8 | BKPT | (imm16 & 0xF));
2345 }
2346
2347
svc(uint32_t imm24,Condition cond)2348 void Assembler::svc(uint32_t imm24, Condition cond) {
2349 DCHECK(is_uint24(imm24));
2350 emit(cond | 15*B24 | imm24);
2351 }
2352
2353
dmb(BarrierOption option)2354 void Assembler::dmb(BarrierOption option) {
2355 if (CpuFeatures::IsSupported(ARMv7)) {
2356 // Details available in ARM DDI 0406C.b, A8-378.
2357 emit(kSpecialCondition | 0x57FF * B12 | 5 * B4 | option);
2358 } else {
2359 // Details available in ARM DDI 0406C.b, B3-1750.
2360 // CP15DMB: CRn=c7, opc1=0, CRm=c10, opc2=5, Rt is ignored.
2361 mcr(p15, 0, r0, cr7, cr10, 5);
2362 }
2363 }
2364
2365
dsb(BarrierOption option)2366 void Assembler::dsb(BarrierOption option) {
2367 if (CpuFeatures::IsSupported(ARMv7)) {
2368 // Details available in ARM DDI 0406C.b, A8-380.
2369 emit(kSpecialCondition | 0x57FF * B12 | 4 * B4 | option);
2370 } else {
2371 // Details available in ARM DDI 0406C.b, B3-1750.
2372 // CP15DSB: CRn=c7, opc1=0, CRm=c10, opc2=4, Rt is ignored.
2373 mcr(p15, 0, r0, cr7, cr10, 4);
2374 }
2375 }
2376
2377
isb(BarrierOption option)2378 void Assembler::isb(BarrierOption option) {
2379 if (CpuFeatures::IsSupported(ARMv7)) {
2380 // Details available in ARM DDI 0406C.b, A8-389.
2381 emit(kSpecialCondition | 0x57FF * B12 | 6 * B4 | option);
2382 } else {
2383 // Details available in ARM DDI 0406C.b, B3-1750.
2384 // CP15ISB: CRn=c7, opc1=0, CRm=c5, opc2=4, Rt is ignored.
2385 mcr(p15, 0, r0, cr7, cr5, 4);
2386 }
2387 }
2388
csdb()2389 void Assembler::csdb() {
2390 // Details available in Arm Cache Speculation Side-channels white paper,
2391 // version 1.1, page 4.
2392 emit(0xE320F014);
2393 }
2394
2395 // Coprocessor instructions.
cdp(Coprocessor coproc,int opcode_1,CRegister crd,CRegister crn,CRegister crm,int opcode_2,Condition cond)2396 void Assembler::cdp(Coprocessor coproc,
2397 int opcode_1,
2398 CRegister crd,
2399 CRegister crn,
2400 CRegister crm,
2401 int opcode_2,
2402 Condition cond) {
2403 DCHECK(is_uint4(opcode_1) && is_uint3(opcode_2));
2404 emit(cond | B27 | B26 | B25 | (opcode_1 & 15)*B20 | crn.code()*B16 |
2405 crd.code()*B12 | coproc*B8 | (opcode_2 & 7)*B5 | crm.code());
2406 }
2407
cdp2(Coprocessor coproc,int opcode_1,CRegister crd,CRegister crn,CRegister crm,int opcode_2)2408 void Assembler::cdp2(Coprocessor coproc, int opcode_1, CRegister crd,
2409 CRegister crn, CRegister crm, int opcode_2) {
2410 cdp(coproc, opcode_1, crd, crn, crm, opcode_2, kSpecialCondition);
2411 }
2412
2413
mcr(Coprocessor coproc,int opcode_1,Register rd,CRegister crn,CRegister crm,int opcode_2,Condition cond)2414 void Assembler::mcr(Coprocessor coproc,
2415 int opcode_1,
2416 Register rd,
2417 CRegister crn,
2418 CRegister crm,
2419 int opcode_2,
2420 Condition cond) {
2421 DCHECK(is_uint3(opcode_1) && is_uint3(opcode_2));
2422 emit(cond | B27 | B26 | B25 | (opcode_1 & 7)*B21 | crn.code()*B16 |
2423 rd.code()*B12 | coproc*B8 | (opcode_2 & 7)*B5 | B4 | crm.code());
2424 }
2425
mcr2(Coprocessor coproc,int opcode_1,Register rd,CRegister crn,CRegister crm,int opcode_2)2426 void Assembler::mcr2(Coprocessor coproc, int opcode_1, Register rd,
2427 CRegister crn, CRegister crm, int opcode_2) {
2428 mcr(coproc, opcode_1, rd, crn, crm, opcode_2, kSpecialCondition);
2429 }
2430
2431
mrc(Coprocessor coproc,int opcode_1,Register rd,CRegister crn,CRegister crm,int opcode_2,Condition cond)2432 void Assembler::mrc(Coprocessor coproc,
2433 int opcode_1,
2434 Register rd,
2435 CRegister crn,
2436 CRegister crm,
2437 int opcode_2,
2438 Condition cond) {
2439 DCHECK(is_uint3(opcode_1) && is_uint3(opcode_2));
2440 emit(cond | B27 | B26 | B25 | (opcode_1 & 7)*B21 | L | crn.code()*B16 |
2441 rd.code()*B12 | coproc*B8 | (opcode_2 & 7)*B5 | B4 | crm.code());
2442 }
2443
mrc2(Coprocessor coproc,int opcode_1,Register rd,CRegister crn,CRegister crm,int opcode_2)2444 void Assembler::mrc2(Coprocessor coproc, int opcode_1, Register rd,
2445 CRegister crn, CRegister crm, int opcode_2) {
2446 mrc(coproc, opcode_1, rd, crn, crm, opcode_2, kSpecialCondition);
2447 }
2448
2449
ldc(Coprocessor coproc,CRegister crd,const MemOperand & src,LFlag l,Condition cond)2450 void Assembler::ldc(Coprocessor coproc,
2451 CRegister crd,
2452 const MemOperand& src,
2453 LFlag l,
2454 Condition cond) {
2455 AddrMode5(cond | B27 | B26 | l | L | coproc * B8, crd, src);
2456 }
2457
2458
ldc(Coprocessor coproc,CRegister crd,Register rn,int option,LFlag l,Condition cond)2459 void Assembler::ldc(Coprocessor coproc,
2460 CRegister crd,
2461 Register rn,
2462 int option,
2463 LFlag l,
2464 Condition cond) {
2465 // Unindexed addressing.
2466 DCHECK(is_uint8(option));
2467 emit(cond | B27 | B26 | U | l | L | rn.code()*B16 | crd.code()*B12 |
2468 coproc*B8 | (option & 255));
2469 }
2470
ldc2(Coprocessor coproc,CRegister crd,const MemOperand & src,LFlag l)2471 void Assembler::ldc2(Coprocessor coproc, CRegister crd, const MemOperand& src,
2472 LFlag l) {
2473 ldc(coproc, crd, src, l, kSpecialCondition);
2474 }
2475
ldc2(Coprocessor coproc,CRegister crd,Register rn,int option,LFlag l)2476 void Assembler::ldc2(Coprocessor coproc, CRegister crd, Register rn, int option,
2477 LFlag l) {
2478 ldc(coproc, crd, rn, option, l, kSpecialCondition);
2479 }
2480
2481
2482 // Support for VFP.
2483
vldr(const DwVfpRegister dst,const Register base,int offset,const Condition cond)2484 void Assembler::vldr(const DwVfpRegister dst,
2485 const Register base,
2486 int offset,
2487 const Condition cond) {
2488 // Ddst = MEM(Rbase + offset).
2489 // Instruction details available in ARM DDI 0406C.b, A8-924.
2490 // cond(31-28) | 1101(27-24)| U(23) | D(22) | 01(21-20) | Rbase(19-16) |
2491 // Vd(15-12) | 1011(11-8) | offset
2492 DCHECK(VfpRegisterIsAvailable(dst));
2493 int u = 1;
2494 if (offset < 0) {
2495 CHECK_NE(offset, kMinInt);
2496 offset = -offset;
2497 u = 0;
2498 }
2499 int vd, d;
2500 dst.split_code(&vd, &d);
2501
2502 DCHECK_GE(offset, 0);
2503 if ((offset % 4) == 0 && (offset / 4) < 256) {
2504 emit(cond | 0xD*B24 | u*B23 | d*B22 | B20 | base.code()*B16 | vd*B12 |
2505 0xB*B8 | ((offset / 4) & 255));
2506 } else {
2507 UseScratchRegisterScope temps(this);
2508 Register scratch = temps.Acquire();
2509 // Larger offsets must be handled by computing the correct address in a
2510 // scratch register.
2511 DCHECK(base != scratch);
2512 if (u == 1) {
2513 add(scratch, base, Operand(offset));
2514 } else {
2515 sub(scratch, base, Operand(offset));
2516 }
2517 emit(cond | 0xD * B24 | d * B22 | B20 | scratch.code() * B16 | vd * B12 |
2518 0xB * B8);
2519 }
2520 }
2521
2522
vldr(const DwVfpRegister dst,const MemOperand & operand,const Condition cond)2523 void Assembler::vldr(const DwVfpRegister dst,
2524 const MemOperand& operand,
2525 const Condition cond) {
2526 DCHECK(VfpRegisterIsAvailable(dst));
2527 DCHECK(operand.am_ == Offset);
2528 if (operand.rm().is_valid()) {
2529 UseScratchRegisterScope temps(this);
2530 Register scratch = temps.Acquire();
2531 add(scratch, operand.rn(),
2532 Operand(operand.rm(), operand.shift_op_, operand.shift_imm_));
2533 vldr(dst, scratch, 0, cond);
2534 } else {
2535 vldr(dst, operand.rn(), operand.offset(), cond);
2536 }
2537 }
2538
2539
vldr(const SwVfpRegister dst,const Register base,int offset,const Condition cond)2540 void Assembler::vldr(const SwVfpRegister dst,
2541 const Register base,
2542 int offset,
2543 const Condition cond) {
2544 // Sdst = MEM(Rbase + offset).
2545 // Instruction details available in ARM DDI 0406A, A8-628.
2546 // cond(31-28) | 1101(27-24)| U001(23-20) | Rbase(19-16) |
2547 // Vdst(15-12) | 1010(11-8) | offset
2548 int u = 1;
2549 if (offset < 0) {
2550 offset = -offset;
2551 u = 0;
2552 }
2553 int sd, d;
2554 dst.split_code(&sd, &d);
2555 DCHECK_GE(offset, 0);
2556
2557 if ((offset % 4) == 0 && (offset / 4) < 256) {
2558 emit(cond | u*B23 | d*B22 | 0xD1*B20 | base.code()*B16 | sd*B12 |
2559 0xA*B8 | ((offset / 4) & 255));
2560 } else {
2561 // Larger offsets must be handled by computing the correct address in a
2562 // scratch register.
2563 UseScratchRegisterScope temps(this);
2564 Register scratch = temps.Acquire();
2565 DCHECK(base != scratch);
2566 if (u == 1) {
2567 add(scratch, base, Operand(offset));
2568 } else {
2569 sub(scratch, base, Operand(offset));
2570 }
2571 emit(cond | d * B22 | 0xD1 * B20 | scratch.code() * B16 | sd * B12 |
2572 0xA * B8);
2573 }
2574 }
2575
2576
vldr(const SwVfpRegister dst,const MemOperand & operand,const Condition cond)2577 void Assembler::vldr(const SwVfpRegister dst,
2578 const MemOperand& operand,
2579 const Condition cond) {
2580 DCHECK(operand.am_ == Offset);
2581 if (operand.rm().is_valid()) {
2582 UseScratchRegisterScope temps(this);
2583 Register scratch = temps.Acquire();
2584 add(scratch, operand.rn(),
2585 Operand(operand.rm(), operand.shift_op_, operand.shift_imm_));
2586 vldr(dst, scratch, 0, cond);
2587 } else {
2588 vldr(dst, operand.rn(), operand.offset(), cond);
2589 }
2590 }
2591
2592
vstr(const DwVfpRegister src,const Register base,int offset,const Condition cond)2593 void Assembler::vstr(const DwVfpRegister src,
2594 const Register base,
2595 int offset,
2596 const Condition cond) {
2597 // MEM(Rbase + offset) = Dsrc.
2598 // Instruction details available in ARM DDI 0406C.b, A8-1082.
2599 // cond(31-28) | 1101(27-24)| U(23) | D(22) | 00(21-20) | Rbase(19-16) |
2600 // Vd(15-12) | 1011(11-8) | (offset/4)
2601 DCHECK(VfpRegisterIsAvailable(src));
2602 int u = 1;
2603 if (offset < 0) {
2604 CHECK_NE(offset, kMinInt);
2605 offset = -offset;
2606 u = 0;
2607 }
2608 DCHECK_GE(offset, 0);
2609 int vd, d;
2610 src.split_code(&vd, &d);
2611
2612 if ((offset % 4) == 0 && (offset / 4) < 256) {
2613 emit(cond | 0xD*B24 | u*B23 | d*B22 | base.code()*B16 | vd*B12 | 0xB*B8 |
2614 ((offset / 4) & 255));
2615 } else {
2616 // Larger offsets must be handled by computing the correct address in the a
2617 // scratch register.
2618 UseScratchRegisterScope temps(this);
2619 Register scratch = temps.Acquire();
2620 DCHECK(base != scratch);
2621 if (u == 1) {
2622 add(scratch, base, Operand(offset));
2623 } else {
2624 sub(scratch, base, Operand(offset));
2625 }
2626 emit(cond | 0xD * B24 | d * B22 | scratch.code() * B16 | vd * B12 |
2627 0xB * B8);
2628 }
2629 }
2630
2631
vstr(const DwVfpRegister src,const MemOperand & operand,const Condition cond)2632 void Assembler::vstr(const DwVfpRegister src,
2633 const MemOperand& operand,
2634 const Condition cond) {
2635 DCHECK(VfpRegisterIsAvailable(src));
2636 DCHECK(operand.am_ == Offset);
2637 if (operand.rm().is_valid()) {
2638 UseScratchRegisterScope temps(this);
2639 Register scratch = temps.Acquire();
2640 add(scratch, operand.rn(),
2641 Operand(operand.rm(), operand.shift_op_, operand.shift_imm_));
2642 vstr(src, scratch, 0, cond);
2643 } else {
2644 vstr(src, operand.rn(), operand.offset(), cond);
2645 }
2646 }
2647
2648
vstr(const SwVfpRegister src,const Register base,int offset,const Condition cond)2649 void Assembler::vstr(const SwVfpRegister src,
2650 const Register base,
2651 int offset,
2652 const Condition cond) {
2653 // MEM(Rbase + offset) = SSrc.
2654 // Instruction details available in ARM DDI 0406A, A8-786.
2655 // cond(31-28) | 1101(27-24)| U000(23-20) | Rbase(19-16) |
2656 // Vdst(15-12) | 1010(11-8) | (offset/4)
2657 int u = 1;
2658 if (offset < 0) {
2659 CHECK_NE(offset, kMinInt);
2660 offset = -offset;
2661 u = 0;
2662 }
2663 int sd, d;
2664 src.split_code(&sd, &d);
2665 DCHECK_GE(offset, 0);
2666 if ((offset % 4) == 0 && (offset / 4) < 256) {
2667 emit(cond | u*B23 | d*B22 | 0xD0*B20 | base.code()*B16 | sd*B12 |
2668 0xA*B8 | ((offset / 4) & 255));
2669 } else {
2670 // Larger offsets must be handled by computing the correct address in a
2671 // scratch register.
2672 UseScratchRegisterScope temps(this);
2673 Register scratch = temps.Acquire();
2674 DCHECK(base != scratch);
2675 if (u == 1) {
2676 add(scratch, base, Operand(offset));
2677 } else {
2678 sub(scratch, base, Operand(offset));
2679 }
2680 emit(cond | d * B22 | 0xD0 * B20 | scratch.code() * B16 | sd * B12 |
2681 0xA * B8);
2682 }
2683 }
2684
2685
vstr(const SwVfpRegister src,const MemOperand & operand,const Condition cond)2686 void Assembler::vstr(const SwVfpRegister src,
2687 const MemOperand& operand,
2688 const Condition cond) {
2689 DCHECK(operand.am_ == Offset);
2690 if (operand.rm().is_valid()) {
2691 UseScratchRegisterScope temps(this);
2692 Register scratch = temps.Acquire();
2693 add(scratch, operand.rn(),
2694 Operand(operand.rm(), operand.shift_op_, operand.shift_imm_));
2695 vstr(src, scratch, 0, cond);
2696 } else {
2697 vstr(src, operand.rn(), operand.offset(), cond);
2698 }
2699 }
2700
vldm(BlockAddrMode am,Register base,DwVfpRegister first,DwVfpRegister last,Condition cond)2701 void Assembler::vldm(BlockAddrMode am, Register base, DwVfpRegister first,
2702 DwVfpRegister last, Condition cond) {
2703 // Instruction details available in ARM DDI 0406C.b, A8-922.
2704 // cond(31-28) | 110(27-25)| PUDW1(24-20) | Rbase(19-16) |
2705 // first(15-12) | 1011(11-8) | (count * 2)
2706 DCHECK_LE(first.code(), last.code());
2707 DCHECK(VfpRegisterIsAvailable(last));
2708 DCHECK(am == ia || am == ia_w || am == db_w);
2709 DCHECK(base != pc);
2710
2711 int sd, d;
2712 first.split_code(&sd, &d);
2713 int count = last.code() - first.code() + 1;
2714 DCHECK_LE(count, 16);
2715 emit(cond | B27 | B26 | am | d*B22 | B20 | base.code()*B16 | sd*B12 |
2716 0xB*B8 | count*2);
2717 }
2718
vstm(BlockAddrMode am,Register base,DwVfpRegister first,DwVfpRegister last,Condition cond)2719 void Assembler::vstm(BlockAddrMode am, Register base, DwVfpRegister first,
2720 DwVfpRegister last, Condition cond) {
2721 // Instruction details available in ARM DDI 0406C.b, A8-1080.
2722 // cond(31-28) | 110(27-25)| PUDW0(24-20) | Rbase(19-16) |
2723 // first(15-12) | 1011(11-8) | (count * 2)
2724 DCHECK_LE(first.code(), last.code());
2725 DCHECK(VfpRegisterIsAvailable(last));
2726 DCHECK(am == ia || am == ia_w || am == db_w);
2727 DCHECK(base != pc);
2728
2729 int sd, d;
2730 first.split_code(&sd, &d);
2731 int count = last.code() - first.code() + 1;
2732 DCHECK_LE(count, 16);
2733 emit(cond | B27 | B26 | am | d*B22 | base.code()*B16 | sd*B12 |
2734 0xB*B8 | count*2);
2735 }
2736
vldm(BlockAddrMode am,Register base,SwVfpRegister first,SwVfpRegister last,Condition cond)2737 void Assembler::vldm(BlockAddrMode am, Register base, SwVfpRegister first,
2738 SwVfpRegister last, Condition cond) {
2739 // Instruction details available in ARM DDI 0406A, A8-626.
2740 // cond(31-28) | 110(27-25)| PUDW1(24-20) | Rbase(19-16) |
2741 // first(15-12) | 1010(11-8) | (count/2)
2742 DCHECK_LE(first.code(), last.code());
2743 DCHECK(am == ia || am == ia_w || am == db_w);
2744 DCHECK(base != pc);
2745
2746 int sd, d;
2747 first.split_code(&sd, &d);
2748 int count = last.code() - first.code() + 1;
2749 emit(cond | B27 | B26 | am | d*B22 | B20 | base.code()*B16 | sd*B12 |
2750 0xA*B8 | count);
2751 }
2752
vstm(BlockAddrMode am,Register base,SwVfpRegister first,SwVfpRegister last,Condition cond)2753 void Assembler::vstm(BlockAddrMode am, Register base, SwVfpRegister first,
2754 SwVfpRegister last, Condition cond) {
2755 // Instruction details available in ARM DDI 0406A, A8-784.
2756 // cond(31-28) | 110(27-25)| PUDW0(24-20) | Rbase(19-16) |
2757 // first(15-12) | 1011(11-8) | (count/2)
2758 DCHECK_LE(first.code(), last.code());
2759 DCHECK(am == ia || am == ia_w || am == db_w);
2760 DCHECK(base != pc);
2761
2762 int sd, d;
2763 first.split_code(&sd, &d);
2764 int count = last.code() - first.code() + 1;
2765 emit(cond | B27 | B26 | am | d*B22 | base.code()*B16 | sd*B12 |
2766 0xA*B8 | count);
2767 }
2768
DoubleAsTwoUInt32(Double d,uint32_t * lo,uint32_t * hi)2769 static void DoubleAsTwoUInt32(Double d, uint32_t* lo, uint32_t* hi) {
2770 uint64_t i = d.AsUint64();
2771
2772 *lo = i & 0xFFFFFFFF;
2773 *hi = i >> 32;
2774 }
2775
2776 // Only works for little endian floating point formats.
2777 // We don't support VFP on the mixed endian floating point platform.
FitsVmovFPImmediate(Double d,uint32_t * encoding)2778 static bool FitsVmovFPImmediate(Double d, uint32_t* encoding) {
2779 // VMOV can accept an immediate of the form:
2780 //
2781 // +/- m * 2^(-n) where 16 <= m <= 31 and 0 <= n <= 7
2782 //
2783 // The immediate is encoded using an 8-bit quantity, comprised of two
2784 // 4-bit fields. For an 8-bit immediate of the form:
2785 //
2786 // [abcdefgh]
2787 //
2788 // where a is the MSB and h is the LSB, an immediate 64-bit double can be
2789 // created of the form:
2790 //
2791 // [aBbbbbbb,bbcdefgh,00000000,00000000,
2792 // 00000000,00000000,00000000,00000000]
2793 //
2794 // where B = ~b.
2795 //
2796
2797 uint32_t lo, hi;
2798 DoubleAsTwoUInt32(d, &lo, &hi);
2799
2800 // The most obvious constraint is the long block of zeroes.
2801 if ((lo != 0) || ((hi & 0xFFFF) != 0)) {
2802 return false;
2803 }
2804
2805 // Bits 61:54 must be all clear or all set.
2806 if (((hi & 0x3FC00000) != 0) && ((hi & 0x3FC00000) != 0x3FC00000)) {
2807 return false;
2808 }
2809
2810 // Bit 62 must be NOT bit 61.
2811 if (((hi ^ (hi << 1)) & (0x40000000)) == 0) {
2812 return false;
2813 }
2814
2815 // Create the encoded immediate in the form:
2816 // [00000000,0000abcd,00000000,0000efgh]
2817 *encoding = (hi >> 16) & 0xF; // Low nybble.
2818 *encoding |= (hi >> 4) & 0x70000; // Low three bits of the high nybble.
2819 *encoding |= (hi >> 12) & 0x80000; // Top bit of the high nybble.
2820
2821 return true;
2822 }
2823
vmov(const SwVfpRegister dst,Float32 imm)2824 void Assembler::vmov(const SwVfpRegister dst, Float32 imm) {
2825 uint32_t enc;
2826 if (CpuFeatures::IsSupported(VFPv3) &&
2827 FitsVmovFPImmediate(Double(imm.get_scalar()), &enc)) {
2828 CpuFeatureScope scope(this, VFPv3);
2829 // The float can be encoded in the instruction.
2830 //
2831 // Sd = immediate
2832 // Instruction details available in ARM DDI 0406C.b, A8-936.
2833 // cond(31-28) | 11101(27-23) | D(22) | 11(21-20) | imm4H(19-16) |
2834 // Vd(15-12) | 101(11-9) | sz=0(8) | imm4L(3-0)
2835 int vd, d;
2836 dst.split_code(&vd, &d);
2837 emit(al | 0x1D * B23 | d * B22 | 0x3 * B20 | vd * B12 | 0x5 * B9 | enc);
2838 } else {
2839 UseScratchRegisterScope temps(this);
2840 Register scratch = temps.Acquire();
2841 mov(scratch, Operand(imm.get_bits()));
2842 vmov(dst, scratch);
2843 }
2844 }
2845
vmov(const DwVfpRegister dst,Double imm,const Register extra_scratch)2846 void Assembler::vmov(const DwVfpRegister dst, Double imm,
2847 const Register extra_scratch) {
2848 DCHECK(VfpRegisterIsAvailable(dst));
2849 uint32_t enc;
2850 if (CpuFeatures::IsSupported(VFPv3) && FitsVmovFPImmediate(imm, &enc)) {
2851 CpuFeatureScope scope(this, VFPv3);
2852 // The double can be encoded in the instruction.
2853 //
2854 // Dd = immediate
2855 // Instruction details available in ARM DDI 0406C.b, A8-936.
2856 // cond(31-28) | 11101(27-23) | D(22) | 11(21-20) | imm4H(19-16) |
2857 // Vd(15-12) | 101(11-9) | sz=1(8) | imm4L(3-0)
2858 int vd, d;
2859 dst.split_code(&vd, &d);
2860 emit(al | 0x1D*B23 | d*B22 | 0x3*B20 | vd*B12 | 0x5*B9 | B8 | enc);
2861 } else {
2862 // Synthesise the double from ARM immediates.
2863 uint32_t lo, hi;
2864 DoubleAsTwoUInt32(imm, &lo, &hi);
2865 UseScratchRegisterScope temps(this);
2866 Register scratch = temps.Acquire();
2867
2868 if (lo == hi) {
2869 // Move the low and high parts of the double to a D register in one
2870 // instruction.
2871 mov(scratch, Operand(lo));
2872 vmov(dst, scratch, scratch);
2873 } else if (extra_scratch == no_reg) {
2874 // We only have one spare scratch register.
2875 mov(scratch, Operand(lo));
2876 vmov(NeonS32, dst, 0, scratch);
2877 if (((lo & 0xFFFF) == (hi & 0xFFFF)) && CpuFeatures::IsSupported(ARMv7)) {
2878 CpuFeatureScope scope(this, ARMv7);
2879 movt(scratch, hi >> 16);
2880 } else {
2881 mov(scratch, Operand(hi));
2882 }
2883 vmov(NeonS32, dst, 1, scratch);
2884 } else {
2885 // Move the low and high parts of the double to a D register in one
2886 // instruction.
2887 mov(scratch, Operand(lo));
2888 mov(extra_scratch, Operand(hi));
2889 vmov(dst, scratch, extra_scratch);
2890 }
2891 }
2892 }
2893
vmov(const SwVfpRegister dst,const SwVfpRegister src,const Condition cond)2894 void Assembler::vmov(const SwVfpRegister dst,
2895 const SwVfpRegister src,
2896 const Condition cond) {
2897 // Sd = Sm
2898 // Instruction details available in ARM DDI 0406B, A8-642.
2899 int sd, d, sm, m;
2900 dst.split_code(&sd, &d);
2901 src.split_code(&sm, &m);
2902 emit(cond | 0xE*B24 | d*B22 | 0xB*B20 | sd*B12 | 0xA*B8 | B6 | m*B5 | sm);
2903 }
2904
2905
vmov(const DwVfpRegister dst,const DwVfpRegister src,const Condition cond)2906 void Assembler::vmov(const DwVfpRegister dst,
2907 const DwVfpRegister src,
2908 const Condition cond) {
2909 // Dd = Dm
2910 // Instruction details available in ARM DDI 0406C.b, A8-938.
2911 // cond(31-28) | 11101(27-23) | D(22) | 11(21-20) | 0000(19-16) | Vd(15-12) |
2912 // 101(11-9) | sz=1(8) | 0(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
2913 DCHECK(VfpRegisterIsAvailable(dst));
2914 DCHECK(VfpRegisterIsAvailable(src));
2915 int vd, d;
2916 dst.split_code(&vd, &d);
2917 int vm, m;
2918 src.split_code(&vm, &m);
2919 emit(cond | 0x1D*B23 | d*B22 | 0x3*B20 | vd*B12 | 0x5*B9 | B8 | B6 | m*B5 |
2920 vm);
2921 }
2922
vmov(const DwVfpRegister dst,const Register src1,const Register src2,const Condition cond)2923 void Assembler::vmov(const DwVfpRegister dst,
2924 const Register src1,
2925 const Register src2,
2926 const Condition cond) {
2927 // Dm = <Rt,Rt2>.
2928 // Instruction details available in ARM DDI 0406C.b, A8-948.
2929 // cond(31-28) | 1100(27-24)| 010(23-21) | op=0(20) | Rt2(19-16) |
2930 // Rt(15-12) | 1011(11-8) | 00(7-6) | M(5) | 1(4) | Vm
2931 DCHECK(VfpRegisterIsAvailable(dst));
2932 DCHECK(src1 != pc && src2 != pc);
2933 int vm, m;
2934 dst.split_code(&vm, &m);
2935 emit(cond | 0xC*B24 | B22 | src2.code()*B16 |
2936 src1.code()*B12 | 0xB*B8 | m*B5 | B4 | vm);
2937 }
2938
2939
vmov(const Register dst1,const Register dst2,const DwVfpRegister src,const Condition cond)2940 void Assembler::vmov(const Register dst1,
2941 const Register dst2,
2942 const DwVfpRegister src,
2943 const Condition cond) {
2944 // <Rt,Rt2> = Dm.
2945 // Instruction details available in ARM DDI 0406C.b, A8-948.
2946 // cond(31-28) | 1100(27-24)| 010(23-21) | op=1(20) | Rt2(19-16) |
2947 // Rt(15-12) | 1011(11-8) | 00(7-6) | M(5) | 1(4) | Vm
2948 DCHECK(VfpRegisterIsAvailable(src));
2949 DCHECK(dst1 != pc && dst2 != pc);
2950 int vm, m;
2951 src.split_code(&vm, &m);
2952 emit(cond | 0xC*B24 | B22 | B20 | dst2.code()*B16 |
2953 dst1.code()*B12 | 0xB*B8 | m*B5 | B4 | vm);
2954 }
2955
2956
vmov(const SwVfpRegister dst,const Register src,const Condition cond)2957 void Assembler::vmov(const SwVfpRegister dst,
2958 const Register src,
2959 const Condition cond) {
2960 // Sn = Rt.
2961 // Instruction details available in ARM DDI 0406A, A8-642.
2962 // cond(31-28) | 1110(27-24)| 000(23-21) | op=0(20) | Vn(19-16) |
2963 // Rt(15-12) | 1010(11-8) | N(7)=0 | 00(6-5) | 1(4) | 0000(3-0)
2964 DCHECK(src != pc);
2965 int sn, n;
2966 dst.split_code(&sn, &n);
2967 emit(cond | 0xE*B24 | sn*B16 | src.code()*B12 | 0xA*B8 | n*B7 | B4);
2968 }
2969
2970
vmov(const Register dst,const SwVfpRegister src,const Condition cond)2971 void Assembler::vmov(const Register dst,
2972 const SwVfpRegister src,
2973 const Condition cond) {
2974 // Rt = Sn.
2975 // Instruction details available in ARM DDI 0406A, A8-642.
2976 // cond(31-28) | 1110(27-24)| 000(23-21) | op=1(20) | Vn(19-16) |
2977 // Rt(15-12) | 1010(11-8) | N(7)=0 | 00(6-5) | 1(4) | 0000(3-0)
2978 DCHECK(dst != pc);
2979 int sn, n;
2980 src.split_code(&sn, &n);
2981 emit(cond | 0xE*B24 | B20 | sn*B16 | dst.code()*B12 | 0xA*B8 | n*B7 | B4);
2982 }
2983
2984 // Type of data to read from or write to VFP register.
2985 // Used as specifier in generic vcvt instruction.
2986 enum VFPType { S32, U32, F32, F64 };
2987
2988
IsSignedVFPType(VFPType type)2989 static bool IsSignedVFPType(VFPType type) {
2990 switch (type) {
2991 case S32:
2992 return true;
2993 case U32:
2994 return false;
2995 default:
2996 UNREACHABLE();
2997 }
2998 }
2999
3000
IsIntegerVFPType(VFPType type)3001 static bool IsIntegerVFPType(VFPType type) {
3002 switch (type) {
3003 case S32:
3004 case U32:
3005 return true;
3006 case F32:
3007 case F64:
3008 return false;
3009 default:
3010 UNREACHABLE();
3011 }
3012 }
3013
3014
IsDoubleVFPType(VFPType type)3015 static bool IsDoubleVFPType(VFPType type) {
3016 switch (type) {
3017 case F32:
3018 return false;
3019 case F64:
3020 return true;
3021 default:
3022 UNREACHABLE();
3023 }
3024 }
3025
3026
3027 // Split five bit reg_code based on size of reg_type.
3028 // 32-bit register codes are Vm:M
3029 // 64-bit register codes are M:Vm
3030 // where Vm is four bits, and M is a single bit.
SplitRegCode(VFPType reg_type,int reg_code,int * vm,int * m)3031 static void SplitRegCode(VFPType reg_type,
3032 int reg_code,
3033 int* vm,
3034 int* m) {
3035 DCHECK((reg_code >= 0) && (reg_code <= 31));
3036 if (IsIntegerVFPType(reg_type) || !IsDoubleVFPType(reg_type)) {
3037 SwVfpRegister::split_code(reg_code, vm, m);
3038 } else {
3039 DwVfpRegister::split_code(reg_code, vm, m);
3040 }
3041 }
3042
3043
3044 // 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)3045 static Instr EncodeVCVT(const VFPType dst_type,
3046 const int dst_code,
3047 const VFPType src_type,
3048 const int src_code,
3049 VFPConversionMode mode,
3050 const Condition cond) {
3051 DCHECK(src_type != dst_type);
3052 int D, Vd, M, Vm;
3053 SplitRegCode(src_type, src_code, &Vm, &M);
3054 SplitRegCode(dst_type, dst_code, &Vd, &D);
3055
3056 if (IsIntegerVFPType(dst_type) || IsIntegerVFPType(src_type)) {
3057 // Conversion between IEEE floating point and 32-bit integer.
3058 // Instruction details available in ARM DDI 0406B, A8.6.295.
3059 // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 1(19) | opc2(18-16) |
3060 // Vd(15-12) | 101(11-9) | sz(8) | op(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
3061 DCHECK(!IsIntegerVFPType(dst_type) || !IsIntegerVFPType(src_type));
3062
3063 int sz, opc2, op;
3064
3065 if (IsIntegerVFPType(dst_type)) {
3066 opc2 = IsSignedVFPType(dst_type) ? 0x5 : 0x4;
3067 sz = IsDoubleVFPType(src_type) ? 0x1 : 0x0;
3068 op = mode;
3069 } else {
3070 DCHECK(IsIntegerVFPType(src_type));
3071 opc2 = 0x0;
3072 sz = IsDoubleVFPType(dst_type) ? 0x1 : 0x0;
3073 op = IsSignedVFPType(src_type) ? 0x1 : 0x0;
3074 }
3075
3076 return (cond | 0xE*B24 | B23 | D*B22 | 0x3*B20 | B19 | opc2*B16 |
3077 Vd*B12 | 0x5*B9 | sz*B8 | op*B7 | B6 | M*B5 | Vm);
3078 } else {
3079 // Conversion between IEEE double and single precision.
3080 // Instruction details available in ARM DDI 0406B, A8.6.298.
3081 // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 0111(19-16) |
3082 // Vd(15-12) | 101(11-9) | sz(8) | 1(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
3083 int sz = IsDoubleVFPType(src_type) ? 0x1 : 0x0;
3084 return (cond | 0xE*B24 | B23 | D*B22 | 0x3*B20 | 0x7*B16 |
3085 Vd*B12 | 0x5*B9 | sz*B8 | B7 | B6 | M*B5 | Vm);
3086 }
3087 }
3088
3089
vcvt_f64_s32(const DwVfpRegister dst,const SwVfpRegister src,VFPConversionMode mode,const Condition cond)3090 void Assembler::vcvt_f64_s32(const DwVfpRegister dst,
3091 const SwVfpRegister src,
3092 VFPConversionMode mode,
3093 const Condition cond) {
3094 DCHECK(VfpRegisterIsAvailable(dst));
3095 emit(EncodeVCVT(F64, dst.code(), S32, src.code(), mode, cond));
3096 }
3097
3098
vcvt_f32_s32(const SwVfpRegister dst,const SwVfpRegister src,VFPConversionMode mode,const Condition cond)3099 void Assembler::vcvt_f32_s32(const SwVfpRegister dst,
3100 const SwVfpRegister src,
3101 VFPConversionMode mode,
3102 const Condition cond) {
3103 emit(EncodeVCVT(F32, dst.code(), S32, src.code(), mode, cond));
3104 }
3105
3106
vcvt_f64_u32(const DwVfpRegister dst,const SwVfpRegister src,VFPConversionMode mode,const Condition cond)3107 void Assembler::vcvt_f64_u32(const DwVfpRegister dst,
3108 const SwVfpRegister src,
3109 VFPConversionMode mode,
3110 const Condition cond) {
3111 DCHECK(VfpRegisterIsAvailable(dst));
3112 emit(EncodeVCVT(F64, dst.code(), U32, src.code(), mode, cond));
3113 }
3114
3115
vcvt_f32_u32(const SwVfpRegister dst,const SwVfpRegister src,VFPConversionMode mode,const Condition cond)3116 void Assembler::vcvt_f32_u32(const SwVfpRegister dst, const SwVfpRegister src,
3117 VFPConversionMode mode, const Condition cond) {
3118 emit(EncodeVCVT(F32, dst.code(), U32, src.code(), mode, cond));
3119 }
3120
3121
vcvt_s32_f32(const SwVfpRegister dst,const SwVfpRegister src,VFPConversionMode mode,const Condition cond)3122 void Assembler::vcvt_s32_f32(const SwVfpRegister dst, const SwVfpRegister src,
3123 VFPConversionMode mode, const Condition cond) {
3124 emit(EncodeVCVT(S32, dst.code(), F32, src.code(), mode, cond));
3125 }
3126
3127
vcvt_u32_f32(const SwVfpRegister dst,const SwVfpRegister src,VFPConversionMode mode,const Condition cond)3128 void Assembler::vcvt_u32_f32(const SwVfpRegister dst, const SwVfpRegister src,
3129 VFPConversionMode mode, const Condition cond) {
3130 emit(EncodeVCVT(U32, dst.code(), F32, src.code(), mode, cond));
3131 }
3132
3133
vcvt_s32_f64(const SwVfpRegister dst,const DwVfpRegister src,VFPConversionMode mode,const Condition cond)3134 void Assembler::vcvt_s32_f64(const SwVfpRegister dst,
3135 const DwVfpRegister src,
3136 VFPConversionMode mode,
3137 const Condition cond) {
3138 DCHECK(VfpRegisterIsAvailable(src));
3139 emit(EncodeVCVT(S32, dst.code(), F64, src.code(), mode, cond));
3140 }
3141
3142
vcvt_u32_f64(const SwVfpRegister dst,const DwVfpRegister src,VFPConversionMode mode,const Condition cond)3143 void Assembler::vcvt_u32_f64(const SwVfpRegister dst,
3144 const DwVfpRegister src,
3145 VFPConversionMode mode,
3146 const Condition cond) {
3147 DCHECK(VfpRegisterIsAvailable(src));
3148 emit(EncodeVCVT(U32, dst.code(), F64, src.code(), mode, cond));
3149 }
3150
3151
vcvt_f64_f32(const DwVfpRegister dst,const SwVfpRegister src,VFPConversionMode mode,const Condition cond)3152 void Assembler::vcvt_f64_f32(const DwVfpRegister dst,
3153 const SwVfpRegister src,
3154 VFPConversionMode mode,
3155 const Condition cond) {
3156 DCHECK(VfpRegisterIsAvailable(dst));
3157 emit(EncodeVCVT(F64, dst.code(), F32, src.code(), mode, cond));
3158 }
3159
3160
vcvt_f32_f64(const SwVfpRegister dst,const DwVfpRegister src,VFPConversionMode mode,const Condition cond)3161 void Assembler::vcvt_f32_f64(const SwVfpRegister dst,
3162 const DwVfpRegister src,
3163 VFPConversionMode mode,
3164 const Condition cond) {
3165 DCHECK(VfpRegisterIsAvailable(src));
3166 emit(EncodeVCVT(F32, dst.code(), F64, src.code(), mode, cond));
3167 }
3168
3169
vcvt_f64_s32(const DwVfpRegister dst,int fraction_bits,const Condition cond)3170 void Assembler::vcvt_f64_s32(const DwVfpRegister dst,
3171 int fraction_bits,
3172 const Condition cond) {
3173 // Instruction details available in ARM DDI 0406C.b, A8-874.
3174 // cond(31-28) | 11101(27-23) | D(22) | 11(21-20) | 1010(19-16) | Vd(15-12) |
3175 // 101(11-9) | sf=1(8) | sx=1(7) | 1(6) | i(5) | 0(4) | imm4(3-0)
3176 DCHECK(IsEnabled(VFPv3));
3177 DCHECK(VfpRegisterIsAvailable(dst));
3178 DCHECK(fraction_bits > 0 && fraction_bits <= 32);
3179 int vd, d;
3180 dst.split_code(&vd, &d);
3181 int imm5 = 32 - fraction_bits;
3182 int i = imm5 & 1;
3183 int imm4 = (imm5 >> 1) & 0xF;
3184 emit(cond | 0xE*B24 | B23 | d*B22 | 0x3*B20 | B19 | 0x2*B16 |
3185 vd*B12 | 0x5*B9 | B8 | B7 | B6 | i*B5 | imm4);
3186 }
3187
3188
vneg(const DwVfpRegister dst,const DwVfpRegister src,const Condition cond)3189 void Assembler::vneg(const DwVfpRegister dst,
3190 const DwVfpRegister src,
3191 const Condition cond) {
3192 // Instruction details available in ARM DDI 0406C.b, A8-968.
3193 // cond(31-28) | 11101(27-23) | D(22) | 11(21-20) | 0001(19-16) | Vd(15-12) |
3194 // 101(11-9) | sz=1(8) | 0(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
3195 DCHECK(VfpRegisterIsAvailable(dst));
3196 DCHECK(VfpRegisterIsAvailable(src));
3197 int vd, d;
3198 dst.split_code(&vd, &d);
3199 int vm, m;
3200 src.split_code(&vm, &m);
3201
3202 emit(cond | 0x1D*B23 | d*B22 | 0x3*B20 | B16 | vd*B12 | 0x5*B9 | B8 | B6 |
3203 m*B5 | vm);
3204 }
3205
3206
vneg(const SwVfpRegister dst,const SwVfpRegister src,const Condition cond)3207 void Assembler::vneg(const SwVfpRegister dst, const SwVfpRegister src,
3208 const Condition cond) {
3209 // Instruction details available in ARM DDI 0406C.b, A8-968.
3210 // cond(31-28) | 11101(27-23) | D(22) | 11(21-20) | 0001(19-16) | Vd(15-12) |
3211 // 101(11-9) | sz=0(8) | 0(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
3212 int vd, d;
3213 dst.split_code(&vd, &d);
3214 int vm, m;
3215 src.split_code(&vm, &m);
3216
3217 emit(cond | 0x1D * B23 | d * B22 | 0x3 * B20 | B16 | vd * B12 | 0x5 * B9 |
3218 B6 | m * B5 | vm);
3219 }
3220
3221
vabs(const DwVfpRegister dst,const DwVfpRegister src,const Condition cond)3222 void Assembler::vabs(const DwVfpRegister dst,
3223 const DwVfpRegister src,
3224 const Condition cond) {
3225 // Instruction details available in ARM DDI 0406C.b, A8-524.
3226 // cond(31-28) | 11101(27-23) | D(22) | 11(21-20) | 0000(19-16) | Vd(15-12) |
3227 // 101(11-9) | sz=1(8) | 1(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
3228 DCHECK(VfpRegisterIsAvailable(dst));
3229 DCHECK(VfpRegisterIsAvailable(src));
3230 int vd, d;
3231 dst.split_code(&vd, &d);
3232 int vm, m;
3233 src.split_code(&vm, &m);
3234 emit(cond | 0x1D*B23 | d*B22 | 0x3*B20 | vd*B12 | 0x5*B9 | B8 | B7 | B6 |
3235 m*B5 | vm);
3236 }
3237
3238
vabs(const SwVfpRegister dst,const SwVfpRegister src,const Condition cond)3239 void Assembler::vabs(const SwVfpRegister dst, const SwVfpRegister src,
3240 const Condition cond) {
3241 // Instruction details available in ARM DDI 0406C.b, A8-524.
3242 // cond(31-28) | 11101(27-23) | D(22) | 11(21-20) | 0000(19-16) | Vd(15-12) |
3243 // 101(11-9) | sz=0(8) | 1(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
3244 int vd, d;
3245 dst.split_code(&vd, &d);
3246 int vm, m;
3247 src.split_code(&vm, &m);
3248 emit(cond | 0x1D * B23 | d * B22 | 0x3 * B20 | vd * B12 | 0x5 * B9 | B7 | B6 |
3249 m * B5 | vm);
3250 }
3251
3252
vadd(const DwVfpRegister dst,const DwVfpRegister src1,const DwVfpRegister src2,const Condition cond)3253 void Assembler::vadd(const DwVfpRegister dst,
3254 const DwVfpRegister src1,
3255 const DwVfpRegister src2,
3256 const Condition cond) {
3257 // Dd = vadd(Dn, Dm) double precision floating point addition.
3258 // Dd = D:Vd; Dm=M:Vm; Dn=N:Vm.
3259 // Instruction details available in ARM DDI 0406C.b, A8-830.
3260 // cond(31-28) | 11100(27-23)| D(22) | 11(21-20) | Vn(19-16) |
3261 // Vd(15-12) | 101(11-9) | sz=1(8) | N(7) | 0(6) | M(5) | 0(4) | Vm(3-0)
3262 DCHECK(VfpRegisterIsAvailable(dst));
3263 DCHECK(VfpRegisterIsAvailable(src1));
3264 DCHECK(VfpRegisterIsAvailable(src2));
3265 int vd, d;
3266 dst.split_code(&vd, &d);
3267 int vn, n;
3268 src1.split_code(&vn, &n);
3269 int vm, m;
3270 src2.split_code(&vm, &m);
3271 emit(cond | 0x1C*B23 | d*B22 | 0x3*B20 | vn*B16 | vd*B12 | 0x5*B9 | B8 |
3272 n*B7 | m*B5 | vm);
3273 }
3274
3275
vadd(const SwVfpRegister dst,const SwVfpRegister src1,const SwVfpRegister src2,const Condition cond)3276 void Assembler::vadd(const SwVfpRegister dst, const SwVfpRegister src1,
3277 const SwVfpRegister src2, const Condition cond) {
3278 // Sd = vadd(Sn, Sm) single precision floating point addition.
3279 // Sd = D:Vd; Sm=M:Vm; Sn=N:Vm.
3280 // Instruction details available in ARM DDI 0406C.b, A8-830.
3281 // cond(31-28) | 11100(27-23)| D(22) | 11(21-20) | Vn(19-16) |
3282 // Vd(15-12) | 101(11-9) | sz=0(8) | N(7) | 0(6) | M(5) | 0(4) | Vm(3-0)
3283 int vd, d;
3284 dst.split_code(&vd, &d);
3285 int vn, n;
3286 src1.split_code(&vn, &n);
3287 int vm, m;
3288 src2.split_code(&vm, &m);
3289 emit(cond | 0x1C * B23 | d * B22 | 0x3 * B20 | vn * B16 | vd * B12 |
3290 0x5 * B9 | n * B7 | m * B5 | vm);
3291 }
3292
3293
vsub(const DwVfpRegister dst,const DwVfpRegister src1,const DwVfpRegister src2,const Condition cond)3294 void Assembler::vsub(const DwVfpRegister dst,
3295 const DwVfpRegister src1,
3296 const DwVfpRegister src2,
3297 const Condition cond) {
3298 // Dd = vsub(Dn, Dm) double precision floating point subtraction.
3299 // Dd = D:Vd; Dm=M:Vm; Dn=N:Vm.
3300 // Instruction details available in ARM DDI 0406C.b, A8-1086.
3301 // cond(31-28) | 11100(27-23)| D(22) | 11(21-20) | Vn(19-16) |
3302 // Vd(15-12) | 101(11-9) | sz=1(8) | N(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
3303 DCHECK(VfpRegisterIsAvailable(dst));
3304 DCHECK(VfpRegisterIsAvailable(src1));
3305 DCHECK(VfpRegisterIsAvailable(src2));
3306 int vd, d;
3307 dst.split_code(&vd, &d);
3308 int vn, n;
3309 src1.split_code(&vn, &n);
3310 int vm, m;
3311 src2.split_code(&vm, &m);
3312 emit(cond | 0x1C*B23 | d*B22 | 0x3*B20 | vn*B16 | vd*B12 | 0x5*B9 | B8 |
3313 n*B7 | B6 | m*B5 | vm);
3314 }
3315
3316
vsub(const SwVfpRegister dst,const SwVfpRegister src1,const SwVfpRegister src2,const Condition cond)3317 void Assembler::vsub(const SwVfpRegister dst, const SwVfpRegister src1,
3318 const SwVfpRegister src2, const Condition cond) {
3319 // Sd = vsub(Sn, Sm) single precision floating point subtraction.
3320 // Sd = D:Vd; Sm=M:Vm; Sn=N:Vm.
3321 // Instruction details available in ARM DDI 0406C.b, A8-1086.
3322 // cond(31-28) | 11100(27-23)| D(22) | 11(21-20) | Vn(19-16) |
3323 // Vd(15-12) | 101(11-9) | sz=0(8) | N(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
3324 int vd, d;
3325 dst.split_code(&vd, &d);
3326 int vn, n;
3327 src1.split_code(&vn, &n);
3328 int vm, m;
3329 src2.split_code(&vm, &m);
3330 emit(cond | 0x1C * B23 | d * B22 | 0x3 * B20 | vn * B16 | vd * B12 |
3331 0x5 * B9 | n * B7 | B6 | m * B5 | vm);
3332 }
3333
3334
vmul(const DwVfpRegister dst,const DwVfpRegister src1,const DwVfpRegister src2,const Condition cond)3335 void Assembler::vmul(const DwVfpRegister dst,
3336 const DwVfpRegister src1,
3337 const DwVfpRegister src2,
3338 const Condition cond) {
3339 // Dd = vmul(Dn, Dm) double precision floating point multiplication.
3340 // Dd = D:Vd; Dm=M:Vm; Dn=N:Vm.
3341 // Instruction details available in ARM DDI 0406C.b, A8-960.
3342 // cond(31-28) | 11100(27-23)| D(22) | 10(21-20) | Vn(19-16) |
3343 // Vd(15-12) | 101(11-9) | sz=1(8) | N(7) | 0(6) | M(5) | 0(4) | Vm(3-0)
3344 DCHECK(VfpRegisterIsAvailable(dst));
3345 DCHECK(VfpRegisterIsAvailable(src1));
3346 DCHECK(VfpRegisterIsAvailable(src2));
3347 int vd, d;
3348 dst.split_code(&vd, &d);
3349 int vn, n;
3350 src1.split_code(&vn, &n);
3351 int vm, m;
3352 src2.split_code(&vm, &m);
3353 emit(cond | 0x1C*B23 | d*B22 | 0x2*B20 | vn*B16 | vd*B12 | 0x5*B9 | B8 |
3354 n*B7 | m*B5 | vm);
3355 }
3356
3357
vmul(const SwVfpRegister dst,const SwVfpRegister src1,const SwVfpRegister src2,const Condition cond)3358 void Assembler::vmul(const SwVfpRegister dst, const SwVfpRegister src1,
3359 const SwVfpRegister src2, const Condition cond) {
3360 // Sd = vmul(Sn, Sm) single precision floating point multiplication.
3361 // Sd = D:Vd; Sm=M:Vm; Sn=N:Vm.
3362 // Instruction details available in ARM DDI 0406C.b, A8-960.
3363 // cond(31-28) | 11100(27-23)| D(22) | 10(21-20) | Vn(19-16) |
3364 // Vd(15-12) | 101(11-9) | sz=0(8) | N(7) | 0(6) | M(5) | 0(4) | Vm(3-0)
3365 int vd, d;
3366 dst.split_code(&vd, &d);
3367 int vn, n;
3368 src1.split_code(&vn, &n);
3369 int vm, m;
3370 src2.split_code(&vm, &m);
3371 emit(cond | 0x1C * B23 | d * B22 | 0x2 * B20 | vn * B16 | vd * B12 |
3372 0x5 * B9 | n * B7 | m * B5 | vm);
3373 }
3374
3375
vmla(const DwVfpRegister dst,const DwVfpRegister src1,const DwVfpRegister src2,const Condition cond)3376 void Assembler::vmla(const DwVfpRegister dst,
3377 const DwVfpRegister src1,
3378 const DwVfpRegister src2,
3379 const Condition cond) {
3380 // Instruction details available in ARM DDI 0406C.b, A8-932.
3381 // cond(31-28) | 11100(27-23) | D(22) | 00(21-20) | Vn(19-16) |
3382 // Vd(15-12) | 101(11-9) | sz=1(8) | N(7) | op=0(6) | M(5) | 0(4) | Vm(3-0)
3383 DCHECK(VfpRegisterIsAvailable(dst));
3384 DCHECK(VfpRegisterIsAvailable(src1));
3385 DCHECK(VfpRegisterIsAvailable(src2));
3386 int vd, d;
3387 dst.split_code(&vd, &d);
3388 int vn, n;
3389 src1.split_code(&vn, &n);
3390 int vm, m;
3391 src2.split_code(&vm, &m);
3392 emit(cond | 0x1C*B23 | d*B22 | vn*B16 | vd*B12 | 0x5*B9 | B8 | n*B7 | m*B5 |
3393 vm);
3394 }
3395
3396
vmla(const SwVfpRegister dst,const SwVfpRegister src1,const SwVfpRegister src2,const Condition cond)3397 void Assembler::vmla(const SwVfpRegister dst, const SwVfpRegister src1,
3398 const SwVfpRegister src2, const Condition cond) {
3399 // Instruction details available in ARM DDI 0406C.b, A8-932.
3400 // cond(31-28) | 11100(27-23) | D(22) | 00(21-20) | Vn(19-16) |
3401 // Vd(15-12) | 101(11-9) | sz=0(8) | N(7) | op=0(6) | M(5) | 0(4) | Vm(3-0)
3402 int vd, d;
3403 dst.split_code(&vd, &d);
3404 int vn, n;
3405 src1.split_code(&vn, &n);
3406 int vm, m;
3407 src2.split_code(&vm, &m);
3408 emit(cond | 0x1C * B23 | d * B22 | vn * B16 | vd * B12 | 0x5 * B9 | n * B7 |
3409 m * B5 | vm);
3410 }
3411
3412
vmls(const DwVfpRegister dst,const DwVfpRegister src1,const DwVfpRegister src2,const Condition cond)3413 void Assembler::vmls(const DwVfpRegister dst,
3414 const DwVfpRegister src1,
3415 const DwVfpRegister src2,
3416 const Condition cond) {
3417 // Instruction details available in ARM DDI 0406C.b, A8-932.
3418 // cond(31-28) | 11100(27-23) | D(22) | 00(21-20) | Vn(19-16) |
3419 // Vd(15-12) | 101(11-9) | sz=1(8) | N(7) | op=1(6) | M(5) | 0(4) | Vm(3-0)
3420 DCHECK(VfpRegisterIsAvailable(dst));
3421 DCHECK(VfpRegisterIsAvailable(src1));
3422 DCHECK(VfpRegisterIsAvailable(src2));
3423 int vd, d;
3424 dst.split_code(&vd, &d);
3425 int vn, n;
3426 src1.split_code(&vn, &n);
3427 int vm, m;
3428 src2.split_code(&vm, &m);
3429 emit(cond | 0x1C*B23 | d*B22 | vn*B16 | vd*B12 | 0x5*B9 | B8 | n*B7 | B6 |
3430 m*B5 | vm);
3431 }
3432
3433
vmls(const SwVfpRegister dst,const SwVfpRegister src1,const SwVfpRegister src2,const Condition cond)3434 void Assembler::vmls(const SwVfpRegister dst, const SwVfpRegister src1,
3435 const SwVfpRegister src2, const Condition cond) {
3436 // Instruction details available in ARM DDI 0406C.b, A8-932.
3437 // cond(31-28) | 11100(27-23) | D(22) | 00(21-20) | Vn(19-16) |
3438 // Vd(15-12) | 101(11-9) | sz=0(8) | N(7) | op=1(6) | M(5) | 0(4) | Vm(3-0)
3439 int vd, d;
3440 dst.split_code(&vd, &d);
3441 int vn, n;
3442 src1.split_code(&vn, &n);
3443 int vm, m;
3444 src2.split_code(&vm, &m);
3445 emit(cond | 0x1C * B23 | d * B22 | vn * B16 | vd * B12 | 0x5 * B9 | n * B7 |
3446 B6 | m * B5 | vm);
3447 }
3448
3449
vdiv(const DwVfpRegister dst,const DwVfpRegister src1,const DwVfpRegister src2,const Condition cond)3450 void Assembler::vdiv(const DwVfpRegister dst,
3451 const DwVfpRegister src1,
3452 const DwVfpRegister src2,
3453 const Condition cond) {
3454 // Dd = vdiv(Dn, Dm) double precision floating point division.
3455 // Dd = D:Vd; Dm=M:Vm; Dn=N:Vm.
3456 // Instruction details available in ARM DDI 0406C.b, A8-882.
3457 // cond(31-28) | 11101(27-23)| D(22) | 00(21-20) | Vn(19-16) |
3458 // Vd(15-12) | 101(11-9) | sz=1(8) | N(7) | 0(6) | M(5) | 0(4) | Vm(3-0)
3459 DCHECK(VfpRegisterIsAvailable(dst));
3460 DCHECK(VfpRegisterIsAvailable(src1));
3461 DCHECK(VfpRegisterIsAvailable(src2));
3462 int vd, d;
3463 dst.split_code(&vd, &d);
3464 int vn, n;
3465 src1.split_code(&vn, &n);
3466 int vm, m;
3467 src2.split_code(&vm, &m);
3468 emit(cond | 0x1D*B23 | d*B22 | vn*B16 | vd*B12 | 0x5*B9 | B8 | n*B7 | m*B5 |
3469 vm);
3470 }
3471
3472
vdiv(const SwVfpRegister dst,const SwVfpRegister src1,const SwVfpRegister src2,const Condition cond)3473 void Assembler::vdiv(const SwVfpRegister dst, const SwVfpRegister src1,
3474 const SwVfpRegister src2, const Condition cond) {
3475 // Sd = vdiv(Sn, Sm) single precision floating point division.
3476 // Sd = D:Vd; Sm=M:Vm; Sn=N:Vm.
3477 // Instruction details available in ARM DDI 0406C.b, A8-882.
3478 // cond(31-28) | 11101(27-23)| D(22) | 00(21-20) | Vn(19-16) |
3479 // Vd(15-12) | 101(11-9) | sz=0(8) | N(7) | 0(6) | M(5) | 0(4) | Vm(3-0)
3480 int vd, d;
3481 dst.split_code(&vd, &d);
3482 int vn, n;
3483 src1.split_code(&vn, &n);
3484 int vm, m;
3485 src2.split_code(&vm, &m);
3486 emit(cond | 0x1D * B23 | d * B22 | vn * B16 | vd * B12 | 0x5 * B9 | n * B7 |
3487 m * B5 | vm);
3488 }
3489
3490
vcmp(const DwVfpRegister src1,const DwVfpRegister src2,const Condition cond)3491 void Assembler::vcmp(const DwVfpRegister src1,
3492 const DwVfpRegister src2,
3493 const Condition cond) {
3494 // vcmp(Dd, Dm) double precision floating point comparison.
3495 // Instruction details available in ARM DDI 0406C.b, A8-864.
3496 // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 0100(19-16) |
3497 // Vd(15-12) | 101(11-9) | sz=1(8) | E=0(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
3498 DCHECK(VfpRegisterIsAvailable(src1));
3499 DCHECK(VfpRegisterIsAvailable(src2));
3500 int vd, d;
3501 src1.split_code(&vd, &d);
3502 int vm, m;
3503 src2.split_code(&vm, &m);
3504 emit(cond | 0x1D*B23 | d*B22 | 0x3*B20 | 0x4*B16 | vd*B12 | 0x5*B9 | B8 | B6 |
3505 m*B5 | vm);
3506 }
3507
3508
vcmp(const SwVfpRegister src1,const SwVfpRegister src2,const Condition cond)3509 void Assembler::vcmp(const SwVfpRegister src1, const SwVfpRegister src2,
3510 const Condition cond) {
3511 // vcmp(Sd, Sm) single precision floating point comparison.
3512 // Instruction details available in ARM DDI 0406C.b, A8-864.
3513 // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 0100(19-16) |
3514 // Vd(15-12) | 101(11-9) | sz=0(8) | E=0(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
3515 int vd, d;
3516 src1.split_code(&vd, &d);
3517 int vm, m;
3518 src2.split_code(&vm, &m);
3519 emit(cond | 0x1D * B23 | d * B22 | 0x3 * B20 | 0x4 * B16 | vd * B12 |
3520 0x5 * B9 | B6 | m * B5 | vm);
3521 }
3522
3523
vcmp(const DwVfpRegister src1,const double src2,const Condition cond)3524 void Assembler::vcmp(const DwVfpRegister src1,
3525 const double src2,
3526 const Condition cond) {
3527 // vcmp(Dd, #0.0) double precision floating point comparison.
3528 // Instruction details available in ARM DDI 0406C.b, A8-864.
3529 // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 0101(19-16) |
3530 // Vd(15-12) | 101(11-9) | sz=1(8) | E=0(7) | 1(6) | 0(5) | 0(4) | 0000(3-0)
3531 DCHECK(VfpRegisterIsAvailable(src1));
3532 DCHECK_EQ(src2, 0.0);
3533 int vd, d;
3534 src1.split_code(&vd, &d);
3535 emit(cond | 0x1D*B23 | d*B22 | 0x3*B20 | 0x5*B16 | vd*B12 | 0x5*B9 | B8 | B6);
3536 }
3537
3538
vcmp(const SwVfpRegister src1,const float src2,const Condition cond)3539 void Assembler::vcmp(const SwVfpRegister src1, const float src2,
3540 const Condition cond) {
3541 // vcmp(Sd, #0.0) single precision floating point comparison.
3542 // Instruction details available in ARM DDI 0406C.b, A8-864.
3543 // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 0101(19-16) |
3544 // Vd(15-12) | 101(11-9) | sz=0(8) | E=0(7) | 1(6) | 0(5) | 0(4) | 0000(3-0)
3545 DCHECK_EQ(src2, 0.0);
3546 int vd, d;
3547 src1.split_code(&vd, &d);
3548 emit(cond | 0x1D * B23 | d * B22 | 0x3 * B20 | 0x5 * B16 | vd * B12 |
3549 0x5 * B9 | B6);
3550 }
3551
vmaxnm(const DwVfpRegister dst,const DwVfpRegister src1,const DwVfpRegister src2)3552 void Assembler::vmaxnm(const DwVfpRegister dst, const DwVfpRegister src1,
3553 const DwVfpRegister src2) {
3554 // kSpecialCondition(31-28) | 11101(27-23) | D(22) | 00(21-20) | Vn(19-16) |
3555 // Vd(15-12) | 101(11-9) | sz=1(8) | N(7) | 0(6) | M(5) | 0(4) | Vm(3-0)
3556 DCHECK(IsEnabled(ARMv8));
3557 int vd, d;
3558 dst.split_code(&vd, &d);
3559 int vn, n;
3560 src1.split_code(&vn, &n);
3561 int vm, m;
3562 src2.split_code(&vm, &m);
3563
3564 emit(kSpecialCondition | 0x1D * B23 | d * B22 | vn * B16 | vd * B12 |
3565 0x5 * B9 | B8 | n * B7 | m * B5 | vm);
3566 }
3567
vmaxnm(const SwVfpRegister dst,const SwVfpRegister src1,const SwVfpRegister src2)3568 void Assembler::vmaxnm(const SwVfpRegister dst, const SwVfpRegister src1,
3569 const SwVfpRegister src2) {
3570 // kSpecialCondition(31-28) | 11101(27-23) | D(22) | 00(21-20) | Vn(19-16) |
3571 // Vd(15-12) | 101(11-9) | sz=0(8) | N(7) | 0(6) | M(5) | 0(4) | Vm(3-0)
3572 DCHECK(IsEnabled(ARMv8));
3573 int vd, d;
3574 dst.split_code(&vd, &d);
3575 int vn, n;
3576 src1.split_code(&vn, &n);
3577 int vm, m;
3578 src2.split_code(&vm, &m);
3579
3580 emit(kSpecialCondition | 0x1D * B23 | d * B22 | vn * B16 | vd * B12 |
3581 0x5 * B9 | n * B7 | m * B5 | vm);
3582 }
3583
vminnm(const DwVfpRegister dst,const DwVfpRegister src1,const DwVfpRegister src2)3584 void Assembler::vminnm(const DwVfpRegister dst, const DwVfpRegister src1,
3585 const DwVfpRegister src2) {
3586 // kSpecialCondition(31-28) | 11101(27-23) | D(22) | 00(21-20) | Vn(19-16) |
3587 // Vd(15-12) | 101(11-9) | sz=1(8) | N(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
3588 DCHECK(IsEnabled(ARMv8));
3589 int vd, d;
3590 dst.split_code(&vd, &d);
3591 int vn, n;
3592 src1.split_code(&vn, &n);
3593 int vm, m;
3594 src2.split_code(&vm, &m);
3595
3596 emit(kSpecialCondition | 0x1D * B23 | d * B22 | vn * B16 | vd * B12 |
3597 0x5 * B9 | B8 | n * B7 | B6 | m * B5 | vm);
3598 }
3599
vminnm(const SwVfpRegister dst,const SwVfpRegister src1,const SwVfpRegister src2)3600 void Assembler::vminnm(const SwVfpRegister dst, const SwVfpRegister src1,
3601 const SwVfpRegister src2) {
3602 // kSpecialCondition(31-28) | 11101(27-23) | D(22) | 00(21-20) | Vn(19-16) |
3603 // Vd(15-12) | 101(11-9) | sz=0(8) | N(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
3604 DCHECK(IsEnabled(ARMv8));
3605 int vd, d;
3606 dst.split_code(&vd, &d);
3607 int vn, n;
3608 src1.split_code(&vn, &n);
3609 int vm, m;
3610 src2.split_code(&vm, &m);
3611
3612 emit(kSpecialCondition | 0x1D * B23 | d * B22 | vn * B16 | vd * B12 |
3613 0x5 * B9 | n * B7 | B6 | m * B5 | vm);
3614 }
3615
vsel(Condition cond,const DwVfpRegister dst,const DwVfpRegister src1,const DwVfpRegister src2)3616 void Assembler::vsel(Condition cond, const DwVfpRegister dst,
3617 const DwVfpRegister src1, const DwVfpRegister src2) {
3618 // cond=kSpecialCondition(31-28) | 11100(27-23) | D(22) |
3619 // vsel_cond=XX(21-20) | Vn(19-16) | Vd(15-12) | 101(11-9) | sz=1(8) | N(7) |
3620 // 0(6) | M(5) | 0(4) | Vm(3-0)
3621 DCHECK(IsEnabled(ARMv8));
3622 int vd, d;
3623 dst.split_code(&vd, &d);
3624 int vn, n;
3625 src1.split_code(&vn, &n);
3626 int vm, m;
3627 src2.split_code(&vm, &m);
3628 int sz = 1;
3629
3630 // VSEL has a special (restricted) condition encoding.
3631 // eq(0b0000)... -> 0b00
3632 // ge(0b1010)... -> 0b10
3633 // gt(0b1100)... -> 0b11
3634 // vs(0b0110)... -> 0b01
3635 // No other conditions are supported.
3636 int vsel_cond = (cond >> 30) & 0x3;
3637 if ((cond != eq) && (cond != ge) && (cond != gt) && (cond != vs)) {
3638 // We can implement some other conditions by swapping the inputs.
3639 DCHECK((cond == ne) | (cond == lt) | (cond == le) | (cond == vc));
3640 std::swap(vn, vm);
3641 std::swap(n, m);
3642 }
3643
3644 emit(kSpecialCondition | 0x1C * B23 | d * B22 | vsel_cond * B20 | vn * B16 |
3645 vd * B12 | 0x5 * B9 | sz * B8 | n * B7 | m * B5 | vm);
3646 }
3647
vsel(Condition cond,const SwVfpRegister dst,const SwVfpRegister src1,const SwVfpRegister src2)3648 void Assembler::vsel(Condition cond, const SwVfpRegister dst,
3649 const SwVfpRegister src1, const SwVfpRegister src2) {
3650 // cond=kSpecialCondition(31-28) | 11100(27-23) | D(22) |
3651 // vsel_cond=XX(21-20) | Vn(19-16) | Vd(15-12) | 101(11-9) | sz=0(8) | N(7) |
3652 // 0(6) | M(5) | 0(4) | Vm(3-0)
3653 DCHECK(IsEnabled(ARMv8));
3654 int vd, d;
3655 dst.split_code(&vd, &d);
3656 int vn, n;
3657 src1.split_code(&vn, &n);
3658 int vm, m;
3659 src2.split_code(&vm, &m);
3660 int sz = 0;
3661
3662 // VSEL has a special (restricted) condition encoding.
3663 // eq(0b0000)... -> 0b00
3664 // ge(0b1010)... -> 0b10
3665 // gt(0b1100)... -> 0b11
3666 // vs(0b0110)... -> 0b01
3667 // No other conditions are supported.
3668 int vsel_cond = (cond >> 30) & 0x3;
3669 if ((cond != eq) && (cond != ge) && (cond != gt) && (cond != vs)) {
3670 // We can implement some other conditions by swapping the inputs.
3671 DCHECK((cond == ne) | (cond == lt) | (cond == le) | (cond == vc));
3672 std::swap(vn, vm);
3673 std::swap(n, m);
3674 }
3675
3676 emit(kSpecialCondition | 0x1C * B23 | d * B22 | vsel_cond * B20 | vn * B16 |
3677 vd * B12 | 0x5 * B9 | sz * B8 | n * B7 | m * B5 | vm);
3678 }
3679
vsqrt(const DwVfpRegister dst,const DwVfpRegister src,const Condition cond)3680 void Assembler::vsqrt(const DwVfpRegister dst,
3681 const DwVfpRegister src,
3682 const Condition cond) {
3683 // Instruction details available in ARM DDI 0406C.b, A8-1058.
3684 // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 0001(19-16) |
3685 // Vd(15-12) | 101(11-9) | sz=1(8) | 11(7-6) | M(5) | 0(4) | Vm(3-0)
3686 DCHECK(VfpRegisterIsAvailable(dst));
3687 DCHECK(VfpRegisterIsAvailable(src));
3688 int vd, d;
3689 dst.split_code(&vd, &d);
3690 int vm, m;
3691 src.split_code(&vm, &m);
3692 emit(cond | 0x1D*B23 | d*B22 | 0x3*B20 | B16 | vd*B12 | 0x5*B9 | B8 | 0x3*B6 |
3693 m*B5 | vm);
3694 }
3695
3696
vsqrt(const SwVfpRegister dst,const SwVfpRegister src,const Condition cond)3697 void Assembler::vsqrt(const SwVfpRegister dst, const SwVfpRegister src,
3698 const Condition cond) {
3699 // Instruction details available in ARM DDI 0406C.b, A8-1058.
3700 // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 0001(19-16) |
3701 // Vd(15-12) | 101(11-9) | sz=0(8) | 11(7-6) | M(5) | 0(4) | Vm(3-0)
3702 int vd, d;
3703 dst.split_code(&vd, &d);
3704 int vm, m;
3705 src.split_code(&vm, &m);
3706 emit(cond | 0x1D * B23 | d * B22 | 0x3 * B20 | B16 | vd * B12 | 0x5 * B9 |
3707 0x3 * B6 | m * B5 | vm);
3708 }
3709
3710
vmsr(Register dst,Condition cond)3711 void Assembler::vmsr(Register dst, Condition cond) {
3712 // Instruction details available in ARM DDI 0406A, A8-652.
3713 // cond(31-28) | 1110 (27-24) | 1110(23-20)| 0001 (19-16) |
3714 // Rt(15-12) | 1010 (11-8) | 0(7) | 00 (6-5) | 1(4) | 0000(3-0)
3715 emit(cond | 0xE * B24 | 0xE * B20 | B16 | dst.code() * B12 | 0xA * B8 | B4);
3716 }
3717
3718
vmrs(Register dst,Condition cond)3719 void Assembler::vmrs(Register dst, Condition cond) {
3720 // Instruction details available in ARM DDI 0406A, A8-652.
3721 // cond(31-28) | 1110 (27-24) | 1111(23-20)| 0001 (19-16) |
3722 // Rt(15-12) | 1010 (11-8) | 0(7) | 00 (6-5) | 1(4) | 0000(3-0)
3723 emit(cond | 0xE * B24 | 0xF * B20 | B16 | dst.code() * B12 | 0xA * B8 | B4);
3724 }
3725
3726
vrinta(const SwVfpRegister dst,const SwVfpRegister src)3727 void Assembler::vrinta(const SwVfpRegister dst, const SwVfpRegister src) {
3728 // cond=kSpecialCondition(31-28) | 11101(27-23)| D(22) | 11(21-20) |
3729 // 10(19-18) | RM=00(17-16) | Vd(15-12) | 101(11-9) | sz=0(8) | 01(7-6) |
3730 // M(5) | 0(4) | Vm(3-0)
3731 DCHECK(IsEnabled(ARMv8));
3732 int vd, d;
3733 dst.split_code(&vd, &d);
3734 int vm, m;
3735 src.split_code(&vm, &m);
3736 emit(kSpecialCondition | 0x1D * B23 | d * B22 | 0x3 * B20 | B19 | vd * B12 |
3737 0x5 * B9 | B6 | m * B5 | vm);
3738 }
3739
3740
vrinta(const DwVfpRegister dst,const DwVfpRegister src)3741 void Assembler::vrinta(const DwVfpRegister dst, const DwVfpRegister src) {
3742 // cond=kSpecialCondition(31-28) | 11101(27-23)| D(22) | 11(21-20) |
3743 // 10(19-18) | RM=00(17-16) | Vd(15-12) | 101(11-9) | sz=1(8) | 01(7-6) |
3744 // M(5) | 0(4) | Vm(3-0)
3745 DCHECK(IsEnabled(ARMv8));
3746 int vd, d;
3747 dst.split_code(&vd, &d);
3748 int vm, m;
3749 src.split_code(&vm, &m);
3750 emit(kSpecialCondition | 0x1D * B23 | d * B22 | 0x3 * B20 | B19 | vd * B12 |
3751 0x5 * B9 | B8 | B6 | m * B5 | vm);
3752 }
3753
3754
vrintn(const SwVfpRegister dst,const SwVfpRegister src)3755 void Assembler::vrintn(const SwVfpRegister dst, const SwVfpRegister src) {
3756 // cond=kSpecialCondition(31-28) | 11101(27-23)| D(22) | 11(21-20) |
3757 // 10(19-18) | RM=01(17-16) | Vd(15-12) | 101(11-9) | sz=0(8) | 01(7-6) |
3758 // M(5) | 0(4) | Vm(3-0)
3759 DCHECK(IsEnabled(ARMv8));
3760 int vd, d;
3761 dst.split_code(&vd, &d);
3762 int vm, m;
3763 src.split_code(&vm, &m);
3764 emit(kSpecialCondition | 0x1D * B23 | d * B22 | 0x3 * B20 | B19 | 0x1 * B16 |
3765 vd * B12 | 0x5 * B9 | B6 | m * B5 | vm);
3766 }
3767
3768
vrintn(const DwVfpRegister dst,const DwVfpRegister src)3769 void Assembler::vrintn(const DwVfpRegister dst, const DwVfpRegister src) {
3770 // cond=kSpecialCondition(31-28) | 11101(27-23)| D(22) | 11(21-20) |
3771 // 10(19-18) | RM=01(17-16) | Vd(15-12) | 101(11-9) | sz=1(8) | 01(7-6) |
3772 // M(5) | 0(4) | Vm(3-0)
3773 DCHECK(IsEnabled(ARMv8));
3774 int vd, d;
3775 dst.split_code(&vd, &d);
3776 int vm, m;
3777 src.split_code(&vm, &m);
3778 emit(kSpecialCondition | 0x1D * B23 | d * B22 | 0x3 * B20 | B19 | 0x1 * B16 |
3779 vd * B12 | 0x5 * B9 | B8 | B6 | m * B5 | vm);
3780 }
3781
3782
vrintp(const SwVfpRegister dst,const SwVfpRegister src)3783 void Assembler::vrintp(const SwVfpRegister dst, const SwVfpRegister src) {
3784 // cond=kSpecialCondition(31-28) | 11101(27-23)| D(22) | 11(21-20) |
3785 // 10(19-18) | RM=10(17-16) | Vd(15-12) | 101(11-9) | sz=0(8) | 01(7-6) |
3786 // M(5) | 0(4) | Vm(3-0)
3787 DCHECK(IsEnabled(ARMv8));
3788 int vd, d;
3789 dst.split_code(&vd, &d);
3790 int vm, m;
3791 src.split_code(&vm, &m);
3792 emit(kSpecialCondition | 0x1D * B23 | d * B22 | 0x3 * B20 | B19 | 0x2 * B16 |
3793 vd * B12 | 0x5 * B9 | B6 | m * B5 | vm);
3794 }
3795
3796
vrintp(const DwVfpRegister dst,const DwVfpRegister src)3797 void Assembler::vrintp(const DwVfpRegister dst, const DwVfpRegister src) {
3798 // cond=kSpecialCondition(31-28) | 11101(27-23)| D(22) | 11(21-20) |
3799 // 10(19-18) | RM=10(17-16) | Vd(15-12) | 101(11-9) | sz=1(8) | 01(7-6) |
3800 // M(5) | 0(4) | Vm(3-0)
3801 DCHECK(IsEnabled(ARMv8));
3802 int vd, d;
3803 dst.split_code(&vd, &d);
3804 int vm, m;
3805 src.split_code(&vm, &m);
3806 emit(kSpecialCondition | 0x1D * B23 | d * B22 | 0x3 * B20 | B19 | 0x2 * B16 |
3807 vd * B12 | 0x5 * B9 | B8 | B6 | m * B5 | vm);
3808 }
3809
3810
vrintm(const SwVfpRegister dst,const SwVfpRegister src)3811 void Assembler::vrintm(const SwVfpRegister dst, const SwVfpRegister src) {
3812 // cond=kSpecialCondition(31-28) | 11101(27-23)| D(22) | 11(21-20) |
3813 // 10(19-18) | RM=11(17-16) | Vd(15-12) | 101(11-9) | sz=0(8) | 01(7-6) |
3814 // M(5) | 0(4) | Vm(3-0)
3815 DCHECK(IsEnabled(ARMv8));
3816 int vd, d;
3817 dst.split_code(&vd, &d);
3818 int vm, m;
3819 src.split_code(&vm, &m);
3820 emit(kSpecialCondition | 0x1D * B23 | d * B22 | 0x3 * B20 | B19 | 0x3 * B16 |
3821 vd * B12 | 0x5 * B9 | B6 | m * B5 | vm);
3822 }
3823
3824
vrintm(const DwVfpRegister dst,const DwVfpRegister src)3825 void Assembler::vrintm(const DwVfpRegister dst, const DwVfpRegister src) {
3826 // cond=kSpecialCondition(31-28) | 11101(27-23)| D(22) | 11(21-20) |
3827 // 10(19-18) | RM=11(17-16) | Vd(15-12) | 101(11-9) | sz=1(8) | 01(7-6) |
3828 // M(5) | 0(4) | Vm(3-0)
3829 DCHECK(IsEnabled(ARMv8));
3830 int vd, d;
3831 dst.split_code(&vd, &d);
3832 int vm, m;
3833 src.split_code(&vm, &m);
3834 emit(kSpecialCondition | 0x1D * B23 | d * B22 | 0x3 * B20 | B19 | 0x3 * B16 |
3835 vd * B12 | 0x5 * B9 | B8 | B6 | m * B5 | vm);
3836 }
3837
3838
vrintz(const SwVfpRegister dst,const SwVfpRegister src,const Condition cond)3839 void Assembler::vrintz(const SwVfpRegister dst, const SwVfpRegister src,
3840 const Condition cond) {
3841 // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 011(19-17) | 0(16) |
3842 // Vd(15-12) | 101(11-9) | sz=0(8) | op=1(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
3843 DCHECK(IsEnabled(ARMv8));
3844 int vd, d;
3845 dst.split_code(&vd, &d);
3846 int vm, m;
3847 src.split_code(&vm, &m);
3848 emit(cond | 0x1D * B23 | d * B22 | 0x3 * B20 | 0x3 * B17 | vd * B12 |
3849 0x5 * B9 | B7 | B6 | m * B5 | vm);
3850 }
3851
3852
vrintz(const DwVfpRegister dst,const DwVfpRegister src,const Condition cond)3853 void Assembler::vrintz(const DwVfpRegister dst, const DwVfpRegister src,
3854 const Condition cond) {
3855 // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 011(19-17) | 0(16) |
3856 // Vd(15-12) | 101(11-9) | sz=1(8) | op=1(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
3857 DCHECK(IsEnabled(ARMv8));
3858 int vd, d;
3859 dst.split_code(&vd, &d);
3860 int vm, m;
3861 src.split_code(&vm, &m);
3862 emit(cond | 0x1D * B23 | d * B22 | 0x3 * B20 | 0x3 * B17 | vd * B12 |
3863 0x5 * B9 | B8 | B7 | B6 | m * B5 | vm);
3864 }
3865
3866
3867 // Support for NEON.
3868
vld1(NeonSize size,const NeonListOperand & dst,const NeonMemOperand & src)3869 void Assembler::vld1(NeonSize size,
3870 const NeonListOperand& dst,
3871 const NeonMemOperand& src) {
3872 // Instruction details available in ARM DDI 0406C.b, A8.8.320.
3873 // 1111(31-28) | 01000(27-23) | D(22) | 10(21-20) | Rn(19-16) |
3874 // Vd(15-12) | type(11-8) | size(7-6) | align(5-4) | Rm(3-0)
3875 DCHECK(IsEnabled(NEON));
3876 int vd, d;
3877 dst.base().split_code(&vd, &d);
3878 emit(0xFU*B28 | 4*B24 | d*B22 | 2*B20 | src.rn().code()*B16 | vd*B12 |
3879 dst.type()*B8 | size*B6 | src.align()*B4 | src.rm().code());
3880 }
3881
vst1(NeonSize size,const NeonListOperand & src,const NeonMemOperand & dst)3882 void Assembler::vst1(NeonSize size, const NeonListOperand& src,
3883 const NeonMemOperand& dst) {
3884 // Instruction details available in ARM DDI 0406C.b, A8.8.404.
3885 // 1111(31-28) | 01000(27-23) | D(22) | 00(21-20) | Rn(19-16) |
3886 // Vd(15-12) | type(11-8) | size(7-6) | align(5-4) | Rm(3-0)
3887 DCHECK(IsEnabled(NEON));
3888 int vd, d;
3889 src.base().split_code(&vd, &d);
3890 emit(0xFU*B28 | 4*B24 | d*B22 | dst.rn().code()*B16 | vd*B12 | src.type()*B8 |
3891 size*B6 | dst.align()*B4 | dst.rm().code());
3892 }
3893
3894
vmovl(NeonDataType dt,QwNeonRegister dst,DwVfpRegister src)3895 void Assembler::vmovl(NeonDataType dt, QwNeonRegister dst, DwVfpRegister src) {
3896 // Instruction details available in ARM DDI 0406C.b, A8.8.346.
3897 // 1111(31-28) | 001(27-25) | U(24) | 1(23) | D(22) | imm3(21-19) |
3898 // 000(18-16) | Vd(15-12) | 101000(11-6) | M(5) | 1(4) | Vm(3-0)
3899 DCHECK(IsEnabled(NEON));
3900 int vd, d;
3901 dst.split_code(&vd, &d);
3902 int vm, m;
3903 src.split_code(&vm, &m);
3904 int U = NeonU(dt);
3905 int imm3 = 1 << NeonSz(dt);
3906 emit(0xFU * B28 | B25 | U * B24 | B23 | d * B22 | imm3 * B19 | vd * B12 |
3907 0xA * B8 | m * B5 | B4 | vm);
3908 }
3909
vqmovn(NeonDataType dt,DwVfpRegister dst,QwNeonRegister src)3910 void Assembler::vqmovn(NeonDataType dt, DwVfpRegister dst, QwNeonRegister src) {
3911 // Instruction details available in ARM DDI 0406C.b, A8.8.1004.
3912 // vqmovn.<type><size> Dd, Qm. ARM vector narrowing move with saturation.
3913 DCHECK(IsEnabled(NEON));
3914 int vd, d;
3915 dst.split_code(&vd, &d);
3916 int vm, m;
3917 src.split_code(&vm, &m);
3918 int size = NeonSz(dt);
3919 int u = NeonU(dt);
3920 int op = u != 0 ? 3 : 2;
3921 emit(0x1E7U * B23 | d * B22 | 0x3 * B20 | size * B18 | 0x2 * B16 | vd * B12 |
3922 0x2 * B8 | op * B6 | m * B5 | vm);
3923 }
3924
EncodeScalar(NeonDataType dt,int index)3925 static int EncodeScalar(NeonDataType dt, int index) {
3926 int opc1_opc2 = 0;
3927 DCHECK_LE(0, index);
3928 switch (dt) {
3929 case NeonS8:
3930 case NeonU8:
3931 DCHECK_GT(8, index);
3932 opc1_opc2 = 0x8 | index;
3933 break;
3934 case NeonS16:
3935 case NeonU16:
3936 DCHECK_GT(4, index);
3937 opc1_opc2 = 0x1 | (index << 1);
3938 break;
3939 case NeonS32:
3940 case NeonU32:
3941 DCHECK_GT(2, index);
3942 opc1_opc2 = index << 2;
3943 break;
3944 default:
3945 UNREACHABLE();
3946 break;
3947 }
3948 return (opc1_opc2 >> 2) * B21 | (opc1_opc2 & 0x3) * B5;
3949 }
3950
vmov(NeonDataType dt,DwVfpRegister dst,int index,Register src)3951 void Assembler::vmov(NeonDataType dt, DwVfpRegister dst, int index,
3952 Register src) {
3953 // Instruction details available in ARM DDI 0406C.b, A8.8.940.
3954 // vmov ARM core register to scalar.
3955 DCHECK(dt == NeonS32 || dt == NeonU32 || IsEnabled(NEON));
3956 int vd, d;
3957 dst.split_code(&vd, &d);
3958 int opc1_opc2 = EncodeScalar(dt, index);
3959 emit(0xEEu * B24 | vd * B16 | src.code() * B12 | 0xB * B8 | d * B7 | B4 |
3960 opc1_opc2);
3961 }
3962
vmov(NeonDataType dt,Register dst,DwVfpRegister src,int index)3963 void Assembler::vmov(NeonDataType dt, Register dst, DwVfpRegister src,
3964 int index) {
3965 // Instruction details available in ARM DDI 0406C.b, A8.8.942.
3966 // vmov Arm scalar to core register.
3967 DCHECK(dt == NeonS32 || dt == NeonU32 || IsEnabled(NEON));
3968 int vn, n;
3969 src.split_code(&vn, &n);
3970 int opc1_opc2 = EncodeScalar(dt, index);
3971 int u = NeonU(dt);
3972 emit(0xEEu * B24 | u * B23 | B20 | vn * B16 | dst.code() * B12 | 0xB * B8 |
3973 n * B7 | B4 | opc1_opc2);
3974 }
3975
vmov(QwNeonRegister dst,QwNeonRegister src)3976 void Assembler::vmov(QwNeonRegister dst, QwNeonRegister src) {
3977 // Instruction details available in ARM DDI 0406C.b, A8-938.
3978 // vmov is encoded as vorr.
3979 vorr(dst, src, src);
3980 }
3981
vdup(NeonSize size,QwNeonRegister dst,Register src)3982 void Assembler::vdup(NeonSize size, QwNeonRegister dst, Register src) {
3983 DCHECK(IsEnabled(NEON));
3984 // Instruction details available in ARM DDI 0406C.b, A8-886.
3985 int B = 0, E = 0;
3986 switch (size) {
3987 case Neon8:
3988 B = 1;
3989 break;
3990 case Neon16:
3991 E = 1;
3992 break;
3993 case Neon32:
3994 break;
3995 default:
3996 UNREACHABLE();
3997 break;
3998 }
3999 int vd, d;
4000 dst.split_code(&vd, &d);
4001
4002 emit(al | 0x1D * B23 | B * B22 | B21 | vd * B16 | src.code() * B12 |
4003 0xB * B8 | d * B7 | E * B5 | B4);
4004 }
4005
4006 enum NeonRegType { NEON_D, NEON_Q };
4007
NeonSplitCode(NeonRegType type,int code,int * vm,int * m,int * encoding)4008 void NeonSplitCode(NeonRegType type, int code, int* vm, int* m, int* encoding) {
4009 if (type == NEON_D) {
4010 DwVfpRegister::split_code(code, vm, m);
4011 } else {
4012 DCHECK_EQ(type, NEON_Q);
4013 QwNeonRegister::split_code(code, vm, m);
4014 *encoding |= B6;
4015 }
4016 }
4017
EncodeNeonDupOp(NeonSize size,NeonRegType reg_type,int dst_code,DwVfpRegister src,int index)4018 static Instr EncodeNeonDupOp(NeonSize size, NeonRegType reg_type, int dst_code,
4019 DwVfpRegister src, int index) {
4020 DCHECK_NE(Neon64, size);
4021 int sz = static_cast<int>(size);
4022 DCHECK_LE(0, index);
4023 DCHECK_GT(kSimd128Size / (1 << sz), index);
4024 int imm4 = (1 << sz) | ((index << (sz + 1)) & 0xF);
4025 int qbit = 0;
4026 int vd, d;
4027 NeonSplitCode(reg_type, dst_code, &vd, &d, &qbit);
4028 int vm, m;
4029 src.split_code(&vm, &m);
4030
4031 return 0x1E7U * B23 | d * B22 | 0x3 * B20 | imm4 * B16 | vd * B12 |
4032 0x18 * B7 | qbit | m * B5 | vm;
4033 }
4034
vdup(NeonSize size,DwVfpRegister dst,DwVfpRegister src,int index)4035 void Assembler::vdup(NeonSize size, DwVfpRegister dst, DwVfpRegister src,
4036 int index) {
4037 DCHECK(IsEnabled(NEON));
4038 // Instruction details available in ARM DDI 0406C.b, A8-884.
4039 emit(EncodeNeonDupOp(size, NEON_D, dst.code(), src, index));
4040 }
4041
vdup(NeonSize size,QwNeonRegister dst,DwVfpRegister src,int index)4042 void Assembler::vdup(NeonSize size, QwNeonRegister dst, DwVfpRegister src,
4043 int index) {
4044 // Instruction details available in ARM DDI 0406C.b, A8-884.
4045 DCHECK(IsEnabled(NEON));
4046 emit(EncodeNeonDupOp(size, NEON_Q, dst.code(), src, index));
4047 }
4048
4049 // Encode NEON vcvt.src_type.dst_type instruction.
EncodeNeonVCVT(VFPType dst_type,QwNeonRegister dst,VFPType src_type,QwNeonRegister src)4050 static Instr EncodeNeonVCVT(VFPType dst_type, QwNeonRegister dst,
4051 VFPType src_type, QwNeonRegister src) {
4052 DCHECK(src_type != dst_type);
4053 DCHECK(src_type == F32 || dst_type == F32);
4054 // Instruction details available in ARM DDI 0406C.b, A8.8.868.
4055 int vd, d;
4056 dst.split_code(&vd, &d);
4057 int vm, m;
4058 src.split_code(&vm, &m);
4059
4060 int op = 0;
4061 if (src_type == F32) {
4062 DCHECK(dst_type == S32 || dst_type == U32);
4063 op = dst_type == U32 ? 3 : 2;
4064 } else {
4065 DCHECK(src_type == S32 || src_type == U32);
4066 op = src_type == U32 ? 1 : 0;
4067 }
4068
4069 return 0x1E7U * B23 | d * B22 | 0x3B * B16 | vd * B12 | 0x3 * B9 | op * B7 |
4070 B6 | m * B5 | vm;
4071 }
4072
vcvt_f32_s32(QwNeonRegister dst,QwNeonRegister src)4073 void Assembler::vcvt_f32_s32(QwNeonRegister dst, QwNeonRegister src) {
4074 DCHECK(IsEnabled(NEON));
4075 DCHECK(VfpRegisterIsAvailable(dst));
4076 DCHECK(VfpRegisterIsAvailable(src));
4077 emit(EncodeNeonVCVT(F32, dst, S32, src));
4078 }
4079
vcvt_f32_u32(QwNeonRegister dst,QwNeonRegister src)4080 void Assembler::vcvt_f32_u32(QwNeonRegister dst, QwNeonRegister src) {
4081 DCHECK(IsEnabled(NEON));
4082 DCHECK(VfpRegisterIsAvailable(dst));
4083 DCHECK(VfpRegisterIsAvailable(src));
4084 emit(EncodeNeonVCVT(F32, dst, U32, src));
4085 }
4086
vcvt_s32_f32(QwNeonRegister dst,QwNeonRegister src)4087 void Assembler::vcvt_s32_f32(QwNeonRegister dst, QwNeonRegister src) {
4088 DCHECK(IsEnabled(NEON));
4089 DCHECK(VfpRegisterIsAvailable(dst));
4090 DCHECK(VfpRegisterIsAvailable(src));
4091 emit(EncodeNeonVCVT(S32, dst, F32, src));
4092 }
4093
vcvt_u32_f32(QwNeonRegister dst,QwNeonRegister src)4094 void Assembler::vcvt_u32_f32(QwNeonRegister dst, QwNeonRegister src) {
4095 DCHECK(IsEnabled(NEON));
4096 DCHECK(VfpRegisterIsAvailable(dst));
4097 DCHECK(VfpRegisterIsAvailable(src));
4098 emit(EncodeNeonVCVT(U32, dst, F32, src));
4099 }
4100
4101 enum UnaryOp { VMVN, VSWP, VABS, VABSF, VNEG, VNEGF };
4102
EncodeNeonUnaryOp(UnaryOp op,NeonRegType reg_type,NeonSize size,int dst_code,int src_code)4103 static Instr EncodeNeonUnaryOp(UnaryOp op, NeonRegType reg_type, NeonSize size,
4104 int dst_code, int src_code) {
4105 int op_encoding = 0;
4106 switch (op) {
4107 case VMVN:
4108 DCHECK_EQ(Neon8, size); // size == 0 for vmvn
4109 op_encoding = B10 | 0x3 * B7;
4110 break;
4111 case VSWP:
4112 DCHECK_EQ(Neon8, size); // size == 0 for vswp
4113 op_encoding = B17;
4114 break;
4115 case VABS:
4116 op_encoding = B16 | 0x6 * B7;
4117 break;
4118 case VABSF:
4119 DCHECK_EQ(Neon32, size);
4120 op_encoding = B16 | B10 | 0x6 * B7;
4121 break;
4122 case VNEG:
4123 op_encoding = B16 | 0x7 * B7;
4124 break;
4125 case VNEGF:
4126 DCHECK_EQ(Neon32, size);
4127 op_encoding = B16 | B10 | 0x7 * B7;
4128 break;
4129 default:
4130 UNREACHABLE();
4131 break;
4132 }
4133 int vd, d;
4134 NeonSplitCode(reg_type, dst_code, &vd, &d, &op_encoding);
4135 int vm, m;
4136 NeonSplitCode(reg_type, src_code, &vm, &m, &op_encoding);
4137
4138 return 0x1E7U * B23 | d * B22 | 0x3 * B20 | size * B18 | vd * B12 | m * B5 |
4139 vm | op_encoding;
4140 }
4141
vmvn(QwNeonRegister dst,QwNeonRegister src)4142 void Assembler::vmvn(QwNeonRegister dst, QwNeonRegister src) {
4143 // Qd = vmvn(Qn, Qm) SIMD bitwise negate.
4144 // Instruction details available in ARM DDI 0406C.b, A8-966.
4145 DCHECK(IsEnabled(NEON));
4146 emit(EncodeNeonUnaryOp(VMVN, NEON_Q, Neon8, dst.code(), src.code()));
4147 }
4148
vswp(DwVfpRegister dst,DwVfpRegister src)4149 void Assembler::vswp(DwVfpRegister dst, DwVfpRegister src) {
4150 DCHECK(IsEnabled(NEON));
4151 // Dd = vswp(Dn, Dm) SIMD d-register swap.
4152 // Instruction details available in ARM DDI 0406C.b, A8.8.418.
4153 DCHECK(IsEnabled(NEON));
4154 emit(EncodeNeonUnaryOp(VSWP, NEON_D, Neon8, dst.code(), src.code()));
4155 }
4156
vswp(QwNeonRegister dst,QwNeonRegister src)4157 void Assembler::vswp(QwNeonRegister dst, QwNeonRegister src) {
4158 // Qd = vswp(Qn, Qm) SIMD q-register swap.
4159 // Instruction details available in ARM DDI 0406C.b, A8.8.418.
4160 DCHECK(IsEnabled(NEON));
4161 emit(EncodeNeonUnaryOp(VSWP, NEON_Q, Neon8, dst.code(), src.code()));
4162 }
4163
vabs(QwNeonRegister dst,QwNeonRegister src)4164 void Assembler::vabs(QwNeonRegister dst, QwNeonRegister src) {
4165 // Qd = vabs.f<size>(Qn, Qm) SIMD floating point absolute value.
4166 // Instruction details available in ARM DDI 0406C.b, A8.8.824.
4167 DCHECK(IsEnabled(NEON));
4168 emit(EncodeNeonUnaryOp(VABSF, NEON_Q, Neon32, dst.code(), src.code()));
4169 }
4170
vabs(NeonSize size,QwNeonRegister dst,QwNeonRegister src)4171 void Assembler::vabs(NeonSize size, QwNeonRegister dst, QwNeonRegister src) {
4172 // Qd = vabs.s<size>(Qn, Qm) SIMD integer absolute value.
4173 // Instruction details available in ARM DDI 0406C.b, A8.8.824.
4174 DCHECK(IsEnabled(NEON));
4175 emit(EncodeNeonUnaryOp(VABS, NEON_Q, size, dst.code(), src.code()));
4176 }
4177
vneg(QwNeonRegister dst,QwNeonRegister src)4178 void Assembler::vneg(QwNeonRegister dst, QwNeonRegister src) {
4179 // Qd = vabs.f<size>(Qn, Qm) SIMD floating point negate.
4180 // Instruction details available in ARM DDI 0406C.b, A8.8.968.
4181 DCHECK(IsEnabled(NEON));
4182 emit(EncodeNeonUnaryOp(VNEGF, NEON_Q, Neon32, dst.code(), src.code()));
4183 }
4184
vneg(NeonSize size,QwNeonRegister dst,QwNeonRegister src)4185 void Assembler::vneg(NeonSize size, QwNeonRegister dst, QwNeonRegister src) {
4186 // Qd = vabs.s<size>(Qn, Qm) SIMD integer negate.
4187 // Instruction details available in ARM DDI 0406C.b, A8.8.968.
4188 DCHECK(IsEnabled(NEON));
4189 emit(EncodeNeonUnaryOp(VNEG, NEON_Q, size, dst.code(), src.code()));
4190 }
4191
4192 enum BinaryBitwiseOp { VAND, VBIC, VBIF, VBIT, VBSL, VEOR, VORR, VORN };
4193
EncodeNeonBinaryBitwiseOp(BinaryBitwiseOp op,NeonRegType reg_type,int dst_code,int src_code1,int src_code2)4194 static Instr EncodeNeonBinaryBitwiseOp(BinaryBitwiseOp op, NeonRegType reg_type,
4195 int dst_code, int src_code1,
4196 int src_code2) {
4197 int op_encoding = 0;
4198 switch (op) {
4199 case VBIC:
4200 op_encoding = 0x1 * B20;
4201 break;
4202 case VBIF:
4203 op_encoding = B24 | 0x3 * B20;
4204 break;
4205 case VBIT:
4206 op_encoding = B24 | 0x2 * B20;
4207 break;
4208 case VBSL:
4209 op_encoding = B24 | 0x1 * B20;
4210 break;
4211 case VEOR:
4212 op_encoding = B24;
4213 break;
4214 case VORR:
4215 op_encoding = 0x2 * B20;
4216 break;
4217 case VORN:
4218 op_encoding = 0x3 * B20;
4219 break;
4220 case VAND:
4221 // op_encoding is 0.
4222 break;
4223 default:
4224 UNREACHABLE();
4225 break;
4226 }
4227 int vd, d;
4228 NeonSplitCode(reg_type, dst_code, &vd, &d, &op_encoding);
4229 int vn, n;
4230 NeonSplitCode(reg_type, src_code1, &vn, &n, &op_encoding);
4231 int vm, m;
4232 NeonSplitCode(reg_type, src_code2, &vm, &m, &op_encoding);
4233
4234 return 0x1E4U * B23 | op_encoding | d * B22 | vn * B16 | vd * B12 | B8 |
4235 n * B7 | m * B5 | B4 | vm;
4236 }
4237
vand(QwNeonRegister dst,QwNeonRegister src1,QwNeonRegister src2)4238 void Assembler::vand(QwNeonRegister dst, QwNeonRegister src1,
4239 QwNeonRegister src2) {
4240 // Qd = vand(Qn, Qm) SIMD AND.
4241 // Instruction details available in ARM DDI 0406C.b, A8.8.836.
4242 DCHECK(IsEnabled(NEON));
4243 emit(EncodeNeonBinaryBitwiseOp(VAND, NEON_Q, dst.code(), src1.code(),
4244 src2.code()));
4245 }
4246
vbsl(QwNeonRegister dst,QwNeonRegister src1,QwNeonRegister src2)4247 void Assembler::vbsl(QwNeonRegister dst, QwNeonRegister src1,
4248 QwNeonRegister src2) {
4249 // Qd = vbsl(Qn, Qm) SIMD bitwise select.
4250 // Instruction details available in ARM DDI 0406C.b, A8-844.
4251 DCHECK(IsEnabled(NEON));
4252 emit(EncodeNeonBinaryBitwiseOp(VBSL, NEON_Q, dst.code(), src1.code(),
4253 src2.code()));
4254 }
4255
veor(DwVfpRegister dst,DwVfpRegister src1,DwVfpRegister src2)4256 void Assembler::veor(DwVfpRegister dst, DwVfpRegister src1,
4257 DwVfpRegister src2) {
4258 // Dd = veor(Dn, Dm) SIMD exclusive OR.
4259 // Instruction details available in ARM DDI 0406C.b, A8.8.888.
4260 DCHECK(IsEnabled(NEON));
4261 emit(EncodeNeonBinaryBitwiseOp(VEOR, NEON_D, dst.code(), src1.code(),
4262 src2.code()));
4263 }
4264
veor(QwNeonRegister dst,QwNeonRegister src1,QwNeonRegister src2)4265 void Assembler::veor(QwNeonRegister dst, QwNeonRegister src1,
4266 QwNeonRegister src2) {
4267 // Qd = veor(Qn, Qm) SIMD exclusive OR.
4268 // Instruction details available in ARM DDI 0406C.b, A8.8.888.
4269 DCHECK(IsEnabled(NEON));
4270 emit(EncodeNeonBinaryBitwiseOp(VEOR, NEON_Q, dst.code(), src1.code(),
4271 src2.code()));
4272 }
4273
vorr(QwNeonRegister dst,QwNeonRegister src1,QwNeonRegister src2)4274 void Assembler::vorr(QwNeonRegister dst, QwNeonRegister src1,
4275 QwNeonRegister src2) {
4276 // Qd = vorr(Qn, Qm) SIMD OR.
4277 // Instruction details available in ARM DDI 0406C.b, A8.8.976.
4278 DCHECK(IsEnabled(NEON));
4279 emit(EncodeNeonBinaryBitwiseOp(VORR, NEON_Q, dst.code(), src1.code(),
4280 src2.code()));
4281 }
4282
4283 enum FPBinOp {
4284 VADDF,
4285 VSUBF,
4286 VMULF,
4287 VMINF,
4288 VMAXF,
4289 VRECPS,
4290 VRSQRTS,
4291 VCEQF,
4292 VCGEF,
4293 VCGTF
4294 };
4295
EncodeNeonBinOp(FPBinOp op,QwNeonRegister dst,QwNeonRegister src1,QwNeonRegister src2)4296 static Instr EncodeNeonBinOp(FPBinOp op, QwNeonRegister dst,
4297 QwNeonRegister src1, QwNeonRegister src2) {
4298 int op_encoding = 0;
4299 switch (op) {
4300 case VADDF:
4301 op_encoding = 0xD * B8;
4302 break;
4303 case VSUBF:
4304 op_encoding = B21 | 0xD * B8;
4305 break;
4306 case VMULF:
4307 op_encoding = B24 | 0xD * B8 | B4;
4308 break;
4309 case VMINF:
4310 op_encoding = B21 | 0xF * B8;
4311 break;
4312 case VMAXF:
4313 op_encoding = 0xF * B8;
4314 break;
4315 case VRECPS:
4316 op_encoding = 0xF * B8 | B4;
4317 break;
4318 case VRSQRTS:
4319 op_encoding = B21 | 0xF * B8 | B4;
4320 break;
4321 case VCEQF:
4322 op_encoding = 0xE * B8;
4323 break;
4324 case VCGEF:
4325 op_encoding = B24 | 0xE * B8;
4326 break;
4327 case VCGTF:
4328 op_encoding = B24 | B21 | 0xE * B8;
4329 break;
4330 default:
4331 UNREACHABLE();
4332 break;
4333 }
4334 int vd, d;
4335 dst.split_code(&vd, &d);
4336 int vn, n;
4337 src1.split_code(&vn, &n);
4338 int vm, m;
4339 src2.split_code(&vm, &m);
4340 return 0x1E4U * B23 | d * B22 | vn * B16 | vd * B12 | n * B7 | B6 | m * B5 |
4341 vm | op_encoding;
4342 }
4343
4344 enum IntegerBinOp {
4345 VADD,
4346 VQADD,
4347 VSUB,
4348 VQSUB,
4349 VMUL,
4350 VMIN,
4351 VMAX,
4352 VTST,
4353 VCEQ,
4354 VCGE,
4355 VCGT
4356 };
4357
EncodeNeonBinOp(IntegerBinOp op,NeonDataType dt,QwNeonRegister dst,QwNeonRegister src1,QwNeonRegister src2)4358 static Instr EncodeNeonBinOp(IntegerBinOp op, NeonDataType dt,
4359 QwNeonRegister dst, QwNeonRegister src1,
4360 QwNeonRegister src2) {
4361 int op_encoding = 0;
4362 switch (op) {
4363 case VADD:
4364 op_encoding = 0x8 * B8;
4365 break;
4366 case VQADD:
4367 op_encoding = B4;
4368 break;
4369 case VSUB:
4370 op_encoding = B24 | 0x8 * B8;
4371 break;
4372 case VQSUB:
4373 op_encoding = 0x2 * B8 | B4;
4374 break;
4375 case VMUL:
4376 op_encoding = 0x9 * B8 | B4;
4377 break;
4378 case VMIN:
4379 op_encoding = 0x6 * B8 | B4;
4380 break;
4381 case VMAX:
4382 op_encoding = 0x6 * B8;
4383 break;
4384 case VTST:
4385 op_encoding = 0x8 * B8 | B4;
4386 break;
4387 case VCEQ:
4388 op_encoding = B24 | 0x8 * B8 | B4;
4389 break;
4390 case VCGE:
4391 op_encoding = 0x3 * B8 | B4;
4392 break;
4393 case VCGT:
4394 op_encoding = 0x3 * B8;
4395 break;
4396 default:
4397 UNREACHABLE();
4398 break;
4399 }
4400 int vd, d;
4401 dst.split_code(&vd, &d);
4402 int vn, n;
4403 src1.split_code(&vn, &n);
4404 int vm, m;
4405 src2.split_code(&vm, &m);
4406 int size = NeonSz(dt);
4407 int u = NeonU(dt);
4408 return 0x1E4U * B23 | u * B24 | d * B22 | size * B20 | vn * B16 | vd * B12 |
4409 n * B7 | B6 | m * B5 | vm | op_encoding;
4410 }
4411
EncodeNeonBinOp(IntegerBinOp op,NeonSize size,QwNeonRegister dst,QwNeonRegister src1,QwNeonRegister src2)4412 static Instr EncodeNeonBinOp(IntegerBinOp op, NeonSize size, QwNeonRegister dst,
4413 QwNeonRegister src1, QwNeonRegister src2) {
4414 // Map NeonSize values to the signed values in NeonDataType, so the U bit
4415 // will be 0.
4416 return EncodeNeonBinOp(op, static_cast<NeonDataType>(size), dst, src1, src2);
4417 }
4418
vadd(QwNeonRegister dst,QwNeonRegister src1,QwNeonRegister src2)4419 void Assembler::vadd(QwNeonRegister dst, QwNeonRegister src1,
4420 QwNeonRegister src2) {
4421 DCHECK(IsEnabled(NEON));
4422 // Qd = vadd(Qn, Qm) SIMD floating point addition.
4423 // Instruction details available in ARM DDI 0406C.b, A8-830.
4424 emit(EncodeNeonBinOp(VADDF, dst, src1, src2));
4425 }
4426
vadd(NeonSize size,QwNeonRegister dst,QwNeonRegister src1,QwNeonRegister src2)4427 void Assembler::vadd(NeonSize size, QwNeonRegister dst, QwNeonRegister src1,
4428 QwNeonRegister src2) {
4429 DCHECK(IsEnabled(NEON));
4430 // Qd = vadd(Qn, Qm) SIMD integer addition.
4431 // Instruction details available in ARM DDI 0406C.b, A8-828.
4432 emit(EncodeNeonBinOp(VADD, size, dst, src1, src2));
4433 }
4434
vqadd(NeonDataType dt,QwNeonRegister dst,QwNeonRegister src1,QwNeonRegister src2)4435 void Assembler::vqadd(NeonDataType dt, QwNeonRegister dst, QwNeonRegister src1,
4436 QwNeonRegister src2) {
4437 DCHECK(IsEnabled(NEON));
4438 // Qd = vqadd(Qn, Qm) SIMD integer saturating addition.
4439 // Instruction details available in ARM DDI 0406C.b, A8-996.
4440 emit(EncodeNeonBinOp(VQADD, dt, dst, src1, src2));
4441 }
4442
vsub(QwNeonRegister dst,QwNeonRegister src1,QwNeonRegister src2)4443 void Assembler::vsub(QwNeonRegister dst, QwNeonRegister src1,
4444 QwNeonRegister src2) {
4445 DCHECK(IsEnabled(NEON));
4446 // Qd = vsub(Qn, Qm) SIMD floating point subtraction.
4447 // Instruction details available in ARM DDI 0406C.b, A8-1086.
4448 emit(EncodeNeonBinOp(VSUBF, dst, src1, src2));
4449 }
4450
vsub(NeonSize size,QwNeonRegister dst,QwNeonRegister src1,QwNeonRegister src2)4451 void Assembler::vsub(NeonSize size, QwNeonRegister dst, QwNeonRegister src1,
4452 QwNeonRegister src2) {
4453 DCHECK(IsEnabled(NEON));
4454 // Qd = vsub(Qn, Qm) SIMD integer subtraction.
4455 // Instruction details available in ARM DDI 0406C.b, A8-1084.
4456 emit(EncodeNeonBinOp(VSUB, size, dst, src1, src2));
4457 }
4458
vqsub(NeonDataType dt,QwNeonRegister dst,QwNeonRegister src1,QwNeonRegister src2)4459 void Assembler::vqsub(NeonDataType dt, QwNeonRegister dst, QwNeonRegister src1,
4460 QwNeonRegister src2) {
4461 DCHECK(IsEnabled(NEON));
4462 // Qd = vqsub(Qn, Qm) SIMD integer saturating subtraction.
4463 // Instruction details available in ARM DDI 0406C.b, A8-1020.
4464 emit(EncodeNeonBinOp(VQSUB, dt, dst, src1, src2));
4465 }
4466
vmul(QwNeonRegister dst,QwNeonRegister src1,QwNeonRegister src2)4467 void Assembler::vmul(QwNeonRegister dst, QwNeonRegister src1,
4468 QwNeonRegister src2) {
4469 DCHECK(IsEnabled(NEON));
4470 // Qd = vadd(Qn, Qm) SIMD floating point multiply.
4471 // Instruction details available in ARM DDI 0406C.b, A8-958.
4472 emit(EncodeNeonBinOp(VMULF, dst, src1, src2));
4473 }
4474
vmul(NeonSize size,QwNeonRegister dst,QwNeonRegister src1,QwNeonRegister src2)4475 void Assembler::vmul(NeonSize size, QwNeonRegister dst, QwNeonRegister src1,
4476 QwNeonRegister src2) {
4477 DCHECK(IsEnabled(NEON));
4478 // Qd = vadd(Qn, Qm) SIMD integer multiply.
4479 // Instruction details available in ARM DDI 0406C.b, A8-960.
4480 emit(EncodeNeonBinOp(VMUL, size, dst, src1, src2));
4481 }
4482
vmin(QwNeonRegister dst,QwNeonRegister src1,QwNeonRegister src2)4483 void Assembler::vmin(QwNeonRegister dst, QwNeonRegister src1,
4484 QwNeonRegister src2) {
4485 DCHECK(IsEnabled(NEON));
4486 // Qd = vmin(Qn, Qm) SIMD floating point MIN.
4487 // Instruction details available in ARM DDI 0406C.b, A8-928.
4488 emit(EncodeNeonBinOp(VMINF, dst, src1, src2));
4489 }
4490
vmin(NeonDataType dt,QwNeonRegister dst,QwNeonRegister src1,QwNeonRegister src2)4491 void Assembler::vmin(NeonDataType dt, QwNeonRegister dst, QwNeonRegister src1,
4492 QwNeonRegister src2) {
4493 DCHECK(IsEnabled(NEON));
4494 // Qd = vmin(Qn, Qm) SIMD integer MIN.
4495 // Instruction details available in ARM DDI 0406C.b, A8-926.
4496 emit(EncodeNeonBinOp(VMIN, dt, dst, src1, src2));
4497 }
4498
vmax(QwNeonRegister dst,QwNeonRegister src1,QwNeonRegister src2)4499 void Assembler::vmax(QwNeonRegister dst, QwNeonRegister src1,
4500 QwNeonRegister src2) {
4501 DCHECK(IsEnabled(NEON));
4502 // Qd = vmax(Qn, Qm) SIMD floating point MAX.
4503 // Instruction details available in ARM DDI 0406C.b, A8-928.
4504 emit(EncodeNeonBinOp(VMAXF, dst, src1, src2));
4505 }
4506
vmax(NeonDataType dt,QwNeonRegister dst,QwNeonRegister src1,QwNeonRegister src2)4507 void Assembler::vmax(NeonDataType dt, QwNeonRegister dst, QwNeonRegister src1,
4508 QwNeonRegister src2) {
4509 DCHECK(IsEnabled(NEON));
4510 // Qd = vmax(Qn, Qm) SIMD integer MAX.
4511 // Instruction details available in ARM DDI 0406C.b, A8-926.
4512 emit(EncodeNeonBinOp(VMAX, dt, dst, src1, src2));
4513 }
4514
4515 enum NeonShiftOp { VSHL, VSHR, VSLI, VSRI };
4516
EncodeNeonShiftOp(NeonShiftOp op,NeonSize size,bool is_unsigned,NeonRegType reg_type,int dst_code,int src_code,int shift)4517 static Instr EncodeNeonShiftOp(NeonShiftOp op, NeonSize size, bool is_unsigned,
4518 NeonRegType reg_type, int dst_code, int src_code,
4519 int shift) {
4520 int imm6 = 0;
4521 int size_in_bits = kBitsPerByte << static_cast<int>(size);
4522 int op_encoding = 0;
4523 switch (op) {
4524 case VSHL: {
4525 DCHECK(shift >= 0 && size_in_bits > shift);
4526 imm6 = size_in_bits + shift;
4527 op_encoding = 0x5 * B8;
4528 break;
4529 }
4530 case VSHR: {
4531 DCHECK(shift > 0 && size_in_bits >= shift);
4532 imm6 = 2 * size_in_bits - shift;
4533 if (is_unsigned) op_encoding |= B24;
4534 break;
4535 }
4536 case VSLI: {
4537 DCHECK(shift >= 0 && size_in_bits > shift);
4538 imm6 = size_in_bits + shift;
4539 int L = imm6 >> 6;
4540 imm6 &= 0x3F;
4541 op_encoding = B24 | 0x5 * B8 | L * B7;
4542 break;
4543 }
4544 case VSRI: {
4545 DCHECK(shift > 0 && size_in_bits >= shift);
4546 imm6 = 2 * size_in_bits - shift;
4547 int L = imm6 >> 6;
4548 imm6 &= 0x3F;
4549 op_encoding = B24 | 0x4 * B8 | L * B7;
4550 break;
4551 }
4552 default:
4553 UNREACHABLE();
4554 break;
4555 }
4556
4557 int vd, d;
4558 NeonSplitCode(reg_type, dst_code, &vd, &d, &op_encoding);
4559 int vm, m;
4560 NeonSplitCode(reg_type, src_code, &vm, &m, &op_encoding);
4561
4562 return 0x1E5U * B23 | d * B22 | imm6 * B16 | vd * B12 | m * B5 | B4 | vm |
4563 op_encoding;
4564 }
4565
vshl(NeonDataType dt,QwNeonRegister dst,QwNeonRegister src,int shift)4566 void Assembler::vshl(NeonDataType dt, QwNeonRegister dst, QwNeonRegister src,
4567 int shift) {
4568 DCHECK(IsEnabled(NEON));
4569 // Qd = vshl(Qm, bits) SIMD shift left immediate.
4570 // Instruction details available in ARM DDI 0406C.b, A8-1046.
4571 emit(EncodeNeonShiftOp(VSHL, NeonDataTypeToSize(dt), false, NEON_Q,
4572 dst.code(), src.code(), shift));
4573 }
4574
vshr(NeonDataType dt,QwNeonRegister dst,QwNeonRegister src,int shift)4575 void Assembler::vshr(NeonDataType dt, QwNeonRegister dst, QwNeonRegister src,
4576 int shift) {
4577 DCHECK(IsEnabled(NEON));
4578 // Qd = vshl(Qm, bits) SIMD shift right immediate.
4579 // Instruction details available in ARM DDI 0406C.b, A8-1052.
4580 emit(EncodeNeonShiftOp(VSHR, NeonDataTypeToSize(dt), NeonU(dt), NEON_Q,
4581 dst.code(), src.code(), shift));
4582 }
4583
vsli(NeonSize size,DwVfpRegister dst,DwVfpRegister src,int shift)4584 void Assembler::vsli(NeonSize size, DwVfpRegister dst, DwVfpRegister src,
4585 int shift) {
4586 DCHECK(IsEnabled(NEON));
4587 // Dd = vsli(Dm, bits) SIMD shift left and insert.
4588 // Instruction details available in ARM DDI 0406C.b, A8-1056.
4589 emit(EncodeNeonShiftOp(VSLI, size, false, NEON_D, dst.code(), src.code(),
4590 shift));
4591 }
4592
vsri(NeonSize size,DwVfpRegister dst,DwVfpRegister src,int shift)4593 void Assembler::vsri(NeonSize size, DwVfpRegister dst, DwVfpRegister src,
4594 int shift) {
4595 DCHECK(IsEnabled(NEON));
4596 // Dd = vsri(Dm, bits) SIMD shift right and insert.
4597 // Instruction details available in ARM DDI 0406C.b, A8-1062.
4598 emit(EncodeNeonShiftOp(VSRI, size, false, NEON_D, dst.code(), src.code(),
4599 shift));
4600 }
4601
EncodeNeonEstimateOp(bool is_rsqrt,QwNeonRegister dst,QwNeonRegister src)4602 static Instr EncodeNeonEstimateOp(bool is_rsqrt, QwNeonRegister dst,
4603 QwNeonRegister src) {
4604 int vd, d;
4605 dst.split_code(&vd, &d);
4606 int vm, m;
4607 src.split_code(&vm, &m);
4608 int rsqrt = is_rsqrt ? 1 : 0;
4609 return 0x1E7U * B23 | d * B22 | 0x3B * B16 | vd * B12 | 0x5 * B8 |
4610 rsqrt * B7 | B6 | m * B5 | vm;
4611 }
4612
vrecpe(QwNeonRegister dst,QwNeonRegister src)4613 void Assembler::vrecpe(QwNeonRegister dst, QwNeonRegister src) {
4614 DCHECK(IsEnabled(NEON));
4615 // Qd = vrecpe(Qm) SIMD reciprocal estimate.
4616 // Instruction details available in ARM DDI 0406C.b, A8-1024.
4617 emit(EncodeNeonEstimateOp(false, dst, src));
4618 }
4619
vrsqrte(QwNeonRegister dst,QwNeonRegister src)4620 void Assembler::vrsqrte(QwNeonRegister dst, QwNeonRegister src) {
4621 DCHECK(IsEnabled(NEON));
4622 // Qd = vrsqrte(Qm) SIMD reciprocal square root estimate.
4623 // Instruction details available in ARM DDI 0406C.b, A8-1038.
4624 emit(EncodeNeonEstimateOp(true, dst, src));
4625 }
4626
vrecps(QwNeonRegister dst,QwNeonRegister src1,QwNeonRegister src2)4627 void Assembler::vrecps(QwNeonRegister dst, QwNeonRegister src1,
4628 QwNeonRegister src2) {
4629 DCHECK(IsEnabled(NEON));
4630 // Qd = vrecps(Qn, Qm) SIMD reciprocal refinement step.
4631 // Instruction details available in ARM DDI 0406C.b, A8-1026.
4632 emit(EncodeNeonBinOp(VRECPS, dst, src1, src2));
4633 }
4634
vrsqrts(QwNeonRegister dst,QwNeonRegister src1,QwNeonRegister src2)4635 void Assembler::vrsqrts(QwNeonRegister dst, QwNeonRegister src1,
4636 QwNeonRegister src2) {
4637 DCHECK(IsEnabled(NEON));
4638 // Qd = vrsqrts(Qn, Qm) SIMD reciprocal square root refinement step.
4639 // Instruction details available in ARM DDI 0406C.b, A8-1040.
4640 emit(EncodeNeonBinOp(VRSQRTS, dst, src1, src2));
4641 }
4642
4643 enum NeonPairwiseOp { VPADD, VPMIN, VPMAX };
4644
EncodeNeonPairwiseOp(NeonPairwiseOp op,NeonDataType dt,DwVfpRegister dst,DwVfpRegister src1,DwVfpRegister src2)4645 static Instr EncodeNeonPairwiseOp(NeonPairwiseOp op, NeonDataType dt,
4646 DwVfpRegister dst, DwVfpRegister src1,
4647 DwVfpRegister src2) {
4648 int op_encoding = 0;
4649 switch (op) {
4650 case VPADD:
4651 op_encoding = 0xB * B8 | B4;
4652 break;
4653 case VPMIN:
4654 op_encoding = 0xA * B8 | B4;
4655 break;
4656 case VPMAX:
4657 op_encoding = 0xA * B8;
4658 break;
4659 default:
4660 UNREACHABLE();
4661 break;
4662 }
4663 int vd, d;
4664 dst.split_code(&vd, &d);
4665 int vn, n;
4666 src1.split_code(&vn, &n);
4667 int vm, m;
4668 src2.split_code(&vm, &m);
4669 int size = NeonSz(dt);
4670 int u = NeonU(dt);
4671 return 0x1E4U * B23 | u * B24 | d * B22 | size * B20 | vn * B16 | vd * B12 |
4672 n * B7 | m * B5 | vm | op_encoding;
4673 }
4674
vpadd(DwVfpRegister dst,DwVfpRegister src1,DwVfpRegister src2)4675 void Assembler::vpadd(DwVfpRegister dst, DwVfpRegister src1,
4676 DwVfpRegister src2) {
4677 DCHECK(IsEnabled(NEON));
4678 // Dd = vpadd(Dn, Dm) SIMD integer pairwise ADD.
4679 // Instruction details available in ARM DDI 0406C.b, A8-982.
4680 int vd, d;
4681 dst.split_code(&vd, &d);
4682 int vn, n;
4683 src1.split_code(&vn, &n);
4684 int vm, m;
4685 src2.split_code(&vm, &m);
4686
4687 emit(0x1E6U * B23 | d * B22 | vn * B16 | vd * B12 | 0xD * B8 | n * B7 |
4688 m * B5 | vm);
4689 }
4690
vpadd(NeonSize size,DwVfpRegister dst,DwVfpRegister src1,DwVfpRegister src2)4691 void Assembler::vpadd(NeonSize size, DwVfpRegister dst, DwVfpRegister src1,
4692 DwVfpRegister src2) {
4693 DCHECK(IsEnabled(NEON));
4694 // Dd = vpadd(Dn, Dm) SIMD integer pairwise ADD.
4695 // Instruction details available in ARM DDI 0406C.b, A8-980.
4696 emit(EncodeNeonPairwiseOp(VPADD, NeonSizeToDataType(size), dst, src1, src2));
4697 }
4698
vpmin(NeonDataType dt,DwVfpRegister dst,DwVfpRegister src1,DwVfpRegister src2)4699 void Assembler::vpmin(NeonDataType dt, DwVfpRegister dst, DwVfpRegister src1,
4700 DwVfpRegister src2) {
4701 DCHECK(IsEnabled(NEON));
4702 // Dd = vpmin(Dn, Dm) SIMD integer pairwise MIN.
4703 // Instruction details available in ARM DDI 0406C.b, A8-986.
4704 emit(EncodeNeonPairwiseOp(VPMIN, dt, dst, src1, src2));
4705 }
4706
vpmax(NeonDataType dt,DwVfpRegister dst,DwVfpRegister src1,DwVfpRegister src2)4707 void Assembler::vpmax(NeonDataType dt, DwVfpRegister dst, DwVfpRegister src1,
4708 DwVfpRegister src2) {
4709 DCHECK(IsEnabled(NEON));
4710 // Dd = vpmax(Dn, Dm) SIMD integer pairwise MAX.
4711 // Instruction details available in ARM DDI 0406C.b, A8-986.
4712 emit(EncodeNeonPairwiseOp(VPMAX, dt, dst, src1, src2));
4713 }
4714
vtst(NeonSize size,QwNeonRegister dst,QwNeonRegister src1,QwNeonRegister src2)4715 void Assembler::vtst(NeonSize size, QwNeonRegister dst, QwNeonRegister src1,
4716 QwNeonRegister src2) {
4717 DCHECK(IsEnabled(NEON));
4718 // Qd = vtst(Qn, Qm) SIMD test integer operands.
4719 // Instruction details available in ARM DDI 0406C.b, A8-1098.
4720 emit(EncodeNeonBinOp(VTST, size, dst, src1, src2));
4721 }
4722
vceq(QwNeonRegister dst,QwNeonRegister src1,QwNeonRegister src2)4723 void Assembler::vceq(QwNeonRegister dst, QwNeonRegister src1,
4724 QwNeonRegister src2) {
4725 DCHECK(IsEnabled(NEON));
4726 // Qd = vceq(Qn, Qm) SIMD floating point compare equal.
4727 // Instruction details available in ARM DDI 0406C.b, A8-844.
4728 emit(EncodeNeonBinOp(VCEQF, dst, src1, src2));
4729 }
4730
vceq(NeonSize size,QwNeonRegister dst,QwNeonRegister src1,QwNeonRegister src2)4731 void Assembler::vceq(NeonSize size, QwNeonRegister dst, QwNeonRegister src1,
4732 QwNeonRegister src2) {
4733 DCHECK(IsEnabled(NEON));
4734 // Qd = vceq(Qn, Qm) SIMD integer compare equal.
4735 // Instruction details available in ARM DDI 0406C.b, A8-844.
4736 emit(EncodeNeonBinOp(VCEQ, size, dst, src1, src2));
4737 }
4738
vcge(QwNeonRegister dst,QwNeonRegister src1,QwNeonRegister src2)4739 void Assembler::vcge(QwNeonRegister dst, QwNeonRegister src1,
4740 QwNeonRegister src2) {
4741 DCHECK(IsEnabled(NEON));
4742 // Qd = vcge(Qn, Qm) SIMD floating point compare greater or equal.
4743 // Instruction details available in ARM DDI 0406C.b, A8-848.
4744 emit(EncodeNeonBinOp(VCGEF, dst, src1, src2));
4745 }
4746
vcge(NeonDataType dt,QwNeonRegister dst,QwNeonRegister src1,QwNeonRegister src2)4747 void Assembler::vcge(NeonDataType dt, QwNeonRegister dst, QwNeonRegister src1,
4748 QwNeonRegister src2) {
4749 DCHECK(IsEnabled(NEON));
4750 // Qd = vcge(Qn, Qm) SIMD integer compare greater or equal.
4751 // Instruction details available in ARM DDI 0406C.b, A8-848.
4752 emit(EncodeNeonBinOp(VCGE, dt, dst, src1, src2));
4753 }
4754
vcgt(QwNeonRegister dst,QwNeonRegister src1,QwNeonRegister src2)4755 void Assembler::vcgt(QwNeonRegister dst, QwNeonRegister src1,
4756 QwNeonRegister src2) {
4757 DCHECK(IsEnabled(NEON));
4758 // Qd = vcgt(Qn, Qm) SIMD floating point compare greater than.
4759 // Instruction details available in ARM DDI 0406C.b, A8-852.
4760 emit(EncodeNeonBinOp(VCGTF, dst, src1, src2));
4761 }
4762
vcgt(NeonDataType dt,QwNeonRegister dst,QwNeonRegister src1,QwNeonRegister src2)4763 void Assembler::vcgt(NeonDataType dt, QwNeonRegister dst, QwNeonRegister src1,
4764 QwNeonRegister src2) {
4765 DCHECK(IsEnabled(NEON));
4766 // Qd = vcgt(Qn, Qm) SIMD integer compare greater than.
4767 // Instruction details available in ARM DDI 0406C.b, A8-852.
4768 emit(EncodeNeonBinOp(VCGT, dt, dst, src1, src2));
4769 }
4770
vext(QwNeonRegister dst,QwNeonRegister src1,QwNeonRegister src2,int bytes)4771 void Assembler::vext(QwNeonRegister dst, QwNeonRegister src1,
4772 QwNeonRegister src2, int bytes) {
4773 DCHECK(IsEnabled(NEON));
4774 // Qd = vext(Qn, Qm) SIMD byte extract.
4775 // Instruction details available in ARM DDI 0406C.b, A8-890.
4776 int vd, d;
4777 dst.split_code(&vd, &d);
4778 int vn, n;
4779 src1.split_code(&vn, &n);
4780 int vm, m;
4781 src2.split_code(&vm, &m);
4782 DCHECK_GT(16, bytes);
4783 emit(0x1E5U * B23 | d * B22 | 0x3 * B20 | vn * B16 | vd * B12 | bytes * B8 |
4784 n * B7 | B6 | m * B5 | vm);
4785 }
4786
4787 enum NeonSizedOp { VZIP, VUZP, VREV16, VREV32, VREV64, VTRN };
4788
EncodeNeonSizedOp(NeonSizedOp op,NeonRegType reg_type,NeonSize size,int dst_code,int src_code)4789 static Instr EncodeNeonSizedOp(NeonSizedOp op, NeonRegType reg_type,
4790 NeonSize size, int dst_code, int src_code) {
4791 int op_encoding = 0;
4792 switch (op) {
4793 case VZIP:
4794 op_encoding = 0x2 * B16 | 0x3 * B7;
4795 break;
4796 case VUZP:
4797 op_encoding = 0x2 * B16 | 0x2 * B7;
4798 break;
4799 case VREV16:
4800 op_encoding = 0x2 * B7;
4801 break;
4802 case VREV32:
4803 op_encoding = 0x1 * B7;
4804 break;
4805 case VREV64:
4806 // op_encoding is 0;
4807 break;
4808 case VTRN:
4809 op_encoding = 0x2 * B16 | B7;
4810 break;
4811 default:
4812 UNREACHABLE();
4813 break;
4814 }
4815 int vd, d;
4816 NeonSplitCode(reg_type, dst_code, &vd, &d, &op_encoding);
4817 int vm, m;
4818 NeonSplitCode(reg_type, src_code, &vm, &m, &op_encoding);
4819
4820 int sz = static_cast<int>(size);
4821 return 0x1E7U * B23 | d * B22 | 0x3 * B20 | sz * B18 | vd * B12 | m * B5 |
4822 vm | op_encoding;
4823 }
4824
vzip(NeonSize size,DwVfpRegister src1,DwVfpRegister src2)4825 void Assembler::vzip(NeonSize size, DwVfpRegister src1, DwVfpRegister src2) {
4826 if (size == Neon32) { // vzip.32 Dd, Dm is a pseudo-op for vtrn.32 Dd, Dm.
4827 vtrn(size, src1, src2);
4828 } else {
4829 DCHECK(IsEnabled(NEON));
4830 // vzip.<size>(Dn, Dm) SIMD zip (interleave).
4831 // Instruction details available in ARM DDI 0406C.b, A8-1102.
4832 emit(EncodeNeonSizedOp(VZIP, NEON_D, size, src1.code(), src2.code()));
4833 }
4834 }
4835
vzip(NeonSize size,QwNeonRegister src1,QwNeonRegister src2)4836 void Assembler::vzip(NeonSize size, QwNeonRegister src1, QwNeonRegister src2) {
4837 DCHECK(IsEnabled(NEON));
4838 // vzip.<size>(Qn, Qm) SIMD zip (interleave).
4839 // Instruction details available in ARM DDI 0406C.b, A8-1102.
4840 emit(EncodeNeonSizedOp(VZIP, NEON_Q, size, src1.code(), src2.code()));
4841 }
4842
vuzp(NeonSize size,DwVfpRegister src1,DwVfpRegister src2)4843 void Assembler::vuzp(NeonSize size, DwVfpRegister src1, DwVfpRegister src2) {
4844 if (size == Neon32) { // vuzp.32 Dd, Dm is a pseudo-op for vtrn.32 Dd, Dm.
4845 vtrn(size, src1, src2);
4846 } else {
4847 DCHECK(IsEnabled(NEON));
4848 // vuzp.<size>(Dn, Dm) SIMD un-zip (de-interleave).
4849 // Instruction details available in ARM DDI 0406C.b, A8-1100.
4850 emit(EncodeNeonSizedOp(VUZP, NEON_D, size, src1.code(), src2.code()));
4851 }
4852 }
4853
vuzp(NeonSize size,QwNeonRegister src1,QwNeonRegister src2)4854 void Assembler::vuzp(NeonSize size, QwNeonRegister src1, QwNeonRegister src2) {
4855 DCHECK(IsEnabled(NEON));
4856 // vuzp.<size>(Qn, Qm) SIMD un-zip (de-interleave).
4857 // Instruction details available in ARM DDI 0406C.b, A8-1100.
4858 emit(EncodeNeonSizedOp(VUZP, NEON_Q, size, src1.code(), src2.code()));
4859 }
4860
vrev16(NeonSize size,QwNeonRegister dst,QwNeonRegister src)4861 void Assembler::vrev16(NeonSize size, QwNeonRegister dst, QwNeonRegister src) {
4862 DCHECK(IsEnabled(NEON));
4863 // Qd = vrev16.<size>(Qm) SIMD element reverse.
4864 // Instruction details available in ARM DDI 0406C.b, A8-1028.
4865 emit(EncodeNeonSizedOp(VREV16, NEON_Q, size, dst.code(), src.code()));
4866 }
4867
vrev32(NeonSize size,QwNeonRegister dst,QwNeonRegister src)4868 void Assembler::vrev32(NeonSize size, QwNeonRegister dst, QwNeonRegister src) {
4869 DCHECK(IsEnabled(NEON));
4870 // Qd = vrev32.<size>(Qm) SIMD element reverse.
4871 // Instruction details available in ARM DDI 0406C.b, A8-1028.
4872 emit(EncodeNeonSizedOp(VREV32, NEON_Q, size, dst.code(), src.code()));
4873 }
4874
vrev64(NeonSize size,QwNeonRegister dst,QwNeonRegister src)4875 void Assembler::vrev64(NeonSize size, QwNeonRegister dst, QwNeonRegister src) {
4876 DCHECK(IsEnabled(NEON));
4877 // Qd = vrev64.<size>(Qm) SIMD element reverse.
4878 // Instruction details available in ARM DDI 0406C.b, A8-1028.
4879 emit(EncodeNeonSizedOp(VREV64, NEON_Q, size, dst.code(), src.code()));
4880 }
4881
vtrn(NeonSize size,DwVfpRegister src1,DwVfpRegister src2)4882 void Assembler::vtrn(NeonSize size, DwVfpRegister src1, DwVfpRegister src2) {
4883 DCHECK(IsEnabled(NEON));
4884 // vtrn.<size>(Dn, Dm) SIMD element transpose.
4885 // Instruction details available in ARM DDI 0406C.b, A8-1096.
4886 emit(EncodeNeonSizedOp(VTRN, NEON_D, size, src1.code(), src2.code()));
4887 }
4888
vtrn(NeonSize size,QwNeonRegister src1,QwNeonRegister src2)4889 void Assembler::vtrn(NeonSize size, QwNeonRegister src1, QwNeonRegister src2) {
4890 DCHECK(IsEnabled(NEON));
4891 // vtrn.<size>(Qn, Qm) SIMD element transpose.
4892 // Instruction details available in ARM DDI 0406C.b, A8-1096.
4893 emit(EncodeNeonSizedOp(VTRN, NEON_Q, size, src1.code(), src2.code()));
4894 }
4895
4896 // Encode NEON vtbl / vtbx instruction.
EncodeNeonVTB(DwVfpRegister dst,const NeonListOperand & list,DwVfpRegister index,bool vtbx)4897 static Instr EncodeNeonVTB(DwVfpRegister dst, const NeonListOperand& list,
4898 DwVfpRegister index, bool vtbx) {
4899 // Dd = vtbl(table, Dm) SIMD vector permute, zero at out of range indices.
4900 // Instruction details available in ARM DDI 0406C.b, A8-1094.
4901 // Dd = vtbx(table, Dm) SIMD vector permute, skip out of range indices.
4902 // Instruction details available in ARM DDI 0406C.b, A8-1094.
4903 int vd, d;
4904 dst.split_code(&vd, &d);
4905 int vn, n;
4906 list.base().split_code(&vn, &n);
4907 int vm, m;
4908 index.split_code(&vm, &m);
4909 int op = vtbx ? 1 : 0; // vtbl = 0, vtbx = 1.
4910 return 0x1E7U * B23 | d * B22 | 0x3 * B20 | vn * B16 | vd * B12 | 0x2 * B10 |
4911 list.length() * B8 | n * B7 | op * B6 | m * B5 | vm;
4912 }
4913
vtbl(DwVfpRegister dst,const NeonListOperand & list,DwVfpRegister index)4914 void Assembler::vtbl(DwVfpRegister dst, const NeonListOperand& list,
4915 DwVfpRegister index) {
4916 DCHECK(IsEnabled(NEON));
4917 emit(EncodeNeonVTB(dst, list, index, false));
4918 }
4919
vtbx(DwVfpRegister dst,const NeonListOperand & list,DwVfpRegister index)4920 void Assembler::vtbx(DwVfpRegister dst, const NeonListOperand& list,
4921 DwVfpRegister index) {
4922 DCHECK(IsEnabled(NEON));
4923 emit(EncodeNeonVTB(dst, list, index, true));
4924 }
4925
4926 // Pseudo instructions.
nop(int type)4927 void Assembler::nop(int type) {
4928 // ARMv6{K/T2} and v7 have an actual NOP instruction but it serializes
4929 // some of the CPU's pipeline and has to issue. Older ARM chips simply used
4930 // MOV Rx, Rx as NOP and it performs better even in newer CPUs.
4931 // We therefore use MOV Rx, Rx, even on newer CPUs, and use Rx to encode
4932 // a type.
4933 DCHECK(0 <= type && type <= 14); // mov pc, pc isn't a nop.
4934 emit(al | 13*B21 | type*B12 | type);
4935 }
4936
pop()4937 void Assembler::pop() { add(sp, sp, Operand(kPointerSize)); }
4938
IsMovT(Instr instr)4939 bool Assembler::IsMovT(Instr instr) {
4940 instr &= ~(((kNumberOfConditions - 1) << 28) | // Mask off conditions
4941 ((kNumRegisters-1)*B12) | // mask out register
4942 EncodeMovwImmediate(0xFFFF)); // mask out immediate value
4943 return instr == kMovtPattern;
4944 }
4945
4946
IsMovW(Instr instr)4947 bool Assembler::IsMovW(Instr instr) {
4948 instr &= ~(((kNumberOfConditions - 1) << 28) | // Mask off conditions
4949 ((kNumRegisters-1)*B12) | // mask out destination
4950 EncodeMovwImmediate(0xFFFF)); // mask out immediate value
4951 return instr == kMovwPattern;
4952 }
4953
4954
GetMovTPattern()4955 Instr Assembler::GetMovTPattern() { return kMovtPattern; }
4956
4957
GetMovWPattern()4958 Instr Assembler::GetMovWPattern() { return kMovwPattern; }
4959
4960
EncodeMovwImmediate(uint32_t immediate)4961 Instr Assembler::EncodeMovwImmediate(uint32_t immediate) {
4962 DCHECK_LT(immediate, 0x10000);
4963 return ((immediate & 0xF000) << 4) | (immediate & 0xFFF);
4964 }
4965
4966
PatchMovwImmediate(Instr instruction,uint32_t immediate)4967 Instr Assembler::PatchMovwImmediate(Instr instruction, uint32_t immediate) {
4968 instruction &= ~EncodeMovwImmediate(0xFFFF);
4969 return instruction | EncodeMovwImmediate(immediate);
4970 }
4971
4972
DecodeShiftImm(Instr instr)4973 int Assembler::DecodeShiftImm(Instr instr) {
4974 int rotate = Instruction::RotateValue(instr) * 2;
4975 int immed8 = Instruction::Immed8Value(instr);
4976 return base::bits::RotateRight32(immed8, rotate);
4977 }
4978
4979
PatchShiftImm(Instr instr,int immed)4980 Instr Assembler::PatchShiftImm(Instr instr, int immed) {
4981 uint32_t rotate_imm = 0;
4982 uint32_t immed_8 = 0;
4983 bool immed_fits = FitsShifter(immed, &rotate_imm, &immed_8, nullptr);
4984 DCHECK(immed_fits);
4985 USE(immed_fits);
4986 return (instr & ~kOff12Mask) | (rotate_imm << 8) | immed_8;
4987 }
4988
4989
IsNop(Instr instr,int type)4990 bool Assembler::IsNop(Instr instr, int type) {
4991 DCHECK(0 <= type && type <= 14); // mov pc, pc isn't a nop.
4992 // Check for mov rx, rx where x = type.
4993 return instr == (al | 13*B21 | type*B12 | type);
4994 }
4995
4996
IsMovImmed(Instr instr)4997 bool Assembler::IsMovImmed(Instr instr) {
4998 return (instr & kMovImmedMask) == kMovImmedPattern;
4999 }
5000
5001
IsOrrImmed(Instr instr)5002 bool Assembler::IsOrrImmed(Instr instr) {
5003 return (instr & kOrrImmedMask) == kOrrImmedPattern;
5004 }
5005
5006
5007 // static
ImmediateFitsAddrMode1Instruction(int32_t imm32)5008 bool Assembler::ImmediateFitsAddrMode1Instruction(int32_t imm32) {
5009 uint32_t dummy1;
5010 uint32_t dummy2;
5011 return FitsShifter(imm32, &dummy1, &dummy2, nullptr);
5012 }
5013
5014
ImmediateFitsAddrMode2Instruction(int32_t imm32)5015 bool Assembler::ImmediateFitsAddrMode2Instruction(int32_t imm32) {
5016 return is_uint12(abs(imm32));
5017 }
5018
5019
5020 // Debugging.
RecordConstPool(int size)5021 void Assembler::RecordConstPool(int size) {
5022 // We only need this for debugger support, to correctly compute offsets in the
5023 // code.
5024 RecordRelocInfo(RelocInfo::CONST_POOL, static_cast<intptr_t>(size));
5025 }
5026
5027
GrowBuffer()5028 void Assembler::GrowBuffer() {
5029 if (!own_buffer_) FATAL("external code buffer is too small");
5030
5031 // Compute new buffer size.
5032 CodeDesc desc; // the new buffer
5033 if (buffer_size_ < 1 * MB) {
5034 desc.buffer_size = 2*buffer_size_;
5035 } else {
5036 desc.buffer_size = buffer_size_ + 1*MB;
5037 }
5038
5039 // Some internal data structures overflow for very large buffers,
5040 // they must ensure that kMaximalBufferSize is not too large.
5041 if (desc.buffer_size > kMaximalBufferSize) {
5042 V8::FatalProcessOutOfMemory(nullptr, "Assembler::GrowBuffer");
5043 }
5044
5045 // Set up new buffer.
5046 desc.buffer = NewArray<byte>(desc.buffer_size);
5047
5048 desc.instr_size = pc_offset();
5049 desc.reloc_size = (buffer_ + buffer_size_) - reloc_info_writer.pos();
5050 desc.origin = this;
5051
5052 // Copy the data.
5053 int pc_delta = desc.buffer - buffer_;
5054 int rc_delta = (desc.buffer + desc.buffer_size) - (buffer_ + buffer_size_);
5055 MemMove(desc.buffer, buffer_, desc.instr_size);
5056 MemMove(reloc_info_writer.pos() + rc_delta, reloc_info_writer.pos(),
5057 desc.reloc_size);
5058
5059 // Switch buffers.
5060 DeleteArray(buffer_);
5061 buffer_ = desc.buffer;
5062 buffer_size_ = desc.buffer_size;
5063 pc_ += pc_delta;
5064 reloc_info_writer.Reposition(reloc_info_writer.pos() + rc_delta,
5065 reloc_info_writer.last_pc() + pc_delta);
5066
5067 // None of our relocation types are pc relative pointing outside the code
5068 // buffer nor pc absolute pointing inside the code buffer, so there is no need
5069 // to relocate any emitted relocation entries.
5070 }
5071
5072
db(uint8_t data)5073 void Assembler::db(uint8_t data) {
5074 // db is used to write raw data. The constant pool should be emitted or
5075 // blocked before using db.
5076 DCHECK(is_const_pool_blocked() || pending_32_bit_constants_.empty());
5077 DCHECK(is_const_pool_blocked() || pending_64_bit_constants_.empty());
5078 CheckBuffer();
5079 *reinterpret_cast<uint8_t*>(pc_) = data;
5080 pc_ += sizeof(uint8_t);
5081 }
5082
5083
dd(uint32_t data)5084 void Assembler::dd(uint32_t data) {
5085 // dd is used to write raw data. The constant pool should be emitted or
5086 // blocked before using dd.
5087 DCHECK(is_const_pool_blocked() || pending_32_bit_constants_.empty());
5088 DCHECK(is_const_pool_blocked() || pending_64_bit_constants_.empty());
5089 CheckBuffer();
5090 *reinterpret_cast<uint32_t*>(pc_) = data;
5091 pc_ += sizeof(uint32_t);
5092 }
5093
5094
dq(uint64_t value)5095 void Assembler::dq(uint64_t value) {
5096 // dq is used to write raw data. The constant pool should be emitted or
5097 // blocked before using dq.
5098 DCHECK(is_const_pool_blocked() || pending_32_bit_constants_.empty());
5099 DCHECK(is_const_pool_blocked() || pending_64_bit_constants_.empty());
5100 CheckBuffer();
5101 *reinterpret_cast<uint64_t*>(pc_) = value;
5102 pc_ += sizeof(uint64_t);
5103 }
5104
RecordRelocInfo(RelocInfo::Mode rmode,intptr_t data)5105 void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) {
5106 if (options().disable_reloc_info_for_patching) return;
5107 if (RelocInfo::IsNone(rmode) ||
5108 // Don't record external references unless the heap will be serialized.
5109 (RelocInfo::IsOnlyForSerializer(rmode) &&
5110 !options().record_reloc_info_for_serialization && !emit_debug_code())) {
5111 return;
5112 }
5113 DCHECK_GE(buffer_space(), kMaxRelocSize); // too late to grow buffer here
5114 RelocInfo rinfo(reinterpret_cast<Address>(pc_), rmode, data, nullptr);
5115 reloc_info_writer.Write(&rinfo);
5116 }
5117
ConstantPoolAddEntry(int position,RelocInfo::Mode rmode,intptr_t value)5118 void Assembler::ConstantPoolAddEntry(int position, RelocInfo::Mode rmode,
5119 intptr_t value) {
5120 DCHECK(rmode != RelocInfo::COMMENT && rmode != RelocInfo::CONST_POOL);
5121 // We can share CODE_TARGETs because we don't patch the code objects anymore,
5122 // and we make sure we emit only one reloc info for them (thus delta patching)
5123 // will apply the delta only once. At the moment, we do not dedup code targets
5124 // if they are wrapped in a heap object request (value == 0).
5125 bool sharing_ok = RelocInfo::IsShareableRelocMode(rmode) ||
5126 (rmode == RelocInfo::CODE_TARGET && value != 0);
5127 DCHECK_LT(pending_32_bit_constants_.size(), kMaxNumPending32Constants);
5128 if (pending_32_bit_constants_.empty()) {
5129 first_const_pool_32_use_ = position;
5130 }
5131 ConstantPoolEntry entry(position, value, sharing_ok, rmode);
5132
5133 bool shared = false;
5134 if (sharing_ok) {
5135 // Merge the constant, if possible.
5136 for (size_t i = 0; i < pending_32_bit_constants_.size(); i++) {
5137 ConstantPoolEntry& current_entry = pending_32_bit_constants_[i];
5138 if (!current_entry.sharing_ok()) continue;
5139 if (entry.value() == current_entry.value() &&
5140 entry.rmode() == current_entry.rmode()) {
5141 entry.set_merged_index(i);
5142 shared = true;
5143 break;
5144 }
5145 }
5146 }
5147
5148 pending_32_bit_constants_.push_back(entry);
5149
5150 // Make sure the constant pool is not emitted in place of the next
5151 // instruction for which we just recorded relocation info.
5152 BlockConstPoolFor(1);
5153
5154 // Emit relocation info.
5155 if (MustOutputRelocInfo(rmode, this) && !shared) {
5156 RecordRelocInfo(rmode);
5157 }
5158 }
5159
BlockConstPoolFor(int instructions)5160 void Assembler::BlockConstPoolFor(int instructions) {
5161 int pc_limit = pc_offset() + instructions * kInstrSize;
5162 if (no_const_pool_before_ < pc_limit) {
5163 // Max pool start (if we need a jump and an alignment).
5164 #ifdef DEBUG
5165 int start = pc_limit + kInstrSize + 2 * kPointerSize;
5166 DCHECK(pending_32_bit_constants_.empty() ||
5167 (start - first_const_pool_32_use_ +
5168 pending_64_bit_constants_.size() * kDoubleSize <
5169 kMaxDistToIntPool));
5170 DCHECK(pending_64_bit_constants_.empty() ||
5171 (start - first_const_pool_64_use_ < kMaxDistToFPPool));
5172 #endif
5173 no_const_pool_before_ = pc_limit;
5174 }
5175
5176 if (next_buffer_check_ < no_const_pool_before_) {
5177 next_buffer_check_ = no_const_pool_before_;
5178 }
5179 }
5180
5181
CheckConstPool(bool force_emit,bool require_jump)5182 void Assembler::CheckConstPool(bool force_emit, bool require_jump) {
5183 // Some short sequence of instruction mustn't be broken up by constant pool
5184 // emission, such sequences are protected by calls to BlockConstPoolFor and
5185 // BlockConstPoolScope.
5186 if (is_const_pool_blocked()) {
5187 // Something is wrong if emission is forced and blocked at the same time.
5188 DCHECK(!force_emit);
5189 return;
5190 }
5191
5192 // There is nothing to do if there are no pending constant pool entries.
5193 if (pending_32_bit_constants_.empty() && pending_64_bit_constants_.empty()) {
5194 // Calculate the offset of the next check.
5195 next_buffer_check_ = pc_offset() + kCheckPoolInterval;
5196 return;
5197 }
5198
5199 // Check that the code buffer is large enough before emitting the constant
5200 // pool (include the jump over the pool and the constant pool marker and
5201 // the gap to the relocation information).
5202 int jump_instr = require_jump ? kInstrSize : 0;
5203 int size_up_to_marker = jump_instr + kInstrSize;
5204 int estimated_size_after_marker =
5205 pending_32_bit_constants_.size() * kPointerSize;
5206 bool has_int_values = !pending_32_bit_constants_.empty();
5207 bool has_fp_values = !pending_64_bit_constants_.empty();
5208 bool require_64_bit_align = false;
5209 if (has_fp_values) {
5210 require_64_bit_align =
5211 !IsAligned(reinterpret_cast<intptr_t>(pc_ + size_up_to_marker),
5212 kDoubleAlignment);
5213 if (require_64_bit_align) {
5214 estimated_size_after_marker += kInstrSize;
5215 }
5216 estimated_size_after_marker +=
5217 pending_64_bit_constants_.size() * kDoubleSize;
5218 }
5219 int estimated_size = size_up_to_marker + estimated_size_after_marker;
5220
5221 // We emit a constant pool when:
5222 // * requested to do so by parameter force_emit (e.g. after each function).
5223 // * the distance from the first instruction accessing the constant pool to
5224 // any of the constant pool entries will exceed its limit the next
5225 // time the pool is checked. This is overly restrictive, but we don't emit
5226 // constant pool entries in-order so it's conservatively correct.
5227 // * the instruction doesn't require a jump after itself to jump over the
5228 // constant pool, and we're getting close to running out of range.
5229 if (!force_emit) {
5230 DCHECK(has_fp_values || has_int_values);
5231 bool need_emit = false;
5232 if (has_fp_values) {
5233 // The 64-bit constants are always emitted before the 32-bit constants, so
5234 // we can ignore the effect of the 32-bit constants on estimated_size.
5235 int dist64 = pc_offset() + estimated_size -
5236 pending_32_bit_constants_.size() * kPointerSize -
5237 first_const_pool_64_use_;
5238 if ((dist64 >= kMaxDistToFPPool - kCheckPoolInterval) ||
5239 (!require_jump && (dist64 >= kMaxDistToFPPool / 2))) {
5240 need_emit = true;
5241 }
5242 }
5243 if (has_int_values) {
5244 int dist32 = pc_offset() + estimated_size - first_const_pool_32_use_;
5245 if ((dist32 >= kMaxDistToIntPool - kCheckPoolInterval) ||
5246 (!require_jump && (dist32 >= kMaxDistToIntPool / 2))) {
5247 need_emit = true;
5248 }
5249 }
5250 if (!need_emit) return;
5251 }
5252
5253 // Deduplicate constants.
5254 int size_after_marker = estimated_size_after_marker;
5255 for (size_t i = 0; i < pending_64_bit_constants_.size(); i++) {
5256 ConstantPoolEntry& entry = pending_64_bit_constants_[i];
5257 if (entry.is_merged()) size_after_marker -= kDoubleSize;
5258 }
5259
5260 for (size_t i = 0; i < pending_32_bit_constants_.size(); i++) {
5261 ConstantPoolEntry& entry = pending_32_bit_constants_[i];
5262 if (entry.is_merged()) size_after_marker -= kPointerSize;
5263 }
5264
5265 int size = size_up_to_marker + size_after_marker;
5266
5267 int needed_space = size + kGap;
5268 while (buffer_space() <= needed_space) GrowBuffer();
5269
5270 {
5271 // Block recursive calls to CheckConstPool.
5272 BlockConstPoolScope block_const_pool(this);
5273 RecordComment("[ Constant Pool");
5274 RecordConstPool(size);
5275
5276 Label size_check;
5277 bind(&size_check);
5278
5279 // Emit jump over constant pool if necessary.
5280 Label after_pool;
5281 if (require_jump) {
5282 b(&after_pool);
5283 }
5284
5285 // Put down constant pool marker "Undefined instruction".
5286 // The data size helps disassembly know what to print.
5287 emit(kConstantPoolMarker |
5288 EncodeConstantPoolLength(size_after_marker / kPointerSize));
5289
5290 if (require_64_bit_align) {
5291 emit(kConstantPoolMarker);
5292 }
5293
5294 // Emit 64-bit constant pool entries first: their range is smaller than
5295 // 32-bit entries.
5296 for (size_t i = 0; i < pending_64_bit_constants_.size(); i++) {
5297 ConstantPoolEntry& entry = pending_64_bit_constants_[i];
5298
5299 Instr instr = instr_at(entry.position());
5300 // Instruction to patch must be 'vldr rd, [pc, #offset]' with offset == 0.
5301 DCHECK((IsVldrDPcImmediateOffset(instr) &&
5302 GetVldrDRegisterImmediateOffset(instr) == 0));
5303
5304 int delta = pc_offset() - entry.position() - Instruction::kPcLoadDelta;
5305 DCHECK(is_uint10(delta));
5306
5307 if (entry.is_merged()) {
5308 ConstantPoolEntry& merged =
5309 pending_64_bit_constants_[entry.merged_index()];
5310 DCHECK(entry.value64() == merged.value64());
5311 Instr merged_instr = instr_at(merged.position());
5312 DCHECK(IsVldrDPcImmediateOffset(merged_instr));
5313 delta = GetVldrDRegisterImmediateOffset(merged_instr);
5314 delta += merged.position() - entry.position();
5315 }
5316 instr_at_put(entry.position(),
5317 SetVldrDRegisterImmediateOffset(instr, delta));
5318 if (!entry.is_merged()) {
5319 DCHECK(IsAligned(reinterpret_cast<intptr_t>(pc_), kDoubleAlignment));
5320 dq(entry.value64());
5321 }
5322 }
5323
5324 // Emit 32-bit constant pool entries.
5325 for (size_t i = 0; i < pending_32_bit_constants_.size(); i++) {
5326 ConstantPoolEntry& entry = pending_32_bit_constants_[i];
5327 Instr instr = instr_at(entry.position());
5328
5329 // 64-bit loads shouldn't get here.
5330 DCHECK(!IsVldrDPcImmediateOffset(instr));
5331 DCHECK(!IsMovW(instr));
5332 DCHECK(IsLdrPcImmediateOffset(instr) &&
5333 GetLdrRegisterImmediateOffset(instr) == 0);
5334
5335 int delta = pc_offset() - entry.position() - Instruction::kPcLoadDelta;
5336 DCHECK(is_uint12(delta));
5337 // 0 is the smallest delta:
5338 // ldr rd, [pc, #0]
5339 // constant pool marker
5340 // data
5341
5342 if (entry.is_merged()) {
5343 DCHECK(entry.sharing_ok());
5344 ConstantPoolEntry& merged =
5345 pending_32_bit_constants_[entry.merged_index()];
5346 DCHECK(entry.value() == merged.value());
5347 Instr merged_instr = instr_at(merged.position());
5348 DCHECK(IsLdrPcImmediateOffset(merged_instr));
5349 delta = GetLdrRegisterImmediateOffset(merged_instr);
5350 delta += merged.position() - entry.position();
5351 }
5352 instr_at_put(entry.position(),
5353 SetLdrRegisterImmediateOffset(instr, delta));
5354 if (!entry.is_merged()) {
5355 emit(entry.value());
5356 }
5357 }
5358
5359 pending_32_bit_constants_.clear();
5360 pending_64_bit_constants_.clear();
5361
5362 first_const_pool_32_use_ = -1;
5363 first_const_pool_64_use_ = -1;
5364
5365 RecordComment("]");
5366
5367 DCHECK_EQ(size, SizeOfCodeGeneratedSince(&size_check));
5368
5369 if (after_pool.is_linked()) {
5370 bind(&after_pool);
5371 }
5372 }
5373
5374 // Since a constant pool was just emitted, move the check offset forward by
5375 // the standard interval.
5376 next_buffer_check_ = pc_offset() + kCheckPoolInterval;
5377 }
5378
PatchingAssembler(const AssemblerOptions & options,byte * address,int instructions)5379 PatchingAssembler::PatchingAssembler(const AssemblerOptions& options,
5380 byte* address, int instructions)
5381 : Assembler(options, address, instructions * kInstrSize + kGap) {
5382 DCHECK_EQ(reloc_info_writer.pos(), buffer_ + buffer_size_);
5383 }
5384
~PatchingAssembler()5385 PatchingAssembler::~PatchingAssembler() {
5386 // Check that we don't have any pending constant pools.
5387 DCHECK(pending_32_bit_constants_.empty());
5388 DCHECK(pending_64_bit_constants_.empty());
5389
5390 // Check that the code was patched as expected.
5391 DCHECK_EQ(pc_, buffer_ + buffer_size_ - kGap);
5392 DCHECK_EQ(reloc_info_writer.pos(), buffer_ + buffer_size_);
5393 }
5394
Emit(Address addr)5395 void PatchingAssembler::Emit(Address addr) { emit(static_cast<Instr>(addr)); }
5396
UseScratchRegisterScope(Assembler * assembler)5397 UseScratchRegisterScope::UseScratchRegisterScope(Assembler* assembler)
5398 : assembler_(assembler),
5399 old_available_(*assembler->GetScratchRegisterList()),
5400 old_available_vfp_(*assembler->GetScratchVfpRegisterList()) {}
5401
~UseScratchRegisterScope()5402 UseScratchRegisterScope::~UseScratchRegisterScope() {
5403 *assembler_->GetScratchRegisterList() = old_available_;
5404 *assembler_->GetScratchVfpRegisterList() = old_available_vfp_;
5405 }
5406
Acquire()5407 Register UseScratchRegisterScope::Acquire() {
5408 RegList* available = assembler_->GetScratchRegisterList();
5409 DCHECK_NOT_NULL(available);
5410 DCHECK_NE(*available, 0);
5411 int index = static_cast<int>(base::bits::CountTrailingZeros32(*available));
5412 Register reg = Register::from_code(index);
5413 *available &= ~reg.bit();
5414 return reg;
5415 }
5416
5417 } // namespace internal
5418 } // namespace v8
5419
5420 #endif // V8_TARGET_ARCH_ARM
5421