blob: 58c6c94dc6172735480929b48668b6bb971ca6f5 [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
811 void subfic(Register dst, Register src, const Operand& imm);
812
813 void subfc(Register dst, Register src1, Register src2, OEBit s = LeaveOE,
814 RCBit r = LeaveRC);
815
816 void add(Register dst, Register src1, Register src2, OEBit s = LeaveOE,
817 RCBit r = LeaveRC);
818
819 void addc(Register dst, Register src1, Register src2, OEBit o = LeaveOE,
820 RCBit r = LeaveRC);
821
822 void addze(Register dst, Register src1, OEBit o, RCBit r);
823
824 void mullw(Register dst, Register src1, Register src2, OEBit o = LeaveOE,
825 RCBit r = LeaveRC);
826
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000827 void mulhw(Register dst, Register src1, Register src2, RCBit r = LeaveRC);
828 void mulhwu(Register dst, Register src1, Register src2, RCBit r = LeaveRC);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400829
830 void divw(Register dst, Register src1, Register src2, OEBit o = LeaveOE,
831 RCBit r = LeaveRC);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000832 void divwu(Register dst, Register src1, Register src2, OEBit o = LeaveOE,
833 RCBit r = LeaveRC);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400834
835 void addi(Register dst, Register src, const Operand& imm);
836 void addis(Register dst, Register src, const Operand& imm);
837 void addic(Register dst, Register src, const Operand& imm);
838
839 void and_(Register dst, Register src1, Register src2, RCBit rc = LeaveRC);
840 void andc(Register dst, Register src1, Register src2, RCBit rc = LeaveRC);
841 void andi(Register ra, Register rs, const Operand& imm);
842 void andis(Register ra, Register rs, const Operand& imm);
843 void nor(Register dst, Register src1, Register src2, RCBit r = LeaveRC);
844 void notx(Register dst, Register src, RCBit r = LeaveRC);
845 void ori(Register dst, Register src, const Operand& imm);
846 void oris(Register dst, Register src, const Operand& imm);
847 void orx(Register dst, Register src1, Register src2, RCBit rc = LeaveRC);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000848 void orc(Register dst, Register src1, Register src2, RCBit rc = LeaveRC);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400849 void xori(Register dst, Register src, const Operand& imm);
850 void xoris(Register ra, Register rs, const Operand& imm);
851 void xor_(Register dst, Register src1, Register src2, RCBit rc = LeaveRC);
852 void cmpi(Register src1, const Operand& src2, CRegister cr = cr7);
853 void cmpli(Register src1, const Operand& src2, CRegister cr = cr7);
854 void cmpwi(Register src1, const Operand& src2, CRegister cr = cr7);
855 void cmplwi(Register src1, const Operand& src2, CRegister cr = cr7);
856 void li(Register dst, const Operand& src);
857 void lis(Register dst, const Operand& imm);
858 void mr(Register dst, Register src);
859
860 void lbz(Register dst, const MemOperand& src);
861 void lbzx(Register dst, const MemOperand& src);
862 void lbzux(Register dst, const MemOperand& src);
863 void lhz(Register dst, const MemOperand& src);
864 void lhzx(Register dst, const MemOperand& src);
865 void lhzux(Register dst, const MemOperand& src);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000866 void lha(Register dst, const MemOperand& src);
867 void lhax(Register dst, const MemOperand& src);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400868 void lwz(Register dst, const MemOperand& src);
869 void lwzu(Register dst, const MemOperand& src);
870 void lwzx(Register dst, const MemOperand& src);
871 void lwzux(Register dst, const MemOperand& src);
872 void lwa(Register dst, const MemOperand& src);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000873 void lwax(Register dst, const MemOperand& src);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400874 void stb(Register dst, const MemOperand& src);
875 void stbx(Register dst, const MemOperand& src);
876 void stbux(Register dst, const MemOperand& src);
877 void sth(Register dst, const MemOperand& src);
878 void sthx(Register dst, const MemOperand& src);
879 void sthux(Register dst, const MemOperand& src);
880 void stw(Register dst, const MemOperand& src);
881 void stwu(Register dst, const MemOperand& src);
882 void stwx(Register rs, const MemOperand& src);
883 void stwux(Register rs, const MemOperand& src);
884
885 void extsb(Register rs, Register ra, RCBit r = LeaveRC);
886 void extsh(Register rs, Register ra, RCBit r = LeaveRC);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000887 void extsw(Register rs, Register ra, RCBit r = LeaveRC);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400888
889 void neg(Register rt, Register ra, OEBit o = LeaveOE, RCBit c = LeaveRC);
890
891#if V8_TARGET_ARCH_PPC64
892 void ld(Register rd, const MemOperand& src);
893 void ldx(Register rd, const MemOperand& src);
894 void ldu(Register rd, const MemOperand& src);
895 void ldux(Register rd, const MemOperand& src);
896 void std(Register rs, const MemOperand& src);
897 void stdx(Register rs, const MemOperand& src);
898 void stdu(Register rs, const MemOperand& src);
899 void stdux(Register rs, const MemOperand& src);
900 void rldic(Register dst, Register src, int sh, int mb, RCBit r = LeaveRC);
901 void rldicl(Register dst, Register src, int sh, int mb, RCBit r = LeaveRC);
902 void rldcl(Register ra, Register rs, Register rb, int mb, RCBit r = LeaveRC);
903 void rldicr(Register dst, Register src, int sh, int me, RCBit r = LeaveRC);
904 void rldimi(Register dst, Register src, int sh, int mb, RCBit r = LeaveRC);
905 void sldi(Register dst, Register src, const Operand& val, RCBit rc = LeaveRC);
906 void srdi(Register dst, Register src, const Operand& val, RCBit rc = LeaveRC);
907 void clrrdi(Register dst, Register src, const Operand& val,
908 RCBit rc = LeaveRC);
909 void clrldi(Register dst, Register src, const Operand& val,
910 RCBit rc = LeaveRC);
911 void sradi(Register ra, Register rs, int sh, RCBit r = LeaveRC);
912 void srd(Register dst, Register src1, Register src2, RCBit r = LeaveRC);
913 void sld(Register dst, Register src1, Register src2, RCBit r = LeaveRC);
914 void srad(Register dst, Register src1, Register src2, RCBit r = LeaveRC);
915 void rotld(Register ra, Register rs, Register rb, RCBit r = LeaveRC);
916 void rotldi(Register ra, Register rs, int sh, RCBit r = LeaveRC);
917 void rotrdi(Register ra, Register rs, int sh, RCBit r = LeaveRC);
918 void cntlzd_(Register dst, Register src, RCBit rc = LeaveRC);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000919 void popcntd(Register dst, Register src);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400920 void mulld(Register dst, Register src1, Register src2, OEBit o = LeaveOE,
921 RCBit r = LeaveRC);
922 void divd(Register dst, Register src1, Register src2, OEBit o = LeaveOE,
923 RCBit r = LeaveRC);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000924 void divdu(Register dst, Register src1, Register src2, OEBit o = LeaveOE,
925 RCBit r = LeaveRC);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400926#endif
927
928 void rlwinm(Register ra, Register rs, int sh, int mb, int me,
929 RCBit rc = LeaveRC);
930 void rlwimi(Register ra, Register rs, int sh, int mb, int me,
931 RCBit rc = LeaveRC);
932 void rlwnm(Register ra, Register rs, Register rb, int mb, int me,
933 RCBit rc = LeaveRC);
934 void slwi(Register dst, Register src, const Operand& val, RCBit rc = LeaveRC);
935 void srwi(Register dst, Register src, const Operand& val, RCBit rc = LeaveRC);
936 void clrrwi(Register dst, Register src, const Operand& val,
937 RCBit rc = LeaveRC);
938 void clrlwi(Register dst, Register src, const Operand& val,
939 RCBit rc = LeaveRC);
940 void srawi(Register ra, Register rs, int sh, RCBit r = LeaveRC);
941 void srw(Register dst, Register src1, Register src2, RCBit r = LeaveRC);
942 void slw(Register dst, Register src1, Register src2, RCBit r = LeaveRC);
943 void sraw(Register dst, Register src1, Register src2, RCBit r = LeaveRC);
944 void rotlw(Register ra, Register rs, Register rb, RCBit r = LeaveRC);
945 void rotlwi(Register ra, Register rs, int sh, RCBit r = LeaveRC);
946 void rotrwi(Register ra, Register rs, int sh, RCBit r = LeaveRC);
947
948 void cntlzw_(Register dst, Register src, RCBit rc = LeaveRC);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000949 void popcntw(Register dst, Register src);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400950
951 void subi(Register dst, Register src1, const Operand& src2);
952
953 void cmp(Register src1, Register src2, CRegister cr = cr7);
954 void cmpl(Register src1, Register src2, CRegister cr = cr7);
955 void cmpw(Register src1, Register src2, CRegister cr = cr7);
956 void cmplw(Register src1, Register src2, CRegister cr = cr7);
957
958 void mov(Register dst, const Operand& src);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000959 void bitwise_mov(Register dst, intptr_t value);
960 void bitwise_mov32(Register dst, int32_t value);
961 void bitwise_add32(Register dst, Register src, int32_t value);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400962
963 // Load the position of the label relative to the generated code object
964 // pointer in a register.
965 void mov_label_offset(Register dst, Label* label);
966
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000967 // dst = base + label position + delta
968 void add_label_offset(Register dst, Register base, Label* label,
969 int delta = 0);
970
971 // Load the address of the label in a register and associate with an
972 // internal reference relocation.
973 void mov_label_addr(Register dst, Label* label);
974
975 // Emit the address of the label (i.e. a jump table entry) and associate with
976 // an internal reference relocation.
977 void emit_label_addr(Label* label);
978
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400979 // Multiply instructions
980 void mul(Register dst, Register src1, Register src2, OEBit s = LeaveOE,
981 RCBit r = LeaveRC);
982
983 // Miscellaneous arithmetic instructions
984
985 // Special register access
986 void crxor(int bt, int ba, int bb);
987 void crclr(int bt) { crxor(bt, bt, bt); }
988 void creqv(int bt, int ba, int bb);
989 void crset(int bt) { creqv(bt, bt, bt); }
990 void mflr(Register dst);
991 void mtlr(Register src);
992 void mtctr(Register src);
993 void mtxer(Register src);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000994 void mcrfs(CRegister cr, FPSCRBit bit);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400995 void mfcr(Register dst);
996#if V8_TARGET_ARCH_PPC64
997 void mffprd(Register dst, DoubleRegister src);
998 void mffprwz(Register dst, DoubleRegister src);
999 void mtfprd(DoubleRegister dst, Register src);
1000 void mtfprwz(DoubleRegister dst, Register src);
1001 void mtfprwa(DoubleRegister dst, Register src);
1002#endif
1003
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001004 void function_descriptor();
1005
1006 // Exception-generating instructions and debugging support
1007 void stop(const char* msg, Condition cond = al,
1008 int32_t code = kDefaultStopCode, CRegister cr = cr7);
1009
1010 void bkpt(uint32_t imm16); // v5 and above
1011
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001012 void dcbf(Register ra, Register rb);
1013 void sync();
1014 void lwsync();
1015 void icbi(Register ra, Register rb);
1016 void isync();
1017
1018 // Support for floating point
1019 void lfd(const DoubleRegister frt, const MemOperand& src);
1020 void lfdu(const DoubleRegister frt, const MemOperand& src);
1021 void lfdx(const DoubleRegister frt, const MemOperand& src);
1022 void lfdux(const DoubleRegister frt, const MemOperand& src);
1023 void lfs(const DoubleRegister frt, const MemOperand& src);
1024 void lfsu(const DoubleRegister frt, const MemOperand& src);
1025 void lfsx(const DoubleRegister frt, const MemOperand& src);
1026 void lfsux(const DoubleRegister frt, const MemOperand& src);
1027 void stfd(const DoubleRegister frs, const MemOperand& src);
1028 void stfdu(const DoubleRegister frs, const MemOperand& src);
1029 void stfdx(const DoubleRegister frs, const MemOperand& src);
1030 void stfdux(const DoubleRegister frs, const MemOperand& src);
1031 void stfs(const DoubleRegister frs, const MemOperand& src);
1032 void stfsu(const DoubleRegister frs, const MemOperand& src);
1033 void stfsx(const DoubleRegister frs, const MemOperand& src);
1034 void stfsux(const DoubleRegister frs, const MemOperand& src);
1035
1036 void fadd(const DoubleRegister frt, const DoubleRegister fra,
1037 const DoubleRegister frb, RCBit rc = LeaveRC);
1038 void fsub(const DoubleRegister frt, const DoubleRegister fra,
1039 const DoubleRegister frb, RCBit rc = LeaveRC);
1040 void fdiv(const DoubleRegister frt, const DoubleRegister fra,
1041 const DoubleRegister frb, RCBit rc = LeaveRC);
1042 void fmul(const DoubleRegister frt, const DoubleRegister fra,
1043 const DoubleRegister frc, RCBit rc = LeaveRC);
1044 void fcmpu(const DoubleRegister fra, const DoubleRegister frb,
1045 CRegister cr = cr7);
1046 void fmr(const DoubleRegister frt, const DoubleRegister frb,
1047 RCBit rc = LeaveRC);
1048 void fctiwz(const DoubleRegister frt, const DoubleRegister frb);
1049 void fctiw(const DoubleRegister frt, const DoubleRegister frb);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001050 void frin(const DoubleRegister frt, const DoubleRegister frb,
1051 RCBit rc = LeaveRC);
1052 void friz(const DoubleRegister frt, const DoubleRegister frb,
1053 RCBit rc = LeaveRC);
1054 void frip(const DoubleRegister frt, const DoubleRegister frb,
1055 RCBit rc = LeaveRC);
1056 void frim(const DoubleRegister frt, const DoubleRegister frb,
1057 RCBit rc = LeaveRC);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001058 void frsp(const DoubleRegister frt, const DoubleRegister frb,
1059 RCBit rc = LeaveRC);
1060 void fcfid(const DoubleRegister frt, const DoubleRegister frb,
1061 RCBit rc = LeaveRC);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001062 void fcfidu(const DoubleRegister frt, const DoubleRegister frb,
1063 RCBit rc = LeaveRC);
1064 void fcfidus(const DoubleRegister frt, const DoubleRegister frb,
1065 RCBit rc = LeaveRC);
1066 void fcfids(const DoubleRegister frt, const DoubleRegister frb,
1067 RCBit rc = LeaveRC);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001068 void fctid(const DoubleRegister frt, const DoubleRegister frb,
1069 RCBit rc = LeaveRC);
1070 void fctidz(const DoubleRegister frt, const DoubleRegister frb,
1071 RCBit rc = LeaveRC);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001072 void fctidu(const DoubleRegister frt, const DoubleRegister frb,
1073 RCBit rc = LeaveRC);
1074 void fctiduz(const DoubleRegister frt, const DoubleRegister frb,
1075 RCBit rc = LeaveRC);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001076 void fsel(const DoubleRegister frt, const DoubleRegister fra,
1077 const DoubleRegister frc, const DoubleRegister frb,
1078 RCBit rc = LeaveRC);
1079 void fneg(const DoubleRegister frt, const DoubleRegister frb,
1080 RCBit rc = LeaveRC);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001081 void mtfsb0(FPSCRBit bit, RCBit rc = LeaveRC);
1082 void mtfsb1(FPSCRBit bit, RCBit rc = LeaveRC);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001083 void mtfsfi(int bf, int immediate, RCBit rc = LeaveRC);
1084 void mffs(const DoubleRegister frt, RCBit rc = LeaveRC);
1085 void mtfsf(const DoubleRegister frb, bool L = 1, int FLM = 0, bool W = 0,
1086 RCBit rc = LeaveRC);
1087 void fsqrt(const DoubleRegister frt, const DoubleRegister frb,
1088 RCBit rc = LeaveRC);
1089 void fabs(const DoubleRegister frt, const DoubleRegister frb,
1090 RCBit rc = LeaveRC);
1091 void fmadd(const DoubleRegister frt, const DoubleRegister fra,
1092 const DoubleRegister frc, const DoubleRegister frb,
1093 RCBit rc = LeaveRC);
1094 void fmsub(const DoubleRegister frt, const DoubleRegister fra,
1095 const DoubleRegister frc, const DoubleRegister frb,
1096 RCBit rc = LeaveRC);
1097
1098 // Pseudo instructions
1099
1100 // Different nop operations are used by the code generator to detect certain
1101 // states of the generated code.
1102 enum NopMarkerTypes {
1103 NON_MARKING_NOP = 0,
1104 GROUP_ENDING_NOP,
1105 DEBUG_BREAK_NOP,
1106 // IC markers.
1107 PROPERTY_ACCESS_INLINED,
1108 PROPERTY_ACCESS_INLINED_CONTEXT,
1109 PROPERTY_ACCESS_INLINED_CONTEXT_DONT_DELETE,
1110 // Helper values.
1111 LAST_CODE_MARKER,
1112 FIRST_IC_MARKER = PROPERTY_ACCESS_INLINED
1113 };
1114
1115 void nop(int type = 0); // 0 is the default non-marking type.
1116
1117 void push(Register src) {
1118#if V8_TARGET_ARCH_PPC64
1119 stdu(src, MemOperand(sp, -kPointerSize));
1120#else
1121 stwu(src, MemOperand(sp, -kPointerSize));
1122#endif
1123 }
1124
1125 void pop(Register dst) {
1126#if V8_TARGET_ARCH_PPC64
1127 ld(dst, MemOperand(sp));
1128#else
1129 lwz(dst, MemOperand(sp));
1130#endif
1131 addi(sp, sp, Operand(kPointerSize));
1132 }
1133
1134 void pop() { addi(sp, sp, Operand(kPointerSize)); }
1135
1136 // Jump unconditionally to given label.
1137 void jmp(Label* L) { b(L); }
1138
1139 // Check the code size generated from label to here.
1140 int SizeOfCodeGeneratedSince(Label* label) {
1141 return pc_offset() - label->pos();
1142 }
1143
1144 // Check the number of instructions generated from label to here.
1145 int InstructionsGeneratedSince(Label* label) {
1146 return SizeOfCodeGeneratedSince(label) / kInstrSize;
1147 }
1148
1149 // Class for scoping postponing the trampoline pool generation.
1150 class BlockTrampolinePoolScope {
1151 public:
1152 explicit BlockTrampolinePoolScope(Assembler* assem) : assem_(assem) {
1153 assem_->StartBlockTrampolinePool();
1154 }
1155 ~BlockTrampolinePoolScope() { assem_->EndBlockTrampolinePool(); }
1156
1157 private:
1158 Assembler* assem_;
1159
1160 DISALLOW_IMPLICIT_CONSTRUCTORS(BlockTrampolinePoolScope);
1161 };
1162
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001163 // Class for scoping disabling constant pool entry merging
1164 class BlockConstantPoolEntrySharingScope {
1165 public:
1166 explicit BlockConstantPoolEntrySharingScope(Assembler* assem)
1167 : assem_(assem) {
1168 assem_->StartBlockConstantPoolEntrySharing();
1169 }
1170 ~BlockConstantPoolEntrySharingScope() {
1171 assem_->EndBlockConstantPoolEntrySharing();
1172 }
1173
1174 private:
1175 Assembler* assem_;
1176
1177 DISALLOW_IMPLICIT_CONSTRUCTORS(BlockConstantPoolEntrySharingScope);
1178 };
1179
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001180 // Debugging
1181
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001182 // Mark generator continuation.
1183 void RecordGeneratorContinuation();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001184
1185 // Mark address of a debug break slot.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001186 void RecordDebugBreakSlot(RelocInfo::Mode mode);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001187
1188 // Record the AST id of the CallIC being compiled, so that it can be placed
1189 // in the relocation information.
1190 void SetRecordedAstId(TypeFeedbackId ast_id) {
1191 // Causes compiler to fail
1192 // DCHECK(recorded_ast_id_.IsNone());
1193 recorded_ast_id_ = ast_id;
1194 }
1195
1196 TypeFeedbackId RecordedAstId() {
1197 // Causes compiler to fail
1198 // DCHECK(!recorded_ast_id_.IsNone());
1199 return recorded_ast_id_;
1200 }
1201
1202 void ClearRecordedAstId() { recorded_ast_id_ = TypeFeedbackId::None(); }
1203
1204 // Record a comment relocation entry that can be used by a disassembler.
1205 // Use --code-comments to enable.
1206 void RecordComment(const char* msg);
1207
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001208 // Record a deoptimization reason that can be used by a log or cpu profiler.
1209 // Use --trace-deopt to enable.
Ben Murdoch097c5b22016-05-18 11:27:45 +01001210 void RecordDeoptReason(const int reason, int raw_position);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001211
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001212 // Writes a single byte or word of data in the code stream. Used
1213 // for inline tables, e.g., jump-tables.
1214 void db(uint8_t data);
1215 void dd(uint32_t data);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001216 void dq(uint64_t data);
1217 void dp(uintptr_t data);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001218
1219 PositionsRecorder* positions_recorder() { return &positions_recorder_; }
1220
1221 // Read/patch instructions
1222 Instr instr_at(int pos) { return *reinterpret_cast<Instr*>(buffer_ + pos); }
1223 void instr_at_put(int pos, Instr instr) {
1224 *reinterpret_cast<Instr*>(buffer_ + pos) = instr;
1225 }
1226 static Instr instr_at(byte* pc) { return *reinterpret_cast<Instr*>(pc); }
1227 static void instr_at_put(byte* pc, Instr instr) {
1228 *reinterpret_cast<Instr*>(pc) = instr;
1229 }
1230 static Condition GetCondition(Instr instr);
1231
1232 static bool IsLis(Instr instr);
1233 static bool IsLi(Instr instr);
1234 static bool IsAddic(Instr instr);
1235 static bool IsOri(Instr instr);
1236
1237 static bool IsBranch(Instr instr);
1238 static Register GetRA(Instr instr);
1239 static Register GetRB(Instr instr);
1240#if V8_TARGET_ARCH_PPC64
1241 static bool Is64BitLoadIntoR12(Instr instr1, Instr instr2, Instr instr3,
1242 Instr instr4, Instr instr5);
1243#else
1244 static bool Is32BitLoadIntoR12(Instr instr1, Instr instr2);
1245#endif
1246
1247 static bool IsCmpRegister(Instr instr);
1248 static bool IsCmpImmediate(Instr instr);
1249 static bool IsRlwinm(Instr instr);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001250 static bool IsAndi(Instr instr);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001251#if V8_TARGET_ARCH_PPC64
1252 static bool IsRldicl(Instr instr);
1253#endif
1254 static bool IsCrSet(Instr instr);
1255 static Register GetCmpImmediateRegister(Instr instr);
1256 static int GetCmpImmediateRawImmediate(Instr instr);
1257 static bool IsNop(Instr instr, int type = NON_MARKING_NOP);
1258
1259 // Postpone the generation of the trampoline pool for the specified number of
1260 // instructions.
1261 void BlockTrampolinePoolFor(int instructions);
1262 void CheckTrampolinePool();
1263
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001264 // For mov. Return the number of actual instructions required to
1265 // load the operand into a register. This can be anywhere from
1266 // one (constant pool small section) to five instructions (full
1267 // 64-bit sequence).
1268 //
1269 // The value returned is only valid as long as no entries are added to the
1270 // constant pool between this call and the actual instruction being emitted.
1271 int instructions_required_for_mov(Register dst, const Operand& src) const;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001272
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001273 // Decide between using the constant pool vs. a mov immediate sequence.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001274 bool use_constant_pool_for_mov(Register dst, const Operand& src,
1275 bool canOptimize) const;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001276
1277 // The code currently calls CheckBuffer() too often. This has the side
1278 // effect of randomly growing the buffer in the middle of multi-instruction
1279 // sequences.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001280 //
1281 // This function allows outside callers to check and grow the buffer
1282 void EnsureSpaceFor(int space_needed);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001283
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001284 int EmitConstantPool() { return constant_pool_builder_.Emit(this); }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001285
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001286 bool ConstantPoolAccessIsInOverflow() const {
1287 return constant_pool_builder_.NextAccess(ConstantPoolEntry::INTPTR) ==
1288 ConstantPoolEntry::OVERFLOWED;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001289 }
1290
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001291 Label* ConstantPoolPosition() {
1292 return constant_pool_builder_.EmittedPosition();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001293 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001294
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001295 void EmitRelocations();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001296
1297 protected:
1298 // Relocation for a type-recording IC has the AST id added to it. This
1299 // member variable is a way to pass the information from the call site to
1300 // the relocation info.
1301 TypeFeedbackId recorded_ast_id_;
1302
1303 int buffer_space() const { return reloc_info_writer.pos() - pc_; }
1304
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001305 // Decode instruction(s) at pos and return backchain to previous
1306 // label reference or kEndOfChain.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001307 int target_at(int pos);
1308
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001309 // Patch instruction(s) at pos to target target_pos (e.g. branch)
1310 void target_at_put(int pos, int target_pos, bool* is_branch = nullptr);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001311
1312 // Record reloc info for current pc_
1313 void RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data = 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001314 ConstantPoolEntry::Access ConstantPoolAddEntry(RelocInfo::Mode rmode,
1315 intptr_t value) {
1316 bool sharing_ok = RelocInfo::IsNone(rmode) ||
1317 !(serializer_enabled() || rmode < RelocInfo::CELL ||
1318 is_constant_pool_entry_sharing_blocked());
1319 return constant_pool_builder_.AddEntry(pc_offset(), value, sharing_ok);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001320 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001321 ConstantPoolEntry::Access ConstantPoolAddEntry(double value) {
1322 return constant_pool_builder_.AddEntry(pc_offset(), value);
1323 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001324
1325 // Block the emission of the trampoline pool before pc_offset.
1326 void BlockTrampolinePoolBefore(int pc_offset) {
1327 if (no_trampoline_pool_before_ < pc_offset)
1328 no_trampoline_pool_before_ = pc_offset;
1329 }
1330
1331 void StartBlockTrampolinePool() { trampoline_pool_blocked_nesting_++; }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001332 void EndBlockTrampolinePool() {
1333 int count = --trampoline_pool_blocked_nesting_;
1334 if (count == 0) CheckTrampolinePoolQuick();
1335 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001336 bool is_trampoline_pool_blocked() const {
1337 return trampoline_pool_blocked_nesting_ > 0;
1338 }
1339
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001340 void StartBlockConstantPoolEntrySharing() {
1341 constant_pool_entry_sharing_blocked_nesting_++;
1342 }
1343 void EndBlockConstantPoolEntrySharing() {
1344 constant_pool_entry_sharing_blocked_nesting_--;
1345 }
1346 bool is_constant_pool_entry_sharing_blocked() const {
1347 return constant_pool_entry_sharing_blocked_nesting_ > 0;
1348 }
1349
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001350 bool has_exception() const { return internal_trampoline_exception_; }
1351
1352 bool is_trampoline_emitted() const { return trampoline_emitted_; }
1353
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001354 private:
1355 // Code generation
1356 // The relocation writer's position is at least kGap bytes below the end of
1357 // the generated instructions. This is so that multi-instruction sequences do
1358 // not have to check for overflow. The same is true for writes of large
1359 // relocation info entries.
1360 static const int kGap = 32;
1361
1362 // Repeated checking whether the trampoline pool should be emitted is rather
1363 // expensive. By default we only check again once a number of instructions
1364 // has been generated.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001365 int next_trampoline_check_; // pc offset of next buffer check.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001366
1367 // Emission of the trampoline pool may be blocked in some code sequences.
1368 int trampoline_pool_blocked_nesting_; // Block emission if this is not zero.
1369 int no_trampoline_pool_before_; // Block emission before this pc offset.
1370
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001371 // Do not share constant pool entries.
1372 int constant_pool_entry_sharing_blocked_nesting_;
1373
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001374 // Relocation info generation
1375 // Each relocation is encoded as a variable size value
1376 static const int kMaxRelocSize = RelocInfoWriter::kMaxSize;
1377 RelocInfoWriter reloc_info_writer;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001378 std::vector<DeferredRelocInfo> relocations_;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001379
1380 // The bound position, before this we cannot do instruction elimination.
1381 int last_bound_pos_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001382 // Optimizable cmpi information.
1383 int optimizable_cmpi_pos_;
1384 CRegister cmpi_cr_;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001385
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001386 ConstantPoolBuilder constant_pool_builder_;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001387
1388 // Code emission
1389 inline void CheckBuffer();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001390 void GrowBuffer(int needed = 0);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001391 inline void emit(Instr x);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001392 inline void TrackBranch();
1393 inline void UntrackBranch();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001394 inline void CheckTrampolinePoolQuick();
1395
1396 // Instruction generation
1397 void a_form(Instr instr, DoubleRegister frt, DoubleRegister fra,
1398 DoubleRegister frb, RCBit r);
1399 void d_form(Instr instr, Register rt, Register ra, const intptr_t val,
1400 bool signed_disp);
1401 void x_form(Instr instr, Register ra, Register rs, Register rb, RCBit r);
1402 void xo_form(Instr instr, Register rt, Register ra, Register rb, OEBit o,
1403 RCBit r);
1404 void md_form(Instr instr, Register ra, Register rs, int shift, int maskbit,
1405 RCBit r);
1406 void mds_form(Instr instr, Register ra, Register rs, Register rb, int maskbit,
1407 RCBit r);
1408
1409 // Labels
1410 void print(Label* L);
1411 int max_reach_from(int pos);
1412 void bind_to(Label* L, int pos);
1413 void next(Label* L);
1414
1415 class Trampoline {
1416 public:
1417 Trampoline() {
1418 next_slot_ = 0;
1419 free_slot_count_ = 0;
1420 }
1421 Trampoline(int start, int slot_count) {
1422 next_slot_ = start;
1423 free_slot_count_ = slot_count;
1424 }
1425 int take_slot() {
1426 int trampoline_slot = kInvalidSlotPos;
1427 if (free_slot_count_ <= 0) {
1428 // We have run out of space on trampolines.
1429 // Make sure we fail in debug mode, so we become aware of each case
1430 // when this happens.
1431 DCHECK(0);
1432 // Internal exception will be caught.
1433 } else {
1434 trampoline_slot = next_slot_;
1435 free_slot_count_--;
1436 next_slot_ += kTrampolineSlotsSize;
1437 }
1438 return trampoline_slot;
1439 }
1440
1441 private:
1442 int next_slot_;
1443 int free_slot_count_;
1444 };
1445
1446 int32_t get_trampoline_entry();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001447 int tracked_branch_count_;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001448 // If trampoline is emitted, generated code is becoming large. As
1449 // this is already a slow case which can possibly break our code
1450 // generation for the extreme case, we use this information to
1451 // trigger different mode of branch instruction generation, where we
1452 // no longer use a single branch instruction.
1453 bool trampoline_emitted_;
1454 static const int kTrampolineSlotsSize = kInstrSize;
1455 static const int kMaxCondBranchReach = (1 << (16 - 1)) - 1;
1456 static const int kMaxBlockTrampolineSectionSize = 64 * kInstrSize;
1457 static const int kInvalidSlotPos = -1;
1458
1459 Trampoline trampoline_;
1460 bool internal_trampoline_exception_;
1461
1462 friend class RegExpMacroAssemblerPPC;
1463 friend class RelocInfo;
1464 friend class CodePatcher;
1465 friend class BlockTrampolinePoolScope;
1466 PositionsRecorder positions_recorder_;
1467 friend class PositionsRecorder;
1468 friend class EnsureSpace;
1469};
1470
1471
1472class EnsureSpace BASE_EMBEDDED {
1473 public:
1474 explicit EnsureSpace(Assembler* assembler) { assembler->CheckBuffer(); }
1475};
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001476} // namespace internal
1477} // namespace v8
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001478
1479#endif // V8_PPC_ASSEMBLER_PPC_H_