blob: 16dc5cdfcfd9f2a48eb5c063ddee5ed0f22ff356 [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
ager@chromium.orgc4c92722009-11-18 14:12:51 +000073void CpuFeatures::Probe() {
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__
ager@chromium.orgc4c92722009-11-18 14:12:51 +000084 if (Serializer::enabled()) {
85 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 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000101#endif
102}
103
104
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000105// -----------------------------------------------------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000106// Implementation of RelocInfo
107
108const int RelocInfo::kApplyMask = 0;
109
110
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000111bool RelocInfo::IsCodedSpecially() {
112 // The deserializer needs to know whether a pointer is specially coded. Being
113 // specially coded on ARM means that it is a movw/movt instruction. We don't
114 // generate those yet.
115 return false;
116}
117
118
119
iposva@chromium.org245aa852009-02-10 00:49:54 +0000120void RelocInfo::PatchCode(byte* instructions, int instruction_count) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000121 // Patch the code at the current address with the supplied instructions.
ager@chromium.org4af710e2009-09-15 12:20:11 +0000122 Instr* pc = reinterpret_cast<Instr*>(pc_);
123 Instr* instr = reinterpret_cast<Instr*>(instructions);
124 for (int i = 0; i < instruction_count; i++) {
125 *(pc + i) = *(instr + i);
126 }
127
128 // Indicate that code has changed.
129 CPU::FlushICache(pc_, instruction_count * Assembler::kInstrSize);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000130}
131
132
133// Patch the code at the current PC with a call to the target address.
iposva@chromium.org245aa852009-02-10 00:49:54 +0000134// Additional guard instructions can be added if required.
135void RelocInfo::PatchCodeWithCall(Address target, int guard_bytes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000136 // Patch the code at the current address with a call to the target.
137 UNIMPLEMENTED();
138}
139
140
141// -----------------------------------------------------------------------------
142// Implementation of Operand and MemOperand
143// See assembler-arm-inl.h for inlined constructors
144
145Operand::Operand(Handle<Object> handle) {
146 rm_ = no_reg;
147 // Verify all Objects referred by code are NOT in new space.
148 Object* obj = *handle;
149 ASSERT(!Heap::InNewSpace(obj));
150 if (obj->IsHeapObject()) {
151 imm32_ = reinterpret_cast<intptr_t>(handle.location());
ager@chromium.org236ad962008-09-25 09:45:57 +0000152 rmode_ = RelocInfo::EMBEDDED_OBJECT;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000153 } else {
154 // no relocation needed
155 imm32_ = reinterpret_cast<intptr_t>(obj);
ager@chromium.org236ad962008-09-25 09:45:57 +0000156 rmode_ = RelocInfo::NONE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000157 }
158}
159
160
161Operand::Operand(Register rm, ShiftOp shift_op, int shift_imm) {
162 ASSERT(is_uint5(shift_imm));
163 ASSERT(shift_op != ROR || shift_imm != 0); // use RRX if you mean it
164 rm_ = rm;
165 rs_ = no_reg;
166 shift_op_ = shift_op;
167 shift_imm_ = shift_imm & 31;
168 if (shift_op == RRX) {
169 // encoded as ROR with shift_imm == 0
170 ASSERT(shift_imm == 0);
171 shift_op_ = ROR;
172 shift_imm_ = 0;
173 }
174}
175
176
177Operand::Operand(Register rm, ShiftOp shift_op, Register rs) {
178 ASSERT(shift_op != RRX);
179 rm_ = rm;
180 rs_ = no_reg;
181 shift_op_ = shift_op;
182 rs_ = rs;
183}
184
185
186MemOperand::MemOperand(Register rn, int32_t offset, AddrMode am) {
187 rn_ = rn;
188 rm_ = no_reg;
189 offset_ = offset;
190 am_ = am;
191}
192
193MemOperand::MemOperand(Register rn, Register rm, AddrMode am) {
194 rn_ = rn;
195 rm_ = rm;
196 shift_op_ = LSL;
197 shift_imm_ = 0;
198 am_ = am;
199}
200
201
202MemOperand::MemOperand(Register rn, Register rm,
203 ShiftOp shift_op, int shift_imm, AddrMode am) {
204 ASSERT(is_uint5(shift_imm));
205 rn_ = rn;
206 rm_ = rm;
207 shift_op_ = shift_op;
208 shift_imm_ = shift_imm & 31;
209 am_ = am;
210}
211
212
213// -----------------------------------------------------------------------------
ager@chromium.org5c838252010-02-19 08:53:10 +0000214// Implementation of Assembler.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000215
ager@chromium.org5c838252010-02-19 08:53:10 +0000216// Instruction encoding bits.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000217enum {
218 H = 1 << 5, // halfword (or byte)
219 S6 = 1 << 6, // signed (or unsigned)
220 L = 1 << 20, // load (or store)
221 S = 1 << 20, // set condition code (or leave unchanged)
222 W = 1 << 21, // writeback base register (or leave unchanged)
223 A = 1 << 21, // accumulate in multiply instruction (or not)
224 B = 1 << 22, // unsigned byte (or word)
225 N = 1 << 22, // long (or short)
226 U = 1 << 23, // positive (or negative) offset/index
227 P = 1 << 24, // offset/pre-indexed addressing (or post-indexed addressing)
228 I = 1 << 25, // immediate shifter operand (or not)
229
230 B4 = 1 << 4,
231 B5 = 1 << 5,
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000232 B6 = 1 << 6,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000233 B7 = 1 << 7,
234 B8 = 1 << 8,
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000235 B9 = 1 << 9,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000236 B12 = 1 << 12,
237 B16 = 1 << 16,
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000238 B18 = 1 << 18,
239 B19 = 1 << 19,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000240 B20 = 1 << 20,
241 B21 = 1 << 21,
242 B22 = 1 << 22,
243 B23 = 1 << 23,
244 B24 = 1 << 24,
245 B25 = 1 << 25,
246 B26 = 1 << 26,
247 B27 = 1 << 27,
248
ager@chromium.org5c838252010-02-19 08:53:10 +0000249 // Instruction bit masks.
mads.s.ager31e71382008-08-13 09:32:07 +0000250 RdMask = 15 << 12, // in str instruction
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000251 CondMask = 15 << 28,
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000252 CoprocessorMask = 15 << 8,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000253 OpCodeMask = 15 << 21, // in data-processing instructions
254 Imm24Mask = (1 << 24) - 1,
255 Off12Mask = (1 << 12) - 1,
ager@chromium.org5c838252010-02-19 08:53:10 +0000256 // Reserved condition.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000257 nv = 15 << 28
258};
259
260
mads.s.ager31e71382008-08-13 09:32:07 +0000261// add(sp, sp, 4) instruction (aka Pop())
262static const Instr kPopInstruction =
263 al | 4 * B21 | 4 | LeaveCC | I | sp.code() * B16 | sp.code() * B12;
264// str(r, MemOperand(sp, 4, NegPreIndex), al) instruction (aka push(r))
265// register r is not encoded.
266static const Instr kPushRegPattern =
267 al | B26 | 4 | NegPreIndex | sp.code() * B16;
268// ldr(r, MemOperand(sp, 4, PostIndex), al) instruction (aka pop(r))
269// register r is not encoded.
270static const Instr kPopRegPattern =
271 al | B26 | L | 4 | PostIndex | sp.code() * B16;
ager@chromium.org4af710e2009-09-15 12:20:11 +0000272// mov lr, pc
273const Instr kMovLrPc = al | 13*B21 | pc.code() | lr.code() * B12;
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000274// ldr rd, [pc, #offset]
275const Instr kLdrPCMask = CondMask | 15 * B24 | 7 * B20 | 15 * B16;
276const Instr kLdrPCPattern = al | 5 * B24 | L | pc.code() * B16;
277// blxcc rm
278const Instr kBlxRegMask =
279 15 * B24 | 15 * B20 | 15 * B16 | 15 * B12 | 15 * B8 | 15 * B4;
280const Instr kBlxRegPattern =
281 B24 | B21 | 15 * B16 | 15 * B12 | 15 * B8 | 3 * B4;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000282const Instr kMovMvnMask = 0x6d * B21 | 0xf * B16;
283const Instr kMovMvnPattern = 0xd * B21;
284const Instr kMovMvnFlip = B22;
285const Instr kCmpCmnMask = 0xdd * B20 | 0xf * B12;
286const Instr kCmpCmnPattern = 0x15 * B20;
287const Instr kCmpCmnFlip = B21;
288const Instr kALUMask = 0x6f * B21;
289const Instr kAddPattern = 0x4 * B21;
290const Instr kSubPattern = 0x2 * B21;
291const Instr kBicPattern = 0xe * B21;
292const Instr kAndPattern = 0x0 * B21;
293const Instr kAddSubFlip = 0x6 * B21;
294const Instr kAndBicFlip = 0xe * B21;
295
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000296// A mask for the Rd register for push, pop, ldr, str instructions.
297const Instr kRdMask = 0x0000f000;
298static const int kRdShift = 12;
299static const Instr kLdrRegFpOffsetPattern =
300 al | B26 | L | Offset | fp.code() * B16;
301static const Instr kStrRegFpOffsetPattern =
302 al | B26 | Offset | fp.code() * B16;
303static const Instr kLdrRegFpNegOffsetPattern =
304 al | B26 | L | NegOffset | fp.code() * B16;
305static const Instr kStrRegFpNegOffsetPattern =
306 al | B26 | NegOffset | fp.code() * B16;
307static const Instr kLdrStrInstrTypeMask = 0xffff0000;
308static const Instr kLdrStrInstrArgumentMask = 0x0000ffff;
309static const Instr kLdrStrOffsetMask = 0x00000fff;
mads.s.ager31e71382008-08-13 09:32:07 +0000310
ager@chromium.org5c838252010-02-19 08:53:10 +0000311// Spare buffer.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000312static const int kMinimalBufferSize = 4*KB;
313static byte* spare_buffer_ = NULL;
314
315Assembler::Assembler(void* buffer, int buffer_size) {
316 if (buffer == NULL) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000317 // Do our own buffer management.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000318 if (buffer_size <= kMinimalBufferSize) {
319 buffer_size = kMinimalBufferSize;
320
321 if (spare_buffer_ != NULL) {
322 buffer = spare_buffer_;
323 spare_buffer_ = NULL;
324 }
325 }
326 if (buffer == NULL) {
327 buffer_ = NewArray<byte>(buffer_size);
328 } else {
329 buffer_ = static_cast<byte*>(buffer);
330 }
331 buffer_size_ = buffer_size;
332 own_buffer_ = true;
333
334 } else {
ager@chromium.org5c838252010-02-19 08:53:10 +0000335 // Use externally provided buffer instead.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000336 ASSERT(buffer_size > 0);
337 buffer_ = static_cast<byte*>(buffer);
338 buffer_size_ = buffer_size;
339 own_buffer_ = false;
340 }
341
ager@chromium.org5c838252010-02-19 08:53:10 +0000342 // Setup buffer pointers.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000343 ASSERT(buffer_ != NULL);
344 pc_ = buffer_;
345 reloc_info_writer.Reposition(buffer_ + buffer_size, pc_);
346 num_prinfo_ = 0;
347 next_buffer_check_ = 0;
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000348 const_pool_blocked_nesting_ = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000349 no_const_pool_before_ = 0;
350 last_const_pool_end_ = 0;
351 last_bound_pos_ = 0;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000352 current_statement_position_ = RelocInfo::kNoPosition;
353 current_position_ = RelocInfo::kNoPosition;
354 written_statement_position_ = current_statement_position_;
355 written_position_ = current_position_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000356}
357
358
359Assembler::~Assembler() {
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000360 ASSERT(const_pool_blocked_nesting_ == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000361 if (own_buffer_) {
362 if (spare_buffer_ == NULL && buffer_size_ == kMinimalBufferSize) {
363 spare_buffer_ = buffer_;
364 } else {
365 DeleteArray(buffer_);
366 }
367 }
368}
369
370
371void Assembler::GetCode(CodeDesc* desc) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000372 // Emit constant pool if necessary.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000373 CheckConstPool(true, false);
374 ASSERT(num_prinfo_ == 0);
375
ager@chromium.org5c838252010-02-19 08:53:10 +0000376 // Setup code descriptor.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000377 desc->buffer = buffer_;
378 desc->buffer_size = buffer_size_;
379 desc->instr_size = pc_offset();
380 desc->reloc_size = (buffer_ + buffer_size_) - reloc_info_writer.pos();
381}
382
383
384void Assembler::Align(int m) {
385 ASSERT(m >= 4 && IsPowerOf2(m));
386 while ((pc_offset() & (m - 1)) != 0) {
387 nop();
388 }
389}
390
391
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000392bool Assembler::IsNop(Instr instr, int type) {
393 // Check for mov rx, rx.
394 ASSERT(0 <= type && type <= 14); // mov pc, pc is not a nop.
395 return instr == (al | 13*B21 | type*B12 | type);
396}
397
398
399bool Assembler::IsBranch(Instr instr) {
400 return (instr & (B27 | B25)) == (B27 | B25);
401}
402
403
404int Assembler::GetBranchOffset(Instr instr) {
405 ASSERT(IsBranch(instr));
406 // Take the jump offset in the lower 24 bits, sign extend it and multiply it
407 // with 4 to get the offset in bytes.
408 return ((instr & Imm24Mask) << 8) >> 6;
409}
410
411
412bool Assembler::IsLdrRegisterImmediate(Instr instr) {
413 return (instr & (B27 | B26 | B25 | B22 | B20)) == (B26 | B20);
414}
415
416
417int Assembler::GetLdrRegisterImmediateOffset(Instr instr) {
418 ASSERT(IsLdrRegisterImmediate(instr));
419 bool positive = (instr & B23) == B23;
420 int offset = instr & Off12Mask; // Zero extended offset.
421 return positive ? offset : -offset;
422}
423
424
425Instr Assembler::SetLdrRegisterImmediateOffset(Instr instr, int offset) {
426 ASSERT(IsLdrRegisterImmediate(instr));
427 bool positive = offset >= 0;
428 if (!positive) offset = -offset;
429 ASSERT(is_uint12(offset));
430 // Set bit indicating whether the offset should be added.
431 instr = (instr & ~B23) | (positive ? B23 : 0);
432 // Set the actual offset.
433 return (instr & ~Off12Mask) | offset;
434}
435
436
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000437Register Assembler::GetRd(Instr instr) {
438 Register reg;
439 reg.code_ = ((instr & kRdMask) >> kRdShift);
440 return reg;
441}
442
443
444bool Assembler::IsPush(Instr instr) {
445 return ((instr & ~kRdMask) == kPushRegPattern);
446}
447
448
449bool Assembler::IsPop(Instr instr) {
450 return ((instr & ~kRdMask) == kPopRegPattern);
451}
452
453
454bool Assembler::IsStrRegFpOffset(Instr instr) {
455 return ((instr & kLdrStrInstrTypeMask) == kStrRegFpOffsetPattern);
456}
457
458
459bool Assembler::IsLdrRegFpOffset(Instr instr) {
460 return ((instr & kLdrStrInstrTypeMask) == kLdrRegFpOffsetPattern);
461}
462
463
464bool Assembler::IsStrRegFpNegOffset(Instr instr) {
465 return ((instr & kLdrStrInstrTypeMask) == kStrRegFpNegOffsetPattern);
466}
467
468
469bool Assembler::IsLdrRegFpNegOffset(Instr instr) {
470 return ((instr & kLdrStrInstrTypeMask) == kLdrRegFpNegOffsetPattern);
471}
472
473
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000474// Labels refer to positions in the (to be) generated code.
475// There are bound, linked, and unused labels.
476//
477// Bound labels refer to known positions in the already
478// generated code. pos() is the position the label refers to.
479//
480// Linked labels refer to unknown positions in the code
481// to be generated; pos() is the position of the last
482// instruction using the label.
483
484
485// The link chain is terminated by a negative code position (must be aligned)
486const int kEndOfChain = -4;
487
488
489int Assembler::target_at(int pos) {
490 Instr instr = instr_at(pos);
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000491 if ((instr & ~Imm24Mask) == 0) {
492 // Emitted label constant, not part of a branch.
493 return instr - (Code::kHeaderSize - kHeapObjectTag);
494 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000495 ASSERT((instr & 7*B25) == 5*B25); // b, bl, or blx imm24
496 int imm26 = ((instr & Imm24Mask) << 8) >> 6;
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000497 if ((instr & CondMask) == nv && (instr & B24) != 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000498 // blx uses bit 24 to encode bit 2 of imm26
499 imm26 += 2;
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000500 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000501 return pos + kPcLoadDelta + imm26;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000502}
503
504
505void Assembler::target_at_put(int pos, int target_pos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000506 Instr instr = instr_at(pos);
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000507 if ((instr & ~Imm24Mask) == 0) {
508 ASSERT(target_pos == kEndOfChain || target_pos >= 0);
509 // Emitted label constant, not part of a branch.
510 // Make label relative to Code* of generated Code object.
511 instr_at_put(pos, target_pos + (Code::kHeaderSize - kHeapObjectTag));
512 return;
513 }
514 int imm26 = target_pos - (pos + kPcLoadDelta);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000515 ASSERT((instr & 7*B25) == 5*B25); // b, bl, or blx imm24
516 if ((instr & CondMask) == nv) {
517 // blx uses bit 24 to encode bit 2 of imm26
518 ASSERT((imm26 & 1) == 0);
519 instr = (instr & ~(B24 | Imm24Mask)) | ((imm26 & 2) >> 1)*B24;
520 } else {
521 ASSERT((imm26 & 3) == 0);
522 instr &= ~Imm24Mask;
523 }
524 int imm24 = imm26 >> 2;
525 ASSERT(is_int24(imm24));
526 instr_at_put(pos, instr | (imm24 & Imm24Mask));
527}
528
529
530void Assembler::print(Label* L) {
531 if (L->is_unused()) {
532 PrintF("unused label\n");
533 } else if (L->is_bound()) {
534 PrintF("bound label to %d\n", L->pos());
535 } else if (L->is_linked()) {
536 Label l = *L;
537 PrintF("unbound label");
538 while (l.is_linked()) {
539 PrintF("@ %d ", l.pos());
540 Instr instr = instr_at(l.pos());
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000541 if ((instr & ~Imm24Mask) == 0) {
542 PrintF("value\n");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000543 } else {
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000544 ASSERT((instr & 7*B25) == 5*B25); // b, bl, or blx
545 int cond = instr & CondMask;
546 const char* b;
547 const char* c;
548 if (cond == nv) {
549 b = "blx";
550 c = "";
551 } else {
552 if ((instr & B24) != 0)
553 b = "bl";
554 else
555 b = "b";
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000556
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000557 switch (cond) {
558 case eq: c = "eq"; break;
559 case ne: c = "ne"; break;
560 case hs: c = "hs"; break;
561 case lo: c = "lo"; break;
562 case mi: c = "mi"; break;
563 case pl: c = "pl"; break;
564 case vs: c = "vs"; break;
565 case vc: c = "vc"; break;
566 case hi: c = "hi"; break;
567 case ls: c = "ls"; break;
568 case ge: c = "ge"; break;
569 case lt: c = "lt"; break;
570 case gt: c = "gt"; break;
571 case le: c = "le"; break;
572 case al: c = ""; break;
573 default:
574 c = "";
575 UNREACHABLE();
576 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000577 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000578 PrintF("%s%s\n", b, c);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000579 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000580 next(&l);
581 }
582 } else {
583 PrintF("label in inconsistent state (pos = %d)\n", L->pos_);
584 }
585}
586
587
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000588void Assembler::bind_to(Label* L, int pos) {
589 ASSERT(0 <= pos && pos <= pc_offset()); // must have a valid binding position
590 while (L->is_linked()) {
591 int fixup_pos = L->pos();
592 next(L); // call next before overwriting link with target at fixup_pos
593 target_at_put(fixup_pos, pos);
594 }
595 L->bind_to(pos);
596
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000597 // Keep track of the last bound label so we don't eliminate any instructions
598 // before a bound label.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000599 if (pos > last_bound_pos_)
600 last_bound_pos_ = pos;
601}
602
603
604void Assembler::link_to(Label* L, Label* appendix) {
605 if (appendix->is_linked()) {
606 if (L->is_linked()) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000607 // Append appendix to L's list.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000608 int fixup_pos;
609 int link = L->pos();
610 do {
611 fixup_pos = link;
612 link = target_at(fixup_pos);
613 } while (link > 0);
614 ASSERT(link == kEndOfChain);
615 target_at_put(fixup_pos, appendix->pos());
616 } else {
ager@chromium.org5c838252010-02-19 08:53:10 +0000617 // L is empty, simply use appendix.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000618 *L = *appendix;
619 }
620 }
621 appendix->Unuse(); // appendix should not be used anymore
622}
623
624
625void Assembler::bind(Label* L) {
626 ASSERT(!L->is_bound()); // label can only be bound once
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000627 bind_to(L, pc_offset());
628}
629
630
631void Assembler::next(Label* L) {
632 ASSERT(L->is_linked());
633 int link = target_at(L->pos());
634 if (link > 0) {
635 L->link_to(link);
636 } else {
637 ASSERT(link == kEndOfChain);
638 L->Unuse();
639 }
640}
641
642
ager@chromium.org5c838252010-02-19 08:53:10 +0000643// Low-level code emission routines depending on the addressing mode.
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000644// If this returns true then you have to use the rotate_imm and immed_8
645// that it returns, because it may have already changed the instruction
646// to match them!
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000647static bool fits_shifter(uint32_t imm32,
648 uint32_t* rotate_imm,
649 uint32_t* immed_8,
650 Instr* instr) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000651 // imm32 must be unsigned.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000652 for (int rot = 0; rot < 16; rot++) {
653 uint32_t imm8 = (imm32 << 2*rot) | (imm32 >> (32 - 2*rot));
654 if ((imm8 <= 0xff)) {
655 *rotate_imm = rot;
656 *immed_8 = imm8;
657 return true;
658 }
659 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000660 // If the opcode is one with a complementary version and the complementary
661 // immediate fits, change the opcode.
662 if (instr != NULL) {
663 if ((*instr & kMovMvnMask) == kMovMvnPattern) {
664 if (fits_shifter(~imm32, rotate_imm, immed_8, NULL)) {
665 *instr ^= kMovMvnFlip;
666 return true;
667 }
668 } else if ((*instr & kCmpCmnMask) == kCmpCmnPattern) {
669 if (fits_shifter(-imm32, rotate_imm, immed_8, NULL)) {
670 *instr ^= kCmpCmnFlip;
671 return true;
672 }
673 } else {
674 Instr alu_insn = (*instr & kALUMask);
675 if (alu_insn == kAddPattern ||
676 alu_insn == kSubPattern) {
677 if (fits_shifter(-imm32, rotate_imm, immed_8, NULL)) {
678 *instr ^= kAddSubFlip;
679 return true;
680 }
681 } else if (alu_insn == kAndPattern ||
682 alu_insn == kBicPattern) {
683 if (fits_shifter(~imm32, rotate_imm, immed_8, NULL)) {
684 *instr ^= kAndBicFlip;
685 return true;
686 }
687 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000688 }
689 }
690 return false;
691}
692
693
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000694// We have to use the temporary register for things that can be relocated even
695// if they can be encoded in the ARM's 12 bits of immediate-offset instruction
696// space. There is no guarantee that the relocated location can be similarly
697// encoded.
698static bool MustUseIp(RelocInfo::Mode rmode) {
699 if (rmode == RelocInfo::EXTERNAL_REFERENCE) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000700#ifdef DEBUG
701 if (!Serializer::enabled()) {
702 Serializer::TooLateToEnableNow();
703 }
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000704#endif // def DEBUG
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000705 return Serializer::enabled();
706 } else if (rmode == RelocInfo::NONE) {
707 return false;
708 }
709 return true;
710}
711
712
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000713bool Operand::is_single_instruction() const {
714 if (rm_.is_valid()) return true;
715 if (MustUseIp(rmode_)) return false;
716 uint32_t dummy1, dummy2;
717 return fits_shifter(imm32_, &dummy1, &dummy2, NULL);
718}
719
720
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000721void Assembler::addrmod1(Instr instr,
722 Register rn,
723 Register rd,
724 const Operand& x) {
725 CheckBuffer();
726 ASSERT((instr & ~(CondMask | OpCodeMask | S)) == 0);
727 if (!x.rm_.is_valid()) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000728 // Immediate.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000729 uint32_t rotate_imm;
730 uint32_t immed_8;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000731 if (MustUseIp(x.rmode_) ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000732 !fits_shifter(x.imm32_, &rotate_imm, &immed_8, &instr)) {
733 // The immediate operand cannot be encoded as a shifter operand, so load
734 // it first to register ip and change the original instruction to use ip.
735 // However, if the original instruction is a 'mov rd, x' (not setting the
ager@chromium.org5c838252010-02-19 08:53:10 +0000736 // condition code), then replace it with a 'ldr rd, [pc]'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000737 RecordRelocInfo(x.rmode_, x.imm32_);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000738 CHECK(!rn.is(ip)); // rn should never be ip, or will be trashed
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000739 Condition cond = static_cast<Condition>(instr & CondMask);
740 if ((instr & ~CondMask) == 13*B21) { // mov, S not set
741 ldr(rd, MemOperand(pc, 0), cond);
742 } else {
743 ldr(ip, MemOperand(pc, 0), cond);
744 addrmod1(instr, rn, rd, Operand(ip));
745 }
746 return;
747 }
748 instr |= I | rotate_imm*B8 | immed_8;
749 } else if (!x.rs_.is_valid()) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000750 // Immediate shift.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000751 instr |= x.shift_imm_*B7 | x.shift_op_ | x.rm_.code();
752 } else {
ager@chromium.org5c838252010-02-19 08:53:10 +0000753 // Register shift.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000754 ASSERT(!rn.is(pc) && !rd.is(pc) && !x.rm_.is(pc) && !x.rs_.is(pc));
755 instr |= x.rs_.code()*B8 | x.shift_op_ | B4 | x.rm_.code();
756 }
757 emit(instr | rn.code()*B16 | rd.code()*B12);
758 if (rn.is(pc) || x.rm_.is(pc))
ager@chromium.org5c838252010-02-19 08:53:10 +0000759 // Block constant pool emission for one instruction after reading pc.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000760 BlockConstPoolBefore(pc_offset() + kInstrSize);
761}
762
763
764void Assembler::addrmod2(Instr instr, Register rd, const MemOperand& x) {
765 ASSERT((instr & ~(CondMask | B | L)) == B26);
766 int am = x.am_;
767 if (!x.rm_.is_valid()) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000768 // Immediate offset.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000769 int offset_12 = x.offset_;
770 if (offset_12 < 0) {
771 offset_12 = -offset_12;
772 am ^= U;
773 }
774 if (!is_uint12(offset_12)) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000775 // Immediate offset cannot be encoded, load it first to register ip
776 // rn (and rd in a load) should never be ip, or will be trashed.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000777 ASSERT(!x.rn_.is(ip) && ((instr & L) == L || !rd.is(ip)));
778 mov(ip, Operand(x.offset_), LeaveCC,
779 static_cast<Condition>(instr & CondMask));
780 addrmod2(instr, rd, MemOperand(x.rn_, ip, x.am_));
781 return;
782 }
783 ASSERT(offset_12 >= 0); // no masking needed
784 instr |= offset_12;
785 } else {
ager@chromium.org5c838252010-02-19 08:53:10 +0000786 // Register offset (shift_imm_ and shift_op_ are 0) or scaled
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000787 // register offset the constructors make sure than both shift_imm_
ager@chromium.org5c838252010-02-19 08:53:10 +0000788 // and shift_op_ are initialized.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000789 ASSERT(!x.rm_.is(pc));
790 instr |= B25 | x.shift_imm_*B7 | x.shift_op_ | x.rm_.code();
791 }
792 ASSERT((am & (P|W)) == P || !x.rn_.is(pc)); // no pc base with writeback
793 emit(instr | am | x.rn_.code()*B16 | rd.code()*B12);
794}
795
796
797void Assembler::addrmod3(Instr instr, Register rd, const MemOperand& x) {
798 ASSERT((instr & ~(CondMask | L | S6 | H)) == (B4 | B7));
799 ASSERT(x.rn_.is_valid());
800 int am = x.am_;
801 if (!x.rm_.is_valid()) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000802 // Immediate offset.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000803 int offset_8 = x.offset_;
804 if (offset_8 < 0) {
805 offset_8 = -offset_8;
806 am ^= U;
807 }
808 if (!is_uint8(offset_8)) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000809 // Immediate offset cannot be encoded, load it first to register ip
810 // rn (and rd in a load) should never be ip, or will be trashed.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000811 ASSERT(!x.rn_.is(ip) && ((instr & L) == L || !rd.is(ip)));
812 mov(ip, Operand(x.offset_), LeaveCC,
813 static_cast<Condition>(instr & CondMask));
814 addrmod3(instr, rd, MemOperand(x.rn_, ip, x.am_));
815 return;
816 }
817 ASSERT(offset_8 >= 0); // no masking needed
818 instr |= B | (offset_8 >> 4)*B8 | (offset_8 & 0xf);
819 } else if (x.shift_imm_ != 0) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000820 // Scaled register offset not supported, load index first
821 // rn (and rd in a load) should never be ip, or will be trashed.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000822 ASSERT(!x.rn_.is(ip) && ((instr & L) == L || !rd.is(ip)));
823 mov(ip, Operand(x.rm_, x.shift_op_, x.shift_imm_), LeaveCC,
824 static_cast<Condition>(instr & CondMask));
825 addrmod3(instr, rd, MemOperand(x.rn_, ip, x.am_));
826 return;
827 } else {
ager@chromium.org5c838252010-02-19 08:53:10 +0000828 // Register offset.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000829 ASSERT((am & (P|W)) == P || !x.rm_.is(pc)); // no pc index with writeback
830 instr |= x.rm_.code();
831 }
832 ASSERT((am & (P|W)) == P || !x.rn_.is(pc)); // no pc base with writeback
833 emit(instr | am | x.rn_.code()*B16 | rd.code()*B12);
834}
835
836
837void Assembler::addrmod4(Instr instr, Register rn, RegList rl) {
838 ASSERT((instr & ~(CondMask | P | U | W | L)) == B27);
839 ASSERT(rl != 0);
840 ASSERT(!rn.is(pc));
841 emit(instr | rn.code()*B16 | rl);
842}
843
844
845void Assembler::addrmod5(Instr instr, CRegister crd, const MemOperand& x) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000846 // Unindexed addressing is not encoded by this function.
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000847 ASSERT_EQ((B27 | B26),
848 (instr & ~(CondMask | CoprocessorMask | P | U | N | W | L)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000849 ASSERT(x.rn_.is_valid() && !x.rm_.is_valid());
850 int am = x.am_;
851 int offset_8 = x.offset_;
852 ASSERT((offset_8 & 3) == 0); // offset must be an aligned word offset
853 offset_8 >>= 2;
854 if (offset_8 < 0) {
855 offset_8 = -offset_8;
856 am ^= U;
857 }
858 ASSERT(is_uint8(offset_8)); // unsigned word offset must fit in a byte
859 ASSERT((am & (P|W)) == P || !x.rn_.is(pc)); // no pc base with writeback
860
ager@chromium.org5c838252010-02-19 08:53:10 +0000861 // Post-indexed addressing requires W == 1; different than in addrmod2/3.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000862 if ((am & P) == 0)
863 am |= W;
864
865 ASSERT(offset_8 >= 0); // no masking needed
866 emit(instr | am | x.rn_.code()*B16 | crd.code()*B12 | offset_8);
867}
868
869
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +0000870int Assembler::branch_offset(Label* L, bool jump_elimination_allowed) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000871 int target_pos;
872 if (L->is_bound()) {
873 target_pos = L->pos();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000874 } else {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000875 if (L->is_linked()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000876 target_pos = L->pos(); // L's link
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000877 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000878 target_pos = kEndOfChain;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000879 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000880 L->link_to(pc_offset());
881 }
882
883 // Block the emission of the constant pool, since the branch instruction must
ager@chromium.org5c838252010-02-19 08:53:10 +0000884 // be emitted at the pc offset recorded by the label.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000885 BlockConstPoolBefore(pc_offset() + kInstrSize);
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000886 return target_pos - (pc_offset() + kPcLoadDelta);
887}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000888
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000889
890void Assembler::label_at_put(Label* L, int at_offset) {
891 int target_pos;
892 if (L->is_bound()) {
893 target_pos = L->pos();
894 } else {
895 if (L->is_linked()) {
896 target_pos = L->pos(); // L's link
897 } else {
898 target_pos = kEndOfChain;
899 }
900 L->link_to(at_offset);
901 instr_at_put(at_offset, target_pos + (Code::kHeaderSize - kHeapObjectTag));
902 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000903}
904
905
ager@chromium.org5c838252010-02-19 08:53:10 +0000906// Branch instructions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000907void Assembler::b(int branch_offset, Condition cond) {
908 ASSERT((branch_offset & 3) == 0);
909 int imm24 = branch_offset >> 2;
910 ASSERT(is_int24(imm24));
911 emit(cond | B27 | B25 | (imm24 & Imm24Mask));
912
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000913 if (cond == al) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000914 // Dead code is a good location to emit the constant pool.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000915 CheckConstPool(false, false);
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000916 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000917}
918
919
920void Assembler::bl(int branch_offset, Condition cond) {
921 ASSERT((branch_offset & 3) == 0);
922 int imm24 = branch_offset >> 2;
923 ASSERT(is_int24(imm24));
924 emit(cond | B27 | B25 | B24 | (imm24 & Imm24Mask));
925}
926
927
928void Assembler::blx(int branch_offset) { // v5 and above
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000929 WriteRecordedPositions();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000930 ASSERT((branch_offset & 1) == 0);
931 int h = ((branch_offset & 2) >> 1)*B24;
932 int imm24 = branch_offset >> 2;
933 ASSERT(is_int24(imm24));
934 emit(15 << 28 | B27 | B25 | h | (imm24 & Imm24Mask));
935}
936
937
938void Assembler::blx(Register target, Condition cond) { // v5 and above
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000939 WriteRecordedPositions();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000940 ASSERT(!target.is(pc));
941 emit(cond | B24 | B21 | 15*B16 | 15*B12 | 15*B8 | 3*B4 | target.code());
942}
943
944
945void Assembler::bx(Register target, Condition cond) { // v5 and above, plus v4t
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000946 WriteRecordedPositions();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000947 ASSERT(!target.is(pc)); // use of pc is actually allowed, but discouraged
948 emit(cond | B24 | B21 | 15*B16 | 15*B12 | 15*B8 | B4 | target.code());
949}
950
951
ager@chromium.org5c838252010-02-19 08:53:10 +0000952// Data-processing instructions.
953
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000954void Assembler::and_(Register dst, Register src1, const Operand& src2,
955 SBit s, Condition cond) {
956 addrmod1(cond | 0*B21 | s, src1, dst, src2);
957}
958
959
960void Assembler::eor(Register dst, Register src1, const Operand& src2,
961 SBit s, Condition cond) {
962 addrmod1(cond | 1*B21 | s, src1, dst, src2);
963}
964
965
966void Assembler::sub(Register dst, Register src1, const Operand& src2,
967 SBit s, Condition cond) {
968 addrmod1(cond | 2*B21 | s, src1, dst, src2);
969}
970
971
972void Assembler::rsb(Register dst, Register src1, const Operand& src2,
973 SBit s, Condition cond) {
974 addrmod1(cond | 3*B21 | s, src1, dst, src2);
975}
976
977
978void Assembler::add(Register dst, Register src1, const Operand& src2,
979 SBit s, Condition cond) {
980 addrmod1(cond | 4*B21 | s, src1, dst, src2);
mads.s.ager31e71382008-08-13 09:32:07 +0000981
982 // Eliminate pattern: push(r), pop()
983 // str(src, MemOperand(sp, 4, NegPreIndex), al);
984 // add(sp, sp, Operand(kPointerSize));
985 // Both instructions can be eliminated.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000986 if (can_peephole_optimize(2) &&
ager@chromium.org5c838252010-02-19 08:53:10 +0000987 // Pattern.
mads.s.ager31e71382008-08-13 09:32:07 +0000988 instr_at(pc_ - 1 * kInstrSize) == kPopInstruction &&
989 (instr_at(pc_ - 2 * kInstrSize) & ~RdMask) == kPushRegPattern) {
990 pc_ -= 2 * kInstrSize;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000991 if (FLAG_print_peephole_optimization) {
mads.s.ager31e71382008-08-13 09:32:07 +0000992 PrintF("%x push(reg)/pop() eliminated\n", pc_offset());
993 }
994 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000995}
996
997
998void Assembler::adc(Register dst, Register src1, const Operand& src2,
999 SBit s, Condition cond) {
1000 addrmod1(cond | 5*B21 | s, src1, dst, src2);
1001}
1002
1003
1004void Assembler::sbc(Register dst, Register src1, const Operand& src2,
1005 SBit s, Condition cond) {
1006 addrmod1(cond | 6*B21 | s, src1, dst, src2);
1007}
1008
1009
1010void Assembler::rsc(Register dst, Register src1, const Operand& src2,
1011 SBit s, Condition cond) {
1012 addrmod1(cond | 7*B21 | s, src1, dst, src2);
1013}
1014
1015
1016void Assembler::tst(Register src1, const Operand& src2, Condition cond) {
1017 addrmod1(cond | 8*B21 | S, src1, r0, src2);
1018}
1019
1020
1021void Assembler::teq(Register src1, const Operand& src2, Condition cond) {
1022 addrmod1(cond | 9*B21 | S, src1, r0, src2);
1023}
1024
1025
1026void Assembler::cmp(Register src1, const Operand& src2, Condition cond) {
1027 addrmod1(cond | 10*B21 | S, src1, r0, src2);
1028}
1029
1030
1031void Assembler::cmn(Register src1, const Operand& src2, Condition cond) {
1032 addrmod1(cond | 11*B21 | S, src1, r0, src2);
1033}
1034
1035
1036void Assembler::orr(Register dst, Register src1, const Operand& src2,
1037 SBit s, Condition cond) {
1038 addrmod1(cond | 12*B21 | s, src1, dst, src2);
1039}
1040
1041
1042void Assembler::mov(Register dst, const Operand& src, SBit s, Condition cond) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001043 if (dst.is(pc)) {
1044 WriteRecordedPositions();
1045 }
fschneider@chromium.org013f3e12010-04-26 13:27:52 +00001046 // Don't allow nop instructions in the form mov rn, rn to be generated using
1047 // the mov instruction. They must be generated using nop(int)
1048 // pseudo instructions.
1049 ASSERT(!(src.is_reg() && src.rm().is(dst) && s == LeaveCC && cond == al));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001050 addrmod1(cond | 13*B21 | s, r0, dst, src);
1051}
1052
1053
1054void Assembler::bic(Register dst, Register src1, const Operand& src2,
1055 SBit s, Condition cond) {
1056 addrmod1(cond | 14*B21 | s, src1, dst, src2);
1057}
1058
1059
1060void Assembler::mvn(Register dst, const Operand& src, SBit s, Condition cond) {
1061 addrmod1(cond | 15*B21 | s, r0, dst, src);
1062}
1063
1064
ager@chromium.org5c838252010-02-19 08:53:10 +00001065// Multiply instructions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001066void Assembler::mla(Register dst, Register src1, Register src2, Register srcA,
1067 SBit s, Condition cond) {
1068 ASSERT(!dst.is(pc) && !src1.is(pc) && !src2.is(pc) && !srcA.is(pc));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001069 emit(cond | A | s | dst.code()*B16 | srcA.code()*B12 |
1070 src2.code()*B8 | B7 | B4 | src1.code());
1071}
1072
1073
1074void Assembler::mul(Register dst, Register src1, Register src2,
1075 SBit s, Condition cond) {
1076 ASSERT(!dst.is(pc) && !src1.is(pc) && !src2.is(pc));
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00001077 // dst goes in bits 16-19 for this instruction!
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001078 emit(cond | s | dst.code()*B16 | src2.code()*B8 | B7 | B4 | src1.code());
1079}
1080
1081
1082void Assembler::smlal(Register dstL,
1083 Register dstH,
1084 Register src1,
1085 Register src2,
1086 SBit s,
1087 Condition cond) {
1088 ASSERT(!dstL.is(pc) && !dstH.is(pc) && !src1.is(pc) && !src2.is(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001089 ASSERT(!dstL.is(dstH));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001090 emit(cond | B23 | B22 | A | s | dstH.code()*B16 | dstL.code()*B12 |
1091 src2.code()*B8 | B7 | B4 | src1.code());
1092}
1093
1094
1095void Assembler::smull(Register dstL,
1096 Register dstH,
1097 Register src1,
1098 Register src2,
1099 SBit s,
1100 Condition cond) {
1101 ASSERT(!dstL.is(pc) && !dstH.is(pc) && !src1.is(pc) && !src2.is(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001102 ASSERT(!dstL.is(dstH));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001103 emit(cond | B23 | B22 | s | dstH.code()*B16 | dstL.code()*B12 |
1104 src2.code()*B8 | B7 | B4 | src1.code());
1105}
1106
1107
1108void Assembler::umlal(Register dstL,
1109 Register dstH,
1110 Register src1,
1111 Register src2,
1112 SBit s,
1113 Condition cond) {
1114 ASSERT(!dstL.is(pc) && !dstH.is(pc) && !src1.is(pc) && !src2.is(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001115 ASSERT(!dstL.is(dstH));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001116 emit(cond | B23 | A | s | dstH.code()*B16 | dstL.code()*B12 |
1117 src2.code()*B8 | B7 | B4 | src1.code());
1118}
1119
1120
1121void Assembler::umull(Register dstL,
1122 Register dstH,
1123 Register src1,
1124 Register src2,
1125 SBit s,
1126 Condition cond) {
1127 ASSERT(!dstL.is(pc) && !dstH.is(pc) && !src1.is(pc) && !src2.is(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001128 ASSERT(!dstL.is(dstH));
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00001129 emit(cond | B23 | s | dstH.code()*B16 | dstL.code()*B12 |
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001130 src2.code()*B8 | B7 | B4 | src1.code());
1131}
1132
1133
ager@chromium.org5c838252010-02-19 08:53:10 +00001134// Miscellaneous arithmetic instructions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001135void Assembler::clz(Register dst, Register src, Condition cond) {
1136 // v5 and above.
1137 ASSERT(!dst.is(pc) && !src.is(pc));
1138 emit(cond | B24 | B22 | B21 | 15*B16 | dst.code()*B12 |
1139 15*B8 | B4 | src.code());
1140}
1141
1142
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001143// Bitfield manipulation instructions.
1144
1145// Unsigned bit field extract.
1146// Extracts #width adjacent bits from position #lsb in a register, and
1147// writes them to the low bits of a destination register.
1148// ubfx dst, src, #lsb, #width
1149void Assembler::ubfx(Register dst,
1150 Register src,
1151 int lsb,
1152 int width,
1153 Condition cond) {
1154 // v7 and above.
1155 ASSERT(CpuFeatures::IsSupported(ARMv7));
1156 ASSERT(!dst.is(pc) && !src.is(pc));
1157 ASSERT((lsb >= 0) && (lsb <= 31));
1158 ASSERT((width >= 1) && (width <= (32 - lsb)));
1159 emit(cond | 0xf*B23 | B22 | B21 | (width - 1)*B16 | dst.code()*B12 |
1160 lsb*B7 | B6 | B4 | src.code());
1161}
1162
1163
1164// Signed bit field extract.
1165// Extracts #width adjacent bits from position #lsb in a register, and
1166// writes them to the low bits of a destination register. The extracted
1167// value is sign extended to fill the destination register.
1168// sbfx dst, src, #lsb, #width
1169void Assembler::sbfx(Register dst,
1170 Register src,
1171 int lsb,
1172 int width,
1173 Condition cond) {
1174 // v7 and above.
1175 ASSERT(CpuFeatures::IsSupported(ARMv7));
1176 ASSERT(!dst.is(pc) && !src.is(pc));
1177 ASSERT((lsb >= 0) && (lsb <= 31));
1178 ASSERT((width >= 1) && (width <= (32 - lsb)));
1179 emit(cond | 0xf*B23 | B21 | (width - 1)*B16 | dst.code()*B12 |
1180 lsb*B7 | B6 | B4 | src.code());
1181}
1182
1183
1184// Bit field clear.
1185// Sets #width adjacent bits at position #lsb in the destination register
1186// to zero, preserving the value of the other bits.
1187// bfc dst, #lsb, #width
1188void Assembler::bfc(Register dst, int lsb, int width, Condition cond) {
1189 // v7 and above.
1190 ASSERT(CpuFeatures::IsSupported(ARMv7));
1191 ASSERT(!dst.is(pc));
1192 ASSERT((lsb >= 0) && (lsb <= 31));
1193 ASSERT((width >= 1) && (width <= (32 - lsb)));
1194 int msb = lsb + width - 1;
1195 emit(cond | 0x1f*B22 | msb*B16 | dst.code()*B12 | lsb*B7 | B4 | 0xf);
1196}
1197
1198
1199// Bit field insert.
1200// Inserts #width adjacent bits from the low bits of the source register
1201// into position #lsb of the destination register.
1202// bfi dst, src, #lsb, #width
1203void Assembler::bfi(Register dst,
1204 Register src,
1205 int lsb,
1206 int width,
1207 Condition cond) {
1208 // v7 and above.
1209 ASSERT(CpuFeatures::IsSupported(ARMv7));
1210 ASSERT(!dst.is(pc) && !src.is(pc));
1211 ASSERT((lsb >= 0) && (lsb <= 31));
1212 ASSERT((width >= 1) && (width <= (32 - lsb)));
1213 int msb = lsb + width - 1;
1214 emit(cond | 0x1f*B22 | msb*B16 | dst.code()*B12 | lsb*B7 | B4 |
1215 src.code());
1216}
1217
1218
ager@chromium.org5c838252010-02-19 08:53:10 +00001219// Status register access instructions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001220void Assembler::mrs(Register dst, SRegister s, Condition cond) {
1221 ASSERT(!dst.is(pc));
1222 emit(cond | B24 | s | 15*B16 | dst.code()*B12);
1223}
1224
1225
1226void Assembler::msr(SRegisterFieldMask fields, const Operand& src,
1227 Condition cond) {
1228 ASSERT(fields >= B16 && fields < B20); // at least one field set
1229 Instr instr;
1230 if (!src.rm_.is_valid()) {
ager@chromium.org5c838252010-02-19 08:53:10 +00001231 // Immediate.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001232 uint32_t rotate_imm;
1233 uint32_t immed_8;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001234 if (MustUseIp(src.rmode_) ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001235 !fits_shifter(src.imm32_, &rotate_imm, &immed_8, NULL)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00001236 // Immediate operand cannot be encoded, load it first to register ip.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001237 RecordRelocInfo(src.rmode_, src.imm32_);
1238 ldr(ip, MemOperand(pc, 0), cond);
1239 msr(fields, Operand(ip), cond);
1240 return;
1241 }
1242 instr = I | rotate_imm*B8 | immed_8;
1243 } else {
1244 ASSERT(!src.rs_.is_valid() && src.shift_imm_ == 0); // only rm allowed
1245 instr = src.rm_.code();
1246 }
1247 emit(cond | instr | B24 | B21 | fields | 15*B12);
1248}
1249
1250
ager@chromium.org5c838252010-02-19 08:53:10 +00001251// Load/Store instructions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001252void Assembler::ldr(Register dst, const MemOperand& src, Condition cond) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001253 if (dst.is(pc)) {
1254 WriteRecordedPositions();
1255 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001256 addrmod2(cond | B26 | L, dst, src);
mads.s.ager31e71382008-08-13 09:32:07 +00001257
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001258 // Eliminate pattern: push(ry), pop(rx)
1259 // str(ry, MemOperand(sp, 4, NegPreIndex), al)
1260 // ldr(rx, MemOperand(sp, 4, PostIndex), al)
1261 // Both instructions can be eliminated if ry = rx.
1262 // If ry != rx, a register copy from ry to rx is inserted
1263 // after eliminating the push and the pop instructions.
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001264 if (can_peephole_optimize(2)) {
1265 Instr push_instr = instr_at(pc_ - 2 * kInstrSize);
1266 Instr pop_instr = instr_at(pc_ - 1 * kInstrSize);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001267
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001268 if (IsPush(push_instr) && IsPop(pop_instr)) {
1269 if ((pop_instr & kRdMask) != (push_instr & kRdMask)) {
1270 // For consecutive push and pop on different registers,
1271 // we delete both the push & pop and insert a register move.
1272 // push ry, pop rx --> mov rx, ry
1273 Register reg_pushed, reg_popped;
1274 reg_pushed = GetRd(push_instr);
1275 reg_popped = GetRd(pop_instr);
1276 pc_ -= 2 * kInstrSize;
1277 // Insert a mov instruction, which is better than a pair of push & pop
1278 mov(reg_popped, reg_pushed);
1279 if (FLAG_print_peephole_optimization) {
1280 PrintF("%x push/pop (diff reg) replaced by a reg move\n",
1281 pc_offset());
1282 }
1283 } else {
1284 // For consecutive push and pop on the same register,
1285 // both the push and the pop can be deleted.
1286 pc_ -= 2 * kInstrSize;
1287 if (FLAG_print_peephole_optimization) {
1288 PrintF("%x push/pop (same reg) eliminated\n", pc_offset());
1289 }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001290 }
1291 }
1292 }
1293
1294 if (can_peephole_optimize(2)) {
1295 Instr str_instr = instr_at(pc_ - 2 * kInstrSize);
1296 Instr ldr_instr = instr_at(pc_ - 1 * kInstrSize);
1297
1298 if ((IsStrRegFpOffset(str_instr) &&
1299 IsLdrRegFpOffset(ldr_instr)) ||
1300 (IsStrRegFpNegOffset(str_instr) &&
1301 IsLdrRegFpNegOffset(ldr_instr))) {
1302 if ((ldr_instr & kLdrStrInstrArgumentMask) ==
1303 (str_instr & kLdrStrInstrArgumentMask)) {
1304 // Pattern: Ldr/str same fp+offset, same register.
1305 //
1306 // The following:
1307 // str rx, [fp, #-12]
1308 // ldr rx, [fp, #-12]
1309 //
1310 // Becomes:
1311 // str rx, [fp, #-12]
1312
1313 pc_ -= 1 * kInstrSize;
1314 if (FLAG_print_peephole_optimization) {
1315 PrintF("%x str/ldr (fp + same offset), same reg\n", pc_offset());
1316 }
1317 } else if ((ldr_instr & kLdrStrOffsetMask) ==
1318 (str_instr & kLdrStrOffsetMask)) {
1319 // Pattern: Ldr/str same fp+offset, different register.
1320 //
1321 // The following:
1322 // str rx, [fp, #-12]
1323 // ldr ry, [fp, #-12]
1324 //
1325 // Becomes:
1326 // str rx, [fp, #-12]
1327 // mov ry, rx
1328
1329 Register reg_stored, reg_loaded;
1330 reg_stored = GetRd(str_instr);
1331 reg_loaded = GetRd(ldr_instr);
1332 pc_ -= 1 * kInstrSize;
1333 // Insert a mov instruction, which is better than ldr.
1334 mov(reg_loaded, reg_stored);
1335 if (FLAG_print_peephole_optimization) {
1336 PrintF("%x str/ldr (fp + same offset), diff reg \n", pc_offset());
1337 }
1338 }
1339 }
1340 }
1341
1342 if (can_peephole_optimize(3)) {
1343 Instr mem_write_instr = instr_at(pc_ - 3 * kInstrSize);
1344 Instr ldr_instr = instr_at(pc_ - 2 * kInstrSize);
1345 Instr mem_read_instr = instr_at(pc_ - 1 * kInstrSize);
1346 if (IsPush(mem_write_instr) &&
1347 IsPop(mem_read_instr)) {
1348 if ((IsLdrRegFpOffset(ldr_instr) ||
1349 IsLdrRegFpNegOffset(ldr_instr))) {
1350 if ((mem_write_instr & kRdMask) ==
1351 (mem_read_instr & kRdMask)) {
1352 // Pattern: push & pop from/to same register,
1353 // with a fp+offset ldr in between
1354 //
1355 // The following:
1356 // str rx, [sp, #-4]!
1357 // ldr rz, [fp, #-24]
1358 // ldr rx, [sp], #+4
1359 //
1360 // Becomes:
1361 // if(rx == rz)
1362 // delete all
1363 // else
1364 // ldr rz, [fp, #-24]
1365
1366 if ((mem_write_instr & kRdMask) == (ldr_instr & kRdMask)) {
1367 pc_ -= 3 * kInstrSize;
1368 } else {
1369 pc_ -= 3 * kInstrSize;
1370 // Reinsert back the ldr rz.
1371 emit(ldr_instr);
1372 }
1373 if (FLAG_print_peephole_optimization) {
1374 PrintF("%x push/pop -dead ldr fp+offset in middle\n", pc_offset());
1375 }
1376 } else {
1377 // Pattern: push & pop from/to different registers
1378 // with a fp+offset ldr in between
1379 //
1380 // The following:
1381 // str rx, [sp, #-4]!
1382 // ldr rz, [fp, #-24]
1383 // ldr ry, [sp], #+4
1384 //
1385 // Becomes:
1386 // if(ry == rz)
1387 // mov ry, rx;
1388 // else if(rx != rz)
1389 // ldr rz, [fp, #-24]
1390 // mov ry, rx
1391 // else if((ry != rz) || (rx == rz)) becomes:
1392 // mov ry, rx
1393 // ldr rz, [fp, #-24]
1394
1395 Register reg_pushed, reg_popped;
1396 if ((mem_read_instr & kRdMask) == (ldr_instr & kRdMask)) {
1397 reg_pushed = GetRd(mem_write_instr);
1398 reg_popped = GetRd(mem_read_instr);
1399 pc_ -= 3 * kInstrSize;
1400 mov(reg_popped, reg_pushed);
1401 } else if ((mem_write_instr & kRdMask)
1402 != (ldr_instr & kRdMask)) {
1403 reg_pushed = GetRd(mem_write_instr);
1404 reg_popped = GetRd(mem_read_instr);
1405 pc_ -= 3 * kInstrSize;
1406 emit(ldr_instr);
1407 mov(reg_popped, reg_pushed);
1408 } else if (((mem_read_instr & kRdMask)
1409 != (ldr_instr & kRdMask)) ||
1410 ((mem_write_instr & kRdMask)
1411 == (ldr_instr & kRdMask)) ) {
1412 reg_pushed = GetRd(mem_write_instr);
1413 reg_popped = GetRd(mem_read_instr);
1414 pc_ -= 3 * kInstrSize;
1415 mov(reg_popped, reg_pushed);
1416 emit(ldr_instr);
1417 }
1418 if (FLAG_print_peephole_optimization) {
1419 PrintF("%x push/pop (ldr fp+off in middle)\n", pc_offset());
1420 }
1421 }
1422 }
mads.s.ager31e71382008-08-13 09:32:07 +00001423 }
1424 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001425}
1426
1427
1428void Assembler::str(Register src, const MemOperand& dst, Condition cond) {
1429 addrmod2(cond | B26, src, dst);
mads.s.ager31e71382008-08-13 09:32:07 +00001430
1431 // Eliminate pattern: pop(), push(r)
1432 // add sp, sp, #4 LeaveCC, al; str r, [sp, #-4], al
1433 // -> str r, [sp, 0], al
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001434 if (can_peephole_optimize(2) &&
ager@chromium.org5c838252010-02-19 08:53:10 +00001435 // Pattern.
mads.s.ager31e71382008-08-13 09:32:07 +00001436 instr_at(pc_ - 1 * kInstrSize) == (kPushRegPattern | src.code() * B12) &&
1437 instr_at(pc_ - 2 * kInstrSize) == kPopInstruction) {
1438 pc_ -= 2 * kInstrSize;
1439 emit(al | B26 | 0 | Offset | sp.code() * B16 | src.code() * B12);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001440 if (FLAG_print_peephole_optimization) {
mads.s.ager31e71382008-08-13 09:32:07 +00001441 PrintF("%x pop()/push(reg) eliminated\n", pc_offset());
1442 }
1443 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001444}
1445
1446
1447void Assembler::ldrb(Register dst, const MemOperand& src, Condition cond) {
1448 addrmod2(cond | B26 | B | L, dst, src);
1449}
1450
1451
1452void Assembler::strb(Register src, const MemOperand& dst, Condition cond) {
1453 addrmod2(cond | B26 | B, src, dst);
1454}
1455
1456
1457void Assembler::ldrh(Register dst, const MemOperand& src, Condition cond) {
1458 addrmod3(cond | L | B7 | H | B4, dst, src);
1459}
1460
1461
1462void Assembler::strh(Register src, const MemOperand& dst, Condition cond) {
1463 addrmod3(cond | B7 | H | B4, src, dst);
1464}
1465
1466
1467void Assembler::ldrsb(Register dst, const MemOperand& src, Condition cond) {
1468 addrmod3(cond | L | B7 | S6 | B4, dst, src);
1469}
1470
1471
1472void Assembler::ldrsh(Register dst, const MemOperand& src, Condition cond) {
1473 addrmod3(cond | L | B7 | S6 | H | B4, dst, src);
1474}
1475
1476
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001477void Assembler::ldrd(Register dst1, Register dst2,
1478 const MemOperand& src, Condition cond) {
1479 ASSERT(CpuFeatures::IsEnabled(ARMv7));
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001480 ASSERT(src.rm().is(no_reg));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001481 ASSERT(!dst1.is(lr)); // r14.
1482 ASSERT_EQ(0, dst1.code() % 2);
1483 ASSERT_EQ(dst1.code() + 1, dst2.code());
1484 addrmod3(cond | B7 | B6 | B4, dst1, src);
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001485}
1486
1487
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001488void Assembler::strd(Register src1, Register src2,
1489 const MemOperand& dst, Condition cond) {
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001490 ASSERT(dst.rm().is(no_reg));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001491 ASSERT(!src1.is(lr)); // r14.
1492 ASSERT_EQ(0, src1.code() % 2);
1493 ASSERT_EQ(src1.code() + 1, src2.code());
1494 ASSERT(CpuFeatures::IsEnabled(ARMv7));
1495 addrmod3(cond | B7 | B6 | B5 | B4, src1, dst);
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001496}
1497
ager@chromium.org5c838252010-02-19 08:53:10 +00001498// Load/Store multiple instructions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001499void Assembler::ldm(BlockAddrMode am,
1500 Register base,
1501 RegList dst,
1502 Condition cond) {
ager@chromium.org5c838252010-02-19 08:53:10 +00001503 // ABI stack constraint: ldmxx base, {..sp..} base != sp is not restartable.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001504 ASSERT(base.is(sp) || (dst & sp.bit()) == 0);
1505
1506 addrmod4(cond | B27 | am | L, base, dst);
1507
ager@chromium.org5c838252010-02-19 08:53:10 +00001508 // Emit the constant pool after a function return implemented by ldm ..{..pc}.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001509 if (cond == al && (dst & pc.bit()) != 0) {
1510 // There is a slight chance that the ldm instruction was actually a call,
1511 // in which case it would be wrong to return into the constant pool; we
1512 // recognize this case by checking if the emission of the pool was blocked
1513 // at the pc of the ldm instruction by a mov lr, pc instruction; if this is
1514 // the case, we emit a jump over the pool.
1515 CheckConstPool(true, no_const_pool_before_ == pc_offset() - kInstrSize);
1516 }
1517}
1518
1519
1520void Assembler::stm(BlockAddrMode am,
1521 Register base,
1522 RegList src,
1523 Condition cond) {
1524 addrmod4(cond | B27 | am, base, src);
1525}
1526
1527
ager@chromium.org5c838252010-02-19 08:53:10 +00001528// Exception-generating instructions and debugging support.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001529void Assembler::stop(const char* msg) {
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001530#ifndef __arm__
kasper.lund7276f142008-07-30 08:49:36 +00001531 // The simulator handles these special instructions and stops execution.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001532 emit(15 << 28 | ((intptr_t) msg));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001533#else // def __arm__
1534#ifdef CAN_USE_ARMV5_INSTRUCTIONS
kasper.lund7276f142008-07-30 08:49:36 +00001535 bkpt(0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001536#else // ndef CAN_USE_ARMV5_INSTRUCTIONS
1537 swi(0x9f0001);
1538#endif // ndef CAN_USE_ARMV5_INSTRUCTIONS
1539#endif // def __arm__
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001540}
1541
1542
1543void Assembler::bkpt(uint32_t imm16) { // v5 and above
1544 ASSERT(is_uint16(imm16));
1545 emit(al | B24 | B21 | (imm16 >> 4)*B8 | 7*B4 | (imm16 & 0xf));
1546}
1547
1548
1549void Assembler::swi(uint32_t imm24, Condition cond) {
1550 ASSERT(is_uint24(imm24));
1551 emit(cond | 15*B24 | imm24);
1552}
1553
1554
ager@chromium.org5c838252010-02-19 08:53:10 +00001555// Coprocessor instructions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001556void Assembler::cdp(Coprocessor coproc,
1557 int opcode_1,
1558 CRegister crd,
1559 CRegister crn,
1560 CRegister crm,
1561 int opcode_2,
1562 Condition cond) {
1563 ASSERT(is_uint4(opcode_1) && is_uint3(opcode_2));
1564 emit(cond | B27 | B26 | B25 | (opcode_1 & 15)*B20 | crn.code()*B16 |
1565 crd.code()*B12 | coproc*B8 | (opcode_2 & 7)*B5 | crm.code());
1566}
1567
1568
1569void Assembler::cdp2(Coprocessor coproc,
1570 int opcode_1,
1571 CRegister crd,
1572 CRegister crn,
1573 CRegister crm,
1574 int opcode_2) { // v5 and above
1575 cdp(coproc, opcode_1, crd, crn, crm, opcode_2, static_cast<Condition>(nv));
1576}
1577
1578
1579void Assembler::mcr(Coprocessor coproc,
1580 int opcode_1,
1581 Register rd,
1582 CRegister crn,
1583 CRegister crm,
1584 int opcode_2,
1585 Condition cond) {
1586 ASSERT(is_uint3(opcode_1) && is_uint3(opcode_2));
1587 emit(cond | B27 | B26 | B25 | (opcode_1 & 7)*B21 | crn.code()*B16 |
1588 rd.code()*B12 | coproc*B8 | (opcode_2 & 7)*B5 | B4 | crm.code());
1589}
1590
1591
1592void Assembler::mcr2(Coprocessor coproc,
1593 int opcode_1,
1594 Register rd,
1595 CRegister crn,
1596 CRegister crm,
1597 int opcode_2) { // v5 and above
1598 mcr(coproc, opcode_1, rd, crn, crm, opcode_2, static_cast<Condition>(nv));
1599}
1600
1601
1602void Assembler::mrc(Coprocessor coproc,
1603 int opcode_1,
1604 Register rd,
1605 CRegister crn,
1606 CRegister crm,
1607 int opcode_2,
1608 Condition cond) {
1609 ASSERT(is_uint3(opcode_1) && is_uint3(opcode_2));
1610 emit(cond | B27 | B26 | B25 | (opcode_1 & 7)*B21 | L | crn.code()*B16 |
1611 rd.code()*B12 | coproc*B8 | (opcode_2 & 7)*B5 | B4 | crm.code());
1612}
1613
1614
1615void Assembler::mrc2(Coprocessor coproc,
1616 int opcode_1,
1617 Register rd,
1618 CRegister crn,
1619 CRegister crm,
1620 int opcode_2) { // v5 and above
1621 mrc(coproc, opcode_1, rd, crn, crm, opcode_2, static_cast<Condition>(nv));
1622}
1623
1624
1625void Assembler::ldc(Coprocessor coproc,
1626 CRegister crd,
1627 const MemOperand& src,
1628 LFlag l,
1629 Condition cond) {
1630 addrmod5(cond | B27 | B26 | l | L | coproc*B8, crd, src);
1631}
1632
1633
1634void Assembler::ldc(Coprocessor coproc,
1635 CRegister crd,
1636 Register rn,
1637 int option,
1638 LFlag l,
1639 Condition cond) {
ager@chromium.org5c838252010-02-19 08:53:10 +00001640 // Unindexed addressing.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001641 ASSERT(is_uint8(option));
1642 emit(cond | B27 | B26 | U | l | L | rn.code()*B16 | crd.code()*B12 |
1643 coproc*B8 | (option & 255));
1644}
1645
1646
1647void Assembler::ldc2(Coprocessor coproc,
1648 CRegister crd,
1649 const MemOperand& src,
1650 LFlag l) { // v5 and above
1651 ldc(coproc, crd, src, l, static_cast<Condition>(nv));
1652}
1653
1654
1655void Assembler::ldc2(Coprocessor coproc,
1656 CRegister crd,
1657 Register rn,
1658 int option,
1659 LFlag l) { // v5 and above
1660 ldc(coproc, crd, rn, option, l, static_cast<Condition>(nv));
1661}
1662
1663
1664void Assembler::stc(Coprocessor coproc,
1665 CRegister crd,
1666 const MemOperand& dst,
1667 LFlag l,
1668 Condition cond) {
1669 addrmod5(cond | B27 | B26 | l | coproc*B8, crd, dst);
1670}
1671
1672
1673void Assembler::stc(Coprocessor coproc,
1674 CRegister crd,
1675 Register rn,
1676 int option,
1677 LFlag l,
1678 Condition cond) {
ager@chromium.org5c838252010-02-19 08:53:10 +00001679 // Unindexed addressing.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001680 ASSERT(is_uint8(option));
1681 emit(cond | B27 | B26 | U | l | rn.code()*B16 | crd.code()*B12 |
1682 coproc*B8 | (option & 255));
1683}
1684
1685
1686void Assembler::stc2(Coprocessor
1687 coproc, CRegister crd,
1688 const MemOperand& dst,
1689 LFlag l) { // v5 and above
1690 stc(coproc, crd, dst, l, static_cast<Condition>(nv));
1691}
1692
1693
1694void Assembler::stc2(Coprocessor coproc,
1695 CRegister crd,
1696 Register rn,
1697 int option,
1698 LFlag l) { // v5 and above
1699 stc(coproc, crd, rn, option, l, static_cast<Condition>(nv));
1700}
1701
1702
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001703// Support for VFP.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001704void Assembler::vldr(const DwVfpRegister dst,
1705 const Register base,
1706 int offset,
1707 const Condition cond) {
1708 // Ddst = MEM(Rbase + offset).
1709 // Instruction details available in ARM DDI 0406A, A8-628.
1710 // cond(31-28) | 1101(27-24)| 1001(23-20) | Rbase(19-16) |
1711 // Vdst(15-12) | 1011(11-8) | offset
1712 ASSERT(CpuFeatures::IsEnabled(VFP3));
1713 ASSERT(offset % 4 == 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001714 ASSERT((offset / 4) < 256);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001715 emit(cond | 0xD9*B20 | base.code()*B16 | dst.code()*B12 |
1716 0xB*B8 | ((offset / 4) & 255));
1717}
1718
1719
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001720void Assembler::vldr(const SwVfpRegister dst,
1721 const Register base,
1722 int offset,
1723 const Condition cond) {
1724 // Sdst = MEM(Rbase + offset).
1725 // Instruction details available in ARM DDI 0406A, A8-628.
1726 // cond(31-28) | 1101(27-24)| 1001(23-20) | Rbase(19-16) |
1727 // Vdst(15-12) | 1010(11-8) | offset
1728 ASSERT(CpuFeatures::IsEnabled(VFP3));
1729 ASSERT(offset % 4 == 0);
1730 ASSERT((offset / 4) < 256);
1731 emit(cond | 0xD9*B20 | base.code()*B16 | dst.code()*B12 |
1732 0xA*B8 | ((offset / 4) & 255));
1733}
1734
1735
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001736void Assembler::vstr(const DwVfpRegister src,
1737 const Register base,
1738 int offset,
1739 const Condition cond) {
1740 // MEM(Rbase + offset) = Dsrc.
1741 // Instruction details available in ARM DDI 0406A, A8-786.
1742 // cond(31-28) | 1101(27-24)| 1000(23-20) | | Rbase(19-16) |
1743 // Vsrc(15-12) | 1011(11-8) | (offset/4)
1744 ASSERT(CpuFeatures::IsEnabled(VFP3));
1745 ASSERT(offset % 4 == 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001746 ASSERT((offset / 4) < 256);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001747 emit(cond | 0xD8*B20 | base.code()*B16 | src.code()*B12 |
1748 0xB*B8 | ((offset / 4) & 255));
1749}
1750
1751
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001752void Assembler::vmov(const DwVfpRegister dst,
1753 const Register src1,
1754 const Register src2,
1755 const Condition cond) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001756 // Dm = <Rt,Rt2>.
1757 // Instruction details available in ARM DDI 0406A, A8-646.
1758 // cond(31-28) | 1100(27-24)| 010(23-21) | op=0(20) | Rt2(19-16) |
1759 // Rt(15-12) | 1011(11-8) | 00(7-6) | M(5) | 1(4) | Vm
1760 ASSERT(CpuFeatures::IsEnabled(VFP3));
1761 ASSERT(!src1.is(pc) && !src2.is(pc));
1762 emit(cond | 0xC*B24 | B22 | src2.code()*B16 |
1763 src1.code()*B12 | 0xB*B8 | B4 | dst.code());
1764}
1765
1766
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001767void Assembler::vmov(const Register dst1,
1768 const Register dst2,
1769 const DwVfpRegister src,
1770 const Condition cond) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001771 // <Rt,Rt2> = Dm.
1772 // Instruction details available in ARM DDI 0406A, A8-646.
1773 // cond(31-28) | 1100(27-24)| 010(23-21) | op=1(20) | Rt2(19-16) |
1774 // Rt(15-12) | 1011(11-8) | 00(7-6) | M(5) | 1(4) | Vm
1775 ASSERT(CpuFeatures::IsEnabled(VFP3));
1776 ASSERT(!dst1.is(pc) && !dst2.is(pc));
1777 emit(cond | 0xC*B24 | B22 | B20 | dst2.code()*B16 |
1778 dst1.code()*B12 | 0xB*B8 | B4 | src.code());
1779}
1780
1781
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001782void Assembler::vmov(const SwVfpRegister dst,
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001783 const Register src,
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001784 const Condition cond) {
1785 // Sn = Rt.
1786 // Instruction details available in ARM DDI 0406A, A8-642.
1787 // cond(31-28) | 1110(27-24)| 000(23-21) | op=0(20) | Vn(19-16) |
1788 // Rt(15-12) | 1010(11-8) | N(7)=0 | 00(6-5) | 1(4) | 0000(3-0)
1789 ASSERT(CpuFeatures::IsEnabled(VFP3));
1790 ASSERT(!src.is(pc));
1791 emit(cond | 0xE*B24 | (dst.code() >> 1)*B16 |
1792 src.code()*B12 | 0xA*B8 | (0x1 & dst.code())*B7 | B4);
1793}
1794
1795
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001796void Assembler::vmov(const Register dst,
1797 const SwVfpRegister src,
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001798 const Condition cond) {
1799 // Rt = Sn.
1800 // Instruction details available in ARM DDI 0406A, A8-642.
1801 // cond(31-28) | 1110(27-24)| 000(23-21) | op=1(20) | Vn(19-16) |
1802 // Rt(15-12) | 1010(11-8) | N(7)=0 | 00(6-5) | 1(4) | 0000(3-0)
1803 ASSERT(CpuFeatures::IsEnabled(VFP3));
1804 ASSERT(!dst.is(pc));
1805 emit(cond | 0xE*B24 | B20 | (src.code() >> 1)*B16 |
1806 dst.code()*B12 | 0xA*B8 | (0x1 & src.code())*B7 | B4);
1807}
1808
1809
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001810// Type of data to read from or write to VFP register.
1811// Used as specifier in generic vcvt instruction.
1812enum VFPType { S32, U32, F32, F64 };
1813
1814
1815static bool IsSignedVFPType(VFPType type) {
1816 switch (type) {
1817 case S32:
1818 return true;
1819 case U32:
1820 return false;
1821 default:
1822 UNREACHABLE();
1823 return false;
1824 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001825}
1826
1827
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001828static bool IsIntegerVFPType(VFPType type) {
1829 switch (type) {
1830 case S32:
1831 case U32:
1832 return true;
1833 case F32:
1834 case F64:
1835 return false;
1836 default:
1837 UNREACHABLE();
1838 return false;
1839 }
1840}
1841
1842
1843static bool IsDoubleVFPType(VFPType type) {
1844 switch (type) {
1845 case F32:
1846 return false;
1847 case F64:
1848 return true;
1849 default:
1850 UNREACHABLE();
1851 return false;
1852 }
1853}
1854
1855
1856// Depending on split_last_bit split binary representation of reg_code into Vm:M
1857// or M:Vm form (where M is single bit).
1858static void SplitRegCode(bool split_last_bit,
1859 int reg_code,
1860 int* vm,
1861 int* m) {
1862 if (split_last_bit) {
1863 *m = reg_code & 0x1;
1864 *vm = reg_code >> 1;
1865 } else {
1866 *m = (reg_code & 0x10) >> 4;
1867 *vm = reg_code & 0x0F;
1868 }
1869}
1870
1871
1872// Encode vcvt.src_type.dst_type instruction.
1873static Instr EncodeVCVT(const VFPType dst_type,
1874 const int dst_code,
1875 const VFPType src_type,
1876 const int src_code,
1877 const Condition cond) {
1878 if (IsIntegerVFPType(dst_type) || IsIntegerVFPType(src_type)) {
1879 // Conversion between IEEE floating point and 32-bit integer.
1880 // Instruction details available in ARM DDI 0406B, A8.6.295.
1881 // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 1(19) | opc2(18-16) |
1882 // Vd(15-12) | 101(11-9) | sz(8) | op(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
1883 ASSERT(!IsIntegerVFPType(dst_type) || !IsIntegerVFPType(src_type));
1884
1885 int sz, opc2, D, Vd, M, Vm, op;
1886
1887 if (IsIntegerVFPType(dst_type)) {
1888 opc2 = IsSignedVFPType(dst_type) ? 0x5 : 0x4;
1889 sz = IsDoubleVFPType(src_type) ? 0x1 : 0x0;
1890 op = 1; // round towards zero
1891 SplitRegCode(!IsDoubleVFPType(src_type), src_code, &Vm, &M);
1892 SplitRegCode(true, dst_code, &Vd, &D);
1893 } else {
1894 ASSERT(IsIntegerVFPType(src_type));
1895
1896 opc2 = 0x0;
1897 sz = IsDoubleVFPType(dst_type) ? 0x1 : 0x0;
1898 op = IsSignedVFPType(src_type) ? 0x1 : 0x0;
1899 SplitRegCode(true, src_code, &Vm, &M);
1900 SplitRegCode(!IsDoubleVFPType(dst_type), dst_code, &Vd, &D);
1901 }
1902
1903 return (cond | 0xE*B24 | B23 | D*B22 | 0x3*B20 | B19 | opc2*B16 |
1904 Vd*B12 | 0x5*B9 | sz*B8 | op*B7 | B6 | M*B5 | Vm);
1905 } else {
1906 // Conversion between IEEE double and single precision.
1907 // Instruction details available in ARM DDI 0406B, A8.6.298.
1908 // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 0111(19-16) |
1909 // Vd(15-12) | 101(11-9) | sz(8) | 1(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
1910 int sz, D, Vd, M, Vm;
1911
1912 ASSERT(IsDoubleVFPType(dst_type) != IsDoubleVFPType(src_type));
1913 sz = IsDoubleVFPType(src_type) ? 0x1 : 0x0;
1914 SplitRegCode(IsDoubleVFPType(src_type), dst_code, &Vd, &D);
1915 SplitRegCode(!IsDoubleVFPType(src_type), src_code, &Vm, &M);
1916
1917 return (cond | 0xE*B24 | B23 | D*B22 | 0x3*B20 | 0x7*B16 |
1918 Vd*B12 | 0x5*B9 | sz*B8 | B7 | B6 | M*B5 | Vm);
1919 }
1920}
1921
1922
1923void Assembler::vcvt_f64_s32(const DwVfpRegister dst,
1924 const SwVfpRegister src,
1925 const Condition cond) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001926 ASSERT(CpuFeatures::IsEnabled(VFP3));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001927 emit(EncodeVCVT(F64, dst.code(), S32, src.code(), cond));
1928}
1929
1930
1931void Assembler::vcvt_f32_s32(const SwVfpRegister dst,
1932 const SwVfpRegister src,
1933 const Condition cond) {
1934 ASSERT(CpuFeatures::IsEnabled(VFP3));
1935 emit(EncodeVCVT(F32, dst.code(), S32, src.code(), cond));
1936}
1937
1938
1939void Assembler::vcvt_f64_u32(const DwVfpRegister dst,
1940 const SwVfpRegister src,
1941 const Condition cond) {
1942 ASSERT(CpuFeatures::IsEnabled(VFP3));
1943 emit(EncodeVCVT(F64, dst.code(), U32, src.code(), cond));
1944}
1945
1946
1947void Assembler::vcvt_s32_f64(const SwVfpRegister dst,
1948 const DwVfpRegister src,
1949 const Condition cond) {
1950 ASSERT(CpuFeatures::IsEnabled(VFP3));
1951 emit(EncodeVCVT(S32, dst.code(), F64, src.code(), cond));
1952}
1953
1954
1955void Assembler::vcvt_u32_f64(const SwVfpRegister dst,
1956 const DwVfpRegister src,
1957 const Condition cond) {
1958 ASSERT(CpuFeatures::IsEnabled(VFP3));
1959 emit(EncodeVCVT(U32, dst.code(), F64, src.code(), cond));
1960}
1961
1962
1963void Assembler::vcvt_f64_f32(const DwVfpRegister dst,
1964 const SwVfpRegister src,
1965 const Condition cond) {
1966 ASSERT(CpuFeatures::IsEnabled(VFP3));
1967 emit(EncodeVCVT(F64, dst.code(), F32, src.code(), cond));
1968}
1969
1970
1971void Assembler::vcvt_f32_f64(const SwVfpRegister dst,
1972 const DwVfpRegister src,
1973 const Condition cond) {
1974 ASSERT(CpuFeatures::IsEnabled(VFP3));
1975 emit(EncodeVCVT(F32, dst.code(), F64, src.code(), cond));
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001976}
1977
1978
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001979void Assembler::vadd(const DwVfpRegister dst,
1980 const DwVfpRegister src1,
1981 const DwVfpRegister src2,
1982 const Condition cond) {
1983 // Dd = vadd(Dn, Dm) double precision floating point addition.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001984 // Dd = D:Vd; Dm=M:Vm; Dn=N:Vm.
1985 // Instruction details available in ARM DDI 0406A, A8-536.
1986 // cond(31-28) | 11100(27-23)| D=?(22) | 11(21-20) | Vn(19-16) |
1987 // Vd(15-12) | 101(11-9) | sz(8)=1 | N(7)=0 | 0(6) | M=?(5) | 0(4) | Vm(3-0)
1988 ASSERT(CpuFeatures::IsEnabled(VFP3));
1989 emit(cond | 0xE*B24 | 0x3*B20 | src1.code()*B16 |
1990 dst.code()*B12 | 0x5*B9 | B8 | src2.code());
1991}
1992
1993
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001994void Assembler::vsub(const DwVfpRegister dst,
1995 const DwVfpRegister src1,
1996 const DwVfpRegister src2,
1997 const Condition cond) {
1998 // Dd = vsub(Dn, Dm) double precision floating point subtraction.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001999 // Dd = D:Vd; Dm=M:Vm; Dn=N:Vm.
2000 // Instruction details available in ARM DDI 0406A, A8-784.
2001 // cond(31-28) | 11100(27-23)| D=?(22) | 11(21-20) | Vn(19-16) |
2002 // Vd(15-12) | 101(11-9) | sz(8)=1 | N(7)=0 | 1(6) | M=?(5) | 0(4) | Vm(3-0)
2003 ASSERT(CpuFeatures::IsEnabled(VFP3));
2004 emit(cond | 0xE*B24 | 0x3*B20 | src1.code()*B16 |
2005 dst.code()*B12 | 0x5*B9 | B8 | B6 | src2.code());
2006}
2007
2008
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00002009void Assembler::vmul(const DwVfpRegister dst,
2010 const DwVfpRegister src1,
2011 const DwVfpRegister src2,
2012 const Condition cond) {
2013 // Dd = vmul(Dn, Dm) double precision floating point multiplication.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002014 // Dd = D:Vd; Dm=M:Vm; Dn=N:Vm.
2015 // Instruction details available in ARM DDI 0406A, A8-784.
2016 // cond(31-28) | 11100(27-23)| D=?(22) | 10(21-20) | Vn(19-16) |
2017 // Vd(15-12) | 101(11-9) | sz(8)=1 | N(7)=0 | 0(6) | M=?(5) | 0(4) | Vm(3-0)
2018 ASSERT(CpuFeatures::IsEnabled(VFP3));
2019 emit(cond | 0xE*B24 | 0x2*B20 | src1.code()*B16 |
2020 dst.code()*B12 | 0x5*B9 | B8 | src2.code());
2021}
2022
2023
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00002024void Assembler::vdiv(const DwVfpRegister dst,
2025 const DwVfpRegister src1,
2026 const DwVfpRegister src2,
2027 const Condition cond) {
2028 // Dd = vdiv(Dn, Dm) double precision floating point division.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002029 // Dd = D:Vd; Dm=M:Vm; Dn=N:Vm.
2030 // Instruction details available in ARM DDI 0406A, A8-584.
2031 // cond(31-28) | 11101(27-23)| D=?(22) | 00(21-20) | Vn(19-16) |
2032 // Vd(15-12) | 101(11-9) | sz(8)=1 | N(7)=? | 0(6) | M=?(5) | 0(4) | Vm(3-0)
2033 ASSERT(CpuFeatures::IsEnabled(VFP3));
2034 emit(cond | 0xE*B24 | B23 | src1.code()*B16 |
2035 dst.code()*B12 | 0x5*B9 | B8 | src2.code());
2036}
2037
2038
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00002039void Assembler::vcmp(const DwVfpRegister src1,
2040 const DwVfpRegister src2,
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002041 const SBit s,
2042 const Condition cond) {
2043 // vcmp(Dd, Dm) double precision floating point comparison.
2044 // Instruction details available in ARM DDI 0406A, A8-570.
2045 // cond(31-28) | 11101 (27-23)| D=?(22) | 11 (21-20) | 0100 (19-16) |
2046 // Vd(15-12) | 101(11-9) | sz(8)=1 | E(7)=? | 1(6) | M(5)=? | 0(4) | Vm(3-0)
2047 ASSERT(CpuFeatures::IsEnabled(VFP3));
2048 emit(cond | 0xE*B24 |B23 | 0x3*B20 | B18 |
2049 src1.code()*B12 | 0x5*B9 | B8 | B6 | src2.code());
2050}
2051
2052
2053void Assembler::vmrs(Register dst, Condition cond) {
2054 // Instruction details available in ARM DDI 0406A, A8-652.
2055 // cond(31-28) | 1110 (27-24) | 1111(23-20)| 0001 (19-16) |
2056 // Rt(15-12) | 1010 (11-8) | 0(7) | 00 (6-5) | 1(4) | 0000(3-0)
2057 ASSERT(CpuFeatures::IsEnabled(VFP3));
2058 emit(cond | 0xE*B24 | 0xF*B20 | B16 |
2059 dst.code()*B12 | 0xA*B8 | B4);
2060}
2061
2062
ager@chromium.org5c838252010-02-19 08:53:10 +00002063// Pseudo instructions.
fschneider@chromium.org013f3e12010-04-26 13:27:52 +00002064void Assembler::nop(int type) {
2065 // This is mov rx, rx.
2066 ASSERT(0 <= type && type <= 14); // mov pc, pc is not a nop.
2067 emit(al | 13*B21 | type*B12 | type);
2068}
2069
2070
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002071bool Assembler::ImmediateFitsAddrMode1Instruction(int32_t imm32) {
2072 uint32_t dummy1;
2073 uint32_t dummy2;
2074 return fits_shifter(imm32, &dummy1, &dummy2, NULL);
2075}
2076
2077
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00002078void Assembler::BlockConstPoolFor(int instructions) {
2079 BlockConstPoolBefore(pc_offset() + instructions * kInstrSize);
2080}
2081
2082
ager@chromium.org5c838252010-02-19 08:53:10 +00002083// Debugging.
ager@chromium.org4af710e2009-09-15 12:20:11 +00002084void Assembler::RecordJSReturn() {
2085 WriteRecordedPositions();
2086 CheckBuffer();
2087 RecordRelocInfo(RelocInfo::JS_RETURN);
2088}
2089
2090
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00002091void Assembler::RecordDebugBreakSlot() {
2092 WriteRecordedPositions();
2093 CheckBuffer();
2094 RecordRelocInfo(RelocInfo::DEBUG_BREAK_SLOT);
2095}
2096
2097
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002098void Assembler::RecordComment(const char* msg) {
2099 if (FLAG_debug_code) {
2100 CheckBuffer();
ager@chromium.org236ad962008-09-25 09:45:57 +00002101 RecordRelocInfo(RelocInfo::COMMENT, reinterpret_cast<intptr_t>(msg));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002102 }
2103}
2104
2105
2106void Assembler::RecordPosition(int pos) {
ager@chromium.org236ad962008-09-25 09:45:57 +00002107 if (pos == RelocInfo::kNoPosition) return;
2108 ASSERT(pos >= 0);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002109 current_position_ = pos;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002110}
2111
2112
2113void Assembler::RecordStatementPosition(int pos) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002114 if (pos == RelocInfo::kNoPosition) return;
2115 ASSERT(pos >= 0);
2116 current_statement_position_ = pos;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002117}
2118
2119
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00002120bool Assembler::WriteRecordedPositions() {
2121 bool written = false;
2122
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002123 // Write the statement position if it is different from what was written last
2124 // time.
2125 if (current_statement_position_ != written_statement_position_) {
2126 CheckBuffer();
2127 RecordRelocInfo(RelocInfo::STATEMENT_POSITION, current_statement_position_);
2128 written_statement_position_ = current_statement_position_;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00002129 written = true;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002130 }
2131
2132 // Write the position if it is different from what was written last time and
ager@chromium.org32912102009-01-16 10:38:43 +00002133 // also different from the written statement position.
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002134 if (current_position_ != written_position_ &&
2135 current_position_ != written_statement_position_) {
2136 CheckBuffer();
2137 RecordRelocInfo(RelocInfo::POSITION, current_position_);
2138 written_position_ = current_position_;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00002139 written = true;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002140 }
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00002141
2142 // Return whether something was written.
2143 return written;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002144}
2145
2146
2147void Assembler::GrowBuffer() {
2148 if (!own_buffer_) FATAL("external code buffer is too small");
2149
ager@chromium.org5c838252010-02-19 08:53:10 +00002150 // Compute new buffer size.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002151 CodeDesc desc; // the new buffer
2152 if (buffer_size_ < 4*KB) {
2153 desc.buffer_size = 4*KB;
2154 } else if (buffer_size_ < 1*MB) {
2155 desc.buffer_size = 2*buffer_size_;
2156 } else {
2157 desc.buffer_size = buffer_size_ + 1*MB;
2158 }
2159 CHECK_GT(desc.buffer_size, 0); // no overflow
2160
ager@chromium.org5c838252010-02-19 08:53:10 +00002161 // Setup new buffer.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002162 desc.buffer = NewArray<byte>(desc.buffer_size);
2163
2164 desc.instr_size = pc_offset();
2165 desc.reloc_size = (buffer_ + buffer_size_) - reloc_info_writer.pos();
2166
ager@chromium.org5c838252010-02-19 08:53:10 +00002167 // Copy the data.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002168 int pc_delta = desc.buffer - buffer_;
2169 int rc_delta = (desc.buffer + desc.buffer_size) - (buffer_ + buffer_size_);
2170 memmove(desc.buffer, buffer_, desc.instr_size);
2171 memmove(reloc_info_writer.pos() + rc_delta,
2172 reloc_info_writer.pos(), desc.reloc_size);
2173
ager@chromium.org5c838252010-02-19 08:53:10 +00002174 // Switch buffers.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002175 DeleteArray(buffer_);
2176 buffer_ = desc.buffer;
2177 buffer_size_ = desc.buffer_size;
2178 pc_ += pc_delta;
2179 reloc_info_writer.Reposition(reloc_info_writer.pos() + rc_delta,
2180 reloc_info_writer.last_pc() + pc_delta);
2181
ager@chromium.org5c838252010-02-19 08:53:10 +00002182 // None of our relocation types are pc relative pointing outside the code
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002183 // buffer nor pc absolute pointing inside the code buffer, so there is no need
ager@chromium.org5c838252010-02-19 08:53:10 +00002184 // to relocate any emitted relocation entries.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002185
ager@chromium.org5c838252010-02-19 08:53:10 +00002186 // Relocate pending relocation entries.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002187 for (int i = 0; i < num_prinfo_; i++) {
2188 RelocInfo& rinfo = prinfo_[i];
ager@chromium.org236ad962008-09-25 09:45:57 +00002189 ASSERT(rinfo.rmode() != RelocInfo::COMMENT &&
2190 rinfo.rmode() != RelocInfo::POSITION);
ager@chromium.org4af710e2009-09-15 12:20:11 +00002191 if (rinfo.rmode() != RelocInfo::JS_RETURN) {
2192 rinfo.set_pc(rinfo.pc() + pc_delta);
2193 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002194 }
2195}
2196
2197
ager@chromium.org236ad962008-09-25 09:45:57 +00002198void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002199 RelocInfo rinfo(pc_, rmode, data); // we do not try to reuse pool constants
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00002200 if (rmode >= RelocInfo::JS_RETURN && rmode <= RelocInfo::DEBUG_BREAK_SLOT) {
ager@chromium.org5c838252010-02-19 08:53:10 +00002201 // Adjust code for new modes.
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00002202 ASSERT(RelocInfo::IsDebugBreakSlot(rmode)
2203 || RelocInfo::IsJSReturn(rmode)
ager@chromium.org4af710e2009-09-15 12:20:11 +00002204 || RelocInfo::IsComment(rmode)
2205 || RelocInfo::IsPosition(rmode));
ager@chromium.org5c838252010-02-19 08:53:10 +00002206 // These modes do not need an entry in the constant pool.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002207 } else {
2208 ASSERT(num_prinfo_ < kMaxNumPRInfo);
2209 prinfo_[num_prinfo_++] = rinfo;
2210 // Make sure the constant pool is not emitted in place of the next
ager@chromium.org5c838252010-02-19 08:53:10 +00002211 // instruction for which we just recorded relocation info.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002212 BlockConstPoolBefore(pc_offset() + kInstrSize);
2213 }
ager@chromium.org236ad962008-09-25 09:45:57 +00002214 if (rinfo.rmode() != RelocInfo::NONE) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002215 // Don't record external references unless the heap will be serialized.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002216 if (rmode == RelocInfo::EXTERNAL_REFERENCE) {
2217#ifdef DEBUG
2218 if (!Serializer::enabled()) {
2219 Serializer::TooLateToEnableNow();
2220 }
2221#endif
2222 if (!Serializer::enabled() && !FLAG_debug_code) {
2223 return;
2224 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002225 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002226 ASSERT(buffer_space() >= kMaxRelocSize); // too late to grow buffer here
2227 reloc_info_writer.Write(&rinfo);
2228 }
2229}
2230
2231
2232void Assembler::CheckConstPool(bool force_emit, bool require_jump) {
2233 // Calculate the offset of the next check. It will be overwritten
2234 // when a const pool is generated or when const pools are being
2235 // blocked for a specific range.
2236 next_buffer_check_ = pc_offset() + kCheckConstInterval;
2237
ager@chromium.org5c838252010-02-19 08:53:10 +00002238 // There is nothing to do if there are no pending relocation info entries.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002239 if (num_prinfo_ == 0) return;
2240
2241 // We emit a constant pool at regular intervals of about kDistBetweenPools
2242 // or when requested by parameter force_emit (e.g. after each function).
2243 // We prefer not to emit a jump unless the max distance is reached or if we
2244 // are running low on slots, which can happen if a lot of constants are being
2245 // emitted (e.g. --debug-code and many static references).
2246 int dist = pc_offset() - last_const_pool_end_;
2247 if (!force_emit && dist < kMaxDistBetweenPools &&
2248 (require_jump || dist < kDistBetweenPools) &&
2249 // TODO(1236125): Cleanup the "magic" number below. We know that
2250 // the code generation will test every kCheckConstIntervalInst.
2251 // Thus we are safe as long as we generate less than 7 constant
2252 // entries per instruction.
2253 (num_prinfo_ < (kMaxNumPRInfo - (7 * kCheckConstIntervalInst)))) {
2254 return;
2255 }
2256
2257 // If we did not return by now, we need to emit the constant pool soon.
2258
2259 // However, some small sequences of instructions must not be broken up by the
2260 // insertion of a constant pool; such sequences are protected by setting
fschneider@chromium.org013f3e12010-04-26 13:27:52 +00002261 // either const_pool_blocked_nesting_ or no_const_pool_before_, which are
2262 // both checked here. Also, recursive calls to CheckConstPool are blocked by
2263 // no_const_pool_before_.
2264 if (const_pool_blocked_nesting_ > 0 || pc_offset() < no_const_pool_before_) {
ager@chromium.org5c838252010-02-19 08:53:10 +00002265 // Emission is currently blocked; make sure we try again as soon as
2266 // possible.
fschneider@chromium.org013f3e12010-04-26 13:27:52 +00002267 if (const_pool_blocked_nesting_ > 0) {
2268 next_buffer_check_ = pc_offset() + kInstrSize;
2269 } else {
2270 next_buffer_check_ = no_const_pool_before_;
2271 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002272
ager@chromium.org5c838252010-02-19 08:53:10 +00002273 // Something is wrong if emission is forced and blocked at the same time.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002274 ASSERT(!force_emit);
2275 return;
2276 }
2277
2278 int jump_instr = require_jump ? kInstrSize : 0;
2279
2280 // Check that the code buffer is large enough before emitting the constant
2281 // pool and relocation information (include the jump over the pool and the
2282 // constant pool marker).
2283 int max_needed_space =
2284 jump_instr + kInstrSize + num_prinfo_*(kInstrSize + kMaxRelocSize);
2285 while (buffer_space() <= (max_needed_space + kGap)) GrowBuffer();
2286
ager@chromium.org5c838252010-02-19 08:53:10 +00002287 // Block recursive calls to CheckConstPool.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002288 BlockConstPoolBefore(pc_offset() + jump_instr + kInstrSize +
2289 num_prinfo_*kInstrSize);
2290 // Don't bother to check for the emit calls below.
2291 next_buffer_check_ = no_const_pool_before_;
2292
ager@chromium.org5c838252010-02-19 08:53:10 +00002293 // Emit jump over constant pool if necessary.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002294 Label after_pool;
2295 if (require_jump) b(&after_pool);
2296
2297 RecordComment("[ Constant Pool");
2298
ager@chromium.org5c838252010-02-19 08:53:10 +00002299 // Put down constant pool marker "Undefined instruction" as specified by
2300 // A3.1 Instruction set encoding.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002301 emit(0x03000000 | num_prinfo_);
2302
ager@chromium.org5c838252010-02-19 08:53:10 +00002303 // Emit constant pool entries.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002304 for (int i = 0; i < num_prinfo_; i++) {
2305 RelocInfo& rinfo = prinfo_[i];
ager@chromium.org236ad962008-09-25 09:45:57 +00002306 ASSERT(rinfo.rmode() != RelocInfo::COMMENT &&
2307 rinfo.rmode() != RelocInfo::POSITION &&
2308 rinfo.rmode() != RelocInfo::STATEMENT_POSITION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002309 Instr instr = instr_at(rinfo.pc());
ager@chromium.org4af710e2009-09-15 12:20:11 +00002310
ager@chromium.org5c838252010-02-19 08:53:10 +00002311 // Instruction to patch must be a ldr/str [pc, #offset].
2312 // P and U set, B and W clear, Rn == pc, offset12 still 0.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002313 ASSERT((instr & (7*B25 | P | U | B | W | 15*B16 | Off12Mask)) ==
2314 (2*B25 | P | U | pc.code()*B16));
2315 int delta = pc_ - rinfo.pc() - 8;
2316 ASSERT(delta >= -4); // instr could be ldr pc, [pc, #-4] followed by targ32
2317 if (delta < 0) {
2318 instr &= ~U;
2319 delta = -delta;
2320 }
2321 ASSERT(is_uint12(delta));
2322 instr_at_put(rinfo.pc(), instr + delta);
2323 emit(rinfo.data());
2324 }
2325 num_prinfo_ = 0;
2326 last_const_pool_end_ = pc_offset();
2327
2328 RecordComment("]");
2329
2330 if (after_pool.is_linked()) {
2331 bind(&after_pool);
2332 }
2333
2334 // Since a constant pool was just emitted, move the check offset forward by
2335 // the standard interval.
2336 next_buffer_check_ = pc_offset() + kCheckConstInterval;
2337}
2338
2339
2340} } // namespace v8::internal
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002341
2342#endif // V8_TARGET_ARCH_ARM