v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
assembler-s390.h
Go to the documentation of this file.
1// 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 S390 Assembler
38// Generates user mode instructions for z/Architecture
39
40#ifndef V8_CODEGEN_S390_ASSEMBLER_S390_H_
41#define V8_CODEGEN_S390_ASSEMBLER_S390_H_
42
43#include <stdio.h>
44#include <memory>
45#if V8_HOST_ARCH_S390X && !V8_OS_ZOS
46// elf.h include is required for auxv check for STFLE facility used
47// for hardware detection, which is sensible only on s390 hosts.
48#include <elf.h>
49#endif
50
51#include <fcntl.h>
52#include <unistd.h>
53
57#include "src/codegen/label.h"
60#include "src/objects/smi.h"
61
62namespace v8 {
63namespace internal {
64
65class SafepointTableBuilder;
66
67// -----------------------------------------------------------------------------
68// Machine instruction Operands
69
70// Class Operand represents a shifter operand in data processing instructions
71// defining immediate numbers and masks
72class V8_EXPORT_PRIVATE Operand {
73 public:
74 // immediate
75 V8_INLINE explicit Operand(intptr_t immediate,
76 RelocInfo::Mode rmode = RelocInfo::NO_INFO)
77 : rmode_(rmode) {
78 value_.immediate = immediate;
79 }
80 V8_INLINE static Operand Zero() { return Operand(static_cast<intptr_t>(0)); }
82 : rmode_(RelocInfo::EXTERNAL_REFERENCE) {
83 value_.immediate = static_cast<intptr_t>(f.address());
84 }
85 explicit Operand(Handle<HeapObject> handle);
86 V8_INLINE explicit Operand(Tagged<Smi> value) : rmode_(RelocInfo::NO_INFO) {
87 value_.immediate = static_cast<intptr_t>(value.ptr());
88 }
89
90 // rm
92
93 static Operand EmbeddedNumber(double value); // Smi or HeapNumber
94
95 // Return true if this is a register operand.
96 V8_INLINE bool is_reg() const { return rm_.is_valid(); }
97
98 bool must_output_reloc_info(const Assembler* assembler) const;
99
100 inline intptr_t immediate() const {
101 DCHECK(!rm_.is_valid());
102 DCHECK(!is_heap_number_request());
103 return value_.immediate;
104 }
105
107 DCHECK(is_heap_number_request());
108 return value_.heap_number_request;
109 }
110
111 inline void setBits(int n) {
112 value_.immediate =
113 (static_cast<uint32_t>(value_.immediate) << (32 - n)) >> (32 - n);
114 }
115
116 Register rm() const { return rm_; }
117
119 DCHECK_IMPLIES(is_heap_number_request_, !rm_.is_valid());
120 DCHECK_IMPLIES(is_heap_number_request_,
121 rmode_ == RelocInfo::FULL_EMBEDDED_OBJECT ||
122 rmode_ == RelocInfo::CODE_TARGET);
123 return is_heap_number_request_;
124 }
125
126 RelocInfo::Mode rmode() const { return rmode_; }
127
128 private:
129 Register rm_ = no_reg;
130 union Value {
131 Value() {}
132 HeapNumberRequest heap_number_request; // if is_heap_number_request_
133 intptr_t immediate; // otherwise
134 } value_; // valid if rm_ == no_reg
135 bool is_heap_number_request_ = false;
136
137 RelocInfo::Mode rmode_;
138
139 friend class Assembler;
140 friend class MacroAssembler;
141};
142
143using Disp = int32_t;
144
145// Class MemOperand represents a memory operand in load and store instructions
146// On S390, we have various flavours of memory operands:
147// 1) a base register + 16 bit unsigned displacement
148// 2) a base register + index register + 16 bit unsigned displacement
149// 3) a base register + index register + 20 bit signed displacement
151 public:
152 explicit MemOperand(Register rx, Disp offset = 0);
153 explicit MemOperand(Register rx, Register rb, Disp offset = 0);
154
155 int32_t offset() const { return offset_; }
156 uint32_t getDisplacement() const { return offset(); }
157
158 // Base register
159 Register rb() const {
160 DCHECK(baseRegister != no_reg);
161 return baseRegister;
162 }
163
164 Register getBaseRegister() const { return rb(); }
165
166 // Index Register
167 Register rx() const {
168 DCHECK(indexRegister != no_reg);
169 return indexRegister;
170 }
171 Register getIndexRegister() const { return rx(); }
172
173 private:
176 int32_t offset_; // offset
177
178 friend class Assembler;
179};
180
182 public:
186
187 int position() const { return position_; }
188 RelocInfo::Mode rmode() const { return rmode_; }
189 intptr_t data() const { return data_; }
190
191 private:
192 int position_;
194 intptr_t data_;
195};
196
197class V8_EXPORT_PRIVATE Assembler : public AssemblerBase {
198 public:
199 // Create an assembler. Instructions and relocation information are emitted
200 // into a buffer, with the instructions starting from the beginning and the
201 // relocation information starting from the end of the buffer. See CodeDesc
202 // for a detailed comment on the layout (globals.h).
203 //
204 // If the provided buffer is nullptr, the assembler allocates and grows its
205 // own buffer. Otherwise it takes ownership of the provided buffer.
207 std::unique_ptr<AssemblerBuffer> = {});
208 // For compatibility with assemblers that require a zone.
210 std::unique_ptr<AssemblerBuffer> buffer = {})
211 : Assembler(options, std::move(buffer)) {}
212
213 virtual ~Assembler() {}
214
215 static RegList DefaultTmpList();
216 static DoubleRegList DefaultFPTmpList();
217
218 // GetCode emits any pending (non-emitted) code and fills the descriptor desc.
219 static constexpr int kNoHandlerTable = 0;
220 static constexpr SafepointTableBuilderBase* kNoSafepointTable = nullptr;
221 void GetCode(LocalIsolate* isolate, CodeDesc* desc,
222 SafepointTableBuilderBase* safepoint_table_builder,
223 int handler_table_offset);
224
225 // Convenience wrapper for allocating with an Isolate.
226 void GetCode(Isolate* isolate, CodeDesc* desc);
227 // Convenience wrapper for code without safepoint or handler tables.
228 void GetCode(LocalIsolate* isolate, CodeDesc* desc) {
229 GetCode(isolate, desc, kNoSafepointTable, kNoHandlerTable);
230 }
231
232 // Unused on this architecture.
234
235 // Label operations & relative jumps (PPUM Appendix D)
236 //
237 // Takes a branch opcode (cc) and a label (L) and generates
238 // either a backward branch or a forward branch and links it
239 // to the label fixup chain. Usage:
240 //
241 // Label L; // unbound label
242 // j(cc, &L); // forward branch to unbound label
243 // bind(&L); // bind label to the current pc
244 // j(cc, &L); // backward branch to bound label
245 // bind(&L); // illegal: a label may be bound only once
246 //
247 // Note: The same Label can be used for forward and backward branches
248 // but it may be bound only once.
249
250 void bind(Label* L); // binds an unbound label L to the current code position
251
252 // Links a label at the current pc_offset(). If already bound, returns the
253 // bound position. If already linked, returns the position of the prior link.
254 // Otherwise, returns the current pc_offset().
255 int link(Label* L);
256
257 // Returns the branch offset to the given label from the current code position
258 // Links the label to the current position if it is still unbound
259 int branch_offset(Label* L) { return link(L) - pc_offset(); }
260
262
263 // Read/Modify the code target address in the branch/call instruction at pc.
264 // The isolate argument is unused (and may be nullptr) when skipping flushing.
265 V8_INLINE static Address target_address_at(Address pc, Address constant_pool);
266
267 // Read/Modify the code target address in the branch/call instruction at pc.
269 Address constant_pool);
271 Address pc, Address constant_pool, Address target,
272 WritableJitAllocation* jit_allocation,
273 ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED);
274
276 Address pc, Address constant_pool, Tagged_t target,
277 WritableJitAllocation* jit_allocation,
278 ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED);
279
282 Address pc, Address constant_pool);
283
284 // Get the size of the special target encoded at 'instruction_payload'.
286 Address instruction_payload);
287
288 // This sets the internal reference at the pc.
290 Address pc, Address target, WritableJitAllocation& jit_allocation,
291 RelocInfo::Mode mode = RelocInfo::INTERNAL_REFERENCE);
292
293 // Read/modify the uint32 constant used at pc.
294 static inline uint32_t uint32_constant_at(Address pc, Address constant_pool);
295 static inline void set_uint32_constant_at(
296 Address pc, Address constant_pool, uint32_t new_constant,
297 WritableJitAllocation* jit_allocation,
298 ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED);
299
300 // Here we are patching the address in the IIHF/IILF instruction pair.
301 // These values are used in the serialization process and must be zero for
302 // S390 platform, as Code, Embedded Object or External-reference pointers
303 // are split across two consecutive instructions and don't exist separately
304 // in the code, so the serializer should not step forwards in memory after
305 // a target is resolved and written.
306 static constexpr int kSpecialTargetSize = 0;
307// Number of bytes for instructions used to store pointer sized constant.
308 static constexpr int kBytesForPtrConstant = 12; // IIHF + IILF
309
310 RegList* GetScratchRegisterList() { return &scratch_register_list_; }
312 return &scratch_double_register_list_;
313 }
314
315 // ---------------------------------------------------------------------------
316 // InstructionStream generation
317
318 template <class T, int size, int lo, int hi>
319 inline T getfield(T value) {
320 DCHECK(lo < hi);
321 DCHECK_GT(size, 0);
322 int mask = hi - lo;
323 int shift = size * 8 - hi;
324 uint32_t mask_value = (mask == 32) ? 0xffffffff : (1 << mask) - 1;
325 return (value & mask_value) << shift;
326 }
327
328#define DECLARE_S390_RIL_AB_INSTRUCTIONS(name, op_name, op_value) \
329 template <class R1> \
330 inline void name(R1 r1, const Operand& i2) { \
331 ril_format(op_name, r1.code(), i2.immediate()); \
332 }
333#define DECLARE_S390_RIL_C_INSTRUCTIONS(name, op_name, op_value) \
334 inline void name(Condition m1, const Operand& i2) { \
335 ril_format(op_name, m1, i2.immediate()); \
336 }
337
338 inline void ril_format(Opcode opcode, int f1, int f2) {
339 uint32_t op1 = opcode >> 4;
340 uint32_t op2 = opcode & 0xf;
341 emit6bytes(
342 getfield<uint64_t, 6, 0, 8>(op1) | getfield<uint64_t, 6, 8, 12>(f1) |
343 getfield<uint64_t, 6, 12, 16>(op2) | getfield<uint64_t, 6, 16, 48>(f2));
344 }
348#undef DECLARE_S390_RIL_AB_INSTRUCTIONS
349#undef DECLARE_S390_RIL_C_INSTRUCTIONS
350
351#define DECLARE_S390_RR_INSTRUCTIONS(name, op_name, op_value) \
352 inline void name(Register r1, Register r2) { \
353 rr_format(op_name, r1.code(), r2.code()); \
354 } \
355 inline void name(DoubleRegister r1, DoubleRegister r2) { \
356 rr_format(op_name, r1.code(), r2.code()); \
357 } \
358 inline void name(Condition m1, Register r2) { \
359 rr_format(op_name, m1, r2.code()); \
360 }
361
362 inline void rr_format(Opcode opcode, int f1, int f2) {
363 emit2bytes(getfield<uint16_t, 2, 0, 8>(opcode) |
364 getfield<uint16_t, 2, 8, 12>(f1) |
365 getfield<uint16_t, 2, 12, 16>(f2));
366 }
368#undef DECLARE_S390_RR_INSTRUCTIONS
369
370#define DECLARE_S390_RRD_INSTRUCTIONS(name, op_name, op_value) \
371 template <class R1, class R2, class R3> \
372 inline void name(R1 r1, R3 r3, R2 r2) { \
373 rrd_format(op_name, r1.code(), r3.code(), r2.code()); \
374 }
375 inline void rrd_format(Opcode opcode, int f1, int f2, int f3) {
376 emit4bytes(getfield<uint32_t, 4, 0, 16>(opcode) |
377 getfield<uint32_t, 4, 16, 20>(f1) |
378 getfield<uint32_t, 4, 24, 28>(f2) |
379 getfield<uint32_t, 4, 28, 32>(f3));
380 }
382#undef DECLARE_S390_RRD_INSTRUCTIONS
383
384#define DECLARE_S390_RRE_INSTRUCTIONS(name, op_name, op_value) \
385 template <class R1, class R2> \
386 inline void name(R1 r1, R2 r2) { \
387 rre_format(op_name, r1.code(), r2.code()); \
388 }
389 inline void rre_format(Opcode opcode, int f1, int f2) {
390 emit4bytes(getfield<uint32_t, 4, 0, 16>(opcode) |
391 getfield<uint32_t, 4, 24, 28>(f1) |
392 getfield<uint32_t, 4, 28, 32>(f2));
393 }
395 // Special format
396 void lzdr(DoubleRegister r1) { rre_format(LZDR, r1.code(), 0); }
397 void lzer(DoubleRegister r1) { rre_format(LZER, r1.code(), 0); }
398#undef DECLARE_S390_RRE_INSTRUCTIONS
399
400#define DECLARE_S390_RX_INSTRUCTIONS(name, op_name, op_value) \
401 template <class R1> \
402 inline void name(R1 r1, Register x2, Register b2, const Operand& d2) { \
403 rx_format(op_name, r1.code(), x2.code(), b2.code(), d2.immediate()); \
404 } \
405 template <class R1> \
406 inline void name(R1 r1, const MemOperand& opnd) { \
407 name(r1, opnd.getIndexRegister(), opnd.getBaseRegister(), \
408 Operand(opnd.getDisplacement())); \
409 }
410
411 inline void rx_format(Opcode opcode, int f1, int f2, int f3, int f4) {
412 DCHECK(is_uint8(opcode));
413 DCHECK(is_uint12(f4));
414 emit4bytes(
415 getfield<uint32_t, 4, 0, 8>(opcode) | getfield<uint32_t, 4, 8, 12>(f1) |
416 getfield<uint32_t, 4, 12, 16>(f2) | getfield<uint32_t, 4, 16, 20>(f3) |
417 getfield<uint32_t, 4, 20, 32>(f4));
418 }
420
421 void bc(Condition cond, const MemOperand& opnd) {
422 bc(cond, opnd.getIndexRegister(), opnd.getBaseRegister(),
423 Operand(opnd.getDisplacement()));
424 }
425 void bc(Condition cond, Register x2, Register b2, const Operand& d2) {
426 rx_format(BC, cond, x2.code(), b2.code(), d2.immediate());
427 }
428#undef DECLARE_S390_RX_INSTRUCTIONS
429
430#define DECLARE_S390_RXY_INSTRUCTIONS(name, op_name, op_value) \
431 template <class R1, class R2> \
432 inline void name(R1 r1, R2 r2, Register b2, const Operand& d2) { \
433 rxy_format(op_name, r1.code(), r2.code(), b2.code(), d2.immediate()); \
434 } \
435 template <class R1> \
436 inline void name(R1 r1, const MemOperand& opnd) { \
437 name(r1, opnd.getIndexRegister(), opnd.getBaseRegister(), \
438 Operand(opnd.getDisplacement())); \
439 }
440
441 inline void rxy_format(Opcode opcode, int f1, int f2, int f3, int f4) {
442 DCHECK(is_uint16(opcode));
443 DCHECK(is_int20(f4));
444 emit6bytes(getfield<uint64_t, 6, 0, 8>(opcode >> 8) |
445 getfield<uint64_t, 6, 8, 12>(f1) |
446 getfield<uint64_t, 6, 12, 16>(f2) |
447 getfield<uint64_t, 6, 16, 20>(f3) |
448 getfield<uint64_t, 6, 20, 32>(f4 & 0x0fff) |
449 getfield<uint64_t, 6, 32, 40>(f4 >> 12) |
450 getfield<uint64_t, 6, 40, 48>(opcode & 0x00ff));
451 }
453
454 void pfd(Condition cond, const MemOperand& opnd) {
455 pfd(cond, opnd.getIndexRegister(), opnd.getBaseRegister(),
456 Operand(opnd.getDisplacement()));
457 }
458 void pfd(Condition cond, Register x2, Register b2, const Operand& d2) {
459 rxy_format(PFD, cond, x2.code(), b2.code(), d2.immediate());
460 }
461#undef DECLARE_S390_RXY_INSTRUCTIONS
462
463 inline void rsy_format(Opcode op, int f1, int f2, int f3, int f4) {
464 DCHECK(is_int20(f4));
465 DCHECK(is_uint16(op));
466 uint64_t code =
467 (getfield<uint64_t, 6, 0, 8>(op >> 8) |
468 getfield<uint64_t, 6, 8, 12>(f1) | getfield<uint64_t, 6, 12, 16>(f2) |
469 getfield<uint64_t, 6, 16, 20>(f3) |
470 getfield<uint64_t, 6, 20, 32>(f4 & 0x0fff) |
471 getfield<uint64_t, 6, 32, 40>(f4 >> 12) |
472 getfield<uint64_t, 6, 40, 48>(op & 0xff));
473 emit6bytes(code);
474 }
475
476#define DECLARE_S390_RSY_A_INSTRUCTIONS(name, op_name, op_value) \
477 void name(Register r1, Register r3, Register b2, \
478 const Operand& d2 = Operand::Zero()) { \
479 rsy_format(op_name, r1.code(), r3.code(), b2.code(), d2.immediate()); \
480 } \
481 void name(Register r1, Register r3, Operand d2) { name(r1, r3, r0, d2); } \
482 void name(Register r1, Register r3, const MemOperand& opnd) { \
483 name(r1, r3, opnd.getBaseRegister(), Operand(opnd.getDisplacement())); \
484 }
486#undef DECLARE_S390_RSY_A_INSTRUCTIONS
487
488#define DECLARE_S390_RSY_B_INSTRUCTIONS(name, op_name, op_value) \
489 void name(Register r1, Condition m3, Register b2, const Operand& d2) { \
490 rsy_format(op_name, r1.code(), m3, b2.code(), d2.immediate()); \
491 } \
492 void name(Register r1, Condition m3, const MemOperand& opnd) { \
493 name(r1, m3, opnd.getBaseRegister(), Operand(opnd.getDisplacement())); \
494 }
496#undef DECLARE_S390_RSY_B_INSTRUCTIONS
497
498 inline void rs_format(Opcode op, int f1, int f2, int f3, const int f4) {
499 uint32_t code =
500 getfield<uint32_t, 4, 0, 8>(op) | getfield<uint32_t, 4, 8, 12>(f1) |
501 getfield<uint32_t, 4, 12, 16>(f2) | getfield<uint32_t, 4, 16, 20>(f3) |
502 getfield<uint32_t, 4, 20, 32>(f4);
503 emit4bytes(code);
504 }
505
506#define DECLARE_S390_RS_A_INSTRUCTIONS(name, op_name, op_value) \
507 void name(Register r1, Register r3, Register b2, const Operand& d2) { \
508 rs_format(op_name, r1.code(), r3.code(), b2.code(), d2.immediate()); \
509 } \
510 void name(Register r1, Register r3, const MemOperand& opnd) { \
511 name(r1, r3, opnd.getBaseRegister(), Operand(opnd.getDisplacement())); \
512 }
514#undef DECLARE_S390_RS_A_INSTRUCTIONS
515
516#define DECLARE_S390_RS_B_INSTRUCTIONS(name, op_name, op_value) \
517 void name(Register r1, Condition m3, Register b2, const Operand& d2) { \
518 rs_format(op_name, r1.code(), m3, b2.code(), d2.immediate()); \
519 } \
520 void name(Register r1, Condition m3, const MemOperand& opnd) { \
521 name(r1, m3, opnd.getBaseRegister(), Operand(opnd.getDisplacement())); \
522 }
524#undef DECLARE_S390_RS_B_INSTRUCTIONS
525
526#define DECLARE_S390_RS_SHIFT_FORMAT(name, opcode) \
527 void name(Register r1, Register r2, const Operand& opnd = Operand::Zero()) { \
528 rs_format(opcode, r1.code(), r0.code(), r2.code(), opnd.immediate()); \
529 } \
530 void name(Register r1, const Operand& opnd) { \
531 rs_format(opcode, r1.code(), r0.code(), r0.code(), opnd.immediate()); \
532 }
540#undef DECLARE_S390_RS_SHIFT_FORMAT
541
542 inline void rxe_format(Opcode op, int f1, int f2, int f3, int f4,
543 int f5 = 0) {
544 DCHECK(is_uint12(f4));
545 DCHECK(is_uint16(op));
546 uint64_t code =
547 (getfield<uint64_t, 6, 0, 8>(op >> 8) |
548 getfield<uint64_t, 6, 8, 12>(f1) | getfield<uint64_t, 6, 12, 16>(f2) |
549 getfield<uint64_t, 6, 16, 20>(f3) |
550 getfield<uint64_t, 6, 20, 32>(f4 & 0x0fff) |
551 getfield<uint64_t, 6, 32, 36>(f5) |
552 getfield<uint64_t, 6, 40, 48>(op & 0xff));
553 emit6bytes(code);
554 }
555
556#define DECLARE_S390_RXE_INSTRUCTIONS(name, op_name, op_value) \
557 void name(Register r1, Register x2, Register b2, const Operand& d2, \
558 Condition m3 = static_cast<Condition>(0)) { \
559 rxe_format(op_name, r1.code(), x2.code(), b2.code(), d2.immediate(), m3); \
560 } \
561 template <class _R1Type> \
562 void name(_R1Type r1, const MemOperand& opnd) { \
563 name(Register::from_code(r1.code()), opnd.rx(), opnd.rb(), \
564 Operand(opnd.offset())); \
565 }
567#undef DECLARE_S390_RXE_INSTRUCTIONS
568
569 inline void ri_format(Opcode opcode, int f1, int f2) {
570 uint32_t op1 = opcode >> 4;
571 uint32_t op2 = opcode & 0xf;
572 emit4bytes(
573 getfield<uint32_t, 4, 0, 8>(op1) | getfield<uint32_t, 4, 8, 12>(f1) |
574 getfield<uint32_t, 4, 12, 16>(op2) | getfield<uint32_t, 4, 16, 32>(f2));
575 }
576
577#define DECLARE_S390_RI_A_INSTRUCTIONS(name, op_name, op_value) \
578 void name(Register r, const Operand& i2) { \
579 DCHECK(is_uint12(op_name)); \
580 DCHECK(is_uint16(i2.immediate()) || is_int16(i2.immediate())); \
581 ri_format(op_name, r.code(), i2.immediate()); \
582 }
584#undef DECLARE_S390_RI_A_INSTRUCTIONS
585
586#define DECLARE_S390_RI_B_INSTRUCTIONS(name, op_name, op_value) \
587 void name(Register r1, const Operand& imm) { \
588 /* 2nd argument encodes # of halfwords, so divide by 2. */ \
589 int16_t numHalfwords = static_cast<int16_t>(imm.immediate()) / 2; \
590 Operand halfwordOp = Operand(numHalfwords); \
591 halfwordOp.setBits(16); \
592 ri_format(op_name, r1.code(), halfwordOp.immediate()); \
593 }
595#undef DECLARE_S390_RI_B_INSTRUCTIONS
596
597#define DECLARE_S390_RI_C_INSTRUCTIONS(name, op_name, op_value) \
598 void name(Condition m, const Operand& i2) { \
599 DCHECK(is_uint12(op_name)); \
600 DCHECK(is_uint4(m)); \
601 DCHECK(op_name == BRC ? is_int16(i2.immediate()) \
602 : is_uint16(i2.immediate())); \
603 ri_format(op_name, m, i2.immediate()); \
604 }
606#undef DECLARE_S390_RI_C_INSTRUCTIONS
607
608 inline void rrf_format(Opcode op, int f1, int f2, int f3, int f4) {
609 uint32_t code =
610 getfield<uint32_t, 4, 0, 16>(op) | getfield<uint32_t, 4, 16, 20>(f1) |
611 getfield<uint32_t, 4, 20, 24>(f2) | getfield<uint32_t, 4, 24, 28>(f3) |
612 getfield<uint32_t, 4, 28, 32>(f4);
613 emit4bytes(code);
614 }
615
616#define DECLARE_S390_RRF_A_INSTRUCTIONS(name, op_name, op_value) \
617 void name(Register r1, Condition m4, Register r2, Register r3) { \
618 rrf_format(op_name, r3.code(), m4, r1.code(), r2.code()); \
619 } \
620 void name(Register r1, Register r2, Register r3) { \
621 name(r1, Condition(0), r2, r3); \
622 }
624#undef DECLARE_S390_RRF_A_INSTRUCTIONS
625
626#define DECLARE_S390_RRF_B_INSTRUCTIONS(name, op_name, op_value) \
627 void name(Register r1, Condition m4, Register r2, Register r3) { \
628 rrf_format(op_name, r3.code(), m4, r1.code(), r2.code()); \
629 } \
630 void name(Register r1, Register r2, Register r3) { \
631 name(r1, Condition(0), r2, r3); \
632 }
634#undef DECLARE_S390_RRF_B_INSTRUCTIONS
635
636#define DECLARE_S390_RRF_C_INSTRUCTIONS(name, op_name, op_value) \
637 template <class R1, class R2> \
638 void name(Condition m3, Condition m4, R1 r1, R2 r2) { \
639 rrf_format(op_name, m3, m4, r1.code(), r2.code()); \
640 } \
641 template <class R1, class R2> \
642 void name(Condition m3, R1 r1, R2 r2) { \
643 name(m3, Condition(0), r1, r2); \
644 }
646#undef DECLARE_S390_RRF_C_INSTRUCTIONS
647
648#define DECLARE_S390_RRF_D_INSTRUCTIONS(name, op_name, op_value) \
649 template <class R1, class R2> \
650 void name(Condition m3, Condition m4, R1 r1, R2 r2) { \
651 rrf_format(op_name, m3, m4, r1.code(), r2.code()); \
652 } \
653 template <class R1, class R2> \
654 void name(Condition m3, R1 r1, R2 r2) { \
655 name(m3, Condition(0), r1, r2); \
656 }
658#undef DECLARE_S390_RRF_D_INSTRUCTIONS
659
660#define DECLARE_S390_RRF_E_INSTRUCTIONS(name, op_name, op_value) \
661 template <class M3, class M4, class R1, class R2> \
662 void name(M3 m3, M4 m4, R1 r1, R2 r2) { \
663 rrf_format(op_name, m3, m4, r1.code(), r2.code()); \
664 } \
665 template <class M3, class R1, class R2> \
666 void name(M3 m3, R1 r1, R2 r2) { \
667 name(m3, Condition(0), r1, r2); \
668 }
670#undef DECLARE_S390_RRF_E_INSTRUCTIONS
671
672 inline void rsi_format(Opcode op, int f1, int f2, int f3) {
673 DCHECK(is_uint8(op));
674 DCHECK(is_uint16(f3) || is_int16(f3));
675 uint32_t code =
676 getfield<uint32_t, 4, 0, 8>(op) | getfield<uint32_t, 4, 8, 12>(f1) |
677 getfield<uint32_t, 4, 12, 16>(f2) | getfield<uint32_t, 4, 16, 32>(f3);
678 emit4bytes(code);
679 }
680
681#define DECLARE_S390_RSI_INSTRUCTIONS(name, op_name, op_value) \
682 void name(Register r1, Register r3, const Operand& i2) { \
683 rsi_format(op_name, r1.code(), r3.code(), i2.immediate()); \
684 }
686#undef DECLARE_S390_RSI_INSTRUCTIONS
687
688 inline void rsl_format(Opcode op, uint16_t f1, int f2, int f3, int f4,
689 int f5) {
690 DCHECK(is_uint16(op));
691 uint64_t code =
692 getfield<uint64_t, 6, 0, 8>(op >> 8) |
693 getfield<uint64_t, 6, 8, 16>(f1) | getfield<uint64_t, 6, 16, 20>(f2) |
694 getfield<uint64_t, 6, 20, 32>(f3) | getfield<uint64_t, 6, 32, 36>(f4) |
695 getfield<uint64_t, 6, 36, 40>(f5) |
696 getfield<uint64_t, 6, 40, 48>(op & 0x00FF);
697 emit6bytes(code);
698 }
699
700#define DECLARE_S390_RSL_A_INSTRUCTIONS(name, op_name, op_value) \
701 void name(const Operand& l1, Register b1, const Operand& d1) { \
702 uint16_t L = static_cast<uint16_t>(l1.immediate() << 8); \
703 rsl_format(op_name, L, b1.code(), d1.immediate(), 0, 0); \
704 }
706#undef DECLARE_S390_RSL_A_INSTRUCTIONS
707
708#define DECLARE_S390_RSL_B_INSTRUCTIONS(name, op_name, op_value) \
709 void name(const Operand& l2, Register b2, const Operand& d2, Register r1, \
710 Condition m3) { \
711 uint16_t L = static_cast<uint16_t>(l2.immediate()); \
712 rsl_format(op_name, L, b2.code(), d2.immediate(), r1.code(), m3); \
713 }
715#undef DECLARE_S390_RSL_B_INSTRUCTIONS
716
717 inline void s_format(Opcode op, int f1, int f2) {
718 DCHECK_NE(op & 0xff00, 0);
719 DCHECK(is_uint12(f2));
720 uint32_t code = getfield<uint32_t, 4, 0, 16>(op) |
721 getfield<uint32_t, 4, 16, 20>(f1) |
722 getfield<uint32_t, 4, 20, 32>(f2);
723 emit4bytes(code);
724 }
725
726#define DECLARE_S390_S_INSTRUCTIONS(name, op_name, op_value) \
727 void name(Register b1, const Operand& d2) { \
728 Opcode op = op_name; \
729 if ((op & 0xFF00) == 0) { \
730 op = (Opcode)(op << 8); \
731 } \
732 s_format(op, b1.code(), d2.immediate()); \
733 } \
734 void name(const MemOperand& opnd) { \
735 Operand d2 = Operand(opnd.getDisplacement()); \
736 name(opnd.getBaseRegister(), d2); \
737 }
739#undef DECLARE_S390_S_INSTRUCTIONS
740
741 inline void si_format(Opcode op, int f1, int f2, int f3) {
742 uint32_t code =
743 getfield<uint32_t, 4, 0, 8>(op) | getfield<uint32_t, 4, 8, 16>(f1) |
744 getfield<uint32_t, 4, 16, 20>(f2) | getfield<uint32_t, 4, 20, 32>(f3);
745 emit4bytes(code);
746 }
747
748#define DECLARE_S390_SI_INSTRUCTIONS(name, op_name, op_value) \
749 void name(const Operand& i2, Register b1, const Operand& d1) { \
750 si_format(op_name, i2.immediate(), b1.code(), d1.immediate()); \
751 } \
752 void name(const MemOperand& opnd, const Operand& i2) { \
753 name(i2, opnd.getBaseRegister(), Operand(opnd.getDisplacement())); \
754 }
756#undef DECLARE_S390_SI_INSTRUCTIONS
757
758 inline void siy_format(Opcode op, int f1, int f2, int f3) {
759 DCHECK(is_uint20(f3) || is_int20(f3));
760 DCHECK(is_uint16(op));
761 DCHECK(is_uint8(f1) || is_int8(f1));
762 uint64_t code = getfield<uint64_t, 6, 0, 8>(op >> 8) |
763 getfield<uint64_t, 6, 8, 16>(f1) |
764 getfield<uint64_t, 6, 16, 20>(f2) |
765 getfield<uint64_t, 6, 20, 32>(f3) |
766 getfield<uint64_t, 6, 32, 40>(f3 >> 12) |
767 getfield<uint64_t, 6, 40, 48>(op & 0x00FF);
768 emit6bytes(code);
769 }
770
771#define DECLARE_S390_SIY_INSTRUCTIONS(name, op_name, op_value) \
772 void name(const Operand& i2, Register b1, const Operand& d1) { \
773 siy_format(op_name, i2.immediate(), b1.code(), d1.immediate()); \
774 } \
775 void name(const MemOperand& opnd, const Operand& i2) { \
776 name(i2, opnd.getBaseRegister(), Operand(opnd.getDisplacement())); \
777 }
779#undef DECLARE_S390_SIY_INSTRUCTIONS
780
781 inline void rrs_format(Opcode op, int f1, int f2, int f3, int f4, int f5) {
782 DCHECK(is_uint12(f4));
783 DCHECK(is_uint16(op));
784 uint64_t code =
785 getfield<uint64_t, 6, 0, 8>(op >> 8) |
786 getfield<uint64_t, 6, 8, 12>(f1) | getfield<uint64_t, 6, 12, 16>(f2) |
787 getfield<uint64_t, 6, 16, 20>(f3) | getfield<uint64_t, 6, 20, 32>(f4) |
788 getfield<uint64_t, 6, 32, 36>(f5) |
789 getfield<uint64_t, 6, 40, 48>(op & 0x00FF);
790 emit6bytes(code);
791 }
792
793#define DECLARE_S390_RRS_INSTRUCTIONS(name, op_name, op_value) \
794 void name(Register r1, Register r2, Register b4, const Operand& d4, \
795 Condition m3) { \
796 rrs_format(op_name, r1.code(), r2.code(), b4.code(), d4.immediate(), m3); \
797 } \
798 void name(Register r1, Register r2, Condition m3, const MemOperand& opnd) { \
799 name(r1, r2, opnd.getBaseRegister(), Operand(opnd.getDisplacement()), m3); \
800 }
802#undef DECLARE_S390_RRS_INSTRUCTIONS
803
804 inline void ris_format(Opcode op, int f1, int f2, int f3, int f4, int f5) {
805 DCHECK(is_uint12(f3));
806 DCHECK(is_uint16(op));
807 DCHECK(is_uint8(f5));
808 uint64_t code =
809 getfield<uint64_t, 6, 0, 8>(op >> 8) |
810 getfield<uint64_t, 6, 8, 12>(f1) | getfield<uint64_t, 6, 12, 16>(f2) |
811 getfield<uint64_t, 6, 16, 20>(f3) | getfield<uint64_t, 6, 20, 32>(f4) |
812 getfield<uint64_t, 6, 32, 40>(f5) |
813 getfield<uint64_t, 6, 40, 48>(op & 0x00FF);
814 emit6bytes(code);
815 }
816
817#define DECLARE_S390_RIS_INSTRUCTIONS(name, op_name, op_value) \
818 void name(Register r1, Condition m3, Register b4, const Operand& d4, \
819 const Operand& i2) { \
820 ris_format(op_name, r1.code(), m3, b4.code(), d4.immediate(), \
821 i2.immediate()); \
822 } \
823 void name(Register r1, const Operand& i2, Condition m3, \
824 const MemOperand& opnd) { \
825 name(r1, m3, opnd.getBaseRegister(), Operand(opnd.getDisplacement()), i2); \
826 }
828#undef DECLARE_S390_RIS_INSTRUCTIONS
829
830 inline void sil_format(Opcode op, int f1, int f2, int f3) {
831 DCHECK(is_uint12(f2));
832 DCHECK(is_uint16(op));
833 DCHECK(is_uint16(f3));
834 uint64_t code =
835 getfield<uint64_t, 6, 0, 16>(op) | getfield<uint64_t, 6, 16, 20>(f1) |
836 getfield<uint64_t, 6, 20, 32>(f2) | getfield<uint64_t, 6, 32, 48>(f3);
837 emit6bytes(code);
838 }
839
840#define DECLARE_S390_SIL_INSTRUCTIONS(name, op_name, op_value) \
841 void name(Register b1, const Operand& d1, const Operand& i2) { \
842 sil_format(op_name, b1.code(), d1.immediate(), i2.immediate()); \
843 } \
844 void name(const MemOperand& opnd, const Operand& i2) { \
845 name(opnd.getBaseRegister(), Operand(opnd.getDisplacement()), i2); \
846 }
848#undef DECLARE_S390_SIL_INSTRUCTIONS
849
850 inline void rie_d_format(Opcode opcode, int f1, int f2, int f3, int f4) {
851 uint32_t op1 = opcode >> 8;
852 uint32_t op2 = opcode & 0xff;
853 uint64_t code =
854 getfield<uint64_t, 6, 0, 8>(op1) | getfield<uint64_t, 6, 8, 12>(f1) |
855 getfield<uint64_t, 6, 12, 16>(f2) | getfield<uint64_t, 6, 16, 32>(f3) |
856 getfield<uint64_t, 6, 32, 40>(f4) | getfield<uint64_t, 6, 40, 48>(op2);
857 emit6bytes(code);
858 }
859
860#define DECLARE_S390_RIE_D_INSTRUCTIONS(name, op_name, op_value) \
861 void name(Register r1, Register r3, const Operand& i2) { \
862 rie_d_format(op_name, r1.code(), r3.code(), i2.immediate(), 0); \
863 }
865#undef DECLARE_S390_RIE_D_INSTRUCTIONS
866
867 inline void rie_e_format(Opcode opcode, int f1, int f2, int f3) {
868 uint32_t op1 = opcode >> 8;
869 uint32_t op2 = opcode & 0xff;
870 uint64_t code =
871 getfield<uint64_t, 6, 0, 8>(op1) | getfield<uint64_t, 6, 8, 12>(f1) |
872 getfield<uint64_t, 6, 12, 16>(f2) | getfield<uint64_t, 6, 16, 32>(f3) |
873 getfield<uint64_t, 6, 40, 48>(op2);
874 emit6bytes(code);
875 }
876
877#define DECLARE_S390_RIE_E_INSTRUCTIONS(name, op_name, op_value) \
878 void name(Register r1, Register r3, const Operand& i2) { \
879 rie_e_format(op_name, r1.code(), r3.code(), i2.immediate()); \
880 }
882#undef DECLARE_S390_RIE_E_INSTRUCTIONS
883
884 inline void rie_f_format(Opcode opcode, int f1, int f2, int f3, int f4,
885 int f5) {
886 uint32_t op1 = opcode >> 8;
887 uint32_t op2 = opcode & 0xff;
888 uint64_t code =
889 getfield<uint64_t, 6, 0, 8>(op1) | getfield<uint64_t, 6, 8, 12>(f1) |
890 getfield<uint64_t, 6, 12, 16>(f2) | getfield<uint64_t, 6, 16, 24>(f3) |
891 getfield<uint64_t, 6, 24, 32>(f4) | getfield<uint64_t, 6, 32, 40>(f5) |
892 getfield<uint64_t, 6, 40, 48>(op2);
893 emit6bytes(code);
894 }
895
896#define DECLARE_S390_RIE_F_INSTRUCTIONS(name, op_name, op_value) \
897 void name(Register dst, Register src, const Operand& startBit, \
898 const Operand& endBit, const Operand& shiftAmt) { \
899 DCHECK(is_uint8(startBit.immediate())); \
900 DCHECK(is_uint8(endBit.immediate())); \
901 DCHECK(is_uint8(shiftAmt.immediate())); \
902 rie_f_format(op_name, dst.code(), src.code(), startBit.immediate(), \
903 endBit.immediate(), shiftAmt.immediate()); \
904 }
906#undef DECLARE_S390_RIE_F_INSTRUCTIONS
907
908 inline void ss_a_format(Opcode op, int f1, int f2, int f3, int f4, int f5) {
909 DCHECK(is_uint12(f5));
910 DCHECK(is_uint12(f3));
911 DCHECK(is_uint8(f1));
912 DCHECK(is_uint8(op));
913 uint64_t code =
914 getfield<uint64_t, 6, 0, 8>(op) | getfield<uint64_t, 6, 8, 16>(f1) |
915 getfield<uint64_t, 6, 16, 20>(f2) | getfield<uint64_t, 6, 20, 32>(f3) |
916 getfield<uint64_t, 6, 32, 36>(f4) | getfield<uint64_t, 6, 36, 48>(f5);
917 emit6bytes(code);
918 }
919
920#define DECLARE_S390_SS_A_INSTRUCTIONS(name, op_name, op_value) \
921 void name(Register b1, const Operand& d1, Register b2, const Operand& d2, \
922 const Operand& length) { \
923 ss_a_format(op_name, length.immediate(), b1.code(), d1.immediate(), \
924 b2.code(), d2.immediate()); \
925 } \
926 void name(const MemOperand& opnd1, const MemOperand& opnd2, \
927 const Operand& length) { \
928 ss_a_format(op_name, length.immediate(), opnd1.getBaseRegister().code(), \
929 opnd1.getDisplacement(), opnd2.getBaseRegister().code(), \
930 opnd2.getDisplacement()); \
931 }
933#undef DECLARE_S390_SS_A_INSTRUCTIONS
934
935 // Helper for unconditional branch to Label with update to save register
936 void b(Register r, Label* l) {
937 int32_t halfwords = branch_offset(l) / 2;
938 brasl(r, Operand(halfwords));
939 }
940
941 // Conditional Branch Instruction - Generates either BRC / BRCL
942 void branchOnCond(Condition c, int branch_offset, bool is_bound = false,
943 bool force_long_branch = false);
944
945 // Helpers for conditional branch to Label
946 void b(Condition cond, Label* l, Label::Distance dist = Label::kFar,
947 bool force_long_branch = false) {
948 branchOnCond(cond, branch_offset(l),
949 l->is_bound() || (dist == Label::kNear), force_long_branch);
950 }
951
952 void bc_short(Condition cond, Label* l, Label::Distance dist = Label::kFar) {
953 b(cond, l, Label::kNear);
954 }
955 void bc_long(Condition cond, Label* l) { b(cond, l, Label::kFar, true); }
956 // Helpers for conditional branch to Label
957 void beq(Label* l, Label::Distance dist = Label::kFar) { b(eq, l, dist); }
958 void bne(Label* l, Label::Distance dist = Label::kFar) { b(ne, l, dist); }
959 void blt(Label* l, Label::Distance dist = Label::kFar) { b(lt, l, dist); }
960 void ble(Label* l, Label::Distance dist = Label::kFar) { b(le, l, dist); }
961 void bgt(Label* l, Label::Distance dist = Label::kFar) { b(gt, l, dist); }
962 void bge(Label* l, Label::Distance dist = Label::kFar) { b(ge, l, dist); }
963 void b(Label* l, Label::Distance dist = Label::kFar) { b(al, l, dist); }
964 void jmp(Label* l, Label::Distance dist = Label::kFar) { b(al, l, dist); }
965 void bunordered(Label* l, Label::Distance dist = Label::kFar) {
966 b(unordered, l, dist);
967 }
968 void bordered(Label* l, Label::Distance dist = Label::kFar) {
969 b(ordered, l, dist);
970 }
971
972 // Helpers for conditional indirect branch off register
973 void b(Condition cond, Register r) { bcr(cond, r); }
974 void beq(Register r) { b(eq, r); }
975 void bne(Register r) { b(ne, r); }
976 void blt(Register r) { b(lt, r); }
977 void ble(Register r) { b(le, r); }
978 void bgt(Register r) { b(gt, r); }
979 void bge(Register r) { b(ge, r); }
980 void b(Register r) { b(al, r); }
981 void jmp(Register r) { b(al, r); }
983 void bordered(Register r) { b(ordered, r); }
984
985 // wrappers around asm instr
986 void brxh(Register dst, Register inc, Label* L) {
987 int offset_halfwords = branch_offset(L) / 2;
988 CHECK(is_int16(offset_halfwords));
989 brxh(dst, inc, Operand(offset_halfwords));
990 }
991
992 void brxhg(Register dst, Register inc, Label* L) {
993 int offset_halfwords = branch_offset(L) / 2;
994 CHECK(is_int16(offset_halfwords));
995 brxhg(dst, inc, Operand(offset_halfwords));
996 }
997
998 template <class R1, class R2>
999 void ledbr(R1 r1, R2 r2) {
1000 ledbra(Condition(0), Condition(0), r1, r2);
1001 }
1002
1003 template <class R1, class R2>
1004 void cdfbr(R1 r1, R2 r2) {
1005 cdfbra(Condition(0), Condition(0), r1, r2);
1006 }
1007
1008 template <class R1, class R2>
1009 void cdgbr(R1 r1, R2 r2) {
1010 cdgbra(Condition(0), Condition(0), r1, r2);
1011 }
1012
1013 template <class R1, class R2>
1014 void cegbr(R1 r1, R2 r2) {
1015 cegbra(Condition(0), Condition(0), r1, r2);
1016 }
1017
1018 template <class R1, class R2>
1019 void cgebr(Condition m3, R1 r1, R2 r2) {
1020 cgebra(m3, Condition(0), r1, r2);
1021 }
1022
1023 template <class R1, class R2>
1024 void cgdbr(Condition m3, R1 r1, R2 r2) {
1025 cgdbra(m3, Condition(0), r1, r2);
1026 }
1027
1028 template <class R1, class R2>
1029 void cfdbr(Condition m3, R1 r1, R2 r2) {
1030 cfdbra(m3, Condition(0), r1, r2);
1031 }
1032
1033 template <class R1, class R2>
1034 void cfebr(Condition m3, R1 r1, R2 r2) {
1035 cfebra(m3, Condition(0), r1, r2);
1036 }
1037
1038 // ---------------------------------------------------------------------------
1039 // InstructionStream generation
1040
1041 // Insert the smallest number of nop instructions
1042 // possible to align the pc offset to a multiple
1043 // of m. m must be a power of 2 (>= 4).
1044 void Align(int m);
1045 // Insert the smallest number of zero bytes possible to align the pc offset
1046 // to a mulitple of m. m must be a power of 2 (>= 2).
1047 void DataAlign(int m);
1048 // Aligns code to something that's optimal for a jump target for the platform.
1050 void LoopHeaderAlign() { CodeTargetAlign(); }
1051
1052 void breakpoint(bool do_print) {
1053 if (do_print) {
1054 PrintF("DebugBreak is inserted to %p\n", static_cast<void*>(pc_));
1055 }
1056#if V8_HOST_ARCH_64_BIT
1057 int64_t value = reinterpret_cast<uint64_t>(&v8::base::OS::DebugBreak);
1058 int32_t hi_32 = static_cast<int64_t>(value) >> 32;
1059 int32_t lo_32 = static_cast<int32_t>(value);
1060
1061 iihf(r1, Operand(hi_32));
1062 iilf(r1, Operand(lo_32));
1063#else
1064 iilf(r1, Operand(reinterpret_cast<uint32_t>(&v8::base::OS::DebugBreak)));
1065#endif
1066 basr(r14, r1);
1067 }
1068
1069 void call(Handle<Code> target, RelocInfo::Mode rmode);
1070 void jump(Handle<Code> target, RelocInfo::Mode rmode, Condition cond);
1071
1072// S390 instruction generation
1073#define DECLARE_VRR_A_INSTRUCTIONS(name, opcode_name, opcode_value) \
1074 void name(DoubleRegister v1, DoubleRegister v2, Condition m5, Condition m4, \
1075 Condition m3) { \
1076 uint64_t code = (static_cast<uint64_t>(opcode_value & 0xFF00)) * B32 | \
1077 (static_cast<uint64_t>(v1.code())) * B36 | \
1078 (static_cast<uint64_t>(v2.code())) * B32 | \
1079 (static_cast<uint64_t>(m5 & 0xF)) * B20 | \
1080 (static_cast<uint64_t>(m4 & 0xF)) * B16 | \
1081 (static_cast<uint64_t>(m3 & 0xF)) * B12 | \
1082 (static_cast<uint64_t>(0)) * B8 | \
1083 (static_cast<uint64_t>(opcode_value & 0x00FF)); \
1084 emit6bytes(code); \
1085 }
1087#undef DECLARE_VRR_A_INSTRUCTIONS
1088
1089#define DECLARE_VRR_C_INSTRUCTIONS(name, opcode_name, opcode_value) \
1090 void name(DoubleRegister v1, DoubleRegister v2, DoubleRegister v3, \
1091 Condition m6, Condition m5, Condition m4) { \
1092 uint64_t code = (static_cast<uint64_t>(opcode_value & 0xFF00)) * B32 | \
1093 (static_cast<uint64_t>(v1.code())) * B36 | \
1094 (static_cast<uint64_t>(v2.code())) * B32 | \
1095 (static_cast<uint64_t>(v3.code())) * B28 | \
1096 (static_cast<uint64_t>(m6 & 0xF)) * B20 | \
1097 (static_cast<uint64_t>(m5 & 0xF)) * B16 | \
1098 (static_cast<uint64_t>(m4 & 0xF)) * B12 | \
1099 (static_cast<uint64_t>(0)) * B8 | \
1100 (static_cast<uint64_t>(opcode_value & 0x00FF)); \
1101 emit6bytes(code); \
1102 }
1104#undef DECLARE_VRR_C_INSTRUCTIONS
1105
1106#define DECLARE_VRR_B_INSTRUCTIONS(name, opcode_name, opcode_value) \
1107 void name(DoubleRegister v1, DoubleRegister v2, DoubleRegister v3, \
1108 Condition m5, Condition m4) { \
1109 uint64_t code = (static_cast<uint64_t>(opcode_value & 0xFF00)) * B32 | \
1110 (static_cast<uint64_t>(v1.code())) * B36 | \
1111 (static_cast<uint64_t>(v2.code())) * B32 | \
1112 (static_cast<uint64_t>(v3.code())) * B28 | \
1113 (static_cast<uint64_t>(m5 & 0xF)) * B20 | \
1114 (static_cast<uint64_t>(m4 & 0xF)) * B12 | \
1115 (static_cast<uint64_t>(0)) * B8 | \
1116 (static_cast<uint64_t>(opcode_value & 0x00FF)); \
1117 emit6bytes(code); \
1118 }
1120#undef DECLARE_VRR_B_INSTRUCTIONS
1121
1122#define DECLARE_VRR_E_INSTRUCTIONS(name, opcode_name, opcode_value) \
1123 void name(DoubleRegister v1, DoubleRegister v2, DoubleRegister v3, \
1124 DoubleRegister v4, Condition m6, Condition m5) { \
1125 uint64_t code = (static_cast<uint64_t>(opcode_value & 0xFF00)) * B32 | \
1126 (static_cast<uint64_t>(v1.code())) * B36 | \
1127 (static_cast<uint64_t>(v2.code())) * B32 | \
1128 (static_cast<uint64_t>(v3.code())) * B28 | \
1129 (static_cast<uint64_t>(m6 & 0xF)) * B24 | \
1130 (static_cast<uint64_t>(m5 & 0xF)) * B16 | \
1131 (static_cast<uint64_t>(v4.code())) * B12 | \
1132 (static_cast<uint64_t>(0)) * B8 | \
1133 (static_cast<uint64_t>(opcode_value & 0x00FF)); \
1134 emit6bytes(code); \
1135 }
1137#undef DECLARE_VRR_E_INSTRUCTIONS
1138
1139#define DECLARE_VRR_F_INSTRUCTIONS(name, opcode_name, opcode_value) \
1140 void name(DoubleRegister v1, Register r1, Register r2) { \
1141 uint64_t code = (static_cast<uint64_t>(opcode_value & 0xFF00)) * B32 | \
1142 (static_cast<uint64_t>(v1.code())) * B36 | \
1143 (static_cast<uint64_t>(r1.code())) * B32 | \
1144 (static_cast<uint64_t>(r2.code())) * B28 | \
1145 (static_cast<uint64_t>(0)) * B8 | \
1146 (static_cast<uint64_t>(opcode_value & 0x00FF)); \
1147 emit6bytes(code); \
1148 }
1150#undef DECLARE_VRR_E_INSTRUCTIONS
1151
1152#define DECLARE_VRX_INSTRUCTIONS(name, opcode_name, opcode_value) \
1153 void name(DoubleRegister v1, const MemOperand& opnd, Condition m3) { \
1154 uint64_t code = \
1155 (static_cast<uint64_t>(opcode_value & 0xFF00)) * B32 | \
1156 (static_cast<uint64_t>(v1.code())) * B36 | \
1157 (static_cast<uint64_t>(opnd.getIndexRegister().code())) * B32 | \
1158 (static_cast<uint64_t>(opnd.getBaseRegister().code())) * B28 | \
1159 (static_cast<uint64_t>(opnd.getDisplacement())) * B16 | \
1160 (static_cast<uint64_t>(m3 & 0xF)) * B12 | \
1161 (static_cast<uint64_t>(0)) * B8 | \
1162 (static_cast<uint64_t>(opcode_value & 0x00FF)); \
1163 emit6bytes(code); \
1164 }
1166#undef DECLARE_VRX_INSTRUCTIONS
1167
1168#define DECLARE_VRS_A_INSTRUCTIONS(name, opcode_name, opcode_value) \
1169 void name(DoubleRegister v1, DoubleRegister v2, const MemOperand& opnd, \
1170 Condition m4 = Condition(0)) { \
1171 uint64_t code = \
1172 (static_cast<uint64_t>(opcode_value & 0xFF00)) * B32 | \
1173 (static_cast<uint64_t>(v1.code())) * B36 | \
1174 (static_cast<uint64_t>(v2.code())) * B32 | \
1175 (static_cast<uint64_t>(opnd.getBaseRegister().code())) * B28 | \
1176 (static_cast<uint64_t>(opnd.getDisplacement())) * B16 | \
1177 (static_cast<uint64_t>(m4 & 0xF)) * B12 | \
1178 (static_cast<uint64_t>(0)) * B8 | \
1179 (static_cast<uint64_t>(opcode_value & 0x00FF)); \
1180 emit6bytes(code); \
1181 }
1183#undef DECLARE_VRS_A_INSTRUCTIONS
1184
1185#define DECLARE_VRS_B_INSTRUCTIONS(name, opcode_name, opcode_value) \
1186 void name(DoubleRegister v1, Register r1, const MemOperand& opnd, \
1187 Condition m4 = Condition(0)) { \
1188 uint64_t code = \
1189 (static_cast<uint64_t>(opcode_value & 0xFF00)) * B32 | \
1190 (static_cast<uint64_t>(v1.code())) * B36 | \
1191 (static_cast<uint64_t>(r1.code())) * B32 | \
1192 (static_cast<uint64_t>(opnd.getBaseRegister().code())) * B28 | \
1193 (static_cast<uint64_t>(opnd.getDisplacement())) * B16 | \
1194 (static_cast<uint64_t>(m4 & 0xF)) * B12 | \
1195 (static_cast<uint64_t>(0)) * B8 | \
1196 (static_cast<uint64_t>(opcode_value & 0x00FF)); \
1197 emit6bytes(code); \
1198 }
1200#undef DECLARE_VRS_B_INSTRUCTIONS
1201
1202#define DECLARE_VRS_C_INSTRUCTIONS(name, opcode_name, opcode_value) \
1203 void name(Register r1, DoubleRegister v1, const MemOperand& opnd, \
1204 Condition m4 = Condition(0)) { \
1205 uint64_t code = \
1206 (static_cast<uint64_t>(opcode_value & 0xFF00)) * B32 | \
1207 (static_cast<uint64_t>(r1.code())) * B36 | \
1208 (static_cast<uint64_t>(v1.code())) * B32 | \
1209 (static_cast<uint64_t>(opnd.getBaseRegister().code())) * B28 | \
1210 (static_cast<uint64_t>(opnd.getDisplacement())) * B16 | \
1211 (static_cast<uint64_t>(m4 & 0xF)) * B12 | \
1212 (static_cast<uint64_t>(0)) * B8 | \
1213 (static_cast<uint64_t>(opcode_value & 0x00FF)); \
1214 emit6bytes(code); \
1215 }
1217#undef DECLARE_VRS_C_INSTRUCTIONS
1218
1219#define DECLARE_VRI_A_INSTRUCTIONS(name, opcode_name, opcode_value) \
1220 void name(DoubleRegister v1, const Operand& i2, Condition m3) { \
1221 uint64_t code = (static_cast<uint64_t>(opcode_value & 0xFF00)) * B32 | \
1222 (static_cast<uint64_t>(v1.code())) * B36 | \
1223 (static_cast<uint32_t>(i2.immediate())) * B16 | \
1224 (static_cast<uint64_t>(m3 & 0xF)) * B12 | \
1225 (static_cast<uint64_t>(0)) * B8 | \
1226 (static_cast<uint64_t>(opcode_value & 0x00FF)); \
1227 emit6bytes(code); \
1228 }
1230#undef DECLARE_VRI_A_INSTRUCTIONS
1231
1232#define DECLARE_VRI_C_INSTRUCTIONS(name, opcode_name, opcode_value) \
1233 void name(DoubleRegister v1, DoubleRegister v2, const Operand& i2, \
1234 Condition m4) { \
1235 uint64_t code = (static_cast<uint64_t>(opcode_value & 0xFF00)) * B32 | \
1236 (static_cast<uint64_t>(v1.code())) * B36 | \
1237 (static_cast<uint64_t>(v2.code())) * B32 | \
1238 (static_cast<uint16_t>(i2.immediate())) * B16 | \
1239 (static_cast<uint64_t>(m4 & 0xF)) * B12 | \
1240 (static_cast<uint64_t>(0)) * B8 | \
1241 (static_cast<uint64_t>(opcode_value & 0x00FF)); \
1242 emit6bytes(code); \
1243 }
1245#undef DECLARE_VRI_C_INSTRUCTIONS
1246
1247 // Single Element format
1249 vfa(v1, v2, v3, static_cast<Condition>(0), static_cast<Condition>(8),
1250 static_cast<Condition>(3));
1251 }
1253 vfs(v1, v2, v3, static_cast<Condition>(0), static_cast<Condition>(8),
1254 static_cast<Condition>(3));
1255 }
1257 vfm(v1, v2, v3, static_cast<Condition>(0), static_cast<Condition>(8),
1258 static_cast<Condition>(3));
1259 }
1261 vfd(v1, v2, v3, static_cast<Condition>(0), static_cast<Condition>(8),
1262 static_cast<Condition>(3));
1263 }
1264
1265 // Load Address Instructions
1268
1269 // Exception-generating instructions and debugging support
1270 void stop(Condition cond = al, int32_t code = kDefaultStopCode,
1271 CRegister cr = cr7);
1272
1273 void bkpt(uint32_t imm16); // v5 and above
1274
1275 // Different nop operations are used by the code generator to detect certain
1276 // states of the generated code.
1278 NON_MARKING_NOP = 0,
1279 GROUP_ENDING_NOP,
1280 DEBUG_BREAK_NOP,
1281#if V8_OS_ZOS
1282 BASR_CALL_TYPE_NOP,
1283 BRAS_CALL_TYPE_NOP,
1284 BRASL_CALL_TYPE_NOP,
1285#endif
1286 // IC markers.
1287 PROPERTY_ACCESS_INLINED,
1288 PROPERTY_ACCESS_INLINED_CONTEXT,
1289 PROPERTY_ACCESS_INLINED_CONTEXT_DONT_DELETE,
1290 // Helper values.
1291 LAST_CODE_MARKER,
1292 FIRST_IC_MARKER = PROPERTY_ACCESS_INLINED
1293 };
1294
1295 void nop(int type = 0); // 0 is the default non-marking type.
1296
1297 void dumy(int r1, int x2, int b2, int d2);
1298
1299 // Check the code size generated from label to here.
1301 return pc_offset() - label->pos();
1302 }
1303
1304 // Record a deoptimization reason that can be used by a log or cpu profiler.
1305 // Use --trace-deopt to enable.
1306 void RecordDeoptReason(DeoptimizeReason reason, uint32_t node_id,
1307 SourcePosition position, int id);
1308
1309 // Writes a single byte or word of data in the code stream. Used
1310 // for inline tables, e.g., jump-tables.
1311 void db(uint8_t data);
1312 void dh(uint16_t data);
1313 void dd(uint32_t data);
1314 void dq(uint64_t data);
1315 void dp(uintptr_t data);
1316
1317 // Read/patch instructions
1319 return Instruction::InstructionBits(buffer_start_ + pos);
1320 }
1321 template <typename T>
1322 void instr_at_put(int pos, T instr) {
1323 Instruction::SetInstructionBits<T>(buffer_start_ + pos, instr);
1324 }
1325
1326 // Decodes instruction at pos, and returns its length
1327 int32_t instr_length_at(int pos) {
1328 return Instruction::InstructionLength(buffer_start_ + pos);
1329 }
1330
1331 static SixByteInstr instr_at(uint8_t* pc) {
1332 return Instruction::InstructionBits(pc);
1333 }
1334
1336
1337 static bool IsBranch(Instr instr);
1338 static bool Is64BitLoadIntoIP(SixByteInstr instr1, SixByteInstr instr2);
1339
1342 static bool IsNop(SixByteInstr instr, int type = NON_MARKING_NOP);
1343
1344 // The code currently calls CheckBuffer() too often. This has the side
1345 // effect of randomly growing the buffer in the middle of multi-instruction
1346 // sequences.
1347 //
1348 // This function allows outside callers to check and grow the buffer
1349 void EnsureSpaceFor(int space_needed);
1350
1353
1354 public:
1355 uint8_t* buffer_pos() const { return buffer_start_; }
1356
1357 // InstructionStream generation
1358 // The relocation writer's position is at least kGap bytes below the end of
1359 // the generated instructions. This is so that multi-instruction sequences do
1360 // not have to check for overflow. The same is true for writes of large
1361 // relocation info entries.
1362 static constexpr int kGap = 32;
1363 static_assert(AssemblerBase::kMinimalBufferSize >= 2 * kGap);
1364
1365 protected:
1366 int buffer_space() const { return reloc_info_writer.pos() - pc_; }
1367
1368 // Decode instruction(s) at pos and return backchain to previous
1369 // label reference or kEndOfChain.
1370 int target_at(int pos);
1371
1372 // Patch instruction(s) at pos to target target_pos (e.g. branch)
1373 void target_at_put(int pos, int target_pos, bool* is_branch = nullptr);
1374
1375 // Record reloc info for current pc_
1376 void RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data = 0);
1377
1378 private:
1379 // Avoid overflows for displacements etc.
1380 static const int kMaximalBufferSize = 512 * MB;
1381
1382 // Relocation info generation
1383 // Each relocation is encoded as a variable size value
1384 static constexpr int kMaxRelocSize = RelocInfoWriter::kMaxSize;
1385 RelocInfoWriter reloc_info_writer;
1386 std::vector<DeferredRelocInfo> relocations_;
1387
1388 // Scratch registers available for use by the Assembler.
1389 RegList scratch_register_list_;
1390 DoubleRegList scratch_double_register_list_;
1391
1392 // The bound position, before this we cannot do instruction elimination.
1393 int last_bound_pos_;
1394
1395 // Code emission
1397 if (buffer_space() <= kGap) {
1398 GrowBuffer();
1399 }
1400 }
1401 void GrowBuffer(int needed = 0);
1402 inline void TrackBranch();
1403 inline void UntrackBranch();
1404
1405 // Helper to emit the binary encoding of a 2 byte instruction
1406 void emit2bytes(uint16_t x) {
1407 CheckBuffer();
1408#if V8_TARGET_LITTLE_ENDIAN
1409 // We need to emit instructions in big endian format as disassembler /
1410 // simulator require the first byte of the instruction in order to decode
1411 // the instruction length. Swap the bytes.
1412 x = ((x & 0x00FF) << 8) | ((x & 0xFF00) >> 8);
1413#endif
1414 *reinterpret_cast<uint16_t*>(pc_) = x;
1415 pc_ += 2;
1416 }
1417
1418 // Helper to emit the binary encoding of a 4 byte instruction
1419 void emit4bytes(uint32_t x) {
1420 CheckBuffer();
1421#if V8_TARGET_LITTLE_ENDIAN
1422 // We need to emit instructions in big endian format as disassembler /
1423 // simulator require the first byte of the instruction in order to decode
1424 // the instruction length. Swap the bytes.
1425 x = ((x & 0x000000FF) << 24) | ((x & 0x0000FF00) << 8) |
1426 ((x & 0x00FF0000) >> 8) | ((x & 0xFF000000) >> 24);
1427#endif
1428 *reinterpret_cast<uint32_t*>(pc_) = x;
1429 pc_ += 4;
1430 }
1431
1432 // Helper to emit the binary encoding of a 6 byte instruction
1433 void emit6bytes(uint64_t x) {
1434 CheckBuffer();
1435#if V8_TARGET_LITTLE_ENDIAN
1436 // We need to emit instructions in big endian format as disassembler /
1437 // simulator require the first byte of the instruction in order to decode
1438 // the instruction length. Swap the bytes.
1439 x = (static_cast<uint64_t>(x & 0xFF) << 40) |
1440 (static_cast<uint64_t>((x >> 8) & 0xFF) << 32) |
1441 (static_cast<uint64_t>((x >> 16) & 0xFF) << 24) |
1442 (static_cast<uint64_t>((x >> 24) & 0xFF) << 16) |
1443 (static_cast<uint64_t>((x >> 32) & 0xFF) << 8) |
1444 (static_cast<uint64_t>((x >> 40) & 0xFF));
1445 x |= (*reinterpret_cast<uint64_t*>(pc_) >> 48) << 48;
1446#else
1447 // We need to pad two bytes of zeros in order to get the 6-bytes
1448 // stored from low address.
1449 x = x << 16;
1450 x |= *reinterpret_cast<uint64_t*>(pc_) & 0xFFFF;
1451#endif
1452 // It is safe to store 8-bytes, as CheckBuffer() guarantees we have kGap
1453 // space left over.
1454 *reinterpret_cast<uint64_t*>(pc_) = x;
1455 pc_ += 6;
1456 }
1457
1458 // Labels
1459 void print(Label* L);
1461 void bind_to(Label* L, int pos);
1462 void next(Label* L);
1463
1465
1467
1469 friend class RelocInfo;
1470 friend class EnsureSpace;
1471 friend class UseScratchRegisterScope;
1472};
1473
1474class EnsureSpace {
1475 public:
1476 explicit EnsureSpace(Assembler* assembler) { assembler->CheckBuffer(); }
1477};
1478
1480 public:
1482 : assembler_(assembler),
1483 old_available_(*assembler->GetScratchRegisterList()),
1484 old_available_double_(*assembler->GetScratchDoubleRegisterList()) {}
1485
1487 *assembler_->GetScratchRegisterList() = old_available_;
1488 *assembler_->GetScratchDoubleRegisterList() = old_available_double_;
1489 }
1490
1492 return assembler_->GetScratchRegisterList()->PopFirst();
1493 }
1494
1496 return assembler_->GetScratchDoubleRegisterList()->PopFirst();
1497 }
1498
1499 // Check if we have registers available to acquire.
1500 bool CanAcquire() const {
1501 return !assembler_->GetScratchRegisterList()->is_empty();
1502 }
1503
1504 void Include(const Register& reg1, const Register& reg2 = no_reg) {
1505 RegList* available = assembler_->GetScratchRegisterList();
1506 DCHECK_NOT_NULL(available);
1507 DCHECK(!available->has(reg1));
1508 DCHECK(!available->has(reg2));
1509 available->set(reg1);
1510 available->set(reg2);
1511 }
1512 void Include(RegList list) {
1513 RegList* available = assembler_->GetScratchRegisterList();
1514 DCHECK_NOT_NULL(available);
1515 *available = *available | list;
1516 }
1518 DoubleRegList* available = assembler_->GetScratchDoubleRegisterList();
1519 DCHECK_NOT_NULL(available);
1520 DCHECK_EQ((*available & list).bits(), 0x0);
1521 *available = *available | list;
1522 }
1523
1525 return *assembler_->GetScratchDoubleRegisterList();
1526 }
1528 *assembler_->GetScratchDoubleRegisterList() = available;
1529 }
1530 RegList Available() { return *assembler_->GetScratchRegisterList(); }
1531 void SetAvailable(RegList available) {
1532 *assembler_->GetScratchRegisterList() = available;
1533 }
1534
1535 private:
1536 friend class Assembler;
1537 friend class MacroAssembler;
1538
1540 RegList old_available_;
1541 DoubleRegList old_available_double_;
1542};
1543
1544} // namespace internal
1545} // namespace v8
1546
1547#endif // V8_CODEGEN_S390_ASSEMBLER_S390_H_
#define DECLARE_S390_RIS_INSTRUCTIONS(name, op_name, op_value)
#define DECLARE_VRI_C_INSTRUCTIONS(name, opcode_name, opcode_value)
#define DECLARE_S390_RRS_INSTRUCTIONS(name, op_name, op_value)
#define DECLARE_S390_RRD_INSTRUCTIONS(name, op_name, op_value)
#define DECLARE_S390_RSI_INSTRUCTIONS(name, op_name, op_value)
#define DECLARE_S390_RX_INSTRUCTIONS(name, op_name, op_value)
#define DECLARE_S390_RIE_E_INSTRUCTIONS(name, op_name, op_value)
#define DECLARE_S390_RXY_INSTRUCTIONS(name, op_name, op_value)
#define DECLARE_S390_RRF_E_INSTRUCTIONS(name, op_name, op_value)
#define DECLARE_VRI_A_INSTRUCTIONS(name, opcode_name, opcode_value)
#define DECLARE_S390_RRF_B_INSTRUCTIONS(name, op_name, op_value)
#define DECLARE_VRR_B_INSTRUCTIONS(name, opcode_name, opcode_value)
#define DECLARE_VRS_C_INSTRUCTIONS(name, opcode_name, opcode_value)
#define DECLARE_VRS_B_INSTRUCTIONS(name, opcode_name, opcode_value)
#define DECLARE_S390_RIL_AB_INSTRUCTIONS(name, op_name, op_value)
#define DECLARE_VRR_C_INSTRUCTIONS(name, opcode_name, opcode_value)
#define DECLARE_VRR_F_INSTRUCTIONS(name, opcode_name, opcode_value)
#define DECLARE_S390_SI_INSTRUCTIONS(name, op_name, op_value)
#define DECLARE_VRS_A_INSTRUCTIONS(name, opcode_name, opcode_value)
#define DECLARE_S390_RRE_INSTRUCTIONS(name, op_name, op_value)
#define DECLARE_S390_RIE_F_INSTRUCTIONS(name, op_name, op_value)
#define DECLARE_S390_SS_A_INSTRUCTIONS(name, op_name, op_value)
#define DECLARE_S390_RIL_C_INSTRUCTIONS(name, op_name, op_value)
#define DECLARE_S390_RXE_INSTRUCTIONS(name, op_name, op_value)
#define DECLARE_S390_RSY_B_INSTRUCTIONS(name, op_name, op_value)
#define DECLARE_S390_RI_C_INSTRUCTIONS(name, op_name, op_value)
#define DECLARE_S390_RS_A_INSTRUCTIONS(name, op_name, op_value)
#define DECLARE_S390_RRF_C_INSTRUCTIONS(name, op_name, op_value)
#define DECLARE_S390_RRF_A_INSTRUCTIONS(name, op_name, op_value)
#define DECLARE_S390_SIL_INSTRUCTIONS(name, op_name, op_value)
#define DECLARE_S390_RS_B_INSTRUCTIONS(name, op_name, op_value)
#define DECLARE_S390_S_INSTRUCTIONS(name, op_name, op_value)
#define DECLARE_S390_RRF_D_INSTRUCTIONS(name, op_name, op_value)
#define DECLARE_VRR_E_INSTRUCTIONS(name, opcode_name, opcode_value)
#define DECLARE_S390_RS_SHIFT_FORMAT(name, opcode)
#define DECLARE_S390_RSL_B_INSTRUCTIONS(name, op_name, op_value)
#define DECLARE_S390_RSL_A_INSTRUCTIONS(name, op_name, op_value)
#define DECLARE_S390_SIY_INSTRUCTIONS(name, op_name, op_value)
#define DECLARE_S390_RI_A_INSTRUCTIONS(name, op_name, op_value)
#define DECLARE_S390_RR_INSTRUCTIONS(name, op_name, op_value)
#define DECLARE_S390_RIE_D_INSTRUCTIONS(name, op_name, op_value)
#define DECLARE_S390_RI_B_INSTRUCTIONS(name, op_name, op_value)
#define DECLARE_S390_RSY_A_INSTRUCTIONS(name, op_name, op_value)
#define DECLARE_VRX_INSTRUCTIONS(name, opcode_name, opcode_value)
#define DECLARE_VRR_A_INSTRUCTIONS(name, opcode_name, opcode_value)
SourcePosition pos
static void DebugBreak()
void bind_to(Label *L, int pos)
void cgdbr(Condition m3, R1 r1, R2 r2)
SixByteInstr instr_at(int pos)
void GetCode(LocalIsolate *isolate, CodeDesc *desc)
void rs_format(Opcode op, int f1, int f2, int f3, const int f4)
void lgrl(Register r, Label *l)
void emit2bytes(uint16_t x)
void b(Condition cond, Register r)
void ble(Label *l, Label::Distance dist=Label::kFar)
static bool IsCmpRegister(Instr instr)
void lzer(DoubleRegister r1)
uint8_t * buffer_pos() const
Assembler(const MaybeAssemblerZone &, const AssemblerOptions &options, std::unique_ptr< AssemblerBuffer > buffer={})
void rie_f_format(Opcode opcode, int f1, int f2, int f3, int f4, int f5)
static int deserialization_special_target_size(Address instruction_payload)
static SixByteInstr instr_at(uint8_t *pc)
void rr_format(Opcode opcode, int f1, int f2)
void stop(Condition cond=al, int32_t code=kDefaultStopCode, CRegister cr=cr7)
void AllocateAndInstallRequestedHeapNumbers(LocalIsolate *isolate)
void emit_label_addr(Label *label)
void pfd(Condition cond, Register x2, Register b2, const Operand &d2)
static bool IsCmpImmediate(Instr instr)
static void deserialization_set_target_internal_reference_at(Address pc, Address target, WritableJitAllocation &jit_allocation, RelocInfo::Mode mode=RelocInfo::INTERNAL_REFERENCE)
void branchOnCond(Condition c, int branch_offset, bool is_bound=false, bool force_long_branch=false)
static bool IsNop(SixByteInstr instr, int type=NON_MARKING_NOP)
DoubleRegList * GetScratchDoubleRegisterList()
void call(Handle< Code > target, RelocInfo::Mode rmode)
void bc_long(Condition cond, Label *l)
void db(uint8_t data)
void vfs(DoubleRegister v1, DoubleRegister v2, DoubleRegister v3)
void jump(Handle< Code > target, RelocInfo::Mode rmode, Condition cond)
void rsl_format(Opcode op, uint16_t f1, int f2, int f3, int f4, int f5)
void s_format(Opcode op, int f1, int f2)
void cdfbr(R1 r1, R2 r2)
void b(Label *l, Label::Distance dist=Label::kFar)
void emit6bytes(uint64_t x)
void rxy_format(Opcode opcode, int f1, int f2, int f3, int f4)
void bunordered(Label *l, Label::Distance dist=Label::kFar)
void ledbr(R1 r1, R2 r2)
void load_label_offset(Register r1, Label *L)
void rrd_format(Opcode opcode, int f1, int f2, int f3)
static void set_uint32_constant_at(Address pc, Address constant_pool, uint32_t new_constant, WritableJitAllocation *jit_allocation, ICacheFlushMode icache_flush_mode=FLUSH_ICACHE_IF_NEEDED)
void print(Label *L)
void brxh(Register dst, Register inc, Label *L)
void RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data=0)
void b(Register r, Label *l)
void rsy_format(Opcode op, int f1, int f2, int f3, int f4)
void sil_format(Opcode op, int f1, int f2, int f3)
void cfdbr(Condition m3, R1 r1, R2 r2)
static uint32_t uint32_constant_at(Address pc, Address constant_pool)
void dumy(int r1, int x2, int b2, int d2)
static V8_INLINE void set_target_address_at(Address pc, Address constant_pool, Address target, WritableJitAllocation *jit_allocation, ICacheFlushMode icache_flush_mode=FLUSH_ICACHE_IF_NEEDED)
RegList * GetScratchRegisterList()
void vfm(DoubleRegister v1, DoubleRegister v2, DoubleRegister v3)
static Tagged_t target_compressed_address_at(Address pc, Address constant_pool)
void cfebr(Condition m3, R1 r1, R2 r2)
void rrf_format(Opcode op, int f1, int f2, int f3, int f4)
void cdgbr(R1 r1, R2 r2)
void beq(Label *l, Label::Distance dist=Label::kFar)
void larl(Register r, Label *l)
void rx_format(Opcode opcode, int f1, int f2, int f3, int f4)
static bool IsBranch(Instr instr)
void jmp(Label *l, Label::Distance dist=Label::kFar)
void EnsureSpaceFor(int space_needed)
void cegbr(R1 r1, R2 r2)
void b(Condition cond, Label *l, Label::Distance dist=Label::kFar, bool force_long_branch=false)
void GetCode(Isolate *isolate, CodeDesc *desc)
void breakpoint(bool do_print)
void ri_format(Opcode opcode, int f1, int f2)
void vfa(DoubleRegister v1, DoubleRegister v2, DoubleRegister v3)
void bordered(Register r)
void bc(Condition cond, Register x2, Register b2, const Operand &d2)
Handle< HeapObject > compressed_embedded_object_handle_at(Address pc, Address constant_pool)
void target_at_put(int pos, int target_pos, bool *is_branch=nullptr)
Handle< Object > code_target_object_handle_at(Address pc)
void dq(uint64_t data)
void si_format(Opcode op, int f1, int f2, int f3)
void instr_at_put(int pos, T instr)
static V8_INLINE Address target_address_at(Address pc, Address constant_pool)
void brxhg(Register dst, Register inc, Label *L)
void bgt(Label *l, Label::Distance dist=Label::kFar)
void rie_d_format(Opcode opcode, int f1, int f2, int f3, int f4)
void GetCode(LocalIsolate *isolate, CodeDesc *desc, SafepointTableBuilderBase *safepoint_table_builder, int handler_table_offset)
void emit4bytes(uint32_t x)
void bge(Label *l, Label::Distance dist=Label::kFar)
void dp(uintptr_t data)
void bordered(Label *l, Label::Distance dist=Label::kFar)
void ris_format(Opcode op, int f1, int f2, int f3, int f4, int f5)
void bne(Label *l, Label::Distance dist=Label::kFar)
void rxe_format(Opcode op, int f1, int f2, int f3, int f4, int f5=0)
int32_t instr_length_at(int pos)
static Condition GetCondition(Instr instr)
void cgebr(Condition m3, R1 r1, R2 r2)
void ril_format(Opcode opcode, int f1, int f2)
void rsi_format(Opcode op, int f1, int f2, int f3)
void nop(int type=0)
void bc_short(Condition cond, Label *l, Label::Distance dist=Label::kFar)
void bkpt(uint32_t imm16)
void dd(uint32_t data)
void blt(Label *l, Label::Distance dist=Label::kFar)
void rre_format(Opcode opcode, int f1, int f2)
Assembler(const AssemblerOptions &, std::unique_ptr< AssemblerBuffer >={})
static bool Is64BitLoadIntoIP(SixByteInstr instr1, SixByteInstr instr2)
void ss_a_format(Opcode op, int f1, int f2, int f3, int f4, int f5)
int SizeOfCodeGeneratedSince(Label *label)
void rrs_format(Opcode op, int f1, int f2, int f3, int f4, int f5)
void RecordDeoptReason(DeoptimizeReason reason, uint32_t node_id, SourcePosition position, int id)
void dh(uint16_t data)
void siy_format(Opcode op, int f1, int f2, int f3)
void rie_e_format(Opcode opcode, int f1, int f2, int f3)
void bunordered(Register r)
void vfd(DoubleRegister v1, DoubleRegister v2, DoubleRegister v3)
static void set_target_compressed_address_at(Address pc, Address constant_pool, Tagged_t target, WritableJitAllocation *jit_allocation, ICacheFlushMode icache_flush_mode=FLUSH_ICACHE_IF_NEEDED)
int max_reach_from(int pos)
void GrowBuffer(int needed=0)
RelocInfo::Mode rmode() const
DeferredRelocInfo(int position, RelocInfo::Mode rmode, intptr_t data)
EnsureSpace(Assembler *assembler)
V8_EXPORT_PRIVATE Address address() const
MemOperand(Register rx, Register rb, Disp offset=0)
Register getBaseRegister() const
Register getIndexRegister() const
MemOperand(Register rx, Disp offset=0)
uint32_t getDisplacement() const
intptr_t immediate() const
V8_INLINE Operand(Tagged< Smi > value)
bool is_heap_number_request() const
RelocInfo::Mode rmode() const
V8_INLINE Operand(const ExternalReference &f)
static Operand EmbeddedNumber(double value)
bool must_output_reloc_info(const Assembler *assembler) const
Operand(Handle< HeapObject > handle)
HeapNumberRequest heap_number_request() const
V8_INLINE bool is_reg() const
Register rm() const
V8_INLINE Operand(intptr_t immediate, RelocInfo::Mode rmode=RelocInfo::NO_INFO)
static V8_INLINE Operand Zero()
int32_t immediate() const
V8_INLINE Operand(Register rm)
constexpr int8_t code() const
UseScratchRegisterScope(Assembler *assembler)
void SetAvailableDoubleRegList(DoubleRegList available)
void Include(const Register &reg1, const Register &reg2=no_reg)
Operand const offset_
Register const value_
#define S390_RIE_E_OPCODE_LIST(V)
#define S390_RRD_OPCODE_LIST(V)
#define S390_VRR_E_OPCODE_LIST(V)
#define S390_SIY_OPCODE_LIST(V)
#define S390_RRF_A_OPCODE_LIST(V)
#define S390_VRI_A_OPCODE_LIST(V)
#define S390_RSL_B_OPCODE_LIST(V)
#define S390_VRI_C_OPCODE_LIST(V)
#define S390_S_OPCODE_LIST(V)
#define S390_RRF_C_OPCODE_LIST(V)
#define S390_RRE_OPCODE_LIST(V)
#define S390_VRR_C_OPCODE_LIST(V)
#define S390_SS_A_OPCODE_LIST(V)
#define S390_RSY_B_OPCODE_LIST(V)
#define S390_RXE_OPCODE_LIST(V)
#define S390_VRS_A_OPCODE_LIST(V)
#define S390_RIE_F_OPCODE_LIST(V)
#define S390_VRR_A_OPCODE_LIST(V)
#define S390_RXY_A_OPCODE_LIST(V)
#define S390_VRS_B_OPCODE_LIST(V)
#define S390_RI_B_OPCODE_LIST(V)
#define S390_RS_A_OPCODE_LIST(V)
#define S390_RSY_A_OPCODE_LIST(V)
#define S390_RI_A_OPCODE_LIST(V)
#define S390_VRR_F_OPCODE_LIST(V)
#define S390_VRR_B_OPCODE_LIST(V)
#define S390_SIL_OPCODE_LIST(V)
#define S390_RIL_A_OPCODE_LIST(V)
#define S390_RIL_B_OPCODE_LIST(V)
#define S390_VRS_C_OPCODE_LIST(V)
#define S390_RRF_D_OPCODE_LIST(V)
#define S390_RSL_A_OPCODE_LIST(V)
#define S390_RRF_E_OPCODE_LIST(V)
#define S390_RIL_C_OPCODE_LIST(V)
#define S390_RIE_D_OPCODE_LIST(V)
#define S390_VRX_OPCODE_LIST(V)
#define S390_RRF_B_OPCODE_LIST(V)
#define S390_RI_C_OPCODE_LIST(V)
#define S390_RX_A_OPCODE_LIST(V)
#define S390_SI_OPCODE_LIST(V)
#define S390_RIS_OPCODE_LIST(V)
#define S390_RS_B_OPCODE_LIST(V)
#define S390_RSI_OPCODE_LIST(V)
#define S390_RRS_OPCODE_LIST(V)
#define S390_RR_OPCODE_LIST(V)
Label label
BytecodeAssembler & assembler_
too high values may cause the compiler to set high thresholds for inlining to as much as possible avoid inlined allocation of objects that cannot escape trace load stores from virtual maglev objects use TurboFan fast string builder analyze liveness of environment slots and zap dead values trace TurboFan load elimination emit data about basic block usage in builtins to this enable builtin reordering when run mksnapshot flag for emit warnings when applying builtin profile data verify register allocation in TurboFan randomly schedule instructions to stress dependency tracking enable store store elimination in TurboFan rewrite far to near simulate GC compiler thread race related to allow float parameters to be passed in simulator mode JS Wasm Run additional turbo_optimize_inlined_js_wasm_wrappers enable experimental feedback collection in generic lowering enable Turboshaft s WasmLoadElimination enable Turboshaft s low level load elimination for JS enable Turboshaft s escape analysis for string concatenation use enable Turbolev features that we want to ship in the not too far future trace individual Turboshaft reduction steps trace intermediate Turboshaft reduction steps invocation count threshold for early optimization Enables optimizations which favor memory size over execution speed Enables sampling allocation profiler with X as a sample interval min size of a semi the new space consists of two semi spaces max size of the Collect garbage after Collect garbage after keeps maps alive for< n > old space garbage collections print one detailed trace line in allocation gc speed threshold for starting incremental marking via a task in percent of available threshold for starting incremental marking immediately in percent of available Use a single schedule for determining a marking schedule between JS and C objects schedules the minor GC task with kUserVisible priority max worker number of concurrent for NumberOfWorkerThreads start background threads that allocate memory concurrent_array_buffer_sweeping use parallel threads to clear weak refs in the atomic pause trace progress of the incremental marking trace object counts and memory usage * MB
int32_t offset
Instruction * instr
int pc_offset
int x
int position
Definition liveedit.cc:290
uint32_t const mask
int m
Definition mul-fft.cc:294
int n
Definition mul-fft.cc:296
int r
Definition mul-fft.cc:298
STL namespace.
constexpr Register no_reg
uint64_t SixByteInstr
void PrintF(const char *format,...)
Definition utils.cc:39
std::variant< Zone *, AccountingAllocator * > MaybeAssemblerZone
Definition assembler.h:262
Address Tagged_t
Definition globals.h:547
constexpr int L
constexpr Opcode BC
#define CHECK(condition)
Definition logging.h:124
#define DCHECK_NOT_NULL(val)
Definition logging.h:492
#define DCHECK_IMPLIES(v1, v2)
Definition logging.h:493
#define DCHECK_NE(v1, v2)
Definition logging.h:486
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
#define DCHECK_GT(v1, v2)
Definition logging.h:487
#define V8_EXPORT_PRIVATE
Definition macros.h:460
#define V8_INLINE
Definition v8config.h:500
#define V8_NODISCARD
Definition v8config.h:693
std::unique_ptr< ValueMirror > value