blob: 20a8a11fbb1d92f55c1e2664a490ab59a59c4638 [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 Murdoch014dc512016-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 Murdoch014dc512016-03-22 12:00:34 +0000176 1 << RelocInfo::INTERNAL_REFERENCE |
177 1 << RelocInfo::INTERNAL_REFERENCE_ENCODED;
Andrei Popescu31002712010-02-23 13:46:05 +0000178
Steve Block44f0eee2011-05-26 01:26:41 +0100179
180bool RelocInfo::IsCodedSpecially() {
181 // The deserializer needs to know whether a pointer is specially coded. Being
182 // specially coded on MIPS means that it is a lui/ori instruction, and that is
183 // always the case inside code objects.
184 return true;
185}
186
187
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000188bool RelocInfo::IsInConstantPool() {
189 return false;
190}
191
Ben Murdochbcf72ee2016-08-08 18:44:38 +0100192Address RelocInfo::wasm_memory_reference() {
193 DCHECK(IsWasmMemoryReference(rmode_));
194 return Assembler::target_address_at(pc_, host_);
195}
196
Ben Murdoch13e2dad2016-09-16 13:49:30 +0100197Address RelocInfo::wasm_global_reference() {
198 DCHECK(IsWasmGlobalReference(rmode_));
199 return Assembler::target_address_at(pc_, host_);
200}
201
Ben Murdochbcf72ee2016-08-08 18:44:38 +0100202uint32_t RelocInfo::wasm_memory_size_reference() {
203 DCHECK(IsWasmMemorySizeReference(rmode_));
204 return reinterpret_cast<uint32_t>(Assembler::target_address_at(pc_, host_));
205}
206
Ben Murdoch13e2dad2016-09-16 13:49:30 +0100207void RelocInfo::unchecked_update_wasm_memory_reference(
208 Address address, ICacheFlushMode flush_mode) {
209 Assembler::set_target_address_at(isolate_, pc_, host_, address, flush_mode);
210}
211
212void RelocInfo::unchecked_update_wasm_memory_size(uint32_t size,
213 ICacheFlushMode flush_mode) {
214 Assembler::set_target_address_at(isolate_, pc_, host_,
215 reinterpret_cast<Address>(size), flush_mode);
Ben Murdochbcf72ee2016-08-08 18:44:38 +0100216}
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000217
Andrei Popescu31002712010-02-23 13:46:05 +0000218// -----------------------------------------------------------------------------
219// Implementation of Operand and MemOperand.
220// See assembler-mips-inl.h for inlined constructors.
221
222Operand::Operand(Handle<Object> handle) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000223 AllowDeferredHandleDereference using_raw_address;
Andrei Popescu31002712010-02-23 13:46:05 +0000224 rm_ = no_reg;
225 // Verify all Objects referred by code are NOT in new space.
226 Object* obj = *handle;
Andrei Popescu31002712010-02-23 13:46:05 +0000227 if (obj->IsHeapObject()) {
228 imm32_ = reinterpret_cast<intptr_t>(handle.location());
229 rmode_ = RelocInfo::EMBEDDED_OBJECT;
230 } else {
231 // No relocation needed.
232 imm32_ = reinterpret_cast<intptr_t>(obj);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000233 rmode_ = RelocInfo::NONE32;
Andrei Popescu31002712010-02-23 13:46:05 +0000234 }
235}
236
Steve Block44f0eee2011-05-26 01:26:41 +0100237
238MemOperand::MemOperand(Register rm, int32_t offset) : Operand(rm) {
Andrei Popescu31002712010-02-23 13:46:05 +0000239 offset_ = offset;
240}
241
242
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000243MemOperand::MemOperand(Register rm, int32_t unit, int32_t multiplier,
244 OffsetAddend offset_addend) : Operand(rm) {
245 offset_ = unit * multiplier + offset_addend;
246}
247
248
Andrei Popescu31002712010-02-23 13:46:05 +0000249// -----------------------------------------------------------------------------
Steve Block44f0eee2011-05-26 01:26:41 +0100250// Specific instructions, constants, and masks.
Andrei Popescu31002712010-02-23 13:46:05 +0000251
Steve Block44f0eee2011-05-26 01:26:41 +0100252static const int kNegOffset = 0x00008000;
253// addiu(sp, sp, 4) aka Pop() operation or part of Pop(r)
254// operations as post-increment of sp.
Ben Murdoch014dc512016-03-22 12:00:34 +0000255const Instr kPopInstruction = ADDIU | (Register::kCode_sp << kRsShift) |
256 (Register::kCode_sp << kRtShift) |
257 (kPointerSize & kImm16Mask); // NOLINT
Steve Block44f0eee2011-05-26 01:26:41 +0100258// addiu(sp, sp, -4) part of Push(r) operation as pre-decrement of sp.
Ben Murdoch014dc512016-03-22 12:00:34 +0000259const Instr kPushInstruction = ADDIU | (Register::kCode_sp << kRsShift) |
260 (Register::kCode_sp << kRtShift) |
261 (-kPointerSize & kImm16Mask); // NOLINT
Steve Block44f0eee2011-05-26 01:26:41 +0100262// sw(r, MemOperand(sp, 0))
Ben Murdoch014dc512016-03-22 12:00:34 +0000263const Instr kPushRegPattern =
264 SW | (Register::kCode_sp << kRsShift) | (0 & kImm16Mask); // NOLINT
Steve Block44f0eee2011-05-26 01:26:41 +0100265// lw(r, MemOperand(sp, 0))
Ben Murdoch014dc512016-03-22 12:00:34 +0000266const Instr kPopRegPattern =
267 LW | (Register::kCode_sp << kRsShift) | (0 & kImm16Mask); // NOLINT
Andrei Popescu31002712010-02-23 13:46:05 +0000268
Ben Murdoch014dc512016-03-22 12:00:34 +0000269const Instr kLwRegFpOffsetPattern =
270 LW | (Register::kCode_fp << kRsShift) | (0 & kImm16Mask); // NOLINT
Steve Block44f0eee2011-05-26 01:26:41 +0100271
Ben Murdoch014dc512016-03-22 12:00:34 +0000272const Instr kSwRegFpOffsetPattern =
273 SW | (Register::kCode_fp << kRsShift) | (0 & kImm16Mask); // NOLINT
Steve Block44f0eee2011-05-26 01:26:41 +0100274
Ben Murdoch014dc512016-03-22 12:00:34 +0000275const Instr kLwRegFpNegOffsetPattern = LW | (Register::kCode_fp << kRsShift) |
276 (kNegOffset & kImm16Mask); // NOLINT
Steve Block44f0eee2011-05-26 01:26:41 +0100277
Ben Murdoch014dc512016-03-22 12:00:34 +0000278const Instr kSwRegFpNegOffsetPattern = SW | (Register::kCode_fp << kRsShift) |
279 (kNegOffset & kImm16Mask); // NOLINT
Steve Block44f0eee2011-05-26 01:26:41 +0100280// A mask for the Rt register for push, pop, lw, sw instructions.
281const Instr kRtMask = kRtFieldMask;
282const Instr kLwSwInstrTypeMask = 0xffe00000;
283const Instr kLwSwInstrArgumentMask = ~kLwSwInstrTypeMask;
284const Instr kLwSwOffsetMask = kImm16Mask;
285
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000286Assembler::Assembler(Isolate* isolate, void* buffer, int buffer_size)
287 : AssemblerBase(isolate, buffer, buffer_size),
Ben Murdochf91f0612016-11-29 16:50:11 +0000288 recorded_ast_id_(TypeFeedbackId::None()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000289 reloc_info_writer.Reposition(buffer_ + buffer_size_, pc_);
Steve Block44f0eee2011-05-26 01:26:41 +0100290
291 last_trampoline_pool_end_ = 0;
292 no_trampoline_pool_before_ = 0;
293 trampoline_pool_blocked_nesting_ = 0;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000294 // We leave space (16 * kTrampolineSlotsSize)
295 // for BlockTrampolinePoolScope buffer.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000296 next_buffer_check_ = FLAG_force_long_branches
297 ? kMaxInt : kMaxBranchOffset - kTrampolineSlotsSize * 16;
Ben Murdoch257744e2011-11-30 15:57:28 +0000298 internal_trampoline_exception_ = false;
299 last_bound_pos_ = 0;
300
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000301 trampoline_emitted_ = FLAG_force_long_branches;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000302 unbound_labels_count_ = 0;
303 block_buffer_growth_ = false;
304
305 ClearRecordedAstId();
Andrei Popescu31002712010-02-23 13:46:05 +0000306}
307
308
Andrei Popescu31002712010-02-23 13:46:05 +0000309void Assembler::GetCode(CodeDesc* desc) {
Ben Murdoch109988c2016-05-18 11:27:45 +0100310 EmitForbiddenSlotInstruction();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000311 DCHECK(pc_ <= reloc_info_writer.pos()); // No overlap.
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100312 // Set up code descriptor.
Andrei Popescu31002712010-02-23 13:46:05 +0000313 desc->buffer = buffer_;
314 desc->buffer_size = buffer_size_;
315 desc->instr_size = pc_offset();
316 desc->reloc_size = (buffer_ + buffer_size_) - reloc_info_writer.pos();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000317 desc->origin = this;
Ben Murdoch014dc512016-03-22 12:00:34 +0000318 desc->constant_pool_size = 0;
Ben Murdoch13e2dad2016-09-16 13:49:30 +0100319 desc->unwinding_info_size = 0;
320 desc->unwinding_info = nullptr;
Andrei Popescu31002712010-02-23 13:46:05 +0000321}
322
323
Steve Block44f0eee2011-05-26 01:26:41 +0100324void Assembler::Align(int m) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000325 DCHECK(m >= 4 && base::bits::IsPowerOfTwo32(m));
Ben Murdoch109988c2016-05-18 11:27:45 +0100326 EmitForbiddenSlotInstruction();
Steve Block44f0eee2011-05-26 01:26:41 +0100327 while ((pc_offset() & (m - 1)) != 0) {
328 nop();
329 }
330}
331
332
333void Assembler::CodeTargetAlign() {
334 // No advantage to aligning branch/call targets to more than
335 // single instruction, that I am aware of.
336 Align(4);
337}
338
339
Ben Murdoch257744e2011-11-30 15:57:28 +0000340Register Assembler::GetRtReg(Instr instr) {
Steve Block44f0eee2011-05-26 01:26:41 +0100341 Register rt;
Ben Murdoch014dc512016-03-22 12:00:34 +0000342 rt.reg_code = (instr & kRtFieldMask) >> kRtShift;
Steve Block44f0eee2011-05-26 01:26:41 +0100343 return rt;
344}
345
346
Ben Murdoch257744e2011-11-30 15:57:28 +0000347Register Assembler::GetRsReg(Instr instr) {
348 Register rs;
Ben Murdoch014dc512016-03-22 12:00:34 +0000349 rs.reg_code = (instr & kRsFieldMask) >> kRsShift;
Ben Murdoch257744e2011-11-30 15:57:28 +0000350 return rs;
351}
352
353
354Register Assembler::GetRdReg(Instr instr) {
355 Register rd;
Ben Murdoch014dc512016-03-22 12:00:34 +0000356 rd.reg_code = (instr & kRdFieldMask) >> kRdShift;
Ben Murdoch257744e2011-11-30 15:57:28 +0000357 return rd;
358}
359
360
361uint32_t Assembler::GetRt(Instr instr) {
362 return (instr & kRtFieldMask) >> kRtShift;
363}
364
365
366uint32_t Assembler::GetRtField(Instr instr) {
367 return instr & kRtFieldMask;
368}
369
370
371uint32_t Assembler::GetRs(Instr instr) {
372 return (instr & kRsFieldMask) >> kRsShift;
373}
374
375
376uint32_t Assembler::GetRsField(Instr instr) {
377 return instr & kRsFieldMask;
378}
379
380
381uint32_t Assembler::GetRd(Instr instr) {
382 return (instr & kRdFieldMask) >> kRdShift;
383}
384
385
386uint32_t Assembler::GetRdField(Instr instr) {
387 return instr & kRdFieldMask;
388}
389
390
391uint32_t Assembler::GetSa(Instr instr) {
392 return (instr & kSaFieldMask) >> kSaShift;
393}
394
395
396uint32_t Assembler::GetSaField(Instr instr) {
397 return instr & kSaFieldMask;
398}
399
400
401uint32_t Assembler::GetOpcodeField(Instr instr) {
402 return instr & kOpcodeMask;
403}
404
405
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000406uint32_t Assembler::GetFunction(Instr instr) {
407 return (instr & kFunctionFieldMask) >> kFunctionShift;
408}
409
410
411uint32_t Assembler::GetFunctionField(Instr instr) {
412 return instr & kFunctionFieldMask;
413}
414
415
Ben Murdoch257744e2011-11-30 15:57:28 +0000416uint32_t Assembler::GetImmediate16(Instr instr) {
417 return instr & kImm16Mask;
418}
419
420
421uint32_t Assembler::GetLabelConst(Instr instr) {
422 return instr & ~kImm16Mask;
423}
424
425
Steve Block44f0eee2011-05-26 01:26:41 +0100426bool Assembler::IsPop(Instr instr) {
427 return (instr & ~kRtMask) == kPopRegPattern;
428}
429
430
431bool Assembler::IsPush(Instr instr) {
432 return (instr & ~kRtMask) == kPushRegPattern;
433}
434
435
436bool Assembler::IsSwRegFpOffset(Instr instr) {
437 return ((instr & kLwSwInstrTypeMask) == kSwRegFpOffsetPattern);
438}
439
440
441bool Assembler::IsLwRegFpOffset(Instr instr) {
442 return ((instr & kLwSwInstrTypeMask) == kLwRegFpOffsetPattern);
443}
444
445
446bool Assembler::IsSwRegFpNegOffset(Instr instr) {
447 return ((instr & (kLwSwInstrTypeMask | kNegOffset)) ==
448 kSwRegFpNegOffsetPattern);
449}
450
451
452bool Assembler::IsLwRegFpNegOffset(Instr instr) {
453 return ((instr & (kLwSwInstrTypeMask | kNegOffset)) ==
454 kLwRegFpNegOffsetPattern);
455}
456
457
Andrei Popescu31002712010-02-23 13:46:05 +0000458// Labels refer to positions in the (to be) generated code.
459// There are bound, linked, and unused labels.
460//
461// Bound labels refer to known positions in the already
462// generated code. pos() is the position the label refers to.
463//
464// Linked labels refer to unknown positions in the code
465// to be generated; pos() is the position of the last
466// instruction using the label.
467
Steve Block44f0eee2011-05-26 01:26:41 +0100468// The link chain is terminated by a value in the instruction of -1,
469// which is an otherwise illegal value (branch -1 is inf loop).
470// The instruction 16-bit offset field addresses 32-bit words, but in
471// code is conv to an 18-bit value addressing bytes, hence the -4 value.
Andrei Popescu31002712010-02-23 13:46:05 +0000472
Andrei Popescu31002712010-02-23 13:46:05 +0000473const int kEndOfChain = -4;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000474// Determines the end of the Jump chain (a subset of the label link chain).
475const int kEndOfJumpChain = 0;
Andrei Popescu31002712010-02-23 13:46:05 +0000476
Steve Block44f0eee2011-05-26 01:26:41 +0100477
478bool Assembler::IsBranch(Instr instr) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000479 uint32_t opcode = GetOpcodeField(instr);
480 uint32_t rt_field = GetRtField(instr);
481 uint32_t rs_field = GetRsField(instr);
Andrei Popescu31002712010-02-23 13:46:05 +0000482 // Checks if the instruction is a branch.
Ben Murdoch014dc512016-03-22 12:00:34 +0000483 bool isBranch =
484 opcode == BEQ || opcode == BNE || opcode == BLEZ || opcode == BGTZ ||
485 opcode == BEQL || opcode == BNEL || opcode == BLEZL || opcode == BGTZL ||
Andrei Popescu31002712010-02-23 13:46:05 +0000486 (opcode == REGIMM && (rt_field == BLTZ || rt_field == BGEZ ||
487 rt_field == BLTZAL || rt_field == BGEZAL)) ||
Steve Block44f0eee2011-05-26 01:26:41 +0100488 (opcode == COP1 && rs_field == BC1) || // Coprocessor branch.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000489 (opcode == COP1 && rs_field == BC1EQZ) ||
490 (opcode == COP1 && rs_field == BC1NEZ);
Ben Murdoch014dc512016-03-22 12:00:34 +0000491 if (!isBranch && IsMipsArchVariant(kMips32r6)) {
492 // All the 3 variants of POP10 (BOVC, BEQC, BEQZALC) and
493 // POP30 (BNVC, BNEC, BNEZALC) are branch ops.
494 isBranch |= opcode == POP10 || opcode == POP30 || opcode == BC ||
495 opcode == BALC ||
496 (opcode == POP66 && rs_field != 0) || // BEQZC
497 (opcode == POP76 && rs_field != 0); // BNEZC
498 }
499 return isBranch;
500}
501
502
503bool Assembler::IsBc(Instr instr) {
504 uint32_t opcode = GetOpcodeField(instr);
505 // Checks if the instruction is a BC or BALC.
506 return opcode == BC || opcode == BALC;
507}
508
509
510bool Assembler::IsBzc(Instr instr) {
511 uint32_t opcode = GetOpcodeField(instr);
512 // Checks if the instruction is BEQZC or BNEZC.
513 return (opcode == POP66 && GetRsField(instr) != 0) ||
514 (opcode == POP76 && GetRsField(instr) != 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000515}
516
517
518bool Assembler::IsEmittedConstant(Instr instr) {
519 uint32_t label_constant = GetLabelConst(instr);
520 return label_constant == 0; // Emitted label const in reg-exp engine.
Steve Block44f0eee2011-05-26 01:26:41 +0100521}
522
523
Ben Murdoch257744e2011-11-30 15:57:28 +0000524bool Assembler::IsBeq(Instr instr) {
525 return GetOpcodeField(instr) == BEQ;
526}
527
528
529bool Assembler::IsBne(Instr instr) {
530 return GetOpcodeField(instr) == BNE;
531}
532
533
Ben Murdoch014dc512016-03-22 12:00:34 +0000534bool Assembler::IsBeqzc(Instr instr) {
535 uint32_t opcode = GetOpcodeField(instr);
536 return opcode == POP66 && GetRsField(instr) != 0;
537}
538
539
540bool Assembler::IsBnezc(Instr instr) {
541 uint32_t opcode = GetOpcodeField(instr);
542 return opcode == POP76 && GetRsField(instr) != 0;
543}
544
545
546bool Assembler::IsBeqc(Instr instr) {
547 uint32_t opcode = GetOpcodeField(instr);
548 uint32_t rs = GetRsField(instr);
549 uint32_t rt = GetRtField(instr);
550 return opcode == POP10 && rs != 0 && rs < rt; // && rt != 0
551}
552
553
554bool Assembler::IsBnec(Instr instr) {
555 uint32_t opcode = GetOpcodeField(instr);
556 uint32_t rs = GetRsField(instr);
557 uint32_t rt = GetRtField(instr);
558 return opcode == POP30 && rs != 0 && rs < rt; // && rt != 0
559}
560
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100561bool Assembler::IsJicOrJialc(Instr instr) {
562 uint32_t opcode = GetOpcodeField(instr);
563 uint32_t rs = GetRsField(instr);
564 return (opcode == POP66 || opcode == POP76) && rs == 0;
565}
Ben Murdoch014dc512016-03-22 12:00:34 +0000566
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000567bool Assembler::IsJump(Instr instr) {
568 uint32_t opcode = GetOpcodeField(instr);
569 uint32_t rt_field = GetRtField(instr);
570 uint32_t rd_field = GetRdField(instr);
571 uint32_t function_field = GetFunctionField(instr);
572 // Checks if the instruction is a jump.
573 return opcode == J || opcode == JAL ||
574 (opcode == SPECIAL && rt_field == 0 &&
575 ((function_field == JALR) || (rd_field == 0 && (function_field == JR))));
576}
577
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000578bool Assembler::IsJ(Instr instr) {
579 uint32_t opcode = GetOpcodeField(instr);
580 // Checks if the instruction is a jump.
581 return opcode == J;
582}
583
584
Ben Murdoch589d6972011-11-30 16:04:58 +0000585bool Assembler::IsJal(Instr instr) {
586 return GetOpcodeField(instr) == JAL;
587}
588
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000589
Ben Murdoch589d6972011-11-30 16:04:58 +0000590bool Assembler::IsJr(Instr instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000591 if (!IsMipsArchVariant(kMips32r6)) {
592 return GetOpcodeField(instr) == SPECIAL && GetFunctionField(instr) == JR;
593 } else {
594 return GetOpcodeField(instr) == SPECIAL &&
595 GetRdField(instr) == 0 && GetFunctionField(instr) == JALR;
596 }
Ben Murdoch589d6972011-11-30 16:04:58 +0000597}
598
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000599
Ben Murdoch589d6972011-11-30 16:04:58 +0000600bool Assembler::IsJalr(Instr instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000601 return GetOpcodeField(instr) == SPECIAL &&
602 GetRdField(instr) != 0 && GetFunctionField(instr) == JALR;
Ben Murdoch589d6972011-11-30 16:04:58 +0000603}
604
605
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000606bool Assembler::IsLui(Instr instr) {
607 uint32_t opcode = GetOpcodeField(instr);
608 // Checks if the instruction is a load upper immediate.
609 return opcode == LUI;
610}
611
612
613bool Assembler::IsOri(Instr instr) {
614 uint32_t opcode = GetOpcodeField(instr);
615 // Checks if the instruction is a load upper immediate.
616 return opcode == ORI;
617}
618
619
Steve Block44f0eee2011-05-26 01:26:41 +0100620bool Assembler::IsNop(Instr instr, unsigned int type) {
621 // See Assembler::nop(type).
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000622 DCHECK(type < 32);
Ben Murdoch257744e2011-11-30 15:57:28 +0000623 uint32_t opcode = GetOpcodeField(instr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000624 uint32_t function = GetFunctionField(instr);
Ben Murdoch257744e2011-11-30 15:57:28 +0000625 uint32_t rt = GetRt(instr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000626 uint32_t rd = GetRd(instr);
Ben Murdoch257744e2011-11-30 15:57:28 +0000627 uint32_t sa = GetSa(instr);
Steve Block44f0eee2011-05-26 01:26:41 +0100628
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000629 // Traditional mips nop == sll(zero_reg, zero_reg, 0)
630 // When marking non-zero type, use sll(zero_reg, at, type)
631 // to avoid use of mips ssnop and ehb special encodings
632 // of the sll instruction.
Steve Block44f0eee2011-05-26 01:26:41 +0100633
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000634 Register nop_rt_reg = (type == 0) ? zero_reg : at;
635 bool ret = (opcode == SPECIAL && function == SLL &&
636 rd == static_cast<uint32_t>(ToNumber(zero_reg)) &&
637 rt == static_cast<uint32_t>(ToNumber(nop_rt_reg)) &&
Steve Block44f0eee2011-05-26 01:26:41 +0100638 sa == type);
639
640 return ret;
641}
642
643
644int32_t Assembler::GetBranchOffset(Instr instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000645 DCHECK(IsBranch(instr));
646 return (static_cast<int16_t>(instr & kImm16Mask)) << 2;
Steve Block44f0eee2011-05-26 01:26:41 +0100647}
648
649
650bool Assembler::IsLw(Instr instr) {
Ben Murdoch014dc512016-03-22 12:00:34 +0000651 return (static_cast<uint32_t>(instr & kOpcodeMask) == LW);
Steve Block44f0eee2011-05-26 01:26:41 +0100652}
653
654
655int16_t Assembler::GetLwOffset(Instr instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000656 DCHECK(IsLw(instr));
Steve Block44f0eee2011-05-26 01:26:41 +0100657 return ((instr & kImm16Mask));
658}
659
660
661Instr Assembler::SetLwOffset(Instr instr, int16_t offset) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000662 DCHECK(IsLw(instr));
Steve Block44f0eee2011-05-26 01:26:41 +0100663
664 // We actually create a new lw instruction based on the original one.
665 Instr temp_instr = LW | (instr & kRsFieldMask) | (instr & kRtFieldMask)
666 | (offset & kImm16Mask);
667
668 return temp_instr;
669}
670
671
672bool Assembler::IsSw(Instr instr) {
Ben Murdoch014dc512016-03-22 12:00:34 +0000673 return (static_cast<uint32_t>(instr & kOpcodeMask) == SW);
Steve Block44f0eee2011-05-26 01:26:41 +0100674}
675
676
677Instr Assembler::SetSwOffset(Instr instr, int16_t offset) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000678 DCHECK(IsSw(instr));
Steve Block44f0eee2011-05-26 01:26:41 +0100679 return ((instr & ~kImm16Mask) | (offset & kImm16Mask));
680}
681
682
683bool Assembler::IsAddImmediate(Instr instr) {
684 return ((instr & kOpcodeMask) == ADDIU);
685}
686
687
688Instr Assembler::SetAddImmediateOffset(Instr instr, int16_t offset) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000689 DCHECK(IsAddImmediate(instr));
Steve Block44f0eee2011-05-26 01:26:41 +0100690 return ((instr & ~kImm16Mask) | (offset & kImm16Mask));
Andrei Popescu31002712010-02-23 13:46:05 +0000691}
692
693
Ben Murdoch257744e2011-11-30 15:57:28 +0000694bool Assembler::IsAndImmediate(Instr instr) {
695 return GetOpcodeField(instr) == ANDI;
696}
697
698
Ben Murdoch014dc512016-03-22 12:00:34 +0000699static Assembler::OffsetSize OffsetSizeInBits(Instr instr) {
700 if (IsMipsArchVariant(kMips32r6)) {
701 if (Assembler::IsBc(instr)) {
702 return Assembler::OffsetSize::kOffset26;
703 } else if (Assembler::IsBzc(instr)) {
704 return Assembler::OffsetSize::kOffset21;
705 }
706 }
707 return Assembler::OffsetSize::kOffset16;
708}
709
710
711static inline int32_t AddBranchOffset(int pos, Instr instr) {
712 int bits = OffsetSizeInBits(instr);
713 const int32_t mask = (1 << bits) - 1;
714 bits = 32 - bits;
715
716 // Do NOT change this to <<2. We rely on arithmetic shifts here, assuming
717 // the compiler uses arithmetic shifts for signed integers.
718 int32_t imm = ((instr & mask) << bits) >> (bits - 2);
719
720 if (imm == kEndOfChain) {
721 // EndOfChain sentinel is returned directly, not relative to pc or pos.
722 return kEndOfChain;
723 } else {
724 return pos + Assembler::kBranchPCOffset + imm;
725 }
726}
727
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100728uint32_t Assembler::CreateTargetAddress(Instr instr_lui, Instr instr_jic) {
729 DCHECK(IsLui(instr_lui) && IsJicOrJialc(instr_jic));
730 int16_t jic_offset = GetImmediate16(instr_jic);
731 int16_t lui_offset = GetImmediate16(instr_lui);
732
733 if (jic_offset < 0) {
734 lui_offset += kImm16Mask;
735 }
736 uint32_t lui_offset_u = (static_cast<uint32_t>(lui_offset)) << kLuiShift;
737 uint32_t jic_offset_u = static_cast<uint32_t>(jic_offset) & kImm16Mask;
738
739 return lui_offset_u | jic_offset_u;
740}
741
742// Use just lui and jic instructions. Insert lower part of the target address in
743// jic offset part. Since jic sign-extends offset and then add it with register,
744// before that addition, difference between upper part of the target address and
745// upper part of the sign-extended offset (0xffff or 0x0000), will be inserted
746// in jic register with lui instruction.
747void Assembler::UnpackTargetAddress(uint32_t address, int16_t& lui_offset,
748 int16_t& jic_offset) {
749 lui_offset = (address & kHiMask) >> kLuiShift;
750 jic_offset = address & kLoMask;
751
752 if (jic_offset < 0) {
753 lui_offset -= kImm16Mask;
754 }
755}
756
757void Assembler::UnpackTargetAddressUnsigned(uint32_t address,
758 uint32_t& lui_offset,
759 uint32_t& jic_offset) {
760 int16_t lui_offset16 = (address & kHiMask) >> kLuiShift;
761 int16_t jic_offset16 = address & kLoMask;
762
763 if (jic_offset16 < 0) {
764 lui_offset16 -= kImm16Mask;
765 }
766 lui_offset = static_cast<uint32_t>(lui_offset16) & kImm16Mask;
767 jic_offset = static_cast<uint32_t>(jic_offset16) & kImm16Mask;
768}
Ben Murdoch014dc512016-03-22 12:00:34 +0000769
770int Assembler::target_at(int pos, bool is_internal) {
Andrei Popescu31002712010-02-23 13:46:05 +0000771 Instr instr = instr_at(pos);
Ben Murdoch014dc512016-03-22 12:00:34 +0000772 if (is_internal) {
773 if (instr == 0) {
774 return kEndOfChain;
775 } else {
776 int32_t instr_address = reinterpret_cast<int32_t>(buffer_ + pos);
777 int delta = static_cast<int>(instr_address - instr);
778 DCHECK(pos > delta);
779 return pos - delta;
780 }
781 }
Andrei Popescu31002712010-02-23 13:46:05 +0000782 if ((instr & ~kImm16Mask) == 0) {
783 // Emitted label constant, not part of a branch.
Steve Block44f0eee2011-05-26 01:26:41 +0100784 if (instr == 0) {
785 return kEndOfChain;
786 } else {
787 int32_t imm18 =((instr & static_cast<int32_t>(kImm16Mask)) << 16) >> 14;
788 return (imm18 + pos);
789 }
Andrei Popescu31002712010-02-23 13:46:05 +0000790 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000791 // Check we have a branch or jump instruction.
Ben Murdoch014dc512016-03-22 12:00:34 +0000792 DCHECK(IsBranch(instr) || IsLui(instr));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000793 if (IsBranch(instr)) {
Ben Murdoch014dc512016-03-22 12:00:34 +0000794 return AddBranchOffset(pos, instr);
795 } else {
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100796 Instr instr1 = instr_at(pos + 0 * Assembler::kInstrSize);
797 Instr instr2 = instr_at(pos + 1 * Assembler::kInstrSize);
798 DCHECK(IsOri(instr2) || IsJicOrJialc(instr2));
799 int32_t imm;
800 if (IsJicOrJialc(instr2)) {
801 imm = CreateTargetAddress(instr1, instr2);
802 } else {
803 imm = (instr1 & static_cast<int32_t>(kImm16Mask)) << kLuiShift;
804 imm |= (instr2 & static_cast<int32_t>(kImm16Mask));
805 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000806
807 if (imm == kEndOfJumpChain) {
808 // EndOfChain sentinel is returned directly, not relative to pc or pos.
809 return kEndOfChain;
810 } else {
811 uint32_t instr_address = reinterpret_cast<int32_t>(buffer_ + pos);
812 int32_t delta = instr_address - imm;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000813 DCHECK(pos > delta);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000814 return pos - delta;
815 }
Steve Block44f0eee2011-05-26 01:26:41 +0100816 }
Ben Murdoch014dc512016-03-22 12:00:34 +0000817 return 0;
Andrei Popescu31002712010-02-23 13:46:05 +0000818}
819
820
Ben Murdoch014dc512016-03-22 12:00:34 +0000821static inline Instr SetBranchOffset(int32_t pos, int32_t target_pos,
822 Instr instr) {
823 int32_t bits = OffsetSizeInBits(instr);
824 int32_t imm = target_pos - (pos + Assembler::kBranchPCOffset);
825 DCHECK((imm & 3) == 0);
826 imm >>= 2;
827
828 const int32_t mask = (1 << bits) - 1;
829 instr &= ~mask;
830 DCHECK(is_intn(imm, bits));
831
832 return instr | (imm & mask);
833}
834
835
836void Assembler::target_at_put(int32_t pos, int32_t target_pos,
837 bool is_internal) {
Andrei Popescu31002712010-02-23 13:46:05 +0000838 Instr instr = instr_at(pos);
Ben Murdoch014dc512016-03-22 12:00:34 +0000839
840 if (is_internal) {
841 uint32_t imm = reinterpret_cast<uint32_t>(buffer_) + target_pos;
842 instr_at_put(pos, imm);
843 return;
844 }
Andrei Popescu31002712010-02-23 13:46:05 +0000845 if ((instr & ~kImm16Mask) == 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000846 DCHECK(target_pos == kEndOfChain || target_pos >= 0);
Andrei Popescu31002712010-02-23 13:46:05 +0000847 // Emitted label constant, not part of a branch.
848 // Make label relative to Code* of generated Code object.
849 instr_at_put(pos, target_pos + (Code::kHeaderSize - kHeapObjectTag));
850 return;
851 }
852
Ben Murdoch014dc512016-03-22 12:00:34 +0000853 DCHECK(IsBranch(instr) || IsLui(instr));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000854 if (IsBranch(instr)) {
Ben Murdoch014dc512016-03-22 12:00:34 +0000855 instr = SetBranchOffset(pos, target_pos, instr);
856 instr_at_put(pos, instr);
857 } else {
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100858 Instr instr1 = instr_at(pos + 0 * Assembler::kInstrSize);
859 Instr instr2 = instr_at(pos + 1 * Assembler::kInstrSize);
860 DCHECK(IsOri(instr2) || IsJicOrJialc(instr2));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000861 uint32_t imm = reinterpret_cast<uint32_t>(buffer_) + target_pos;
862 DCHECK((imm & 3) == 0);
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100863 DCHECK(IsLui(instr1) && (IsJicOrJialc(instr2) || IsOri(instr2)));
864 instr1 &= ~kImm16Mask;
865 instr2 &= ~kImm16Mask;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000866
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100867 if (IsJicOrJialc(instr2)) {
868 uint32_t lui_offset_u, jic_offset_u;
869 UnpackTargetAddressUnsigned(imm, lui_offset_u, jic_offset_u);
870 instr_at_put(pos + 0 * Assembler::kInstrSize, instr1 | lui_offset_u);
871 instr_at_put(pos + 1 * Assembler::kInstrSize, instr2 | jic_offset_u);
872 } else {
873 instr_at_put(pos + 0 * Assembler::kInstrSize,
874 instr1 | ((imm & kHiMask) >> kLuiShift));
875 instr_at_put(pos + 1 * Assembler::kInstrSize,
876 instr2 | (imm & kImm16Mask));
877 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000878 }
Andrei Popescu31002712010-02-23 13:46:05 +0000879}
880
881
882void Assembler::print(Label* L) {
883 if (L->is_unused()) {
884 PrintF("unused label\n");
885 } else if (L->is_bound()) {
886 PrintF("bound label to %d\n", L->pos());
887 } else if (L->is_linked()) {
888 Label l = *L;
889 PrintF("unbound label");
890 while (l.is_linked()) {
891 PrintF("@ %d ", l.pos());
892 Instr instr = instr_at(l.pos());
893 if ((instr & ~kImm16Mask) == 0) {
894 PrintF("value\n");
895 } else {
896 PrintF("%d\n", instr);
897 }
Ben Murdoch014dc512016-03-22 12:00:34 +0000898 next(&l, internal_reference_positions_.find(l.pos()) !=
899 internal_reference_positions_.end());
Andrei Popescu31002712010-02-23 13:46:05 +0000900 }
901 } else {
902 PrintF("label in inconsistent state (pos = %d)\n", L->pos_);
903 }
904}
905
906
907void Assembler::bind_to(Label* L, int pos) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000908 DCHECK(0 <= pos && pos <= pc_offset()); // Must have valid binding position.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000909 int32_t trampoline_pos = kInvalidSlotPos;
Ben Murdoch014dc512016-03-22 12:00:34 +0000910 bool is_internal = false;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000911 if (L->is_linked() && !trampoline_emitted_) {
912 unbound_labels_count_--;
913 next_buffer_check_ += kTrampolineSlotsSize;
914 }
915
Andrei Popescu31002712010-02-23 13:46:05 +0000916 while (L->is_linked()) {
917 int32_t fixup_pos = L->pos();
Steve Block44f0eee2011-05-26 01:26:41 +0100918 int32_t dist = pos - fixup_pos;
Ben Murdoch014dc512016-03-22 12:00:34 +0000919 is_internal = internal_reference_positions_.find(fixup_pos) !=
920 internal_reference_positions_.end();
921 next(L, is_internal); // Call next before overwriting link with target at
922 // fixup_pos.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000923 Instr instr = instr_at(fixup_pos);
Ben Murdoch014dc512016-03-22 12:00:34 +0000924 if (is_internal) {
925 target_at_put(fixup_pos, pos, is_internal);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000926 } else {
Ben Murdoch014dc512016-03-22 12:00:34 +0000927 if (IsBranch(instr)) {
928 int branch_offset = BranchOffset(instr);
929 if (dist > branch_offset) {
930 if (trampoline_pos == kInvalidSlotPos) {
931 trampoline_pos = get_trampoline_entry(fixup_pos);
932 CHECK(trampoline_pos != kInvalidSlotPos);
933 }
934 CHECK((trampoline_pos - fixup_pos) <= branch_offset);
935 target_at_put(fixup_pos, trampoline_pos, false);
936 fixup_pos = trampoline_pos;
937 dist = pos - fixup_pos;
938 }
939 target_at_put(fixup_pos, pos, false);
940 } else {
941 target_at_put(fixup_pos, pos, false);
942 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000943 }
Andrei Popescu31002712010-02-23 13:46:05 +0000944 }
945 L->bind_to(pos);
946
947 // Keep track of the last bound label so we don't eliminate any instructions
948 // before a bound label.
949 if (pos > last_bound_pos_)
950 last_bound_pos_ = pos;
951}
952
953
Andrei Popescu31002712010-02-23 13:46:05 +0000954void Assembler::bind(Label* L) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000955 DCHECK(!L->is_bound()); // Label can only be bound once.
Andrei Popescu31002712010-02-23 13:46:05 +0000956 bind_to(L, pc_offset());
957}
958
959
Ben Murdoch014dc512016-03-22 12:00:34 +0000960void Assembler::next(Label* L, bool is_internal) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000961 DCHECK(L->is_linked());
Ben Murdoch014dc512016-03-22 12:00:34 +0000962 int link = target_at(L->pos(), is_internal);
Steve Block44f0eee2011-05-26 01:26:41 +0100963 if (link == kEndOfChain) {
Andrei Popescu31002712010-02-23 13:46:05 +0000964 L->Unuse();
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000965 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000966 DCHECK(link >= 0);
Steve Block44f0eee2011-05-26 01:26:41 +0100967 L->link_to(link);
Andrei Popescu31002712010-02-23 13:46:05 +0000968 }
969}
970
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000971
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000972bool Assembler::is_near(Label* L) {
Ben Murdoch014dc512016-03-22 12:00:34 +0000973 DCHECK(L->is_bound());
974 return pc_offset() - L->pos() < kMaxBranchOffset - 4 * kInstrSize;
975}
976
977
978bool Assembler::is_near(Label* L, OffsetSize bits) {
979 if (L == nullptr || !L->is_bound()) return true;
980 return pc_offset() - L->pos() < (1 << (bits + 2 - 1)) - 1 - 5 * kInstrSize;
981}
982
983
984bool Assembler::is_near_branch(Label* L) {
985 DCHECK(L->is_bound());
986 return IsMipsArchVariant(kMips32r6) ? is_near_r6(L) : is_near_pre_r6(L);
987}
988
989
990int Assembler::BranchOffset(Instr instr) {
991 // At pre-R6 and for other R6 branches the offset is 16 bits.
992 int bits = OffsetSize::kOffset16;
993
994 if (IsMipsArchVariant(kMips32r6)) {
995 uint32_t opcode = GetOpcodeField(instr);
996 switch (opcode) {
997 // Checks BC or BALC.
998 case BC:
999 case BALC:
1000 bits = OffsetSize::kOffset26;
1001 break;
1002
1003 // Checks BEQZC or BNEZC.
1004 case POP66:
1005 case POP76:
1006 if (GetRsField(instr) != 0) bits = OffsetSize::kOffset21;
1007 break;
1008 default:
1009 break;
1010 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001011 }
Ben Murdoch014dc512016-03-22 12:00:34 +00001012
1013 return (1 << (bits + 2 - 1)) - 1;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001014}
Andrei Popescu31002712010-02-23 13:46:05 +00001015
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001016
Andrei Popescu31002712010-02-23 13:46:05 +00001017// We have to use a temporary register for things that can be relocated even
1018// if they can be encoded in the MIPS's 16 bits of immediate-offset instruction
1019// space. There is no guarantee that the relocated location can be similarly
1020// encoded.
Steve Block44f0eee2011-05-26 01:26:41 +01001021bool Assembler::MustUseReg(RelocInfo::Mode rmode) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001022 return !RelocInfo::IsNone(rmode);
Andrei Popescu31002712010-02-23 13:46:05 +00001023}
1024
Andrei Popescu31002712010-02-23 13:46:05 +00001025void Assembler::GenInstrRegister(Opcode opcode,
1026 Register rs,
1027 Register rt,
1028 Register rd,
1029 uint16_t sa,
1030 SecondaryField func) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001031 DCHECK(rd.is_valid() && rs.is_valid() && rt.is_valid() && is_uint5(sa));
Andrei Popescu31002712010-02-23 13:46:05 +00001032 Instr instr = opcode | (rs.code() << kRsShift) | (rt.code() << kRtShift)
1033 | (rd.code() << kRdShift) | (sa << kSaShift) | func;
1034 emit(instr);
1035}
1036
1037
1038void Assembler::GenInstrRegister(Opcode opcode,
Steve Block44f0eee2011-05-26 01:26:41 +01001039 Register rs,
1040 Register rt,
1041 uint16_t msb,
1042 uint16_t lsb,
1043 SecondaryField func) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001044 DCHECK(rs.is_valid() && rt.is_valid() && is_uint5(msb) && is_uint5(lsb));
Steve Block44f0eee2011-05-26 01:26:41 +01001045 Instr instr = opcode | (rs.code() << kRsShift) | (rt.code() << kRtShift)
1046 | (msb << kRdShift) | (lsb << kSaShift) | func;
1047 emit(instr);
1048}
1049
1050
1051void Assembler::GenInstrRegister(Opcode opcode,
Andrei Popescu31002712010-02-23 13:46:05 +00001052 SecondaryField fmt,
1053 FPURegister ft,
1054 FPURegister fs,
1055 FPURegister fd,
1056 SecondaryField func) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001057 DCHECK(fd.is_valid() && fs.is_valid() && ft.is_valid());
Steve Block44f0eee2011-05-26 01:26:41 +01001058 Instr instr = opcode | fmt | (ft.code() << kFtShift) | (fs.code() << kFsShift)
1059 | (fd.code() << kFdShift) | func;
Andrei Popescu31002712010-02-23 13:46:05 +00001060 emit(instr);
1061}
1062
1063
1064void Assembler::GenInstrRegister(Opcode opcode,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001065 FPURegister fr,
1066 FPURegister ft,
1067 FPURegister fs,
1068 FPURegister fd,
1069 SecondaryField func) {
1070 DCHECK(fd.is_valid() && fr.is_valid() && fs.is_valid() && ft.is_valid());
1071 Instr instr = opcode | (fr.code() << kFrShift) | (ft.code() << kFtShift)
1072 | (fs.code() << kFsShift) | (fd.code() << kFdShift) | func;
1073 emit(instr);
1074}
1075
1076
1077void Assembler::GenInstrRegister(Opcode opcode,
Andrei Popescu31002712010-02-23 13:46:05 +00001078 SecondaryField fmt,
1079 Register rt,
1080 FPURegister fs,
1081 FPURegister fd,
1082 SecondaryField func) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001083 DCHECK(fd.is_valid() && fs.is_valid() && rt.is_valid());
Andrei Popescu31002712010-02-23 13:46:05 +00001084 Instr instr = opcode | fmt | (rt.code() << kRtShift)
Steve Block44f0eee2011-05-26 01:26:41 +01001085 | (fs.code() << kFsShift) | (fd.code() << kFdShift) | func;
1086 emit(instr);
1087}
1088
1089
1090void Assembler::GenInstrRegister(Opcode opcode,
1091 SecondaryField fmt,
1092 Register rt,
1093 FPUControlRegister fs,
1094 SecondaryField func) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001095 DCHECK(fs.is_valid() && rt.is_valid());
Steve Block44f0eee2011-05-26 01:26:41 +01001096 Instr instr =
1097 opcode | fmt | (rt.code() << kRtShift) | (fs.code() << kFsShift) | func;
Andrei Popescu31002712010-02-23 13:46:05 +00001098 emit(instr);
1099}
1100
1101
1102// Instructions with immediate value.
1103// Registers are in the order of the instruction encoding, from left to right.
Ben Murdoch014dc512016-03-22 12:00:34 +00001104void Assembler::GenInstrImmediate(Opcode opcode, Register rs, Register rt,
1105 int32_t j,
1106 CompactBranchType is_compact_branch) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001107 DCHECK(rs.is_valid() && rt.is_valid() && (is_int16(j) || is_uint16(j)));
Andrei Popescu31002712010-02-23 13:46:05 +00001108 Instr instr = opcode | (rs.code() << kRsShift) | (rt.code() << kRtShift)
1109 | (j & kImm16Mask);
Ben Murdoch014dc512016-03-22 12:00:34 +00001110 emit(instr, is_compact_branch);
Andrei Popescu31002712010-02-23 13:46:05 +00001111}
1112
1113
Ben Murdoch014dc512016-03-22 12:00:34 +00001114void Assembler::GenInstrImmediate(Opcode opcode, Register rs, SecondaryField SF,
1115 int32_t j,
1116 CompactBranchType is_compact_branch) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001117 DCHECK(rs.is_valid() && (is_int16(j) || is_uint16(j)));
Andrei Popescu31002712010-02-23 13:46:05 +00001118 Instr instr = opcode | (rs.code() << kRsShift) | SF | (j & kImm16Mask);
Ben Murdoch014dc512016-03-22 12:00:34 +00001119 emit(instr, is_compact_branch);
Andrei Popescu31002712010-02-23 13:46:05 +00001120}
1121
1122
Ben Murdoch014dc512016-03-22 12:00:34 +00001123void Assembler::GenInstrImmediate(Opcode opcode, Register rs, FPURegister ft,
1124 int32_t j,
1125 CompactBranchType is_compact_branch) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001126 DCHECK(rs.is_valid() && ft.is_valid() && (is_int16(j) || is_uint16(j)));
Andrei Popescu31002712010-02-23 13:46:05 +00001127 Instr instr = opcode | (rs.code() << kRsShift) | (ft.code() << kFtShift)
1128 | (j & kImm16Mask);
Ben Murdoch014dc512016-03-22 12:00:34 +00001129 emit(instr, is_compact_branch);
1130}
1131
1132
1133void Assembler::GenInstrImmediate(Opcode opcode, Register rs, int32_t offset21,
1134 CompactBranchType is_compact_branch) {
1135 DCHECK(rs.is_valid() && (is_int21(offset21)));
1136 Instr instr = opcode | (rs.code() << kRsShift) | (offset21 & kImm21Mask);
1137 emit(instr, is_compact_branch);
1138}
1139
1140
1141void Assembler::GenInstrImmediate(Opcode opcode, Register rs,
1142 uint32_t offset21) {
1143 DCHECK(rs.is_valid() && (is_uint21(offset21)));
1144 Instr instr = opcode | (rs.code() << kRsShift) | (offset21 & kImm21Mask);
Andrei Popescu31002712010-02-23 13:46:05 +00001145 emit(instr);
1146}
1147
1148
Ben Murdoch014dc512016-03-22 12:00:34 +00001149void Assembler::GenInstrImmediate(Opcode opcode, int32_t offset26,
1150 CompactBranchType is_compact_branch) {
1151 DCHECK(is_int26(offset26));
1152 Instr instr = opcode | (offset26 & kImm26Mask);
1153 emit(instr, is_compact_branch);
1154}
1155
1156
Andrei Popescu31002712010-02-23 13:46:05 +00001157void Assembler::GenInstrJump(Opcode opcode,
Ben Murdoch589d6972011-11-30 16:04:58 +00001158 uint32_t address) {
Steve Block44f0eee2011-05-26 01:26:41 +01001159 BlockTrampolinePoolScope block_trampoline_pool(this);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001160 DCHECK(is_uint26(address));
Andrei Popescu31002712010-02-23 13:46:05 +00001161 Instr instr = opcode | address;
1162 emit(instr);
Steve Block44f0eee2011-05-26 01:26:41 +01001163 BlockTrampolinePoolFor(1); // For associated delay slot.
1164}
1165
1166
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001167// Returns the next free trampoline entry.
1168int32_t Assembler::get_trampoline_entry(int32_t pos) {
Ben Murdoch257744e2011-11-30 15:57:28 +00001169 int32_t trampoline_entry = kInvalidSlotPos;
Steve Block44f0eee2011-05-26 01:26:41 +01001170
Ben Murdoch257744e2011-11-30 15:57:28 +00001171 if (!internal_trampoline_exception_) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001172 if (trampoline_.start() > pos) {
1173 trampoline_entry = trampoline_.take_slot();
Steve Block44f0eee2011-05-26 01:26:41 +01001174 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001175
Ben Murdoch257744e2011-11-30 15:57:28 +00001176 if (kInvalidSlotPos == trampoline_entry) {
1177 internal_trampoline_exception_ = true;
Steve Block44f0eee2011-05-26 01:26:41 +01001178 }
1179 }
1180 return trampoline_entry;
Andrei Popescu31002712010-02-23 13:46:05 +00001181}
1182
1183
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001184uint32_t Assembler::jump_address(Label* L) {
Andrei Popescu31002712010-02-23 13:46:05 +00001185 int32_t target_pos;
Steve Block44f0eee2011-05-26 01:26:41 +01001186
Andrei Popescu31002712010-02-23 13:46:05 +00001187 if (L->is_bound()) {
1188 target_pos = L->pos();
1189 } else {
1190 if (L->is_linked()) {
Steve Block44f0eee2011-05-26 01:26:41 +01001191 target_pos = L->pos(); // L's link.
Steve Block44f0eee2011-05-26 01:26:41 +01001192 L->link_to(pc_offset());
Andrei Popescu31002712010-02-23 13:46:05 +00001193 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01001194 L->link_to(pc_offset());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001195 return kEndOfJumpChain;
1196 }
1197 }
1198
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001199 uint32_t imm = reinterpret_cast<uint32_t>(buffer_) + target_pos;
1200 DCHECK((imm & 3) == 0);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001201
1202 return imm;
1203}
1204
1205
Ben Murdoch014dc512016-03-22 12:00:34 +00001206int32_t Assembler::branch_offset_helper(Label* L, OffsetSize bits) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001207 int32_t target_pos;
Ben Murdoch014dc512016-03-22 12:00:34 +00001208 int32_t pad = IsPrevInstrCompactBranch() ? kInstrSize : 0;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001209
1210 if (L->is_bound()) {
1211 target_pos = L->pos();
1212 } else {
1213 if (L->is_linked()) {
1214 target_pos = L->pos();
Ben Murdoch014dc512016-03-22 12:00:34 +00001215 L->link_to(pc_offset() + pad);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001216 } else {
Ben Murdoch014dc512016-03-22 12:00:34 +00001217 L->link_to(pc_offset() + pad);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001218 if (!trampoline_emitted_) {
1219 unbound_labels_count_++;
1220 next_buffer_check_ -= kTrampolineSlotsSize;
1221 }
Steve Block44f0eee2011-05-26 01:26:41 +01001222 return kEndOfChain;
Andrei Popescu31002712010-02-23 13:46:05 +00001223 }
Andrei Popescu31002712010-02-23 13:46:05 +00001224 }
1225
Ben Murdoch014dc512016-03-22 12:00:34 +00001226 int32_t offset = target_pos - (pc_offset() + kBranchPCOffset + pad);
1227 DCHECK(is_intn(offset, bits + 2));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001228 DCHECK((offset & 3) == 0);
Steve Block44f0eee2011-05-26 01:26:41 +01001229
Andrei Popescu31002712010-02-23 13:46:05 +00001230 return offset;
1231}
1232
1233
1234void Assembler::label_at_put(Label* L, int at_offset) {
1235 int target_pos;
1236 if (L->is_bound()) {
1237 target_pos = L->pos();
Steve Block44f0eee2011-05-26 01:26:41 +01001238 instr_at_put(at_offset, target_pos + (Code::kHeaderSize - kHeapObjectTag));
Andrei Popescu31002712010-02-23 13:46:05 +00001239 } else {
1240 if (L->is_linked()) {
Steve Block44f0eee2011-05-26 01:26:41 +01001241 target_pos = L->pos(); // L's link.
1242 int32_t imm18 = target_pos - at_offset;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001243 DCHECK((imm18 & 3) == 0);
Steve Block44f0eee2011-05-26 01:26:41 +01001244 int32_t imm16 = imm18 >> 2;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001245 DCHECK(is_int16(imm16));
Steve Block44f0eee2011-05-26 01:26:41 +01001246 instr_at_put(at_offset, (imm16 & kImm16Mask));
Andrei Popescu31002712010-02-23 13:46:05 +00001247 } else {
1248 target_pos = kEndOfChain;
Steve Block44f0eee2011-05-26 01:26:41 +01001249 instr_at_put(at_offset, 0);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001250 if (!trampoline_emitted_) {
1251 unbound_labels_count_++;
1252 next_buffer_check_ -= kTrampolineSlotsSize;
1253 }
Andrei Popescu31002712010-02-23 13:46:05 +00001254 }
1255 L->link_to(at_offset);
Andrei Popescu31002712010-02-23 13:46:05 +00001256 }
1257}
1258
1259
1260//------- Branch and jump instructions --------
1261
1262void Assembler::b(int16_t offset) {
1263 beq(zero_reg, zero_reg, offset);
1264}
1265
1266
1267void Assembler::bal(int16_t offset) {
1268 bgezal(zero_reg, offset);
1269}
1270
1271
Ben Murdoch014dc512016-03-22 12:00:34 +00001272void Assembler::bc(int32_t offset) {
1273 DCHECK(IsMipsArchVariant(kMips32r6));
1274 GenInstrImmediate(BC, offset, CompactBranchType::COMPACT_BRANCH);
1275}
1276
1277
1278void Assembler::balc(int32_t offset) {
1279 DCHECK(IsMipsArchVariant(kMips32r6));
Ben Murdoch014dc512016-03-22 12:00:34 +00001280 GenInstrImmediate(BALC, offset, CompactBranchType::COMPACT_BRANCH);
1281}
1282
1283
Andrei Popescu31002712010-02-23 13:46:05 +00001284void Assembler::beq(Register rs, Register rt, int16_t offset) {
Steve Block44f0eee2011-05-26 01:26:41 +01001285 BlockTrampolinePoolScope block_trampoline_pool(this);
Andrei Popescu31002712010-02-23 13:46:05 +00001286 GenInstrImmediate(BEQ, rs, rt, offset);
Steve Block44f0eee2011-05-26 01:26:41 +01001287 BlockTrampolinePoolFor(1); // For associated delay slot.
Andrei Popescu31002712010-02-23 13:46:05 +00001288}
1289
1290
1291void Assembler::bgez(Register rs, int16_t offset) {
Steve Block44f0eee2011-05-26 01:26:41 +01001292 BlockTrampolinePoolScope block_trampoline_pool(this);
Andrei Popescu31002712010-02-23 13:46:05 +00001293 GenInstrImmediate(REGIMM, rs, BGEZ, offset);
Steve Block44f0eee2011-05-26 01:26:41 +01001294 BlockTrampolinePoolFor(1); // For associated delay slot.
Andrei Popescu31002712010-02-23 13:46:05 +00001295}
1296
1297
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001298void Assembler::bgezc(Register rt, int16_t offset) {
1299 DCHECK(IsMipsArchVariant(kMips32r6));
1300 DCHECK(!(rt.is(zero_reg)));
Ben Murdoch014dc512016-03-22 12:00:34 +00001301 GenInstrImmediate(BLEZL, rt, rt, offset, CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001302}
1303
1304
1305void Assembler::bgeuc(Register rs, Register rt, int16_t offset) {
1306 DCHECK(IsMipsArchVariant(kMips32r6));
1307 DCHECK(!(rs.is(zero_reg)));
1308 DCHECK(!(rt.is(zero_reg)));
1309 DCHECK(rs.code() != rt.code());
Ben Murdoch014dc512016-03-22 12:00:34 +00001310 GenInstrImmediate(BLEZ, rs, rt, offset, CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001311}
1312
1313
1314void Assembler::bgec(Register rs, Register rt, int16_t offset) {
1315 DCHECK(IsMipsArchVariant(kMips32r6));
1316 DCHECK(!(rs.is(zero_reg)));
1317 DCHECK(!(rt.is(zero_reg)));
1318 DCHECK(rs.code() != rt.code());
Ben Murdoch014dc512016-03-22 12:00:34 +00001319 GenInstrImmediate(BLEZL, rs, rt, offset, CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001320}
1321
1322
Andrei Popescu31002712010-02-23 13:46:05 +00001323void Assembler::bgezal(Register rs, int16_t offset) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001324 DCHECK(!IsMipsArchVariant(kMips32r6) || rs.is(zero_reg));
Steve Block44f0eee2011-05-26 01:26:41 +01001325 BlockTrampolinePoolScope block_trampoline_pool(this);
Andrei Popescu31002712010-02-23 13:46:05 +00001326 GenInstrImmediate(REGIMM, rs, BGEZAL, offset);
Steve Block44f0eee2011-05-26 01:26:41 +01001327 BlockTrampolinePoolFor(1); // For associated delay slot.
Andrei Popescu31002712010-02-23 13:46:05 +00001328}
1329
1330
1331void Assembler::bgtz(Register rs, int16_t offset) {
Steve Block44f0eee2011-05-26 01:26:41 +01001332 BlockTrampolinePoolScope block_trampoline_pool(this);
Andrei Popescu31002712010-02-23 13:46:05 +00001333 GenInstrImmediate(BGTZ, rs, zero_reg, offset);
Steve Block44f0eee2011-05-26 01:26:41 +01001334 BlockTrampolinePoolFor(1); // For associated delay slot.
Andrei Popescu31002712010-02-23 13:46:05 +00001335}
1336
1337
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001338void Assembler::bgtzc(Register rt, int16_t offset) {
1339 DCHECK(IsMipsArchVariant(kMips32r6));
1340 DCHECK(!(rt.is(zero_reg)));
Ben Murdoch014dc512016-03-22 12:00:34 +00001341 GenInstrImmediate(BGTZL, zero_reg, rt, offset,
1342 CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001343}
1344
1345
Andrei Popescu31002712010-02-23 13:46:05 +00001346void Assembler::blez(Register rs, int16_t offset) {
Steve Block44f0eee2011-05-26 01:26:41 +01001347 BlockTrampolinePoolScope block_trampoline_pool(this);
Andrei Popescu31002712010-02-23 13:46:05 +00001348 GenInstrImmediate(BLEZ, rs, zero_reg, offset);
Steve Block44f0eee2011-05-26 01:26:41 +01001349 BlockTrampolinePoolFor(1); // For associated delay slot.
Andrei Popescu31002712010-02-23 13:46:05 +00001350}
1351
1352
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001353void Assembler::blezc(Register rt, int16_t offset) {
1354 DCHECK(IsMipsArchVariant(kMips32r6));
1355 DCHECK(!(rt.is(zero_reg)));
Ben Murdoch014dc512016-03-22 12:00:34 +00001356 GenInstrImmediate(BLEZL, zero_reg, rt, offset,
1357 CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001358}
1359
1360
1361void Assembler::bltzc(Register rt, int16_t offset) {
1362 DCHECK(IsMipsArchVariant(kMips32r6));
Ben Murdoch014dc512016-03-22 12:00:34 +00001363 DCHECK(!rt.is(zero_reg));
1364 GenInstrImmediate(BGTZL, rt, rt, offset, CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001365}
1366
1367
1368void Assembler::bltuc(Register rs, Register rt, int16_t offset) {
1369 DCHECK(IsMipsArchVariant(kMips32r6));
1370 DCHECK(!(rs.is(zero_reg)));
1371 DCHECK(!(rt.is(zero_reg)));
1372 DCHECK(rs.code() != rt.code());
Ben Murdoch014dc512016-03-22 12:00:34 +00001373 GenInstrImmediate(BGTZ, rs, rt, offset, CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001374}
1375
1376
1377void Assembler::bltc(Register rs, Register rt, int16_t offset) {
1378 DCHECK(IsMipsArchVariant(kMips32r6));
Ben Murdoch014dc512016-03-22 12:00:34 +00001379 DCHECK(!rs.is(zero_reg));
1380 DCHECK(!rt.is(zero_reg));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001381 DCHECK(rs.code() != rt.code());
Ben Murdoch014dc512016-03-22 12:00:34 +00001382 GenInstrImmediate(BGTZL, rs, rt, offset, CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001383}
1384
1385
Andrei Popescu31002712010-02-23 13:46:05 +00001386void Assembler::bltz(Register rs, int16_t offset) {
Steve Block44f0eee2011-05-26 01:26:41 +01001387 BlockTrampolinePoolScope block_trampoline_pool(this);
Andrei Popescu31002712010-02-23 13:46:05 +00001388 GenInstrImmediate(REGIMM, rs, BLTZ, offset);
Steve Block44f0eee2011-05-26 01:26:41 +01001389 BlockTrampolinePoolFor(1); // For associated delay slot.
Andrei Popescu31002712010-02-23 13:46:05 +00001390}
1391
1392
1393void Assembler::bltzal(Register rs, int16_t offset) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001394 DCHECK(!IsMipsArchVariant(kMips32r6) || rs.is(zero_reg));
Steve Block44f0eee2011-05-26 01:26:41 +01001395 BlockTrampolinePoolScope block_trampoline_pool(this);
Andrei Popescu31002712010-02-23 13:46:05 +00001396 GenInstrImmediate(REGIMM, rs, BLTZAL, offset);
Steve Block44f0eee2011-05-26 01:26:41 +01001397 BlockTrampolinePoolFor(1); // For associated delay slot.
Andrei Popescu31002712010-02-23 13:46:05 +00001398}
1399
1400
1401void Assembler::bne(Register rs, Register rt, int16_t offset) {
Steve Block44f0eee2011-05-26 01:26:41 +01001402 BlockTrampolinePoolScope block_trampoline_pool(this);
Andrei Popescu31002712010-02-23 13:46:05 +00001403 GenInstrImmediate(BNE, rs, rt, offset);
Steve Block44f0eee2011-05-26 01:26:41 +01001404 BlockTrampolinePoolFor(1); // For associated delay slot.
Andrei Popescu31002712010-02-23 13:46:05 +00001405}
1406
1407
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001408void Assembler::bovc(Register rs, Register rt, int16_t offset) {
1409 DCHECK(IsMipsArchVariant(kMips32r6));
Ben Murdoch014dc512016-03-22 12:00:34 +00001410 if (rs.code() >= rt.code()) {
1411 GenInstrImmediate(ADDI, rs, rt, offset, CompactBranchType::COMPACT_BRANCH);
1412 } else {
1413 GenInstrImmediate(ADDI, rt, rs, offset, CompactBranchType::COMPACT_BRANCH);
1414 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001415}
1416
1417
1418void Assembler::bnvc(Register rs, Register rt, int16_t offset) {
1419 DCHECK(IsMipsArchVariant(kMips32r6));
Ben Murdoch014dc512016-03-22 12:00:34 +00001420 if (rs.code() >= rt.code()) {
1421 GenInstrImmediate(DADDI, rs, rt, offset, CompactBranchType::COMPACT_BRANCH);
1422 } else {
1423 GenInstrImmediate(DADDI, rt, rs, offset, CompactBranchType::COMPACT_BRANCH);
1424 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001425}
1426
1427
1428void Assembler::blezalc(Register rt, int16_t offset) {
1429 DCHECK(IsMipsArchVariant(kMips32r6));
1430 DCHECK(!(rt.is(zero_reg)));
Ben Murdoch014dc512016-03-22 12:00:34 +00001431 GenInstrImmediate(BLEZ, zero_reg, rt, offset,
1432 CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001433}
1434
1435
1436void Assembler::bgezalc(Register rt, int16_t offset) {
1437 DCHECK(IsMipsArchVariant(kMips32r6));
1438 DCHECK(!(rt.is(zero_reg)));
Ben Murdoch014dc512016-03-22 12:00:34 +00001439 GenInstrImmediate(BLEZ, rt, rt, offset, CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001440}
1441
1442
1443void Assembler::bgezall(Register rs, int16_t offset) {
Ben Murdoch014dc512016-03-22 12:00:34 +00001444 DCHECK(!IsMipsArchVariant(kMips32r6));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001445 DCHECK(!(rs.is(zero_reg)));
Ben Murdoch014dc512016-03-22 12:00:34 +00001446 BlockTrampolinePoolScope block_trampoline_pool(this);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001447 GenInstrImmediate(REGIMM, rs, BGEZALL, offset);
Ben Murdoch014dc512016-03-22 12:00:34 +00001448 BlockTrampolinePoolFor(1); // For associated delay slot.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001449}
1450
1451
1452void Assembler::bltzalc(Register rt, int16_t offset) {
1453 DCHECK(IsMipsArchVariant(kMips32r6));
1454 DCHECK(!(rt.is(zero_reg)));
Ben Murdoch014dc512016-03-22 12:00:34 +00001455 GenInstrImmediate(BGTZ, rt, rt, offset, CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001456}
1457
1458
1459void Assembler::bgtzalc(Register rt, int16_t offset) {
1460 DCHECK(IsMipsArchVariant(kMips32r6));
1461 DCHECK(!(rt.is(zero_reg)));
Ben Murdoch014dc512016-03-22 12:00:34 +00001462 GenInstrImmediate(BGTZ, zero_reg, rt, offset,
1463 CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001464}
1465
1466
1467void Assembler::beqzalc(Register rt, int16_t offset) {
1468 DCHECK(IsMipsArchVariant(kMips32r6));
1469 DCHECK(!(rt.is(zero_reg)));
Ben Murdoch014dc512016-03-22 12:00:34 +00001470 GenInstrImmediate(ADDI, zero_reg, rt, offset,
1471 CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001472}
1473
1474
1475void Assembler::bnezalc(Register rt, int16_t offset) {
1476 DCHECK(IsMipsArchVariant(kMips32r6));
1477 DCHECK(!(rt.is(zero_reg)));
Ben Murdoch014dc512016-03-22 12:00:34 +00001478 GenInstrImmediate(DADDI, zero_reg, rt, offset,
1479 CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001480}
1481
1482
1483void Assembler::beqc(Register rs, Register rt, int16_t offset) {
1484 DCHECK(IsMipsArchVariant(kMips32r6));
Ben Murdoch014dc512016-03-22 12:00:34 +00001485 DCHECK(rs.code() != rt.code() && rs.code() != 0 && rt.code() != 0);
1486 if (rs.code() < rt.code()) {
1487 GenInstrImmediate(ADDI, rs, rt, offset, CompactBranchType::COMPACT_BRANCH);
1488 } else {
1489 GenInstrImmediate(ADDI, rt, rs, offset, CompactBranchType::COMPACT_BRANCH);
1490 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001491}
1492
1493
1494void Assembler::beqzc(Register rs, int32_t offset) {
1495 DCHECK(IsMipsArchVariant(kMips32r6));
1496 DCHECK(!(rs.is(zero_reg)));
Ben Murdoch014dc512016-03-22 12:00:34 +00001497 GenInstrImmediate(POP66, rs, offset, CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001498}
1499
1500
1501void Assembler::bnec(Register rs, Register rt, int16_t offset) {
1502 DCHECK(IsMipsArchVariant(kMips32r6));
Ben Murdoch014dc512016-03-22 12:00:34 +00001503 DCHECK(rs.code() != rt.code() && rs.code() != 0 && rt.code() != 0);
1504 if (rs.code() < rt.code()) {
1505 GenInstrImmediate(DADDI, rs, rt, offset, CompactBranchType::COMPACT_BRANCH);
1506 } else {
1507 GenInstrImmediate(DADDI, rt, rs, offset, CompactBranchType::COMPACT_BRANCH);
1508 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001509}
1510
1511
1512void Assembler::bnezc(Register rs, int32_t offset) {
1513 DCHECK(IsMipsArchVariant(kMips32r6));
1514 DCHECK(!(rs.is(zero_reg)));
Ben Murdoch014dc512016-03-22 12:00:34 +00001515 GenInstrImmediate(POP76, rs, offset, CompactBranchType::COMPACT_BRANCH);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001516}
1517
1518
Andrei Popescu31002712010-02-23 13:46:05 +00001519void Assembler::j(int32_t target) {
Ben Murdoch589d6972011-11-30 16:04:58 +00001520#if DEBUG
1521 // Get pc of delay slot.
1522 uint32_t ipc = reinterpret_cast<uint32_t>(pc_ + 1 * kInstrSize);
Ben Murdoch014dc512016-03-22 12:00:34 +00001523 bool in_range = ((ipc ^ static_cast<uint32_t>(target)) >>
1524 (kImm26Bits + kImmFieldShift)) == 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001525 DCHECK(in_range && ((target & 3) == 0));
Ben Murdoch589d6972011-11-30 16:04:58 +00001526#endif
Ben Murdoch014dc512016-03-22 12:00:34 +00001527 BlockTrampolinePoolScope block_trampoline_pool(this);
1528 GenInstrJump(J, (target >> 2) & kImm26Mask);
1529 BlockTrampolinePoolFor(1); // For associated delay slot.
Andrei Popescu31002712010-02-23 13:46:05 +00001530}
1531
1532
1533void Assembler::jr(Register rs) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001534 if (!IsMipsArchVariant(kMips32r6)) {
1535 BlockTrampolinePoolScope block_trampoline_pool(this);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001536 GenInstrRegister(SPECIAL, rs, zero_reg, zero_reg, 0, JR);
1537 BlockTrampolinePoolFor(1); // For associated delay slot.
1538 } else {
1539 jalr(rs, zero_reg);
Steve Block44f0eee2011-05-26 01:26:41 +01001540 }
Andrei Popescu31002712010-02-23 13:46:05 +00001541}
1542
1543
1544void Assembler::jal(int32_t target) {
Ben Murdoch589d6972011-11-30 16:04:58 +00001545#ifdef DEBUG
1546 // Get pc of delay slot.
1547 uint32_t ipc = reinterpret_cast<uint32_t>(pc_ + 1 * kInstrSize);
Ben Murdoch014dc512016-03-22 12:00:34 +00001548 bool in_range = ((ipc ^ static_cast<uint32_t>(target)) >>
1549 (kImm26Bits + kImmFieldShift)) == 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001550 DCHECK(in_range && ((target & 3) == 0));
Ben Murdoch589d6972011-11-30 16:04:58 +00001551#endif
Ben Murdoch014dc512016-03-22 12:00:34 +00001552 BlockTrampolinePoolScope block_trampoline_pool(this);
Ben Murdoch014dc512016-03-22 12:00:34 +00001553 GenInstrJump(JAL, (target >> 2) & kImm26Mask);
1554 BlockTrampolinePoolFor(1); // For associated delay slot.
Andrei Popescu31002712010-02-23 13:46:05 +00001555}
1556
1557
1558void Assembler::jalr(Register rs, Register rd) {
Ben Murdoch014dc512016-03-22 12:00:34 +00001559 DCHECK(rs.code() != rd.code());
Steve Block44f0eee2011-05-26 01:26:41 +01001560 BlockTrampolinePoolScope block_trampoline_pool(this);
Andrei Popescu31002712010-02-23 13:46:05 +00001561 GenInstrRegister(SPECIAL, rs, zero_reg, rd, 0, JALR);
Steve Block44f0eee2011-05-26 01:26:41 +01001562 BlockTrampolinePoolFor(1); // For associated delay slot.
Andrei Popescu31002712010-02-23 13:46:05 +00001563}
1564
1565
Ben Murdoch014dc512016-03-22 12:00:34 +00001566void Assembler::jic(Register rt, int16_t offset) {
1567 DCHECK(IsMipsArchVariant(kMips32r6));
1568 GenInstrImmediate(POP66, zero_reg, rt, offset);
Ben Murdoch589d6972011-11-30 16:04:58 +00001569}
1570
1571
Ben Murdoch014dc512016-03-22 12:00:34 +00001572void Assembler::jialc(Register rt, int16_t offset) {
1573 DCHECK(IsMipsArchVariant(kMips32r6));
Ben Murdoch014dc512016-03-22 12:00:34 +00001574 GenInstrImmediate(POP76, zero_reg, rt, offset);
Ben Murdoch589d6972011-11-30 16:04:58 +00001575}
1576
1577
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001578// -------Data-processing-instructions---------
Andrei Popescu31002712010-02-23 13:46:05 +00001579
1580// Arithmetic.
1581
Andrei Popescu31002712010-02-23 13:46:05 +00001582void Assembler::addu(Register rd, Register rs, Register rt) {
1583 GenInstrRegister(SPECIAL, rs, rt, rd, 0, ADDU);
1584}
1585
1586
Andrei Popescu31002712010-02-23 13:46:05 +00001587void Assembler::addiu(Register rd, Register rs, int32_t j) {
1588 GenInstrImmediate(ADDIU, rs, rd, j);
Andrei Popescu31002712010-02-23 13:46:05 +00001589}
1590
1591
1592void Assembler::subu(Register rd, Register rs, Register rt) {
1593 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SUBU);
1594}
1595
1596
1597void Assembler::mul(Register rd, Register rs, Register rt) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001598 if (!IsMipsArchVariant(kMips32r6)) {
1599 GenInstrRegister(SPECIAL2, rs, rt, rd, 0, MUL);
1600 } else {
1601 GenInstrRegister(SPECIAL, rs, rt, rd, MUL_OP, MUL_MUH);
1602 }
1603}
1604
1605
1606void Assembler::mulu(Register rd, Register rs, Register rt) {
1607 DCHECK(IsMipsArchVariant(kMips32r6));
1608 GenInstrRegister(SPECIAL, rs, rt, rd, MUL_OP, MUL_MUH_U);
1609}
1610
1611
1612void Assembler::muh(Register rd, Register rs, Register rt) {
1613 DCHECK(IsMipsArchVariant(kMips32r6));
1614 GenInstrRegister(SPECIAL, rs, rt, rd, MUH_OP, MUL_MUH);
1615}
1616
1617
1618void Assembler::muhu(Register rd, Register rs, Register rt) {
1619 DCHECK(IsMipsArchVariant(kMips32r6));
1620 GenInstrRegister(SPECIAL, rs, rt, rd, MUH_OP, MUL_MUH_U);
1621}
1622
1623
1624void Assembler::mod(Register rd, Register rs, Register rt) {
1625 DCHECK(IsMipsArchVariant(kMips32r6));
1626 GenInstrRegister(SPECIAL, rs, rt, rd, MOD_OP, DIV_MOD);
1627}
1628
1629
1630void Assembler::modu(Register rd, Register rs, Register rt) {
1631 DCHECK(IsMipsArchVariant(kMips32r6));
1632 GenInstrRegister(SPECIAL, rs, rt, rd, MOD_OP, DIV_MOD_U);
Andrei Popescu31002712010-02-23 13:46:05 +00001633}
1634
1635
1636void Assembler::mult(Register rs, Register rt) {
1637 GenInstrRegister(SPECIAL, rs, rt, zero_reg, 0, MULT);
1638}
1639
1640
1641void Assembler::multu(Register rs, Register rt) {
1642 GenInstrRegister(SPECIAL, rs, rt, zero_reg, 0, MULTU);
1643}
1644
1645
1646void Assembler::div(Register rs, Register rt) {
1647 GenInstrRegister(SPECIAL, rs, rt, zero_reg, 0, DIV);
1648}
1649
1650
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001651void Assembler::div(Register rd, Register rs, Register rt) {
1652 DCHECK(IsMipsArchVariant(kMips32r6));
1653 GenInstrRegister(SPECIAL, rs, rt, rd, DIV_OP, DIV_MOD);
1654}
1655
1656
Andrei Popescu31002712010-02-23 13:46:05 +00001657void Assembler::divu(Register rs, Register rt) {
1658 GenInstrRegister(SPECIAL, rs, rt, zero_reg, 0, DIVU);
1659}
1660
1661
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001662void Assembler::divu(Register rd, Register rs, Register rt) {
1663 DCHECK(IsMipsArchVariant(kMips32r6));
1664 GenInstrRegister(SPECIAL, rs, rt, rd, DIV_OP, DIV_MOD_U);
1665}
1666
1667
Andrei Popescu31002712010-02-23 13:46:05 +00001668// Logical.
1669
1670void Assembler::and_(Register rd, Register rs, Register rt) {
1671 GenInstrRegister(SPECIAL, rs, rt, rd, 0, AND);
1672}
1673
1674
1675void Assembler::andi(Register rt, Register rs, int32_t j) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001676 DCHECK(is_uint16(j));
Andrei Popescu31002712010-02-23 13:46:05 +00001677 GenInstrImmediate(ANDI, rs, rt, j);
1678}
1679
1680
1681void Assembler::or_(Register rd, Register rs, Register rt) {
1682 GenInstrRegister(SPECIAL, rs, rt, rd, 0, OR);
1683}
1684
1685
1686void Assembler::ori(Register rt, Register rs, int32_t j) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001687 DCHECK(is_uint16(j));
Andrei Popescu31002712010-02-23 13:46:05 +00001688 GenInstrImmediate(ORI, rs, rt, j);
1689}
1690
1691
1692void Assembler::xor_(Register rd, Register rs, Register rt) {
1693 GenInstrRegister(SPECIAL, rs, rt, rd, 0, XOR);
1694}
1695
1696
1697void Assembler::xori(Register rt, Register rs, int32_t j) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001698 DCHECK(is_uint16(j));
Andrei Popescu31002712010-02-23 13:46:05 +00001699 GenInstrImmediate(XORI, rs, rt, j);
1700}
1701
1702
1703void Assembler::nor(Register rd, Register rs, Register rt) {
1704 GenInstrRegister(SPECIAL, rs, rt, rd, 0, NOR);
1705}
1706
1707
1708// Shifts.
Steve Block44f0eee2011-05-26 01:26:41 +01001709void Assembler::sll(Register rd,
1710 Register rt,
1711 uint16_t sa,
1712 bool coming_from_nop) {
1713 // Don't allow nop instructions in the form sll zero_reg, zero_reg to be
1714 // generated using the sll instruction. They must be generated using
1715 // nop(int/NopMarkerTypes) or MarkCode(int/NopMarkerTypes) pseudo
1716 // instructions.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001717 DCHECK(coming_from_nop || !(rd.is(zero_reg) && rt.is(zero_reg)));
Ben Murdoch014dc512016-03-22 12:00:34 +00001718 GenInstrRegister(SPECIAL, zero_reg, rt, rd, sa & 0x1F, SLL);
Andrei Popescu31002712010-02-23 13:46:05 +00001719}
1720
1721
1722void Assembler::sllv(Register rd, Register rt, Register rs) {
1723 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SLLV);
1724}
1725
1726
1727void Assembler::srl(Register rd, Register rt, uint16_t sa) {
Ben Murdoch014dc512016-03-22 12:00:34 +00001728 GenInstrRegister(SPECIAL, zero_reg, rt, rd, sa & 0x1F, SRL);
Andrei Popescu31002712010-02-23 13:46:05 +00001729}
1730
1731
1732void Assembler::srlv(Register rd, Register rt, Register rs) {
1733 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SRLV);
1734}
1735
1736
1737void Assembler::sra(Register rd, Register rt, uint16_t sa) {
Ben Murdoch014dc512016-03-22 12:00:34 +00001738 GenInstrRegister(SPECIAL, zero_reg, rt, rd, sa & 0x1F, SRA);
Andrei Popescu31002712010-02-23 13:46:05 +00001739}
1740
1741
1742void Assembler::srav(Register rd, Register rt, Register rs) {
1743 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SRAV);
1744}
1745
1746
Steve Block44f0eee2011-05-26 01:26:41 +01001747void Assembler::rotr(Register rd, Register rt, uint16_t sa) {
1748 // Should be called via MacroAssembler::Ror.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001749 DCHECK(rd.is_valid() && rt.is_valid() && is_uint5(sa));
Ben Murdoch014dc512016-03-22 12:00:34 +00001750 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
Steve Block44f0eee2011-05-26 01:26:41 +01001751 Instr instr = SPECIAL | (1 << kRsShift) | (rt.code() << kRtShift)
1752 | (rd.code() << kRdShift) | (sa << kSaShift) | SRL;
1753 emit(instr);
1754}
1755
1756
1757void Assembler::rotrv(Register rd, Register rt, Register rs) {
1758 // Should be called via MacroAssembler::Ror.
Ben Murdoch014dc512016-03-22 12:00:34 +00001759 DCHECK(rd.is_valid() && rt.is_valid() && rs.is_valid());
1760 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
Steve Block44f0eee2011-05-26 01:26:41 +01001761 Instr instr = SPECIAL | (rs.code() << kRsShift) | (rt.code() << kRtShift)
1762 | (rd.code() << kRdShift) | (1 << kSaShift) | SRLV;
1763 emit(instr);
1764}
1765
1766
Ben Murdoch014dc512016-03-22 12:00:34 +00001767void Assembler::lsa(Register rd, Register rt, Register rs, uint8_t sa) {
1768 DCHECK(rd.is_valid() && rt.is_valid() && rs.is_valid());
Ben Murdoch3b9bc312016-06-02 14:46:10 +01001769 DCHECK(sa <= 3);
Ben Murdoch014dc512016-03-22 12:00:34 +00001770 DCHECK(IsMipsArchVariant(kMips32r6));
Ben Murdoch3b9bc312016-06-02 14:46:10 +01001771 Instr instr = SPECIAL | rs.code() << kRsShift | rt.code() << kRtShift |
1772 rd.code() << kRdShift | sa << kSaShift | LSA;
Ben Murdoch014dc512016-03-22 12:00:34 +00001773 emit(instr);
1774}
1775
1776
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001777// ------------Memory-instructions-------------
Andrei Popescu31002712010-02-23 13:46:05 +00001778
Steve Block44f0eee2011-05-26 01:26:41 +01001779// Helper for base-reg + offset, when offset is larger than int16.
1780void Assembler::LoadRegPlusOffsetToAt(const MemOperand& src) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001781 DCHECK(!src.rm().is(at));
1782 lui(at, (src.offset_ >> kLuiShift) & kImm16Mask);
Steve Block44f0eee2011-05-26 01:26:41 +01001783 ori(at, at, src.offset_ & kImm16Mask); // Load 32-bit offset.
1784 addu(at, at, src.rm()); // Add base register.
1785}
1786
1787
Andrei Popescu31002712010-02-23 13:46:05 +00001788void Assembler::lb(Register rd, const MemOperand& rs) {
Steve Block44f0eee2011-05-26 01:26:41 +01001789 if (is_int16(rs.offset_)) {
1790 GenInstrImmediate(LB, rs.rm(), rd, rs.offset_);
1791 } else { // Offset > 16 bits, use multiple instructions to load.
1792 LoadRegPlusOffsetToAt(rs);
1793 GenInstrImmediate(LB, at, rd, 0); // Equiv to lb(rd, MemOperand(at, 0));
1794 }
Andrei Popescu31002712010-02-23 13:46:05 +00001795}
1796
1797
1798void Assembler::lbu(Register rd, const MemOperand& rs) {
Steve Block44f0eee2011-05-26 01:26:41 +01001799 if (is_int16(rs.offset_)) {
1800 GenInstrImmediate(LBU, rs.rm(), rd, rs.offset_);
1801 } else { // Offset > 16 bits, use multiple instructions to load.
1802 LoadRegPlusOffsetToAt(rs);
1803 GenInstrImmediate(LBU, at, rd, 0); // Equiv to lbu(rd, MemOperand(at, 0));
1804 }
1805}
1806
1807
1808void Assembler::lh(Register rd, const MemOperand& rs) {
1809 if (is_int16(rs.offset_)) {
1810 GenInstrImmediate(LH, rs.rm(), rd, rs.offset_);
1811 } else { // Offset > 16 bits, use multiple instructions to load.
1812 LoadRegPlusOffsetToAt(rs);
1813 GenInstrImmediate(LH, at, rd, 0); // Equiv to lh(rd, MemOperand(at, 0));
1814 }
1815}
1816
1817
1818void Assembler::lhu(Register rd, const MemOperand& rs) {
1819 if (is_int16(rs.offset_)) {
1820 GenInstrImmediate(LHU, rs.rm(), rd, rs.offset_);
1821 } else { // Offset > 16 bits, use multiple instructions to load.
1822 LoadRegPlusOffsetToAt(rs);
1823 GenInstrImmediate(LHU, at, rd, 0); // Equiv to lhu(rd, MemOperand(at, 0));
1824 }
Andrei Popescu31002712010-02-23 13:46:05 +00001825}
1826
1827
1828void Assembler::lw(Register rd, const MemOperand& rs) {
Steve Block44f0eee2011-05-26 01:26:41 +01001829 if (is_int16(rs.offset_)) {
1830 GenInstrImmediate(LW, rs.rm(), rd, rs.offset_);
1831 } else { // Offset > 16 bits, use multiple instructions to load.
1832 LoadRegPlusOffsetToAt(rs);
1833 GenInstrImmediate(LW, at, rd, 0); // Equiv to lw(rd, MemOperand(at, 0));
1834 }
Steve Block44f0eee2011-05-26 01:26:41 +01001835}
1836
1837
1838void Assembler::lwl(Register rd, const MemOperand& rs) {
Ben Murdochbcf72ee2016-08-08 18:44:38 +01001839 DCHECK(is_int16(rs.offset_));
1840 DCHECK(IsMipsArchVariant(kLoongson) || IsMipsArchVariant(kMips32r1) ||
1841 IsMipsArchVariant(kMips32r2));
Steve Block44f0eee2011-05-26 01:26:41 +01001842 GenInstrImmediate(LWL, rs.rm(), rd, rs.offset_);
1843}
1844
1845
1846void Assembler::lwr(Register rd, const MemOperand& rs) {
Ben Murdochbcf72ee2016-08-08 18:44:38 +01001847 DCHECK(is_int16(rs.offset_));
1848 DCHECK(IsMipsArchVariant(kLoongson) || IsMipsArchVariant(kMips32r1) ||
1849 IsMipsArchVariant(kMips32r2));
Steve Block44f0eee2011-05-26 01:26:41 +01001850 GenInstrImmediate(LWR, rs.rm(), rd, rs.offset_);
Andrei Popescu31002712010-02-23 13:46:05 +00001851}
1852
1853
1854void Assembler::sb(Register rd, const MemOperand& rs) {
Steve Block44f0eee2011-05-26 01:26:41 +01001855 if (is_int16(rs.offset_)) {
1856 GenInstrImmediate(SB, rs.rm(), rd, rs.offset_);
1857 } else { // Offset > 16 bits, use multiple instructions to store.
1858 LoadRegPlusOffsetToAt(rs);
1859 GenInstrImmediate(SB, at, rd, 0); // Equiv to sb(rd, MemOperand(at, 0));
1860 }
1861}
1862
1863
1864void Assembler::sh(Register rd, const MemOperand& rs) {
1865 if (is_int16(rs.offset_)) {
1866 GenInstrImmediate(SH, rs.rm(), rd, rs.offset_);
1867 } else { // Offset > 16 bits, use multiple instructions to store.
1868 LoadRegPlusOffsetToAt(rs);
1869 GenInstrImmediate(SH, at, rd, 0); // Equiv to sh(rd, MemOperand(at, 0));
1870 }
Andrei Popescu31002712010-02-23 13:46:05 +00001871}
1872
1873
1874void Assembler::sw(Register rd, const MemOperand& rs) {
Steve Block44f0eee2011-05-26 01:26:41 +01001875 if (is_int16(rs.offset_)) {
1876 GenInstrImmediate(SW, rs.rm(), rd, rs.offset_);
1877 } else { // Offset > 16 bits, use multiple instructions to store.
1878 LoadRegPlusOffsetToAt(rs);
1879 GenInstrImmediate(SW, at, rd, 0); // Equiv to sw(rd, MemOperand(at, 0));
1880 }
Steve Block44f0eee2011-05-26 01:26:41 +01001881}
1882
1883
1884void Assembler::swl(Register rd, const MemOperand& rs) {
Ben Murdochbcf72ee2016-08-08 18:44:38 +01001885 DCHECK(is_int16(rs.offset_));
1886 DCHECK(IsMipsArchVariant(kLoongson) || IsMipsArchVariant(kMips32r1) ||
1887 IsMipsArchVariant(kMips32r2));
Steve Block44f0eee2011-05-26 01:26:41 +01001888 GenInstrImmediate(SWL, rs.rm(), rd, rs.offset_);
1889}
1890
1891
1892void Assembler::swr(Register rd, const MemOperand& rs) {
Ben Murdochbcf72ee2016-08-08 18:44:38 +01001893 DCHECK(is_int16(rs.offset_));
1894 DCHECK(IsMipsArchVariant(kLoongson) || IsMipsArchVariant(kMips32r1) ||
1895 IsMipsArchVariant(kMips32r2));
Steve Block44f0eee2011-05-26 01:26:41 +01001896 GenInstrImmediate(SWR, rs.rm(), rd, rs.offset_);
Andrei Popescu31002712010-02-23 13:46:05 +00001897}
1898
1899
1900void Assembler::lui(Register rd, int32_t j) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001901 DCHECK(is_uint16(j));
Andrei Popescu31002712010-02-23 13:46:05 +00001902 GenInstrImmediate(LUI, zero_reg, rd, j);
1903}
1904
1905
Ben Murdoch014dc512016-03-22 12:00:34 +00001906void Assembler::aui(Register rt, Register rs, int32_t j) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001907 // This instruction uses same opcode as 'lui'. The difference in encoding is
1908 // 'lui' has zero reg. for rs field.
Ben Murdoch014dc512016-03-22 12:00:34 +00001909 DCHECK(!(rs.is(zero_reg)));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001910 DCHECK(is_uint16(j));
1911 GenInstrImmediate(LUI, rs, rt, j);
1912}
1913
Ben Murdoch014dc512016-03-22 12:00:34 +00001914// ---------PC-Relative instructions-----------
1915
1916void Assembler::addiupc(Register rs, int32_t imm19) {
1917 DCHECK(IsMipsArchVariant(kMips32r6));
1918 DCHECK(rs.is_valid() && is_int19(imm19));
1919 uint32_t imm21 = ADDIUPC << kImm19Bits | (imm19 & kImm19Mask);
1920 GenInstrImmediate(PCREL, rs, imm21);
1921}
1922
1923
1924void Assembler::lwpc(Register rs, int32_t offset19) {
1925 DCHECK(IsMipsArchVariant(kMips32r6));
1926 DCHECK(rs.is_valid() && is_int19(offset19));
1927 uint32_t imm21 = LWPC << kImm19Bits | (offset19 & kImm19Mask);
1928 GenInstrImmediate(PCREL, rs, imm21);
1929}
1930
1931
1932void Assembler::auipc(Register rs, int16_t imm16) {
1933 DCHECK(IsMipsArchVariant(kMips32r6));
1934 DCHECK(rs.is_valid());
1935 uint32_t imm21 = AUIPC << kImm16Bits | (imm16 & kImm16Mask);
1936 GenInstrImmediate(PCREL, rs, imm21);
1937}
1938
1939
1940void Assembler::aluipc(Register rs, int16_t imm16) {
1941 DCHECK(IsMipsArchVariant(kMips32r6));
1942 DCHECK(rs.is_valid());
1943 uint32_t imm21 = ALUIPC << kImm16Bits | (imm16 & kImm16Mask);
1944 GenInstrImmediate(PCREL, rs, imm21);
1945}
1946
1947
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001948// -------------Misc-instructions--------------
Andrei Popescu31002712010-02-23 13:46:05 +00001949
1950// Break / Trap instructions.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001951void Assembler::break_(uint32_t code, bool break_as_stop) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001952 DCHECK((code & ~0xfffff) == 0);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001953 // We need to invalidate breaks that could be stops as well because the
1954 // simulator expects a char pointer after the stop instruction.
1955 // See constants-mips.h for explanation.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001956 DCHECK((break_as_stop &&
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001957 code <= kMaxStopCode &&
1958 code > kMaxWatchpointCode) ||
1959 (!break_as_stop &&
1960 (code > kMaxStopCode ||
1961 code <= kMaxWatchpointCode)));
Andrei Popescu31002712010-02-23 13:46:05 +00001962 Instr break_instr = SPECIAL | BREAK | (code << 6);
1963 emit(break_instr);
1964}
1965
1966
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001967void Assembler::stop(const char* msg, uint32_t code) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001968 DCHECK(code > kMaxWatchpointCode);
1969 DCHECK(code <= kMaxStopCode);
1970#if V8_HOST_ARCH_MIPS
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001971 break_(0x54321);
1972#else // V8_HOST_ARCH_MIPS
1973 BlockTrampolinePoolFor(2);
1974 // The Simulator will handle the stop instruction and get the message address.
1975 // On MIPS stop() is just a special kind of break_().
1976 break_(code, true);
Ben Murdochf91f0612016-11-29 16:50:11 +00001977 // Do not embed the message string address! We used to do this, but that
1978 // made snapshots created from position-independent executable builds
1979 // non-deterministic.
1980 // TODO(yangguo): remove this field entirely.
1981 nop();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001982#endif
1983}
1984
1985
Andrei Popescu31002712010-02-23 13:46:05 +00001986void Assembler::tge(Register rs, Register rt, uint16_t code) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001987 DCHECK(is_uint10(code));
Andrei Popescu31002712010-02-23 13:46:05 +00001988 Instr instr = SPECIAL | TGE | rs.code() << kRsShift
1989 | rt.code() << kRtShift | code << 6;
1990 emit(instr);
1991}
1992
1993
1994void Assembler::tgeu(Register rs, Register rt, uint16_t code) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001995 DCHECK(is_uint10(code));
Andrei Popescu31002712010-02-23 13:46:05 +00001996 Instr instr = SPECIAL | TGEU | rs.code() << kRsShift
1997 | rt.code() << kRtShift | code << 6;
1998 emit(instr);
1999}
2000
2001
2002void Assembler::tlt(Register rs, Register rt, uint16_t code) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002003 DCHECK(is_uint10(code));
Andrei Popescu31002712010-02-23 13:46:05 +00002004 Instr instr =
2005 SPECIAL | TLT | rs.code() << kRsShift | rt.code() << kRtShift | code << 6;
2006 emit(instr);
2007}
2008
2009
2010void Assembler::tltu(Register rs, Register rt, uint16_t code) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002011 DCHECK(is_uint10(code));
Steve Block44f0eee2011-05-26 01:26:41 +01002012 Instr instr =
2013 SPECIAL | TLTU | rs.code() << kRsShift
Andrei Popescu31002712010-02-23 13:46:05 +00002014 | rt.code() << kRtShift | code << 6;
2015 emit(instr);
2016}
2017
2018
2019void Assembler::teq(Register rs, Register rt, uint16_t code) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002020 DCHECK(is_uint10(code));
Andrei Popescu31002712010-02-23 13:46:05 +00002021 Instr instr =
2022 SPECIAL | TEQ | rs.code() << kRsShift | rt.code() << kRtShift | code << 6;
2023 emit(instr);
2024}
2025
2026
2027void Assembler::tne(Register rs, Register rt, uint16_t code) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002028 DCHECK(is_uint10(code));
Andrei Popescu31002712010-02-23 13:46:05 +00002029 Instr instr =
2030 SPECIAL | TNE | rs.code() << kRsShift | rt.code() << kRtShift | code << 6;
2031 emit(instr);
2032}
2033
Ben Murdochbcf72ee2016-08-08 18:44:38 +01002034void Assembler::sync() {
2035 Instr sync_instr = SPECIAL | SYNC;
2036 emit(sync_instr);
2037}
Andrei Popescu31002712010-02-23 13:46:05 +00002038
2039// Move from HI/LO register.
2040
2041void Assembler::mfhi(Register rd) {
2042 GenInstrRegister(SPECIAL, zero_reg, zero_reg, rd, 0, MFHI);
2043}
2044
2045
2046void Assembler::mflo(Register rd) {
2047 GenInstrRegister(SPECIAL, zero_reg, zero_reg, rd, 0, MFLO);
2048}
2049
2050
2051// Set on less than instructions.
2052void Assembler::slt(Register rd, Register rs, Register rt) {
2053 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SLT);
2054}
2055
2056
2057void Assembler::sltu(Register rd, Register rs, Register rt) {
2058 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SLTU);
2059}
2060
2061
2062void Assembler::slti(Register rt, Register rs, int32_t j) {
2063 GenInstrImmediate(SLTI, rs, rt, j);
2064}
2065
2066
2067void Assembler::sltiu(Register rt, Register rs, int32_t j) {
2068 GenInstrImmediate(SLTIU, rs, rt, j);
2069}
2070
2071
Steve Block44f0eee2011-05-26 01:26:41 +01002072// Conditional move.
2073void Assembler::movz(Register rd, Register rs, Register rt) {
2074 GenInstrRegister(SPECIAL, rs, rt, rd, 0, MOVZ);
2075}
2076
2077
2078void Assembler::movn(Register rd, Register rs, Register rt) {
2079 GenInstrRegister(SPECIAL, rs, rt, rd, 0, MOVN);
2080}
2081
2082
2083void Assembler::movt(Register rd, Register rs, uint16_t cc) {
2084 Register rt;
Ben Murdoch014dc512016-03-22 12:00:34 +00002085 rt.reg_code = (cc & 0x0007) << 2 | 1;
Steve Block44f0eee2011-05-26 01:26:41 +01002086 GenInstrRegister(SPECIAL, rs, rt, rd, 0, MOVCI);
2087}
2088
2089
2090void Assembler::movf(Register rd, Register rs, uint16_t cc) {
2091 Register rt;
Ben Murdoch014dc512016-03-22 12:00:34 +00002092 rt.reg_code = (cc & 0x0007) << 2 | 0;
Steve Block44f0eee2011-05-26 01:26:41 +01002093 GenInstrRegister(SPECIAL, rs, rt, rd, 0, MOVCI);
2094}
2095
2096
Ben Murdoch014dc512016-03-22 12:00:34 +00002097void Assembler::seleqz(Register rd, Register rs, Register rt) {
2098 DCHECK(IsMipsArchVariant(kMips32r6));
2099 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SELEQZ_S);
2100}
2101
2102
Steve Block44f0eee2011-05-26 01:26:41 +01002103// Bit twiddling.
2104void Assembler::clz(Register rd, Register rs) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002105 if (!IsMipsArchVariant(kMips32r6)) {
2106 // Clz instr requires same GPR number in 'rd' and 'rt' fields.
2107 GenInstrRegister(SPECIAL2, rs, rd, rd, 0, CLZ);
2108 } else {
2109 GenInstrRegister(SPECIAL, rs, zero_reg, rd, 1, CLZ_R6);
2110 }
Steve Block44f0eee2011-05-26 01:26:41 +01002111}
2112
2113
2114void Assembler::ins_(Register rt, Register rs, uint16_t pos, uint16_t size) {
2115 // Should be called via MacroAssembler::Ins.
2116 // Ins instr has 'rt' field as dest, and two uint5: msb, lsb.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002117 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
Steve Block44f0eee2011-05-26 01:26:41 +01002118 GenInstrRegister(SPECIAL3, rs, rt, pos + size - 1, pos, INS);
2119}
2120
2121
2122void Assembler::ext_(Register rt, Register rs, uint16_t pos, uint16_t size) {
2123 // Should be called via MacroAssembler::Ext.
2124 // Ext instr has 'rt' field as dest, and two uint5: msb, lsb.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002125 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
Steve Block44f0eee2011-05-26 01:26:41 +01002126 GenInstrRegister(SPECIAL3, rs, rt, size - 1, pos, EXT);
2127}
2128
2129
Ben Murdoch014dc512016-03-22 12:00:34 +00002130void Assembler::bitswap(Register rd, Register rt) {
2131 DCHECK(IsMipsArchVariant(kMips32r6));
2132 GenInstrRegister(SPECIAL3, zero_reg, rt, rd, 0, BSHFL);
2133}
2134
2135
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002136void Assembler::pref(int32_t hint, const MemOperand& rs) {
2137 DCHECK(!IsMipsArchVariant(kLoongson));
2138 DCHECK(is_uint5(hint) && is_uint16(rs.offset_));
2139 Instr instr = PREF | (rs.rm().code() << kRsShift) | (hint << kRtShift)
2140 | (rs.offset_);
2141 emit(instr);
2142}
2143
2144
Ben Murdoch014dc512016-03-22 12:00:34 +00002145void Assembler::align(Register rd, Register rs, Register rt, uint8_t bp) {
2146 DCHECK(IsMipsArchVariant(kMips32r6));
2147 DCHECK(is_uint3(bp));
2148 uint16_t sa = (ALIGN << kBp2Bits) | bp;
2149 GenInstrRegister(SPECIAL3, rs, rt, rd, sa, BSHFL);
2150}
2151
Ben Murdoch13e2dad2016-09-16 13:49:30 +01002152// Byte swap.
2153void Assembler::wsbh(Register rd, Register rt) {
2154 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
2155 GenInstrRegister(SPECIAL3, zero_reg, rt, rd, WSBH, BSHFL);
2156}
2157
2158void Assembler::seh(Register rd, Register rt) {
2159 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
2160 GenInstrRegister(SPECIAL3, zero_reg, rt, rd, SEH, BSHFL);
2161}
2162
2163void Assembler::seb(Register rd, Register rt) {
2164 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
2165 GenInstrRegister(SPECIAL3, zero_reg, rt, rd, SEB, BSHFL);
2166}
Ben Murdoch014dc512016-03-22 12:00:34 +00002167
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002168// --------Coprocessor-instructions----------------
Andrei Popescu31002712010-02-23 13:46:05 +00002169
2170// Load, store, move.
2171void Assembler::lwc1(FPURegister fd, const MemOperand& src) {
Ben Murdoch014dc512016-03-22 12:00:34 +00002172 if (is_int16(src.offset_)) {
2173 GenInstrImmediate(LWC1, src.rm(), fd, src.offset_);
2174 } else { // Offset > 16 bits, use multiple instructions to load.
2175 LoadRegPlusOffsetToAt(src);
2176 GenInstrImmediate(LWC1, at, fd, 0);
2177 }
Andrei Popescu31002712010-02-23 13:46:05 +00002178}
2179
2180
2181void Assembler::ldc1(FPURegister fd, const MemOperand& src) {
Steve Block44f0eee2011-05-26 01:26:41 +01002182 // Workaround for non-8-byte alignment of HeapNumber, convert 64-bit
2183 // load to two 32-bit loads.
Ben Murdoch109988c2016-05-18 11:27:45 +01002184 if (IsFp32Mode()) { // fp32 mode.
Ben Murdoch014dc512016-03-22 12:00:34 +00002185 if (is_int16(src.offset_) && is_int16(src.offset_ + kIntSize)) {
2186 GenInstrImmediate(LWC1, src.rm(), fd,
2187 src.offset_ + Register::kMantissaOffset);
2188 FPURegister nextfpreg;
2189 nextfpreg.setcode(fd.code() + 1);
2190 GenInstrImmediate(LWC1, src.rm(), nextfpreg,
2191 src.offset_ + Register::kExponentOffset);
2192 } else { // Offset > 16 bits, use multiple instructions to load.
2193 LoadRegPlusOffsetToAt(src);
2194 GenInstrImmediate(LWC1, at, fd, Register::kMantissaOffset);
2195 FPURegister nextfpreg;
2196 nextfpreg.setcode(fd.code() + 1);
2197 GenInstrImmediate(LWC1, at, nextfpreg, Register::kExponentOffset);
2198 }
Ben Murdoch109988c2016-05-18 11:27:45 +01002199 } else {
2200 DCHECK(IsFp64Mode() || IsFpxxMode());
2201 // Currently we support FPXX and FP64 on Mips32r2 and Mips32r6
2202 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
2203 if (is_int16(src.offset_) && is_int16(src.offset_ + kIntSize)) {
2204 GenInstrImmediate(LWC1, src.rm(), fd,
2205 src.offset_ + Register::kMantissaOffset);
2206 GenInstrImmediate(LW, src.rm(), at,
2207 src.offset_ + Register::kExponentOffset);
2208 mthc1(at, fd);
2209 } else { // Offset > 16 bits, use multiple instructions to load.
2210 LoadRegPlusOffsetToAt(src);
2211 GenInstrImmediate(LWC1, at, fd, Register::kMantissaOffset);
2212 GenInstrImmediate(LW, at, at, Register::kExponentOffset);
2213 mthc1(at, fd);
2214 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002215 }
Andrei Popescu31002712010-02-23 13:46:05 +00002216}
2217
2218
2219void Assembler::swc1(FPURegister fd, const MemOperand& src) {
Ben Murdoch014dc512016-03-22 12:00:34 +00002220 if (is_int16(src.offset_)) {
2221 GenInstrImmediate(SWC1, src.rm(), fd, src.offset_);
2222 } else { // Offset > 16 bits, use multiple instructions to load.
2223 LoadRegPlusOffsetToAt(src);
2224 GenInstrImmediate(SWC1, at, fd, 0);
2225 }
Andrei Popescu31002712010-02-23 13:46:05 +00002226}
2227
2228
2229void Assembler::sdc1(FPURegister fd, const MemOperand& src) {
Steve Block44f0eee2011-05-26 01:26:41 +01002230 // Workaround for non-8-byte alignment of HeapNumber, convert 64-bit
2231 // store to two 32-bit stores.
Ben Murdoch014dc512016-03-22 12:00:34 +00002232 DCHECK(!src.rm().is(at));
2233 DCHECK(!src.rm().is(t8));
Ben Murdoch109988c2016-05-18 11:27:45 +01002234 if (IsFp32Mode()) { // fp32 mode.
Ben Murdoch014dc512016-03-22 12:00:34 +00002235 if (is_int16(src.offset_) && is_int16(src.offset_ + kIntSize)) {
2236 GenInstrImmediate(SWC1, src.rm(), fd,
2237 src.offset_ + Register::kMantissaOffset);
2238 FPURegister nextfpreg;
2239 nextfpreg.setcode(fd.code() + 1);
2240 GenInstrImmediate(SWC1, src.rm(), nextfpreg,
2241 src.offset_ + Register::kExponentOffset);
2242 } else { // Offset > 16 bits, use multiple instructions to load.
2243 LoadRegPlusOffsetToAt(src);
2244 GenInstrImmediate(SWC1, at, fd, Register::kMantissaOffset);
2245 FPURegister nextfpreg;
2246 nextfpreg.setcode(fd.code() + 1);
2247 GenInstrImmediate(SWC1, at, nextfpreg, Register::kExponentOffset);
2248 }
Ben Murdoch109988c2016-05-18 11:27:45 +01002249 } else {
2250 DCHECK(IsFp64Mode() || IsFpxxMode());
2251 // Currently we support FPXX and FP64 on Mips32r2 and Mips32r6
2252 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
2253 if (is_int16(src.offset_) && is_int16(src.offset_ + kIntSize)) {
2254 GenInstrImmediate(SWC1, src.rm(), fd,
2255 src.offset_ + Register::kMantissaOffset);
2256 mfhc1(at, fd);
2257 GenInstrImmediate(SW, src.rm(), at,
2258 src.offset_ + Register::kExponentOffset);
2259 } else { // Offset > 16 bits, use multiple instructions to load.
2260 LoadRegPlusOffsetToAt(src);
2261 GenInstrImmediate(SWC1, at, fd, Register::kMantissaOffset);
2262 mfhc1(t8, fd);
2263 GenInstrImmediate(SW, at, t8, Register::kExponentOffset);
2264 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002265 }
Andrei Popescu31002712010-02-23 13:46:05 +00002266}
2267
2268
Steve Block44f0eee2011-05-26 01:26:41 +01002269void Assembler::mtc1(Register rt, FPURegister fs) {
Andrei Popescu31002712010-02-23 13:46:05 +00002270 GenInstrRegister(COP1, MTC1, rt, fs, f0);
2271}
2272
2273
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002274void Assembler::mthc1(Register rt, FPURegister fs) {
2275 GenInstrRegister(COP1, MTHC1, rt, fs, f0);
2276}
2277
2278
Steve Block44f0eee2011-05-26 01:26:41 +01002279void Assembler::mfc1(Register rt, FPURegister fs) {
Andrei Popescu31002712010-02-23 13:46:05 +00002280 GenInstrRegister(COP1, MFC1, rt, fs, f0);
2281}
2282
2283
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002284void Assembler::mfhc1(Register rt, FPURegister fs) {
2285 GenInstrRegister(COP1, MFHC1, rt, fs, f0);
2286}
2287
2288
Steve Block44f0eee2011-05-26 01:26:41 +01002289void Assembler::ctc1(Register rt, FPUControlRegister fs) {
2290 GenInstrRegister(COP1, CTC1, rt, fs);
2291}
2292
2293
2294void Assembler::cfc1(Register rt, FPUControlRegister fs) {
2295 GenInstrRegister(COP1, CFC1, rt, fs);
2296}
2297
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002298
Ben Murdoch589d6972011-11-30 16:04:58 +00002299void Assembler::DoubleAsTwoUInt32(double d, uint32_t* lo, uint32_t* hi) {
2300 uint64_t i;
2301 memcpy(&i, &d, 8);
2302
2303 *lo = i & 0xffffffff;
2304 *hi = i >> 32;
2305}
Steve Block44f0eee2011-05-26 01:26:41 +01002306
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002307
Ben Murdoch014dc512016-03-22 12:00:34 +00002308void Assembler::movn_s(FPURegister fd, FPURegister fs, Register rt) {
2309 DCHECK(!IsMipsArchVariant(kMips32r6));
2310 GenInstrRegister(COP1, S, rt, fs, fd, MOVN_C);
2311}
2312
2313
2314void Assembler::movn_d(FPURegister fd, FPURegister fs, Register rt) {
2315 DCHECK(!IsMipsArchVariant(kMips32r6));
2316 GenInstrRegister(COP1, D, rt, fs, fd, MOVN_C);
2317}
2318
2319
2320void Assembler::sel(SecondaryField fmt, FPURegister fd, FPURegister fs,
2321 FPURegister ft) {
2322 DCHECK(IsMipsArchVariant(kMips32r6));
2323 DCHECK((fmt == D) || (fmt == S));
2324
2325 GenInstrRegister(COP1, fmt, ft, fs, fd, SEL);
2326}
2327
2328
2329void Assembler::sel_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2330 sel(S, fd, fs, ft);
2331}
2332
2333
2334void Assembler::sel_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2335 sel(D, fd, fs, ft);
2336}
2337
2338
2339void Assembler::seleqz(SecondaryField fmt, FPURegister fd, FPURegister fs,
2340 FPURegister ft) {
2341 DCHECK(IsMipsArchVariant(kMips32r6));
2342 DCHECK((fmt == D) || (fmt == S));
2343 GenInstrRegister(COP1, fmt, ft, fs, fd, SELEQZ_C);
2344}
2345
2346
2347void Assembler::selnez(Register rd, Register rs, Register rt) {
2348 DCHECK(IsMipsArchVariant(kMips32r6));
2349 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SELNEZ_S);
2350}
2351
2352
2353void Assembler::selnez(SecondaryField fmt, FPURegister fd, FPURegister fs,
2354 FPURegister ft) {
2355 DCHECK(IsMipsArchVariant(kMips32r6));
2356 DCHECK((fmt == D) || (fmt == S));
2357 GenInstrRegister(COP1, fmt, ft, fs, fd, SELNEZ_C);
2358}
2359
2360
2361void Assembler::seleqz_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2362 seleqz(D, fd, fs, ft);
2363}
2364
2365
2366void Assembler::seleqz_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2367 seleqz(S, fd, fs, ft);
2368}
2369
2370
2371void Assembler::selnez_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2372 selnez(D, fd, fs, ft);
2373}
2374
2375
2376void Assembler::selnez_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2377 selnez(S, fd, fs, ft);
2378}
2379
2380
2381void Assembler::movz_s(FPURegister fd, FPURegister fs, Register rt) {
2382 DCHECK(!IsMipsArchVariant(kMips32r6));
2383 GenInstrRegister(COP1, S, rt, fs, fd, MOVZ_C);
2384}
2385
2386
2387void Assembler::movz_d(FPURegister fd, FPURegister fs, Register rt) {
2388 DCHECK(!IsMipsArchVariant(kMips32r6));
2389 GenInstrRegister(COP1, D, rt, fs, fd, MOVZ_C);
2390}
2391
2392
2393void Assembler::movt_s(FPURegister fd, FPURegister fs, uint16_t cc) {
2394 DCHECK(!IsMipsArchVariant(kMips32r6));
2395 FPURegister ft;
2396 ft.reg_code = (cc & 0x0007) << 2 | 1;
2397 GenInstrRegister(COP1, S, ft, fs, fd, MOVF);
2398}
2399
2400
2401void Assembler::movt_d(FPURegister fd, FPURegister fs, uint16_t cc) {
2402 DCHECK(!IsMipsArchVariant(kMips32r6));
2403 FPURegister ft;
2404 ft.reg_code = (cc & 0x0007) << 2 | 1;
2405 GenInstrRegister(COP1, D, ft, fs, fd, MOVF);
2406}
2407
2408
2409void Assembler::movf_s(FPURegister fd, FPURegister fs, uint16_t cc) {
2410 DCHECK(!IsMipsArchVariant(kMips32r6));
2411 FPURegister ft;
2412 ft.reg_code = (cc & 0x0007) << 2 | 0;
2413 GenInstrRegister(COP1, S, ft, fs, fd, MOVF);
2414}
2415
2416
2417void Assembler::movf_d(FPURegister fd, FPURegister fs, uint16_t cc) {
2418 DCHECK(!IsMipsArchVariant(kMips32r6));
2419 FPURegister ft;
2420 ft.reg_code = (cc & 0x0007) << 2 | 0;
2421 GenInstrRegister(COP1, D, ft, fs, fd, MOVF);
2422}
2423
2424
Steve Block44f0eee2011-05-26 01:26:41 +01002425// Arithmetic.
2426
Ben Murdoch014dc512016-03-22 12:00:34 +00002427void Assembler::add_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2428 GenInstrRegister(COP1, S, ft, fs, fd, ADD_S);
2429}
2430
2431
Steve Block44f0eee2011-05-26 01:26:41 +01002432void Assembler::add_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2433 GenInstrRegister(COP1, D, ft, fs, fd, ADD_D);
2434}
2435
2436
Ben Murdoch014dc512016-03-22 12:00:34 +00002437void Assembler::sub_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2438 GenInstrRegister(COP1, S, ft, fs, fd, SUB_S);
2439}
2440
2441
Steve Block44f0eee2011-05-26 01:26:41 +01002442void Assembler::sub_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2443 GenInstrRegister(COP1, D, ft, fs, fd, SUB_D);
2444}
2445
2446
Ben Murdoch014dc512016-03-22 12:00:34 +00002447void Assembler::mul_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2448 GenInstrRegister(COP1, S, ft, fs, fd, MUL_S);
2449}
2450
2451
Steve Block44f0eee2011-05-26 01:26:41 +01002452void Assembler::mul_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2453 GenInstrRegister(COP1, D, ft, fs, fd, MUL_D);
2454}
2455
2456
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002457void Assembler::madd_d(FPURegister fd, FPURegister fr, FPURegister fs,
2458 FPURegister ft) {
Emily Bernier958fae72015-03-24 16:35:39 -04002459 DCHECK(IsMipsArchVariant(kMips32r2));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002460 GenInstrRegister(COP1X, fr, ft, fs, fd, MADD_D);
2461}
2462
2463
Ben Murdoch014dc512016-03-22 12:00:34 +00002464void Assembler::div_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2465 GenInstrRegister(COP1, S, ft, fs, fd, DIV_S);
2466}
2467
2468
Steve Block44f0eee2011-05-26 01:26:41 +01002469void Assembler::div_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2470 GenInstrRegister(COP1, D, ft, fs, fd, DIV_D);
2471}
2472
2473
Ben Murdoch014dc512016-03-22 12:00:34 +00002474void Assembler::abs_s(FPURegister fd, FPURegister fs) {
2475 GenInstrRegister(COP1, S, f0, fs, fd, ABS_S);
2476}
2477
2478
Steve Block44f0eee2011-05-26 01:26:41 +01002479void Assembler::abs_d(FPURegister fd, FPURegister fs) {
2480 GenInstrRegister(COP1, D, f0, fs, fd, ABS_D);
2481}
2482
2483
2484void Assembler::mov_d(FPURegister fd, FPURegister fs) {
2485 GenInstrRegister(COP1, D, f0, fs, fd, MOV_D);
2486}
2487
2488
Ben Murdoch014dc512016-03-22 12:00:34 +00002489void Assembler::mov_s(FPURegister fd, FPURegister fs) {
2490 GenInstrRegister(COP1, S, f0, fs, fd, MOV_S);
2491}
2492
2493
2494void Assembler::neg_s(FPURegister fd, FPURegister fs) {
Ben Murdochf91f0612016-11-29 16:50:11 +00002495 DCHECK(!IsMipsArchVariant(kMips32r6));
Ben Murdoch014dc512016-03-22 12:00:34 +00002496 GenInstrRegister(COP1, S, f0, fs, fd, NEG_S);
2497}
2498
2499
Steve Block44f0eee2011-05-26 01:26:41 +01002500void Assembler::neg_d(FPURegister fd, FPURegister fs) {
Ben Murdochf91f0612016-11-29 16:50:11 +00002501 DCHECK(!IsMipsArchVariant(kMips32r6));
Steve Block44f0eee2011-05-26 01:26:41 +01002502 GenInstrRegister(COP1, D, f0, fs, fd, NEG_D);
2503}
2504
2505
Ben Murdoch014dc512016-03-22 12:00:34 +00002506void Assembler::sqrt_s(FPURegister fd, FPURegister fs) {
2507 GenInstrRegister(COP1, S, f0, fs, fd, SQRT_S);
2508}
2509
2510
Steve Block44f0eee2011-05-26 01:26:41 +01002511void Assembler::sqrt_d(FPURegister fd, FPURegister fs) {
2512 GenInstrRegister(COP1, D, f0, fs, fd, SQRT_D);
Andrei Popescu31002712010-02-23 13:46:05 +00002513}
2514
2515
Ben Murdoch014dc512016-03-22 12:00:34 +00002516void Assembler::rsqrt_s(FPURegister fd, FPURegister fs) {
2517 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
2518 GenInstrRegister(COP1, S, f0, fs, fd, RSQRT_S);
2519}
2520
2521
2522void Assembler::rsqrt_d(FPURegister fd, FPURegister fs) {
2523 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
2524 GenInstrRegister(COP1, D, f0, fs, fd, RSQRT_D);
2525}
2526
2527
2528void Assembler::recip_d(FPURegister fd, FPURegister fs) {
2529 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
2530 GenInstrRegister(COP1, D, f0, fs, fd, RECIP_D);
2531}
2532
2533
2534void Assembler::recip_s(FPURegister fd, FPURegister fs) {
2535 DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
2536 GenInstrRegister(COP1, S, f0, fs, fd, RECIP_S);
2537}
2538
2539
Andrei Popescu31002712010-02-23 13:46:05 +00002540// Conversions.
2541
2542void Assembler::cvt_w_s(FPURegister fd, FPURegister fs) {
2543 GenInstrRegister(COP1, S, f0, fs, fd, CVT_W_S);
2544}
2545
2546
2547void Assembler::cvt_w_d(FPURegister fd, FPURegister fs) {
2548 GenInstrRegister(COP1, D, f0, fs, fd, CVT_W_D);
2549}
2550
2551
Steve Block44f0eee2011-05-26 01:26:41 +01002552void Assembler::trunc_w_s(FPURegister fd, FPURegister fs) {
2553 GenInstrRegister(COP1, S, f0, fs, fd, TRUNC_W_S);
2554}
2555
2556
2557void Assembler::trunc_w_d(FPURegister fd, FPURegister fs) {
2558 GenInstrRegister(COP1, D, f0, fs, fd, TRUNC_W_D);
2559}
2560
2561
2562void Assembler::round_w_s(FPURegister fd, FPURegister fs) {
2563 GenInstrRegister(COP1, S, f0, fs, fd, ROUND_W_S);
2564}
2565
2566
2567void Assembler::round_w_d(FPURegister fd, FPURegister fs) {
2568 GenInstrRegister(COP1, D, f0, fs, fd, ROUND_W_D);
2569}
2570
2571
2572void Assembler::floor_w_s(FPURegister fd, FPURegister fs) {
2573 GenInstrRegister(COP1, S, f0, fs, fd, FLOOR_W_S);
2574}
2575
2576
2577void Assembler::floor_w_d(FPURegister fd, FPURegister fs) {
2578 GenInstrRegister(COP1, D, f0, fs, fd, FLOOR_W_D);
2579}
2580
2581
2582void Assembler::ceil_w_s(FPURegister fd, FPURegister fs) {
2583 GenInstrRegister(COP1, S, f0, fs, fd, CEIL_W_S);
2584}
2585
2586
2587void Assembler::ceil_w_d(FPURegister fd, FPURegister fs) {
2588 GenInstrRegister(COP1, D, f0, fs, fd, CEIL_W_D);
2589}
2590
2591
Ben Murdoch014dc512016-03-22 12:00:34 +00002592void Assembler::rint_s(FPURegister fd, FPURegister fs) { rint(S, fd, fs); }
2593
2594
2595void Assembler::rint(SecondaryField fmt, FPURegister fd, FPURegister fs) {
2596 DCHECK(IsMipsArchVariant(kMips32r6));
2597 DCHECK((fmt == D) || (fmt == S));
2598 GenInstrRegister(COP1, fmt, f0, fs, fd, RINT);
2599}
2600
2601
2602void Assembler::rint_d(FPURegister fd, FPURegister fs) { rint(D, fd, fs); }
2603
2604
Andrei Popescu31002712010-02-23 13:46:05 +00002605void Assembler::cvt_l_s(FPURegister fd, FPURegister fs) {
Ben Murdoch014dc512016-03-22 12:00:34 +00002606 DCHECK((IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) &&
2607 IsFp64Mode());
Andrei Popescu31002712010-02-23 13:46:05 +00002608 GenInstrRegister(COP1, S, f0, fs, fd, CVT_L_S);
2609}
2610
2611
2612void Assembler::cvt_l_d(FPURegister fd, FPURegister fs) {
Ben Murdoch014dc512016-03-22 12:00:34 +00002613 DCHECK((IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) &&
2614 IsFp64Mode());
Andrei Popescu31002712010-02-23 13:46:05 +00002615 GenInstrRegister(COP1, D, f0, fs, fd, CVT_L_D);
2616}
2617
2618
Steve Block44f0eee2011-05-26 01:26:41 +01002619void Assembler::trunc_l_s(FPURegister fd, FPURegister fs) {
Ben Murdoch014dc512016-03-22 12:00:34 +00002620 DCHECK((IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) &&
2621 IsFp64Mode());
Steve Block44f0eee2011-05-26 01:26:41 +01002622 GenInstrRegister(COP1, S, f0, fs, fd, TRUNC_L_S);
2623}
2624
2625
2626void Assembler::trunc_l_d(FPURegister fd, FPURegister fs) {
Ben Murdoch014dc512016-03-22 12:00:34 +00002627 DCHECK((IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) &&
2628 IsFp64Mode());
Steve Block44f0eee2011-05-26 01:26:41 +01002629 GenInstrRegister(COP1, D, f0, fs, fd, TRUNC_L_D);
2630}
2631
2632
2633void Assembler::round_l_s(FPURegister fd, FPURegister fs) {
Ben Murdoch014dc512016-03-22 12:00:34 +00002634 DCHECK((IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) &&
2635 IsFp64Mode());
Steve Block44f0eee2011-05-26 01:26:41 +01002636 GenInstrRegister(COP1, S, f0, fs, fd, ROUND_L_S);
2637}
2638
2639
2640void Assembler::round_l_d(FPURegister fd, FPURegister fs) {
Ben Murdoch014dc512016-03-22 12:00:34 +00002641 DCHECK((IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) &&
2642 IsFp64Mode());
Steve Block44f0eee2011-05-26 01:26:41 +01002643 GenInstrRegister(COP1, D, f0, fs, fd, ROUND_L_D);
2644}
2645
2646
2647void Assembler::floor_l_s(FPURegister fd, FPURegister fs) {
Ben Murdoch014dc512016-03-22 12:00:34 +00002648 DCHECK((IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) &&
2649 IsFp64Mode());
Steve Block44f0eee2011-05-26 01:26:41 +01002650 GenInstrRegister(COP1, S, f0, fs, fd, FLOOR_L_S);
2651}
2652
2653
2654void Assembler::floor_l_d(FPURegister fd, FPURegister fs) {
Ben Murdoch014dc512016-03-22 12:00:34 +00002655 DCHECK((IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) &&
2656 IsFp64Mode());
Steve Block44f0eee2011-05-26 01:26:41 +01002657 GenInstrRegister(COP1, D, f0, fs, fd, FLOOR_L_D);
2658}
2659
2660
2661void Assembler::ceil_l_s(FPURegister fd, FPURegister fs) {
Ben Murdoch014dc512016-03-22 12:00:34 +00002662 DCHECK((IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) &&
2663 IsFp64Mode());
Steve Block44f0eee2011-05-26 01:26:41 +01002664 GenInstrRegister(COP1, S, f0, fs, fd, CEIL_L_S);
2665}
2666
2667
2668void Assembler::ceil_l_d(FPURegister fd, FPURegister fs) {
Ben Murdoch014dc512016-03-22 12:00:34 +00002669 DCHECK((IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) &&
2670 IsFp64Mode());
Steve Block44f0eee2011-05-26 01:26:41 +01002671 GenInstrRegister(COP1, D, f0, fs, fd, CEIL_L_D);
2672}
2673
2674
Ben Murdoch014dc512016-03-22 12:00:34 +00002675void Assembler::class_s(FPURegister fd, FPURegister fs) {
2676 DCHECK(IsMipsArchVariant(kMips32r6));
2677 GenInstrRegister(COP1, S, f0, fs, fd, CLASS_S);
2678}
2679
2680
2681void Assembler::class_d(FPURegister fd, FPURegister fs) {
2682 DCHECK(IsMipsArchVariant(kMips32r6));
2683 GenInstrRegister(COP1, D, f0, fs, fd, CLASS_D);
2684}
2685
2686
2687void Assembler::min(SecondaryField fmt, FPURegister fd, FPURegister fs,
2688 FPURegister ft) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002689 DCHECK(IsMipsArchVariant(kMips32r6));
2690 DCHECK((fmt == D) || (fmt == S));
2691 GenInstrRegister(COP1, fmt, ft, fs, fd, MIN);
2692}
2693
2694
Ben Murdoch014dc512016-03-22 12:00:34 +00002695void Assembler::mina(SecondaryField fmt, FPURegister fd, FPURegister fs,
2696 FPURegister ft) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002697 DCHECK(IsMipsArchVariant(kMips32r6));
2698 DCHECK((fmt == D) || (fmt == S));
2699 GenInstrRegister(COP1, fmt, ft, fs, fd, MINA);
2700}
2701
2702
Ben Murdoch014dc512016-03-22 12:00:34 +00002703void Assembler::max(SecondaryField fmt, FPURegister fd, FPURegister fs,
2704 FPURegister ft) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002705 DCHECK(IsMipsArchVariant(kMips32r6));
2706 DCHECK((fmt == D) || (fmt == S));
2707 GenInstrRegister(COP1, fmt, ft, fs, fd, MAX);
2708}
2709
2710
Ben Murdoch014dc512016-03-22 12:00:34 +00002711void Assembler::maxa(SecondaryField fmt, FPURegister fd, FPURegister fs,
2712 FPURegister ft) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002713 DCHECK(IsMipsArchVariant(kMips32r6));
2714 DCHECK((fmt == D) || (fmt == S));
2715 GenInstrRegister(COP1, fmt, ft, fs, fd, MAXA);
2716}
2717
2718
Ben Murdoch014dc512016-03-22 12:00:34 +00002719void Assembler::min_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2720 min(S, fd, fs, ft);
2721}
2722
2723
2724void Assembler::min_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2725 min(D, fd, fs, ft);
2726}
2727
2728
2729void Assembler::max_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2730 max(S, fd, fs, ft);
2731}
2732
2733
2734void Assembler::max_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2735 max(D, fd, fs, ft);
2736}
2737
2738
2739void Assembler::mina_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2740 mina(S, fd, fs, ft);
2741}
2742
2743
2744void Assembler::mina_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2745 mina(D, fd, fs, ft);
2746}
2747
2748
2749void Assembler::maxa_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2750 maxa(S, fd, fs, ft);
2751}
2752
2753
2754void Assembler::maxa_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2755 maxa(D, fd, fs, ft);
2756}
2757
2758
Andrei Popescu31002712010-02-23 13:46:05 +00002759void Assembler::cvt_s_w(FPURegister fd, FPURegister fs) {
2760 GenInstrRegister(COP1, W, f0, fs, fd, CVT_S_W);
2761}
2762
2763
2764void Assembler::cvt_s_l(FPURegister fd, FPURegister fs) {
Ben Murdoch014dc512016-03-22 12:00:34 +00002765 DCHECK((IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) &&
2766 IsFp64Mode());
Andrei Popescu31002712010-02-23 13:46:05 +00002767 GenInstrRegister(COP1, L, f0, fs, fd, CVT_S_L);
2768}
2769
2770
2771void Assembler::cvt_s_d(FPURegister fd, FPURegister fs) {
2772 GenInstrRegister(COP1, D, f0, fs, fd, CVT_S_D);
2773}
2774
2775
2776void Assembler::cvt_d_w(FPURegister fd, FPURegister fs) {
2777 GenInstrRegister(COP1, W, f0, fs, fd, CVT_D_W);
2778}
2779
2780
2781void Assembler::cvt_d_l(FPURegister fd, FPURegister fs) {
Ben Murdoch014dc512016-03-22 12:00:34 +00002782 DCHECK((IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) &&
2783 IsFp64Mode());
Andrei Popescu31002712010-02-23 13:46:05 +00002784 GenInstrRegister(COP1, L, f0, fs, fd, CVT_D_L);
2785}
2786
2787
2788void Assembler::cvt_d_s(FPURegister fd, FPURegister fs) {
2789 GenInstrRegister(COP1, S, f0, fs, fd, CVT_D_S);
2790}
2791
2792
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002793// Conditions for >= MIPSr6.
2794void Assembler::cmp(FPUCondition cond, SecondaryField fmt,
2795 FPURegister fd, FPURegister fs, FPURegister ft) {
2796 DCHECK(IsMipsArchVariant(kMips32r6));
2797 DCHECK((fmt & ~(31 << kRsShift)) == 0);
2798 Instr instr = COP1 | fmt | ft.code() << kFtShift |
2799 fs.code() << kFsShift | fd.code() << kFdShift | (0 << 5) | cond;
2800 emit(instr);
2801}
2802
2803
Ben Murdoch014dc512016-03-22 12:00:34 +00002804void Assembler::cmp_s(FPUCondition cond, FPURegister fd, FPURegister fs,
2805 FPURegister ft) {
2806 cmp(cond, W, fd, fs, ft);
2807}
2808
2809void Assembler::cmp_d(FPUCondition cond, FPURegister fd, FPURegister fs,
2810 FPURegister ft) {
2811 cmp(cond, L, fd, fs, ft);
2812}
2813
2814
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002815void Assembler::bc1eqz(int16_t offset, FPURegister ft) {
2816 DCHECK(IsMipsArchVariant(kMips32r6));
2817 Instr instr = COP1 | BC1EQZ | ft.code() << kFtShift | (offset & kImm16Mask);
2818 emit(instr);
2819}
2820
2821
2822void Assembler::bc1nez(int16_t offset, FPURegister ft) {
2823 DCHECK(IsMipsArchVariant(kMips32r6));
2824 Instr instr = COP1 | BC1NEZ | ft.code() << kFtShift | (offset & kImm16Mask);
2825 emit(instr);
2826}
2827
2828
2829// Conditions for < MIPSr6.
Andrei Popescu31002712010-02-23 13:46:05 +00002830void Assembler::c(FPUCondition cond, SecondaryField fmt,
Steve Block44f0eee2011-05-26 01:26:41 +01002831 FPURegister fs, FPURegister ft, uint16_t cc) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002832 DCHECK(is_uint3(cc));
Ben Murdoch014dc512016-03-22 12:00:34 +00002833 DCHECK(fmt == S || fmt == D);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002834 DCHECK((fmt & ~(31 << kRsShift)) == 0);
Andrei Popescu31002712010-02-23 13:46:05 +00002835 Instr instr = COP1 | fmt | ft.code() << 16 | fs.code() << kFsShift
2836 | cc << 8 | 3 << 4 | cond;
2837 emit(instr);
2838}
2839
2840
Ben Murdoch014dc512016-03-22 12:00:34 +00002841void Assembler::c_s(FPUCondition cond, FPURegister fs, FPURegister ft,
2842 uint16_t cc) {
2843 c(cond, S, fs, ft, cc);
2844}
2845
2846
2847void Assembler::c_d(FPUCondition cond, FPURegister fs, FPURegister ft,
2848 uint16_t cc) {
2849 c(cond, D, fs, ft, cc);
2850}
2851
2852
Steve Block44f0eee2011-05-26 01:26:41 +01002853void Assembler::fcmp(FPURegister src1, const double src2,
2854 FPUCondition cond) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002855 DCHECK(src2 == 0.0);
Steve Block44f0eee2011-05-26 01:26:41 +01002856 mtc1(zero_reg, f14);
2857 cvt_d_w(f14, f14);
2858 c(cond, D, src1, f14, 0);
2859}
2860
2861
Andrei Popescu31002712010-02-23 13:46:05 +00002862void Assembler::bc1f(int16_t offset, uint16_t cc) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002863 DCHECK(is_uint3(cc));
Andrei Popescu31002712010-02-23 13:46:05 +00002864 Instr instr = COP1 | BC1 | cc << 18 | 0 << 16 | (offset & kImm16Mask);
2865 emit(instr);
2866}
2867
2868
2869void Assembler::bc1t(int16_t offset, uint16_t cc) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002870 DCHECK(is_uint3(cc));
Andrei Popescu31002712010-02-23 13:46:05 +00002871 Instr instr = COP1 | BC1 | cc << 18 | 1 << 16 | (offset & kImm16Mask);
2872 emit(instr);
2873}
2874
2875
Ben Murdoch014dc512016-03-22 12:00:34 +00002876int Assembler::RelocateInternalReference(RelocInfo::Mode rmode, byte* pc,
2877 intptr_t pc_delta) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002878 Instr instr = instr_at(pc);
Ben Murdoch014dc512016-03-22 12:00:34 +00002879
2880 if (RelocInfo::IsInternalReference(rmode)) {
2881 int32_t* p = reinterpret_cast<int32_t*>(pc);
2882 if (*p == 0) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002883 return 0; // Number of instructions patched.
2884 }
Ben Murdoch014dc512016-03-22 12:00:34 +00002885 *p += pc_delta;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002886 return 1; // Number of instructions patched.
Ben Murdoch014dc512016-03-22 12:00:34 +00002887 } else {
2888 DCHECK(RelocInfo::IsInternalReferenceEncoded(rmode));
2889 if (IsLui(instr)) {
Ben Murdoch3b9bc312016-06-02 14:46:10 +01002890 Instr instr1 = instr_at(pc + 0 * Assembler::kInstrSize);
2891 Instr instr2 = instr_at(pc + 1 * Assembler::kInstrSize);
2892 DCHECK(IsOri(instr2) || IsJicOrJialc(instr2));
2893 int32_t imm;
2894 if (IsJicOrJialc(instr2)) {
2895 imm = CreateTargetAddress(instr1, instr2);
2896 } else {
2897 imm = (instr1 & static_cast<int32_t>(kImm16Mask)) << kLuiShift;
2898 imm |= (instr2 & static_cast<int32_t>(kImm16Mask));
2899 }
2900
Ben Murdoch014dc512016-03-22 12:00:34 +00002901 if (imm == kEndOfJumpChain) {
2902 return 0; // Number of instructions patched.
2903 }
2904 imm += pc_delta;
2905 DCHECK((imm & 3) == 0);
Ben Murdoch3b9bc312016-06-02 14:46:10 +01002906 instr1 &= ~kImm16Mask;
2907 instr2 &= ~kImm16Mask;
Ben Murdoch014dc512016-03-22 12:00:34 +00002908
Ben Murdoch3b9bc312016-06-02 14:46:10 +01002909 if (IsJicOrJialc(instr2)) {
2910 uint32_t lui_offset_u, jic_offset_u;
2911 Assembler::UnpackTargetAddressUnsigned(imm, lui_offset_u, jic_offset_u);
2912 instr_at_put(pc + 0 * Assembler::kInstrSize, instr1 | lui_offset_u);
2913 instr_at_put(pc + 1 * Assembler::kInstrSize, instr2 | jic_offset_u);
2914 } else {
2915 instr_at_put(pc + 0 * Assembler::kInstrSize,
2916 instr1 | ((imm >> kLuiShift) & kImm16Mask));
2917 instr_at_put(pc + 1 * Assembler::kInstrSize,
2918 instr2 | (imm & kImm16Mask));
2919 }
Ben Murdoch014dc512016-03-22 12:00:34 +00002920 return 2; // Number of instructions patched.
2921 } else {
2922 UNREACHABLE();
2923 return 0;
2924 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002925 }
2926}
2927
2928
Andrei Popescu31002712010-02-23 13:46:05 +00002929void Assembler::GrowBuffer() {
2930 if (!own_buffer_) FATAL("external code buffer is too small");
2931
2932 // Compute new buffer size.
Steve Block44f0eee2011-05-26 01:26:41 +01002933 CodeDesc desc; // The new buffer.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002934 if (buffer_size_ < 1 * MB) {
Andrei Popescu31002712010-02-23 13:46:05 +00002935 desc.buffer_size = 2*buffer_size_;
2936 } else {
2937 desc.buffer_size = buffer_size_ + 1*MB;
2938 }
Steve Block44f0eee2011-05-26 01:26:41 +01002939 CHECK_GT(desc.buffer_size, 0); // No overflow.
Andrei Popescu31002712010-02-23 13:46:05 +00002940
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002941 // Set up new buffer.
Andrei Popescu31002712010-02-23 13:46:05 +00002942 desc.buffer = NewArray<byte>(desc.buffer_size);
Ben Murdoch014dc512016-03-22 12:00:34 +00002943 desc.origin = this;
Andrei Popescu31002712010-02-23 13:46:05 +00002944
2945 desc.instr_size = pc_offset();
2946 desc.reloc_size = (buffer_ + buffer_size_) - reloc_info_writer.pos();
2947
2948 // Copy the data.
2949 int pc_delta = desc.buffer - buffer_;
2950 int rc_delta = (desc.buffer + desc.buffer_size) - (buffer_ + buffer_size_);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002951 MemMove(desc.buffer, buffer_, desc.instr_size);
2952 MemMove(reloc_info_writer.pos() + rc_delta, reloc_info_writer.pos(),
2953 desc.reloc_size);
Andrei Popescu31002712010-02-23 13:46:05 +00002954
2955 // Switch buffers.
2956 DeleteArray(buffer_);
2957 buffer_ = desc.buffer;
2958 buffer_size_ = desc.buffer_size;
2959 pc_ += pc_delta;
2960 reloc_info_writer.Reposition(reloc_info_writer.pos() + rc_delta,
2961 reloc_info_writer.last_pc() + pc_delta);
2962
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002963 // Relocate runtime entries.
2964 for (RelocIterator it(desc); !it.done(); it.next()) {
2965 RelocInfo::Mode rmode = it.rinfo()->rmode();
Ben Murdoch014dc512016-03-22 12:00:34 +00002966 if (rmode == RelocInfo::INTERNAL_REFERENCE_ENCODED ||
2967 rmode == RelocInfo::INTERNAL_REFERENCE) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002968 byte* p = reinterpret_cast<byte*>(it.rinfo()->pc());
Ben Murdoch014dc512016-03-22 12:00:34 +00002969 RelocateInternalReference(rmode, p, pc_delta);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002970 }
2971 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002972 DCHECK(!overflow());
Andrei Popescu31002712010-02-23 13:46:05 +00002973}
2974
2975
Steve Block44f0eee2011-05-26 01:26:41 +01002976void Assembler::db(uint8_t data) {
Ben Murdoch014dc512016-03-22 12:00:34 +00002977 CheckForEmitInForbiddenSlot();
2978 EmitHelper(data);
Steve Block44f0eee2011-05-26 01:26:41 +01002979}
2980
2981
2982void Assembler::dd(uint32_t data) {
Ben Murdoch014dc512016-03-22 12:00:34 +00002983 CheckForEmitInForbiddenSlot();
2984 EmitHelper(data);
Steve Block44f0eee2011-05-26 01:26:41 +01002985}
2986
2987
Ben Murdoch014dc512016-03-22 12:00:34 +00002988void Assembler::dq(uint64_t data) {
2989 CheckForEmitInForbiddenSlot();
2990 EmitHelper(data);
2991}
2992
2993
2994void Assembler::dd(Label* label) {
2995 uint32_t data;
2996 CheckForEmitInForbiddenSlot();
2997 if (label->is_bound()) {
2998 data = reinterpret_cast<uint32_t>(buffer_ + label->pos());
2999 } else {
3000 data = jump_address(label);
Ben Murdochbcf72ee2016-08-08 18:44:38 +01003001 unbound_labels_count_++;
Ben Murdoch014dc512016-03-22 12:00:34 +00003002 internal_reference_positions_.insert(label->pos());
3003 }
3004 RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE);
3005 EmitHelper(data);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003006}
3007
3008
Andrei Popescu31002712010-02-23 13:46:05 +00003009void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003010 // We do not try to reuse pool constants.
Ben Murdoch014dc512016-03-22 12:00:34 +00003011 RelocInfo rinfo(isolate(), pc_, rmode, data, NULL);
3012 if (rmode >= RelocInfo::COMMENT &&
Ben Murdoch3b9bc312016-06-02 14:46:10 +01003013 rmode <= RelocInfo::DEBUG_BREAK_SLOT_AT_TAIL_CALL) {
Andrei Popescu31002712010-02-23 13:46:05 +00003014 // Adjust code for new modes.
Ben Murdochf91f0612016-11-29 16:50:11 +00003015 DCHECK(RelocInfo::IsDebugBreakSlot(rmode) || RelocInfo::IsComment(rmode));
Andrei Popescu31002712010-02-23 13:46:05 +00003016 // These modes do not need an entry in the constant pool.
3017 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003018 if (!RelocInfo::IsNone(rinfo.rmode())) {
Andrei Popescu31002712010-02-23 13:46:05 +00003019 // Don't record external references unless the heap will be serialized.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003020 if (rmode == RelocInfo::EXTERNAL_REFERENCE &&
3021 !serializer_enabled() && !emit_debug_code()) {
3022 return;
Andrei Popescu31002712010-02-23 13:46:05 +00003023 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003024 DCHECK(buffer_space() >= kMaxRelocSize); // Too late to grow buffer here.
Ben Murdoch257744e2011-11-30 15:57:28 +00003025 if (rmode == RelocInfo::CODE_TARGET_WITH_ID) {
Ben Murdoch014dc512016-03-22 12:00:34 +00003026 RelocInfo reloc_info_with_ast_id(isolate(), pc_, rmode,
3027 RecordedAstId().ToInt(), NULL);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003028 ClearRecordedAstId();
Ben Murdoch257744e2011-11-30 15:57:28 +00003029 reloc_info_writer.Write(&reloc_info_with_ast_id);
3030 } else {
3031 reloc_info_writer.Write(&rinfo);
3032 }
Andrei Popescu31002712010-02-23 13:46:05 +00003033 }
3034}
3035
3036
Steve Block44f0eee2011-05-26 01:26:41 +01003037void Assembler::BlockTrampolinePoolFor(int instructions) {
Ben Murdoch014dc512016-03-22 12:00:34 +00003038 CheckTrampolinePoolQuick(instructions);
Steve Block44f0eee2011-05-26 01:26:41 +01003039 BlockTrampolinePoolBefore(pc_offset() + instructions * kInstrSize);
3040}
3041
3042
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003043void Assembler::CheckTrampolinePool() {
Steve Block44f0eee2011-05-26 01:26:41 +01003044 // Some small sequences of instructions must not be broken up by the
3045 // insertion of a trampoline pool; such sequences are protected by setting
3046 // either trampoline_pool_blocked_nesting_ or no_trampoline_pool_before_,
3047 // which are both checked here. Also, recursive calls to CheckTrampolinePool
3048 // are blocked by trampoline_pool_blocked_nesting_.
3049 if ((trampoline_pool_blocked_nesting_ > 0) ||
3050 (pc_offset() < no_trampoline_pool_before_)) {
3051 // Emission is currently blocked; make sure we try again as soon as
3052 // possible.
3053 if (trampoline_pool_blocked_nesting_ > 0) {
3054 next_buffer_check_ = pc_offset() + kInstrSize;
3055 } else {
3056 next_buffer_check_ = no_trampoline_pool_before_;
3057 }
3058 return;
3059 }
3060
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003061 DCHECK(!trampoline_emitted_);
3062 DCHECK(unbound_labels_count_ >= 0);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003063 if (unbound_labels_count_ > 0) {
3064 // First we emit jump (2 instructions), then we emit trampoline pool.
3065 { BlockTrampolinePoolScope block_trampoline_pool(this);
3066 Label after_pool;
Ben Murdoch014dc512016-03-22 12:00:34 +00003067 if (IsMipsArchVariant(kMips32r6)) {
3068 bc(&after_pool);
3069 } else {
3070 b(&after_pool);
3071 nop();
3072 }
Steve Block44f0eee2011-05-26 01:26:41 +01003073
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003074 int pool_start = pc_offset();
Ben Murdoch3b9bc312016-06-02 14:46:10 +01003075 if (IsMipsArchVariant(kMips32r6)) {
3076 for (int i = 0; i < unbound_labels_count_; i++) {
3077 uint32_t imm32;
3078 imm32 = jump_address(&after_pool);
3079 uint32_t lui_offset, jic_offset;
3080 UnpackTargetAddressUnsigned(imm32, lui_offset, jic_offset);
3081 {
3082 BlockGrowBufferScope block_buf_growth(this);
3083 // Buffer growth (and relocation) must be blocked for internal
3084 // references until associated instructions are emitted and
3085 // available to be patched.
3086 RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE_ENCODED);
3087 lui(at, lui_offset);
3088 jic(at, jic_offset);
3089 }
3090 CheckBuffer();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003091 }
Ben Murdoch3b9bc312016-06-02 14:46:10 +01003092 } else {
3093 for (int i = 0; i < unbound_labels_count_; i++) {
3094 uint32_t imm32;
3095 imm32 = jump_address(&after_pool);
3096 {
3097 BlockGrowBufferScope block_buf_growth(this);
3098 // Buffer growth (and relocation) must be blocked for internal
3099 // references until associated instructions are emitted and
3100 // available to be patched.
3101 RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE_ENCODED);
3102 lui(at, (imm32 & kHiMask) >> kLuiShift);
3103 ori(at, at, (imm32 & kImm16Mask));
3104 }
3105 CheckBuffer();
3106 jr(at);
3107 nop();
3108 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003109 }
3110 bind(&after_pool);
3111 trampoline_ = Trampoline(pool_start, unbound_labels_count_);
3112
3113 trampoline_emitted_ = true;
3114 // As we are only going to emit trampoline once, we need to prevent any
3115 // further emission.
3116 next_buffer_check_ = kMaxInt;
3117 }
3118 } else {
3119 // Number of branches to unbound label at this point is zero, so we can
3120 // move next buffer check to maximum.
3121 next_buffer_check_ = pc_offset() +
3122 kMaxBranchOffset - kTrampolineSlotsSize * 16;
Steve Block44f0eee2011-05-26 01:26:41 +01003123 }
3124 return;
3125}
3126
3127
Andrei Popescu31002712010-02-23 13:46:05 +00003128Address Assembler::target_address_at(Address pc) {
3129 Instr instr1 = instr_at(pc);
3130 Instr instr2 = instr_at(pc + kInstrSize);
Ben Murdoch257744e2011-11-30 15:57:28 +00003131 // Interpret 2 instructions generated by li: lui/ori
Ben Murdoch3b9bc312016-06-02 14:46:10 +01003132 if (IsLui(instr1) && IsOri(instr2)) {
Ben Murdoch257744e2011-11-30 15:57:28 +00003133 // Assemble the 32 bit value.
Ben Murdoch3b9bc312016-06-02 14:46:10 +01003134 return reinterpret_cast<Address>((GetImmediate16(instr1) << kLuiShift) |
3135 GetImmediate16(instr2));
Andrei Popescu31002712010-02-23 13:46:05 +00003136 }
3137
Ben Murdoch257744e2011-11-30 15:57:28 +00003138 // We should never get here, force a bad address if we do.
Andrei Popescu31002712010-02-23 13:46:05 +00003139 UNREACHABLE();
3140 return (Address)0x0;
3141}
3142
3143
Ben Murdochdb1b4382012-04-26 19:03:50 +01003144// MIPS and ia32 use opposite encoding for qNaN and sNaN, such that ia32
3145// qNaN is a MIPS sNaN, and ia32 sNaN is MIPS qNaN. If running from a heap
3146// snapshot generated on ia32, the resulting MIPS sNaN must be quieted.
3147// OS::nan_value() returns a qNaN.
3148void Assembler::QuietNaN(HeapObject* object) {
Ben Murdoch014dc512016-03-22 12:00:34 +00003149 HeapNumber::cast(object)->set_value(std::numeric_limits<double>::quiet_NaN());
Ben Murdochdb1b4382012-04-26 19:03:50 +01003150}
3151
3152
Ben Murdoch589d6972011-11-30 16:04:58 +00003153// On Mips, a target address is stored in a lui/ori instruction pair, each
3154// of which load 16 bits of the 32-bit address to a register.
3155// Patching the address must replace both instr, and flush the i-cache.
Ben Murdoch3b9bc312016-06-02 14:46:10 +01003156// On r6, target address is stored in a lui/jic pair, and both instr have to be
3157// patched.
Ben Murdoch589d6972011-11-30 16:04:58 +00003158//
3159// There is an optimization below, which emits a nop when the address
3160// fits in just 16 bits. This is unlikely to help, and should be benchmarked,
3161// and possibly removed.
Ben Murdoch014dc512016-03-22 12:00:34 +00003162void Assembler::set_target_address_at(Isolate* isolate, Address pc,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003163 Address target,
3164 ICacheFlushMode icache_flush_mode) {
Andrei Popescu31002712010-02-23 13:46:05 +00003165 Instr instr2 = instr_at(pc + kInstrSize);
Ben Murdoch257744e2011-11-30 15:57:28 +00003166 uint32_t rt_code = GetRtField(instr2);
Andrei Popescu31002712010-02-23 13:46:05 +00003167 uint32_t* p = reinterpret_cast<uint32_t*>(pc);
3168 uint32_t itarget = reinterpret_cast<uint32_t>(target);
3169
Ben Murdoch589d6972011-11-30 16:04:58 +00003170#ifdef DEBUG
3171 // Check we have the result from a li macro-instruction, using instr pair.
3172 Instr instr1 = instr_at(pc);
Ben Murdoch3b9bc312016-06-02 14:46:10 +01003173 CHECK(IsLui(instr1) && (IsOri(instr2) || IsJicOrJialc(instr2)));
Ben Murdoch589d6972011-11-30 16:04:58 +00003174#endif
3175
Ben Murdoch3b9bc312016-06-02 14:46:10 +01003176 if (IsJicOrJialc(instr2)) {
3177 // Must use 2 instructions to insure patchable code => use lui and jic
3178 uint32_t lui_offset, jic_offset;
3179 Assembler::UnpackTargetAddressUnsigned(itarget, lui_offset, jic_offset);
Andrei Popescu31002712010-02-23 13:46:05 +00003180
Ben Murdoch3b9bc312016-06-02 14:46:10 +01003181 *p &= ~kImm16Mask;
3182 *(p + 1) &= ~kImm16Mask;
3183
3184 *p |= lui_offset;
3185 *(p + 1) |= jic_offset;
3186
3187 } else {
3188 // Must use 2 instructions to insure patchable code => just use lui and ori.
3189 // lui rt, upper-16.
3190 // ori rt rt, lower-16.
3191 *p = LUI | rt_code | ((itarget & kHiMask) >> kLuiShift);
3192 *(p + 1) = ORI | rt_code | (rt_code << 5) | (itarget & kImm16Mask);
3193 }
Ben Murdoch589d6972011-11-30 16:04:58 +00003194
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003195 if (icache_flush_mode != SKIP_ICACHE_FLUSH) {
Ben Murdoch014dc512016-03-22 12:00:34 +00003196 Assembler::FlushICache(isolate, pc, 2 * sizeof(int32_t));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003197 }
Andrei Popescu31002712010-02-23 13:46:05 +00003198}
3199
Ben Murdoch014dc512016-03-22 12:00:34 +00003200} // namespace internal
3201} // namespace v8
Andrei Popescu31002712010-02-23 13:46:05 +00003202
Leon Clarkef7060e22010-06-03 12:02:55 +01003203#endif // V8_TARGET_ARCH_MIPS