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