blob: d2e3231bb8a297e11cbf1af16409a6246eb86aa1 [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();
85 cache_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)) {
140 cache_line_size_ = 32;
141 }
142
143 if (FLAG_enable_32dregs && cpu.has_vfp3_d32()) supported_ |= 1u << VFP32DREGS;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400144
145 if (cpu.implementer() == base::CPU::NVIDIA &&
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000146 cpu.variant() == base::CPU::NVIDIA_DENVER &&
147 cpu.part() <= base::CPU::NVIDIA_DENVER_V10) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400148 supported_ |= 1u << COHERENT_CACHE;
149 }
Steve Block6ded16b2010-05-10 14:33:55 +0100150#endif
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000151
152 DCHECK(!IsSupported(VFP3) || IsSupported(ARMv7));
153}
154
155
156void CpuFeatures::PrintTarget() {
157 const char* arm_arch = NULL;
158 const char* arm_target_type = "";
159 const char* arm_no_probe = "";
160 const char* arm_fpu = "";
161 const char* arm_thumb = "";
162 const char* arm_float_abi = NULL;
163
164#if !defined __arm__
165 arm_target_type = " simulator";
166#endif
167
168#if defined ARM_TEST_NO_FEATURE_PROBE
169 arm_no_probe = " noprobe";
170#endif
171
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000172#if defined CAN_USE_ARMV8_INSTRUCTIONS
173 arm_arch = "arm v8";
174#elif defined CAN_USE_ARMV7_INSTRUCTIONS
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000175 arm_arch = "arm v7";
176#else
177 arm_arch = "arm v6";
178#endif
179
180#if defined CAN_USE_NEON
181 arm_fpu = " neon";
182#elif defined CAN_USE_VFP3_INSTRUCTIONS
183# if defined CAN_USE_VFP32DREGS
184 arm_fpu = " vfp3";
185# else
186 arm_fpu = " vfp3-d16";
187# endif
188#else
189 arm_fpu = " vfp2";
190#endif
191
192#ifdef __arm__
193 arm_float_abi = base::OS::ArmUsingHardFloat() ? "hard" : "softfp";
194#elif USE_EABI_HARDFLOAT
195 arm_float_abi = "hard";
196#else
197 arm_float_abi = "softfp";
198#endif
199
200#if defined __arm__ && (defined __thumb__) || (defined __thumb2__)
201 arm_thumb = " thumb";
202#endif
203
204 printf("target%s%s %s%s%s %s\n",
205 arm_target_type, arm_no_probe, arm_arch, arm_fpu, arm_thumb,
206 arm_float_abi);
207}
208
209
210void CpuFeatures::PrintFeatures() {
211 printf(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000212 "ARMv8=%d ARMv7=%d VFP3=%d VFP32DREGS=%d NEON=%d SUDIV=%d MLS=%d"
213 "UNALIGNED_ACCESSES=%d MOVW_MOVT_IMMEDIATE_LOADS=%d COHERENT_CACHE=%d",
214 CpuFeatures::IsSupported(ARMv8),
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000215 CpuFeatures::IsSupported(ARMv7),
216 CpuFeatures::IsSupported(VFP3),
217 CpuFeatures::IsSupported(VFP32DREGS),
218 CpuFeatures::IsSupported(NEON),
219 CpuFeatures::IsSupported(SUDIV),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000220 CpuFeatures::IsSupported(MLS),
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000221 CpuFeatures::IsSupported(UNALIGNED_ACCESSES),
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400222 CpuFeatures::IsSupported(MOVW_MOVT_IMMEDIATE_LOADS),
223 CpuFeatures::IsSupported(COHERENT_CACHE));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000224#ifdef __arm__
225 bool eabi_hardfloat = base::OS::ArmUsingHardFloat();
226#elif USE_EABI_HARDFLOAT
227 bool eabi_hardfloat = true;
228#else
229 bool eabi_hardfloat = false;
230#endif
231 printf(" USE_EABI_HARDFLOAT=%d\n", eabi_hardfloat);
232}
233
234
235// -----------------------------------------------------------------------------
Steve Blocka7e24c12009-10-30 11:49:00 +0000236// Implementation of RelocInfo
237
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000238// static
Steve Blocka7e24c12009-10-30 11:49:00 +0000239const int RelocInfo::kApplyMask = 0;
240
241
Leon Clarkef7060e22010-06-03 12:02:55 +0100242bool RelocInfo::IsCodedSpecially() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000243 // The deserializer needs to know whether a pointer is specially coded.  Being
244 // specially coded on ARM means that it is a movw/movt instruction, or is an
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000245 // embedded constant pool entry.  These only occur if
246 // FLAG_enable_embedded_constant_pool is true.
247 return FLAG_enable_embedded_constant_pool;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000248}
249
250
251bool RelocInfo::IsInConstantPool() {
252 return Assembler::is_constant_pool_load(pc_);
Leon Clarkef7060e22010-06-03 12:02:55 +0100253}
254
255
Steve Blocka7e24c12009-10-30 11:49:00 +0000256// -----------------------------------------------------------------------------
257// Implementation of Operand and MemOperand
258// See assembler-arm-inl.h for inlined constructors
259
260Operand::Operand(Handle<Object> handle) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000261 AllowDeferredHandleDereference using_raw_address;
Steve Blocka7e24c12009-10-30 11:49:00 +0000262 rm_ = no_reg;
263 // Verify all Objects referred by code are NOT in new space.
264 Object* obj = *handle;
Steve Blocka7e24c12009-10-30 11:49:00 +0000265 if (obj->IsHeapObject()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000266 DCHECK(!HeapObject::cast(obj)->GetHeap()->InNewSpace(obj));
Steve Blocka7e24c12009-10-30 11:49:00 +0000267 imm32_ = reinterpret_cast<intptr_t>(handle.location());
268 rmode_ = RelocInfo::EMBEDDED_OBJECT;
269 } else {
270 // no relocation needed
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000271 imm32_ = reinterpret_cast<intptr_t>(obj);
272 rmode_ = RelocInfo::NONE32;
Steve Blocka7e24c12009-10-30 11:49:00 +0000273 }
274}
275
276
277Operand::Operand(Register rm, ShiftOp shift_op, int shift_imm) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000278 DCHECK(is_uint5(shift_imm));
279
Steve Blocka7e24c12009-10-30 11:49:00 +0000280 rm_ = rm;
281 rs_ = no_reg;
282 shift_op_ = shift_op;
283 shift_imm_ = shift_imm & 31;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000284
285 if ((shift_op == ROR) && (shift_imm == 0)) {
286 // ROR #0 is functionally equivalent to LSL #0 and this allow us to encode
287 // RRX as ROR #0 (See below).
288 shift_op = LSL;
289 } else if (shift_op == RRX) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000290 // encoded as ROR with shift_imm == 0
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000291 DCHECK(shift_imm == 0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000292 shift_op_ = ROR;
293 shift_imm_ = 0;
294 }
295}
296
297
298Operand::Operand(Register rm, ShiftOp shift_op, Register rs) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000299 DCHECK(shift_op != RRX);
Steve Blocka7e24c12009-10-30 11:49:00 +0000300 rm_ = rm;
301 rs_ = no_reg;
302 shift_op_ = shift_op;
303 rs_ = rs;
304}
305
306
307MemOperand::MemOperand(Register rn, int32_t offset, AddrMode am) {
308 rn_ = rn;
309 rm_ = no_reg;
310 offset_ = offset;
311 am_ = am;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000312
313 // Accesses below the stack pointer are not safe, and are prohibited by the
314 // ABI. We can check obvious violations here.
315 if (rn.is(sp)) {
316 if (am == Offset) DCHECK_LE(0, offset);
317 if (am == NegOffset) DCHECK_GE(0, offset);
318 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000319}
320
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000321
Steve Blocka7e24c12009-10-30 11:49:00 +0000322MemOperand::MemOperand(Register rn, Register rm, AddrMode am) {
323 rn_ = rn;
324 rm_ = rm;
325 shift_op_ = LSL;
326 shift_imm_ = 0;
327 am_ = am;
328}
329
330
331MemOperand::MemOperand(Register rn, Register rm,
332 ShiftOp shift_op, int shift_imm, AddrMode am) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000333 DCHECK(is_uint5(shift_imm));
Steve Blocka7e24c12009-10-30 11:49:00 +0000334 rn_ = rn;
335 rm_ = rm;
336 shift_op_ = shift_op;
337 shift_imm_ = shift_imm & 31;
338 am_ = am;
339}
340
341
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000342NeonMemOperand::NeonMemOperand(Register rn, AddrMode am, int align) {
343 DCHECK((am == Offset) || (am == PostIndex));
344 rn_ = rn;
345 rm_ = (am == Offset) ? pc : sp;
346 SetAlignment(align);
347}
348
349
350NeonMemOperand::NeonMemOperand(Register rn, Register rm, int align) {
351 rn_ = rn;
352 rm_ = rm;
353 SetAlignment(align);
354}
355
356
357void NeonMemOperand::SetAlignment(int align) {
358 switch (align) {
359 case 0:
360 align_ = 0;
361 break;
362 case 64:
363 align_ = 1;
364 break;
365 case 128:
366 align_ = 2;
367 break;
368 case 256:
369 align_ = 3;
370 break;
371 default:
372 UNREACHABLE();
373 align_ = 0;
374 break;
375 }
376}
377
378
379NeonListOperand::NeonListOperand(DoubleRegister base, int registers_count) {
380 base_ = base;
381 switch (registers_count) {
382 case 1:
383 type_ = nlt_1;
384 break;
385 case 2:
386 type_ = nlt_2;
387 break;
388 case 3:
389 type_ = nlt_3;
390 break;
391 case 4:
392 type_ = nlt_4;
393 break;
394 default:
395 UNREACHABLE();
396 type_ = nlt_1;
397 break;
398 }
399}
400
401
Steve Blocka7e24c12009-10-30 11:49:00 +0000402// -----------------------------------------------------------------------------
Steve Block1e0659c2011-05-24 12:43:12 +0100403// Specific instructions, constants, and masks.
Steve Blocka7e24c12009-10-30 11:49:00 +0000404
Steve Blocka7e24c12009-10-30 11:49:00 +0000405// str(r, MemOperand(sp, 4, NegPreIndex), al) instruction (aka push(r))
406// register r is not encoded.
Steve Block1e0659c2011-05-24 12:43:12 +0100407const Instr kPushRegPattern =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000408 al | B26 | 4 | NegPreIndex | Register::kCode_sp * B16;
Steve Blocka7e24c12009-10-30 11:49:00 +0000409// ldr(r, MemOperand(sp, 4, PostIndex), al) instruction (aka pop(r))
410// register r is not encoded.
Steve Block1e0659c2011-05-24 12:43:12 +0100411const Instr kPopRegPattern =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000412 al | B26 | L | 4 | PostIndex | Register::kCode_sp * B16;
Steve Block6ded16b2010-05-10 14:33:55 +0100413// ldr rd, [pc, #offset]
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000414const Instr kLdrPCImmedMask = 15 * B24 | 7 * B20 | 15 * B16;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000415const Instr kLdrPCImmedPattern = 5 * B24 | L | Register::kCode_pc * B16;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000416// ldr rd, [pp, #offset]
417const Instr kLdrPpImmedMask = 15 * B24 | 7 * B20 | 15 * B16;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000418const Instr kLdrPpImmedPattern = 5 * B24 | L | Register::kCode_r8 * B16;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000419// ldr rd, [pp, rn]
420const Instr kLdrPpRegMask = 15 * B24 | 7 * B20 | 15 * B16;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000421const Instr kLdrPpRegPattern = 7 * B24 | L | Register::kCode_r8 * B16;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000422// vldr dd, [pc, #offset]
423const Instr kVldrDPCMask = 15 * B24 | 3 * B20 | 15 * B16 | 15 * B8;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000424const Instr kVldrDPCPattern = 13 * B24 | L | Register::kCode_pc * B16 | 11 * B8;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000425// vldr dd, [pp, #offset]
426const Instr kVldrDPpMask = 15 * B24 | 3 * B20 | 15 * B16 | 15 * B8;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000427const Instr kVldrDPpPattern = 13 * B24 | L | Register::kCode_r8 * B16 | 11 * B8;
Steve Block6ded16b2010-05-10 14:33:55 +0100428// blxcc rm
429const Instr kBlxRegMask =
430 15 * B24 | 15 * B20 | 15 * B16 | 15 * B12 | 15 * B8 | 15 * B4;
431const Instr kBlxRegPattern =
Steve Block1e0659c2011-05-24 12:43:12 +0100432 B24 | B21 | 15 * B16 | 15 * B12 | 15 * B8 | BLX;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100433const Instr kBlxIp = al | kBlxRegPattern | ip.code();
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100434const Instr kMovMvnMask = 0x6d * B21 | 0xf * B16;
435const Instr kMovMvnPattern = 0xd * B21;
436const Instr kMovMvnFlip = B22;
437const Instr kMovLeaveCCMask = 0xdff * B16;
438const Instr kMovLeaveCCPattern = 0x1a0 * B16;
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100439const Instr kMovwPattern = 0x30 * B20;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000440const Instr kMovtPattern = 0x34 * B20;
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100441const Instr kMovwLeaveCCFlip = 0x5 * B21;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000442const Instr kMovImmedMask = 0x7f * B21;
443const Instr kMovImmedPattern = 0x1d * B21;
444const Instr kOrrImmedMask = 0x7f * B21;
445const Instr kOrrImmedPattern = 0x1c * B21;
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100446const Instr kCmpCmnMask = 0xdd * B20 | 0xf * B12;
447const Instr kCmpCmnPattern = 0x15 * B20;
448const Instr kCmpCmnFlip = B21;
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100449const Instr kAddSubFlip = 0x6 * B21;
450const Instr kAndBicFlip = 0xe * B21;
451
Leon Clarkef7060e22010-06-03 12:02:55 +0100452// A mask for the Rd register for push, pop, ldr, str instructions.
Steve Block1e0659c2011-05-24 12:43:12 +0100453const Instr kLdrRegFpOffsetPattern =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000454 al | B26 | L | Offset | Register::kCode_fp * B16;
Steve Block1e0659c2011-05-24 12:43:12 +0100455const Instr kStrRegFpOffsetPattern =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000456 al | B26 | Offset | Register::kCode_fp * B16;
Steve Block1e0659c2011-05-24 12:43:12 +0100457const Instr kLdrRegFpNegOffsetPattern =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000458 al | B26 | L | NegOffset | Register::kCode_fp * B16;
Steve Block1e0659c2011-05-24 12:43:12 +0100459const Instr kStrRegFpNegOffsetPattern =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000460 al | B26 | NegOffset | Register::kCode_fp * B16;
Steve Block1e0659c2011-05-24 12:43:12 +0100461const Instr kLdrStrInstrTypeMask = 0xffff0000;
Steve Block1e0659c2011-05-24 12:43:12 +0100462
Steve Blocka7e24c12009-10-30 11:49:00 +0000463
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000464Assembler::Assembler(Isolate* isolate, void* buffer, int buffer_size)
465 : AssemblerBase(isolate, buffer, buffer_size),
466 recorded_ast_id_(TypeFeedbackId::None()),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000467 pending_32_bit_constants_(&pending_32_bit_constants_buffer_[0]),
468 pending_64_bit_constants_(&pending_64_bit_constants_buffer_[0]),
469 constant_pool_builder_(kLdrMaxReachBits, kVldrMaxReachBits),
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000470 positions_recorder_(this) {
471 reloc_info_writer.Reposition(buffer_ + buffer_size_, pc_);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000472 num_pending_32_bit_constants_ = 0;
473 num_pending_64_bit_constants_ = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +0000474 next_buffer_check_ = 0;
Steve Block6ded16b2010-05-10 14:33:55 +0100475 const_pool_blocked_nesting_ = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +0000476 no_const_pool_before_ = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000477 first_const_pool_32_use_ = -1;
478 first_const_pool_64_use_ = -1;
Steve Blocka7e24c12009-10-30 11:49:00 +0000479 last_bound_pos_ = 0;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000480 ClearRecordedAstId();
Steve Blocka7e24c12009-10-30 11:49:00 +0000481}
482
483
484Assembler::~Assembler() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000485 DCHECK(const_pool_blocked_nesting_ == 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000486 if (pending_32_bit_constants_ != &pending_32_bit_constants_buffer_[0]) {
487 delete[] pending_32_bit_constants_;
488 }
489 if (pending_64_bit_constants_ != &pending_64_bit_constants_buffer_[0]) {
490 delete[] pending_64_bit_constants_;
491 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000492}
493
494
495void Assembler::GetCode(CodeDesc* desc) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000496 reloc_info_writer.Finish();
497
498 // Emit constant pool if necessary.
499 int constant_pool_offset = 0;
500 if (FLAG_enable_embedded_constant_pool) {
501 constant_pool_offset = EmitEmbeddedConstantPool();
502 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000503 CheckConstPool(true, false);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000504 DCHECK(num_pending_32_bit_constants_ == 0);
505 DCHECK(num_pending_64_bit_constants_ == 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000506 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100507 // Set up code descriptor.
Steve Blocka7e24c12009-10-30 11:49:00 +0000508 desc->buffer = buffer_;
509 desc->buffer_size = buffer_size_;
510 desc->instr_size = pc_offset();
511 desc->reloc_size = (buffer_ + buffer_size_) - reloc_info_writer.pos();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000512 desc->constant_pool_size =
513 (constant_pool_offset ? desc->instr_size - constant_pool_offset : 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000514 desc->origin = this;
Steve Blocka7e24c12009-10-30 11:49:00 +0000515}
516
517
518void Assembler::Align(int m) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000519 DCHECK(m >= 4 && base::bits::IsPowerOfTwo32(m));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000520 DCHECK((pc_offset() & (kInstrSize - 1)) == 0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000521 while ((pc_offset() & (m - 1)) != 0) {
522 nop();
523 }
524}
525
526
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100527void Assembler::CodeTargetAlign() {
528 // Preferred alignment of jump targets on some ARM chips.
529 Align(8);
530}
531
532
Steve Block1e0659c2011-05-24 12:43:12 +0100533Condition Assembler::GetCondition(Instr instr) {
534 return Instruction::ConditionField(instr);
535}
536
537
Steve Block6ded16b2010-05-10 14:33:55 +0100538bool Assembler::IsBranch(Instr instr) {
539 return (instr & (B27 | B25)) == (B27 | B25);
540}
541
542
543int Assembler::GetBranchOffset(Instr instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000544 DCHECK(IsBranch(instr));
Steve Block6ded16b2010-05-10 14:33:55 +0100545 // Take the jump offset in the lower 24 bits, sign extend it and multiply it
546 // with 4 to get the offset in bytes.
Steve Block1e0659c2011-05-24 12:43:12 +0100547 return ((instr & kImm24Mask) << 8) >> 6;
Steve Block6ded16b2010-05-10 14:33:55 +0100548}
549
550
551bool Assembler::IsLdrRegisterImmediate(Instr instr) {
552 return (instr & (B27 | B26 | B25 | B22 | B20)) == (B26 | B20);
553}
554
555
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000556bool Assembler::IsVldrDRegisterImmediate(Instr instr) {
557 return (instr & (15 * B24 | 3 * B20 | 15 * B8)) == (13 * B24 | B20 | 11 * B8);
558}
559
560
Steve Block6ded16b2010-05-10 14:33:55 +0100561int Assembler::GetLdrRegisterImmediateOffset(Instr instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000562 DCHECK(IsLdrRegisterImmediate(instr));
Steve Block6ded16b2010-05-10 14:33:55 +0100563 bool positive = (instr & B23) == B23;
Steve Block1e0659c2011-05-24 12:43:12 +0100564 int offset = instr & kOff12Mask; // Zero extended offset.
Steve Block6ded16b2010-05-10 14:33:55 +0100565 return positive ? offset : -offset;
566}
567
568
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000569int Assembler::GetVldrDRegisterImmediateOffset(Instr instr) {
570 DCHECK(IsVldrDRegisterImmediate(instr));
571 bool positive = (instr & B23) == B23;
572 int offset = instr & kOff8Mask; // Zero extended offset.
573 offset <<= 2;
574 return positive ? offset : -offset;
575}
576
577
Steve Block6ded16b2010-05-10 14:33:55 +0100578Instr Assembler::SetLdrRegisterImmediateOffset(Instr instr, int offset) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000579 DCHECK(IsLdrRegisterImmediate(instr));
Steve Block6ded16b2010-05-10 14:33:55 +0100580 bool positive = offset >= 0;
581 if (!positive) offset = -offset;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000582 DCHECK(is_uint12(offset));
Steve Block6ded16b2010-05-10 14:33:55 +0100583 // Set bit indicating whether the offset should be added.
584 instr = (instr & ~B23) | (positive ? B23 : 0);
585 // Set the actual offset.
Steve Block1e0659c2011-05-24 12:43:12 +0100586 return (instr & ~kOff12Mask) | offset;
Steve Block6ded16b2010-05-10 14:33:55 +0100587}
588
589
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000590Instr Assembler::SetVldrDRegisterImmediateOffset(Instr instr, int offset) {
591 DCHECK(IsVldrDRegisterImmediate(instr));
592 DCHECK((offset & ~3) == offset); // Must be 64-bit aligned.
593 bool positive = offset >= 0;
594 if (!positive) offset = -offset;
595 DCHECK(is_uint10(offset));
596 // Set bit indicating whether the offset should be added.
597 instr = (instr & ~B23) | (positive ? B23 : 0);
598 // Set the actual offset. Its bottom 2 bits are zero.
599 return (instr & ~kOff8Mask) | (offset >> 2);
600}
601
602
Kristian Monsen50ef84f2010-07-29 15:18:00 +0100603bool Assembler::IsStrRegisterImmediate(Instr instr) {
604 return (instr & (B27 | B26 | B25 | B22 | B20)) == B26;
605}
606
607
608Instr Assembler::SetStrRegisterImmediateOffset(Instr instr, int offset) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000609 DCHECK(IsStrRegisterImmediate(instr));
Kristian Monsen50ef84f2010-07-29 15:18:00 +0100610 bool positive = offset >= 0;
611 if (!positive) offset = -offset;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000612 DCHECK(is_uint12(offset));
Kristian Monsen50ef84f2010-07-29 15:18:00 +0100613 // Set bit indicating whether the offset should be added.
614 instr = (instr & ~B23) | (positive ? B23 : 0);
615 // Set the actual offset.
Steve Block1e0659c2011-05-24 12:43:12 +0100616 return (instr & ~kOff12Mask) | offset;
Kristian Monsen50ef84f2010-07-29 15:18:00 +0100617}
618
619
620bool Assembler::IsAddRegisterImmediate(Instr instr) {
621 return (instr & (B27 | B26 | B25 | B24 | B23 | B22 | B21)) == (B25 | B23);
622}
623
624
625Instr Assembler::SetAddRegisterImmediateOffset(Instr instr, int offset) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000626 DCHECK(IsAddRegisterImmediate(instr));
627 DCHECK(offset >= 0);
628 DCHECK(is_uint12(offset));
Kristian Monsen50ef84f2010-07-29 15:18:00 +0100629 // Set the offset.
Steve Block1e0659c2011-05-24 12:43:12 +0100630 return (instr & ~kOff12Mask) | offset;
Kristian Monsen50ef84f2010-07-29 15:18:00 +0100631}
632
633
Leon Clarkef7060e22010-06-03 12:02:55 +0100634Register Assembler::GetRd(Instr instr) {
635 Register reg;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000636 reg.reg_code = Instruction::RdValue(instr);
Steve Block1e0659c2011-05-24 12:43:12 +0100637 return reg;
638}
639
640
641Register Assembler::GetRn(Instr instr) {
642 Register reg;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000643 reg.reg_code = Instruction::RnValue(instr);
Steve Block1e0659c2011-05-24 12:43:12 +0100644 return reg;
645}
646
647
648Register Assembler::GetRm(Instr instr) {
649 Register reg;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000650 reg.reg_code = Instruction::RmValue(instr);
Leon Clarkef7060e22010-06-03 12:02:55 +0100651 return reg;
652}
653
654
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000655Instr Assembler::GetConsantPoolLoadPattern() {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000656 if (FLAG_enable_embedded_constant_pool) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000657 return kLdrPpImmedPattern;
658 } else {
659 return kLdrPCImmedPattern;
660 }
661}
662
663
664Instr Assembler::GetConsantPoolLoadMask() {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000665 if (FLAG_enable_embedded_constant_pool) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000666 return kLdrPpImmedMask;
667 } else {
668 return kLdrPCImmedMask;
669 }
670}
671
672
Leon Clarkef7060e22010-06-03 12:02:55 +0100673bool Assembler::IsPush(Instr instr) {
674 return ((instr & ~kRdMask) == kPushRegPattern);
675}
676
677
678bool Assembler::IsPop(Instr instr) {
679 return ((instr & ~kRdMask) == kPopRegPattern);
680}
681
682
683bool Assembler::IsStrRegFpOffset(Instr instr) {
684 return ((instr & kLdrStrInstrTypeMask) == kStrRegFpOffsetPattern);
685}
686
687
688bool Assembler::IsLdrRegFpOffset(Instr instr) {
689 return ((instr & kLdrStrInstrTypeMask) == kLdrRegFpOffsetPattern);
690}
691
692
693bool Assembler::IsStrRegFpNegOffset(Instr instr) {
694 return ((instr & kLdrStrInstrTypeMask) == kStrRegFpNegOffsetPattern);
695}
696
697
698bool Assembler::IsLdrRegFpNegOffset(Instr instr) {
699 return ((instr & kLdrStrInstrTypeMask) == kLdrRegFpNegOffsetPattern);
700}
701
702
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800703bool Assembler::IsLdrPcImmediateOffset(Instr instr) {
704 // Check the instruction is indeed a
705 // ldr<cond> <Rd>, [pc +/- offset_12].
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000706 return (instr & kLdrPCImmedMask) == kLdrPCImmedPattern;
707}
708
709
710bool Assembler::IsLdrPpImmediateOffset(Instr instr) {
711 // Check the instruction is indeed a
712 // ldr<cond> <Rd>, [pp +/- offset_12].
713 return (instr & kLdrPpImmedMask) == kLdrPpImmedPattern;
714}
715
716
717bool Assembler::IsLdrPpRegOffset(Instr instr) {
718 // Check the instruction is indeed a
719 // ldr<cond> <Rd>, [pp, +/- <Rm>].
720 return (instr & kLdrPpRegMask) == kLdrPpRegPattern;
721}
722
723
724Instr Assembler::GetLdrPpRegOffsetPattern() { return kLdrPpRegPattern; }
725
726
727bool Assembler::IsVldrDPcImmediateOffset(Instr instr) {
728 // Check the instruction is indeed a
729 // vldr<cond> <Dd>, [pc +/- offset_10].
730 return (instr & kVldrDPCMask) == kVldrDPCPattern;
731}
732
733
734bool Assembler::IsVldrDPpImmediateOffset(Instr instr) {
735 // Check the instruction is indeed a
736 // vldr<cond> <Dd>, [pp +/- offset_10].
737 return (instr & kVldrDPpMask) == kVldrDPpPattern;
738}
739
740
741bool Assembler::IsBlxReg(Instr instr) {
742 // Check the instruction is indeed a
743 // blxcc <Rm>
744 return (instr & kBlxRegMask) == kBlxRegPattern;
745}
746
747
748bool Assembler::IsBlxIp(Instr instr) {
749 // Check the instruction is indeed a
750 // blx ip
751 return instr == kBlxIp;
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800752}
753
754
Steve Block1e0659c2011-05-24 12:43:12 +0100755bool Assembler::IsTstImmediate(Instr instr) {
756 return (instr & (B27 | B26 | I | kOpCodeMask | S | kRdMask)) ==
757 (I | TST | S);
758}
759
760
761bool Assembler::IsCmpRegister(Instr instr) {
762 return (instr & (B27 | B26 | I | kOpCodeMask | S | kRdMask | B4)) ==
763 (CMP | S);
764}
765
766
767bool Assembler::IsCmpImmediate(Instr instr) {
768 return (instr & (B27 | B26 | I | kOpCodeMask | S | kRdMask)) ==
769 (I | CMP | S);
770}
771
772
773Register Assembler::GetCmpImmediateRegister(Instr instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000774 DCHECK(IsCmpImmediate(instr));
Steve Block1e0659c2011-05-24 12:43:12 +0100775 return GetRn(instr);
776}
777
778
779int Assembler::GetCmpImmediateRawImmediate(Instr instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000780 DCHECK(IsCmpImmediate(instr));
Steve Block1e0659c2011-05-24 12:43:12 +0100781 return instr & kOff12Mask;
782}
783
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000784
Steve Blocka7e24c12009-10-30 11:49:00 +0000785// Labels refer to positions in the (to be) generated code.
786// There are bound, linked, and unused labels.
787//
788// Bound labels refer to known positions in the already
789// generated code. pos() is the position the label refers to.
790//
791// Linked labels refer to unknown positions in the code
792// to be generated; pos() is the position of the last
793// instruction using the label.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000794//
795// The linked labels form a link chain by making the branch offset
796// in the instruction steam to point to the previous branch
797// instruction using the same label.
798//
799// The link chain is terminated by a branch offset pointing to the
800// same position.
Steve Blocka7e24c12009-10-30 11:49:00 +0000801
802
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000803int Assembler::target_at(int pos) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000804 Instr instr = instr_at(pos);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000805 if (is_uint24(instr)) {
806 // Emitted link to a label, not part of a branch.
807 return instr;
Steve Blocka7e24c12009-10-30 11:49:00 +0000808 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000809 DCHECK_EQ(5 * B25, instr & 7 * B25); // b, bl, or blx imm24
Steve Block1e0659c2011-05-24 12:43:12 +0100810 int imm26 = ((instr & kImm24Mask) << 8) >> 6;
811 if ((Instruction::ConditionField(instr) == kSpecialCondition) &&
812 ((instr & B24) != 0)) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000813 // blx uses bit 24 to encode bit 2 of imm26
814 imm26 += 2;
Steve Block6ded16b2010-05-10 14:33:55 +0100815 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000816 return pos + kPcLoadDelta + imm26;
817}
818
819
820void Assembler::target_at_put(int pos, int target_pos) {
821 Instr instr = instr_at(pos);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000822 if (is_uint24(instr)) {
823 DCHECK(target_pos == pos || target_pos >= 0);
824 // Emitted link to a label, not part of a branch.
825 // Load the position of the label relative to the generated code object
826 // pointer in a register.
827
828 // Here are the instructions we need to emit:
829 // For ARMv7: target24 => target16_1:target16_0
830 // movw dst, #target16_0
831 // movt dst, #target16_1
832 // For ARMv6: target24 => target8_2:target8_1:target8_0
833 // mov dst, #target8_0
834 // orr dst, dst, #target8_1 << 8
835 // orr dst, dst, #target8_2 << 16
836
837 // We extract the destination register from the emitted nop instruction.
838 Register dst = Register::from_code(
839 Instruction::RmValue(instr_at(pos + kInstrSize)));
840 DCHECK(IsNop(instr_at(pos + kInstrSize), dst.code()));
841 uint32_t target24 = target_pos + (Code::kHeaderSize - kHeapObjectTag);
842 DCHECK(is_uint24(target24));
843 if (is_uint8(target24)) {
844 // If the target fits in a byte then only patch with a mov
845 // instruction.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000846 CodePatcher patcher(isolate(), reinterpret_cast<byte*>(buffer_ + pos), 1,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000847 CodePatcher::DONT_FLUSH);
848 patcher.masm()->mov(dst, Operand(target24));
849 } else {
850 uint16_t target16_0 = target24 & kImm16Mask;
851 uint16_t target16_1 = target24 >> 16;
852 if (CpuFeatures::IsSupported(ARMv7)) {
853 // Patch with movw/movt.
854 if (target16_1 == 0) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000855 CodePatcher patcher(isolate(), reinterpret_cast<byte*>(buffer_ + pos),
856 1, CodePatcher::DONT_FLUSH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000857 patcher.masm()->movw(dst, target16_0);
858 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000859 CodePatcher patcher(isolate(), reinterpret_cast<byte*>(buffer_ + pos),
860 2, CodePatcher::DONT_FLUSH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000861 patcher.masm()->movw(dst, target16_0);
862 patcher.masm()->movt(dst, target16_1);
863 }
864 } else {
865 // Patch with a sequence of mov/orr/orr instructions.
866 uint8_t target8_0 = target16_0 & kImm8Mask;
867 uint8_t target8_1 = target16_0 >> 8;
868 uint8_t target8_2 = target16_1 & kImm8Mask;
869 if (target8_2 == 0) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000870 CodePatcher patcher(isolate(), reinterpret_cast<byte*>(buffer_ + pos),
871 2, CodePatcher::DONT_FLUSH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000872 patcher.masm()->mov(dst, Operand(target8_0));
873 patcher.masm()->orr(dst, dst, Operand(target8_1 << 8));
874 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000875 CodePatcher patcher(isolate(), reinterpret_cast<byte*>(buffer_ + pos),
876 3, CodePatcher::DONT_FLUSH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000877 patcher.masm()->mov(dst, Operand(target8_0));
878 patcher.masm()->orr(dst, dst, Operand(target8_1 << 8));
879 patcher.masm()->orr(dst, dst, Operand(target8_2 << 16));
880 }
881 }
882 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000883 return;
884 }
885 int imm26 = target_pos - (pos + kPcLoadDelta);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000886 DCHECK_EQ(5 * B25, instr & 7 * B25); // b, bl, or blx imm24
Steve Block1e0659c2011-05-24 12:43:12 +0100887 if (Instruction::ConditionField(instr) == kSpecialCondition) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000888 // blx uses bit 24 to encode bit 2 of imm26
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000889 DCHECK_EQ(0, imm26 & 1);
890 instr = (instr & ~(B24 | kImm24Mask)) | ((imm26 & 2) >> 1) * B24;
Steve Blocka7e24c12009-10-30 11:49:00 +0000891 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000892 DCHECK_EQ(0, imm26 & 3);
Steve Block1e0659c2011-05-24 12:43:12 +0100893 instr &= ~kImm24Mask;
Steve Blocka7e24c12009-10-30 11:49:00 +0000894 }
895 int imm24 = imm26 >> 2;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000896 DCHECK(is_int24(imm24));
Steve Block1e0659c2011-05-24 12:43:12 +0100897 instr_at_put(pos, instr | (imm24 & kImm24Mask));
Steve Blocka7e24c12009-10-30 11:49:00 +0000898}
899
900
901void Assembler::print(Label* L) {
902 if (L->is_unused()) {
903 PrintF("unused label\n");
904 } else if (L->is_bound()) {
905 PrintF("bound label to %d\n", L->pos());
906 } else if (L->is_linked()) {
907 Label l = *L;
908 PrintF("unbound label");
909 while (l.is_linked()) {
910 PrintF("@ %d ", l.pos());
911 Instr instr = instr_at(l.pos());
Steve Block1e0659c2011-05-24 12:43:12 +0100912 if ((instr & ~kImm24Mask) == 0) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000913 PrintF("value\n");
914 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000915 DCHECK((instr & 7*B25) == 5*B25); // b, bl, or blx
Steve Block1e0659c2011-05-24 12:43:12 +0100916 Condition cond = Instruction::ConditionField(instr);
Steve Blocka7e24c12009-10-30 11:49:00 +0000917 const char* b;
918 const char* c;
Steve Block1e0659c2011-05-24 12:43:12 +0100919 if (cond == kSpecialCondition) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000920 b = "blx";
921 c = "";
922 } else {
923 if ((instr & B24) != 0)
924 b = "bl";
925 else
926 b = "b";
927
928 switch (cond) {
929 case eq: c = "eq"; break;
930 case ne: c = "ne"; break;
931 case hs: c = "hs"; break;
932 case lo: c = "lo"; break;
933 case mi: c = "mi"; break;
934 case pl: c = "pl"; break;
935 case vs: c = "vs"; break;
936 case vc: c = "vc"; break;
937 case hi: c = "hi"; break;
938 case ls: c = "ls"; break;
939 case ge: c = "ge"; break;
940 case lt: c = "lt"; break;
941 case gt: c = "gt"; break;
942 case le: c = "le"; break;
943 case al: c = ""; break;
944 default:
945 c = "";
946 UNREACHABLE();
947 }
948 }
949 PrintF("%s%s\n", b, c);
950 }
951 next(&l);
952 }
953 } else {
954 PrintF("label in inconsistent state (pos = %d)\n", L->pos_);
955 }
956}
957
958
959void Assembler::bind_to(Label* L, int pos) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000960 DCHECK(0 <= pos && pos <= pc_offset()); // must have a valid binding position
Steve Blocka7e24c12009-10-30 11:49:00 +0000961 while (L->is_linked()) {
962 int fixup_pos = L->pos();
963 next(L); // call next before overwriting link with target at fixup_pos
964 target_at_put(fixup_pos, pos);
965 }
966 L->bind_to(pos);
967
968 // Keep track of the last bound label so we don't eliminate any instructions
969 // before a bound label.
970 if (pos > last_bound_pos_)
971 last_bound_pos_ = pos;
972}
973
974
Steve Blocka7e24c12009-10-30 11:49:00 +0000975void Assembler::bind(Label* L) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000976 DCHECK(!L->is_bound()); // label can only be bound once
Steve Blocka7e24c12009-10-30 11:49:00 +0000977 bind_to(L, pc_offset());
978}
979
980
981void Assembler::next(Label* L) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000982 DCHECK(L->is_linked());
Steve Blocka7e24c12009-10-30 11:49:00 +0000983 int link = target_at(L->pos());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000984 if (link == L->pos()) {
985 // Branch target points to the same instuction. This is the end of the link
986 // chain.
Steve Blocka7e24c12009-10-30 11:49:00 +0000987 L->Unuse();
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000988 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000989 DCHECK(link >= 0);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000990 L->link_to(link);
Steve Blocka7e24c12009-10-30 11:49:00 +0000991 }
992}
993
994
Andrei Popescu31002712010-02-23 13:46:05 +0000995// Low-level code emission routines depending on the addressing mode.
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100996// If this returns true then you have to use the rotate_imm and immed_8
997// that it returns, because it may have already changed the instruction
998// to match them!
Steve Blocka7e24c12009-10-30 11:49:00 +0000999static bool fits_shifter(uint32_t imm32,
1000 uint32_t* rotate_imm,
1001 uint32_t* immed_8,
1002 Instr* instr) {
Andrei Popescu31002712010-02-23 13:46:05 +00001003 // imm32 must be unsigned.
Steve Blocka7e24c12009-10-30 11:49:00 +00001004 for (int rot = 0; rot < 16; rot++) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001005 uint32_t imm8 = base::bits::RotateLeft32(imm32, 2 * rot);
Steve Blocka7e24c12009-10-30 11:49:00 +00001006 if ((imm8 <= 0xff)) {
1007 *rotate_imm = rot;
1008 *immed_8 = imm8;
1009 return true;
1010 }
1011 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001012 // If the opcode is one with a complementary version and the complementary
1013 // immediate fits, change the opcode.
1014 if (instr != NULL) {
1015 if ((*instr & kMovMvnMask) == kMovMvnPattern) {
1016 if (fits_shifter(~imm32, rotate_imm, immed_8, NULL)) {
1017 *instr ^= kMovMvnFlip;
1018 return true;
1019 } else if ((*instr & kMovLeaveCCMask) == kMovLeaveCCPattern) {
Ben Murdoch8b112d22011-06-08 16:22:53 +01001020 if (CpuFeatures::IsSupported(ARMv7)) {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001021 if (imm32 < 0x10000) {
1022 *instr ^= kMovwLeaveCCFlip;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001023 *instr |= Assembler::EncodeMovwImmediate(imm32);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001024 *rotate_imm = *immed_8 = 0; // Not used for movw.
1025 return true;
1026 }
1027 }
1028 }
1029 } else if ((*instr & kCmpCmnMask) == kCmpCmnPattern) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001030 if (fits_shifter(-static_cast<int>(imm32), rotate_imm, immed_8, NULL)) {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001031 *instr ^= kCmpCmnFlip;
1032 return true;
1033 }
1034 } else {
1035 Instr alu_insn = (*instr & kALUMask);
Steve Block1e0659c2011-05-24 12:43:12 +01001036 if (alu_insn == ADD ||
1037 alu_insn == SUB) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001038 if (fits_shifter(-static_cast<int>(imm32), rotate_imm, immed_8, NULL)) {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001039 *instr ^= kAddSubFlip;
1040 return true;
1041 }
Steve Block1e0659c2011-05-24 12:43:12 +01001042 } else if (alu_insn == AND ||
1043 alu_insn == BIC) {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001044 if (fits_shifter(~imm32, rotate_imm, immed_8, NULL)) {
1045 *instr ^= kAndBicFlip;
1046 return true;
1047 }
1048 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001049 }
1050 }
1051 return false;
1052}
1053
1054
1055// We have to use the temporary register for things that can be relocated even
1056// if they can be encoded in the ARM's 12 bits of immediate-offset instruction
1057// space. There is no guarantee that the relocated location can be similarly
1058// encoded.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001059bool Operand::must_output_reloc_info(const Assembler* assembler) const {
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001060 if (rmode_ == RelocInfo::EXTERNAL_REFERENCE) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001061 if (assembler != NULL && assembler->predictable_code_size()) return true;
1062 return assembler->serializer_enabled();
1063 } else if (RelocInfo::IsNone(rmode_)) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001064 return false;
1065 }
1066 return true;
1067}
1068
1069
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001070static bool use_mov_immediate_load(const Operand& x,
1071 const Assembler* assembler) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001072 if (FLAG_enable_embedded_constant_pool && assembler != NULL &&
1073 !assembler->is_constant_pool_available()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001074 return true;
1075 } else if (CpuFeatures::IsSupported(MOVW_MOVT_IMMEDIATE_LOADS) &&
1076 (assembler == NULL || !assembler->predictable_code_size())) {
1077 // Prefer movw / movt to constant pool if it is more efficient on the CPU.
1078 return true;
1079 } else if (x.must_output_reloc_info(assembler)) {
1080 // Prefer constant pool if data is likely to be patched.
1081 return false;
1082 } else {
1083 // Otherwise, use immediate load if movw / movt is available.
1084 return CpuFeatures::IsSupported(ARMv7);
1085 }
1086}
1087
1088
1089int Operand::instructions_required(const Assembler* assembler,
1090 Instr instr) const {
1091 if (rm_.is_valid()) return 1;
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001092 uint32_t dummy1, dummy2;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001093 if (must_output_reloc_info(assembler) ||
Steve Block44f0eee2011-05-26 01:26:41 +01001094 !fits_shifter(imm32_, &dummy1, &dummy2, &instr)) {
1095 // The immediate operand cannot be encoded as a shifter operand, or use of
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001096 // constant pool is required. First account for the instructions required
1097 // for the constant pool or immediate load
1098 int instructions;
1099 if (use_mov_immediate_load(*this, assembler)) {
1100 // A movw / movt or mov / orr immediate load.
1101 instructions = CpuFeatures::IsSupported(ARMv7) ? 2 : 4;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001102 } else if (assembler != NULL &&
1103 assembler->ConstantPoolAccessIsInOverflow()) {
1104 // An overflowed constant pool load.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001105 instructions = CpuFeatures::IsSupported(ARMv7) ? 3 : 5;
Steve Block44f0eee2011-05-26 01:26:41 +01001106 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001107 // A small constant pool load.
1108 instructions = 1;
Steve Block44f0eee2011-05-26 01:26:41 +01001109 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001110
1111 if ((instr & ~kCondMask) != 13 * B21) { // mov, S not set
1112 // For a mov or mvn instruction which doesn't set the condition
1113 // code, the constant pool or immediate load is enough, otherwise we need
1114 // to account for the actual instruction being requested.
1115 instructions += 1;
1116 }
1117 return instructions;
Steve Block44f0eee2011-05-26 01:26:41 +01001118 } else {
1119 // No use of constant pool and the immediate operand can be encoded as a
1120 // shifter operand.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001121 return 1;
1122 }
1123}
1124
1125
1126void Assembler::move_32_bit_immediate(Register rd,
1127 const Operand& x,
1128 Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001129 uint32_t imm32 = static_cast<uint32_t>(x.imm32_);
1130 if (x.must_output_reloc_info(this)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001131 RecordRelocInfo(x.rmode_);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001132 }
1133
1134 if (use_mov_immediate_load(x, this)) {
1135 Register target = rd.code() == pc.code() ? ip : rd;
1136 if (CpuFeatures::IsSupported(ARMv7)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001137 if (!FLAG_enable_embedded_constant_pool &&
1138 x.must_output_reloc_info(this)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001139 // Make sure the movw/movt doesn't get separated.
1140 BlockConstPoolFor(2);
1141 }
1142 movw(target, imm32 & 0xffff, cond);
1143 movt(target, imm32 >> 16, cond);
1144 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001145 DCHECK(FLAG_enable_embedded_constant_pool);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001146 mov(target, Operand(imm32 & kImm8Mask), LeaveCC, cond);
1147 orr(target, target, Operand(imm32 & (kImm8Mask << 8)), LeaveCC, cond);
1148 orr(target, target, Operand(imm32 & (kImm8Mask << 16)), LeaveCC, cond);
1149 orr(target, target, Operand(imm32 & (kImm8Mask << 24)), LeaveCC, cond);
1150 }
1151 if (target.code() != rd.code()) {
1152 mov(rd, target, LeaveCC, cond);
1153 }
1154 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001155 DCHECK(!FLAG_enable_embedded_constant_pool || is_constant_pool_available());
1156 ConstantPoolEntry::Access access =
1157 ConstantPoolAddEntry(pc_offset(), x.rmode_, x.imm32_);
1158 if (access == ConstantPoolEntry::OVERFLOWED) {
1159 DCHECK(FLAG_enable_embedded_constant_pool);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001160 Register target = rd.code() == pc.code() ? ip : rd;
1161 // Emit instructions to load constant pool offset.
1162 if (CpuFeatures::IsSupported(ARMv7)) {
1163 movw(target, 0, cond);
1164 movt(target, 0, cond);
1165 } else {
1166 mov(target, Operand(0), LeaveCC, cond);
1167 orr(target, target, Operand(0), LeaveCC, cond);
1168 orr(target, target, Operand(0), LeaveCC, cond);
1169 orr(target, target, Operand(0), LeaveCC, cond);
1170 }
1171 // Load from constant pool at offset.
1172 ldr(rd, MemOperand(pp, target), cond);
1173 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001174 DCHECK(access == ConstantPoolEntry::REGULAR);
1175 ldr(rd, MemOperand(FLAG_enable_embedded_constant_pool ? pp : pc, 0),
1176 cond);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001177 }
Steve Block44f0eee2011-05-26 01:26:41 +01001178 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001179}
1180
1181
Steve Blocka7e24c12009-10-30 11:49:00 +00001182void Assembler::addrmod1(Instr instr,
1183 Register rn,
1184 Register rd,
1185 const Operand& x) {
1186 CheckBuffer();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001187 DCHECK((instr & ~(kCondMask | kOpCodeMask | S)) == 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00001188 if (!x.rm_.is_valid()) {
Andrei Popescu31002712010-02-23 13:46:05 +00001189 // Immediate.
Steve Blocka7e24c12009-10-30 11:49:00 +00001190 uint32_t rotate_imm;
1191 uint32_t immed_8;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001192 if (x.must_output_reloc_info(this) ||
Steve Blocka7e24c12009-10-30 11:49:00 +00001193 !fits_shifter(x.imm32_, &rotate_imm, &immed_8, &instr)) {
1194 // The immediate operand cannot be encoded as a shifter operand, so load
1195 // it first to register ip and change the original instruction to use ip.
1196 // However, if the original instruction is a 'mov rd, x' (not setting the
Andrei Popescu31002712010-02-23 13:46:05 +00001197 // condition code), then replace it with a 'ldr rd, [pc]'.
Steve Blocka7e24c12009-10-30 11:49:00 +00001198 CHECK(!rn.is(ip)); // rn should never be ip, or will be trashed
Steve Block1e0659c2011-05-24 12:43:12 +01001199 Condition cond = Instruction::ConditionField(instr);
1200 if ((instr & ~kCondMask) == 13*B21) { // mov, S not set
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001201 move_32_bit_immediate(rd, x, cond);
Steve Blocka7e24c12009-10-30 11:49:00 +00001202 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001203 mov(ip, x, LeaveCC, cond);
Steve Blocka7e24c12009-10-30 11:49:00 +00001204 addrmod1(instr, rn, rd, Operand(ip));
1205 }
1206 return;
1207 }
1208 instr |= I | rotate_imm*B8 | immed_8;
1209 } else if (!x.rs_.is_valid()) {
Andrei Popescu31002712010-02-23 13:46:05 +00001210 // Immediate shift.
Steve Blocka7e24c12009-10-30 11:49:00 +00001211 instr |= x.shift_imm_*B7 | x.shift_op_ | x.rm_.code();
1212 } else {
Andrei Popescu31002712010-02-23 13:46:05 +00001213 // Register shift.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001214 DCHECK(!rn.is(pc) && !rd.is(pc) && !x.rm_.is(pc) && !x.rs_.is(pc));
Steve Blocka7e24c12009-10-30 11:49:00 +00001215 instr |= x.rs_.code()*B8 | x.shift_op_ | B4 | x.rm_.code();
1216 }
1217 emit(instr | rn.code()*B16 | rd.code()*B12);
Kristian Monsen50ef84f2010-07-29 15:18:00 +01001218 if (rn.is(pc) || x.rm_.is(pc)) {
Andrei Popescu31002712010-02-23 13:46:05 +00001219 // Block constant pool emission for one instruction after reading pc.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001220 BlockConstPoolFor(1);
Kristian Monsen50ef84f2010-07-29 15:18:00 +01001221 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001222}
1223
1224
1225void Assembler::addrmod2(Instr instr, Register rd, const MemOperand& x) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001226 DCHECK((instr & ~(kCondMask | B | L)) == B26);
Steve Blocka7e24c12009-10-30 11:49:00 +00001227 int am = x.am_;
1228 if (!x.rm_.is_valid()) {
Andrei Popescu31002712010-02-23 13:46:05 +00001229 // Immediate offset.
Steve Blocka7e24c12009-10-30 11:49:00 +00001230 int offset_12 = x.offset_;
1231 if (offset_12 < 0) {
1232 offset_12 = -offset_12;
1233 am ^= U;
1234 }
1235 if (!is_uint12(offset_12)) {
Andrei Popescu31002712010-02-23 13:46:05 +00001236 // Immediate offset cannot be encoded, load it first to register ip
1237 // rn (and rd in a load) should never be ip, or will be trashed.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001238 DCHECK(!x.rn_.is(ip) && ((instr & L) == L || !rd.is(ip)));
Steve Block1e0659c2011-05-24 12:43:12 +01001239 mov(ip, Operand(x.offset_), LeaveCC, Instruction::ConditionField(instr));
Steve Blocka7e24c12009-10-30 11:49:00 +00001240 addrmod2(instr, rd, MemOperand(x.rn_, ip, x.am_));
1241 return;
1242 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001243 DCHECK(offset_12 >= 0); // no masking needed
Steve Blocka7e24c12009-10-30 11:49:00 +00001244 instr |= offset_12;
1245 } else {
Andrei Popescu31002712010-02-23 13:46:05 +00001246 // Register offset (shift_imm_ and shift_op_ are 0) or scaled
Steve Blocka7e24c12009-10-30 11:49:00 +00001247 // register offset the constructors make sure than both shift_imm_
Andrei Popescu31002712010-02-23 13:46:05 +00001248 // and shift_op_ are initialized.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001249 DCHECK(!x.rm_.is(pc));
Steve Blocka7e24c12009-10-30 11:49:00 +00001250 instr |= B25 | x.shift_imm_*B7 | x.shift_op_ | x.rm_.code();
1251 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001252 DCHECK((am & (P|W)) == P || !x.rn_.is(pc)); // no pc base with writeback
Steve Blocka7e24c12009-10-30 11:49:00 +00001253 emit(instr | am | x.rn_.code()*B16 | rd.code()*B12);
1254}
1255
1256
1257void Assembler::addrmod3(Instr instr, Register rd, const MemOperand& x) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001258 DCHECK((instr & ~(kCondMask | L | S6 | H)) == (B4 | B7));
1259 DCHECK(x.rn_.is_valid());
Steve Blocka7e24c12009-10-30 11:49:00 +00001260 int am = x.am_;
1261 if (!x.rm_.is_valid()) {
Andrei Popescu31002712010-02-23 13:46:05 +00001262 // Immediate offset.
Steve Blocka7e24c12009-10-30 11:49:00 +00001263 int offset_8 = x.offset_;
1264 if (offset_8 < 0) {
1265 offset_8 = -offset_8;
1266 am ^= U;
1267 }
1268 if (!is_uint8(offset_8)) {
Andrei Popescu31002712010-02-23 13:46:05 +00001269 // Immediate offset cannot be encoded, load it first to register ip
1270 // rn (and rd in a load) should never be ip, or will be trashed.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001271 DCHECK(!x.rn_.is(ip) && ((instr & L) == L || !rd.is(ip)));
Steve Block1e0659c2011-05-24 12:43:12 +01001272 mov(ip, Operand(x.offset_), LeaveCC, Instruction::ConditionField(instr));
Steve Blocka7e24c12009-10-30 11:49:00 +00001273 addrmod3(instr, rd, MemOperand(x.rn_, ip, x.am_));
1274 return;
1275 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001276 DCHECK(offset_8 >= 0); // no masking needed
Steve Blocka7e24c12009-10-30 11:49:00 +00001277 instr |= B | (offset_8 >> 4)*B8 | (offset_8 & 0xf);
1278 } else if (x.shift_imm_ != 0) {
Andrei Popescu31002712010-02-23 13:46:05 +00001279 // Scaled register offset not supported, load index first
1280 // rn (and rd in a load) should never be ip, or will be trashed.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001281 DCHECK(!x.rn_.is(ip) && ((instr & L) == L || !rd.is(ip)));
Steve Blocka7e24c12009-10-30 11:49:00 +00001282 mov(ip, Operand(x.rm_, x.shift_op_, x.shift_imm_), LeaveCC,
Steve Block1e0659c2011-05-24 12:43:12 +01001283 Instruction::ConditionField(instr));
Steve Blocka7e24c12009-10-30 11:49:00 +00001284 addrmod3(instr, rd, MemOperand(x.rn_, ip, x.am_));
1285 return;
1286 } else {
Andrei Popescu31002712010-02-23 13:46:05 +00001287 // Register offset.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001288 DCHECK((am & (P|W)) == P || !x.rm_.is(pc)); // no pc index with writeback
Steve Blocka7e24c12009-10-30 11:49:00 +00001289 instr |= x.rm_.code();
1290 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001291 DCHECK((am & (P|W)) == P || !x.rn_.is(pc)); // no pc base with writeback
Steve Blocka7e24c12009-10-30 11:49:00 +00001292 emit(instr | am | x.rn_.code()*B16 | rd.code()*B12);
1293}
1294
1295
1296void Assembler::addrmod4(Instr instr, Register rn, RegList rl) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001297 DCHECK((instr & ~(kCondMask | P | U | W | L)) == B27);
1298 DCHECK(rl != 0);
1299 DCHECK(!rn.is(pc));
Steve Blocka7e24c12009-10-30 11:49:00 +00001300 emit(instr | rn.code()*B16 | rl);
1301}
1302
1303
1304void Assembler::addrmod5(Instr instr, CRegister crd, const MemOperand& x) {
Andrei Popescu31002712010-02-23 13:46:05 +00001305 // Unindexed addressing is not encoded by this function.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001306 DCHECK_EQ((B27 | B26),
Steve Block1e0659c2011-05-24 12:43:12 +01001307 (instr & ~(kCondMask | kCoprocessorMask | P | U | N | W | L)));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001308 DCHECK(x.rn_.is_valid() && !x.rm_.is_valid());
Steve Blocka7e24c12009-10-30 11:49:00 +00001309 int am = x.am_;
1310 int offset_8 = x.offset_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001311 DCHECK((offset_8 & 3) == 0); // offset must be an aligned word offset
Steve Blocka7e24c12009-10-30 11:49:00 +00001312 offset_8 >>= 2;
1313 if (offset_8 < 0) {
1314 offset_8 = -offset_8;
1315 am ^= U;
1316 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001317 DCHECK(is_uint8(offset_8)); // unsigned word offset must fit in a byte
1318 DCHECK((am & (P|W)) == P || !x.rn_.is(pc)); // no pc base with writeback
Steve Blocka7e24c12009-10-30 11:49:00 +00001319
Andrei Popescu31002712010-02-23 13:46:05 +00001320 // Post-indexed addressing requires W == 1; different than in addrmod2/3.
Steve Blocka7e24c12009-10-30 11:49:00 +00001321 if ((am & P) == 0)
1322 am |= W;
1323
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001324 DCHECK(offset_8 >= 0); // no masking needed
Steve Blocka7e24c12009-10-30 11:49:00 +00001325 emit(instr | am | x.rn_.code()*B16 | crd.code()*B12 | offset_8);
1326}
1327
1328
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001329int Assembler::branch_offset(Label* L) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001330 int target_pos;
1331 if (L->is_bound()) {
1332 target_pos = L->pos();
1333 } else {
1334 if (L->is_linked()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001335 // Point to previous instruction that uses the link.
1336 target_pos = L->pos();
Steve Blocka7e24c12009-10-30 11:49:00 +00001337 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001338 // First entry of the link chain points to itself.
1339 target_pos = pc_offset();
Steve Blocka7e24c12009-10-30 11:49:00 +00001340 }
1341 L->link_to(pc_offset());
1342 }
1343
1344 // Block the emission of the constant pool, since the branch instruction must
Andrei Popescu31002712010-02-23 13:46:05 +00001345 // be emitted at the pc offset recorded by the label.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001346 if (!is_const_pool_blocked()) BlockConstPoolFor(1);
1347
Steve Blocka7e24c12009-10-30 11:49:00 +00001348 return target_pos - (pc_offset() + kPcLoadDelta);
1349}
1350
1351
Andrei Popescu31002712010-02-23 13:46:05 +00001352// Branch instructions.
Steve Blocka7e24c12009-10-30 11:49:00 +00001353void Assembler::b(int branch_offset, Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001354 DCHECK((branch_offset & 3) == 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00001355 int imm24 = branch_offset >> 2;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001356 CHECK(is_int24(imm24));
Steve Block1e0659c2011-05-24 12:43:12 +01001357 emit(cond | B27 | B25 | (imm24 & kImm24Mask));
Steve Blocka7e24c12009-10-30 11:49:00 +00001358
Steve Block6ded16b2010-05-10 14:33:55 +01001359 if (cond == al) {
Andrei Popescu31002712010-02-23 13:46:05 +00001360 // Dead code is a good location to emit the constant pool.
Steve Blocka7e24c12009-10-30 11:49:00 +00001361 CheckConstPool(false, false);
Steve Block6ded16b2010-05-10 14:33:55 +01001362 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001363}
1364
1365
1366void Assembler::bl(int branch_offset, Condition cond) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01001367 positions_recorder()->WriteRecordedPositions();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001368 DCHECK((branch_offset & 3) == 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00001369 int imm24 = branch_offset >> 2;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001370 CHECK(is_int24(imm24));
Steve Block1e0659c2011-05-24 12:43:12 +01001371 emit(cond | B27 | B25 | B24 | (imm24 & kImm24Mask));
Steve Blocka7e24c12009-10-30 11:49:00 +00001372}
1373
1374
1375void Assembler::blx(int branch_offset) { // v5 and above
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001376 positions_recorder()->WriteRecordedPositions();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001377 DCHECK((branch_offset & 1) == 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00001378 int h = ((branch_offset & 2) >> 1)*B24;
1379 int imm24 = branch_offset >> 2;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001380 CHECK(is_int24(imm24));
Steve Block1e0659c2011-05-24 12:43:12 +01001381 emit(kSpecialCondition | B27 | B25 | h | (imm24 & kImm24Mask));
Steve Blocka7e24c12009-10-30 11:49:00 +00001382}
1383
1384
1385void Assembler::blx(Register target, Condition cond) { // v5 and above
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001386 positions_recorder()->WriteRecordedPositions();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001387 DCHECK(!target.is(pc));
Steve Block1e0659c2011-05-24 12:43:12 +01001388 emit(cond | B24 | B21 | 15*B16 | 15*B12 | 15*B8 | BLX | target.code());
Steve Blocka7e24c12009-10-30 11:49:00 +00001389}
1390
1391
1392void Assembler::bx(Register target, Condition cond) { // v5 and above, plus v4t
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001393 positions_recorder()->WriteRecordedPositions();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001394 DCHECK(!target.is(pc)); // use of pc is actually allowed, but discouraged
Steve Block1e0659c2011-05-24 12:43:12 +01001395 emit(cond | B24 | B21 | 15*B16 | 15*B12 | 15*B8 | BX | target.code());
Steve Blocka7e24c12009-10-30 11:49:00 +00001396}
1397
1398
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001399void Assembler::b(Label* L, Condition cond) {
1400 CheckBuffer();
1401 b(branch_offset(L), cond);
1402}
1403
1404
1405void Assembler::bl(Label* L, Condition cond) {
1406 CheckBuffer();
1407 bl(branch_offset(L), cond);
1408}
1409
1410
1411void Assembler::blx(Label* L) {
1412 CheckBuffer();
1413 blx(branch_offset(L));
1414}
1415
1416
Andrei Popescu31002712010-02-23 13:46:05 +00001417// Data-processing instructions.
1418
Steve Blocka7e24c12009-10-30 11:49:00 +00001419void Assembler::and_(Register dst, Register src1, const Operand& src2,
1420 SBit s, Condition cond) {
Steve Block1e0659c2011-05-24 12:43:12 +01001421 addrmod1(cond | AND | s, src1, dst, src2);
Steve Blocka7e24c12009-10-30 11:49:00 +00001422}
1423
1424
1425void Assembler::eor(Register dst, Register src1, const Operand& src2,
1426 SBit s, Condition cond) {
Steve Block1e0659c2011-05-24 12:43:12 +01001427 addrmod1(cond | EOR | s, src1, dst, src2);
Steve Blocka7e24c12009-10-30 11:49:00 +00001428}
1429
1430
1431void Assembler::sub(Register dst, Register src1, const Operand& src2,
1432 SBit s, Condition cond) {
Steve Block1e0659c2011-05-24 12:43:12 +01001433 addrmod1(cond | SUB | s, src1, dst, src2);
Steve Blocka7e24c12009-10-30 11:49:00 +00001434}
1435
1436
1437void Assembler::rsb(Register dst, Register src1, const Operand& src2,
1438 SBit s, Condition cond) {
Steve Block1e0659c2011-05-24 12:43:12 +01001439 addrmod1(cond | RSB | s, src1, dst, src2);
Steve Blocka7e24c12009-10-30 11:49:00 +00001440}
1441
1442
1443void Assembler::add(Register dst, Register src1, const Operand& src2,
1444 SBit s, Condition cond) {
Steve Block1e0659c2011-05-24 12:43:12 +01001445 addrmod1(cond | ADD | s, src1, dst, src2);
Steve Blocka7e24c12009-10-30 11:49:00 +00001446}
1447
1448
1449void Assembler::adc(Register dst, Register src1, const Operand& src2,
1450 SBit s, Condition cond) {
Steve Block1e0659c2011-05-24 12:43:12 +01001451 addrmod1(cond | ADC | s, src1, dst, src2);
Steve Blocka7e24c12009-10-30 11:49:00 +00001452}
1453
1454
1455void Assembler::sbc(Register dst, Register src1, const Operand& src2,
1456 SBit s, Condition cond) {
Steve Block1e0659c2011-05-24 12:43:12 +01001457 addrmod1(cond | SBC | s, src1, dst, src2);
Steve Blocka7e24c12009-10-30 11:49:00 +00001458}
1459
1460
1461void Assembler::rsc(Register dst, Register src1, const Operand& src2,
1462 SBit s, Condition cond) {
Steve Block1e0659c2011-05-24 12:43:12 +01001463 addrmod1(cond | RSC | s, src1, dst, src2);
Steve Blocka7e24c12009-10-30 11:49:00 +00001464}
1465
1466
1467void Assembler::tst(Register src1, const Operand& src2, Condition cond) {
Steve Block1e0659c2011-05-24 12:43:12 +01001468 addrmod1(cond | TST | S, src1, r0, src2);
Steve Blocka7e24c12009-10-30 11:49:00 +00001469}
1470
1471
1472void Assembler::teq(Register src1, const Operand& src2, Condition cond) {
Steve Block1e0659c2011-05-24 12:43:12 +01001473 addrmod1(cond | TEQ | S, src1, r0, src2);
Steve Blocka7e24c12009-10-30 11:49:00 +00001474}
1475
1476
1477void Assembler::cmp(Register src1, const Operand& src2, Condition cond) {
Steve Block1e0659c2011-05-24 12:43:12 +01001478 addrmod1(cond | CMP | S, src1, r0, src2);
1479}
1480
1481
1482void Assembler::cmp_raw_immediate(
1483 Register src, int raw_immediate, Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001484 DCHECK(is_uint12(raw_immediate));
Steve Block1e0659c2011-05-24 12:43:12 +01001485 emit(cond | I | CMP | S | src.code() << 16 | raw_immediate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001486}
1487
1488
1489void Assembler::cmn(Register src1, const Operand& src2, Condition cond) {
Steve Block1e0659c2011-05-24 12:43:12 +01001490 addrmod1(cond | CMN | S, src1, r0, src2);
Steve Blocka7e24c12009-10-30 11:49:00 +00001491}
1492
1493
1494void Assembler::orr(Register dst, Register src1, const Operand& src2,
1495 SBit s, Condition cond) {
Steve Block1e0659c2011-05-24 12:43:12 +01001496 addrmod1(cond | ORR | s, src1, dst, src2);
Steve Blocka7e24c12009-10-30 11:49:00 +00001497}
1498
1499
1500void Assembler::mov(Register dst, const Operand& src, SBit s, Condition cond) {
1501 if (dst.is(pc)) {
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001502 positions_recorder()->WriteRecordedPositions();
Steve Blocka7e24c12009-10-30 11:49:00 +00001503 }
Steve Block6ded16b2010-05-10 14:33:55 +01001504 // Don't allow nop instructions in the form mov rn, rn to be generated using
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001505 // the mov instruction. They must be generated using nop(int/NopMarkerTypes)
1506 // or MarkCode(int/NopMarkerTypes) pseudo instructions.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001507 DCHECK(!(src.is_reg() && src.rm().is(dst) && s == LeaveCC && cond == al));
Steve Block1e0659c2011-05-24 12:43:12 +01001508 addrmod1(cond | MOV | s, r0, dst, src);
Steve Blocka7e24c12009-10-30 11:49:00 +00001509}
1510
1511
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001512void Assembler::mov_label_offset(Register dst, Label* label) {
1513 if (label->is_bound()) {
1514 mov(dst, Operand(label->pos() + (Code::kHeaderSize - kHeapObjectTag)));
1515 } else {
1516 // Emit the link to the label in the code stream followed by extra nop
1517 // instructions.
1518 // If the label is not linked, then start a new link chain by linking it to
1519 // itself, emitting pc_offset().
1520 int link = label->is_linked() ? label->pos() : pc_offset();
1521 label->link_to(pc_offset());
1522
1523 // When the label is bound, these instructions will be patched with a
1524 // sequence of movw/movt or mov/orr/orr instructions. They will load the
1525 // destination register with the position of the label from the beginning
1526 // of the code.
1527 //
1528 // The link will be extracted from the first instruction and the destination
1529 // register from the second.
1530 // For ARMv7:
1531 // link
1532 // mov dst, dst
1533 // For ARMv6:
1534 // link
1535 // mov dst, dst
1536 // mov dst, dst
1537 //
1538 // When the label gets bound: target_at extracts the link and target_at_put
1539 // patches the instructions.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001540 CHECK(is_uint24(link));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001541 BlockConstPoolScope block_const_pool(this);
1542 emit(link);
1543 nop(dst.code());
1544 if (!CpuFeatures::IsSupported(ARMv7)) {
1545 nop(dst.code());
1546 }
1547 }
1548}
1549
1550
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001551void Assembler::movw(Register reg, uint32_t immediate, Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001552 DCHECK(CpuFeatures::IsSupported(ARMv7));
1553 emit(cond | 0x30*B20 | reg.code()*B12 | EncodeMovwImmediate(immediate));
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001554}
1555
1556
1557void Assembler::movt(Register reg, uint32_t immediate, Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001558 DCHECK(CpuFeatures::IsSupported(ARMv7));
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001559 emit(cond | 0x34*B20 | reg.code()*B12 | EncodeMovwImmediate(immediate));
1560}
1561
1562
Steve Blocka7e24c12009-10-30 11:49:00 +00001563void Assembler::bic(Register dst, Register src1, const Operand& src2,
1564 SBit s, Condition cond) {
Steve Block1e0659c2011-05-24 12:43:12 +01001565 addrmod1(cond | BIC | s, src1, dst, src2);
Steve Blocka7e24c12009-10-30 11:49:00 +00001566}
1567
1568
1569void Assembler::mvn(Register dst, const Operand& src, SBit s, Condition cond) {
Steve Block1e0659c2011-05-24 12:43:12 +01001570 addrmod1(cond | MVN | s, r0, dst, src);
Steve Blocka7e24c12009-10-30 11:49:00 +00001571}
1572
1573
Andrei Popescu31002712010-02-23 13:46:05 +00001574// Multiply instructions.
Steve Blocka7e24c12009-10-30 11:49:00 +00001575void Assembler::mla(Register dst, Register src1, Register src2, Register srcA,
1576 SBit s, Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001577 DCHECK(!dst.is(pc) && !src1.is(pc) && !src2.is(pc) && !srcA.is(pc));
Steve Blocka7e24c12009-10-30 11:49:00 +00001578 emit(cond | A | s | dst.code()*B16 | srcA.code()*B12 |
1579 src2.code()*B8 | B7 | B4 | src1.code());
1580}
1581
1582
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001583void Assembler::mls(Register dst, Register src1, Register src2, Register srcA,
1584 Condition cond) {
1585 DCHECK(!dst.is(pc) && !src1.is(pc) && !src2.is(pc) && !srcA.is(pc));
1586 DCHECK(IsEnabled(MLS));
1587 emit(cond | B22 | B21 | dst.code()*B16 | srcA.code()*B12 |
1588 src2.code()*B8 | B7 | B4 | src1.code());
1589}
1590
1591
1592void Assembler::sdiv(Register dst, Register src1, Register src2,
1593 Condition cond) {
1594 DCHECK(!dst.is(pc) && !src1.is(pc) && !src2.is(pc));
1595 DCHECK(IsEnabled(SUDIV));
1596 emit(cond | B26 | B25| B24 | B20 | dst.code()*B16 | 0xf * B12 |
1597 src2.code()*B8 | B4 | src1.code());
1598}
1599
1600
1601void Assembler::udiv(Register dst, Register src1, Register src2,
1602 Condition cond) {
1603 DCHECK(!dst.is(pc) && !src1.is(pc) && !src2.is(pc));
1604 DCHECK(IsEnabled(SUDIV));
1605 emit(cond | B26 | B25 | B24 | B21 | B20 | dst.code() * B16 | 0xf * B12 |
1606 src2.code() * B8 | B4 | src1.code());
1607}
1608
1609
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001610void Assembler::mul(Register dst, Register src1, Register src2, SBit s,
1611 Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001612 DCHECK(!dst.is(pc) && !src1.is(pc) && !src2.is(pc));
Steve Blocka7e24c12009-10-30 11:49:00 +00001613 // dst goes in bits 16-19 for this instruction!
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001614 emit(cond | s | dst.code() * B16 | src2.code() * B8 | B7 | B4 | src1.code());
1615}
1616
1617
1618void Assembler::smmla(Register dst, Register src1, Register src2, Register srcA,
1619 Condition cond) {
1620 DCHECK(!dst.is(pc) && !src1.is(pc) && !src2.is(pc) && !srcA.is(pc));
1621 emit(cond | B26 | B25 | B24 | B22 | B20 | dst.code() * B16 |
1622 srcA.code() * B12 | src2.code() * B8 | B4 | src1.code());
1623}
1624
1625
1626void Assembler::smmul(Register dst, Register src1, Register src2,
1627 Condition cond) {
1628 DCHECK(!dst.is(pc) && !src1.is(pc) && !src2.is(pc));
1629 emit(cond | B26 | B25 | B24 | B22 | B20 | dst.code() * B16 | 0xf * B12 |
1630 src2.code() * B8 | B4 | src1.code());
Steve Blocka7e24c12009-10-30 11:49:00 +00001631}
1632
1633
1634void Assembler::smlal(Register dstL,
1635 Register dstH,
1636 Register src1,
1637 Register src2,
1638 SBit s,
1639 Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001640 DCHECK(!dstL.is(pc) && !dstH.is(pc) && !src1.is(pc) && !src2.is(pc));
1641 DCHECK(!dstL.is(dstH));
Steve Blocka7e24c12009-10-30 11:49:00 +00001642 emit(cond | B23 | B22 | A | s | dstH.code()*B16 | dstL.code()*B12 |
1643 src2.code()*B8 | B7 | B4 | src1.code());
1644}
1645
1646
1647void Assembler::smull(Register dstL,
1648 Register dstH,
1649 Register src1,
1650 Register src2,
1651 SBit s,
1652 Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001653 DCHECK(!dstL.is(pc) && !dstH.is(pc) && !src1.is(pc) && !src2.is(pc));
1654 DCHECK(!dstL.is(dstH));
Steve Blocka7e24c12009-10-30 11:49:00 +00001655 emit(cond | B23 | B22 | s | dstH.code()*B16 | dstL.code()*B12 |
1656 src2.code()*B8 | B7 | B4 | src1.code());
1657}
1658
1659
1660void Assembler::umlal(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 | A | s | dstH.code()*B16 | dstL.code()*B12 |
1669 src2.code()*B8 | B7 | B4 | src1.code());
1670}
1671
1672
1673void Assembler::umull(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 | s | dstH.code()*B16 | dstL.code()*B12 |
1682 src2.code()*B8 | B7 | B4 | src1.code());
1683}
1684
1685
Andrei Popescu31002712010-02-23 13:46:05 +00001686// Miscellaneous arithmetic instructions.
Steve Blocka7e24c12009-10-30 11:49:00 +00001687void Assembler::clz(Register dst, Register src, Condition cond) {
1688 // v5 and above.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001689 DCHECK(!dst.is(pc) && !src.is(pc));
Steve Blocka7e24c12009-10-30 11:49:00 +00001690 emit(cond | B24 | B22 | B21 | 15*B16 | dst.code()*B12 |
Steve Block1e0659c2011-05-24 12:43:12 +01001691 15*B8 | CLZ | src.code());
Steve Blocka7e24c12009-10-30 11:49:00 +00001692}
1693
1694
Kristian Monsen50ef84f2010-07-29 15:18:00 +01001695// Saturating instructions.
1696
1697// Unsigned saturate.
1698void Assembler::usat(Register dst,
1699 int satpos,
1700 const Operand& src,
1701 Condition cond) {
1702 // v6 and above.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001703 DCHECK(CpuFeatures::IsSupported(ARMv7));
1704 DCHECK(!dst.is(pc) && !src.rm_.is(pc));
1705 DCHECK((satpos >= 0) && (satpos <= 31));
1706 DCHECK((src.shift_op_ == ASR) || (src.shift_op_ == LSL));
1707 DCHECK(src.rs_.is(no_reg));
Kristian Monsen50ef84f2010-07-29 15:18:00 +01001708
1709 int sh = 0;
1710 if (src.shift_op_ == ASR) {
1711 sh = 1;
1712 }
1713
1714 emit(cond | 0x6*B24 | 0xe*B20 | satpos*B16 | dst.code()*B12 |
1715 src.shift_imm_*B7 | sh*B6 | 0x1*B4 | src.rm_.code());
1716}
1717
1718
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001719// Bitfield manipulation instructions.
1720
1721// Unsigned bit field extract.
1722// Extracts #width adjacent bits from position #lsb in a register, and
1723// writes them to the low bits of a destination register.
1724// ubfx dst, src, #lsb, #width
1725void Assembler::ubfx(Register dst,
1726 Register src,
1727 int lsb,
1728 int width,
1729 Condition cond) {
1730 // v7 and above.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001731 DCHECK(CpuFeatures::IsSupported(ARMv7));
1732 DCHECK(!dst.is(pc) && !src.is(pc));
1733 DCHECK((lsb >= 0) && (lsb <= 31));
1734 DCHECK((width >= 1) && (width <= (32 - lsb)));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001735 emit(cond | 0xf*B23 | B22 | B21 | (width - 1)*B16 | dst.code()*B12 |
1736 lsb*B7 | B6 | B4 | src.code());
1737}
1738
1739
1740// Signed bit field extract.
1741// Extracts #width adjacent bits from position #lsb in a register, and
1742// writes them to the low bits of a destination register. The extracted
1743// value is sign extended to fill the destination register.
1744// sbfx dst, src, #lsb, #width
1745void Assembler::sbfx(Register dst,
1746 Register src,
1747 int lsb,
1748 int width,
1749 Condition cond) {
1750 // v7 and above.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001751 DCHECK(CpuFeatures::IsSupported(ARMv7));
1752 DCHECK(!dst.is(pc) && !src.is(pc));
1753 DCHECK((lsb >= 0) && (lsb <= 31));
1754 DCHECK((width >= 1) && (width <= (32 - lsb)));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001755 emit(cond | 0xf*B23 | B21 | (width - 1)*B16 | dst.code()*B12 |
1756 lsb*B7 | B6 | B4 | src.code());
1757}
1758
1759
1760// Bit field clear.
1761// Sets #width adjacent bits at position #lsb in the destination register
1762// to zero, preserving the value of the other bits.
1763// bfc dst, #lsb, #width
1764void Assembler::bfc(Register dst, int lsb, int width, Condition cond) {
1765 // v7 and above.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001766 DCHECK(CpuFeatures::IsSupported(ARMv7));
1767 DCHECK(!dst.is(pc));
1768 DCHECK((lsb >= 0) && (lsb <= 31));
1769 DCHECK((width >= 1) && (width <= (32 - lsb)));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001770 int msb = lsb + width - 1;
1771 emit(cond | 0x1f*B22 | msb*B16 | dst.code()*B12 | lsb*B7 | B4 | 0xf);
1772}
1773
1774
1775// Bit field insert.
1776// Inserts #width adjacent bits from the low bits of the source register
1777// into position #lsb of the destination register.
1778// bfi dst, src, #lsb, #width
1779void Assembler::bfi(Register dst,
1780 Register src,
1781 int lsb,
1782 int width,
1783 Condition cond) {
1784 // v7 and above.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001785 DCHECK(CpuFeatures::IsSupported(ARMv7));
1786 DCHECK(!dst.is(pc) && !src.is(pc));
1787 DCHECK((lsb >= 0) && (lsb <= 31));
1788 DCHECK((width >= 1) && (width <= (32 - lsb)));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001789 int msb = lsb + width - 1;
1790 emit(cond | 0x1f*B22 | msb*B16 | dst.code()*B12 | lsb*B7 | B4 |
1791 src.code());
1792}
1793
1794
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001795void Assembler::pkhbt(Register dst,
1796 Register src1,
1797 const Operand& src2,
1798 Condition cond ) {
1799 // Instruction details available in ARM DDI 0406C.b, A8.8.125.
1800 // cond(31-28) | 01101000(27-20) | Rn(19-16) |
1801 // Rd(15-12) | imm5(11-7) | 0(6) | 01(5-4) | Rm(3-0)
1802 DCHECK(!dst.is(pc));
1803 DCHECK(!src1.is(pc));
1804 DCHECK(!src2.rm().is(pc));
1805 DCHECK(!src2.rm().is(no_reg));
1806 DCHECK(src2.rs().is(no_reg));
1807 DCHECK((src2.shift_imm_ >= 0) && (src2.shift_imm_ <= 31));
1808 DCHECK(src2.shift_op() == LSL);
1809 emit(cond | 0x68*B20 | src1.code()*B16 | dst.code()*B12 |
1810 src2.shift_imm_*B7 | B4 | src2.rm().code());
1811}
1812
1813
1814void Assembler::pkhtb(Register dst,
1815 Register src1,
1816 const Operand& src2,
1817 Condition cond) {
1818 // Instruction details available in ARM DDI 0406C.b, A8.8.125.
1819 // cond(31-28) | 01101000(27-20) | Rn(19-16) |
1820 // Rd(15-12) | imm5(11-7) | 1(6) | 01(5-4) | Rm(3-0)
1821 DCHECK(!dst.is(pc));
1822 DCHECK(!src1.is(pc));
1823 DCHECK(!src2.rm().is(pc));
1824 DCHECK(!src2.rm().is(no_reg));
1825 DCHECK(src2.rs().is(no_reg));
1826 DCHECK((src2.shift_imm_ >= 1) && (src2.shift_imm_ <= 32));
1827 DCHECK(src2.shift_op() == ASR);
1828 int asr = (src2.shift_imm_ == 32) ? 0 : src2.shift_imm_;
1829 emit(cond | 0x68*B20 | src1.code()*B16 | dst.code()*B12 |
1830 asr*B7 | B6 | B4 | src2.rm().code());
1831}
1832
1833
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001834void Assembler::sxtb(Register dst, Register src, int rotate, Condition cond) {
1835 // Instruction details available in ARM DDI 0406C.b, A8.8.233.
1836 // cond(31-28) | 01101010(27-20) | 1111(19-16) |
1837 // Rd(15-12) | rotate(11-10) | 00(9-8)| 0111(7-4) | Rm(3-0)
1838 DCHECK(!dst.is(pc));
1839 DCHECK(!src.is(pc));
1840 DCHECK(rotate == 0 || rotate == 8 || rotate == 16 || rotate == 24);
1841 emit(cond | 0x6A * B20 | 0xF * B16 | dst.code() * B12 |
1842 ((rotate >> 1) & 0xC) * B8 | 7 * B4 | src.code());
1843}
1844
1845
1846void Assembler::sxtab(Register dst, Register src1, Register src2, int rotate,
1847 Condition cond) {
1848 // Instruction details available in ARM DDI 0406C.b, A8.8.233.
1849 // cond(31-28) | 01101010(27-20) | Rn(19-16) |
1850 // Rd(15-12) | rotate(11-10) | 00(9-8)| 0111(7-4) | Rm(3-0)
1851 DCHECK(!dst.is(pc));
1852 DCHECK(!src1.is(pc));
1853 DCHECK(!src2.is(pc));
1854 DCHECK(rotate == 0 || rotate == 8 || rotate == 16 || rotate == 24);
1855 emit(cond | 0x6A * B20 | src1.code() * B16 | dst.code() * B12 |
1856 ((rotate >> 1) & 0xC) * B8 | 7 * B4 | src2.code());
1857}
1858
1859
1860void Assembler::sxth(Register dst, Register src, int rotate, Condition cond) {
1861 // Instruction details available in ARM DDI 0406C.b, A8.8.235.
1862 // cond(31-28) | 01101011(27-20) | 1111(19-16) |
1863 // Rd(15-12) | rotate(11-10) | 00(9-8)| 0111(7-4) | Rm(3-0)
1864 DCHECK(!dst.is(pc));
1865 DCHECK(!src.is(pc));
1866 DCHECK(rotate == 0 || rotate == 8 || rotate == 16 || rotate == 24);
1867 emit(cond | 0x6B * B20 | 0xF * B16 | dst.code() * B12 |
1868 ((rotate >> 1) & 0xC) * B8 | 7 * B4 | src.code());
1869}
1870
1871
1872void Assembler::sxtah(Register dst, Register src1, Register src2, int rotate,
1873 Condition cond) {
1874 // Instruction details available in ARM DDI 0406C.b, A8.8.235.
1875 // cond(31-28) | 01101011(27-20) | Rn(19-16) |
1876 // Rd(15-12) | rotate(11-10) | 00(9-8)| 0111(7-4) | Rm(3-0)
1877 DCHECK(!dst.is(pc));
1878 DCHECK(!src1.is(pc));
1879 DCHECK(!src2.is(pc));
1880 DCHECK(rotate == 0 || rotate == 8 || rotate == 16 || rotate == 24);
1881 emit(cond | 0x6B * B20 | src1.code() * B16 | dst.code() * B12 |
1882 ((rotate >> 1) & 0xC) * B8 | 7 * B4 | src2.code());
1883}
1884
1885
1886void Assembler::uxtb(Register dst, Register src, int rotate, Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001887 // Instruction details available in ARM DDI 0406C.b, A8.8.274.
1888 // cond(31-28) | 01101110(27-20) | 1111(19-16) |
1889 // Rd(15-12) | rotate(11-10) | 00(9-8)| 0111(7-4) | Rm(3-0)
1890 DCHECK(!dst.is(pc));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001891 DCHECK(!src.is(pc));
1892 DCHECK(rotate == 0 || rotate == 8 || rotate == 16 || rotate == 24);
1893 emit(cond | 0x6E * B20 | 0xF * B16 | dst.code() * B12 |
1894 ((rotate >> 1) & 0xC) * B8 | 7 * B4 | src.code());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001895}
1896
1897
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001898void Assembler::uxtab(Register dst, Register src1, Register src2, int rotate,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001899 Condition cond) {
1900 // Instruction details available in ARM DDI 0406C.b, A8.8.271.
1901 // cond(31-28) | 01101110(27-20) | Rn(19-16) |
1902 // Rd(15-12) | rotate(11-10) | 00(9-8)| 0111(7-4) | Rm(3-0)
1903 DCHECK(!dst.is(pc));
1904 DCHECK(!src1.is(pc));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001905 DCHECK(!src2.is(pc));
1906 DCHECK(rotate == 0 || rotate == 8 || rotate == 16 || rotate == 24);
1907 emit(cond | 0x6E * B20 | src1.code() * B16 | dst.code() * B12 |
1908 ((rotate >> 1) & 0xC) * B8 | 7 * B4 | src2.code());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001909}
1910
1911
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001912void Assembler::uxtb16(Register dst, Register src, int rotate, Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001913 // Instruction details available in ARM DDI 0406C.b, A8.8.275.
1914 // cond(31-28) | 01101100(27-20) | 1111(19-16) |
1915 // Rd(15-12) | rotate(11-10) | 00(9-8)| 0111(7-4) | Rm(3-0)
1916 DCHECK(!dst.is(pc));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001917 DCHECK(!src.is(pc));
1918 DCHECK(rotate == 0 || rotate == 8 || rotate == 16 || rotate == 24);
1919 emit(cond | 0x6C * B20 | 0xF * B16 | dst.code() * B12 |
1920 ((rotate >> 1) & 0xC) * B8 | 7 * B4 | src.code());
1921}
1922
1923
1924void Assembler::uxth(Register dst, Register src, int rotate, Condition cond) {
1925 // Instruction details available in ARM DDI 0406C.b, A8.8.276.
1926 // cond(31-28) | 01101111(27-20) | 1111(19-16) |
1927 // Rd(15-12) | rotate(11-10) | 00(9-8)| 0111(7-4) | Rm(3-0)
1928 DCHECK(!dst.is(pc));
1929 DCHECK(!src.is(pc));
1930 DCHECK(rotate == 0 || rotate == 8 || rotate == 16 || rotate == 24);
1931 emit(cond | 0x6F * B20 | 0xF * B16 | dst.code() * B12 |
1932 ((rotate >> 1) & 0xC) * B8 | 7 * B4 | src.code());
1933}
1934
1935
1936void Assembler::uxtah(Register dst, Register src1, Register src2, int rotate,
1937 Condition cond) {
1938 // Instruction details available in ARM DDI 0406C.b, A8.8.273.
1939 // cond(31-28) | 01101111(27-20) | Rn(19-16) |
1940 // Rd(15-12) | rotate(11-10) | 00(9-8)| 0111(7-4) | Rm(3-0)
1941 DCHECK(!dst.is(pc));
1942 DCHECK(!src1.is(pc));
1943 DCHECK(!src2.is(pc));
1944 DCHECK(rotate == 0 || rotate == 8 || rotate == 16 || rotate == 24);
1945 emit(cond | 0x6F * B20 | src1.code() * B16 | dst.code() * B12 |
1946 ((rotate >> 1) & 0xC) * B8 | 7 * B4 | src2.code());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001947}
1948
1949
Andrei Popescu31002712010-02-23 13:46:05 +00001950// Status register access instructions.
Steve Blocka7e24c12009-10-30 11:49:00 +00001951void Assembler::mrs(Register dst, SRegister s, Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001952 DCHECK(!dst.is(pc));
Steve Blocka7e24c12009-10-30 11:49:00 +00001953 emit(cond | B24 | s | 15*B16 | dst.code()*B12);
1954}
1955
1956
1957void Assembler::msr(SRegisterFieldMask fields, const Operand& src,
1958 Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001959 DCHECK(fields >= B16 && fields < B20); // at least one field set
Steve Blocka7e24c12009-10-30 11:49:00 +00001960 Instr instr;
1961 if (!src.rm_.is_valid()) {
Andrei Popescu31002712010-02-23 13:46:05 +00001962 // Immediate.
Steve Blocka7e24c12009-10-30 11:49:00 +00001963 uint32_t rotate_imm;
1964 uint32_t immed_8;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001965 if (src.must_output_reloc_info(this) ||
Steve Blocka7e24c12009-10-30 11:49:00 +00001966 !fits_shifter(src.imm32_, &rotate_imm, &immed_8, NULL)) {
Andrei Popescu31002712010-02-23 13:46:05 +00001967 // Immediate operand cannot be encoded, load it first to register ip.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001968 move_32_bit_immediate(ip, src);
Steve Blocka7e24c12009-10-30 11:49:00 +00001969 msr(fields, Operand(ip), cond);
1970 return;
1971 }
1972 instr = I | rotate_imm*B8 | immed_8;
1973 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001974 DCHECK(!src.rs_.is_valid() && src.shift_imm_ == 0); // only rm allowed
Steve Blocka7e24c12009-10-30 11:49:00 +00001975 instr = src.rm_.code();
1976 }
1977 emit(cond | instr | B24 | B21 | fields | 15*B12);
1978}
1979
1980
Andrei Popescu31002712010-02-23 13:46:05 +00001981// Load/Store instructions.
Steve Blocka7e24c12009-10-30 11:49:00 +00001982void Assembler::ldr(Register dst, const MemOperand& src, Condition cond) {
1983 if (dst.is(pc)) {
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001984 positions_recorder()->WriteRecordedPositions();
Steve Blocka7e24c12009-10-30 11:49:00 +00001985 }
1986 addrmod2(cond | B26 | L, dst, src);
Steve Blocka7e24c12009-10-30 11:49:00 +00001987}
1988
1989
1990void Assembler::str(Register src, const MemOperand& dst, Condition cond) {
1991 addrmod2(cond | B26, src, dst);
Steve Blocka7e24c12009-10-30 11:49:00 +00001992}
1993
1994
1995void Assembler::ldrb(Register dst, const MemOperand& src, Condition cond) {
1996 addrmod2(cond | B26 | B | L, dst, src);
1997}
1998
1999
2000void Assembler::strb(Register src, const MemOperand& dst, Condition cond) {
2001 addrmod2(cond | B26 | B, src, dst);
2002}
2003
2004
2005void Assembler::ldrh(Register dst, const MemOperand& src, Condition cond) {
2006 addrmod3(cond | L | B7 | H | B4, dst, src);
2007}
2008
2009
2010void Assembler::strh(Register src, const MemOperand& dst, Condition cond) {
2011 addrmod3(cond | B7 | H | B4, src, dst);
2012}
2013
2014
2015void Assembler::ldrsb(Register dst, const MemOperand& src, Condition cond) {
2016 addrmod3(cond | L | B7 | S6 | B4, dst, src);
2017}
2018
2019
2020void Assembler::ldrsh(Register dst, const MemOperand& src, Condition cond) {
2021 addrmod3(cond | L | B7 | S6 | H | B4, dst, src);
2022}
2023
2024
Leon Clarkef7060e22010-06-03 12:02:55 +01002025void Assembler::ldrd(Register dst1, Register dst2,
2026 const MemOperand& src, Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002027 DCHECK(IsEnabled(ARMv7));
2028 DCHECK(src.rm().is(no_reg));
2029 DCHECK(!dst1.is(lr)); // r14.
2030 DCHECK_EQ(0, dst1.code() % 2);
2031 DCHECK_EQ(dst1.code() + 1, dst2.code());
Leon Clarkef7060e22010-06-03 12:02:55 +01002032 addrmod3(cond | B7 | B6 | B4, dst1, src);
Kristian Monsen25f61362010-05-21 11:50:48 +01002033}
2034
2035
Leon Clarkef7060e22010-06-03 12:02:55 +01002036void Assembler::strd(Register src1, Register src2,
2037 const MemOperand& dst, Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002038 DCHECK(dst.rm().is(no_reg));
2039 DCHECK(!src1.is(lr)); // r14.
2040 DCHECK_EQ(0, src1.code() % 2);
2041 DCHECK_EQ(src1.code() + 1, src2.code());
2042 DCHECK(IsEnabled(ARMv7));
Leon Clarkef7060e22010-06-03 12:02:55 +01002043 addrmod3(cond | B7 | B6 | B5 | B4, src1, dst);
Kristian Monsen25f61362010-05-21 11:50:48 +01002044}
2045
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002046
2047// Preload instructions.
2048void Assembler::pld(const MemOperand& address) {
2049 // Instruction details available in ARM DDI 0406C.b, A8.8.128.
2050 // 1111(31-28) | 0111(27-24) | U(23) | R(22) | 01(21-20) | Rn(19-16) |
2051 // 1111(15-12) | imm5(11-07) | type(6-5) | 0(4)| Rm(3-0) |
2052 DCHECK(address.rm().is(no_reg));
2053 DCHECK(address.am() == Offset);
2054 int U = B23;
2055 int offset = address.offset();
2056 if (offset < 0) {
2057 offset = -offset;
2058 U = 0;
2059 }
2060 DCHECK(offset < 4096);
2061 emit(kSpecialCondition | B26 | B24 | U | B22 | B20 | address.rn().code()*B16 |
2062 0xf*B12 | offset);
2063}
2064
2065
Andrei Popescu31002712010-02-23 13:46:05 +00002066// Load/Store multiple instructions.
Steve Blocka7e24c12009-10-30 11:49:00 +00002067void Assembler::ldm(BlockAddrMode am,
2068 Register base,
2069 RegList dst,
2070 Condition cond) {
Andrei Popescu31002712010-02-23 13:46:05 +00002071 // ABI stack constraint: ldmxx base, {..sp..} base != sp is not restartable.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002072 DCHECK(base.is(sp) || (dst & sp.bit()) == 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00002073
2074 addrmod4(cond | B27 | am | L, base, dst);
2075
Andrei Popescu31002712010-02-23 13:46:05 +00002076 // Emit the constant pool after a function return implemented by ldm ..{..pc}.
Steve Blocka7e24c12009-10-30 11:49:00 +00002077 if (cond == al && (dst & pc.bit()) != 0) {
2078 // There is a slight chance that the ldm instruction was actually a call,
2079 // in which case it would be wrong to return into the constant pool; we
2080 // recognize this case by checking if the emission of the pool was blocked
2081 // at the pc of the ldm instruction by a mov lr, pc instruction; if this is
2082 // the case, we emit a jump over the pool.
2083 CheckConstPool(true, no_const_pool_before_ == pc_offset() - kInstrSize);
2084 }
2085}
2086
2087
2088void Assembler::stm(BlockAddrMode am,
2089 Register base,
2090 RegList src,
2091 Condition cond) {
2092 addrmod4(cond | B27 | am, base, src);
2093}
2094
2095
Andrei Popescu31002712010-02-23 13:46:05 +00002096// Exception-generating instructions and debugging support.
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002097// Stops with a non-negative code less than kNumOfWatchedStops support
2098// enabling/disabling and a counter feature. See simulator-arm.h .
2099void Assembler::stop(const char* msg, Condition cond, int32_t code) {
Andrei Popescu402d9372010-02-26 13:31:12 +00002100#ifndef __arm__
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002101 DCHECK(code >= kDefaultStopCode);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002102 {
2103 // The Simulator will handle the stop instruction and get the message
2104 // address. It expects to find the address just after the svc instruction.
2105 BlockConstPoolScope block_const_pool(this);
2106 if (code >= 0) {
2107 svc(kStopCode + code, cond);
2108 } else {
2109 svc(kStopCode + kMaxStopCode, cond);
2110 }
2111 emit(reinterpret_cast<Instr>(msg));
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002112 }
Andrei Popescu402d9372010-02-26 13:31:12 +00002113#else // def __arm__
Steve Block1e0659c2011-05-24 12:43:12 +01002114 if (cond != al) {
2115 Label skip;
2116 b(&skip, NegateCondition(cond));
2117 bkpt(0);
2118 bind(&skip);
2119 } else {
2120 bkpt(0);
2121 }
Andrei Popescu402d9372010-02-26 13:31:12 +00002122#endif // def __arm__
Steve Blocka7e24c12009-10-30 11:49:00 +00002123}
2124
2125
2126void Assembler::bkpt(uint32_t imm16) { // v5 and above
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002127 DCHECK(is_uint16(imm16));
Steve Block1e0659c2011-05-24 12:43:12 +01002128 emit(al | B24 | B21 | (imm16 >> 4)*B8 | BKPT | (imm16 & 0xf));
Steve Blocka7e24c12009-10-30 11:49:00 +00002129}
2130
2131
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002132void Assembler::svc(uint32_t imm24, Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002133 DCHECK(is_uint24(imm24));
Steve Blocka7e24c12009-10-30 11:49:00 +00002134 emit(cond | 15*B24 | imm24);
2135}
2136
2137
Andrei Popescu31002712010-02-23 13:46:05 +00002138// Coprocessor instructions.
Steve Blocka7e24c12009-10-30 11:49:00 +00002139void Assembler::cdp(Coprocessor coproc,
2140 int opcode_1,
2141 CRegister crd,
2142 CRegister crn,
2143 CRegister crm,
2144 int opcode_2,
2145 Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002146 DCHECK(is_uint4(opcode_1) && is_uint3(opcode_2));
Steve Blocka7e24c12009-10-30 11:49:00 +00002147 emit(cond | B27 | B26 | B25 | (opcode_1 & 15)*B20 | crn.code()*B16 |
2148 crd.code()*B12 | coproc*B8 | (opcode_2 & 7)*B5 | crm.code());
2149}
2150
2151
2152void Assembler::cdp2(Coprocessor coproc,
2153 int opcode_1,
2154 CRegister crd,
2155 CRegister crn,
2156 CRegister crm,
2157 int opcode_2) { // v5 and above
Steve Block1e0659c2011-05-24 12:43:12 +01002158 cdp(coproc, opcode_1, crd, crn, crm, opcode_2, kSpecialCondition);
Steve Blocka7e24c12009-10-30 11:49:00 +00002159}
2160
2161
2162void Assembler::mcr(Coprocessor coproc,
2163 int opcode_1,
2164 Register rd,
2165 CRegister crn,
2166 CRegister crm,
2167 int opcode_2,
2168 Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002169 DCHECK(is_uint3(opcode_1) && is_uint3(opcode_2));
Steve Blocka7e24c12009-10-30 11:49:00 +00002170 emit(cond | B27 | B26 | B25 | (opcode_1 & 7)*B21 | crn.code()*B16 |
2171 rd.code()*B12 | coproc*B8 | (opcode_2 & 7)*B5 | B4 | crm.code());
2172}
2173
2174
2175void Assembler::mcr2(Coprocessor coproc,
2176 int opcode_1,
2177 Register rd,
2178 CRegister crn,
2179 CRegister crm,
2180 int opcode_2) { // v5 and above
Steve Block1e0659c2011-05-24 12:43:12 +01002181 mcr(coproc, opcode_1, rd, crn, crm, opcode_2, kSpecialCondition);
Steve Blocka7e24c12009-10-30 11:49:00 +00002182}
2183
2184
2185void Assembler::mrc(Coprocessor coproc,
2186 int opcode_1,
2187 Register rd,
2188 CRegister crn,
2189 CRegister crm,
2190 int opcode_2,
2191 Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002192 DCHECK(is_uint3(opcode_1) && is_uint3(opcode_2));
Steve Blocka7e24c12009-10-30 11:49:00 +00002193 emit(cond | B27 | B26 | B25 | (opcode_1 & 7)*B21 | L | crn.code()*B16 |
2194 rd.code()*B12 | coproc*B8 | (opcode_2 & 7)*B5 | B4 | crm.code());
2195}
2196
2197
2198void Assembler::mrc2(Coprocessor coproc,
2199 int opcode_1,
2200 Register rd,
2201 CRegister crn,
2202 CRegister crm,
2203 int opcode_2) { // v5 and above
Steve Block1e0659c2011-05-24 12:43:12 +01002204 mrc(coproc, opcode_1, rd, crn, crm, opcode_2, kSpecialCondition);
Steve Blocka7e24c12009-10-30 11:49:00 +00002205}
2206
2207
2208void Assembler::ldc(Coprocessor coproc,
2209 CRegister crd,
2210 const MemOperand& src,
2211 LFlag l,
2212 Condition cond) {
2213 addrmod5(cond | B27 | B26 | l | L | coproc*B8, crd, src);
2214}
2215
2216
2217void Assembler::ldc(Coprocessor coproc,
2218 CRegister crd,
2219 Register rn,
2220 int option,
2221 LFlag l,
2222 Condition cond) {
Andrei Popescu31002712010-02-23 13:46:05 +00002223 // Unindexed addressing.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002224 DCHECK(is_uint8(option));
Steve Blocka7e24c12009-10-30 11:49:00 +00002225 emit(cond | B27 | B26 | U | l | L | rn.code()*B16 | crd.code()*B12 |
2226 coproc*B8 | (option & 255));
2227}
2228
2229
2230void Assembler::ldc2(Coprocessor coproc,
2231 CRegister crd,
2232 const MemOperand& src,
2233 LFlag l) { // v5 and above
Steve Block1e0659c2011-05-24 12:43:12 +01002234 ldc(coproc, crd, src, l, kSpecialCondition);
Steve Blocka7e24c12009-10-30 11:49:00 +00002235}
2236
2237
2238void Assembler::ldc2(Coprocessor coproc,
2239 CRegister crd,
2240 Register rn,
2241 int option,
2242 LFlag l) { // v5 and above
Steve Block1e0659c2011-05-24 12:43:12 +01002243 ldc(coproc, crd, rn, option, l, kSpecialCondition);
Steve Blocka7e24c12009-10-30 11:49:00 +00002244}
2245
2246
Steve Blockd0582a62009-12-15 09:54:21 +00002247// Support for VFP.
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002248
Leon Clarked91b9f72010-01-27 17:25:45 +00002249void Assembler::vldr(const DwVfpRegister dst,
2250 const Register base,
2251 int offset,
2252 const Condition cond) {
2253 // Ddst = MEM(Rbase + offset).
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002254 // Instruction details available in ARM DDI 0406C.b, A8-924.
2255 // cond(31-28) | 1101(27-24)| U(23) | D(22) | 01(21-20) | Rbase(19-16) |
2256 // Vd(15-12) | 1011(11-8) | offset
Ben Murdochb0fe1622011-05-05 13:52:32 +01002257 int u = 1;
2258 if (offset < 0) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002259 CHECK(offset != kMinInt);
Ben Murdochb0fe1622011-05-05 13:52:32 +01002260 offset = -offset;
2261 u = 0;
2262 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002263 int vd, d;
2264 dst.split_code(&vd, &d);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002265
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002266 DCHECK(offset >= 0);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002267 if ((offset % 4) == 0 && (offset / 4) < 256) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002268 emit(cond | 0xD*B24 | u*B23 | d*B22 | B20 | base.code()*B16 | vd*B12 |
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002269 0xB*B8 | ((offset / 4) & 255));
2270 } else {
2271 // Larger offsets must be handled by computing the correct address
2272 // in the ip register.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002273 DCHECK(!base.is(ip));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002274 if (u == 1) {
2275 add(ip, base, Operand(offset));
2276 } else {
2277 sub(ip, base, Operand(offset));
2278 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002279 emit(cond | 0xD*B24 | d*B22 | B20 | ip.code()*B16 | vd*B12 | 0xB*B8);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002280 }
2281}
2282
2283
2284void Assembler::vldr(const DwVfpRegister dst,
2285 const MemOperand& operand,
2286 const Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002287 DCHECK(operand.am_ == Offset);
2288 if (operand.rm().is_valid()) {
2289 add(ip, operand.rn(),
2290 Operand(operand.rm(), operand.shift_op_, operand.shift_imm_));
2291 vldr(dst, ip, 0, cond);
2292 } else {
2293 vldr(dst, operand.rn(), operand.offset(), cond);
2294 }
Leon Clarked91b9f72010-01-27 17:25:45 +00002295}
2296
2297
Steve Block6ded16b2010-05-10 14:33:55 +01002298void Assembler::vldr(const SwVfpRegister dst,
2299 const Register base,
2300 int offset,
2301 const Condition cond) {
2302 // Sdst = MEM(Rbase + offset).
2303 // Instruction details available in ARM DDI 0406A, A8-628.
Ben Murdochb0fe1622011-05-05 13:52:32 +01002304 // cond(31-28) | 1101(27-24)| U001(23-20) | Rbase(19-16) |
Steve Block6ded16b2010-05-10 14:33:55 +01002305 // Vdst(15-12) | 1010(11-8) | offset
Ben Murdochb0fe1622011-05-05 13:52:32 +01002306 int u = 1;
2307 if (offset < 0) {
2308 offset = -offset;
2309 u = 0;
2310 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002311 int sd, d;
2312 dst.split_code(&sd, &d);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002313 DCHECK(offset >= 0);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002314
2315 if ((offset % 4) == 0 && (offset / 4) < 256) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01002316 emit(cond | u*B23 | d*B22 | 0xD1*B20 | base.code()*B16 | sd*B12 |
Steve Block6ded16b2010-05-10 14:33:55 +01002317 0xA*B8 | ((offset / 4) & 255));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002318 } 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 }
2327 emit(cond | d*B22 | 0xD1*B20 | ip.code()*B16 | sd*B12 | 0xA*B8);
2328 }
2329}
2330
2331
2332void Assembler::vldr(const SwVfpRegister 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 }
Steve Block6ded16b2010-05-10 14:33:55 +01002343}
2344
2345
Leon Clarked91b9f72010-01-27 17:25:45 +00002346void Assembler::vstr(const DwVfpRegister src,
2347 const Register base,
2348 int offset,
2349 const Condition cond) {
2350 // MEM(Rbase + offset) = Dsrc.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002351 // Instruction details available in ARM DDI 0406C.b, A8-1082.
2352 // cond(31-28) | 1101(27-24)| U(23) | D(22) | 00(21-20) | Rbase(19-16) |
2353 // Vd(15-12) | 1011(11-8) | (offset/4)
Ben Murdochb0fe1622011-05-05 13:52:32 +01002354 int u = 1;
2355 if (offset < 0) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002356 CHECK(offset != kMinInt);
Ben Murdochb0fe1622011-05-05 13:52:32 +01002357 offset = -offset;
2358 u = 0;
2359 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002360 DCHECK(offset >= 0);
2361 int vd, d;
2362 src.split_code(&vd, &d);
2363
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002364 if ((offset % 4) == 0 && (offset / 4) < 256) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002365 emit(cond | 0xD*B24 | u*B23 | d*B22 | base.code()*B16 | vd*B12 | 0xB*B8 |
2366 ((offset / 4) & 255));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002367 } else {
2368 // Larger offsets must be handled by computing the correct address
2369 // in the ip register.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002370 DCHECK(!base.is(ip));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002371 if (u == 1) {
2372 add(ip, base, Operand(offset));
2373 } else {
2374 sub(ip, base, Operand(offset));
2375 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002376 emit(cond | 0xD*B24 | d*B22 | ip.code()*B16 | vd*B12 | 0xB*B8);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002377 }
2378}
2379
2380
2381void Assembler::vstr(const DwVfpRegister src,
2382 const MemOperand& operand,
2383 const Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002384 DCHECK(operand.am_ == Offset);
2385 if (operand.rm().is_valid()) {
2386 add(ip, operand.rn(),
2387 Operand(operand.rm(), operand.shift_op_, operand.shift_imm_));
2388 vstr(src, ip, 0, cond);
2389 } else {
2390 vstr(src, operand.rn(), operand.offset(), cond);
2391 }
Leon Clarked91b9f72010-01-27 17:25:45 +00002392}
2393
2394
Iain Merrick75681382010-08-19 15:07:18 +01002395void Assembler::vstr(const SwVfpRegister src,
2396 const Register base,
2397 int offset,
2398 const Condition cond) {
2399 // MEM(Rbase + offset) = SSrc.
2400 // Instruction details available in ARM DDI 0406A, A8-786.
Ben Murdochb0fe1622011-05-05 13:52:32 +01002401 // cond(31-28) | 1101(27-24)| U000(23-20) | Rbase(19-16) |
Iain Merrick75681382010-08-19 15:07:18 +01002402 // Vdst(15-12) | 1010(11-8) | (offset/4)
Ben Murdochb0fe1622011-05-05 13:52:32 +01002403 int u = 1;
2404 if (offset < 0) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002405 CHECK(offset != kMinInt);
Ben Murdochb0fe1622011-05-05 13:52:32 +01002406 offset = -offset;
2407 u = 0;
2408 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002409 int sd, d;
2410 src.split_code(&sd, &d);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002411 DCHECK(offset >= 0);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002412 if ((offset % 4) == 0 && (offset / 4) < 256) {
2413 emit(cond | u*B23 | d*B22 | 0xD0*B20 | base.code()*B16 | sd*B12 |
2414 0xA*B8 | ((offset / 4) & 255));
2415 } 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 }
2424 emit(cond | d*B22 | 0xD0*B20 | ip.code()*B16 | sd*B12 | 0xA*B8);
2425 }
2426}
2427
2428
2429void Assembler::vstr(const SwVfpRegister 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 }
Iain Merrick75681382010-08-19 15:07:18 +01002440}
2441
2442
Ben Murdoch8b112d22011-06-08 16:22:53 +01002443void Assembler::vldm(BlockAddrMode am,
2444 Register base,
2445 DwVfpRegister first,
2446 DwVfpRegister last,
2447 Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002448 // Instruction details available in ARM DDI 0406C.b, A8-922.
Ben Murdoch8b112d22011-06-08 16:22:53 +01002449 // cond(31-28) | 110(27-25)| PUDW1(24-20) | Rbase(19-16) |
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002450 // first(15-12) | 1011(11-8) | (count * 2)
2451 DCHECK_LE(first.code(), last.code());
2452 DCHECK(am == ia || am == ia_w || am == db_w);
2453 DCHECK(!base.is(pc));
Ben Murdoch8b112d22011-06-08 16:22:53 +01002454
2455 int sd, d;
2456 first.split_code(&sd, &d);
2457 int count = last.code() - first.code() + 1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002458 DCHECK(count <= 16);
Ben Murdoch8b112d22011-06-08 16:22:53 +01002459 emit(cond | B27 | B26 | am | d*B22 | B20 | base.code()*B16 | sd*B12 |
2460 0xB*B8 | count*2);
2461}
2462
2463
2464void Assembler::vstm(BlockAddrMode am,
2465 Register base,
2466 DwVfpRegister first,
2467 DwVfpRegister last,
2468 Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002469 // Instruction details available in ARM DDI 0406C.b, A8-1080.
Ben Murdoch8b112d22011-06-08 16:22:53 +01002470 // cond(31-28) | 110(27-25)| PUDW0(24-20) | Rbase(19-16) |
2471 // first(15-12) | 1011(11-8) | (count * 2)
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002472 DCHECK_LE(first.code(), last.code());
2473 DCHECK(am == ia || am == ia_w || am == db_w);
2474 DCHECK(!base.is(pc));
Ben Murdoch8b112d22011-06-08 16:22:53 +01002475
2476 int sd, d;
2477 first.split_code(&sd, &d);
2478 int count = last.code() - first.code() + 1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002479 DCHECK(count <= 16);
Ben Murdoch8b112d22011-06-08 16:22:53 +01002480 emit(cond | B27 | B26 | am | d*B22 | base.code()*B16 | sd*B12 |
2481 0xB*B8 | count*2);
2482}
2483
2484void Assembler::vldm(BlockAddrMode am,
2485 Register base,
2486 SwVfpRegister first,
2487 SwVfpRegister last,
2488 Condition cond) {
2489 // Instruction details available in ARM DDI 0406A, A8-626.
2490 // cond(31-28) | 110(27-25)| PUDW1(24-20) | Rbase(19-16) |
2491 // first(15-12) | 1010(11-8) | (count/2)
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002492 DCHECK_LE(first.code(), last.code());
2493 DCHECK(am == ia || am == ia_w || am == db_w);
2494 DCHECK(!base.is(pc));
Ben Murdoch8b112d22011-06-08 16:22:53 +01002495
2496 int sd, d;
2497 first.split_code(&sd, &d);
2498 int count = last.code() - first.code() + 1;
2499 emit(cond | B27 | B26 | am | d*B22 | B20 | base.code()*B16 | sd*B12 |
2500 0xA*B8 | count);
2501}
2502
2503
2504void Assembler::vstm(BlockAddrMode am,
2505 Register base,
2506 SwVfpRegister first,
2507 SwVfpRegister last,
2508 Condition cond) {
2509 // Instruction details available in ARM DDI 0406A, A8-784.
2510 // cond(31-28) | 110(27-25)| PUDW0(24-20) | Rbase(19-16) |
2511 // first(15-12) | 1011(11-8) | (count/2)
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002512 DCHECK_LE(first.code(), last.code());
2513 DCHECK(am == ia || am == ia_w || am == db_w);
2514 DCHECK(!base.is(pc));
Ben Murdoch8b112d22011-06-08 16:22:53 +01002515
2516 int sd, d;
2517 first.split_code(&sd, &d);
2518 int count = last.code() - first.code() + 1;
2519 emit(cond | B27 | B26 | am | d*B22 | base.code()*B16 | sd*B12 |
2520 0xA*B8 | count);
2521}
2522
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002523
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002524void Assembler::vmov(const SwVfpRegister dst, float imm) {
2525 mov(ip, Operand(bit_cast<int32_t>(imm)));
2526 vmov(dst, ip);
2527}
2528
2529
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002530static void DoubleAsTwoUInt32(double d, uint32_t* lo, uint32_t* hi) {
2531 uint64_t i;
2532 memcpy(&i, &d, 8);
2533
2534 *lo = i & 0xffffffff;
2535 *hi = i >> 32;
2536}
2537
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002538
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002539// Only works for little endian floating point formats.
2540// We don't support VFP on the mixed endian floating point platform.
2541static bool FitsVMOVDoubleImmediate(double d, uint32_t *encoding) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002542 DCHECK(CpuFeatures::IsSupported(VFP3));
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002543
2544 // VMOV can accept an immediate of the form:
2545 //
2546 // +/- m * 2^(-n) where 16 <= m <= 31 and 0 <= n <= 7
2547 //
2548 // The immediate is encoded using an 8-bit quantity, comprised of two
2549 // 4-bit fields. For an 8-bit immediate of the form:
2550 //
2551 // [abcdefgh]
2552 //
2553 // where a is the MSB and h is the LSB, an immediate 64-bit double can be
2554 // created of the form:
2555 //
2556 // [aBbbbbbb,bbcdefgh,00000000,00000000,
2557 // 00000000,00000000,00000000,00000000]
2558 //
2559 // where B = ~b.
2560 //
2561
2562 uint32_t lo, hi;
2563 DoubleAsTwoUInt32(d, &lo, &hi);
2564
2565 // The most obvious constraint is the long block of zeroes.
2566 if ((lo != 0) || ((hi & 0xffff) != 0)) {
2567 return false;
2568 }
2569
2570 // Bits 62:55 must be all clear or all set.
2571 if (((hi & 0x3fc00000) != 0) && ((hi & 0x3fc00000) != 0x3fc00000)) {
2572 return false;
2573 }
2574
2575 // Bit 63 must be NOT bit 62.
2576 if (((hi ^ (hi << 1)) & (0x40000000)) == 0) {
2577 return false;
2578 }
2579
2580 // Create the encoded immediate in the form:
2581 // [00000000,0000abcd,00000000,0000efgh]
2582 *encoding = (hi >> 16) & 0xf; // Low nybble.
2583 *encoding |= (hi >> 4) & 0x70000; // Low three bits of the high nybble.
2584 *encoding |= (hi >> 12) & 0x80000; // Top bit of the high nybble.
2585
2586 return true;
2587}
2588
2589
2590void Assembler::vmov(const DwVfpRegister dst,
2591 double imm,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002592 const Register scratch) {
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002593 uint32_t enc;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002594 // If the embedded constant pool is disabled, we can use the normal, inline
2595 // constant pool. If the embedded constant pool is enabled (via
2596 // FLAG_enable_embedded_constant_pool), we can only use it where the pool
2597 // pointer (pp) is valid.
2598 bool can_use_pool =
2599 !FLAG_enable_embedded_constant_pool || is_constant_pool_available();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002600 if (CpuFeatures::IsSupported(VFP3) && FitsVMOVDoubleImmediate(imm, &enc)) {
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002601 // The double can be encoded in the instruction.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002602 //
2603 // Dd = immediate
2604 // Instruction details available in ARM DDI 0406C.b, A8-936.
2605 // cond(31-28) | 11101(27-23) | D(22) | 11(21-20) | imm4H(19-16) |
2606 // Vd(15-12) | 101(11-9) | sz=1(8) | imm4L(3-0)
2607 int vd, d;
2608 dst.split_code(&vd, &d);
2609 emit(al | 0x1D*B23 | d*B22 | 0x3*B20 | vd*B12 | 0x5*B9 | B8 | enc);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002610 } else if (FLAG_enable_vldr_imm && can_use_pool) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002611 // TODO(jfb) Temporarily turned off until we have constant blinding or
2612 // some equivalent mitigation: an attacker can otherwise control
2613 // generated data which also happens to be executable, a Very Bad
2614 // Thing indeed.
2615 // Blinding gets tricky because we don't have xor, we probably
2616 // need to add/subtract without losing precision, which requires a
2617 // cookie value that Lithium is probably better positioned to
2618 // choose.
2619 // We could also add a few peepholes here like detecting 0.0 and
2620 // -0.0 and doing a vmov from the sequestered d14, forcing denorms
2621 // to zero (we set flush-to-zero), and normalizing NaN values.
2622 // We could also detect redundant values.
2623 // The code could also randomize the order of values, though
2624 // that's tricky because vldr has a limited reach. Furthermore
2625 // it breaks load locality.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002626 ConstantPoolEntry::Access access = ConstantPoolAddEntry(pc_offset(), imm);
2627 if (access == ConstantPoolEntry::OVERFLOWED) {
2628 DCHECK(FLAG_enable_embedded_constant_pool);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002629 // Emit instructions to load constant pool offset.
2630 movw(ip, 0);
2631 movt(ip, 0);
2632 // Load from constant pool at offset.
2633 vldr(dst, MemOperand(pp, ip));
2634 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002635 DCHECK(access == ConstantPoolEntry::REGULAR);
2636 vldr(dst, MemOperand(FLAG_enable_embedded_constant_pool ? pp : pc, 0));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002637 }
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002638 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002639 // Synthesise the double from ARM immediates.
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002640 uint32_t lo, hi;
2641 DoubleAsTwoUInt32(imm, &lo, &hi);
2642
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002643 if (lo == hi) {
2644 // Move the low and high parts of the double to a D register in one
2645 // instruction.
2646 mov(ip, Operand(lo));
2647 vmov(dst, ip, ip);
2648 } else if (scratch.is(no_reg)) {
2649 mov(ip, Operand(lo));
2650 vmov(dst, VmovIndexLo, ip);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002651 if (((lo & 0xffff) == (hi & 0xffff)) &&
2652 CpuFeatures::IsSupported(ARMv7)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002653 movt(ip, hi >> 16);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002654 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002655 mov(ip, Operand(hi));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002656 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002657 vmov(dst, VmovIndexHi, ip);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002658 } else {
2659 // Move the low and high parts of the double to a D register in one
2660 // instruction.
2661 mov(ip, Operand(lo));
2662 mov(scratch, Operand(hi));
2663 vmov(dst, ip, scratch);
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002664 }
2665 }
2666}
2667
2668
2669void Assembler::vmov(const SwVfpRegister dst,
2670 const SwVfpRegister src,
2671 const Condition cond) {
2672 // Sd = Sm
2673 // Instruction details available in ARM DDI 0406B, A8-642.
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002674 int sd, d, sm, m;
2675 dst.split_code(&sd, &d);
2676 src.split_code(&sm, &m);
2677 emit(cond | 0xE*B24 | d*B22 | 0xB*B20 | sd*B12 | 0xA*B8 | B6 | m*B5 | sm);
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002678}
2679
2680
Leon Clarkee46be812010-01-19 14:06:41 +00002681void Assembler::vmov(const DwVfpRegister dst,
Steve Block8defd9f2010-07-08 12:39:36 +01002682 const DwVfpRegister src,
2683 const Condition cond) {
2684 // Dd = Dm
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002685 // Instruction details available in ARM DDI 0406C.b, A8-938.
2686 // cond(31-28) | 11101(27-23) | D(22) | 11(21-20) | 0000(19-16) | Vd(15-12) |
2687 // 101(11-9) | sz=1(8) | 0(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
2688 int vd, d;
2689 dst.split_code(&vd, &d);
2690 int vm, m;
2691 src.split_code(&vm, &m);
2692 emit(cond | 0x1D*B23 | d*B22 | 0x3*B20 | vd*B12 | 0x5*B9 | B8 | B6 | m*B5 |
2693 vm);
2694}
2695
2696
2697void Assembler::vmov(const DwVfpRegister dst,
2698 const VmovIndex index,
2699 const Register src,
2700 const Condition cond) {
2701 // Dd[index] = Rt
2702 // Instruction details available in ARM DDI 0406C.b, A8-940.
2703 // cond(31-28) | 1110(27-24) | 0(23) | opc1=0index(22-21) | 0(20) |
2704 // Vd(19-16) | Rt(15-12) | 1011(11-8) | D(7) | opc2=00(6-5) | 1(4) | 0000(3-0)
2705 DCHECK(index.index == 0 || index.index == 1);
2706 int vd, d;
2707 dst.split_code(&vd, &d);
2708 emit(cond | 0xE*B24 | index.index*B21 | vd*B16 | src.code()*B12 | 0xB*B8 |
2709 d*B7 | B4);
2710}
2711
2712
2713void Assembler::vmov(const Register dst,
2714 const VmovIndex index,
2715 const DwVfpRegister src,
2716 const Condition cond) {
2717 // Dd[index] = Rt
2718 // Instruction details available in ARM DDI 0406C.b, A8.8.342.
2719 // cond(31-28) | 1110(27-24) | U=0(23) | opc1=0index(22-21) | 1(20) |
2720 // Vn(19-16) | Rt(15-12) | 1011(11-8) | N(7) | opc2=00(6-5) | 1(4) | 0000(3-0)
2721 DCHECK(index.index == 0 || index.index == 1);
2722 int vn, n;
2723 src.split_code(&vn, &n);
2724 emit(cond | 0xE*B24 | index.index*B21 | B20 | vn*B16 | dst.code()*B12 |
2725 0xB*B8 | n*B7 | B4);
Steve Block8defd9f2010-07-08 12:39:36 +01002726}
2727
2728
2729void Assembler::vmov(const DwVfpRegister dst,
Leon Clarkee46be812010-01-19 14:06:41 +00002730 const Register src1,
2731 const Register src2,
2732 const Condition cond) {
Steve Blockd0582a62009-12-15 09:54:21 +00002733 // Dm = <Rt,Rt2>.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002734 // Instruction details available in ARM DDI 0406C.b, A8-948.
Steve Blockd0582a62009-12-15 09:54:21 +00002735 // cond(31-28) | 1100(27-24)| 010(23-21) | op=0(20) | Rt2(19-16) |
2736 // Rt(15-12) | 1011(11-8) | 00(7-6) | M(5) | 1(4) | Vm
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002737 DCHECK(!src1.is(pc) && !src2.is(pc));
2738 int vm, m;
2739 dst.split_code(&vm, &m);
Steve Blockd0582a62009-12-15 09:54:21 +00002740 emit(cond | 0xC*B24 | B22 | src2.code()*B16 |
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002741 src1.code()*B12 | 0xB*B8 | m*B5 | B4 | vm);
Steve Blockd0582a62009-12-15 09:54:21 +00002742}
2743
2744
Leon Clarkee46be812010-01-19 14:06:41 +00002745void Assembler::vmov(const Register dst1,
2746 const Register dst2,
2747 const DwVfpRegister src,
2748 const Condition cond) {
Steve Blockd0582a62009-12-15 09:54:21 +00002749 // <Rt,Rt2> = Dm.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002750 // Instruction details available in ARM DDI 0406C.b, A8-948.
Steve Blockd0582a62009-12-15 09:54:21 +00002751 // cond(31-28) | 1100(27-24)| 010(23-21) | op=1(20) | Rt2(19-16) |
2752 // Rt(15-12) | 1011(11-8) | 00(7-6) | M(5) | 1(4) | Vm
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002753 DCHECK(!dst1.is(pc) && !dst2.is(pc));
2754 int vm, m;
2755 src.split_code(&vm, &m);
Steve Blockd0582a62009-12-15 09:54:21 +00002756 emit(cond | 0xC*B24 | B22 | B20 | dst2.code()*B16 |
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002757 dst1.code()*B12 | 0xB*B8 | m*B5 | B4 | vm);
Steve Blockd0582a62009-12-15 09:54:21 +00002758}
2759
2760
Leon Clarkee46be812010-01-19 14:06:41 +00002761void Assembler::vmov(const SwVfpRegister dst,
Steve Blockd0582a62009-12-15 09:54:21 +00002762 const Register src,
Steve Blockd0582a62009-12-15 09:54:21 +00002763 const Condition cond) {
2764 // Sn = Rt.
2765 // Instruction details available in ARM DDI 0406A, A8-642.
2766 // cond(31-28) | 1110(27-24)| 000(23-21) | op=0(20) | Vn(19-16) |
2767 // Rt(15-12) | 1010(11-8) | N(7)=0 | 00(6-5) | 1(4) | 0000(3-0)
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002768 DCHECK(!src.is(pc));
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002769 int sn, n;
2770 dst.split_code(&sn, &n);
2771 emit(cond | 0xE*B24 | sn*B16 | src.code()*B12 | 0xA*B8 | n*B7 | B4);
Steve Blockd0582a62009-12-15 09:54:21 +00002772}
2773
2774
Leon Clarkee46be812010-01-19 14:06:41 +00002775void Assembler::vmov(const Register dst,
2776 const SwVfpRegister src,
Steve Blockd0582a62009-12-15 09:54:21 +00002777 const Condition cond) {
2778 // Rt = Sn.
2779 // Instruction details available in ARM DDI 0406A, A8-642.
2780 // cond(31-28) | 1110(27-24)| 000(23-21) | op=1(20) | Vn(19-16) |
2781 // Rt(15-12) | 1010(11-8) | N(7)=0 | 00(6-5) | 1(4) | 0000(3-0)
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002782 DCHECK(!dst.is(pc));
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002783 int sn, n;
2784 src.split_code(&sn, &n);
2785 emit(cond | 0xE*B24 | B20 | sn*B16 | dst.code()*B12 | 0xA*B8 | n*B7 | B4);
Steve Blockd0582a62009-12-15 09:54:21 +00002786}
2787
2788
Steve Block6ded16b2010-05-10 14:33:55 +01002789// Type of data to read from or write to VFP register.
2790// Used as specifier in generic vcvt instruction.
2791enum VFPType { S32, U32, F32, F64 };
2792
2793
2794static bool IsSignedVFPType(VFPType type) {
2795 switch (type) {
2796 case S32:
2797 return true;
2798 case U32:
2799 return false;
2800 default:
2801 UNREACHABLE();
2802 return false;
2803 }
Steve Blockd0582a62009-12-15 09:54:21 +00002804}
2805
2806
Steve Block6ded16b2010-05-10 14:33:55 +01002807static bool IsIntegerVFPType(VFPType type) {
2808 switch (type) {
2809 case S32:
2810 case U32:
2811 return true;
2812 case F32:
2813 case F64:
2814 return false;
2815 default:
2816 UNREACHABLE();
2817 return false;
2818 }
2819}
2820
2821
2822static bool IsDoubleVFPType(VFPType type) {
2823 switch (type) {
2824 case F32:
2825 return false;
2826 case F64:
2827 return true;
2828 default:
2829 UNREACHABLE();
2830 return false;
2831 }
2832}
2833
2834
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002835// Split five bit reg_code based on size of reg_type.
2836// 32-bit register codes are Vm:M
2837// 64-bit register codes are M:Vm
2838// where Vm is four bits, and M is a single bit.
2839static void SplitRegCode(VFPType reg_type,
Steve Block6ded16b2010-05-10 14:33:55 +01002840 int reg_code,
2841 int* vm,
2842 int* m) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002843 DCHECK((reg_code >= 0) && (reg_code <= 31));
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002844 if (IsIntegerVFPType(reg_type) || !IsDoubleVFPType(reg_type)) {
2845 // 32 bit type.
Steve Block6ded16b2010-05-10 14:33:55 +01002846 *m = reg_code & 0x1;
2847 *vm = reg_code >> 1;
2848 } else {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002849 // 64 bit type.
Steve Block6ded16b2010-05-10 14:33:55 +01002850 *m = (reg_code & 0x10) >> 4;
2851 *vm = reg_code & 0x0F;
2852 }
2853}
2854
2855
2856// Encode vcvt.src_type.dst_type instruction.
2857static Instr EncodeVCVT(const VFPType dst_type,
2858 const int dst_code,
2859 const VFPType src_type,
2860 const int src_code,
Steve Block1e0659c2011-05-24 12:43:12 +01002861 VFPConversionMode mode,
Steve Block6ded16b2010-05-10 14:33:55 +01002862 const Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002863 DCHECK(src_type != dst_type);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002864 int D, Vd, M, Vm;
2865 SplitRegCode(src_type, src_code, &Vm, &M);
2866 SplitRegCode(dst_type, dst_code, &Vd, &D);
2867
Steve Block6ded16b2010-05-10 14:33:55 +01002868 if (IsIntegerVFPType(dst_type) || IsIntegerVFPType(src_type)) {
2869 // Conversion between IEEE floating point and 32-bit integer.
2870 // Instruction details available in ARM DDI 0406B, A8.6.295.
2871 // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 1(19) | opc2(18-16) |
2872 // 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 +00002873 DCHECK(!IsIntegerVFPType(dst_type) || !IsIntegerVFPType(src_type));
Steve Block6ded16b2010-05-10 14:33:55 +01002874
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002875 int sz, opc2, op;
Steve Block6ded16b2010-05-10 14:33:55 +01002876
2877 if (IsIntegerVFPType(dst_type)) {
2878 opc2 = IsSignedVFPType(dst_type) ? 0x5 : 0x4;
2879 sz = IsDoubleVFPType(src_type) ? 0x1 : 0x0;
Russell Brenner90bac252010-11-18 13:33:46 -08002880 op = mode;
Steve Block6ded16b2010-05-10 14:33:55 +01002881 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002882 DCHECK(IsIntegerVFPType(src_type));
Steve Block6ded16b2010-05-10 14:33:55 +01002883 opc2 = 0x0;
2884 sz = IsDoubleVFPType(dst_type) ? 0x1 : 0x0;
2885 op = IsSignedVFPType(src_type) ? 0x1 : 0x0;
Steve Block6ded16b2010-05-10 14:33:55 +01002886 }
2887
2888 return (cond | 0xE*B24 | B23 | D*B22 | 0x3*B20 | B19 | opc2*B16 |
2889 Vd*B12 | 0x5*B9 | sz*B8 | op*B7 | B6 | M*B5 | Vm);
2890 } else {
2891 // Conversion between IEEE double and single precision.
2892 // Instruction details available in ARM DDI 0406B, A8.6.298.
2893 // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 0111(19-16) |
2894 // 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 +01002895 int sz = IsDoubleVFPType(src_type) ? 0x1 : 0x0;
Steve Block6ded16b2010-05-10 14:33:55 +01002896 return (cond | 0xE*B24 | B23 | D*B22 | 0x3*B20 | 0x7*B16 |
2897 Vd*B12 | 0x5*B9 | sz*B8 | B7 | B6 | M*B5 | Vm);
2898 }
2899}
2900
2901
2902void Assembler::vcvt_f64_s32(const DwVfpRegister dst,
2903 const SwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +01002904 VFPConversionMode mode,
Steve Block6ded16b2010-05-10 14:33:55 +01002905 const Condition cond) {
Russell Brenner90bac252010-11-18 13:33:46 -08002906 emit(EncodeVCVT(F64, dst.code(), S32, src.code(), mode, cond));
Steve Block6ded16b2010-05-10 14:33:55 +01002907}
2908
2909
2910void Assembler::vcvt_f32_s32(const SwVfpRegister dst,
2911 const SwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +01002912 VFPConversionMode mode,
Steve Block6ded16b2010-05-10 14:33:55 +01002913 const Condition cond) {
Russell Brenner90bac252010-11-18 13:33:46 -08002914 emit(EncodeVCVT(F32, dst.code(), S32, src.code(), mode, cond));
Steve Block6ded16b2010-05-10 14:33:55 +01002915}
2916
2917
2918void Assembler::vcvt_f64_u32(const DwVfpRegister dst,
2919 const SwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +01002920 VFPConversionMode mode,
Steve Block6ded16b2010-05-10 14:33:55 +01002921 const Condition cond) {
Russell Brenner90bac252010-11-18 13:33:46 -08002922 emit(EncodeVCVT(F64, dst.code(), U32, src.code(), mode, cond));
Steve Block6ded16b2010-05-10 14:33:55 +01002923}
2924
2925
2926void Assembler::vcvt_s32_f64(const SwVfpRegister dst,
2927 const DwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +01002928 VFPConversionMode mode,
Steve Block6ded16b2010-05-10 14:33:55 +01002929 const Condition cond) {
Russell Brenner90bac252010-11-18 13:33:46 -08002930 emit(EncodeVCVT(S32, dst.code(), F64, src.code(), mode, cond));
Steve Block6ded16b2010-05-10 14:33:55 +01002931}
2932
2933
2934void Assembler::vcvt_u32_f64(const SwVfpRegister dst,
2935 const DwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +01002936 VFPConversionMode mode,
Steve Block6ded16b2010-05-10 14:33:55 +01002937 const Condition cond) {
Russell Brenner90bac252010-11-18 13:33:46 -08002938 emit(EncodeVCVT(U32, dst.code(), F64, src.code(), mode, cond));
Steve Block6ded16b2010-05-10 14:33:55 +01002939}
2940
2941
2942void Assembler::vcvt_f64_f32(const DwVfpRegister dst,
2943 const SwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +01002944 VFPConversionMode mode,
Steve Block6ded16b2010-05-10 14:33:55 +01002945 const Condition cond) {
Russell Brenner90bac252010-11-18 13:33:46 -08002946 emit(EncodeVCVT(F64, dst.code(), F32, src.code(), mode, cond));
Steve Block6ded16b2010-05-10 14:33:55 +01002947}
2948
2949
2950void Assembler::vcvt_f32_f64(const SwVfpRegister dst,
2951 const DwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +01002952 VFPConversionMode mode,
Steve Block6ded16b2010-05-10 14:33:55 +01002953 const Condition cond) {
Russell Brenner90bac252010-11-18 13:33:46 -08002954 emit(EncodeVCVT(F32, dst.code(), F64, src.code(), mode, cond));
Steve Blockd0582a62009-12-15 09:54:21 +00002955}
2956
2957
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002958void Assembler::vcvt_f64_s32(const DwVfpRegister dst,
2959 int fraction_bits,
2960 const Condition cond) {
2961 // Instruction details available in ARM DDI 0406C.b, A8-874.
2962 // cond(31-28) | 11101(27-23) | D(22) | 11(21-20) | 1010(19-16) | Vd(15-12) |
2963 // 101(11-9) | sf=1(8) | sx=1(7) | 1(6) | i(5) | 0(4) | imm4(3-0)
2964 DCHECK(fraction_bits > 0 && fraction_bits <= 32);
2965 DCHECK(CpuFeatures::IsSupported(VFP3));
2966 int vd, d;
2967 dst.split_code(&vd, &d);
2968 int imm5 = 32 - fraction_bits;
2969 int i = imm5 & 1;
2970 int imm4 = (imm5 >> 1) & 0xf;
2971 emit(cond | 0xE*B24 | B23 | d*B22 | 0x3*B20 | B19 | 0x2*B16 |
2972 vd*B12 | 0x5*B9 | B8 | B7 | B6 | i*B5 | imm4);
2973}
2974
2975
Steve Block44f0eee2011-05-26 01:26:41 +01002976void Assembler::vneg(const DwVfpRegister dst,
2977 const DwVfpRegister src,
2978 const Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002979 // Instruction details available in ARM DDI 0406C.b, A8-968.
2980 // cond(31-28) | 11101(27-23) | D(22) | 11(21-20) | 0001(19-16) | Vd(15-12) |
2981 // 101(11-9) | sz=1(8) | 0(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
2982 int vd, d;
2983 dst.split_code(&vd, &d);
2984 int vm, m;
2985 src.split_code(&vm, &m);
2986
2987 emit(cond | 0x1D*B23 | d*B22 | 0x3*B20 | B16 | vd*B12 | 0x5*B9 | B8 | B6 |
2988 m*B5 | vm);
Steve Block44f0eee2011-05-26 01:26:41 +01002989}
2990
2991
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002992void Assembler::vneg(const SwVfpRegister dst, const SwVfpRegister src,
2993 const Condition cond) {
2994 // Instruction details available in ARM DDI 0406C.b, A8-968.
2995 // cond(31-28) | 11101(27-23) | D(22) | 11(21-20) | 0001(19-16) | Vd(15-12) |
2996 // 101(11-9) | sz=0(8) | 0(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
2997 int vd, d;
2998 dst.split_code(&vd, &d);
2999 int vm, m;
3000 src.split_code(&vm, &m);
3001
3002 emit(cond | 0x1D * B23 | d * B22 | 0x3 * B20 | B16 | vd * B12 | 0x5 * B9 |
3003 B6 | m * B5 | vm);
3004}
3005
3006
Steve Block1e0659c2011-05-24 12:43:12 +01003007void Assembler::vabs(const DwVfpRegister dst,
3008 const DwVfpRegister src,
3009 const Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003010 // Instruction details available in ARM DDI 0406C.b, A8-524.
3011 // cond(31-28) | 11101(27-23) | D(22) | 11(21-20) | 0000(19-16) | Vd(15-12) |
3012 // 101(11-9) | sz=1(8) | 1(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
3013 int vd, d;
3014 dst.split_code(&vd, &d);
3015 int vm, m;
3016 src.split_code(&vm, &m);
3017 emit(cond | 0x1D*B23 | d*B22 | 0x3*B20 | vd*B12 | 0x5*B9 | B8 | B7 | B6 |
3018 m*B5 | vm);
Steve Block1e0659c2011-05-24 12:43:12 +01003019}
3020
3021
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003022void Assembler::vabs(const SwVfpRegister dst, const SwVfpRegister src,
3023 const Condition cond) {
3024 // Instruction details available in ARM DDI 0406C.b, A8-524.
3025 // cond(31-28) | 11101(27-23) | D(22) | 11(21-20) | 0000(19-16) | Vd(15-12) |
3026 // 101(11-9) | sz=0(8) | 1(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
3027 int vd, d;
3028 dst.split_code(&vd, &d);
3029 int vm, m;
3030 src.split_code(&vm, &m);
3031 emit(cond | 0x1D * B23 | d * B22 | 0x3 * B20 | vd * B12 | 0x5 * B9 | B7 | B6 |
3032 m * B5 | vm);
3033}
3034
3035
Leon Clarkee46be812010-01-19 14:06:41 +00003036void Assembler::vadd(const DwVfpRegister dst,
3037 const DwVfpRegister src1,
3038 const DwVfpRegister src2,
3039 const Condition cond) {
3040 // Dd = vadd(Dn, Dm) double precision floating point addition.
Steve Blockd0582a62009-12-15 09:54:21 +00003041 // Dd = D:Vd; Dm=M:Vm; Dn=N:Vm.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003042 // Instruction details available in ARM DDI 0406C.b, A8-830.
3043 // cond(31-28) | 11100(27-23)| D(22) | 11(21-20) | Vn(19-16) |
3044 // Vd(15-12) | 101(11-9) | sz=1(8) | N(7) | 0(6) | M(5) | 0(4) | Vm(3-0)
3045 int vd, d;
3046 dst.split_code(&vd, &d);
3047 int vn, n;
3048 src1.split_code(&vn, &n);
3049 int vm, m;
3050 src2.split_code(&vm, &m);
3051 emit(cond | 0x1C*B23 | d*B22 | 0x3*B20 | vn*B16 | vd*B12 | 0x5*B9 | B8 |
3052 n*B7 | m*B5 | vm);
Steve Blockd0582a62009-12-15 09:54:21 +00003053}
3054
3055
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003056void Assembler::vadd(const SwVfpRegister dst, const SwVfpRegister src1,
3057 const SwVfpRegister src2, const Condition cond) {
3058 // Sd = vadd(Sn, Sm) single precision floating point addition.
3059 // Sd = D:Vd; Sm=M:Vm; Sn=N:Vm.
3060 // Instruction details available in ARM DDI 0406C.b, A8-830.
3061 // cond(31-28) | 11100(27-23)| D(22) | 11(21-20) | Vn(19-16) |
3062 // Vd(15-12) | 101(11-9) | sz=0(8) | N(7) | 0(6) | M(5) | 0(4) | Vm(3-0)
3063 int vd, d;
3064 dst.split_code(&vd, &d);
3065 int vn, n;
3066 src1.split_code(&vn, &n);
3067 int vm, m;
3068 src2.split_code(&vm, &m);
3069 emit(cond | 0x1C * B23 | d * B22 | 0x3 * B20 | vn * B16 | vd * B12 |
3070 0x5 * B9 | n * B7 | m * B5 | vm);
3071}
3072
3073
Leon Clarkee46be812010-01-19 14:06:41 +00003074void Assembler::vsub(const DwVfpRegister dst,
3075 const DwVfpRegister src1,
3076 const DwVfpRegister src2,
3077 const Condition cond) {
3078 // Dd = vsub(Dn, Dm) double precision floating point subtraction.
Steve Blockd0582a62009-12-15 09:54:21 +00003079 // Dd = D:Vd; Dm=M:Vm; Dn=N:Vm.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003080 // Instruction details available in ARM DDI 0406C.b, A8-1086.
3081 // cond(31-28) | 11100(27-23)| D(22) | 11(21-20) | Vn(19-16) |
3082 // Vd(15-12) | 101(11-9) | sz=1(8) | N(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
3083 int vd, d;
3084 dst.split_code(&vd, &d);
3085 int vn, n;
3086 src1.split_code(&vn, &n);
3087 int vm, m;
3088 src2.split_code(&vm, &m);
3089 emit(cond | 0x1C*B23 | d*B22 | 0x3*B20 | vn*B16 | vd*B12 | 0x5*B9 | B8 |
3090 n*B7 | B6 | m*B5 | vm);
Steve Blockd0582a62009-12-15 09:54:21 +00003091}
3092
3093
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003094void Assembler::vsub(const SwVfpRegister dst, const SwVfpRegister src1,
3095 const SwVfpRegister src2, const Condition cond) {
3096 // Sd = vsub(Sn, Sm) single precision floating point subtraction.
3097 // Sd = D:Vd; Sm=M:Vm; Sn=N:Vm.
3098 // Instruction details available in ARM DDI 0406C.b, A8-1086.
3099 // cond(31-28) | 11100(27-23)| D(22) | 11(21-20) | Vn(19-16) |
3100 // Vd(15-12) | 101(11-9) | sz=0(8) | N(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
3101 int vd, d;
3102 dst.split_code(&vd, &d);
3103 int vn, n;
3104 src1.split_code(&vn, &n);
3105 int vm, m;
3106 src2.split_code(&vm, &m);
3107 emit(cond | 0x1C * B23 | d * B22 | 0x3 * B20 | vn * B16 | vd * B12 |
3108 0x5 * B9 | n * B7 | B6 | m * B5 | vm);
3109}
3110
3111
Leon Clarkee46be812010-01-19 14:06:41 +00003112void Assembler::vmul(const DwVfpRegister dst,
3113 const DwVfpRegister src1,
3114 const DwVfpRegister src2,
3115 const Condition cond) {
3116 // Dd = vmul(Dn, Dm) double precision floating point multiplication.
Steve Blockd0582a62009-12-15 09:54:21 +00003117 // Dd = D:Vd; Dm=M:Vm; Dn=N:Vm.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003118 // Instruction details available in ARM DDI 0406C.b, A8-960.
3119 // cond(31-28) | 11100(27-23)| D(22) | 10(21-20) | Vn(19-16) |
3120 // Vd(15-12) | 101(11-9) | sz=1(8) | N(7) | 0(6) | M(5) | 0(4) | Vm(3-0)
3121 int vd, d;
3122 dst.split_code(&vd, &d);
3123 int vn, n;
3124 src1.split_code(&vn, &n);
3125 int vm, m;
3126 src2.split_code(&vm, &m);
3127 emit(cond | 0x1C*B23 | d*B22 | 0x2*B20 | vn*B16 | vd*B12 | 0x5*B9 | B8 |
3128 n*B7 | m*B5 | vm);
3129}
3130
3131
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003132void Assembler::vmul(const SwVfpRegister dst, const SwVfpRegister src1,
3133 const SwVfpRegister src2, const Condition cond) {
3134 // Sd = vmul(Sn, Sm) single precision floating point multiplication.
3135 // Sd = D:Vd; Sm=M:Vm; Sn=N:Vm.
3136 // Instruction details available in ARM DDI 0406C.b, A8-960.
3137 // cond(31-28) | 11100(27-23)| D(22) | 10(21-20) | Vn(19-16) |
3138 // Vd(15-12) | 101(11-9) | sz=0(8) | N(7) | 0(6) | M(5) | 0(4) | Vm(3-0)
3139 int vd, d;
3140 dst.split_code(&vd, &d);
3141 int vn, n;
3142 src1.split_code(&vn, &n);
3143 int vm, m;
3144 src2.split_code(&vm, &m);
3145 emit(cond | 0x1C * B23 | d * B22 | 0x2 * B20 | vn * B16 | vd * B12 |
3146 0x5 * B9 | n * B7 | m * B5 | vm);
3147}
3148
3149
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003150void Assembler::vmla(const DwVfpRegister dst,
3151 const DwVfpRegister src1,
3152 const DwVfpRegister src2,
3153 const Condition cond) {
3154 // Instruction details available in ARM DDI 0406C.b, A8-932.
3155 // cond(31-28) | 11100(27-23) | D(22) | 00(21-20) | Vn(19-16) |
3156 // Vd(15-12) | 101(11-9) | sz=1(8) | N(7) | op=0(6) | M(5) | 0(4) | Vm(3-0)
3157 int vd, d;
3158 dst.split_code(&vd, &d);
3159 int vn, n;
3160 src1.split_code(&vn, &n);
3161 int vm, m;
3162 src2.split_code(&vm, &m);
3163 emit(cond | 0x1C*B23 | d*B22 | vn*B16 | vd*B12 | 0x5*B9 | B8 | n*B7 | m*B5 |
3164 vm);
3165}
3166
3167
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003168void Assembler::vmla(const SwVfpRegister dst, const SwVfpRegister src1,
3169 const SwVfpRegister src2, const Condition cond) {
3170 // Instruction details available in ARM DDI 0406C.b, A8-932.
3171 // cond(31-28) | 11100(27-23) | D(22) | 00(21-20) | Vn(19-16) |
3172 // Vd(15-12) | 101(11-9) | sz=0(8) | N(7) | op=0(6) | M(5) | 0(4) | Vm(3-0)
3173 int vd, d;
3174 dst.split_code(&vd, &d);
3175 int vn, n;
3176 src1.split_code(&vn, &n);
3177 int vm, m;
3178 src2.split_code(&vm, &m);
3179 emit(cond | 0x1C * B23 | d * B22 | vn * B16 | vd * B12 | 0x5 * B9 | n * B7 |
3180 m * B5 | vm);
3181}
3182
3183
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003184void Assembler::vmls(const DwVfpRegister dst,
3185 const DwVfpRegister src1,
3186 const DwVfpRegister src2,
3187 const Condition cond) {
3188 // Instruction details available in ARM DDI 0406C.b, A8-932.
3189 // cond(31-28) | 11100(27-23) | D(22) | 00(21-20) | Vn(19-16) |
3190 // Vd(15-12) | 101(11-9) | sz=1(8) | N(7) | op=1(6) | M(5) | 0(4) | Vm(3-0)
3191 int vd, d;
3192 dst.split_code(&vd, &d);
3193 int vn, n;
3194 src1.split_code(&vn, &n);
3195 int vm, m;
3196 src2.split_code(&vm, &m);
3197 emit(cond | 0x1C*B23 | d*B22 | vn*B16 | vd*B12 | 0x5*B9 | B8 | n*B7 | B6 |
3198 m*B5 | vm);
Steve Blockd0582a62009-12-15 09:54:21 +00003199}
3200
3201
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003202void Assembler::vmls(const SwVfpRegister dst, const SwVfpRegister src1,
3203 const SwVfpRegister src2, const Condition cond) {
3204 // Instruction details available in ARM DDI 0406C.b, A8-932.
3205 // cond(31-28) | 11100(27-23) | D(22) | 00(21-20) | Vn(19-16) |
3206 // Vd(15-12) | 101(11-9) | sz=0(8) | N(7) | op=1(6) | M(5) | 0(4) | Vm(3-0)
3207 int vd, d;
3208 dst.split_code(&vd, &d);
3209 int vn, n;
3210 src1.split_code(&vn, &n);
3211 int vm, m;
3212 src2.split_code(&vm, &m);
3213 emit(cond | 0x1C * B23 | d * B22 | vn * B16 | vd * B12 | 0x5 * B9 | n * B7 |
3214 B6 | m * B5 | vm);
3215}
3216
3217
Leon Clarkee46be812010-01-19 14:06:41 +00003218void Assembler::vdiv(const DwVfpRegister dst,
3219 const DwVfpRegister src1,
3220 const DwVfpRegister src2,
3221 const Condition cond) {
3222 // Dd = vdiv(Dn, Dm) double precision floating point division.
Steve Blockd0582a62009-12-15 09:54:21 +00003223 // Dd = D:Vd; Dm=M:Vm; Dn=N:Vm.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003224 // Instruction details available in ARM DDI 0406C.b, A8-882.
3225 // cond(31-28) | 11101(27-23)| D(22) | 00(21-20) | Vn(19-16) |
3226 // Vd(15-12) | 101(11-9) | sz=1(8) | N(7) | 0(6) | M(5) | 0(4) | Vm(3-0)
3227 int vd, d;
3228 dst.split_code(&vd, &d);
3229 int vn, n;
3230 src1.split_code(&vn, &n);
3231 int vm, m;
3232 src2.split_code(&vm, &m);
3233 emit(cond | 0x1D*B23 | d*B22 | vn*B16 | vd*B12 | 0x5*B9 | B8 | n*B7 | m*B5 |
3234 vm);
Steve Blockd0582a62009-12-15 09:54:21 +00003235}
3236
3237
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003238void Assembler::vdiv(const SwVfpRegister dst, const SwVfpRegister src1,
3239 const SwVfpRegister src2, const Condition cond) {
3240 // Sd = vdiv(Sn, Sm) single precision floating point division.
3241 // Sd = D:Vd; Sm=M:Vm; Sn=N:Vm.
3242 // Instruction details available in ARM DDI 0406C.b, A8-882.
3243 // cond(31-28) | 11101(27-23)| D(22) | 00(21-20) | Vn(19-16) |
3244 // Vd(15-12) | 101(11-9) | sz=0(8) | N(7) | 0(6) | M(5) | 0(4) | Vm(3-0)
3245 int vd, d;
3246 dst.split_code(&vd, &d);
3247 int vn, n;
3248 src1.split_code(&vn, &n);
3249 int vm, m;
3250 src2.split_code(&vm, &m);
3251 emit(cond | 0x1D * B23 | d * B22 | vn * B16 | vd * B12 | 0x5 * B9 | n * B7 |
3252 m * B5 | vm);
3253}
3254
3255
Leon Clarkee46be812010-01-19 14:06:41 +00003256void Assembler::vcmp(const DwVfpRegister src1,
3257 const DwVfpRegister src2,
Steve Blockd0582a62009-12-15 09:54:21 +00003258 const Condition cond) {
3259 // vcmp(Dd, Dm) double precision floating point comparison.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003260 // Instruction details available in ARM DDI 0406C.b, A8-864.
3261 // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 0100(19-16) |
3262 // Vd(15-12) | 101(11-9) | sz=1(8) | E=0(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
3263 int vd, d;
3264 src1.split_code(&vd, &d);
3265 int vm, m;
3266 src2.split_code(&vm, &m);
3267 emit(cond | 0x1D*B23 | d*B22 | 0x3*B20 | 0x4*B16 | vd*B12 | 0x5*B9 | B8 | B6 |
3268 m*B5 | vm);
Steve Blockd0582a62009-12-15 09:54:21 +00003269}
3270
3271
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003272void Assembler::vcmp(const SwVfpRegister src1, const SwVfpRegister src2,
3273 const Condition cond) {
3274 // vcmp(Sd, Sm) single precision floating point comparison.
3275 // Instruction details available in ARM DDI 0406C.b, A8-864.
3276 // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 0100(19-16) |
3277 // Vd(15-12) | 101(11-9) | sz=0(8) | E=0(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
3278 int vd, d;
3279 src1.split_code(&vd, &d);
3280 int vm, m;
3281 src2.split_code(&vm, &m);
3282 emit(cond | 0x1D * B23 | d * B22 | 0x3 * B20 | 0x4 * B16 | vd * B12 |
3283 0x5 * B9 | B6 | m * B5 | vm);
3284}
3285
3286
Iain Merrick75681382010-08-19 15:07:18 +01003287void Assembler::vcmp(const DwVfpRegister src1,
3288 const double src2,
Iain Merrick75681382010-08-19 15:07:18 +01003289 const Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003290 // vcmp(Dd, #0.0) double precision floating point comparison.
3291 // Instruction details available in ARM DDI 0406C.b, A8-864.
3292 // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 0101(19-16) |
3293 // Vd(15-12) | 101(11-9) | sz=1(8) | E=0(7) | 1(6) | 0(5) | 0(4) | 0000(3-0)
3294 DCHECK(src2 == 0.0);
3295 int vd, d;
3296 src1.split_code(&vd, &d);
3297 emit(cond | 0x1D*B23 | d*B22 | 0x3*B20 | 0x5*B16 | vd*B12 | 0x5*B9 | B8 | B6);
Iain Merrick75681382010-08-19 15:07:18 +01003298}
3299
3300
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003301void Assembler::vcmp(const SwVfpRegister src1, const float src2,
3302 const Condition cond) {
3303 // vcmp(Sd, #0.0) single precision floating point comparison.
3304 // Instruction details available in ARM DDI 0406C.b, A8-864.
3305 // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 0101(19-16) |
3306 // Vd(15-12) | 101(11-9) | sz=0(8) | E=0(7) | 1(6) | 0(5) | 0(4) | 0000(3-0)
3307 DCHECK(src2 == 0.0);
3308 int vd, d;
3309 src1.split_code(&vd, &d);
3310 emit(cond | 0x1D * B23 | d * B22 | 0x3 * B20 | 0x5 * B16 | vd * B12 |
3311 0x5 * B9 | B6);
Steve Blockd0582a62009-12-15 09:54:21 +00003312}
3313
3314
Steve Block8defd9f2010-07-08 12:39:36 +01003315void Assembler::vsqrt(const DwVfpRegister dst,
3316 const DwVfpRegister src,
3317 const Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003318 // Instruction details available in ARM DDI 0406C.b, A8-1058.
3319 // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 0001(19-16) |
3320 // Vd(15-12) | 101(11-9) | sz=1(8) | 11(7-6) | M(5) | 0(4) | Vm(3-0)
3321 int vd, d;
3322 dst.split_code(&vd, &d);
3323 int vm, m;
3324 src.split_code(&vm, &m);
3325 emit(cond | 0x1D*B23 | d*B22 | 0x3*B20 | B16 | vd*B12 | 0x5*B9 | B8 | 0x3*B6 |
3326 m*B5 | vm);
3327}
3328
3329
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003330void Assembler::vsqrt(const SwVfpRegister dst, const SwVfpRegister src,
3331 const Condition cond) {
3332 // Instruction details available in ARM DDI 0406C.b, A8-1058.
3333 // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 0001(19-16) |
3334 // Vd(15-12) | 101(11-9) | sz=0(8) | 11(7-6) | M(5) | 0(4) | Vm(3-0)
3335 int vd, d;
3336 dst.split_code(&vd, &d);
3337 int vm, m;
3338 src.split_code(&vm, &m);
3339 emit(cond | 0x1D * B23 | d * B22 | 0x3 * B20 | B16 | vd * B12 | 0x5 * B9 |
3340 0x3 * B6 | m * B5 | vm);
3341}
3342
3343
3344void Assembler::vmsr(Register dst, Condition cond) {
3345 // Instruction details available in ARM DDI 0406A, A8-652.
3346 // cond(31-28) | 1110 (27-24) | 1110(23-20)| 0001 (19-16) |
3347 // Rt(15-12) | 1010 (11-8) | 0(7) | 00 (6-5) | 1(4) | 0000(3-0)
3348 emit(cond | 0xE * B24 | 0xE * B20 | B16 | dst.code() * B12 | 0xA * B8 | B4);
3349}
3350
3351
3352void Assembler::vmrs(Register dst, Condition cond) {
3353 // Instruction details available in ARM DDI 0406A, A8-652.
3354 // cond(31-28) | 1110 (27-24) | 1111(23-20)| 0001 (19-16) |
3355 // Rt(15-12) | 1010 (11-8) | 0(7) | 00 (6-5) | 1(4) | 0000(3-0)
3356 emit(cond | 0xE * B24 | 0xF * B20 | B16 | dst.code() * B12 | 0xA * B8 | B4);
3357}
3358
3359
3360void Assembler::vrinta(const SwVfpRegister dst, const SwVfpRegister src) {
3361 // cond=kSpecialCondition(31-28) | 11101(27-23)| D(22) | 11(21-20) |
3362 // 10(19-18) | RM=00(17-16) | Vd(15-12) | 101(11-9) | sz=0(8) | 01(7-6) |
3363 // M(5) | 0(4) | Vm(3-0)
3364 DCHECK(CpuFeatures::IsSupported(ARMv8));
3365 int vd, d;
3366 dst.split_code(&vd, &d);
3367 int vm, m;
3368 src.split_code(&vm, &m);
3369 emit(kSpecialCondition | 0x1D * B23 | d * B22 | 0x3 * B20 | B19 | vd * B12 |
3370 0x5 * B9 | B6 | m * B5 | vm);
3371}
3372
3373
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003374void Assembler::vrinta(const DwVfpRegister dst, const DwVfpRegister src) {
3375 // cond=kSpecialCondition(31-28) | 11101(27-23)| D(22) | 11(21-20) |
3376 // 10(19-18) | RM=00(17-16) | Vd(15-12) | 101(11-9) | sz=1(8) | 01(7-6) |
3377 // M(5) | 0(4) | Vm(3-0)
3378 DCHECK(CpuFeatures::IsSupported(ARMv8));
3379 int vd, d;
3380 dst.split_code(&vd, &d);
3381 int vm, m;
3382 src.split_code(&vm, &m);
3383 emit(kSpecialCondition | 0x1D * B23 | d * B22 | 0x3 * B20 | B19 | vd * B12 |
3384 0x5 * B9 | B8 | B6 | m * B5 | vm);
3385}
3386
3387
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003388void Assembler::vrintn(const SwVfpRegister dst, const SwVfpRegister src) {
3389 // cond=kSpecialCondition(31-28) | 11101(27-23)| D(22) | 11(21-20) |
3390 // 10(19-18) | RM=01(17-16) | Vd(15-12) | 101(11-9) | sz=0(8) | 01(7-6) |
3391 // M(5) | 0(4) | Vm(3-0)
3392 DCHECK(CpuFeatures::IsSupported(ARMv8));
3393 int vd, d;
3394 dst.split_code(&vd, &d);
3395 int vm, m;
3396 src.split_code(&vm, &m);
3397 emit(kSpecialCondition | 0x1D * B23 | d * B22 | 0x3 * B20 | B19 | 0x1 * B16 |
3398 vd * B12 | 0x5 * B9 | B6 | m * B5 | vm);
3399}
3400
3401
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003402void Assembler::vrintn(const DwVfpRegister dst, const DwVfpRegister src) {
3403 // cond=kSpecialCondition(31-28) | 11101(27-23)| D(22) | 11(21-20) |
3404 // 10(19-18) | RM=01(17-16) | Vd(15-12) | 101(11-9) | sz=1(8) | 01(7-6) |
3405 // M(5) | 0(4) | Vm(3-0)
3406 DCHECK(CpuFeatures::IsSupported(ARMv8));
3407 int vd, d;
3408 dst.split_code(&vd, &d);
3409 int vm, m;
3410 src.split_code(&vm, &m);
3411 emit(kSpecialCondition | 0x1D * B23 | d * B22 | 0x3 * B20 | B19 | 0x1 * B16 |
3412 vd * B12 | 0x5 * B9 | B8 | B6 | m * B5 | vm);
3413}
3414
3415
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003416void Assembler::vrintp(const SwVfpRegister dst, const SwVfpRegister src) {
3417 // cond=kSpecialCondition(31-28) | 11101(27-23)| D(22) | 11(21-20) |
3418 // 10(19-18) | RM=10(17-16) | Vd(15-12) | 101(11-9) | sz=0(8) | 01(7-6) |
3419 // M(5) | 0(4) | Vm(3-0)
3420 DCHECK(CpuFeatures::IsSupported(ARMv8));
3421 int vd, d;
3422 dst.split_code(&vd, &d);
3423 int vm, m;
3424 src.split_code(&vm, &m);
3425 emit(kSpecialCondition | 0x1D * B23 | d * B22 | 0x3 * B20 | B19 | 0x2 * B16 |
3426 vd * B12 | 0x5 * B9 | B6 | m * B5 | vm);
3427}
3428
3429
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003430void Assembler::vrintp(const DwVfpRegister dst, const DwVfpRegister src) {
3431 // cond=kSpecialCondition(31-28) | 11101(27-23)| D(22) | 11(21-20) |
3432 // 10(19-18) | RM=10(17-16) | Vd(15-12) | 101(11-9) | sz=1(8) | 01(7-6) |
3433 // M(5) | 0(4) | Vm(3-0)
3434 DCHECK(CpuFeatures::IsSupported(ARMv8));
3435 int vd, d;
3436 dst.split_code(&vd, &d);
3437 int vm, m;
3438 src.split_code(&vm, &m);
3439 emit(kSpecialCondition | 0x1D * B23 | d * B22 | 0x3 * B20 | B19 | 0x2 * B16 |
3440 vd * B12 | 0x5 * B9 | B8 | B6 | m * B5 | vm);
3441}
3442
3443
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003444void Assembler::vrintm(const SwVfpRegister dst, const SwVfpRegister src) {
3445 // cond=kSpecialCondition(31-28) | 11101(27-23)| D(22) | 11(21-20) |
3446 // 10(19-18) | RM=11(17-16) | Vd(15-12) | 101(11-9) | sz=0(8) | 01(7-6) |
3447 // M(5) | 0(4) | Vm(3-0)
3448 DCHECK(CpuFeatures::IsSupported(ARMv8));
3449 int vd, d;
3450 dst.split_code(&vd, &d);
3451 int vm, m;
3452 src.split_code(&vm, &m);
3453 emit(kSpecialCondition | 0x1D * B23 | d * B22 | 0x3 * B20 | B19 | 0x3 * B16 |
3454 vd * B12 | 0x5 * B9 | B6 | m * B5 | vm);
3455}
3456
3457
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003458void Assembler::vrintm(const DwVfpRegister dst, const DwVfpRegister src) {
3459 // cond=kSpecialCondition(31-28) | 11101(27-23)| D(22) | 11(21-20) |
3460 // 10(19-18) | RM=11(17-16) | Vd(15-12) | 101(11-9) | sz=1(8) | 01(7-6) |
3461 // M(5) | 0(4) | Vm(3-0)
3462 DCHECK(CpuFeatures::IsSupported(ARMv8));
3463 int vd, d;
3464 dst.split_code(&vd, &d);
3465 int vm, m;
3466 src.split_code(&vm, &m);
3467 emit(kSpecialCondition | 0x1D * B23 | d * B22 | 0x3 * B20 | B19 | 0x3 * B16 |
3468 vd * B12 | 0x5 * B9 | B8 | B6 | m * B5 | vm);
3469}
3470
3471
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003472void Assembler::vrintz(const SwVfpRegister dst, const SwVfpRegister src,
3473 const Condition cond) {
3474 // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 011(19-17) | 0(16) |
3475 // Vd(15-12) | 101(11-9) | sz=0(8) | op=1(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
3476 DCHECK(CpuFeatures::IsSupported(ARMv8));
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 | 0x3 * B17 | vd * B12 |
3482 0x5 * B9 | B7 | B6 | m * B5 | vm);
3483}
3484
3485
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003486void Assembler::vrintz(const DwVfpRegister dst, const DwVfpRegister src,
3487 const Condition cond) {
3488 // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 011(19-17) | 0(16) |
3489 // Vd(15-12) | 101(11-9) | sz=1(8) | op=1(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
3490 DCHECK(CpuFeatures::IsSupported(ARMv8));
3491 int vd, d;
3492 dst.split_code(&vd, &d);
3493 int vm, m;
3494 src.split_code(&vm, &m);
3495 emit(cond | 0x1D * B23 | d * B22 | 0x3 * B20 | 0x3 * B17 | vd * B12 |
3496 0x5 * B9 | B8 | B7 | B6 | m * B5 | vm);
3497}
3498
3499
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003500// Support for NEON.
3501
3502void Assembler::vld1(NeonSize size,
3503 const NeonListOperand& dst,
3504 const NeonMemOperand& src) {
3505 // Instruction details available in ARM DDI 0406C.b, A8.8.320.
3506 // 1111(31-28) | 01000(27-23) | D(22) | 10(21-20) | Rn(19-16) |
3507 // Vd(15-12) | type(11-8) | size(7-6) | align(5-4) | Rm(3-0)
3508 DCHECK(CpuFeatures::IsSupported(NEON));
3509 int vd, d;
3510 dst.base().split_code(&vd, &d);
3511 emit(0xFU*B28 | 4*B24 | d*B22 | 2*B20 | src.rn().code()*B16 | vd*B12 |
3512 dst.type()*B8 | size*B6 | src.align()*B4 | src.rm().code());
3513}
3514
3515
3516void Assembler::vst1(NeonSize size,
3517 const NeonListOperand& src,
3518 const NeonMemOperand& dst) {
3519 // Instruction details available in ARM DDI 0406C.b, A8.8.404.
3520 // 1111(31-28) | 01000(27-23) | D(22) | 00(21-20) | Rn(19-16) |
3521 // Vd(15-12) | type(11-8) | size(7-6) | align(5-4) | Rm(3-0)
3522 DCHECK(CpuFeatures::IsSupported(NEON));
3523 int vd, d;
3524 src.base().split_code(&vd, &d);
3525 emit(0xFU*B28 | 4*B24 | d*B22 | dst.rn().code()*B16 | vd*B12 | src.type()*B8 |
3526 size*B6 | dst.align()*B4 | dst.rm().code());
3527}
3528
3529
3530void Assembler::vmovl(NeonDataType dt, QwNeonRegister dst, DwVfpRegister src) {
3531 // Instruction details available in ARM DDI 0406C.b, A8.8.346.
3532 // 1111(31-28) | 001(27-25) | U(24) | 1(23) | D(22) | imm3(21-19) |
3533 // 000(18-16) | Vd(15-12) | 101000(11-6) | M(5) | 1(4) | Vm(3-0)
3534 DCHECK(CpuFeatures::IsSupported(NEON));
3535 int vd, d;
3536 dst.split_code(&vd, &d);
3537 int vm, m;
3538 src.split_code(&vm, &m);
3539 emit(0xFU*B28 | B25 | (dt & NeonDataTypeUMask) | B23 | d*B22 |
3540 (dt & NeonDataTypeSizeMask)*B19 | vd*B12 | 0xA*B8 | m*B5 | B4 | vm);
Steve Block8defd9f2010-07-08 12:39:36 +01003541}
3542
3543
Andrei Popescu31002712010-02-23 13:46:05 +00003544// Pseudo instructions.
Steve Block6ded16b2010-05-10 14:33:55 +01003545void Assembler::nop(int type) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003546 // ARMv6{K/T2} and v7 have an actual NOP instruction but it serializes
3547 // some of the CPU's pipeline and has to issue. Older ARM chips simply used
3548 // MOV Rx, Rx as NOP and it performs better even in newer CPUs.
3549 // We therefore use MOV Rx, Rx, even on newer CPUs, and use Rx to encode
3550 // a type.
3551 DCHECK(0 <= type && type <= 14); // mov pc, pc isn't a nop.
Steve Block6ded16b2010-05-10 14:33:55 +01003552 emit(al | 13*B21 | type*B12 | type);
3553}
3554
3555
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003556bool Assembler::IsMovT(Instr instr) {
3557 instr &= ~(((kNumberOfConditions - 1) << 28) | // Mask off conditions
3558 ((kNumRegisters-1)*B12) | // mask out register
3559 EncodeMovwImmediate(0xFFFF)); // mask out immediate value
3560 return instr == kMovtPattern;
3561}
3562
3563
3564bool Assembler::IsMovW(Instr instr) {
3565 instr &= ~(((kNumberOfConditions - 1) << 28) | // Mask off conditions
3566 ((kNumRegisters-1)*B12) | // mask out destination
3567 EncodeMovwImmediate(0xFFFF)); // mask out immediate value
3568 return instr == kMovwPattern;
3569}
3570
3571
3572Instr Assembler::GetMovTPattern() { return kMovtPattern; }
3573
3574
3575Instr Assembler::GetMovWPattern() { return kMovwPattern; }
3576
3577
3578Instr Assembler::EncodeMovwImmediate(uint32_t immediate) {
3579 DCHECK(immediate < 0x10000);
3580 return ((immediate & 0xf000) << 4) | (immediate & 0xfff);
3581}
3582
3583
3584Instr Assembler::PatchMovwImmediate(Instr instruction, uint32_t immediate) {
3585 instruction &= ~EncodeMovwImmediate(0xffff);
3586 return instruction | EncodeMovwImmediate(immediate);
3587}
3588
3589
3590int Assembler::DecodeShiftImm(Instr instr) {
3591 int rotate = Instruction::RotateValue(instr) * 2;
3592 int immed8 = Instruction::Immed8Value(instr);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003593 return base::bits::RotateRight32(immed8, rotate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003594}
3595
3596
3597Instr Assembler::PatchShiftImm(Instr instr, int immed) {
3598 uint32_t rotate_imm = 0;
3599 uint32_t immed_8 = 0;
3600 bool immed_fits = fits_shifter(immed, &rotate_imm, &immed_8, NULL);
3601 DCHECK(immed_fits);
3602 USE(immed_fits);
3603 return (instr & ~kOff12Mask) | (rotate_imm << 8) | immed_8;
3604}
3605
3606
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08003607bool Assembler::IsNop(Instr instr, int type) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003608 DCHECK(0 <= type && type <= 14); // mov pc, pc isn't a nop.
Steve Block1e0659c2011-05-24 12:43:12 +01003609 // Check for mov rx, rx where x = type.
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08003610 return instr == (al | 13*B21 | type*B12 | type);
3611}
3612
3613
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003614bool Assembler::IsMovImmed(Instr instr) {
3615 return (instr & kMovImmedMask) == kMovImmedPattern;
3616}
3617
3618
3619bool Assembler::IsOrrImmed(Instr instr) {
3620 return (instr & kOrrImmedMask) == kOrrImmedPattern;
3621}
3622
3623
3624// static
Steve Blockd0582a62009-12-15 09:54:21 +00003625bool Assembler::ImmediateFitsAddrMode1Instruction(int32_t imm32) {
3626 uint32_t dummy1;
3627 uint32_t dummy2;
3628 return fits_shifter(imm32, &dummy1, &dummy2, NULL);
3629}
3630
3631
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003632bool Assembler::ImmediateFitsAddrMode2Instruction(int32_t imm32) {
3633 return is_uint12(abs(imm32));
3634}
3635
3636
Andrei Popescu31002712010-02-23 13:46:05 +00003637// Debugging.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003638void Assembler::RecordConstPool(int size) {
3639 // We only need this for debugger support, to correctly compute offsets in the
3640 // code.
3641 RecordRelocInfo(RelocInfo::CONST_POOL, static_cast<intptr_t>(size));
3642}
3643
3644
Steve Blocka7e24c12009-10-30 11:49:00 +00003645void Assembler::GrowBuffer() {
3646 if (!own_buffer_) FATAL("external code buffer is too small");
3647
Andrei Popescu31002712010-02-23 13:46:05 +00003648 // Compute new buffer size.
Steve Blocka7e24c12009-10-30 11:49:00 +00003649 CodeDesc desc; // the new buffer
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003650 if (buffer_size_ < 1 * MB) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003651 desc.buffer_size = 2*buffer_size_;
3652 } else {
3653 desc.buffer_size = buffer_size_ + 1*MB;
3654 }
3655 CHECK_GT(desc.buffer_size, 0); // no overflow
3656
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003657 // Set up new buffer.
Steve Blocka7e24c12009-10-30 11:49:00 +00003658 desc.buffer = NewArray<byte>(desc.buffer_size);
3659
3660 desc.instr_size = pc_offset();
3661 desc.reloc_size = (buffer_ + buffer_size_) - reloc_info_writer.pos();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003662 desc.origin = this;
Steve Blocka7e24c12009-10-30 11:49:00 +00003663
Andrei Popescu31002712010-02-23 13:46:05 +00003664 // Copy the data.
Steve Blocka7e24c12009-10-30 11:49:00 +00003665 int pc_delta = desc.buffer - buffer_;
3666 int rc_delta = (desc.buffer + desc.buffer_size) - (buffer_ + buffer_size_);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003667 MemMove(desc.buffer, buffer_, desc.instr_size);
3668 MemMove(reloc_info_writer.pos() + rc_delta, reloc_info_writer.pos(),
3669 desc.reloc_size);
Steve Blocka7e24c12009-10-30 11:49:00 +00003670
Andrei Popescu31002712010-02-23 13:46:05 +00003671 // Switch buffers.
Steve Blocka7e24c12009-10-30 11:49:00 +00003672 DeleteArray(buffer_);
3673 buffer_ = desc.buffer;
3674 buffer_size_ = desc.buffer_size;
3675 pc_ += pc_delta;
3676 reloc_info_writer.Reposition(reloc_info_writer.pos() + rc_delta,
3677 reloc_info_writer.last_pc() + pc_delta);
3678
Andrei Popescu31002712010-02-23 13:46:05 +00003679 // None of our relocation types are pc relative pointing outside the code
Steve Blocka7e24c12009-10-30 11:49:00 +00003680 // buffer nor pc absolute pointing inside the code buffer, so there is no need
Andrei Popescu31002712010-02-23 13:46:05 +00003681 // to relocate any emitted relocation entries.
Steve Blocka7e24c12009-10-30 11:49:00 +00003682}
3683
3684
Ben Murdochb0fe1622011-05-05 13:52:32 +01003685void Assembler::db(uint8_t data) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003686 // db is used to write raw data. The constant pool should be emitted or
3687 // blocked before using db.
3688 DCHECK(is_const_pool_blocked() || (num_pending_32_bit_constants_ == 0));
3689 DCHECK(is_const_pool_blocked() || (num_pending_64_bit_constants_ == 0));
Ben Murdochb0fe1622011-05-05 13:52:32 +01003690 CheckBuffer();
3691 *reinterpret_cast<uint8_t*>(pc_) = data;
3692 pc_ += sizeof(uint8_t);
3693}
3694
3695
3696void Assembler::dd(uint32_t data) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003697 // dd is used to write raw data. The constant pool should be emitted or
3698 // blocked before using dd.
3699 DCHECK(is_const_pool_blocked() || (num_pending_32_bit_constants_ == 0));
3700 DCHECK(is_const_pool_blocked() || (num_pending_64_bit_constants_ == 0));
Ben Murdochb0fe1622011-05-05 13:52:32 +01003701 CheckBuffer();
3702 *reinterpret_cast<uint32_t*>(pc_) = data;
3703 pc_ += sizeof(uint32_t);
3704}
3705
3706
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003707void Assembler::dq(uint64_t value) {
3708 // dq is used to write raw data. The constant pool should be emitted or
3709 // blocked before using dq.
3710 DCHECK(is_const_pool_blocked() || (num_pending_32_bit_constants_ == 0));
3711 DCHECK(is_const_pool_blocked() || (num_pending_64_bit_constants_ == 0));
3712 CheckBuffer();
3713 *reinterpret_cast<uint64_t*>(pc_) = value;
3714 pc_ += sizeof(uint64_t);
3715}
3716
3717
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003718void Assembler::emit_code_stub_address(Code* stub) {
3719 CheckBuffer();
3720 *reinterpret_cast<uint32_t*>(pc_) =
3721 reinterpret_cast<uint32_t>(stub->instruction_start());
3722 pc_ += sizeof(uint32_t);
3723}
3724
3725
Steve Blocka7e24c12009-10-30 11:49:00 +00003726void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003727 if (RelocInfo::IsNone(rmode) ||
3728 // Don't record external references unless the heap will be serialized.
3729 (rmode == RelocInfo::EXTERNAL_REFERENCE && !serializer_enabled() &&
3730 !emit_debug_code())) {
3731 return;
3732 }
3733 DCHECK(buffer_space() >= kMaxRelocSize); // too late to grow buffer here
3734 if (rmode == RelocInfo::CODE_TARGET_WITH_ID) {
3735 data = RecordedAstId().ToInt();
3736 ClearRecordedAstId();
3737 }
3738 RelocInfo rinfo(isolate(), pc_, rmode, data, NULL);
3739 reloc_info_writer.Write(&rinfo);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003740}
3741
3742
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003743ConstantPoolEntry::Access Assembler::ConstantPoolAddEntry(int position,
3744 RelocInfo::Mode rmode,
3745 intptr_t value) {
3746 DCHECK(rmode != RelocInfo::COMMENT && rmode != RelocInfo::POSITION &&
3747 rmode != RelocInfo::STATEMENT_POSITION &&
3748 rmode != RelocInfo::CONST_POOL && rmode != RelocInfo::NONE64);
3749 bool sharing_ok = RelocInfo::IsNone(rmode) ||
3750 !(serializer_enabled() || rmode < RelocInfo::CELL);
3751 if (FLAG_enable_embedded_constant_pool) {
3752 return constant_pool_builder_.AddEntry(position, value, sharing_ok);
3753 } else {
3754 DCHECK(num_pending_32_bit_constants_ < kMaxNumPending32Constants);
3755 if (num_pending_32_bit_constants_ == 0) {
3756 first_const_pool_32_use_ = position;
3757 } else if (num_pending_32_bit_constants_ == kMinNumPendingConstants &&
3758 pending_32_bit_constants_ ==
3759 &pending_32_bit_constants_buffer_[0]) {
3760 // Inline buffer is full, switch to dynamically allocated buffer.
3761 pending_32_bit_constants_ =
3762 new ConstantPoolEntry[kMaxNumPending32Constants];
3763 std::copy(&pending_32_bit_constants_buffer_[0],
3764 &pending_32_bit_constants_buffer_[kMinNumPendingConstants],
3765 &pending_32_bit_constants_[0]);
Steve Blocka7e24c12009-10-30 11:49:00 +00003766 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003767 ConstantPoolEntry entry(position, value, sharing_ok);
3768 pending_32_bit_constants_[num_pending_32_bit_constants_++] = entry;
3769
3770 // Make sure the constant pool is not emitted in place of the next
3771 // instruction for which we just recorded relocation info.
3772 BlockConstPoolFor(1);
3773 return ConstantPoolEntry::REGULAR;
Steve Blocka7e24c12009-10-30 11:49:00 +00003774 }
3775}
3776
3777
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003778ConstantPoolEntry::Access Assembler::ConstantPoolAddEntry(int position,
3779 double value) {
3780 if (FLAG_enable_embedded_constant_pool) {
3781 return constant_pool_builder_.AddEntry(position, value);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003782 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003783 DCHECK(num_pending_64_bit_constants_ < kMaxNumPending64Constants);
3784 if (num_pending_64_bit_constants_ == 0) {
3785 first_const_pool_64_use_ = position;
3786 } else if (num_pending_64_bit_constants_ == kMinNumPendingConstants &&
3787 pending_64_bit_constants_ ==
3788 &pending_64_bit_constants_buffer_[0]) {
3789 // Inline buffer is full, switch to dynamically allocated buffer.
3790 pending_64_bit_constants_ =
3791 new ConstantPoolEntry[kMaxNumPending64Constants];
3792 std::copy(&pending_64_bit_constants_buffer_[0],
3793 &pending_64_bit_constants_buffer_[kMinNumPendingConstants],
3794 &pending_64_bit_constants_[0]);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003795 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003796 ConstantPoolEntry entry(position, value);
3797 pending_64_bit_constants_[num_pending_64_bit_constants_++] = entry;
3798
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003799 // Make sure the constant pool is not emitted in place of the next
3800 // instruction for which we just recorded relocation info.
3801 BlockConstPoolFor(1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003802 return ConstantPoolEntry::REGULAR;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003803 }
3804}
3805
3806
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003807void Assembler::BlockConstPoolFor(int instructions) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003808 if (FLAG_enable_embedded_constant_pool) {
3809 // Should be a no-op if using an embedded constant pool.
3810 DCHECK(num_pending_32_bit_constants_ == 0);
3811 DCHECK(num_pending_64_bit_constants_ == 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003812 return;
3813 }
3814
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003815 int pc_limit = pc_offset() + instructions * kInstrSize;
3816 if (no_const_pool_before_ < pc_limit) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003817 // Max pool start (if we need a jump and an alignment).
3818#ifdef DEBUG
3819 int start = pc_limit + kInstrSize + 2 * kPointerSize;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003820 DCHECK((num_pending_32_bit_constants_ == 0) ||
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003821 (start - first_const_pool_32_use_ +
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003822 num_pending_64_bit_constants_ * kDoubleSize <
3823 kMaxDistToIntPool));
3824 DCHECK((num_pending_64_bit_constants_ == 0) ||
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003825 (start - first_const_pool_64_use_ < kMaxDistToFPPool));
3826#endif
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003827 no_const_pool_before_ = pc_limit;
Steve Blocka7e24c12009-10-30 11:49:00 +00003828 }
3829
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003830 if (next_buffer_check_ < no_const_pool_before_) {
3831 next_buffer_check_ = no_const_pool_before_;
3832 }
3833}
Steve Blocka7e24c12009-10-30 11:49:00 +00003834
Steve Blocka7e24c12009-10-30 11:49:00 +00003835
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003836void Assembler::CheckConstPool(bool force_emit, bool require_jump) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003837 if (FLAG_enable_embedded_constant_pool) {
3838 // Should be a no-op if using an embedded constant pool.
3839 DCHECK(num_pending_32_bit_constants_ == 0);
3840 DCHECK(num_pending_64_bit_constants_ == 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003841 return;
3842 }
3843
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003844 // Some short sequence of instruction mustn't be broken up by constant pool
3845 // emission, such sequences are protected by calls to BlockConstPoolFor and
3846 // BlockConstPoolScope.
3847 if (is_const_pool_blocked()) {
Andrei Popescu31002712010-02-23 13:46:05 +00003848 // Something is wrong if emission is forced and blocked at the same time.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003849 DCHECK(!force_emit);
Steve Blocka7e24c12009-10-30 11:49:00 +00003850 return;
3851 }
3852
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003853 // There is nothing to do if there are no pending constant pool entries.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003854 if ((num_pending_32_bit_constants_ == 0) &&
3855 (num_pending_64_bit_constants_ == 0)) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003856 // Calculate the offset of the next check.
3857 next_buffer_check_ = pc_offset() + kCheckPoolInterval;
3858 return;
3859 }
3860
Steve Blocka7e24c12009-10-30 11:49:00 +00003861 // Check that the code buffer is large enough before emitting the constant
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003862 // pool (include the jump over the pool and the constant pool marker and
3863 // the gap to the relocation information).
3864 int jump_instr = require_jump ? kInstrSize : 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003865 int size_up_to_marker = jump_instr + kInstrSize;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003866 int estimated_size_after_marker =
3867 num_pending_32_bit_constants_ * kPointerSize;
3868 bool has_int_values = (num_pending_32_bit_constants_ > 0);
3869 bool has_fp_values = (num_pending_64_bit_constants_ > 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003870 bool require_64_bit_align = false;
3871 if (has_fp_values) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003872 require_64_bit_align =
3873 !IsAligned(reinterpret_cast<intptr_t>(pc_ + size_up_to_marker),
3874 kDoubleAlignment);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003875 if (require_64_bit_align) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003876 estimated_size_after_marker += kInstrSize;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003877 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003878 estimated_size_after_marker += num_pending_64_bit_constants_ * kDoubleSize;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003879 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003880 int estimated_size = size_up_to_marker + estimated_size_after_marker;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003881
3882 // We emit a constant pool when:
3883 // * requested to do so by parameter force_emit (e.g. after each function).
3884 // * the distance from the first instruction accessing the constant pool to
3885 // any of the constant pool entries will exceed its limit the next
3886 // time the pool is checked. This is overly restrictive, but we don't emit
3887 // constant pool entries in-order so it's conservatively correct.
3888 // * the instruction doesn't require a jump after itself to jump over the
3889 // constant pool, and we're getting close to running out of range.
3890 if (!force_emit) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003891 DCHECK(has_fp_values || has_int_values);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003892 bool need_emit = false;
3893 if (has_fp_values) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003894 // The 64-bit constants are always emitted before the 32-bit constants, so
3895 // we can ignore the effect of the 32-bit constants on estimated_size.
3896 int dist64 = pc_offset() + estimated_size -
3897 num_pending_32_bit_constants_ * kPointerSize -
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003898 first_const_pool_64_use_;
3899 if ((dist64 >= kMaxDistToFPPool - kCheckPoolInterval) ||
3900 (!require_jump && (dist64 >= kMaxDistToFPPool / 2))) {
3901 need_emit = true;
3902 }
3903 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003904 if (has_int_values) {
3905 int dist32 = pc_offset() + estimated_size - first_const_pool_32_use_;
3906 if ((dist32 >= kMaxDistToIntPool - kCheckPoolInterval) ||
3907 (!require_jump && (dist32 >= kMaxDistToIntPool / 2))) {
3908 need_emit = true;
3909 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003910 }
3911 if (!need_emit) return;
3912 }
3913
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003914 // Deduplicate constants.
3915 int size_after_marker = estimated_size_after_marker;
3916 for (int i = 0; i < num_pending_64_bit_constants_; i++) {
3917 ConstantPoolEntry& entry = pending_64_bit_constants_[i];
3918 DCHECK(!entry.is_merged());
3919 for (int j = 0; j < i; j++) {
3920 if (entry.value64() == pending_64_bit_constants_[j].value64()) {
3921 DCHECK(!pending_64_bit_constants_[j].is_merged());
3922 entry.set_merged_index(j);
3923 size_after_marker -= kDoubleSize;
3924 break;
3925 }
3926 }
3927 }
3928
3929 for (int i = 0; i < num_pending_32_bit_constants_; i++) {
3930 ConstantPoolEntry& entry = pending_32_bit_constants_[i];
3931 DCHECK(!entry.is_merged());
3932 if (!entry.sharing_ok()) continue;
3933 for (int j = 0; j < i; j++) {
3934 if (entry.value() == pending_32_bit_constants_[j].value()) {
3935 DCHECK(!pending_32_bit_constants_[j].is_merged());
3936 entry.set_merged_index(j);
3937 size_after_marker -= kPointerSize;
3938 break;
3939 }
3940 }
3941 }
3942
3943 int size = size_up_to_marker + size_after_marker;
3944
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003945 int needed_space = size + kGap;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003946 while (buffer_space() <= needed_space) GrowBuffer();
Steve Blocka7e24c12009-10-30 11:49:00 +00003947
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003948 {
3949 // Block recursive calls to CheckConstPool.
3950 BlockConstPoolScope block_const_pool(this);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003951 RecordComment("[ Constant Pool");
3952 RecordConstPool(size);
Steve Blocka7e24c12009-10-30 11:49:00 +00003953
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003954 Label size_check;
3955 bind(&size_check);
3956
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003957 // Emit jump over constant pool if necessary.
3958 Label after_pool;
3959 if (require_jump) {
3960 b(&after_pool);
Steve Blocka7e24c12009-10-30 11:49:00 +00003961 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003962
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003963 // Put down constant pool marker "Undefined instruction".
3964 // The data size helps disassembly know what to print.
3965 emit(kConstantPoolMarker |
3966 EncodeConstantPoolLength(size_after_marker / kPointerSize));
Steve Blocka7e24c12009-10-30 11:49:00 +00003967
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003968 if (require_64_bit_align) {
3969 emit(kConstantPoolMarker);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003970 }
3971
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003972 // Emit 64-bit constant pool entries first: their range is smaller than
3973 // 32-bit entries.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003974 for (int i = 0; i < num_pending_64_bit_constants_; i++) {
3975 ConstantPoolEntry& entry = pending_64_bit_constants_[i];
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003976
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003977 Instr instr = instr_at(entry.position());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003978 // Instruction to patch must be 'vldr rd, [pc, #offset]' with offset == 0.
3979 DCHECK((IsVldrDPcImmediateOffset(instr) &&
3980 GetVldrDRegisterImmediateOffset(instr) == 0));
3981
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003982 int delta = pc_offset() - entry.position() - kPcLoadDelta;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003983 DCHECK(is_uint10(delta));
3984
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003985 if (entry.is_merged()) {
3986 ConstantPoolEntry& merged =
3987 pending_64_bit_constants_[entry.merged_index()];
3988 DCHECK(entry.value64() == merged.value64());
3989 Instr merged_instr = instr_at(merged.position());
3990 DCHECK(IsVldrDPcImmediateOffset(merged_instr));
3991 delta = GetVldrDRegisterImmediateOffset(merged_instr);
3992 delta += merged.position() - entry.position();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003993 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003994 instr_at_put(entry.position(),
3995 SetVldrDRegisterImmediateOffset(instr, delta));
3996 if (!entry.is_merged()) {
3997 DCHECK(IsAligned(reinterpret_cast<intptr_t>(pc_), kDoubleAlignment));
3998 dq(entry.value64());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003999 }
4000 }
4001
4002 // Emit 32-bit constant pool entries.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004003 for (int i = 0; i < num_pending_32_bit_constants_; i++) {
4004 ConstantPoolEntry& entry = pending_32_bit_constants_[i];
4005 Instr instr = instr_at(entry.position());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004006
4007 // 64-bit loads shouldn't get here.
4008 DCHECK(!IsVldrDPcImmediateOffset(instr));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004009 DCHECK(!IsMovW(instr));
4010 DCHECK(IsLdrPcImmediateOffset(instr) &&
4011 GetLdrRegisterImmediateOffset(instr) == 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004012
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004013 int delta = pc_offset() - entry.position() - kPcLoadDelta;
4014 DCHECK(is_uint12(delta));
4015 // 0 is the smallest delta:
4016 // ldr rd, [pc, #0]
4017 // constant pool marker
4018 // data
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004019
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004020 if (entry.is_merged()) {
4021 DCHECK(entry.sharing_ok());
4022 ConstantPoolEntry& merged =
4023 pending_32_bit_constants_[entry.merged_index()];
4024 DCHECK(entry.value() == merged.value());
4025 Instr merged_instr = instr_at(merged.position());
4026 DCHECK(IsLdrPcImmediateOffset(merged_instr));
4027 delta = GetLdrRegisterImmediateOffset(merged_instr);
4028 delta += merged.position() - entry.position();
4029 }
4030 instr_at_put(entry.position(),
4031 SetLdrRegisterImmediateOffset(instr, delta));
4032 if (!entry.is_merged()) {
4033 emit(entry.value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004034 }
4035 }
4036
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004037 num_pending_32_bit_constants_ = 0;
4038 num_pending_64_bit_constants_ = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004039 first_const_pool_32_use_ = -1;
4040 first_const_pool_64_use_ = -1;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004041
4042 RecordComment("]");
4043
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004044 DCHECK_EQ(size, SizeOfCodeGeneratedSince(&size_check));
4045
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004046 if (after_pool.is_linked()) {
4047 bind(&after_pool);
4048 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004049 }
4050
4051 // Since a constant pool was just emitted, move the check offset forward by
4052 // the standard interval.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004053 next_buffer_check_ = pc_offset() + kCheckPoolInterval;
Steve Blocka7e24c12009-10-30 11:49:00 +00004054}
4055
4056
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004057void Assembler::PatchConstantPoolAccessInstruction(
4058 int pc_offset, int offset, ConstantPoolEntry::Access access,
4059 ConstantPoolEntry::Type type) {
4060 DCHECK(FLAG_enable_embedded_constant_pool);
4061 Address pc = buffer_ + pc_offset;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004062
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004063 // Patch vldr/ldr instruction with correct offset.
4064 Instr instr = instr_at(pc);
4065 if (access == ConstantPoolEntry::OVERFLOWED) {
4066 if (CpuFeatures::IsSupported(ARMv7)) {
4067 // Instructions to patch must be 'movw rd, [#0]' and 'movt rd, [#0].
4068 Instr next_instr = instr_at(pc + kInstrSize);
4069 DCHECK((IsMovW(instr) && Instruction::ImmedMovwMovtValue(instr) == 0));
4070 DCHECK((IsMovT(next_instr) &&
4071 Instruction::ImmedMovwMovtValue(next_instr) == 0));
4072 instr_at_put(pc, PatchMovwImmediate(instr, offset & 0xffff));
4073 instr_at_put(pc + kInstrSize,
4074 PatchMovwImmediate(next_instr, offset >> 16));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004075 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004076 // Instructions to patch must be 'mov rd, [#0]' and 'orr rd, rd, [#0].
4077 Instr instr_2 = instr_at(pc + kInstrSize);
4078 Instr instr_3 = instr_at(pc + 2 * kInstrSize);
4079 Instr instr_4 = instr_at(pc + 3 * kInstrSize);
4080 DCHECK((IsMovImmed(instr) && Instruction::Immed8Value(instr) == 0));
4081 DCHECK((IsOrrImmed(instr_2) && Instruction::Immed8Value(instr_2) == 0) &&
4082 GetRn(instr_2).is(GetRd(instr_2)));
4083 DCHECK((IsOrrImmed(instr_3) && Instruction::Immed8Value(instr_3) == 0) &&
4084 GetRn(instr_3).is(GetRd(instr_3)));
4085 DCHECK((IsOrrImmed(instr_4) && Instruction::Immed8Value(instr_4) == 0) &&
4086 GetRn(instr_4).is(GetRd(instr_4)));
4087 instr_at_put(pc, PatchShiftImm(instr, (offset & kImm8Mask)));
4088 instr_at_put(pc + kInstrSize,
4089 PatchShiftImm(instr_2, (offset & (kImm8Mask << 8))));
4090 instr_at_put(pc + 2 * kInstrSize,
4091 PatchShiftImm(instr_3, (offset & (kImm8Mask << 16))));
4092 instr_at_put(pc + 3 * kInstrSize,
4093 PatchShiftImm(instr_4, (offset & (kImm8Mask << 24))));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004094 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004095 } else if (type == ConstantPoolEntry::DOUBLE) {
4096 // Instruction to patch must be 'vldr rd, [pp, #0]'.
4097 DCHECK((IsVldrDPpImmediateOffset(instr) &&
4098 GetVldrDRegisterImmediateOffset(instr) == 0));
4099 DCHECK(is_uint10(offset));
4100 instr_at_put(pc, SetVldrDRegisterImmediateOffset(instr, offset));
4101 } else {
4102 // Instruction to patch must be 'ldr rd, [pp, #0]'.
4103 DCHECK((IsLdrPpImmediateOffset(instr) &&
4104 GetLdrRegisterImmediateOffset(instr) == 0));
4105 DCHECK(is_uint12(offset));
4106 instr_at_put(pc, SetLdrRegisterImmediateOffset(instr, offset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004107 }
4108}
4109
4110
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004111} // namespace internal
4112} // namespace v8
Leon Clarkef7060e22010-06-03 12:02:55 +01004113
4114#endif // V8_TARGET_ARCH_ARM