blob: 9633a63ea9f7c95011221e899e4bac8f38c34913 [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;
Ben Murdoch61f157c2016-09-16 13:49:30 +010060 answer |= 1u << SUDIV;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000061 }
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;
Ben Murdoch61f157c2016-09-16 13:49:30 +010096 supported_ |= 1u << SUDIV;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000097 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_unaligned_accesses) supported_ |= 1u << UNALIGNED_ACCESSES;
108
109#else // __arm__
110 // Probe for additional features at runtime.
111 base::CPU cpu;
112 if (FLAG_enable_vfp3 && cpu.has_vfp3()) {
Ben Murdoch8b112d22011-06-08 16:22:53 +0100113 // This implementation also sets the VFP flags if runtime
114 // detection of VFP returns true. VFPv3 implies ARMv7, see ARM DDI
115 // 0406B, page A1-6.
116 supported_ |= 1u << VFP3 | 1u << ARMv7;
Steve Blockd0582a62009-12-15 09:54:21 +0000117 }
Andrei Popescu31002712010-02-23 13:46:05 +0000118
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000119 if (FLAG_enable_neon && cpu.has_neon()) supported_ |= 1u << NEON;
120 if (FLAG_enable_sudiv && cpu.has_idiva()) supported_ |= 1u << SUDIV;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000121
122 if (cpu.architecture() >= 7) {
123 if (FLAG_enable_armv7) supported_ |= 1u << ARMv7;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400124 if (FLAG_enable_armv8 && cpu.architecture() >= 8) {
125 supported_ |= 1u << ARMv8;
126 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000127 if (FLAG_enable_unaligned_accesses) supported_ |= 1u << UNALIGNED_ACCESSES;
128 // Use movw/movt for QUALCOMM ARMv7 cores.
129 if (FLAG_enable_movw_movt && cpu.implementer() == base::CPU::QUALCOMM) {
130 supported_ |= 1u << MOVW_MOVT_IMMEDIATE_LOADS;
131 }
Andrei Popescu31002712010-02-23 13:46:05 +0000132 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000133
134 // ARM Cortex-A9 and Cortex-A5 have 32 byte cachelines.
135 if (cpu.implementer() == base::CPU::ARM &&
136 (cpu.part() == base::CPU::ARM_CORTEX_A5 ||
137 cpu.part() == base::CPU::ARM_CORTEX_A9)) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100138 dcache_line_size_ = 32;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000139 }
140
141 if (FLAG_enable_32dregs && cpu.has_vfp3_d32()) supported_ |= 1u << VFP32DREGS;
Steve Block6ded16b2010-05-10 14:33:55 +0100142#endif
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000143
144 DCHECK(!IsSupported(VFP3) || IsSupported(ARMv7));
145}
146
147
148void CpuFeatures::PrintTarget() {
149 const char* arm_arch = NULL;
150 const char* arm_target_type = "";
151 const char* arm_no_probe = "";
152 const char* arm_fpu = "";
153 const char* arm_thumb = "";
154 const char* arm_float_abi = NULL;
155
156#if !defined __arm__
157 arm_target_type = " simulator";
158#endif
159
160#if defined ARM_TEST_NO_FEATURE_PROBE
161 arm_no_probe = " noprobe";
162#endif
163
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000164#if defined CAN_USE_ARMV8_INSTRUCTIONS
165 arm_arch = "arm v8";
166#elif defined CAN_USE_ARMV7_INSTRUCTIONS
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000167 arm_arch = "arm v7";
168#else
169 arm_arch = "arm v6";
170#endif
171
172#if defined CAN_USE_NEON
173 arm_fpu = " neon";
174#elif defined CAN_USE_VFP3_INSTRUCTIONS
175# if defined CAN_USE_VFP32DREGS
176 arm_fpu = " vfp3";
177# else
178 arm_fpu = " vfp3-d16";
179# endif
180#else
181 arm_fpu = " vfp2";
182#endif
183
184#ifdef __arm__
185 arm_float_abi = base::OS::ArmUsingHardFloat() ? "hard" : "softfp";
186#elif USE_EABI_HARDFLOAT
187 arm_float_abi = "hard";
188#else
189 arm_float_abi = "softfp";
190#endif
191
192#if defined __arm__ && (defined __thumb__) || (defined __thumb2__)
193 arm_thumb = " thumb";
194#endif
195
196 printf("target%s%s %s%s%s %s\n",
197 arm_target_type, arm_no_probe, arm_arch, arm_fpu, arm_thumb,
198 arm_float_abi);
199}
200
201
202void CpuFeatures::PrintFeatures() {
203 printf(
Ben Murdoch61f157c2016-09-16 13:49:30 +0100204 "ARMv8=%d ARMv7=%d VFP3=%d VFP32DREGS=%d NEON=%d SUDIV=%d "
Ben Murdochc5610432016-08-08 18:44:38 +0100205 "UNALIGNED_ACCESSES=%d MOVW_MOVT_IMMEDIATE_LOADS=%d",
206 CpuFeatures::IsSupported(ARMv8), CpuFeatures::IsSupported(ARMv7),
207 CpuFeatures::IsSupported(VFP3), CpuFeatures::IsSupported(VFP32DREGS),
208 CpuFeatures::IsSupported(NEON), CpuFeatures::IsSupported(SUDIV),
Ben Murdochc5610432016-08-08 18:44:38 +0100209 CpuFeatures::IsSupported(UNALIGNED_ACCESSES),
210 CpuFeatures::IsSupported(MOVW_MOVT_IMMEDIATE_LOADS));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000211#ifdef __arm__
212 bool eabi_hardfloat = base::OS::ArmUsingHardFloat();
213#elif USE_EABI_HARDFLOAT
214 bool eabi_hardfloat = true;
215#else
216 bool eabi_hardfloat = false;
217#endif
218 printf(" USE_EABI_HARDFLOAT=%d\n", eabi_hardfloat);
219}
220
221
222// -----------------------------------------------------------------------------
Steve Blocka7e24c12009-10-30 11:49:00 +0000223// Implementation of RelocInfo
224
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000225// static
Steve Blocka7e24c12009-10-30 11:49:00 +0000226const int RelocInfo::kApplyMask = 0;
227
228
Leon Clarkef7060e22010-06-03 12:02:55 +0100229bool RelocInfo::IsCodedSpecially() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000230 // The deserializer needs to know whether a pointer is specially coded.  Being
231 // specially coded on ARM means that it is a movw/movt instruction, or is an
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000232 // embedded constant pool entry.  These only occur if
233 // FLAG_enable_embedded_constant_pool is true.
234 return FLAG_enable_embedded_constant_pool;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000235}
236
237
238bool RelocInfo::IsInConstantPool() {
239 return Assembler::is_constant_pool_load(pc_);
Leon Clarkef7060e22010-06-03 12:02:55 +0100240}
241
Ben Murdochc5610432016-08-08 18:44:38 +0100242Address RelocInfo::wasm_memory_reference() {
243 DCHECK(IsWasmMemoryReference(rmode_));
244 return Assembler::target_address_at(pc_, host_);
245}
246
247uint32_t RelocInfo::wasm_memory_size_reference() {
248 DCHECK(IsWasmMemorySizeReference(rmode_));
249 return reinterpret_cast<uint32_t>(Assembler::target_address_at(pc_, host_));
250}
251
Ben Murdoch61f157c2016-09-16 13:49:30 +0100252Address RelocInfo::wasm_global_reference() {
253 DCHECK(IsWasmGlobalReference(rmode_));
254 return Assembler::target_address_at(pc_, host_);
255}
256
257void RelocInfo::unchecked_update_wasm_memory_reference(
258 Address address, ICacheFlushMode flush_mode) {
259 Assembler::set_target_address_at(isolate_, pc_, host_, address, flush_mode);
260}
261
262void RelocInfo::unchecked_update_wasm_memory_size(uint32_t size,
263 ICacheFlushMode flush_mode) {
264 Assembler::set_target_address_at(isolate_, pc_, host_,
265 reinterpret_cast<Address>(size), flush_mode);
Ben Murdochc5610432016-08-08 18:44:38 +0100266}
Leon Clarkef7060e22010-06-03 12:02:55 +0100267
Steve Blocka7e24c12009-10-30 11:49:00 +0000268// -----------------------------------------------------------------------------
269// Implementation of Operand and MemOperand
270// See assembler-arm-inl.h for inlined constructors
271
272Operand::Operand(Handle<Object> handle) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000273 AllowDeferredHandleDereference using_raw_address;
Steve Blocka7e24c12009-10-30 11:49:00 +0000274 rm_ = no_reg;
275 // Verify all Objects referred by code are NOT in new space.
276 Object* obj = *handle;
Steve Blocka7e24c12009-10-30 11:49:00 +0000277 if (obj->IsHeapObject()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000278 DCHECK(!HeapObject::cast(obj)->GetHeap()->InNewSpace(obj));
Steve Blocka7e24c12009-10-30 11:49:00 +0000279 imm32_ = reinterpret_cast<intptr_t>(handle.location());
280 rmode_ = RelocInfo::EMBEDDED_OBJECT;
281 } else {
282 // no relocation needed
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000283 imm32_ = reinterpret_cast<intptr_t>(obj);
284 rmode_ = RelocInfo::NONE32;
Steve Blocka7e24c12009-10-30 11:49:00 +0000285 }
286}
287
288
289Operand::Operand(Register rm, ShiftOp shift_op, int shift_imm) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000290 DCHECK(is_uint5(shift_imm));
291
Steve Blocka7e24c12009-10-30 11:49:00 +0000292 rm_ = rm;
293 rs_ = no_reg;
294 shift_op_ = shift_op;
295 shift_imm_ = shift_imm & 31;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000296
297 if ((shift_op == ROR) && (shift_imm == 0)) {
298 // ROR #0 is functionally equivalent to LSL #0 and this allow us to encode
299 // RRX as ROR #0 (See below).
300 shift_op = LSL;
301 } else if (shift_op == RRX) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000302 // encoded as ROR with shift_imm == 0
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000303 DCHECK(shift_imm == 0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000304 shift_op_ = ROR;
305 shift_imm_ = 0;
306 }
307}
308
309
310Operand::Operand(Register rm, ShiftOp shift_op, Register rs) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000311 DCHECK(shift_op != RRX);
Steve Blocka7e24c12009-10-30 11:49:00 +0000312 rm_ = rm;
313 rs_ = no_reg;
314 shift_op_ = shift_op;
315 rs_ = rs;
316}
317
318
319MemOperand::MemOperand(Register rn, int32_t offset, AddrMode am) {
320 rn_ = rn;
321 rm_ = no_reg;
322 offset_ = offset;
323 am_ = am;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000324
325 // Accesses below the stack pointer are not safe, and are prohibited by the
326 // ABI. We can check obvious violations here.
327 if (rn.is(sp)) {
328 if (am == Offset) DCHECK_LE(0, offset);
329 if (am == NegOffset) DCHECK_GE(0, offset);
330 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000331}
332
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000333
Steve Blocka7e24c12009-10-30 11:49:00 +0000334MemOperand::MemOperand(Register rn, Register rm, AddrMode am) {
335 rn_ = rn;
336 rm_ = rm;
337 shift_op_ = LSL;
338 shift_imm_ = 0;
339 am_ = am;
340}
341
342
343MemOperand::MemOperand(Register rn, Register rm,
344 ShiftOp shift_op, int shift_imm, AddrMode am) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000345 DCHECK(is_uint5(shift_imm));
Steve Blocka7e24c12009-10-30 11:49:00 +0000346 rn_ = rn;
347 rm_ = rm;
348 shift_op_ = shift_op;
349 shift_imm_ = shift_imm & 31;
350 am_ = am;
351}
352
353
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000354NeonMemOperand::NeonMemOperand(Register rn, AddrMode am, int align) {
355 DCHECK((am == Offset) || (am == PostIndex));
356 rn_ = rn;
357 rm_ = (am == Offset) ? pc : sp;
358 SetAlignment(align);
359}
360
361
362NeonMemOperand::NeonMemOperand(Register rn, Register rm, int align) {
363 rn_ = rn;
364 rm_ = rm;
365 SetAlignment(align);
366}
367
368
369void NeonMemOperand::SetAlignment(int align) {
370 switch (align) {
371 case 0:
372 align_ = 0;
373 break;
374 case 64:
375 align_ = 1;
376 break;
377 case 128:
378 align_ = 2;
379 break;
380 case 256:
381 align_ = 3;
382 break;
383 default:
384 UNREACHABLE();
385 align_ = 0;
386 break;
387 }
388}
389
390
391NeonListOperand::NeonListOperand(DoubleRegister base, int registers_count) {
392 base_ = base;
393 switch (registers_count) {
394 case 1:
395 type_ = nlt_1;
396 break;
397 case 2:
398 type_ = nlt_2;
399 break;
400 case 3:
401 type_ = nlt_3;
402 break;
403 case 4:
404 type_ = nlt_4;
405 break;
406 default:
407 UNREACHABLE();
408 type_ = nlt_1;
409 break;
410 }
411}
412
413
Steve Blocka7e24c12009-10-30 11:49:00 +0000414// -----------------------------------------------------------------------------
Steve Block1e0659c2011-05-24 12:43:12 +0100415// Specific instructions, constants, and masks.
Steve Blocka7e24c12009-10-30 11:49:00 +0000416
Steve Blocka7e24c12009-10-30 11:49:00 +0000417// str(r, MemOperand(sp, 4, NegPreIndex), al) instruction (aka push(r))
418// register r is not encoded.
Steve Block1e0659c2011-05-24 12:43:12 +0100419const Instr kPushRegPattern =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000420 al | B26 | 4 | NegPreIndex | Register::kCode_sp * B16;
Steve Blocka7e24c12009-10-30 11:49:00 +0000421// ldr(r, MemOperand(sp, 4, PostIndex), al) instruction (aka pop(r))
422// register r is not encoded.
Steve Block1e0659c2011-05-24 12:43:12 +0100423const Instr kPopRegPattern =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000424 al | B26 | L | 4 | PostIndex | Register::kCode_sp * B16;
Steve Block6ded16b2010-05-10 14:33:55 +0100425// ldr rd, [pc, #offset]
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000426const Instr kLdrPCImmedMask = 15 * B24 | 7 * B20 | 15 * B16;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000427const Instr kLdrPCImmedPattern = 5 * B24 | L | Register::kCode_pc * B16;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000428// ldr rd, [pp, #offset]
429const Instr kLdrPpImmedMask = 15 * B24 | 7 * B20 | 15 * B16;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000430const Instr kLdrPpImmedPattern = 5 * B24 | L | Register::kCode_r8 * B16;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000431// ldr rd, [pp, rn]
432const Instr kLdrPpRegMask = 15 * B24 | 7 * B20 | 15 * B16;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000433const Instr kLdrPpRegPattern = 7 * B24 | L | Register::kCode_r8 * B16;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000434// vldr dd, [pc, #offset]
435const Instr kVldrDPCMask = 15 * B24 | 3 * B20 | 15 * B16 | 15 * B8;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000436const Instr kVldrDPCPattern = 13 * B24 | L | Register::kCode_pc * B16 | 11 * B8;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000437// vldr dd, [pp, #offset]
438const Instr kVldrDPpMask = 15 * B24 | 3 * B20 | 15 * B16 | 15 * B8;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000439const Instr kVldrDPpPattern = 13 * B24 | L | Register::kCode_r8 * B16 | 11 * B8;
Steve Block6ded16b2010-05-10 14:33:55 +0100440// blxcc rm
441const Instr kBlxRegMask =
442 15 * B24 | 15 * B20 | 15 * B16 | 15 * B12 | 15 * B8 | 15 * B4;
443const Instr kBlxRegPattern =
Steve Block1e0659c2011-05-24 12:43:12 +0100444 B24 | B21 | 15 * B16 | 15 * B12 | 15 * B8 | BLX;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100445const Instr kBlxIp = al | kBlxRegPattern | ip.code();
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100446const Instr kMovMvnMask = 0x6d * B21 | 0xf * B16;
447const Instr kMovMvnPattern = 0xd * B21;
448const Instr kMovMvnFlip = B22;
449const Instr kMovLeaveCCMask = 0xdff * B16;
450const Instr kMovLeaveCCPattern = 0x1a0 * B16;
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100451const Instr kMovwPattern = 0x30 * B20;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000452const Instr kMovtPattern = 0x34 * B20;
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100453const Instr kMovwLeaveCCFlip = 0x5 * B21;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000454const Instr kMovImmedMask = 0x7f * B21;
455const Instr kMovImmedPattern = 0x1d * B21;
456const Instr kOrrImmedMask = 0x7f * B21;
457const Instr kOrrImmedPattern = 0x1c * B21;
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100458const Instr kCmpCmnMask = 0xdd * B20 | 0xf * B12;
459const Instr kCmpCmnPattern = 0x15 * B20;
460const Instr kCmpCmnFlip = B21;
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100461const Instr kAddSubFlip = 0x6 * B21;
462const Instr kAndBicFlip = 0xe * B21;
463
Leon Clarkef7060e22010-06-03 12:02:55 +0100464// A mask for the Rd register for push, pop, ldr, str instructions.
Steve Block1e0659c2011-05-24 12:43:12 +0100465const Instr kLdrRegFpOffsetPattern =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000466 al | B26 | L | Offset | Register::kCode_fp * B16;
Steve Block1e0659c2011-05-24 12:43:12 +0100467const Instr kStrRegFpOffsetPattern =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000468 al | B26 | Offset | Register::kCode_fp * B16;
Steve Block1e0659c2011-05-24 12:43:12 +0100469const Instr kLdrRegFpNegOffsetPattern =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000470 al | B26 | L | NegOffset | Register::kCode_fp * B16;
Steve Block1e0659c2011-05-24 12:43:12 +0100471const Instr kStrRegFpNegOffsetPattern =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000472 al | B26 | NegOffset | Register::kCode_fp * B16;
Steve Block1e0659c2011-05-24 12:43:12 +0100473const Instr kLdrStrInstrTypeMask = 0xffff0000;
Steve Block1e0659c2011-05-24 12:43:12 +0100474
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000475Assembler::Assembler(Isolate* isolate, void* buffer, int buffer_size)
476 : AssemblerBase(isolate, buffer, buffer_size),
477 recorded_ast_id_(TypeFeedbackId::None()),
Ben Murdoch61f157c2016-09-16 13:49:30 +0100478 pending_32_bit_constants_(),
479 pending_64_bit_constants_(),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000480 constant_pool_builder_(kLdrMaxReachBits, kVldrMaxReachBits),
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000481 positions_recorder_(this) {
Ben Murdoch61f157c2016-09-16 13:49:30 +0100482 pending_32_bit_constants_.reserve(kMinNumPendingConstants);
483 pending_64_bit_constants_.reserve(kMinNumPendingConstants);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000484 reloc_info_writer.Reposition(buffer_ + buffer_size_, pc_);
Steve Blocka7e24c12009-10-30 11:49:00 +0000485 next_buffer_check_ = 0;
Steve Block6ded16b2010-05-10 14:33:55 +0100486 const_pool_blocked_nesting_ = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +0000487 no_const_pool_before_ = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000488 first_const_pool_32_use_ = -1;
489 first_const_pool_64_use_ = -1;
Steve Blocka7e24c12009-10-30 11:49:00 +0000490 last_bound_pos_ = 0;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000491 ClearRecordedAstId();
Steve Blocka7e24c12009-10-30 11:49:00 +0000492}
493
494
495Assembler::~Assembler() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000496 DCHECK(const_pool_blocked_nesting_ == 0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000497}
498
499
500void Assembler::GetCode(CodeDesc* desc) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000501 reloc_info_writer.Finish();
502
503 // Emit constant pool if necessary.
504 int constant_pool_offset = 0;
505 if (FLAG_enable_embedded_constant_pool) {
506 constant_pool_offset = EmitEmbeddedConstantPool();
507 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000508 CheckConstPool(true, false);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100509 DCHECK(pending_32_bit_constants_.empty());
510 DCHECK(pending_64_bit_constants_.empty());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000511 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100512 // Set up code descriptor.
Steve Blocka7e24c12009-10-30 11:49:00 +0000513 desc->buffer = buffer_;
514 desc->buffer_size = buffer_size_;
515 desc->instr_size = pc_offset();
516 desc->reloc_size = (buffer_ + buffer_size_) - reloc_info_writer.pos();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000517 desc->constant_pool_size =
518 (constant_pool_offset ? desc->instr_size - constant_pool_offset : 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000519 desc->origin = this;
Ben Murdoch61f157c2016-09-16 13:49:30 +0100520 desc->unwinding_info_size = 0;
521 desc->unwinding_info = nullptr;
Steve Blocka7e24c12009-10-30 11:49:00 +0000522}
523
524
525void Assembler::Align(int m) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000526 DCHECK(m >= 4 && base::bits::IsPowerOfTwo32(m));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000527 DCHECK((pc_offset() & (kInstrSize - 1)) == 0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000528 while ((pc_offset() & (m - 1)) != 0) {
529 nop();
530 }
531}
532
533
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100534void Assembler::CodeTargetAlign() {
535 // Preferred alignment of jump targets on some ARM chips.
536 Align(8);
537}
538
539
Steve Block1e0659c2011-05-24 12:43:12 +0100540Condition Assembler::GetCondition(Instr instr) {
541 return Instruction::ConditionField(instr);
542}
543
544
Steve Block6ded16b2010-05-10 14:33:55 +0100545bool Assembler::IsBranch(Instr instr) {
546 return (instr & (B27 | B25)) == (B27 | B25);
547}
548
549
550int Assembler::GetBranchOffset(Instr instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000551 DCHECK(IsBranch(instr));
Steve Block6ded16b2010-05-10 14:33:55 +0100552 // Take the jump offset in the lower 24 bits, sign extend it and multiply it
553 // with 4 to get the offset in bytes.
Steve Block1e0659c2011-05-24 12:43:12 +0100554 return ((instr & kImm24Mask) << 8) >> 6;
Steve Block6ded16b2010-05-10 14:33:55 +0100555}
556
557
558bool Assembler::IsLdrRegisterImmediate(Instr instr) {
559 return (instr & (B27 | B26 | B25 | B22 | B20)) == (B26 | B20);
560}
561
562
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000563bool Assembler::IsVldrDRegisterImmediate(Instr instr) {
564 return (instr & (15 * B24 | 3 * B20 | 15 * B8)) == (13 * B24 | B20 | 11 * B8);
565}
566
567
Steve Block6ded16b2010-05-10 14:33:55 +0100568int Assembler::GetLdrRegisterImmediateOffset(Instr instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000569 DCHECK(IsLdrRegisterImmediate(instr));
Steve Block6ded16b2010-05-10 14:33:55 +0100570 bool positive = (instr & B23) == B23;
Steve Block1e0659c2011-05-24 12:43:12 +0100571 int offset = instr & kOff12Mask; // Zero extended offset.
Steve Block6ded16b2010-05-10 14:33:55 +0100572 return positive ? offset : -offset;
573}
574
575
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000576int Assembler::GetVldrDRegisterImmediateOffset(Instr instr) {
577 DCHECK(IsVldrDRegisterImmediate(instr));
578 bool positive = (instr & B23) == B23;
579 int offset = instr & kOff8Mask; // Zero extended offset.
580 offset <<= 2;
581 return positive ? offset : -offset;
582}
583
584
Steve Block6ded16b2010-05-10 14:33:55 +0100585Instr Assembler::SetLdrRegisterImmediateOffset(Instr instr, int offset) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000586 DCHECK(IsLdrRegisterImmediate(instr));
Steve Block6ded16b2010-05-10 14:33:55 +0100587 bool positive = offset >= 0;
588 if (!positive) offset = -offset;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000589 DCHECK(is_uint12(offset));
Steve Block6ded16b2010-05-10 14:33:55 +0100590 // Set bit indicating whether the offset should be added.
591 instr = (instr & ~B23) | (positive ? B23 : 0);
592 // Set the actual offset.
Steve Block1e0659c2011-05-24 12:43:12 +0100593 return (instr & ~kOff12Mask) | offset;
Steve Block6ded16b2010-05-10 14:33:55 +0100594}
595
596
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000597Instr Assembler::SetVldrDRegisterImmediateOffset(Instr instr, int offset) {
598 DCHECK(IsVldrDRegisterImmediate(instr));
599 DCHECK((offset & ~3) == offset); // Must be 64-bit aligned.
600 bool positive = offset >= 0;
601 if (!positive) offset = -offset;
602 DCHECK(is_uint10(offset));
603 // Set bit indicating whether the offset should be added.
604 instr = (instr & ~B23) | (positive ? B23 : 0);
605 // Set the actual offset. Its bottom 2 bits are zero.
606 return (instr & ~kOff8Mask) | (offset >> 2);
607}
608
609
Kristian Monsen50ef84f2010-07-29 15:18:00 +0100610bool Assembler::IsStrRegisterImmediate(Instr instr) {
611 return (instr & (B27 | B26 | B25 | B22 | B20)) == B26;
612}
613
614
615Instr Assembler::SetStrRegisterImmediateOffset(Instr instr, int offset) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000616 DCHECK(IsStrRegisterImmediate(instr));
Kristian Monsen50ef84f2010-07-29 15:18:00 +0100617 bool positive = offset >= 0;
618 if (!positive) offset = -offset;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000619 DCHECK(is_uint12(offset));
Kristian Monsen50ef84f2010-07-29 15:18:00 +0100620 // Set bit indicating whether the offset should be added.
621 instr = (instr & ~B23) | (positive ? B23 : 0);
622 // Set the actual offset.
Steve Block1e0659c2011-05-24 12:43:12 +0100623 return (instr & ~kOff12Mask) | offset;
Kristian Monsen50ef84f2010-07-29 15:18:00 +0100624}
625
626
627bool Assembler::IsAddRegisterImmediate(Instr instr) {
628 return (instr & (B27 | B26 | B25 | B24 | B23 | B22 | B21)) == (B25 | B23);
629}
630
631
632Instr Assembler::SetAddRegisterImmediateOffset(Instr instr, int offset) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000633 DCHECK(IsAddRegisterImmediate(instr));
634 DCHECK(offset >= 0);
635 DCHECK(is_uint12(offset));
Kristian Monsen50ef84f2010-07-29 15:18:00 +0100636 // Set the offset.
Steve Block1e0659c2011-05-24 12:43:12 +0100637 return (instr & ~kOff12Mask) | offset;
Kristian Monsen50ef84f2010-07-29 15:18:00 +0100638}
639
640
Leon Clarkef7060e22010-06-03 12:02:55 +0100641Register Assembler::GetRd(Instr instr) {
642 Register reg;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000643 reg.reg_code = Instruction::RdValue(instr);
Steve Block1e0659c2011-05-24 12:43:12 +0100644 return reg;
645}
646
647
648Register Assembler::GetRn(Instr instr) {
649 Register reg;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000650 reg.reg_code = Instruction::RnValue(instr);
Steve Block1e0659c2011-05-24 12:43:12 +0100651 return reg;
652}
653
654
655Register Assembler::GetRm(Instr instr) {
656 Register reg;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000657 reg.reg_code = Instruction::RmValue(instr);
Leon Clarkef7060e22010-06-03 12:02:55 +0100658 return reg;
659}
660
661
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000662Instr Assembler::GetConsantPoolLoadPattern() {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000663 if (FLAG_enable_embedded_constant_pool) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000664 return kLdrPpImmedPattern;
665 } else {
666 return kLdrPCImmedPattern;
667 }
668}
669
670
671Instr Assembler::GetConsantPoolLoadMask() {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000672 if (FLAG_enable_embedded_constant_pool) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000673 return kLdrPpImmedMask;
674 } else {
675 return kLdrPCImmedMask;
676 }
677}
678
679
Leon Clarkef7060e22010-06-03 12:02:55 +0100680bool Assembler::IsPush(Instr instr) {
681 return ((instr & ~kRdMask) == kPushRegPattern);
682}
683
684
685bool Assembler::IsPop(Instr instr) {
686 return ((instr & ~kRdMask) == kPopRegPattern);
687}
688
689
690bool Assembler::IsStrRegFpOffset(Instr instr) {
691 return ((instr & kLdrStrInstrTypeMask) == kStrRegFpOffsetPattern);
692}
693
694
695bool Assembler::IsLdrRegFpOffset(Instr instr) {
696 return ((instr & kLdrStrInstrTypeMask) == kLdrRegFpOffsetPattern);
697}
698
699
700bool Assembler::IsStrRegFpNegOffset(Instr instr) {
701 return ((instr & kLdrStrInstrTypeMask) == kStrRegFpNegOffsetPattern);
702}
703
704
705bool Assembler::IsLdrRegFpNegOffset(Instr instr) {
706 return ((instr & kLdrStrInstrTypeMask) == kLdrRegFpNegOffsetPattern);
707}
708
709
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800710bool Assembler::IsLdrPcImmediateOffset(Instr instr) {
711 // Check the instruction is indeed a
712 // ldr<cond> <Rd>, [pc +/- offset_12].
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000713 return (instr & kLdrPCImmedMask) == kLdrPCImmedPattern;
714}
715
716
717bool Assembler::IsLdrPpImmediateOffset(Instr instr) {
718 // Check the instruction is indeed a
719 // ldr<cond> <Rd>, [pp +/- offset_12].
720 return (instr & kLdrPpImmedMask) == kLdrPpImmedPattern;
721}
722
723
724bool Assembler::IsLdrPpRegOffset(Instr instr) {
725 // Check the instruction is indeed a
726 // ldr<cond> <Rd>, [pp, +/- <Rm>].
727 return (instr & kLdrPpRegMask) == kLdrPpRegPattern;
728}
729
730
731Instr Assembler::GetLdrPpRegOffsetPattern() { return kLdrPpRegPattern; }
732
733
734bool Assembler::IsVldrDPcImmediateOffset(Instr instr) {
735 // Check the instruction is indeed a
736 // vldr<cond> <Dd>, [pc +/- offset_10].
737 return (instr & kVldrDPCMask) == kVldrDPCPattern;
738}
739
740
741bool Assembler::IsVldrDPpImmediateOffset(Instr instr) {
742 // Check the instruction is indeed a
743 // vldr<cond> <Dd>, [pp +/- offset_10].
744 return (instr & kVldrDPpMask) == kVldrDPpPattern;
745}
746
747
748bool Assembler::IsBlxReg(Instr instr) {
749 // Check the instruction is indeed a
750 // blxcc <Rm>
751 return (instr & kBlxRegMask) == kBlxRegPattern;
752}
753
754
755bool Assembler::IsBlxIp(Instr instr) {
756 // Check the instruction is indeed a
757 // blx ip
758 return instr == kBlxIp;
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800759}
760
761
Steve Block1e0659c2011-05-24 12:43:12 +0100762bool Assembler::IsTstImmediate(Instr instr) {
763 return (instr & (B27 | B26 | I | kOpCodeMask | S | kRdMask)) ==
764 (I | TST | S);
765}
766
767
768bool Assembler::IsCmpRegister(Instr instr) {
769 return (instr & (B27 | B26 | I | kOpCodeMask | S | kRdMask | B4)) ==
770 (CMP | S);
771}
772
773
774bool Assembler::IsCmpImmediate(Instr instr) {
775 return (instr & (B27 | B26 | I | kOpCodeMask | S | kRdMask)) ==
776 (I | CMP | S);
777}
778
779
780Register Assembler::GetCmpImmediateRegister(Instr instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000781 DCHECK(IsCmpImmediate(instr));
Steve Block1e0659c2011-05-24 12:43:12 +0100782 return GetRn(instr);
783}
784
785
786int Assembler::GetCmpImmediateRawImmediate(Instr instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000787 DCHECK(IsCmpImmediate(instr));
Steve Block1e0659c2011-05-24 12:43:12 +0100788 return instr & kOff12Mask;
789}
790
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000791
Steve Blocka7e24c12009-10-30 11:49:00 +0000792// Labels refer to positions in the (to be) generated code.
793// There are bound, linked, and unused labels.
794//
795// Bound labels refer to known positions in the already
796// generated code. pos() is the position the label refers to.
797//
798// Linked labels refer to unknown positions in the code
799// to be generated; pos() is the position of the last
800// instruction using the label.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000801//
802// The linked labels form a link chain by making the branch offset
803// in the instruction steam to point to the previous branch
804// instruction using the same label.
805//
806// The link chain is terminated by a branch offset pointing to the
807// same position.
Steve Blocka7e24c12009-10-30 11:49:00 +0000808
809
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000810int Assembler::target_at(int pos) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000811 Instr instr = instr_at(pos);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000812 if (is_uint24(instr)) {
813 // Emitted link to a label, not part of a branch.
814 return instr;
Steve Blocka7e24c12009-10-30 11:49:00 +0000815 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000816 DCHECK_EQ(5 * B25, instr & 7 * B25); // b, bl, or blx imm24
Steve Block1e0659c2011-05-24 12:43:12 +0100817 int imm26 = ((instr & kImm24Mask) << 8) >> 6;
818 if ((Instruction::ConditionField(instr) == kSpecialCondition) &&
819 ((instr & B24) != 0)) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000820 // blx uses bit 24 to encode bit 2 of imm26
821 imm26 += 2;
Steve Block6ded16b2010-05-10 14:33:55 +0100822 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000823 return pos + kPcLoadDelta + imm26;
824}
825
826
827void Assembler::target_at_put(int pos, int target_pos) {
828 Instr instr = instr_at(pos);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000829 if (is_uint24(instr)) {
830 DCHECK(target_pos == pos || target_pos >= 0);
831 // Emitted link to a label, not part of a branch.
832 // Load the position of the label relative to the generated code object
833 // pointer in a register.
834
Ben Murdoch61f157c2016-09-16 13:49:30 +0100835 // The existing code must be a single 24-bit label chain link, followed by
836 // nops encoding the destination register. See mov_label_offset.
837
838 // Extract the destination register from the first nop instructions.
839 Register dst =
840 Register::from_code(Instruction::RmValue(instr_at(pos + kInstrSize)));
841 // In addition to the 24-bit label chain link, we expect to find one nop for
842 // ARMv7 and above, or two nops for ARMv6. See mov_label_offset.
843 DCHECK(IsNop(instr_at(pos + kInstrSize), dst.code()));
844 if (!CpuFeatures::IsSupported(ARMv7)) {
845 DCHECK(IsNop(instr_at(pos + 2 * kInstrSize), dst.code()));
846 }
847
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000848 // Here are the instructions we need to emit:
849 // For ARMv7: target24 => target16_1:target16_0
850 // movw dst, #target16_0
851 // movt dst, #target16_1
852 // For ARMv6: target24 => target8_2:target8_1:target8_0
853 // mov dst, #target8_0
854 // orr dst, dst, #target8_1 << 8
855 // orr dst, dst, #target8_2 << 16
856
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000857 uint32_t target24 = target_pos + (Code::kHeaderSize - kHeapObjectTag);
858 DCHECK(is_uint24(target24));
859 if (is_uint8(target24)) {
860 // If the target fits in a byte then only patch with a mov
861 // instruction.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000862 CodePatcher patcher(isolate(), reinterpret_cast<byte*>(buffer_ + pos), 1,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000863 CodePatcher::DONT_FLUSH);
864 patcher.masm()->mov(dst, Operand(target24));
865 } else {
866 uint16_t target16_0 = target24 & kImm16Mask;
867 uint16_t target16_1 = target24 >> 16;
868 if (CpuFeatures::IsSupported(ARMv7)) {
869 // Patch with movw/movt.
870 if (target16_1 == 0) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000871 CodePatcher patcher(isolate(), reinterpret_cast<byte*>(buffer_ + pos),
872 1, CodePatcher::DONT_FLUSH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000873 patcher.masm()->movw(dst, target16_0);
874 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000875 CodePatcher patcher(isolate(), reinterpret_cast<byte*>(buffer_ + pos),
876 2, CodePatcher::DONT_FLUSH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000877 patcher.masm()->movw(dst, target16_0);
878 patcher.masm()->movt(dst, target16_1);
879 }
880 } else {
881 // Patch with a sequence of mov/orr/orr instructions.
882 uint8_t target8_0 = target16_0 & kImm8Mask;
883 uint8_t target8_1 = target16_0 >> 8;
884 uint8_t target8_2 = target16_1 & kImm8Mask;
885 if (target8_2 == 0) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000886 CodePatcher patcher(isolate(), reinterpret_cast<byte*>(buffer_ + pos),
887 2, CodePatcher::DONT_FLUSH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000888 patcher.masm()->mov(dst, Operand(target8_0));
889 patcher.masm()->orr(dst, dst, Operand(target8_1 << 8));
890 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000891 CodePatcher patcher(isolate(), reinterpret_cast<byte*>(buffer_ + pos),
892 3, CodePatcher::DONT_FLUSH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000893 patcher.masm()->mov(dst, Operand(target8_0));
894 patcher.masm()->orr(dst, dst, Operand(target8_1 << 8));
895 patcher.masm()->orr(dst, dst, Operand(target8_2 << 16));
896 }
897 }
898 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000899 return;
900 }
901 int imm26 = target_pos - (pos + kPcLoadDelta);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000902 DCHECK_EQ(5 * B25, instr & 7 * B25); // b, bl, or blx imm24
Steve Block1e0659c2011-05-24 12:43:12 +0100903 if (Instruction::ConditionField(instr) == kSpecialCondition) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000904 // blx uses bit 24 to encode bit 2 of imm26
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000905 DCHECK_EQ(0, imm26 & 1);
906 instr = (instr & ~(B24 | kImm24Mask)) | ((imm26 & 2) >> 1) * B24;
Steve Blocka7e24c12009-10-30 11:49:00 +0000907 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000908 DCHECK_EQ(0, imm26 & 3);
Steve Block1e0659c2011-05-24 12:43:12 +0100909 instr &= ~kImm24Mask;
Steve Blocka7e24c12009-10-30 11:49:00 +0000910 }
911 int imm24 = imm26 >> 2;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000912 DCHECK(is_int24(imm24));
Steve Block1e0659c2011-05-24 12:43:12 +0100913 instr_at_put(pos, instr | (imm24 & kImm24Mask));
Steve Blocka7e24c12009-10-30 11:49:00 +0000914}
915
916
917void Assembler::print(Label* L) {
918 if (L->is_unused()) {
919 PrintF("unused label\n");
920 } else if (L->is_bound()) {
921 PrintF("bound label to %d\n", L->pos());
922 } else if (L->is_linked()) {
923 Label l = *L;
924 PrintF("unbound label");
925 while (l.is_linked()) {
926 PrintF("@ %d ", l.pos());
927 Instr instr = instr_at(l.pos());
Steve Block1e0659c2011-05-24 12:43:12 +0100928 if ((instr & ~kImm24Mask) == 0) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000929 PrintF("value\n");
930 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000931 DCHECK((instr & 7*B25) == 5*B25); // b, bl, or blx
Steve Block1e0659c2011-05-24 12:43:12 +0100932 Condition cond = Instruction::ConditionField(instr);
Steve Blocka7e24c12009-10-30 11:49:00 +0000933 const char* b;
934 const char* c;
Steve Block1e0659c2011-05-24 12:43:12 +0100935 if (cond == kSpecialCondition) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000936 b = "blx";
937 c = "";
938 } else {
939 if ((instr & B24) != 0)
940 b = "bl";
941 else
942 b = "b";
943
944 switch (cond) {
945 case eq: c = "eq"; break;
946 case ne: c = "ne"; break;
947 case hs: c = "hs"; break;
948 case lo: c = "lo"; break;
949 case mi: c = "mi"; break;
950 case pl: c = "pl"; break;
951 case vs: c = "vs"; break;
952 case vc: c = "vc"; break;
953 case hi: c = "hi"; break;
954 case ls: c = "ls"; break;
955 case ge: c = "ge"; break;
956 case lt: c = "lt"; break;
957 case gt: c = "gt"; break;
958 case le: c = "le"; break;
959 case al: c = ""; break;
960 default:
961 c = "";
962 UNREACHABLE();
963 }
964 }
965 PrintF("%s%s\n", b, c);
966 }
967 next(&l);
968 }
969 } else {
970 PrintF("label in inconsistent state (pos = %d)\n", L->pos_);
971 }
972}
973
974
975void Assembler::bind_to(Label* L, int pos) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000976 DCHECK(0 <= pos && pos <= pc_offset()); // must have a valid binding position
Steve Blocka7e24c12009-10-30 11:49:00 +0000977 while (L->is_linked()) {
978 int fixup_pos = L->pos();
979 next(L); // call next before overwriting link with target at fixup_pos
980 target_at_put(fixup_pos, pos);
981 }
982 L->bind_to(pos);
983
984 // Keep track of the last bound label so we don't eliminate any instructions
985 // before a bound label.
986 if (pos > last_bound_pos_)
987 last_bound_pos_ = pos;
988}
989
990
Steve Blocka7e24c12009-10-30 11:49:00 +0000991void Assembler::bind(Label* L) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000992 DCHECK(!L->is_bound()); // label can only be bound once
Steve Blocka7e24c12009-10-30 11:49:00 +0000993 bind_to(L, pc_offset());
994}
995
996
997void Assembler::next(Label* L) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000998 DCHECK(L->is_linked());
Steve Blocka7e24c12009-10-30 11:49:00 +0000999 int link = target_at(L->pos());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001000 if (link == L->pos()) {
1001 // Branch target points to the same instuction. This is the end of the link
1002 // chain.
Steve Blocka7e24c12009-10-30 11:49:00 +00001003 L->Unuse();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001004 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001005 DCHECK(link >= 0);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001006 L->link_to(link);
Steve Blocka7e24c12009-10-30 11:49:00 +00001007 }
1008}
1009
1010
Andrei Popescu31002712010-02-23 13:46:05 +00001011// Low-level code emission routines depending on the addressing mode.
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001012// If this returns true then you have to use the rotate_imm and immed_8
1013// that it returns, because it may have already changed the instruction
1014// to match them!
Steve Blocka7e24c12009-10-30 11:49:00 +00001015static bool fits_shifter(uint32_t imm32,
1016 uint32_t* rotate_imm,
1017 uint32_t* immed_8,
1018 Instr* instr) {
Andrei Popescu31002712010-02-23 13:46:05 +00001019 // imm32 must be unsigned.
Steve Blocka7e24c12009-10-30 11:49:00 +00001020 for (int rot = 0; rot < 16; rot++) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001021 uint32_t imm8 = base::bits::RotateLeft32(imm32, 2 * rot);
Steve Blocka7e24c12009-10-30 11:49:00 +00001022 if ((imm8 <= 0xff)) {
1023 *rotate_imm = rot;
1024 *immed_8 = imm8;
1025 return true;
1026 }
1027 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001028 // If the opcode is one with a complementary version and the complementary
1029 // immediate fits, change the opcode.
1030 if (instr != NULL) {
1031 if ((*instr & kMovMvnMask) == kMovMvnPattern) {
1032 if (fits_shifter(~imm32, rotate_imm, immed_8, NULL)) {
1033 *instr ^= kMovMvnFlip;
1034 return true;
1035 } else if ((*instr & kMovLeaveCCMask) == kMovLeaveCCPattern) {
Ben Murdoch8b112d22011-06-08 16:22:53 +01001036 if (CpuFeatures::IsSupported(ARMv7)) {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001037 if (imm32 < 0x10000) {
1038 *instr ^= kMovwLeaveCCFlip;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001039 *instr |= Assembler::EncodeMovwImmediate(imm32);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001040 *rotate_imm = *immed_8 = 0; // Not used for movw.
1041 return true;
1042 }
1043 }
1044 }
1045 } else if ((*instr & kCmpCmnMask) == kCmpCmnPattern) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001046 if (fits_shifter(-static_cast<int>(imm32), rotate_imm, immed_8, NULL)) {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001047 *instr ^= kCmpCmnFlip;
1048 return true;
1049 }
1050 } else {
1051 Instr alu_insn = (*instr & kALUMask);
Steve Block1e0659c2011-05-24 12:43:12 +01001052 if (alu_insn == ADD ||
1053 alu_insn == SUB) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001054 if (fits_shifter(-static_cast<int>(imm32), rotate_imm, immed_8, NULL)) {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001055 *instr ^= kAddSubFlip;
1056 return true;
1057 }
Steve Block1e0659c2011-05-24 12:43:12 +01001058 } else if (alu_insn == AND ||
1059 alu_insn == BIC) {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001060 if (fits_shifter(~imm32, rotate_imm, immed_8, NULL)) {
1061 *instr ^= kAndBicFlip;
1062 return true;
1063 }
1064 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001065 }
1066 }
1067 return false;
1068}
1069
1070
1071// We have to use the temporary register for things that can be relocated even
1072// if they can be encoded in the ARM's 12 bits of immediate-offset instruction
1073// space. There is no guarantee that the relocated location can be similarly
1074// encoded.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001075bool Operand::must_output_reloc_info(const Assembler* assembler) const {
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001076 if (rmode_ == RelocInfo::EXTERNAL_REFERENCE) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001077 if (assembler != NULL && assembler->predictable_code_size()) return true;
1078 return assembler->serializer_enabled();
1079 } else if (RelocInfo::IsNone(rmode_)) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001080 return false;
1081 }
1082 return true;
1083}
1084
1085
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001086static bool use_mov_immediate_load(const Operand& x,
1087 const Assembler* assembler) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001088 if (FLAG_enable_embedded_constant_pool && assembler != NULL &&
1089 !assembler->is_constant_pool_available()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001090 return true;
1091 } else if (CpuFeatures::IsSupported(MOVW_MOVT_IMMEDIATE_LOADS) &&
1092 (assembler == NULL || !assembler->predictable_code_size())) {
1093 // Prefer movw / movt to constant pool if it is more efficient on the CPU.
1094 return true;
1095 } else if (x.must_output_reloc_info(assembler)) {
1096 // Prefer constant pool if data is likely to be patched.
1097 return false;
1098 } else {
1099 // Otherwise, use immediate load if movw / movt is available.
1100 return CpuFeatures::IsSupported(ARMv7);
1101 }
1102}
1103
1104
1105int Operand::instructions_required(const Assembler* assembler,
1106 Instr instr) const {
1107 if (rm_.is_valid()) return 1;
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001108 uint32_t dummy1, dummy2;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001109 if (must_output_reloc_info(assembler) ||
Steve Block44f0eee2011-05-26 01:26:41 +01001110 !fits_shifter(imm32_, &dummy1, &dummy2, &instr)) {
1111 // The immediate operand cannot be encoded as a shifter operand, or use of
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001112 // constant pool is required. First account for the instructions required
1113 // for the constant pool or immediate load
1114 int instructions;
1115 if (use_mov_immediate_load(*this, assembler)) {
1116 // A movw / movt or mov / orr immediate load.
1117 instructions = CpuFeatures::IsSupported(ARMv7) ? 2 : 4;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001118 } else if (assembler != NULL &&
1119 assembler->ConstantPoolAccessIsInOverflow()) {
1120 // An overflowed constant pool load.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001121 instructions = CpuFeatures::IsSupported(ARMv7) ? 3 : 5;
Steve Block44f0eee2011-05-26 01:26:41 +01001122 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001123 // A small constant pool load.
1124 instructions = 1;
Steve Block44f0eee2011-05-26 01:26:41 +01001125 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001126
1127 if ((instr & ~kCondMask) != 13 * B21) { // mov, S not set
1128 // For a mov or mvn instruction which doesn't set the condition
1129 // code, the constant pool or immediate load is enough, otherwise we need
1130 // to account for the actual instruction being requested.
1131 instructions += 1;
1132 }
1133 return instructions;
Steve Block44f0eee2011-05-26 01:26:41 +01001134 } else {
1135 // No use of constant pool and the immediate operand can be encoded as a
1136 // shifter operand.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001137 return 1;
1138 }
1139}
1140
1141
1142void Assembler::move_32_bit_immediate(Register rd,
1143 const Operand& x,
1144 Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001145 uint32_t imm32 = static_cast<uint32_t>(x.imm32_);
1146 if (x.must_output_reloc_info(this)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001147 RecordRelocInfo(x.rmode_);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001148 }
1149
1150 if (use_mov_immediate_load(x, this)) {
1151 Register target = rd.code() == pc.code() ? ip : rd;
1152 if (CpuFeatures::IsSupported(ARMv7)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001153 if (!FLAG_enable_embedded_constant_pool &&
1154 x.must_output_reloc_info(this)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001155 // Make sure the movw/movt doesn't get separated.
1156 BlockConstPoolFor(2);
1157 }
1158 movw(target, imm32 & 0xffff, cond);
1159 movt(target, imm32 >> 16, cond);
1160 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001161 DCHECK(FLAG_enable_embedded_constant_pool);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001162 mov(target, Operand(imm32 & kImm8Mask), LeaveCC, cond);
1163 orr(target, target, Operand(imm32 & (kImm8Mask << 8)), LeaveCC, cond);
1164 orr(target, target, Operand(imm32 & (kImm8Mask << 16)), LeaveCC, cond);
1165 orr(target, target, Operand(imm32 & (kImm8Mask << 24)), LeaveCC, cond);
1166 }
1167 if (target.code() != rd.code()) {
1168 mov(rd, target, LeaveCC, cond);
1169 }
1170 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001171 DCHECK(!FLAG_enable_embedded_constant_pool || is_constant_pool_available());
1172 ConstantPoolEntry::Access access =
1173 ConstantPoolAddEntry(pc_offset(), x.rmode_, x.imm32_);
1174 if (access == ConstantPoolEntry::OVERFLOWED) {
1175 DCHECK(FLAG_enable_embedded_constant_pool);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001176 Register target = rd.code() == pc.code() ? ip : rd;
1177 // Emit instructions to load constant pool offset.
1178 if (CpuFeatures::IsSupported(ARMv7)) {
1179 movw(target, 0, cond);
1180 movt(target, 0, cond);
1181 } else {
1182 mov(target, Operand(0), LeaveCC, cond);
1183 orr(target, target, Operand(0), LeaveCC, cond);
1184 orr(target, target, Operand(0), LeaveCC, cond);
1185 orr(target, target, Operand(0), LeaveCC, cond);
1186 }
1187 // Load from constant pool at offset.
1188 ldr(rd, MemOperand(pp, target), cond);
1189 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001190 DCHECK(access == ConstantPoolEntry::REGULAR);
1191 ldr(rd, MemOperand(FLAG_enable_embedded_constant_pool ? pp : pc, 0),
1192 cond);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001193 }
Steve Block44f0eee2011-05-26 01:26:41 +01001194 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001195}
1196
1197
Steve Blocka7e24c12009-10-30 11:49:00 +00001198void Assembler::addrmod1(Instr instr,
1199 Register rn,
1200 Register rd,
1201 const Operand& x) {
1202 CheckBuffer();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001203 DCHECK((instr & ~(kCondMask | kOpCodeMask | S)) == 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00001204 if (!x.rm_.is_valid()) {
Andrei Popescu31002712010-02-23 13:46:05 +00001205 // Immediate.
Steve Blocka7e24c12009-10-30 11:49:00 +00001206 uint32_t rotate_imm;
1207 uint32_t immed_8;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001208 if (x.must_output_reloc_info(this) ||
Steve Blocka7e24c12009-10-30 11:49:00 +00001209 !fits_shifter(x.imm32_, &rotate_imm, &immed_8, &instr)) {
1210 // The immediate operand cannot be encoded as a shifter operand, so load
1211 // it first to register ip and change the original instruction to use ip.
1212 // However, if the original instruction is a 'mov rd, x' (not setting the
Andrei Popescu31002712010-02-23 13:46:05 +00001213 // condition code), then replace it with a 'ldr rd, [pc]'.
Steve Blocka7e24c12009-10-30 11:49:00 +00001214 CHECK(!rn.is(ip)); // rn should never be ip, or will be trashed
Steve Block1e0659c2011-05-24 12:43:12 +01001215 Condition cond = Instruction::ConditionField(instr);
1216 if ((instr & ~kCondMask) == 13*B21) { // mov, S not set
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001217 move_32_bit_immediate(rd, x, cond);
Steve Blocka7e24c12009-10-30 11:49:00 +00001218 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001219 mov(ip, x, LeaveCC, cond);
Steve Blocka7e24c12009-10-30 11:49:00 +00001220 addrmod1(instr, rn, rd, Operand(ip));
1221 }
1222 return;
1223 }
1224 instr |= I | rotate_imm*B8 | immed_8;
1225 } else if (!x.rs_.is_valid()) {
Andrei Popescu31002712010-02-23 13:46:05 +00001226 // Immediate shift.
Steve Blocka7e24c12009-10-30 11:49:00 +00001227 instr |= x.shift_imm_*B7 | x.shift_op_ | x.rm_.code();
1228 } else {
Andrei Popescu31002712010-02-23 13:46:05 +00001229 // Register shift.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001230 DCHECK(!rn.is(pc) && !rd.is(pc) && !x.rm_.is(pc) && !x.rs_.is(pc));
Steve Blocka7e24c12009-10-30 11:49:00 +00001231 instr |= x.rs_.code()*B8 | x.shift_op_ | B4 | x.rm_.code();
1232 }
1233 emit(instr | rn.code()*B16 | rd.code()*B12);
Kristian Monsen50ef84f2010-07-29 15:18:00 +01001234 if (rn.is(pc) || x.rm_.is(pc)) {
Andrei Popescu31002712010-02-23 13:46:05 +00001235 // Block constant pool emission for one instruction after reading pc.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001236 BlockConstPoolFor(1);
Kristian Monsen50ef84f2010-07-29 15:18:00 +01001237 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001238}
1239
1240
1241void Assembler::addrmod2(Instr instr, Register rd, const MemOperand& x) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001242 DCHECK((instr & ~(kCondMask | B | L)) == B26);
Steve Blocka7e24c12009-10-30 11:49:00 +00001243 int am = x.am_;
1244 if (!x.rm_.is_valid()) {
Andrei Popescu31002712010-02-23 13:46:05 +00001245 // Immediate offset.
Steve Blocka7e24c12009-10-30 11:49:00 +00001246 int offset_12 = x.offset_;
1247 if (offset_12 < 0) {
1248 offset_12 = -offset_12;
1249 am ^= U;
1250 }
1251 if (!is_uint12(offset_12)) {
Andrei Popescu31002712010-02-23 13:46:05 +00001252 // Immediate offset cannot be encoded, load it first to register ip
1253 // rn (and rd in a load) should never be ip, or will be trashed.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001254 DCHECK(!x.rn_.is(ip) && ((instr & L) == L || !rd.is(ip)));
Steve Block1e0659c2011-05-24 12:43:12 +01001255 mov(ip, Operand(x.offset_), LeaveCC, Instruction::ConditionField(instr));
Steve Blocka7e24c12009-10-30 11:49:00 +00001256 addrmod2(instr, rd, MemOperand(x.rn_, ip, x.am_));
1257 return;
1258 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001259 DCHECK(offset_12 >= 0); // no masking needed
Steve Blocka7e24c12009-10-30 11:49:00 +00001260 instr |= offset_12;
1261 } else {
Andrei Popescu31002712010-02-23 13:46:05 +00001262 // Register offset (shift_imm_ and shift_op_ are 0) or scaled
Steve Blocka7e24c12009-10-30 11:49:00 +00001263 // register offset the constructors make sure than both shift_imm_
Andrei Popescu31002712010-02-23 13:46:05 +00001264 // and shift_op_ are initialized.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001265 DCHECK(!x.rm_.is(pc));
Steve Blocka7e24c12009-10-30 11:49:00 +00001266 instr |= B25 | x.shift_imm_*B7 | x.shift_op_ | x.rm_.code();
1267 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001268 DCHECK((am & (P|W)) == P || !x.rn_.is(pc)); // no pc base with writeback
Steve Blocka7e24c12009-10-30 11:49:00 +00001269 emit(instr | am | x.rn_.code()*B16 | rd.code()*B12);
1270}
1271
1272
1273void Assembler::addrmod3(Instr instr, Register rd, const MemOperand& x) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001274 DCHECK((instr & ~(kCondMask | L | S6 | H)) == (B4 | B7));
1275 DCHECK(x.rn_.is_valid());
Steve Blocka7e24c12009-10-30 11:49:00 +00001276 int am = x.am_;
1277 if (!x.rm_.is_valid()) {
Andrei Popescu31002712010-02-23 13:46:05 +00001278 // Immediate offset.
Steve Blocka7e24c12009-10-30 11:49:00 +00001279 int offset_8 = x.offset_;
1280 if (offset_8 < 0) {
1281 offset_8 = -offset_8;
1282 am ^= U;
1283 }
1284 if (!is_uint8(offset_8)) {
Andrei Popescu31002712010-02-23 13:46:05 +00001285 // Immediate offset cannot be encoded, load it first to register ip
1286 // rn (and rd in a load) should never be ip, or will be trashed.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001287 DCHECK(!x.rn_.is(ip) && ((instr & L) == L || !rd.is(ip)));
Steve Block1e0659c2011-05-24 12:43:12 +01001288 mov(ip, Operand(x.offset_), LeaveCC, Instruction::ConditionField(instr));
Steve Blocka7e24c12009-10-30 11:49:00 +00001289 addrmod3(instr, rd, MemOperand(x.rn_, ip, x.am_));
1290 return;
1291 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001292 DCHECK(offset_8 >= 0); // no masking needed
Steve Blocka7e24c12009-10-30 11:49:00 +00001293 instr |= B | (offset_8 >> 4)*B8 | (offset_8 & 0xf);
1294 } else if (x.shift_imm_ != 0) {
Andrei Popescu31002712010-02-23 13:46:05 +00001295 // Scaled register offset not supported, load index first
1296 // rn (and rd in a load) should never be ip, or will be trashed.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001297 DCHECK(!x.rn_.is(ip) && ((instr & L) == L || !rd.is(ip)));
Steve Blocka7e24c12009-10-30 11:49:00 +00001298 mov(ip, Operand(x.rm_, x.shift_op_, x.shift_imm_), LeaveCC,
Steve Block1e0659c2011-05-24 12:43:12 +01001299 Instruction::ConditionField(instr));
Steve Blocka7e24c12009-10-30 11:49:00 +00001300 addrmod3(instr, rd, MemOperand(x.rn_, ip, x.am_));
1301 return;
1302 } else {
Andrei Popescu31002712010-02-23 13:46:05 +00001303 // Register offset.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001304 DCHECK((am & (P|W)) == P || !x.rm_.is(pc)); // no pc index with writeback
Steve Blocka7e24c12009-10-30 11:49:00 +00001305 instr |= x.rm_.code();
1306 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001307 DCHECK((am & (P|W)) == P || !x.rn_.is(pc)); // no pc base with writeback
Steve Blocka7e24c12009-10-30 11:49:00 +00001308 emit(instr | am | x.rn_.code()*B16 | rd.code()*B12);
1309}
1310
1311
1312void Assembler::addrmod4(Instr instr, Register rn, RegList rl) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001313 DCHECK((instr & ~(kCondMask | P | U | W | L)) == B27);
1314 DCHECK(rl != 0);
1315 DCHECK(!rn.is(pc));
Steve Blocka7e24c12009-10-30 11:49:00 +00001316 emit(instr | rn.code()*B16 | rl);
1317}
1318
1319
1320void Assembler::addrmod5(Instr instr, CRegister crd, const MemOperand& x) {
Andrei Popescu31002712010-02-23 13:46:05 +00001321 // Unindexed addressing is not encoded by this function.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001322 DCHECK_EQ((B27 | B26),
Steve Block1e0659c2011-05-24 12:43:12 +01001323 (instr & ~(kCondMask | kCoprocessorMask | P | U | N | W | L)));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001324 DCHECK(x.rn_.is_valid() && !x.rm_.is_valid());
Steve Blocka7e24c12009-10-30 11:49:00 +00001325 int am = x.am_;
1326 int offset_8 = x.offset_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001327 DCHECK((offset_8 & 3) == 0); // offset must be an aligned word offset
Steve Blocka7e24c12009-10-30 11:49:00 +00001328 offset_8 >>= 2;
1329 if (offset_8 < 0) {
1330 offset_8 = -offset_8;
1331 am ^= U;
1332 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001333 DCHECK(is_uint8(offset_8)); // unsigned word offset must fit in a byte
1334 DCHECK((am & (P|W)) == P || !x.rn_.is(pc)); // no pc base with writeback
Steve Blocka7e24c12009-10-30 11:49:00 +00001335
Andrei Popescu31002712010-02-23 13:46:05 +00001336 // Post-indexed addressing requires W == 1; different than in addrmod2/3.
Steve Blocka7e24c12009-10-30 11:49:00 +00001337 if ((am & P) == 0)
1338 am |= W;
1339
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001340 DCHECK(offset_8 >= 0); // no masking needed
Steve Blocka7e24c12009-10-30 11:49:00 +00001341 emit(instr | am | x.rn_.code()*B16 | crd.code()*B12 | offset_8);
1342}
1343
1344
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001345int Assembler::branch_offset(Label* L) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001346 int target_pos;
1347 if (L->is_bound()) {
1348 target_pos = L->pos();
1349 } else {
1350 if (L->is_linked()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001351 // Point to previous instruction that uses the link.
1352 target_pos = L->pos();
Steve Blocka7e24c12009-10-30 11:49:00 +00001353 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001354 // First entry of the link chain points to itself.
1355 target_pos = pc_offset();
Steve Blocka7e24c12009-10-30 11:49:00 +00001356 }
1357 L->link_to(pc_offset());
1358 }
1359
1360 // Block the emission of the constant pool, since the branch instruction must
Andrei Popescu31002712010-02-23 13:46:05 +00001361 // be emitted at the pc offset recorded by the label.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001362 if (!is_const_pool_blocked()) BlockConstPoolFor(1);
1363
Steve Blocka7e24c12009-10-30 11:49:00 +00001364 return target_pos - (pc_offset() + kPcLoadDelta);
1365}
1366
1367
Andrei Popescu31002712010-02-23 13:46:05 +00001368// Branch instructions.
Steve Blocka7e24c12009-10-30 11:49:00 +00001369void Assembler::b(int branch_offset, Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001370 DCHECK((branch_offset & 3) == 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00001371 int imm24 = branch_offset >> 2;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001372 CHECK(is_int24(imm24));
Steve Block1e0659c2011-05-24 12:43:12 +01001373 emit(cond | B27 | B25 | (imm24 & kImm24Mask));
Steve Blocka7e24c12009-10-30 11:49:00 +00001374
Steve Block6ded16b2010-05-10 14:33:55 +01001375 if (cond == al) {
Andrei Popescu31002712010-02-23 13:46:05 +00001376 // Dead code is a good location to emit the constant pool.
Steve Blocka7e24c12009-10-30 11:49:00 +00001377 CheckConstPool(false, false);
Steve Block6ded16b2010-05-10 14:33:55 +01001378 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001379}
1380
1381
1382void Assembler::bl(int branch_offset, Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001383 DCHECK((branch_offset & 3) == 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00001384 int imm24 = branch_offset >> 2;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001385 CHECK(is_int24(imm24));
Steve Block1e0659c2011-05-24 12:43:12 +01001386 emit(cond | B27 | B25 | B24 | (imm24 & kImm24Mask));
Steve Blocka7e24c12009-10-30 11:49:00 +00001387}
1388
1389
1390void Assembler::blx(int branch_offset) { // v5 and above
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001391 DCHECK((branch_offset & 1) == 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00001392 int h = ((branch_offset & 2) >> 1)*B24;
1393 int imm24 = branch_offset >> 2;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001394 CHECK(is_int24(imm24));
Steve Block1e0659c2011-05-24 12:43:12 +01001395 emit(kSpecialCondition | B27 | B25 | h | (imm24 & kImm24Mask));
Steve Blocka7e24c12009-10-30 11:49:00 +00001396}
1397
1398
1399void Assembler::blx(Register target, Condition cond) { // v5 and above
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001400 DCHECK(!target.is(pc));
Steve Block1e0659c2011-05-24 12:43:12 +01001401 emit(cond | B24 | B21 | 15*B16 | 15*B12 | 15*B8 | BLX | target.code());
Steve Blocka7e24c12009-10-30 11:49:00 +00001402}
1403
1404
1405void Assembler::bx(Register target, Condition cond) { // v5 and above, plus v4t
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001406 DCHECK(!target.is(pc)); // use of pc is actually allowed, but discouraged
Steve Block1e0659c2011-05-24 12:43:12 +01001407 emit(cond | B24 | B21 | 15*B16 | 15*B12 | 15*B8 | BX | target.code());
Steve Blocka7e24c12009-10-30 11:49:00 +00001408}
1409
1410
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001411void Assembler::b(Label* L, Condition cond) {
1412 CheckBuffer();
1413 b(branch_offset(L), cond);
1414}
1415
1416
1417void Assembler::bl(Label* L, Condition cond) {
1418 CheckBuffer();
1419 bl(branch_offset(L), cond);
1420}
1421
1422
1423void Assembler::blx(Label* L) {
1424 CheckBuffer();
1425 blx(branch_offset(L));
1426}
1427
1428
Andrei Popescu31002712010-02-23 13:46:05 +00001429// Data-processing instructions.
1430
Steve Blocka7e24c12009-10-30 11:49:00 +00001431void Assembler::and_(Register dst, Register src1, const Operand& src2,
1432 SBit s, Condition cond) {
Steve Block1e0659c2011-05-24 12:43:12 +01001433 addrmod1(cond | AND | s, src1, dst, src2);
Steve Blocka7e24c12009-10-30 11:49:00 +00001434}
1435
1436
1437void Assembler::eor(Register dst, Register src1, const Operand& src2,
1438 SBit s, Condition cond) {
Steve Block1e0659c2011-05-24 12:43:12 +01001439 addrmod1(cond | EOR | s, src1, dst, src2);
Steve Blocka7e24c12009-10-30 11:49:00 +00001440}
1441
1442
1443void Assembler::sub(Register dst, Register src1, const Operand& src2,
1444 SBit s, Condition cond) {
Steve Block1e0659c2011-05-24 12:43:12 +01001445 addrmod1(cond | SUB | s, src1, dst, src2);
Steve Blocka7e24c12009-10-30 11:49:00 +00001446}
1447
1448
1449void Assembler::rsb(Register dst, Register src1, const Operand& src2,
1450 SBit s, Condition cond) {
Steve Block1e0659c2011-05-24 12:43:12 +01001451 addrmod1(cond | RSB | s, src1, dst, src2);
Steve Blocka7e24c12009-10-30 11:49:00 +00001452}
1453
1454
1455void Assembler::add(Register dst, Register src1, const Operand& src2,
1456 SBit s, Condition cond) {
Steve Block1e0659c2011-05-24 12:43:12 +01001457 addrmod1(cond | ADD | s, src1, dst, src2);
Steve Blocka7e24c12009-10-30 11:49:00 +00001458}
1459
1460
1461void Assembler::adc(Register dst, Register src1, const Operand& src2,
1462 SBit s, Condition cond) {
Steve Block1e0659c2011-05-24 12:43:12 +01001463 addrmod1(cond | ADC | s, src1, dst, src2);
Steve Blocka7e24c12009-10-30 11:49:00 +00001464}
1465
1466
1467void Assembler::sbc(Register dst, Register src1, const Operand& src2,
1468 SBit s, Condition cond) {
Steve Block1e0659c2011-05-24 12:43:12 +01001469 addrmod1(cond | SBC | s, src1, dst, src2);
Steve Blocka7e24c12009-10-30 11:49:00 +00001470}
1471
1472
1473void Assembler::rsc(Register dst, Register src1, const Operand& src2,
1474 SBit s, Condition cond) {
Steve Block1e0659c2011-05-24 12:43:12 +01001475 addrmod1(cond | RSC | s, src1, dst, src2);
Steve Blocka7e24c12009-10-30 11:49:00 +00001476}
1477
1478
1479void Assembler::tst(Register src1, const Operand& src2, Condition cond) {
Steve Block1e0659c2011-05-24 12:43:12 +01001480 addrmod1(cond | TST | S, src1, r0, src2);
Steve Blocka7e24c12009-10-30 11:49:00 +00001481}
1482
1483
1484void Assembler::teq(Register src1, const Operand& src2, Condition cond) {
Steve Block1e0659c2011-05-24 12:43:12 +01001485 addrmod1(cond | TEQ | S, src1, r0, src2);
Steve Blocka7e24c12009-10-30 11:49:00 +00001486}
1487
1488
1489void Assembler::cmp(Register src1, const Operand& src2, Condition cond) {
Steve Block1e0659c2011-05-24 12:43:12 +01001490 addrmod1(cond | CMP | S, src1, r0, src2);
1491}
1492
1493
1494void Assembler::cmp_raw_immediate(
1495 Register src, int raw_immediate, Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001496 DCHECK(is_uint12(raw_immediate));
Steve Block1e0659c2011-05-24 12:43:12 +01001497 emit(cond | I | CMP | S | src.code() << 16 | raw_immediate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001498}
1499
1500
1501void Assembler::cmn(Register src1, const Operand& src2, Condition cond) {
Steve Block1e0659c2011-05-24 12:43:12 +01001502 addrmod1(cond | CMN | S, src1, r0, src2);
Steve Blocka7e24c12009-10-30 11:49:00 +00001503}
1504
1505
1506void Assembler::orr(Register dst, Register src1, const Operand& src2,
1507 SBit s, Condition cond) {
Steve Block1e0659c2011-05-24 12:43:12 +01001508 addrmod1(cond | ORR | s, src1, dst, src2);
Steve Blocka7e24c12009-10-30 11:49:00 +00001509}
1510
1511
1512void Assembler::mov(Register dst, const Operand& src, SBit s, Condition cond) {
Steve Block6ded16b2010-05-10 14:33:55 +01001513 // Don't allow nop instructions in the form mov rn, rn to be generated using
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001514 // the mov instruction. They must be generated using nop(int/NopMarkerTypes)
1515 // or MarkCode(int/NopMarkerTypes) pseudo instructions.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001516 DCHECK(!(src.is_reg() && src.rm().is(dst) && s == LeaveCC && cond == al));
Steve Block1e0659c2011-05-24 12:43:12 +01001517 addrmod1(cond | MOV | s, r0, dst, src);
Steve Blocka7e24c12009-10-30 11:49:00 +00001518}
1519
1520
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001521void Assembler::mov_label_offset(Register dst, Label* label) {
1522 if (label->is_bound()) {
1523 mov(dst, Operand(label->pos() + (Code::kHeaderSize - kHeapObjectTag)));
1524 } else {
1525 // Emit the link to the label in the code stream followed by extra nop
1526 // instructions.
1527 // If the label is not linked, then start a new link chain by linking it to
1528 // itself, emitting pc_offset().
1529 int link = label->is_linked() ? label->pos() : pc_offset();
1530 label->link_to(pc_offset());
1531
1532 // When the label is bound, these instructions will be patched with a
1533 // sequence of movw/movt or mov/orr/orr instructions. They will load the
1534 // destination register with the position of the label from the beginning
1535 // of the code.
1536 //
1537 // The link will be extracted from the first instruction and the destination
1538 // register from the second.
1539 // For ARMv7:
1540 // link
1541 // mov dst, dst
1542 // For ARMv6:
1543 // link
1544 // mov dst, dst
1545 // mov dst, dst
1546 //
1547 // When the label gets bound: target_at extracts the link and target_at_put
1548 // patches the instructions.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001549 CHECK(is_uint24(link));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001550 BlockConstPoolScope block_const_pool(this);
1551 emit(link);
1552 nop(dst.code());
1553 if (!CpuFeatures::IsSupported(ARMv7)) {
1554 nop(dst.code());
1555 }
1556 }
1557}
1558
1559
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001560void Assembler::movw(Register reg, uint32_t immediate, Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001561 DCHECK(CpuFeatures::IsSupported(ARMv7));
1562 emit(cond | 0x30*B20 | reg.code()*B12 | EncodeMovwImmediate(immediate));
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001563}
1564
1565
1566void Assembler::movt(Register reg, uint32_t immediate, Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001567 DCHECK(CpuFeatures::IsSupported(ARMv7));
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001568 emit(cond | 0x34*B20 | reg.code()*B12 | EncodeMovwImmediate(immediate));
1569}
1570
1571
Steve Blocka7e24c12009-10-30 11:49:00 +00001572void Assembler::bic(Register dst, Register src1, const Operand& src2,
1573 SBit s, Condition cond) {
Steve Block1e0659c2011-05-24 12:43:12 +01001574 addrmod1(cond | BIC | s, src1, dst, src2);
Steve Blocka7e24c12009-10-30 11:49:00 +00001575}
1576
1577
1578void Assembler::mvn(Register dst, const Operand& src, SBit s, Condition cond) {
Steve Block1e0659c2011-05-24 12:43:12 +01001579 addrmod1(cond | MVN | s, r0, dst, src);
Steve Blocka7e24c12009-10-30 11:49:00 +00001580}
1581
1582
Andrei Popescu31002712010-02-23 13:46:05 +00001583// Multiply instructions.
Steve Blocka7e24c12009-10-30 11:49:00 +00001584void Assembler::mla(Register dst, Register src1, Register src2, Register srcA,
1585 SBit s, Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001586 DCHECK(!dst.is(pc) && !src1.is(pc) && !src2.is(pc) && !srcA.is(pc));
Steve Blocka7e24c12009-10-30 11:49:00 +00001587 emit(cond | A | s | dst.code()*B16 | srcA.code()*B12 |
1588 src2.code()*B8 | B7 | B4 | src1.code());
1589}
1590
1591
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001592void Assembler::mls(Register dst, Register src1, Register src2, Register srcA,
1593 Condition cond) {
1594 DCHECK(!dst.is(pc) && !src1.is(pc) && !src2.is(pc) && !srcA.is(pc));
Ben Murdoch61f157c2016-09-16 13:49:30 +01001595 DCHECK(IsEnabled(ARMv7));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001596 emit(cond | B22 | B21 | dst.code()*B16 | srcA.code()*B12 |
1597 src2.code()*B8 | B7 | B4 | src1.code());
1598}
1599
1600
1601void Assembler::sdiv(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 | B20 | dst.code()*B16 | 0xf * B12 |
1606 src2.code()*B8 | B4 | src1.code());
1607}
1608
1609
1610void Assembler::udiv(Register dst, Register src1, Register src2,
1611 Condition cond) {
1612 DCHECK(!dst.is(pc) && !src1.is(pc) && !src2.is(pc));
1613 DCHECK(IsEnabled(SUDIV));
1614 emit(cond | B26 | B25 | B24 | B21 | B20 | dst.code() * B16 | 0xf * B12 |
1615 src2.code() * B8 | B4 | src1.code());
1616}
1617
1618
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001619void Assembler::mul(Register dst, Register src1, Register src2, SBit s,
1620 Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001621 DCHECK(!dst.is(pc) && !src1.is(pc) && !src2.is(pc));
Steve Blocka7e24c12009-10-30 11:49:00 +00001622 // dst goes in bits 16-19 for this instruction!
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001623 emit(cond | s | dst.code() * B16 | src2.code() * B8 | B7 | B4 | src1.code());
1624}
1625
1626
1627void Assembler::smmla(Register dst, Register src1, Register src2, Register srcA,
1628 Condition cond) {
1629 DCHECK(!dst.is(pc) && !src1.is(pc) && !src2.is(pc) && !srcA.is(pc));
1630 emit(cond | B26 | B25 | B24 | B22 | B20 | dst.code() * B16 |
1631 srcA.code() * B12 | src2.code() * B8 | B4 | src1.code());
1632}
1633
1634
1635void Assembler::smmul(Register dst, Register src1, Register src2,
1636 Condition cond) {
1637 DCHECK(!dst.is(pc) && !src1.is(pc) && !src2.is(pc));
1638 emit(cond | B26 | B25 | B24 | B22 | B20 | dst.code() * B16 | 0xf * B12 |
1639 src2.code() * B8 | B4 | src1.code());
Steve Blocka7e24c12009-10-30 11:49:00 +00001640}
1641
1642
1643void Assembler::smlal(Register dstL,
1644 Register dstH,
1645 Register src1,
1646 Register src2,
1647 SBit s,
1648 Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001649 DCHECK(!dstL.is(pc) && !dstH.is(pc) && !src1.is(pc) && !src2.is(pc));
1650 DCHECK(!dstL.is(dstH));
Steve Blocka7e24c12009-10-30 11:49:00 +00001651 emit(cond | B23 | B22 | A | s | dstH.code()*B16 | dstL.code()*B12 |
1652 src2.code()*B8 | B7 | B4 | src1.code());
1653}
1654
1655
1656void Assembler::smull(Register dstL,
1657 Register dstH,
1658 Register src1,
1659 Register src2,
1660 SBit s,
1661 Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001662 DCHECK(!dstL.is(pc) && !dstH.is(pc) && !src1.is(pc) && !src2.is(pc));
1663 DCHECK(!dstL.is(dstH));
Steve Blocka7e24c12009-10-30 11:49:00 +00001664 emit(cond | B23 | B22 | s | dstH.code()*B16 | dstL.code()*B12 |
1665 src2.code()*B8 | B7 | B4 | src1.code());
1666}
1667
1668
1669void Assembler::umlal(Register dstL,
1670 Register dstH,
1671 Register src1,
1672 Register src2,
1673 SBit s,
1674 Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001675 DCHECK(!dstL.is(pc) && !dstH.is(pc) && !src1.is(pc) && !src2.is(pc));
1676 DCHECK(!dstL.is(dstH));
Steve Blocka7e24c12009-10-30 11:49:00 +00001677 emit(cond | B23 | A | s | dstH.code()*B16 | dstL.code()*B12 |
1678 src2.code()*B8 | B7 | B4 | src1.code());
1679}
1680
1681
1682void Assembler::umull(Register dstL,
1683 Register dstH,
1684 Register src1,
1685 Register src2,
1686 SBit s,
1687 Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001688 DCHECK(!dstL.is(pc) && !dstH.is(pc) && !src1.is(pc) && !src2.is(pc));
1689 DCHECK(!dstL.is(dstH));
Steve Blocka7e24c12009-10-30 11:49:00 +00001690 emit(cond | B23 | s | dstH.code()*B16 | dstL.code()*B12 |
1691 src2.code()*B8 | B7 | B4 | src1.code());
1692}
1693
1694
Andrei Popescu31002712010-02-23 13:46:05 +00001695// Miscellaneous arithmetic instructions.
Steve Blocka7e24c12009-10-30 11:49:00 +00001696void Assembler::clz(Register dst, Register src, Condition cond) {
1697 // v5 and above.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001698 DCHECK(!dst.is(pc) && !src.is(pc));
Steve Blocka7e24c12009-10-30 11:49:00 +00001699 emit(cond | B24 | B22 | B21 | 15*B16 | dst.code()*B12 |
Steve Block1e0659c2011-05-24 12:43:12 +01001700 15*B8 | CLZ | src.code());
Steve Blocka7e24c12009-10-30 11:49:00 +00001701}
1702
1703
Kristian Monsen50ef84f2010-07-29 15:18:00 +01001704// Saturating instructions.
1705
1706// Unsigned saturate.
1707void Assembler::usat(Register dst,
1708 int satpos,
1709 const Operand& src,
1710 Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001711 DCHECK(!dst.is(pc) && !src.rm_.is(pc));
1712 DCHECK((satpos >= 0) && (satpos <= 31));
1713 DCHECK((src.shift_op_ == ASR) || (src.shift_op_ == LSL));
1714 DCHECK(src.rs_.is(no_reg));
Kristian Monsen50ef84f2010-07-29 15:18:00 +01001715
1716 int sh = 0;
1717 if (src.shift_op_ == ASR) {
1718 sh = 1;
1719 }
1720
1721 emit(cond | 0x6*B24 | 0xe*B20 | satpos*B16 | dst.code()*B12 |
1722 src.shift_imm_*B7 | sh*B6 | 0x1*B4 | src.rm_.code());
1723}
1724
1725
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001726// Bitfield manipulation instructions.
1727
1728// Unsigned bit field extract.
1729// Extracts #width adjacent bits from position #lsb in a register, and
1730// writes them to the low bits of a destination register.
1731// ubfx dst, src, #lsb, #width
1732void Assembler::ubfx(Register dst,
1733 Register src,
1734 int lsb,
1735 int width,
1736 Condition cond) {
1737 // v7 and above.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001738 DCHECK(CpuFeatures::IsSupported(ARMv7));
1739 DCHECK(!dst.is(pc) && !src.is(pc));
1740 DCHECK((lsb >= 0) && (lsb <= 31));
1741 DCHECK((width >= 1) && (width <= (32 - lsb)));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001742 emit(cond | 0xf*B23 | B22 | B21 | (width - 1)*B16 | dst.code()*B12 |
1743 lsb*B7 | B6 | B4 | src.code());
1744}
1745
1746
1747// Signed bit field extract.
1748// Extracts #width adjacent bits from position #lsb in a register, and
1749// writes them to the low bits of a destination register. The extracted
1750// value is sign extended to fill the destination register.
1751// sbfx dst, src, #lsb, #width
1752void Assembler::sbfx(Register dst,
1753 Register src,
1754 int lsb,
1755 int width,
1756 Condition cond) {
1757 // v7 and above.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001758 DCHECK(CpuFeatures::IsSupported(ARMv7));
1759 DCHECK(!dst.is(pc) && !src.is(pc));
1760 DCHECK((lsb >= 0) && (lsb <= 31));
1761 DCHECK((width >= 1) && (width <= (32 - lsb)));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001762 emit(cond | 0xf*B23 | B21 | (width - 1)*B16 | dst.code()*B12 |
1763 lsb*B7 | B6 | B4 | src.code());
1764}
1765
1766
1767// Bit field clear.
1768// Sets #width adjacent bits at position #lsb in the destination register
1769// to zero, preserving the value of the other bits.
1770// bfc dst, #lsb, #width
1771void Assembler::bfc(Register dst, int lsb, int width, Condition cond) {
1772 // v7 and above.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001773 DCHECK(CpuFeatures::IsSupported(ARMv7));
1774 DCHECK(!dst.is(pc));
1775 DCHECK((lsb >= 0) && (lsb <= 31));
1776 DCHECK((width >= 1) && (width <= (32 - lsb)));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001777 int msb = lsb + width - 1;
1778 emit(cond | 0x1f*B22 | msb*B16 | dst.code()*B12 | lsb*B7 | B4 | 0xf);
1779}
1780
1781
1782// Bit field insert.
1783// Inserts #width adjacent bits from the low bits of the source register
1784// into position #lsb of the destination register.
1785// bfi dst, src, #lsb, #width
1786void Assembler::bfi(Register dst,
1787 Register src,
1788 int lsb,
1789 int width,
1790 Condition cond) {
1791 // v7 and above.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001792 DCHECK(CpuFeatures::IsSupported(ARMv7));
1793 DCHECK(!dst.is(pc) && !src.is(pc));
1794 DCHECK((lsb >= 0) && (lsb <= 31));
1795 DCHECK((width >= 1) && (width <= (32 - lsb)));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001796 int msb = lsb + width - 1;
1797 emit(cond | 0x1f*B22 | msb*B16 | dst.code()*B12 | lsb*B7 | B4 |
1798 src.code());
1799}
1800
1801
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001802void Assembler::pkhbt(Register dst,
1803 Register src1,
1804 const Operand& src2,
1805 Condition cond ) {
1806 // Instruction details available in ARM DDI 0406C.b, A8.8.125.
1807 // cond(31-28) | 01101000(27-20) | Rn(19-16) |
1808 // Rd(15-12) | imm5(11-7) | 0(6) | 01(5-4) | Rm(3-0)
1809 DCHECK(!dst.is(pc));
1810 DCHECK(!src1.is(pc));
1811 DCHECK(!src2.rm().is(pc));
1812 DCHECK(!src2.rm().is(no_reg));
1813 DCHECK(src2.rs().is(no_reg));
1814 DCHECK((src2.shift_imm_ >= 0) && (src2.shift_imm_ <= 31));
1815 DCHECK(src2.shift_op() == LSL);
1816 emit(cond | 0x68*B20 | src1.code()*B16 | dst.code()*B12 |
1817 src2.shift_imm_*B7 | B4 | src2.rm().code());
1818}
1819
1820
1821void Assembler::pkhtb(Register dst,
1822 Register src1,
1823 const Operand& src2,
1824 Condition cond) {
1825 // Instruction details available in ARM DDI 0406C.b, A8.8.125.
1826 // cond(31-28) | 01101000(27-20) | Rn(19-16) |
1827 // Rd(15-12) | imm5(11-7) | 1(6) | 01(5-4) | Rm(3-0)
1828 DCHECK(!dst.is(pc));
1829 DCHECK(!src1.is(pc));
1830 DCHECK(!src2.rm().is(pc));
1831 DCHECK(!src2.rm().is(no_reg));
1832 DCHECK(src2.rs().is(no_reg));
1833 DCHECK((src2.shift_imm_ >= 1) && (src2.shift_imm_ <= 32));
1834 DCHECK(src2.shift_op() == ASR);
1835 int asr = (src2.shift_imm_ == 32) ? 0 : src2.shift_imm_;
1836 emit(cond | 0x68*B20 | src1.code()*B16 | dst.code()*B12 |
1837 asr*B7 | B6 | B4 | src2.rm().code());
1838}
1839
1840
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001841void Assembler::sxtb(Register dst, Register src, int rotate, Condition cond) {
1842 // Instruction details available in ARM DDI 0406C.b, A8.8.233.
1843 // cond(31-28) | 01101010(27-20) | 1111(19-16) |
1844 // Rd(15-12) | rotate(11-10) | 00(9-8)| 0111(7-4) | Rm(3-0)
1845 DCHECK(!dst.is(pc));
1846 DCHECK(!src.is(pc));
1847 DCHECK(rotate == 0 || rotate == 8 || rotate == 16 || rotate == 24);
1848 emit(cond | 0x6A * B20 | 0xF * B16 | dst.code() * B12 |
1849 ((rotate >> 1) & 0xC) * B8 | 7 * B4 | src.code());
1850}
1851
1852
1853void Assembler::sxtab(Register dst, Register src1, Register src2, int rotate,
1854 Condition cond) {
1855 // Instruction details available in ARM DDI 0406C.b, A8.8.233.
1856 // cond(31-28) | 01101010(27-20) | Rn(19-16) |
1857 // Rd(15-12) | rotate(11-10) | 00(9-8)| 0111(7-4) | Rm(3-0)
1858 DCHECK(!dst.is(pc));
1859 DCHECK(!src1.is(pc));
1860 DCHECK(!src2.is(pc));
1861 DCHECK(rotate == 0 || rotate == 8 || rotate == 16 || rotate == 24);
1862 emit(cond | 0x6A * B20 | src1.code() * B16 | dst.code() * B12 |
1863 ((rotate >> 1) & 0xC) * B8 | 7 * B4 | src2.code());
1864}
1865
1866
1867void Assembler::sxth(Register dst, Register src, int rotate, Condition cond) {
1868 // Instruction details available in ARM DDI 0406C.b, A8.8.235.
1869 // cond(31-28) | 01101011(27-20) | 1111(19-16) |
1870 // Rd(15-12) | rotate(11-10) | 00(9-8)| 0111(7-4) | Rm(3-0)
1871 DCHECK(!dst.is(pc));
1872 DCHECK(!src.is(pc));
1873 DCHECK(rotate == 0 || rotate == 8 || rotate == 16 || rotate == 24);
1874 emit(cond | 0x6B * B20 | 0xF * B16 | dst.code() * B12 |
1875 ((rotate >> 1) & 0xC) * B8 | 7 * B4 | src.code());
1876}
1877
1878
1879void Assembler::sxtah(Register dst, Register src1, Register src2, int rotate,
1880 Condition cond) {
1881 // Instruction details available in ARM DDI 0406C.b, A8.8.235.
1882 // cond(31-28) | 01101011(27-20) | Rn(19-16) |
1883 // Rd(15-12) | rotate(11-10) | 00(9-8)| 0111(7-4) | Rm(3-0)
1884 DCHECK(!dst.is(pc));
1885 DCHECK(!src1.is(pc));
1886 DCHECK(!src2.is(pc));
1887 DCHECK(rotate == 0 || rotate == 8 || rotate == 16 || rotate == 24);
1888 emit(cond | 0x6B * B20 | src1.code() * B16 | dst.code() * B12 |
1889 ((rotate >> 1) & 0xC) * B8 | 7 * B4 | src2.code());
1890}
1891
1892
1893void Assembler::uxtb(Register dst, Register src, int rotate, Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001894 // Instruction details available in ARM DDI 0406C.b, A8.8.274.
1895 // cond(31-28) | 01101110(27-20) | 1111(19-16) |
1896 // Rd(15-12) | rotate(11-10) | 00(9-8)| 0111(7-4) | Rm(3-0)
1897 DCHECK(!dst.is(pc));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001898 DCHECK(!src.is(pc));
1899 DCHECK(rotate == 0 || rotate == 8 || rotate == 16 || rotate == 24);
1900 emit(cond | 0x6E * B20 | 0xF * B16 | dst.code() * B12 |
1901 ((rotate >> 1) & 0xC) * B8 | 7 * B4 | src.code());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001902}
1903
1904
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001905void Assembler::uxtab(Register dst, Register src1, Register src2, int rotate,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001906 Condition cond) {
1907 // Instruction details available in ARM DDI 0406C.b, A8.8.271.
1908 // cond(31-28) | 01101110(27-20) | Rn(19-16) |
1909 // Rd(15-12) | rotate(11-10) | 00(9-8)| 0111(7-4) | Rm(3-0)
1910 DCHECK(!dst.is(pc));
1911 DCHECK(!src1.is(pc));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001912 DCHECK(!src2.is(pc));
1913 DCHECK(rotate == 0 || rotate == 8 || rotate == 16 || rotate == 24);
1914 emit(cond | 0x6E * B20 | src1.code() * B16 | dst.code() * B12 |
1915 ((rotate >> 1) & 0xC) * B8 | 7 * B4 | src2.code());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001916}
1917
1918
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001919void Assembler::uxtb16(Register dst, Register src, int rotate, Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001920 // Instruction details available in ARM DDI 0406C.b, A8.8.275.
1921 // cond(31-28) | 01101100(27-20) | 1111(19-16) |
1922 // Rd(15-12) | rotate(11-10) | 00(9-8)| 0111(7-4) | Rm(3-0)
1923 DCHECK(!dst.is(pc));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001924 DCHECK(!src.is(pc));
1925 DCHECK(rotate == 0 || rotate == 8 || rotate == 16 || rotate == 24);
1926 emit(cond | 0x6C * B20 | 0xF * B16 | dst.code() * B12 |
1927 ((rotate >> 1) & 0xC) * B8 | 7 * B4 | src.code());
1928}
1929
1930
1931void Assembler::uxth(Register dst, Register src, int rotate, Condition cond) {
1932 // Instruction details available in ARM DDI 0406C.b, A8.8.276.
1933 // cond(31-28) | 01101111(27-20) | 1111(19-16) |
1934 // Rd(15-12) | rotate(11-10) | 00(9-8)| 0111(7-4) | Rm(3-0)
1935 DCHECK(!dst.is(pc));
1936 DCHECK(!src.is(pc));
1937 DCHECK(rotate == 0 || rotate == 8 || rotate == 16 || rotate == 24);
1938 emit(cond | 0x6F * B20 | 0xF * B16 | dst.code() * B12 |
1939 ((rotate >> 1) & 0xC) * B8 | 7 * B4 | src.code());
1940}
1941
1942
1943void Assembler::uxtah(Register dst, Register src1, Register src2, int rotate,
1944 Condition cond) {
1945 // Instruction details available in ARM DDI 0406C.b, A8.8.273.
1946 // cond(31-28) | 01101111(27-20) | Rn(19-16) |
1947 // Rd(15-12) | rotate(11-10) | 00(9-8)| 0111(7-4) | Rm(3-0)
1948 DCHECK(!dst.is(pc));
1949 DCHECK(!src1.is(pc));
1950 DCHECK(!src2.is(pc));
1951 DCHECK(rotate == 0 || rotate == 8 || rotate == 16 || rotate == 24);
1952 emit(cond | 0x6F * B20 | src1.code() * B16 | dst.code() * B12 |
1953 ((rotate >> 1) & 0xC) * B8 | 7 * B4 | src2.code());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001954}
1955
1956
Ben Murdoch097c5b22016-05-18 11:27:45 +01001957void Assembler::rbit(Register dst, Register src, Condition cond) {
1958 // Instruction details available in ARM DDI 0406C.b, A8.8.144.
1959 // cond(31-28) | 011011111111(27-16) | Rd(15-12) | 11110011(11-4) | Rm(3-0)
1960 DCHECK(IsEnabled(ARMv7));
1961 DCHECK(!dst.is(pc));
1962 DCHECK(!src.is(pc));
1963 emit(cond | 0x6FF * B16 | dst.code() * B12 | 0xF3 * B4 | src.code());
1964}
1965
1966
Andrei Popescu31002712010-02-23 13:46:05 +00001967// Status register access instructions.
Steve Blocka7e24c12009-10-30 11:49:00 +00001968void Assembler::mrs(Register dst, SRegister s, Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001969 DCHECK(!dst.is(pc));
Steve Blocka7e24c12009-10-30 11:49:00 +00001970 emit(cond | B24 | s | 15*B16 | dst.code()*B12);
1971}
1972
1973
1974void Assembler::msr(SRegisterFieldMask fields, const Operand& src,
1975 Condition cond) {
Ben Murdochda12d292016-06-02 14:46:10 +01001976 DCHECK((fields & 0x000f0000) != 0); // At least one field must be set.
1977 DCHECK(((fields & 0xfff0ffff) == CPSR) || ((fields & 0xfff0ffff) == SPSR));
Steve Blocka7e24c12009-10-30 11:49:00 +00001978 Instr instr;
1979 if (!src.rm_.is_valid()) {
Andrei Popescu31002712010-02-23 13:46:05 +00001980 // Immediate.
Steve Blocka7e24c12009-10-30 11:49:00 +00001981 uint32_t rotate_imm;
1982 uint32_t immed_8;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001983 if (src.must_output_reloc_info(this) ||
Steve Blocka7e24c12009-10-30 11:49:00 +00001984 !fits_shifter(src.imm32_, &rotate_imm, &immed_8, NULL)) {
Andrei Popescu31002712010-02-23 13:46:05 +00001985 // Immediate operand cannot be encoded, load it first to register ip.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001986 move_32_bit_immediate(ip, src);
Steve Blocka7e24c12009-10-30 11:49:00 +00001987 msr(fields, Operand(ip), cond);
1988 return;
1989 }
1990 instr = I | rotate_imm*B8 | immed_8;
1991 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001992 DCHECK(!src.rs_.is_valid() && src.shift_imm_ == 0); // only rm allowed
Steve Blocka7e24c12009-10-30 11:49:00 +00001993 instr = src.rm_.code();
1994 }
1995 emit(cond | instr | B24 | B21 | fields | 15*B12);
1996}
1997
1998
Andrei Popescu31002712010-02-23 13:46:05 +00001999// Load/Store instructions.
Steve Blocka7e24c12009-10-30 11:49:00 +00002000void Assembler::ldr(Register dst, const MemOperand& src, Condition cond) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002001 addrmod2(cond | B26 | L, dst, src);
Steve Blocka7e24c12009-10-30 11:49:00 +00002002}
2003
2004
2005void Assembler::str(Register src, const MemOperand& dst, Condition cond) {
2006 addrmod2(cond | B26, src, dst);
Steve Blocka7e24c12009-10-30 11:49:00 +00002007}
2008
2009
2010void Assembler::ldrb(Register dst, const MemOperand& src, Condition cond) {
2011 addrmod2(cond | B26 | B | L, dst, src);
2012}
2013
2014
2015void Assembler::strb(Register src, const MemOperand& dst, Condition cond) {
2016 addrmod2(cond | B26 | B, src, dst);
2017}
2018
2019
2020void Assembler::ldrh(Register dst, const MemOperand& src, Condition cond) {
2021 addrmod3(cond | L | B7 | H | B4, dst, src);
2022}
2023
2024
2025void Assembler::strh(Register src, const MemOperand& dst, Condition cond) {
2026 addrmod3(cond | B7 | H | B4, src, dst);
2027}
2028
2029
2030void Assembler::ldrsb(Register dst, const MemOperand& src, Condition cond) {
2031 addrmod3(cond | L | B7 | S6 | B4, dst, src);
2032}
2033
2034
2035void Assembler::ldrsh(Register dst, const MemOperand& src, Condition cond) {
2036 addrmod3(cond | L | B7 | S6 | H | B4, dst, src);
2037}
2038
2039
Leon Clarkef7060e22010-06-03 12:02:55 +01002040void Assembler::ldrd(Register dst1, Register dst2,
2041 const MemOperand& src, Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002042 DCHECK(src.rm().is(no_reg));
2043 DCHECK(!dst1.is(lr)); // r14.
2044 DCHECK_EQ(0, dst1.code() % 2);
2045 DCHECK_EQ(dst1.code() + 1, dst2.code());
Leon Clarkef7060e22010-06-03 12:02:55 +01002046 addrmod3(cond | B7 | B6 | B4, dst1, src);
Kristian Monsen25f61362010-05-21 11:50:48 +01002047}
2048
2049
Leon Clarkef7060e22010-06-03 12:02:55 +01002050void Assembler::strd(Register src1, Register src2,
2051 const MemOperand& dst, Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002052 DCHECK(dst.rm().is(no_reg));
2053 DCHECK(!src1.is(lr)); // r14.
2054 DCHECK_EQ(0, src1.code() % 2);
2055 DCHECK_EQ(src1.code() + 1, src2.code());
Leon Clarkef7060e22010-06-03 12:02:55 +01002056 addrmod3(cond | B7 | B6 | B5 | B4, src1, dst);
Kristian Monsen25f61362010-05-21 11:50:48 +01002057}
2058
Ben Murdoch61f157c2016-09-16 13:49:30 +01002059// Load/Store exclusive instructions.
2060void Assembler::ldrex(Register dst, Register src, Condition cond) {
2061 // Instruction details available in ARM DDI 0406C.b, A8.8.75.
2062 // cond(31-28) | 00011001(27-20) | Rn(19-16) | Rt(15-12) | 111110011111(11-0)
2063 emit(cond | B24 | B23 | B20 | src.code() * B16 | dst.code() * B12 | 0xf9f);
2064}
2065
2066void Assembler::strex(Register src1, Register src2, Register dst,
2067 Condition cond) {
2068 // Instruction details available in ARM DDI 0406C.b, A8.8.212.
2069 // cond(31-28) | 00011000(27-20) | Rn(19-16) | Rd(15-12) | 11111001(11-4) |
2070 // Rt(3-0)
2071 emit(cond | B24 | B23 | dst.code() * B16 | src1.code() * B12 | 0xf9 * B4 |
2072 src2.code());
2073}
2074
2075void Assembler::ldrexb(Register dst, Register src, Condition cond) {
2076 // Instruction details available in ARM DDI 0406C.b, A8.8.76.
2077 // cond(31-28) | 00011101(27-20) | Rn(19-16) | Rt(15-12) | 111110011111(11-0)
2078 emit(cond | B24 | B23 | B22 | B20 | src.code() * B16 | dst.code() * B12 |
2079 0xf9f);
2080}
2081
2082void Assembler::strexb(Register src1, Register src2, Register dst,
2083 Condition cond) {
2084 // Instruction details available in ARM DDI 0406C.b, A8.8.213.
2085 // cond(31-28) | 00011100(27-20) | Rn(19-16) | Rd(15-12) | 11111001(11-4) |
2086 // Rt(3-0)
2087 emit(cond | B24 | B23 | B22 | dst.code() * B16 | src1.code() * B12 |
2088 0xf9 * B4 | src2.code());
2089}
2090
2091void Assembler::ldrexh(Register dst, Register src, Condition cond) {
2092 // Instruction details available in ARM DDI 0406C.b, A8.8.78.
2093 // cond(31-28) | 00011111(27-20) | Rn(19-16) | Rt(15-12) | 111110011111(11-0)
2094 emit(cond | B24 | B23 | B22 | B21 | B20 | src.code() * B16 |
2095 dst.code() * B12 | 0xf9f);
2096}
2097
2098void Assembler::strexh(Register src1, Register src2, Register dst,
2099 Condition cond) {
2100 // Instruction details available in ARM DDI 0406C.b, A8.8.215.
2101 // cond(31-28) | 00011110(27-20) | Rn(19-16) | Rd(15-12) | 11111001(11-4) |
2102 // Rt(3-0)
2103 emit(cond | B24 | B23 | B22 | B21 | dst.code() * B16 | src1.code() * B12 |
2104 0xf9 * B4 | src2.code());
2105}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002106
2107// Preload instructions.
2108void Assembler::pld(const MemOperand& address) {
2109 // Instruction details available in ARM DDI 0406C.b, A8.8.128.
2110 // 1111(31-28) | 0111(27-24) | U(23) | R(22) | 01(21-20) | Rn(19-16) |
2111 // 1111(15-12) | imm5(11-07) | type(6-5) | 0(4)| Rm(3-0) |
2112 DCHECK(address.rm().is(no_reg));
2113 DCHECK(address.am() == Offset);
2114 int U = B23;
2115 int offset = address.offset();
2116 if (offset < 0) {
2117 offset = -offset;
2118 U = 0;
2119 }
2120 DCHECK(offset < 4096);
2121 emit(kSpecialCondition | B26 | B24 | U | B22 | B20 | address.rn().code()*B16 |
2122 0xf*B12 | offset);
2123}
2124
2125
Andrei Popescu31002712010-02-23 13:46:05 +00002126// Load/Store multiple instructions.
Steve Blocka7e24c12009-10-30 11:49:00 +00002127void Assembler::ldm(BlockAddrMode am,
2128 Register base,
2129 RegList dst,
2130 Condition cond) {
Andrei Popescu31002712010-02-23 13:46:05 +00002131 // ABI stack constraint: ldmxx base, {..sp..} base != sp is not restartable.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002132 DCHECK(base.is(sp) || (dst & sp.bit()) == 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00002133
2134 addrmod4(cond | B27 | am | L, base, dst);
2135
Andrei Popescu31002712010-02-23 13:46:05 +00002136 // Emit the constant pool after a function return implemented by ldm ..{..pc}.
Steve Blocka7e24c12009-10-30 11:49:00 +00002137 if (cond == al && (dst & pc.bit()) != 0) {
2138 // There is a slight chance that the ldm instruction was actually a call,
2139 // in which case it would be wrong to return into the constant pool; we
2140 // recognize this case by checking if the emission of the pool was blocked
2141 // at the pc of the ldm instruction by a mov lr, pc instruction; if this is
2142 // the case, we emit a jump over the pool.
2143 CheckConstPool(true, no_const_pool_before_ == pc_offset() - kInstrSize);
2144 }
2145}
2146
2147
2148void Assembler::stm(BlockAddrMode am,
2149 Register base,
2150 RegList src,
2151 Condition cond) {
2152 addrmod4(cond | B27 | am, base, src);
2153}
2154
2155
Andrei Popescu31002712010-02-23 13:46:05 +00002156// Exception-generating instructions and debugging support.
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002157// Stops with a non-negative code less than kNumOfWatchedStops support
2158// enabling/disabling and a counter feature. See simulator-arm.h .
2159void Assembler::stop(const char* msg, Condition cond, int32_t code) {
Andrei Popescu402d9372010-02-26 13:31:12 +00002160#ifndef __arm__
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002161 DCHECK(code >= kDefaultStopCode);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002162 {
2163 // The Simulator will handle the stop instruction and get the message
2164 // address. It expects to find the address just after the svc instruction.
2165 BlockConstPoolScope block_const_pool(this);
2166 if (code >= 0) {
2167 svc(kStopCode + code, cond);
2168 } else {
2169 svc(kStopCode + kMaxStopCode, cond);
2170 }
2171 emit(reinterpret_cast<Instr>(msg));
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002172 }
Andrei Popescu402d9372010-02-26 13:31:12 +00002173#else // def __arm__
Steve Block1e0659c2011-05-24 12:43:12 +01002174 if (cond != al) {
2175 Label skip;
2176 b(&skip, NegateCondition(cond));
2177 bkpt(0);
2178 bind(&skip);
2179 } else {
2180 bkpt(0);
2181 }
Andrei Popescu402d9372010-02-26 13:31:12 +00002182#endif // def __arm__
Steve Blocka7e24c12009-10-30 11:49:00 +00002183}
2184
2185
2186void Assembler::bkpt(uint32_t imm16) { // v5 and above
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002187 DCHECK(is_uint16(imm16));
Steve Block1e0659c2011-05-24 12:43:12 +01002188 emit(al | B24 | B21 | (imm16 >> 4)*B8 | BKPT | (imm16 & 0xf));
Steve Blocka7e24c12009-10-30 11:49:00 +00002189}
2190
2191
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08002192void Assembler::svc(uint32_t imm24, Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002193 DCHECK(is_uint24(imm24));
Steve Blocka7e24c12009-10-30 11:49:00 +00002194 emit(cond | 15*B24 | imm24);
2195}
2196
2197
Ben Murdoch097c5b22016-05-18 11:27:45 +01002198void Assembler::dmb(BarrierOption option) {
2199 emit(kSpecialCondition | 0x57ff*B12 | 5*B4 | option);
2200}
2201
2202
2203void Assembler::dsb(BarrierOption option) {
2204 emit(kSpecialCondition | 0x57ff*B12 | 4*B4 | option);
2205}
2206
2207
2208void Assembler::isb(BarrierOption option) {
2209 emit(kSpecialCondition | 0x57ff*B12 | 6*B4 | option);
2210}
2211
2212
Andrei Popescu31002712010-02-23 13:46:05 +00002213// Coprocessor instructions.
Steve Blocka7e24c12009-10-30 11:49:00 +00002214void Assembler::cdp(Coprocessor coproc,
2215 int opcode_1,
2216 CRegister crd,
2217 CRegister crn,
2218 CRegister crm,
2219 int opcode_2,
2220 Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002221 DCHECK(is_uint4(opcode_1) && is_uint3(opcode_2));
Steve Blocka7e24c12009-10-30 11:49:00 +00002222 emit(cond | B27 | B26 | B25 | (opcode_1 & 15)*B20 | crn.code()*B16 |
2223 crd.code()*B12 | coproc*B8 | (opcode_2 & 7)*B5 | crm.code());
2224}
2225
2226
2227void Assembler::cdp2(Coprocessor coproc,
2228 int opcode_1,
2229 CRegister crd,
2230 CRegister crn,
2231 CRegister crm,
2232 int opcode_2) { // v5 and above
Steve Block1e0659c2011-05-24 12:43:12 +01002233 cdp(coproc, opcode_1, crd, crn, crm, opcode_2, kSpecialCondition);
Steve Blocka7e24c12009-10-30 11:49:00 +00002234}
2235
2236
2237void Assembler::mcr(Coprocessor coproc,
2238 int opcode_1,
2239 Register rd,
2240 CRegister crn,
2241 CRegister crm,
2242 int opcode_2,
2243 Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002244 DCHECK(is_uint3(opcode_1) && is_uint3(opcode_2));
Steve Blocka7e24c12009-10-30 11:49:00 +00002245 emit(cond | B27 | B26 | B25 | (opcode_1 & 7)*B21 | crn.code()*B16 |
2246 rd.code()*B12 | coproc*B8 | (opcode_2 & 7)*B5 | B4 | crm.code());
2247}
2248
2249
2250void Assembler::mcr2(Coprocessor coproc,
2251 int opcode_1,
2252 Register rd,
2253 CRegister crn,
2254 CRegister crm,
2255 int opcode_2) { // v5 and above
Steve Block1e0659c2011-05-24 12:43:12 +01002256 mcr(coproc, opcode_1, rd, crn, crm, opcode_2, kSpecialCondition);
Steve Blocka7e24c12009-10-30 11:49:00 +00002257}
2258
2259
2260void Assembler::mrc(Coprocessor coproc,
2261 int opcode_1,
2262 Register rd,
2263 CRegister crn,
2264 CRegister crm,
2265 int opcode_2,
2266 Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002267 DCHECK(is_uint3(opcode_1) && is_uint3(opcode_2));
Steve Blocka7e24c12009-10-30 11:49:00 +00002268 emit(cond | B27 | B26 | B25 | (opcode_1 & 7)*B21 | L | crn.code()*B16 |
2269 rd.code()*B12 | coproc*B8 | (opcode_2 & 7)*B5 | B4 | crm.code());
2270}
2271
2272
2273void Assembler::mrc2(Coprocessor coproc,
2274 int opcode_1,
2275 Register rd,
2276 CRegister crn,
2277 CRegister crm,
2278 int opcode_2) { // v5 and above
Steve Block1e0659c2011-05-24 12:43:12 +01002279 mrc(coproc, opcode_1, rd, crn, crm, opcode_2, kSpecialCondition);
Steve Blocka7e24c12009-10-30 11:49:00 +00002280}
2281
2282
2283void Assembler::ldc(Coprocessor coproc,
2284 CRegister crd,
2285 const MemOperand& src,
2286 LFlag l,
2287 Condition cond) {
2288 addrmod5(cond | B27 | B26 | l | L | coproc*B8, crd, src);
2289}
2290
2291
2292void Assembler::ldc(Coprocessor coproc,
2293 CRegister crd,
2294 Register rn,
2295 int option,
2296 LFlag l,
2297 Condition cond) {
Andrei Popescu31002712010-02-23 13:46:05 +00002298 // Unindexed addressing.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002299 DCHECK(is_uint8(option));
Steve Blocka7e24c12009-10-30 11:49:00 +00002300 emit(cond | B27 | B26 | U | l | L | rn.code()*B16 | crd.code()*B12 |
2301 coproc*B8 | (option & 255));
2302}
2303
2304
2305void Assembler::ldc2(Coprocessor coproc,
2306 CRegister crd,
2307 const MemOperand& src,
2308 LFlag l) { // v5 and above
Steve Block1e0659c2011-05-24 12:43:12 +01002309 ldc(coproc, crd, src, l, kSpecialCondition);
Steve Blocka7e24c12009-10-30 11:49:00 +00002310}
2311
2312
2313void Assembler::ldc2(Coprocessor coproc,
2314 CRegister crd,
2315 Register rn,
2316 int option,
2317 LFlag l) { // v5 and above
Steve Block1e0659c2011-05-24 12:43:12 +01002318 ldc(coproc, crd, rn, option, l, kSpecialCondition);
Steve Blocka7e24c12009-10-30 11:49:00 +00002319}
2320
2321
Steve Blockd0582a62009-12-15 09:54:21 +00002322// Support for VFP.
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002323
Leon Clarked91b9f72010-01-27 17:25:45 +00002324void Assembler::vldr(const DwVfpRegister dst,
2325 const Register base,
2326 int offset,
2327 const Condition cond) {
2328 // Ddst = MEM(Rbase + offset).
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002329 // Instruction details available in ARM DDI 0406C.b, A8-924.
2330 // cond(31-28) | 1101(27-24)| U(23) | D(22) | 01(21-20) | Rbase(19-16) |
2331 // Vd(15-12) | 1011(11-8) | offset
Ben Murdochb0fe1622011-05-05 13:52:32 +01002332 int u = 1;
2333 if (offset < 0) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002334 CHECK(offset != kMinInt);
Ben Murdochb0fe1622011-05-05 13:52:32 +01002335 offset = -offset;
2336 u = 0;
2337 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002338 int vd, d;
2339 dst.split_code(&vd, &d);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002340
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002341 DCHECK(offset >= 0);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002342 if ((offset % 4) == 0 && (offset / 4) < 256) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002343 emit(cond | 0xD*B24 | u*B23 | d*B22 | B20 | base.code()*B16 | vd*B12 |
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002344 0xB*B8 | ((offset / 4) & 255));
2345 } else {
2346 // Larger offsets must be handled by computing the correct address
2347 // in the ip register.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002348 DCHECK(!base.is(ip));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002349 if (u == 1) {
2350 add(ip, base, Operand(offset));
2351 } else {
2352 sub(ip, base, Operand(offset));
2353 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002354 emit(cond | 0xD*B24 | d*B22 | B20 | ip.code()*B16 | vd*B12 | 0xB*B8);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002355 }
2356}
2357
2358
2359void Assembler::vldr(const DwVfpRegister dst,
2360 const MemOperand& operand,
2361 const Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002362 DCHECK(operand.am_ == Offset);
2363 if (operand.rm().is_valid()) {
2364 add(ip, operand.rn(),
2365 Operand(operand.rm(), operand.shift_op_, operand.shift_imm_));
2366 vldr(dst, ip, 0, cond);
2367 } else {
2368 vldr(dst, operand.rn(), operand.offset(), cond);
2369 }
Leon Clarked91b9f72010-01-27 17:25:45 +00002370}
2371
2372
Steve Block6ded16b2010-05-10 14:33:55 +01002373void Assembler::vldr(const SwVfpRegister dst,
2374 const Register base,
2375 int offset,
2376 const Condition cond) {
2377 // Sdst = MEM(Rbase + offset).
2378 // Instruction details available in ARM DDI 0406A, A8-628.
Ben Murdochb0fe1622011-05-05 13:52:32 +01002379 // cond(31-28) | 1101(27-24)| U001(23-20) | Rbase(19-16) |
Steve Block6ded16b2010-05-10 14:33:55 +01002380 // Vdst(15-12) | 1010(11-8) | offset
Ben Murdochb0fe1622011-05-05 13:52:32 +01002381 int u = 1;
2382 if (offset < 0) {
2383 offset = -offset;
2384 u = 0;
2385 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002386 int sd, d;
2387 dst.split_code(&sd, &d);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002388 DCHECK(offset >= 0);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002389
2390 if ((offset % 4) == 0 && (offset / 4) < 256) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01002391 emit(cond | u*B23 | d*B22 | 0xD1*B20 | base.code()*B16 | sd*B12 |
Steve Block6ded16b2010-05-10 14:33:55 +01002392 0xA*B8 | ((offset / 4) & 255));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002393 } else {
2394 // Larger offsets must be handled by computing the correct address
2395 // in the ip register.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002396 DCHECK(!base.is(ip));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002397 if (u == 1) {
2398 add(ip, base, Operand(offset));
2399 } else {
2400 sub(ip, base, Operand(offset));
2401 }
2402 emit(cond | d*B22 | 0xD1*B20 | ip.code()*B16 | sd*B12 | 0xA*B8);
2403 }
2404}
2405
2406
2407void Assembler::vldr(const SwVfpRegister dst,
2408 const MemOperand& operand,
2409 const Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002410 DCHECK(operand.am_ == Offset);
2411 if (operand.rm().is_valid()) {
2412 add(ip, operand.rn(),
2413 Operand(operand.rm(), operand.shift_op_, operand.shift_imm_));
2414 vldr(dst, ip, 0, cond);
2415 } else {
2416 vldr(dst, operand.rn(), operand.offset(), cond);
2417 }
Steve Block6ded16b2010-05-10 14:33:55 +01002418}
2419
2420
Leon Clarked91b9f72010-01-27 17:25:45 +00002421void Assembler::vstr(const DwVfpRegister src,
2422 const Register base,
2423 int offset,
2424 const Condition cond) {
2425 // MEM(Rbase + offset) = Dsrc.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002426 // Instruction details available in ARM DDI 0406C.b, A8-1082.
2427 // cond(31-28) | 1101(27-24)| U(23) | D(22) | 00(21-20) | Rbase(19-16) |
2428 // Vd(15-12) | 1011(11-8) | (offset/4)
Ben Murdochb0fe1622011-05-05 13:52:32 +01002429 int u = 1;
2430 if (offset < 0) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002431 CHECK(offset != kMinInt);
Ben Murdochb0fe1622011-05-05 13:52:32 +01002432 offset = -offset;
2433 u = 0;
2434 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002435 DCHECK(offset >= 0);
2436 int vd, d;
2437 src.split_code(&vd, &d);
2438
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002439 if ((offset % 4) == 0 && (offset / 4) < 256) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002440 emit(cond | 0xD*B24 | u*B23 | d*B22 | base.code()*B16 | vd*B12 | 0xB*B8 |
2441 ((offset / 4) & 255));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002442 } else {
2443 // Larger offsets must be handled by computing the correct address
2444 // in the ip register.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002445 DCHECK(!base.is(ip));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002446 if (u == 1) {
2447 add(ip, base, Operand(offset));
2448 } else {
2449 sub(ip, base, Operand(offset));
2450 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002451 emit(cond | 0xD*B24 | d*B22 | ip.code()*B16 | vd*B12 | 0xB*B8);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002452 }
2453}
2454
2455
2456void Assembler::vstr(const DwVfpRegister src,
2457 const MemOperand& operand,
2458 const Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002459 DCHECK(operand.am_ == Offset);
2460 if (operand.rm().is_valid()) {
2461 add(ip, operand.rn(),
2462 Operand(operand.rm(), operand.shift_op_, operand.shift_imm_));
2463 vstr(src, ip, 0, cond);
2464 } else {
2465 vstr(src, operand.rn(), operand.offset(), cond);
2466 }
Leon Clarked91b9f72010-01-27 17:25:45 +00002467}
2468
2469
Iain Merrick75681382010-08-19 15:07:18 +01002470void Assembler::vstr(const SwVfpRegister src,
2471 const Register base,
2472 int offset,
2473 const Condition cond) {
2474 // MEM(Rbase + offset) = SSrc.
2475 // Instruction details available in ARM DDI 0406A, A8-786.
Ben Murdochb0fe1622011-05-05 13:52:32 +01002476 // cond(31-28) | 1101(27-24)| U000(23-20) | Rbase(19-16) |
Iain Merrick75681382010-08-19 15:07:18 +01002477 // Vdst(15-12) | 1010(11-8) | (offset/4)
Ben Murdochb0fe1622011-05-05 13:52:32 +01002478 int u = 1;
2479 if (offset < 0) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002480 CHECK(offset != kMinInt);
Ben Murdochb0fe1622011-05-05 13:52:32 +01002481 offset = -offset;
2482 u = 0;
2483 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002484 int sd, d;
2485 src.split_code(&sd, &d);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002486 DCHECK(offset >= 0);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002487 if ((offset % 4) == 0 && (offset / 4) < 256) {
2488 emit(cond | u*B23 | d*B22 | 0xD0*B20 | base.code()*B16 | sd*B12 |
2489 0xA*B8 | ((offset / 4) & 255));
2490 } else {
2491 // Larger offsets must be handled by computing the correct address
2492 // in the ip register.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002493 DCHECK(!base.is(ip));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002494 if (u == 1) {
2495 add(ip, base, Operand(offset));
2496 } else {
2497 sub(ip, base, Operand(offset));
2498 }
2499 emit(cond | d*B22 | 0xD0*B20 | ip.code()*B16 | sd*B12 | 0xA*B8);
2500 }
2501}
2502
2503
2504void Assembler::vstr(const SwVfpRegister src,
2505 const MemOperand& operand,
2506 const Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002507 DCHECK(operand.am_ == Offset);
2508 if (operand.rm().is_valid()) {
2509 add(ip, operand.rn(),
2510 Operand(operand.rm(), operand.shift_op_, operand.shift_imm_));
2511 vstr(src, ip, 0, cond);
2512 } else {
2513 vstr(src, operand.rn(), operand.offset(), cond);
2514 }
Iain Merrick75681382010-08-19 15:07:18 +01002515}
2516
2517
Ben Murdoch8b112d22011-06-08 16:22:53 +01002518void Assembler::vldm(BlockAddrMode am,
2519 Register base,
2520 DwVfpRegister first,
2521 DwVfpRegister last,
2522 Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002523 // Instruction details available in ARM DDI 0406C.b, A8-922.
Ben Murdoch8b112d22011-06-08 16:22:53 +01002524 // cond(31-28) | 110(27-25)| PUDW1(24-20) | Rbase(19-16) |
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002525 // first(15-12) | 1011(11-8) | (count * 2)
2526 DCHECK_LE(first.code(), last.code());
2527 DCHECK(am == ia || am == ia_w || am == db_w);
2528 DCHECK(!base.is(pc));
Ben Murdoch8b112d22011-06-08 16:22:53 +01002529
2530 int sd, d;
2531 first.split_code(&sd, &d);
2532 int count = last.code() - first.code() + 1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002533 DCHECK(count <= 16);
Ben Murdoch8b112d22011-06-08 16:22:53 +01002534 emit(cond | B27 | B26 | am | d*B22 | B20 | base.code()*B16 | sd*B12 |
2535 0xB*B8 | count*2);
2536}
2537
2538
2539void Assembler::vstm(BlockAddrMode am,
2540 Register base,
2541 DwVfpRegister first,
2542 DwVfpRegister last,
2543 Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002544 // Instruction details available in ARM DDI 0406C.b, A8-1080.
Ben Murdoch8b112d22011-06-08 16:22:53 +01002545 // cond(31-28) | 110(27-25)| PUDW0(24-20) | Rbase(19-16) |
2546 // first(15-12) | 1011(11-8) | (count * 2)
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002547 DCHECK_LE(first.code(), last.code());
2548 DCHECK(am == ia || am == ia_w || am == db_w);
2549 DCHECK(!base.is(pc));
Ben Murdoch8b112d22011-06-08 16:22:53 +01002550
2551 int sd, d;
2552 first.split_code(&sd, &d);
2553 int count = last.code() - first.code() + 1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002554 DCHECK(count <= 16);
Ben Murdoch8b112d22011-06-08 16:22:53 +01002555 emit(cond | B27 | B26 | am | d*B22 | base.code()*B16 | sd*B12 |
2556 0xB*B8 | count*2);
2557}
2558
2559void Assembler::vldm(BlockAddrMode am,
2560 Register base,
2561 SwVfpRegister first,
2562 SwVfpRegister last,
2563 Condition cond) {
2564 // Instruction details available in ARM DDI 0406A, A8-626.
2565 // cond(31-28) | 110(27-25)| PUDW1(24-20) | Rbase(19-16) |
2566 // first(15-12) | 1010(11-8) | (count/2)
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002567 DCHECK_LE(first.code(), last.code());
2568 DCHECK(am == ia || am == ia_w || am == db_w);
2569 DCHECK(!base.is(pc));
Ben Murdoch8b112d22011-06-08 16:22:53 +01002570
2571 int sd, d;
2572 first.split_code(&sd, &d);
2573 int count = last.code() - first.code() + 1;
2574 emit(cond | B27 | B26 | am | d*B22 | B20 | base.code()*B16 | sd*B12 |
2575 0xA*B8 | count);
2576}
2577
2578
2579void Assembler::vstm(BlockAddrMode am,
2580 Register base,
2581 SwVfpRegister first,
2582 SwVfpRegister last,
2583 Condition cond) {
2584 // Instruction details available in ARM DDI 0406A, A8-784.
2585 // cond(31-28) | 110(27-25)| PUDW0(24-20) | Rbase(19-16) |
2586 // first(15-12) | 1011(11-8) | (count/2)
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002587 DCHECK_LE(first.code(), last.code());
2588 DCHECK(am == ia || am == ia_w || am == db_w);
2589 DCHECK(!base.is(pc));
Ben Murdoch8b112d22011-06-08 16:22:53 +01002590
2591 int sd, d;
2592 first.split_code(&sd, &d);
2593 int count = last.code() - first.code() + 1;
2594 emit(cond | B27 | B26 | am | d*B22 | base.code()*B16 | sd*B12 |
2595 0xA*B8 | count);
2596}
2597
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002598
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002599static void DoubleAsTwoUInt32(double d, uint32_t* lo, uint32_t* hi) {
2600 uint64_t i;
2601 memcpy(&i, &d, 8);
2602
2603 *lo = i & 0xffffffff;
2604 *hi = i >> 32;
2605}
2606
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002607
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002608// Only works for little endian floating point formats.
2609// We don't support VFP on the mixed endian floating point platform.
Ben Murdochda12d292016-06-02 14:46:10 +01002610static bool FitsVmovFPImmediate(double d, uint32_t* encoding) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002611 DCHECK(CpuFeatures::IsSupported(VFP3));
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002612
2613 // VMOV can accept an immediate of the form:
2614 //
2615 // +/- m * 2^(-n) where 16 <= m <= 31 and 0 <= n <= 7
2616 //
2617 // The immediate is encoded using an 8-bit quantity, comprised of two
2618 // 4-bit fields. For an 8-bit immediate of the form:
2619 //
2620 // [abcdefgh]
2621 //
2622 // where a is the MSB and h is the LSB, an immediate 64-bit double can be
2623 // created of the form:
2624 //
2625 // [aBbbbbbb,bbcdefgh,00000000,00000000,
2626 // 00000000,00000000,00000000,00000000]
2627 //
2628 // where B = ~b.
2629 //
2630
2631 uint32_t lo, hi;
2632 DoubleAsTwoUInt32(d, &lo, &hi);
2633
2634 // The most obvious constraint is the long block of zeroes.
2635 if ((lo != 0) || ((hi & 0xffff) != 0)) {
2636 return false;
2637 }
2638
Ben Murdochda12d292016-06-02 14:46:10 +01002639 // Bits 61:54 must be all clear or all set.
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002640 if (((hi & 0x3fc00000) != 0) && ((hi & 0x3fc00000) != 0x3fc00000)) {
2641 return false;
2642 }
2643
Ben Murdochda12d292016-06-02 14:46:10 +01002644 // Bit 62 must be NOT bit 61.
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002645 if (((hi ^ (hi << 1)) & (0x40000000)) == 0) {
2646 return false;
2647 }
2648
2649 // Create the encoded immediate in the form:
2650 // [00000000,0000abcd,00000000,0000efgh]
2651 *encoding = (hi >> 16) & 0xf; // Low nybble.
2652 *encoding |= (hi >> 4) & 0x70000; // Low three bits of the high nybble.
2653 *encoding |= (hi >> 12) & 0x80000; // Top bit of the high nybble.
2654
2655 return true;
2656}
2657
2658
Ben Murdochda12d292016-06-02 14:46:10 +01002659void Assembler::vmov(const SwVfpRegister dst, float imm) {
2660 uint32_t enc;
2661 if (CpuFeatures::IsSupported(VFP3) && FitsVmovFPImmediate(imm, &enc)) {
2662 // The float can be encoded in the instruction.
2663 //
2664 // Sd = immediate
2665 // Instruction details available in ARM DDI 0406C.b, A8-936.
2666 // cond(31-28) | 11101(27-23) | D(22) | 11(21-20) | imm4H(19-16) |
2667 // Vd(15-12) | 101(11-9) | sz=0(8) | imm4L(3-0)
2668 int vd, d;
2669 dst.split_code(&vd, &d);
2670 emit(al | 0x1D * B23 | d * B22 | 0x3 * B20 | vd * B12 | 0x5 * B9 | enc);
2671 } else {
2672 mov(ip, Operand(bit_cast<int32_t>(imm)));
2673 vmov(dst, ip);
2674 }
2675}
2676
2677
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002678void Assembler::vmov(const DwVfpRegister dst,
2679 double imm,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002680 const Register scratch) {
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002681 uint32_t enc;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002682 // If the embedded constant pool is disabled, we can use the normal, inline
2683 // constant pool. If the embedded constant pool is enabled (via
2684 // FLAG_enable_embedded_constant_pool), we can only use it where the pool
2685 // pointer (pp) is valid.
2686 bool can_use_pool =
2687 !FLAG_enable_embedded_constant_pool || is_constant_pool_available();
Ben Murdochda12d292016-06-02 14:46:10 +01002688 if (CpuFeatures::IsSupported(VFP3) && FitsVmovFPImmediate(imm, &enc)) {
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002689 // The double can be encoded in the instruction.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002690 //
2691 // Dd = immediate
2692 // Instruction details available in ARM DDI 0406C.b, A8-936.
2693 // cond(31-28) | 11101(27-23) | D(22) | 11(21-20) | imm4H(19-16) |
2694 // Vd(15-12) | 101(11-9) | sz=1(8) | imm4L(3-0)
2695 int vd, d;
2696 dst.split_code(&vd, &d);
2697 emit(al | 0x1D*B23 | d*B22 | 0x3*B20 | vd*B12 | 0x5*B9 | B8 | enc);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002698 } else if (FLAG_enable_vldr_imm && can_use_pool) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002699 // TODO(jfb) Temporarily turned off until we have constant blinding or
2700 // some equivalent mitigation: an attacker can otherwise control
2701 // generated data which also happens to be executable, a Very Bad
2702 // Thing indeed.
2703 // Blinding gets tricky because we don't have xor, we probably
2704 // need to add/subtract without losing precision, which requires a
2705 // cookie value that Lithium is probably better positioned to
2706 // choose.
2707 // We could also add a few peepholes here like detecting 0.0 and
2708 // -0.0 and doing a vmov from the sequestered d14, forcing denorms
2709 // to zero (we set flush-to-zero), and normalizing NaN values.
2710 // We could also detect redundant values.
2711 // The code could also randomize the order of values, though
2712 // that's tricky because vldr has a limited reach. Furthermore
2713 // it breaks load locality.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002714 ConstantPoolEntry::Access access = ConstantPoolAddEntry(pc_offset(), imm);
2715 if (access == ConstantPoolEntry::OVERFLOWED) {
2716 DCHECK(FLAG_enable_embedded_constant_pool);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002717 // Emit instructions to load constant pool offset.
2718 movw(ip, 0);
2719 movt(ip, 0);
2720 // Load from constant pool at offset.
2721 vldr(dst, MemOperand(pp, ip));
2722 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002723 DCHECK(access == ConstantPoolEntry::REGULAR);
2724 vldr(dst, MemOperand(FLAG_enable_embedded_constant_pool ? pp : pc, 0));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002725 }
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002726 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002727 // Synthesise the double from ARM immediates.
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002728 uint32_t lo, hi;
2729 DoubleAsTwoUInt32(imm, &lo, &hi);
2730
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002731 if (lo == hi) {
2732 // Move the low and high parts of the double to a D register in one
2733 // instruction.
2734 mov(ip, Operand(lo));
2735 vmov(dst, ip, ip);
2736 } else if (scratch.is(no_reg)) {
2737 mov(ip, Operand(lo));
2738 vmov(dst, VmovIndexLo, ip);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002739 if (((lo & 0xffff) == (hi & 0xffff)) &&
2740 CpuFeatures::IsSupported(ARMv7)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002741 movt(ip, hi >> 16);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002742 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002743 mov(ip, Operand(hi));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002744 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002745 vmov(dst, VmovIndexHi, ip);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002746 } else {
2747 // Move the low and high parts of the double to a D register in one
2748 // instruction.
2749 mov(ip, Operand(lo));
2750 mov(scratch, Operand(hi));
2751 vmov(dst, ip, scratch);
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002752 }
2753 }
2754}
2755
2756
2757void Assembler::vmov(const SwVfpRegister dst,
2758 const SwVfpRegister src,
2759 const Condition cond) {
2760 // Sd = Sm
2761 // Instruction details available in ARM DDI 0406B, A8-642.
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002762 int sd, d, sm, m;
2763 dst.split_code(&sd, &d);
2764 src.split_code(&sm, &m);
2765 emit(cond | 0xE*B24 | d*B22 | 0xB*B20 | sd*B12 | 0xA*B8 | B6 | m*B5 | sm);
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002766}
2767
2768
Leon Clarkee46be812010-01-19 14:06:41 +00002769void Assembler::vmov(const DwVfpRegister dst,
Steve Block8defd9f2010-07-08 12:39:36 +01002770 const DwVfpRegister src,
2771 const Condition cond) {
2772 // Dd = Dm
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002773 // Instruction details available in ARM DDI 0406C.b, A8-938.
2774 // cond(31-28) | 11101(27-23) | D(22) | 11(21-20) | 0000(19-16) | Vd(15-12) |
2775 // 101(11-9) | sz=1(8) | 0(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
2776 int vd, d;
2777 dst.split_code(&vd, &d);
2778 int vm, m;
2779 src.split_code(&vm, &m);
2780 emit(cond | 0x1D*B23 | d*B22 | 0x3*B20 | vd*B12 | 0x5*B9 | B8 | B6 | m*B5 |
2781 vm);
2782}
2783
2784
2785void Assembler::vmov(const DwVfpRegister dst,
2786 const VmovIndex index,
2787 const Register src,
2788 const Condition cond) {
2789 // Dd[index] = Rt
2790 // Instruction details available in ARM DDI 0406C.b, A8-940.
2791 // cond(31-28) | 1110(27-24) | 0(23) | opc1=0index(22-21) | 0(20) |
2792 // Vd(19-16) | Rt(15-12) | 1011(11-8) | D(7) | opc2=00(6-5) | 1(4) | 0000(3-0)
2793 DCHECK(index.index == 0 || index.index == 1);
2794 int vd, d;
2795 dst.split_code(&vd, &d);
2796 emit(cond | 0xE*B24 | index.index*B21 | vd*B16 | src.code()*B12 | 0xB*B8 |
2797 d*B7 | B4);
2798}
2799
2800
2801void Assembler::vmov(const Register dst,
2802 const VmovIndex index,
2803 const DwVfpRegister src,
2804 const Condition cond) {
2805 // Dd[index] = Rt
2806 // Instruction details available in ARM DDI 0406C.b, A8.8.342.
2807 // cond(31-28) | 1110(27-24) | U=0(23) | opc1=0index(22-21) | 1(20) |
2808 // Vn(19-16) | Rt(15-12) | 1011(11-8) | N(7) | opc2=00(6-5) | 1(4) | 0000(3-0)
2809 DCHECK(index.index == 0 || index.index == 1);
2810 int vn, n;
2811 src.split_code(&vn, &n);
2812 emit(cond | 0xE*B24 | index.index*B21 | B20 | vn*B16 | dst.code()*B12 |
2813 0xB*B8 | n*B7 | B4);
Steve Block8defd9f2010-07-08 12:39:36 +01002814}
2815
2816
2817void Assembler::vmov(const DwVfpRegister dst,
Leon Clarkee46be812010-01-19 14:06:41 +00002818 const Register src1,
2819 const Register src2,
2820 const Condition cond) {
Steve Blockd0582a62009-12-15 09:54:21 +00002821 // Dm = <Rt,Rt2>.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002822 // Instruction details available in ARM DDI 0406C.b, A8-948.
Steve Blockd0582a62009-12-15 09:54:21 +00002823 // cond(31-28) | 1100(27-24)| 010(23-21) | op=0(20) | Rt2(19-16) |
2824 // Rt(15-12) | 1011(11-8) | 00(7-6) | M(5) | 1(4) | Vm
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002825 DCHECK(!src1.is(pc) && !src2.is(pc));
2826 int vm, m;
2827 dst.split_code(&vm, &m);
Steve Blockd0582a62009-12-15 09:54:21 +00002828 emit(cond | 0xC*B24 | B22 | src2.code()*B16 |
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002829 src1.code()*B12 | 0xB*B8 | m*B5 | B4 | vm);
Steve Blockd0582a62009-12-15 09:54:21 +00002830}
2831
2832
Leon Clarkee46be812010-01-19 14:06:41 +00002833void Assembler::vmov(const Register dst1,
2834 const Register dst2,
2835 const DwVfpRegister src,
2836 const Condition cond) {
Steve Blockd0582a62009-12-15 09:54:21 +00002837 // <Rt,Rt2> = Dm.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002838 // Instruction details available in ARM DDI 0406C.b, A8-948.
Steve Blockd0582a62009-12-15 09:54:21 +00002839 // cond(31-28) | 1100(27-24)| 010(23-21) | op=1(20) | Rt2(19-16) |
2840 // Rt(15-12) | 1011(11-8) | 00(7-6) | M(5) | 1(4) | Vm
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002841 DCHECK(!dst1.is(pc) && !dst2.is(pc));
2842 int vm, m;
2843 src.split_code(&vm, &m);
Steve Blockd0582a62009-12-15 09:54:21 +00002844 emit(cond | 0xC*B24 | B22 | B20 | dst2.code()*B16 |
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002845 dst1.code()*B12 | 0xB*B8 | m*B5 | B4 | vm);
Steve Blockd0582a62009-12-15 09:54:21 +00002846}
2847
2848
Leon Clarkee46be812010-01-19 14:06:41 +00002849void Assembler::vmov(const SwVfpRegister dst,
Steve Blockd0582a62009-12-15 09:54:21 +00002850 const Register src,
Steve Blockd0582a62009-12-15 09:54:21 +00002851 const Condition cond) {
2852 // Sn = Rt.
2853 // Instruction details available in ARM DDI 0406A, A8-642.
2854 // cond(31-28) | 1110(27-24)| 000(23-21) | op=0(20) | Vn(19-16) |
2855 // Rt(15-12) | 1010(11-8) | N(7)=0 | 00(6-5) | 1(4) | 0000(3-0)
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002856 DCHECK(!src.is(pc));
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002857 int sn, n;
2858 dst.split_code(&sn, &n);
2859 emit(cond | 0xE*B24 | sn*B16 | src.code()*B12 | 0xA*B8 | n*B7 | B4);
Steve Blockd0582a62009-12-15 09:54:21 +00002860}
2861
2862
Leon Clarkee46be812010-01-19 14:06:41 +00002863void Assembler::vmov(const Register dst,
2864 const SwVfpRegister src,
Steve Blockd0582a62009-12-15 09:54:21 +00002865 const Condition cond) {
2866 // Rt = Sn.
2867 // Instruction details available in ARM DDI 0406A, A8-642.
2868 // cond(31-28) | 1110(27-24)| 000(23-21) | op=1(20) | Vn(19-16) |
2869 // Rt(15-12) | 1010(11-8) | N(7)=0 | 00(6-5) | 1(4) | 0000(3-0)
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002870 DCHECK(!dst.is(pc));
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002871 int sn, n;
2872 src.split_code(&sn, &n);
2873 emit(cond | 0xE*B24 | B20 | sn*B16 | dst.code()*B12 | 0xA*B8 | n*B7 | B4);
Steve Blockd0582a62009-12-15 09:54:21 +00002874}
2875
2876
Steve Block6ded16b2010-05-10 14:33:55 +01002877// Type of data to read from or write to VFP register.
2878// Used as specifier in generic vcvt instruction.
2879enum VFPType { S32, U32, F32, F64 };
2880
2881
2882static bool IsSignedVFPType(VFPType type) {
2883 switch (type) {
2884 case S32:
2885 return true;
2886 case U32:
2887 return false;
2888 default:
2889 UNREACHABLE();
2890 return false;
2891 }
Steve Blockd0582a62009-12-15 09:54:21 +00002892}
2893
2894
Steve Block6ded16b2010-05-10 14:33:55 +01002895static bool IsIntegerVFPType(VFPType type) {
2896 switch (type) {
2897 case S32:
2898 case U32:
2899 return true;
2900 case F32:
2901 case F64:
2902 return false;
2903 default:
2904 UNREACHABLE();
2905 return false;
2906 }
2907}
2908
2909
2910static bool IsDoubleVFPType(VFPType type) {
2911 switch (type) {
2912 case F32:
2913 return false;
2914 case F64:
2915 return true;
2916 default:
2917 UNREACHABLE();
2918 return false;
2919 }
2920}
2921
2922
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002923// Split five bit reg_code based on size of reg_type.
2924// 32-bit register codes are Vm:M
2925// 64-bit register codes are M:Vm
2926// where Vm is four bits, and M is a single bit.
2927static void SplitRegCode(VFPType reg_type,
Steve Block6ded16b2010-05-10 14:33:55 +01002928 int reg_code,
2929 int* vm,
2930 int* m) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002931 DCHECK((reg_code >= 0) && (reg_code <= 31));
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002932 if (IsIntegerVFPType(reg_type) || !IsDoubleVFPType(reg_type)) {
2933 // 32 bit type.
Steve Block6ded16b2010-05-10 14:33:55 +01002934 *m = reg_code & 0x1;
2935 *vm = reg_code >> 1;
2936 } else {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002937 // 64 bit type.
Steve Block6ded16b2010-05-10 14:33:55 +01002938 *m = (reg_code & 0x10) >> 4;
2939 *vm = reg_code & 0x0F;
2940 }
2941}
2942
2943
2944// Encode vcvt.src_type.dst_type instruction.
2945static Instr EncodeVCVT(const VFPType dst_type,
2946 const int dst_code,
2947 const VFPType src_type,
2948 const int src_code,
Steve Block1e0659c2011-05-24 12:43:12 +01002949 VFPConversionMode mode,
Steve Block6ded16b2010-05-10 14:33:55 +01002950 const Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002951 DCHECK(src_type != dst_type);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002952 int D, Vd, M, Vm;
2953 SplitRegCode(src_type, src_code, &Vm, &M);
2954 SplitRegCode(dst_type, dst_code, &Vd, &D);
2955
Steve Block6ded16b2010-05-10 14:33:55 +01002956 if (IsIntegerVFPType(dst_type) || IsIntegerVFPType(src_type)) {
2957 // Conversion between IEEE floating point and 32-bit integer.
2958 // Instruction details available in ARM DDI 0406B, A8.6.295.
2959 // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 1(19) | opc2(18-16) |
2960 // 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 +00002961 DCHECK(!IsIntegerVFPType(dst_type) || !IsIntegerVFPType(src_type));
Steve Block6ded16b2010-05-10 14:33:55 +01002962
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002963 int sz, opc2, op;
Steve Block6ded16b2010-05-10 14:33:55 +01002964
2965 if (IsIntegerVFPType(dst_type)) {
2966 opc2 = IsSignedVFPType(dst_type) ? 0x5 : 0x4;
2967 sz = IsDoubleVFPType(src_type) ? 0x1 : 0x0;
Russell Brenner90bac252010-11-18 13:33:46 -08002968 op = mode;
Steve Block6ded16b2010-05-10 14:33:55 +01002969 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002970 DCHECK(IsIntegerVFPType(src_type));
Steve Block6ded16b2010-05-10 14:33:55 +01002971 opc2 = 0x0;
2972 sz = IsDoubleVFPType(dst_type) ? 0x1 : 0x0;
2973 op = IsSignedVFPType(src_type) ? 0x1 : 0x0;
Steve Block6ded16b2010-05-10 14:33:55 +01002974 }
2975
2976 return (cond | 0xE*B24 | B23 | D*B22 | 0x3*B20 | B19 | opc2*B16 |
2977 Vd*B12 | 0x5*B9 | sz*B8 | op*B7 | B6 | M*B5 | Vm);
2978 } else {
2979 // Conversion between IEEE double and single precision.
2980 // Instruction details available in ARM DDI 0406B, A8.6.298.
2981 // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 0111(19-16) |
2982 // 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 +01002983 int sz = IsDoubleVFPType(src_type) ? 0x1 : 0x0;
Steve Block6ded16b2010-05-10 14:33:55 +01002984 return (cond | 0xE*B24 | B23 | D*B22 | 0x3*B20 | 0x7*B16 |
2985 Vd*B12 | 0x5*B9 | sz*B8 | B7 | B6 | M*B5 | Vm);
2986 }
2987}
2988
2989
2990void Assembler::vcvt_f64_s32(const DwVfpRegister dst,
2991 const SwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +01002992 VFPConversionMode mode,
Steve Block6ded16b2010-05-10 14:33:55 +01002993 const Condition cond) {
Russell Brenner90bac252010-11-18 13:33:46 -08002994 emit(EncodeVCVT(F64, dst.code(), S32, src.code(), mode, cond));
Steve Block6ded16b2010-05-10 14:33:55 +01002995}
2996
2997
2998void Assembler::vcvt_f32_s32(const SwVfpRegister dst,
2999 const SwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +01003000 VFPConversionMode mode,
Steve Block6ded16b2010-05-10 14:33:55 +01003001 const Condition cond) {
Russell Brenner90bac252010-11-18 13:33:46 -08003002 emit(EncodeVCVT(F32, dst.code(), S32, src.code(), mode, cond));
Steve Block6ded16b2010-05-10 14:33:55 +01003003}
3004
3005
3006void Assembler::vcvt_f64_u32(const DwVfpRegister dst,
3007 const SwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +01003008 VFPConversionMode mode,
Steve Block6ded16b2010-05-10 14:33:55 +01003009 const Condition cond) {
Russell Brenner90bac252010-11-18 13:33:46 -08003010 emit(EncodeVCVT(F64, dst.code(), U32, src.code(), mode, cond));
Steve Block6ded16b2010-05-10 14:33:55 +01003011}
3012
3013
Ben Murdoch097c5b22016-05-18 11:27:45 +01003014void Assembler::vcvt_f32_u32(const SwVfpRegister dst, const SwVfpRegister src,
3015 VFPConversionMode mode, const Condition cond) {
3016 emit(EncodeVCVT(F32, dst.code(), U32, src.code(), mode, cond));
3017}
3018
3019
3020void Assembler::vcvt_s32_f32(const SwVfpRegister dst, const SwVfpRegister src,
3021 VFPConversionMode mode, const Condition cond) {
3022 emit(EncodeVCVT(S32, dst.code(), F32, src.code(), mode, cond));
3023}
3024
3025
3026void Assembler::vcvt_u32_f32(const SwVfpRegister dst, const SwVfpRegister src,
3027 VFPConversionMode mode, const Condition cond) {
3028 emit(EncodeVCVT(U32, dst.code(), F32, src.code(), mode, cond));
3029}
3030
3031
Steve Block6ded16b2010-05-10 14:33:55 +01003032void Assembler::vcvt_s32_f64(const SwVfpRegister dst,
3033 const DwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +01003034 VFPConversionMode mode,
Steve Block6ded16b2010-05-10 14:33:55 +01003035 const Condition cond) {
Russell Brenner90bac252010-11-18 13:33:46 -08003036 emit(EncodeVCVT(S32, dst.code(), F64, src.code(), mode, cond));
Steve Block6ded16b2010-05-10 14:33:55 +01003037}
3038
3039
3040void Assembler::vcvt_u32_f64(const SwVfpRegister dst,
3041 const DwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +01003042 VFPConversionMode mode,
Steve Block6ded16b2010-05-10 14:33:55 +01003043 const Condition cond) {
Russell Brenner90bac252010-11-18 13:33:46 -08003044 emit(EncodeVCVT(U32, dst.code(), F64, src.code(), mode, cond));
Steve Block6ded16b2010-05-10 14:33:55 +01003045}
3046
3047
3048void Assembler::vcvt_f64_f32(const DwVfpRegister dst,
3049 const SwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +01003050 VFPConversionMode mode,
Steve Block6ded16b2010-05-10 14:33:55 +01003051 const Condition cond) {
Russell Brenner90bac252010-11-18 13:33:46 -08003052 emit(EncodeVCVT(F64, dst.code(), F32, src.code(), mode, cond));
Steve Block6ded16b2010-05-10 14:33:55 +01003053}
3054
3055
3056void Assembler::vcvt_f32_f64(const SwVfpRegister dst,
3057 const DwVfpRegister src,
Steve Block1e0659c2011-05-24 12:43:12 +01003058 VFPConversionMode mode,
Steve Block6ded16b2010-05-10 14:33:55 +01003059 const Condition cond) {
Russell Brenner90bac252010-11-18 13:33:46 -08003060 emit(EncodeVCVT(F32, dst.code(), F64, src.code(), mode, cond));
Steve Blockd0582a62009-12-15 09:54:21 +00003061}
3062
3063
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003064void Assembler::vcvt_f64_s32(const DwVfpRegister dst,
3065 int fraction_bits,
3066 const Condition cond) {
3067 // Instruction details available in ARM DDI 0406C.b, A8-874.
3068 // cond(31-28) | 11101(27-23) | D(22) | 11(21-20) | 1010(19-16) | Vd(15-12) |
3069 // 101(11-9) | sf=1(8) | sx=1(7) | 1(6) | i(5) | 0(4) | imm4(3-0)
3070 DCHECK(fraction_bits > 0 && fraction_bits <= 32);
3071 DCHECK(CpuFeatures::IsSupported(VFP3));
3072 int vd, d;
3073 dst.split_code(&vd, &d);
3074 int imm5 = 32 - fraction_bits;
3075 int i = imm5 & 1;
3076 int imm4 = (imm5 >> 1) & 0xf;
3077 emit(cond | 0xE*B24 | B23 | d*B22 | 0x3*B20 | B19 | 0x2*B16 |
3078 vd*B12 | 0x5*B9 | B8 | B7 | B6 | i*B5 | imm4);
3079}
3080
3081
Steve Block44f0eee2011-05-26 01:26:41 +01003082void Assembler::vneg(const DwVfpRegister dst,
3083 const DwVfpRegister src,
3084 const Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003085 // Instruction details available in ARM DDI 0406C.b, A8-968.
3086 // cond(31-28) | 11101(27-23) | D(22) | 11(21-20) | 0001(19-16) | Vd(15-12) |
3087 // 101(11-9) | sz=1(8) | 0(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
3088 int vd, d;
3089 dst.split_code(&vd, &d);
3090 int vm, m;
3091 src.split_code(&vm, &m);
3092
3093 emit(cond | 0x1D*B23 | d*B22 | 0x3*B20 | B16 | vd*B12 | 0x5*B9 | B8 | B6 |
3094 m*B5 | vm);
Steve Block44f0eee2011-05-26 01:26:41 +01003095}
3096
3097
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003098void Assembler::vneg(const SwVfpRegister dst, const SwVfpRegister src,
3099 const Condition cond) {
3100 // Instruction details available in ARM DDI 0406C.b, A8-968.
3101 // cond(31-28) | 11101(27-23) | D(22) | 11(21-20) | 0001(19-16) | Vd(15-12) |
3102 // 101(11-9) | sz=0(8) | 0(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
3103 int vd, d;
3104 dst.split_code(&vd, &d);
3105 int vm, m;
3106 src.split_code(&vm, &m);
3107
3108 emit(cond | 0x1D * B23 | d * B22 | 0x3 * B20 | B16 | vd * B12 | 0x5 * B9 |
3109 B6 | m * B5 | vm);
3110}
3111
3112
Steve Block1e0659c2011-05-24 12:43:12 +01003113void Assembler::vabs(const DwVfpRegister dst,
3114 const DwVfpRegister src,
3115 const Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003116 // Instruction details available in ARM DDI 0406C.b, A8-524.
3117 // cond(31-28) | 11101(27-23) | D(22) | 11(21-20) | 0000(19-16) | Vd(15-12) |
3118 // 101(11-9) | sz=1(8) | 1(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
3119 int vd, d;
3120 dst.split_code(&vd, &d);
3121 int vm, m;
3122 src.split_code(&vm, &m);
3123 emit(cond | 0x1D*B23 | d*B22 | 0x3*B20 | vd*B12 | 0x5*B9 | B8 | B7 | B6 |
3124 m*B5 | vm);
Steve Block1e0659c2011-05-24 12:43:12 +01003125}
3126
3127
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003128void Assembler::vabs(const SwVfpRegister dst, const SwVfpRegister src,
3129 const Condition cond) {
3130 // Instruction details available in ARM DDI 0406C.b, A8-524.
3131 // cond(31-28) | 11101(27-23) | D(22) | 11(21-20) | 0000(19-16) | Vd(15-12) |
3132 // 101(11-9) | sz=0(8) | 1(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
3133 int vd, d;
3134 dst.split_code(&vd, &d);
3135 int vm, m;
3136 src.split_code(&vm, &m);
3137 emit(cond | 0x1D * B23 | d * B22 | 0x3 * B20 | vd * B12 | 0x5 * B9 | B7 | B6 |
3138 m * B5 | vm);
3139}
3140
3141
Leon Clarkee46be812010-01-19 14:06:41 +00003142void Assembler::vadd(const DwVfpRegister dst,
3143 const DwVfpRegister src1,
3144 const DwVfpRegister src2,
3145 const Condition cond) {
3146 // Dd = vadd(Dn, Dm) double precision floating point addition.
Steve Blockd0582a62009-12-15 09:54:21 +00003147 // Dd = D:Vd; Dm=M:Vm; Dn=N:Vm.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003148 // Instruction details available in ARM DDI 0406C.b, A8-830.
3149 // cond(31-28) | 11100(27-23)| D(22) | 11(21-20) | Vn(19-16) |
3150 // Vd(15-12) | 101(11-9) | sz=1(8) | N(7) | 0(6) | M(5) | 0(4) | Vm(3-0)
3151 int vd, d;
3152 dst.split_code(&vd, &d);
3153 int vn, n;
3154 src1.split_code(&vn, &n);
3155 int vm, m;
3156 src2.split_code(&vm, &m);
3157 emit(cond | 0x1C*B23 | d*B22 | 0x3*B20 | vn*B16 | vd*B12 | 0x5*B9 | B8 |
3158 n*B7 | m*B5 | vm);
Steve Blockd0582a62009-12-15 09:54:21 +00003159}
3160
3161
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003162void Assembler::vadd(const SwVfpRegister dst, const SwVfpRegister src1,
3163 const SwVfpRegister src2, const Condition cond) {
3164 // Sd = vadd(Sn, Sm) single precision floating point addition.
3165 // Sd = D:Vd; Sm=M:Vm; Sn=N:Vm.
3166 // Instruction details available in ARM DDI 0406C.b, A8-830.
3167 // cond(31-28) | 11100(27-23)| D(22) | 11(21-20) | Vn(19-16) |
3168 // Vd(15-12) | 101(11-9) | sz=0(8) | N(7) | 0(6) | M(5) | 0(4) | Vm(3-0)
3169 int vd, d;
3170 dst.split_code(&vd, &d);
3171 int vn, n;
3172 src1.split_code(&vn, &n);
3173 int vm, m;
3174 src2.split_code(&vm, &m);
3175 emit(cond | 0x1C * B23 | d * B22 | 0x3 * B20 | vn * B16 | vd * B12 |
3176 0x5 * B9 | n * B7 | m * B5 | vm);
3177}
3178
3179
Leon Clarkee46be812010-01-19 14:06:41 +00003180void Assembler::vsub(const DwVfpRegister dst,
3181 const DwVfpRegister src1,
3182 const DwVfpRegister src2,
3183 const Condition cond) {
3184 // Dd = vsub(Dn, Dm) double precision floating point subtraction.
Steve Blockd0582a62009-12-15 09:54:21 +00003185 // Dd = D:Vd; Dm=M:Vm; Dn=N:Vm.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003186 // Instruction details available in ARM DDI 0406C.b, A8-1086.
3187 // cond(31-28) | 11100(27-23)| D(22) | 11(21-20) | Vn(19-16) |
3188 // Vd(15-12) | 101(11-9) | sz=1(8) | N(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
3189 int vd, d;
3190 dst.split_code(&vd, &d);
3191 int vn, n;
3192 src1.split_code(&vn, &n);
3193 int vm, m;
3194 src2.split_code(&vm, &m);
3195 emit(cond | 0x1C*B23 | d*B22 | 0x3*B20 | vn*B16 | vd*B12 | 0x5*B9 | B8 |
3196 n*B7 | B6 | m*B5 | vm);
Steve Blockd0582a62009-12-15 09:54:21 +00003197}
3198
3199
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003200void Assembler::vsub(const SwVfpRegister dst, const SwVfpRegister src1,
3201 const SwVfpRegister src2, const Condition cond) {
3202 // Sd = vsub(Sn, Sm) single precision floating point subtraction.
3203 // Sd = D:Vd; Sm=M:Vm; Sn=N:Vm.
3204 // Instruction details available in ARM DDI 0406C.b, A8-1086.
3205 // cond(31-28) | 11100(27-23)| D(22) | 11(21-20) | Vn(19-16) |
3206 // Vd(15-12) | 101(11-9) | sz=0(8) | N(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
3207 int vd, d;
3208 dst.split_code(&vd, &d);
3209 int vn, n;
3210 src1.split_code(&vn, &n);
3211 int vm, m;
3212 src2.split_code(&vm, &m);
3213 emit(cond | 0x1C * B23 | d * B22 | 0x3 * B20 | vn * B16 | vd * B12 |
3214 0x5 * B9 | n * B7 | B6 | m * B5 | vm);
3215}
3216
3217
Leon Clarkee46be812010-01-19 14:06:41 +00003218void Assembler::vmul(const DwVfpRegister dst,
3219 const DwVfpRegister src1,
3220 const DwVfpRegister src2,
3221 const Condition cond) {
3222 // Dd = vmul(Dn, Dm) double precision floating point multiplication.
Steve Blockd0582a62009-12-15 09:54:21 +00003223 // Dd = D:Vd; Dm=M:Vm; Dn=N:Vm.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003224 // Instruction details available in ARM DDI 0406C.b, A8-960.
3225 // cond(31-28) | 11100(27-23)| D(22) | 10(21-20) | Vn(19-16) |
3226 // Vd(15-12) | 101(11-9) | sz=1(8) | N(7) | 0(6) | M(5) | 0(4) | Vm(3-0)
3227 int vd, d;
3228 dst.split_code(&vd, &d);
3229 int vn, n;
3230 src1.split_code(&vn, &n);
3231 int vm, m;
3232 src2.split_code(&vm, &m);
3233 emit(cond | 0x1C*B23 | d*B22 | 0x2*B20 | vn*B16 | vd*B12 | 0x5*B9 | B8 |
3234 n*B7 | m*B5 | vm);
3235}
3236
3237
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003238void Assembler::vmul(const SwVfpRegister dst, const SwVfpRegister src1,
3239 const SwVfpRegister src2, const Condition cond) {
3240 // Sd = vmul(Sn, Sm) single precision floating point multiplication.
3241 // Sd = D:Vd; Sm=M:Vm; Sn=N:Vm.
3242 // Instruction details available in ARM DDI 0406C.b, A8-960.
3243 // cond(31-28) | 11100(27-23)| D(22) | 10(21-20) | Vn(19-16) |
3244 // Vd(15-12) | 101(11-9) | sz=0(8) | N(7) | 0(6) | M(5) | 0(4) | Vm(3-0)
3245 int vd, d;
3246 dst.split_code(&vd, &d);
3247 int vn, n;
3248 src1.split_code(&vn, &n);
3249 int vm, m;
3250 src2.split_code(&vm, &m);
3251 emit(cond | 0x1C * B23 | d * B22 | 0x2 * B20 | vn * B16 | vd * B12 |
3252 0x5 * B9 | n * B7 | m * B5 | vm);
3253}
3254
3255
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003256void Assembler::vmla(const DwVfpRegister dst,
3257 const DwVfpRegister src1,
3258 const DwVfpRegister src2,
3259 const Condition cond) {
3260 // Instruction details available in ARM DDI 0406C.b, A8-932.
3261 // cond(31-28) | 11100(27-23) | D(22) | 00(21-20) | Vn(19-16) |
3262 // Vd(15-12) | 101(11-9) | sz=1(8) | N(7) | op=0(6) | M(5) | 0(4) | Vm(3-0)
3263 int vd, d;
3264 dst.split_code(&vd, &d);
3265 int vn, n;
3266 src1.split_code(&vn, &n);
3267 int vm, m;
3268 src2.split_code(&vm, &m);
3269 emit(cond | 0x1C*B23 | d*B22 | vn*B16 | vd*B12 | 0x5*B9 | B8 | n*B7 | m*B5 |
3270 vm);
3271}
3272
3273
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003274void Assembler::vmla(const SwVfpRegister dst, const SwVfpRegister src1,
3275 const SwVfpRegister src2, const Condition cond) {
3276 // Instruction details available in ARM DDI 0406C.b, A8-932.
3277 // cond(31-28) | 11100(27-23) | D(22) | 00(21-20) | Vn(19-16) |
3278 // Vd(15-12) | 101(11-9) | sz=0(8) | N(7) | op=0(6) | M(5) | 0(4) | Vm(3-0)
3279 int vd, d;
3280 dst.split_code(&vd, &d);
3281 int vn, n;
3282 src1.split_code(&vn, &n);
3283 int vm, m;
3284 src2.split_code(&vm, &m);
3285 emit(cond | 0x1C * B23 | d * B22 | vn * B16 | vd * B12 | 0x5 * B9 | n * B7 |
3286 m * B5 | vm);
3287}
3288
3289
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003290void Assembler::vmls(const DwVfpRegister dst,
3291 const DwVfpRegister src1,
3292 const DwVfpRegister src2,
3293 const Condition cond) {
3294 // Instruction details available in ARM DDI 0406C.b, A8-932.
3295 // cond(31-28) | 11100(27-23) | D(22) | 00(21-20) | Vn(19-16) |
3296 // Vd(15-12) | 101(11-9) | sz=1(8) | N(7) | op=1(6) | M(5) | 0(4) | Vm(3-0)
3297 int vd, d;
3298 dst.split_code(&vd, &d);
3299 int vn, n;
3300 src1.split_code(&vn, &n);
3301 int vm, m;
3302 src2.split_code(&vm, &m);
3303 emit(cond | 0x1C*B23 | d*B22 | vn*B16 | vd*B12 | 0x5*B9 | B8 | n*B7 | B6 |
3304 m*B5 | vm);
Steve Blockd0582a62009-12-15 09:54:21 +00003305}
3306
3307
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003308void Assembler::vmls(const SwVfpRegister dst, const SwVfpRegister src1,
3309 const SwVfpRegister src2, const Condition cond) {
3310 // Instruction details available in ARM DDI 0406C.b, A8-932.
3311 // cond(31-28) | 11100(27-23) | D(22) | 00(21-20) | Vn(19-16) |
3312 // Vd(15-12) | 101(11-9) | sz=0(8) | N(7) | op=1(6) | M(5) | 0(4) | Vm(3-0)
3313 int vd, d;
3314 dst.split_code(&vd, &d);
3315 int vn, n;
3316 src1.split_code(&vn, &n);
3317 int vm, m;
3318 src2.split_code(&vm, &m);
3319 emit(cond | 0x1C * B23 | d * B22 | vn * B16 | vd * B12 | 0x5 * B9 | n * B7 |
3320 B6 | m * B5 | vm);
3321}
3322
3323
Leon Clarkee46be812010-01-19 14:06:41 +00003324void Assembler::vdiv(const DwVfpRegister dst,
3325 const DwVfpRegister src1,
3326 const DwVfpRegister src2,
3327 const Condition cond) {
3328 // Dd = vdiv(Dn, Dm) double precision floating point division.
Steve Blockd0582a62009-12-15 09:54:21 +00003329 // Dd = D:Vd; Dm=M:Vm; Dn=N:Vm.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003330 // Instruction details available in ARM DDI 0406C.b, A8-882.
3331 // cond(31-28) | 11101(27-23)| D(22) | 00(21-20) | Vn(19-16) |
3332 // Vd(15-12) | 101(11-9) | sz=1(8) | N(7) | 0(6) | M(5) | 0(4) | Vm(3-0)
3333 int vd, d;
3334 dst.split_code(&vd, &d);
3335 int vn, n;
3336 src1.split_code(&vn, &n);
3337 int vm, m;
3338 src2.split_code(&vm, &m);
3339 emit(cond | 0x1D*B23 | d*B22 | vn*B16 | vd*B12 | 0x5*B9 | B8 | n*B7 | m*B5 |
3340 vm);
Steve Blockd0582a62009-12-15 09:54:21 +00003341}
3342
3343
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003344void Assembler::vdiv(const SwVfpRegister dst, const SwVfpRegister src1,
3345 const SwVfpRegister src2, const Condition cond) {
3346 // Sd = vdiv(Sn, Sm) single precision floating point division.
3347 // Sd = D:Vd; Sm=M:Vm; Sn=N:Vm.
3348 // Instruction details available in ARM DDI 0406C.b, A8-882.
3349 // cond(31-28) | 11101(27-23)| D(22) | 00(21-20) | Vn(19-16) |
3350 // Vd(15-12) | 101(11-9) | sz=0(8) | N(7) | 0(6) | M(5) | 0(4) | Vm(3-0)
3351 int vd, d;
3352 dst.split_code(&vd, &d);
3353 int vn, n;
3354 src1.split_code(&vn, &n);
3355 int vm, m;
3356 src2.split_code(&vm, &m);
3357 emit(cond | 0x1D * B23 | d * B22 | vn * B16 | vd * B12 | 0x5 * B9 | n * B7 |
3358 m * B5 | vm);
3359}
3360
3361
Leon Clarkee46be812010-01-19 14:06:41 +00003362void Assembler::vcmp(const DwVfpRegister src1,
3363 const DwVfpRegister src2,
Steve Blockd0582a62009-12-15 09:54:21 +00003364 const Condition cond) {
3365 // vcmp(Dd, Dm) double precision floating point comparison.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003366 // Instruction details available in ARM DDI 0406C.b, A8-864.
3367 // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 0100(19-16) |
3368 // Vd(15-12) | 101(11-9) | sz=1(8) | E=0(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
3369 int vd, d;
3370 src1.split_code(&vd, &d);
3371 int vm, m;
3372 src2.split_code(&vm, &m);
3373 emit(cond | 0x1D*B23 | d*B22 | 0x3*B20 | 0x4*B16 | vd*B12 | 0x5*B9 | B8 | B6 |
3374 m*B5 | vm);
Steve Blockd0582a62009-12-15 09:54:21 +00003375}
3376
3377
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003378void Assembler::vcmp(const SwVfpRegister src1, const SwVfpRegister src2,
3379 const Condition cond) {
3380 // vcmp(Sd, Sm) single precision floating point comparison.
3381 // Instruction details available in ARM DDI 0406C.b, A8-864.
3382 // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 0100(19-16) |
3383 // Vd(15-12) | 101(11-9) | sz=0(8) | E=0(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
3384 int vd, d;
3385 src1.split_code(&vd, &d);
3386 int vm, m;
3387 src2.split_code(&vm, &m);
3388 emit(cond | 0x1D * B23 | d * B22 | 0x3 * B20 | 0x4 * B16 | vd * B12 |
3389 0x5 * B9 | B6 | m * B5 | vm);
3390}
3391
3392
Iain Merrick75681382010-08-19 15:07:18 +01003393void Assembler::vcmp(const DwVfpRegister src1,
3394 const double src2,
Iain Merrick75681382010-08-19 15:07:18 +01003395 const Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003396 // vcmp(Dd, #0.0) double precision floating point comparison.
3397 // Instruction details available in ARM DDI 0406C.b, A8-864.
3398 // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 0101(19-16) |
3399 // Vd(15-12) | 101(11-9) | sz=1(8) | E=0(7) | 1(6) | 0(5) | 0(4) | 0000(3-0)
3400 DCHECK(src2 == 0.0);
3401 int vd, d;
3402 src1.split_code(&vd, &d);
3403 emit(cond | 0x1D*B23 | d*B22 | 0x3*B20 | 0x5*B16 | vd*B12 | 0x5*B9 | B8 | B6);
Iain Merrick75681382010-08-19 15:07:18 +01003404}
3405
3406
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003407void Assembler::vcmp(const SwVfpRegister src1, const float src2,
3408 const Condition cond) {
3409 // vcmp(Sd, #0.0) single precision floating point comparison.
3410 // Instruction details available in ARM DDI 0406C.b, A8-864.
3411 // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 0101(19-16) |
3412 // Vd(15-12) | 101(11-9) | sz=0(8) | E=0(7) | 1(6) | 0(5) | 0(4) | 0000(3-0)
3413 DCHECK(src2 == 0.0);
3414 int vd, d;
3415 src1.split_code(&vd, &d);
3416 emit(cond | 0x1D * B23 | d * B22 | 0x3 * B20 | 0x5 * B16 | vd * B12 |
3417 0x5 * B9 | B6);
Steve Blockd0582a62009-12-15 09:54:21 +00003418}
3419
Ben Murdochc5610432016-08-08 18:44:38 +01003420void Assembler::vsel(Condition cond, const DwVfpRegister dst,
3421 const DwVfpRegister src1, const DwVfpRegister src2) {
3422 // cond=kSpecialCondition(31-28) | 11100(27-23) | D(22) |
3423 // vsel_cond=XX(21-20) | Vn(19-16) | Vd(15-12) | 101(11-9) | sz=1(8) | N(7) |
3424 // 0(6) | M(5) | 0(4) | Vm(3-0)
3425 DCHECK(CpuFeatures::IsSupported(ARMv8));
3426 int vd, d;
3427 dst.split_code(&vd, &d);
3428 int vn, n;
3429 src1.split_code(&vn, &n);
3430 int vm, m;
3431 src2.split_code(&vm, &m);
3432 int sz = 1;
3433
3434 // VSEL has a special (restricted) condition encoding.
3435 // eq(0b0000)... -> 0b00
3436 // ge(0b1010)... -> 0b10
3437 // gt(0b1100)... -> 0b11
3438 // vs(0b0110)... -> 0b01
3439 // No other conditions are supported.
3440 int vsel_cond = (cond >> 30) & 0x3;
3441 if ((cond != eq) && (cond != ge) && (cond != gt) && (cond != vs)) {
3442 // We can implement some other conditions by swapping the inputs.
3443 DCHECK((cond == ne) | (cond == lt) | (cond == le) | (cond == vc));
3444 std::swap(vn, vm);
3445 std::swap(n, m);
3446 }
3447
3448 emit(kSpecialCondition | 0x1C * B23 | d * B22 | vsel_cond * B20 | vn * B16 |
3449 vd * B12 | 0x5 * B9 | sz * B8 | n * B7 | m * B5 | vm);
3450}
3451
3452void Assembler::vsel(Condition cond, const SwVfpRegister dst,
3453 const SwVfpRegister src1, const SwVfpRegister src2) {
3454 // cond=kSpecialCondition(31-28) | 11100(27-23) | D(22) |
3455 // vsel_cond=XX(21-20) | Vn(19-16) | Vd(15-12) | 101(11-9) | sz=0(8) | N(7) |
3456 // 0(6) | M(5) | 0(4) | Vm(3-0)
3457 DCHECK(CpuFeatures::IsSupported(ARMv8));
3458 int vd, d;
3459 dst.split_code(&vd, &d);
3460 int vn, n;
3461 src1.split_code(&vn, &n);
3462 int vm, m;
3463 src2.split_code(&vm, &m);
3464 int sz = 0;
3465
3466 // VSEL has a special (restricted) condition encoding.
3467 // eq(0b0000)... -> 0b00
3468 // ge(0b1010)... -> 0b10
3469 // gt(0b1100)... -> 0b11
3470 // vs(0b0110)... -> 0b01
3471 // No other conditions are supported.
3472 int vsel_cond = (cond >> 30) & 0x3;
3473 if ((cond != eq) && (cond != ge) && (cond != gt) && (cond != vs)) {
3474 // We can implement some other conditions by swapping the inputs.
3475 DCHECK((cond == ne) | (cond == lt) | (cond == le) | (cond == vc));
3476 std::swap(vn, vm);
3477 std::swap(n, m);
3478 }
3479
3480 emit(kSpecialCondition | 0x1C * B23 | d * B22 | vsel_cond * B20 | vn * B16 |
3481 vd * B12 | 0x5 * B9 | sz * B8 | n * B7 | m * B5 | vm);
3482}
Steve Blockd0582a62009-12-15 09:54:21 +00003483
Steve Block8defd9f2010-07-08 12:39:36 +01003484void Assembler::vsqrt(const DwVfpRegister dst,
3485 const DwVfpRegister src,
3486 const Condition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003487 // Instruction details available in ARM DDI 0406C.b, A8-1058.
3488 // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 0001(19-16) |
3489 // Vd(15-12) | 101(11-9) | sz=1(8) | 11(7-6) | M(5) | 0(4) | Vm(3-0)
3490 int vd, d;
3491 dst.split_code(&vd, &d);
3492 int vm, m;
3493 src.split_code(&vm, &m);
3494 emit(cond | 0x1D*B23 | d*B22 | 0x3*B20 | B16 | vd*B12 | 0x5*B9 | B8 | 0x3*B6 |
3495 m*B5 | vm);
3496}
3497
3498
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003499void Assembler::vsqrt(const SwVfpRegister dst, const SwVfpRegister src,
3500 const Condition cond) {
3501 // Instruction details available in ARM DDI 0406C.b, A8-1058.
3502 // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 0001(19-16) |
3503 // Vd(15-12) | 101(11-9) | sz=0(8) | 11(7-6) | M(5) | 0(4) | Vm(3-0)
3504 int vd, d;
3505 dst.split_code(&vd, &d);
3506 int vm, m;
3507 src.split_code(&vm, &m);
3508 emit(cond | 0x1D * B23 | d * B22 | 0x3 * B20 | B16 | vd * B12 | 0x5 * B9 |
3509 0x3 * B6 | m * B5 | vm);
3510}
3511
3512
3513void Assembler::vmsr(Register dst, Condition cond) {
3514 // Instruction details available in ARM DDI 0406A, A8-652.
3515 // cond(31-28) | 1110 (27-24) | 1110(23-20)| 0001 (19-16) |
3516 // Rt(15-12) | 1010 (11-8) | 0(7) | 00 (6-5) | 1(4) | 0000(3-0)
3517 emit(cond | 0xE * B24 | 0xE * B20 | B16 | dst.code() * B12 | 0xA * B8 | B4);
3518}
3519
3520
3521void Assembler::vmrs(Register dst, Condition cond) {
3522 // Instruction details available in ARM DDI 0406A, A8-652.
3523 // cond(31-28) | 1110 (27-24) | 1111(23-20)| 0001 (19-16) |
3524 // Rt(15-12) | 1010 (11-8) | 0(7) | 00 (6-5) | 1(4) | 0000(3-0)
3525 emit(cond | 0xE * B24 | 0xF * B20 | B16 | dst.code() * B12 | 0xA * B8 | B4);
3526}
3527
3528
3529void Assembler::vrinta(const SwVfpRegister dst, const SwVfpRegister src) {
3530 // cond=kSpecialCondition(31-28) | 11101(27-23)| D(22) | 11(21-20) |
3531 // 10(19-18) | RM=00(17-16) | Vd(15-12) | 101(11-9) | sz=0(8) | 01(7-6) |
3532 // 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(kSpecialCondition | 0x1D * B23 | d * B22 | 0x3 * B20 | B19 | vd * B12 |
3539 0x5 * B9 | B6 | m * B5 | vm);
3540}
3541
3542
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003543void Assembler::vrinta(const DwVfpRegister dst, const DwVfpRegister src) {
3544 // cond=kSpecialCondition(31-28) | 11101(27-23)| D(22) | 11(21-20) |
3545 // 10(19-18) | RM=00(17-16) | Vd(15-12) | 101(11-9) | sz=1(8) | 01(7-6) |
3546 // M(5) | 0(4) | Vm(3-0)
3547 DCHECK(CpuFeatures::IsSupported(ARMv8));
3548 int vd, d;
3549 dst.split_code(&vd, &d);
3550 int vm, m;
3551 src.split_code(&vm, &m);
3552 emit(kSpecialCondition | 0x1D * B23 | d * B22 | 0x3 * B20 | B19 | vd * B12 |
3553 0x5 * B9 | B8 | B6 | m * B5 | vm);
3554}
3555
3556
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003557void Assembler::vrintn(const SwVfpRegister dst, const SwVfpRegister src) {
3558 // cond=kSpecialCondition(31-28) | 11101(27-23)| D(22) | 11(21-20) |
3559 // 10(19-18) | RM=01(17-16) | Vd(15-12) | 101(11-9) | sz=0(8) | 01(7-6) |
3560 // M(5) | 0(4) | Vm(3-0)
3561 DCHECK(CpuFeatures::IsSupported(ARMv8));
3562 int vd, d;
3563 dst.split_code(&vd, &d);
3564 int vm, m;
3565 src.split_code(&vm, &m);
3566 emit(kSpecialCondition | 0x1D * B23 | d * B22 | 0x3 * B20 | B19 | 0x1 * B16 |
3567 vd * B12 | 0x5 * B9 | B6 | m * B5 | vm);
3568}
3569
3570
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003571void Assembler::vrintn(const DwVfpRegister dst, const DwVfpRegister src) {
3572 // cond=kSpecialCondition(31-28) | 11101(27-23)| D(22) | 11(21-20) |
3573 // 10(19-18) | RM=01(17-16) | Vd(15-12) | 101(11-9) | sz=1(8) | 01(7-6) |
3574 // M(5) | 0(4) | Vm(3-0)
3575 DCHECK(CpuFeatures::IsSupported(ARMv8));
3576 int vd, d;
3577 dst.split_code(&vd, &d);
3578 int vm, m;
3579 src.split_code(&vm, &m);
3580 emit(kSpecialCondition | 0x1D * B23 | d * B22 | 0x3 * B20 | B19 | 0x1 * B16 |
3581 vd * B12 | 0x5 * B9 | B8 | B6 | m * B5 | vm);
3582}
3583
3584
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003585void Assembler::vrintp(const SwVfpRegister dst, const SwVfpRegister src) {
3586 // cond=kSpecialCondition(31-28) | 11101(27-23)| D(22) | 11(21-20) |
3587 // 10(19-18) | RM=10(17-16) | Vd(15-12) | 101(11-9) | sz=0(8) | 01(7-6) |
3588 // M(5) | 0(4) | Vm(3-0)
3589 DCHECK(CpuFeatures::IsSupported(ARMv8));
3590 int vd, d;
3591 dst.split_code(&vd, &d);
3592 int vm, m;
3593 src.split_code(&vm, &m);
3594 emit(kSpecialCondition | 0x1D * B23 | d * B22 | 0x3 * B20 | B19 | 0x2 * B16 |
3595 vd * B12 | 0x5 * B9 | B6 | m * B5 | vm);
3596}
3597
3598
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003599void Assembler::vrintp(const DwVfpRegister dst, const DwVfpRegister src) {
3600 // cond=kSpecialCondition(31-28) | 11101(27-23)| D(22) | 11(21-20) |
3601 // 10(19-18) | RM=10(17-16) | Vd(15-12) | 101(11-9) | sz=1(8) | 01(7-6) |
3602 // M(5) | 0(4) | Vm(3-0)
3603 DCHECK(CpuFeatures::IsSupported(ARMv8));
3604 int vd, d;
3605 dst.split_code(&vd, &d);
3606 int vm, m;
3607 src.split_code(&vm, &m);
3608 emit(kSpecialCondition | 0x1D * B23 | d * B22 | 0x3 * B20 | B19 | 0x2 * B16 |
3609 vd * B12 | 0x5 * B9 | B8 | B6 | m * B5 | vm);
3610}
3611
3612
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003613void Assembler::vrintm(const SwVfpRegister dst, const SwVfpRegister src) {
3614 // cond=kSpecialCondition(31-28) | 11101(27-23)| D(22) | 11(21-20) |
3615 // 10(19-18) | RM=11(17-16) | Vd(15-12) | 101(11-9) | sz=0(8) | 01(7-6) |
3616 // M(5) | 0(4) | Vm(3-0)
3617 DCHECK(CpuFeatures::IsSupported(ARMv8));
3618 int vd, d;
3619 dst.split_code(&vd, &d);
3620 int vm, m;
3621 src.split_code(&vm, &m);
3622 emit(kSpecialCondition | 0x1D * B23 | d * B22 | 0x3 * B20 | B19 | 0x3 * B16 |
3623 vd * B12 | 0x5 * B9 | B6 | m * B5 | vm);
3624}
3625
3626
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003627void Assembler::vrintm(const DwVfpRegister dst, const DwVfpRegister src) {
3628 // cond=kSpecialCondition(31-28) | 11101(27-23)| D(22) | 11(21-20) |
3629 // 10(19-18) | RM=11(17-16) | Vd(15-12) | 101(11-9) | sz=1(8) | 01(7-6) |
3630 // M(5) | 0(4) | Vm(3-0)
3631 DCHECK(CpuFeatures::IsSupported(ARMv8));
3632 int vd, d;
3633 dst.split_code(&vd, &d);
3634 int vm, m;
3635 src.split_code(&vm, &m);
3636 emit(kSpecialCondition | 0x1D * B23 | d * B22 | 0x3 * B20 | B19 | 0x3 * B16 |
3637 vd * B12 | 0x5 * B9 | B8 | B6 | m * B5 | vm);
3638}
3639
3640
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003641void Assembler::vrintz(const SwVfpRegister dst, const SwVfpRegister src,
3642 const Condition cond) {
3643 // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 011(19-17) | 0(16) |
3644 // Vd(15-12) | 101(11-9) | sz=0(8) | op=1(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
3645 DCHECK(CpuFeatures::IsSupported(ARMv8));
3646 int vd, d;
3647 dst.split_code(&vd, &d);
3648 int vm, m;
3649 src.split_code(&vm, &m);
3650 emit(cond | 0x1D * B23 | d * B22 | 0x3 * B20 | 0x3 * B17 | vd * B12 |
3651 0x5 * B9 | B7 | B6 | m * B5 | vm);
3652}
3653
3654
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003655void Assembler::vrintz(const DwVfpRegister dst, const DwVfpRegister src,
3656 const Condition cond) {
3657 // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 011(19-17) | 0(16) |
3658 // Vd(15-12) | 101(11-9) | sz=1(8) | op=1(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
3659 DCHECK(CpuFeatures::IsSupported(ARMv8));
3660 int vd, d;
3661 dst.split_code(&vd, &d);
3662 int vm, m;
3663 src.split_code(&vm, &m);
3664 emit(cond | 0x1D * B23 | d * B22 | 0x3 * B20 | 0x3 * B17 | vd * B12 |
3665 0x5 * B9 | B8 | B7 | B6 | m * B5 | vm);
3666}
3667
3668
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003669// Support for NEON.
3670
3671void Assembler::vld1(NeonSize size,
3672 const NeonListOperand& dst,
3673 const NeonMemOperand& src) {
3674 // Instruction details available in ARM DDI 0406C.b, A8.8.320.
3675 // 1111(31-28) | 01000(27-23) | D(22) | 10(21-20) | Rn(19-16) |
3676 // Vd(15-12) | type(11-8) | size(7-6) | align(5-4) | Rm(3-0)
3677 DCHECK(CpuFeatures::IsSupported(NEON));
3678 int vd, d;
3679 dst.base().split_code(&vd, &d);
3680 emit(0xFU*B28 | 4*B24 | d*B22 | 2*B20 | src.rn().code()*B16 | vd*B12 |
3681 dst.type()*B8 | size*B6 | src.align()*B4 | src.rm().code());
3682}
3683
3684
3685void Assembler::vst1(NeonSize size,
3686 const NeonListOperand& src,
3687 const NeonMemOperand& dst) {
3688 // Instruction details available in ARM DDI 0406C.b, A8.8.404.
3689 // 1111(31-28) | 01000(27-23) | D(22) | 00(21-20) | Rn(19-16) |
3690 // Vd(15-12) | type(11-8) | size(7-6) | align(5-4) | Rm(3-0)
3691 DCHECK(CpuFeatures::IsSupported(NEON));
3692 int vd, d;
3693 src.base().split_code(&vd, &d);
3694 emit(0xFU*B28 | 4*B24 | d*B22 | dst.rn().code()*B16 | vd*B12 | src.type()*B8 |
3695 size*B6 | dst.align()*B4 | dst.rm().code());
3696}
3697
3698
3699void Assembler::vmovl(NeonDataType dt, QwNeonRegister dst, DwVfpRegister src) {
3700 // Instruction details available in ARM DDI 0406C.b, A8.8.346.
3701 // 1111(31-28) | 001(27-25) | U(24) | 1(23) | D(22) | imm3(21-19) |
3702 // 000(18-16) | Vd(15-12) | 101000(11-6) | M(5) | 1(4) | Vm(3-0)
3703 DCHECK(CpuFeatures::IsSupported(NEON));
3704 int vd, d;
3705 dst.split_code(&vd, &d);
3706 int vm, m;
3707 src.split_code(&vm, &m);
3708 emit(0xFU*B28 | B25 | (dt & NeonDataTypeUMask) | B23 | d*B22 |
3709 (dt & NeonDataTypeSizeMask)*B19 | vd*B12 | 0xA*B8 | m*B5 | B4 | vm);
Steve Block8defd9f2010-07-08 12:39:36 +01003710}
3711
3712
Andrei Popescu31002712010-02-23 13:46:05 +00003713// Pseudo instructions.
Steve Block6ded16b2010-05-10 14:33:55 +01003714void Assembler::nop(int type) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003715 // ARMv6{K/T2} and v7 have an actual NOP instruction but it serializes
3716 // some of the CPU's pipeline and has to issue. Older ARM chips simply used
3717 // MOV Rx, Rx as NOP and it performs better even in newer CPUs.
3718 // We therefore use MOV Rx, Rx, even on newer CPUs, and use Rx to encode
3719 // a type.
3720 DCHECK(0 <= type && type <= 14); // mov pc, pc isn't a nop.
Steve Block6ded16b2010-05-10 14:33:55 +01003721 emit(al | 13*B21 | type*B12 | type);
3722}
3723
3724
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003725bool Assembler::IsMovT(Instr instr) {
3726 instr &= ~(((kNumberOfConditions - 1) << 28) | // Mask off conditions
3727 ((kNumRegisters-1)*B12) | // mask out register
3728 EncodeMovwImmediate(0xFFFF)); // mask out immediate value
3729 return instr == kMovtPattern;
3730}
3731
3732
3733bool Assembler::IsMovW(Instr instr) {
3734 instr &= ~(((kNumberOfConditions - 1) << 28) | // Mask off conditions
3735 ((kNumRegisters-1)*B12) | // mask out destination
3736 EncodeMovwImmediate(0xFFFF)); // mask out immediate value
3737 return instr == kMovwPattern;
3738}
3739
3740
3741Instr Assembler::GetMovTPattern() { return kMovtPattern; }
3742
3743
3744Instr Assembler::GetMovWPattern() { return kMovwPattern; }
3745
3746
3747Instr Assembler::EncodeMovwImmediate(uint32_t immediate) {
3748 DCHECK(immediate < 0x10000);
3749 return ((immediate & 0xf000) << 4) | (immediate & 0xfff);
3750}
3751
3752
3753Instr Assembler::PatchMovwImmediate(Instr instruction, uint32_t immediate) {
3754 instruction &= ~EncodeMovwImmediate(0xffff);
3755 return instruction | EncodeMovwImmediate(immediate);
3756}
3757
3758
3759int Assembler::DecodeShiftImm(Instr instr) {
3760 int rotate = Instruction::RotateValue(instr) * 2;
3761 int immed8 = Instruction::Immed8Value(instr);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003762 return base::bits::RotateRight32(immed8, rotate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003763}
3764
3765
3766Instr Assembler::PatchShiftImm(Instr instr, int immed) {
3767 uint32_t rotate_imm = 0;
3768 uint32_t immed_8 = 0;
3769 bool immed_fits = fits_shifter(immed, &rotate_imm, &immed_8, NULL);
3770 DCHECK(immed_fits);
3771 USE(immed_fits);
3772 return (instr & ~kOff12Mask) | (rotate_imm << 8) | immed_8;
3773}
3774
3775
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08003776bool Assembler::IsNop(Instr instr, int type) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003777 DCHECK(0 <= type && type <= 14); // mov pc, pc isn't a nop.
Steve Block1e0659c2011-05-24 12:43:12 +01003778 // Check for mov rx, rx where x = type.
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08003779 return instr == (al | 13*B21 | type*B12 | type);
3780}
3781
3782
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003783bool Assembler::IsMovImmed(Instr instr) {
3784 return (instr & kMovImmedMask) == kMovImmedPattern;
3785}
3786
3787
3788bool Assembler::IsOrrImmed(Instr instr) {
3789 return (instr & kOrrImmedMask) == kOrrImmedPattern;
3790}
3791
3792
3793// static
Steve Blockd0582a62009-12-15 09:54:21 +00003794bool Assembler::ImmediateFitsAddrMode1Instruction(int32_t imm32) {
3795 uint32_t dummy1;
3796 uint32_t dummy2;
3797 return fits_shifter(imm32, &dummy1, &dummy2, NULL);
3798}
3799
3800
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003801bool Assembler::ImmediateFitsAddrMode2Instruction(int32_t imm32) {
3802 return is_uint12(abs(imm32));
3803}
3804
3805
Andrei Popescu31002712010-02-23 13:46:05 +00003806// Debugging.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003807void Assembler::RecordConstPool(int size) {
3808 // We only need this for debugger support, to correctly compute offsets in the
3809 // code.
3810 RecordRelocInfo(RelocInfo::CONST_POOL, static_cast<intptr_t>(size));
3811}
3812
3813
Steve Blocka7e24c12009-10-30 11:49:00 +00003814void Assembler::GrowBuffer() {
3815 if (!own_buffer_) FATAL("external code buffer is too small");
3816
Andrei Popescu31002712010-02-23 13:46:05 +00003817 // Compute new buffer size.
Steve Blocka7e24c12009-10-30 11:49:00 +00003818 CodeDesc desc; // the new buffer
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003819 if (buffer_size_ < 1 * MB) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003820 desc.buffer_size = 2*buffer_size_;
3821 } else {
3822 desc.buffer_size = buffer_size_ + 1*MB;
3823 }
3824 CHECK_GT(desc.buffer_size, 0); // no overflow
3825
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003826 // Set up new buffer.
Steve Blocka7e24c12009-10-30 11:49:00 +00003827 desc.buffer = NewArray<byte>(desc.buffer_size);
3828
3829 desc.instr_size = pc_offset();
3830 desc.reloc_size = (buffer_ + buffer_size_) - reloc_info_writer.pos();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003831 desc.origin = this;
Steve Blocka7e24c12009-10-30 11:49:00 +00003832
Andrei Popescu31002712010-02-23 13:46:05 +00003833 // Copy the data.
Steve Blocka7e24c12009-10-30 11:49:00 +00003834 int pc_delta = desc.buffer - buffer_;
3835 int rc_delta = (desc.buffer + desc.buffer_size) - (buffer_ + buffer_size_);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003836 MemMove(desc.buffer, buffer_, desc.instr_size);
3837 MemMove(reloc_info_writer.pos() + rc_delta, reloc_info_writer.pos(),
3838 desc.reloc_size);
Steve Blocka7e24c12009-10-30 11:49:00 +00003839
Andrei Popescu31002712010-02-23 13:46:05 +00003840 // Switch buffers.
Steve Blocka7e24c12009-10-30 11:49:00 +00003841 DeleteArray(buffer_);
3842 buffer_ = desc.buffer;
3843 buffer_size_ = desc.buffer_size;
3844 pc_ += pc_delta;
3845 reloc_info_writer.Reposition(reloc_info_writer.pos() + rc_delta,
3846 reloc_info_writer.last_pc() + pc_delta);
3847
Andrei Popescu31002712010-02-23 13:46:05 +00003848 // None of our relocation types are pc relative pointing outside the code
Steve Blocka7e24c12009-10-30 11:49:00 +00003849 // buffer nor pc absolute pointing inside the code buffer, so there is no need
Andrei Popescu31002712010-02-23 13:46:05 +00003850 // to relocate any emitted relocation entries.
Steve Blocka7e24c12009-10-30 11:49:00 +00003851}
3852
3853
Ben Murdochb0fe1622011-05-05 13:52:32 +01003854void Assembler::db(uint8_t data) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003855 // db is used to write raw data. The constant pool should be emitted or
3856 // blocked before using db.
Ben Murdoch61f157c2016-09-16 13:49:30 +01003857 DCHECK(is_const_pool_blocked() || pending_32_bit_constants_.empty());
3858 DCHECK(is_const_pool_blocked() || pending_64_bit_constants_.empty());
Ben Murdochb0fe1622011-05-05 13:52:32 +01003859 CheckBuffer();
3860 *reinterpret_cast<uint8_t*>(pc_) = data;
3861 pc_ += sizeof(uint8_t);
3862}
3863
3864
3865void Assembler::dd(uint32_t data) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003866 // dd is used to write raw data. The constant pool should be emitted or
3867 // blocked before using dd.
Ben Murdoch61f157c2016-09-16 13:49:30 +01003868 DCHECK(is_const_pool_blocked() || pending_32_bit_constants_.empty());
3869 DCHECK(is_const_pool_blocked() || pending_64_bit_constants_.empty());
Ben Murdochb0fe1622011-05-05 13:52:32 +01003870 CheckBuffer();
3871 *reinterpret_cast<uint32_t*>(pc_) = data;
3872 pc_ += sizeof(uint32_t);
3873}
3874
3875
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003876void Assembler::dq(uint64_t value) {
3877 // dq is used to write raw data. The constant pool should be emitted or
3878 // blocked before using dq.
Ben Murdoch61f157c2016-09-16 13:49:30 +01003879 DCHECK(is_const_pool_blocked() || pending_32_bit_constants_.empty());
3880 DCHECK(is_const_pool_blocked() || pending_64_bit_constants_.empty());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003881 CheckBuffer();
3882 *reinterpret_cast<uint64_t*>(pc_) = value;
3883 pc_ += sizeof(uint64_t);
3884}
3885
3886
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003887void Assembler::emit_code_stub_address(Code* stub) {
3888 CheckBuffer();
3889 *reinterpret_cast<uint32_t*>(pc_) =
3890 reinterpret_cast<uint32_t>(stub->instruction_start());
3891 pc_ += sizeof(uint32_t);
3892}
3893
3894
Steve Blocka7e24c12009-10-30 11:49:00 +00003895void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003896 if (RelocInfo::IsNone(rmode) ||
3897 // Don't record external references unless the heap will be serialized.
3898 (rmode == RelocInfo::EXTERNAL_REFERENCE && !serializer_enabled() &&
3899 !emit_debug_code())) {
3900 return;
3901 }
3902 DCHECK(buffer_space() >= kMaxRelocSize); // too late to grow buffer here
3903 if (rmode == RelocInfo::CODE_TARGET_WITH_ID) {
3904 data = RecordedAstId().ToInt();
3905 ClearRecordedAstId();
3906 }
3907 RelocInfo rinfo(isolate(), pc_, rmode, data, NULL);
3908 reloc_info_writer.Write(&rinfo);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003909}
3910
3911
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003912ConstantPoolEntry::Access Assembler::ConstantPoolAddEntry(int position,
3913 RelocInfo::Mode rmode,
3914 intptr_t value) {
3915 DCHECK(rmode != RelocInfo::COMMENT && rmode != RelocInfo::POSITION &&
3916 rmode != RelocInfo::STATEMENT_POSITION &&
3917 rmode != RelocInfo::CONST_POOL && rmode != RelocInfo::NONE64);
3918 bool sharing_ok = RelocInfo::IsNone(rmode) ||
3919 !(serializer_enabled() || rmode < RelocInfo::CELL);
3920 if (FLAG_enable_embedded_constant_pool) {
3921 return constant_pool_builder_.AddEntry(position, value, sharing_ok);
3922 } else {
Ben Murdoch61f157c2016-09-16 13:49:30 +01003923 DCHECK(pending_32_bit_constants_.size() < kMaxNumPending32Constants);
3924 if (pending_32_bit_constants_.empty()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003925 first_const_pool_32_use_ = position;
Steve Blocka7e24c12009-10-30 11:49:00 +00003926 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003927 ConstantPoolEntry entry(position, value, sharing_ok);
Ben Murdoch61f157c2016-09-16 13:49:30 +01003928 pending_32_bit_constants_.push_back(entry);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003929
3930 // Make sure the constant pool is not emitted in place of the next
3931 // instruction for which we just recorded relocation info.
3932 BlockConstPoolFor(1);
3933 return ConstantPoolEntry::REGULAR;
Steve Blocka7e24c12009-10-30 11:49:00 +00003934 }
3935}
3936
3937
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003938ConstantPoolEntry::Access Assembler::ConstantPoolAddEntry(int position,
3939 double value) {
3940 if (FLAG_enable_embedded_constant_pool) {
3941 return constant_pool_builder_.AddEntry(position, value);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003942 } else {
Ben Murdoch61f157c2016-09-16 13:49:30 +01003943 DCHECK(pending_64_bit_constants_.size() < kMaxNumPending64Constants);
3944 if (pending_64_bit_constants_.empty()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003945 first_const_pool_64_use_ = position;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003946 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003947 ConstantPoolEntry entry(position, value);
Ben Murdoch61f157c2016-09-16 13:49:30 +01003948 pending_64_bit_constants_.push_back(entry);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003949
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003950 // Make sure the constant pool is not emitted in place of the next
3951 // instruction for which we just recorded relocation info.
3952 BlockConstPoolFor(1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003953 return ConstantPoolEntry::REGULAR;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003954 }
3955}
3956
3957
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003958void Assembler::BlockConstPoolFor(int instructions) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003959 if (FLAG_enable_embedded_constant_pool) {
3960 // Should be a no-op if using an embedded constant pool.
Ben Murdoch61f157c2016-09-16 13:49:30 +01003961 DCHECK(pending_32_bit_constants_.empty());
3962 DCHECK(pending_64_bit_constants_.empty());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003963 return;
3964 }
3965
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003966 int pc_limit = pc_offset() + instructions * kInstrSize;
3967 if (no_const_pool_before_ < pc_limit) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003968 // Max pool start (if we need a jump and an alignment).
3969#ifdef DEBUG
3970 int start = pc_limit + kInstrSize + 2 * kPointerSize;
Ben Murdoch61f157c2016-09-16 13:49:30 +01003971 DCHECK(pending_32_bit_constants_.empty() ||
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003972 (start - first_const_pool_32_use_ +
Ben Murdoch61f157c2016-09-16 13:49:30 +01003973 pending_64_bit_constants_.size() * kDoubleSize <
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003974 kMaxDistToIntPool));
Ben Murdoch61f157c2016-09-16 13:49:30 +01003975 DCHECK(pending_64_bit_constants_.empty() ||
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003976 (start - first_const_pool_64_use_ < kMaxDistToFPPool));
3977#endif
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003978 no_const_pool_before_ = pc_limit;
Steve Blocka7e24c12009-10-30 11:49:00 +00003979 }
3980
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003981 if (next_buffer_check_ < no_const_pool_before_) {
3982 next_buffer_check_ = no_const_pool_before_;
3983 }
3984}
Steve Blocka7e24c12009-10-30 11:49:00 +00003985
Steve Blocka7e24c12009-10-30 11:49:00 +00003986
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003987void Assembler::CheckConstPool(bool force_emit, bool require_jump) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003988 if (FLAG_enable_embedded_constant_pool) {
3989 // Should be a no-op if using an embedded constant pool.
Ben Murdoch61f157c2016-09-16 13:49:30 +01003990 DCHECK(pending_32_bit_constants_.empty());
3991 DCHECK(pending_64_bit_constants_.empty());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003992 return;
3993 }
3994
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003995 // Some short sequence of instruction mustn't be broken up by constant pool
3996 // emission, such sequences are protected by calls to BlockConstPoolFor and
3997 // BlockConstPoolScope.
3998 if (is_const_pool_blocked()) {
Andrei Popescu31002712010-02-23 13:46:05 +00003999 // Something is wrong if emission is forced and blocked at the same time.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004000 DCHECK(!force_emit);
Steve Blocka7e24c12009-10-30 11:49:00 +00004001 return;
4002 }
4003
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004004 // There is nothing to do if there are no pending constant pool entries.
Ben Murdoch61f157c2016-09-16 13:49:30 +01004005 if (pending_32_bit_constants_.empty() && pending_64_bit_constants_.empty()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004006 // Calculate the offset of the next check.
4007 next_buffer_check_ = pc_offset() + kCheckPoolInterval;
4008 return;
4009 }
4010
Steve Blocka7e24c12009-10-30 11:49:00 +00004011 // Check that the code buffer is large enough before emitting the constant
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004012 // pool (include the jump over the pool and the constant pool marker and
4013 // the gap to the relocation information).
4014 int jump_instr = require_jump ? kInstrSize : 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004015 int size_up_to_marker = jump_instr + kInstrSize;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004016 int estimated_size_after_marker =
Ben Murdoch61f157c2016-09-16 13:49:30 +01004017 pending_32_bit_constants_.size() * kPointerSize;
4018 bool has_int_values = !pending_32_bit_constants_.empty();
4019 bool has_fp_values = !pending_64_bit_constants_.empty();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004020 bool require_64_bit_align = false;
4021 if (has_fp_values) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004022 require_64_bit_align =
4023 !IsAligned(reinterpret_cast<intptr_t>(pc_ + size_up_to_marker),
4024 kDoubleAlignment);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004025 if (require_64_bit_align) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004026 estimated_size_after_marker += kInstrSize;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004027 }
Ben Murdoch61f157c2016-09-16 13:49:30 +01004028 estimated_size_after_marker +=
4029 pending_64_bit_constants_.size() * kDoubleSize;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004030 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004031 int estimated_size = size_up_to_marker + estimated_size_after_marker;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004032
4033 // We emit a constant pool when:
4034 // * requested to do so by parameter force_emit (e.g. after each function).
4035 // * the distance from the first instruction accessing the constant pool to
4036 // any of the constant pool entries will exceed its limit the next
4037 // time the pool is checked. This is overly restrictive, but we don't emit
4038 // constant pool entries in-order so it's conservatively correct.
4039 // * the instruction doesn't require a jump after itself to jump over the
4040 // constant pool, and we're getting close to running out of range.
4041 if (!force_emit) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004042 DCHECK(has_fp_values || has_int_values);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004043 bool need_emit = false;
4044 if (has_fp_values) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004045 // The 64-bit constants are always emitted before the 32-bit constants, so
4046 // we can ignore the effect of the 32-bit constants on estimated_size.
4047 int dist64 = pc_offset() + estimated_size -
Ben Murdoch61f157c2016-09-16 13:49:30 +01004048 pending_32_bit_constants_.size() * kPointerSize -
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004049 first_const_pool_64_use_;
4050 if ((dist64 >= kMaxDistToFPPool - kCheckPoolInterval) ||
4051 (!require_jump && (dist64 >= kMaxDistToFPPool / 2))) {
4052 need_emit = true;
4053 }
4054 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004055 if (has_int_values) {
4056 int dist32 = pc_offset() + estimated_size - first_const_pool_32_use_;
4057 if ((dist32 >= kMaxDistToIntPool - kCheckPoolInterval) ||
4058 (!require_jump && (dist32 >= kMaxDistToIntPool / 2))) {
4059 need_emit = true;
4060 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004061 }
4062 if (!need_emit) return;
4063 }
4064
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004065 // Deduplicate constants.
4066 int size_after_marker = estimated_size_after_marker;
Ben Murdoch61f157c2016-09-16 13:49:30 +01004067 for (int i = 0; i < pending_64_bit_constants_.size(); i++) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004068 ConstantPoolEntry& entry = pending_64_bit_constants_[i];
4069 DCHECK(!entry.is_merged());
4070 for (int j = 0; j < i; j++) {
4071 if (entry.value64() == pending_64_bit_constants_[j].value64()) {
4072 DCHECK(!pending_64_bit_constants_[j].is_merged());
4073 entry.set_merged_index(j);
4074 size_after_marker -= kDoubleSize;
4075 break;
4076 }
4077 }
4078 }
4079
Ben Murdoch61f157c2016-09-16 13:49:30 +01004080 for (int i = 0; i < pending_32_bit_constants_.size(); i++) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004081 ConstantPoolEntry& entry = pending_32_bit_constants_[i];
4082 DCHECK(!entry.is_merged());
4083 if (!entry.sharing_ok()) continue;
4084 for (int j = 0; j < i; j++) {
4085 if (entry.value() == pending_32_bit_constants_[j].value()) {
4086 DCHECK(!pending_32_bit_constants_[j].is_merged());
4087 entry.set_merged_index(j);
4088 size_after_marker -= kPointerSize;
4089 break;
4090 }
4091 }
4092 }
4093
4094 int size = size_up_to_marker + size_after_marker;
4095
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004096 int needed_space = size + kGap;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004097 while (buffer_space() <= needed_space) GrowBuffer();
Steve Blocka7e24c12009-10-30 11:49:00 +00004098
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004099 {
4100 // Block recursive calls to CheckConstPool.
4101 BlockConstPoolScope block_const_pool(this);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004102 RecordComment("[ Constant Pool");
4103 RecordConstPool(size);
Steve Blocka7e24c12009-10-30 11:49:00 +00004104
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004105 Label size_check;
4106 bind(&size_check);
4107
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004108 // Emit jump over constant pool if necessary.
4109 Label after_pool;
4110 if (require_jump) {
4111 b(&after_pool);
Steve Blocka7e24c12009-10-30 11:49:00 +00004112 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004113
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004114 // Put down constant pool marker "Undefined instruction".
4115 // The data size helps disassembly know what to print.
4116 emit(kConstantPoolMarker |
4117 EncodeConstantPoolLength(size_after_marker / kPointerSize));
Steve Blocka7e24c12009-10-30 11:49:00 +00004118
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004119 if (require_64_bit_align) {
4120 emit(kConstantPoolMarker);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004121 }
4122
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004123 // Emit 64-bit constant pool entries first: their range is smaller than
4124 // 32-bit entries.
Ben Murdoch61f157c2016-09-16 13:49:30 +01004125 for (int i = 0; i < pending_64_bit_constants_.size(); i++) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004126 ConstantPoolEntry& entry = pending_64_bit_constants_[i];
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004127
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004128 Instr instr = instr_at(entry.position());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004129 // Instruction to patch must be 'vldr rd, [pc, #offset]' with offset == 0.
4130 DCHECK((IsVldrDPcImmediateOffset(instr) &&
4131 GetVldrDRegisterImmediateOffset(instr) == 0));
4132
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004133 int delta = pc_offset() - entry.position() - kPcLoadDelta;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004134 DCHECK(is_uint10(delta));
4135
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004136 if (entry.is_merged()) {
4137 ConstantPoolEntry& merged =
4138 pending_64_bit_constants_[entry.merged_index()];
4139 DCHECK(entry.value64() == merged.value64());
4140 Instr merged_instr = instr_at(merged.position());
4141 DCHECK(IsVldrDPcImmediateOffset(merged_instr));
4142 delta = GetVldrDRegisterImmediateOffset(merged_instr);
4143 delta += merged.position() - entry.position();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004144 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004145 instr_at_put(entry.position(),
4146 SetVldrDRegisterImmediateOffset(instr, delta));
4147 if (!entry.is_merged()) {
4148 DCHECK(IsAligned(reinterpret_cast<intptr_t>(pc_), kDoubleAlignment));
4149 dq(entry.value64());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004150 }
4151 }
4152
4153 // Emit 32-bit constant pool entries.
Ben Murdoch61f157c2016-09-16 13:49:30 +01004154 for (int i = 0; i < pending_32_bit_constants_.size(); i++) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004155 ConstantPoolEntry& entry = pending_32_bit_constants_[i];
4156 Instr instr = instr_at(entry.position());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004157
4158 // 64-bit loads shouldn't get here.
4159 DCHECK(!IsVldrDPcImmediateOffset(instr));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004160 DCHECK(!IsMovW(instr));
4161 DCHECK(IsLdrPcImmediateOffset(instr) &&
4162 GetLdrRegisterImmediateOffset(instr) == 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004163
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004164 int delta = pc_offset() - entry.position() - kPcLoadDelta;
4165 DCHECK(is_uint12(delta));
4166 // 0 is the smallest delta:
4167 // ldr rd, [pc, #0]
4168 // constant pool marker
4169 // data
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004170
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004171 if (entry.is_merged()) {
4172 DCHECK(entry.sharing_ok());
4173 ConstantPoolEntry& merged =
4174 pending_32_bit_constants_[entry.merged_index()];
4175 DCHECK(entry.value() == merged.value());
4176 Instr merged_instr = instr_at(merged.position());
4177 DCHECK(IsLdrPcImmediateOffset(merged_instr));
4178 delta = GetLdrRegisterImmediateOffset(merged_instr);
4179 delta += merged.position() - entry.position();
4180 }
4181 instr_at_put(entry.position(),
4182 SetLdrRegisterImmediateOffset(instr, delta));
4183 if (!entry.is_merged()) {
4184 emit(entry.value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004185 }
4186 }
4187
Ben Murdoch61f157c2016-09-16 13:49:30 +01004188 pending_32_bit_constants_.clear();
4189 pending_64_bit_constants_.clear();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004190 first_const_pool_32_use_ = -1;
4191 first_const_pool_64_use_ = -1;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004192
4193 RecordComment("]");
4194
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004195 DCHECK_EQ(size, SizeOfCodeGeneratedSince(&size_check));
4196
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004197 if (after_pool.is_linked()) {
4198 bind(&after_pool);
4199 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004200 }
4201
4202 // Since a constant pool was just emitted, move the check offset forward by
4203 // the standard interval.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004204 next_buffer_check_ = pc_offset() + kCheckPoolInterval;
Steve Blocka7e24c12009-10-30 11:49:00 +00004205}
4206
4207
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004208void Assembler::PatchConstantPoolAccessInstruction(
4209 int pc_offset, int offset, ConstantPoolEntry::Access access,
4210 ConstantPoolEntry::Type type) {
4211 DCHECK(FLAG_enable_embedded_constant_pool);
4212 Address pc = buffer_ + pc_offset;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004213
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004214 // Patch vldr/ldr instruction with correct offset.
4215 Instr instr = instr_at(pc);
4216 if (access == ConstantPoolEntry::OVERFLOWED) {
4217 if (CpuFeatures::IsSupported(ARMv7)) {
4218 // Instructions to patch must be 'movw rd, [#0]' and 'movt rd, [#0].
4219 Instr next_instr = instr_at(pc + kInstrSize);
4220 DCHECK((IsMovW(instr) && Instruction::ImmedMovwMovtValue(instr) == 0));
4221 DCHECK((IsMovT(next_instr) &&
4222 Instruction::ImmedMovwMovtValue(next_instr) == 0));
4223 instr_at_put(pc, PatchMovwImmediate(instr, offset & 0xffff));
4224 instr_at_put(pc + kInstrSize,
4225 PatchMovwImmediate(next_instr, offset >> 16));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004226 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004227 // Instructions to patch must be 'mov rd, [#0]' and 'orr rd, rd, [#0].
4228 Instr instr_2 = instr_at(pc + kInstrSize);
4229 Instr instr_3 = instr_at(pc + 2 * kInstrSize);
4230 Instr instr_4 = instr_at(pc + 3 * kInstrSize);
4231 DCHECK((IsMovImmed(instr) && Instruction::Immed8Value(instr) == 0));
4232 DCHECK((IsOrrImmed(instr_2) && Instruction::Immed8Value(instr_2) == 0) &&
4233 GetRn(instr_2).is(GetRd(instr_2)));
4234 DCHECK((IsOrrImmed(instr_3) && Instruction::Immed8Value(instr_3) == 0) &&
4235 GetRn(instr_3).is(GetRd(instr_3)));
4236 DCHECK((IsOrrImmed(instr_4) && Instruction::Immed8Value(instr_4) == 0) &&
4237 GetRn(instr_4).is(GetRd(instr_4)));
4238 instr_at_put(pc, PatchShiftImm(instr, (offset & kImm8Mask)));
4239 instr_at_put(pc + kInstrSize,
4240 PatchShiftImm(instr_2, (offset & (kImm8Mask << 8))));
4241 instr_at_put(pc + 2 * kInstrSize,
4242 PatchShiftImm(instr_3, (offset & (kImm8Mask << 16))));
4243 instr_at_put(pc + 3 * kInstrSize,
4244 PatchShiftImm(instr_4, (offset & (kImm8Mask << 24))));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004245 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004246 } else if (type == ConstantPoolEntry::DOUBLE) {
4247 // Instruction to patch must be 'vldr rd, [pp, #0]'.
4248 DCHECK((IsVldrDPpImmediateOffset(instr) &&
4249 GetVldrDRegisterImmediateOffset(instr) == 0));
4250 DCHECK(is_uint10(offset));
4251 instr_at_put(pc, SetVldrDRegisterImmediateOffset(instr, offset));
4252 } else {
4253 // Instruction to patch must be 'ldr rd, [pp, #0]'.
4254 DCHECK((IsLdrPpImmediateOffset(instr) &&
4255 GetLdrRegisterImmediateOffset(instr) == 0));
4256 DCHECK(is_uint12(offset));
4257 instr_at_put(pc, SetLdrRegisterImmediateOffset(instr, offset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004258 }
4259}
4260
4261
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004262} // namespace internal
4263} // namespace v8
Leon Clarkef7060e22010-06-03 12:02:55 +01004264
4265#endif // V8_TARGET_ARCH_ARM