blob: 3e8be7d75aa156e63ee4ec63a0fd52f29a01841b [file] [log] [blame]
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001// 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
6// are 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
14// distribution.
15//
16// - Neither the name of Sun Microsystems or the names of contributors may
17// be used to endorse or promote products derived from this software without
18// specific prior written permission.
19//
20// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
31// OF THE POSSIBILITY OF SUCH DAMAGE.
32
33// The original source code covered by the above license above has been
34// modified significantly by Google Inc.
35// Copyright 2014 the V8 project authors. All rights reserved.
36
37// A light-weight PPC Assembler
38// Generates user mode instructions for the PPC architecture up
39
40#ifndef V8_PPC_ASSEMBLER_PPC_H_
41#define V8_PPC_ASSEMBLER_PPC_H_
42
43#include <stdio.h>
44#include <vector>
45
46#include "src/assembler.h"
47#include "src/ppc/constants-ppc.h"
Emily Bernierd0a1eb72015-03-24 16:35:39 -040048
Ben Murdoch097c5b22016-05-18 11:27:45 +010049#if V8_HOST_ARCH_PPC && \
50 (V8_OS_AIX || (V8_TARGET_ARCH_PPC64 && V8_TARGET_BIG_ENDIAN))
51#define ABI_USES_FUNCTION_DESCRIPTORS 1
52#else
53#define ABI_USES_FUNCTION_DESCRIPTORS 0
54#endif
Emily Bernierd0a1eb72015-03-24 16:35:39 -040055
Ben Murdoch097c5b22016-05-18 11:27:45 +010056#if !V8_HOST_ARCH_PPC || V8_OS_AIX || V8_TARGET_ARCH_PPC64
57#define ABI_PASSES_HANDLES_IN_REGS 1
58#else
59#define ABI_PASSES_HANDLES_IN_REGS 0
60#endif
Emily Bernierd0a1eb72015-03-24 16:35:39 -040061
Ben Murdoch097c5b22016-05-18 11:27:45 +010062#if !V8_HOST_ARCH_PPC || !V8_TARGET_ARCH_PPC64 || V8_TARGET_LITTLE_ENDIAN
63#define ABI_RETURNS_OBJECT_PAIRS_IN_REGS 1
64#else
65#define ABI_RETURNS_OBJECT_PAIRS_IN_REGS 0
66#endif
Emily Bernierd0a1eb72015-03-24 16:35:39 -040067
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000068#if !V8_HOST_ARCH_PPC || (V8_TARGET_ARCH_PPC64 && V8_TARGET_LITTLE_ENDIAN)
69#define ABI_CALL_VIA_IP 1
70#else
71#define ABI_CALL_VIA_IP 0
72#endif
Emily Bernierd0a1eb72015-03-24 16:35:39 -040073
74#if !V8_HOST_ARCH_PPC || V8_OS_AIX || V8_TARGET_ARCH_PPC64
Ben Murdoch097c5b22016-05-18 11:27:45 +010075#define ABI_TOC_REGISTER 2
Emily Bernierd0a1eb72015-03-24 16:35:39 -040076#else
Ben Murdoch097c5b22016-05-18 11:27:45 +010077#define ABI_TOC_REGISTER 13
Emily Bernierd0a1eb72015-03-24 16:35:39 -040078#endif
79
80#define INSTR_AND_DATA_CACHE_COHERENCY LWSYNC
81
82namespace v8 {
83namespace internal {
84
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000085// clang-format off
86#define GENERAL_REGISTERS(V) \
87 V(r0) V(sp) V(r2) V(r3) V(r4) V(r5) V(r6) V(r7) \
88 V(r8) V(r9) V(r10) V(r11) V(ip) V(r13) V(r14) V(r15) \
89 V(r16) V(r17) V(r18) V(r19) V(r20) V(r21) V(r22) V(r23) \
90 V(r24) V(r25) V(r26) V(r27) V(r28) V(r29) V(r30) V(fp)
91
92#if V8_EMBEDDED_CONSTANT_POOL
93#define ALLOCATABLE_GENERAL_REGISTERS(V) \
94 V(r3) V(r4) V(r5) V(r6) V(r7) \
95 V(r8) V(r9) V(r10) V(r14) V(r15) \
96 V(r16) V(r17) V(r18) V(r19) V(r20) V(r21) V(r22) V(r23) \
97 V(r24) V(r25) V(r26) V(r27) V(r30)
98#else
99#define ALLOCATABLE_GENERAL_REGISTERS(V) \
100 V(r3) V(r4) V(r5) V(r6) V(r7) \
101 V(r8) V(r9) V(r10) V(r14) V(r15) \
102 V(r16) V(r17) V(r18) V(r19) V(r20) V(r21) V(r22) V(r23) \
103 V(r24) V(r25) V(r26) V(r27) V(r28) V(r30)
104#endif
105
106#define DOUBLE_REGISTERS(V) \
107 V(d0) V(d1) V(d2) V(d3) V(d4) V(d5) V(d6) V(d7) \
108 V(d8) V(d9) V(d10) V(d11) V(d12) V(d13) V(d14) V(d15) \
109 V(d16) V(d17) V(d18) V(d19) V(d20) V(d21) V(d22) V(d23) \
110 V(d24) V(d25) V(d26) V(d27) V(d28) V(d29) V(d30) V(d31)
111
112#define ALLOCATABLE_DOUBLE_REGISTERS(V) \
113 V(d1) V(d2) V(d3) V(d4) V(d5) V(d6) V(d7) \
114 V(d8) V(d9) V(d10) V(d11) V(d12) V(d15) \
115 V(d16) V(d17) V(d18) V(d19) V(d20) V(d21) V(d22) V(d23) \
116 V(d24) V(d25) V(d26) V(d27) V(d28) V(d29) V(d30) V(d31)
117// clang-format on
118
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400119// CPU Registers.
120//
121// 1) We would prefer to use an enum, but enum values are assignment-
122// compatible with int, which has caused code-generation bugs.
123//
124// 2) We would prefer to use a class instead of a struct but we don't like
125// the register initialization to depend on the particular initialization
126// order (which appears to be different on OS X, Linux, and Windows for the
127// installed versions of C++ we tried). Using a struct permits C-style
128// "initialization". Also, the Register objects cannot be const as this
129// forces initialization stubs in MSVC, making us dependent on initialization
130// order.
131//
132// 3) By not using an enum, we are possibly preventing the compiler from
133// doing certain constant folds, which may significantly reduce the
134// code generated for some assembly instructions (because they boil down
135// to a few constants). If this is a problem, we could change the code
136// such that we use an enum in optimized mode, and the struct in debug
137// mode. This way we get the compile-time error checking in debug mode
138// and best performance in optimized code.
139
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400140struct Register {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000141 enum Code {
142#define REGISTER_CODE(R) kCode_##R,
143 GENERAL_REGISTERS(REGISTER_CODE)
144#undef REGISTER_CODE
145 kAfterLast,
146 kCode_no_reg = -1
147 };
148
149 static const int kNumRegisters = Code::kAfterLast;
150
151#define REGISTER_COUNT(R) 1 +
152 static const int kNumAllocatable =
153 ALLOCATABLE_GENERAL_REGISTERS(REGISTER_COUNT)0;
154#undef REGISTER_COUNT
155
156#define REGISTER_BIT(R) 1 << kCode_##R |
157 static const RegList kAllocatable =
158 ALLOCATABLE_GENERAL_REGISTERS(REGISTER_BIT)0;
159#undef REGISTER_BIT
160
161 static Register from_code(int code) {
162 DCHECK(code >= 0);
163 DCHECK(code < kNumRegisters);
164 Register r = {code};
165 return r;
166 }
167 const char* ToString();
168 bool IsAllocatable() const;
169 bool is_valid() const { return 0 <= reg_code && reg_code < kNumRegisters; }
170 bool is(Register reg) const { return reg_code == reg.reg_code; }
171 int code() const {
172 DCHECK(is_valid());
173 return reg_code;
174 }
175 int bit() const {
176 DCHECK(is_valid());
177 return 1 << reg_code;
178 }
179 void set_code(int code) {
180 reg_code = code;
181 DCHECK(is_valid());
182 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400183
184#if V8_TARGET_LITTLE_ENDIAN
185 static const int kMantissaOffset = 0;
186 static const int kExponentOffset = 4;
187#else
188 static const int kMantissaOffset = 4;
189 static const int kExponentOffset = 0;
190#endif
191
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400192 // Unfortunately we can't make this private in a struct.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000193 int reg_code;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400194};
195
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000196#define DECLARE_REGISTER(R) const Register R = {Register::kCode_##R};
197GENERAL_REGISTERS(DECLARE_REGISTER)
198#undef DECLARE_REGISTER
199const Register no_reg = {Register::kCode_no_reg};
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400200
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000201// Aliases
202const Register kLithiumScratch = r11; // lithium scratch.
203const Register kConstantPoolRegister = r28; // Constant pool.
204const Register kRootRegister = r29; // Roots array pointer.
205const Register cp = r30; // JavaScript context pointer.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400206
207// Double word FP register.
208struct DoubleRegister {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000209 enum Code {
210#define REGISTER_CODE(R) kCode_##R,
211 DOUBLE_REGISTERS(REGISTER_CODE)
212#undef REGISTER_CODE
213 kAfterLast,
214 kCode_no_reg = -1
215 };
216
217 static const int kNumRegisters = Code::kAfterLast;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400218 static const int kMaxNumRegisters = kNumRegisters;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400219
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000220 const char* ToString();
221 bool IsAllocatable() const;
222 bool is_valid() const { return 0 <= reg_code && reg_code < kNumRegisters; }
223 bool is(DoubleRegister reg) const { return reg_code == reg.reg_code; }
224 int code() const {
225 DCHECK(is_valid());
226 return reg_code;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400227 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000228 int bit() const {
229 DCHECK(is_valid());
230 return 1 << reg_code;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400231 }
232
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400233 static DoubleRegister from_code(int code) {
234 DoubleRegister r = {code};
235 return r;
236 }
237
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000238 int reg_code;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400239};
240
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000241#define DECLARE_REGISTER(R) \
242 const DoubleRegister R = {DoubleRegister::kCode_##R};
243DOUBLE_REGISTERS(DECLARE_REGISTER)
244#undef DECLARE_REGISTER
245const Register no_dreg = {Register::kCode_no_reg};
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400246
247// Aliases for double registers. Defined using #define instead of
248// "static const DoubleRegister&" because Clang complains otherwise when a
249// compilation unit that includes this header doesn't use the variables.
250#define kFirstCalleeSavedDoubleReg d14
251#define kLastCalleeSavedDoubleReg d31
252#define kDoubleRegZero d14
253#define kScratchDoubleReg d13
254
255Register ToRegister(int num);
256
257// Coprocessor register
258struct CRegister {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100259 bool is_valid() const { return 0 <= reg_code && reg_code < 8; }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000260 bool is(CRegister creg) const { return reg_code == creg.reg_code; }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400261 int code() const {
262 DCHECK(is_valid());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000263 return reg_code;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400264 }
265 int bit() const {
266 DCHECK(is_valid());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000267 return 1 << reg_code;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400268 }
269
270 // Unfortunately we can't make this private in a struct.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000271 int reg_code;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400272};
273
274
275const CRegister no_creg = {-1};
276
277const CRegister cr0 = {0};
278const CRegister cr1 = {1};
279const CRegister cr2 = {2};
280const CRegister cr3 = {3};
281const CRegister cr4 = {4};
282const CRegister cr5 = {5};
283const CRegister cr6 = {6};
284const CRegister cr7 = {7};
Ben Murdoch097c5b22016-05-18 11:27:45 +0100285
286// TODO(ppc) Define SIMD registers.
287typedef DoubleRegister Simd128Register;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400288
289// -----------------------------------------------------------------------------
290// Machine instruction Operands
291
292#if V8_TARGET_ARCH_PPC64
293const RelocInfo::Mode kRelocInfo_NONEPTR = RelocInfo::NONE64;
294#else
295const RelocInfo::Mode kRelocInfo_NONEPTR = RelocInfo::NONE32;
296#endif
297
298// Class Operand represents a shifter operand in data processing instructions
299class Operand BASE_EMBEDDED {
300 public:
301 // immediate
302 INLINE(explicit Operand(intptr_t immediate,
303 RelocInfo::Mode rmode = kRelocInfo_NONEPTR));
304 INLINE(static Operand Zero()) { return Operand(static_cast<intptr_t>(0)); }
305 INLINE(explicit Operand(const ExternalReference& f));
306 explicit Operand(Handle<Object> handle);
307 INLINE(explicit Operand(Smi* value));
308
309 // rm
310 INLINE(explicit Operand(Register rm));
311
312 // Return true if this is a register operand.
313 INLINE(bool is_reg() const);
314
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400315 bool must_output_reloc_info(const Assembler* assembler) const;
316
317 inline intptr_t immediate() const {
318 DCHECK(!rm_.is_valid());
319 return imm_;
320 }
321
322 Register rm() const { return rm_; }
323
324 private:
325 Register rm_;
326 intptr_t imm_; // valid if rm_ == no_reg
327 RelocInfo::Mode rmode_;
328
329 friend class Assembler;
330 friend class MacroAssembler;
331};
332
333
334// Class MemOperand represents a memory operand in load and store instructions
335// On PowerPC we have base register + 16bit signed value
336// Alternatively we can have a 16bit signed value immediate
337class MemOperand BASE_EMBEDDED {
338 public:
339 explicit MemOperand(Register rn, int32_t offset = 0);
340
341 explicit MemOperand(Register ra, Register rb);
342
343 int32_t offset() const {
344 DCHECK(rb_.is(no_reg));
345 return offset_;
346 }
347
348 // PowerPC - base register
349 Register ra() const {
350 DCHECK(!ra_.is(no_reg));
351 return ra_;
352 }
353
354 Register rb() const {
355 DCHECK(offset_ == 0 && !rb_.is(no_reg));
356 return rb_;
357 }
358
359 private:
360 Register ra_; // base
361 int32_t offset_; // offset
362 Register rb_; // index
363
364 friend class Assembler;
365};
366
367
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000368class DeferredRelocInfo {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400369 public:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000370 DeferredRelocInfo() {}
371 DeferredRelocInfo(int position, RelocInfo::Mode rmode, intptr_t data)
372 : position_(position), rmode_(rmode), data_(data) {}
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400373
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000374 int position() const { return position_; }
375 RelocInfo::Mode rmode() const { return rmode_; }
376 intptr_t data() const { return data_; }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400377
378 private:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000379 int position_;
380 RelocInfo::Mode rmode_;
381 intptr_t data_;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400382};
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400383
384
385class Assembler : public AssemblerBase {
386 public:
387 // Create an assembler. Instructions and relocation information are emitted
388 // into a buffer, with the instructions starting from the beginning and the
389 // relocation information starting from the end of the buffer. See CodeDesc
390 // for a detailed comment on the layout (globals.h).
391 //
392 // If the provided buffer is NULL, the assembler allocates and grows its own
393 // buffer, and buffer_size determines the initial buffer size. The buffer is
394 // owned by the assembler and deallocated upon destruction of the assembler.
395 //
396 // If the provided buffer is not NULL, the assembler uses the provided buffer
397 // for code generation and assumes its size to be buffer_size. If the buffer
398 // is too small, a fatal error occurs. No deallocation of the buffer is done
399 // upon destruction of the assembler.
400 Assembler(Isolate* isolate, void* buffer, int buffer_size);
401 virtual ~Assembler() {}
402
403 // GetCode emits any pending (non-emitted) code and fills the descriptor
404 // desc. GetCode() is idempotent; it returns the same result if no other
405 // Assembler functions are invoked in between GetCode() calls.
406 void GetCode(CodeDesc* desc);
407
408 // Label operations & relative jumps (PPUM Appendix D)
409 //
410 // Takes a branch opcode (cc) and a label (L) and generates
411 // either a backward branch or a forward branch and links it
412 // to the label fixup chain. Usage:
413 //
414 // Label L; // unbound label
415 // j(cc, &L); // forward branch to unbound label
416 // bind(&L); // bind label to the current pc
417 // j(cc, &L); // backward branch to bound label
418 // bind(&L); // illegal: a label may be bound only once
419 //
420 // Note: The same Label can be used for forward and backward branches
421 // but it may be bound only once.
422
423 void bind(Label* L); // binds an unbound label L to the current code position
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000424
425 // Links a label at the current pc_offset(). If already bound, returns the
426 // bound position. If already linked, returns the position of the prior link.
427 // Otherwise, returns the current pc_offset().
428 int link(Label* L);
429
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400430 // Determines if Label is bound and near enough so that a single
431 // branch instruction can be used to reach it.
432 bool is_near(Label* L, Condition cond);
433
434 // Returns the branch offset to the given label from the current code position
435 // Links the label to the current position if it is still unbound
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000436 int branch_offset(Label* L) {
437 if (L->is_unused() && !trampoline_emitted_) {
438 TrackBranch();
439 }
440 return link(L) - pc_offset();
441 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400442
443 // Puts a labels target address at the given position.
444 // The high 8 bits are set to zero.
445 void label_at_put(Label* L, int at_offset);
446
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000447 INLINE(static bool IsConstantPoolLoadStart(
448 Address pc, ConstantPoolEntry::Access* access = nullptr));
449 INLINE(static bool IsConstantPoolLoadEnd(
450 Address pc, ConstantPoolEntry::Access* access = nullptr));
451 INLINE(static int GetConstantPoolOffset(Address pc,
452 ConstantPoolEntry::Access access,
453 ConstantPoolEntry::Type type));
454 INLINE(void PatchConstantPoolAccessInstruction(
455 int pc_offset, int offset, ConstantPoolEntry::Access access,
456 ConstantPoolEntry::Type type));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400457
458 // Return the address in the constant pool of the code target address used by
459 // the branch/call instruction at pc, or the object in a mov.
460 INLINE(static Address target_constant_pool_address_at(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000461 Address pc, Address constant_pool, ConstantPoolEntry::Access access,
462 ConstantPoolEntry::Type type));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400463
464 // Read/Modify the code target address in the branch/call instruction at pc.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000465 INLINE(static Address target_address_at(Address pc, Address constant_pool));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400466 INLINE(static void set_target_address_at(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000467 Isolate* isolate, Address pc, Address constant_pool, Address target,
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400468 ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED));
469 INLINE(static Address target_address_at(Address pc, Code* code)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000470 Address constant_pool = code ? code->constant_pool() : NULL;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400471 return target_address_at(pc, constant_pool);
472 }
473 INLINE(static void set_target_address_at(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000474 Isolate* isolate, Address pc, Code* code, Address target,
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400475 ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000476 Address constant_pool = code ? code->constant_pool() : NULL;
477 set_target_address_at(isolate, pc, constant_pool, target,
478 icache_flush_mode);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400479 }
480
481 // Return the code target address at a call site from the return address
482 // of that call in the instruction stream.
483 inline static Address target_address_from_return_address(Address pc);
484
485 // Given the address of the beginning of a call, return the address
486 // in the instruction stream that the call will return to.
487 INLINE(static Address return_address_from_call_start(Address pc));
488
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400489 // This sets the branch destination.
490 // This is for calls and branches within generated code.
491 inline static void deserialization_set_special_target_at(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000492 Isolate* isolate, Address instruction_payload, Code* code,
493 Address target);
494
495 // This sets the internal reference at the pc.
496 inline static void deserialization_set_target_internal_reference_at(
497 Isolate* isolate, Address pc, Address target,
498 RelocInfo::Mode mode = RelocInfo::INTERNAL_REFERENCE);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400499
500 // Size of an instruction.
501 static const int kInstrSize = sizeof(Instr);
502
503 // Here we are patching the address in the LUI/ORI instruction pair.
504 // These values are used in the serialization process and must be zero for
505 // PPC platform, as Code, Embedded Object or External-reference pointers
506 // are split across two consecutive instructions and don't exist separately
507 // in the code, so the serializer should not step forwards in memory after
508 // a target is resolved and written.
509 static const int kSpecialTargetSize = 0;
510
511// Number of instructions to load an address via a mov sequence.
512#if V8_TARGET_ARCH_PPC64
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000513 static const int kMovInstructionsConstantPool = 1;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400514 static const int kMovInstructionsNoConstantPool = 5;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000515#if defined(V8_PPC_TAGGING_OPT)
516 static const int kTaggedLoadInstructions = 1;
517#else
518 static const int kTaggedLoadInstructions = 2;
519#endif
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400520#else
521 static const int kMovInstructionsConstantPool = 1;
522 static const int kMovInstructionsNoConstantPool = 2;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000523 static const int kTaggedLoadInstructions = 1;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400524#endif
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000525 static const int kMovInstructions = FLAG_enable_embedded_constant_pool
526 ? kMovInstructionsConstantPool
527 : kMovInstructionsNoConstantPool;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400528
529 // Distance between the instruction referring to the address of the call
530 // target and the return address.
531
532 // Call sequence is a FIXED_SEQUENCE:
533 // mov r8, @ call address
534 // mtlr r8
535 // blrl
536 // @ return address
537 static const int kCallTargetAddressOffset =
538 (kMovInstructions + 2) * kInstrSize;
539
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400540 // Distance between start of patched debug break slot and the emitted address
541 // to jump to.
542 // Patched debug break slot code is a FIXED_SEQUENCE:
543 // mov r0, <address>
544 // mtlr r0
545 // blrl
546 static const int kPatchDebugBreakSlotAddressOffset = 0 * kInstrSize;
547
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400548 // This is the length of the code sequence from SetDebugBreakAtSlot()
549 // FIXED_SEQUENCE
550 static const int kDebugBreakSlotInstructions =
551 kMovInstructionsNoConstantPool + 2;
552 static const int kDebugBreakSlotLength =
553 kDebugBreakSlotInstructions * kInstrSize;
554
555 static inline int encode_crbit(const CRegister& cr, enum CRBit crbit) {
556 return ((cr.code() * CRWIDTH) + crbit);
557 }
558
559 // ---------------------------------------------------------------------------
560 // Code generation
561
562 // Insert the smallest number of nop instructions
563 // possible to align the pc offset to a multiple
564 // of m. m must be a power of 2 (>= 4).
565 void Align(int m);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000566 // Insert the smallest number of zero bytes possible to align the pc offset
567 // to a mulitple of m. m must be a power of 2 (>= 2).
568 void DataAlign(int m);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400569 // Aligns code to something that's optimal for a jump target for the platform.
570 void CodeTargetAlign();
571
572 // Branch instructions
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000573 void bclr(BOfield bo, int condition_bit, LKBit lk);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400574 void blr();
575 void bc(int branch_offset, BOfield bo, int condition_bit, LKBit lk = LeaveLK);
576 void b(int branch_offset, LKBit lk);
577
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000578 void bcctr(BOfield bo, int condition_bit, LKBit lk);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400579 void bctr();
580 void bctrl();
581
582 // Convenience branch instructions using labels
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000583 void b(Label* L, LKBit lk = LeaveLK) { b(branch_offset(L), lk); }
584
585 inline CRegister cmpi_optimization(CRegister cr) {
586 // Check whether the branch is preceeded by an optimizable cmpi against 0.
587 // The cmpi can be deleted if it is also preceeded by an instruction that
588 // sets the register used by the compare and supports a dot form.
589 unsigned int sradi_mask = kOpcodeMask | kExt2OpcodeVariant2Mask;
590 unsigned int srawi_mask = kOpcodeMask | kExt2OpcodeMask;
591 int pos = pc_offset();
592 int cmpi_pos = pc_offset() - kInstrSize;
593
594 if (cmpi_pos > 0 && optimizable_cmpi_pos_ == cmpi_pos &&
595 cmpi_cr_.code() == cr.code() && last_bound_pos_ != pos) {
596 int xpos = cmpi_pos - kInstrSize;
597 int xinstr = instr_at(xpos);
598 int cmpi_ra = (instr_at(cmpi_pos) & 0x1f0000) >> 16;
599 // ra is at the same bit position for the three cases below.
600 int ra = (xinstr & 0x1f0000) >> 16;
601 if (cmpi_ra == ra) {
602 if ((xinstr & sradi_mask) == (EXT2 | SRADIX)) {
603 cr = cr0;
604 instr_at_put(xpos, xinstr | SetRC);
605 pc_ -= kInstrSize;
606 } else if ((xinstr & srawi_mask) == (EXT2 | SRAWIX)) {
607 cr = cr0;
608 instr_at_put(xpos, xinstr | SetRC);
609 pc_ -= kInstrSize;
610 } else if ((xinstr & kOpcodeMask) == ANDIx) {
611 cr = cr0;
612 pc_ -= kInstrSize;
613 // nothing to do here since andi. records.
614 }
615 // didn't match one of the above, must keep cmpwi.
616 }
617 }
618 return cr;
619 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400620
621 void bc_short(Condition cond, Label* L, CRegister cr = cr7,
622 LKBit lk = LeaveLK) {
623 DCHECK(cond != al);
624 DCHECK(cr.code() >= 0 && cr.code() <= 7);
625
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000626 cr = cmpi_optimization(cr);
627
628 int b_offset = branch_offset(L);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400629
630 switch (cond) {
631 case eq:
632 bc(b_offset, BT, encode_crbit(cr, CR_EQ), lk);
633 break;
634 case ne:
635 bc(b_offset, BF, encode_crbit(cr, CR_EQ), lk);
636 break;
637 case gt:
638 bc(b_offset, BT, encode_crbit(cr, CR_GT), lk);
639 break;
640 case le:
641 bc(b_offset, BF, encode_crbit(cr, CR_GT), lk);
642 break;
643 case lt:
644 bc(b_offset, BT, encode_crbit(cr, CR_LT), lk);
645 break;
646 case ge:
647 bc(b_offset, BF, encode_crbit(cr, CR_LT), lk);
648 break;
649 case unordered:
650 bc(b_offset, BT, encode_crbit(cr, CR_FU), lk);
651 break;
652 case ordered:
653 bc(b_offset, BF, encode_crbit(cr, CR_FU), lk);
654 break;
655 case overflow:
656 bc(b_offset, BT, encode_crbit(cr, CR_SO), lk);
657 break;
658 case nooverflow:
659 bc(b_offset, BF, encode_crbit(cr, CR_SO), lk);
660 break;
661 default:
662 UNIMPLEMENTED();
663 }
664 }
665
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000666 void bclr(Condition cond, CRegister cr = cr7, LKBit lk = LeaveLK) {
667 DCHECK(cond != al);
668 DCHECK(cr.code() >= 0 && cr.code() <= 7);
669
670 cr = cmpi_optimization(cr);
671
672 switch (cond) {
673 case eq:
674 bclr(BT, encode_crbit(cr, CR_EQ), lk);
675 break;
676 case ne:
677 bclr(BF, encode_crbit(cr, CR_EQ), lk);
678 break;
679 case gt:
680 bclr(BT, encode_crbit(cr, CR_GT), lk);
681 break;
682 case le:
683 bclr(BF, encode_crbit(cr, CR_GT), lk);
684 break;
685 case lt:
686 bclr(BT, encode_crbit(cr, CR_LT), lk);
687 break;
688 case ge:
689 bclr(BF, encode_crbit(cr, CR_LT), lk);
690 break;
691 case unordered:
692 bclr(BT, encode_crbit(cr, CR_FU), lk);
693 break;
694 case ordered:
695 bclr(BF, encode_crbit(cr, CR_FU), lk);
696 break;
697 case overflow:
698 bclr(BT, encode_crbit(cr, CR_SO), lk);
699 break;
700 case nooverflow:
701 bclr(BF, encode_crbit(cr, CR_SO), lk);
702 break;
703 default:
704 UNIMPLEMENTED();
705 }
706 }
707
708 void isel(Register rt, Register ra, Register rb, int cb);
709 void isel(Condition cond, Register rt, Register ra, Register rb,
710 CRegister cr = cr7) {
711 DCHECK(cond != al);
712 DCHECK(cr.code() >= 0 && cr.code() <= 7);
713
714 cr = cmpi_optimization(cr);
715
716 switch (cond) {
717 case eq:
718 isel(rt, ra, rb, encode_crbit(cr, CR_EQ));
719 break;
720 case ne:
721 isel(rt, rb, ra, encode_crbit(cr, CR_EQ));
722 break;
723 case gt:
724 isel(rt, ra, rb, encode_crbit(cr, CR_GT));
725 break;
726 case le:
727 isel(rt, rb, ra, encode_crbit(cr, CR_GT));
728 break;
729 case lt:
730 isel(rt, ra, rb, encode_crbit(cr, CR_LT));
731 break;
732 case ge:
733 isel(rt, rb, ra, encode_crbit(cr, CR_LT));
734 break;
735 case unordered:
736 isel(rt, ra, rb, encode_crbit(cr, CR_FU));
737 break;
738 case ordered:
739 isel(rt, rb, ra, encode_crbit(cr, CR_FU));
740 break;
741 case overflow:
742 isel(rt, ra, rb, encode_crbit(cr, CR_SO));
743 break;
744 case nooverflow:
745 isel(rt, rb, ra, encode_crbit(cr, CR_SO));
746 break;
747 default:
748 UNIMPLEMENTED();
749 }
750 }
751
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400752 void b(Condition cond, Label* L, CRegister cr = cr7, LKBit lk = LeaveLK) {
753 if (cond == al) {
754 b(L, lk);
755 return;
756 }
757
758 if ((L->is_bound() && is_near(L, cond)) || !is_trampoline_emitted()) {
759 bc_short(cond, L, cr, lk);
760 return;
761 }
762
763 Label skip;
764 Condition neg_cond = NegateCondition(cond);
765 bc_short(neg_cond, &skip, cr);
766 b(L, lk);
767 bind(&skip);
768 }
769
770 void bne(Label* L, CRegister cr = cr7, LKBit lk = LeaveLK) {
771 b(ne, L, cr, lk);
772 }
773 void beq(Label* L, CRegister cr = cr7, LKBit lk = LeaveLK) {
774 b(eq, L, cr, lk);
775 }
776 void blt(Label* L, CRegister cr = cr7, LKBit lk = LeaveLK) {
777 b(lt, L, cr, lk);
778 }
779 void bge(Label* L, CRegister cr = cr7, LKBit lk = LeaveLK) {
780 b(ge, L, cr, lk);
781 }
782 void ble(Label* L, CRegister cr = cr7, LKBit lk = LeaveLK) {
783 b(le, L, cr, lk);
784 }
785 void bgt(Label* L, CRegister cr = cr7, LKBit lk = LeaveLK) {
786 b(gt, L, cr, lk);
787 }
788 void bunordered(Label* L, CRegister cr = cr7, LKBit lk = LeaveLK) {
789 b(unordered, L, cr, lk);
790 }
791 void bordered(Label* L, CRegister cr = cr7, LKBit lk = LeaveLK) {
792 b(ordered, L, cr, lk);
793 }
794 void boverflow(Label* L, CRegister cr = cr0, LKBit lk = LeaveLK) {
795 b(overflow, L, cr, lk);
796 }
797 void bnooverflow(Label* L, CRegister cr = cr0, LKBit lk = LeaveLK) {
798 b(nooverflow, L, cr, lk);
799 }
800
801 // Decrement CTR; branch if CTR != 0
802 void bdnz(Label* L, LKBit lk = LeaveLK) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000803 bc(branch_offset(L), DCBNZ, 0, lk);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400804 }
805
806 // Data-processing instructions
807
808 void sub(Register dst, Register src1, Register src2, OEBit s = LeaveOE,
809 RCBit r = LeaveRC);
810
Ben Murdochda12d292016-06-02 14:46:10 +0100811 void subc(Register dst, Register src1, Register src2, OEBit s = LeaveOE,
812 RCBit r = LeaveRC);
813 void sube(Register dst, Register src1, Register src2, OEBit s = LeaveOE,
814 RCBit r = LeaveRC);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400815
Ben Murdochda12d292016-06-02 14:46:10 +0100816 void subfic(Register dst, Register src, const Operand& imm);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400817
818 void add(Register dst, Register src1, Register src2, OEBit s = LeaveOE,
819 RCBit r = LeaveRC);
820
821 void addc(Register dst, Register src1, Register src2, OEBit o = LeaveOE,
822 RCBit r = LeaveRC);
Ben Murdochda12d292016-06-02 14:46:10 +0100823 void adde(Register dst, Register src1, Register src2, OEBit o = LeaveOE,
824 RCBit r = LeaveRC);
825 void addze(Register dst, Register src1, OEBit o = LeaveOE, RCBit r = LeaveRC);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400826
827 void mullw(Register dst, Register src1, Register src2, OEBit o = LeaveOE,
828 RCBit r = LeaveRC);
829
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000830 void mulhw(Register dst, Register src1, Register src2, RCBit r = LeaveRC);
831 void mulhwu(Register dst, Register src1, Register src2, RCBit r = LeaveRC);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400832
833 void divw(Register dst, Register src1, Register src2, OEBit o = LeaveOE,
834 RCBit r = LeaveRC);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000835 void divwu(Register dst, Register src1, Register src2, OEBit o = LeaveOE,
836 RCBit r = LeaveRC);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400837
838 void addi(Register dst, Register src, const Operand& imm);
839 void addis(Register dst, Register src, const Operand& imm);
840 void addic(Register dst, Register src, const Operand& imm);
841
842 void and_(Register dst, Register src1, Register src2, RCBit rc = LeaveRC);
843 void andc(Register dst, Register src1, Register src2, RCBit rc = LeaveRC);
844 void andi(Register ra, Register rs, const Operand& imm);
845 void andis(Register ra, Register rs, const Operand& imm);
846 void nor(Register dst, Register src1, Register src2, RCBit r = LeaveRC);
847 void notx(Register dst, Register src, RCBit r = LeaveRC);
848 void ori(Register dst, Register src, const Operand& imm);
849 void oris(Register dst, Register src, const Operand& imm);
850 void orx(Register dst, Register src1, Register src2, RCBit rc = LeaveRC);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000851 void orc(Register dst, Register src1, Register src2, RCBit rc = LeaveRC);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400852 void xori(Register dst, Register src, const Operand& imm);
853 void xoris(Register ra, Register rs, const Operand& imm);
854 void xor_(Register dst, Register src1, Register src2, RCBit rc = LeaveRC);
855 void cmpi(Register src1, const Operand& src2, CRegister cr = cr7);
856 void cmpli(Register src1, const Operand& src2, CRegister cr = cr7);
857 void cmpwi(Register src1, const Operand& src2, CRegister cr = cr7);
858 void cmplwi(Register src1, const Operand& src2, CRegister cr = cr7);
859 void li(Register dst, const Operand& src);
860 void lis(Register dst, const Operand& imm);
861 void mr(Register dst, Register src);
862
863 void lbz(Register dst, const MemOperand& src);
864 void lbzx(Register dst, const MemOperand& src);
865 void lbzux(Register dst, const MemOperand& src);
866 void lhz(Register dst, const MemOperand& src);
867 void lhzx(Register dst, const MemOperand& src);
868 void lhzux(Register dst, const MemOperand& src);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000869 void lha(Register dst, const MemOperand& src);
870 void lhax(Register dst, const MemOperand& src);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400871 void lwz(Register dst, const MemOperand& src);
872 void lwzu(Register dst, const MemOperand& src);
873 void lwzx(Register dst, const MemOperand& src);
874 void lwzux(Register dst, const MemOperand& src);
875 void lwa(Register dst, const MemOperand& src);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000876 void lwax(Register dst, const MemOperand& src);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400877 void stb(Register dst, const MemOperand& src);
878 void stbx(Register dst, const MemOperand& src);
879 void stbux(Register dst, const MemOperand& src);
880 void sth(Register dst, const MemOperand& src);
881 void sthx(Register dst, const MemOperand& src);
882 void sthux(Register dst, const MemOperand& src);
883 void stw(Register dst, const MemOperand& src);
884 void stwu(Register dst, const MemOperand& src);
885 void stwx(Register rs, const MemOperand& src);
886 void stwux(Register rs, const MemOperand& src);
887
888 void extsb(Register rs, Register ra, RCBit r = LeaveRC);
889 void extsh(Register rs, Register ra, RCBit r = LeaveRC);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000890 void extsw(Register rs, Register ra, RCBit r = LeaveRC);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400891
892 void neg(Register rt, Register ra, OEBit o = LeaveOE, RCBit c = LeaveRC);
893
894#if V8_TARGET_ARCH_PPC64
895 void ld(Register rd, const MemOperand& src);
896 void ldx(Register rd, const MemOperand& src);
897 void ldu(Register rd, const MemOperand& src);
898 void ldux(Register rd, const MemOperand& src);
899 void std(Register rs, const MemOperand& src);
900 void stdx(Register rs, const MemOperand& src);
901 void stdu(Register rs, const MemOperand& src);
902 void stdux(Register rs, const MemOperand& src);
903 void rldic(Register dst, Register src, int sh, int mb, RCBit r = LeaveRC);
904 void rldicl(Register dst, Register src, int sh, int mb, RCBit r = LeaveRC);
905 void rldcl(Register ra, Register rs, Register rb, int mb, RCBit r = LeaveRC);
906 void rldicr(Register dst, Register src, int sh, int me, RCBit r = LeaveRC);
907 void rldimi(Register dst, Register src, int sh, int mb, RCBit r = LeaveRC);
908 void sldi(Register dst, Register src, const Operand& val, RCBit rc = LeaveRC);
909 void srdi(Register dst, Register src, const Operand& val, RCBit rc = LeaveRC);
910 void clrrdi(Register dst, Register src, const Operand& val,
911 RCBit rc = LeaveRC);
912 void clrldi(Register dst, Register src, const Operand& val,
913 RCBit rc = LeaveRC);
914 void sradi(Register ra, Register rs, int sh, RCBit r = LeaveRC);
915 void srd(Register dst, Register src1, Register src2, RCBit r = LeaveRC);
916 void sld(Register dst, Register src1, Register src2, RCBit r = LeaveRC);
917 void srad(Register dst, Register src1, Register src2, RCBit r = LeaveRC);
918 void rotld(Register ra, Register rs, Register rb, RCBit r = LeaveRC);
919 void rotldi(Register ra, Register rs, int sh, RCBit r = LeaveRC);
920 void rotrdi(Register ra, Register rs, int sh, RCBit r = LeaveRC);
921 void cntlzd_(Register dst, Register src, RCBit rc = LeaveRC);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000922 void popcntd(Register dst, Register src);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400923 void mulld(Register dst, Register src1, Register src2, OEBit o = LeaveOE,
924 RCBit r = LeaveRC);
925 void divd(Register dst, Register src1, Register src2, OEBit o = LeaveOE,
926 RCBit r = LeaveRC);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000927 void divdu(Register dst, Register src1, Register src2, OEBit o = LeaveOE,
928 RCBit r = LeaveRC);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400929#endif
930
931 void rlwinm(Register ra, Register rs, int sh, int mb, int me,
932 RCBit rc = LeaveRC);
933 void rlwimi(Register ra, Register rs, int sh, int mb, int me,
934 RCBit rc = LeaveRC);
935 void rlwnm(Register ra, Register rs, Register rb, int mb, int me,
936 RCBit rc = LeaveRC);
937 void slwi(Register dst, Register src, const Operand& val, RCBit rc = LeaveRC);
938 void srwi(Register dst, Register src, const Operand& val, RCBit rc = LeaveRC);
939 void clrrwi(Register dst, Register src, const Operand& val,
940 RCBit rc = LeaveRC);
941 void clrlwi(Register dst, Register src, const Operand& val,
942 RCBit rc = LeaveRC);
943 void srawi(Register ra, Register rs, int sh, RCBit r = LeaveRC);
944 void srw(Register dst, Register src1, Register src2, RCBit r = LeaveRC);
945 void slw(Register dst, Register src1, Register src2, RCBit r = LeaveRC);
946 void sraw(Register dst, Register src1, Register src2, RCBit r = LeaveRC);
947 void rotlw(Register ra, Register rs, Register rb, RCBit r = LeaveRC);
948 void rotlwi(Register ra, Register rs, int sh, RCBit r = LeaveRC);
949 void rotrwi(Register ra, Register rs, int sh, RCBit r = LeaveRC);
950
951 void cntlzw_(Register dst, Register src, RCBit rc = LeaveRC);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000952 void popcntw(Register dst, Register src);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400953
954 void subi(Register dst, Register src1, const Operand& src2);
955
956 void cmp(Register src1, Register src2, CRegister cr = cr7);
957 void cmpl(Register src1, Register src2, CRegister cr = cr7);
958 void cmpw(Register src1, Register src2, CRegister cr = cr7);
959 void cmplw(Register src1, Register src2, CRegister cr = cr7);
960
961 void mov(Register dst, const Operand& src);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000962 void bitwise_mov(Register dst, intptr_t value);
963 void bitwise_mov32(Register dst, int32_t value);
964 void bitwise_add32(Register dst, Register src, int32_t value);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400965
966 // Load the position of the label relative to the generated code object
967 // pointer in a register.
968 void mov_label_offset(Register dst, Label* label);
969
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000970 // dst = base + label position + delta
971 void add_label_offset(Register dst, Register base, Label* label,
972 int delta = 0);
973
974 // Load the address of the label in a register and associate with an
975 // internal reference relocation.
976 void mov_label_addr(Register dst, Label* label);
977
978 // Emit the address of the label (i.e. a jump table entry) and associate with
979 // an internal reference relocation.
980 void emit_label_addr(Label* label);
981
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400982 // Multiply instructions
983 void mul(Register dst, Register src1, Register src2, OEBit s = LeaveOE,
984 RCBit r = LeaveRC);
985
986 // Miscellaneous arithmetic instructions
987
988 // Special register access
989 void crxor(int bt, int ba, int bb);
990 void crclr(int bt) { crxor(bt, bt, bt); }
991 void creqv(int bt, int ba, int bb);
992 void crset(int bt) { creqv(bt, bt, bt); }
993 void mflr(Register dst);
994 void mtlr(Register src);
995 void mtctr(Register src);
996 void mtxer(Register src);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000997 void mcrfs(CRegister cr, FPSCRBit bit);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400998 void mfcr(Register dst);
999#if V8_TARGET_ARCH_PPC64
1000 void mffprd(Register dst, DoubleRegister src);
1001 void mffprwz(Register dst, DoubleRegister src);
1002 void mtfprd(DoubleRegister dst, Register src);
1003 void mtfprwz(DoubleRegister dst, Register src);
1004 void mtfprwa(DoubleRegister dst, Register src);
1005#endif
1006
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001007 void function_descriptor();
1008
1009 // Exception-generating instructions and debugging support
1010 void stop(const char* msg, Condition cond = al,
1011 int32_t code = kDefaultStopCode, CRegister cr = cr7);
1012
1013 void bkpt(uint32_t imm16); // v5 and above
1014
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001015 void dcbf(Register ra, Register rb);
1016 void sync();
1017 void lwsync();
1018 void icbi(Register ra, Register rb);
1019 void isync();
1020
1021 // Support for floating point
1022 void lfd(const DoubleRegister frt, const MemOperand& src);
1023 void lfdu(const DoubleRegister frt, const MemOperand& src);
1024 void lfdx(const DoubleRegister frt, const MemOperand& src);
1025 void lfdux(const DoubleRegister frt, const MemOperand& src);
1026 void lfs(const DoubleRegister frt, const MemOperand& src);
1027 void lfsu(const DoubleRegister frt, const MemOperand& src);
1028 void lfsx(const DoubleRegister frt, const MemOperand& src);
1029 void lfsux(const DoubleRegister frt, const MemOperand& src);
1030 void stfd(const DoubleRegister frs, const MemOperand& src);
1031 void stfdu(const DoubleRegister frs, const MemOperand& src);
1032 void stfdx(const DoubleRegister frs, const MemOperand& src);
1033 void stfdux(const DoubleRegister frs, const MemOperand& src);
1034 void stfs(const DoubleRegister frs, const MemOperand& src);
1035 void stfsu(const DoubleRegister frs, const MemOperand& src);
1036 void stfsx(const DoubleRegister frs, const MemOperand& src);
1037 void stfsux(const DoubleRegister frs, const MemOperand& src);
1038
1039 void fadd(const DoubleRegister frt, const DoubleRegister fra,
1040 const DoubleRegister frb, RCBit rc = LeaveRC);
1041 void fsub(const DoubleRegister frt, const DoubleRegister fra,
1042 const DoubleRegister frb, RCBit rc = LeaveRC);
1043 void fdiv(const DoubleRegister frt, const DoubleRegister fra,
1044 const DoubleRegister frb, RCBit rc = LeaveRC);
1045 void fmul(const DoubleRegister frt, const DoubleRegister fra,
1046 const DoubleRegister frc, RCBit rc = LeaveRC);
1047 void fcmpu(const DoubleRegister fra, const DoubleRegister frb,
1048 CRegister cr = cr7);
1049 void fmr(const DoubleRegister frt, const DoubleRegister frb,
1050 RCBit rc = LeaveRC);
1051 void fctiwz(const DoubleRegister frt, const DoubleRegister frb);
1052 void fctiw(const DoubleRegister frt, const DoubleRegister frb);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001053 void frin(const DoubleRegister frt, const DoubleRegister frb,
1054 RCBit rc = LeaveRC);
1055 void friz(const DoubleRegister frt, const DoubleRegister frb,
1056 RCBit rc = LeaveRC);
1057 void frip(const DoubleRegister frt, const DoubleRegister frb,
1058 RCBit rc = LeaveRC);
1059 void frim(const DoubleRegister frt, const DoubleRegister frb,
1060 RCBit rc = LeaveRC);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001061 void frsp(const DoubleRegister frt, const DoubleRegister frb,
1062 RCBit rc = LeaveRC);
1063 void fcfid(const DoubleRegister frt, const DoubleRegister frb,
1064 RCBit rc = LeaveRC);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001065 void fcfidu(const DoubleRegister frt, const DoubleRegister frb,
1066 RCBit rc = LeaveRC);
1067 void fcfidus(const DoubleRegister frt, const DoubleRegister frb,
1068 RCBit rc = LeaveRC);
1069 void fcfids(const DoubleRegister frt, const DoubleRegister frb,
1070 RCBit rc = LeaveRC);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001071 void fctid(const DoubleRegister frt, const DoubleRegister frb,
1072 RCBit rc = LeaveRC);
1073 void fctidz(const DoubleRegister frt, const DoubleRegister frb,
1074 RCBit rc = LeaveRC);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001075 void fctidu(const DoubleRegister frt, const DoubleRegister frb,
1076 RCBit rc = LeaveRC);
1077 void fctiduz(const DoubleRegister frt, const DoubleRegister frb,
1078 RCBit rc = LeaveRC);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001079 void fsel(const DoubleRegister frt, const DoubleRegister fra,
1080 const DoubleRegister frc, const DoubleRegister frb,
1081 RCBit rc = LeaveRC);
1082 void fneg(const DoubleRegister frt, const DoubleRegister frb,
1083 RCBit rc = LeaveRC);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001084 void mtfsb0(FPSCRBit bit, RCBit rc = LeaveRC);
1085 void mtfsb1(FPSCRBit bit, RCBit rc = LeaveRC);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001086 void mtfsfi(int bf, int immediate, RCBit rc = LeaveRC);
1087 void mffs(const DoubleRegister frt, RCBit rc = LeaveRC);
1088 void mtfsf(const DoubleRegister frb, bool L = 1, int FLM = 0, bool W = 0,
1089 RCBit rc = LeaveRC);
1090 void fsqrt(const DoubleRegister frt, const DoubleRegister frb,
1091 RCBit rc = LeaveRC);
1092 void fabs(const DoubleRegister frt, const DoubleRegister frb,
1093 RCBit rc = LeaveRC);
1094 void fmadd(const DoubleRegister frt, const DoubleRegister fra,
1095 const DoubleRegister frc, const DoubleRegister frb,
1096 RCBit rc = LeaveRC);
1097 void fmsub(const DoubleRegister frt, const DoubleRegister fra,
1098 const DoubleRegister frc, const DoubleRegister frb,
1099 RCBit rc = LeaveRC);
1100
1101 // Pseudo instructions
1102
1103 // Different nop operations are used by the code generator to detect certain
1104 // states of the generated code.
1105 enum NopMarkerTypes {
1106 NON_MARKING_NOP = 0,
1107 GROUP_ENDING_NOP,
1108 DEBUG_BREAK_NOP,
1109 // IC markers.
1110 PROPERTY_ACCESS_INLINED,
1111 PROPERTY_ACCESS_INLINED_CONTEXT,
1112 PROPERTY_ACCESS_INLINED_CONTEXT_DONT_DELETE,
1113 // Helper values.
1114 LAST_CODE_MARKER,
1115 FIRST_IC_MARKER = PROPERTY_ACCESS_INLINED
1116 };
1117
1118 void nop(int type = 0); // 0 is the default non-marking type.
1119
1120 void push(Register src) {
1121#if V8_TARGET_ARCH_PPC64
1122 stdu(src, MemOperand(sp, -kPointerSize));
1123#else
1124 stwu(src, MemOperand(sp, -kPointerSize));
1125#endif
1126 }
1127
1128 void pop(Register dst) {
1129#if V8_TARGET_ARCH_PPC64
1130 ld(dst, MemOperand(sp));
1131#else
1132 lwz(dst, MemOperand(sp));
1133#endif
1134 addi(sp, sp, Operand(kPointerSize));
1135 }
1136
1137 void pop() { addi(sp, sp, Operand(kPointerSize)); }
1138
1139 // Jump unconditionally to given label.
1140 void jmp(Label* L) { b(L); }
1141
1142 // Check the code size generated from label to here.
1143 int SizeOfCodeGeneratedSince(Label* label) {
1144 return pc_offset() - label->pos();
1145 }
1146
1147 // Check the number of instructions generated from label to here.
1148 int InstructionsGeneratedSince(Label* label) {
1149 return SizeOfCodeGeneratedSince(label) / kInstrSize;
1150 }
1151
1152 // Class for scoping postponing the trampoline pool generation.
1153 class BlockTrampolinePoolScope {
1154 public:
1155 explicit BlockTrampolinePoolScope(Assembler* assem) : assem_(assem) {
1156 assem_->StartBlockTrampolinePool();
1157 }
1158 ~BlockTrampolinePoolScope() { assem_->EndBlockTrampolinePool(); }
1159
1160 private:
1161 Assembler* assem_;
1162
1163 DISALLOW_IMPLICIT_CONSTRUCTORS(BlockTrampolinePoolScope);
1164 };
1165
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001166 // Class for scoping disabling constant pool entry merging
1167 class BlockConstantPoolEntrySharingScope {
1168 public:
1169 explicit BlockConstantPoolEntrySharingScope(Assembler* assem)
1170 : assem_(assem) {
1171 assem_->StartBlockConstantPoolEntrySharing();
1172 }
1173 ~BlockConstantPoolEntrySharingScope() {
1174 assem_->EndBlockConstantPoolEntrySharing();
1175 }
1176
1177 private:
1178 Assembler* assem_;
1179
1180 DISALLOW_IMPLICIT_CONSTRUCTORS(BlockConstantPoolEntrySharingScope);
1181 };
1182
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001183 // Debugging
1184
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001185 // Mark generator continuation.
1186 void RecordGeneratorContinuation();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001187
1188 // Mark address of a debug break slot.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001189 void RecordDebugBreakSlot(RelocInfo::Mode mode);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001190
1191 // Record the AST id of the CallIC being compiled, so that it can be placed
1192 // in the relocation information.
1193 void SetRecordedAstId(TypeFeedbackId ast_id) {
1194 // Causes compiler to fail
1195 // DCHECK(recorded_ast_id_.IsNone());
1196 recorded_ast_id_ = ast_id;
1197 }
1198
1199 TypeFeedbackId RecordedAstId() {
1200 // Causes compiler to fail
1201 // DCHECK(!recorded_ast_id_.IsNone());
1202 return recorded_ast_id_;
1203 }
1204
1205 void ClearRecordedAstId() { recorded_ast_id_ = TypeFeedbackId::None(); }
1206
1207 // Record a comment relocation entry that can be used by a disassembler.
1208 // Use --code-comments to enable.
1209 void RecordComment(const char* msg);
1210
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001211 // Record a deoptimization reason that can be used by a log or cpu profiler.
1212 // Use --trace-deopt to enable.
Ben Murdoch097c5b22016-05-18 11:27:45 +01001213 void RecordDeoptReason(const int reason, int raw_position);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001214
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001215 // Writes a single byte or word of data in the code stream. Used
1216 // for inline tables, e.g., jump-tables.
1217 void db(uint8_t data);
1218 void dd(uint32_t data);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001219 void dq(uint64_t data);
1220 void dp(uintptr_t data);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001221
Ben Murdochda12d292016-06-02 14:46:10 +01001222 AssemblerPositionsRecorder* positions_recorder() {
1223 return &positions_recorder_;
1224 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001225
1226 // Read/patch instructions
1227 Instr instr_at(int pos) { return *reinterpret_cast<Instr*>(buffer_ + pos); }
1228 void instr_at_put(int pos, Instr instr) {
1229 *reinterpret_cast<Instr*>(buffer_ + pos) = instr;
1230 }
1231 static Instr instr_at(byte* pc) { return *reinterpret_cast<Instr*>(pc); }
1232 static void instr_at_put(byte* pc, Instr instr) {
1233 *reinterpret_cast<Instr*>(pc) = instr;
1234 }
1235 static Condition GetCondition(Instr instr);
1236
1237 static bool IsLis(Instr instr);
1238 static bool IsLi(Instr instr);
1239 static bool IsAddic(Instr instr);
1240 static bool IsOri(Instr instr);
1241
1242 static bool IsBranch(Instr instr);
1243 static Register GetRA(Instr instr);
1244 static Register GetRB(Instr instr);
1245#if V8_TARGET_ARCH_PPC64
1246 static bool Is64BitLoadIntoR12(Instr instr1, Instr instr2, Instr instr3,
1247 Instr instr4, Instr instr5);
1248#else
1249 static bool Is32BitLoadIntoR12(Instr instr1, Instr instr2);
1250#endif
1251
1252 static bool IsCmpRegister(Instr instr);
1253 static bool IsCmpImmediate(Instr instr);
1254 static bool IsRlwinm(Instr instr);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001255 static bool IsAndi(Instr instr);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001256#if V8_TARGET_ARCH_PPC64
1257 static bool IsRldicl(Instr instr);
1258#endif
1259 static bool IsCrSet(Instr instr);
1260 static Register GetCmpImmediateRegister(Instr instr);
1261 static int GetCmpImmediateRawImmediate(Instr instr);
1262 static bool IsNop(Instr instr, int type = NON_MARKING_NOP);
1263
1264 // Postpone the generation of the trampoline pool for the specified number of
1265 // instructions.
1266 void BlockTrampolinePoolFor(int instructions);
1267 void CheckTrampolinePool();
1268
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001269 // For mov. Return the number of actual instructions required to
1270 // load the operand into a register. This can be anywhere from
1271 // one (constant pool small section) to five instructions (full
1272 // 64-bit sequence).
1273 //
1274 // The value returned is only valid as long as no entries are added to the
1275 // constant pool between this call and the actual instruction being emitted.
1276 int instructions_required_for_mov(Register dst, const Operand& src) const;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001277
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001278 // Decide between using the constant pool vs. a mov immediate sequence.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001279 bool use_constant_pool_for_mov(Register dst, const Operand& src,
1280 bool canOptimize) const;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001281
1282 // The code currently calls CheckBuffer() too often. This has the side
1283 // effect of randomly growing the buffer in the middle of multi-instruction
1284 // sequences.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001285 //
1286 // This function allows outside callers to check and grow the buffer
1287 void EnsureSpaceFor(int space_needed);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001288
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001289 int EmitConstantPool() { return constant_pool_builder_.Emit(this); }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001290
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001291 bool ConstantPoolAccessIsInOverflow() const {
1292 return constant_pool_builder_.NextAccess(ConstantPoolEntry::INTPTR) ==
1293 ConstantPoolEntry::OVERFLOWED;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001294 }
1295
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001296 Label* ConstantPoolPosition() {
1297 return constant_pool_builder_.EmittedPosition();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001298 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001299
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001300 void EmitRelocations();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001301
1302 protected:
1303 // Relocation for a type-recording IC has the AST id added to it. This
1304 // member variable is a way to pass the information from the call site to
1305 // the relocation info.
1306 TypeFeedbackId recorded_ast_id_;
1307
1308 int buffer_space() const { return reloc_info_writer.pos() - pc_; }
1309
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001310 // Decode instruction(s) at pos and return backchain to previous
1311 // label reference or kEndOfChain.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001312 int target_at(int pos);
1313
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001314 // Patch instruction(s) at pos to target target_pos (e.g. branch)
1315 void target_at_put(int pos, int target_pos, bool* is_branch = nullptr);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001316
1317 // Record reloc info for current pc_
1318 void RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data = 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001319 ConstantPoolEntry::Access ConstantPoolAddEntry(RelocInfo::Mode rmode,
1320 intptr_t value) {
1321 bool sharing_ok = RelocInfo::IsNone(rmode) ||
1322 !(serializer_enabled() || rmode < RelocInfo::CELL ||
1323 is_constant_pool_entry_sharing_blocked());
1324 return constant_pool_builder_.AddEntry(pc_offset(), value, sharing_ok);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001325 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001326 ConstantPoolEntry::Access ConstantPoolAddEntry(double value) {
1327 return constant_pool_builder_.AddEntry(pc_offset(), value);
1328 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001329
1330 // Block the emission of the trampoline pool before pc_offset.
1331 void BlockTrampolinePoolBefore(int pc_offset) {
1332 if (no_trampoline_pool_before_ < pc_offset)
1333 no_trampoline_pool_before_ = pc_offset;
1334 }
1335
1336 void StartBlockTrampolinePool() { trampoline_pool_blocked_nesting_++; }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001337 void EndBlockTrampolinePool() {
1338 int count = --trampoline_pool_blocked_nesting_;
1339 if (count == 0) CheckTrampolinePoolQuick();
1340 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001341 bool is_trampoline_pool_blocked() const {
1342 return trampoline_pool_blocked_nesting_ > 0;
1343 }
1344
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001345 void StartBlockConstantPoolEntrySharing() {
1346 constant_pool_entry_sharing_blocked_nesting_++;
1347 }
1348 void EndBlockConstantPoolEntrySharing() {
1349 constant_pool_entry_sharing_blocked_nesting_--;
1350 }
1351 bool is_constant_pool_entry_sharing_blocked() const {
1352 return constant_pool_entry_sharing_blocked_nesting_ > 0;
1353 }
1354
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001355 bool has_exception() const { return internal_trampoline_exception_; }
1356
1357 bool is_trampoline_emitted() const { return trampoline_emitted_; }
1358
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001359 private:
1360 // Code generation
1361 // The relocation writer's position is at least kGap bytes below the end of
1362 // the generated instructions. This is so that multi-instruction sequences do
1363 // not have to check for overflow. The same is true for writes of large
1364 // relocation info entries.
1365 static const int kGap = 32;
1366
1367 // Repeated checking whether the trampoline pool should be emitted is rather
1368 // expensive. By default we only check again once a number of instructions
1369 // has been generated.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001370 int next_trampoline_check_; // pc offset of next buffer check.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001371
1372 // Emission of the trampoline pool may be blocked in some code sequences.
1373 int trampoline_pool_blocked_nesting_; // Block emission if this is not zero.
1374 int no_trampoline_pool_before_; // Block emission before this pc offset.
1375
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001376 // Do not share constant pool entries.
1377 int constant_pool_entry_sharing_blocked_nesting_;
1378
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001379 // Relocation info generation
1380 // Each relocation is encoded as a variable size value
1381 static const int kMaxRelocSize = RelocInfoWriter::kMaxSize;
1382 RelocInfoWriter reloc_info_writer;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001383 std::vector<DeferredRelocInfo> relocations_;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001384
1385 // The bound position, before this we cannot do instruction elimination.
1386 int last_bound_pos_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001387 // Optimizable cmpi information.
1388 int optimizable_cmpi_pos_;
1389 CRegister cmpi_cr_;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001390
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001391 ConstantPoolBuilder constant_pool_builder_;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001392
1393 // Code emission
1394 inline void CheckBuffer();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001395 void GrowBuffer(int needed = 0);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001396 inline void emit(Instr x);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001397 inline void TrackBranch();
1398 inline void UntrackBranch();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001399 inline void CheckTrampolinePoolQuick();
1400
1401 // Instruction generation
1402 void a_form(Instr instr, DoubleRegister frt, DoubleRegister fra,
1403 DoubleRegister frb, RCBit r);
1404 void d_form(Instr instr, Register rt, Register ra, const intptr_t val,
1405 bool signed_disp);
1406 void x_form(Instr instr, Register ra, Register rs, Register rb, RCBit r);
1407 void xo_form(Instr instr, Register rt, Register ra, Register rb, OEBit o,
1408 RCBit r);
1409 void md_form(Instr instr, Register ra, Register rs, int shift, int maskbit,
1410 RCBit r);
1411 void mds_form(Instr instr, Register ra, Register rs, Register rb, int maskbit,
1412 RCBit r);
1413
1414 // Labels
1415 void print(Label* L);
1416 int max_reach_from(int pos);
1417 void bind_to(Label* L, int pos);
1418 void next(Label* L);
1419
1420 class Trampoline {
1421 public:
1422 Trampoline() {
1423 next_slot_ = 0;
1424 free_slot_count_ = 0;
1425 }
1426 Trampoline(int start, int slot_count) {
1427 next_slot_ = start;
1428 free_slot_count_ = slot_count;
1429 }
1430 int take_slot() {
1431 int trampoline_slot = kInvalidSlotPos;
1432 if (free_slot_count_ <= 0) {
1433 // We have run out of space on trampolines.
1434 // Make sure we fail in debug mode, so we become aware of each case
1435 // when this happens.
1436 DCHECK(0);
1437 // Internal exception will be caught.
1438 } else {
1439 trampoline_slot = next_slot_;
1440 free_slot_count_--;
1441 next_slot_ += kTrampolineSlotsSize;
1442 }
1443 return trampoline_slot;
1444 }
1445
1446 private:
1447 int next_slot_;
1448 int free_slot_count_;
1449 };
1450
1451 int32_t get_trampoline_entry();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001452 int tracked_branch_count_;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001453 // If trampoline is emitted, generated code is becoming large. As
1454 // this is already a slow case which can possibly break our code
1455 // generation for the extreme case, we use this information to
1456 // trigger different mode of branch instruction generation, where we
1457 // no longer use a single branch instruction.
1458 bool trampoline_emitted_;
1459 static const int kTrampolineSlotsSize = kInstrSize;
1460 static const int kMaxCondBranchReach = (1 << (16 - 1)) - 1;
1461 static const int kMaxBlockTrampolineSectionSize = 64 * kInstrSize;
1462 static const int kInvalidSlotPos = -1;
1463
1464 Trampoline trampoline_;
1465 bool internal_trampoline_exception_;
1466
1467 friend class RegExpMacroAssemblerPPC;
1468 friend class RelocInfo;
1469 friend class CodePatcher;
1470 friend class BlockTrampolinePoolScope;
Ben Murdochda12d292016-06-02 14:46:10 +01001471 AssemblerPositionsRecorder positions_recorder_;
1472 friend class AssemblerPositionsRecorder;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001473 friend class EnsureSpace;
1474};
1475
1476
1477class EnsureSpace BASE_EMBEDDED {
1478 public:
1479 explicit EnsureSpace(Assembler* assembler) { assembler->CheckBuffer(); }
1480};
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001481} // namespace internal
1482} // namespace v8
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001483
1484#endif // V8_PPC_ASSEMBLER_PPC_H_