blob: f95323b41fa64b5128468aaa6f2d93b38a93520b [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
Ben Murdochc5610432016-08-08 18:44:38 +0100192Address RelocInfo::wasm_memory_reference() {
193 DCHECK(IsWasmMemoryReference(rmode_));
194 return Assembler::target_address_at(pc_, host_);
195}
196
197uint32_t RelocInfo::wasm_memory_size_reference() {
198 DCHECK(IsWasmMemorySizeReference(rmode_));
199 return reinterpret_cast<uint32_t>(Assembler::target_address_at(pc_, host_));
200}
201
202void RelocInfo::update_wasm_memory_reference(
203 Address old_base, Address new_base, uint32_t old_size, uint32_t new_size,
204 ICacheFlushMode icache_flush_mode) {
205 DCHECK(IsWasmMemoryReference(rmode_) || IsWasmMemorySizeReference(rmode_));
206 if (IsWasmMemoryReference(rmode_)) {
207 Address updated_memory_reference;
208 DCHECK(old_base <= wasm_memory_reference() &&
209 wasm_memory_reference() < old_base + old_size);
210 updated_memory_reference = new_base + (wasm_memory_reference() - old_base);
211 DCHECK(new_base <= updated_memory_reference &&
212 updated_memory_reference < new_base + new_size);
213 Assembler::set_target_address_at(
214 isolate_, pc_, host_, updated_memory_reference, icache_flush_mode);
215 } else if (IsWasmMemorySizeReference(rmode_)) {
216 uint32_t updated_size_reference;
217 DCHECK(wasm_memory_size_reference() <= old_size);
218 updated_size_reference =
219 new_size + (wasm_memory_size_reference() - old_size);
220 DCHECK(updated_size_reference <= new_size);
221 Assembler::set_target_address_at(
222 isolate_, pc_, host_, reinterpret_cast<Address>(updated_size_reference),
223 icache_flush_mode);
224 } else {
225 UNREACHABLE();
226 }
227}
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000228
Andrei Popescu31002712010-02-23 13:46:05 +0000229// -----------------------------------------------------------------------------
230// Implementation of Operand and MemOperand.
231// See assembler-mips-inl.h for inlined constructors.
232
233Operand::Operand(Handle<Object> handle) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000234 AllowDeferredHandleDereference using_raw_address;
Andrei Popescu31002712010-02-23 13:46:05 +0000235 rm_ = no_reg;
236 // Verify all Objects referred by code are NOT in new space.
237 Object* obj = *handle;
Andrei Popescu31002712010-02-23 13:46:05 +0000238 if (obj->IsHeapObject()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000239 DCHECK(!HeapObject::cast(obj)->GetHeap()->InNewSpace(obj));
Andrei Popescu31002712010-02-23 13:46:05 +0000240 imm32_ = reinterpret_cast<intptr_t>(handle.location());
241 rmode_ = RelocInfo::EMBEDDED_OBJECT;
242 } else {
243 // No relocation needed.
244 imm32_ = reinterpret_cast<intptr_t>(obj);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000245 rmode_ = RelocInfo::NONE32;
Andrei Popescu31002712010-02-23 13:46:05 +0000246 }
247}
248
Steve Block44f0eee2011-05-26 01:26:41 +0100249
250MemOperand::MemOperand(Register rm, int32_t offset) : Operand(rm) {
Andrei Popescu31002712010-02-23 13:46:05 +0000251 offset_ = offset;
252}
253
254
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000255MemOperand::MemOperand(Register rm, int32_t unit, int32_t multiplier,
256 OffsetAddend offset_addend) : Operand(rm) {
257 offset_ = unit * multiplier + offset_addend;
258}
259
260
Andrei Popescu31002712010-02-23 13:46:05 +0000261// -----------------------------------------------------------------------------
Steve Block44f0eee2011-05-26 01:26:41 +0100262// Specific instructions, constants, and masks.
Andrei Popescu31002712010-02-23 13:46:05 +0000263
Steve Block44f0eee2011-05-26 01:26:41 +0100264static const int kNegOffset = 0x00008000;
265// addiu(sp, sp, 4) aka Pop() operation or part of Pop(r)
266// operations as post-increment of sp.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000267const Instr kPopInstruction = ADDIU | (Register::kCode_sp << kRsShift) |
268 (Register::kCode_sp << kRtShift) |
269 (kPointerSize & kImm16Mask); // NOLINT
Steve Block44f0eee2011-05-26 01:26:41 +0100270// addiu(sp, sp, -4) part of Push(r) operation as pre-decrement of sp.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000271const Instr kPushInstruction = ADDIU | (Register::kCode_sp << kRsShift) |
272 (Register::kCode_sp << kRtShift) |
273 (-kPointerSize & kImm16Mask); // NOLINT
Steve Block44f0eee2011-05-26 01:26:41 +0100274// sw(r, MemOperand(sp, 0))
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000275const Instr kPushRegPattern =
276 SW | (Register::kCode_sp << kRsShift) | (0 & kImm16Mask); // NOLINT
Steve Block44f0eee2011-05-26 01:26:41 +0100277// lw(r, MemOperand(sp, 0))
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000278const Instr kPopRegPattern =
279 LW | (Register::kCode_sp << kRsShift) | (0 & kImm16Mask); // NOLINT
Andrei Popescu31002712010-02-23 13:46:05 +0000280
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000281const Instr kLwRegFpOffsetPattern =
282 LW | (Register::kCode_fp << kRsShift) | (0 & kImm16Mask); // NOLINT
Steve Block44f0eee2011-05-26 01:26:41 +0100283
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000284const Instr kSwRegFpOffsetPattern =
285 SW | (Register::kCode_fp << kRsShift) | (0 & kImm16Mask); // NOLINT
Steve Block44f0eee2011-05-26 01:26:41 +0100286
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000287const Instr kLwRegFpNegOffsetPattern = LW | (Register::kCode_fp << kRsShift) |
288 (kNegOffset & kImm16Mask); // NOLINT
Steve Block44f0eee2011-05-26 01:26:41 +0100289
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000290const Instr kSwRegFpNegOffsetPattern = SW | (Register::kCode_fp << kRsShift) |
291 (kNegOffset & kImm16Mask); // NOLINT
Steve Block44f0eee2011-05-26 01:26:41 +0100292// A mask for the Rt register for push, pop, lw, sw instructions.
293const Instr kRtMask = kRtFieldMask;
294const Instr kLwSwInstrTypeMask = 0xffe00000;
295const Instr kLwSwInstrArgumentMask = ~kLwSwInstrTypeMask;
296const Instr kLwSwOffsetMask = kImm16Mask;
297
298
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000299Assembler::Assembler(Isolate* isolate, void* buffer, int buffer_size)
300 : AssemblerBase(isolate, buffer, buffer_size),
301 recorded_ast_id_(TypeFeedbackId::None()),
302 positions_recorder_(this) {
303 reloc_info_writer.Reposition(buffer_ + buffer_size_, pc_);
Steve Block44f0eee2011-05-26 01:26:41 +0100304
305 last_trampoline_pool_end_ = 0;
306 no_trampoline_pool_before_ = 0;
307 trampoline_pool_blocked_nesting_ = 0;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000308 // We leave space (16 * kTrampolineSlotsSize)
309 // for BlockTrampolinePoolScope buffer.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000310 next_buffer_check_ = FLAG_force_long_branches
311 ? kMaxInt : kMaxBranchOffset - kTrampolineSlotsSize * 16;
Ben Murdoch257744e2011-11-30 15:57:28 +0000312 internal_trampoline_exception_ = false;
313 last_bound_pos_ = 0;
314
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000315 trampoline_emitted_ = FLAG_force_long_branches;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000316 unbound_labels_count_ = 0;
317 block_buffer_growth_ = false;
318
319 ClearRecordedAstId();
Andrei Popescu31002712010-02-23 13:46:05 +0000320}
321
322
Andrei Popescu31002712010-02-23 13:46:05 +0000323void Assembler::GetCode(CodeDesc* desc) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100324 EmitForbiddenSlotInstruction();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000325 DCHECK(pc_ <= reloc_info_writer.pos()); // No overlap.
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100326 // Set up code descriptor.
Andrei Popescu31002712010-02-23 13:46:05 +0000327 desc->buffer = buffer_;
328 desc->buffer_size = buffer_size_;
329 desc->instr_size = pc_offset();
330 desc->reloc_size = (buffer_ + buffer_size_) - reloc_info_writer.pos();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000331 desc->origin = this;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000332 desc->constant_pool_size = 0;
Andrei Popescu31002712010-02-23 13:46:05 +0000333}
334
335
Steve Block44f0eee2011-05-26 01:26:41 +0100336void Assembler::Align(int m) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000337 DCHECK(m >= 4 && base::bits::IsPowerOfTwo32(m));
Ben Murdoch097c5b22016-05-18 11:27:45 +0100338 EmitForbiddenSlotInstruction();
Steve Block44f0eee2011-05-26 01:26:41 +0100339 while ((pc_offset() & (m - 1)) != 0) {
340 nop();
341 }
342}
343
344
345void Assembler::CodeTargetAlign() {
346 // No advantage to aligning branch/call targets to more than
347 // single instruction, that I am aware of.
348 Align(4);
349}
350
351
Ben Murdoch257744e2011-11-30 15:57:28 +0000352Register Assembler::GetRtReg(Instr instr) {
Steve Block44f0eee2011-05-26 01:26:41 +0100353 Register rt;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000354 rt.reg_code = (instr & kRtFieldMask) >> kRtShift;
Steve Block44f0eee2011-05-26 01:26:41 +0100355 return rt;
356}
357
358
Ben Murdoch257744e2011-11-30 15:57:28 +0000359Register Assembler::GetRsReg(Instr instr) {
360 Register rs;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000361 rs.reg_code = (instr & kRsFieldMask) >> kRsShift;
Ben Murdoch257744e2011-11-30 15:57:28 +0000362 return rs;
363}
364
365
366Register Assembler::GetRdReg(Instr instr) {
367 Register rd;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000368 rd.reg_code = (instr & kRdFieldMask) >> kRdShift;
Ben Murdoch257744e2011-11-30 15:57:28 +0000369 return rd;
370}
371
372
373uint32_t Assembler::GetRt(Instr instr) {
374 return (instr & kRtFieldMask) >> kRtShift;
375}
376
377
378uint32_t Assembler::GetRtField(Instr instr) {
379 return instr & kRtFieldMask;
380}
381
382
383uint32_t Assembler::GetRs(Instr instr) {
384 return (instr & kRsFieldMask) >> kRsShift;
385}
386
387
388uint32_t Assembler::GetRsField(Instr instr) {
389 return instr & kRsFieldMask;
390}
391
392
393uint32_t Assembler::GetRd(Instr instr) {
394 return (instr & kRdFieldMask) >> kRdShift;
395}
396
397
398uint32_t Assembler::GetRdField(Instr instr) {
399 return instr & kRdFieldMask;
400}
401
402
403uint32_t Assembler::GetSa(Instr instr) {
404 return (instr & kSaFieldMask) >> kSaShift;
405}
406
407
408uint32_t Assembler::GetSaField(Instr instr) {
409 return instr & kSaFieldMask;
410}
411
412
413uint32_t Assembler::GetOpcodeField(Instr instr) {
414 return instr & kOpcodeMask;
415}
416
417
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000418uint32_t Assembler::GetFunction(Instr instr) {
419 return (instr & kFunctionFieldMask) >> kFunctionShift;
420}
421
422
423uint32_t Assembler::GetFunctionField(Instr instr) {
424 return instr & kFunctionFieldMask;
425}
426
427
Ben Murdoch257744e2011-11-30 15:57:28 +0000428uint32_t Assembler::GetImmediate16(Instr instr) {
429 return instr & kImm16Mask;
430}
431
432
433uint32_t Assembler::GetLabelConst(Instr instr) {
434 return instr & ~kImm16Mask;
435}
436
437
Steve Block44f0eee2011-05-26 01:26:41 +0100438bool Assembler::IsPop(Instr instr) {
439 return (instr & ~kRtMask) == kPopRegPattern;
440}
441
442
443bool Assembler::IsPush(Instr instr) {
444 return (instr & ~kRtMask) == kPushRegPattern;
445}
446
447
448bool Assembler::IsSwRegFpOffset(Instr instr) {
449 return ((instr & kLwSwInstrTypeMask) == kSwRegFpOffsetPattern);
450}
451
452
453bool Assembler::IsLwRegFpOffset(Instr instr) {
454 return ((instr & kLwSwInstrTypeMask) == kLwRegFpOffsetPattern);
455}
456
457
458bool Assembler::IsSwRegFpNegOffset(Instr instr) {
459 return ((instr & (kLwSwInstrTypeMask | kNegOffset)) ==
460 kSwRegFpNegOffsetPattern);
461}
462
463
464bool Assembler::IsLwRegFpNegOffset(Instr instr) {
465 return ((instr & (kLwSwInstrTypeMask | kNegOffset)) ==
466 kLwRegFpNegOffsetPattern);
467}
468
469
Andrei Popescu31002712010-02-23 13:46:05 +0000470// Labels refer to positions in the (to be) generated code.
471// There are bound, linked, and unused labels.
472//
473// Bound labels refer to known positions in the already
474// generated code. pos() is the position the label refers to.
475//
476// Linked labels refer to unknown positions in the code
477// to be generated; pos() is the position of the last
478// instruction using the label.
479
Steve Block44f0eee2011-05-26 01:26:41 +0100480// The link chain is terminated by a value in the instruction of -1,
481// which is an otherwise illegal value (branch -1 is inf loop).
482// The instruction 16-bit offset field addresses 32-bit words, but in
483// code is conv to an 18-bit value addressing bytes, hence the -4 value.
Andrei Popescu31002712010-02-23 13:46:05 +0000484
Andrei Popescu31002712010-02-23 13:46:05 +0000485const int kEndOfChain = -4;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000486// Determines the end of the Jump chain (a subset of the label link chain).
487const int kEndOfJumpChain = 0;
Andrei Popescu31002712010-02-23 13:46:05 +0000488
Steve Block44f0eee2011-05-26 01:26:41 +0100489
490bool Assembler::IsBranch(Instr instr) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000491 uint32_t opcode = GetOpcodeField(instr);
492 uint32_t rt_field = GetRtField(instr);
493 uint32_t rs_field = GetRsField(instr);
Andrei Popescu31002712010-02-23 13:46:05 +0000494 // Checks if the instruction is a branch.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000495 bool isBranch =
496 opcode == BEQ || opcode == BNE || opcode == BLEZ || opcode == BGTZ ||
497 opcode == BEQL || opcode == BNEL || opcode == BLEZL || opcode == BGTZL ||
Andrei Popescu31002712010-02-23 13:46:05 +0000498 (opcode == REGIMM && (rt_field == BLTZ || rt_field == BGEZ ||
499 rt_field == BLTZAL || rt_field == BGEZAL)) ||
Steve Block44f0eee2011-05-26 01:26:41 +0100500 (opcode == COP1 && rs_field == BC1) || // Coprocessor branch.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000501 (opcode == COP1 && rs_field == BC1EQZ) ||
502 (opcode == COP1 && rs_field == BC1NEZ);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000503 if (!isBranch && IsMipsArchVariant(kMips32r6)) {
504 // All the 3 variants of POP10 (BOVC, BEQC, BEQZALC) and
505 // POP30 (BNVC, BNEC, BNEZALC) are branch ops.
506 isBranch |= opcode == POP10 || opcode == POP30 || opcode == BC ||
507 opcode == BALC ||
508 (opcode == POP66 && rs_field != 0) || // BEQZC
509 (opcode == POP76 && rs_field != 0); // BNEZC
510 }
511 return isBranch;
512}
513
514
515bool Assembler::IsBc(Instr instr) {
516 uint32_t opcode = GetOpcodeField(instr);
517 // Checks if the instruction is a BC or BALC.
518 return opcode == BC || opcode == BALC;
519}
520
521
522bool Assembler::IsBzc(Instr instr) {
523 uint32_t opcode = GetOpcodeField(instr);
524 // Checks if the instruction is BEQZC or BNEZC.
525 return (opcode == POP66 && GetRsField(instr) != 0) ||
526 (opcode == POP76 && GetRsField(instr) != 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000527}
528
529
530bool Assembler::IsEmittedConstant(Instr instr) {
531 uint32_t label_constant = GetLabelConst(instr);
532 return label_constant == 0; // Emitted label const in reg-exp engine.
Steve Block44f0eee2011-05-26 01:26:41 +0100533}
534
535
Ben Murdoch257744e2011-11-30 15:57:28 +0000536bool Assembler::IsBeq(Instr instr) {
537 return GetOpcodeField(instr) == BEQ;
538}
539
540
541bool Assembler::IsBne(Instr instr) {
542 return GetOpcodeField(instr) == BNE;
543}
544
545
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000546bool Assembler::IsBeqzc(Instr instr) {
547 uint32_t opcode = GetOpcodeField(instr);
548 return opcode == POP66 && GetRsField(instr) != 0;
549}
550
551
552bool Assembler::IsBnezc(Instr instr) {
553 uint32_t opcode = GetOpcodeField(instr);
554 return opcode == POP76 && GetRsField(instr) != 0;
555}
556
557
558bool Assembler::IsBeqc(Instr instr) {
559 uint32_t opcode = GetOpcodeField(instr);
560 uint32_t rs = GetRsField(instr);
561 uint32_t rt = GetRtField(instr);
562 return opcode == POP10 && rs != 0 && rs < rt; // && rt != 0
563}
564
565
566bool Assembler::IsBnec(Instr instr) {
567 uint32_t opcode = GetOpcodeField(instr);
568 uint32_t rs = GetRsField(instr);
569 uint32_t rt = GetRtField(instr);
570 return opcode == POP30 && rs != 0 && rs < rt; // && rt != 0
571}
572
Ben Murdochda12d292016-06-02 14:46:10 +0100573bool Assembler::IsJicOrJialc(Instr instr) {
574 uint32_t opcode = GetOpcodeField(instr);
575 uint32_t rs = GetRsField(instr);
576 return (opcode == POP66 || opcode == POP76) && rs == 0;
577}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000578
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000579bool Assembler::IsJump(Instr instr) {
580 uint32_t opcode = GetOpcodeField(instr);
581 uint32_t rt_field = GetRtField(instr);
582 uint32_t rd_field = GetRdField(instr);
583 uint32_t function_field = GetFunctionField(instr);
584 // Checks if the instruction is a jump.
585 return opcode == J || opcode == JAL ||
586 (opcode == SPECIAL && rt_field == 0 &&
587 ((function_field == JALR) || (rd_field == 0 && (function_field == JR))));
588}
589
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000590bool Assembler::IsJ(Instr instr) {
591 uint32_t opcode = GetOpcodeField(instr);
592 // Checks if the instruction is a jump.
593 return opcode == J;
594}
595
596
Ben Murdoch589d6972011-11-30 16:04:58 +0000597bool Assembler::IsJal(Instr instr) {
598 return GetOpcodeField(instr) == JAL;
599}
600
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000601
Ben Murdoch589d6972011-11-30 16:04:58 +0000602bool Assembler::IsJr(Instr instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000603 if (!IsMipsArchVariant(kMips32r6)) {
604 return GetOpcodeField(instr) == SPECIAL && GetFunctionField(instr) == JR;
605 } else {
606 return GetOpcodeField(instr) == SPECIAL &&
607 GetRdField(instr) == 0 && GetFunctionField(instr) == JALR;
608 }
Ben Murdoch589d6972011-11-30 16:04:58 +0000609}
610
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000611
Ben Murdoch589d6972011-11-30 16:04:58 +0000612bool Assembler::IsJalr(Instr instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000613 return GetOpcodeField(instr) == SPECIAL &&
614 GetRdField(instr) != 0 && GetFunctionField(instr) == JALR;
Ben Murdoch589d6972011-11-30 16:04:58 +0000615}
616
617
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000618bool Assembler::IsLui(Instr instr) {
619 uint32_t opcode = GetOpcodeField(instr);
620 // Checks if the instruction is a load upper immediate.
621 return opcode == LUI;
622}
623
624
625bool Assembler::IsOri(Instr instr) {
626 uint32_t opcode = GetOpcodeField(instr);
627 // Checks if the instruction is a load upper immediate.
628 return opcode == ORI;
629}
630
631
Steve Block44f0eee2011-05-26 01:26:41 +0100632bool Assembler::IsNop(Instr instr, unsigned int type) {
633 // See Assembler::nop(type).
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000634 DCHECK(type < 32);
Ben Murdoch257744e2011-11-30 15:57:28 +0000635 uint32_t opcode = GetOpcodeField(instr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000636 uint32_t function = GetFunctionField(instr);
Ben Murdoch257744e2011-11-30 15:57:28 +0000637 uint32_t rt = GetRt(instr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000638 uint32_t rd = GetRd(instr);
Ben Murdoch257744e2011-11-30 15:57:28 +0000639 uint32_t sa = GetSa(instr);
Steve Block44f0eee2011-05-26 01:26:41 +0100640
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000641 // Traditional mips nop == sll(zero_reg, zero_reg, 0)
642 // When marking non-zero type, use sll(zero_reg, at, type)
643 // to avoid use of mips ssnop and ehb special encodings
644 // of the sll instruction.
Steve Block44f0eee2011-05-26 01:26:41 +0100645
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000646 Register nop_rt_reg = (type == 0) ? zero_reg : at;
647 bool ret = (opcode == SPECIAL && function == SLL &&
648 rd == static_cast<uint32_t>(ToNumber(zero_reg)) &&
649 rt == static_cast<uint32_t>(ToNumber(nop_rt_reg)) &&
Steve Block44f0eee2011-05-26 01:26:41 +0100650 sa == type);
651
652 return ret;
653}
654
655
656int32_t Assembler::GetBranchOffset(Instr instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000657 DCHECK(IsBranch(instr));
658 return (static_cast<int16_t>(instr & kImm16Mask)) << 2;
Steve Block44f0eee2011-05-26 01:26:41 +0100659}
660
661
662bool Assembler::IsLw(Instr instr) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000663 return (static_cast<uint32_t>(instr & kOpcodeMask) == LW);
Steve Block44f0eee2011-05-26 01:26:41 +0100664}
665
666
667int16_t Assembler::GetLwOffset(Instr instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000668 DCHECK(IsLw(instr));
Steve Block44f0eee2011-05-26 01:26:41 +0100669 return ((instr & kImm16Mask));
670}
671
672
673Instr Assembler::SetLwOffset(Instr instr, int16_t offset) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000674 DCHECK(IsLw(instr));
Steve Block44f0eee2011-05-26 01:26:41 +0100675
676 // We actually create a new lw instruction based on the original one.
677 Instr temp_instr = LW | (instr & kRsFieldMask) | (instr & kRtFieldMask)
678 | (offset & kImm16Mask);
679
680 return temp_instr;
681}
682
683
684bool Assembler::IsSw(Instr instr) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000685 return (static_cast<uint32_t>(instr & kOpcodeMask) == SW);
Steve Block44f0eee2011-05-26 01:26:41 +0100686}
687
688
689Instr Assembler::SetSwOffset(Instr instr, int16_t offset) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000690 DCHECK(IsSw(instr));
Steve Block44f0eee2011-05-26 01:26:41 +0100691 return ((instr & ~kImm16Mask) | (offset & kImm16Mask));
692}
693
694
695bool Assembler::IsAddImmediate(Instr instr) {
696 return ((instr & kOpcodeMask) == ADDIU);
697}
698
699
700Instr Assembler::SetAddImmediateOffset(Instr instr, int16_t offset) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000701 DCHECK(IsAddImmediate(instr));
Steve Block44f0eee2011-05-26 01:26:41 +0100702 return ((instr & ~kImm16Mask) | (offset & kImm16Mask));
Andrei Popescu31002712010-02-23 13:46:05 +0000703}
704
705
Ben Murdoch257744e2011-11-30 15:57:28 +0000706bool Assembler::IsAndImmediate(Instr instr) {
707 return GetOpcodeField(instr) == ANDI;
708}
709
710
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000711static Assembler::OffsetSize OffsetSizeInBits(Instr instr) {
712 if (IsMipsArchVariant(kMips32r6)) {
713 if (Assembler::IsBc(instr)) {
714 return Assembler::OffsetSize::kOffset26;
715 } else if (Assembler::IsBzc(instr)) {
716 return Assembler::OffsetSize::kOffset21;
717 }
718 }
719 return Assembler::OffsetSize::kOffset16;
720}
721
722
723static inline int32_t AddBranchOffset(int pos, Instr instr) {
724 int bits = OffsetSizeInBits(instr);
725 const int32_t mask = (1 << bits) - 1;
726 bits = 32 - bits;
727
728 // Do NOT change this to <<2. We rely on arithmetic shifts here, assuming
729 // the compiler uses arithmetic shifts for signed integers.
730 int32_t imm = ((instr & mask) << bits) >> (bits - 2);
731
732 if (imm == kEndOfChain) {
733 // EndOfChain sentinel is returned directly, not relative to pc or pos.
734 return kEndOfChain;
735 } else {
736 return pos + Assembler::kBranchPCOffset + imm;
737 }
738}
739
Ben Murdochda12d292016-06-02 14:46:10 +0100740uint32_t Assembler::CreateTargetAddress(Instr instr_lui, Instr instr_jic) {
741 DCHECK(IsLui(instr_lui) && IsJicOrJialc(instr_jic));
742 int16_t jic_offset = GetImmediate16(instr_jic);
743 int16_t lui_offset = GetImmediate16(instr_lui);
744
745 if (jic_offset < 0) {
746 lui_offset += kImm16Mask;
747 }
748 uint32_t lui_offset_u = (static_cast<uint32_t>(lui_offset)) << kLuiShift;
749 uint32_t jic_offset_u = static_cast<uint32_t>(jic_offset) & kImm16Mask;
750
751 return lui_offset_u | jic_offset_u;
752}
753
754// Use just lui and jic instructions. Insert lower part of the target address in
755// jic offset part. Since jic sign-extends offset and then add it with register,
756// before that addition, difference between upper part of the target address and
757// upper part of the sign-extended offset (0xffff or 0x0000), will be inserted
758// in jic register with lui instruction.
759void Assembler::UnpackTargetAddress(uint32_t address, int16_t& lui_offset,
760 int16_t& jic_offset) {
761 lui_offset = (address & kHiMask) >> kLuiShift;
762 jic_offset = address & kLoMask;
763
764 if (jic_offset < 0) {
765 lui_offset -= kImm16Mask;
766 }
767}
768
769void Assembler::UnpackTargetAddressUnsigned(uint32_t address,
770 uint32_t& lui_offset,
771 uint32_t& jic_offset) {
772 int16_t lui_offset16 = (address & kHiMask) >> kLuiShift;
773 int16_t jic_offset16 = address & kLoMask;
774
775 if (jic_offset16 < 0) {
776 lui_offset16 -= kImm16Mask;
777 }
778 lui_offset = static_cast<uint32_t>(lui_offset16) & kImm16Mask;
779 jic_offset = static_cast<uint32_t>(jic_offset16) & kImm16Mask;
780}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000781
782int Assembler::target_at(int pos, bool is_internal) {
Andrei Popescu31002712010-02-23 13:46:05 +0000783 Instr instr = instr_at(pos);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000784 if (is_internal) {
785 if (instr == 0) {
786 return kEndOfChain;
787 } else {
788 int32_t instr_address = reinterpret_cast<int32_t>(buffer_ + pos);
789 int delta = static_cast<int>(instr_address - instr);
790 DCHECK(pos > delta);
791 return pos - delta;
792 }
793 }
Andrei Popescu31002712010-02-23 13:46:05 +0000794 if ((instr & ~kImm16Mask) == 0) {
795 // Emitted label constant, not part of a branch.
Steve Block44f0eee2011-05-26 01:26:41 +0100796 if (instr == 0) {
797 return kEndOfChain;
798 } else {
799 int32_t imm18 =((instr & static_cast<int32_t>(kImm16Mask)) << 16) >> 14;
800 return (imm18 + pos);
801 }
Andrei Popescu31002712010-02-23 13:46:05 +0000802 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000803 // Check we have a branch or jump instruction.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000804 DCHECK(IsBranch(instr) || IsLui(instr));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000805 if (IsBranch(instr)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000806 return AddBranchOffset(pos, instr);
807 } else {
Ben Murdochda12d292016-06-02 14:46:10 +0100808 Instr instr1 = instr_at(pos + 0 * Assembler::kInstrSize);
809 Instr instr2 = instr_at(pos + 1 * Assembler::kInstrSize);
810 DCHECK(IsOri(instr2) || IsJicOrJialc(instr2));
811 int32_t imm;
812 if (IsJicOrJialc(instr2)) {
813 imm = CreateTargetAddress(instr1, instr2);
814 } else {
815 imm = (instr1 & static_cast<int32_t>(kImm16Mask)) << kLuiShift;
816 imm |= (instr2 & static_cast<int32_t>(kImm16Mask));
817 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000818
819 if (imm == kEndOfJumpChain) {
820 // EndOfChain sentinel is returned directly, not relative to pc or pos.
821 return kEndOfChain;
822 } else {
823 uint32_t instr_address = reinterpret_cast<int32_t>(buffer_ + pos);
824 int32_t delta = instr_address - imm;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000825 DCHECK(pos > delta);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000826 return pos - delta;
827 }
Steve Block44f0eee2011-05-26 01:26:41 +0100828 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000829 return 0;
Andrei Popescu31002712010-02-23 13:46:05 +0000830}
831
832
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000833static inline Instr SetBranchOffset(int32_t pos, int32_t target_pos,
834 Instr instr) {
835 int32_t bits = OffsetSizeInBits(instr);
836 int32_t imm = target_pos - (pos + Assembler::kBranchPCOffset);
837 DCHECK((imm & 3) == 0);
838 imm >>= 2;
839
840 const int32_t mask = (1 << bits) - 1;
841 instr &= ~mask;
842 DCHECK(is_intn(imm, bits));
843
844 return instr | (imm & mask);
845}
846
847
848void Assembler::target_at_put(int32_t pos, int32_t target_pos,
849 bool is_internal) {
Andrei Popescu31002712010-02-23 13:46:05 +0000850 Instr instr = instr_at(pos);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000851
852 if (is_internal) {
853 uint32_t imm = reinterpret_cast<uint32_t>(buffer_) + target_pos;
854 instr_at_put(pos, imm);
855 return;
856 }
Andrei Popescu31002712010-02-23 13:46:05 +0000857 if ((instr & ~kImm16Mask) == 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000858 DCHECK(target_pos == kEndOfChain || target_pos >= 0);
Andrei Popescu31002712010-02-23 13:46:05 +0000859 // Emitted label constant, not part of a branch.
860 // Make label relative to Code* of generated Code object.
861 instr_at_put(pos, target_pos + (Code::kHeaderSize - kHeapObjectTag));
862 return;
863 }
864
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000865 DCHECK(IsBranch(instr) || IsLui(instr));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000866 if (IsBranch(instr)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000867 instr = SetBranchOffset(pos, target_pos, instr);
868 instr_at_put(pos, instr);
869 } else {
Ben Murdochda12d292016-06-02 14:46:10 +0100870 Instr instr1 = instr_at(pos + 0 * Assembler::kInstrSize);
871 Instr instr2 = instr_at(pos + 1 * Assembler::kInstrSize);
872 DCHECK(IsOri(instr2) || IsJicOrJialc(instr2));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000873 uint32_t imm = reinterpret_cast<uint32_t>(buffer_) + target_pos;
874 DCHECK((imm & 3) == 0);
Ben Murdochda12d292016-06-02 14:46:10 +0100875 DCHECK(IsLui(instr1) && (IsJicOrJialc(instr2) || IsOri(instr2)));
876 instr1 &= ~kImm16Mask;
877 instr2 &= ~kImm16Mask;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000878
Ben Murdochda12d292016-06-02 14:46:10 +0100879 if (IsJicOrJialc(instr2)) {
880 uint32_t lui_offset_u, jic_offset_u;
881 UnpackTargetAddressUnsigned(imm, lui_offset_u, jic_offset_u);
882 instr_at_put(pos + 0 * Assembler::kInstrSize, instr1 | lui_offset_u);
883 instr_at_put(pos + 1 * Assembler::kInstrSize, instr2 | jic_offset_u);
884 } else {
885 instr_at_put(pos + 0 * Assembler::kInstrSize,
886 instr1 | ((imm & kHiMask) >> kLuiShift));
887 instr_at_put(pos + 1 * Assembler::kInstrSize,
888 instr2 | (imm & kImm16Mask));
889 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000890 }
Andrei Popescu31002712010-02-23 13:46:05 +0000891}
892
893
894void Assembler::print(Label* L) {
895 if (L->is_unused()) {
896 PrintF("unused label\n");
897 } else if (L->is_bound()) {
898 PrintF("bound label to %d\n", L->pos());
899 } else if (L->is_linked()) {
900 Label l = *L;
901 PrintF("unbound label");
902 while (l.is_linked()) {
903 PrintF("@ %d ", l.pos());
904 Instr instr = instr_at(l.pos());
905 if ((instr & ~kImm16Mask) == 0) {
906 PrintF("value\n");
907 } else {
908 PrintF("%d\n", instr);
909 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000910 next(&l, internal_reference_positions_.find(l.pos()) !=
911 internal_reference_positions_.end());
Andrei Popescu31002712010-02-23 13:46:05 +0000912 }
913 } else {
914 PrintF("label in inconsistent state (pos = %d)\n", L->pos_);
915 }
916}
917
918
919void Assembler::bind_to(Label* L, int pos) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000920 DCHECK(0 <= pos && pos <= pc_offset()); // Must have valid binding position.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000921 int32_t trampoline_pos = kInvalidSlotPos;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000922 bool is_internal = false;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000923 if (L->is_linked() && !trampoline_emitted_) {
924 unbound_labels_count_--;
925 next_buffer_check_ += kTrampolineSlotsSize;
926 }
927
Andrei Popescu31002712010-02-23 13:46:05 +0000928 while (L->is_linked()) {
929 int32_t fixup_pos = L->pos();
Steve Block44f0eee2011-05-26 01:26:41 +0100930 int32_t dist = pos - fixup_pos;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000931 is_internal = internal_reference_positions_.find(fixup_pos) !=
932 internal_reference_positions_.end();
933 next(L, is_internal); // Call next before overwriting link with target at
934 // fixup_pos.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000935 Instr instr = instr_at(fixup_pos);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000936 if (is_internal) {
937 target_at_put(fixup_pos, pos, is_internal);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000938 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000939 if (IsBranch(instr)) {
940 int branch_offset = BranchOffset(instr);
941 if (dist > branch_offset) {
942 if (trampoline_pos == kInvalidSlotPos) {
943 trampoline_pos = get_trampoline_entry(fixup_pos);
944 CHECK(trampoline_pos != kInvalidSlotPos);
945 }
946 CHECK((trampoline_pos - fixup_pos) <= branch_offset);
947 target_at_put(fixup_pos, trampoline_pos, false);
948 fixup_pos = trampoline_pos;
949 dist = pos - fixup_pos;
950 }
951 target_at_put(fixup_pos, pos, false);
952 } else {
953 target_at_put(fixup_pos, pos, false);
954 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000955 }
Andrei Popescu31002712010-02-23 13:46:05 +0000956 }
957 L->bind_to(pos);
958
959 // Keep track of the last bound label so we don't eliminate any instructions
960 // before a bound label.
961 if (pos > last_bound_pos_)
962 last_bound_pos_ = pos;
963}
964
965
Andrei Popescu31002712010-02-23 13:46:05 +0000966void Assembler::bind(Label* L) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000967 DCHECK(!L->is_bound()); // Label can only be bound once.
Andrei Popescu31002712010-02-23 13:46:05 +0000968 bind_to(L, pc_offset());
969}
970
971
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000972void Assembler::next(Label* L, bool is_internal) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000973 DCHECK(L->is_linked());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000974 int link = target_at(L->pos(), is_internal);
Steve Block44f0eee2011-05-26 01:26:41 +0100975 if (link == kEndOfChain) {
Andrei Popescu31002712010-02-23 13:46:05 +0000976 L->Unuse();
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000977 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000978 DCHECK(link >= 0);
Steve Block44f0eee2011-05-26 01:26:41 +0100979 L->link_to(link);
Andrei Popescu31002712010-02-23 13:46:05 +0000980 }
981}
982
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000983
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000984bool Assembler::is_near(Label* L) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000985 DCHECK(L->is_bound());
986 return pc_offset() - L->pos() < kMaxBranchOffset - 4 * kInstrSize;
987}
988
989
990bool Assembler::is_near(Label* L, OffsetSize bits) {
991 if (L == nullptr || !L->is_bound()) return true;
992 return pc_offset() - L->pos() < (1 << (bits + 2 - 1)) - 1 - 5 * kInstrSize;
993}
994
995
996bool Assembler::is_near_branch(Label* L) {
997 DCHECK(L->is_bound());
998 return IsMipsArchVariant(kMips32r6) ? is_near_r6(L) : is_near_pre_r6(L);
999}
1000
1001
1002int Assembler::BranchOffset(Instr instr) {
1003 // At pre-R6 and for other R6 branches the offset is 16 bits.
1004 int bits = OffsetSize::kOffset16;
1005
1006 if (IsMipsArchVariant(kMips32r6)) {
1007 uint32_t opcode = GetOpcodeField(instr);
1008 switch (opcode) {
1009 // Checks BC or BALC.
1010 case BC:
1011 case BALC:
1012 bits = OffsetSize::kOffset26;
1013 break;
1014
1015 // Checks BEQZC or BNEZC.
1016 case POP66:
1017 case POP76:
1018 if (GetRsField(instr) != 0) bits = OffsetSize::kOffset21;
1019 break;
1020 default:
1021 break;
1022 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001023 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001024
1025 return (1 << (bits + 2 - 1)) - 1;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001026}
Andrei Popescu31002712010-02-23 13:46:05 +00001027
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001028
Andrei Popescu31002712010-02-23 13:46:05 +00001029// We have to use a temporary register for things that can be relocated even
1030// if they can be encoded in the MIPS's 16 bits of immediate-offset instruction
1031// space. There is no guarantee that the relocated location can be similarly
1032// encoded.
Steve Block44f0eee2011-05-26 01:26:41 +01001033bool Assembler::MustUseReg(RelocInfo::Mode rmode) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001034 return !RelocInfo::IsNone(rmode);
Andrei Popescu31002712010-02-23 13:46:05 +00001035}
1036
Andrei Popescu31002712010-02-23 13:46:05 +00001037void Assembler::GenInstrRegister(Opcode opcode,
1038 Register rs,
1039 Register rt,
1040 Register rd,
1041 uint16_t sa,
1042 SecondaryField func) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001043 DCHECK(rd.is_valid() && rs.is_valid() && rt.is_valid() && is_uint5(sa));
Andrei Popescu31002712010-02-23 13:46:05 +00001044 Instr instr = opcode | (rs.code() << kRsShift) | (rt.code() << kRtShift)
1045 | (rd.code() << kRdShift) | (sa << kSaShift) | func;
1046 emit(instr);
1047}
1048
1049
1050void Assembler::GenInstrRegister(Opcode opcode,
Steve Block44f0eee2011-05-26 01:26:41 +01001051 Register rs,
1052 Register rt,
1053 uint16_t msb,
1054 uint16_t lsb,
1055 SecondaryField func) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001056 DCHECK(rs.is_valid() && rt.is_valid() && is_uint5(msb) && is_uint5(lsb));
Steve Block44f0eee2011-05-26 01:26:41 +01001057 Instr instr = opcode | (rs.code() << kRsShift) | (rt.code() << kRtShift)
1058 | (msb << kRdShift) | (lsb << kSaShift) | func;
1059 emit(instr);
1060}
1061
1062
1063void Assembler::GenInstrRegister(Opcode opcode,
Andrei Popescu31002712010-02-23 13:46:05 +00001064 SecondaryField fmt,
1065 FPURegister ft,
1066 FPURegister fs,
1067 FPURegister fd,
1068 SecondaryField func) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001069 DCHECK(fd.is_valid() && fs.is_valid() && ft.is_valid());
Steve Block44f0eee2011-05-26 01:26:41 +01001070 Instr instr = opcode | fmt | (ft.code() << kFtShift) | (fs.code() << kFsShift)
1071 | (fd.code() << kFdShift) | func;
Andrei Popescu31002712010-02-23 13:46:05 +00001072 emit(instr);
1073}
1074
1075
1076void Assembler::GenInstrRegister(Opcode opcode,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001077 FPURegister fr,
1078 FPURegister ft,
1079 FPURegister fs,
1080 FPURegister fd,
1081 SecondaryField func) {
1082 DCHECK(fd.is_valid() && fr.is_valid() && fs.is_valid() && ft.is_valid());
1083 Instr instr = opcode | (fr.code() << kFrShift) | (ft.code() << kFtShift)
1084 | (fs.code() << kFsShift) | (fd.code() << kFdShift) | func;
1085 emit(instr);
1086}
1087
1088
1089void Assembler::GenInstrRegister(Opcode opcode,
Andrei Popescu31002712010-02-23 13:46:05 +00001090 SecondaryField fmt,
1091 Register rt,
1092 FPURegister fs,
1093 FPURegister fd,
1094 SecondaryField func) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001095 DCHECK(fd.is_valid() && fs.is_valid() && rt.is_valid());
Andrei Popescu31002712010-02-23 13:46:05 +00001096 Instr instr = opcode | fmt | (rt.code() << kRtShift)
Steve Block44f0eee2011-05-26 01:26:41 +01001097 | (fs.code() << kFsShift) | (fd.code() << kFdShift) | func;
1098 emit(instr);
1099}
1100
1101
1102void Assembler::GenInstrRegister(Opcode opcode,
1103 SecondaryField fmt,
1104 Register rt,
1105 FPUControlRegister fs,
1106 SecondaryField func) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001107 DCHECK(fs.is_valid() && rt.is_valid());
Steve Block44f0eee2011-05-26 01:26:41 +01001108 Instr instr =
1109 opcode | fmt | (rt.code() << kRtShift) | (fs.code() << kFsShift) | func;
Andrei Popescu31002712010-02-23 13:46:05 +00001110 emit(instr);
1111}
1112
1113
1114// Instructions with immediate value.
1115// Registers are in the order of the instruction encoding, from left to right.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001116void Assembler::GenInstrImmediate(Opcode opcode, Register rs, Register rt,
1117 int32_t j,
1118 CompactBranchType is_compact_branch) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001119 DCHECK(rs.is_valid() && rt.is_valid() && (is_int16(j) || is_uint16(j)));
Andrei Popescu31002712010-02-23 13:46:05 +00001120 Instr instr = opcode | (rs.code() << kRsShift) | (rt.code() << kRtShift)
1121 | (j & kImm16Mask);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001122 emit(instr, is_compact_branch);
Andrei Popescu31002712010-02-23 13:46:05 +00001123}
1124
1125
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001126void Assembler::GenInstrImmediate(Opcode opcode, Register rs, SecondaryField SF,
1127 int32_t j,
1128 CompactBranchType is_compact_branch) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001129 DCHECK(rs.is_valid() && (is_int16(j) || is_uint16(j)));
Andrei Popescu31002712010-02-23 13:46:05 +00001130 Instr instr = opcode | (rs.code() << kRsShift) | SF | (j & kImm16Mask);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001131 emit(instr, is_compact_branch);
Andrei Popescu31002712010-02-23 13:46:05 +00001132}
1133
1134
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001135void Assembler::GenInstrImmediate(Opcode opcode, Register rs, FPURegister ft,
1136 int32_t j,
1137 CompactBranchType is_compact_branch) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001138 DCHECK(rs.is_valid() && ft.is_valid() && (is_int16(j) || is_uint16(j)));
Andrei Popescu31002712010-02-23 13:46:05 +00001139 Instr instr = opcode | (rs.code() << kRsShift) | (ft.code() << kFtShift)
1140 | (j & kImm16Mask);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001141 emit(instr, is_compact_branch);
1142}
1143
1144
1145void Assembler::GenInstrImmediate(Opcode opcode, Register rs, int32_t offset21,
1146 CompactBranchType is_compact_branch) {
1147 DCHECK(rs.is_valid() && (is_int21(offset21)));
1148 Instr instr = opcode | (rs.code() << kRsShift) | (offset21 & kImm21Mask);
1149 emit(instr, is_compact_branch);
1150}
1151
1152
1153void Assembler::GenInstrImmediate(Opcode opcode, Register rs,
1154 uint32_t offset21) {
1155 DCHECK(rs.is_valid() && (is_uint21(offset21)));
1156 Instr instr = opcode | (rs.code() << kRsShift) | (offset21 & kImm21Mask);
Andrei Popescu31002712010-02-23 13:46:05 +00001157 emit(instr);
1158}
1159
1160
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001161void Assembler::GenInstrImmediate(Opcode opcode, int32_t offset26,
1162 CompactBranchType is_compact_branch) {
1163 DCHECK(is_int26(offset26));
1164 Instr instr = opcode | (offset26 & kImm26Mask);
1165 emit(instr, is_compact_branch);
1166}
1167
1168
Andrei Popescu31002712010-02-23 13:46:05 +00001169void Assembler::GenInstrJump(Opcode opcode,
Ben Murdoch589d6972011-11-30 16:04:58 +00001170 uint32_t address) {
Steve Block44f0eee2011-05-26 01:26:41 +01001171 BlockTrampolinePoolScope block_trampoline_pool(this);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001172 DCHECK(is_uint26(address));
Andrei Popescu31002712010-02-23 13:46:05 +00001173 Instr instr = opcode | address;
1174 emit(instr);
Steve Block44f0eee2011-05-26 01:26:41 +01001175 BlockTrampolinePoolFor(1); // For associated delay slot.
1176}
1177
1178
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001179// Returns the next free trampoline entry.
1180int32_t Assembler::get_trampoline_entry(int32_t pos) {
Ben Murdoch257744e2011-11-30 15:57:28 +00001181 int32_t trampoline_entry = kInvalidSlotPos;
Steve Block44f0eee2011-05-26 01:26:41 +01001182
Ben Murdoch257744e2011-11-30 15:57:28 +00001183 if (!internal_trampoline_exception_) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001184 if (trampoline_.start() > pos) {
1185 trampoline_entry = trampoline_.take_slot();
Steve Block44f0eee2011-05-26 01:26:41 +01001186 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001187
Ben Murdoch257744e2011-11-30 15:57:28 +00001188 if (kInvalidSlotPos == trampoline_entry) {
1189 internal_trampoline_exception_ = true;
Steve Block44f0eee2011-05-26 01:26:41 +01001190 }
1191 }
1192 return trampoline_entry;
Andrei Popescu31002712010-02-23 13:46:05 +00001193}
1194
1195
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001196uint32_t Assembler::jump_address(Label* L) {
Andrei Popescu31002712010-02-23 13:46:05 +00001197 int32_t target_pos;
Steve Block44f0eee2011-05-26 01:26:41 +01001198
Andrei Popescu31002712010-02-23 13:46:05 +00001199 if (L->is_bound()) {
1200 target_pos = L->pos();
1201 } else {
1202 if (L->is_linked()) {
Steve Block44f0eee2011-05-26 01:26:41 +01001203 target_pos = L->pos(); // L's link.
Steve Block44f0eee2011-05-26 01:26:41 +01001204 L->link_to(pc_offset());
Andrei Popescu31002712010-02-23 13:46:05 +00001205 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01001206 L->link_to(pc_offset());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001207 return kEndOfJumpChain;
1208 }
1209 }
1210
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001211 uint32_t imm = reinterpret_cast<uint32_t>(buffer_) + target_pos;
1212 DCHECK((imm & 3) == 0);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001213
1214 return imm;
1215}
1216
1217
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001218int32_t Assembler::branch_offset_helper(Label* L, OffsetSize bits) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001219 int32_t target_pos;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001220 int32_t pad = IsPrevInstrCompactBranch() ? kInstrSize : 0;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001221
1222 if (L->is_bound()) {
1223 target_pos = L->pos();
1224 } else {
1225 if (L->is_linked()) {
1226 target_pos = L->pos();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001227 L->link_to(pc_offset() + pad);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001228 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001229 L->link_to(pc_offset() + pad);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001230 if (!trampoline_emitted_) {
1231 unbound_labels_count_++;
1232 next_buffer_check_ -= kTrampolineSlotsSize;
1233 }
Steve Block44f0eee2011-05-26 01:26:41 +01001234 return kEndOfChain;
Andrei Popescu31002712010-02-23 13:46:05 +00001235 }
Andrei Popescu31002712010-02-23 13:46:05 +00001236 }
1237
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001238 int32_t offset = target_pos - (pc_offset() + kBranchPCOffset + pad);
1239 DCHECK(is_intn(offset, bits + 2));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001240 DCHECK((offset & 3) == 0);
Steve Block44f0eee2011-05-26 01:26:41 +01001241
Andrei Popescu31002712010-02-23 13:46:05 +00001242 return offset;
1243}
1244
1245
1246void Assembler::label_at_put(Label* L, int at_offset) {
1247 int target_pos;
1248 if (L->is_bound()) {
1249 target_pos = L->pos();
Steve Block44f0eee2011-05-26 01:26:41 +01001250 instr_at_put(at_offset, target_pos + (Code::kHeaderSize - kHeapObjectTag));
Andrei Popescu31002712010-02-23 13:46:05 +00001251 } else {
1252 if (L->is_linked()) {
Steve Block44f0eee2011-05-26 01:26:41 +01001253 target_pos = L->pos(); // L's link.
1254 int32_t imm18 = target_pos - at_offset;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001255 DCHECK((imm18 & 3) == 0);
Steve Block44f0eee2011-05-26 01:26:41 +01001256 int32_t imm16 = imm18 >> 2;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001257 DCHECK(is_int16(imm16));
Steve Block44f0eee2011-05-26 01:26:41 +01001258 instr_at_put(at_offset, (imm16 & kImm16Mask));
Andrei Popescu31002712010-02-23 13:46:05 +00001259 } else {
1260 target_pos = kEndOfChain;
Steve Block44f0eee2011-05-26 01:26:41 +01001261 instr_at_put(at_offset, 0);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001262 if (!trampoline_emitted_) {
1263 unbound_labels_count_++;
1264 next_buffer_check_ -= kTrampolineSlotsSize;
1265 }
Andrei Popescu31002712010-02-23 13:46:05 +00001266 }
1267 L->link_to(at_offset);
Andrei Popescu31002712010-02-23 13:46:05 +00001268 }
1269}
1270
1271
1272//------- Branch and jump instructions --------
1273
1274void Assembler::b(int16_t offset) {
1275 beq(zero_reg, zero_reg, offset);
1276}
1277
1278
1279void Assembler::bal(int16_t offset) {
Steve Block44f0eee2011-05-26 01:26:41 +01001280 positions_recorder()->WriteRecordedPositions();
Andrei Popescu31002712010-02-23 13:46:05 +00001281 bgezal(zero_reg, offset);
1282}
1283
1284
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001285void Assembler::bc(int32_t offset) {
1286 DCHECK(IsMipsArchVariant(kMips32r6));
1287 GenInstrImmediate(BC, offset, CompactBranchType::COMPACT_BRANCH);
1288}
1289
1290
1291void Assembler::balc(int32_t offset) {
1292 DCHECK(IsMipsArchVariant(kMips32r6));
1293 positions_recorder()->WriteRecordedPositions();
1294 GenInstrImmediate(BALC, offset, CompactBranchType::COMPACT_BRANCH);
1295}
1296
1297
Andrei Popescu31002712010-02-23 13:46:05 +00001298void Assembler::beq(Register rs, Register rt, int16_t offset) {
Steve Block44f0eee2011-05-26 01:26:41 +01001299 BlockTrampolinePoolScope block_trampoline_pool(this);
Andrei Popescu31002712010-02-23 13:46:05 +00001300 GenInstrImmediate(BEQ, rs, rt, offset);
Steve Block44f0eee2011-05-26 01:26:41 +01001301 BlockTrampolinePoolFor(1); // For associated delay slot.
Andrei Popescu31002712010-02-23 13:46:05 +00001302}
1303
1304
1305void Assembler::bgez(Register rs, int16_t offset) {
Steve Block44f0eee2011-05-26 01:26:41 +01001306 BlockTrampolinePoolScope block_trampoline_pool(this);
Andrei Popescu31002712010-02-23 13:46:05 +00001307 GenInstrImmediate(REGIMM, rs, BGEZ, offset);
Steve Block44f0eee2011-05-26 01:26:41 +01001308 BlockTrampolinePoolFor(1); // For associated delay slot.
Andrei Popescu31002712010-02-23 13:46:05 +00001309}
1310
1311
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001312void Assembler::bgezc(Register rt, int16_t offset) {
1313 DCHECK(IsMipsArchVariant(kMips32r6));
1314 DCHECK(!(rt.is(zero_reg)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001315 GenInstrImmediate(BLEZL, rt, rt, offset, CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001316}
1317
1318
1319void Assembler::bgeuc(Register rs, Register rt, int16_t offset) {
1320 DCHECK(IsMipsArchVariant(kMips32r6));
1321 DCHECK(!(rs.is(zero_reg)));
1322 DCHECK(!(rt.is(zero_reg)));
1323 DCHECK(rs.code() != rt.code());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001324 GenInstrImmediate(BLEZ, rs, rt, offset, CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001325}
1326
1327
1328void Assembler::bgec(Register rs, Register rt, int16_t offset) {
1329 DCHECK(IsMipsArchVariant(kMips32r6));
1330 DCHECK(!(rs.is(zero_reg)));
1331 DCHECK(!(rt.is(zero_reg)));
1332 DCHECK(rs.code() != rt.code());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001333 GenInstrImmediate(BLEZL, rs, rt, offset, CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001334}
1335
1336
Andrei Popescu31002712010-02-23 13:46:05 +00001337void Assembler::bgezal(Register rs, int16_t offset) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001338 DCHECK(!IsMipsArchVariant(kMips32r6) || rs.is(zero_reg));
Steve Block44f0eee2011-05-26 01:26:41 +01001339 BlockTrampolinePoolScope block_trampoline_pool(this);
1340 positions_recorder()->WriteRecordedPositions();
Andrei Popescu31002712010-02-23 13:46:05 +00001341 GenInstrImmediate(REGIMM, rs, BGEZAL, offset);
Steve Block44f0eee2011-05-26 01:26:41 +01001342 BlockTrampolinePoolFor(1); // For associated delay slot.
Andrei Popescu31002712010-02-23 13:46:05 +00001343}
1344
1345
1346void Assembler::bgtz(Register rs, int16_t offset) {
Steve Block44f0eee2011-05-26 01:26:41 +01001347 BlockTrampolinePoolScope block_trampoline_pool(this);
Andrei Popescu31002712010-02-23 13:46:05 +00001348 GenInstrImmediate(BGTZ, rs, zero_reg, offset);
Steve Block44f0eee2011-05-26 01:26:41 +01001349 BlockTrampolinePoolFor(1); // For associated delay slot.
Andrei Popescu31002712010-02-23 13:46:05 +00001350}
1351
1352
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001353void Assembler::bgtzc(Register rt, int16_t offset) {
1354 DCHECK(IsMipsArchVariant(kMips32r6));
1355 DCHECK(!(rt.is(zero_reg)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001356 GenInstrImmediate(BGTZL, zero_reg, rt, offset,
1357 CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001358}
1359
1360
Andrei Popescu31002712010-02-23 13:46:05 +00001361void Assembler::blez(Register rs, int16_t offset) {
Steve Block44f0eee2011-05-26 01:26:41 +01001362 BlockTrampolinePoolScope block_trampoline_pool(this);
Andrei Popescu31002712010-02-23 13:46:05 +00001363 GenInstrImmediate(BLEZ, rs, zero_reg, offset);
Steve Block44f0eee2011-05-26 01:26:41 +01001364 BlockTrampolinePoolFor(1); // For associated delay slot.
Andrei Popescu31002712010-02-23 13:46:05 +00001365}
1366
1367
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001368void Assembler::blezc(Register rt, int16_t offset) {
1369 DCHECK(IsMipsArchVariant(kMips32r6));
1370 DCHECK(!(rt.is(zero_reg)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001371 GenInstrImmediate(BLEZL, zero_reg, rt, offset,
1372 CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001373}
1374
1375
1376void Assembler::bltzc(Register rt, int16_t offset) {
1377 DCHECK(IsMipsArchVariant(kMips32r6));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001378 DCHECK(!rt.is(zero_reg));
1379 GenInstrImmediate(BGTZL, rt, rt, offset, CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001380}
1381
1382
1383void Assembler::bltuc(Register rs, Register rt, int16_t offset) {
1384 DCHECK(IsMipsArchVariant(kMips32r6));
1385 DCHECK(!(rs.is(zero_reg)));
1386 DCHECK(!(rt.is(zero_reg)));
1387 DCHECK(rs.code() != rt.code());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001388 GenInstrImmediate(BGTZ, rs, rt, offset, CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001389}
1390
1391
1392void Assembler::bltc(Register rs, Register rt, int16_t offset) {
1393 DCHECK(IsMipsArchVariant(kMips32r6));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001394 DCHECK(!rs.is(zero_reg));
1395 DCHECK(!rt.is(zero_reg));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001396 DCHECK(rs.code() != rt.code());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001397 GenInstrImmediate(BGTZL, rs, rt, offset, CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001398}
1399
1400
Andrei Popescu31002712010-02-23 13:46:05 +00001401void Assembler::bltz(Register rs, int16_t offset) {
Steve Block44f0eee2011-05-26 01:26:41 +01001402 BlockTrampolinePoolScope block_trampoline_pool(this);
Andrei Popescu31002712010-02-23 13:46:05 +00001403 GenInstrImmediate(REGIMM, rs, BLTZ, offset);
Steve Block44f0eee2011-05-26 01:26:41 +01001404 BlockTrampolinePoolFor(1); // For associated delay slot.
Andrei Popescu31002712010-02-23 13:46:05 +00001405}
1406
1407
1408void Assembler::bltzal(Register rs, int16_t offset) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001409 DCHECK(!IsMipsArchVariant(kMips32r6) || rs.is(zero_reg));
Steve Block44f0eee2011-05-26 01:26:41 +01001410 BlockTrampolinePoolScope block_trampoline_pool(this);
1411 positions_recorder()->WriteRecordedPositions();
Andrei Popescu31002712010-02-23 13:46:05 +00001412 GenInstrImmediate(REGIMM, rs, BLTZAL, offset);
Steve Block44f0eee2011-05-26 01:26:41 +01001413 BlockTrampolinePoolFor(1); // For associated delay slot.
Andrei Popescu31002712010-02-23 13:46:05 +00001414}
1415
1416
1417void Assembler::bne(Register rs, Register rt, int16_t offset) {
Steve Block44f0eee2011-05-26 01:26:41 +01001418 BlockTrampolinePoolScope block_trampoline_pool(this);
Andrei Popescu31002712010-02-23 13:46:05 +00001419 GenInstrImmediate(BNE, rs, rt, offset);
Steve Block44f0eee2011-05-26 01:26:41 +01001420 BlockTrampolinePoolFor(1); // For associated delay slot.
Andrei Popescu31002712010-02-23 13:46:05 +00001421}
1422
1423
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001424void Assembler::bovc(Register rs, Register rt, int16_t offset) {
1425 DCHECK(IsMipsArchVariant(kMips32r6));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001426 if (rs.code() >= rt.code()) {
1427 GenInstrImmediate(ADDI, rs, rt, offset, CompactBranchType::COMPACT_BRANCH);
1428 } else {
1429 GenInstrImmediate(ADDI, rt, rs, offset, CompactBranchType::COMPACT_BRANCH);
1430 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001431}
1432
1433
1434void Assembler::bnvc(Register rs, Register rt, int16_t offset) {
1435 DCHECK(IsMipsArchVariant(kMips32r6));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001436 if (rs.code() >= rt.code()) {
1437 GenInstrImmediate(DADDI, rs, rt, offset, CompactBranchType::COMPACT_BRANCH);
1438 } else {
1439 GenInstrImmediate(DADDI, rt, rs, offset, CompactBranchType::COMPACT_BRANCH);
1440 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001441}
1442
1443
1444void Assembler::blezalc(Register rt, int16_t offset) {
1445 DCHECK(IsMipsArchVariant(kMips32r6));
1446 DCHECK(!(rt.is(zero_reg)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001447 positions_recorder()->WriteRecordedPositions();
1448 GenInstrImmediate(BLEZ, zero_reg, rt, offset,
1449 CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001450}
1451
1452
1453void Assembler::bgezalc(Register rt, int16_t offset) {
1454 DCHECK(IsMipsArchVariant(kMips32r6));
1455 DCHECK(!(rt.is(zero_reg)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001456 positions_recorder()->WriteRecordedPositions();
1457 GenInstrImmediate(BLEZ, rt, rt, offset, CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001458}
1459
1460
1461void Assembler::bgezall(Register rs, int16_t offset) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001462 DCHECK(!IsMipsArchVariant(kMips32r6));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001463 DCHECK(!(rs.is(zero_reg)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001464 BlockTrampolinePoolScope block_trampoline_pool(this);
1465 positions_recorder()->WriteRecordedPositions();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001466 GenInstrImmediate(REGIMM, rs, BGEZALL, offset);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001467 BlockTrampolinePoolFor(1); // For associated delay slot.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001468}
1469
1470
1471void Assembler::bltzalc(Register rt, int16_t offset) {
1472 DCHECK(IsMipsArchVariant(kMips32r6));
1473 DCHECK(!(rt.is(zero_reg)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001474 positions_recorder()->WriteRecordedPositions();
1475 GenInstrImmediate(BGTZ, rt, rt, offset, CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001476}
1477
1478
1479void Assembler::bgtzalc(Register rt, int16_t offset) {
1480 DCHECK(IsMipsArchVariant(kMips32r6));
1481 DCHECK(!(rt.is(zero_reg)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001482 positions_recorder()->WriteRecordedPositions();
1483 GenInstrImmediate(BGTZ, zero_reg, rt, offset,
1484 CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001485}
1486
1487
1488void Assembler::beqzalc(Register rt, int16_t offset) {
1489 DCHECK(IsMipsArchVariant(kMips32r6));
1490 DCHECK(!(rt.is(zero_reg)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001491 positions_recorder()->WriteRecordedPositions();
1492 GenInstrImmediate(ADDI, zero_reg, rt, offset,
1493 CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001494}
1495
1496
1497void Assembler::bnezalc(Register rt, int16_t offset) {
1498 DCHECK(IsMipsArchVariant(kMips32r6));
1499 DCHECK(!(rt.is(zero_reg)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001500 positions_recorder()->WriteRecordedPositions();
1501 GenInstrImmediate(DADDI, zero_reg, rt, offset,
1502 CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001503}
1504
1505
1506void Assembler::beqc(Register rs, Register rt, int16_t offset) {
1507 DCHECK(IsMipsArchVariant(kMips32r6));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001508 DCHECK(rs.code() != rt.code() && rs.code() != 0 && rt.code() != 0);
1509 if (rs.code() < rt.code()) {
1510 GenInstrImmediate(ADDI, rs, rt, offset, CompactBranchType::COMPACT_BRANCH);
1511 } else {
1512 GenInstrImmediate(ADDI, rt, rs, offset, CompactBranchType::COMPACT_BRANCH);
1513 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001514}
1515
1516
1517void Assembler::beqzc(Register rs, int32_t offset) {
1518 DCHECK(IsMipsArchVariant(kMips32r6));
1519 DCHECK(!(rs.is(zero_reg)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001520 GenInstrImmediate(POP66, rs, offset, CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001521}
1522
1523
1524void Assembler::bnec(Register rs, Register rt, int16_t offset) {
1525 DCHECK(IsMipsArchVariant(kMips32r6));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001526 DCHECK(rs.code() != rt.code() && rs.code() != 0 && rt.code() != 0);
1527 if (rs.code() < rt.code()) {
1528 GenInstrImmediate(DADDI, rs, rt, offset, CompactBranchType::COMPACT_BRANCH);
1529 } else {
1530 GenInstrImmediate(DADDI, rt, rs, offset, CompactBranchType::COMPACT_BRANCH);
1531 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001532}
1533
1534
1535void Assembler::bnezc(Register rs, int32_t offset) {
1536 DCHECK(IsMipsArchVariant(kMips32r6));
1537 DCHECK(!(rs.is(zero_reg)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001538 GenInstrImmediate(POP76, rs, offset, CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001539}
1540
1541
Andrei Popescu31002712010-02-23 13:46:05 +00001542void Assembler::j(int32_t target) {
Ben Murdoch589d6972011-11-30 16:04:58 +00001543#if DEBUG
1544 // Get pc of delay slot.
1545 uint32_t ipc = reinterpret_cast<uint32_t>(pc_ + 1 * kInstrSize);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001546 bool in_range = ((ipc ^ static_cast<uint32_t>(target)) >>
1547 (kImm26Bits + kImmFieldShift)) == 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001548 DCHECK(in_range && ((target & 3) == 0));
Ben Murdoch589d6972011-11-30 16:04:58 +00001549#endif
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001550 BlockTrampolinePoolScope block_trampoline_pool(this);
1551 GenInstrJump(J, (target >> 2) & kImm26Mask);
1552 BlockTrampolinePoolFor(1); // For associated delay slot.
Andrei Popescu31002712010-02-23 13:46:05 +00001553}
1554
1555
1556void Assembler::jr(Register rs) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001557 if (!IsMipsArchVariant(kMips32r6)) {
1558 BlockTrampolinePoolScope block_trampoline_pool(this);
1559 if (rs.is(ra)) {
1560 positions_recorder()->WriteRecordedPositions();
1561 }
1562 GenInstrRegister(SPECIAL, rs, zero_reg, zero_reg, 0, JR);
1563 BlockTrampolinePoolFor(1); // For associated delay slot.
1564 } else {
1565 jalr(rs, zero_reg);
Steve Block44f0eee2011-05-26 01:26:41 +01001566 }
Andrei Popescu31002712010-02-23 13:46:05 +00001567}
1568
1569
1570void Assembler::jal(int32_t target) {
Ben Murdoch589d6972011-11-30 16:04:58 +00001571#ifdef DEBUG
1572 // Get pc of delay slot.
1573 uint32_t ipc = reinterpret_cast<uint32_t>(pc_ + 1 * kInstrSize);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001574 bool in_range = ((ipc ^ static_cast<uint32_t>(target)) >>
1575 (kImm26Bits + kImmFieldShift)) == 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001576 DCHECK(in_range && ((target & 3) == 0));
Ben Murdoch589d6972011-11-30 16:04:58 +00001577#endif
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001578 BlockTrampolinePoolScope block_trampoline_pool(this);
Steve Block44f0eee2011-05-26 01:26:41 +01001579 positions_recorder()->WriteRecordedPositions();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001580 GenInstrJump(JAL, (target >> 2) & kImm26Mask);
1581 BlockTrampolinePoolFor(1); // For associated delay slot.
Andrei Popescu31002712010-02-23 13:46:05 +00001582}
1583
1584
1585void Assembler::jalr(Register rs, Register rd) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001586 DCHECK(rs.code() != rd.code());
Steve Block44f0eee2011-05-26 01:26:41 +01001587 BlockTrampolinePoolScope block_trampoline_pool(this);
1588 positions_recorder()->WriteRecordedPositions();
Andrei Popescu31002712010-02-23 13:46:05 +00001589 GenInstrRegister(SPECIAL, rs, zero_reg, rd, 0, JALR);
Steve Block44f0eee2011-05-26 01:26:41 +01001590 BlockTrampolinePoolFor(1); // For associated delay slot.
Andrei Popescu31002712010-02-23 13:46:05 +00001591}
1592
1593
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001594void Assembler::jic(Register rt, int16_t offset) {
1595 DCHECK(IsMipsArchVariant(kMips32r6));
1596 GenInstrImmediate(POP66, zero_reg, rt, offset);
Ben Murdoch589d6972011-11-30 16:04:58 +00001597}
1598
1599
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001600void Assembler::jialc(Register rt, int16_t offset) {
1601 DCHECK(IsMipsArchVariant(kMips32r6));
1602 positions_recorder()->WriteRecordedPositions();
1603 GenInstrImmediate(POP76, zero_reg, rt, offset);
Ben Murdoch589d6972011-11-30 16:04:58 +00001604}
1605
1606
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001607// -------Data-processing-instructions---------
Andrei Popescu31002712010-02-23 13:46:05 +00001608
1609// Arithmetic.
1610
Andrei Popescu31002712010-02-23 13:46:05 +00001611void Assembler::addu(Register rd, Register rs, Register rt) {
1612 GenInstrRegister(SPECIAL, rs, rt, rd, 0, ADDU);
1613}
1614
1615
Andrei Popescu31002712010-02-23 13:46:05 +00001616void Assembler::addiu(Register rd, Register rs, int32_t j) {
1617 GenInstrImmediate(ADDIU, rs, rd, j);
Andrei Popescu31002712010-02-23 13:46:05 +00001618}
1619
1620
1621void Assembler::subu(Register rd, Register rs, Register rt) {
1622 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SUBU);
1623}
1624
1625
1626void Assembler::mul(Register rd, Register rs, Register rt) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001627 if (!IsMipsArchVariant(kMips32r6)) {
1628 GenInstrRegister(SPECIAL2, rs, rt, rd, 0, MUL);
1629 } else {
1630 GenInstrRegister(SPECIAL, rs, rt, rd, MUL_OP, MUL_MUH);
1631 }
1632}
1633
1634
1635void Assembler::mulu(Register rd, Register rs, Register rt) {
1636 DCHECK(IsMipsArchVariant(kMips32r6));
1637 GenInstrRegister(SPECIAL, rs, rt, rd, MUL_OP, MUL_MUH_U);
1638}
1639
1640
1641void Assembler::muh(Register rd, Register rs, Register rt) {
1642 DCHECK(IsMipsArchVariant(kMips32r6));
1643 GenInstrRegister(SPECIAL, rs, rt, rd, MUH_OP, MUL_MUH);
1644}
1645
1646
1647void Assembler::muhu(Register rd, Register rs, Register rt) {
1648 DCHECK(IsMipsArchVariant(kMips32r6));
1649 GenInstrRegister(SPECIAL, rs, rt, rd, MUH_OP, MUL_MUH_U);
1650}
1651
1652
1653void Assembler::mod(Register rd, Register rs, Register rt) {
1654 DCHECK(IsMipsArchVariant(kMips32r6));
1655 GenInstrRegister(SPECIAL, rs, rt, rd, MOD_OP, DIV_MOD);
1656}
1657
1658
1659void Assembler::modu(Register rd, Register rs, Register rt) {
1660 DCHECK(IsMipsArchVariant(kMips32r6));
1661 GenInstrRegister(SPECIAL, rs, rt, rd, MOD_OP, DIV_MOD_U);
Andrei Popescu31002712010-02-23 13:46:05 +00001662}
1663
1664
1665void Assembler::mult(Register rs, Register rt) {
1666 GenInstrRegister(SPECIAL, rs, rt, zero_reg, 0, MULT);
1667}
1668
1669
1670void Assembler::multu(Register rs, Register rt) {
1671 GenInstrRegister(SPECIAL, rs, rt, zero_reg, 0, MULTU);
1672}
1673
1674
1675void Assembler::div(Register rs, Register rt) {
1676 GenInstrRegister(SPECIAL, rs, rt, zero_reg, 0, DIV);
1677}
1678
1679
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001680void Assembler::div(Register rd, Register rs, Register rt) {
1681 DCHECK(IsMipsArchVariant(kMips32r6));
1682 GenInstrRegister(SPECIAL, rs, rt, rd, DIV_OP, DIV_MOD);
1683}
1684
1685
Andrei Popescu31002712010-02-23 13:46:05 +00001686void Assembler::divu(Register rs, Register rt) {
1687 GenInstrRegister(SPECIAL, rs, rt, zero_reg, 0, DIVU);
1688}
1689
1690
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001691void Assembler::divu(Register rd, Register rs, Register rt) {
1692 DCHECK(IsMipsArchVariant(kMips32r6));
1693 GenInstrRegister(SPECIAL, rs, rt, rd, DIV_OP, DIV_MOD_U);
1694}
1695
1696
Andrei Popescu31002712010-02-23 13:46:05 +00001697// Logical.
1698
1699void Assembler::and_(Register rd, Register rs, Register rt) {
1700 GenInstrRegister(SPECIAL, rs, rt, rd, 0, AND);
1701}
1702
1703
1704void Assembler::andi(Register rt, Register rs, int32_t j) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001705 DCHECK(is_uint16(j));
Andrei Popescu31002712010-02-23 13:46:05 +00001706 GenInstrImmediate(ANDI, rs, rt, j);
1707}
1708
1709
1710void Assembler::or_(Register rd, Register rs, Register rt) {
1711 GenInstrRegister(SPECIAL, rs, rt, rd, 0, OR);
1712}
1713
1714
1715void Assembler::ori(Register rt, Register rs, int32_t j) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001716 DCHECK(is_uint16(j));
Andrei Popescu31002712010-02-23 13:46:05 +00001717 GenInstrImmediate(ORI, rs, rt, j);
1718}
1719
1720
1721void Assembler::xor_(Register rd, Register rs, Register rt) {
1722 GenInstrRegister(SPECIAL, rs, rt, rd, 0, XOR);
1723}
1724
1725
1726void Assembler::xori(Register rt, Register rs, int32_t j) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001727 DCHECK(is_uint16(j));
Andrei Popescu31002712010-02-23 13:46:05 +00001728 GenInstrImmediate(XORI, rs, rt, j);
1729}
1730
1731
1732void Assembler::nor(Register rd, Register rs, Register rt) {
1733 GenInstrRegister(SPECIAL, rs, rt, rd, 0, NOR);
1734}
1735
1736
1737// Shifts.
Steve Block44f0eee2011-05-26 01:26:41 +01001738void Assembler::sll(Register rd,
1739 Register rt,
1740 uint16_t sa,
1741 bool coming_from_nop) {
1742 // Don't allow nop instructions in the form sll zero_reg, zero_reg to be
1743 // generated using the sll instruction. They must be generated using
1744 // nop(int/NopMarkerTypes) or MarkCode(int/NopMarkerTypes) pseudo
1745 // instructions.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001746 DCHECK(coming_from_nop || !(rd.is(zero_reg) && rt.is(zero_reg)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001747 GenInstrRegister(SPECIAL, zero_reg, rt, rd, sa & 0x1F, SLL);
Andrei Popescu31002712010-02-23 13:46:05 +00001748}
1749
1750
1751void Assembler::sllv(Register rd, Register rt, Register rs) {
1752 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SLLV);
1753}
1754
1755
1756void Assembler::srl(Register rd, Register rt, uint16_t sa) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001757 GenInstrRegister(SPECIAL, zero_reg, rt, rd, sa & 0x1F, SRL);
Andrei Popescu31002712010-02-23 13:46:05 +00001758}
1759
1760
1761void Assembler::srlv(Register rd, Register rt, Register rs) {
1762 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SRLV);
1763}
1764
1765
1766void Assembler::sra(Register rd, Register rt, uint16_t sa) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001767 GenInstrRegister(SPECIAL, zero_reg, rt, rd, sa & 0x1F, SRA);
Andrei Popescu31002712010-02-23 13:46:05 +00001768}
1769
1770
1771void Assembler::srav(Register rd, Register rt, Register rs) {
1772 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SRAV);
1773}
1774
1775
Steve Block44f0eee2011-05-26 01:26:41 +01001776void Assembler::rotr(Register rd, Register rt, uint16_t sa) {
1777 // Should be called via MacroAssembler::Ror.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001778 DCHECK(rd.is_valid() && rt.is_valid() && is_uint5(sa));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001779 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
Steve Block44f0eee2011-05-26 01:26:41 +01001780 Instr instr = SPECIAL | (1 << kRsShift) | (rt.code() << kRtShift)
1781 | (rd.code() << kRdShift) | (sa << kSaShift) | SRL;
1782 emit(instr);
1783}
1784
1785
1786void Assembler::rotrv(Register rd, Register rt, Register rs) {
1787 // Should be called via MacroAssembler::Ror.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001788 DCHECK(rd.is_valid() && rt.is_valid() && rs.is_valid());
1789 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
Steve Block44f0eee2011-05-26 01:26:41 +01001790 Instr instr = SPECIAL | (rs.code() << kRsShift) | (rt.code() << kRtShift)
1791 | (rd.code() << kRdShift) | (1 << kSaShift) | SRLV;
1792 emit(instr);
1793}
1794
1795
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001796void Assembler::lsa(Register rd, Register rt, Register rs, uint8_t sa) {
1797 DCHECK(rd.is_valid() && rt.is_valid() && rs.is_valid());
Ben Murdochda12d292016-06-02 14:46:10 +01001798 DCHECK(sa <= 3);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001799 DCHECK(IsMipsArchVariant(kMips32r6));
Ben Murdochda12d292016-06-02 14:46:10 +01001800 Instr instr = SPECIAL | rs.code() << kRsShift | rt.code() << kRtShift |
1801 rd.code() << kRdShift | sa << kSaShift | LSA;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001802 emit(instr);
1803}
1804
1805
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001806// ------------Memory-instructions-------------
Andrei Popescu31002712010-02-23 13:46:05 +00001807
Steve Block44f0eee2011-05-26 01:26:41 +01001808// Helper for base-reg + offset, when offset is larger than int16.
1809void Assembler::LoadRegPlusOffsetToAt(const MemOperand& src) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001810 DCHECK(!src.rm().is(at));
1811 lui(at, (src.offset_ >> kLuiShift) & kImm16Mask);
Steve Block44f0eee2011-05-26 01:26:41 +01001812 ori(at, at, src.offset_ & kImm16Mask); // Load 32-bit offset.
1813 addu(at, at, src.rm()); // Add base register.
1814}
1815
1816
Andrei Popescu31002712010-02-23 13:46:05 +00001817void Assembler::lb(Register rd, const MemOperand& rs) {
Steve Block44f0eee2011-05-26 01:26:41 +01001818 if (is_int16(rs.offset_)) {
1819 GenInstrImmediate(LB, rs.rm(), rd, rs.offset_);
1820 } else { // Offset > 16 bits, use multiple instructions to load.
1821 LoadRegPlusOffsetToAt(rs);
1822 GenInstrImmediate(LB, at, rd, 0); // Equiv to lb(rd, MemOperand(at, 0));
1823 }
Andrei Popescu31002712010-02-23 13:46:05 +00001824}
1825
1826
1827void Assembler::lbu(Register rd, const MemOperand& rs) {
Steve Block44f0eee2011-05-26 01:26:41 +01001828 if (is_int16(rs.offset_)) {
1829 GenInstrImmediate(LBU, rs.rm(), rd, rs.offset_);
1830 } else { // Offset > 16 bits, use multiple instructions to load.
1831 LoadRegPlusOffsetToAt(rs);
1832 GenInstrImmediate(LBU, at, rd, 0); // Equiv to lbu(rd, MemOperand(at, 0));
1833 }
1834}
1835
1836
1837void Assembler::lh(Register rd, const MemOperand& rs) {
1838 if (is_int16(rs.offset_)) {
1839 GenInstrImmediate(LH, rs.rm(), rd, rs.offset_);
1840 } else { // Offset > 16 bits, use multiple instructions to load.
1841 LoadRegPlusOffsetToAt(rs);
1842 GenInstrImmediate(LH, at, rd, 0); // Equiv to lh(rd, MemOperand(at, 0));
1843 }
1844}
1845
1846
1847void Assembler::lhu(Register rd, const MemOperand& rs) {
1848 if (is_int16(rs.offset_)) {
1849 GenInstrImmediate(LHU, rs.rm(), rd, rs.offset_);
1850 } else { // Offset > 16 bits, use multiple instructions to load.
1851 LoadRegPlusOffsetToAt(rs);
1852 GenInstrImmediate(LHU, at, rd, 0); // Equiv to lhu(rd, MemOperand(at, 0));
1853 }
Andrei Popescu31002712010-02-23 13:46:05 +00001854}
1855
1856
1857void Assembler::lw(Register rd, const MemOperand& rs) {
Steve Block44f0eee2011-05-26 01:26:41 +01001858 if (is_int16(rs.offset_)) {
1859 GenInstrImmediate(LW, rs.rm(), rd, rs.offset_);
1860 } else { // Offset > 16 bits, use multiple instructions to load.
1861 LoadRegPlusOffsetToAt(rs);
1862 GenInstrImmediate(LW, at, rd, 0); // Equiv to lw(rd, MemOperand(at, 0));
1863 }
Steve Block44f0eee2011-05-26 01:26:41 +01001864}
1865
1866
1867void Assembler::lwl(Register rd, const MemOperand& rs) {
Ben Murdochc5610432016-08-08 18:44:38 +01001868 DCHECK(is_int16(rs.offset_));
1869 DCHECK(IsMipsArchVariant(kLoongson) || IsMipsArchVariant(kMips32r1) ||
1870 IsMipsArchVariant(kMips32r2));
Steve Block44f0eee2011-05-26 01:26:41 +01001871 GenInstrImmediate(LWL, rs.rm(), rd, rs.offset_);
1872}
1873
1874
1875void Assembler::lwr(Register rd, const MemOperand& rs) {
Ben Murdochc5610432016-08-08 18:44:38 +01001876 DCHECK(is_int16(rs.offset_));
1877 DCHECK(IsMipsArchVariant(kLoongson) || IsMipsArchVariant(kMips32r1) ||
1878 IsMipsArchVariant(kMips32r2));
Steve Block44f0eee2011-05-26 01:26:41 +01001879 GenInstrImmediate(LWR, rs.rm(), rd, rs.offset_);
Andrei Popescu31002712010-02-23 13:46:05 +00001880}
1881
1882
1883void Assembler::sb(Register rd, const MemOperand& rs) {
Steve Block44f0eee2011-05-26 01:26:41 +01001884 if (is_int16(rs.offset_)) {
1885 GenInstrImmediate(SB, rs.rm(), rd, rs.offset_);
1886 } else { // Offset > 16 bits, use multiple instructions to store.
1887 LoadRegPlusOffsetToAt(rs);
1888 GenInstrImmediate(SB, at, rd, 0); // Equiv to sb(rd, MemOperand(at, 0));
1889 }
1890}
1891
1892
1893void Assembler::sh(Register rd, const MemOperand& rs) {
1894 if (is_int16(rs.offset_)) {
1895 GenInstrImmediate(SH, rs.rm(), rd, rs.offset_);
1896 } else { // Offset > 16 bits, use multiple instructions to store.
1897 LoadRegPlusOffsetToAt(rs);
1898 GenInstrImmediate(SH, at, rd, 0); // Equiv to sh(rd, MemOperand(at, 0));
1899 }
Andrei Popescu31002712010-02-23 13:46:05 +00001900}
1901
1902
1903void Assembler::sw(Register rd, const MemOperand& rs) {
Steve Block44f0eee2011-05-26 01:26:41 +01001904 if (is_int16(rs.offset_)) {
1905 GenInstrImmediate(SW, rs.rm(), rd, rs.offset_);
1906 } else { // Offset > 16 bits, use multiple instructions to store.
1907 LoadRegPlusOffsetToAt(rs);
1908 GenInstrImmediate(SW, at, rd, 0); // Equiv to sw(rd, MemOperand(at, 0));
1909 }
Steve Block44f0eee2011-05-26 01:26:41 +01001910}
1911
1912
1913void Assembler::swl(Register rd, const MemOperand& rs) {
Ben Murdochc5610432016-08-08 18:44:38 +01001914 DCHECK(is_int16(rs.offset_));
1915 DCHECK(IsMipsArchVariant(kLoongson) || IsMipsArchVariant(kMips32r1) ||
1916 IsMipsArchVariant(kMips32r2));
Steve Block44f0eee2011-05-26 01:26:41 +01001917 GenInstrImmediate(SWL, rs.rm(), rd, rs.offset_);
1918}
1919
1920
1921void Assembler::swr(Register rd, const MemOperand& rs) {
Ben Murdochc5610432016-08-08 18:44:38 +01001922 DCHECK(is_int16(rs.offset_));
1923 DCHECK(IsMipsArchVariant(kLoongson) || IsMipsArchVariant(kMips32r1) ||
1924 IsMipsArchVariant(kMips32r2));
Steve Block44f0eee2011-05-26 01:26:41 +01001925 GenInstrImmediate(SWR, rs.rm(), rd, rs.offset_);
Andrei Popescu31002712010-02-23 13:46:05 +00001926}
1927
1928
1929void Assembler::lui(Register rd, int32_t j) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001930 DCHECK(is_uint16(j));
Andrei Popescu31002712010-02-23 13:46:05 +00001931 GenInstrImmediate(LUI, zero_reg, rd, j);
1932}
1933
1934
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001935void Assembler::aui(Register rt, Register rs, int32_t j) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001936 // This instruction uses same opcode as 'lui'. The difference in encoding is
1937 // 'lui' has zero reg. for rs field.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001938 DCHECK(!(rs.is(zero_reg)));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001939 DCHECK(is_uint16(j));
1940 GenInstrImmediate(LUI, rs, rt, j);
1941}
1942
1943
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001944// ---------PC-Relative instructions-----------
1945
1946void Assembler::addiupc(Register rs, int32_t imm19) {
1947 DCHECK(IsMipsArchVariant(kMips32r6));
1948 DCHECK(rs.is_valid() && is_int19(imm19));
1949 uint32_t imm21 = ADDIUPC << kImm19Bits | (imm19 & kImm19Mask);
1950 GenInstrImmediate(PCREL, rs, imm21);
1951}
1952
1953
1954void Assembler::lwpc(Register rs, int32_t offset19) {
1955 DCHECK(IsMipsArchVariant(kMips32r6));
1956 DCHECK(rs.is_valid() && is_int19(offset19));
1957 uint32_t imm21 = LWPC << kImm19Bits | (offset19 & kImm19Mask);
1958 GenInstrImmediate(PCREL, rs, imm21);
1959}
1960
1961
1962void Assembler::auipc(Register rs, int16_t imm16) {
1963 DCHECK(IsMipsArchVariant(kMips32r6));
1964 DCHECK(rs.is_valid());
1965 uint32_t imm21 = AUIPC << kImm16Bits | (imm16 & kImm16Mask);
1966 GenInstrImmediate(PCREL, rs, imm21);
1967}
1968
1969
1970void Assembler::aluipc(Register rs, int16_t imm16) {
1971 DCHECK(IsMipsArchVariant(kMips32r6));
1972 DCHECK(rs.is_valid());
1973 uint32_t imm21 = ALUIPC << kImm16Bits | (imm16 & kImm16Mask);
1974 GenInstrImmediate(PCREL, rs, imm21);
1975}
1976
1977
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001978// -------------Misc-instructions--------------
Andrei Popescu31002712010-02-23 13:46:05 +00001979
1980// Break / Trap instructions.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001981void Assembler::break_(uint32_t code, bool break_as_stop) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001982 DCHECK((code & ~0xfffff) == 0);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001983 // We need to invalidate breaks that could be stops as well because the
1984 // simulator expects a char pointer after the stop instruction.
1985 // See constants-mips.h for explanation.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001986 DCHECK((break_as_stop &&
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001987 code <= kMaxStopCode &&
1988 code > kMaxWatchpointCode) ||
1989 (!break_as_stop &&
1990 (code > kMaxStopCode ||
1991 code <= kMaxWatchpointCode)));
Andrei Popescu31002712010-02-23 13:46:05 +00001992 Instr break_instr = SPECIAL | BREAK | (code << 6);
1993 emit(break_instr);
1994}
1995
1996
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001997void Assembler::stop(const char* msg, uint32_t code) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001998 DCHECK(code > kMaxWatchpointCode);
1999 DCHECK(code <= kMaxStopCode);
2000#if V8_HOST_ARCH_MIPS
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002001 break_(0x54321);
2002#else // V8_HOST_ARCH_MIPS
2003 BlockTrampolinePoolFor(2);
2004 // The Simulator will handle the stop instruction and get the message address.
2005 // On MIPS stop() is just a special kind of break_().
2006 break_(code, true);
2007 emit(reinterpret_cast<Instr>(msg));
2008#endif
2009}
2010
2011
Andrei Popescu31002712010-02-23 13:46:05 +00002012void Assembler::tge(Register rs, Register rt, uint16_t code) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002013 DCHECK(is_uint10(code));
Andrei Popescu31002712010-02-23 13:46:05 +00002014 Instr instr = SPECIAL | TGE | rs.code() << kRsShift
2015 | rt.code() << kRtShift | code << 6;
2016 emit(instr);
2017}
2018
2019
2020void Assembler::tgeu(Register rs, Register rt, uint16_t code) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002021 DCHECK(is_uint10(code));
Andrei Popescu31002712010-02-23 13:46:05 +00002022 Instr instr = SPECIAL | TGEU | rs.code() << kRsShift
2023 | rt.code() << kRtShift | code << 6;
2024 emit(instr);
2025}
2026
2027
2028void Assembler::tlt(Register rs, Register rt, uint16_t code) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002029 DCHECK(is_uint10(code));
Andrei Popescu31002712010-02-23 13:46:05 +00002030 Instr instr =
2031 SPECIAL | TLT | rs.code() << kRsShift | rt.code() << kRtShift | code << 6;
2032 emit(instr);
2033}
2034
2035
2036void Assembler::tltu(Register rs, Register rt, uint16_t code) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002037 DCHECK(is_uint10(code));
Steve Block44f0eee2011-05-26 01:26:41 +01002038 Instr instr =
2039 SPECIAL | TLTU | rs.code() << kRsShift
Andrei Popescu31002712010-02-23 13:46:05 +00002040 | rt.code() << kRtShift | code << 6;
2041 emit(instr);
2042}
2043
2044
2045void Assembler::teq(Register rs, Register rt, uint16_t code) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002046 DCHECK(is_uint10(code));
Andrei Popescu31002712010-02-23 13:46:05 +00002047 Instr instr =
2048 SPECIAL | TEQ | rs.code() << kRsShift | rt.code() << kRtShift | code << 6;
2049 emit(instr);
2050}
2051
2052
2053void Assembler::tne(Register rs, Register rt, uint16_t code) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002054 DCHECK(is_uint10(code));
Andrei Popescu31002712010-02-23 13:46:05 +00002055 Instr instr =
2056 SPECIAL | TNE | rs.code() << kRsShift | rt.code() << kRtShift | code << 6;
2057 emit(instr);
2058}
2059
Ben Murdochc5610432016-08-08 18:44:38 +01002060void Assembler::sync() {
2061 Instr sync_instr = SPECIAL | SYNC;
2062 emit(sync_instr);
2063}
Andrei Popescu31002712010-02-23 13:46:05 +00002064
2065// Move from HI/LO register.
2066
2067void Assembler::mfhi(Register rd) {
2068 GenInstrRegister(SPECIAL, zero_reg, zero_reg, rd, 0, MFHI);
2069}
2070
2071
2072void Assembler::mflo(Register rd) {
2073 GenInstrRegister(SPECIAL, zero_reg, zero_reg, rd, 0, MFLO);
2074}
2075
2076
2077// Set on less than instructions.
2078void Assembler::slt(Register rd, Register rs, Register rt) {
2079 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SLT);
2080}
2081
2082
2083void Assembler::sltu(Register rd, Register rs, Register rt) {
2084 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SLTU);
2085}
2086
2087
2088void Assembler::slti(Register rt, Register rs, int32_t j) {
2089 GenInstrImmediate(SLTI, rs, rt, j);
2090}
2091
2092
2093void Assembler::sltiu(Register rt, Register rs, int32_t j) {
2094 GenInstrImmediate(SLTIU, rs, rt, j);
2095}
2096
2097
Steve Block44f0eee2011-05-26 01:26:41 +01002098// Conditional move.
2099void Assembler::movz(Register rd, Register rs, Register rt) {
2100 GenInstrRegister(SPECIAL, rs, rt, rd, 0, MOVZ);
2101}
2102
2103
2104void Assembler::movn(Register rd, Register rs, Register rt) {
2105 GenInstrRegister(SPECIAL, rs, rt, rd, 0, MOVN);
2106}
2107
2108
2109void Assembler::movt(Register rd, Register rs, uint16_t cc) {
2110 Register rt;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002111 rt.reg_code = (cc & 0x0007) << 2 | 1;
Steve Block44f0eee2011-05-26 01:26:41 +01002112 GenInstrRegister(SPECIAL, rs, rt, rd, 0, MOVCI);
2113}
2114
2115
2116void Assembler::movf(Register rd, Register rs, uint16_t cc) {
2117 Register rt;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002118 rt.reg_code = (cc & 0x0007) << 2 | 0;
Steve Block44f0eee2011-05-26 01:26:41 +01002119 GenInstrRegister(SPECIAL, rs, rt, rd, 0, MOVCI);
2120}
2121
2122
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002123void Assembler::seleqz(Register rd, Register rs, Register rt) {
2124 DCHECK(IsMipsArchVariant(kMips32r6));
2125 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SELEQZ_S);
2126}
2127
2128
Steve Block44f0eee2011-05-26 01:26:41 +01002129// Bit twiddling.
2130void Assembler::clz(Register rd, Register rs) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002131 if (!IsMipsArchVariant(kMips32r6)) {
2132 // Clz instr requires same GPR number in 'rd' and 'rt' fields.
2133 GenInstrRegister(SPECIAL2, rs, rd, rd, 0, CLZ);
2134 } else {
2135 GenInstrRegister(SPECIAL, rs, zero_reg, rd, 1, CLZ_R6);
2136 }
Steve Block44f0eee2011-05-26 01:26:41 +01002137}
2138
2139
2140void Assembler::ins_(Register rt, Register rs, uint16_t pos, uint16_t size) {
2141 // Should be called via MacroAssembler::Ins.
2142 // Ins instr has 'rt' field as dest, and two uint5: msb, lsb.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002143 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
Steve Block44f0eee2011-05-26 01:26:41 +01002144 GenInstrRegister(SPECIAL3, rs, rt, pos + size - 1, pos, INS);
2145}
2146
2147
2148void Assembler::ext_(Register rt, Register rs, uint16_t pos, uint16_t size) {
2149 // Should be called via MacroAssembler::Ext.
2150 // Ext instr has 'rt' field as dest, and two uint5: msb, lsb.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002151 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
Steve Block44f0eee2011-05-26 01:26:41 +01002152 GenInstrRegister(SPECIAL3, rs, rt, size - 1, pos, EXT);
2153}
2154
2155
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002156void Assembler::bitswap(Register rd, Register rt) {
2157 DCHECK(IsMipsArchVariant(kMips32r6));
2158 GenInstrRegister(SPECIAL3, zero_reg, rt, rd, 0, BSHFL);
2159}
2160
2161
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002162void Assembler::pref(int32_t hint, const MemOperand& rs) {
2163 DCHECK(!IsMipsArchVariant(kLoongson));
2164 DCHECK(is_uint5(hint) && is_uint16(rs.offset_));
2165 Instr instr = PREF | (rs.rm().code() << kRsShift) | (hint << kRtShift)
2166 | (rs.offset_);
2167 emit(instr);
2168}
2169
2170
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002171void Assembler::align(Register rd, Register rs, Register rt, uint8_t bp) {
2172 DCHECK(IsMipsArchVariant(kMips32r6));
2173 DCHECK(is_uint3(bp));
2174 uint16_t sa = (ALIGN << kBp2Bits) | bp;
2175 GenInstrRegister(SPECIAL3, rs, rt, rd, sa, BSHFL);
2176}
2177
2178
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002179// --------Coprocessor-instructions----------------
Andrei Popescu31002712010-02-23 13:46:05 +00002180
2181// Load, store, move.
2182void Assembler::lwc1(FPURegister fd, const MemOperand& src) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002183 if (is_int16(src.offset_)) {
2184 GenInstrImmediate(LWC1, src.rm(), fd, src.offset_);
2185 } else { // Offset > 16 bits, use multiple instructions to load.
2186 LoadRegPlusOffsetToAt(src);
2187 GenInstrImmediate(LWC1, at, fd, 0);
2188 }
Andrei Popescu31002712010-02-23 13:46:05 +00002189}
2190
2191
2192void Assembler::ldc1(FPURegister fd, const MemOperand& src) {
Steve Block44f0eee2011-05-26 01:26:41 +01002193 // Workaround for non-8-byte alignment of HeapNumber, convert 64-bit
2194 // load to two 32-bit loads.
Ben Murdoch097c5b22016-05-18 11:27:45 +01002195 if (IsFp32Mode()) { // fp32 mode.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002196 if (is_int16(src.offset_) && is_int16(src.offset_ + kIntSize)) {
2197 GenInstrImmediate(LWC1, src.rm(), fd,
2198 src.offset_ + Register::kMantissaOffset);
2199 FPURegister nextfpreg;
2200 nextfpreg.setcode(fd.code() + 1);
2201 GenInstrImmediate(LWC1, src.rm(), nextfpreg,
2202 src.offset_ + Register::kExponentOffset);
2203 } else { // Offset > 16 bits, use multiple instructions to load.
2204 LoadRegPlusOffsetToAt(src);
2205 GenInstrImmediate(LWC1, at, fd, Register::kMantissaOffset);
2206 FPURegister nextfpreg;
2207 nextfpreg.setcode(fd.code() + 1);
2208 GenInstrImmediate(LWC1, at, nextfpreg, Register::kExponentOffset);
2209 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01002210 } else {
2211 DCHECK(IsFp64Mode() || IsFpxxMode());
2212 // Currently we support FPXX and FP64 on Mips32r2 and Mips32r6
2213 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
2214 if (is_int16(src.offset_) && is_int16(src.offset_ + kIntSize)) {
2215 GenInstrImmediate(LWC1, src.rm(), fd,
2216 src.offset_ + Register::kMantissaOffset);
2217 GenInstrImmediate(LW, src.rm(), at,
2218 src.offset_ + Register::kExponentOffset);
2219 mthc1(at, fd);
2220 } else { // Offset > 16 bits, use multiple instructions to load.
2221 LoadRegPlusOffsetToAt(src);
2222 GenInstrImmediate(LWC1, at, fd, Register::kMantissaOffset);
2223 GenInstrImmediate(LW, at, at, Register::kExponentOffset);
2224 mthc1(at, fd);
2225 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002226 }
Andrei Popescu31002712010-02-23 13:46:05 +00002227}
2228
2229
2230void Assembler::swc1(FPURegister fd, const MemOperand& src) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002231 if (is_int16(src.offset_)) {
2232 GenInstrImmediate(SWC1, src.rm(), fd, src.offset_);
2233 } else { // Offset > 16 bits, use multiple instructions to load.
2234 LoadRegPlusOffsetToAt(src);
2235 GenInstrImmediate(SWC1, at, fd, 0);
2236 }
Andrei Popescu31002712010-02-23 13:46:05 +00002237}
2238
2239
2240void Assembler::sdc1(FPURegister fd, const MemOperand& src) {
Steve Block44f0eee2011-05-26 01:26:41 +01002241 // Workaround for non-8-byte alignment of HeapNumber, convert 64-bit
2242 // store to two 32-bit stores.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002243 DCHECK(!src.rm().is(at));
2244 DCHECK(!src.rm().is(t8));
Ben Murdoch097c5b22016-05-18 11:27:45 +01002245 if (IsFp32Mode()) { // fp32 mode.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002246 if (is_int16(src.offset_) && is_int16(src.offset_ + kIntSize)) {
2247 GenInstrImmediate(SWC1, src.rm(), fd,
2248 src.offset_ + Register::kMantissaOffset);
2249 FPURegister nextfpreg;
2250 nextfpreg.setcode(fd.code() + 1);
2251 GenInstrImmediate(SWC1, src.rm(), nextfpreg,
2252 src.offset_ + Register::kExponentOffset);
2253 } else { // Offset > 16 bits, use multiple instructions to load.
2254 LoadRegPlusOffsetToAt(src);
2255 GenInstrImmediate(SWC1, at, fd, Register::kMantissaOffset);
2256 FPURegister nextfpreg;
2257 nextfpreg.setcode(fd.code() + 1);
2258 GenInstrImmediate(SWC1, at, nextfpreg, Register::kExponentOffset);
2259 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01002260 } else {
2261 DCHECK(IsFp64Mode() || IsFpxxMode());
2262 // Currently we support FPXX and FP64 on Mips32r2 and Mips32r6
2263 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
2264 if (is_int16(src.offset_) && is_int16(src.offset_ + kIntSize)) {
2265 GenInstrImmediate(SWC1, src.rm(), fd,
2266 src.offset_ + Register::kMantissaOffset);
2267 mfhc1(at, fd);
2268 GenInstrImmediate(SW, src.rm(), at,
2269 src.offset_ + Register::kExponentOffset);
2270 } else { // Offset > 16 bits, use multiple instructions to load.
2271 LoadRegPlusOffsetToAt(src);
2272 GenInstrImmediate(SWC1, at, fd, Register::kMantissaOffset);
2273 mfhc1(t8, fd);
2274 GenInstrImmediate(SW, at, t8, Register::kExponentOffset);
2275 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002276 }
Andrei Popescu31002712010-02-23 13:46:05 +00002277}
2278
2279
Steve Block44f0eee2011-05-26 01:26:41 +01002280void Assembler::mtc1(Register rt, FPURegister fs) {
Andrei Popescu31002712010-02-23 13:46:05 +00002281 GenInstrRegister(COP1, MTC1, rt, fs, f0);
2282}
2283
2284
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002285void Assembler::mthc1(Register rt, FPURegister fs) {
2286 GenInstrRegister(COP1, MTHC1, rt, fs, f0);
2287}
2288
2289
Steve Block44f0eee2011-05-26 01:26:41 +01002290void Assembler::mfc1(Register rt, FPURegister fs) {
Andrei Popescu31002712010-02-23 13:46:05 +00002291 GenInstrRegister(COP1, MFC1, rt, fs, f0);
2292}
2293
2294
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002295void Assembler::mfhc1(Register rt, FPURegister fs) {
2296 GenInstrRegister(COP1, MFHC1, rt, fs, f0);
2297}
2298
2299
Steve Block44f0eee2011-05-26 01:26:41 +01002300void Assembler::ctc1(Register rt, FPUControlRegister fs) {
2301 GenInstrRegister(COP1, CTC1, rt, fs);
2302}
2303
2304
2305void Assembler::cfc1(Register rt, FPUControlRegister fs) {
2306 GenInstrRegister(COP1, CFC1, rt, fs);
2307}
2308
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002309
Ben Murdoch589d6972011-11-30 16:04:58 +00002310void Assembler::DoubleAsTwoUInt32(double d, uint32_t* lo, uint32_t* hi) {
2311 uint64_t i;
2312 memcpy(&i, &d, 8);
2313
2314 *lo = i & 0xffffffff;
2315 *hi = i >> 32;
2316}
Steve Block44f0eee2011-05-26 01:26:41 +01002317
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002318
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002319void Assembler::movn_s(FPURegister fd, FPURegister fs, Register rt) {
2320 DCHECK(!IsMipsArchVariant(kMips32r6));
2321 GenInstrRegister(COP1, S, rt, fs, fd, MOVN_C);
2322}
2323
2324
2325void Assembler::movn_d(FPURegister fd, FPURegister fs, Register rt) {
2326 DCHECK(!IsMipsArchVariant(kMips32r6));
2327 GenInstrRegister(COP1, D, rt, fs, fd, MOVN_C);
2328}
2329
2330
2331void Assembler::sel(SecondaryField fmt, FPURegister fd, FPURegister fs,
2332 FPURegister ft) {
2333 DCHECK(IsMipsArchVariant(kMips32r6));
2334 DCHECK((fmt == D) || (fmt == S));
2335
2336 GenInstrRegister(COP1, fmt, ft, fs, fd, SEL);
2337}
2338
2339
2340void Assembler::sel_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2341 sel(S, fd, fs, ft);
2342}
2343
2344
2345void Assembler::sel_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2346 sel(D, fd, fs, ft);
2347}
2348
2349
2350void Assembler::seleqz(SecondaryField fmt, FPURegister fd, FPURegister fs,
2351 FPURegister ft) {
2352 DCHECK(IsMipsArchVariant(kMips32r6));
2353 DCHECK((fmt == D) || (fmt == S));
2354 GenInstrRegister(COP1, fmt, ft, fs, fd, SELEQZ_C);
2355}
2356
2357
2358void Assembler::selnez(Register rd, Register rs, Register rt) {
2359 DCHECK(IsMipsArchVariant(kMips32r6));
2360 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SELNEZ_S);
2361}
2362
2363
2364void Assembler::selnez(SecondaryField fmt, FPURegister fd, FPURegister fs,
2365 FPURegister ft) {
2366 DCHECK(IsMipsArchVariant(kMips32r6));
2367 DCHECK((fmt == D) || (fmt == S));
2368 GenInstrRegister(COP1, fmt, ft, fs, fd, SELNEZ_C);
2369}
2370
2371
2372void Assembler::seleqz_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2373 seleqz(D, fd, fs, ft);
2374}
2375
2376
2377void Assembler::seleqz_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2378 seleqz(S, fd, fs, ft);
2379}
2380
2381
2382void Assembler::selnez_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2383 selnez(D, fd, fs, ft);
2384}
2385
2386
2387void Assembler::selnez_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2388 selnez(S, fd, fs, ft);
2389}
2390
2391
2392void Assembler::movz_s(FPURegister fd, FPURegister fs, Register rt) {
2393 DCHECK(!IsMipsArchVariant(kMips32r6));
2394 GenInstrRegister(COP1, S, rt, fs, fd, MOVZ_C);
2395}
2396
2397
2398void Assembler::movz_d(FPURegister fd, FPURegister fs, Register rt) {
2399 DCHECK(!IsMipsArchVariant(kMips32r6));
2400 GenInstrRegister(COP1, D, rt, fs, fd, MOVZ_C);
2401}
2402
2403
2404void Assembler::movt_s(FPURegister fd, FPURegister fs, uint16_t cc) {
2405 DCHECK(!IsMipsArchVariant(kMips32r6));
2406 FPURegister ft;
2407 ft.reg_code = (cc & 0x0007) << 2 | 1;
2408 GenInstrRegister(COP1, S, ft, fs, fd, MOVF);
2409}
2410
2411
2412void Assembler::movt_d(FPURegister fd, FPURegister fs, uint16_t cc) {
2413 DCHECK(!IsMipsArchVariant(kMips32r6));
2414 FPURegister ft;
2415 ft.reg_code = (cc & 0x0007) << 2 | 1;
2416 GenInstrRegister(COP1, D, ft, fs, fd, MOVF);
2417}
2418
2419
2420void Assembler::movf_s(FPURegister fd, FPURegister fs, uint16_t cc) {
2421 DCHECK(!IsMipsArchVariant(kMips32r6));
2422 FPURegister ft;
2423 ft.reg_code = (cc & 0x0007) << 2 | 0;
2424 GenInstrRegister(COP1, S, ft, fs, fd, MOVF);
2425}
2426
2427
2428void Assembler::movf_d(FPURegister fd, FPURegister fs, uint16_t cc) {
2429 DCHECK(!IsMipsArchVariant(kMips32r6));
2430 FPURegister ft;
2431 ft.reg_code = (cc & 0x0007) << 2 | 0;
2432 GenInstrRegister(COP1, D, ft, fs, fd, MOVF);
2433}
2434
2435
Steve Block44f0eee2011-05-26 01:26:41 +01002436// Arithmetic.
2437
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002438void Assembler::add_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2439 GenInstrRegister(COP1, S, ft, fs, fd, ADD_S);
2440}
2441
2442
Steve Block44f0eee2011-05-26 01:26:41 +01002443void Assembler::add_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2444 GenInstrRegister(COP1, D, ft, fs, fd, ADD_D);
2445}
2446
2447
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002448void Assembler::sub_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2449 GenInstrRegister(COP1, S, ft, fs, fd, SUB_S);
2450}
2451
2452
Steve Block44f0eee2011-05-26 01:26:41 +01002453void Assembler::sub_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2454 GenInstrRegister(COP1, D, ft, fs, fd, SUB_D);
2455}
2456
2457
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002458void Assembler::mul_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2459 GenInstrRegister(COP1, S, ft, fs, fd, MUL_S);
2460}
2461
2462
Steve Block44f0eee2011-05-26 01:26:41 +01002463void Assembler::mul_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2464 GenInstrRegister(COP1, D, ft, fs, fd, MUL_D);
2465}
2466
2467
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002468void Assembler::madd_d(FPURegister fd, FPURegister fr, FPURegister fs,
2469 FPURegister ft) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002470 DCHECK(IsMipsArchVariant(kMips32r2));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002471 GenInstrRegister(COP1X, fr, ft, fs, fd, MADD_D);
2472}
2473
2474
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002475void Assembler::div_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2476 GenInstrRegister(COP1, S, ft, fs, fd, DIV_S);
2477}
2478
2479
Steve Block44f0eee2011-05-26 01:26:41 +01002480void Assembler::div_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2481 GenInstrRegister(COP1, D, ft, fs, fd, DIV_D);
2482}
2483
2484
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002485void Assembler::abs_s(FPURegister fd, FPURegister fs) {
2486 GenInstrRegister(COP1, S, f0, fs, fd, ABS_S);
2487}
2488
2489
Steve Block44f0eee2011-05-26 01:26:41 +01002490void Assembler::abs_d(FPURegister fd, FPURegister fs) {
2491 GenInstrRegister(COP1, D, f0, fs, fd, ABS_D);
2492}
2493
2494
2495void Assembler::mov_d(FPURegister fd, FPURegister fs) {
2496 GenInstrRegister(COP1, D, f0, fs, fd, MOV_D);
2497}
2498
2499
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002500void Assembler::mov_s(FPURegister fd, FPURegister fs) {
2501 GenInstrRegister(COP1, S, f0, fs, fd, MOV_S);
2502}
2503
2504
2505void Assembler::neg_s(FPURegister fd, FPURegister fs) {
2506 GenInstrRegister(COP1, S, f0, fs, fd, NEG_S);
2507}
2508
2509
Steve Block44f0eee2011-05-26 01:26:41 +01002510void Assembler::neg_d(FPURegister fd, FPURegister fs) {
2511 GenInstrRegister(COP1, D, f0, fs, fd, NEG_D);
2512}
2513
2514
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002515void Assembler::sqrt_s(FPURegister fd, FPURegister fs) {
2516 GenInstrRegister(COP1, S, f0, fs, fd, SQRT_S);
2517}
2518
2519
Steve Block44f0eee2011-05-26 01:26:41 +01002520void Assembler::sqrt_d(FPURegister fd, FPURegister fs) {
2521 GenInstrRegister(COP1, D, f0, fs, fd, SQRT_D);
Andrei Popescu31002712010-02-23 13:46:05 +00002522}
2523
2524
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002525void Assembler::rsqrt_s(FPURegister fd, FPURegister fs) {
2526 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
2527 GenInstrRegister(COP1, S, f0, fs, fd, RSQRT_S);
2528}
2529
2530
2531void Assembler::rsqrt_d(FPURegister fd, FPURegister fs) {
2532 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
2533 GenInstrRegister(COP1, D, f0, fs, fd, RSQRT_D);
2534}
2535
2536
2537void Assembler::recip_d(FPURegister fd, FPURegister fs) {
2538 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
2539 GenInstrRegister(COP1, D, f0, fs, fd, RECIP_D);
2540}
2541
2542
2543void Assembler::recip_s(FPURegister fd, FPURegister fs) {
2544 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
2545 GenInstrRegister(COP1, S, f0, fs, fd, RECIP_S);
2546}
2547
2548
Andrei Popescu31002712010-02-23 13:46:05 +00002549// Conversions.
2550
2551void Assembler::cvt_w_s(FPURegister fd, FPURegister fs) {
2552 GenInstrRegister(COP1, S, f0, fs, fd, CVT_W_S);
2553}
2554
2555
2556void Assembler::cvt_w_d(FPURegister fd, FPURegister fs) {
2557 GenInstrRegister(COP1, D, f0, fs, fd, CVT_W_D);
2558}
2559
2560
Steve Block44f0eee2011-05-26 01:26:41 +01002561void Assembler::trunc_w_s(FPURegister fd, FPURegister fs) {
2562 GenInstrRegister(COP1, S, f0, fs, fd, TRUNC_W_S);
2563}
2564
2565
2566void Assembler::trunc_w_d(FPURegister fd, FPURegister fs) {
2567 GenInstrRegister(COP1, D, f0, fs, fd, TRUNC_W_D);
2568}
2569
2570
2571void Assembler::round_w_s(FPURegister fd, FPURegister fs) {
2572 GenInstrRegister(COP1, S, f0, fs, fd, ROUND_W_S);
2573}
2574
2575
2576void Assembler::round_w_d(FPURegister fd, FPURegister fs) {
2577 GenInstrRegister(COP1, D, f0, fs, fd, ROUND_W_D);
2578}
2579
2580
2581void Assembler::floor_w_s(FPURegister fd, FPURegister fs) {
2582 GenInstrRegister(COP1, S, f0, fs, fd, FLOOR_W_S);
2583}
2584
2585
2586void Assembler::floor_w_d(FPURegister fd, FPURegister fs) {
2587 GenInstrRegister(COP1, D, f0, fs, fd, FLOOR_W_D);
2588}
2589
2590
2591void Assembler::ceil_w_s(FPURegister fd, FPURegister fs) {
2592 GenInstrRegister(COP1, S, f0, fs, fd, CEIL_W_S);
2593}
2594
2595
2596void Assembler::ceil_w_d(FPURegister fd, FPURegister fs) {
2597 GenInstrRegister(COP1, D, f0, fs, fd, CEIL_W_D);
2598}
2599
2600
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002601void Assembler::rint_s(FPURegister fd, FPURegister fs) { rint(S, fd, fs); }
2602
2603
2604void Assembler::rint(SecondaryField fmt, FPURegister fd, FPURegister fs) {
2605 DCHECK(IsMipsArchVariant(kMips32r6));
2606 DCHECK((fmt == D) || (fmt == S));
2607 GenInstrRegister(COP1, fmt, f0, fs, fd, RINT);
2608}
2609
2610
2611void Assembler::rint_d(FPURegister fd, FPURegister fs) { rint(D, fd, fs); }
2612
2613
Andrei Popescu31002712010-02-23 13:46:05 +00002614void Assembler::cvt_l_s(FPURegister fd, FPURegister fs) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002615 DCHECK((IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) &&
2616 IsFp64Mode());
Andrei Popescu31002712010-02-23 13:46:05 +00002617 GenInstrRegister(COP1, S, f0, fs, fd, CVT_L_S);
2618}
2619
2620
2621void Assembler::cvt_l_d(FPURegister fd, FPURegister fs) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002622 DCHECK((IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) &&
2623 IsFp64Mode());
Andrei Popescu31002712010-02-23 13:46:05 +00002624 GenInstrRegister(COP1, D, f0, fs, fd, CVT_L_D);
2625}
2626
2627
Steve Block44f0eee2011-05-26 01:26:41 +01002628void Assembler::trunc_l_s(FPURegister fd, FPURegister fs) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002629 DCHECK((IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) &&
2630 IsFp64Mode());
Steve Block44f0eee2011-05-26 01:26:41 +01002631 GenInstrRegister(COP1, S, f0, fs, fd, TRUNC_L_S);
2632}
2633
2634
2635void Assembler::trunc_l_d(FPURegister fd, FPURegister fs) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002636 DCHECK((IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) &&
2637 IsFp64Mode());
Steve Block44f0eee2011-05-26 01:26:41 +01002638 GenInstrRegister(COP1, D, f0, fs, fd, TRUNC_L_D);
2639}
2640
2641
2642void Assembler::round_l_s(FPURegister fd, FPURegister fs) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002643 DCHECK((IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) &&
2644 IsFp64Mode());
Steve Block44f0eee2011-05-26 01:26:41 +01002645 GenInstrRegister(COP1, S, f0, fs, fd, ROUND_L_S);
2646}
2647
2648
2649void Assembler::round_l_d(FPURegister fd, FPURegister fs) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002650 DCHECK((IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) &&
2651 IsFp64Mode());
Steve Block44f0eee2011-05-26 01:26:41 +01002652 GenInstrRegister(COP1, D, f0, fs, fd, ROUND_L_D);
2653}
2654
2655
2656void Assembler::floor_l_s(FPURegister fd, FPURegister fs) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002657 DCHECK((IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) &&
2658 IsFp64Mode());
Steve Block44f0eee2011-05-26 01:26:41 +01002659 GenInstrRegister(COP1, S, f0, fs, fd, FLOOR_L_S);
2660}
2661
2662
2663void Assembler::floor_l_d(FPURegister fd, FPURegister fs) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002664 DCHECK((IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) &&
2665 IsFp64Mode());
Steve Block44f0eee2011-05-26 01:26:41 +01002666 GenInstrRegister(COP1, D, f0, fs, fd, FLOOR_L_D);
2667}
2668
2669
2670void Assembler::ceil_l_s(FPURegister fd, FPURegister fs) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002671 DCHECK((IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) &&
2672 IsFp64Mode());
Steve Block44f0eee2011-05-26 01:26:41 +01002673 GenInstrRegister(COP1, S, f0, fs, fd, CEIL_L_S);
2674}
2675
2676
2677void Assembler::ceil_l_d(FPURegister fd, FPURegister fs) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002678 DCHECK((IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) &&
2679 IsFp64Mode());
Steve Block44f0eee2011-05-26 01:26:41 +01002680 GenInstrRegister(COP1, D, f0, fs, fd, CEIL_L_D);
2681}
2682
2683
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002684void Assembler::class_s(FPURegister fd, FPURegister fs) {
2685 DCHECK(IsMipsArchVariant(kMips32r6));
2686 GenInstrRegister(COP1, S, f0, fs, fd, CLASS_S);
2687}
2688
2689
2690void Assembler::class_d(FPURegister fd, FPURegister fs) {
2691 DCHECK(IsMipsArchVariant(kMips32r6));
2692 GenInstrRegister(COP1, D, f0, fs, fd, CLASS_D);
2693}
2694
2695
2696void Assembler::min(SecondaryField fmt, FPURegister fd, FPURegister fs,
2697 FPURegister ft) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002698 DCHECK(IsMipsArchVariant(kMips32r6));
2699 DCHECK((fmt == D) || (fmt == S));
2700 GenInstrRegister(COP1, fmt, ft, fs, fd, MIN);
2701}
2702
2703
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002704void Assembler::mina(SecondaryField fmt, FPURegister fd, FPURegister fs,
2705 FPURegister ft) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002706 DCHECK(IsMipsArchVariant(kMips32r6));
2707 DCHECK((fmt == D) || (fmt == S));
2708 GenInstrRegister(COP1, fmt, ft, fs, fd, MINA);
2709}
2710
2711
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002712void Assembler::max(SecondaryField fmt, FPURegister fd, FPURegister fs,
2713 FPURegister ft) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002714 DCHECK(IsMipsArchVariant(kMips32r6));
2715 DCHECK((fmt == D) || (fmt == S));
2716 GenInstrRegister(COP1, fmt, ft, fs, fd, MAX);
2717}
2718
2719
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002720void Assembler::maxa(SecondaryField fmt, FPURegister fd, FPURegister fs,
2721 FPURegister ft) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002722 DCHECK(IsMipsArchVariant(kMips32r6));
2723 DCHECK((fmt == D) || (fmt == S));
2724 GenInstrRegister(COP1, fmt, ft, fs, fd, MAXA);
2725}
2726
2727
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002728void Assembler::min_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2729 min(S, fd, fs, ft);
2730}
2731
2732
2733void Assembler::min_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2734 min(D, fd, fs, ft);
2735}
2736
2737
2738void Assembler::max_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2739 max(S, fd, fs, ft);
2740}
2741
2742
2743void Assembler::max_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2744 max(D, fd, fs, ft);
2745}
2746
2747
2748void Assembler::mina_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2749 mina(S, fd, fs, ft);
2750}
2751
2752
2753void Assembler::mina_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2754 mina(D, fd, fs, ft);
2755}
2756
2757
2758void Assembler::maxa_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2759 maxa(S, fd, fs, ft);
2760}
2761
2762
2763void Assembler::maxa_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2764 maxa(D, fd, fs, ft);
2765}
2766
2767
Andrei Popescu31002712010-02-23 13:46:05 +00002768void Assembler::cvt_s_w(FPURegister fd, FPURegister fs) {
2769 GenInstrRegister(COP1, W, f0, fs, fd, CVT_S_W);
2770}
2771
2772
2773void Assembler::cvt_s_l(FPURegister fd, FPURegister fs) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002774 DCHECK((IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) &&
2775 IsFp64Mode());
Andrei Popescu31002712010-02-23 13:46:05 +00002776 GenInstrRegister(COP1, L, f0, fs, fd, CVT_S_L);
2777}
2778
2779
2780void Assembler::cvt_s_d(FPURegister fd, FPURegister fs) {
2781 GenInstrRegister(COP1, D, f0, fs, fd, CVT_S_D);
2782}
2783
2784
2785void Assembler::cvt_d_w(FPURegister fd, FPURegister fs) {
2786 GenInstrRegister(COP1, W, f0, fs, fd, CVT_D_W);
2787}
2788
2789
2790void Assembler::cvt_d_l(FPURegister fd, FPURegister fs) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002791 DCHECK((IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) &&
2792 IsFp64Mode());
Andrei Popescu31002712010-02-23 13:46:05 +00002793 GenInstrRegister(COP1, L, f0, fs, fd, CVT_D_L);
2794}
2795
2796
2797void Assembler::cvt_d_s(FPURegister fd, FPURegister fs) {
2798 GenInstrRegister(COP1, S, f0, fs, fd, CVT_D_S);
2799}
2800
2801
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002802// Conditions for >= MIPSr6.
2803void Assembler::cmp(FPUCondition cond, SecondaryField fmt,
2804 FPURegister fd, FPURegister fs, FPURegister ft) {
2805 DCHECK(IsMipsArchVariant(kMips32r6));
2806 DCHECK((fmt & ~(31 << kRsShift)) == 0);
2807 Instr instr = COP1 | fmt | ft.code() << kFtShift |
2808 fs.code() << kFsShift | fd.code() << kFdShift | (0 << 5) | cond;
2809 emit(instr);
2810}
2811
2812
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002813void Assembler::cmp_s(FPUCondition cond, FPURegister fd, FPURegister fs,
2814 FPURegister ft) {
2815 cmp(cond, W, fd, fs, ft);
2816}
2817
2818void Assembler::cmp_d(FPUCondition cond, FPURegister fd, FPURegister fs,
2819 FPURegister ft) {
2820 cmp(cond, L, fd, fs, ft);
2821}
2822
2823
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002824void Assembler::bc1eqz(int16_t offset, FPURegister ft) {
2825 DCHECK(IsMipsArchVariant(kMips32r6));
2826 Instr instr = COP1 | BC1EQZ | ft.code() << kFtShift | (offset & kImm16Mask);
2827 emit(instr);
2828}
2829
2830
2831void Assembler::bc1nez(int16_t offset, FPURegister ft) {
2832 DCHECK(IsMipsArchVariant(kMips32r6));
2833 Instr instr = COP1 | BC1NEZ | ft.code() << kFtShift | (offset & kImm16Mask);
2834 emit(instr);
2835}
2836
2837
2838// Conditions for < MIPSr6.
Andrei Popescu31002712010-02-23 13:46:05 +00002839void Assembler::c(FPUCondition cond, SecondaryField fmt,
Steve Block44f0eee2011-05-26 01:26:41 +01002840 FPURegister fs, FPURegister ft, uint16_t cc) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002841 DCHECK(is_uint3(cc));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002842 DCHECK(fmt == S || fmt == D);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002843 DCHECK((fmt & ~(31 << kRsShift)) == 0);
Andrei Popescu31002712010-02-23 13:46:05 +00002844 Instr instr = COP1 | fmt | ft.code() << 16 | fs.code() << kFsShift
2845 | cc << 8 | 3 << 4 | cond;
2846 emit(instr);
2847}
2848
2849
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002850void Assembler::c_s(FPUCondition cond, FPURegister fs, FPURegister ft,
2851 uint16_t cc) {
2852 c(cond, S, fs, ft, cc);
2853}
2854
2855
2856void Assembler::c_d(FPUCondition cond, FPURegister fs, FPURegister ft,
2857 uint16_t cc) {
2858 c(cond, D, fs, ft, cc);
2859}
2860
2861
Steve Block44f0eee2011-05-26 01:26:41 +01002862void Assembler::fcmp(FPURegister src1, const double src2,
2863 FPUCondition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002864 DCHECK(src2 == 0.0);
Steve Block44f0eee2011-05-26 01:26:41 +01002865 mtc1(zero_reg, f14);
2866 cvt_d_w(f14, f14);
2867 c(cond, D, src1, f14, 0);
2868}
2869
2870
Andrei Popescu31002712010-02-23 13:46:05 +00002871void Assembler::bc1f(int16_t offset, uint16_t cc) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002872 DCHECK(is_uint3(cc));
Andrei Popescu31002712010-02-23 13:46:05 +00002873 Instr instr = COP1 | BC1 | cc << 18 | 0 << 16 | (offset & kImm16Mask);
2874 emit(instr);
2875}
2876
2877
2878void Assembler::bc1t(int16_t offset, uint16_t cc) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002879 DCHECK(is_uint3(cc));
Andrei Popescu31002712010-02-23 13:46:05 +00002880 Instr instr = COP1 | BC1 | cc << 18 | 1 << 16 | (offset & kImm16Mask);
2881 emit(instr);
2882}
2883
2884
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002885int Assembler::RelocateInternalReference(RelocInfo::Mode rmode, byte* pc,
2886 intptr_t pc_delta) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002887 Instr instr = instr_at(pc);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002888
2889 if (RelocInfo::IsInternalReference(rmode)) {
2890 int32_t* p = reinterpret_cast<int32_t*>(pc);
2891 if (*p == 0) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002892 return 0; // Number of instructions patched.
2893 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002894 *p += pc_delta;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002895 return 1; // Number of instructions patched.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002896 } else {
2897 DCHECK(RelocInfo::IsInternalReferenceEncoded(rmode));
2898 if (IsLui(instr)) {
Ben Murdochda12d292016-06-02 14:46:10 +01002899 Instr instr1 = instr_at(pc + 0 * Assembler::kInstrSize);
2900 Instr instr2 = instr_at(pc + 1 * Assembler::kInstrSize);
2901 DCHECK(IsOri(instr2) || IsJicOrJialc(instr2));
2902 int32_t imm;
2903 if (IsJicOrJialc(instr2)) {
2904 imm = CreateTargetAddress(instr1, instr2);
2905 } else {
2906 imm = (instr1 & static_cast<int32_t>(kImm16Mask)) << kLuiShift;
2907 imm |= (instr2 & static_cast<int32_t>(kImm16Mask));
2908 }
2909
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002910 if (imm == kEndOfJumpChain) {
2911 return 0; // Number of instructions patched.
2912 }
2913 imm += pc_delta;
2914 DCHECK((imm & 3) == 0);
Ben Murdochda12d292016-06-02 14:46:10 +01002915 instr1 &= ~kImm16Mask;
2916 instr2 &= ~kImm16Mask;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002917
Ben Murdochda12d292016-06-02 14:46:10 +01002918 if (IsJicOrJialc(instr2)) {
2919 uint32_t lui_offset_u, jic_offset_u;
2920 Assembler::UnpackTargetAddressUnsigned(imm, lui_offset_u, jic_offset_u);
2921 instr_at_put(pc + 0 * Assembler::kInstrSize, instr1 | lui_offset_u);
2922 instr_at_put(pc + 1 * Assembler::kInstrSize, instr2 | jic_offset_u);
2923 } else {
2924 instr_at_put(pc + 0 * Assembler::kInstrSize,
2925 instr1 | ((imm >> kLuiShift) & kImm16Mask));
2926 instr_at_put(pc + 1 * Assembler::kInstrSize,
2927 instr2 | (imm & kImm16Mask));
2928 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002929 return 2; // Number of instructions patched.
2930 } else {
2931 UNREACHABLE();
2932 return 0;
2933 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002934 }
2935}
2936
2937
Andrei Popescu31002712010-02-23 13:46:05 +00002938void Assembler::GrowBuffer() {
2939 if (!own_buffer_) FATAL("external code buffer is too small");
2940
2941 // Compute new buffer size.
Steve Block44f0eee2011-05-26 01:26:41 +01002942 CodeDesc desc; // The new buffer.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002943 if (buffer_size_ < 1 * MB) {
Andrei Popescu31002712010-02-23 13:46:05 +00002944 desc.buffer_size = 2*buffer_size_;
2945 } else {
2946 desc.buffer_size = buffer_size_ + 1*MB;
2947 }
Steve Block44f0eee2011-05-26 01:26:41 +01002948 CHECK_GT(desc.buffer_size, 0); // No overflow.
Andrei Popescu31002712010-02-23 13:46:05 +00002949
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002950 // Set up new buffer.
Andrei Popescu31002712010-02-23 13:46:05 +00002951 desc.buffer = NewArray<byte>(desc.buffer_size);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002952 desc.origin = this;
Andrei Popescu31002712010-02-23 13:46:05 +00002953
2954 desc.instr_size = pc_offset();
2955 desc.reloc_size = (buffer_ + buffer_size_) - reloc_info_writer.pos();
2956
2957 // Copy the data.
2958 int pc_delta = desc.buffer - buffer_;
2959 int rc_delta = (desc.buffer + desc.buffer_size) - (buffer_ + buffer_size_);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002960 MemMove(desc.buffer, buffer_, desc.instr_size);
2961 MemMove(reloc_info_writer.pos() + rc_delta, reloc_info_writer.pos(),
2962 desc.reloc_size);
Andrei Popescu31002712010-02-23 13:46:05 +00002963
2964 // Switch buffers.
2965 DeleteArray(buffer_);
2966 buffer_ = desc.buffer;
2967 buffer_size_ = desc.buffer_size;
2968 pc_ += pc_delta;
2969 reloc_info_writer.Reposition(reloc_info_writer.pos() + rc_delta,
2970 reloc_info_writer.last_pc() + pc_delta);
2971
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002972 // Relocate runtime entries.
2973 for (RelocIterator it(desc); !it.done(); it.next()) {
2974 RelocInfo::Mode rmode = it.rinfo()->rmode();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002975 if (rmode == RelocInfo::INTERNAL_REFERENCE_ENCODED ||
2976 rmode == RelocInfo::INTERNAL_REFERENCE) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002977 byte* p = reinterpret_cast<byte*>(it.rinfo()->pc());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002978 RelocateInternalReference(rmode, p, pc_delta);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002979 }
2980 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002981 DCHECK(!overflow());
Andrei Popescu31002712010-02-23 13:46:05 +00002982}
2983
2984
Steve Block44f0eee2011-05-26 01:26:41 +01002985void Assembler::db(uint8_t data) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002986 CheckForEmitInForbiddenSlot();
2987 EmitHelper(data);
Steve Block44f0eee2011-05-26 01:26:41 +01002988}
2989
2990
2991void Assembler::dd(uint32_t data) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002992 CheckForEmitInForbiddenSlot();
2993 EmitHelper(data);
Steve Block44f0eee2011-05-26 01:26:41 +01002994}
2995
2996
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002997void Assembler::dq(uint64_t data) {
2998 CheckForEmitInForbiddenSlot();
2999 EmitHelper(data);
3000}
3001
3002
3003void Assembler::dd(Label* label) {
3004 uint32_t data;
3005 CheckForEmitInForbiddenSlot();
3006 if (label->is_bound()) {
3007 data = reinterpret_cast<uint32_t>(buffer_ + label->pos());
3008 } else {
3009 data = jump_address(label);
Ben Murdochc5610432016-08-08 18:44:38 +01003010 unbound_labels_count_++;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003011 internal_reference_positions_.insert(label->pos());
3012 }
3013 RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE);
3014 EmitHelper(data);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003015}
3016
3017
Andrei Popescu31002712010-02-23 13:46:05 +00003018void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003019 // We do not try to reuse pool constants.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003020 RelocInfo rinfo(isolate(), pc_, rmode, data, NULL);
3021 if (rmode >= RelocInfo::COMMENT &&
Ben Murdochda12d292016-06-02 14:46:10 +01003022 rmode <= RelocInfo::DEBUG_BREAK_SLOT_AT_TAIL_CALL) {
Andrei Popescu31002712010-02-23 13:46:05 +00003023 // Adjust code for new modes.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003024 DCHECK(RelocInfo::IsDebugBreakSlot(rmode)
Andrei Popescu31002712010-02-23 13:46:05 +00003025 || RelocInfo::IsComment(rmode)
3026 || RelocInfo::IsPosition(rmode));
3027 // These modes do not need an entry in the constant pool.
3028 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003029 if (!RelocInfo::IsNone(rinfo.rmode())) {
Andrei Popescu31002712010-02-23 13:46:05 +00003030 // Don't record external references unless the heap will be serialized.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003031 if (rmode == RelocInfo::EXTERNAL_REFERENCE &&
3032 !serializer_enabled() && !emit_debug_code()) {
3033 return;
Andrei Popescu31002712010-02-23 13:46:05 +00003034 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003035 DCHECK(buffer_space() >= kMaxRelocSize); // Too late to grow buffer here.
Ben Murdoch257744e2011-11-30 15:57:28 +00003036 if (rmode == RelocInfo::CODE_TARGET_WITH_ID) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003037 RelocInfo reloc_info_with_ast_id(isolate(), pc_, rmode,
3038 RecordedAstId().ToInt(), NULL);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003039 ClearRecordedAstId();
Ben Murdoch257744e2011-11-30 15:57:28 +00003040 reloc_info_writer.Write(&reloc_info_with_ast_id);
3041 } else {
3042 reloc_info_writer.Write(&rinfo);
3043 }
Andrei Popescu31002712010-02-23 13:46:05 +00003044 }
3045}
3046
3047
Steve Block44f0eee2011-05-26 01:26:41 +01003048void Assembler::BlockTrampolinePoolFor(int instructions) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003049 CheckTrampolinePoolQuick(instructions);
Steve Block44f0eee2011-05-26 01:26:41 +01003050 BlockTrampolinePoolBefore(pc_offset() + instructions * kInstrSize);
3051}
3052
3053
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003054void Assembler::CheckTrampolinePool() {
Steve Block44f0eee2011-05-26 01:26:41 +01003055 // Some small sequences of instructions must not be broken up by the
3056 // insertion of a trampoline pool; such sequences are protected by setting
3057 // either trampoline_pool_blocked_nesting_ or no_trampoline_pool_before_,
3058 // which are both checked here. Also, recursive calls to CheckTrampolinePool
3059 // are blocked by trampoline_pool_blocked_nesting_.
3060 if ((trampoline_pool_blocked_nesting_ > 0) ||
3061 (pc_offset() < no_trampoline_pool_before_)) {
3062 // Emission is currently blocked; make sure we try again as soon as
3063 // possible.
3064 if (trampoline_pool_blocked_nesting_ > 0) {
3065 next_buffer_check_ = pc_offset() + kInstrSize;
3066 } else {
3067 next_buffer_check_ = no_trampoline_pool_before_;
3068 }
3069 return;
3070 }
3071
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003072 DCHECK(!trampoline_emitted_);
3073 DCHECK(unbound_labels_count_ >= 0);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003074 if (unbound_labels_count_ > 0) {
3075 // First we emit jump (2 instructions), then we emit trampoline pool.
3076 { BlockTrampolinePoolScope block_trampoline_pool(this);
3077 Label after_pool;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003078 if (IsMipsArchVariant(kMips32r6)) {
3079 bc(&after_pool);
3080 } else {
3081 b(&after_pool);
3082 nop();
3083 }
Steve Block44f0eee2011-05-26 01:26:41 +01003084
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003085 int pool_start = pc_offset();
Ben Murdochda12d292016-06-02 14:46:10 +01003086 if (IsMipsArchVariant(kMips32r6)) {
3087 for (int i = 0; i < unbound_labels_count_; i++) {
3088 uint32_t imm32;
3089 imm32 = jump_address(&after_pool);
3090 uint32_t lui_offset, jic_offset;
3091 UnpackTargetAddressUnsigned(imm32, lui_offset, jic_offset);
3092 {
3093 BlockGrowBufferScope block_buf_growth(this);
3094 // Buffer growth (and relocation) must be blocked for internal
3095 // references until associated instructions are emitted and
3096 // available to be patched.
3097 RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE_ENCODED);
3098 lui(at, lui_offset);
3099 jic(at, jic_offset);
3100 }
3101 CheckBuffer();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003102 }
Ben Murdochda12d292016-06-02 14:46:10 +01003103 } else {
3104 for (int i = 0; i < unbound_labels_count_; i++) {
3105 uint32_t imm32;
3106 imm32 = jump_address(&after_pool);
3107 {
3108 BlockGrowBufferScope block_buf_growth(this);
3109 // Buffer growth (and relocation) must be blocked for internal
3110 // references until associated instructions are emitted and
3111 // available to be patched.
3112 RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE_ENCODED);
3113 lui(at, (imm32 & kHiMask) >> kLuiShift);
3114 ori(at, at, (imm32 & kImm16Mask));
3115 }
3116 CheckBuffer();
3117 jr(at);
3118 nop();
3119 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003120 }
3121 bind(&after_pool);
3122 trampoline_ = Trampoline(pool_start, unbound_labels_count_);
3123
3124 trampoline_emitted_ = true;
3125 // As we are only going to emit trampoline once, we need to prevent any
3126 // further emission.
3127 next_buffer_check_ = kMaxInt;
3128 }
3129 } else {
3130 // Number of branches to unbound label at this point is zero, so we can
3131 // move next buffer check to maximum.
3132 next_buffer_check_ = pc_offset() +
3133 kMaxBranchOffset - kTrampolineSlotsSize * 16;
Steve Block44f0eee2011-05-26 01:26:41 +01003134 }
3135 return;
3136}
3137
3138
Andrei Popescu31002712010-02-23 13:46:05 +00003139Address Assembler::target_address_at(Address pc) {
3140 Instr instr1 = instr_at(pc);
3141 Instr instr2 = instr_at(pc + kInstrSize);
Ben Murdoch257744e2011-11-30 15:57:28 +00003142 // Interpret 2 instructions generated by li: lui/ori
Ben Murdochda12d292016-06-02 14:46:10 +01003143 if (IsLui(instr1) && IsOri(instr2)) {
Ben Murdoch257744e2011-11-30 15:57:28 +00003144 // Assemble the 32 bit value.
Ben Murdochda12d292016-06-02 14:46:10 +01003145 return reinterpret_cast<Address>((GetImmediate16(instr1) << kLuiShift) |
3146 GetImmediate16(instr2));
Andrei Popescu31002712010-02-23 13:46:05 +00003147 }
3148
Ben Murdoch257744e2011-11-30 15:57:28 +00003149 // We should never get here, force a bad address if we do.
Andrei Popescu31002712010-02-23 13:46:05 +00003150 UNREACHABLE();
3151 return (Address)0x0;
3152}
3153
3154
Ben Murdochdb1b4382012-04-26 19:03:50 +01003155// MIPS and ia32 use opposite encoding for qNaN and sNaN, such that ia32
3156// qNaN is a MIPS sNaN, and ia32 sNaN is MIPS qNaN. If running from a heap
3157// snapshot generated on ia32, the resulting MIPS sNaN must be quieted.
3158// OS::nan_value() returns a qNaN.
3159void Assembler::QuietNaN(HeapObject* object) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003160 HeapNumber::cast(object)->set_value(std::numeric_limits<double>::quiet_NaN());
Ben Murdochdb1b4382012-04-26 19:03:50 +01003161}
3162
3163
Ben Murdoch589d6972011-11-30 16:04:58 +00003164// On Mips, a target address is stored in a lui/ori instruction pair, each
3165// of which load 16 bits of the 32-bit address to a register.
3166// Patching the address must replace both instr, and flush the i-cache.
Ben Murdochda12d292016-06-02 14:46:10 +01003167// On r6, target address is stored in a lui/jic pair, and both instr have to be
3168// patched.
Ben Murdoch589d6972011-11-30 16:04:58 +00003169//
3170// There is an optimization below, which emits a nop when the address
3171// fits in just 16 bits. This is unlikely to help, and should be benchmarked,
3172// and possibly removed.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003173void Assembler::set_target_address_at(Isolate* isolate, Address pc,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003174 Address target,
3175 ICacheFlushMode icache_flush_mode) {
Andrei Popescu31002712010-02-23 13:46:05 +00003176 Instr instr2 = instr_at(pc + kInstrSize);
Ben Murdoch257744e2011-11-30 15:57:28 +00003177 uint32_t rt_code = GetRtField(instr2);
Andrei Popescu31002712010-02-23 13:46:05 +00003178 uint32_t* p = reinterpret_cast<uint32_t*>(pc);
3179 uint32_t itarget = reinterpret_cast<uint32_t>(target);
3180
Ben Murdoch589d6972011-11-30 16:04:58 +00003181#ifdef DEBUG
3182 // Check we have the result from a li macro-instruction, using instr pair.
3183 Instr instr1 = instr_at(pc);
Ben Murdochda12d292016-06-02 14:46:10 +01003184 CHECK(IsLui(instr1) && (IsOri(instr2) || IsJicOrJialc(instr2)));
Ben Murdoch589d6972011-11-30 16:04:58 +00003185#endif
3186
Ben Murdochda12d292016-06-02 14:46:10 +01003187 if (IsJicOrJialc(instr2)) {
3188 // Must use 2 instructions to insure patchable code => use lui and jic
3189 uint32_t lui_offset, jic_offset;
3190 Assembler::UnpackTargetAddressUnsigned(itarget, lui_offset, jic_offset);
Andrei Popescu31002712010-02-23 13:46:05 +00003191
Ben Murdochda12d292016-06-02 14:46:10 +01003192 *p &= ~kImm16Mask;
3193 *(p + 1) &= ~kImm16Mask;
3194
3195 *p |= lui_offset;
3196 *(p + 1) |= jic_offset;
3197
3198 } else {
3199 // Must use 2 instructions to insure patchable code => just use lui and ori.
3200 // lui rt, upper-16.
3201 // ori rt rt, lower-16.
3202 *p = LUI | rt_code | ((itarget & kHiMask) >> kLuiShift);
3203 *(p + 1) = ORI | rt_code | (rt_code << 5) | (itarget & kImm16Mask);
3204 }
Ben Murdoch589d6972011-11-30 16:04:58 +00003205
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003206 if (icache_flush_mode != SKIP_ICACHE_FLUSH) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003207 Assembler::FlushICache(isolate, pc, 2 * sizeof(int32_t));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003208 }
Andrei Popescu31002712010-02-23 13:46:05 +00003209}
3210
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003211} // namespace internal
3212} // namespace v8
Andrei Popescu31002712010-02-23 13:46:05 +00003213
Leon Clarkef7060e22010-06-03 12:02:55 +01003214#endif // V8_TARGET_ARCH_MIPS