blob: 1ccc3a6237cb10467980f790f7ff477071b1bb7e [file] [log] [blame]
Steve Blocka7e24c12009-10-30 11:49:00 +00001// 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
Leon Clarked91b9f72010-01-27 17:25:45 +000033// The original source code covered by the above license above has been
34// modified significantly by Google Inc.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000035// Copyright 2012 the V8 project authors. All rights reserved.
Steve Blocka7e24c12009-10-30 11:49:00 +000036
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000037#include "src/arm/assembler-arm.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000038
Ben Murdochb8a8cc12014-11-26 15:28:44 +000039#if V8_TARGET_ARCH_ARM
Leon Clarkef7060e22010-06-03 12:02:55 +010040
Ben Murdochb8a8cc12014-11-26 15:28:44 +000041#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"
Steve Blocka7e24c12009-10-30 11:49:00 +000045
46namespace v8 {
47namespace internal {
48
Ben Murdoch257744e2011-11-30 15:57:28 +000049// Get the CPU features enabled by the build. For cross compilation the
Ben Murdochb8a8cc12014-11-26 15:28:44 +000050// preprocessor symbols CAN_USE_ARMV7_INSTRUCTIONS and CAN_USE_VFP3_INSTRUCTIONS
Ben Murdoch257744e2011-11-30 15:57:28 +000051// can be defined to enable ARMv7 and VFPv3 instructions when building the
52// snapshot.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000053static unsigned CpuFeaturesImpliedByCompiler() {
54 unsigned answer = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000055#ifdef CAN_USE_ARMV8_INSTRUCTIONS
56 if (FLAG_enable_armv8) {
57 answer |= 1u << ARMv8;
58 // ARMv8 always features VFP and NEON.
59 answer |= 1u << ARMv7 | 1u << VFP3 | 1u << NEON | 1u << VFP32DREGS;
60 answer |= 1u << SUDIV | 1u << MLS;
61 }
62#endif // CAN_USE_ARMV8_INSTRUCTIONS
Andrei Popescu402d9372010-02-26 13:31:12 +000063#ifdef CAN_USE_ARMV7_INSTRUCTIONS
Ben Murdochb8a8cc12014-11-26 15:28:44 +000064 if (FLAG_enable_armv7) answer |= 1u << ARMv7;
65#endif // CAN_USE_ARMV7_INSTRUCTIONS
66#ifdef CAN_USE_VFP3_INSTRUCTIONS
67 if (FLAG_enable_vfp3) answer |= 1u << VFP3 | 1u << ARMv7;
68#endif // CAN_USE_VFP3_INSTRUCTIONS
69#ifdef CAN_USE_VFP32DREGS
70 if (FLAG_enable_32dregs) answer |= 1u << VFP32DREGS;
71#endif // CAN_USE_VFP32DREGS
72#ifdef CAN_USE_NEON
73 if (FLAG_enable_neon) answer |= 1u << NEON;
74#endif // CAN_USE_VFP32DREGS
75 if ((answer & (1u << ARMv7)) && FLAG_enable_unaligned_accesses) {
76 answer |= 1u << UNALIGNED_ACCESSES;
77 }
Ben Murdoch257744e2011-11-30 15:57:28 +000078
Andrei Popescu402d9372010-02-26 13:31:12 +000079 return answer;
80}
Andrei Popescu402d9372010-02-26 13:31:12 +000081
82
Ben Murdochb8a8cc12014-11-26 15:28:44 +000083void CpuFeatures::ProbeImpl(bool cross_compile) {
84 supported_ |= CpuFeaturesImpliedByCompiler();
Ben Murdoch097c5b22016-05-18 11:27:45 +010085 dcache_line_size_ = 64;
Ben Murdoch257744e2011-11-30 15:57:28 +000086
Ben Murdochb8a8cc12014-11-26 15:28:44 +000087 // Only use statically determined features for cross compile (snapshot).
88 if (cross_compile) return;
Ben Murdoch257744e2011-11-30 15:57:28 +000089
Andrei Popescu402d9372010-02-26 13:31:12 +000090#ifndef __arm__
Ben Murdochb8a8cc12014-11-26 15:28:44 +000091 // For the simulator build, use whatever the flags specify.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000092 if (FLAG_enable_armv8) {
93 supported_ |= 1u << ARMv8;
94 // ARMv8 always features VFP and NEON.
95 supported_ |= 1u << ARMv7 | 1u << VFP3 | 1u << NEON | 1u << VFP32DREGS;
96 supported_ |= 1u << SUDIV | 1u << MLS;
97 if (FLAG_enable_movw_movt) supported_ |= 1u << MOVW_MOVT_IMMEDIATE_LOADS;
98 }
Andrei Popescu31002712010-02-23 13:46:05 +000099 if (FLAG_enable_armv7) {
Steve Block6ded16b2010-05-10 14:33:55 +0100100 supported_ |= 1u << ARMv7;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000101 if (FLAG_enable_vfp3) supported_ |= 1u << VFP3;
102 if (FLAG_enable_neon) supported_ |= 1u << NEON | 1u << VFP32DREGS;
103 if (FLAG_enable_sudiv) supported_ |= 1u << SUDIV;
104 if (FLAG_enable_movw_movt) supported_ |= 1u << MOVW_MOVT_IMMEDIATE_LOADS;
105 if (FLAG_enable_32dregs) supported_ |= 1u << VFP32DREGS;
Andrei Popescu31002712010-02-23 13:46:05 +0000106 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000107 if (FLAG_enable_mls) supported_ |= 1u << MLS;
108 if (FLAG_enable_unaligned_accesses) supported_ |= 1u << UNALIGNED_ACCESSES;
109
110#else // __arm__
111 // Probe for additional features at runtime.
112 base::CPU cpu;
113 if (FLAG_enable_vfp3 && cpu.has_vfp3()) {
Ben Murdoch8b112d22011-06-08 16:22:53 +0100114 // This implementation also sets the VFP flags if runtime
115 // detection of VFP returns true. VFPv3 implies ARMv7, see ARM DDI
116 // 0406B, page A1-6.
117 supported_ |= 1u << VFP3 | 1u << ARMv7;
Steve Blockd0582a62009-12-15 09:54:21 +0000118 }
Andrei Popescu31002712010-02-23 13:46:05 +0000119
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000120 if (FLAG_enable_neon && cpu.has_neon()) supported_ |= 1u << NEON;
121 if (FLAG_enable_sudiv && cpu.has_idiva()) supported_ |= 1u << SUDIV;
122 if (FLAG_enable_mls && cpu.has_thumb2()) supported_ |= 1u << MLS;
123
124 if (cpu.architecture() >= 7) {
125 if (FLAG_enable_armv7) supported_ |= 1u << ARMv7;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400126 if (FLAG_enable_armv8 && cpu.architecture() >= 8) {
127 supported_ |= 1u << ARMv8;
128 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000129 if (FLAG_enable_unaligned_accesses) supported_ |= 1u << UNALIGNED_ACCESSES;
130 // Use movw/movt for QUALCOMM ARMv7 cores.
131 if (FLAG_enable_movw_movt && cpu.implementer() == base::CPU::QUALCOMM) {
132 supported_ |= 1u << MOVW_MOVT_IMMEDIATE_LOADS;
133 }
Andrei Popescu31002712010-02-23 13:46:05 +0000134 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000135
136 // ARM Cortex-A9 and Cortex-A5 have 32 byte cachelines.
137 if (cpu.implementer() == base::CPU::ARM &&
138 (cpu.part() == base::CPU::ARM_CORTEX_A5 ||
139 cpu.part() == base::CPU::ARM_CORTEX_A9)) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100140 dcache_line_size_ = 32;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000141 }
142
143 if (FLAG_enable_32dregs && cpu.has_vfp3_d32()) supported_ |= 1u << VFP32DREGS;
Steve Block6ded16b2010-05-10 14:33:55 +0100144#endif
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000145
146 DCHECK(!IsSupported(VFP3) || IsSupported(ARMv7));
147}
148
149
150void CpuFeatures::PrintTarget() {
151 const char* arm_arch = NULL;
152 const char* arm_target_type = "";
153 const char* arm_no_probe = "";
154 const char* arm_fpu = "";
155 const char* arm_thumb = "";
156 const char* arm_float_abi = NULL;
157
158#if !defined __arm__
159 arm_target_type = " simulator";
160#endif
161
162#if defined ARM_TEST_NO_FEATURE_PROBE
163 arm_no_probe = " noprobe";
164#endif
165
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000166#if defined CAN_USE_ARMV8_INSTRUCTIONS
167 arm_arch = "arm v8";
168#elif defined CAN_USE_ARMV7_INSTRUCTIONS
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000169 arm_arch = "arm v7";
170#else
171 arm_arch = "arm v6";
172#endif
173
174#if defined CAN_USE_NEON
175 arm_fpu = " neon";
176#elif defined CAN_USE_VFP3_INSTRUCTIONS
177# if defined CAN_USE_VFP32DREGS
178 arm_fpu = " vfp3";
179# else
180 arm_fpu = " vfp3-d16";
181# endif
182#else
183 arm_fpu = " vfp2";
184#endif
185
186#ifdef __arm__
187 arm_float_abi = base::OS::ArmUsingHardFloat() ? "hard" : "softfp";
188#elif USE_EABI_HARDFLOAT
189 arm_float_abi = "hard";
190#else
191 arm_float_abi = "softfp";
192#endif
193
194#if defined __arm__ && (defined __thumb__) || (defined __thumb2__)
195 arm_thumb = " thumb";
196#endif
197
198 printf("target%s%s %s%s%s %s\n",
199 arm_target_type, arm_no_probe, arm_arch, arm_fpu, arm_thumb,
200 arm_float_abi);
201}
202
203
204void CpuFeatures::PrintFeatures() {
205 printf(
Ben Murdochc5610432016-08-08 18:44:38 +0100206 "ARMv8=%d ARMv7=%d VFP3=%d VFP32DREGS=%d NEON=%d SUDIV=%d MLS=%d"
207 "UNALIGNED_ACCESSES=%d MOVW_MOVT_IMMEDIATE_LOADS=%d",
208 CpuFeatures::IsSupported(ARMv8), CpuFeatures::IsSupported(ARMv7),
209 CpuFeatures::IsSupported(VFP3), CpuFeatures::IsSupported(VFP32DREGS),
210 CpuFeatures::IsSupported(NEON), CpuFeatures::IsSupported(SUDIV),
211 CpuFeatures::IsSupported(MLS),
212 CpuFeatures::IsSupported(UNALIGNED_ACCESSES),
213 CpuFeatures::IsSupported(MOVW_MOVT_IMMEDIATE_LOADS));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000214#ifdef __arm__
215 bool eabi_hardfloat = base::OS::ArmUsingHardFloat();
216#elif USE_EABI_HARDFLOAT
217 bool eabi_hardfloat = true;
218#else
219 bool eabi_hardfloat = false;
220#endif
221 printf(" USE_EABI_HARDFLOAT=%d\n", eabi_hardfloat);
222}
223
224
225// -----------------------------------------------------------------------------
Steve Blocka7e24c12009-10-30 11:49:00 +0000226// Implementation of RelocInfo
227
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000228// static
Steve Blocka7e24c12009-10-30 11:49:00 +0000229const int RelocInfo::kApplyMask = 0;
230
231
Leon Clarkef7060e22010-06-03 12:02:55 +0100232bool RelocInfo::IsCodedSpecially() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000233 // The deserializer needs to know whether a pointer is specially coded.  Being
234 // specially coded on ARM means that it is a movw/movt instruction, or is an
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000235 // embedded constant pool entry.  These only occur if
236 // FLAG_enable_embedded_constant_pool is true.
237 return FLAG_enable_embedded_constant_pool;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000238}
239
240
241bool RelocInfo::IsInConstantPool() {
242 return Assembler::is_constant_pool_load(pc_);
Leon Clarkef7060e22010-06-03 12:02:55 +0100243}
244
Ben Murdochc5610432016-08-08 18:44:38 +0100245Address RelocInfo::wasm_memory_reference() {
246 DCHECK(IsWasmMemoryReference(rmode_));
247 return Assembler::target_address_at(pc_, host_);
248}
249
250uint32_t RelocInfo::wasm_memory_size_reference() {
251 DCHECK(IsWasmMemorySizeReference(rmode_));
252 return reinterpret_cast<uint32_t>(Assembler::target_address_at(pc_, host_));
253}
254
255void RelocInfo::update_wasm_memory_reference(
256 Address old_base, Address new_base, uint32_t old_size, uint32_t new_size,
257 ICacheFlushMode icache_flush_mode) {
258 DCHECK(IsWasmMemoryReference(rmode_) || IsWasmMemorySizeReference(rmode_));
259 if (IsWasmMemoryReference(rmode_)) {
260 Address updated_memory_reference;
261 DCHECK(old_base <= wasm_memory_reference() &&
262 wasm_memory_reference() < old_base + old_size);
263 updated_memory_reference = new_base + (wasm_memory_reference() - old_base);
264 DCHECK(new_base <= updated_memory_reference &&
265 updated_memory_reference < new_base + new_size);
266 Assembler::set_target_address_at(
267 isolate_, pc_, host_, updated_memory_reference, icache_flush_mode);
268 } else if (IsWasmMemorySizeReference(rmode_)) {
269 uint32_t updated_size_reference;
270 DCHECK(wasm_memory_size_reference() <= old_size);
271 updated_size_reference =
272 new_size + (wasm_memory_size_reference() - old_size);
273 DCHECK(updated_size_reference <= new_size);
274 Assembler::set_target_address_at(
275 isolate_, pc_, host_, reinterpret_cast<Address>(updated_size_reference),
276 icache_flush_mode);
277 } else {
278 UNREACHABLE();
279 }
280}
Leon Clarkef7060e22010-06-03 12:02:55 +0100281
Steve Blocka7e24c12009-10-30 11:49:00 +0000282// -----------------------------------------------------------------------------
283// Implementation of Operand and MemOperand
284// See assembler-arm-inl.h for inlined constructors
285
286Operand::Operand(Handle<Object> handle) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000287 AllowDeferredHandleDereference using_raw_address;
Steve Blocka7e24c12009-10-30 11:49:00 +0000288 rm_ = no_reg;
289 // Verify all Objects referred by code are NOT in new space.
290 Object* obj = *handle;
Steve Blocka7e24c12009-10-30 11:49:00 +0000291 if (obj->IsHeapObject()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000292 DCHECK(!HeapObject::cast(obj)->GetHeap()->InNewSpace(obj));
Steve Blocka7e24c12009-10-30 11:49:00 +0000293 imm32_ = reinterpret_cast<intptr_t>(handle.location());
294 rmode_ = RelocInfo::EMBEDDED_OBJECT;
295 } else {
296 // no relocation needed
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000297 imm32_ = reinterpret_cast<intptr_t>(obj);
298 rmode_ = RelocInfo::NONE32;
Steve Blocka7e24c12009-10-30 11:49:00 +0000299 }
300}
301
302
303Operand::Operand(Register rm, ShiftOp shift_op, int shift_imm) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000304 DCHECK(is_uint5(shift_imm));
305
Steve Blocka7e24c12009-10-30 11:49:00 +0000306 rm_ = rm;
307 rs_ = no_reg;
308 shift_op_ = shift_op;
309 shift_imm_ = shift_imm & 31;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000310
311 if ((shift_op == ROR) && (shift_imm == 0)) {
312 // ROR #0 is functionally equivalent to LSL #0 and this allow us to encode
313 // RRX as ROR #0 (See below).
314 shift_op = LSL;
315 } else if (shift_op == RRX) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000316 // encoded as ROR with shift_imm == 0
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000317 DCHECK(shift_imm == 0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000318 shift_op_ = ROR;
319 shift_imm_ = 0;
320 }
321}
322
323
324Operand::Operand(Register rm, ShiftOp shift_op, Register rs) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000325 DCHECK(shift_op != RRX);
Steve Blocka7e24c12009-10-30 11:49:00 +0000326 rm_ = rm;
327 rs_ = no_reg;
328 shift_op_ = shift_op;
329 rs_ = rs;
330}
331
332
333MemOperand::MemOperand(Register rn, int32_t offset, AddrMode am) {
334 rn_ = rn;
335 rm_ = no_reg;
336 offset_ = offset;
337 am_ = am;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000338
339 // Accesses below the stack pointer are not safe, and are prohibited by the
340 // ABI. We can check obvious violations here.
341 if (rn.is(sp)) {
342 if (am == Offset) DCHECK_LE(0, offset);
343 if (am == NegOffset) DCHECK_GE(0, offset);
344 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000345}
346
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000347
Steve Blocka7e24c12009-10-30 11:49:00 +0000348MemOperand::MemOperand(Register rn, Register rm, AddrMode am) {
349 rn_ = rn;
350 rm_ = rm;
351 shift_op_ = LSL;
352 shift_imm_ = 0;
353 am_ = am;
354}
355
356
357MemOperand::MemOperand(Register rn, Register rm,
358 ShiftOp shift_op, int shift_imm, AddrMode am) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000359 DCHECK(is_uint5(shift_imm));
Steve Blocka7e24c12009-10-30 11:49:00 +0000360 rn_ = rn;
361 rm_ = rm;
362 shift_op_ = shift_op;
363 shift_imm_ = shift_imm & 31;
364 am_ = am;
365}
366
367
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000368NeonMemOperand::NeonMemOperand(Register rn, AddrMode am, int align) {
369 DCHECK((am == Offset) || (am == PostIndex));
370 rn_ = rn;
371 rm_ = (am == Offset) ? pc : sp;
372 SetAlignment(align);
373}
374
375
376NeonMemOperand::NeonMemOperand(Register rn, Register rm, int align) {
377 rn_ = rn;
378 rm_ = rm;
379 SetAlignment(align);
380}
381
382
383void NeonMemOperand::SetAlignment(int align) {
384 switch (align) {
385 case 0:
386 align_ = 0;
387 break;
388 case 64:
389 align_ = 1;
390 break;
391 case 128:
392 align_ = 2;
393 break;
394 case 256:
395 align_ = 3;
396 break;
397 default:
398 UNREACHABLE();
399 align_ = 0;
400 break;
401 }
402}
403
404
405NeonListOperand::NeonListOperand(DoubleRegister base, int registers_count) {
406 base_ = base;
407 switch (registers_count) {
408 case 1:
409 type_ = nlt_1;
410 break;
411 case 2:
412 type_ = nlt_2;
413 break;
414 case 3:
415 type_ = nlt_3;
416 break;
417 case 4:
418 type_ = nlt_4;
419 break;
420 default:
421 UNREACHABLE();
422 type_ = nlt_1;
423 break;
424 }
425}
426
427
Steve Blocka7e24c12009-10-30 11:49:00 +0000428// -----------------------------------------------------------------------------
Steve Block1e0659c2011-05-24 12:43:12 +0100429// Specific instructions, constants, and masks.
Steve Blocka7e24c12009-10-30 11:49:00 +0000430
Steve Blocka7e24c12009-10-30 11:49:00 +0000431// str(r, MemOperand(sp, 4, NegPreIndex), al) instruction (aka push(r))
432// register r is not encoded.
Steve Block1e0659c2011-05-24 12:43:12 +0100433const Instr kPushRegPattern =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000434 al | B26 | 4 | NegPreIndex | Register::kCode_sp * B16;
Steve Blocka7e24c12009-10-30 11:49:00 +0000435// ldr(r, MemOperand(sp, 4, PostIndex), al) instruction (aka pop(r))
436// register r is not encoded.
Steve Block1e0659c2011-05-24 12:43:12 +0100437const Instr kPopRegPattern =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000438 al | B26 | L | 4 | PostIndex | Register::kCode_sp * B16;
Steve Block6ded16b2010-05-10 14:33:55 +0100439// ldr rd, [pc, #offset]
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000440const Instr kLdrPCImmedMask = 15 * B24 | 7 * B20 | 15 * B16;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000441const Instr kLdrPCImmedPattern = 5 * B24 | L | Register::kCode_pc * B16;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000442// ldr rd, [pp, #offset]
443const Instr kLdrPpImmedMask = 15 * B24 | 7 * B20 | 15 * B16;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000444const Instr kLdrPpImmedPattern = 5 * B24 | L | Register::kCode_r8 * B16;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000445// ldr rd, [pp, rn]
446const Instr kLdrPpRegMask = 15 * B24 | 7 * B20 | 15 * B16;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000447const Instr kLdrPpRegPattern = 7 * B24 | L | Register::kCode_r8 * B16;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000448// vldr dd, [pc, #offset]
449const Instr kVldrDPCMask = 15 * B24 | 3 * B20 | 15 * B16 | 15 * B8;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000450const Instr kVldrDPCPattern = 13 * B24 | L | Register::kCode_pc * B16 | 11 * B8;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000451// vldr dd, [pp, #offset]
452const Instr kVldrDPpMask = 15 * B24 | 3 * B20 | 15 * B16 | 15 * B8;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000453const Instr kVldrDPpPattern = 13 * B24 | L | Register::kCode_r8 * B16 | 11 * B8;
Steve Block6ded16b2010-05-10 14:33:55 +0100454// blxcc rm
455const Instr kBlxRegMask =
456 15 * B24 | 15 * B20 | 15 * B16 | 15 * B12 | 15 * B8 | 15 * B4;
457const Instr kBlxRegPattern =
Steve Block1e0659c2011-05-24 12:43:12 +0100458 B24 | B21 | 15 * B16 | 15 * B12 | 15 * B8 | BLX;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100459const Instr kBlxIp = al | kBlxRegPattern | ip.code();
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100460const Instr kMovMvnMask = 0x6d * B21 | 0xf * B16;
461const Instr kMovMvnPattern = 0xd * B21;
462const Instr kMovMvnFlip = B22;
463const Instr kMovLeaveCCMask = 0xdff * B16;
464const Instr kMovLeaveCCPattern = 0x1a0 * B16;
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100465const Instr kMovwPattern = 0x30 * B20;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000466const Instr kMovtPattern = 0x34 * B20;
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100467const Instr kMovwLeaveCCFlip = 0x5 * B21;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000468const Instr kMovImmedMask = 0x7f * B21;
469const Instr kMovImmedPattern = 0x1d * B21;
470const Instr kOrrImmedMask = 0x7f * B21;
471const Instr kOrrImmedPattern = 0x1c * B21;
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100472const Instr kCmpCmnMask = 0xdd * B20 | 0xf * B12;
473const Instr kCmpCmnPattern = 0x15 * B20;
474const Instr kCmpCmnFlip = B21;
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100475const Instr kAddSubFlip = 0x6 * B21;
476const Instr kAndBicFlip = 0xe * B21;
477
Leon Clarkef7060e22010-06-03 12:02:55 +0100478// A mask for the Rd register for push, pop, ldr, str instructions.
Steve Block1e0659c2011-05-24 12:43:12 +0100479const Instr kLdrRegFpOffsetPattern =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000480 al | B26 | L | Offset | Register::kCode_fp * B16;
Steve Block1e0659c2011-05-24 12:43:12 +0100481const Instr kStrRegFpOffsetPattern =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000482 al | B26 | Offset | Register::kCode_fp * B16;
Steve Block1e0659c2011-05-24 12:43:12 +0100483const Instr kLdrRegFpNegOffsetPattern =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000484 al | B26 | L | NegOffset | Register::kCode_fp * B16;
Steve Block1e0659c2011-05-24 12:43:12 +0100485const Instr kStrRegFpNegOffsetPattern =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000486 al | B26 | NegOffset | Register::kCode_fp * B16;
Steve Block1e0659c2011-05-24 12:43:12 +0100487const Instr kLdrStrInstrTypeMask = 0xffff0000;
Steve Block1e0659c2011-05-24 12:43:12 +0100488
Steve Blocka7e24c12009-10-30 11:49:00 +0000489
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000490Assembler::Assembler(Isolate* isolate, void* buffer, int buffer_size)
491 : AssemblerBase(isolate, buffer, buffer_size),
492 recorded_ast_id_(TypeFeedbackId::None()),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000493 pending_32_bit_constants_(&pending_32_bit_constants_buffer_[0]),
494 pending_64_bit_constants_(&pending_64_bit_constants_buffer_[0]),
495 constant_pool_builder_(kLdrMaxReachBits, kVldrMaxReachBits),
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000496 positions_recorder_(this) {
497 reloc_info_writer.Reposition(buffer_ + buffer_size_, pc_);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000498 num_pending_32_bit_constants_ = 0;
499 num_pending_64_bit_constants_ = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +0000500 next_buffer_check_ = 0;
Steve Block6ded16b2010-05-10 14:33:55 +0100501 const_pool_blocked_nesting_ = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +0000502 no_const_pool_before_ = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000503 first_const_pool_32_use_ = -1;
504 first_const_pool_64_use_ = -1;
Steve Blocka7e24c12009-10-30 11:49:00 +0000505 last_bound_pos_ = 0;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000506 ClearRecordedAstId();
Steve Blocka7e24c12009-10-30 11:49:00 +0000507}
508
509
510Assembler::~Assembler() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000511 DCHECK(const_pool_blocked_nesting_ == 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000512 if (pending_32_bit_constants_ != &pending_32_bit_constants_buffer_[0]) {
513 delete[] pending_32_bit_constants_;
514 }
515 if (pending_64_bit_constants_ != &pending_64_bit_constants_buffer_[0]) {
516 delete[] pending_64_bit_constants_;
517 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000518}
519
520
521void Assembler::GetCode(CodeDesc* desc) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000522 reloc_info_writer.Finish();
523
524 // Emit constant pool if necessary.
525 int constant_pool_offset = 0;
526 if (FLAG_enable_embedded_constant_pool) {
527 constant_pool_offset = EmitEmbeddedConstantPool();
528 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000529 CheckConstPool(true, false);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000530 DCHECK(num_pending_32_bit_constants_ == 0);
531 DCHECK(num_pending_64_bit_constants_ == 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000532 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100533 // Set up code descriptor.
Steve Blocka7e24c12009-10-30 11:49:00 +0000534 desc->buffer = buffer_;
535 desc->buffer_size = buffer_size_;
536 desc->instr_size = pc_offset();
537 desc->reloc_size = (buffer_ + buffer_size_) - reloc_info_writer.pos();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000538 desc->constant_pool_size =
539 (constant_pool_offset ? desc->instr_size - constant_pool_offset : 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000540 desc->origin = this;
Steve Blocka7e24c12009-10-30 11:49:00 +0000541}
542
543
544void Assembler::Align(int m) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000545 DCHECK(m >= 4 && base::bits::IsPowerOfTwo32(m));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000546 DCHECK((pc_offset() & (kInstrSize - 1)) == 0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000547 while ((pc_offset() & (m - 1)) != 0) {
548 nop();
549 }
550}
551
552
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100553void Assembler::CodeTargetAlign() {
554 // Preferred alignment of jump targets on some ARM chips.
555 Align(8);
556}
557
558
Steve Block1e0659c2011-05-24 12:43:12 +0100559Condition Assembler::GetCondition(Instr instr) {
560 return Instruction::ConditionField(instr);
561}
562
563
Steve Block6ded16b2010-05-10 14:33:55 +0100564bool Assembler::IsBranch(Instr instr) {
565 return (instr & (B27 | B25)) == (B27 | B25);
566}
567
568
569int Assembler::GetBranchOffset(Instr instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000570 DCHECK(IsBranch(instr));
Steve Block6ded16b2010-05-10 14:33:55 +0100571 // Take the jump offset in the lower 24 bits, sign extend it and multiply it
572 // with 4 to get the offset in bytes.
Steve Block1e0659c2011-05-24 12:43:12 +0100573 return ((instr & kImm24Mask) << 8) >> 6;
Steve Block6ded16b2010-05-10 14:33:55 +0100574}
575
576
577bool Assembler::IsLdrRegisterImmediate(Instr instr) {
578 return (instr & (B27 | B26 | B25 | B22 | B20)) == (B26 | B20);
579}
580
581
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000582bool Assembler::IsVldrDRegisterImmediate(Instr instr) {
583 return (instr & (15 * B24 | 3 * B20 | 15 * B8)) == (13 * B24 | B20 | 11 * B8);
584}
585
586
Steve Block6ded16b2010-05-10 14:33:55 +0100587int Assembler::GetLdrRegisterImmediateOffset(Instr instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000588 DCHECK(IsLdrRegisterImmediate(instr));
Steve Block6ded16b2010-05-10 14:33:55 +0100589 bool positive = (instr & B23) == B23;
Steve Block1e0659c2011-05-24 12:43:12 +0100590 int offset = instr & kOff12Mask; // Zero extended offset.
Steve Block6ded16b2010-05-10 14:33:55 +0100591 return positive ? offset : -offset;
592}
593
594
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000595int Assembler::GetVldrDRegisterImmediateOffset(Instr instr) {
596 DCHECK(IsVldrDRegisterImmediate(instr));
597 bool positive = (instr & B23) == B23;
598 int offset = instr & kOff8Mask; // Zero extended offset.
599 offset <<= 2;
600 return positive ? offset : -offset;
601}
602
603
Steve Block6ded16b2010-05-10 14:33:55 +0100604Instr Assembler::SetLdrRegisterImmediateOffset(Instr instr, int offset) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000605 DCHECK(IsLdrRegisterImmediate(instr));
Steve Block6ded16b2010-05-10 14:33:55 +0100606 bool positive = offset >= 0;
607 if (!positive) offset = -offset;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000608 DCHECK(is_uint12(offset));
Steve Block6ded16b2010-05-10 14:33:55 +0100609 // Set bit indicating whether the offset should be added.
610 instr = (instr & ~B23) | (positive ? B23 : 0);
611 // Set the actual offset.
Steve Block1e0659c2011-05-24 12:43:12 +0100612 return (instr & ~kOff12Mask) | offset;
Steve Block6ded16b2010-05-10 14:33:55 +0100613}
614
615
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000616Instr Assembler::SetVldrDRegisterImmediateOffset(Instr instr, int offset) {
617 DCHECK(IsVldrDRegisterImmediate(instr));
618 DCHECK((offset & ~3) == offset); // Must be 64-bit aligned.
619 bool positive = offset >= 0;
620 if (!positive) offset = -offset;
621 DCHECK(is_uint10(offset));
622 // Set bit indicating whether the offset should be added.
623 instr = (instr & ~B23) | (positive ? B23 : 0);
624 // Set the actual offset. Its bottom 2 bits are zero.
625 return (instr & ~kOff8Mask) | (offset >> 2);
626}
627
628
Kristian Monsen50ef84f2010-07-29 15:18:00 +0100629bool Assembler::IsStrRegisterImmediate(Instr instr) {
630 return (instr & (B27 | B26 | B25 | B22 | B20)) == B26;
631}
632
633
634Instr Assembler::SetStrRegisterImmediateOffset(Instr instr, int offset) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000635 DCHECK(IsStrRegisterImmediate(instr));
Kristian Monsen50ef84f2010-07-29 15:18:00 +0100636 bool positive = offset >= 0;
637 if (!positive) offset = -offset;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000638 DCHECK(is_uint12(offset));
Kristian Monsen50ef84f2010-07-29 15:18:00 +0100639 // Set bit indicating whether the offset should be added.
640 instr = (instr & ~B23) | (positive ? B23 : 0);
641 // Set the actual offset.
Steve Block1e0659c2011-05-24 12:43:12 +0100642 return (instr & ~kOff12Mask) | offset;
Kristian Monsen50ef84f2010-07-29 15:18:00 +0100643}
644
645
646bool Assembler::IsAddRegisterImmediate(Instr instr) {
647 return (instr & (B27 | B26 | B25 | B24 | B23 | B22 | B21)) == (B25 | B23);
648}
649
650
651Instr Assembler::SetAddRegisterImmediateOffset(Instr instr, int offset) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000652 DCHECK(IsAddRegisterImmediate(instr));
653 DCHECK(offset >= 0);
654 DCHECK(is_uint12(offset));
Kristian Monsen50ef84f2010-07-29 15:18:00 +0100655 // Set the offset.
Steve Block1e0659c2011-05-24 12:43:12 +0100656 return (instr & ~kOff12Mask) | offset;
Kristian Monsen50ef84f2010-07-29 15:18:00 +0100657}
658
659
Leon Clarkef7060e22010-06-03 12:02:55 +0100660Register Assembler::GetRd(Instr instr) {
661 Register reg;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000662 reg.reg_code = Instruction::RdValue(instr);
Steve Block1e0659c2011-05-24 12:43:12 +0100663 return reg;
664}
665
666
667Register Assembler::GetRn(Instr instr) {
668 Register reg;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000669 reg.reg_code = Instruction::RnValue(instr);
Steve Block1e0659c2011-05-24 12:43:12 +0100670 return reg;
671}
672
673
674Register Assembler::GetRm(Instr instr) {
675 Register reg;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000676 reg.reg_code = Instruction::RmValue(instr);
Leon Clarkef7060e22010-06-03 12:02:55 +0100677 return reg;
678}
679
680
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000681Instr Assembler::GetConsantPoolLoadPattern() {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000682 if (FLAG_enable_embedded_constant_pool) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000683 return kLdrPpImmedPattern;
684 } else {
685 return kLdrPCImmedPattern;
686 }
687}
688
689
690Instr Assembler::GetConsantPoolLoadMask() {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000691 if (FLAG_enable_embedded_constant_pool) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000692 return kLdrPpImmedMask;
693 } else {
694 return kLdrPCImmedMask;
695 }
696}
697
698
Leon Clarkef7060e22010-06-03 12:02:55 +0100699bool Assembler::IsPush(Instr instr) {
700 return ((instr & ~kRdMask) == kPushRegPattern);
701}
702
703
704bool Assembler::IsPop(Instr instr) {
705 return ((instr & ~kRdMask) == kPopRegPattern);
706}
707
708
709bool Assembler::IsStrRegFpOffset(Instr instr) {
710 return ((instr & kLdrStrInstrTypeMask) == kStrRegFpOffsetPattern);
711}
712
713
714bool Assembler::IsLdrRegFpOffset(Instr instr) {
715 return ((instr & kLdrStrInstrTypeMask) == kLdrRegFpOffsetPattern);
716}
717
718
719bool Assembler::IsStrRegFpNegOffset(Instr instr) {
720 return ((instr & kLdrStrInstrTypeMask) == kStrRegFpNegOffsetPattern);
721}
722
723
724bool Assembler::IsLdrRegFpNegOffset(Instr instr) {
725 return ((instr & kLdrStrInstrTypeMask) == kLdrRegFpNegOffsetPattern);
726}
727
728
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800729bool Assembler::IsLdrPcImmediateOffset(Instr instr) {
730 // Check the instruction is indeed a
731 // ldr<cond> <Rd>, [pc +/- offset_12].
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000732 return (instr & kLdrPCImmedMask) == kLdrPCImmedPattern;
733}
734
735
736bool Assembler::IsLdrPpImmediateOffset(Instr instr) {
737 // Check the instruction is indeed a
738 // ldr<cond> <Rd>, [pp +/- offset_12].
739 return (instr & kLdrPpImmedMask) == kLdrPpImmedPattern;
740}
741
742
743bool Assembler::IsLdrPpRegOffset(Instr instr) {
744 // Check the instruction is indeed a
745 // ldr<cond> <Rd>, [pp, +/- <Rm>].
746 return (instr & kLdrPpRegMask) == kLdrPpRegPattern;
747}
748
749
750Instr Assembler::GetLdrPpRegOffsetPattern() { return kLdrPpRegPattern; }
751
752
753bool Assembler::IsVldrDPcImmediateOffset(Instr instr) {
754 // Check the instruction is indeed a
755 // vldr<cond> <Dd>, [pc +/- offset_10].
756 return (instr & kVldrDPCMask) == kVldrDPCPattern;
757}
758
759
760bool Assembler::IsVldrDPpImmediateOffset(Instr instr) {
761 // Check the instruction is indeed a
762 // vldr<cond> <Dd>, [pp +/- offset_10].
763 return (instr & kVldrDPpMask) == kVldrDPpPattern;
764}
765
766
767bool Assembler::IsBlxReg(Instr instr) {
768 // Check the instruction is indeed a
769 // blxcc <Rm>
770 return (instr & kBlxRegMask) == kBlxRegPattern;
771}
772
773
774bool Assembler::IsBlxIp(Instr instr) {
775 // Check the instruction is indeed a
776 // blx ip
777 return instr == kBlxIp;
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800778}
779
780
Steve Block1e0659c2011-05-24 12:43:12 +0100781bool Assembler::IsTstImmediate(Instr instr) {
782 return (instr & (B27 | B26 | I | kOpCodeMask | S | kRdMask)) ==
783 (I | TST | S);
784}
785
786
787bool Assembler::IsCmpRegister(Instr instr) {
788 return (instr & (B27 | B26 | I | kOpCodeMask | S | kRdMask | B4)) ==
789 (CMP | S);
790}
791
792
793bool Assembler::IsCmpImmediate(Instr instr) {
794 return (instr & (B27 | B26 | I | kOpCodeMask | S | kRdMask)) ==
795 (I | CMP | S);
796}
797
798
799Register Assembler::GetCmpImmediateRegister(Instr instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000800 DCHECK(IsCmpImmediate(instr));
Steve Block1e0659c2011-05-24 12:43:12 +0100801 return GetRn(instr);
802}
803
804
805int Assembler::GetCmpImmediateRawImmediate(Instr instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000806 DCHECK(IsCmpImmediate(instr));
Steve Block1e0659c2011-05-24 12:43:12 +0100807 return instr & kOff12Mask;
808}
809
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000810
Steve Blocka7e24c12009-10-30 11:49:00 +0000811// Labels refer to positions in the (to be) generated code.
812// There are bound, linked, and unused labels.
813//
814// Bound labels refer to known positions in the already
815// generated code. pos() is the position the label refers to.
816//
817// Linked labels refer to unknown positions in the code
818// to be generated; pos() is the position of the last
819// instruction using the label.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000820//
821// The linked labels form a link chain by making the branch offset
822// in the instruction steam to point to the previous branch
823// instruction using the same label.
824//
825// The link chain is terminated by a branch offset pointing to the
826// same position.
Steve Blocka7e24c12009-10-30 11:49:00 +0000827
828
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000829int Assembler::target_at(int pos) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000830 Instr instr = instr_at(pos);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000831 if (is_uint24(instr)) {
832 // Emitted link to a label, not part of a branch.
833 return instr;
Steve Blocka7e24c12009-10-30 11:49:00 +0000834 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000835 DCHECK_EQ(5 * B25, instr & 7 * B25); // b, bl, or blx imm24
Steve Block1e0659c2011-05-24 12:43:12 +0100836 int imm26 = ((instr & kImm24Mask) << 8) >> 6;
837 if ((Instruction::ConditionField(instr) == kSpecialCondition) &&
838 ((instr & B24) != 0)) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000839 // blx uses bit 24 to encode bit 2 of imm26
840 imm26 += 2;
Steve Block6ded16b2010-05-10 14:33:55 +0100841 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000842 return pos + kPcLoadDelta + imm26;
843}
844
845
846void Assembler::target_at_put(int pos, int target_pos) {
847 Instr instr = instr_at(pos);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000848 if (is_uint24(instr)) {
849 DCHECK(target_pos == pos || target_pos >= 0);
850 // Emitted link to a label, not part of a branch.
851 // Load the position of the label relative to the generated code object
852 // pointer in a register.
853
854 // Here are the instructions we need to emit:
855 // For ARMv7: target24 => target16_1:target16_0
856 // movw dst, #target16_0
857 // movt dst, #target16_1
858 // For ARMv6: target24 => target8_2:target8_1:target8_0
859 // mov dst, #target8_0
860 // orr dst, dst, #target8_1 << 8
861 // orr dst, dst, #target8_2 << 16
862
863 // We extract the destination register from the emitted nop instruction.
864 Register dst = Register::from_code(
865 Instruction::RmValue(instr_at(pos + kInstrSize)));
866 DCHECK(IsNop(instr_at(pos + kInstrSize), dst.code()));
867 uint32_t target24 = target_pos + (Code::kHeaderSize - kHeapObjectTag);
868 DCHECK(is_uint24(target24));
869 if (is_uint8(target24)) {
870 // If the target fits in a byte then only patch with a mov
871 // instruction.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000872 CodePatcher patcher(isolate(), reinterpret_cast<byte*>(buffer_ + pos), 1,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000873 CodePatcher::DONT_FLUSH);
874 patcher.masm()->mov(dst, Operand(target24));
875 } else {
876 uint16_t target16_0 = target24 & kImm16Mask;
877 uint16_t target16_1 = target24 >> 16;
878 if (CpuFeatures::IsSupported(ARMv7)) {
879 // Patch with movw/movt.
880 if (target16_1 == 0) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000881 CodePatcher patcher(isolate(), reinterpret_cast<byte*>(buffer_ + pos),
882 1, CodePatcher::DONT_FLUSH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000883 patcher.masm()->movw(dst, target16_0);
884 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000885 CodePatcher patcher(isolate(), reinterpret_cast<byte*>(buffer_ + pos),
886 2, CodePatcher::DONT_FLUSH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000887 patcher.masm()->movw(dst, target16_0);
888 patcher.masm()->movt(dst, target16_1);
889 }
890 } else {
891 // Patch with a sequence of mov/orr/orr instructions.
892 uint8_t target8_0 = target16_0 & kImm8Mask;
893 uint8_t target8_1 = target16_0 >> 8;
894 uint8_t target8_2 = target16_1 & kImm8Mask;
895 if (target8_2 == 0) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000896 CodePatcher patcher(isolate(), reinterpret_cast<byte*>(buffer_ + pos),
897 2, CodePatcher::DONT_FLUSH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000898 patcher.masm()->mov(dst, Operand(target8_0));
899 patcher.masm()->orr(dst, dst, Operand(target8_1 << 8));
900 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000901 CodePatcher patcher(isolate(), reinterpret_cast<byte*>(buffer_ + pos),
902 3, CodePatcher::DONT_FLUSH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000903 patcher.masm()->mov(dst, Operand(target8_0));
904 patcher.masm()->orr(dst, dst, Operand(target8_1 << 8));
905 patcher.masm()->orr(dst, dst, Operand(target8_2 << 16));
906 }
907 }
908 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000909 return;
910 }
911 int imm26 = target_pos - (pos + kPcLoadDelta);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000912 DCHECK_EQ(5 * B25, instr & 7 * B25); // b, bl, or blx imm24
Steve Block1e0659c2011-05-24 12:43:12 +0100913 if (Instruction::ConditionField(instr) == kSpecialCondition) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000914 // blx uses bit 24 to encode bit 2 of imm26
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000915 DCHECK_EQ(0, imm26 & 1);
916 instr = (instr & ~(B24 | kImm24Mask)) | ((imm26 & 2) >> 1) * B24;
Steve Blocka7e24c12009-10-30 11:49:00 +0000917 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000918 DCHECK_EQ(0, imm26 & 3);
Steve Block1e0659c2011-05-24 12:43:12 +0100919 instr &= ~kImm24Mask;
Steve Blocka7e24c12009-10-30 11:49:00 +0000920 }
921 int imm24 = imm26 >> 2;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000922 DCHECK(is_int24(imm24));
Steve Block1e0659c2011-05-24 12:43:12 +0100923 instr_at_put(pos, instr | (imm24 & kImm24Mask));
Steve Blocka7e24c12009-10-30 11:49:00 +0000924}
925
926
927void Assembler::print(Label* L) {
928 if (L->is_unused()) {
929 PrintF("unused label\n");
930 } else if (L->is_bound()) {
931 PrintF("bound label to %d\n", L->pos());
932 } else if (L->is_linked()) {
933 Label l = *L;
934 PrintF("unbound label");
935 while (l.is_linked()) {
936 PrintF("@ %d ", l.pos());
937 Instr instr = instr_at(l.pos());
Steve Block1e0659c2011-05-24 12:43:12 +0100938 if ((instr & ~kImm24Mask) == 0) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000939 PrintF("value\n");
940 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000941 DCHECK((instr & 7*B25) == 5*B25); // b, bl, or blx
Steve Block1e0659c2011-05-24 12:43:12 +0100942 Condition cond = Instruction::ConditionField(instr);
Steve Blocka7e24c12009-10-30 11:49:00 +0000943 const char* b;
944 const char* c;
Steve Block1e0659c2011-05-24 12:43:12 +0100945 if (cond == kSpecialCondition) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000946 b = "blx";
947 c = "";
948 } else {
949 if ((instr & B24) != 0)
950 b = "bl";
951 else
952 b = "b";
953
954 switch (cond) {
955 case eq: c = "eq"; break;
956 case ne: c = "ne"; break;
957 case hs: c = "hs"; break;
958 case lo: c = "lo"; break;
959 case mi: c = "mi"; break;
960 case pl: c = "pl"; break;
961 case vs: c = "vs"; break;
962 case vc: c = "vc"; break;
963 case hi: c = "hi"; break;
964 case ls: c = "ls"; break;
965 case ge: c = "ge"; break;
966 case lt: c = "lt"; break;
967 case gt: c = "gt"; break;
968 case le: c = "le"; break;
969 case al: c = ""; break;
970 default:
971 c = "";
972 UNREACHABLE();
973 }
974 }
975 PrintF("%s%s\n", b, c);
976 }
977 next(&l);
978 }
979 } else {
980 PrintF("label in inconsistent state (pos = %d)\n", L->pos_);
981 }
982}
983
984
985void Assembler::bind_to(Label* L, int pos) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000986 DCHECK(0 <= pos && pos <= pc_offset()); // must have a valid binding position
Steve Blocka7e24c12009-10-30 11:49:00 +0000987 while (L->is_linked()) {
988 int fixup_pos = L->pos();
989 next(L); // call next before overwriting link with target at fixup_pos
990 target_at_put(fixup_pos, pos);
991 }
992 L->bind_to(pos);
993
994 // Keep track of the last bound label so we don't eliminate any instructions
995 // before a bound label.
996 if (pos > last_bound_pos_)
997 last_bound_pos_ = pos;
998}
999
1000
Steve Blocka7e24c12009-10-30 11:49:00 +00001001void Assembler::bind(Label* L) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001002 DCHECK(!L->is_bound()); // label can only be bound once
Steve Blocka7e24c12009-10-30 11:49:00 +00001003 bind_to(L, pc_offset());
1004}
1005
1006
1007void Assembler::next(Label* L) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001008 DCHECK(L->is_linked());
Steve Blocka7e24c12009-10-30 11:49:00 +00001009 int link = target_at(L->pos());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001010 if (link == L->pos()) {
1011 // Branch target points to the same instuction. This is the end of the link
1012 // chain.
Steve Blocka7e24c12009-10-30 11:49:00 +00001013 L->Unuse();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001014 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001015 DCHECK(link >= 0);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001016 L->link_to(link);
Steve Blocka7e24c12009-10-30 11:49:00 +00001017 }
1018}
1019
1020
Andrei Popescu31002712010-02-23 13:46:05 +00001021// Low-level code emission routines depending on the addressing mode.
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001022// If this returns true then you have to use the rotate_imm and immed_8
1023// that it returns, because it may have already changed the instruction
1024// to match them!
Steve Blocka7e24c12009-10-30 11:49:00 +00001025static bool fits_shifter(uint32_t imm32,
1026 uint32_t* rotate_imm,
1027 uint32_t* immed_8,
1028 Instr* instr) {
Andrei Popescu31002712010-02-23 13:46:05 +00001029 // imm32 must be unsigned.
Steve Blocka7e24c12009-10-30 11:49:00 +00001030 for (int rot = 0; rot < 16; rot++) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001031 uint32_t imm8 = base::bits::RotateLeft32(imm32, 2 * rot);
Steve Blocka7e24c12009-10-30 11:49:00 +00001032 if ((imm8 <= 0xff)) {
1033 *rotate_imm = rot;
1034 *immed_8 = imm8;
1035 return true;
1036 }
1037 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001038 // If the opcode is one with a complementary version and the complementary
1039 // immediate fits, change the opcode.
1040 if (instr != NULL) {
1041 if ((*instr & kMovMvnMask) == kMovMvnPattern) {
1042 if (fits_shifter(~imm32, rotate_imm, immed_8, NULL)) {
1043 *instr ^= kMovMvnFlip;
1044 return true;
1045 } else if ((*instr & kMovLeaveCCMask) == kMovLeaveCCPattern) {
Ben Murdoch8b112d22011-06-08 16:22:53 +01001046 if (CpuFeatures::IsSupported(ARMv7)) {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001047 if (imm32 < 0x10000) {
1048 *instr ^= kMovwLeaveCCFlip;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001049 *instr |= Assembler::EncodeMovwImmediate(imm32);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001050 *rotate_imm = *immed_8 = 0; // Not used for movw.
1051 return true;
1052 }
1053 }
1054 }
1055 } else if ((*instr & kCmpCmnMask) == kCmpCmnPattern) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001056 if (fits_shifter(-static_cast<int>(imm32), rotate_imm, immed_8, NULL)) {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001057 *instr ^= kCmpCmnFlip;
1058 return true;
1059 }
1060 } else {
1061 Instr alu_insn = (*instr & kALUMask);
Steve Block1e0659c2011-05-24 12:43:12 +01001062 if (alu_insn == ADD ||
1063 alu_insn == SUB) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001064 if (fits_shifter(-static_cast<int>(imm32), rotate_imm, immed_8, NULL)) {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001065 *instr ^= kAddSubFlip;
1066 return true;
1067 }
Steve Block1e0659c2011-05-24 12:43:12 +01001068 } else if (alu_insn == AND ||
1069 alu_insn == BIC) {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001070 if (fits_shifter(~imm32, rotate_imm, immed_8, NULL)) {
1071 *instr ^= kAndBicFlip;
1072 return true;
1073 }
1074 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001075 }
1076 }
1077 return false;
1078}
1079
1080
1081// We have to use the temporary register for things that can be relocated even
1082// if they can be encoded in the ARM's 12 bits of immediate-offset instruction
1083// space. There is no guarantee that the relocated location can be similarly
1084// encoded.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001085bool Operand::must_output_reloc_info(const Assembler* assembler) const {
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001086 if (rmode_ == RelocInfo::EXTERNAL_REFERENCE) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001087 if (assembler != NULL && assembler->predictable_code_size()) return true;
1088 return assembler->serializer_enabled();
1089 } else if (RelocInfo::IsNone(rmode_)) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001090 return false;
1091 }
1092 return true;
1093}
1094
1095
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001096static bool use_mov_immediate_load(const Operand& x,
1097 const Assembler* assembler) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001098 if (FLAG_enable_embedded_constant_pool && assembler != NULL &&
1099 !assembler->is_constant_pool_available()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001100 return true;
1101 } else if (CpuFeatures::IsSupported(MOVW_MOVT_IMMEDIATE_LOADS) &&
1102 (assembler == NULL || !assembler->predictable_code_size())) {
1103 // Prefer movw / movt to constant pool if it is more efficient on the CPU.
1104 return true;
1105 } else if (x.must_output_reloc_info(assembler)) {
1106 // Prefer constant pool if data is likely to be patched.
1107 return false;
1108 } else {
1109 // Otherwise, use immediate load if movw / movt is available.
1110 return CpuFeatures::IsSupported(ARMv7);
1111 }
1112}
1113
1114
1115int Operand::instructions_required(const Assembler* assembler,
1116 Instr instr) const {
1117 if (rm_.is_valid()) return 1;
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001118 uint32_t dummy1, dummy2;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001119 if (must_output_reloc_info(assembler) ||
Steve Block44f0eee2011-05-26 01:26:41 +01001120 !fits_shifter(imm32_, &dummy1, &dummy2, &instr)) {
1121 // The immediate operand cannot be encoded as a shifter operand, or use of
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001122 // constant pool is required. First account for the instructions required
1123 // for the constant pool or immediate load
1124 int instructions;
1125 if (use_mov_immediate_load(*this, assembler)) {
1126 // A movw / movt or mov / orr immediate load.
1127 instructions = CpuFeatures::IsSupported(ARMv7) ? 2 : 4;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001128 } else if (assembler != NULL &&
1129 assembler->ConstantPoolAccessIsInOverflow()) {
1130 // An overflowed constant pool load.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001131 instructions = CpuFeatures::IsSupported(ARMv7) ? 3 : 5;
Steve Block44f0eee2011-05-26 01:26:41 +01001132 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001133 // A small constant pool load.
1134 instructions = 1;
Steve Block44f0eee2011-05-26 01:26:41 +01001135 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001136
1137 if ((instr & ~kCondMask) != 13 * B21) { // mov, S not set
1138 // For a mov or mvn instruction which doesn't set the condition
1139 // code, the constant pool or immediate load is enough, otherwise we need
1140 // to account for the actual instruction being requested.
1141 instructions += 1;
1142 }
1143 return instructions;
Steve Block44f0eee2011-05-26 01:26:41 +01001144 } else {
1145 // No use of constant pool and the immediate operand can be encoded as a
1146 // shifter operand.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001147 return 1;
1148 }
1149}
1150
1151
1152void Assembler::move_32_bit_immediate(Register rd,
1153 const Operand& x,
1154 Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001155 uint32_t imm32 = static_cast<uint32_t>(x.imm32_);
1156 if (x.must_output_reloc_info(this)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001157 RecordRelocInfo(x.rmode_);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001158 }
1159
1160 if (use_mov_immediate_load(x, this)) {
1161 Register target = rd.code() == pc.code() ? ip : rd;
1162 if (CpuFeatures::IsSupported(ARMv7)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001163 if (!FLAG_enable_embedded_constant_pool &&
1164 x.must_output_reloc_info(this)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001165 // Make sure the movw/movt doesn't get separated.
1166 BlockConstPoolFor(2);
1167 }
1168 movw(target, imm32 & 0xffff, cond);
1169 movt(target, imm32 >> 16, cond);
1170 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001171 DCHECK(FLAG_enable_embedded_constant_pool);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001172 mov(target, Operand(imm32 & kImm8Mask), LeaveCC, cond);
1173 orr(target, target, Operand(imm32 & (kImm8Mask << 8)), LeaveCC, cond);
1174 orr(target, target, Operand(imm32 & (kImm8Mask << 16)), LeaveCC, cond);
1175 orr(target, target, Operand(imm32 & (kImm8Mask << 24)), LeaveCC, cond);
1176 }
1177 if (target.code() != rd.code()) {
1178 mov(rd, target, LeaveCC, cond);
1179 }
1180 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001181 DCHECK(!FLAG_enable_embedded_constant_pool || is_constant_pool_available());
1182 ConstantPoolEntry::Access access =
1183 ConstantPoolAddEntry(pc_offset(), x.rmode_, x.imm32_);
1184 if (access == ConstantPoolEntry::OVERFLOWED) {
1185 DCHECK(FLAG_enable_embedded_constant_pool);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001186 Register target = rd.code() == pc.code() ? ip : rd;
1187 // Emit instructions to load constant pool offset.
1188 if (CpuFeatures::IsSupported(ARMv7)) {
1189 movw(target, 0, cond);
1190 movt(target, 0, cond);
1191 } else {
1192 mov(target, Operand(0), LeaveCC, cond);
1193 orr(target, target, Operand(0), LeaveCC, cond);
1194 orr(target, target, Operand(0), LeaveCC, cond);
1195 orr(target, target, Operand(0), LeaveCC, cond);
1196 }
1197 // Load from constant pool at offset.
1198 ldr(rd, MemOperand(pp, target), cond);
1199 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001200 DCHECK(access == ConstantPoolEntry::REGULAR);
1201 ldr(rd, MemOperand(FLAG_enable_embedded_constant_pool ? pp : pc, 0),
1202 cond);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001203 }
Steve Block44f0eee2011-05-26 01:26:41 +01001204 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001205}
1206
1207
Steve Blocka7e24c12009-10-30 11:49:00 +00001208void Assembler::addrmod1(Instr instr,
1209 Register rn,
1210 Register rd,
1211 const Operand& x) {
1212 CheckBuffer();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001213 DCHECK((instr & ~(kCondMask | kOpCodeMask | S)) == 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00001214 if (!x.rm_.is_valid()) {
Andrei Popescu31002712010-02-23 13:46:05 +00001215 // Immediate.
Steve Blocka7e24c12009-10-30 11:49:00 +00001216 uint32_t rotate_imm;
1217 uint32_t immed_8;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001218 if (x.must_output_reloc_info(this) ||
Steve Blocka7e24c12009-10-30 11:49:00 +00001219 !fits_shifter(x.imm32_, &rotate_imm, &immed_8, &instr)) {
1220 // The immediate operand cannot be encoded as a shifter operand, so load
1221 // it first to register ip and change the original instruction to use ip.
1222 // However, if the original instruction is a 'mov rd, x' (not setting the
Andrei Popescu31002712010-02-23 13:46:05 +00001223 // condition code), then replace it with a 'ldr rd, [pc]'.
Steve Blocka7e24c12009-10-30 11:49:00 +00001224 CHECK(!rn.is(ip)); // rn should never be ip, or will be trashed
Steve Block1e0659c2011-05-24 12:43:12 +01001225 Condition cond = Instruction::ConditionField(instr);
1226 if ((instr & ~kCondMask) == 13*B21) { // mov, S not set
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001227 move_32_bit_immediate(rd, x, cond);
Steve Blocka7e24c12009-10-30 11:49:00 +00001228 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001229 mov(ip, x, LeaveCC, cond);
Steve Blocka7e24c12009-10-30 11:49:00 +00001230 addrmod1(instr, rn, rd, Operand(ip));
1231 }
1232 return;
1233 }
1234 instr |= I | rotate_imm*B8 | immed_8;
1235 } else if (!x.rs_.is_valid()) {
Andrei Popescu31002712010-02-23 13:46:05 +00001236 // Immediate shift.
Steve Blocka7e24c12009-10-30 11:49:00 +00001237 instr |= x.shift_imm_*B7 | x.shift_op_ | x.rm_.code();
1238 } else {
Andrei Popescu31002712010-02-23 13:46:05 +00001239 // Register shift.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001240 DCHECK(!rn.is(pc) && !rd.is(pc) && !x.rm_.is(pc) && !x.rs_.is(pc));
Steve Blocka7e24c12009-10-30 11:49:00 +00001241 instr |= x.rs_.code()*B8 | x.shift_op_ | B4 | x.rm_.code();
1242 }
1243 emit(instr | rn.code()*B16 | rd.code()*B12);
Kristian Monsen50ef84f2010-07-29 15:18:00 +01001244 if (rn.is(pc) || x.rm_.is(pc)) {
Andrei Popescu31002712010-02-23 13:46:05 +00001245 // Block constant pool emission for one instruction after reading pc.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001246 BlockConstPoolFor(1);
Kristian Monsen50ef84f2010-07-29 15:18:00 +01001247 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001248}
1249
1250
1251void Assembler::addrmod2(Instr instr, Register rd, const MemOperand& x) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001252 DCHECK((instr & ~(kCondMask | B | L)) == B26);
Steve Blocka7e24c12009-10-30 11:49:00 +00001253 int am = x.am_;
1254 if (!x.rm_.is_valid()) {
Andrei Popescu31002712010-02-23 13:46:05 +00001255 // Immediate offset.
Steve Blocka7e24c12009-10-30 11:49:00 +00001256 int offset_12 = x.offset_;
1257 if (offset_12 < 0) {
1258 offset_12 = -offset_12;
1259 am ^= U;
1260 }
1261 if (!is_uint12(offset_12)) {
Andrei Popescu31002712010-02-23 13:46:05 +00001262 // Immediate offset cannot be encoded, load it first to register ip
1263 // rn (and rd in a load) should never be ip, or will be trashed.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001264 DCHECK(!x.rn_.is(ip) && ((instr & L) == L || !rd.is(ip)));
Steve Block1e0659c2011-05-24 12:43:12 +01001265 mov(ip, Operand(x.offset_), LeaveCC, Instruction::ConditionField(instr));
Steve Blocka7e24c12009-10-30 11:49:00 +00001266 addrmod2(instr, rd, MemOperand(x.rn_, ip, x.am_));
1267 return;
1268 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001269 DCHECK(offset_12 >= 0); // no masking needed
Steve Blocka7e24c12009-10-30 11:49:00 +00001270 instr |= offset_12;
1271 } else {
Andrei Popescu31002712010-02-23 13:46:05 +00001272 // Register offset (shift_imm_ and shift_op_ are 0) or scaled
Steve Blocka7e24c12009-10-30 11:49:00 +00001273 // register offset the constructors make sure than both shift_imm_
Andrei Popescu31002712010-02-23 13:46:05 +00001274 // and shift_op_ are initialized.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001275 DCHECK(!x.rm_.is(pc));
Steve Blocka7e24c12009-10-30 11:49:00 +00001276 instr |= B25 | x.shift_imm_*B7 | x.shift_op_ | x.rm_.code();
1277 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001278 DCHECK((am & (P|W)) == P || !x.rn_.is(pc)); // no pc base with writeback
Steve Blocka7e24c12009-10-30 11:49:00 +00001279 emit(instr | am | x.rn_.code()*B16 | rd.code()*B12);
1280}
1281
1282
1283void Assembler::addrmod3(Instr instr, Register rd, const MemOperand& x) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001284 DCHECK((instr & ~(kCondMask | L | S6 | H)) == (B4 | B7));
1285 DCHECK(x.rn_.is_valid());
Steve Blocka7e24c12009-10-30 11:49:00 +00001286 int am = x.am_;
1287 if (!x.rm_.is_valid()) {
Andrei Popescu31002712010-02-23 13:46:05 +00001288 // Immediate offset.
Steve Blocka7e24c12009-10-30 11:49:00 +00001289 int offset_8 = x.offset_;
1290 if (offset_8 < 0) {
1291 offset_8 = -offset_8;
1292 am ^= U;
1293 }
1294 if (!is_uint8(offset_8)) {
Andrei Popescu31002712010-02-23 13:46:05 +00001295 // Immediate offset cannot be encoded, load it first to register ip
1296 // rn (and rd in a load) should never be ip, or will be trashed.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001297 DCHECK(!x.rn_.is(ip) && ((instr & L) == L || !rd.is(ip)));
Steve Block1e0659c2011-05-24 12:43:12 +01001298 mov(ip, Operand(x.offset_), LeaveCC, Instruction::ConditionField(instr));
Steve Blocka7e24c12009-10-30 11:49:00 +00001299 addrmod3(instr, rd, MemOperand(x.rn_, ip, x.am_));
1300 return;
1301 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001302 DCHECK(offset_8 >= 0); // no masking needed
Steve Blocka7e24c12009-10-30 11:49:00 +00001303 instr |= B | (offset_8 >> 4)*B8 | (offset_8 & 0xf);
1304 } else if (x.shift_imm_ != 0) {
Andrei Popescu31002712010-02-23 13:46:05 +00001305 // Scaled register offset not supported, load index first
1306 // rn (and rd in a load) should never be ip, or will be trashed.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001307 DCHECK(!x.rn_.is(ip) && ((instr & L) == L || !rd.is(ip)));
Steve Blocka7e24c12009-10-30 11:49:00 +00001308 mov(ip, Operand(x.rm_, x.shift_op_, x.shift_imm_), LeaveCC,
Steve Block1e0659c2011-05-24 12:43:12 +01001309 Instruction::ConditionField(instr));
Steve Blocka7e24c12009-10-30 11:49:00 +00001310 addrmod3(instr, rd, MemOperand(x.rn_, ip, x.am_));
1311 return;
1312 } else {
Andrei Popescu31002712010-02-23 13:46:05 +00001313 // Register offset.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001314 DCHECK((am & (P|W)) == P || !x.rm_.is(pc)); // no pc index with writeback
Steve Blocka7e24c12009-10-30 11:49:00 +00001315 instr |= x.rm_.code();
1316 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001317 DCHECK((am & (P|W)) == P || !x.rn_.is(pc)); // no pc base with writeback
Steve Blocka7e24c12009-10-30 11:49:00 +00001318 emit(instr | am | x.rn_.code()*B16 | rd.code()*B12);
1319}
1320
1321
1322void Assembler::addrmod4(Instr instr, Register rn, RegList rl) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001323 DCHECK((instr & ~(kCondMask | P | U | W | L)) == B27);
1324 DCHECK(rl != 0);
1325 DCHECK(!rn.is(pc));
Steve Blocka7e24c12009-10-30 11:49:00 +00001326 emit(instr | rn.code()*B16 | rl);
1327}
1328
1329
1330void Assembler::addrmod5(Instr instr, CRegister crd, const MemOperand& x) {
Andrei Popescu31002712010-02-23 13:46:05 +00001331 // Unindexed addressing is not encoded by this function.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001332 DCHECK_EQ((B27 | B26),
Steve Block1e0659c2011-05-24 12:43:12 +01001333 (instr & ~(kCondMask | kCoprocessorMask | P | U | N | W | L)));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001334 DCHECK(x.rn_.is_valid() && !x.rm_.is_valid());
Steve Blocka7e24c12009-10-30 11:49:00 +00001335 int am = x.am_;
1336 int offset_8 = x.offset_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001337 DCHECK((offset_8 & 3) == 0); // offset must be an aligned word offset
Steve Blocka7e24c12009-10-30 11:49:00 +00001338 offset_8 >>= 2;
1339 if (offset_8 < 0) {
1340 offset_8 = -offset_8;
1341 am ^= U;
1342 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001343 DCHECK(is_uint8(offset_8)); // unsigned word offset must fit in a byte
1344 DCHECK((am & (P|W)) == P || !x.rn_.is(pc)); // no pc base with writeback
Steve Blocka7e24c12009-10-30 11:49:00 +00001345
Andrei Popescu31002712010-02-23 13:46:05 +00001346 // Post-indexed addressing requires W == 1; different than in addrmod2/3.
Steve Blocka7e24c12009-10-30 11:49:00 +00001347 if ((am & P) == 0)
1348 am |= W;
1349
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001350 DCHECK(offset_8 >= 0); // no masking needed
Steve Blocka7e24c12009-10-30 11:49:00 +00001351 emit(instr | am | x.rn_.code()*B16 | crd.code()*B12 | offset_8);
1352}
1353
1354
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001355int Assembler::branch_offset(Label* L) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001356 int target_pos;
1357 if (L->is_bound()) {
1358 target_pos = L->pos();
1359 } else {
1360 if (L->is_linked()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001361 // Point to previous instruction that uses the link.
1362 target_pos = L->pos();
Steve Blocka7e24c12009-10-30 11:49:00 +00001363 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001364 // First entry of the link chain points to itself.
1365 target_pos = pc_offset();
Steve Blocka7e24c12009-10-30 11:49:00 +00001366 }
1367 L->link_to(pc_offset());
1368 }
1369
1370 // Block the emission of the constant pool, since the branch instruction must
Andrei Popescu31002712010-02-23 13:46:05 +00001371 // be emitted at the pc offset recorded by the label.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001372 if (!is_const_pool_blocked()) BlockConstPoolFor(1);
1373
Steve Blocka7e24c12009-10-30 11:49:00 +00001374 return target_pos - (pc_offset() + kPcLoadDelta);
1375}
1376
1377
Andrei Popescu31002712010-02-23 13:46:05 +00001378// Branch instructions.
Steve Blocka7e24c12009-10-30 11:49:00 +00001379void Assembler::b(int branch_offset, Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001380 DCHECK((branch_offset & 3) == 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00001381 int imm24 = branch_offset >> 2;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001382 CHECK(is_int24(imm24));
Steve Block1e0659c2011-05-24 12:43:12 +01001383 emit(cond | B27 | B25 | (imm24 & kImm24Mask));
Steve Blocka7e24c12009-10-30 11:49:00 +00001384
Steve Block6ded16b2010-05-10 14:33:55 +01001385 if (cond == al) {
Andrei Popescu31002712010-02-23 13:46:05 +00001386 // Dead code is a good location to emit the constant pool.
Steve Blocka7e24c12009-10-30 11:49:00 +00001387 CheckConstPool(false, false);
Steve Block6ded16b2010-05-10 14:33:55 +01001388 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001389}
1390
1391
1392void Assembler::bl(int branch_offset, Condition cond) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01001393 positions_recorder()->WriteRecordedPositions();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001394 DCHECK((branch_offset & 3) == 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00001395 int imm24 = branch_offset >> 2;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001396 CHECK(is_int24(imm24));
Steve Block1e0659c2011-05-24 12:43:12 +01001397 emit(cond | B27 | B25 | B24 | (imm24 & kImm24Mask));
Steve Blocka7e24c12009-10-30 11:49:00 +00001398}
1399
1400
1401void Assembler::blx(int branch_offset) { // v5 and above
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001402 positions_recorder()->WriteRecordedPositions();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001403 DCHECK((branch_offset & 1) == 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00001404 int h = ((branch_offset & 2) >> 1)*B24;
1405 int imm24 = branch_offset >> 2;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001406 CHECK(is_int24(imm24));
Steve Block1e0659c2011-05-24 12:43:12 +01001407 emit(kSpecialCondition | B27 | B25 | h | (imm24 & kImm24Mask));
Steve Blocka7e24c12009-10-30 11:49:00 +00001408}
1409
1410
1411void Assembler::blx(Register target, Condition cond) { // v5 and above
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001412 positions_recorder()->WriteRecordedPositions();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001413 DCHECK(!target.is(pc));
Steve Block1e0659c2011-05-24 12:43:12 +01001414 emit(cond | B24 | B21 | 15*B16 | 15*B12 | 15*B8 | BLX | target.code());
Steve Blocka7e24c12009-10-30 11:49:00 +00001415}
1416
1417
1418void Assembler::bx(Register target, Condition cond) { // v5 and above, plus v4t
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001419 positions_recorder()->WriteRecordedPositions();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001420 DCHECK(!target.is(pc)); // use of pc is actually allowed, but discouraged
Steve Block1e0659c2011-05-24 12:43:12 +01001421 emit(cond | B24 | B21 | 15*B16 | 15*B12 | 15*B8 | BX | target.code());
Steve Blocka7e24c12009-10-30 11:49:00 +00001422}
1423
1424
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001425void Assembler::b(Label* L, Condition cond) {
1426 CheckBuffer();
1427 b(branch_offset(L), cond);
1428}
1429
1430
1431void Assembler::bl(Label* L, Condition cond) {
1432 CheckBuffer();
1433 bl(branch_offset(L), cond);
1434}
1435
1436
1437void Assembler::blx(Label* L) {
1438 CheckBuffer();
1439 blx(branch_offset(L));
1440}
1441
1442
Andrei Popescu31002712010-02-23 13:46:05 +00001443// Data-processing instructions.
1444
Steve Blocka7e24c12009-10-30 11:49:00 +00001445void Assembler::and_(Register dst, Register src1, const Operand& src2,
1446 SBit s, Condition cond) {
Steve Block1e0659c2011-05-24 12:43:12 +01001447 addrmod1(cond | AND | s, src1, dst, src2);
Steve Blocka7e24c12009-10-30 11:49:00 +00001448}
1449
1450
1451void Assembler::eor(Register dst, Register src1, const Operand& src2,
1452 SBit s, Condition cond) {
Steve Block1e0659c2011-05-24 12:43:12 +01001453 addrmod1(cond | EOR | s, src1, dst, src2);
Steve Blocka7e24c12009-10-30 11:49:00 +00001454}
1455
1456
1457void Assembler::sub(Register dst, Register src1, const Operand& src2,
1458 SBit s, Condition cond) {
Steve Block1e0659c2011-05-24 12:43:12 +01001459 addrmod1(cond | SUB | s, src1, dst, src2);
Steve Blocka7e24c12009-10-30 11:49:00 +00001460}
1461
1462
1463void Assembler::rsb(Register dst, Register src1, const Operand& src2,
1464 SBit s, Condition cond) {
Steve Block1e0659c2011-05-24 12:43:12 +01001465 addrmod1(cond | RSB | s, src1, dst, src2);
Steve Blocka7e24c12009-10-30 11:49:00 +00001466}
1467
1468
1469void Assembler::add(Register dst, Register src1, const Operand& src2,
1470 SBit s, Condition cond) {
Steve Block1e0659c2011-05-24 12:43:12 +01001471 addrmod1(cond | ADD | s, src1, dst, src2);
Steve Blocka7e24c12009-10-30 11:49:00 +00001472}
1473
1474
1475void Assembler::adc(Register dst, Register src1, const Operand& src2,
1476 SBit s, Condition cond) {
Steve Block1e0659c2011-05-24 12:43:12 +01001477 addrmod1(cond | ADC | s, src1, dst, src2);
Steve Blocka7e24c12009-10-30 11:49:00 +00001478}
1479
1480
1481void Assembler::sbc(Register dst, Register src1, const Operand& src2,
1482 SBit s, Condition cond) {
Steve Block1e0659c2011-05-24 12:43:12 +01001483 addrmod1(cond | SBC | s, src1, dst, src2);
Steve Blocka7e24c12009-10-30 11:49:00 +00001484}
1485
1486
1487void Assembler::rsc(Register dst, Register src1, const Operand& src2,
1488 SBit s, Condition cond) {
Steve Block1e0659c2011-05-24 12:43:12 +01001489 addrmod1(cond | RSC | s, src1, dst, src2);
Steve Blocka7e24c12009-10-30 11:49:00 +00001490}
1491
1492
1493void Assembler::tst(Register src1, const Operand& src2, Condition cond) {
Steve Block1e0659c2011-05-24 12:43:12 +01001494 addrmod1(cond | TST | S, src1, r0, src2);
Steve Blocka7e24c12009-10-30 11:49:00 +00001495}
1496
1497
1498void Assembler::teq(Register src1, const Operand& src2, Condition cond) {
Steve Block1e0659c2011-05-24 12:43:12 +01001499 addrmod1(cond | TEQ | S, src1, r0, src2);
Steve Blocka7e24c12009-10-30 11:49:00 +00001500}
1501
1502
1503void Assembler::cmp(Register src1, const Operand& src2, Condition cond) {
Steve Block1e0659c2011-05-24 12:43:12 +01001504 addrmod1(cond | CMP | S, src1, r0, src2);
1505}
1506
1507
1508void Assembler::cmp_raw_immediate(
1509 Register src, int raw_immediate, Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001510 DCHECK(is_uint12(raw_immediate));
Steve Block1e0659c2011-05-24 12:43:12 +01001511 emit(cond | I | CMP | S | src.code() << 16 | raw_immediate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001512}
1513
1514
1515void Assembler::cmn(Register src1, const Operand& src2, Condition cond) {
Steve Block1e0659c2011-05-24 12:43:12 +01001516 addrmod1(cond | CMN | S, src1, r0, src2);
Steve Blocka7e24c12009-10-30 11:49:00 +00001517}
1518
1519
1520void Assembler::orr(Register dst, Register src1, const Operand& src2,
1521 SBit s, Condition cond) {
Steve Block1e0659c2011-05-24 12:43:12 +01001522 addrmod1(cond | ORR | s, src1, dst, src2);
Steve Blocka7e24c12009-10-30 11:49:00 +00001523}
1524
1525
1526void Assembler::mov(Register dst, const Operand& src, SBit s, Condition cond) {
1527 if (dst.is(pc)) {
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001528 positions_recorder()->WriteRecordedPositions();
Steve Blocka7e24c12009-10-30 11:49:00 +00001529 }
Steve Block6ded16b2010-05-10 14:33:55 +01001530 // Don't allow nop instructions in the form mov rn, rn to be generated using
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001531 // the mov instruction. They must be generated using nop(int/NopMarkerTypes)
1532 // or MarkCode(int/NopMarkerTypes) pseudo instructions.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001533 DCHECK(!(src.is_reg() && src.rm().is(dst) && s == LeaveCC && cond == al));
Steve Block1e0659c2011-05-24 12:43:12 +01001534 addrmod1(cond | MOV | s, r0, dst, src);
Steve Blocka7e24c12009-10-30 11:49:00 +00001535}
1536
1537
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001538void Assembler::mov_label_offset(Register dst, Label* label) {
1539 if (label->is_bound()) {
1540 mov(dst, Operand(label->pos() + (Code::kHeaderSize - kHeapObjectTag)));
1541 } else {
1542 // Emit the link to the label in the code stream followed by extra nop
1543 // instructions.
1544 // If the label is not linked, then start a new link chain by linking it to
1545 // itself, emitting pc_offset().
1546 int link = label->is_linked() ? label->pos() : pc_offset();
1547 label->link_to(pc_offset());
1548
1549 // When the label is bound, these instructions will be patched with a
1550 // sequence of movw/movt or mov/orr/orr instructions. They will load the
1551 // destination register with the position of the label from the beginning
1552 // of the code.
1553 //
1554 // The link will be extracted from the first instruction and the destination
1555 // register from the second.
1556 // For ARMv7:
1557 // link
1558 // mov dst, dst
1559 // For ARMv6:
1560 // link
1561 // mov dst, dst
1562 // mov dst, dst
1563 //
1564 // When the label gets bound: target_at extracts the link and target_at_put
1565 // patches the instructions.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001566 CHECK(is_uint24(link));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001567 BlockConstPoolScope block_const_pool(this);
1568 emit(link);
1569 nop(dst.code());
1570 if (!CpuFeatures::IsSupported(ARMv7)) {
1571 nop(dst.code());
1572 }
1573 }
1574}
1575
1576
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001577void Assembler::movw(Register reg, uint32_t immediate, Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001578 DCHECK(CpuFeatures::IsSupported(ARMv7));
1579 emit(cond | 0x30*B20 | reg.code()*B12 | EncodeMovwImmediate(immediate));
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001580}
1581
1582
1583void Assembler::movt(Register reg, uint32_t immediate, Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001584 DCHECK(CpuFeatures::IsSupported(ARMv7));
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001585 emit(cond | 0x34*B20 | reg.code()*B12 | EncodeMovwImmediate(immediate));
1586}
1587
1588
Steve Blocka7e24c12009-10-30 11:49:00 +00001589void Assembler::bic(Register dst, Register src1, const Operand& src2,
1590 SBit s, Condition cond) {
Steve Block1e0659c2011-05-24 12:43:12 +01001591 addrmod1(cond | BIC | s, src1, dst, src2);
Steve Blocka7e24c12009-10-30 11:49:00 +00001592}
1593
1594
1595void Assembler::mvn(Register dst, const Operand& src, SBit s, Condition cond) {
Steve Block1e0659c2011-05-24 12:43:12 +01001596 addrmod1(cond | MVN | s, r0, dst, src);
Steve Blocka7e24c12009-10-30 11:49:00 +00001597}
1598
1599
Andrei Popescu31002712010-02-23 13:46:05 +00001600// Multiply instructions.
Steve Blocka7e24c12009-10-30 11:49:00 +00001601void Assembler::mla(Register dst, Register src1, Register src2, Register srcA,
1602 SBit s, Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001603 DCHECK(!dst.is(pc) && !src1.is(pc) && !src2.is(pc) && !srcA.is(pc));
Steve Blocka7e24c12009-10-30 11:49:00 +00001604 emit(cond | A | s | dst.code()*B16 | srcA.code()*B12 |
1605 src2.code()*B8 | B7 | B4 | src1.code());
1606}
1607
1608
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001609void Assembler::mls(Register dst, Register src1, Register src2, Register srcA,
1610 Condition cond) {
1611 DCHECK(!dst.is(pc) && !src1.is(pc) && !src2.is(pc) && !srcA.is(pc));
1612 DCHECK(IsEnabled(MLS));
1613 emit(cond | B22 | B21 | dst.code()*B16 | srcA.code()*B12 |
1614 src2.code()*B8 | B7 | B4 | src1.code());
1615}
1616
1617
1618void Assembler::sdiv(Register dst, Register src1, Register src2,
1619 Condition cond) {
1620 DCHECK(!dst.is(pc) && !src1.is(pc) && !src2.is(pc));
1621 DCHECK(IsEnabled(SUDIV));
1622 emit(cond | B26 | B25| B24 | B20 | dst.code()*B16 | 0xf * B12 |
1623 src2.code()*B8 | B4 | src1.code());
1624}
1625
1626
1627void Assembler::udiv(Register dst, Register src1, Register src2,
1628 Condition cond) {
1629 DCHECK(!dst.is(pc) && !src1.is(pc) && !src2.is(pc));
1630 DCHECK(IsEnabled(SUDIV));
1631 emit(cond | B26 | B25 | B24 | B21 | B20 | dst.code() * B16 | 0xf * B12 |
1632 src2.code() * B8 | B4 | src1.code());
1633}
1634
1635
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001636void Assembler::mul(Register dst, Register src1, Register src2, SBit s,
1637 Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001638 DCHECK(!dst.is(pc) && !src1.is(pc) && !src2.is(pc));
Steve Blocka7e24c12009-10-30 11:49:00 +00001639 // dst goes in bits 16-19 for this instruction!
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001640 emit(cond | s | dst.code() * B16 | src2.code() * B8 | B7 | B4 | src1.code());
1641}
1642
1643
1644void Assembler::smmla(Register dst, Register src1, Register src2, Register srcA,
1645 Condition cond) {
1646 DCHECK(!dst.is(pc) && !src1.is(pc) && !src2.is(pc) && !srcA.is(pc));
1647 emit(cond | B26 | B25 | B24 | B22 | B20 | dst.code() * B16 |
1648 srcA.code() * B12 | src2.code() * B8 | B4 | src1.code());
1649}
1650
1651
1652void Assembler::smmul(Register dst, Register src1, Register src2,
1653 Condition cond) {
1654 DCHECK(!dst.is(pc) && !src1.is(pc) && !src2.is(pc));
1655 emit(cond | B26 | B25 | B24 | B22 | B20 | dst.code() * B16 | 0xf * B12 |
1656 src2.code() * B8 | B4 | src1.code());
Steve Blocka7e24c12009-10-30 11:49:00 +00001657}
1658
1659
1660void Assembler::smlal(Register dstL,
1661 Register dstH,
1662 Register src1,
1663 Register src2,
1664 SBit s,
1665 Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001666 DCHECK(!dstL.is(pc) && !dstH.is(pc) && !src1.is(pc) && !src2.is(pc));
1667 DCHECK(!dstL.is(dstH));
Steve Blocka7e24c12009-10-30 11:49:00 +00001668 emit(cond | B23 | B22 | A | s | dstH.code()*B16 | dstL.code()*B12 |
1669 src2.code()*B8 | B7 | B4 | src1.code());
1670}
1671
1672
1673void Assembler::smull(Register dstL,
1674 Register dstH,
1675 Register src1,
1676 Register src2,
1677 SBit s,
1678 Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001679 DCHECK(!dstL.is(pc) && !dstH.is(pc) && !src1.is(pc) && !src2.is(pc));
1680 DCHECK(!dstL.is(dstH));
Steve Blocka7e24c12009-10-30 11:49:00 +00001681 emit(cond | B23 | B22 | s | dstH.code()*B16 | dstL.code()*B12 |
1682 src2.code()*B8 | B7 | B4 | src1.code());
1683}
1684
1685
1686void Assembler::umlal(Register dstL,
1687 Register dstH,
1688 Register src1,
1689 Register src2,
1690 SBit s,
1691 Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001692 DCHECK(!dstL.is(pc) && !dstH.is(pc) && !src1.is(pc) && !src2.is(pc));
1693 DCHECK(!dstL.is(dstH));
Steve Blocka7e24c12009-10-30 11:49:00 +00001694 emit(cond | B23 | A | s | dstH.code()*B16 | dstL.code()*B12 |
1695 src2.code()*B8 | B7 | B4 | src1.code());
1696}
1697
1698
1699void Assembler::umull(Register dstL,
1700 Register dstH,
1701 Register src1,
1702 Register src2,
1703 SBit s,
1704 Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001705 DCHECK(!dstL.is(pc) && !dstH.is(pc) && !src1.is(pc) && !src2.is(pc));
1706 DCHECK(!dstL.is(dstH));
Steve Blocka7e24c12009-10-30 11:49:00 +00001707 emit(cond | B23 | s | dstH.code()*B16 | dstL.code()*B12 |
1708 src2.code()*B8 | B7 | B4 | src1.code());
1709}
1710
1711
Andrei Popescu31002712010-02-23 13:46:05 +00001712// Miscellaneous arithmetic instructions.
Steve Blocka7e24c12009-10-30 11:49:00 +00001713void Assembler::clz(Register dst, Register src, Condition cond) {
1714 // v5 and above.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001715 DCHECK(!dst.is(pc) && !src.is(pc));
Steve Blocka7e24c12009-10-30 11:49:00 +00001716 emit(cond | B24 | B22 | B21 | 15*B16 | dst.code()*B12 |
Steve Block1e0659c2011-05-24 12:43:12 +01001717 15*B8 | CLZ | src.code());
Steve Blocka7e24c12009-10-30 11:49:00 +00001718}
1719
1720
Kristian Monsen50ef84f2010-07-29 15:18:00 +01001721// Saturating instructions.
1722
1723// Unsigned saturate.
1724void Assembler::usat(Register dst,
1725 int satpos,
1726 const Operand& src,
1727 Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001728 DCHECK(!dst.is(pc) && !src.rm_.is(pc));
1729 DCHECK((satpos >= 0) && (satpos <= 31));
1730 DCHECK((src.shift_op_ == ASR) || (src.shift_op_ == LSL));
1731 DCHECK(src.rs_.is(no_reg));
Kristian Monsen50ef84f2010-07-29 15:18:00 +01001732
1733 int sh = 0;
1734 if (src.shift_op_ == ASR) {
1735 sh = 1;
1736 }
1737
1738 emit(cond | 0x6*B24 | 0xe*B20 | satpos*B16 | dst.code()*B12 |
1739 src.shift_imm_*B7 | sh*B6 | 0x1*B4 | src.rm_.code());
1740}
1741
1742
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001743// Bitfield manipulation instructions.
1744
1745// Unsigned bit field extract.
1746// Extracts #width adjacent bits from position #lsb in a register, and
1747// writes them to the low bits of a destination register.
1748// ubfx dst, src, #lsb, #width
1749void Assembler::ubfx(Register dst,
1750 Register src,
1751 int lsb,
1752 int width,
1753 Condition cond) {
1754 // v7 and above.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001755 DCHECK(CpuFeatures::IsSupported(ARMv7));
1756 DCHECK(!dst.is(pc) && !src.is(pc));
1757 DCHECK((lsb >= 0) && (lsb <= 31));
1758 DCHECK((width >= 1) && (width <= (32 - lsb)));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001759 emit(cond | 0xf*B23 | B22 | B21 | (width - 1)*B16 | dst.code()*B12 |
1760 lsb*B7 | B6 | B4 | src.code());
1761}
1762
1763
1764// Signed bit field extract.
1765// Extracts #width adjacent bits from position #lsb in a register, and
1766// writes them to the low bits of a destination register. The extracted
1767// value is sign extended to fill the destination register.
1768// sbfx dst, src, #lsb, #width
1769void Assembler::sbfx(Register dst,
1770 Register src,
1771 int lsb,
1772 int width,
1773 Condition cond) {
1774 // v7 and above.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001775 DCHECK(CpuFeatures::IsSupported(ARMv7));
1776 DCHECK(!dst.is(pc) && !src.is(pc));
1777 DCHECK((lsb >= 0) && (lsb <= 31));
1778 DCHECK((width >= 1) && (width <= (32 - lsb)));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001779 emit(cond | 0xf*B23 | B21 | (width - 1)*B16 | dst.code()*B12 |
1780 lsb*B7 | B6 | B4 | src.code());
1781}
1782
1783
1784// Bit field clear.
1785// Sets #width adjacent bits at position #lsb in the destination register
1786// to zero, preserving the value of the other bits.
1787// bfc dst, #lsb, #width
1788void Assembler::bfc(Register dst, int lsb, int width, Condition cond) {
1789 // v7 and above.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001790 DCHECK(CpuFeatures::IsSupported(ARMv7));
1791 DCHECK(!dst.is(pc));
1792 DCHECK((lsb >= 0) && (lsb <= 31));
1793 DCHECK((width >= 1) && (width <= (32 - lsb)));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001794 int msb = lsb + width - 1;
1795 emit(cond | 0x1f*B22 | msb*B16 | dst.code()*B12 | lsb*B7 | B4 | 0xf);
1796}
1797
1798
1799// Bit field insert.
1800// Inserts #width adjacent bits from the low bits of the source register
1801// into position #lsb of the destination register.
1802// bfi dst, src, #lsb, #width
1803void Assembler::bfi(Register dst,
1804 Register src,
1805 int lsb,
1806 int width,
1807 Condition cond) {
1808 // v7 and above.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001809 DCHECK(CpuFeatures::IsSupported(ARMv7));
1810 DCHECK(!dst.is(pc) && !src.is(pc));
1811 DCHECK((lsb >= 0) && (lsb <= 31));
1812 DCHECK((width >= 1) && (width <= (32 - lsb)));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001813 int msb = lsb + width - 1;
1814 emit(cond | 0x1f*B22 | msb*B16 | dst.code()*B12 | lsb*B7 | B4 |
1815 src.code());
1816}
1817
1818
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001819void Assembler::pkhbt(Register dst,
1820 Register src1,
1821 const Operand& src2,
1822 Condition cond ) {
1823 // Instruction details available in ARM DDI 0406C.b, A8.8.125.
1824 // cond(31-28) | 01101000(27-20) | Rn(19-16) |
1825 // Rd(15-12) | imm5(11-7) | 0(6) | 01(5-4) | Rm(3-0)
1826 DCHECK(!dst.is(pc));
1827 DCHECK(!src1.is(pc));
1828 DCHECK(!src2.rm().is(pc));
1829 DCHECK(!src2.rm().is(no_reg));
1830 DCHECK(src2.rs().is(no_reg));
1831 DCHECK((src2.shift_imm_ >= 0) && (src2.shift_imm_ <= 31));
1832 DCHECK(src2.shift_op() == LSL);
1833 emit(cond | 0x68*B20 | src1.code()*B16 | dst.code()*B12 |
1834 src2.shift_imm_*B7 | B4 | src2.rm().code());
1835}
1836
1837
1838void Assembler::pkhtb(Register dst,
1839 Register src1,
1840 const Operand& src2,
1841 Condition cond) {
1842 // Instruction details available in ARM DDI 0406C.b, A8.8.125.
1843 // cond(31-28) | 01101000(27-20) | Rn(19-16) |
1844 // Rd(15-12) | imm5(11-7) | 1(6) | 01(5-4) | Rm(3-0)
1845 DCHECK(!dst.is(pc));
1846 DCHECK(!src1.is(pc));
1847 DCHECK(!src2.rm().is(pc));
1848 DCHECK(!src2.rm().is(no_reg));
1849 DCHECK(src2.rs().is(no_reg));
1850 DCHECK((src2.shift_imm_ >= 1) && (src2.shift_imm_ <= 32));
1851 DCHECK(src2.shift_op() == ASR);
1852 int asr = (src2.shift_imm_ == 32) ? 0 : src2.shift_imm_;
1853 emit(cond | 0x68*B20 | src1.code()*B16 | dst.code()*B12 |
1854 asr*B7 | B6 | B4 | src2.rm().code());
1855}
1856
1857
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001858void Assembler::sxtb(Register dst, Register src, int rotate, Condition cond) {
1859 // Instruction details available in ARM DDI 0406C.b, A8.8.233.
1860 // cond(31-28) | 01101010(27-20) | 1111(19-16) |
1861 // Rd(15-12) | rotate(11-10) | 00(9-8)| 0111(7-4) | Rm(3-0)
1862 DCHECK(!dst.is(pc));
1863 DCHECK(!src.is(pc));
1864 DCHECK(rotate == 0 || rotate == 8 || rotate == 16 || rotate == 24);
1865 emit(cond | 0x6A * B20 | 0xF * B16 | dst.code() * B12 |
1866 ((rotate >> 1) & 0xC) * B8 | 7 * B4 | src.code());
1867}
1868
1869
1870void Assembler::sxtab(Register dst, Register src1, Register src2, int rotate,
1871 Condition cond) {
1872 // Instruction details available in ARM DDI 0406C.b, A8.8.233.
1873 // cond(31-28) | 01101010(27-20) | Rn(19-16) |
1874 // Rd(15-12) | rotate(11-10) | 00(9-8)| 0111(7-4) | Rm(3-0)
1875 DCHECK(!dst.is(pc));
1876 DCHECK(!src1.is(pc));
1877 DCHECK(!src2.is(pc));
1878 DCHECK(rotate == 0 || rotate == 8 || rotate == 16 || rotate == 24);
1879 emit(cond | 0x6A * B20 | src1.code() * B16 | dst.code() * B12 |
1880 ((rotate >> 1) & 0xC) * B8 | 7 * B4 | src2.code());
1881}
1882
1883
1884void Assembler::sxth(Register dst, Register src, int rotate, Condition cond) {
1885 // Instruction details available in ARM DDI 0406C.b, A8.8.235.
1886 // cond(31-28) | 01101011(27-20) | 1111(19-16) |
1887 // Rd(15-12) | rotate(11-10) | 00(9-8)| 0111(7-4) | Rm(3-0)
1888 DCHECK(!dst.is(pc));
1889 DCHECK(!src.is(pc));
1890 DCHECK(rotate == 0 || rotate == 8 || rotate == 16 || rotate == 24);
1891 emit(cond | 0x6B * B20 | 0xF * B16 | dst.code() * B12 |
1892 ((rotate >> 1) & 0xC) * B8 | 7 * B4 | src.code());
1893}
1894
1895
1896void Assembler::sxtah(Register dst, Register src1, Register src2, int rotate,
1897 Condition cond) {
1898 // Instruction details available in ARM DDI 0406C.b, A8.8.235.
1899 // cond(31-28) | 01101011(27-20) | Rn(19-16) |
1900 // Rd(15-12) | rotate(11-10) | 00(9-8)| 0111(7-4) | Rm(3-0)
1901 DCHECK(!dst.is(pc));
1902 DCHECK(!src1.is(pc));
1903 DCHECK(!src2.is(pc));
1904 DCHECK(rotate == 0 || rotate == 8 || rotate == 16 || rotate == 24);
1905 emit(cond | 0x6B * B20 | src1.code() * B16 | dst.code() * B12 |
1906 ((rotate >> 1) & 0xC) * B8 | 7 * B4 | src2.code());
1907}
1908
1909
1910void Assembler::uxtb(Register dst, Register src, int rotate, Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001911 // Instruction details available in ARM DDI 0406C.b, A8.8.274.
1912 // cond(31-28) | 01101110(27-20) | 1111(19-16) |
1913 // Rd(15-12) | rotate(11-10) | 00(9-8)| 0111(7-4) | Rm(3-0)
1914 DCHECK(!dst.is(pc));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001915 DCHECK(!src.is(pc));
1916 DCHECK(rotate == 0 || rotate == 8 || rotate == 16 || rotate == 24);
1917 emit(cond | 0x6E * B20 | 0xF * B16 | dst.code() * B12 |
1918 ((rotate >> 1) & 0xC) * B8 | 7 * B4 | src.code());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001919}
1920
1921
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001922void Assembler::uxtab(Register dst, Register src1, Register src2, int rotate,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001923 Condition cond) {
1924 // Instruction details available in ARM DDI 0406C.b, A8.8.271.
1925 // cond(31-28) | 01101110(27-20) | Rn(19-16) |
1926 // Rd(15-12) | rotate(11-10) | 00(9-8)| 0111(7-4) | Rm(3-0)
1927 DCHECK(!dst.is(pc));
1928 DCHECK(!src1.is(pc));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001929 DCHECK(!src2.is(pc));
1930 DCHECK(rotate == 0 || rotate == 8 || rotate == 16 || rotate == 24);
1931 emit(cond | 0x6E * B20 | src1.code() * B16 | dst.code() * B12 |
1932 ((rotate >> 1) & 0xC) * B8 | 7 * B4 | src2.code());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001933}
1934
1935
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001936void Assembler::uxtb16(Register dst, Register src, int rotate, Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001937 // Instruction details available in ARM DDI 0406C.b, A8.8.275.
1938 // cond(31-28) | 01101100(27-20) | 1111(19-16) |
1939 // Rd(15-12) | rotate(11-10) | 00(9-8)| 0111(7-4) | Rm(3-0)
1940 DCHECK(!dst.is(pc));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001941 DCHECK(!src.is(pc));
1942 DCHECK(rotate == 0 || rotate == 8 || rotate == 16 || rotate == 24);
1943 emit(cond | 0x6C * B20 | 0xF * B16 | dst.code() * B12 |
1944 ((rotate >> 1) & 0xC) * B8 | 7 * B4 | src.code());
1945}
1946
1947
1948void Assembler::uxth(Register dst, Register src, int rotate, Condition cond) {
1949 // Instruction details available in ARM DDI 0406C.b, A8.8.276.
1950 // cond(31-28) | 01101111(27-20) | 1111(19-16) |
1951 // Rd(15-12) | rotate(11-10) | 00(9-8)| 0111(7-4) | Rm(3-0)
1952 DCHECK(!dst.is(pc));
1953 DCHECK(!src.is(pc));
1954 DCHECK(rotate == 0 || rotate == 8 || rotate == 16 || rotate == 24);
1955 emit(cond | 0x6F * B20 | 0xF * B16 | dst.code() * B12 |
1956 ((rotate >> 1) & 0xC) * B8 | 7 * B4 | src.code());
1957}
1958
1959
1960void Assembler::uxtah(Register dst, Register src1, Register src2, int rotate,
1961 Condition cond) {
1962 // Instruction details available in ARM DDI 0406C.b, A8.8.273.
1963 // cond(31-28) | 01101111(27-20) | Rn(19-16) |
1964 // Rd(15-12) | rotate(11-10) | 00(9-8)| 0111(7-4) | Rm(3-0)
1965 DCHECK(!dst.is(pc));
1966 DCHECK(!src1.is(pc));
1967 DCHECK(!src2.is(pc));
1968 DCHECK(rotate == 0 || rotate == 8 || rotate == 16 || rotate == 24);
1969 emit(cond | 0x6F * B20 | src1.code() * B16 | dst.code() * B12 |
1970 ((rotate >> 1) & 0xC) * B8 | 7 * B4 | src2.code());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001971}
1972
1973
Ben Murdoch097c5b22016-05-18 11:27:45 +01001974void Assembler::rbit(Register dst, Register src, Condition cond) {
1975 // Instruction details available in ARM DDI 0406C.b, A8.8.144.
1976 // cond(31-28) | 011011111111(27-16) | Rd(15-12) | 11110011(11-4) | Rm(3-0)
1977 DCHECK(IsEnabled(ARMv7));
1978 DCHECK(!dst.is(pc));
1979 DCHECK(!src.is(pc));
1980 emit(cond | 0x6FF * B16 | dst.code() * B12 | 0xF3 * B4 | src.code());
1981}
1982
1983
Andrei Popescu31002712010-02-23 13:46:05 +00001984// Status register access instructions.
Steve Blocka7e24c12009-10-30 11:49:00 +00001985void Assembler::mrs(Register dst, SRegister s, Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001986 DCHECK(!dst.is(pc));
Steve Blocka7e24c12009-10-30 11:49:00 +00001987 emit(cond | B24 | s | 15*B16 | dst.code()*B12);
1988}
1989
1990
1991void Assembler::msr(SRegisterFieldMask fields, const Operand& src,
1992 Condition cond) {
Ben Murdochda12d292016-06-02 14:46:10 +01001993 DCHECK((fields & 0x000f0000) != 0); // At least one field must be set.
1994 DCHECK(((fields & 0xfff0ffff) == CPSR) || ((fields & 0xfff0ffff) == SPSR));
Steve Blocka7e24c12009-10-30 11:49:00 +00001995 Instr instr;
1996 if (!src.rm_.is_valid()) {
Andrei Popescu31002712010-02-23 13:46:05 +00001997 // Immediate.
Steve Blocka7e24c12009-10-30 11:49:00 +00001998 uint32_t rotate_imm;
1999 uint32_t immed_8;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002000 if (src.must_output_reloc_info(this) ||
Steve Blocka7e24c12009-10-30 11:49:00 +00002001 !fits_shifter(src.imm32_, &rotate_imm, &immed_8, NULL)) {
Andrei Popescu31002712010-02-23 13:46:05 +00002002 // Immediate operand cannot be encoded, load it first to register ip.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002003 move_32_bit_immediate(ip, src);
Steve Blocka7e24c12009-10-30 11:49:00 +00002004 msr(fields, Operand(ip), cond);
2005 return;
2006 }
2007 instr = I | rotate_imm*B8 | immed_8;
2008 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002009 DCHECK(!src.rs_.is_valid() && src.shift_imm_ == 0); // only rm allowed
Steve Blocka7e24c12009-10-30 11:49:00 +00002010 instr = src.rm_.code();
2011 }
2012 emit(cond | instr | B24 | B21 | fields | 15*B12);
2013}
2014
2015
Andrei Popescu31002712010-02-23 13:46:05 +00002016// Load/Store instructions.
Steve Blocka7e24c12009-10-30 11:49:00 +00002017void Assembler::ldr(Register dst, const MemOperand& src, Condition cond) {
2018 if (dst.is(pc)) {
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002019 positions_recorder()->WriteRecordedPositions();
Steve Blocka7e24c12009-10-30 11:49:00 +00002020 }
2021 addrmod2(cond | B26 | L, dst, src);
Steve Blocka7e24c12009-10-30 11:49:00 +00002022}
2023
2024
2025void Assembler::str(Register src, const MemOperand& dst, Condition cond) {
2026 addrmod2(cond | B26, src, dst);
Steve Blocka7e24c12009-10-30 11:49:00 +00002027}
2028
2029
2030void Assembler::ldrb(Register dst, const MemOperand& src, Condition cond) {
2031 addrmod2(cond | B26 | B | L, dst, src);
2032}
2033
2034
2035void Assembler::strb(Register src, const MemOperand& dst, Condition cond) {
2036 addrmod2(cond | B26 | B, src, dst);
2037}
2038
2039
2040void Assembler::ldrh(Register dst, const MemOperand& src, Condition cond) {
2041 addrmod3(cond | L | B7 | H | B4, dst, src);
2042}
2043
2044
2045void Assembler::strh(Register src, const MemOperand& dst, Condition cond) {
2046 addrmod3(cond | B7 | H | B4, src, dst);
2047}
2048
2049
2050void Assembler::ldrsb(Register dst, const MemOperand& src, Condition cond) {
2051 addrmod3(cond | L | B7 | S6 | B4, dst, src);
2052}
2053
2054
2055void Assembler::ldrsh(Register dst, const MemOperand& src, Condition cond) {
2056 addrmod3(cond | L | B7 | S6 | H | B4, dst, src);
2057}
2058
2059
Leon Clarkef7060e22010-06-03 12:02:55 +01002060void Assembler::ldrd(Register dst1, Register dst2,
2061 const MemOperand& src, Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002062 DCHECK(src.rm().is(no_reg));
2063 DCHECK(!dst1.is(lr)); // r14.
2064 DCHECK_EQ(0, dst1.code() % 2);
2065 DCHECK_EQ(dst1.code() + 1, dst2.code());
Leon Clarkef7060e22010-06-03 12:02:55 +01002066 addrmod3(cond | B7 | B6 | B4, dst1, src);
Kristian Monsen25f61362010-05-21 11:50:48 +01002067}
2068
2069
Leon Clarkef7060e22010-06-03 12:02:55 +01002070void Assembler::strd(Register src1, Register src2,
2071 const MemOperand& dst, Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002072 DCHECK(dst.rm().is(no_reg));
2073 DCHECK(!src1.is(lr)); // r14.
2074 DCHECK_EQ(0, src1.code() % 2);
2075 DCHECK_EQ(src1.code() + 1, src2.code());
Leon Clarkef7060e22010-06-03 12:02:55 +01002076 addrmod3(cond | B7 | B6 | B5 | B4, src1, dst);
Kristian Monsen25f61362010-05-21 11:50:48 +01002077}
2078
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002079
2080// Preload instructions.
2081void Assembler::pld(const MemOperand& address) {
2082 // Instruction details available in ARM DDI 0406C.b, A8.8.128.
2083 // 1111(31-28) | 0111(27-24) | U(23) | R(22) | 01(21-20) | Rn(19-16) |
2084 // 1111(15-12) | imm5(11-07) | type(6-5) | 0(4)| Rm(3-0) |
2085 DCHECK(address.rm().is(no_reg));
2086 DCHECK(address.am() == Offset);
2087 int U = B23;
2088 int offset = address.offset();
2089 if (offset < 0) {
2090 offset = -offset;
2091 U = 0;
2092 }
2093 DCHECK(offset < 4096);
2094 emit(kSpecialCondition | B26 | B24 | U | B22 | B20 | address.rn().code()*B16 |
2095 0xf*B12 | offset);
2096}
2097
2098
Andrei Popescu31002712010-02-23 13:46:05 +00002099// Load/Store multiple instructions.
Steve Blocka7e24c12009-10-30 11:49:00 +00002100void Assembler::ldm(BlockAddrMode am,
2101 Register base,
2102 RegList dst,
2103 Condition cond) {
Andrei Popescu31002712010-02-23 13:46:05 +00002104 // ABI stack constraint: ldmxx base, {..sp..} base != sp is not restartable.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002105 DCHECK(base.is(sp) || (dst & sp.bit()) == 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00002106
2107 addrmod4(cond | B27 | am | L, base, dst);
2108
Andrei Popescu31002712010-02-23 13:46:05 +00002109 // Emit the constant pool after a function return implemented by ldm ..{..pc}.
Steve Blocka7e24c12009-10-30 11:49:00 +00002110 if (cond == al && (dst & pc.bit()) != 0) {
2111 // There is a slight chance that the ldm instruction was actually a call,
2112 // in which case it would be wrong to return into the constant pool; we
2113 // recognize this case by checking if the emission of the pool was blocked
2114 // at the pc of the ldm instruction by a mov lr, pc instruction; if this is
2115 // the case, we emit a jump over the pool.
2116 CheckConstPool(true, no_const_pool_before_ == pc_offset() - kInstrSize);
2117 }
2118}
2119
2120
2121void Assembler::stm(BlockAddrMode am,
2122 Register base,
2123 RegList src,
2124 Condition cond) {
2125 addrmod4(cond | B27 | am, base, src);
2126}
2127
2128
Andrei Popescu31002712010-02-23 13:46:05 +00002129// Exception-generating instructions and debugging support.
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002130// Stops with a non-negative code less than kNumOfWatchedStops support
2131// enabling/disabling and a counter feature. See simulator-arm.h .
2132void Assembler::stop(const char* msg, Condition cond, int32_t code) {
Andrei Popescu402d9372010-02-26 13:31:12 +00002133#ifndef __arm__
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002134 DCHECK(code >= kDefaultStopCode);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002135 {
2136 // The Simulator will handle the stop instruction and get the message
2137 // address. It expects to find the address just after the svc instruction.
2138 BlockConstPoolScope block_const_pool(this);
2139 if (code >= 0) {
2140 svc(kStopCode + code, cond);
2141 } else {
2142 svc(kStopCode + kMaxStopCode, cond);
2143 }
2144 emit(reinterpret_cast<Instr>(msg));
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002145 }
Andrei Popescu402d9372010-02-26 13:31:12 +00002146#else // def __arm__
Steve Block1e0659c2011-05-24 12:43:12 +01002147 if (cond != al) {
2148 Label skip;
2149 b(&skip, NegateCondition(cond));
2150 bkpt(0);
2151 bind(&skip);
2152 } else {
2153 bkpt(0);
2154 }
Andrei Popescu402d9372010-02-26 13:31:12 +00002155#endif // def __arm__
Steve Blocka7e24c12009-10-30 11:49:00 +00002156}
2157
2158
2159void Assembler::bkpt(uint32_t imm16) { // v5 and above
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002160 DCHECK(is_uint16(imm16));
Steve Block1e0659c2011-05-24 12:43:12 +01002161 emit(al | B24 | B21 | (imm16 >> 4)*B8 | BKPT | (imm16 & 0xf));
Steve Blocka7e24c12009-10-30 11:49:00 +00002162}
2163
2164
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002165void Assembler::svc(uint32_t imm24, Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002166 DCHECK(is_uint24(imm24));
Steve Blocka7e24c12009-10-30 11:49:00 +00002167 emit(cond | 15*B24 | imm24);
2168}
2169
2170
Ben Murdoch097c5b22016-05-18 11:27:45 +01002171void Assembler::dmb(BarrierOption option) {
2172 emit(kSpecialCondition | 0x57ff*B12 | 5*B4 | option);
2173}
2174
2175
2176void Assembler::dsb(BarrierOption option) {
2177 emit(kSpecialCondition | 0x57ff*B12 | 4*B4 | option);
2178}
2179
2180
2181void Assembler::isb(BarrierOption option) {
2182 emit(kSpecialCondition | 0x57ff*B12 | 6*B4 | option);
2183}
2184
2185
Andrei Popescu31002712010-02-23 13:46:05 +00002186// Coprocessor instructions.
Steve Blocka7e24c12009-10-30 11:49:00 +00002187void Assembler::cdp(Coprocessor coproc,
2188 int opcode_1,
2189 CRegister crd,
2190 CRegister crn,
2191 CRegister crm,
2192 int opcode_2,
2193 Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002194 DCHECK(is_uint4(opcode_1) && is_uint3(opcode_2));
Steve Blocka7e24c12009-10-30 11:49:00 +00002195 emit(cond | B27 | B26 | B25 | (opcode_1 & 15)*B20 | crn.code()*B16 |
2196 crd.code()*B12 | coproc*B8 | (opcode_2 & 7)*B5 | crm.code());
2197}
2198
2199
2200void Assembler::cdp2(Coprocessor coproc,
2201 int opcode_1,
2202 CRegister crd,
2203 CRegister crn,
2204 CRegister crm,
2205 int opcode_2) { // v5 and above
Steve Block1e0659c2011-05-24 12:43:12 +01002206 cdp(coproc, opcode_1, crd, crn, crm, opcode_2, kSpecialCondition);
Steve Blocka7e24c12009-10-30 11:49:00 +00002207}
2208
2209
2210void Assembler::mcr(Coprocessor coproc,
2211 int opcode_1,
2212 Register rd,
2213 CRegister crn,
2214 CRegister crm,
2215 int opcode_2,
2216 Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002217 DCHECK(is_uint3(opcode_1) && is_uint3(opcode_2));
Steve Blocka7e24c12009-10-30 11:49:00 +00002218 emit(cond | B27 | B26 | B25 | (opcode_1 & 7)*B21 | crn.code()*B16 |
2219 rd.code()*B12 | coproc*B8 | (opcode_2 & 7)*B5 | B4 | crm.code());
2220}
2221
2222
2223void Assembler::mcr2(Coprocessor coproc,
2224 int opcode_1,
2225 Register rd,
2226 CRegister crn,
2227 CRegister crm,
2228 int opcode_2) { // v5 and above
Steve Block1e0659c2011-05-24 12:43:12 +01002229 mcr(coproc, opcode_1, rd, crn, crm, opcode_2, kSpecialCondition);
Steve Blocka7e24c12009-10-30 11:49:00 +00002230}
2231
2232
2233void Assembler::mrc(Coprocessor coproc,
2234 int opcode_1,
2235 Register rd,
2236 CRegister crn,
2237 CRegister crm,
2238 int opcode_2,
2239 Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002240 DCHECK(is_uint3(opcode_1) && is_uint3(opcode_2));
Steve Blocka7e24c12009-10-30 11:49:00 +00002241 emit(cond | B27 | B26 | B25 | (opcode_1 & 7)*B21 | L | crn.code()*B16 |
2242 rd.code()*B12 | coproc*B8 | (opcode_2 & 7)*B5 | B4 | crm.code());
2243}
2244
2245
2246void Assembler::mrc2(Coprocessor coproc,
2247 int opcode_1,
2248 Register rd,
2249 CRegister crn,
2250 CRegister crm,
2251 int opcode_2) { // v5 and above
Steve Block1e0659c2011-05-24 12:43:12 +01002252 mrc(coproc, opcode_1, rd, crn, crm, opcode_2, kSpecialCondition);
Steve Blocka7e24c12009-10-30 11:49:00 +00002253}
2254
2255
2256void Assembler::ldc(Coprocessor coproc,
2257 CRegister crd,
2258 const MemOperand& src,
2259 LFlag l,
2260 Condition cond) {
2261 addrmod5(cond | B27 | B26 | l | L | coproc*B8, crd, src);
2262}
2263
2264
2265void Assembler::ldc(Coprocessor coproc,
2266 CRegister crd,
2267 Register rn,
2268 int option,
2269 LFlag l,
2270 Condition cond) {
Andrei Popescu31002712010-02-23 13:46:05 +00002271 // Unindexed addressing.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002272 DCHECK(is_uint8(option));
Steve Blocka7e24c12009-10-30 11:49:00 +00002273 emit(cond | B27 | B26 | U | l | L | rn.code()*B16 | crd.code()*B12 |
2274 coproc*B8 | (option & 255));
2275}
2276
2277
2278void Assembler::ldc2(Coprocessor coproc,
2279 CRegister crd,
2280 const MemOperand& src,
2281 LFlag l) { // v5 and above
Steve Block1e0659c2011-05-24 12:43:12 +01002282 ldc(coproc, crd, src, l, kSpecialCondition);
Steve Blocka7e24c12009-10-30 11:49:00 +00002283}
2284
2285
2286void Assembler::ldc2(Coprocessor coproc,
2287 CRegister crd,
2288 Register rn,
2289 int option,
2290 LFlag l) { // v5 and above
Steve Block1e0659c2011-05-24 12:43:12 +01002291 ldc(coproc, crd, rn, option, l, kSpecialCondition);
Steve Blocka7e24c12009-10-30 11:49:00 +00002292}
2293
2294
Steve Blockd0582a62009-12-15 09:54:21 +00002295// Support for VFP.
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002296
Leon Clarked91b9f72010-01-27 17:25:45 +00002297void Assembler::vldr(const DwVfpRegister dst,
2298 const Register base,
2299 int offset,
2300 const Condition cond) {
2301 // Ddst = MEM(Rbase + offset).
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002302 // Instruction details available in ARM DDI 0406C.b, A8-924.
2303 // cond(31-28) | 1101(27-24)| U(23) | D(22) | 01(21-20) | Rbase(19-16) |
2304 // Vd(15-12) | 1011(11-8) | offset
Ben Murdochb0fe1622011-05-05 13:52:32 +01002305 int u = 1;
2306 if (offset < 0) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002307 CHECK(offset != kMinInt);
Ben Murdochb0fe1622011-05-05 13:52:32 +01002308 offset = -offset;
2309 u = 0;
2310 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002311 int vd, d;
2312 dst.split_code(&vd, &d);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002313
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002314 DCHECK(offset >= 0);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002315 if ((offset % 4) == 0 && (offset / 4) < 256) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002316 emit(cond | 0xD*B24 | u*B23 | d*B22 | B20 | base.code()*B16 | vd*B12 |
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002317 0xB*B8 | ((offset / 4) & 255));
2318 } else {
2319 // Larger offsets must be handled by computing the correct address
2320 // in the ip register.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002321 DCHECK(!base.is(ip));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002322 if (u == 1) {
2323 add(ip, base, Operand(offset));
2324 } else {
2325 sub(ip, base, Operand(offset));
2326 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002327 emit(cond | 0xD*B24 | d*B22 | B20 | ip.code()*B16 | vd*B12 | 0xB*B8);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002328 }
2329}
2330
2331
2332void Assembler::vldr(const DwVfpRegister dst,
2333 const MemOperand& operand,
2334 const Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002335 DCHECK(operand.am_ == Offset);
2336 if (operand.rm().is_valid()) {
2337 add(ip, operand.rn(),
2338 Operand(operand.rm(), operand.shift_op_, operand.shift_imm_));
2339 vldr(dst, ip, 0, cond);
2340 } else {
2341 vldr(dst, operand.rn(), operand.offset(), cond);
2342 }
Leon Clarked91b9f72010-01-27 17:25:45 +00002343}
2344
2345
Steve Block6ded16b2010-05-10 14:33:55 +01002346void Assembler::vldr(const SwVfpRegister dst,
2347 const Register base,
2348 int offset,
2349 const Condition cond) {
2350 // Sdst = MEM(Rbase + offset).
2351 // Instruction details available in ARM DDI 0406A, A8-628.
Ben Murdochb0fe1622011-05-05 13:52:32 +01002352 // cond(31-28) | 1101(27-24)| U001(23-20) | Rbase(19-16) |
Steve Block6ded16b2010-05-10 14:33:55 +01002353 // Vdst(15-12) | 1010(11-8) | offset
Ben Murdochb0fe1622011-05-05 13:52:32 +01002354 int u = 1;
2355 if (offset < 0) {
2356 offset = -offset;
2357 u = 0;
2358 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002359 int sd, d;
2360 dst.split_code(&sd, &d);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002361 DCHECK(offset >= 0);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002362
2363 if ((offset % 4) == 0 && (offset / 4) < 256) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01002364 emit(cond | u*B23 | d*B22 | 0xD1*B20 | base.code()*B16 | sd*B12 |
Steve Block6ded16b2010-05-10 14:33:55 +01002365 0xA*B8 | ((offset / 4) & 255));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002366 } else {
2367 // Larger offsets must be handled by computing the correct address
2368 // in the ip register.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002369 DCHECK(!base.is(ip));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002370 if (u == 1) {
2371 add(ip, base, Operand(offset));
2372 } else {
2373 sub(ip, base, Operand(offset));
2374 }
2375 emit(cond | d*B22 | 0xD1*B20 | ip.code()*B16 | sd*B12 | 0xA*B8);
2376 }
2377}
2378
2379
2380void Assembler::vldr(const SwVfpRegister dst,
2381 const MemOperand& operand,
2382 const Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002383 DCHECK(operand.am_ == Offset);
2384 if (operand.rm().is_valid()) {
2385 add(ip, operand.rn(),
2386 Operand(operand.rm(), operand.shift_op_, operand.shift_imm_));
2387 vldr(dst, ip, 0, cond);
2388 } else {
2389 vldr(dst, operand.rn(), operand.offset(), cond);
2390 }
Steve Block6ded16b2010-05-10 14:33:55 +01002391}
2392
2393
Leon Clarked91b9f72010-01-27 17:25:45 +00002394void Assembler::vstr(const DwVfpRegister src,
2395 const Register base,
2396 int offset,
2397 const Condition cond) {
2398 // MEM(Rbase + offset) = Dsrc.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002399 // Instruction details available in ARM DDI 0406C.b, A8-1082.
2400 // cond(31-28) | 1101(27-24)| U(23) | D(22) | 00(21-20) | Rbase(19-16) |
2401 // Vd(15-12) | 1011(11-8) | (offset/4)
Ben Murdochb0fe1622011-05-05 13:52:32 +01002402 int u = 1;
2403 if (offset < 0) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002404 CHECK(offset != kMinInt);
Ben Murdochb0fe1622011-05-05 13:52:32 +01002405 offset = -offset;
2406 u = 0;
2407 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002408 DCHECK(offset >= 0);
2409 int vd, d;
2410 src.split_code(&vd, &d);
2411
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002412 if ((offset % 4) == 0 && (offset / 4) < 256) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002413 emit(cond | 0xD*B24 | u*B23 | d*B22 | base.code()*B16 | vd*B12 | 0xB*B8 |
2414 ((offset / 4) & 255));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002415 } else {
2416 // Larger offsets must be handled by computing the correct address
2417 // in the ip register.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002418 DCHECK(!base.is(ip));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002419 if (u == 1) {
2420 add(ip, base, Operand(offset));
2421 } else {
2422 sub(ip, base, Operand(offset));
2423 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002424 emit(cond | 0xD*B24 | d*B22 | ip.code()*B16 | vd*B12 | 0xB*B8);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002425 }
2426}
2427
2428
2429void Assembler::vstr(const DwVfpRegister src,
2430 const MemOperand& operand,
2431 const Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002432 DCHECK(operand.am_ == Offset);
2433 if (operand.rm().is_valid()) {
2434 add(ip, operand.rn(),
2435 Operand(operand.rm(), operand.shift_op_, operand.shift_imm_));
2436 vstr(src, ip, 0, cond);
2437 } else {
2438 vstr(src, operand.rn(), operand.offset(), cond);
2439 }
Leon Clarked91b9f72010-01-27 17:25:45 +00002440}
2441
2442
Iain Merrick75681382010-08-19 15:07:18 +01002443void Assembler::vstr(const SwVfpRegister src,
2444 const Register base,
2445 int offset,
2446 const Condition cond) {
2447 // MEM(Rbase + offset) = SSrc.
2448 // Instruction details available in ARM DDI 0406A, A8-786.
Ben Murdochb0fe1622011-05-05 13:52:32 +01002449 // cond(31-28) | 1101(27-24)| U000(23-20) | Rbase(19-16) |
Iain Merrick75681382010-08-19 15:07:18 +01002450 // Vdst(15-12) | 1010(11-8) | (offset/4)
Ben Murdochb0fe1622011-05-05 13:52:32 +01002451 int u = 1;
2452 if (offset < 0) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002453 CHECK(offset != kMinInt);
Ben Murdochb0fe1622011-05-05 13:52:32 +01002454 offset = -offset;
2455 u = 0;
2456 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002457 int sd, d;
2458 src.split_code(&sd, &d);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002459 DCHECK(offset >= 0);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002460 if ((offset % 4) == 0 && (offset / 4) < 256) {
2461 emit(cond | u*B23 | d*B22 | 0xD0*B20 | base.code()*B16 | sd*B12 |
2462 0xA*B8 | ((offset / 4) & 255));
2463 } else {
2464 // Larger offsets must be handled by computing the correct address
2465 // in the ip register.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002466 DCHECK(!base.is(ip));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002467 if (u == 1) {
2468 add(ip, base, Operand(offset));
2469 } else {
2470 sub(ip, base, Operand(offset));
2471 }
2472 emit(cond | d*B22 | 0xD0*B20 | ip.code()*B16 | sd*B12 | 0xA*B8);
2473 }
2474}
2475
2476
2477void Assembler::vstr(const SwVfpRegister src,
2478 const MemOperand& operand,
2479 const Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002480 DCHECK(operand.am_ == Offset);
2481 if (operand.rm().is_valid()) {
2482 add(ip, operand.rn(),
2483 Operand(operand.rm(), operand.shift_op_, operand.shift_imm_));
2484 vstr(src, ip, 0, cond);
2485 } else {
2486 vstr(src, operand.rn(), operand.offset(), cond);
2487 }
Iain Merrick75681382010-08-19 15:07:18 +01002488}
2489
2490
Ben Murdoch8b112d22011-06-08 16:22:53 +01002491void Assembler::vldm(BlockAddrMode am,
2492 Register base,
2493 DwVfpRegister first,
2494 DwVfpRegister last,
2495 Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002496 // Instruction details available in ARM DDI 0406C.b, A8-922.
Ben Murdoch8b112d22011-06-08 16:22:53 +01002497 // cond(31-28) | 110(27-25)| PUDW1(24-20) | Rbase(19-16) |
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002498 // first(15-12) | 1011(11-8) | (count * 2)
2499 DCHECK_LE(first.code(), last.code());
2500 DCHECK(am == ia || am == ia_w || am == db_w);
2501 DCHECK(!base.is(pc));
Ben Murdoch8b112d22011-06-08 16:22:53 +01002502
2503 int sd, d;
2504 first.split_code(&sd, &d);
2505 int count = last.code() - first.code() + 1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002506 DCHECK(count <= 16);
Ben Murdoch8b112d22011-06-08 16:22:53 +01002507 emit(cond | B27 | B26 | am | d*B22 | B20 | base.code()*B16 | sd*B12 |
2508 0xB*B8 | count*2);
2509}
2510
2511
2512void Assembler::vstm(BlockAddrMode am,
2513 Register base,
2514 DwVfpRegister first,
2515 DwVfpRegister last,
2516 Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002517 // Instruction details available in ARM DDI 0406C.b, A8-1080.
Ben Murdoch8b112d22011-06-08 16:22:53 +01002518 // cond(31-28) | 110(27-25)| PUDW0(24-20) | Rbase(19-16) |
2519 // first(15-12) | 1011(11-8) | (count * 2)
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002520 DCHECK_LE(first.code(), last.code());
2521 DCHECK(am == ia || am == ia_w || am == db_w);
2522 DCHECK(!base.is(pc));
Ben Murdoch8b112d22011-06-08 16:22:53 +01002523
2524 int sd, d;
2525 first.split_code(&sd, &d);
2526 int count = last.code() - first.code() + 1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002527 DCHECK(count <= 16);
Ben Murdoch8b112d22011-06-08 16:22:53 +01002528 emit(cond | B27 | B26 | am | d*B22 | base.code()*B16 | sd*B12 |
2529 0xB*B8 | count*2);
2530}
2531
2532void Assembler::vldm(BlockAddrMode am,
2533 Register base,
2534 SwVfpRegister first,
2535 SwVfpRegister last,
2536 Condition cond) {
2537 // Instruction details available in ARM DDI 0406A, A8-626.
2538 // cond(31-28) | 110(27-25)| PUDW1(24-20) | Rbase(19-16) |
2539 // first(15-12) | 1010(11-8) | (count/2)
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002540 DCHECK_LE(first.code(), last.code());
2541 DCHECK(am == ia || am == ia_w || am == db_w);
2542 DCHECK(!base.is(pc));
Ben Murdoch8b112d22011-06-08 16:22:53 +01002543
2544 int sd, d;
2545 first.split_code(&sd, &d);
2546 int count = last.code() - first.code() + 1;
2547 emit(cond | B27 | B26 | am | d*B22 | B20 | base.code()*B16 | sd*B12 |
2548 0xA*B8 | count);
2549}
2550
2551
2552void Assembler::vstm(BlockAddrMode am,
2553 Register base,
2554 SwVfpRegister first,
2555 SwVfpRegister last,
2556 Condition cond) {
2557 // Instruction details available in ARM DDI 0406A, A8-784.
2558 // cond(31-28) | 110(27-25)| PUDW0(24-20) | Rbase(19-16) |
2559 // first(15-12) | 1011(11-8) | (count/2)
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002560 DCHECK_LE(first.code(), last.code());
2561 DCHECK(am == ia || am == ia_w || am == db_w);
2562 DCHECK(!base.is(pc));
Ben Murdoch8b112d22011-06-08 16:22:53 +01002563
2564 int sd, d;
2565 first.split_code(&sd, &d);
2566 int count = last.code() - first.code() + 1;
2567 emit(cond | B27 | B26 | am | d*B22 | base.code()*B16 | sd*B12 |
2568 0xA*B8 | count);
2569}
2570
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002571
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002572static void DoubleAsTwoUInt32(double d, uint32_t* lo, uint32_t* hi) {
2573 uint64_t i;
2574 memcpy(&i, &d, 8);
2575
2576 *lo = i & 0xffffffff;
2577 *hi = i >> 32;
2578}
2579
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002580
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002581// Only works for little endian floating point formats.
2582// We don't support VFP on the mixed endian floating point platform.
Ben Murdochda12d292016-06-02 14:46:10 +01002583static bool FitsVmovFPImmediate(double d, uint32_t* encoding) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002584 DCHECK(CpuFeatures::IsSupported(VFP3));
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002585
2586 // VMOV can accept an immediate of the form:
2587 //
2588 // +/- m * 2^(-n) where 16 <= m <= 31 and 0 <= n <= 7
2589 //
2590 // The immediate is encoded using an 8-bit quantity, comprised of two
2591 // 4-bit fields. For an 8-bit immediate of the form:
2592 //
2593 // [abcdefgh]
2594 //
2595 // where a is the MSB and h is the LSB, an immediate 64-bit double can be
2596 // created of the form:
2597 //
2598 // [aBbbbbbb,bbcdefgh,00000000,00000000,
2599 // 00000000,00000000,00000000,00000000]
2600 //
2601 // where B = ~b.
2602 //
2603
2604 uint32_t lo, hi;
2605 DoubleAsTwoUInt32(d, &lo, &hi);
2606
2607 // The most obvious constraint is the long block of zeroes.
2608 if ((lo != 0) || ((hi & 0xffff) != 0)) {
2609 return false;
2610 }
2611
Ben Murdochda12d292016-06-02 14:46:10 +01002612 // Bits 61:54 must be all clear or all set.
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002613 if (((hi & 0x3fc00000) != 0) && ((hi & 0x3fc00000) != 0x3fc00000)) {
2614 return false;
2615 }
2616
Ben Murdochda12d292016-06-02 14:46:10 +01002617 // Bit 62 must be NOT bit 61.
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002618 if (((hi ^ (hi << 1)) & (0x40000000)) == 0) {
2619 return false;
2620 }
2621
2622 // Create the encoded immediate in the form:
2623 // [00000000,0000abcd,00000000,0000efgh]
2624 *encoding = (hi >> 16) & 0xf; // Low nybble.
2625 *encoding |= (hi >> 4) & 0x70000; // Low three bits of the high nybble.
2626 *encoding |= (hi >> 12) & 0x80000; // Top bit of the high nybble.
2627
2628 return true;
2629}
2630
2631
Ben Murdochda12d292016-06-02 14:46:10 +01002632void Assembler::vmov(const SwVfpRegister dst, float imm) {
2633 uint32_t enc;
2634 if (CpuFeatures::IsSupported(VFP3) && FitsVmovFPImmediate(imm, &enc)) {
2635 // The float can be encoded in the instruction.
2636 //
2637 // Sd = immediate
2638 // Instruction details available in ARM DDI 0406C.b, A8-936.
2639 // cond(31-28) | 11101(27-23) | D(22) | 11(21-20) | imm4H(19-16) |
2640 // Vd(15-12) | 101(11-9) | sz=0(8) | imm4L(3-0)
2641 int vd, d;
2642 dst.split_code(&vd, &d);
2643 emit(al | 0x1D * B23 | d * B22 | 0x3 * B20 | vd * B12 | 0x5 * B9 | enc);
2644 } else {
2645 mov(ip, Operand(bit_cast<int32_t>(imm)));
2646 vmov(dst, ip);
2647 }
2648}
2649
2650
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002651void Assembler::vmov(const DwVfpRegister dst,
2652 double imm,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002653 const Register scratch) {
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002654 uint32_t enc;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002655 // If the embedded constant pool is disabled, we can use the normal, inline
2656 // constant pool. If the embedded constant pool is enabled (via
2657 // FLAG_enable_embedded_constant_pool), we can only use it where the pool
2658 // pointer (pp) is valid.
2659 bool can_use_pool =
2660 !FLAG_enable_embedded_constant_pool || is_constant_pool_available();
Ben Murdochda12d292016-06-02 14:46:10 +01002661 if (CpuFeatures::IsSupported(VFP3) && FitsVmovFPImmediate(imm, &enc)) {
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002662 // The double can be encoded in the instruction.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002663 //
2664 // Dd = immediate
2665 // Instruction details available in ARM DDI 0406C.b, A8-936.
2666 // cond(31-28) | 11101(27-23) | D(22) | 11(21-20) | imm4H(19-16) |
2667 // Vd(15-12) | 101(11-9) | sz=1(8) | imm4L(3-0)
2668 int vd, d;
2669 dst.split_code(&vd, &d);
2670 emit(al | 0x1D*B23 | d*B22 | 0x3*B20 | vd*B12 | 0x5*B9 | B8 | enc);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002671 } else if (FLAG_enable_vldr_imm && can_use_pool) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002672 // TODO(jfb) Temporarily turned off until we have constant blinding or
2673 // some equivalent mitigation: an attacker can otherwise control
2674 // generated data which also happens to be executable, a Very Bad
2675 // Thing indeed.
2676 // Blinding gets tricky because we don't have xor, we probably
2677 // need to add/subtract without losing precision, which requires a
2678 // cookie value that Lithium is probably better positioned to
2679 // choose.
2680 // We could also add a few peepholes here like detecting 0.0 and
2681 // -0.0 and doing a vmov from the sequestered d14, forcing denorms
2682 // to zero (we set flush-to-zero), and normalizing NaN values.
2683 // We could also detect redundant values.
2684 // The code could also randomize the order of values, though
2685 // that's tricky because vldr has a limited reach. Furthermore
2686 // it breaks load locality.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002687 ConstantPoolEntry::Access access = ConstantPoolAddEntry(pc_offset(), imm);
2688 if (access == ConstantPoolEntry::OVERFLOWED) {
2689 DCHECK(FLAG_enable_embedded_constant_pool);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002690 // Emit instructions to load constant pool offset.
2691 movw(ip, 0);
2692 movt(ip, 0);
2693 // Load from constant pool at offset.
2694 vldr(dst, MemOperand(pp, ip));
2695 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002696 DCHECK(access == ConstantPoolEntry::REGULAR);
2697 vldr(dst, MemOperand(FLAG_enable_embedded_constant_pool ? pp : pc, 0));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002698 }
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002699 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002700 // Synthesise the double from ARM immediates.
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002701 uint32_t lo, hi;
2702 DoubleAsTwoUInt32(imm, &lo, &hi);
2703
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002704 if (lo == hi) {
2705 // Move the low and high parts of the double to a D register in one
2706 // instruction.
2707 mov(ip, Operand(lo));
2708 vmov(dst, ip, ip);
2709 } else if (scratch.is(no_reg)) {
2710 mov(ip, Operand(lo));
2711 vmov(dst, VmovIndexLo, ip);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002712 if (((lo & 0xffff) == (hi & 0xffff)) &&
2713 CpuFeatures::IsSupported(ARMv7)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002714 movt(ip, hi >> 16);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002715 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002716 mov(ip, Operand(hi));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002717 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002718 vmov(dst, VmovIndexHi, ip);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002719 } else {
2720 // Move the low and high parts of the double to a D register in one
2721 // instruction.
2722 mov(ip, Operand(lo));
2723 mov(scratch, Operand(hi));
2724 vmov(dst, ip, scratch);
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002725 }
2726 }
2727}
2728
2729
2730void Assembler::vmov(const SwVfpRegister dst,
2731 const SwVfpRegister src,
2732 const Condition cond) {
2733 // Sd = Sm
2734 // Instruction details available in ARM DDI 0406B, A8-642.
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002735 int sd, d, sm, m;
2736 dst.split_code(&sd, &d);
2737 src.split_code(&sm, &m);
2738 emit(cond | 0xE*B24 | d*B22 | 0xB*B20 | sd*B12 | 0xA*B8 | B6 | m*B5 | sm);
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002739}
2740
2741
Leon Clarkee46be812010-01-19 14:06:41 +00002742void Assembler::vmov(const DwVfpRegister dst,
Steve Block8defd9f2010-07-08 12:39:36 +01002743 const DwVfpRegister src,
2744 const Condition cond) {
2745 // Dd = Dm
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002746 // Instruction details available in ARM DDI 0406C.b, A8-938.
2747 // cond(31-28) | 11101(27-23) | D(22) | 11(21-20) | 0000(19-16) | Vd(15-12) |
2748 // 101(11-9) | sz=1(8) | 0(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
2749 int vd, d;
2750 dst.split_code(&vd, &d);
2751 int vm, m;
2752 src.split_code(&vm, &m);
2753 emit(cond | 0x1D*B23 | d*B22 | 0x3*B20 | vd*B12 | 0x5*B9 | B8 | B6 | m*B5 |
2754 vm);
2755}
2756
2757
2758void Assembler::vmov(const DwVfpRegister dst,
2759 const VmovIndex index,
2760 const Register src,
2761 const Condition cond) {
2762 // Dd[index] = Rt
2763 // Instruction details available in ARM DDI 0406C.b, A8-940.
2764 // cond(31-28) | 1110(27-24) | 0(23) | opc1=0index(22-21) | 0(20) |
2765 // Vd(19-16) | Rt(15-12) | 1011(11-8) | D(7) | opc2=00(6-5) | 1(4) | 0000(3-0)
2766 DCHECK(index.index == 0 || index.index == 1);
2767 int vd, d;
2768 dst.split_code(&vd, &d);
2769 emit(cond | 0xE*B24 | index.index*B21 | vd*B16 | src.code()*B12 | 0xB*B8 |
2770 d*B7 | B4);
2771}
2772
2773
2774void Assembler::vmov(const Register dst,
2775 const VmovIndex index,
2776 const DwVfpRegister src,
2777 const Condition cond) {
2778 // Dd[index] = Rt
2779 // Instruction details available in ARM DDI 0406C.b, A8.8.342.
2780 // cond(31-28) | 1110(27-24) | U=0(23) | opc1=0index(22-21) | 1(20) |
2781 // Vn(19-16) | Rt(15-12) | 1011(11-8) | N(7) | opc2=00(6-5) | 1(4) | 0000(3-0)
2782 DCHECK(index.index == 0 || index.index == 1);
2783 int vn, n;
2784 src.split_code(&vn, &n);
2785 emit(cond | 0xE*B24 | index.index*B21 | B20 | vn*B16 | dst.code()*B12 |
2786 0xB*B8 | n*B7 | B4);
Steve Block8defd9f2010-07-08 12:39:36 +01002787}
2788
2789
2790void Assembler::vmov(const DwVfpRegister dst,
Leon Clarkee46be812010-01-19 14:06:41 +00002791 const Register src1,
2792 const Register src2,
2793 const Condition cond) {
Steve Blockd0582a62009-12-15 09:54:21 +00002794 // Dm = <Rt,Rt2>.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002795 // Instruction details available in ARM DDI 0406C.b, A8-948.
Steve Blockd0582a62009-12-15 09:54:21 +00002796 // cond(31-28) | 1100(27-24)| 010(23-21) | op=0(20) | Rt2(19-16) |
2797 // Rt(15-12) | 1011(11-8) | 00(7-6) | M(5) | 1(4) | Vm
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002798 DCHECK(!src1.is(pc) && !src2.is(pc));
2799 int vm, m;
2800 dst.split_code(&vm, &m);
Steve Blockd0582a62009-12-15 09:54:21 +00002801 emit(cond | 0xC*B24 | B22 | src2.code()*B16 |
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002802 src1.code()*B12 | 0xB*B8 | m*B5 | B4 | vm);
Steve Blockd0582a62009-12-15 09:54:21 +00002803}
2804
2805
Leon Clarkee46be812010-01-19 14:06:41 +00002806void Assembler::vmov(const Register dst1,
2807 const Register dst2,
2808 const DwVfpRegister src,
2809 const Condition cond) {
Steve Blockd0582a62009-12-15 09:54:21 +00002810 // <Rt,Rt2> = Dm.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002811 // Instruction details available in ARM DDI 0406C.b, A8-948.
Steve Blockd0582a62009-12-15 09:54:21 +00002812 // cond(31-28) | 1100(27-24)| 010(23-21) | op=1(20) | Rt2(19-16) |
2813 // Rt(15-12) | 1011(11-8) | 00(7-6) | M(5) | 1(4) | Vm
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002814 DCHECK(!dst1.is(pc) && !dst2.is(pc));
2815 int vm, m;
2816 src.split_code(&vm, &m);
Steve Blockd0582a62009-12-15 09:54:21 +00002817 emit(cond | 0xC*B24 | B22 | B20 | dst2.code()*B16 |
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002818 dst1.code()*B12 | 0xB*B8 | m*B5 | B4 | vm);
Steve Blockd0582a62009-12-15 09:54:21 +00002819}
2820
2821
Leon Clarkee46be812010-01-19 14:06:41 +00002822void Assembler::vmov(const SwVfpRegister dst,
Steve Blockd0582a62009-12-15 09:54:21 +00002823 const Register src,
Steve Blockd0582a62009-12-15 09:54:21 +00002824 const Condition cond) {
2825 // Sn = Rt.
2826 // Instruction details available in ARM DDI 0406A, A8-642.
2827 // cond(31-28) | 1110(27-24)| 000(23-21) | op=0(20) | Vn(19-16) |
2828 // Rt(15-12) | 1010(11-8) | N(7)=0 | 00(6-5) | 1(4) | 0000(3-0)
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002829 DCHECK(!src.is(pc));
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002830 int sn, n;
2831 dst.split_code(&sn, &n);
2832 emit(cond | 0xE*B24 | sn*B16 | src.code()*B12 | 0xA*B8 | n*B7 | B4);
Steve Blockd0582a62009-12-15 09:54:21 +00002833}
2834
2835
Leon Clarkee46be812010-01-19 14:06:41 +00002836void Assembler::vmov(const Register dst,
2837 const SwVfpRegister src,
Steve Blockd0582a62009-12-15 09:54:21 +00002838 const Condition cond) {
2839 // Rt = Sn.
2840 // Instruction details available in ARM DDI 0406A, A8-642.
2841 // cond(31-28) | 1110(27-24)| 000(23-21) | op=1(20) | Vn(19-16) |
2842 // Rt(15-12) | 1010(11-8) | N(7)=0 | 00(6-5) | 1(4) | 0000(3-0)
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002843 DCHECK(!dst.is(pc));
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002844 int sn, n;
2845 src.split_code(&sn, &n);
2846 emit(cond | 0xE*B24 | B20 | sn*B16 | dst.code()*B12 | 0xA*B8 | n*B7 | B4);
Steve Blockd0582a62009-12-15 09:54:21 +00002847}
2848
2849
Steve Block6ded16b2010-05-10 14:33:55 +01002850// Type of data to read from or write to VFP register.
2851// Used as specifier in generic vcvt instruction.
2852enum VFPType { S32, U32, F32, F64 };
2853
2854
2855static bool IsSignedVFPType(VFPType type) {
2856 switch (type) {
2857 case S32:
2858 return true;
2859 case U32:
2860 return false;
2861 default:
2862 UNREACHABLE();
2863 return false;
2864 }
Steve Blockd0582a62009-12-15 09:54:21 +00002865}
2866
2867
Steve Block6ded16b2010-05-10 14:33:55 +01002868static bool IsIntegerVFPType(VFPType type) {
2869 switch (type) {
2870 case S32:
2871 case U32:
2872 return true;
2873 case F32:
2874 case F64:
2875 return false;
2876 default:
2877 UNREACHABLE();
2878 return false;
2879 }
2880}
2881
2882
2883static bool IsDoubleVFPType(VFPType type) {
2884 switch (type) {
2885 case F32:
2886 return false;
2887 case F64:
2888 return true;
2889 default:
2890 UNREACHABLE();
2891 return false;
2892 }
2893}
2894
2895
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002896// Split five bit reg_code based on size of reg_type.
2897// 32-bit register codes are Vm:M
2898// 64-bit register codes are M:Vm
2899// where Vm is four bits, and M is a single bit.
2900static void SplitRegCode(VFPType reg_type,
Steve Block6ded16b2010-05-10 14:33:55 +01002901 int reg_code,
2902 int* vm,
2903 int* m) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002904 DCHECK((reg_code >= 0) && (reg_code <= 31));
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002905 if (IsIntegerVFPType(reg_type) || !IsDoubleVFPType(reg_type)) {
2906 // 32 bit type.
Steve Block6ded16b2010-05-10 14:33:55 +01002907 *m = reg_code & 0x1;
2908 *vm = reg_code >> 1;
2909 } else {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002910 // 64 bit type.
Steve Block6ded16b2010-05-10 14:33:55 +01002911 *m = (reg_code & 0x10) >> 4;
2912 *vm = reg_code & 0x0F;
2913 }
2914}
2915
2916
2917// Encode vcvt.src_type.dst_type instruction.
2918static Instr EncodeVCVT(const VFPType dst_type,
2919 const int dst_code,
2920 const VFPType src_type,
2921 const int src_code,
Steve Block1e0659c2011-05-24 12:43:12 +01002922 VFPConversionMode mode,
Steve Block6ded16b2010-05-10 14:33:55 +01002923 const Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002924 DCHECK(src_type != dst_type);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002925 int D, Vd, M, Vm;
2926 SplitRegCode(src_type, src_code, &Vm, &M);
2927 SplitRegCode(dst_type, dst_code, &Vd, &D);
2928
Steve Block6ded16b2010-05-10 14:33:55 +01002929 if (IsIntegerVFPType(dst_type) || IsIntegerVFPType(src_type)) {
2930 // Conversion between IEEE floating point and 32-bit integer.
2931 // Instruction details available in ARM DDI 0406B, A8.6.295.
2932 // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 1(19) | opc2(18-16) |
2933 // Vd(15-12) | 101(11-9) | sz(8) | op(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002934 DCHECK(!IsIntegerVFPType(dst_type) || !IsIntegerVFPType(src_type));
Steve Block6ded16b2010-05-10 14:33:55 +01002935
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002936 int sz, opc2, op;
Steve Block6ded16b2010-05-10 14:33:55 +01002937
2938 if (IsIntegerVFPType(dst_type)) {
2939 opc2 = IsSignedVFPType(dst_type) ? 0x5 : 0x4;
2940 sz = IsDoubleVFPType(src_type) ? 0x1 : 0x0;
Russell Brenner90bac252010-11-18 13:33:46 -08002941 op = mode;
Steve Block6ded16b2010-05-10 14:33:55 +01002942 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002943 DCHECK(IsIntegerVFPType(src_type));
Steve Block6ded16b2010-05-10 14:33:55 +01002944 opc2 = 0x0;
2945 sz = IsDoubleVFPType(dst_type) ? 0x1 : 0x0;
2946 op = IsSignedVFPType(src_type) ? 0x1 : 0x0;
Steve Block6ded16b2010-05-10 14:33:55 +01002947 }
2948
2949 return (cond | 0xE*B24 | B23 | D*B22 | 0x3*B20 | B19 | opc2*B16 |
2950 Vd*B12 | 0x5*B9 | sz*B8 | op*B7 | B6 | M*B5 | Vm);
2951 } else {
2952 // Conversion between IEEE double and single precision.
2953 // Instruction details available in ARM DDI 0406B, A8.6.298.
2954 // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 0111(19-16) |
2955 // Vd(15-12) | 101(11-9) | sz(8) | 1(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002956 int sz = IsDoubleVFPType(src_type) ? 0x1 : 0x0;
Steve Block6ded16b2010-05-10 14:33:55 +01002957 return (cond | 0xE*B24 | B23 | D*B22 | 0x3*B20 | 0x7*B16 |
2958 Vd*B12 | 0x5*B9 | sz*B8 | B7 | B6 | M*B5 | Vm);
2959 }
2960}
2961
2962
2963void Assembler::vcvt_f64_s32(const DwVfpRegister dst,
2964 const SwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +01002965 VFPConversionMode mode,
Steve Block6ded16b2010-05-10 14:33:55 +01002966 const Condition cond) {
Russell Brenner90bac252010-11-18 13:33:46 -08002967 emit(EncodeVCVT(F64, dst.code(), S32, src.code(), mode, cond));
Steve Block6ded16b2010-05-10 14:33:55 +01002968}
2969
2970
2971void Assembler::vcvt_f32_s32(const SwVfpRegister dst,
2972 const SwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +01002973 VFPConversionMode mode,
Steve Block6ded16b2010-05-10 14:33:55 +01002974 const Condition cond) {
Russell Brenner90bac252010-11-18 13:33:46 -08002975 emit(EncodeVCVT(F32, dst.code(), S32, src.code(), mode, cond));
Steve Block6ded16b2010-05-10 14:33:55 +01002976}
2977
2978
2979void Assembler::vcvt_f64_u32(const DwVfpRegister dst,
2980 const SwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +01002981 VFPConversionMode mode,
Steve Block6ded16b2010-05-10 14:33:55 +01002982 const Condition cond) {
Russell Brenner90bac252010-11-18 13:33:46 -08002983 emit(EncodeVCVT(F64, dst.code(), U32, src.code(), mode, cond));
Steve Block6ded16b2010-05-10 14:33:55 +01002984}
2985
2986
Ben Murdoch097c5b22016-05-18 11:27:45 +01002987void Assembler::vcvt_f32_u32(const SwVfpRegister dst, const SwVfpRegister src,
2988 VFPConversionMode mode, const Condition cond) {
2989 emit(EncodeVCVT(F32, dst.code(), U32, src.code(), mode, cond));
2990}
2991
2992
2993void Assembler::vcvt_s32_f32(const SwVfpRegister dst, const SwVfpRegister src,
2994 VFPConversionMode mode, const Condition cond) {
2995 emit(EncodeVCVT(S32, dst.code(), F32, src.code(), mode, cond));
2996}
2997
2998
2999void Assembler::vcvt_u32_f32(const SwVfpRegister dst, const SwVfpRegister src,
3000 VFPConversionMode mode, const Condition cond) {
3001 emit(EncodeVCVT(U32, dst.code(), F32, src.code(), mode, cond));
3002}
3003
3004
Steve Block6ded16b2010-05-10 14:33:55 +01003005void Assembler::vcvt_s32_f64(const SwVfpRegister dst,
3006 const DwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +01003007 VFPConversionMode mode,
Steve Block6ded16b2010-05-10 14:33:55 +01003008 const Condition cond) {
Russell Brenner90bac252010-11-18 13:33:46 -08003009 emit(EncodeVCVT(S32, dst.code(), F64, src.code(), mode, cond));
Steve Block6ded16b2010-05-10 14:33:55 +01003010}
3011
3012
3013void Assembler::vcvt_u32_f64(const SwVfpRegister dst,
3014 const DwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +01003015 VFPConversionMode mode,
Steve Block6ded16b2010-05-10 14:33:55 +01003016 const Condition cond) {
Russell Brenner90bac252010-11-18 13:33:46 -08003017 emit(EncodeVCVT(U32, dst.code(), F64, src.code(), mode, cond));
Steve Block6ded16b2010-05-10 14:33:55 +01003018}
3019
3020
3021void Assembler::vcvt_f64_f32(const DwVfpRegister dst,
3022 const SwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +01003023 VFPConversionMode mode,
Steve Block6ded16b2010-05-10 14:33:55 +01003024 const Condition cond) {
Russell Brenner90bac252010-11-18 13:33:46 -08003025 emit(EncodeVCVT(F64, dst.code(), F32, src.code(), mode, cond));
Steve Block6ded16b2010-05-10 14:33:55 +01003026}
3027
3028
3029void Assembler::vcvt_f32_f64(const SwVfpRegister dst,
3030 const DwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +01003031 VFPConversionMode mode,
Steve Block6ded16b2010-05-10 14:33:55 +01003032 const Condition cond) {
Russell Brenner90bac252010-11-18 13:33:46 -08003033 emit(EncodeVCVT(F32, dst.code(), F64, src.code(), mode, cond));
Steve Blockd0582a62009-12-15 09:54:21 +00003034}
3035
3036
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003037void Assembler::vcvt_f64_s32(const DwVfpRegister dst,
3038 int fraction_bits,
3039 const Condition cond) {
3040 // Instruction details available in ARM DDI 0406C.b, A8-874.
3041 // cond(31-28) | 11101(27-23) | D(22) | 11(21-20) | 1010(19-16) | Vd(15-12) |
3042 // 101(11-9) | sf=1(8) | sx=1(7) | 1(6) | i(5) | 0(4) | imm4(3-0)
3043 DCHECK(fraction_bits > 0 && fraction_bits <= 32);
3044 DCHECK(CpuFeatures::IsSupported(VFP3));
3045 int vd, d;
3046 dst.split_code(&vd, &d);
3047 int imm5 = 32 - fraction_bits;
3048 int i = imm5 & 1;
3049 int imm4 = (imm5 >> 1) & 0xf;
3050 emit(cond | 0xE*B24 | B23 | d*B22 | 0x3*B20 | B19 | 0x2*B16 |
3051 vd*B12 | 0x5*B9 | B8 | B7 | B6 | i*B5 | imm4);
3052}
3053
3054
Steve Block44f0eee2011-05-26 01:26:41 +01003055void Assembler::vneg(const DwVfpRegister dst,
3056 const DwVfpRegister src,
3057 const Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003058 // Instruction details available in ARM DDI 0406C.b, A8-968.
3059 // cond(31-28) | 11101(27-23) | D(22) | 11(21-20) | 0001(19-16) | Vd(15-12) |
3060 // 101(11-9) | sz=1(8) | 0(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
3061 int vd, d;
3062 dst.split_code(&vd, &d);
3063 int vm, m;
3064 src.split_code(&vm, &m);
3065
3066 emit(cond | 0x1D*B23 | d*B22 | 0x3*B20 | B16 | vd*B12 | 0x5*B9 | B8 | B6 |
3067 m*B5 | vm);
Steve Block44f0eee2011-05-26 01:26:41 +01003068}
3069
3070
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003071void Assembler::vneg(const SwVfpRegister dst, const SwVfpRegister src,
3072 const Condition cond) {
3073 // Instruction details available in ARM DDI 0406C.b, A8-968.
3074 // cond(31-28) | 11101(27-23) | D(22) | 11(21-20) | 0001(19-16) | Vd(15-12) |
3075 // 101(11-9) | sz=0(8) | 0(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
3076 int vd, d;
3077 dst.split_code(&vd, &d);
3078 int vm, m;
3079 src.split_code(&vm, &m);
3080
3081 emit(cond | 0x1D * B23 | d * B22 | 0x3 * B20 | B16 | vd * B12 | 0x5 * B9 |
3082 B6 | m * B5 | vm);
3083}
3084
3085
Steve Block1e0659c2011-05-24 12:43:12 +01003086void Assembler::vabs(const DwVfpRegister dst,
3087 const DwVfpRegister src,
3088 const Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003089 // Instruction details available in ARM DDI 0406C.b, A8-524.
3090 // cond(31-28) | 11101(27-23) | D(22) | 11(21-20) | 0000(19-16) | Vd(15-12) |
3091 // 101(11-9) | sz=1(8) | 1(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
3092 int vd, d;
3093 dst.split_code(&vd, &d);
3094 int vm, m;
3095 src.split_code(&vm, &m);
3096 emit(cond | 0x1D*B23 | d*B22 | 0x3*B20 | vd*B12 | 0x5*B9 | B8 | B7 | B6 |
3097 m*B5 | vm);
Steve Block1e0659c2011-05-24 12:43:12 +01003098}
3099
3100
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003101void Assembler::vabs(const SwVfpRegister dst, const SwVfpRegister src,
3102 const Condition cond) {
3103 // Instruction details available in ARM DDI 0406C.b, A8-524.
3104 // cond(31-28) | 11101(27-23) | D(22) | 11(21-20) | 0000(19-16) | Vd(15-12) |
3105 // 101(11-9) | sz=0(8) | 1(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
3106 int vd, d;
3107 dst.split_code(&vd, &d);
3108 int vm, m;
3109 src.split_code(&vm, &m);
3110 emit(cond | 0x1D * B23 | d * B22 | 0x3 * B20 | vd * B12 | 0x5 * B9 | B7 | B6 |
3111 m * B5 | vm);
3112}
3113
3114
Leon Clarkee46be812010-01-19 14:06:41 +00003115void Assembler::vadd(const DwVfpRegister dst,
3116 const DwVfpRegister src1,
3117 const DwVfpRegister src2,
3118 const Condition cond) {
3119 // Dd = vadd(Dn, Dm) double precision floating point addition.
Steve Blockd0582a62009-12-15 09:54:21 +00003120 // Dd = D:Vd; Dm=M:Vm; Dn=N:Vm.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003121 // Instruction details available in ARM DDI 0406C.b, A8-830.
3122 // cond(31-28) | 11100(27-23)| D(22) | 11(21-20) | Vn(19-16) |
3123 // Vd(15-12) | 101(11-9) | sz=1(8) | N(7) | 0(6) | M(5) | 0(4) | Vm(3-0)
3124 int vd, d;
3125 dst.split_code(&vd, &d);
3126 int vn, n;
3127 src1.split_code(&vn, &n);
3128 int vm, m;
3129 src2.split_code(&vm, &m);
3130 emit(cond | 0x1C*B23 | d*B22 | 0x3*B20 | vn*B16 | vd*B12 | 0x5*B9 | B8 |
3131 n*B7 | m*B5 | vm);
Steve Blockd0582a62009-12-15 09:54:21 +00003132}
3133
3134
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003135void Assembler::vadd(const SwVfpRegister dst, const SwVfpRegister src1,
3136 const SwVfpRegister src2, const Condition cond) {
3137 // Sd = vadd(Sn, Sm) single precision floating point addition.
3138 // Sd = D:Vd; Sm=M:Vm; Sn=N:Vm.
3139 // Instruction details available in ARM DDI 0406C.b, A8-830.
3140 // cond(31-28) | 11100(27-23)| D(22) | 11(21-20) | Vn(19-16) |
3141 // Vd(15-12) | 101(11-9) | sz=0(8) | N(7) | 0(6) | M(5) | 0(4) | Vm(3-0)
3142 int vd, d;
3143 dst.split_code(&vd, &d);
3144 int vn, n;
3145 src1.split_code(&vn, &n);
3146 int vm, m;
3147 src2.split_code(&vm, &m);
3148 emit(cond | 0x1C * B23 | d * B22 | 0x3 * B20 | vn * B16 | vd * B12 |
3149 0x5 * B9 | n * B7 | m * B5 | vm);
3150}
3151
3152
Leon Clarkee46be812010-01-19 14:06:41 +00003153void Assembler::vsub(const DwVfpRegister dst,
3154 const DwVfpRegister src1,
3155 const DwVfpRegister src2,
3156 const Condition cond) {
3157 // Dd = vsub(Dn, Dm) double precision floating point subtraction.
Steve Blockd0582a62009-12-15 09:54:21 +00003158 // Dd = D:Vd; Dm=M:Vm; Dn=N:Vm.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003159 // Instruction details available in ARM DDI 0406C.b, A8-1086.
3160 // cond(31-28) | 11100(27-23)| D(22) | 11(21-20) | Vn(19-16) |
3161 // Vd(15-12) | 101(11-9) | sz=1(8) | N(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
3162 int vd, d;
3163 dst.split_code(&vd, &d);
3164 int vn, n;
3165 src1.split_code(&vn, &n);
3166 int vm, m;
3167 src2.split_code(&vm, &m);
3168 emit(cond | 0x1C*B23 | d*B22 | 0x3*B20 | vn*B16 | vd*B12 | 0x5*B9 | B8 |
3169 n*B7 | B6 | m*B5 | vm);
Steve Blockd0582a62009-12-15 09:54:21 +00003170}
3171
3172
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003173void Assembler::vsub(const SwVfpRegister dst, const SwVfpRegister src1,
3174 const SwVfpRegister src2, const Condition cond) {
3175 // Sd = vsub(Sn, Sm) single precision floating point subtraction.
3176 // Sd = D:Vd; Sm=M:Vm; Sn=N:Vm.
3177 // Instruction details available in ARM DDI 0406C.b, A8-1086.
3178 // cond(31-28) | 11100(27-23)| D(22) | 11(21-20) | Vn(19-16) |
3179 // Vd(15-12) | 101(11-9) | sz=0(8) | N(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
3180 int vd, d;
3181 dst.split_code(&vd, &d);
3182 int vn, n;
3183 src1.split_code(&vn, &n);
3184 int vm, m;
3185 src2.split_code(&vm, &m);
3186 emit(cond | 0x1C * B23 | d * B22 | 0x3 * B20 | vn * B16 | vd * B12 |
3187 0x5 * B9 | n * B7 | B6 | m * B5 | vm);
3188}
3189
3190
Leon Clarkee46be812010-01-19 14:06:41 +00003191void Assembler::vmul(const DwVfpRegister dst,
3192 const DwVfpRegister src1,
3193 const DwVfpRegister src2,
3194 const Condition cond) {
3195 // Dd = vmul(Dn, Dm) double precision floating point multiplication.
Steve Blockd0582a62009-12-15 09:54:21 +00003196 // Dd = D:Vd; Dm=M:Vm; Dn=N:Vm.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003197 // Instruction details available in ARM DDI 0406C.b, A8-960.
3198 // cond(31-28) | 11100(27-23)| D(22) | 10(21-20) | Vn(19-16) |
3199 // Vd(15-12) | 101(11-9) | sz=1(8) | N(7) | 0(6) | M(5) | 0(4) | Vm(3-0)
3200 int vd, d;
3201 dst.split_code(&vd, &d);
3202 int vn, n;
3203 src1.split_code(&vn, &n);
3204 int vm, m;
3205 src2.split_code(&vm, &m);
3206 emit(cond | 0x1C*B23 | d*B22 | 0x2*B20 | vn*B16 | vd*B12 | 0x5*B9 | B8 |
3207 n*B7 | m*B5 | vm);
3208}
3209
3210
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003211void Assembler::vmul(const SwVfpRegister dst, const SwVfpRegister src1,
3212 const SwVfpRegister src2, const Condition cond) {
3213 // Sd = vmul(Sn, Sm) single precision floating point multiplication.
3214 // Sd = D:Vd; Sm=M:Vm; Sn=N:Vm.
3215 // Instruction details available in ARM DDI 0406C.b, A8-960.
3216 // cond(31-28) | 11100(27-23)| D(22) | 10(21-20) | Vn(19-16) |
3217 // Vd(15-12) | 101(11-9) | sz=0(8) | N(7) | 0(6) | M(5) | 0(4) | Vm(3-0)
3218 int vd, d;
3219 dst.split_code(&vd, &d);
3220 int vn, n;
3221 src1.split_code(&vn, &n);
3222 int vm, m;
3223 src2.split_code(&vm, &m);
3224 emit(cond | 0x1C * B23 | d * B22 | 0x2 * B20 | vn * B16 | vd * B12 |
3225 0x5 * B9 | n * B7 | m * B5 | vm);
3226}
3227
3228
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003229void Assembler::vmla(const DwVfpRegister dst,
3230 const DwVfpRegister src1,
3231 const DwVfpRegister src2,
3232 const Condition cond) {
3233 // Instruction details available in ARM DDI 0406C.b, A8-932.
3234 // cond(31-28) | 11100(27-23) | D(22) | 00(21-20) | Vn(19-16) |
3235 // Vd(15-12) | 101(11-9) | sz=1(8) | N(7) | op=0(6) | M(5) | 0(4) | Vm(3-0)
3236 int vd, d;
3237 dst.split_code(&vd, &d);
3238 int vn, n;
3239 src1.split_code(&vn, &n);
3240 int vm, m;
3241 src2.split_code(&vm, &m);
3242 emit(cond | 0x1C*B23 | d*B22 | vn*B16 | vd*B12 | 0x5*B9 | B8 | n*B7 | m*B5 |
3243 vm);
3244}
3245
3246
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003247void Assembler::vmla(const SwVfpRegister dst, const SwVfpRegister src1,
3248 const SwVfpRegister src2, const Condition cond) {
3249 // Instruction details available in ARM DDI 0406C.b, A8-932.
3250 // cond(31-28) | 11100(27-23) | D(22) | 00(21-20) | Vn(19-16) |
3251 // Vd(15-12) | 101(11-9) | sz=0(8) | N(7) | op=0(6) | M(5) | 0(4) | Vm(3-0)
3252 int vd, d;
3253 dst.split_code(&vd, &d);
3254 int vn, n;
3255 src1.split_code(&vn, &n);
3256 int vm, m;
3257 src2.split_code(&vm, &m);
3258 emit(cond | 0x1C * B23 | d * B22 | vn * B16 | vd * B12 | 0x5 * B9 | n * B7 |
3259 m * B5 | vm);
3260}
3261
3262
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003263void Assembler::vmls(const DwVfpRegister dst,
3264 const DwVfpRegister src1,
3265 const DwVfpRegister src2,
3266 const Condition cond) {
3267 // Instruction details available in ARM DDI 0406C.b, A8-932.
3268 // cond(31-28) | 11100(27-23) | D(22) | 00(21-20) | Vn(19-16) |
3269 // Vd(15-12) | 101(11-9) | sz=1(8) | N(7) | op=1(6) | M(5) | 0(4) | Vm(3-0)
3270 int vd, d;
3271 dst.split_code(&vd, &d);
3272 int vn, n;
3273 src1.split_code(&vn, &n);
3274 int vm, m;
3275 src2.split_code(&vm, &m);
3276 emit(cond | 0x1C*B23 | d*B22 | vn*B16 | vd*B12 | 0x5*B9 | B8 | n*B7 | B6 |
3277 m*B5 | vm);
Steve Blockd0582a62009-12-15 09:54:21 +00003278}
3279
3280
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003281void Assembler::vmls(const SwVfpRegister dst, const SwVfpRegister src1,
3282 const SwVfpRegister src2, const Condition cond) {
3283 // Instruction details available in ARM DDI 0406C.b, A8-932.
3284 // cond(31-28) | 11100(27-23) | D(22) | 00(21-20) | Vn(19-16) |
3285 // Vd(15-12) | 101(11-9) | sz=0(8) | N(7) | op=1(6) | M(5) | 0(4) | Vm(3-0)
3286 int vd, d;
3287 dst.split_code(&vd, &d);
3288 int vn, n;
3289 src1.split_code(&vn, &n);
3290 int vm, m;
3291 src2.split_code(&vm, &m);
3292 emit(cond | 0x1C * B23 | d * B22 | vn * B16 | vd * B12 | 0x5 * B9 | n * B7 |
3293 B6 | m * B5 | vm);
3294}
3295
3296
Leon Clarkee46be812010-01-19 14:06:41 +00003297void Assembler::vdiv(const DwVfpRegister dst,
3298 const DwVfpRegister src1,
3299 const DwVfpRegister src2,
3300 const Condition cond) {
3301 // Dd = vdiv(Dn, Dm) double precision floating point division.
Steve Blockd0582a62009-12-15 09:54:21 +00003302 // Dd = D:Vd; Dm=M:Vm; Dn=N:Vm.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003303 // Instruction details available in ARM DDI 0406C.b, A8-882.
3304 // cond(31-28) | 11101(27-23)| D(22) | 00(21-20) | Vn(19-16) |
3305 // Vd(15-12) | 101(11-9) | sz=1(8) | N(7) | 0(6) | M(5) | 0(4) | Vm(3-0)
3306 int vd, d;
3307 dst.split_code(&vd, &d);
3308 int vn, n;
3309 src1.split_code(&vn, &n);
3310 int vm, m;
3311 src2.split_code(&vm, &m);
3312 emit(cond | 0x1D*B23 | d*B22 | vn*B16 | vd*B12 | 0x5*B9 | B8 | n*B7 | m*B5 |
3313 vm);
Steve Blockd0582a62009-12-15 09:54:21 +00003314}
3315
3316
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003317void Assembler::vdiv(const SwVfpRegister dst, const SwVfpRegister src1,
3318 const SwVfpRegister src2, const Condition cond) {
3319 // Sd = vdiv(Sn, Sm) single precision floating point division.
3320 // Sd = D:Vd; Sm=M:Vm; Sn=N:Vm.
3321 // Instruction details available in ARM DDI 0406C.b, A8-882.
3322 // cond(31-28) | 11101(27-23)| D(22) | 00(21-20) | Vn(19-16) |
3323 // Vd(15-12) | 101(11-9) | sz=0(8) | N(7) | 0(6) | M(5) | 0(4) | Vm(3-0)
3324 int vd, d;
3325 dst.split_code(&vd, &d);
3326 int vn, n;
3327 src1.split_code(&vn, &n);
3328 int vm, m;
3329 src2.split_code(&vm, &m);
3330 emit(cond | 0x1D * B23 | d * B22 | vn * B16 | vd * B12 | 0x5 * B9 | n * B7 |
3331 m * B5 | vm);
3332}
3333
3334
Leon Clarkee46be812010-01-19 14:06:41 +00003335void Assembler::vcmp(const DwVfpRegister src1,
3336 const DwVfpRegister src2,
Steve Blockd0582a62009-12-15 09:54:21 +00003337 const Condition cond) {
3338 // vcmp(Dd, Dm) double precision floating point comparison.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003339 // Instruction details available in ARM DDI 0406C.b, A8-864.
3340 // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 0100(19-16) |
3341 // Vd(15-12) | 101(11-9) | sz=1(8) | E=0(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
3342 int vd, d;
3343 src1.split_code(&vd, &d);
3344 int vm, m;
3345 src2.split_code(&vm, &m);
3346 emit(cond | 0x1D*B23 | d*B22 | 0x3*B20 | 0x4*B16 | vd*B12 | 0x5*B9 | B8 | B6 |
3347 m*B5 | vm);
Steve Blockd0582a62009-12-15 09:54:21 +00003348}
3349
3350
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003351void Assembler::vcmp(const SwVfpRegister src1, const SwVfpRegister src2,
3352 const Condition cond) {
3353 // vcmp(Sd, Sm) single precision floating point comparison.
3354 // Instruction details available in ARM DDI 0406C.b, A8-864.
3355 // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 0100(19-16) |
3356 // Vd(15-12) | 101(11-9) | sz=0(8) | E=0(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
3357 int vd, d;
3358 src1.split_code(&vd, &d);
3359 int vm, m;
3360 src2.split_code(&vm, &m);
3361 emit(cond | 0x1D * B23 | d * B22 | 0x3 * B20 | 0x4 * B16 | vd * B12 |
3362 0x5 * B9 | B6 | m * B5 | vm);
3363}
3364
3365
Iain Merrick75681382010-08-19 15:07:18 +01003366void Assembler::vcmp(const DwVfpRegister src1,
3367 const double src2,
Iain Merrick75681382010-08-19 15:07:18 +01003368 const Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003369 // vcmp(Dd, #0.0) double precision floating point comparison.
3370 // Instruction details available in ARM DDI 0406C.b, A8-864.
3371 // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 0101(19-16) |
3372 // Vd(15-12) | 101(11-9) | sz=1(8) | E=0(7) | 1(6) | 0(5) | 0(4) | 0000(3-0)
3373 DCHECK(src2 == 0.0);
3374 int vd, d;
3375 src1.split_code(&vd, &d);
3376 emit(cond | 0x1D*B23 | d*B22 | 0x3*B20 | 0x5*B16 | vd*B12 | 0x5*B9 | B8 | B6);
Iain Merrick75681382010-08-19 15:07:18 +01003377}
3378
3379
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003380void Assembler::vcmp(const SwVfpRegister src1, const float src2,
3381 const Condition cond) {
3382 // vcmp(Sd, #0.0) single precision floating point comparison.
3383 // Instruction details available in ARM DDI 0406C.b, A8-864.
3384 // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 0101(19-16) |
3385 // Vd(15-12) | 101(11-9) | sz=0(8) | E=0(7) | 1(6) | 0(5) | 0(4) | 0000(3-0)
3386 DCHECK(src2 == 0.0);
3387 int vd, d;
3388 src1.split_code(&vd, &d);
3389 emit(cond | 0x1D * B23 | d * B22 | 0x3 * B20 | 0x5 * B16 | vd * B12 |
3390 0x5 * B9 | B6);
Steve Blockd0582a62009-12-15 09:54:21 +00003391}
3392
Ben Murdochc5610432016-08-08 18:44:38 +01003393void Assembler::vsel(Condition cond, const DwVfpRegister dst,
3394 const DwVfpRegister src1, const DwVfpRegister src2) {
3395 // cond=kSpecialCondition(31-28) | 11100(27-23) | D(22) |
3396 // vsel_cond=XX(21-20) | Vn(19-16) | Vd(15-12) | 101(11-9) | sz=1(8) | N(7) |
3397 // 0(6) | M(5) | 0(4) | Vm(3-0)
3398 DCHECK(CpuFeatures::IsSupported(ARMv8));
3399 int vd, d;
3400 dst.split_code(&vd, &d);
3401 int vn, n;
3402 src1.split_code(&vn, &n);
3403 int vm, m;
3404 src2.split_code(&vm, &m);
3405 int sz = 1;
3406
3407 // VSEL has a special (restricted) condition encoding.
3408 // eq(0b0000)... -> 0b00
3409 // ge(0b1010)... -> 0b10
3410 // gt(0b1100)... -> 0b11
3411 // vs(0b0110)... -> 0b01
3412 // No other conditions are supported.
3413 int vsel_cond = (cond >> 30) & 0x3;
3414 if ((cond != eq) && (cond != ge) && (cond != gt) && (cond != vs)) {
3415 // We can implement some other conditions by swapping the inputs.
3416 DCHECK((cond == ne) | (cond == lt) | (cond == le) | (cond == vc));
3417 std::swap(vn, vm);
3418 std::swap(n, m);
3419 }
3420
3421 emit(kSpecialCondition | 0x1C * B23 | d * B22 | vsel_cond * B20 | vn * B16 |
3422 vd * B12 | 0x5 * B9 | sz * B8 | n * B7 | m * B5 | vm);
3423}
3424
3425void Assembler::vsel(Condition cond, const SwVfpRegister dst,
3426 const SwVfpRegister src1, const SwVfpRegister src2) {
3427 // cond=kSpecialCondition(31-28) | 11100(27-23) | D(22) |
3428 // vsel_cond=XX(21-20) | Vn(19-16) | Vd(15-12) | 101(11-9) | sz=0(8) | N(7) |
3429 // 0(6) | M(5) | 0(4) | Vm(3-0)
3430 DCHECK(CpuFeatures::IsSupported(ARMv8));
3431 int vd, d;
3432 dst.split_code(&vd, &d);
3433 int vn, n;
3434 src1.split_code(&vn, &n);
3435 int vm, m;
3436 src2.split_code(&vm, &m);
3437 int sz = 0;
3438
3439 // VSEL has a special (restricted) condition encoding.
3440 // eq(0b0000)... -> 0b00
3441 // ge(0b1010)... -> 0b10
3442 // gt(0b1100)... -> 0b11
3443 // vs(0b0110)... -> 0b01
3444 // No other conditions are supported.
3445 int vsel_cond = (cond >> 30) & 0x3;
3446 if ((cond != eq) && (cond != ge) && (cond != gt) && (cond != vs)) {
3447 // We can implement some other conditions by swapping the inputs.
3448 DCHECK((cond == ne) | (cond == lt) | (cond == le) | (cond == vc));
3449 std::swap(vn, vm);
3450 std::swap(n, m);
3451 }
3452
3453 emit(kSpecialCondition | 0x1C * B23 | d * B22 | vsel_cond * B20 | vn * B16 |
3454 vd * B12 | 0x5 * B9 | sz * B8 | n * B7 | m * B5 | vm);
3455}
Steve Blockd0582a62009-12-15 09:54:21 +00003456
Steve Block8defd9f2010-07-08 12:39:36 +01003457void Assembler::vsqrt(const DwVfpRegister dst,
3458 const DwVfpRegister src,
3459 const Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003460 // Instruction details available in ARM DDI 0406C.b, A8-1058.
3461 // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 0001(19-16) |
3462 // Vd(15-12) | 101(11-9) | sz=1(8) | 11(7-6) | M(5) | 0(4) | Vm(3-0)
3463 int vd, d;
3464 dst.split_code(&vd, &d);
3465 int vm, m;
3466 src.split_code(&vm, &m);
3467 emit(cond | 0x1D*B23 | d*B22 | 0x3*B20 | B16 | vd*B12 | 0x5*B9 | B8 | 0x3*B6 |
3468 m*B5 | vm);
3469}
3470
3471
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003472void Assembler::vsqrt(const SwVfpRegister dst, const SwVfpRegister src,
3473 const Condition cond) {
3474 // Instruction details available in ARM DDI 0406C.b, A8-1058.
3475 // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 0001(19-16) |
3476 // Vd(15-12) | 101(11-9) | sz=0(8) | 11(7-6) | M(5) | 0(4) | Vm(3-0)
3477 int vd, d;
3478 dst.split_code(&vd, &d);
3479 int vm, m;
3480 src.split_code(&vm, &m);
3481 emit(cond | 0x1D * B23 | d * B22 | 0x3 * B20 | B16 | vd * B12 | 0x5 * B9 |
3482 0x3 * B6 | m * B5 | vm);
3483}
3484
3485
3486void Assembler::vmsr(Register dst, Condition cond) {
3487 // Instruction details available in ARM DDI 0406A, A8-652.
3488 // cond(31-28) | 1110 (27-24) | 1110(23-20)| 0001 (19-16) |
3489 // Rt(15-12) | 1010 (11-8) | 0(7) | 00 (6-5) | 1(4) | 0000(3-0)
3490 emit(cond | 0xE * B24 | 0xE * B20 | B16 | dst.code() * B12 | 0xA * B8 | B4);
3491}
3492
3493
3494void Assembler::vmrs(Register dst, Condition cond) {
3495 // Instruction details available in ARM DDI 0406A, A8-652.
3496 // cond(31-28) | 1110 (27-24) | 1111(23-20)| 0001 (19-16) |
3497 // Rt(15-12) | 1010 (11-8) | 0(7) | 00 (6-5) | 1(4) | 0000(3-0)
3498 emit(cond | 0xE * B24 | 0xF * B20 | B16 | dst.code() * B12 | 0xA * B8 | B4);
3499}
3500
3501
3502void Assembler::vrinta(const SwVfpRegister dst, const SwVfpRegister src) {
3503 // cond=kSpecialCondition(31-28) | 11101(27-23)| D(22) | 11(21-20) |
3504 // 10(19-18) | RM=00(17-16) | Vd(15-12) | 101(11-9) | sz=0(8) | 01(7-6) |
3505 // M(5) | 0(4) | Vm(3-0)
3506 DCHECK(CpuFeatures::IsSupported(ARMv8));
3507 int vd, d;
3508 dst.split_code(&vd, &d);
3509 int vm, m;
3510 src.split_code(&vm, &m);
3511 emit(kSpecialCondition | 0x1D * B23 | d * B22 | 0x3 * B20 | B19 | vd * B12 |
3512 0x5 * B9 | B6 | m * B5 | vm);
3513}
3514
3515
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003516void Assembler::vrinta(const DwVfpRegister dst, const DwVfpRegister src) {
3517 // cond=kSpecialCondition(31-28) | 11101(27-23)| D(22) | 11(21-20) |
3518 // 10(19-18) | RM=00(17-16) | Vd(15-12) | 101(11-9) | sz=1(8) | 01(7-6) |
3519 // M(5) | 0(4) | Vm(3-0)
3520 DCHECK(CpuFeatures::IsSupported(ARMv8));
3521 int vd, d;
3522 dst.split_code(&vd, &d);
3523 int vm, m;
3524 src.split_code(&vm, &m);
3525 emit(kSpecialCondition | 0x1D * B23 | d * B22 | 0x3 * B20 | B19 | vd * B12 |
3526 0x5 * B9 | B8 | B6 | m * B5 | vm);
3527}
3528
3529
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003530void Assembler::vrintn(const SwVfpRegister dst, const SwVfpRegister src) {
3531 // cond=kSpecialCondition(31-28) | 11101(27-23)| D(22) | 11(21-20) |
3532 // 10(19-18) | RM=01(17-16) | Vd(15-12) | 101(11-9) | sz=0(8) | 01(7-6) |
3533 // M(5) | 0(4) | Vm(3-0)
3534 DCHECK(CpuFeatures::IsSupported(ARMv8));
3535 int vd, d;
3536 dst.split_code(&vd, &d);
3537 int vm, m;
3538 src.split_code(&vm, &m);
3539 emit(kSpecialCondition | 0x1D * B23 | d * B22 | 0x3 * B20 | B19 | 0x1 * B16 |
3540 vd * B12 | 0x5 * B9 | B6 | m * B5 | vm);
3541}
3542
3543
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003544void Assembler::vrintn(const DwVfpRegister dst, const DwVfpRegister src) {
3545 // cond=kSpecialCondition(31-28) | 11101(27-23)| D(22) | 11(21-20) |
3546 // 10(19-18) | RM=01(17-16) | Vd(15-12) | 101(11-9) | sz=1(8) | 01(7-6) |
3547 // M(5) | 0(4) | Vm(3-0)
3548 DCHECK(CpuFeatures::IsSupported(ARMv8));
3549 int vd, d;
3550 dst.split_code(&vd, &d);
3551 int vm, m;
3552 src.split_code(&vm, &m);
3553 emit(kSpecialCondition | 0x1D * B23 | d * B22 | 0x3 * B20 | B19 | 0x1 * B16 |
3554 vd * B12 | 0x5 * B9 | B8 | B6 | m * B5 | vm);
3555}
3556
3557
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003558void Assembler::vrintp(const SwVfpRegister dst, const SwVfpRegister src) {
3559 // cond=kSpecialCondition(31-28) | 11101(27-23)| D(22) | 11(21-20) |
3560 // 10(19-18) | RM=10(17-16) | Vd(15-12) | 101(11-9) | sz=0(8) | 01(7-6) |
3561 // M(5) | 0(4) | Vm(3-0)
3562 DCHECK(CpuFeatures::IsSupported(ARMv8));
3563 int vd, d;
3564 dst.split_code(&vd, &d);
3565 int vm, m;
3566 src.split_code(&vm, &m);
3567 emit(kSpecialCondition | 0x1D * B23 | d * B22 | 0x3 * B20 | B19 | 0x2 * B16 |
3568 vd * B12 | 0x5 * B9 | B6 | m * B5 | vm);
3569}
3570
3571
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003572void Assembler::vrintp(const DwVfpRegister dst, const DwVfpRegister src) {
3573 // cond=kSpecialCondition(31-28) | 11101(27-23)| D(22) | 11(21-20) |
3574 // 10(19-18) | RM=10(17-16) | Vd(15-12) | 101(11-9) | sz=1(8) | 01(7-6) |
3575 // M(5) | 0(4) | Vm(3-0)
3576 DCHECK(CpuFeatures::IsSupported(ARMv8));
3577 int vd, d;
3578 dst.split_code(&vd, &d);
3579 int vm, m;
3580 src.split_code(&vm, &m);
3581 emit(kSpecialCondition | 0x1D * B23 | d * B22 | 0x3 * B20 | B19 | 0x2 * B16 |
3582 vd * B12 | 0x5 * B9 | B8 | B6 | m * B5 | vm);
3583}
3584
3585
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003586void Assembler::vrintm(const SwVfpRegister dst, const SwVfpRegister src) {
3587 // cond=kSpecialCondition(31-28) | 11101(27-23)| D(22) | 11(21-20) |
3588 // 10(19-18) | RM=11(17-16) | Vd(15-12) | 101(11-9) | sz=0(8) | 01(7-6) |
3589 // M(5) | 0(4) | Vm(3-0)
3590 DCHECK(CpuFeatures::IsSupported(ARMv8));
3591 int vd, d;
3592 dst.split_code(&vd, &d);
3593 int vm, m;
3594 src.split_code(&vm, &m);
3595 emit(kSpecialCondition | 0x1D * B23 | d * B22 | 0x3 * B20 | B19 | 0x3 * B16 |
3596 vd * B12 | 0x5 * B9 | B6 | m * B5 | vm);
3597}
3598
3599
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003600void Assembler::vrintm(const DwVfpRegister dst, const DwVfpRegister src) {
3601 // cond=kSpecialCondition(31-28) | 11101(27-23)| D(22) | 11(21-20) |
3602 // 10(19-18) | RM=11(17-16) | Vd(15-12) | 101(11-9) | sz=1(8) | 01(7-6) |
3603 // M(5) | 0(4) | Vm(3-0)
3604 DCHECK(CpuFeatures::IsSupported(ARMv8));
3605 int vd, d;
3606 dst.split_code(&vd, &d);
3607 int vm, m;
3608 src.split_code(&vm, &m);
3609 emit(kSpecialCondition | 0x1D * B23 | d * B22 | 0x3 * B20 | B19 | 0x3 * B16 |
3610 vd * B12 | 0x5 * B9 | B8 | B6 | m * B5 | vm);
3611}
3612
3613
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003614void Assembler::vrintz(const SwVfpRegister dst, const SwVfpRegister src,
3615 const Condition cond) {
3616 // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 011(19-17) | 0(16) |
3617 // Vd(15-12) | 101(11-9) | sz=0(8) | op=1(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
3618 DCHECK(CpuFeatures::IsSupported(ARMv8));
3619 int vd, d;
3620 dst.split_code(&vd, &d);
3621 int vm, m;
3622 src.split_code(&vm, &m);
3623 emit(cond | 0x1D * B23 | d * B22 | 0x3 * B20 | 0x3 * B17 | vd * B12 |
3624 0x5 * B9 | B7 | B6 | m * B5 | vm);
3625}
3626
3627
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003628void Assembler::vrintz(const DwVfpRegister dst, const DwVfpRegister src,
3629 const Condition cond) {
3630 // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 011(19-17) | 0(16) |
3631 // Vd(15-12) | 101(11-9) | sz=1(8) | op=1(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
3632 DCHECK(CpuFeatures::IsSupported(ARMv8));
3633 int vd, d;
3634 dst.split_code(&vd, &d);
3635 int vm, m;
3636 src.split_code(&vm, &m);
3637 emit(cond | 0x1D * B23 | d * B22 | 0x3 * B20 | 0x3 * B17 | vd * B12 |
3638 0x5 * B9 | B8 | B7 | B6 | m * B5 | vm);
3639}
3640
3641
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003642// Support for NEON.
3643
3644void Assembler::vld1(NeonSize size,
3645 const NeonListOperand& dst,
3646 const NeonMemOperand& src) {
3647 // Instruction details available in ARM DDI 0406C.b, A8.8.320.
3648 // 1111(31-28) | 01000(27-23) | D(22) | 10(21-20) | Rn(19-16) |
3649 // Vd(15-12) | type(11-8) | size(7-6) | align(5-4) | Rm(3-0)
3650 DCHECK(CpuFeatures::IsSupported(NEON));
3651 int vd, d;
3652 dst.base().split_code(&vd, &d);
3653 emit(0xFU*B28 | 4*B24 | d*B22 | 2*B20 | src.rn().code()*B16 | vd*B12 |
3654 dst.type()*B8 | size*B6 | src.align()*B4 | src.rm().code());
3655}
3656
3657
3658void Assembler::vst1(NeonSize size,
3659 const NeonListOperand& src,
3660 const NeonMemOperand& dst) {
3661 // Instruction details available in ARM DDI 0406C.b, A8.8.404.
3662 // 1111(31-28) | 01000(27-23) | D(22) | 00(21-20) | Rn(19-16) |
3663 // Vd(15-12) | type(11-8) | size(7-6) | align(5-4) | Rm(3-0)
3664 DCHECK(CpuFeatures::IsSupported(NEON));
3665 int vd, d;
3666 src.base().split_code(&vd, &d);
3667 emit(0xFU*B28 | 4*B24 | d*B22 | dst.rn().code()*B16 | vd*B12 | src.type()*B8 |
3668 size*B6 | dst.align()*B4 | dst.rm().code());
3669}
3670
3671
3672void Assembler::vmovl(NeonDataType dt, QwNeonRegister dst, DwVfpRegister src) {
3673 // Instruction details available in ARM DDI 0406C.b, A8.8.346.
3674 // 1111(31-28) | 001(27-25) | U(24) | 1(23) | D(22) | imm3(21-19) |
3675 // 000(18-16) | Vd(15-12) | 101000(11-6) | M(5) | 1(4) | Vm(3-0)
3676 DCHECK(CpuFeatures::IsSupported(NEON));
3677 int vd, d;
3678 dst.split_code(&vd, &d);
3679 int vm, m;
3680 src.split_code(&vm, &m);
3681 emit(0xFU*B28 | B25 | (dt & NeonDataTypeUMask) | B23 | d*B22 |
3682 (dt & NeonDataTypeSizeMask)*B19 | vd*B12 | 0xA*B8 | m*B5 | B4 | vm);
Steve Block8defd9f2010-07-08 12:39:36 +01003683}
3684
3685
Andrei Popescu31002712010-02-23 13:46:05 +00003686// Pseudo instructions.
Steve Block6ded16b2010-05-10 14:33:55 +01003687void Assembler::nop(int type) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003688 // ARMv6{K/T2} and v7 have an actual NOP instruction but it serializes
3689 // some of the CPU's pipeline and has to issue. Older ARM chips simply used
3690 // MOV Rx, Rx as NOP and it performs better even in newer CPUs.
3691 // We therefore use MOV Rx, Rx, even on newer CPUs, and use Rx to encode
3692 // a type.
3693 DCHECK(0 <= type && type <= 14); // mov pc, pc isn't a nop.
Steve Block6ded16b2010-05-10 14:33:55 +01003694 emit(al | 13*B21 | type*B12 | type);
3695}
3696
3697
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003698bool Assembler::IsMovT(Instr instr) {
3699 instr &= ~(((kNumberOfConditions - 1) << 28) | // Mask off conditions
3700 ((kNumRegisters-1)*B12) | // mask out register
3701 EncodeMovwImmediate(0xFFFF)); // mask out immediate value
3702 return instr == kMovtPattern;
3703}
3704
3705
3706bool Assembler::IsMovW(Instr instr) {
3707 instr &= ~(((kNumberOfConditions - 1) << 28) | // Mask off conditions
3708 ((kNumRegisters-1)*B12) | // mask out destination
3709 EncodeMovwImmediate(0xFFFF)); // mask out immediate value
3710 return instr == kMovwPattern;
3711}
3712
3713
3714Instr Assembler::GetMovTPattern() { return kMovtPattern; }
3715
3716
3717Instr Assembler::GetMovWPattern() { return kMovwPattern; }
3718
3719
3720Instr Assembler::EncodeMovwImmediate(uint32_t immediate) {
3721 DCHECK(immediate < 0x10000);
3722 return ((immediate & 0xf000) << 4) | (immediate & 0xfff);
3723}
3724
3725
3726Instr Assembler::PatchMovwImmediate(Instr instruction, uint32_t immediate) {
3727 instruction &= ~EncodeMovwImmediate(0xffff);
3728 return instruction | EncodeMovwImmediate(immediate);
3729}
3730
3731
3732int Assembler::DecodeShiftImm(Instr instr) {
3733 int rotate = Instruction::RotateValue(instr) * 2;
3734 int immed8 = Instruction::Immed8Value(instr);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003735 return base::bits::RotateRight32(immed8, rotate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003736}
3737
3738
3739Instr Assembler::PatchShiftImm(Instr instr, int immed) {
3740 uint32_t rotate_imm = 0;
3741 uint32_t immed_8 = 0;
3742 bool immed_fits = fits_shifter(immed, &rotate_imm, &immed_8, NULL);
3743 DCHECK(immed_fits);
3744 USE(immed_fits);
3745 return (instr & ~kOff12Mask) | (rotate_imm << 8) | immed_8;
3746}
3747
3748
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08003749bool Assembler::IsNop(Instr instr, int type) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003750 DCHECK(0 <= type && type <= 14); // mov pc, pc isn't a nop.
Steve Block1e0659c2011-05-24 12:43:12 +01003751 // Check for mov rx, rx where x = type.
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08003752 return instr == (al | 13*B21 | type*B12 | type);
3753}
3754
3755
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003756bool Assembler::IsMovImmed(Instr instr) {
3757 return (instr & kMovImmedMask) == kMovImmedPattern;
3758}
3759
3760
3761bool Assembler::IsOrrImmed(Instr instr) {
3762 return (instr & kOrrImmedMask) == kOrrImmedPattern;
3763}
3764
3765
3766// static
Steve Blockd0582a62009-12-15 09:54:21 +00003767bool Assembler::ImmediateFitsAddrMode1Instruction(int32_t imm32) {
3768 uint32_t dummy1;
3769 uint32_t dummy2;
3770 return fits_shifter(imm32, &dummy1, &dummy2, NULL);
3771}
3772
3773
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003774bool Assembler::ImmediateFitsAddrMode2Instruction(int32_t imm32) {
3775 return is_uint12(abs(imm32));
3776}
3777
3778
Andrei Popescu31002712010-02-23 13:46:05 +00003779// Debugging.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003780void Assembler::RecordConstPool(int size) {
3781 // We only need this for debugger support, to correctly compute offsets in the
3782 // code.
3783 RecordRelocInfo(RelocInfo::CONST_POOL, static_cast<intptr_t>(size));
3784}
3785
3786
Steve Blocka7e24c12009-10-30 11:49:00 +00003787void Assembler::GrowBuffer() {
3788 if (!own_buffer_) FATAL("external code buffer is too small");
3789
Andrei Popescu31002712010-02-23 13:46:05 +00003790 // Compute new buffer size.
Steve Blocka7e24c12009-10-30 11:49:00 +00003791 CodeDesc desc; // the new buffer
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003792 if (buffer_size_ < 1 * MB) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003793 desc.buffer_size = 2*buffer_size_;
3794 } else {
3795 desc.buffer_size = buffer_size_ + 1*MB;
3796 }
3797 CHECK_GT(desc.buffer_size, 0); // no overflow
3798
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003799 // Set up new buffer.
Steve Blocka7e24c12009-10-30 11:49:00 +00003800 desc.buffer = NewArray<byte>(desc.buffer_size);
3801
3802 desc.instr_size = pc_offset();
3803 desc.reloc_size = (buffer_ + buffer_size_) - reloc_info_writer.pos();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003804 desc.origin = this;
Steve Blocka7e24c12009-10-30 11:49:00 +00003805
Andrei Popescu31002712010-02-23 13:46:05 +00003806 // Copy the data.
Steve Blocka7e24c12009-10-30 11:49:00 +00003807 int pc_delta = desc.buffer - buffer_;
3808 int rc_delta = (desc.buffer + desc.buffer_size) - (buffer_ + buffer_size_);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003809 MemMove(desc.buffer, buffer_, desc.instr_size);
3810 MemMove(reloc_info_writer.pos() + rc_delta, reloc_info_writer.pos(),
3811 desc.reloc_size);
Steve Blocka7e24c12009-10-30 11:49:00 +00003812
Andrei Popescu31002712010-02-23 13:46:05 +00003813 // Switch buffers.
Steve Blocka7e24c12009-10-30 11:49:00 +00003814 DeleteArray(buffer_);
3815 buffer_ = desc.buffer;
3816 buffer_size_ = desc.buffer_size;
3817 pc_ += pc_delta;
3818 reloc_info_writer.Reposition(reloc_info_writer.pos() + rc_delta,
3819 reloc_info_writer.last_pc() + pc_delta);
3820
Andrei Popescu31002712010-02-23 13:46:05 +00003821 // None of our relocation types are pc relative pointing outside the code
Steve Blocka7e24c12009-10-30 11:49:00 +00003822 // buffer nor pc absolute pointing inside the code buffer, so there is no need
Andrei Popescu31002712010-02-23 13:46:05 +00003823 // to relocate any emitted relocation entries.
Steve Blocka7e24c12009-10-30 11:49:00 +00003824}
3825
3826
Ben Murdochb0fe1622011-05-05 13:52:32 +01003827void Assembler::db(uint8_t data) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003828 // db is used to write raw data. The constant pool should be emitted or
3829 // blocked before using db.
3830 DCHECK(is_const_pool_blocked() || (num_pending_32_bit_constants_ == 0));
3831 DCHECK(is_const_pool_blocked() || (num_pending_64_bit_constants_ == 0));
Ben Murdochb0fe1622011-05-05 13:52:32 +01003832 CheckBuffer();
3833 *reinterpret_cast<uint8_t*>(pc_) = data;
3834 pc_ += sizeof(uint8_t);
3835}
3836
3837
3838void Assembler::dd(uint32_t data) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003839 // dd is used to write raw data. The constant pool should be emitted or
3840 // blocked before using dd.
3841 DCHECK(is_const_pool_blocked() || (num_pending_32_bit_constants_ == 0));
3842 DCHECK(is_const_pool_blocked() || (num_pending_64_bit_constants_ == 0));
Ben Murdochb0fe1622011-05-05 13:52:32 +01003843 CheckBuffer();
3844 *reinterpret_cast<uint32_t*>(pc_) = data;
3845 pc_ += sizeof(uint32_t);
3846}
3847
3848
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003849void Assembler::dq(uint64_t value) {
3850 // dq is used to write raw data. The constant pool should be emitted or
3851 // blocked before using dq.
3852 DCHECK(is_const_pool_blocked() || (num_pending_32_bit_constants_ == 0));
3853 DCHECK(is_const_pool_blocked() || (num_pending_64_bit_constants_ == 0));
3854 CheckBuffer();
3855 *reinterpret_cast<uint64_t*>(pc_) = value;
3856 pc_ += sizeof(uint64_t);
3857}
3858
3859
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003860void Assembler::emit_code_stub_address(Code* stub) {
3861 CheckBuffer();
3862 *reinterpret_cast<uint32_t*>(pc_) =
3863 reinterpret_cast<uint32_t>(stub->instruction_start());
3864 pc_ += sizeof(uint32_t);
3865}
3866
3867
Steve Blocka7e24c12009-10-30 11:49:00 +00003868void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003869 if (RelocInfo::IsNone(rmode) ||
3870 // Don't record external references unless the heap will be serialized.
3871 (rmode == RelocInfo::EXTERNAL_REFERENCE && !serializer_enabled() &&
3872 !emit_debug_code())) {
3873 return;
3874 }
3875 DCHECK(buffer_space() >= kMaxRelocSize); // too late to grow buffer here
3876 if (rmode == RelocInfo::CODE_TARGET_WITH_ID) {
3877 data = RecordedAstId().ToInt();
3878 ClearRecordedAstId();
3879 }
3880 RelocInfo rinfo(isolate(), pc_, rmode, data, NULL);
3881 reloc_info_writer.Write(&rinfo);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003882}
3883
3884
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003885ConstantPoolEntry::Access Assembler::ConstantPoolAddEntry(int position,
3886 RelocInfo::Mode rmode,
3887 intptr_t value) {
3888 DCHECK(rmode != RelocInfo::COMMENT && rmode != RelocInfo::POSITION &&
3889 rmode != RelocInfo::STATEMENT_POSITION &&
3890 rmode != RelocInfo::CONST_POOL && rmode != RelocInfo::NONE64);
3891 bool sharing_ok = RelocInfo::IsNone(rmode) ||
3892 !(serializer_enabled() || rmode < RelocInfo::CELL);
3893 if (FLAG_enable_embedded_constant_pool) {
3894 return constant_pool_builder_.AddEntry(position, value, sharing_ok);
3895 } else {
3896 DCHECK(num_pending_32_bit_constants_ < kMaxNumPending32Constants);
3897 if (num_pending_32_bit_constants_ == 0) {
3898 first_const_pool_32_use_ = position;
3899 } else if (num_pending_32_bit_constants_ == kMinNumPendingConstants &&
3900 pending_32_bit_constants_ ==
3901 &pending_32_bit_constants_buffer_[0]) {
3902 // Inline buffer is full, switch to dynamically allocated buffer.
3903 pending_32_bit_constants_ =
3904 new ConstantPoolEntry[kMaxNumPending32Constants];
3905 std::copy(&pending_32_bit_constants_buffer_[0],
3906 &pending_32_bit_constants_buffer_[kMinNumPendingConstants],
3907 &pending_32_bit_constants_[0]);
Steve Blocka7e24c12009-10-30 11:49:00 +00003908 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003909 ConstantPoolEntry entry(position, value, sharing_ok);
3910 pending_32_bit_constants_[num_pending_32_bit_constants_++] = entry;
3911
3912 // Make sure the constant pool is not emitted in place of the next
3913 // instruction for which we just recorded relocation info.
3914 BlockConstPoolFor(1);
3915 return ConstantPoolEntry::REGULAR;
Steve Blocka7e24c12009-10-30 11:49:00 +00003916 }
3917}
3918
3919
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003920ConstantPoolEntry::Access Assembler::ConstantPoolAddEntry(int position,
3921 double value) {
3922 if (FLAG_enable_embedded_constant_pool) {
3923 return constant_pool_builder_.AddEntry(position, value);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003924 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003925 DCHECK(num_pending_64_bit_constants_ < kMaxNumPending64Constants);
3926 if (num_pending_64_bit_constants_ == 0) {
3927 first_const_pool_64_use_ = position;
3928 } else if (num_pending_64_bit_constants_ == kMinNumPendingConstants &&
3929 pending_64_bit_constants_ ==
3930 &pending_64_bit_constants_buffer_[0]) {
3931 // Inline buffer is full, switch to dynamically allocated buffer.
3932 pending_64_bit_constants_ =
3933 new ConstantPoolEntry[kMaxNumPending64Constants];
3934 std::copy(&pending_64_bit_constants_buffer_[0],
3935 &pending_64_bit_constants_buffer_[kMinNumPendingConstants],
3936 &pending_64_bit_constants_[0]);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003937 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003938 ConstantPoolEntry entry(position, value);
3939 pending_64_bit_constants_[num_pending_64_bit_constants_++] = entry;
3940
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003941 // Make sure the constant pool is not emitted in place of the next
3942 // instruction for which we just recorded relocation info.
3943 BlockConstPoolFor(1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003944 return ConstantPoolEntry::REGULAR;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003945 }
3946}
3947
3948
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003949void Assembler::BlockConstPoolFor(int instructions) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003950 if (FLAG_enable_embedded_constant_pool) {
3951 // Should be a no-op if using an embedded constant pool.
3952 DCHECK(num_pending_32_bit_constants_ == 0);
3953 DCHECK(num_pending_64_bit_constants_ == 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003954 return;
3955 }
3956
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003957 int pc_limit = pc_offset() + instructions * kInstrSize;
3958 if (no_const_pool_before_ < pc_limit) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003959 // Max pool start (if we need a jump and an alignment).
3960#ifdef DEBUG
3961 int start = pc_limit + kInstrSize + 2 * kPointerSize;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003962 DCHECK((num_pending_32_bit_constants_ == 0) ||
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003963 (start - first_const_pool_32_use_ +
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003964 num_pending_64_bit_constants_ * kDoubleSize <
3965 kMaxDistToIntPool));
3966 DCHECK((num_pending_64_bit_constants_ == 0) ||
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003967 (start - first_const_pool_64_use_ < kMaxDistToFPPool));
3968#endif
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003969 no_const_pool_before_ = pc_limit;
Steve Blocka7e24c12009-10-30 11:49:00 +00003970 }
3971
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003972 if (next_buffer_check_ < no_const_pool_before_) {
3973 next_buffer_check_ = no_const_pool_before_;
3974 }
3975}
Steve Blocka7e24c12009-10-30 11:49:00 +00003976
Steve Blocka7e24c12009-10-30 11:49:00 +00003977
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003978void Assembler::CheckConstPool(bool force_emit, bool require_jump) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003979 if (FLAG_enable_embedded_constant_pool) {
3980 // Should be a no-op if using an embedded constant pool.
3981 DCHECK(num_pending_32_bit_constants_ == 0);
3982 DCHECK(num_pending_64_bit_constants_ == 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003983 return;
3984 }
3985
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003986 // Some short sequence of instruction mustn't be broken up by constant pool
3987 // emission, such sequences are protected by calls to BlockConstPoolFor and
3988 // BlockConstPoolScope.
3989 if (is_const_pool_blocked()) {
Andrei Popescu31002712010-02-23 13:46:05 +00003990 // Something is wrong if emission is forced and blocked at the same time.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003991 DCHECK(!force_emit);
Steve Blocka7e24c12009-10-30 11:49:00 +00003992 return;
3993 }
3994
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003995 // There is nothing to do if there are no pending constant pool entries.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003996 if ((num_pending_32_bit_constants_ == 0) &&
3997 (num_pending_64_bit_constants_ == 0)) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003998 // Calculate the offset of the next check.
3999 next_buffer_check_ = pc_offset() + kCheckPoolInterval;
4000 return;
4001 }
4002
Steve Blocka7e24c12009-10-30 11:49:00 +00004003 // Check that the code buffer is large enough before emitting the constant
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004004 // pool (include the jump over the pool and the constant pool marker and
4005 // the gap to the relocation information).
4006 int jump_instr = require_jump ? kInstrSize : 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004007 int size_up_to_marker = jump_instr + kInstrSize;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004008 int estimated_size_after_marker =
4009 num_pending_32_bit_constants_ * kPointerSize;
4010 bool has_int_values = (num_pending_32_bit_constants_ > 0);
4011 bool has_fp_values = (num_pending_64_bit_constants_ > 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004012 bool require_64_bit_align = false;
4013 if (has_fp_values) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004014 require_64_bit_align =
4015 !IsAligned(reinterpret_cast<intptr_t>(pc_ + size_up_to_marker),
4016 kDoubleAlignment);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004017 if (require_64_bit_align) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004018 estimated_size_after_marker += kInstrSize;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004019 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004020 estimated_size_after_marker += num_pending_64_bit_constants_ * kDoubleSize;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004021 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004022 int estimated_size = size_up_to_marker + estimated_size_after_marker;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004023
4024 // We emit a constant pool when:
4025 // * requested to do so by parameter force_emit (e.g. after each function).
4026 // * the distance from the first instruction accessing the constant pool to
4027 // any of the constant pool entries will exceed its limit the next
4028 // time the pool is checked. This is overly restrictive, but we don't emit
4029 // constant pool entries in-order so it's conservatively correct.
4030 // * the instruction doesn't require a jump after itself to jump over the
4031 // constant pool, and we're getting close to running out of range.
4032 if (!force_emit) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004033 DCHECK(has_fp_values || has_int_values);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004034 bool need_emit = false;
4035 if (has_fp_values) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004036 // The 64-bit constants are always emitted before the 32-bit constants, so
4037 // we can ignore the effect of the 32-bit constants on estimated_size.
4038 int dist64 = pc_offset() + estimated_size -
4039 num_pending_32_bit_constants_ * kPointerSize -
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004040 first_const_pool_64_use_;
4041 if ((dist64 >= kMaxDistToFPPool - kCheckPoolInterval) ||
4042 (!require_jump && (dist64 >= kMaxDistToFPPool / 2))) {
4043 need_emit = true;
4044 }
4045 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004046 if (has_int_values) {
4047 int dist32 = pc_offset() + estimated_size - first_const_pool_32_use_;
4048 if ((dist32 >= kMaxDistToIntPool - kCheckPoolInterval) ||
4049 (!require_jump && (dist32 >= kMaxDistToIntPool / 2))) {
4050 need_emit = true;
4051 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004052 }
4053 if (!need_emit) return;
4054 }
4055
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004056 // Deduplicate constants.
4057 int size_after_marker = estimated_size_after_marker;
4058 for (int i = 0; i < num_pending_64_bit_constants_; i++) {
4059 ConstantPoolEntry& entry = pending_64_bit_constants_[i];
4060 DCHECK(!entry.is_merged());
4061 for (int j = 0; j < i; j++) {
4062 if (entry.value64() == pending_64_bit_constants_[j].value64()) {
4063 DCHECK(!pending_64_bit_constants_[j].is_merged());
4064 entry.set_merged_index(j);
4065 size_after_marker -= kDoubleSize;
4066 break;
4067 }
4068 }
4069 }
4070
4071 for (int i = 0; i < num_pending_32_bit_constants_; i++) {
4072 ConstantPoolEntry& entry = pending_32_bit_constants_[i];
4073 DCHECK(!entry.is_merged());
4074 if (!entry.sharing_ok()) continue;
4075 for (int j = 0; j < i; j++) {
4076 if (entry.value() == pending_32_bit_constants_[j].value()) {
4077 DCHECK(!pending_32_bit_constants_[j].is_merged());
4078 entry.set_merged_index(j);
4079 size_after_marker -= kPointerSize;
4080 break;
4081 }
4082 }
4083 }
4084
4085 int size = size_up_to_marker + size_after_marker;
4086
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004087 int needed_space = size + kGap;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004088 while (buffer_space() <= needed_space) GrowBuffer();
Steve Blocka7e24c12009-10-30 11:49:00 +00004089
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004090 {
4091 // Block recursive calls to CheckConstPool.
4092 BlockConstPoolScope block_const_pool(this);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004093 RecordComment("[ Constant Pool");
4094 RecordConstPool(size);
Steve Blocka7e24c12009-10-30 11:49:00 +00004095
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004096 Label size_check;
4097 bind(&size_check);
4098
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004099 // Emit jump over constant pool if necessary.
4100 Label after_pool;
4101 if (require_jump) {
4102 b(&after_pool);
Steve Blocka7e24c12009-10-30 11:49:00 +00004103 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004104
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004105 // Put down constant pool marker "Undefined instruction".
4106 // The data size helps disassembly know what to print.
4107 emit(kConstantPoolMarker |
4108 EncodeConstantPoolLength(size_after_marker / kPointerSize));
Steve Blocka7e24c12009-10-30 11:49:00 +00004109
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004110 if (require_64_bit_align) {
4111 emit(kConstantPoolMarker);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004112 }
4113
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004114 // Emit 64-bit constant pool entries first: their range is smaller than
4115 // 32-bit entries.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004116 for (int i = 0; i < num_pending_64_bit_constants_; i++) {
4117 ConstantPoolEntry& entry = pending_64_bit_constants_[i];
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004118
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004119 Instr instr = instr_at(entry.position());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004120 // Instruction to patch must be 'vldr rd, [pc, #offset]' with offset == 0.
4121 DCHECK((IsVldrDPcImmediateOffset(instr) &&
4122 GetVldrDRegisterImmediateOffset(instr) == 0));
4123
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004124 int delta = pc_offset() - entry.position() - kPcLoadDelta;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004125 DCHECK(is_uint10(delta));
4126
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004127 if (entry.is_merged()) {
4128 ConstantPoolEntry& merged =
4129 pending_64_bit_constants_[entry.merged_index()];
4130 DCHECK(entry.value64() == merged.value64());
4131 Instr merged_instr = instr_at(merged.position());
4132 DCHECK(IsVldrDPcImmediateOffset(merged_instr));
4133 delta = GetVldrDRegisterImmediateOffset(merged_instr);
4134 delta += merged.position() - entry.position();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004135 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004136 instr_at_put(entry.position(),
4137 SetVldrDRegisterImmediateOffset(instr, delta));
4138 if (!entry.is_merged()) {
4139 DCHECK(IsAligned(reinterpret_cast<intptr_t>(pc_), kDoubleAlignment));
4140 dq(entry.value64());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004141 }
4142 }
4143
4144 // Emit 32-bit constant pool entries.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004145 for (int i = 0; i < num_pending_32_bit_constants_; i++) {
4146 ConstantPoolEntry& entry = pending_32_bit_constants_[i];
4147 Instr instr = instr_at(entry.position());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004148
4149 // 64-bit loads shouldn't get here.
4150 DCHECK(!IsVldrDPcImmediateOffset(instr));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004151 DCHECK(!IsMovW(instr));
4152 DCHECK(IsLdrPcImmediateOffset(instr) &&
4153 GetLdrRegisterImmediateOffset(instr) == 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004154
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004155 int delta = pc_offset() - entry.position() - kPcLoadDelta;
4156 DCHECK(is_uint12(delta));
4157 // 0 is the smallest delta:
4158 // ldr rd, [pc, #0]
4159 // constant pool marker
4160 // data
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004161
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004162 if (entry.is_merged()) {
4163 DCHECK(entry.sharing_ok());
4164 ConstantPoolEntry& merged =
4165 pending_32_bit_constants_[entry.merged_index()];
4166 DCHECK(entry.value() == merged.value());
4167 Instr merged_instr = instr_at(merged.position());
4168 DCHECK(IsLdrPcImmediateOffset(merged_instr));
4169 delta = GetLdrRegisterImmediateOffset(merged_instr);
4170 delta += merged.position() - entry.position();
4171 }
4172 instr_at_put(entry.position(),
4173 SetLdrRegisterImmediateOffset(instr, delta));
4174 if (!entry.is_merged()) {
4175 emit(entry.value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004176 }
4177 }
4178
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004179 num_pending_32_bit_constants_ = 0;
4180 num_pending_64_bit_constants_ = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004181 first_const_pool_32_use_ = -1;
4182 first_const_pool_64_use_ = -1;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004183
4184 RecordComment("]");
4185
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004186 DCHECK_EQ(size, SizeOfCodeGeneratedSince(&size_check));
4187
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004188 if (after_pool.is_linked()) {
4189 bind(&after_pool);
4190 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004191 }
4192
4193 // Since a constant pool was just emitted, move the check offset forward by
4194 // the standard interval.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004195 next_buffer_check_ = pc_offset() + kCheckPoolInterval;
Steve Blocka7e24c12009-10-30 11:49:00 +00004196}
4197
4198
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004199void Assembler::PatchConstantPoolAccessInstruction(
4200 int pc_offset, int offset, ConstantPoolEntry::Access access,
4201 ConstantPoolEntry::Type type) {
4202 DCHECK(FLAG_enable_embedded_constant_pool);
4203 Address pc = buffer_ + pc_offset;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004204
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004205 // Patch vldr/ldr instruction with correct offset.
4206 Instr instr = instr_at(pc);
4207 if (access == ConstantPoolEntry::OVERFLOWED) {
4208 if (CpuFeatures::IsSupported(ARMv7)) {
4209 // Instructions to patch must be 'movw rd, [#0]' and 'movt rd, [#0].
4210 Instr next_instr = instr_at(pc + kInstrSize);
4211 DCHECK((IsMovW(instr) && Instruction::ImmedMovwMovtValue(instr) == 0));
4212 DCHECK((IsMovT(next_instr) &&
4213 Instruction::ImmedMovwMovtValue(next_instr) == 0));
4214 instr_at_put(pc, PatchMovwImmediate(instr, offset & 0xffff));
4215 instr_at_put(pc + kInstrSize,
4216 PatchMovwImmediate(next_instr, offset >> 16));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004217 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004218 // Instructions to patch must be 'mov rd, [#0]' and 'orr rd, rd, [#0].
4219 Instr instr_2 = instr_at(pc + kInstrSize);
4220 Instr instr_3 = instr_at(pc + 2 * kInstrSize);
4221 Instr instr_4 = instr_at(pc + 3 * kInstrSize);
4222 DCHECK((IsMovImmed(instr) && Instruction::Immed8Value(instr) == 0));
4223 DCHECK((IsOrrImmed(instr_2) && Instruction::Immed8Value(instr_2) == 0) &&
4224 GetRn(instr_2).is(GetRd(instr_2)));
4225 DCHECK((IsOrrImmed(instr_3) && Instruction::Immed8Value(instr_3) == 0) &&
4226 GetRn(instr_3).is(GetRd(instr_3)));
4227 DCHECK((IsOrrImmed(instr_4) && Instruction::Immed8Value(instr_4) == 0) &&
4228 GetRn(instr_4).is(GetRd(instr_4)));
4229 instr_at_put(pc, PatchShiftImm(instr, (offset & kImm8Mask)));
4230 instr_at_put(pc + kInstrSize,
4231 PatchShiftImm(instr_2, (offset & (kImm8Mask << 8))));
4232 instr_at_put(pc + 2 * kInstrSize,
4233 PatchShiftImm(instr_3, (offset & (kImm8Mask << 16))));
4234 instr_at_put(pc + 3 * kInstrSize,
4235 PatchShiftImm(instr_4, (offset & (kImm8Mask << 24))));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004236 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004237 } else if (type == ConstantPoolEntry::DOUBLE) {
4238 // Instruction to patch must be 'vldr rd, [pp, #0]'.
4239 DCHECK((IsVldrDPpImmediateOffset(instr) &&
4240 GetVldrDRegisterImmediateOffset(instr) == 0));
4241 DCHECK(is_uint10(offset));
4242 instr_at_put(pc, SetVldrDRegisterImmediateOffset(instr, offset));
4243 } else {
4244 // Instruction to patch must be 'ldr rd, [pp, #0]'.
4245 DCHECK((IsLdrPpImmediateOffset(instr) &&
4246 GetLdrRegisterImmediateOffset(instr) == 0));
4247 DCHECK(is_uint12(offset));
4248 instr_at_put(pc, SetLdrRegisterImmediateOffset(instr, offset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004249 }
4250}
4251
4252
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004253} // namespace internal
4254} // namespace v8
Leon Clarkef7060e22010-06-03 12:02:55 +01004255
4256#endif // V8_TARGET_ARCH_ARM