blob: e58d968c5fb4bf00644abb652cf92bcf16c09279 [file] [log] [blame]
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001// Copyright (c) 1994-2006 Sun Microsystems Inc.
2// All Rights Reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003//
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004// 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.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000019//
20// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000022// 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
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000033// The original source code covered by the above license above has been
34// modified significantly by Google Inc.
35// Copyright 2010 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000036
37#include "v8.h"
38
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000039#if defined(V8_TARGET_ARCH_ARM)
40
ager@chromium.org3a37e9b2009-04-27 09:26:21 +000041#include "arm/assembler-arm-inl.h"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000042#include "serialize.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000043
kasperl@chromium.org71affb52009-05-26 05:44:31 +000044namespace v8 {
45namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000046
ager@chromium.orgc4c92722009-11-18 14:12:51 +000047// Safe default is no features.
48unsigned CpuFeatures::supported_ = 0;
49unsigned CpuFeatures::enabled_ = 0;
50unsigned CpuFeatures::found_by_runtime_probing_ = 0;
51
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000052
53#ifdef __arm__
54static uint64_t CpuFeaturesImpliedByCompiler() {
55 uint64_t answer = 0;
56#ifdef CAN_USE_ARMV7_INSTRUCTIONS
57 answer |= 1u << ARMv7;
58#endif // def CAN_USE_ARMV7_INSTRUCTIONS
59 // If the compiler is allowed to use VFP then we can use VFP too in our code
60 // generation even when generating snapshots. This won't work for cross
61 // compilation.
62#if defined(__VFP_FP__) && !defined(__SOFTFP__)
63 answer |= 1u << VFP3;
64#endif // defined(__VFP_FP__) && !defined(__SOFTFP__)
65#ifdef CAN_USE_VFP_INSTRUCTIONS
66 answer |= 1u << VFP3;
67#endif // def CAN_USE_VFP_INSTRUCTIONS
68 return answer;
69}
70#endif // def __arm__
71
72
kasperl@chromium.orga5551262010-12-07 12:49:48 +000073void CpuFeatures::Probe(bool portable) {
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000074#ifndef __arm__
ager@chromium.org5c838252010-02-19 08:53:10 +000075 // For the simulator=arm build, use VFP when FLAG_enable_vfp3 is enabled.
76 if (FLAG_enable_vfp3) {
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000077 supported_ |= 1u << VFP3;
ager@chromium.org5c838252010-02-19 08:53:10 +000078 }
79 // For the simulator=arm build, use ARMv7 when FLAG_enable_armv7 is enabled
80 if (FLAG_enable_armv7) {
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000081 supported_ |= 1u << ARMv7;
ager@chromium.org5c838252010-02-19 08:53:10 +000082 }
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000083#else // def __arm__
kasperl@chromium.orga5551262010-12-07 12:49:48 +000084 if (portable && Serializer::enabled()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +000085 supported_ |= OS::CpuFeaturesImpliedByPlatform();
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000086 supported_ |= CpuFeaturesImpliedByCompiler();
ager@chromium.orgc4c92722009-11-18 14:12:51 +000087 return; // No features if we might serialize.
88 }
89
90 if (OS::ArmCpuHasFeature(VFP3)) {
91 // This implementation also sets the VFP flags if
92 // runtime detection of VFP returns true.
93 supported_ |= 1u << VFP3;
94 found_by_runtime_probing_ |= 1u << VFP3;
95 }
ager@chromium.org5c838252010-02-19 08:53:10 +000096
97 if (OS::ArmCpuHasFeature(ARMv7)) {
98 supported_ |= 1u << ARMv7;
99 found_by_runtime_probing_ |= 1u << ARMv7;
100 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000101
102 if (!portable) found_by_runtime_probing_ = 0;
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000103#endif
104}
105
106
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000107// -----------------------------------------------------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000108// Implementation of RelocInfo
109
110const int RelocInfo::kApplyMask = 0;
111
112
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000113bool RelocInfo::IsCodedSpecially() {
114 // The deserializer needs to know whether a pointer is specially coded. Being
115 // specially coded on ARM means that it is a movw/movt instruction. We don't
116 // generate those yet.
117 return false;
118}
119
120
121
iposva@chromium.org245aa852009-02-10 00:49:54 +0000122void RelocInfo::PatchCode(byte* instructions, int instruction_count) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000123 // Patch the code at the current address with the supplied instructions.
ager@chromium.org4af710e2009-09-15 12:20:11 +0000124 Instr* pc = reinterpret_cast<Instr*>(pc_);
125 Instr* instr = reinterpret_cast<Instr*>(instructions);
126 for (int i = 0; i < instruction_count; i++) {
127 *(pc + i) = *(instr + i);
128 }
129
130 // Indicate that code has changed.
131 CPU::FlushICache(pc_, instruction_count * Assembler::kInstrSize);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000132}
133
134
135// Patch the code at the current PC with a call to the target address.
iposva@chromium.org245aa852009-02-10 00:49:54 +0000136// Additional guard instructions can be added if required.
137void RelocInfo::PatchCodeWithCall(Address target, int guard_bytes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000138 // Patch the code at the current address with a call to the target.
139 UNIMPLEMENTED();
140}
141
142
143// -----------------------------------------------------------------------------
144// Implementation of Operand and MemOperand
145// See assembler-arm-inl.h for inlined constructors
146
147Operand::Operand(Handle<Object> handle) {
148 rm_ = no_reg;
149 // Verify all Objects referred by code are NOT in new space.
150 Object* obj = *handle;
151 ASSERT(!Heap::InNewSpace(obj));
152 if (obj->IsHeapObject()) {
153 imm32_ = reinterpret_cast<intptr_t>(handle.location());
ager@chromium.org236ad962008-09-25 09:45:57 +0000154 rmode_ = RelocInfo::EMBEDDED_OBJECT;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000155 } else {
156 // no relocation needed
157 imm32_ = reinterpret_cast<intptr_t>(obj);
ager@chromium.org236ad962008-09-25 09:45:57 +0000158 rmode_ = RelocInfo::NONE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000159 }
160}
161
162
163Operand::Operand(Register rm, ShiftOp shift_op, int shift_imm) {
164 ASSERT(is_uint5(shift_imm));
165 ASSERT(shift_op != ROR || shift_imm != 0); // use RRX if you mean it
166 rm_ = rm;
167 rs_ = no_reg;
168 shift_op_ = shift_op;
169 shift_imm_ = shift_imm & 31;
170 if (shift_op == RRX) {
171 // encoded as ROR with shift_imm == 0
172 ASSERT(shift_imm == 0);
173 shift_op_ = ROR;
174 shift_imm_ = 0;
175 }
176}
177
178
179Operand::Operand(Register rm, ShiftOp shift_op, Register rs) {
180 ASSERT(shift_op != RRX);
181 rm_ = rm;
182 rs_ = no_reg;
183 shift_op_ = shift_op;
184 rs_ = rs;
185}
186
187
188MemOperand::MemOperand(Register rn, int32_t offset, AddrMode am) {
189 rn_ = rn;
190 rm_ = no_reg;
191 offset_ = offset;
192 am_ = am;
193}
194
195MemOperand::MemOperand(Register rn, Register rm, AddrMode am) {
196 rn_ = rn;
197 rm_ = rm;
198 shift_op_ = LSL;
199 shift_imm_ = 0;
200 am_ = am;
201}
202
203
204MemOperand::MemOperand(Register rn, Register rm,
205 ShiftOp shift_op, int shift_imm, AddrMode am) {
206 ASSERT(is_uint5(shift_imm));
207 rn_ = rn;
208 rm_ = rm;
209 shift_op_ = shift_op;
210 shift_imm_ = shift_imm & 31;
211 am_ = am;
212}
213
214
215// -----------------------------------------------------------------------------
ager@chromium.org378b34e2011-01-28 08:04:38 +0000216// Specific instructions, constants, and masks.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000217
mads.s.ager31e71382008-08-13 09:32:07 +0000218// add(sp, sp, 4) instruction (aka Pop())
ager@chromium.org378b34e2011-01-28 08:04:38 +0000219const Instr kPopInstruction =
220 al | PostIndex | 4 | LeaveCC | I | sp.code() * B16 | sp.code() * B12;
mads.s.ager31e71382008-08-13 09:32:07 +0000221// str(r, MemOperand(sp, 4, NegPreIndex), al) instruction (aka push(r))
222// register r is not encoded.
ager@chromium.org378b34e2011-01-28 08:04:38 +0000223const Instr kPushRegPattern =
mads.s.ager31e71382008-08-13 09:32:07 +0000224 al | B26 | 4 | NegPreIndex | sp.code() * B16;
225// ldr(r, MemOperand(sp, 4, PostIndex), al) instruction (aka pop(r))
226// register r is not encoded.
ager@chromium.org378b34e2011-01-28 08:04:38 +0000227const Instr kPopRegPattern =
mads.s.ager31e71382008-08-13 09:32:07 +0000228 al | B26 | L | 4 | PostIndex | sp.code() * B16;
ager@chromium.org4af710e2009-09-15 12:20:11 +0000229// mov lr, pc
ager@chromium.org378b34e2011-01-28 08:04:38 +0000230const Instr kMovLrPc = al | MOV | pc.code() | lr.code() * B12;
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000231// ldr rd, [pc, #offset]
ager@chromium.org378b34e2011-01-28 08:04:38 +0000232const Instr kLdrPCMask = kCondMask | 15 * B24 | 7 * B20 | 15 * B16;
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000233const Instr kLdrPCPattern = al | 5 * B24 | L | pc.code() * B16;
234// blxcc rm
235const Instr kBlxRegMask =
236 15 * B24 | 15 * B20 | 15 * B16 | 15 * B12 | 15 * B8 | 15 * B4;
237const Instr kBlxRegPattern =
ager@chromium.org378b34e2011-01-28 08:04:38 +0000238 B24 | B21 | 15 * B16 | 15 * B12 | 15 * B8 | BLX;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000239const Instr kMovMvnMask = 0x6d * B21 | 0xf * B16;
240const Instr kMovMvnPattern = 0xd * B21;
241const Instr kMovMvnFlip = B22;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000242const Instr kMovLeaveCCMask = 0xdff * B16;
243const Instr kMovLeaveCCPattern = 0x1a0 * B16;
244const Instr kMovwMask = 0xff * B20;
245const Instr kMovwPattern = 0x30 * B20;
246const Instr kMovwLeaveCCFlip = 0x5 * B21;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000247const Instr kCmpCmnMask = 0xdd * B20 | 0xf * B12;
248const Instr kCmpCmnPattern = 0x15 * B20;
249const Instr kCmpCmnFlip = B21;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000250const Instr kAddSubFlip = 0x6 * B21;
251const Instr kAndBicFlip = 0xe * B21;
252
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000253// A mask for the Rd register for push, pop, ldr, str instructions.
ager@chromium.org378b34e2011-01-28 08:04:38 +0000254const Instr kLdrRegFpOffsetPattern =
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000255 al | B26 | L | Offset | fp.code() * B16;
ager@chromium.org378b34e2011-01-28 08:04:38 +0000256const Instr kStrRegFpOffsetPattern =
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000257 al | B26 | Offset | fp.code() * B16;
ager@chromium.org378b34e2011-01-28 08:04:38 +0000258const Instr kLdrRegFpNegOffsetPattern =
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000259 al | B26 | L | NegOffset | fp.code() * B16;
ager@chromium.org378b34e2011-01-28 08:04:38 +0000260const Instr kStrRegFpNegOffsetPattern =
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000261 al | B26 | NegOffset | fp.code() * B16;
ager@chromium.org378b34e2011-01-28 08:04:38 +0000262const Instr kLdrStrInstrTypeMask = 0xffff0000;
263const Instr kLdrStrInstrArgumentMask = 0x0000ffff;
264const Instr kLdrStrOffsetMask = 0x00000fff;
265
mads.s.ager31e71382008-08-13 09:32:07 +0000266
ager@chromium.org5c838252010-02-19 08:53:10 +0000267// Spare buffer.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000268static const int kMinimalBufferSize = 4*KB;
269static byte* spare_buffer_ = NULL;
270
ager@chromium.org378b34e2011-01-28 08:04:38 +0000271
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000272Assembler::Assembler(void* buffer, int buffer_size)
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000273 : positions_recorder_(this),
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000274 allow_peephole_optimization_(false),
275 emit_debug_code_(FLAG_debug_code) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000276 allow_peephole_optimization_ = FLAG_peephole_optimization;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000277 if (buffer == NULL) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000278 // Do our own buffer management.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000279 if (buffer_size <= kMinimalBufferSize) {
280 buffer_size = kMinimalBufferSize;
281
282 if (spare_buffer_ != NULL) {
283 buffer = spare_buffer_;
284 spare_buffer_ = NULL;
285 }
286 }
287 if (buffer == NULL) {
288 buffer_ = NewArray<byte>(buffer_size);
289 } else {
290 buffer_ = static_cast<byte*>(buffer);
291 }
292 buffer_size_ = buffer_size;
293 own_buffer_ = true;
294
295 } else {
ager@chromium.org5c838252010-02-19 08:53:10 +0000296 // Use externally provided buffer instead.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000297 ASSERT(buffer_size > 0);
298 buffer_ = static_cast<byte*>(buffer);
299 buffer_size_ = buffer_size;
300 own_buffer_ = false;
301 }
302
ager@chromium.org5c838252010-02-19 08:53:10 +0000303 // Setup buffer pointers.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000304 ASSERT(buffer_ != NULL);
305 pc_ = buffer_;
306 reloc_info_writer.Reposition(buffer_ + buffer_size, pc_);
307 num_prinfo_ = 0;
308 next_buffer_check_ = 0;
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000309 const_pool_blocked_nesting_ = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000310 no_const_pool_before_ = 0;
311 last_const_pool_end_ = 0;
312 last_bound_pos_ = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000313}
314
315
316Assembler::~Assembler() {
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000317 ASSERT(const_pool_blocked_nesting_ == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000318 if (own_buffer_) {
319 if (spare_buffer_ == NULL && buffer_size_ == kMinimalBufferSize) {
320 spare_buffer_ = buffer_;
321 } else {
322 DeleteArray(buffer_);
323 }
324 }
325}
326
327
328void Assembler::GetCode(CodeDesc* desc) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000329 // Emit constant pool if necessary.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000330 CheckConstPool(true, false);
331 ASSERT(num_prinfo_ == 0);
332
ager@chromium.org5c838252010-02-19 08:53:10 +0000333 // Setup code descriptor.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000334 desc->buffer = buffer_;
335 desc->buffer_size = buffer_size_;
336 desc->instr_size = pc_offset();
337 desc->reloc_size = (buffer_ + buffer_size_) - reloc_info_writer.pos();
338}
339
340
341void Assembler::Align(int m) {
342 ASSERT(m >= 4 && IsPowerOf2(m));
343 while ((pc_offset() & (m - 1)) != 0) {
344 nop();
345 }
346}
347
348
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000349void Assembler::CodeTargetAlign() {
350 // Preferred alignment of jump targets on some ARM chips.
351 Align(8);
352}
353
354
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000355Condition Assembler::GetCondition(Instr instr) {
356 return Instruction::ConditionField(instr);
357}
358
359
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000360bool Assembler::IsBranch(Instr instr) {
361 return (instr & (B27 | B25)) == (B27 | B25);
362}
363
364
365int Assembler::GetBranchOffset(Instr instr) {
366 ASSERT(IsBranch(instr));
367 // Take the jump offset in the lower 24 bits, sign extend it and multiply it
368 // with 4 to get the offset in bytes.
ager@chromium.org378b34e2011-01-28 08:04:38 +0000369 return ((instr & kImm24Mask) << 8) >> 6;
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000370}
371
372
373bool Assembler::IsLdrRegisterImmediate(Instr instr) {
374 return (instr & (B27 | B26 | B25 | B22 | B20)) == (B26 | B20);
375}
376
377
378int Assembler::GetLdrRegisterImmediateOffset(Instr instr) {
379 ASSERT(IsLdrRegisterImmediate(instr));
380 bool positive = (instr & B23) == B23;
ager@chromium.org378b34e2011-01-28 08:04:38 +0000381 int offset = instr & kOff12Mask; // Zero extended offset.
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000382 return positive ? offset : -offset;
383}
384
385
386Instr Assembler::SetLdrRegisterImmediateOffset(Instr instr, int offset) {
387 ASSERT(IsLdrRegisterImmediate(instr));
388 bool positive = offset >= 0;
389 if (!positive) offset = -offset;
390 ASSERT(is_uint12(offset));
391 // Set bit indicating whether the offset should be added.
392 instr = (instr & ~B23) | (positive ? B23 : 0);
393 // Set the actual offset.
ager@chromium.org378b34e2011-01-28 08:04:38 +0000394 return (instr & ~kOff12Mask) | offset;
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000395}
396
397
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000398bool Assembler::IsStrRegisterImmediate(Instr instr) {
399 return (instr & (B27 | B26 | B25 | B22 | B20)) == B26;
400}
401
402
403Instr Assembler::SetStrRegisterImmediateOffset(Instr instr, int offset) {
404 ASSERT(IsStrRegisterImmediate(instr));
405 bool positive = offset >= 0;
406 if (!positive) offset = -offset;
407 ASSERT(is_uint12(offset));
408 // Set bit indicating whether the offset should be added.
409 instr = (instr & ~B23) | (positive ? B23 : 0);
410 // Set the actual offset.
ager@chromium.org378b34e2011-01-28 08:04:38 +0000411 return (instr & ~kOff12Mask) | offset;
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000412}
413
414
415bool Assembler::IsAddRegisterImmediate(Instr instr) {
416 return (instr & (B27 | B26 | B25 | B24 | B23 | B22 | B21)) == (B25 | B23);
417}
418
419
420Instr Assembler::SetAddRegisterImmediateOffset(Instr instr, int offset) {
421 ASSERT(IsAddRegisterImmediate(instr));
422 ASSERT(offset >= 0);
423 ASSERT(is_uint12(offset));
424 // Set the offset.
ager@chromium.org378b34e2011-01-28 08:04:38 +0000425 return (instr & ~kOff12Mask) | offset;
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000426}
427
428
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000429Register Assembler::GetRd(Instr instr) {
430 Register reg;
ager@chromium.org378b34e2011-01-28 08:04:38 +0000431 reg.code_ = Instruction::RdValue(instr);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000432 return reg;
433}
434
435
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000436Register Assembler::GetRn(Instr instr) {
437 Register reg;
438 reg.code_ = Instruction::RnValue(instr);
439 return reg;
440}
441
442
443Register Assembler::GetRm(Instr instr) {
444 Register reg;
445 reg.code_ = Instruction::RmValue(instr);
446 return reg;
447}
448
449
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000450bool Assembler::IsPush(Instr instr) {
451 return ((instr & ~kRdMask) == kPushRegPattern);
452}
453
454
455bool Assembler::IsPop(Instr instr) {
456 return ((instr & ~kRdMask) == kPopRegPattern);
457}
458
459
460bool Assembler::IsStrRegFpOffset(Instr instr) {
461 return ((instr & kLdrStrInstrTypeMask) == kStrRegFpOffsetPattern);
462}
463
464
465bool Assembler::IsLdrRegFpOffset(Instr instr) {
466 return ((instr & kLdrStrInstrTypeMask) == kLdrRegFpOffsetPattern);
467}
468
469
470bool Assembler::IsStrRegFpNegOffset(Instr instr) {
471 return ((instr & kLdrStrInstrTypeMask) == kStrRegFpNegOffsetPattern);
472}
473
474
475bool Assembler::IsLdrRegFpNegOffset(Instr instr) {
476 return ((instr & kLdrStrInstrTypeMask) == kLdrRegFpNegOffsetPattern);
477}
478
479
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000480bool Assembler::IsLdrPcImmediateOffset(Instr instr) {
481 // Check the instruction is indeed a
482 // ldr<cond> <Rd>, [pc +/- offset_12].
ager@chromium.org378b34e2011-01-28 08:04:38 +0000483 return (instr & (kLdrPCMask & ~kCondMask)) == 0x051f0000;
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000484}
485
486
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000487bool Assembler::IsTstImmediate(Instr instr) {
488 return (instr & (B27 | B26 | I | kOpCodeMask | S | kRdMask)) ==
489 (I | TST | S);
490}
491
492
493bool Assembler::IsCmpRegister(Instr instr) {
494 return (instr & (B27 | B26 | I | kOpCodeMask | S | kRdMask | B4)) ==
495 (CMP | S);
496}
497
498
499bool Assembler::IsCmpImmediate(Instr instr) {
500 return (instr & (B27 | B26 | I | kOpCodeMask | S | kRdMask)) ==
501 (I | CMP | S);
502}
503
504
505Register Assembler::GetCmpImmediateRegister(Instr instr) {
506 ASSERT(IsCmpImmediate(instr));
507 return GetRn(instr);
508}
509
510
511int Assembler::GetCmpImmediateRawImmediate(Instr instr) {
512 ASSERT(IsCmpImmediate(instr));
513 return instr & kOff12Mask;
514}
515
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000516// Labels refer to positions in the (to be) generated code.
517// There are bound, linked, and unused labels.
518//
519// Bound labels refer to known positions in the already
520// generated code. pos() is the position the label refers to.
521//
522// Linked labels refer to unknown positions in the code
523// to be generated; pos() is the position of the last
524// instruction using the label.
525
526
527// The link chain is terminated by a negative code position (must be aligned)
528const int kEndOfChain = -4;
529
530
531int Assembler::target_at(int pos) {
532 Instr instr = instr_at(pos);
ager@chromium.org378b34e2011-01-28 08:04:38 +0000533 if ((instr & ~kImm24Mask) == 0) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000534 // Emitted label constant, not part of a branch.
535 return instr - (Code::kHeaderSize - kHeapObjectTag);
536 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000537 ASSERT((instr & 7*B25) == 5*B25); // b, bl, or blx imm24
ager@chromium.org378b34e2011-01-28 08:04:38 +0000538 int imm26 = ((instr & kImm24Mask) << 8) >> 6;
539 if ((Instruction::ConditionField(instr) == kSpecialCondition) &&
540 ((instr & B24) != 0)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000541 // blx uses bit 24 to encode bit 2 of imm26
542 imm26 += 2;
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000543 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000544 return pos + kPcLoadDelta + imm26;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000545}
546
547
548void Assembler::target_at_put(int pos, int target_pos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000549 Instr instr = instr_at(pos);
ager@chromium.org378b34e2011-01-28 08:04:38 +0000550 if ((instr & ~kImm24Mask) == 0) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000551 ASSERT(target_pos == kEndOfChain || target_pos >= 0);
552 // Emitted label constant, not part of a branch.
553 // Make label relative to Code* of generated Code object.
554 instr_at_put(pos, target_pos + (Code::kHeaderSize - kHeapObjectTag));
555 return;
556 }
557 int imm26 = target_pos - (pos + kPcLoadDelta);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000558 ASSERT((instr & 7*B25) == 5*B25); // b, bl, or blx imm24
ager@chromium.org378b34e2011-01-28 08:04:38 +0000559 if (Instruction::ConditionField(instr) == kSpecialCondition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000560 // blx uses bit 24 to encode bit 2 of imm26
561 ASSERT((imm26 & 1) == 0);
ager@chromium.org378b34e2011-01-28 08:04:38 +0000562 instr = (instr & ~(B24 | kImm24Mask)) | ((imm26 & 2) >> 1)*B24;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000563 } else {
564 ASSERT((imm26 & 3) == 0);
ager@chromium.org378b34e2011-01-28 08:04:38 +0000565 instr &= ~kImm24Mask;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000566 }
567 int imm24 = imm26 >> 2;
568 ASSERT(is_int24(imm24));
ager@chromium.org378b34e2011-01-28 08:04:38 +0000569 instr_at_put(pos, instr | (imm24 & kImm24Mask));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000570}
571
572
573void Assembler::print(Label* L) {
574 if (L->is_unused()) {
575 PrintF("unused label\n");
576 } else if (L->is_bound()) {
577 PrintF("bound label to %d\n", L->pos());
578 } else if (L->is_linked()) {
579 Label l = *L;
580 PrintF("unbound label");
581 while (l.is_linked()) {
582 PrintF("@ %d ", l.pos());
583 Instr instr = instr_at(l.pos());
ager@chromium.org378b34e2011-01-28 08:04:38 +0000584 if ((instr & ~kImm24Mask) == 0) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000585 PrintF("value\n");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000586 } else {
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000587 ASSERT((instr & 7*B25) == 5*B25); // b, bl, or blx
ager@chromium.org378b34e2011-01-28 08:04:38 +0000588 Condition cond = Instruction::ConditionField(instr);
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000589 const char* b;
590 const char* c;
ager@chromium.org378b34e2011-01-28 08:04:38 +0000591 if (cond == kSpecialCondition) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000592 b = "blx";
593 c = "";
594 } else {
595 if ((instr & B24) != 0)
596 b = "bl";
597 else
598 b = "b";
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000599
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000600 switch (cond) {
601 case eq: c = "eq"; break;
602 case ne: c = "ne"; break;
603 case hs: c = "hs"; break;
604 case lo: c = "lo"; break;
605 case mi: c = "mi"; break;
606 case pl: c = "pl"; break;
607 case vs: c = "vs"; break;
608 case vc: c = "vc"; break;
609 case hi: c = "hi"; break;
610 case ls: c = "ls"; break;
611 case ge: c = "ge"; break;
612 case lt: c = "lt"; break;
613 case gt: c = "gt"; break;
614 case le: c = "le"; break;
615 case al: c = ""; break;
616 default:
617 c = "";
618 UNREACHABLE();
619 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000620 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000621 PrintF("%s%s\n", b, c);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000622 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000623 next(&l);
624 }
625 } else {
626 PrintF("label in inconsistent state (pos = %d)\n", L->pos_);
627 }
628}
629
630
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000631void Assembler::bind_to(Label* L, int pos) {
632 ASSERT(0 <= pos && pos <= pc_offset()); // must have a valid binding position
633 while (L->is_linked()) {
634 int fixup_pos = L->pos();
635 next(L); // call next before overwriting link with target at fixup_pos
636 target_at_put(fixup_pos, pos);
637 }
638 L->bind_to(pos);
639
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000640 // Keep track of the last bound label so we don't eliminate any instructions
641 // before a bound label.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000642 if (pos > last_bound_pos_)
643 last_bound_pos_ = pos;
644}
645
646
647void Assembler::link_to(Label* L, Label* appendix) {
648 if (appendix->is_linked()) {
649 if (L->is_linked()) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000650 // Append appendix to L's list.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000651 int fixup_pos;
652 int link = L->pos();
653 do {
654 fixup_pos = link;
655 link = target_at(fixup_pos);
656 } while (link > 0);
657 ASSERT(link == kEndOfChain);
658 target_at_put(fixup_pos, appendix->pos());
659 } else {
ager@chromium.org5c838252010-02-19 08:53:10 +0000660 // L is empty, simply use appendix.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000661 *L = *appendix;
662 }
663 }
664 appendix->Unuse(); // appendix should not be used anymore
665}
666
667
668void Assembler::bind(Label* L) {
669 ASSERT(!L->is_bound()); // label can only be bound once
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000670 bind_to(L, pc_offset());
671}
672
673
674void Assembler::next(Label* L) {
675 ASSERT(L->is_linked());
676 int link = target_at(L->pos());
677 if (link > 0) {
678 L->link_to(link);
679 } else {
680 ASSERT(link == kEndOfChain);
681 L->Unuse();
682 }
683}
684
685
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000686static Instr EncodeMovwImmediate(uint32_t immediate) {
687 ASSERT(immediate < 0x10000);
688 return ((immediate & 0xf000) << 4) | (immediate & 0xfff);
689}
690
691
ager@chromium.org5c838252010-02-19 08:53:10 +0000692// Low-level code emission routines depending on the addressing mode.
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000693// If this returns true then you have to use the rotate_imm and immed_8
694// that it returns, because it may have already changed the instruction
695// to match them!
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000696static bool fits_shifter(uint32_t imm32,
697 uint32_t* rotate_imm,
698 uint32_t* immed_8,
699 Instr* instr) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000700 // imm32 must be unsigned.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000701 for (int rot = 0; rot < 16; rot++) {
702 uint32_t imm8 = (imm32 << 2*rot) | (imm32 >> (32 - 2*rot));
703 if ((imm8 <= 0xff)) {
704 *rotate_imm = rot;
705 *immed_8 = imm8;
706 return true;
707 }
708 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000709 // If the opcode is one with a complementary version and the complementary
710 // immediate fits, change the opcode.
711 if (instr != NULL) {
712 if ((*instr & kMovMvnMask) == kMovMvnPattern) {
713 if (fits_shifter(~imm32, rotate_imm, immed_8, NULL)) {
714 *instr ^= kMovMvnFlip;
715 return true;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000716 } else if ((*instr & kMovLeaveCCMask) == kMovLeaveCCPattern) {
717 if (CpuFeatures::IsSupported(ARMv7)) {
718 if (imm32 < 0x10000) {
719 *instr ^= kMovwLeaveCCFlip;
720 *instr |= EncodeMovwImmediate(imm32);
721 *rotate_imm = *immed_8 = 0; // Not used for movw.
722 return true;
723 }
724 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000725 }
726 } else if ((*instr & kCmpCmnMask) == kCmpCmnPattern) {
727 if (fits_shifter(-imm32, rotate_imm, immed_8, NULL)) {
728 *instr ^= kCmpCmnFlip;
729 return true;
730 }
731 } else {
732 Instr alu_insn = (*instr & kALUMask);
ager@chromium.org378b34e2011-01-28 08:04:38 +0000733 if (alu_insn == ADD ||
734 alu_insn == SUB) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000735 if (fits_shifter(-imm32, rotate_imm, immed_8, NULL)) {
736 *instr ^= kAddSubFlip;
737 return true;
738 }
ager@chromium.org378b34e2011-01-28 08:04:38 +0000739 } else if (alu_insn == AND ||
740 alu_insn == BIC) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000741 if (fits_shifter(~imm32, rotate_imm, immed_8, NULL)) {
742 *instr ^= kAndBicFlip;
743 return true;
744 }
745 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000746 }
747 }
748 return false;
749}
750
751
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000752// We have to use the temporary register for things that can be relocated even
753// if they can be encoded in the ARM's 12 bits of immediate-offset instruction
754// space. There is no guarantee that the relocated location can be similarly
755// encoded.
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000756bool Operand::must_use_constant_pool() const {
757 if (rmode_ == RelocInfo::EXTERNAL_REFERENCE) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000758#ifdef DEBUG
759 if (!Serializer::enabled()) {
760 Serializer::TooLateToEnableNow();
761 }
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000762#endif // def DEBUG
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000763 return Serializer::enabled();
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000764 } else if (rmode_ == RelocInfo::NONE) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000765 return false;
766 }
767 return true;
768}
769
770
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000771bool Operand::is_single_instruction(Instr instr) const {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000772 if (rm_.is_valid()) return true;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000773 uint32_t dummy1, dummy2;
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000774 if (must_use_constant_pool() ||
775 !fits_shifter(imm32_, &dummy1, &dummy2, &instr)) {
776 // The immediate operand cannot be encoded as a shifter operand, or use of
777 // constant pool is required. For a mov instruction not setting the
778 // condition code additional instruction conventions can be used.
779 if ((instr & ~kCondMask) == 13*B21) { // mov, S not set
780 if (must_use_constant_pool() || !CpuFeatures::IsSupported(ARMv7)) {
781 // mov instruction will be an ldr from constant pool (one instruction).
782 return true;
783 } else {
784 // mov instruction will be a mov or movw followed by movt (two
785 // instructions).
786 return false;
787 }
788 } else {
789 // If this is not a mov or mvn instruction there will always an additional
790 // instructions - either mov or ldr. The mov might actually be two
791 // instructions mov or movw followed by movt so including the actual
792 // instruction two or three instructions will be generated.
793 return false;
794 }
795 } else {
796 // No use of constant pool and the immediate operand can be encoded as a
797 // shifter operand.
798 return true;
799 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000800}
801
802
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000803void Assembler::addrmod1(Instr instr,
804 Register rn,
805 Register rd,
806 const Operand& x) {
807 CheckBuffer();
ager@chromium.org378b34e2011-01-28 08:04:38 +0000808 ASSERT((instr & ~(kCondMask | kOpCodeMask | S)) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000809 if (!x.rm_.is_valid()) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000810 // Immediate.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000811 uint32_t rotate_imm;
812 uint32_t immed_8;
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000813 if (x.must_use_constant_pool() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000814 !fits_shifter(x.imm32_, &rotate_imm, &immed_8, &instr)) {
815 // The immediate operand cannot be encoded as a shifter operand, so load
816 // it first to register ip and change the original instruction to use ip.
817 // However, if the original instruction is a 'mov rd, x' (not setting the
ager@chromium.org5c838252010-02-19 08:53:10 +0000818 // condition code), then replace it with a 'ldr rd, [pc]'.
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000819 CHECK(!rn.is(ip)); // rn should never be ip, or will be trashed
ager@chromium.org378b34e2011-01-28 08:04:38 +0000820 Condition cond = Instruction::ConditionField(instr);
821 if ((instr & ~kCondMask) == 13*B21) { // mov, S not set
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000822 if (x.must_use_constant_pool() || !CpuFeatures::IsSupported(ARMv7)) {
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000823 RecordRelocInfo(x.rmode_, x.imm32_);
824 ldr(rd, MemOperand(pc, 0), cond);
825 } else {
826 // Will probably use movw, will certainly not use constant pool.
827 mov(rd, Operand(x.imm32_ & 0xffff), LeaveCC, cond);
828 movt(rd, static_cast<uint32_t>(x.imm32_) >> 16, cond);
829 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000830 } else {
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000831 // If this is not a mov or mvn instruction we may still be able to avoid
832 // a constant pool entry by using mvn or movw.
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000833 if (!x.must_use_constant_pool() &&
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000834 (instr & kMovMvnMask) != kMovMvnPattern) {
835 mov(ip, x, LeaveCC, cond);
836 } else {
837 RecordRelocInfo(x.rmode_, x.imm32_);
838 ldr(ip, MemOperand(pc, 0), cond);
839 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000840 addrmod1(instr, rn, rd, Operand(ip));
841 }
842 return;
843 }
844 instr |= I | rotate_imm*B8 | immed_8;
845 } else if (!x.rs_.is_valid()) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000846 // Immediate shift.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000847 instr |= x.shift_imm_*B7 | x.shift_op_ | x.rm_.code();
848 } else {
ager@chromium.org5c838252010-02-19 08:53:10 +0000849 // Register shift.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000850 ASSERT(!rn.is(pc) && !rd.is(pc) && !x.rm_.is(pc) && !x.rs_.is(pc));
851 instr |= x.rs_.code()*B8 | x.shift_op_ | B4 | x.rm_.code();
852 }
853 emit(instr | rn.code()*B16 | rd.code()*B12);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000854 if (rn.is(pc) || x.rm_.is(pc)) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000855 // Block constant pool emission for one instruction after reading pc.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000856 BlockConstPoolBefore(pc_offset() + kInstrSize);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000857 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000858}
859
860
861void Assembler::addrmod2(Instr instr, Register rd, const MemOperand& x) {
ager@chromium.org378b34e2011-01-28 08:04:38 +0000862 ASSERT((instr & ~(kCondMask | B | L)) == B26);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000863 int am = x.am_;
864 if (!x.rm_.is_valid()) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000865 // Immediate offset.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000866 int offset_12 = x.offset_;
867 if (offset_12 < 0) {
868 offset_12 = -offset_12;
869 am ^= U;
870 }
871 if (!is_uint12(offset_12)) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000872 // Immediate offset cannot be encoded, load it first to register ip
873 // rn (and rd in a load) should never be ip, or will be trashed.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000874 ASSERT(!x.rn_.is(ip) && ((instr & L) == L || !rd.is(ip)));
ager@chromium.org378b34e2011-01-28 08:04:38 +0000875 mov(ip, Operand(x.offset_), LeaveCC, Instruction::ConditionField(instr));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000876 addrmod2(instr, rd, MemOperand(x.rn_, ip, x.am_));
877 return;
878 }
879 ASSERT(offset_12 >= 0); // no masking needed
880 instr |= offset_12;
881 } else {
ager@chromium.org5c838252010-02-19 08:53:10 +0000882 // Register offset (shift_imm_ and shift_op_ are 0) or scaled
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000883 // register offset the constructors make sure than both shift_imm_
ager@chromium.org5c838252010-02-19 08:53:10 +0000884 // and shift_op_ are initialized.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000885 ASSERT(!x.rm_.is(pc));
886 instr |= B25 | x.shift_imm_*B7 | x.shift_op_ | x.rm_.code();
887 }
888 ASSERT((am & (P|W)) == P || !x.rn_.is(pc)); // no pc base with writeback
889 emit(instr | am | x.rn_.code()*B16 | rd.code()*B12);
890}
891
892
893void Assembler::addrmod3(Instr instr, Register rd, const MemOperand& x) {
ager@chromium.org378b34e2011-01-28 08:04:38 +0000894 ASSERT((instr & ~(kCondMask | L | S6 | H)) == (B4 | B7));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000895 ASSERT(x.rn_.is_valid());
896 int am = x.am_;
897 if (!x.rm_.is_valid()) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000898 // Immediate offset.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000899 int offset_8 = x.offset_;
900 if (offset_8 < 0) {
901 offset_8 = -offset_8;
902 am ^= U;
903 }
904 if (!is_uint8(offset_8)) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000905 // Immediate offset cannot be encoded, load it first to register ip
906 // rn (and rd in a load) should never be ip, or will be trashed.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000907 ASSERT(!x.rn_.is(ip) && ((instr & L) == L || !rd.is(ip)));
ager@chromium.org378b34e2011-01-28 08:04:38 +0000908 mov(ip, Operand(x.offset_), LeaveCC, Instruction::ConditionField(instr));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000909 addrmod3(instr, rd, MemOperand(x.rn_, ip, x.am_));
910 return;
911 }
912 ASSERT(offset_8 >= 0); // no masking needed
913 instr |= B | (offset_8 >> 4)*B8 | (offset_8 & 0xf);
914 } else if (x.shift_imm_ != 0) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000915 // Scaled register offset not supported, load index first
916 // rn (and rd in a load) should never be ip, or will be trashed.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000917 ASSERT(!x.rn_.is(ip) && ((instr & L) == L || !rd.is(ip)));
918 mov(ip, Operand(x.rm_, x.shift_op_, x.shift_imm_), LeaveCC,
ager@chromium.org378b34e2011-01-28 08:04:38 +0000919 Instruction::ConditionField(instr));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000920 addrmod3(instr, rd, MemOperand(x.rn_, ip, x.am_));
921 return;
922 } else {
ager@chromium.org5c838252010-02-19 08:53:10 +0000923 // Register offset.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000924 ASSERT((am & (P|W)) == P || !x.rm_.is(pc)); // no pc index with writeback
925 instr |= x.rm_.code();
926 }
927 ASSERT((am & (P|W)) == P || !x.rn_.is(pc)); // no pc base with writeback
928 emit(instr | am | x.rn_.code()*B16 | rd.code()*B12);
929}
930
931
932void Assembler::addrmod4(Instr instr, Register rn, RegList rl) {
ager@chromium.org378b34e2011-01-28 08:04:38 +0000933 ASSERT((instr & ~(kCondMask | P | U | W | L)) == B27);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000934 ASSERT(rl != 0);
935 ASSERT(!rn.is(pc));
936 emit(instr | rn.code()*B16 | rl);
937}
938
939
940void Assembler::addrmod5(Instr instr, CRegister crd, const MemOperand& x) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000941 // Unindexed addressing is not encoded by this function.
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000942 ASSERT_EQ((B27 | B26),
ager@chromium.org378b34e2011-01-28 08:04:38 +0000943 (instr & ~(kCondMask | kCoprocessorMask | P | U | N | W | L)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000944 ASSERT(x.rn_.is_valid() && !x.rm_.is_valid());
945 int am = x.am_;
946 int offset_8 = x.offset_;
947 ASSERT((offset_8 & 3) == 0); // offset must be an aligned word offset
948 offset_8 >>= 2;
949 if (offset_8 < 0) {
950 offset_8 = -offset_8;
951 am ^= U;
952 }
953 ASSERT(is_uint8(offset_8)); // unsigned word offset must fit in a byte
954 ASSERT((am & (P|W)) == P || !x.rn_.is(pc)); // no pc base with writeback
955
ager@chromium.org5c838252010-02-19 08:53:10 +0000956 // Post-indexed addressing requires W == 1; different than in addrmod2/3.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000957 if ((am & P) == 0)
958 am |= W;
959
960 ASSERT(offset_8 >= 0); // no masking needed
961 emit(instr | am | x.rn_.code()*B16 | crd.code()*B12 | offset_8);
962}
963
964
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +0000965int Assembler::branch_offset(Label* L, bool jump_elimination_allowed) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000966 int target_pos;
967 if (L->is_bound()) {
968 target_pos = L->pos();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000969 } else {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000970 if (L->is_linked()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000971 target_pos = L->pos(); // L's link
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000972 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000973 target_pos = kEndOfChain;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000974 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000975 L->link_to(pc_offset());
976 }
977
978 // Block the emission of the constant pool, since the branch instruction must
ager@chromium.org5c838252010-02-19 08:53:10 +0000979 // be emitted at the pc offset recorded by the label.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000980 BlockConstPoolBefore(pc_offset() + kInstrSize);
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000981 return target_pos - (pc_offset() + kPcLoadDelta);
982}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000983
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000984
985void Assembler::label_at_put(Label* L, int at_offset) {
986 int target_pos;
987 if (L->is_bound()) {
988 target_pos = L->pos();
989 } else {
990 if (L->is_linked()) {
991 target_pos = L->pos(); // L's link
992 } else {
993 target_pos = kEndOfChain;
994 }
995 L->link_to(at_offset);
996 instr_at_put(at_offset, target_pos + (Code::kHeaderSize - kHeapObjectTag));
997 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000998}
999
1000
ager@chromium.org5c838252010-02-19 08:53:10 +00001001// Branch instructions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001002void Assembler::b(int branch_offset, Condition cond) {
1003 ASSERT((branch_offset & 3) == 0);
1004 int imm24 = branch_offset >> 2;
1005 ASSERT(is_int24(imm24));
ager@chromium.org378b34e2011-01-28 08:04:38 +00001006 emit(cond | B27 | B25 | (imm24 & kImm24Mask));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001007
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001008 if (cond == al) {
ager@chromium.org5c838252010-02-19 08:53:10 +00001009 // Dead code is a good location to emit the constant pool.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001010 CheckConstPool(false, false);
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001011 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001012}
1013
1014
1015void Assembler::bl(int branch_offset, Condition cond) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001016 positions_recorder()->WriteRecordedPositions();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001017 ASSERT((branch_offset & 3) == 0);
1018 int imm24 = branch_offset >> 2;
1019 ASSERT(is_int24(imm24));
ager@chromium.org378b34e2011-01-28 08:04:38 +00001020 emit(cond | B27 | B25 | B24 | (imm24 & kImm24Mask));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001021}
1022
1023
1024void Assembler::blx(int branch_offset) { // v5 and above
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00001025 positions_recorder()->WriteRecordedPositions();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001026 ASSERT((branch_offset & 1) == 0);
1027 int h = ((branch_offset & 2) >> 1)*B24;
1028 int imm24 = branch_offset >> 2;
1029 ASSERT(is_int24(imm24));
ager@chromium.org378b34e2011-01-28 08:04:38 +00001030 emit(kSpecialCondition | B27 | B25 | h | (imm24 & kImm24Mask));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001031}
1032
1033
1034void Assembler::blx(Register target, Condition cond) { // v5 and above
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00001035 positions_recorder()->WriteRecordedPositions();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001036 ASSERT(!target.is(pc));
ager@chromium.org378b34e2011-01-28 08:04:38 +00001037 emit(cond | B24 | B21 | 15*B16 | 15*B12 | 15*B8 | BLX | target.code());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001038}
1039
1040
1041void Assembler::bx(Register target, Condition cond) { // v5 and above, plus v4t
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00001042 positions_recorder()->WriteRecordedPositions();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001043 ASSERT(!target.is(pc)); // use of pc is actually allowed, but discouraged
ager@chromium.org378b34e2011-01-28 08:04:38 +00001044 emit(cond | B24 | B21 | 15*B16 | 15*B12 | 15*B8 | BX | target.code());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001045}
1046
1047
ager@chromium.org5c838252010-02-19 08:53:10 +00001048// Data-processing instructions.
1049
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001050void Assembler::and_(Register dst, Register src1, const Operand& src2,
1051 SBit s, Condition cond) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00001052 addrmod1(cond | AND | s, src1, dst, src2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001053}
1054
1055
1056void Assembler::eor(Register dst, Register src1, const Operand& src2,
1057 SBit s, Condition cond) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00001058 addrmod1(cond | EOR | s, src1, dst, src2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001059}
1060
1061
1062void Assembler::sub(Register dst, Register src1, const Operand& src2,
1063 SBit s, Condition cond) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00001064 addrmod1(cond | SUB | s, src1, dst, src2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001065}
1066
1067
1068void Assembler::rsb(Register dst, Register src1, const Operand& src2,
1069 SBit s, Condition cond) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00001070 addrmod1(cond | RSB | s, src1, dst, src2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001071}
1072
1073
1074void Assembler::add(Register dst, Register src1, const Operand& src2,
1075 SBit s, Condition cond) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00001076 addrmod1(cond | ADD | s, src1, dst, src2);
mads.s.ager31e71382008-08-13 09:32:07 +00001077
1078 // Eliminate pattern: push(r), pop()
1079 // str(src, MemOperand(sp, 4, NegPreIndex), al);
1080 // add(sp, sp, Operand(kPointerSize));
1081 // Both instructions can be eliminated.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001082 if (can_peephole_optimize(2) &&
ager@chromium.org5c838252010-02-19 08:53:10 +00001083 // Pattern.
mads.s.ager31e71382008-08-13 09:32:07 +00001084 instr_at(pc_ - 1 * kInstrSize) == kPopInstruction &&
ager@chromium.org378b34e2011-01-28 08:04:38 +00001085 (instr_at(pc_ - 2 * kInstrSize) & ~kRdMask) == kPushRegPattern) {
mads.s.ager31e71382008-08-13 09:32:07 +00001086 pc_ -= 2 * kInstrSize;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001087 if (FLAG_print_peephole_optimization) {
mads.s.ager31e71382008-08-13 09:32:07 +00001088 PrintF("%x push(reg)/pop() eliminated\n", pc_offset());
1089 }
1090 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001091}
1092
1093
1094void Assembler::adc(Register dst, Register src1, const Operand& src2,
1095 SBit s, Condition cond) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00001096 addrmod1(cond | ADC | s, src1, dst, src2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001097}
1098
1099
1100void Assembler::sbc(Register dst, Register src1, const Operand& src2,
1101 SBit s, Condition cond) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00001102 addrmod1(cond | SBC | s, src1, dst, src2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001103}
1104
1105
1106void Assembler::rsc(Register dst, Register src1, const Operand& src2,
1107 SBit s, Condition cond) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00001108 addrmod1(cond | RSC | s, src1, dst, src2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001109}
1110
1111
1112void Assembler::tst(Register src1, const Operand& src2, Condition cond) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00001113 addrmod1(cond | TST | S, src1, r0, src2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001114}
1115
1116
1117void Assembler::teq(Register src1, const Operand& src2, Condition cond) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00001118 addrmod1(cond | TEQ | S, src1, r0, src2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001119}
1120
1121
1122void Assembler::cmp(Register src1, const Operand& src2, Condition cond) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00001123 addrmod1(cond | CMP | S, src1, r0, src2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001124}
1125
1126
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001127void Assembler::cmp_raw_immediate(
1128 Register src, int raw_immediate, Condition cond) {
1129 ASSERT(is_uint12(raw_immediate));
1130 emit(cond | I | CMP | S | src.code() << 16 | raw_immediate);
1131}
1132
1133
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001134void Assembler::cmn(Register src1, const Operand& src2, Condition cond) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00001135 addrmod1(cond | CMN | S, src1, r0, src2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001136}
1137
1138
1139void Assembler::orr(Register dst, Register src1, const Operand& src2,
1140 SBit s, Condition cond) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00001141 addrmod1(cond | ORR | s, src1, dst, src2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001142}
1143
1144
1145void Assembler::mov(Register dst, const Operand& src, SBit s, Condition cond) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001146 if (dst.is(pc)) {
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00001147 positions_recorder()->WriteRecordedPositions();
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001148 }
fschneider@chromium.org013f3e12010-04-26 13:27:52 +00001149 // Don't allow nop instructions in the form mov rn, rn to be generated using
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001150 // the mov instruction. They must be generated using nop(int/NopMarkerTypes)
1151 // or MarkCode(int/NopMarkerTypes) pseudo instructions.
fschneider@chromium.org013f3e12010-04-26 13:27:52 +00001152 ASSERT(!(src.is_reg() && src.rm().is(dst) && s == LeaveCC && cond == al));
ager@chromium.org378b34e2011-01-28 08:04:38 +00001153 addrmod1(cond | MOV | s, r0, dst, src);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001154}
1155
1156
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001157void Assembler::movw(Register reg, uint32_t immediate, Condition cond) {
1158 ASSERT(immediate < 0x10000);
1159 mov(reg, Operand(immediate), LeaveCC, cond);
1160}
1161
1162
1163void Assembler::movt(Register reg, uint32_t immediate, Condition cond) {
1164 emit(cond | 0x34*B20 | reg.code()*B12 | EncodeMovwImmediate(immediate));
1165}
1166
1167
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001168void Assembler::bic(Register dst, Register src1, const Operand& src2,
1169 SBit s, Condition cond) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00001170 addrmod1(cond | BIC | s, src1, dst, src2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001171}
1172
1173
1174void Assembler::mvn(Register dst, const Operand& src, SBit s, Condition cond) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00001175 addrmod1(cond | MVN | s, r0, dst, src);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001176}
1177
1178
ager@chromium.org5c838252010-02-19 08:53:10 +00001179// Multiply instructions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001180void Assembler::mla(Register dst, Register src1, Register src2, Register srcA,
1181 SBit s, Condition cond) {
1182 ASSERT(!dst.is(pc) && !src1.is(pc) && !src2.is(pc) && !srcA.is(pc));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001183 emit(cond | A | s | dst.code()*B16 | srcA.code()*B12 |
1184 src2.code()*B8 | B7 | B4 | src1.code());
1185}
1186
1187
1188void Assembler::mul(Register dst, Register src1, Register src2,
1189 SBit s, Condition cond) {
1190 ASSERT(!dst.is(pc) && !src1.is(pc) && !src2.is(pc));
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00001191 // dst goes in bits 16-19 for this instruction!
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001192 emit(cond | s | dst.code()*B16 | src2.code()*B8 | B7 | B4 | src1.code());
1193}
1194
1195
1196void Assembler::smlal(Register dstL,
1197 Register dstH,
1198 Register src1,
1199 Register src2,
1200 SBit s,
1201 Condition cond) {
1202 ASSERT(!dstL.is(pc) && !dstH.is(pc) && !src1.is(pc) && !src2.is(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001203 ASSERT(!dstL.is(dstH));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001204 emit(cond | B23 | B22 | A | s | dstH.code()*B16 | dstL.code()*B12 |
1205 src2.code()*B8 | B7 | B4 | src1.code());
1206}
1207
1208
1209void Assembler::smull(Register dstL,
1210 Register dstH,
1211 Register src1,
1212 Register src2,
1213 SBit s,
1214 Condition cond) {
1215 ASSERT(!dstL.is(pc) && !dstH.is(pc) && !src1.is(pc) && !src2.is(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001216 ASSERT(!dstL.is(dstH));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001217 emit(cond | B23 | B22 | s | dstH.code()*B16 | dstL.code()*B12 |
1218 src2.code()*B8 | B7 | B4 | src1.code());
1219}
1220
1221
1222void Assembler::umlal(Register dstL,
1223 Register dstH,
1224 Register src1,
1225 Register src2,
1226 SBit s,
1227 Condition cond) {
1228 ASSERT(!dstL.is(pc) && !dstH.is(pc) && !src1.is(pc) && !src2.is(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001229 ASSERT(!dstL.is(dstH));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001230 emit(cond | B23 | A | s | dstH.code()*B16 | dstL.code()*B12 |
1231 src2.code()*B8 | B7 | B4 | src1.code());
1232}
1233
1234
1235void Assembler::umull(Register dstL,
1236 Register dstH,
1237 Register src1,
1238 Register src2,
1239 SBit s,
1240 Condition cond) {
1241 ASSERT(!dstL.is(pc) && !dstH.is(pc) && !src1.is(pc) && !src2.is(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001242 ASSERT(!dstL.is(dstH));
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00001243 emit(cond | B23 | s | dstH.code()*B16 | dstL.code()*B12 |
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001244 src2.code()*B8 | B7 | B4 | src1.code());
1245}
1246
1247
ager@chromium.org5c838252010-02-19 08:53:10 +00001248// Miscellaneous arithmetic instructions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001249void Assembler::clz(Register dst, Register src, Condition cond) {
1250 // v5 and above.
1251 ASSERT(!dst.is(pc) && !src.is(pc));
1252 emit(cond | B24 | B22 | B21 | 15*B16 | dst.code()*B12 |
ager@chromium.org378b34e2011-01-28 08:04:38 +00001253 15*B8 | CLZ | src.code());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001254}
1255
1256
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +00001257// Saturating instructions.
1258
1259// Unsigned saturate.
1260void Assembler::usat(Register dst,
1261 int satpos,
1262 const Operand& src,
1263 Condition cond) {
1264 // v6 and above.
1265 ASSERT(CpuFeatures::IsSupported(ARMv7));
1266 ASSERT(!dst.is(pc) && !src.rm_.is(pc));
1267 ASSERT((satpos >= 0) && (satpos <= 31));
1268 ASSERT((src.shift_op_ == ASR) || (src.shift_op_ == LSL));
1269 ASSERT(src.rs_.is(no_reg));
1270
1271 int sh = 0;
1272 if (src.shift_op_ == ASR) {
1273 sh = 1;
1274 }
1275
1276 emit(cond | 0x6*B24 | 0xe*B20 | satpos*B16 | dst.code()*B12 |
1277 src.shift_imm_*B7 | sh*B6 | 0x1*B4 | src.rm_.code());
1278}
1279
1280
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001281// Bitfield manipulation instructions.
1282
1283// Unsigned bit field extract.
1284// Extracts #width adjacent bits from position #lsb in a register, and
1285// writes them to the low bits of a destination register.
1286// ubfx dst, src, #lsb, #width
1287void Assembler::ubfx(Register dst,
1288 Register src,
1289 int lsb,
1290 int width,
1291 Condition cond) {
1292 // v7 and above.
1293 ASSERT(CpuFeatures::IsSupported(ARMv7));
1294 ASSERT(!dst.is(pc) && !src.is(pc));
1295 ASSERT((lsb >= 0) && (lsb <= 31));
1296 ASSERT((width >= 1) && (width <= (32 - lsb)));
1297 emit(cond | 0xf*B23 | B22 | B21 | (width - 1)*B16 | dst.code()*B12 |
1298 lsb*B7 | B6 | B4 | src.code());
1299}
1300
1301
1302// Signed bit field extract.
1303// Extracts #width adjacent bits from position #lsb in a register, and
1304// writes them to the low bits of a destination register. The extracted
1305// value is sign extended to fill the destination register.
1306// sbfx dst, src, #lsb, #width
1307void Assembler::sbfx(Register dst,
1308 Register src,
1309 int lsb,
1310 int width,
1311 Condition cond) {
1312 // v7 and above.
1313 ASSERT(CpuFeatures::IsSupported(ARMv7));
1314 ASSERT(!dst.is(pc) && !src.is(pc));
1315 ASSERT((lsb >= 0) && (lsb <= 31));
1316 ASSERT((width >= 1) && (width <= (32 - lsb)));
1317 emit(cond | 0xf*B23 | B21 | (width - 1)*B16 | dst.code()*B12 |
1318 lsb*B7 | B6 | B4 | src.code());
1319}
1320
1321
1322// Bit field clear.
1323// Sets #width adjacent bits at position #lsb in the destination register
1324// to zero, preserving the value of the other bits.
1325// bfc dst, #lsb, #width
1326void Assembler::bfc(Register dst, int lsb, int width, Condition cond) {
1327 // v7 and above.
1328 ASSERT(CpuFeatures::IsSupported(ARMv7));
1329 ASSERT(!dst.is(pc));
1330 ASSERT((lsb >= 0) && (lsb <= 31));
1331 ASSERT((width >= 1) && (width <= (32 - lsb)));
1332 int msb = lsb + width - 1;
1333 emit(cond | 0x1f*B22 | msb*B16 | dst.code()*B12 | lsb*B7 | B4 | 0xf);
1334}
1335
1336
1337// Bit field insert.
1338// Inserts #width adjacent bits from the low bits of the source register
1339// into position #lsb of the destination register.
1340// bfi dst, src, #lsb, #width
1341void Assembler::bfi(Register dst,
1342 Register src,
1343 int lsb,
1344 int width,
1345 Condition cond) {
1346 // v7 and above.
1347 ASSERT(CpuFeatures::IsSupported(ARMv7));
1348 ASSERT(!dst.is(pc) && !src.is(pc));
1349 ASSERT((lsb >= 0) && (lsb <= 31));
1350 ASSERT((width >= 1) && (width <= (32 - lsb)));
1351 int msb = lsb + width - 1;
1352 emit(cond | 0x1f*B22 | msb*B16 | dst.code()*B12 | lsb*B7 | B4 |
1353 src.code());
1354}
1355
1356
ager@chromium.org5c838252010-02-19 08:53:10 +00001357// Status register access instructions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001358void Assembler::mrs(Register dst, SRegister s, Condition cond) {
1359 ASSERT(!dst.is(pc));
1360 emit(cond | B24 | s | 15*B16 | dst.code()*B12);
1361}
1362
1363
1364void Assembler::msr(SRegisterFieldMask fields, const Operand& src,
1365 Condition cond) {
1366 ASSERT(fields >= B16 && fields < B20); // at least one field set
1367 Instr instr;
1368 if (!src.rm_.is_valid()) {
ager@chromium.org5c838252010-02-19 08:53:10 +00001369 // Immediate.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001370 uint32_t rotate_imm;
1371 uint32_t immed_8;
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00001372 if (src.must_use_constant_pool() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001373 !fits_shifter(src.imm32_, &rotate_imm, &immed_8, NULL)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00001374 // Immediate operand cannot be encoded, load it first to register ip.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001375 RecordRelocInfo(src.rmode_, src.imm32_);
1376 ldr(ip, MemOperand(pc, 0), cond);
1377 msr(fields, Operand(ip), cond);
1378 return;
1379 }
1380 instr = I | rotate_imm*B8 | immed_8;
1381 } else {
1382 ASSERT(!src.rs_.is_valid() && src.shift_imm_ == 0); // only rm allowed
1383 instr = src.rm_.code();
1384 }
1385 emit(cond | instr | B24 | B21 | fields | 15*B12);
1386}
1387
1388
ager@chromium.org5c838252010-02-19 08:53:10 +00001389// Load/Store instructions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001390void Assembler::ldr(Register dst, const MemOperand& src, Condition cond) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001391 if (dst.is(pc)) {
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00001392 positions_recorder()->WriteRecordedPositions();
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001393 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001394 addrmod2(cond | B26 | L, dst, src);
mads.s.ager31e71382008-08-13 09:32:07 +00001395
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001396 // Eliminate pattern: push(ry), pop(rx)
1397 // str(ry, MemOperand(sp, 4, NegPreIndex), al)
1398 // ldr(rx, MemOperand(sp, 4, PostIndex), al)
1399 // Both instructions can be eliminated if ry = rx.
1400 // If ry != rx, a register copy from ry to rx is inserted
1401 // after eliminating the push and the pop instructions.
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001402 if (can_peephole_optimize(2)) {
1403 Instr push_instr = instr_at(pc_ - 2 * kInstrSize);
1404 Instr pop_instr = instr_at(pc_ - 1 * kInstrSize);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001405
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001406 if (IsPush(push_instr) && IsPop(pop_instr)) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00001407 if (Instruction::RdValue(pop_instr) != Instruction::RdValue(push_instr)) {
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001408 // For consecutive push and pop on different registers,
1409 // we delete both the push & pop and insert a register move.
1410 // push ry, pop rx --> mov rx, ry
1411 Register reg_pushed, reg_popped;
1412 reg_pushed = GetRd(push_instr);
1413 reg_popped = GetRd(pop_instr);
1414 pc_ -= 2 * kInstrSize;
1415 // Insert a mov instruction, which is better than a pair of push & pop
1416 mov(reg_popped, reg_pushed);
1417 if (FLAG_print_peephole_optimization) {
1418 PrintF("%x push/pop (diff reg) replaced by a reg move\n",
1419 pc_offset());
1420 }
1421 } else {
1422 // For consecutive push and pop on the same register,
1423 // both the push and the pop can be deleted.
1424 pc_ -= 2 * kInstrSize;
1425 if (FLAG_print_peephole_optimization) {
1426 PrintF("%x push/pop (same reg) eliminated\n", pc_offset());
1427 }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001428 }
1429 }
1430 }
1431
1432 if (can_peephole_optimize(2)) {
1433 Instr str_instr = instr_at(pc_ - 2 * kInstrSize);
1434 Instr ldr_instr = instr_at(pc_ - 1 * kInstrSize);
1435
1436 if ((IsStrRegFpOffset(str_instr) &&
1437 IsLdrRegFpOffset(ldr_instr)) ||
1438 (IsStrRegFpNegOffset(str_instr) &&
1439 IsLdrRegFpNegOffset(ldr_instr))) {
1440 if ((ldr_instr & kLdrStrInstrArgumentMask) ==
1441 (str_instr & kLdrStrInstrArgumentMask)) {
1442 // Pattern: Ldr/str same fp+offset, same register.
1443 //
1444 // The following:
1445 // str rx, [fp, #-12]
1446 // ldr rx, [fp, #-12]
1447 //
1448 // Becomes:
1449 // str rx, [fp, #-12]
1450
1451 pc_ -= 1 * kInstrSize;
1452 if (FLAG_print_peephole_optimization) {
1453 PrintF("%x str/ldr (fp + same offset), same reg\n", pc_offset());
1454 }
1455 } else if ((ldr_instr & kLdrStrOffsetMask) ==
1456 (str_instr & kLdrStrOffsetMask)) {
1457 // Pattern: Ldr/str same fp+offset, different register.
1458 //
1459 // The following:
1460 // str rx, [fp, #-12]
1461 // ldr ry, [fp, #-12]
1462 //
1463 // Becomes:
1464 // str rx, [fp, #-12]
1465 // mov ry, rx
1466
1467 Register reg_stored, reg_loaded;
1468 reg_stored = GetRd(str_instr);
1469 reg_loaded = GetRd(ldr_instr);
1470 pc_ -= 1 * kInstrSize;
1471 // Insert a mov instruction, which is better than ldr.
1472 mov(reg_loaded, reg_stored);
1473 if (FLAG_print_peephole_optimization) {
1474 PrintF("%x str/ldr (fp + same offset), diff reg \n", pc_offset());
1475 }
1476 }
1477 }
1478 }
1479
1480 if (can_peephole_optimize(3)) {
1481 Instr mem_write_instr = instr_at(pc_ - 3 * kInstrSize);
1482 Instr ldr_instr = instr_at(pc_ - 2 * kInstrSize);
1483 Instr mem_read_instr = instr_at(pc_ - 1 * kInstrSize);
1484 if (IsPush(mem_write_instr) &&
1485 IsPop(mem_read_instr)) {
1486 if ((IsLdrRegFpOffset(ldr_instr) ||
1487 IsLdrRegFpNegOffset(ldr_instr))) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00001488 if (Instruction::RdValue(mem_write_instr) ==
1489 Instruction::RdValue(mem_read_instr)) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001490 // Pattern: push & pop from/to same register,
1491 // with a fp+offset ldr in between
1492 //
1493 // The following:
1494 // str rx, [sp, #-4]!
1495 // ldr rz, [fp, #-24]
1496 // ldr rx, [sp], #+4
1497 //
1498 // Becomes:
1499 // if(rx == rz)
1500 // delete all
1501 // else
1502 // ldr rz, [fp, #-24]
1503
ager@chromium.org378b34e2011-01-28 08:04:38 +00001504 if (Instruction::RdValue(mem_write_instr) ==
1505 Instruction::RdValue(ldr_instr)) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001506 pc_ -= 3 * kInstrSize;
1507 } else {
1508 pc_ -= 3 * kInstrSize;
1509 // Reinsert back the ldr rz.
1510 emit(ldr_instr);
1511 }
1512 if (FLAG_print_peephole_optimization) {
1513 PrintF("%x push/pop -dead ldr fp+offset in middle\n", pc_offset());
1514 }
1515 } else {
1516 // Pattern: push & pop from/to different registers
1517 // with a fp+offset ldr in between
1518 //
1519 // The following:
1520 // str rx, [sp, #-4]!
1521 // ldr rz, [fp, #-24]
1522 // ldr ry, [sp], #+4
1523 //
1524 // Becomes:
1525 // if(ry == rz)
1526 // mov ry, rx;
1527 // else if(rx != rz)
1528 // ldr rz, [fp, #-24]
1529 // mov ry, rx
1530 // else if((ry != rz) || (rx == rz)) becomes:
1531 // mov ry, rx
1532 // ldr rz, [fp, #-24]
1533
1534 Register reg_pushed, reg_popped;
ager@chromium.org378b34e2011-01-28 08:04:38 +00001535 if (Instruction::RdValue(mem_read_instr) ==
1536 Instruction::RdValue(ldr_instr)) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001537 reg_pushed = GetRd(mem_write_instr);
1538 reg_popped = GetRd(mem_read_instr);
1539 pc_ -= 3 * kInstrSize;
1540 mov(reg_popped, reg_pushed);
ager@chromium.org378b34e2011-01-28 08:04:38 +00001541 } else if (Instruction::RdValue(mem_write_instr) !=
1542 Instruction::RdValue(ldr_instr)) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001543 reg_pushed = GetRd(mem_write_instr);
1544 reg_popped = GetRd(mem_read_instr);
1545 pc_ -= 3 * kInstrSize;
1546 emit(ldr_instr);
1547 mov(reg_popped, reg_pushed);
ager@chromium.org378b34e2011-01-28 08:04:38 +00001548 } else if ((Instruction::RdValue(mem_read_instr) !=
1549 Instruction::RdValue(ldr_instr)) ||
1550 (Instruction::RdValue(mem_write_instr) ==
1551 Instruction::RdValue(ldr_instr))) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001552 reg_pushed = GetRd(mem_write_instr);
1553 reg_popped = GetRd(mem_read_instr);
1554 pc_ -= 3 * kInstrSize;
1555 mov(reg_popped, reg_pushed);
1556 emit(ldr_instr);
1557 }
1558 if (FLAG_print_peephole_optimization) {
1559 PrintF("%x push/pop (ldr fp+off in middle)\n", pc_offset());
1560 }
1561 }
1562 }
mads.s.ager31e71382008-08-13 09:32:07 +00001563 }
1564 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001565}
1566
1567
1568void Assembler::str(Register src, const MemOperand& dst, Condition cond) {
1569 addrmod2(cond | B26, src, dst);
mads.s.ager31e71382008-08-13 09:32:07 +00001570
1571 // Eliminate pattern: pop(), push(r)
1572 // add sp, sp, #4 LeaveCC, al; str r, [sp, #-4], al
1573 // -> str r, [sp, 0], al
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001574 if (can_peephole_optimize(2) &&
ager@chromium.org5c838252010-02-19 08:53:10 +00001575 // Pattern.
mads.s.ager31e71382008-08-13 09:32:07 +00001576 instr_at(pc_ - 1 * kInstrSize) == (kPushRegPattern | src.code() * B12) &&
1577 instr_at(pc_ - 2 * kInstrSize) == kPopInstruction) {
1578 pc_ -= 2 * kInstrSize;
1579 emit(al | B26 | 0 | Offset | sp.code() * B16 | src.code() * B12);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001580 if (FLAG_print_peephole_optimization) {
mads.s.ager31e71382008-08-13 09:32:07 +00001581 PrintF("%x pop()/push(reg) eliminated\n", pc_offset());
1582 }
1583 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001584}
1585
1586
1587void Assembler::ldrb(Register dst, const MemOperand& src, Condition cond) {
1588 addrmod2(cond | B26 | B | L, dst, src);
1589}
1590
1591
1592void Assembler::strb(Register src, const MemOperand& dst, Condition cond) {
1593 addrmod2(cond | B26 | B, src, dst);
1594}
1595
1596
1597void Assembler::ldrh(Register dst, const MemOperand& src, Condition cond) {
1598 addrmod3(cond | L | B7 | H | B4, dst, src);
1599}
1600
1601
1602void Assembler::strh(Register src, const MemOperand& dst, Condition cond) {
1603 addrmod3(cond | B7 | H | B4, src, dst);
1604}
1605
1606
1607void Assembler::ldrsb(Register dst, const MemOperand& src, Condition cond) {
1608 addrmod3(cond | L | B7 | S6 | B4, dst, src);
1609}
1610
1611
1612void Assembler::ldrsh(Register dst, const MemOperand& src, Condition cond) {
1613 addrmod3(cond | L | B7 | S6 | H | B4, dst, src);
1614}
1615
1616
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001617void Assembler::ldrd(Register dst1, Register dst2,
1618 const MemOperand& src, Condition cond) {
1619 ASSERT(CpuFeatures::IsEnabled(ARMv7));
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001620 ASSERT(src.rm().is(no_reg));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001621 ASSERT(!dst1.is(lr)); // r14.
1622 ASSERT_EQ(0, dst1.code() % 2);
1623 ASSERT_EQ(dst1.code() + 1, dst2.code());
1624 addrmod3(cond | B7 | B6 | B4, dst1, src);
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001625}
1626
1627
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001628void Assembler::strd(Register src1, Register src2,
1629 const MemOperand& dst, Condition cond) {
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001630 ASSERT(dst.rm().is(no_reg));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001631 ASSERT(!src1.is(lr)); // r14.
1632 ASSERT_EQ(0, src1.code() % 2);
1633 ASSERT_EQ(src1.code() + 1, src2.code());
1634 ASSERT(CpuFeatures::IsEnabled(ARMv7));
1635 addrmod3(cond | B7 | B6 | B5 | B4, src1, dst);
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001636}
1637
ager@chromium.org5c838252010-02-19 08:53:10 +00001638// Load/Store multiple instructions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001639void Assembler::ldm(BlockAddrMode am,
1640 Register base,
1641 RegList dst,
1642 Condition cond) {
ager@chromium.org5c838252010-02-19 08:53:10 +00001643 // ABI stack constraint: ldmxx base, {..sp..} base != sp is not restartable.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001644 ASSERT(base.is(sp) || (dst & sp.bit()) == 0);
1645
1646 addrmod4(cond | B27 | am | L, base, dst);
1647
ager@chromium.org5c838252010-02-19 08:53:10 +00001648 // Emit the constant pool after a function return implemented by ldm ..{..pc}.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001649 if (cond == al && (dst & pc.bit()) != 0) {
1650 // There is a slight chance that the ldm instruction was actually a call,
1651 // in which case it would be wrong to return into the constant pool; we
1652 // recognize this case by checking if the emission of the pool was blocked
1653 // at the pc of the ldm instruction by a mov lr, pc instruction; if this is
1654 // the case, we emit a jump over the pool.
1655 CheckConstPool(true, no_const_pool_before_ == pc_offset() - kInstrSize);
1656 }
1657}
1658
1659
1660void Assembler::stm(BlockAddrMode am,
1661 Register base,
1662 RegList src,
1663 Condition cond) {
1664 addrmod4(cond | B27 | am, base, src);
1665}
1666
1667
ager@chromium.org5c838252010-02-19 08:53:10 +00001668// Exception-generating instructions and debugging support.
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001669// Stops with a non-negative code less than kNumOfWatchedStops support
1670// enabling/disabling and a counter feature. See simulator-arm.h .
1671void Assembler::stop(const char* msg, Condition cond, int32_t code) {
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001672#ifndef __arm__
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001673 ASSERT(code >= kDefaultStopCode);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001674 // The Simulator will handle the stop instruction and get the message address.
1675 // It expects to find the address just after the svc instruction.
1676 BlockConstPoolFor(2);
1677 if (code >= 0) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00001678 svc(kStopCode + code, cond);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001679 } else {
ager@chromium.org378b34e2011-01-28 08:04:38 +00001680 svc(kStopCode + kMaxStopCode, cond);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001681 }
1682 emit(reinterpret_cast<Instr>(msg));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001683#else // def __arm__
1684#ifdef CAN_USE_ARMV5_INSTRUCTIONS
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001685 if (cond != al) {
1686 Label skip;
1687 b(&skip, NegateCondition(cond));
1688 bkpt(0);
1689 bind(&skip);
1690 } else {
1691 bkpt(0);
1692 }
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001693#else // ndef CAN_USE_ARMV5_INSTRUCTIONS
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001694 svc(0x9f0001, cond);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001695#endif // ndef CAN_USE_ARMV5_INSTRUCTIONS
1696#endif // def __arm__
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001697}
1698
1699
1700void Assembler::bkpt(uint32_t imm16) { // v5 and above
1701 ASSERT(is_uint16(imm16));
ager@chromium.org378b34e2011-01-28 08:04:38 +00001702 emit(al | B24 | B21 | (imm16 >> 4)*B8 | BKPT | (imm16 & 0xf));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001703}
1704
1705
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001706void Assembler::svc(uint32_t imm24, Condition cond) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001707 ASSERT(is_uint24(imm24));
1708 emit(cond | 15*B24 | imm24);
1709}
1710
1711
ager@chromium.org5c838252010-02-19 08:53:10 +00001712// Coprocessor instructions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001713void Assembler::cdp(Coprocessor coproc,
1714 int opcode_1,
1715 CRegister crd,
1716 CRegister crn,
1717 CRegister crm,
1718 int opcode_2,
1719 Condition cond) {
1720 ASSERT(is_uint4(opcode_1) && is_uint3(opcode_2));
1721 emit(cond | B27 | B26 | B25 | (opcode_1 & 15)*B20 | crn.code()*B16 |
1722 crd.code()*B12 | coproc*B8 | (opcode_2 & 7)*B5 | crm.code());
1723}
1724
1725
1726void Assembler::cdp2(Coprocessor coproc,
1727 int opcode_1,
1728 CRegister crd,
1729 CRegister crn,
1730 CRegister crm,
1731 int opcode_2) { // v5 and above
ager@chromium.org378b34e2011-01-28 08:04:38 +00001732 cdp(coproc, opcode_1, crd, crn, crm, opcode_2, kSpecialCondition);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001733}
1734
1735
1736void Assembler::mcr(Coprocessor coproc,
1737 int opcode_1,
1738 Register rd,
1739 CRegister crn,
1740 CRegister crm,
1741 int opcode_2,
1742 Condition cond) {
1743 ASSERT(is_uint3(opcode_1) && is_uint3(opcode_2));
1744 emit(cond | B27 | B26 | B25 | (opcode_1 & 7)*B21 | crn.code()*B16 |
1745 rd.code()*B12 | coproc*B8 | (opcode_2 & 7)*B5 | B4 | crm.code());
1746}
1747
1748
1749void Assembler::mcr2(Coprocessor coproc,
1750 int opcode_1,
1751 Register rd,
1752 CRegister crn,
1753 CRegister crm,
1754 int opcode_2) { // v5 and above
ager@chromium.org378b34e2011-01-28 08:04:38 +00001755 mcr(coproc, opcode_1, rd, crn, crm, opcode_2, kSpecialCondition);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001756}
1757
1758
1759void Assembler::mrc(Coprocessor coproc,
1760 int opcode_1,
1761 Register rd,
1762 CRegister crn,
1763 CRegister crm,
1764 int opcode_2,
1765 Condition cond) {
1766 ASSERT(is_uint3(opcode_1) && is_uint3(opcode_2));
1767 emit(cond | B27 | B26 | B25 | (opcode_1 & 7)*B21 | L | crn.code()*B16 |
1768 rd.code()*B12 | coproc*B8 | (opcode_2 & 7)*B5 | B4 | crm.code());
1769}
1770
1771
1772void Assembler::mrc2(Coprocessor coproc,
1773 int opcode_1,
1774 Register rd,
1775 CRegister crn,
1776 CRegister crm,
1777 int opcode_2) { // v5 and above
ager@chromium.org378b34e2011-01-28 08:04:38 +00001778 mrc(coproc, opcode_1, rd, crn, crm, opcode_2, kSpecialCondition);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001779}
1780
1781
1782void Assembler::ldc(Coprocessor coproc,
1783 CRegister crd,
1784 const MemOperand& src,
1785 LFlag l,
1786 Condition cond) {
1787 addrmod5(cond | B27 | B26 | l | L | coproc*B8, crd, src);
1788}
1789
1790
1791void Assembler::ldc(Coprocessor coproc,
1792 CRegister crd,
1793 Register rn,
1794 int option,
1795 LFlag l,
1796 Condition cond) {
ager@chromium.org5c838252010-02-19 08:53:10 +00001797 // Unindexed addressing.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001798 ASSERT(is_uint8(option));
1799 emit(cond | B27 | B26 | U | l | L | rn.code()*B16 | crd.code()*B12 |
1800 coproc*B8 | (option & 255));
1801}
1802
1803
1804void Assembler::ldc2(Coprocessor coproc,
1805 CRegister crd,
1806 const MemOperand& src,
1807 LFlag l) { // v5 and above
ager@chromium.org378b34e2011-01-28 08:04:38 +00001808 ldc(coproc, crd, src, l, kSpecialCondition);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001809}
1810
1811
1812void Assembler::ldc2(Coprocessor coproc,
1813 CRegister crd,
1814 Register rn,
1815 int option,
1816 LFlag l) { // v5 and above
ager@chromium.org378b34e2011-01-28 08:04:38 +00001817 ldc(coproc, crd, rn, option, l, kSpecialCondition);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001818}
1819
1820
1821void Assembler::stc(Coprocessor coproc,
1822 CRegister crd,
1823 const MemOperand& dst,
1824 LFlag l,
1825 Condition cond) {
1826 addrmod5(cond | B27 | B26 | l | coproc*B8, crd, dst);
1827}
1828
1829
1830void Assembler::stc(Coprocessor coproc,
1831 CRegister crd,
1832 Register rn,
1833 int option,
1834 LFlag l,
1835 Condition cond) {
ager@chromium.org5c838252010-02-19 08:53:10 +00001836 // Unindexed addressing.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001837 ASSERT(is_uint8(option));
1838 emit(cond | B27 | B26 | U | l | rn.code()*B16 | crd.code()*B12 |
1839 coproc*B8 | (option & 255));
1840}
1841
1842
1843void Assembler::stc2(Coprocessor
1844 coproc, CRegister crd,
1845 const MemOperand& dst,
1846 LFlag l) { // v5 and above
ager@chromium.org378b34e2011-01-28 08:04:38 +00001847 stc(coproc, crd, dst, l, kSpecialCondition);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001848}
1849
1850
1851void Assembler::stc2(Coprocessor coproc,
1852 CRegister crd,
1853 Register rn,
1854 int option,
1855 LFlag l) { // v5 and above
ager@chromium.org378b34e2011-01-28 08:04:38 +00001856 stc(coproc, crd, rn, option, l, kSpecialCondition);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001857}
1858
1859
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001860// Support for VFP.
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001861
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001862void Assembler::vldr(const DwVfpRegister dst,
1863 const Register base,
1864 int offset,
1865 const Condition cond) {
1866 // Ddst = MEM(Rbase + offset).
1867 // Instruction details available in ARM DDI 0406A, A8-628.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001868 // cond(31-28) | 1101(27-24)| U001(23-20) | Rbase(19-16) |
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001869 // Vdst(15-12) | 1011(11-8) | offset
1870 ASSERT(CpuFeatures::IsEnabled(VFP3));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001871 int u = 1;
1872 if (offset < 0) {
1873 offset = -offset;
1874 u = 0;
1875 }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001876
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001877 ASSERT(offset >= 0);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001878 if ((offset % 4) == 0 && (offset / 4) < 256) {
1879 emit(cond | u*B23 | 0xD1*B20 | base.code()*B16 | dst.code()*B12 |
1880 0xB*B8 | ((offset / 4) & 255));
1881 } else {
1882 // Larger offsets must be handled by computing the correct address
1883 // in the ip register.
1884 ASSERT(!base.is(ip));
1885 if (u == 1) {
1886 add(ip, base, Operand(offset));
1887 } else {
1888 sub(ip, base, Operand(offset));
1889 }
1890 emit(cond | 0xD1*B20 | ip.code()*B16 | dst.code()*B12 | 0xB*B8);
1891 }
1892}
1893
1894
1895void Assembler::vldr(const DwVfpRegister dst,
1896 const MemOperand& operand,
1897 const Condition cond) {
1898 ASSERT(!operand.rm().is_valid());
1899 ASSERT(operand.am_ == Offset);
1900 vldr(dst, operand.rn(), operand.offset(), cond);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001901}
1902
1903
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001904void Assembler::vldr(const SwVfpRegister dst,
1905 const Register base,
1906 int offset,
1907 const Condition cond) {
1908 // Sdst = MEM(Rbase + offset).
1909 // Instruction details available in ARM DDI 0406A, A8-628.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001910 // cond(31-28) | 1101(27-24)| U001(23-20) | Rbase(19-16) |
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001911 // Vdst(15-12) | 1010(11-8) | offset
1912 ASSERT(CpuFeatures::IsEnabled(VFP3));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001913 int u = 1;
1914 if (offset < 0) {
1915 offset = -offset;
1916 u = 0;
1917 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001918 int sd, d;
1919 dst.split_code(&sd, &d);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001920 ASSERT(offset >= 0);
1921
1922 if ((offset % 4) == 0 && (offset / 4) < 256) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001923 emit(cond | u*B23 | d*B22 | 0xD1*B20 | base.code()*B16 | sd*B12 |
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001924 0xA*B8 | ((offset / 4) & 255));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001925 } else {
1926 // Larger offsets must be handled by computing the correct address
1927 // in the ip register.
1928 ASSERT(!base.is(ip));
1929 if (u == 1) {
1930 add(ip, base, Operand(offset));
1931 } else {
1932 sub(ip, base, Operand(offset));
1933 }
1934 emit(cond | d*B22 | 0xD1*B20 | ip.code()*B16 | sd*B12 | 0xA*B8);
1935 }
1936}
1937
1938
1939void Assembler::vldr(const SwVfpRegister dst,
1940 const MemOperand& operand,
1941 const Condition cond) {
1942 ASSERT(!operand.rm().is_valid());
1943 ASSERT(operand.am_ == Offset);
1944 vldr(dst, operand.rn(), operand.offset(), cond);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001945}
1946
1947
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001948void Assembler::vstr(const DwVfpRegister src,
1949 const Register base,
1950 int offset,
1951 const Condition cond) {
1952 // MEM(Rbase + offset) = Dsrc.
1953 // Instruction details available in ARM DDI 0406A, A8-786.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001954 // cond(31-28) | 1101(27-24)| U000(23-20) | | Rbase(19-16) |
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001955 // Vsrc(15-12) | 1011(11-8) | (offset/4)
1956 ASSERT(CpuFeatures::IsEnabled(VFP3));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001957 int u = 1;
1958 if (offset < 0) {
1959 offset = -offset;
1960 u = 0;
1961 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001962 ASSERT(offset >= 0);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001963 if ((offset % 4) == 0 && (offset / 4) < 256) {
1964 emit(cond | u*B23 | 0xD0*B20 | base.code()*B16 | src.code()*B12 |
1965 0xB*B8 | ((offset / 4) & 255));
1966 } else {
1967 // Larger offsets must be handled by computing the correct address
1968 // in the ip register.
1969 ASSERT(!base.is(ip));
1970 if (u == 1) {
1971 add(ip, base, Operand(offset));
1972 } else {
1973 sub(ip, base, Operand(offset));
1974 }
1975 emit(cond | 0xD0*B20 | ip.code()*B16 | src.code()*B12 | 0xB*B8);
1976 }
1977}
1978
1979
1980void Assembler::vstr(const DwVfpRegister src,
1981 const MemOperand& operand,
1982 const Condition cond) {
1983 ASSERT(!operand.rm().is_valid());
1984 ASSERT(operand.am_ == Offset);
1985 vstr(src, operand.rn(), operand.offset(), cond);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001986}
1987
1988
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001989void Assembler::vstr(const SwVfpRegister src,
1990 const Register base,
1991 int offset,
1992 const Condition cond) {
1993 // MEM(Rbase + offset) = SSrc.
1994 // Instruction details available in ARM DDI 0406A, A8-786.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001995 // cond(31-28) | 1101(27-24)| U000(23-20) | Rbase(19-16) |
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001996 // Vdst(15-12) | 1010(11-8) | (offset/4)
1997 ASSERT(CpuFeatures::IsEnabled(VFP3));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001998 int u = 1;
1999 if (offset < 0) {
2000 offset = -offset;
2001 u = 0;
2002 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002003 int sd, d;
2004 src.split_code(&sd, &d);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002005 ASSERT(offset >= 0);
2006 if ((offset % 4) == 0 && (offset / 4) < 256) {
2007 emit(cond | u*B23 | d*B22 | 0xD0*B20 | base.code()*B16 | sd*B12 |
2008 0xA*B8 | ((offset / 4) & 255));
2009 } else {
2010 // Larger offsets must be handled by computing the correct address
2011 // in the ip register.
2012 ASSERT(!base.is(ip));
2013 if (u == 1) {
2014 add(ip, base, Operand(offset));
2015 } else {
2016 sub(ip, base, Operand(offset));
2017 }
2018 emit(cond | d*B22 | 0xD0*B20 | ip.code()*B16 | sd*B12 | 0xA*B8);
2019 }
2020}
2021
2022
2023void Assembler::vstr(const SwVfpRegister src,
2024 const MemOperand& operand,
2025 const Condition cond) {
2026 ASSERT(!operand.rm().is_valid());
2027 ASSERT(operand.am_ == Offset);
2028 vldr(src, operand.rn(), operand.offset(), cond);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00002029}
2030
2031
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002032static void DoubleAsTwoUInt32(double d, uint32_t* lo, uint32_t* hi) {
2033 uint64_t i;
2034 memcpy(&i, &d, 8);
2035
2036 *lo = i & 0xffffffff;
2037 *hi = i >> 32;
2038}
2039
2040// Only works for little endian floating point formats.
2041// We don't support VFP on the mixed endian floating point platform.
2042static bool FitsVMOVDoubleImmediate(double d, uint32_t *encoding) {
2043 ASSERT(CpuFeatures::IsEnabled(VFP3));
2044
2045 // VMOV can accept an immediate of the form:
2046 //
2047 // +/- m * 2^(-n) where 16 <= m <= 31 and 0 <= n <= 7
2048 //
2049 // The immediate is encoded using an 8-bit quantity, comprised of two
2050 // 4-bit fields. For an 8-bit immediate of the form:
2051 //
2052 // [abcdefgh]
2053 //
2054 // where a is the MSB and h is the LSB, an immediate 64-bit double can be
2055 // created of the form:
2056 //
2057 // [aBbbbbbb,bbcdefgh,00000000,00000000,
2058 // 00000000,00000000,00000000,00000000]
2059 //
2060 // where B = ~b.
2061 //
2062
2063 uint32_t lo, hi;
2064 DoubleAsTwoUInt32(d, &lo, &hi);
2065
2066 // The most obvious constraint is the long block of zeroes.
2067 if ((lo != 0) || ((hi & 0xffff) != 0)) {
2068 return false;
2069 }
2070
2071 // Bits 62:55 must be all clear or all set.
2072 if (((hi & 0x3fc00000) != 0) && ((hi & 0x3fc00000) != 0x3fc00000)) {
2073 return false;
2074 }
2075
2076 // Bit 63 must be NOT bit 62.
2077 if (((hi ^ (hi << 1)) & (0x40000000)) == 0) {
2078 return false;
2079 }
2080
2081 // Create the encoded immediate in the form:
2082 // [00000000,0000abcd,00000000,0000efgh]
2083 *encoding = (hi >> 16) & 0xf; // Low nybble.
2084 *encoding |= (hi >> 4) & 0x70000; // Low three bits of the high nybble.
2085 *encoding |= (hi >> 12) & 0x80000; // Top bit of the high nybble.
2086
2087 return true;
2088}
2089
2090
2091void Assembler::vmov(const DwVfpRegister dst,
2092 double imm,
2093 const Condition cond) {
2094 // Dd = immediate
2095 // Instruction details available in ARM DDI 0406B, A8-640.
2096 ASSERT(CpuFeatures::IsEnabled(VFP3));
2097
2098 uint32_t enc;
2099 if (FitsVMOVDoubleImmediate(imm, &enc)) {
2100 // The double can be encoded in the instruction.
2101 emit(cond | 0xE*B24 | 0xB*B20 | dst.code()*B12 | 0xB*B8 | enc);
2102 } else {
2103 // Synthesise the double from ARM immediates. This could be implemented
2104 // using vldr from a constant pool.
2105 uint32_t lo, hi;
2106 DoubleAsTwoUInt32(imm, &lo, &hi);
2107
2108 if (lo == hi) {
2109 // If the lo and hi parts of the double are equal, the literal is easier
2110 // to create. This is the case with 0.0.
2111 mov(ip, Operand(lo));
2112 vmov(dst, ip, ip);
2113 } else {
2114 // Move the low part of the double into the lower of the corresponsing S
2115 // registers of D register dst.
2116 mov(ip, Operand(lo));
2117 vmov(dst.low(), ip, cond);
2118
2119 // Move the high part of the double into the higher of the corresponsing S
2120 // registers of D register dst.
2121 mov(ip, Operand(hi));
2122 vmov(dst.high(), ip, cond);
2123 }
2124 }
2125}
2126
2127
2128void Assembler::vmov(const SwVfpRegister dst,
2129 const SwVfpRegister src,
2130 const Condition cond) {
2131 // Sd = Sm
2132 // Instruction details available in ARM DDI 0406B, A8-642.
2133 ASSERT(CpuFeatures::IsEnabled(VFP3));
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002134 int sd, d, sm, m;
2135 dst.split_code(&sd, &d);
2136 src.split_code(&sm, &m);
2137 emit(cond | 0xE*B24 | d*B22 | 0xB*B20 | sd*B12 | 0xA*B8 | B6 | m*B5 | sm);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002138}
2139
2140
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00002141void Assembler::vmov(const DwVfpRegister dst,
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00002142 const DwVfpRegister src,
2143 const Condition cond) {
2144 // Dd = Dm
2145 // Instruction details available in ARM DDI 0406B, A8-642.
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002146 ASSERT(CpuFeatures::IsEnabled(VFP3));
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00002147 emit(cond | 0xE*B24 | 0xB*B20 |
2148 dst.code()*B12 | 0x5*B9 | B8 | B6 | src.code());
2149}
2150
2151
2152void Assembler::vmov(const DwVfpRegister dst,
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00002153 const Register src1,
2154 const Register src2,
2155 const Condition cond) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002156 // Dm = <Rt,Rt2>.
2157 // Instruction details available in ARM DDI 0406A, A8-646.
2158 // cond(31-28) | 1100(27-24)| 010(23-21) | op=0(20) | Rt2(19-16) |
2159 // Rt(15-12) | 1011(11-8) | 00(7-6) | M(5) | 1(4) | Vm
2160 ASSERT(CpuFeatures::IsEnabled(VFP3));
2161 ASSERT(!src1.is(pc) && !src2.is(pc));
2162 emit(cond | 0xC*B24 | B22 | src2.code()*B16 |
2163 src1.code()*B12 | 0xB*B8 | B4 | dst.code());
2164}
2165
2166
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00002167void Assembler::vmov(const Register dst1,
2168 const Register dst2,
2169 const DwVfpRegister src,
2170 const Condition cond) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002171 // <Rt,Rt2> = Dm.
2172 // Instruction details available in ARM DDI 0406A, A8-646.
2173 // cond(31-28) | 1100(27-24)| 010(23-21) | op=1(20) | Rt2(19-16) |
2174 // Rt(15-12) | 1011(11-8) | 00(7-6) | M(5) | 1(4) | Vm
2175 ASSERT(CpuFeatures::IsEnabled(VFP3));
2176 ASSERT(!dst1.is(pc) && !dst2.is(pc));
2177 emit(cond | 0xC*B24 | B22 | B20 | dst2.code()*B16 |
2178 dst1.code()*B12 | 0xB*B8 | B4 | src.code());
2179}
2180
2181
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00002182void Assembler::vmov(const SwVfpRegister dst,
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002183 const Register src,
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002184 const Condition cond) {
2185 // Sn = Rt.
2186 // Instruction details available in ARM DDI 0406A, A8-642.
2187 // cond(31-28) | 1110(27-24)| 000(23-21) | op=0(20) | Vn(19-16) |
2188 // Rt(15-12) | 1010(11-8) | N(7)=0 | 00(6-5) | 1(4) | 0000(3-0)
2189 ASSERT(CpuFeatures::IsEnabled(VFP3));
2190 ASSERT(!src.is(pc));
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002191 int sn, n;
2192 dst.split_code(&sn, &n);
2193 emit(cond | 0xE*B24 | sn*B16 | src.code()*B12 | 0xA*B8 | n*B7 | B4);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002194}
2195
2196
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00002197void Assembler::vmov(const Register dst,
2198 const SwVfpRegister src,
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002199 const Condition cond) {
2200 // Rt = Sn.
2201 // Instruction details available in ARM DDI 0406A, A8-642.
2202 // cond(31-28) | 1110(27-24)| 000(23-21) | op=1(20) | Vn(19-16) |
2203 // Rt(15-12) | 1010(11-8) | N(7)=0 | 00(6-5) | 1(4) | 0000(3-0)
2204 ASSERT(CpuFeatures::IsEnabled(VFP3));
2205 ASSERT(!dst.is(pc));
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002206 int sn, n;
2207 src.split_code(&sn, &n);
2208 emit(cond | 0xE*B24 | B20 | sn*B16 | dst.code()*B12 | 0xA*B8 | n*B7 | B4);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002209}
2210
2211
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002212// Type of data to read from or write to VFP register.
2213// Used as specifier in generic vcvt instruction.
2214enum VFPType { S32, U32, F32, F64 };
2215
2216
2217static bool IsSignedVFPType(VFPType type) {
2218 switch (type) {
2219 case S32:
2220 return true;
2221 case U32:
2222 return false;
2223 default:
2224 UNREACHABLE();
2225 return false;
2226 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002227}
2228
2229
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002230static bool IsIntegerVFPType(VFPType type) {
2231 switch (type) {
2232 case S32:
2233 case U32:
2234 return true;
2235 case F32:
2236 case F64:
2237 return false;
2238 default:
2239 UNREACHABLE();
2240 return false;
2241 }
2242}
2243
2244
2245static bool IsDoubleVFPType(VFPType type) {
2246 switch (type) {
2247 case F32:
2248 return false;
2249 case F64:
2250 return true;
2251 default:
2252 UNREACHABLE();
2253 return false;
2254 }
2255}
2256
2257
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002258// Split five bit reg_code based on size of reg_type.
2259// 32-bit register codes are Vm:M
2260// 64-bit register codes are M:Vm
2261// where Vm is four bits, and M is a single bit.
2262static void SplitRegCode(VFPType reg_type,
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002263 int reg_code,
2264 int* vm,
2265 int* m) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002266 ASSERT((reg_code >= 0) && (reg_code <= 31));
2267 if (IsIntegerVFPType(reg_type) || !IsDoubleVFPType(reg_type)) {
2268 // 32 bit type.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002269 *m = reg_code & 0x1;
2270 *vm = reg_code >> 1;
2271 } else {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002272 // 64 bit type.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002273 *m = (reg_code & 0x10) >> 4;
2274 *vm = reg_code & 0x0F;
2275 }
2276}
2277
2278
2279// Encode vcvt.src_type.dst_type instruction.
2280static Instr EncodeVCVT(const VFPType dst_type,
2281 const int dst_code,
2282 const VFPType src_type,
2283 const int src_code,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002284 VFPConversionMode mode,
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002285 const Condition cond) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002286 ASSERT(src_type != dst_type);
2287 int D, Vd, M, Vm;
2288 SplitRegCode(src_type, src_code, &Vm, &M);
2289 SplitRegCode(dst_type, dst_code, &Vd, &D);
2290
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002291 if (IsIntegerVFPType(dst_type) || IsIntegerVFPType(src_type)) {
2292 // Conversion between IEEE floating point and 32-bit integer.
2293 // Instruction details available in ARM DDI 0406B, A8.6.295.
2294 // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 1(19) | opc2(18-16) |
2295 // Vd(15-12) | 101(11-9) | sz(8) | op(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
2296 ASSERT(!IsIntegerVFPType(dst_type) || !IsIntegerVFPType(src_type));
2297
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002298 int sz, opc2, op;
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002299
2300 if (IsIntegerVFPType(dst_type)) {
2301 opc2 = IsSignedVFPType(dst_type) ? 0x5 : 0x4;
2302 sz = IsDoubleVFPType(src_type) ? 0x1 : 0x0;
ager@chromium.org01fe7df2010-11-10 11:59:11 +00002303 op = mode;
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002304 } else {
2305 ASSERT(IsIntegerVFPType(src_type));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002306 opc2 = 0x0;
2307 sz = IsDoubleVFPType(dst_type) ? 0x1 : 0x0;
2308 op = IsSignedVFPType(src_type) ? 0x1 : 0x0;
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002309 }
2310
2311 return (cond | 0xE*B24 | B23 | D*B22 | 0x3*B20 | B19 | opc2*B16 |
2312 Vd*B12 | 0x5*B9 | sz*B8 | op*B7 | B6 | M*B5 | Vm);
2313 } else {
2314 // Conversion between IEEE double and single precision.
2315 // Instruction details available in ARM DDI 0406B, A8.6.298.
2316 // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 0111(19-16) |
2317 // Vd(15-12) | 101(11-9) | sz(8) | 1(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002318 int sz = IsDoubleVFPType(src_type) ? 0x1 : 0x0;
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002319 return (cond | 0xE*B24 | B23 | D*B22 | 0x3*B20 | 0x7*B16 |
2320 Vd*B12 | 0x5*B9 | sz*B8 | B7 | B6 | M*B5 | Vm);
2321 }
2322}
2323
2324
2325void Assembler::vcvt_f64_s32(const DwVfpRegister dst,
2326 const SwVfpRegister src,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002327 VFPConversionMode mode,
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002328 const Condition cond) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002329 ASSERT(CpuFeatures::IsEnabled(VFP3));
ager@chromium.org01fe7df2010-11-10 11:59:11 +00002330 emit(EncodeVCVT(F64, dst.code(), S32, src.code(), mode, cond));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002331}
2332
2333
2334void Assembler::vcvt_f32_s32(const SwVfpRegister dst,
2335 const SwVfpRegister src,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002336 VFPConversionMode mode,
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002337 const Condition cond) {
2338 ASSERT(CpuFeatures::IsEnabled(VFP3));
ager@chromium.org01fe7df2010-11-10 11:59:11 +00002339 emit(EncodeVCVT(F32, dst.code(), S32, src.code(), mode, cond));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002340}
2341
2342
2343void Assembler::vcvt_f64_u32(const DwVfpRegister dst,
2344 const SwVfpRegister src,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002345 VFPConversionMode mode,
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002346 const Condition cond) {
2347 ASSERT(CpuFeatures::IsEnabled(VFP3));
ager@chromium.org01fe7df2010-11-10 11:59:11 +00002348 emit(EncodeVCVT(F64, dst.code(), U32, src.code(), mode, cond));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002349}
2350
2351
2352void Assembler::vcvt_s32_f64(const SwVfpRegister dst,
2353 const DwVfpRegister src,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002354 VFPConversionMode mode,
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002355 const Condition cond) {
2356 ASSERT(CpuFeatures::IsEnabled(VFP3));
ager@chromium.org01fe7df2010-11-10 11:59:11 +00002357 emit(EncodeVCVT(S32, dst.code(), F64, src.code(), mode, cond));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002358}
2359
2360
2361void Assembler::vcvt_u32_f64(const SwVfpRegister dst,
2362 const DwVfpRegister src,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002363 VFPConversionMode mode,
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002364 const Condition cond) {
2365 ASSERT(CpuFeatures::IsEnabled(VFP3));
ager@chromium.org01fe7df2010-11-10 11:59:11 +00002366 emit(EncodeVCVT(U32, dst.code(), F64, src.code(), mode, cond));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002367}
2368
2369
2370void Assembler::vcvt_f64_f32(const DwVfpRegister dst,
2371 const SwVfpRegister src,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002372 VFPConversionMode mode,
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002373 const Condition cond) {
2374 ASSERT(CpuFeatures::IsEnabled(VFP3));
ager@chromium.org01fe7df2010-11-10 11:59:11 +00002375 emit(EncodeVCVT(F64, dst.code(), F32, src.code(), mode, cond));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002376}
2377
2378
2379void Assembler::vcvt_f32_f64(const SwVfpRegister dst,
2380 const DwVfpRegister src,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002381 VFPConversionMode mode,
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002382 const Condition cond) {
2383 ASSERT(CpuFeatures::IsEnabled(VFP3));
ager@chromium.org01fe7df2010-11-10 11:59:11 +00002384 emit(EncodeVCVT(F32, dst.code(), F64, src.code(), mode, cond));
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002385}
2386
2387
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002388void Assembler::vneg(const DwVfpRegister dst,
2389 const DwVfpRegister src,
2390 const Condition cond) {
2391 emit(cond | 0xE*B24 | 0xB*B20 | B16 | dst.code()*B12 |
2392 0x5*B9 | B8 | B6 | src.code());
2393}
2394
2395
whesse@chromium.org7a392b32011-01-31 11:30:36 +00002396void Assembler::vabs(const DwVfpRegister dst,
2397 const DwVfpRegister src,
2398 const Condition cond) {
2399 emit(cond | 0xE*B24 | 0xB*B20 | dst.code()*B12 |
2400 0x5*B9 | B8 | 0x3*B6 | src.code());
2401}
2402
2403
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00002404void Assembler::vadd(const DwVfpRegister dst,
2405 const DwVfpRegister src1,
2406 const DwVfpRegister src2,
2407 const Condition cond) {
2408 // Dd = vadd(Dn, Dm) double precision floating point addition.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002409 // Dd = D:Vd; Dm=M:Vm; Dn=N:Vm.
2410 // Instruction details available in ARM DDI 0406A, A8-536.
2411 // cond(31-28) | 11100(27-23)| D=?(22) | 11(21-20) | Vn(19-16) |
2412 // Vd(15-12) | 101(11-9) | sz(8)=1 | N(7)=0 | 0(6) | M=?(5) | 0(4) | Vm(3-0)
2413 ASSERT(CpuFeatures::IsEnabled(VFP3));
2414 emit(cond | 0xE*B24 | 0x3*B20 | src1.code()*B16 |
2415 dst.code()*B12 | 0x5*B9 | B8 | src2.code());
2416}
2417
2418
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00002419void Assembler::vsub(const DwVfpRegister dst,
2420 const DwVfpRegister src1,
2421 const DwVfpRegister src2,
2422 const Condition cond) {
2423 // Dd = vsub(Dn, Dm) double precision floating point subtraction.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002424 // Dd = D:Vd; Dm=M:Vm; Dn=N:Vm.
2425 // Instruction details available in ARM DDI 0406A, A8-784.
2426 // cond(31-28) | 11100(27-23)| D=?(22) | 11(21-20) | Vn(19-16) |
2427 // Vd(15-12) | 101(11-9) | sz(8)=1 | N(7)=0 | 1(6) | M=?(5) | 0(4) | Vm(3-0)
2428 ASSERT(CpuFeatures::IsEnabled(VFP3));
2429 emit(cond | 0xE*B24 | 0x3*B20 | src1.code()*B16 |
2430 dst.code()*B12 | 0x5*B9 | B8 | B6 | src2.code());
2431}
2432
2433
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00002434void Assembler::vmul(const DwVfpRegister dst,
2435 const DwVfpRegister src1,
2436 const DwVfpRegister src2,
2437 const Condition cond) {
2438 // Dd = vmul(Dn, Dm) double precision floating point multiplication.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002439 // Dd = D:Vd; Dm=M:Vm; Dn=N:Vm.
2440 // Instruction details available in ARM DDI 0406A, A8-784.
2441 // cond(31-28) | 11100(27-23)| D=?(22) | 10(21-20) | Vn(19-16) |
2442 // Vd(15-12) | 101(11-9) | sz(8)=1 | N(7)=0 | 0(6) | M=?(5) | 0(4) | Vm(3-0)
2443 ASSERT(CpuFeatures::IsEnabled(VFP3));
2444 emit(cond | 0xE*B24 | 0x2*B20 | src1.code()*B16 |
2445 dst.code()*B12 | 0x5*B9 | B8 | src2.code());
2446}
2447
2448
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00002449void Assembler::vdiv(const DwVfpRegister dst,
2450 const DwVfpRegister src1,
2451 const DwVfpRegister src2,
2452 const Condition cond) {
2453 // Dd = vdiv(Dn, Dm) double precision floating point division.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002454 // Dd = D:Vd; Dm=M:Vm; Dn=N:Vm.
2455 // Instruction details available in ARM DDI 0406A, A8-584.
2456 // cond(31-28) | 11101(27-23)| D=?(22) | 00(21-20) | Vn(19-16) |
2457 // Vd(15-12) | 101(11-9) | sz(8)=1 | N(7)=? | 0(6) | M=?(5) | 0(4) | Vm(3-0)
2458 ASSERT(CpuFeatures::IsEnabled(VFP3));
2459 emit(cond | 0xE*B24 | B23 | src1.code()*B16 |
2460 dst.code()*B12 | 0x5*B9 | B8 | src2.code());
2461}
2462
2463
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00002464void Assembler::vcmp(const DwVfpRegister src1,
2465 const DwVfpRegister src2,
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002466 const Condition cond) {
2467 // vcmp(Dd, Dm) double precision floating point comparison.
2468 // Instruction details available in ARM DDI 0406A, A8-570.
2469 // cond(31-28) | 11101 (27-23)| D=?(22) | 11 (21-20) | 0100 (19-16) |
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002470 // Vd(15-12) | 101(11-9) | sz(8)=1 | E(7)=0 | 1(6) | M(5)=? | 0(4) | Vm(3-0)
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002471 ASSERT(CpuFeatures::IsEnabled(VFP3));
2472 emit(cond | 0xE*B24 |B23 | 0x3*B20 | B18 |
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002473 src1.code()*B12 | 0x5*B9 | B8 | B6 | src2.code());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002474}
2475
2476
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002477void Assembler::vcmp(const DwVfpRegister src1,
2478 const double src2,
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002479 const Condition cond) {
2480 // vcmp(Dd, Dm) double precision floating point comparison.
2481 // Instruction details available in ARM DDI 0406A, A8-570.
2482 // cond(31-28) | 11101 (27-23)| D=?(22) | 11 (21-20) | 0101 (19-16) |
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002483 // Vd(15-12) | 101(11-9) | sz(8)=1 | E(7)=0 | 1(6) | M(5)=? | 0(4) | 0000(3-0)
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002484 ASSERT(CpuFeatures::IsEnabled(VFP3));
2485 ASSERT(src2 == 0.0);
2486 emit(cond | 0xE*B24 |B23 | 0x3*B20 | B18 | B16 |
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002487 src1.code()*B12 | 0x5*B9 | B8 | B6);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002488}
2489
2490
ager@chromium.org01fe7df2010-11-10 11:59:11 +00002491void Assembler::vmsr(Register dst, Condition cond) {
2492 // Instruction details available in ARM DDI 0406A, A8-652.
2493 // cond(31-28) | 1110 (27-24) | 1110(23-20)| 0001 (19-16) |
2494 // Rt(15-12) | 1010 (11-8) | 0(7) | 00 (6-5) | 1(4) | 0000(3-0)
2495 ASSERT(CpuFeatures::IsEnabled(VFP3));
2496 emit(cond | 0xE*B24 | 0xE*B20 | B16 |
2497 dst.code()*B12 | 0xA*B8 | B4);
2498}
2499
2500
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002501void Assembler::vmrs(Register dst, Condition cond) {
2502 // Instruction details available in ARM DDI 0406A, A8-652.
2503 // cond(31-28) | 1110 (27-24) | 1111(23-20)| 0001 (19-16) |
2504 // Rt(15-12) | 1010 (11-8) | 0(7) | 00 (6-5) | 1(4) | 0000(3-0)
2505 ASSERT(CpuFeatures::IsEnabled(VFP3));
2506 emit(cond | 0xE*B24 | 0xF*B20 | B16 |
2507 dst.code()*B12 | 0xA*B8 | B4);
2508}
2509
2510
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002511void Assembler::vsqrt(const DwVfpRegister dst,
2512 const DwVfpRegister src,
2513 const Condition cond) {
2514 // cond(31-28) | 11101 (27-23)| D=?(22) | 11 (21-20) | 0001 (19-16) |
2515 // Vd(15-12) | 101(11-9) | sz(8)=1 | 11 (7-6) | M(5)=? | 0(4) | Vm(3-0)
2516 ASSERT(CpuFeatures::IsEnabled(VFP3));
2517 emit(cond | 0xE*B24 | B23 | 0x3*B20 | B16 |
2518 dst.code()*B12 | 0x5*B9 | B8 | 3*B6 | src.code());
2519}
2520
2521
ager@chromium.org5c838252010-02-19 08:53:10 +00002522// Pseudo instructions.
fschneider@chromium.org013f3e12010-04-26 13:27:52 +00002523void Assembler::nop(int type) {
2524 // This is mov rx, rx.
2525 ASSERT(0 <= type && type <= 14); // mov pc, pc is not a nop.
2526 emit(al | 13*B21 | type*B12 | type);
2527}
2528
2529
ager@chromium.orgbeb25712010-11-29 08:02:25 +00002530bool Assembler::IsNop(Instr instr, int type) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002531 // Check for mov rx, rx where x = type.
ager@chromium.orgbeb25712010-11-29 08:02:25 +00002532 ASSERT(0 <= type && type <= 14); // mov pc, pc is not a nop.
2533 return instr == (al | 13*B21 | type*B12 | type);
2534}
2535
2536
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002537bool Assembler::ImmediateFitsAddrMode1Instruction(int32_t imm32) {
2538 uint32_t dummy1;
2539 uint32_t dummy2;
2540 return fits_shifter(imm32, &dummy1, &dummy2, NULL);
2541}
2542
2543
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00002544void Assembler::BlockConstPoolFor(int instructions) {
2545 BlockConstPoolBefore(pc_offset() + instructions * kInstrSize);
2546}
2547
2548
ager@chromium.org5c838252010-02-19 08:53:10 +00002549// Debugging.
ager@chromium.org4af710e2009-09-15 12:20:11 +00002550void Assembler::RecordJSReturn() {
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002551 positions_recorder()->WriteRecordedPositions();
ager@chromium.org4af710e2009-09-15 12:20:11 +00002552 CheckBuffer();
2553 RecordRelocInfo(RelocInfo::JS_RETURN);
2554}
2555
2556
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00002557void Assembler::RecordDebugBreakSlot() {
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002558 positions_recorder()->WriteRecordedPositions();
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00002559 CheckBuffer();
2560 RecordRelocInfo(RelocInfo::DEBUG_BREAK_SLOT);
2561}
2562
2563
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002564void Assembler::RecordComment(const char* msg) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002565 if (FLAG_code_comments) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002566 CheckBuffer();
ager@chromium.org236ad962008-09-25 09:45:57 +00002567 RecordRelocInfo(RelocInfo::COMMENT, reinterpret_cast<intptr_t>(msg));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002568 }
2569}
2570
2571
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002572void Assembler::GrowBuffer() {
2573 if (!own_buffer_) FATAL("external code buffer is too small");
2574
ager@chromium.org5c838252010-02-19 08:53:10 +00002575 // Compute new buffer size.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002576 CodeDesc desc; // the new buffer
2577 if (buffer_size_ < 4*KB) {
2578 desc.buffer_size = 4*KB;
2579 } else if (buffer_size_ < 1*MB) {
2580 desc.buffer_size = 2*buffer_size_;
2581 } else {
2582 desc.buffer_size = buffer_size_ + 1*MB;
2583 }
2584 CHECK_GT(desc.buffer_size, 0); // no overflow
2585
ager@chromium.org5c838252010-02-19 08:53:10 +00002586 // Setup new buffer.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002587 desc.buffer = NewArray<byte>(desc.buffer_size);
2588
2589 desc.instr_size = pc_offset();
2590 desc.reloc_size = (buffer_ + buffer_size_) - reloc_info_writer.pos();
2591
ager@chromium.org5c838252010-02-19 08:53:10 +00002592 // Copy the data.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002593 int pc_delta = desc.buffer - buffer_;
2594 int rc_delta = (desc.buffer + desc.buffer_size) - (buffer_ + buffer_size_);
2595 memmove(desc.buffer, buffer_, desc.instr_size);
2596 memmove(reloc_info_writer.pos() + rc_delta,
2597 reloc_info_writer.pos(), desc.reloc_size);
2598
ager@chromium.org5c838252010-02-19 08:53:10 +00002599 // Switch buffers.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002600 DeleteArray(buffer_);
2601 buffer_ = desc.buffer;
2602 buffer_size_ = desc.buffer_size;
2603 pc_ += pc_delta;
2604 reloc_info_writer.Reposition(reloc_info_writer.pos() + rc_delta,
2605 reloc_info_writer.last_pc() + pc_delta);
2606
ager@chromium.org5c838252010-02-19 08:53:10 +00002607 // None of our relocation types are pc relative pointing outside the code
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002608 // buffer nor pc absolute pointing inside the code buffer, so there is no need
ager@chromium.org5c838252010-02-19 08:53:10 +00002609 // to relocate any emitted relocation entries.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002610
ager@chromium.org5c838252010-02-19 08:53:10 +00002611 // Relocate pending relocation entries.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002612 for (int i = 0; i < num_prinfo_; i++) {
2613 RelocInfo& rinfo = prinfo_[i];
ager@chromium.org236ad962008-09-25 09:45:57 +00002614 ASSERT(rinfo.rmode() != RelocInfo::COMMENT &&
2615 rinfo.rmode() != RelocInfo::POSITION);
ager@chromium.org4af710e2009-09-15 12:20:11 +00002616 if (rinfo.rmode() != RelocInfo::JS_RETURN) {
2617 rinfo.set_pc(rinfo.pc() + pc_delta);
2618 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002619 }
2620}
2621
2622
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002623void Assembler::db(uint8_t data) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002624 // No relocation info should be pending while using db. db is used
2625 // to write pure data with no pointers and the constant pool should
2626 // be emitted before using db.
2627 ASSERT(num_prinfo_ == 0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002628 CheckBuffer();
2629 *reinterpret_cast<uint8_t*>(pc_) = data;
2630 pc_ += sizeof(uint8_t);
2631}
2632
2633
2634void Assembler::dd(uint32_t data) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002635 // No relocation info should be pending while using dd. dd is used
2636 // to write pure data with no pointers and the constant pool should
2637 // be emitted before using dd.
2638 ASSERT(num_prinfo_ == 0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002639 CheckBuffer();
2640 *reinterpret_cast<uint32_t*>(pc_) = data;
2641 pc_ += sizeof(uint32_t);
2642}
2643
2644
ager@chromium.org236ad962008-09-25 09:45:57 +00002645void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002646 RelocInfo rinfo(pc_, rmode, data); // we do not try to reuse pool constants
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00002647 if (rmode >= RelocInfo::JS_RETURN && rmode <= RelocInfo::DEBUG_BREAK_SLOT) {
ager@chromium.org5c838252010-02-19 08:53:10 +00002648 // Adjust code for new modes.
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00002649 ASSERT(RelocInfo::IsDebugBreakSlot(rmode)
2650 || RelocInfo::IsJSReturn(rmode)
ager@chromium.org4af710e2009-09-15 12:20:11 +00002651 || RelocInfo::IsComment(rmode)
2652 || RelocInfo::IsPosition(rmode));
ager@chromium.org5c838252010-02-19 08:53:10 +00002653 // These modes do not need an entry in the constant pool.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002654 } else {
2655 ASSERT(num_prinfo_ < kMaxNumPRInfo);
2656 prinfo_[num_prinfo_++] = rinfo;
2657 // Make sure the constant pool is not emitted in place of the next
ager@chromium.org5c838252010-02-19 08:53:10 +00002658 // instruction for which we just recorded relocation info.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002659 BlockConstPoolBefore(pc_offset() + kInstrSize);
2660 }
ager@chromium.org236ad962008-09-25 09:45:57 +00002661 if (rinfo.rmode() != RelocInfo::NONE) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002662 // Don't record external references unless the heap will be serialized.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002663 if (rmode == RelocInfo::EXTERNAL_REFERENCE) {
2664#ifdef DEBUG
2665 if (!Serializer::enabled()) {
2666 Serializer::TooLateToEnableNow();
2667 }
2668#endif
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002669 if (!Serializer::enabled() && !emit_debug_code()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002670 return;
2671 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002672 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002673 ASSERT(buffer_space() >= kMaxRelocSize); // too late to grow buffer here
2674 reloc_info_writer.Write(&rinfo);
2675 }
2676}
2677
2678
2679void Assembler::CheckConstPool(bool force_emit, bool require_jump) {
2680 // Calculate the offset of the next check. It will be overwritten
2681 // when a const pool is generated or when const pools are being
2682 // blocked for a specific range.
2683 next_buffer_check_ = pc_offset() + kCheckConstInterval;
2684
ager@chromium.org5c838252010-02-19 08:53:10 +00002685 // There is nothing to do if there are no pending relocation info entries.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002686 if (num_prinfo_ == 0) return;
2687
2688 // We emit a constant pool at regular intervals of about kDistBetweenPools
2689 // or when requested by parameter force_emit (e.g. after each function).
2690 // We prefer not to emit a jump unless the max distance is reached or if we
2691 // are running low on slots, which can happen if a lot of constants are being
2692 // emitted (e.g. --debug-code and many static references).
2693 int dist = pc_offset() - last_const_pool_end_;
2694 if (!force_emit && dist < kMaxDistBetweenPools &&
2695 (require_jump || dist < kDistBetweenPools) &&
2696 // TODO(1236125): Cleanup the "magic" number below. We know that
2697 // the code generation will test every kCheckConstIntervalInst.
2698 // Thus we are safe as long as we generate less than 7 constant
2699 // entries per instruction.
2700 (num_prinfo_ < (kMaxNumPRInfo - (7 * kCheckConstIntervalInst)))) {
2701 return;
2702 }
2703
2704 // If we did not return by now, we need to emit the constant pool soon.
2705
2706 // However, some small sequences of instructions must not be broken up by the
2707 // insertion of a constant pool; such sequences are protected by setting
fschneider@chromium.org013f3e12010-04-26 13:27:52 +00002708 // either const_pool_blocked_nesting_ or no_const_pool_before_, which are
2709 // both checked here. Also, recursive calls to CheckConstPool are blocked by
2710 // no_const_pool_before_.
2711 if (const_pool_blocked_nesting_ > 0 || pc_offset() < no_const_pool_before_) {
ager@chromium.org5c838252010-02-19 08:53:10 +00002712 // Emission is currently blocked; make sure we try again as soon as
2713 // possible.
fschneider@chromium.org013f3e12010-04-26 13:27:52 +00002714 if (const_pool_blocked_nesting_ > 0) {
2715 next_buffer_check_ = pc_offset() + kInstrSize;
2716 } else {
2717 next_buffer_check_ = no_const_pool_before_;
2718 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002719
ager@chromium.org5c838252010-02-19 08:53:10 +00002720 // Something is wrong if emission is forced and blocked at the same time.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002721 ASSERT(!force_emit);
2722 return;
2723 }
2724
2725 int jump_instr = require_jump ? kInstrSize : 0;
2726
2727 // Check that the code buffer is large enough before emitting the constant
2728 // pool and relocation information (include the jump over the pool and the
2729 // constant pool marker).
2730 int max_needed_space =
2731 jump_instr + kInstrSize + num_prinfo_*(kInstrSize + kMaxRelocSize);
2732 while (buffer_space() <= (max_needed_space + kGap)) GrowBuffer();
2733
ager@chromium.org5c838252010-02-19 08:53:10 +00002734 // Block recursive calls to CheckConstPool.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002735 BlockConstPoolBefore(pc_offset() + jump_instr + kInstrSize +
2736 num_prinfo_*kInstrSize);
2737 // Don't bother to check for the emit calls below.
2738 next_buffer_check_ = no_const_pool_before_;
2739
ager@chromium.org5c838252010-02-19 08:53:10 +00002740 // Emit jump over constant pool if necessary.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002741 Label after_pool;
2742 if (require_jump) b(&after_pool);
2743
2744 RecordComment("[ Constant Pool");
2745
ager@chromium.org5c838252010-02-19 08:53:10 +00002746 // Put down constant pool marker "Undefined instruction" as specified by
2747 // A3.1 Instruction set encoding.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002748 emit(0x03000000 | num_prinfo_);
2749
ager@chromium.org5c838252010-02-19 08:53:10 +00002750 // Emit constant pool entries.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002751 for (int i = 0; i < num_prinfo_; i++) {
2752 RelocInfo& rinfo = prinfo_[i];
ager@chromium.org236ad962008-09-25 09:45:57 +00002753 ASSERT(rinfo.rmode() != RelocInfo::COMMENT &&
2754 rinfo.rmode() != RelocInfo::POSITION &&
2755 rinfo.rmode() != RelocInfo::STATEMENT_POSITION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002756 Instr instr = instr_at(rinfo.pc());
ager@chromium.org4af710e2009-09-15 12:20:11 +00002757
ager@chromium.org5c838252010-02-19 08:53:10 +00002758 // Instruction to patch must be a ldr/str [pc, #offset].
2759 // P and U set, B and W clear, Rn == pc, offset12 still 0.
ager@chromium.org378b34e2011-01-28 08:04:38 +00002760 ASSERT((instr & (7*B25 | P | U | B | W | 15*B16 | kOff12Mask)) ==
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002761 (2*B25 | P | U | pc.code()*B16));
2762 int delta = pc_ - rinfo.pc() - 8;
2763 ASSERT(delta >= -4); // instr could be ldr pc, [pc, #-4] followed by targ32
2764 if (delta < 0) {
2765 instr &= ~U;
2766 delta = -delta;
2767 }
2768 ASSERT(is_uint12(delta));
2769 instr_at_put(rinfo.pc(), instr + delta);
2770 emit(rinfo.data());
2771 }
2772 num_prinfo_ = 0;
2773 last_const_pool_end_ = pc_offset();
2774
2775 RecordComment("]");
2776
2777 if (after_pool.is_linked()) {
2778 bind(&after_pool);
2779 }
2780
2781 // Since a constant pool was just emitted, move the check offset forward by
2782 // the standard interval.
2783 next_buffer_check_ = pc_offset() + kCheckConstInterval;
2784}
2785
2786
2787} } // namespace v8::internal
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002788
2789#endif // V8_TARGET_ARCH_ARM