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