blob: 48b91a6a922d8bc5bc793ebe49bcfbacb86b10f0 [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),
274 allow_peephole_optimization_(false) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000275 allow_peephole_optimization_ = FLAG_peephole_optimization;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000276 if (buffer == NULL) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000277 // Do our own buffer management.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000278 if (buffer_size <= kMinimalBufferSize) {
279 buffer_size = kMinimalBufferSize;
280
281 if (spare_buffer_ != NULL) {
282 buffer = spare_buffer_;
283 spare_buffer_ = NULL;
284 }
285 }
286 if (buffer == NULL) {
287 buffer_ = NewArray<byte>(buffer_size);
288 } else {
289 buffer_ = static_cast<byte*>(buffer);
290 }
291 buffer_size_ = buffer_size;
292 own_buffer_ = true;
293
294 } else {
ager@chromium.org5c838252010-02-19 08:53:10 +0000295 // Use externally provided buffer instead.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000296 ASSERT(buffer_size > 0);
297 buffer_ = static_cast<byte*>(buffer);
298 buffer_size_ = buffer_size;
299 own_buffer_ = false;
300 }
301
ager@chromium.org5c838252010-02-19 08:53:10 +0000302 // Setup buffer pointers.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000303 ASSERT(buffer_ != NULL);
304 pc_ = buffer_;
305 reloc_info_writer.Reposition(buffer_ + buffer_size, pc_);
306 num_prinfo_ = 0;
307 next_buffer_check_ = 0;
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000308 const_pool_blocked_nesting_ = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000309 no_const_pool_before_ = 0;
310 last_const_pool_end_ = 0;
311 last_bound_pos_ = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000312}
313
314
315Assembler::~Assembler() {
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000316 ASSERT(const_pool_blocked_nesting_ == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000317 if (own_buffer_) {
318 if (spare_buffer_ == NULL && buffer_size_ == kMinimalBufferSize) {
319 spare_buffer_ = buffer_;
320 } else {
321 DeleteArray(buffer_);
322 }
323 }
324}
325
326
327void Assembler::GetCode(CodeDesc* desc) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000328 // Emit constant pool if necessary.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000329 CheckConstPool(true, false);
330 ASSERT(num_prinfo_ == 0);
331
ager@chromium.org5c838252010-02-19 08:53:10 +0000332 // Setup code descriptor.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000333 desc->buffer = buffer_;
334 desc->buffer_size = buffer_size_;
335 desc->instr_size = pc_offset();
336 desc->reloc_size = (buffer_ + buffer_size_) - reloc_info_writer.pos();
337}
338
339
340void Assembler::Align(int m) {
341 ASSERT(m >= 4 && IsPowerOf2(m));
342 while ((pc_offset() & (m - 1)) != 0) {
343 nop();
344 }
345}
346
347
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000348void Assembler::CodeTargetAlign() {
349 // Preferred alignment of jump targets on some ARM chips.
350 Align(8);
351}
352
353
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000354Condition Assembler::GetCondition(Instr instr) {
355 return Instruction::ConditionField(instr);
356}
357
358
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000359bool Assembler::IsBranch(Instr instr) {
360 return (instr & (B27 | B25)) == (B27 | B25);
361}
362
363
364int Assembler::GetBranchOffset(Instr instr) {
365 ASSERT(IsBranch(instr));
366 // Take the jump offset in the lower 24 bits, sign extend it and multiply it
367 // with 4 to get the offset in bytes.
ager@chromium.org378b34e2011-01-28 08:04:38 +0000368 return ((instr & kImm24Mask) << 8) >> 6;
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000369}
370
371
372bool Assembler::IsLdrRegisterImmediate(Instr instr) {
373 return (instr & (B27 | B26 | B25 | B22 | B20)) == (B26 | B20);
374}
375
376
377int Assembler::GetLdrRegisterImmediateOffset(Instr instr) {
378 ASSERT(IsLdrRegisterImmediate(instr));
379 bool positive = (instr & B23) == B23;
ager@chromium.org378b34e2011-01-28 08:04:38 +0000380 int offset = instr & kOff12Mask; // Zero extended offset.
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000381 return positive ? offset : -offset;
382}
383
384
385Instr Assembler::SetLdrRegisterImmediateOffset(Instr instr, int offset) {
386 ASSERT(IsLdrRegisterImmediate(instr));
387 bool positive = offset >= 0;
388 if (!positive) offset = -offset;
389 ASSERT(is_uint12(offset));
390 // Set bit indicating whether the offset should be added.
391 instr = (instr & ~B23) | (positive ? B23 : 0);
392 // Set the actual offset.
ager@chromium.org378b34e2011-01-28 08:04:38 +0000393 return (instr & ~kOff12Mask) | offset;
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000394}
395
396
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000397bool Assembler::IsStrRegisterImmediate(Instr instr) {
398 return (instr & (B27 | B26 | B25 | B22 | B20)) == B26;
399}
400
401
402Instr Assembler::SetStrRegisterImmediateOffset(Instr instr, int offset) {
403 ASSERT(IsStrRegisterImmediate(instr));
404 bool positive = offset >= 0;
405 if (!positive) offset = -offset;
406 ASSERT(is_uint12(offset));
407 // Set bit indicating whether the offset should be added.
408 instr = (instr & ~B23) | (positive ? B23 : 0);
409 // Set the actual offset.
ager@chromium.org378b34e2011-01-28 08:04:38 +0000410 return (instr & ~kOff12Mask) | offset;
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000411}
412
413
414bool Assembler::IsAddRegisterImmediate(Instr instr) {
415 return (instr & (B27 | B26 | B25 | B24 | B23 | B22 | B21)) == (B25 | B23);
416}
417
418
419Instr Assembler::SetAddRegisterImmediateOffset(Instr instr, int offset) {
420 ASSERT(IsAddRegisterImmediate(instr));
421 ASSERT(offset >= 0);
422 ASSERT(is_uint12(offset));
423 // Set the offset.
ager@chromium.org378b34e2011-01-28 08:04:38 +0000424 return (instr & ~kOff12Mask) | offset;
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000425}
426
427
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000428Register Assembler::GetRd(Instr instr) {
429 Register reg;
ager@chromium.org378b34e2011-01-28 08:04:38 +0000430 reg.code_ = Instruction::RdValue(instr);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000431 return reg;
432}
433
434
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000435Register Assembler::GetRn(Instr instr) {
436 Register reg;
437 reg.code_ = Instruction::RnValue(instr);
438 return reg;
439}
440
441
442Register Assembler::GetRm(Instr instr) {
443 Register reg;
444 reg.code_ = Instruction::RmValue(instr);
445 return reg;
446}
447
448
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000449bool Assembler::IsPush(Instr instr) {
450 return ((instr & ~kRdMask) == kPushRegPattern);
451}
452
453
454bool Assembler::IsPop(Instr instr) {
455 return ((instr & ~kRdMask) == kPopRegPattern);
456}
457
458
459bool Assembler::IsStrRegFpOffset(Instr instr) {
460 return ((instr & kLdrStrInstrTypeMask) == kStrRegFpOffsetPattern);
461}
462
463
464bool Assembler::IsLdrRegFpOffset(Instr instr) {
465 return ((instr & kLdrStrInstrTypeMask) == kLdrRegFpOffsetPattern);
466}
467
468
469bool Assembler::IsStrRegFpNegOffset(Instr instr) {
470 return ((instr & kLdrStrInstrTypeMask) == kStrRegFpNegOffsetPattern);
471}
472
473
474bool Assembler::IsLdrRegFpNegOffset(Instr instr) {
475 return ((instr & kLdrStrInstrTypeMask) == kLdrRegFpNegOffsetPattern);
476}
477
478
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000479bool Assembler::IsLdrPcImmediateOffset(Instr instr) {
480 // Check the instruction is indeed a
481 // ldr<cond> <Rd>, [pc +/- offset_12].
ager@chromium.org378b34e2011-01-28 08:04:38 +0000482 return (instr & (kLdrPCMask & ~kCondMask)) == 0x051f0000;
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000483}
484
485
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000486bool Assembler::IsTstImmediate(Instr instr) {
487 return (instr & (B27 | B26 | I | kOpCodeMask | S | kRdMask)) ==
488 (I | TST | S);
489}
490
491
492bool Assembler::IsCmpRegister(Instr instr) {
493 return (instr & (B27 | B26 | I | kOpCodeMask | S | kRdMask | B4)) ==
494 (CMP | S);
495}
496
497
498bool Assembler::IsCmpImmediate(Instr instr) {
499 return (instr & (B27 | B26 | I | kOpCodeMask | S | kRdMask)) ==
500 (I | CMP | S);
501}
502
503
504Register Assembler::GetCmpImmediateRegister(Instr instr) {
505 ASSERT(IsCmpImmediate(instr));
506 return GetRn(instr);
507}
508
509
510int Assembler::GetCmpImmediateRawImmediate(Instr instr) {
511 ASSERT(IsCmpImmediate(instr));
512 return instr & kOff12Mask;
513}
514
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000515// Labels refer to positions in the (to be) generated code.
516// There are bound, linked, and unused labels.
517//
518// Bound labels refer to known positions in the already
519// generated code. pos() is the position the label refers to.
520//
521// Linked labels refer to unknown positions in the code
522// to be generated; pos() is the position of the last
523// instruction using the label.
524
525
526// The link chain is terminated by a negative code position (must be aligned)
527const int kEndOfChain = -4;
528
529
530int Assembler::target_at(int pos) {
531 Instr instr = instr_at(pos);
ager@chromium.org378b34e2011-01-28 08:04:38 +0000532 if ((instr & ~kImm24Mask) == 0) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000533 // Emitted label constant, not part of a branch.
534 return instr - (Code::kHeaderSize - kHeapObjectTag);
535 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000536 ASSERT((instr & 7*B25) == 5*B25); // b, bl, or blx imm24
ager@chromium.org378b34e2011-01-28 08:04:38 +0000537 int imm26 = ((instr & kImm24Mask) << 8) >> 6;
538 if ((Instruction::ConditionField(instr) == kSpecialCondition) &&
539 ((instr & B24) != 0)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000540 // blx uses bit 24 to encode bit 2 of imm26
541 imm26 += 2;
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000542 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000543 return pos + kPcLoadDelta + imm26;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000544}
545
546
547void Assembler::target_at_put(int pos, int target_pos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000548 Instr instr = instr_at(pos);
ager@chromium.org378b34e2011-01-28 08:04:38 +0000549 if ((instr & ~kImm24Mask) == 0) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000550 ASSERT(target_pos == kEndOfChain || target_pos >= 0);
551 // Emitted label constant, not part of a branch.
552 // Make label relative to Code* of generated Code object.
553 instr_at_put(pos, target_pos + (Code::kHeaderSize - kHeapObjectTag));
554 return;
555 }
556 int imm26 = target_pos - (pos + kPcLoadDelta);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000557 ASSERT((instr & 7*B25) == 5*B25); // b, bl, or blx imm24
ager@chromium.org378b34e2011-01-28 08:04:38 +0000558 if (Instruction::ConditionField(instr) == kSpecialCondition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000559 // blx uses bit 24 to encode bit 2 of imm26
560 ASSERT((imm26 & 1) == 0);
ager@chromium.org378b34e2011-01-28 08:04:38 +0000561 instr = (instr & ~(B24 | kImm24Mask)) | ((imm26 & 2) >> 1)*B24;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000562 } else {
563 ASSERT((imm26 & 3) == 0);
ager@chromium.org378b34e2011-01-28 08:04:38 +0000564 instr &= ~kImm24Mask;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000565 }
566 int imm24 = imm26 >> 2;
567 ASSERT(is_int24(imm24));
ager@chromium.org378b34e2011-01-28 08:04:38 +0000568 instr_at_put(pos, instr | (imm24 & kImm24Mask));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000569}
570
571
572void Assembler::print(Label* L) {
573 if (L->is_unused()) {
574 PrintF("unused label\n");
575 } else if (L->is_bound()) {
576 PrintF("bound label to %d\n", L->pos());
577 } else if (L->is_linked()) {
578 Label l = *L;
579 PrintF("unbound label");
580 while (l.is_linked()) {
581 PrintF("@ %d ", l.pos());
582 Instr instr = instr_at(l.pos());
ager@chromium.org378b34e2011-01-28 08:04:38 +0000583 if ((instr & ~kImm24Mask) == 0) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000584 PrintF("value\n");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000585 } else {
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000586 ASSERT((instr & 7*B25) == 5*B25); // b, bl, or blx
ager@chromium.org378b34e2011-01-28 08:04:38 +0000587 Condition cond = Instruction::ConditionField(instr);
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000588 const char* b;
589 const char* c;
ager@chromium.org378b34e2011-01-28 08:04:38 +0000590 if (cond == kSpecialCondition) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000591 b = "blx";
592 c = "";
593 } else {
594 if ((instr & B24) != 0)
595 b = "bl";
596 else
597 b = "b";
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000598
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000599 switch (cond) {
600 case eq: c = "eq"; break;
601 case ne: c = "ne"; break;
602 case hs: c = "hs"; break;
603 case lo: c = "lo"; break;
604 case mi: c = "mi"; break;
605 case pl: c = "pl"; break;
606 case vs: c = "vs"; break;
607 case vc: c = "vc"; break;
608 case hi: c = "hi"; break;
609 case ls: c = "ls"; break;
610 case ge: c = "ge"; break;
611 case lt: c = "lt"; break;
612 case gt: c = "gt"; break;
613 case le: c = "le"; break;
614 case al: c = ""; break;
615 default:
616 c = "";
617 UNREACHABLE();
618 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000619 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000620 PrintF("%s%s\n", b, c);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000621 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000622 next(&l);
623 }
624 } else {
625 PrintF("label in inconsistent state (pos = %d)\n", L->pos_);
626 }
627}
628
629
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000630void Assembler::bind_to(Label* L, int pos) {
631 ASSERT(0 <= pos && pos <= pc_offset()); // must have a valid binding position
632 while (L->is_linked()) {
633 int fixup_pos = L->pos();
634 next(L); // call next before overwriting link with target at fixup_pos
635 target_at_put(fixup_pos, pos);
636 }
637 L->bind_to(pos);
638
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000639 // Keep track of the last bound label so we don't eliminate any instructions
640 // before a bound label.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000641 if (pos > last_bound_pos_)
642 last_bound_pos_ = pos;
643}
644
645
646void Assembler::link_to(Label* L, Label* appendix) {
647 if (appendix->is_linked()) {
648 if (L->is_linked()) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000649 // Append appendix to L's list.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000650 int fixup_pos;
651 int link = L->pos();
652 do {
653 fixup_pos = link;
654 link = target_at(fixup_pos);
655 } while (link > 0);
656 ASSERT(link == kEndOfChain);
657 target_at_put(fixup_pos, appendix->pos());
658 } else {
ager@chromium.org5c838252010-02-19 08:53:10 +0000659 // L is empty, simply use appendix.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000660 *L = *appendix;
661 }
662 }
663 appendix->Unuse(); // appendix should not be used anymore
664}
665
666
667void Assembler::bind(Label* L) {
668 ASSERT(!L->is_bound()); // label can only be bound once
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000669 bind_to(L, pc_offset());
670}
671
672
673void Assembler::next(Label* L) {
674 ASSERT(L->is_linked());
675 int link = target_at(L->pos());
676 if (link > 0) {
677 L->link_to(link);
678 } else {
679 ASSERT(link == kEndOfChain);
680 L->Unuse();
681 }
682}
683
684
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000685static Instr EncodeMovwImmediate(uint32_t immediate) {
686 ASSERT(immediate < 0x10000);
687 return ((immediate & 0xf000) << 4) | (immediate & 0xfff);
688}
689
690
ager@chromium.org5c838252010-02-19 08:53:10 +0000691// Low-level code emission routines depending on the addressing mode.
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000692// If this returns true then you have to use the rotate_imm and immed_8
693// that it returns, because it may have already changed the instruction
694// to match them!
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000695static bool fits_shifter(uint32_t imm32,
696 uint32_t* rotate_imm,
697 uint32_t* immed_8,
698 Instr* instr) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000699 // imm32 must be unsigned.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000700 for (int rot = 0; rot < 16; rot++) {
701 uint32_t imm8 = (imm32 << 2*rot) | (imm32 >> (32 - 2*rot));
702 if ((imm8 <= 0xff)) {
703 *rotate_imm = rot;
704 *immed_8 = imm8;
705 return true;
706 }
707 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000708 // If the opcode is one with a complementary version and the complementary
709 // immediate fits, change the opcode.
710 if (instr != NULL) {
711 if ((*instr & kMovMvnMask) == kMovMvnPattern) {
712 if (fits_shifter(~imm32, rotate_imm, immed_8, NULL)) {
713 *instr ^= kMovMvnFlip;
714 return true;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000715 } else if ((*instr & kMovLeaveCCMask) == kMovLeaveCCPattern) {
716 if (CpuFeatures::IsSupported(ARMv7)) {
717 if (imm32 < 0x10000) {
718 *instr ^= kMovwLeaveCCFlip;
719 *instr |= EncodeMovwImmediate(imm32);
720 *rotate_imm = *immed_8 = 0; // Not used for movw.
721 return true;
722 }
723 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000724 }
725 } else if ((*instr & kCmpCmnMask) == kCmpCmnPattern) {
726 if (fits_shifter(-imm32, rotate_imm, immed_8, NULL)) {
727 *instr ^= kCmpCmnFlip;
728 return true;
729 }
730 } else {
731 Instr alu_insn = (*instr & kALUMask);
ager@chromium.org378b34e2011-01-28 08:04:38 +0000732 if (alu_insn == ADD ||
733 alu_insn == SUB) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000734 if (fits_shifter(-imm32, rotate_imm, immed_8, NULL)) {
735 *instr ^= kAddSubFlip;
736 return true;
737 }
ager@chromium.org378b34e2011-01-28 08:04:38 +0000738 } else if (alu_insn == AND ||
739 alu_insn == BIC) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000740 if (fits_shifter(~imm32, rotate_imm, immed_8, NULL)) {
741 *instr ^= kAndBicFlip;
742 return true;
743 }
744 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000745 }
746 }
747 return false;
748}
749
750
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000751// We have to use the temporary register for things that can be relocated even
752// if they can be encoded in the ARM's 12 bits of immediate-offset instruction
753// space. There is no guarantee that the relocated location can be similarly
754// encoded.
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000755bool Operand::must_use_constant_pool() const {
756 if (rmode_ == RelocInfo::EXTERNAL_REFERENCE) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000757#ifdef DEBUG
758 if (!Serializer::enabled()) {
759 Serializer::TooLateToEnableNow();
760 }
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000761#endif // def DEBUG
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000762 return Serializer::enabled();
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000763 } else if (rmode_ == RelocInfo::NONE) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000764 return false;
765 }
766 return true;
767}
768
769
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000770bool Operand::is_single_instruction(Instr instr) const {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000771 if (rm_.is_valid()) return true;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000772 uint32_t dummy1, dummy2;
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000773 if (must_use_constant_pool() ||
774 !fits_shifter(imm32_, &dummy1, &dummy2, &instr)) {
775 // The immediate operand cannot be encoded as a shifter operand, or use of
776 // constant pool is required. For a mov instruction not setting the
777 // condition code additional instruction conventions can be used.
778 if ((instr & ~kCondMask) == 13*B21) { // mov, S not set
779 if (must_use_constant_pool() || !CpuFeatures::IsSupported(ARMv7)) {
780 // mov instruction will be an ldr from constant pool (one instruction).
781 return true;
782 } else {
783 // mov instruction will be a mov or movw followed by movt (two
784 // instructions).
785 return false;
786 }
787 } else {
788 // If this is not a mov or mvn instruction there will always an additional
789 // instructions - either mov or ldr. The mov might actually be two
790 // instructions mov or movw followed by movt so including the actual
791 // instruction two or three instructions will be generated.
792 return false;
793 }
794 } else {
795 // No use of constant pool and the immediate operand can be encoded as a
796 // shifter operand.
797 return true;
798 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000799}
800
801
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000802void Assembler::addrmod1(Instr instr,
803 Register rn,
804 Register rd,
805 const Operand& x) {
806 CheckBuffer();
ager@chromium.org378b34e2011-01-28 08:04:38 +0000807 ASSERT((instr & ~(kCondMask | kOpCodeMask | S)) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000808 if (!x.rm_.is_valid()) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000809 // Immediate.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000810 uint32_t rotate_imm;
811 uint32_t immed_8;
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000812 if (x.must_use_constant_pool() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000813 !fits_shifter(x.imm32_, &rotate_imm, &immed_8, &instr)) {
814 // The immediate operand cannot be encoded as a shifter operand, so load
815 // it first to register ip and change the original instruction to use ip.
816 // However, if the original instruction is a 'mov rd, x' (not setting the
ager@chromium.org5c838252010-02-19 08:53:10 +0000817 // condition code), then replace it with a 'ldr rd, [pc]'.
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000818 CHECK(!rn.is(ip)); // rn should never be ip, or will be trashed
ager@chromium.org378b34e2011-01-28 08:04:38 +0000819 Condition cond = Instruction::ConditionField(instr);
820 if ((instr & ~kCondMask) == 13*B21) { // mov, S not set
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000821 if (x.must_use_constant_pool() || !CpuFeatures::IsSupported(ARMv7)) {
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000822 RecordRelocInfo(x.rmode_, x.imm32_);
823 ldr(rd, MemOperand(pc, 0), cond);
824 } else {
825 // Will probably use movw, will certainly not use constant pool.
826 mov(rd, Operand(x.imm32_ & 0xffff), LeaveCC, cond);
827 movt(rd, static_cast<uint32_t>(x.imm32_) >> 16, cond);
828 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000829 } else {
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000830 // If this is not a mov or mvn instruction we may still be able to avoid
831 // a constant pool entry by using mvn or movw.
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000832 if (!x.must_use_constant_pool() &&
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000833 (instr & kMovMvnMask) != kMovMvnPattern) {
834 mov(ip, x, LeaveCC, cond);
835 } else {
836 RecordRelocInfo(x.rmode_, x.imm32_);
837 ldr(ip, MemOperand(pc, 0), cond);
838 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000839 addrmod1(instr, rn, rd, Operand(ip));
840 }
841 return;
842 }
843 instr |= I | rotate_imm*B8 | immed_8;
844 } else if (!x.rs_.is_valid()) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000845 // Immediate shift.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000846 instr |= x.shift_imm_*B7 | x.shift_op_ | x.rm_.code();
847 } else {
ager@chromium.org5c838252010-02-19 08:53:10 +0000848 // Register shift.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000849 ASSERT(!rn.is(pc) && !rd.is(pc) && !x.rm_.is(pc) && !x.rs_.is(pc));
850 instr |= x.rs_.code()*B8 | x.shift_op_ | B4 | x.rm_.code();
851 }
852 emit(instr | rn.code()*B16 | rd.code()*B12);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000853 if (rn.is(pc) || x.rm_.is(pc)) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000854 // Block constant pool emission for one instruction after reading pc.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000855 BlockConstPoolBefore(pc_offset() + kInstrSize);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000856 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000857}
858
859
860void Assembler::addrmod2(Instr instr, Register rd, const MemOperand& x) {
ager@chromium.org378b34e2011-01-28 08:04:38 +0000861 ASSERT((instr & ~(kCondMask | B | L)) == B26);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000862 int am = x.am_;
863 if (!x.rm_.is_valid()) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000864 // Immediate offset.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000865 int offset_12 = x.offset_;
866 if (offset_12 < 0) {
867 offset_12 = -offset_12;
868 am ^= U;
869 }
870 if (!is_uint12(offset_12)) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000871 // Immediate offset cannot be encoded, load it first to register ip
872 // rn (and rd in a load) should never be ip, or will be trashed.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000873 ASSERT(!x.rn_.is(ip) && ((instr & L) == L || !rd.is(ip)));
ager@chromium.org378b34e2011-01-28 08:04:38 +0000874 mov(ip, Operand(x.offset_), LeaveCC, Instruction::ConditionField(instr));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000875 addrmod2(instr, rd, MemOperand(x.rn_, ip, x.am_));
876 return;
877 }
878 ASSERT(offset_12 >= 0); // no masking needed
879 instr |= offset_12;
880 } else {
ager@chromium.org5c838252010-02-19 08:53:10 +0000881 // Register offset (shift_imm_ and shift_op_ are 0) or scaled
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000882 // register offset the constructors make sure than both shift_imm_
ager@chromium.org5c838252010-02-19 08:53:10 +0000883 // and shift_op_ are initialized.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000884 ASSERT(!x.rm_.is(pc));
885 instr |= B25 | x.shift_imm_*B7 | x.shift_op_ | x.rm_.code();
886 }
887 ASSERT((am & (P|W)) == P || !x.rn_.is(pc)); // no pc base with writeback
888 emit(instr | am | x.rn_.code()*B16 | rd.code()*B12);
889}
890
891
892void Assembler::addrmod3(Instr instr, Register rd, const MemOperand& x) {
ager@chromium.org378b34e2011-01-28 08:04:38 +0000893 ASSERT((instr & ~(kCondMask | L | S6 | H)) == (B4 | B7));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000894 ASSERT(x.rn_.is_valid());
895 int am = x.am_;
896 if (!x.rm_.is_valid()) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000897 // Immediate offset.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000898 int offset_8 = x.offset_;
899 if (offset_8 < 0) {
900 offset_8 = -offset_8;
901 am ^= U;
902 }
903 if (!is_uint8(offset_8)) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000904 // Immediate offset cannot be encoded, load it first to register ip
905 // rn (and rd in a load) should never be ip, or will be trashed.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000906 ASSERT(!x.rn_.is(ip) && ((instr & L) == L || !rd.is(ip)));
ager@chromium.org378b34e2011-01-28 08:04:38 +0000907 mov(ip, Operand(x.offset_), LeaveCC, Instruction::ConditionField(instr));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000908 addrmod3(instr, rd, MemOperand(x.rn_, ip, x.am_));
909 return;
910 }
911 ASSERT(offset_8 >= 0); // no masking needed
912 instr |= B | (offset_8 >> 4)*B8 | (offset_8 & 0xf);
913 } else if (x.shift_imm_ != 0) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000914 // Scaled register offset not supported, load index first
915 // rn (and rd in a load) should never be ip, or will be trashed.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000916 ASSERT(!x.rn_.is(ip) && ((instr & L) == L || !rd.is(ip)));
917 mov(ip, Operand(x.rm_, x.shift_op_, x.shift_imm_), LeaveCC,
ager@chromium.org378b34e2011-01-28 08:04:38 +0000918 Instruction::ConditionField(instr));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000919 addrmod3(instr, rd, MemOperand(x.rn_, ip, x.am_));
920 return;
921 } else {
ager@chromium.org5c838252010-02-19 08:53:10 +0000922 // Register offset.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000923 ASSERT((am & (P|W)) == P || !x.rm_.is(pc)); // no pc index with writeback
924 instr |= x.rm_.code();
925 }
926 ASSERT((am & (P|W)) == P || !x.rn_.is(pc)); // no pc base with writeback
927 emit(instr | am | x.rn_.code()*B16 | rd.code()*B12);
928}
929
930
931void Assembler::addrmod4(Instr instr, Register rn, RegList rl) {
ager@chromium.org378b34e2011-01-28 08:04:38 +0000932 ASSERT((instr & ~(kCondMask | P | U | W | L)) == B27);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000933 ASSERT(rl != 0);
934 ASSERT(!rn.is(pc));
935 emit(instr | rn.code()*B16 | rl);
936}
937
938
939void Assembler::addrmod5(Instr instr, CRegister crd, const MemOperand& x) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000940 // Unindexed addressing is not encoded by this function.
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000941 ASSERT_EQ((B27 | B26),
ager@chromium.org378b34e2011-01-28 08:04:38 +0000942 (instr & ~(kCondMask | kCoprocessorMask | P | U | N | W | L)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000943 ASSERT(x.rn_.is_valid() && !x.rm_.is_valid());
944 int am = x.am_;
945 int offset_8 = x.offset_;
946 ASSERT((offset_8 & 3) == 0); // offset must be an aligned word offset
947 offset_8 >>= 2;
948 if (offset_8 < 0) {
949 offset_8 = -offset_8;
950 am ^= U;
951 }
952 ASSERT(is_uint8(offset_8)); // unsigned word offset must fit in a byte
953 ASSERT((am & (P|W)) == P || !x.rn_.is(pc)); // no pc base with writeback
954
ager@chromium.org5c838252010-02-19 08:53:10 +0000955 // Post-indexed addressing requires W == 1; different than in addrmod2/3.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000956 if ((am & P) == 0)
957 am |= W;
958
959 ASSERT(offset_8 >= 0); // no masking needed
960 emit(instr | am | x.rn_.code()*B16 | crd.code()*B12 | offset_8);
961}
962
963
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +0000964int Assembler::branch_offset(Label* L, bool jump_elimination_allowed) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000965 int target_pos;
966 if (L->is_bound()) {
967 target_pos = L->pos();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000968 } else {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000969 if (L->is_linked()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000970 target_pos = L->pos(); // L's link
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000971 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000972 target_pos = kEndOfChain;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000973 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000974 L->link_to(pc_offset());
975 }
976
977 // Block the emission of the constant pool, since the branch instruction must
ager@chromium.org5c838252010-02-19 08:53:10 +0000978 // be emitted at the pc offset recorded by the label.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000979 BlockConstPoolBefore(pc_offset() + kInstrSize);
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000980 return target_pos - (pc_offset() + kPcLoadDelta);
981}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000982
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000983
984void Assembler::label_at_put(Label* L, int at_offset) {
985 int target_pos;
986 if (L->is_bound()) {
987 target_pos = L->pos();
988 } else {
989 if (L->is_linked()) {
990 target_pos = L->pos(); // L's link
991 } else {
992 target_pos = kEndOfChain;
993 }
994 L->link_to(at_offset);
995 instr_at_put(at_offset, target_pos + (Code::kHeaderSize - kHeapObjectTag));
996 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000997}
998
999
ager@chromium.org5c838252010-02-19 08:53:10 +00001000// Branch instructions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001001void Assembler::b(int branch_offset, Condition cond) {
1002 ASSERT((branch_offset & 3) == 0);
1003 int imm24 = branch_offset >> 2;
1004 ASSERT(is_int24(imm24));
ager@chromium.org378b34e2011-01-28 08:04:38 +00001005 emit(cond | B27 | B25 | (imm24 & kImm24Mask));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001006
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001007 if (cond == al) {
ager@chromium.org5c838252010-02-19 08:53:10 +00001008 // Dead code is a good location to emit the constant pool.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001009 CheckConstPool(false, false);
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001010 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001011}
1012
1013
1014void Assembler::bl(int branch_offset, Condition cond) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001015 positions_recorder()->WriteRecordedPositions();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001016 ASSERT((branch_offset & 3) == 0);
1017 int imm24 = branch_offset >> 2;
1018 ASSERT(is_int24(imm24));
ager@chromium.org378b34e2011-01-28 08:04:38 +00001019 emit(cond | B27 | B25 | B24 | (imm24 & kImm24Mask));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001020}
1021
1022
1023void Assembler::blx(int branch_offset) { // v5 and above
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00001024 positions_recorder()->WriteRecordedPositions();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001025 ASSERT((branch_offset & 1) == 0);
1026 int h = ((branch_offset & 2) >> 1)*B24;
1027 int imm24 = branch_offset >> 2;
1028 ASSERT(is_int24(imm24));
ager@chromium.org378b34e2011-01-28 08:04:38 +00001029 emit(kSpecialCondition | B27 | B25 | h | (imm24 & kImm24Mask));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001030}
1031
1032
1033void Assembler::blx(Register target, Condition cond) { // v5 and above
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00001034 positions_recorder()->WriteRecordedPositions();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001035 ASSERT(!target.is(pc));
ager@chromium.org378b34e2011-01-28 08:04:38 +00001036 emit(cond | B24 | B21 | 15*B16 | 15*B12 | 15*B8 | BLX | target.code());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001037}
1038
1039
1040void Assembler::bx(Register target, Condition cond) { // v5 and above, plus v4t
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00001041 positions_recorder()->WriteRecordedPositions();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001042 ASSERT(!target.is(pc)); // use of pc is actually allowed, but discouraged
ager@chromium.org378b34e2011-01-28 08:04:38 +00001043 emit(cond | B24 | B21 | 15*B16 | 15*B12 | 15*B8 | BX | target.code());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001044}
1045
1046
ager@chromium.org5c838252010-02-19 08:53:10 +00001047// Data-processing instructions.
1048
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001049void Assembler::and_(Register dst, Register src1, const Operand& src2,
1050 SBit s, Condition cond) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00001051 addrmod1(cond | AND | s, src1, dst, src2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001052}
1053
1054
1055void Assembler::eor(Register dst, Register src1, const Operand& src2,
1056 SBit s, Condition cond) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00001057 addrmod1(cond | EOR | s, src1, dst, src2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001058}
1059
1060
1061void Assembler::sub(Register dst, Register src1, const Operand& src2,
1062 SBit s, Condition cond) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00001063 addrmod1(cond | SUB | s, src1, dst, src2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001064}
1065
1066
1067void Assembler::rsb(Register dst, Register src1, const Operand& src2,
1068 SBit s, Condition cond) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00001069 addrmod1(cond | RSB | s, src1, dst, src2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001070}
1071
1072
1073void Assembler::add(Register dst, Register src1, const Operand& src2,
1074 SBit s, Condition cond) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00001075 addrmod1(cond | ADD | s, src1, dst, src2);
mads.s.ager31e71382008-08-13 09:32:07 +00001076
1077 // Eliminate pattern: push(r), pop()
1078 // str(src, MemOperand(sp, 4, NegPreIndex), al);
1079 // add(sp, sp, Operand(kPointerSize));
1080 // Both instructions can be eliminated.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001081 if (can_peephole_optimize(2) &&
ager@chromium.org5c838252010-02-19 08:53:10 +00001082 // Pattern.
mads.s.ager31e71382008-08-13 09:32:07 +00001083 instr_at(pc_ - 1 * kInstrSize) == kPopInstruction &&
ager@chromium.org378b34e2011-01-28 08:04:38 +00001084 (instr_at(pc_ - 2 * kInstrSize) & ~kRdMask) == kPushRegPattern) {
mads.s.ager31e71382008-08-13 09:32:07 +00001085 pc_ -= 2 * kInstrSize;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001086 if (FLAG_print_peephole_optimization) {
mads.s.ager31e71382008-08-13 09:32:07 +00001087 PrintF("%x push(reg)/pop() eliminated\n", pc_offset());
1088 }
1089 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001090}
1091
1092
1093void Assembler::adc(Register dst, Register src1, const Operand& src2,
1094 SBit s, Condition cond) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00001095 addrmod1(cond | ADC | s, src1, dst, src2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001096}
1097
1098
1099void Assembler::sbc(Register dst, Register src1, const Operand& src2,
1100 SBit s, Condition cond) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00001101 addrmod1(cond | SBC | s, src1, dst, src2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001102}
1103
1104
1105void Assembler::rsc(Register dst, Register src1, const Operand& src2,
1106 SBit s, Condition cond) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00001107 addrmod1(cond | RSC | s, src1, dst, src2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001108}
1109
1110
1111void Assembler::tst(Register src1, const Operand& src2, Condition cond) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00001112 addrmod1(cond | TST | S, src1, r0, src2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001113}
1114
1115
1116void Assembler::teq(Register src1, const Operand& src2, Condition cond) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00001117 addrmod1(cond | TEQ | S, src1, r0, src2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001118}
1119
1120
1121void Assembler::cmp(Register src1, const Operand& src2, Condition cond) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00001122 addrmod1(cond | CMP | S, src1, r0, src2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001123}
1124
1125
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001126void Assembler::cmp_raw_immediate(
1127 Register src, int raw_immediate, Condition cond) {
1128 ASSERT(is_uint12(raw_immediate));
1129 emit(cond | I | CMP | S | src.code() << 16 | raw_immediate);
1130}
1131
1132
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001133void Assembler::cmn(Register src1, const Operand& src2, Condition cond) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00001134 addrmod1(cond | CMN | S, src1, r0, src2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001135}
1136
1137
1138void Assembler::orr(Register dst, Register src1, const Operand& src2,
1139 SBit s, Condition cond) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00001140 addrmod1(cond | ORR | s, src1, dst, src2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001141}
1142
1143
1144void Assembler::mov(Register dst, const Operand& src, SBit s, Condition cond) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001145 if (dst.is(pc)) {
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00001146 positions_recorder()->WriteRecordedPositions();
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001147 }
fschneider@chromium.org013f3e12010-04-26 13:27:52 +00001148 // Don't allow nop instructions in the form mov rn, rn to be generated using
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001149 // the mov instruction. They must be generated using nop(int/NopMarkerTypes)
1150 // or MarkCode(int/NopMarkerTypes) pseudo instructions.
fschneider@chromium.org013f3e12010-04-26 13:27:52 +00001151 ASSERT(!(src.is_reg() && src.rm().is(dst) && s == LeaveCC && cond == al));
ager@chromium.org378b34e2011-01-28 08:04:38 +00001152 addrmod1(cond | MOV | s, r0, dst, src);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001153}
1154
1155
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001156void Assembler::movw(Register reg, uint32_t immediate, Condition cond) {
1157 ASSERT(immediate < 0x10000);
1158 mov(reg, Operand(immediate), LeaveCC, cond);
1159}
1160
1161
1162void Assembler::movt(Register reg, uint32_t immediate, Condition cond) {
1163 emit(cond | 0x34*B20 | reg.code()*B12 | EncodeMovwImmediate(immediate));
1164}
1165
1166
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001167void Assembler::bic(Register dst, Register src1, const Operand& src2,
1168 SBit s, Condition cond) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00001169 addrmod1(cond | BIC | s, src1, dst, src2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001170}
1171
1172
1173void Assembler::mvn(Register dst, const Operand& src, SBit s, Condition cond) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00001174 addrmod1(cond | MVN | s, r0, dst, src);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001175}
1176
1177
ager@chromium.org5c838252010-02-19 08:53:10 +00001178// Multiply instructions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001179void Assembler::mla(Register dst, Register src1, Register src2, Register srcA,
1180 SBit s, Condition cond) {
1181 ASSERT(!dst.is(pc) && !src1.is(pc) && !src2.is(pc) && !srcA.is(pc));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001182 emit(cond | A | s | dst.code()*B16 | srcA.code()*B12 |
1183 src2.code()*B8 | B7 | B4 | src1.code());
1184}
1185
1186
1187void Assembler::mul(Register dst, Register src1, Register src2,
1188 SBit s, Condition cond) {
1189 ASSERT(!dst.is(pc) && !src1.is(pc) && !src2.is(pc));
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00001190 // dst goes in bits 16-19 for this instruction!
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001191 emit(cond | s | dst.code()*B16 | src2.code()*B8 | B7 | B4 | src1.code());
1192}
1193
1194
1195void Assembler::smlal(Register dstL,
1196 Register dstH,
1197 Register src1,
1198 Register src2,
1199 SBit s,
1200 Condition cond) {
1201 ASSERT(!dstL.is(pc) && !dstH.is(pc) && !src1.is(pc) && !src2.is(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001202 ASSERT(!dstL.is(dstH));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001203 emit(cond | B23 | B22 | A | s | dstH.code()*B16 | dstL.code()*B12 |
1204 src2.code()*B8 | B7 | B4 | src1.code());
1205}
1206
1207
1208void Assembler::smull(Register dstL,
1209 Register dstH,
1210 Register src1,
1211 Register src2,
1212 SBit s,
1213 Condition cond) {
1214 ASSERT(!dstL.is(pc) && !dstH.is(pc) && !src1.is(pc) && !src2.is(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001215 ASSERT(!dstL.is(dstH));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001216 emit(cond | B23 | B22 | s | dstH.code()*B16 | dstL.code()*B12 |
1217 src2.code()*B8 | B7 | B4 | src1.code());
1218}
1219
1220
1221void Assembler::umlal(Register dstL,
1222 Register dstH,
1223 Register src1,
1224 Register src2,
1225 SBit s,
1226 Condition cond) {
1227 ASSERT(!dstL.is(pc) && !dstH.is(pc) && !src1.is(pc) && !src2.is(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001228 ASSERT(!dstL.is(dstH));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001229 emit(cond | B23 | A | s | dstH.code()*B16 | dstL.code()*B12 |
1230 src2.code()*B8 | B7 | B4 | src1.code());
1231}
1232
1233
1234void Assembler::umull(Register dstL,
1235 Register dstH,
1236 Register src1,
1237 Register src2,
1238 SBit s,
1239 Condition cond) {
1240 ASSERT(!dstL.is(pc) && !dstH.is(pc) && !src1.is(pc) && !src2.is(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001241 ASSERT(!dstL.is(dstH));
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00001242 emit(cond | B23 | s | dstH.code()*B16 | dstL.code()*B12 |
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001243 src2.code()*B8 | B7 | B4 | src1.code());
1244}
1245
1246
ager@chromium.org5c838252010-02-19 08:53:10 +00001247// Miscellaneous arithmetic instructions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001248void Assembler::clz(Register dst, Register src, Condition cond) {
1249 // v5 and above.
1250 ASSERT(!dst.is(pc) && !src.is(pc));
1251 emit(cond | B24 | B22 | B21 | 15*B16 | dst.code()*B12 |
ager@chromium.org378b34e2011-01-28 08:04:38 +00001252 15*B8 | CLZ | src.code());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001253}
1254
1255
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +00001256// Saturating instructions.
1257
1258// Unsigned saturate.
1259void Assembler::usat(Register dst,
1260 int satpos,
1261 const Operand& src,
1262 Condition cond) {
1263 // v6 and above.
1264 ASSERT(CpuFeatures::IsSupported(ARMv7));
1265 ASSERT(!dst.is(pc) && !src.rm_.is(pc));
1266 ASSERT((satpos >= 0) && (satpos <= 31));
1267 ASSERT((src.shift_op_ == ASR) || (src.shift_op_ == LSL));
1268 ASSERT(src.rs_.is(no_reg));
1269
1270 int sh = 0;
1271 if (src.shift_op_ == ASR) {
1272 sh = 1;
1273 }
1274
1275 emit(cond | 0x6*B24 | 0xe*B20 | satpos*B16 | dst.code()*B12 |
1276 src.shift_imm_*B7 | sh*B6 | 0x1*B4 | src.rm_.code());
1277}
1278
1279
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001280// Bitfield manipulation instructions.
1281
1282// Unsigned bit field extract.
1283// Extracts #width adjacent bits from position #lsb in a register, and
1284// writes them to the low bits of a destination register.
1285// ubfx dst, src, #lsb, #width
1286void Assembler::ubfx(Register dst,
1287 Register src,
1288 int lsb,
1289 int width,
1290 Condition cond) {
1291 // v7 and above.
1292 ASSERT(CpuFeatures::IsSupported(ARMv7));
1293 ASSERT(!dst.is(pc) && !src.is(pc));
1294 ASSERT((lsb >= 0) && (lsb <= 31));
1295 ASSERT((width >= 1) && (width <= (32 - lsb)));
1296 emit(cond | 0xf*B23 | B22 | B21 | (width - 1)*B16 | dst.code()*B12 |
1297 lsb*B7 | B6 | B4 | src.code());
1298}
1299
1300
1301// Signed bit field extract.
1302// Extracts #width adjacent bits from position #lsb in a register, and
1303// writes them to the low bits of a destination register. The extracted
1304// value is sign extended to fill the destination register.
1305// sbfx dst, src, #lsb, #width
1306void Assembler::sbfx(Register dst,
1307 Register src,
1308 int lsb,
1309 int width,
1310 Condition cond) {
1311 // v7 and above.
1312 ASSERT(CpuFeatures::IsSupported(ARMv7));
1313 ASSERT(!dst.is(pc) && !src.is(pc));
1314 ASSERT((lsb >= 0) && (lsb <= 31));
1315 ASSERT((width >= 1) && (width <= (32 - lsb)));
1316 emit(cond | 0xf*B23 | B21 | (width - 1)*B16 | dst.code()*B12 |
1317 lsb*B7 | B6 | B4 | src.code());
1318}
1319
1320
1321// Bit field clear.
1322// Sets #width adjacent bits at position #lsb in the destination register
1323// to zero, preserving the value of the other bits.
1324// bfc dst, #lsb, #width
1325void Assembler::bfc(Register dst, int lsb, int width, Condition cond) {
1326 // v7 and above.
1327 ASSERT(CpuFeatures::IsSupported(ARMv7));
1328 ASSERT(!dst.is(pc));
1329 ASSERT((lsb >= 0) && (lsb <= 31));
1330 ASSERT((width >= 1) && (width <= (32 - lsb)));
1331 int msb = lsb + width - 1;
1332 emit(cond | 0x1f*B22 | msb*B16 | dst.code()*B12 | lsb*B7 | B4 | 0xf);
1333}
1334
1335
1336// Bit field insert.
1337// Inserts #width adjacent bits from the low bits of the source register
1338// into position #lsb of the destination register.
1339// bfi dst, src, #lsb, #width
1340void Assembler::bfi(Register dst,
1341 Register src,
1342 int lsb,
1343 int width,
1344 Condition cond) {
1345 // v7 and above.
1346 ASSERT(CpuFeatures::IsSupported(ARMv7));
1347 ASSERT(!dst.is(pc) && !src.is(pc));
1348 ASSERT((lsb >= 0) && (lsb <= 31));
1349 ASSERT((width >= 1) && (width <= (32 - lsb)));
1350 int msb = lsb + width - 1;
1351 emit(cond | 0x1f*B22 | msb*B16 | dst.code()*B12 | lsb*B7 | B4 |
1352 src.code());
1353}
1354
1355
ager@chromium.org5c838252010-02-19 08:53:10 +00001356// Status register access instructions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001357void Assembler::mrs(Register dst, SRegister s, Condition cond) {
1358 ASSERT(!dst.is(pc));
1359 emit(cond | B24 | s | 15*B16 | dst.code()*B12);
1360}
1361
1362
1363void Assembler::msr(SRegisterFieldMask fields, const Operand& src,
1364 Condition cond) {
1365 ASSERT(fields >= B16 && fields < B20); // at least one field set
1366 Instr instr;
1367 if (!src.rm_.is_valid()) {
ager@chromium.org5c838252010-02-19 08:53:10 +00001368 // Immediate.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001369 uint32_t rotate_imm;
1370 uint32_t immed_8;
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00001371 if (src.must_use_constant_pool() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001372 !fits_shifter(src.imm32_, &rotate_imm, &immed_8, NULL)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00001373 // Immediate operand cannot be encoded, load it first to register ip.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001374 RecordRelocInfo(src.rmode_, src.imm32_);
1375 ldr(ip, MemOperand(pc, 0), cond);
1376 msr(fields, Operand(ip), cond);
1377 return;
1378 }
1379 instr = I | rotate_imm*B8 | immed_8;
1380 } else {
1381 ASSERT(!src.rs_.is_valid() && src.shift_imm_ == 0); // only rm allowed
1382 instr = src.rm_.code();
1383 }
1384 emit(cond | instr | B24 | B21 | fields | 15*B12);
1385}
1386
1387
ager@chromium.org5c838252010-02-19 08:53:10 +00001388// Load/Store instructions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001389void Assembler::ldr(Register dst, const MemOperand& src, Condition cond) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001390 if (dst.is(pc)) {
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00001391 positions_recorder()->WriteRecordedPositions();
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001392 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001393 addrmod2(cond | B26 | L, dst, src);
mads.s.ager31e71382008-08-13 09:32:07 +00001394
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001395 // Eliminate pattern: push(ry), pop(rx)
1396 // str(ry, MemOperand(sp, 4, NegPreIndex), al)
1397 // ldr(rx, MemOperand(sp, 4, PostIndex), al)
1398 // Both instructions can be eliminated if ry = rx.
1399 // If ry != rx, a register copy from ry to rx is inserted
1400 // after eliminating the push and the pop instructions.
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001401 if (can_peephole_optimize(2)) {
1402 Instr push_instr = instr_at(pc_ - 2 * kInstrSize);
1403 Instr pop_instr = instr_at(pc_ - 1 * kInstrSize);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001404
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001405 if (IsPush(push_instr) && IsPop(pop_instr)) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00001406 if (Instruction::RdValue(pop_instr) != Instruction::RdValue(push_instr)) {
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001407 // For consecutive push and pop on different registers,
1408 // we delete both the push & pop and insert a register move.
1409 // push ry, pop rx --> mov rx, ry
1410 Register reg_pushed, reg_popped;
1411 reg_pushed = GetRd(push_instr);
1412 reg_popped = GetRd(pop_instr);
1413 pc_ -= 2 * kInstrSize;
1414 // Insert a mov instruction, which is better than a pair of push & pop
1415 mov(reg_popped, reg_pushed);
1416 if (FLAG_print_peephole_optimization) {
1417 PrintF("%x push/pop (diff reg) replaced by a reg move\n",
1418 pc_offset());
1419 }
1420 } else {
1421 // For consecutive push and pop on the same register,
1422 // both the push and the pop can be deleted.
1423 pc_ -= 2 * kInstrSize;
1424 if (FLAG_print_peephole_optimization) {
1425 PrintF("%x push/pop (same reg) eliminated\n", pc_offset());
1426 }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001427 }
1428 }
1429 }
1430
1431 if (can_peephole_optimize(2)) {
1432 Instr str_instr = instr_at(pc_ - 2 * kInstrSize);
1433 Instr ldr_instr = instr_at(pc_ - 1 * kInstrSize);
1434
1435 if ((IsStrRegFpOffset(str_instr) &&
1436 IsLdrRegFpOffset(ldr_instr)) ||
1437 (IsStrRegFpNegOffset(str_instr) &&
1438 IsLdrRegFpNegOffset(ldr_instr))) {
1439 if ((ldr_instr & kLdrStrInstrArgumentMask) ==
1440 (str_instr & kLdrStrInstrArgumentMask)) {
1441 // Pattern: Ldr/str same fp+offset, same register.
1442 //
1443 // The following:
1444 // str rx, [fp, #-12]
1445 // ldr rx, [fp, #-12]
1446 //
1447 // Becomes:
1448 // str rx, [fp, #-12]
1449
1450 pc_ -= 1 * kInstrSize;
1451 if (FLAG_print_peephole_optimization) {
1452 PrintF("%x str/ldr (fp + same offset), same reg\n", pc_offset());
1453 }
1454 } else if ((ldr_instr & kLdrStrOffsetMask) ==
1455 (str_instr & kLdrStrOffsetMask)) {
1456 // Pattern: Ldr/str same fp+offset, different register.
1457 //
1458 // The following:
1459 // str rx, [fp, #-12]
1460 // ldr ry, [fp, #-12]
1461 //
1462 // Becomes:
1463 // str rx, [fp, #-12]
1464 // mov ry, rx
1465
1466 Register reg_stored, reg_loaded;
1467 reg_stored = GetRd(str_instr);
1468 reg_loaded = GetRd(ldr_instr);
1469 pc_ -= 1 * kInstrSize;
1470 // Insert a mov instruction, which is better than ldr.
1471 mov(reg_loaded, reg_stored);
1472 if (FLAG_print_peephole_optimization) {
1473 PrintF("%x str/ldr (fp + same offset), diff reg \n", pc_offset());
1474 }
1475 }
1476 }
1477 }
1478
1479 if (can_peephole_optimize(3)) {
1480 Instr mem_write_instr = instr_at(pc_ - 3 * kInstrSize);
1481 Instr ldr_instr = instr_at(pc_ - 2 * kInstrSize);
1482 Instr mem_read_instr = instr_at(pc_ - 1 * kInstrSize);
1483 if (IsPush(mem_write_instr) &&
1484 IsPop(mem_read_instr)) {
1485 if ((IsLdrRegFpOffset(ldr_instr) ||
1486 IsLdrRegFpNegOffset(ldr_instr))) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00001487 if (Instruction::RdValue(mem_write_instr) ==
1488 Instruction::RdValue(mem_read_instr)) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001489 // Pattern: push & pop from/to same register,
1490 // with a fp+offset ldr in between
1491 //
1492 // The following:
1493 // str rx, [sp, #-4]!
1494 // ldr rz, [fp, #-24]
1495 // ldr rx, [sp], #+4
1496 //
1497 // Becomes:
1498 // if(rx == rz)
1499 // delete all
1500 // else
1501 // ldr rz, [fp, #-24]
1502
ager@chromium.org378b34e2011-01-28 08:04:38 +00001503 if (Instruction::RdValue(mem_write_instr) ==
1504 Instruction::RdValue(ldr_instr)) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001505 pc_ -= 3 * kInstrSize;
1506 } else {
1507 pc_ -= 3 * kInstrSize;
1508 // Reinsert back the ldr rz.
1509 emit(ldr_instr);
1510 }
1511 if (FLAG_print_peephole_optimization) {
1512 PrintF("%x push/pop -dead ldr fp+offset in middle\n", pc_offset());
1513 }
1514 } else {
1515 // Pattern: push & pop from/to different registers
1516 // with a fp+offset ldr in between
1517 //
1518 // The following:
1519 // str rx, [sp, #-4]!
1520 // ldr rz, [fp, #-24]
1521 // ldr ry, [sp], #+4
1522 //
1523 // Becomes:
1524 // if(ry == rz)
1525 // mov ry, rx;
1526 // else if(rx != rz)
1527 // ldr rz, [fp, #-24]
1528 // mov ry, rx
1529 // else if((ry != rz) || (rx == rz)) becomes:
1530 // mov ry, rx
1531 // ldr rz, [fp, #-24]
1532
1533 Register reg_pushed, reg_popped;
ager@chromium.org378b34e2011-01-28 08:04:38 +00001534 if (Instruction::RdValue(mem_read_instr) ==
1535 Instruction::RdValue(ldr_instr)) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001536 reg_pushed = GetRd(mem_write_instr);
1537 reg_popped = GetRd(mem_read_instr);
1538 pc_ -= 3 * kInstrSize;
1539 mov(reg_popped, reg_pushed);
ager@chromium.org378b34e2011-01-28 08:04:38 +00001540 } else if (Instruction::RdValue(mem_write_instr) !=
1541 Instruction::RdValue(ldr_instr)) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001542 reg_pushed = GetRd(mem_write_instr);
1543 reg_popped = GetRd(mem_read_instr);
1544 pc_ -= 3 * kInstrSize;
1545 emit(ldr_instr);
1546 mov(reg_popped, reg_pushed);
ager@chromium.org378b34e2011-01-28 08:04:38 +00001547 } else if ((Instruction::RdValue(mem_read_instr) !=
1548 Instruction::RdValue(ldr_instr)) ||
1549 (Instruction::RdValue(mem_write_instr) ==
1550 Instruction::RdValue(ldr_instr))) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001551 reg_pushed = GetRd(mem_write_instr);
1552 reg_popped = GetRd(mem_read_instr);
1553 pc_ -= 3 * kInstrSize;
1554 mov(reg_popped, reg_pushed);
1555 emit(ldr_instr);
1556 }
1557 if (FLAG_print_peephole_optimization) {
1558 PrintF("%x push/pop (ldr fp+off in middle)\n", pc_offset());
1559 }
1560 }
1561 }
mads.s.ager31e71382008-08-13 09:32:07 +00001562 }
1563 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001564}
1565
1566
1567void Assembler::str(Register src, const MemOperand& dst, Condition cond) {
1568 addrmod2(cond | B26, src, dst);
mads.s.ager31e71382008-08-13 09:32:07 +00001569
1570 // Eliminate pattern: pop(), push(r)
1571 // add sp, sp, #4 LeaveCC, al; str r, [sp, #-4], al
1572 // -> str r, [sp, 0], al
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001573 if (can_peephole_optimize(2) &&
ager@chromium.org5c838252010-02-19 08:53:10 +00001574 // Pattern.
mads.s.ager31e71382008-08-13 09:32:07 +00001575 instr_at(pc_ - 1 * kInstrSize) == (kPushRegPattern | src.code() * B12) &&
1576 instr_at(pc_ - 2 * kInstrSize) == kPopInstruction) {
1577 pc_ -= 2 * kInstrSize;
1578 emit(al | B26 | 0 | Offset | sp.code() * B16 | src.code() * B12);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001579 if (FLAG_print_peephole_optimization) {
mads.s.ager31e71382008-08-13 09:32:07 +00001580 PrintF("%x pop()/push(reg) eliminated\n", pc_offset());
1581 }
1582 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001583}
1584
1585
1586void Assembler::ldrb(Register dst, const MemOperand& src, Condition cond) {
1587 addrmod2(cond | B26 | B | L, dst, src);
1588}
1589
1590
1591void Assembler::strb(Register src, const MemOperand& dst, Condition cond) {
1592 addrmod2(cond | B26 | B, src, dst);
1593}
1594
1595
1596void Assembler::ldrh(Register dst, const MemOperand& src, Condition cond) {
1597 addrmod3(cond | L | B7 | H | B4, dst, src);
1598}
1599
1600
1601void Assembler::strh(Register src, const MemOperand& dst, Condition cond) {
1602 addrmod3(cond | B7 | H | B4, src, dst);
1603}
1604
1605
1606void Assembler::ldrsb(Register dst, const MemOperand& src, Condition cond) {
1607 addrmod3(cond | L | B7 | S6 | B4, dst, src);
1608}
1609
1610
1611void Assembler::ldrsh(Register dst, const MemOperand& src, Condition cond) {
1612 addrmod3(cond | L | B7 | S6 | H | B4, dst, src);
1613}
1614
1615
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001616void Assembler::ldrd(Register dst1, Register dst2,
1617 const MemOperand& src, Condition cond) {
1618 ASSERT(CpuFeatures::IsEnabled(ARMv7));
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001619 ASSERT(src.rm().is(no_reg));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001620 ASSERT(!dst1.is(lr)); // r14.
1621 ASSERT_EQ(0, dst1.code() % 2);
1622 ASSERT_EQ(dst1.code() + 1, dst2.code());
1623 addrmod3(cond | B7 | B6 | B4, dst1, src);
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001624}
1625
1626
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001627void Assembler::strd(Register src1, Register src2,
1628 const MemOperand& dst, Condition cond) {
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001629 ASSERT(dst.rm().is(no_reg));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001630 ASSERT(!src1.is(lr)); // r14.
1631 ASSERT_EQ(0, src1.code() % 2);
1632 ASSERT_EQ(src1.code() + 1, src2.code());
1633 ASSERT(CpuFeatures::IsEnabled(ARMv7));
1634 addrmod3(cond | B7 | B6 | B5 | B4, src1, dst);
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001635}
1636
ager@chromium.org5c838252010-02-19 08:53:10 +00001637// Load/Store multiple instructions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001638void Assembler::ldm(BlockAddrMode am,
1639 Register base,
1640 RegList dst,
1641 Condition cond) {
ager@chromium.org5c838252010-02-19 08:53:10 +00001642 // ABI stack constraint: ldmxx base, {..sp..} base != sp is not restartable.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001643 ASSERT(base.is(sp) || (dst & sp.bit()) == 0);
1644
1645 addrmod4(cond | B27 | am | L, base, dst);
1646
ager@chromium.org5c838252010-02-19 08:53:10 +00001647 // Emit the constant pool after a function return implemented by ldm ..{..pc}.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001648 if (cond == al && (dst & pc.bit()) != 0) {
1649 // There is a slight chance that the ldm instruction was actually a call,
1650 // in which case it would be wrong to return into the constant pool; we
1651 // recognize this case by checking if the emission of the pool was blocked
1652 // at the pc of the ldm instruction by a mov lr, pc instruction; if this is
1653 // the case, we emit a jump over the pool.
1654 CheckConstPool(true, no_const_pool_before_ == pc_offset() - kInstrSize);
1655 }
1656}
1657
1658
1659void Assembler::stm(BlockAddrMode am,
1660 Register base,
1661 RegList src,
1662 Condition cond) {
1663 addrmod4(cond | B27 | am, base, src);
1664}
1665
1666
ager@chromium.org5c838252010-02-19 08:53:10 +00001667// Exception-generating instructions and debugging support.
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001668// Stops with a non-negative code less than kNumOfWatchedStops support
1669// enabling/disabling and a counter feature. See simulator-arm.h .
1670void Assembler::stop(const char* msg, Condition cond, int32_t code) {
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001671#ifndef __arm__
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001672 ASSERT(code >= kDefaultStopCode);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001673 // The Simulator will handle the stop instruction and get the message address.
1674 // It expects to find the address just after the svc instruction.
1675 BlockConstPoolFor(2);
1676 if (code >= 0) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00001677 svc(kStopCode + code, cond);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001678 } else {
ager@chromium.org378b34e2011-01-28 08:04:38 +00001679 svc(kStopCode + kMaxStopCode, cond);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001680 }
1681 emit(reinterpret_cast<Instr>(msg));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001682#else // def __arm__
1683#ifdef CAN_USE_ARMV5_INSTRUCTIONS
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001684 if (cond != al) {
1685 Label skip;
1686 b(&skip, NegateCondition(cond));
1687 bkpt(0);
1688 bind(&skip);
1689 } else {
1690 bkpt(0);
1691 }
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001692#else // ndef CAN_USE_ARMV5_INSTRUCTIONS
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001693 svc(0x9f0001, cond);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001694#endif // ndef CAN_USE_ARMV5_INSTRUCTIONS
1695#endif // def __arm__
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001696}
1697
1698
1699void Assembler::bkpt(uint32_t imm16) { // v5 and above
1700 ASSERT(is_uint16(imm16));
ager@chromium.org378b34e2011-01-28 08:04:38 +00001701 emit(al | B24 | B21 | (imm16 >> 4)*B8 | BKPT | (imm16 & 0xf));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001702}
1703
1704
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001705void Assembler::svc(uint32_t imm24, Condition cond) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001706 ASSERT(is_uint24(imm24));
1707 emit(cond | 15*B24 | imm24);
1708}
1709
1710
ager@chromium.org5c838252010-02-19 08:53:10 +00001711// Coprocessor instructions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001712void Assembler::cdp(Coprocessor coproc,
1713 int opcode_1,
1714 CRegister crd,
1715 CRegister crn,
1716 CRegister crm,
1717 int opcode_2,
1718 Condition cond) {
1719 ASSERT(is_uint4(opcode_1) && is_uint3(opcode_2));
1720 emit(cond | B27 | B26 | B25 | (opcode_1 & 15)*B20 | crn.code()*B16 |
1721 crd.code()*B12 | coproc*B8 | (opcode_2 & 7)*B5 | crm.code());
1722}
1723
1724
1725void Assembler::cdp2(Coprocessor coproc,
1726 int opcode_1,
1727 CRegister crd,
1728 CRegister crn,
1729 CRegister crm,
1730 int opcode_2) { // v5 and above
ager@chromium.org378b34e2011-01-28 08:04:38 +00001731 cdp(coproc, opcode_1, crd, crn, crm, opcode_2, kSpecialCondition);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001732}
1733
1734
1735void Assembler::mcr(Coprocessor coproc,
1736 int opcode_1,
1737 Register rd,
1738 CRegister crn,
1739 CRegister crm,
1740 int opcode_2,
1741 Condition cond) {
1742 ASSERT(is_uint3(opcode_1) && is_uint3(opcode_2));
1743 emit(cond | B27 | B26 | B25 | (opcode_1 & 7)*B21 | crn.code()*B16 |
1744 rd.code()*B12 | coproc*B8 | (opcode_2 & 7)*B5 | B4 | crm.code());
1745}
1746
1747
1748void Assembler::mcr2(Coprocessor coproc,
1749 int opcode_1,
1750 Register rd,
1751 CRegister crn,
1752 CRegister crm,
1753 int opcode_2) { // v5 and above
ager@chromium.org378b34e2011-01-28 08:04:38 +00001754 mcr(coproc, opcode_1, rd, crn, crm, opcode_2, kSpecialCondition);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001755}
1756
1757
1758void Assembler::mrc(Coprocessor coproc,
1759 int opcode_1,
1760 Register rd,
1761 CRegister crn,
1762 CRegister crm,
1763 int opcode_2,
1764 Condition cond) {
1765 ASSERT(is_uint3(opcode_1) && is_uint3(opcode_2));
1766 emit(cond | B27 | B26 | B25 | (opcode_1 & 7)*B21 | L | crn.code()*B16 |
1767 rd.code()*B12 | coproc*B8 | (opcode_2 & 7)*B5 | B4 | crm.code());
1768}
1769
1770
1771void Assembler::mrc2(Coprocessor coproc,
1772 int opcode_1,
1773 Register rd,
1774 CRegister crn,
1775 CRegister crm,
1776 int opcode_2) { // v5 and above
ager@chromium.org378b34e2011-01-28 08:04:38 +00001777 mrc(coproc, opcode_1, rd, crn, crm, opcode_2, kSpecialCondition);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001778}
1779
1780
1781void Assembler::ldc(Coprocessor coproc,
1782 CRegister crd,
1783 const MemOperand& src,
1784 LFlag l,
1785 Condition cond) {
1786 addrmod5(cond | B27 | B26 | l | L | coproc*B8, crd, src);
1787}
1788
1789
1790void Assembler::ldc(Coprocessor coproc,
1791 CRegister crd,
1792 Register rn,
1793 int option,
1794 LFlag l,
1795 Condition cond) {
ager@chromium.org5c838252010-02-19 08:53:10 +00001796 // Unindexed addressing.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001797 ASSERT(is_uint8(option));
1798 emit(cond | B27 | B26 | U | l | L | rn.code()*B16 | crd.code()*B12 |
1799 coproc*B8 | (option & 255));
1800}
1801
1802
1803void Assembler::ldc2(Coprocessor coproc,
1804 CRegister crd,
1805 const MemOperand& src,
1806 LFlag l) { // v5 and above
ager@chromium.org378b34e2011-01-28 08:04:38 +00001807 ldc(coproc, crd, src, l, kSpecialCondition);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001808}
1809
1810
1811void Assembler::ldc2(Coprocessor coproc,
1812 CRegister crd,
1813 Register rn,
1814 int option,
1815 LFlag l) { // v5 and above
ager@chromium.org378b34e2011-01-28 08:04:38 +00001816 ldc(coproc, crd, rn, option, l, kSpecialCondition);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001817}
1818
1819
1820void Assembler::stc(Coprocessor coproc,
1821 CRegister crd,
1822 const MemOperand& dst,
1823 LFlag l,
1824 Condition cond) {
1825 addrmod5(cond | B27 | B26 | l | coproc*B8, crd, dst);
1826}
1827
1828
1829void Assembler::stc(Coprocessor coproc,
1830 CRegister crd,
1831 Register rn,
1832 int option,
1833 LFlag l,
1834 Condition cond) {
ager@chromium.org5c838252010-02-19 08:53:10 +00001835 // Unindexed addressing.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001836 ASSERT(is_uint8(option));
1837 emit(cond | B27 | B26 | U | l | rn.code()*B16 | crd.code()*B12 |
1838 coproc*B8 | (option & 255));
1839}
1840
1841
1842void Assembler::stc2(Coprocessor
1843 coproc, CRegister crd,
1844 const MemOperand& dst,
1845 LFlag l) { // v5 and above
ager@chromium.org378b34e2011-01-28 08:04:38 +00001846 stc(coproc, crd, dst, l, kSpecialCondition);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001847}
1848
1849
1850void Assembler::stc2(Coprocessor coproc,
1851 CRegister crd,
1852 Register rn,
1853 int option,
1854 LFlag l) { // v5 and above
ager@chromium.org378b34e2011-01-28 08:04:38 +00001855 stc(coproc, crd, rn, option, l, kSpecialCondition);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001856}
1857
1858
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001859// Support for VFP.
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001860
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001861void Assembler::vldr(const DwVfpRegister dst,
1862 const Register base,
1863 int offset,
1864 const Condition cond) {
1865 // Ddst = MEM(Rbase + offset).
1866 // Instruction details available in ARM DDI 0406A, A8-628.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001867 // cond(31-28) | 1101(27-24)| U001(23-20) | Rbase(19-16) |
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001868 // Vdst(15-12) | 1011(11-8) | offset
1869 ASSERT(CpuFeatures::IsEnabled(VFP3));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001870 int u = 1;
1871 if (offset < 0) {
1872 offset = -offset;
1873 u = 0;
1874 }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001875
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001876 ASSERT(offset >= 0);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001877 if ((offset % 4) == 0 && (offset / 4) < 256) {
1878 emit(cond | u*B23 | 0xD1*B20 | base.code()*B16 | dst.code()*B12 |
1879 0xB*B8 | ((offset / 4) & 255));
1880 } else {
1881 // Larger offsets must be handled by computing the correct address
1882 // in the ip register.
1883 ASSERT(!base.is(ip));
1884 if (u == 1) {
1885 add(ip, base, Operand(offset));
1886 } else {
1887 sub(ip, base, Operand(offset));
1888 }
1889 emit(cond | 0xD1*B20 | ip.code()*B16 | dst.code()*B12 | 0xB*B8);
1890 }
1891}
1892
1893
1894void Assembler::vldr(const DwVfpRegister dst,
1895 const MemOperand& operand,
1896 const Condition cond) {
1897 ASSERT(!operand.rm().is_valid());
1898 ASSERT(operand.am_ == Offset);
1899 vldr(dst, operand.rn(), operand.offset(), cond);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001900}
1901
1902
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001903void Assembler::vldr(const SwVfpRegister dst,
1904 const Register base,
1905 int offset,
1906 const Condition cond) {
1907 // Sdst = MEM(Rbase + offset).
1908 // Instruction details available in ARM DDI 0406A, A8-628.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001909 // cond(31-28) | 1101(27-24)| U001(23-20) | Rbase(19-16) |
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001910 // Vdst(15-12) | 1010(11-8) | offset
1911 ASSERT(CpuFeatures::IsEnabled(VFP3));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001912 int u = 1;
1913 if (offset < 0) {
1914 offset = -offset;
1915 u = 0;
1916 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001917 int sd, d;
1918 dst.split_code(&sd, &d);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001919 ASSERT(offset >= 0);
1920
1921 if ((offset % 4) == 0 && (offset / 4) < 256) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001922 emit(cond | u*B23 | d*B22 | 0xD1*B20 | base.code()*B16 | sd*B12 |
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001923 0xA*B8 | ((offset / 4) & 255));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001924 } else {
1925 // Larger offsets must be handled by computing the correct address
1926 // in the ip register.
1927 ASSERT(!base.is(ip));
1928 if (u == 1) {
1929 add(ip, base, Operand(offset));
1930 } else {
1931 sub(ip, base, Operand(offset));
1932 }
1933 emit(cond | d*B22 | 0xD1*B20 | ip.code()*B16 | sd*B12 | 0xA*B8);
1934 }
1935}
1936
1937
1938void Assembler::vldr(const SwVfpRegister dst,
1939 const MemOperand& operand,
1940 const Condition cond) {
1941 ASSERT(!operand.rm().is_valid());
1942 ASSERT(operand.am_ == Offset);
1943 vldr(dst, operand.rn(), operand.offset(), cond);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001944}
1945
1946
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001947void Assembler::vstr(const DwVfpRegister src,
1948 const Register base,
1949 int offset,
1950 const Condition cond) {
1951 // MEM(Rbase + offset) = Dsrc.
1952 // Instruction details available in ARM DDI 0406A, A8-786.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001953 // cond(31-28) | 1101(27-24)| U000(23-20) | | Rbase(19-16) |
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001954 // Vsrc(15-12) | 1011(11-8) | (offset/4)
1955 ASSERT(CpuFeatures::IsEnabled(VFP3));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001956 int u = 1;
1957 if (offset < 0) {
1958 offset = -offset;
1959 u = 0;
1960 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001961 ASSERT(offset >= 0);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001962 if ((offset % 4) == 0 && (offset / 4) < 256) {
1963 emit(cond | u*B23 | 0xD0*B20 | base.code()*B16 | src.code()*B12 |
1964 0xB*B8 | ((offset / 4) & 255));
1965 } else {
1966 // Larger offsets must be handled by computing the correct address
1967 // in the ip register.
1968 ASSERT(!base.is(ip));
1969 if (u == 1) {
1970 add(ip, base, Operand(offset));
1971 } else {
1972 sub(ip, base, Operand(offset));
1973 }
1974 emit(cond | 0xD0*B20 | ip.code()*B16 | src.code()*B12 | 0xB*B8);
1975 }
1976}
1977
1978
1979void Assembler::vstr(const DwVfpRegister src,
1980 const MemOperand& operand,
1981 const Condition cond) {
1982 ASSERT(!operand.rm().is_valid());
1983 ASSERT(operand.am_ == Offset);
1984 vstr(src, operand.rn(), operand.offset(), cond);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001985}
1986
1987
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001988void Assembler::vstr(const SwVfpRegister src,
1989 const Register base,
1990 int offset,
1991 const Condition cond) {
1992 // MEM(Rbase + offset) = SSrc.
1993 // Instruction details available in ARM DDI 0406A, A8-786.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001994 // cond(31-28) | 1101(27-24)| U000(23-20) | Rbase(19-16) |
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001995 // Vdst(15-12) | 1010(11-8) | (offset/4)
1996 ASSERT(CpuFeatures::IsEnabled(VFP3));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001997 int u = 1;
1998 if (offset < 0) {
1999 offset = -offset;
2000 u = 0;
2001 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002002 int sd, d;
2003 src.split_code(&sd, &d);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002004 ASSERT(offset >= 0);
2005 if ((offset % 4) == 0 && (offset / 4) < 256) {
2006 emit(cond | u*B23 | d*B22 | 0xD0*B20 | base.code()*B16 | sd*B12 |
2007 0xA*B8 | ((offset / 4) & 255));
2008 } else {
2009 // Larger offsets must be handled by computing the correct address
2010 // in the ip register.
2011 ASSERT(!base.is(ip));
2012 if (u == 1) {
2013 add(ip, base, Operand(offset));
2014 } else {
2015 sub(ip, base, Operand(offset));
2016 }
2017 emit(cond | d*B22 | 0xD0*B20 | ip.code()*B16 | sd*B12 | 0xA*B8);
2018 }
2019}
2020
2021
2022void Assembler::vstr(const SwVfpRegister src,
2023 const MemOperand& operand,
2024 const Condition cond) {
2025 ASSERT(!operand.rm().is_valid());
2026 ASSERT(operand.am_ == Offset);
2027 vldr(src, operand.rn(), operand.offset(), cond);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00002028}
2029
2030
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002031static void DoubleAsTwoUInt32(double d, uint32_t* lo, uint32_t* hi) {
2032 uint64_t i;
2033 memcpy(&i, &d, 8);
2034
2035 *lo = i & 0xffffffff;
2036 *hi = i >> 32;
2037}
2038
2039// Only works for little endian floating point formats.
2040// We don't support VFP on the mixed endian floating point platform.
2041static bool FitsVMOVDoubleImmediate(double d, uint32_t *encoding) {
2042 ASSERT(CpuFeatures::IsEnabled(VFP3));
2043
2044 // VMOV can accept an immediate of the form:
2045 //
2046 // +/- m * 2^(-n) where 16 <= m <= 31 and 0 <= n <= 7
2047 //
2048 // The immediate is encoded using an 8-bit quantity, comprised of two
2049 // 4-bit fields. For an 8-bit immediate of the form:
2050 //
2051 // [abcdefgh]
2052 //
2053 // where a is the MSB and h is the LSB, an immediate 64-bit double can be
2054 // created of the form:
2055 //
2056 // [aBbbbbbb,bbcdefgh,00000000,00000000,
2057 // 00000000,00000000,00000000,00000000]
2058 //
2059 // where B = ~b.
2060 //
2061
2062 uint32_t lo, hi;
2063 DoubleAsTwoUInt32(d, &lo, &hi);
2064
2065 // The most obvious constraint is the long block of zeroes.
2066 if ((lo != 0) || ((hi & 0xffff) != 0)) {
2067 return false;
2068 }
2069
2070 // Bits 62:55 must be all clear or all set.
2071 if (((hi & 0x3fc00000) != 0) && ((hi & 0x3fc00000) != 0x3fc00000)) {
2072 return false;
2073 }
2074
2075 // Bit 63 must be NOT bit 62.
2076 if (((hi ^ (hi << 1)) & (0x40000000)) == 0) {
2077 return false;
2078 }
2079
2080 // Create the encoded immediate in the form:
2081 // [00000000,0000abcd,00000000,0000efgh]
2082 *encoding = (hi >> 16) & 0xf; // Low nybble.
2083 *encoding |= (hi >> 4) & 0x70000; // Low three bits of the high nybble.
2084 *encoding |= (hi >> 12) & 0x80000; // Top bit of the high nybble.
2085
2086 return true;
2087}
2088
2089
2090void Assembler::vmov(const DwVfpRegister dst,
2091 double imm,
2092 const Condition cond) {
2093 // Dd = immediate
2094 // Instruction details available in ARM DDI 0406B, A8-640.
2095 ASSERT(CpuFeatures::IsEnabled(VFP3));
2096
2097 uint32_t enc;
2098 if (FitsVMOVDoubleImmediate(imm, &enc)) {
2099 // The double can be encoded in the instruction.
2100 emit(cond | 0xE*B24 | 0xB*B20 | dst.code()*B12 | 0xB*B8 | enc);
2101 } else {
2102 // Synthesise the double from ARM immediates. This could be implemented
2103 // using vldr from a constant pool.
2104 uint32_t lo, hi;
2105 DoubleAsTwoUInt32(imm, &lo, &hi);
2106
2107 if (lo == hi) {
2108 // If the lo and hi parts of the double are equal, the literal is easier
2109 // to create. This is the case with 0.0.
2110 mov(ip, Operand(lo));
2111 vmov(dst, ip, ip);
2112 } else {
2113 // Move the low part of the double into the lower of the corresponsing S
2114 // registers of D register dst.
2115 mov(ip, Operand(lo));
2116 vmov(dst.low(), ip, cond);
2117
2118 // Move the high part of the double into the higher of the corresponsing S
2119 // registers of D register dst.
2120 mov(ip, Operand(hi));
2121 vmov(dst.high(), ip, cond);
2122 }
2123 }
2124}
2125
2126
2127void Assembler::vmov(const SwVfpRegister dst,
2128 const SwVfpRegister src,
2129 const Condition cond) {
2130 // Sd = Sm
2131 // Instruction details available in ARM DDI 0406B, A8-642.
2132 ASSERT(CpuFeatures::IsEnabled(VFP3));
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002133 int sd, d, sm, m;
2134 dst.split_code(&sd, &d);
2135 src.split_code(&sm, &m);
2136 emit(cond | 0xE*B24 | d*B22 | 0xB*B20 | sd*B12 | 0xA*B8 | B6 | m*B5 | sm);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002137}
2138
2139
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00002140void Assembler::vmov(const DwVfpRegister dst,
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00002141 const DwVfpRegister src,
2142 const Condition cond) {
2143 // Dd = Dm
2144 // Instruction details available in ARM DDI 0406B, A8-642.
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002145 ASSERT(CpuFeatures::IsEnabled(VFP3));
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00002146 emit(cond | 0xE*B24 | 0xB*B20 |
2147 dst.code()*B12 | 0x5*B9 | B8 | B6 | src.code());
2148}
2149
2150
2151void Assembler::vmov(const DwVfpRegister dst,
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00002152 const Register src1,
2153 const Register src2,
2154 const Condition cond) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002155 // Dm = <Rt,Rt2>.
2156 // Instruction details available in ARM DDI 0406A, A8-646.
2157 // cond(31-28) | 1100(27-24)| 010(23-21) | op=0(20) | Rt2(19-16) |
2158 // Rt(15-12) | 1011(11-8) | 00(7-6) | M(5) | 1(4) | Vm
2159 ASSERT(CpuFeatures::IsEnabled(VFP3));
2160 ASSERT(!src1.is(pc) && !src2.is(pc));
2161 emit(cond | 0xC*B24 | B22 | src2.code()*B16 |
2162 src1.code()*B12 | 0xB*B8 | B4 | dst.code());
2163}
2164
2165
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00002166void Assembler::vmov(const Register dst1,
2167 const Register dst2,
2168 const DwVfpRegister src,
2169 const Condition cond) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002170 // <Rt,Rt2> = Dm.
2171 // Instruction details available in ARM DDI 0406A, A8-646.
2172 // cond(31-28) | 1100(27-24)| 010(23-21) | op=1(20) | Rt2(19-16) |
2173 // Rt(15-12) | 1011(11-8) | 00(7-6) | M(5) | 1(4) | Vm
2174 ASSERT(CpuFeatures::IsEnabled(VFP3));
2175 ASSERT(!dst1.is(pc) && !dst2.is(pc));
2176 emit(cond | 0xC*B24 | B22 | B20 | dst2.code()*B16 |
2177 dst1.code()*B12 | 0xB*B8 | B4 | src.code());
2178}
2179
2180
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00002181void Assembler::vmov(const SwVfpRegister dst,
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002182 const Register src,
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002183 const Condition cond) {
2184 // Sn = Rt.
2185 // Instruction details available in ARM DDI 0406A, A8-642.
2186 // cond(31-28) | 1110(27-24)| 000(23-21) | op=0(20) | Vn(19-16) |
2187 // Rt(15-12) | 1010(11-8) | N(7)=0 | 00(6-5) | 1(4) | 0000(3-0)
2188 ASSERT(CpuFeatures::IsEnabled(VFP3));
2189 ASSERT(!src.is(pc));
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002190 int sn, n;
2191 dst.split_code(&sn, &n);
2192 emit(cond | 0xE*B24 | sn*B16 | src.code()*B12 | 0xA*B8 | n*B7 | B4);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002193}
2194
2195
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00002196void Assembler::vmov(const Register dst,
2197 const SwVfpRegister src,
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002198 const Condition cond) {
2199 // Rt = Sn.
2200 // Instruction details available in ARM DDI 0406A, A8-642.
2201 // cond(31-28) | 1110(27-24)| 000(23-21) | op=1(20) | Vn(19-16) |
2202 // Rt(15-12) | 1010(11-8) | N(7)=0 | 00(6-5) | 1(4) | 0000(3-0)
2203 ASSERT(CpuFeatures::IsEnabled(VFP3));
2204 ASSERT(!dst.is(pc));
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002205 int sn, n;
2206 src.split_code(&sn, &n);
2207 emit(cond | 0xE*B24 | B20 | sn*B16 | dst.code()*B12 | 0xA*B8 | n*B7 | B4);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002208}
2209
2210
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002211// Type of data to read from or write to VFP register.
2212// Used as specifier in generic vcvt instruction.
2213enum VFPType { S32, U32, F32, F64 };
2214
2215
2216static bool IsSignedVFPType(VFPType type) {
2217 switch (type) {
2218 case S32:
2219 return true;
2220 case U32:
2221 return false;
2222 default:
2223 UNREACHABLE();
2224 return false;
2225 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002226}
2227
2228
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002229static bool IsIntegerVFPType(VFPType type) {
2230 switch (type) {
2231 case S32:
2232 case U32:
2233 return true;
2234 case F32:
2235 case F64:
2236 return false;
2237 default:
2238 UNREACHABLE();
2239 return false;
2240 }
2241}
2242
2243
2244static bool IsDoubleVFPType(VFPType type) {
2245 switch (type) {
2246 case F32:
2247 return false;
2248 case F64:
2249 return true;
2250 default:
2251 UNREACHABLE();
2252 return false;
2253 }
2254}
2255
2256
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002257// Split five bit reg_code based on size of reg_type.
2258// 32-bit register codes are Vm:M
2259// 64-bit register codes are M:Vm
2260// where Vm is four bits, and M is a single bit.
2261static void SplitRegCode(VFPType reg_type,
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002262 int reg_code,
2263 int* vm,
2264 int* m) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002265 ASSERT((reg_code >= 0) && (reg_code <= 31));
2266 if (IsIntegerVFPType(reg_type) || !IsDoubleVFPType(reg_type)) {
2267 // 32 bit type.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002268 *m = reg_code & 0x1;
2269 *vm = reg_code >> 1;
2270 } else {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002271 // 64 bit type.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002272 *m = (reg_code & 0x10) >> 4;
2273 *vm = reg_code & 0x0F;
2274 }
2275}
2276
2277
2278// Encode vcvt.src_type.dst_type instruction.
2279static Instr EncodeVCVT(const VFPType dst_type,
2280 const int dst_code,
2281 const VFPType src_type,
2282 const int src_code,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002283 VFPConversionMode mode,
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002284 const Condition cond) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002285 ASSERT(src_type != dst_type);
2286 int D, Vd, M, Vm;
2287 SplitRegCode(src_type, src_code, &Vm, &M);
2288 SplitRegCode(dst_type, dst_code, &Vd, &D);
2289
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002290 if (IsIntegerVFPType(dst_type) || IsIntegerVFPType(src_type)) {
2291 // Conversion between IEEE floating point and 32-bit integer.
2292 // Instruction details available in ARM DDI 0406B, A8.6.295.
2293 // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 1(19) | opc2(18-16) |
2294 // Vd(15-12) | 101(11-9) | sz(8) | op(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
2295 ASSERT(!IsIntegerVFPType(dst_type) || !IsIntegerVFPType(src_type));
2296
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002297 int sz, opc2, op;
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002298
2299 if (IsIntegerVFPType(dst_type)) {
2300 opc2 = IsSignedVFPType(dst_type) ? 0x5 : 0x4;
2301 sz = IsDoubleVFPType(src_type) ? 0x1 : 0x0;
ager@chromium.org01fe7df2010-11-10 11:59:11 +00002302 op = mode;
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002303 } else {
2304 ASSERT(IsIntegerVFPType(src_type));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002305 opc2 = 0x0;
2306 sz = IsDoubleVFPType(dst_type) ? 0x1 : 0x0;
2307 op = IsSignedVFPType(src_type) ? 0x1 : 0x0;
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002308 }
2309
2310 return (cond | 0xE*B24 | B23 | D*B22 | 0x3*B20 | B19 | opc2*B16 |
2311 Vd*B12 | 0x5*B9 | sz*B8 | op*B7 | B6 | M*B5 | Vm);
2312 } else {
2313 // Conversion between IEEE double and single precision.
2314 // Instruction details available in ARM DDI 0406B, A8.6.298.
2315 // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 0111(19-16) |
2316 // 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 +00002317 int sz = IsDoubleVFPType(src_type) ? 0x1 : 0x0;
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002318 return (cond | 0xE*B24 | B23 | D*B22 | 0x3*B20 | 0x7*B16 |
2319 Vd*B12 | 0x5*B9 | sz*B8 | B7 | B6 | M*B5 | Vm);
2320 }
2321}
2322
2323
2324void Assembler::vcvt_f64_s32(const DwVfpRegister dst,
2325 const SwVfpRegister src,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002326 VFPConversionMode mode,
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002327 const Condition cond) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002328 ASSERT(CpuFeatures::IsEnabled(VFP3));
ager@chromium.org01fe7df2010-11-10 11:59:11 +00002329 emit(EncodeVCVT(F64, dst.code(), S32, src.code(), mode, cond));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002330}
2331
2332
2333void Assembler::vcvt_f32_s32(const SwVfpRegister dst,
2334 const SwVfpRegister src,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002335 VFPConversionMode mode,
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002336 const Condition cond) {
2337 ASSERT(CpuFeatures::IsEnabled(VFP3));
ager@chromium.org01fe7df2010-11-10 11:59:11 +00002338 emit(EncodeVCVT(F32, dst.code(), S32, src.code(), mode, cond));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002339}
2340
2341
2342void Assembler::vcvt_f64_u32(const DwVfpRegister dst,
2343 const SwVfpRegister src,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002344 VFPConversionMode mode,
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002345 const Condition cond) {
2346 ASSERT(CpuFeatures::IsEnabled(VFP3));
ager@chromium.org01fe7df2010-11-10 11:59:11 +00002347 emit(EncodeVCVT(F64, dst.code(), U32, src.code(), mode, cond));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002348}
2349
2350
2351void Assembler::vcvt_s32_f64(const SwVfpRegister dst,
2352 const DwVfpRegister src,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002353 VFPConversionMode mode,
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002354 const Condition cond) {
2355 ASSERT(CpuFeatures::IsEnabled(VFP3));
ager@chromium.org01fe7df2010-11-10 11:59:11 +00002356 emit(EncodeVCVT(S32, dst.code(), F64, src.code(), mode, cond));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002357}
2358
2359
2360void Assembler::vcvt_u32_f64(const SwVfpRegister dst,
2361 const DwVfpRegister src,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002362 VFPConversionMode mode,
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002363 const Condition cond) {
2364 ASSERT(CpuFeatures::IsEnabled(VFP3));
ager@chromium.org01fe7df2010-11-10 11:59:11 +00002365 emit(EncodeVCVT(U32, dst.code(), F64, src.code(), mode, cond));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002366}
2367
2368
2369void Assembler::vcvt_f64_f32(const DwVfpRegister dst,
2370 const SwVfpRegister src,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002371 VFPConversionMode mode,
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002372 const Condition cond) {
2373 ASSERT(CpuFeatures::IsEnabled(VFP3));
ager@chromium.org01fe7df2010-11-10 11:59:11 +00002374 emit(EncodeVCVT(F64, dst.code(), F32, src.code(), mode, cond));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002375}
2376
2377
2378void Assembler::vcvt_f32_f64(const SwVfpRegister dst,
2379 const DwVfpRegister src,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002380 VFPConversionMode mode,
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002381 const Condition cond) {
2382 ASSERT(CpuFeatures::IsEnabled(VFP3));
ager@chromium.org01fe7df2010-11-10 11:59:11 +00002383 emit(EncodeVCVT(F32, dst.code(), F64, src.code(), mode, cond));
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002384}
2385
2386
whesse@chromium.org7a392b32011-01-31 11:30:36 +00002387void Assembler::vabs(const DwVfpRegister dst,
2388 const DwVfpRegister src,
2389 const Condition cond) {
2390 emit(cond | 0xE*B24 | 0xB*B20 | dst.code()*B12 |
2391 0x5*B9 | B8 | 0x3*B6 | src.code());
2392}
2393
2394
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00002395void Assembler::vadd(const DwVfpRegister dst,
2396 const DwVfpRegister src1,
2397 const DwVfpRegister src2,
2398 const Condition cond) {
2399 // Dd = vadd(Dn, Dm) double precision floating point addition.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002400 // Dd = D:Vd; Dm=M:Vm; Dn=N:Vm.
2401 // Instruction details available in ARM DDI 0406A, A8-536.
2402 // cond(31-28) | 11100(27-23)| D=?(22) | 11(21-20) | Vn(19-16) |
2403 // Vd(15-12) | 101(11-9) | sz(8)=1 | N(7)=0 | 0(6) | M=?(5) | 0(4) | Vm(3-0)
2404 ASSERT(CpuFeatures::IsEnabled(VFP3));
2405 emit(cond | 0xE*B24 | 0x3*B20 | src1.code()*B16 |
2406 dst.code()*B12 | 0x5*B9 | B8 | src2.code());
2407}
2408
2409
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00002410void Assembler::vsub(const DwVfpRegister dst,
2411 const DwVfpRegister src1,
2412 const DwVfpRegister src2,
2413 const Condition cond) {
2414 // Dd = vsub(Dn, Dm) double precision floating point subtraction.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002415 // Dd = D:Vd; Dm=M:Vm; Dn=N:Vm.
2416 // Instruction details available in ARM DDI 0406A, A8-784.
2417 // cond(31-28) | 11100(27-23)| D=?(22) | 11(21-20) | Vn(19-16) |
2418 // Vd(15-12) | 101(11-9) | sz(8)=1 | N(7)=0 | 1(6) | M=?(5) | 0(4) | Vm(3-0)
2419 ASSERT(CpuFeatures::IsEnabled(VFP3));
2420 emit(cond | 0xE*B24 | 0x3*B20 | src1.code()*B16 |
2421 dst.code()*B12 | 0x5*B9 | B8 | B6 | src2.code());
2422}
2423
2424
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00002425void Assembler::vmul(const DwVfpRegister dst,
2426 const DwVfpRegister src1,
2427 const DwVfpRegister src2,
2428 const Condition cond) {
2429 // Dd = vmul(Dn, Dm) double precision floating point multiplication.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002430 // Dd = D:Vd; Dm=M:Vm; Dn=N:Vm.
2431 // Instruction details available in ARM DDI 0406A, A8-784.
2432 // cond(31-28) | 11100(27-23)| D=?(22) | 10(21-20) | Vn(19-16) |
2433 // Vd(15-12) | 101(11-9) | sz(8)=1 | N(7)=0 | 0(6) | M=?(5) | 0(4) | Vm(3-0)
2434 ASSERT(CpuFeatures::IsEnabled(VFP3));
2435 emit(cond | 0xE*B24 | 0x2*B20 | src1.code()*B16 |
2436 dst.code()*B12 | 0x5*B9 | B8 | src2.code());
2437}
2438
2439
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00002440void Assembler::vdiv(const DwVfpRegister dst,
2441 const DwVfpRegister src1,
2442 const DwVfpRegister src2,
2443 const Condition cond) {
2444 // Dd = vdiv(Dn, Dm) double precision floating point division.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002445 // Dd = D:Vd; Dm=M:Vm; Dn=N:Vm.
2446 // Instruction details available in ARM DDI 0406A, A8-584.
2447 // cond(31-28) | 11101(27-23)| D=?(22) | 00(21-20) | Vn(19-16) |
2448 // Vd(15-12) | 101(11-9) | sz(8)=1 | N(7)=? | 0(6) | M=?(5) | 0(4) | Vm(3-0)
2449 ASSERT(CpuFeatures::IsEnabled(VFP3));
2450 emit(cond | 0xE*B24 | B23 | src1.code()*B16 |
2451 dst.code()*B12 | 0x5*B9 | B8 | src2.code());
2452}
2453
2454
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00002455void Assembler::vcmp(const DwVfpRegister src1,
2456 const DwVfpRegister src2,
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002457 const Condition cond) {
2458 // vcmp(Dd, Dm) double precision floating point comparison.
2459 // Instruction details available in ARM DDI 0406A, A8-570.
2460 // cond(31-28) | 11101 (27-23)| D=?(22) | 11 (21-20) | 0100 (19-16) |
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002461 // 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 +00002462 ASSERT(CpuFeatures::IsEnabled(VFP3));
2463 emit(cond | 0xE*B24 |B23 | 0x3*B20 | B18 |
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002464 src1.code()*B12 | 0x5*B9 | B8 | B6 | src2.code());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002465}
2466
2467
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002468void Assembler::vcmp(const DwVfpRegister src1,
2469 const double src2,
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002470 const Condition cond) {
2471 // vcmp(Dd, Dm) double precision floating point comparison.
2472 // Instruction details available in ARM DDI 0406A, A8-570.
2473 // cond(31-28) | 11101 (27-23)| D=?(22) | 11 (21-20) | 0101 (19-16) |
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002474 // 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 +00002475 ASSERT(CpuFeatures::IsEnabled(VFP3));
2476 ASSERT(src2 == 0.0);
2477 emit(cond | 0xE*B24 |B23 | 0x3*B20 | B18 | B16 |
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002478 src1.code()*B12 | 0x5*B9 | B8 | B6);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002479}
2480
2481
ager@chromium.org01fe7df2010-11-10 11:59:11 +00002482void Assembler::vmsr(Register dst, Condition cond) {
2483 // Instruction details available in ARM DDI 0406A, A8-652.
2484 // cond(31-28) | 1110 (27-24) | 1110(23-20)| 0001 (19-16) |
2485 // Rt(15-12) | 1010 (11-8) | 0(7) | 00 (6-5) | 1(4) | 0000(3-0)
2486 ASSERT(CpuFeatures::IsEnabled(VFP3));
2487 emit(cond | 0xE*B24 | 0xE*B20 | B16 |
2488 dst.code()*B12 | 0xA*B8 | B4);
2489}
2490
2491
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002492void Assembler::vmrs(Register dst, Condition cond) {
2493 // Instruction details available in ARM DDI 0406A, A8-652.
2494 // cond(31-28) | 1110 (27-24) | 1111(23-20)| 0001 (19-16) |
2495 // Rt(15-12) | 1010 (11-8) | 0(7) | 00 (6-5) | 1(4) | 0000(3-0)
2496 ASSERT(CpuFeatures::IsEnabled(VFP3));
2497 emit(cond | 0xE*B24 | 0xF*B20 | B16 |
2498 dst.code()*B12 | 0xA*B8 | B4);
2499}
2500
2501
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002502void Assembler::vsqrt(const DwVfpRegister dst,
2503 const DwVfpRegister src,
2504 const Condition cond) {
2505 // cond(31-28) | 11101 (27-23)| D=?(22) | 11 (21-20) | 0001 (19-16) |
2506 // Vd(15-12) | 101(11-9) | sz(8)=1 | 11 (7-6) | M(5)=? | 0(4) | Vm(3-0)
2507 ASSERT(CpuFeatures::IsEnabled(VFP3));
2508 emit(cond | 0xE*B24 | B23 | 0x3*B20 | B16 |
2509 dst.code()*B12 | 0x5*B9 | B8 | 3*B6 | src.code());
2510}
2511
2512
ager@chromium.org5c838252010-02-19 08:53:10 +00002513// Pseudo instructions.
fschneider@chromium.org013f3e12010-04-26 13:27:52 +00002514void Assembler::nop(int type) {
2515 // This is mov rx, rx.
2516 ASSERT(0 <= type && type <= 14); // mov pc, pc is not a nop.
2517 emit(al | 13*B21 | type*B12 | type);
2518}
2519
2520
ager@chromium.orgbeb25712010-11-29 08:02:25 +00002521bool Assembler::IsNop(Instr instr, int type) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002522 // Check for mov rx, rx where x = type.
ager@chromium.orgbeb25712010-11-29 08:02:25 +00002523 ASSERT(0 <= type && type <= 14); // mov pc, pc is not a nop.
2524 return instr == (al | 13*B21 | type*B12 | type);
2525}
2526
2527
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002528bool Assembler::ImmediateFitsAddrMode1Instruction(int32_t imm32) {
2529 uint32_t dummy1;
2530 uint32_t dummy2;
2531 return fits_shifter(imm32, &dummy1, &dummy2, NULL);
2532}
2533
2534
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00002535void Assembler::BlockConstPoolFor(int instructions) {
2536 BlockConstPoolBefore(pc_offset() + instructions * kInstrSize);
2537}
2538
2539
ager@chromium.org5c838252010-02-19 08:53:10 +00002540// Debugging.
ager@chromium.org4af710e2009-09-15 12:20:11 +00002541void Assembler::RecordJSReturn() {
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002542 positions_recorder()->WriteRecordedPositions();
ager@chromium.org4af710e2009-09-15 12:20:11 +00002543 CheckBuffer();
2544 RecordRelocInfo(RelocInfo::JS_RETURN);
2545}
2546
2547
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00002548void Assembler::RecordDebugBreakSlot() {
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002549 positions_recorder()->WriteRecordedPositions();
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00002550 CheckBuffer();
2551 RecordRelocInfo(RelocInfo::DEBUG_BREAK_SLOT);
2552}
2553
2554
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002555void Assembler::RecordComment(const char* msg) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002556 if (FLAG_code_comments) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002557 CheckBuffer();
ager@chromium.org236ad962008-09-25 09:45:57 +00002558 RecordRelocInfo(RelocInfo::COMMENT, reinterpret_cast<intptr_t>(msg));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002559 }
2560}
2561
2562
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002563void Assembler::GrowBuffer() {
2564 if (!own_buffer_) FATAL("external code buffer is too small");
2565
ager@chromium.org5c838252010-02-19 08:53:10 +00002566 // Compute new buffer size.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002567 CodeDesc desc; // the new buffer
2568 if (buffer_size_ < 4*KB) {
2569 desc.buffer_size = 4*KB;
2570 } else if (buffer_size_ < 1*MB) {
2571 desc.buffer_size = 2*buffer_size_;
2572 } else {
2573 desc.buffer_size = buffer_size_ + 1*MB;
2574 }
2575 CHECK_GT(desc.buffer_size, 0); // no overflow
2576
ager@chromium.org5c838252010-02-19 08:53:10 +00002577 // Setup new buffer.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002578 desc.buffer = NewArray<byte>(desc.buffer_size);
2579
2580 desc.instr_size = pc_offset();
2581 desc.reloc_size = (buffer_ + buffer_size_) - reloc_info_writer.pos();
2582
ager@chromium.org5c838252010-02-19 08:53:10 +00002583 // Copy the data.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002584 int pc_delta = desc.buffer - buffer_;
2585 int rc_delta = (desc.buffer + desc.buffer_size) - (buffer_ + buffer_size_);
2586 memmove(desc.buffer, buffer_, desc.instr_size);
2587 memmove(reloc_info_writer.pos() + rc_delta,
2588 reloc_info_writer.pos(), desc.reloc_size);
2589
ager@chromium.org5c838252010-02-19 08:53:10 +00002590 // Switch buffers.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002591 DeleteArray(buffer_);
2592 buffer_ = desc.buffer;
2593 buffer_size_ = desc.buffer_size;
2594 pc_ += pc_delta;
2595 reloc_info_writer.Reposition(reloc_info_writer.pos() + rc_delta,
2596 reloc_info_writer.last_pc() + pc_delta);
2597
ager@chromium.org5c838252010-02-19 08:53:10 +00002598 // None of our relocation types are pc relative pointing outside the code
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002599 // buffer nor pc absolute pointing inside the code buffer, so there is no need
ager@chromium.org5c838252010-02-19 08:53:10 +00002600 // to relocate any emitted relocation entries.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002601
ager@chromium.org5c838252010-02-19 08:53:10 +00002602 // Relocate pending relocation entries.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002603 for (int i = 0; i < num_prinfo_; i++) {
2604 RelocInfo& rinfo = prinfo_[i];
ager@chromium.org236ad962008-09-25 09:45:57 +00002605 ASSERT(rinfo.rmode() != RelocInfo::COMMENT &&
2606 rinfo.rmode() != RelocInfo::POSITION);
ager@chromium.org4af710e2009-09-15 12:20:11 +00002607 if (rinfo.rmode() != RelocInfo::JS_RETURN) {
2608 rinfo.set_pc(rinfo.pc() + pc_delta);
2609 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002610 }
2611}
2612
2613
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002614void Assembler::db(uint8_t data) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002615 // No relocation info should be pending while using db. db is used
2616 // to write pure data with no pointers and the constant pool should
2617 // be emitted before using db.
2618 ASSERT(num_prinfo_ == 0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002619 CheckBuffer();
2620 *reinterpret_cast<uint8_t*>(pc_) = data;
2621 pc_ += sizeof(uint8_t);
2622}
2623
2624
2625void Assembler::dd(uint32_t data) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002626 // No relocation info should be pending while using dd. dd is used
2627 // to write pure data with no pointers and the constant pool should
2628 // be emitted before using dd.
2629 ASSERT(num_prinfo_ == 0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002630 CheckBuffer();
2631 *reinterpret_cast<uint32_t*>(pc_) = data;
2632 pc_ += sizeof(uint32_t);
2633}
2634
2635
ager@chromium.org236ad962008-09-25 09:45:57 +00002636void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002637 RelocInfo rinfo(pc_, rmode, data); // we do not try to reuse pool constants
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00002638 if (rmode >= RelocInfo::JS_RETURN && rmode <= RelocInfo::DEBUG_BREAK_SLOT) {
ager@chromium.org5c838252010-02-19 08:53:10 +00002639 // Adjust code for new modes.
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00002640 ASSERT(RelocInfo::IsDebugBreakSlot(rmode)
2641 || RelocInfo::IsJSReturn(rmode)
ager@chromium.org4af710e2009-09-15 12:20:11 +00002642 || RelocInfo::IsComment(rmode)
2643 || RelocInfo::IsPosition(rmode));
ager@chromium.org5c838252010-02-19 08:53:10 +00002644 // These modes do not need an entry in the constant pool.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002645 } else {
2646 ASSERT(num_prinfo_ < kMaxNumPRInfo);
2647 prinfo_[num_prinfo_++] = rinfo;
2648 // Make sure the constant pool is not emitted in place of the next
ager@chromium.org5c838252010-02-19 08:53:10 +00002649 // instruction for which we just recorded relocation info.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002650 BlockConstPoolBefore(pc_offset() + kInstrSize);
2651 }
ager@chromium.org236ad962008-09-25 09:45:57 +00002652 if (rinfo.rmode() != RelocInfo::NONE) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002653 // Don't record external references unless the heap will be serialized.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002654 if (rmode == RelocInfo::EXTERNAL_REFERENCE) {
2655#ifdef DEBUG
2656 if (!Serializer::enabled()) {
2657 Serializer::TooLateToEnableNow();
2658 }
2659#endif
2660 if (!Serializer::enabled() && !FLAG_debug_code) {
2661 return;
2662 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002663 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002664 ASSERT(buffer_space() >= kMaxRelocSize); // too late to grow buffer here
2665 reloc_info_writer.Write(&rinfo);
2666 }
2667}
2668
2669
2670void Assembler::CheckConstPool(bool force_emit, bool require_jump) {
2671 // Calculate the offset of the next check. It will be overwritten
2672 // when a const pool is generated or when const pools are being
2673 // blocked for a specific range.
2674 next_buffer_check_ = pc_offset() + kCheckConstInterval;
2675
ager@chromium.org5c838252010-02-19 08:53:10 +00002676 // There is nothing to do if there are no pending relocation info entries.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002677 if (num_prinfo_ == 0) return;
2678
2679 // We emit a constant pool at regular intervals of about kDistBetweenPools
2680 // or when requested by parameter force_emit (e.g. after each function).
2681 // We prefer not to emit a jump unless the max distance is reached or if we
2682 // are running low on slots, which can happen if a lot of constants are being
2683 // emitted (e.g. --debug-code and many static references).
2684 int dist = pc_offset() - last_const_pool_end_;
2685 if (!force_emit && dist < kMaxDistBetweenPools &&
2686 (require_jump || dist < kDistBetweenPools) &&
2687 // TODO(1236125): Cleanup the "magic" number below. We know that
2688 // the code generation will test every kCheckConstIntervalInst.
2689 // Thus we are safe as long as we generate less than 7 constant
2690 // entries per instruction.
2691 (num_prinfo_ < (kMaxNumPRInfo - (7 * kCheckConstIntervalInst)))) {
2692 return;
2693 }
2694
2695 // If we did not return by now, we need to emit the constant pool soon.
2696
2697 // However, some small sequences of instructions must not be broken up by the
2698 // insertion of a constant pool; such sequences are protected by setting
fschneider@chromium.org013f3e12010-04-26 13:27:52 +00002699 // either const_pool_blocked_nesting_ or no_const_pool_before_, which are
2700 // both checked here. Also, recursive calls to CheckConstPool are blocked by
2701 // no_const_pool_before_.
2702 if (const_pool_blocked_nesting_ > 0 || pc_offset() < no_const_pool_before_) {
ager@chromium.org5c838252010-02-19 08:53:10 +00002703 // Emission is currently blocked; make sure we try again as soon as
2704 // possible.
fschneider@chromium.org013f3e12010-04-26 13:27:52 +00002705 if (const_pool_blocked_nesting_ > 0) {
2706 next_buffer_check_ = pc_offset() + kInstrSize;
2707 } else {
2708 next_buffer_check_ = no_const_pool_before_;
2709 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002710
ager@chromium.org5c838252010-02-19 08:53:10 +00002711 // Something is wrong if emission is forced and blocked at the same time.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002712 ASSERT(!force_emit);
2713 return;
2714 }
2715
2716 int jump_instr = require_jump ? kInstrSize : 0;
2717
2718 // Check that the code buffer is large enough before emitting the constant
2719 // pool and relocation information (include the jump over the pool and the
2720 // constant pool marker).
2721 int max_needed_space =
2722 jump_instr + kInstrSize + num_prinfo_*(kInstrSize + kMaxRelocSize);
2723 while (buffer_space() <= (max_needed_space + kGap)) GrowBuffer();
2724
ager@chromium.org5c838252010-02-19 08:53:10 +00002725 // Block recursive calls to CheckConstPool.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002726 BlockConstPoolBefore(pc_offset() + jump_instr + kInstrSize +
2727 num_prinfo_*kInstrSize);
2728 // Don't bother to check for the emit calls below.
2729 next_buffer_check_ = no_const_pool_before_;
2730
ager@chromium.org5c838252010-02-19 08:53:10 +00002731 // Emit jump over constant pool if necessary.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002732 Label after_pool;
2733 if (require_jump) b(&after_pool);
2734
2735 RecordComment("[ Constant Pool");
2736
ager@chromium.org5c838252010-02-19 08:53:10 +00002737 // Put down constant pool marker "Undefined instruction" as specified by
2738 // A3.1 Instruction set encoding.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002739 emit(0x03000000 | num_prinfo_);
2740
ager@chromium.org5c838252010-02-19 08:53:10 +00002741 // Emit constant pool entries.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002742 for (int i = 0; i < num_prinfo_; i++) {
2743 RelocInfo& rinfo = prinfo_[i];
ager@chromium.org236ad962008-09-25 09:45:57 +00002744 ASSERT(rinfo.rmode() != RelocInfo::COMMENT &&
2745 rinfo.rmode() != RelocInfo::POSITION &&
2746 rinfo.rmode() != RelocInfo::STATEMENT_POSITION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002747 Instr instr = instr_at(rinfo.pc());
ager@chromium.org4af710e2009-09-15 12:20:11 +00002748
ager@chromium.org5c838252010-02-19 08:53:10 +00002749 // Instruction to patch must be a ldr/str [pc, #offset].
2750 // P and U set, B and W clear, Rn == pc, offset12 still 0.
ager@chromium.org378b34e2011-01-28 08:04:38 +00002751 ASSERT((instr & (7*B25 | P | U | B | W | 15*B16 | kOff12Mask)) ==
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002752 (2*B25 | P | U | pc.code()*B16));
2753 int delta = pc_ - rinfo.pc() - 8;
2754 ASSERT(delta >= -4); // instr could be ldr pc, [pc, #-4] followed by targ32
2755 if (delta < 0) {
2756 instr &= ~U;
2757 delta = -delta;
2758 }
2759 ASSERT(is_uint12(delta));
2760 instr_at_put(rinfo.pc(), instr + delta);
2761 emit(rinfo.data());
2762 }
2763 num_prinfo_ = 0;
2764 last_const_pool_end_ = pc_offset();
2765
2766 RecordComment("]");
2767
2768 if (after_pool.is_linked()) {
2769 bind(&after_pool);
2770 }
2771
2772 // Since a constant pool was just emitted, move the check offset forward by
2773 // the standard interval.
2774 next_buffer_check_ = pc_offset() + kCheckConstInterval;
2775}
2776
2777
2778} } // namespace v8::internal
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002779
2780#endif // V8_TARGET_ARCH_ARM