blob: b0fa462c9fe81f1f10b7a8b4e11d0c331303840b [file] [log] [blame]
Steve Blocka7e24c12009-10-30 11:49:00 +00001// Copyright (c) 1994-2006 Sun Microsystems Inc.
2// All Rights Reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions
6// are met:
7//
8// - Redistributions of source code must retain the above copyright notice,
9// this list of conditions and the following disclaimer.
10//
11// - Redistribution in binary form must reproduce the above copyright
12// notice, this list of conditions and the following disclaimer in the
13// documentation and/or other materials provided with the
14// distribution.
15//
16// - Neither the name of Sun Microsystems or the names of contributors may
17// be used to endorse or promote products derived from this software without
18// specific prior written permission.
19//
20// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
31// OF THE POSSIBILITY OF SUCH DAMAGE.
32
Leon Clarked91b9f72010-01-27 17:25:45 +000033// The original source code covered by the above license above has been
34// modified significantly by Google Inc.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000035// Copyright 2012 the V8 project authors. All rights reserved.
Steve Blocka7e24c12009-10-30 11:49:00 +000036
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000037#include "src/arm/assembler-arm.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000038
Ben Murdochb8a8cc12014-11-26 15:28:44 +000039#if V8_TARGET_ARCH_ARM
Leon Clarkef7060e22010-06-03 12:02:55 +010040
Ben Murdochb8a8cc12014-11-26 15:28:44 +000041#include "src/arm/assembler-arm-inl.h"
42#include "src/base/bits.h"
43#include "src/base/cpu.h"
44#include "src/macro-assembler.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000045
46namespace v8 {
47namespace internal {
48
Ben Murdoch257744e2011-11-30 15:57:28 +000049// Get the CPU features enabled by the build. For cross compilation the
Ben Murdochb8a8cc12014-11-26 15:28:44 +000050// preprocessor symbols CAN_USE_ARMV7_INSTRUCTIONS and CAN_USE_VFP3_INSTRUCTIONS
Ben Murdoch257744e2011-11-30 15:57:28 +000051// can be defined to enable ARMv7 and VFPv3 instructions when building the
52// snapshot.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000053static unsigned CpuFeaturesImpliedByCompiler() {
54 unsigned answer = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000055#ifdef CAN_USE_ARMV8_INSTRUCTIONS
56 if (FLAG_enable_armv8) {
57 answer |= 1u << ARMv8;
58 // ARMv8 always features VFP and NEON.
59 answer |= 1u << ARMv7 | 1u << VFP3 | 1u << NEON | 1u << VFP32DREGS;
60 answer |= 1u << SUDIV | 1u << MLS;
61 }
62#endif // CAN_USE_ARMV8_INSTRUCTIONS
Andrei Popescu402d9372010-02-26 13:31:12 +000063#ifdef CAN_USE_ARMV7_INSTRUCTIONS
Ben Murdochb8a8cc12014-11-26 15:28:44 +000064 if (FLAG_enable_armv7) answer |= 1u << ARMv7;
65#endif // CAN_USE_ARMV7_INSTRUCTIONS
66#ifdef CAN_USE_VFP3_INSTRUCTIONS
67 if (FLAG_enable_vfp3) answer |= 1u << VFP3 | 1u << ARMv7;
68#endif // CAN_USE_VFP3_INSTRUCTIONS
69#ifdef CAN_USE_VFP32DREGS
70 if (FLAG_enable_32dregs) answer |= 1u << VFP32DREGS;
71#endif // CAN_USE_VFP32DREGS
72#ifdef CAN_USE_NEON
73 if (FLAG_enable_neon) answer |= 1u << NEON;
74#endif // CAN_USE_VFP32DREGS
75 if ((answer & (1u << ARMv7)) && FLAG_enable_unaligned_accesses) {
76 answer |= 1u << UNALIGNED_ACCESSES;
77 }
Ben Murdoch257744e2011-11-30 15:57:28 +000078
Andrei Popescu402d9372010-02-26 13:31:12 +000079 return answer;
80}
Andrei Popescu402d9372010-02-26 13:31:12 +000081
82
Ben Murdochb8a8cc12014-11-26 15:28:44 +000083void CpuFeatures::ProbeImpl(bool cross_compile) {
84 supported_ |= CpuFeaturesImpliedByCompiler();
Ben Murdoch097c5b22016-05-18 11:27:45 +010085 dcache_line_size_ = 64;
Ben Murdoch257744e2011-11-30 15:57:28 +000086
Ben Murdochb8a8cc12014-11-26 15:28:44 +000087 // Only use statically determined features for cross compile (snapshot).
88 if (cross_compile) return;
Ben Murdoch257744e2011-11-30 15:57:28 +000089
Andrei Popescu402d9372010-02-26 13:31:12 +000090#ifndef __arm__
Ben Murdochb8a8cc12014-11-26 15:28:44 +000091 // For the simulator build, use whatever the flags specify.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000092 if (FLAG_enable_armv8) {
93 supported_ |= 1u << ARMv8;
94 // ARMv8 always features VFP and NEON.
95 supported_ |= 1u << ARMv7 | 1u << VFP3 | 1u << NEON | 1u << VFP32DREGS;
96 supported_ |= 1u << SUDIV | 1u << MLS;
97 if (FLAG_enable_movw_movt) supported_ |= 1u << MOVW_MOVT_IMMEDIATE_LOADS;
98 }
Andrei Popescu31002712010-02-23 13:46:05 +000099 if (FLAG_enable_armv7) {
Steve Block6ded16b2010-05-10 14:33:55 +0100100 supported_ |= 1u << ARMv7;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000101 if (FLAG_enable_vfp3) supported_ |= 1u << VFP3;
102 if (FLAG_enable_neon) supported_ |= 1u << NEON | 1u << VFP32DREGS;
103 if (FLAG_enable_sudiv) supported_ |= 1u << SUDIV;
104 if (FLAG_enable_movw_movt) supported_ |= 1u << MOVW_MOVT_IMMEDIATE_LOADS;
105 if (FLAG_enable_32dregs) supported_ |= 1u << VFP32DREGS;
Andrei Popescu31002712010-02-23 13:46:05 +0000106 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000107 if (FLAG_enable_mls) supported_ |= 1u << MLS;
108 if (FLAG_enable_unaligned_accesses) supported_ |= 1u << UNALIGNED_ACCESSES;
109
110#else // __arm__
111 // Probe for additional features at runtime.
112 base::CPU cpu;
113 if (FLAG_enable_vfp3 && cpu.has_vfp3()) {
Ben Murdoch8b112d22011-06-08 16:22:53 +0100114 // This implementation also sets the VFP flags if runtime
115 // detection of VFP returns true. VFPv3 implies ARMv7, see ARM DDI
116 // 0406B, page A1-6.
117 supported_ |= 1u << VFP3 | 1u << ARMv7;
Steve Blockd0582a62009-12-15 09:54:21 +0000118 }
Andrei Popescu31002712010-02-23 13:46:05 +0000119
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000120 if (FLAG_enable_neon && cpu.has_neon()) supported_ |= 1u << NEON;
121 if (FLAG_enable_sudiv && cpu.has_idiva()) supported_ |= 1u << SUDIV;
122 if (FLAG_enable_mls && cpu.has_thumb2()) supported_ |= 1u << MLS;
123
124 if (cpu.architecture() >= 7) {
125 if (FLAG_enable_armv7) supported_ |= 1u << ARMv7;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400126 if (FLAG_enable_armv8 && cpu.architecture() >= 8) {
127 supported_ |= 1u << ARMv8;
128 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000129 if (FLAG_enable_unaligned_accesses) supported_ |= 1u << UNALIGNED_ACCESSES;
130 // Use movw/movt for QUALCOMM ARMv7 cores.
131 if (FLAG_enable_movw_movt && cpu.implementer() == base::CPU::QUALCOMM) {
132 supported_ |= 1u << MOVW_MOVT_IMMEDIATE_LOADS;
133 }
Andrei Popescu31002712010-02-23 13:46:05 +0000134 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000135
136 // ARM Cortex-A9 and Cortex-A5 have 32 byte cachelines.
137 if (cpu.implementer() == base::CPU::ARM &&
138 (cpu.part() == base::CPU::ARM_CORTEX_A5 ||
139 cpu.part() == base::CPU::ARM_CORTEX_A9)) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100140 dcache_line_size_ = 32;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000141 }
142
143 if (FLAG_enable_32dregs && cpu.has_vfp3_d32()) supported_ |= 1u << VFP32DREGS;
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
Ben Murdoch097c5b22016-05-18 11:27:45 +01001950void Assembler::rbit(Register dst, Register src, Condition cond) {
1951 // Instruction details available in ARM DDI 0406C.b, A8.8.144.
1952 // cond(31-28) | 011011111111(27-16) | Rd(15-12) | 11110011(11-4) | Rm(3-0)
1953 DCHECK(IsEnabled(ARMv7));
1954 DCHECK(!dst.is(pc));
1955 DCHECK(!src.is(pc));
1956 emit(cond | 0x6FF * B16 | dst.code() * B12 | 0xF3 * B4 | src.code());
1957}
1958
1959
Andrei Popescu31002712010-02-23 13:46:05 +00001960// Status register access instructions.
Steve Blocka7e24c12009-10-30 11:49:00 +00001961void Assembler::mrs(Register dst, SRegister s, Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001962 DCHECK(!dst.is(pc));
Steve Blocka7e24c12009-10-30 11:49:00 +00001963 emit(cond | B24 | s | 15*B16 | dst.code()*B12);
1964}
1965
1966
1967void Assembler::msr(SRegisterFieldMask fields, const Operand& src,
1968 Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001969 DCHECK(fields >= B16 && fields < B20); // at least one field set
Steve Blocka7e24c12009-10-30 11:49:00 +00001970 Instr instr;
1971 if (!src.rm_.is_valid()) {
Andrei Popescu31002712010-02-23 13:46:05 +00001972 // Immediate.
Steve Blocka7e24c12009-10-30 11:49:00 +00001973 uint32_t rotate_imm;
1974 uint32_t immed_8;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001975 if (src.must_output_reloc_info(this) ||
Steve Blocka7e24c12009-10-30 11:49:00 +00001976 !fits_shifter(src.imm32_, &rotate_imm, &immed_8, NULL)) {
Andrei Popescu31002712010-02-23 13:46:05 +00001977 // Immediate operand cannot be encoded, load it first to register ip.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001978 move_32_bit_immediate(ip, src);
Steve Blocka7e24c12009-10-30 11:49:00 +00001979 msr(fields, Operand(ip), cond);
1980 return;
1981 }
1982 instr = I | rotate_imm*B8 | immed_8;
1983 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001984 DCHECK(!src.rs_.is_valid() && src.shift_imm_ == 0); // only rm allowed
Steve Blocka7e24c12009-10-30 11:49:00 +00001985 instr = src.rm_.code();
1986 }
1987 emit(cond | instr | B24 | B21 | fields | 15*B12);
1988}
1989
1990
Andrei Popescu31002712010-02-23 13:46:05 +00001991// Load/Store instructions.
Steve Blocka7e24c12009-10-30 11:49:00 +00001992void Assembler::ldr(Register dst, const MemOperand& src, Condition cond) {
1993 if (dst.is(pc)) {
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001994 positions_recorder()->WriteRecordedPositions();
Steve Blocka7e24c12009-10-30 11:49:00 +00001995 }
1996 addrmod2(cond | B26 | L, dst, src);
Steve Blocka7e24c12009-10-30 11:49:00 +00001997}
1998
1999
2000void Assembler::str(Register src, const MemOperand& dst, Condition cond) {
2001 addrmod2(cond | B26, src, dst);
Steve Blocka7e24c12009-10-30 11:49:00 +00002002}
2003
2004
2005void Assembler::ldrb(Register dst, const MemOperand& src, Condition cond) {
2006 addrmod2(cond | B26 | B | L, dst, src);
2007}
2008
2009
2010void Assembler::strb(Register src, const MemOperand& dst, Condition cond) {
2011 addrmod2(cond | B26 | B, src, dst);
2012}
2013
2014
2015void Assembler::ldrh(Register dst, const MemOperand& src, Condition cond) {
2016 addrmod3(cond | L | B7 | H | B4, dst, src);
2017}
2018
2019
2020void Assembler::strh(Register src, const MemOperand& dst, Condition cond) {
2021 addrmod3(cond | B7 | H | B4, src, dst);
2022}
2023
2024
2025void Assembler::ldrsb(Register dst, const MemOperand& src, Condition cond) {
2026 addrmod3(cond | L | B7 | S6 | B4, dst, src);
2027}
2028
2029
2030void Assembler::ldrsh(Register dst, const MemOperand& src, Condition cond) {
2031 addrmod3(cond | L | B7 | S6 | H | B4, dst, src);
2032}
2033
2034
Leon Clarkef7060e22010-06-03 12:02:55 +01002035void Assembler::ldrd(Register dst1, Register dst2,
2036 const MemOperand& src, Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002037 DCHECK(IsEnabled(ARMv7));
2038 DCHECK(src.rm().is(no_reg));
2039 DCHECK(!dst1.is(lr)); // r14.
2040 DCHECK_EQ(0, dst1.code() % 2);
2041 DCHECK_EQ(dst1.code() + 1, dst2.code());
Leon Clarkef7060e22010-06-03 12:02:55 +01002042 addrmod3(cond | B7 | B6 | B4, dst1, src);
Kristian Monsen25f61362010-05-21 11:50:48 +01002043}
2044
2045
Leon Clarkef7060e22010-06-03 12:02:55 +01002046void Assembler::strd(Register src1, Register src2,
2047 const MemOperand& dst, Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002048 DCHECK(dst.rm().is(no_reg));
2049 DCHECK(!src1.is(lr)); // r14.
2050 DCHECK_EQ(0, src1.code() % 2);
2051 DCHECK_EQ(src1.code() + 1, src2.code());
2052 DCHECK(IsEnabled(ARMv7));
Leon Clarkef7060e22010-06-03 12:02:55 +01002053 addrmod3(cond | B7 | B6 | B5 | B4, src1, dst);
Kristian Monsen25f61362010-05-21 11:50:48 +01002054}
2055
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002056
2057// Preload instructions.
2058void Assembler::pld(const MemOperand& address) {
2059 // Instruction details available in ARM DDI 0406C.b, A8.8.128.
2060 // 1111(31-28) | 0111(27-24) | U(23) | R(22) | 01(21-20) | Rn(19-16) |
2061 // 1111(15-12) | imm5(11-07) | type(6-5) | 0(4)| Rm(3-0) |
2062 DCHECK(address.rm().is(no_reg));
2063 DCHECK(address.am() == Offset);
2064 int U = B23;
2065 int offset = address.offset();
2066 if (offset < 0) {
2067 offset = -offset;
2068 U = 0;
2069 }
2070 DCHECK(offset < 4096);
2071 emit(kSpecialCondition | B26 | B24 | U | B22 | B20 | address.rn().code()*B16 |
2072 0xf*B12 | offset);
2073}
2074
2075
Andrei Popescu31002712010-02-23 13:46:05 +00002076// Load/Store multiple instructions.
Steve Blocka7e24c12009-10-30 11:49:00 +00002077void Assembler::ldm(BlockAddrMode am,
2078 Register base,
2079 RegList dst,
2080 Condition cond) {
Andrei Popescu31002712010-02-23 13:46:05 +00002081 // ABI stack constraint: ldmxx base, {..sp..} base != sp is not restartable.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002082 DCHECK(base.is(sp) || (dst & sp.bit()) == 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00002083
2084 addrmod4(cond | B27 | am | L, base, dst);
2085
Andrei Popescu31002712010-02-23 13:46:05 +00002086 // Emit the constant pool after a function return implemented by ldm ..{..pc}.
Steve Blocka7e24c12009-10-30 11:49:00 +00002087 if (cond == al && (dst & pc.bit()) != 0) {
2088 // There is a slight chance that the ldm instruction was actually a call,
2089 // in which case it would be wrong to return into the constant pool; we
2090 // recognize this case by checking if the emission of the pool was blocked
2091 // at the pc of the ldm instruction by a mov lr, pc instruction; if this is
2092 // the case, we emit a jump over the pool.
2093 CheckConstPool(true, no_const_pool_before_ == pc_offset() - kInstrSize);
2094 }
2095}
2096
2097
2098void Assembler::stm(BlockAddrMode am,
2099 Register base,
2100 RegList src,
2101 Condition cond) {
2102 addrmod4(cond | B27 | am, base, src);
2103}
2104
2105
Andrei Popescu31002712010-02-23 13:46:05 +00002106// Exception-generating instructions and debugging support.
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002107// Stops with a non-negative code less than kNumOfWatchedStops support
2108// enabling/disabling and a counter feature. See simulator-arm.h .
2109void Assembler::stop(const char* msg, Condition cond, int32_t code) {
Andrei Popescu402d9372010-02-26 13:31:12 +00002110#ifndef __arm__
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002111 DCHECK(code >= kDefaultStopCode);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002112 {
2113 // The Simulator will handle the stop instruction and get the message
2114 // address. It expects to find the address just after the svc instruction.
2115 BlockConstPoolScope block_const_pool(this);
2116 if (code >= 0) {
2117 svc(kStopCode + code, cond);
2118 } else {
2119 svc(kStopCode + kMaxStopCode, cond);
2120 }
2121 emit(reinterpret_cast<Instr>(msg));
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002122 }
Andrei Popescu402d9372010-02-26 13:31:12 +00002123#else // def __arm__
Steve Block1e0659c2011-05-24 12:43:12 +01002124 if (cond != al) {
2125 Label skip;
2126 b(&skip, NegateCondition(cond));
2127 bkpt(0);
2128 bind(&skip);
2129 } else {
2130 bkpt(0);
2131 }
Andrei Popescu402d9372010-02-26 13:31:12 +00002132#endif // def __arm__
Steve Blocka7e24c12009-10-30 11:49:00 +00002133}
2134
2135
2136void Assembler::bkpt(uint32_t imm16) { // v5 and above
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002137 DCHECK(is_uint16(imm16));
Steve Block1e0659c2011-05-24 12:43:12 +01002138 emit(al | B24 | B21 | (imm16 >> 4)*B8 | BKPT | (imm16 & 0xf));
Steve Blocka7e24c12009-10-30 11:49:00 +00002139}
2140
2141
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002142void Assembler::svc(uint32_t imm24, Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002143 DCHECK(is_uint24(imm24));
Steve Blocka7e24c12009-10-30 11:49:00 +00002144 emit(cond | 15*B24 | imm24);
2145}
2146
2147
Ben Murdoch097c5b22016-05-18 11:27:45 +01002148void Assembler::dmb(BarrierOption option) {
2149 emit(kSpecialCondition | 0x57ff*B12 | 5*B4 | option);
2150}
2151
2152
2153void Assembler::dsb(BarrierOption option) {
2154 emit(kSpecialCondition | 0x57ff*B12 | 4*B4 | option);
2155}
2156
2157
2158void Assembler::isb(BarrierOption option) {
2159 emit(kSpecialCondition | 0x57ff*B12 | 6*B4 | option);
2160}
2161
2162
Andrei Popescu31002712010-02-23 13:46:05 +00002163// Coprocessor instructions.
Steve Blocka7e24c12009-10-30 11:49:00 +00002164void Assembler::cdp(Coprocessor coproc,
2165 int opcode_1,
2166 CRegister crd,
2167 CRegister crn,
2168 CRegister crm,
2169 int opcode_2,
2170 Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002171 DCHECK(is_uint4(opcode_1) && is_uint3(opcode_2));
Steve Blocka7e24c12009-10-30 11:49:00 +00002172 emit(cond | B27 | B26 | B25 | (opcode_1 & 15)*B20 | crn.code()*B16 |
2173 crd.code()*B12 | coproc*B8 | (opcode_2 & 7)*B5 | crm.code());
2174}
2175
2176
2177void Assembler::cdp2(Coprocessor coproc,
2178 int opcode_1,
2179 CRegister crd,
2180 CRegister crn,
2181 CRegister crm,
2182 int opcode_2) { // v5 and above
Steve Block1e0659c2011-05-24 12:43:12 +01002183 cdp(coproc, opcode_1, crd, crn, crm, opcode_2, kSpecialCondition);
Steve Blocka7e24c12009-10-30 11:49:00 +00002184}
2185
2186
2187void Assembler::mcr(Coprocessor coproc,
2188 int opcode_1,
2189 Register rd,
2190 CRegister crn,
2191 CRegister crm,
2192 int opcode_2,
2193 Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002194 DCHECK(is_uint3(opcode_1) && is_uint3(opcode_2));
Steve Blocka7e24c12009-10-30 11:49:00 +00002195 emit(cond | B27 | B26 | B25 | (opcode_1 & 7)*B21 | crn.code()*B16 |
2196 rd.code()*B12 | coproc*B8 | (opcode_2 & 7)*B5 | B4 | crm.code());
2197}
2198
2199
2200void Assembler::mcr2(Coprocessor coproc,
2201 int opcode_1,
2202 Register rd,
2203 CRegister crn,
2204 CRegister crm,
2205 int opcode_2) { // v5 and above
Steve Block1e0659c2011-05-24 12:43:12 +01002206 mcr(coproc, opcode_1, rd, crn, crm, opcode_2, kSpecialCondition);
Steve Blocka7e24c12009-10-30 11:49:00 +00002207}
2208
2209
2210void Assembler::mrc(Coprocessor coproc,
2211 int opcode_1,
2212 Register rd,
2213 CRegister crn,
2214 CRegister crm,
2215 int opcode_2,
2216 Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002217 DCHECK(is_uint3(opcode_1) && is_uint3(opcode_2));
Steve Blocka7e24c12009-10-30 11:49:00 +00002218 emit(cond | B27 | B26 | B25 | (opcode_1 & 7)*B21 | L | crn.code()*B16 |
2219 rd.code()*B12 | coproc*B8 | (opcode_2 & 7)*B5 | B4 | crm.code());
2220}
2221
2222
2223void Assembler::mrc2(Coprocessor coproc,
2224 int opcode_1,
2225 Register rd,
2226 CRegister crn,
2227 CRegister crm,
2228 int opcode_2) { // v5 and above
Steve Block1e0659c2011-05-24 12:43:12 +01002229 mrc(coproc, opcode_1, rd, crn, crm, opcode_2, kSpecialCondition);
Steve Blocka7e24c12009-10-30 11:49:00 +00002230}
2231
2232
2233void Assembler::ldc(Coprocessor coproc,
2234 CRegister crd,
2235 const MemOperand& src,
2236 LFlag l,
2237 Condition cond) {
2238 addrmod5(cond | B27 | B26 | l | L | coproc*B8, crd, src);
2239}
2240
2241
2242void Assembler::ldc(Coprocessor coproc,
2243 CRegister crd,
2244 Register rn,
2245 int option,
2246 LFlag l,
2247 Condition cond) {
Andrei Popescu31002712010-02-23 13:46:05 +00002248 // Unindexed addressing.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002249 DCHECK(is_uint8(option));
Steve Blocka7e24c12009-10-30 11:49:00 +00002250 emit(cond | B27 | B26 | U | l | L | rn.code()*B16 | crd.code()*B12 |
2251 coproc*B8 | (option & 255));
2252}
2253
2254
2255void Assembler::ldc2(Coprocessor coproc,
2256 CRegister crd,
2257 const MemOperand& src,
2258 LFlag l) { // v5 and above
Steve Block1e0659c2011-05-24 12:43:12 +01002259 ldc(coproc, crd, src, l, kSpecialCondition);
Steve Blocka7e24c12009-10-30 11:49:00 +00002260}
2261
2262
2263void Assembler::ldc2(Coprocessor coproc,
2264 CRegister crd,
2265 Register rn,
2266 int option,
2267 LFlag l) { // v5 and above
Steve Block1e0659c2011-05-24 12:43:12 +01002268 ldc(coproc, crd, rn, option, l, kSpecialCondition);
Steve Blocka7e24c12009-10-30 11:49:00 +00002269}
2270
2271
Steve Blockd0582a62009-12-15 09:54:21 +00002272// Support for VFP.
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002273
Leon Clarked91b9f72010-01-27 17:25:45 +00002274void Assembler::vldr(const DwVfpRegister dst,
2275 const Register base,
2276 int offset,
2277 const Condition cond) {
2278 // Ddst = MEM(Rbase + offset).
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002279 // Instruction details available in ARM DDI 0406C.b, A8-924.
2280 // cond(31-28) | 1101(27-24)| U(23) | D(22) | 01(21-20) | Rbase(19-16) |
2281 // Vd(15-12) | 1011(11-8) | offset
Ben Murdochb0fe1622011-05-05 13:52:32 +01002282 int u = 1;
2283 if (offset < 0) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002284 CHECK(offset != kMinInt);
Ben Murdochb0fe1622011-05-05 13:52:32 +01002285 offset = -offset;
2286 u = 0;
2287 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002288 int vd, d;
2289 dst.split_code(&vd, &d);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002290
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002291 DCHECK(offset >= 0);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002292 if ((offset % 4) == 0 && (offset / 4) < 256) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002293 emit(cond | 0xD*B24 | u*B23 | d*B22 | B20 | base.code()*B16 | vd*B12 |
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002294 0xB*B8 | ((offset / 4) & 255));
2295 } else {
2296 // Larger offsets must be handled by computing the correct address
2297 // in the ip register.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002298 DCHECK(!base.is(ip));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002299 if (u == 1) {
2300 add(ip, base, Operand(offset));
2301 } else {
2302 sub(ip, base, Operand(offset));
2303 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002304 emit(cond | 0xD*B24 | d*B22 | B20 | ip.code()*B16 | vd*B12 | 0xB*B8);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002305 }
2306}
2307
2308
2309void Assembler::vldr(const DwVfpRegister dst,
2310 const MemOperand& operand,
2311 const Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002312 DCHECK(operand.am_ == Offset);
2313 if (operand.rm().is_valid()) {
2314 add(ip, operand.rn(),
2315 Operand(operand.rm(), operand.shift_op_, operand.shift_imm_));
2316 vldr(dst, ip, 0, cond);
2317 } else {
2318 vldr(dst, operand.rn(), operand.offset(), cond);
2319 }
Leon Clarked91b9f72010-01-27 17:25:45 +00002320}
2321
2322
Steve Block6ded16b2010-05-10 14:33:55 +01002323void Assembler::vldr(const SwVfpRegister dst,
2324 const Register base,
2325 int offset,
2326 const Condition cond) {
2327 // Sdst = MEM(Rbase + offset).
2328 // Instruction details available in ARM DDI 0406A, A8-628.
Ben Murdochb0fe1622011-05-05 13:52:32 +01002329 // cond(31-28) | 1101(27-24)| U001(23-20) | Rbase(19-16) |
Steve Block6ded16b2010-05-10 14:33:55 +01002330 // Vdst(15-12) | 1010(11-8) | offset
Ben Murdochb0fe1622011-05-05 13:52:32 +01002331 int u = 1;
2332 if (offset < 0) {
2333 offset = -offset;
2334 u = 0;
2335 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002336 int sd, d;
2337 dst.split_code(&sd, &d);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002338 DCHECK(offset >= 0);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002339
2340 if ((offset % 4) == 0 && (offset / 4) < 256) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01002341 emit(cond | u*B23 | d*B22 | 0xD1*B20 | base.code()*B16 | sd*B12 |
Steve Block6ded16b2010-05-10 14:33:55 +01002342 0xA*B8 | ((offset / 4) & 255));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002343 } else {
2344 // Larger offsets must be handled by computing the correct address
2345 // in the ip register.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002346 DCHECK(!base.is(ip));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002347 if (u == 1) {
2348 add(ip, base, Operand(offset));
2349 } else {
2350 sub(ip, base, Operand(offset));
2351 }
2352 emit(cond | d*B22 | 0xD1*B20 | ip.code()*B16 | sd*B12 | 0xA*B8);
2353 }
2354}
2355
2356
2357void Assembler::vldr(const SwVfpRegister dst,
2358 const MemOperand& operand,
2359 const Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002360 DCHECK(operand.am_ == Offset);
2361 if (operand.rm().is_valid()) {
2362 add(ip, operand.rn(),
2363 Operand(operand.rm(), operand.shift_op_, operand.shift_imm_));
2364 vldr(dst, ip, 0, cond);
2365 } else {
2366 vldr(dst, operand.rn(), operand.offset(), cond);
2367 }
Steve Block6ded16b2010-05-10 14:33:55 +01002368}
2369
2370
Leon Clarked91b9f72010-01-27 17:25:45 +00002371void Assembler::vstr(const DwVfpRegister src,
2372 const Register base,
2373 int offset,
2374 const Condition cond) {
2375 // MEM(Rbase + offset) = Dsrc.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002376 // Instruction details available in ARM DDI 0406C.b, A8-1082.
2377 // cond(31-28) | 1101(27-24)| U(23) | D(22) | 00(21-20) | Rbase(19-16) |
2378 // Vd(15-12) | 1011(11-8) | (offset/4)
Ben Murdochb0fe1622011-05-05 13:52:32 +01002379 int u = 1;
2380 if (offset < 0) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002381 CHECK(offset != kMinInt);
Ben Murdochb0fe1622011-05-05 13:52:32 +01002382 offset = -offset;
2383 u = 0;
2384 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002385 DCHECK(offset >= 0);
2386 int vd, d;
2387 src.split_code(&vd, &d);
2388
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002389 if ((offset % 4) == 0 && (offset / 4) < 256) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002390 emit(cond | 0xD*B24 | u*B23 | d*B22 | base.code()*B16 | vd*B12 | 0xB*B8 |
2391 ((offset / 4) & 255));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002392 } else {
2393 // Larger offsets must be handled by computing the correct address
2394 // in the ip register.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002395 DCHECK(!base.is(ip));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002396 if (u == 1) {
2397 add(ip, base, Operand(offset));
2398 } else {
2399 sub(ip, base, Operand(offset));
2400 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002401 emit(cond | 0xD*B24 | d*B22 | ip.code()*B16 | vd*B12 | 0xB*B8);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002402 }
2403}
2404
2405
2406void Assembler::vstr(const DwVfpRegister src,
2407 const MemOperand& operand,
2408 const Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002409 DCHECK(operand.am_ == Offset);
2410 if (operand.rm().is_valid()) {
2411 add(ip, operand.rn(),
2412 Operand(operand.rm(), operand.shift_op_, operand.shift_imm_));
2413 vstr(src, ip, 0, cond);
2414 } else {
2415 vstr(src, operand.rn(), operand.offset(), cond);
2416 }
Leon Clarked91b9f72010-01-27 17:25:45 +00002417}
2418
2419
Iain Merrick75681382010-08-19 15:07:18 +01002420void Assembler::vstr(const SwVfpRegister src,
2421 const Register base,
2422 int offset,
2423 const Condition cond) {
2424 // MEM(Rbase + offset) = SSrc.
2425 // Instruction details available in ARM DDI 0406A, A8-786.
Ben Murdochb0fe1622011-05-05 13:52:32 +01002426 // cond(31-28) | 1101(27-24)| U000(23-20) | Rbase(19-16) |
Iain Merrick75681382010-08-19 15:07:18 +01002427 // Vdst(15-12) | 1010(11-8) | (offset/4)
Ben Murdochb0fe1622011-05-05 13:52:32 +01002428 int u = 1;
2429 if (offset < 0) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002430 CHECK(offset != kMinInt);
Ben Murdochb0fe1622011-05-05 13:52:32 +01002431 offset = -offset;
2432 u = 0;
2433 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002434 int sd, d;
2435 src.split_code(&sd, &d);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002436 DCHECK(offset >= 0);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002437 if ((offset % 4) == 0 && (offset / 4) < 256) {
2438 emit(cond | u*B23 | d*B22 | 0xD0*B20 | base.code()*B16 | sd*B12 |
2439 0xA*B8 | ((offset / 4) & 255));
2440 } else {
2441 // Larger offsets must be handled by computing the correct address
2442 // in the ip register.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002443 DCHECK(!base.is(ip));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002444 if (u == 1) {
2445 add(ip, base, Operand(offset));
2446 } else {
2447 sub(ip, base, Operand(offset));
2448 }
2449 emit(cond | d*B22 | 0xD0*B20 | ip.code()*B16 | sd*B12 | 0xA*B8);
2450 }
2451}
2452
2453
2454void Assembler::vstr(const SwVfpRegister src,
2455 const MemOperand& operand,
2456 const Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002457 DCHECK(operand.am_ == Offset);
2458 if (operand.rm().is_valid()) {
2459 add(ip, operand.rn(),
2460 Operand(operand.rm(), operand.shift_op_, operand.shift_imm_));
2461 vstr(src, ip, 0, cond);
2462 } else {
2463 vstr(src, operand.rn(), operand.offset(), cond);
2464 }
Iain Merrick75681382010-08-19 15:07:18 +01002465}
2466
2467
Ben Murdoch8b112d22011-06-08 16:22:53 +01002468void Assembler::vldm(BlockAddrMode am,
2469 Register base,
2470 DwVfpRegister first,
2471 DwVfpRegister last,
2472 Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002473 // Instruction details available in ARM DDI 0406C.b, A8-922.
Ben Murdoch8b112d22011-06-08 16:22:53 +01002474 // cond(31-28) | 110(27-25)| PUDW1(24-20) | Rbase(19-16) |
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002475 // first(15-12) | 1011(11-8) | (count * 2)
2476 DCHECK_LE(first.code(), last.code());
2477 DCHECK(am == ia || am == ia_w || am == db_w);
2478 DCHECK(!base.is(pc));
Ben Murdoch8b112d22011-06-08 16:22:53 +01002479
2480 int sd, d;
2481 first.split_code(&sd, &d);
2482 int count = last.code() - first.code() + 1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002483 DCHECK(count <= 16);
Ben Murdoch8b112d22011-06-08 16:22:53 +01002484 emit(cond | B27 | B26 | am | d*B22 | B20 | base.code()*B16 | sd*B12 |
2485 0xB*B8 | count*2);
2486}
2487
2488
2489void Assembler::vstm(BlockAddrMode am,
2490 Register base,
2491 DwVfpRegister first,
2492 DwVfpRegister last,
2493 Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002494 // Instruction details available in ARM DDI 0406C.b, A8-1080.
Ben Murdoch8b112d22011-06-08 16:22:53 +01002495 // cond(31-28) | 110(27-25)| PUDW0(24-20) | Rbase(19-16) |
2496 // first(15-12) | 1011(11-8) | (count * 2)
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002497 DCHECK_LE(first.code(), last.code());
2498 DCHECK(am == ia || am == ia_w || am == db_w);
2499 DCHECK(!base.is(pc));
Ben Murdoch8b112d22011-06-08 16:22:53 +01002500
2501 int sd, d;
2502 first.split_code(&sd, &d);
2503 int count = last.code() - first.code() + 1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002504 DCHECK(count <= 16);
Ben Murdoch8b112d22011-06-08 16:22:53 +01002505 emit(cond | B27 | B26 | am | d*B22 | base.code()*B16 | sd*B12 |
2506 0xB*B8 | count*2);
2507}
2508
2509void Assembler::vldm(BlockAddrMode am,
2510 Register base,
2511 SwVfpRegister first,
2512 SwVfpRegister last,
2513 Condition cond) {
2514 // Instruction details available in ARM DDI 0406A, A8-626.
2515 // cond(31-28) | 110(27-25)| PUDW1(24-20) | Rbase(19-16) |
2516 // first(15-12) | 1010(11-8) | (count/2)
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002517 DCHECK_LE(first.code(), last.code());
2518 DCHECK(am == ia || am == ia_w || am == db_w);
2519 DCHECK(!base.is(pc));
Ben Murdoch8b112d22011-06-08 16:22:53 +01002520
2521 int sd, d;
2522 first.split_code(&sd, &d);
2523 int count = last.code() - first.code() + 1;
2524 emit(cond | B27 | B26 | am | d*B22 | B20 | base.code()*B16 | sd*B12 |
2525 0xA*B8 | count);
2526}
2527
2528
2529void Assembler::vstm(BlockAddrMode am,
2530 Register base,
2531 SwVfpRegister first,
2532 SwVfpRegister last,
2533 Condition cond) {
2534 // Instruction details available in ARM DDI 0406A, A8-784.
2535 // cond(31-28) | 110(27-25)| PUDW0(24-20) | Rbase(19-16) |
2536 // first(15-12) | 1011(11-8) | (count/2)
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002537 DCHECK_LE(first.code(), last.code());
2538 DCHECK(am == ia || am == ia_w || am == db_w);
2539 DCHECK(!base.is(pc));
Ben Murdoch8b112d22011-06-08 16:22:53 +01002540
2541 int sd, d;
2542 first.split_code(&sd, &d);
2543 int count = last.code() - first.code() + 1;
2544 emit(cond | B27 | B26 | am | d*B22 | base.code()*B16 | sd*B12 |
2545 0xA*B8 | count);
2546}
2547
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002548
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002549void Assembler::vmov(const SwVfpRegister dst, float imm) {
2550 mov(ip, Operand(bit_cast<int32_t>(imm)));
2551 vmov(dst, ip);
2552}
2553
2554
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002555static void DoubleAsTwoUInt32(double d, uint32_t* lo, uint32_t* hi) {
2556 uint64_t i;
2557 memcpy(&i, &d, 8);
2558
2559 *lo = i & 0xffffffff;
2560 *hi = i >> 32;
2561}
2562
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002563
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002564// Only works for little endian floating point formats.
2565// We don't support VFP on the mixed endian floating point platform.
2566static bool FitsVMOVDoubleImmediate(double d, uint32_t *encoding) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002567 DCHECK(CpuFeatures::IsSupported(VFP3));
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002568
2569 // VMOV can accept an immediate of the form:
2570 //
2571 // +/- m * 2^(-n) where 16 <= m <= 31 and 0 <= n <= 7
2572 //
2573 // The immediate is encoded using an 8-bit quantity, comprised of two
2574 // 4-bit fields. For an 8-bit immediate of the form:
2575 //
2576 // [abcdefgh]
2577 //
2578 // where a is the MSB and h is the LSB, an immediate 64-bit double can be
2579 // created of the form:
2580 //
2581 // [aBbbbbbb,bbcdefgh,00000000,00000000,
2582 // 00000000,00000000,00000000,00000000]
2583 //
2584 // where B = ~b.
2585 //
2586
2587 uint32_t lo, hi;
2588 DoubleAsTwoUInt32(d, &lo, &hi);
2589
2590 // The most obvious constraint is the long block of zeroes.
2591 if ((lo != 0) || ((hi & 0xffff) != 0)) {
2592 return false;
2593 }
2594
2595 // Bits 62:55 must be all clear or all set.
2596 if (((hi & 0x3fc00000) != 0) && ((hi & 0x3fc00000) != 0x3fc00000)) {
2597 return false;
2598 }
2599
2600 // Bit 63 must be NOT bit 62.
2601 if (((hi ^ (hi << 1)) & (0x40000000)) == 0) {
2602 return false;
2603 }
2604
2605 // Create the encoded immediate in the form:
2606 // [00000000,0000abcd,00000000,0000efgh]
2607 *encoding = (hi >> 16) & 0xf; // Low nybble.
2608 *encoding |= (hi >> 4) & 0x70000; // Low three bits of the high nybble.
2609 *encoding |= (hi >> 12) & 0x80000; // Top bit of the high nybble.
2610
2611 return true;
2612}
2613
2614
2615void Assembler::vmov(const DwVfpRegister dst,
2616 double imm,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002617 const Register scratch) {
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002618 uint32_t enc;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002619 // If the embedded constant pool is disabled, we can use the normal, inline
2620 // constant pool. If the embedded constant pool is enabled (via
2621 // FLAG_enable_embedded_constant_pool), we can only use it where the pool
2622 // pointer (pp) is valid.
2623 bool can_use_pool =
2624 !FLAG_enable_embedded_constant_pool || is_constant_pool_available();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002625 if (CpuFeatures::IsSupported(VFP3) && FitsVMOVDoubleImmediate(imm, &enc)) {
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002626 // The double can be encoded in the instruction.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002627 //
2628 // Dd = immediate
2629 // Instruction details available in ARM DDI 0406C.b, A8-936.
2630 // cond(31-28) | 11101(27-23) | D(22) | 11(21-20) | imm4H(19-16) |
2631 // Vd(15-12) | 101(11-9) | sz=1(8) | imm4L(3-0)
2632 int vd, d;
2633 dst.split_code(&vd, &d);
2634 emit(al | 0x1D*B23 | d*B22 | 0x3*B20 | vd*B12 | 0x5*B9 | B8 | enc);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002635 } else if (FLAG_enable_vldr_imm && can_use_pool) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002636 // TODO(jfb) Temporarily turned off until we have constant blinding or
2637 // some equivalent mitigation: an attacker can otherwise control
2638 // generated data which also happens to be executable, a Very Bad
2639 // Thing indeed.
2640 // Blinding gets tricky because we don't have xor, we probably
2641 // need to add/subtract without losing precision, which requires a
2642 // cookie value that Lithium is probably better positioned to
2643 // choose.
2644 // We could also add a few peepholes here like detecting 0.0 and
2645 // -0.0 and doing a vmov from the sequestered d14, forcing denorms
2646 // to zero (we set flush-to-zero), and normalizing NaN values.
2647 // We could also detect redundant values.
2648 // The code could also randomize the order of values, though
2649 // that's tricky because vldr has a limited reach. Furthermore
2650 // it breaks load locality.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002651 ConstantPoolEntry::Access access = ConstantPoolAddEntry(pc_offset(), imm);
2652 if (access == ConstantPoolEntry::OVERFLOWED) {
2653 DCHECK(FLAG_enable_embedded_constant_pool);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002654 // Emit instructions to load constant pool offset.
2655 movw(ip, 0);
2656 movt(ip, 0);
2657 // Load from constant pool at offset.
2658 vldr(dst, MemOperand(pp, ip));
2659 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002660 DCHECK(access == ConstantPoolEntry::REGULAR);
2661 vldr(dst, MemOperand(FLAG_enable_embedded_constant_pool ? pp : pc, 0));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002662 }
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002663 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002664 // Synthesise the double from ARM immediates.
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002665 uint32_t lo, hi;
2666 DoubleAsTwoUInt32(imm, &lo, &hi);
2667
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002668 if (lo == hi) {
2669 // Move the low and high parts of the double to a D register in one
2670 // instruction.
2671 mov(ip, Operand(lo));
2672 vmov(dst, ip, ip);
2673 } else if (scratch.is(no_reg)) {
2674 mov(ip, Operand(lo));
2675 vmov(dst, VmovIndexLo, ip);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002676 if (((lo & 0xffff) == (hi & 0xffff)) &&
2677 CpuFeatures::IsSupported(ARMv7)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002678 movt(ip, hi >> 16);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002679 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002680 mov(ip, Operand(hi));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002681 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002682 vmov(dst, VmovIndexHi, ip);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002683 } else {
2684 // Move the low and high parts of the double to a D register in one
2685 // instruction.
2686 mov(ip, Operand(lo));
2687 mov(scratch, Operand(hi));
2688 vmov(dst, ip, scratch);
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002689 }
2690 }
2691}
2692
2693
2694void Assembler::vmov(const SwVfpRegister dst,
2695 const SwVfpRegister src,
2696 const Condition cond) {
2697 // Sd = Sm
2698 // Instruction details available in ARM DDI 0406B, A8-642.
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002699 int sd, d, sm, m;
2700 dst.split_code(&sd, &d);
2701 src.split_code(&sm, &m);
2702 emit(cond | 0xE*B24 | d*B22 | 0xB*B20 | sd*B12 | 0xA*B8 | B6 | m*B5 | sm);
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002703}
2704
2705
Leon Clarkee46be812010-01-19 14:06:41 +00002706void Assembler::vmov(const DwVfpRegister dst,
Steve Block8defd9f2010-07-08 12:39:36 +01002707 const DwVfpRegister src,
2708 const Condition cond) {
2709 // Dd = Dm
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002710 // Instruction details available in ARM DDI 0406C.b, A8-938.
2711 // cond(31-28) | 11101(27-23) | D(22) | 11(21-20) | 0000(19-16) | Vd(15-12) |
2712 // 101(11-9) | sz=1(8) | 0(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
2713 int vd, d;
2714 dst.split_code(&vd, &d);
2715 int vm, m;
2716 src.split_code(&vm, &m);
2717 emit(cond | 0x1D*B23 | d*B22 | 0x3*B20 | vd*B12 | 0x5*B9 | B8 | B6 | m*B5 |
2718 vm);
2719}
2720
2721
2722void Assembler::vmov(const DwVfpRegister dst,
2723 const VmovIndex index,
2724 const Register src,
2725 const Condition cond) {
2726 // Dd[index] = Rt
2727 // Instruction details available in ARM DDI 0406C.b, A8-940.
2728 // cond(31-28) | 1110(27-24) | 0(23) | opc1=0index(22-21) | 0(20) |
2729 // Vd(19-16) | Rt(15-12) | 1011(11-8) | D(7) | opc2=00(6-5) | 1(4) | 0000(3-0)
2730 DCHECK(index.index == 0 || index.index == 1);
2731 int vd, d;
2732 dst.split_code(&vd, &d);
2733 emit(cond | 0xE*B24 | index.index*B21 | vd*B16 | src.code()*B12 | 0xB*B8 |
2734 d*B7 | B4);
2735}
2736
2737
2738void Assembler::vmov(const Register dst,
2739 const VmovIndex index,
2740 const DwVfpRegister src,
2741 const Condition cond) {
2742 // Dd[index] = Rt
2743 // Instruction details available in ARM DDI 0406C.b, A8.8.342.
2744 // cond(31-28) | 1110(27-24) | U=0(23) | opc1=0index(22-21) | 1(20) |
2745 // Vn(19-16) | Rt(15-12) | 1011(11-8) | N(7) | opc2=00(6-5) | 1(4) | 0000(3-0)
2746 DCHECK(index.index == 0 || index.index == 1);
2747 int vn, n;
2748 src.split_code(&vn, &n);
2749 emit(cond | 0xE*B24 | index.index*B21 | B20 | vn*B16 | dst.code()*B12 |
2750 0xB*B8 | n*B7 | B4);
Steve Block8defd9f2010-07-08 12:39:36 +01002751}
2752
2753
2754void Assembler::vmov(const DwVfpRegister dst,
Leon Clarkee46be812010-01-19 14:06:41 +00002755 const Register src1,
2756 const Register src2,
2757 const Condition cond) {
Steve Blockd0582a62009-12-15 09:54:21 +00002758 // Dm = <Rt,Rt2>.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002759 // Instruction details available in ARM DDI 0406C.b, A8-948.
Steve Blockd0582a62009-12-15 09:54:21 +00002760 // cond(31-28) | 1100(27-24)| 010(23-21) | op=0(20) | Rt2(19-16) |
2761 // Rt(15-12) | 1011(11-8) | 00(7-6) | M(5) | 1(4) | Vm
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002762 DCHECK(!src1.is(pc) && !src2.is(pc));
2763 int vm, m;
2764 dst.split_code(&vm, &m);
Steve Blockd0582a62009-12-15 09:54:21 +00002765 emit(cond | 0xC*B24 | B22 | src2.code()*B16 |
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002766 src1.code()*B12 | 0xB*B8 | m*B5 | B4 | vm);
Steve Blockd0582a62009-12-15 09:54:21 +00002767}
2768
2769
Leon Clarkee46be812010-01-19 14:06:41 +00002770void Assembler::vmov(const Register dst1,
2771 const Register dst2,
2772 const DwVfpRegister src,
2773 const Condition cond) {
Steve Blockd0582a62009-12-15 09:54:21 +00002774 // <Rt,Rt2> = Dm.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002775 // Instruction details available in ARM DDI 0406C.b, A8-948.
Steve Blockd0582a62009-12-15 09:54:21 +00002776 // cond(31-28) | 1100(27-24)| 010(23-21) | op=1(20) | Rt2(19-16) |
2777 // Rt(15-12) | 1011(11-8) | 00(7-6) | M(5) | 1(4) | Vm
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002778 DCHECK(!dst1.is(pc) && !dst2.is(pc));
2779 int vm, m;
2780 src.split_code(&vm, &m);
Steve Blockd0582a62009-12-15 09:54:21 +00002781 emit(cond | 0xC*B24 | B22 | B20 | dst2.code()*B16 |
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002782 dst1.code()*B12 | 0xB*B8 | m*B5 | B4 | vm);
Steve Blockd0582a62009-12-15 09:54:21 +00002783}
2784
2785
Leon Clarkee46be812010-01-19 14:06:41 +00002786void Assembler::vmov(const SwVfpRegister dst,
Steve Blockd0582a62009-12-15 09:54:21 +00002787 const Register src,
Steve Blockd0582a62009-12-15 09:54:21 +00002788 const Condition cond) {
2789 // Sn = Rt.
2790 // Instruction details available in ARM DDI 0406A, A8-642.
2791 // cond(31-28) | 1110(27-24)| 000(23-21) | op=0(20) | Vn(19-16) |
2792 // Rt(15-12) | 1010(11-8) | N(7)=0 | 00(6-5) | 1(4) | 0000(3-0)
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002793 DCHECK(!src.is(pc));
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002794 int sn, n;
2795 dst.split_code(&sn, &n);
2796 emit(cond | 0xE*B24 | sn*B16 | src.code()*B12 | 0xA*B8 | n*B7 | B4);
Steve Blockd0582a62009-12-15 09:54:21 +00002797}
2798
2799
Leon Clarkee46be812010-01-19 14:06:41 +00002800void Assembler::vmov(const Register dst,
2801 const SwVfpRegister src,
Steve Blockd0582a62009-12-15 09:54:21 +00002802 const Condition cond) {
2803 // Rt = Sn.
2804 // Instruction details available in ARM DDI 0406A, A8-642.
2805 // cond(31-28) | 1110(27-24)| 000(23-21) | op=1(20) | Vn(19-16) |
2806 // Rt(15-12) | 1010(11-8) | N(7)=0 | 00(6-5) | 1(4) | 0000(3-0)
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002807 DCHECK(!dst.is(pc));
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002808 int sn, n;
2809 src.split_code(&sn, &n);
2810 emit(cond | 0xE*B24 | B20 | sn*B16 | dst.code()*B12 | 0xA*B8 | n*B7 | B4);
Steve Blockd0582a62009-12-15 09:54:21 +00002811}
2812
2813
Steve Block6ded16b2010-05-10 14:33:55 +01002814// Type of data to read from or write to VFP register.
2815// Used as specifier in generic vcvt instruction.
2816enum VFPType { S32, U32, F32, F64 };
2817
2818
2819static bool IsSignedVFPType(VFPType type) {
2820 switch (type) {
2821 case S32:
2822 return true;
2823 case U32:
2824 return false;
2825 default:
2826 UNREACHABLE();
2827 return false;
2828 }
Steve Blockd0582a62009-12-15 09:54:21 +00002829}
2830
2831
Steve Block6ded16b2010-05-10 14:33:55 +01002832static bool IsIntegerVFPType(VFPType type) {
2833 switch (type) {
2834 case S32:
2835 case U32:
2836 return true;
2837 case F32:
2838 case F64:
2839 return false;
2840 default:
2841 UNREACHABLE();
2842 return false;
2843 }
2844}
2845
2846
2847static bool IsDoubleVFPType(VFPType type) {
2848 switch (type) {
2849 case F32:
2850 return false;
2851 case F64:
2852 return true;
2853 default:
2854 UNREACHABLE();
2855 return false;
2856 }
2857}
2858
2859
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002860// Split five bit reg_code based on size of reg_type.
2861// 32-bit register codes are Vm:M
2862// 64-bit register codes are M:Vm
2863// where Vm is four bits, and M is a single bit.
2864static void SplitRegCode(VFPType reg_type,
Steve Block6ded16b2010-05-10 14:33:55 +01002865 int reg_code,
2866 int* vm,
2867 int* m) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002868 DCHECK((reg_code >= 0) && (reg_code <= 31));
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002869 if (IsIntegerVFPType(reg_type) || !IsDoubleVFPType(reg_type)) {
2870 // 32 bit type.
Steve Block6ded16b2010-05-10 14:33:55 +01002871 *m = reg_code & 0x1;
2872 *vm = reg_code >> 1;
2873 } else {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002874 // 64 bit type.
Steve Block6ded16b2010-05-10 14:33:55 +01002875 *m = (reg_code & 0x10) >> 4;
2876 *vm = reg_code & 0x0F;
2877 }
2878}
2879
2880
2881// Encode vcvt.src_type.dst_type instruction.
2882static Instr EncodeVCVT(const VFPType dst_type,
2883 const int dst_code,
2884 const VFPType src_type,
2885 const int src_code,
Steve Block1e0659c2011-05-24 12:43:12 +01002886 VFPConversionMode mode,
Steve Block6ded16b2010-05-10 14:33:55 +01002887 const Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002888 DCHECK(src_type != dst_type);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002889 int D, Vd, M, Vm;
2890 SplitRegCode(src_type, src_code, &Vm, &M);
2891 SplitRegCode(dst_type, dst_code, &Vd, &D);
2892
Steve Block6ded16b2010-05-10 14:33:55 +01002893 if (IsIntegerVFPType(dst_type) || IsIntegerVFPType(src_type)) {
2894 // Conversion between IEEE floating point and 32-bit integer.
2895 // Instruction details available in ARM DDI 0406B, A8.6.295.
2896 // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 1(19) | opc2(18-16) |
2897 // 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 +00002898 DCHECK(!IsIntegerVFPType(dst_type) || !IsIntegerVFPType(src_type));
Steve Block6ded16b2010-05-10 14:33:55 +01002899
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002900 int sz, opc2, op;
Steve Block6ded16b2010-05-10 14:33:55 +01002901
2902 if (IsIntegerVFPType(dst_type)) {
2903 opc2 = IsSignedVFPType(dst_type) ? 0x5 : 0x4;
2904 sz = IsDoubleVFPType(src_type) ? 0x1 : 0x0;
Russell Brenner90bac252010-11-18 13:33:46 -08002905 op = mode;
Steve Block6ded16b2010-05-10 14:33:55 +01002906 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002907 DCHECK(IsIntegerVFPType(src_type));
Steve Block6ded16b2010-05-10 14:33:55 +01002908 opc2 = 0x0;
2909 sz = IsDoubleVFPType(dst_type) ? 0x1 : 0x0;
2910 op = IsSignedVFPType(src_type) ? 0x1 : 0x0;
Steve Block6ded16b2010-05-10 14:33:55 +01002911 }
2912
2913 return (cond | 0xE*B24 | B23 | D*B22 | 0x3*B20 | B19 | opc2*B16 |
2914 Vd*B12 | 0x5*B9 | sz*B8 | op*B7 | B6 | M*B5 | Vm);
2915 } else {
2916 // Conversion between IEEE double and single precision.
2917 // Instruction details available in ARM DDI 0406B, A8.6.298.
2918 // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 0111(19-16) |
2919 // 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 +01002920 int sz = IsDoubleVFPType(src_type) ? 0x1 : 0x0;
Steve Block6ded16b2010-05-10 14:33:55 +01002921 return (cond | 0xE*B24 | B23 | D*B22 | 0x3*B20 | 0x7*B16 |
2922 Vd*B12 | 0x5*B9 | sz*B8 | B7 | B6 | M*B5 | Vm);
2923 }
2924}
2925
2926
2927void Assembler::vcvt_f64_s32(const DwVfpRegister dst,
2928 const SwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +01002929 VFPConversionMode mode,
Steve Block6ded16b2010-05-10 14:33:55 +01002930 const Condition cond) {
Russell Brenner90bac252010-11-18 13:33:46 -08002931 emit(EncodeVCVT(F64, dst.code(), S32, src.code(), mode, cond));
Steve Block6ded16b2010-05-10 14:33:55 +01002932}
2933
2934
2935void Assembler::vcvt_f32_s32(const SwVfpRegister dst,
2936 const SwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +01002937 VFPConversionMode mode,
Steve Block6ded16b2010-05-10 14:33:55 +01002938 const Condition cond) {
Russell Brenner90bac252010-11-18 13:33:46 -08002939 emit(EncodeVCVT(F32, dst.code(), S32, src.code(), mode, cond));
Steve Block6ded16b2010-05-10 14:33:55 +01002940}
2941
2942
2943void Assembler::vcvt_f64_u32(const DwVfpRegister dst,
2944 const SwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +01002945 VFPConversionMode mode,
Steve Block6ded16b2010-05-10 14:33:55 +01002946 const Condition cond) {
Russell Brenner90bac252010-11-18 13:33:46 -08002947 emit(EncodeVCVT(F64, dst.code(), U32, src.code(), mode, cond));
Steve Block6ded16b2010-05-10 14:33:55 +01002948}
2949
2950
Ben Murdoch097c5b22016-05-18 11:27:45 +01002951void Assembler::vcvt_f32_u32(const SwVfpRegister dst, const SwVfpRegister src,
2952 VFPConversionMode mode, const Condition cond) {
2953 emit(EncodeVCVT(F32, dst.code(), U32, src.code(), mode, cond));
2954}
2955
2956
2957void Assembler::vcvt_s32_f32(const SwVfpRegister dst, const SwVfpRegister src,
2958 VFPConversionMode mode, const Condition cond) {
2959 emit(EncodeVCVT(S32, dst.code(), F32, src.code(), mode, cond));
2960}
2961
2962
2963void Assembler::vcvt_u32_f32(const SwVfpRegister dst, const SwVfpRegister src,
2964 VFPConversionMode mode, const Condition cond) {
2965 emit(EncodeVCVT(U32, dst.code(), F32, src.code(), mode, cond));
2966}
2967
2968
Steve Block6ded16b2010-05-10 14:33:55 +01002969void Assembler::vcvt_s32_f64(const SwVfpRegister dst,
2970 const DwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +01002971 VFPConversionMode mode,
Steve Block6ded16b2010-05-10 14:33:55 +01002972 const Condition cond) {
Russell Brenner90bac252010-11-18 13:33:46 -08002973 emit(EncodeVCVT(S32, dst.code(), F64, src.code(), mode, cond));
Steve Block6ded16b2010-05-10 14:33:55 +01002974}
2975
2976
2977void Assembler::vcvt_u32_f64(const SwVfpRegister dst,
2978 const DwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +01002979 VFPConversionMode mode,
Steve Block6ded16b2010-05-10 14:33:55 +01002980 const Condition cond) {
Russell Brenner90bac252010-11-18 13:33:46 -08002981 emit(EncodeVCVT(U32, dst.code(), F64, src.code(), mode, cond));
Steve Block6ded16b2010-05-10 14:33:55 +01002982}
2983
2984
2985void Assembler::vcvt_f64_f32(const DwVfpRegister dst,
2986 const SwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +01002987 VFPConversionMode mode,
Steve Block6ded16b2010-05-10 14:33:55 +01002988 const Condition cond) {
Russell Brenner90bac252010-11-18 13:33:46 -08002989 emit(EncodeVCVT(F64, dst.code(), F32, src.code(), mode, cond));
Steve Block6ded16b2010-05-10 14:33:55 +01002990}
2991
2992
2993void Assembler::vcvt_f32_f64(const SwVfpRegister dst,
2994 const DwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +01002995 VFPConversionMode mode,
Steve Block6ded16b2010-05-10 14:33:55 +01002996 const Condition cond) {
Russell Brenner90bac252010-11-18 13:33:46 -08002997 emit(EncodeVCVT(F32, dst.code(), F64, src.code(), mode, cond));
Steve Blockd0582a62009-12-15 09:54:21 +00002998}
2999
3000
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003001void Assembler::vcvt_f64_s32(const DwVfpRegister dst,
3002 int fraction_bits,
3003 const Condition cond) {
3004 // Instruction details available in ARM DDI 0406C.b, A8-874.
3005 // cond(31-28) | 11101(27-23) | D(22) | 11(21-20) | 1010(19-16) | Vd(15-12) |
3006 // 101(11-9) | sf=1(8) | sx=1(7) | 1(6) | i(5) | 0(4) | imm4(3-0)
3007 DCHECK(fraction_bits > 0 && fraction_bits <= 32);
3008 DCHECK(CpuFeatures::IsSupported(VFP3));
3009 int vd, d;
3010 dst.split_code(&vd, &d);
3011 int imm5 = 32 - fraction_bits;
3012 int i = imm5 & 1;
3013 int imm4 = (imm5 >> 1) & 0xf;
3014 emit(cond | 0xE*B24 | B23 | d*B22 | 0x3*B20 | B19 | 0x2*B16 |
3015 vd*B12 | 0x5*B9 | B8 | B7 | B6 | i*B5 | imm4);
3016}
3017
3018
Steve Block44f0eee2011-05-26 01:26:41 +01003019void Assembler::vneg(const DwVfpRegister dst,
3020 const DwVfpRegister src,
3021 const Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003022 // Instruction details available in ARM DDI 0406C.b, A8-968.
3023 // cond(31-28) | 11101(27-23) | D(22) | 11(21-20) | 0001(19-16) | Vd(15-12) |
3024 // 101(11-9) | sz=1(8) | 0(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
3025 int vd, d;
3026 dst.split_code(&vd, &d);
3027 int vm, m;
3028 src.split_code(&vm, &m);
3029
3030 emit(cond | 0x1D*B23 | d*B22 | 0x3*B20 | B16 | vd*B12 | 0x5*B9 | B8 | B6 |
3031 m*B5 | vm);
Steve Block44f0eee2011-05-26 01:26:41 +01003032}
3033
3034
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003035void Assembler::vneg(const SwVfpRegister dst, const SwVfpRegister src,
3036 const Condition cond) {
3037 // Instruction details available in ARM DDI 0406C.b, A8-968.
3038 // cond(31-28) | 11101(27-23) | D(22) | 11(21-20) | 0001(19-16) | Vd(15-12) |
3039 // 101(11-9) | sz=0(8) | 0(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
3040 int vd, d;
3041 dst.split_code(&vd, &d);
3042 int vm, m;
3043 src.split_code(&vm, &m);
3044
3045 emit(cond | 0x1D * B23 | d * B22 | 0x3 * B20 | B16 | vd * B12 | 0x5 * B9 |
3046 B6 | m * B5 | vm);
3047}
3048
3049
Steve Block1e0659c2011-05-24 12:43:12 +01003050void Assembler::vabs(const DwVfpRegister dst,
3051 const DwVfpRegister src,
3052 const Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003053 // Instruction details available in ARM DDI 0406C.b, A8-524.
3054 // cond(31-28) | 11101(27-23) | D(22) | 11(21-20) | 0000(19-16) | Vd(15-12) |
3055 // 101(11-9) | sz=1(8) | 1(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
3056 int vd, d;
3057 dst.split_code(&vd, &d);
3058 int vm, m;
3059 src.split_code(&vm, &m);
3060 emit(cond | 0x1D*B23 | d*B22 | 0x3*B20 | vd*B12 | 0x5*B9 | B8 | B7 | B6 |
3061 m*B5 | vm);
Steve Block1e0659c2011-05-24 12:43:12 +01003062}
3063
3064
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003065void Assembler::vabs(const SwVfpRegister dst, const SwVfpRegister src,
3066 const Condition cond) {
3067 // Instruction details available in ARM DDI 0406C.b, A8-524.
3068 // cond(31-28) | 11101(27-23) | D(22) | 11(21-20) | 0000(19-16) | Vd(15-12) |
3069 // 101(11-9) | sz=0(8) | 1(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
3070 int vd, d;
3071 dst.split_code(&vd, &d);
3072 int vm, m;
3073 src.split_code(&vm, &m);
3074 emit(cond | 0x1D * B23 | d * B22 | 0x3 * B20 | vd * B12 | 0x5 * B9 | B7 | B6 |
3075 m * B5 | vm);
3076}
3077
3078
Leon Clarkee46be812010-01-19 14:06:41 +00003079void Assembler::vadd(const DwVfpRegister dst,
3080 const DwVfpRegister src1,
3081 const DwVfpRegister src2,
3082 const Condition cond) {
3083 // Dd = vadd(Dn, Dm) double precision floating point addition.
Steve Blockd0582a62009-12-15 09:54:21 +00003084 // Dd = D:Vd; Dm=M:Vm; Dn=N:Vm.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003085 // Instruction details available in ARM DDI 0406C.b, A8-830.
3086 // cond(31-28) | 11100(27-23)| D(22) | 11(21-20) | Vn(19-16) |
3087 // Vd(15-12) | 101(11-9) | sz=1(8) | N(7) | 0(6) | M(5) | 0(4) | Vm(3-0)
3088 int vd, d;
3089 dst.split_code(&vd, &d);
3090 int vn, n;
3091 src1.split_code(&vn, &n);
3092 int vm, m;
3093 src2.split_code(&vm, &m);
3094 emit(cond | 0x1C*B23 | d*B22 | 0x3*B20 | vn*B16 | vd*B12 | 0x5*B9 | B8 |
3095 n*B7 | m*B5 | vm);
Steve Blockd0582a62009-12-15 09:54:21 +00003096}
3097
3098
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003099void Assembler::vadd(const SwVfpRegister dst, const SwVfpRegister src1,
3100 const SwVfpRegister src2, const Condition cond) {
3101 // Sd = vadd(Sn, Sm) single precision floating point addition.
3102 // Sd = D:Vd; Sm=M:Vm; Sn=N:Vm.
3103 // Instruction details available in ARM DDI 0406C.b, A8-830.
3104 // cond(31-28) | 11100(27-23)| D(22) | 11(21-20) | Vn(19-16) |
3105 // Vd(15-12) | 101(11-9) | sz=0(8) | N(7) | 0(6) | M(5) | 0(4) | Vm(3-0)
3106 int vd, d;
3107 dst.split_code(&vd, &d);
3108 int vn, n;
3109 src1.split_code(&vn, &n);
3110 int vm, m;
3111 src2.split_code(&vm, &m);
3112 emit(cond | 0x1C * B23 | d * B22 | 0x3 * B20 | vn * B16 | vd * B12 |
3113 0x5 * B9 | n * B7 | m * B5 | vm);
3114}
3115
3116
Leon Clarkee46be812010-01-19 14:06:41 +00003117void Assembler::vsub(const DwVfpRegister dst,
3118 const DwVfpRegister src1,
3119 const DwVfpRegister src2,
3120 const Condition cond) {
3121 // Dd = vsub(Dn, Dm) double precision floating point subtraction.
Steve Blockd0582a62009-12-15 09:54:21 +00003122 // Dd = D:Vd; Dm=M:Vm; Dn=N:Vm.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003123 // Instruction details available in ARM DDI 0406C.b, A8-1086.
3124 // cond(31-28) | 11100(27-23)| D(22) | 11(21-20) | Vn(19-16) |
3125 // Vd(15-12) | 101(11-9) | sz=1(8) | N(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
3126 int vd, d;
3127 dst.split_code(&vd, &d);
3128 int vn, n;
3129 src1.split_code(&vn, &n);
3130 int vm, m;
3131 src2.split_code(&vm, &m);
3132 emit(cond | 0x1C*B23 | d*B22 | 0x3*B20 | vn*B16 | vd*B12 | 0x5*B9 | B8 |
3133 n*B7 | B6 | m*B5 | vm);
Steve Blockd0582a62009-12-15 09:54:21 +00003134}
3135
3136
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003137void Assembler::vsub(const SwVfpRegister dst, const SwVfpRegister src1,
3138 const SwVfpRegister src2, const Condition cond) {
3139 // Sd = vsub(Sn, Sm) single precision floating point subtraction.
3140 // Sd = D:Vd; Sm=M:Vm; Sn=N:Vm.
3141 // Instruction details available in ARM DDI 0406C.b, A8-1086.
3142 // cond(31-28) | 11100(27-23)| D(22) | 11(21-20) | Vn(19-16) |
3143 // Vd(15-12) | 101(11-9) | sz=0(8) | N(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
3144 int vd, d;
3145 dst.split_code(&vd, &d);
3146 int vn, n;
3147 src1.split_code(&vn, &n);
3148 int vm, m;
3149 src2.split_code(&vm, &m);
3150 emit(cond | 0x1C * B23 | d * B22 | 0x3 * B20 | vn * B16 | vd * B12 |
3151 0x5 * B9 | n * B7 | B6 | m * B5 | vm);
3152}
3153
3154
Leon Clarkee46be812010-01-19 14:06:41 +00003155void Assembler::vmul(const DwVfpRegister dst,
3156 const DwVfpRegister src1,
3157 const DwVfpRegister src2,
3158 const Condition cond) {
3159 // Dd = vmul(Dn, Dm) double precision floating point multiplication.
Steve Blockd0582a62009-12-15 09:54:21 +00003160 // Dd = D:Vd; Dm=M:Vm; Dn=N:Vm.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003161 // Instruction details available in ARM DDI 0406C.b, A8-960.
3162 // cond(31-28) | 11100(27-23)| D(22) | 10(21-20) | Vn(19-16) |
3163 // Vd(15-12) | 101(11-9) | sz=1(8) | N(7) | 0(6) | M(5) | 0(4) | Vm(3-0)
3164 int vd, d;
3165 dst.split_code(&vd, &d);
3166 int vn, n;
3167 src1.split_code(&vn, &n);
3168 int vm, m;
3169 src2.split_code(&vm, &m);
3170 emit(cond | 0x1C*B23 | d*B22 | 0x2*B20 | vn*B16 | vd*B12 | 0x5*B9 | B8 |
3171 n*B7 | m*B5 | vm);
3172}
3173
3174
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003175void Assembler::vmul(const SwVfpRegister dst, const SwVfpRegister src1,
3176 const SwVfpRegister src2, const Condition cond) {
3177 // Sd = vmul(Sn, Sm) single precision floating point multiplication.
3178 // Sd = D:Vd; Sm=M:Vm; Sn=N:Vm.
3179 // Instruction details available in ARM DDI 0406C.b, A8-960.
3180 // cond(31-28) | 11100(27-23)| D(22) | 10(21-20) | Vn(19-16) |
3181 // Vd(15-12) | 101(11-9) | sz=0(8) | N(7) | 0(6) | M(5) | 0(4) | Vm(3-0)
3182 int vd, d;
3183 dst.split_code(&vd, &d);
3184 int vn, n;
3185 src1.split_code(&vn, &n);
3186 int vm, m;
3187 src2.split_code(&vm, &m);
3188 emit(cond | 0x1C * B23 | d * B22 | 0x2 * B20 | vn * B16 | vd * B12 |
3189 0x5 * B9 | n * B7 | m * B5 | vm);
3190}
3191
3192
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003193void Assembler::vmla(const DwVfpRegister dst,
3194 const DwVfpRegister src1,
3195 const DwVfpRegister src2,
3196 const Condition cond) {
3197 // Instruction details available in ARM DDI 0406C.b, A8-932.
3198 // cond(31-28) | 11100(27-23) | D(22) | 00(21-20) | Vn(19-16) |
3199 // Vd(15-12) | 101(11-9) | sz=1(8) | N(7) | op=0(6) | M(5) | 0(4) | Vm(3-0)
3200 int vd, d;
3201 dst.split_code(&vd, &d);
3202 int vn, n;
3203 src1.split_code(&vn, &n);
3204 int vm, m;
3205 src2.split_code(&vm, &m);
3206 emit(cond | 0x1C*B23 | d*B22 | vn*B16 | vd*B12 | 0x5*B9 | B8 | n*B7 | m*B5 |
3207 vm);
3208}
3209
3210
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003211void Assembler::vmla(const SwVfpRegister dst, const SwVfpRegister src1,
3212 const SwVfpRegister src2, const Condition cond) {
3213 // Instruction details available in ARM DDI 0406C.b, A8-932.
3214 // cond(31-28) | 11100(27-23) | D(22) | 00(21-20) | Vn(19-16) |
3215 // Vd(15-12) | 101(11-9) | sz=0(8) | N(7) | op=0(6) | M(5) | 0(4) | Vm(3-0)
3216 int vd, d;
3217 dst.split_code(&vd, &d);
3218 int vn, n;
3219 src1.split_code(&vn, &n);
3220 int vm, m;
3221 src2.split_code(&vm, &m);
3222 emit(cond | 0x1C * B23 | d * B22 | vn * B16 | vd * B12 | 0x5 * B9 | n * B7 |
3223 m * B5 | vm);
3224}
3225
3226
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003227void Assembler::vmls(const DwVfpRegister dst,
3228 const DwVfpRegister src1,
3229 const DwVfpRegister src2,
3230 const Condition cond) {
3231 // Instruction details available in ARM DDI 0406C.b, A8-932.
3232 // cond(31-28) | 11100(27-23) | D(22) | 00(21-20) | Vn(19-16) |
3233 // Vd(15-12) | 101(11-9) | sz=1(8) | N(7) | op=1(6) | M(5) | 0(4) | Vm(3-0)
3234 int vd, d;
3235 dst.split_code(&vd, &d);
3236 int vn, n;
3237 src1.split_code(&vn, &n);
3238 int vm, m;
3239 src2.split_code(&vm, &m);
3240 emit(cond | 0x1C*B23 | d*B22 | vn*B16 | vd*B12 | 0x5*B9 | B8 | n*B7 | B6 |
3241 m*B5 | vm);
Steve Blockd0582a62009-12-15 09:54:21 +00003242}
3243
3244
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003245void Assembler::vmls(const SwVfpRegister dst, const SwVfpRegister src1,
3246 const SwVfpRegister src2, const Condition cond) {
3247 // Instruction details available in ARM DDI 0406C.b, A8-932.
3248 // cond(31-28) | 11100(27-23) | D(22) | 00(21-20) | Vn(19-16) |
3249 // Vd(15-12) | 101(11-9) | sz=0(8) | N(7) | op=1(6) | M(5) | 0(4) | Vm(3-0)
3250 int vd, d;
3251 dst.split_code(&vd, &d);
3252 int vn, n;
3253 src1.split_code(&vn, &n);
3254 int vm, m;
3255 src2.split_code(&vm, &m);
3256 emit(cond | 0x1C * B23 | d * B22 | vn * B16 | vd * B12 | 0x5 * B9 | n * B7 |
3257 B6 | m * B5 | vm);
3258}
3259
3260
Leon Clarkee46be812010-01-19 14:06:41 +00003261void Assembler::vdiv(const DwVfpRegister dst,
3262 const DwVfpRegister src1,
3263 const DwVfpRegister src2,
3264 const Condition cond) {
3265 // Dd = vdiv(Dn, Dm) double precision floating point division.
Steve Blockd0582a62009-12-15 09:54:21 +00003266 // Dd = D:Vd; Dm=M:Vm; Dn=N:Vm.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003267 // Instruction details available in ARM DDI 0406C.b, A8-882.
3268 // cond(31-28) | 11101(27-23)| D(22) | 00(21-20) | Vn(19-16) |
3269 // Vd(15-12) | 101(11-9) | sz=1(8) | N(7) | 0(6) | M(5) | 0(4) | Vm(3-0)
3270 int vd, d;
3271 dst.split_code(&vd, &d);
3272 int vn, n;
3273 src1.split_code(&vn, &n);
3274 int vm, m;
3275 src2.split_code(&vm, &m);
3276 emit(cond | 0x1D*B23 | d*B22 | vn*B16 | vd*B12 | 0x5*B9 | B8 | n*B7 | m*B5 |
3277 vm);
Steve Blockd0582a62009-12-15 09:54:21 +00003278}
3279
3280
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003281void Assembler::vdiv(const SwVfpRegister dst, const SwVfpRegister src1,
3282 const SwVfpRegister src2, const Condition cond) {
3283 // Sd = vdiv(Sn, Sm) single precision floating point division.
3284 // Sd = D:Vd; Sm=M:Vm; Sn=N:Vm.
3285 // Instruction details available in ARM DDI 0406C.b, A8-882.
3286 // cond(31-28) | 11101(27-23)| D(22) | 00(21-20) | Vn(19-16) |
3287 // Vd(15-12) | 101(11-9) | sz=0(8) | N(7) | 0(6) | M(5) | 0(4) | Vm(3-0)
3288 int vd, d;
3289 dst.split_code(&vd, &d);
3290 int vn, n;
3291 src1.split_code(&vn, &n);
3292 int vm, m;
3293 src2.split_code(&vm, &m);
3294 emit(cond | 0x1D * B23 | d * B22 | vn * B16 | vd * B12 | 0x5 * B9 | n * B7 |
3295 m * B5 | vm);
3296}
3297
3298
Leon Clarkee46be812010-01-19 14:06:41 +00003299void Assembler::vcmp(const DwVfpRegister src1,
3300 const DwVfpRegister src2,
Steve Blockd0582a62009-12-15 09:54:21 +00003301 const Condition cond) {
3302 // vcmp(Dd, Dm) double precision floating point comparison.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003303 // Instruction details available in ARM DDI 0406C.b, A8-864.
3304 // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 0100(19-16) |
3305 // Vd(15-12) | 101(11-9) | sz=1(8) | E=0(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
3306 int vd, d;
3307 src1.split_code(&vd, &d);
3308 int vm, m;
3309 src2.split_code(&vm, &m);
3310 emit(cond | 0x1D*B23 | d*B22 | 0x3*B20 | 0x4*B16 | vd*B12 | 0x5*B9 | B8 | B6 |
3311 m*B5 | vm);
Steve Blockd0582a62009-12-15 09:54:21 +00003312}
3313
3314
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003315void Assembler::vcmp(const SwVfpRegister src1, const SwVfpRegister src2,
3316 const Condition cond) {
3317 // vcmp(Sd, Sm) single precision floating point comparison.
3318 // Instruction details available in ARM DDI 0406C.b, A8-864.
3319 // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 0100(19-16) |
3320 // Vd(15-12) | 101(11-9) | sz=0(8) | E=0(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
3321 int vd, d;
3322 src1.split_code(&vd, &d);
3323 int vm, m;
3324 src2.split_code(&vm, &m);
3325 emit(cond | 0x1D * B23 | d * B22 | 0x3 * B20 | 0x4 * B16 | vd * B12 |
3326 0x5 * B9 | B6 | m * B5 | vm);
3327}
3328
3329
Iain Merrick75681382010-08-19 15:07:18 +01003330void Assembler::vcmp(const DwVfpRegister src1,
3331 const double src2,
Iain Merrick75681382010-08-19 15:07:18 +01003332 const Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003333 // vcmp(Dd, #0.0) double precision floating point comparison.
3334 // Instruction details available in ARM DDI 0406C.b, A8-864.
3335 // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 0101(19-16) |
3336 // Vd(15-12) | 101(11-9) | sz=1(8) | E=0(7) | 1(6) | 0(5) | 0(4) | 0000(3-0)
3337 DCHECK(src2 == 0.0);
3338 int vd, d;
3339 src1.split_code(&vd, &d);
3340 emit(cond | 0x1D*B23 | d*B22 | 0x3*B20 | 0x5*B16 | vd*B12 | 0x5*B9 | B8 | B6);
Iain Merrick75681382010-08-19 15:07:18 +01003341}
3342
3343
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003344void Assembler::vcmp(const SwVfpRegister src1, const float src2,
3345 const Condition cond) {
3346 // vcmp(Sd, #0.0) single precision floating point comparison.
3347 // Instruction details available in ARM DDI 0406C.b, A8-864.
3348 // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 0101(19-16) |
3349 // Vd(15-12) | 101(11-9) | sz=0(8) | E=0(7) | 1(6) | 0(5) | 0(4) | 0000(3-0)
3350 DCHECK(src2 == 0.0);
3351 int vd, d;
3352 src1.split_code(&vd, &d);
3353 emit(cond | 0x1D * B23 | d * B22 | 0x3 * B20 | 0x5 * B16 | vd * B12 |
3354 0x5 * B9 | B6);
Steve Blockd0582a62009-12-15 09:54:21 +00003355}
3356
3357
Steve Block8defd9f2010-07-08 12:39:36 +01003358void Assembler::vsqrt(const DwVfpRegister dst,
3359 const DwVfpRegister src,
3360 const Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003361 // Instruction details available in ARM DDI 0406C.b, A8-1058.
3362 // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 0001(19-16) |
3363 // Vd(15-12) | 101(11-9) | sz=1(8) | 11(7-6) | M(5) | 0(4) | Vm(3-0)
3364 int vd, d;
3365 dst.split_code(&vd, &d);
3366 int vm, m;
3367 src.split_code(&vm, &m);
3368 emit(cond | 0x1D*B23 | d*B22 | 0x3*B20 | B16 | vd*B12 | 0x5*B9 | B8 | 0x3*B6 |
3369 m*B5 | vm);
3370}
3371
3372
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003373void Assembler::vsqrt(const SwVfpRegister dst, const SwVfpRegister src,
3374 const Condition cond) {
3375 // Instruction details available in ARM DDI 0406C.b, A8-1058.
3376 // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 0001(19-16) |
3377 // Vd(15-12) | 101(11-9) | sz=0(8) | 11(7-6) | M(5) | 0(4) | Vm(3-0)
3378 int vd, d;
3379 dst.split_code(&vd, &d);
3380 int vm, m;
3381 src.split_code(&vm, &m);
3382 emit(cond | 0x1D * B23 | d * B22 | 0x3 * B20 | B16 | vd * B12 | 0x5 * B9 |
3383 0x3 * B6 | m * B5 | vm);
3384}
3385
3386
3387void Assembler::vmsr(Register dst, Condition cond) {
3388 // Instruction details available in ARM DDI 0406A, A8-652.
3389 // cond(31-28) | 1110 (27-24) | 1110(23-20)| 0001 (19-16) |
3390 // Rt(15-12) | 1010 (11-8) | 0(7) | 00 (6-5) | 1(4) | 0000(3-0)
3391 emit(cond | 0xE * B24 | 0xE * B20 | B16 | dst.code() * B12 | 0xA * B8 | B4);
3392}
3393
3394
3395void Assembler::vmrs(Register dst, Condition cond) {
3396 // Instruction details available in ARM DDI 0406A, A8-652.
3397 // cond(31-28) | 1110 (27-24) | 1111(23-20)| 0001 (19-16) |
3398 // Rt(15-12) | 1010 (11-8) | 0(7) | 00 (6-5) | 1(4) | 0000(3-0)
3399 emit(cond | 0xE * B24 | 0xF * B20 | B16 | dst.code() * B12 | 0xA * B8 | B4);
3400}
3401
3402
3403void Assembler::vrinta(const SwVfpRegister dst, const SwVfpRegister src) {
3404 // cond=kSpecialCondition(31-28) | 11101(27-23)| D(22) | 11(21-20) |
3405 // 10(19-18) | RM=00(17-16) | Vd(15-12) | 101(11-9) | sz=0(8) | 01(7-6) |
3406 // M(5) | 0(4) | Vm(3-0)
3407 DCHECK(CpuFeatures::IsSupported(ARMv8));
3408 int vd, d;
3409 dst.split_code(&vd, &d);
3410 int vm, m;
3411 src.split_code(&vm, &m);
3412 emit(kSpecialCondition | 0x1D * B23 | d * B22 | 0x3 * B20 | B19 | vd * B12 |
3413 0x5 * B9 | B6 | m * B5 | vm);
3414}
3415
3416
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003417void Assembler::vrinta(const DwVfpRegister dst, const DwVfpRegister src) {
3418 // cond=kSpecialCondition(31-28) | 11101(27-23)| D(22) | 11(21-20) |
3419 // 10(19-18) | RM=00(17-16) | Vd(15-12) | 101(11-9) | sz=1(8) | 01(7-6) |
3420 // M(5) | 0(4) | Vm(3-0)
3421 DCHECK(CpuFeatures::IsSupported(ARMv8));
3422 int vd, d;
3423 dst.split_code(&vd, &d);
3424 int vm, m;
3425 src.split_code(&vm, &m);
3426 emit(kSpecialCondition | 0x1D * B23 | d * B22 | 0x3 * B20 | B19 | vd * B12 |
3427 0x5 * B9 | B8 | B6 | m * B5 | vm);
3428}
3429
3430
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003431void Assembler::vrintn(const SwVfpRegister dst, const SwVfpRegister src) {
3432 // cond=kSpecialCondition(31-28) | 11101(27-23)| D(22) | 11(21-20) |
3433 // 10(19-18) | RM=01(17-16) | Vd(15-12) | 101(11-9) | sz=0(8) | 01(7-6) |
3434 // M(5) | 0(4) | Vm(3-0)
3435 DCHECK(CpuFeatures::IsSupported(ARMv8));
3436 int vd, d;
3437 dst.split_code(&vd, &d);
3438 int vm, m;
3439 src.split_code(&vm, &m);
3440 emit(kSpecialCondition | 0x1D * B23 | d * B22 | 0x3 * B20 | B19 | 0x1 * B16 |
3441 vd * B12 | 0x5 * B9 | B6 | m * B5 | vm);
3442}
3443
3444
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003445void Assembler::vrintn(const DwVfpRegister dst, const DwVfpRegister src) {
3446 // cond=kSpecialCondition(31-28) | 11101(27-23)| D(22) | 11(21-20) |
3447 // 10(19-18) | RM=01(17-16) | Vd(15-12) | 101(11-9) | sz=1(8) | 01(7-6) |
3448 // M(5) | 0(4) | Vm(3-0)
3449 DCHECK(CpuFeatures::IsSupported(ARMv8));
3450 int vd, d;
3451 dst.split_code(&vd, &d);
3452 int vm, m;
3453 src.split_code(&vm, &m);
3454 emit(kSpecialCondition | 0x1D * B23 | d * B22 | 0x3 * B20 | B19 | 0x1 * B16 |
3455 vd * B12 | 0x5 * B9 | B8 | B6 | m * B5 | vm);
3456}
3457
3458
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003459void Assembler::vrintp(const SwVfpRegister dst, const SwVfpRegister src) {
3460 // cond=kSpecialCondition(31-28) | 11101(27-23)| D(22) | 11(21-20) |
3461 // 10(19-18) | RM=10(17-16) | Vd(15-12) | 101(11-9) | sz=0(8) | 01(7-6) |
3462 // M(5) | 0(4) | Vm(3-0)
3463 DCHECK(CpuFeatures::IsSupported(ARMv8));
3464 int vd, d;
3465 dst.split_code(&vd, &d);
3466 int vm, m;
3467 src.split_code(&vm, &m);
3468 emit(kSpecialCondition | 0x1D * B23 | d * B22 | 0x3 * B20 | B19 | 0x2 * B16 |
3469 vd * B12 | 0x5 * B9 | B6 | m * B5 | vm);
3470}
3471
3472
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003473void Assembler::vrintp(const DwVfpRegister dst, const DwVfpRegister src) {
3474 // cond=kSpecialCondition(31-28) | 11101(27-23)| D(22) | 11(21-20) |
3475 // 10(19-18) | RM=10(17-16) | Vd(15-12) | 101(11-9) | sz=1(8) | 01(7-6) |
3476 // M(5) | 0(4) | Vm(3-0)
3477 DCHECK(CpuFeatures::IsSupported(ARMv8));
3478 int vd, d;
3479 dst.split_code(&vd, &d);
3480 int vm, m;
3481 src.split_code(&vm, &m);
3482 emit(kSpecialCondition | 0x1D * B23 | d * B22 | 0x3 * B20 | B19 | 0x2 * B16 |
3483 vd * B12 | 0x5 * B9 | B8 | B6 | m * B5 | vm);
3484}
3485
3486
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003487void Assembler::vrintm(const SwVfpRegister dst, const SwVfpRegister src) {
3488 // cond=kSpecialCondition(31-28) | 11101(27-23)| D(22) | 11(21-20) |
3489 // 10(19-18) | RM=11(17-16) | Vd(15-12) | 101(11-9) | sz=0(8) | 01(7-6) |
3490 // M(5) | 0(4) | Vm(3-0)
3491 DCHECK(CpuFeatures::IsSupported(ARMv8));
3492 int vd, d;
3493 dst.split_code(&vd, &d);
3494 int vm, m;
3495 src.split_code(&vm, &m);
3496 emit(kSpecialCondition | 0x1D * B23 | d * B22 | 0x3 * B20 | B19 | 0x3 * B16 |
3497 vd * B12 | 0x5 * B9 | B6 | m * B5 | vm);
3498}
3499
3500
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003501void Assembler::vrintm(const DwVfpRegister dst, const DwVfpRegister src) {
3502 // cond=kSpecialCondition(31-28) | 11101(27-23)| D(22) | 11(21-20) |
3503 // 10(19-18) | RM=11(17-16) | Vd(15-12) | 101(11-9) | sz=1(8) | 01(7-6) |
3504 // M(5) | 0(4) | Vm(3-0)
3505 DCHECK(CpuFeatures::IsSupported(ARMv8));
3506 int vd, d;
3507 dst.split_code(&vd, &d);
3508 int vm, m;
3509 src.split_code(&vm, &m);
3510 emit(kSpecialCondition | 0x1D * B23 | d * B22 | 0x3 * B20 | B19 | 0x3 * B16 |
3511 vd * B12 | 0x5 * B9 | B8 | B6 | m * B5 | vm);
3512}
3513
3514
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003515void Assembler::vrintz(const SwVfpRegister dst, const SwVfpRegister src,
3516 const Condition cond) {
3517 // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 011(19-17) | 0(16) |
3518 // Vd(15-12) | 101(11-9) | sz=0(8) | op=1(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
3519 DCHECK(CpuFeatures::IsSupported(ARMv8));
3520 int vd, d;
3521 dst.split_code(&vd, &d);
3522 int vm, m;
3523 src.split_code(&vm, &m);
3524 emit(cond | 0x1D * B23 | d * B22 | 0x3 * B20 | 0x3 * B17 | vd * B12 |
3525 0x5 * B9 | B7 | B6 | m * B5 | vm);
3526}
3527
3528
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003529void Assembler::vrintz(const DwVfpRegister dst, const DwVfpRegister src,
3530 const Condition cond) {
3531 // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 011(19-17) | 0(16) |
3532 // Vd(15-12) | 101(11-9) | sz=1(8) | op=1(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
3533 DCHECK(CpuFeatures::IsSupported(ARMv8));
3534 int vd, d;
3535 dst.split_code(&vd, &d);
3536 int vm, m;
3537 src.split_code(&vm, &m);
3538 emit(cond | 0x1D * B23 | d * B22 | 0x3 * B20 | 0x3 * B17 | vd * B12 |
3539 0x5 * B9 | B8 | B7 | B6 | m * B5 | vm);
3540}
3541
3542
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003543// Support for NEON.
3544
3545void Assembler::vld1(NeonSize size,
3546 const NeonListOperand& dst,
3547 const NeonMemOperand& src) {
3548 // Instruction details available in ARM DDI 0406C.b, A8.8.320.
3549 // 1111(31-28) | 01000(27-23) | D(22) | 10(21-20) | Rn(19-16) |
3550 // Vd(15-12) | type(11-8) | size(7-6) | align(5-4) | Rm(3-0)
3551 DCHECK(CpuFeatures::IsSupported(NEON));
3552 int vd, d;
3553 dst.base().split_code(&vd, &d);
3554 emit(0xFU*B28 | 4*B24 | d*B22 | 2*B20 | src.rn().code()*B16 | vd*B12 |
3555 dst.type()*B8 | size*B6 | src.align()*B4 | src.rm().code());
3556}
3557
3558
3559void Assembler::vst1(NeonSize size,
3560 const NeonListOperand& src,
3561 const NeonMemOperand& dst) {
3562 // Instruction details available in ARM DDI 0406C.b, A8.8.404.
3563 // 1111(31-28) | 01000(27-23) | D(22) | 00(21-20) | Rn(19-16) |
3564 // Vd(15-12) | type(11-8) | size(7-6) | align(5-4) | Rm(3-0)
3565 DCHECK(CpuFeatures::IsSupported(NEON));
3566 int vd, d;
3567 src.base().split_code(&vd, &d);
3568 emit(0xFU*B28 | 4*B24 | d*B22 | dst.rn().code()*B16 | vd*B12 | src.type()*B8 |
3569 size*B6 | dst.align()*B4 | dst.rm().code());
3570}
3571
3572
3573void Assembler::vmovl(NeonDataType dt, QwNeonRegister dst, DwVfpRegister src) {
3574 // Instruction details available in ARM DDI 0406C.b, A8.8.346.
3575 // 1111(31-28) | 001(27-25) | U(24) | 1(23) | D(22) | imm3(21-19) |
3576 // 000(18-16) | Vd(15-12) | 101000(11-6) | M(5) | 1(4) | Vm(3-0)
3577 DCHECK(CpuFeatures::IsSupported(NEON));
3578 int vd, d;
3579 dst.split_code(&vd, &d);
3580 int vm, m;
3581 src.split_code(&vm, &m);
3582 emit(0xFU*B28 | B25 | (dt & NeonDataTypeUMask) | B23 | d*B22 |
3583 (dt & NeonDataTypeSizeMask)*B19 | vd*B12 | 0xA*B8 | m*B5 | B4 | vm);
Steve Block8defd9f2010-07-08 12:39:36 +01003584}
3585
3586
Andrei Popescu31002712010-02-23 13:46:05 +00003587// Pseudo instructions.
Steve Block6ded16b2010-05-10 14:33:55 +01003588void Assembler::nop(int type) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003589 // ARMv6{K/T2} and v7 have an actual NOP instruction but it serializes
3590 // some of the CPU's pipeline and has to issue. Older ARM chips simply used
3591 // MOV Rx, Rx as NOP and it performs better even in newer CPUs.
3592 // We therefore use MOV Rx, Rx, even on newer CPUs, and use Rx to encode
3593 // a type.
3594 DCHECK(0 <= type && type <= 14); // mov pc, pc isn't a nop.
Steve Block6ded16b2010-05-10 14:33:55 +01003595 emit(al | 13*B21 | type*B12 | type);
3596}
3597
3598
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003599bool Assembler::IsMovT(Instr instr) {
3600 instr &= ~(((kNumberOfConditions - 1) << 28) | // Mask off conditions
3601 ((kNumRegisters-1)*B12) | // mask out register
3602 EncodeMovwImmediate(0xFFFF)); // mask out immediate value
3603 return instr == kMovtPattern;
3604}
3605
3606
3607bool Assembler::IsMovW(Instr instr) {
3608 instr &= ~(((kNumberOfConditions - 1) << 28) | // Mask off conditions
3609 ((kNumRegisters-1)*B12) | // mask out destination
3610 EncodeMovwImmediate(0xFFFF)); // mask out immediate value
3611 return instr == kMovwPattern;
3612}
3613
3614
3615Instr Assembler::GetMovTPattern() { return kMovtPattern; }
3616
3617
3618Instr Assembler::GetMovWPattern() { return kMovwPattern; }
3619
3620
3621Instr Assembler::EncodeMovwImmediate(uint32_t immediate) {
3622 DCHECK(immediate < 0x10000);
3623 return ((immediate & 0xf000) << 4) | (immediate & 0xfff);
3624}
3625
3626
3627Instr Assembler::PatchMovwImmediate(Instr instruction, uint32_t immediate) {
3628 instruction &= ~EncodeMovwImmediate(0xffff);
3629 return instruction | EncodeMovwImmediate(immediate);
3630}
3631
3632
3633int Assembler::DecodeShiftImm(Instr instr) {
3634 int rotate = Instruction::RotateValue(instr) * 2;
3635 int immed8 = Instruction::Immed8Value(instr);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003636 return base::bits::RotateRight32(immed8, rotate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003637}
3638
3639
3640Instr Assembler::PatchShiftImm(Instr instr, int immed) {
3641 uint32_t rotate_imm = 0;
3642 uint32_t immed_8 = 0;
3643 bool immed_fits = fits_shifter(immed, &rotate_imm, &immed_8, NULL);
3644 DCHECK(immed_fits);
3645 USE(immed_fits);
3646 return (instr & ~kOff12Mask) | (rotate_imm << 8) | immed_8;
3647}
3648
3649
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08003650bool Assembler::IsNop(Instr instr, int type) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003651 DCHECK(0 <= type && type <= 14); // mov pc, pc isn't a nop.
Steve Block1e0659c2011-05-24 12:43:12 +01003652 // Check for mov rx, rx where x = type.
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08003653 return instr == (al | 13*B21 | type*B12 | type);
3654}
3655
3656
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003657bool Assembler::IsMovImmed(Instr instr) {
3658 return (instr & kMovImmedMask) == kMovImmedPattern;
3659}
3660
3661
3662bool Assembler::IsOrrImmed(Instr instr) {
3663 return (instr & kOrrImmedMask) == kOrrImmedPattern;
3664}
3665
3666
3667// static
Steve Blockd0582a62009-12-15 09:54:21 +00003668bool Assembler::ImmediateFitsAddrMode1Instruction(int32_t imm32) {
3669 uint32_t dummy1;
3670 uint32_t dummy2;
3671 return fits_shifter(imm32, &dummy1, &dummy2, NULL);
3672}
3673
3674
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003675bool Assembler::ImmediateFitsAddrMode2Instruction(int32_t imm32) {
3676 return is_uint12(abs(imm32));
3677}
3678
3679
Andrei Popescu31002712010-02-23 13:46:05 +00003680// Debugging.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003681void Assembler::RecordConstPool(int size) {
3682 // We only need this for debugger support, to correctly compute offsets in the
3683 // code.
3684 RecordRelocInfo(RelocInfo::CONST_POOL, static_cast<intptr_t>(size));
3685}
3686
3687
Steve Blocka7e24c12009-10-30 11:49:00 +00003688void Assembler::GrowBuffer() {
3689 if (!own_buffer_) FATAL("external code buffer is too small");
3690
Andrei Popescu31002712010-02-23 13:46:05 +00003691 // Compute new buffer size.
Steve Blocka7e24c12009-10-30 11:49:00 +00003692 CodeDesc desc; // the new buffer
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003693 if (buffer_size_ < 1 * MB) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003694 desc.buffer_size = 2*buffer_size_;
3695 } else {
3696 desc.buffer_size = buffer_size_ + 1*MB;
3697 }
3698 CHECK_GT(desc.buffer_size, 0); // no overflow
3699
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003700 // Set up new buffer.
Steve Blocka7e24c12009-10-30 11:49:00 +00003701 desc.buffer = NewArray<byte>(desc.buffer_size);
3702
3703 desc.instr_size = pc_offset();
3704 desc.reloc_size = (buffer_ + buffer_size_) - reloc_info_writer.pos();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003705 desc.origin = this;
Steve Blocka7e24c12009-10-30 11:49:00 +00003706
Andrei Popescu31002712010-02-23 13:46:05 +00003707 // Copy the data.
Steve Blocka7e24c12009-10-30 11:49:00 +00003708 int pc_delta = desc.buffer - buffer_;
3709 int rc_delta = (desc.buffer + desc.buffer_size) - (buffer_ + buffer_size_);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003710 MemMove(desc.buffer, buffer_, desc.instr_size);
3711 MemMove(reloc_info_writer.pos() + rc_delta, reloc_info_writer.pos(),
3712 desc.reloc_size);
Steve Blocka7e24c12009-10-30 11:49:00 +00003713
Andrei Popescu31002712010-02-23 13:46:05 +00003714 // Switch buffers.
Steve Blocka7e24c12009-10-30 11:49:00 +00003715 DeleteArray(buffer_);
3716 buffer_ = desc.buffer;
3717 buffer_size_ = desc.buffer_size;
3718 pc_ += pc_delta;
3719 reloc_info_writer.Reposition(reloc_info_writer.pos() + rc_delta,
3720 reloc_info_writer.last_pc() + pc_delta);
3721
Andrei Popescu31002712010-02-23 13:46:05 +00003722 // None of our relocation types are pc relative pointing outside the code
Steve Blocka7e24c12009-10-30 11:49:00 +00003723 // buffer nor pc absolute pointing inside the code buffer, so there is no need
Andrei Popescu31002712010-02-23 13:46:05 +00003724 // to relocate any emitted relocation entries.
Steve Blocka7e24c12009-10-30 11:49:00 +00003725}
3726
3727
Ben Murdochb0fe1622011-05-05 13:52:32 +01003728void Assembler::db(uint8_t data) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003729 // db is used to write raw data. The constant pool should be emitted or
3730 // blocked before using db.
3731 DCHECK(is_const_pool_blocked() || (num_pending_32_bit_constants_ == 0));
3732 DCHECK(is_const_pool_blocked() || (num_pending_64_bit_constants_ == 0));
Ben Murdochb0fe1622011-05-05 13:52:32 +01003733 CheckBuffer();
3734 *reinterpret_cast<uint8_t*>(pc_) = data;
3735 pc_ += sizeof(uint8_t);
3736}
3737
3738
3739void Assembler::dd(uint32_t data) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003740 // dd is used to write raw data. The constant pool should be emitted or
3741 // blocked before using dd.
3742 DCHECK(is_const_pool_blocked() || (num_pending_32_bit_constants_ == 0));
3743 DCHECK(is_const_pool_blocked() || (num_pending_64_bit_constants_ == 0));
Ben Murdochb0fe1622011-05-05 13:52:32 +01003744 CheckBuffer();
3745 *reinterpret_cast<uint32_t*>(pc_) = data;
3746 pc_ += sizeof(uint32_t);
3747}
3748
3749
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003750void Assembler::dq(uint64_t value) {
3751 // dq is used to write raw data. The constant pool should be emitted or
3752 // blocked before using dq.
3753 DCHECK(is_const_pool_blocked() || (num_pending_32_bit_constants_ == 0));
3754 DCHECK(is_const_pool_blocked() || (num_pending_64_bit_constants_ == 0));
3755 CheckBuffer();
3756 *reinterpret_cast<uint64_t*>(pc_) = value;
3757 pc_ += sizeof(uint64_t);
3758}
3759
3760
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003761void Assembler::emit_code_stub_address(Code* stub) {
3762 CheckBuffer();
3763 *reinterpret_cast<uint32_t*>(pc_) =
3764 reinterpret_cast<uint32_t>(stub->instruction_start());
3765 pc_ += sizeof(uint32_t);
3766}
3767
3768
Steve Blocka7e24c12009-10-30 11:49:00 +00003769void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003770 if (RelocInfo::IsNone(rmode) ||
3771 // Don't record external references unless the heap will be serialized.
3772 (rmode == RelocInfo::EXTERNAL_REFERENCE && !serializer_enabled() &&
3773 !emit_debug_code())) {
3774 return;
3775 }
3776 DCHECK(buffer_space() >= kMaxRelocSize); // too late to grow buffer here
3777 if (rmode == RelocInfo::CODE_TARGET_WITH_ID) {
3778 data = RecordedAstId().ToInt();
3779 ClearRecordedAstId();
3780 }
3781 RelocInfo rinfo(isolate(), pc_, rmode, data, NULL);
3782 reloc_info_writer.Write(&rinfo);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003783}
3784
3785
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003786ConstantPoolEntry::Access Assembler::ConstantPoolAddEntry(int position,
3787 RelocInfo::Mode rmode,
3788 intptr_t value) {
3789 DCHECK(rmode != RelocInfo::COMMENT && rmode != RelocInfo::POSITION &&
3790 rmode != RelocInfo::STATEMENT_POSITION &&
3791 rmode != RelocInfo::CONST_POOL && rmode != RelocInfo::NONE64);
3792 bool sharing_ok = RelocInfo::IsNone(rmode) ||
3793 !(serializer_enabled() || rmode < RelocInfo::CELL);
3794 if (FLAG_enable_embedded_constant_pool) {
3795 return constant_pool_builder_.AddEntry(position, value, sharing_ok);
3796 } else {
3797 DCHECK(num_pending_32_bit_constants_ < kMaxNumPending32Constants);
3798 if (num_pending_32_bit_constants_ == 0) {
3799 first_const_pool_32_use_ = position;
3800 } else if (num_pending_32_bit_constants_ == kMinNumPendingConstants &&
3801 pending_32_bit_constants_ ==
3802 &pending_32_bit_constants_buffer_[0]) {
3803 // Inline buffer is full, switch to dynamically allocated buffer.
3804 pending_32_bit_constants_ =
3805 new ConstantPoolEntry[kMaxNumPending32Constants];
3806 std::copy(&pending_32_bit_constants_buffer_[0],
3807 &pending_32_bit_constants_buffer_[kMinNumPendingConstants],
3808 &pending_32_bit_constants_[0]);
Steve Blocka7e24c12009-10-30 11:49:00 +00003809 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003810 ConstantPoolEntry entry(position, value, sharing_ok);
3811 pending_32_bit_constants_[num_pending_32_bit_constants_++] = entry;
3812
3813 // Make sure the constant pool is not emitted in place of the next
3814 // instruction for which we just recorded relocation info.
3815 BlockConstPoolFor(1);
3816 return ConstantPoolEntry::REGULAR;
Steve Blocka7e24c12009-10-30 11:49:00 +00003817 }
3818}
3819
3820
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003821ConstantPoolEntry::Access Assembler::ConstantPoolAddEntry(int position,
3822 double value) {
3823 if (FLAG_enable_embedded_constant_pool) {
3824 return constant_pool_builder_.AddEntry(position, value);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003825 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003826 DCHECK(num_pending_64_bit_constants_ < kMaxNumPending64Constants);
3827 if (num_pending_64_bit_constants_ == 0) {
3828 first_const_pool_64_use_ = position;
3829 } else if (num_pending_64_bit_constants_ == kMinNumPendingConstants &&
3830 pending_64_bit_constants_ ==
3831 &pending_64_bit_constants_buffer_[0]) {
3832 // Inline buffer is full, switch to dynamically allocated buffer.
3833 pending_64_bit_constants_ =
3834 new ConstantPoolEntry[kMaxNumPending64Constants];
3835 std::copy(&pending_64_bit_constants_buffer_[0],
3836 &pending_64_bit_constants_buffer_[kMinNumPendingConstants],
3837 &pending_64_bit_constants_[0]);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003838 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003839 ConstantPoolEntry entry(position, value);
3840 pending_64_bit_constants_[num_pending_64_bit_constants_++] = entry;
3841
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003842 // Make sure the constant pool is not emitted in place of the next
3843 // instruction for which we just recorded relocation info.
3844 BlockConstPoolFor(1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003845 return ConstantPoolEntry::REGULAR;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003846 }
3847}
3848
3849
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003850void Assembler::BlockConstPoolFor(int instructions) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003851 if (FLAG_enable_embedded_constant_pool) {
3852 // Should be a no-op if using an embedded constant pool.
3853 DCHECK(num_pending_32_bit_constants_ == 0);
3854 DCHECK(num_pending_64_bit_constants_ == 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003855 return;
3856 }
3857
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003858 int pc_limit = pc_offset() + instructions * kInstrSize;
3859 if (no_const_pool_before_ < pc_limit) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003860 // Max pool start (if we need a jump and an alignment).
3861#ifdef DEBUG
3862 int start = pc_limit + kInstrSize + 2 * kPointerSize;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003863 DCHECK((num_pending_32_bit_constants_ == 0) ||
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003864 (start - first_const_pool_32_use_ +
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003865 num_pending_64_bit_constants_ * kDoubleSize <
3866 kMaxDistToIntPool));
3867 DCHECK((num_pending_64_bit_constants_ == 0) ||
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003868 (start - first_const_pool_64_use_ < kMaxDistToFPPool));
3869#endif
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003870 no_const_pool_before_ = pc_limit;
Steve Blocka7e24c12009-10-30 11:49:00 +00003871 }
3872
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003873 if (next_buffer_check_ < no_const_pool_before_) {
3874 next_buffer_check_ = no_const_pool_before_;
3875 }
3876}
Steve Blocka7e24c12009-10-30 11:49:00 +00003877
Steve Blocka7e24c12009-10-30 11:49:00 +00003878
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003879void Assembler::CheckConstPool(bool force_emit, bool require_jump) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003880 if (FLAG_enable_embedded_constant_pool) {
3881 // Should be a no-op if using an embedded constant pool.
3882 DCHECK(num_pending_32_bit_constants_ == 0);
3883 DCHECK(num_pending_64_bit_constants_ == 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003884 return;
3885 }
3886
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003887 // Some short sequence of instruction mustn't be broken up by constant pool
3888 // emission, such sequences are protected by calls to BlockConstPoolFor and
3889 // BlockConstPoolScope.
3890 if (is_const_pool_blocked()) {
Andrei Popescu31002712010-02-23 13:46:05 +00003891 // Something is wrong if emission is forced and blocked at the same time.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003892 DCHECK(!force_emit);
Steve Blocka7e24c12009-10-30 11:49:00 +00003893 return;
3894 }
3895
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003896 // There is nothing to do if there are no pending constant pool entries.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003897 if ((num_pending_32_bit_constants_ == 0) &&
3898 (num_pending_64_bit_constants_ == 0)) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003899 // Calculate the offset of the next check.
3900 next_buffer_check_ = pc_offset() + kCheckPoolInterval;
3901 return;
3902 }
3903
Steve Blocka7e24c12009-10-30 11:49:00 +00003904 // Check that the code buffer is large enough before emitting the constant
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003905 // pool (include the jump over the pool and the constant pool marker and
3906 // the gap to the relocation information).
3907 int jump_instr = require_jump ? kInstrSize : 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003908 int size_up_to_marker = jump_instr + kInstrSize;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003909 int estimated_size_after_marker =
3910 num_pending_32_bit_constants_ * kPointerSize;
3911 bool has_int_values = (num_pending_32_bit_constants_ > 0);
3912 bool has_fp_values = (num_pending_64_bit_constants_ > 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003913 bool require_64_bit_align = false;
3914 if (has_fp_values) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003915 require_64_bit_align =
3916 !IsAligned(reinterpret_cast<intptr_t>(pc_ + size_up_to_marker),
3917 kDoubleAlignment);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003918 if (require_64_bit_align) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003919 estimated_size_after_marker += kInstrSize;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003920 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003921 estimated_size_after_marker += num_pending_64_bit_constants_ * kDoubleSize;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003922 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003923 int estimated_size = size_up_to_marker + estimated_size_after_marker;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003924
3925 // We emit a constant pool when:
3926 // * requested to do so by parameter force_emit (e.g. after each function).
3927 // * the distance from the first instruction accessing the constant pool to
3928 // any of the constant pool entries will exceed its limit the next
3929 // time the pool is checked. This is overly restrictive, but we don't emit
3930 // constant pool entries in-order so it's conservatively correct.
3931 // * the instruction doesn't require a jump after itself to jump over the
3932 // constant pool, and we're getting close to running out of range.
3933 if (!force_emit) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003934 DCHECK(has_fp_values || has_int_values);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003935 bool need_emit = false;
3936 if (has_fp_values) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003937 // The 64-bit constants are always emitted before the 32-bit constants, so
3938 // we can ignore the effect of the 32-bit constants on estimated_size.
3939 int dist64 = pc_offset() + estimated_size -
3940 num_pending_32_bit_constants_ * kPointerSize -
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003941 first_const_pool_64_use_;
3942 if ((dist64 >= kMaxDistToFPPool - kCheckPoolInterval) ||
3943 (!require_jump && (dist64 >= kMaxDistToFPPool / 2))) {
3944 need_emit = true;
3945 }
3946 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003947 if (has_int_values) {
3948 int dist32 = pc_offset() + estimated_size - first_const_pool_32_use_;
3949 if ((dist32 >= kMaxDistToIntPool - kCheckPoolInterval) ||
3950 (!require_jump && (dist32 >= kMaxDistToIntPool / 2))) {
3951 need_emit = true;
3952 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003953 }
3954 if (!need_emit) return;
3955 }
3956
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003957 // Deduplicate constants.
3958 int size_after_marker = estimated_size_after_marker;
3959 for (int i = 0; i < num_pending_64_bit_constants_; i++) {
3960 ConstantPoolEntry& entry = pending_64_bit_constants_[i];
3961 DCHECK(!entry.is_merged());
3962 for (int j = 0; j < i; j++) {
3963 if (entry.value64() == pending_64_bit_constants_[j].value64()) {
3964 DCHECK(!pending_64_bit_constants_[j].is_merged());
3965 entry.set_merged_index(j);
3966 size_after_marker -= kDoubleSize;
3967 break;
3968 }
3969 }
3970 }
3971
3972 for (int i = 0; i < num_pending_32_bit_constants_; i++) {
3973 ConstantPoolEntry& entry = pending_32_bit_constants_[i];
3974 DCHECK(!entry.is_merged());
3975 if (!entry.sharing_ok()) continue;
3976 for (int j = 0; j < i; j++) {
3977 if (entry.value() == pending_32_bit_constants_[j].value()) {
3978 DCHECK(!pending_32_bit_constants_[j].is_merged());
3979 entry.set_merged_index(j);
3980 size_after_marker -= kPointerSize;
3981 break;
3982 }
3983 }
3984 }
3985
3986 int size = size_up_to_marker + size_after_marker;
3987
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003988 int needed_space = size + kGap;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003989 while (buffer_space() <= needed_space) GrowBuffer();
Steve Blocka7e24c12009-10-30 11:49:00 +00003990
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003991 {
3992 // Block recursive calls to CheckConstPool.
3993 BlockConstPoolScope block_const_pool(this);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003994 RecordComment("[ Constant Pool");
3995 RecordConstPool(size);
Steve Blocka7e24c12009-10-30 11:49:00 +00003996
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003997 Label size_check;
3998 bind(&size_check);
3999
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004000 // Emit jump over constant pool if necessary.
4001 Label after_pool;
4002 if (require_jump) {
4003 b(&after_pool);
Steve Blocka7e24c12009-10-30 11:49:00 +00004004 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004005
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004006 // Put down constant pool marker "Undefined instruction".
4007 // The data size helps disassembly know what to print.
4008 emit(kConstantPoolMarker |
4009 EncodeConstantPoolLength(size_after_marker / kPointerSize));
Steve Blocka7e24c12009-10-30 11:49:00 +00004010
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004011 if (require_64_bit_align) {
4012 emit(kConstantPoolMarker);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004013 }
4014
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004015 // Emit 64-bit constant pool entries first: their range is smaller than
4016 // 32-bit entries.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004017 for (int i = 0; i < num_pending_64_bit_constants_; i++) {
4018 ConstantPoolEntry& entry = pending_64_bit_constants_[i];
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004019
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004020 Instr instr = instr_at(entry.position());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004021 // Instruction to patch must be 'vldr rd, [pc, #offset]' with offset == 0.
4022 DCHECK((IsVldrDPcImmediateOffset(instr) &&
4023 GetVldrDRegisterImmediateOffset(instr) == 0));
4024
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004025 int delta = pc_offset() - entry.position() - kPcLoadDelta;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004026 DCHECK(is_uint10(delta));
4027
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004028 if (entry.is_merged()) {
4029 ConstantPoolEntry& merged =
4030 pending_64_bit_constants_[entry.merged_index()];
4031 DCHECK(entry.value64() == merged.value64());
4032 Instr merged_instr = instr_at(merged.position());
4033 DCHECK(IsVldrDPcImmediateOffset(merged_instr));
4034 delta = GetVldrDRegisterImmediateOffset(merged_instr);
4035 delta += merged.position() - entry.position();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004036 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004037 instr_at_put(entry.position(),
4038 SetVldrDRegisterImmediateOffset(instr, delta));
4039 if (!entry.is_merged()) {
4040 DCHECK(IsAligned(reinterpret_cast<intptr_t>(pc_), kDoubleAlignment));
4041 dq(entry.value64());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004042 }
4043 }
4044
4045 // Emit 32-bit constant pool entries.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004046 for (int i = 0; i < num_pending_32_bit_constants_; i++) {
4047 ConstantPoolEntry& entry = pending_32_bit_constants_[i];
4048 Instr instr = instr_at(entry.position());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004049
4050 // 64-bit loads shouldn't get here.
4051 DCHECK(!IsVldrDPcImmediateOffset(instr));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004052 DCHECK(!IsMovW(instr));
4053 DCHECK(IsLdrPcImmediateOffset(instr) &&
4054 GetLdrRegisterImmediateOffset(instr) == 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004055
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004056 int delta = pc_offset() - entry.position() - kPcLoadDelta;
4057 DCHECK(is_uint12(delta));
4058 // 0 is the smallest delta:
4059 // ldr rd, [pc, #0]
4060 // constant pool marker
4061 // data
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004062
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004063 if (entry.is_merged()) {
4064 DCHECK(entry.sharing_ok());
4065 ConstantPoolEntry& merged =
4066 pending_32_bit_constants_[entry.merged_index()];
4067 DCHECK(entry.value() == merged.value());
4068 Instr merged_instr = instr_at(merged.position());
4069 DCHECK(IsLdrPcImmediateOffset(merged_instr));
4070 delta = GetLdrRegisterImmediateOffset(merged_instr);
4071 delta += merged.position() - entry.position();
4072 }
4073 instr_at_put(entry.position(),
4074 SetLdrRegisterImmediateOffset(instr, delta));
4075 if (!entry.is_merged()) {
4076 emit(entry.value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004077 }
4078 }
4079
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004080 num_pending_32_bit_constants_ = 0;
4081 num_pending_64_bit_constants_ = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004082 first_const_pool_32_use_ = -1;
4083 first_const_pool_64_use_ = -1;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004084
4085 RecordComment("]");
4086
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004087 DCHECK_EQ(size, SizeOfCodeGeneratedSince(&size_check));
4088
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004089 if (after_pool.is_linked()) {
4090 bind(&after_pool);
4091 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004092 }
4093
4094 // Since a constant pool was just emitted, move the check offset forward by
4095 // the standard interval.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004096 next_buffer_check_ = pc_offset() + kCheckPoolInterval;
Steve Blocka7e24c12009-10-30 11:49:00 +00004097}
4098
4099
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004100void Assembler::PatchConstantPoolAccessInstruction(
4101 int pc_offset, int offset, ConstantPoolEntry::Access access,
4102 ConstantPoolEntry::Type type) {
4103 DCHECK(FLAG_enable_embedded_constant_pool);
4104 Address pc = buffer_ + pc_offset;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004105
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004106 // Patch vldr/ldr instruction with correct offset.
4107 Instr instr = instr_at(pc);
4108 if (access == ConstantPoolEntry::OVERFLOWED) {
4109 if (CpuFeatures::IsSupported(ARMv7)) {
4110 // Instructions to patch must be 'movw rd, [#0]' and 'movt rd, [#0].
4111 Instr next_instr = instr_at(pc + kInstrSize);
4112 DCHECK((IsMovW(instr) && Instruction::ImmedMovwMovtValue(instr) == 0));
4113 DCHECK((IsMovT(next_instr) &&
4114 Instruction::ImmedMovwMovtValue(next_instr) == 0));
4115 instr_at_put(pc, PatchMovwImmediate(instr, offset & 0xffff));
4116 instr_at_put(pc + kInstrSize,
4117 PatchMovwImmediate(next_instr, offset >> 16));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004118 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004119 // Instructions to patch must be 'mov rd, [#0]' and 'orr rd, rd, [#0].
4120 Instr instr_2 = instr_at(pc + kInstrSize);
4121 Instr instr_3 = instr_at(pc + 2 * kInstrSize);
4122 Instr instr_4 = instr_at(pc + 3 * kInstrSize);
4123 DCHECK((IsMovImmed(instr) && Instruction::Immed8Value(instr) == 0));
4124 DCHECK((IsOrrImmed(instr_2) && Instruction::Immed8Value(instr_2) == 0) &&
4125 GetRn(instr_2).is(GetRd(instr_2)));
4126 DCHECK((IsOrrImmed(instr_3) && Instruction::Immed8Value(instr_3) == 0) &&
4127 GetRn(instr_3).is(GetRd(instr_3)));
4128 DCHECK((IsOrrImmed(instr_4) && Instruction::Immed8Value(instr_4) == 0) &&
4129 GetRn(instr_4).is(GetRd(instr_4)));
4130 instr_at_put(pc, PatchShiftImm(instr, (offset & kImm8Mask)));
4131 instr_at_put(pc + kInstrSize,
4132 PatchShiftImm(instr_2, (offset & (kImm8Mask << 8))));
4133 instr_at_put(pc + 2 * kInstrSize,
4134 PatchShiftImm(instr_3, (offset & (kImm8Mask << 16))));
4135 instr_at_put(pc + 3 * kInstrSize,
4136 PatchShiftImm(instr_4, (offset & (kImm8Mask << 24))));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004137 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004138 } else if (type == ConstantPoolEntry::DOUBLE) {
4139 // Instruction to patch must be 'vldr rd, [pp, #0]'.
4140 DCHECK((IsVldrDPpImmediateOffset(instr) &&
4141 GetVldrDRegisterImmediateOffset(instr) == 0));
4142 DCHECK(is_uint10(offset));
4143 instr_at_put(pc, SetVldrDRegisterImmediateOffset(instr, offset));
4144 } else {
4145 // Instruction to patch must be 'ldr rd, [pp, #0]'.
4146 DCHECK((IsLdrPpImmediateOffset(instr) &&
4147 GetLdrRegisterImmediateOffset(instr) == 0));
4148 DCHECK(is_uint12(offset));
4149 instr_at_put(pc, SetLdrRegisterImmediateOffset(instr, offset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004150 }
4151}
4152
4153
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004154} // namespace internal
4155} // namespace v8
Leon Clarkef7060e22010-06-03 12:02:55 +01004156
4157#endif // V8_TARGET_ARCH_ARM