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