blob: a8b6cc7c32dc9d15a9e2f0e054bdc34f9d9bc32c [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 Murdoch4a90d5f2016-03-22 12:00:34 +0000288 if (IsPrevInstrCompactBranch()) {
289 nop();
290 ClearCompactBranchState();
291 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000292 DCHECK(pc_ <= reloc_info_writer.pos()); // No overlap.
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100293 // Set up code descriptor.
Andrei Popescu31002712010-02-23 13:46:05 +0000294 desc->buffer = buffer_;
295 desc->buffer_size = buffer_size_;
296 desc->instr_size = pc_offset();
297 desc->reloc_size = (buffer_ + buffer_size_) - reloc_info_writer.pos();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000298 desc->origin = this;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000299 desc->constant_pool_size = 0;
Andrei Popescu31002712010-02-23 13:46:05 +0000300}
301
302
Steve Block44f0eee2011-05-26 01:26:41 +0100303void Assembler::Align(int m) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000304 DCHECK(m >= 4 && base::bits::IsPowerOfTwo32(m));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000305 if (IsPrevInstrCompactBranch()) {
306 nop();
307 ClearCompactBranchState();
308 }
Steve Block44f0eee2011-05-26 01:26:41 +0100309 while ((pc_offset() & (m - 1)) != 0) {
310 nop();
311 }
312}
313
314
315void Assembler::CodeTargetAlign() {
316 // No advantage to aligning branch/call targets to more than
317 // single instruction, that I am aware of.
318 Align(4);
319}
320
321
Ben Murdoch257744e2011-11-30 15:57:28 +0000322Register Assembler::GetRtReg(Instr instr) {
Steve Block44f0eee2011-05-26 01:26:41 +0100323 Register rt;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000324 rt.reg_code = (instr & kRtFieldMask) >> kRtShift;
Steve Block44f0eee2011-05-26 01:26:41 +0100325 return rt;
326}
327
328
Ben Murdoch257744e2011-11-30 15:57:28 +0000329Register Assembler::GetRsReg(Instr instr) {
330 Register rs;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000331 rs.reg_code = (instr & kRsFieldMask) >> kRsShift;
Ben Murdoch257744e2011-11-30 15:57:28 +0000332 return rs;
333}
334
335
336Register Assembler::GetRdReg(Instr instr) {
337 Register rd;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000338 rd.reg_code = (instr & kRdFieldMask) >> kRdShift;
Ben Murdoch257744e2011-11-30 15:57:28 +0000339 return rd;
340}
341
342
343uint32_t Assembler::GetRt(Instr instr) {
344 return (instr & kRtFieldMask) >> kRtShift;
345}
346
347
348uint32_t Assembler::GetRtField(Instr instr) {
349 return instr & kRtFieldMask;
350}
351
352
353uint32_t Assembler::GetRs(Instr instr) {
354 return (instr & kRsFieldMask) >> kRsShift;
355}
356
357
358uint32_t Assembler::GetRsField(Instr instr) {
359 return instr & kRsFieldMask;
360}
361
362
363uint32_t Assembler::GetRd(Instr instr) {
364 return (instr & kRdFieldMask) >> kRdShift;
365}
366
367
368uint32_t Assembler::GetRdField(Instr instr) {
369 return instr & kRdFieldMask;
370}
371
372
373uint32_t Assembler::GetSa(Instr instr) {
374 return (instr & kSaFieldMask) >> kSaShift;
375}
376
377
378uint32_t Assembler::GetSaField(Instr instr) {
379 return instr & kSaFieldMask;
380}
381
382
383uint32_t Assembler::GetOpcodeField(Instr instr) {
384 return instr & kOpcodeMask;
385}
386
387
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000388uint32_t Assembler::GetFunction(Instr instr) {
389 return (instr & kFunctionFieldMask) >> kFunctionShift;
390}
391
392
393uint32_t Assembler::GetFunctionField(Instr instr) {
394 return instr & kFunctionFieldMask;
395}
396
397
Ben Murdoch257744e2011-11-30 15:57:28 +0000398uint32_t Assembler::GetImmediate16(Instr instr) {
399 return instr & kImm16Mask;
400}
401
402
403uint32_t Assembler::GetLabelConst(Instr instr) {
404 return instr & ~kImm16Mask;
405}
406
407
Steve Block44f0eee2011-05-26 01:26:41 +0100408bool Assembler::IsPop(Instr instr) {
409 return (instr & ~kRtMask) == kPopRegPattern;
410}
411
412
413bool Assembler::IsPush(Instr instr) {
414 return (instr & ~kRtMask) == kPushRegPattern;
415}
416
417
418bool Assembler::IsSwRegFpOffset(Instr instr) {
419 return ((instr & kLwSwInstrTypeMask) == kSwRegFpOffsetPattern);
420}
421
422
423bool Assembler::IsLwRegFpOffset(Instr instr) {
424 return ((instr & kLwSwInstrTypeMask) == kLwRegFpOffsetPattern);
425}
426
427
428bool Assembler::IsSwRegFpNegOffset(Instr instr) {
429 return ((instr & (kLwSwInstrTypeMask | kNegOffset)) ==
430 kSwRegFpNegOffsetPattern);
431}
432
433
434bool Assembler::IsLwRegFpNegOffset(Instr instr) {
435 return ((instr & (kLwSwInstrTypeMask | kNegOffset)) ==
436 kLwRegFpNegOffsetPattern);
437}
438
439
Andrei Popescu31002712010-02-23 13:46:05 +0000440// Labels refer to positions in the (to be) generated code.
441// There are bound, linked, and unused labels.
442//
443// Bound labels refer to known positions in the already
444// generated code. pos() is the position the label refers to.
445//
446// Linked labels refer to unknown positions in the code
447// to be generated; pos() is the position of the last
448// instruction using the label.
449
Steve Block44f0eee2011-05-26 01:26:41 +0100450// The link chain is terminated by a value in the instruction of -1,
451// which is an otherwise illegal value (branch -1 is inf loop).
452// The instruction 16-bit offset field addresses 32-bit words, but in
453// code is conv to an 18-bit value addressing bytes, hence the -4 value.
Andrei Popescu31002712010-02-23 13:46:05 +0000454
Andrei Popescu31002712010-02-23 13:46:05 +0000455const int kEndOfChain = -4;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000456// Determines the end of the Jump chain (a subset of the label link chain).
457const int kEndOfJumpChain = 0;
Andrei Popescu31002712010-02-23 13:46:05 +0000458
Steve Block44f0eee2011-05-26 01:26:41 +0100459
460bool Assembler::IsBranch(Instr instr) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000461 uint32_t opcode = GetOpcodeField(instr);
462 uint32_t rt_field = GetRtField(instr);
463 uint32_t rs_field = GetRsField(instr);
Andrei Popescu31002712010-02-23 13:46:05 +0000464 // Checks if the instruction is a branch.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000465 bool isBranch =
466 opcode == BEQ || opcode == BNE || opcode == BLEZ || opcode == BGTZ ||
467 opcode == BEQL || opcode == BNEL || opcode == BLEZL || opcode == BGTZL ||
Andrei Popescu31002712010-02-23 13:46:05 +0000468 (opcode == REGIMM && (rt_field == BLTZ || rt_field == BGEZ ||
469 rt_field == BLTZAL || rt_field == BGEZAL)) ||
Steve Block44f0eee2011-05-26 01:26:41 +0100470 (opcode == COP1 && rs_field == BC1) || // Coprocessor branch.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000471 (opcode == COP1 && rs_field == BC1EQZ) ||
472 (opcode == COP1 && rs_field == BC1NEZ);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000473 if (!isBranch && IsMipsArchVariant(kMips32r6)) {
474 // All the 3 variants of POP10 (BOVC, BEQC, BEQZALC) and
475 // POP30 (BNVC, BNEC, BNEZALC) are branch ops.
476 isBranch |= opcode == POP10 || opcode == POP30 || opcode == BC ||
477 opcode == BALC ||
478 (opcode == POP66 && rs_field != 0) || // BEQZC
479 (opcode == POP76 && rs_field != 0); // BNEZC
480 }
481 return isBranch;
482}
483
484
485bool Assembler::IsBc(Instr instr) {
486 uint32_t opcode = GetOpcodeField(instr);
487 // Checks if the instruction is a BC or BALC.
488 return opcode == BC || opcode == BALC;
489}
490
491
492bool Assembler::IsBzc(Instr instr) {
493 uint32_t opcode = GetOpcodeField(instr);
494 // Checks if the instruction is BEQZC or BNEZC.
495 return (opcode == POP66 && GetRsField(instr) != 0) ||
496 (opcode == POP76 && GetRsField(instr) != 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000497}
498
499
500bool Assembler::IsEmittedConstant(Instr instr) {
501 uint32_t label_constant = GetLabelConst(instr);
502 return label_constant == 0; // Emitted label const in reg-exp engine.
Steve Block44f0eee2011-05-26 01:26:41 +0100503}
504
505
Ben Murdoch257744e2011-11-30 15:57:28 +0000506bool Assembler::IsBeq(Instr instr) {
507 return GetOpcodeField(instr) == BEQ;
508}
509
510
511bool Assembler::IsBne(Instr instr) {
512 return GetOpcodeField(instr) == BNE;
513}
514
515
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000516bool Assembler::IsBeqzc(Instr instr) {
517 uint32_t opcode = GetOpcodeField(instr);
518 return opcode == POP66 && GetRsField(instr) != 0;
519}
520
521
522bool Assembler::IsBnezc(Instr instr) {
523 uint32_t opcode = GetOpcodeField(instr);
524 return opcode == POP76 && GetRsField(instr) != 0;
525}
526
527
528bool Assembler::IsBeqc(Instr instr) {
529 uint32_t opcode = GetOpcodeField(instr);
530 uint32_t rs = GetRsField(instr);
531 uint32_t rt = GetRtField(instr);
532 return opcode == POP10 && rs != 0 && rs < rt; // && rt != 0
533}
534
535
536bool Assembler::IsBnec(Instr instr) {
537 uint32_t opcode = GetOpcodeField(instr);
538 uint32_t rs = GetRsField(instr);
539 uint32_t rt = GetRtField(instr);
540 return opcode == POP30 && rs != 0 && rs < rt; // && rt != 0
541}
542
543
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000544bool Assembler::IsJump(Instr instr) {
545 uint32_t opcode = GetOpcodeField(instr);
546 uint32_t rt_field = GetRtField(instr);
547 uint32_t rd_field = GetRdField(instr);
548 uint32_t function_field = GetFunctionField(instr);
549 // Checks if the instruction is a jump.
550 return opcode == J || opcode == JAL ||
551 (opcode == SPECIAL && rt_field == 0 &&
552 ((function_field == JALR) || (rd_field == 0 && (function_field == JR))));
553}
554
555
556bool Assembler::IsJ(Instr instr) {
557 uint32_t opcode = GetOpcodeField(instr);
558 // Checks if the instruction is a jump.
559 return opcode == J;
560}
561
562
Ben Murdoch589d6972011-11-30 16:04:58 +0000563bool Assembler::IsJal(Instr instr) {
564 return GetOpcodeField(instr) == JAL;
565}
566
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000567
Ben Murdoch589d6972011-11-30 16:04:58 +0000568bool Assembler::IsJr(Instr instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000569 if (!IsMipsArchVariant(kMips32r6)) {
570 return GetOpcodeField(instr) == SPECIAL && GetFunctionField(instr) == JR;
571 } else {
572 return GetOpcodeField(instr) == SPECIAL &&
573 GetRdField(instr) == 0 && GetFunctionField(instr) == JALR;
574 }
Ben Murdoch589d6972011-11-30 16:04:58 +0000575}
576
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000577
Ben Murdoch589d6972011-11-30 16:04:58 +0000578bool Assembler::IsJalr(Instr instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000579 return GetOpcodeField(instr) == SPECIAL &&
580 GetRdField(instr) != 0 && GetFunctionField(instr) == JALR;
Ben Murdoch589d6972011-11-30 16:04:58 +0000581}
582
583
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000584bool Assembler::IsLui(Instr instr) {
585 uint32_t opcode = GetOpcodeField(instr);
586 // Checks if the instruction is a load upper immediate.
587 return opcode == LUI;
588}
589
590
591bool Assembler::IsOri(Instr instr) {
592 uint32_t opcode = GetOpcodeField(instr);
593 // Checks if the instruction is a load upper immediate.
594 return opcode == ORI;
595}
596
597
Steve Block44f0eee2011-05-26 01:26:41 +0100598bool Assembler::IsNop(Instr instr, unsigned int type) {
599 // See Assembler::nop(type).
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000600 DCHECK(type < 32);
Ben Murdoch257744e2011-11-30 15:57:28 +0000601 uint32_t opcode = GetOpcodeField(instr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000602 uint32_t function = GetFunctionField(instr);
Ben Murdoch257744e2011-11-30 15:57:28 +0000603 uint32_t rt = GetRt(instr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000604 uint32_t rd = GetRd(instr);
Ben Murdoch257744e2011-11-30 15:57:28 +0000605 uint32_t sa = GetSa(instr);
Steve Block44f0eee2011-05-26 01:26:41 +0100606
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000607 // Traditional mips nop == sll(zero_reg, zero_reg, 0)
608 // When marking non-zero type, use sll(zero_reg, at, type)
609 // to avoid use of mips ssnop and ehb special encodings
610 // of the sll instruction.
Steve Block44f0eee2011-05-26 01:26:41 +0100611
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000612 Register nop_rt_reg = (type == 0) ? zero_reg : at;
613 bool ret = (opcode == SPECIAL && function == SLL &&
614 rd == static_cast<uint32_t>(ToNumber(zero_reg)) &&
615 rt == static_cast<uint32_t>(ToNumber(nop_rt_reg)) &&
Steve Block44f0eee2011-05-26 01:26:41 +0100616 sa == type);
617
618 return ret;
619}
620
621
622int32_t Assembler::GetBranchOffset(Instr instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000623 DCHECK(IsBranch(instr));
624 return (static_cast<int16_t>(instr & kImm16Mask)) << 2;
Steve Block44f0eee2011-05-26 01:26:41 +0100625}
626
627
628bool Assembler::IsLw(Instr instr) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000629 return (static_cast<uint32_t>(instr & kOpcodeMask) == LW);
Steve Block44f0eee2011-05-26 01:26:41 +0100630}
631
632
633int16_t Assembler::GetLwOffset(Instr instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000634 DCHECK(IsLw(instr));
Steve Block44f0eee2011-05-26 01:26:41 +0100635 return ((instr & kImm16Mask));
636}
637
638
639Instr Assembler::SetLwOffset(Instr instr, int16_t offset) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000640 DCHECK(IsLw(instr));
Steve Block44f0eee2011-05-26 01:26:41 +0100641
642 // We actually create a new lw instruction based on the original one.
643 Instr temp_instr = LW | (instr & kRsFieldMask) | (instr & kRtFieldMask)
644 | (offset & kImm16Mask);
645
646 return temp_instr;
647}
648
649
650bool Assembler::IsSw(Instr instr) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000651 return (static_cast<uint32_t>(instr & kOpcodeMask) == SW);
Steve Block44f0eee2011-05-26 01:26:41 +0100652}
653
654
655Instr Assembler::SetSwOffset(Instr instr, int16_t offset) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000656 DCHECK(IsSw(instr));
Steve Block44f0eee2011-05-26 01:26:41 +0100657 return ((instr & ~kImm16Mask) | (offset & kImm16Mask));
658}
659
660
661bool Assembler::IsAddImmediate(Instr instr) {
662 return ((instr & kOpcodeMask) == ADDIU);
663}
664
665
666Instr Assembler::SetAddImmediateOffset(Instr instr, int16_t offset) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000667 DCHECK(IsAddImmediate(instr));
Steve Block44f0eee2011-05-26 01:26:41 +0100668 return ((instr & ~kImm16Mask) | (offset & kImm16Mask));
Andrei Popescu31002712010-02-23 13:46:05 +0000669}
670
671
Ben Murdoch257744e2011-11-30 15:57:28 +0000672bool Assembler::IsAndImmediate(Instr instr) {
673 return GetOpcodeField(instr) == ANDI;
674}
675
676
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000677static Assembler::OffsetSize OffsetSizeInBits(Instr instr) {
678 if (IsMipsArchVariant(kMips32r6)) {
679 if (Assembler::IsBc(instr)) {
680 return Assembler::OffsetSize::kOffset26;
681 } else if (Assembler::IsBzc(instr)) {
682 return Assembler::OffsetSize::kOffset21;
683 }
684 }
685 return Assembler::OffsetSize::kOffset16;
686}
687
688
689static inline int32_t AddBranchOffset(int pos, Instr instr) {
690 int bits = OffsetSizeInBits(instr);
691 const int32_t mask = (1 << bits) - 1;
692 bits = 32 - bits;
693
694 // Do NOT change this to <<2. We rely on arithmetic shifts here, assuming
695 // the compiler uses arithmetic shifts for signed integers.
696 int32_t imm = ((instr & mask) << bits) >> (bits - 2);
697
698 if (imm == kEndOfChain) {
699 // EndOfChain sentinel is returned directly, not relative to pc or pos.
700 return kEndOfChain;
701 } else {
702 return pos + Assembler::kBranchPCOffset + imm;
703 }
704}
705
706
707int Assembler::target_at(int pos, bool is_internal) {
Andrei Popescu31002712010-02-23 13:46:05 +0000708 Instr instr = instr_at(pos);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000709 if (is_internal) {
710 if (instr == 0) {
711 return kEndOfChain;
712 } else {
713 int32_t instr_address = reinterpret_cast<int32_t>(buffer_ + pos);
714 int delta = static_cast<int>(instr_address - instr);
715 DCHECK(pos > delta);
716 return pos - delta;
717 }
718 }
Andrei Popescu31002712010-02-23 13:46:05 +0000719 if ((instr & ~kImm16Mask) == 0) {
720 // Emitted label constant, not part of a branch.
Steve Block44f0eee2011-05-26 01:26:41 +0100721 if (instr == 0) {
722 return kEndOfChain;
723 } else {
724 int32_t imm18 =((instr & static_cast<int32_t>(kImm16Mask)) << 16) >> 14;
725 return (imm18 + pos);
726 }
Andrei Popescu31002712010-02-23 13:46:05 +0000727 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000728 // Check we have a branch or jump instruction.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000729 DCHECK(IsBranch(instr) || IsLui(instr));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000730 if (IsBranch(instr)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000731 return AddBranchOffset(pos, instr);
732 } else {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000733 Instr instr_lui = instr_at(pos + 0 * Assembler::kInstrSize);
734 Instr instr_ori = instr_at(pos + 1 * Assembler::kInstrSize);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000735 DCHECK(IsOri(instr_ori));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000736 int32_t imm = (instr_lui & static_cast<int32_t>(kImm16Mask)) << kLuiShift;
737 imm |= (instr_ori & static_cast<int32_t>(kImm16Mask));
738
739 if (imm == kEndOfJumpChain) {
740 // EndOfChain sentinel is returned directly, not relative to pc or pos.
741 return kEndOfChain;
742 } else {
743 uint32_t instr_address = reinterpret_cast<int32_t>(buffer_ + pos);
744 int32_t delta = instr_address - imm;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000745 DCHECK(pos > delta);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000746 return pos - delta;
747 }
Steve Block44f0eee2011-05-26 01:26:41 +0100748 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000749 return 0;
Andrei Popescu31002712010-02-23 13:46:05 +0000750}
751
752
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000753static inline Instr SetBranchOffset(int32_t pos, int32_t target_pos,
754 Instr instr) {
755 int32_t bits = OffsetSizeInBits(instr);
756 int32_t imm = target_pos - (pos + Assembler::kBranchPCOffset);
757 DCHECK((imm & 3) == 0);
758 imm >>= 2;
759
760 const int32_t mask = (1 << bits) - 1;
761 instr &= ~mask;
762 DCHECK(is_intn(imm, bits));
763
764 return instr | (imm & mask);
765}
766
767
768void Assembler::target_at_put(int32_t pos, int32_t target_pos,
769 bool is_internal) {
Andrei Popescu31002712010-02-23 13:46:05 +0000770 Instr instr = instr_at(pos);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000771
772 if (is_internal) {
773 uint32_t imm = reinterpret_cast<uint32_t>(buffer_) + target_pos;
774 instr_at_put(pos, imm);
775 return;
776 }
Andrei Popescu31002712010-02-23 13:46:05 +0000777 if ((instr & ~kImm16Mask) == 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000778 DCHECK(target_pos == kEndOfChain || target_pos >= 0);
Andrei Popescu31002712010-02-23 13:46:05 +0000779 // Emitted label constant, not part of a branch.
780 // Make label relative to Code* of generated Code object.
781 instr_at_put(pos, target_pos + (Code::kHeaderSize - kHeapObjectTag));
782 return;
783 }
784
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000785 DCHECK(IsBranch(instr) || IsLui(instr));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000786 if (IsBranch(instr)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000787 instr = SetBranchOffset(pos, target_pos, instr);
788 instr_at_put(pos, instr);
789 } else {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000790 Instr instr_lui = instr_at(pos + 0 * Assembler::kInstrSize);
791 Instr instr_ori = instr_at(pos + 1 * Assembler::kInstrSize);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000792 DCHECK(IsOri(instr_ori));
793 uint32_t imm = reinterpret_cast<uint32_t>(buffer_) + target_pos;
794 DCHECK((imm & 3) == 0);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000795
796 instr_lui &= ~kImm16Mask;
797 instr_ori &= ~kImm16Mask;
798
799 instr_at_put(pos + 0 * Assembler::kInstrSize,
800 instr_lui | ((imm & kHiMask) >> kLuiShift));
801 instr_at_put(pos + 1 * Assembler::kInstrSize,
802 instr_ori | (imm & kImm16Mask));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000803 }
Andrei Popescu31002712010-02-23 13:46:05 +0000804}
805
806
807void Assembler::print(Label* L) {
808 if (L->is_unused()) {
809 PrintF("unused label\n");
810 } else if (L->is_bound()) {
811 PrintF("bound label to %d\n", L->pos());
812 } else if (L->is_linked()) {
813 Label l = *L;
814 PrintF("unbound label");
815 while (l.is_linked()) {
816 PrintF("@ %d ", l.pos());
817 Instr instr = instr_at(l.pos());
818 if ((instr & ~kImm16Mask) == 0) {
819 PrintF("value\n");
820 } else {
821 PrintF("%d\n", instr);
822 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000823 next(&l, internal_reference_positions_.find(l.pos()) !=
824 internal_reference_positions_.end());
Andrei Popescu31002712010-02-23 13:46:05 +0000825 }
826 } else {
827 PrintF("label in inconsistent state (pos = %d)\n", L->pos_);
828 }
829}
830
831
832void Assembler::bind_to(Label* L, int pos) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000833 DCHECK(0 <= pos && pos <= pc_offset()); // Must have valid binding position.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000834 int32_t trampoline_pos = kInvalidSlotPos;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000835 bool is_internal = false;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000836 if (L->is_linked() && !trampoline_emitted_) {
837 unbound_labels_count_--;
838 next_buffer_check_ += kTrampolineSlotsSize;
839 }
840
Andrei Popescu31002712010-02-23 13:46:05 +0000841 while (L->is_linked()) {
842 int32_t fixup_pos = L->pos();
Steve Block44f0eee2011-05-26 01:26:41 +0100843 int32_t dist = pos - fixup_pos;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000844 is_internal = internal_reference_positions_.find(fixup_pos) !=
845 internal_reference_positions_.end();
846 next(L, is_internal); // Call next before overwriting link with target at
847 // fixup_pos.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000848 Instr instr = instr_at(fixup_pos);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000849 if (is_internal) {
850 target_at_put(fixup_pos, pos, is_internal);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000851 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000852 if (IsBranch(instr)) {
853 int branch_offset = BranchOffset(instr);
854 if (dist > branch_offset) {
855 if (trampoline_pos == kInvalidSlotPos) {
856 trampoline_pos = get_trampoline_entry(fixup_pos);
857 CHECK(trampoline_pos != kInvalidSlotPos);
858 }
859 CHECK((trampoline_pos - fixup_pos) <= branch_offset);
860 target_at_put(fixup_pos, trampoline_pos, false);
861 fixup_pos = trampoline_pos;
862 dist = pos - fixup_pos;
863 }
864 target_at_put(fixup_pos, pos, false);
865 } else {
866 target_at_put(fixup_pos, pos, false);
867 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000868 }
Andrei Popescu31002712010-02-23 13:46:05 +0000869 }
870 L->bind_to(pos);
871
872 // Keep track of the last bound label so we don't eliminate any instructions
873 // before a bound label.
874 if (pos > last_bound_pos_)
875 last_bound_pos_ = pos;
876}
877
878
Andrei Popescu31002712010-02-23 13:46:05 +0000879void Assembler::bind(Label* L) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000880 DCHECK(!L->is_bound()); // Label can only be bound once.
Andrei Popescu31002712010-02-23 13:46:05 +0000881 bind_to(L, pc_offset());
882}
883
884
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000885void Assembler::next(Label* L, bool is_internal) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000886 DCHECK(L->is_linked());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000887 int link = target_at(L->pos(), is_internal);
Steve Block44f0eee2011-05-26 01:26:41 +0100888 if (link == kEndOfChain) {
Andrei Popescu31002712010-02-23 13:46:05 +0000889 L->Unuse();
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000890 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000891 DCHECK(link >= 0);
Steve Block44f0eee2011-05-26 01:26:41 +0100892 L->link_to(link);
Andrei Popescu31002712010-02-23 13:46:05 +0000893 }
894}
895
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000896
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000897bool Assembler::is_near(Label* L) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000898 DCHECK(L->is_bound());
899 return pc_offset() - L->pos() < kMaxBranchOffset - 4 * kInstrSize;
900}
901
902
903bool Assembler::is_near(Label* L, OffsetSize bits) {
904 if (L == nullptr || !L->is_bound()) return true;
905 return pc_offset() - L->pos() < (1 << (bits + 2 - 1)) - 1 - 5 * kInstrSize;
906}
907
908
909bool Assembler::is_near_branch(Label* L) {
910 DCHECK(L->is_bound());
911 return IsMipsArchVariant(kMips32r6) ? is_near_r6(L) : is_near_pre_r6(L);
912}
913
914
915int Assembler::BranchOffset(Instr instr) {
916 // At pre-R6 and for other R6 branches the offset is 16 bits.
917 int bits = OffsetSize::kOffset16;
918
919 if (IsMipsArchVariant(kMips32r6)) {
920 uint32_t opcode = GetOpcodeField(instr);
921 switch (opcode) {
922 // Checks BC or BALC.
923 case BC:
924 case BALC:
925 bits = OffsetSize::kOffset26;
926 break;
927
928 // Checks BEQZC or BNEZC.
929 case POP66:
930 case POP76:
931 if (GetRsField(instr) != 0) bits = OffsetSize::kOffset21;
932 break;
933 default:
934 break;
935 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000936 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000937
938 return (1 << (bits + 2 - 1)) - 1;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000939}
Andrei Popescu31002712010-02-23 13:46:05 +0000940
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000941
Andrei Popescu31002712010-02-23 13:46:05 +0000942// We have to use a temporary register for things that can be relocated even
943// if they can be encoded in the MIPS's 16 bits of immediate-offset instruction
944// space. There is no guarantee that the relocated location can be similarly
945// encoded.
Steve Block44f0eee2011-05-26 01:26:41 +0100946bool Assembler::MustUseReg(RelocInfo::Mode rmode) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000947 return !RelocInfo::IsNone(rmode);
Andrei Popescu31002712010-02-23 13:46:05 +0000948}
949
Andrei Popescu31002712010-02-23 13:46:05 +0000950void Assembler::GenInstrRegister(Opcode opcode,
951 Register rs,
952 Register rt,
953 Register rd,
954 uint16_t sa,
955 SecondaryField func) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000956 DCHECK(rd.is_valid() && rs.is_valid() && rt.is_valid() && is_uint5(sa));
Andrei Popescu31002712010-02-23 13:46:05 +0000957 Instr instr = opcode | (rs.code() << kRsShift) | (rt.code() << kRtShift)
958 | (rd.code() << kRdShift) | (sa << kSaShift) | func;
959 emit(instr);
960}
961
962
963void Assembler::GenInstrRegister(Opcode opcode,
Steve Block44f0eee2011-05-26 01:26:41 +0100964 Register rs,
965 Register rt,
966 uint16_t msb,
967 uint16_t lsb,
968 SecondaryField func) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000969 DCHECK(rs.is_valid() && rt.is_valid() && is_uint5(msb) && is_uint5(lsb));
Steve Block44f0eee2011-05-26 01:26:41 +0100970 Instr instr = opcode | (rs.code() << kRsShift) | (rt.code() << kRtShift)
971 | (msb << kRdShift) | (lsb << kSaShift) | func;
972 emit(instr);
973}
974
975
976void Assembler::GenInstrRegister(Opcode opcode,
Andrei Popescu31002712010-02-23 13:46:05 +0000977 SecondaryField fmt,
978 FPURegister ft,
979 FPURegister fs,
980 FPURegister fd,
981 SecondaryField func) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000982 DCHECK(fd.is_valid() && fs.is_valid() && ft.is_valid());
Steve Block44f0eee2011-05-26 01:26:41 +0100983 Instr instr = opcode | fmt | (ft.code() << kFtShift) | (fs.code() << kFsShift)
984 | (fd.code() << kFdShift) | func;
Andrei Popescu31002712010-02-23 13:46:05 +0000985 emit(instr);
986}
987
988
989void Assembler::GenInstrRegister(Opcode opcode,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000990 FPURegister fr,
991 FPURegister ft,
992 FPURegister fs,
993 FPURegister fd,
994 SecondaryField func) {
995 DCHECK(fd.is_valid() && fr.is_valid() && fs.is_valid() && ft.is_valid());
996 Instr instr = opcode | (fr.code() << kFrShift) | (ft.code() << kFtShift)
997 | (fs.code() << kFsShift) | (fd.code() << kFdShift) | func;
998 emit(instr);
999}
1000
1001
1002void Assembler::GenInstrRegister(Opcode opcode,
Andrei Popescu31002712010-02-23 13:46:05 +00001003 SecondaryField fmt,
1004 Register rt,
1005 FPURegister fs,
1006 FPURegister fd,
1007 SecondaryField func) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001008 DCHECK(fd.is_valid() && fs.is_valid() && rt.is_valid());
Andrei Popescu31002712010-02-23 13:46:05 +00001009 Instr instr = opcode | fmt | (rt.code() << kRtShift)
Steve Block44f0eee2011-05-26 01:26:41 +01001010 | (fs.code() << kFsShift) | (fd.code() << kFdShift) | func;
1011 emit(instr);
1012}
1013
1014
1015void Assembler::GenInstrRegister(Opcode opcode,
1016 SecondaryField fmt,
1017 Register rt,
1018 FPUControlRegister fs,
1019 SecondaryField func) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001020 DCHECK(fs.is_valid() && rt.is_valid());
Steve Block44f0eee2011-05-26 01:26:41 +01001021 Instr instr =
1022 opcode | fmt | (rt.code() << kRtShift) | (fs.code() << kFsShift) | func;
Andrei Popescu31002712010-02-23 13:46:05 +00001023 emit(instr);
1024}
1025
1026
1027// Instructions with immediate value.
1028// Registers are in the order of the instruction encoding, from left to right.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001029void Assembler::GenInstrImmediate(Opcode opcode, Register rs, Register rt,
1030 int32_t j,
1031 CompactBranchType is_compact_branch) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001032 DCHECK(rs.is_valid() && rt.is_valid() && (is_int16(j) || is_uint16(j)));
Andrei Popescu31002712010-02-23 13:46:05 +00001033 Instr instr = opcode | (rs.code() << kRsShift) | (rt.code() << kRtShift)
1034 | (j & kImm16Mask);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001035 emit(instr, is_compact_branch);
Andrei Popescu31002712010-02-23 13:46:05 +00001036}
1037
1038
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001039void Assembler::GenInstrImmediate(Opcode opcode, Register rs, SecondaryField SF,
1040 int32_t j,
1041 CompactBranchType is_compact_branch) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001042 DCHECK(rs.is_valid() && (is_int16(j) || is_uint16(j)));
Andrei Popescu31002712010-02-23 13:46:05 +00001043 Instr instr = opcode | (rs.code() << kRsShift) | SF | (j & kImm16Mask);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001044 emit(instr, is_compact_branch);
Andrei Popescu31002712010-02-23 13:46:05 +00001045}
1046
1047
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001048void Assembler::GenInstrImmediate(Opcode opcode, Register rs, FPURegister ft,
1049 int32_t j,
1050 CompactBranchType is_compact_branch) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001051 DCHECK(rs.is_valid() && ft.is_valid() && (is_int16(j) || is_uint16(j)));
Andrei Popescu31002712010-02-23 13:46:05 +00001052 Instr instr = opcode | (rs.code() << kRsShift) | (ft.code() << kFtShift)
1053 | (j & kImm16Mask);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001054 emit(instr, is_compact_branch);
1055}
1056
1057
1058void Assembler::GenInstrImmediate(Opcode opcode, Register rs, int32_t offset21,
1059 CompactBranchType is_compact_branch) {
1060 DCHECK(rs.is_valid() && (is_int21(offset21)));
1061 Instr instr = opcode | (rs.code() << kRsShift) | (offset21 & kImm21Mask);
1062 emit(instr, is_compact_branch);
1063}
1064
1065
1066void Assembler::GenInstrImmediate(Opcode opcode, Register rs,
1067 uint32_t offset21) {
1068 DCHECK(rs.is_valid() && (is_uint21(offset21)));
1069 Instr instr = opcode | (rs.code() << kRsShift) | (offset21 & kImm21Mask);
Andrei Popescu31002712010-02-23 13:46:05 +00001070 emit(instr);
1071}
1072
1073
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001074void Assembler::GenInstrImmediate(Opcode opcode, int32_t offset26,
1075 CompactBranchType is_compact_branch) {
1076 DCHECK(is_int26(offset26));
1077 Instr instr = opcode | (offset26 & kImm26Mask);
1078 emit(instr, is_compact_branch);
1079}
1080
1081
Andrei Popescu31002712010-02-23 13:46:05 +00001082void Assembler::GenInstrJump(Opcode opcode,
Ben Murdoch589d6972011-11-30 16:04:58 +00001083 uint32_t address) {
Steve Block44f0eee2011-05-26 01:26:41 +01001084 BlockTrampolinePoolScope block_trampoline_pool(this);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001085 DCHECK(is_uint26(address));
Andrei Popescu31002712010-02-23 13:46:05 +00001086 Instr instr = opcode | address;
1087 emit(instr);
Steve Block44f0eee2011-05-26 01:26:41 +01001088 BlockTrampolinePoolFor(1); // For associated delay slot.
1089}
1090
1091
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001092// Returns the next free trampoline entry.
1093int32_t Assembler::get_trampoline_entry(int32_t pos) {
Ben Murdoch257744e2011-11-30 15:57:28 +00001094 int32_t trampoline_entry = kInvalidSlotPos;
Steve Block44f0eee2011-05-26 01:26:41 +01001095
Ben Murdoch257744e2011-11-30 15:57:28 +00001096 if (!internal_trampoline_exception_) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001097 if (trampoline_.start() > pos) {
1098 trampoline_entry = trampoline_.take_slot();
Steve Block44f0eee2011-05-26 01:26:41 +01001099 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001100
Ben Murdoch257744e2011-11-30 15:57:28 +00001101 if (kInvalidSlotPos == trampoline_entry) {
1102 internal_trampoline_exception_ = true;
Steve Block44f0eee2011-05-26 01:26:41 +01001103 }
1104 }
1105 return trampoline_entry;
Andrei Popescu31002712010-02-23 13:46:05 +00001106}
1107
1108
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001109uint32_t Assembler::jump_address(Label* L) {
Andrei Popescu31002712010-02-23 13:46:05 +00001110 int32_t target_pos;
Steve Block44f0eee2011-05-26 01:26:41 +01001111
Andrei Popescu31002712010-02-23 13:46:05 +00001112 if (L->is_bound()) {
1113 target_pos = L->pos();
1114 } else {
1115 if (L->is_linked()) {
Steve Block44f0eee2011-05-26 01:26:41 +01001116 target_pos = L->pos(); // L's link.
Steve Block44f0eee2011-05-26 01:26:41 +01001117 L->link_to(pc_offset());
Andrei Popescu31002712010-02-23 13:46:05 +00001118 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01001119 L->link_to(pc_offset());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001120 return kEndOfJumpChain;
1121 }
1122 }
1123
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001124 uint32_t imm = reinterpret_cast<uint32_t>(buffer_) + target_pos;
1125 DCHECK((imm & 3) == 0);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001126
1127 return imm;
1128}
1129
1130
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001131int32_t Assembler::branch_offset_helper(Label* L, OffsetSize bits) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001132 int32_t target_pos;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001133 int32_t pad = IsPrevInstrCompactBranch() ? kInstrSize : 0;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001134
1135 if (L->is_bound()) {
1136 target_pos = L->pos();
1137 } else {
1138 if (L->is_linked()) {
1139 target_pos = L->pos();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001140 L->link_to(pc_offset() + pad);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001141 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001142 L->link_to(pc_offset() + pad);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001143 if (!trampoline_emitted_) {
1144 unbound_labels_count_++;
1145 next_buffer_check_ -= kTrampolineSlotsSize;
1146 }
Steve Block44f0eee2011-05-26 01:26:41 +01001147 return kEndOfChain;
Andrei Popescu31002712010-02-23 13:46:05 +00001148 }
Andrei Popescu31002712010-02-23 13:46:05 +00001149 }
1150
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001151 int32_t offset = target_pos - (pc_offset() + kBranchPCOffset + pad);
1152 DCHECK(is_intn(offset, bits + 2));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001153 DCHECK((offset & 3) == 0);
Steve Block44f0eee2011-05-26 01:26:41 +01001154
Andrei Popescu31002712010-02-23 13:46:05 +00001155 return offset;
1156}
1157
1158
1159void Assembler::label_at_put(Label* L, int at_offset) {
1160 int target_pos;
1161 if (L->is_bound()) {
1162 target_pos = L->pos();
Steve Block44f0eee2011-05-26 01:26:41 +01001163 instr_at_put(at_offset, target_pos + (Code::kHeaderSize - kHeapObjectTag));
Andrei Popescu31002712010-02-23 13:46:05 +00001164 } else {
1165 if (L->is_linked()) {
Steve Block44f0eee2011-05-26 01:26:41 +01001166 target_pos = L->pos(); // L's link.
1167 int32_t imm18 = target_pos - at_offset;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001168 DCHECK((imm18 & 3) == 0);
Steve Block44f0eee2011-05-26 01:26:41 +01001169 int32_t imm16 = imm18 >> 2;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001170 DCHECK(is_int16(imm16));
Steve Block44f0eee2011-05-26 01:26:41 +01001171 instr_at_put(at_offset, (imm16 & kImm16Mask));
Andrei Popescu31002712010-02-23 13:46:05 +00001172 } else {
1173 target_pos = kEndOfChain;
Steve Block44f0eee2011-05-26 01:26:41 +01001174 instr_at_put(at_offset, 0);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001175 if (!trampoline_emitted_) {
1176 unbound_labels_count_++;
1177 next_buffer_check_ -= kTrampolineSlotsSize;
1178 }
Andrei Popescu31002712010-02-23 13:46:05 +00001179 }
1180 L->link_to(at_offset);
Andrei Popescu31002712010-02-23 13:46:05 +00001181 }
1182}
1183
1184
1185//------- Branch and jump instructions --------
1186
1187void Assembler::b(int16_t offset) {
1188 beq(zero_reg, zero_reg, offset);
1189}
1190
1191
1192void Assembler::bal(int16_t offset) {
Steve Block44f0eee2011-05-26 01:26:41 +01001193 positions_recorder()->WriteRecordedPositions();
Andrei Popescu31002712010-02-23 13:46:05 +00001194 bgezal(zero_reg, offset);
1195}
1196
1197
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001198void Assembler::bc(int32_t offset) {
1199 DCHECK(IsMipsArchVariant(kMips32r6));
1200 GenInstrImmediate(BC, offset, CompactBranchType::COMPACT_BRANCH);
1201}
1202
1203
1204void Assembler::balc(int32_t offset) {
1205 DCHECK(IsMipsArchVariant(kMips32r6));
1206 positions_recorder()->WriteRecordedPositions();
1207 GenInstrImmediate(BALC, offset, CompactBranchType::COMPACT_BRANCH);
1208}
1209
1210
Andrei Popescu31002712010-02-23 13:46:05 +00001211void Assembler::beq(Register rs, Register rt, int16_t offset) {
Steve Block44f0eee2011-05-26 01:26:41 +01001212 BlockTrampolinePoolScope block_trampoline_pool(this);
Andrei Popescu31002712010-02-23 13:46:05 +00001213 GenInstrImmediate(BEQ, rs, rt, offset);
Steve Block44f0eee2011-05-26 01:26:41 +01001214 BlockTrampolinePoolFor(1); // For associated delay slot.
Andrei Popescu31002712010-02-23 13:46:05 +00001215}
1216
1217
1218void Assembler::bgez(Register rs, int16_t offset) {
Steve Block44f0eee2011-05-26 01:26:41 +01001219 BlockTrampolinePoolScope block_trampoline_pool(this);
Andrei Popescu31002712010-02-23 13:46:05 +00001220 GenInstrImmediate(REGIMM, rs, BGEZ, offset);
Steve Block44f0eee2011-05-26 01:26:41 +01001221 BlockTrampolinePoolFor(1); // For associated delay slot.
Andrei Popescu31002712010-02-23 13:46:05 +00001222}
1223
1224
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001225void Assembler::bgezc(Register rt, int16_t offset) {
1226 DCHECK(IsMipsArchVariant(kMips32r6));
1227 DCHECK(!(rt.is(zero_reg)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001228 GenInstrImmediate(BLEZL, rt, rt, offset, CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001229}
1230
1231
1232void Assembler::bgeuc(Register rs, Register rt, int16_t offset) {
1233 DCHECK(IsMipsArchVariant(kMips32r6));
1234 DCHECK(!(rs.is(zero_reg)));
1235 DCHECK(!(rt.is(zero_reg)));
1236 DCHECK(rs.code() != rt.code());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001237 GenInstrImmediate(BLEZ, rs, rt, offset, CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001238}
1239
1240
1241void Assembler::bgec(Register rs, Register rt, int16_t offset) {
1242 DCHECK(IsMipsArchVariant(kMips32r6));
1243 DCHECK(!(rs.is(zero_reg)));
1244 DCHECK(!(rt.is(zero_reg)));
1245 DCHECK(rs.code() != rt.code());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001246 GenInstrImmediate(BLEZL, rs, rt, offset, CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001247}
1248
1249
Andrei Popescu31002712010-02-23 13:46:05 +00001250void Assembler::bgezal(Register rs, int16_t offset) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001251 DCHECK(!IsMipsArchVariant(kMips32r6) || rs.is(zero_reg));
Steve Block44f0eee2011-05-26 01:26:41 +01001252 BlockTrampolinePoolScope block_trampoline_pool(this);
1253 positions_recorder()->WriteRecordedPositions();
Andrei Popescu31002712010-02-23 13:46:05 +00001254 GenInstrImmediate(REGIMM, rs, BGEZAL, offset);
Steve Block44f0eee2011-05-26 01:26:41 +01001255 BlockTrampolinePoolFor(1); // For associated delay slot.
Andrei Popescu31002712010-02-23 13:46:05 +00001256}
1257
1258
1259void Assembler::bgtz(Register rs, int16_t offset) {
Steve Block44f0eee2011-05-26 01:26:41 +01001260 BlockTrampolinePoolScope block_trampoline_pool(this);
Andrei Popescu31002712010-02-23 13:46:05 +00001261 GenInstrImmediate(BGTZ, rs, zero_reg, offset);
Steve Block44f0eee2011-05-26 01:26:41 +01001262 BlockTrampolinePoolFor(1); // For associated delay slot.
Andrei Popescu31002712010-02-23 13:46:05 +00001263}
1264
1265
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001266void Assembler::bgtzc(Register rt, int16_t offset) {
1267 DCHECK(IsMipsArchVariant(kMips32r6));
1268 DCHECK(!(rt.is(zero_reg)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001269 GenInstrImmediate(BGTZL, zero_reg, rt, offset,
1270 CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001271}
1272
1273
Andrei Popescu31002712010-02-23 13:46:05 +00001274void Assembler::blez(Register rs, int16_t offset) {
Steve Block44f0eee2011-05-26 01:26:41 +01001275 BlockTrampolinePoolScope block_trampoline_pool(this);
Andrei Popescu31002712010-02-23 13:46:05 +00001276 GenInstrImmediate(BLEZ, rs, zero_reg, offset);
Steve Block44f0eee2011-05-26 01:26:41 +01001277 BlockTrampolinePoolFor(1); // For associated delay slot.
Andrei Popescu31002712010-02-23 13:46:05 +00001278}
1279
1280
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001281void Assembler::blezc(Register rt, int16_t offset) {
1282 DCHECK(IsMipsArchVariant(kMips32r6));
1283 DCHECK(!(rt.is(zero_reg)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001284 GenInstrImmediate(BLEZL, zero_reg, rt, offset,
1285 CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001286}
1287
1288
1289void Assembler::bltzc(Register rt, int16_t offset) {
1290 DCHECK(IsMipsArchVariant(kMips32r6));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001291 DCHECK(!rt.is(zero_reg));
1292 GenInstrImmediate(BGTZL, rt, rt, offset, CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001293}
1294
1295
1296void Assembler::bltuc(Register rs, Register rt, int16_t offset) {
1297 DCHECK(IsMipsArchVariant(kMips32r6));
1298 DCHECK(!(rs.is(zero_reg)));
1299 DCHECK(!(rt.is(zero_reg)));
1300 DCHECK(rs.code() != rt.code());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001301 GenInstrImmediate(BGTZ, rs, rt, offset, CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001302}
1303
1304
1305void Assembler::bltc(Register rs, Register rt, int16_t offset) {
1306 DCHECK(IsMipsArchVariant(kMips32r6));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001307 DCHECK(!rs.is(zero_reg));
1308 DCHECK(!rt.is(zero_reg));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001309 DCHECK(rs.code() != rt.code());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001310 GenInstrImmediate(BGTZL, rs, rt, offset, CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001311}
1312
1313
Andrei Popescu31002712010-02-23 13:46:05 +00001314void Assembler::bltz(Register rs, int16_t offset) {
Steve Block44f0eee2011-05-26 01:26:41 +01001315 BlockTrampolinePoolScope block_trampoline_pool(this);
Andrei Popescu31002712010-02-23 13:46:05 +00001316 GenInstrImmediate(REGIMM, rs, BLTZ, offset);
Steve Block44f0eee2011-05-26 01:26:41 +01001317 BlockTrampolinePoolFor(1); // For associated delay slot.
Andrei Popescu31002712010-02-23 13:46:05 +00001318}
1319
1320
1321void Assembler::bltzal(Register rs, int16_t offset) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001322 DCHECK(!IsMipsArchVariant(kMips32r6) || rs.is(zero_reg));
Steve Block44f0eee2011-05-26 01:26:41 +01001323 BlockTrampolinePoolScope block_trampoline_pool(this);
1324 positions_recorder()->WriteRecordedPositions();
Andrei Popescu31002712010-02-23 13:46:05 +00001325 GenInstrImmediate(REGIMM, rs, BLTZAL, offset);
Steve Block44f0eee2011-05-26 01:26:41 +01001326 BlockTrampolinePoolFor(1); // For associated delay slot.
Andrei Popescu31002712010-02-23 13:46:05 +00001327}
1328
1329
1330void Assembler::bne(Register rs, Register rt, int16_t offset) {
Steve Block44f0eee2011-05-26 01:26:41 +01001331 BlockTrampolinePoolScope block_trampoline_pool(this);
Andrei Popescu31002712010-02-23 13:46:05 +00001332 GenInstrImmediate(BNE, rs, rt, offset);
Steve Block44f0eee2011-05-26 01:26:41 +01001333 BlockTrampolinePoolFor(1); // For associated delay slot.
Andrei Popescu31002712010-02-23 13:46:05 +00001334}
1335
1336
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001337void Assembler::bovc(Register rs, Register rt, int16_t offset) {
1338 DCHECK(IsMipsArchVariant(kMips32r6));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001339 DCHECK(!rs.is(zero_reg));
1340 if (rs.code() >= rt.code()) {
1341 GenInstrImmediate(ADDI, rs, rt, offset, CompactBranchType::COMPACT_BRANCH);
1342 } else {
1343 GenInstrImmediate(ADDI, rt, rs, offset, CompactBranchType::COMPACT_BRANCH);
1344 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001345}
1346
1347
1348void Assembler::bnvc(Register rs, Register rt, int16_t offset) {
1349 DCHECK(IsMipsArchVariant(kMips32r6));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001350 DCHECK(!rs.is(zero_reg));
1351 if (rs.code() >= rt.code()) {
1352 GenInstrImmediate(DADDI, rs, rt, offset, CompactBranchType::COMPACT_BRANCH);
1353 } else {
1354 GenInstrImmediate(DADDI, rt, rs, offset, CompactBranchType::COMPACT_BRANCH);
1355 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001356}
1357
1358
1359void Assembler::blezalc(Register rt, int16_t offset) {
1360 DCHECK(IsMipsArchVariant(kMips32r6));
1361 DCHECK(!(rt.is(zero_reg)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001362 positions_recorder()->WriteRecordedPositions();
1363 GenInstrImmediate(BLEZ, zero_reg, rt, offset,
1364 CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001365}
1366
1367
1368void Assembler::bgezalc(Register rt, int16_t offset) {
1369 DCHECK(IsMipsArchVariant(kMips32r6));
1370 DCHECK(!(rt.is(zero_reg)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001371 positions_recorder()->WriteRecordedPositions();
1372 GenInstrImmediate(BLEZ, rt, rt, offset, CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001373}
1374
1375
1376void Assembler::bgezall(Register rs, int16_t offset) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001377 DCHECK(!IsMipsArchVariant(kMips32r6));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001378 DCHECK(!(rs.is(zero_reg)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001379 BlockTrampolinePoolScope block_trampoline_pool(this);
1380 positions_recorder()->WriteRecordedPositions();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001381 GenInstrImmediate(REGIMM, rs, BGEZALL, offset);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001382 BlockTrampolinePoolFor(1); // For associated delay slot.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001383}
1384
1385
1386void Assembler::bltzalc(Register rt, int16_t offset) {
1387 DCHECK(IsMipsArchVariant(kMips32r6));
1388 DCHECK(!(rt.is(zero_reg)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001389 positions_recorder()->WriteRecordedPositions();
1390 GenInstrImmediate(BGTZ, rt, rt, offset, CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001391}
1392
1393
1394void Assembler::bgtzalc(Register rt, int16_t offset) {
1395 DCHECK(IsMipsArchVariant(kMips32r6));
1396 DCHECK(!(rt.is(zero_reg)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001397 positions_recorder()->WriteRecordedPositions();
1398 GenInstrImmediate(BGTZ, zero_reg, rt, offset,
1399 CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001400}
1401
1402
1403void Assembler::beqzalc(Register rt, int16_t offset) {
1404 DCHECK(IsMipsArchVariant(kMips32r6));
1405 DCHECK(!(rt.is(zero_reg)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001406 positions_recorder()->WriteRecordedPositions();
1407 GenInstrImmediate(ADDI, zero_reg, rt, offset,
1408 CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001409}
1410
1411
1412void Assembler::bnezalc(Register rt, int16_t offset) {
1413 DCHECK(IsMipsArchVariant(kMips32r6));
1414 DCHECK(!(rt.is(zero_reg)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001415 positions_recorder()->WriteRecordedPositions();
1416 GenInstrImmediate(DADDI, zero_reg, rt, offset,
1417 CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001418}
1419
1420
1421void Assembler::beqc(Register rs, Register rt, int16_t offset) {
1422 DCHECK(IsMipsArchVariant(kMips32r6));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001423 DCHECK(rs.code() != rt.code() && rs.code() != 0 && rt.code() != 0);
1424 if (rs.code() < rt.code()) {
1425 GenInstrImmediate(ADDI, rs, rt, offset, CompactBranchType::COMPACT_BRANCH);
1426 } else {
1427 GenInstrImmediate(ADDI, rt, rs, offset, CompactBranchType::COMPACT_BRANCH);
1428 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001429}
1430
1431
1432void Assembler::beqzc(Register rs, int32_t offset) {
1433 DCHECK(IsMipsArchVariant(kMips32r6));
1434 DCHECK(!(rs.is(zero_reg)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001435 GenInstrImmediate(POP66, rs, offset, CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001436}
1437
1438
1439void Assembler::bnec(Register rs, Register rt, int16_t offset) {
1440 DCHECK(IsMipsArchVariant(kMips32r6));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001441 DCHECK(rs.code() != rt.code() && rs.code() != 0 && rt.code() != 0);
1442 if (rs.code() < rt.code()) {
1443 GenInstrImmediate(DADDI, rs, rt, offset, CompactBranchType::COMPACT_BRANCH);
1444 } else {
1445 GenInstrImmediate(DADDI, rt, rs, offset, CompactBranchType::COMPACT_BRANCH);
1446 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001447}
1448
1449
1450void Assembler::bnezc(Register rs, int32_t offset) {
1451 DCHECK(IsMipsArchVariant(kMips32r6));
1452 DCHECK(!(rs.is(zero_reg)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001453 GenInstrImmediate(POP76, rs, offset, CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001454}
1455
1456
Andrei Popescu31002712010-02-23 13:46:05 +00001457void Assembler::j(int32_t target) {
Ben Murdoch589d6972011-11-30 16:04:58 +00001458#if DEBUG
1459 // Get pc of delay slot.
1460 uint32_t ipc = reinterpret_cast<uint32_t>(pc_ + 1 * kInstrSize);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001461 bool in_range = ((ipc ^ static_cast<uint32_t>(target)) >>
1462 (kImm26Bits + kImmFieldShift)) == 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001463 DCHECK(in_range && ((target & 3) == 0));
Ben Murdoch589d6972011-11-30 16:04:58 +00001464#endif
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001465 BlockTrampolinePoolScope block_trampoline_pool(this);
1466 GenInstrJump(J, (target >> 2) & kImm26Mask);
1467 BlockTrampolinePoolFor(1); // For associated delay slot.
Andrei Popescu31002712010-02-23 13:46:05 +00001468}
1469
1470
1471void Assembler::jr(Register rs) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001472 if (!IsMipsArchVariant(kMips32r6)) {
1473 BlockTrampolinePoolScope block_trampoline_pool(this);
1474 if (rs.is(ra)) {
1475 positions_recorder()->WriteRecordedPositions();
1476 }
1477 GenInstrRegister(SPECIAL, rs, zero_reg, zero_reg, 0, JR);
1478 BlockTrampolinePoolFor(1); // For associated delay slot.
1479 } else {
1480 jalr(rs, zero_reg);
Steve Block44f0eee2011-05-26 01:26:41 +01001481 }
Andrei Popescu31002712010-02-23 13:46:05 +00001482}
1483
1484
1485void Assembler::jal(int32_t target) {
Ben Murdoch589d6972011-11-30 16:04:58 +00001486#ifdef DEBUG
1487 // Get pc of delay slot.
1488 uint32_t ipc = reinterpret_cast<uint32_t>(pc_ + 1 * kInstrSize);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001489 bool in_range = ((ipc ^ static_cast<uint32_t>(target)) >>
1490 (kImm26Bits + kImmFieldShift)) == 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001491 DCHECK(in_range && ((target & 3) == 0));
Ben Murdoch589d6972011-11-30 16:04:58 +00001492#endif
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001493 BlockTrampolinePoolScope block_trampoline_pool(this);
Steve Block44f0eee2011-05-26 01:26:41 +01001494 positions_recorder()->WriteRecordedPositions();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001495 GenInstrJump(JAL, (target >> 2) & kImm26Mask);
1496 BlockTrampolinePoolFor(1); // For associated delay slot.
Andrei Popescu31002712010-02-23 13:46:05 +00001497}
1498
1499
1500void Assembler::jalr(Register rs, Register rd) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001501 DCHECK(rs.code() != rd.code());
Steve Block44f0eee2011-05-26 01:26:41 +01001502 BlockTrampolinePoolScope block_trampoline_pool(this);
1503 positions_recorder()->WriteRecordedPositions();
Andrei Popescu31002712010-02-23 13:46:05 +00001504 GenInstrRegister(SPECIAL, rs, zero_reg, rd, 0, JALR);
Steve Block44f0eee2011-05-26 01:26:41 +01001505 BlockTrampolinePoolFor(1); // For associated delay slot.
Andrei Popescu31002712010-02-23 13:46:05 +00001506}
1507
1508
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001509void Assembler::jic(Register rt, int16_t offset) {
1510 DCHECK(IsMipsArchVariant(kMips32r6));
1511 GenInstrImmediate(POP66, zero_reg, rt, offset);
Ben Murdoch589d6972011-11-30 16:04:58 +00001512}
1513
1514
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001515void Assembler::jialc(Register rt, int16_t offset) {
1516 DCHECK(IsMipsArchVariant(kMips32r6));
1517 positions_recorder()->WriteRecordedPositions();
1518 GenInstrImmediate(POP76, zero_reg, rt, offset);
Ben Murdoch589d6972011-11-30 16:04:58 +00001519}
1520
1521
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001522// -------Data-processing-instructions---------
Andrei Popescu31002712010-02-23 13:46:05 +00001523
1524// Arithmetic.
1525
Andrei Popescu31002712010-02-23 13:46:05 +00001526void Assembler::addu(Register rd, Register rs, Register rt) {
1527 GenInstrRegister(SPECIAL, rs, rt, rd, 0, ADDU);
1528}
1529
1530
Andrei Popescu31002712010-02-23 13:46:05 +00001531void Assembler::addiu(Register rd, Register rs, int32_t j) {
1532 GenInstrImmediate(ADDIU, rs, rd, j);
Andrei Popescu31002712010-02-23 13:46:05 +00001533}
1534
1535
1536void Assembler::subu(Register rd, Register rs, Register rt) {
1537 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SUBU);
1538}
1539
1540
1541void Assembler::mul(Register rd, Register rs, Register rt) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001542 if (!IsMipsArchVariant(kMips32r6)) {
1543 GenInstrRegister(SPECIAL2, rs, rt, rd, 0, MUL);
1544 } else {
1545 GenInstrRegister(SPECIAL, rs, rt, rd, MUL_OP, MUL_MUH);
1546 }
1547}
1548
1549
1550void Assembler::mulu(Register rd, Register rs, Register rt) {
1551 DCHECK(IsMipsArchVariant(kMips32r6));
1552 GenInstrRegister(SPECIAL, rs, rt, rd, MUL_OP, MUL_MUH_U);
1553}
1554
1555
1556void Assembler::muh(Register rd, Register rs, Register rt) {
1557 DCHECK(IsMipsArchVariant(kMips32r6));
1558 GenInstrRegister(SPECIAL, rs, rt, rd, MUH_OP, MUL_MUH);
1559}
1560
1561
1562void Assembler::muhu(Register rd, Register rs, Register rt) {
1563 DCHECK(IsMipsArchVariant(kMips32r6));
1564 GenInstrRegister(SPECIAL, rs, rt, rd, MUH_OP, MUL_MUH_U);
1565}
1566
1567
1568void Assembler::mod(Register rd, Register rs, Register rt) {
1569 DCHECK(IsMipsArchVariant(kMips32r6));
1570 GenInstrRegister(SPECIAL, rs, rt, rd, MOD_OP, DIV_MOD);
1571}
1572
1573
1574void Assembler::modu(Register rd, Register rs, Register rt) {
1575 DCHECK(IsMipsArchVariant(kMips32r6));
1576 GenInstrRegister(SPECIAL, rs, rt, rd, MOD_OP, DIV_MOD_U);
Andrei Popescu31002712010-02-23 13:46:05 +00001577}
1578
1579
1580void Assembler::mult(Register rs, Register rt) {
1581 GenInstrRegister(SPECIAL, rs, rt, zero_reg, 0, MULT);
1582}
1583
1584
1585void Assembler::multu(Register rs, Register rt) {
1586 GenInstrRegister(SPECIAL, rs, rt, zero_reg, 0, MULTU);
1587}
1588
1589
1590void Assembler::div(Register rs, Register rt) {
1591 GenInstrRegister(SPECIAL, rs, rt, zero_reg, 0, DIV);
1592}
1593
1594
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001595void Assembler::div(Register rd, Register rs, Register rt) {
1596 DCHECK(IsMipsArchVariant(kMips32r6));
1597 GenInstrRegister(SPECIAL, rs, rt, rd, DIV_OP, DIV_MOD);
1598}
1599
1600
Andrei Popescu31002712010-02-23 13:46:05 +00001601void Assembler::divu(Register rs, Register rt) {
1602 GenInstrRegister(SPECIAL, rs, rt, zero_reg, 0, DIVU);
1603}
1604
1605
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001606void Assembler::divu(Register rd, Register rs, Register rt) {
1607 DCHECK(IsMipsArchVariant(kMips32r6));
1608 GenInstrRegister(SPECIAL, rs, rt, rd, DIV_OP, DIV_MOD_U);
1609}
1610
1611
Andrei Popescu31002712010-02-23 13:46:05 +00001612// Logical.
1613
1614void Assembler::and_(Register rd, Register rs, Register rt) {
1615 GenInstrRegister(SPECIAL, rs, rt, rd, 0, AND);
1616}
1617
1618
1619void Assembler::andi(Register rt, Register rs, int32_t j) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001620 DCHECK(is_uint16(j));
Andrei Popescu31002712010-02-23 13:46:05 +00001621 GenInstrImmediate(ANDI, rs, rt, j);
1622}
1623
1624
1625void Assembler::or_(Register rd, Register rs, Register rt) {
1626 GenInstrRegister(SPECIAL, rs, rt, rd, 0, OR);
1627}
1628
1629
1630void Assembler::ori(Register rt, Register rs, int32_t j) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001631 DCHECK(is_uint16(j));
Andrei Popescu31002712010-02-23 13:46:05 +00001632 GenInstrImmediate(ORI, rs, rt, j);
1633}
1634
1635
1636void Assembler::xor_(Register rd, Register rs, Register rt) {
1637 GenInstrRegister(SPECIAL, rs, rt, rd, 0, XOR);
1638}
1639
1640
1641void Assembler::xori(Register rt, Register rs, int32_t j) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001642 DCHECK(is_uint16(j));
Andrei Popescu31002712010-02-23 13:46:05 +00001643 GenInstrImmediate(XORI, rs, rt, j);
1644}
1645
1646
1647void Assembler::nor(Register rd, Register rs, Register rt) {
1648 GenInstrRegister(SPECIAL, rs, rt, rd, 0, NOR);
1649}
1650
1651
1652// Shifts.
Steve Block44f0eee2011-05-26 01:26:41 +01001653void Assembler::sll(Register rd,
1654 Register rt,
1655 uint16_t sa,
1656 bool coming_from_nop) {
1657 // Don't allow nop instructions in the form sll zero_reg, zero_reg to be
1658 // generated using the sll instruction. They must be generated using
1659 // nop(int/NopMarkerTypes) or MarkCode(int/NopMarkerTypes) pseudo
1660 // instructions.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001661 DCHECK(coming_from_nop || !(rd.is(zero_reg) && rt.is(zero_reg)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001662 GenInstrRegister(SPECIAL, zero_reg, rt, rd, sa & 0x1F, SLL);
Andrei Popescu31002712010-02-23 13:46:05 +00001663}
1664
1665
1666void Assembler::sllv(Register rd, Register rt, Register rs) {
1667 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SLLV);
1668}
1669
1670
1671void Assembler::srl(Register rd, Register rt, uint16_t sa) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001672 GenInstrRegister(SPECIAL, zero_reg, rt, rd, sa & 0x1F, SRL);
Andrei Popescu31002712010-02-23 13:46:05 +00001673}
1674
1675
1676void Assembler::srlv(Register rd, Register rt, Register rs) {
1677 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SRLV);
1678}
1679
1680
1681void Assembler::sra(Register rd, Register rt, uint16_t sa) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001682 GenInstrRegister(SPECIAL, zero_reg, rt, rd, sa & 0x1F, SRA);
Andrei Popescu31002712010-02-23 13:46:05 +00001683}
1684
1685
1686void Assembler::srav(Register rd, Register rt, Register rs) {
1687 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SRAV);
1688}
1689
1690
Steve Block44f0eee2011-05-26 01:26:41 +01001691void Assembler::rotr(Register rd, Register rt, uint16_t sa) {
1692 // Should be called via MacroAssembler::Ror.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001693 DCHECK(rd.is_valid() && rt.is_valid() && is_uint5(sa));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001694 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
Steve Block44f0eee2011-05-26 01:26:41 +01001695 Instr instr = SPECIAL | (1 << kRsShift) | (rt.code() << kRtShift)
1696 | (rd.code() << kRdShift) | (sa << kSaShift) | SRL;
1697 emit(instr);
1698}
1699
1700
1701void Assembler::rotrv(Register rd, Register rt, Register rs) {
1702 // Should be called via MacroAssembler::Ror.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001703 DCHECK(rd.is_valid() && rt.is_valid() && rs.is_valid());
1704 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
Steve Block44f0eee2011-05-26 01:26:41 +01001705 Instr instr = SPECIAL | (rs.code() << kRsShift) | (rt.code() << kRtShift)
1706 | (rd.code() << kRdShift) | (1 << kSaShift) | SRLV;
1707 emit(instr);
1708}
1709
1710
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001711void Assembler::lsa(Register rd, Register rt, Register rs, uint8_t sa) {
1712 DCHECK(rd.is_valid() && rt.is_valid() && rs.is_valid());
1713 DCHECK(sa < 5 && sa > 0);
1714 DCHECK(IsMipsArchVariant(kMips32r6));
1715 Instr instr = SPECIAL | (rs.code() << kRsShift) | (rt.code() << kRtShift) |
1716 (rd.code() << kRdShift) | (sa - 1) << kSaShift | LSA;
1717 emit(instr);
1718}
1719
1720
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001721// ------------Memory-instructions-------------
Andrei Popescu31002712010-02-23 13:46:05 +00001722
Steve Block44f0eee2011-05-26 01:26:41 +01001723// Helper for base-reg + offset, when offset is larger than int16.
1724void Assembler::LoadRegPlusOffsetToAt(const MemOperand& src) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001725 DCHECK(!src.rm().is(at));
1726 lui(at, (src.offset_ >> kLuiShift) & kImm16Mask);
Steve Block44f0eee2011-05-26 01:26:41 +01001727 ori(at, at, src.offset_ & kImm16Mask); // Load 32-bit offset.
1728 addu(at, at, src.rm()); // Add base register.
1729}
1730
1731
Andrei Popescu31002712010-02-23 13:46:05 +00001732void Assembler::lb(Register rd, const MemOperand& rs) {
Steve Block44f0eee2011-05-26 01:26:41 +01001733 if (is_int16(rs.offset_)) {
1734 GenInstrImmediate(LB, rs.rm(), rd, rs.offset_);
1735 } else { // Offset > 16 bits, use multiple instructions to load.
1736 LoadRegPlusOffsetToAt(rs);
1737 GenInstrImmediate(LB, at, rd, 0); // Equiv to lb(rd, MemOperand(at, 0));
1738 }
Andrei Popescu31002712010-02-23 13:46:05 +00001739}
1740
1741
1742void Assembler::lbu(Register rd, const MemOperand& rs) {
Steve Block44f0eee2011-05-26 01:26:41 +01001743 if (is_int16(rs.offset_)) {
1744 GenInstrImmediate(LBU, rs.rm(), rd, rs.offset_);
1745 } else { // Offset > 16 bits, use multiple instructions to load.
1746 LoadRegPlusOffsetToAt(rs);
1747 GenInstrImmediate(LBU, at, rd, 0); // Equiv to lbu(rd, MemOperand(at, 0));
1748 }
1749}
1750
1751
1752void Assembler::lh(Register rd, const MemOperand& rs) {
1753 if (is_int16(rs.offset_)) {
1754 GenInstrImmediate(LH, rs.rm(), rd, rs.offset_);
1755 } else { // Offset > 16 bits, use multiple instructions to load.
1756 LoadRegPlusOffsetToAt(rs);
1757 GenInstrImmediate(LH, at, rd, 0); // Equiv to lh(rd, MemOperand(at, 0));
1758 }
1759}
1760
1761
1762void Assembler::lhu(Register rd, const MemOperand& rs) {
1763 if (is_int16(rs.offset_)) {
1764 GenInstrImmediate(LHU, rs.rm(), rd, rs.offset_);
1765 } else { // Offset > 16 bits, use multiple instructions to load.
1766 LoadRegPlusOffsetToAt(rs);
1767 GenInstrImmediate(LHU, at, rd, 0); // Equiv to lhu(rd, MemOperand(at, 0));
1768 }
Andrei Popescu31002712010-02-23 13:46:05 +00001769}
1770
1771
1772void Assembler::lw(Register rd, const MemOperand& rs) {
Steve Block44f0eee2011-05-26 01:26:41 +01001773 if (is_int16(rs.offset_)) {
1774 GenInstrImmediate(LW, rs.rm(), rd, rs.offset_);
1775 } else { // Offset > 16 bits, use multiple instructions to load.
1776 LoadRegPlusOffsetToAt(rs);
1777 GenInstrImmediate(LW, at, rd, 0); // Equiv to lw(rd, MemOperand(at, 0));
1778 }
Steve Block44f0eee2011-05-26 01:26:41 +01001779}
1780
1781
1782void Assembler::lwl(Register rd, const MemOperand& rs) {
1783 GenInstrImmediate(LWL, rs.rm(), rd, rs.offset_);
1784}
1785
1786
1787void Assembler::lwr(Register rd, const MemOperand& rs) {
1788 GenInstrImmediate(LWR, rs.rm(), rd, rs.offset_);
Andrei Popescu31002712010-02-23 13:46:05 +00001789}
1790
1791
1792void Assembler::sb(Register rd, const MemOperand& rs) {
Steve Block44f0eee2011-05-26 01:26:41 +01001793 if (is_int16(rs.offset_)) {
1794 GenInstrImmediate(SB, rs.rm(), rd, rs.offset_);
1795 } else { // Offset > 16 bits, use multiple instructions to store.
1796 LoadRegPlusOffsetToAt(rs);
1797 GenInstrImmediate(SB, at, rd, 0); // Equiv to sb(rd, MemOperand(at, 0));
1798 }
1799}
1800
1801
1802void Assembler::sh(Register rd, const MemOperand& rs) {
1803 if (is_int16(rs.offset_)) {
1804 GenInstrImmediate(SH, rs.rm(), rd, rs.offset_);
1805 } else { // Offset > 16 bits, use multiple instructions to store.
1806 LoadRegPlusOffsetToAt(rs);
1807 GenInstrImmediate(SH, at, rd, 0); // Equiv to sh(rd, MemOperand(at, 0));
1808 }
Andrei Popescu31002712010-02-23 13:46:05 +00001809}
1810
1811
1812void Assembler::sw(Register rd, const MemOperand& rs) {
Steve Block44f0eee2011-05-26 01:26:41 +01001813 if (is_int16(rs.offset_)) {
1814 GenInstrImmediate(SW, rs.rm(), rd, rs.offset_);
1815 } else { // Offset > 16 bits, use multiple instructions to store.
1816 LoadRegPlusOffsetToAt(rs);
1817 GenInstrImmediate(SW, at, rd, 0); // Equiv to sw(rd, MemOperand(at, 0));
1818 }
Steve Block44f0eee2011-05-26 01:26:41 +01001819}
1820
1821
1822void Assembler::swl(Register rd, const MemOperand& rs) {
1823 GenInstrImmediate(SWL, rs.rm(), rd, rs.offset_);
1824}
1825
1826
1827void Assembler::swr(Register rd, const MemOperand& rs) {
1828 GenInstrImmediate(SWR, rs.rm(), rd, rs.offset_);
Andrei Popescu31002712010-02-23 13:46:05 +00001829}
1830
1831
1832void Assembler::lui(Register rd, int32_t j) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001833 DCHECK(is_uint16(j));
Andrei Popescu31002712010-02-23 13:46:05 +00001834 GenInstrImmediate(LUI, zero_reg, rd, j);
1835}
1836
1837
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001838void Assembler::aui(Register rt, Register rs, int32_t j) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001839 // This instruction uses same opcode as 'lui'. The difference in encoding is
1840 // 'lui' has zero reg. for rs field.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001841 DCHECK(!(rs.is(zero_reg)));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001842 DCHECK(is_uint16(j));
1843 GenInstrImmediate(LUI, rs, rt, j);
1844}
1845
1846
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001847// ---------PC-Relative instructions-----------
1848
1849void Assembler::addiupc(Register rs, int32_t imm19) {
1850 DCHECK(IsMipsArchVariant(kMips32r6));
1851 DCHECK(rs.is_valid() && is_int19(imm19));
1852 uint32_t imm21 = ADDIUPC << kImm19Bits | (imm19 & kImm19Mask);
1853 GenInstrImmediate(PCREL, rs, imm21);
1854}
1855
1856
1857void Assembler::lwpc(Register rs, int32_t offset19) {
1858 DCHECK(IsMipsArchVariant(kMips32r6));
1859 DCHECK(rs.is_valid() && is_int19(offset19));
1860 uint32_t imm21 = LWPC << kImm19Bits | (offset19 & kImm19Mask);
1861 GenInstrImmediate(PCREL, rs, imm21);
1862}
1863
1864
1865void Assembler::auipc(Register rs, int16_t imm16) {
1866 DCHECK(IsMipsArchVariant(kMips32r6));
1867 DCHECK(rs.is_valid());
1868 uint32_t imm21 = AUIPC << kImm16Bits | (imm16 & kImm16Mask);
1869 GenInstrImmediate(PCREL, rs, imm21);
1870}
1871
1872
1873void Assembler::aluipc(Register rs, int16_t imm16) {
1874 DCHECK(IsMipsArchVariant(kMips32r6));
1875 DCHECK(rs.is_valid());
1876 uint32_t imm21 = ALUIPC << kImm16Bits | (imm16 & kImm16Mask);
1877 GenInstrImmediate(PCREL, rs, imm21);
1878}
1879
1880
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001881// -------------Misc-instructions--------------
Andrei Popescu31002712010-02-23 13:46:05 +00001882
1883// Break / Trap instructions.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001884void Assembler::break_(uint32_t code, bool break_as_stop) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001885 DCHECK((code & ~0xfffff) == 0);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001886 // We need to invalidate breaks that could be stops as well because the
1887 // simulator expects a char pointer after the stop instruction.
1888 // See constants-mips.h for explanation.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001889 DCHECK((break_as_stop &&
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001890 code <= kMaxStopCode &&
1891 code > kMaxWatchpointCode) ||
1892 (!break_as_stop &&
1893 (code > kMaxStopCode ||
1894 code <= kMaxWatchpointCode)));
Andrei Popescu31002712010-02-23 13:46:05 +00001895 Instr break_instr = SPECIAL | BREAK | (code << 6);
1896 emit(break_instr);
1897}
1898
1899
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001900void Assembler::stop(const char* msg, uint32_t code) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001901 DCHECK(code > kMaxWatchpointCode);
1902 DCHECK(code <= kMaxStopCode);
1903#if V8_HOST_ARCH_MIPS
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001904 break_(0x54321);
1905#else // V8_HOST_ARCH_MIPS
1906 BlockTrampolinePoolFor(2);
1907 // The Simulator will handle the stop instruction and get the message address.
1908 // On MIPS stop() is just a special kind of break_().
1909 break_(code, true);
1910 emit(reinterpret_cast<Instr>(msg));
1911#endif
1912}
1913
1914
Andrei Popescu31002712010-02-23 13:46:05 +00001915void Assembler::tge(Register rs, Register rt, uint16_t code) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001916 DCHECK(is_uint10(code));
Andrei Popescu31002712010-02-23 13:46:05 +00001917 Instr instr = SPECIAL | TGE | rs.code() << kRsShift
1918 | rt.code() << kRtShift | code << 6;
1919 emit(instr);
1920}
1921
1922
1923void Assembler::tgeu(Register rs, Register rt, uint16_t code) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001924 DCHECK(is_uint10(code));
Andrei Popescu31002712010-02-23 13:46:05 +00001925 Instr instr = SPECIAL | TGEU | rs.code() << kRsShift
1926 | rt.code() << kRtShift | code << 6;
1927 emit(instr);
1928}
1929
1930
1931void Assembler::tlt(Register rs, Register rt, uint16_t code) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001932 DCHECK(is_uint10(code));
Andrei Popescu31002712010-02-23 13:46:05 +00001933 Instr instr =
1934 SPECIAL | TLT | rs.code() << kRsShift | rt.code() << kRtShift | code << 6;
1935 emit(instr);
1936}
1937
1938
1939void Assembler::tltu(Register rs, Register rt, uint16_t code) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001940 DCHECK(is_uint10(code));
Steve Block44f0eee2011-05-26 01:26:41 +01001941 Instr instr =
1942 SPECIAL | TLTU | rs.code() << kRsShift
Andrei Popescu31002712010-02-23 13:46:05 +00001943 | rt.code() << kRtShift | code << 6;
1944 emit(instr);
1945}
1946
1947
1948void Assembler::teq(Register rs, Register rt, uint16_t code) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001949 DCHECK(is_uint10(code));
Andrei Popescu31002712010-02-23 13:46:05 +00001950 Instr instr =
1951 SPECIAL | TEQ | rs.code() << kRsShift | rt.code() << kRtShift | code << 6;
1952 emit(instr);
1953}
1954
1955
1956void Assembler::tne(Register rs, Register rt, uint16_t code) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001957 DCHECK(is_uint10(code));
Andrei Popescu31002712010-02-23 13:46:05 +00001958 Instr instr =
1959 SPECIAL | TNE | rs.code() << kRsShift | rt.code() << kRtShift | code << 6;
1960 emit(instr);
1961}
1962
1963
1964// Move from HI/LO register.
1965
1966void Assembler::mfhi(Register rd) {
1967 GenInstrRegister(SPECIAL, zero_reg, zero_reg, rd, 0, MFHI);
1968}
1969
1970
1971void Assembler::mflo(Register rd) {
1972 GenInstrRegister(SPECIAL, zero_reg, zero_reg, rd, 0, MFLO);
1973}
1974
1975
1976// Set on less than instructions.
1977void Assembler::slt(Register rd, Register rs, Register rt) {
1978 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SLT);
1979}
1980
1981
1982void Assembler::sltu(Register rd, Register rs, Register rt) {
1983 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SLTU);
1984}
1985
1986
1987void Assembler::slti(Register rt, Register rs, int32_t j) {
1988 GenInstrImmediate(SLTI, rs, rt, j);
1989}
1990
1991
1992void Assembler::sltiu(Register rt, Register rs, int32_t j) {
1993 GenInstrImmediate(SLTIU, rs, rt, j);
1994}
1995
1996
Steve Block44f0eee2011-05-26 01:26:41 +01001997// Conditional move.
1998void Assembler::movz(Register rd, Register rs, Register rt) {
1999 GenInstrRegister(SPECIAL, rs, rt, rd, 0, MOVZ);
2000}
2001
2002
2003void Assembler::movn(Register rd, Register rs, Register rt) {
2004 GenInstrRegister(SPECIAL, rs, rt, rd, 0, MOVN);
2005}
2006
2007
2008void Assembler::movt(Register rd, Register rs, uint16_t cc) {
2009 Register rt;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002010 rt.reg_code = (cc & 0x0007) << 2 | 1;
Steve Block44f0eee2011-05-26 01:26:41 +01002011 GenInstrRegister(SPECIAL, rs, rt, rd, 0, MOVCI);
2012}
2013
2014
2015void Assembler::movf(Register rd, Register rs, uint16_t cc) {
2016 Register rt;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002017 rt.reg_code = (cc & 0x0007) << 2 | 0;
Steve Block44f0eee2011-05-26 01:26:41 +01002018 GenInstrRegister(SPECIAL, rs, rt, rd, 0, MOVCI);
2019}
2020
2021
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002022void Assembler::seleqz(Register rd, Register rs, Register rt) {
2023 DCHECK(IsMipsArchVariant(kMips32r6));
2024 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SELEQZ_S);
2025}
2026
2027
Steve Block44f0eee2011-05-26 01:26:41 +01002028// Bit twiddling.
2029void Assembler::clz(Register rd, Register rs) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002030 if (!IsMipsArchVariant(kMips32r6)) {
2031 // Clz instr requires same GPR number in 'rd' and 'rt' fields.
2032 GenInstrRegister(SPECIAL2, rs, rd, rd, 0, CLZ);
2033 } else {
2034 GenInstrRegister(SPECIAL, rs, zero_reg, rd, 1, CLZ_R6);
2035 }
Steve Block44f0eee2011-05-26 01:26:41 +01002036}
2037
2038
2039void Assembler::ins_(Register rt, Register rs, uint16_t pos, uint16_t size) {
2040 // Should be called via MacroAssembler::Ins.
2041 // Ins instr has 'rt' field as dest, and two uint5: msb, lsb.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002042 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
Steve Block44f0eee2011-05-26 01:26:41 +01002043 GenInstrRegister(SPECIAL3, rs, rt, pos + size - 1, pos, INS);
2044}
2045
2046
2047void Assembler::ext_(Register rt, Register rs, uint16_t pos, uint16_t size) {
2048 // Should be called via MacroAssembler::Ext.
2049 // Ext instr has 'rt' field as dest, and two uint5: msb, lsb.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002050 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
Steve Block44f0eee2011-05-26 01:26:41 +01002051 GenInstrRegister(SPECIAL3, rs, rt, size - 1, pos, EXT);
2052}
2053
2054
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002055void Assembler::bitswap(Register rd, Register rt) {
2056 DCHECK(IsMipsArchVariant(kMips32r6));
2057 GenInstrRegister(SPECIAL3, zero_reg, rt, rd, 0, BSHFL);
2058}
2059
2060
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002061void Assembler::pref(int32_t hint, const MemOperand& rs) {
2062 DCHECK(!IsMipsArchVariant(kLoongson));
2063 DCHECK(is_uint5(hint) && is_uint16(rs.offset_));
2064 Instr instr = PREF | (rs.rm().code() << kRsShift) | (hint << kRtShift)
2065 | (rs.offset_);
2066 emit(instr);
2067}
2068
2069
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002070void Assembler::align(Register rd, Register rs, Register rt, uint8_t bp) {
2071 DCHECK(IsMipsArchVariant(kMips32r6));
2072 DCHECK(is_uint3(bp));
2073 uint16_t sa = (ALIGN << kBp2Bits) | bp;
2074 GenInstrRegister(SPECIAL3, rs, rt, rd, sa, BSHFL);
2075}
2076
2077
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002078// --------Coprocessor-instructions----------------
Andrei Popescu31002712010-02-23 13:46:05 +00002079
2080// Load, store, move.
2081void Assembler::lwc1(FPURegister fd, const MemOperand& src) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002082 if (is_int16(src.offset_)) {
2083 GenInstrImmediate(LWC1, src.rm(), fd, src.offset_);
2084 } else { // Offset > 16 bits, use multiple instructions to load.
2085 LoadRegPlusOffsetToAt(src);
2086 GenInstrImmediate(LWC1, at, fd, 0);
2087 }
Andrei Popescu31002712010-02-23 13:46:05 +00002088}
2089
2090
2091void Assembler::ldc1(FPURegister fd, const MemOperand& src) {
Steve Block44f0eee2011-05-26 01:26:41 +01002092 // Workaround for non-8-byte alignment of HeapNumber, convert 64-bit
2093 // load to two 32-bit loads.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002094 DCHECK(!src.rm().is(at));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002095 if (IsFp64Mode()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002096 if (is_int16(src.offset_) && is_int16(src.offset_ + kIntSize)) {
2097 GenInstrImmediate(LWC1, src.rm(), fd,
2098 src.offset_ + Register::kMantissaOffset);
2099 GenInstrImmediate(LW, src.rm(), at,
2100 src.offset_ + Register::kExponentOffset);
2101 mthc1(at, fd);
2102 } else { // Offset > 16 bits, use multiple instructions to load.
2103 LoadRegPlusOffsetToAt(src);
2104 GenInstrImmediate(LWC1, at, fd, Register::kMantissaOffset);
2105 GenInstrImmediate(LW, at, at, Register::kExponentOffset);
2106 mthc1(at, fd);
2107 }
2108 } else { // fp32 mode.
2109 if (is_int16(src.offset_) && is_int16(src.offset_ + kIntSize)) {
2110 GenInstrImmediate(LWC1, src.rm(), fd,
2111 src.offset_ + Register::kMantissaOffset);
2112 FPURegister nextfpreg;
2113 nextfpreg.setcode(fd.code() + 1);
2114 GenInstrImmediate(LWC1, src.rm(), nextfpreg,
2115 src.offset_ + Register::kExponentOffset);
2116 } else { // Offset > 16 bits, use multiple instructions to load.
2117 LoadRegPlusOffsetToAt(src);
2118 GenInstrImmediate(LWC1, at, fd, Register::kMantissaOffset);
2119 FPURegister nextfpreg;
2120 nextfpreg.setcode(fd.code() + 1);
2121 GenInstrImmediate(LWC1, at, nextfpreg, Register::kExponentOffset);
2122 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002123 }
Andrei Popescu31002712010-02-23 13:46:05 +00002124}
2125
2126
2127void Assembler::swc1(FPURegister fd, const MemOperand& src) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002128 if (is_int16(src.offset_)) {
2129 GenInstrImmediate(SWC1, src.rm(), fd, src.offset_);
2130 } else { // Offset > 16 bits, use multiple instructions to load.
2131 LoadRegPlusOffsetToAt(src);
2132 GenInstrImmediate(SWC1, at, fd, 0);
2133 }
Andrei Popescu31002712010-02-23 13:46:05 +00002134}
2135
2136
2137void Assembler::sdc1(FPURegister fd, const MemOperand& src) {
Steve Block44f0eee2011-05-26 01:26:41 +01002138 // Workaround for non-8-byte alignment of HeapNumber, convert 64-bit
2139 // store to two 32-bit stores.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002140 DCHECK(!src.rm().is(at));
2141 DCHECK(!src.rm().is(t8));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002142 if (IsFp64Mode()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002143 if (is_int16(src.offset_) && is_int16(src.offset_ + kIntSize)) {
2144 GenInstrImmediate(SWC1, src.rm(), fd,
2145 src.offset_ + Register::kMantissaOffset);
2146 mfhc1(at, fd);
2147 GenInstrImmediate(SW, src.rm(), at,
2148 src.offset_ + Register::kExponentOffset);
2149 } else { // Offset > 16 bits, use multiple instructions to load.
2150 LoadRegPlusOffsetToAt(src);
2151 GenInstrImmediate(SWC1, at, fd, Register::kMantissaOffset);
2152 mfhc1(t8, fd);
2153 GenInstrImmediate(SW, at, t8, Register::kExponentOffset);
2154 }
2155 } else { // fp32 mode.
2156 if (is_int16(src.offset_) && is_int16(src.offset_ + kIntSize)) {
2157 GenInstrImmediate(SWC1, src.rm(), fd,
2158 src.offset_ + Register::kMantissaOffset);
2159 FPURegister nextfpreg;
2160 nextfpreg.setcode(fd.code() + 1);
2161 GenInstrImmediate(SWC1, src.rm(), nextfpreg,
2162 src.offset_ + Register::kExponentOffset);
2163 } else { // Offset > 16 bits, use multiple instructions to load.
2164 LoadRegPlusOffsetToAt(src);
2165 GenInstrImmediate(SWC1, at, fd, Register::kMantissaOffset);
2166 FPURegister nextfpreg;
2167 nextfpreg.setcode(fd.code() + 1);
2168 GenInstrImmediate(SWC1, at, nextfpreg, 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