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