blob: 8bda17c9088be5c1100582c52db5b8b26458035d [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
Ben Murdoch61f157c2016-09-16 13:49:30 +0100197Address RelocInfo::wasm_global_reference() {
198 DCHECK(IsWasmGlobalReference(rmode_));
199 return Assembler::target_address_at(pc_, host_);
200}
201
Ben Murdochc5610432016-08-08 18:44:38 +0100202uint32_t RelocInfo::wasm_memory_size_reference() {
203 DCHECK(IsWasmMemorySizeReference(rmode_));
204 return reinterpret_cast<uint32_t>(Assembler::target_address_at(pc_, host_));
205}
206
Ben Murdoch61f157c2016-09-16 13:49:30 +0100207void RelocInfo::unchecked_update_wasm_memory_reference(
208 Address address, ICacheFlushMode flush_mode) {
209 Assembler::set_target_address_at(isolate_, pc_, host_, address, flush_mode);
210}
211
212void RelocInfo::unchecked_update_wasm_memory_size(uint32_t size,
213 ICacheFlushMode flush_mode) {
214 Assembler::set_target_address_at(isolate_, pc_, host_,
215 reinterpret_cast<Address>(size), flush_mode);
Ben Murdochc5610432016-08-08 18:44:38 +0100216}
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000217
Andrei Popescu31002712010-02-23 13:46:05 +0000218// -----------------------------------------------------------------------------
219// Implementation of Operand and MemOperand.
220// See assembler-mips-inl.h for inlined constructors.
221
222Operand::Operand(Handle<Object> handle) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000223 AllowDeferredHandleDereference using_raw_address;
Andrei Popescu31002712010-02-23 13:46:05 +0000224 rm_ = no_reg;
225 // Verify all Objects referred by code are NOT in new space.
226 Object* obj = *handle;
Andrei Popescu31002712010-02-23 13:46:05 +0000227 if (obj->IsHeapObject()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000228 DCHECK(!HeapObject::cast(obj)->GetHeap()->InNewSpace(obj));
Andrei Popescu31002712010-02-23 13:46:05 +0000229 imm32_ = reinterpret_cast<intptr_t>(handle.location());
230 rmode_ = RelocInfo::EMBEDDED_OBJECT;
231 } else {
232 // No relocation needed.
233 imm32_ = reinterpret_cast<intptr_t>(obj);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000234 rmode_ = RelocInfo::NONE32;
Andrei Popescu31002712010-02-23 13:46:05 +0000235 }
236}
237
Steve Block44f0eee2011-05-26 01:26:41 +0100238
239MemOperand::MemOperand(Register rm, int32_t offset) : Operand(rm) {
Andrei Popescu31002712010-02-23 13:46:05 +0000240 offset_ = offset;
241}
242
243
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000244MemOperand::MemOperand(Register rm, int32_t unit, int32_t multiplier,
245 OffsetAddend offset_addend) : Operand(rm) {
246 offset_ = unit * multiplier + offset_addend;
247}
248
249
Andrei Popescu31002712010-02-23 13:46:05 +0000250// -----------------------------------------------------------------------------
Steve Block44f0eee2011-05-26 01:26:41 +0100251// Specific instructions, constants, and masks.
Andrei Popescu31002712010-02-23 13:46:05 +0000252
Steve Block44f0eee2011-05-26 01:26:41 +0100253static const int kNegOffset = 0x00008000;
254// addiu(sp, sp, 4) aka Pop() operation or part of Pop(r)
255// operations as post-increment of sp.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000256const Instr kPopInstruction = ADDIU | (Register::kCode_sp << kRsShift) |
257 (Register::kCode_sp << kRtShift) |
258 (kPointerSize & kImm16Mask); // NOLINT
Steve Block44f0eee2011-05-26 01:26:41 +0100259// addiu(sp, sp, -4) part of Push(r) operation as pre-decrement of sp.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000260const Instr kPushInstruction = ADDIU | (Register::kCode_sp << kRsShift) |
261 (Register::kCode_sp << kRtShift) |
262 (-kPointerSize & kImm16Mask); // NOLINT
Steve Block44f0eee2011-05-26 01:26:41 +0100263// sw(r, MemOperand(sp, 0))
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000264const Instr kPushRegPattern =
265 SW | (Register::kCode_sp << kRsShift) | (0 & kImm16Mask); // NOLINT
Steve Block44f0eee2011-05-26 01:26:41 +0100266// lw(r, MemOperand(sp, 0))
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000267const Instr kPopRegPattern =
268 LW | (Register::kCode_sp << kRsShift) | (0 & kImm16Mask); // NOLINT
Andrei Popescu31002712010-02-23 13:46:05 +0000269
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000270const Instr kLwRegFpOffsetPattern =
271 LW | (Register::kCode_fp << kRsShift) | (0 & kImm16Mask); // NOLINT
Steve Block44f0eee2011-05-26 01:26:41 +0100272
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000273const Instr kSwRegFpOffsetPattern =
274 SW | (Register::kCode_fp << kRsShift) | (0 & kImm16Mask); // NOLINT
Steve Block44f0eee2011-05-26 01:26:41 +0100275
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000276const Instr kLwRegFpNegOffsetPattern = LW | (Register::kCode_fp << kRsShift) |
277 (kNegOffset & kImm16Mask); // NOLINT
Steve Block44f0eee2011-05-26 01:26:41 +0100278
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000279const Instr kSwRegFpNegOffsetPattern = SW | (Register::kCode_fp << kRsShift) |
280 (kNegOffset & kImm16Mask); // NOLINT
Steve Block44f0eee2011-05-26 01:26:41 +0100281// A mask for the Rt register for push, pop, lw, sw instructions.
282const Instr kRtMask = kRtFieldMask;
283const Instr kLwSwInstrTypeMask = 0xffe00000;
284const Instr kLwSwInstrArgumentMask = ~kLwSwInstrTypeMask;
285const Instr kLwSwOffsetMask = kImm16Mask;
286
287
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000288Assembler::Assembler(Isolate* isolate, void* buffer, int buffer_size)
289 : AssemblerBase(isolate, buffer, buffer_size),
290 recorded_ast_id_(TypeFeedbackId::None()),
291 positions_recorder_(this) {
292 reloc_info_writer.Reposition(buffer_ + buffer_size_, pc_);
Steve Block44f0eee2011-05-26 01:26:41 +0100293
294 last_trampoline_pool_end_ = 0;
295 no_trampoline_pool_before_ = 0;
296 trampoline_pool_blocked_nesting_ = 0;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000297 // We leave space (16 * kTrampolineSlotsSize)
298 // for BlockTrampolinePoolScope buffer.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000299 next_buffer_check_ = FLAG_force_long_branches
300 ? kMaxInt : kMaxBranchOffset - kTrampolineSlotsSize * 16;
Ben Murdoch257744e2011-11-30 15:57:28 +0000301 internal_trampoline_exception_ = false;
302 last_bound_pos_ = 0;
303
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000304 trampoline_emitted_ = FLAG_force_long_branches;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000305 unbound_labels_count_ = 0;
306 block_buffer_growth_ = false;
307
308 ClearRecordedAstId();
Andrei Popescu31002712010-02-23 13:46:05 +0000309}
310
311
Andrei Popescu31002712010-02-23 13:46:05 +0000312void Assembler::GetCode(CodeDesc* desc) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100313 EmitForbiddenSlotInstruction();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000314 DCHECK(pc_ <= reloc_info_writer.pos()); // No overlap.
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100315 // Set up code descriptor.
Andrei Popescu31002712010-02-23 13:46:05 +0000316 desc->buffer = buffer_;
317 desc->buffer_size = buffer_size_;
318 desc->instr_size = pc_offset();
319 desc->reloc_size = (buffer_ + buffer_size_) - reloc_info_writer.pos();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000320 desc->origin = this;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000321 desc->constant_pool_size = 0;
Ben Murdoch61f157c2016-09-16 13:49:30 +0100322 desc->unwinding_info_size = 0;
323 desc->unwinding_info = nullptr;
Andrei Popescu31002712010-02-23 13:46:05 +0000324}
325
326
Steve Block44f0eee2011-05-26 01:26:41 +0100327void Assembler::Align(int m) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000328 DCHECK(m >= 4 && base::bits::IsPowerOfTwo32(m));
Ben Murdoch097c5b22016-05-18 11:27:45 +0100329 EmitForbiddenSlotInstruction();
Steve Block44f0eee2011-05-26 01:26:41 +0100330 while ((pc_offset() & (m - 1)) != 0) {
331 nop();
332 }
333}
334
335
336void Assembler::CodeTargetAlign() {
337 // No advantage to aligning branch/call targets to more than
338 // single instruction, that I am aware of.
339 Align(4);
340}
341
342
Ben Murdoch257744e2011-11-30 15:57:28 +0000343Register Assembler::GetRtReg(Instr instr) {
Steve Block44f0eee2011-05-26 01:26:41 +0100344 Register rt;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000345 rt.reg_code = (instr & kRtFieldMask) >> kRtShift;
Steve Block44f0eee2011-05-26 01:26:41 +0100346 return rt;
347}
348
349
Ben Murdoch257744e2011-11-30 15:57:28 +0000350Register Assembler::GetRsReg(Instr instr) {
351 Register rs;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000352 rs.reg_code = (instr & kRsFieldMask) >> kRsShift;
Ben Murdoch257744e2011-11-30 15:57:28 +0000353 return rs;
354}
355
356
357Register Assembler::GetRdReg(Instr instr) {
358 Register rd;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000359 rd.reg_code = (instr & kRdFieldMask) >> kRdShift;
Ben Murdoch257744e2011-11-30 15:57:28 +0000360 return rd;
361}
362
363
364uint32_t Assembler::GetRt(Instr instr) {
365 return (instr & kRtFieldMask) >> kRtShift;
366}
367
368
369uint32_t Assembler::GetRtField(Instr instr) {
370 return instr & kRtFieldMask;
371}
372
373
374uint32_t Assembler::GetRs(Instr instr) {
375 return (instr & kRsFieldMask) >> kRsShift;
376}
377
378
379uint32_t Assembler::GetRsField(Instr instr) {
380 return instr & kRsFieldMask;
381}
382
383
384uint32_t Assembler::GetRd(Instr instr) {
385 return (instr & kRdFieldMask) >> kRdShift;
386}
387
388
389uint32_t Assembler::GetRdField(Instr instr) {
390 return instr & kRdFieldMask;
391}
392
393
394uint32_t Assembler::GetSa(Instr instr) {
395 return (instr & kSaFieldMask) >> kSaShift;
396}
397
398
399uint32_t Assembler::GetSaField(Instr instr) {
400 return instr & kSaFieldMask;
401}
402
403
404uint32_t Assembler::GetOpcodeField(Instr instr) {
405 return instr & kOpcodeMask;
406}
407
408
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000409uint32_t Assembler::GetFunction(Instr instr) {
410 return (instr & kFunctionFieldMask) >> kFunctionShift;
411}
412
413
414uint32_t Assembler::GetFunctionField(Instr instr) {
415 return instr & kFunctionFieldMask;
416}
417
418
Ben Murdoch257744e2011-11-30 15:57:28 +0000419uint32_t Assembler::GetImmediate16(Instr instr) {
420 return instr & kImm16Mask;
421}
422
423
424uint32_t Assembler::GetLabelConst(Instr instr) {
425 return instr & ~kImm16Mask;
426}
427
428
Steve Block44f0eee2011-05-26 01:26:41 +0100429bool Assembler::IsPop(Instr instr) {
430 return (instr & ~kRtMask) == kPopRegPattern;
431}
432
433
434bool Assembler::IsPush(Instr instr) {
435 return (instr & ~kRtMask) == kPushRegPattern;
436}
437
438
439bool Assembler::IsSwRegFpOffset(Instr instr) {
440 return ((instr & kLwSwInstrTypeMask) == kSwRegFpOffsetPattern);
441}
442
443
444bool Assembler::IsLwRegFpOffset(Instr instr) {
445 return ((instr & kLwSwInstrTypeMask) == kLwRegFpOffsetPattern);
446}
447
448
449bool Assembler::IsSwRegFpNegOffset(Instr instr) {
450 return ((instr & (kLwSwInstrTypeMask | kNegOffset)) ==
451 kSwRegFpNegOffsetPattern);
452}
453
454
455bool Assembler::IsLwRegFpNegOffset(Instr instr) {
456 return ((instr & (kLwSwInstrTypeMask | kNegOffset)) ==
457 kLwRegFpNegOffsetPattern);
458}
459
460
Andrei Popescu31002712010-02-23 13:46:05 +0000461// Labels refer to positions in the (to be) generated code.
462// There are bound, linked, and unused labels.
463//
464// Bound labels refer to known positions in the already
465// generated code. pos() is the position the label refers to.
466//
467// Linked labels refer to unknown positions in the code
468// to be generated; pos() is the position of the last
469// instruction using the label.
470
Steve Block44f0eee2011-05-26 01:26:41 +0100471// The link chain is terminated by a value in the instruction of -1,
472// which is an otherwise illegal value (branch -1 is inf loop).
473// The instruction 16-bit offset field addresses 32-bit words, but in
474// code is conv to an 18-bit value addressing bytes, hence the -4 value.
Andrei Popescu31002712010-02-23 13:46:05 +0000475
Andrei Popescu31002712010-02-23 13:46:05 +0000476const int kEndOfChain = -4;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000477// Determines the end of the Jump chain (a subset of the label link chain).
478const int kEndOfJumpChain = 0;
Andrei Popescu31002712010-02-23 13:46:05 +0000479
Steve Block44f0eee2011-05-26 01:26:41 +0100480
481bool Assembler::IsBranch(Instr instr) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000482 uint32_t opcode = GetOpcodeField(instr);
483 uint32_t rt_field = GetRtField(instr);
484 uint32_t rs_field = GetRsField(instr);
Andrei Popescu31002712010-02-23 13:46:05 +0000485 // Checks if the instruction is a branch.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000486 bool isBranch =
487 opcode == BEQ || opcode == BNE || opcode == BLEZ || opcode == BGTZ ||
488 opcode == BEQL || opcode == BNEL || opcode == BLEZL || opcode == BGTZL ||
Andrei Popescu31002712010-02-23 13:46:05 +0000489 (opcode == REGIMM && (rt_field == BLTZ || rt_field == BGEZ ||
490 rt_field == BLTZAL || rt_field == BGEZAL)) ||
Steve Block44f0eee2011-05-26 01:26:41 +0100491 (opcode == COP1 && rs_field == BC1) || // Coprocessor branch.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000492 (opcode == COP1 && rs_field == BC1EQZ) ||
493 (opcode == COP1 && rs_field == BC1NEZ);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000494 if (!isBranch && IsMipsArchVariant(kMips32r6)) {
495 // All the 3 variants of POP10 (BOVC, BEQC, BEQZALC) and
496 // POP30 (BNVC, BNEC, BNEZALC) are branch ops.
497 isBranch |= opcode == POP10 || opcode == POP30 || opcode == BC ||
498 opcode == BALC ||
499 (opcode == POP66 && rs_field != 0) || // BEQZC
500 (opcode == POP76 && rs_field != 0); // BNEZC
501 }
502 return isBranch;
503}
504
505
506bool Assembler::IsBc(Instr instr) {
507 uint32_t opcode = GetOpcodeField(instr);
508 // Checks if the instruction is a BC or BALC.
509 return opcode == BC || opcode == BALC;
510}
511
512
513bool Assembler::IsBzc(Instr instr) {
514 uint32_t opcode = GetOpcodeField(instr);
515 // Checks if the instruction is BEQZC or BNEZC.
516 return (opcode == POP66 && GetRsField(instr) != 0) ||
517 (opcode == POP76 && GetRsField(instr) != 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000518}
519
520
521bool Assembler::IsEmittedConstant(Instr instr) {
522 uint32_t label_constant = GetLabelConst(instr);
523 return label_constant == 0; // Emitted label const in reg-exp engine.
Steve Block44f0eee2011-05-26 01:26:41 +0100524}
525
526
Ben Murdoch257744e2011-11-30 15:57:28 +0000527bool Assembler::IsBeq(Instr instr) {
528 return GetOpcodeField(instr) == BEQ;
529}
530
531
532bool Assembler::IsBne(Instr instr) {
533 return GetOpcodeField(instr) == BNE;
534}
535
536
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000537bool Assembler::IsBeqzc(Instr instr) {
538 uint32_t opcode = GetOpcodeField(instr);
539 return opcode == POP66 && GetRsField(instr) != 0;
540}
541
542
543bool Assembler::IsBnezc(Instr instr) {
544 uint32_t opcode = GetOpcodeField(instr);
545 return opcode == POP76 && GetRsField(instr) != 0;
546}
547
548
549bool Assembler::IsBeqc(Instr instr) {
550 uint32_t opcode = GetOpcodeField(instr);
551 uint32_t rs = GetRsField(instr);
552 uint32_t rt = GetRtField(instr);
553 return opcode == POP10 && rs != 0 && rs < rt; // && rt != 0
554}
555
556
557bool Assembler::IsBnec(Instr instr) {
558 uint32_t opcode = GetOpcodeField(instr);
559 uint32_t rs = GetRsField(instr);
560 uint32_t rt = GetRtField(instr);
561 return opcode == POP30 && rs != 0 && rs < rt; // && rt != 0
562}
563
Ben Murdochda12d292016-06-02 14:46:10 +0100564bool Assembler::IsJicOrJialc(Instr instr) {
565 uint32_t opcode = GetOpcodeField(instr);
566 uint32_t rs = GetRsField(instr);
567 return (opcode == POP66 || opcode == POP76) && rs == 0;
568}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000569
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000570bool Assembler::IsJump(Instr instr) {
571 uint32_t opcode = GetOpcodeField(instr);
572 uint32_t rt_field = GetRtField(instr);
573 uint32_t rd_field = GetRdField(instr);
574 uint32_t function_field = GetFunctionField(instr);
575 // Checks if the instruction is a jump.
576 return opcode == J || opcode == JAL ||
577 (opcode == SPECIAL && rt_field == 0 &&
578 ((function_field == JALR) || (rd_field == 0 && (function_field == JR))));
579}
580
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000581bool Assembler::IsJ(Instr instr) {
582 uint32_t opcode = GetOpcodeField(instr);
583 // Checks if the instruction is a jump.
584 return opcode == J;
585}
586
587
Ben Murdoch589d6972011-11-30 16:04:58 +0000588bool Assembler::IsJal(Instr instr) {
589 return GetOpcodeField(instr) == JAL;
590}
591
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000592
Ben Murdoch589d6972011-11-30 16:04:58 +0000593bool Assembler::IsJr(Instr instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000594 if (!IsMipsArchVariant(kMips32r6)) {
595 return GetOpcodeField(instr) == SPECIAL && GetFunctionField(instr) == JR;
596 } else {
597 return GetOpcodeField(instr) == SPECIAL &&
598 GetRdField(instr) == 0 && GetFunctionField(instr) == JALR;
599 }
Ben Murdoch589d6972011-11-30 16:04:58 +0000600}
601
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000602
Ben Murdoch589d6972011-11-30 16:04:58 +0000603bool Assembler::IsJalr(Instr instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000604 return GetOpcodeField(instr) == SPECIAL &&
605 GetRdField(instr) != 0 && GetFunctionField(instr) == JALR;
Ben Murdoch589d6972011-11-30 16:04:58 +0000606}
607
608
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000609bool Assembler::IsLui(Instr instr) {
610 uint32_t opcode = GetOpcodeField(instr);
611 // Checks if the instruction is a load upper immediate.
612 return opcode == LUI;
613}
614
615
616bool Assembler::IsOri(Instr instr) {
617 uint32_t opcode = GetOpcodeField(instr);
618 // Checks if the instruction is a load upper immediate.
619 return opcode == ORI;
620}
621
622
Steve Block44f0eee2011-05-26 01:26:41 +0100623bool Assembler::IsNop(Instr instr, unsigned int type) {
624 // See Assembler::nop(type).
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000625 DCHECK(type < 32);
Ben Murdoch257744e2011-11-30 15:57:28 +0000626 uint32_t opcode = GetOpcodeField(instr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000627 uint32_t function = GetFunctionField(instr);
Ben Murdoch257744e2011-11-30 15:57:28 +0000628 uint32_t rt = GetRt(instr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000629 uint32_t rd = GetRd(instr);
Ben Murdoch257744e2011-11-30 15:57:28 +0000630 uint32_t sa = GetSa(instr);
Steve Block44f0eee2011-05-26 01:26:41 +0100631
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000632 // Traditional mips nop == sll(zero_reg, zero_reg, 0)
633 // When marking non-zero type, use sll(zero_reg, at, type)
634 // to avoid use of mips ssnop and ehb special encodings
635 // of the sll instruction.
Steve Block44f0eee2011-05-26 01:26:41 +0100636
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000637 Register nop_rt_reg = (type == 0) ? zero_reg : at;
638 bool ret = (opcode == SPECIAL && function == SLL &&
639 rd == static_cast<uint32_t>(ToNumber(zero_reg)) &&
640 rt == static_cast<uint32_t>(ToNumber(nop_rt_reg)) &&
Steve Block44f0eee2011-05-26 01:26:41 +0100641 sa == type);
642
643 return ret;
644}
645
646
647int32_t Assembler::GetBranchOffset(Instr instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000648 DCHECK(IsBranch(instr));
649 return (static_cast<int16_t>(instr & kImm16Mask)) << 2;
Steve Block44f0eee2011-05-26 01:26:41 +0100650}
651
652
653bool Assembler::IsLw(Instr instr) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000654 return (static_cast<uint32_t>(instr & kOpcodeMask) == LW);
Steve Block44f0eee2011-05-26 01:26:41 +0100655}
656
657
658int16_t Assembler::GetLwOffset(Instr instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000659 DCHECK(IsLw(instr));
Steve Block44f0eee2011-05-26 01:26:41 +0100660 return ((instr & kImm16Mask));
661}
662
663
664Instr Assembler::SetLwOffset(Instr instr, int16_t offset) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000665 DCHECK(IsLw(instr));
Steve Block44f0eee2011-05-26 01:26:41 +0100666
667 // We actually create a new lw instruction based on the original one.
668 Instr temp_instr = LW | (instr & kRsFieldMask) | (instr & kRtFieldMask)
669 | (offset & kImm16Mask);
670
671 return temp_instr;
672}
673
674
675bool Assembler::IsSw(Instr instr) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000676 return (static_cast<uint32_t>(instr & kOpcodeMask) == SW);
Steve Block44f0eee2011-05-26 01:26:41 +0100677}
678
679
680Instr Assembler::SetSwOffset(Instr instr, int16_t offset) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000681 DCHECK(IsSw(instr));
Steve Block44f0eee2011-05-26 01:26:41 +0100682 return ((instr & ~kImm16Mask) | (offset & kImm16Mask));
683}
684
685
686bool Assembler::IsAddImmediate(Instr instr) {
687 return ((instr & kOpcodeMask) == ADDIU);
688}
689
690
691Instr Assembler::SetAddImmediateOffset(Instr instr, int16_t offset) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000692 DCHECK(IsAddImmediate(instr));
Steve Block44f0eee2011-05-26 01:26:41 +0100693 return ((instr & ~kImm16Mask) | (offset & kImm16Mask));
Andrei Popescu31002712010-02-23 13:46:05 +0000694}
695
696
Ben Murdoch257744e2011-11-30 15:57:28 +0000697bool Assembler::IsAndImmediate(Instr instr) {
698 return GetOpcodeField(instr) == ANDI;
699}
700
701
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000702static Assembler::OffsetSize OffsetSizeInBits(Instr instr) {
703 if (IsMipsArchVariant(kMips32r6)) {
704 if (Assembler::IsBc(instr)) {
705 return Assembler::OffsetSize::kOffset26;
706 } else if (Assembler::IsBzc(instr)) {
707 return Assembler::OffsetSize::kOffset21;
708 }
709 }
710 return Assembler::OffsetSize::kOffset16;
711}
712
713
714static inline int32_t AddBranchOffset(int pos, Instr instr) {
715 int bits = OffsetSizeInBits(instr);
716 const int32_t mask = (1 << bits) - 1;
717 bits = 32 - bits;
718
719 // Do NOT change this to <<2. We rely on arithmetic shifts here, assuming
720 // the compiler uses arithmetic shifts for signed integers.
721 int32_t imm = ((instr & mask) << bits) >> (bits - 2);
722
723 if (imm == kEndOfChain) {
724 // EndOfChain sentinel is returned directly, not relative to pc or pos.
725 return kEndOfChain;
726 } else {
727 return pos + Assembler::kBranchPCOffset + imm;
728 }
729}
730
Ben Murdochda12d292016-06-02 14:46:10 +0100731uint32_t Assembler::CreateTargetAddress(Instr instr_lui, Instr instr_jic) {
732 DCHECK(IsLui(instr_lui) && IsJicOrJialc(instr_jic));
733 int16_t jic_offset = GetImmediate16(instr_jic);
734 int16_t lui_offset = GetImmediate16(instr_lui);
735
736 if (jic_offset < 0) {
737 lui_offset += kImm16Mask;
738 }
739 uint32_t lui_offset_u = (static_cast<uint32_t>(lui_offset)) << kLuiShift;
740 uint32_t jic_offset_u = static_cast<uint32_t>(jic_offset) & kImm16Mask;
741
742 return lui_offset_u | jic_offset_u;
743}
744
745// Use just lui and jic instructions. Insert lower part of the target address in
746// jic offset part. Since jic sign-extends offset and then add it with register,
747// before that addition, difference between upper part of the target address and
748// upper part of the sign-extended offset (0xffff or 0x0000), will be inserted
749// in jic register with lui instruction.
750void Assembler::UnpackTargetAddress(uint32_t address, int16_t& lui_offset,
751 int16_t& jic_offset) {
752 lui_offset = (address & kHiMask) >> kLuiShift;
753 jic_offset = address & kLoMask;
754
755 if (jic_offset < 0) {
756 lui_offset -= kImm16Mask;
757 }
758}
759
760void Assembler::UnpackTargetAddressUnsigned(uint32_t address,
761 uint32_t& lui_offset,
762 uint32_t& jic_offset) {
763 int16_t lui_offset16 = (address & kHiMask) >> kLuiShift;
764 int16_t jic_offset16 = address & kLoMask;
765
766 if (jic_offset16 < 0) {
767 lui_offset16 -= kImm16Mask;
768 }
769 lui_offset = static_cast<uint32_t>(lui_offset16) & kImm16Mask;
770 jic_offset = static_cast<uint32_t>(jic_offset16) & kImm16Mask;
771}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000772
773int Assembler::target_at(int pos, bool is_internal) {
Andrei Popescu31002712010-02-23 13:46:05 +0000774 Instr instr = instr_at(pos);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000775 if (is_internal) {
776 if (instr == 0) {
777 return kEndOfChain;
778 } else {
779 int32_t instr_address = reinterpret_cast<int32_t>(buffer_ + pos);
780 int delta = static_cast<int>(instr_address - instr);
781 DCHECK(pos > delta);
782 return pos - delta;
783 }
784 }
Andrei Popescu31002712010-02-23 13:46:05 +0000785 if ((instr & ~kImm16Mask) == 0) {
786 // Emitted label constant, not part of a branch.
Steve Block44f0eee2011-05-26 01:26:41 +0100787 if (instr == 0) {
788 return kEndOfChain;
789 } else {
790 int32_t imm18 =((instr & static_cast<int32_t>(kImm16Mask)) << 16) >> 14;
791 return (imm18 + pos);
792 }
Andrei Popescu31002712010-02-23 13:46:05 +0000793 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000794 // Check we have a branch or jump instruction.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000795 DCHECK(IsBranch(instr) || IsLui(instr));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000796 if (IsBranch(instr)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000797 return AddBranchOffset(pos, instr);
798 } else {
Ben Murdochda12d292016-06-02 14:46:10 +0100799 Instr instr1 = instr_at(pos + 0 * Assembler::kInstrSize);
800 Instr instr2 = instr_at(pos + 1 * Assembler::kInstrSize);
801 DCHECK(IsOri(instr2) || IsJicOrJialc(instr2));
802 int32_t imm;
803 if (IsJicOrJialc(instr2)) {
804 imm = CreateTargetAddress(instr1, instr2);
805 } else {
806 imm = (instr1 & static_cast<int32_t>(kImm16Mask)) << kLuiShift;
807 imm |= (instr2 & static_cast<int32_t>(kImm16Mask));
808 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000809
810 if (imm == kEndOfJumpChain) {
811 // EndOfChain sentinel is returned directly, not relative to pc or pos.
812 return kEndOfChain;
813 } else {
814 uint32_t instr_address = reinterpret_cast<int32_t>(buffer_ + pos);
815 int32_t delta = instr_address - imm;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000816 DCHECK(pos > delta);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000817 return pos - delta;
818 }
Steve Block44f0eee2011-05-26 01:26:41 +0100819 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000820 return 0;
Andrei Popescu31002712010-02-23 13:46:05 +0000821}
822
823
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000824static inline Instr SetBranchOffset(int32_t pos, int32_t target_pos,
825 Instr instr) {
826 int32_t bits = OffsetSizeInBits(instr);
827 int32_t imm = target_pos - (pos + Assembler::kBranchPCOffset);
828 DCHECK((imm & 3) == 0);
829 imm >>= 2;
830
831 const int32_t mask = (1 << bits) - 1;
832 instr &= ~mask;
833 DCHECK(is_intn(imm, bits));
834
835 return instr | (imm & mask);
836}
837
838
839void Assembler::target_at_put(int32_t pos, int32_t target_pos,
840 bool is_internal) {
Andrei Popescu31002712010-02-23 13:46:05 +0000841 Instr instr = instr_at(pos);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000842
843 if (is_internal) {
844 uint32_t imm = reinterpret_cast<uint32_t>(buffer_) + target_pos;
845 instr_at_put(pos, imm);
846 return;
847 }
Andrei Popescu31002712010-02-23 13:46:05 +0000848 if ((instr & ~kImm16Mask) == 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000849 DCHECK(target_pos == kEndOfChain || target_pos >= 0);
Andrei Popescu31002712010-02-23 13:46:05 +0000850 // Emitted label constant, not part of a branch.
851 // Make label relative to Code* of generated Code object.
852 instr_at_put(pos, target_pos + (Code::kHeaderSize - kHeapObjectTag));
853 return;
854 }
855
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000856 DCHECK(IsBranch(instr) || IsLui(instr));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000857 if (IsBranch(instr)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000858 instr = SetBranchOffset(pos, target_pos, instr);
859 instr_at_put(pos, instr);
860 } else {
Ben Murdochda12d292016-06-02 14:46:10 +0100861 Instr instr1 = instr_at(pos + 0 * Assembler::kInstrSize);
862 Instr instr2 = instr_at(pos + 1 * Assembler::kInstrSize);
863 DCHECK(IsOri(instr2) || IsJicOrJialc(instr2));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000864 uint32_t imm = reinterpret_cast<uint32_t>(buffer_) + target_pos;
865 DCHECK((imm & 3) == 0);
Ben Murdochda12d292016-06-02 14:46:10 +0100866 DCHECK(IsLui(instr1) && (IsJicOrJialc(instr2) || IsOri(instr2)));
867 instr1 &= ~kImm16Mask;
868 instr2 &= ~kImm16Mask;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000869
Ben Murdochda12d292016-06-02 14:46:10 +0100870 if (IsJicOrJialc(instr2)) {
871 uint32_t lui_offset_u, jic_offset_u;
872 UnpackTargetAddressUnsigned(imm, lui_offset_u, jic_offset_u);
873 instr_at_put(pos + 0 * Assembler::kInstrSize, instr1 | lui_offset_u);
874 instr_at_put(pos + 1 * Assembler::kInstrSize, instr2 | jic_offset_u);
875 } else {
876 instr_at_put(pos + 0 * Assembler::kInstrSize,
877 instr1 | ((imm & kHiMask) >> kLuiShift));
878 instr_at_put(pos + 1 * Assembler::kInstrSize,
879 instr2 | (imm & kImm16Mask));
880 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000881 }
Andrei Popescu31002712010-02-23 13:46:05 +0000882}
883
884
885void Assembler::print(Label* L) {
886 if (L->is_unused()) {
887 PrintF("unused label\n");
888 } else if (L->is_bound()) {
889 PrintF("bound label to %d\n", L->pos());
890 } else if (L->is_linked()) {
891 Label l = *L;
892 PrintF("unbound label");
893 while (l.is_linked()) {
894 PrintF("@ %d ", l.pos());
895 Instr instr = instr_at(l.pos());
896 if ((instr & ~kImm16Mask) == 0) {
897 PrintF("value\n");
898 } else {
899 PrintF("%d\n", instr);
900 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000901 next(&l, internal_reference_positions_.find(l.pos()) !=
902 internal_reference_positions_.end());
Andrei Popescu31002712010-02-23 13:46:05 +0000903 }
904 } else {
905 PrintF("label in inconsistent state (pos = %d)\n", L->pos_);
906 }
907}
908
909
910void Assembler::bind_to(Label* L, int pos) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000911 DCHECK(0 <= pos && pos <= pc_offset()); // Must have valid binding position.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000912 int32_t trampoline_pos = kInvalidSlotPos;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000913 bool is_internal = false;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000914 if (L->is_linked() && !trampoline_emitted_) {
915 unbound_labels_count_--;
916 next_buffer_check_ += kTrampolineSlotsSize;
917 }
918
Andrei Popescu31002712010-02-23 13:46:05 +0000919 while (L->is_linked()) {
920 int32_t fixup_pos = L->pos();
Steve Block44f0eee2011-05-26 01:26:41 +0100921 int32_t dist = pos - fixup_pos;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000922 is_internal = internal_reference_positions_.find(fixup_pos) !=
923 internal_reference_positions_.end();
924 next(L, is_internal); // Call next before overwriting link with target at
925 // fixup_pos.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000926 Instr instr = instr_at(fixup_pos);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000927 if (is_internal) {
928 target_at_put(fixup_pos, pos, is_internal);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000929 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000930 if (IsBranch(instr)) {
931 int branch_offset = BranchOffset(instr);
932 if (dist > branch_offset) {
933 if (trampoline_pos == kInvalidSlotPos) {
934 trampoline_pos = get_trampoline_entry(fixup_pos);
935 CHECK(trampoline_pos != kInvalidSlotPos);
936 }
937 CHECK((trampoline_pos - fixup_pos) <= branch_offset);
938 target_at_put(fixup_pos, trampoline_pos, false);
939 fixup_pos = trampoline_pos;
940 dist = pos - fixup_pos;
941 }
942 target_at_put(fixup_pos, pos, false);
943 } else {
944 target_at_put(fixup_pos, pos, false);
945 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000946 }
Andrei Popescu31002712010-02-23 13:46:05 +0000947 }
948 L->bind_to(pos);
949
950 // Keep track of the last bound label so we don't eliminate any instructions
951 // before a bound label.
952 if (pos > last_bound_pos_)
953 last_bound_pos_ = pos;
954}
955
956
Andrei Popescu31002712010-02-23 13:46:05 +0000957void Assembler::bind(Label* L) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000958 DCHECK(!L->is_bound()); // Label can only be bound once.
Andrei Popescu31002712010-02-23 13:46:05 +0000959 bind_to(L, pc_offset());
960}
961
962
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000963void Assembler::next(Label* L, bool is_internal) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000964 DCHECK(L->is_linked());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000965 int link = target_at(L->pos(), is_internal);
Steve Block44f0eee2011-05-26 01:26:41 +0100966 if (link == kEndOfChain) {
Andrei Popescu31002712010-02-23 13:46:05 +0000967 L->Unuse();
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000968 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000969 DCHECK(link >= 0);
Steve Block44f0eee2011-05-26 01:26:41 +0100970 L->link_to(link);
Andrei Popescu31002712010-02-23 13:46:05 +0000971 }
972}
973
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000974
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000975bool Assembler::is_near(Label* L) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000976 DCHECK(L->is_bound());
977 return pc_offset() - L->pos() < kMaxBranchOffset - 4 * kInstrSize;
978}
979
980
981bool Assembler::is_near(Label* L, OffsetSize bits) {
982 if (L == nullptr || !L->is_bound()) return true;
983 return pc_offset() - L->pos() < (1 << (bits + 2 - 1)) - 1 - 5 * kInstrSize;
984}
985
986
987bool Assembler::is_near_branch(Label* L) {
988 DCHECK(L->is_bound());
989 return IsMipsArchVariant(kMips32r6) ? is_near_r6(L) : is_near_pre_r6(L);
990}
991
992
993int Assembler::BranchOffset(Instr instr) {
994 // At pre-R6 and for other R6 branches the offset is 16 bits.
995 int bits = OffsetSize::kOffset16;
996
997 if (IsMipsArchVariant(kMips32r6)) {
998 uint32_t opcode = GetOpcodeField(instr);
999 switch (opcode) {
1000 // Checks BC or BALC.
1001 case BC:
1002 case BALC:
1003 bits = OffsetSize::kOffset26;
1004 break;
1005
1006 // Checks BEQZC or BNEZC.
1007 case POP66:
1008 case POP76:
1009 if (GetRsField(instr) != 0) bits = OffsetSize::kOffset21;
1010 break;
1011 default:
1012 break;
1013 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001014 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001015
1016 return (1 << (bits + 2 - 1)) - 1;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001017}
Andrei Popescu31002712010-02-23 13:46:05 +00001018
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001019
Andrei Popescu31002712010-02-23 13:46:05 +00001020// We have to use a temporary register for things that can be relocated even
1021// if they can be encoded in the MIPS's 16 bits of immediate-offset instruction
1022// space. There is no guarantee that the relocated location can be similarly
1023// encoded.
Steve Block44f0eee2011-05-26 01:26:41 +01001024bool Assembler::MustUseReg(RelocInfo::Mode rmode) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001025 return !RelocInfo::IsNone(rmode);
Andrei Popescu31002712010-02-23 13:46:05 +00001026}
1027
Andrei Popescu31002712010-02-23 13:46:05 +00001028void Assembler::GenInstrRegister(Opcode opcode,
1029 Register rs,
1030 Register rt,
1031 Register rd,
1032 uint16_t sa,
1033 SecondaryField func) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001034 DCHECK(rd.is_valid() && rs.is_valid() && rt.is_valid() && is_uint5(sa));
Andrei Popescu31002712010-02-23 13:46:05 +00001035 Instr instr = opcode | (rs.code() << kRsShift) | (rt.code() << kRtShift)
1036 | (rd.code() << kRdShift) | (sa << kSaShift) | func;
1037 emit(instr);
1038}
1039
1040
1041void Assembler::GenInstrRegister(Opcode opcode,
Steve Block44f0eee2011-05-26 01:26:41 +01001042 Register rs,
1043 Register rt,
1044 uint16_t msb,
1045 uint16_t lsb,
1046 SecondaryField func) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001047 DCHECK(rs.is_valid() && rt.is_valid() && is_uint5(msb) && is_uint5(lsb));
Steve Block44f0eee2011-05-26 01:26:41 +01001048 Instr instr = opcode | (rs.code() << kRsShift) | (rt.code() << kRtShift)
1049 | (msb << kRdShift) | (lsb << kSaShift) | func;
1050 emit(instr);
1051}
1052
1053
1054void Assembler::GenInstrRegister(Opcode opcode,
Andrei Popescu31002712010-02-23 13:46:05 +00001055 SecondaryField fmt,
1056 FPURegister ft,
1057 FPURegister fs,
1058 FPURegister fd,
1059 SecondaryField func) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001060 DCHECK(fd.is_valid() && fs.is_valid() && ft.is_valid());
Steve Block44f0eee2011-05-26 01:26:41 +01001061 Instr instr = opcode | fmt | (ft.code() << kFtShift) | (fs.code() << kFsShift)
1062 | (fd.code() << kFdShift) | func;
Andrei Popescu31002712010-02-23 13:46:05 +00001063 emit(instr);
1064}
1065
1066
1067void Assembler::GenInstrRegister(Opcode opcode,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001068 FPURegister fr,
1069 FPURegister ft,
1070 FPURegister fs,
1071 FPURegister fd,
1072 SecondaryField func) {
1073 DCHECK(fd.is_valid() && fr.is_valid() && fs.is_valid() && ft.is_valid());
1074 Instr instr = opcode | (fr.code() << kFrShift) | (ft.code() << kFtShift)
1075 | (fs.code() << kFsShift) | (fd.code() << kFdShift) | func;
1076 emit(instr);
1077}
1078
1079
1080void Assembler::GenInstrRegister(Opcode opcode,
Andrei Popescu31002712010-02-23 13:46:05 +00001081 SecondaryField fmt,
1082 Register rt,
1083 FPURegister fs,
1084 FPURegister fd,
1085 SecondaryField func) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001086 DCHECK(fd.is_valid() && fs.is_valid() && rt.is_valid());
Andrei Popescu31002712010-02-23 13:46:05 +00001087 Instr instr = opcode | fmt | (rt.code() << kRtShift)
Steve Block44f0eee2011-05-26 01:26:41 +01001088 | (fs.code() << kFsShift) | (fd.code() << kFdShift) | func;
1089 emit(instr);
1090}
1091
1092
1093void Assembler::GenInstrRegister(Opcode opcode,
1094 SecondaryField fmt,
1095 Register rt,
1096 FPUControlRegister fs,
1097 SecondaryField func) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001098 DCHECK(fs.is_valid() && rt.is_valid());
Steve Block44f0eee2011-05-26 01:26:41 +01001099 Instr instr =
1100 opcode | fmt | (rt.code() << kRtShift) | (fs.code() << kFsShift) | func;
Andrei Popescu31002712010-02-23 13:46:05 +00001101 emit(instr);
1102}
1103
1104
1105// Instructions with immediate value.
1106// Registers are in the order of the instruction encoding, from left to right.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001107void Assembler::GenInstrImmediate(Opcode opcode, Register rs, Register rt,
1108 int32_t j,
1109 CompactBranchType is_compact_branch) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001110 DCHECK(rs.is_valid() && rt.is_valid() && (is_int16(j) || is_uint16(j)));
Andrei Popescu31002712010-02-23 13:46:05 +00001111 Instr instr = opcode | (rs.code() << kRsShift) | (rt.code() << kRtShift)
1112 | (j & kImm16Mask);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001113 emit(instr, is_compact_branch);
Andrei Popescu31002712010-02-23 13:46:05 +00001114}
1115
1116
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001117void Assembler::GenInstrImmediate(Opcode opcode, Register rs, SecondaryField SF,
1118 int32_t j,
1119 CompactBranchType is_compact_branch) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001120 DCHECK(rs.is_valid() && (is_int16(j) || is_uint16(j)));
Andrei Popescu31002712010-02-23 13:46:05 +00001121 Instr instr = opcode | (rs.code() << kRsShift) | SF | (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, FPURegister ft,
1127 int32_t j,
1128 CompactBranchType is_compact_branch) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001129 DCHECK(rs.is_valid() && ft.is_valid() && (is_int16(j) || is_uint16(j)));
Andrei Popescu31002712010-02-23 13:46:05 +00001130 Instr instr = opcode | (rs.code() << kRsShift) | (ft.code() << kFtShift)
1131 | (j & kImm16Mask);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001132 emit(instr, is_compact_branch);
1133}
1134
1135
1136void Assembler::GenInstrImmediate(Opcode opcode, Register rs, int32_t offset21,
1137 CompactBranchType is_compact_branch) {
1138 DCHECK(rs.is_valid() && (is_int21(offset21)));
1139 Instr instr = opcode | (rs.code() << kRsShift) | (offset21 & kImm21Mask);
1140 emit(instr, is_compact_branch);
1141}
1142
1143
1144void Assembler::GenInstrImmediate(Opcode opcode, Register rs,
1145 uint32_t offset21) {
1146 DCHECK(rs.is_valid() && (is_uint21(offset21)));
1147 Instr instr = opcode | (rs.code() << kRsShift) | (offset21 & kImm21Mask);
Andrei Popescu31002712010-02-23 13:46:05 +00001148 emit(instr);
1149}
1150
1151
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001152void Assembler::GenInstrImmediate(Opcode opcode, int32_t offset26,
1153 CompactBranchType is_compact_branch) {
1154 DCHECK(is_int26(offset26));
1155 Instr instr = opcode | (offset26 & kImm26Mask);
1156 emit(instr, is_compact_branch);
1157}
1158
1159
Andrei Popescu31002712010-02-23 13:46:05 +00001160void Assembler::GenInstrJump(Opcode opcode,
Ben Murdoch589d6972011-11-30 16:04:58 +00001161 uint32_t address) {
Steve Block44f0eee2011-05-26 01:26:41 +01001162 BlockTrampolinePoolScope block_trampoline_pool(this);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001163 DCHECK(is_uint26(address));
Andrei Popescu31002712010-02-23 13:46:05 +00001164 Instr instr = opcode | address;
1165 emit(instr);
Steve Block44f0eee2011-05-26 01:26:41 +01001166 BlockTrampolinePoolFor(1); // For associated delay slot.
1167}
1168
1169
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001170// Returns the next free trampoline entry.
1171int32_t Assembler::get_trampoline_entry(int32_t pos) {
Ben Murdoch257744e2011-11-30 15:57:28 +00001172 int32_t trampoline_entry = kInvalidSlotPos;
Steve Block44f0eee2011-05-26 01:26:41 +01001173
Ben Murdoch257744e2011-11-30 15:57:28 +00001174 if (!internal_trampoline_exception_) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001175 if (trampoline_.start() > pos) {
1176 trampoline_entry = trampoline_.take_slot();
Steve Block44f0eee2011-05-26 01:26:41 +01001177 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001178
Ben Murdoch257744e2011-11-30 15:57:28 +00001179 if (kInvalidSlotPos == trampoline_entry) {
1180 internal_trampoline_exception_ = true;
Steve Block44f0eee2011-05-26 01:26:41 +01001181 }
1182 }
1183 return trampoline_entry;
Andrei Popescu31002712010-02-23 13:46:05 +00001184}
1185
1186
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001187uint32_t Assembler::jump_address(Label* L) {
Andrei Popescu31002712010-02-23 13:46:05 +00001188 int32_t target_pos;
Steve Block44f0eee2011-05-26 01:26:41 +01001189
Andrei Popescu31002712010-02-23 13:46:05 +00001190 if (L->is_bound()) {
1191 target_pos = L->pos();
1192 } else {
1193 if (L->is_linked()) {
Steve Block44f0eee2011-05-26 01:26:41 +01001194 target_pos = L->pos(); // L's link.
Steve Block44f0eee2011-05-26 01:26:41 +01001195 L->link_to(pc_offset());
Andrei Popescu31002712010-02-23 13:46:05 +00001196 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01001197 L->link_to(pc_offset());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001198 return kEndOfJumpChain;
1199 }
1200 }
1201
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001202 uint32_t imm = reinterpret_cast<uint32_t>(buffer_) + target_pos;
1203 DCHECK((imm & 3) == 0);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001204
1205 return imm;
1206}
1207
1208
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001209int32_t Assembler::branch_offset_helper(Label* L, OffsetSize bits) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001210 int32_t target_pos;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001211 int32_t pad = IsPrevInstrCompactBranch() ? kInstrSize : 0;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001212
1213 if (L->is_bound()) {
1214 target_pos = L->pos();
1215 } else {
1216 if (L->is_linked()) {
1217 target_pos = L->pos();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001218 L->link_to(pc_offset() + pad);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001219 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001220 L->link_to(pc_offset() + pad);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001221 if (!trampoline_emitted_) {
1222 unbound_labels_count_++;
1223 next_buffer_check_ -= kTrampolineSlotsSize;
1224 }
Steve Block44f0eee2011-05-26 01:26:41 +01001225 return kEndOfChain;
Andrei Popescu31002712010-02-23 13:46:05 +00001226 }
Andrei Popescu31002712010-02-23 13:46:05 +00001227 }
1228
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001229 int32_t offset = target_pos - (pc_offset() + kBranchPCOffset + pad);
1230 DCHECK(is_intn(offset, bits + 2));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001231 DCHECK((offset & 3) == 0);
Steve Block44f0eee2011-05-26 01:26:41 +01001232
Andrei Popescu31002712010-02-23 13:46:05 +00001233 return offset;
1234}
1235
1236
1237void Assembler::label_at_put(Label* L, int at_offset) {
1238 int target_pos;
1239 if (L->is_bound()) {
1240 target_pos = L->pos();
Steve Block44f0eee2011-05-26 01:26:41 +01001241 instr_at_put(at_offset, target_pos + (Code::kHeaderSize - kHeapObjectTag));
Andrei Popescu31002712010-02-23 13:46:05 +00001242 } else {
1243 if (L->is_linked()) {
Steve Block44f0eee2011-05-26 01:26:41 +01001244 target_pos = L->pos(); // L's link.
1245 int32_t imm18 = target_pos - at_offset;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001246 DCHECK((imm18 & 3) == 0);
Steve Block44f0eee2011-05-26 01:26:41 +01001247 int32_t imm16 = imm18 >> 2;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001248 DCHECK(is_int16(imm16));
Steve Block44f0eee2011-05-26 01:26:41 +01001249 instr_at_put(at_offset, (imm16 & kImm16Mask));
Andrei Popescu31002712010-02-23 13:46:05 +00001250 } else {
1251 target_pos = kEndOfChain;
Steve Block44f0eee2011-05-26 01:26:41 +01001252 instr_at_put(at_offset, 0);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001253 if (!trampoline_emitted_) {
1254 unbound_labels_count_++;
1255 next_buffer_check_ -= kTrampolineSlotsSize;
1256 }
Andrei Popescu31002712010-02-23 13:46:05 +00001257 }
1258 L->link_to(at_offset);
Andrei Popescu31002712010-02-23 13:46:05 +00001259 }
1260}
1261
1262
1263//------- Branch and jump instructions --------
1264
1265void Assembler::b(int16_t offset) {
1266 beq(zero_reg, zero_reg, offset);
1267}
1268
1269
1270void Assembler::bal(int16_t offset) {
1271 bgezal(zero_reg, offset);
1272}
1273
1274
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001275void Assembler::bc(int32_t offset) {
1276 DCHECK(IsMipsArchVariant(kMips32r6));
1277 GenInstrImmediate(BC, offset, CompactBranchType::COMPACT_BRANCH);
1278}
1279
1280
1281void Assembler::balc(int32_t offset) {
1282 DCHECK(IsMipsArchVariant(kMips32r6));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001283 GenInstrImmediate(BALC, offset, CompactBranchType::COMPACT_BRANCH);
1284}
1285
1286
Andrei Popescu31002712010-02-23 13:46:05 +00001287void Assembler::beq(Register rs, Register rt, int16_t offset) {
Steve Block44f0eee2011-05-26 01:26:41 +01001288 BlockTrampolinePoolScope block_trampoline_pool(this);
Andrei Popescu31002712010-02-23 13:46:05 +00001289 GenInstrImmediate(BEQ, rs, rt, offset);
Steve Block44f0eee2011-05-26 01:26:41 +01001290 BlockTrampolinePoolFor(1); // For associated delay slot.
Andrei Popescu31002712010-02-23 13:46:05 +00001291}
1292
1293
1294void Assembler::bgez(Register rs, int16_t offset) {
Steve Block44f0eee2011-05-26 01:26:41 +01001295 BlockTrampolinePoolScope block_trampoline_pool(this);
Andrei Popescu31002712010-02-23 13:46:05 +00001296 GenInstrImmediate(REGIMM, rs, BGEZ, offset);
Steve Block44f0eee2011-05-26 01:26:41 +01001297 BlockTrampolinePoolFor(1); // For associated delay slot.
Andrei Popescu31002712010-02-23 13:46:05 +00001298}
1299
1300
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001301void Assembler::bgezc(Register rt, int16_t offset) {
1302 DCHECK(IsMipsArchVariant(kMips32r6));
1303 DCHECK(!(rt.is(zero_reg)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001304 GenInstrImmediate(BLEZL, rt, rt, offset, CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001305}
1306
1307
1308void Assembler::bgeuc(Register rs, Register rt, int16_t offset) {
1309 DCHECK(IsMipsArchVariant(kMips32r6));
1310 DCHECK(!(rs.is(zero_reg)));
1311 DCHECK(!(rt.is(zero_reg)));
1312 DCHECK(rs.code() != rt.code());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001313 GenInstrImmediate(BLEZ, rs, rt, offset, CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001314}
1315
1316
1317void Assembler::bgec(Register rs, Register rt, int16_t offset) {
1318 DCHECK(IsMipsArchVariant(kMips32r6));
1319 DCHECK(!(rs.is(zero_reg)));
1320 DCHECK(!(rt.is(zero_reg)));
1321 DCHECK(rs.code() != rt.code());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001322 GenInstrImmediate(BLEZL, rs, rt, offset, CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001323}
1324
1325
Andrei Popescu31002712010-02-23 13:46:05 +00001326void Assembler::bgezal(Register rs, int16_t offset) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001327 DCHECK(!IsMipsArchVariant(kMips32r6) || rs.is(zero_reg));
Steve Block44f0eee2011-05-26 01:26:41 +01001328 BlockTrampolinePoolScope block_trampoline_pool(this);
Andrei Popescu31002712010-02-23 13:46:05 +00001329 GenInstrImmediate(REGIMM, rs, BGEZAL, offset);
Steve Block44f0eee2011-05-26 01:26:41 +01001330 BlockTrampolinePoolFor(1); // For associated delay slot.
Andrei Popescu31002712010-02-23 13:46:05 +00001331}
1332
1333
1334void Assembler::bgtz(Register rs, int16_t offset) {
Steve Block44f0eee2011-05-26 01:26:41 +01001335 BlockTrampolinePoolScope block_trampoline_pool(this);
Andrei Popescu31002712010-02-23 13:46:05 +00001336 GenInstrImmediate(BGTZ, rs, zero_reg, offset);
Steve Block44f0eee2011-05-26 01:26:41 +01001337 BlockTrampolinePoolFor(1); // For associated delay slot.
Andrei Popescu31002712010-02-23 13:46:05 +00001338}
1339
1340
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001341void Assembler::bgtzc(Register rt, int16_t offset) {
1342 DCHECK(IsMipsArchVariant(kMips32r6));
1343 DCHECK(!(rt.is(zero_reg)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001344 GenInstrImmediate(BGTZL, zero_reg, rt, offset,
1345 CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001346}
1347
1348
Andrei Popescu31002712010-02-23 13:46:05 +00001349void Assembler::blez(Register rs, int16_t offset) {
Steve Block44f0eee2011-05-26 01:26:41 +01001350 BlockTrampolinePoolScope block_trampoline_pool(this);
Andrei Popescu31002712010-02-23 13:46:05 +00001351 GenInstrImmediate(BLEZ, rs, zero_reg, offset);
Steve Block44f0eee2011-05-26 01:26:41 +01001352 BlockTrampolinePoolFor(1); // For associated delay slot.
Andrei Popescu31002712010-02-23 13:46:05 +00001353}
1354
1355
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001356void Assembler::blezc(Register rt, int16_t offset) {
1357 DCHECK(IsMipsArchVariant(kMips32r6));
1358 DCHECK(!(rt.is(zero_reg)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001359 GenInstrImmediate(BLEZL, zero_reg, rt, offset,
1360 CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001361}
1362
1363
1364void Assembler::bltzc(Register rt, int16_t offset) {
1365 DCHECK(IsMipsArchVariant(kMips32r6));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001366 DCHECK(!rt.is(zero_reg));
1367 GenInstrImmediate(BGTZL, rt, rt, offset, CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001368}
1369
1370
1371void Assembler::bltuc(Register rs, Register rt, int16_t offset) {
1372 DCHECK(IsMipsArchVariant(kMips32r6));
1373 DCHECK(!(rs.is(zero_reg)));
1374 DCHECK(!(rt.is(zero_reg)));
1375 DCHECK(rs.code() != rt.code());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001376 GenInstrImmediate(BGTZ, rs, rt, offset, CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001377}
1378
1379
1380void Assembler::bltc(Register rs, Register rt, int16_t offset) {
1381 DCHECK(IsMipsArchVariant(kMips32r6));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001382 DCHECK(!rs.is(zero_reg));
1383 DCHECK(!rt.is(zero_reg));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001384 DCHECK(rs.code() != rt.code());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001385 GenInstrImmediate(BGTZL, rs, rt, offset, CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001386}
1387
1388
Andrei Popescu31002712010-02-23 13:46:05 +00001389void Assembler::bltz(Register rs, int16_t offset) {
Steve Block44f0eee2011-05-26 01:26:41 +01001390 BlockTrampolinePoolScope block_trampoline_pool(this);
Andrei Popescu31002712010-02-23 13:46:05 +00001391 GenInstrImmediate(REGIMM, rs, BLTZ, offset);
Steve Block44f0eee2011-05-26 01:26:41 +01001392 BlockTrampolinePoolFor(1); // For associated delay slot.
Andrei Popescu31002712010-02-23 13:46:05 +00001393}
1394
1395
1396void Assembler::bltzal(Register rs, int16_t offset) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001397 DCHECK(!IsMipsArchVariant(kMips32r6) || rs.is(zero_reg));
Steve Block44f0eee2011-05-26 01:26:41 +01001398 BlockTrampolinePoolScope block_trampoline_pool(this);
Andrei Popescu31002712010-02-23 13:46:05 +00001399 GenInstrImmediate(REGIMM, rs, BLTZAL, offset);
Steve Block44f0eee2011-05-26 01:26:41 +01001400 BlockTrampolinePoolFor(1); // For associated delay slot.
Andrei Popescu31002712010-02-23 13:46:05 +00001401}
1402
1403
1404void Assembler::bne(Register rs, Register rt, int16_t offset) {
Steve Block44f0eee2011-05-26 01:26:41 +01001405 BlockTrampolinePoolScope block_trampoline_pool(this);
Andrei Popescu31002712010-02-23 13:46:05 +00001406 GenInstrImmediate(BNE, rs, rt, offset);
Steve Block44f0eee2011-05-26 01:26:41 +01001407 BlockTrampolinePoolFor(1); // For associated delay slot.
Andrei Popescu31002712010-02-23 13:46:05 +00001408}
1409
1410
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001411void Assembler::bovc(Register rs, Register rt, int16_t offset) {
1412 DCHECK(IsMipsArchVariant(kMips32r6));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001413 if (rs.code() >= rt.code()) {
1414 GenInstrImmediate(ADDI, rs, rt, offset, CompactBranchType::COMPACT_BRANCH);
1415 } else {
1416 GenInstrImmediate(ADDI, rt, rs, offset, CompactBranchType::COMPACT_BRANCH);
1417 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001418}
1419
1420
1421void Assembler::bnvc(Register rs, Register rt, int16_t offset) {
1422 DCHECK(IsMipsArchVariant(kMips32r6));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001423 if (rs.code() >= rt.code()) {
1424 GenInstrImmediate(DADDI, rs, rt, offset, CompactBranchType::COMPACT_BRANCH);
1425 } else {
1426 GenInstrImmediate(DADDI, rt, rs, offset, CompactBranchType::COMPACT_BRANCH);
1427 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001428}
1429
1430
1431void Assembler::blezalc(Register rt, int16_t offset) {
1432 DCHECK(IsMipsArchVariant(kMips32r6));
1433 DCHECK(!(rt.is(zero_reg)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001434 GenInstrImmediate(BLEZ, zero_reg, rt, offset,
1435 CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001436}
1437
1438
1439void Assembler::bgezalc(Register rt, int16_t offset) {
1440 DCHECK(IsMipsArchVariant(kMips32r6));
1441 DCHECK(!(rt.is(zero_reg)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001442 GenInstrImmediate(BLEZ, rt, rt, offset, CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001443}
1444
1445
1446void Assembler::bgezall(Register rs, int16_t offset) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001447 DCHECK(!IsMipsArchVariant(kMips32r6));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001448 DCHECK(!(rs.is(zero_reg)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001449 BlockTrampolinePoolScope block_trampoline_pool(this);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001450 GenInstrImmediate(REGIMM, rs, BGEZALL, offset);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001451 BlockTrampolinePoolFor(1); // For associated delay slot.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001452}
1453
1454
1455void Assembler::bltzalc(Register rt, int16_t offset) {
1456 DCHECK(IsMipsArchVariant(kMips32r6));
1457 DCHECK(!(rt.is(zero_reg)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001458 GenInstrImmediate(BGTZ, rt, rt, offset, CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001459}
1460
1461
1462void Assembler::bgtzalc(Register rt, int16_t offset) {
1463 DCHECK(IsMipsArchVariant(kMips32r6));
1464 DCHECK(!(rt.is(zero_reg)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001465 GenInstrImmediate(BGTZ, zero_reg, rt, offset,
1466 CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001467}
1468
1469
1470void Assembler::beqzalc(Register rt, int16_t offset) {
1471 DCHECK(IsMipsArchVariant(kMips32r6));
1472 DCHECK(!(rt.is(zero_reg)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001473 GenInstrImmediate(ADDI, zero_reg, rt, offset,
1474 CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001475}
1476
1477
1478void Assembler::bnezalc(Register rt, int16_t offset) {
1479 DCHECK(IsMipsArchVariant(kMips32r6));
1480 DCHECK(!(rt.is(zero_reg)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001481 GenInstrImmediate(DADDI, zero_reg, rt, offset,
1482 CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001483}
1484
1485
1486void Assembler::beqc(Register rs, Register rt, int16_t offset) {
1487 DCHECK(IsMipsArchVariant(kMips32r6));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001488 DCHECK(rs.code() != rt.code() && rs.code() != 0 && rt.code() != 0);
1489 if (rs.code() < rt.code()) {
1490 GenInstrImmediate(ADDI, rs, rt, offset, CompactBranchType::COMPACT_BRANCH);
1491 } else {
1492 GenInstrImmediate(ADDI, rt, rs, offset, CompactBranchType::COMPACT_BRANCH);
1493 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001494}
1495
1496
1497void Assembler::beqzc(Register rs, int32_t offset) {
1498 DCHECK(IsMipsArchVariant(kMips32r6));
1499 DCHECK(!(rs.is(zero_reg)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001500 GenInstrImmediate(POP66, rs, offset, CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001501}
1502
1503
1504void Assembler::bnec(Register rs, Register rt, int16_t offset) {
1505 DCHECK(IsMipsArchVariant(kMips32r6));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001506 DCHECK(rs.code() != rt.code() && rs.code() != 0 && rt.code() != 0);
1507 if (rs.code() < rt.code()) {
1508 GenInstrImmediate(DADDI, rs, rt, offset, CompactBranchType::COMPACT_BRANCH);
1509 } else {
1510 GenInstrImmediate(DADDI, rt, rs, offset, CompactBranchType::COMPACT_BRANCH);
1511 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001512}
1513
1514
1515void Assembler::bnezc(Register rs, int32_t offset) {
1516 DCHECK(IsMipsArchVariant(kMips32r6));
1517 DCHECK(!(rs.is(zero_reg)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001518 GenInstrImmediate(POP76, rs, offset, CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001519}
1520
1521
Andrei Popescu31002712010-02-23 13:46:05 +00001522void Assembler::j(int32_t target) {
Ben Murdoch589d6972011-11-30 16:04:58 +00001523#if DEBUG
1524 // Get pc of delay slot.
1525 uint32_t ipc = reinterpret_cast<uint32_t>(pc_ + 1 * kInstrSize);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001526 bool in_range = ((ipc ^ static_cast<uint32_t>(target)) >>
1527 (kImm26Bits + kImmFieldShift)) == 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001528 DCHECK(in_range && ((target & 3) == 0));
Ben Murdoch589d6972011-11-30 16:04:58 +00001529#endif
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001530 BlockTrampolinePoolScope block_trampoline_pool(this);
1531 GenInstrJump(J, (target >> 2) & kImm26Mask);
1532 BlockTrampolinePoolFor(1); // For associated delay slot.
Andrei Popescu31002712010-02-23 13:46:05 +00001533}
1534
1535
1536void Assembler::jr(Register rs) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001537 if (!IsMipsArchVariant(kMips32r6)) {
1538 BlockTrampolinePoolScope block_trampoline_pool(this);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001539 GenInstrRegister(SPECIAL, rs, zero_reg, zero_reg, 0, JR);
1540 BlockTrampolinePoolFor(1); // For associated delay slot.
1541 } else {
1542 jalr(rs, zero_reg);
Steve Block44f0eee2011-05-26 01:26:41 +01001543 }
Andrei Popescu31002712010-02-23 13:46:05 +00001544}
1545
1546
1547void Assembler::jal(int32_t target) {
Ben Murdoch589d6972011-11-30 16:04:58 +00001548#ifdef DEBUG
1549 // Get pc of delay slot.
1550 uint32_t ipc = reinterpret_cast<uint32_t>(pc_ + 1 * kInstrSize);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001551 bool in_range = ((ipc ^ static_cast<uint32_t>(target)) >>
1552 (kImm26Bits + kImmFieldShift)) == 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001553 DCHECK(in_range && ((target & 3) == 0));
Ben Murdoch589d6972011-11-30 16:04:58 +00001554#endif
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001555 BlockTrampolinePoolScope block_trampoline_pool(this);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001556 GenInstrJump(JAL, (target >> 2) & kImm26Mask);
1557 BlockTrampolinePoolFor(1); // For associated delay slot.
Andrei Popescu31002712010-02-23 13:46:05 +00001558}
1559
1560
1561void Assembler::jalr(Register rs, Register rd) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001562 DCHECK(rs.code() != rd.code());
Steve Block44f0eee2011-05-26 01:26:41 +01001563 BlockTrampolinePoolScope block_trampoline_pool(this);
Andrei Popescu31002712010-02-23 13:46:05 +00001564 GenInstrRegister(SPECIAL, rs, zero_reg, rd, 0, JALR);
Steve Block44f0eee2011-05-26 01:26:41 +01001565 BlockTrampolinePoolFor(1); // For associated delay slot.
Andrei Popescu31002712010-02-23 13:46:05 +00001566}
1567
1568
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001569void Assembler::jic(Register rt, int16_t offset) {
1570 DCHECK(IsMipsArchVariant(kMips32r6));
1571 GenInstrImmediate(POP66, zero_reg, rt, offset);
Ben Murdoch589d6972011-11-30 16:04:58 +00001572}
1573
1574
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001575void Assembler::jialc(Register rt, int16_t offset) {
1576 DCHECK(IsMipsArchVariant(kMips32r6));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001577 GenInstrImmediate(POP76, zero_reg, rt, offset);
Ben Murdoch589d6972011-11-30 16:04:58 +00001578}
1579
1580
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001581// -------Data-processing-instructions---------
Andrei Popescu31002712010-02-23 13:46:05 +00001582
1583// Arithmetic.
1584
Andrei Popescu31002712010-02-23 13:46:05 +00001585void Assembler::addu(Register rd, Register rs, Register rt) {
1586 GenInstrRegister(SPECIAL, rs, rt, rd, 0, ADDU);
1587}
1588
1589
Andrei Popescu31002712010-02-23 13:46:05 +00001590void Assembler::addiu(Register rd, Register rs, int32_t j) {
1591 GenInstrImmediate(ADDIU, rs, rd, j);
Andrei Popescu31002712010-02-23 13:46:05 +00001592}
1593
1594
1595void Assembler::subu(Register rd, Register rs, Register rt) {
1596 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SUBU);
1597}
1598
1599
1600void Assembler::mul(Register rd, Register rs, Register rt) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001601 if (!IsMipsArchVariant(kMips32r6)) {
1602 GenInstrRegister(SPECIAL2, rs, rt, rd, 0, MUL);
1603 } else {
1604 GenInstrRegister(SPECIAL, rs, rt, rd, MUL_OP, MUL_MUH);
1605 }
1606}
1607
1608
1609void Assembler::mulu(Register rd, Register rs, Register rt) {
1610 DCHECK(IsMipsArchVariant(kMips32r6));
1611 GenInstrRegister(SPECIAL, rs, rt, rd, MUL_OP, MUL_MUH_U);
1612}
1613
1614
1615void Assembler::muh(Register rd, Register rs, Register rt) {
1616 DCHECK(IsMipsArchVariant(kMips32r6));
1617 GenInstrRegister(SPECIAL, rs, rt, rd, MUH_OP, MUL_MUH);
1618}
1619
1620
1621void Assembler::muhu(Register rd, Register rs, Register rt) {
1622 DCHECK(IsMipsArchVariant(kMips32r6));
1623 GenInstrRegister(SPECIAL, rs, rt, rd, MUH_OP, MUL_MUH_U);
1624}
1625
1626
1627void Assembler::mod(Register rd, Register rs, Register rt) {
1628 DCHECK(IsMipsArchVariant(kMips32r6));
1629 GenInstrRegister(SPECIAL, rs, rt, rd, MOD_OP, DIV_MOD);
1630}
1631
1632
1633void Assembler::modu(Register rd, Register rs, Register rt) {
1634 DCHECK(IsMipsArchVariant(kMips32r6));
1635 GenInstrRegister(SPECIAL, rs, rt, rd, MOD_OP, DIV_MOD_U);
Andrei Popescu31002712010-02-23 13:46:05 +00001636}
1637
1638
1639void Assembler::mult(Register rs, Register rt) {
1640 GenInstrRegister(SPECIAL, rs, rt, zero_reg, 0, MULT);
1641}
1642
1643
1644void Assembler::multu(Register rs, Register rt) {
1645 GenInstrRegister(SPECIAL, rs, rt, zero_reg, 0, MULTU);
1646}
1647
1648
1649void Assembler::div(Register rs, Register rt) {
1650 GenInstrRegister(SPECIAL, rs, rt, zero_reg, 0, DIV);
1651}
1652
1653
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001654void Assembler::div(Register rd, Register rs, Register rt) {
1655 DCHECK(IsMipsArchVariant(kMips32r6));
1656 GenInstrRegister(SPECIAL, rs, rt, rd, DIV_OP, DIV_MOD);
1657}
1658
1659
Andrei Popescu31002712010-02-23 13:46:05 +00001660void Assembler::divu(Register rs, Register rt) {
1661 GenInstrRegister(SPECIAL, rs, rt, zero_reg, 0, DIVU);
1662}
1663
1664
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001665void Assembler::divu(Register rd, Register rs, Register rt) {
1666 DCHECK(IsMipsArchVariant(kMips32r6));
1667 GenInstrRegister(SPECIAL, rs, rt, rd, DIV_OP, DIV_MOD_U);
1668}
1669
1670
Andrei Popescu31002712010-02-23 13:46:05 +00001671// Logical.
1672
1673void Assembler::and_(Register rd, Register rs, Register rt) {
1674 GenInstrRegister(SPECIAL, rs, rt, rd, 0, AND);
1675}
1676
1677
1678void Assembler::andi(Register rt, Register rs, int32_t j) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001679 DCHECK(is_uint16(j));
Andrei Popescu31002712010-02-23 13:46:05 +00001680 GenInstrImmediate(ANDI, rs, rt, j);
1681}
1682
1683
1684void Assembler::or_(Register rd, Register rs, Register rt) {
1685 GenInstrRegister(SPECIAL, rs, rt, rd, 0, OR);
1686}
1687
1688
1689void Assembler::ori(Register rt, Register rs, int32_t j) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001690 DCHECK(is_uint16(j));
Andrei Popescu31002712010-02-23 13:46:05 +00001691 GenInstrImmediate(ORI, rs, rt, j);
1692}
1693
1694
1695void Assembler::xor_(Register rd, Register rs, Register rt) {
1696 GenInstrRegister(SPECIAL, rs, rt, rd, 0, XOR);
1697}
1698
1699
1700void Assembler::xori(Register rt, Register rs, int32_t j) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001701 DCHECK(is_uint16(j));
Andrei Popescu31002712010-02-23 13:46:05 +00001702 GenInstrImmediate(XORI, rs, rt, j);
1703}
1704
1705
1706void Assembler::nor(Register rd, Register rs, Register rt) {
1707 GenInstrRegister(SPECIAL, rs, rt, rd, 0, NOR);
1708}
1709
1710
1711// Shifts.
Steve Block44f0eee2011-05-26 01:26:41 +01001712void Assembler::sll(Register rd,
1713 Register rt,
1714 uint16_t sa,
1715 bool coming_from_nop) {
1716 // Don't allow nop instructions in the form sll zero_reg, zero_reg to be
1717 // generated using the sll instruction. They must be generated using
1718 // nop(int/NopMarkerTypes) or MarkCode(int/NopMarkerTypes) pseudo
1719 // instructions.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001720 DCHECK(coming_from_nop || !(rd.is(zero_reg) && rt.is(zero_reg)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001721 GenInstrRegister(SPECIAL, zero_reg, rt, rd, sa & 0x1F, SLL);
Andrei Popescu31002712010-02-23 13:46:05 +00001722}
1723
1724
1725void Assembler::sllv(Register rd, Register rt, Register rs) {
1726 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SLLV);
1727}
1728
1729
1730void Assembler::srl(Register rd, Register rt, uint16_t sa) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001731 GenInstrRegister(SPECIAL, zero_reg, rt, rd, sa & 0x1F, SRL);
Andrei Popescu31002712010-02-23 13:46:05 +00001732}
1733
1734
1735void Assembler::srlv(Register rd, Register rt, Register rs) {
1736 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SRLV);
1737}
1738
1739
1740void Assembler::sra(Register rd, Register rt, uint16_t sa) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001741 GenInstrRegister(SPECIAL, zero_reg, rt, rd, sa & 0x1F, SRA);
Andrei Popescu31002712010-02-23 13:46:05 +00001742}
1743
1744
1745void Assembler::srav(Register rd, Register rt, Register rs) {
1746 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SRAV);
1747}
1748
1749
Steve Block44f0eee2011-05-26 01:26:41 +01001750void Assembler::rotr(Register rd, Register rt, uint16_t sa) {
1751 // Should be called via MacroAssembler::Ror.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001752 DCHECK(rd.is_valid() && rt.is_valid() && is_uint5(sa));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001753 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
Steve Block44f0eee2011-05-26 01:26:41 +01001754 Instr instr = SPECIAL | (1 << kRsShift) | (rt.code() << kRtShift)
1755 | (rd.code() << kRdShift) | (sa << kSaShift) | SRL;
1756 emit(instr);
1757}
1758
1759
1760void Assembler::rotrv(Register rd, Register rt, Register rs) {
1761 // Should be called via MacroAssembler::Ror.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001762 DCHECK(rd.is_valid() && rt.is_valid() && rs.is_valid());
1763 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
Steve Block44f0eee2011-05-26 01:26:41 +01001764 Instr instr = SPECIAL | (rs.code() << kRsShift) | (rt.code() << kRtShift)
1765 | (rd.code() << kRdShift) | (1 << kSaShift) | SRLV;
1766 emit(instr);
1767}
1768
1769
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001770void Assembler::lsa(Register rd, Register rt, Register rs, uint8_t sa) {
1771 DCHECK(rd.is_valid() && rt.is_valid() && rs.is_valid());
Ben Murdochda12d292016-06-02 14:46:10 +01001772 DCHECK(sa <= 3);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001773 DCHECK(IsMipsArchVariant(kMips32r6));
Ben Murdochda12d292016-06-02 14:46:10 +01001774 Instr instr = SPECIAL | rs.code() << kRsShift | rt.code() << kRtShift |
1775 rd.code() << kRdShift | sa << kSaShift | LSA;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001776 emit(instr);
1777}
1778
1779
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001780// ------------Memory-instructions-------------
Andrei Popescu31002712010-02-23 13:46:05 +00001781
Steve Block44f0eee2011-05-26 01:26:41 +01001782// Helper for base-reg + offset, when offset is larger than int16.
1783void Assembler::LoadRegPlusOffsetToAt(const MemOperand& src) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001784 DCHECK(!src.rm().is(at));
1785 lui(at, (src.offset_ >> kLuiShift) & kImm16Mask);
Steve Block44f0eee2011-05-26 01:26:41 +01001786 ori(at, at, src.offset_ & kImm16Mask); // Load 32-bit offset.
1787 addu(at, at, src.rm()); // Add base register.
1788}
1789
1790
Andrei Popescu31002712010-02-23 13:46:05 +00001791void Assembler::lb(Register rd, const MemOperand& rs) {
Steve Block44f0eee2011-05-26 01:26:41 +01001792 if (is_int16(rs.offset_)) {
1793 GenInstrImmediate(LB, rs.rm(), rd, rs.offset_);
1794 } else { // Offset > 16 bits, use multiple instructions to load.
1795 LoadRegPlusOffsetToAt(rs);
1796 GenInstrImmediate(LB, at, rd, 0); // Equiv to lb(rd, MemOperand(at, 0));
1797 }
Andrei Popescu31002712010-02-23 13:46:05 +00001798}
1799
1800
1801void Assembler::lbu(Register rd, const MemOperand& rs) {
Steve Block44f0eee2011-05-26 01:26:41 +01001802 if (is_int16(rs.offset_)) {
1803 GenInstrImmediate(LBU, rs.rm(), rd, rs.offset_);
1804 } else { // Offset > 16 bits, use multiple instructions to load.
1805 LoadRegPlusOffsetToAt(rs);
1806 GenInstrImmediate(LBU, at, rd, 0); // Equiv to lbu(rd, MemOperand(at, 0));
1807 }
1808}
1809
1810
1811void Assembler::lh(Register rd, const MemOperand& rs) {
1812 if (is_int16(rs.offset_)) {
1813 GenInstrImmediate(LH, rs.rm(), rd, rs.offset_);
1814 } else { // Offset > 16 bits, use multiple instructions to load.
1815 LoadRegPlusOffsetToAt(rs);
1816 GenInstrImmediate(LH, at, rd, 0); // Equiv to lh(rd, MemOperand(at, 0));
1817 }
1818}
1819
1820
1821void Assembler::lhu(Register rd, const MemOperand& rs) {
1822 if (is_int16(rs.offset_)) {
1823 GenInstrImmediate(LHU, rs.rm(), rd, rs.offset_);
1824 } else { // Offset > 16 bits, use multiple instructions to load.
1825 LoadRegPlusOffsetToAt(rs);
1826 GenInstrImmediate(LHU, at, rd, 0); // Equiv to lhu(rd, MemOperand(at, 0));
1827 }
Andrei Popescu31002712010-02-23 13:46:05 +00001828}
1829
1830
1831void Assembler::lw(Register rd, const MemOperand& rs) {
Steve Block44f0eee2011-05-26 01:26:41 +01001832 if (is_int16(rs.offset_)) {
1833 GenInstrImmediate(LW, rs.rm(), rd, rs.offset_);
1834 } else { // Offset > 16 bits, use multiple instructions to load.
1835 LoadRegPlusOffsetToAt(rs);
1836 GenInstrImmediate(LW, at, rd, 0); // Equiv to lw(rd, MemOperand(at, 0));
1837 }
Steve Block44f0eee2011-05-26 01:26:41 +01001838}
1839
1840
1841void Assembler::lwl(Register rd, const MemOperand& rs) {
Ben Murdochc5610432016-08-08 18:44:38 +01001842 DCHECK(is_int16(rs.offset_));
1843 DCHECK(IsMipsArchVariant(kLoongson) || IsMipsArchVariant(kMips32r1) ||
1844 IsMipsArchVariant(kMips32r2));
Steve Block44f0eee2011-05-26 01:26:41 +01001845 GenInstrImmediate(LWL, rs.rm(), rd, rs.offset_);
1846}
1847
1848
1849void Assembler::lwr(Register rd, const MemOperand& rs) {
Ben Murdochc5610432016-08-08 18:44:38 +01001850 DCHECK(is_int16(rs.offset_));
1851 DCHECK(IsMipsArchVariant(kLoongson) || IsMipsArchVariant(kMips32r1) ||
1852 IsMipsArchVariant(kMips32r2));
Steve Block44f0eee2011-05-26 01:26:41 +01001853 GenInstrImmediate(LWR, rs.rm(), rd, rs.offset_);
Andrei Popescu31002712010-02-23 13:46:05 +00001854}
1855
1856
1857void Assembler::sb(Register rd, const MemOperand& rs) {
Steve Block44f0eee2011-05-26 01:26:41 +01001858 if (is_int16(rs.offset_)) {
1859 GenInstrImmediate(SB, rs.rm(), rd, rs.offset_);
1860 } else { // Offset > 16 bits, use multiple instructions to store.
1861 LoadRegPlusOffsetToAt(rs);
1862 GenInstrImmediate(SB, at, rd, 0); // Equiv to sb(rd, MemOperand(at, 0));
1863 }
1864}
1865
1866
1867void Assembler::sh(Register rd, const MemOperand& rs) {
1868 if (is_int16(rs.offset_)) {
1869 GenInstrImmediate(SH, rs.rm(), rd, rs.offset_);
1870 } else { // Offset > 16 bits, use multiple instructions to store.
1871 LoadRegPlusOffsetToAt(rs);
1872 GenInstrImmediate(SH, at, rd, 0); // Equiv to sh(rd, MemOperand(at, 0));
1873 }
Andrei Popescu31002712010-02-23 13:46:05 +00001874}
1875
1876
1877void Assembler::sw(Register rd, const MemOperand& rs) {
Steve Block44f0eee2011-05-26 01:26:41 +01001878 if (is_int16(rs.offset_)) {
1879 GenInstrImmediate(SW, rs.rm(), rd, rs.offset_);
1880 } else { // Offset > 16 bits, use multiple instructions to store.
1881 LoadRegPlusOffsetToAt(rs);
1882 GenInstrImmediate(SW, at, rd, 0); // Equiv to sw(rd, MemOperand(at, 0));
1883 }
Steve Block44f0eee2011-05-26 01:26:41 +01001884}
1885
1886
1887void Assembler::swl(Register rd, const MemOperand& rs) {
Ben Murdochc5610432016-08-08 18:44:38 +01001888 DCHECK(is_int16(rs.offset_));
1889 DCHECK(IsMipsArchVariant(kLoongson) || IsMipsArchVariant(kMips32r1) ||
1890 IsMipsArchVariant(kMips32r2));
Steve Block44f0eee2011-05-26 01:26:41 +01001891 GenInstrImmediate(SWL, rs.rm(), rd, rs.offset_);
1892}
1893
1894
1895void Assembler::swr(Register rd, const MemOperand& rs) {
Ben Murdochc5610432016-08-08 18:44:38 +01001896 DCHECK(is_int16(rs.offset_));
1897 DCHECK(IsMipsArchVariant(kLoongson) || IsMipsArchVariant(kMips32r1) ||
1898 IsMipsArchVariant(kMips32r2));
Steve Block44f0eee2011-05-26 01:26:41 +01001899 GenInstrImmediate(SWR, rs.rm(), rd, rs.offset_);
Andrei Popescu31002712010-02-23 13:46:05 +00001900}
1901
1902
1903void Assembler::lui(Register rd, int32_t j) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001904 DCHECK(is_uint16(j));
Andrei Popescu31002712010-02-23 13:46:05 +00001905 GenInstrImmediate(LUI, zero_reg, rd, j);
1906}
1907
1908
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001909void Assembler::aui(Register rt, Register rs, int32_t j) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001910 // This instruction uses same opcode as 'lui'. The difference in encoding is
1911 // 'lui' has zero reg. for rs field.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001912 DCHECK(!(rs.is(zero_reg)));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001913 DCHECK(is_uint16(j));
1914 GenInstrImmediate(LUI, rs, rt, j);
1915}
1916
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001917// ---------PC-Relative instructions-----------
1918
1919void Assembler::addiupc(Register rs, int32_t imm19) {
1920 DCHECK(IsMipsArchVariant(kMips32r6));
1921 DCHECK(rs.is_valid() && is_int19(imm19));
1922 uint32_t imm21 = ADDIUPC << kImm19Bits | (imm19 & kImm19Mask);
1923 GenInstrImmediate(PCREL, rs, imm21);
1924}
1925
1926
1927void Assembler::lwpc(Register rs, int32_t offset19) {
1928 DCHECK(IsMipsArchVariant(kMips32r6));
1929 DCHECK(rs.is_valid() && is_int19(offset19));
1930 uint32_t imm21 = LWPC << kImm19Bits | (offset19 & kImm19Mask);
1931 GenInstrImmediate(PCREL, rs, imm21);
1932}
1933
1934
1935void Assembler::auipc(Register rs, int16_t imm16) {
1936 DCHECK(IsMipsArchVariant(kMips32r6));
1937 DCHECK(rs.is_valid());
1938 uint32_t imm21 = AUIPC << kImm16Bits | (imm16 & kImm16Mask);
1939 GenInstrImmediate(PCREL, rs, imm21);
1940}
1941
1942
1943void Assembler::aluipc(Register rs, int16_t imm16) {
1944 DCHECK(IsMipsArchVariant(kMips32r6));
1945 DCHECK(rs.is_valid());
1946 uint32_t imm21 = ALUIPC << kImm16Bits | (imm16 & kImm16Mask);
1947 GenInstrImmediate(PCREL, rs, imm21);
1948}
1949
1950
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001951// -------------Misc-instructions--------------
Andrei Popescu31002712010-02-23 13:46:05 +00001952
1953// Break / Trap instructions.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001954void Assembler::break_(uint32_t code, bool break_as_stop) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001955 DCHECK((code & ~0xfffff) == 0);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001956 // We need to invalidate breaks that could be stops as well because the
1957 // simulator expects a char pointer after the stop instruction.
1958 // See constants-mips.h for explanation.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001959 DCHECK((break_as_stop &&
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001960 code <= kMaxStopCode &&
1961 code > kMaxWatchpointCode) ||
1962 (!break_as_stop &&
1963 (code > kMaxStopCode ||
1964 code <= kMaxWatchpointCode)));
Andrei Popescu31002712010-02-23 13:46:05 +00001965 Instr break_instr = SPECIAL | BREAK | (code << 6);
1966 emit(break_instr);
1967}
1968
1969
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001970void Assembler::stop(const char* msg, uint32_t code) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001971 DCHECK(code > kMaxWatchpointCode);
1972 DCHECK(code <= kMaxStopCode);
1973#if V8_HOST_ARCH_MIPS
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001974 break_(0x54321);
1975#else // V8_HOST_ARCH_MIPS
1976 BlockTrampolinePoolFor(2);
1977 // The Simulator will handle the stop instruction and get the message address.
1978 // On MIPS stop() is just a special kind of break_().
1979 break_(code, true);
1980 emit(reinterpret_cast<Instr>(msg));
1981#endif
1982}
1983
1984
Andrei Popescu31002712010-02-23 13:46:05 +00001985void Assembler::tge(Register rs, Register rt, uint16_t code) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001986 DCHECK(is_uint10(code));
Andrei Popescu31002712010-02-23 13:46:05 +00001987 Instr instr = SPECIAL | TGE | rs.code() << kRsShift
1988 | rt.code() << kRtShift | code << 6;
1989 emit(instr);
1990}
1991
1992
1993void Assembler::tgeu(Register rs, Register rt, uint16_t code) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001994 DCHECK(is_uint10(code));
Andrei Popescu31002712010-02-23 13:46:05 +00001995 Instr instr = SPECIAL | TGEU | rs.code() << kRsShift
1996 | rt.code() << kRtShift | code << 6;
1997 emit(instr);
1998}
1999
2000
2001void Assembler::tlt(Register rs, Register rt, uint16_t code) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002002 DCHECK(is_uint10(code));
Andrei Popescu31002712010-02-23 13:46:05 +00002003 Instr instr =
2004 SPECIAL | TLT | rs.code() << kRsShift | rt.code() << kRtShift | code << 6;
2005 emit(instr);
2006}
2007
2008
2009void Assembler::tltu(Register rs, Register rt, uint16_t code) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002010 DCHECK(is_uint10(code));
Steve Block44f0eee2011-05-26 01:26:41 +01002011 Instr instr =
2012 SPECIAL | TLTU | rs.code() << kRsShift
Andrei Popescu31002712010-02-23 13:46:05 +00002013 | rt.code() << kRtShift | code << 6;
2014 emit(instr);
2015}
2016
2017
2018void Assembler::teq(Register rs, Register rt, uint16_t code) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002019 DCHECK(is_uint10(code));
Andrei Popescu31002712010-02-23 13:46:05 +00002020 Instr instr =
2021 SPECIAL | TEQ | rs.code() << kRsShift | rt.code() << kRtShift | code << 6;
2022 emit(instr);
2023}
2024
2025
2026void Assembler::tne(Register rs, Register rt, uint16_t code) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002027 DCHECK(is_uint10(code));
Andrei Popescu31002712010-02-23 13:46:05 +00002028 Instr instr =
2029 SPECIAL | TNE | rs.code() << kRsShift | rt.code() << kRtShift | code << 6;
2030 emit(instr);
2031}
2032
Ben Murdochc5610432016-08-08 18:44:38 +01002033void Assembler::sync() {
2034 Instr sync_instr = SPECIAL | SYNC;
2035 emit(sync_instr);
2036}
Andrei Popescu31002712010-02-23 13:46:05 +00002037
2038// Move from HI/LO register.
2039
2040void Assembler::mfhi(Register rd) {
2041 GenInstrRegister(SPECIAL, zero_reg, zero_reg, rd, 0, MFHI);
2042}
2043
2044
2045void Assembler::mflo(Register rd) {
2046 GenInstrRegister(SPECIAL, zero_reg, zero_reg, rd, 0, MFLO);
2047}
2048
2049
2050// Set on less than instructions.
2051void Assembler::slt(Register rd, Register rs, Register rt) {
2052 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SLT);
2053}
2054
2055
2056void Assembler::sltu(Register rd, Register rs, Register rt) {
2057 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SLTU);
2058}
2059
2060
2061void Assembler::slti(Register rt, Register rs, int32_t j) {
2062 GenInstrImmediate(SLTI, rs, rt, j);
2063}
2064
2065
2066void Assembler::sltiu(Register rt, Register rs, int32_t j) {
2067 GenInstrImmediate(SLTIU, rs, rt, j);
2068}
2069
2070
Steve Block44f0eee2011-05-26 01:26:41 +01002071// Conditional move.
2072void Assembler::movz(Register rd, Register rs, Register rt) {
2073 GenInstrRegister(SPECIAL, rs, rt, rd, 0, MOVZ);
2074}
2075
2076
2077void Assembler::movn(Register rd, Register rs, Register rt) {
2078 GenInstrRegister(SPECIAL, rs, rt, rd, 0, MOVN);
2079}
2080
2081
2082void Assembler::movt(Register rd, Register rs, uint16_t cc) {
2083 Register rt;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002084 rt.reg_code = (cc & 0x0007) << 2 | 1;
Steve Block44f0eee2011-05-26 01:26:41 +01002085 GenInstrRegister(SPECIAL, rs, rt, rd, 0, MOVCI);
2086}
2087
2088
2089void Assembler::movf(Register rd, Register rs, uint16_t cc) {
2090 Register rt;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002091 rt.reg_code = (cc & 0x0007) << 2 | 0;
Steve Block44f0eee2011-05-26 01:26:41 +01002092 GenInstrRegister(SPECIAL, rs, rt, rd, 0, MOVCI);
2093}
2094
2095
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002096void Assembler::seleqz(Register rd, Register rs, Register rt) {
2097 DCHECK(IsMipsArchVariant(kMips32r6));
2098 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SELEQZ_S);
2099}
2100
2101
Steve Block44f0eee2011-05-26 01:26:41 +01002102// Bit twiddling.
2103void Assembler::clz(Register rd, Register rs) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002104 if (!IsMipsArchVariant(kMips32r6)) {
2105 // Clz instr requires same GPR number in 'rd' and 'rt' fields.
2106 GenInstrRegister(SPECIAL2, rs, rd, rd, 0, CLZ);
2107 } else {
2108 GenInstrRegister(SPECIAL, rs, zero_reg, rd, 1, CLZ_R6);
2109 }
Steve Block44f0eee2011-05-26 01:26:41 +01002110}
2111
2112
2113void Assembler::ins_(Register rt, Register rs, uint16_t pos, uint16_t size) {
2114 // Should be called via MacroAssembler::Ins.
2115 // Ins instr has 'rt' field as dest, and two uint5: msb, lsb.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002116 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
Steve Block44f0eee2011-05-26 01:26:41 +01002117 GenInstrRegister(SPECIAL3, rs, rt, pos + size - 1, pos, INS);
2118}
2119
2120
2121void Assembler::ext_(Register rt, Register rs, uint16_t pos, uint16_t size) {
2122 // Should be called via MacroAssembler::Ext.
2123 // Ext instr has 'rt' field as dest, and two uint5: msb, lsb.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002124 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
Steve Block44f0eee2011-05-26 01:26:41 +01002125 GenInstrRegister(SPECIAL3, rs, rt, size - 1, pos, EXT);
2126}
2127
2128
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002129void Assembler::bitswap(Register rd, Register rt) {
2130 DCHECK(IsMipsArchVariant(kMips32r6));
2131 GenInstrRegister(SPECIAL3, zero_reg, rt, rd, 0, BSHFL);
2132}
2133
2134
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002135void Assembler::pref(int32_t hint, const MemOperand& rs) {
2136 DCHECK(!IsMipsArchVariant(kLoongson));
2137 DCHECK(is_uint5(hint) && is_uint16(rs.offset_));
2138 Instr instr = PREF | (rs.rm().code() << kRsShift) | (hint << kRtShift)
2139 | (rs.offset_);
2140 emit(instr);
2141}
2142
2143
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002144void Assembler::align(Register rd, Register rs, Register rt, uint8_t bp) {
2145 DCHECK(IsMipsArchVariant(kMips32r6));
2146 DCHECK(is_uint3(bp));
2147 uint16_t sa = (ALIGN << kBp2Bits) | bp;
2148 GenInstrRegister(SPECIAL3, rs, rt, rd, sa, BSHFL);
2149}
2150
Ben Murdoch61f157c2016-09-16 13:49:30 +01002151// Byte swap.
2152void Assembler::wsbh(Register rd, Register rt) {
2153 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
2154 GenInstrRegister(SPECIAL3, zero_reg, rt, rd, WSBH, BSHFL);
2155}
2156
2157void Assembler::seh(Register rd, Register rt) {
2158 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
2159 GenInstrRegister(SPECIAL3, zero_reg, rt, rd, SEH, BSHFL);
2160}
2161
2162void Assembler::seb(Register rd, Register rt) {
2163 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
2164 GenInstrRegister(SPECIAL3, zero_reg, rt, rd, SEB, BSHFL);
2165}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002166
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002167// --------Coprocessor-instructions----------------
Andrei Popescu31002712010-02-23 13:46:05 +00002168
2169// Load, store, move.
2170void Assembler::lwc1(FPURegister fd, const MemOperand& src) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002171 if (is_int16(src.offset_)) {
2172 GenInstrImmediate(LWC1, src.rm(), fd, src.offset_);
2173 } else { // Offset > 16 bits, use multiple instructions to load.
2174 LoadRegPlusOffsetToAt(src);
2175 GenInstrImmediate(LWC1, at, fd, 0);
2176 }
Andrei Popescu31002712010-02-23 13:46:05 +00002177}
2178
2179
2180void Assembler::ldc1(FPURegister fd, const MemOperand& src) {
Steve Block44f0eee2011-05-26 01:26:41 +01002181 // Workaround for non-8-byte alignment of HeapNumber, convert 64-bit
2182 // load to two 32-bit loads.
Ben Murdoch097c5b22016-05-18 11:27:45 +01002183 if (IsFp32Mode()) { // fp32 mode.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002184 if (is_int16(src.offset_) && is_int16(src.offset_ + kIntSize)) {
2185 GenInstrImmediate(LWC1, src.rm(), fd,
2186 src.offset_ + Register::kMantissaOffset);
2187 FPURegister nextfpreg;
2188 nextfpreg.setcode(fd.code() + 1);
2189 GenInstrImmediate(LWC1, src.rm(), nextfpreg,
2190 src.offset_ + Register::kExponentOffset);
2191 } else { // Offset > 16 bits, use multiple instructions to load.
2192 LoadRegPlusOffsetToAt(src);
2193 GenInstrImmediate(LWC1, at, fd, Register::kMantissaOffset);
2194 FPURegister nextfpreg;
2195 nextfpreg.setcode(fd.code() + 1);
2196 GenInstrImmediate(LWC1, at, nextfpreg, Register::kExponentOffset);
2197 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01002198 } else {
2199 DCHECK(IsFp64Mode() || IsFpxxMode());
2200 // Currently we support FPXX and FP64 on Mips32r2 and Mips32r6
2201 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
2202 if (is_int16(src.offset_) && is_int16(src.offset_ + kIntSize)) {
2203 GenInstrImmediate(LWC1, src.rm(), fd,
2204 src.offset_ + Register::kMantissaOffset);
2205 GenInstrImmediate(LW, src.rm(), at,
2206 src.offset_ + Register::kExponentOffset);
2207 mthc1(at, fd);
2208 } else { // Offset > 16 bits, use multiple instructions to load.
2209 LoadRegPlusOffsetToAt(src);
2210 GenInstrImmediate(LWC1, at, fd, Register::kMantissaOffset);
2211 GenInstrImmediate(LW, at, at, Register::kExponentOffset);
2212 mthc1(at, fd);
2213 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002214 }
Andrei Popescu31002712010-02-23 13:46:05 +00002215}
2216
2217
2218void Assembler::swc1(FPURegister fd, const MemOperand& src) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002219 if (is_int16(src.offset_)) {
2220 GenInstrImmediate(SWC1, src.rm(), fd, src.offset_);
2221 } else { // Offset > 16 bits, use multiple instructions to load.
2222 LoadRegPlusOffsetToAt(src);
2223 GenInstrImmediate(SWC1, at, fd, 0);
2224 }
Andrei Popescu31002712010-02-23 13:46:05 +00002225}
2226
2227
2228void Assembler::sdc1(FPURegister fd, const MemOperand& src) {
Steve Block44f0eee2011-05-26 01:26:41 +01002229 // Workaround for non-8-byte alignment of HeapNumber, convert 64-bit
2230 // store to two 32-bit stores.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002231 DCHECK(!src.rm().is(at));
2232 DCHECK(!src.rm().is(t8));
Ben Murdoch097c5b22016-05-18 11:27:45 +01002233 if (IsFp32Mode()) { // fp32 mode.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002234 if (is_int16(src.offset_) && is_int16(src.offset_ + kIntSize)) {
2235 GenInstrImmediate(SWC1, src.rm(), fd,
2236 src.offset_ + Register::kMantissaOffset);
2237 FPURegister nextfpreg;
2238 nextfpreg.setcode(fd.code() + 1);
2239 GenInstrImmediate(SWC1, src.rm(), nextfpreg,
2240 src.offset_ + Register::kExponentOffset);
2241 } else { // Offset > 16 bits, use multiple instructions to load.
2242 LoadRegPlusOffsetToAt(src);
2243 GenInstrImmediate(SWC1, at, fd, Register::kMantissaOffset);
2244 FPURegister nextfpreg;
2245 nextfpreg.setcode(fd.code() + 1);
2246 GenInstrImmediate(SWC1, at, nextfpreg, Register::kExponentOffset);
2247 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01002248 } else {
2249 DCHECK(IsFp64Mode() || IsFpxxMode());
2250 // Currently we support FPXX and FP64 on Mips32r2 and Mips32r6
2251 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
2252 if (is_int16(src.offset_) && is_int16(src.offset_ + kIntSize)) {
2253 GenInstrImmediate(SWC1, src.rm(), fd,
2254 src.offset_ + Register::kMantissaOffset);
2255 mfhc1(at, fd);
2256 GenInstrImmediate(SW, src.rm(), at,
2257 src.offset_ + Register::kExponentOffset);
2258 } else { // Offset > 16 bits, use multiple instructions to load.
2259 LoadRegPlusOffsetToAt(src);
2260 GenInstrImmediate(SWC1, at, fd, Register::kMantissaOffset);
2261 mfhc1(t8, fd);
2262 GenInstrImmediate(SW, at, t8, Register::kExponentOffset);
2263 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002264 }
Andrei Popescu31002712010-02-23 13:46:05 +00002265}
2266
2267
Steve Block44f0eee2011-05-26 01:26:41 +01002268void Assembler::mtc1(Register rt, FPURegister fs) {
Andrei Popescu31002712010-02-23 13:46:05 +00002269 GenInstrRegister(COP1, MTC1, rt, fs, f0);
2270}
2271
2272
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002273void Assembler::mthc1(Register rt, FPURegister fs) {
2274 GenInstrRegister(COP1, MTHC1, rt, fs, f0);
2275}
2276
2277
Steve Block44f0eee2011-05-26 01:26:41 +01002278void Assembler::mfc1(Register rt, FPURegister fs) {
Andrei Popescu31002712010-02-23 13:46:05 +00002279 GenInstrRegister(COP1, MFC1, rt, fs, f0);
2280}
2281
2282
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002283void Assembler::mfhc1(Register rt, FPURegister fs) {
2284 GenInstrRegister(COP1, MFHC1, rt, fs, f0);
2285}
2286
2287
Steve Block44f0eee2011-05-26 01:26:41 +01002288void Assembler::ctc1(Register rt, FPUControlRegister fs) {
2289 GenInstrRegister(COP1, CTC1, rt, fs);
2290}
2291
2292
2293void Assembler::cfc1(Register rt, FPUControlRegister fs) {
2294 GenInstrRegister(COP1, CFC1, rt, fs);
2295}
2296
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002297
Ben Murdoch589d6972011-11-30 16:04:58 +00002298void Assembler::DoubleAsTwoUInt32(double d, uint32_t* lo, uint32_t* hi) {
2299 uint64_t i;
2300 memcpy(&i, &d, 8);
2301
2302 *lo = i & 0xffffffff;
2303 *hi = i >> 32;
2304}
Steve Block44f0eee2011-05-26 01:26:41 +01002305
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002306
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002307void Assembler::movn_s(FPURegister fd, FPURegister fs, Register rt) {
2308 DCHECK(!IsMipsArchVariant(kMips32r6));
2309 GenInstrRegister(COP1, S, rt, fs, fd, MOVN_C);
2310}
2311
2312
2313void Assembler::movn_d(FPURegister fd, FPURegister fs, Register rt) {
2314 DCHECK(!IsMipsArchVariant(kMips32r6));
2315 GenInstrRegister(COP1, D, rt, fs, fd, MOVN_C);
2316}
2317
2318
2319void Assembler::sel(SecondaryField fmt, FPURegister fd, FPURegister fs,
2320 FPURegister ft) {
2321 DCHECK(IsMipsArchVariant(kMips32r6));
2322 DCHECK((fmt == D) || (fmt == S));
2323
2324 GenInstrRegister(COP1, fmt, ft, fs, fd, SEL);
2325}
2326
2327
2328void Assembler::sel_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2329 sel(S, fd, fs, ft);
2330}
2331
2332
2333void Assembler::sel_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2334 sel(D, fd, fs, ft);
2335}
2336
2337
2338void Assembler::seleqz(SecondaryField fmt, FPURegister fd, FPURegister fs,
2339 FPURegister ft) {
2340 DCHECK(IsMipsArchVariant(kMips32r6));
2341 DCHECK((fmt == D) || (fmt == S));
2342 GenInstrRegister(COP1, fmt, ft, fs, fd, SELEQZ_C);
2343}
2344
2345
2346void Assembler::selnez(Register rd, Register rs, Register rt) {
2347 DCHECK(IsMipsArchVariant(kMips32r6));
2348 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SELNEZ_S);
2349}
2350
2351
2352void Assembler::selnez(SecondaryField fmt, FPURegister fd, FPURegister fs,
2353 FPURegister ft) {
2354 DCHECK(IsMipsArchVariant(kMips32r6));
2355 DCHECK((fmt == D) || (fmt == S));
2356 GenInstrRegister(COP1, fmt, ft, fs, fd, SELNEZ_C);
2357}
2358
2359
2360void Assembler::seleqz_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2361 seleqz(D, fd, fs, ft);
2362}
2363
2364
2365void Assembler::seleqz_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2366 seleqz(S, fd, fs, ft);
2367}
2368
2369
2370void Assembler::selnez_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2371 selnez(D, fd, fs, ft);
2372}
2373
2374
2375void Assembler::selnez_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2376 selnez(S, fd, fs, ft);
2377}
2378
2379
2380void Assembler::movz_s(FPURegister fd, FPURegister fs, Register rt) {
2381 DCHECK(!IsMipsArchVariant(kMips32r6));
2382 GenInstrRegister(COP1, S, rt, fs, fd, MOVZ_C);
2383}
2384
2385
2386void Assembler::movz_d(FPURegister fd, FPURegister fs, Register rt) {
2387 DCHECK(!IsMipsArchVariant(kMips32r6));
2388 GenInstrRegister(COP1, D, rt, fs, fd, MOVZ_C);
2389}
2390
2391
2392void Assembler::movt_s(FPURegister fd, FPURegister fs, uint16_t cc) {
2393 DCHECK(!IsMipsArchVariant(kMips32r6));
2394 FPURegister ft;
2395 ft.reg_code = (cc & 0x0007) << 2 | 1;
2396 GenInstrRegister(COP1, S, ft, fs, fd, MOVF);
2397}
2398
2399
2400void Assembler::movt_d(FPURegister fd, FPURegister fs, uint16_t cc) {
2401 DCHECK(!IsMipsArchVariant(kMips32r6));
2402 FPURegister ft;
2403 ft.reg_code = (cc & 0x0007) << 2 | 1;
2404 GenInstrRegister(COP1, D, ft, fs, fd, MOVF);
2405}
2406
2407
2408void Assembler::movf_s(FPURegister fd, FPURegister fs, uint16_t cc) {
2409 DCHECK(!IsMipsArchVariant(kMips32r6));
2410 FPURegister ft;
2411 ft.reg_code = (cc & 0x0007) << 2 | 0;
2412 GenInstrRegister(COP1, S, ft, fs, fd, MOVF);
2413}
2414
2415
2416void Assembler::movf_d(FPURegister fd, FPURegister fs, uint16_t cc) {
2417 DCHECK(!IsMipsArchVariant(kMips32r6));
2418 FPURegister ft;
2419 ft.reg_code = (cc & 0x0007) << 2 | 0;
2420 GenInstrRegister(COP1, D, ft, fs, fd, MOVF);
2421}
2422
2423
Steve Block44f0eee2011-05-26 01:26:41 +01002424// Arithmetic.
2425
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002426void Assembler::add_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2427 GenInstrRegister(COP1, S, ft, fs, fd, ADD_S);
2428}
2429
2430
Steve Block44f0eee2011-05-26 01:26:41 +01002431void Assembler::add_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2432 GenInstrRegister(COP1, D, ft, fs, fd, ADD_D);
2433}
2434
2435
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002436void Assembler::sub_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2437 GenInstrRegister(COP1, S, ft, fs, fd, SUB_S);
2438}
2439
2440
Steve Block44f0eee2011-05-26 01:26:41 +01002441void Assembler::sub_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2442 GenInstrRegister(COP1, D, ft, fs, fd, SUB_D);
2443}
2444
2445
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002446void Assembler::mul_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2447 GenInstrRegister(COP1, S, ft, fs, fd, MUL_S);
2448}
2449
2450
Steve Block44f0eee2011-05-26 01:26:41 +01002451void Assembler::mul_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2452 GenInstrRegister(COP1, D, ft, fs, fd, MUL_D);
2453}
2454
2455
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002456void Assembler::madd_d(FPURegister fd, FPURegister fr, FPURegister fs,
2457 FPURegister ft) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002458 DCHECK(IsMipsArchVariant(kMips32r2));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002459 GenInstrRegister(COP1X, fr, ft, fs, fd, MADD_D);
2460}
2461
2462
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002463void Assembler::div_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2464 GenInstrRegister(COP1, S, ft, fs, fd, DIV_S);
2465}
2466
2467
Steve Block44f0eee2011-05-26 01:26:41 +01002468void Assembler::div_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2469 GenInstrRegister(COP1, D, ft, fs, fd, DIV_D);
2470}
2471
2472
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002473void Assembler::abs_s(FPURegister fd, FPURegister fs) {
2474 GenInstrRegister(COP1, S, f0, fs, fd, ABS_S);
2475}
2476
2477
Steve Block44f0eee2011-05-26 01:26:41 +01002478void Assembler::abs_d(FPURegister fd, FPURegister fs) {
2479 GenInstrRegister(COP1, D, f0, fs, fd, ABS_D);
2480}
2481
2482
2483void Assembler::mov_d(FPURegister fd, FPURegister fs) {
2484 GenInstrRegister(COP1, D, f0, fs, fd, MOV_D);
2485}
2486
2487
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002488void Assembler::mov_s(FPURegister fd, FPURegister fs) {
2489 GenInstrRegister(COP1, S, f0, fs, fd, MOV_S);
2490}
2491
2492
2493void Assembler::neg_s(FPURegister fd, FPURegister fs) {
2494 GenInstrRegister(COP1, S, f0, fs, fd, NEG_S);
2495}
2496
2497
Steve Block44f0eee2011-05-26 01:26:41 +01002498void Assembler::neg_d(FPURegister fd, FPURegister fs) {
2499 GenInstrRegister(COP1, D, f0, fs, fd, NEG_D);
2500}
2501
2502
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002503void Assembler::sqrt_s(FPURegister fd, FPURegister fs) {
2504 GenInstrRegister(COP1, S, f0, fs, fd, SQRT_S);
2505}
2506
2507
Steve Block44f0eee2011-05-26 01:26:41 +01002508void Assembler::sqrt_d(FPURegister fd, FPURegister fs) {
2509 GenInstrRegister(COP1, D, f0, fs, fd, SQRT_D);
Andrei Popescu31002712010-02-23 13:46:05 +00002510}
2511
2512
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002513void Assembler::rsqrt_s(FPURegister fd, FPURegister fs) {
2514 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
2515 GenInstrRegister(COP1, S, f0, fs, fd, RSQRT_S);
2516}
2517
2518
2519void Assembler::rsqrt_d(FPURegister fd, FPURegister fs) {
2520 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
2521 GenInstrRegister(COP1, D, f0, fs, fd, RSQRT_D);
2522}
2523
2524
2525void Assembler::recip_d(FPURegister fd, FPURegister fs) {
2526 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
2527 GenInstrRegister(COP1, D, f0, fs, fd, RECIP_D);
2528}
2529
2530
2531void Assembler::recip_s(FPURegister fd, FPURegister fs) {
2532 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
2533 GenInstrRegister(COP1, S, f0, fs, fd, RECIP_S);
2534}
2535
2536
Andrei Popescu31002712010-02-23 13:46:05 +00002537// Conversions.
2538
2539void Assembler::cvt_w_s(FPURegister fd, FPURegister fs) {
2540 GenInstrRegister(COP1, S, f0, fs, fd, CVT_W_S);
2541}
2542
2543
2544void Assembler::cvt_w_d(FPURegister fd, FPURegister fs) {
2545 GenInstrRegister(COP1, D, f0, fs, fd, CVT_W_D);
2546}
2547
2548
Steve Block44f0eee2011-05-26 01:26:41 +01002549void Assembler::trunc_w_s(FPURegister fd, FPURegister fs) {
2550 GenInstrRegister(COP1, S, f0, fs, fd, TRUNC_W_S);
2551}
2552
2553
2554void Assembler::trunc_w_d(FPURegister fd, FPURegister fs) {
2555 GenInstrRegister(COP1, D, f0, fs, fd, TRUNC_W_D);
2556}
2557
2558
2559void Assembler::round_w_s(FPURegister fd, FPURegister fs) {
2560 GenInstrRegister(COP1, S, f0, fs, fd, ROUND_W_S);
2561}
2562
2563
2564void Assembler::round_w_d(FPURegister fd, FPURegister fs) {
2565 GenInstrRegister(COP1, D, f0, fs, fd, ROUND_W_D);
2566}
2567
2568
2569void Assembler::floor_w_s(FPURegister fd, FPURegister fs) {
2570 GenInstrRegister(COP1, S, f0, fs, fd, FLOOR_W_S);
2571}
2572
2573
2574void Assembler::floor_w_d(FPURegister fd, FPURegister fs) {
2575 GenInstrRegister(COP1, D, f0, fs, fd, FLOOR_W_D);
2576}
2577
2578
2579void Assembler::ceil_w_s(FPURegister fd, FPURegister fs) {
2580 GenInstrRegister(COP1, S, f0, fs, fd, CEIL_W_S);
2581}
2582
2583
2584void Assembler::ceil_w_d(FPURegister fd, FPURegister fs) {
2585 GenInstrRegister(COP1, D, f0, fs, fd, CEIL_W_D);
2586}
2587
2588
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002589void Assembler::rint_s(FPURegister fd, FPURegister fs) { rint(S, fd, fs); }
2590
2591
2592void Assembler::rint(SecondaryField fmt, FPURegister fd, FPURegister fs) {
2593 DCHECK(IsMipsArchVariant(kMips32r6));
2594 DCHECK((fmt == D) || (fmt == S));
2595 GenInstrRegister(COP1, fmt, f0, fs, fd, RINT);
2596}
2597
2598
2599void Assembler::rint_d(FPURegister fd, FPURegister fs) { rint(D, fd, fs); }
2600
2601
Andrei Popescu31002712010-02-23 13:46:05 +00002602void Assembler::cvt_l_s(FPURegister fd, FPURegister fs) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002603 DCHECK((IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) &&
2604 IsFp64Mode());
Andrei Popescu31002712010-02-23 13:46:05 +00002605 GenInstrRegister(COP1, S, f0, fs, fd, CVT_L_S);
2606}
2607
2608
2609void Assembler::cvt_l_d(FPURegister fd, FPURegister fs) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002610 DCHECK((IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) &&
2611 IsFp64Mode());
Andrei Popescu31002712010-02-23 13:46:05 +00002612 GenInstrRegister(COP1, D, f0, fs, fd, CVT_L_D);
2613}
2614
2615
Steve Block44f0eee2011-05-26 01:26:41 +01002616void Assembler::trunc_l_s(FPURegister fd, FPURegister fs) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002617 DCHECK((IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) &&
2618 IsFp64Mode());
Steve Block44f0eee2011-05-26 01:26:41 +01002619 GenInstrRegister(COP1, S, f0, fs, fd, TRUNC_L_S);
2620}
2621
2622
2623void Assembler::trunc_l_d(FPURegister fd, FPURegister fs) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002624 DCHECK((IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) &&
2625 IsFp64Mode());
Steve Block44f0eee2011-05-26 01:26:41 +01002626 GenInstrRegister(COP1, D, f0, fs, fd, TRUNC_L_D);
2627}
2628
2629
2630void Assembler::round_l_s(FPURegister fd, FPURegister fs) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002631 DCHECK((IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) &&
2632 IsFp64Mode());
Steve Block44f0eee2011-05-26 01:26:41 +01002633 GenInstrRegister(COP1, S, f0, fs, fd, ROUND_L_S);
2634}
2635
2636
2637void Assembler::round_l_d(FPURegister fd, FPURegister fs) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002638 DCHECK((IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) &&
2639 IsFp64Mode());
Steve Block44f0eee2011-05-26 01:26:41 +01002640 GenInstrRegister(COP1, D, f0, fs, fd, ROUND_L_D);
2641}
2642
2643
2644void Assembler::floor_l_s(FPURegister fd, FPURegister fs) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002645 DCHECK((IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) &&
2646 IsFp64Mode());
Steve Block44f0eee2011-05-26 01:26:41 +01002647 GenInstrRegister(COP1, S, f0, fs, fd, FLOOR_L_S);
2648}
2649
2650
2651void Assembler::floor_l_d(FPURegister fd, FPURegister fs) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002652 DCHECK((IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) &&
2653 IsFp64Mode());
Steve Block44f0eee2011-05-26 01:26:41 +01002654 GenInstrRegister(COP1, D, f0, fs, fd, FLOOR_L_D);
2655}
2656
2657
2658void Assembler::ceil_l_s(FPURegister fd, FPURegister fs) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002659 DCHECK((IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) &&
2660 IsFp64Mode());
Steve Block44f0eee2011-05-26 01:26:41 +01002661 GenInstrRegister(COP1, S, f0, fs, fd, CEIL_L_S);
2662}
2663
2664
2665void Assembler::ceil_l_d(FPURegister fd, FPURegister fs) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002666 DCHECK((IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) &&
2667 IsFp64Mode());
Steve Block44f0eee2011-05-26 01:26:41 +01002668 GenInstrRegister(COP1, D, f0, fs, fd, CEIL_L_D);
2669}
2670
2671
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002672void Assembler::class_s(FPURegister fd, FPURegister fs) {
2673 DCHECK(IsMipsArchVariant(kMips32r6));
2674 GenInstrRegister(COP1, S, f0, fs, fd, CLASS_S);
2675}
2676
2677
2678void Assembler::class_d(FPURegister fd, FPURegister fs) {
2679 DCHECK(IsMipsArchVariant(kMips32r6));
2680 GenInstrRegister(COP1, D, f0, fs, fd, CLASS_D);
2681}
2682
2683
2684void Assembler::min(SecondaryField fmt, FPURegister fd, FPURegister fs,
2685 FPURegister ft) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002686 DCHECK(IsMipsArchVariant(kMips32r6));
2687 DCHECK((fmt == D) || (fmt == S));
2688 GenInstrRegister(COP1, fmt, ft, fs, fd, MIN);
2689}
2690
2691
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002692void Assembler::mina(SecondaryField fmt, FPURegister fd, FPURegister fs,
2693 FPURegister ft) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002694 DCHECK(IsMipsArchVariant(kMips32r6));
2695 DCHECK((fmt == D) || (fmt == S));
2696 GenInstrRegister(COP1, fmt, ft, fs, fd, MINA);
2697}
2698
2699
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002700void Assembler::max(SecondaryField fmt, FPURegister fd, FPURegister fs,
2701 FPURegister ft) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002702 DCHECK(IsMipsArchVariant(kMips32r6));
2703 DCHECK((fmt == D) || (fmt == S));
2704 GenInstrRegister(COP1, fmt, ft, fs, fd, MAX);
2705}
2706
2707
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002708void Assembler::maxa(SecondaryField fmt, FPURegister fd, FPURegister fs,
2709 FPURegister ft) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002710 DCHECK(IsMipsArchVariant(kMips32r6));
2711 DCHECK((fmt == D) || (fmt == S));
2712 GenInstrRegister(COP1, fmt, ft, fs, fd, MAXA);
2713}
2714
2715
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002716void Assembler::min_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2717 min(S, fd, fs, ft);
2718}
2719
2720
2721void Assembler::min_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2722 min(D, fd, fs, ft);
2723}
2724
2725
2726void Assembler::max_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2727 max(S, fd, fs, ft);
2728}
2729
2730
2731void Assembler::max_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2732 max(D, fd, fs, ft);
2733}
2734
2735
2736void Assembler::mina_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2737 mina(S, fd, fs, ft);
2738}
2739
2740
2741void Assembler::mina_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2742 mina(D, fd, fs, ft);
2743}
2744
2745
2746void Assembler::maxa_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2747 maxa(S, fd, fs, ft);
2748}
2749
2750
2751void Assembler::maxa_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2752 maxa(D, fd, fs, ft);
2753}
2754
2755
Andrei Popescu31002712010-02-23 13:46:05 +00002756void Assembler::cvt_s_w(FPURegister fd, FPURegister fs) {
2757 GenInstrRegister(COP1, W, f0, fs, fd, CVT_S_W);
2758}
2759
2760
2761void Assembler::cvt_s_l(FPURegister fd, FPURegister fs) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002762 DCHECK((IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) &&
2763 IsFp64Mode());
Andrei Popescu31002712010-02-23 13:46:05 +00002764 GenInstrRegister(COP1, L, f0, fs, fd, CVT_S_L);
2765}
2766
2767
2768void Assembler::cvt_s_d(FPURegister fd, FPURegister fs) {
2769 GenInstrRegister(COP1, D, f0, fs, fd, CVT_S_D);
2770}
2771
2772
2773void Assembler::cvt_d_w(FPURegister fd, FPURegister fs) {
2774 GenInstrRegister(COP1, W, f0, fs, fd, CVT_D_W);
2775}
2776
2777
2778void Assembler::cvt_d_l(FPURegister fd, FPURegister fs) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002779 DCHECK((IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) &&
2780 IsFp64Mode());
Andrei Popescu31002712010-02-23 13:46:05 +00002781 GenInstrRegister(COP1, L, f0, fs, fd, CVT_D_L);
2782}
2783
2784
2785void Assembler::cvt_d_s(FPURegister fd, FPURegister fs) {
2786 GenInstrRegister(COP1, S, f0, fs, fd, CVT_D_S);
2787}
2788
2789
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002790// Conditions for >= MIPSr6.
2791void Assembler::cmp(FPUCondition cond, SecondaryField fmt,
2792 FPURegister fd, FPURegister fs, FPURegister ft) {
2793 DCHECK(IsMipsArchVariant(kMips32r6));
2794 DCHECK((fmt & ~(31 << kRsShift)) == 0);
2795 Instr instr = COP1 | fmt | ft.code() << kFtShift |
2796 fs.code() << kFsShift | fd.code() << kFdShift | (0 << 5) | cond;
2797 emit(instr);
2798}
2799
2800
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002801void Assembler::cmp_s(FPUCondition cond, FPURegister fd, FPURegister fs,
2802 FPURegister ft) {
2803 cmp(cond, W, fd, fs, ft);
2804}
2805
2806void Assembler::cmp_d(FPUCondition cond, FPURegister fd, FPURegister fs,
2807 FPURegister ft) {
2808 cmp(cond, L, fd, fs, ft);
2809}
2810
2811
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002812void Assembler::bc1eqz(int16_t offset, FPURegister ft) {
2813 DCHECK(IsMipsArchVariant(kMips32r6));
2814 Instr instr = COP1 | BC1EQZ | ft.code() << kFtShift | (offset & kImm16Mask);
2815 emit(instr);
2816}
2817
2818
2819void Assembler::bc1nez(int16_t offset, FPURegister ft) {
2820 DCHECK(IsMipsArchVariant(kMips32r6));
2821 Instr instr = COP1 | BC1NEZ | ft.code() << kFtShift | (offset & kImm16Mask);
2822 emit(instr);
2823}
2824
2825
2826// Conditions for < MIPSr6.
Andrei Popescu31002712010-02-23 13:46:05 +00002827void Assembler::c(FPUCondition cond, SecondaryField fmt,
Steve Block44f0eee2011-05-26 01:26:41 +01002828 FPURegister fs, FPURegister ft, uint16_t cc) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002829 DCHECK(is_uint3(cc));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002830 DCHECK(fmt == S || fmt == D);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002831 DCHECK((fmt & ~(31 << kRsShift)) == 0);
Andrei Popescu31002712010-02-23 13:46:05 +00002832 Instr instr = COP1 | fmt | ft.code() << 16 | fs.code() << kFsShift
2833 | cc << 8 | 3 << 4 | cond;
2834 emit(instr);
2835}
2836
2837
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002838void Assembler::c_s(FPUCondition cond, FPURegister fs, FPURegister ft,
2839 uint16_t cc) {
2840 c(cond, S, fs, ft, cc);
2841}
2842
2843
2844void Assembler::c_d(FPUCondition cond, FPURegister fs, FPURegister ft,
2845 uint16_t cc) {
2846 c(cond, D, fs, ft, cc);
2847}
2848
2849
Steve Block44f0eee2011-05-26 01:26:41 +01002850void Assembler::fcmp(FPURegister src1, const double src2,
2851 FPUCondition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002852 DCHECK(src2 == 0.0);
Steve Block44f0eee2011-05-26 01:26:41 +01002853 mtc1(zero_reg, f14);
2854 cvt_d_w(f14, f14);
2855 c(cond, D, src1, f14, 0);
2856}
2857
2858
Andrei Popescu31002712010-02-23 13:46:05 +00002859void Assembler::bc1f(int16_t offset, uint16_t cc) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002860 DCHECK(is_uint3(cc));
Andrei Popescu31002712010-02-23 13:46:05 +00002861 Instr instr = COP1 | BC1 | cc << 18 | 0 << 16 | (offset & kImm16Mask);
2862 emit(instr);
2863}
2864
2865
2866void Assembler::bc1t(int16_t offset, uint16_t cc) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002867 DCHECK(is_uint3(cc));
Andrei Popescu31002712010-02-23 13:46:05 +00002868 Instr instr = COP1 | BC1 | cc << 18 | 1 << 16 | (offset & kImm16Mask);
2869 emit(instr);
2870}
2871
2872
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002873int Assembler::RelocateInternalReference(RelocInfo::Mode rmode, byte* pc,
2874 intptr_t pc_delta) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002875 Instr instr = instr_at(pc);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002876
2877 if (RelocInfo::IsInternalReference(rmode)) {
2878 int32_t* p = reinterpret_cast<int32_t*>(pc);
2879 if (*p == 0) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002880 return 0; // Number of instructions patched.
2881 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002882 *p += pc_delta;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002883 return 1; // Number of instructions patched.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002884 } else {
2885 DCHECK(RelocInfo::IsInternalReferenceEncoded(rmode));
2886 if (IsLui(instr)) {
Ben Murdochda12d292016-06-02 14:46:10 +01002887 Instr instr1 = instr_at(pc + 0 * Assembler::kInstrSize);
2888 Instr instr2 = instr_at(pc + 1 * Assembler::kInstrSize);
2889 DCHECK(IsOri(instr2) || IsJicOrJialc(instr2));
2890 int32_t imm;
2891 if (IsJicOrJialc(instr2)) {
2892 imm = CreateTargetAddress(instr1, instr2);
2893 } else {
2894 imm = (instr1 & static_cast<int32_t>(kImm16Mask)) << kLuiShift;
2895 imm |= (instr2 & static_cast<int32_t>(kImm16Mask));
2896 }
2897
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002898 if (imm == kEndOfJumpChain) {
2899 return 0; // Number of instructions patched.
2900 }
2901 imm += pc_delta;
2902 DCHECK((imm & 3) == 0);
Ben Murdochda12d292016-06-02 14:46:10 +01002903 instr1 &= ~kImm16Mask;
2904 instr2 &= ~kImm16Mask;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002905
Ben Murdochda12d292016-06-02 14:46:10 +01002906 if (IsJicOrJialc(instr2)) {
2907 uint32_t lui_offset_u, jic_offset_u;
2908 Assembler::UnpackTargetAddressUnsigned(imm, lui_offset_u, jic_offset_u);
2909 instr_at_put(pc + 0 * Assembler::kInstrSize, instr1 | lui_offset_u);
2910 instr_at_put(pc + 1 * Assembler::kInstrSize, instr2 | jic_offset_u);
2911 } else {
2912 instr_at_put(pc + 0 * Assembler::kInstrSize,
2913 instr1 | ((imm >> kLuiShift) & kImm16Mask));
2914 instr_at_put(pc + 1 * Assembler::kInstrSize,
2915 instr2 | (imm & kImm16Mask));
2916 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002917 return 2; // Number of instructions patched.
2918 } else {
2919 UNREACHABLE();
2920 return 0;
2921 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002922 }
2923}
2924
2925
Andrei Popescu31002712010-02-23 13:46:05 +00002926void Assembler::GrowBuffer() {
2927 if (!own_buffer_) FATAL("external code buffer is too small");
2928
2929 // Compute new buffer size.
Steve Block44f0eee2011-05-26 01:26:41 +01002930 CodeDesc desc; // The new buffer.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002931 if (buffer_size_ < 1 * MB) {
Andrei Popescu31002712010-02-23 13:46:05 +00002932 desc.buffer_size = 2*buffer_size_;
2933 } else {
2934 desc.buffer_size = buffer_size_ + 1*MB;
2935 }
Steve Block44f0eee2011-05-26 01:26:41 +01002936 CHECK_GT(desc.buffer_size, 0); // No overflow.
Andrei Popescu31002712010-02-23 13:46:05 +00002937
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002938 // Set up new buffer.
Andrei Popescu31002712010-02-23 13:46:05 +00002939 desc.buffer = NewArray<byte>(desc.buffer_size);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002940 desc.origin = this;
Andrei Popescu31002712010-02-23 13:46:05 +00002941
2942 desc.instr_size = pc_offset();
2943 desc.reloc_size = (buffer_ + buffer_size_) - reloc_info_writer.pos();
2944
2945 // Copy the data.
2946 int pc_delta = desc.buffer - buffer_;
2947 int rc_delta = (desc.buffer + desc.buffer_size) - (buffer_ + buffer_size_);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002948 MemMove(desc.buffer, buffer_, desc.instr_size);
2949 MemMove(reloc_info_writer.pos() + rc_delta, reloc_info_writer.pos(),
2950 desc.reloc_size);
Andrei Popescu31002712010-02-23 13:46:05 +00002951
2952 // Switch buffers.
2953 DeleteArray(buffer_);
2954 buffer_ = desc.buffer;
2955 buffer_size_ = desc.buffer_size;
2956 pc_ += pc_delta;
2957 reloc_info_writer.Reposition(reloc_info_writer.pos() + rc_delta,
2958 reloc_info_writer.last_pc() + pc_delta);
2959
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002960 // Relocate runtime entries.
2961 for (RelocIterator it(desc); !it.done(); it.next()) {
2962 RelocInfo::Mode rmode = it.rinfo()->rmode();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002963 if (rmode == RelocInfo::INTERNAL_REFERENCE_ENCODED ||
2964 rmode == RelocInfo::INTERNAL_REFERENCE) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002965 byte* p = reinterpret_cast<byte*>(it.rinfo()->pc());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002966 RelocateInternalReference(rmode, p, pc_delta);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002967 }
2968 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002969 DCHECK(!overflow());
Andrei Popescu31002712010-02-23 13:46:05 +00002970}
2971
2972
Steve Block44f0eee2011-05-26 01:26:41 +01002973void Assembler::db(uint8_t data) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002974 CheckForEmitInForbiddenSlot();
2975 EmitHelper(data);
Steve Block44f0eee2011-05-26 01:26:41 +01002976}
2977
2978
2979void Assembler::dd(uint32_t data) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002980 CheckForEmitInForbiddenSlot();
2981 EmitHelper(data);
Steve Block44f0eee2011-05-26 01:26:41 +01002982}
2983
2984
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002985void Assembler::dq(uint64_t data) {
2986 CheckForEmitInForbiddenSlot();
2987 EmitHelper(data);
2988}
2989
2990
2991void Assembler::dd(Label* label) {
2992 uint32_t data;
2993 CheckForEmitInForbiddenSlot();
2994 if (label->is_bound()) {
2995 data = reinterpret_cast<uint32_t>(buffer_ + label->pos());
2996 } else {
2997 data = jump_address(label);
Ben Murdochc5610432016-08-08 18:44:38 +01002998 unbound_labels_count_++;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002999 internal_reference_positions_.insert(label->pos());
3000 }
3001 RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE);
3002 EmitHelper(data);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003003}
3004
3005
Andrei Popescu31002712010-02-23 13:46:05 +00003006void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003007 // We do not try to reuse pool constants.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003008 RelocInfo rinfo(isolate(), pc_, rmode, data, NULL);
3009 if (rmode >= RelocInfo::COMMENT &&
Ben Murdochda12d292016-06-02 14:46:10 +01003010 rmode <= RelocInfo::DEBUG_BREAK_SLOT_AT_TAIL_CALL) {
Andrei Popescu31002712010-02-23 13:46:05 +00003011 // Adjust code for new modes.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003012 DCHECK(RelocInfo::IsDebugBreakSlot(rmode)
Andrei Popescu31002712010-02-23 13:46:05 +00003013 || RelocInfo::IsComment(rmode)
3014 || RelocInfo::IsPosition(rmode));
3015 // These modes do not need an entry in the constant pool.
3016 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003017 if (!RelocInfo::IsNone(rinfo.rmode())) {
Andrei Popescu31002712010-02-23 13:46:05 +00003018 // Don't record external references unless the heap will be serialized.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003019 if (rmode == RelocInfo::EXTERNAL_REFERENCE &&
3020 !serializer_enabled() && !emit_debug_code()) {
3021 return;
Andrei Popescu31002712010-02-23 13:46:05 +00003022 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003023 DCHECK(buffer_space() >= kMaxRelocSize); // Too late to grow buffer here.
Ben Murdoch257744e2011-11-30 15:57:28 +00003024 if (rmode == RelocInfo::CODE_TARGET_WITH_ID) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003025 RelocInfo reloc_info_with_ast_id(isolate(), pc_, rmode,
3026 RecordedAstId().ToInt(), NULL);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003027 ClearRecordedAstId();
Ben Murdoch257744e2011-11-30 15:57:28 +00003028 reloc_info_writer.Write(&reloc_info_with_ast_id);
3029 } else {
3030 reloc_info_writer.Write(&rinfo);
3031 }
Andrei Popescu31002712010-02-23 13:46:05 +00003032 }
3033}
3034
3035
Steve Block44f0eee2011-05-26 01:26:41 +01003036void Assembler::BlockTrampolinePoolFor(int instructions) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003037 CheckTrampolinePoolQuick(instructions);
Steve Block44f0eee2011-05-26 01:26:41 +01003038 BlockTrampolinePoolBefore(pc_offset() + instructions * kInstrSize);
3039}
3040
3041
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003042void Assembler::CheckTrampolinePool() {
Steve Block44f0eee2011-05-26 01:26:41 +01003043 // Some small sequences of instructions must not be broken up by the
3044 // insertion of a trampoline pool; such sequences are protected by setting
3045 // either trampoline_pool_blocked_nesting_ or no_trampoline_pool_before_,
3046 // which are both checked here. Also, recursive calls to CheckTrampolinePool
3047 // are blocked by trampoline_pool_blocked_nesting_.
3048 if ((trampoline_pool_blocked_nesting_ > 0) ||
3049 (pc_offset() < no_trampoline_pool_before_)) {
3050 // Emission is currently blocked; make sure we try again as soon as
3051 // possible.
3052 if (trampoline_pool_blocked_nesting_ > 0) {
3053 next_buffer_check_ = pc_offset() + kInstrSize;
3054 } else {
3055 next_buffer_check_ = no_trampoline_pool_before_;
3056 }
3057 return;
3058 }
3059
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003060 DCHECK(!trampoline_emitted_);
3061 DCHECK(unbound_labels_count_ >= 0);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003062 if (unbound_labels_count_ > 0) {
3063 // First we emit jump (2 instructions), then we emit trampoline pool.
3064 { BlockTrampolinePoolScope block_trampoline_pool(this);
3065 Label after_pool;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003066 if (IsMipsArchVariant(kMips32r6)) {
3067 bc(&after_pool);
3068 } else {
3069 b(&after_pool);
3070 nop();
3071 }
Steve Block44f0eee2011-05-26 01:26:41 +01003072
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003073 int pool_start = pc_offset();
Ben Murdochda12d292016-06-02 14:46:10 +01003074 if (IsMipsArchVariant(kMips32r6)) {
3075 for (int i = 0; i < unbound_labels_count_; i++) {
3076 uint32_t imm32;
3077 imm32 = jump_address(&after_pool);
3078 uint32_t lui_offset, jic_offset;
3079 UnpackTargetAddressUnsigned(imm32, lui_offset, jic_offset);
3080 {
3081 BlockGrowBufferScope block_buf_growth(this);
3082 // Buffer growth (and relocation) must be blocked for internal
3083 // references until associated instructions are emitted and
3084 // available to be patched.
3085 RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE_ENCODED);
3086 lui(at, lui_offset);
3087 jic(at, jic_offset);
3088 }
3089 CheckBuffer();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003090 }
Ben Murdochda12d292016-06-02 14:46:10 +01003091 } else {
3092 for (int i = 0; i < unbound_labels_count_; i++) {
3093 uint32_t imm32;
3094 imm32 = jump_address(&after_pool);
3095 {
3096 BlockGrowBufferScope block_buf_growth(this);
3097 // Buffer growth (and relocation) must be blocked for internal
3098 // references until associated instructions are emitted and
3099 // available to be patched.
3100 RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE_ENCODED);
3101 lui(at, (imm32 & kHiMask) >> kLuiShift);
3102 ori(at, at, (imm32 & kImm16Mask));
3103 }
3104 CheckBuffer();
3105 jr(at);
3106 nop();
3107 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003108 }
3109 bind(&after_pool);
3110 trampoline_ = Trampoline(pool_start, unbound_labels_count_);
3111
3112 trampoline_emitted_ = true;
3113 // As we are only going to emit trampoline once, we need to prevent any
3114 // further emission.
3115 next_buffer_check_ = kMaxInt;
3116 }
3117 } else {
3118 // Number of branches to unbound label at this point is zero, so we can
3119 // move next buffer check to maximum.
3120 next_buffer_check_ = pc_offset() +
3121 kMaxBranchOffset - kTrampolineSlotsSize * 16;
Steve Block44f0eee2011-05-26 01:26:41 +01003122 }
3123 return;
3124}
3125
3126
Andrei Popescu31002712010-02-23 13:46:05 +00003127Address Assembler::target_address_at(Address pc) {
3128 Instr instr1 = instr_at(pc);
3129 Instr instr2 = instr_at(pc + kInstrSize);
Ben Murdoch257744e2011-11-30 15:57:28 +00003130 // Interpret 2 instructions generated by li: lui/ori
Ben Murdochda12d292016-06-02 14:46:10 +01003131 if (IsLui(instr1) && IsOri(instr2)) {
Ben Murdoch257744e2011-11-30 15:57:28 +00003132 // Assemble the 32 bit value.
Ben Murdochda12d292016-06-02 14:46:10 +01003133 return reinterpret_cast<Address>((GetImmediate16(instr1) << kLuiShift) |
3134 GetImmediate16(instr2));
Andrei Popescu31002712010-02-23 13:46:05 +00003135 }
3136
Ben Murdoch257744e2011-11-30 15:57:28 +00003137 // We should never get here, force a bad address if we do.
Andrei Popescu31002712010-02-23 13:46:05 +00003138 UNREACHABLE();
3139 return (Address)0x0;
3140}
3141
3142
Ben Murdochdb1b4382012-04-26 19:03:50 +01003143// MIPS and ia32 use opposite encoding for qNaN and sNaN, such that ia32
3144// qNaN is a MIPS sNaN, and ia32 sNaN is MIPS qNaN. If running from a heap
3145// snapshot generated on ia32, the resulting MIPS sNaN must be quieted.
3146// OS::nan_value() returns a qNaN.
3147void Assembler::QuietNaN(HeapObject* object) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003148 HeapNumber::cast(object)->set_value(std::numeric_limits<double>::quiet_NaN());
Ben Murdochdb1b4382012-04-26 19:03:50 +01003149}
3150
3151
Ben Murdoch589d6972011-11-30 16:04:58 +00003152// On Mips, a target address is stored in a lui/ori instruction pair, each
3153// of which load 16 bits of the 32-bit address to a register.
3154// Patching the address must replace both instr, and flush the i-cache.
Ben Murdochda12d292016-06-02 14:46:10 +01003155// On r6, target address is stored in a lui/jic pair, and both instr have to be
3156// patched.
Ben Murdoch589d6972011-11-30 16:04:58 +00003157//
3158// There is an optimization below, which emits a nop when the address
3159// fits in just 16 bits. This is unlikely to help, and should be benchmarked,
3160// and possibly removed.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003161void Assembler::set_target_address_at(Isolate* isolate, Address pc,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003162 Address target,
3163 ICacheFlushMode icache_flush_mode) {
Andrei Popescu31002712010-02-23 13:46:05 +00003164 Instr instr2 = instr_at(pc + kInstrSize);
Ben Murdoch257744e2011-11-30 15:57:28 +00003165 uint32_t rt_code = GetRtField(instr2);
Andrei Popescu31002712010-02-23 13:46:05 +00003166 uint32_t* p = reinterpret_cast<uint32_t*>(pc);
3167 uint32_t itarget = reinterpret_cast<uint32_t>(target);
3168
Ben Murdoch589d6972011-11-30 16:04:58 +00003169#ifdef DEBUG
3170 // Check we have the result from a li macro-instruction, using instr pair.
3171 Instr instr1 = instr_at(pc);
Ben Murdochda12d292016-06-02 14:46:10 +01003172 CHECK(IsLui(instr1) && (IsOri(instr2) || IsJicOrJialc(instr2)));
Ben Murdoch589d6972011-11-30 16:04:58 +00003173#endif
3174
Ben Murdochda12d292016-06-02 14:46:10 +01003175 if (IsJicOrJialc(instr2)) {
3176 // Must use 2 instructions to insure patchable code => use lui and jic
3177 uint32_t lui_offset, jic_offset;
3178 Assembler::UnpackTargetAddressUnsigned(itarget, lui_offset, jic_offset);
Andrei Popescu31002712010-02-23 13:46:05 +00003179
Ben Murdochda12d292016-06-02 14:46:10 +01003180 *p &= ~kImm16Mask;
3181 *(p + 1) &= ~kImm16Mask;
3182
3183 *p |= lui_offset;
3184 *(p + 1) |= jic_offset;
3185
3186 } else {
3187 // Must use 2 instructions to insure patchable code => just use lui and ori.
3188 // lui rt, upper-16.
3189 // ori rt rt, lower-16.
3190 *p = LUI | rt_code | ((itarget & kHiMask) >> kLuiShift);
3191 *(p + 1) = ORI | rt_code | (rt_code << 5) | (itarget & kImm16Mask);
3192 }
Ben Murdoch589d6972011-11-30 16:04:58 +00003193
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003194 if (icache_flush_mode != SKIP_ICACHE_FLUSH) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003195 Assembler::FlushICache(isolate, pc, 2 * sizeof(int32_t));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003196 }
Andrei Popescu31002712010-02-23 13:46:05 +00003197}
3198
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003199} // namespace internal
3200} // namespace v8
Andrei Popescu31002712010-02-23 13:46:05 +00003201
Leon Clarkef7060e22010-06-03 12:02:55 +01003202#endif // V8_TARGET_ARCH_MIPS