blob: e50a239a4a9c6c0533995a2ed8a337743797d915 [file] [log] [blame]
Andrei Popescu31002712010-02-23 13:46:05 +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.
Ben Murdoch3ef787d2012-04-12 10:51:47 +010033// Copyright 2012 the V8 project authors. All rights reserved.
Andrei Popescu31002712010-02-23 13:46:05 +000034
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000035#include "src/mips/assembler-mips.h"
Leon Clarkef7060e22010-06-03 12:02:55 +010036
Ben Murdochb8a8cc12014-11-26 15:28:44 +000037#if V8_TARGET_ARCH_MIPS
Leon Clarkef7060e22010-06-03 12:02:55 +010038
Ben Murdochb8a8cc12014-11-26 15:28:44 +000039#include "src/base/bits.h"
40#include "src/base/cpu.h"
41#include "src/mips/assembler-mips-inl.h"
Andrei Popescu31002712010-02-23 13:46:05 +000042
Andrei Popescu31002712010-02-23 13:46:05 +000043namespace v8 {
44namespace internal {
45
Ben Murdoch589d6972011-11-30 16:04:58 +000046// 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.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000050static unsigned CpuFeaturesImpliedByCompiler() {
51 unsigned answer = 0;
Ben Murdoch589d6972011-11-30 16:04:58 +000052#ifdef CAN_USE_FPU_INSTRUCTIONS
53 answer |= 1u << FPU;
54#endif // def CAN_USE_FPU_INSTRUCTIONS
55
Ben Murdoch589d6972011-11-30 16:04:58 +000056 // 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.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000059#if defined(__mips__) && defined(__mips_hard_float) && __mips_hard_float != 0
Ben Murdoch589d6972011-11-30 16:04:58 +000060 answer |= 1u << FPU;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000061#endif
Ben Murdoch589d6972011-11-30 16:04:58 +000062
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;
Ben Murdoch589d6972011-11-30 16:04:58 +000072
Steve Block44f0eee2011-05-26 01:26:41 +010073 // If the compiler is allowed to use fpu then we can use fpu too in our
74 // code generation.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000075#ifndef __mips__
76 // For the simulator build, use FPU.
77 supported_ |= 1u << FPU;
78#if defined(_MIPS_ARCH_MIPS32R6)
79 // FP64 mode is implied on r6.
80 supported_ |= 1u << FP64FPU;
81#endif
82#if defined(FPU_MODE_FP64)
83 supported_ |= 1u << FP64FPU;
84#endif
Steve Block44f0eee2011-05-26 01:26:41 +010085#else
Ben Murdochb8a8cc12014-11-26 15:28:44 +000086 // Probe for additional features at runtime.
87 base::CPU cpu;
88 if (cpu.has_fpu()) supported_ |= 1u << FPU;
89#if defined(FPU_MODE_FPXX)
90 if (cpu.is_fp64_mode()) supported_ |= 1u << FP64FPU;
91#elif defined(FPU_MODE_FP64)
92 supported_ |= 1u << FP64FPU;
93#endif
94#if defined(_MIPS_ARCH_MIPS32RX)
95 if (cpu.architecture() == 6) {
96 supported_ |= 1u << MIPSr6;
97 } else if (cpu.architecture() == 2) {
98 supported_ |= 1u << MIPSr1;
99 supported_ |= 1u << MIPSr2;
100 } else {
101 supported_ |= 1u << MIPSr1;
Steve Block44f0eee2011-05-26 01:26:41 +0100102 }
Steve Block44f0eee2011-05-26 01:26:41 +0100103#endif
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000104#endif
Steve Block44f0eee2011-05-26 01:26:41 +0100105}
Andrei Popescu31002712010-02-23 13:46:05 +0000106
107
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000108void CpuFeatures::PrintTarget() { }
109void CpuFeatures::PrintFeatures() { }
110
111
Andrei Popescu31002712010-02-23 13:46:05 +0000112int ToNumber(Register reg) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000113 DCHECK(reg.is_valid());
Andrei Popescu31002712010-02-23 13:46:05 +0000114 const int kNumbers[] = {
115 0, // zero_reg
116 1, // at
117 2, // v0
118 3, // v1
119 4, // a0
120 5, // a1
121 6, // a2
122 7, // a3
123 8, // t0
124 9, // t1
125 10, // t2
126 11, // t3
127 12, // t4
128 13, // t5
129 14, // t6
130 15, // t7
131 16, // s0
132 17, // s1
133 18, // s2
134 19, // s3
135 20, // s4
136 21, // s5
137 22, // s6
138 23, // s7
139 24, // t8
140 25, // t9
141 26, // k0
142 27, // k1
143 28, // gp
144 29, // sp
Ben Murdochdb1b4382012-04-26 19:03:50 +0100145 30, // fp
Andrei Popescu31002712010-02-23 13:46:05 +0000146 31, // ra
147 };
148 return kNumbers[reg.code()];
149}
150
Steve Block44f0eee2011-05-26 01:26:41 +0100151
Andrei Popescu31002712010-02-23 13:46:05 +0000152Register ToRegister(int num) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000153 DCHECK(num >= 0 && num < kNumRegisters);
Andrei Popescu31002712010-02-23 13:46:05 +0000154 const Register kRegisters[] = {
155 zero_reg,
156 at,
157 v0, v1,
158 a0, a1, a2, a3,
159 t0, t1, t2, t3, t4, t5, t6, t7,
160 s0, s1, s2, s3, s4, s5, s6, s7,
161 t8, t9,
162 k0, k1,
163 gp,
164 sp,
Ben Murdochdb1b4382012-04-26 19:03:50 +0100165 fp,
Andrei Popescu31002712010-02-23 13:46:05 +0000166 ra
167 };
168 return kRegisters[num];
169}
170
171
172// -----------------------------------------------------------------------------
173// Implementation of RelocInfo.
174
Ben Murdoch589d6972011-11-30 16:04:58 +0000175const int RelocInfo::kApplyMask = RelocInfo::kCodeTargetMask |
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000176 1 << RelocInfo::INTERNAL_REFERENCE |
177 1 << RelocInfo::INTERNAL_REFERENCE_ENCODED;
Andrei Popescu31002712010-02-23 13:46:05 +0000178
Steve Block44f0eee2011-05-26 01:26:41 +0100179
180bool RelocInfo::IsCodedSpecially() {
181 // The deserializer needs to know whether a pointer is specially coded. Being
182 // specially coded on MIPS means that it is a lui/ori instruction, and that is
183 // always the case inside code objects.
184 return true;
185}
186
187
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000188bool RelocInfo::IsInConstantPool() {
189 return false;
190}
191
192
Andrei Popescu31002712010-02-23 13:46:05 +0000193// -----------------------------------------------------------------------------
194// Implementation of Operand and MemOperand.
195// See assembler-mips-inl.h for inlined constructors.
196
197Operand::Operand(Handle<Object> handle) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000198 AllowDeferredHandleDereference using_raw_address;
Andrei Popescu31002712010-02-23 13:46:05 +0000199 rm_ = no_reg;
200 // Verify all Objects referred by code are NOT in new space.
201 Object* obj = *handle;
Andrei Popescu31002712010-02-23 13:46:05 +0000202 if (obj->IsHeapObject()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000203 DCHECK(!HeapObject::cast(obj)->GetHeap()->InNewSpace(obj));
Andrei Popescu31002712010-02-23 13:46:05 +0000204 imm32_ = reinterpret_cast<intptr_t>(handle.location());
205 rmode_ = RelocInfo::EMBEDDED_OBJECT;
206 } else {
207 // No relocation needed.
208 imm32_ = reinterpret_cast<intptr_t>(obj);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000209 rmode_ = RelocInfo::NONE32;
Andrei Popescu31002712010-02-23 13:46:05 +0000210 }
211}
212
Steve Block44f0eee2011-05-26 01:26:41 +0100213
214MemOperand::MemOperand(Register rm, int32_t offset) : Operand(rm) {
Andrei Popescu31002712010-02-23 13:46:05 +0000215 offset_ = offset;
216}
217
218
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000219MemOperand::MemOperand(Register rm, int32_t unit, int32_t multiplier,
220 OffsetAddend offset_addend) : Operand(rm) {
221 offset_ = unit * multiplier + offset_addend;
222}
223
224
Andrei Popescu31002712010-02-23 13:46:05 +0000225// -----------------------------------------------------------------------------
Steve Block44f0eee2011-05-26 01:26:41 +0100226// Specific instructions, constants, and masks.
Andrei Popescu31002712010-02-23 13:46:05 +0000227
Steve Block44f0eee2011-05-26 01:26:41 +0100228static const int kNegOffset = 0x00008000;
229// addiu(sp, sp, 4) aka Pop() operation or part of Pop(r)
230// operations as post-increment of sp.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000231const Instr kPopInstruction = ADDIU | (Register::kCode_sp << kRsShift) |
232 (Register::kCode_sp << kRtShift) |
233 (kPointerSize & kImm16Mask); // NOLINT
Steve Block44f0eee2011-05-26 01:26:41 +0100234// addiu(sp, sp, -4) part of Push(r) operation as pre-decrement of sp.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000235const Instr kPushInstruction = ADDIU | (Register::kCode_sp << kRsShift) |
236 (Register::kCode_sp << kRtShift) |
237 (-kPointerSize & kImm16Mask); // NOLINT
Steve Block44f0eee2011-05-26 01:26:41 +0100238// sw(r, MemOperand(sp, 0))
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000239const Instr kPushRegPattern =
240 SW | (Register::kCode_sp << kRsShift) | (0 & kImm16Mask); // NOLINT
Steve Block44f0eee2011-05-26 01:26:41 +0100241// lw(r, MemOperand(sp, 0))
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000242const Instr kPopRegPattern =
243 LW | (Register::kCode_sp << kRsShift) | (0 & kImm16Mask); // NOLINT
Andrei Popescu31002712010-02-23 13:46:05 +0000244
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000245const Instr kLwRegFpOffsetPattern =
246 LW | (Register::kCode_fp << kRsShift) | (0 & kImm16Mask); // NOLINT
Steve Block44f0eee2011-05-26 01:26:41 +0100247
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000248const Instr kSwRegFpOffsetPattern =
249 SW | (Register::kCode_fp << kRsShift) | (0 & kImm16Mask); // NOLINT
Steve Block44f0eee2011-05-26 01:26:41 +0100250
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000251const Instr kLwRegFpNegOffsetPattern = LW | (Register::kCode_fp << kRsShift) |
252 (kNegOffset & kImm16Mask); // NOLINT
Steve Block44f0eee2011-05-26 01:26:41 +0100253
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000254const Instr kSwRegFpNegOffsetPattern = SW | (Register::kCode_fp << kRsShift) |
255 (kNegOffset & kImm16Mask); // NOLINT
Steve Block44f0eee2011-05-26 01:26:41 +0100256// A mask for the Rt register for push, pop, lw, sw instructions.
257const Instr kRtMask = kRtFieldMask;
258const Instr kLwSwInstrTypeMask = 0xffe00000;
259const Instr kLwSwInstrArgumentMask = ~kLwSwInstrTypeMask;
260const Instr kLwSwOffsetMask = kImm16Mask;
261
262
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000263Assembler::Assembler(Isolate* isolate, void* buffer, int buffer_size)
264 : AssemblerBase(isolate, buffer, buffer_size),
265 recorded_ast_id_(TypeFeedbackId::None()),
266 positions_recorder_(this) {
267 reloc_info_writer.Reposition(buffer_ + buffer_size_, pc_);
Steve Block44f0eee2011-05-26 01:26:41 +0100268
269 last_trampoline_pool_end_ = 0;
270 no_trampoline_pool_before_ = 0;
271 trampoline_pool_blocked_nesting_ = 0;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000272 // We leave space (16 * kTrampolineSlotsSize)
273 // for BlockTrampolinePoolScope buffer.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000274 next_buffer_check_ = FLAG_force_long_branches
275 ? kMaxInt : kMaxBranchOffset - kTrampolineSlotsSize * 16;
Ben Murdoch257744e2011-11-30 15:57:28 +0000276 internal_trampoline_exception_ = false;
277 last_bound_pos_ = 0;
278
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000279 trampoline_emitted_ = FLAG_force_long_branches;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000280 unbound_labels_count_ = 0;
281 block_buffer_growth_ = false;
282
283 ClearRecordedAstId();
Andrei Popescu31002712010-02-23 13:46:05 +0000284}
285
286
Andrei Popescu31002712010-02-23 13:46:05 +0000287void Assembler::GetCode(CodeDesc* desc) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100288 EmitForbiddenSlotInstruction();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000289 DCHECK(pc_ <= reloc_info_writer.pos()); // No overlap.
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100290 // Set up code descriptor.
Andrei Popescu31002712010-02-23 13:46:05 +0000291 desc->buffer = buffer_;
292 desc->buffer_size = buffer_size_;
293 desc->instr_size = pc_offset();
294 desc->reloc_size = (buffer_ + buffer_size_) - reloc_info_writer.pos();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000295 desc->origin = this;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000296 desc->constant_pool_size = 0;
Andrei Popescu31002712010-02-23 13:46:05 +0000297}
298
299
Steve Block44f0eee2011-05-26 01:26:41 +0100300void Assembler::Align(int m) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000301 DCHECK(m >= 4 && base::bits::IsPowerOfTwo32(m));
Ben Murdoch097c5b22016-05-18 11:27:45 +0100302 EmitForbiddenSlotInstruction();
Steve Block44f0eee2011-05-26 01:26:41 +0100303 while ((pc_offset() & (m - 1)) != 0) {
304 nop();
305 }
306}
307
308
309void Assembler::CodeTargetAlign() {
310 // No advantage to aligning branch/call targets to more than
311 // single instruction, that I am aware of.
312 Align(4);
313}
314
315
Ben Murdoch257744e2011-11-30 15:57:28 +0000316Register Assembler::GetRtReg(Instr instr) {
Steve Block44f0eee2011-05-26 01:26:41 +0100317 Register rt;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000318 rt.reg_code = (instr & kRtFieldMask) >> kRtShift;
Steve Block44f0eee2011-05-26 01:26:41 +0100319 return rt;
320}
321
322
Ben Murdoch257744e2011-11-30 15:57:28 +0000323Register Assembler::GetRsReg(Instr instr) {
324 Register rs;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000325 rs.reg_code = (instr & kRsFieldMask) >> kRsShift;
Ben Murdoch257744e2011-11-30 15:57:28 +0000326 return rs;
327}
328
329
330Register Assembler::GetRdReg(Instr instr) {
331 Register rd;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000332 rd.reg_code = (instr & kRdFieldMask) >> kRdShift;
Ben Murdoch257744e2011-11-30 15:57:28 +0000333 return rd;
334}
335
336
337uint32_t Assembler::GetRt(Instr instr) {
338 return (instr & kRtFieldMask) >> kRtShift;
339}
340
341
342uint32_t Assembler::GetRtField(Instr instr) {
343 return instr & kRtFieldMask;
344}
345
346
347uint32_t Assembler::GetRs(Instr instr) {
348 return (instr & kRsFieldMask) >> kRsShift;
349}
350
351
352uint32_t Assembler::GetRsField(Instr instr) {
353 return instr & kRsFieldMask;
354}
355
356
357uint32_t Assembler::GetRd(Instr instr) {
358 return (instr & kRdFieldMask) >> kRdShift;
359}
360
361
362uint32_t Assembler::GetRdField(Instr instr) {
363 return instr & kRdFieldMask;
364}
365
366
367uint32_t Assembler::GetSa(Instr instr) {
368 return (instr & kSaFieldMask) >> kSaShift;
369}
370
371
372uint32_t Assembler::GetSaField(Instr instr) {
373 return instr & kSaFieldMask;
374}
375
376
377uint32_t Assembler::GetOpcodeField(Instr instr) {
378 return instr & kOpcodeMask;
379}
380
381
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000382uint32_t Assembler::GetFunction(Instr instr) {
383 return (instr & kFunctionFieldMask) >> kFunctionShift;
384}
385
386
387uint32_t Assembler::GetFunctionField(Instr instr) {
388 return instr & kFunctionFieldMask;
389}
390
391
Ben Murdoch257744e2011-11-30 15:57:28 +0000392uint32_t Assembler::GetImmediate16(Instr instr) {
393 return instr & kImm16Mask;
394}
395
396
397uint32_t Assembler::GetLabelConst(Instr instr) {
398 return instr & ~kImm16Mask;
399}
400
401
Steve Block44f0eee2011-05-26 01:26:41 +0100402bool Assembler::IsPop(Instr instr) {
403 return (instr & ~kRtMask) == kPopRegPattern;
404}
405
406
407bool Assembler::IsPush(Instr instr) {
408 return (instr & ~kRtMask) == kPushRegPattern;
409}
410
411
412bool Assembler::IsSwRegFpOffset(Instr instr) {
413 return ((instr & kLwSwInstrTypeMask) == kSwRegFpOffsetPattern);
414}
415
416
417bool Assembler::IsLwRegFpOffset(Instr instr) {
418 return ((instr & kLwSwInstrTypeMask) == kLwRegFpOffsetPattern);
419}
420
421
422bool Assembler::IsSwRegFpNegOffset(Instr instr) {
423 return ((instr & (kLwSwInstrTypeMask | kNegOffset)) ==
424 kSwRegFpNegOffsetPattern);
425}
426
427
428bool Assembler::IsLwRegFpNegOffset(Instr instr) {
429 return ((instr & (kLwSwInstrTypeMask | kNegOffset)) ==
430 kLwRegFpNegOffsetPattern);
431}
432
433
Andrei Popescu31002712010-02-23 13:46:05 +0000434// Labels refer to positions in the (to be) generated code.
435// There are bound, linked, and unused labels.
436//
437// Bound labels refer to known positions in the already
438// generated code. pos() is the position the label refers to.
439//
440// Linked labels refer to unknown positions in the code
441// to be generated; pos() is the position of the last
442// instruction using the label.
443
Steve Block44f0eee2011-05-26 01:26:41 +0100444// The link chain is terminated by a value in the instruction of -1,
445// which is an otherwise illegal value (branch -1 is inf loop).
446// The instruction 16-bit offset field addresses 32-bit words, but in
447// code is conv to an 18-bit value addressing bytes, hence the -4 value.
Andrei Popescu31002712010-02-23 13:46:05 +0000448
Andrei Popescu31002712010-02-23 13:46:05 +0000449const int kEndOfChain = -4;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000450// Determines the end of the Jump chain (a subset of the label link chain).
451const int kEndOfJumpChain = 0;
Andrei Popescu31002712010-02-23 13:46:05 +0000452
Steve Block44f0eee2011-05-26 01:26:41 +0100453
454bool Assembler::IsBranch(Instr instr) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000455 uint32_t opcode = GetOpcodeField(instr);
456 uint32_t rt_field = GetRtField(instr);
457 uint32_t rs_field = GetRsField(instr);
Andrei Popescu31002712010-02-23 13:46:05 +0000458 // Checks if the instruction is a branch.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000459 bool isBranch =
460 opcode == BEQ || opcode == BNE || opcode == BLEZ || opcode == BGTZ ||
461 opcode == BEQL || opcode == BNEL || opcode == BLEZL || opcode == BGTZL ||
Andrei Popescu31002712010-02-23 13:46:05 +0000462 (opcode == REGIMM && (rt_field == BLTZ || rt_field == BGEZ ||
463 rt_field == BLTZAL || rt_field == BGEZAL)) ||
Steve Block44f0eee2011-05-26 01:26:41 +0100464 (opcode == COP1 && rs_field == BC1) || // Coprocessor branch.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000465 (opcode == COP1 && rs_field == BC1EQZ) ||
466 (opcode == COP1 && rs_field == BC1NEZ);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000467 if (!isBranch && IsMipsArchVariant(kMips32r6)) {
468 // All the 3 variants of POP10 (BOVC, BEQC, BEQZALC) and
469 // POP30 (BNVC, BNEC, BNEZALC) are branch ops.
470 isBranch |= opcode == POP10 || opcode == POP30 || opcode == BC ||
471 opcode == BALC ||
472 (opcode == POP66 && rs_field != 0) || // BEQZC
473 (opcode == POP76 && rs_field != 0); // BNEZC
474 }
475 return isBranch;
476}
477
478
479bool Assembler::IsBc(Instr instr) {
480 uint32_t opcode = GetOpcodeField(instr);
481 // Checks if the instruction is a BC or BALC.
482 return opcode == BC || opcode == BALC;
483}
484
485
486bool Assembler::IsBzc(Instr instr) {
487 uint32_t opcode = GetOpcodeField(instr);
488 // Checks if the instruction is BEQZC or BNEZC.
489 return (opcode == POP66 && GetRsField(instr) != 0) ||
490 (opcode == POP76 && GetRsField(instr) != 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000491}
492
493
494bool Assembler::IsEmittedConstant(Instr instr) {
495 uint32_t label_constant = GetLabelConst(instr);
496 return label_constant == 0; // Emitted label const in reg-exp engine.
Steve Block44f0eee2011-05-26 01:26:41 +0100497}
498
499
Ben Murdoch257744e2011-11-30 15:57:28 +0000500bool Assembler::IsBeq(Instr instr) {
501 return GetOpcodeField(instr) == BEQ;
502}
503
504
505bool Assembler::IsBne(Instr instr) {
506 return GetOpcodeField(instr) == BNE;
507}
508
509
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000510bool Assembler::IsBeqzc(Instr instr) {
511 uint32_t opcode = GetOpcodeField(instr);
512 return opcode == POP66 && GetRsField(instr) != 0;
513}
514
515
516bool Assembler::IsBnezc(Instr instr) {
517 uint32_t opcode = GetOpcodeField(instr);
518 return opcode == POP76 && GetRsField(instr) != 0;
519}
520
521
522bool Assembler::IsBeqc(Instr instr) {
523 uint32_t opcode = GetOpcodeField(instr);
524 uint32_t rs = GetRsField(instr);
525 uint32_t rt = GetRtField(instr);
526 return opcode == POP10 && rs != 0 && rs < rt; // && rt != 0
527}
528
529
530bool Assembler::IsBnec(Instr instr) {
531 uint32_t opcode = GetOpcodeField(instr);
532 uint32_t rs = GetRsField(instr);
533 uint32_t rt = GetRtField(instr);
534 return opcode == POP30 && rs != 0 && rs < rt; // && rt != 0
535}
536
537
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000538bool Assembler::IsJump(Instr instr) {
539 uint32_t opcode = GetOpcodeField(instr);
540 uint32_t rt_field = GetRtField(instr);
541 uint32_t rd_field = GetRdField(instr);
542 uint32_t function_field = GetFunctionField(instr);
543 // Checks if the instruction is a jump.
544 return opcode == J || opcode == JAL ||
545 (opcode == SPECIAL && rt_field == 0 &&
546 ((function_field == JALR) || (rd_field == 0 && (function_field == JR))));
547}
548
549
550bool Assembler::IsJ(Instr instr) {
551 uint32_t opcode = GetOpcodeField(instr);
552 // Checks if the instruction is a jump.
553 return opcode == J;
554}
555
556
Ben Murdoch589d6972011-11-30 16:04:58 +0000557bool Assembler::IsJal(Instr instr) {
558 return GetOpcodeField(instr) == JAL;
559}
560
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000561
Ben Murdoch589d6972011-11-30 16:04:58 +0000562bool Assembler::IsJr(Instr instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000563 if (!IsMipsArchVariant(kMips32r6)) {
564 return GetOpcodeField(instr) == SPECIAL && GetFunctionField(instr) == JR;
565 } else {
566 return GetOpcodeField(instr) == SPECIAL &&
567 GetRdField(instr) == 0 && GetFunctionField(instr) == JALR;
568 }
Ben Murdoch589d6972011-11-30 16:04:58 +0000569}
570
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000571
Ben Murdoch589d6972011-11-30 16:04:58 +0000572bool Assembler::IsJalr(Instr instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000573 return GetOpcodeField(instr) == SPECIAL &&
574 GetRdField(instr) != 0 && GetFunctionField(instr) == JALR;
Ben Murdoch589d6972011-11-30 16:04:58 +0000575}
576
577
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000578bool Assembler::IsLui(Instr instr) {
579 uint32_t opcode = GetOpcodeField(instr);
580 // Checks if the instruction is a load upper immediate.
581 return opcode == LUI;
582}
583
584
585bool Assembler::IsOri(Instr instr) {
586 uint32_t opcode = GetOpcodeField(instr);
587 // Checks if the instruction is a load upper immediate.
588 return opcode == ORI;
589}
590
591
Steve Block44f0eee2011-05-26 01:26:41 +0100592bool Assembler::IsNop(Instr instr, unsigned int type) {
593 // See Assembler::nop(type).
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000594 DCHECK(type < 32);
Ben Murdoch257744e2011-11-30 15:57:28 +0000595 uint32_t opcode = GetOpcodeField(instr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000596 uint32_t function = GetFunctionField(instr);
Ben Murdoch257744e2011-11-30 15:57:28 +0000597 uint32_t rt = GetRt(instr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000598 uint32_t rd = GetRd(instr);
Ben Murdoch257744e2011-11-30 15:57:28 +0000599 uint32_t sa = GetSa(instr);
Steve Block44f0eee2011-05-26 01:26:41 +0100600
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000601 // Traditional mips nop == sll(zero_reg, zero_reg, 0)
602 // When marking non-zero type, use sll(zero_reg, at, type)
603 // to avoid use of mips ssnop and ehb special encodings
604 // of the sll instruction.
Steve Block44f0eee2011-05-26 01:26:41 +0100605
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000606 Register nop_rt_reg = (type == 0) ? zero_reg : at;
607 bool ret = (opcode == SPECIAL && function == SLL &&
608 rd == static_cast<uint32_t>(ToNumber(zero_reg)) &&
609 rt == static_cast<uint32_t>(ToNumber(nop_rt_reg)) &&
Steve Block44f0eee2011-05-26 01:26:41 +0100610 sa == type);
611
612 return ret;
613}
614
615
616int32_t Assembler::GetBranchOffset(Instr instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000617 DCHECK(IsBranch(instr));
618 return (static_cast<int16_t>(instr & kImm16Mask)) << 2;
Steve Block44f0eee2011-05-26 01:26:41 +0100619}
620
621
622bool Assembler::IsLw(Instr instr) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000623 return (static_cast<uint32_t>(instr & kOpcodeMask) == LW);
Steve Block44f0eee2011-05-26 01:26:41 +0100624}
625
626
627int16_t Assembler::GetLwOffset(Instr instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000628 DCHECK(IsLw(instr));
Steve Block44f0eee2011-05-26 01:26:41 +0100629 return ((instr & kImm16Mask));
630}
631
632
633Instr Assembler::SetLwOffset(Instr instr, int16_t offset) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000634 DCHECK(IsLw(instr));
Steve Block44f0eee2011-05-26 01:26:41 +0100635
636 // We actually create a new lw instruction based on the original one.
637 Instr temp_instr = LW | (instr & kRsFieldMask) | (instr & kRtFieldMask)
638 | (offset & kImm16Mask);
639
640 return temp_instr;
641}
642
643
644bool Assembler::IsSw(Instr instr) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000645 return (static_cast<uint32_t>(instr & kOpcodeMask) == SW);
Steve Block44f0eee2011-05-26 01:26:41 +0100646}
647
648
649Instr Assembler::SetSwOffset(Instr instr, int16_t offset) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000650 DCHECK(IsSw(instr));
Steve Block44f0eee2011-05-26 01:26:41 +0100651 return ((instr & ~kImm16Mask) | (offset & kImm16Mask));
652}
653
654
655bool Assembler::IsAddImmediate(Instr instr) {
656 return ((instr & kOpcodeMask) == ADDIU);
657}
658
659
660Instr Assembler::SetAddImmediateOffset(Instr instr, int16_t offset) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000661 DCHECK(IsAddImmediate(instr));
Steve Block44f0eee2011-05-26 01:26:41 +0100662 return ((instr & ~kImm16Mask) | (offset & kImm16Mask));
Andrei Popescu31002712010-02-23 13:46:05 +0000663}
664
665
Ben Murdoch257744e2011-11-30 15:57:28 +0000666bool Assembler::IsAndImmediate(Instr instr) {
667 return GetOpcodeField(instr) == ANDI;
668}
669
670
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000671static Assembler::OffsetSize OffsetSizeInBits(Instr instr) {
672 if (IsMipsArchVariant(kMips32r6)) {
673 if (Assembler::IsBc(instr)) {
674 return Assembler::OffsetSize::kOffset26;
675 } else if (Assembler::IsBzc(instr)) {
676 return Assembler::OffsetSize::kOffset21;
677 }
678 }
679 return Assembler::OffsetSize::kOffset16;
680}
681
682
683static inline int32_t AddBranchOffset(int pos, Instr instr) {
684 int bits = OffsetSizeInBits(instr);
685 const int32_t mask = (1 << bits) - 1;
686 bits = 32 - bits;
687
688 // Do NOT change this to <<2. We rely on arithmetic shifts here, assuming
689 // the compiler uses arithmetic shifts for signed integers.
690 int32_t imm = ((instr & mask) << bits) >> (bits - 2);
691
692 if (imm == kEndOfChain) {
693 // EndOfChain sentinel is returned directly, not relative to pc or pos.
694 return kEndOfChain;
695 } else {
696 return pos + Assembler::kBranchPCOffset + imm;
697 }
698}
699
700
701int Assembler::target_at(int pos, bool is_internal) {
Andrei Popescu31002712010-02-23 13:46:05 +0000702 Instr instr = instr_at(pos);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000703 if (is_internal) {
704 if (instr == 0) {
705 return kEndOfChain;
706 } else {
707 int32_t instr_address = reinterpret_cast<int32_t>(buffer_ + pos);
708 int delta = static_cast<int>(instr_address - instr);
709 DCHECK(pos > delta);
710 return pos - delta;
711 }
712 }
Andrei Popescu31002712010-02-23 13:46:05 +0000713 if ((instr & ~kImm16Mask) == 0) {
714 // Emitted label constant, not part of a branch.
Steve Block44f0eee2011-05-26 01:26:41 +0100715 if (instr == 0) {
716 return kEndOfChain;
717 } else {
718 int32_t imm18 =((instr & static_cast<int32_t>(kImm16Mask)) << 16) >> 14;
719 return (imm18 + pos);
720 }
Andrei Popescu31002712010-02-23 13:46:05 +0000721 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000722 // Check we have a branch or jump instruction.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000723 DCHECK(IsBranch(instr) || IsLui(instr));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000724 if (IsBranch(instr)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000725 return AddBranchOffset(pos, instr);
726 } else {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000727 Instr instr_lui = instr_at(pos + 0 * Assembler::kInstrSize);
728 Instr instr_ori = instr_at(pos + 1 * Assembler::kInstrSize);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000729 DCHECK(IsOri(instr_ori));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000730 int32_t imm = (instr_lui & static_cast<int32_t>(kImm16Mask)) << kLuiShift;
731 imm |= (instr_ori & static_cast<int32_t>(kImm16Mask));
732
733 if (imm == kEndOfJumpChain) {
734 // EndOfChain sentinel is returned directly, not relative to pc or pos.
735 return kEndOfChain;
736 } else {
737 uint32_t instr_address = reinterpret_cast<int32_t>(buffer_ + pos);
738 int32_t delta = instr_address - imm;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000739 DCHECK(pos > delta);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000740 return pos - delta;
741 }
Steve Block44f0eee2011-05-26 01:26:41 +0100742 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000743 return 0;
Andrei Popescu31002712010-02-23 13:46:05 +0000744}
745
746
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000747static inline Instr SetBranchOffset(int32_t pos, int32_t target_pos,
748 Instr instr) {
749 int32_t bits = OffsetSizeInBits(instr);
750 int32_t imm = target_pos - (pos + Assembler::kBranchPCOffset);
751 DCHECK((imm & 3) == 0);
752 imm >>= 2;
753
754 const int32_t mask = (1 << bits) - 1;
755 instr &= ~mask;
756 DCHECK(is_intn(imm, bits));
757
758 return instr | (imm & mask);
759}
760
761
762void Assembler::target_at_put(int32_t pos, int32_t target_pos,
763 bool is_internal) {
Andrei Popescu31002712010-02-23 13:46:05 +0000764 Instr instr = instr_at(pos);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000765
766 if (is_internal) {
767 uint32_t imm = reinterpret_cast<uint32_t>(buffer_) + target_pos;
768 instr_at_put(pos, imm);
769 return;
770 }
Andrei Popescu31002712010-02-23 13:46:05 +0000771 if ((instr & ~kImm16Mask) == 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000772 DCHECK(target_pos == kEndOfChain || target_pos >= 0);
Andrei Popescu31002712010-02-23 13:46:05 +0000773 // Emitted label constant, not part of a branch.
774 // Make label relative to Code* of generated Code object.
775 instr_at_put(pos, target_pos + (Code::kHeaderSize - kHeapObjectTag));
776 return;
777 }
778
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000779 DCHECK(IsBranch(instr) || IsLui(instr));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000780 if (IsBranch(instr)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000781 instr = SetBranchOffset(pos, target_pos, instr);
782 instr_at_put(pos, instr);
783 } else {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000784 Instr instr_lui = instr_at(pos + 0 * Assembler::kInstrSize);
785 Instr instr_ori = instr_at(pos + 1 * Assembler::kInstrSize);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000786 DCHECK(IsOri(instr_ori));
787 uint32_t imm = reinterpret_cast<uint32_t>(buffer_) + target_pos;
788 DCHECK((imm & 3) == 0);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000789
790 instr_lui &= ~kImm16Mask;
791 instr_ori &= ~kImm16Mask;
792
793 instr_at_put(pos + 0 * Assembler::kInstrSize,
794 instr_lui | ((imm & kHiMask) >> kLuiShift));
795 instr_at_put(pos + 1 * Assembler::kInstrSize,
796 instr_ori | (imm & kImm16Mask));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000797 }
Andrei Popescu31002712010-02-23 13:46:05 +0000798}
799
800
801void Assembler::print(Label* L) {
802 if (L->is_unused()) {
803 PrintF("unused label\n");
804 } else if (L->is_bound()) {
805 PrintF("bound label to %d\n", L->pos());
806 } else if (L->is_linked()) {
807 Label l = *L;
808 PrintF("unbound label");
809 while (l.is_linked()) {
810 PrintF("@ %d ", l.pos());
811 Instr instr = instr_at(l.pos());
812 if ((instr & ~kImm16Mask) == 0) {
813 PrintF("value\n");
814 } else {
815 PrintF("%d\n", instr);
816 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000817 next(&l, internal_reference_positions_.find(l.pos()) !=
818 internal_reference_positions_.end());
Andrei Popescu31002712010-02-23 13:46:05 +0000819 }
820 } else {
821 PrintF("label in inconsistent state (pos = %d)\n", L->pos_);
822 }
823}
824
825
826void Assembler::bind_to(Label* L, int pos) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000827 DCHECK(0 <= pos && pos <= pc_offset()); // Must have valid binding position.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000828 int32_t trampoline_pos = kInvalidSlotPos;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000829 bool is_internal = false;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000830 if (L->is_linked() && !trampoline_emitted_) {
831 unbound_labels_count_--;
832 next_buffer_check_ += kTrampolineSlotsSize;
833 }
834
Andrei Popescu31002712010-02-23 13:46:05 +0000835 while (L->is_linked()) {
836 int32_t fixup_pos = L->pos();
Steve Block44f0eee2011-05-26 01:26:41 +0100837 int32_t dist = pos - fixup_pos;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000838 is_internal = internal_reference_positions_.find(fixup_pos) !=
839 internal_reference_positions_.end();
840 next(L, is_internal); // Call next before overwriting link with target at
841 // fixup_pos.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000842 Instr instr = instr_at(fixup_pos);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000843 if (is_internal) {
844 target_at_put(fixup_pos, pos, is_internal);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000845 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000846 if (IsBranch(instr)) {
847 int branch_offset = BranchOffset(instr);
848 if (dist > branch_offset) {
849 if (trampoline_pos == kInvalidSlotPos) {
850 trampoline_pos = get_trampoline_entry(fixup_pos);
851 CHECK(trampoline_pos != kInvalidSlotPos);
852 }
853 CHECK((trampoline_pos - fixup_pos) <= branch_offset);
854 target_at_put(fixup_pos, trampoline_pos, false);
855 fixup_pos = trampoline_pos;
856 dist = pos - fixup_pos;
857 }
858 target_at_put(fixup_pos, pos, false);
859 } else {
860 target_at_put(fixup_pos, pos, false);
861 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000862 }
Andrei Popescu31002712010-02-23 13:46:05 +0000863 }
864 L->bind_to(pos);
865
866 // Keep track of the last bound label so we don't eliminate any instructions
867 // before a bound label.
868 if (pos > last_bound_pos_)
869 last_bound_pos_ = pos;
870}
871
872
Andrei Popescu31002712010-02-23 13:46:05 +0000873void Assembler::bind(Label* L) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000874 DCHECK(!L->is_bound()); // Label can only be bound once.
Andrei Popescu31002712010-02-23 13:46:05 +0000875 bind_to(L, pc_offset());
876}
877
878
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000879void Assembler::next(Label* L, bool is_internal) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000880 DCHECK(L->is_linked());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000881 int link = target_at(L->pos(), is_internal);
Steve Block44f0eee2011-05-26 01:26:41 +0100882 if (link == kEndOfChain) {
Andrei Popescu31002712010-02-23 13:46:05 +0000883 L->Unuse();
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000884 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000885 DCHECK(link >= 0);
Steve Block44f0eee2011-05-26 01:26:41 +0100886 L->link_to(link);
Andrei Popescu31002712010-02-23 13:46:05 +0000887 }
888}
889
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000890
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000891bool Assembler::is_near(Label* L) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000892 DCHECK(L->is_bound());
893 return pc_offset() - L->pos() < kMaxBranchOffset - 4 * kInstrSize;
894}
895
896
897bool Assembler::is_near(Label* L, OffsetSize bits) {
898 if (L == nullptr || !L->is_bound()) return true;
899 return pc_offset() - L->pos() < (1 << (bits + 2 - 1)) - 1 - 5 * kInstrSize;
900}
901
902
903bool Assembler::is_near_branch(Label* L) {
904 DCHECK(L->is_bound());
905 return IsMipsArchVariant(kMips32r6) ? is_near_r6(L) : is_near_pre_r6(L);
906}
907
908
909int Assembler::BranchOffset(Instr instr) {
910 // At pre-R6 and for other R6 branches the offset is 16 bits.
911 int bits = OffsetSize::kOffset16;
912
913 if (IsMipsArchVariant(kMips32r6)) {
914 uint32_t opcode = GetOpcodeField(instr);
915 switch (opcode) {
916 // Checks BC or BALC.
917 case BC:
918 case BALC:
919 bits = OffsetSize::kOffset26;
920 break;
921
922 // Checks BEQZC or BNEZC.
923 case POP66:
924 case POP76:
925 if (GetRsField(instr) != 0) bits = OffsetSize::kOffset21;
926 break;
927 default:
928 break;
929 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000930 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000931
932 return (1 << (bits + 2 - 1)) - 1;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000933}
Andrei Popescu31002712010-02-23 13:46:05 +0000934
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000935
Andrei Popescu31002712010-02-23 13:46:05 +0000936// We have to use a temporary register for things that can be relocated even
937// if they can be encoded in the MIPS's 16 bits of immediate-offset instruction
938// space. There is no guarantee that the relocated location can be similarly
939// encoded.
Steve Block44f0eee2011-05-26 01:26:41 +0100940bool Assembler::MustUseReg(RelocInfo::Mode rmode) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000941 return !RelocInfo::IsNone(rmode);
Andrei Popescu31002712010-02-23 13:46:05 +0000942}
943
Andrei Popescu31002712010-02-23 13:46:05 +0000944void Assembler::GenInstrRegister(Opcode opcode,
945 Register rs,
946 Register rt,
947 Register rd,
948 uint16_t sa,
949 SecondaryField func) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000950 DCHECK(rd.is_valid() && rs.is_valid() && rt.is_valid() && is_uint5(sa));
Andrei Popescu31002712010-02-23 13:46:05 +0000951 Instr instr = opcode | (rs.code() << kRsShift) | (rt.code() << kRtShift)
952 | (rd.code() << kRdShift) | (sa << kSaShift) | func;
953 emit(instr);
954}
955
956
957void Assembler::GenInstrRegister(Opcode opcode,
Steve Block44f0eee2011-05-26 01:26:41 +0100958 Register rs,
959 Register rt,
960 uint16_t msb,
961 uint16_t lsb,
962 SecondaryField func) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000963 DCHECK(rs.is_valid() && rt.is_valid() && is_uint5(msb) && is_uint5(lsb));
Steve Block44f0eee2011-05-26 01:26:41 +0100964 Instr instr = opcode | (rs.code() << kRsShift) | (rt.code() << kRtShift)
965 | (msb << kRdShift) | (lsb << kSaShift) | func;
966 emit(instr);
967}
968
969
970void Assembler::GenInstrRegister(Opcode opcode,
Andrei Popescu31002712010-02-23 13:46:05 +0000971 SecondaryField fmt,
972 FPURegister ft,
973 FPURegister fs,
974 FPURegister fd,
975 SecondaryField func) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000976 DCHECK(fd.is_valid() && fs.is_valid() && ft.is_valid());
Steve Block44f0eee2011-05-26 01:26:41 +0100977 Instr instr = opcode | fmt | (ft.code() << kFtShift) | (fs.code() << kFsShift)
978 | (fd.code() << kFdShift) | func;
Andrei Popescu31002712010-02-23 13:46:05 +0000979 emit(instr);
980}
981
982
983void Assembler::GenInstrRegister(Opcode opcode,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000984 FPURegister fr,
985 FPURegister ft,
986 FPURegister fs,
987 FPURegister fd,
988 SecondaryField func) {
989 DCHECK(fd.is_valid() && fr.is_valid() && fs.is_valid() && ft.is_valid());
990 Instr instr = opcode | (fr.code() << kFrShift) | (ft.code() << kFtShift)
991 | (fs.code() << kFsShift) | (fd.code() << kFdShift) | func;
992 emit(instr);
993}
994
995
996void Assembler::GenInstrRegister(Opcode opcode,
Andrei Popescu31002712010-02-23 13:46:05 +0000997 SecondaryField fmt,
998 Register rt,
999 FPURegister fs,
1000 FPURegister fd,
1001 SecondaryField func) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001002 DCHECK(fd.is_valid() && fs.is_valid() && rt.is_valid());
Andrei Popescu31002712010-02-23 13:46:05 +00001003 Instr instr = opcode | fmt | (rt.code() << kRtShift)
Steve Block44f0eee2011-05-26 01:26:41 +01001004 | (fs.code() << kFsShift) | (fd.code() << kFdShift) | func;
1005 emit(instr);
1006}
1007
1008
1009void Assembler::GenInstrRegister(Opcode opcode,
1010 SecondaryField fmt,
1011 Register rt,
1012 FPUControlRegister fs,
1013 SecondaryField func) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001014 DCHECK(fs.is_valid() && rt.is_valid());
Steve Block44f0eee2011-05-26 01:26:41 +01001015 Instr instr =
1016 opcode | fmt | (rt.code() << kRtShift) | (fs.code() << kFsShift) | func;
Andrei Popescu31002712010-02-23 13:46:05 +00001017 emit(instr);
1018}
1019
1020
1021// Instructions with immediate value.
1022// Registers are in the order of the instruction encoding, from left to right.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001023void Assembler::GenInstrImmediate(Opcode opcode, Register rs, Register rt,
1024 int32_t j,
1025 CompactBranchType is_compact_branch) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001026 DCHECK(rs.is_valid() && rt.is_valid() && (is_int16(j) || is_uint16(j)));
Andrei Popescu31002712010-02-23 13:46:05 +00001027 Instr instr = opcode | (rs.code() << kRsShift) | (rt.code() << kRtShift)
1028 | (j & kImm16Mask);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001029 emit(instr, is_compact_branch);
Andrei Popescu31002712010-02-23 13:46:05 +00001030}
1031
1032
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001033void Assembler::GenInstrImmediate(Opcode opcode, Register rs, SecondaryField SF,
1034 int32_t j,
1035 CompactBranchType is_compact_branch) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001036 DCHECK(rs.is_valid() && (is_int16(j) || is_uint16(j)));
Andrei Popescu31002712010-02-23 13:46:05 +00001037 Instr instr = opcode | (rs.code() << kRsShift) | SF | (j & kImm16Mask);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001038 emit(instr, is_compact_branch);
Andrei Popescu31002712010-02-23 13:46:05 +00001039}
1040
1041
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001042void Assembler::GenInstrImmediate(Opcode opcode, Register rs, FPURegister ft,
1043 int32_t j,
1044 CompactBranchType is_compact_branch) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001045 DCHECK(rs.is_valid() && ft.is_valid() && (is_int16(j) || is_uint16(j)));
Andrei Popescu31002712010-02-23 13:46:05 +00001046 Instr instr = opcode | (rs.code() << kRsShift) | (ft.code() << kFtShift)
1047 | (j & kImm16Mask);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001048 emit(instr, is_compact_branch);
1049}
1050
1051
1052void Assembler::GenInstrImmediate(Opcode opcode, Register rs, int32_t offset21,
1053 CompactBranchType is_compact_branch) {
1054 DCHECK(rs.is_valid() && (is_int21(offset21)));
1055 Instr instr = opcode | (rs.code() << kRsShift) | (offset21 & kImm21Mask);
1056 emit(instr, is_compact_branch);
1057}
1058
1059
1060void Assembler::GenInstrImmediate(Opcode opcode, Register rs,
1061 uint32_t offset21) {
1062 DCHECK(rs.is_valid() && (is_uint21(offset21)));
1063 Instr instr = opcode | (rs.code() << kRsShift) | (offset21 & kImm21Mask);
Andrei Popescu31002712010-02-23 13:46:05 +00001064 emit(instr);
1065}
1066
1067
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001068void Assembler::GenInstrImmediate(Opcode opcode, int32_t offset26,
1069 CompactBranchType is_compact_branch) {
1070 DCHECK(is_int26(offset26));
1071 Instr instr = opcode | (offset26 & kImm26Mask);
1072 emit(instr, is_compact_branch);
1073}
1074
1075
Andrei Popescu31002712010-02-23 13:46:05 +00001076void Assembler::GenInstrJump(Opcode opcode,
Ben Murdoch589d6972011-11-30 16:04:58 +00001077 uint32_t address) {
Steve Block44f0eee2011-05-26 01:26:41 +01001078 BlockTrampolinePoolScope block_trampoline_pool(this);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001079 DCHECK(is_uint26(address));
Andrei Popescu31002712010-02-23 13:46:05 +00001080 Instr instr = opcode | address;
1081 emit(instr);
Steve Block44f0eee2011-05-26 01:26:41 +01001082 BlockTrampolinePoolFor(1); // For associated delay slot.
1083}
1084
1085
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001086// Returns the next free trampoline entry.
1087int32_t Assembler::get_trampoline_entry(int32_t pos) {
Ben Murdoch257744e2011-11-30 15:57:28 +00001088 int32_t trampoline_entry = kInvalidSlotPos;
Steve Block44f0eee2011-05-26 01:26:41 +01001089
Ben Murdoch257744e2011-11-30 15:57:28 +00001090 if (!internal_trampoline_exception_) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001091 if (trampoline_.start() > pos) {
1092 trampoline_entry = trampoline_.take_slot();
Steve Block44f0eee2011-05-26 01:26:41 +01001093 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001094
Ben Murdoch257744e2011-11-30 15:57:28 +00001095 if (kInvalidSlotPos == trampoline_entry) {
1096 internal_trampoline_exception_ = true;
Steve Block44f0eee2011-05-26 01:26:41 +01001097 }
1098 }
1099 return trampoline_entry;
Andrei Popescu31002712010-02-23 13:46:05 +00001100}
1101
1102
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001103uint32_t Assembler::jump_address(Label* L) {
Andrei Popescu31002712010-02-23 13:46:05 +00001104 int32_t target_pos;
Steve Block44f0eee2011-05-26 01:26:41 +01001105
Andrei Popescu31002712010-02-23 13:46:05 +00001106 if (L->is_bound()) {
1107 target_pos = L->pos();
1108 } else {
1109 if (L->is_linked()) {
Steve Block44f0eee2011-05-26 01:26:41 +01001110 target_pos = L->pos(); // L's link.
Steve Block44f0eee2011-05-26 01:26:41 +01001111 L->link_to(pc_offset());
Andrei Popescu31002712010-02-23 13:46:05 +00001112 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01001113 L->link_to(pc_offset());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001114 return kEndOfJumpChain;
1115 }
1116 }
1117
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001118 uint32_t imm = reinterpret_cast<uint32_t>(buffer_) + target_pos;
1119 DCHECK((imm & 3) == 0);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001120
1121 return imm;
1122}
1123
1124
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001125int32_t Assembler::branch_offset_helper(Label* L, OffsetSize bits) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001126 int32_t target_pos;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001127 int32_t pad = IsPrevInstrCompactBranch() ? kInstrSize : 0;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001128
1129 if (L->is_bound()) {
1130 target_pos = L->pos();
1131 } else {
1132 if (L->is_linked()) {
1133 target_pos = L->pos();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001134 L->link_to(pc_offset() + pad);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001135 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001136 L->link_to(pc_offset() + pad);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001137 if (!trampoline_emitted_) {
1138 unbound_labels_count_++;
1139 next_buffer_check_ -= kTrampolineSlotsSize;
1140 }
Steve Block44f0eee2011-05-26 01:26:41 +01001141 return kEndOfChain;
Andrei Popescu31002712010-02-23 13:46:05 +00001142 }
Andrei Popescu31002712010-02-23 13:46:05 +00001143 }
1144
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001145 int32_t offset = target_pos - (pc_offset() + kBranchPCOffset + pad);
1146 DCHECK(is_intn(offset, bits + 2));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001147 DCHECK((offset & 3) == 0);
Steve Block44f0eee2011-05-26 01:26:41 +01001148
Andrei Popescu31002712010-02-23 13:46:05 +00001149 return offset;
1150}
1151
1152
1153void Assembler::label_at_put(Label* L, int at_offset) {
1154 int target_pos;
1155 if (L->is_bound()) {
1156 target_pos = L->pos();
Steve Block44f0eee2011-05-26 01:26:41 +01001157 instr_at_put(at_offset, target_pos + (Code::kHeaderSize - kHeapObjectTag));
Andrei Popescu31002712010-02-23 13:46:05 +00001158 } else {
1159 if (L->is_linked()) {
Steve Block44f0eee2011-05-26 01:26:41 +01001160 target_pos = L->pos(); // L's link.
1161 int32_t imm18 = target_pos - at_offset;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001162 DCHECK((imm18 & 3) == 0);
Steve Block44f0eee2011-05-26 01:26:41 +01001163 int32_t imm16 = imm18 >> 2;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001164 DCHECK(is_int16(imm16));
Steve Block44f0eee2011-05-26 01:26:41 +01001165 instr_at_put(at_offset, (imm16 & kImm16Mask));
Andrei Popescu31002712010-02-23 13:46:05 +00001166 } else {
1167 target_pos = kEndOfChain;
Steve Block44f0eee2011-05-26 01:26:41 +01001168 instr_at_put(at_offset, 0);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001169 if (!trampoline_emitted_) {
1170 unbound_labels_count_++;
1171 next_buffer_check_ -= kTrampolineSlotsSize;
1172 }
Andrei Popescu31002712010-02-23 13:46:05 +00001173 }
1174 L->link_to(at_offset);
Andrei Popescu31002712010-02-23 13:46:05 +00001175 }
1176}
1177
1178
1179//------- Branch and jump instructions --------
1180
1181void Assembler::b(int16_t offset) {
1182 beq(zero_reg, zero_reg, offset);
1183}
1184
1185
1186void Assembler::bal(int16_t offset) {
Steve Block44f0eee2011-05-26 01:26:41 +01001187 positions_recorder()->WriteRecordedPositions();
Andrei Popescu31002712010-02-23 13:46:05 +00001188 bgezal(zero_reg, offset);
1189}
1190
1191
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001192void Assembler::bc(int32_t offset) {
1193 DCHECK(IsMipsArchVariant(kMips32r6));
1194 GenInstrImmediate(BC, offset, CompactBranchType::COMPACT_BRANCH);
1195}
1196
1197
1198void Assembler::balc(int32_t offset) {
1199 DCHECK(IsMipsArchVariant(kMips32r6));
1200 positions_recorder()->WriteRecordedPositions();
1201 GenInstrImmediate(BALC, offset, CompactBranchType::COMPACT_BRANCH);
1202}
1203
1204
Andrei Popescu31002712010-02-23 13:46:05 +00001205void Assembler::beq(Register rs, Register rt, int16_t offset) {
Steve Block44f0eee2011-05-26 01:26:41 +01001206 BlockTrampolinePoolScope block_trampoline_pool(this);
Andrei Popescu31002712010-02-23 13:46:05 +00001207 GenInstrImmediate(BEQ, rs, rt, offset);
Steve Block44f0eee2011-05-26 01:26:41 +01001208 BlockTrampolinePoolFor(1); // For associated delay slot.
Andrei Popescu31002712010-02-23 13:46:05 +00001209}
1210
1211
1212void Assembler::bgez(Register rs, int16_t offset) {
Steve Block44f0eee2011-05-26 01:26:41 +01001213 BlockTrampolinePoolScope block_trampoline_pool(this);
Andrei Popescu31002712010-02-23 13:46:05 +00001214 GenInstrImmediate(REGIMM, rs, BGEZ, offset);
Steve Block44f0eee2011-05-26 01:26:41 +01001215 BlockTrampolinePoolFor(1); // For associated delay slot.
Andrei Popescu31002712010-02-23 13:46:05 +00001216}
1217
1218
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001219void Assembler::bgezc(Register rt, int16_t offset) {
1220 DCHECK(IsMipsArchVariant(kMips32r6));
1221 DCHECK(!(rt.is(zero_reg)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001222 GenInstrImmediate(BLEZL, rt, rt, offset, CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001223}
1224
1225
1226void Assembler::bgeuc(Register rs, Register rt, int16_t offset) {
1227 DCHECK(IsMipsArchVariant(kMips32r6));
1228 DCHECK(!(rs.is(zero_reg)));
1229 DCHECK(!(rt.is(zero_reg)));
1230 DCHECK(rs.code() != rt.code());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001231 GenInstrImmediate(BLEZ, rs, rt, offset, CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001232}
1233
1234
1235void Assembler::bgec(Register rs, Register rt, int16_t offset) {
1236 DCHECK(IsMipsArchVariant(kMips32r6));
1237 DCHECK(!(rs.is(zero_reg)));
1238 DCHECK(!(rt.is(zero_reg)));
1239 DCHECK(rs.code() != rt.code());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001240 GenInstrImmediate(BLEZL, rs, rt, offset, CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001241}
1242
1243
Andrei Popescu31002712010-02-23 13:46:05 +00001244void Assembler::bgezal(Register rs, int16_t offset) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001245 DCHECK(!IsMipsArchVariant(kMips32r6) || rs.is(zero_reg));
Steve Block44f0eee2011-05-26 01:26:41 +01001246 BlockTrampolinePoolScope block_trampoline_pool(this);
1247 positions_recorder()->WriteRecordedPositions();
Andrei Popescu31002712010-02-23 13:46:05 +00001248 GenInstrImmediate(REGIMM, rs, BGEZAL, offset);
Steve Block44f0eee2011-05-26 01:26:41 +01001249 BlockTrampolinePoolFor(1); // For associated delay slot.
Andrei Popescu31002712010-02-23 13:46:05 +00001250}
1251
1252
1253void Assembler::bgtz(Register rs, int16_t offset) {
Steve Block44f0eee2011-05-26 01:26:41 +01001254 BlockTrampolinePoolScope block_trampoline_pool(this);
Andrei Popescu31002712010-02-23 13:46:05 +00001255 GenInstrImmediate(BGTZ, rs, zero_reg, offset);
Steve Block44f0eee2011-05-26 01:26:41 +01001256 BlockTrampolinePoolFor(1); // For associated delay slot.
Andrei Popescu31002712010-02-23 13:46:05 +00001257}
1258
1259
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001260void Assembler::bgtzc(Register rt, int16_t offset) {
1261 DCHECK(IsMipsArchVariant(kMips32r6));
1262 DCHECK(!(rt.is(zero_reg)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001263 GenInstrImmediate(BGTZL, zero_reg, rt, offset,
1264 CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001265}
1266
1267
Andrei Popescu31002712010-02-23 13:46:05 +00001268void Assembler::blez(Register rs, int16_t offset) {
Steve Block44f0eee2011-05-26 01:26:41 +01001269 BlockTrampolinePoolScope block_trampoline_pool(this);
Andrei Popescu31002712010-02-23 13:46:05 +00001270 GenInstrImmediate(BLEZ, rs, zero_reg, offset);
Steve Block44f0eee2011-05-26 01:26:41 +01001271 BlockTrampolinePoolFor(1); // For associated delay slot.
Andrei Popescu31002712010-02-23 13:46:05 +00001272}
1273
1274
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001275void Assembler::blezc(Register rt, int16_t offset) {
1276 DCHECK(IsMipsArchVariant(kMips32r6));
1277 DCHECK(!(rt.is(zero_reg)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001278 GenInstrImmediate(BLEZL, zero_reg, rt, offset,
1279 CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001280}
1281
1282
1283void Assembler::bltzc(Register rt, int16_t offset) {
1284 DCHECK(IsMipsArchVariant(kMips32r6));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001285 DCHECK(!rt.is(zero_reg));
1286 GenInstrImmediate(BGTZL, rt, rt, offset, CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001287}
1288
1289
1290void Assembler::bltuc(Register rs, Register rt, int16_t offset) {
1291 DCHECK(IsMipsArchVariant(kMips32r6));
1292 DCHECK(!(rs.is(zero_reg)));
1293 DCHECK(!(rt.is(zero_reg)));
1294 DCHECK(rs.code() != rt.code());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001295 GenInstrImmediate(BGTZ, rs, rt, offset, CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001296}
1297
1298
1299void Assembler::bltc(Register rs, Register rt, int16_t offset) {
1300 DCHECK(IsMipsArchVariant(kMips32r6));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001301 DCHECK(!rs.is(zero_reg));
1302 DCHECK(!rt.is(zero_reg));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001303 DCHECK(rs.code() != rt.code());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001304 GenInstrImmediate(BGTZL, rs, rt, offset, CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001305}
1306
1307
Andrei Popescu31002712010-02-23 13:46:05 +00001308void Assembler::bltz(Register rs, int16_t offset) {
Steve Block44f0eee2011-05-26 01:26:41 +01001309 BlockTrampolinePoolScope block_trampoline_pool(this);
Andrei Popescu31002712010-02-23 13:46:05 +00001310 GenInstrImmediate(REGIMM, rs, BLTZ, offset);
Steve Block44f0eee2011-05-26 01:26:41 +01001311 BlockTrampolinePoolFor(1); // For associated delay slot.
Andrei Popescu31002712010-02-23 13:46:05 +00001312}
1313
1314
1315void Assembler::bltzal(Register rs, int16_t offset) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001316 DCHECK(!IsMipsArchVariant(kMips32r6) || rs.is(zero_reg));
Steve Block44f0eee2011-05-26 01:26:41 +01001317 BlockTrampolinePoolScope block_trampoline_pool(this);
1318 positions_recorder()->WriteRecordedPositions();
Andrei Popescu31002712010-02-23 13:46:05 +00001319 GenInstrImmediate(REGIMM, rs, BLTZAL, offset);
Steve Block44f0eee2011-05-26 01:26:41 +01001320 BlockTrampolinePoolFor(1); // For associated delay slot.
Andrei Popescu31002712010-02-23 13:46:05 +00001321}
1322
1323
1324void Assembler::bne(Register rs, Register rt, int16_t offset) {
Steve Block44f0eee2011-05-26 01:26:41 +01001325 BlockTrampolinePoolScope block_trampoline_pool(this);
Andrei Popescu31002712010-02-23 13:46:05 +00001326 GenInstrImmediate(BNE, rs, rt, offset);
Steve Block44f0eee2011-05-26 01:26:41 +01001327 BlockTrampolinePoolFor(1); // For associated delay slot.
Andrei Popescu31002712010-02-23 13:46:05 +00001328}
1329
1330
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001331void Assembler::bovc(Register rs, Register rt, int16_t offset) {
1332 DCHECK(IsMipsArchVariant(kMips32r6));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001333 DCHECK(!rs.is(zero_reg));
1334 if (rs.code() >= rt.code()) {
1335 GenInstrImmediate(ADDI, rs, rt, offset, CompactBranchType::COMPACT_BRANCH);
1336 } else {
1337 GenInstrImmediate(ADDI, rt, rs, offset, CompactBranchType::COMPACT_BRANCH);
1338 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001339}
1340
1341
1342void Assembler::bnvc(Register rs, Register rt, int16_t offset) {
1343 DCHECK(IsMipsArchVariant(kMips32r6));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001344 DCHECK(!rs.is(zero_reg));
1345 if (rs.code() >= rt.code()) {
1346 GenInstrImmediate(DADDI, rs, rt, offset, CompactBranchType::COMPACT_BRANCH);
1347 } else {
1348 GenInstrImmediate(DADDI, rt, rs, offset, CompactBranchType::COMPACT_BRANCH);
1349 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001350}
1351
1352
1353void Assembler::blezalc(Register rt, int16_t offset) {
1354 DCHECK(IsMipsArchVariant(kMips32r6));
1355 DCHECK(!(rt.is(zero_reg)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001356 positions_recorder()->WriteRecordedPositions();
1357 GenInstrImmediate(BLEZ, zero_reg, rt, offset,
1358 CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001359}
1360
1361
1362void Assembler::bgezalc(Register rt, int16_t offset) {
1363 DCHECK(IsMipsArchVariant(kMips32r6));
1364 DCHECK(!(rt.is(zero_reg)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001365 positions_recorder()->WriteRecordedPositions();
1366 GenInstrImmediate(BLEZ, rt, rt, offset, CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001367}
1368
1369
1370void Assembler::bgezall(Register rs, int16_t offset) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001371 DCHECK(!IsMipsArchVariant(kMips32r6));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001372 DCHECK(!(rs.is(zero_reg)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001373 BlockTrampolinePoolScope block_trampoline_pool(this);
1374 positions_recorder()->WriteRecordedPositions();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001375 GenInstrImmediate(REGIMM, rs, BGEZALL, offset);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001376 BlockTrampolinePoolFor(1); // For associated delay slot.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001377}
1378
1379
1380void Assembler::bltzalc(Register rt, int16_t offset) {
1381 DCHECK(IsMipsArchVariant(kMips32r6));
1382 DCHECK(!(rt.is(zero_reg)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001383 positions_recorder()->WriteRecordedPositions();
1384 GenInstrImmediate(BGTZ, rt, rt, offset, CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001385}
1386
1387
1388void Assembler::bgtzalc(Register rt, int16_t offset) {
1389 DCHECK(IsMipsArchVariant(kMips32r6));
1390 DCHECK(!(rt.is(zero_reg)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001391 positions_recorder()->WriteRecordedPositions();
1392 GenInstrImmediate(BGTZ, zero_reg, rt, offset,
1393 CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001394}
1395
1396
1397void Assembler::beqzalc(Register rt, int16_t offset) {
1398 DCHECK(IsMipsArchVariant(kMips32r6));
1399 DCHECK(!(rt.is(zero_reg)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001400 positions_recorder()->WriteRecordedPositions();
1401 GenInstrImmediate(ADDI, zero_reg, rt, offset,
1402 CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001403}
1404
1405
1406void Assembler::bnezalc(Register rt, int16_t offset) {
1407 DCHECK(IsMipsArchVariant(kMips32r6));
1408 DCHECK(!(rt.is(zero_reg)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001409 positions_recorder()->WriteRecordedPositions();
1410 GenInstrImmediate(DADDI, zero_reg, rt, offset,
1411 CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001412}
1413
1414
1415void Assembler::beqc(Register rs, Register rt, int16_t offset) {
1416 DCHECK(IsMipsArchVariant(kMips32r6));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001417 DCHECK(rs.code() != rt.code() && rs.code() != 0 && rt.code() != 0);
1418 if (rs.code() < rt.code()) {
1419 GenInstrImmediate(ADDI, rs, rt, offset, CompactBranchType::COMPACT_BRANCH);
1420 } else {
1421 GenInstrImmediate(ADDI, rt, rs, offset, CompactBranchType::COMPACT_BRANCH);
1422 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001423}
1424
1425
1426void Assembler::beqzc(Register rs, int32_t offset) {
1427 DCHECK(IsMipsArchVariant(kMips32r6));
1428 DCHECK(!(rs.is(zero_reg)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001429 GenInstrImmediate(POP66, rs, offset, CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001430}
1431
1432
1433void Assembler::bnec(Register rs, Register rt, int16_t offset) {
1434 DCHECK(IsMipsArchVariant(kMips32r6));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001435 DCHECK(rs.code() != rt.code() && rs.code() != 0 && rt.code() != 0);
1436 if (rs.code() < rt.code()) {
1437 GenInstrImmediate(DADDI, rs, rt, offset, CompactBranchType::COMPACT_BRANCH);
1438 } else {
1439 GenInstrImmediate(DADDI, rt, rs, offset, CompactBranchType::COMPACT_BRANCH);
1440 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001441}
1442
1443
1444void Assembler::bnezc(Register rs, int32_t offset) {
1445 DCHECK(IsMipsArchVariant(kMips32r6));
1446 DCHECK(!(rs.is(zero_reg)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001447 GenInstrImmediate(POP76, rs, offset, CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001448}
1449
1450
Andrei Popescu31002712010-02-23 13:46:05 +00001451void Assembler::j(int32_t target) {
Ben Murdoch589d6972011-11-30 16:04:58 +00001452#if DEBUG
1453 // Get pc of delay slot.
1454 uint32_t ipc = reinterpret_cast<uint32_t>(pc_ + 1 * kInstrSize);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001455 bool in_range = ((ipc ^ static_cast<uint32_t>(target)) >>
1456 (kImm26Bits + kImmFieldShift)) == 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001457 DCHECK(in_range && ((target & 3) == 0));
Ben Murdoch589d6972011-11-30 16:04:58 +00001458#endif
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001459 BlockTrampolinePoolScope block_trampoline_pool(this);
1460 GenInstrJump(J, (target >> 2) & kImm26Mask);
1461 BlockTrampolinePoolFor(1); // For associated delay slot.
Andrei Popescu31002712010-02-23 13:46:05 +00001462}
1463
1464
1465void Assembler::jr(Register rs) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001466 if (!IsMipsArchVariant(kMips32r6)) {
1467 BlockTrampolinePoolScope block_trampoline_pool(this);
1468 if (rs.is(ra)) {
1469 positions_recorder()->WriteRecordedPositions();
1470 }
1471 GenInstrRegister(SPECIAL, rs, zero_reg, zero_reg, 0, JR);
1472 BlockTrampolinePoolFor(1); // For associated delay slot.
1473 } else {
1474 jalr(rs, zero_reg);
Steve Block44f0eee2011-05-26 01:26:41 +01001475 }
Andrei Popescu31002712010-02-23 13:46:05 +00001476}
1477
1478
1479void Assembler::jal(int32_t target) {
Ben Murdoch589d6972011-11-30 16:04:58 +00001480#ifdef DEBUG
1481 // Get pc of delay slot.
1482 uint32_t ipc = reinterpret_cast<uint32_t>(pc_ + 1 * kInstrSize);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001483 bool in_range = ((ipc ^ static_cast<uint32_t>(target)) >>
1484 (kImm26Bits + kImmFieldShift)) == 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001485 DCHECK(in_range && ((target & 3) == 0));
Ben Murdoch589d6972011-11-30 16:04:58 +00001486#endif
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001487 BlockTrampolinePoolScope block_trampoline_pool(this);
Steve Block44f0eee2011-05-26 01:26:41 +01001488 positions_recorder()->WriteRecordedPositions();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001489 GenInstrJump(JAL, (target >> 2) & kImm26Mask);
1490 BlockTrampolinePoolFor(1); // For associated delay slot.
Andrei Popescu31002712010-02-23 13:46:05 +00001491}
1492
1493
1494void Assembler::jalr(Register rs, Register rd) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001495 DCHECK(rs.code() != rd.code());
Steve Block44f0eee2011-05-26 01:26:41 +01001496 BlockTrampolinePoolScope block_trampoline_pool(this);
1497 positions_recorder()->WriteRecordedPositions();
Andrei Popescu31002712010-02-23 13:46:05 +00001498 GenInstrRegister(SPECIAL, rs, zero_reg, rd, 0, JALR);
Steve Block44f0eee2011-05-26 01:26:41 +01001499 BlockTrampolinePoolFor(1); // For associated delay slot.
Andrei Popescu31002712010-02-23 13:46:05 +00001500}
1501
1502
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001503void Assembler::jic(Register rt, int16_t offset) {
1504 DCHECK(IsMipsArchVariant(kMips32r6));
1505 GenInstrImmediate(POP66, zero_reg, rt, offset);
Ben Murdoch589d6972011-11-30 16:04:58 +00001506}
1507
1508
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001509void Assembler::jialc(Register rt, int16_t offset) {
1510 DCHECK(IsMipsArchVariant(kMips32r6));
1511 positions_recorder()->WriteRecordedPositions();
1512 GenInstrImmediate(POP76, zero_reg, rt, offset);
Ben Murdoch589d6972011-11-30 16:04:58 +00001513}
1514
1515
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001516// -------Data-processing-instructions---------
Andrei Popescu31002712010-02-23 13:46:05 +00001517
1518// Arithmetic.
1519
Andrei Popescu31002712010-02-23 13:46:05 +00001520void Assembler::addu(Register rd, Register rs, Register rt) {
1521 GenInstrRegister(SPECIAL, rs, rt, rd, 0, ADDU);
1522}
1523
1524
Andrei Popescu31002712010-02-23 13:46:05 +00001525void Assembler::addiu(Register rd, Register rs, int32_t j) {
1526 GenInstrImmediate(ADDIU, rs, rd, j);
Andrei Popescu31002712010-02-23 13:46:05 +00001527}
1528
1529
1530void Assembler::subu(Register rd, Register rs, Register rt) {
1531 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SUBU);
1532}
1533
1534
1535void Assembler::mul(Register rd, Register rs, Register rt) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001536 if (!IsMipsArchVariant(kMips32r6)) {
1537 GenInstrRegister(SPECIAL2, rs, rt, rd, 0, MUL);
1538 } else {
1539 GenInstrRegister(SPECIAL, rs, rt, rd, MUL_OP, MUL_MUH);
1540 }
1541}
1542
1543
1544void Assembler::mulu(Register rd, Register rs, Register rt) {
1545 DCHECK(IsMipsArchVariant(kMips32r6));
1546 GenInstrRegister(SPECIAL, rs, rt, rd, MUL_OP, MUL_MUH_U);
1547}
1548
1549
1550void Assembler::muh(Register rd, Register rs, Register rt) {
1551 DCHECK(IsMipsArchVariant(kMips32r6));
1552 GenInstrRegister(SPECIAL, rs, rt, rd, MUH_OP, MUL_MUH);
1553}
1554
1555
1556void Assembler::muhu(Register rd, Register rs, Register rt) {
1557 DCHECK(IsMipsArchVariant(kMips32r6));
1558 GenInstrRegister(SPECIAL, rs, rt, rd, MUH_OP, MUL_MUH_U);
1559}
1560
1561
1562void Assembler::mod(Register rd, Register rs, Register rt) {
1563 DCHECK(IsMipsArchVariant(kMips32r6));
1564 GenInstrRegister(SPECIAL, rs, rt, rd, MOD_OP, DIV_MOD);
1565}
1566
1567
1568void Assembler::modu(Register rd, Register rs, Register rt) {
1569 DCHECK(IsMipsArchVariant(kMips32r6));
1570 GenInstrRegister(SPECIAL, rs, rt, rd, MOD_OP, DIV_MOD_U);
Andrei Popescu31002712010-02-23 13:46:05 +00001571}
1572
1573
1574void Assembler::mult(Register rs, Register rt) {
1575 GenInstrRegister(SPECIAL, rs, rt, zero_reg, 0, MULT);
1576}
1577
1578
1579void Assembler::multu(Register rs, Register rt) {
1580 GenInstrRegister(SPECIAL, rs, rt, zero_reg, 0, MULTU);
1581}
1582
1583
1584void Assembler::div(Register rs, Register rt) {
1585 GenInstrRegister(SPECIAL, rs, rt, zero_reg, 0, DIV);
1586}
1587
1588
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001589void Assembler::div(Register rd, Register rs, Register rt) {
1590 DCHECK(IsMipsArchVariant(kMips32r6));
1591 GenInstrRegister(SPECIAL, rs, rt, rd, DIV_OP, DIV_MOD);
1592}
1593
1594
Andrei Popescu31002712010-02-23 13:46:05 +00001595void Assembler::divu(Register rs, Register rt) {
1596 GenInstrRegister(SPECIAL, rs, rt, zero_reg, 0, DIVU);
1597}
1598
1599
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001600void Assembler::divu(Register rd, Register rs, Register rt) {
1601 DCHECK(IsMipsArchVariant(kMips32r6));
1602 GenInstrRegister(SPECIAL, rs, rt, rd, DIV_OP, DIV_MOD_U);
1603}
1604
1605
Andrei Popescu31002712010-02-23 13:46:05 +00001606// Logical.
1607
1608void Assembler::and_(Register rd, Register rs, Register rt) {
1609 GenInstrRegister(SPECIAL, rs, rt, rd, 0, AND);
1610}
1611
1612
1613void Assembler::andi(Register rt, Register rs, int32_t j) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001614 DCHECK(is_uint16(j));
Andrei Popescu31002712010-02-23 13:46:05 +00001615 GenInstrImmediate(ANDI, rs, rt, j);
1616}
1617
1618
1619void Assembler::or_(Register rd, Register rs, Register rt) {
1620 GenInstrRegister(SPECIAL, rs, rt, rd, 0, OR);
1621}
1622
1623
1624void Assembler::ori(Register rt, Register rs, int32_t j) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001625 DCHECK(is_uint16(j));
Andrei Popescu31002712010-02-23 13:46:05 +00001626 GenInstrImmediate(ORI, rs, rt, j);
1627}
1628
1629
1630void Assembler::xor_(Register rd, Register rs, Register rt) {
1631 GenInstrRegister(SPECIAL, rs, rt, rd, 0, XOR);
1632}
1633
1634
1635void Assembler::xori(Register rt, Register rs, int32_t j) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001636 DCHECK(is_uint16(j));
Andrei Popescu31002712010-02-23 13:46:05 +00001637 GenInstrImmediate(XORI, rs, rt, j);
1638}
1639
1640
1641void Assembler::nor(Register rd, Register rs, Register rt) {
1642 GenInstrRegister(SPECIAL, rs, rt, rd, 0, NOR);
1643}
1644
1645
1646// Shifts.
Steve Block44f0eee2011-05-26 01:26:41 +01001647void Assembler::sll(Register rd,
1648 Register rt,
1649 uint16_t sa,
1650 bool coming_from_nop) {
1651 // Don't allow nop instructions in the form sll zero_reg, zero_reg to be
1652 // generated using the sll instruction. They must be generated using
1653 // nop(int/NopMarkerTypes) or MarkCode(int/NopMarkerTypes) pseudo
1654 // instructions.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001655 DCHECK(coming_from_nop || !(rd.is(zero_reg) && rt.is(zero_reg)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001656 GenInstrRegister(SPECIAL, zero_reg, rt, rd, sa & 0x1F, SLL);
Andrei Popescu31002712010-02-23 13:46:05 +00001657}
1658
1659
1660void Assembler::sllv(Register rd, Register rt, Register rs) {
1661 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SLLV);
1662}
1663
1664
1665void Assembler::srl(Register rd, Register rt, uint16_t sa) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001666 GenInstrRegister(SPECIAL, zero_reg, rt, rd, sa & 0x1F, SRL);
Andrei Popescu31002712010-02-23 13:46:05 +00001667}
1668
1669
1670void Assembler::srlv(Register rd, Register rt, Register rs) {
1671 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SRLV);
1672}
1673
1674
1675void Assembler::sra(Register rd, Register rt, uint16_t sa) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001676 GenInstrRegister(SPECIAL, zero_reg, rt, rd, sa & 0x1F, SRA);
Andrei Popescu31002712010-02-23 13:46:05 +00001677}
1678
1679
1680void Assembler::srav(Register rd, Register rt, Register rs) {
1681 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SRAV);
1682}
1683
1684
Steve Block44f0eee2011-05-26 01:26:41 +01001685void Assembler::rotr(Register rd, Register rt, uint16_t sa) {
1686 // Should be called via MacroAssembler::Ror.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001687 DCHECK(rd.is_valid() && rt.is_valid() && is_uint5(sa));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001688 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
Steve Block44f0eee2011-05-26 01:26:41 +01001689 Instr instr = SPECIAL | (1 << kRsShift) | (rt.code() << kRtShift)
1690 | (rd.code() << kRdShift) | (sa << kSaShift) | SRL;
1691 emit(instr);
1692}
1693
1694
1695void Assembler::rotrv(Register rd, Register rt, Register rs) {
1696 // Should be called via MacroAssembler::Ror.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001697 DCHECK(rd.is_valid() && rt.is_valid() && rs.is_valid());
1698 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
Steve Block44f0eee2011-05-26 01:26:41 +01001699 Instr instr = SPECIAL | (rs.code() << kRsShift) | (rt.code() << kRtShift)
1700 | (rd.code() << kRdShift) | (1 << kSaShift) | SRLV;
1701 emit(instr);
1702}
1703
1704
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001705void Assembler::lsa(Register rd, Register rt, Register rs, uint8_t sa) {
1706 DCHECK(rd.is_valid() && rt.is_valid() && rs.is_valid());
1707 DCHECK(sa < 5 && sa > 0);
1708 DCHECK(IsMipsArchVariant(kMips32r6));
1709 Instr instr = SPECIAL | (rs.code() << kRsShift) | (rt.code() << kRtShift) |
1710 (rd.code() << kRdShift) | (sa - 1) << kSaShift | LSA;
1711 emit(instr);
1712}
1713
1714
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001715// ------------Memory-instructions-------------
Andrei Popescu31002712010-02-23 13:46:05 +00001716
Steve Block44f0eee2011-05-26 01:26:41 +01001717// Helper for base-reg + offset, when offset is larger than int16.
1718void Assembler::LoadRegPlusOffsetToAt(const MemOperand& src) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001719 DCHECK(!src.rm().is(at));
1720 lui(at, (src.offset_ >> kLuiShift) & kImm16Mask);
Steve Block44f0eee2011-05-26 01:26:41 +01001721 ori(at, at, src.offset_ & kImm16Mask); // Load 32-bit offset.
1722 addu(at, at, src.rm()); // Add base register.
1723}
1724
1725
Andrei Popescu31002712010-02-23 13:46:05 +00001726void Assembler::lb(Register rd, const MemOperand& rs) {
Steve Block44f0eee2011-05-26 01:26:41 +01001727 if (is_int16(rs.offset_)) {
1728 GenInstrImmediate(LB, rs.rm(), rd, rs.offset_);
1729 } else { // Offset > 16 bits, use multiple instructions to load.
1730 LoadRegPlusOffsetToAt(rs);
1731 GenInstrImmediate(LB, at, rd, 0); // Equiv to lb(rd, MemOperand(at, 0));
1732 }
Andrei Popescu31002712010-02-23 13:46:05 +00001733}
1734
1735
1736void Assembler::lbu(Register rd, const MemOperand& rs) {
Steve Block44f0eee2011-05-26 01:26:41 +01001737 if (is_int16(rs.offset_)) {
1738 GenInstrImmediate(LBU, rs.rm(), rd, rs.offset_);
1739 } else { // Offset > 16 bits, use multiple instructions to load.
1740 LoadRegPlusOffsetToAt(rs);
1741 GenInstrImmediate(LBU, at, rd, 0); // Equiv to lbu(rd, MemOperand(at, 0));
1742 }
1743}
1744
1745
1746void Assembler::lh(Register rd, const MemOperand& rs) {
1747 if (is_int16(rs.offset_)) {
1748 GenInstrImmediate(LH, rs.rm(), rd, rs.offset_);
1749 } else { // Offset > 16 bits, use multiple instructions to load.
1750 LoadRegPlusOffsetToAt(rs);
1751 GenInstrImmediate(LH, at, rd, 0); // Equiv to lh(rd, MemOperand(at, 0));
1752 }
1753}
1754
1755
1756void Assembler::lhu(Register rd, const MemOperand& rs) {
1757 if (is_int16(rs.offset_)) {
1758 GenInstrImmediate(LHU, rs.rm(), rd, rs.offset_);
1759 } else { // Offset > 16 bits, use multiple instructions to load.
1760 LoadRegPlusOffsetToAt(rs);
1761 GenInstrImmediate(LHU, at, rd, 0); // Equiv to lhu(rd, MemOperand(at, 0));
1762 }
Andrei Popescu31002712010-02-23 13:46:05 +00001763}
1764
1765
1766void Assembler::lw(Register rd, const MemOperand& rs) {
Steve Block44f0eee2011-05-26 01:26:41 +01001767 if (is_int16(rs.offset_)) {
1768 GenInstrImmediate(LW, rs.rm(), rd, rs.offset_);
1769 } else { // Offset > 16 bits, use multiple instructions to load.
1770 LoadRegPlusOffsetToAt(rs);
1771 GenInstrImmediate(LW, at, rd, 0); // Equiv to lw(rd, MemOperand(at, 0));
1772 }
Steve Block44f0eee2011-05-26 01:26:41 +01001773}
1774
1775
1776void Assembler::lwl(Register rd, const MemOperand& rs) {
1777 GenInstrImmediate(LWL, rs.rm(), rd, rs.offset_);
1778}
1779
1780
1781void Assembler::lwr(Register rd, const MemOperand& rs) {
1782 GenInstrImmediate(LWR, rs.rm(), rd, rs.offset_);
Andrei Popescu31002712010-02-23 13:46:05 +00001783}
1784
1785
1786void Assembler::sb(Register rd, const MemOperand& rs) {
Steve Block44f0eee2011-05-26 01:26:41 +01001787 if (is_int16(rs.offset_)) {
1788 GenInstrImmediate(SB, rs.rm(), rd, rs.offset_);
1789 } else { // Offset > 16 bits, use multiple instructions to store.
1790 LoadRegPlusOffsetToAt(rs);
1791 GenInstrImmediate(SB, at, rd, 0); // Equiv to sb(rd, MemOperand(at, 0));
1792 }
1793}
1794
1795
1796void Assembler::sh(Register rd, const MemOperand& rs) {
1797 if (is_int16(rs.offset_)) {
1798 GenInstrImmediate(SH, rs.rm(), rd, rs.offset_);
1799 } else { // Offset > 16 bits, use multiple instructions to store.
1800 LoadRegPlusOffsetToAt(rs);
1801 GenInstrImmediate(SH, at, rd, 0); // Equiv to sh(rd, MemOperand(at, 0));
1802 }
Andrei Popescu31002712010-02-23 13:46:05 +00001803}
1804
1805
1806void Assembler::sw(Register rd, const MemOperand& rs) {
Steve Block44f0eee2011-05-26 01:26:41 +01001807 if (is_int16(rs.offset_)) {
1808 GenInstrImmediate(SW, rs.rm(), rd, rs.offset_);
1809 } else { // Offset > 16 bits, use multiple instructions to store.
1810 LoadRegPlusOffsetToAt(rs);
1811 GenInstrImmediate(SW, at, rd, 0); // Equiv to sw(rd, MemOperand(at, 0));
1812 }
Steve Block44f0eee2011-05-26 01:26:41 +01001813}
1814
1815
1816void Assembler::swl(Register rd, const MemOperand& rs) {
1817 GenInstrImmediate(SWL, rs.rm(), rd, rs.offset_);
1818}
1819
1820
1821void Assembler::swr(Register rd, const MemOperand& rs) {
1822 GenInstrImmediate(SWR, rs.rm(), rd, rs.offset_);
Andrei Popescu31002712010-02-23 13:46:05 +00001823}
1824
1825
1826void Assembler::lui(Register rd, int32_t j) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001827 DCHECK(is_uint16(j));
Andrei Popescu31002712010-02-23 13:46:05 +00001828 GenInstrImmediate(LUI, zero_reg, rd, j);
1829}
1830
1831
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001832void Assembler::aui(Register rt, Register rs, int32_t j) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001833 // This instruction uses same opcode as 'lui'. The difference in encoding is
1834 // 'lui' has zero reg. for rs field.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001835 DCHECK(!(rs.is(zero_reg)));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001836 DCHECK(is_uint16(j));
1837 GenInstrImmediate(LUI, rs, rt, j);
1838}
1839
1840
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001841// ---------PC-Relative instructions-----------
1842
1843void Assembler::addiupc(Register rs, int32_t imm19) {
1844 DCHECK(IsMipsArchVariant(kMips32r6));
1845 DCHECK(rs.is_valid() && is_int19(imm19));
1846 uint32_t imm21 = ADDIUPC << kImm19Bits | (imm19 & kImm19Mask);
1847 GenInstrImmediate(PCREL, rs, imm21);
1848}
1849
1850
1851void Assembler::lwpc(Register rs, int32_t offset19) {
1852 DCHECK(IsMipsArchVariant(kMips32r6));
1853 DCHECK(rs.is_valid() && is_int19(offset19));
1854 uint32_t imm21 = LWPC << kImm19Bits | (offset19 & kImm19Mask);
1855 GenInstrImmediate(PCREL, rs, imm21);
1856}
1857
1858
1859void Assembler::auipc(Register rs, int16_t imm16) {
1860 DCHECK(IsMipsArchVariant(kMips32r6));
1861 DCHECK(rs.is_valid());
1862 uint32_t imm21 = AUIPC << kImm16Bits | (imm16 & kImm16Mask);
1863 GenInstrImmediate(PCREL, rs, imm21);
1864}
1865
1866
1867void Assembler::aluipc(Register rs, int16_t imm16) {
1868 DCHECK(IsMipsArchVariant(kMips32r6));
1869 DCHECK(rs.is_valid());
1870 uint32_t imm21 = ALUIPC << kImm16Bits | (imm16 & kImm16Mask);
1871 GenInstrImmediate(PCREL, rs, imm21);
1872}
1873
1874
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001875// -------------Misc-instructions--------------
Andrei Popescu31002712010-02-23 13:46:05 +00001876
1877// Break / Trap instructions.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001878void Assembler::break_(uint32_t code, bool break_as_stop) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001879 DCHECK((code & ~0xfffff) == 0);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001880 // We need to invalidate breaks that could be stops as well because the
1881 // simulator expects a char pointer after the stop instruction.
1882 // See constants-mips.h for explanation.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001883 DCHECK((break_as_stop &&
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001884 code <= kMaxStopCode &&
1885 code > kMaxWatchpointCode) ||
1886 (!break_as_stop &&
1887 (code > kMaxStopCode ||
1888 code <= kMaxWatchpointCode)));
Andrei Popescu31002712010-02-23 13:46:05 +00001889 Instr break_instr = SPECIAL | BREAK | (code << 6);
1890 emit(break_instr);
1891}
1892
1893
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001894void Assembler::stop(const char* msg, uint32_t code) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001895 DCHECK(code > kMaxWatchpointCode);
1896 DCHECK(code <= kMaxStopCode);
1897#if V8_HOST_ARCH_MIPS
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001898 break_(0x54321);
1899#else // V8_HOST_ARCH_MIPS
1900 BlockTrampolinePoolFor(2);
1901 // The Simulator will handle the stop instruction and get the message address.
1902 // On MIPS stop() is just a special kind of break_().
1903 break_(code, true);
1904 emit(reinterpret_cast<Instr>(msg));
1905#endif
1906}
1907
1908
Andrei Popescu31002712010-02-23 13:46:05 +00001909void Assembler::tge(Register rs, Register rt, uint16_t code) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001910 DCHECK(is_uint10(code));
Andrei Popescu31002712010-02-23 13:46:05 +00001911 Instr instr = SPECIAL | TGE | rs.code() << kRsShift
1912 | rt.code() << kRtShift | code << 6;
1913 emit(instr);
1914}
1915
1916
1917void Assembler::tgeu(Register rs, Register rt, uint16_t code) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001918 DCHECK(is_uint10(code));
Andrei Popescu31002712010-02-23 13:46:05 +00001919 Instr instr = SPECIAL | TGEU | rs.code() << kRsShift
1920 | rt.code() << kRtShift | code << 6;
1921 emit(instr);
1922}
1923
1924
1925void Assembler::tlt(Register rs, Register rt, uint16_t code) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001926 DCHECK(is_uint10(code));
Andrei Popescu31002712010-02-23 13:46:05 +00001927 Instr instr =
1928 SPECIAL | TLT | rs.code() << kRsShift | rt.code() << kRtShift | code << 6;
1929 emit(instr);
1930}
1931
1932
1933void Assembler::tltu(Register rs, Register rt, uint16_t code) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001934 DCHECK(is_uint10(code));
Steve Block44f0eee2011-05-26 01:26:41 +01001935 Instr instr =
1936 SPECIAL | TLTU | rs.code() << kRsShift
Andrei Popescu31002712010-02-23 13:46:05 +00001937 | rt.code() << kRtShift | code << 6;
1938 emit(instr);
1939}
1940
1941
1942void Assembler::teq(Register rs, Register rt, uint16_t code) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001943 DCHECK(is_uint10(code));
Andrei Popescu31002712010-02-23 13:46:05 +00001944 Instr instr =
1945 SPECIAL | TEQ | rs.code() << kRsShift | rt.code() << kRtShift | code << 6;
1946 emit(instr);
1947}
1948
1949
1950void Assembler::tne(Register rs, Register rt, uint16_t code) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001951 DCHECK(is_uint10(code));
Andrei Popescu31002712010-02-23 13:46:05 +00001952 Instr instr =
1953 SPECIAL | TNE | rs.code() << kRsShift | rt.code() << kRtShift | code << 6;
1954 emit(instr);
1955}
1956
1957
1958// Move from HI/LO register.
1959
1960void Assembler::mfhi(Register rd) {
1961 GenInstrRegister(SPECIAL, zero_reg, zero_reg, rd, 0, MFHI);
1962}
1963
1964
1965void Assembler::mflo(Register rd) {
1966 GenInstrRegister(SPECIAL, zero_reg, zero_reg, rd, 0, MFLO);
1967}
1968
1969
1970// Set on less than instructions.
1971void Assembler::slt(Register rd, Register rs, Register rt) {
1972 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SLT);
1973}
1974
1975
1976void Assembler::sltu(Register rd, Register rs, Register rt) {
1977 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SLTU);
1978}
1979
1980
1981void Assembler::slti(Register rt, Register rs, int32_t j) {
1982 GenInstrImmediate(SLTI, rs, rt, j);
1983}
1984
1985
1986void Assembler::sltiu(Register rt, Register rs, int32_t j) {
1987 GenInstrImmediate(SLTIU, rs, rt, j);
1988}
1989
1990
Steve Block44f0eee2011-05-26 01:26:41 +01001991// Conditional move.
1992void Assembler::movz(Register rd, Register rs, Register rt) {
1993 GenInstrRegister(SPECIAL, rs, rt, rd, 0, MOVZ);
1994}
1995
1996
1997void Assembler::movn(Register rd, Register rs, Register rt) {
1998 GenInstrRegister(SPECIAL, rs, rt, rd, 0, MOVN);
1999}
2000
2001
2002void Assembler::movt(Register rd, Register rs, uint16_t cc) {
2003 Register rt;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002004 rt.reg_code = (cc & 0x0007) << 2 | 1;
Steve Block44f0eee2011-05-26 01:26:41 +01002005 GenInstrRegister(SPECIAL, rs, rt, rd, 0, MOVCI);
2006}
2007
2008
2009void Assembler::movf(Register rd, Register rs, uint16_t cc) {
2010 Register rt;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002011 rt.reg_code = (cc & 0x0007) << 2 | 0;
Steve Block44f0eee2011-05-26 01:26:41 +01002012 GenInstrRegister(SPECIAL, rs, rt, rd, 0, MOVCI);
2013}
2014
2015
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002016void Assembler::seleqz(Register rd, Register rs, Register rt) {
2017 DCHECK(IsMipsArchVariant(kMips32r6));
2018 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SELEQZ_S);
2019}
2020
2021
Steve Block44f0eee2011-05-26 01:26:41 +01002022// Bit twiddling.
2023void Assembler::clz(Register rd, Register rs) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002024 if (!IsMipsArchVariant(kMips32r6)) {
2025 // Clz instr requires same GPR number in 'rd' and 'rt' fields.
2026 GenInstrRegister(SPECIAL2, rs, rd, rd, 0, CLZ);
2027 } else {
2028 GenInstrRegister(SPECIAL, rs, zero_reg, rd, 1, CLZ_R6);
2029 }
Steve Block44f0eee2011-05-26 01:26:41 +01002030}
2031
2032
2033void Assembler::ins_(Register rt, Register rs, uint16_t pos, uint16_t size) {
2034 // Should be called via MacroAssembler::Ins.
2035 // Ins instr has 'rt' field as dest, and two uint5: msb, lsb.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002036 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
Steve Block44f0eee2011-05-26 01:26:41 +01002037 GenInstrRegister(SPECIAL3, rs, rt, pos + size - 1, pos, INS);
2038}
2039
2040
2041void Assembler::ext_(Register rt, Register rs, uint16_t pos, uint16_t size) {
2042 // Should be called via MacroAssembler::Ext.
2043 // Ext instr has 'rt' field as dest, and two uint5: msb, lsb.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002044 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
Steve Block44f0eee2011-05-26 01:26:41 +01002045 GenInstrRegister(SPECIAL3, rs, rt, size - 1, pos, EXT);
2046}
2047
2048
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002049void Assembler::bitswap(Register rd, Register rt) {
2050 DCHECK(IsMipsArchVariant(kMips32r6));
2051 GenInstrRegister(SPECIAL3, zero_reg, rt, rd, 0, BSHFL);
2052}
2053
2054
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002055void Assembler::pref(int32_t hint, const MemOperand& rs) {
2056 DCHECK(!IsMipsArchVariant(kLoongson));
2057 DCHECK(is_uint5(hint) && is_uint16(rs.offset_));
2058 Instr instr = PREF | (rs.rm().code() << kRsShift) | (hint << kRtShift)
2059 | (rs.offset_);
2060 emit(instr);
2061}
2062
2063
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002064void Assembler::align(Register rd, Register rs, Register rt, uint8_t bp) {
2065 DCHECK(IsMipsArchVariant(kMips32r6));
2066 DCHECK(is_uint3(bp));
2067 uint16_t sa = (ALIGN << kBp2Bits) | bp;
2068 GenInstrRegister(SPECIAL3, rs, rt, rd, sa, BSHFL);
2069}
2070
2071
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002072// --------Coprocessor-instructions----------------
Andrei Popescu31002712010-02-23 13:46:05 +00002073
2074// Load, store, move.
2075void Assembler::lwc1(FPURegister fd, const MemOperand& src) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002076 if (is_int16(src.offset_)) {
2077 GenInstrImmediate(LWC1, src.rm(), fd, src.offset_);
2078 } else { // Offset > 16 bits, use multiple instructions to load.
2079 LoadRegPlusOffsetToAt(src);
2080 GenInstrImmediate(LWC1, at, fd, 0);
2081 }
Andrei Popescu31002712010-02-23 13:46:05 +00002082}
2083
2084
2085void Assembler::ldc1(FPURegister fd, const MemOperand& src) {
Steve Block44f0eee2011-05-26 01:26:41 +01002086 // Workaround for non-8-byte alignment of HeapNumber, convert 64-bit
2087 // load to two 32-bit loads.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002088 DCHECK(!src.rm().is(at));
Ben Murdoch097c5b22016-05-18 11:27:45 +01002089 if (IsFp32Mode()) { // fp32 mode.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002090 if (is_int16(src.offset_) && is_int16(src.offset_ + kIntSize)) {
2091 GenInstrImmediate(LWC1, src.rm(), fd,
2092 src.offset_ + Register::kMantissaOffset);
2093 FPURegister nextfpreg;
2094 nextfpreg.setcode(fd.code() + 1);
2095 GenInstrImmediate(LWC1, src.rm(), nextfpreg,
2096 src.offset_ + Register::kExponentOffset);
2097 } else { // Offset > 16 bits, use multiple instructions to load.
2098 LoadRegPlusOffsetToAt(src);
2099 GenInstrImmediate(LWC1, at, fd, Register::kMantissaOffset);
2100 FPURegister nextfpreg;
2101 nextfpreg.setcode(fd.code() + 1);
2102 GenInstrImmediate(LWC1, at, nextfpreg, Register::kExponentOffset);
2103 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01002104 } else {
2105 DCHECK(IsFp64Mode() || IsFpxxMode());
2106 // Currently we support FPXX and FP64 on Mips32r2 and Mips32r6
2107 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
2108 if (is_int16(src.offset_) && is_int16(src.offset_ + kIntSize)) {
2109 GenInstrImmediate(LWC1, src.rm(), fd,
2110 src.offset_ + Register::kMantissaOffset);
2111 GenInstrImmediate(LW, src.rm(), at,
2112 src.offset_ + Register::kExponentOffset);
2113 mthc1(at, fd);
2114 } else { // Offset > 16 bits, use multiple instructions to load.
2115 LoadRegPlusOffsetToAt(src);
2116 GenInstrImmediate(LWC1, at, fd, Register::kMantissaOffset);
2117 GenInstrImmediate(LW, at, at, Register::kExponentOffset);
2118 mthc1(at, fd);
2119 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002120 }
Andrei Popescu31002712010-02-23 13:46:05 +00002121}
2122
2123
2124void Assembler::swc1(FPURegister fd, const MemOperand& src) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002125 if (is_int16(src.offset_)) {
2126 GenInstrImmediate(SWC1, src.rm(), fd, src.offset_);
2127 } else { // Offset > 16 bits, use multiple instructions to load.
2128 LoadRegPlusOffsetToAt(src);
2129 GenInstrImmediate(SWC1, at, fd, 0);
2130 }
Andrei Popescu31002712010-02-23 13:46:05 +00002131}
2132
2133
2134void Assembler::sdc1(FPURegister fd, const MemOperand& src) {
Steve Block44f0eee2011-05-26 01:26:41 +01002135 // Workaround for non-8-byte alignment of HeapNumber, convert 64-bit
2136 // store to two 32-bit stores.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002137 DCHECK(!src.rm().is(at));
2138 DCHECK(!src.rm().is(t8));
Ben Murdoch097c5b22016-05-18 11:27:45 +01002139 if (IsFp32Mode()) { // fp32 mode.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002140 if (is_int16(src.offset_) && is_int16(src.offset_ + kIntSize)) {
2141 GenInstrImmediate(SWC1, src.rm(), fd,
2142 src.offset_ + Register::kMantissaOffset);
2143 FPURegister nextfpreg;
2144 nextfpreg.setcode(fd.code() + 1);
2145 GenInstrImmediate(SWC1, src.rm(), nextfpreg,
2146 src.offset_ + Register::kExponentOffset);
2147 } else { // Offset > 16 bits, use multiple instructions to load.
2148 LoadRegPlusOffsetToAt(src);
2149 GenInstrImmediate(SWC1, at, fd, Register::kMantissaOffset);
2150 FPURegister nextfpreg;
2151 nextfpreg.setcode(fd.code() + 1);
2152 GenInstrImmediate(SWC1, at, nextfpreg, Register::kExponentOffset);
2153 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01002154 } else {
2155 DCHECK(IsFp64Mode() || IsFpxxMode());
2156 // Currently we support FPXX and FP64 on Mips32r2 and Mips32r6
2157 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
2158 if (is_int16(src.offset_) && is_int16(src.offset_ + kIntSize)) {
2159 GenInstrImmediate(SWC1, src.rm(), fd,
2160 src.offset_ + Register::kMantissaOffset);
2161 mfhc1(at, fd);
2162 GenInstrImmediate(SW, src.rm(), at,
2163 src.offset_ + Register::kExponentOffset);
2164 } else { // Offset > 16 bits, use multiple instructions to load.
2165 LoadRegPlusOffsetToAt(src);
2166 GenInstrImmediate(SWC1, at, fd, Register::kMantissaOffset);
2167 mfhc1(t8, fd);
2168 GenInstrImmediate(SW, at, t8, Register::kExponentOffset);
2169 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002170 }
Andrei Popescu31002712010-02-23 13:46:05 +00002171}
2172
2173
Steve Block44f0eee2011-05-26 01:26:41 +01002174void Assembler::mtc1(Register rt, FPURegister fs) {
Andrei Popescu31002712010-02-23 13:46:05 +00002175 GenInstrRegister(COP1, MTC1, rt, fs, f0);
2176}
2177
2178
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002179void Assembler::mthc1(Register rt, FPURegister fs) {
2180 GenInstrRegister(COP1, MTHC1, rt, fs, f0);
2181}
2182
2183
Steve Block44f0eee2011-05-26 01:26:41 +01002184void Assembler::mfc1(Register rt, FPURegister fs) {
Andrei Popescu31002712010-02-23 13:46:05 +00002185 GenInstrRegister(COP1, MFC1, rt, fs, f0);
2186}
2187
2188
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002189void Assembler::mfhc1(Register rt, FPURegister fs) {
2190 GenInstrRegister(COP1, MFHC1, rt, fs, f0);
2191}
2192
2193
Steve Block44f0eee2011-05-26 01:26:41 +01002194void Assembler::ctc1(Register rt, FPUControlRegister fs) {
2195 GenInstrRegister(COP1, CTC1, rt, fs);
2196}
2197
2198
2199void Assembler::cfc1(Register rt, FPUControlRegister fs) {
2200 GenInstrRegister(COP1, CFC1, rt, fs);
2201}
2202
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002203
Ben Murdoch589d6972011-11-30 16:04:58 +00002204void Assembler::DoubleAsTwoUInt32(double d, uint32_t* lo, uint32_t* hi) {
2205 uint64_t i;
2206 memcpy(&i, &d, 8);
2207
2208 *lo = i & 0xffffffff;
2209 *hi = i >> 32;
2210}
Steve Block44f0eee2011-05-26 01:26:41 +01002211
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002212
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002213void Assembler::movn_s(FPURegister fd, FPURegister fs, Register rt) {
2214 DCHECK(!IsMipsArchVariant(kMips32r6));
2215 GenInstrRegister(COP1, S, rt, fs, fd, MOVN_C);
2216}
2217
2218
2219void Assembler::movn_d(FPURegister fd, FPURegister fs, Register rt) {
2220 DCHECK(!IsMipsArchVariant(kMips32r6));
2221 GenInstrRegister(COP1, D, rt, fs, fd, MOVN_C);
2222}
2223
2224
2225void Assembler::sel(SecondaryField fmt, FPURegister fd, FPURegister fs,
2226 FPURegister ft) {
2227 DCHECK(IsMipsArchVariant(kMips32r6));
2228 DCHECK((fmt == D) || (fmt == S));
2229
2230 GenInstrRegister(COP1, fmt, ft, fs, fd, SEL);
2231}
2232
2233
2234void Assembler::sel_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2235 sel(S, fd, fs, ft);
2236}
2237
2238
2239void Assembler::sel_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2240 sel(D, fd, fs, ft);
2241}
2242
2243
2244void Assembler::seleqz(SecondaryField fmt, FPURegister fd, FPURegister fs,
2245 FPURegister ft) {
2246 DCHECK(IsMipsArchVariant(kMips32r6));
2247 DCHECK((fmt == D) || (fmt == S));
2248 GenInstrRegister(COP1, fmt, ft, fs, fd, SELEQZ_C);
2249}
2250
2251
2252void Assembler::selnez(Register rd, Register rs, Register rt) {
2253 DCHECK(IsMipsArchVariant(kMips32r6));
2254 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SELNEZ_S);
2255}
2256
2257
2258void Assembler::selnez(SecondaryField fmt, FPURegister fd, FPURegister fs,
2259 FPURegister ft) {
2260 DCHECK(IsMipsArchVariant(kMips32r6));
2261 DCHECK((fmt == D) || (fmt == S));
2262 GenInstrRegister(COP1, fmt, ft, fs, fd, SELNEZ_C);
2263}
2264
2265
2266void Assembler::seleqz_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2267 seleqz(D, fd, fs, ft);
2268}
2269
2270
2271void Assembler::seleqz_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2272 seleqz(S, fd, fs, ft);
2273}
2274
2275
2276void Assembler::selnez_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2277 selnez(D, fd, fs, ft);
2278}
2279
2280
2281void Assembler::selnez_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2282 selnez(S, fd, fs, ft);
2283}
2284
2285
2286void Assembler::movz_s(FPURegister fd, FPURegister fs, Register rt) {
2287 DCHECK(!IsMipsArchVariant(kMips32r6));
2288 GenInstrRegister(COP1, S, rt, fs, fd, MOVZ_C);
2289}
2290
2291
2292void Assembler::movz_d(FPURegister fd, FPURegister fs, Register rt) {
2293 DCHECK(!IsMipsArchVariant(kMips32r6));
2294 GenInstrRegister(COP1, D, rt, fs, fd, MOVZ_C);
2295}
2296
2297
2298void Assembler::movt_s(FPURegister fd, FPURegister fs, uint16_t cc) {
2299 DCHECK(!IsMipsArchVariant(kMips32r6));
2300 FPURegister ft;
2301 ft.reg_code = (cc & 0x0007) << 2 | 1;
2302 GenInstrRegister(COP1, S, ft, fs, fd, MOVF);
2303}
2304
2305
2306void Assembler::movt_d(FPURegister fd, FPURegister fs, uint16_t cc) {
2307 DCHECK(!IsMipsArchVariant(kMips32r6));
2308 FPURegister ft;
2309 ft.reg_code = (cc & 0x0007) << 2 | 1;
2310 GenInstrRegister(COP1, D, ft, fs, fd, MOVF);
2311}
2312
2313
2314void Assembler::movf_s(FPURegister fd, FPURegister fs, uint16_t cc) {
2315 DCHECK(!IsMipsArchVariant(kMips32r6));
2316 FPURegister ft;
2317 ft.reg_code = (cc & 0x0007) << 2 | 0;
2318 GenInstrRegister(COP1, S, ft, fs, fd, MOVF);
2319}
2320
2321
2322void Assembler::movf_d(FPURegister fd, FPURegister fs, uint16_t cc) {
2323 DCHECK(!IsMipsArchVariant(kMips32r6));
2324 FPURegister ft;
2325 ft.reg_code = (cc & 0x0007) << 2 | 0;
2326 GenInstrRegister(COP1, D, ft, fs, fd, MOVF);
2327}
2328
2329
Steve Block44f0eee2011-05-26 01:26:41 +01002330// Arithmetic.
2331
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002332void Assembler::add_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2333 GenInstrRegister(COP1, S, ft, fs, fd, ADD_S);
2334}
2335
2336
Steve Block44f0eee2011-05-26 01:26:41 +01002337void Assembler::add_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2338 GenInstrRegister(COP1, D, ft, fs, fd, ADD_D);
2339}
2340
2341
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002342void Assembler::sub_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2343 GenInstrRegister(COP1, S, ft, fs, fd, SUB_S);
2344}
2345
2346
Steve Block44f0eee2011-05-26 01:26:41 +01002347void Assembler::sub_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2348 GenInstrRegister(COP1, D, ft, fs, fd, SUB_D);
2349}
2350
2351
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002352void Assembler::mul_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2353 GenInstrRegister(COP1, S, ft, fs, fd, MUL_S);
2354}
2355
2356
Steve Block44f0eee2011-05-26 01:26:41 +01002357void Assembler::mul_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2358 GenInstrRegister(COP1, D, ft, fs, fd, MUL_D);
2359}
2360
2361
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002362void Assembler::madd_d(FPURegister fd, FPURegister fr, FPURegister fs,
2363 FPURegister ft) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002364 DCHECK(IsMipsArchVariant(kMips32r2));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002365 GenInstrRegister(COP1X, fr, ft, fs, fd, MADD_D);
2366}
2367
2368
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002369void Assembler::div_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2370 GenInstrRegister(COP1, S, ft, fs, fd, DIV_S);
2371}
2372
2373
Steve Block44f0eee2011-05-26 01:26:41 +01002374void Assembler::div_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2375 GenInstrRegister(COP1, D, ft, fs, fd, DIV_D);
2376}
2377
2378
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002379void Assembler::abs_s(FPURegister fd, FPURegister fs) {
2380 GenInstrRegister(COP1, S, f0, fs, fd, ABS_S);
2381}
2382
2383
Steve Block44f0eee2011-05-26 01:26:41 +01002384void Assembler::abs_d(FPURegister fd, FPURegister fs) {
2385 GenInstrRegister(COP1, D, f0, fs, fd, ABS_D);
2386}
2387
2388
2389void Assembler::mov_d(FPURegister fd, FPURegister fs) {
2390 GenInstrRegister(COP1, D, f0, fs, fd, MOV_D);
2391}
2392
2393
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002394void Assembler::mov_s(FPURegister fd, FPURegister fs) {
2395 GenInstrRegister(COP1, S, f0, fs, fd, MOV_S);
2396}
2397
2398
2399void Assembler::neg_s(FPURegister fd, FPURegister fs) {
2400 GenInstrRegister(COP1, S, f0, fs, fd, NEG_S);
2401}
2402
2403
Steve Block44f0eee2011-05-26 01:26:41 +01002404void Assembler::neg_d(FPURegister fd, FPURegister fs) {
2405 GenInstrRegister(COP1, D, f0, fs, fd, NEG_D);
2406}
2407
2408
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002409void Assembler::sqrt_s(FPURegister fd, FPURegister fs) {
2410 GenInstrRegister(COP1, S, f0, fs, fd, SQRT_S);
2411}
2412
2413
Steve Block44f0eee2011-05-26 01:26:41 +01002414void Assembler::sqrt_d(FPURegister fd, FPURegister fs) {
2415 GenInstrRegister(COP1, D, f0, fs, fd, SQRT_D);
Andrei Popescu31002712010-02-23 13:46:05 +00002416}
2417
2418
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002419void Assembler::rsqrt_s(FPURegister fd, FPURegister fs) {
2420 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
2421 GenInstrRegister(COP1, S, f0, fs, fd, RSQRT_S);
2422}
2423
2424
2425void Assembler::rsqrt_d(FPURegister fd, FPURegister fs) {
2426 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
2427 GenInstrRegister(COP1, D, f0, fs, fd, RSQRT_D);
2428}
2429
2430
2431void Assembler::recip_d(FPURegister fd, FPURegister fs) {
2432 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
2433 GenInstrRegister(COP1, D, f0, fs, fd, RECIP_D);
2434}
2435
2436
2437void Assembler::recip_s(FPURegister fd, FPURegister fs) {
2438 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
2439 GenInstrRegister(COP1, S, f0, fs, fd, RECIP_S);
2440}
2441
2442
Andrei Popescu31002712010-02-23 13:46:05 +00002443// Conversions.
2444
2445void Assembler::cvt_w_s(FPURegister fd, FPURegister fs) {
2446 GenInstrRegister(COP1, S, f0, fs, fd, CVT_W_S);
2447}
2448
2449
2450void Assembler::cvt_w_d(FPURegister fd, FPURegister fs) {
2451 GenInstrRegister(COP1, D, f0, fs, fd, CVT_W_D);
2452}
2453
2454
Steve Block44f0eee2011-05-26 01:26:41 +01002455void Assembler::trunc_w_s(FPURegister fd, FPURegister fs) {
2456 GenInstrRegister(COP1, S, f0, fs, fd, TRUNC_W_S);
2457}
2458
2459
2460void Assembler::trunc_w_d(FPURegister fd, FPURegister fs) {
2461 GenInstrRegister(COP1, D, f0, fs, fd, TRUNC_W_D);
2462}
2463
2464
2465void Assembler::round_w_s(FPURegister fd, FPURegister fs) {
2466 GenInstrRegister(COP1, S, f0, fs, fd, ROUND_W_S);
2467}
2468
2469
2470void Assembler::round_w_d(FPURegister fd, FPURegister fs) {
2471 GenInstrRegister(COP1, D, f0, fs, fd, ROUND_W_D);
2472}
2473
2474
2475void Assembler::floor_w_s(FPURegister fd, FPURegister fs) {
2476 GenInstrRegister(COP1, S, f0, fs, fd, FLOOR_W_S);
2477}
2478
2479
2480void Assembler::floor_w_d(FPURegister fd, FPURegister fs) {
2481 GenInstrRegister(COP1, D, f0, fs, fd, FLOOR_W_D);
2482}
2483
2484
2485void Assembler::ceil_w_s(FPURegister fd, FPURegister fs) {
2486 GenInstrRegister(COP1, S, f0, fs, fd, CEIL_W_S);
2487}
2488
2489
2490void Assembler::ceil_w_d(FPURegister fd, FPURegister fs) {
2491 GenInstrRegister(COP1, D, f0, fs, fd, CEIL_W_D);
2492}
2493
2494
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002495void Assembler::rint_s(FPURegister fd, FPURegister fs) { rint(S, fd, fs); }
2496
2497
2498void Assembler::rint(SecondaryField fmt, FPURegister fd, FPURegister fs) {
2499 DCHECK(IsMipsArchVariant(kMips32r6));
2500 DCHECK((fmt == D) || (fmt == S));
2501 GenInstrRegister(COP1, fmt, f0, fs, fd, RINT);
2502}
2503
2504
2505void Assembler::rint_d(FPURegister fd, FPURegister fs) { rint(D, fd, fs); }
2506
2507
Andrei Popescu31002712010-02-23 13:46:05 +00002508void Assembler::cvt_l_s(FPURegister fd, FPURegister fs) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002509 DCHECK((IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) &&
2510 IsFp64Mode());
Andrei Popescu31002712010-02-23 13:46:05 +00002511 GenInstrRegister(COP1, S, f0, fs, fd, CVT_L_S);
2512}
2513
2514
2515void Assembler::cvt_l_d(FPURegister fd, FPURegister fs) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002516 DCHECK((IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) &&
2517 IsFp64Mode());
Andrei Popescu31002712010-02-23 13:46:05 +00002518 GenInstrRegister(COP1, D, f0, fs, fd, CVT_L_D);
2519}
2520
2521
Steve Block44f0eee2011-05-26 01:26:41 +01002522void Assembler::trunc_l_s(FPURegister fd, FPURegister fs) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002523 DCHECK((IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) &&
2524 IsFp64Mode());
Steve Block44f0eee2011-05-26 01:26:41 +01002525 GenInstrRegister(COP1, S, f0, fs, fd, TRUNC_L_S);
2526}
2527
2528
2529void Assembler::trunc_l_d(FPURegister fd, FPURegister fs) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002530 DCHECK((IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) &&
2531 IsFp64Mode());
Steve Block44f0eee2011-05-26 01:26:41 +01002532 GenInstrRegister(COP1, D, f0, fs, fd, TRUNC_L_D);
2533}
2534
2535
2536void Assembler::round_l_s(FPURegister fd, FPURegister fs) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002537 DCHECK((IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) &&
2538 IsFp64Mode());
Steve Block44f0eee2011-05-26 01:26:41 +01002539 GenInstrRegister(COP1, S, f0, fs, fd, ROUND_L_S);
2540}
2541
2542
2543void Assembler::round_l_d(FPURegister fd, FPURegister fs) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002544 DCHECK((IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) &&
2545 IsFp64Mode());
Steve Block44f0eee2011-05-26 01:26:41 +01002546 GenInstrRegister(COP1, D, f0, fs, fd, ROUND_L_D);
2547}
2548
2549
2550void Assembler::floor_l_s(FPURegister fd, FPURegister fs) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002551 DCHECK((IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) &&
2552 IsFp64Mode());
Steve Block44f0eee2011-05-26 01:26:41 +01002553 GenInstrRegister(COP1, S, f0, fs, fd, FLOOR_L_S);
2554}
2555
2556
2557void Assembler::floor_l_d(FPURegister fd, FPURegister fs) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002558 DCHECK((IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) &&
2559 IsFp64Mode());
Steve Block44f0eee2011-05-26 01:26:41 +01002560 GenInstrRegister(COP1, D, f0, fs, fd, FLOOR_L_D);
2561}
2562
2563
2564void Assembler::ceil_l_s(FPURegister fd, FPURegister fs) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002565 DCHECK((IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) &&
2566 IsFp64Mode());
Steve Block44f0eee2011-05-26 01:26:41 +01002567 GenInstrRegister(COP1, S, f0, fs, fd, CEIL_L_S);
2568}
2569
2570
2571void Assembler::ceil_l_d(FPURegister fd, FPURegister fs) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002572 DCHECK((IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) &&
2573 IsFp64Mode());
Steve Block44f0eee2011-05-26 01:26:41 +01002574 GenInstrRegister(COP1, D, f0, fs, fd, CEIL_L_D);
2575}
2576
2577
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002578void Assembler::class_s(FPURegister fd, FPURegister fs) {
2579 DCHECK(IsMipsArchVariant(kMips32r6));
2580 GenInstrRegister(COP1, S, f0, fs, fd, CLASS_S);
2581}
2582
2583
2584void Assembler::class_d(FPURegister fd, FPURegister fs) {
2585 DCHECK(IsMipsArchVariant(kMips32r6));
2586 GenInstrRegister(COP1, D, f0, fs, fd, CLASS_D);
2587}
2588
2589
2590void Assembler::min(SecondaryField fmt, FPURegister fd, FPURegister fs,
2591 FPURegister ft) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002592 DCHECK(IsMipsArchVariant(kMips32r6));
2593 DCHECK((fmt == D) || (fmt == S));
2594 GenInstrRegister(COP1, fmt, ft, fs, fd, MIN);
2595}
2596
2597
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002598void Assembler::mina(SecondaryField fmt, FPURegister fd, FPURegister fs,
2599 FPURegister ft) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002600 DCHECK(IsMipsArchVariant(kMips32r6));
2601 DCHECK((fmt == D) || (fmt == S));
2602 GenInstrRegister(COP1, fmt, ft, fs, fd, MINA);
2603}
2604
2605
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002606void Assembler::max(SecondaryField fmt, FPURegister fd, FPURegister fs,
2607 FPURegister ft) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002608 DCHECK(IsMipsArchVariant(kMips32r6));
2609 DCHECK((fmt == D) || (fmt == S));
2610 GenInstrRegister(COP1, fmt, ft, fs, fd, MAX);
2611}
2612
2613
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002614void Assembler::maxa(SecondaryField fmt, FPURegister fd, FPURegister fs,
2615 FPURegister ft) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002616 DCHECK(IsMipsArchVariant(kMips32r6));
2617 DCHECK((fmt == D) || (fmt == S));
2618 GenInstrRegister(COP1, fmt, ft, fs, fd, MAXA);
2619}
2620
2621
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002622void Assembler::min_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2623 min(S, fd, fs, ft);
2624}
2625
2626
2627void Assembler::min_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2628 min(D, fd, fs, ft);
2629}
2630
2631
2632void Assembler::max_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2633 max(S, fd, fs, ft);
2634}
2635
2636
2637void Assembler::max_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2638 max(D, fd, fs, ft);
2639}
2640
2641
2642void Assembler::mina_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2643 mina(S, fd, fs, ft);
2644}
2645
2646
2647void Assembler::mina_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2648 mina(D, fd, fs, ft);
2649}
2650
2651
2652void Assembler::maxa_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2653 maxa(S, fd, fs, ft);
2654}
2655
2656
2657void Assembler::maxa_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2658 maxa(D, fd, fs, ft);
2659}
2660
2661
Andrei Popescu31002712010-02-23 13:46:05 +00002662void Assembler::cvt_s_w(FPURegister fd, FPURegister fs) {
2663 GenInstrRegister(COP1, W, f0, fs, fd, CVT_S_W);
2664}
2665
2666
2667void Assembler::cvt_s_l(FPURegister fd, FPURegister fs) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002668 DCHECK((IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) &&
2669 IsFp64Mode());
Andrei Popescu31002712010-02-23 13:46:05 +00002670 GenInstrRegister(COP1, L, f0, fs, fd, CVT_S_L);
2671}
2672
2673
2674void Assembler::cvt_s_d(FPURegister fd, FPURegister fs) {
2675 GenInstrRegister(COP1, D, f0, fs, fd, CVT_S_D);
2676}
2677
2678
2679void Assembler::cvt_d_w(FPURegister fd, FPURegister fs) {
2680 GenInstrRegister(COP1, W, f0, fs, fd, CVT_D_W);
2681}
2682
2683
2684void Assembler::cvt_d_l(FPURegister fd, FPURegister fs) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002685 DCHECK((IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) &&
2686 IsFp64Mode());
Andrei Popescu31002712010-02-23 13:46:05 +00002687 GenInstrRegister(COP1, L, f0, fs, fd, CVT_D_L);
2688}
2689
2690
2691void Assembler::cvt_d_s(FPURegister fd, FPURegister fs) {
2692 GenInstrRegister(COP1, S, f0, fs, fd, CVT_D_S);
2693}
2694
2695
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002696// Conditions for >= MIPSr6.
2697void Assembler::cmp(FPUCondition cond, SecondaryField fmt,
2698 FPURegister fd, FPURegister fs, FPURegister ft) {
2699 DCHECK(IsMipsArchVariant(kMips32r6));
2700 DCHECK((fmt & ~(31 << kRsShift)) == 0);
2701 Instr instr = COP1 | fmt | ft.code() << kFtShift |
2702 fs.code() << kFsShift | fd.code() << kFdShift | (0 << 5) | cond;
2703 emit(instr);
2704}
2705
2706
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002707void Assembler::cmp_s(FPUCondition cond, FPURegister fd, FPURegister fs,
2708 FPURegister ft) {
2709 cmp(cond, W, fd, fs, ft);
2710}
2711
2712void Assembler::cmp_d(FPUCondition cond, FPURegister fd, FPURegister fs,
2713 FPURegister ft) {
2714 cmp(cond, L, fd, fs, ft);
2715}
2716
2717
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002718void Assembler::bc1eqz(int16_t offset, FPURegister ft) {
2719 DCHECK(IsMipsArchVariant(kMips32r6));
2720 Instr instr = COP1 | BC1EQZ | ft.code() << kFtShift | (offset & kImm16Mask);
2721 emit(instr);
2722}
2723
2724
2725void Assembler::bc1nez(int16_t offset, FPURegister ft) {
2726 DCHECK(IsMipsArchVariant(kMips32r6));
2727 Instr instr = COP1 | BC1NEZ | ft.code() << kFtShift | (offset & kImm16Mask);
2728 emit(instr);
2729}
2730
2731
2732// Conditions for < MIPSr6.
Andrei Popescu31002712010-02-23 13:46:05 +00002733void Assembler::c(FPUCondition cond, SecondaryField fmt,
Steve Block44f0eee2011-05-26 01:26:41 +01002734 FPURegister fs, FPURegister ft, uint16_t cc) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002735 DCHECK(is_uint3(cc));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002736 DCHECK(fmt == S || fmt == D);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002737 DCHECK((fmt & ~(31 << kRsShift)) == 0);
Andrei Popescu31002712010-02-23 13:46:05 +00002738 Instr instr = COP1 | fmt | ft.code() << 16 | fs.code() << kFsShift
2739 | cc << 8 | 3 << 4 | cond;
2740 emit(instr);
2741}
2742
2743
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002744void Assembler::c_s(FPUCondition cond, FPURegister fs, FPURegister ft,
2745 uint16_t cc) {
2746 c(cond, S, fs, ft, cc);
2747}
2748
2749
2750void Assembler::c_d(FPUCondition cond, FPURegister fs, FPURegister ft,
2751 uint16_t cc) {
2752 c(cond, D, fs, ft, cc);
2753}
2754
2755
Steve Block44f0eee2011-05-26 01:26:41 +01002756void Assembler::fcmp(FPURegister src1, const double src2,
2757 FPUCondition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002758 DCHECK(src2 == 0.0);
Steve Block44f0eee2011-05-26 01:26:41 +01002759 mtc1(zero_reg, f14);
2760 cvt_d_w(f14, f14);
2761 c(cond, D, src1, f14, 0);
2762}
2763
2764
Andrei Popescu31002712010-02-23 13:46:05 +00002765void Assembler::bc1f(int16_t offset, uint16_t cc) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002766 DCHECK(is_uint3(cc));
Andrei Popescu31002712010-02-23 13:46:05 +00002767 Instr instr = COP1 | BC1 | cc << 18 | 0 << 16 | (offset & kImm16Mask);
2768 emit(instr);
2769}
2770
2771
2772void Assembler::bc1t(int16_t offset, uint16_t cc) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002773 DCHECK(is_uint3(cc));
Andrei Popescu31002712010-02-23 13:46:05 +00002774 Instr instr = COP1 | BC1 | cc << 18 | 1 << 16 | (offset & kImm16Mask);
2775 emit(instr);
2776}
2777
2778
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002779int Assembler::RelocateInternalReference(RelocInfo::Mode rmode, byte* pc,
2780 intptr_t pc_delta) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002781 Instr instr = instr_at(pc);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002782
2783 if (RelocInfo::IsInternalReference(rmode)) {
2784 int32_t* p = reinterpret_cast<int32_t*>(pc);
2785 if (*p == 0) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002786 return 0; // Number of instructions patched.
2787 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002788 *p += pc_delta;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002789 return 1; // Number of instructions patched.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002790 } else {
2791 DCHECK(RelocInfo::IsInternalReferenceEncoded(rmode));
2792 if (IsLui(instr)) {
2793 Instr instr_lui = instr_at(pc + 0 * Assembler::kInstrSize);
2794 Instr instr_ori = instr_at(pc + 1 * Assembler::kInstrSize);
2795 DCHECK(IsOri(instr_ori));
2796 int32_t imm = (instr_lui & static_cast<int32_t>(kImm16Mask)) << kLuiShift;
2797 imm |= (instr_ori & static_cast<int32_t>(kImm16Mask));
2798 if (imm == kEndOfJumpChain) {
2799 return 0; // Number of instructions patched.
2800 }
2801 imm += pc_delta;
2802 DCHECK((imm & 3) == 0);
2803
2804 instr_lui &= ~kImm16Mask;
2805 instr_ori &= ~kImm16Mask;
2806
2807 instr_at_put(pc + 0 * Assembler::kInstrSize,
2808 instr_lui | ((imm >> kLuiShift) & kImm16Mask));
2809 instr_at_put(pc + 1 * Assembler::kInstrSize,
2810 instr_ori | (imm & kImm16Mask));
2811 return 2; // Number of instructions patched.
2812 } else {
2813 UNREACHABLE();
2814 return 0;
2815 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002816 }
2817}
2818
2819
Andrei Popescu31002712010-02-23 13:46:05 +00002820void Assembler::GrowBuffer() {
2821 if (!own_buffer_) FATAL("external code buffer is too small");
2822
2823 // Compute new buffer size.
Steve Block44f0eee2011-05-26 01:26:41 +01002824 CodeDesc desc; // The new buffer.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002825 if (buffer_size_ < 1 * MB) {
Andrei Popescu31002712010-02-23 13:46:05 +00002826 desc.buffer_size = 2*buffer_size_;
2827 } else {
2828 desc.buffer_size = buffer_size_ + 1*MB;
2829 }
Steve Block44f0eee2011-05-26 01:26:41 +01002830 CHECK_GT(desc.buffer_size, 0); // No overflow.
Andrei Popescu31002712010-02-23 13:46:05 +00002831
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002832 // Set up new buffer.
Andrei Popescu31002712010-02-23 13:46:05 +00002833 desc.buffer = NewArray<byte>(desc.buffer_size);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002834 desc.origin = this;
Andrei Popescu31002712010-02-23 13:46:05 +00002835
2836 desc.instr_size = pc_offset();
2837 desc.reloc_size = (buffer_ + buffer_size_) - reloc_info_writer.pos();
2838
2839 // Copy the data.
2840 int pc_delta = desc.buffer - buffer_;
2841 int rc_delta = (desc.buffer + desc.buffer_size) - (buffer_ + buffer_size_);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002842 MemMove(desc.buffer, buffer_, desc.instr_size);
2843 MemMove(reloc_info_writer.pos() + rc_delta, reloc_info_writer.pos(),
2844 desc.reloc_size);
Andrei Popescu31002712010-02-23 13:46:05 +00002845
2846 // Switch buffers.
2847 DeleteArray(buffer_);
2848 buffer_ = desc.buffer;
2849 buffer_size_ = desc.buffer_size;
2850 pc_ += pc_delta;
2851 reloc_info_writer.Reposition(reloc_info_writer.pos() + rc_delta,
2852 reloc_info_writer.last_pc() + pc_delta);
2853
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002854 // Relocate runtime entries.
2855 for (RelocIterator it(desc); !it.done(); it.next()) {
2856 RelocInfo::Mode rmode = it.rinfo()->rmode();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002857 if (rmode == RelocInfo::INTERNAL_REFERENCE_ENCODED ||
2858 rmode == RelocInfo::INTERNAL_REFERENCE) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002859 byte* p = reinterpret_cast<byte*>(it.rinfo()->pc());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002860 RelocateInternalReference(rmode, p, pc_delta);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002861 }
2862 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002863 DCHECK(!overflow());
Andrei Popescu31002712010-02-23 13:46:05 +00002864}
2865
2866
Steve Block44f0eee2011-05-26 01:26:41 +01002867void Assembler::db(uint8_t data) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002868 CheckForEmitInForbiddenSlot();
2869 EmitHelper(data);
Steve Block44f0eee2011-05-26 01:26:41 +01002870}
2871
2872
2873void Assembler::dd(uint32_t data) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002874 CheckForEmitInForbiddenSlot();
2875 EmitHelper(data);
Steve Block44f0eee2011-05-26 01:26:41 +01002876}
2877
2878
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002879void Assembler::dq(uint64_t data) {
2880 CheckForEmitInForbiddenSlot();
2881 EmitHelper(data);
2882}
2883
2884
2885void Assembler::dd(Label* label) {
2886 uint32_t data;
2887 CheckForEmitInForbiddenSlot();
2888 if (label->is_bound()) {
2889 data = reinterpret_cast<uint32_t>(buffer_ + label->pos());
2890 } else {
2891 data = jump_address(label);
2892 internal_reference_positions_.insert(label->pos());
2893 }
2894 RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE);
2895 EmitHelper(data);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002896}
2897
2898
Andrei Popescu31002712010-02-23 13:46:05 +00002899void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002900 // We do not try to reuse pool constants.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002901 RelocInfo rinfo(isolate(), pc_, rmode, data, NULL);
2902 if (rmode >= RelocInfo::COMMENT &&
2903 rmode <= RelocInfo::DEBUG_BREAK_SLOT_AT_CALL) {
Andrei Popescu31002712010-02-23 13:46:05 +00002904 // Adjust code for new modes.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002905 DCHECK(RelocInfo::IsDebugBreakSlot(rmode)
Andrei Popescu31002712010-02-23 13:46:05 +00002906 || RelocInfo::IsComment(rmode)
2907 || RelocInfo::IsPosition(rmode));
2908 // These modes do not need an entry in the constant pool.
2909 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002910 if (!RelocInfo::IsNone(rinfo.rmode())) {
Andrei Popescu31002712010-02-23 13:46:05 +00002911 // Don't record external references unless the heap will be serialized.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002912 if (rmode == RelocInfo::EXTERNAL_REFERENCE &&
2913 !serializer_enabled() && !emit_debug_code()) {
2914 return;
Andrei Popescu31002712010-02-23 13:46:05 +00002915 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002916 DCHECK(buffer_space() >= kMaxRelocSize); // Too late to grow buffer here.
Ben Murdoch257744e2011-11-30 15:57:28 +00002917 if (rmode == RelocInfo::CODE_TARGET_WITH_ID) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002918 RelocInfo reloc_info_with_ast_id(isolate(), pc_, rmode,
2919 RecordedAstId().ToInt(), NULL);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002920 ClearRecordedAstId();
Ben Murdoch257744e2011-11-30 15:57:28 +00002921 reloc_info_writer.Write(&reloc_info_with_ast_id);
2922 } else {
2923 reloc_info_writer.Write(&rinfo);
2924 }
Andrei Popescu31002712010-02-23 13:46:05 +00002925 }
2926}
2927
2928
Steve Block44f0eee2011-05-26 01:26:41 +01002929void Assembler::BlockTrampolinePoolFor(int instructions) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002930 CheckTrampolinePoolQuick(instructions);
Steve Block44f0eee2011-05-26 01:26:41 +01002931 BlockTrampolinePoolBefore(pc_offset() + instructions * kInstrSize);
2932}
2933
2934
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002935void Assembler::CheckTrampolinePool() {
Steve Block44f0eee2011-05-26 01:26:41 +01002936 // Some small sequences of instructions must not be broken up by the
2937 // insertion of a trampoline pool; such sequences are protected by setting
2938 // either trampoline_pool_blocked_nesting_ or no_trampoline_pool_before_,
2939 // which are both checked here. Also, recursive calls to CheckTrampolinePool
2940 // are blocked by trampoline_pool_blocked_nesting_.
2941 if ((trampoline_pool_blocked_nesting_ > 0) ||
2942 (pc_offset() < no_trampoline_pool_before_)) {
2943 // Emission is currently blocked; make sure we try again as soon as
2944 // possible.
2945 if (trampoline_pool_blocked_nesting_ > 0) {
2946 next_buffer_check_ = pc_offset() + kInstrSize;
2947 } else {
2948 next_buffer_check_ = no_trampoline_pool_before_;
2949 }
2950 return;
2951 }
2952
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002953 DCHECK(!trampoline_emitted_);
2954 DCHECK(unbound_labels_count_ >= 0);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002955 if (unbound_labels_count_ > 0) {
2956 // First we emit jump (2 instructions), then we emit trampoline pool.
2957 { BlockTrampolinePoolScope block_trampoline_pool(this);
2958 Label after_pool;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002959 if (IsMipsArchVariant(kMips32r6)) {
2960 bc(&after_pool);
2961 } else {
2962 b(&after_pool);
2963 nop();
2964 }
Steve Block44f0eee2011-05-26 01:26:41 +01002965
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002966 int pool_start = pc_offset();
2967 for (int i = 0; i < unbound_labels_count_; i++) {
2968 uint32_t imm32;
2969 imm32 = jump_address(&after_pool);
2970 { BlockGrowBufferScope block_buf_growth(this);
2971 // Buffer growth (and relocation) must be blocked for internal
2972 // references until associated instructions are emitted and available
2973 // to be patched.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002974 RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE_ENCODED);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002975 lui(at, (imm32 & kHiMask) >> kLuiShift);
2976 ori(at, at, (imm32 & kImm16Mask));
2977 }
2978 jr(at);
2979 nop();
2980 }
2981 bind(&after_pool);
2982 trampoline_ = Trampoline(pool_start, unbound_labels_count_);
2983
2984 trampoline_emitted_ = true;
2985 // As we are only going to emit trampoline once, we need to prevent any
2986 // further emission.
2987 next_buffer_check_ = kMaxInt;
2988 }
2989 } else {
2990 // Number of branches to unbound label at this point is zero, so we can
2991 // move next buffer check to maximum.
2992 next_buffer_check_ = pc_offset() +
2993 kMaxBranchOffset - kTrampolineSlotsSize * 16;
Steve Block44f0eee2011-05-26 01:26:41 +01002994 }
2995 return;
2996}
2997
2998
Andrei Popescu31002712010-02-23 13:46:05 +00002999Address Assembler::target_address_at(Address pc) {
3000 Instr instr1 = instr_at(pc);
3001 Instr instr2 = instr_at(pc + kInstrSize);
Ben Murdoch257744e2011-11-30 15:57:28 +00003002 // Interpret 2 instructions generated by li: lui/ori
3003 if ((GetOpcodeField(instr1) == LUI) && (GetOpcodeField(instr2) == ORI)) {
3004 // Assemble the 32 bit value.
Andrei Popescu31002712010-02-23 13:46:05 +00003005 return reinterpret_cast<Address>(
Ben Murdoch257744e2011-11-30 15:57:28 +00003006 (GetImmediate16(instr1) << 16) | GetImmediate16(instr2));
Andrei Popescu31002712010-02-23 13:46:05 +00003007 }
3008
Ben Murdoch257744e2011-11-30 15:57:28 +00003009 // We should never get here, force a bad address if we do.
Andrei Popescu31002712010-02-23 13:46:05 +00003010 UNREACHABLE();
3011 return (Address)0x0;
3012}
3013
3014
Ben Murdochdb1b4382012-04-26 19:03:50 +01003015// MIPS and ia32 use opposite encoding for qNaN and sNaN, such that ia32
3016// qNaN is a MIPS sNaN, and ia32 sNaN is MIPS qNaN. If running from a heap
3017// snapshot generated on ia32, the resulting MIPS sNaN must be quieted.
3018// OS::nan_value() returns a qNaN.
3019void Assembler::QuietNaN(HeapObject* object) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003020 HeapNumber::cast(object)->set_value(std::numeric_limits<double>::quiet_NaN());
Ben Murdochdb1b4382012-04-26 19:03:50 +01003021}
3022
3023
Ben Murdoch589d6972011-11-30 16:04:58 +00003024// On Mips, a target address is stored in a lui/ori instruction pair, each
3025// of which load 16 bits of the 32-bit address to a register.
3026// Patching the address must replace both instr, and flush the i-cache.
3027//
3028// There is an optimization below, which emits a nop when the address
3029// fits in just 16 bits. This is unlikely to help, and should be benchmarked,
3030// and possibly removed.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003031void Assembler::set_target_address_at(Isolate* isolate, Address pc,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003032 Address target,
3033 ICacheFlushMode icache_flush_mode) {
Andrei Popescu31002712010-02-23 13:46:05 +00003034 Instr instr2 = instr_at(pc + kInstrSize);
Ben Murdoch257744e2011-11-30 15:57:28 +00003035 uint32_t rt_code = GetRtField(instr2);
Andrei Popescu31002712010-02-23 13:46:05 +00003036 uint32_t* p = reinterpret_cast<uint32_t*>(pc);
3037 uint32_t itarget = reinterpret_cast<uint32_t>(target);
3038
Ben Murdoch589d6972011-11-30 16:04:58 +00003039#ifdef DEBUG
3040 // Check we have the result from a li macro-instruction, using instr pair.
3041 Instr instr1 = instr_at(pc);
3042 CHECK((GetOpcodeField(instr1) == LUI && GetOpcodeField(instr2) == ORI));
3043#endif
3044
3045 // Must use 2 instructions to insure patchable code => just use lui and ori.
3046 // lui rt, upper-16.
3047 // ori rt rt, lower-16.
Ben Murdoch257744e2011-11-30 15:57:28 +00003048 *p = LUI | rt_code | ((itarget & kHiMask) >> kLuiShift);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003049 *(p + 1) = ORI | rt_code | (rt_code << 5) | (itarget & kImm16Mask);
Andrei Popescu31002712010-02-23 13:46:05 +00003050
Ben Murdoch589d6972011-11-30 16:04:58 +00003051
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003052 if (icache_flush_mode != SKIP_ICACHE_FLUSH) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003053 Assembler::FlushICache(isolate, pc, 2 * sizeof(int32_t));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003054 }
Andrei Popescu31002712010-02-23 13:46:05 +00003055}
3056
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003057} // namespace internal
3058} // namespace v8
Andrei Popescu31002712010-02-23 13:46:05 +00003059
Leon Clarkef7060e22010-06-03 12:02:55 +01003060#endif // V8_TARGET_ARCH_MIPS