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 #include "src/mips64/assembler-mips64.h"
36
37 #if V8_TARGET_ARCH_MIPS64
38
39 #include "src/base/cpu.h"
40 #include "src/mips64/assembler-mips64-inl.h"
41
42 namespace v8 {
43 namespace internal {
44
45
46 // Get the CPU features enabled by the build. For cross compilation the
47 // preprocessor symbols CAN_USE_FPU_INSTRUCTIONS
48 // can be defined to enable FPU instructions when building the
49 // snapshot.
CpuFeaturesImpliedByCompiler()50 static unsigned CpuFeaturesImpliedByCompiler() {
51 unsigned answer = 0;
52 #ifdef CAN_USE_FPU_INSTRUCTIONS
53 answer |= 1u << FPU;
54 #endif // def CAN_USE_FPU_INSTRUCTIONS
55
56 // If the compiler is allowed to use FPU then we can use FPU too in our code
57 // generation even when generating snapshots. This won't work for cross
58 // compilation.
59 #if defined(__mips__) && defined(__mips_hard_float) && __mips_hard_float != 0
60 answer |= 1u << FPU;
61 #endif
62
63 return answer;
64 }
65
66
ProbeImpl(bool cross_compile)67 void CpuFeatures::ProbeImpl(bool cross_compile) {
68 supported_ |= CpuFeaturesImpliedByCompiler();
69
70 // Only use statically determined features for cross compile (snapshot).
71 if (cross_compile) return;
72
73 // If the compiler is allowed to use fpu then we can use fpu too in our
74 // code generation.
75 #ifndef __mips__
76 // For the simulator build, use FPU.
77 supported_ |= 1u << FPU;
78 #else
79 // Probe for additional features at runtime.
80 base::CPU cpu;
81 if (cpu.has_fpu()) supported_ |= 1u << FPU;
82 #endif
83 }
84
85
PrintTarget()86 void CpuFeatures::PrintTarget() { }
PrintFeatures()87 void CpuFeatures::PrintFeatures() { }
88
89
ToNumber(Register reg)90 int ToNumber(Register reg) {
91 DCHECK(reg.is_valid());
92 const int kNumbers[] = {
93 0, // zero_reg
94 1, // at
95 2, // v0
96 3, // v1
97 4, // a0
98 5, // a1
99 6, // a2
100 7, // a3
101 8, // a4
102 9, // a5
103 10, // a6
104 11, // a7
105 12, // t0
106 13, // t1
107 14, // t2
108 15, // t3
109 16, // s0
110 17, // s1
111 18, // s2
112 19, // s3
113 20, // s4
114 21, // s5
115 22, // s6
116 23, // s7
117 24, // t8
118 25, // t9
119 26, // k0
120 27, // k1
121 28, // gp
122 29, // sp
123 30, // fp
124 31, // ra
125 };
126 return kNumbers[reg.code()];
127 }
128
129
ToRegister(int num)130 Register ToRegister(int num) {
131 DCHECK(num >= 0 && num < kNumRegisters);
132 const Register kRegisters[] = {
133 zero_reg,
134 at,
135 v0, v1,
136 a0, a1, a2, a3, a4, a5, a6, a7,
137 t0, t1, t2, t3,
138 s0, s1, s2, s3, s4, s5, s6, s7,
139 t8, t9,
140 k0, k1,
141 gp,
142 sp,
143 fp,
144 ra
145 };
146 return kRegisters[num];
147 }
148
149
150 // -----------------------------------------------------------------------------
151 // Implementation of RelocInfo.
152
153 const int RelocInfo::kApplyMask = RelocInfo::kCodeTargetMask |
154 1 << RelocInfo::INTERNAL_REFERENCE |
155 1 << RelocInfo::INTERNAL_REFERENCE_ENCODED;
156
157
IsCodedSpecially()158 bool RelocInfo::IsCodedSpecially() {
159 // The deserializer needs to know whether a pointer is specially coded. Being
160 // specially coded on MIPS means that it is a lui/ori instruction, and that is
161 // always the case inside code objects.
162 return true;
163 }
164
165
IsInConstantPool()166 bool RelocInfo::IsInConstantPool() {
167 return false;
168 }
169
wasm_memory_reference()170 Address RelocInfo::wasm_memory_reference() {
171 DCHECK(IsWasmMemoryReference(rmode_));
172 return Assembler::target_address_at(pc_, host_);
173 }
174
wasm_global_reference()175 Address RelocInfo::wasm_global_reference() {
176 DCHECK(IsWasmGlobalReference(rmode_));
177 return Assembler::target_address_at(pc_, host_);
178 }
179
wasm_memory_size_reference()180 uint32_t RelocInfo::wasm_memory_size_reference() {
181 DCHECK(IsWasmMemorySizeReference(rmode_));
182 return static_cast<uint32_t>(
183 reinterpret_cast<intptr_t>((Assembler::target_address_at(pc_, host_))));
184 }
185
unchecked_update_wasm_memory_reference(Address address,ICacheFlushMode flush_mode)186 void RelocInfo::unchecked_update_wasm_memory_reference(
187 Address address, ICacheFlushMode flush_mode) {
188 Assembler::set_target_address_at(isolate_, pc_, host_, address, flush_mode);
189 }
190
unchecked_update_wasm_memory_size(uint32_t size,ICacheFlushMode flush_mode)191 void RelocInfo::unchecked_update_wasm_memory_size(uint32_t size,
192 ICacheFlushMode flush_mode) {
193 Assembler::set_target_address_at(isolate_, pc_, host_,
194 reinterpret_cast<Address>(size), flush_mode);
195 }
196
197 // -----------------------------------------------------------------------------
198 // Implementation of Operand and MemOperand.
199 // See assembler-mips-inl.h for inlined constructors.
200
Operand(Handle<Object> handle)201 Operand::Operand(Handle<Object> handle) {
202 AllowDeferredHandleDereference using_raw_address;
203 rm_ = no_reg;
204 // Verify all Objects referred by code are NOT in new space.
205 Object* obj = *handle;
206 if (obj->IsHeapObject()) {
207 DCHECK(!HeapObject::cast(obj)->GetHeap()->InNewSpace(obj));
208 imm64_ = reinterpret_cast<intptr_t>(handle.location());
209 rmode_ = RelocInfo::EMBEDDED_OBJECT;
210 } else {
211 // No relocation needed.
212 imm64_ = reinterpret_cast<intptr_t>(obj);
213 rmode_ = RelocInfo::NONE64;
214 }
215 }
216
217
MemOperand(Register rm,int32_t offset)218 MemOperand::MemOperand(Register rm, int32_t offset) : Operand(rm) {
219 offset_ = offset;
220 }
221
222
MemOperand(Register rm,int32_t unit,int32_t multiplier,OffsetAddend offset_addend)223 MemOperand::MemOperand(Register rm, int32_t unit, int32_t multiplier,
224 OffsetAddend offset_addend)
225 : Operand(rm) {
226 offset_ = unit * multiplier + offset_addend;
227 }
228
229
230 // -----------------------------------------------------------------------------
231 // Specific instructions, constants, and masks.
232
233 static const int kNegOffset = 0x00008000;
234 // daddiu(sp, sp, 8) aka Pop() operation or part of Pop(r)
235 // operations as post-increment of sp.
236 const Instr kPopInstruction = DADDIU | (Register::kCode_sp << kRsShift) |
237 (Register::kCode_sp << kRtShift) |
238 (kPointerSize & kImm16Mask); // NOLINT
239 // daddiu(sp, sp, -8) part of Push(r) operation as pre-decrement of sp.
240 const Instr kPushInstruction = DADDIU | (Register::kCode_sp << kRsShift) |
241 (Register::kCode_sp << kRtShift) |
242 (-kPointerSize & kImm16Mask); // NOLINT
243 // sd(r, MemOperand(sp, 0))
244 const Instr kPushRegPattern =
245 SD | (Register::kCode_sp << kRsShift) | (0 & kImm16Mask); // NOLINT
246 // ld(r, MemOperand(sp, 0))
247 const Instr kPopRegPattern =
248 LD | (Register::kCode_sp << kRsShift) | (0 & kImm16Mask); // NOLINT
249
250 const Instr kLwRegFpOffsetPattern =
251 LW | (Register::kCode_fp << kRsShift) | (0 & kImm16Mask); // NOLINT
252
253 const Instr kSwRegFpOffsetPattern =
254 SW | (Register::kCode_fp << kRsShift) | (0 & kImm16Mask); // NOLINT
255
256 const Instr kLwRegFpNegOffsetPattern = LW | (Register::kCode_fp << kRsShift) |
257 (kNegOffset & kImm16Mask); // NOLINT
258
259 const Instr kSwRegFpNegOffsetPattern = SW | (Register::kCode_fp << kRsShift) |
260 (kNegOffset & kImm16Mask); // NOLINT
261 // A mask for the Rt register for push, pop, lw, sw instructions.
262 const Instr kRtMask = kRtFieldMask;
263 const Instr kLwSwInstrTypeMask = 0xffe00000;
264 const Instr kLwSwInstrArgumentMask = ~kLwSwInstrTypeMask;
265 const Instr kLwSwOffsetMask = kImm16Mask;
266
267
Assembler(Isolate * isolate,void * buffer,int buffer_size)268 Assembler::Assembler(Isolate* isolate, void* buffer, int buffer_size)
269 : AssemblerBase(isolate, buffer, buffer_size),
270 recorded_ast_id_(TypeFeedbackId::None()),
271 positions_recorder_(this) {
272 reloc_info_writer.Reposition(buffer_ + buffer_size_, pc_);
273
274 last_trampoline_pool_end_ = 0;
275 no_trampoline_pool_before_ = 0;
276 trampoline_pool_blocked_nesting_ = 0;
277 // We leave space (16 * kTrampolineSlotsSize)
278 // for BlockTrampolinePoolScope buffer.
279 next_buffer_check_ = FLAG_force_long_branches
280 ? kMaxInt : kMaxBranchOffset - kTrampolineSlotsSize * 16;
281 internal_trampoline_exception_ = false;
282 last_bound_pos_ = 0;
283
284 trampoline_emitted_ = FLAG_force_long_branches;
285 unbound_labels_count_ = 0;
286 block_buffer_growth_ = false;
287
288 ClearRecordedAstId();
289 }
290
291
GetCode(CodeDesc * desc)292 void Assembler::GetCode(CodeDesc* desc) {
293 EmitForbiddenSlotInstruction();
294 DCHECK(pc_ <= reloc_info_writer.pos()); // No overlap.
295 // Set up code descriptor.
296 desc->buffer = buffer_;
297 desc->buffer_size = buffer_size_;
298 desc->instr_size = pc_offset();
299 desc->reloc_size =
300 static_cast<int>((buffer_ + buffer_size_) - reloc_info_writer.pos());
301 desc->origin = this;
302 desc->constant_pool_size = 0;
303 desc->unwinding_info_size = 0;
304 desc->unwinding_info = nullptr;
305 }
306
307
Align(int m)308 void Assembler::Align(int m) {
309 DCHECK(m >= 4 && base::bits::IsPowerOfTwo32(m));
310 EmitForbiddenSlotInstruction();
311 while ((pc_offset() & (m - 1)) != 0) {
312 nop();
313 }
314 }
315
316
CodeTargetAlign()317 void Assembler::CodeTargetAlign() {
318 // No advantage to aligning branch/call targets to more than
319 // single instruction, that I am aware of.
320 Align(4);
321 }
322
323
GetRtReg(Instr instr)324 Register Assembler::GetRtReg(Instr instr) {
325 Register rt;
326 rt.reg_code = (instr & kRtFieldMask) >> kRtShift;
327 return rt;
328 }
329
330
GetRsReg(Instr instr)331 Register Assembler::GetRsReg(Instr instr) {
332 Register rs;
333 rs.reg_code = (instr & kRsFieldMask) >> kRsShift;
334 return rs;
335 }
336
337
GetRdReg(Instr instr)338 Register Assembler::GetRdReg(Instr instr) {
339 Register rd;
340 rd.reg_code = (instr & kRdFieldMask) >> kRdShift;
341 return rd;
342 }
343
344
GetRt(Instr instr)345 uint32_t Assembler::GetRt(Instr instr) {
346 return (instr & kRtFieldMask) >> kRtShift;
347 }
348
349
GetRtField(Instr instr)350 uint32_t Assembler::GetRtField(Instr instr) {
351 return instr & kRtFieldMask;
352 }
353
354
GetRs(Instr instr)355 uint32_t Assembler::GetRs(Instr instr) {
356 return (instr & kRsFieldMask) >> kRsShift;
357 }
358
359
GetRsField(Instr instr)360 uint32_t Assembler::GetRsField(Instr instr) {
361 return instr & kRsFieldMask;
362 }
363
364
GetRd(Instr instr)365 uint32_t Assembler::GetRd(Instr instr) {
366 return (instr & kRdFieldMask) >> kRdShift;
367 }
368
369
GetRdField(Instr instr)370 uint32_t Assembler::GetRdField(Instr instr) {
371 return instr & kRdFieldMask;
372 }
373
374
GetSa(Instr instr)375 uint32_t Assembler::GetSa(Instr instr) {
376 return (instr & kSaFieldMask) >> kSaShift;
377 }
378
379
GetSaField(Instr instr)380 uint32_t Assembler::GetSaField(Instr instr) {
381 return instr & kSaFieldMask;
382 }
383
384
GetOpcodeField(Instr instr)385 uint32_t Assembler::GetOpcodeField(Instr instr) {
386 return instr & kOpcodeMask;
387 }
388
389
GetFunction(Instr instr)390 uint32_t Assembler::GetFunction(Instr instr) {
391 return (instr & kFunctionFieldMask) >> kFunctionShift;
392 }
393
394
GetFunctionField(Instr instr)395 uint32_t Assembler::GetFunctionField(Instr instr) {
396 return instr & kFunctionFieldMask;
397 }
398
399
GetImmediate16(Instr instr)400 uint32_t Assembler::GetImmediate16(Instr instr) {
401 return instr & kImm16Mask;
402 }
403
404
GetLabelConst(Instr instr)405 uint32_t Assembler::GetLabelConst(Instr instr) {
406 return instr & ~kImm16Mask;
407 }
408
409
IsPop(Instr instr)410 bool Assembler::IsPop(Instr instr) {
411 return (instr & ~kRtMask) == kPopRegPattern;
412 }
413
414
IsPush(Instr instr)415 bool Assembler::IsPush(Instr instr) {
416 return (instr & ~kRtMask) == kPushRegPattern;
417 }
418
419
IsSwRegFpOffset(Instr instr)420 bool Assembler::IsSwRegFpOffset(Instr instr) {
421 return ((instr & kLwSwInstrTypeMask) == kSwRegFpOffsetPattern);
422 }
423
424
IsLwRegFpOffset(Instr instr)425 bool Assembler::IsLwRegFpOffset(Instr instr) {
426 return ((instr & kLwSwInstrTypeMask) == kLwRegFpOffsetPattern);
427 }
428
429
IsSwRegFpNegOffset(Instr instr)430 bool Assembler::IsSwRegFpNegOffset(Instr instr) {
431 return ((instr & (kLwSwInstrTypeMask | kNegOffset)) ==
432 kSwRegFpNegOffsetPattern);
433 }
434
435
IsLwRegFpNegOffset(Instr instr)436 bool Assembler::IsLwRegFpNegOffset(Instr instr) {
437 return ((instr & (kLwSwInstrTypeMask | kNegOffset)) ==
438 kLwRegFpNegOffsetPattern);
439 }
440
441
442 // Labels refer to positions in the (to be) generated code.
443 // There are bound, linked, and unused labels.
444 //
445 // Bound labels refer to known positions in the already
446 // generated code. pos() is the position the label refers to.
447 //
448 // Linked labels refer to unknown positions in the code
449 // to be generated; pos() is the position of the last
450 // instruction using the label.
451
452 // The link chain is terminated by a value in the instruction of -1,
453 // which is an otherwise illegal value (branch -1 is inf loop).
454 // The instruction 16-bit offset field addresses 32-bit words, but in
455 // code is conv to an 18-bit value addressing bytes, hence the -4 value.
456
457 const int kEndOfChain = -4;
458 // Determines the end of the Jump chain (a subset of the label link chain).
459 const int kEndOfJumpChain = 0;
460
461
IsBranch(Instr instr)462 bool Assembler::IsBranch(Instr instr) {
463 uint32_t opcode = GetOpcodeField(instr);
464 uint32_t rt_field = GetRtField(instr);
465 uint32_t rs_field = GetRsField(instr);
466 // Checks if the instruction is a branch.
467 bool isBranch =
468 opcode == BEQ || opcode == BNE || opcode == BLEZ || opcode == BGTZ ||
469 opcode == BEQL || opcode == BNEL || opcode == BLEZL || opcode == BGTZL ||
470 (opcode == REGIMM && (rt_field == BLTZ || rt_field == BGEZ ||
471 rt_field == BLTZAL || rt_field == BGEZAL)) ||
472 (opcode == COP1 && rs_field == BC1) || // Coprocessor branch.
473 (opcode == COP1 && rs_field == BC1EQZ) ||
474 (opcode == COP1 && rs_field == BC1NEZ);
475 if (!isBranch && kArchVariant == kMips64r6) {
476 // All the 3 variants of POP10 (BOVC, BEQC, BEQZALC) and
477 // POP30 (BNVC, BNEC, BNEZALC) are branch ops.
478 isBranch |= opcode == POP10 || opcode == POP30 || opcode == BC ||
479 opcode == BALC ||
480 (opcode == POP66 && rs_field != 0) || // BEQZC
481 (opcode == POP76 && rs_field != 0); // BNEZC
482 }
483 return isBranch;
484 }
485
486
IsBc(Instr instr)487 bool Assembler::IsBc(Instr instr) {
488 uint32_t opcode = GetOpcodeField(instr);
489 // Checks if the instruction is a BC or BALC.
490 return opcode == BC || opcode == BALC;
491 }
492
493
IsBzc(Instr instr)494 bool Assembler::IsBzc(Instr instr) {
495 uint32_t opcode = GetOpcodeField(instr);
496 // Checks if the instruction is BEQZC or BNEZC.
497 return (opcode == POP66 && GetRsField(instr) != 0) ||
498 (opcode == POP76 && GetRsField(instr) != 0);
499 }
500
501
IsEmittedConstant(Instr instr)502 bool Assembler::IsEmittedConstant(Instr instr) {
503 uint32_t label_constant = GetLabelConst(instr);
504 return label_constant == 0; // Emitted label const in reg-exp engine.
505 }
506
507
IsBeq(Instr instr)508 bool Assembler::IsBeq(Instr instr) {
509 return GetOpcodeField(instr) == BEQ;
510 }
511
512
IsBne(Instr instr)513 bool Assembler::IsBne(Instr instr) {
514 return GetOpcodeField(instr) == BNE;
515 }
516
517
IsBeqzc(Instr instr)518 bool Assembler::IsBeqzc(Instr instr) {
519 uint32_t opcode = GetOpcodeField(instr);
520 return opcode == POP66 && GetRsField(instr) != 0;
521 }
522
523
IsBnezc(Instr instr)524 bool Assembler::IsBnezc(Instr instr) {
525 uint32_t opcode = GetOpcodeField(instr);
526 return opcode == POP76 && GetRsField(instr) != 0;
527 }
528
529
IsBeqc(Instr instr)530 bool Assembler::IsBeqc(Instr instr) {
531 uint32_t opcode = GetOpcodeField(instr);
532 uint32_t rs = GetRsField(instr);
533 uint32_t rt = GetRtField(instr);
534 return opcode == POP10 && rs != 0 && rs < rt; // && rt != 0
535 }
536
537
IsBnec(Instr instr)538 bool Assembler::IsBnec(Instr instr) {
539 uint32_t opcode = GetOpcodeField(instr);
540 uint32_t rs = GetRsField(instr);
541 uint32_t rt = GetRtField(instr);
542 return opcode == POP30 && rs != 0 && rs < rt; // && rt != 0
543 }
544
545
IsJump(Instr instr)546 bool Assembler::IsJump(Instr instr) {
547 uint32_t opcode = GetOpcodeField(instr);
548 uint32_t rt_field = GetRtField(instr);
549 uint32_t rd_field = GetRdField(instr);
550 uint32_t function_field = GetFunctionField(instr);
551 // Checks if the instruction is a jump.
552 return opcode == J || opcode == JAL ||
553 (opcode == SPECIAL && rt_field == 0 &&
554 ((function_field == JALR) || (rd_field == 0 && (function_field == JR))));
555 }
556
557
IsJ(Instr instr)558 bool Assembler::IsJ(Instr instr) {
559 uint32_t opcode = GetOpcodeField(instr);
560 // Checks if the instruction is a jump.
561 return opcode == J;
562 }
563
564
IsJal(Instr instr)565 bool Assembler::IsJal(Instr instr) {
566 return GetOpcodeField(instr) == JAL;
567 }
568
569
IsJr(Instr instr)570 bool Assembler::IsJr(Instr instr) {
571 return GetOpcodeField(instr) == SPECIAL && GetFunctionField(instr) == JR;
572 }
573
574
IsJalr(Instr instr)575 bool Assembler::IsJalr(Instr instr) {
576 return GetOpcodeField(instr) == SPECIAL && GetFunctionField(instr) == JALR;
577 }
578
579
IsLui(Instr instr)580 bool Assembler::IsLui(Instr instr) {
581 uint32_t opcode = GetOpcodeField(instr);
582 // Checks if the instruction is a load upper immediate.
583 return opcode == LUI;
584 }
585
586
IsOri(Instr instr)587 bool Assembler::IsOri(Instr instr) {
588 uint32_t opcode = GetOpcodeField(instr);
589 // Checks if the instruction is a load upper immediate.
590 return opcode == ORI;
591 }
592
593
IsNop(Instr instr,unsigned int type)594 bool Assembler::IsNop(Instr instr, unsigned int type) {
595 // See Assembler::nop(type).
596 DCHECK(type < 32);
597 uint32_t opcode = GetOpcodeField(instr);
598 uint32_t function = GetFunctionField(instr);
599 uint32_t rt = GetRt(instr);
600 uint32_t rd = GetRd(instr);
601 uint32_t sa = GetSa(instr);
602
603 // Traditional mips nop == sll(zero_reg, zero_reg, 0)
604 // When marking non-zero type, use sll(zero_reg, at, type)
605 // to avoid use of mips ssnop and ehb special encodings
606 // of the sll instruction.
607
608 Register nop_rt_reg = (type == 0) ? zero_reg : at;
609 bool ret = (opcode == SPECIAL && function == SLL &&
610 rd == static_cast<uint32_t>(ToNumber(zero_reg)) &&
611 rt == static_cast<uint32_t>(ToNumber(nop_rt_reg)) &&
612 sa == type);
613
614 return ret;
615 }
616
617
GetBranchOffset(Instr instr)618 int32_t Assembler::GetBranchOffset(Instr instr) {
619 DCHECK(IsBranch(instr));
620 return (static_cast<int16_t>(instr & kImm16Mask)) << 2;
621 }
622
623
IsLw(Instr instr)624 bool Assembler::IsLw(Instr instr) {
625 return (static_cast<uint32_t>(instr & kOpcodeMask) == LW);
626 }
627
628
GetLwOffset(Instr instr)629 int16_t Assembler::GetLwOffset(Instr instr) {
630 DCHECK(IsLw(instr));
631 return ((instr & kImm16Mask));
632 }
633
634
SetLwOffset(Instr instr,int16_t offset)635 Instr Assembler::SetLwOffset(Instr instr, int16_t offset) {
636 DCHECK(IsLw(instr));
637
638 // We actually create a new lw instruction based on the original one.
639 Instr temp_instr = LW | (instr & kRsFieldMask) | (instr & kRtFieldMask)
640 | (offset & kImm16Mask);
641
642 return temp_instr;
643 }
644
645
IsSw(Instr instr)646 bool Assembler::IsSw(Instr instr) {
647 return (static_cast<uint32_t>(instr & kOpcodeMask) == SW);
648 }
649
650
SetSwOffset(Instr instr,int16_t offset)651 Instr Assembler::SetSwOffset(Instr instr, int16_t offset) {
652 DCHECK(IsSw(instr));
653 return ((instr & ~kImm16Mask) | (offset & kImm16Mask));
654 }
655
656
IsAddImmediate(Instr instr)657 bool Assembler::IsAddImmediate(Instr instr) {
658 return ((instr & kOpcodeMask) == ADDIU || (instr & kOpcodeMask) == DADDIU);
659 }
660
661
SetAddImmediateOffset(Instr instr,int16_t offset)662 Instr Assembler::SetAddImmediateOffset(Instr instr, int16_t offset) {
663 DCHECK(IsAddImmediate(instr));
664 return ((instr & ~kImm16Mask) | (offset & kImm16Mask));
665 }
666
667
IsAndImmediate(Instr instr)668 bool Assembler::IsAndImmediate(Instr instr) {
669 return GetOpcodeField(instr) == ANDI;
670 }
671
672
OffsetSizeInBits(Instr instr)673 static Assembler::OffsetSize OffsetSizeInBits(Instr instr) {
674 if (kArchVariant == kMips64r6) {
675 if (Assembler::IsBc(instr)) {
676 return Assembler::OffsetSize::kOffset26;
677 } else if (Assembler::IsBzc(instr)) {
678 return Assembler::OffsetSize::kOffset21;
679 }
680 }
681 return Assembler::OffsetSize::kOffset16;
682 }
683
684
AddBranchOffset(int pos,Instr instr)685 static inline int32_t AddBranchOffset(int pos, Instr instr) {
686 int bits = OffsetSizeInBits(instr);
687 const int32_t mask = (1 << bits) - 1;
688 bits = 32 - bits;
689
690 // Do NOT change this to <<2. We rely on arithmetic shifts here, assuming
691 // the compiler uses arithmetic shifts for signed integers.
692 int32_t imm = ((instr & mask) << bits) >> (bits - 2);
693
694 if (imm == kEndOfChain) {
695 // EndOfChain sentinel is returned directly, not relative to pc or pos.
696 return kEndOfChain;
697 } else {
698 return pos + Assembler::kBranchPCOffset + imm;
699 }
700 }
701
702
target_at(int pos,bool is_internal)703 int Assembler::target_at(int pos, bool is_internal) {
704 if (is_internal) {
705 int64_t* p = reinterpret_cast<int64_t*>(buffer_ + pos);
706 int64_t address = *p;
707 if (address == kEndOfJumpChain) {
708 return kEndOfChain;
709 } else {
710 int64_t instr_address = reinterpret_cast<int64_t>(p);
711 DCHECK(instr_address - address < INT_MAX);
712 int delta = static_cast<int>(instr_address - address);
713 DCHECK(pos > delta);
714 return pos - delta;
715 }
716 }
717 Instr instr = instr_at(pos);
718 if ((instr & ~kImm16Mask) == 0) {
719 // Emitted label constant, not part of a branch.
720 if (instr == 0) {
721 return kEndOfChain;
722 } else {
723 int32_t imm18 =((instr & static_cast<int32_t>(kImm16Mask)) << 16) >> 14;
724 return (imm18 + pos);
725 }
726 }
727 // Check we have a branch or jump instruction.
728 DCHECK(IsBranch(instr) || IsJ(instr) || IsJal(instr) || IsLui(instr));
729 // Do NOT change this to <<2. We rely on arithmetic shifts here, assuming
730 // the compiler uses arithmetic shifts for signed integers.
731 if (IsBranch(instr)) {
732 return AddBranchOffset(pos, instr);
733 } else if (IsLui(instr)) {
734 Instr instr_lui = instr_at(pos + 0 * Assembler::kInstrSize);
735 Instr instr_ori = instr_at(pos + 1 * Assembler::kInstrSize);
736 Instr instr_ori2 = instr_at(pos + 3 * Assembler::kInstrSize);
737 DCHECK(IsOri(instr_ori));
738 DCHECK(IsOri(instr_ori2));
739
740 // TODO(plind) create named constants for shift values.
741 int64_t imm = static_cast<int64_t>(instr_lui & kImm16Mask) << 48;
742 imm |= static_cast<int64_t>(instr_ori & kImm16Mask) << 32;
743 imm |= static_cast<int64_t>(instr_ori2 & kImm16Mask) << 16;
744 // Sign extend address;
745 imm >>= 16;
746
747 if (imm == kEndOfJumpChain) {
748 // EndOfChain sentinel is returned directly, not relative to pc or pos.
749 return kEndOfChain;
750 } else {
751 uint64_t instr_address = reinterpret_cast<int64_t>(buffer_ + pos);
752 DCHECK(instr_address - imm < INT_MAX);
753 int delta = static_cast<int>(instr_address - imm);
754 DCHECK(pos > delta);
755 return pos - delta;
756 }
757 } else {
758 DCHECK(IsJ(instr) || IsJal(instr));
759 int32_t imm28 = (instr & static_cast<int32_t>(kImm26Mask)) << 2;
760 if (imm28 == kEndOfJumpChain) {
761 // EndOfChain sentinel is returned directly, not relative to pc or pos.
762 return kEndOfChain;
763 } else {
764 // Sign extend 28-bit offset.
765 int32_t delta = static_cast<int32_t>((imm28 << 4) >> 4);
766 return pos + delta;
767 }
768 }
769 }
770
771
SetBranchOffset(int32_t pos,int32_t target_pos,Instr instr)772 static inline Instr SetBranchOffset(int32_t pos, int32_t target_pos,
773 Instr instr) {
774 int32_t bits = OffsetSizeInBits(instr);
775 int32_t imm = target_pos - (pos + Assembler::kBranchPCOffset);
776 DCHECK((imm & 3) == 0);
777 imm >>= 2;
778
779 const int32_t mask = (1 << bits) - 1;
780 instr &= ~mask;
781 DCHECK(is_intn(imm, bits));
782
783 return instr | (imm & mask);
784 }
785
786
target_at_put(int pos,int target_pos,bool is_internal)787 void Assembler::target_at_put(int pos, int target_pos, bool is_internal) {
788 if (is_internal) {
789 uint64_t imm = reinterpret_cast<uint64_t>(buffer_) + target_pos;
790 *reinterpret_cast<uint64_t*>(buffer_ + pos) = imm;
791 return;
792 }
793 Instr instr = instr_at(pos);
794 if ((instr & ~kImm16Mask) == 0) {
795 DCHECK(target_pos == kEndOfChain || target_pos >= 0);
796 // Emitted label constant, not part of a branch.
797 // Make label relative to Code* of generated Code object.
798 instr_at_put(pos, target_pos + (Code::kHeaderSize - kHeapObjectTag));
799 return;
800 }
801
802 if (IsBranch(instr)) {
803 instr = SetBranchOffset(pos, target_pos, instr);
804 instr_at_put(pos, instr);
805 } else if (IsLui(instr)) {
806 Instr instr_lui = instr_at(pos + 0 * Assembler::kInstrSize);
807 Instr instr_ori = instr_at(pos + 1 * Assembler::kInstrSize);
808 Instr instr_ori2 = instr_at(pos + 3 * Assembler::kInstrSize);
809 DCHECK(IsOri(instr_ori));
810 DCHECK(IsOri(instr_ori2));
811
812 uint64_t imm = reinterpret_cast<uint64_t>(buffer_) + target_pos;
813 DCHECK((imm & 3) == 0);
814
815 instr_lui &= ~kImm16Mask;
816 instr_ori &= ~kImm16Mask;
817 instr_ori2 &= ~kImm16Mask;
818
819 instr_at_put(pos + 0 * Assembler::kInstrSize,
820 instr_lui | ((imm >> 32) & kImm16Mask));
821 instr_at_put(pos + 1 * Assembler::kInstrSize,
822 instr_ori | ((imm >> 16) & kImm16Mask));
823 instr_at_put(pos + 3 * Assembler::kInstrSize,
824 instr_ori2 | (imm & kImm16Mask));
825 } else if (IsJ(instr) || IsJal(instr)) {
826 int32_t imm28 = target_pos - pos;
827 DCHECK((imm28 & 3) == 0);
828
829 uint32_t imm26 = static_cast<uint32_t>(imm28 >> 2);
830 DCHECK(is_uint26(imm26));
831 // Place 26-bit signed offset with markings.
832 // When code is committed it will be resolved to j/jal.
833 int32_t mark = IsJ(instr) ? kJRawMark : kJalRawMark;
834 instr_at_put(pos, mark | (imm26 & kImm26Mask));
835 } else {
836 int32_t imm28 = target_pos - pos;
837 DCHECK((imm28 & 3) == 0);
838
839 uint32_t imm26 = static_cast<uint32_t>(imm28 >> 2);
840 DCHECK(is_uint26(imm26));
841 // Place raw 26-bit signed offset.
842 // When code is committed it will be resolved to j/jal.
843 instr &= ~kImm26Mask;
844 instr_at_put(pos, instr | (imm26 & kImm26Mask));
845 }
846 }
847
848
print(Label * L)849 void Assembler::print(Label* L) {
850 if (L->is_unused()) {
851 PrintF("unused label\n");
852 } else if (L->is_bound()) {
853 PrintF("bound label to %d\n", L->pos());
854 } else if (L->is_linked()) {
855 Label l = *L;
856 PrintF("unbound label");
857 while (l.is_linked()) {
858 PrintF("@ %d ", l.pos());
859 Instr instr = instr_at(l.pos());
860 if ((instr & ~kImm16Mask) == 0) {
861 PrintF("value\n");
862 } else {
863 PrintF("%d\n", instr);
864 }
865 next(&l, internal_reference_positions_.find(l.pos()) !=
866 internal_reference_positions_.end());
867 }
868 } else {
869 PrintF("label in inconsistent state (pos = %d)\n", L->pos_);
870 }
871 }
872
873
bind_to(Label * L,int pos)874 void Assembler::bind_to(Label* L, int pos) {
875 DCHECK(0 <= pos && pos <= pc_offset()); // Must have valid binding position.
876 int trampoline_pos = kInvalidSlotPos;
877 bool is_internal = false;
878 if (L->is_linked() && !trampoline_emitted_) {
879 unbound_labels_count_--;
880 next_buffer_check_ += kTrampolineSlotsSize;
881 }
882
883 while (L->is_linked()) {
884 int fixup_pos = L->pos();
885 int dist = pos - fixup_pos;
886 is_internal = internal_reference_positions_.find(fixup_pos) !=
887 internal_reference_positions_.end();
888 next(L, is_internal); // Call next before overwriting link with target at
889 // fixup_pos.
890 Instr instr = instr_at(fixup_pos);
891 if (is_internal) {
892 target_at_put(fixup_pos, pos, is_internal);
893 } else {
894 if (IsBranch(instr)) {
895 int branch_offset = BranchOffset(instr);
896 if (dist > branch_offset) {
897 if (trampoline_pos == kInvalidSlotPos) {
898 trampoline_pos = get_trampoline_entry(fixup_pos);
899 CHECK(trampoline_pos != kInvalidSlotPos);
900 }
901 CHECK((trampoline_pos - fixup_pos) <= branch_offset);
902 target_at_put(fixup_pos, trampoline_pos, false);
903 fixup_pos = trampoline_pos;
904 dist = pos - fixup_pos;
905 }
906 target_at_put(fixup_pos, pos, false);
907 } else {
908 DCHECK(IsJ(instr) || IsJal(instr) || IsLui(instr) ||
909 IsEmittedConstant(instr));
910 target_at_put(fixup_pos, pos, false);
911 }
912 }
913 }
914 L->bind_to(pos);
915
916 // Keep track of the last bound label so we don't eliminate any instructions
917 // before a bound label.
918 if (pos > last_bound_pos_)
919 last_bound_pos_ = pos;
920 }
921
922
bind(Label * L)923 void Assembler::bind(Label* L) {
924 DCHECK(!L->is_bound()); // Label can only be bound once.
925 bind_to(L, pc_offset());
926 }
927
928
next(Label * L,bool is_internal)929 void Assembler::next(Label* L, bool is_internal) {
930 DCHECK(L->is_linked());
931 int link = target_at(L->pos(), is_internal);
932 if (link == kEndOfChain) {
933 L->Unuse();
934 } else {
935 DCHECK(link >= 0);
936 L->link_to(link);
937 }
938 }
939
940
is_near(Label * L)941 bool Assembler::is_near(Label* L) {
942 DCHECK(L->is_bound());
943 return pc_offset() - L->pos() < kMaxBranchOffset - 4 * kInstrSize;
944 }
945
946
is_near(Label * L,OffsetSize bits)947 bool Assembler::is_near(Label* L, OffsetSize bits) {
948 if (L == nullptr || !L->is_bound()) return true;
949 return ((pc_offset() - L->pos()) <
950 (1 << (bits + 2 - 1)) - 1 - 5 * kInstrSize);
951 }
952
953
is_near_branch(Label * L)954 bool Assembler::is_near_branch(Label* L) {
955 DCHECK(L->is_bound());
956 return kArchVariant == kMips64r6 ? is_near_r6(L) : is_near_pre_r6(L);
957 }
958
959
BranchOffset(Instr instr)960 int Assembler::BranchOffset(Instr instr) {
961 // At pre-R6 and for other R6 branches the offset is 16 bits.
962 int bits = OffsetSize::kOffset16;
963
964 if (kArchVariant == kMips64r6) {
965 uint32_t opcode = GetOpcodeField(instr);
966 switch (opcode) {
967 // Checks BC or BALC.
968 case BC:
969 case BALC:
970 bits = OffsetSize::kOffset26;
971 break;
972
973 // Checks BEQZC or BNEZC.
974 case POP66:
975 case POP76:
976 if (GetRsField(instr) != 0) bits = OffsetSize::kOffset21;
977 break;
978 default:
979 break;
980 }
981 }
982
983 return (1 << (bits + 2 - 1)) - 1;
984 }
985
986
987 // We have to use a temporary register for things that can be relocated even
988 // if they can be encoded in the MIPS's 16 bits of immediate-offset instruction
989 // space. There is no guarantee that the relocated location can be similarly
990 // encoded.
MustUseReg(RelocInfo::Mode rmode)991 bool Assembler::MustUseReg(RelocInfo::Mode rmode) {
992 return !RelocInfo::IsNone(rmode);
993 }
994
GenInstrRegister(Opcode opcode,Register rs,Register rt,Register rd,uint16_t sa,SecondaryField func)995 void Assembler::GenInstrRegister(Opcode opcode,
996 Register rs,
997 Register rt,
998 Register rd,
999 uint16_t sa,
1000 SecondaryField func) {
1001 DCHECK(rd.is_valid() && rs.is_valid() && rt.is_valid() && is_uint5(sa));
1002 Instr instr = opcode | (rs.code() << kRsShift) | (rt.code() << kRtShift)
1003 | (rd.code() << kRdShift) | (sa << kSaShift) | func;
1004 emit(instr);
1005 }
1006
1007
GenInstrRegister(Opcode opcode,Register rs,Register rt,uint16_t msb,uint16_t lsb,SecondaryField func)1008 void Assembler::GenInstrRegister(Opcode opcode,
1009 Register rs,
1010 Register rt,
1011 uint16_t msb,
1012 uint16_t lsb,
1013 SecondaryField func) {
1014 DCHECK(rs.is_valid() && rt.is_valid() && is_uint5(msb) && is_uint5(lsb));
1015 Instr instr = opcode | (rs.code() << kRsShift) | (rt.code() << kRtShift)
1016 | (msb << kRdShift) | (lsb << kSaShift) | func;
1017 emit(instr);
1018 }
1019
1020
GenInstrRegister(Opcode opcode,SecondaryField fmt,FPURegister ft,FPURegister fs,FPURegister fd,SecondaryField func)1021 void Assembler::GenInstrRegister(Opcode opcode,
1022 SecondaryField fmt,
1023 FPURegister ft,
1024 FPURegister fs,
1025 FPURegister fd,
1026 SecondaryField func) {
1027 DCHECK(fd.is_valid() && fs.is_valid() && ft.is_valid());
1028 Instr instr = opcode | fmt | (ft.code() << kFtShift) | (fs.code() << kFsShift)
1029 | (fd.code() << kFdShift) | func;
1030 emit(instr);
1031 }
1032
1033
GenInstrRegister(Opcode opcode,FPURegister fr,FPURegister ft,FPURegister fs,FPURegister fd,SecondaryField func)1034 void Assembler::GenInstrRegister(Opcode opcode,
1035 FPURegister fr,
1036 FPURegister ft,
1037 FPURegister fs,
1038 FPURegister fd,
1039 SecondaryField func) {
1040 DCHECK(fd.is_valid() && fr.is_valid() && fs.is_valid() && ft.is_valid());
1041 Instr instr = opcode | (fr.code() << kFrShift) | (ft.code() << kFtShift)
1042 | (fs.code() << kFsShift) | (fd.code() << kFdShift) | func;
1043 emit(instr);
1044 }
1045
1046
GenInstrRegister(Opcode opcode,SecondaryField fmt,Register rt,FPURegister fs,FPURegister fd,SecondaryField func)1047 void Assembler::GenInstrRegister(Opcode opcode,
1048 SecondaryField fmt,
1049 Register rt,
1050 FPURegister fs,
1051 FPURegister fd,
1052 SecondaryField func) {
1053 DCHECK(fd.is_valid() && fs.is_valid() && rt.is_valid());
1054 Instr instr = opcode | fmt | (rt.code() << kRtShift)
1055 | (fs.code() << kFsShift) | (fd.code() << kFdShift) | func;
1056 emit(instr);
1057 }
1058
1059
GenInstrRegister(Opcode opcode,SecondaryField fmt,Register rt,FPUControlRegister fs,SecondaryField func)1060 void Assembler::GenInstrRegister(Opcode opcode,
1061 SecondaryField fmt,
1062 Register rt,
1063 FPUControlRegister fs,
1064 SecondaryField func) {
1065 DCHECK(fs.is_valid() && rt.is_valid());
1066 Instr instr =
1067 opcode | fmt | (rt.code() << kRtShift) | (fs.code() << kFsShift) | func;
1068 emit(instr);
1069 }
1070
1071
1072 // Instructions with immediate value.
1073 // Registers are in the order of the instruction encoding, from left to right.
GenInstrImmediate(Opcode opcode,Register rs,Register rt,int32_t j,CompactBranchType is_compact_branch)1074 void Assembler::GenInstrImmediate(Opcode opcode, Register rs, Register rt,
1075 int32_t j,
1076 CompactBranchType is_compact_branch) {
1077 DCHECK(rs.is_valid() && rt.is_valid() && (is_int16(j) || is_uint16(j)));
1078 Instr instr = opcode | (rs.code() << kRsShift) | (rt.code() << kRtShift)
1079 | (j & kImm16Mask);
1080 emit(instr, is_compact_branch);
1081 }
1082
1083
GenInstrImmediate(Opcode opcode,Register rs,SecondaryField SF,int32_t j,CompactBranchType is_compact_branch)1084 void Assembler::GenInstrImmediate(Opcode opcode, Register rs, SecondaryField SF,
1085 int32_t j,
1086 CompactBranchType is_compact_branch) {
1087 DCHECK(rs.is_valid() && (is_int16(j) || is_uint16(j)));
1088 Instr instr = opcode | (rs.code() << kRsShift) | SF | (j & kImm16Mask);
1089 emit(instr, is_compact_branch);
1090 }
1091
1092
GenInstrImmediate(Opcode opcode,Register rs,FPURegister ft,int32_t j,CompactBranchType is_compact_branch)1093 void Assembler::GenInstrImmediate(Opcode opcode, Register rs, FPURegister ft,
1094 int32_t j,
1095 CompactBranchType is_compact_branch) {
1096 DCHECK(rs.is_valid() && ft.is_valid() && (is_int16(j) || is_uint16(j)));
1097 Instr instr = opcode | (rs.code() << kRsShift) | (ft.code() << kFtShift)
1098 | (j & kImm16Mask);
1099 emit(instr, is_compact_branch);
1100 }
1101
1102
GenInstrImmediate(Opcode opcode,Register rs,int32_t offset21,CompactBranchType is_compact_branch)1103 void Assembler::GenInstrImmediate(Opcode opcode, Register rs, int32_t offset21,
1104 CompactBranchType is_compact_branch) {
1105 DCHECK(rs.is_valid() && (is_int21(offset21)));
1106 Instr instr = opcode | (rs.code() << kRsShift) | (offset21 & kImm21Mask);
1107 emit(instr, is_compact_branch);
1108 }
1109
1110
GenInstrImmediate(Opcode opcode,Register rs,uint32_t offset21)1111 void Assembler::GenInstrImmediate(Opcode opcode, Register rs,
1112 uint32_t offset21) {
1113 DCHECK(rs.is_valid() && (is_uint21(offset21)));
1114 Instr instr = opcode | (rs.code() << kRsShift) | (offset21 & kImm21Mask);
1115 emit(instr);
1116 }
1117
1118
GenInstrImmediate(Opcode opcode,int32_t offset26,CompactBranchType is_compact_branch)1119 void Assembler::GenInstrImmediate(Opcode opcode, int32_t offset26,
1120 CompactBranchType is_compact_branch) {
1121 DCHECK(is_int26(offset26));
1122 Instr instr = opcode | (offset26 & kImm26Mask);
1123 emit(instr, is_compact_branch);
1124 }
1125
1126
GenInstrJump(Opcode opcode,uint32_t address)1127 void Assembler::GenInstrJump(Opcode opcode,
1128 uint32_t address) {
1129 BlockTrampolinePoolScope block_trampoline_pool(this);
1130 DCHECK(is_uint26(address));
1131 Instr instr = opcode | address;
1132 emit(instr);
1133 BlockTrampolinePoolFor(1); // For associated delay slot.
1134 }
1135
1136
1137 // Returns the next free trampoline entry.
get_trampoline_entry(int32_t pos)1138 int32_t Assembler::get_trampoline_entry(int32_t pos) {
1139 int32_t trampoline_entry = kInvalidSlotPos;
1140 if (!internal_trampoline_exception_) {
1141 if (trampoline_.start() > pos) {
1142 trampoline_entry = trampoline_.take_slot();
1143 }
1144
1145 if (kInvalidSlotPos == trampoline_entry) {
1146 internal_trampoline_exception_ = true;
1147 }
1148 }
1149 return trampoline_entry;
1150 }
1151
1152
jump_address(Label * L)1153 uint64_t Assembler::jump_address(Label* L) {
1154 int64_t target_pos;
1155 if (L->is_bound()) {
1156 target_pos = L->pos();
1157 } else {
1158 if (L->is_linked()) {
1159 target_pos = L->pos(); // L's link.
1160 L->link_to(pc_offset());
1161 } else {
1162 L->link_to(pc_offset());
1163 return kEndOfJumpChain;
1164 }
1165 }
1166 uint64_t imm = reinterpret_cast<uint64_t>(buffer_) + target_pos;
1167 DCHECK((imm & 3) == 0);
1168
1169 return imm;
1170 }
1171
1172
jump_offset(Label * L)1173 uint64_t Assembler::jump_offset(Label* L) {
1174 int64_t target_pos;
1175 int32_t pad = IsPrevInstrCompactBranch() ? kInstrSize : 0;
1176
1177 if (L->is_bound()) {
1178 target_pos = L->pos();
1179 } else {
1180 if (L->is_linked()) {
1181 target_pos = L->pos(); // L's link.
1182 L->link_to(pc_offset() + pad);
1183 } else {
1184 L->link_to(pc_offset() + pad);
1185 return kEndOfJumpChain;
1186 }
1187 }
1188 int64_t imm = target_pos - (pc_offset() + pad);
1189 DCHECK((imm & 3) == 0);
1190
1191 return static_cast<uint64_t>(imm);
1192 }
1193
1194
branch_offset_helper(Label * L,OffsetSize bits)1195 int32_t Assembler::branch_offset_helper(Label* L, OffsetSize bits) {
1196 int32_t target_pos;
1197 int32_t pad = IsPrevInstrCompactBranch() ? kInstrSize : 0;
1198
1199 if (L->is_bound()) {
1200 target_pos = L->pos();
1201 } else {
1202 if (L->is_linked()) {
1203 target_pos = L->pos();
1204 L->link_to(pc_offset() + pad);
1205 } else {
1206 L->link_to(pc_offset() + pad);
1207 if (!trampoline_emitted_) {
1208 unbound_labels_count_++;
1209 next_buffer_check_ -= kTrampolineSlotsSize;
1210 }
1211 return kEndOfChain;
1212 }
1213 }
1214
1215 int32_t offset = target_pos - (pc_offset() + kBranchPCOffset + pad);
1216 DCHECK(is_intn(offset, bits + 2));
1217 DCHECK((offset & 3) == 0);
1218
1219 return offset;
1220 }
1221
1222
label_at_put(Label * L,int at_offset)1223 void Assembler::label_at_put(Label* L, int at_offset) {
1224 int target_pos;
1225 if (L->is_bound()) {
1226 target_pos = L->pos();
1227 instr_at_put(at_offset, target_pos + (Code::kHeaderSize - kHeapObjectTag));
1228 } else {
1229 if (L->is_linked()) {
1230 target_pos = L->pos(); // L's link.
1231 int32_t imm18 = target_pos - at_offset;
1232 DCHECK((imm18 & 3) == 0);
1233 int32_t imm16 = imm18 >> 2;
1234 DCHECK(is_int16(imm16));
1235 instr_at_put(at_offset, (imm16 & kImm16Mask));
1236 } else {
1237 target_pos = kEndOfChain;
1238 instr_at_put(at_offset, 0);
1239 if (!trampoline_emitted_) {
1240 unbound_labels_count_++;
1241 next_buffer_check_ -= kTrampolineSlotsSize;
1242 }
1243 }
1244 L->link_to(at_offset);
1245 }
1246 }
1247
1248
1249 //------- Branch and jump instructions --------
1250
b(int16_t offset)1251 void Assembler::b(int16_t offset) {
1252 beq(zero_reg, zero_reg, offset);
1253 }
1254
1255
bal(int16_t offset)1256 void Assembler::bal(int16_t offset) {
1257 bgezal(zero_reg, offset);
1258 }
1259
1260
bc(int32_t offset)1261 void Assembler::bc(int32_t offset) {
1262 DCHECK(kArchVariant == kMips64r6);
1263 GenInstrImmediate(BC, offset, CompactBranchType::COMPACT_BRANCH);
1264 }
1265
1266
balc(int32_t offset)1267 void Assembler::balc(int32_t offset) {
1268 DCHECK(kArchVariant == kMips64r6);
1269 GenInstrImmediate(BALC, offset, CompactBranchType::COMPACT_BRANCH);
1270 }
1271
1272
beq(Register rs,Register rt,int16_t offset)1273 void Assembler::beq(Register rs, Register rt, int16_t offset) {
1274 BlockTrampolinePoolScope block_trampoline_pool(this);
1275 GenInstrImmediate(BEQ, rs, rt, offset);
1276 BlockTrampolinePoolFor(1); // For associated delay slot.
1277 }
1278
1279
bgez(Register rs,int16_t offset)1280 void Assembler::bgez(Register rs, int16_t offset) {
1281 BlockTrampolinePoolScope block_trampoline_pool(this);
1282 GenInstrImmediate(REGIMM, rs, BGEZ, offset);
1283 BlockTrampolinePoolFor(1); // For associated delay slot.
1284 }
1285
1286
bgezc(Register rt,int16_t offset)1287 void Assembler::bgezc(Register rt, int16_t offset) {
1288 DCHECK(kArchVariant == kMips64r6);
1289 DCHECK(!(rt.is(zero_reg)));
1290 GenInstrImmediate(BLEZL, rt, rt, offset, CompactBranchType::COMPACT_BRANCH);
1291 }
1292
1293
bgeuc(Register rs,Register rt,int16_t offset)1294 void Assembler::bgeuc(Register rs, Register rt, int16_t offset) {
1295 DCHECK(kArchVariant == kMips64r6);
1296 DCHECK(!(rs.is(zero_reg)));
1297 DCHECK(!(rt.is(zero_reg)));
1298 DCHECK(rs.code() != rt.code());
1299 GenInstrImmediate(BLEZ, rs, rt, offset, CompactBranchType::COMPACT_BRANCH);
1300 }
1301
1302
bgec(Register rs,Register rt,int16_t offset)1303 void Assembler::bgec(Register rs, Register rt, int16_t offset) {
1304 DCHECK(kArchVariant == kMips64r6);
1305 DCHECK(!(rs.is(zero_reg)));
1306 DCHECK(!(rt.is(zero_reg)));
1307 DCHECK(rs.code() != rt.code());
1308 GenInstrImmediate(BLEZL, rs, rt, offset, CompactBranchType::COMPACT_BRANCH);
1309 }
1310
1311
bgezal(Register rs,int16_t offset)1312 void Assembler::bgezal(Register rs, int16_t offset) {
1313 DCHECK(kArchVariant != kMips64r6 || rs.is(zero_reg));
1314 BlockTrampolinePoolScope block_trampoline_pool(this);
1315 GenInstrImmediate(REGIMM, rs, BGEZAL, offset);
1316 BlockTrampolinePoolFor(1); // For associated delay slot.
1317 }
1318
1319
bgtz(Register rs,int16_t offset)1320 void Assembler::bgtz(Register rs, int16_t offset) {
1321 BlockTrampolinePoolScope block_trampoline_pool(this);
1322 GenInstrImmediate(BGTZ, rs, zero_reg, offset);
1323 BlockTrampolinePoolFor(1); // For associated delay slot.
1324 }
1325
1326
bgtzc(Register rt,int16_t offset)1327 void Assembler::bgtzc(Register rt, int16_t offset) {
1328 DCHECK(kArchVariant == kMips64r6);
1329 DCHECK(!(rt.is(zero_reg)));
1330 GenInstrImmediate(BGTZL, zero_reg, rt, offset,
1331 CompactBranchType::COMPACT_BRANCH);
1332 }
1333
1334
blez(Register rs,int16_t offset)1335 void Assembler::blez(Register rs, int16_t offset) {
1336 BlockTrampolinePoolScope block_trampoline_pool(this);
1337 GenInstrImmediate(BLEZ, rs, zero_reg, offset);
1338 BlockTrampolinePoolFor(1); // For associated delay slot.
1339 }
1340
1341
blezc(Register rt,int16_t offset)1342 void Assembler::blezc(Register rt, int16_t offset) {
1343 DCHECK(kArchVariant == kMips64r6);
1344 DCHECK(!(rt.is(zero_reg)));
1345 GenInstrImmediate(BLEZL, zero_reg, rt, offset,
1346 CompactBranchType::COMPACT_BRANCH);
1347 }
1348
1349
bltzc(Register rt,int16_t offset)1350 void Assembler::bltzc(Register rt, int16_t offset) {
1351 DCHECK(kArchVariant == kMips64r6);
1352 DCHECK(!rt.is(zero_reg));
1353 GenInstrImmediate(BGTZL, rt, rt, offset, CompactBranchType::COMPACT_BRANCH);
1354 }
1355
1356
bltuc(Register rs,Register rt,int16_t offset)1357 void Assembler::bltuc(Register rs, Register rt, int16_t offset) {
1358 DCHECK(kArchVariant == kMips64r6);
1359 DCHECK(!(rs.is(zero_reg)));
1360 DCHECK(!(rt.is(zero_reg)));
1361 DCHECK(rs.code() != rt.code());
1362 GenInstrImmediate(BGTZ, rs, rt, offset, CompactBranchType::COMPACT_BRANCH);
1363 }
1364
1365
bltc(Register rs,Register rt,int16_t offset)1366 void Assembler::bltc(Register rs, Register rt, int16_t offset) {
1367 DCHECK(kArchVariant == kMips64r6);
1368 DCHECK(!rs.is(zero_reg));
1369 DCHECK(!rt.is(zero_reg));
1370 DCHECK(rs.code() != rt.code());
1371 GenInstrImmediate(BGTZL, rs, rt, offset, CompactBranchType::COMPACT_BRANCH);
1372 }
1373
1374
bltz(Register rs,int16_t offset)1375 void Assembler::bltz(Register rs, int16_t offset) {
1376 BlockTrampolinePoolScope block_trampoline_pool(this);
1377 GenInstrImmediate(REGIMM, rs, BLTZ, offset);
1378 BlockTrampolinePoolFor(1); // For associated delay slot.
1379 }
1380
1381
bltzal(Register rs,int16_t offset)1382 void Assembler::bltzal(Register rs, int16_t offset) {
1383 DCHECK(kArchVariant != kMips64r6 || rs.is(zero_reg));
1384 BlockTrampolinePoolScope block_trampoline_pool(this);
1385 GenInstrImmediate(REGIMM, rs, BLTZAL, offset);
1386 BlockTrampolinePoolFor(1); // For associated delay slot.
1387 }
1388
1389
bne(Register rs,Register rt,int16_t offset)1390 void Assembler::bne(Register rs, Register rt, int16_t offset) {
1391 BlockTrampolinePoolScope block_trampoline_pool(this);
1392 GenInstrImmediate(BNE, rs, rt, offset);
1393 BlockTrampolinePoolFor(1); // For associated delay slot.
1394 }
1395
1396
bovc(Register rs,Register rt,int16_t offset)1397 void Assembler::bovc(Register rs, Register rt, int16_t offset) {
1398 DCHECK(kArchVariant == kMips64r6);
1399 if (rs.code() >= rt.code()) {
1400 GenInstrImmediate(ADDI, rs, rt, offset, CompactBranchType::COMPACT_BRANCH);
1401 } else {
1402 GenInstrImmediate(ADDI, rt, rs, offset, CompactBranchType::COMPACT_BRANCH);
1403 }
1404 }
1405
1406
bnvc(Register rs,Register rt,int16_t offset)1407 void Assembler::bnvc(Register rs, Register rt, int16_t offset) {
1408 DCHECK(kArchVariant == kMips64r6);
1409 if (rs.code() >= rt.code()) {
1410 GenInstrImmediate(DADDI, rs, rt, offset, CompactBranchType::COMPACT_BRANCH);
1411 } else {
1412 GenInstrImmediate(DADDI, rt, rs, offset, CompactBranchType::COMPACT_BRANCH);
1413 }
1414 }
1415
1416
blezalc(Register rt,int16_t offset)1417 void Assembler::blezalc(Register rt, int16_t offset) {
1418 DCHECK(kArchVariant == kMips64r6);
1419 DCHECK(!(rt.is(zero_reg)));
1420 GenInstrImmediate(BLEZ, zero_reg, rt, offset,
1421 CompactBranchType::COMPACT_BRANCH);
1422 }
1423
1424
bgezalc(Register rt,int16_t offset)1425 void Assembler::bgezalc(Register rt, int16_t offset) {
1426 DCHECK(kArchVariant == kMips64r6);
1427 DCHECK(!(rt.is(zero_reg)));
1428 GenInstrImmediate(BLEZ, rt, rt, offset, CompactBranchType::COMPACT_BRANCH);
1429 }
1430
1431
bgezall(Register rs,int16_t offset)1432 void Assembler::bgezall(Register rs, int16_t offset) {
1433 DCHECK(kArchVariant != kMips64r6);
1434 DCHECK(!(rs.is(zero_reg)));
1435 BlockTrampolinePoolScope block_trampoline_pool(this);
1436 GenInstrImmediate(REGIMM, rs, BGEZALL, offset);
1437 BlockTrampolinePoolFor(1); // For associated delay slot.
1438 }
1439
1440
bltzalc(Register rt,int16_t offset)1441 void Assembler::bltzalc(Register rt, int16_t offset) {
1442 DCHECK(kArchVariant == kMips64r6);
1443 DCHECK(!(rt.is(zero_reg)));
1444 GenInstrImmediate(BGTZ, rt, rt, offset, CompactBranchType::COMPACT_BRANCH);
1445 }
1446
1447
bgtzalc(Register rt,int16_t offset)1448 void Assembler::bgtzalc(Register rt, int16_t offset) {
1449 DCHECK(kArchVariant == kMips64r6);
1450 DCHECK(!(rt.is(zero_reg)));
1451 GenInstrImmediate(BGTZ, zero_reg, rt, offset,
1452 CompactBranchType::COMPACT_BRANCH);
1453 }
1454
1455
beqzalc(Register rt,int16_t offset)1456 void Assembler::beqzalc(Register rt, int16_t offset) {
1457 DCHECK(kArchVariant == kMips64r6);
1458 DCHECK(!(rt.is(zero_reg)));
1459 GenInstrImmediate(ADDI, zero_reg, rt, offset,
1460 CompactBranchType::COMPACT_BRANCH);
1461 }
1462
1463
bnezalc(Register rt,int16_t offset)1464 void Assembler::bnezalc(Register rt, int16_t offset) {
1465 DCHECK(kArchVariant == kMips64r6);
1466 DCHECK(!(rt.is(zero_reg)));
1467 GenInstrImmediate(DADDI, zero_reg, rt, offset,
1468 CompactBranchType::COMPACT_BRANCH);
1469 }
1470
1471
beqc(Register rs,Register rt,int16_t offset)1472 void Assembler::beqc(Register rs, Register rt, int16_t offset) {
1473 DCHECK(kArchVariant == kMips64r6);
1474 DCHECK(rs.code() != rt.code() && rs.code() != 0 && rt.code() != 0);
1475 if (rs.code() < rt.code()) {
1476 GenInstrImmediate(ADDI, rs, rt, offset, CompactBranchType::COMPACT_BRANCH);
1477 } else {
1478 GenInstrImmediate(ADDI, rt, rs, offset, CompactBranchType::COMPACT_BRANCH);
1479 }
1480 }
1481
1482
beqzc(Register rs,int32_t offset)1483 void Assembler::beqzc(Register rs, int32_t offset) {
1484 DCHECK(kArchVariant == kMips64r6);
1485 DCHECK(!(rs.is(zero_reg)));
1486 GenInstrImmediate(POP66, rs, offset, CompactBranchType::COMPACT_BRANCH);
1487 }
1488
1489
bnec(Register rs,Register rt,int16_t offset)1490 void Assembler::bnec(Register rs, Register rt, int16_t offset) {
1491 DCHECK(kArchVariant == kMips64r6);
1492 DCHECK(rs.code() != rt.code() && rs.code() != 0 && rt.code() != 0);
1493 if (rs.code() < rt.code()) {
1494 GenInstrImmediate(DADDI, rs, rt, offset, CompactBranchType::COMPACT_BRANCH);
1495 } else {
1496 GenInstrImmediate(DADDI, rt, rs, offset, CompactBranchType::COMPACT_BRANCH);
1497 }
1498 }
1499
1500
bnezc(Register rs,int32_t offset)1501 void Assembler::bnezc(Register rs, int32_t offset) {
1502 DCHECK(kArchVariant == kMips64r6);
1503 DCHECK(!(rs.is(zero_reg)));
1504 GenInstrImmediate(POP76, rs, offset, CompactBranchType::COMPACT_BRANCH);
1505 }
1506
1507
j(int64_t target)1508 void Assembler::j(int64_t target) {
1509 BlockTrampolinePoolScope block_trampoline_pool(this);
1510 GenInstrJump(J, static_cast<uint32_t>(target >> 2) & kImm26Mask);
1511 BlockTrampolinePoolFor(1); // For associated delay slot.
1512 }
1513
1514
j(Label * target)1515 void Assembler::j(Label* target) {
1516 uint64_t imm = jump_offset(target);
1517 if (target->is_bound()) {
1518 BlockTrampolinePoolScope block_trampoline_pool(this);
1519 GenInstrJump(static_cast<Opcode>(kJRawMark),
1520 static_cast<uint32_t>(imm >> 2) & kImm26Mask);
1521 BlockTrampolinePoolFor(1); // For associated delay slot.
1522 } else {
1523 j(imm);
1524 }
1525 }
1526
1527
jal(Label * target)1528 void Assembler::jal(Label* target) {
1529 uint64_t imm = jump_offset(target);
1530 if (target->is_bound()) {
1531 BlockTrampolinePoolScope block_trampoline_pool(this);
1532 GenInstrJump(static_cast<Opcode>(kJalRawMark),
1533 static_cast<uint32_t>(imm >> 2) & kImm26Mask);
1534 BlockTrampolinePoolFor(1); // For associated delay slot.
1535 } else {
1536 jal(imm);
1537 }
1538 }
1539
1540
jr(Register rs)1541 void Assembler::jr(Register rs) {
1542 if (kArchVariant != kMips64r6) {
1543 BlockTrampolinePoolScope block_trampoline_pool(this);
1544 GenInstrRegister(SPECIAL, rs, zero_reg, zero_reg, 0, JR);
1545 BlockTrampolinePoolFor(1); // For associated delay slot.
1546 } else {
1547 jalr(rs, zero_reg);
1548 }
1549 }
1550
1551
jal(int64_t target)1552 void Assembler::jal(int64_t target) {
1553 BlockTrampolinePoolScope block_trampoline_pool(this);
1554 GenInstrJump(JAL, static_cast<uint32_t>(target >> 2) & kImm26Mask);
1555 BlockTrampolinePoolFor(1); // For associated delay slot.
1556 }
1557
1558
jalr(Register rs,Register rd)1559 void Assembler::jalr(Register rs, Register rd) {
1560 DCHECK(rs.code() != rd.code());
1561 BlockTrampolinePoolScope block_trampoline_pool(this);
1562 GenInstrRegister(SPECIAL, rs, zero_reg, rd, 0, JALR);
1563 BlockTrampolinePoolFor(1); // For associated delay slot.
1564 }
1565
1566
jic(Register rt,int16_t offset)1567 void Assembler::jic(Register rt, int16_t offset) {
1568 DCHECK(kArchVariant == kMips64r6);
1569 GenInstrImmediate(POP66, zero_reg, rt, offset);
1570 }
1571
1572
jialc(Register rt,int16_t offset)1573 void Assembler::jialc(Register rt, int16_t offset) {
1574 DCHECK(kArchVariant == kMips64r6);
1575 GenInstrImmediate(POP76, zero_reg, rt, offset);
1576 }
1577
1578
1579 // -------Data-processing-instructions---------
1580
1581 // Arithmetic.
1582
addu(Register rd,Register rs,Register rt)1583 void Assembler::addu(Register rd, Register rs, Register rt) {
1584 GenInstrRegister(SPECIAL, rs, rt, rd, 0, ADDU);
1585 }
1586
1587
addiu(Register rd,Register rs,int32_t j)1588 void Assembler::addiu(Register rd, Register rs, int32_t j) {
1589 GenInstrImmediate(ADDIU, rs, rd, j);
1590 }
1591
1592
subu(Register rd,Register rs,Register rt)1593 void Assembler::subu(Register rd, Register rs, Register rt) {
1594 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SUBU);
1595 }
1596
1597
mul(Register rd,Register rs,Register rt)1598 void Assembler::mul(Register rd, Register rs, Register rt) {
1599 if (kArchVariant == kMips64r6) {
1600 GenInstrRegister(SPECIAL, rs, rt, rd, MUL_OP, MUL_MUH);
1601 } else {
1602 GenInstrRegister(SPECIAL2, rs, rt, rd, 0, MUL);
1603 }
1604 }
1605
1606
muh(Register rd,Register rs,Register rt)1607 void Assembler::muh(Register rd, Register rs, Register rt) {
1608 DCHECK(kArchVariant == kMips64r6);
1609 GenInstrRegister(SPECIAL, rs, rt, rd, MUH_OP, MUL_MUH);
1610 }
1611
1612
mulu(Register rd,Register rs,Register rt)1613 void Assembler::mulu(Register rd, Register rs, Register rt) {
1614 DCHECK(kArchVariant == kMips64r6);
1615 GenInstrRegister(SPECIAL, rs, rt, rd, MUL_OP, MUL_MUH_U);
1616 }
1617
1618
muhu(Register rd,Register rs,Register rt)1619 void Assembler::muhu(Register rd, Register rs, Register rt) {
1620 DCHECK(kArchVariant == kMips64r6);
1621 GenInstrRegister(SPECIAL, rs, rt, rd, MUH_OP, MUL_MUH_U);
1622 }
1623
1624
dmul(Register rd,Register rs,Register rt)1625 void Assembler::dmul(Register rd, Register rs, Register rt) {
1626 DCHECK(kArchVariant == kMips64r6);
1627 GenInstrRegister(SPECIAL, rs, rt, rd, MUL_OP, D_MUL_MUH);
1628 }
1629
1630
dmuh(Register rd,Register rs,Register rt)1631 void Assembler::dmuh(Register rd, Register rs, Register rt) {
1632 DCHECK(kArchVariant == kMips64r6);
1633 GenInstrRegister(SPECIAL, rs, rt, rd, MUH_OP, D_MUL_MUH);
1634 }
1635
1636
dmulu(Register rd,Register rs,Register rt)1637 void Assembler::dmulu(Register rd, Register rs, Register rt) {
1638 DCHECK(kArchVariant == kMips64r6);
1639 GenInstrRegister(SPECIAL, rs, rt, rd, MUL_OP, D_MUL_MUH_U);
1640 }
1641
1642
dmuhu(Register rd,Register rs,Register rt)1643 void Assembler::dmuhu(Register rd, Register rs, Register rt) {
1644 DCHECK(kArchVariant == kMips64r6);
1645 GenInstrRegister(SPECIAL, rs, rt, rd, MUH_OP, D_MUL_MUH_U);
1646 }
1647
1648
mult(Register rs,Register rt)1649 void Assembler::mult(Register rs, Register rt) {
1650 DCHECK(kArchVariant != kMips64r6);
1651 GenInstrRegister(SPECIAL, rs, rt, zero_reg, 0, MULT);
1652 }
1653
1654
multu(Register rs,Register rt)1655 void Assembler::multu(Register rs, Register rt) {
1656 DCHECK(kArchVariant != kMips64r6);
1657 GenInstrRegister(SPECIAL, rs, rt, zero_reg, 0, MULTU);
1658 }
1659
1660
daddiu(Register rd,Register rs,int32_t j)1661 void Assembler::daddiu(Register rd, Register rs, int32_t j) {
1662 GenInstrImmediate(DADDIU, rs, rd, j);
1663 }
1664
1665
div(Register rs,Register rt)1666 void Assembler::div(Register rs, Register rt) {
1667 GenInstrRegister(SPECIAL, rs, rt, zero_reg, 0, DIV);
1668 }
1669
1670
div(Register rd,Register rs,Register rt)1671 void Assembler::div(Register rd, Register rs, Register rt) {
1672 DCHECK(kArchVariant == kMips64r6);
1673 GenInstrRegister(SPECIAL, rs, rt, rd, DIV_OP, DIV_MOD);
1674 }
1675
1676
mod(Register rd,Register rs,Register rt)1677 void Assembler::mod(Register rd, Register rs, Register rt) {
1678 DCHECK(kArchVariant == kMips64r6);
1679 GenInstrRegister(SPECIAL, rs, rt, rd, MOD_OP, DIV_MOD);
1680 }
1681
1682
divu(Register rs,Register rt)1683 void Assembler::divu(Register rs, Register rt) {
1684 GenInstrRegister(SPECIAL, rs, rt, zero_reg, 0, DIVU);
1685 }
1686
1687
divu(Register rd,Register rs,Register rt)1688 void Assembler::divu(Register rd, Register rs, Register rt) {
1689 DCHECK(kArchVariant == kMips64r6);
1690 GenInstrRegister(SPECIAL, rs, rt, rd, DIV_OP, DIV_MOD_U);
1691 }
1692
1693
modu(Register rd,Register rs,Register rt)1694 void Assembler::modu(Register rd, Register rs, Register rt) {
1695 DCHECK(kArchVariant == kMips64r6);
1696 GenInstrRegister(SPECIAL, rs, rt, rd, MOD_OP, DIV_MOD_U);
1697 }
1698
1699
daddu(Register rd,Register rs,Register rt)1700 void Assembler::daddu(Register rd, Register rs, Register rt) {
1701 GenInstrRegister(SPECIAL, rs, rt, rd, 0, DADDU);
1702 }
1703
1704
dsubu(Register rd,Register rs,Register rt)1705 void Assembler::dsubu(Register rd, Register rs, Register rt) {
1706 GenInstrRegister(SPECIAL, rs, rt, rd, 0, DSUBU);
1707 }
1708
1709
dmult(Register rs,Register rt)1710 void Assembler::dmult(Register rs, Register rt) {
1711 GenInstrRegister(SPECIAL, rs, rt, zero_reg, 0, DMULT);
1712 }
1713
1714
dmultu(Register rs,Register rt)1715 void Assembler::dmultu(Register rs, Register rt) {
1716 GenInstrRegister(SPECIAL, rs, rt, zero_reg, 0, DMULTU);
1717 }
1718
1719
ddiv(Register rs,Register rt)1720 void Assembler::ddiv(Register rs, Register rt) {
1721 GenInstrRegister(SPECIAL, rs, rt, zero_reg, 0, DDIV);
1722 }
1723
1724
ddiv(Register rd,Register rs,Register rt)1725 void Assembler::ddiv(Register rd, Register rs, Register rt) {
1726 DCHECK(kArchVariant == kMips64r6);
1727 GenInstrRegister(SPECIAL, rs, rt, rd, DIV_OP, D_DIV_MOD);
1728 }
1729
1730
dmod(Register rd,Register rs,Register rt)1731 void Assembler::dmod(Register rd, Register rs, Register rt) {
1732 DCHECK(kArchVariant == kMips64r6);
1733 GenInstrRegister(SPECIAL, rs, rt, rd, MOD_OP, D_DIV_MOD);
1734 }
1735
1736
ddivu(Register rs,Register rt)1737 void Assembler::ddivu(Register rs, Register rt) {
1738 GenInstrRegister(SPECIAL, rs, rt, zero_reg, 0, DDIVU);
1739 }
1740
1741
ddivu(Register rd,Register rs,Register rt)1742 void Assembler::ddivu(Register rd, Register rs, Register rt) {
1743 DCHECK(kArchVariant == kMips64r6);
1744 GenInstrRegister(SPECIAL, rs, rt, rd, DIV_OP, D_DIV_MOD_U);
1745 }
1746
1747
dmodu(Register rd,Register rs,Register rt)1748 void Assembler::dmodu(Register rd, Register rs, Register rt) {
1749 DCHECK(kArchVariant == kMips64r6);
1750 GenInstrRegister(SPECIAL, rs, rt, rd, MOD_OP, D_DIV_MOD_U);
1751 }
1752
1753
1754 // Logical.
1755
and_(Register rd,Register rs,Register rt)1756 void Assembler::and_(Register rd, Register rs, Register rt) {
1757 GenInstrRegister(SPECIAL, rs, rt, rd, 0, AND);
1758 }
1759
1760
andi(Register rt,Register rs,int32_t j)1761 void Assembler::andi(Register rt, Register rs, int32_t j) {
1762 DCHECK(is_uint16(j));
1763 GenInstrImmediate(ANDI, rs, rt, j);
1764 }
1765
1766
or_(Register rd,Register rs,Register rt)1767 void Assembler::or_(Register rd, Register rs, Register rt) {
1768 GenInstrRegister(SPECIAL, rs, rt, rd, 0, OR);
1769 }
1770
1771
ori(Register rt,Register rs,int32_t j)1772 void Assembler::ori(Register rt, Register rs, int32_t j) {
1773 DCHECK(is_uint16(j));
1774 GenInstrImmediate(ORI, rs, rt, j);
1775 }
1776
1777
xor_(Register rd,Register rs,Register rt)1778 void Assembler::xor_(Register rd, Register rs, Register rt) {
1779 GenInstrRegister(SPECIAL, rs, rt, rd, 0, XOR);
1780 }
1781
1782
xori(Register rt,Register rs,int32_t j)1783 void Assembler::xori(Register rt, Register rs, int32_t j) {
1784 DCHECK(is_uint16(j));
1785 GenInstrImmediate(XORI, rs, rt, j);
1786 }
1787
1788
nor(Register rd,Register rs,Register rt)1789 void Assembler::nor(Register rd, Register rs, Register rt) {
1790 GenInstrRegister(SPECIAL, rs, rt, rd, 0, NOR);
1791 }
1792
1793
1794 // Shifts.
sll(Register rd,Register rt,uint16_t sa,bool coming_from_nop)1795 void Assembler::sll(Register rd,
1796 Register rt,
1797 uint16_t sa,
1798 bool coming_from_nop) {
1799 // Don't allow nop instructions in the form sll zero_reg, zero_reg to be
1800 // generated using the sll instruction. They must be generated using
1801 // nop(int/NopMarkerTypes) or MarkCode(int/NopMarkerTypes) pseudo
1802 // instructions.
1803 DCHECK(coming_from_nop || !(rd.is(zero_reg) && rt.is(zero_reg)));
1804 GenInstrRegister(SPECIAL, zero_reg, rt, rd, sa & 0x1F, SLL);
1805 }
1806
1807
sllv(Register rd,Register rt,Register rs)1808 void Assembler::sllv(Register rd, Register rt, Register rs) {
1809 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SLLV);
1810 }
1811
1812
srl(Register rd,Register rt,uint16_t sa)1813 void Assembler::srl(Register rd, Register rt, uint16_t sa) {
1814 GenInstrRegister(SPECIAL, zero_reg, rt, rd, sa & 0x1F, SRL);
1815 }
1816
1817
srlv(Register rd,Register rt,Register rs)1818 void Assembler::srlv(Register rd, Register rt, Register rs) {
1819 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SRLV);
1820 }
1821
1822
sra(Register rd,Register rt,uint16_t sa)1823 void Assembler::sra(Register rd, Register rt, uint16_t sa) {
1824 GenInstrRegister(SPECIAL, zero_reg, rt, rd, sa & 0x1F, SRA);
1825 }
1826
1827
srav(Register rd,Register rt,Register rs)1828 void Assembler::srav(Register rd, Register rt, Register rs) {
1829 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SRAV);
1830 }
1831
1832
rotr(Register rd,Register rt,uint16_t sa)1833 void Assembler::rotr(Register rd, Register rt, uint16_t sa) {
1834 // Should be called via MacroAssembler::Ror.
1835 DCHECK(rd.is_valid() && rt.is_valid() && is_uint5(sa));
1836 DCHECK(kArchVariant == kMips64r2 || kArchVariant == kMips64r6);
1837 Instr instr = SPECIAL | (1 << kRsShift) | (rt.code() << kRtShift)
1838 | (rd.code() << kRdShift) | (sa << kSaShift) | SRL;
1839 emit(instr);
1840 }
1841
1842
rotrv(Register rd,Register rt,Register rs)1843 void Assembler::rotrv(Register rd, Register rt, Register rs) {
1844 // Should be called via MacroAssembler::Ror.
1845 DCHECK(rd.is_valid() && rt.is_valid() && rs.is_valid());
1846 DCHECK(kArchVariant == kMips64r2 || kArchVariant == kMips64r6);
1847 Instr instr = SPECIAL | (rs.code() << kRsShift) | (rt.code() << kRtShift)
1848 | (rd.code() << kRdShift) | (1 << kSaShift) | SRLV;
1849 emit(instr);
1850 }
1851
1852
dsll(Register rd,Register rt,uint16_t sa)1853 void Assembler::dsll(Register rd, Register rt, uint16_t sa) {
1854 GenInstrRegister(SPECIAL, zero_reg, rt, rd, sa & 0x1F, DSLL);
1855 }
1856
1857
dsllv(Register rd,Register rt,Register rs)1858 void Assembler::dsllv(Register rd, Register rt, Register rs) {
1859 GenInstrRegister(SPECIAL, rs, rt, rd, 0, DSLLV);
1860 }
1861
1862
dsrl(Register rd,Register rt,uint16_t sa)1863 void Assembler::dsrl(Register rd, Register rt, uint16_t sa) {
1864 GenInstrRegister(SPECIAL, zero_reg, rt, rd, sa & 0x1F, DSRL);
1865 }
1866
1867
dsrlv(Register rd,Register rt,Register rs)1868 void Assembler::dsrlv(Register rd, Register rt, Register rs) {
1869 GenInstrRegister(SPECIAL, rs, rt, rd, 0, DSRLV);
1870 }
1871
1872
drotr(Register rd,Register rt,uint16_t sa)1873 void Assembler::drotr(Register rd, Register rt, uint16_t sa) {
1874 DCHECK(rd.is_valid() && rt.is_valid() && is_uint5(sa));
1875 Instr instr = SPECIAL | (1 << kRsShift) | (rt.code() << kRtShift)
1876 | (rd.code() << kRdShift) | (sa << kSaShift) | DSRL;
1877 emit(instr);
1878 }
1879
drotr32(Register rd,Register rt,uint16_t sa)1880 void Assembler::drotr32(Register rd, Register rt, uint16_t sa) {
1881 DCHECK(rd.is_valid() && rt.is_valid() && is_uint5(sa));
1882 Instr instr = SPECIAL | (1 << kRsShift) | (rt.code() << kRtShift) |
1883 (rd.code() << kRdShift) | (sa << kSaShift) | DSRL32;
1884 emit(instr);
1885 }
1886
drotrv(Register rd,Register rt,Register rs)1887 void Assembler::drotrv(Register rd, Register rt, Register rs) {
1888 DCHECK(rd.is_valid() && rt.is_valid() && rs.is_valid() );
1889 Instr instr = SPECIAL | (rs.code() << kRsShift) | (rt.code() << kRtShift)
1890 | (rd.code() << kRdShift) | (1 << kSaShift) | DSRLV;
1891 emit(instr);
1892 }
1893
1894
dsra(Register rd,Register rt,uint16_t sa)1895 void Assembler::dsra(Register rd, Register rt, uint16_t sa) {
1896 GenInstrRegister(SPECIAL, zero_reg, rt, rd, sa & 0x1F, DSRA);
1897 }
1898
1899
dsrav(Register rd,Register rt,Register rs)1900 void Assembler::dsrav(Register rd, Register rt, Register rs) {
1901 GenInstrRegister(SPECIAL, rs, rt, rd, 0, DSRAV);
1902 }
1903
1904
dsll32(Register rd,Register rt,uint16_t sa)1905 void Assembler::dsll32(Register rd, Register rt, uint16_t sa) {
1906 GenInstrRegister(SPECIAL, zero_reg, rt, rd, sa & 0x1F, DSLL32);
1907 }
1908
1909
dsrl32(Register rd,Register rt,uint16_t sa)1910 void Assembler::dsrl32(Register rd, Register rt, uint16_t sa) {
1911 GenInstrRegister(SPECIAL, zero_reg, rt, rd, sa & 0x1F, DSRL32);
1912 }
1913
1914
dsra32(Register rd,Register rt,uint16_t sa)1915 void Assembler::dsra32(Register rd, Register rt, uint16_t sa) {
1916 GenInstrRegister(SPECIAL, zero_reg, rt, rd, sa & 0x1F, DSRA32);
1917 }
1918
1919
lsa(Register rd,Register rt,Register rs,uint8_t sa)1920 void Assembler::lsa(Register rd, Register rt, Register rs, uint8_t sa) {
1921 DCHECK(rd.is_valid() && rt.is_valid() && rs.is_valid());
1922 DCHECK(sa <= 3);
1923 DCHECK(kArchVariant == kMips64r6);
1924 Instr instr = SPECIAL | rs.code() << kRsShift | rt.code() << kRtShift |
1925 rd.code() << kRdShift | sa << kSaShift | LSA;
1926 emit(instr);
1927 }
1928
1929
dlsa(Register rd,Register rt,Register rs,uint8_t sa)1930 void Assembler::dlsa(Register rd, Register rt, Register rs, uint8_t sa) {
1931 DCHECK(rd.is_valid() && rt.is_valid() && rs.is_valid());
1932 DCHECK(sa <= 3);
1933 DCHECK(kArchVariant == kMips64r6);
1934 Instr instr = SPECIAL | rs.code() << kRsShift | rt.code() << kRtShift |
1935 rd.code() << kRdShift | sa << kSaShift | DLSA;
1936 emit(instr);
1937 }
1938
1939
1940 // ------------Memory-instructions-------------
1941
1942 // Helper for base-reg + offset, when offset is larger than int16.
LoadRegPlusOffsetToAt(const MemOperand & src)1943 void Assembler::LoadRegPlusOffsetToAt(const MemOperand& src) {
1944 DCHECK(!src.rm().is(at));
1945 DCHECK(is_int32(src.offset_));
1946 daddiu(at, zero_reg, (src.offset_ >> kLuiShift) & kImm16Mask);
1947 dsll(at, at, kLuiShift);
1948 ori(at, at, src.offset_ & kImm16Mask); // Load 32-bit offset.
1949 daddu(at, at, src.rm()); // Add base register.
1950 }
1951
1952
lb(Register rd,const MemOperand & rs)1953 void Assembler::lb(Register rd, const MemOperand& rs) {
1954 if (is_int16(rs.offset_)) {
1955 GenInstrImmediate(LB, rs.rm(), rd, rs.offset_);
1956 } else { // Offset > 16 bits, use multiple instructions to load.
1957 LoadRegPlusOffsetToAt(rs);
1958 GenInstrImmediate(LB, at, rd, 0); // Equiv to lb(rd, MemOperand(at, 0));
1959 }
1960 }
1961
1962
lbu(Register rd,const MemOperand & rs)1963 void Assembler::lbu(Register rd, const MemOperand& rs) {
1964 if (is_int16(rs.offset_)) {
1965 GenInstrImmediate(LBU, rs.rm(), rd, rs.offset_);
1966 } else { // Offset > 16 bits, use multiple instructions to load.
1967 LoadRegPlusOffsetToAt(rs);
1968 GenInstrImmediate(LBU, at, rd, 0); // Equiv to lbu(rd, MemOperand(at, 0));
1969 }
1970 }
1971
1972
lh(Register rd,const MemOperand & rs)1973 void Assembler::lh(Register rd, const MemOperand& rs) {
1974 if (is_int16(rs.offset_)) {
1975 GenInstrImmediate(LH, rs.rm(), rd, rs.offset_);
1976 } else { // Offset > 16 bits, use multiple instructions to load.
1977 LoadRegPlusOffsetToAt(rs);
1978 GenInstrImmediate(LH, at, rd, 0); // Equiv to lh(rd, MemOperand(at, 0));
1979 }
1980 }
1981
1982
lhu(Register rd,const MemOperand & rs)1983 void Assembler::lhu(Register rd, const MemOperand& rs) {
1984 if (is_int16(rs.offset_)) {
1985 GenInstrImmediate(LHU, rs.rm(), rd, rs.offset_);
1986 } else { // Offset > 16 bits, use multiple instructions to load.
1987 LoadRegPlusOffsetToAt(rs);
1988 GenInstrImmediate(LHU, at, rd, 0); // Equiv to lhu(rd, MemOperand(at, 0));
1989 }
1990 }
1991
1992
lw(Register rd,const MemOperand & rs)1993 void Assembler::lw(Register rd, const MemOperand& rs) {
1994 if (is_int16(rs.offset_)) {
1995 GenInstrImmediate(LW, rs.rm(), rd, rs.offset_);
1996 } else { // Offset > 16 bits, use multiple instructions to load.
1997 LoadRegPlusOffsetToAt(rs);
1998 GenInstrImmediate(LW, at, rd, 0); // Equiv to lw(rd, MemOperand(at, 0));
1999 }
2000 }
2001
2002
lwu(Register rd,const MemOperand & rs)2003 void Assembler::lwu(Register rd, const MemOperand& rs) {
2004 if (is_int16(rs.offset_)) {
2005 GenInstrImmediate(LWU, rs.rm(), rd, rs.offset_);
2006 } else { // Offset > 16 bits, use multiple instructions to load.
2007 LoadRegPlusOffsetToAt(rs);
2008 GenInstrImmediate(LWU, at, rd, 0); // Equiv to lwu(rd, MemOperand(at, 0));
2009 }
2010 }
2011
2012
lwl(Register rd,const MemOperand & rs)2013 void Assembler::lwl(Register rd, const MemOperand& rs) {
2014 DCHECK(is_int16(rs.offset_));
2015 DCHECK(kArchVariant == kMips64r2);
2016 GenInstrImmediate(LWL, rs.rm(), rd, rs.offset_);
2017 }
2018
2019
lwr(Register rd,const MemOperand & rs)2020 void Assembler::lwr(Register rd, const MemOperand& rs) {
2021 DCHECK(is_int16(rs.offset_));
2022 DCHECK(kArchVariant == kMips64r2);
2023 GenInstrImmediate(LWR, rs.rm(), rd, rs.offset_);
2024 }
2025
2026
sb(Register rd,const MemOperand & rs)2027 void Assembler::sb(Register rd, const MemOperand& rs) {
2028 if (is_int16(rs.offset_)) {
2029 GenInstrImmediate(SB, rs.rm(), rd, rs.offset_);
2030 } else { // Offset > 16 bits, use multiple instructions to store.
2031 LoadRegPlusOffsetToAt(rs);
2032 GenInstrImmediate(SB, at, rd, 0); // Equiv to sb(rd, MemOperand(at, 0));
2033 }
2034 }
2035
2036
sh(Register rd,const MemOperand & rs)2037 void Assembler::sh(Register rd, const MemOperand& rs) {
2038 if (is_int16(rs.offset_)) {
2039 GenInstrImmediate(SH, rs.rm(), rd, rs.offset_);
2040 } else { // Offset > 16 bits, use multiple instructions to store.
2041 LoadRegPlusOffsetToAt(rs);
2042 GenInstrImmediate(SH, at, rd, 0); // Equiv to sh(rd, MemOperand(at, 0));
2043 }
2044 }
2045
2046
sw(Register rd,const MemOperand & rs)2047 void Assembler::sw(Register rd, const MemOperand& rs) {
2048 if (is_int16(rs.offset_)) {
2049 GenInstrImmediate(SW, rs.rm(), rd, rs.offset_);
2050 } else { // Offset > 16 bits, use multiple instructions to store.
2051 LoadRegPlusOffsetToAt(rs);
2052 GenInstrImmediate(SW, at, rd, 0); // Equiv to sw(rd, MemOperand(at, 0));
2053 }
2054 }
2055
2056
swl(Register rd,const MemOperand & rs)2057 void Assembler::swl(Register rd, const MemOperand& rs) {
2058 DCHECK(is_int16(rs.offset_));
2059 DCHECK(kArchVariant == kMips64r2);
2060 GenInstrImmediate(SWL, rs.rm(), rd, rs.offset_);
2061 }
2062
2063
swr(Register rd,const MemOperand & rs)2064 void Assembler::swr(Register rd, const MemOperand& rs) {
2065 DCHECK(is_int16(rs.offset_));
2066 DCHECK(kArchVariant == kMips64r2);
2067 GenInstrImmediate(SWR, rs.rm(), rd, rs.offset_);
2068 }
2069
2070
lui(Register rd,int32_t j)2071 void Assembler::lui(Register rd, int32_t j) {
2072 DCHECK(is_uint16(j));
2073 GenInstrImmediate(LUI, zero_reg, rd, j);
2074 }
2075
2076
aui(Register rt,Register rs,int32_t j)2077 void Assembler::aui(Register rt, Register rs, int32_t j) {
2078 // This instruction uses same opcode as 'lui'. The difference in encoding is
2079 // 'lui' has zero reg. for rs field.
2080 DCHECK(is_uint16(j));
2081 GenInstrImmediate(LUI, rs, rt, j);
2082 }
2083
2084
daui(Register rt,Register rs,int32_t j)2085 void Assembler::daui(Register rt, Register rs, int32_t j) {
2086 DCHECK(is_uint16(j));
2087 DCHECK(!rs.is(zero_reg));
2088 GenInstrImmediate(DAUI, rs, rt, j);
2089 }
2090
2091
dahi(Register rs,int32_t j)2092 void Assembler::dahi(Register rs, int32_t j) {
2093 DCHECK(is_uint16(j));
2094 GenInstrImmediate(REGIMM, rs, DAHI, j);
2095 }
2096
2097
dati(Register rs,int32_t j)2098 void Assembler::dati(Register rs, int32_t j) {
2099 DCHECK(is_uint16(j));
2100 GenInstrImmediate(REGIMM, rs, DATI, j);
2101 }
2102
2103
ldl(Register rd,const MemOperand & rs)2104 void Assembler::ldl(Register rd, const MemOperand& rs) {
2105 DCHECK(is_int16(rs.offset_));
2106 DCHECK(kArchVariant == kMips64r2);
2107 GenInstrImmediate(LDL, rs.rm(), rd, rs.offset_);
2108 }
2109
2110
ldr(Register rd,const MemOperand & rs)2111 void Assembler::ldr(Register rd, const MemOperand& rs) {
2112 DCHECK(is_int16(rs.offset_));
2113 DCHECK(kArchVariant == kMips64r2);
2114 GenInstrImmediate(LDR, rs.rm(), rd, rs.offset_);
2115 }
2116
2117
sdl(Register rd,const MemOperand & rs)2118 void Assembler::sdl(Register rd, const MemOperand& rs) {
2119 DCHECK(is_int16(rs.offset_));
2120 DCHECK(kArchVariant == kMips64r2);
2121 GenInstrImmediate(SDL, rs.rm(), rd, rs.offset_);
2122 }
2123
2124
sdr(Register rd,const MemOperand & rs)2125 void Assembler::sdr(Register rd, const MemOperand& rs) {
2126 DCHECK(is_int16(rs.offset_));
2127 DCHECK(kArchVariant == kMips64r2);
2128 GenInstrImmediate(SDR, rs.rm(), rd, rs.offset_);
2129 }
2130
2131
ld(Register rd,const MemOperand & rs)2132 void Assembler::ld(Register rd, const MemOperand& rs) {
2133 if (is_int16(rs.offset_)) {
2134 GenInstrImmediate(LD, rs.rm(), rd, rs.offset_);
2135 } else { // Offset > 16 bits, use multiple instructions to load.
2136 LoadRegPlusOffsetToAt(rs);
2137 GenInstrImmediate(LD, at, rd, 0); // Equiv to lw(rd, MemOperand(at, 0));
2138 }
2139 }
2140
2141
sd(Register rd,const MemOperand & rs)2142 void Assembler::sd(Register rd, const MemOperand& rs) {
2143 if (is_int16(rs.offset_)) {
2144 GenInstrImmediate(SD, rs.rm(), rd, rs.offset_);
2145 } else { // Offset > 16 bits, use multiple instructions to store.
2146 LoadRegPlusOffsetToAt(rs);
2147 GenInstrImmediate(SD, at, rd, 0); // Equiv to sw(rd, MemOperand(at, 0));
2148 }
2149 }
2150
2151
2152 // ---------PC-Relative instructions-----------
2153
addiupc(Register rs,int32_t imm19)2154 void Assembler::addiupc(Register rs, int32_t imm19) {
2155 DCHECK(kArchVariant == kMips64r6);
2156 DCHECK(rs.is_valid() && is_int19(imm19));
2157 uint32_t imm21 = ADDIUPC << kImm19Bits | (imm19 & kImm19Mask);
2158 GenInstrImmediate(PCREL, rs, imm21);
2159 }
2160
2161
lwpc(Register rs,int32_t offset19)2162 void Assembler::lwpc(Register rs, int32_t offset19) {
2163 DCHECK(kArchVariant == kMips64r6);
2164 DCHECK(rs.is_valid() && is_int19(offset19));
2165 uint32_t imm21 = LWPC << kImm19Bits | (offset19 & kImm19Mask);
2166 GenInstrImmediate(PCREL, rs, imm21);
2167 }
2168
2169
lwupc(Register rs,int32_t offset19)2170 void Assembler::lwupc(Register rs, int32_t offset19) {
2171 DCHECK(kArchVariant == kMips64r6);
2172 DCHECK(rs.is_valid() && is_int19(offset19));
2173 uint32_t imm21 = LWUPC << kImm19Bits | (offset19 & kImm19Mask);
2174 GenInstrImmediate(PCREL, rs, imm21);
2175 }
2176
2177
ldpc(Register rs,int32_t offset18)2178 void Assembler::ldpc(Register rs, int32_t offset18) {
2179 DCHECK(kArchVariant == kMips64r6);
2180 DCHECK(rs.is_valid() && is_int18(offset18));
2181 uint32_t imm21 = LDPC << kImm18Bits | (offset18 & kImm18Mask);
2182 GenInstrImmediate(PCREL, rs, imm21);
2183 }
2184
2185
auipc(Register rs,int16_t imm16)2186 void Assembler::auipc(Register rs, int16_t imm16) {
2187 DCHECK(kArchVariant == kMips64r6);
2188 DCHECK(rs.is_valid());
2189 uint32_t imm21 = AUIPC << kImm16Bits | (imm16 & kImm16Mask);
2190 GenInstrImmediate(PCREL, rs, imm21);
2191 }
2192
2193
aluipc(Register rs,int16_t imm16)2194 void Assembler::aluipc(Register rs, int16_t imm16) {
2195 DCHECK(kArchVariant == kMips64r6);
2196 DCHECK(rs.is_valid());
2197 uint32_t imm21 = ALUIPC << kImm16Bits | (imm16 & kImm16Mask);
2198 GenInstrImmediate(PCREL, rs, imm21);
2199 }
2200
2201
2202 // -------------Misc-instructions--------------
2203
2204 // Break / Trap instructions.
break_(uint32_t code,bool break_as_stop)2205 void Assembler::break_(uint32_t code, bool break_as_stop) {
2206 DCHECK((code & ~0xfffff) == 0);
2207 // We need to invalidate breaks that could be stops as well because the
2208 // simulator expects a char pointer after the stop instruction.
2209 // See constants-mips.h for explanation.
2210 DCHECK((break_as_stop &&
2211 code <= kMaxStopCode &&
2212 code > kMaxWatchpointCode) ||
2213 (!break_as_stop &&
2214 (code > kMaxStopCode ||
2215 code <= kMaxWatchpointCode)));
2216 Instr break_instr = SPECIAL | BREAK | (code << 6);
2217 emit(break_instr);
2218 }
2219
2220
stop(const char * msg,uint32_t code)2221 void Assembler::stop(const char* msg, uint32_t code) {
2222 DCHECK(code > kMaxWatchpointCode);
2223 DCHECK(code <= kMaxStopCode);
2224 #if defined(V8_HOST_ARCH_MIPS) || defined(V8_HOST_ARCH_MIPS64)
2225 break_(0x54321);
2226 #else // V8_HOST_ARCH_MIPS
2227 BlockTrampolinePoolFor(3);
2228 // The Simulator will handle the stop instruction and get the message address.
2229 // On MIPS stop() is just a special kind of break_().
2230 break_(code, true);
2231 emit(reinterpret_cast<uint64_t>(msg));
2232 #endif
2233 }
2234
2235
tge(Register rs,Register rt,uint16_t code)2236 void Assembler::tge(Register rs, Register rt, uint16_t code) {
2237 DCHECK(is_uint10(code));
2238 Instr instr = SPECIAL | TGE | rs.code() << kRsShift
2239 | rt.code() << kRtShift | code << 6;
2240 emit(instr);
2241 }
2242
2243
tgeu(Register rs,Register rt,uint16_t code)2244 void Assembler::tgeu(Register rs, Register rt, uint16_t code) {
2245 DCHECK(is_uint10(code));
2246 Instr instr = SPECIAL | TGEU | rs.code() << kRsShift
2247 | rt.code() << kRtShift | code << 6;
2248 emit(instr);
2249 }
2250
2251
tlt(Register rs,Register rt,uint16_t code)2252 void Assembler::tlt(Register rs, Register rt, uint16_t code) {
2253 DCHECK(is_uint10(code));
2254 Instr instr =
2255 SPECIAL | TLT | rs.code() << kRsShift | rt.code() << kRtShift | code << 6;
2256 emit(instr);
2257 }
2258
2259
tltu(Register rs,Register rt,uint16_t code)2260 void Assembler::tltu(Register rs, Register rt, uint16_t code) {
2261 DCHECK(is_uint10(code));
2262 Instr instr =
2263 SPECIAL | TLTU | rs.code() << kRsShift
2264 | rt.code() << kRtShift | code << 6;
2265 emit(instr);
2266 }
2267
2268
teq(Register rs,Register rt,uint16_t code)2269 void Assembler::teq(Register rs, Register rt, uint16_t code) {
2270 DCHECK(is_uint10(code));
2271 Instr instr =
2272 SPECIAL | TEQ | rs.code() << kRsShift | rt.code() << kRtShift | code << 6;
2273 emit(instr);
2274 }
2275
2276
tne(Register rs,Register rt,uint16_t code)2277 void Assembler::tne(Register rs, Register rt, uint16_t code) {
2278 DCHECK(is_uint10(code));
2279 Instr instr =
2280 SPECIAL | TNE | rs.code() << kRsShift | rt.code() << kRtShift | code << 6;
2281 emit(instr);
2282 }
2283
sync()2284 void Assembler::sync() {
2285 Instr sync_instr = SPECIAL | SYNC;
2286 emit(sync_instr);
2287 }
2288
2289 // Move from HI/LO register.
2290
mfhi(Register rd)2291 void Assembler::mfhi(Register rd) {
2292 GenInstrRegister(SPECIAL, zero_reg, zero_reg, rd, 0, MFHI);
2293 }
2294
2295
mflo(Register rd)2296 void Assembler::mflo(Register rd) {
2297 GenInstrRegister(SPECIAL, zero_reg, zero_reg, rd, 0, MFLO);
2298 }
2299
2300
2301 // Set on less than instructions.
slt(Register rd,Register rs,Register rt)2302 void Assembler::slt(Register rd, Register rs, Register rt) {
2303 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SLT);
2304 }
2305
2306
sltu(Register rd,Register rs,Register rt)2307 void Assembler::sltu(Register rd, Register rs, Register rt) {
2308 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SLTU);
2309 }
2310
2311
slti(Register rt,Register rs,int32_t j)2312 void Assembler::slti(Register rt, Register rs, int32_t j) {
2313 GenInstrImmediate(SLTI, rs, rt, j);
2314 }
2315
2316
sltiu(Register rt,Register rs,int32_t j)2317 void Assembler::sltiu(Register rt, Register rs, int32_t j) {
2318 GenInstrImmediate(SLTIU, rs, rt, j);
2319 }
2320
2321
2322 // Conditional move.
movz(Register rd,Register rs,Register rt)2323 void Assembler::movz(Register rd, Register rs, Register rt) {
2324 GenInstrRegister(SPECIAL, rs, rt, rd, 0, MOVZ);
2325 }
2326
2327
movn(Register rd,Register rs,Register rt)2328 void Assembler::movn(Register rd, Register rs, Register rt) {
2329 GenInstrRegister(SPECIAL, rs, rt, rd, 0, MOVN);
2330 }
2331
2332
movt(Register rd,Register rs,uint16_t cc)2333 void Assembler::movt(Register rd, Register rs, uint16_t cc) {
2334 Register rt;
2335 rt.reg_code = (cc & 0x0007) << 2 | 1;
2336 GenInstrRegister(SPECIAL, rs, rt, rd, 0, MOVCI);
2337 }
2338
2339
movf(Register rd,Register rs,uint16_t cc)2340 void Assembler::movf(Register rd, Register rs, uint16_t cc) {
2341 Register rt;
2342 rt.reg_code = (cc & 0x0007) << 2 | 0;
2343 GenInstrRegister(SPECIAL, rs, rt, rd, 0, MOVCI);
2344 }
2345
2346
min_s(FPURegister fd,FPURegister fs,FPURegister ft)2347 void Assembler::min_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2348 min(S, fd, fs, ft);
2349 }
2350
2351
min_d(FPURegister fd,FPURegister fs,FPURegister ft)2352 void Assembler::min_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2353 min(D, fd, fs, ft);
2354 }
2355
2356
max_s(FPURegister fd,FPURegister fs,FPURegister ft)2357 void Assembler::max_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2358 max(S, fd, fs, ft);
2359 }
2360
2361
max_d(FPURegister fd,FPURegister fs,FPURegister ft)2362 void Assembler::max_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2363 max(D, fd, fs, ft);
2364 }
2365
2366
mina_s(FPURegister fd,FPURegister fs,FPURegister ft)2367 void Assembler::mina_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2368 mina(S, fd, fs, ft);
2369 }
2370
2371
mina_d(FPURegister fd,FPURegister fs,FPURegister ft)2372 void Assembler::mina_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2373 mina(D, fd, fs, ft);
2374 }
2375
2376
maxa_s(FPURegister fd,FPURegister fs,FPURegister ft)2377 void Assembler::maxa_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2378 maxa(S, fd, fs, ft);
2379 }
2380
2381
maxa_d(FPURegister fd,FPURegister fs,FPURegister ft)2382 void Assembler::maxa_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2383 maxa(D, fd, fs, ft);
2384 }
2385
2386
max(SecondaryField fmt,FPURegister fd,FPURegister fs,FPURegister ft)2387 void Assembler::max(SecondaryField fmt, FPURegister fd, FPURegister fs,
2388 FPURegister ft) {
2389 DCHECK(kArchVariant == kMips64r6);
2390 DCHECK((fmt == D) || (fmt == S));
2391 GenInstrRegister(COP1, fmt, ft, fs, fd, MAX);
2392 }
2393
2394
min(SecondaryField fmt,FPURegister fd,FPURegister fs,FPURegister ft)2395 void Assembler::min(SecondaryField fmt, FPURegister fd, FPURegister fs,
2396 FPURegister ft) {
2397 DCHECK(kArchVariant == kMips64r6);
2398 DCHECK((fmt == D) || (fmt == S));
2399 GenInstrRegister(COP1, fmt, ft, fs, fd, MIN);
2400 }
2401
2402
2403 // GPR.
seleqz(Register rd,Register rs,Register rt)2404 void Assembler::seleqz(Register rd, Register rs, Register rt) {
2405 DCHECK(kArchVariant == kMips64r6);
2406 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SELEQZ_S);
2407 }
2408
2409
2410 // GPR.
selnez(Register rd,Register rs,Register rt)2411 void Assembler::selnez(Register rd, Register rs, Register rt) {
2412 DCHECK(kArchVariant == kMips64r6);
2413 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SELNEZ_S);
2414 }
2415
2416
2417 // Bit twiddling.
clz(Register rd,Register rs)2418 void Assembler::clz(Register rd, Register rs) {
2419 if (kArchVariant != kMips64r6) {
2420 // Clz instr requires same GPR number in 'rd' and 'rt' fields.
2421 GenInstrRegister(SPECIAL2, rs, rd, rd, 0, CLZ);
2422 } else {
2423 GenInstrRegister(SPECIAL, rs, zero_reg, rd, 1, CLZ_R6);
2424 }
2425 }
2426
2427
dclz(Register rd,Register rs)2428 void Assembler::dclz(Register rd, Register rs) {
2429 if (kArchVariant != kMips64r6) {
2430 // dclz instr requires same GPR number in 'rd' and 'rt' fields.
2431 GenInstrRegister(SPECIAL2, rs, rd, rd, 0, DCLZ);
2432 } else {
2433 GenInstrRegister(SPECIAL, rs, zero_reg, rd, 1, DCLZ_R6);
2434 }
2435 }
2436
2437
ins_(Register rt,Register rs,uint16_t pos,uint16_t size)2438 void Assembler::ins_(Register rt, Register rs, uint16_t pos, uint16_t size) {
2439 // Should be called via MacroAssembler::Ins.
2440 // Ins instr has 'rt' field as dest, and two uint5: msb, lsb.
2441 DCHECK((kArchVariant == kMips64r2) || (kArchVariant == kMips64r6));
2442 GenInstrRegister(SPECIAL3, rs, rt, pos + size - 1, pos, INS);
2443 }
2444
2445
dins_(Register rt,Register rs,uint16_t pos,uint16_t size)2446 void Assembler::dins_(Register rt, Register rs, uint16_t pos, uint16_t size) {
2447 // Should be called via MacroAssembler::Dins.
2448 // Dext instr has 'rt' field as dest, and two uint5: msb, lsb.
2449 DCHECK(kArchVariant == kMips64r2 || kArchVariant == kMips64r6);
2450 GenInstrRegister(SPECIAL3, rs, rt, pos + size - 1, pos, DINS);
2451 }
2452
2453
ext_(Register rt,Register rs,uint16_t pos,uint16_t size)2454 void Assembler::ext_(Register rt, Register rs, uint16_t pos, uint16_t size) {
2455 // Should be called via MacroAssembler::Ext.
2456 // Ext instr has 'rt' field as dest, and two uint5: msb, lsb.
2457 DCHECK(kArchVariant == kMips64r2 || kArchVariant == kMips64r6);
2458 GenInstrRegister(SPECIAL3, rs, rt, size - 1, pos, EXT);
2459 }
2460
2461
dext_(Register rt,Register rs,uint16_t pos,uint16_t size)2462 void Assembler::dext_(Register rt, Register rs, uint16_t pos, uint16_t size) {
2463 // Should be called via MacroAssembler::Dext.
2464 // Dext instr has 'rt' field as dest, and two uint5: msb, lsb.
2465 DCHECK(kArchVariant == kMips64r2 || kArchVariant == kMips64r6);
2466 GenInstrRegister(SPECIAL3, rs, rt, size - 1, pos, DEXT);
2467 }
2468
2469
dextm(Register rt,Register rs,uint16_t pos,uint16_t size)2470 void Assembler::dextm(Register rt, Register rs, uint16_t pos, uint16_t size) {
2471 // Should be called via MacroAssembler::Dextm.
2472 // Dextm instr has 'rt' field as dest, and two uint5: msb, lsb.
2473 DCHECK(kArchVariant == kMips64r2 || kArchVariant == kMips64r6);
2474 GenInstrRegister(SPECIAL3, rs, rt, size - 1 - 32, pos, DEXTM);
2475 }
2476
2477
dextu(Register rt,Register rs,uint16_t pos,uint16_t size)2478 void Assembler::dextu(Register rt, Register rs, uint16_t pos, uint16_t size) {
2479 // Should be called via MacroAssembler::Dextu.
2480 // Dext instr has 'rt' field as dest, and two uint5: msb, lsb.
2481 DCHECK(kArchVariant == kMips64r2 || kArchVariant == kMips64r6);
2482 GenInstrRegister(SPECIAL3, rs, rt, size - 1, pos - 32, DEXTU);
2483 }
2484
2485
bitswap(Register rd,Register rt)2486 void Assembler::bitswap(Register rd, Register rt) {
2487 DCHECK(kArchVariant == kMips64r6);
2488 GenInstrRegister(SPECIAL3, zero_reg, rt, rd, 0, BSHFL);
2489 }
2490
2491
dbitswap(Register rd,Register rt)2492 void Assembler::dbitswap(Register rd, Register rt) {
2493 DCHECK(kArchVariant == kMips64r6);
2494 GenInstrRegister(SPECIAL3, zero_reg, rt, rd, 0, DBSHFL);
2495 }
2496
2497
pref(int32_t hint,const MemOperand & rs)2498 void Assembler::pref(int32_t hint, const MemOperand& rs) {
2499 DCHECK(is_uint5(hint) && is_uint16(rs.offset_));
2500 Instr instr = PREF | (rs.rm().code() << kRsShift) | (hint << kRtShift)
2501 | (rs.offset_);
2502 emit(instr);
2503 }
2504
2505
align(Register rd,Register rs,Register rt,uint8_t bp)2506 void Assembler::align(Register rd, Register rs, Register rt, uint8_t bp) {
2507 DCHECK(kArchVariant == kMips64r6);
2508 DCHECK(is_uint3(bp));
2509 uint16_t sa = (ALIGN << kBp2Bits) | bp;
2510 GenInstrRegister(SPECIAL3, rs, rt, rd, sa, BSHFL);
2511 }
2512
2513
dalign(Register rd,Register rs,Register rt,uint8_t bp)2514 void Assembler::dalign(Register rd, Register rs, Register rt, uint8_t bp) {
2515 DCHECK(kArchVariant == kMips64r6);
2516 DCHECK(is_uint3(bp));
2517 uint16_t sa = (DALIGN << kBp3Bits) | bp;
2518 GenInstrRegister(SPECIAL3, rs, rt, rd, sa, DBSHFL);
2519 }
2520
wsbh(Register rd,Register rt)2521 void Assembler::wsbh(Register rd, Register rt) {
2522 DCHECK(kArchVariant == kMips64r2 || kArchVariant == kMips64r6);
2523 GenInstrRegister(SPECIAL3, zero_reg, rt, rd, WSBH, BSHFL);
2524 }
2525
dsbh(Register rd,Register rt)2526 void Assembler::dsbh(Register rd, Register rt) {
2527 DCHECK(kArchVariant == kMips64r2 || kArchVariant == kMips64r6);
2528 GenInstrRegister(SPECIAL3, zero_reg, rt, rd, DSBH, DBSHFL);
2529 }
2530
dshd(Register rd,Register rt)2531 void Assembler::dshd(Register rd, Register rt) {
2532 DCHECK(kArchVariant == kMips64r2 || kArchVariant == kMips64r6);
2533 GenInstrRegister(SPECIAL3, zero_reg, rt, rd, DSHD, DBSHFL);
2534 }
2535
seh(Register rd,Register rt)2536 void Assembler::seh(Register rd, Register rt) {
2537 DCHECK(kArchVariant == kMips64r2 || kArchVariant == kMips64r6);
2538 GenInstrRegister(SPECIAL3, zero_reg, rt, rd, SEH, BSHFL);
2539 }
2540
seb(Register rd,Register rt)2541 void Assembler::seb(Register rd, Register rt) {
2542 DCHECK(kArchVariant == kMips64r2 || kArchVariant == kMips64r6);
2543 GenInstrRegister(SPECIAL3, zero_reg, rt, rd, SEB, BSHFL);
2544 }
2545
2546 // --------Coprocessor-instructions----------------
2547
2548 // Load, store, move.
lwc1(FPURegister fd,const MemOperand & src)2549 void Assembler::lwc1(FPURegister fd, const MemOperand& src) {
2550 if (is_int16(src.offset_)) {
2551 GenInstrImmediate(LWC1, src.rm(), fd, src.offset_);
2552 } else { // Offset > 16 bits, use multiple instructions to load.
2553 LoadRegPlusOffsetToAt(src);
2554 GenInstrImmediate(LWC1, at, fd, 0);
2555 }
2556 }
2557
2558
ldc1(FPURegister fd,const MemOperand & src)2559 void Assembler::ldc1(FPURegister fd, const MemOperand& src) {
2560 if (is_int16(src.offset_)) {
2561 GenInstrImmediate(LDC1, src.rm(), fd, src.offset_);
2562 } else { // Offset > 16 bits, use multiple instructions to load.
2563 LoadRegPlusOffsetToAt(src);
2564 GenInstrImmediate(LDC1, at, fd, 0);
2565 }
2566 }
2567
2568
swc1(FPURegister fd,const MemOperand & src)2569 void Assembler::swc1(FPURegister fd, const MemOperand& src) {
2570 if (is_int16(src.offset_)) {
2571 GenInstrImmediate(SWC1, src.rm(), fd, src.offset_);
2572 } else { // Offset > 16 bits, use multiple instructions to load.
2573 LoadRegPlusOffsetToAt(src);
2574 GenInstrImmediate(SWC1, at, fd, 0);
2575 }
2576 }
2577
2578
sdc1(FPURegister fd,const MemOperand & src)2579 void Assembler::sdc1(FPURegister fd, const MemOperand& src) {
2580 DCHECK(!src.rm().is(at));
2581 if (is_int16(src.offset_)) {
2582 GenInstrImmediate(SDC1, src.rm(), fd, src.offset_);
2583 } else { // Offset > 16 bits, use multiple instructions to load.
2584 LoadRegPlusOffsetToAt(src);
2585 GenInstrImmediate(SDC1, at, fd, 0);
2586 }
2587 }
2588
2589
mtc1(Register rt,FPURegister fs)2590 void Assembler::mtc1(Register rt, FPURegister fs) {
2591 GenInstrRegister(COP1, MTC1, rt, fs, f0);
2592 }
2593
2594
mthc1(Register rt,FPURegister fs)2595 void Assembler::mthc1(Register rt, FPURegister fs) {
2596 GenInstrRegister(COP1, MTHC1, rt, fs, f0);
2597 }
2598
2599
dmtc1(Register rt,FPURegister fs)2600 void Assembler::dmtc1(Register rt, FPURegister fs) {
2601 GenInstrRegister(COP1, DMTC1, rt, fs, f0);
2602 }
2603
2604
mfc1(Register rt,FPURegister fs)2605 void Assembler::mfc1(Register rt, FPURegister fs) {
2606 GenInstrRegister(COP1, MFC1, rt, fs, f0);
2607 }
2608
2609
mfhc1(Register rt,FPURegister fs)2610 void Assembler::mfhc1(Register rt, FPURegister fs) {
2611 GenInstrRegister(COP1, MFHC1, rt, fs, f0);
2612 }
2613
2614
dmfc1(Register rt,FPURegister fs)2615 void Assembler::dmfc1(Register rt, FPURegister fs) {
2616 GenInstrRegister(COP1, DMFC1, rt, fs, f0);
2617 }
2618
2619
ctc1(Register rt,FPUControlRegister fs)2620 void Assembler::ctc1(Register rt, FPUControlRegister fs) {
2621 GenInstrRegister(COP1, CTC1, rt, fs);
2622 }
2623
2624
cfc1(Register rt,FPUControlRegister fs)2625 void Assembler::cfc1(Register rt, FPUControlRegister fs) {
2626 GenInstrRegister(COP1, CFC1, rt, fs);
2627 }
2628
2629
DoubleAsTwoUInt32(double d,uint32_t * lo,uint32_t * hi)2630 void Assembler::DoubleAsTwoUInt32(double d, uint32_t* lo, uint32_t* hi) {
2631 uint64_t i;
2632 memcpy(&i, &d, 8);
2633
2634 *lo = i & 0xffffffff;
2635 *hi = i >> 32;
2636 }
2637
2638
sel(SecondaryField fmt,FPURegister fd,FPURegister fs,FPURegister ft)2639 void Assembler::sel(SecondaryField fmt, FPURegister fd, FPURegister fs,
2640 FPURegister ft) {
2641 DCHECK(kArchVariant == kMips64r6);
2642 DCHECK((fmt == D) || (fmt == S));
2643
2644 GenInstrRegister(COP1, fmt, ft, fs, fd, SEL);
2645 }
2646
2647
sel_s(FPURegister fd,FPURegister fs,FPURegister ft)2648 void Assembler::sel_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2649 sel(S, fd, fs, ft);
2650 }
2651
2652
sel_d(FPURegister fd,FPURegister fs,FPURegister ft)2653 void Assembler::sel_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2654 sel(D, fd, fs, ft);
2655 }
2656
2657
2658 // FPR.
seleqz(SecondaryField fmt,FPURegister fd,FPURegister fs,FPURegister ft)2659 void Assembler::seleqz(SecondaryField fmt, FPURegister fd, FPURegister fs,
2660 FPURegister ft) {
2661 DCHECK((fmt == D) || (fmt == S));
2662 GenInstrRegister(COP1, fmt, ft, fs, fd, SELEQZ_C);
2663 }
2664
2665
seleqz_d(FPURegister fd,FPURegister fs,FPURegister ft)2666 void Assembler::seleqz_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2667 seleqz(D, fd, fs, ft);
2668 }
2669
2670
seleqz_s(FPURegister fd,FPURegister fs,FPURegister ft)2671 void Assembler::seleqz_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2672 seleqz(S, fd, fs, ft);
2673 }
2674
2675
selnez_d(FPURegister fd,FPURegister fs,FPURegister ft)2676 void Assembler::selnez_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2677 selnez(D, fd, fs, ft);
2678 }
2679
2680
selnez_s(FPURegister fd,FPURegister fs,FPURegister ft)2681 void Assembler::selnez_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2682 selnez(S, fd, fs, ft);
2683 }
2684
2685
movz_s(FPURegister fd,FPURegister fs,Register rt)2686 void Assembler::movz_s(FPURegister fd, FPURegister fs, Register rt) {
2687 DCHECK(kArchVariant == kMips64r2);
2688 GenInstrRegister(COP1, S, rt, fs, fd, MOVZ_C);
2689 }
2690
2691
movz_d(FPURegister fd,FPURegister fs,Register rt)2692 void Assembler::movz_d(FPURegister fd, FPURegister fs, Register rt) {
2693 DCHECK(kArchVariant == kMips64r2);
2694 GenInstrRegister(COP1, D, rt, fs, fd, MOVZ_C);
2695 }
2696
2697
movt_s(FPURegister fd,FPURegister fs,uint16_t cc)2698 void Assembler::movt_s(FPURegister fd, FPURegister fs, uint16_t cc) {
2699 DCHECK(kArchVariant == kMips64r2);
2700 FPURegister ft;
2701 ft.reg_code = (cc & 0x0007) << 2 | 1;
2702 GenInstrRegister(COP1, S, ft, fs, fd, MOVF);
2703 }
2704
2705
movt_d(FPURegister fd,FPURegister fs,uint16_t cc)2706 void Assembler::movt_d(FPURegister fd, FPURegister fs, uint16_t cc) {
2707 DCHECK(kArchVariant == kMips64r2);
2708 FPURegister ft;
2709 ft.reg_code = (cc & 0x0007) << 2 | 1;
2710 GenInstrRegister(COP1, D, ft, fs, fd, MOVF);
2711 }
2712
2713
movf_s(FPURegister fd,FPURegister fs,uint16_t cc)2714 void Assembler::movf_s(FPURegister fd, FPURegister fs, uint16_t cc) {
2715 DCHECK(kArchVariant == kMips64r2);
2716 FPURegister ft;
2717 ft.reg_code = (cc & 0x0007) << 2 | 0;
2718 GenInstrRegister(COP1, S, ft, fs, fd, MOVF);
2719 }
2720
2721
movf_d(FPURegister fd,FPURegister fs,uint16_t cc)2722 void Assembler::movf_d(FPURegister fd, FPURegister fs, uint16_t cc) {
2723 DCHECK(kArchVariant == kMips64r2);
2724 FPURegister ft;
2725 ft.reg_code = (cc & 0x0007) << 2 | 0;
2726 GenInstrRegister(COP1, D, ft, fs, fd, MOVF);
2727 }
2728
2729
movn_s(FPURegister fd,FPURegister fs,Register rt)2730 void Assembler::movn_s(FPURegister fd, FPURegister fs, Register rt) {
2731 DCHECK(kArchVariant == kMips64r2);
2732 GenInstrRegister(COP1, S, rt, fs, fd, MOVN_C);
2733 }
2734
2735
movn_d(FPURegister fd,FPURegister fs,Register rt)2736 void Assembler::movn_d(FPURegister fd, FPURegister fs, Register rt) {
2737 DCHECK(kArchVariant == kMips64r2);
2738 GenInstrRegister(COP1, D, rt, fs, fd, MOVN_C);
2739 }
2740
2741
2742 // FPR.
selnez(SecondaryField fmt,FPURegister fd,FPURegister fs,FPURegister ft)2743 void Assembler::selnez(SecondaryField fmt, FPURegister fd, FPURegister fs,
2744 FPURegister ft) {
2745 DCHECK(kArchVariant == kMips64r6);
2746 DCHECK((fmt == D) || (fmt == S));
2747 GenInstrRegister(COP1, fmt, ft, fs, fd, SELNEZ_C);
2748 }
2749
2750
2751 // Arithmetic.
2752
add_s(FPURegister fd,FPURegister fs,FPURegister ft)2753 void Assembler::add_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2754 GenInstrRegister(COP1, S, ft, fs, fd, ADD_D);
2755 }
2756
2757
add_d(FPURegister fd,FPURegister fs,FPURegister ft)2758 void Assembler::add_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2759 GenInstrRegister(COP1, D, ft, fs, fd, ADD_D);
2760 }
2761
2762
sub_s(FPURegister fd,FPURegister fs,FPURegister ft)2763 void Assembler::sub_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2764 GenInstrRegister(COP1, S, ft, fs, fd, SUB_D);
2765 }
2766
2767
sub_d(FPURegister fd,FPURegister fs,FPURegister ft)2768 void Assembler::sub_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2769 GenInstrRegister(COP1, D, ft, fs, fd, SUB_D);
2770 }
2771
2772
mul_s(FPURegister fd,FPURegister fs,FPURegister ft)2773 void Assembler::mul_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2774 GenInstrRegister(COP1, S, ft, fs, fd, MUL_D);
2775 }
2776
2777
mul_d(FPURegister fd,FPURegister fs,FPURegister ft)2778 void Assembler::mul_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2779 GenInstrRegister(COP1, D, ft, fs, fd, MUL_D);
2780 }
2781
2782
madd_d(FPURegister fd,FPURegister fr,FPURegister fs,FPURegister ft)2783 void Assembler::madd_d(FPURegister fd, FPURegister fr, FPURegister fs,
2784 FPURegister ft) {
2785 GenInstrRegister(COP1X, fr, ft, fs, fd, MADD_D);
2786 }
2787
2788
div_s(FPURegister fd,FPURegister fs,FPURegister ft)2789 void Assembler::div_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2790 GenInstrRegister(COP1, S, ft, fs, fd, DIV_D);
2791 }
2792
2793
div_d(FPURegister fd,FPURegister fs,FPURegister ft)2794 void Assembler::div_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2795 GenInstrRegister(COP1, D, ft, fs, fd, DIV_D);
2796 }
2797
2798
abs_s(FPURegister fd,FPURegister fs)2799 void Assembler::abs_s(FPURegister fd, FPURegister fs) {
2800 GenInstrRegister(COP1, S, f0, fs, fd, ABS_D);
2801 }
2802
2803
abs_d(FPURegister fd,FPURegister fs)2804 void Assembler::abs_d(FPURegister fd, FPURegister fs) {
2805 GenInstrRegister(COP1, D, f0, fs, fd, ABS_D);
2806 }
2807
2808
mov_d(FPURegister fd,FPURegister fs)2809 void Assembler::mov_d(FPURegister fd, FPURegister fs) {
2810 GenInstrRegister(COP1, D, f0, fs, fd, MOV_D);
2811 }
2812
2813
mov_s(FPURegister fd,FPURegister fs)2814 void Assembler::mov_s(FPURegister fd, FPURegister fs) {
2815 GenInstrRegister(COP1, S, f0, fs, fd, MOV_S);
2816 }
2817
2818
neg_s(FPURegister fd,FPURegister fs)2819 void Assembler::neg_s(FPURegister fd, FPURegister fs) {
2820 GenInstrRegister(COP1, S, f0, fs, fd, NEG_D);
2821 }
2822
2823
neg_d(FPURegister fd,FPURegister fs)2824 void Assembler::neg_d(FPURegister fd, FPURegister fs) {
2825 GenInstrRegister(COP1, D, f0, fs, fd, NEG_D);
2826 }
2827
2828
sqrt_s(FPURegister fd,FPURegister fs)2829 void Assembler::sqrt_s(FPURegister fd, FPURegister fs) {
2830 GenInstrRegister(COP1, S, f0, fs, fd, SQRT_D);
2831 }
2832
2833
sqrt_d(FPURegister fd,FPURegister fs)2834 void Assembler::sqrt_d(FPURegister fd, FPURegister fs) {
2835 GenInstrRegister(COP1, D, f0, fs, fd, SQRT_D);
2836 }
2837
2838
rsqrt_s(FPURegister fd,FPURegister fs)2839 void Assembler::rsqrt_s(FPURegister fd, FPURegister fs) {
2840 GenInstrRegister(COP1, S, f0, fs, fd, RSQRT_S);
2841 }
2842
2843
rsqrt_d(FPURegister fd,FPURegister fs)2844 void Assembler::rsqrt_d(FPURegister fd, FPURegister fs) {
2845 GenInstrRegister(COP1, D, f0, fs, fd, RSQRT_D);
2846 }
2847
2848
recip_d(FPURegister fd,FPURegister fs)2849 void Assembler::recip_d(FPURegister fd, FPURegister fs) {
2850 GenInstrRegister(COP1, D, f0, fs, fd, RECIP_D);
2851 }
2852
2853
recip_s(FPURegister fd,FPURegister fs)2854 void Assembler::recip_s(FPURegister fd, FPURegister fs) {
2855 GenInstrRegister(COP1, S, f0, fs, fd, RECIP_S);
2856 }
2857
2858
2859 // Conversions.
cvt_w_s(FPURegister fd,FPURegister fs)2860 void Assembler::cvt_w_s(FPURegister fd, FPURegister fs) {
2861 GenInstrRegister(COP1, S, f0, fs, fd, CVT_W_S);
2862 }
2863
2864
cvt_w_d(FPURegister fd,FPURegister fs)2865 void Assembler::cvt_w_d(FPURegister fd, FPURegister fs) {
2866 GenInstrRegister(COP1, D, f0, fs, fd, CVT_W_D);
2867 }
2868
2869
trunc_w_s(FPURegister fd,FPURegister fs)2870 void Assembler::trunc_w_s(FPURegister fd, FPURegister fs) {
2871 GenInstrRegister(COP1, S, f0, fs, fd, TRUNC_W_S);
2872 }
2873
2874
trunc_w_d(FPURegister fd,FPURegister fs)2875 void Assembler::trunc_w_d(FPURegister fd, FPURegister fs) {
2876 GenInstrRegister(COP1, D, f0, fs, fd, TRUNC_W_D);
2877 }
2878
2879
round_w_s(FPURegister fd,FPURegister fs)2880 void Assembler::round_w_s(FPURegister fd, FPURegister fs) {
2881 GenInstrRegister(COP1, S, f0, fs, fd, ROUND_W_S);
2882 }
2883
2884
round_w_d(FPURegister fd,FPURegister fs)2885 void Assembler::round_w_d(FPURegister fd, FPURegister fs) {
2886 GenInstrRegister(COP1, D, f0, fs, fd, ROUND_W_D);
2887 }
2888
2889
floor_w_s(FPURegister fd,FPURegister fs)2890 void Assembler::floor_w_s(FPURegister fd, FPURegister fs) {
2891 GenInstrRegister(COP1, S, f0, fs, fd, FLOOR_W_S);
2892 }
2893
2894
floor_w_d(FPURegister fd,FPURegister fs)2895 void Assembler::floor_w_d(FPURegister fd, FPURegister fs) {
2896 GenInstrRegister(COP1, D, f0, fs, fd, FLOOR_W_D);
2897 }
2898
2899
ceil_w_s(FPURegister fd,FPURegister fs)2900 void Assembler::ceil_w_s(FPURegister fd, FPURegister fs) {
2901 GenInstrRegister(COP1, S, f0, fs, fd, CEIL_W_S);
2902 }
2903
2904
ceil_w_d(FPURegister fd,FPURegister fs)2905 void Assembler::ceil_w_d(FPURegister fd, FPURegister fs) {
2906 GenInstrRegister(COP1, D, f0, fs, fd, CEIL_W_D);
2907 }
2908
2909
rint_s(FPURegister fd,FPURegister fs)2910 void Assembler::rint_s(FPURegister fd, FPURegister fs) { rint(S, fd, fs); }
2911
2912
rint_d(FPURegister fd,FPURegister fs)2913 void Assembler::rint_d(FPURegister fd, FPURegister fs) { rint(D, fd, fs); }
2914
2915
rint(SecondaryField fmt,FPURegister fd,FPURegister fs)2916 void Assembler::rint(SecondaryField fmt, FPURegister fd, FPURegister fs) {
2917 DCHECK(kArchVariant == kMips64r6);
2918 GenInstrRegister(COP1, fmt, f0, fs, fd, RINT);
2919 }
2920
2921
cvt_l_s(FPURegister fd,FPURegister fs)2922 void Assembler::cvt_l_s(FPURegister fd, FPURegister fs) {
2923 DCHECK(kArchVariant == kMips64r2 || kArchVariant == kMips64r6);
2924 GenInstrRegister(COP1, S, f0, fs, fd, CVT_L_S);
2925 }
2926
2927
cvt_l_d(FPURegister fd,FPURegister fs)2928 void Assembler::cvt_l_d(FPURegister fd, FPURegister fs) {
2929 DCHECK(kArchVariant == kMips64r2 || kArchVariant == kMips64r6);
2930 GenInstrRegister(COP1, D, f0, fs, fd, CVT_L_D);
2931 }
2932
2933
trunc_l_s(FPURegister fd,FPURegister fs)2934 void Assembler::trunc_l_s(FPURegister fd, FPURegister fs) {
2935 DCHECK(kArchVariant == kMips64r2 || kArchVariant == kMips64r6);
2936 GenInstrRegister(COP1, S, f0, fs, fd, TRUNC_L_S);
2937 }
2938
2939
trunc_l_d(FPURegister fd,FPURegister fs)2940 void Assembler::trunc_l_d(FPURegister fd, FPURegister fs) {
2941 DCHECK(kArchVariant == kMips64r2 || kArchVariant == kMips64r6);
2942 GenInstrRegister(COP1, D, f0, fs, fd, TRUNC_L_D);
2943 }
2944
2945
round_l_s(FPURegister fd,FPURegister fs)2946 void Assembler::round_l_s(FPURegister fd, FPURegister fs) {
2947 GenInstrRegister(COP1, S, f0, fs, fd, ROUND_L_S);
2948 }
2949
2950
round_l_d(FPURegister fd,FPURegister fs)2951 void Assembler::round_l_d(FPURegister fd, FPURegister fs) {
2952 GenInstrRegister(COP1, D, f0, fs, fd, ROUND_L_D);
2953 }
2954
2955
floor_l_s(FPURegister fd,FPURegister fs)2956 void Assembler::floor_l_s(FPURegister fd, FPURegister fs) {
2957 GenInstrRegister(COP1, S, f0, fs, fd, FLOOR_L_S);
2958 }
2959
2960
floor_l_d(FPURegister fd,FPURegister fs)2961 void Assembler::floor_l_d(FPURegister fd, FPURegister fs) {
2962 GenInstrRegister(COP1, D, f0, fs, fd, FLOOR_L_D);
2963 }
2964
2965
ceil_l_s(FPURegister fd,FPURegister fs)2966 void Assembler::ceil_l_s(FPURegister fd, FPURegister fs) {
2967 GenInstrRegister(COP1, S, f0, fs, fd, CEIL_L_S);
2968 }
2969
2970
ceil_l_d(FPURegister fd,FPURegister fs)2971 void Assembler::ceil_l_d(FPURegister fd, FPURegister fs) {
2972 GenInstrRegister(COP1, D, f0, fs, fd, CEIL_L_D);
2973 }
2974
2975
class_s(FPURegister fd,FPURegister fs)2976 void Assembler::class_s(FPURegister fd, FPURegister fs) {
2977 DCHECK(kArchVariant == kMips64r6);
2978 GenInstrRegister(COP1, S, f0, fs, fd, CLASS_S);
2979 }
2980
2981
class_d(FPURegister fd,FPURegister fs)2982 void Assembler::class_d(FPURegister fd, FPURegister fs) {
2983 DCHECK(kArchVariant == kMips64r6);
2984 GenInstrRegister(COP1, D, f0, fs, fd, CLASS_D);
2985 }
2986
2987
mina(SecondaryField fmt,FPURegister fd,FPURegister fs,FPURegister ft)2988 void Assembler::mina(SecondaryField fmt, FPURegister fd, FPURegister fs,
2989 FPURegister ft) {
2990 DCHECK(kArchVariant == kMips64r6);
2991 DCHECK((fmt == D) || (fmt == S));
2992 GenInstrRegister(COP1, fmt, ft, fs, fd, MINA);
2993 }
2994
2995
maxa(SecondaryField fmt,FPURegister fd,FPURegister fs,FPURegister ft)2996 void Assembler::maxa(SecondaryField fmt, FPURegister fd, FPURegister fs,
2997 FPURegister ft) {
2998 DCHECK(kArchVariant == kMips64r6);
2999 DCHECK((fmt == D) || (fmt == S));
3000 GenInstrRegister(COP1, fmt, ft, fs, fd, MAXA);
3001 }
3002
3003
cvt_s_w(FPURegister fd,FPURegister fs)3004 void Assembler::cvt_s_w(FPURegister fd, FPURegister fs) {
3005 GenInstrRegister(COP1, W, f0, fs, fd, CVT_S_W);
3006 }
3007
3008
cvt_s_l(FPURegister fd,FPURegister fs)3009 void Assembler::cvt_s_l(FPURegister fd, FPURegister fs) {
3010 DCHECK(kArchVariant == kMips64r2 || kArchVariant == kMips64r6);
3011 GenInstrRegister(COP1, L, f0, fs, fd, CVT_S_L);
3012 }
3013
3014
cvt_s_d(FPURegister fd,FPURegister fs)3015 void Assembler::cvt_s_d(FPURegister fd, FPURegister fs) {
3016 GenInstrRegister(COP1, D, f0, fs, fd, CVT_S_D);
3017 }
3018
3019
cvt_d_w(FPURegister fd,FPURegister fs)3020 void Assembler::cvt_d_w(FPURegister fd, FPURegister fs) {
3021 GenInstrRegister(COP1, W, f0, fs, fd, CVT_D_W);
3022 }
3023
3024
cvt_d_l(FPURegister fd,FPURegister fs)3025 void Assembler::cvt_d_l(FPURegister fd, FPURegister fs) {
3026 DCHECK(kArchVariant == kMips64r2 || kArchVariant == kMips64r6);
3027 GenInstrRegister(COP1, L, f0, fs, fd, CVT_D_L);
3028 }
3029
3030
cvt_d_s(FPURegister fd,FPURegister fs)3031 void Assembler::cvt_d_s(FPURegister fd, FPURegister fs) {
3032 GenInstrRegister(COP1, S, f0, fs, fd, CVT_D_S);
3033 }
3034
3035
3036 // Conditions for >= MIPSr6.
cmp(FPUCondition cond,SecondaryField fmt,FPURegister fd,FPURegister fs,FPURegister ft)3037 void Assembler::cmp(FPUCondition cond, SecondaryField fmt,
3038 FPURegister fd, FPURegister fs, FPURegister ft) {
3039 DCHECK(kArchVariant == kMips64r6);
3040 DCHECK((fmt & ~(31 << kRsShift)) == 0);
3041 Instr instr = COP1 | fmt | ft.code() << kFtShift |
3042 fs.code() << kFsShift | fd.code() << kFdShift | (0 << 5) | cond;
3043 emit(instr);
3044 }
3045
3046
cmp_s(FPUCondition cond,FPURegister fd,FPURegister fs,FPURegister ft)3047 void Assembler::cmp_s(FPUCondition cond, FPURegister fd, FPURegister fs,
3048 FPURegister ft) {
3049 cmp(cond, W, fd, fs, ft);
3050 }
3051
cmp_d(FPUCondition cond,FPURegister fd,FPURegister fs,FPURegister ft)3052 void Assembler::cmp_d(FPUCondition cond, FPURegister fd, FPURegister fs,
3053 FPURegister ft) {
3054 cmp(cond, L, fd, fs, ft);
3055 }
3056
3057
bc1eqz(int16_t offset,FPURegister ft)3058 void Assembler::bc1eqz(int16_t offset, FPURegister ft) {
3059 DCHECK(kArchVariant == kMips64r6);
3060 Instr instr = COP1 | BC1EQZ | ft.code() << kFtShift | (offset & kImm16Mask);
3061 emit(instr);
3062 }
3063
3064
bc1nez(int16_t offset,FPURegister ft)3065 void Assembler::bc1nez(int16_t offset, FPURegister ft) {
3066 DCHECK(kArchVariant == kMips64r6);
3067 Instr instr = COP1 | BC1NEZ | ft.code() << kFtShift | (offset & kImm16Mask);
3068 emit(instr);
3069 }
3070
3071
3072 // Conditions for < MIPSr6.
c(FPUCondition cond,SecondaryField fmt,FPURegister fs,FPURegister ft,uint16_t cc)3073 void Assembler::c(FPUCondition cond, SecondaryField fmt,
3074 FPURegister fs, FPURegister ft, uint16_t cc) {
3075 DCHECK(kArchVariant != kMips64r6);
3076 DCHECK(is_uint3(cc));
3077 DCHECK(fmt == S || fmt == D);
3078 DCHECK((fmt & ~(31 << kRsShift)) == 0);
3079 Instr instr = COP1 | fmt | ft.code() << kFtShift | fs.code() << kFsShift
3080 | cc << 8 | 3 << 4 | cond;
3081 emit(instr);
3082 }
3083
3084
c_s(FPUCondition cond,FPURegister fs,FPURegister ft,uint16_t cc)3085 void Assembler::c_s(FPUCondition cond, FPURegister fs, FPURegister ft,
3086 uint16_t cc) {
3087 c(cond, S, fs, ft, cc);
3088 }
3089
3090
c_d(FPUCondition cond,FPURegister fs,FPURegister ft,uint16_t cc)3091 void Assembler::c_d(FPUCondition cond, FPURegister fs, FPURegister ft,
3092 uint16_t cc) {
3093 c(cond, D, fs, ft, cc);
3094 }
3095
3096
fcmp(FPURegister src1,const double src2,FPUCondition cond)3097 void Assembler::fcmp(FPURegister src1, const double src2,
3098 FPUCondition cond) {
3099 DCHECK(src2 == 0.0);
3100 mtc1(zero_reg, f14);
3101 cvt_d_w(f14, f14);
3102 c(cond, D, src1, f14, 0);
3103 }
3104
3105
bc1f(int16_t offset,uint16_t cc)3106 void Assembler::bc1f(int16_t offset, uint16_t cc) {
3107 DCHECK(is_uint3(cc));
3108 Instr instr = COP1 | BC1 | cc << 18 | 0 << 16 | (offset & kImm16Mask);
3109 emit(instr);
3110 }
3111
3112
bc1t(int16_t offset,uint16_t cc)3113 void Assembler::bc1t(int16_t offset, uint16_t cc) {
3114 DCHECK(is_uint3(cc));
3115 Instr instr = COP1 | BC1 | cc << 18 | 1 << 16 | (offset & kImm16Mask);
3116 emit(instr);
3117 }
3118
3119
RelocateInternalReference(RelocInfo::Mode rmode,byte * pc,intptr_t pc_delta)3120 int Assembler::RelocateInternalReference(RelocInfo::Mode rmode, byte* pc,
3121 intptr_t pc_delta) {
3122 if (RelocInfo::IsInternalReference(rmode)) {
3123 int64_t* p = reinterpret_cast<int64_t*>(pc);
3124 if (*p == kEndOfJumpChain) {
3125 return 0; // Number of instructions patched.
3126 }
3127 *p += pc_delta;
3128 return 2; // Number of instructions patched.
3129 }
3130 Instr instr = instr_at(pc);
3131 DCHECK(RelocInfo::IsInternalReferenceEncoded(rmode));
3132 if (IsLui(instr)) {
3133 Instr instr_lui = instr_at(pc + 0 * Assembler::kInstrSize);
3134 Instr instr_ori = instr_at(pc + 1 * Assembler::kInstrSize);
3135 Instr instr_ori2 = instr_at(pc + 3 * Assembler::kInstrSize);
3136 DCHECK(IsOri(instr_ori));
3137 DCHECK(IsOri(instr_ori2));
3138 // TODO(plind): symbolic names for the shifts.
3139 int64_t imm = (instr_lui & static_cast<int64_t>(kImm16Mask)) << 48;
3140 imm |= (instr_ori & static_cast<int64_t>(kImm16Mask)) << 32;
3141 imm |= (instr_ori2 & static_cast<int64_t>(kImm16Mask)) << 16;
3142 // Sign extend address.
3143 imm >>= 16;
3144
3145 if (imm == kEndOfJumpChain) {
3146 return 0; // Number of instructions patched.
3147 }
3148 imm += pc_delta;
3149 DCHECK((imm & 3) == 0);
3150
3151 instr_lui &= ~kImm16Mask;
3152 instr_ori &= ~kImm16Mask;
3153 instr_ori2 &= ~kImm16Mask;
3154
3155 instr_at_put(pc + 0 * Assembler::kInstrSize,
3156 instr_lui | ((imm >> 32) & kImm16Mask));
3157 instr_at_put(pc + 1 * Assembler::kInstrSize,
3158 instr_ori | (imm >> 16 & kImm16Mask));
3159 instr_at_put(pc + 3 * Assembler::kInstrSize,
3160 instr_ori2 | (imm & kImm16Mask));
3161 return 4; // Number of instructions patched.
3162 } else if (IsJ(instr) || IsJal(instr)) {
3163 // Regular j/jal relocation.
3164 uint32_t imm28 = (instr & static_cast<int32_t>(kImm26Mask)) << 2;
3165 imm28 += pc_delta;
3166 imm28 &= kImm28Mask;
3167 instr &= ~kImm26Mask;
3168 DCHECK((imm28 & 3) == 0);
3169 uint32_t imm26 = static_cast<uint32_t>(imm28 >> 2);
3170 instr_at_put(pc, instr | (imm26 & kImm26Mask));
3171 return 1; // Number of instructions patched.
3172 } else {
3173 DCHECK(((instr & kJumpRawMask) == kJRawMark) ||
3174 ((instr & kJumpRawMask) == kJalRawMark));
3175 // Unbox raw offset and emit j/jal.
3176 int32_t imm28 = (instr & static_cast<int32_t>(kImm26Mask)) << 2;
3177 // Sign extend 28-bit offset to 32-bit.
3178 imm28 = (imm28 << 4) >> 4;
3179 uint64_t target =
3180 static_cast<int64_t>(imm28) + reinterpret_cast<uint64_t>(pc);
3181 target &= kImm28Mask;
3182 DCHECK((imm28 & 3) == 0);
3183 uint32_t imm26 = static_cast<uint32_t>(target >> 2);
3184 // Check markings whether to emit j or jal.
3185 uint32_t unbox = (instr & kJRawMark) ? J : JAL;
3186 instr_at_put(pc, unbox | (imm26 & kImm26Mask));
3187 return 1; // Number of instructions patched.
3188 }
3189 }
3190
3191
GrowBuffer()3192 void Assembler::GrowBuffer() {
3193 if (!own_buffer_) FATAL("external code buffer is too small");
3194
3195 // Compute new buffer size.
3196 CodeDesc desc; // The new buffer.
3197 if (buffer_size_ < 1 * MB) {
3198 desc.buffer_size = 2*buffer_size_;
3199 } else {
3200 desc.buffer_size = buffer_size_ + 1*MB;
3201 }
3202 CHECK_GT(desc.buffer_size, 0); // No overflow.
3203
3204 // Set up new buffer.
3205 desc.buffer = NewArray<byte>(desc.buffer_size);
3206 desc.origin = this;
3207
3208 desc.instr_size = pc_offset();
3209 desc.reloc_size =
3210 static_cast<int>((buffer_ + buffer_size_) - reloc_info_writer.pos());
3211
3212 // Copy the data.
3213 intptr_t pc_delta = desc.buffer - buffer_;
3214 intptr_t rc_delta = (desc.buffer + desc.buffer_size) -
3215 (buffer_ + buffer_size_);
3216 MemMove(desc.buffer, buffer_, desc.instr_size);
3217 MemMove(reloc_info_writer.pos() + rc_delta,
3218 reloc_info_writer.pos(), desc.reloc_size);
3219
3220 // Switch buffers.
3221 DeleteArray(buffer_);
3222 buffer_ = desc.buffer;
3223 buffer_size_ = desc.buffer_size;
3224 pc_ += pc_delta;
3225 reloc_info_writer.Reposition(reloc_info_writer.pos() + rc_delta,
3226 reloc_info_writer.last_pc() + pc_delta);
3227
3228 // Relocate runtime entries.
3229 for (RelocIterator it(desc); !it.done(); it.next()) {
3230 RelocInfo::Mode rmode = it.rinfo()->rmode();
3231 if (rmode == RelocInfo::INTERNAL_REFERENCE) {
3232 byte* p = reinterpret_cast<byte*>(it.rinfo()->pc());
3233 RelocateInternalReference(rmode, p, pc_delta);
3234 }
3235 }
3236 DCHECK(!overflow());
3237 }
3238
3239
db(uint8_t data)3240 void Assembler::db(uint8_t data) {
3241 CheckForEmitInForbiddenSlot();
3242 EmitHelper(data);
3243 }
3244
3245
dd(uint32_t data)3246 void Assembler::dd(uint32_t data) {
3247 CheckForEmitInForbiddenSlot();
3248 EmitHelper(data);
3249 }
3250
3251
dq(uint64_t data)3252 void Assembler::dq(uint64_t data) {
3253 CheckForEmitInForbiddenSlot();
3254 EmitHelper(data);
3255 }
3256
3257
dd(Label * label)3258 void Assembler::dd(Label* label) {
3259 uint64_t data;
3260 CheckForEmitInForbiddenSlot();
3261 if (label->is_bound()) {
3262 data = reinterpret_cast<uint64_t>(buffer_ + label->pos());
3263 } else {
3264 data = jump_address(label);
3265 unbound_labels_count_++;
3266 internal_reference_positions_.insert(label->pos());
3267 }
3268 RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE);
3269 EmitHelper(data);
3270 }
3271
3272
RecordRelocInfo(RelocInfo::Mode rmode,intptr_t data)3273 void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) {
3274 // We do not try to reuse pool constants.
3275 RelocInfo rinfo(isolate(), pc_, rmode, data, NULL);
3276 if (rmode >= RelocInfo::COMMENT &&
3277 rmode <= RelocInfo::DEBUG_BREAK_SLOT_AT_TAIL_CALL) {
3278 // Adjust code for new modes.
3279 DCHECK(RelocInfo::IsDebugBreakSlot(rmode)
3280 || RelocInfo::IsComment(rmode)
3281 || RelocInfo::IsPosition(rmode));
3282 // These modes do not need an entry in the constant pool.
3283 }
3284 if (!RelocInfo::IsNone(rinfo.rmode())) {
3285 // Don't record external references unless the heap will be serialized.
3286 if (rmode == RelocInfo::EXTERNAL_REFERENCE &&
3287 !serializer_enabled() && !emit_debug_code()) {
3288 return;
3289 }
3290 DCHECK(buffer_space() >= kMaxRelocSize); // Too late to grow buffer here.
3291 if (rmode == RelocInfo::CODE_TARGET_WITH_ID) {
3292 RelocInfo reloc_info_with_ast_id(isolate(), pc_, rmode,
3293 RecordedAstId().ToInt(), NULL);
3294 ClearRecordedAstId();
3295 reloc_info_writer.Write(&reloc_info_with_ast_id);
3296 } else {
3297 reloc_info_writer.Write(&rinfo);
3298 }
3299 }
3300 }
3301
3302
BlockTrampolinePoolFor(int instructions)3303 void Assembler::BlockTrampolinePoolFor(int instructions) {
3304 CheckTrampolinePoolQuick(instructions);
3305 BlockTrampolinePoolBefore(pc_offset() + instructions * kInstrSize);
3306 }
3307
3308
CheckTrampolinePool()3309 void Assembler::CheckTrampolinePool() {
3310 // Some small sequences of instructions must not be broken up by the
3311 // insertion of a trampoline pool; such sequences are protected by setting
3312 // either trampoline_pool_blocked_nesting_ or no_trampoline_pool_before_,
3313 // which are both checked here. Also, recursive calls to CheckTrampolinePool
3314 // are blocked by trampoline_pool_blocked_nesting_.
3315 if ((trampoline_pool_blocked_nesting_ > 0) ||
3316 (pc_offset() < no_trampoline_pool_before_)) {
3317 // Emission is currently blocked; make sure we try again as soon as
3318 // possible.
3319 if (trampoline_pool_blocked_nesting_ > 0) {
3320 next_buffer_check_ = pc_offset() + kInstrSize;
3321 } else {
3322 next_buffer_check_ = no_trampoline_pool_before_;
3323 }
3324 return;
3325 }
3326
3327 DCHECK(!trampoline_emitted_);
3328 DCHECK(unbound_labels_count_ >= 0);
3329 if (unbound_labels_count_ > 0) {
3330 // First we emit jump (2 instructions), then we emit trampoline pool.
3331 { BlockTrampolinePoolScope block_trampoline_pool(this);
3332 Label after_pool;
3333 if (kArchVariant == kMips64r6) {
3334 bc(&after_pool);
3335 } else {
3336 b(&after_pool);
3337 }
3338 nop();
3339
3340 int pool_start = pc_offset();
3341 for (int i = 0; i < unbound_labels_count_; i++) {
3342 { BlockGrowBufferScope block_buf_growth(this);
3343 // Buffer growth (and relocation) must be blocked for internal
3344 // references until associated instructions are emitted and available
3345 // to be patched.
3346 RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE_ENCODED);
3347 j(&after_pool);
3348 }
3349 nop();
3350 }
3351 bind(&after_pool);
3352 trampoline_ = Trampoline(pool_start, unbound_labels_count_);
3353
3354 trampoline_emitted_ = true;
3355 // As we are only going to emit trampoline once, we need to prevent any
3356 // further emission.
3357 next_buffer_check_ = kMaxInt;
3358 }
3359 } else {
3360 // Number of branches to unbound label at this point is zero, so we can
3361 // move next buffer check to maximum.
3362 next_buffer_check_ = pc_offset() +
3363 kMaxBranchOffset - kTrampolineSlotsSize * 16;
3364 }
3365 return;
3366 }
3367
3368
target_address_at(Address pc)3369 Address Assembler::target_address_at(Address pc) {
3370 Instr instr0 = instr_at(pc);
3371 Instr instr1 = instr_at(pc + 1 * kInstrSize);
3372 Instr instr3 = instr_at(pc + 3 * kInstrSize);
3373
3374 // Interpret 4 instructions for address generated by li: See listing in
3375 // Assembler::set_target_address_at() just below.
3376 if ((GetOpcodeField(instr0) == LUI) && (GetOpcodeField(instr1) == ORI) &&
3377 (GetOpcodeField(instr3) == ORI)) {
3378 // Assemble the 48 bit value.
3379 int64_t addr = static_cast<int64_t>(
3380 ((uint64_t)(GetImmediate16(instr0)) << 32) |
3381 ((uint64_t)(GetImmediate16(instr1)) << 16) |
3382 ((uint64_t)(GetImmediate16(instr3))));
3383
3384 // Sign extend to get canonical address.
3385 addr = (addr << 16) >> 16;
3386 return reinterpret_cast<Address>(addr);
3387 }
3388 // We should never get here, force a bad address if we do.
3389 UNREACHABLE();
3390 return (Address)0x0;
3391 }
3392
3393
3394 // MIPS and ia32 use opposite encoding for qNaN and sNaN, such that ia32
3395 // qNaN is a MIPS sNaN, and ia32 sNaN is MIPS qNaN. If running from a heap
3396 // snapshot generated on ia32, the resulting MIPS sNaN must be quieted.
3397 // OS::nan_value() returns a qNaN.
QuietNaN(HeapObject * object)3398 void Assembler::QuietNaN(HeapObject* object) {
3399 HeapNumber::cast(object)->set_value(std::numeric_limits<double>::quiet_NaN());
3400 }
3401
3402
3403 // On Mips64, a target address is stored in a 4-instruction sequence:
3404 // 0: lui(rd, (j.imm64_ >> 32) & kImm16Mask);
3405 // 1: ori(rd, rd, (j.imm64_ >> 16) & kImm16Mask);
3406 // 2: dsll(rd, rd, 16);
3407 // 3: ori(rd, rd, j.imm32_ & kImm16Mask);
3408 //
3409 // Patching the address must replace all the lui & ori instructions,
3410 // and flush the i-cache.
3411 //
3412 // There is an optimization below, which emits a nop when the address
3413 // fits in just 16 bits. This is unlikely to help, and should be benchmarked,
3414 // and possibly removed.
set_target_address_at(Isolate * isolate,Address pc,Address target,ICacheFlushMode icache_flush_mode)3415 void Assembler::set_target_address_at(Isolate* isolate, Address pc,
3416 Address target,
3417 ICacheFlushMode icache_flush_mode) {
3418 // There is an optimization where only 4 instructions are used to load address
3419 // in code on MIP64 because only 48-bits of address is effectively used.
3420 // It relies on fact the upper [63:48] bits are not used for virtual address
3421 // translation and they have to be set according to value of bit 47 in order
3422 // get canonical address.
3423 Instr instr1 = instr_at(pc + kInstrSize);
3424 uint32_t rt_code = GetRt(instr1);
3425 uint32_t* p = reinterpret_cast<uint32_t*>(pc);
3426 uint64_t itarget = reinterpret_cast<uint64_t>(target);
3427
3428 #ifdef DEBUG
3429 // Check we have the result from a li macro-instruction.
3430 Instr instr0 = instr_at(pc);
3431 Instr instr3 = instr_at(pc + kInstrSize * 3);
3432 CHECK((GetOpcodeField(instr0) == LUI && GetOpcodeField(instr1) == ORI &&
3433 GetOpcodeField(instr3) == ORI));
3434 #endif
3435
3436 // Must use 4 instructions to insure patchable code.
3437 // lui rt, upper-16.
3438 // ori rt, rt, lower-16.
3439 // dsll rt, rt, 16.
3440 // ori rt rt, lower-16.
3441 *p = LUI | (rt_code << kRtShift) | ((itarget >> 32) & kImm16Mask);
3442 *(p + 1) = ORI | (rt_code << kRtShift) | (rt_code << kRsShift)
3443 | ((itarget >> 16) & kImm16Mask);
3444 *(p + 3) = ORI | (rt_code << kRsShift) | (rt_code << kRtShift)
3445 | (itarget & kImm16Mask);
3446
3447 if (icache_flush_mode != SKIP_ICACHE_FLUSH) {
3448 Assembler::FlushICache(isolate, pc, 4 * Assembler::kInstrSize);
3449 }
3450 }
3451
3452 } // namespace internal
3453 } // namespace v8
3454
3455 #endif // V8_TARGET_ARCH_MIPS64
3456