blob: bfa232892a941fc3f57f4b768f650cfb93997ff9 [file] [log] [blame]
Andrei Popescu31002712010-02-23 13:46:05 +00001// Copyright (c) 1994-2006 Sun Microsystems Inc.
2// All Rights Reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions are
6// met:
7//
8// - Redistributions of source code must retain the above copyright notice,
9// this list of conditions and the following disclaimer.
10//
11// - Redistribution in binary form must reproduce the above copyright
12// notice, this list of conditions and the following disclaimer in the
13// documentation and/or other materials provided with the distribution.
14//
15// - Neither the name of Sun Microsystems or the names of contributors may
16// be used to endorse or promote products derived from this software without
17// specific prior written permission.
18//
19// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
20// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
23// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
27// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31// The original source code covered by the above license above has been
32// modified significantly by Google Inc.
Ben Murdoch3ef787d2012-04-12 10:51:47 +010033// Copyright 2012 the V8 project authors. All rights reserved.
Andrei Popescu31002712010-02-23 13:46:05 +000034
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000035#include "src/mips/assembler-mips.h"
Leon Clarkef7060e22010-06-03 12:02:55 +010036
Ben Murdochb8a8cc12014-11-26 15:28:44 +000037#if V8_TARGET_ARCH_MIPS
Leon Clarkef7060e22010-06-03 12:02:55 +010038
Ben Murdochb8a8cc12014-11-26 15:28:44 +000039#include "src/base/bits.h"
40#include "src/base/cpu.h"
41#include "src/mips/assembler-mips-inl.h"
Andrei Popescu31002712010-02-23 13:46:05 +000042
Andrei Popescu31002712010-02-23 13:46:05 +000043namespace v8 {
44namespace internal {
45
Ben Murdoch589d6972011-11-30 16:04:58 +000046// Get the CPU features enabled by the build. For cross compilation the
47// preprocessor symbols CAN_USE_FPU_INSTRUCTIONS
48// can be defined to enable FPU instructions when building the
49// snapshot.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000050static unsigned CpuFeaturesImpliedByCompiler() {
51 unsigned answer = 0;
Ben Murdoch589d6972011-11-30 16:04:58 +000052#ifdef CAN_USE_FPU_INSTRUCTIONS
53 answer |= 1u << FPU;
54#endif // def CAN_USE_FPU_INSTRUCTIONS
55
Ben Murdoch589d6972011-11-30 16:04:58 +000056 // If the compiler is allowed to use FPU then we can use FPU too in our code
57 // generation even when generating snapshots. This won't work for cross
58 // compilation.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000059#if defined(__mips__) && defined(__mips_hard_float) && __mips_hard_float != 0
Ben Murdoch589d6972011-11-30 16:04:58 +000060 answer |= 1u << FPU;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000061#endif
Ben Murdoch589d6972011-11-30 16:04:58 +000062
63 return answer;
64}
65
66
Ben Murdochb8a8cc12014-11-26 15:28:44 +000067void CpuFeatures::ProbeImpl(bool cross_compile) {
68 supported_ |= CpuFeaturesImpliedByCompiler();
69
70 // Only use statically determined features for cross compile (snapshot).
71 if (cross_compile) return;
Ben Murdoch589d6972011-11-30 16:04:58 +000072
Steve Block44f0eee2011-05-26 01:26:41 +010073 // If the compiler is allowed to use fpu then we can use fpu too in our
74 // code generation.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000075#ifndef __mips__
76 // For the simulator build, use FPU.
77 supported_ |= 1u << FPU;
78#if defined(_MIPS_ARCH_MIPS32R6)
79 // FP64 mode is implied on r6.
80 supported_ |= 1u << FP64FPU;
81#endif
82#if defined(FPU_MODE_FP64)
83 supported_ |= 1u << FP64FPU;
84#endif
Steve Block44f0eee2011-05-26 01:26:41 +010085#else
Ben Murdochb8a8cc12014-11-26 15:28:44 +000086 // Probe for additional features at runtime.
87 base::CPU cpu;
88 if (cpu.has_fpu()) supported_ |= 1u << FPU;
89#if defined(FPU_MODE_FPXX)
90 if (cpu.is_fp64_mode()) supported_ |= 1u << FP64FPU;
91#elif defined(FPU_MODE_FP64)
92 supported_ |= 1u << FP64FPU;
93#endif
94#if defined(_MIPS_ARCH_MIPS32RX)
95 if (cpu.architecture() == 6) {
96 supported_ |= 1u << MIPSr6;
97 } else if (cpu.architecture() == 2) {
98 supported_ |= 1u << MIPSr1;
99 supported_ |= 1u << MIPSr2;
100 } else {
101 supported_ |= 1u << MIPSr1;
Steve Block44f0eee2011-05-26 01:26:41 +0100102 }
Steve Block44f0eee2011-05-26 01:26:41 +0100103#endif
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000104#endif
Steve Block44f0eee2011-05-26 01:26:41 +0100105}
Andrei Popescu31002712010-02-23 13:46:05 +0000106
107
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000108void CpuFeatures::PrintTarget() { }
109void CpuFeatures::PrintFeatures() { }
110
111
Andrei Popescu31002712010-02-23 13:46:05 +0000112int ToNumber(Register reg) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000113 DCHECK(reg.is_valid());
Andrei Popescu31002712010-02-23 13:46:05 +0000114 const int kNumbers[] = {
115 0, // zero_reg
116 1, // at
117 2, // v0
118 3, // v1
119 4, // a0
120 5, // a1
121 6, // a2
122 7, // a3
123 8, // t0
124 9, // t1
125 10, // t2
126 11, // t3
127 12, // t4
128 13, // t5
129 14, // t6
130 15, // t7
131 16, // s0
132 17, // s1
133 18, // s2
134 19, // s3
135 20, // s4
136 21, // s5
137 22, // s6
138 23, // s7
139 24, // t8
140 25, // t9
141 26, // k0
142 27, // k1
143 28, // gp
144 29, // sp
Ben Murdochdb1b4382012-04-26 19:03:50 +0100145 30, // fp
Andrei Popescu31002712010-02-23 13:46:05 +0000146 31, // ra
147 };
148 return kNumbers[reg.code()];
149}
150
Steve Block44f0eee2011-05-26 01:26:41 +0100151
Andrei Popescu31002712010-02-23 13:46:05 +0000152Register ToRegister(int num) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000153 DCHECK(num >= 0 && num < kNumRegisters);
Andrei Popescu31002712010-02-23 13:46:05 +0000154 const Register kRegisters[] = {
155 zero_reg,
156 at,
157 v0, v1,
158 a0, a1, a2, a3,
159 t0, t1, t2, t3, t4, t5, t6, t7,
160 s0, s1, s2, s3, s4, s5, s6, s7,
161 t8, t9,
162 k0, k1,
163 gp,
164 sp,
Ben Murdochdb1b4382012-04-26 19:03:50 +0100165 fp,
Andrei Popescu31002712010-02-23 13:46:05 +0000166 ra
167 };
168 return kRegisters[num];
169}
170
171
172// -----------------------------------------------------------------------------
173// Implementation of RelocInfo.
174
Ben Murdoch589d6972011-11-30 16:04:58 +0000175const int RelocInfo::kApplyMask = RelocInfo::kCodeTargetMask |
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000176 1 << RelocInfo::INTERNAL_REFERENCE |
177 1 << RelocInfo::INTERNAL_REFERENCE_ENCODED;
Andrei Popescu31002712010-02-23 13:46:05 +0000178
Steve Block44f0eee2011-05-26 01:26:41 +0100179
180bool RelocInfo::IsCodedSpecially() {
181 // The deserializer needs to know whether a pointer is specially coded. Being
182 // specially coded on MIPS means that it is a lui/ori instruction, and that is
183 // always the case inside code objects.
184 return true;
185}
186
187
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000188bool RelocInfo::IsInConstantPool() {
189 return false;
190}
191
192
Andrei Popescu31002712010-02-23 13:46:05 +0000193// -----------------------------------------------------------------------------
194// Implementation of Operand and MemOperand.
195// See assembler-mips-inl.h for inlined constructors.
196
197Operand::Operand(Handle<Object> handle) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000198 AllowDeferredHandleDereference using_raw_address;
Andrei Popescu31002712010-02-23 13:46:05 +0000199 rm_ = no_reg;
200 // Verify all Objects referred by code are NOT in new space.
201 Object* obj = *handle;
Andrei Popescu31002712010-02-23 13:46:05 +0000202 if (obj->IsHeapObject()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000203 DCHECK(!HeapObject::cast(obj)->GetHeap()->InNewSpace(obj));
Andrei Popescu31002712010-02-23 13:46:05 +0000204 imm32_ = reinterpret_cast<intptr_t>(handle.location());
205 rmode_ = RelocInfo::EMBEDDED_OBJECT;
206 } else {
207 // No relocation needed.
208 imm32_ = reinterpret_cast<intptr_t>(obj);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000209 rmode_ = RelocInfo::NONE32;
Andrei Popescu31002712010-02-23 13:46:05 +0000210 }
211}
212
Steve Block44f0eee2011-05-26 01:26:41 +0100213
214MemOperand::MemOperand(Register rm, int32_t offset) : Operand(rm) {
Andrei Popescu31002712010-02-23 13:46:05 +0000215 offset_ = offset;
216}
217
218
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000219MemOperand::MemOperand(Register rm, int32_t unit, int32_t multiplier,
220 OffsetAddend offset_addend) : Operand(rm) {
221 offset_ = unit * multiplier + offset_addend;
222}
223
224
Andrei Popescu31002712010-02-23 13:46:05 +0000225// -----------------------------------------------------------------------------
Steve Block44f0eee2011-05-26 01:26:41 +0100226// Specific instructions, constants, and masks.
Andrei Popescu31002712010-02-23 13:46:05 +0000227
Steve Block44f0eee2011-05-26 01:26:41 +0100228static const int kNegOffset = 0x00008000;
229// addiu(sp, sp, 4) aka Pop() operation or part of Pop(r)
230// operations as post-increment of sp.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000231const Instr kPopInstruction = ADDIU | (Register::kCode_sp << kRsShift) |
232 (Register::kCode_sp << kRtShift) |
233 (kPointerSize & kImm16Mask); // NOLINT
Steve Block44f0eee2011-05-26 01:26:41 +0100234// addiu(sp, sp, -4) part of Push(r) operation as pre-decrement of sp.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000235const Instr kPushInstruction = ADDIU | (Register::kCode_sp << kRsShift) |
236 (Register::kCode_sp << kRtShift) |
237 (-kPointerSize & kImm16Mask); // NOLINT
Steve Block44f0eee2011-05-26 01:26:41 +0100238// sw(r, MemOperand(sp, 0))
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000239const Instr kPushRegPattern =
240 SW | (Register::kCode_sp << kRsShift) | (0 & kImm16Mask); // NOLINT
Steve Block44f0eee2011-05-26 01:26:41 +0100241// lw(r, MemOperand(sp, 0))
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000242const Instr kPopRegPattern =
243 LW | (Register::kCode_sp << kRsShift) | (0 & kImm16Mask); // NOLINT
Andrei Popescu31002712010-02-23 13:46:05 +0000244
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000245const Instr kLwRegFpOffsetPattern =
246 LW | (Register::kCode_fp << kRsShift) | (0 & kImm16Mask); // NOLINT
Steve Block44f0eee2011-05-26 01:26:41 +0100247
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000248const Instr kSwRegFpOffsetPattern =
249 SW | (Register::kCode_fp << kRsShift) | (0 & kImm16Mask); // NOLINT
Steve Block44f0eee2011-05-26 01:26:41 +0100250
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000251const Instr kLwRegFpNegOffsetPattern = LW | (Register::kCode_fp << kRsShift) |
252 (kNegOffset & kImm16Mask); // NOLINT
Steve Block44f0eee2011-05-26 01:26:41 +0100253
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000254const Instr kSwRegFpNegOffsetPattern = SW | (Register::kCode_fp << kRsShift) |
255 (kNegOffset & kImm16Mask); // NOLINT
Steve Block44f0eee2011-05-26 01:26:41 +0100256// A mask for the Rt register for push, pop, lw, sw instructions.
257const Instr kRtMask = kRtFieldMask;
258const Instr kLwSwInstrTypeMask = 0xffe00000;
259const Instr kLwSwInstrArgumentMask = ~kLwSwInstrTypeMask;
260const Instr kLwSwOffsetMask = kImm16Mask;
261
262
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000263Assembler::Assembler(Isolate* isolate, void* buffer, int buffer_size)
264 : AssemblerBase(isolate, buffer, buffer_size),
265 recorded_ast_id_(TypeFeedbackId::None()),
266 positions_recorder_(this) {
267 reloc_info_writer.Reposition(buffer_ + buffer_size_, pc_);
Steve Block44f0eee2011-05-26 01:26:41 +0100268
269 last_trampoline_pool_end_ = 0;
270 no_trampoline_pool_before_ = 0;
271 trampoline_pool_blocked_nesting_ = 0;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000272 // We leave space (16 * kTrampolineSlotsSize)
273 // for BlockTrampolinePoolScope buffer.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000274 next_buffer_check_ = FLAG_force_long_branches
275 ? kMaxInt : kMaxBranchOffset - kTrampolineSlotsSize * 16;
Ben Murdoch257744e2011-11-30 15:57:28 +0000276 internal_trampoline_exception_ = false;
277 last_bound_pos_ = 0;
278
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000279 trampoline_emitted_ = FLAG_force_long_branches;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000280 unbound_labels_count_ = 0;
281 block_buffer_growth_ = false;
282
283 ClearRecordedAstId();
Andrei Popescu31002712010-02-23 13:46:05 +0000284}
285
286
Andrei Popescu31002712010-02-23 13:46:05 +0000287void Assembler::GetCode(CodeDesc* desc) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100288 EmitForbiddenSlotInstruction();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000289 DCHECK(pc_ <= reloc_info_writer.pos()); // No overlap.
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100290 // Set up code descriptor.
Andrei Popescu31002712010-02-23 13:46:05 +0000291 desc->buffer = buffer_;
292 desc->buffer_size = buffer_size_;
293 desc->instr_size = pc_offset();
294 desc->reloc_size = (buffer_ + buffer_size_) - reloc_info_writer.pos();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000295 desc->origin = this;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000296 desc->constant_pool_size = 0;
Andrei Popescu31002712010-02-23 13:46:05 +0000297}
298
299
Steve Block44f0eee2011-05-26 01:26:41 +0100300void Assembler::Align(int m) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000301 DCHECK(m >= 4 && base::bits::IsPowerOfTwo32(m));
Ben Murdoch097c5b22016-05-18 11:27:45 +0100302 EmitForbiddenSlotInstruction();
Steve Block44f0eee2011-05-26 01:26:41 +0100303 while ((pc_offset() & (m - 1)) != 0) {
304 nop();
305 }
306}
307
308
309void Assembler::CodeTargetAlign() {
310 // No advantage to aligning branch/call targets to more than
311 // single instruction, that I am aware of.
312 Align(4);
313}
314
315
Ben Murdoch257744e2011-11-30 15:57:28 +0000316Register Assembler::GetRtReg(Instr instr) {
Steve Block44f0eee2011-05-26 01:26:41 +0100317 Register rt;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000318 rt.reg_code = (instr & kRtFieldMask) >> kRtShift;
Steve Block44f0eee2011-05-26 01:26:41 +0100319 return rt;
320}
321
322
Ben Murdoch257744e2011-11-30 15:57:28 +0000323Register Assembler::GetRsReg(Instr instr) {
324 Register rs;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000325 rs.reg_code = (instr & kRsFieldMask) >> kRsShift;
Ben Murdoch257744e2011-11-30 15:57:28 +0000326 return rs;
327}
328
329
330Register Assembler::GetRdReg(Instr instr) {
331 Register rd;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000332 rd.reg_code = (instr & kRdFieldMask) >> kRdShift;
Ben Murdoch257744e2011-11-30 15:57:28 +0000333 return rd;
334}
335
336
337uint32_t Assembler::GetRt(Instr instr) {
338 return (instr & kRtFieldMask) >> kRtShift;
339}
340
341
342uint32_t Assembler::GetRtField(Instr instr) {
343 return instr & kRtFieldMask;
344}
345
346
347uint32_t Assembler::GetRs(Instr instr) {
348 return (instr & kRsFieldMask) >> kRsShift;
349}
350
351
352uint32_t Assembler::GetRsField(Instr instr) {
353 return instr & kRsFieldMask;
354}
355
356
357uint32_t Assembler::GetRd(Instr instr) {
358 return (instr & kRdFieldMask) >> kRdShift;
359}
360
361
362uint32_t Assembler::GetRdField(Instr instr) {
363 return instr & kRdFieldMask;
364}
365
366
367uint32_t Assembler::GetSa(Instr instr) {
368 return (instr & kSaFieldMask) >> kSaShift;
369}
370
371
372uint32_t Assembler::GetSaField(Instr instr) {
373 return instr & kSaFieldMask;
374}
375
376
377uint32_t Assembler::GetOpcodeField(Instr instr) {
378 return instr & kOpcodeMask;
379}
380
381
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000382uint32_t Assembler::GetFunction(Instr instr) {
383 return (instr & kFunctionFieldMask) >> kFunctionShift;
384}
385
386
387uint32_t Assembler::GetFunctionField(Instr instr) {
388 return instr & kFunctionFieldMask;
389}
390
391
Ben Murdoch257744e2011-11-30 15:57:28 +0000392uint32_t Assembler::GetImmediate16(Instr instr) {
393 return instr & kImm16Mask;
394}
395
396
397uint32_t Assembler::GetLabelConst(Instr instr) {
398 return instr & ~kImm16Mask;
399}
400
401
Steve Block44f0eee2011-05-26 01:26:41 +0100402bool Assembler::IsPop(Instr instr) {
403 return (instr & ~kRtMask) == kPopRegPattern;
404}
405
406
407bool Assembler::IsPush(Instr instr) {
408 return (instr & ~kRtMask) == kPushRegPattern;
409}
410
411
412bool Assembler::IsSwRegFpOffset(Instr instr) {
413 return ((instr & kLwSwInstrTypeMask) == kSwRegFpOffsetPattern);
414}
415
416
417bool Assembler::IsLwRegFpOffset(Instr instr) {
418 return ((instr & kLwSwInstrTypeMask) == kLwRegFpOffsetPattern);
419}
420
421
422bool Assembler::IsSwRegFpNegOffset(Instr instr) {
423 return ((instr & (kLwSwInstrTypeMask | kNegOffset)) ==
424 kSwRegFpNegOffsetPattern);
425}
426
427
428bool Assembler::IsLwRegFpNegOffset(Instr instr) {
429 return ((instr & (kLwSwInstrTypeMask | kNegOffset)) ==
430 kLwRegFpNegOffsetPattern);
431}
432
433
Andrei Popescu31002712010-02-23 13:46:05 +0000434// Labels refer to positions in the (to be) generated code.
435// There are bound, linked, and unused labels.
436//
437// Bound labels refer to known positions in the already
438// generated code. pos() is the position the label refers to.
439//
440// Linked labels refer to unknown positions in the code
441// to be generated; pos() is the position of the last
442// instruction using the label.
443
Steve Block44f0eee2011-05-26 01:26:41 +0100444// The link chain is terminated by a value in the instruction of -1,
445// which is an otherwise illegal value (branch -1 is inf loop).
446// The instruction 16-bit offset field addresses 32-bit words, but in
447// code is conv to an 18-bit value addressing bytes, hence the -4 value.
Andrei Popescu31002712010-02-23 13:46:05 +0000448
Andrei Popescu31002712010-02-23 13:46:05 +0000449const int kEndOfChain = -4;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000450// Determines the end of the Jump chain (a subset of the label link chain).
451const int kEndOfJumpChain = 0;
Andrei Popescu31002712010-02-23 13:46:05 +0000452
Steve Block44f0eee2011-05-26 01:26:41 +0100453
454bool Assembler::IsBranch(Instr instr) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000455 uint32_t opcode = GetOpcodeField(instr);
456 uint32_t rt_field = GetRtField(instr);
457 uint32_t rs_field = GetRsField(instr);
Andrei Popescu31002712010-02-23 13:46:05 +0000458 // Checks if the instruction is a branch.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000459 bool isBranch =
460 opcode == BEQ || opcode == BNE || opcode == BLEZ || opcode == BGTZ ||
461 opcode == BEQL || opcode == BNEL || opcode == BLEZL || opcode == BGTZL ||
Andrei Popescu31002712010-02-23 13:46:05 +0000462 (opcode == REGIMM && (rt_field == BLTZ || rt_field == BGEZ ||
463 rt_field == BLTZAL || rt_field == BGEZAL)) ||
Steve Block44f0eee2011-05-26 01:26:41 +0100464 (opcode == COP1 && rs_field == BC1) || // Coprocessor branch.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000465 (opcode == COP1 && rs_field == BC1EQZ) ||
466 (opcode == COP1 && rs_field == BC1NEZ);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000467 if (!isBranch && IsMipsArchVariant(kMips32r6)) {
468 // All the 3 variants of POP10 (BOVC, BEQC, BEQZALC) and
469 // POP30 (BNVC, BNEC, BNEZALC) are branch ops.
470 isBranch |= opcode == POP10 || opcode == POP30 || opcode == BC ||
471 opcode == BALC ||
472 (opcode == POP66 && rs_field != 0) || // BEQZC
473 (opcode == POP76 && rs_field != 0); // BNEZC
474 }
475 return isBranch;
476}
477
478
479bool Assembler::IsBc(Instr instr) {
480 uint32_t opcode = GetOpcodeField(instr);
481 // Checks if the instruction is a BC or BALC.
482 return opcode == BC || opcode == BALC;
483}
484
485
486bool Assembler::IsBzc(Instr instr) {
487 uint32_t opcode = GetOpcodeField(instr);
488 // Checks if the instruction is BEQZC or BNEZC.
489 return (opcode == POP66 && GetRsField(instr) != 0) ||
490 (opcode == POP76 && GetRsField(instr) != 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000491}
492
493
494bool Assembler::IsEmittedConstant(Instr instr) {
495 uint32_t label_constant = GetLabelConst(instr);
496 return label_constant == 0; // Emitted label const in reg-exp engine.
Steve Block44f0eee2011-05-26 01:26:41 +0100497}
498
499
Ben Murdoch257744e2011-11-30 15:57:28 +0000500bool Assembler::IsBeq(Instr instr) {
501 return GetOpcodeField(instr) == BEQ;
502}
503
504
505bool Assembler::IsBne(Instr instr) {
506 return GetOpcodeField(instr) == BNE;
507}
508
509
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000510bool Assembler::IsBeqzc(Instr instr) {
511 uint32_t opcode = GetOpcodeField(instr);
512 return opcode == POP66 && GetRsField(instr) != 0;
513}
514
515
516bool Assembler::IsBnezc(Instr instr) {
517 uint32_t opcode = GetOpcodeField(instr);
518 return opcode == POP76 && GetRsField(instr) != 0;
519}
520
521
522bool Assembler::IsBeqc(Instr instr) {
523 uint32_t opcode = GetOpcodeField(instr);
524 uint32_t rs = GetRsField(instr);
525 uint32_t rt = GetRtField(instr);
526 return opcode == POP10 && rs != 0 && rs < rt; // && rt != 0
527}
528
529
530bool Assembler::IsBnec(Instr instr) {
531 uint32_t opcode = GetOpcodeField(instr);
532 uint32_t rs = GetRsField(instr);
533 uint32_t rt = GetRtField(instr);
534 return opcode == POP30 && rs != 0 && rs < rt; // && rt != 0
535}
536
Ben Murdochda12d292016-06-02 14:46:10 +0100537bool Assembler::IsJicOrJialc(Instr instr) {
538 uint32_t opcode = GetOpcodeField(instr);
539 uint32_t rs = GetRsField(instr);
540 return (opcode == POP66 || opcode == POP76) && rs == 0;
541}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000542
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000543bool Assembler::IsJump(Instr instr) {
544 uint32_t opcode = GetOpcodeField(instr);
545 uint32_t rt_field = GetRtField(instr);
546 uint32_t rd_field = GetRdField(instr);
547 uint32_t function_field = GetFunctionField(instr);
548 // Checks if the instruction is a jump.
549 return opcode == J || opcode == JAL ||
550 (opcode == SPECIAL && rt_field == 0 &&
551 ((function_field == JALR) || (rd_field == 0 && (function_field == JR))));
552}
553
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000554bool Assembler::IsJ(Instr instr) {
555 uint32_t opcode = GetOpcodeField(instr);
556 // Checks if the instruction is a jump.
557 return opcode == J;
558}
559
560
Ben Murdoch589d6972011-11-30 16:04:58 +0000561bool Assembler::IsJal(Instr instr) {
562 return GetOpcodeField(instr) == JAL;
563}
564
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000565
Ben Murdoch589d6972011-11-30 16:04:58 +0000566bool Assembler::IsJr(Instr instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000567 if (!IsMipsArchVariant(kMips32r6)) {
568 return GetOpcodeField(instr) == SPECIAL && GetFunctionField(instr) == JR;
569 } else {
570 return GetOpcodeField(instr) == SPECIAL &&
571 GetRdField(instr) == 0 && GetFunctionField(instr) == JALR;
572 }
Ben Murdoch589d6972011-11-30 16:04:58 +0000573}
574
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000575
Ben Murdoch589d6972011-11-30 16:04:58 +0000576bool Assembler::IsJalr(Instr instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000577 return GetOpcodeField(instr) == SPECIAL &&
578 GetRdField(instr) != 0 && GetFunctionField(instr) == JALR;
Ben Murdoch589d6972011-11-30 16:04:58 +0000579}
580
581
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000582bool Assembler::IsLui(Instr instr) {
583 uint32_t opcode = GetOpcodeField(instr);
584 // Checks if the instruction is a load upper immediate.
585 return opcode == LUI;
586}
587
588
589bool Assembler::IsOri(Instr instr) {
590 uint32_t opcode = GetOpcodeField(instr);
591 // Checks if the instruction is a load upper immediate.
592 return opcode == ORI;
593}
594
595
Steve Block44f0eee2011-05-26 01:26:41 +0100596bool Assembler::IsNop(Instr instr, unsigned int type) {
597 // See Assembler::nop(type).
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000598 DCHECK(type < 32);
Ben Murdoch257744e2011-11-30 15:57:28 +0000599 uint32_t opcode = GetOpcodeField(instr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000600 uint32_t function = GetFunctionField(instr);
Ben Murdoch257744e2011-11-30 15:57:28 +0000601 uint32_t rt = GetRt(instr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000602 uint32_t rd = GetRd(instr);
Ben Murdoch257744e2011-11-30 15:57:28 +0000603 uint32_t sa = GetSa(instr);
Steve Block44f0eee2011-05-26 01:26:41 +0100604
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000605 // Traditional mips nop == sll(zero_reg, zero_reg, 0)
606 // When marking non-zero type, use sll(zero_reg, at, type)
607 // to avoid use of mips ssnop and ehb special encodings
608 // of the sll instruction.
Steve Block44f0eee2011-05-26 01:26:41 +0100609
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000610 Register nop_rt_reg = (type == 0) ? zero_reg : at;
611 bool ret = (opcode == SPECIAL && function == SLL &&
612 rd == static_cast<uint32_t>(ToNumber(zero_reg)) &&
613 rt == static_cast<uint32_t>(ToNumber(nop_rt_reg)) &&
Steve Block44f0eee2011-05-26 01:26:41 +0100614 sa == type);
615
616 return ret;
617}
618
619
620int32_t Assembler::GetBranchOffset(Instr instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000621 DCHECK(IsBranch(instr));
622 return (static_cast<int16_t>(instr & kImm16Mask)) << 2;
Steve Block44f0eee2011-05-26 01:26:41 +0100623}
624
625
626bool Assembler::IsLw(Instr instr) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000627 return (static_cast<uint32_t>(instr & kOpcodeMask) == LW);
Steve Block44f0eee2011-05-26 01:26:41 +0100628}
629
630
631int16_t Assembler::GetLwOffset(Instr instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000632 DCHECK(IsLw(instr));
Steve Block44f0eee2011-05-26 01:26:41 +0100633 return ((instr & kImm16Mask));
634}
635
636
637Instr Assembler::SetLwOffset(Instr instr, int16_t offset) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000638 DCHECK(IsLw(instr));
Steve Block44f0eee2011-05-26 01:26:41 +0100639
640 // We actually create a new lw instruction based on the original one.
641 Instr temp_instr = LW | (instr & kRsFieldMask) | (instr & kRtFieldMask)
642 | (offset & kImm16Mask);
643
644 return temp_instr;
645}
646
647
648bool Assembler::IsSw(Instr instr) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000649 return (static_cast<uint32_t>(instr & kOpcodeMask) == SW);
Steve Block44f0eee2011-05-26 01:26:41 +0100650}
651
652
653Instr Assembler::SetSwOffset(Instr instr, int16_t offset) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000654 DCHECK(IsSw(instr));
Steve Block44f0eee2011-05-26 01:26:41 +0100655 return ((instr & ~kImm16Mask) | (offset & kImm16Mask));
656}
657
658
659bool Assembler::IsAddImmediate(Instr instr) {
660 return ((instr & kOpcodeMask) == ADDIU);
661}
662
663
664Instr Assembler::SetAddImmediateOffset(Instr instr, int16_t offset) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000665 DCHECK(IsAddImmediate(instr));
Steve Block44f0eee2011-05-26 01:26:41 +0100666 return ((instr & ~kImm16Mask) | (offset & kImm16Mask));
Andrei Popescu31002712010-02-23 13:46:05 +0000667}
668
669
Ben Murdoch257744e2011-11-30 15:57:28 +0000670bool Assembler::IsAndImmediate(Instr instr) {
671 return GetOpcodeField(instr) == ANDI;
672}
673
674
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000675static Assembler::OffsetSize OffsetSizeInBits(Instr instr) {
676 if (IsMipsArchVariant(kMips32r6)) {
677 if (Assembler::IsBc(instr)) {
678 return Assembler::OffsetSize::kOffset26;
679 } else if (Assembler::IsBzc(instr)) {
680 return Assembler::OffsetSize::kOffset21;
681 }
682 }
683 return Assembler::OffsetSize::kOffset16;
684}
685
686
687static inline int32_t AddBranchOffset(int pos, Instr instr) {
688 int bits = OffsetSizeInBits(instr);
689 const int32_t mask = (1 << bits) - 1;
690 bits = 32 - bits;
691
692 // Do NOT change this to <<2. We rely on arithmetic shifts here, assuming
693 // the compiler uses arithmetic shifts for signed integers.
694 int32_t imm = ((instr & mask) << bits) >> (bits - 2);
695
696 if (imm == kEndOfChain) {
697 // EndOfChain sentinel is returned directly, not relative to pc or pos.
698 return kEndOfChain;
699 } else {
700 return pos + Assembler::kBranchPCOffset + imm;
701 }
702}
703
Ben Murdochda12d292016-06-02 14:46:10 +0100704uint32_t Assembler::CreateTargetAddress(Instr instr_lui, Instr instr_jic) {
705 DCHECK(IsLui(instr_lui) && IsJicOrJialc(instr_jic));
706 int16_t jic_offset = GetImmediate16(instr_jic);
707 int16_t lui_offset = GetImmediate16(instr_lui);
708
709 if (jic_offset < 0) {
710 lui_offset += kImm16Mask;
711 }
712 uint32_t lui_offset_u = (static_cast<uint32_t>(lui_offset)) << kLuiShift;
713 uint32_t jic_offset_u = static_cast<uint32_t>(jic_offset) & kImm16Mask;
714
715 return lui_offset_u | jic_offset_u;
716}
717
718// Use just lui and jic instructions. Insert lower part of the target address in
719// jic offset part. Since jic sign-extends offset and then add it with register,
720// before that addition, difference between upper part of the target address and
721// upper part of the sign-extended offset (0xffff or 0x0000), will be inserted
722// in jic register with lui instruction.
723void Assembler::UnpackTargetAddress(uint32_t address, int16_t& lui_offset,
724 int16_t& jic_offset) {
725 lui_offset = (address & kHiMask) >> kLuiShift;
726 jic_offset = address & kLoMask;
727
728 if (jic_offset < 0) {
729 lui_offset -= kImm16Mask;
730 }
731}
732
733void Assembler::UnpackTargetAddressUnsigned(uint32_t address,
734 uint32_t& lui_offset,
735 uint32_t& jic_offset) {
736 int16_t lui_offset16 = (address & kHiMask) >> kLuiShift;
737 int16_t jic_offset16 = address & kLoMask;
738
739 if (jic_offset16 < 0) {
740 lui_offset16 -= kImm16Mask;
741 }
742 lui_offset = static_cast<uint32_t>(lui_offset16) & kImm16Mask;
743 jic_offset = static_cast<uint32_t>(jic_offset16) & kImm16Mask;
744}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000745
746int Assembler::target_at(int pos, bool is_internal) {
Andrei Popescu31002712010-02-23 13:46:05 +0000747 Instr instr = instr_at(pos);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000748 if (is_internal) {
749 if (instr == 0) {
750 return kEndOfChain;
751 } else {
752 int32_t instr_address = reinterpret_cast<int32_t>(buffer_ + pos);
753 int delta = static_cast<int>(instr_address - instr);
754 DCHECK(pos > delta);
755 return pos - delta;
756 }
757 }
Andrei Popescu31002712010-02-23 13:46:05 +0000758 if ((instr & ~kImm16Mask) == 0) {
759 // Emitted label constant, not part of a branch.
Steve Block44f0eee2011-05-26 01:26:41 +0100760 if (instr == 0) {
761 return kEndOfChain;
762 } else {
763 int32_t imm18 =((instr & static_cast<int32_t>(kImm16Mask)) << 16) >> 14;
764 return (imm18 + pos);
765 }
Andrei Popescu31002712010-02-23 13:46:05 +0000766 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000767 // Check we have a branch or jump instruction.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000768 DCHECK(IsBranch(instr) || IsLui(instr));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000769 if (IsBranch(instr)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000770 return AddBranchOffset(pos, instr);
771 } else {
Ben Murdochda12d292016-06-02 14:46:10 +0100772 Instr instr1 = instr_at(pos + 0 * Assembler::kInstrSize);
773 Instr instr2 = instr_at(pos + 1 * Assembler::kInstrSize);
774 DCHECK(IsOri(instr2) || IsJicOrJialc(instr2));
775 int32_t imm;
776 if (IsJicOrJialc(instr2)) {
777 imm = CreateTargetAddress(instr1, instr2);
778 } else {
779 imm = (instr1 & static_cast<int32_t>(kImm16Mask)) << kLuiShift;
780 imm |= (instr2 & static_cast<int32_t>(kImm16Mask));
781 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000782
783 if (imm == kEndOfJumpChain) {
784 // EndOfChain sentinel is returned directly, not relative to pc or pos.
785 return kEndOfChain;
786 } else {
787 uint32_t instr_address = reinterpret_cast<int32_t>(buffer_ + pos);
788 int32_t delta = instr_address - imm;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000789 DCHECK(pos > delta);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000790 return pos - delta;
791 }
Steve Block44f0eee2011-05-26 01:26:41 +0100792 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000793 return 0;
Andrei Popescu31002712010-02-23 13:46:05 +0000794}
795
796
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000797static inline Instr SetBranchOffset(int32_t pos, int32_t target_pos,
798 Instr instr) {
799 int32_t bits = OffsetSizeInBits(instr);
800 int32_t imm = target_pos - (pos + Assembler::kBranchPCOffset);
801 DCHECK((imm & 3) == 0);
802 imm >>= 2;
803
804 const int32_t mask = (1 << bits) - 1;
805 instr &= ~mask;
806 DCHECK(is_intn(imm, bits));
807
808 return instr | (imm & mask);
809}
810
811
812void Assembler::target_at_put(int32_t pos, int32_t target_pos,
813 bool is_internal) {
Andrei Popescu31002712010-02-23 13:46:05 +0000814 Instr instr = instr_at(pos);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000815
816 if (is_internal) {
817 uint32_t imm = reinterpret_cast<uint32_t>(buffer_) + target_pos;
818 instr_at_put(pos, imm);
819 return;
820 }
Andrei Popescu31002712010-02-23 13:46:05 +0000821 if ((instr & ~kImm16Mask) == 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000822 DCHECK(target_pos == kEndOfChain || target_pos >= 0);
Andrei Popescu31002712010-02-23 13:46:05 +0000823 // Emitted label constant, not part of a branch.
824 // Make label relative to Code* of generated Code object.
825 instr_at_put(pos, target_pos + (Code::kHeaderSize - kHeapObjectTag));
826 return;
827 }
828
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000829 DCHECK(IsBranch(instr) || IsLui(instr));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000830 if (IsBranch(instr)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000831 instr = SetBranchOffset(pos, target_pos, instr);
832 instr_at_put(pos, instr);
833 } else {
Ben Murdochda12d292016-06-02 14:46:10 +0100834 Instr instr1 = instr_at(pos + 0 * Assembler::kInstrSize);
835 Instr instr2 = instr_at(pos + 1 * Assembler::kInstrSize);
836 DCHECK(IsOri(instr2) || IsJicOrJialc(instr2));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000837 uint32_t imm = reinterpret_cast<uint32_t>(buffer_) + target_pos;
838 DCHECK((imm & 3) == 0);
Ben Murdochda12d292016-06-02 14:46:10 +0100839 DCHECK(IsLui(instr1) && (IsJicOrJialc(instr2) || IsOri(instr2)));
840 instr1 &= ~kImm16Mask;
841 instr2 &= ~kImm16Mask;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000842
Ben Murdochda12d292016-06-02 14:46:10 +0100843 if (IsJicOrJialc(instr2)) {
844 uint32_t lui_offset_u, jic_offset_u;
845 UnpackTargetAddressUnsigned(imm, lui_offset_u, jic_offset_u);
846 instr_at_put(pos + 0 * Assembler::kInstrSize, instr1 | lui_offset_u);
847 instr_at_put(pos + 1 * Assembler::kInstrSize, instr2 | jic_offset_u);
848 } else {
849 instr_at_put(pos + 0 * Assembler::kInstrSize,
850 instr1 | ((imm & kHiMask) >> kLuiShift));
851 instr_at_put(pos + 1 * Assembler::kInstrSize,
852 instr2 | (imm & kImm16Mask));
853 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000854 }
Andrei Popescu31002712010-02-23 13:46:05 +0000855}
856
857
858void Assembler::print(Label* L) {
859 if (L->is_unused()) {
860 PrintF("unused label\n");
861 } else if (L->is_bound()) {
862 PrintF("bound label to %d\n", L->pos());
863 } else if (L->is_linked()) {
864 Label l = *L;
865 PrintF("unbound label");
866 while (l.is_linked()) {
867 PrintF("@ %d ", l.pos());
868 Instr instr = instr_at(l.pos());
869 if ((instr & ~kImm16Mask) == 0) {
870 PrintF("value\n");
871 } else {
872 PrintF("%d\n", instr);
873 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000874 next(&l, internal_reference_positions_.find(l.pos()) !=
875 internal_reference_positions_.end());
Andrei Popescu31002712010-02-23 13:46:05 +0000876 }
877 } else {
878 PrintF("label in inconsistent state (pos = %d)\n", L->pos_);
879 }
880}
881
882
883void Assembler::bind_to(Label* L, int pos) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000884 DCHECK(0 <= pos && pos <= pc_offset()); // Must have valid binding position.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000885 int32_t trampoline_pos = kInvalidSlotPos;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000886 bool is_internal = false;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000887 if (L->is_linked() && !trampoline_emitted_) {
888 unbound_labels_count_--;
889 next_buffer_check_ += kTrampolineSlotsSize;
890 }
891
Andrei Popescu31002712010-02-23 13:46:05 +0000892 while (L->is_linked()) {
893 int32_t fixup_pos = L->pos();
Steve Block44f0eee2011-05-26 01:26:41 +0100894 int32_t dist = pos - fixup_pos;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000895 is_internal = internal_reference_positions_.find(fixup_pos) !=
896 internal_reference_positions_.end();
897 next(L, is_internal); // Call next before overwriting link with target at
898 // fixup_pos.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000899 Instr instr = instr_at(fixup_pos);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000900 if (is_internal) {
901 target_at_put(fixup_pos, pos, is_internal);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000902 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000903 if (IsBranch(instr)) {
904 int branch_offset = BranchOffset(instr);
905 if (dist > branch_offset) {
906 if (trampoline_pos == kInvalidSlotPos) {
907 trampoline_pos = get_trampoline_entry(fixup_pos);
908 CHECK(trampoline_pos != kInvalidSlotPos);
909 }
910 CHECK((trampoline_pos - fixup_pos) <= branch_offset);
911 target_at_put(fixup_pos, trampoline_pos, false);
912 fixup_pos = trampoline_pos;
913 dist = pos - fixup_pos;
914 }
915 target_at_put(fixup_pos, pos, false);
916 } else {
917 target_at_put(fixup_pos, pos, false);
918 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000919 }
Andrei Popescu31002712010-02-23 13:46:05 +0000920 }
921 L->bind_to(pos);
922
923 // Keep track of the last bound label so we don't eliminate any instructions
924 // before a bound label.
925 if (pos > last_bound_pos_)
926 last_bound_pos_ = pos;
927}
928
929
Andrei Popescu31002712010-02-23 13:46:05 +0000930void Assembler::bind(Label* L) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000931 DCHECK(!L->is_bound()); // Label can only be bound once.
Andrei Popescu31002712010-02-23 13:46:05 +0000932 bind_to(L, pc_offset());
933}
934
935
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000936void Assembler::next(Label* L, bool is_internal) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000937 DCHECK(L->is_linked());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000938 int link = target_at(L->pos(), is_internal);
Steve Block44f0eee2011-05-26 01:26:41 +0100939 if (link == kEndOfChain) {
Andrei Popescu31002712010-02-23 13:46:05 +0000940 L->Unuse();
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000941 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000942 DCHECK(link >= 0);
Steve Block44f0eee2011-05-26 01:26:41 +0100943 L->link_to(link);
Andrei Popescu31002712010-02-23 13:46:05 +0000944 }
945}
946
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000947
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000948bool Assembler::is_near(Label* L) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000949 DCHECK(L->is_bound());
950 return pc_offset() - L->pos() < kMaxBranchOffset - 4 * kInstrSize;
951}
952
953
954bool Assembler::is_near(Label* L, OffsetSize bits) {
955 if (L == nullptr || !L->is_bound()) return true;
956 return pc_offset() - L->pos() < (1 << (bits + 2 - 1)) - 1 - 5 * kInstrSize;
957}
958
959
960bool Assembler::is_near_branch(Label* L) {
961 DCHECK(L->is_bound());
962 return IsMipsArchVariant(kMips32r6) ? is_near_r6(L) : is_near_pre_r6(L);
963}
964
965
966int Assembler::BranchOffset(Instr instr) {
967 // At pre-R6 and for other R6 branches the offset is 16 bits.
968 int bits = OffsetSize::kOffset16;
969
970 if (IsMipsArchVariant(kMips32r6)) {
971 uint32_t opcode = GetOpcodeField(instr);
972 switch (opcode) {
973 // Checks BC or BALC.
974 case BC:
975 case BALC:
976 bits = OffsetSize::kOffset26;
977 break;
978
979 // Checks BEQZC or BNEZC.
980 case POP66:
981 case POP76:
982 if (GetRsField(instr) != 0) bits = OffsetSize::kOffset21;
983 break;
984 default:
985 break;
986 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000987 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000988
989 return (1 << (bits + 2 - 1)) - 1;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000990}
Andrei Popescu31002712010-02-23 13:46:05 +0000991
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000992
Andrei Popescu31002712010-02-23 13:46:05 +0000993// We have to use a temporary register for things that can be relocated even
994// if they can be encoded in the MIPS's 16 bits of immediate-offset instruction
995// space. There is no guarantee that the relocated location can be similarly
996// encoded.
Steve Block44f0eee2011-05-26 01:26:41 +0100997bool Assembler::MustUseReg(RelocInfo::Mode rmode) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000998 return !RelocInfo::IsNone(rmode);
Andrei Popescu31002712010-02-23 13:46:05 +0000999}
1000
Andrei Popescu31002712010-02-23 13:46:05 +00001001void Assembler::GenInstrRegister(Opcode opcode,
1002 Register rs,
1003 Register rt,
1004 Register rd,
1005 uint16_t sa,
1006 SecondaryField func) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001007 DCHECK(rd.is_valid() && rs.is_valid() && rt.is_valid() && is_uint5(sa));
Andrei Popescu31002712010-02-23 13:46:05 +00001008 Instr instr = opcode | (rs.code() << kRsShift) | (rt.code() << kRtShift)
1009 | (rd.code() << kRdShift) | (sa << kSaShift) | func;
1010 emit(instr);
1011}
1012
1013
1014void Assembler::GenInstrRegister(Opcode opcode,
Steve Block44f0eee2011-05-26 01:26:41 +01001015 Register rs,
1016 Register rt,
1017 uint16_t msb,
1018 uint16_t lsb,
1019 SecondaryField func) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001020 DCHECK(rs.is_valid() && rt.is_valid() && is_uint5(msb) && is_uint5(lsb));
Steve Block44f0eee2011-05-26 01:26:41 +01001021 Instr instr = opcode | (rs.code() << kRsShift) | (rt.code() << kRtShift)
1022 | (msb << kRdShift) | (lsb << kSaShift) | func;
1023 emit(instr);
1024}
1025
1026
1027void Assembler::GenInstrRegister(Opcode opcode,
Andrei Popescu31002712010-02-23 13:46:05 +00001028 SecondaryField fmt,
1029 FPURegister ft,
1030 FPURegister fs,
1031 FPURegister fd,
1032 SecondaryField func) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001033 DCHECK(fd.is_valid() && fs.is_valid() && ft.is_valid());
Steve Block44f0eee2011-05-26 01:26:41 +01001034 Instr instr = opcode | fmt | (ft.code() << kFtShift) | (fs.code() << kFsShift)
1035 | (fd.code() << kFdShift) | func;
Andrei Popescu31002712010-02-23 13:46:05 +00001036 emit(instr);
1037}
1038
1039
1040void Assembler::GenInstrRegister(Opcode opcode,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001041 FPURegister fr,
1042 FPURegister ft,
1043 FPURegister fs,
1044 FPURegister fd,
1045 SecondaryField func) {
1046 DCHECK(fd.is_valid() && fr.is_valid() && fs.is_valid() && ft.is_valid());
1047 Instr instr = opcode | (fr.code() << kFrShift) | (ft.code() << kFtShift)
1048 | (fs.code() << kFsShift) | (fd.code() << kFdShift) | func;
1049 emit(instr);
1050}
1051
1052
1053void Assembler::GenInstrRegister(Opcode opcode,
Andrei Popescu31002712010-02-23 13:46:05 +00001054 SecondaryField fmt,
1055 Register rt,
1056 FPURegister fs,
1057 FPURegister fd,
1058 SecondaryField func) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001059 DCHECK(fd.is_valid() && fs.is_valid() && rt.is_valid());
Andrei Popescu31002712010-02-23 13:46:05 +00001060 Instr instr = opcode | fmt | (rt.code() << kRtShift)
Steve Block44f0eee2011-05-26 01:26:41 +01001061 | (fs.code() << kFsShift) | (fd.code() << kFdShift) | func;
1062 emit(instr);
1063}
1064
1065
1066void Assembler::GenInstrRegister(Opcode opcode,
1067 SecondaryField fmt,
1068 Register rt,
1069 FPUControlRegister fs,
1070 SecondaryField func) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001071 DCHECK(fs.is_valid() && rt.is_valid());
Steve Block44f0eee2011-05-26 01:26:41 +01001072 Instr instr =
1073 opcode | fmt | (rt.code() << kRtShift) | (fs.code() << kFsShift) | func;
Andrei Popescu31002712010-02-23 13:46:05 +00001074 emit(instr);
1075}
1076
1077
1078// Instructions with immediate value.
1079// Registers are in the order of the instruction encoding, from left to right.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001080void Assembler::GenInstrImmediate(Opcode opcode, Register rs, Register rt,
1081 int32_t j,
1082 CompactBranchType is_compact_branch) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001083 DCHECK(rs.is_valid() && rt.is_valid() && (is_int16(j) || is_uint16(j)));
Andrei Popescu31002712010-02-23 13:46:05 +00001084 Instr instr = opcode | (rs.code() << kRsShift) | (rt.code() << kRtShift)
1085 | (j & kImm16Mask);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001086 emit(instr, is_compact_branch);
Andrei Popescu31002712010-02-23 13:46:05 +00001087}
1088
1089
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001090void Assembler::GenInstrImmediate(Opcode opcode, Register rs, SecondaryField SF,
1091 int32_t j,
1092 CompactBranchType is_compact_branch) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001093 DCHECK(rs.is_valid() && (is_int16(j) || is_uint16(j)));
Andrei Popescu31002712010-02-23 13:46:05 +00001094 Instr instr = opcode | (rs.code() << kRsShift) | SF | (j & kImm16Mask);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001095 emit(instr, is_compact_branch);
Andrei Popescu31002712010-02-23 13:46:05 +00001096}
1097
1098
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001099void Assembler::GenInstrImmediate(Opcode opcode, Register rs, FPURegister ft,
1100 int32_t j,
1101 CompactBranchType is_compact_branch) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001102 DCHECK(rs.is_valid() && ft.is_valid() && (is_int16(j) || is_uint16(j)));
Andrei Popescu31002712010-02-23 13:46:05 +00001103 Instr instr = opcode | (rs.code() << kRsShift) | (ft.code() << kFtShift)
1104 | (j & kImm16Mask);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001105 emit(instr, is_compact_branch);
1106}
1107
1108
1109void Assembler::GenInstrImmediate(Opcode opcode, Register rs, int32_t offset21,
1110 CompactBranchType is_compact_branch) {
1111 DCHECK(rs.is_valid() && (is_int21(offset21)));
1112 Instr instr = opcode | (rs.code() << kRsShift) | (offset21 & kImm21Mask);
1113 emit(instr, is_compact_branch);
1114}
1115
1116
1117void Assembler::GenInstrImmediate(Opcode opcode, Register rs,
1118 uint32_t offset21) {
1119 DCHECK(rs.is_valid() && (is_uint21(offset21)));
1120 Instr instr = opcode | (rs.code() << kRsShift) | (offset21 & kImm21Mask);
Andrei Popescu31002712010-02-23 13:46:05 +00001121 emit(instr);
1122}
1123
1124
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001125void Assembler::GenInstrImmediate(Opcode opcode, int32_t offset26,
1126 CompactBranchType is_compact_branch) {
1127 DCHECK(is_int26(offset26));
1128 Instr instr = opcode | (offset26 & kImm26Mask);
1129 emit(instr, is_compact_branch);
1130}
1131
1132
Andrei Popescu31002712010-02-23 13:46:05 +00001133void Assembler::GenInstrJump(Opcode opcode,
Ben Murdoch589d6972011-11-30 16:04:58 +00001134 uint32_t address) {
Steve Block44f0eee2011-05-26 01:26:41 +01001135 BlockTrampolinePoolScope block_trampoline_pool(this);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001136 DCHECK(is_uint26(address));
Andrei Popescu31002712010-02-23 13:46:05 +00001137 Instr instr = opcode | address;
1138 emit(instr);
Steve Block44f0eee2011-05-26 01:26:41 +01001139 BlockTrampolinePoolFor(1); // For associated delay slot.
1140}
1141
1142
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001143// Returns the next free trampoline entry.
1144int32_t Assembler::get_trampoline_entry(int32_t pos) {
Ben Murdoch257744e2011-11-30 15:57:28 +00001145 int32_t trampoline_entry = kInvalidSlotPos;
Steve Block44f0eee2011-05-26 01:26:41 +01001146
Ben Murdoch257744e2011-11-30 15:57:28 +00001147 if (!internal_trampoline_exception_) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001148 if (trampoline_.start() > pos) {
1149 trampoline_entry = trampoline_.take_slot();
Steve Block44f0eee2011-05-26 01:26:41 +01001150 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001151
Ben Murdoch257744e2011-11-30 15:57:28 +00001152 if (kInvalidSlotPos == trampoline_entry) {
1153 internal_trampoline_exception_ = true;
Steve Block44f0eee2011-05-26 01:26:41 +01001154 }
1155 }
1156 return trampoline_entry;
Andrei Popescu31002712010-02-23 13:46:05 +00001157}
1158
1159
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001160uint32_t Assembler::jump_address(Label* L) {
Andrei Popescu31002712010-02-23 13:46:05 +00001161 int32_t target_pos;
Steve Block44f0eee2011-05-26 01:26:41 +01001162
Andrei Popescu31002712010-02-23 13:46:05 +00001163 if (L->is_bound()) {
1164 target_pos = L->pos();
1165 } else {
1166 if (L->is_linked()) {
Steve Block44f0eee2011-05-26 01:26:41 +01001167 target_pos = L->pos(); // L's link.
Steve Block44f0eee2011-05-26 01:26:41 +01001168 L->link_to(pc_offset());
Andrei Popescu31002712010-02-23 13:46:05 +00001169 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01001170 L->link_to(pc_offset());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001171 return kEndOfJumpChain;
1172 }
1173 }
1174
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001175 uint32_t imm = reinterpret_cast<uint32_t>(buffer_) + target_pos;
1176 DCHECK((imm & 3) == 0);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001177
1178 return imm;
1179}
1180
1181
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001182int32_t Assembler::branch_offset_helper(Label* L, OffsetSize bits) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001183 int32_t target_pos;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001184 int32_t pad = IsPrevInstrCompactBranch() ? kInstrSize : 0;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001185
1186 if (L->is_bound()) {
1187 target_pos = L->pos();
1188 } else {
1189 if (L->is_linked()) {
1190 target_pos = L->pos();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001191 L->link_to(pc_offset() + pad);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001192 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001193 L->link_to(pc_offset() + pad);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001194 if (!trampoline_emitted_) {
1195 unbound_labels_count_++;
1196 next_buffer_check_ -= kTrampolineSlotsSize;
1197 }
Steve Block44f0eee2011-05-26 01:26:41 +01001198 return kEndOfChain;
Andrei Popescu31002712010-02-23 13:46:05 +00001199 }
Andrei Popescu31002712010-02-23 13:46:05 +00001200 }
1201
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001202 int32_t offset = target_pos - (pc_offset() + kBranchPCOffset + pad);
1203 DCHECK(is_intn(offset, bits + 2));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001204 DCHECK((offset & 3) == 0);
Steve Block44f0eee2011-05-26 01:26:41 +01001205
Andrei Popescu31002712010-02-23 13:46:05 +00001206 return offset;
1207}
1208
1209
1210void Assembler::label_at_put(Label* L, int at_offset) {
1211 int target_pos;
1212 if (L->is_bound()) {
1213 target_pos = L->pos();
Steve Block44f0eee2011-05-26 01:26:41 +01001214 instr_at_put(at_offset, target_pos + (Code::kHeaderSize - kHeapObjectTag));
Andrei Popescu31002712010-02-23 13:46:05 +00001215 } else {
1216 if (L->is_linked()) {
Steve Block44f0eee2011-05-26 01:26:41 +01001217 target_pos = L->pos(); // L's link.
1218 int32_t imm18 = target_pos - at_offset;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001219 DCHECK((imm18 & 3) == 0);
Steve Block44f0eee2011-05-26 01:26:41 +01001220 int32_t imm16 = imm18 >> 2;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001221 DCHECK(is_int16(imm16));
Steve Block44f0eee2011-05-26 01:26:41 +01001222 instr_at_put(at_offset, (imm16 & kImm16Mask));
Andrei Popescu31002712010-02-23 13:46:05 +00001223 } else {
1224 target_pos = kEndOfChain;
Steve Block44f0eee2011-05-26 01:26:41 +01001225 instr_at_put(at_offset, 0);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001226 if (!trampoline_emitted_) {
1227 unbound_labels_count_++;
1228 next_buffer_check_ -= kTrampolineSlotsSize;
1229 }
Andrei Popescu31002712010-02-23 13:46:05 +00001230 }
1231 L->link_to(at_offset);
Andrei Popescu31002712010-02-23 13:46:05 +00001232 }
1233}
1234
1235
1236//------- Branch and jump instructions --------
1237
1238void Assembler::b(int16_t offset) {
1239 beq(zero_reg, zero_reg, offset);
1240}
1241
1242
1243void Assembler::bal(int16_t offset) {
Steve Block44f0eee2011-05-26 01:26:41 +01001244 positions_recorder()->WriteRecordedPositions();
Andrei Popescu31002712010-02-23 13:46:05 +00001245 bgezal(zero_reg, offset);
1246}
1247
1248
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001249void Assembler::bc(int32_t offset) {
1250 DCHECK(IsMipsArchVariant(kMips32r6));
1251 GenInstrImmediate(BC, offset, CompactBranchType::COMPACT_BRANCH);
1252}
1253
1254
1255void Assembler::balc(int32_t offset) {
1256 DCHECK(IsMipsArchVariant(kMips32r6));
1257 positions_recorder()->WriteRecordedPositions();
1258 GenInstrImmediate(BALC, offset, CompactBranchType::COMPACT_BRANCH);
1259}
1260
1261
Andrei Popescu31002712010-02-23 13:46:05 +00001262void Assembler::beq(Register rs, Register rt, int16_t offset) {
Steve Block44f0eee2011-05-26 01:26:41 +01001263 BlockTrampolinePoolScope block_trampoline_pool(this);
Andrei Popescu31002712010-02-23 13:46:05 +00001264 GenInstrImmediate(BEQ, rs, rt, offset);
Steve Block44f0eee2011-05-26 01:26:41 +01001265 BlockTrampolinePoolFor(1); // For associated delay slot.
Andrei Popescu31002712010-02-23 13:46:05 +00001266}
1267
1268
1269void Assembler::bgez(Register rs, int16_t offset) {
Steve Block44f0eee2011-05-26 01:26:41 +01001270 BlockTrampolinePoolScope block_trampoline_pool(this);
Andrei Popescu31002712010-02-23 13:46:05 +00001271 GenInstrImmediate(REGIMM, rs, BGEZ, offset);
Steve Block44f0eee2011-05-26 01:26:41 +01001272 BlockTrampolinePoolFor(1); // For associated delay slot.
Andrei Popescu31002712010-02-23 13:46:05 +00001273}
1274
1275
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001276void Assembler::bgezc(Register rt, int16_t offset) {
1277 DCHECK(IsMipsArchVariant(kMips32r6));
1278 DCHECK(!(rt.is(zero_reg)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001279 GenInstrImmediate(BLEZL, rt, rt, offset, CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001280}
1281
1282
1283void Assembler::bgeuc(Register rs, Register rt, int16_t offset) {
1284 DCHECK(IsMipsArchVariant(kMips32r6));
1285 DCHECK(!(rs.is(zero_reg)));
1286 DCHECK(!(rt.is(zero_reg)));
1287 DCHECK(rs.code() != rt.code());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001288 GenInstrImmediate(BLEZ, rs, rt, offset, CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001289}
1290
1291
1292void Assembler::bgec(Register rs, Register rt, int16_t offset) {
1293 DCHECK(IsMipsArchVariant(kMips32r6));
1294 DCHECK(!(rs.is(zero_reg)));
1295 DCHECK(!(rt.is(zero_reg)));
1296 DCHECK(rs.code() != rt.code());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001297 GenInstrImmediate(BLEZL, rs, rt, offset, CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001298}
1299
1300
Andrei Popescu31002712010-02-23 13:46:05 +00001301void Assembler::bgezal(Register rs, int16_t offset) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001302 DCHECK(!IsMipsArchVariant(kMips32r6) || rs.is(zero_reg));
Steve Block44f0eee2011-05-26 01:26:41 +01001303 BlockTrampolinePoolScope block_trampoline_pool(this);
1304 positions_recorder()->WriteRecordedPositions();
Andrei Popescu31002712010-02-23 13:46:05 +00001305 GenInstrImmediate(REGIMM, rs, BGEZAL, offset);
Steve Block44f0eee2011-05-26 01:26:41 +01001306 BlockTrampolinePoolFor(1); // For associated delay slot.
Andrei Popescu31002712010-02-23 13:46:05 +00001307}
1308
1309
1310void Assembler::bgtz(Register rs, int16_t offset) {
Steve Block44f0eee2011-05-26 01:26:41 +01001311 BlockTrampolinePoolScope block_trampoline_pool(this);
Andrei Popescu31002712010-02-23 13:46:05 +00001312 GenInstrImmediate(BGTZ, rs, zero_reg, offset);
Steve Block44f0eee2011-05-26 01:26:41 +01001313 BlockTrampolinePoolFor(1); // For associated delay slot.
Andrei Popescu31002712010-02-23 13:46:05 +00001314}
1315
1316
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001317void Assembler::bgtzc(Register rt, int16_t offset) {
1318 DCHECK(IsMipsArchVariant(kMips32r6));
1319 DCHECK(!(rt.is(zero_reg)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001320 GenInstrImmediate(BGTZL, zero_reg, rt, offset,
1321 CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001322}
1323
1324
Andrei Popescu31002712010-02-23 13:46:05 +00001325void Assembler::blez(Register rs, int16_t offset) {
Steve Block44f0eee2011-05-26 01:26:41 +01001326 BlockTrampolinePoolScope block_trampoline_pool(this);
Andrei Popescu31002712010-02-23 13:46:05 +00001327 GenInstrImmediate(BLEZ, rs, zero_reg, offset);
Steve Block44f0eee2011-05-26 01:26:41 +01001328 BlockTrampolinePoolFor(1); // For associated delay slot.
Andrei Popescu31002712010-02-23 13:46:05 +00001329}
1330
1331
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001332void Assembler::blezc(Register rt, int16_t offset) {
1333 DCHECK(IsMipsArchVariant(kMips32r6));
1334 DCHECK(!(rt.is(zero_reg)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001335 GenInstrImmediate(BLEZL, zero_reg, rt, offset,
1336 CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001337}
1338
1339
1340void Assembler::bltzc(Register rt, int16_t offset) {
1341 DCHECK(IsMipsArchVariant(kMips32r6));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001342 DCHECK(!rt.is(zero_reg));
1343 GenInstrImmediate(BGTZL, rt, rt, offset, CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001344}
1345
1346
1347void Assembler::bltuc(Register rs, Register rt, int16_t offset) {
1348 DCHECK(IsMipsArchVariant(kMips32r6));
1349 DCHECK(!(rs.is(zero_reg)));
1350 DCHECK(!(rt.is(zero_reg)));
1351 DCHECK(rs.code() != rt.code());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001352 GenInstrImmediate(BGTZ, rs, rt, offset, CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001353}
1354
1355
1356void Assembler::bltc(Register rs, Register rt, int16_t offset) {
1357 DCHECK(IsMipsArchVariant(kMips32r6));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001358 DCHECK(!rs.is(zero_reg));
1359 DCHECK(!rt.is(zero_reg));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001360 DCHECK(rs.code() != rt.code());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001361 GenInstrImmediate(BGTZL, rs, rt, offset, CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001362}
1363
1364
Andrei Popescu31002712010-02-23 13:46:05 +00001365void Assembler::bltz(Register rs, int16_t offset) {
Steve Block44f0eee2011-05-26 01:26:41 +01001366 BlockTrampolinePoolScope block_trampoline_pool(this);
Andrei Popescu31002712010-02-23 13:46:05 +00001367 GenInstrImmediate(REGIMM, rs, BLTZ, offset);
Steve Block44f0eee2011-05-26 01:26:41 +01001368 BlockTrampolinePoolFor(1); // For associated delay slot.
Andrei Popescu31002712010-02-23 13:46:05 +00001369}
1370
1371
1372void Assembler::bltzal(Register rs, int16_t offset) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001373 DCHECK(!IsMipsArchVariant(kMips32r6) || rs.is(zero_reg));
Steve Block44f0eee2011-05-26 01:26:41 +01001374 BlockTrampolinePoolScope block_trampoline_pool(this);
1375 positions_recorder()->WriteRecordedPositions();
Andrei Popescu31002712010-02-23 13:46:05 +00001376 GenInstrImmediate(REGIMM, rs, BLTZAL, offset);
Steve Block44f0eee2011-05-26 01:26:41 +01001377 BlockTrampolinePoolFor(1); // For associated delay slot.
Andrei Popescu31002712010-02-23 13:46:05 +00001378}
1379
1380
1381void Assembler::bne(Register rs, Register rt, int16_t offset) {
Steve Block44f0eee2011-05-26 01:26:41 +01001382 BlockTrampolinePoolScope block_trampoline_pool(this);
Andrei Popescu31002712010-02-23 13:46:05 +00001383 GenInstrImmediate(BNE, rs, rt, offset);
Steve Block44f0eee2011-05-26 01:26:41 +01001384 BlockTrampolinePoolFor(1); // For associated delay slot.
Andrei Popescu31002712010-02-23 13:46:05 +00001385}
1386
1387
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001388void Assembler::bovc(Register rs, Register rt, int16_t offset) {
1389 DCHECK(IsMipsArchVariant(kMips32r6));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001390 if (rs.code() >= rt.code()) {
1391 GenInstrImmediate(ADDI, rs, rt, offset, CompactBranchType::COMPACT_BRANCH);
1392 } else {
1393 GenInstrImmediate(ADDI, rt, rs, offset, CompactBranchType::COMPACT_BRANCH);
1394 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001395}
1396
1397
1398void Assembler::bnvc(Register rs, Register rt, int16_t offset) {
1399 DCHECK(IsMipsArchVariant(kMips32r6));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001400 if (rs.code() >= rt.code()) {
1401 GenInstrImmediate(DADDI, rs, rt, offset, CompactBranchType::COMPACT_BRANCH);
1402 } else {
1403 GenInstrImmediate(DADDI, rt, rs, offset, CompactBranchType::COMPACT_BRANCH);
1404 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001405}
1406
1407
1408void Assembler::blezalc(Register rt, int16_t offset) {
1409 DCHECK(IsMipsArchVariant(kMips32r6));
1410 DCHECK(!(rt.is(zero_reg)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001411 positions_recorder()->WriteRecordedPositions();
1412 GenInstrImmediate(BLEZ, zero_reg, rt, offset,
1413 CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001414}
1415
1416
1417void Assembler::bgezalc(Register rt, int16_t offset) {
1418 DCHECK(IsMipsArchVariant(kMips32r6));
1419 DCHECK(!(rt.is(zero_reg)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001420 positions_recorder()->WriteRecordedPositions();
1421 GenInstrImmediate(BLEZ, rt, rt, offset, CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001422}
1423
1424
1425void Assembler::bgezall(Register rs, int16_t offset) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001426 DCHECK(!IsMipsArchVariant(kMips32r6));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001427 DCHECK(!(rs.is(zero_reg)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001428 BlockTrampolinePoolScope block_trampoline_pool(this);
1429 positions_recorder()->WriteRecordedPositions();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001430 GenInstrImmediate(REGIMM, rs, BGEZALL, offset);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001431 BlockTrampolinePoolFor(1); // For associated delay slot.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001432}
1433
1434
1435void Assembler::bltzalc(Register rt, int16_t offset) {
1436 DCHECK(IsMipsArchVariant(kMips32r6));
1437 DCHECK(!(rt.is(zero_reg)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001438 positions_recorder()->WriteRecordedPositions();
1439 GenInstrImmediate(BGTZ, rt, rt, offset, CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001440}
1441
1442
1443void Assembler::bgtzalc(Register rt, int16_t offset) {
1444 DCHECK(IsMipsArchVariant(kMips32r6));
1445 DCHECK(!(rt.is(zero_reg)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001446 positions_recorder()->WriteRecordedPositions();
1447 GenInstrImmediate(BGTZ, zero_reg, rt, offset,
1448 CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001449}
1450
1451
1452void Assembler::beqzalc(Register rt, int16_t offset) {
1453 DCHECK(IsMipsArchVariant(kMips32r6));
1454 DCHECK(!(rt.is(zero_reg)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001455 positions_recorder()->WriteRecordedPositions();
1456 GenInstrImmediate(ADDI, zero_reg, rt, offset,
1457 CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001458}
1459
1460
1461void Assembler::bnezalc(Register rt, int16_t offset) {
1462 DCHECK(IsMipsArchVariant(kMips32r6));
1463 DCHECK(!(rt.is(zero_reg)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001464 positions_recorder()->WriteRecordedPositions();
1465 GenInstrImmediate(DADDI, zero_reg, rt, offset,
1466 CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001467}
1468
1469
1470void Assembler::beqc(Register rs, Register rt, int16_t offset) {
1471 DCHECK(IsMipsArchVariant(kMips32r6));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001472 DCHECK(rs.code() != rt.code() && rs.code() != 0 && rt.code() != 0);
1473 if (rs.code() < rt.code()) {
1474 GenInstrImmediate(ADDI, rs, rt, offset, CompactBranchType::COMPACT_BRANCH);
1475 } else {
1476 GenInstrImmediate(ADDI, rt, rs, offset, CompactBranchType::COMPACT_BRANCH);
1477 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001478}
1479
1480
1481void Assembler::beqzc(Register rs, int32_t offset) {
1482 DCHECK(IsMipsArchVariant(kMips32r6));
1483 DCHECK(!(rs.is(zero_reg)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001484 GenInstrImmediate(POP66, rs, offset, CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001485}
1486
1487
1488void Assembler::bnec(Register rs, Register rt, int16_t offset) {
1489 DCHECK(IsMipsArchVariant(kMips32r6));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001490 DCHECK(rs.code() != rt.code() && rs.code() != 0 && rt.code() != 0);
1491 if (rs.code() < rt.code()) {
1492 GenInstrImmediate(DADDI, rs, rt, offset, CompactBranchType::COMPACT_BRANCH);
1493 } else {
1494 GenInstrImmediate(DADDI, rt, rs, offset, CompactBranchType::COMPACT_BRANCH);
1495 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001496}
1497
1498
1499void Assembler::bnezc(Register rs, int32_t offset) {
1500 DCHECK(IsMipsArchVariant(kMips32r6));
1501 DCHECK(!(rs.is(zero_reg)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001502 GenInstrImmediate(POP76, rs, offset, CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001503}
1504
1505
Andrei Popescu31002712010-02-23 13:46:05 +00001506void Assembler::j(int32_t target) {
Ben Murdoch589d6972011-11-30 16:04:58 +00001507#if DEBUG
1508 // Get pc of delay slot.
1509 uint32_t ipc = reinterpret_cast<uint32_t>(pc_ + 1 * kInstrSize);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001510 bool in_range = ((ipc ^ static_cast<uint32_t>(target)) >>
1511 (kImm26Bits + kImmFieldShift)) == 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001512 DCHECK(in_range && ((target & 3) == 0));
Ben Murdoch589d6972011-11-30 16:04:58 +00001513#endif
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001514 BlockTrampolinePoolScope block_trampoline_pool(this);
1515 GenInstrJump(J, (target >> 2) & kImm26Mask);
1516 BlockTrampolinePoolFor(1); // For associated delay slot.
Andrei Popescu31002712010-02-23 13:46:05 +00001517}
1518
1519
1520void Assembler::jr(Register rs) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001521 if (!IsMipsArchVariant(kMips32r6)) {
1522 BlockTrampolinePoolScope block_trampoline_pool(this);
1523 if (rs.is(ra)) {
1524 positions_recorder()->WriteRecordedPositions();
1525 }
1526 GenInstrRegister(SPECIAL, rs, zero_reg, zero_reg, 0, JR);
1527 BlockTrampolinePoolFor(1); // For associated delay slot.
1528 } else {
1529 jalr(rs, zero_reg);
Steve Block44f0eee2011-05-26 01:26:41 +01001530 }
Andrei Popescu31002712010-02-23 13:46:05 +00001531}
1532
1533
1534void Assembler::jal(int32_t target) {
Ben Murdoch589d6972011-11-30 16:04:58 +00001535#ifdef DEBUG
1536 // Get pc of delay slot.
1537 uint32_t ipc = reinterpret_cast<uint32_t>(pc_ + 1 * kInstrSize);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001538 bool in_range = ((ipc ^ static_cast<uint32_t>(target)) >>
1539 (kImm26Bits + kImmFieldShift)) == 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001540 DCHECK(in_range && ((target & 3) == 0));
Ben Murdoch589d6972011-11-30 16:04:58 +00001541#endif
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001542 BlockTrampolinePoolScope block_trampoline_pool(this);
Steve Block44f0eee2011-05-26 01:26:41 +01001543 positions_recorder()->WriteRecordedPositions();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001544 GenInstrJump(JAL, (target >> 2) & kImm26Mask);
1545 BlockTrampolinePoolFor(1); // For associated delay slot.
Andrei Popescu31002712010-02-23 13:46:05 +00001546}
1547
1548
1549void Assembler::jalr(Register rs, Register rd) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001550 DCHECK(rs.code() != rd.code());
Steve Block44f0eee2011-05-26 01:26:41 +01001551 BlockTrampolinePoolScope block_trampoline_pool(this);
1552 positions_recorder()->WriteRecordedPositions();
Andrei Popescu31002712010-02-23 13:46:05 +00001553 GenInstrRegister(SPECIAL, rs, zero_reg, rd, 0, JALR);
Steve Block44f0eee2011-05-26 01:26:41 +01001554 BlockTrampolinePoolFor(1); // For associated delay slot.
Andrei Popescu31002712010-02-23 13:46:05 +00001555}
1556
1557
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001558void Assembler::jic(Register rt, int16_t offset) {
1559 DCHECK(IsMipsArchVariant(kMips32r6));
1560 GenInstrImmediate(POP66, zero_reg, rt, offset);
Ben Murdoch589d6972011-11-30 16:04:58 +00001561}
1562
1563
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001564void Assembler::jialc(Register rt, int16_t offset) {
1565 DCHECK(IsMipsArchVariant(kMips32r6));
1566 positions_recorder()->WriteRecordedPositions();
1567 GenInstrImmediate(POP76, zero_reg, rt, offset);
Ben Murdoch589d6972011-11-30 16:04:58 +00001568}
1569
1570
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001571// -------Data-processing-instructions---------
Andrei Popescu31002712010-02-23 13:46:05 +00001572
1573// Arithmetic.
1574
Andrei Popescu31002712010-02-23 13:46:05 +00001575void Assembler::addu(Register rd, Register rs, Register rt) {
1576 GenInstrRegister(SPECIAL, rs, rt, rd, 0, ADDU);
1577}
1578
1579
Andrei Popescu31002712010-02-23 13:46:05 +00001580void Assembler::addiu(Register rd, Register rs, int32_t j) {
1581 GenInstrImmediate(ADDIU, rs, rd, j);
Andrei Popescu31002712010-02-23 13:46:05 +00001582}
1583
1584
1585void Assembler::subu(Register rd, Register rs, Register rt) {
1586 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SUBU);
1587}
1588
1589
1590void Assembler::mul(Register rd, Register rs, Register rt) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001591 if (!IsMipsArchVariant(kMips32r6)) {
1592 GenInstrRegister(SPECIAL2, rs, rt, rd, 0, MUL);
1593 } else {
1594 GenInstrRegister(SPECIAL, rs, rt, rd, MUL_OP, MUL_MUH);
1595 }
1596}
1597
1598
1599void Assembler::mulu(Register rd, Register rs, Register rt) {
1600 DCHECK(IsMipsArchVariant(kMips32r6));
1601 GenInstrRegister(SPECIAL, rs, rt, rd, MUL_OP, MUL_MUH_U);
1602}
1603
1604
1605void Assembler::muh(Register rd, Register rs, Register rt) {
1606 DCHECK(IsMipsArchVariant(kMips32r6));
1607 GenInstrRegister(SPECIAL, rs, rt, rd, MUH_OP, MUL_MUH);
1608}
1609
1610
1611void Assembler::muhu(Register rd, Register rs, Register rt) {
1612 DCHECK(IsMipsArchVariant(kMips32r6));
1613 GenInstrRegister(SPECIAL, rs, rt, rd, MUH_OP, MUL_MUH_U);
1614}
1615
1616
1617void Assembler::mod(Register rd, Register rs, Register rt) {
1618 DCHECK(IsMipsArchVariant(kMips32r6));
1619 GenInstrRegister(SPECIAL, rs, rt, rd, MOD_OP, DIV_MOD);
1620}
1621
1622
1623void Assembler::modu(Register rd, Register rs, Register rt) {
1624 DCHECK(IsMipsArchVariant(kMips32r6));
1625 GenInstrRegister(SPECIAL, rs, rt, rd, MOD_OP, DIV_MOD_U);
Andrei Popescu31002712010-02-23 13:46:05 +00001626}
1627
1628
1629void Assembler::mult(Register rs, Register rt) {
1630 GenInstrRegister(SPECIAL, rs, rt, zero_reg, 0, MULT);
1631}
1632
1633
1634void Assembler::multu(Register rs, Register rt) {
1635 GenInstrRegister(SPECIAL, rs, rt, zero_reg, 0, MULTU);
1636}
1637
1638
1639void Assembler::div(Register rs, Register rt) {
1640 GenInstrRegister(SPECIAL, rs, rt, zero_reg, 0, DIV);
1641}
1642
1643
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001644void Assembler::div(Register rd, Register rs, Register rt) {
1645 DCHECK(IsMipsArchVariant(kMips32r6));
1646 GenInstrRegister(SPECIAL, rs, rt, rd, DIV_OP, DIV_MOD);
1647}
1648
1649
Andrei Popescu31002712010-02-23 13:46:05 +00001650void Assembler::divu(Register rs, Register rt) {
1651 GenInstrRegister(SPECIAL, rs, rt, zero_reg, 0, DIVU);
1652}
1653
1654
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001655void Assembler::divu(Register rd, Register rs, Register rt) {
1656 DCHECK(IsMipsArchVariant(kMips32r6));
1657 GenInstrRegister(SPECIAL, rs, rt, rd, DIV_OP, DIV_MOD_U);
1658}
1659
1660
Andrei Popescu31002712010-02-23 13:46:05 +00001661// Logical.
1662
1663void Assembler::and_(Register rd, Register rs, Register rt) {
1664 GenInstrRegister(SPECIAL, rs, rt, rd, 0, AND);
1665}
1666
1667
1668void Assembler::andi(Register rt, Register rs, int32_t j) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001669 DCHECK(is_uint16(j));
Andrei Popescu31002712010-02-23 13:46:05 +00001670 GenInstrImmediate(ANDI, rs, rt, j);
1671}
1672
1673
1674void Assembler::or_(Register rd, Register rs, Register rt) {
1675 GenInstrRegister(SPECIAL, rs, rt, rd, 0, OR);
1676}
1677
1678
1679void Assembler::ori(Register rt, Register rs, int32_t j) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001680 DCHECK(is_uint16(j));
Andrei Popescu31002712010-02-23 13:46:05 +00001681 GenInstrImmediate(ORI, rs, rt, j);
1682}
1683
1684
1685void Assembler::xor_(Register rd, Register rs, Register rt) {
1686 GenInstrRegister(SPECIAL, rs, rt, rd, 0, XOR);
1687}
1688
1689
1690void Assembler::xori(Register rt, Register rs, int32_t j) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001691 DCHECK(is_uint16(j));
Andrei Popescu31002712010-02-23 13:46:05 +00001692 GenInstrImmediate(XORI, rs, rt, j);
1693}
1694
1695
1696void Assembler::nor(Register rd, Register rs, Register rt) {
1697 GenInstrRegister(SPECIAL, rs, rt, rd, 0, NOR);
1698}
1699
1700
1701// Shifts.
Steve Block44f0eee2011-05-26 01:26:41 +01001702void Assembler::sll(Register rd,
1703 Register rt,
1704 uint16_t sa,
1705 bool coming_from_nop) {
1706 // Don't allow nop instructions in the form sll zero_reg, zero_reg to be
1707 // generated using the sll instruction. They must be generated using
1708 // nop(int/NopMarkerTypes) or MarkCode(int/NopMarkerTypes) pseudo
1709 // instructions.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001710 DCHECK(coming_from_nop || !(rd.is(zero_reg) && rt.is(zero_reg)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001711 GenInstrRegister(SPECIAL, zero_reg, rt, rd, sa & 0x1F, SLL);
Andrei Popescu31002712010-02-23 13:46:05 +00001712}
1713
1714
1715void Assembler::sllv(Register rd, Register rt, Register rs) {
1716 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SLLV);
1717}
1718
1719
1720void Assembler::srl(Register rd, Register rt, uint16_t sa) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001721 GenInstrRegister(SPECIAL, zero_reg, rt, rd, sa & 0x1F, SRL);
Andrei Popescu31002712010-02-23 13:46:05 +00001722}
1723
1724
1725void Assembler::srlv(Register rd, Register rt, Register rs) {
1726 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SRLV);
1727}
1728
1729
1730void Assembler::sra(Register rd, Register rt, uint16_t sa) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001731 GenInstrRegister(SPECIAL, zero_reg, rt, rd, sa & 0x1F, SRA);
Andrei Popescu31002712010-02-23 13:46:05 +00001732}
1733
1734
1735void Assembler::srav(Register rd, Register rt, Register rs) {
1736 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SRAV);
1737}
1738
1739
Steve Block44f0eee2011-05-26 01:26:41 +01001740void Assembler::rotr(Register rd, Register rt, uint16_t sa) {
1741 // Should be called via MacroAssembler::Ror.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001742 DCHECK(rd.is_valid() && rt.is_valid() && is_uint5(sa));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001743 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
Steve Block44f0eee2011-05-26 01:26:41 +01001744 Instr instr = SPECIAL | (1 << kRsShift) | (rt.code() << kRtShift)
1745 | (rd.code() << kRdShift) | (sa << kSaShift) | SRL;
1746 emit(instr);
1747}
1748
1749
1750void Assembler::rotrv(Register rd, Register rt, Register rs) {
1751 // Should be called via MacroAssembler::Ror.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001752 DCHECK(rd.is_valid() && rt.is_valid() && rs.is_valid());
1753 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
Steve Block44f0eee2011-05-26 01:26:41 +01001754 Instr instr = SPECIAL | (rs.code() << kRsShift) | (rt.code() << kRtShift)
1755 | (rd.code() << kRdShift) | (1 << kSaShift) | SRLV;
1756 emit(instr);
1757}
1758
1759
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001760void Assembler::lsa(Register rd, Register rt, Register rs, uint8_t sa) {
1761 DCHECK(rd.is_valid() && rt.is_valid() && rs.is_valid());
Ben Murdochda12d292016-06-02 14:46:10 +01001762 DCHECK(sa <= 3);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001763 DCHECK(IsMipsArchVariant(kMips32r6));
Ben Murdochda12d292016-06-02 14:46:10 +01001764 Instr instr = SPECIAL | rs.code() << kRsShift | rt.code() << kRtShift |
1765 rd.code() << kRdShift | sa << kSaShift | LSA;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001766 emit(instr);
1767}
1768
1769
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001770// ------------Memory-instructions-------------
Andrei Popescu31002712010-02-23 13:46:05 +00001771
Steve Block44f0eee2011-05-26 01:26:41 +01001772// Helper for base-reg + offset, when offset is larger than int16.
1773void Assembler::LoadRegPlusOffsetToAt(const MemOperand& src) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001774 DCHECK(!src.rm().is(at));
1775 lui(at, (src.offset_ >> kLuiShift) & kImm16Mask);
Steve Block44f0eee2011-05-26 01:26:41 +01001776 ori(at, at, src.offset_ & kImm16Mask); // Load 32-bit offset.
1777 addu(at, at, src.rm()); // Add base register.
1778}
1779
1780
Andrei Popescu31002712010-02-23 13:46:05 +00001781void Assembler::lb(Register rd, const MemOperand& rs) {
Steve Block44f0eee2011-05-26 01:26:41 +01001782 if (is_int16(rs.offset_)) {
1783 GenInstrImmediate(LB, rs.rm(), rd, rs.offset_);
1784 } else { // Offset > 16 bits, use multiple instructions to load.
1785 LoadRegPlusOffsetToAt(rs);
1786 GenInstrImmediate(LB, at, rd, 0); // Equiv to lb(rd, MemOperand(at, 0));
1787 }
Andrei Popescu31002712010-02-23 13:46:05 +00001788}
1789
1790
1791void Assembler::lbu(Register rd, const MemOperand& rs) {
Steve Block44f0eee2011-05-26 01:26:41 +01001792 if (is_int16(rs.offset_)) {
1793 GenInstrImmediate(LBU, rs.rm(), rd, rs.offset_);
1794 } else { // Offset > 16 bits, use multiple instructions to load.
1795 LoadRegPlusOffsetToAt(rs);
1796 GenInstrImmediate(LBU, at, rd, 0); // Equiv to lbu(rd, MemOperand(at, 0));
1797 }
1798}
1799
1800
1801void Assembler::lh(Register rd, const MemOperand& rs) {
1802 if (is_int16(rs.offset_)) {
1803 GenInstrImmediate(LH, rs.rm(), rd, rs.offset_);
1804 } else { // Offset > 16 bits, use multiple instructions to load.
1805 LoadRegPlusOffsetToAt(rs);
1806 GenInstrImmediate(LH, at, rd, 0); // Equiv to lh(rd, MemOperand(at, 0));
1807 }
1808}
1809
1810
1811void Assembler::lhu(Register rd, const MemOperand& rs) {
1812 if (is_int16(rs.offset_)) {
1813 GenInstrImmediate(LHU, rs.rm(), rd, rs.offset_);
1814 } else { // Offset > 16 bits, use multiple instructions to load.
1815 LoadRegPlusOffsetToAt(rs);
1816 GenInstrImmediate(LHU, at, rd, 0); // Equiv to lhu(rd, MemOperand(at, 0));
1817 }
Andrei Popescu31002712010-02-23 13:46:05 +00001818}
1819
1820
1821void Assembler::lw(Register rd, const MemOperand& rs) {
Steve Block44f0eee2011-05-26 01:26:41 +01001822 if (is_int16(rs.offset_)) {
1823 GenInstrImmediate(LW, rs.rm(), rd, rs.offset_);
1824 } else { // Offset > 16 bits, use multiple instructions to load.
1825 LoadRegPlusOffsetToAt(rs);
1826 GenInstrImmediate(LW, at, rd, 0); // Equiv to lw(rd, MemOperand(at, 0));
1827 }
Steve Block44f0eee2011-05-26 01:26:41 +01001828}
1829
1830
1831void Assembler::lwl(Register rd, const MemOperand& rs) {
1832 GenInstrImmediate(LWL, rs.rm(), rd, rs.offset_);
1833}
1834
1835
1836void Assembler::lwr(Register rd, const MemOperand& rs) {
1837 GenInstrImmediate(LWR, rs.rm(), rd, rs.offset_);
Andrei Popescu31002712010-02-23 13:46:05 +00001838}
1839
1840
1841void Assembler::sb(Register rd, const MemOperand& rs) {
Steve Block44f0eee2011-05-26 01:26:41 +01001842 if (is_int16(rs.offset_)) {
1843 GenInstrImmediate(SB, rs.rm(), rd, rs.offset_);
1844 } else { // Offset > 16 bits, use multiple instructions to store.
1845 LoadRegPlusOffsetToAt(rs);
1846 GenInstrImmediate(SB, at, rd, 0); // Equiv to sb(rd, MemOperand(at, 0));
1847 }
1848}
1849
1850
1851void Assembler::sh(Register rd, const MemOperand& rs) {
1852 if (is_int16(rs.offset_)) {
1853 GenInstrImmediate(SH, rs.rm(), rd, rs.offset_);
1854 } else { // Offset > 16 bits, use multiple instructions to store.
1855 LoadRegPlusOffsetToAt(rs);
1856 GenInstrImmediate(SH, at, rd, 0); // Equiv to sh(rd, MemOperand(at, 0));
1857 }
Andrei Popescu31002712010-02-23 13:46:05 +00001858}
1859
1860
1861void Assembler::sw(Register rd, const MemOperand& rs) {
Steve Block44f0eee2011-05-26 01:26:41 +01001862 if (is_int16(rs.offset_)) {
1863 GenInstrImmediate(SW, rs.rm(), rd, rs.offset_);
1864 } else { // Offset > 16 bits, use multiple instructions to store.
1865 LoadRegPlusOffsetToAt(rs);
1866 GenInstrImmediate(SW, at, rd, 0); // Equiv to sw(rd, MemOperand(at, 0));
1867 }
Steve Block44f0eee2011-05-26 01:26:41 +01001868}
1869
1870
1871void Assembler::swl(Register rd, const MemOperand& rs) {
1872 GenInstrImmediate(SWL, rs.rm(), rd, rs.offset_);
1873}
1874
1875
1876void Assembler::swr(Register rd, const MemOperand& rs) {
1877 GenInstrImmediate(SWR, rs.rm(), rd, rs.offset_);
Andrei Popescu31002712010-02-23 13:46:05 +00001878}
1879
1880
1881void Assembler::lui(Register rd, int32_t j) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001882 DCHECK(is_uint16(j));
Andrei Popescu31002712010-02-23 13:46:05 +00001883 GenInstrImmediate(LUI, zero_reg, rd, j);
1884}
1885
1886
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001887void Assembler::aui(Register rt, Register rs, int32_t j) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001888 // This instruction uses same opcode as 'lui'. The difference in encoding is
1889 // 'lui' has zero reg. for rs field.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001890 DCHECK(!(rs.is(zero_reg)));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001891 DCHECK(is_uint16(j));
1892 GenInstrImmediate(LUI, rs, rt, j);
1893}
1894
1895
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001896// ---------PC-Relative instructions-----------
1897
1898void Assembler::addiupc(Register rs, int32_t imm19) {
1899 DCHECK(IsMipsArchVariant(kMips32r6));
1900 DCHECK(rs.is_valid() && is_int19(imm19));
1901 uint32_t imm21 = ADDIUPC << kImm19Bits | (imm19 & kImm19Mask);
1902 GenInstrImmediate(PCREL, rs, imm21);
1903}
1904
1905
1906void Assembler::lwpc(Register rs, int32_t offset19) {
1907 DCHECK(IsMipsArchVariant(kMips32r6));
1908 DCHECK(rs.is_valid() && is_int19(offset19));
1909 uint32_t imm21 = LWPC << kImm19Bits | (offset19 & kImm19Mask);
1910 GenInstrImmediate(PCREL, rs, imm21);
1911}
1912
1913
1914void Assembler::auipc(Register rs, int16_t imm16) {
1915 DCHECK(IsMipsArchVariant(kMips32r6));
1916 DCHECK(rs.is_valid());
1917 uint32_t imm21 = AUIPC << kImm16Bits | (imm16 & kImm16Mask);
1918 GenInstrImmediate(PCREL, rs, imm21);
1919}
1920
1921
1922void Assembler::aluipc(Register rs, int16_t imm16) {
1923 DCHECK(IsMipsArchVariant(kMips32r6));
1924 DCHECK(rs.is_valid());
1925 uint32_t imm21 = ALUIPC << kImm16Bits | (imm16 & kImm16Mask);
1926 GenInstrImmediate(PCREL, rs, imm21);
1927}
1928
1929
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001930// -------------Misc-instructions--------------
Andrei Popescu31002712010-02-23 13:46:05 +00001931
1932// Break / Trap instructions.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001933void Assembler::break_(uint32_t code, bool break_as_stop) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001934 DCHECK((code & ~0xfffff) == 0);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001935 // We need to invalidate breaks that could be stops as well because the
1936 // simulator expects a char pointer after the stop instruction.
1937 // See constants-mips.h for explanation.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001938 DCHECK((break_as_stop &&
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001939 code <= kMaxStopCode &&
1940 code > kMaxWatchpointCode) ||
1941 (!break_as_stop &&
1942 (code > kMaxStopCode ||
1943 code <= kMaxWatchpointCode)));
Andrei Popescu31002712010-02-23 13:46:05 +00001944 Instr break_instr = SPECIAL | BREAK | (code << 6);
1945 emit(break_instr);
1946}
1947
1948
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001949void Assembler::stop(const char* msg, uint32_t code) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001950 DCHECK(code > kMaxWatchpointCode);
1951 DCHECK(code <= kMaxStopCode);
1952#if V8_HOST_ARCH_MIPS
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001953 break_(0x54321);
1954#else // V8_HOST_ARCH_MIPS
1955 BlockTrampolinePoolFor(2);
1956 // The Simulator will handle the stop instruction and get the message address.
1957 // On MIPS stop() is just a special kind of break_().
1958 break_(code, true);
1959 emit(reinterpret_cast<Instr>(msg));
1960#endif
1961}
1962
1963
Andrei Popescu31002712010-02-23 13:46:05 +00001964void Assembler::tge(Register rs, Register rt, uint16_t code) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001965 DCHECK(is_uint10(code));
Andrei Popescu31002712010-02-23 13:46:05 +00001966 Instr instr = SPECIAL | TGE | rs.code() << kRsShift
1967 | rt.code() << kRtShift | code << 6;
1968 emit(instr);
1969}
1970
1971
1972void Assembler::tgeu(Register rs, Register rt, uint16_t code) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001973 DCHECK(is_uint10(code));
Andrei Popescu31002712010-02-23 13:46:05 +00001974 Instr instr = SPECIAL | TGEU | rs.code() << kRsShift
1975 | rt.code() << kRtShift | code << 6;
1976 emit(instr);
1977}
1978
1979
1980void Assembler::tlt(Register rs, Register rt, uint16_t code) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001981 DCHECK(is_uint10(code));
Andrei Popescu31002712010-02-23 13:46:05 +00001982 Instr instr =
1983 SPECIAL | TLT | rs.code() << kRsShift | rt.code() << kRtShift | code << 6;
1984 emit(instr);
1985}
1986
1987
1988void Assembler::tltu(Register rs, Register rt, uint16_t code) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001989 DCHECK(is_uint10(code));
Steve Block44f0eee2011-05-26 01:26:41 +01001990 Instr instr =
1991 SPECIAL | TLTU | rs.code() << kRsShift
Andrei Popescu31002712010-02-23 13:46:05 +00001992 | rt.code() << kRtShift | code << 6;
1993 emit(instr);
1994}
1995
1996
1997void Assembler::teq(Register rs, Register rt, uint16_t code) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001998 DCHECK(is_uint10(code));
Andrei Popescu31002712010-02-23 13:46:05 +00001999 Instr instr =
2000 SPECIAL | TEQ | rs.code() << kRsShift | rt.code() << kRtShift | code << 6;
2001 emit(instr);
2002}
2003
2004
2005void Assembler::tne(Register rs, Register rt, uint16_t code) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002006 DCHECK(is_uint10(code));
Andrei Popescu31002712010-02-23 13:46:05 +00002007 Instr instr =
2008 SPECIAL | TNE | rs.code() << kRsShift | rt.code() << kRtShift | code << 6;
2009 emit(instr);
2010}
2011
2012
2013// Move from HI/LO register.
2014
2015void Assembler::mfhi(Register rd) {
2016 GenInstrRegister(SPECIAL, zero_reg, zero_reg, rd, 0, MFHI);
2017}
2018
2019
2020void Assembler::mflo(Register rd) {
2021 GenInstrRegister(SPECIAL, zero_reg, zero_reg, rd, 0, MFLO);
2022}
2023
2024
2025// Set on less than instructions.
2026void Assembler::slt(Register rd, Register rs, Register rt) {
2027 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SLT);
2028}
2029
2030
2031void Assembler::sltu(Register rd, Register rs, Register rt) {
2032 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SLTU);
2033}
2034
2035
2036void Assembler::slti(Register rt, Register rs, int32_t j) {
2037 GenInstrImmediate(SLTI, rs, rt, j);
2038}
2039
2040
2041void Assembler::sltiu(Register rt, Register rs, int32_t j) {
2042 GenInstrImmediate(SLTIU, rs, rt, j);
2043}
2044
2045
Steve Block44f0eee2011-05-26 01:26:41 +01002046// Conditional move.
2047void Assembler::movz(Register rd, Register rs, Register rt) {
2048 GenInstrRegister(SPECIAL, rs, rt, rd, 0, MOVZ);
2049}
2050
2051
2052void Assembler::movn(Register rd, Register rs, Register rt) {
2053 GenInstrRegister(SPECIAL, rs, rt, rd, 0, MOVN);
2054}
2055
2056
2057void Assembler::movt(Register rd, Register rs, uint16_t cc) {
2058 Register rt;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002059 rt.reg_code = (cc & 0x0007) << 2 | 1;
Steve Block44f0eee2011-05-26 01:26:41 +01002060 GenInstrRegister(SPECIAL, rs, rt, rd, 0, MOVCI);
2061}
2062
2063
2064void Assembler::movf(Register rd, Register rs, uint16_t cc) {
2065 Register rt;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002066 rt.reg_code = (cc & 0x0007) << 2 | 0;
Steve Block44f0eee2011-05-26 01:26:41 +01002067 GenInstrRegister(SPECIAL, rs, rt, rd, 0, MOVCI);
2068}
2069
2070
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002071void Assembler::seleqz(Register rd, Register rs, Register rt) {
2072 DCHECK(IsMipsArchVariant(kMips32r6));
2073 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SELEQZ_S);
2074}
2075
2076
Steve Block44f0eee2011-05-26 01:26:41 +01002077// Bit twiddling.
2078void Assembler::clz(Register rd, Register rs) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002079 if (!IsMipsArchVariant(kMips32r6)) {
2080 // Clz instr requires same GPR number in 'rd' and 'rt' fields.
2081 GenInstrRegister(SPECIAL2, rs, rd, rd, 0, CLZ);
2082 } else {
2083 GenInstrRegister(SPECIAL, rs, zero_reg, rd, 1, CLZ_R6);
2084 }
Steve Block44f0eee2011-05-26 01:26:41 +01002085}
2086
2087
2088void Assembler::ins_(Register rt, Register rs, uint16_t pos, uint16_t size) {
2089 // Should be called via MacroAssembler::Ins.
2090 // Ins instr has 'rt' field as dest, and two uint5: msb, lsb.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002091 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
Steve Block44f0eee2011-05-26 01:26:41 +01002092 GenInstrRegister(SPECIAL3, rs, rt, pos + size - 1, pos, INS);
2093}
2094
2095
2096void Assembler::ext_(Register rt, Register rs, uint16_t pos, uint16_t size) {
2097 // Should be called via MacroAssembler::Ext.
2098 // Ext instr has 'rt' field as dest, and two uint5: msb, lsb.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002099 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
Steve Block44f0eee2011-05-26 01:26:41 +01002100 GenInstrRegister(SPECIAL3, rs, rt, size - 1, pos, EXT);
2101}
2102
2103
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002104void Assembler::bitswap(Register rd, Register rt) {
2105 DCHECK(IsMipsArchVariant(kMips32r6));
2106 GenInstrRegister(SPECIAL3, zero_reg, rt, rd, 0, BSHFL);
2107}
2108
2109
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002110void Assembler::pref(int32_t hint, const MemOperand& rs) {
2111 DCHECK(!IsMipsArchVariant(kLoongson));
2112 DCHECK(is_uint5(hint) && is_uint16(rs.offset_));
2113 Instr instr = PREF | (rs.rm().code() << kRsShift) | (hint << kRtShift)
2114 | (rs.offset_);
2115 emit(instr);
2116}
2117
2118
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002119void Assembler::align(Register rd, Register rs, Register rt, uint8_t bp) {
2120 DCHECK(IsMipsArchVariant(kMips32r6));
2121 DCHECK(is_uint3(bp));
2122 uint16_t sa = (ALIGN << kBp2Bits) | bp;
2123 GenInstrRegister(SPECIAL3, rs, rt, rd, sa, BSHFL);
2124}
2125
2126
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002127// --------Coprocessor-instructions----------------
Andrei Popescu31002712010-02-23 13:46:05 +00002128
2129// Load, store, move.
2130void Assembler::lwc1(FPURegister fd, const MemOperand& src) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002131 if (is_int16(src.offset_)) {
2132 GenInstrImmediate(LWC1, src.rm(), fd, src.offset_);
2133 } else { // Offset > 16 bits, use multiple instructions to load.
2134 LoadRegPlusOffsetToAt(src);
2135 GenInstrImmediate(LWC1, at, fd, 0);
2136 }
Andrei Popescu31002712010-02-23 13:46:05 +00002137}
2138
2139
2140void Assembler::ldc1(FPURegister fd, const MemOperand& src) {
Steve Block44f0eee2011-05-26 01:26:41 +01002141 // Workaround for non-8-byte alignment of HeapNumber, convert 64-bit
2142 // load to two 32-bit loads.
Ben Murdoch097c5b22016-05-18 11:27:45 +01002143 if (IsFp32Mode()) { // fp32 mode.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002144 if (is_int16(src.offset_) && is_int16(src.offset_ + kIntSize)) {
2145 GenInstrImmediate(LWC1, src.rm(), fd,
2146 src.offset_ + Register::kMantissaOffset);
2147 FPURegister nextfpreg;
2148 nextfpreg.setcode(fd.code() + 1);
2149 GenInstrImmediate(LWC1, src.rm(), nextfpreg,
2150 src.offset_ + Register::kExponentOffset);
2151 } else { // Offset > 16 bits, use multiple instructions to load.
2152 LoadRegPlusOffsetToAt(src);
2153 GenInstrImmediate(LWC1, at, fd, Register::kMantissaOffset);
2154 FPURegister nextfpreg;
2155 nextfpreg.setcode(fd.code() + 1);
2156 GenInstrImmediate(LWC1, at, nextfpreg, Register::kExponentOffset);
2157 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01002158 } else {
2159 DCHECK(IsFp64Mode() || IsFpxxMode());
2160 // Currently we support FPXX and FP64 on Mips32r2 and Mips32r6
2161 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
2162 if (is_int16(src.offset_) && is_int16(src.offset_ + kIntSize)) {
2163 GenInstrImmediate(LWC1, src.rm(), fd,
2164 src.offset_ + Register::kMantissaOffset);
2165 GenInstrImmediate(LW, src.rm(), at,
2166 src.offset_ + Register::kExponentOffset);
2167 mthc1(at, fd);
2168 } else { // Offset > 16 bits, use multiple instructions to load.
2169 LoadRegPlusOffsetToAt(src);
2170 GenInstrImmediate(LWC1, at, fd, Register::kMantissaOffset);
2171 GenInstrImmediate(LW, at, at, Register::kExponentOffset);
2172 mthc1(at, fd);
2173 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002174 }
Andrei Popescu31002712010-02-23 13:46:05 +00002175}
2176
2177
2178void Assembler::swc1(FPURegister fd, const MemOperand& src) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002179 if (is_int16(src.offset_)) {
2180 GenInstrImmediate(SWC1, src.rm(), fd, src.offset_);
2181 } else { // Offset > 16 bits, use multiple instructions to load.
2182 LoadRegPlusOffsetToAt(src);
2183 GenInstrImmediate(SWC1, at, fd, 0);
2184 }
Andrei Popescu31002712010-02-23 13:46:05 +00002185}
2186
2187
2188void Assembler::sdc1(FPURegister fd, const MemOperand& src) {
Steve Block44f0eee2011-05-26 01:26:41 +01002189 // Workaround for non-8-byte alignment of HeapNumber, convert 64-bit
2190 // store to two 32-bit stores.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002191 DCHECK(!src.rm().is(at));
2192 DCHECK(!src.rm().is(t8));
Ben Murdoch097c5b22016-05-18 11:27:45 +01002193 if (IsFp32Mode()) { // fp32 mode.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002194 if (is_int16(src.offset_) && is_int16(src.offset_ + kIntSize)) {
2195 GenInstrImmediate(SWC1, src.rm(), fd,
2196 src.offset_ + Register::kMantissaOffset);
2197 FPURegister nextfpreg;
2198 nextfpreg.setcode(fd.code() + 1);
2199 GenInstrImmediate(SWC1, src.rm(), nextfpreg,
2200 src.offset_ + Register::kExponentOffset);
2201 } else { // Offset > 16 bits, use multiple instructions to load.
2202 LoadRegPlusOffsetToAt(src);
2203 GenInstrImmediate(SWC1, at, fd, Register::kMantissaOffset);
2204 FPURegister nextfpreg;
2205 nextfpreg.setcode(fd.code() + 1);
2206 GenInstrImmediate(SWC1, at, nextfpreg, Register::kExponentOffset);
2207 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01002208 } else {
2209 DCHECK(IsFp64Mode() || IsFpxxMode());
2210 // Currently we support FPXX and FP64 on Mips32r2 and Mips32r6
2211 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
2212 if (is_int16(src.offset_) && is_int16(src.offset_ + kIntSize)) {
2213 GenInstrImmediate(SWC1, src.rm(), fd,
2214 src.offset_ + Register::kMantissaOffset);
2215 mfhc1(at, fd);
2216 GenInstrImmediate(SW, src.rm(), at,
2217 src.offset_ + Register::kExponentOffset);
2218 } else { // Offset > 16 bits, use multiple instructions to load.
2219 LoadRegPlusOffsetToAt(src);
2220 GenInstrImmediate(SWC1, at, fd, Register::kMantissaOffset);
2221 mfhc1(t8, fd);
2222 GenInstrImmediate(SW, at, t8, Register::kExponentOffset);
2223 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002224 }
Andrei Popescu31002712010-02-23 13:46:05 +00002225}
2226
2227
Steve Block44f0eee2011-05-26 01:26:41 +01002228void Assembler::mtc1(Register rt, FPURegister fs) {
Andrei Popescu31002712010-02-23 13:46:05 +00002229 GenInstrRegister(COP1, MTC1, rt, fs, f0);
2230}
2231
2232
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002233void Assembler::mthc1(Register rt, FPURegister fs) {
2234 GenInstrRegister(COP1, MTHC1, rt, fs, f0);
2235}
2236
2237
Steve Block44f0eee2011-05-26 01:26:41 +01002238void Assembler::mfc1(Register rt, FPURegister fs) {
Andrei Popescu31002712010-02-23 13:46:05 +00002239 GenInstrRegister(COP1, MFC1, rt, fs, f0);
2240}
2241
2242
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002243void Assembler::mfhc1(Register rt, FPURegister fs) {
2244 GenInstrRegister(COP1, MFHC1, rt, fs, f0);
2245}
2246
2247
Steve Block44f0eee2011-05-26 01:26:41 +01002248void Assembler::ctc1(Register rt, FPUControlRegister fs) {
2249 GenInstrRegister(COP1, CTC1, rt, fs);
2250}
2251
2252
2253void Assembler::cfc1(Register rt, FPUControlRegister fs) {
2254 GenInstrRegister(COP1, CFC1, rt, fs);
2255}
2256
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002257
Ben Murdoch589d6972011-11-30 16:04:58 +00002258void Assembler::DoubleAsTwoUInt32(double d, uint32_t* lo, uint32_t* hi) {
2259 uint64_t i;
2260 memcpy(&i, &d, 8);
2261
2262 *lo = i & 0xffffffff;
2263 *hi = i >> 32;
2264}
Steve Block44f0eee2011-05-26 01:26:41 +01002265
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002266
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002267void Assembler::movn_s(FPURegister fd, FPURegister fs, Register rt) {
2268 DCHECK(!IsMipsArchVariant(kMips32r6));
2269 GenInstrRegister(COP1, S, rt, fs, fd, MOVN_C);
2270}
2271
2272
2273void Assembler::movn_d(FPURegister fd, FPURegister fs, Register rt) {
2274 DCHECK(!IsMipsArchVariant(kMips32r6));
2275 GenInstrRegister(COP1, D, rt, fs, fd, MOVN_C);
2276}
2277
2278
2279void Assembler::sel(SecondaryField fmt, FPURegister fd, FPURegister fs,
2280 FPURegister ft) {
2281 DCHECK(IsMipsArchVariant(kMips32r6));
2282 DCHECK((fmt == D) || (fmt == S));
2283
2284 GenInstrRegister(COP1, fmt, ft, fs, fd, SEL);
2285}
2286
2287
2288void Assembler::sel_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2289 sel(S, fd, fs, ft);
2290}
2291
2292
2293void Assembler::sel_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2294 sel(D, fd, fs, ft);
2295}
2296
2297
2298void Assembler::seleqz(SecondaryField fmt, FPURegister fd, FPURegister fs,
2299 FPURegister ft) {
2300 DCHECK(IsMipsArchVariant(kMips32r6));
2301 DCHECK((fmt == D) || (fmt == S));
2302 GenInstrRegister(COP1, fmt, ft, fs, fd, SELEQZ_C);
2303}
2304
2305
2306void Assembler::selnez(Register rd, Register rs, Register rt) {
2307 DCHECK(IsMipsArchVariant(kMips32r6));
2308 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SELNEZ_S);
2309}
2310
2311
2312void Assembler::selnez(SecondaryField fmt, FPURegister fd, FPURegister fs,
2313 FPURegister ft) {
2314 DCHECK(IsMipsArchVariant(kMips32r6));
2315 DCHECK((fmt == D) || (fmt == S));
2316 GenInstrRegister(COP1, fmt, ft, fs, fd, SELNEZ_C);
2317}
2318
2319
2320void Assembler::seleqz_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2321 seleqz(D, fd, fs, ft);
2322}
2323
2324
2325void Assembler::seleqz_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2326 seleqz(S, fd, fs, ft);
2327}
2328
2329
2330void Assembler::selnez_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2331 selnez(D, fd, fs, ft);
2332}
2333
2334
2335void Assembler::selnez_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2336 selnez(S, fd, fs, ft);
2337}
2338
2339
2340void Assembler::movz_s(FPURegister fd, FPURegister fs, Register rt) {
2341 DCHECK(!IsMipsArchVariant(kMips32r6));
2342 GenInstrRegister(COP1, S, rt, fs, fd, MOVZ_C);
2343}
2344
2345
2346void Assembler::movz_d(FPURegister fd, FPURegister fs, Register rt) {
2347 DCHECK(!IsMipsArchVariant(kMips32r6));
2348 GenInstrRegister(COP1, D, rt, fs, fd, MOVZ_C);
2349}
2350
2351
2352void Assembler::movt_s(FPURegister fd, FPURegister fs, uint16_t cc) {
2353 DCHECK(!IsMipsArchVariant(kMips32r6));
2354 FPURegister ft;
2355 ft.reg_code = (cc & 0x0007) << 2 | 1;
2356 GenInstrRegister(COP1, S, ft, fs, fd, MOVF);
2357}
2358
2359
2360void Assembler::movt_d(FPURegister fd, FPURegister fs, uint16_t cc) {
2361 DCHECK(!IsMipsArchVariant(kMips32r6));
2362 FPURegister ft;
2363 ft.reg_code = (cc & 0x0007) << 2 | 1;
2364 GenInstrRegister(COP1, D, ft, fs, fd, MOVF);
2365}
2366
2367
2368void Assembler::movf_s(FPURegister fd, FPURegister fs, uint16_t cc) {
2369 DCHECK(!IsMipsArchVariant(kMips32r6));
2370 FPURegister ft;
2371 ft.reg_code = (cc & 0x0007) << 2 | 0;
2372 GenInstrRegister(COP1, S, ft, fs, fd, MOVF);
2373}
2374
2375
2376void Assembler::movf_d(FPURegister fd, FPURegister fs, uint16_t cc) {
2377 DCHECK(!IsMipsArchVariant(kMips32r6));
2378 FPURegister ft;
2379 ft.reg_code = (cc & 0x0007) << 2 | 0;
2380 GenInstrRegister(COP1, D, ft, fs, fd, MOVF);
2381}
2382
2383
Steve Block44f0eee2011-05-26 01:26:41 +01002384// Arithmetic.
2385
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002386void Assembler::add_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2387 GenInstrRegister(COP1, S, ft, fs, fd, ADD_S);
2388}
2389
2390
Steve Block44f0eee2011-05-26 01:26:41 +01002391void Assembler::add_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2392 GenInstrRegister(COP1, D, ft, fs, fd, ADD_D);
2393}
2394
2395
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002396void Assembler::sub_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2397 GenInstrRegister(COP1, S, ft, fs, fd, SUB_S);
2398}
2399
2400
Steve Block44f0eee2011-05-26 01:26:41 +01002401void Assembler::sub_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2402 GenInstrRegister(COP1, D, ft, fs, fd, SUB_D);
2403}
2404
2405
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002406void Assembler::mul_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2407 GenInstrRegister(COP1, S, ft, fs, fd, MUL_S);
2408}
2409
2410
Steve Block44f0eee2011-05-26 01:26:41 +01002411void Assembler::mul_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2412 GenInstrRegister(COP1, D, ft, fs, fd, MUL_D);
2413}
2414
2415
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002416void Assembler::madd_d(FPURegister fd, FPURegister fr, FPURegister fs,
2417 FPURegister ft) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002418 DCHECK(IsMipsArchVariant(kMips32r2));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002419 GenInstrRegister(COP1X, fr, ft, fs, fd, MADD_D);
2420}
2421
2422
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002423void Assembler::div_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2424 GenInstrRegister(COP1, S, ft, fs, fd, DIV_S);
2425}
2426
2427
Steve Block44f0eee2011-05-26 01:26:41 +01002428void Assembler::div_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2429 GenInstrRegister(COP1, D, ft, fs, fd, DIV_D);
2430}
2431
2432
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002433void Assembler::abs_s(FPURegister fd, FPURegister fs) {
2434 GenInstrRegister(COP1, S, f0, fs, fd, ABS_S);
2435}
2436
2437
Steve Block44f0eee2011-05-26 01:26:41 +01002438void Assembler::abs_d(FPURegister fd, FPURegister fs) {
2439 GenInstrRegister(COP1, D, f0, fs, fd, ABS_D);
2440}
2441
2442
2443void Assembler::mov_d(FPURegister fd, FPURegister fs) {
2444 GenInstrRegister(COP1, D, f0, fs, fd, MOV_D);
2445}
2446
2447
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002448void Assembler::mov_s(FPURegister fd, FPURegister fs) {
2449 GenInstrRegister(COP1, S, f0, fs, fd, MOV_S);
2450}
2451
2452
2453void Assembler::neg_s(FPURegister fd, FPURegister fs) {
2454 GenInstrRegister(COP1, S, f0, fs, fd, NEG_S);
2455}
2456
2457
Steve Block44f0eee2011-05-26 01:26:41 +01002458void Assembler::neg_d(FPURegister fd, FPURegister fs) {
2459 GenInstrRegister(COP1, D, f0, fs, fd, NEG_D);
2460}
2461
2462
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002463void Assembler::sqrt_s(FPURegister fd, FPURegister fs) {
2464 GenInstrRegister(COP1, S, f0, fs, fd, SQRT_S);
2465}
2466
2467
Steve Block44f0eee2011-05-26 01:26:41 +01002468void Assembler::sqrt_d(FPURegister fd, FPURegister fs) {
2469 GenInstrRegister(COP1, D, f0, fs, fd, SQRT_D);
Andrei Popescu31002712010-02-23 13:46:05 +00002470}
2471
2472
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002473void Assembler::rsqrt_s(FPURegister fd, FPURegister fs) {
2474 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
2475 GenInstrRegister(COP1, S, f0, fs, fd, RSQRT_S);
2476}
2477
2478
2479void Assembler::rsqrt_d(FPURegister fd, FPURegister fs) {
2480 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
2481 GenInstrRegister(COP1, D, f0, fs, fd, RSQRT_D);
2482}
2483
2484
2485void Assembler::recip_d(FPURegister fd, FPURegister fs) {
2486 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
2487 GenInstrRegister(COP1, D, f0, fs, fd, RECIP_D);
2488}
2489
2490
2491void Assembler::recip_s(FPURegister fd, FPURegister fs) {
2492 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
2493 GenInstrRegister(COP1, S, f0, fs, fd, RECIP_S);
2494}
2495
2496
Andrei Popescu31002712010-02-23 13:46:05 +00002497// Conversions.
2498
2499void Assembler::cvt_w_s(FPURegister fd, FPURegister fs) {
2500 GenInstrRegister(COP1, S, f0, fs, fd, CVT_W_S);
2501}
2502
2503
2504void Assembler::cvt_w_d(FPURegister fd, FPURegister fs) {
2505 GenInstrRegister(COP1, D, f0, fs, fd, CVT_W_D);
2506}
2507
2508
Steve Block44f0eee2011-05-26 01:26:41 +01002509void Assembler::trunc_w_s(FPURegister fd, FPURegister fs) {
2510 GenInstrRegister(COP1, S, f0, fs, fd, TRUNC_W_S);
2511}
2512
2513
2514void Assembler::trunc_w_d(FPURegister fd, FPURegister fs) {
2515 GenInstrRegister(COP1, D, f0, fs, fd, TRUNC_W_D);
2516}
2517
2518
2519void Assembler::round_w_s(FPURegister fd, FPURegister fs) {
2520 GenInstrRegister(COP1, S, f0, fs, fd, ROUND_W_S);
2521}
2522
2523
2524void Assembler::round_w_d(FPURegister fd, FPURegister fs) {
2525 GenInstrRegister(COP1, D, f0, fs, fd, ROUND_W_D);
2526}
2527
2528
2529void Assembler::floor_w_s(FPURegister fd, FPURegister fs) {
2530 GenInstrRegister(COP1, S, f0, fs, fd, FLOOR_W_S);
2531}
2532
2533
2534void Assembler::floor_w_d(FPURegister fd, FPURegister fs) {
2535 GenInstrRegister(COP1, D, f0, fs, fd, FLOOR_W_D);
2536}
2537
2538
2539void Assembler::ceil_w_s(FPURegister fd, FPURegister fs) {
2540 GenInstrRegister(COP1, S, f0, fs, fd, CEIL_W_S);
2541}
2542
2543
2544void Assembler::ceil_w_d(FPURegister fd, FPURegister fs) {
2545 GenInstrRegister(COP1, D, f0, fs, fd, CEIL_W_D);
2546}
2547
2548
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002549void Assembler::rint_s(FPURegister fd, FPURegister fs) { rint(S, fd, fs); }
2550
2551
2552void Assembler::rint(SecondaryField fmt, FPURegister fd, FPURegister fs) {
2553 DCHECK(IsMipsArchVariant(kMips32r6));
2554 DCHECK((fmt == D) || (fmt == S));
2555 GenInstrRegister(COP1, fmt, f0, fs, fd, RINT);
2556}
2557
2558
2559void Assembler::rint_d(FPURegister fd, FPURegister fs) { rint(D, fd, fs); }
2560
2561
Andrei Popescu31002712010-02-23 13:46:05 +00002562void Assembler::cvt_l_s(FPURegister fd, FPURegister fs) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002563 DCHECK((IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) &&
2564 IsFp64Mode());
Andrei Popescu31002712010-02-23 13:46:05 +00002565 GenInstrRegister(COP1, S, f0, fs, fd, CVT_L_S);
2566}
2567
2568
2569void Assembler::cvt_l_d(FPURegister fd, FPURegister fs) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002570 DCHECK((IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) &&
2571 IsFp64Mode());
Andrei Popescu31002712010-02-23 13:46:05 +00002572 GenInstrRegister(COP1, D, f0, fs, fd, CVT_L_D);
2573}
2574
2575
Steve Block44f0eee2011-05-26 01:26:41 +01002576void Assembler::trunc_l_s(FPURegister fd, FPURegister fs) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002577 DCHECK((IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) &&
2578 IsFp64Mode());
Steve Block44f0eee2011-05-26 01:26:41 +01002579 GenInstrRegister(COP1, S, f0, fs, fd, TRUNC_L_S);
2580}
2581
2582
2583void Assembler::trunc_l_d(FPURegister fd, FPURegister fs) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002584 DCHECK((IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) &&
2585 IsFp64Mode());
Steve Block44f0eee2011-05-26 01:26:41 +01002586 GenInstrRegister(COP1, D, f0, fs, fd, TRUNC_L_D);
2587}
2588
2589
2590void Assembler::round_l_s(FPURegister fd, FPURegister fs) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002591 DCHECK((IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) &&
2592 IsFp64Mode());
Steve Block44f0eee2011-05-26 01:26:41 +01002593 GenInstrRegister(COP1, S, f0, fs, fd, ROUND_L_S);
2594}
2595
2596
2597void Assembler::round_l_d(FPURegister fd, FPURegister fs) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002598 DCHECK((IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) &&
2599 IsFp64Mode());
Steve Block44f0eee2011-05-26 01:26:41 +01002600 GenInstrRegister(COP1, D, f0, fs, fd, ROUND_L_D);
2601}
2602
2603
2604void Assembler::floor_l_s(FPURegister fd, FPURegister fs) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002605 DCHECK((IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) &&
2606 IsFp64Mode());
Steve Block44f0eee2011-05-26 01:26:41 +01002607 GenInstrRegister(COP1, S, f0, fs, fd, FLOOR_L_S);
2608}
2609
2610
2611void Assembler::floor_l_d(FPURegister fd, FPURegister fs) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002612 DCHECK((IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) &&
2613 IsFp64Mode());
Steve Block44f0eee2011-05-26 01:26:41 +01002614 GenInstrRegister(COP1, D, f0, fs, fd, FLOOR_L_D);
2615}
2616
2617
2618void Assembler::ceil_l_s(FPURegister fd, FPURegister fs) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002619 DCHECK((IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) &&
2620 IsFp64Mode());
Steve Block44f0eee2011-05-26 01:26:41 +01002621 GenInstrRegister(COP1, S, f0, fs, fd, CEIL_L_S);
2622}
2623
2624
2625void Assembler::ceil_l_d(FPURegister fd, FPURegister fs) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002626 DCHECK((IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) &&
2627 IsFp64Mode());
Steve Block44f0eee2011-05-26 01:26:41 +01002628 GenInstrRegister(COP1, D, f0, fs, fd, CEIL_L_D);
2629}
2630
2631
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002632void Assembler::class_s(FPURegister fd, FPURegister fs) {
2633 DCHECK(IsMipsArchVariant(kMips32r6));
2634 GenInstrRegister(COP1, S, f0, fs, fd, CLASS_S);
2635}
2636
2637
2638void Assembler::class_d(FPURegister fd, FPURegister fs) {
2639 DCHECK(IsMipsArchVariant(kMips32r6));
2640 GenInstrRegister(COP1, D, f0, fs, fd, CLASS_D);
2641}
2642
2643
2644void Assembler::min(SecondaryField fmt, FPURegister fd, FPURegister fs,
2645 FPURegister ft) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002646 DCHECK(IsMipsArchVariant(kMips32r6));
2647 DCHECK((fmt == D) || (fmt == S));
2648 GenInstrRegister(COP1, fmt, ft, fs, fd, MIN);
2649}
2650
2651
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002652void Assembler::mina(SecondaryField fmt, FPURegister fd, FPURegister fs,
2653 FPURegister ft) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002654 DCHECK(IsMipsArchVariant(kMips32r6));
2655 DCHECK((fmt == D) || (fmt == S));
2656 GenInstrRegister(COP1, fmt, ft, fs, fd, MINA);
2657}
2658
2659
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002660void Assembler::max(SecondaryField fmt, FPURegister fd, FPURegister fs,
2661 FPURegister ft) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002662 DCHECK(IsMipsArchVariant(kMips32r6));
2663 DCHECK((fmt == D) || (fmt == S));
2664 GenInstrRegister(COP1, fmt, ft, fs, fd, MAX);
2665}
2666
2667
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002668void Assembler::maxa(SecondaryField fmt, FPURegister fd, FPURegister fs,
2669 FPURegister ft) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002670 DCHECK(IsMipsArchVariant(kMips32r6));
2671 DCHECK((fmt == D) || (fmt == S));
2672 GenInstrRegister(COP1, fmt, ft, fs, fd, MAXA);
2673}
2674
2675
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002676void Assembler::min_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2677 min(S, fd, fs, ft);
2678}
2679
2680
2681void Assembler::min_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2682 min(D, fd, fs, ft);
2683}
2684
2685
2686void Assembler::max_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2687 max(S, fd, fs, ft);
2688}
2689
2690
2691void Assembler::max_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2692 max(D, fd, fs, ft);
2693}
2694
2695
2696void Assembler::mina_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2697 mina(S, fd, fs, ft);
2698}
2699
2700
2701void Assembler::mina_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2702 mina(D, fd, fs, ft);
2703}
2704
2705
2706void Assembler::maxa_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2707 maxa(S, fd, fs, ft);
2708}
2709
2710
2711void Assembler::maxa_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2712 maxa(D, fd, fs, ft);
2713}
2714
2715
Andrei Popescu31002712010-02-23 13:46:05 +00002716void Assembler::cvt_s_w(FPURegister fd, FPURegister fs) {
2717 GenInstrRegister(COP1, W, f0, fs, fd, CVT_S_W);
2718}
2719
2720
2721void Assembler::cvt_s_l(FPURegister fd, FPURegister fs) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002722 DCHECK((IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) &&
2723 IsFp64Mode());
Andrei Popescu31002712010-02-23 13:46:05 +00002724 GenInstrRegister(COP1, L, f0, fs, fd, CVT_S_L);
2725}
2726
2727
2728void Assembler::cvt_s_d(FPURegister fd, FPURegister fs) {
2729 GenInstrRegister(COP1, D, f0, fs, fd, CVT_S_D);
2730}
2731
2732
2733void Assembler::cvt_d_w(FPURegister fd, FPURegister fs) {
2734 GenInstrRegister(COP1, W, f0, fs, fd, CVT_D_W);
2735}
2736
2737
2738void Assembler::cvt_d_l(FPURegister fd, FPURegister fs) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002739 DCHECK((IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) &&
2740 IsFp64Mode());
Andrei Popescu31002712010-02-23 13:46:05 +00002741 GenInstrRegister(COP1, L, f0, fs, fd, CVT_D_L);
2742}
2743
2744
2745void Assembler::cvt_d_s(FPURegister fd, FPURegister fs) {
2746 GenInstrRegister(COP1, S, f0, fs, fd, CVT_D_S);
2747}
2748
2749
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002750// Conditions for >= MIPSr6.
2751void Assembler::cmp(FPUCondition cond, SecondaryField fmt,
2752 FPURegister fd, FPURegister fs, FPURegister ft) {
2753 DCHECK(IsMipsArchVariant(kMips32r6));
2754 DCHECK((fmt & ~(31 << kRsShift)) == 0);
2755 Instr instr = COP1 | fmt | ft.code() << kFtShift |
2756 fs.code() << kFsShift | fd.code() << kFdShift | (0 << 5) | cond;
2757 emit(instr);
2758}
2759
2760
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002761void Assembler::cmp_s(FPUCondition cond, FPURegister fd, FPURegister fs,
2762 FPURegister ft) {
2763 cmp(cond, W, fd, fs, ft);
2764}
2765
2766void Assembler::cmp_d(FPUCondition cond, FPURegister fd, FPURegister fs,
2767 FPURegister ft) {
2768 cmp(cond, L, fd, fs, ft);
2769}
2770
2771
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002772void Assembler::bc1eqz(int16_t offset, FPURegister ft) {
2773 DCHECK(IsMipsArchVariant(kMips32r6));
2774 Instr instr = COP1 | BC1EQZ | ft.code() << kFtShift | (offset & kImm16Mask);
2775 emit(instr);
2776}
2777
2778
2779void Assembler::bc1nez(int16_t offset, FPURegister ft) {
2780 DCHECK(IsMipsArchVariant(kMips32r6));
2781 Instr instr = COP1 | BC1NEZ | ft.code() << kFtShift | (offset & kImm16Mask);
2782 emit(instr);
2783}
2784
2785
2786// Conditions for < MIPSr6.
Andrei Popescu31002712010-02-23 13:46:05 +00002787void Assembler::c(FPUCondition cond, SecondaryField fmt,
Steve Block44f0eee2011-05-26 01:26:41 +01002788 FPURegister fs, FPURegister ft, uint16_t cc) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002789 DCHECK(is_uint3(cc));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002790 DCHECK(fmt == S || fmt == D);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002791 DCHECK((fmt & ~(31 << kRsShift)) == 0);
Andrei Popescu31002712010-02-23 13:46:05 +00002792 Instr instr = COP1 | fmt | ft.code() << 16 | fs.code() << kFsShift
2793 | cc << 8 | 3 << 4 | cond;
2794 emit(instr);
2795}
2796
2797
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002798void Assembler::c_s(FPUCondition cond, FPURegister fs, FPURegister ft,
2799 uint16_t cc) {
2800 c(cond, S, fs, ft, cc);
2801}
2802
2803
2804void Assembler::c_d(FPUCondition cond, FPURegister fs, FPURegister ft,
2805 uint16_t cc) {
2806 c(cond, D, fs, ft, cc);
2807}
2808
2809
Steve Block44f0eee2011-05-26 01:26:41 +01002810void Assembler::fcmp(FPURegister src1, const double src2,
2811 FPUCondition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002812 DCHECK(src2 == 0.0);
Steve Block44f0eee2011-05-26 01:26:41 +01002813 mtc1(zero_reg, f14);
2814 cvt_d_w(f14, f14);
2815 c(cond, D, src1, f14, 0);
2816}
2817
2818
Andrei Popescu31002712010-02-23 13:46:05 +00002819void Assembler::bc1f(int16_t offset, uint16_t cc) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002820 DCHECK(is_uint3(cc));
Andrei Popescu31002712010-02-23 13:46:05 +00002821 Instr instr = COP1 | BC1 | cc << 18 | 0 << 16 | (offset & kImm16Mask);
2822 emit(instr);
2823}
2824
2825
2826void Assembler::bc1t(int16_t offset, uint16_t cc) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002827 DCHECK(is_uint3(cc));
Andrei Popescu31002712010-02-23 13:46:05 +00002828 Instr instr = COP1 | BC1 | cc << 18 | 1 << 16 | (offset & kImm16Mask);
2829 emit(instr);
2830}
2831
2832
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002833int Assembler::RelocateInternalReference(RelocInfo::Mode rmode, byte* pc,
2834 intptr_t pc_delta) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002835 Instr instr = instr_at(pc);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002836
2837 if (RelocInfo::IsInternalReference(rmode)) {
2838 int32_t* p = reinterpret_cast<int32_t*>(pc);
2839 if (*p == 0) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002840 return 0; // Number of instructions patched.
2841 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002842 *p += pc_delta;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002843 return 1; // Number of instructions patched.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002844 } else {
2845 DCHECK(RelocInfo::IsInternalReferenceEncoded(rmode));
2846 if (IsLui(instr)) {
Ben Murdochda12d292016-06-02 14:46:10 +01002847 Instr instr1 = instr_at(pc + 0 * Assembler::kInstrSize);
2848 Instr instr2 = instr_at(pc + 1 * Assembler::kInstrSize);
2849 DCHECK(IsOri(instr2) || IsJicOrJialc(instr2));
2850 int32_t imm;
2851 if (IsJicOrJialc(instr2)) {
2852 imm = CreateTargetAddress(instr1, instr2);
2853 } else {
2854 imm = (instr1 & static_cast<int32_t>(kImm16Mask)) << kLuiShift;
2855 imm |= (instr2 & static_cast<int32_t>(kImm16Mask));
2856 }
2857
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002858 if (imm == kEndOfJumpChain) {
2859 return 0; // Number of instructions patched.
2860 }
2861 imm += pc_delta;
2862 DCHECK((imm & 3) == 0);
Ben Murdochda12d292016-06-02 14:46:10 +01002863 instr1 &= ~kImm16Mask;
2864 instr2 &= ~kImm16Mask;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002865
Ben Murdochda12d292016-06-02 14:46:10 +01002866 if (IsJicOrJialc(instr2)) {
2867 uint32_t lui_offset_u, jic_offset_u;
2868 Assembler::UnpackTargetAddressUnsigned(imm, lui_offset_u, jic_offset_u);
2869 instr_at_put(pc + 0 * Assembler::kInstrSize, instr1 | lui_offset_u);
2870 instr_at_put(pc + 1 * Assembler::kInstrSize, instr2 | jic_offset_u);
2871 } else {
2872 instr_at_put(pc + 0 * Assembler::kInstrSize,
2873 instr1 | ((imm >> kLuiShift) & kImm16Mask));
2874 instr_at_put(pc + 1 * Assembler::kInstrSize,
2875 instr2 | (imm & kImm16Mask));
2876 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002877 return 2; // Number of instructions patched.
2878 } else {
2879 UNREACHABLE();
2880 return 0;
2881 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002882 }
2883}
2884
2885
Andrei Popescu31002712010-02-23 13:46:05 +00002886void Assembler::GrowBuffer() {
2887 if (!own_buffer_) FATAL("external code buffer is too small");
2888
2889 // Compute new buffer size.
Steve Block44f0eee2011-05-26 01:26:41 +01002890 CodeDesc desc; // The new buffer.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002891 if (buffer_size_ < 1 * MB) {
Andrei Popescu31002712010-02-23 13:46:05 +00002892 desc.buffer_size = 2*buffer_size_;
2893 } else {
2894 desc.buffer_size = buffer_size_ + 1*MB;
2895 }
Steve Block44f0eee2011-05-26 01:26:41 +01002896 CHECK_GT(desc.buffer_size, 0); // No overflow.
Andrei Popescu31002712010-02-23 13:46:05 +00002897
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002898 // Set up new buffer.
Andrei Popescu31002712010-02-23 13:46:05 +00002899 desc.buffer = NewArray<byte>(desc.buffer_size);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002900 desc.origin = this;
Andrei Popescu31002712010-02-23 13:46:05 +00002901
2902 desc.instr_size = pc_offset();
2903 desc.reloc_size = (buffer_ + buffer_size_) - reloc_info_writer.pos();
2904
2905 // Copy the data.
2906 int pc_delta = desc.buffer - buffer_;
2907 int rc_delta = (desc.buffer + desc.buffer_size) - (buffer_ + buffer_size_);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002908 MemMove(desc.buffer, buffer_, desc.instr_size);
2909 MemMove(reloc_info_writer.pos() + rc_delta, reloc_info_writer.pos(),
2910 desc.reloc_size);
Andrei Popescu31002712010-02-23 13:46:05 +00002911
2912 // Switch buffers.
2913 DeleteArray(buffer_);
2914 buffer_ = desc.buffer;
2915 buffer_size_ = desc.buffer_size;
2916 pc_ += pc_delta;
2917 reloc_info_writer.Reposition(reloc_info_writer.pos() + rc_delta,
2918 reloc_info_writer.last_pc() + pc_delta);
2919
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002920 // Relocate runtime entries.
2921 for (RelocIterator it(desc); !it.done(); it.next()) {
2922 RelocInfo::Mode rmode = it.rinfo()->rmode();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002923 if (rmode == RelocInfo::INTERNAL_REFERENCE_ENCODED ||
2924 rmode == RelocInfo::INTERNAL_REFERENCE) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002925 byte* p = reinterpret_cast<byte*>(it.rinfo()->pc());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002926 RelocateInternalReference(rmode, p, pc_delta);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002927 }
2928 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002929 DCHECK(!overflow());
Andrei Popescu31002712010-02-23 13:46:05 +00002930}
2931
2932
Steve Block44f0eee2011-05-26 01:26:41 +01002933void Assembler::db(uint8_t data) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002934 CheckForEmitInForbiddenSlot();
2935 EmitHelper(data);
Steve Block44f0eee2011-05-26 01:26:41 +01002936}
2937
2938
2939void Assembler::dd(uint32_t data) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002940 CheckForEmitInForbiddenSlot();
2941 EmitHelper(data);
Steve Block44f0eee2011-05-26 01:26:41 +01002942}
2943
2944
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002945void Assembler::dq(uint64_t data) {
2946 CheckForEmitInForbiddenSlot();
2947 EmitHelper(data);
2948}
2949
2950
2951void Assembler::dd(Label* label) {
2952 uint32_t data;
2953 CheckForEmitInForbiddenSlot();
2954 if (label->is_bound()) {
2955 data = reinterpret_cast<uint32_t>(buffer_ + label->pos());
2956 } else {
2957 data = jump_address(label);
2958 internal_reference_positions_.insert(label->pos());
2959 }
2960 RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE);
2961 EmitHelper(data);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002962}
2963
2964
Andrei Popescu31002712010-02-23 13:46:05 +00002965void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002966 // We do not try to reuse pool constants.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002967 RelocInfo rinfo(isolate(), pc_, rmode, data, NULL);
2968 if (rmode >= RelocInfo::COMMENT &&
Ben Murdochda12d292016-06-02 14:46:10 +01002969 rmode <= RelocInfo::DEBUG_BREAK_SLOT_AT_TAIL_CALL) {
Andrei Popescu31002712010-02-23 13:46:05 +00002970 // Adjust code for new modes.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002971 DCHECK(RelocInfo::IsDebugBreakSlot(rmode)
Andrei Popescu31002712010-02-23 13:46:05 +00002972 || RelocInfo::IsComment(rmode)
2973 || RelocInfo::IsPosition(rmode));
2974 // These modes do not need an entry in the constant pool.
2975 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002976 if (!RelocInfo::IsNone(rinfo.rmode())) {
Andrei Popescu31002712010-02-23 13:46:05 +00002977 // Don't record external references unless the heap will be serialized.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002978 if (rmode == RelocInfo::EXTERNAL_REFERENCE &&
2979 !serializer_enabled() && !emit_debug_code()) {
2980 return;
Andrei Popescu31002712010-02-23 13:46:05 +00002981 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002982 DCHECK(buffer_space() >= kMaxRelocSize); // Too late to grow buffer here.
Ben Murdoch257744e2011-11-30 15:57:28 +00002983 if (rmode == RelocInfo::CODE_TARGET_WITH_ID) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002984 RelocInfo reloc_info_with_ast_id(isolate(), pc_, rmode,
2985 RecordedAstId().ToInt(), NULL);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002986 ClearRecordedAstId();
Ben Murdoch257744e2011-11-30 15:57:28 +00002987 reloc_info_writer.Write(&reloc_info_with_ast_id);
2988 } else {
2989 reloc_info_writer.Write(&rinfo);
2990 }
Andrei Popescu31002712010-02-23 13:46:05 +00002991 }
2992}
2993
2994
Steve Block44f0eee2011-05-26 01:26:41 +01002995void Assembler::BlockTrampolinePoolFor(int instructions) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002996 CheckTrampolinePoolQuick(instructions);
Steve Block44f0eee2011-05-26 01:26:41 +01002997 BlockTrampolinePoolBefore(pc_offset() + instructions * kInstrSize);
2998}
2999
3000
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003001void Assembler::CheckTrampolinePool() {
Steve Block44f0eee2011-05-26 01:26:41 +01003002 // Some small sequences of instructions must not be broken up by the
3003 // insertion of a trampoline pool; such sequences are protected by setting
3004 // either trampoline_pool_blocked_nesting_ or no_trampoline_pool_before_,
3005 // which are both checked here. Also, recursive calls to CheckTrampolinePool
3006 // are blocked by trampoline_pool_blocked_nesting_.
3007 if ((trampoline_pool_blocked_nesting_ > 0) ||
3008 (pc_offset() < no_trampoline_pool_before_)) {
3009 // Emission is currently blocked; make sure we try again as soon as
3010 // possible.
3011 if (trampoline_pool_blocked_nesting_ > 0) {
3012 next_buffer_check_ = pc_offset() + kInstrSize;
3013 } else {
3014 next_buffer_check_ = no_trampoline_pool_before_;
3015 }
3016 return;
3017 }
3018
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003019 DCHECK(!trampoline_emitted_);
3020 DCHECK(unbound_labels_count_ >= 0);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003021 if (unbound_labels_count_ > 0) {
3022 // First we emit jump (2 instructions), then we emit trampoline pool.
3023 { BlockTrampolinePoolScope block_trampoline_pool(this);
3024 Label after_pool;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003025 if (IsMipsArchVariant(kMips32r6)) {
3026 bc(&after_pool);
3027 } else {
3028 b(&after_pool);
3029 nop();
3030 }
Steve Block44f0eee2011-05-26 01:26:41 +01003031
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003032 int pool_start = pc_offset();
Ben Murdochda12d292016-06-02 14:46:10 +01003033 if (IsMipsArchVariant(kMips32r6)) {
3034 for (int i = 0; i < unbound_labels_count_; i++) {
3035 uint32_t imm32;
3036 imm32 = jump_address(&after_pool);
3037 uint32_t lui_offset, jic_offset;
3038 UnpackTargetAddressUnsigned(imm32, lui_offset, jic_offset);
3039 {
3040 BlockGrowBufferScope block_buf_growth(this);
3041 // Buffer growth (and relocation) must be blocked for internal
3042 // references until associated instructions are emitted and
3043 // available to be patched.
3044 RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE_ENCODED);
3045 lui(at, lui_offset);
3046 jic(at, jic_offset);
3047 }
3048 CheckBuffer();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003049 }
Ben Murdochda12d292016-06-02 14:46:10 +01003050 } else {
3051 for (int i = 0; i < unbound_labels_count_; i++) {
3052 uint32_t imm32;
3053 imm32 = jump_address(&after_pool);
3054 {
3055 BlockGrowBufferScope block_buf_growth(this);
3056 // Buffer growth (and relocation) must be blocked for internal
3057 // references until associated instructions are emitted and
3058 // available to be patched.
3059 RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE_ENCODED);
3060 lui(at, (imm32 & kHiMask) >> kLuiShift);
3061 ori(at, at, (imm32 & kImm16Mask));
3062 }
3063 CheckBuffer();
3064 jr(at);
3065 nop();
3066 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003067 }
3068 bind(&after_pool);
3069 trampoline_ = Trampoline(pool_start, unbound_labels_count_);
3070
3071 trampoline_emitted_ = true;
3072 // As we are only going to emit trampoline once, we need to prevent any
3073 // further emission.
3074 next_buffer_check_ = kMaxInt;
3075 }
3076 } else {
3077 // Number of branches to unbound label at this point is zero, so we can
3078 // move next buffer check to maximum.
3079 next_buffer_check_ = pc_offset() +
3080 kMaxBranchOffset - kTrampolineSlotsSize * 16;
Steve Block44f0eee2011-05-26 01:26:41 +01003081 }
3082 return;
3083}
3084
3085
Andrei Popescu31002712010-02-23 13:46:05 +00003086Address Assembler::target_address_at(Address pc) {
3087 Instr instr1 = instr_at(pc);
3088 Instr instr2 = instr_at(pc + kInstrSize);
Ben Murdoch257744e2011-11-30 15:57:28 +00003089 // Interpret 2 instructions generated by li: lui/ori
Ben Murdochda12d292016-06-02 14:46:10 +01003090 if (IsLui(instr1) && IsOri(instr2)) {
Ben Murdoch257744e2011-11-30 15:57:28 +00003091 // Assemble the 32 bit value.
Ben Murdochda12d292016-06-02 14:46:10 +01003092 return reinterpret_cast<Address>((GetImmediate16(instr1) << kLuiShift) |
3093 GetImmediate16(instr2));
Andrei Popescu31002712010-02-23 13:46:05 +00003094 }
3095
Ben Murdoch257744e2011-11-30 15:57:28 +00003096 // We should never get here, force a bad address if we do.
Andrei Popescu31002712010-02-23 13:46:05 +00003097 UNREACHABLE();
3098 return (Address)0x0;
3099}
3100
3101
Ben Murdochdb1b4382012-04-26 19:03:50 +01003102// MIPS and ia32 use opposite encoding for qNaN and sNaN, such that ia32
3103// qNaN is a MIPS sNaN, and ia32 sNaN is MIPS qNaN. If running from a heap
3104// snapshot generated on ia32, the resulting MIPS sNaN must be quieted.
3105// OS::nan_value() returns a qNaN.
3106void Assembler::QuietNaN(HeapObject* object) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003107 HeapNumber::cast(object)->set_value(std::numeric_limits<double>::quiet_NaN());
Ben Murdochdb1b4382012-04-26 19:03:50 +01003108}
3109
3110
Ben Murdoch589d6972011-11-30 16:04:58 +00003111// On Mips, a target address is stored in a lui/ori instruction pair, each
3112// of which load 16 bits of the 32-bit address to a register.
3113// Patching the address must replace both instr, and flush the i-cache.
Ben Murdochda12d292016-06-02 14:46:10 +01003114// On r6, target address is stored in a lui/jic pair, and both instr have to be
3115// patched.
Ben Murdoch589d6972011-11-30 16:04:58 +00003116//
3117// There is an optimization below, which emits a nop when the address
3118// fits in just 16 bits. This is unlikely to help, and should be benchmarked,
3119// and possibly removed.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003120void Assembler::set_target_address_at(Isolate* isolate, Address pc,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003121 Address target,
3122 ICacheFlushMode icache_flush_mode) {
Andrei Popescu31002712010-02-23 13:46:05 +00003123 Instr instr2 = instr_at(pc + kInstrSize);
Ben Murdoch257744e2011-11-30 15:57:28 +00003124 uint32_t rt_code = GetRtField(instr2);
Andrei Popescu31002712010-02-23 13:46:05 +00003125 uint32_t* p = reinterpret_cast<uint32_t*>(pc);
3126 uint32_t itarget = reinterpret_cast<uint32_t>(target);
3127
Ben Murdoch589d6972011-11-30 16:04:58 +00003128#ifdef DEBUG
3129 // Check we have the result from a li macro-instruction, using instr pair.
3130 Instr instr1 = instr_at(pc);
Ben Murdochda12d292016-06-02 14:46:10 +01003131 CHECK(IsLui(instr1) && (IsOri(instr2) || IsJicOrJialc(instr2)));
Ben Murdoch589d6972011-11-30 16:04:58 +00003132#endif
3133
Ben Murdochda12d292016-06-02 14:46:10 +01003134 if (IsJicOrJialc(instr2)) {
3135 // Must use 2 instructions to insure patchable code => use lui and jic
3136 uint32_t lui_offset, jic_offset;
3137 Assembler::UnpackTargetAddressUnsigned(itarget, lui_offset, jic_offset);
Andrei Popescu31002712010-02-23 13:46:05 +00003138
Ben Murdochda12d292016-06-02 14:46:10 +01003139 *p &= ~kImm16Mask;
3140 *(p + 1) &= ~kImm16Mask;
3141
3142 *p |= lui_offset;
3143 *(p + 1) |= jic_offset;
3144
3145 } else {
3146 // Must use 2 instructions to insure patchable code => just use lui and ori.
3147 // lui rt, upper-16.
3148 // ori rt rt, lower-16.
3149 *p = LUI | rt_code | ((itarget & kHiMask) >> kLuiShift);
3150 *(p + 1) = ORI | rt_code | (rt_code << 5) | (itarget & kImm16Mask);
3151 }
Ben Murdoch589d6972011-11-30 16:04:58 +00003152
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003153 if (icache_flush_mode != SKIP_ICACHE_FLUSH) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003154 Assembler::FlushICache(isolate, pc, 2 * sizeof(int32_t));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003155 }
Andrei Popescu31002712010-02-23 13:46:05 +00003156}
3157
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003158} // namespace internal
3159} // namespace v8
Andrei Popescu31002712010-02-23 13:46:05 +00003160
Leon Clarkef7060e22010-06-03 12:02:55 +01003161#endif // V8_TARGET_ARCH_MIPS