blob: a04d456ae9692f9bc838bcc730a91bde6e683dff [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
jkummerow@chromium.org93a47f42013-07-02 14:43:41 +000038#if V8_TARGET_ARCH_MIPS
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000039
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) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +000083 ASSERT(index >= 0 && index < kMaxNumAllocatableRegisters);
84 const char* const names[] = {
85 "f0",
86 "f2",
87 "f4",
88 "f6",
89 "f8",
90 "f10",
91 "f12",
92 "f14",
93 "f16",
94 "f18",
95 "f20",
96 "f22",
97 "f24",
98 "f26"
99 };
100 return names[index];
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000101}
102
103
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000104void CpuFeatures::Probe() {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000105 unsigned standard_features = (OS::CpuFeaturesImpliedByPlatform() |
106 CpuFeaturesImpliedByCompiler());
107 ASSERT(supported_ == 0 || supported_ == standard_features);
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000108#ifdef DEBUG
109 initialized_ = true;
110#endif
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000111
112 // Get the features implied by the OS and the compiler settings. This is the
113 // minimal set of features which is also allowed for generated code in the
114 // snapshot.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000115 supported_ |= standard_features;
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000116
117 if (Serializer::enabled()) {
118 // No probing for features if we might serialize (generate snapshot).
119 return;
120 }
121
lrn@chromium.org7516f052011-03-30 08:52:27 +0000122 // If the compiler is allowed to use fpu then we can use fpu too in our
123 // code generation.
124#if !defined(__mips__)
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000125 // For the simulator build, use FPU.
126 supported_ |= static_cast<uint64_t>(1) << FPU;
lrn@chromium.org7516f052011-03-30 08:52:27 +0000127#else
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000128 // Probe for additional features not already known to be available.
lrn@chromium.org7516f052011-03-30 08:52:27 +0000129 if (OS::MipsCpuHasFeature(FPU)) {
130 // This implementation also sets the FPU flags if
131 // runtime detection of FPU returns true.
ulan@chromium.org750145a2013-03-07 15:14:13 +0000132 supported_ |= static_cast<uint64_t>(1) << FPU;
133 found_by_runtime_probing_only_ |= static_cast<uint64_t>(1) << FPU;
lrn@chromium.org7516f052011-03-30 08:52:27 +0000134 }
lrn@chromium.org7516f052011-03-30 08:52:27 +0000135#endif
136}
ager@chromium.org5c838252010-02-19 08:53:10 +0000137
138
ager@chromium.org5c838252010-02-19 08:53:10 +0000139int ToNumber(Register reg) {
140 ASSERT(reg.is_valid());
141 const int kNumbers[] = {
142 0, // zero_reg
143 1, // at
144 2, // v0
145 3, // v1
146 4, // a0
147 5, // a1
148 6, // a2
149 7, // a3
150 8, // t0
151 9, // t1
152 10, // t2
153 11, // t3
154 12, // t4
155 13, // t5
156 14, // t6
157 15, // t7
158 16, // s0
159 17, // s1
160 18, // s2
161 19, // s3
162 20, // s4
163 21, // s5
164 22, // s6
165 23, // s7
166 24, // t8
167 25, // t9
168 26, // k0
169 27, // k1
170 28, // gp
171 29, // sp
fschneider@chromium.org7d10be52012-04-10 12:30:14 +0000172 30, // fp
ager@chromium.org5c838252010-02-19 08:53:10 +0000173 31, // ra
174 };
175 return kNumbers[reg.code()];
176}
177
lrn@chromium.org7516f052011-03-30 08:52:27 +0000178
ager@chromium.org5c838252010-02-19 08:53:10 +0000179Register ToRegister(int num) {
180 ASSERT(num >= 0 && num < kNumRegisters);
181 const Register kRegisters[] = {
182 zero_reg,
183 at,
184 v0, v1,
185 a0, a1, a2, a3,
186 t0, t1, t2, t3, t4, t5, t6, t7,
187 s0, s1, s2, s3, s4, s5, s6, s7,
188 t8, t9,
189 k0, k1,
190 gp,
191 sp,
fschneider@chromium.org7d10be52012-04-10 12:30:14 +0000192 fp,
ager@chromium.org5c838252010-02-19 08:53:10 +0000193 ra
194 };
195 return kRegisters[num];
196}
197
198
199// -----------------------------------------------------------------------------
200// Implementation of RelocInfo.
201
lrn@chromium.org34e60782011-09-15 07:25:40 +0000202const int RelocInfo::kApplyMask = RelocInfo::kCodeTargetMask |
203 1 << RelocInfo::INTERNAL_REFERENCE;
ager@chromium.org5c838252010-02-19 08:53:10 +0000204
lrn@chromium.org7516f052011-03-30 08:52:27 +0000205
206bool RelocInfo::IsCodedSpecially() {
207 // The deserializer needs to know whether a pointer is specially coded. Being
208 // specially coded on MIPS means that it is a lui/ori instruction, and that is
209 // always the case inside code objects.
210 return true;
211}
212
213
ager@chromium.org5c838252010-02-19 08:53:10 +0000214// Patch the code at the current address with the supplied instructions.
215void RelocInfo::PatchCode(byte* instructions, int instruction_count) {
216 Instr* pc = reinterpret_cast<Instr*>(pc_);
217 Instr* instr = reinterpret_cast<Instr*>(instructions);
218 for (int i = 0; i < instruction_count; i++) {
219 *(pc + i) = *(instr + i);
220 }
221
222 // Indicate that code has changed.
223 CPU::FlushICache(pc_, instruction_count * Assembler::kInstrSize);
224}
225
226
227// Patch the code at the current PC with a call to the target address.
228// Additional guard instructions can be added if required.
229void RelocInfo::PatchCodeWithCall(Address target, int guard_bytes) {
230 // Patch the code at the current address with a call to the target.
231 UNIMPLEMENTED_MIPS();
232}
233
234
235// -----------------------------------------------------------------------------
236// Implementation of Operand and MemOperand.
237// See assembler-mips-inl.h for inlined constructors.
238
239Operand::Operand(Handle<Object> handle) {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000240#ifdef DEBUG
241 Isolate* isolate = Isolate::Current();
242#endif
rossberg@chromium.org79e79022013-06-03 15:43:46 +0000243 AllowDeferredHandleDereference using_raw_address;
ager@chromium.org5c838252010-02-19 08:53:10 +0000244 rm_ = no_reg;
245 // Verify all Objects referred by code are NOT in new space.
246 Object* obj = *handle;
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000247 ASSERT(!isolate->heap()->InNewSpace(obj));
ager@chromium.org5c838252010-02-19 08:53:10 +0000248 if (obj->IsHeapObject()) {
249 imm32_ = reinterpret_cast<intptr_t>(handle.location());
250 rmode_ = RelocInfo::EMBEDDED_OBJECT;
251 } else {
252 // No relocation needed.
253 imm32_ = reinterpret_cast<intptr_t>(obj);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000254 rmode_ = RelocInfo::NONE32;
ager@chromium.org5c838252010-02-19 08:53:10 +0000255 }
256}
257
lrn@chromium.org7516f052011-03-30 08:52:27 +0000258
259MemOperand::MemOperand(Register rm, int32_t offset) : Operand(rm) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000260 offset_ = offset;
261}
262
263
264// -----------------------------------------------------------------------------
lrn@chromium.org7516f052011-03-30 08:52:27 +0000265// Specific instructions, constants, and masks.
ager@chromium.org5c838252010-02-19 08:53:10 +0000266
lrn@chromium.org7516f052011-03-30 08:52:27 +0000267static const int kNegOffset = 0x00008000;
268// addiu(sp, sp, 4) aka Pop() operation or part of Pop(r)
269// operations as post-increment of sp.
fschneider@chromium.org7d10be52012-04-10 12:30:14 +0000270const Instr kPopInstruction = ADDIU | (kRegister_sp_Code << kRsShift)
271 | (kRegister_sp_Code << kRtShift) | (kPointerSize & kImm16Mask);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000272// addiu(sp, sp, -4) part of Push(r) operation as pre-decrement of sp.
fschneider@chromium.org7d10be52012-04-10 12:30:14 +0000273const Instr kPushInstruction = ADDIU | (kRegister_sp_Code << kRsShift)
274 | (kRegister_sp_Code << kRtShift) | (-kPointerSize & kImm16Mask);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000275// sw(r, MemOperand(sp, 0))
fschneider@chromium.org7d10be52012-04-10 12:30:14 +0000276const Instr kPushRegPattern = SW | (kRegister_sp_Code << kRsShift)
lrn@chromium.org7516f052011-03-30 08:52:27 +0000277 | (0 & kImm16Mask);
278// lw(r, MemOperand(sp, 0))
fschneider@chromium.org7d10be52012-04-10 12:30:14 +0000279const Instr kPopRegPattern = LW | (kRegister_sp_Code << kRsShift)
lrn@chromium.org7516f052011-03-30 08:52:27 +0000280 | (0 & kImm16Mask);
ager@chromium.org5c838252010-02-19 08:53:10 +0000281
fschneider@chromium.org7d10be52012-04-10 12:30:14 +0000282const Instr kLwRegFpOffsetPattern = LW | (kRegister_fp_Code << kRsShift)
lrn@chromium.org7516f052011-03-30 08:52:27 +0000283 | (0 & kImm16Mask);
284
fschneider@chromium.org7d10be52012-04-10 12:30:14 +0000285const Instr kSwRegFpOffsetPattern = SW | (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 kLwRegFpNegOffsetPattern = LW | (kRegister_fp_Code << kRsShift)
lrn@chromium.org7516f052011-03-30 08:52:27 +0000289 | (kNegOffset & kImm16Mask);
290
fschneider@chromium.org7d10be52012-04-10 12:30:14 +0000291const Instr kSwRegFpNegOffsetPattern = SW | (kRegister_fp_Code << kRsShift)
lrn@chromium.org7516f052011-03-30 08:52:27 +0000292 | (kNegOffset & kImm16Mask);
293// A mask for the Rt register for push, pop, lw, sw instructions.
294const Instr kRtMask = kRtFieldMask;
295const Instr kLwSwInstrTypeMask = 0xffe00000;
296const Instr kLwSwInstrArgumentMask = ~kLwSwInstrTypeMask;
297const Instr kLwSwOffsetMask = kImm16Mask;
298
299
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000300Assembler::Assembler(Isolate* isolate, void* buffer, int buffer_size)
301 : AssemblerBase(isolate, buffer, buffer_size),
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000302 recorded_ast_id_(TypeFeedbackId::None()),
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +0000303 positions_recorder_(this) {
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000304 reloc_info_writer.Reposition(buffer_ + buffer_size_, pc_);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000305
306 last_trampoline_pool_end_ = 0;
307 no_trampoline_pool_before_ = 0;
308 trampoline_pool_blocked_nesting_ = 0;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +0000309 // We leave space (16 * kTrampolineSlotsSize)
310 // for BlockTrampolinePoolScope buffer.
311 next_buffer_check_ = kMaxBranchOffset - kTrampolineSlotsSize * 16;
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000312 internal_trampoline_exception_ = false;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000313 last_bound_pos_ = 0;
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000314
vegorov@chromium.org3cf47312011-06-29 13:20:01 +0000315 trampoline_emitted_ = false;
316 unbound_labels_count_ = 0;
317 block_buffer_growth_ = false;
318
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000319 ClearRecordedAstId();
ager@chromium.org5c838252010-02-19 08:53:10 +0000320}
321
322
ager@chromium.org5c838252010-02-19 08:53:10 +0000323void Assembler::GetCode(CodeDesc* desc) {
lrn@chromium.org7516f052011-03-30 08:52:27 +0000324 ASSERT(pc_ <= reloc_info_writer.pos()); // No overlap.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000325 // Set up code descriptor.
ager@chromium.org5c838252010-02-19 08:53:10 +0000326 desc->buffer = buffer_;
327 desc->buffer_size = buffer_size_;
328 desc->instr_size = pc_offset();
329 desc->reloc_size = (buffer_ + buffer_size_) - reloc_info_writer.pos();
330}
331
332
lrn@chromium.org7516f052011-03-30 08:52:27 +0000333void Assembler::Align(int m) {
334 ASSERT(m >= 4 && IsPowerOf2(m));
335 while ((pc_offset() & (m - 1)) != 0) {
336 nop();
337 }
338}
339
340
341void Assembler::CodeTargetAlign() {
342 // No advantage to aligning branch/call targets to more than
343 // single instruction, that I am aware of.
344 Align(4);
345}
346
347
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000348Register Assembler::GetRtReg(Instr instr) {
lrn@chromium.org7516f052011-03-30 08:52:27 +0000349 Register rt;
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000350 rt.code_ = (instr & kRtFieldMask) >> kRtShift;
lrn@chromium.org7516f052011-03-30 08:52:27 +0000351 return rt;
352}
353
354
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000355Register Assembler::GetRsReg(Instr instr) {
356 Register rs;
357 rs.code_ = (instr & kRsFieldMask) >> kRsShift;
358 return rs;
359}
360
361
362Register Assembler::GetRdReg(Instr instr) {
363 Register rd;
364 rd.code_ = (instr & kRdFieldMask) >> kRdShift;
365 return rd;
366}
367
368
369uint32_t Assembler::GetRt(Instr instr) {
370 return (instr & kRtFieldMask) >> kRtShift;
371}
372
373
374uint32_t Assembler::GetRtField(Instr instr) {
375 return instr & kRtFieldMask;
376}
377
378
379uint32_t Assembler::GetRs(Instr instr) {
380 return (instr & kRsFieldMask) >> kRsShift;
381}
382
383
384uint32_t Assembler::GetRsField(Instr instr) {
385 return instr & kRsFieldMask;
386}
387
388
389uint32_t Assembler::GetRd(Instr instr) {
390 return (instr & kRdFieldMask) >> kRdShift;
391}
392
393
394uint32_t Assembler::GetRdField(Instr instr) {
395 return instr & kRdFieldMask;
396}
397
398
399uint32_t Assembler::GetSa(Instr instr) {
400 return (instr & kSaFieldMask) >> kSaShift;
401}
402
403
404uint32_t Assembler::GetSaField(Instr instr) {
405 return instr & kSaFieldMask;
406}
407
408
409uint32_t Assembler::GetOpcodeField(Instr instr) {
410 return instr & kOpcodeMask;
411}
412
413
vegorov@chromium.org3cf47312011-06-29 13:20:01 +0000414uint32_t Assembler::GetFunction(Instr instr) {
415 return (instr & kFunctionFieldMask) >> kFunctionShift;
416}
417
418
419uint32_t Assembler::GetFunctionField(Instr instr) {
420 return instr & kFunctionFieldMask;
421}
422
423
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000424uint32_t Assembler::GetImmediate16(Instr instr) {
425 return instr & kImm16Mask;
426}
427
428
429uint32_t Assembler::GetLabelConst(Instr instr) {
430 return instr & ~kImm16Mask;
431}
432
433
lrn@chromium.org7516f052011-03-30 08:52:27 +0000434bool Assembler::IsPop(Instr instr) {
435 return (instr & ~kRtMask) == kPopRegPattern;
436}
437
438
439bool Assembler::IsPush(Instr instr) {
440 return (instr & ~kRtMask) == kPushRegPattern;
441}
442
443
444bool Assembler::IsSwRegFpOffset(Instr instr) {
445 return ((instr & kLwSwInstrTypeMask) == kSwRegFpOffsetPattern);
446}
447
448
449bool Assembler::IsLwRegFpOffset(Instr instr) {
450 return ((instr & kLwSwInstrTypeMask) == kLwRegFpOffsetPattern);
451}
452
453
454bool Assembler::IsSwRegFpNegOffset(Instr instr) {
455 return ((instr & (kLwSwInstrTypeMask | kNegOffset)) ==
456 kSwRegFpNegOffsetPattern);
457}
458
459
460bool Assembler::IsLwRegFpNegOffset(Instr instr) {
461 return ((instr & (kLwSwInstrTypeMask | kNegOffset)) ==
462 kLwRegFpNegOffsetPattern);
463}
464
465
ager@chromium.org5c838252010-02-19 08:53:10 +0000466// Labels refer to positions in the (to be) generated code.
467// There are bound, linked, and unused labels.
468//
469// Bound labels refer to known positions in the already
470// generated code. pos() is the position the label refers to.
471//
472// Linked labels refer to unknown positions in the code
473// to be generated; pos() is the position of the last
474// instruction using the label.
475
lrn@chromium.org7516f052011-03-30 08:52:27 +0000476// The link chain is terminated by a value in the instruction of -1,
477// which is an otherwise illegal value (branch -1 is inf loop).
478// The instruction 16-bit offset field addresses 32-bit words, but in
479// code is conv to an 18-bit value addressing bytes, hence the -4 value.
ager@chromium.org5c838252010-02-19 08:53:10 +0000480
ager@chromium.org5c838252010-02-19 08:53:10 +0000481const int kEndOfChain = -4;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +0000482// Determines the end of the Jump chain (a subset of the label link chain).
483const int kEndOfJumpChain = 0;
ager@chromium.org5c838252010-02-19 08:53:10 +0000484
lrn@chromium.org7516f052011-03-30 08:52:27 +0000485
486bool Assembler::IsBranch(Instr instr) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000487 uint32_t opcode = GetOpcodeField(instr);
488 uint32_t rt_field = GetRtField(instr);
489 uint32_t rs_field = GetRsField(instr);
ager@chromium.org5c838252010-02-19 08:53:10 +0000490 // Checks if the instruction is a branch.
491 return opcode == BEQ ||
492 opcode == BNE ||
493 opcode == BLEZ ||
494 opcode == BGTZ ||
495 opcode == BEQL ||
496 opcode == BNEL ||
497 opcode == BLEZL ||
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000498 opcode == BGTZL ||
ager@chromium.org5c838252010-02-19 08:53:10 +0000499 (opcode == REGIMM && (rt_field == BLTZ || rt_field == BGEZ ||
500 rt_field == BLTZAL || rt_field == BGEZAL)) ||
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +0000501 (opcode == COP1 && rs_field == BC1); // Coprocessor branch.
lrn@chromium.org7516f052011-03-30 08:52:27 +0000502}
503
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +0000504
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +0000505bool Assembler::IsEmittedConstant(Instr instr) {
506 uint32_t label_constant = GetLabelConst(instr);
507 return label_constant == 0; // Emitted label const in reg-exp engine.
508}
lrn@chromium.org7516f052011-03-30 08:52:27 +0000509
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +0000510
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000511bool Assembler::IsBeq(Instr instr) {
512 return GetOpcodeField(instr) == BEQ;
513}
514
515
516bool Assembler::IsBne(Instr instr) {
517 return GetOpcodeField(instr) == BNE;
518}
519
520
vegorov@chromium.org3cf47312011-06-29 13:20:01 +0000521bool Assembler::IsJump(Instr instr) {
522 uint32_t opcode = GetOpcodeField(instr);
523 uint32_t rt_field = GetRtField(instr);
524 uint32_t rd_field = GetRdField(instr);
525 uint32_t function_field = GetFunctionField(instr);
526 // Checks if the instruction is a jump.
527 return opcode == J || opcode == JAL ||
528 (opcode == SPECIAL && rt_field == 0 &&
529 ((function_field == JALR) || (rd_field == 0 && (function_field == JR))));
530}
531
532
533bool Assembler::IsJ(Instr instr) {
534 uint32_t opcode = GetOpcodeField(instr);
535 // Checks if the instruction is a jump.
536 return opcode == J;
537}
538
539
lrn@chromium.org34e60782011-09-15 07:25:40 +0000540bool Assembler::IsJal(Instr instr) {
541 return GetOpcodeField(instr) == JAL;
542}
543
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +0000544
lrn@chromium.org34e60782011-09-15 07:25:40 +0000545bool Assembler::IsJr(Instr instr) {
546 return GetOpcodeField(instr) == SPECIAL && GetFunctionField(instr) == JR;
547}
548
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +0000549
lrn@chromium.org34e60782011-09-15 07:25:40 +0000550bool Assembler::IsJalr(Instr instr) {
551 return GetOpcodeField(instr) == SPECIAL && GetFunctionField(instr) == JALR;
552}
553
554
vegorov@chromium.org3cf47312011-06-29 13:20:01 +0000555bool Assembler::IsLui(Instr instr) {
556 uint32_t opcode = GetOpcodeField(instr);
557 // Checks if the instruction is a load upper immediate.
558 return opcode == LUI;
559}
560
561
562bool Assembler::IsOri(Instr instr) {
563 uint32_t opcode = GetOpcodeField(instr);
564 // Checks if the instruction is a load upper immediate.
565 return opcode == ORI;
566}
567
568
lrn@chromium.org7516f052011-03-30 08:52:27 +0000569bool Assembler::IsNop(Instr instr, unsigned int type) {
570 // See Assembler::nop(type).
571 ASSERT(type < 32);
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000572 uint32_t opcode = GetOpcodeField(instr);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000573 uint32_t function = GetFunctionField(instr);
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000574 uint32_t rt = GetRt(instr);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000575 uint32_t rd = GetRd(instr);
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000576 uint32_t sa = GetSa(instr);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000577
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000578 // Traditional mips nop == sll(zero_reg, zero_reg, 0)
579 // When marking non-zero type, use sll(zero_reg, at, type)
580 // to avoid use of mips ssnop and ehb special encodings
581 // of the sll instruction.
lrn@chromium.org7516f052011-03-30 08:52:27 +0000582
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000583 Register nop_rt_reg = (type == 0) ? zero_reg : at;
584 bool ret = (opcode == SPECIAL && function == SLL &&
585 rd == static_cast<uint32_t>(ToNumber(zero_reg)) &&
586 rt == static_cast<uint32_t>(ToNumber(nop_rt_reg)) &&
lrn@chromium.org7516f052011-03-30 08:52:27 +0000587 sa == type);
588
589 return ret;
590}
591
592
593int32_t Assembler::GetBranchOffset(Instr instr) {
594 ASSERT(IsBranch(instr));
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000595 return (static_cast<int16_t>(instr & kImm16Mask)) << 2;
lrn@chromium.org7516f052011-03-30 08:52:27 +0000596}
597
598
599bool Assembler::IsLw(Instr instr) {
600 return ((instr & kOpcodeMask) == LW);
601}
602
603
604int16_t Assembler::GetLwOffset(Instr instr) {
605 ASSERT(IsLw(instr));
606 return ((instr & kImm16Mask));
607}
608
609
610Instr Assembler::SetLwOffset(Instr instr, int16_t offset) {
611 ASSERT(IsLw(instr));
612
613 // We actually create a new lw instruction based on the original one.
614 Instr temp_instr = LW | (instr & kRsFieldMask) | (instr & kRtFieldMask)
615 | (offset & kImm16Mask);
616
617 return temp_instr;
618}
619
620
621bool Assembler::IsSw(Instr instr) {
622 return ((instr & kOpcodeMask) == SW);
623}
624
625
626Instr Assembler::SetSwOffset(Instr instr, int16_t offset) {
627 ASSERT(IsSw(instr));
628 return ((instr & ~kImm16Mask) | (offset & kImm16Mask));
629}
630
631
632bool Assembler::IsAddImmediate(Instr instr) {
633 return ((instr & kOpcodeMask) == ADDIU);
634}
635
636
637Instr Assembler::SetAddImmediateOffset(Instr instr, int16_t offset) {
638 ASSERT(IsAddImmediate(instr));
639 return ((instr & ~kImm16Mask) | (offset & kImm16Mask));
ager@chromium.org5c838252010-02-19 08:53:10 +0000640}
641
642
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000643bool Assembler::IsAndImmediate(Instr instr) {
644 return GetOpcodeField(instr) == ANDI;
645}
646
647
ager@chromium.org5c838252010-02-19 08:53:10 +0000648int Assembler::target_at(int32_t pos) {
649 Instr instr = instr_at(pos);
650 if ((instr & ~kImm16Mask) == 0) {
651 // Emitted label constant, not part of a branch.
lrn@chromium.org7516f052011-03-30 08:52:27 +0000652 if (instr == 0) {
653 return kEndOfChain;
654 } else {
655 int32_t imm18 =((instr & static_cast<int32_t>(kImm16Mask)) << 16) >> 14;
656 return (imm18 + pos);
657 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000658 }
vegorov@chromium.org3cf47312011-06-29 13:20:01 +0000659 // Check we have a branch or jump instruction.
660 ASSERT(IsBranch(instr) || IsJ(instr) || IsLui(instr));
ager@chromium.org5c838252010-02-19 08:53:10 +0000661 // Do NOT change this to <<2. We rely on arithmetic shifts here, assuming
662 // the compiler uses arithmectic shifts for signed integers.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +0000663 if (IsBranch(instr)) {
664 int32_t imm18 = ((instr & static_cast<int32_t>(kImm16Mask)) << 16) >> 14;
ager@chromium.org5c838252010-02-19 08:53:10 +0000665
vegorov@chromium.org3cf47312011-06-29 13:20:01 +0000666 if (imm18 == kEndOfChain) {
667 // EndOfChain sentinel is returned directly, not relative to pc or pos.
668 return kEndOfChain;
669 } else {
670 return pos + kBranchPCOffset + imm18;
671 }
672 } else if (IsLui(instr)) {
673 Instr instr_lui = instr_at(pos + 0 * Assembler::kInstrSize);
674 Instr instr_ori = instr_at(pos + 1 * Assembler::kInstrSize);
675 ASSERT(IsOri(instr_ori));
676 int32_t imm = (instr_lui & static_cast<int32_t>(kImm16Mask)) << kLuiShift;
677 imm |= (instr_ori & static_cast<int32_t>(kImm16Mask));
678
679 if (imm == kEndOfJumpChain) {
680 // EndOfChain sentinel is returned directly, not relative to pc or pos.
681 return kEndOfChain;
682 } else {
683 uint32_t instr_address = reinterpret_cast<int32_t>(buffer_ + pos);
684 int32_t delta = instr_address - imm;
685 ASSERT(pos > delta);
686 return pos - delta;
687 }
lrn@chromium.org7516f052011-03-30 08:52:27 +0000688 } else {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +0000689 int32_t imm28 = (instr & static_cast<int32_t>(kImm26Mask)) << 2;
690 if (imm28 == kEndOfJumpChain) {
691 // EndOfChain sentinel is returned directly, not relative to pc or pos.
692 return kEndOfChain;
693 } else {
694 uint32_t instr_address = reinterpret_cast<int32_t>(buffer_ + pos);
695 instr_address &= kImm28Mask;
696 int32_t delta = instr_address - imm28;
697 ASSERT(pos > delta);
698 return pos - delta;
699 }
lrn@chromium.org7516f052011-03-30 08:52:27 +0000700 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000701}
702
703
704void Assembler::target_at_put(int32_t pos, int32_t target_pos) {
705 Instr instr = instr_at(pos);
706 if ((instr & ~kImm16Mask) == 0) {
707 ASSERT(target_pos == kEndOfChain || target_pos >= 0);
708 // Emitted label constant, not part of a branch.
709 // Make label relative to Code* of generated Code object.
710 instr_at_put(pos, target_pos + (Code::kHeaderSize - kHeapObjectTag));
711 return;
712 }
713
vegorov@chromium.org3cf47312011-06-29 13:20:01 +0000714 ASSERT(IsBranch(instr) || IsJ(instr) || IsLui(instr));
715 if (IsBranch(instr)) {
716 int32_t imm18 = target_pos - (pos + kBranchPCOffset);
717 ASSERT((imm18 & 3) == 0);
ager@chromium.org5c838252010-02-19 08:53:10 +0000718
vegorov@chromium.org3cf47312011-06-29 13:20:01 +0000719 instr &= ~kImm16Mask;
720 int32_t imm16 = imm18 >> 2;
721 ASSERT(is_int16(imm16));
ager@chromium.org5c838252010-02-19 08:53:10 +0000722
vegorov@chromium.org3cf47312011-06-29 13:20:01 +0000723 instr_at_put(pos, instr | (imm16 & kImm16Mask));
724 } else if (IsLui(instr)) {
725 Instr instr_lui = instr_at(pos + 0 * Assembler::kInstrSize);
726 Instr instr_ori = instr_at(pos + 1 * Assembler::kInstrSize);
727 ASSERT(IsOri(instr_ori));
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000728 uint32_t imm = reinterpret_cast<uint32_t>(buffer_) + target_pos;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +0000729 ASSERT((imm & 3) == 0);
730
731 instr_lui &= ~kImm16Mask;
732 instr_ori &= ~kImm16Mask;
733
734 instr_at_put(pos + 0 * Assembler::kInstrSize,
735 instr_lui | ((imm & kHiMask) >> kLuiShift));
736 instr_at_put(pos + 1 * Assembler::kInstrSize,
737 instr_ori | (imm & kImm16Mask));
738 } else {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000739 uint32_t imm28 = reinterpret_cast<uint32_t>(buffer_) + target_pos;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +0000740 imm28 &= kImm28Mask;
741 ASSERT((imm28 & 3) == 0);
742
743 instr &= ~kImm26Mask;
744 uint32_t imm26 = imm28 >> 2;
745 ASSERT(is_uint26(imm26));
746
747 instr_at_put(pos, instr | (imm26 & kImm26Mask));
748 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000749}
750
751
752void Assembler::print(Label* L) {
753 if (L->is_unused()) {
754 PrintF("unused label\n");
755 } else if (L->is_bound()) {
756 PrintF("bound label to %d\n", L->pos());
757 } else if (L->is_linked()) {
758 Label l = *L;
759 PrintF("unbound label");
760 while (l.is_linked()) {
761 PrintF("@ %d ", l.pos());
762 Instr instr = instr_at(l.pos());
763 if ((instr & ~kImm16Mask) == 0) {
764 PrintF("value\n");
765 } else {
766 PrintF("%d\n", instr);
767 }
768 next(&l);
769 }
770 } else {
771 PrintF("label in inconsistent state (pos = %d)\n", L->pos_);
772 }
773}
774
775
776void Assembler::bind_to(Label* L, int pos) {
lrn@chromium.org7516f052011-03-30 08:52:27 +0000777 ASSERT(0 <= pos && pos <= pc_offset()); // Must have valid binding position.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +0000778 int32_t trampoline_pos = kInvalidSlotPos;
779 if (L->is_linked() && !trampoline_emitted_) {
780 unbound_labels_count_--;
781 next_buffer_check_ += kTrampolineSlotsSize;
782 }
783
ager@chromium.org5c838252010-02-19 08:53:10 +0000784 while (L->is_linked()) {
785 int32_t fixup_pos = L->pos();
lrn@chromium.org7516f052011-03-30 08:52:27 +0000786 int32_t dist = pos - fixup_pos;
787 next(L); // Call next before overwriting link with target at fixup_pos.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +0000788 Instr instr = instr_at(fixup_pos);
789 if (IsBranch(instr)) {
790 if (dist > kMaxBranchOffset) {
791 if (trampoline_pos == kInvalidSlotPos) {
792 trampoline_pos = get_trampoline_entry(fixup_pos);
793 CHECK(trampoline_pos != kInvalidSlotPos);
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000794 }
lrn@chromium.org7516f052011-03-30 08:52:27 +0000795 ASSERT((trampoline_pos - fixup_pos) <= kMaxBranchOffset);
796 target_at_put(fixup_pos, trampoline_pos);
797 fixup_pos = trampoline_pos;
798 dist = pos - fixup_pos;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +0000799 }
800 target_at_put(fixup_pos, pos);
801 } else {
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +0000802 ASSERT(IsJ(instr) || IsLui(instr) || IsEmittedConstant(instr));
vegorov@chromium.org3cf47312011-06-29 13:20:01 +0000803 target_at_put(fixup_pos, pos);
804 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000805 }
806 L->bind_to(pos);
807
808 // Keep track of the last bound label so we don't eliminate any instructions
809 // before a bound label.
810 if (pos > last_bound_pos_)
811 last_bound_pos_ = pos;
812}
813
814
ager@chromium.org5c838252010-02-19 08:53:10 +0000815void Assembler::bind(Label* L) {
lrn@chromium.org7516f052011-03-30 08:52:27 +0000816 ASSERT(!L->is_bound()); // Label can only be bound once.
ager@chromium.org5c838252010-02-19 08:53:10 +0000817 bind_to(L, pc_offset());
818}
819
820
821void Assembler::next(Label* L) {
822 ASSERT(L->is_linked());
823 int link = target_at(L->pos());
lrn@chromium.org7516f052011-03-30 08:52:27 +0000824 if (link == kEndOfChain) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000825 L->Unuse();
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +0000826 } else {
827 ASSERT(link >= 0);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000828 L->link_to(link);
ager@chromium.org5c838252010-02-19 08:53:10 +0000829 }
830}
831
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +0000832
vegorov@chromium.org3cf47312011-06-29 13:20:01 +0000833bool Assembler::is_near(Label* L) {
834 if (L->is_bound()) {
835 return ((pc_offset() - L->pos()) < kMaxBranchOffset - 4 * kInstrSize);
836 }
837 return false;
838}
ager@chromium.org5c838252010-02-19 08:53:10 +0000839
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +0000840
ager@chromium.org5c838252010-02-19 08:53:10 +0000841// We have to use a temporary register for things that can be relocated even
842// if they can be encoded in the MIPS's 16 bits of immediate-offset instruction
843// space. There is no guarantee that the relocated location can be similarly
844// encoded.
lrn@chromium.org7516f052011-03-30 08:52:27 +0000845bool Assembler::MustUseReg(RelocInfo::Mode rmode) {
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +0000846 return !RelocInfo::IsNone(rmode);
ager@chromium.org5c838252010-02-19 08:53:10 +0000847}
848
ager@chromium.org5c838252010-02-19 08:53:10 +0000849void Assembler::GenInstrRegister(Opcode opcode,
850 Register rs,
851 Register rt,
852 Register rd,
853 uint16_t sa,
854 SecondaryField func) {
855 ASSERT(rd.is_valid() && rs.is_valid() && rt.is_valid() && is_uint5(sa));
856 Instr instr = opcode | (rs.code() << kRsShift) | (rt.code() << kRtShift)
857 | (rd.code() << kRdShift) | (sa << kSaShift) | func;
858 emit(instr);
859}
860
861
862void Assembler::GenInstrRegister(Opcode opcode,
lrn@chromium.org7516f052011-03-30 08:52:27 +0000863 Register rs,
864 Register rt,
865 uint16_t msb,
866 uint16_t lsb,
867 SecondaryField func) {
868 ASSERT(rs.is_valid() && rt.is_valid() && is_uint5(msb) && is_uint5(lsb));
869 Instr instr = opcode | (rs.code() << kRsShift) | (rt.code() << kRtShift)
870 | (msb << kRdShift) | (lsb << kSaShift) | func;
871 emit(instr);
872}
873
874
875void Assembler::GenInstrRegister(Opcode opcode,
ager@chromium.org5c838252010-02-19 08:53:10 +0000876 SecondaryField fmt,
877 FPURegister ft,
878 FPURegister fs,
879 FPURegister fd,
880 SecondaryField func) {
881 ASSERT(fd.is_valid() && fs.is_valid() && ft.is_valid());
lrn@chromium.org7516f052011-03-30 08:52:27 +0000882 Instr instr = opcode | fmt | (ft.code() << kFtShift) | (fs.code() << kFsShift)
883 | (fd.code() << kFdShift) | func;
ager@chromium.org5c838252010-02-19 08:53:10 +0000884 emit(instr);
885}
886
887
888void Assembler::GenInstrRegister(Opcode opcode,
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000889 FPURegister fr,
890 FPURegister ft,
891 FPURegister fs,
892 FPURegister fd,
893 SecondaryField func) {
894 ASSERT(fd.is_valid() && fr.is_valid() && fs.is_valid() && ft.is_valid());
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000895 Instr instr = opcode | (fr.code() << kFrShift) | (ft.code() << kFtShift)
896 | (fs.code() << kFsShift) | (fd.code() << kFdShift) | func;
897 emit(instr);
898}
899
900
901void Assembler::GenInstrRegister(Opcode opcode,
ager@chromium.org5c838252010-02-19 08:53:10 +0000902 SecondaryField fmt,
903 Register rt,
904 FPURegister fs,
905 FPURegister fd,
906 SecondaryField func) {
907 ASSERT(fd.is_valid() && fs.is_valid() && rt.is_valid());
908 Instr instr = opcode | fmt | (rt.code() << kRtShift)
lrn@chromium.org7516f052011-03-30 08:52:27 +0000909 | (fs.code() << kFsShift) | (fd.code() << kFdShift) | func;
910 emit(instr);
911}
912
913
914void Assembler::GenInstrRegister(Opcode opcode,
915 SecondaryField fmt,
916 Register rt,
917 FPUControlRegister fs,
918 SecondaryField func) {
919 ASSERT(fs.is_valid() && rt.is_valid());
lrn@chromium.org7516f052011-03-30 08:52:27 +0000920 Instr instr =
921 opcode | fmt | (rt.code() << kRtShift) | (fs.code() << kFsShift) | func;
ager@chromium.org5c838252010-02-19 08:53:10 +0000922 emit(instr);
923}
924
925
926// Instructions with immediate value.
927// Registers are in the order of the instruction encoding, from left to right.
928void Assembler::GenInstrImmediate(Opcode opcode,
929 Register rs,
930 Register rt,
931 int32_t j) {
932 ASSERT(rs.is_valid() && rt.is_valid() && (is_int16(j) || is_uint16(j)));
933 Instr instr = opcode | (rs.code() << kRsShift) | (rt.code() << kRtShift)
934 | (j & kImm16Mask);
935 emit(instr);
936}
937
938
939void Assembler::GenInstrImmediate(Opcode opcode,
940 Register rs,
941 SecondaryField SF,
942 int32_t j) {
943 ASSERT(rs.is_valid() && (is_int16(j) || is_uint16(j)));
944 Instr instr = opcode | (rs.code() << kRsShift) | SF | (j & kImm16Mask);
945 emit(instr);
946}
947
948
949void Assembler::GenInstrImmediate(Opcode opcode,
950 Register rs,
951 FPURegister ft,
952 int32_t j) {
953 ASSERT(rs.is_valid() && ft.is_valid() && (is_int16(j) || is_uint16(j)));
954 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);
jkummerow@chromium.org93a47f42013-07-02 14:43:41 +00001484#if V8_HOST_ARCH_MIPS
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00001485 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
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00001678
lrn@chromium.org34e60782011-09-15 07:25:40 +00001679void Assembler::DoubleAsTwoUInt32(double d, uint32_t* lo, uint32_t* hi) {
1680 uint64_t i;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001681 OS::MemCopy(&i, &d, 8);
lrn@chromium.org34e60782011-09-15 07:25:40 +00001682
1683 *lo = i & 0xffffffff;
1684 *hi = i >> 32;
1685}
lrn@chromium.org7516f052011-03-30 08:52:27 +00001686
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00001687
lrn@chromium.org7516f052011-03-30 08:52:27 +00001688// Arithmetic.
1689
1690void Assembler::add_d(FPURegister fd, FPURegister fs, FPURegister ft) {
1691 GenInstrRegister(COP1, D, ft, fs, fd, ADD_D);
1692}
1693
1694
1695void Assembler::sub_d(FPURegister fd, FPURegister fs, FPURegister ft) {
1696 GenInstrRegister(COP1, D, ft, fs, fd, SUB_D);
1697}
1698
1699
1700void Assembler::mul_d(FPURegister fd, FPURegister fs, FPURegister ft) {
1701 GenInstrRegister(COP1, D, ft, fs, fd, MUL_D);
1702}
1703
1704
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001705void Assembler::madd_d(FPURegister fd, FPURegister fr, FPURegister fs,
1706 FPURegister ft) {
1707 GenInstrRegister(COP1X, fr, ft, fs, fd, MADD_D);
1708}
1709
1710
lrn@chromium.org7516f052011-03-30 08:52:27 +00001711void Assembler::div_d(FPURegister fd, FPURegister fs, FPURegister ft) {
1712 GenInstrRegister(COP1, D, ft, fs, fd, DIV_D);
1713}
1714
1715
1716void Assembler::abs_d(FPURegister fd, FPURegister fs) {
1717 GenInstrRegister(COP1, D, f0, fs, fd, ABS_D);
1718}
1719
1720
1721void Assembler::mov_d(FPURegister fd, FPURegister fs) {
1722 GenInstrRegister(COP1, D, f0, fs, fd, MOV_D);
1723}
1724
1725
1726void Assembler::neg_d(FPURegister fd, FPURegister fs) {
1727 GenInstrRegister(COP1, D, f0, fs, fd, NEG_D);
1728}
1729
1730
1731void Assembler::sqrt_d(FPURegister fd, FPURegister fs) {
1732 GenInstrRegister(COP1, D, f0, fs, fd, SQRT_D);
ager@chromium.org5c838252010-02-19 08:53:10 +00001733}
1734
1735
1736// Conversions.
1737
1738void Assembler::cvt_w_s(FPURegister fd, FPURegister fs) {
1739 GenInstrRegister(COP1, S, f0, fs, fd, CVT_W_S);
1740}
1741
1742
1743void Assembler::cvt_w_d(FPURegister fd, FPURegister fs) {
1744 GenInstrRegister(COP1, D, f0, fs, fd, CVT_W_D);
1745}
1746
1747
lrn@chromium.org7516f052011-03-30 08:52:27 +00001748void Assembler::trunc_w_s(FPURegister fd, FPURegister fs) {
1749 GenInstrRegister(COP1, S, f0, fs, fd, TRUNC_W_S);
1750}
1751
1752
1753void Assembler::trunc_w_d(FPURegister fd, FPURegister fs) {
1754 GenInstrRegister(COP1, D, f0, fs, fd, TRUNC_W_D);
1755}
1756
1757
1758void Assembler::round_w_s(FPURegister fd, FPURegister fs) {
1759 GenInstrRegister(COP1, S, f0, fs, fd, ROUND_W_S);
1760}
1761
1762
1763void Assembler::round_w_d(FPURegister fd, FPURegister fs) {
1764 GenInstrRegister(COP1, D, f0, fs, fd, ROUND_W_D);
1765}
1766
1767
1768void Assembler::floor_w_s(FPURegister fd, FPURegister fs) {
1769 GenInstrRegister(COP1, S, f0, fs, fd, FLOOR_W_S);
1770}
1771
1772
1773void Assembler::floor_w_d(FPURegister fd, FPURegister fs) {
1774 GenInstrRegister(COP1, D, f0, fs, fd, FLOOR_W_D);
1775}
1776
1777
1778void Assembler::ceil_w_s(FPURegister fd, FPURegister fs) {
1779 GenInstrRegister(COP1, S, f0, fs, fd, CEIL_W_S);
1780}
1781
1782
1783void Assembler::ceil_w_d(FPURegister fd, FPURegister fs) {
1784 GenInstrRegister(COP1, D, f0, fs, fd, CEIL_W_D);
1785}
1786
1787
ager@chromium.org5c838252010-02-19 08:53:10 +00001788void Assembler::cvt_l_s(FPURegister fd, FPURegister fs) {
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001789 ASSERT(kArchVariant == kMips32r2);
ager@chromium.org5c838252010-02-19 08:53:10 +00001790 GenInstrRegister(COP1, S, f0, fs, fd, CVT_L_S);
1791}
1792
1793
1794void Assembler::cvt_l_d(FPURegister fd, FPURegister fs) {
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001795 ASSERT(kArchVariant == kMips32r2);
ager@chromium.org5c838252010-02-19 08:53:10 +00001796 GenInstrRegister(COP1, D, f0, fs, fd, CVT_L_D);
1797}
1798
1799
lrn@chromium.org7516f052011-03-30 08:52:27 +00001800void Assembler::trunc_l_s(FPURegister fd, FPURegister fs) {
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001801 ASSERT(kArchVariant == kMips32r2);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001802 GenInstrRegister(COP1, S, f0, fs, fd, TRUNC_L_S);
1803}
1804
1805
1806void Assembler::trunc_l_d(FPURegister fd, FPURegister fs) {
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001807 ASSERT(kArchVariant == kMips32r2);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001808 GenInstrRegister(COP1, D, f0, fs, fd, TRUNC_L_D);
1809}
1810
1811
1812void Assembler::round_l_s(FPURegister fd, FPURegister fs) {
1813 GenInstrRegister(COP1, S, f0, fs, fd, ROUND_L_S);
1814}
1815
1816
1817void Assembler::round_l_d(FPURegister fd, FPURegister fs) {
1818 GenInstrRegister(COP1, D, f0, fs, fd, ROUND_L_D);
1819}
1820
1821
1822void Assembler::floor_l_s(FPURegister fd, FPURegister fs) {
1823 GenInstrRegister(COP1, S, f0, fs, fd, FLOOR_L_S);
1824}
1825
1826
1827void Assembler::floor_l_d(FPURegister fd, FPURegister fs) {
1828 GenInstrRegister(COP1, D, f0, fs, fd, FLOOR_L_D);
1829}
1830
1831
1832void Assembler::ceil_l_s(FPURegister fd, FPURegister fs) {
1833 GenInstrRegister(COP1, S, f0, fs, fd, CEIL_L_S);
1834}
1835
1836
1837void Assembler::ceil_l_d(FPURegister fd, FPURegister fs) {
1838 GenInstrRegister(COP1, D, f0, fs, fd, CEIL_L_D);
1839}
1840
1841
ager@chromium.org5c838252010-02-19 08:53:10 +00001842void Assembler::cvt_s_w(FPURegister fd, FPURegister fs) {
1843 GenInstrRegister(COP1, W, f0, fs, fd, CVT_S_W);
1844}
1845
1846
1847void Assembler::cvt_s_l(FPURegister fd, FPURegister fs) {
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001848 ASSERT(kArchVariant == kMips32r2);
ager@chromium.org5c838252010-02-19 08:53:10 +00001849 GenInstrRegister(COP1, L, f0, fs, fd, CVT_S_L);
1850}
1851
1852
1853void Assembler::cvt_s_d(FPURegister fd, FPURegister fs) {
1854 GenInstrRegister(COP1, D, f0, fs, fd, CVT_S_D);
1855}
1856
1857
1858void Assembler::cvt_d_w(FPURegister fd, FPURegister fs) {
1859 GenInstrRegister(COP1, W, f0, fs, fd, CVT_D_W);
1860}
1861
1862
1863void Assembler::cvt_d_l(FPURegister fd, FPURegister fs) {
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001864 ASSERT(kArchVariant == kMips32r2);
ager@chromium.org5c838252010-02-19 08:53:10 +00001865 GenInstrRegister(COP1, L, f0, fs, fd, CVT_D_L);
1866}
1867
1868
1869void Assembler::cvt_d_s(FPURegister fd, FPURegister fs) {
1870 GenInstrRegister(COP1, S, f0, fs, fd, CVT_D_S);
1871}
1872
1873
1874// Conditions.
1875void Assembler::c(FPUCondition cond, SecondaryField fmt,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001876 FPURegister fs, FPURegister ft, uint16_t cc) {
ager@chromium.org5c838252010-02-19 08:53:10 +00001877 ASSERT(is_uint3(cc));
1878 ASSERT((fmt & ~(31 << kRsShift)) == 0);
1879 Instr instr = COP1 | fmt | ft.code() << 16 | fs.code() << kFsShift
1880 | cc << 8 | 3 << 4 | cond;
1881 emit(instr);
1882}
1883
1884
lrn@chromium.org7516f052011-03-30 08:52:27 +00001885void Assembler::fcmp(FPURegister src1, const double src2,
1886 FPUCondition cond) {
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) {
1895 ASSERT(is_uint3(cc));
1896 Instr instr = COP1 | BC1 | cc << 18 | 0 << 16 | (offset & kImm16Mask);
1897 emit(instr);
1898}
1899
1900
1901void Assembler::bc1t(int16_t offset, uint16_t cc) {
1902 ASSERT(is_uint3(cc));
1903 Instr instr = COP1 | BC1 | cc << 18 | 1 << 16 | (offset & kImm16Mask);
1904 emit(instr);
1905}
1906
1907
1908// Debugging.
1909void Assembler::RecordJSReturn() {
lrn@chromium.org7516f052011-03-30 08:52:27 +00001910 positions_recorder()->WriteRecordedPositions();
ager@chromium.org5c838252010-02-19 08:53:10 +00001911 CheckBuffer();
1912 RecordRelocInfo(RelocInfo::JS_RETURN);
1913}
1914
1915
lrn@chromium.org7516f052011-03-30 08:52:27 +00001916void Assembler::RecordDebugBreakSlot() {
1917 positions_recorder()->WriteRecordedPositions();
1918 CheckBuffer();
1919 RecordRelocInfo(RelocInfo::DEBUG_BREAK_SLOT);
1920}
1921
1922
ager@chromium.org5c838252010-02-19 08:53:10 +00001923void Assembler::RecordComment(const char* msg) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00001924 if (FLAG_code_comments) {
ager@chromium.org5c838252010-02-19 08:53:10 +00001925 CheckBuffer();
1926 RecordRelocInfo(RelocInfo::COMMENT, reinterpret_cast<intptr_t>(msg));
1927 }
1928}
1929
1930
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001931int Assembler::RelocateInternalReference(byte* pc, intptr_t pc_delta) {
1932 Instr instr = instr_at(pc);
1933 ASSERT(IsJ(instr) || IsLui(instr));
1934 if (IsLui(instr)) {
1935 Instr instr_lui = instr_at(pc + 0 * Assembler::kInstrSize);
1936 Instr instr_ori = instr_at(pc + 1 * Assembler::kInstrSize);
1937 ASSERT(IsOri(instr_ori));
1938 int32_t imm = (instr_lui & static_cast<int32_t>(kImm16Mask)) << kLuiShift;
1939 imm |= (instr_ori & static_cast<int32_t>(kImm16Mask));
1940 if (imm == kEndOfJumpChain) {
1941 return 0; // Number of instructions patched.
1942 }
1943 imm += pc_delta;
1944 ASSERT((imm & 3) == 0);
1945
1946 instr_lui &= ~kImm16Mask;
1947 instr_ori &= ~kImm16Mask;
1948
1949 instr_at_put(pc + 0 * Assembler::kInstrSize,
1950 instr_lui | ((imm >> kLuiShift) & kImm16Mask));
1951 instr_at_put(pc + 1 * Assembler::kInstrSize,
1952 instr_ori | (imm & kImm16Mask));
1953 return 2; // Number of instructions patched.
1954 } else {
1955 uint32_t imm28 = (instr & static_cast<int32_t>(kImm26Mask)) << 2;
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001956 if (static_cast<int32_t>(imm28) == kEndOfJumpChain) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001957 return 0; // Number of instructions patched.
1958 }
1959 imm28 += pc_delta;
1960 imm28 &= kImm28Mask;
1961 ASSERT((imm28 & 3) == 0);
1962
1963 instr &= ~kImm26Mask;
1964 uint32_t imm26 = imm28 >> 2;
1965 ASSERT(is_uint26(imm26));
1966
1967 instr_at_put(pc, instr | (imm26 & kImm26Mask));
1968 return 1; // Number of instructions patched.
1969 }
1970}
1971
1972
ager@chromium.org5c838252010-02-19 08:53:10 +00001973void Assembler::GrowBuffer() {
1974 if (!own_buffer_) FATAL("external code buffer is too small");
1975
1976 // Compute new buffer size.
lrn@chromium.org7516f052011-03-30 08:52:27 +00001977 CodeDesc desc; // The new buffer.
ager@chromium.org5c838252010-02-19 08:53:10 +00001978 if (buffer_size_ < 4*KB) {
1979 desc.buffer_size = 4*KB;
1980 } else if (buffer_size_ < 1*MB) {
1981 desc.buffer_size = 2*buffer_size_;
1982 } else {
1983 desc.buffer_size = buffer_size_ + 1*MB;
1984 }
lrn@chromium.org7516f052011-03-30 08:52:27 +00001985 CHECK_GT(desc.buffer_size, 0); // No overflow.
ager@chromium.org5c838252010-02-19 08:53:10 +00001986
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001987 // Set up new buffer.
ager@chromium.org5c838252010-02-19 08:53:10 +00001988 desc.buffer = NewArray<byte>(desc.buffer_size);
1989
1990 desc.instr_size = pc_offset();
1991 desc.reloc_size = (buffer_ + buffer_size_) - reloc_info_writer.pos();
1992
1993 // Copy the data.
1994 int pc_delta = desc.buffer - buffer_;
1995 int rc_delta = (desc.buffer + desc.buffer_size) - (buffer_ + buffer_size_);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001996 OS::MemMove(desc.buffer, buffer_, desc.instr_size);
1997 OS::MemMove(reloc_info_writer.pos() + rc_delta,
1998 reloc_info_writer.pos(), desc.reloc_size);
ager@chromium.org5c838252010-02-19 08:53:10 +00001999
2000 // Switch buffers.
2001 DeleteArray(buffer_);
2002 buffer_ = desc.buffer;
2003 buffer_size_ = desc.buffer_size;
2004 pc_ += pc_delta;
2005 reloc_info_writer.Reposition(reloc_info_writer.pos() + rc_delta,
2006 reloc_info_writer.last_pc() + pc_delta);
2007
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00002008 // Relocate runtime entries.
2009 for (RelocIterator it(desc); !it.done(); it.next()) {
2010 RelocInfo::Mode rmode = it.rinfo()->rmode();
2011 if (rmode == RelocInfo::INTERNAL_REFERENCE) {
2012 byte* p = reinterpret_cast<byte*>(it.rinfo()->pc());
2013 RelocateInternalReference(p, pc_delta);
2014 }
2015 }
ager@chromium.org5c838252010-02-19 08:53:10 +00002016
2017 ASSERT(!overflow());
2018}
2019
2020
lrn@chromium.org7516f052011-03-30 08:52:27 +00002021void Assembler::db(uint8_t data) {
2022 CheckBuffer();
2023 *reinterpret_cast<uint8_t*>(pc_) = data;
2024 pc_ += sizeof(uint8_t);
2025}
2026
2027
2028void Assembler::dd(uint32_t data) {
2029 CheckBuffer();
2030 *reinterpret_cast<uint32_t*>(pc_) = data;
2031 pc_ += sizeof(uint32_t);
2032}
2033
2034
ager@chromium.org5c838252010-02-19 08:53:10 +00002035void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002036 // We do not try to reuse pool constants.
2037 RelocInfo rinfo(pc_, rmode, data, NULL);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002038 if (rmode >= RelocInfo::JS_RETURN && rmode <= RelocInfo::DEBUG_BREAK_SLOT) {
ager@chromium.org5c838252010-02-19 08:53:10 +00002039 // Adjust code for new modes.
lrn@chromium.org7516f052011-03-30 08:52:27 +00002040 ASSERT(RelocInfo::IsDebugBreakSlot(rmode)
2041 || RelocInfo::IsJSReturn(rmode)
ager@chromium.org5c838252010-02-19 08:53:10 +00002042 || RelocInfo::IsComment(rmode)
2043 || RelocInfo::IsPosition(rmode));
2044 // These modes do not need an entry in the constant pool.
2045 }
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00002046 if (!RelocInfo::IsNone(rinfo.rmode())) {
ager@chromium.org5c838252010-02-19 08:53:10 +00002047 // Don't record external references unless the heap will be serialized.
lrn@chromium.org34e60782011-09-15 07:25:40 +00002048 if (rmode == RelocInfo::EXTERNAL_REFERENCE) {
2049#ifdef DEBUG
2050 if (!Serializer::enabled()) {
2051 Serializer::TooLateToEnableNow();
2052 }
2053#endif
2054 if (!Serializer::enabled() && !emit_debug_code()) {
2055 return;
2056 }
ager@chromium.org5c838252010-02-19 08:53:10 +00002057 }
lrn@chromium.org7516f052011-03-30 08:52:27 +00002058 ASSERT(buffer_space() >= kMaxRelocSize); // Too late to grow buffer here.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002059 if (rmode == RelocInfo::CODE_TARGET_WITH_ID) {
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002060 RelocInfo reloc_info_with_ast_id(pc_,
2061 rmode,
2062 RecordedAstId().ToInt(),
2063 NULL);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002064 ClearRecordedAstId();
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002065 reloc_info_writer.Write(&reloc_info_with_ast_id);
2066 } else {
2067 reloc_info_writer.Write(&rinfo);
2068 }
ager@chromium.org5c838252010-02-19 08:53:10 +00002069 }
2070}
2071
2072
lrn@chromium.org7516f052011-03-30 08:52:27 +00002073void Assembler::BlockTrampolinePoolFor(int instructions) {
2074 BlockTrampolinePoolBefore(pc_offset() + instructions * kInstrSize);
2075}
2076
2077
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00002078void Assembler::CheckTrampolinePool() {
lrn@chromium.org7516f052011-03-30 08:52:27 +00002079 // Some small sequences of instructions must not be broken up by the
2080 // insertion of a trampoline pool; such sequences are protected by setting
2081 // either trampoline_pool_blocked_nesting_ or no_trampoline_pool_before_,
2082 // which are both checked here. Also, recursive calls to CheckTrampolinePool
2083 // are blocked by trampoline_pool_blocked_nesting_.
2084 if ((trampoline_pool_blocked_nesting_ > 0) ||
2085 (pc_offset() < no_trampoline_pool_before_)) {
2086 // Emission is currently blocked; make sure we try again as soon as
2087 // possible.
2088 if (trampoline_pool_blocked_nesting_ > 0) {
2089 next_buffer_check_ = pc_offset() + kInstrSize;
2090 } else {
2091 next_buffer_check_ = no_trampoline_pool_before_;
2092 }
2093 return;
2094 }
2095
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00002096 ASSERT(!trampoline_emitted_);
2097 ASSERT(unbound_labels_count_ >= 0);
2098 if (unbound_labels_count_ > 0) {
2099 // First we emit jump (2 instructions), then we emit trampoline pool.
2100 { BlockTrampolinePoolScope block_trampoline_pool(this);
2101 Label after_pool;
lrn@chromium.org7516f052011-03-30 08:52:27 +00002102 b(&after_pool);
2103 nop();
lrn@chromium.org7516f052011-03-30 08:52:27 +00002104
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00002105 int pool_start = pc_offset();
2106 for (int i = 0; i < unbound_labels_count_; i++) {
2107 uint32_t imm32;
2108 imm32 = jump_address(&after_pool);
2109 { BlockGrowBufferScope block_buf_growth(this);
2110 // Buffer growth (and relocation) must be blocked for internal
2111 // references until associated instructions are emitted and available
2112 // to be patched.
2113 RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE);
2114 lui(at, (imm32 & kHiMask) >> kLuiShift);
2115 ori(at, at, (imm32 & kImm16Mask));
2116 }
2117 jr(at);
2118 nop();
2119 }
2120 bind(&after_pool);
2121 trampoline_ = Trampoline(pool_start, unbound_labels_count_);
2122
2123 trampoline_emitted_ = true;
2124 // As we are only going to emit trampoline once, we need to prevent any
2125 // further emission.
2126 next_buffer_check_ = kMaxInt;
2127 }
2128 } else {
2129 // Number of branches to unbound label at this point is zero, so we can
2130 // move next buffer check to maximum.
2131 next_buffer_check_ = pc_offset() +
2132 kMaxBranchOffset - kTrampolineSlotsSize * 16;
lrn@chromium.org7516f052011-03-30 08:52:27 +00002133 }
2134 return;
2135}
2136
2137
ager@chromium.org5c838252010-02-19 08:53:10 +00002138Address Assembler::target_address_at(Address pc) {
2139 Instr instr1 = instr_at(pc);
2140 Instr instr2 = instr_at(pc + kInstrSize);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002141 // Interpret 2 instructions generated by li: lui/ori
2142 if ((GetOpcodeField(instr1) == LUI) && (GetOpcodeField(instr2) == ORI)) {
2143 // Assemble the 32 bit value.
ager@chromium.org5c838252010-02-19 08:53:10 +00002144 return reinterpret_cast<Address>(
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002145 (GetImmediate16(instr1) << 16) | GetImmediate16(instr2));
ager@chromium.org5c838252010-02-19 08:53:10 +00002146 }
2147
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002148 // We should never get here, force a bad address if we do.
ager@chromium.org5c838252010-02-19 08:53:10 +00002149 UNREACHABLE();
2150 return (Address)0x0;
2151}
2152
2153
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +00002154// MIPS and ia32 use opposite encoding for qNaN and sNaN, such that ia32
2155// qNaN is a MIPS sNaN, and ia32 sNaN is MIPS qNaN. If running from a heap
2156// snapshot generated on ia32, the resulting MIPS sNaN must be quieted.
2157// OS::nan_value() returns a qNaN.
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00002158void Assembler::QuietNaN(HeapObject* object) {
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +00002159 HeapNumber::cast(object)->set_value(OS::nan_value());
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00002160}
2161
2162
lrn@chromium.org34e60782011-09-15 07:25:40 +00002163// On Mips, a target address is stored in a lui/ori instruction pair, each
2164// of which load 16 bits of the 32-bit address to a register.
2165// Patching the address must replace both instr, and flush the i-cache.
2166//
2167// There is an optimization below, which emits a nop when the address
2168// fits in just 16 bits. This is unlikely to help, and should be benchmarked,
2169// and possibly removed.
ager@chromium.org5c838252010-02-19 08:53:10 +00002170void Assembler::set_target_address_at(Address pc, Address target) {
ager@chromium.org5c838252010-02-19 08:53:10 +00002171 Instr instr2 = instr_at(pc + kInstrSize);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002172 uint32_t rt_code = GetRtField(instr2);
ager@chromium.org5c838252010-02-19 08:53:10 +00002173 uint32_t* p = reinterpret_cast<uint32_t*>(pc);
2174 uint32_t itarget = reinterpret_cast<uint32_t>(target);
2175
lrn@chromium.org34e60782011-09-15 07:25:40 +00002176#ifdef DEBUG
2177 // Check we have the result from a li macro-instruction, using instr pair.
2178 Instr instr1 = instr_at(pc);
2179 CHECK((GetOpcodeField(instr1) == LUI && GetOpcodeField(instr2) == ORI));
2180#endif
2181
2182 // Must use 2 instructions to insure patchable code => just use lui and ori.
2183 // lui rt, upper-16.
2184 // ori rt rt, lower-16.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002185 *p = LUI | rt_code | ((itarget & kHiMask) >> kLuiShift);
2186 *(p+1) = ORI | rt_code | (rt_code << 5) | (itarget & kImm16Mask);
ager@chromium.org5c838252010-02-19 08:53:10 +00002187
lrn@chromium.org34e60782011-09-15 07:25:40 +00002188 // The following code is an optimization for the common case of Call()
2189 // or Jump() which is load to register, and jump through register:
2190 // li(t9, address); jalr(t9) (or jr(t9)).
2191 // If the destination address is in the same 256 MB page as the call, it
2192 // is faster to do a direct jal, or j, rather than jump thru register, since
2193 // that lets the cpu pipeline prefetch the target address. However each
2194 // time the address above is patched, we have to patch the direct jal/j
2195 // instruction, as well as possibly revert to jalr/jr if we now cross a
2196 // 256 MB page. Note that with the jal/j instructions, we do not need to
2197 // load the register, but that code is left, since it makes it easy to
2198 // revert this process. A further optimization could try replacing the
2199 // li sequence with nops.
2200 // This optimization can only be applied if the rt-code from instr2 is the
2201 // register used for the jalr/jr. Finally, we have to skip 'jr ra', which is
2202 // mips return. Occasionally this lands after an li().
2203
2204 Instr instr3 = instr_at(pc + 2 * kInstrSize);
2205 uint32_t ipc = reinterpret_cast<uint32_t>(pc + 3 * kInstrSize);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002206 bool in_range = (ipc ^ static_cast<uint32_t>(itarget) >>
2207 (kImm26Bits + kImmFieldShift)) == 0;
2208 uint32_t target_field =
ulan@chromium.org837a67e2013-06-11 15:39:48 +00002209 static_cast<uint32_t>(itarget & kJumpAddrMask) >> kImmFieldShift;
lrn@chromium.org34e60782011-09-15 07:25:40 +00002210 bool patched_jump = false;
2211
2212#ifndef ALLOW_JAL_IN_BOUNDARY_REGION
2213 // This is a workaround to the 24k core E156 bug (affect some 34k cores also).
2214 // Since the excluded space is only 64KB out of 256MB (0.02 %), we will just
2215 // apply this workaround for all cores so we don't have to identify the core.
2216 if (in_range) {
2217 // The 24k core E156 bug has some very specific requirements, we only check
2218 // the most simple one: if the address of the delay slot instruction is in
2219 // the first or last 32 KB of the 256 MB segment.
2220 uint32_t segment_mask = ((256 * MB) - 1) ^ ((32 * KB) - 1);
2221 uint32_t ipc_segment_addr = ipc & segment_mask;
2222 if (ipc_segment_addr == 0 || ipc_segment_addr == segment_mask)
2223 in_range = false;
2224 }
2225#endif
2226
2227 if (IsJalr(instr3)) {
2228 // Try to convert JALR to JAL.
2229 if (in_range && GetRt(instr2) == GetRs(instr3)) {
2230 *(p+2) = JAL | target_field;
2231 patched_jump = true;
2232 }
2233 } else if (IsJr(instr3)) {
2234 // Try to convert JR to J, skip returns (jr ra).
2235 bool is_ret = static_cast<int>(GetRs(instr3)) == ra.code();
2236 if (in_range && !is_ret && GetRt(instr2) == GetRs(instr3)) {
2237 *(p+2) = J | target_field;
2238 patched_jump = true;
2239 }
2240 } else if (IsJal(instr3)) {
2241 if (in_range) {
2242 // We are patching an already converted JAL.
2243 *(p+2) = JAL | target_field;
2244 } else {
2245 // Patch JAL, but out of range, revert to JALR.
2246 // JALR rs reg is the rt reg specified in the ORI instruction.
2247 uint32_t rs_field = GetRt(instr2) << kRsShift;
2248 uint32_t rd_field = ra.code() << kRdShift; // Return-address (ra) reg.
2249 *(p+2) = SPECIAL | rs_field | rd_field | JALR;
2250 }
2251 patched_jump = true;
2252 } else if (IsJ(instr3)) {
2253 if (in_range) {
2254 // We are patching an already converted J (jump).
2255 *(p+2) = J | target_field;
2256 } else {
2257 // Trying patch J, but out of range, just go back to JR.
2258 // JR 'rs' reg is the 'rt' reg specified in the ORI instruction (instr2).
2259 uint32_t rs_field = GetRt(instr2) << kRsShift;
2260 *(p+2) = SPECIAL | rs_field | JR;
2261 }
2262 patched_jump = true;
2263 }
2264
2265 CPU::FlushICache(pc, (patched_jump ? 3 : 2) * sizeof(int32_t));
ager@chromium.org5c838252010-02-19 08:53:10 +00002266}
2267
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00002268
lrn@chromium.org34e60782011-09-15 07:25:40 +00002269void Assembler::JumpLabelToJumpRegister(Address pc) {
2270 // Address pc points to lui/ori instructions.
2271 // Jump to label may follow at pc + 2 * kInstrSize.
2272 uint32_t* p = reinterpret_cast<uint32_t*>(pc);
2273#ifdef DEBUG
2274 Instr instr1 = instr_at(pc);
2275#endif
2276 Instr instr2 = instr_at(pc + 1 * kInstrSize);
2277 Instr instr3 = instr_at(pc + 2 * kInstrSize);
2278 bool patched = false;
2279
2280 if (IsJal(instr3)) {
2281 ASSERT(GetOpcodeField(instr1) == LUI);
2282 ASSERT(GetOpcodeField(instr2) == ORI);
2283
2284 uint32_t rs_field = GetRt(instr2) << kRsShift;
2285 uint32_t rd_field = ra.code() << kRdShift; // Return-address (ra) reg.
2286 *(p+2) = SPECIAL | rs_field | rd_field | JALR;
2287 patched = true;
2288 } else if (IsJ(instr3)) {
2289 ASSERT(GetOpcodeField(instr1) == LUI);
2290 ASSERT(GetOpcodeField(instr2) == ORI);
2291
2292 uint32_t rs_field = GetRt(instr2) << kRsShift;
2293 *(p+2) = SPECIAL | rs_field | JR;
2294 patched = true;
2295 }
2296
2297 if (patched) {
2298 CPU::FlushICache(pc+2, sizeof(Address));
2299 }
2300}
ager@chromium.org5c838252010-02-19 08:53:10 +00002301
2302} } // namespace v8::internal
2303
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002304#endif // V8_TARGET_ARCH_MIPS