blob: 9c313a18d696eecb165bcc095da403ce663f24b3 [file] [log] [blame]
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001// Copyright (c) 1994-2006 Sun Microsystems Inc.
2// All Rights Reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions are
6// met:
7//
8// - Redistributions of source code must retain the above copyright notice,
9// this list of conditions and the following disclaimer.
10//
11// - Redistribution in binary form must reproduce the above copyright
12// notice, this list of conditions and the following disclaimer in the
13// documentation and/or other materials provided with the distribution.
14//
15// - Neither the name of Sun Microsystems or the names of contributors may
16// be used to endorse or promote products derived from this software without
17// specific prior written permission.
18//
19// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
20// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
23// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
27// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31// The original source code covered by the above license above has been
32// modified significantly by Google Inc.
33// Copyright 2012 the V8 project authors. All rights reserved.
34
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000035#include "src/mips64/assembler-mips64.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000036
37#if V8_TARGET_ARCH_MIPS64
38
39#include "src/base/cpu.h"
40#include "src/mips64/assembler-mips64-inl.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000041
42namespace v8 {
43namespace 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.
50static 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
Ben Murdochb8a8cc12014-11-26 15:28:44 +000067void 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
86void CpuFeatures::PrintTarget() { }
87void CpuFeatures::PrintFeatures() { }
88
89
90int 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
130Register 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
153const int RelocInfo::kApplyMask = RelocInfo::kCodeTargetMask |
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000154 1 << RelocInfo::INTERNAL_REFERENCE |
155 1 << RelocInfo::INTERNAL_REFERENCE_ENCODED;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000156
157
158bool 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
166bool RelocInfo::IsInConstantPool() {
167 return false;
168}
169
170
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000171// -----------------------------------------------------------------------------
172// Implementation of Operand and MemOperand.
173// See assembler-mips-inl.h for inlined constructors.
174
175Operand::Operand(Handle<Object> handle) {
176 AllowDeferredHandleDereference using_raw_address;
177 rm_ = no_reg;
178 // Verify all Objects referred by code are NOT in new space.
179 Object* obj = *handle;
180 if (obj->IsHeapObject()) {
181 DCHECK(!HeapObject::cast(obj)->GetHeap()->InNewSpace(obj));
182 imm64_ = reinterpret_cast<intptr_t>(handle.location());
183 rmode_ = RelocInfo::EMBEDDED_OBJECT;
184 } else {
185 // No relocation needed.
186 imm64_ = reinterpret_cast<intptr_t>(obj);
187 rmode_ = RelocInfo::NONE64;
188 }
189}
190
191
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000192MemOperand::MemOperand(Register rm, int32_t offset) : Operand(rm) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000193 offset_ = offset;
194}
195
196
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000197MemOperand::MemOperand(Register rm, int32_t unit, int32_t multiplier,
198 OffsetAddend offset_addend)
199 : Operand(rm) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000200 offset_ = unit * multiplier + offset_addend;
201}
202
203
204// -----------------------------------------------------------------------------
205// Specific instructions, constants, and masks.
206
207static const int kNegOffset = 0x00008000;
208// daddiu(sp, sp, 8) aka Pop() operation or part of Pop(r)
209// operations as post-increment of sp.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000210const Instr kPopInstruction = DADDIU | (Register::kCode_sp << kRsShift) |
211 (Register::kCode_sp << kRtShift) |
212 (kPointerSize & kImm16Mask); // NOLINT
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000213// daddiu(sp, sp, -8) part of Push(r) operation as pre-decrement of sp.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000214const Instr kPushInstruction = DADDIU | (Register::kCode_sp << kRsShift) |
215 (Register::kCode_sp << kRtShift) |
216 (-kPointerSize & kImm16Mask); // NOLINT
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000217// sd(r, MemOperand(sp, 0))
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000218const Instr kPushRegPattern =
219 SD | (Register::kCode_sp << kRsShift) | (0 & kImm16Mask); // NOLINT
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000220// ld(r, MemOperand(sp, 0))
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000221const Instr kPopRegPattern =
222 LD | (Register::kCode_sp << kRsShift) | (0 & kImm16Mask); // NOLINT
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000223
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000224const Instr kLwRegFpOffsetPattern =
225 LW | (Register::kCode_fp << kRsShift) | (0 & kImm16Mask); // NOLINT
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000226
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000227const Instr kSwRegFpOffsetPattern =
228 SW | (Register::kCode_fp << kRsShift) | (0 & kImm16Mask); // NOLINT
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000229
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000230const Instr kLwRegFpNegOffsetPattern = LW | (Register::kCode_fp << kRsShift) |
231 (kNegOffset & kImm16Mask); // NOLINT
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000232
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000233const Instr kSwRegFpNegOffsetPattern = SW | (Register::kCode_fp << kRsShift) |
234 (kNegOffset & kImm16Mask); // NOLINT
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000235// A mask for the Rt register for push, pop, lw, sw instructions.
236const Instr kRtMask = kRtFieldMask;
237const Instr kLwSwInstrTypeMask = 0xffe00000;
238const Instr kLwSwInstrArgumentMask = ~kLwSwInstrTypeMask;
239const Instr kLwSwOffsetMask = kImm16Mask;
240
241
242Assembler::Assembler(Isolate* isolate, void* buffer, int buffer_size)
243 : AssemblerBase(isolate, buffer, buffer_size),
244 recorded_ast_id_(TypeFeedbackId::None()),
245 positions_recorder_(this) {
246 reloc_info_writer.Reposition(buffer_ + buffer_size_, pc_);
247
248 last_trampoline_pool_end_ = 0;
249 no_trampoline_pool_before_ = 0;
250 trampoline_pool_blocked_nesting_ = 0;
251 // We leave space (16 * kTrampolineSlotsSize)
252 // for BlockTrampolinePoolScope buffer.
253 next_buffer_check_ = FLAG_force_long_branches
254 ? kMaxInt : kMaxBranchOffset - kTrampolineSlotsSize * 16;
255 internal_trampoline_exception_ = false;
256 last_bound_pos_ = 0;
257
258 trampoline_emitted_ = FLAG_force_long_branches;
259 unbound_labels_count_ = 0;
260 block_buffer_growth_ = false;
261
262 ClearRecordedAstId();
263}
264
265
266void Assembler::GetCode(CodeDesc* desc) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000267 EmitForbiddenSlotInstruction();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000268 DCHECK(pc_ <= reloc_info_writer.pos()); // No overlap.
269 // Set up code descriptor.
270 desc->buffer = buffer_;
271 desc->buffer_size = buffer_size_;
272 desc->instr_size = pc_offset();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000273 desc->reloc_size =
274 static_cast<int>((buffer_ + buffer_size_) - reloc_info_writer.pos());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000275 desc->origin = this;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000276 desc->constant_pool_size = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000277}
278
279
280void Assembler::Align(int m) {
281 DCHECK(m >= 4 && base::bits::IsPowerOfTwo32(m));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000282 EmitForbiddenSlotInstruction();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000283 while ((pc_offset() & (m - 1)) != 0) {
284 nop();
285 }
286}
287
288
289void Assembler::CodeTargetAlign() {
290 // No advantage to aligning branch/call targets to more than
291 // single instruction, that I am aware of.
292 Align(4);
293}
294
295
296Register Assembler::GetRtReg(Instr instr) {
297 Register rt;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000298 rt.reg_code = (instr & kRtFieldMask) >> kRtShift;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000299 return rt;
300}
301
302
303Register Assembler::GetRsReg(Instr instr) {
304 Register rs;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000305 rs.reg_code = (instr & kRsFieldMask) >> kRsShift;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000306 return rs;
307}
308
309
310Register Assembler::GetRdReg(Instr instr) {
311 Register rd;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000312 rd.reg_code = (instr & kRdFieldMask) >> kRdShift;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000313 return rd;
314}
315
316
317uint32_t Assembler::GetRt(Instr instr) {
318 return (instr & kRtFieldMask) >> kRtShift;
319}
320
321
322uint32_t Assembler::GetRtField(Instr instr) {
323 return instr & kRtFieldMask;
324}
325
326
327uint32_t Assembler::GetRs(Instr instr) {
328 return (instr & kRsFieldMask) >> kRsShift;
329}
330
331
332uint32_t Assembler::GetRsField(Instr instr) {
333 return instr & kRsFieldMask;
334}
335
336
337uint32_t Assembler::GetRd(Instr instr) {
338 return (instr & kRdFieldMask) >> kRdShift;
339}
340
341
342uint32_t Assembler::GetRdField(Instr instr) {
343 return instr & kRdFieldMask;
344}
345
346
347uint32_t Assembler::GetSa(Instr instr) {
348 return (instr & kSaFieldMask) >> kSaShift;
349}
350
351
352uint32_t Assembler::GetSaField(Instr instr) {
353 return instr & kSaFieldMask;
354}
355
356
357uint32_t Assembler::GetOpcodeField(Instr instr) {
358 return instr & kOpcodeMask;
359}
360
361
362uint32_t Assembler::GetFunction(Instr instr) {
363 return (instr & kFunctionFieldMask) >> kFunctionShift;
364}
365
366
367uint32_t Assembler::GetFunctionField(Instr instr) {
368 return instr & kFunctionFieldMask;
369}
370
371
372uint32_t Assembler::GetImmediate16(Instr instr) {
373 return instr & kImm16Mask;
374}
375
376
377uint32_t Assembler::GetLabelConst(Instr instr) {
378 return instr & ~kImm16Mask;
379}
380
381
382bool Assembler::IsPop(Instr instr) {
383 return (instr & ~kRtMask) == kPopRegPattern;
384}
385
386
387bool Assembler::IsPush(Instr instr) {
388 return (instr & ~kRtMask) == kPushRegPattern;
389}
390
391
392bool Assembler::IsSwRegFpOffset(Instr instr) {
393 return ((instr & kLwSwInstrTypeMask) == kSwRegFpOffsetPattern);
394}
395
396
397bool Assembler::IsLwRegFpOffset(Instr instr) {
398 return ((instr & kLwSwInstrTypeMask) == kLwRegFpOffsetPattern);
399}
400
401
402bool Assembler::IsSwRegFpNegOffset(Instr instr) {
403 return ((instr & (kLwSwInstrTypeMask | kNegOffset)) ==
404 kSwRegFpNegOffsetPattern);
405}
406
407
408bool Assembler::IsLwRegFpNegOffset(Instr instr) {
409 return ((instr & (kLwSwInstrTypeMask | kNegOffset)) ==
410 kLwRegFpNegOffsetPattern);
411}
412
413
414// Labels refer to positions in the (to be) generated code.
415// There are bound, linked, and unused labels.
416//
417// Bound labels refer to known positions in the already
418// generated code. pos() is the position the label refers to.
419//
420// Linked labels refer to unknown positions in the code
421// to be generated; pos() is the position of the last
422// instruction using the label.
423
424// The link chain is terminated by a value in the instruction of -1,
425// which is an otherwise illegal value (branch -1 is inf loop).
426// The instruction 16-bit offset field addresses 32-bit words, but in
427// code is conv to an 18-bit value addressing bytes, hence the -4 value.
428
429const int kEndOfChain = -4;
430// Determines the end of the Jump chain (a subset of the label link chain).
431const int kEndOfJumpChain = 0;
432
433
434bool Assembler::IsBranch(Instr instr) {
435 uint32_t opcode = GetOpcodeField(instr);
436 uint32_t rt_field = GetRtField(instr);
437 uint32_t rs_field = GetRsField(instr);
438 // Checks if the instruction is a branch.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000439 bool isBranch =
440 opcode == BEQ || opcode == BNE || opcode == BLEZ || opcode == BGTZ ||
441 opcode == BEQL || opcode == BNEL || opcode == BLEZL || opcode == BGTZL ||
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000442 (opcode == REGIMM && (rt_field == BLTZ || rt_field == BGEZ ||
443 rt_field == BLTZAL || rt_field == BGEZAL)) ||
444 (opcode == COP1 && rs_field == BC1) || // Coprocessor branch.
445 (opcode == COP1 && rs_field == BC1EQZ) ||
446 (opcode == COP1 && rs_field == BC1NEZ);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000447 if (!isBranch && kArchVariant == kMips64r6) {
448 // All the 3 variants of POP10 (BOVC, BEQC, BEQZALC) and
449 // POP30 (BNVC, BNEC, BNEZALC) are branch ops.
450 isBranch |= opcode == POP10 || opcode == POP30 || opcode == BC ||
451 opcode == BALC ||
452 (opcode == POP66 && rs_field != 0) || // BEQZC
453 (opcode == POP76 && rs_field != 0); // BNEZC
454 }
455 return isBranch;
456}
457
458
459bool Assembler::IsBc(Instr instr) {
460 uint32_t opcode = GetOpcodeField(instr);
461 // Checks if the instruction is a BC or BALC.
462 return opcode == BC || opcode == BALC;
463}
464
465
466bool Assembler::IsBzc(Instr instr) {
467 uint32_t opcode = GetOpcodeField(instr);
468 // Checks if the instruction is BEQZC or BNEZC.
469 return (opcode == POP66 && GetRsField(instr) != 0) ||
470 (opcode == POP76 && GetRsField(instr) != 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000471}
472
473
474bool Assembler::IsEmittedConstant(Instr instr) {
475 uint32_t label_constant = GetLabelConst(instr);
476 return label_constant == 0; // Emitted label const in reg-exp engine.
477}
478
479
480bool Assembler::IsBeq(Instr instr) {
481 return GetOpcodeField(instr) == BEQ;
482}
483
484
485bool Assembler::IsBne(Instr instr) {
486 return GetOpcodeField(instr) == BNE;
487}
488
489
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000490bool Assembler::IsBeqzc(Instr instr) {
491 uint32_t opcode = GetOpcodeField(instr);
492 return opcode == POP66 && GetRsField(instr) != 0;
493}
494
495
496bool Assembler::IsBnezc(Instr instr) {
497 uint32_t opcode = GetOpcodeField(instr);
498 return opcode == POP76 && GetRsField(instr) != 0;
499}
500
501
502bool Assembler::IsBeqc(Instr instr) {
503 uint32_t opcode = GetOpcodeField(instr);
504 uint32_t rs = GetRsField(instr);
505 uint32_t rt = GetRtField(instr);
506 return opcode == POP10 && rs != 0 && rs < rt; // && rt != 0
507}
508
509
510bool Assembler::IsBnec(Instr instr) {
511 uint32_t opcode = GetOpcodeField(instr);
512 uint32_t rs = GetRsField(instr);
513 uint32_t rt = GetRtField(instr);
514 return opcode == POP30 && rs != 0 && rs < rt; // && rt != 0
515}
516
517
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000518bool Assembler::IsJump(Instr instr) {
519 uint32_t opcode = GetOpcodeField(instr);
520 uint32_t rt_field = GetRtField(instr);
521 uint32_t rd_field = GetRdField(instr);
522 uint32_t function_field = GetFunctionField(instr);
523 // Checks if the instruction is a jump.
524 return opcode == J || opcode == JAL ||
525 (opcode == SPECIAL && rt_field == 0 &&
526 ((function_field == JALR) || (rd_field == 0 && (function_field == JR))));
527}
528
529
530bool Assembler::IsJ(Instr instr) {
531 uint32_t opcode = GetOpcodeField(instr);
532 // Checks if the instruction is a jump.
533 return opcode == J;
534}
535
536
537bool Assembler::IsJal(Instr instr) {
538 return GetOpcodeField(instr) == JAL;
539}
540
541
542bool Assembler::IsJr(Instr instr) {
543 return GetOpcodeField(instr) == SPECIAL && GetFunctionField(instr) == JR;
544}
545
546
547bool Assembler::IsJalr(Instr instr) {
548 return GetOpcodeField(instr) == SPECIAL && GetFunctionField(instr) == JALR;
549}
550
551
552bool Assembler::IsLui(Instr instr) {
553 uint32_t opcode = GetOpcodeField(instr);
554 // Checks if the instruction is a load upper immediate.
555 return opcode == LUI;
556}
557
558
559bool Assembler::IsOri(Instr instr) {
560 uint32_t opcode = GetOpcodeField(instr);
561 // Checks if the instruction is a load upper immediate.
562 return opcode == ORI;
563}
564
565
566bool Assembler::IsNop(Instr instr, unsigned int type) {
567 // See Assembler::nop(type).
568 DCHECK(type < 32);
569 uint32_t opcode = GetOpcodeField(instr);
570 uint32_t function = GetFunctionField(instr);
571 uint32_t rt = GetRt(instr);
572 uint32_t rd = GetRd(instr);
573 uint32_t sa = GetSa(instr);
574
575 // Traditional mips nop == sll(zero_reg, zero_reg, 0)
576 // When marking non-zero type, use sll(zero_reg, at, type)
577 // to avoid use of mips ssnop and ehb special encodings
578 // of the sll instruction.
579
580 Register nop_rt_reg = (type == 0) ? zero_reg : at;
581 bool ret = (opcode == SPECIAL && function == SLL &&
582 rd == static_cast<uint32_t>(ToNumber(zero_reg)) &&
583 rt == static_cast<uint32_t>(ToNumber(nop_rt_reg)) &&
584 sa == type);
585
586 return ret;
587}
588
589
590int32_t Assembler::GetBranchOffset(Instr instr) {
591 DCHECK(IsBranch(instr));
592 return (static_cast<int16_t>(instr & kImm16Mask)) << 2;
593}
594
595
596bool Assembler::IsLw(Instr instr) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000597 return (static_cast<uint32_t>(instr & kOpcodeMask) == LW);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000598}
599
600
601int16_t Assembler::GetLwOffset(Instr instr) {
602 DCHECK(IsLw(instr));
603 return ((instr & kImm16Mask));
604}
605
606
607Instr Assembler::SetLwOffset(Instr instr, int16_t offset) {
608 DCHECK(IsLw(instr));
609
610 // We actually create a new lw instruction based on the original one.
611 Instr temp_instr = LW | (instr & kRsFieldMask) | (instr & kRtFieldMask)
612 | (offset & kImm16Mask);
613
614 return temp_instr;
615}
616
617
618bool Assembler::IsSw(Instr instr) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000619 return (static_cast<uint32_t>(instr & kOpcodeMask) == SW);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000620}
621
622
623Instr Assembler::SetSwOffset(Instr instr, int16_t offset) {
624 DCHECK(IsSw(instr));
625 return ((instr & ~kImm16Mask) | (offset & kImm16Mask));
626}
627
628
629bool Assembler::IsAddImmediate(Instr instr) {
630 return ((instr & kOpcodeMask) == ADDIU || (instr & kOpcodeMask) == DADDIU);
631}
632
633
634Instr Assembler::SetAddImmediateOffset(Instr instr, int16_t offset) {
635 DCHECK(IsAddImmediate(instr));
636 return ((instr & ~kImm16Mask) | (offset & kImm16Mask));
637}
638
639
640bool Assembler::IsAndImmediate(Instr instr) {
641 return GetOpcodeField(instr) == ANDI;
642}
643
644
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000645static Assembler::OffsetSize OffsetSizeInBits(Instr instr) {
646 if (kArchVariant == kMips64r6) {
647 if (Assembler::IsBc(instr)) {
648 return Assembler::OffsetSize::kOffset26;
649 } else if (Assembler::IsBzc(instr)) {
650 return Assembler::OffsetSize::kOffset21;
651 }
652 }
653 return Assembler::OffsetSize::kOffset16;
654}
655
656
657static inline int32_t AddBranchOffset(int pos, Instr instr) {
658 int bits = OffsetSizeInBits(instr);
659 const int32_t mask = (1 << bits) - 1;
660 bits = 32 - bits;
661
662 // Do NOT change this to <<2. We rely on arithmetic shifts here, assuming
663 // the compiler uses arithmetic shifts for signed integers.
664 int32_t imm = ((instr & mask) << bits) >> (bits - 2);
665
666 if (imm == kEndOfChain) {
667 // EndOfChain sentinel is returned directly, not relative to pc or pos.
668 return kEndOfChain;
669 } else {
670 return pos + Assembler::kBranchPCOffset + imm;
671 }
672}
673
674
675int Assembler::target_at(int pos, bool is_internal) {
676 if (is_internal) {
677 int64_t* p = reinterpret_cast<int64_t*>(buffer_ + pos);
678 int64_t address = *p;
679 if (address == kEndOfJumpChain) {
680 return kEndOfChain;
681 } else {
682 int64_t instr_address = reinterpret_cast<int64_t>(p);
683 DCHECK(instr_address - address < INT_MAX);
684 int delta = static_cast<int>(instr_address - address);
685 DCHECK(pos > delta);
686 return pos - delta;
687 }
688 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000689 Instr instr = instr_at(pos);
690 if ((instr & ~kImm16Mask) == 0) {
691 // Emitted label constant, not part of a branch.
692 if (instr == 0) {
693 return kEndOfChain;
694 } else {
695 int32_t imm18 =((instr & static_cast<int32_t>(kImm16Mask)) << 16) >> 14;
696 return (imm18 + pos);
697 }
698 }
699 // Check we have a branch or jump instruction.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000700 DCHECK(IsBranch(instr) || IsJ(instr) || IsJal(instr) || IsLui(instr));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000701 // Do NOT change this to <<2. We rely on arithmetic shifts here, assuming
702 // the compiler uses arithmetic shifts for signed integers.
703 if (IsBranch(instr)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000704 return AddBranchOffset(pos, instr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000705 } else if (IsLui(instr)) {
706 Instr instr_lui = instr_at(pos + 0 * Assembler::kInstrSize);
707 Instr instr_ori = instr_at(pos + 1 * Assembler::kInstrSize);
708 Instr instr_ori2 = instr_at(pos + 3 * Assembler::kInstrSize);
709 DCHECK(IsOri(instr_ori));
710 DCHECK(IsOri(instr_ori2));
711
712 // TODO(plind) create named constants for shift values.
713 int64_t imm = static_cast<int64_t>(instr_lui & kImm16Mask) << 48;
714 imm |= static_cast<int64_t>(instr_ori & kImm16Mask) << 32;
715 imm |= static_cast<int64_t>(instr_ori2 & kImm16Mask) << 16;
716 // Sign extend address;
717 imm >>= 16;
718
719 if (imm == kEndOfJumpChain) {
720 // EndOfChain sentinel is returned directly, not relative to pc or pos.
721 return kEndOfChain;
722 } else {
723 uint64_t instr_address = reinterpret_cast<int64_t>(buffer_ + pos);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000724 DCHECK(instr_address - imm < INT_MAX);
725 int delta = static_cast<int>(instr_address - imm);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000726 DCHECK(pos > delta);
727 return pos - delta;
728 }
729 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000730 DCHECK(IsJ(instr) || IsJal(instr));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000731 int32_t imm28 = (instr & static_cast<int32_t>(kImm26Mask)) << 2;
732 if (imm28 == kEndOfJumpChain) {
733 // EndOfChain sentinel is returned directly, not relative to pc or pos.
734 return kEndOfChain;
735 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000736 // Sign extend 28-bit offset.
737 int32_t delta = static_cast<int32_t>((imm28 << 4) >> 4);
738 return pos + delta;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000739 }
740 }
741}
742
743
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000744static inline Instr SetBranchOffset(int32_t pos, int32_t target_pos,
745 Instr instr) {
746 int32_t bits = OffsetSizeInBits(instr);
747 int32_t imm = target_pos - (pos + Assembler::kBranchPCOffset);
748 DCHECK((imm & 3) == 0);
749 imm >>= 2;
750
751 const int32_t mask = (1 << bits) - 1;
752 instr &= ~mask;
753 DCHECK(is_intn(imm, bits));
754
755 return instr | (imm & mask);
756}
757
758
759void Assembler::target_at_put(int pos, int target_pos, bool is_internal) {
760 if (is_internal) {
761 uint64_t imm = reinterpret_cast<uint64_t>(buffer_) + target_pos;
762 *reinterpret_cast<uint64_t*>(buffer_ + pos) = imm;
763 return;
764 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000765 Instr instr = instr_at(pos);
766 if ((instr & ~kImm16Mask) == 0) {
767 DCHECK(target_pos == kEndOfChain || target_pos >= 0);
768 // Emitted label constant, not part of a branch.
769 // Make label relative to Code* of generated Code object.
770 instr_at_put(pos, target_pos + (Code::kHeaderSize - kHeapObjectTag));
771 return;
772 }
773
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000774 if (IsBranch(instr)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000775 instr = SetBranchOffset(pos, target_pos, instr);
776 instr_at_put(pos, instr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000777 } else if (IsLui(instr)) {
778 Instr instr_lui = instr_at(pos + 0 * Assembler::kInstrSize);
779 Instr instr_ori = instr_at(pos + 1 * Assembler::kInstrSize);
780 Instr instr_ori2 = instr_at(pos + 3 * Assembler::kInstrSize);
781 DCHECK(IsOri(instr_ori));
782 DCHECK(IsOri(instr_ori2));
783
784 uint64_t imm = reinterpret_cast<uint64_t>(buffer_) + target_pos;
785 DCHECK((imm & 3) == 0);
786
787 instr_lui &= ~kImm16Mask;
788 instr_ori &= ~kImm16Mask;
789 instr_ori2 &= ~kImm16Mask;
790
791 instr_at_put(pos + 0 * Assembler::kInstrSize,
792 instr_lui | ((imm >> 32) & kImm16Mask));
793 instr_at_put(pos + 1 * Assembler::kInstrSize,
794 instr_ori | ((imm >> 16) & kImm16Mask));
795 instr_at_put(pos + 3 * Assembler::kInstrSize,
796 instr_ori2 | (imm & kImm16Mask));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000797 } else if (IsJ(instr) || IsJal(instr)) {
798 int32_t imm28 = target_pos - pos;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000799 DCHECK((imm28 & 3) == 0);
800
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000801 uint32_t imm26 = static_cast<uint32_t>(imm28 >> 2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000802 DCHECK(is_uint26(imm26));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000803 // Place 26-bit signed offset with markings.
804 // When code is committed it will be resolved to j/jal.
805 int32_t mark = IsJ(instr) ? kJRawMark : kJalRawMark;
806 instr_at_put(pos, mark | (imm26 & kImm26Mask));
807 } else {
808 int32_t imm28 = target_pos - pos;
809 DCHECK((imm28 & 3) == 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000810
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000811 uint32_t imm26 = static_cast<uint32_t>(imm28 >> 2);
812 DCHECK(is_uint26(imm26));
813 // Place raw 26-bit signed offset.
814 // When code is committed it will be resolved to j/jal.
815 instr &= ~kImm26Mask;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000816 instr_at_put(pos, instr | (imm26 & kImm26Mask));
817 }
818}
819
820
821void Assembler::print(Label* L) {
822 if (L->is_unused()) {
823 PrintF("unused label\n");
824 } else if (L->is_bound()) {
825 PrintF("bound label to %d\n", L->pos());
826 } else if (L->is_linked()) {
827 Label l = *L;
828 PrintF("unbound label");
829 while (l.is_linked()) {
830 PrintF("@ %d ", l.pos());
831 Instr instr = instr_at(l.pos());
832 if ((instr & ~kImm16Mask) == 0) {
833 PrintF("value\n");
834 } else {
835 PrintF("%d\n", instr);
836 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000837 next(&l, internal_reference_positions_.find(l.pos()) !=
838 internal_reference_positions_.end());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000839 }
840 } else {
841 PrintF("label in inconsistent state (pos = %d)\n", L->pos_);
842 }
843}
844
845
846void Assembler::bind_to(Label* L, int pos) {
847 DCHECK(0 <= pos && pos <= pc_offset()); // Must have valid binding position.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000848 int trampoline_pos = kInvalidSlotPos;
849 bool is_internal = false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000850 if (L->is_linked() && !trampoline_emitted_) {
851 unbound_labels_count_--;
852 next_buffer_check_ += kTrampolineSlotsSize;
853 }
854
855 while (L->is_linked()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000856 int fixup_pos = L->pos();
857 int dist = pos - fixup_pos;
858 is_internal = internal_reference_positions_.find(fixup_pos) !=
859 internal_reference_positions_.end();
860 next(L, is_internal); // Call next before overwriting link with target at
861 // fixup_pos.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000862 Instr instr = instr_at(fixup_pos);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000863 if (is_internal) {
864 target_at_put(fixup_pos, pos, is_internal);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000865 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000866 if (IsBranch(instr)) {
867 int branch_offset = BranchOffset(instr);
868 if (dist > branch_offset) {
869 if (trampoline_pos == kInvalidSlotPos) {
870 trampoline_pos = get_trampoline_entry(fixup_pos);
871 CHECK(trampoline_pos != kInvalidSlotPos);
872 }
873 CHECK((trampoline_pos - fixup_pos) <= branch_offset);
874 target_at_put(fixup_pos, trampoline_pos, false);
875 fixup_pos = trampoline_pos;
876 dist = pos - fixup_pos;
877 }
878 target_at_put(fixup_pos, pos, false);
879 } else {
880 DCHECK(IsJ(instr) || IsJal(instr) || IsLui(instr) ||
881 IsEmittedConstant(instr));
882 target_at_put(fixup_pos, pos, false);
883 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000884 }
885 }
886 L->bind_to(pos);
887
888 // Keep track of the last bound label so we don't eliminate any instructions
889 // before a bound label.
890 if (pos > last_bound_pos_)
891 last_bound_pos_ = pos;
892}
893
894
895void Assembler::bind(Label* L) {
896 DCHECK(!L->is_bound()); // Label can only be bound once.
897 bind_to(L, pc_offset());
898}
899
900
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000901void Assembler::next(Label* L, bool is_internal) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000902 DCHECK(L->is_linked());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000903 int link = target_at(L->pos(), is_internal);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000904 if (link == kEndOfChain) {
905 L->Unuse();
906 } else {
907 DCHECK(link >= 0);
908 L->link_to(link);
909 }
910}
911
912
913bool Assembler::is_near(Label* L) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000914 DCHECK(L->is_bound());
915 return pc_offset() - L->pos() < kMaxBranchOffset - 4 * kInstrSize;
916}
917
918
919bool Assembler::is_near(Label* L, OffsetSize bits) {
920 if (L == nullptr || !L->is_bound()) return true;
921 return ((pc_offset() - L->pos()) <
922 (1 << (bits + 2 - 1)) - 1 - 5 * kInstrSize);
923}
924
925
926bool Assembler::is_near_branch(Label* L) {
927 DCHECK(L->is_bound());
928 return kArchVariant == kMips64r6 ? is_near_r6(L) : is_near_pre_r6(L);
929}
930
931
932int Assembler::BranchOffset(Instr instr) {
933 // At pre-R6 and for other R6 branches the offset is 16 bits.
934 int bits = OffsetSize::kOffset16;
935
936 if (kArchVariant == kMips64r6) {
937 uint32_t opcode = GetOpcodeField(instr);
938 switch (opcode) {
939 // Checks BC or BALC.
940 case BC:
941 case BALC:
942 bits = OffsetSize::kOffset26;
943 break;
944
945 // Checks BEQZC or BNEZC.
946 case POP66:
947 case POP76:
948 if (GetRsField(instr) != 0) bits = OffsetSize::kOffset21;
949 break;
950 default:
951 break;
952 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000953 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000954
955 return (1 << (bits + 2 - 1)) - 1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000956}
957
958
959// We have to use a temporary register for things that can be relocated even
960// if they can be encoded in the MIPS's 16 bits of immediate-offset instruction
961// space. There is no guarantee that the relocated location can be similarly
962// encoded.
963bool Assembler::MustUseReg(RelocInfo::Mode rmode) {
964 return !RelocInfo::IsNone(rmode);
965}
966
967void Assembler::GenInstrRegister(Opcode opcode,
968 Register rs,
969 Register rt,
970 Register rd,
971 uint16_t sa,
972 SecondaryField func) {
973 DCHECK(rd.is_valid() && rs.is_valid() && rt.is_valid() && is_uint5(sa));
974 Instr instr = opcode | (rs.code() << kRsShift) | (rt.code() << kRtShift)
975 | (rd.code() << kRdShift) | (sa << kSaShift) | func;
976 emit(instr);
977}
978
979
980void Assembler::GenInstrRegister(Opcode opcode,
981 Register rs,
982 Register rt,
983 uint16_t msb,
984 uint16_t lsb,
985 SecondaryField func) {
986 DCHECK(rs.is_valid() && rt.is_valid() && is_uint5(msb) && is_uint5(lsb));
987 Instr instr = opcode | (rs.code() << kRsShift) | (rt.code() << kRtShift)
988 | (msb << kRdShift) | (lsb << kSaShift) | func;
989 emit(instr);
990}
991
992
993void Assembler::GenInstrRegister(Opcode opcode,
994 SecondaryField fmt,
995 FPURegister ft,
996 FPURegister fs,
997 FPURegister fd,
998 SecondaryField func) {
999 DCHECK(fd.is_valid() && fs.is_valid() && ft.is_valid());
1000 Instr instr = opcode | fmt | (ft.code() << kFtShift) | (fs.code() << kFsShift)
1001 | (fd.code() << kFdShift) | func;
1002 emit(instr);
1003}
1004
1005
1006void Assembler::GenInstrRegister(Opcode opcode,
1007 FPURegister fr,
1008 FPURegister ft,
1009 FPURegister fs,
1010 FPURegister fd,
1011 SecondaryField func) {
1012 DCHECK(fd.is_valid() && fr.is_valid() && fs.is_valid() && ft.is_valid());
1013 Instr instr = opcode | (fr.code() << kFrShift) | (ft.code() << kFtShift)
1014 | (fs.code() << kFsShift) | (fd.code() << kFdShift) | func;
1015 emit(instr);
1016}
1017
1018
1019void Assembler::GenInstrRegister(Opcode opcode,
1020 SecondaryField fmt,
1021 Register rt,
1022 FPURegister fs,
1023 FPURegister fd,
1024 SecondaryField func) {
1025 DCHECK(fd.is_valid() && fs.is_valid() && rt.is_valid());
1026 Instr instr = opcode | fmt | (rt.code() << kRtShift)
1027 | (fs.code() << kFsShift) | (fd.code() << kFdShift) | func;
1028 emit(instr);
1029}
1030
1031
1032void Assembler::GenInstrRegister(Opcode opcode,
1033 SecondaryField fmt,
1034 Register rt,
1035 FPUControlRegister fs,
1036 SecondaryField func) {
1037 DCHECK(fs.is_valid() && rt.is_valid());
1038 Instr instr =
1039 opcode | fmt | (rt.code() << kRtShift) | (fs.code() << kFsShift) | func;
1040 emit(instr);
1041}
1042
1043
1044// Instructions with immediate value.
1045// Registers are in the order of the instruction encoding, from left to right.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001046void Assembler::GenInstrImmediate(Opcode opcode, Register rs, Register rt,
1047 int32_t j,
1048 CompactBranchType is_compact_branch) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001049 DCHECK(rs.is_valid() && rt.is_valid() && (is_int16(j) || is_uint16(j)));
1050 Instr instr = opcode | (rs.code() << kRsShift) | (rt.code() << kRtShift)
1051 | (j & kImm16Mask);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001052 emit(instr, is_compact_branch);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001053}
1054
1055
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001056void Assembler::GenInstrImmediate(Opcode opcode, Register rs, SecondaryField SF,
1057 int32_t j,
1058 CompactBranchType is_compact_branch) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001059 DCHECK(rs.is_valid() && (is_int16(j) || is_uint16(j)));
1060 Instr instr = opcode | (rs.code() << kRsShift) | SF | (j & kImm16Mask);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001061 emit(instr, is_compact_branch);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001062}
1063
1064
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001065void Assembler::GenInstrImmediate(Opcode opcode, Register rs, FPURegister ft,
1066 int32_t j,
1067 CompactBranchType is_compact_branch) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001068 DCHECK(rs.is_valid() && ft.is_valid() && (is_int16(j) || is_uint16(j)));
1069 Instr instr = opcode | (rs.code() << kRsShift) | (ft.code() << kFtShift)
1070 | (j & kImm16Mask);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001071 emit(instr, is_compact_branch);
1072}
1073
1074
1075void Assembler::GenInstrImmediate(Opcode opcode, Register rs, int32_t offset21,
1076 CompactBranchType is_compact_branch) {
1077 DCHECK(rs.is_valid() && (is_int21(offset21)));
1078 Instr instr = opcode | (rs.code() << kRsShift) | (offset21 & kImm21Mask);
1079 emit(instr, is_compact_branch);
1080}
1081
1082
1083void Assembler::GenInstrImmediate(Opcode opcode, Register rs,
1084 uint32_t offset21) {
1085 DCHECK(rs.is_valid() && (is_uint21(offset21)));
1086 Instr instr = opcode | (rs.code() << kRsShift) | (offset21 & kImm21Mask);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001087 emit(instr);
1088}
1089
1090
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001091void Assembler::GenInstrImmediate(Opcode opcode, int32_t offset26,
1092 CompactBranchType is_compact_branch) {
1093 DCHECK(is_int26(offset26));
1094 Instr instr = opcode | (offset26 & kImm26Mask);
1095 emit(instr, is_compact_branch);
1096}
1097
1098
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001099void Assembler::GenInstrJump(Opcode opcode,
1100 uint32_t address) {
1101 BlockTrampolinePoolScope block_trampoline_pool(this);
1102 DCHECK(is_uint26(address));
1103 Instr instr = opcode | address;
1104 emit(instr);
1105 BlockTrampolinePoolFor(1); // For associated delay slot.
1106}
1107
1108
1109// Returns the next free trampoline entry.
1110int32_t Assembler::get_trampoline_entry(int32_t pos) {
1111 int32_t trampoline_entry = kInvalidSlotPos;
1112 if (!internal_trampoline_exception_) {
1113 if (trampoline_.start() > pos) {
1114 trampoline_entry = trampoline_.take_slot();
1115 }
1116
1117 if (kInvalidSlotPos == trampoline_entry) {
1118 internal_trampoline_exception_ = true;
1119 }
1120 }
1121 return trampoline_entry;
1122}
1123
1124
1125uint64_t Assembler::jump_address(Label* L) {
1126 int64_t target_pos;
1127 if (L->is_bound()) {
1128 target_pos = L->pos();
1129 } else {
1130 if (L->is_linked()) {
1131 target_pos = L->pos(); // L's link.
1132 L->link_to(pc_offset());
1133 } else {
1134 L->link_to(pc_offset());
1135 return kEndOfJumpChain;
1136 }
1137 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001138 uint64_t imm = reinterpret_cast<uint64_t>(buffer_) + target_pos;
1139 DCHECK((imm & 3) == 0);
1140
1141 return imm;
1142}
1143
1144
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001145uint64_t Assembler::jump_offset(Label* L) {
1146 int64_t target_pos;
1147 int32_t pad = IsPrevInstrCompactBranch() ? kInstrSize : 0;
1148
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001149 if (L->is_bound()) {
1150 target_pos = L->pos();
1151 } else {
1152 if (L->is_linked()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001153 target_pos = L->pos(); // L's link.
1154 L->link_to(pc_offset() + pad);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001155 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001156 L->link_to(pc_offset() + pad);
1157 return kEndOfJumpChain;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001158 }
1159 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001160 int64_t imm = target_pos - (pc_offset() + pad);
1161 DCHECK((imm & 3) == 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001162
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001163 return static_cast<uint64_t>(imm);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001164}
1165
1166
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001167int32_t Assembler::branch_offset_helper(Label* L, OffsetSize bits) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001168 int32_t target_pos;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001169 int32_t pad = IsPrevInstrCompactBranch() ? kInstrSize : 0;
1170
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001171 if (L->is_bound()) {
1172 target_pos = L->pos();
1173 } else {
1174 if (L->is_linked()) {
1175 target_pos = L->pos();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001176 L->link_to(pc_offset() + pad);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001177 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001178 L->link_to(pc_offset() + pad);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001179 if (!trampoline_emitted_) {
1180 unbound_labels_count_++;
1181 next_buffer_check_ -= kTrampolineSlotsSize;
1182 }
1183 return kEndOfChain;
1184 }
1185 }
1186
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001187 int32_t offset = target_pos - (pc_offset() + kBranchPCOffset + pad);
1188 DCHECK(is_intn(offset, bits + 2));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001189 DCHECK((offset & 3) == 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001190
1191 return offset;
1192}
1193
1194
1195void Assembler::label_at_put(Label* L, int at_offset) {
1196 int target_pos;
1197 if (L->is_bound()) {
1198 target_pos = L->pos();
1199 instr_at_put(at_offset, target_pos + (Code::kHeaderSize - kHeapObjectTag));
1200 } else {
1201 if (L->is_linked()) {
1202 target_pos = L->pos(); // L's link.
1203 int32_t imm18 = target_pos - at_offset;
1204 DCHECK((imm18 & 3) == 0);
1205 int32_t imm16 = imm18 >> 2;
1206 DCHECK(is_int16(imm16));
1207 instr_at_put(at_offset, (imm16 & kImm16Mask));
1208 } else {
1209 target_pos = kEndOfChain;
1210 instr_at_put(at_offset, 0);
1211 if (!trampoline_emitted_) {
1212 unbound_labels_count_++;
1213 next_buffer_check_ -= kTrampolineSlotsSize;
1214 }
1215 }
1216 L->link_to(at_offset);
1217 }
1218}
1219
1220
1221//------- Branch and jump instructions --------
1222
1223void Assembler::b(int16_t offset) {
1224 beq(zero_reg, zero_reg, offset);
1225}
1226
1227
1228void Assembler::bal(int16_t offset) {
1229 positions_recorder()->WriteRecordedPositions();
1230 bgezal(zero_reg, offset);
1231}
1232
1233
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001234void Assembler::bc(int32_t offset) {
1235 DCHECK(kArchVariant == kMips64r6);
1236 GenInstrImmediate(BC, offset, CompactBranchType::COMPACT_BRANCH);
1237}
1238
1239
1240void Assembler::balc(int32_t offset) {
1241 DCHECK(kArchVariant == kMips64r6);
1242 positions_recorder()->WriteRecordedPositions();
1243 GenInstrImmediate(BALC, offset, CompactBranchType::COMPACT_BRANCH);
1244}
1245
1246
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001247void Assembler::beq(Register rs, Register rt, int16_t offset) {
1248 BlockTrampolinePoolScope block_trampoline_pool(this);
1249 GenInstrImmediate(BEQ, rs, rt, offset);
1250 BlockTrampolinePoolFor(1); // For associated delay slot.
1251}
1252
1253
1254void Assembler::bgez(Register rs, int16_t offset) {
1255 BlockTrampolinePoolScope block_trampoline_pool(this);
1256 GenInstrImmediate(REGIMM, rs, BGEZ, offset);
1257 BlockTrampolinePoolFor(1); // For associated delay slot.
1258}
1259
1260
1261void Assembler::bgezc(Register rt, int16_t offset) {
1262 DCHECK(kArchVariant == kMips64r6);
1263 DCHECK(!(rt.is(zero_reg)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001264 GenInstrImmediate(BLEZL, rt, rt, offset, CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001265}
1266
1267
1268void Assembler::bgeuc(Register rs, Register rt, int16_t offset) {
1269 DCHECK(kArchVariant == kMips64r6);
1270 DCHECK(!(rs.is(zero_reg)));
1271 DCHECK(!(rt.is(zero_reg)));
1272 DCHECK(rs.code() != rt.code());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001273 GenInstrImmediate(BLEZ, rs, rt, offset, CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001274}
1275
1276
1277void Assembler::bgec(Register rs, Register rt, int16_t offset) {
1278 DCHECK(kArchVariant == kMips64r6);
1279 DCHECK(!(rs.is(zero_reg)));
1280 DCHECK(!(rt.is(zero_reg)));
1281 DCHECK(rs.code() != rt.code());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001282 GenInstrImmediate(BLEZL, rs, rt, offset, CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001283}
1284
1285
1286void Assembler::bgezal(Register rs, int16_t offset) {
1287 DCHECK(kArchVariant != kMips64r6 || rs.is(zero_reg));
1288 BlockTrampolinePoolScope block_trampoline_pool(this);
1289 positions_recorder()->WriteRecordedPositions();
1290 GenInstrImmediate(REGIMM, rs, BGEZAL, offset);
1291 BlockTrampolinePoolFor(1); // For associated delay slot.
1292}
1293
1294
1295void Assembler::bgtz(Register rs, int16_t offset) {
1296 BlockTrampolinePoolScope block_trampoline_pool(this);
1297 GenInstrImmediate(BGTZ, rs, zero_reg, offset);
1298 BlockTrampolinePoolFor(1); // For associated delay slot.
1299}
1300
1301
1302void Assembler::bgtzc(Register rt, int16_t offset) {
1303 DCHECK(kArchVariant == kMips64r6);
1304 DCHECK(!(rt.is(zero_reg)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001305 GenInstrImmediate(BGTZL, zero_reg, rt, offset,
1306 CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001307}
1308
1309
1310void Assembler::blez(Register rs, int16_t offset) {
1311 BlockTrampolinePoolScope block_trampoline_pool(this);
1312 GenInstrImmediate(BLEZ, rs, zero_reg, offset);
1313 BlockTrampolinePoolFor(1); // For associated delay slot.
1314}
1315
1316
1317void Assembler::blezc(Register rt, int16_t offset) {
1318 DCHECK(kArchVariant == kMips64r6);
1319 DCHECK(!(rt.is(zero_reg)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001320 GenInstrImmediate(BLEZL, zero_reg, rt, offset,
1321 CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001322}
1323
1324
1325void Assembler::bltzc(Register rt, int16_t offset) {
1326 DCHECK(kArchVariant == kMips64r6);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001327 DCHECK(!rt.is(zero_reg));
1328 GenInstrImmediate(BGTZL, rt, rt, offset, CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001329}
1330
1331
1332void Assembler::bltuc(Register rs, Register rt, int16_t offset) {
1333 DCHECK(kArchVariant == kMips64r6);
1334 DCHECK(!(rs.is(zero_reg)));
1335 DCHECK(!(rt.is(zero_reg)));
1336 DCHECK(rs.code() != rt.code());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001337 GenInstrImmediate(BGTZ, rs, rt, offset, CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001338}
1339
1340
1341void Assembler::bltc(Register rs, Register rt, int16_t offset) {
1342 DCHECK(kArchVariant == kMips64r6);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001343 DCHECK(!rs.is(zero_reg));
1344 DCHECK(!rt.is(zero_reg));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001345 DCHECK(rs.code() != rt.code());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001346 GenInstrImmediate(BGTZL, rs, rt, offset, CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001347}
1348
1349
1350void Assembler::bltz(Register rs, int16_t offset) {
1351 BlockTrampolinePoolScope block_trampoline_pool(this);
1352 GenInstrImmediate(REGIMM, rs, BLTZ, offset);
1353 BlockTrampolinePoolFor(1); // For associated delay slot.
1354}
1355
1356
1357void Assembler::bltzal(Register rs, int16_t offset) {
1358 DCHECK(kArchVariant != kMips64r6 || rs.is(zero_reg));
1359 BlockTrampolinePoolScope block_trampoline_pool(this);
1360 positions_recorder()->WriteRecordedPositions();
1361 GenInstrImmediate(REGIMM, rs, BLTZAL, offset);
1362 BlockTrampolinePoolFor(1); // For associated delay slot.
1363}
1364
1365
1366void Assembler::bne(Register rs, Register rt, int16_t offset) {
1367 BlockTrampolinePoolScope block_trampoline_pool(this);
1368 GenInstrImmediate(BNE, rs, rt, offset);
1369 BlockTrampolinePoolFor(1); // For associated delay slot.
1370}
1371
1372
1373void Assembler::bovc(Register rs, Register rt, int16_t offset) {
1374 DCHECK(kArchVariant == kMips64r6);
1375 DCHECK(!(rs.is(zero_reg)));
1376 DCHECK(rs.code() >= rt.code());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001377 GenInstrImmediate(ADDI, rs, rt, offset, CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001378}
1379
1380
1381void Assembler::bnvc(Register rs, Register rt, int16_t offset) {
1382 DCHECK(kArchVariant == kMips64r6);
1383 DCHECK(!(rs.is(zero_reg)));
1384 DCHECK(rs.code() >= rt.code());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001385 GenInstrImmediate(DADDI, rs, rt, offset, CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001386}
1387
1388
1389void Assembler::blezalc(Register rt, int16_t offset) {
1390 DCHECK(kArchVariant == kMips64r6);
1391 DCHECK(!(rt.is(zero_reg)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001392 positions_recorder()->WriteRecordedPositions();
1393 GenInstrImmediate(BLEZ, zero_reg, rt, offset,
1394 CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001395}
1396
1397
1398void Assembler::bgezalc(Register rt, int16_t offset) {
1399 DCHECK(kArchVariant == kMips64r6);
1400 DCHECK(!(rt.is(zero_reg)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001401 positions_recorder()->WriteRecordedPositions();
1402 GenInstrImmediate(BLEZ, rt, rt, offset, CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001403}
1404
1405
1406void Assembler::bgezall(Register rs, int16_t offset) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001407 DCHECK(kArchVariant != kMips64r6);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001408 DCHECK(!(rs.is(zero_reg)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001409 BlockTrampolinePoolScope block_trampoline_pool(this);
1410 positions_recorder()->WriteRecordedPositions();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001411 GenInstrImmediate(REGIMM, rs, BGEZALL, offset);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001412 BlockTrampolinePoolFor(1); // For associated delay slot.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001413}
1414
1415
1416void Assembler::bltzalc(Register rt, int16_t offset) {
1417 DCHECK(kArchVariant == kMips64r6);
1418 DCHECK(!(rt.is(zero_reg)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001419 positions_recorder()->WriteRecordedPositions();
1420 GenInstrImmediate(BGTZ, rt, rt, offset, CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001421}
1422
1423
1424void Assembler::bgtzalc(Register rt, int16_t offset) {
1425 DCHECK(kArchVariant == kMips64r6);
1426 DCHECK(!(rt.is(zero_reg)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001427 positions_recorder()->WriteRecordedPositions();
1428 GenInstrImmediate(BGTZ, zero_reg, rt, offset,
1429 CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001430}
1431
1432
1433void Assembler::beqzalc(Register rt, int16_t offset) {
1434 DCHECK(kArchVariant == kMips64r6);
1435 DCHECK(!(rt.is(zero_reg)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001436 positions_recorder()->WriteRecordedPositions();
1437 GenInstrImmediate(ADDI, zero_reg, rt, offset,
1438 CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001439}
1440
1441
1442void Assembler::bnezalc(Register rt, int16_t offset) {
1443 DCHECK(kArchVariant == kMips64r6);
1444 DCHECK(!(rt.is(zero_reg)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001445 positions_recorder()->WriteRecordedPositions();
1446 GenInstrImmediate(DADDI, zero_reg, rt, offset,
1447 CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001448}
1449
1450
1451void Assembler::beqc(Register rs, Register rt, int16_t offset) {
1452 DCHECK(kArchVariant == kMips64r6);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001453 DCHECK(rs.code() != rt.code() && rs.code() != 0 && rt.code() != 0);
1454 if (rs.code() < rt.code()) {
1455 GenInstrImmediate(ADDI, rs, rt, offset, CompactBranchType::COMPACT_BRANCH);
1456 } else {
1457 GenInstrImmediate(ADDI, rt, rs, offset, CompactBranchType::COMPACT_BRANCH);
1458 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001459}
1460
1461
1462void Assembler::beqzc(Register rs, int32_t offset) {
1463 DCHECK(kArchVariant == kMips64r6);
1464 DCHECK(!(rs.is(zero_reg)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001465 GenInstrImmediate(POP66, rs, offset, CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001466}
1467
1468
1469void Assembler::bnec(Register rs, Register rt, int16_t offset) {
1470 DCHECK(kArchVariant == kMips64r6);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001471 DCHECK(rs.code() != rt.code() && rs.code() != 0 && rt.code() != 0);
1472 if (rs.code() < rt.code()) {
1473 GenInstrImmediate(DADDI, rs, rt, offset, CompactBranchType::COMPACT_BRANCH);
1474 } else {
1475 GenInstrImmediate(DADDI, rt, rs, offset, CompactBranchType::COMPACT_BRANCH);
1476 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001477}
1478
1479
1480void Assembler::bnezc(Register rs, int32_t offset) {
1481 DCHECK(kArchVariant == kMips64r6);
1482 DCHECK(!(rs.is(zero_reg)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001483 GenInstrImmediate(POP76, rs, offset, CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001484}
1485
1486
1487void Assembler::j(int64_t target) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001488 BlockTrampolinePoolScope block_trampoline_pool(this);
1489 GenInstrJump(J, static_cast<uint32_t>(target >> 2) & kImm26Mask);
1490 BlockTrampolinePoolFor(1); // For associated delay slot.
1491}
1492
1493
1494void Assembler::j(Label* target) {
1495 uint64_t imm = jump_offset(target);
1496 if (target->is_bound()) {
1497 BlockTrampolinePoolScope block_trampoline_pool(this);
1498 GenInstrJump(static_cast<Opcode>(kJRawMark),
1499 static_cast<uint32_t>(imm >> 2) & kImm26Mask);
1500 BlockTrampolinePoolFor(1); // For associated delay slot.
1501 } else {
1502 j(imm);
1503 }
1504}
1505
1506
1507void Assembler::jal(Label* target) {
1508 uint64_t imm = jump_offset(target);
1509 if (target->is_bound()) {
1510 BlockTrampolinePoolScope block_trampoline_pool(this);
1511 positions_recorder()->WriteRecordedPositions();
1512 GenInstrJump(static_cast<Opcode>(kJalRawMark),
1513 static_cast<uint32_t>(imm >> 2) & kImm26Mask);
1514 BlockTrampolinePoolFor(1); // For associated delay slot.
1515 } else {
1516 jal(imm);
1517 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001518}
1519
1520
1521void Assembler::jr(Register rs) {
1522 if (kArchVariant != kMips64r6) {
1523 BlockTrampolinePoolScope block_trampoline_pool(this);
1524 if (rs.is(ra)) {
1525 positions_recorder()->WriteRecordedPositions();
1526 }
1527 GenInstrRegister(SPECIAL, rs, zero_reg, zero_reg, 0, JR);
1528 BlockTrampolinePoolFor(1); // For associated delay slot.
1529 } else {
1530 jalr(rs, zero_reg);
1531 }
1532}
1533
1534
1535void Assembler::jal(int64_t target) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001536 BlockTrampolinePoolScope block_trampoline_pool(this);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001537 positions_recorder()->WriteRecordedPositions();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001538 GenInstrJump(JAL, static_cast<uint32_t>(target >> 2) & kImm26Mask);
1539 BlockTrampolinePoolFor(1); // For associated delay slot.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001540}
1541
1542
1543void Assembler::jalr(Register rs, Register rd) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001544 DCHECK(rs.code() != rd.code());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001545 BlockTrampolinePoolScope block_trampoline_pool(this);
1546 positions_recorder()->WriteRecordedPositions();
1547 GenInstrRegister(SPECIAL, rs, zero_reg, rd, 0, JALR);
1548 BlockTrampolinePoolFor(1); // For associated delay slot.
1549}
1550
1551
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001552void Assembler::jic(Register rt, int16_t offset) {
1553 DCHECK(kArchVariant == kMips64r6);
1554 GenInstrImmediate(POP66, zero_reg, rt, offset);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001555}
1556
1557
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001558void Assembler::jialc(Register rt, int16_t offset) {
1559 DCHECK(kArchVariant == kMips64r6);
1560 positions_recorder()->WriteRecordedPositions();
1561 GenInstrImmediate(POP76, zero_reg, rt, offset);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001562}
1563
1564
1565// -------Data-processing-instructions---------
1566
1567// Arithmetic.
1568
1569void Assembler::addu(Register rd, Register rs, Register rt) {
1570 GenInstrRegister(SPECIAL, rs, rt, rd, 0, ADDU);
1571}
1572
1573
1574void Assembler::addiu(Register rd, Register rs, int32_t j) {
1575 GenInstrImmediate(ADDIU, rs, rd, j);
1576}
1577
1578
1579void Assembler::subu(Register rd, Register rs, Register rt) {
1580 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SUBU);
1581}
1582
1583
1584void Assembler::mul(Register rd, Register rs, Register rt) {
1585 if (kArchVariant == kMips64r6) {
1586 GenInstrRegister(SPECIAL, rs, rt, rd, MUL_OP, MUL_MUH);
1587 } else {
1588 GenInstrRegister(SPECIAL2, rs, rt, rd, 0, MUL);
1589 }
1590}
1591
1592
1593void Assembler::muh(Register rd, Register rs, Register rt) {
1594 DCHECK(kArchVariant == kMips64r6);
1595 GenInstrRegister(SPECIAL, rs, rt, rd, MUH_OP, MUL_MUH);
1596}
1597
1598
1599void Assembler::mulu(Register rd, Register rs, Register rt) {
1600 DCHECK(kArchVariant == kMips64r6);
1601 GenInstrRegister(SPECIAL, rs, rt, rd, MUL_OP, MUL_MUH_U);
1602}
1603
1604
1605void Assembler::muhu(Register rd, Register rs, Register rt) {
1606 DCHECK(kArchVariant == kMips64r6);
1607 GenInstrRegister(SPECIAL, rs, rt, rd, MUH_OP, MUL_MUH_U);
1608}
1609
1610
1611void Assembler::dmul(Register rd, Register rs, Register rt) {
1612 DCHECK(kArchVariant == kMips64r6);
1613 GenInstrRegister(SPECIAL, rs, rt, rd, MUL_OP, D_MUL_MUH);
1614}
1615
1616
1617void Assembler::dmuh(Register rd, Register rs, Register rt) {
1618 DCHECK(kArchVariant == kMips64r6);
1619 GenInstrRegister(SPECIAL, rs, rt, rd, MUH_OP, D_MUL_MUH);
1620}
1621
1622
1623void Assembler::dmulu(Register rd, Register rs, Register rt) {
1624 DCHECK(kArchVariant == kMips64r6);
1625 GenInstrRegister(SPECIAL, rs, rt, rd, MUL_OP, D_MUL_MUH_U);
1626}
1627
1628
1629void Assembler::dmuhu(Register rd, Register rs, Register rt) {
1630 DCHECK(kArchVariant == kMips64r6);
1631 GenInstrRegister(SPECIAL, rs, rt, rd, MUH_OP, D_MUL_MUH_U);
1632}
1633
1634
1635void Assembler::mult(Register rs, Register rt) {
1636 DCHECK(kArchVariant != kMips64r6);
1637 GenInstrRegister(SPECIAL, rs, rt, zero_reg, 0, MULT);
1638}
1639
1640
1641void Assembler::multu(Register rs, Register rt) {
1642 DCHECK(kArchVariant != kMips64r6);
1643 GenInstrRegister(SPECIAL, rs, rt, zero_reg, 0, MULTU);
1644}
1645
1646
1647void Assembler::daddiu(Register rd, Register rs, int32_t j) {
1648 GenInstrImmediate(DADDIU, rs, rd, j);
1649}
1650
1651
1652void Assembler::div(Register rs, Register rt) {
1653 GenInstrRegister(SPECIAL, rs, rt, zero_reg, 0, DIV);
1654}
1655
1656
1657void Assembler::div(Register rd, Register rs, Register rt) {
1658 DCHECK(kArchVariant == kMips64r6);
1659 GenInstrRegister(SPECIAL, rs, rt, rd, DIV_OP, DIV_MOD);
1660}
1661
1662
1663void Assembler::mod(Register rd, Register rs, Register rt) {
1664 DCHECK(kArchVariant == kMips64r6);
1665 GenInstrRegister(SPECIAL, rs, rt, rd, MOD_OP, DIV_MOD);
1666}
1667
1668
1669void Assembler::divu(Register rs, Register rt) {
1670 GenInstrRegister(SPECIAL, rs, rt, zero_reg, 0, DIVU);
1671}
1672
1673
1674void Assembler::divu(Register rd, Register rs, Register rt) {
1675 DCHECK(kArchVariant == kMips64r6);
1676 GenInstrRegister(SPECIAL, rs, rt, rd, DIV_OP, DIV_MOD_U);
1677}
1678
1679
1680void Assembler::modu(Register rd, Register rs, Register rt) {
1681 DCHECK(kArchVariant == kMips64r6);
1682 GenInstrRegister(SPECIAL, rs, rt, rd, MOD_OP, DIV_MOD_U);
1683}
1684
1685
1686void Assembler::daddu(Register rd, Register rs, Register rt) {
1687 GenInstrRegister(SPECIAL, rs, rt, rd, 0, DADDU);
1688}
1689
1690
1691void Assembler::dsubu(Register rd, Register rs, Register rt) {
1692 GenInstrRegister(SPECIAL, rs, rt, rd, 0, DSUBU);
1693}
1694
1695
1696void Assembler::dmult(Register rs, Register rt) {
1697 GenInstrRegister(SPECIAL, rs, rt, zero_reg, 0, DMULT);
1698}
1699
1700
1701void Assembler::dmultu(Register rs, Register rt) {
1702 GenInstrRegister(SPECIAL, rs, rt, zero_reg, 0, DMULTU);
1703}
1704
1705
1706void Assembler::ddiv(Register rs, Register rt) {
1707 GenInstrRegister(SPECIAL, rs, rt, zero_reg, 0, DDIV);
1708}
1709
1710
1711void Assembler::ddiv(Register rd, Register rs, Register rt) {
1712 DCHECK(kArchVariant == kMips64r6);
1713 GenInstrRegister(SPECIAL, rs, rt, rd, DIV_OP, D_DIV_MOD);
1714}
1715
1716
1717void Assembler::dmod(Register rd, Register rs, Register rt) {
1718 DCHECK(kArchVariant == kMips64r6);
1719 GenInstrRegister(SPECIAL, rs, rt, rd, MOD_OP, D_DIV_MOD);
1720}
1721
1722
1723void Assembler::ddivu(Register rs, Register rt) {
1724 GenInstrRegister(SPECIAL, rs, rt, zero_reg, 0, DDIVU);
1725}
1726
1727
1728void Assembler::ddivu(Register rd, Register rs, Register rt) {
1729 DCHECK(kArchVariant == kMips64r6);
1730 GenInstrRegister(SPECIAL, rs, rt, rd, DIV_OP, D_DIV_MOD_U);
1731}
1732
1733
1734void Assembler::dmodu(Register rd, Register rs, Register rt) {
1735 DCHECK(kArchVariant == kMips64r6);
1736 GenInstrRegister(SPECIAL, rs, rt, rd, MOD_OP, D_DIV_MOD_U);
1737}
1738
1739
1740// Logical.
1741
1742void Assembler::and_(Register rd, Register rs, Register rt) {
1743 GenInstrRegister(SPECIAL, rs, rt, rd, 0, AND);
1744}
1745
1746
1747void Assembler::andi(Register rt, Register rs, int32_t j) {
1748 DCHECK(is_uint16(j));
1749 GenInstrImmediate(ANDI, rs, rt, j);
1750}
1751
1752
1753void Assembler::or_(Register rd, Register rs, Register rt) {
1754 GenInstrRegister(SPECIAL, rs, rt, rd, 0, OR);
1755}
1756
1757
1758void Assembler::ori(Register rt, Register rs, int32_t j) {
1759 DCHECK(is_uint16(j));
1760 GenInstrImmediate(ORI, rs, rt, j);
1761}
1762
1763
1764void Assembler::xor_(Register rd, Register rs, Register rt) {
1765 GenInstrRegister(SPECIAL, rs, rt, rd, 0, XOR);
1766}
1767
1768
1769void Assembler::xori(Register rt, Register rs, int32_t j) {
1770 DCHECK(is_uint16(j));
1771 GenInstrImmediate(XORI, rs, rt, j);
1772}
1773
1774
1775void Assembler::nor(Register rd, Register rs, Register rt) {
1776 GenInstrRegister(SPECIAL, rs, rt, rd, 0, NOR);
1777}
1778
1779
1780// Shifts.
1781void Assembler::sll(Register rd,
1782 Register rt,
1783 uint16_t sa,
1784 bool coming_from_nop) {
1785 // Don't allow nop instructions in the form sll zero_reg, zero_reg to be
1786 // generated using the sll instruction. They must be generated using
1787 // nop(int/NopMarkerTypes) or MarkCode(int/NopMarkerTypes) pseudo
1788 // instructions.
1789 DCHECK(coming_from_nop || !(rd.is(zero_reg) && rt.is(zero_reg)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001790 GenInstrRegister(SPECIAL, zero_reg, rt, rd, sa & 0x1F, SLL);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001791}
1792
1793
1794void Assembler::sllv(Register rd, Register rt, Register rs) {
1795 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SLLV);
1796}
1797
1798
1799void Assembler::srl(Register rd, Register rt, uint16_t sa) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001800 GenInstrRegister(SPECIAL, zero_reg, rt, rd, sa & 0x1F, SRL);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001801}
1802
1803
1804void Assembler::srlv(Register rd, Register rt, Register rs) {
1805 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SRLV);
1806}
1807
1808
1809void Assembler::sra(Register rd, Register rt, uint16_t sa) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001810 GenInstrRegister(SPECIAL, zero_reg, rt, rd, sa & 0x1F, SRA);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001811}
1812
1813
1814void Assembler::srav(Register rd, Register rt, Register rs) {
1815 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SRAV);
1816}
1817
1818
1819void Assembler::rotr(Register rd, Register rt, uint16_t sa) {
1820 // Should be called via MacroAssembler::Ror.
1821 DCHECK(rd.is_valid() && rt.is_valid() && is_uint5(sa));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001822 DCHECK(kArchVariant == kMips64r2 || kArchVariant == kMips64r6);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001823 Instr instr = SPECIAL | (1 << kRsShift) | (rt.code() << kRtShift)
1824 | (rd.code() << kRdShift) | (sa << kSaShift) | SRL;
1825 emit(instr);
1826}
1827
1828
1829void Assembler::rotrv(Register rd, Register rt, Register rs) {
1830 // Should be called via MacroAssembler::Ror.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001831 DCHECK(rd.is_valid() && rt.is_valid() && rs.is_valid());
1832 DCHECK(kArchVariant == kMips64r2 || kArchVariant == kMips64r6);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001833 Instr instr = SPECIAL | (rs.code() << kRsShift) | (rt.code() << kRtShift)
1834 | (rd.code() << kRdShift) | (1 << kSaShift) | SRLV;
1835 emit(instr);
1836}
1837
1838
1839void Assembler::dsll(Register rd, Register rt, uint16_t sa) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001840 GenInstrRegister(SPECIAL, zero_reg, rt, rd, sa & 0x1F, DSLL);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001841}
1842
1843
1844void Assembler::dsllv(Register rd, Register rt, Register rs) {
1845 GenInstrRegister(SPECIAL, rs, rt, rd, 0, DSLLV);
1846}
1847
1848
1849void Assembler::dsrl(Register rd, Register rt, uint16_t sa) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001850 GenInstrRegister(SPECIAL, zero_reg, rt, rd, sa & 0x1F, DSRL);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001851}
1852
1853
1854void Assembler::dsrlv(Register rd, Register rt, Register rs) {
1855 GenInstrRegister(SPECIAL, rs, rt, rd, 0, DSRLV);
1856}
1857
1858
1859void Assembler::drotr(Register rd, Register rt, uint16_t sa) {
1860 DCHECK(rd.is_valid() && rt.is_valid() && is_uint5(sa));
1861 Instr instr = SPECIAL | (1 << kRsShift) | (rt.code() << kRtShift)
1862 | (rd.code() << kRdShift) | (sa << kSaShift) | DSRL;
1863 emit(instr);
1864}
1865
1866
1867void Assembler::drotrv(Register rd, Register rt, Register rs) {
1868 DCHECK(rd.is_valid() && rt.is_valid() && rs.is_valid() );
1869 Instr instr = SPECIAL | (rs.code() << kRsShift) | (rt.code() << kRtShift)
1870 | (rd.code() << kRdShift) | (1 << kSaShift) | DSRLV;
1871 emit(instr);
1872}
1873
1874
1875void Assembler::dsra(Register rd, Register rt, uint16_t sa) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001876 GenInstrRegister(SPECIAL, zero_reg, rt, rd, sa & 0x1F, DSRA);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001877}
1878
1879
1880void Assembler::dsrav(Register rd, Register rt, Register rs) {
1881 GenInstrRegister(SPECIAL, rs, rt, rd, 0, DSRAV);
1882}
1883
1884
1885void Assembler::dsll32(Register rd, Register rt, uint16_t sa) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001886 GenInstrRegister(SPECIAL, zero_reg, rt, rd, sa & 0x1F, DSLL32);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001887}
1888
1889
1890void Assembler::dsrl32(Register rd, Register rt, uint16_t sa) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001891 GenInstrRegister(SPECIAL, zero_reg, rt, rd, sa & 0x1F, DSRL32);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001892}
1893
1894
1895void Assembler::dsra32(Register rd, Register rt, uint16_t sa) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001896 GenInstrRegister(SPECIAL, zero_reg, rt, rd, sa & 0x1F, DSRA32);
1897}
1898
1899
1900void Assembler::lsa(Register rd, Register rt, Register rs, uint8_t sa) {
1901 DCHECK(rd.is_valid() && rt.is_valid() && rs.is_valid());
1902 DCHECK(sa < 5 && sa > 0);
1903 DCHECK(kArchVariant == kMips64r6);
1904 Instr instr = SPECIAL | (rs.code() << kRsShift) | (rt.code() << kRtShift) |
1905 (rd.code() << kRdShift) | (sa - 1) << kSaShift | LSA;
1906 emit(instr);
1907}
1908
1909
1910void Assembler::dlsa(Register rd, Register rt, Register rs, uint8_t sa) {
1911 DCHECK(rd.is_valid() && rt.is_valid() && rs.is_valid());
1912 DCHECK(sa < 5 && sa > 0);
1913 DCHECK(kArchVariant == kMips64r6);
1914 Instr instr = SPECIAL | (rs.code() << kRsShift) | (rt.code() << kRtShift) |
1915 (rd.code() << kRdShift) | (sa - 1) << kSaShift | DLSA;
1916 emit(instr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001917}
1918
1919
1920// ------------Memory-instructions-------------
1921
1922// Helper for base-reg + offset, when offset is larger than int16.
1923void Assembler::LoadRegPlusOffsetToAt(const MemOperand& src) {
1924 DCHECK(!src.rm().is(at));
1925 DCHECK(is_int32(src.offset_));
1926 daddiu(at, zero_reg, (src.offset_ >> kLuiShift) & kImm16Mask);
1927 dsll(at, at, kLuiShift);
1928 ori(at, at, src.offset_ & kImm16Mask); // Load 32-bit offset.
1929 daddu(at, at, src.rm()); // Add base register.
1930}
1931
1932
1933void Assembler::lb(Register rd, const MemOperand& rs) {
1934 if (is_int16(rs.offset_)) {
1935 GenInstrImmediate(LB, rs.rm(), rd, rs.offset_);
1936 } else { // Offset > 16 bits, use multiple instructions to load.
1937 LoadRegPlusOffsetToAt(rs);
1938 GenInstrImmediate(LB, at, rd, 0); // Equiv to lb(rd, MemOperand(at, 0));
1939 }
1940}
1941
1942
1943void Assembler::lbu(Register rd, const MemOperand& rs) {
1944 if (is_int16(rs.offset_)) {
1945 GenInstrImmediate(LBU, rs.rm(), rd, rs.offset_);
1946 } else { // Offset > 16 bits, use multiple instructions to load.
1947 LoadRegPlusOffsetToAt(rs);
1948 GenInstrImmediate(LBU, at, rd, 0); // Equiv to lbu(rd, MemOperand(at, 0));
1949 }
1950}
1951
1952
1953void Assembler::lh(Register rd, const MemOperand& rs) {
1954 if (is_int16(rs.offset_)) {
1955 GenInstrImmediate(LH, rs.rm(), rd, rs.offset_);
1956 } else { // Offset > 16 bits, use multiple instructions to load.
1957 LoadRegPlusOffsetToAt(rs);
1958 GenInstrImmediate(LH, at, rd, 0); // Equiv to lh(rd, MemOperand(at, 0));
1959 }
1960}
1961
1962
1963void Assembler::lhu(Register rd, const MemOperand& rs) {
1964 if (is_int16(rs.offset_)) {
1965 GenInstrImmediate(LHU, rs.rm(), rd, rs.offset_);
1966 } else { // Offset > 16 bits, use multiple instructions to load.
1967 LoadRegPlusOffsetToAt(rs);
1968 GenInstrImmediate(LHU, at, rd, 0); // Equiv to lhu(rd, MemOperand(at, 0));
1969 }
1970}
1971
1972
1973void Assembler::lw(Register rd, const MemOperand& rs) {
1974 if (is_int16(rs.offset_)) {
1975 GenInstrImmediate(LW, rs.rm(), rd, rs.offset_);
1976 } else { // Offset > 16 bits, use multiple instructions to load.
1977 LoadRegPlusOffsetToAt(rs);
1978 GenInstrImmediate(LW, at, rd, 0); // Equiv to lw(rd, MemOperand(at, 0));
1979 }
1980}
1981
1982
1983void Assembler::lwu(Register rd, const MemOperand& rs) {
1984 if (is_int16(rs.offset_)) {
1985 GenInstrImmediate(LWU, rs.rm(), rd, rs.offset_);
1986 } else { // Offset > 16 bits, use multiple instructions to load.
1987 LoadRegPlusOffsetToAt(rs);
1988 GenInstrImmediate(LWU, at, rd, 0); // Equiv to lwu(rd, MemOperand(at, 0));
1989 }
1990}
1991
1992
1993void Assembler::lwl(Register rd, const MemOperand& rs) {
1994 GenInstrImmediate(LWL, rs.rm(), rd, rs.offset_);
1995}
1996
1997
1998void Assembler::lwr(Register rd, const MemOperand& rs) {
1999 GenInstrImmediate(LWR, rs.rm(), rd, rs.offset_);
2000}
2001
2002
2003void Assembler::sb(Register rd, const MemOperand& rs) {
2004 if (is_int16(rs.offset_)) {
2005 GenInstrImmediate(SB, rs.rm(), rd, rs.offset_);
2006 } else { // Offset > 16 bits, use multiple instructions to store.
2007 LoadRegPlusOffsetToAt(rs);
2008 GenInstrImmediate(SB, at, rd, 0); // Equiv to sb(rd, MemOperand(at, 0));
2009 }
2010}
2011
2012
2013void Assembler::sh(Register rd, const MemOperand& rs) {
2014 if (is_int16(rs.offset_)) {
2015 GenInstrImmediate(SH, rs.rm(), rd, rs.offset_);
2016 } else { // Offset > 16 bits, use multiple instructions to store.
2017 LoadRegPlusOffsetToAt(rs);
2018 GenInstrImmediate(SH, at, rd, 0); // Equiv to sh(rd, MemOperand(at, 0));
2019 }
2020}
2021
2022
2023void Assembler::sw(Register rd, const MemOperand& rs) {
2024 if (is_int16(rs.offset_)) {
2025 GenInstrImmediate(SW, rs.rm(), rd, rs.offset_);
2026 } else { // Offset > 16 bits, use multiple instructions to store.
2027 LoadRegPlusOffsetToAt(rs);
2028 GenInstrImmediate(SW, at, rd, 0); // Equiv to sw(rd, MemOperand(at, 0));
2029 }
2030}
2031
2032
2033void Assembler::swl(Register rd, const MemOperand& rs) {
2034 GenInstrImmediate(SWL, rs.rm(), rd, rs.offset_);
2035}
2036
2037
2038void Assembler::swr(Register rd, const MemOperand& rs) {
2039 GenInstrImmediate(SWR, rs.rm(), rd, rs.offset_);
2040}
2041
2042
2043void Assembler::lui(Register rd, int32_t j) {
2044 DCHECK(is_uint16(j));
2045 GenInstrImmediate(LUI, zero_reg, rd, j);
2046}
2047
2048
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002049void Assembler::aui(Register rt, Register rs, int32_t j) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002050 // This instruction uses same opcode as 'lui'. The difference in encoding is
2051 // 'lui' has zero reg. for rs field.
2052 DCHECK(is_uint16(j));
2053 GenInstrImmediate(LUI, rs, rt, j);
2054}
2055
2056
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002057void Assembler::daui(Register rt, Register rs, int32_t j) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002058 DCHECK(is_uint16(j));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002059 DCHECK(!rs.is(zero_reg));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002060 GenInstrImmediate(DAUI, rs, rt, j);
2061}
2062
2063
2064void Assembler::dahi(Register rs, int32_t j) {
2065 DCHECK(is_uint16(j));
2066 GenInstrImmediate(REGIMM, rs, DAHI, j);
2067}
2068
2069
2070void Assembler::dati(Register rs, int32_t j) {
2071 DCHECK(is_uint16(j));
2072 GenInstrImmediate(REGIMM, rs, DATI, j);
2073}
2074
2075
2076void Assembler::ldl(Register rd, const MemOperand& rs) {
2077 GenInstrImmediate(LDL, rs.rm(), rd, rs.offset_);
2078}
2079
2080
2081void Assembler::ldr(Register rd, const MemOperand& rs) {
2082 GenInstrImmediate(LDR, rs.rm(), rd, rs.offset_);
2083}
2084
2085
2086void Assembler::sdl(Register rd, const MemOperand& rs) {
2087 GenInstrImmediate(SDL, rs.rm(), rd, rs.offset_);
2088}
2089
2090
2091void Assembler::sdr(Register rd, const MemOperand& rs) {
2092 GenInstrImmediate(SDR, rs.rm(), rd, rs.offset_);
2093}
2094
2095
2096void Assembler::ld(Register rd, const MemOperand& rs) {
2097 if (is_int16(rs.offset_)) {
2098 GenInstrImmediate(LD, rs.rm(), rd, rs.offset_);
2099 } else { // Offset > 16 bits, use multiple instructions to load.
2100 LoadRegPlusOffsetToAt(rs);
2101 GenInstrImmediate(LD, at, rd, 0); // Equiv to lw(rd, MemOperand(at, 0));
2102 }
2103}
2104
2105
2106void Assembler::sd(Register rd, const MemOperand& rs) {
2107 if (is_int16(rs.offset_)) {
2108 GenInstrImmediate(SD, rs.rm(), rd, rs.offset_);
2109 } else { // Offset > 16 bits, use multiple instructions to store.
2110 LoadRegPlusOffsetToAt(rs);
2111 GenInstrImmediate(SD, at, rd, 0); // Equiv to sw(rd, MemOperand(at, 0));
2112 }
2113}
2114
2115
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002116// ---------PC-Relative instructions-----------
2117
2118void Assembler::addiupc(Register rs, int32_t imm19) {
2119 DCHECK(kArchVariant == kMips64r6);
2120 DCHECK(rs.is_valid() && is_int19(imm19));
2121 uint32_t imm21 = ADDIUPC << kImm19Bits | (imm19 & kImm19Mask);
2122 GenInstrImmediate(PCREL, rs, imm21);
2123}
2124
2125
2126void Assembler::lwpc(Register rs, int32_t offset19) {
2127 DCHECK(kArchVariant == kMips64r6);
2128 DCHECK(rs.is_valid() && is_int19(offset19));
2129 uint32_t imm21 = LWPC << kImm19Bits | (offset19 & kImm19Mask);
2130 GenInstrImmediate(PCREL, rs, imm21);
2131}
2132
2133
2134void Assembler::lwupc(Register rs, int32_t offset19) {
2135 DCHECK(kArchVariant == kMips64r6);
2136 DCHECK(rs.is_valid() && is_int19(offset19));
2137 uint32_t imm21 = LWUPC << kImm19Bits | (offset19 & kImm19Mask);
2138 GenInstrImmediate(PCREL, rs, imm21);
2139}
2140
2141
2142void Assembler::ldpc(Register rs, int32_t offset18) {
2143 DCHECK(kArchVariant == kMips64r6);
2144 DCHECK(rs.is_valid() && is_int18(offset18));
2145 uint32_t imm21 = LDPC << kImm18Bits | (offset18 & kImm18Mask);
2146 GenInstrImmediate(PCREL, rs, imm21);
2147}
2148
2149
2150void Assembler::auipc(Register rs, int16_t imm16) {
2151 DCHECK(kArchVariant == kMips64r6);
2152 DCHECK(rs.is_valid());
2153 uint32_t imm21 = AUIPC << kImm16Bits | (imm16 & kImm16Mask);
2154 GenInstrImmediate(PCREL, rs, imm21);
2155}
2156
2157
2158void Assembler::aluipc(Register rs, int16_t imm16) {
2159 DCHECK(kArchVariant == kMips64r6);
2160 DCHECK(rs.is_valid());
2161 uint32_t imm21 = ALUIPC << kImm16Bits | (imm16 & kImm16Mask);
2162 GenInstrImmediate(PCREL, rs, imm21);
2163}
2164
2165
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002166// -------------Misc-instructions--------------
2167
2168// Break / Trap instructions.
2169void Assembler::break_(uint32_t code, bool break_as_stop) {
2170 DCHECK((code & ~0xfffff) == 0);
2171 // We need to invalidate breaks that could be stops as well because the
2172 // simulator expects a char pointer after the stop instruction.
2173 // See constants-mips.h for explanation.
2174 DCHECK((break_as_stop &&
2175 code <= kMaxStopCode &&
2176 code > kMaxWatchpointCode) ||
2177 (!break_as_stop &&
2178 (code > kMaxStopCode ||
2179 code <= kMaxWatchpointCode)));
2180 Instr break_instr = SPECIAL | BREAK | (code << 6);
2181 emit(break_instr);
2182}
2183
2184
2185void Assembler::stop(const char* msg, uint32_t code) {
2186 DCHECK(code > kMaxWatchpointCode);
2187 DCHECK(code <= kMaxStopCode);
2188#if defined(V8_HOST_ARCH_MIPS) || defined(V8_HOST_ARCH_MIPS64)
2189 break_(0x54321);
2190#else // V8_HOST_ARCH_MIPS
2191 BlockTrampolinePoolFor(3);
2192 // The Simulator will handle the stop instruction and get the message address.
2193 // On MIPS stop() is just a special kind of break_().
2194 break_(code, true);
2195 emit(reinterpret_cast<uint64_t>(msg));
2196#endif
2197}
2198
2199
2200void Assembler::tge(Register rs, Register rt, uint16_t code) {
2201 DCHECK(is_uint10(code));
2202 Instr instr = SPECIAL | TGE | rs.code() << kRsShift
2203 | rt.code() << kRtShift | code << 6;
2204 emit(instr);
2205}
2206
2207
2208void Assembler::tgeu(Register rs, Register rt, uint16_t code) {
2209 DCHECK(is_uint10(code));
2210 Instr instr = SPECIAL | TGEU | rs.code() << kRsShift
2211 | rt.code() << kRtShift | code << 6;
2212 emit(instr);
2213}
2214
2215
2216void Assembler::tlt(Register rs, Register rt, uint16_t code) {
2217 DCHECK(is_uint10(code));
2218 Instr instr =
2219 SPECIAL | TLT | rs.code() << kRsShift | rt.code() << kRtShift | code << 6;
2220 emit(instr);
2221}
2222
2223
2224void Assembler::tltu(Register rs, Register rt, uint16_t code) {
2225 DCHECK(is_uint10(code));
2226 Instr instr =
2227 SPECIAL | TLTU | rs.code() << kRsShift
2228 | rt.code() << kRtShift | code << 6;
2229 emit(instr);
2230}
2231
2232
2233void Assembler::teq(Register rs, Register rt, uint16_t code) {
2234 DCHECK(is_uint10(code));
2235 Instr instr =
2236 SPECIAL | TEQ | rs.code() << kRsShift | rt.code() << kRtShift | code << 6;
2237 emit(instr);
2238}
2239
2240
2241void Assembler::tne(Register rs, Register rt, uint16_t code) {
2242 DCHECK(is_uint10(code));
2243 Instr instr =
2244 SPECIAL | TNE | rs.code() << kRsShift | rt.code() << kRtShift | code << 6;
2245 emit(instr);
2246}
2247
2248
2249// Move from HI/LO register.
2250
2251void Assembler::mfhi(Register rd) {
2252 GenInstrRegister(SPECIAL, zero_reg, zero_reg, rd, 0, MFHI);
2253}
2254
2255
2256void Assembler::mflo(Register rd) {
2257 GenInstrRegister(SPECIAL, zero_reg, zero_reg, rd, 0, MFLO);
2258}
2259
2260
2261// Set on less than instructions.
2262void Assembler::slt(Register rd, Register rs, Register rt) {
2263 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SLT);
2264}
2265
2266
2267void Assembler::sltu(Register rd, Register rs, Register rt) {
2268 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SLTU);
2269}
2270
2271
2272void Assembler::slti(Register rt, Register rs, int32_t j) {
2273 GenInstrImmediate(SLTI, rs, rt, j);
2274}
2275
2276
2277void Assembler::sltiu(Register rt, Register rs, int32_t j) {
2278 GenInstrImmediate(SLTIU, rs, rt, j);
2279}
2280
2281
2282// Conditional move.
2283void Assembler::movz(Register rd, Register rs, Register rt) {
2284 GenInstrRegister(SPECIAL, rs, rt, rd, 0, MOVZ);
2285}
2286
2287
2288void Assembler::movn(Register rd, Register rs, Register rt) {
2289 GenInstrRegister(SPECIAL, rs, rt, rd, 0, MOVN);
2290}
2291
2292
2293void Assembler::movt(Register rd, Register rs, uint16_t cc) {
2294 Register rt;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002295 rt.reg_code = (cc & 0x0007) << 2 | 1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002296 GenInstrRegister(SPECIAL, rs, rt, rd, 0, MOVCI);
2297}
2298
2299
2300void Assembler::movf(Register rd, Register rs, uint16_t cc) {
2301 Register rt;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002302 rt.reg_code = (cc & 0x0007) << 2 | 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002303 GenInstrRegister(SPECIAL, rs, rt, rd, 0, MOVCI);
2304}
2305
2306
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002307void Assembler::min_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2308 min(S, fd, fs, ft);
2309}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002310
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002311
2312void Assembler::min_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2313 min(D, fd, fs, ft);
2314}
2315
2316
2317void Assembler::max_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2318 max(S, fd, fs, ft);
2319}
2320
2321
2322void Assembler::max_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2323 max(D, fd, fs, ft);
2324}
2325
2326
2327void Assembler::mina_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2328 mina(S, fd, fs, ft);
2329}
2330
2331
2332void Assembler::mina_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2333 mina(D, fd, fs, ft);
2334}
2335
2336
2337void Assembler::maxa_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2338 maxa(S, fd, fs, ft);
2339}
2340
2341
2342void Assembler::maxa_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2343 maxa(D, fd, fs, ft);
2344}
2345
2346
2347void Assembler::max(SecondaryField fmt, FPURegister fd, FPURegister fs,
2348 FPURegister ft) {
2349 DCHECK(kArchVariant == kMips64r6);
2350 DCHECK((fmt == D) || (fmt == S));
2351 GenInstrRegister(COP1, fmt, ft, fs, fd, MAX);
2352}
2353
2354
2355void Assembler::min(SecondaryField fmt, FPURegister fd, FPURegister fs,
2356 FPURegister ft) {
2357 DCHECK(kArchVariant == kMips64r6);
2358 DCHECK((fmt == D) || (fmt == S));
2359 GenInstrRegister(COP1, fmt, ft, fs, fd, MIN);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002360}
2361
2362
2363// GPR.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002364void Assembler::seleqz(Register rd, Register rs, Register rt) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002365 DCHECK(kArchVariant == kMips64r6);
2366 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SELEQZ_S);
2367}
2368
2369
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002370// GPR.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002371void Assembler::selnez(Register rd, Register rs, Register rt) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002372 DCHECK(kArchVariant == kMips64r6);
2373 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SELNEZ_S);
2374}
2375
2376
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002377// Bit twiddling.
2378void Assembler::clz(Register rd, Register rs) {
2379 if (kArchVariant != kMips64r6) {
2380 // Clz instr requires same GPR number in 'rd' and 'rt' fields.
2381 GenInstrRegister(SPECIAL2, rs, rd, rd, 0, CLZ);
2382 } else {
2383 GenInstrRegister(SPECIAL, rs, zero_reg, rd, 1, CLZ_R6);
2384 }
2385}
2386
2387
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002388void Assembler::dclz(Register rd, Register rs) {
2389 if (kArchVariant != kMips64r6) {
2390 // dclz instr requires same GPR number in 'rd' and 'rt' fields.
2391 GenInstrRegister(SPECIAL2, rs, rd, rd, 0, DCLZ);
2392 } else {
2393 GenInstrRegister(SPECIAL, rs, zero_reg, rd, 1, DCLZ_R6);
2394 }
2395}
2396
2397
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002398void Assembler::ins_(Register rt, Register rs, uint16_t pos, uint16_t size) {
2399 // Should be called via MacroAssembler::Ins.
2400 // Ins instr has 'rt' field as dest, and two uint5: msb, lsb.
2401 DCHECK((kArchVariant == kMips64r2) || (kArchVariant == kMips64r6));
2402 GenInstrRegister(SPECIAL3, rs, rt, pos + size - 1, pos, INS);
2403}
2404
2405
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002406void Assembler::dins_(Register rt, Register rs, uint16_t pos, uint16_t size) {
2407 // Should be called via MacroAssembler::Dins.
2408 // Dext instr has 'rt' field as dest, and two uint5: msb, lsb.
2409 DCHECK(kArchVariant == kMips64r2 || kArchVariant == kMips64r6);
2410 GenInstrRegister(SPECIAL3, rs, rt, pos + size - 1, pos, DINS);
2411}
2412
2413
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002414void Assembler::ext_(Register rt, Register rs, uint16_t pos, uint16_t size) {
2415 // Should be called via MacroAssembler::Ext.
2416 // Ext instr has 'rt' field as dest, and two uint5: msb, lsb.
2417 DCHECK(kArchVariant == kMips64r2 || kArchVariant == kMips64r6);
2418 GenInstrRegister(SPECIAL3, rs, rt, size - 1, pos, EXT);
2419}
2420
2421
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002422void Assembler::dext_(Register rt, Register rs, uint16_t pos, uint16_t size) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002423 // Should be called via MacroAssembler::Dext.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002424 // Dext instr has 'rt' field as dest, and two uint5: msb, lsb.
2425 DCHECK(kArchVariant == kMips64r2 || kArchVariant == kMips64r6);
2426 GenInstrRegister(SPECIAL3, rs, rt, size - 1, pos, DEXT);
2427}
2428
2429
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002430void Assembler::dextm(Register rt, Register rs, uint16_t pos, uint16_t size) {
2431 // Should be called via MacroAssembler::Dextm.
2432 // Dextm instr has 'rt' field as dest, and two uint5: msb, lsb.
2433 DCHECK(kArchVariant == kMips64r2 || kArchVariant == kMips64r6);
2434 GenInstrRegister(SPECIAL3, rs, rt, size - 1 - 32, pos, DEXTM);
2435}
2436
2437
2438void Assembler::dextu(Register rt, Register rs, uint16_t pos, uint16_t size) {
2439 // Should be called via MacroAssembler::Dextu.
2440 // Dext instr has 'rt' field as dest, and two uint5: msb, lsb.
2441 DCHECK(kArchVariant == kMips64r2 || kArchVariant == kMips64r6);
2442 GenInstrRegister(SPECIAL3, rs, rt, size - 1, pos - 32, DEXTU);
2443}
2444
2445
2446void Assembler::bitswap(Register rd, Register rt) {
2447 DCHECK(kArchVariant == kMips64r6);
2448 GenInstrRegister(SPECIAL3, zero_reg, rt, rd, 0, BSHFL);
2449}
2450
2451
2452void Assembler::dbitswap(Register rd, Register rt) {
2453 DCHECK(kArchVariant == kMips64r6);
2454 GenInstrRegister(SPECIAL3, zero_reg, rt, rd, 0, DBSHFL);
2455}
2456
2457
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002458void Assembler::pref(int32_t hint, const MemOperand& rs) {
2459 DCHECK(is_uint5(hint) && is_uint16(rs.offset_));
2460 Instr instr = PREF | (rs.rm().code() << kRsShift) | (hint << kRtShift)
2461 | (rs.offset_);
2462 emit(instr);
2463}
2464
2465
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002466void Assembler::align(Register rd, Register rs, Register rt, uint8_t bp) {
2467 DCHECK(kArchVariant == kMips64r6);
2468 DCHECK(is_uint3(bp));
2469 uint16_t sa = (ALIGN << kBp2Bits) | bp;
2470 GenInstrRegister(SPECIAL3, rs, rt, rd, sa, BSHFL);
2471}
2472
2473
2474void Assembler::dalign(Register rd, Register rs, Register rt, uint8_t bp) {
2475 DCHECK(kArchVariant == kMips64r6);
2476 DCHECK(is_uint3(bp));
2477 uint16_t sa = (DALIGN << kBp3Bits) | bp;
2478 GenInstrRegister(SPECIAL3, rs, rt, rd, sa, DBSHFL);
2479}
2480
2481
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002482// --------Coprocessor-instructions----------------
2483
2484// Load, store, move.
2485void Assembler::lwc1(FPURegister fd, const MemOperand& src) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002486 if (is_int16(src.offset_)) {
2487 GenInstrImmediate(LWC1, src.rm(), fd, src.offset_);
2488 } else { // Offset > 16 bits, use multiple instructions to load.
2489 LoadRegPlusOffsetToAt(src);
2490 GenInstrImmediate(LWC1, at, fd, 0);
2491 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002492}
2493
2494
2495void Assembler::ldc1(FPURegister fd, const MemOperand& src) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002496 DCHECK(!src.rm().is(at));
2497 if (is_int16(src.offset_)) {
2498 GenInstrImmediate(LDC1, src.rm(), fd, src.offset_);
2499 } else { // Offset > 16 bits, use multiple instructions to load.
2500 LoadRegPlusOffsetToAt(src);
2501 GenInstrImmediate(LDC1, at, fd, 0);
2502 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002503}
2504
2505
2506void Assembler::swc1(FPURegister fd, const MemOperand& src) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002507 if (is_int16(src.offset_)) {
2508 GenInstrImmediate(SWC1, src.rm(), fd, src.offset_);
2509 } else { // Offset > 16 bits, use multiple instructions to load.
2510 LoadRegPlusOffsetToAt(src);
2511 GenInstrImmediate(SWC1, at, fd, 0);
2512 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002513}
2514
2515
2516void Assembler::sdc1(FPURegister fd, const MemOperand& src) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002517 DCHECK(!src.rm().is(at));
2518 if (is_int16(src.offset_)) {
2519 GenInstrImmediate(SDC1, src.rm(), fd, src.offset_);
2520 } else { // Offset > 16 bits, use multiple instructions to load.
2521 LoadRegPlusOffsetToAt(src);
2522 GenInstrImmediate(SDC1, at, fd, 0);
2523 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002524}
2525
2526
2527void Assembler::mtc1(Register rt, FPURegister fs) {
2528 GenInstrRegister(COP1, MTC1, rt, fs, f0);
2529}
2530
2531
2532void Assembler::mthc1(Register rt, FPURegister fs) {
2533 GenInstrRegister(COP1, MTHC1, rt, fs, f0);
2534}
2535
2536
2537void Assembler::dmtc1(Register rt, FPURegister fs) {
2538 GenInstrRegister(COP1, DMTC1, rt, fs, f0);
2539}
2540
2541
2542void Assembler::mfc1(Register rt, FPURegister fs) {
2543 GenInstrRegister(COP1, MFC1, rt, fs, f0);
2544}
2545
2546
2547void Assembler::mfhc1(Register rt, FPURegister fs) {
2548 GenInstrRegister(COP1, MFHC1, rt, fs, f0);
2549}
2550
2551
2552void Assembler::dmfc1(Register rt, FPURegister fs) {
2553 GenInstrRegister(COP1, DMFC1, rt, fs, f0);
2554}
2555
2556
2557void Assembler::ctc1(Register rt, FPUControlRegister fs) {
2558 GenInstrRegister(COP1, CTC1, rt, fs);
2559}
2560
2561
2562void Assembler::cfc1(Register rt, FPUControlRegister fs) {
2563 GenInstrRegister(COP1, CFC1, rt, fs);
2564}
2565
2566
2567void Assembler::DoubleAsTwoUInt32(double d, uint32_t* lo, uint32_t* hi) {
2568 uint64_t i;
2569 memcpy(&i, &d, 8);
2570
2571 *lo = i & 0xffffffff;
2572 *hi = i >> 32;
2573}
2574
2575
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002576void Assembler::sel(SecondaryField fmt, FPURegister fd, FPURegister fs,
2577 FPURegister ft) {
2578 DCHECK(kArchVariant == kMips64r6);
2579 DCHECK((fmt == D) || (fmt == S));
2580
2581 GenInstrRegister(COP1, fmt, ft, fs, fd, SEL);
2582}
2583
2584
2585void Assembler::sel_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2586 sel(S, fd, fs, ft);
2587}
2588
2589
2590void Assembler::sel_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2591 sel(D, fd, fs, ft);
2592}
2593
2594
2595// FPR.
2596void Assembler::seleqz(SecondaryField fmt, FPURegister fd, FPURegister fs,
2597 FPURegister ft) {
2598 DCHECK((fmt == D) || (fmt == S));
2599 GenInstrRegister(COP1, fmt, ft, fs, fd, SELEQZ_C);
2600}
2601
2602
2603void Assembler::seleqz_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2604 seleqz(D, fd, fs, ft);
2605}
2606
2607
2608void Assembler::seleqz_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2609 seleqz(S, fd, fs, ft);
2610}
2611
2612
2613void Assembler::selnez_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2614 selnez(D, fd, fs, ft);
2615}
2616
2617
2618void Assembler::selnez_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2619 selnez(S, fd, fs, ft);
2620}
2621
2622
2623void Assembler::movz_s(FPURegister fd, FPURegister fs, Register rt) {
2624 DCHECK(kArchVariant == kMips64r2);
2625 GenInstrRegister(COP1, S, rt, fs, fd, MOVZ_C);
2626}
2627
2628
2629void Assembler::movz_d(FPURegister fd, FPURegister fs, Register rt) {
2630 DCHECK(kArchVariant == kMips64r2);
2631 GenInstrRegister(COP1, D, rt, fs, fd, MOVZ_C);
2632}
2633
2634
2635void Assembler::movt_s(FPURegister fd, FPURegister fs, uint16_t cc) {
2636 DCHECK(kArchVariant == kMips64r2);
2637 FPURegister ft;
2638 ft.reg_code = (cc & 0x0007) << 2 | 1;
2639 GenInstrRegister(COP1, S, ft, fs, fd, MOVF);
2640}
2641
2642
2643void Assembler::movt_d(FPURegister fd, FPURegister fs, uint16_t cc) {
2644 DCHECK(kArchVariant == kMips64r2);
2645 FPURegister ft;
2646 ft.reg_code = (cc & 0x0007) << 2 | 1;
2647 GenInstrRegister(COP1, D, ft, fs, fd, MOVF);
2648}
2649
2650
2651void Assembler::movf_s(FPURegister fd, FPURegister fs, uint16_t cc) {
2652 DCHECK(kArchVariant == kMips64r2);
2653 FPURegister ft;
2654 ft.reg_code = (cc & 0x0007) << 2 | 0;
2655 GenInstrRegister(COP1, S, ft, fs, fd, MOVF);
2656}
2657
2658
2659void Assembler::movf_d(FPURegister fd, FPURegister fs, uint16_t cc) {
2660 DCHECK(kArchVariant == kMips64r2);
2661 FPURegister ft;
2662 ft.reg_code = (cc & 0x0007) << 2 | 0;
2663 GenInstrRegister(COP1, D, ft, fs, fd, MOVF);
2664}
2665
2666
2667void Assembler::movn_s(FPURegister fd, FPURegister fs, Register rt) {
2668 DCHECK(kArchVariant == kMips64r2);
2669 GenInstrRegister(COP1, S, rt, fs, fd, MOVN_C);
2670}
2671
2672
2673void Assembler::movn_d(FPURegister fd, FPURegister fs, Register rt) {
2674 DCHECK(kArchVariant == kMips64r2);
2675 GenInstrRegister(COP1, D, rt, fs, fd, MOVN_C);
2676}
2677
2678
2679// FPR.
2680void Assembler::selnez(SecondaryField fmt, FPURegister fd, FPURegister fs,
2681 FPURegister ft) {
2682 DCHECK(kArchVariant == kMips64r6);
2683 DCHECK((fmt == D) || (fmt == S));
2684 GenInstrRegister(COP1, fmt, ft, fs, fd, SELNEZ_C);
2685}
2686
2687
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002688// Arithmetic.
2689
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002690void Assembler::add_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2691 GenInstrRegister(COP1, S, ft, fs, fd, ADD_D);
2692}
2693
2694
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002695void Assembler::add_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2696 GenInstrRegister(COP1, D, ft, fs, fd, ADD_D);
2697}
2698
2699
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002700void Assembler::sub_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2701 GenInstrRegister(COP1, S, ft, fs, fd, SUB_D);
2702}
2703
2704
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002705void Assembler::sub_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2706 GenInstrRegister(COP1, D, ft, fs, fd, SUB_D);
2707}
2708
2709
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002710void Assembler::mul_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2711 GenInstrRegister(COP1, S, ft, fs, fd, MUL_D);
2712}
2713
2714
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002715void Assembler::mul_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2716 GenInstrRegister(COP1, D, ft, fs, fd, MUL_D);
2717}
2718
2719
2720void Assembler::madd_d(FPURegister fd, FPURegister fr, FPURegister fs,
2721 FPURegister ft) {
2722 GenInstrRegister(COP1X, fr, ft, fs, fd, MADD_D);
2723}
2724
2725
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002726void Assembler::div_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2727 GenInstrRegister(COP1, S, ft, fs, fd, DIV_D);
2728}
2729
2730
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002731void Assembler::div_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2732 GenInstrRegister(COP1, D, ft, fs, fd, DIV_D);
2733}
2734
2735
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002736void Assembler::abs_s(FPURegister fd, FPURegister fs) {
2737 GenInstrRegister(COP1, S, f0, fs, fd, ABS_D);
2738}
2739
2740
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002741void Assembler::abs_d(FPURegister fd, FPURegister fs) {
2742 GenInstrRegister(COP1, D, f0, fs, fd, ABS_D);
2743}
2744
2745
2746void Assembler::mov_d(FPURegister fd, FPURegister fs) {
2747 GenInstrRegister(COP1, D, f0, fs, fd, MOV_D);
2748}
2749
2750
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002751void Assembler::mov_s(FPURegister fd, FPURegister fs) {
2752 GenInstrRegister(COP1, S, f0, fs, fd, MOV_S);
2753}
2754
2755
2756void Assembler::neg_s(FPURegister fd, FPURegister fs) {
2757 GenInstrRegister(COP1, S, f0, fs, fd, NEG_D);
2758}
2759
2760
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002761void Assembler::neg_d(FPURegister fd, FPURegister fs) {
2762 GenInstrRegister(COP1, D, f0, fs, fd, NEG_D);
2763}
2764
2765
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002766void Assembler::sqrt_s(FPURegister fd, FPURegister fs) {
2767 GenInstrRegister(COP1, S, f0, fs, fd, SQRT_D);
2768}
2769
2770
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002771void Assembler::sqrt_d(FPURegister fd, FPURegister fs) {
2772 GenInstrRegister(COP1, D, f0, fs, fd, SQRT_D);
2773}
2774
2775
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002776void Assembler::rsqrt_s(FPURegister fd, FPURegister fs) {
2777 GenInstrRegister(COP1, S, f0, fs, fd, RSQRT_S);
2778}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002779
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002780
2781void Assembler::rsqrt_d(FPURegister fd, FPURegister fs) {
2782 GenInstrRegister(COP1, D, f0, fs, fd, RSQRT_D);
2783}
2784
2785
2786void Assembler::recip_d(FPURegister fd, FPURegister fs) {
2787 GenInstrRegister(COP1, D, f0, fs, fd, RECIP_D);
2788}
2789
2790
2791void Assembler::recip_s(FPURegister fd, FPURegister fs) {
2792 GenInstrRegister(COP1, S, f0, fs, fd, RECIP_S);
2793}
2794
2795
2796// Conversions.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002797void Assembler::cvt_w_s(FPURegister fd, FPURegister fs) {
2798 GenInstrRegister(COP1, S, f0, fs, fd, CVT_W_S);
2799}
2800
2801
2802void Assembler::cvt_w_d(FPURegister fd, FPURegister fs) {
2803 GenInstrRegister(COP1, D, f0, fs, fd, CVT_W_D);
2804}
2805
2806
2807void Assembler::trunc_w_s(FPURegister fd, FPURegister fs) {
2808 GenInstrRegister(COP1, S, f0, fs, fd, TRUNC_W_S);
2809}
2810
2811
2812void Assembler::trunc_w_d(FPURegister fd, FPURegister fs) {
2813 GenInstrRegister(COP1, D, f0, fs, fd, TRUNC_W_D);
2814}
2815
2816
2817void Assembler::round_w_s(FPURegister fd, FPURegister fs) {
2818 GenInstrRegister(COP1, S, f0, fs, fd, ROUND_W_S);
2819}
2820
2821
2822void Assembler::round_w_d(FPURegister fd, FPURegister fs) {
2823 GenInstrRegister(COP1, D, f0, fs, fd, ROUND_W_D);
2824}
2825
2826
2827void Assembler::floor_w_s(FPURegister fd, FPURegister fs) {
2828 GenInstrRegister(COP1, S, f0, fs, fd, FLOOR_W_S);
2829}
2830
2831
2832void Assembler::floor_w_d(FPURegister fd, FPURegister fs) {
2833 GenInstrRegister(COP1, D, f0, fs, fd, FLOOR_W_D);
2834}
2835
2836
2837void Assembler::ceil_w_s(FPURegister fd, FPURegister fs) {
2838 GenInstrRegister(COP1, S, f0, fs, fd, CEIL_W_S);
2839}
2840
2841
2842void Assembler::ceil_w_d(FPURegister fd, FPURegister fs) {
2843 GenInstrRegister(COP1, D, f0, fs, fd, CEIL_W_D);
2844}
2845
2846
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002847void Assembler::rint_s(FPURegister fd, FPURegister fs) { rint(S, fd, fs); }
2848
2849
2850void Assembler::rint_d(FPURegister fd, FPURegister fs) { rint(D, fd, fs); }
2851
2852
2853void Assembler::rint(SecondaryField fmt, FPURegister fd, FPURegister fs) {
2854 DCHECK(kArchVariant == kMips64r6);
2855 GenInstrRegister(COP1, fmt, f0, fs, fd, RINT);
2856}
2857
2858
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002859void Assembler::cvt_l_s(FPURegister fd, FPURegister fs) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002860 DCHECK(kArchVariant == kMips64r2 || kArchVariant == kMips64r6);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002861 GenInstrRegister(COP1, S, f0, fs, fd, CVT_L_S);
2862}
2863
2864
2865void Assembler::cvt_l_d(FPURegister fd, FPURegister fs) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002866 DCHECK(kArchVariant == kMips64r2 || kArchVariant == kMips64r6);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002867 GenInstrRegister(COP1, D, f0, fs, fd, CVT_L_D);
2868}
2869
2870
2871void Assembler::trunc_l_s(FPURegister fd, FPURegister fs) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002872 DCHECK(kArchVariant == kMips64r2 || kArchVariant == kMips64r6);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002873 GenInstrRegister(COP1, S, f0, fs, fd, TRUNC_L_S);
2874}
2875
2876
2877void Assembler::trunc_l_d(FPURegister fd, FPURegister fs) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002878 DCHECK(kArchVariant == kMips64r2 || kArchVariant == kMips64r6);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002879 GenInstrRegister(COP1, D, f0, fs, fd, TRUNC_L_D);
2880}
2881
2882
2883void Assembler::round_l_s(FPURegister fd, FPURegister fs) {
2884 GenInstrRegister(COP1, S, f0, fs, fd, ROUND_L_S);
2885}
2886
2887
2888void Assembler::round_l_d(FPURegister fd, FPURegister fs) {
2889 GenInstrRegister(COP1, D, f0, fs, fd, ROUND_L_D);
2890}
2891
2892
2893void Assembler::floor_l_s(FPURegister fd, FPURegister fs) {
2894 GenInstrRegister(COP1, S, f0, fs, fd, FLOOR_L_S);
2895}
2896
2897
2898void Assembler::floor_l_d(FPURegister fd, FPURegister fs) {
2899 GenInstrRegister(COP1, D, f0, fs, fd, FLOOR_L_D);
2900}
2901
2902
2903void Assembler::ceil_l_s(FPURegister fd, FPURegister fs) {
2904 GenInstrRegister(COP1, S, f0, fs, fd, CEIL_L_S);
2905}
2906
2907
2908void Assembler::ceil_l_d(FPURegister fd, FPURegister fs) {
2909 GenInstrRegister(COP1, D, f0, fs, fd, CEIL_L_D);
2910}
2911
2912
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002913void Assembler::class_s(FPURegister fd, FPURegister fs) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002914 DCHECK(kArchVariant == kMips64r6);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002915 GenInstrRegister(COP1, S, f0, fs, fd, CLASS_S);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002916}
2917
2918
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002919void Assembler::class_d(FPURegister fd, FPURegister fs) {
2920 DCHECK(kArchVariant == kMips64r6);
2921 GenInstrRegister(COP1, D, f0, fs, fd, CLASS_D);
2922}
2923
2924
2925void Assembler::mina(SecondaryField fmt, FPURegister fd, FPURegister fs,
2926 FPURegister ft) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002927 DCHECK(kArchVariant == kMips64r6);
2928 DCHECK((fmt == D) || (fmt == S));
2929 GenInstrRegister(COP1, fmt, ft, fs, fd, MINA);
2930}
2931
2932
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002933void Assembler::maxa(SecondaryField fmt, FPURegister fd, FPURegister fs,
2934 FPURegister ft) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002935 DCHECK(kArchVariant == kMips64r6);
2936 DCHECK((fmt == D) || (fmt == S));
2937 GenInstrRegister(COP1, fmt, ft, fs, fd, MAXA);
2938}
2939
2940
2941void Assembler::cvt_s_w(FPURegister fd, FPURegister fs) {
2942 GenInstrRegister(COP1, W, f0, fs, fd, CVT_S_W);
2943}
2944
2945
2946void Assembler::cvt_s_l(FPURegister fd, FPURegister fs) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002947 DCHECK(kArchVariant == kMips64r2 || kArchVariant == kMips64r6);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002948 GenInstrRegister(COP1, L, f0, fs, fd, CVT_S_L);
2949}
2950
2951
2952void Assembler::cvt_s_d(FPURegister fd, FPURegister fs) {
2953 GenInstrRegister(COP1, D, f0, fs, fd, CVT_S_D);
2954}
2955
2956
2957void Assembler::cvt_d_w(FPURegister fd, FPURegister fs) {
2958 GenInstrRegister(COP1, W, f0, fs, fd, CVT_D_W);
2959}
2960
2961
2962void Assembler::cvt_d_l(FPURegister fd, FPURegister fs) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002963 DCHECK(kArchVariant == kMips64r2 || kArchVariant == kMips64r6);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002964 GenInstrRegister(COP1, L, f0, fs, fd, CVT_D_L);
2965}
2966
2967
2968void Assembler::cvt_d_s(FPURegister fd, FPURegister fs) {
2969 GenInstrRegister(COP1, S, f0, fs, fd, CVT_D_S);
2970}
2971
2972
2973// Conditions for >= MIPSr6.
2974void Assembler::cmp(FPUCondition cond, SecondaryField fmt,
2975 FPURegister fd, FPURegister fs, FPURegister ft) {
2976 DCHECK(kArchVariant == kMips64r6);
2977 DCHECK((fmt & ~(31 << kRsShift)) == 0);
2978 Instr instr = COP1 | fmt | ft.code() << kFtShift |
2979 fs.code() << kFsShift | fd.code() << kFdShift | (0 << 5) | cond;
2980 emit(instr);
2981}
2982
2983
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002984void Assembler::cmp_s(FPUCondition cond, FPURegister fd, FPURegister fs,
2985 FPURegister ft) {
2986 cmp(cond, W, fd, fs, ft);
2987}
2988
2989void Assembler::cmp_d(FPUCondition cond, FPURegister fd, FPURegister fs,
2990 FPURegister ft) {
2991 cmp(cond, L, fd, fs, ft);
2992}
2993
2994
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002995void Assembler::bc1eqz(int16_t offset, FPURegister ft) {
2996 DCHECK(kArchVariant == kMips64r6);
2997 Instr instr = COP1 | BC1EQZ | ft.code() << kFtShift | (offset & kImm16Mask);
2998 emit(instr);
2999}
3000
3001
3002void Assembler::bc1nez(int16_t offset, FPURegister ft) {
3003 DCHECK(kArchVariant == kMips64r6);
3004 Instr instr = COP1 | BC1NEZ | ft.code() << kFtShift | (offset & kImm16Mask);
3005 emit(instr);
3006}
3007
3008
3009// Conditions for < MIPSr6.
3010void Assembler::c(FPUCondition cond, SecondaryField fmt,
3011 FPURegister fs, FPURegister ft, uint16_t cc) {
3012 DCHECK(kArchVariant != kMips64r6);
3013 DCHECK(is_uint3(cc));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003014 DCHECK(fmt == S || fmt == D);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003015 DCHECK((fmt & ~(31 << kRsShift)) == 0);
3016 Instr instr = COP1 | fmt | ft.code() << kFtShift | fs.code() << kFsShift
3017 | cc << 8 | 3 << 4 | cond;
3018 emit(instr);
3019}
3020
3021
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003022void Assembler::c_s(FPUCondition cond, FPURegister fs, FPURegister ft,
3023 uint16_t cc) {
3024 c(cond, S, fs, ft, cc);
3025}
3026
3027
3028void Assembler::c_d(FPUCondition cond, FPURegister fs, FPURegister ft,
3029 uint16_t cc) {
3030 c(cond, D, fs, ft, cc);
3031}
3032
3033
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003034void Assembler::fcmp(FPURegister src1, const double src2,
3035 FPUCondition cond) {
3036 DCHECK(src2 == 0.0);
3037 mtc1(zero_reg, f14);
3038 cvt_d_w(f14, f14);
3039 c(cond, D, src1, f14, 0);
3040}
3041
3042
3043void Assembler::bc1f(int16_t offset, uint16_t cc) {
3044 DCHECK(is_uint3(cc));
3045 Instr instr = COP1 | BC1 | cc << 18 | 0 << 16 | (offset & kImm16Mask);
3046 emit(instr);
3047}
3048
3049
3050void Assembler::bc1t(int16_t offset, uint16_t cc) {
3051 DCHECK(is_uint3(cc));
3052 Instr instr = COP1 | BC1 | cc << 18 | 1 << 16 | (offset & kImm16Mask);
3053 emit(instr);
3054}
3055
3056
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003057int Assembler::RelocateInternalReference(RelocInfo::Mode rmode, byte* pc,
3058 intptr_t pc_delta) {
3059 if (RelocInfo::IsInternalReference(rmode)) {
3060 int64_t* p = reinterpret_cast<int64_t*>(pc);
3061 if (*p == kEndOfJumpChain) {
3062 return 0; // Number of instructions patched.
3063 }
3064 *p += pc_delta;
3065 return 2; // Number of instructions patched.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003066 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003067 Instr instr = instr_at(pc);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003068 DCHECK(RelocInfo::IsInternalReferenceEncoded(rmode));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003069 if (IsLui(instr)) {
3070 Instr instr_lui = instr_at(pc + 0 * Assembler::kInstrSize);
3071 Instr instr_ori = instr_at(pc + 1 * Assembler::kInstrSize);
3072 Instr instr_ori2 = instr_at(pc + 3 * Assembler::kInstrSize);
3073 DCHECK(IsOri(instr_ori));
3074 DCHECK(IsOri(instr_ori2));
3075 // TODO(plind): symbolic names for the shifts.
3076 int64_t imm = (instr_lui & static_cast<int64_t>(kImm16Mask)) << 48;
3077 imm |= (instr_ori & static_cast<int64_t>(kImm16Mask)) << 32;
3078 imm |= (instr_ori2 & static_cast<int64_t>(kImm16Mask)) << 16;
3079 // Sign extend address.
3080 imm >>= 16;
3081
3082 if (imm == kEndOfJumpChain) {
3083 return 0; // Number of instructions patched.
3084 }
3085 imm += pc_delta;
3086 DCHECK((imm & 3) == 0);
3087
3088 instr_lui &= ~kImm16Mask;
3089 instr_ori &= ~kImm16Mask;
3090 instr_ori2 &= ~kImm16Mask;
3091
3092 instr_at_put(pc + 0 * Assembler::kInstrSize,
3093 instr_lui | ((imm >> 32) & kImm16Mask));
3094 instr_at_put(pc + 1 * Assembler::kInstrSize,
3095 instr_ori | (imm >> 16 & kImm16Mask));
3096 instr_at_put(pc + 3 * Assembler::kInstrSize,
3097 instr_ori2 | (imm & kImm16Mask));
3098 return 4; // Number of instructions patched.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003099 } else if (IsJ(instr) || IsJal(instr)) {
3100 // Regular j/jal relocation.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003101 uint32_t imm28 = (instr & static_cast<int32_t>(kImm26Mask)) << 2;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003102 imm28 += pc_delta;
3103 imm28 &= kImm28Mask;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003104 instr &= ~kImm26Mask;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003105 DCHECK((imm28 & 3) == 0);
3106 uint32_t imm26 = static_cast<uint32_t>(imm28 >> 2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003107 instr_at_put(pc, instr | (imm26 & kImm26Mask));
3108 return 1; // Number of instructions patched.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003109 } else {
3110 DCHECK(((instr & kJumpRawMask) == kJRawMark) ||
3111 ((instr & kJumpRawMask) == kJalRawMark));
3112 // Unbox raw offset and emit j/jal.
3113 int32_t imm28 = (instr & static_cast<int32_t>(kImm26Mask)) << 2;
3114 // Sign extend 28-bit offset to 32-bit.
3115 imm28 = (imm28 << 4) >> 4;
3116 uint64_t target =
3117 static_cast<int64_t>(imm28) + reinterpret_cast<uint64_t>(pc);
3118 target &= kImm28Mask;
3119 DCHECK((imm28 & 3) == 0);
3120 uint32_t imm26 = static_cast<uint32_t>(target >> 2);
3121 // Check markings whether to emit j or jal.
3122 uint32_t unbox = (instr & kJRawMark) ? J : JAL;
3123 instr_at_put(pc, unbox | (imm26 & kImm26Mask));
3124 return 1; // Number of instructions patched.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003125 }
3126}
3127
3128
3129void Assembler::GrowBuffer() {
3130 if (!own_buffer_) FATAL("external code buffer is too small");
3131
3132 // Compute new buffer size.
3133 CodeDesc desc; // The new buffer.
3134 if (buffer_size_ < 1 * MB) {
3135 desc.buffer_size = 2*buffer_size_;
3136 } else {
3137 desc.buffer_size = buffer_size_ + 1*MB;
3138 }
3139 CHECK_GT(desc.buffer_size, 0); // No overflow.
3140
3141 // Set up new buffer.
3142 desc.buffer = NewArray<byte>(desc.buffer_size);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003143 desc.origin = this;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003144
3145 desc.instr_size = pc_offset();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003146 desc.reloc_size =
3147 static_cast<int>((buffer_ + buffer_size_) - reloc_info_writer.pos());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003148
3149 // Copy the data.
3150 intptr_t pc_delta = desc.buffer - buffer_;
3151 intptr_t rc_delta = (desc.buffer + desc.buffer_size) -
3152 (buffer_ + buffer_size_);
3153 MemMove(desc.buffer, buffer_, desc.instr_size);
3154 MemMove(reloc_info_writer.pos() + rc_delta,
3155 reloc_info_writer.pos(), desc.reloc_size);
3156
3157 // Switch buffers.
3158 DeleteArray(buffer_);
3159 buffer_ = desc.buffer;
3160 buffer_size_ = desc.buffer_size;
3161 pc_ += pc_delta;
3162 reloc_info_writer.Reposition(reloc_info_writer.pos() + rc_delta,
3163 reloc_info_writer.last_pc() + pc_delta);
3164
3165 // Relocate runtime entries.
3166 for (RelocIterator it(desc); !it.done(); it.next()) {
3167 RelocInfo::Mode rmode = it.rinfo()->rmode();
3168 if (rmode == RelocInfo::INTERNAL_REFERENCE) {
3169 byte* p = reinterpret_cast<byte*>(it.rinfo()->pc());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003170 RelocateInternalReference(rmode, p, pc_delta);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003171 }
3172 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003173 DCHECK(!overflow());
3174}
3175
3176
3177void Assembler::db(uint8_t data) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003178 CheckForEmitInForbiddenSlot();
3179 EmitHelper(data);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003180}
3181
3182
3183void Assembler::dd(uint32_t data) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003184 CheckForEmitInForbiddenSlot();
3185 EmitHelper(data);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003186}
3187
3188
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003189void Assembler::dq(uint64_t data) {
3190 CheckForEmitInForbiddenSlot();
3191 EmitHelper(data);
3192}
3193
3194
3195void Assembler::dd(Label* label) {
3196 uint64_t data;
3197 CheckForEmitInForbiddenSlot();
3198 if (label->is_bound()) {
3199 data = reinterpret_cast<uint64_t>(buffer_ + label->pos());
3200 } else {
3201 data = jump_address(label);
3202 internal_reference_positions_.insert(label->pos());
3203 }
3204 RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE);
3205 EmitHelper(data);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003206}
3207
3208
3209void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) {
3210 // We do not try to reuse pool constants.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003211 RelocInfo rinfo(isolate(), pc_, rmode, data, NULL);
3212 if (rmode >= RelocInfo::COMMENT &&
3213 rmode <= RelocInfo::DEBUG_BREAK_SLOT_AT_CALL) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003214 // Adjust code for new modes.
3215 DCHECK(RelocInfo::IsDebugBreakSlot(rmode)
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003216 || RelocInfo::IsComment(rmode)
3217 || RelocInfo::IsPosition(rmode));
3218 // These modes do not need an entry in the constant pool.
3219 }
3220 if (!RelocInfo::IsNone(rinfo.rmode())) {
3221 // Don't record external references unless the heap will be serialized.
3222 if (rmode == RelocInfo::EXTERNAL_REFERENCE &&
3223 !serializer_enabled() && !emit_debug_code()) {
3224 return;
3225 }
3226 DCHECK(buffer_space() >= kMaxRelocSize); // Too late to grow buffer here.
3227 if (rmode == RelocInfo::CODE_TARGET_WITH_ID) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003228 RelocInfo reloc_info_with_ast_id(isolate(), pc_, rmode,
3229 RecordedAstId().ToInt(), NULL);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003230 ClearRecordedAstId();
3231 reloc_info_writer.Write(&reloc_info_with_ast_id);
3232 } else {
3233 reloc_info_writer.Write(&rinfo);
3234 }
3235 }
3236}
3237
3238
3239void Assembler::BlockTrampolinePoolFor(int instructions) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003240 CheckTrampolinePoolQuick(instructions);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003241 BlockTrampolinePoolBefore(pc_offset() + instructions * kInstrSize);
3242}
3243
3244
3245void Assembler::CheckTrampolinePool() {
3246 // Some small sequences of instructions must not be broken up by the
3247 // insertion of a trampoline pool; such sequences are protected by setting
3248 // either trampoline_pool_blocked_nesting_ or no_trampoline_pool_before_,
3249 // which are both checked here. Also, recursive calls to CheckTrampolinePool
3250 // are blocked by trampoline_pool_blocked_nesting_.
3251 if ((trampoline_pool_blocked_nesting_ > 0) ||
3252 (pc_offset() < no_trampoline_pool_before_)) {
3253 // Emission is currently blocked; make sure we try again as soon as
3254 // possible.
3255 if (trampoline_pool_blocked_nesting_ > 0) {
3256 next_buffer_check_ = pc_offset() + kInstrSize;
3257 } else {
3258 next_buffer_check_ = no_trampoline_pool_before_;
3259 }
3260 return;
3261 }
3262
3263 DCHECK(!trampoline_emitted_);
3264 DCHECK(unbound_labels_count_ >= 0);
3265 if (unbound_labels_count_ > 0) {
3266 // First we emit jump (2 instructions), then we emit trampoline pool.
3267 { BlockTrampolinePoolScope block_trampoline_pool(this);
3268 Label after_pool;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003269 if (kArchVariant == kMips64r6) {
3270 bc(&after_pool);
3271 } else {
3272 b(&after_pool);
3273 nop();
3274 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003275
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003276 EmitForbiddenSlotInstruction();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003277 int pool_start = pc_offset();
3278 for (int i = 0; i < unbound_labels_count_; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003279 { BlockGrowBufferScope block_buf_growth(this);
3280 // Buffer growth (and relocation) must be blocked for internal
3281 // references until associated instructions are emitted and available
3282 // to be patched.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003283 RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE_ENCODED);
3284 j(&after_pool);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003285 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003286 nop();
3287 }
3288 bind(&after_pool);
3289 trampoline_ = Trampoline(pool_start, unbound_labels_count_);
3290
3291 trampoline_emitted_ = true;
3292 // As we are only going to emit trampoline once, we need to prevent any
3293 // further emission.
3294 next_buffer_check_ = kMaxInt;
3295 }
3296 } else {
3297 // Number of branches to unbound label at this point is zero, so we can
3298 // move next buffer check to maximum.
3299 next_buffer_check_ = pc_offset() +
3300 kMaxBranchOffset - kTrampolineSlotsSize * 16;
3301 }
3302 return;
3303}
3304
3305
3306Address Assembler::target_address_at(Address pc) {
3307 Instr instr0 = instr_at(pc);
3308 Instr instr1 = instr_at(pc + 1 * kInstrSize);
3309 Instr instr3 = instr_at(pc + 3 * kInstrSize);
3310
3311 // Interpret 4 instructions for address generated by li: See listing in
3312 // Assembler::set_target_address_at() just below.
3313 if ((GetOpcodeField(instr0) == LUI) && (GetOpcodeField(instr1) == ORI) &&
3314 (GetOpcodeField(instr3) == ORI)) {
3315 // Assemble the 48 bit value.
3316 int64_t addr = static_cast<int64_t>(
3317 ((uint64_t)(GetImmediate16(instr0)) << 32) |
3318 ((uint64_t)(GetImmediate16(instr1)) << 16) |
3319 ((uint64_t)(GetImmediate16(instr3))));
3320
3321 // Sign extend to get canonical address.
3322 addr = (addr << 16) >> 16;
3323 return reinterpret_cast<Address>(addr);
3324 }
3325 // We should never get here, force a bad address if we do.
3326 UNREACHABLE();
3327 return (Address)0x0;
3328}
3329
3330
3331// MIPS and ia32 use opposite encoding for qNaN and sNaN, such that ia32
3332// qNaN is a MIPS sNaN, and ia32 sNaN is MIPS qNaN. If running from a heap
3333// snapshot generated on ia32, the resulting MIPS sNaN must be quieted.
3334// OS::nan_value() returns a qNaN.
3335void Assembler::QuietNaN(HeapObject* object) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003336 HeapNumber::cast(object)->set_value(std::numeric_limits<double>::quiet_NaN());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003337}
3338
3339
3340// On Mips64, a target address is stored in a 4-instruction sequence:
3341// 0: lui(rd, (j.imm64_ >> 32) & kImm16Mask);
3342// 1: ori(rd, rd, (j.imm64_ >> 16) & kImm16Mask);
3343// 2: dsll(rd, rd, 16);
3344// 3: ori(rd, rd, j.imm32_ & kImm16Mask);
3345//
3346// Patching the address must replace all the lui & ori instructions,
3347// and flush the i-cache.
3348//
3349// There is an optimization below, which emits a nop when the address
3350// fits in just 16 bits. This is unlikely to help, and should be benchmarked,
3351// and possibly removed.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003352void Assembler::set_target_address_at(Isolate* isolate, Address pc,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003353 Address target,
3354 ICacheFlushMode icache_flush_mode) {
3355// There is an optimization where only 4 instructions are used to load address
3356// in code on MIP64 because only 48-bits of address is effectively used.
3357// It relies on fact the upper [63:48] bits are not used for virtual address
3358// translation and they have to be set according to value of bit 47 in order
3359// get canonical address.
3360 Instr instr1 = instr_at(pc + kInstrSize);
3361 uint32_t rt_code = GetRt(instr1);
3362 uint32_t* p = reinterpret_cast<uint32_t*>(pc);
3363 uint64_t itarget = reinterpret_cast<uint64_t>(target);
3364
3365#ifdef DEBUG
3366 // Check we have the result from a li macro-instruction.
3367 Instr instr0 = instr_at(pc);
3368 Instr instr3 = instr_at(pc + kInstrSize * 3);
3369 CHECK((GetOpcodeField(instr0) == LUI && GetOpcodeField(instr1) == ORI &&
3370 GetOpcodeField(instr3) == ORI));
3371#endif
3372
3373 // Must use 4 instructions to insure patchable code.
3374 // lui rt, upper-16.
3375 // ori rt, rt, lower-16.
3376 // dsll rt, rt, 16.
3377 // ori rt rt, lower-16.
3378 *p = LUI | (rt_code << kRtShift) | ((itarget >> 32) & kImm16Mask);
3379 *(p + 1) = ORI | (rt_code << kRtShift) | (rt_code << kRsShift)
3380 | ((itarget >> 16) & kImm16Mask);
3381 *(p + 3) = ORI | (rt_code << kRsShift) | (rt_code << kRtShift)
3382 | (itarget & kImm16Mask);
3383
3384 if (icache_flush_mode != SKIP_ICACHE_FLUSH) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003385 Assembler::FlushICache(isolate, pc, 4 * Assembler::kInstrSize);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003386 }
3387}
3388
3389
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003390} // namespace internal
3391} // namespace v8
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003392
3393#endif // V8_TARGET_ARCH_MIPS64