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