1 // 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.
33 // Copyright 2012 the V8 project authors. All rights reserved.
34
35
36 #include "v8.h"
37
38 #if defined(V8_TARGET_ARCH_MIPS)
39
40 #include "mips/assembler-mips-inl.h"
41 #include "serialize.h"
42
43 namespace v8 {
44 namespace internal {
45
46 #ifdef DEBUG
47 bool CpuFeatures::initialized_ = false;
48 #endif
49 unsigned CpuFeatures::supported_ = 0;
50 unsigned CpuFeatures::found_by_runtime_probing_ = 0;
51
52
53 // Get the CPU features enabled by the build. For cross compilation the
54 // preprocessor symbols CAN_USE_FPU_INSTRUCTIONS
55 // can be defined to enable FPU instructions when building the
56 // snapshot.
CpuFeaturesImpliedByCompiler()57 static uint64_t CpuFeaturesImpliedByCompiler() {
58 uint64_t answer = 0;
59 #ifdef CAN_USE_FPU_INSTRUCTIONS
60 answer |= 1u << FPU;
61 #endif // def CAN_USE_FPU_INSTRUCTIONS
62
63 #ifdef __mips__
64 // If the compiler is allowed to use FPU then we can use FPU too in our code
65 // generation even when generating snapshots. This won't work for cross
66 // compilation.
67 #if(defined(__mips_hard_float) && __mips_hard_float != 0)
68 answer |= 1u << FPU;
69 #endif // defined(__mips_hard_float) && __mips_hard_float != 0
70 #endif // def __mips__
71
72 return answer;
73 }
74
75
Probe()76 void CpuFeatures::Probe() {
77 unsigned standard_features = (OS::CpuFeaturesImpliedByPlatform() |
78 CpuFeaturesImpliedByCompiler());
79 ASSERT(supported_ == 0 || supported_ == standard_features);
80 #ifdef DEBUG
81 initialized_ = true;
82 #endif
83
84 // Get the features implied by the OS and the compiler settings. This is the
85 // minimal set of features which is also allowed for generated code in the
86 // snapshot.
87 supported_ |= standard_features;
88
89 if (Serializer::enabled()) {
90 // No probing for features if we might serialize (generate snapshot).
91 return;
92 }
93
94 // If the compiler is allowed to use fpu then we can use fpu too in our
95 // code generation.
96 #if !defined(__mips__)
97 // For the simulator=mips build, use FPU when FLAG_enable_fpu is enabled.
98 if (FLAG_enable_fpu) {
99 supported_ |= 1u << FPU;
100 }
101 #else
102 // Probe for additional features not already known to be available.
103 if (OS::MipsCpuHasFeature(FPU)) {
104 // This implementation also sets the FPU flags if
105 // runtime detection of FPU returns true.
106 supported_ |= 1u << FPU;
107 found_by_runtime_probing_ |= 1u << FPU;
108 }
109 #endif
110 }
111
112
ToNumber(Register reg)113 int ToNumber(Register reg) {
114 ASSERT(reg.is_valid());
115 const int kNumbers[] = {
116 0, // zero_reg
117 1, // at
118 2, // v0
119 3, // v1
120 4, // a0
121 5, // a1
122 6, // a2
123 7, // a3
124 8, // t0
125 9, // t1
126 10, // t2
127 11, // t3
128 12, // t4
129 13, // t5
130 14, // t6
131 15, // t7
132 16, // s0
133 17, // s1
134 18, // s2
135 19, // s3
136 20, // s4
137 21, // s5
138 22, // s6
139 23, // s7
140 24, // t8
141 25, // t9
142 26, // k0
143 27, // k1
144 28, // gp
145 29, // sp
146 30, // fp
147 31, // ra
148 };
149 return kNumbers[reg.code()];
150 }
151
152
ToRegister(int num)153 Register ToRegister(int num) {
154 ASSERT(num >= 0 && num < kNumRegisters);
155 const Register kRegisters[] = {
156 zero_reg,
157 at,
158 v0, v1,
159 a0, a1, a2, a3,
160 t0, t1, t2, t3, t4, t5, t6, t7,
161 s0, s1, s2, s3, s4, s5, s6, s7,
162 t8, t9,
163 k0, k1,
164 gp,
165 sp,
166 fp,
167 ra
168 };
169 return kRegisters[num];
170 }
171
172
173 // -----------------------------------------------------------------------------
174 // Implementation of RelocInfo.
175
176 const int RelocInfo::kApplyMask = RelocInfo::kCodeTargetMask |
177 1 << RelocInfo::INTERNAL_REFERENCE;
178
179
IsCodedSpecially()180 bool RelocInfo::IsCodedSpecially() {
181 // The deserializer needs to know whether a pointer is specially coded. Being
182 // specially coded on MIPS means that it is a lui/ori instruction, and that is
183 // always the case inside code objects.
184 return true;
185 }
186
187
188 // Patch the code at the current address with the supplied instructions.
PatchCode(byte * instructions,int instruction_count)189 void RelocInfo::PatchCode(byte* instructions, int instruction_count) {
190 Instr* pc = reinterpret_cast<Instr*>(pc_);
191 Instr* instr = reinterpret_cast<Instr*>(instructions);
192 for (int i = 0; i < instruction_count; i++) {
193 *(pc + i) = *(instr + i);
194 }
195
196 // Indicate that code has changed.
197 CPU::FlushICache(pc_, instruction_count * Assembler::kInstrSize);
198 }
199
200
201 // Patch the code at the current PC with a call to the target address.
202 // Additional guard instructions can be added if required.
PatchCodeWithCall(Address target,int guard_bytes)203 void RelocInfo::PatchCodeWithCall(Address target, int guard_bytes) {
204 // Patch the code at the current address with a call to the target.
205 UNIMPLEMENTED_MIPS();
206 }
207
208
209 // -----------------------------------------------------------------------------
210 // Implementation of Operand and MemOperand.
211 // See assembler-mips-inl.h for inlined constructors.
212
Operand(Handle<Object> handle)213 Operand::Operand(Handle<Object> handle) {
214 rm_ = no_reg;
215 // Verify all Objects referred by code are NOT in new space.
216 Object* obj = *handle;
217 ASSERT(!HEAP->InNewSpace(obj));
218 if (obj->IsHeapObject()) {
219 imm32_ = reinterpret_cast<intptr_t>(handle.location());
220 rmode_ = RelocInfo::EMBEDDED_OBJECT;
221 } else {
222 // No relocation needed.
223 imm32_ = reinterpret_cast<intptr_t>(obj);
224 rmode_ = RelocInfo::NONE;
225 }
226 }
227
228
MemOperand(Register rm,int32_t offset)229 MemOperand::MemOperand(Register rm, int32_t offset) : Operand(rm) {
230 offset_ = offset;
231 }
232
233
234 // -----------------------------------------------------------------------------
235 // Specific instructions, constants, and masks.
236
237 static const int kNegOffset = 0x00008000;
238 // addiu(sp, sp, 4) aka Pop() operation or part of Pop(r)
239 // operations as post-increment of sp.
240 const Instr kPopInstruction = ADDIU | (kRegister_sp_Code << kRsShift)
241 | (kRegister_sp_Code << kRtShift) | (kPointerSize & kImm16Mask);
242 // addiu(sp, sp, -4) part of Push(r) operation as pre-decrement of sp.
243 const Instr kPushInstruction = ADDIU | (kRegister_sp_Code << kRsShift)
244 | (kRegister_sp_Code << kRtShift) | (-kPointerSize & kImm16Mask);
245 // sw(r, MemOperand(sp, 0))
246 const Instr kPushRegPattern = SW | (kRegister_sp_Code << kRsShift)
247 | (0 & kImm16Mask);
248 // lw(r, MemOperand(sp, 0))
249 const Instr kPopRegPattern = LW | (kRegister_sp_Code << kRsShift)
250 | (0 & kImm16Mask);
251
252 const Instr kLwRegFpOffsetPattern = LW | (kRegister_fp_Code << kRsShift)
253 | (0 & kImm16Mask);
254
255 const Instr kSwRegFpOffsetPattern = SW | (kRegister_fp_Code << kRsShift)
256 | (0 & kImm16Mask);
257
258 const Instr kLwRegFpNegOffsetPattern = LW | (kRegister_fp_Code << kRsShift)
259 | (kNegOffset & kImm16Mask);
260
261 const Instr kSwRegFpNegOffsetPattern = SW | (kRegister_fp_Code << kRsShift)
262 | (kNegOffset & kImm16Mask);
263 // A mask for the Rt register for push, pop, lw, sw instructions.
264 const Instr kRtMask = kRtFieldMask;
265 const Instr kLwSwInstrTypeMask = 0xffe00000;
266 const Instr kLwSwInstrArgumentMask = ~kLwSwInstrTypeMask;
267 const Instr kLwSwOffsetMask = kImm16Mask;
268
269
270 // Spare buffer.
271 static const int kMinimalBufferSize = 4 * KB;
272
273
Assembler(Isolate * arg_isolate,void * buffer,int buffer_size)274 Assembler::Assembler(Isolate* arg_isolate, void* buffer, int buffer_size)
275 : AssemblerBase(arg_isolate),
276 positions_recorder_(this),
277 emit_debug_code_(FLAG_debug_code) {
278 if (buffer == NULL) {
279 // Do our own buffer management.
280 if (buffer_size <= kMinimalBufferSize) {
281 buffer_size = kMinimalBufferSize;
282
283 if (isolate()->assembler_spare_buffer() != NULL) {
284 buffer = isolate()->assembler_spare_buffer();
285 isolate()->set_assembler_spare_buffer(NULL);
286 }
287 }
288 if (buffer == NULL) {
289 buffer_ = NewArray<byte>(buffer_size);
290 } else {
291 buffer_ = static_cast<byte*>(buffer);
292 }
293 buffer_size_ = buffer_size;
294 own_buffer_ = true;
295
296 } else {
297 // Use externally provided buffer instead.
298 ASSERT(buffer_size > 0);
299 buffer_ = static_cast<byte*>(buffer);
300 buffer_size_ = buffer_size;
301 own_buffer_ = false;
302 }
303
304 // Set up buffer pointers.
305 ASSERT(buffer_ != NULL);
306 pc_ = buffer_;
307 reloc_info_writer.Reposition(buffer_ + buffer_size, pc_);
308
309 last_trampoline_pool_end_ = 0;
310 no_trampoline_pool_before_ = 0;
311 trampoline_pool_blocked_nesting_ = 0;
312 // We leave space (16 * kTrampolineSlotsSize)
313 // for BlockTrampolinePoolScope buffer.
314 next_buffer_check_ = kMaxBranchOffset - kTrampolineSlotsSize * 16;
315 internal_trampoline_exception_ = false;
316 last_bound_pos_ = 0;
317
318 trampoline_emitted_ = false;
319 unbound_labels_count_ = 0;
320 block_buffer_growth_ = false;
321
322 ClearRecordedAstId();
323 }
324
325
~Assembler()326 Assembler::~Assembler() {
327 if (own_buffer_) {
328 if (isolate()->assembler_spare_buffer() == NULL &&
329 buffer_size_ == kMinimalBufferSize) {
330 isolate()->set_assembler_spare_buffer(buffer_);
331 } else {
332 DeleteArray(buffer_);
333 }
334 }
335 }
336
337
GetCode(CodeDesc * desc)338 void Assembler::GetCode(CodeDesc* desc) {
339 ASSERT(pc_ <= reloc_info_writer.pos()); // No overlap.
340 // Set up code descriptor.
341 desc->buffer = buffer_;
342 desc->buffer_size = buffer_size_;
343 desc->instr_size = pc_offset();
344 desc->reloc_size = (buffer_ + buffer_size_) - reloc_info_writer.pos();
345 }
346
347
Align(int m)348 void Assembler::Align(int m) {
349 ASSERT(m >= 4 && IsPowerOf2(m));
350 while ((pc_offset() & (m - 1)) != 0) {
351 nop();
352 }
353 }
354
355
CodeTargetAlign()356 void Assembler::CodeTargetAlign() {
357 // No advantage to aligning branch/call targets to more than
358 // single instruction, that I am aware of.
359 Align(4);
360 }
361
362
GetRtReg(Instr instr)363 Register Assembler::GetRtReg(Instr instr) {
364 Register rt;
365 rt.code_ = (instr & kRtFieldMask) >> kRtShift;
366 return rt;
367 }
368
369
GetRsReg(Instr instr)370 Register Assembler::GetRsReg(Instr instr) {
371 Register rs;
372 rs.code_ = (instr & kRsFieldMask) >> kRsShift;
373 return rs;
374 }
375
376
GetRdReg(Instr instr)377 Register Assembler::GetRdReg(Instr instr) {
378 Register rd;
379 rd.code_ = (instr & kRdFieldMask) >> kRdShift;
380 return rd;
381 }
382
383
GetRt(Instr instr)384 uint32_t Assembler::GetRt(Instr instr) {
385 return (instr & kRtFieldMask) >> kRtShift;
386 }
387
388
GetRtField(Instr instr)389 uint32_t Assembler::GetRtField(Instr instr) {
390 return instr & kRtFieldMask;
391 }
392
393
GetRs(Instr instr)394 uint32_t Assembler::GetRs(Instr instr) {
395 return (instr & kRsFieldMask) >> kRsShift;
396 }
397
398
GetRsField(Instr instr)399 uint32_t Assembler::GetRsField(Instr instr) {
400 return instr & kRsFieldMask;
401 }
402
403
GetRd(Instr instr)404 uint32_t Assembler::GetRd(Instr instr) {
405 return (instr & kRdFieldMask) >> kRdShift;
406 }
407
408
GetRdField(Instr instr)409 uint32_t Assembler::GetRdField(Instr instr) {
410 return instr & kRdFieldMask;
411 }
412
413
GetSa(Instr instr)414 uint32_t Assembler::GetSa(Instr instr) {
415 return (instr & kSaFieldMask) >> kSaShift;
416 }
417
418
GetSaField(Instr instr)419 uint32_t Assembler::GetSaField(Instr instr) {
420 return instr & kSaFieldMask;
421 }
422
423
GetOpcodeField(Instr instr)424 uint32_t Assembler::GetOpcodeField(Instr instr) {
425 return instr & kOpcodeMask;
426 }
427
428
GetFunction(Instr instr)429 uint32_t Assembler::GetFunction(Instr instr) {
430 return (instr & kFunctionFieldMask) >> kFunctionShift;
431 }
432
433
GetFunctionField(Instr instr)434 uint32_t Assembler::GetFunctionField(Instr instr) {
435 return instr & kFunctionFieldMask;
436 }
437
438
GetImmediate16(Instr instr)439 uint32_t Assembler::GetImmediate16(Instr instr) {
440 return instr & kImm16Mask;
441 }
442
443
GetLabelConst(Instr instr)444 uint32_t Assembler::GetLabelConst(Instr instr) {
445 return instr & ~kImm16Mask;
446 }
447
448
IsPop(Instr instr)449 bool Assembler::IsPop(Instr instr) {
450 return (instr & ~kRtMask) == kPopRegPattern;
451 }
452
453
IsPush(Instr instr)454 bool Assembler::IsPush(Instr instr) {
455 return (instr & ~kRtMask) == kPushRegPattern;
456 }
457
458
IsSwRegFpOffset(Instr instr)459 bool Assembler::IsSwRegFpOffset(Instr instr) {
460 return ((instr & kLwSwInstrTypeMask) == kSwRegFpOffsetPattern);
461 }
462
463
IsLwRegFpOffset(Instr instr)464 bool Assembler::IsLwRegFpOffset(Instr instr) {
465 return ((instr & kLwSwInstrTypeMask) == kLwRegFpOffsetPattern);
466 }
467
468
IsSwRegFpNegOffset(Instr instr)469 bool Assembler::IsSwRegFpNegOffset(Instr instr) {
470 return ((instr & (kLwSwInstrTypeMask | kNegOffset)) ==
471 kSwRegFpNegOffsetPattern);
472 }
473
474
IsLwRegFpNegOffset(Instr instr)475 bool Assembler::IsLwRegFpNegOffset(Instr instr) {
476 return ((instr & (kLwSwInstrTypeMask | kNegOffset)) ==
477 kLwRegFpNegOffsetPattern);
478 }
479
480
481 // Labels refer to positions in the (to be) generated code.
482 // There are bound, linked, and unused labels.
483 //
484 // Bound labels refer to known positions in the already
485 // generated code. pos() is the position the label refers to.
486 //
487 // Linked labels refer to unknown positions in the code
488 // to be generated; pos() is the position of the last
489 // instruction using the label.
490
491 // The link chain is terminated by a value in the instruction of -1,
492 // which is an otherwise illegal value (branch -1 is inf loop).
493 // The instruction 16-bit offset field addresses 32-bit words, but in
494 // code is conv to an 18-bit value addressing bytes, hence the -4 value.
495
496 const int kEndOfChain = -4;
497 // Determines the end of the Jump chain (a subset of the label link chain).
498 const int kEndOfJumpChain = 0;
499
500
IsBranch(Instr instr)501 bool Assembler::IsBranch(Instr instr) {
502 uint32_t opcode = GetOpcodeField(instr);
503 uint32_t rt_field = GetRtField(instr);
504 uint32_t rs_field = GetRsField(instr);
505 uint32_t label_constant = GetLabelConst(instr);
506 // Checks if the instruction is a branch.
507 return opcode == BEQ ||
508 opcode == BNE ||
509 opcode == BLEZ ||
510 opcode == BGTZ ||
511 opcode == BEQL ||
512 opcode == BNEL ||
513 opcode == BLEZL ||
514 opcode == BGTZL ||
515 (opcode == REGIMM && (rt_field == BLTZ || rt_field == BGEZ ||
516 rt_field == BLTZAL || rt_field == BGEZAL)) ||
517 (opcode == COP1 && rs_field == BC1) || // Coprocessor branch.
518 label_constant == 0; // Emitted label const in reg-exp engine.
519 }
520
521
IsBeq(Instr instr)522 bool Assembler::IsBeq(Instr instr) {
523 return GetOpcodeField(instr) == BEQ;
524 }
525
526
IsBne(Instr instr)527 bool Assembler::IsBne(Instr instr) {
528 return GetOpcodeField(instr) == BNE;
529 }
530
531
IsJump(Instr instr)532 bool Assembler::IsJump(Instr instr) {
533 uint32_t opcode = GetOpcodeField(instr);
534 uint32_t rt_field = GetRtField(instr);
535 uint32_t rd_field = GetRdField(instr);
536 uint32_t function_field = GetFunctionField(instr);
537 // Checks if the instruction is a jump.
538 return opcode == J || opcode == JAL ||
539 (opcode == SPECIAL && rt_field == 0 &&
540 ((function_field == JALR) || (rd_field == 0 && (function_field == JR))));
541 }
542
543
IsJ(Instr instr)544 bool Assembler::IsJ(Instr instr) {
545 uint32_t opcode = GetOpcodeField(instr);
546 // Checks if the instruction is a jump.
547 return opcode == J;
548 }
549
550
IsJal(Instr instr)551 bool Assembler::IsJal(Instr instr) {
552 return GetOpcodeField(instr) == JAL;
553 }
554
IsJr(Instr instr)555 bool Assembler::IsJr(Instr instr) {
556 return GetOpcodeField(instr) == SPECIAL && GetFunctionField(instr) == JR;
557 }
558
IsJalr(Instr instr)559 bool Assembler::IsJalr(Instr instr) {
560 return GetOpcodeField(instr) == SPECIAL && GetFunctionField(instr) == JALR;
561 }
562
563
IsLui(Instr instr)564 bool Assembler::IsLui(Instr instr) {
565 uint32_t opcode = GetOpcodeField(instr);
566 // Checks if the instruction is a load upper immediate.
567 return opcode == LUI;
568 }
569
570
IsOri(Instr instr)571 bool Assembler::IsOri(Instr instr) {
572 uint32_t opcode = GetOpcodeField(instr);
573 // Checks if the instruction is a load upper immediate.
574 return opcode == ORI;
575 }
576
577
IsNop(Instr instr,unsigned int type)578 bool Assembler::IsNop(Instr instr, unsigned int type) {
579 // See Assembler::nop(type).
580 ASSERT(type < 32);
581 uint32_t opcode = GetOpcodeField(instr);
582 uint32_t rt = GetRt(instr);
583 uint32_t rs = GetRs(instr);
584 uint32_t sa = GetSa(instr);
585
586 // nop(type) == sll(zero_reg, zero_reg, type);
587 // Technically all these values will be 0 but
588 // this makes more sense to the reader.
589
590 bool ret = (opcode == SLL &&
591 rt == static_cast<uint32_t>(ToNumber(zero_reg)) &&
592 rs == static_cast<uint32_t>(ToNumber(zero_reg)) &&
593 sa == type);
594
595 return ret;
596 }
597
598
GetBranchOffset(Instr instr)599 int32_t Assembler::GetBranchOffset(Instr instr) {
600 ASSERT(IsBranch(instr));
601 return ((int16_t)(instr & kImm16Mask)) << 2;
602 }
603
604
IsLw(Instr instr)605 bool Assembler::IsLw(Instr instr) {
606 return ((instr & kOpcodeMask) == LW);
607 }
608
609
GetLwOffset(Instr instr)610 int16_t Assembler::GetLwOffset(Instr instr) {
611 ASSERT(IsLw(instr));
612 return ((instr & kImm16Mask));
613 }
614
615
SetLwOffset(Instr instr,int16_t offset)616 Instr Assembler::SetLwOffset(Instr instr, int16_t offset) {
617 ASSERT(IsLw(instr));
618
619 // We actually create a new lw instruction based on the original one.
620 Instr temp_instr = LW | (instr & kRsFieldMask) | (instr & kRtFieldMask)
621 | (offset & kImm16Mask);
622
623 return temp_instr;
624 }
625
626
IsSw(Instr instr)627 bool Assembler::IsSw(Instr instr) {
628 return ((instr & kOpcodeMask) == SW);
629 }
630
631
SetSwOffset(Instr instr,int16_t offset)632 Instr Assembler::SetSwOffset(Instr instr, int16_t offset) {
633 ASSERT(IsSw(instr));
634 return ((instr & ~kImm16Mask) | (offset & kImm16Mask));
635 }
636
637
IsAddImmediate(Instr instr)638 bool Assembler::IsAddImmediate(Instr instr) {
639 return ((instr & kOpcodeMask) == ADDIU);
640 }
641
642
SetAddImmediateOffset(Instr instr,int16_t offset)643 Instr Assembler::SetAddImmediateOffset(Instr instr, int16_t offset) {
644 ASSERT(IsAddImmediate(instr));
645 return ((instr & ~kImm16Mask) | (offset & kImm16Mask));
646 }
647
648
IsAndImmediate(Instr instr)649 bool Assembler::IsAndImmediate(Instr instr) {
650 return GetOpcodeField(instr) == ANDI;
651 }
652
653
target_at(int32_t pos)654 int Assembler::target_at(int32_t pos) {
655 Instr instr = instr_at(pos);
656 if ((instr & ~kImm16Mask) == 0) {
657 // Emitted label constant, not part of a branch.
658 if (instr == 0) {
659 return kEndOfChain;
660 } else {
661 int32_t imm18 =((instr & static_cast<int32_t>(kImm16Mask)) << 16) >> 14;
662 return (imm18 + pos);
663 }
664 }
665 // Check we have a branch or jump instruction.
666 ASSERT(IsBranch(instr) || IsJ(instr) || IsLui(instr));
667 // Do NOT change this to <<2. We rely on arithmetic shifts here, assuming
668 // the compiler uses arithmectic shifts for signed integers.
669 if (IsBranch(instr)) {
670 int32_t imm18 = ((instr & static_cast<int32_t>(kImm16Mask)) << 16) >> 14;
671
672 if (imm18 == kEndOfChain) {
673 // EndOfChain sentinel is returned directly, not relative to pc or pos.
674 return kEndOfChain;
675 } else {
676 return pos + kBranchPCOffset + imm18;
677 }
678 } else if (IsLui(instr)) {
679 Instr instr_lui = instr_at(pos + 0 * Assembler::kInstrSize);
680 Instr instr_ori = instr_at(pos + 1 * Assembler::kInstrSize);
681 ASSERT(IsOri(instr_ori));
682 int32_t imm = (instr_lui & static_cast<int32_t>(kImm16Mask)) << kLuiShift;
683 imm |= (instr_ori & static_cast<int32_t>(kImm16Mask));
684
685 if (imm == kEndOfJumpChain) {
686 // EndOfChain sentinel is returned directly, not relative to pc or pos.
687 return kEndOfChain;
688 } else {
689 uint32_t instr_address = reinterpret_cast<int32_t>(buffer_ + pos);
690 int32_t delta = instr_address - imm;
691 ASSERT(pos > delta);
692 return pos - delta;
693 }
694 } else {
695 int32_t imm28 = (instr & static_cast<int32_t>(kImm26Mask)) << 2;
696 if (imm28 == kEndOfJumpChain) {
697 // EndOfChain sentinel is returned directly, not relative to pc or pos.
698 return kEndOfChain;
699 } else {
700 uint32_t instr_address = reinterpret_cast<int32_t>(buffer_ + pos);
701 instr_address &= kImm28Mask;
702 int32_t delta = instr_address - imm28;
703 ASSERT(pos > delta);
704 return pos - delta;
705 }
706 }
707 }
708
709
target_at_put(int32_t pos,int32_t target_pos)710 void Assembler::target_at_put(int32_t pos, int32_t target_pos) {
711 Instr instr = instr_at(pos);
712 if ((instr & ~kImm16Mask) == 0) {
713 ASSERT(target_pos == kEndOfChain || target_pos >= 0);
714 // Emitted label constant, not part of a branch.
715 // Make label relative to Code* of generated Code object.
716 instr_at_put(pos, target_pos + (Code::kHeaderSize - kHeapObjectTag));
717 return;
718 }
719
720 ASSERT(IsBranch(instr) || IsJ(instr) || IsLui(instr));
721 if (IsBranch(instr)) {
722 int32_t imm18 = target_pos - (pos + kBranchPCOffset);
723 ASSERT((imm18 & 3) == 0);
724
725 instr &= ~kImm16Mask;
726 int32_t imm16 = imm18 >> 2;
727 ASSERT(is_int16(imm16));
728
729 instr_at_put(pos, instr | (imm16 & kImm16Mask));
730 } else if (IsLui(instr)) {
731 Instr instr_lui = instr_at(pos + 0 * Assembler::kInstrSize);
732 Instr instr_ori = instr_at(pos + 1 * Assembler::kInstrSize);
733 ASSERT(IsOri(instr_ori));
734 uint32_t imm = (uint32_t)buffer_ + target_pos;
735 ASSERT((imm & 3) == 0);
736
737 instr_lui &= ~kImm16Mask;
738 instr_ori &= ~kImm16Mask;
739
740 instr_at_put(pos + 0 * Assembler::kInstrSize,
741 instr_lui | ((imm & kHiMask) >> kLuiShift));
742 instr_at_put(pos + 1 * Assembler::kInstrSize,
743 instr_ori | (imm & kImm16Mask));
744 } else {
745 uint32_t imm28 = (uint32_t)buffer_ + target_pos;
746 imm28 &= kImm28Mask;
747 ASSERT((imm28 & 3) == 0);
748
749 instr &= ~kImm26Mask;
750 uint32_t imm26 = imm28 >> 2;
751 ASSERT(is_uint26(imm26));
752
753 instr_at_put(pos, instr | (imm26 & kImm26Mask));
754 }
755 }
756
757
print(Label * L)758 void Assembler::print(Label* L) {
759 if (L->is_unused()) {
760 PrintF("unused label\n");
761 } else if (L->is_bound()) {
762 PrintF("bound label to %d\n", L->pos());
763 } else if (L->is_linked()) {
764 Label l = *L;
765 PrintF("unbound label");
766 while (l.is_linked()) {
767 PrintF("@ %d ", l.pos());
768 Instr instr = instr_at(l.pos());
769 if ((instr & ~kImm16Mask) == 0) {
770 PrintF("value\n");
771 } else {
772 PrintF("%d\n", instr);
773 }
774 next(&l);
775 }
776 } else {
777 PrintF("label in inconsistent state (pos = %d)\n", L->pos_);
778 }
779 }
780
781
bind_to(Label * L,int pos)782 void Assembler::bind_to(Label* L, int pos) {
783 ASSERT(0 <= pos && pos <= pc_offset()); // Must have valid binding position.
784 int32_t trampoline_pos = kInvalidSlotPos;
785 if (L->is_linked() && !trampoline_emitted_) {
786 unbound_labels_count_--;
787 next_buffer_check_ += kTrampolineSlotsSize;
788 }
789
790 while (L->is_linked()) {
791 int32_t fixup_pos = L->pos();
792 int32_t dist = pos - fixup_pos;
793 next(L); // Call next before overwriting link with target at fixup_pos.
794 Instr instr = instr_at(fixup_pos);
795 if (IsBranch(instr)) {
796 if (dist > kMaxBranchOffset) {
797 if (trampoline_pos == kInvalidSlotPos) {
798 trampoline_pos = get_trampoline_entry(fixup_pos);
799 CHECK(trampoline_pos != kInvalidSlotPos);
800 }
801 ASSERT((trampoline_pos - fixup_pos) <= kMaxBranchOffset);
802 target_at_put(fixup_pos, trampoline_pos);
803 fixup_pos = trampoline_pos;
804 dist = pos - fixup_pos;
805 }
806 target_at_put(fixup_pos, pos);
807 } else {
808 ASSERT(IsJ(instr) || IsLui(instr));
809 target_at_put(fixup_pos, pos);
810 }
811 }
812 L->bind_to(pos);
813
814 // Keep track of the last bound label so we don't eliminate any instructions
815 // before a bound label.
816 if (pos > last_bound_pos_)
817 last_bound_pos_ = pos;
818 }
819
820
bind(Label * L)821 void Assembler::bind(Label* L) {
822 ASSERT(!L->is_bound()); // Label can only be bound once.
823 bind_to(L, pc_offset());
824 }
825
826
next(Label * L)827 void Assembler::next(Label* L) {
828 ASSERT(L->is_linked());
829 int link = target_at(L->pos());
830 if (link == kEndOfChain) {
831 L->Unuse();
832 } else {
833 ASSERT(link >= 0);
834 L->link_to(link);
835 }
836 }
837
is_near(Label * L)838 bool Assembler::is_near(Label* L) {
839 if (L->is_bound()) {
840 return ((pc_offset() - L->pos()) < kMaxBranchOffset - 4 * kInstrSize);
841 }
842 return false;
843 }
844
845 // We have to use a temporary register for things that can be relocated even
846 // if they can be encoded in the MIPS's 16 bits of immediate-offset instruction
847 // space. There is no guarantee that the relocated location can be similarly
848 // encoded.
MustUseReg(RelocInfo::Mode rmode)849 bool Assembler::MustUseReg(RelocInfo::Mode rmode) {
850 return rmode != RelocInfo::NONE;
851 }
852
GenInstrRegister(Opcode opcode,Register rs,Register rt,Register rd,uint16_t sa,SecondaryField func)853 void Assembler::GenInstrRegister(Opcode opcode,
854 Register rs,
855 Register rt,
856 Register rd,
857 uint16_t sa,
858 SecondaryField func) {
859 ASSERT(rd.is_valid() && rs.is_valid() && rt.is_valid() && is_uint5(sa));
860 Instr instr = opcode | (rs.code() << kRsShift) | (rt.code() << kRtShift)
861 | (rd.code() << kRdShift) | (sa << kSaShift) | func;
862 emit(instr);
863 }
864
865
GenInstrRegister(Opcode opcode,Register rs,Register rt,uint16_t msb,uint16_t lsb,SecondaryField func)866 void Assembler::GenInstrRegister(Opcode opcode,
867 Register rs,
868 Register rt,
869 uint16_t msb,
870 uint16_t lsb,
871 SecondaryField func) {
872 ASSERT(rs.is_valid() && rt.is_valid() && is_uint5(msb) && is_uint5(lsb));
873 Instr instr = opcode | (rs.code() << kRsShift) | (rt.code() << kRtShift)
874 | (msb << kRdShift) | (lsb << kSaShift) | func;
875 emit(instr);
876 }
877
878
GenInstrRegister(Opcode opcode,SecondaryField fmt,FPURegister ft,FPURegister fs,FPURegister fd,SecondaryField func)879 void Assembler::GenInstrRegister(Opcode opcode,
880 SecondaryField fmt,
881 FPURegister ft,
882 FPURegister fs,
883 FPURegister fd,
884 SecondaryField func) {
885 ASSERT(fd.is_valid() && fs.is_valid() && ft.is_valid());
886 ASSERT(CpuFeatures::IsEnabled(FPU));
887 Instr instr = opcode | fmt | (ft.code() << kFtShift) | (fs.code() << kFsShift)
888 | (fd.code() << kFdShift) | func;
889 emit(instr);
890 }
891
892
GenInstrRegister(Opcode opcode,SecondaryField fmt,Register rt,FPURegister fs,FPURegister fd,SecondaryField func)893 void Assembler::GenInstrRegister(Opcode opcode,
894 SecondaryField fmt,
895 Register rt,
896 FPURegister fs,
897 FPURegister fd,
898 SecondaryField func) {
899 ASSERT(fd.is_valid() && fs.is_valid() && rt.is_valid());
900 ASSERT(CpuFeatures::IsEnabled(FPU));
901 Instr instr = opcode | fmt | (rt.code() << kRtShift)
902 | (fs.code() << kFsShift) | (fd.code() << kFdShift) | func;
903 emit(instr);
904 }
905
906
GenInstrRegister(Opcode opcode,SecondaryField fmt,Register rt,FPUControlRegister fs,SecondaryField func)907 void Assembler::GenInstrRegister(Opcode opcode,
908 SecondaryField fmt,
909 Register rt,
910 FPUControlRegister fs,
911 SecondaryField func) {
912 ASSERT(fs.is_valid() && rt.is_valid());
913 ASSERT(CpuFeatures::IsEnabled(FPU));
914 Instr instr =
915 opcode | fmt | (rt.code() << kRtShift) | (fs.code() << kFsShift) | func;
916 emit(instr);
917 }
918
919
920 // Instructions with immediate value.
921 // Registers are in the order of the instruction encoding, from left to right.
GenInstrImmediate(Opcode opcode,Register rs,Register rt,int32_t j)922 void Assembler::GenInstrImmediate(Opcode opcode,
923 Register rs,
924 Register rt,
925 int32_t j) {
926 ASSERT(rs.is_valid() && rt.is_valid() && (is_int16(j) || is_uint16(j)));
927 Instr instr = opcode | (rs.code() << kRsShift) | (rt.code() << kRtShift)
928 | (j & kImm16Mask);
929 emit(instr);
930 }
931
932
GenInstrImmediate(Opcode opcode,Register rs,SecondaryField SF,int32_t j)933 void Assembler::GenInstrImmediate(Opcode opcode,
934 Register rs,
935 SecondaryField SF,
936 int32_t j) {
937 ASSERT(rs.is_valid() && (is_int16(j) || is_uint16(j)));
938 Instr instr = opcode | (rs.code() << kRsShift) | SF | (j & kImm16Mask);
939 emit(instr);
940 }
941
942
GenInstrImmediate(Opcode opcode,Register rs,FPURegister ft,int32_t j)943 void Assembler::GenInstrImmediate(Opcode opcode,
944 Register rs,
945 FPURegister ft,
946 int32_t j) {
947 ASSERT(rs.is_valid() && ft.is_valid() && (is_int16(j) || is_uint16(j)));
948 ASSERT(CpuFeatures::IsEnabled(FPU));
949 Instr instr = opcode | (rs.code() << kRsShift) | (ft.code() << kFtShift)
950 | (j & kImm16Mask);
951 emit(instr);
952 }
953
954
GenInstrJump(Opcode opcode,uint32_t address)955 void Assembler::GenInstrJump(Opcode opcode,
956 uint32_t address) {
957 BlockTrampolinePoolScope block_trampoline_pool(this);
958 ASSERT(is_uint26(address));
959 Instr instr = opcode | address;
960 emit(instr);
961 BlockTrampolinePoolFor(1); // For associated delay slot.
962 }
963
964
965 // Returns the next free trampoline entry.
get_trampoline_entry(int32_t pos)966 int32_t Assembler::get_trampoline_entry(int32_t pos) {
967 int32_t trampoline_entry = kInvalidSlotPos;
968
969 if (!internal_trampoline_exception_) {
970 if (trampoline_.start() > pos) {
971 trampoline_entry = trampoline_.take_slot();
972 }
973
974 if (kInvalidSlotPos == trampoline_entry) {
975 internal_trampoline_exception_ = true;
976 }
977 }
978 return trampoline_entry;
979 }
980
981
jump_address(Label * L)982 uint32_t Assembler::jump_address(Label* L) {
983 int32_t target_pos;
984
985 if (L->is_bound()) {
986 target_pos = L->pos();
987 } else {
988 if (L->is_linked()) {
989 target_pos = L->pos(); // L's link.
990 L->link_to(pc_offset());
991 } else {
992 L->link_to(pc_offset());
993 return kEndOfJumpChain;
994 }
995 }
996
997 uint32_t imm = (uint32_t)buffer_ + target_pos;
998 ASSERT((imm & 3) == 0);
999
1000 return imm;
1001 }
1002
1003
branch_offset(Label * L,bool jump_elimination_allowed)1004 int32_t Assembler::branch_offset(Label* L, bool jump_elimination_allowed) {
1005 int32_t target_pos;
1006
1007 if (L->is_bound()) {
1008 target_pos = L->pos();
1009 } else {
1010 if (L->is_linked()) {
1011 target_pos = L->pos();
1012 L->link_to(pc_offset());
1013 } else {
1014 L->link_to(pc_offset());
1015 if (!trampoline_emitted_) {
1016 unbound_labels_count_++;
1017 next_buffer_check_ -= kTrampolineSlotsSize;
1018 }
1019 return kEndOfChain;
1020 }
1021 }
1022
1023 int32_t offset = target_pos - (pc_offset() + kBranchPCOffset);
1024 ASSERT((offset & 3) == 0);
1025 ASSERT(is_int16(offset >> 2));
1026
1027 return offset;
1028 }
1029
1030
label_at_put(Label * L,int at_offset)1031 void Assembler::label_at_put(Label* L, int at_offset) {
1032 int target_pos;
1033 if (L->is_bound()) {
1034 target_pos = L->pos();
1035 instr_at_put(at_offset, target_pos + (Code::kHeaderSize - kHeapObjectTag));
1036 } else {
1037 if (L->is_linked()) {
1038 target_pos = L->pos(); // L's link.
1039 int32_t imm18 = target_pos - at_offset;
1040 ASSERT((imm18 & 3) == 0);
1041 int32_t imm16 = imm18 >> 2;
1042 ASSERT(is_int16(imm16));
1043 instr_at_put(at_offset, (imm16 & kImm16Mask));
1044 } else {
1045 target_pos = kEndOfChain;
1046 instr_at_put(at_offset, 0);
1047 if (!trampoline_emitted_) {
1048 unbound_labels_count_++;
1049 next_buffer_check_ -= kTrampolineSlotsSize;
1050 }
1051 }
1052 L->link_to(at_offset);
1053 }
1054 }
1055
1056
1057 //------- Branch and jump instructions --------
1058
b(int16_t offset)1059 void Assembler::b(int16_t offset) {
1060 beq(zero_reg, zero_reg, offset);
1061 }
1062
1063
bal(int16_t offset)1064 void Assembler::bal(int16_t offset) {
1065 positions_recorder()->WriteRecordedPositions();
1066 bgezal(zero_reg, offset);
1067 }
1068
1069
beq(Register rs,Register rt,int16_t offset)1070 void Assembler::beq(Register rs, Register rt, int16_t offset) {
1071 BlockTrampolinePoolScope block_trampoline_pool(this);
1072 GenInstrImmediate(BEQ, rs, rt, offset);
1073 BlockTrampolinePoolFor(1); // For associated delay slot.
1074 }
1075
1076
bgez(Register rs,int16_t offset)1077 void Assembler::bgez(Register rs, int16_t offset) {
1078 BlockTrampolinePoolScope block_trampoline_pool(this);
1079 GenInstrImmediate(REGIMM, rs, BGEZ, offset);
1080 BlockTrampolinePoolFor(1); // For associated delay slot.
1081 }
1082
1083
bgezal(Register rs,int16_t offset)1084 void Assembler::bgezal(Register rs, int16_t offset) {
1085 BlockTrampolinePoolScope block_trampoline_pool(this);
1086 positions_recorder()->WriteRecordedPositions();
1087 GenInstrImmediate(REGIMM, rs, BGEZAL, offset);
1088 BlockTrampolinePoolFor(1); // For associated delay slot.
1089 }
1090
1091
bgtz(Register rs,int16_t offset)1092 void Assembler::bgtz(Register rs, int16_t offset) {
1093 BlockTrampolinePoolScope block_trampoline_pool(this);
1094 GenInstrImmediate(BGTZ, rs, zero_reg, offset);
1095 BlockTrampolinePoolFor(1); // For associated delay slot.
1096 }
1097
1098
blez(Register rs,int16_t offset)1099 void Assembler::blez(Register rs, int16_t offset) {
1100 BlockTrampolinePoolScope block_trampoline_pool(this);
1101 GenInstrImmediate(BLEZ, rs, zero_reg, offset);
1102 BlockTrampolinePoolFor(1); // For associated delay slot.
1103 }
1104
1105
bltz(Register rs,int16_t offset)1106 void Assembler::bltz(Register rs, int16_t offset) {
1107 BlockTrampolinePoolScope block_trampoline_pool(this);
1108 GenInstrImmediate(REGIMM, rs, BLTZ, offset);
1109 BlockTrampolinePoolFor(1); // For associated delay slot.
1110 }
1111
1112
bltzal(Register rs,int16_t offset)1113 void Assembler::bltzal(Register rs, int16_t offset) {
1114 BlockTrampolinePoolScope block_trampoline_pool(this);
1115 positions_recorder()->WriteRecordedPositions();
1116 GenInstrImmediate(REGIMM, rs, BLTZAL, offset);
1117 BlockTrampolinePoolFor(1); // For associated delay slot.
1118 }
1119
1120
bne(Register rs,Register rt,int16_t offset)1121 void Assembler::bne(Register rs, Register rt, int16_t offset) {
1122 BlockTrampolinePoolScope block_trampoline_pool(this);
1123 GenInstrImmediate(BNE, rs, rt, offset);
1124 BlockTrampolinePoolFor(1); // For associated delay slot.
1125 }
1126
1127
j(int32_t target)1128 void Assembler::j(int32_t target) {
1129 #if DEBUG
1130 // Get pc of delay slot.
1131 uint32_t ipc = reinterpret_cast<uint32_t>(pc_ + 1 * kInstrSize);
1132 bool in_range = ((uint32_t)(ipc^target) >> (kImm26Bits+kImmFieldShift)) == 0;
1133 ASSERT(in_range && ((target & 3) == 0));
1134 #endif
1135 GenInstrJump(J, target >> 2);
1136 }
1137
1138
jr(Register rs)1139 void Assembler::jr(Register rs) {
1140 BlockTrampolinePoolScope block_trampoline_pool(this);
1141 if (rs.is(ra)) {
1142 positions_recorder()->WriteRecordedPositions();
1143 }
1144 GenInstrRegister(SPECIAL, rs, zero_reg, zero_reg, 0, JR);
1145 BlockTrampolinePoolFor(1); // For associated delay slot.
1146 }
1147
1148
jal(int32_t target)1149 void Assembler::jal(int32_t target) {
1150 #ifdef DEBUG
1151 // Get pc of delay slot.
1152 uint32_t ipc = reinterpret_cast<uint32_t>(pc_ + 1 * kInstrSize);
1153 bool in_range = ((uint32_t)(ipc^target) >> (kImm26Bits+kImmFieldShift)) == 0;
1154 ASSERT(in_range && ((target & 3) == 0));
1155 #endif
1156 positions_recorder()->WriteRecordedPositions();
1157 GenInstrJump(JAL, target >> 2);
1158 }
1159
1160
jalr(Register rs,Register rd)1161 void Assembler::jalr(Register rs, Register rd) {
1162 BlockTrampolinePoolScope block_trampoline_pool(this);
1163 positions_recorder()->WriteRecordedPositions();
1164 GenInstrRegister(SPECIAL, rs, zero_reg, rd, 0, JALR);
1165 BlockTrampolinePoolFor(1); // For associated delay slot.
1166 }
1167
1168
j_or_jr(int32_t target,Register rs)1169 void Assembler::j_or_jr(int32_t target, Register rs) {
1170 // Get pc of delay slot.
1171 uint32_t ipc = reinterpret_cast<uint32_t>(pc_ + 1 * kInstrSize);
1172 bool in_range = ((uint32_t)(ipc^target) >> (kImm26Bits+kImmFieldShift)) == 0;
1173
1174 if (in_range) {
1175 j(target);
1176 } else {
1177 jr(t9);
1178 }
1179 }
1180
1181
jal_or_jalr(int32_t target,Register rs)1182 void Assembler::jal_or_jalr(int32_t target, Register rs) {
1183 // Get pc of delay slot.
1184 uint32_t ipc = reinterpret_cast<uint32_t>(pc_ + 1 * kInstrSize);
1185 bool in_range = ((uint32_t)(ipc^target) >> (kImm26Bits+kImmFieldShift)) == 0;
1186
1187 if (in_range) {
1188 jal(target);
1189 } else {
1190 jalr(t9);
1191 }
1192 }
1193
1194
1195 //-------Data-processing-instructions---------
1196
1197 // Arithmetic.
1198
addu(Register rd,Register rs,Register rt)1199 void Assembler::addu(Register rd, Register rs, Register rt) {
1200 GenInstrRegister(SPECIAL, rs, rt, rd, 0, ADDU);
1201 }
1202
1203
addiu(Register rd,Register rs,int32_t j)1204 void Assembler::addiu(Register rd, Register rs, int32_t j) {
1205 GenInstrImmediate(ADDIU, rs, rd, j);
1206 }
1207
1208
subu(Register rd,Register rs,Register rt)1209 void Assembler::subu(Register rd, Register rs, Register rt) {
1210 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SUBU);
1211 }
1212
1213
mul(Register rd,Register rs,Register rt)1214 void Assembler::mul(Register rd, Register rs, Register rt) {
1215 GenInstrRegister(SPECIAL2, rs, rt, rd, 0, MUL);
1216 }
1217
1218
mult(Register rs,Register rt)1219 void Assembler::mult(Register rs, Register rt) {
1220 GenInstrRegister(SPECIAL, rs, rt, zero_reg, 0, MULT);
1221 }
1222
1223
multu(Register rs,Register rt)1224 void Assembler::multu(Register rs, Register rt) {
1225 GenInstrRegister(SPECIAL, rs, rt, zero_reg, 0, MULTU);
1226 }
1227
1228
div(Register rs,Register rt)1229 void Assembler::div(Register rs, Register rt) {
1230 GenInstrRegister(SPECIAL, rs, rt, zero_reg, 0, DIV);
1231 }
1232
1233
divu(Register rs,Register rt)1234 void Assembler::divu(Register rs, Register rt) {
1235 GenInstrRegister(SPECIAL, rs, rt, zero_reg, 0, DIVU);
1236 }
1237
1238
1239 // Logical.
1240
and_(Register rd,Register rs,Register rt)1241 void Assembler::and_(Register rd, Register rs, Register rt) {
1242 GenInstrRegister(SPECIAL, rs, rt, rd, 0, AND);
1243 }
1244
1245
andi(Register rt,Register rs,int32_t j)1246 void Assembler::andi(Register rt, Register rs, int32_t j) {
1247 ASSERT(is_uint16(j));
1248 GenInstrImmediate(ANDI, rs, rt, j);
1249 }
1250
1251
or_(Register rd,Register rs,Register rt)1252 void Assembler::or_(Register rd, Register rs, Register rt) {
1253 GenInstrRegister(SPECIAL, rs, rt, rd, 0, OR);
1254 }
1255
1256
ori(Register rt,Register rs,int32_t j)1257 void Assembler::ori(Register rt, Register rs, int32_t j) {
1258 ASSERT(is_uint16(j));
1259 GenInstrImmediate(ORI, rs, rt, j);
1260 }
1261
1262
xor_(Register rd,Register rs,Register rt)1263 void Assembler::xor_(Register rd, Register rs, Register rt) {
1264 GenInstrRegister(SPECIAL, rs, rt, rd, 0, XOR);
1265 }
1266
1267
xori(Register rt,Register rs,int32_t j)1268 void Assembler::xori(Register rt, Register rs, int32_t j) {
1269 ASSERT(is_uint16(j));
1270 GenInstrImmediate(XORI, rs, rt, j);
1271 }
1272
1273
nor(Register rd,Register rs,Register rt)1274 void Assembler::nor(Register rd, Register rs, Register rt) {
1275 GenInstrRegister(SPECIAL, rs, rt, rd, 0, NOR);
1276 }
1277
1278
1279 // Shifts.
sll(Register rd,Register rt,uint16_t sa,bool coming_from_nop)1280 void Assembler::sll(Register rd,
1281 Register rt,
1282 uint16_t sa,
1283 bool coming_from_nop) {
1284 // Don't allow nop instructions in the form sll zero_reg, zero_reg to be
1285 // generated using the sll instruction. They must be generated using
1286 // nop(int/NopMarkerTypes) or MarkCode(int/NopMarkerTypes) pseudo
1287 // instructions.
1288 ASSERT(coming_from_nop || !(rd.is(zero_reg) && rt.is(zero_reg)));
1289 GenInstrRegister(SPECIAL, zero_reg, rt, rd, sa, SLL);
1290 }
1291
1292
sllv(Register rd,Register rt,Register rs)1293 void Assembler::sllv(Register rd, Register rt, Register rs) {
1294 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SLLV);
1295 }
1296
1297
srl(Register rd,Register rt,uint16_t sa)1298 void Assembler::srl(Register rd, Register rt, uint16_t sa) {
1299 GenInstrRegister(SPECIAL, zero_reg, rt, rd, sa, SRL);
1300 }
1301
1302
srlv(Register rd,Register rt,Register rs)1303 void Assembler::srlv(Register rd, Register rt, Register rs) {
1304 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SRLV);
1305 }
1306
1307
sra(Register rd,Register rt,uint16_t sa)1308 void Assembler::sra(Register rd, Register rt, uint16_t sa) {
1309 GenInstrRegister(SPECIAL, zero_reg, rt, rd, sa, SRA);
1310 }
1311
1312
srav(Register rd,Register rt,Register rs)1313 void Assembler::srav(Register rd, Register rt, Register rs) {
1314 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SRAV);
1315 }
1316
1317
rotr(Register rd,Register rt,uint16_t sa)1318 void Assembler::rotr(Register rd, Register rt, uint16_t sa) {
1319 // Should be called via MacroAssembler::Ror.
1320 ASSERT(rd.is_valid() && rt.is_valid() && is_uint5(sa));
1321 ASSERT(kArchVariant == kMips32r2);
1322 Instr instr = SPECIAL | (1 << kRsShift) | (rt.code() << kRtShift)
1323 | (rd.code() << kRdShift) | (sa << kSaShift) | SRL;
1324 emit(instr);
1325 }
1326
1327
rotrv(Register rd,Register rt,Register rs)1328 void Assembler::rotrv(Register rd, Register rt, Register rs) {
1329 // Should be called via MacroAssembler::Ror.
1330 ASSERT(rd.is_valid() && rt.is_valid() && rs.is_valid() );
1331 ASSERT(kArchVariant == kMips32r2);
1332 Instr instr = SPECIAL | (rs.code() << kRsShift) | (rt.code() << kRtShift)
1333 | (rd.code() << kRdShift) | (1 << kSaShift) | SRLV;
1334 emit(instr);
1335 }
1336
1337
1338 //------------Memory-instructions-------------
1339
1340 // Helper for base-reg + offset, when offset is larger than int16.
LoadRegPlusOffsetToAt(const MemOperand & src)1341 void Assembler::LoadRegPlusOffsetToAt(const MemOperand& src) {
1342 ASSERT(!src.rm().is(at));
1343 lui(at, src.offset_ >> kLuiShift);
1344 ori(at, at, src.offset_ & kImm16Mask); // Load 32-bit offset.
1345 addu(at, at, src.rm()); // Add base register.
1346 }
1347
1348
lb(Register rd,const MemOperand & rs)1349 void Assembler::lb(Register rd, const MemOperand& rs) {
1350 if (is_int16(rs.offset_)) {
1351 GenInstrImmediate(LB, rs.rm(), rd, rs.offset_);
1352 } else { // Offset > 16 bits, use multiple instructions to load.
1353 LoadRegPlusOffsetToAt(rs);
1354 GenInstrImmediate(LB, at, rd, 0); // Equiv to lb(rd, MemOperand(at, 0));
1355 }
1356 }
1357
1358
lbu(Register rd,const MemOperand & rs)1359 void Assembler::lbu(Register rd, const MemOperand& rs) {
1360 if (is_int16(rs.offset_)) {
1361 GenInstrImmediate(LBU, rs.rm(), rd, rs.offset_);
1362 } else { // Offset > 16 bits, use multiple instructions to load.
1363 LoadRegPlusOffsetToAt(rs);
1364 GenInstrImmediate(LBU, at, rd, 0); // Equiv to lbu(rd, MemOperand(at, 0));
1365 }
1366 }
1367
1368
lh(Register rd,const MemOperand & rs)1369 void Assembler::lh(Register rd, const MemOperand& rs) {
1370 if (is_int16(rs.offset_)) {
1371 GenInstrImmediate(LH, rs.rm(), rd, rs.offset_);
1372 } else { // Offset > 16 bits, use multiple instructions to load.
1373 LoadRegPlusOffsetToAt(rs);
1374 GenInstrImmediate(LH, at, rd, 0); // Equiv to lh(rd, MemOperand(at, 0));
1375 }
1376 }
1377
1378
lhu(Register rd,const MemOperand & rs)1379 void Assembler::lhu(Register rd, const MemOperand& rs) {
1380 if (is_int16(rs.offset_)) {
1381 GenInstrImmediate(LHU, rs.rm(), rd, rs.offset_);
1382 } else { // Offset > 16 bits, use multiple instructions to load.
1383 LoadRegPlusOffsetToAt(rs);
1384 GenInstrImmediate(LHU, at, rd, 0); // Equiv to lhu(rd, MemOperand(at, 0));
1385 }
1386 }
1387
1388
lw(Register rd,const MemOperand & rs)1389 void Assembler::lw(Register rd, const MemOperand& rs) {
1390 if (is_int16(rs.offset_)) {
1391 GenInstrImmediate(LW, rs.rm(), rd, rs.offset_);
1392 } else { // Offset > 16 bits, use multiple instructions to load.
1393 LoadRegPlusOffsetToAt(rs);
1394 GenInstrImmediate(LW, at, rd, 0); // Equiv to lw(rd, MemOperand(at, 0));
1395 }
1396 }
1397
1398
lwl(Register rd,const MemOperand & rs)1399 void Assembler::lwl(Register rd, const MemOperand& rs) {
1400 GenInstrImmediate(LWL, rs.rm(), rd, rs.offset_);
1401 }
1402
1403
lwr(Register rd,const MemOperand & rs)1404 void Assembler::lwr(Register rd, const MemOperand& rs) {
1405 GenInstrImmediate(LWR, rs.rm(), rd, rs.offset_);
1406 }
1407
1408
sb(Register rd,const MemOperand & rs)1409 void Assembler::sb(Register rd, const MemOperand& rs) {
1410 if (is_int16(rs.offset_)) {
1411 GenInstrImmediate(SB, rs.rm(), rd, rs.offset_);
1412 } else { // Offset > 16 bits, use multiple instructions to store.
1413 LoadRegPlusOffsetToAt(rs);
1414 GenInstrImmediate(SB, at, rd, 0); // Equiv to sb(rd, MemOperand(at, 0));
1415 }
1416 }
1417
1418
sh(Register rd,const MemOperand & rs)1419 void Assembler::sh(Register rd, const MemOperand& rs) {
1420 if (is_int16(rs.offset_)) {
1421 GenInstrImmediate(SH, rs.rm(), rd, rs.offset_);
1422 } else { // Offset > 16 bits, use multiple instructions to store.
1423 LoadRegPlusOffsetToAt(rs);
1424 GenInstrImmediate(SH, at, rd, 0); // Equiv to sh(rd, MemOperand(at, 0));
1425 }
1426 }
1427
1428
sw(Register rd,const MemOperand & rs)1429 void Assembler::sw(Register rd, const MemOperand& rs) {
1430 if (is_int16(rs.offset_)) {
1431 GenInstrImmediate(SW, rs.rm(), rd, rs.offset_);
1432 } else { // Offset > 16 bits, use multiple instructions to store.
1433 LoadRegPlusOffsetToAt(rs);
1434 GenInstrImmediate(SW, at, rd, 0); // Equiv to sw(rd, MemOperand(at, 0));
1435 }
1436 }
1437
1438
swl(Register rd,const MemOperand & rs)1439 void Assembler::swl(Register rd, const MemOperand& rs) {
1440 GenInstrImmediate(SWL, rs.rm(), rd, rs.offset_);
1441 }
1442
1443
swr(Register rd,const MemOperand & rs)1444 void Assembler::swr(Register rd, const MemOperand& rs) {
1445 GenInstrImmediate(SWR, rs.rm(), rd, rs.offset_);
1446 }
1447
1448
lui(Register rd,int32_t j)1449 void Assembler::lui(Register rd, int32_t j) {
1450 ASSERT(is_uint16(j));
1451 GenInstrImmediate(LUI, zero_reg, rd, j);
1452 }
1453
1454
1455 //-------------Misc-instructions--------------
1456
1457 // Break / Trap instructions.
break_(uint32_t code,bool break_as_stop)1458 void Assembler::break_(uint32_t code, bool break_as_stop) {
1459 ASSERT((code & ~0xfffff) == 0);
1460 // We need to invalidate breaks that could be stops as well because the
1461 // simulator expects a char pointer after the stop instruction.
1462 // See constants-mips.h for explanation.
1463 ASSERT((break_as_stop &&
1464 code <= kMaxStopCode &&
1465 code > kMaxWatchpointCode) ||
1466 (!break_as_stop &&
1467 (code > kMaxStopCode ||
1468 code <= kMaxWatchpointCode)));
1469 Instr break_instr = SPECIAL | BREAK | (code << 6);
1470 emit(break_instr);
1471 }
1472
1473
stop(const char * msg,uint32_t code)1474 void Assembler::stop(const char* msg, uint32_t code) {
1475 ASSERT(code > kMaxWatchpointCode);
1476 ASSERT(code <= kMaxStopCode);
1477 #if defined(V8_HOST_ARCH_MIPS)
1478 break_(0x54321);
1479 #else // V8_HOST_ARCH_MIPS
1480 BlockTrampolinePoolFor(2);
1481 // The Simulator will handle the stop instruction and get the message address.
1482 // On MIPS stop() is just a special kind of break_().
1483 break_(code, true);
1484 emit(reinterpret_cast<Instr>(msg));
1485 #endif
1486 }
1487
1488
tge(Register rs,Register rt,uint16_t code)1489 void Assembler::tge(Register rs, Register rt, uint16_t code) {
1490 ASSERT(is_uint10(code));
1491 Instr instr = SPECIAL | TGE | rs.code() << kRsShift
1492 | rt.code() << kRtShift | code << 6;
1493 emit(instr);
1494 }
1495
1496
tgeu(Register rs,Register rt,uint16_t code)1497 void Assembler::tgeu(Register rs, Register rt, uint16_t code) {
1498 ASSERT(is_uint10(code));
1499 Instr instr = SPECIAL | TGEU | rs.code() << kRsShift
1500 | rt.code() << kRtShift | code << 6;
1501 emit(instr);
1502 }
1503
1504
tlt(Register rs,Register rt,uint16_t code)1505 void Assembler::tlt(Register rs, Register rt, uint16_t code) {
1506 ASSERT(is_uint10(code));
1507 Instr instr =
1508 SPECIAL | TLT | rs.code() << kRsShift | rt.code() << kRtShift | code << 6;
1509 emit(instr);
1510 }
1511
1512
tltu(Register rs,Register rt,uint16_t code)1513 void Assembler::tltu(Register rs, Register rt, uint16_t code) {
1514 ASSERT(is_uint10(code));
1515 Instr instr =
1516 SPECIAL | TLTU | rs.code() << kRsShift
1517 | rt.code() << kRtShift | code << 6;
1518 emit(instr);
1519 }
1520
1521
teq(Register rs,Register rt,uint16_t code)1522 void Assembler::teq(Register rs, Register rt, uint16_t code) {
1523 ASSERT(is_uint10(code));
1524 Instr instr =
1525 SPECIAL | TEQ | rs.code() << kRsShift | rt.code() << kRtShift | code << 6;
1526 emit(instr);
1527 }
1528
1529
tne(Register rs,Register rt,uint16_t code)1530 void Assembler::tne(Register rs, Register rt, uint16_t code) {
1531 ASSERT(is_uint10(code));
1532 Instr instr =
1533 SPECIAL | TNE | rs.code() << kRsShift | rt.code() << kRtShift | code << 6;
1534 emit(instr);
1535 }
1536
1537
1538 // Move from HI/LO register.
1539
mfhi(Register rd)1540 void Assembler::mfhi(Register rd) {
1541 GenInstrRegister(SPECIAL, zero_reg, zero_reg, rd, 0, MFHI);
1542 }
1543
1544
mflo(Register rd)1545 void Assembler::mflo(Register rd) {
1546 GenInstrRegister(SPECIAL, zero_reg, zero_reg, rd, 0, MFLO);
1547 }
1548
1549
1550 // Set on less than instructions.
slt(Register rd,Register rs,Register rt)1551 void Assembler::slt(Register rd, Register rs, Register rt) {
1552 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SLT);
1553 }
1554
1555
sltu(Register rd,Register rs,Register rt)1556 void Assembler::sltu(Register rd, Register rs, Register rt) {
1557 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SLTU);
1558 }
1559
1560
slti(Register rt,Register rs,int32_t j)1561 void Assembler::slti(Register rt, Register rs, int32_t j) {
1562 GenInstrImmediate(SLTI, rs, rt, j);
1563 }
1564
1565
sltiu(Register rt,Register rs,int32_t j)1566 void Assembler::sltiu(Register rt, Register rs, int32_t j) {
1567 GenInstrImmediate(SLTIU, rs, rt, j);
1568 }
1569
1570
1571 // Conditional move.
movz(Register rd,Register rs,Register rt)1572 void Assembler::movz(Register rd, Register rs, Register rt) {
1573 GenInstrRegister(SPECIAL, rs, rt, rd, 0, MOVZ);
1574 }
1575
1576
movn(Register rd,Register rs,Register rt)1577 void Assembler::movn(Register rd, Register rs, Register rt) {
1578 GenInstrRegister(SPECIAL, rs, rt, rd, 0, MOVN);
1579 }
1580
1581
movt(Register rd,Register rs,uint16_t cc)1582 void Assembler::movt(Register rd, Register rs, uint16_t cc) {
1583 Register rt;
1584 rt.code_ = (cc & 0x0007) << 2 | 1;
1585 GenInstrRegister(SPECIAL, rs, rt, rd, 0, MOVCI);
1586 }
1587
1588
movf(Register rd,Register rs,uint16_t cc)1589 void Assembler::movf(Register rd, Register rs, uint16_t cc) {
1590 Register rt;
1591 rt.code_ = (cc & 0x0007) << 2 | 0;
1592 GenInstrRegister(SPECIAL, rs, rt, rd, 0, MOVCI);
1593 }
1594
1595
1596 // Bit twiddling.
clz(Register rd,Register rs)1597 void Assembler::clz(Register rd, Register rs) {
1598 // Clz instr requires same GPR number in 'rd' and 'rt' fields.
1599 GenInstrRegister(SPECIAL2, rs, rd, rd, 0, CLZ);
1600 }
1601
1602
ins_(Register rt,Register rs,uint16_t pos,uint16_t size)1603 void Assembler::ins_(Register rt, Register rs, uint16_t pos, uint16_t size) {
1604 // Should be called via MacroAssembler::Ins.
1605 // Ins instr has 'rt' field as dest, and two uint5: msb, lsb.
1606 ASSERT(kArchVariant == kMips32r2);
1607 GenInstrRegister(SPECIAL3, rs, rt, pos + size - 1, pos, INS);
1608 }
1609
1610
ext_(Register rt,Register rs,uint16_t pos,uint16_t size)1611 void Assembler::ext_(Register rt, Register rs, uint16_t pos, uint16_t size) {
1612 // Should be called via MacroAssembler::Ext.
1613 // Ext instr has 'rt' field as dest, and two uint5: msb, lsb.
1614 ASSERT(kArchVariant == kMips32r2);
1615 GenInstrRegister(SPECIAL3, rs, rt, size - 1, pos, EXT);
1616 }
1617
1618
1619 //--------Coprocessor-instructions----------------
1620
1621 // Load, store, move.
lwc1(FPURegister fd,const MemOperand & src)1622 void Assembler::lwc1(FPURegister fd, const MemOperand& src) {
1623 GenInstrImmediate(LWC1, src.rm(), fd, src.offset_);
1624 }
1625
1626
ldc1(FPURegister fd,const MemOperand & src)1627 void Assembler::ldc1(FPURegister fd, const MemOperand& src) {
1628 // Workaround for non-8-byte alignment of HeapNumber, convert 64-bit
1629 // load to two 32-bit loads.
1630 GenInstrImmediate(LWC1, src.rm(), fd, src.offset_);
1631 FPURegister nextfpreg;
1632 nextfpreg.setcode(fd.code() + 1);
1633 GenInstrImmediate(LWC1, src.rm(), nextfpreg, src.offset_ + 4);
1634 }
1635
1636
swc1(FPURegister fd,const MemOperand & src)1637 void Assembler::swc1(FPURegister fd, const MemOperand& src) {
1638 GenInstrImmediate(SWC1, src.rm(), fd, src.offset_);
1639 }
1640
1641
sdc1(FPURegister fd,const MemOperand & src)1642 void Assembler::sdc1(FPURegister fd, const MemOperand& src) {
1643 // Workaround for non-8-byte alignment of HeapNumber, convert 64-bit
1644 // store to two 32-bit stores.
1645 GenInstrImmediate(SWC1, src.rm(), fd, src.offset_);
1646 FPURegister nextfpreg;
1647 nextfpreg.setcode(fd.code() + 1);
1648 GenInstrImmediate(SWC1, src.rm(), nextfpreg, src.offset_ + 4);
1649 }
1650
1651
mtc1(Register rt,FPURegister fs)1652 void Assembler::mtc1(Register rt, FPURegister fs) {
1653 GenInstrRegister(COP1, MTC1, rt, fs, f0);
1654 }
1655
1656
mfc1(Register rt,FPURegister fs)1657 void Assembler::mfc1(Register rt, FPURegister fs) {
1658 GenInstrRegister(COP1, MFC1, rt, fs, f0);
1659 }
1660
1661
ctc1(Register rt,FPUControlRegister fs)1662 void Assembler::ctc1(Register rt, FPUControlRegister fs) {
1663 GenInstrRegister(COP1, CTC1, rt, fs);
1664 }
1665
1666
cfc1(Register rt,FPUControlRegister fs)1667 void Assembler::cfc1(Register rt, FPUControlRegister fs) {
1668 GenInstrRegister(COP1, CFC1, rt, fs);
1669 }
1670
DoubleAsTwoUInt32(double d,uint32_t * lo,uint32_t * hi)1671 void Assembler::DoubleAsTwoUInt32(double d, uint32_t* lo, uint32_t* hi) {
1672 uint64_t i;
1673 memcpy(&i, &d, 8);
1674
1675 *lo = i & 0xffffffff;
1676 *hi = i >> 32;
1677 }
1678
1679 // Arithmetic.
1680
add_d(FPURegister fd,FPURegister fs,FPURegister ft)1681 void Assembler::add_d(FPURegister fd, FPURegister fs, FPURegister ft) {
1682 GenInstrRegister(COP1, D, ft, fs, fd, ADD_D);
1683 }
1684
1685
sub_d(FPURegister fd,FPURegister fs,FPURegister ft)1686 void Assembler::sub_d(FPURegister fd, FPURegister fs, FPURegister ft) {
1687 GenInstrRegister(COP1, D, ft, fs, fd, SUB_D);
1688 }
1689
1690
mul_d(FPURegister fd,FPURegister fs,FPURegister ft)1691 void Assembler::mul_d(FPURegister fd, FPURegister fs, FPURegister ft) {
1692 GenInstrRegister(COP1, D, ft, fs, fd, MUL_D);
1693 }
1694
1695
div_d(FPURegister fd,FPURegister fs,FPURegister ft)1696 void Assembler::div_d(FPURegister fd, FPURegister fs, FPURegister ft) {
1697 GenInstrRegister(COP1, D, ft, fs, fd, DIV_D);
1698 }
1699
1700
abs_d(FPURegister fd,FPURegister fs)1701 void Assembler::abs_d(FPURegister fd, FPURegister fs) {
1702 GenInstrRegister(COP1, D, f0, fs, fd, ABS_D);
1703 }
1704
1705
mov_d(FPURegister fd,FPURegister fs)1706 void Assembler::mov_d(FPURegister fd, FPURegister fs) {
1707 GenInstrRegister(COP1, D, f0, fs, fd, MOV_D);
1708 }
1709
1710
neg_d(FPURegister fd,FPURegister fs)1711 void Assembler::neg_d(FPURegister fd, FPURegister fs) {
1712 GenInstrRegister(COP1, D, f0, fs, fd, NEG_D);
1713 }
1714
1715
sqrt_d(FPURegister fd,FPURegister fs)1716 void Assembler::sqrt_d(FPURegister fd, FPURegister fs) {
1717 GenInstrRegister(COP1, D, f0, fs, fd, SQRT_D);
1718 }
1719
1720
1721 // Conversions.
1722
cvt_w_s(FPURegister fd,FPURegister fs)1723 void Assembler::cvt_w_s(FPURegister fd, FPURegister fs) {
1724 GenInstrRegister(COP1, S, f0, fs, fd, CVT_W_S);
1725 }
1726
1727
cvt_w_d(FPURegister fd,FPURegister fs)1728 void Assembler::cvt_w_d(FPURegister fd, FPURegister fs) {
1729 GenInstrRegister(COP1, D, f0, fs, fd, CVT_W_D);
1730 }
1731
1732
trunc_w_s(FPURegister fd,FPURegister fs)1733 void Assembler::trunc_w_s(FPURegister fd, FPURegister fs) {
1734 GenInstrRegister(COP1, S, f0, fs, fd, TRUNC_W_S);
1735 }
1736
1737
trunc_w_d(FPURegister fd,FPURegister fs)1738 void Assembler::trunc_w_d(FPURegister fd, FPURegister fs) {
1739 GenInstrRegister(COP1, D, f0, fs, fd, TRUNC_W_D);
1740 }
1741
1742
round_w_s(FPURegister fd,FPURegister fs)1743 void Assembler::round_w_s(FPURegister fd, FPURegister fs) {
1744 GenInstrRegister(COP1, S, f0, fs, fd, ROUND_W_S);
1745 }
1746
1747
round_w_d(FPURegister fd,FPURegister fs)1748 void Assembler::round_w_d(FPURegister fd, FPURegister fs) {
1749 GenInstrRegister(COP1, D, f0, fs, fd, ROUND_W_D);
1750 }
1751
1752
floor_w_s(FPURegister fd,FPURegister fs)1753 void Assembler::floor_w_s(FPURegister fd, FPURegister fs) {
1754 GenInstrRegister(COP1, S, f0, fs, fd, FLOOR_W_S);
1755 }
1756
1757
floor_w_d(FPURegister fd,FPURegister fs)1758 void Assembler::floor_w_d(FPURegister fd, FPURegister fs) {
1759 GenInstrRegister(COP1, D, f0, fs, fd, FLOOR_W_D);
1760 }
1761
1762
ceil_w_s(FPURegister fd,FPURegister fs)1763 void Assembler::ceil_w_s(FPURegister fd, FPURegister fs) {
1764 GenInstrRegister(COP1, S, f0, fs, fd, CEIL_W_S);
1765 }
1766
1767
ceil_w_d(FPURegister fd,FPURegister fs)1768 void Assembler::ceil_w_d(FPURegister fd, FPURegister fs) {
1769 GenInstrRegister(COP1, D, f0, fs, fd, CEIL_W_D);
1770 }
1771
1772
cvt_l_s(FPURegister fd,FPURegister fs)1773 void Assembler::cvt_l_s(FPURegister fd, FPURegister fs) {
1774 ASSERT(kArchVariant == kMips32r2);
1775 GenInstrRegister(COP1, S, f0, fs, fd, CVT_L_S);
1776 }
1777
1778
cvt_l_d(FPURegister fd,FPURegister fs)1779 void Assembler::cvt_l_d(FPURegister fd, FPURegister fs) {
1780 ASSERT(kArchVariant == kMips32r2);
1781 GenInstrRegister(COP1, D, f0, fs, fd, CVT_L_D);
1782 }
1783
1784
trunc_l_s(FPURegister fd,FPURegister fs)1785 void Assembler::trunc_l_s(FPURegister fd, FPURegister fs) {
1786 ASSERT(kArchVariant == kMips32r2);
1787 GenInstrRegister(COP1, S, f0, fs, fd, TRUNC_L_S);
1788 }
1789
1790
trunc_l_d(FPURegister fd,FPURegister fs)1791 void Assembler::trunc_l_d(FPURegister fd, FPURegister fs) {
1792 ASSERT(kArchVariant == kMips32r2);
1793 GenInstrRegister(COP1, D, f0, fs, fd, TRUNC_L_D);
1794 }
1795
1796
round_l_s(FPURegister fd,FPURegister fs)1797 void Assembler::round_l_s(FPURegister fd, FPURegister fs) {
1798 GenInstrRegister(COP1, S, f0, fs, fd, ROUND_L_S);
1799 }
1800
1801
round_l_d(FPURegister fd,FPURegister fs)1802 void Assembler::round_l_d(FPURegister fd, FPURegister fs) {
1803 GenInstrRegister(COP1, D, f0, fs, fd, ROUND_L_D);
1804 }
1805
1806
floor_l_s(FPURegister fd,FPURegister fs)1807 void Assembler::floor_l_s(FPURegister fd, FPURegister fs) {
1808 GenInstrRegister(COP1, S, f0, fs, fd, FLOOR_L_S);
1809 }
1810
1811
floor_l_d(FPURegister fd,FPURegister fs)1812 void Assembler::floor_l_d(FPURegister fd, FPURegister fs) {
1813 GenInstrRegister(COP1, D, f0, fs, fd, FLOOR_L_D);
1814 }
1815
1816
ceil_l_s(FPURegister fd,FPURegister fs)1817 void Assembler::ceil_l_s(FPURegister fd, FPURegister fs) {
1818 GenInstrRegister(COP1, S, f0, fs, fd, CEIL_L_S);
1819 }
1820
1821
ceil_l_d(FPURegister fd,FPURegister fs)1822 void Assembler::ceil_l_d(FPURegister fd, FPURegister fs) {
1823 GenInstrRegister(COP1, D, f0, fs, fd, CEIL_L_D);
1824 }
1825
1826
cvt_s_w(FPURegister fd,FPURegister fs)1827 void Assembler::cvt_s_w(FPURegister fd, FPURegister fs) {
1828 GenInstrRegister(COP1, W, f0, fs, fd, CVT_S_W);
1829 }
1830
1831
cvt_s_l(FPURegister fd,FPURegister fs)1832 void Assembler::cvt_s_l(FPURegister fd, FPURegister fs) {
1833 ASSERT(kArchVariant == kMips32r2);
1834 GenInstrRegister(COP1, L, f0, fs, fd, CVT_S_L);
1835 }
1836
1837
cvt_s_d(FPURegister fd,FPURegister fs)1838 void Assembler::cvt_s_d(FPURegister fd, FPURegister fs) {
1839 GenInstrRegister(COP1, D, f0, fs, fd, CVT_S_D);
1840 }
1841
1842
cvt_d_w(FPURegister fd,FPURegister fs)1843 void Assembler::cvt_d_w(FPURegister fd, FPURegister fs) {
1844 GenInstrRegister(COP1, W, f0, fs, fd, CVT_D_W);
1845 }
1846
1847
cvt_d_l(FPURegister fd,FPURegister fs)1848 void Assembler::cvt_d_l(FPURegister fd, FPURegister fs) {
1849 ASSERT(kArchVariant == kMips32r2);
1850 GenInstrRegister(COP1, L, f0, fs, fd, CVT_D_L);
1851 }
1852
1853
cvt_d_s(FPURegister fd,FPURegister fs)1854 void Assembler::cvt_d_s(FPURegister fd, FPURegister fs) {
1855 GenInstrRegister(COP1, S, f0, fs, fd, CVT_D_S);
1856 }
1857
1858
1859 // Conditions.
c(FPUCondition cond,SecondaryField fmt,FPURegister fs,FPURegister ft,uint16_t cc)1860 void Assembler::c(FPUCondition cond, SecondaryField fmt,
1861 FPURegister fs, FPURegister ft, uint16_t cc) {
1862 ASSERT(CpuFeatures::IsEnabled(FPU));
1863 ASSERT(is_uint3(cc));
1864 ASSERT((fmt & ~(31 << kRsShift)) == 0);
1865 Instr instr = COP1 | fmt | ft.code() << 16 | fs.code() << kFsShift
1866 | cc << 8 | 3 << 4 | cond;
1867 emit(instr);
1868 }
1869
1870
fcmp(FPURegister src1,const double src2,FPUCondition cond)1871 void Assembler::fcmp(FPURegister src1, const double src2,
1872 FPUCondition cond) {
1873 ASSERT(CpuFeatures::IsEnabled(FPU));
1874 ASSERT(src2 == 0.0);
1875 mtc1(zero_reg, f14);
1876 cvt_d_w(f14, f14);
1877 c(cond, D, src1, f14, 0);
1878 }
1879
1880
bc1f(int16_t offset,uint16_t cc)1881 void Assembler::bc1f(int16_t offset, uint16_t cc) {
1882 ASSERT(CpuFeatures::IsEnabled(FPU));
1883 ASSERT(is_uint3(cc));
1884 Instr instr = COP1 | BC1 | cc << 18 | 0 << 16 | (offset & kImm16Mask);
1885 emit(instr);
1886 }
1887
1888
bc1t(int16_t offset,uint16_t cc)1889 void Assembler::bc1t(int16_t offset, uint16_t cc) {
1890 ASSERT(CpuFeatures::IsEnabled(FPU));
1891 ASSERT(is_uint3(cc));
1892 Instr instr = COP1 | BC1 | cc << 18 | 1 << 16 | (offset & kImm16Mask);
1893 emit(instr);
1894 }
1895
1896
1897 // Debugging.
RecordJSReturn()1898 void Assembler::RecordJSReturn() {
1899 positions_recorder()->WriteRecordedPositions();
1900 CheckBuffer();
1901 RecordRelocInfo(RelocInfo::JS_RETURN);
1902 }
1903
1904
RecordDebugBreakSlot()1905 void Assembler::RecordDebugBreakSlot() {
1906 positions_recorder()->WriteRecordedPositions();
1907 CheckBuffer();
1908 RecordRelocInfo(RelocInfo::DEBUG_BREAK_SLOT);
1909 }
1910
1911
RecordComment(const char * msg)1912 void Assembler::RecordComment(const char* msg) {
1913 if (FLAG_code_comments) {
1914 CheckBuffer();
1915 RecordRelocInfo(RelocInfo::COMMENT, reinterpret_cast<intptr_t>(msg));
1916 }
1917 }
1918
1919
RelocateInternalReference(byte * pc,intptr_t pc_delta)1920 int Assembler::RelocateInternalReference(byte* pc, intptr_t pc_delta) {
1921 Instr instr = instr_at(pc);
1922 ASSERT(IsJ(instr) || IsLui(instr));
1923 if (IsLui(instr)) {
1924 Instr instr_lui = instr_at(pc + 0 * Assembler::kInstrSize);
1925 Instr instr_ori = instr_at(pc + 1 * Assembler::kInstrSize);
1926 ASSERT(IsOri(instr_ori));
1927 int32_t imm = (instr_lui & static_cast<int32_t>(kImm16Mask)) << kLuiShift;
1928 imm |= (instr_ori & static_cast<int32_t>(kImm16Mask));
1929 if (imm == kEndOfJumpChain) {
1930 return 0; // Number of instructions patched.
1931 }
1932 imm += pc_delta;
1933 ASSERT((imm & 3) == 0);
1934
1935 instr_lui &= ~kImm16Mask;
1936 instr_ori &= ~kImm16Mask;
1937
1938 instr_at_put(pc + 0 * Assembler::kInstrSize,
1939 instr_lui | ((imm >> kLuiShift) & kImm16Mask));
1940 instr_at_put(pc + 1 * Assembler::kInstrSize,
1941 instr_ori | (imm & kImm16Mask));
1942 return 2; // Number of instructions patched.
1943 } else {
1944 uint32_t imm28 = (instr & static_cast<int32_t>(kImm26Mask)) << 2;
1945 if ((int32_t)imm28 == kEndOfJumpChain) {
1946 return 0; // Number of instructions patched.
1947 }
1948 imm28 += pc_delta;
1949 imm28 &= kImm28Mask;
1950 ASSERT((imm28 & 3) == 0);
1951
1952 instr &= ~kImm26Mask;
1953 uint32_t imm26 = imm28 >> 2;
1954 ASSERT(is_uint26(imm26));
1955
1956 instr_at_put(pc, instr | (imm26 & kImm26Mask));
1957 return 1; // Number of instructions patched.
1958 }
1959 }
1960
1961
GrowBuffer()1962 void Assembler::GrowBuffer() {
1963 if (!own_buffer_) FATAL("external code buffer is too small");
1964
1965 // Compute new buffer size.
1966 CodeDesc desc; // The new buffer.
1967 if (buffer_size_ < 4*KB) {
1968 desc.buffer_size = 4*KB;
1969 } else if (buffer_size_ < 1*MB) {
1970 desc.buffer_size = 2*buffer_size_;
1971 } else {
1972 desc.buffer_size = buffer_size_ + 1*MB;
1973 }
1974 CHECK_GT(desc.buffer_size, 0); // No overflow.
1975
1976 // Set up new buffer.
1977 desc.buffer = NewArray<byte>(desc.buffer_size);
1978
1979 desc.instr_size = pc_offset();
1980 desc.reloc_size = (buffer_ + buffer_size_) - reloc_info_writer.pos();
1981
1982 // Copy the data.
1983 int pc_delta = desc.buffer - buffer_;
1984 int rc_delta = (desc.buffer + desc.buffer_size) - (buffer_ + buffer_size_);
1985 memmove(desc.buffer, buffer_, desc.instr_size);
1986 memmove(reloc_info_writer.pos() + rc_delta,
1987 reloc_info_writer.pos(), desc.reloc_size);
1988
1989 // Switch buffers.
1990 DeleteArray(buffer_);
1991 buffer_ = desc.buffer;
1992 buffer_size_ = desc.buffer_size;
1993 pc_ += pc_delta;
1994 reloc_info_writer.Reposition(reloc_info_writer.pos() + rc_delta,
1995 reloc_info_writer.last_pc() + pc_delta);
1996
1997 // Relocate runtime entries.
1998 for (RelocIterator it(desc); !it.done(); it.next()) {
1999 RelocInfo::Mode rmode = it.rinfo()->rmode();
2000 if (rmode == RelocInfo::INTERNAL_REFERENCE) {
2001 byte* p = reinterpret_cast<byte*>(it.rinfo()->pc());
2002 RelocateInternalReference(p, pc_delta);
2003 }
2004 }
2005
2006 ASSERT(!overflow());
2007 }
2008
2009
db(uint8_t data)2010 void Assembler::db(uint8_t data) {
2011 CheckBuffer();
2012 *reinterpret_cast<uint8_t*>(pc_) = data;
2013 pc_ += sizeof(uint8_t);
2014 }
2015
2016
dd(uint32_t data)2017 void Assembler::dd(uint32_t data) {
2018 CheckBuffer();
2019 *reinterpret_cast<uint32_t*>(pc_) = data;
2020 pc_ += sizeof(uint32_t);
2021 }
2022
2023
RecordRelocInfo(RelocInfo::Mode rmode,intptr_t data)2024 void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) {
2025 // We do not try to reuse pool constants.
2026 RelocInfo rinfo(pc_, rmode, data, NULL);
2027 if (rmode >= RelocInfo::JS_RETURN && rmode <= RelocInfo::DEBUG_BREAK_SLOT) {
2028 // Adjust code for new modes.
2029 ASSERT(RelocInfo::IsDebugBreakSlot(rmode)
2030 || RelocInfo::IsJSReturn(rmode)
2031 || RelocInfo::IsComment(rmode)
2032 || RelocInfo::IsPosition(rmode));
2033 // These modes do not need an entry in the constant pool.
2034 }
2035 if (rinfo.rmode() != RelocInfo::NONE) {
2036 // Don't record external references unless the heap will be serialized.
2037 if (rmode == RelocInfo::EXTERNAL_REFERENCE) {
2038 #ifdef DEBUG
2039 if (!Serializer::enabled()) {
2040 Serializer::TooLateToEnableNow();
2041 }
2042 #endif
2043 if (!Serializer::enabled() && !emit_debug_code()) {
2044 return;
2045 }
2046 }
2047 ASSERT(buffer_space() >= kMaxRelocSize); // Too late to grow buffer here.
2048 if (rmode == RelocInfo::CODE_TARGET_WITH_ID) {
2049 RelocInfo reloc_info_with_ast_id(pc_, rmode, RecordedAstId(), NULL);
2050 ClearRecordedAstId();
2051 reloc_info_writer.Write(&reloc_info_with_ast_id);
2052 } else {
2053 reloc_info_writer.Write(&rinfo);
2054 }
2055 }
2056 }
2057
2058
BlockTrampolinePoolFor(int instructions)2059 void Assembler::BlockTrampolinePoolFor(int instructions) {
2060 BlockTrampolinePoolBefore(pc_offset() + instructions * kInstrSize);
2061 }
2062
2063
CheckTrampolinePool()2064 void Assembler::CheckTrampolinePool() {
2065 // Some small sequences of instructions must not be broken up by the
2066 // insertion of a trampoline pool; such sequences are protected by setting
2067 // either trampoline_pool_blocked_nesting_ or no_trampoline_pool_before_,
2068 // which are both checked here. Also, recursive calls to CheckTrampolinePool
2069 // are blocked by trampoline_pool_blocked_nesting_.
2070 if ((trampoline_pool_blocked_nesting_ > 0) ||
2071 (pc_offset() < no_trampoline_pool_before_)) {
2072 // Emission is currently blocked; make sure we try again as soon as
2073 // possible.
2074 if (trampoline_pool_blocked_nesting_ > 0) {
2075 next_buffer_check_ = pc_offset() + kInstrSize;
2076 } else {
2077 next_buffer_check_ = no_trampoline_pool_before_;
2078 }
2079 return;
2080 }
2081
2082 ASSERT(!trampoline_emitted_);
2083 ASSERT(unbound_labels_count_ >= 0);
2084 if (unbound_labels_count_ > 0) {
2085 // First we emit jump (2 instructions), then we emit trampoline pool.
2086 { BlockTrampolinePoolScope block_trampoline_pool(this);
2087 Label after_pool;
2088 b(&after_pool);
2089 nop();
2090
2091 int pool_start = pc_offset();
2092 for (int i = 0; i < unbound_labels_count_; i++) {
2093 uint32_t imm32;
2094 imm32 = jump_address(&after_pool);
2095 { BlockGrowBufferScope block_buf_growth(this);
2096 // Buffer growth (and relocation) must be blocked for internal
2097 // references until associated instructions are emitted and available
2098 // to be patched.
2099 RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE);
2100 lui(at, (imm32 & kHiMask) >> kLuiShift);
2101 ori(at, at, (imm32 & kImm16Mask));
2102 }
2103 jr(at);
2104 nop();
2105 }
2106 bind(&after_pool);
2107 trampoline_ = Trampoline(pool_start, unbound_labels_count_);
2108
2109 trampoline_emitted_ = true;
2110 // As we are only going to emit trampoline once, we need to prevent any
2111 // further emission.
2112 next_buffer_check_ = kMaxInt;
2113 }
2114 } else {
2115 // Number of branches to unbound label at this point is zero, so we can
2116 // move next buffer check to maximum.
2117 next_buffer_check_ = pc_offset() +
2118 kMaxBranchOffset - kTrampolineSlotsSize * 16;
2119 }
2120 return;
2121 }
2122
2123
target_address_at(Address pc)2124 Address Assembler::target_address_at(Address pc) {
2125 Instr instr1 = instr_at(pc);
2126 Instr instr2 = instr_at(pc + kInstrSize);
2127 // Interpret 2 instructions generated by li: lui/ori
2128 if ((GetOpcodeField(instr1) == LUI) && (GetOpcodeField(instr2) == ORI)) {
2129 // Assemble the 32 bit value.
2130 return reinterpret_cast<Address>(
2131 (GetImmediate16(instr1) << 16) | GetImmediate16(instr2));
2132 }
2133
2134 // We should never get here, force a bad address if we do.
2135 UNREACHABLE();
2136 return (Address)0x0;
2137 }
2138
2139
2140 // MIPS and ia32 use opposite encoding for qNaN and sNaN, such that ia32
2141 // qNaN is a MIPS sNaN, and ia32 sNaN is MIPS qNaN. If running from a heap
2142 // snapshot generated on ia32, the resulting MIPS sNaN must be quieted.
2143 // OS::nan_value() returns a qNaN.
QuietNaN(HeapObject * object)2144 void Assembler::QuietNaN(HeapObject* object) {
2145 HeapNumber::cast(object)->set_value(OS::nan_value());
2146 }
2147
2148
2149 // On Mips, a target address is stored in a lui/ori instruction pair, each
2150 // of which load 16 bits of the 32-bit address to a register.
2151 // Patching the address must replace both instr, and flush the i-cache.
2152 //
2153 // There is an optimization below, which emits a nop when the address
2154 // fits in just 16 bits. This is unlikely to help, and should be benchmarked,
2155 // and possibly removed.
set_target_address_at(Address pc,Address target)2156 void Assembler::set_target_address_at(Address pc, Address target) {
2157 Instr instr2 = instr_at(pc + kInstrSize);
2158 uint32_t rt_code = GetRtField(instr2);
2159 uint32_t* p = reinterpret_cast<uint32_t*>(pc);
2160 uint32_t itarget = reinterpret_cast<uint32_t>(target);
2161
2162 #ifdef DEBUG
2163 // Check we have the result from a li macro-instruction, using instr pair.
2164 Instr instr1 = instr_at(pc);
2165 CHECK((GetOpcodeField(instr1) == LUI && GetOpcodeField(instr2) == ORI));
2166 #endif
2167
2168 // Must use 2 instructions to insure patchable code => just use lui and ori.
2169 // lui rt, upper-16.
2170 // ori rt rt, lower-16.
2171 *p = LUI | rt_code | ((itarget & kHiMask) >> kLuiShift);
2172 *(p+1) = ORI | rt_code | (rt_code << 5) | (itarget & kImm16Mask);
2173
2174 // The following code is an optimization for the common case of Call()
2175 // or Jump() which is load to register, and jump through register:
2176 // li(t9, address); jalr(t9) (or jr(t9)).
2177 // If the destination address is in the same 256 MB page as the call, it
2178 // is faster to do a direct jal, or j, rather than jump thru register, since
2179 // that lets the cpu pipeline prefetch the target address. However each
2180 // time the address above is patched, we have to patch the direct jal/j
2181 // instruction, as well as possibly revert to jalr/jr if we now cross a
2182 // 256 MB page. Note that with the jal/j instructions, we do not need to
2183 // load the register, but that code is left, since it makes it easy to
2184 // revert this process. A further optimization could try replacing the
2185 // li sequence with nops.
2186 // This optimization can only be applied if the rt-code from instr2 is the
2187 // register used for the jalr/jr. Finally, we have to skip 'jr ra', which is
2188 // mips return. Occasionally this lands after an li().
2189
2190 Instr instr3 = instr_at(pc + 2 * kInstrSize);
2191 uint32_t ipc = reinterpret_cast<uint32_t>(pc + 3 * kInstrSize);
2192 bool in_range =
2193 ((uint32_t)(ipc ^ itarget) >> (kImm26Bits + kImmFieldShift)) == 0;
2194 uint32_t target_field = (uint32_t)(itarget & kJumpAddrMask) >> kImmFieldShift;
2195 bool patched_jump = false;
2196
2197 #ifndef ALLOW_JAL_IN_BOUNDARY_REGION
2198 // This is a workaround to the 24k core E156 bug (affect some 34k cores also).
2199 // Since the excluded space is only 64KB out of 256MB (0.02 %), we will just
2200 // apply this workaround for all cores so we don't have to identify the core.
2201 if (in_range) {
2202 // The 24k core E156 bug has some very specific requirements, we only check
2203 // the most simple one: if the address of the delay slot instruction is in
2204 // the first or last 32 KB of the 256 MB segment.
2205 uint32_t segment_mask = ((256 * MB) - 1) ^ ((32 * KB) - 1);
2206 uint32_t ipc_segment_addr = ipc & segment_mask;
2207 if (ipc_segment_addr == 0 || ipc_segment_addr == segment_mask)
2208 in_range = false;
2209 }
2210 #endif
2211
2212 if (IsJalr(instr3)) {
2213 // Try to convert JALR to JAL.
2214 if (in_range && GetRt(instr2) == GetRs(instr3)) {
2215 *(p+2) = JAL | target_field;
2216 patched_jump = true;
2217 }
2218 } else if (IsJr(instr3)) {
2219 // Try to convert JR to J, skip returns (jr ra).
2220 bool is_ret = static_cast<int>(GetRs(instr3)) == ra.code();
2221 if (in_range && !is_ret && GetRt(instr2) == GetRs(instr3)) {
2222 *(p+2) = J | target_field;
2223 patched_jump = true;
2224 }
2225 } else if (IsJal(instr3)) {
2226 if (in_range) {
2227 // We are patching an already converted JAL.
2228 *(p+2) = JAL | target_field;
2229 } else {
2230 // Patch JAL, but out of range, revert to JALR.
2231 // JALR rs reg is the rt reg specified in the ORI instruction.
2232 uint32_t rs_field = GetRt(instr2) << kRsShift;
2233 uint32_t rd_field = ra.code() << kRdShift; // Return-address (ra) reg.
2234 *(p+2) = SPECIAL | rs_field | rd_field | JALR;
2235 }
2236 patched_jump = true;
2237 } else if (IsJ(instr3)) {
2238 if (in_range) {
2239 // We are patching an already converted J (jump).
2240 *(p+2) = J | target_field;
2241 } else {
2242 // Trying patch J, but out of range, just go back to JR.
2243 // JR 'rs' reg is the 'rt' reg specified in the ORI instruction (instr2).
2244 uint32_t rs_field = GetRt(instr2) << kRsShift;
2245 *(p+2) = SPECIAL | rs_field | JR;
2246 }
2247 patched_jump = true;
2248 }
2249
2250 CPU::FlushICache(pc, (patched_jump ? 3 : 2) * sizeof(int32_t));
2251 }
2252
JumpLabelToJumpRegister(Address pc)2253 void Assembler::JumpLabelToJumpRegister(Address pc) {
2254 // Address pc points to lui/ori instructions.
2255 // Jump to label may follow at pc + 2 * kInstrSize.
2256 uint32_t* p = reinterpret_cast<uint32_t*>(pc);
2257 #ifdef DEBUG
2258 Instr instr1 = instr_at(pc);
2259 #endif
2260 Instr instr2 = instr_at(pc + 1 * kInstrSize);
2261 Instr instr3 = instr_at(pc + 2 * kInstrSize);
2262 bool patched = false;
2263
2264 if (IsJal(instr3)) {
2265 ASSERT(GetOpcodeField(instr1) == LUI);
2266 ASSERT(GetOpcodeField(instr2) == ORI);
2267
2268 uint32_t rs_field = GetRt(instr2) << kRsShift;
2269 uint32_t rd_field = ra.code() << kRdShift; // Return-address (ra) reg.
2270 *(p+2) = SPECIAL | rs_field | rd_field | JALR;
2271 patched = true;
2272 } else if (IsJ(instr3)) {
2273 ASSERT(GetOpcodeField(instr1) == LUI);
2274 ASSERT(GetOpcodeField(instr2) == ORI);
2275
2276 uint32_t rs_field = GetRt(instr2) << kRsShift;
2277 *(p+2) = SPECIAL | rs_field | JR;
2278 patched = true;
2279 }
2280
2281 if (patched) {
2282 CPU::FlushICache(pc+2, sizeof(Address));
2283 }
2284 }
2285
2286 } } // namespace v8::internal
2287
2288 #endif // V8_TARGET_ARCH_MIPS
2289