blob: 4c11c7f5490b7fa940b5c625f7883e5ab6c05245 [file] [log] [blame]
ager@chromium.org5c838252010-02-19 08:53:10 +00001// Copyright (c) 1994-2006 Sun Microsystems Inc.
2// All Rights Reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions are
6// 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 distribution.
14//
15// - Neither the name of Sun Microsystems or the names of contributors may
16// be used to endorse or promote products derived from this software without
17// specific prior written permission.
18//
19// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
20// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
23// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
27// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31// The original source code covered by the above license above has been
32// modified significantly by Google Inc.
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +000033// Copyright 2012 the V8 project authors. All rights reserved.
ager@chromium.org5c838252010-02-19 08:53:10 +000034
35
36#include "v8.h"
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000037
38#if defined(V8_TARGET_ARCH_MIPS)
39
ager@chromium.org5c838252010-02-19 08:53:10 +000040#include "mips/assembler-mips-inl.h"
41#include "serialize.h"
42
ager@chromium.org5c838252010-02-19 08:53:10 +000043namespace v8 {
44namespace internal {
45
karlklose@chromium.org83a47282011-05-11 11:54:09 +000046#ifdef DEBUG
47bool CpuFeatures::initialized_ = false;
48#endif
49unsigned CpuFeatures::supported_ = 0;
ulan@chromium.org750145a2013-03-07 15:14:13 +000050unsigned CpuFeatures::found_by_runtime_probing_only_ = 0;
ager@chromium.org5c838252010-02-19 08:53:10 +000051
fschneider@chromium.org1805e212011-09-05 10:49:12 +000052
yangguo@chromium.org003650e2013-01-24 16:31:08 +000053ExternalReference ExternalReference::cpu_features() {
54 ASSERT(CpuFeatures::initialized_);
55 return ExternalReference(&CpuFeatures::supported_);
56}
57
58
fschneider@chromium.org1805e212011-09-05 10:49:12 +000059// Get the CPU features enabled by the build. For cross compilation the
60// preprocessor symbols CAN_USE_FPU_INSTRUCTIONS
61// can be defined to enable FPU instructions when building the
62// snapshot.
63static uint64_t CpuFeaturesImpliedByCompiler() {
64 uint64_t answer = 0;
65#ifdef CAN_USE_FPU_INSTRUCTIONS
ulan@chromium.org750145a2013-03-07 15:14:13 +000066 answer |= static_cast<uint64_t>(1) << FPU;
fschneider@chromium.org1805e212011-09-05 10:49:12 +000067#endif // def CAN_USE_FPU_INSTRUCTIONS
68
69#ifdef __mips__
70 // If the compiler is allowed to use FPU then we can use FPU too in our code
71 // generation even when generating snapshots. This won't work for cross
72 // compilation.
73#if(defined(__mips_hard_float) && __mips_hard_float != 0)
ulan@chromium.org750145a2013-03-07 15:14:13 +000074 answer |= static_cast<uint64_t>(1) << FPU;
fschneider@chromium.org1805e212011-09-05 10:49:12 +000075#endif // defined(__mips_hard_float) && __mips_hard_float != 0
76#endif // def __mips__
77
78 return answer;
79}
80
81
jkummerow@chromium.org59297c72013-01-09 16:32:23 +000082const char* DoubleRegister::AllocationIndexToString(int index) {
83 if (CpuFeatures::IsSupported(FPU)) {
84 ASSERT(index >= 0 && index < kMaxNumAllocatableRegisters);
85 const char* const names[] = {
86 "f0",
87 "f2",
88 "f4",
89 "f6",
90 "f8",
91 "f10",
92 "f12",
93 "f14",
94 "f16",
95 "f18",
96 "f20",
97 "f22",
98 "f24",
99 "f26"
100 };
101 return names[index];
102 } else {
103 ASSERT(index == 0);
104 return "sfpd0";
105 }
106}
107
108
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000109void CpuFeatures::Probe() {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000110 unsigned standard_features = (OS::CpuFeaturesImpliedByPlatform() |
111 CpuFeaturesImpliedByCompiler());
112 ASSERT(supported_ == 0 || supported_ == standard_features);
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000113#ifdef DEBUG
114 initialized_ = true;
115#endif
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000116
117 // Get the features implied by the OS and the compiler settings. This is the
118 // minimal set of features which is also allowed for generated code in the
119 // snapshot.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000120 supported_ |= standard_features;
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000121
122 if (Serializer::enabled()) {
123 // No probing for features if we might serialize (generate snapshot).
124 return;
125 }
126
lrn@chromium.org7516f052011-03-30 08:52:27 +0000127 // If the compiler is allowed to use fpu then we can use fpu too in our
128 // code generation.
129#if !defined(__mips__)
130 // For the simulator=mips build, use FPU when FLAG_enable_fpu is enabled.
131 if (FLAG_enable_fpu) {
ulan@chromium.org750145a2013-03-07 15:14:13 +0000132 supported_ |= static_cast<uint64_t>(1) << FPU;
lrn@chromium.org7516f052011-03-30 08:52:27 +0000133 }
134#else
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000135 // Probe for additional features not already known to be available.
lrn@chromium.org7516f052011-03-30 08:52:27 +0000136 if (OS::MipsCpuHasFeature(FPU)) {
137 // This implementation also sets the FPU flags if
138 // runtime detection of FPU returns true.
ulan@chromium.org750145a2013-03-07 15:14:13 +0000139 supported_ |= static_cast<uint64_t>(1) << FPU;
140 found_by_runtime_probing_only_ |= static_cast<uint64_t>(1) << FPU;
lrn@chromium.org7516f052011-03-30 08:52:27 +0000141 }
lrn@chromium.org7516f052011-03-30 08:52:27 +0000142#endif
143}
ager@chromium.org5c838252010-02-19 08:53:10 +0000144
145
ager@chromium.org5c838252010-02-19 08:53:10 +0000146int ToNumber(Register reg) {
147 ASSERT(reg.is_valid());
148 const int kNumbers[] = {
149 0, // zero_reg
150 1, // at
151 2, // v0
152 3, // v1
153 4, // a0
154 5, // a1
155 6, // a2
156 7, // a3
157 8, // t0
158 9, // t1
159 10, // t2
160 11, // t3
161 12, // t4
162 13, // t5
163 14, // t6
164 15, // t7
165 16, // s0
166 17, // s1
167 18, // s2
168 19, // s3
169 20, // s4
170 21, // s5
171 22, // s6
172 23, // s7
173 24, // t8
174 25, // t9
175 26, // k0
176 27, // k1
177 28, // gp
178 29, // sp
fschneider@chromium.org7d10be52012-04-10 12:30:14 +0000179 30, // fp
ager@chromium.org5c838252010-02-19 08:53:10 +0000180 31, // ra
181 };
182 return kNumbers[reg.code()];
183}
184
lrn@chromium.org7516f052011-03-30 08:52:27 +0000185
ager@chromium.org5c838252010-02-19 08:53:10 +0000186Register ToRegister(int num) {
187 ASSERT(num >= 0 && num < kNumRegisters);
188 const Register kRegisters[] = {
189 zero_reg,
190 at,
191 v0, v1,
192 a0, a1, a2, a3,
193 t0, t1, t2, t3, t4, t5, t6, t7,
194 s0, s1, s2, s3, s4, s5, s6, s7,
195 t8, t9,
196 k0, k1,
197 gp,
198 sp,
fschneider@chromium.org7d10be52012-04-10 12:30:14 +0000199 fp,
ager@chromium.org5c838252010-02-19 08:53:10 +0000200 ra
201 };
202 return kRegisters[num];
203}
204
205
206// -----------------------------------------------------------------------------
207// Implementation of RelocInfo.
208
lrn@chromium.org34e60782011-09-15 07:25:40 +0000209const int RelocInfo::kApplyMask = RelocInfo::kCodeTargetMask |
210 1 << RelocInfo::INTERNAL_REFERENCE;
ager@chromium.org5c838252010-02-19 08:53:10 +0000211
lrn@chromium.org7516f052011-03-30 08:52:27 +0000212
213bool RelocInfo::IsCodedSpecially() {
214 // The deserializer needs to know whether a pointer is specially coded. Being
215 // specially coded on MIPS means that it is a lui/ori instruction, and that is
216 // always the case inside code objects.
217 return true;
218}
219
220
ager@chromium.org5c838252010-02-19 08:53:10 +0000221// Patch the code at the current address with the supplied instructions.
222void RelocInfo::PatchCode(byte* instructions, int instruction_count) {
223 Instr* pc = reinterpret_cast<Instr*>(pc_);
224 Instr* instr = reinterpret_cast<Instr*>(instructions);
225 for (int i = 0; i < instruction_count; i++) {
226 *(pc + i) = *(instr + i);
227 }
228
229 // Indicate that code has changed.
230 CPU::FlushICache(pc_, instruction_count * Assembler::kInstrSize);
231}
232
233
234// Patch the code at the current PC with a call to the target address.
235// Additional guard instructions can be added if required.
236void RelocInfo::PatchCodeWithCall(Address target, int guard_bytes) {
237 // Patch the code at the current address with a call to the target.
238 UNIMPLEMENTED_MIPS();
239}
240
241
242// -----------------------------------------------------------------------------
243// Implementation of Operand and MemOperand.
244// See assembler-mips-inl.h for inlined constructors.
245
246Operand::Operand(Handle<Object> handle) {
247 rm_ = no_reg;
248 // Verify all Objects referred by code are NOT in new space.
249 Object* obj = *handle;
lrn@chromium.org7516f052011-03-30 08:52:27 +0000250 ASSERT(!HEAP->InNewSpace(obj));
ager@chromium.org5c838252010-02-19 08:53:10 +0000251 if (obj->IsHeapObject()) {
252 imm32_ = reinterpret_cast<intptr_t>(handle.location());
253 rmode_ = RelocInfo::EMBEDDED_OBJECT;
254 } else {
255 // No relocation needed.
256 imm32_ = reinterpret_cast<intptr_t>(obj);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000257 rmode_ = RelocInfo::NONE32;
ager@chromium.org5c838252010-02-19 08:53:10 +0000258 }
259}
260
lrn@chromium.org7516f052011-03-30 08:52:27 +0000261
262MemOperand::MemOperand(Register rm, int32_t offset) : Operand(rm) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000263 offset_ = offset;
264}
265
266
267// -----------------------------------------------------------------------------
lrn@chromium.org7516f052011-03-30 08:52:27 +0000268// Specific instructions, constants, and masks.
ager@chromium.org5c838252010-02-19 08:53:10 +0000269
lrn@chromium.org7516f052011-03-30 08:52:27 +0000270static const int kNegOffset = 0x00008000;
271// addiu(sp, sp, 4) aka Pop() operation or part of Pop(r)
272// operations as post-increment of sp.
fschneider@chromium.org7d10be52012-04-10 12:30:14 +0000273const Instr kPopInstruction = ADDIU | (kRegister_sp_Code << kRsShift)
274 | (kRegister_sp_Code << kRtShift) | (kPointerSize & kImm16Mask);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000275// addiu(sp, sp, -4) part of Push(r) operation as pre-decrement of sp.
fschneider@chromium.org7d10be52012-04-10 12:30:14 +0000276const Instr kPushInstruction = ADDIU | (kRegister_sp_Code << kRsShift)
277 | (kRegister_sp_Code << kRtShift) | (-kPointerSize & kImm16Mask);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000278// sw(r, MemOperand(sp, 0))
fschneider@chromium.org7d10be52012-04-10 12:30:14 +0000279const Instr kPushRegPattern = SW | (kRegister_sp_Code << kRsShift)
lrn@chromium.org7516f052011-03-30 08:52:27 +0000280 | (0 & kImm16Mask);
281// lw(r, MemOperand(sp, 0))
fschneider@chromium.org7d10be52012-04-10 12:30:14 +0000282const Instr kPopRegPattern = LW | (kRegister_sp_Code << kRsShift)
lrn@chromium.org7516f052011-03-30 08:52:27 +0000283 | (0 & kImm16Mask);
ager@chromium.org5c838252010-02-19 08:53:10 +0000284
fschneider@chromium.org7d10be52012-04-10 12:30:14 +0000285const Instr kLwRegFpOffsetPattern = LW | (kRegister_fp_Code << kRsShift)
lrn@chromium.org7516f052011-03-30 08:52:27 +0000286 | (0 & kImm16Mask);
287
fschneider@chromium.org7d10be52012-04-10 12:30:14 +0000288const Instr kSwRegFpOffsetPattern = SW | (kRegister_fp_Code << kRsShift)
lrn@chromium.org7516f052011-03-30 08:52:27 +0000289 | (0 & kImm16Mask);
290
fschneider@chromium.org7d10be52012-04-10 12:30:14 +0000291const Instr kLwRegFpNegOffsetPattern = LW | (kRegister_fp_Code << kRsShift)
lrn@chromium.org7516f052011-03-30 08:52:27 +0000292 | (kNegOffset & kImm16Mask);
293
fschneider@chromium.org7d10be52012-04-10 12:30:14 +0000294const Instr kSwRegFpNegOffsetPattern = SW | (kRegister_fp_Code << kRsShift)
lrn@chromium.org7516f052011-03-30 08:52:27 +0000295 | (kNegOffset & kImm16Mask);
296// A mask for the Rt register for push, pop, lw, sw instructions.
297const Instr kRtMask = kRtFieldMask;
298const Instr kLwSwInstrTypeMask = 0xffe00000;
299const Instr kLwSwInstrArgumentMask = ~kLwSwInstrTypeMask;
300const Instr kLwSwOffsetMask = kImm16Mask;
301
302
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000303Assembler::Assembler(Isolate* isolate, void* buffer, int buffer_size)
304 : AssemblerBase(isolate, buffer, buffer_size),
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000305 recorded_ast_id_(TypeFeedbackId::None()),
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +0000306 positions_recorder_(this) {
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000307 reloc_info_writer.Reposition(buffer_ + buffer_size_, pc_);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000308
309 last_trampoline_pool_end_ = 0;
310 no_trampoline_pool_before_ = 0;
311 trampoline_pool_blocked_nesting_ = 0;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +0000312 // We leave space (16 * kTrampolineSlotsSize)
313 // for BlockTrampolinePoolScope buffer.
314 next_buffer_check_ = kMaxBranchOffset - kTrampolineSlotsSize * 16;
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000315 internal_trampoline_exception_ = false;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000316 last_bound_pos_ = 0;
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000317
vegorov@chromium.org3cf47312011-06-29 13:20:01 +0000318 trampoline_emitted_ = false;
319 unbound_labels_count_ = 0;
320 block_buffer_growth_ = false;
321
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000322 ClearRecordedAstId();
ager@chromium.org5c838252010-02-19 08:53:10 +0000323}
324
325
ager@chromium.org5c838252010-02-19 08:53:10 +0000326void Assembler::GetCode(CodeDesc* desc) {
lrn@chromium.org7516f052011-03-30 08:52:27 +0000327 ASSERT(pc_ <= reloc_info_writer.pos()); // No overlap.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000328 // Set up code descriptor.
ager@chromium.org5c838252010-02-19 08:53:10 +0000329 desc->buffer = buffer_;
330 desc->buffer_size = buffer_size_;
331 desc->instr_size = pc_offset();
332 desc->reloc_size = (buffer_ + buffer_size_) - reloc_info_writer.pos();
333}
334
335
lrn@chromium.org7516f052011-03-30 08:52:27 +0000336void Assembler::Align(int m) {
337 ASSERT(m >= 4 && IsPowerOf2(m));
338 while ((pc_offset() & (m - 1)) != 0) {
339 nop();
340 }
341}
342
343
344void Assembler::CodeTargetAlign() {
345 // No advantage to aligning branch/call targets to more than
346 // single instruction, that I am aware of.
347 Align(4);
348}
349
350
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000351Register Assembler::GetRtReg(Instr instr) {
lrn@chromium.org7516f052011-03-30 08:52:27 +0000352 Register rt;
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000353 rt.code_ = (instr & kRtFieldMask) >> kRtShift;
lrn@chromium.org7516f052011-03-30 08:52:27 +0000354 return rt;
355}
356
357
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000358Register Assembler::GetRsReg(Instr instr) {
359 Register rs;
360 rs.code_ = (instr & kRsFieldMask) >> kRsShift;
361 return rs;
362}
363
364
365Register Assembler::GetRdReg(Instr instr) {
366 Register rd;
367 rd.code_ = (instr & kRdFieldMask) >> kRdShift;
368 return rd;
369}
370
371
372uint32_t Assembler::GetRt(Instr instr) {
373 return (instr & kRtFieldMask) >> kRtShift;
374}
375
376
377uint32_t Assembler::GetRtField(Instr instr) {
378 return instr & kRtFieldMask;
379}
380
381
382uint32_t Assembler::GetRs(Instr instr) {
383 return (instr & kRsFieldMask) >> kRsShift;
384}
385
386
387uint32_t Assembler::GetRsField(Instr instr) {
388 return instr & kRsFieldMask;
389}
390
391
392uint32_t Assembler::GetRd(Instr instr) {
393 return (instr & kRdFieldMask) >> kRdShift;
394}
395
396
397uint32_t Assembler::GetRdField(Instr instr) {
398 return instr & kRdFieldMask;
399}
400
401
402uint32_t Assembler::GetSa(Instr instr) {
403 return (instr & kSaFieldMask) >> kSaShift;
404}
405
406
407uint32_t Assembler::GetSaField(Instr instr) {
408 return instr & kSaFieldMask;
409}
410
411
412uint32_t Assembler::GetOpcodeField(Instr instr) {
413 return instr & kOpcodeMask;
414}
415
416
vegorov@chromium.org3cf47312011-06-29 13:20:01 +0000417uint32_t Assembler::GetFunction(Instr instr) {
418 return (instr & kFunctionFieldMask) >> kFunctionShift;
419}
420
421
422uint32_t Assembler::GetFunctionField(Instr instr) {
423 return instr & kFunctionFieldMask;
424}
425
426
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000427uint32_t Assembler::GetImmediate16(Instr instr) {
428 return instr & kImm16Mask;
429}
430
431
432uint32_t Assembler::GetLabelConst(Instr instr) {
433 return instr & ~kImm16Mask;
434}
435
436
lrn@chromium.org7516f052011-03-30 08:52:27 +0000437bool Assembler::IsPop(Instr instr) {
438 return (instr & ~kRtMask) == kPopRegPattern;
439}
440
441
442bool Assembler::IsPush(Instr instr) {
443 return (instr & ~kRtMask) == kPushRegPattern;
444}
445
446
447bool Assembler::IsSwRegFpOffset(Instr instr) {
448 return ((instr & kLwSwInstrTypeMask) == kSwRegFpOffsetPattern);
449}
450
451
452bool Assembler::IsLwRegFpOffset(Instr instr) {
453 return ((instr & kLwSwInstrTypeMask) == kLwRegFpOffsetPattern);
454}
455
456
457bool Assembler::IsSwRegFpNegOffset(Instr instr) {
458 return ((instr & (kLwSwInstrTypeMask | kNegOffset)) ==
459 kSwRegFpNegOffsetPattern);
460}
461
462
463bool Assembler::IsLwRegFpNegOffset(Instr instr) {
464 return ((instr & (kLwSwInstrTypeMask | kNegOffset)) ==
465 kLwRegFpNegOffsetPattern);
466}
467
468
ager@chromium.org5c838252010-02-19 08:53:10 +0000469// Labels refer to positions in the (to be) generated code.
470// There are bound, linked, and unused labels.
471//
472// Bound labels refer to known positions in the already
473// generated code. pos() is the position the label refers to.
474//
475// Linked labels refer to unknown positions in the code
476// to be generated; pos() is the position of the last
477// instruction using the label.
478
lrn@chromium.org7516f052011-03-30 08:52:27 +0000479// The link chain is terminated by a value in the instruction of -1,
480// which is an otherwise illegal value (branch -1 is inf loop).
481// The instruction 16-bit offset field addresses 32-bit words, but in
482// code is conv to an 18-bit value addressing bytes, hence the -4 value.
ager@chromium.org5c838252010-02-19 08:53:10 +0000483
ager@chromium.org5c838252010-02-19 08:53:10 +0000484const int kEndOfChain = -4;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +0000485// Determines the end of the Jump chain (a subset of the label link chain).
486const int kEndOfJumpChain = 0;
ager@chromium.org5c838252010-02-19 08:53:10 +0000487
lrn@chromium.org7516f052011-03-30 08:52:27 +0000488
489bool Assembler::IsBranch(Instr instr) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000490 uint32_t opcode = GetOpcodeField(instr);
491 uint32_t rt_field = GetRtField(instr);
492 uint32_t rs_field = GetRsField(instr);
493 uint32_t label_constant = GetLabelConst(instr);
ager@chromium.org5c838252010-02-19 08:53:10 +0000494 // Checks if the instruction is a branch.
495 return opcode == BEQ ||
496 opcode == BNE ||
497 opcode == BLEZ ||
498 opcode == BGTZ ||
499 opcode == BEQL ||
500 opcode == BNEL ||
501 opcode == BLEZL ||
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000502 opcode == BGTZL ||
ager@chromium.org5c838252010-02-19 08:53:10 +0000503 (opcode == REGIMM && (rt_field == BLTZ || rt_field == BGEZ ||
504 rt_field == BLTZAL || rt_field == BGEZAL)) ||
lrn@chromium.org7516f052011-03-30 08:52:27 +0000505 (opcode == COP1 && rs_field == BC1) || // Coprocessor branch.
506 label_constant == 0; // Emitted label const in reg-exp engine.
507}
508
509
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000510bool Assembler::IsBeq(Instr instr) {
511 return GetOpcodeField(instr) == BEQ;
512}
513
514
515bool Assembler::IsBne(Instr instr) {
516 return GetOpcodeField(instr) == BNE;
517}
518
519
vegorov@chromium.org3cf47312011-06-29 13:20:01 +0000520bool Assembler::IsJump(Instr instr) {
521 uint32_t opcode = GetOpcodeField(instr);
522 uint32_t rt_field = GetRtField(instr);
523 uint32_t rd_field = GetRdField(instr);
524 uint32_t function_field = GetFunctionField(instr);
525 // Checks if the instruction is a jump.
526 return opcode == J || opcode == JAL ||
527 (opcode == SPECIAL && rt_field == 0 &&
528 ((function_field == JALR) || (rd_field == 0 && (function_field == JR))));
529}
530
531
532bool Assembler::IsJ(Instr instr) {
533 uint32_t opcode = GetOpcodeField(instr);
534 // Checks if the instruction is a jump.
535 return opcode == J;
536}
537
538
lrn@chromium.org34e60782011-09-15 07:25:40 +0000539bool Assembler::IsJal(Instr instr) {
540 return GetOpcodeField(instr) == JAL;
541}
542
543bool Assembler::IsJr(Instr instr) {
544 return GetOpcodeField(instr) == SPECIAL && GetFunctionField(instr) == JR;
545}
546
547bool Assembler::IsJalr(Instr instr) {
548 return GetOpcodeField(instr) == SPECIAL && GetFunctionField(instr) == JALR;
549}
550
551
vegorov@chromium.org3cf47312011-06-29 13:20:01 +0000552bool Assembler::IsLui(Instr instr) {
553 uint32_t opcode = GetOpcodeField(instr);
554 // Checks if the instruction is a load upper immediate.
555 return opcode == LUI;
556}
557
558
559bool Assembler::IsOri(Instr instr) {
560 uint32_t opcode = GetOpcodeField(instr);
561 // Checks if the instruction is a load upper immediate.
562 return opcode == ORI;
563}
564
565
lrn@chromium.org7516f052011-03-30 08:52:27 +0000566bool Assembler::IsNop(Instr instr, unsigned int type) {
567 // See Assembler::nop(type).
568 ASSERT(type < 32);
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000569 uint32_t opcode = GetOpcodeField(instr);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000570 uint32_t function = GetFunctionField(instr);
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000571 uint32_t rt = GetRt(instr);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000572 uint32_t rd = GetRd(instr);
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000573 uint32_t sa = GetSa(instr);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000574
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000575 // Traditional mips nop == sll(zero_reg, zero_reg, 0)
576 // When marking non-zero type, use sll(zero_reg, at, type)
577 // to avoid use of mips ssnop and ehb special encodings
578 // of the sll instruction.
lrn@chromium.org7516f052011-03-30 08:52:27 +0000579
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000580 Register nop_rt_reg = (type == 0) ? zero_reg : at;
581 bool ret = (opcode == SPECIAL && function == SLL &&
582 rd == static_cast<uint32_t>(ToNumber(zero_reg)) &&
583 rt == static_cast<uint32_t>(ToNumber(nop_rt_reg)) &&
lrn@chromium.org7516f052011-03-30 08:52:27 +0000584 sa == type);
585
586 return ret;
587}
588
589
590int32_t Assembler::GetBranchOffset(Instr instr) {
591 ASSERT(IsBranch(instr));
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000592 return (static_cast<int16_t>(instr & kImm16Mask)) << 2;
lrn@chromium.org7516f052011-03-30 08:52:27 +0000593}
594
595
596bool Assembler::IsLw(Instr instr) {
597 return ((instr & kOpcodeMask) == LW);
598}
599
600
601int16_t Assembler::GetLwOffset(Instr instr) {
602 ASSERT(IsLw(instr));
603 return ((instr & kImm16Mask));
604}
605
606
607Instr Assembler::SetLwOffset(Instr instr, int16_t offset) {
608 ASSERT(IsLw(instr));
609
610 // We actually create a new lw instruction based on the original one.
611 Instr temp_instr = LW | (instr & kRsFieldMask) | (instr & kRtFieldMask)
612 | (offset & kImm16Mask);
613
614 return temp_instr;
615}
616
617
618bool Assembler::IsSw(Instr instr) {
619 return ((instr & kOpcodeMask) == SW);
620}
621
622
623Instr Assembler::SetSwOffset(Instr instr, int16_t offset) {
624 ASSERT(IsSw(instr));
625 return ((instr & ~kImm16Mask) | (offset & kImm16Mask));
626}
627
628
629bool Assembler::IsAddImmediate(Instr instr) {
630 return ((instr & kOpcodeMask) == ADDIU);
631}
632
633
634Instr Assembler::SetAddImmediateOffset(Instr instr, int16_t offset) {
635 ASSERT(IsAddImmediate(instr));
636 return ((instr & ~kImm16Mask) | (offset & kImm16Mask));
ager@chromium.org5c838252010-02-19 08:53:10 +0000637}
638
639
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000640bool Assembler::IsAndImmediate(Instr instr) {
641 return GetOpcodeField(instr) == ANDI;
642}
643
644
ager@chromium.org5c838252010-02-19 08:53:10 +0000645int Assembler::target_at(int32_t pos) {
646 Instr instr = instr_at(pos);
647 if ((instr & ~kImm16Mask) == 0) {
648 // Emitted label constant, not part of a branch.
lrn@chromium.org7516f052011-03-30 08:52:27 +0000649 if (instr == 0) {
650 return kEndOfChain;
651 } else {
652 int32_t imm18 =((instr & static_cast<int32_t>(kImm16Mask)) << 16) >> 14;
653 return (imm18 + pos);
654 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000655 }
vegorov@chromium.org3cf47312011-06-29 13:20:01 +0000656 // Check we have a branch or jump instruction.
657 ASSERT(IsBranch(instr) || IsJ(instr) || IsLui(instr));
ager@chromium.org5c838252010-02-19 08:53:10 +0000658 // Do NOT change this to <<2. We rely on arithmetic shifts here, assuming
659 // the compiler uses arithmectic shifts for signed integers.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +0000660 if (IsBranch(instr)) {
661 int32_t imm18 = ((instr & static_cast<int32_t>(kImm16Mask)) << 16) >> 14;
ager@chromium.org5c838252010-02-19 08:53:10 +0000662
vegorov@chromium.org3cf47312011-06-29 13:20:01 +0000663 if (imm18 == kEndOfChain) {
664 // EndOfChain sentinel is returned directly, not relative to pc or pos.
665 return kEndOfChain;
666 } else {
667 return pos + kBranchPCOffset + imm18;
668 }
669 } else if (IsLui(instr)) {
670 Instr instr_lui = instr_at(pos + 0 * Assembler::kInstrSize);
671 Instr instr_ori = instr_at(pos + 1 * Assembler::kInstrSize);
672 ASSERT(IsOri(instr_ori));
673 int32_t imm = (instr_lui & static_cast<int32_t>(kImm16Mask)) << kLuiShift;
674 imm |= (instr_ori & static_cast<int32_t>(kImm16Mask));
675
676 if (imm == kEndOfJumpChain) {
677 // EndOfChain sentinel is returned directly, not relative to pc or pos.
678 return kEndOfChain;
679 } else {
680 uint32_t instr_address = reinterpret_cast<int32_t>(buffer_ + pos);
681 int32_t delta = instr_address - imm;
682 ASSERT(pos > delta);
683 return pos - delta;
684 }
lrn@chromium.org7516f052011-03-30 08:52:27 +0000685 } else {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +0000686 int32_t imm28 = (instr & static_cast<int32_t>(kImm26Mask)) << 2;
687 if (imm28 == kEndOfJumpChain) {
688 // EndOfChain sentinel is returned directly, not relative to pc or pos.
689 return kEndOfChain;
690 } else {
691 uint32_t instr_address = reinterpret_cast<int32_t>(buffer_ + pos);
692 instr_address &= kImm28Mask;
693 int32_t delta = instr_address - imm28;
694 ASSERT(pos > delta);
695 return pos - delta;
696 }
lrn@chromium.org7516f052011-03-30 08:52:27 +0000697 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000698}
699
700
701void Assembler::target_at_put(int32_t pos, int32_t target_pos) {
702 Instr instr = instr_at(pos);
703 if ((instr & ~kImm16Mask) == 0) {
704 ASSERT(target_pos == kEndOfChain || target_pos >= 0);
705 // Emitted label constant, not part of a branch.
706 // Make label relative to Code* of generated Code object.
707 instr_at_put(pos, target_pos + (Code::kHeaderSize - kHeapObjectTag));
708 return;
709 }
710
vegorov@chromium.org3cf47312011-06-29 13:20:01 +0000711 ASSERT(IsBranch(instr) || IsJ(instr) || IsLui(instr));
712 if (IsBranch(instr)) {
713 int32_t imm18 = target_pos - (pos + kBranchPCOffset);
714 ASSERT((imm18 & 3) == 0);
ager@chromium.org5c838252010-02-19 08:53:10 +0000715
vegorov@chromium.org3cf47312011-06-29 13:20:01 +0000716 instr &= ~kImm16Mask;
717 int32_t imm16 = imm18 >> 2;
718 ASSERT(is_int16(imm16));
ager@chromium.org5c838252010-02-19 08:53:10 +0000719
vegorov@chromium.org3cf47312011-06-29 13:20:01 +0000720 instr_at_put(pos, instr | (imm16 & kImm16Mask));
721 } else if (IsLui(instr)) {
722 Instr instr_lui = instr_at(pos + 0 * Assembler::kInstrSize);
723 Instr instr_ori = instr_at(pos + 1 * Assembler::kInstrSize);
724 ASSERT(IsOri(instr_ori));
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000725 uint32_t imm = reinterpret_cast<uint32_t>(buffer_) + target_pos;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +0000726 ASSERT((imm & 3) == 0);
727
728 instr_lui &= ~kImm16Mask;
729 instr_ori &= ~kImm16Mask;
730
731 instr_at_put(pos + 0 * Assembler::kInstrSize,
732 instr_lui | ((imm & kHiMask) >> kLuiShift));
733 instr_at_put(pos + 1 * Assembler::kInstrSize,
734 instr_ori | (imm & kImm16Mask));
735 } else {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000736 uint32_t imm28 = reinterpret_cast<uint32_t>(buffer_) + target_pos;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +0000737 imm28 &= kImm28Mask;
738 ASSERT((imm28 & 3) == 0);
739
740 instr &= ~kImm26Mask;
741 uint32_t imm26 = imm28 >> 2;
742 ASSERT(is_uint26(imm26));
743
744 instr_at_put(pos, instr | (imm26 & kImm26Mask));
745 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000746}
747
748
749void Assembler::print(Label* L) {
750 if (L->is_unused()) {
751 PrintF("unused label\n");
752 } else if (L->is_bound()) {
753 PrintF("bound label to %d\n", L->pos());
754 } else if (L->is_linked()) {
755 Label l = *L;
756 PrintF("unbound label");
757 while (l.is_linked()) {
758 PrintF("@ %d ", l.pos());
759 Instr instr = instr_at(l.pos());
760 if ((instr & ~kImm16Mask) == 0) {
761 PrintF("value\n");
762 } else {
763 PrintF("%d\n", instr);
764 }
765 next(&l);
766 }
767 } else {
768 PrintF("label in inconsistent state (pos = %d)\n", L->pos_);
769 }
770}
771
772
773void Assembler::bind_to(Label* L, int pos) {
lrn@chromium.org7516f052011-03-30 08:52:27 +0000774 ASSERT(0 <= pos && pos <= pc_offset()); // Must have valid binding position.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +0000775 int32_t trampoline_pos = kInvalidSlotPos;
776 if (L->is_linked() && !trampoline_emitted_) {
777 unbound_labels_count_--;
778 next_buffer_check_ += kTrampolineSlotsSize;
779 }
780
ager@chromium.org5c838252010-02-19 08:53:10 +0000781 while (L->is_linked()) {
782 int32_t fixup_pos = L->pos();
lrn@chromium.org7516f052011-03-30 08:52:27 +0000783 int32_t dist = pos - fixup_pos;
784 next(L); // Call next before overwriting link with target at fixup_pos.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +0000785 Instr instr = instr_at(fixup_pos);
786 if (IsBranch(instr)) {
787 if (dist > kMaxBranchOffset) {
788 if (trampoline_pos == kInvalidSlotPos) {
789 trampoline_pos = get_trampoline_entry(fixup_pos);
790 CHECK(trampoline_pos != kInvalidSlotPos);
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000791 }
lrn@chromium.org7516f052011-03-30 08:52:27 +0000792 ASSERT((trampoline_pos - fixup_pos) <= kMaxBranchOffset);
793 target_at_put(fixup_pos, trampoline_pos);
794 fixup_pos = trampoline_pos;
795 dist = pos - fixup_pos;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +0000796 }
797 target_at_put(fixup_pos, pos);
798 } else {
799 ASSERT(IsJ(instr) || IsLui(instr));
800 target_at_put(fixup_pos, pos);
801 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000802 }
803 L->bind_to(pos);
804
805 // Keep track of the last bound label so we don't eliminate any instructions
806 // before a bound label.
807 if (pos > last_bound_pos_)
808 last_bound_pos_ = pos;
809}
810
811
ager@chromium.org5c838252010-02-19 08:53:10 +0000812void Assembler::bind(Label* L) {
lrn@chromium.org7516f052011-03-30 08:52:27 +0000813 ASSERT(!L->is_bound()); // Label can only be bound once.
ager@chromium.org5c838252010-02-19 08:53:10 +0000814 bind_to(L, pc_offset());
815}
816
817
818void Assembler::next(Label* L) {
819 ASSERT(L->is_linked());
820 int link = target_at(L->pos());
lrn@chromium.org7516f052011-03-30 08:52:27 +0000821 if (link == kEndOfChain) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000822 L->Unuse();
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +0000823 } else {
824 ASSERT(link >= 0);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000825 L->link_to(link);
ager@chromium.org5c838252010-02-19 08:53:10 +0000826 }
827}
828
vegorov@chromium.org3cf47312011-06-29 13:20:01 +0000829bool Assembler::is_near(Label* L) {
830 if (L->is_bound()) {
831 return ((pc_offset() - L->pos()) < kMaxBranchOffset - 4 * kInstrSize);
832 }
833 return false;
834}
ager@chromium.org5c838252010-02-19 08:53:10 +0000835
836// We have to use a temporary register for things that can be relocated even
837// if they can be encoded in the MIPS's 16 bits of immediate-offset instruction
838// space. There is no guarantee that the relocated location can be similarly
839// encoded.
lrn@chromium.org7516f052011-03-30 08:52:27 +0000840bool Assembler::MustUseReg(RelocInfo::Mode rmode) {
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +0000841 return !RelocInfo::IsNone(rmode);
ager@chromium.org5c838252010-02-19 08:53:10 +0000842}
843
ager@chromium.org5c838252010-02-19 08:53:10 +0000844void Assembler::GenInstrRegister(Opcode opcode,
845 Register rs,
846 Register rt,
847 Register rd,
848 uint16_t sa,
849 SecondaryField func) {
850 ASSERT(rd.is_valid() && rs.is_valid() && rt.is_valid() && is_uint5(sa));
851 Instr instr = opcode | (rs.code() << kRsShift) | (rt.code() << kRtShift)
852 | (rd.code() << kRdShift) | (sa << kSaShift) | func;
853 emit(instr);
854}
855
856
857void Assembler::GenInstrRegister(Opcode opcode,
lrn@chromium.org7516f052011-03-30 08:52:27 +0000858 Register rs,
859 Register rt,
860 uint16_t msb,
861 uint16_t lsb,
862 SecondaryField func) {
863 ASSERT(rs.is_valid() && rt.is_valid() && is_uint5(msb) && is_uint5(lsb));
864 Instr instr = opcode | (rs.code() << kRsShift) | (rt.code() << kRtShift)
865 | (msb << kRdShift) | (lsb << kSaShift) | func;
866 emit(instr);
867}
868
869
870void Assembler::GenInstrRegister(Opcode opcode,
ager@chromium.org5c838252010-02-19 08:53:10 +0000871 SecondaryField fmt,
872 FPURegister ft,
873 FPURegister fs,
874 FPURegister fd,
875 SecondaryField func) {
876 ASSERT(fd.is_valid() && fs.is_valid() && ft.is_valid());
ulan@chromium.org750145a2013-03-07 15:14:13 +0000877 ASSERT(IsEnabled(FPU));
lrn@chromium.org7516f052011-03-30 08:52:27 +0000878 Instr instr = opcode | fmt | (ft.code() << kFtShift) | (fs.code() << kFsShift)
879 | (fd.code() << kFdShift) | func;
ager@chromium.org5c838252010-02-19 08:53:10 +0000880 emit(instr);
881}
882
883
884void Assembler::GenInstrRegister(Opcode opcode,
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000885 FPURegister fr,
886 FPURegister ft,
887 FPURegister fs,
888 FPURegister fd,
889 SecondaryField func) {
890 ASSERT(fd.is_valid() && fr.is_valid() && fs.is_valid() && ft.is_valid());
ulan@chromium.org750145a2013-03-07 15:14:13 +0000891 ASSERT(IsEnabled(FPU));
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000892 Instr instr = opcode | (fr.code() << kFrShift) | (ft.code() << kFtShift)
893 | (fs.code() << kFsShift) | (fd.code() << kFdShift) | func;
894 emit(instr);
895}
896
897
898void Assembler::GenInstrRegister(Opcode opcode,
ager@chromium.org5c838252010-02-19 08:53:10 +0000899 SecondaryField fmt,
900 Register rt,
901 FPURegister fs,
902 FPURegister fd,
903 SecondaryField func) {
904 ASSERT(fd.is_valid() && fs.is_valid() && rt.is_valid());
ulan@chromium.org750145a2013-03-07 15:14:13 +0000905 ASSERT(IsEnabled(FPU));
ager@chromium.org5c838252010-02-19 08:53:10 +0000906 Instr instr = opcode | fmt | (rt.code() << kRtShift)
lrn@chromium.org7516f052011-03-30 08:52:27 +0000907 | (fs.code() << kFsShift) | (fd.code() << kFdShift) | func;
908 emit(instr);
909}
910
911
912void Assembler::GenInstrRegister(Opcode opcode,
913 SecondaryField fmt,
914 Register rt,
915 FPUControlRegister fs,
916 SecondaryField func) {
917 ASSERT(fs.is_valid() && rt.is_valid());
ulan@chromium.org750145a2013-03-07 15:14:13 +0000918 ASSERT(IsEnabled(FPU));
lrn@chromium.org7516f052011-03-30 08:52:27 +0000919 Instr instr =
920 opcode | fmt | (rt.code() << kRtShift) | (fs.code() << kFsShift) | func;
ager@chromium.org5c838252010-02-19 08:53:10 +0000921 emit(instr);
922}
923
924
925// Instructions with immediate value.
926// Registers are in the order of the instruction encoding, from left to right.
927void Assembler::GenInstrImmediate(Opcode opcode,
928 Register rs,
929 Register rt,
930 int32_t j) {
931 ASSERT(rs.is_valid() && rt.is_valid() && (is_int16(j) || is_uint16(j)));
932 Instr instr = opcode | (rs.code() << kRsShift) | (rt.code() << kRtShift)
933 | (j & kImm16Mask);
934 emit(instr);
935}
936
937
938void Assembler::GenInstrImmediate(Opcode opcode,
939 Register rs,
940 SecondaryField SF,
941 int32_t j) {
942 ASSERT(rs.is_valid() && (is_int16(j) || is_uint16(j)));
943 Instr instr = opcode | (rs.code() << kRsShift) | SF | (j & kImm16Mask);
944 emit(instr);
945}
946
947
948void Assembler::GenInstrImmediate(Opcode opcode,
949 Register rs,
950 FPURegister ft,
951 int32_t j) {
952 ASSERT(rs.is_valid() && ft.is_valid() && (is_int16(j) || is_uint16(j)));
ulan@chromium.org750145a2013-03-07 15:14:13 +0000953 ASSERT(IsEnabled(FPU));
ager@chromium.org5c838252010-02-19 08:53:10 +0000954 Instr instr = opcode | (rs.code() << kRsShift) | (ft.code() << kFtShift)
955 | (j & kImm16Mask);
956 emit(instr);
957}
958
959
ager@chromium.org5c838252010-02-19 08:53:10 +0000960void Assembler::GenInstrJump(Opcode opcode,
lrn@chromium.org34e60782011-09-15 07:25:40 +0000961 uint32_t address) {
lrn@chromium.org7516f052011-03-30 08:52:27 +0000962 BlockTrampolinePoolScope block_trampoline_pool(this);
ager@chromium.org5c838252010-02-19 08:53:10 +0000963 ASSERT(is_uint26(address));
964 Instr instr = opcode | address;
965 emit(instr);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000966 BlockTrampolinePoolFor(1); // For associated delay slot.
967}
968
969
vegorov@chromium.org3cf47312011-06-29 13:20:01 +0000970// Returns the next free trampoline entry.
971int32_t Assembler::get_trampoline_entry(int32_t pos) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000972 int32_t trampoline_entry = kInvalidSlotPos;
lrn@chromium.org7516f052011-03-30 08:52:27 +0000973
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000974 if (!internal_trampoline_exception_) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +0000975 if (trampoline_.start() > pos) {
976 trampoline_entry = trampoline_.take_slot();
lrn@chromium.org7516f052011-03-30 08:52:27 +0000977 }
vegorov@chromium.org3cf47312011-06-29 13:20:01 +0000978
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000979 if (kInvalidSlotPos == trampoline_entry) {
980 internal_trampoline_exception_ = true;
lrn@chromium.org7516f052011-03-30 08:52:27 +0000981 }
982 }
983 return trampoline_entry;
ager@chromium.org5c838252010-02-19 08:53:10 +0000984}
985
986
vegorov@chromium.org3cf47312011-06-29 13:20:01 +0000987uint32_t Assembler::jump_address(Label* L) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000988 int32_t target_pos;
lrn@chromium.org7516f052011-03-30 08:52:27 +0000989
ager@chromium.org5c838252010-02-19 08:53:10 +0000990 if (L->is_bound()) {
991 target_pos = L->pos();
992 } else {
993 if (L->is_linked()) {
lrn@chromium.org7516f052011-03-30 08:52:27 +0000994 target_pos = L->pos(); // L's link.
lrn@chromium.org7516f052011-03-30 08:52:27 +0000995 L->link_to(pc_offset());
ager@chromium.org5c838252010-02-19 08:53:10 +0000996 } else {
lrn@chromium.org7516f052011-03-30 08:52:27 +0000997 L->link_to(pc_offset());
vegorov@chromium.org3cf47312011-06-29 13:20:01 +0000998 return kEndOfJumpChain;
999 }
1000 }
1001
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001002 uint32_t imm = reinterpret_cast<uint32_t>(buffer_) + target_pos;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001003 ASSERT((imm & 3) == 0);
1004
1005 return imm;
1006}
1007
1008
1009int32_t Assembler::branch_offset(Label* L, bool jump_elimination_allowed) {
1010 int32_t target_pos;
1011
1012 if (L->is_bound()) {
1013 target_pos = L->pos();
1014 } else {
1015 if (L->is_linked()) {
1016 target_pos = L->pos();
1017 L->link_to(pc_offset());
1018 } else {
1019 L->link_to(pc_offset());
1020 if (!trampoline_emitted_) {
1021 unbound_labels_count_++;
1022 next_buffer_check_ -= kTrampolineSlotsSize;
1023 }
lrn@chromium.org7516f052011-03-30 08:52:27 +00001024 return kEndOfChain;
ager@chromium.org5c838252010-02-19 08:53:10 +00001025 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001026 }
1027
1028 int32_t offset = target_pos - (pc_offset() + kBranchPCOffset);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001029 ASSERT((offset & 3) == 0);
1030 ASSERT(is_int16(offset >> 2));
1031
ager@chromium.org5c838252010-02-19 08:53:10 +00001032 return offset;
1033}
1034
1035
1036void Assembler::label_at_put(Label* L, int at_offset) {
1037 int target_pos;
1038 if (L->is_bound()) {
1039 target_pos = L->pos();
lrn@chromium.org7516f052011-03-30 08:52:27 +00001040 instr_at_put(at_offset, target_pos + (Code::kHeaderSize - kHeapObjectTag));
ager@chromium.org5c838252010-02-19 08:53:10 +00001041 } else {
1042 if (L->is_linked()) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00001043 target_pos = L->pos(); // L's link.
1044 int32_t imm18 = target_pos - at_offset;
1045 ASSERT((imm18 & 3) == 0);
1046 int32_t imm16 = imm18 >> 2;
1047 ASSERT(is_int16(imm16));
1048 instr_at_put(at_offset, (imm16 & kImm16Mask));
ager@chromium.org5c838252010-02-19 08:53:10 +00001049 } else {
1050 target_pos = kEndOfChain;
lrn@chromium.org7516f052011-03-30 08:52:27 +00001051 instr_at_put(at_offset, 0);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001052 if (!trampoline_emitted_) {
1053 unbound_labels_count_++;
1054 next_buffer_check_ -= kTrampolineSlotsSize;
1055 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001056 }
1057 L->link_to(at_offset);
ager@chromium.org5c838252010-02-19 08:53:10 +00001058 }
1059}
1060
1061
1062//------- Branch and jump instructions --------
1063
1064void Assembler::b(int16_t offset) {
1065 beq(zero_reg, zero_reg, offset);
1066}
1067
1068
1069void Assembler::bal(int16_t offset) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00001070 positions_recorder()->WriteRecordedPositions();
ager@chromium.org5c838252010-02-19 08:53:10 +00001071 bgezal(zero_reg, offset);
1072}
1073
1074
1075void Assembler::beq(Register rs, Register rt, int16_t offset) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00001076 BlockTrampolinePoolScope block_trampoline_pool(this);
ager@chromium.org5c838252010-02-19 08:53:10 +00001077 GenInstrImmediate(BEQ, rs, rt, offset);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001078 BlockTrampolinePoolFor(1); // For associated delay slot.
ager@chromium.org5c838252010-02-19 08:53:10 +00001079}
1080
1081
1082void Assembler::bgez(Register rs, int16_t offset) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00001083 BlockTrampolinePoolScope block_trampoline_pool(this);
ager@chromium.org5c838252010-02-19 08:53:10 +00001084 GenInstrImmediate(REGIMM, rs, BGEZ, offset);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001085 BlockTrampolinePoolFor(1); // For associated delay slot.
ager@chromium.org5c838252010-02-19 08:53:10 +00001086}
1087
1088
1089void Assembler::bgezal(Register rs, int16_t offset) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00001090 BlockTrampolinePoolScope block_trampoline_pool(this);
1091 positions_recorder()->WriteRecordedPositions();
ager@chromium.org5c838252010-02-19 08:53:10 +00001092 GenInstrImmediate(REGIMM, rs, BGEZAL, offset);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001093 BlockTrampolinePoolFor(1); // For associated delay slot.
ager@chromium.org5c838252010-02-19 08:53:10 +00001094}
1095
1096
1097void Assembler::bgtz(Register rs, int16_t offset) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00001098 BlockTrampolinePoolScope block_trampoline_pool(this);
ager@chromium.org5c838252010-02-19 08:53:10 +00001099 GenInstrImmediate(BGTZ, rs, zero_reg, offset);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001100 BlockTrampolinePoolFor(1); // For associated delay slot.
ager@chromium.org5c838252010-02-19 08:53:10 +00001101}
1102
1103
1104void Assembler::blez(Register rs, int16_t offset) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00001105 BlockTrampolinePoolScope block_trampoline_pool(this);
ager@chromium.org5c838252010-02-19 08:53:10 +00001106 GenInstrImmediate(BLEZ, rs, zero_reg, offset);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001107 BlockTrampolinePoolFor(1); // For associated delay slot.
ager@chromium.org5c838252010-02-19 08:53:10 +00001108}
1109
1110
1111void Assembler::bltz(Register rs, int16_t offset) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00001112 BlockTrampolinePoolScope block_trampoline_pool(this);
ager@chromium.org5c838252010-02-19 08:53:10 +00001113 GenInstrImmediate(REGIMM, rs, BLTZ, offset);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001114 BlockTrampolinePoolFor(1); // For associated delay slot.
ager@chromium.org5c838252010-02-19 08:53:10 +00001115}
1116
1117
1118void Assembler::bltzal(Register rs, int16_t offset) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00001119 BlockTrampolinePoolScope block_trampoline_pool(this);
1120 positions_recorder()->WriteRecordedPositions();
ager@chromium.org5c838252010-02-19 08:53:10 +00001121 GenInstrImmediate(REGIMM, rs, BLTZAL, offset);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001122 BlockTrampolinePoolFor(1); // For associated delay slot.
ager@chromium.org5c838252010-02-19 08:53:10 +00001123}
1124
1125
1126void Assembler::bne(Register rs, Register rt, int16_t offset) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00001127 BlockTrampolinePoolScope block_trampoline_pool(this);
ager@chromium.org5c838252010-02-19 08:53:10 +00001128 GenInstrImmediate(BNE, rs, rt, offset);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001129 BlockTrampolinePoolFor(1); // For associated delay slot.
ager@chromium.org5c838252010-02-19 08:53:10 +00001130}
1131
1132
1133void Assembler::j(int32_t target) {
lrn@chromium.org34e60782011-09-15 07:25:40 +00001134#if DEBUG
1135 // Get pc of delay slot.
1136 uint32_t ipc = reinterpret_cast<uint32_t>(pc_ + 1 * kInstrSize);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001137 bool in_range = (ipc ^ static_cast<uint32_t>(target) >>
1138 (kImm26Bits + kImmFieldShift)) == 0;
lrn@chromium.org34e60782011-09-15 07:25:40 +00001139 ASSERT(in_range && ((target & 3) == 0));
1140#endif
ager@chromium.org5c838252010-02-19 08:53:10 +00001141 GenInstrJump(J, target >> 2);
1142}
1143
1144
1145void Assembler::jr(Register rs) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00001146 BlockTrampolinePoolScope block_trampoline_pool(this);
1147 if (rs.is(ra)) {
1148 positions_recorder()->WriteRecordedPositions();
1149 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001150 GenInstrRegister(SPECIAL, rs, zero_reg, zero_reg, 0, JR);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001151 BlockTrampolinePoolFor(1); // For associated delay slot.
ager@chromium.org5c838252010-02-19 08:53:10 +00001152}
1153
1154
1155void Assembler::jal(int32_t target) {
lrn@chromium.org34e60782011-09-15 07:25:40 +00001156#ifdef DEBUG
1157 // Get pc of delay slot.
1158 uint32_t ipc = reinterpret_cast<uint32_t>(pc_ + 1 * kInstrSize);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001159 bool in_range = (ipc ^ static_cast<uint32_t>(target) >>
1160 (kImm26Bits + kImmFieldShift)) == 0;
lrn@chromium.org34e60782011-09-15 07:25:40 +00001161 ASSERT(in_range && ((target & 3) == 0));
1162#endif
lrn@chromium.org7516f052011-03-30 08:52:27 +00001163 positions_recorder()->WriteRecordedPositions();
ager@chromium.org5c838252010-02-19 08:53:10 +00001164 GenInstrJump(JAL, target >> 2);
1165}
1166
1167
1168void Assembler::jalr(Register rs, Register rd) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00001169 BlockTrampolinePoolScope block_trampoline_pool(this);
1170 positions_recorder()->WriteRecordedPositions();
ager@chromium.org5c838252010-02-19 08:53:10 +00001171 GenInstrRegister(SPECIAL, rs, zero_reg, rd, 0, JALR);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001172 BlockTrampolinePoolFor(1); // For associated delay slot.
ager@chromium.org5c838252010-02-19 08:53:10 +00001173}
1174
1175
lrn@chromium.org34e60782011-09-15 07:25:40 +00001176void Assembler::j_or_jr(int32_t target, Register rs) {
1177 // Get pc of delay slot.
1178 uint32_t ipc = reinterpret_cast<uint32_t>(pc_ + 1 * kInstrSize);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001179 bool in_range = (ipc ^ static_cast<uint32_t>(target) >>
1180 (kImm26Bits + kImmFieldShift)) == 0;
lrn@chromium.org34e60782011-09-15 07:25:40 +00001181 if (in_range) {
1182 j(target);
1183 } else {
1184 jr(t9);
1185 }
1186}
1187
1188
1189void Assembler::jal_or_jalr(int32_t target, Register rs) {
1190 // Get pc of delay slot.
1191 uint32_t ipc = reinterpret_cast<uint32_t>(pc_ + 1 * kInstrSize);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001192 bool in_range = (ipc ^ static_cast<uint32_t>(target) >>
1193 (kImm26Bits+kImmFieldShift)) == 0;
lrn@chromium.org34e60782011-09-15 07:25:40 +00001194 if (in_range) {
1195 jal(target);
1196 } else {
1197 jalr(t9);
1198 }
1199}
1200
1201
ager@chromium.org5c838252010-02-19 08:53:10 +00001202//-------Data-processing-instructions---------
1203
1204// Arithmetic.
1205
ager@chromium.org5c838252010-02-19 08:53:10 +00001206void Assembler::addu(Register rd, Register rs, Register rt) {
1207 GenInstrRegister(SPECIAL, rs, rt, rd, 0, ADDU);
1208}
1209
1210
ager@chromium.org5c838252010-02-19 08:53:10 +00001211void Assembler::addiu(Register rd, Register rs, int32_t j) {
1212 GenInstrImmediate(ADDIU, rs, rd, j);
ager@chromium.org5c838252010-02-19 08:53:10 +00001213}
1214
1215
1216void Assembler::subu(Register rd, Register rs, Register rt) {
1217 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SUBU);
1218}
1219
1220
1221void Assembler::mul(Register rd, Register rs, Register rt) {
1222 GenInstrRegister(SPECIAL2, rs, rt, rd, 0, MUL);
1223}
1224
1225
1226void Assembler::mult(Register rs, Register rt) {
1227 GenInstrRegister(SPECIAL, rs, rt, zero_reg, 0, MULT);
1228}
1229
1230
1231void Assembler::multu(Register rs, Register rt) {
1232 GenInstrRegister(SPECIAL, rs, rt, zero_reg, 0, MULTU);
1233}
1234
1235
1236void Assembler::div(Register rs, Register rt) {
1237 GenInstrRegister(SPECIAL, rs, rt, zero_reg, 0, DIV);
1238}
1239
1240
1241void Assembler::divu(Register rs, Register rt) {
1242 GenInstrRegister(SPECIAL, rs, rt, zero_reg, 0, DIVU);
1243}
1244
1245
1246// Logical.
1247
1248void Assembler::and_(Register rd, Register rs, Register rt) {
1249 GenInstrRegister(SPECIAL, rs, rt, rd, 0, AND);
1250}
1251
1252
1253void Assembler::andi(Register rt, Register rs, int32_t j) {
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001254 ASSERT(is_uint16(j));
ager@chromium.org5c838252010-02-19 08:53:10 +00001255 GenInstrImmediate(ANDI, rs, rt, j);
1256}
1257
1258
1259void Assembler::or_(Register rd, Register rs, Register rt) {
1260 GenInstrRegister(SPECIAL, rs, rt, rd, 0, OR);
1261}
1262
1263
1264void Assembler::ori(Register rt, Register rs, int32_t j) {
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001265 ASSERT(is_uint16(j));
ager@chromium.org5c838252010-02-19 08:53:10 +00001266 GenInstrImmediate(ORI, rs, rt, j);
1267}
1268
1269
1270void Assembler::xor_(Register rd, Register rs, Register rt) {
1271 GenInstrRegister(SPECIAL, rs, rt, rd, 0, XOR);
1272}
1273
1274
1275void Assembler::xori(Register rt, Register rs, int32_t j) {
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001276 ASSERT(is_uint16(j));
ager@chromium.org5c838252010-02-19 08:53:10 +00001277 GenInstrImmediate(XORI, rs, rt, j);
1278}
1279
1280
1281void Assembler::nor(Register rd, Register rs, Register rt) {
1282 GenInstrRegister(SPECIAL, rs, rt, rd, 0, NOR);
1283}
1284
1285
1286// Shifts.
lrn@chromium.org7516f052011-03-30 08:52:27 +00001287void Assembler::sll(Register rd,
1288 Register rt,
1289 uint16_t sa,
1290 bool coming_from_nop) {
1291 // Don't allow nop instructions in the form sll zero_reg, zero_reg to be
1292 // generated using the sll instruction. They must be generated using
1293 // nop(int/NopMarkerTypes) or MarkCode(int/NopMarkerTypes) pseudo
1294 // instructions.
1295 ASSERT(coming_from_nop || !(rd.is(zero_reg) && rt.is(zero_reg)));
ager@chromium.org5c838252010-02-19 08:53:10 +00001296 GenInstrRegister(SPECIAL, zero_reg, rt, rd, sa, SLL);
1297}
1298
1299
1300void Assembler::sllv(Register rd, Register rt, Register rs) {
1301 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SLLV);
1302}
1303
1304
1305void Assembler::srl(Register rd, Register rt, uint16_t sa) {
1306 GenInstrRegister(SPECIAL, zero_reg, rt, rd, sa, SRL);
1307}
1308
1309
1310void Assembler::srlv(Register rd, Register rt, Register rs) {
1311 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SRLV);
1312}
1313
1314
1315void Assembler::sra(Register rd, Register rt, uint16_t sa) {
1316 GenInstrRegister(SPECIAL, zero_reg, rt, rd, sa, SRA);
1317}
1318
1319
1320void Assembler::srav(Register rd, Register rt, Register rs) {
1321 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SRAV);
1322}
1323
1324
lrn@chromium.org7516f052011-03-30 08:52:27 +00001325void Assembler::rotr(Register rd, Register rt, uint16_t sa) {
1326 // Should be called via MacroAssembler::Ror.
1327 ASSERT(rd.is_valid() && rt.is_valid() && is_uint5(sa));
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001328 ASSERT(kArchVariant == kMips32r2);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001329 Instr instr = SPECIAL | (1 << kRsShift) | (rt.code() << kRtShift)
1330 | (rd.code() << kRdShift) | (sa << kSaShift) | SRL;
1331 emit(instr);
1332}
1333
1334
1335void Assembler::rotrv(Register rd, Register rt, Register rs) {
1336 // Should be called via MacroAssembler::Ror.
1337 ASSERT(rd.is_valid() && rt.is_valid() && rs.is_valid() );
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001338 ASSERT(kArchVariant == kMips32r2);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001339 Instr instr = SPECIAL | (rs.code() << kRsShift) | (rt.code() << kRtShift)
1340 | (rd.code() << kRdShift) | (1 << kSaShift) | SRLV;
1341 emit(instr);
1342}
1343
1344
ager@chromium.org5c838252010-02-19 08:53:10 +00001345//------------Memory-instructions-------------
1346
lrn@chromium.org7516f052011-03-30 08:52:27 +00001347// Helper for base-reg + offset, when offset is larger than int16.
1348void Assembler::LoadRegPlusOffsetToAt(const MemOperand& src) {
1349 ASSERT(!src.rm().is(at));
1350 lui(at, src.offset_ >> kLuiShift);
1351 ori(at, at, src.offset_ & kImm16Mask); // Load 32-bit offset.
1352 addu(at, at, src.rm()); // Add base register.
1353}
1354
1355
ager@chromium.org5c838252010-02-19 08:53:10 +00001356void Assembler::lb(Register rd, const MemOperand& rs) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00001357 if (is_int16(rs.offset_)) {
1358 GenInstrImmediate(LB, rs.rm(), rd, rs.offset_);
1359 } else { // Offset > 16 bits, use multiple instructions to load.
1360 LoadRegPlusOffsetToAt(rs);
1361 GenInstrImmediate(LB, at, rd, 0); // Equiv to lb(rd, MemOperand(at, 0));
1362 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001363}
1364
1365
1366void Assembler::lbu(Register rd, const MemOperand& rs) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00001367 if (is_int16(rs.offset_)) {
1368 GenInstrImmediate(LBU, rs.rm(), rd, rs.offset_);
1369 } else { // Offset > 16 bits, use multiple instructions to load.
1370 LoadRegPlusOffsetToAt(rs);
1371 GenInstrImmediate(LBU, at, rd, 0); // Equiv to lbu(rd, MemOperand(at, 0));
1372 }
1373}
1374
1375
1376void Assembler::lh(Register rd, const MemOperand& rs) {
1377 if (is_int16(rs.offset_)) {
1378 GenInstrImmediate(LH, rs.rm(), rd, rs.offset_);
1379 } else { // Offset > 16 bits, use multiple instructions to load.
1380 LoadRegPlusOffsetToAt(rs);
1381 GenInstrImmediate(LH, at, rd, 0); // Equiv to lh(rd, MemOperand(at, 0));
1382 }
1383}
1384
1385
1386void Assembler::lhu(Register rd, const MemOperand& rs) {
1387 if (is_int16(rs.offset_)) {
1388 GenInstrImmediate(LHU, rs.rm(), rd, rs.offset_);
1389 } else { // Offset > 16 bits, use multiple instructions to load.
1390 LoadRegPlusOffsetToAt(rs);
1391 GenInstrImmediate(LHU, at, rd, 0); // Equiv to lhu(rd, MemOperand(at, 0));
1392 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001393}
1394
1395
1396void Assembler::lw(Register rd, const MemOperand& rs) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00001397 if (is_int16(rs.offset_)) {
1398 GenInstrImmediate(LW, rs.rm(), rd, rs.offset_);
1399 } else { // Offset > 16 bits, use multiple instructions to load.
1400 LoadRegPlusOffsetToAt(rs);
1401 GenInstrImmediate(LW, at, rd, 0); // Equiv to lw(rd, MemOperand(at, 0));
1402 }
lrn@chromium.org7516f052011-03-30 08:52:27 +00001403}
1404
1405
1406void Assembler::lwl(Register rd, const MemOperand& rs) {
1407 GenInstrImmediate(LWL, rs.rm(), rd, rs.offset_);
1408}
1409
1410
1411void Assembler::lwr(Register rd, const MemOperand& rs) {
1412 GenInstrImmediate(LWR, rs.rm(), rd, rs.offset_);
ager@chromium.org5c838252010-02-19 08:53:10 +00001413}
1414
1415
1416void Assembler::sb(Register rd, const MemOperand& rs) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00001417 if (is_int16(rs.offset_)) {
1418 GenInstrImmediate(SB, rs.rm(), rd, rs.offset_);
1419 } else { // Offset > 16 bits, use multiple instructions to store.
1420 LoadRegPlusOffsetToAt(rs);
1421 GenInstrImmediate(SB, at, rd, 0); // Equiv to sb(rd, MemOperand(at, 0));
1422 }
1423}
1424
1425
1426void Assembler::sh(Register rd, const MemOperand& rs) {
1427 if (is_int16(rs.offset_)) {
1428 GenInstrImmediate(SH, rs.rm(), rd, rs.offset_);
1429 } else { // Offset > 16 bits, use multiple instructions to store.
1430 LoadRegPlusOffsetToAt(rs);
1431 GenInstrImmediate(SH, at, rd, 0); // Equiv to sh(rd, MemOperand(at, 0));
1432 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001433}
1434
1435
1436void Assembler::sw(Register rd, const MemOperand& rs) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00001437 if (is_int16(rs.offset_)) {
1438 GenInstrImmediate(SW, rs.rm(), rd, rs.offset_);
1439 } else { // Offset > 16 bits, use multiple instructions to store.
1440 LoadRegPlusOffsetToAt(rs);
1441 GenInstrImmediate(SW, at, rd, 0); // Equiv to sw(rd, MemOperand(at, 0));
1442 }
lrn@chromium.org7516f052011-03-30 08:52:27 +00001443}
1444
1445
1446void Assembler::swl(Register rd, const MemOperand& rs) {
1447 GenInstrImmediate(SWL, rs.rm(), rd, rs.offset_);
1448}
1449
1450
1451void Assembler::swr(Register rd, const MemOperand& rs) {
1452 GenInstrImmediate(SWR, rs.rm(), rd, rs.offset_);
ager@chromium.org5c838252010-02-19 08:53:10 +00001453}
1454
1455
1456void Assembler::lui(Register rd, int32_t j) {
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001457 ASSERT(is_uint16(j));
ager@chromium.org5c838252010-02-19 08:53:10 +00001458 GenInstrImmediate(LUI, zero_reg, rd, j);
1459}
1460
1461
1462//-------------Misc-instructions--------------
1463
1464// Break / Trap instructions.
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00001465void Assembler::break_(uint32_t code, bool break_as_stop) {
ager@chromium.org5c838252010-02-19 08:53:10 +00001466 ASSERT((code & ~0xfffff) == 0);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00001467 // We need to invalidate breaks that could be stops as well because the
1468 // simulator expects a char pointer after the stop instruction.
1469 // See constants-mips.h for explanation.
1470 ASSERT((break_as_stop &&
1471 code <= kMaxStopCode &&
1472 code > kMaxWatchpointCode) ||
1473 (!break_as_stop &&
1474 (code > kMaxStopCode ||
1475 code <= kMaxWatchpointCode)));
ager@chromium.org5c838252010-02-19 08:53:10 +00001476 Instr break_instr = SPECIAL | BREAK | (code << 6);
1477 emit(break_instr);
1478}
1479
1480
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00001481void Assembler::stop(const char* msg, uint32_t code) {
1482 ASSERT(code > kMaxWatchpointCode);
1483 ASSERT(code <= kMaxStopCode);
1484#if defined(V8_HOST_ARCH_MIPS)
1485 break_(0x54321);
1486#else // V8_HOST_ARCH_MIPS
1487 BlockTrampolinePoolFor(2);
1488 // The Simulator will handle the stop instruction and get the message address.
1489 // On MIPS stop() is just a special kind of break_().
1490 break_(code, true);
1491 emit(reinterpret_cast<Instr>(msg));
1492#endif
1493}
1494
1495
ager@chromium.org5c838252010-02-19 08:53:10 +00001496void Assembler::tge(Register rs, Register rt, uint16_t code) {
1497 ASSERT(is_uint10(code));
1498 Instr instr = SPECIAL | TGE | rs.code() << kRsShift
1499 | rt.code() << kRtShift | code << 6;
1500 emit(instr);
1501}
1502
1503
1504void Assembler::tgeu(Register rs, Register rt, uint16_t code) {
1505 ASSERT(is_uint10(code));
1506 Instr instr = SPECIAL | TGEU | rs.code() << kRsShift
1507 | rt.code() << kRtShift | code << 6;
1508 emit(instr);
1509}
1510
1511
1512void Assembler::tlt(Register rs, Register rt, uint16_t code) {
1513 ASSERT(is_uint10(code));
1514 Instr instr =
1515 SPECIAL | TLT | rs.code() << kRsShift | rt.code() << kRtShift | code << 6;
1516 emit(instr);
1517}
1518
1519
1520void Assembler::tltu(Register rs, Register rt, uint16_t code) {
1521 ASSERT(is_uint10(code));
lrn@chromium.org7516f052011-03-30 08:52:27 +00001522 Instr instr =
1523 SPECIAL | TLTU | rs.code() << kRsShift
ager@chromium.org5c838252010-02-19 08:53:10 +00001524 | rt.code() << kRtShift | code << 6;
1525 emit(instr);
1526}
1527
1528
1529void Assembler::teq(Register rs, Register rt, uint16_t code) {
1530 ASSERT(is_uint10(code));
1531 Instr instr =
1532 SPECIAL | TEQ | rs.code() << kRsShift | rt.code() << kRtShift | code << 6;
1533 emit(instr);
1534}
1535
1536
1537void Assembler::tne(Register rs, Register rt, uint16_t code) {
1538 ASSERT(is_uint10(code));
1539 Instr instr =
1540 SPECIAL | TNE | rs.code() << kRsShift | rt.code() << kRtShift | code << 6;
1541 emit(instr);
1542}
1543
1544
1545// Move from HI/LO register.
1546
1547void Assembler::mfhi(Register rd) {
1548 GenInstrRegister(SPECIAL, zero_reg, zero_reg, rd, 0, MFHI);
1549}
1550
1551
1552void Assembler::mflo(Register rd) {
1553 GenInstrRegister(SPECIAL, zero_reg, zero_reg, rd, 0, MFLO);
1554}
1555
1556
1557// Set on less than instructions.
1558void Assembler::slt(Register rd, Register rs, Register rt) {
1559 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SLT);
1560}
1561
1562
1563void Assembler::sltu(Register rd, Register rs, Register rt) {
1564 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SLTU);
1565}
1566
1567
1568void Assembler::slti(Register rt, Register rs, int32_t j) {
1569 GenInstrImmediate(SLTI, rs, rt, j);
1570}
1571
1572
1573void Assembler::sltiu(Register rt, Register rs, int32_t j) {
1574 GenInstrImmediate(SLTIU, rs, rt, j);
1575}
1576
1577
lrn@chromium.org7516f052011-03-30 08:52:27 +00001578// Conditional move.
1579void Assembler::movz(Register rd, Register rs, Register rt) {
1580 GenInstrRegister(SPECIAL, rs, rt, rd, 0, MOVZ);
1581}
1582
1583
1584void Assembler::movn(Register rd, Register rs, Register rt) {
1585 GenInstrRegister(SPECIAL, rs, rt, rd, 0, MOVN);
1586}
1587
1588
1589void Assembler::movt(Register rd, Register rs, uint16_t cc) {
1590 Register rt;
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001591 rt.code_ = (cc & 0x0007) << 2 | 1;
lrn@chromium.org7516f052011-03-30 08:52:27 +00001592 GenInstrRegister(SPECIAL, rs, rt, rd, 0, MOVCI);
1593}
1594
1595
1596void Assembler::movf(Register rd, Register rs, uint16_t cc) {
1597 Register rt;
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001598 rt.code_ = (cc & 0x0007) << 2 | 0;
lrn@chromium.org7516f052011-03-30 08:52:27 +00001599 GenInstrRegister(SPECIAL, rs, rt, rd, 0, MOVCI);
1600}
1601
1602
1603// Bit twiddling.
1604void Assembler::clz(Register rd, Register rs) {
1605 // Clz instr requires same GPR number in 'rd' and 'rt' fields.
1606 GenInstrRegister(SPECIAL2, rs, rd, rd, 0, CLZ);
1607}
1608
1609
1610void Assembler::ins_(Register rt, Register rs, uint16_t pos, uint16_t size) {
1611 // Should be called via MacroAssembler::Ins.
1612 // Ins instr has 'rt' field as dest, and two uint5: msb, lsb.
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001613 ASSERT(kArchVariant == kMips32r2);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001614 GenInstrRegister(SPECIAL3, rs, rt, pos + size - 1, pos, INS);
1615}
1616
1617
1618void Assembler::ext_(Register rt, Register rs, uint16_t pos, uint16_t size) {
1619 // Should be called via MacroAssembler::Ext.
1620 // Ext instr has 'rt' field as dest, and two uint5: msb, lsb.
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001621 ASSERT(kArchVariant == kMips32r2);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001622 GenInstrRegister(SPECIAL3, rs, rt, size - 1, pos, EXT);
1623}
1624
1625
ager@chromium.org5c838252010-02-19 08:53:10 +00001626//--------Coprocessor-instructions----------------
1627
1628// Load, store, move.
1629void Assembler::lwc1(FPURegister fd, const MemOperand& src) {
1630 GenInstrImmediate(LWC1, src.rm(), fd, src.offset_);
1631}
1632
1633
1634void Assembler::ldc1(FPURegister fd, const MemOperand& src) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00001635 // Workaround for non-8-byte alignment of HeapNumber, convert 64-bit
1636 // load to two 32-bit loads.
1637 GenInstrImmediate(LWC1, src.rm(), fd, src.offset_);
1638 FPURegister nextfpreg;
1639 nextfpreg.setcode(fd.code() + 1);
1640 GenInstrImmediate(LWC1, src.rm(), nextfpreg, src.offset_ + 4);
ager@chromium.org5c838252010-02-19 08:53:10 +00001641}
1642
1643
1644void Assembler::swc1(FPURegister fd, const MemOperand& src) {
1645 GenInstrImmediate(SWC1, src.rm(), fd, src.offset_);
1646}
1647
1648
1649void Assembler::sdc1(FPURegister fd, const MemOperand& src) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00001650 // Workaround for non-8-byte alignment of HeapNumber, convert 64-bit
1651 // store to two 32-bit stores.
1652 GenInstrImmediate(SWC1, src.rm(), fd, src.offset_);
1653 FPURegister nextfpreg;
1654 nextfpreg.setcode(fd.code() + 1);
1655 GenInstrImmediate(SWC1, src.rm(), nextfpreg, src.offset_ + 4);
ager@chromium.org5c838252010-02-19 08:53:10 +00001656}
1657
1658
lrn@chromium.org7516f052011-03-30 08:52:27 +00001659void Assembler::mtc1(Register rt, FPURegister fs) {
ager@chromium.org5c838252010-02-19 08:53:10 +00001660 GenInstrRegister(COP1, MTC1, rt, fs, f0);
1661}
1662
1663
lrn@chromium.org7516f052011-03-30 08:52:27 +00001664void Assembler::mfc1(Register rt, FPURegister fs) {
ager@chromium.org5c838252010-02-19 08:53:10 +00001665 GenInstrRegister(COP1, MFC1, rt, fs, f0);
1666}
1667
1668
lrn@chromium.org7516f052011-03-30 08:52:27 +00001669void Assembler::ctc1(Register rt, FPUControlRegister fs) {
1670 GenInstrRegister(COP1, CTC1, rt, fs);
1671}
1672
1673
1674void Assembler::cfc1(Register rt, FPUControlRegister fs) {
1675 GenInstrRegister(COP1, CFC1, rt, fs);
1676}
1677
lrn@chromium.org34e60782011-09-15 07:25:40 +00001678void Assembler::DoubleAsTwoUInt32(double d, uint32_t* lo, uint32_t* hi) {
1679 uint64_t i;
1680 memcpy(&i, &d, 8);
1681
1682 *lo = i & 0xffffffff;
1683 *hi = i >> 32;
1684}
lrn@chromium.org7516f052011-03-30 08:52:27 +00001685
1686// Arithmetic.
1687
1688void Assembler::add_d(FPURegister fd, FPURegister fs, FPURegister ft) {
1689 GenInstrRegister(COP1, D, ft, fs, fd, ADD_D);
1690}
1691
1692
1693void Assembler::sub_d(FPURegister fd, FPURegister fs, FPURegister ft) {
1694 GenInstrRegister(COP1, D, ft, fs, fd, SUB_D);
1695}
1696
1697
1698void Assembler::mul_d(FPURegister fd, FPURegister fs, FPURegister ft) {
1699 GenInstrRegister(COP1, D, ft, fs, fd, MUL_D);
1700}
1701
1702
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001703void Assembler::madd_d(FPURegister fd, FPURegister fr, FPURegister fs,
1704 FPURegister ft) {
1705 GenInstrRegister(COP1X, fr, ft, fs, fd, MADD_D);
1706}
1707
1708
lrn@chromium.org7516f052011-03-30 08:52:27 +00001709void Assembler::div_d(FPURegister fd, FPURegister fs, FPURegister ft) {
1710 GenInstrRegister(COP1, D, ft, fs, fd, DIV_D);
1711}
1712
1713
1714void Assembler::abs_d(FPURegister fd, FPURegister fs) {
1715 GenInstrRegister(COP1, D, f0, fs, fd, ABS_D);
1716}
1717
1718
1719void Assembler::mov_d(FPURegister fd, FPURegister fs) {
1720 GenInstrRegister(COP1, D, f0, fs, fd, MOV_D);
1721}
1722
1723
1724void Assembler::neg_d(FPURegister fd, FPURegister fs) {
1725 GenInstrRegister(COP1, D, f0, fs, fd, NEG_D);
1726}
1727
1728
1729void Assembler::sqrt_d(FPURegister fd, FPURegister fs) {
1730 GenInstrRegister(COP1, D, f0, fs, fd, SQRT_D);
ager@chromium.org5c838252010-02-19 08:53:10 +00001731}
1732
1733
1734// Conversions.
1735
1736void Assembler::cvt_w_s(FPURegister fd, FPURegister fs) {
1737 GenInstrRegister(COP1, S, f0, fs, fd, CVT_W_S);
1738}
1739
1740
1741void Assembler::cvt_w_d(FPURegister fd, FPURegister fs) {
1742 GenInstrRegister(COP1, D, f0, fs, fd, CVT_W_D);
1743}
1744
1745
lrn@chromium.org7516f052011-03-30 08:52:27 +00001746void Assembler::trunc_w_s(FPURegister fd, FPURegister fs) {
1747 GenInstrRegister(COP1, S, f0, fs, fd, TRUNC_W_S);
1748}
1749
1750
1751void Assembler::trunc_w_d(FPURegister fd, FPURegister fs) {
1752 GenInstrRegister(COP1, D, f0, fs, fd, TRUNC_W_D);
1753}
1754
1755
1756void Assembler::round_w_s(FPURegister fd, FPURegister fs) {
1757 GenInstrRegister(COP1, S, f0, fs, fd, ROUND_W_S);
1758}
1759
1760
1761void Assembler::round_w_d(FPURegister fd, FPURegister fs) {
1762 GenInstrRegister(COP1, D, f0, fs, fd, ROUND_W_D);
1763}
1764
1765
1766void Assembler::floor_w_s(FPURegister fd, FPURegister fs) {
1767 GenInstrRegister(COP1, S, f0, fs, fd, FLOOR_W_S);
1768}
1769
1770
1771void Assembler::floor_w_d(FPURegister fd, FPURegister fs) {
1772 GenInstrRegister(COP1, D, f0, fs, fd, FLOOR_W_D);
1773}
1774
1775
1776void Assembler::ceil_w_s(FPURegister fd, FPURegister fs) {
1777 GenInstrRegister(COP1, S, f0, fs, fd, CEIL_W_S);
1778}
1779
1780
1781void Assembler::ceil_w_d(FPURegister fd, FPURegister fs) {
1782 GenInstrRegister(COP1, D, f0, fs, fd, CEIL_W_D);
1783}
1784
1785
ager@chromium.org5c838252010-02-19 08:53:10 +00001786void Assembler::cvt_l_s(FPURegister fd, FPURegister fs) {
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001787 ASSERT(kArchVariant == kMips32r2);
ager@chromium.org5c838252010-02-19 08:53:10 +00001788 GenInstrRegister(COP1, S, f0, fs, fd, CVT_L_S);
1789}
1790
1791
1792void Assembler::cvt_l_d(FPURegister fd, FPURegister fs) {
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001793 ASSERT(kArchVariant == kMips32r2);
ager@chromium.org5c838252010-02-19 08:53:10 +00001794 GenInstrRegister(COP1, D, f0, fs, fd, CVT_L_D);
1795}
1796
1797
lrn@chromium.org7516f052011-03-30 08:52:27 +00001798void Assembler::trunc_l_s(FPURegister fd, FPURegister fs) {
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001799 ASSERT(kArchVariant == kMips32r2);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001800 GenInstrRegister(COP1, S, f0, fs, fd, TRUNC_L_S);
1801}
1802
1803
1804void Assembler::trunc_l_d(FPURegister fd, FPURegister fs) {
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001805 ASSERT(kArchVariant == kMips32r2);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001806 GenInstrRegister(COP1, D, f0, fs, fd, TRUNC_L_D);
1807}
1808
1809
1810void Assembler::round_l_s(FPURegister fd, FPURegister fs) {
1811 GenInstrRegister(COP1, S, f0, fs, fd, ROUND_L_S);
1812}
1813
1814
1815void Assembler::round_l_d(FPURegister fd, FPURegister fs) {
1816 GenInstrRegister(COP1, D, f0, fs, fd, ROUND_L_D);
1817}
1818
1819
1820void Assembler::floor_l_s(FPURegister fd, FPURegister fs) {
1821 GenInstrRegister(COP1, S, f0, fs, fd, FLOOR_L_S);
1822}
1823
1824
1825void Assembler::floor_l_d(FPURegister fd, FPURegister fs) {
1826 GenInstrRegister(COP1, D, f0, fs, fd, FLOOR_L_D);
1827}
1828
1829
1830void Assembler::ceil_l_s(FPURegister fd, FPURegister fs) {
1831 GenInstrRegister(COP1, S, f0, fs, fd, CEIL_L_S);
1832}
1833
1834
1835void Assembler::ceil_l_d(FPURegister fd, FPURegister fs) {
1836 GenInstrRegister(COP1, D, f0, fs, fd, CEIL_L_D);
1837}
1838
1839
ager@chromium.org5c838252010-02-19 08:53:10 +00001840void Assembler::cvt_s_w(FPURegister fd, FPURegister fs) {
1841 GenInstrRegister(COP1, W, f0, fs, fd, CVT_S_W);
1842}
1843
1844
1845void Assembler::cvt_s_l(FPURegister fd, FPURegister fs) {
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001846 ASSERT(kArchVariant == kMips32r2);
ager@chromium.org5c838252010-02-19 08:53:10 +00001847 GenInstrRegister(COP1, L, f0, fs, fd, CVT_S_L);
1848}
1849
1850
1851void Assembler::cvt_s_d(FPURegister fd, FPURegister fs) {
1852 GenInstrRegister(COP1, D, f0, fs, fd, CVT_S_D);
1853}
1854
1855
1856void Assembler::cvt_d_w(FPURegister fd, FPURegister fs) {
1857 GenInstrRegister(COP1, W, f0, fs, fd, CVT_D_W);
1858}
1859
1860
1861void Assembler::cvt_d_l(FPURegister fd, FPURegister fs) {
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001862 ASSERT(kArchVariant == kMips32r2);
ager@chromium.org5c838252010-02-19 08:53:10 +00001863 GenInstrRegister(COP1, L, f0, fs, fd, CVT_D_L);
1864}
1865
1866
1867void Assembler::cvt_d_s(FPURegister fd, FPURegister fs) {
1868 GenInstrRegister(COP1, S, f0, fs, fd, CVT_D_S);
1869}
1870
1871
1872// Conditions.
1873void Assembler::c(FPUCondition cond, SecondaryField fmt,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001874 FPURegister fs, FPURegister ft, uint16_t cc) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00001875 ASSERT(IsEnabled(FPU));
ager@chromium.org5c838252010-02-19 08:53:10 +00001876 ASSERT(is_uint3(cc));
1877 ASSERT((fmt & ~(31 << kRsShift)) == 0);
1878 Instr instr = COP1 | fmt | ft.code() << 16 | fs.code() << kFsShift
1879 | cc << 8 | 3 << 4 | cond;
1880 emit(instr);
1881}
1882
1883
lrn@chromium.org7516f052011-03-30 08:52:27 +00001884void Assembler::fcmp(FPURegister src1, const double src2,
1885 FPUCondition cond) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00001886 ASSERT(IsEnabled(FPU));
lrn@chromium.org7516f052011-03-30 08:52:27 +00001887 ASSERT(src2 == 0.0);
1888 mtc1(zero_reg, f14);
1889 cvt_d_w(f14, f14);
1890 c(cond, D, src1, f14, 0);
1891}
1892
1893
ager@chromium.org5c838252010-02-19 08:53:10 +00001894void Assembler::bc1f(int16_t offset, uint16_t cc) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00001895 ASSERT(IsEnabled(FPU));
ager@chromium.org5c838252010-02-19 08:53:10 +00001896 ASSERT(is_uint3(cc));
1897 Instr instr = COP1 | BC1 | cc << 18 | 0 << 16 | (offset & kImm16Mask);
1898 emit(instr);
1899}
1900
1901
1902void Assembler::bc1t(int16_t offset, uint16_t cc) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00001903 ASSERT(IsEnabled(FPU));
ager@chromium.org5c838252010-02-19 08:53:10 +00001904 ASSERT(is_uint3(cc));
1905 Instr instr = COP1 | BC1 | cc << 18 | 1 << 16 | (offset & kImm16Mask);
1906 emit(instr);
1907}
1908
1909
1910// Debugging.
1911void Assembler::RecordJSReturn() {
lrn@chromium.org7516f052011-03-30 08:52:27 +00001912 positions_recorder()->WriteRecordedPositions();
ager@chromium.org5c838252010-02-19 08:53:10 +00001913 CheckBuffer();
1914 RecordRelocInfo(RelocInfo::JS_RETURN);
1915}
1916
1917
lrn@chromium.org7516f052011-03-30 08:52:27 +00001918void Assembler::RecordDebugBreakSlot() {
1919 positions_recorder()->WriteRecordedPositions();
1920 CheckBuffer();
1921 RecordRelocInfo(RelocInfo::DEBUG_BREAK_SLOT);
1922}
1923
1924
ager@chromium.org5c838252010-02-19 08:53:10 +00001925void Assembler::RecordComment(const char* msg) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00001926 if (FLAG_code_comments) {
ager@chromium.org5c838252010-02-19 08:53:10 +00001927 CheckBuffer();
1928 RecordRelocInfo(RelocInfo::COMMENT, reinterpret_cast<intptr_t>(msg));
1929 }
1930}
1931
1932
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001933int Assembler::RelocateInternalReference(byte* pc, intptr_t pc_delta) {
1934 Instr instr = instr_at(pc);
1935 ASSERT(IsJ(instr) || IsLui(instr));
1936 if (IsLui(instr)) {
1937 Instr instr_lui = instr_at(pc + 0 * Assembler::kInstrSize);
1938 Instr instr_ori = instr_at(pc + 1 * Assembler::kInstrSize);
1939 ASSERT(IsOri(instr_ori));
1940 int32_t imm = (instr_lui & static_cast<int32_t>(kImm16Mask)) << kLuiShift;
1941 imm |= (instr_ori & static_cast<int32_t>(kImm16Mask));
1942 if (imm == kEndOfJumpChain) {
1943 return 0; // Number of instructions patched.
1944 }
1945 imm += pc_delta;
1946 ASSERT((imm & 3) == 0);
1947
1948 instr_lui &= ~kImm16Mask;
1949 instr_ori &= ~kImm16Mask;
1950
1951 instr_at_put(pc + 0 * Assembler::kInstrSize,
1952 instr_lui | ((imm >> kLuiShift) & kImm16Mask));
1953 instr_at_put(pc + 1 * Assembler::kInstrSize,
1954 instr_ori | (imm & kImm16Mask));
1955 return 2; // Number of instructions patched.
1956 } else {
1957 uint32_t imm28 = (instr & static_cast<int32_t>(kImm26Mask)) << 2;
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001958 if (static_cast<int32_t>(imm28) == kEndOfJumpChain) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001959 return 0; // Number of instructions patched.
1960 }
1961 imm28 += pc_delta;
1962 imm28 &= kImm28Mask;
1963 ASSERT((imm28 & 3) == 0);
1964
1965 instr &= ~kImm26Mask;
1966 uint32_t imm26 = imm28 >> 2;
1967 ASSERT(is_uint26(imm26));
1968
1969 instr_at_put(pc, instr | (imm26 & kImm26Mask));
1970 return 1; // Number of instructions patched.
1971 }
1972}
1973
1974
ager@chromium.org5c838252010-02-19 08:53:10 +00001975void Assembler::GrowBuffer() {
1976 if (!own_buffer_) FATAL("external code buffer is too small");
1977
1978 // Compute new buffer size.
lrn@chromium.org7516f052011-03-30 08:52:27 +00001979 CodeDesc desc; // The new buffer.
ager@chromium.org5c838252010-02-19 08:53:10 +00001980 if (buffer_size_ < 4*KB) {
1981 desc.buffer_size = 4*KB;
1982 } else if (buffer_size_ < 1*MB) {
1983 desc.buffer_size = 2*buffer_size_;
1984 } else {
1985 desc.buffer_size = buffer_size_ + 1*MB;
1986 }
lrn@chromium.org7516f052011-03-30 08:52:27 +00001987 CHECK_GT(desc.buffer_size, 0); // No overflow.
ager@chromium.org5c838252010-02-19 08:53:10 +00001988
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001989 // Set up new buffer.
ager@chromium.org5c838252010-02-19 08:53:10 +00001990 desc.buffer = NewArray<byte>(desc.buffer_size);
1991
1992 desc.instr_size = pc_offset();
1993 desc.reloc_size = (buffer_ + buffer_size_) - reloc_info_writer.pos();
1994
1995 // Copy the data.
1996 int pc_delta = desc.buffer - buffer_;
1997 int rc_delta = (desc.buffer + desc.buffer_size) - (buffer_ + buffer_size_);
1998 memmove(desc.buffer, buffer_, desc.instr_size);
1999 memmove(reloc_info_writer.pos() + rc_delta,
2000 reloc_info_writer.pos(), desc.reloc_size);
2001
2002 // Switch buffers.
2003 DeleteArray(buffer_);
2004 buffer_ = desc.buffer;
2005 buffer_size_ = desc.buffer_size;
2006 pc_ += pc_delta;
2007 reloc_info_writer.Reposition(reloc_info_writer.pos() + rc_delta,
2008 reloc_info_writer.last_pc() + pc_delta);
2009
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00002010 // Relocate runtime entries.
2011 for (RelocIterator it(desc); !it.done(); it.next()) {
2012 RelocInfo::Mode rmode = it.rinfo()->rmode();
2013 if (rmode == RelocInfo::INTERNAL_REFERENCE) {
2014 byte* p = reinterpret_cast<byte*>(it.rinfo()->pc());
2015 RelocateInternalReference(p, pc_delta);
2016 }
2017 }
ager@chromium.org5c838252010-02-19 08:53:10 +00002018
2019 ASSERT(!overflow());
2020}
2021
2022
lrn@chromium.org7516f052011-03-30 08:52:27 +00002023void Assembler::db(uint8_t data) {
2024 CheckBuffer();
2025 *reinterpret_cast<uint8_t*>(pc_) = data;
2026 pc_ += sizeof(uint8_t);
2027}
2028
2029
2030void Assembler::dd(uint32_t data) {
2031 CheckBuffer();
2032 *reinterpret_cast<uint32_t*>(pc_) = data;
2033 pc_ += sizeof(uint32_t);
2034}
2035
2036
ager@chromium.org5c838252010-02-19 08:53:10 +00002037void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002038 // We do not try to reuse pool constants.
2039 RelocInfo rinfo(pc_, rmode, data, NULL);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002040 if (rmode >= RelocInfo::JS_RETURN && rmode <= RelocInfo::DEBUG_BREAK_SLOT) {
ager@chromium.org5c838252010-02-19 08:53:10 +00002041 // Adjust code for new modes.
lrn@chromium.org7516f052011-03-30 08:52:27 +00002042 ASSERT(RelocInfo::IsDebugBreakSlot(rmode)
2043 || RelocInfo::IsJSReturn(rmode)
ager@chromium.org5c838252010-02-19 08:53:10 +00002044 || RelocInfo::IsComment(rmode)
2045 || RelocInfo::IsPosition(rmode));
2046 // These modes do not need an entry in the constant pool.
2047 }
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00002048 if (!RelocInfo::IsNone(rinfo.rmode())) {
ager@chromium.org5c838252010-02-19 08:53:10 +00002049 // Don't record external references unless the heap will be serialized.
lrn@chromium.org34e60782011-09-15 07:25:40 +00002050 if (rmode == RelocInfo::EXTERNAL_REFERENCE) {
2051#ifdef DEBUG
2052 if (!Serializer::enabled()) {
2053 Serializer::TooLateToEnableNow();
2054 }
2055#endif
2056 if (!Serializer::enabled() && !emit_debug_code()) {
2057 return;
2058 }
ager@chromium.org5c838252010-02-19 08:53:10 +00002059 }
lrn@chromium.org7516f052011-03-30 08:52:27 +00002060 ASSERT(buffer_space() >= kMaxRelocSize); // Too late to grow buffer here.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002061 if (rmode == RelocInfo::CODE_TARGET_WITH_ID) {
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002062 RelocInfo reloc_info_with_ast_id(pc_,
2063 rmode,
2064 RecordedAstId().ToInt(),
2065 NULL);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002066 ClearRecordedAstId();
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002067 reloc_info_writer.Write(&reloc_info_with_ast_id);
2068 } else {
2069 reloc_info_writer.Write(&rinfo);
2070 }
ager@chromium.org5c838252010-02-19 08:53:10 +00002071 }
2072}
2073
2074
lrn@chromium.org7516f052011-03-30 08:52:27 +00002075void Assembler::BlockTrampolinePoolFor(int instructions) {
2076 BlockTrampolinePoolBefore(pc_offset() + instructions * kInstrSize);
2077}
2078
2079
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00002080void Assembler::CheckTrampolinePool() {
lrn@chromium.org7516f052011-03-30 08:52:27 +00002081 // Some small sequences of instructions must not be broken up by the
2082 // insertion of a trampoline pool; such sequences are protected by setting
2083 // either trampoline_pool_blocked_nesting_ or no_trampoline_pool_before_,
2084 // which are both checked here. Also, recursive calls to CheckTrampolinePool
2085 // are blocked by trampoline_pool_blocked_nesting_.
2086 if ((trampoline_pool_blocked_nesting_ > 0) ||
2087 (pc_offset() < no_trampoline_pool_before_)) {
2088 // Emission is currently blocked; make sure we try again as soon as
2089 // possible.
2090 if (trampoline_pool_blocked_nesting_ > 0) {
2091 next_buffer_check_ = pc_offset() + kInstrSize;
2092 } else {
2093 next_buffer_check_ = no_trampoline_pool_before_;
2094 }
2095 return;
2096 }
2097
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00002098 ASSERT(!trampoline_emitted_);
2099 ASSERT(unbound_labels_count_ >= 0);
2100 if (unbound_labels_count_ > 0) {
2101 // First we emit jump (2 instructions), then we emit trampoline pool.
2102 { BlockTrampolinePoolScope block_trampoline_pool(this);
2103 Label after_pool;
lrn@chromium.org7516f052011-03-30 08:52:27 +00002104 b(&after_pool);
2105 nop();
lrn@chromium.org7516f052011-03-30 08:52:27 +00002106
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00002107 int pool_start = pc_offset();
2108 for (int i = 0; i < unbound_labels_count_; i++) {
2109 uint32_t imm32;
2110 imm32 = jump_address(&after_pool);
2111 { BlockGrowBufferScope block_buf_growth(this);
2112 // Buffer growth (and relocation) must be blocked for internal
2113 // references until associated instructions are emitted and available
2114 // to be patched.
2115 RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE);
2116 lui(at, (imm32 & kHiMask) >> kLuiShift);
2117 ori(at, at, (imm32 & kImm16Mask));
2118 }
2119 jr(at);
2120 nop();
2121 }
2122 bind(&after_pool);
2123 trampoline_ = Trampoline(pool_start, unbound_labels_count_);
2124
2125 trampoline_emitted_ = true;
2126 // As we are only going to emit trampoline once, we need to prevent any
2127 // further emission.
2128 next_buffer_check_ = kMaxInt;
2129 }
2130 } else {
2131 // Number of branches to unbound label at this point is zero, so we can
2132 // move next buffer check to maximum.
2133 next_buffer_check_ = pc_offset() +
2134 kMaxBranchOffset - kTrampolineSlotsSize * 16;
lrn@chromium.org7516f052011-03-30 08:52:27 +00002135 }
2136 return;
2137}
2138
2139
ager@chromium.org5c838252010-02-19 08:53:10 +00002140Address Assembler::target_address_at(Address pc) {
2141 Instr instr1 = instr_at(pc);
2142 Instr instr2 = instr_at(pc + kInstrSize);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002143 // Interpret 2 instructions generated by li: lui/ori
2144 if ((GetOpcodeField(instr1) == LUI) && (GetOpcodeField(instr2) == ORI)) {
2145 // Assemble the 32 bit value.
ager@chromium.org5c838252010-02-19 08:53:10 +00002146 return reinterpret_cast<Address>(
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002147 (GetImmediate16(instr1) << 16) | GetImmediate16(instr2));
ager@chromium.org5c838252010-02-19 08:53:10 +00002148 }
2149
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002150 // We should never get here, force a bad address if we do.
ager@chromium.org5c838252010-02-19 08:53:10 +00002151 UNREACHABLE();
2152 return (Address)0x0;
2153}
2154
2155
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +00002156// MIPS and ia32 use opposite encoding for qNaN and sNaN, such that ia32
2157// qNaN is a MIPS sNaN, and ia32 sNaN is MIPS qNaN. If running from a heap
2158// snapshot generated on ia32, the resulting MIPS sNaN must be quieted.
2159// OS::nan_value() returns a qNaN.
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00002160void Assembler::QuietNaN(HeapObject* object) {
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +00002161 HeapNumber::cast(object)->set_value(OS::nan_value());
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00002162}
2163
2164
lrn@chromium.org34e60782011-09-15 07:25:40 +00002165// On Mips, a target address is stored in a lui/ori instruction pair, each
2166// of which load 16 bits of the 32-bit address to a register.
2167// Patching the address must replace both instr, and flush the i-cache.
2168//
2169// There is an optimization below, which emits a nop when the address
2170// fits in just 16 bits. This is unlikely to help, and should be benchmarked,
2171// and possibly removed.
ager@chromium.org5c838252010-02-19 08:53:10 +00002172void Assembler::set_target_address_at(Address pc, Address target) {
ager@chromium.org5c838252010-02-19 08:53:10 +00002173 Instr instr2 = instr_at(pc + kInstrSize);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002174 uint32_t rt_code = GetRtField(instr2);
ager@chromium.org5c838252010-02-19 08:53:10 +00002175 uint32_t* p = reinterpret_cast<uint32_t*>(pc);
2176 uint32_t itarget = reinterpret_cast<uint32_t>(target);
2177
lrn@chromium.org34e60782011-09-15 07:25:40 +00002178#ifdef DEBUG
2179 // Check we have the result from a li macro-instruction, using instr pair.
2180 Instr instr1 = instr_at(pc);
2181 CHECK((GetOpcodeField(instr1) == LUI && GetOpcodeField(instr2) == ORI));
2182#endif
2183
2184 // Must use 2 instructions to insure patchable code => just use lui and ori.
2185 // lui rt, upper-16.
2186 // ori rt rt, lower-16.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002187 *p = LUI | rt_code | ((itarget & kHiMask) >> kLuiShift);
2188 *(p+1) = ORI | rt_code | (rt_code << 5) | (itarget & kImm16Mask);
ager@chromium.org5c838252010-02-19 08:53:10 +00002189
lrn@chromium.org34e60782011-09-15 07:25:40 +00002190 // The following code is an optimization for the common case of Call()
2191 // or Jump() which is load to register, and jump through register:
2192 // li(t9, address); jalr(t9) (or jr(t9)).
2193 // If the destination address is in the same 256 MB page as the call, it
2194 // is faster to do a direct jal, or j, rather than jump thru register, since
2195 // that lets the cpu pipeline prefetch the target address. However each
2196 // time the address above is patched, we have to patch the direct jal/j
2197 // instruction, as well as possibly revert to jalr/jr if we now cross a
2198 // 256 MB page. Note that with the jal/j instructions, we do not need to
2199 // load the register, but that code is left, since it makes it easy to
2200 // revert this process. A further optimization could try replacing the
2201 // li sequence with nops.
2202 // This optimization can only be applied if the rt-code from instr2 is the
2203 // register used for the jalr/jr. Finally, we have to skip 'jr ra', which is
2204 // mips return. Occasionally this lands after an li().
2205
2206 Instr instr3 = instr_at(pc + 2 * kInstrSize);
2207 uint32_t ipc = reinterpret_cast<uint32_t>(pc + 3 * kInstrSize);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002208 bool in_range = (ipc ^ static_cast<uint32_t>(itarget) >>
2209 (kImm26Bits + kImmFieldShift)) == 0;
2210 uint32_t target_field =
2211 static_cast<uint32_t>(itarget & kJumpAddrMask) >>kImmFieldShift;
lrn@chromium.org34e60782011-09-15 07:25:40 +00002212 bool patched_jump = false;
2213
2214#ifndef ALLOW_JAL_IN_BOUNDARY_REGION
2215 // This is a workaround to the 24k core E156 bug (affect some 34k cores also).
2216 // Since the excluded space is only 64KB out of 256MB (0.02 %), we will just
2217 // apply this workaround for all cores so we don't have to identify the core.
2218 if (in_range) {
2219 // The 24k core E156 bug has some very specific requirements, we only check
2220 // the most simple one: if the address of the delay slot instruction is in
2221 // the first or last 32 KB of the 256 MB segment.
2222 uint32_t segment_mask = ((256 * MB) - 1) ^ ((32 * KB) - 1);
2223 uint32_t ipc_segment_addr = ipc & segment_mask;
2224 if (ipc_segment_addr == 0 || ipc_segment_addr == segment_mask)
2225 in_range = false;
2226 }
2227#endif
2228
2229 if (IsJalr(instr3)) {
2230 // Try to convert JALR to JAL.
2231 if (in_range && GetRt(instr2) == GetRs(instr3)) {
2232 *(p+2) = JAL | target_field;
2233 patched_jump = true;
2234 }
2235 } else if (IsJr(instr3)) {
2236 // Try to convert JR to J, skip returns (jr ra).
2237 bool is_ret = static_cast<int>(GetRs(instr3)) == ra.code();
2238 if (in_range && !is_ret && GetRt(instr2) == GetRs(instr3)) {
2239 *(p+2) = J | target_field;
2240 patched_jump = true;
2241 }
2242 } else if (IsJal(instr3)) {
2243 if (in_range) {
2244 // We are patching an already converted JAL.
2245 *(p+2) = JAL | target_field;
2246 } else {
2247 // Patch JAL, but out of range, revert to JALR.
2248 // JALR rs reg is the rt reg specified in the ORI instruction.
2249 uint32_t rs_field = GetRt(instr2) << kRsShift;
2250 uint32_t rd_field = ra.code() << kRdShift; // Return-address (ra) reg.
2251 *(p+2) = SPECIAL | rs_field | rd_field | JALR;
2252 }
2253 patched_jump = true;
2254 } else if (IsJ(instr3)) {
2255 if (in_range) {
2256 // We are patching an already converted J (jump).
2257 *(p+2) = J | target_field;
2258 } else {
2259 // Trying patch J, but out of range, just go back to JR.
2260 // JR 'rs' reg is the 'rt' reg specified in the ORI instruction (instr2).
2261 uint32_t rs_field = GetRt(instr2) << kRsShift;
2262 *(p+2) = SPECIAL | rs_field | JR;
2263 }
2264 patched_jump = true;
2265 }
2266
2267 CPU::FlushICache(pc, (patched_jump ? 3 : 2) * sizeof(int32_t));
ager@chromium.org5c838252010-02-19 08:53:10 +00002268}
2269
lrn@chromium.org34e60782011-09-15 07:25:40 +00002270void Assembler::JumpLabelToJumpRegister(Address pc) {
2271 // Address pc points to lui/ori instructions.
2272 // Jump to label may follow at pc + 2 * kInstrSize.
2273 uint32_t* p = reinterpret_cast<uint32_t*>(pc);
2274#ifdef DEBUG
2275 Instr instr1 = instr_at(pc);
2276#endif
2277 Instr instr2 = instr_at(pc + 1 * kInstrSize);
2278 Instr instr3 = instr_at(pc + 2 * kInstrSize);
2279 bool patched = false;
2280
2281 if (IsJal(instr3)) {
2282 ASSERT(GetOpcodeField(instr1) == LUI);
2283 ASSERT(GetOpcodeField(instr2) == ORI);
2284
2285 uint32_t rs_field = GetRt(instr2) << kRsShift;
2286 uint32_t rd_field = ra.code() << kRdShift; // Return-address (ra) reg.
2287 *(p+2) = SPECIAL | rs_field | rd_field | JALR;
2288 patched = true;
2289 } else if (IsJ(instr3)) {
2290 ASSERT(GetOpcodeField(instr1) == LUI);
2291 ASSERT(GetOpcodeField(instr2) == ORI);
2292
2293 uint32_t rs_field = GetRt(instr2) << kRsShift;
2294 *(p+2) = SPECIAL | rs_field | JR;
2295 patched = true;
2296 }
2297
2298 if (patched) {
2299 CPU::FlushICache(pc+2, sizeof(Address));
2300 }
2301}
ager@chromium.org5c838252010-02-19 08:53:10 +00002302
2303} } // namespace v8::internal
2304
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002305#endif // V8_TARGET_ARCH_MIPS