assembler-s390.h 56.9 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
// Copyright (c) 1994-2006 Sun Microsystems Inc.
// All Rights Reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// - Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// - Redistribution in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the
// distribution.
//
// - Neither the name of Sun Microsystems or the names of contributors may
// be used to endorse or promote products derived from this software without
// specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.

// The original source code covered by the above license above has been
// modified significantly by Google Inc.
// Copyright 2014 the V8 project authors. All rights reserved.

// A light-weight S390 Assembler
// Generates user mode instructions for z/Architecture

#ifndef V8_S390_ASSEMBLER_S390_H_
#define V8_S390_ASSEMBLER_S390_H_
#include <stdio.h>
#if V8_HOST_ARCH_S390
// elf.h include is required for auxv check for STFLE facility used
// for hardware detection, which is sensible only on s390 hosts.
#include <elf.h>
#endif

#include <fcntl.h>
#include <unistd.h>
51 52
#include <vector>

53
#include "src/assembler.h"
54 55
#include "src/external-reference.h"
#include "src/label.h"
56
#include "src/objects/smi.h"
57
#include "src/s390/constants-s390.h"
58
#include "src/s390/register-s390.h"
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83

#define ABI_USES_FUNCTION_DESCRIPTORS 0

#define ABI_PASSES_HANDLES_IN_REGS 1

// ObjectPair is defined under runtime/runtime-util.h.
// On 31-bit, ObjectPair == uint64_t.  ABI dictates long long
//            be returned with the lower addressed half in r2
//            and the higher addressed half in r3. (Returns in Regs)
// On 64-bit, ObjectPair is a Struct.  ABI dictaes Structs be
//            returned in a storage buffer allocated by the caller,
//            with the address of this buffer passed as a hidden
//            argument in r2. (Does NOT return in Regs)
// For x86 linux, ObjectPair is returned in registers.
#if V8_TARGET_ARCH_S390X
#define ABI_RETURNS_OBJECTPAIR_IN_REGS 0
#else
#define ABI_RETURNS_OBJECTPAIR_IN_REGS 1
#endif

#define ABI_CALL_VIA_IP 1

namespace v8 {
namespace internal {

84 85
class SafepointTableBuilder;

86 87 88 89 90
// -----------------------------------------------------------------------------
// Machine instruction Operands

// Class Operand represents a shifter operand in data processing instructions
// defining immediate numbers and masks
91
class Operand {
92 93
 public:
  // immediate
94 95 96
  V8_INLINE explicit Operand(intptr_t immediate,
                             RelocInfo::Mode rmode = RelocInfo::NONE)
      : rmode_(rmode) {
97 98
    value_.immediate = immediate;
  }
99 100 101
  V8_INLINE static Operand Zero() { return Operand(static_cast<intptr_t>(0)); }
  V8_INLINE explicit Operand(const ExternalReference& f)
      : rmode_(RelocInfo::EXTERNAL_REFERENCE) {
102
    value_.immediate = static_cast<intptr_t>(f.address());
103
  }
104
  explicit Operand(Handle<HeapObject> handle);
105 106
  V8_INLINE explicit Operand(Smi value) : rmode_(RelocInfo::NONE) {
    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 119 120 121

  bool must_output_reloc_info(const Assembler* assembler) const;

  inline intptr_t immediate() const {
    DCHECK(!rm_.is_valid());
122 123 124 125 126 127 128
    DCHECK(!is_heap_object_request());
    return value_.immediate;
  }

  HeapObjectRequest heap_object_request() const {
    DCHECK(is_heap_object_request());
    return value_.heap_object_request;
129 130 131
  }

  inline void setBits(int n) {
132 133
    value_.immediate =
        (static_cast<uint32_t>(value_.immediate) << (32 - n)) >> (32 - n);
134 135 136 137
  }

  Register rm() const { return rm_; }

138 139 140 141 142 143 144 145
  bool is_heap_object_request() const {
    DCHECK_IMPLIES(is_heap_object_request_, !rm_.is_valid());
    DCHECK_IMPLIES(is_heap_object_request_,
                   rmode_ == RelocInfo::EMBEDDED_OBJECT ||
                       rmode_ == RelocInfo::CODE_TARGET);
    return is_heap_object_request_;
  }

146 147
  RelocInfo::Mode rmode() const { return rmode_; }

148
 private:
149
  Register rm_ = no_reg;
150 151 152 153 154 155 156
  union Value {
    Value() {}
    HeapObjectRequest heap_object_request;  // if is_heap_object_request_
    intptr_t immediate;                     // otherwise
  } value_;                                 // valid if rm_ == no_reg
  bool is_heap_object_request_ = false;

157 158 159 160 161 162 163 164 165 166 167 168 169
  RelocInfo::Mode rmode_;

  friend class Assembler;
  friend class MacroAssembler;
};

typedef int32_t Disp;

// Class MemOperand represents a memory operand in load and store instructions
// On S390, we have various flavours of memory operands:
//   1) a base register + 16 bit unsigned displacement
//   2) a base register + index register + 16 bit unsigned displacement
//   3) a base register + index register + 20 bit signed displacement
170
class MemOperand {
171 172 173 174 175 176 177 178 179
 public:
  explicit MemOperand(Register rx, Disp offset = 0);
  explicit MemOperand(Register rx, Register rb, Disp offset = 0);

  int32_t offset() const { return offset_; }
  uint32_t getDisplacement() const { return offset(); }

  // Base register
  Register rb() const {
180
    DCHECK(baseRegister != no_reg);
181 182 183 184 185 186 187
    return baseRegister;
  }

  Register getBaseRegister() const { return rb(); }

  // Index Register
  Register rx() const {
188
    DCHECK(indexRegister != no_reg);
189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216
    return indexRegister;
  }
  Register getIndexRegister() const { return rx(); }

 private:
  Register baseRegister;   // base
  Register indexRegister;  // index
  int32_t offset_;         // offset

  friend class Assembler;
};

class DeferredRelocInfo {
 public:
  DeferredRelocInfo() {}
  DeferredRelocInfo(int position, RelocInfo::Mode rmode, intptr_t data)
      : position_(position), rmode_(rmode), data_(data) {}

  int position() const { return position_; }
  RelocInfo::Mode rmode() const { return rmode_; }
  intptr_t data() const { return data_; }

 private:
  int position_;
  RelocInfo::Mode rmode_;
  intptr_t data_;
};

217
class V8_EXPORT_PRIVATE Assembler : public AssemblerBase {
218 219 220 221 222 223
 public:
  // Create an assembler. Instructions and relocation information are emitted
  // into a buffer, with the instructions starting from the beginning and the
  // relocation information starting from the end of the buffer. See CodeDesc
  // for a detailed comment on the layout (globals.h).
  //
224
  // If the provided buffer is nullptr, the assembler allocates and grows its
225 226 227 228
  // own buffer. Otherwise it takes ownership of the provided buffer.
  explicit Assembler(const AssemblerOptions&,
                     std::unique_ptr<AssemblerBuffer> = {});

229 230
  virtual ~Assembler() {}

231 232 233 234 235 236 237 238 239 240 241
  // GetCode emits any pending (non-emitted) code and fills the descriptor desc.
  static constexpr int kNoHandlerTable = 0;
  static constexpr SafepointTableBuilder* kNoSafepointTable = nullptr;
  void GetCode(Isolate* isolate, CodeDesc* desc,
               SafepointTableBuilder* safepoint_table_builder,
               int handler_table_offset);

  // Convenience wrapper for code without safepoint or handler tables.
  void GetCode(Isolate* isolate, CodeDesc* desc) {
    GetCode(isolate, desc, kNoSafepointTable, kNoHandlerTable);
  }
242

243 244 245
  // Unused on this architecture.
  void MaybeEmitOutOfLineConstantPool() {}

246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281
  // Label operations & relative jumps (PPUM Appendix D)
  //
  // Takes a branch opcode (cc) and a label (L) and generates
  // either a backward branch or a forward branch and links it
  // to the label fixup chain. Usage:
  //
  // Label L;    // unbound label
  // j(cc, &L);  // forward branch to unbound label
  // bind(&L);   // bind label to the current pc
  // j(cc, &L);  // backward branch to bound label
  // bind(&L);   // illegal: a label may be bound only once
  //
  // Note: The same Label can be used for forward and backward branches
  // but it may be bound only once.

  void bind(Label* L);  // binds an unbound label L to the current code position

  // Links a label at the current pc_offset().  If already bound, returns the
  // bound position.  If already linked, returns the position of the prior link.
  // Otherwise, returns the current pc_offset().
  int link(Label* L);

  // Determines if Label is bound and near enough so that a single
  // branch instruction can be used to reach it.
  bool is_near(Label* L, Condition cond);

  // Returns the branch offset to the given label from the current code position
  // Links the label to the current position if it is still unbound
  int branch_offset(Label* L) { return link(L) - pc_offset(); }

  // Puts a labels target address at the given position.
  // The high 8 bits are set to zero.
  void label_at_put(Label* L, int at_offset);
  void load_label_offset(Register r1, Label* L);

  // Read/Modify the code target address in the branch/call instruction at pc.
282
  // The isolate argument is unused (and may be nullptr) when skipping flushing.
283 284
  V8_INLINE static Address target_address_at(Address pc, Address constant_pool);
  V8_INLINE static void set_target_address_at(
285
      Address pc, Address constant_pool, Address target,
286
      ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED);
287 288 289 290 291 292 293

  // Return the code target address at a call site from the return address
  // of that call in the instruction stream.
  inline static Address target_address_from_return_address(Address pc);

  // Given the address of the beginning of a call, return the address
  // in the instruction stream that the call will return to.
294
  V8_INLINE static Address return_address_from_call_start(Address pc);
295 296 297 298 299

  inline Handle<Object> code_target_object_handle_at(Address pc);
  // This sets the branch destination.
  // This is for calls and branches within generated code.
  inline static void deserialization_set_special_target_at(
300
      Address instruction_payload, Code code, Address target);
301

302 303 304 305
  // Get the size of the special target encoded at 'instruction_payload'.
  inline static int deserialization_special_target_size(
      Address instruction_payload);

306 307
  // This sets the internal reference at the pc.
  inline static void deserialization_set_target_internal_reference_at(
308
      Address pc, Address target,
309 310 311 312 313 314 315 316
      RelocInfo::Mode mode = RelocInfo::INTERNAL_REFERENCE);

  // Here we are patching the address in the IIHF/IILF instruction pair.
  // These values are used in the serialization process and must be zero for
  // S390 platform, as Code, Embedded Object or External-reference pointers
  // are split across two consecutive instructions and don't exist separately
  // in the code, so the serializer should not step forwards in memory after
  // a target is resolved and written.
317
  static constexpr int kSpecialTargetSize = 0;
318 319 320

// Number of bytes for instructions used to store pointer sized constant.
#if V8_TARGET_ARCH_S390X
321
  static constexpr int kBytesForPtrConstant = 12;  // IIHF + IILF
322
#else
323
  static constexpr int kBytesForPtrConstant = 6;  // IILF
324 325 326 327 328 329 330 331
#endif

  // Distance between the instruction referring to the address of the call
  // target and the return address.

  // Offset between call target address and return address
  // for BRASL calls
  // Patch will be appiled to other FIXED_SEQUENCE call
332
  static constexpr int kCallTargetAddressOffset = 6;
333 334 335 336

  // ---------------------------------------------------------------------------
  // Code generation

337 338 339
  template <class T, int size, int lo, int hi>
  inline T getfield(T value) {
    DCHECK(lo < hi);
340
    DCHECK_GT(size, 0);
341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417
    int mask = hi - lo;
    int shift = size * 8 - hi;
    uint32_t mask_value = (mask == 32) ? 0xffffffff : (1 << mask) - 1;
    return (value & mask_value) << shift;
  }

#define DECLARE_S390_RIL_AB_INSTRUCTIONS(name, op_name, op_value) \
  template <class R1>                                             \
  inline void name(R1 r1, const Operand& i2) {                    \
    ril_format(op_name, r1.code(), i2.immediate());               \
  }
#define DECLARE_S390_RIL_C_INSTRUCTIONS(name, op_name, op_value) \
  inline void name(Condition m1, const Operand& i2) {            \
    ril_format(op_name, m1, i2.immediate());                     \
  }

  inline void ril_format(Opcode opcode, int f1, int f2) {
    uint32_t op1 = opcode >> 4;
    uint32_t op2 = opcode & 0xf;
    emit6bytes(
        getfield<uint64_t, 6, 0, 8>(op1) | getfield<uint64_t, 6, 8, 12>(f1) |
        getfield<uint64_t, 6, 12, 16>(op2) | getfield<uint64_t, 6, 16, 48>(f2));
  }
  S390_RIL_A_OPCODE_LIST(DECLARE_S390_RIL_AB_INSTRUCTIONS)
  S390_RIL_B_OPCODE_LIST(DECLARE_S390_RIL_AB_INSTRUCTIONS)
  S390_RIL_C_OPCODE_LIST(DECLARE_S390_RIL_C_INSTRUCTIONS)
#undef DECLARE_S390_RIL_AB_INSTRUCTIONS
#undef DECLARE_S390_RIL_C_INSTRUCTIONS

#define DECLARE_S390_RR_INSTRUCTIONS(name, op_name, op_value) \
  inline void name(Register r1, Register r2) {                \
    rr_format(op_name, r1.code(), r2.code());                 \
  }                                                           \
  inline void name(DoubleRegister r1, DoubleRegister r2) {    \
    rr_format(op_name, r1.code(), r2.code());                 \
  }                                                           \
  inline void name(Condition m1, Register r2) {               \
    rr_format(op_name, m1, r2.code());                        \
  }

  inline void rr_format(Opcode opcode, int f1, int f2) {
    emit2bytes(getfield<uint16_t, 2, 0, 8>(opcode) |
               getfield<uint16_t, 2, 8, 12>(f1) |
               getfield<uint16_t, 2, 12, 16>(f2));
  }
  S390_RR_OPCODE_LIST(DECLARE_S390_RR_INSTRUCTIONS)
#undef DECLARE_S390_RR_INSTRUCTIONS

#define DECLARE_S390_RRD_INSTRUCTIONS(name, op_name, op_value) \
  template <class R1, class R2, class R3>                      \
  inline void name(R1 r1, R3 r3, R2 r2) {                      \
    rrd_format(op_name, r1.code(), r3.code(), r2.code());      \
  }
  inline void rrd_format(Opcode opcode, int f1, int f2, int f3) {
    emit4bytes(getfield<uint32_t, 4, 0, 16>(opcode) |
               getfield<uint32_t, 4, 16, 20>(f1) |
               getfield<uint32_t, 4, 24, 28>(f2) |
               getfield<uint32_t, 4, 28, 32>(f3));
  }
  S390_RRD_OPCODE_LIST(DECLARE_S390_RRD_INSTRUCTIONS)
#undef DECLARE_S390_RRD_INSTRUCTIONS

#define DECLARE_S390_RRE_INSTRUCTIONS(name, op_name, op_value) \
  template <class R1, class R2>                                \
  inline void name(R1 r1, R2 r2) {                             \
    rre_format(op_name, r1.code(), r2.code());                 \
  }
  inline void rre_format(Opcode opcode, int f1, int f2) {
    emit4bytes(getfield<uint32_t, 4, 0, 16>(opcode) |
               getfield<uint32_t, 4, 24, 28>(f1) |
               getfield<uint32_t, 4, 28, 32>(f2));
  }
  S390_RRE_OPCODE_LIST(DECLARE_S390_RRE_INSTRUCTIONS)
  // Special format
  void lzdr(DoubleRegister r1) { rre_format(LZDR, r1.code(), 0); }
#undef DECLARE_S390_RRE_INSTRUCTIONS

418 419 420 421 422 423 424 425 426 427
#define DECLARE_S390_RX_INSTRUCTIONS(name, op_name, op_value)            \
  template <class R1>                                                    \
  inline void name(R1 r1, Register x2, Register b2, const Operand& d2) { \
    rx_format(op_name, r1.code(), x2.code(), b2.code(),                  \
              d2.immediate());                                           \
  }                                                                      \
  template <class R1>                                                    \
  inline void name(R1 r1, const MemOperand& opnd) {                      \
    name(r1, opnd.getIndexRegister(), opnd.getBaseRegister(),            \
         Operand(opnd.getDisplacement()));                               \
428 429 430 431 432 433 434 435 436 437 438 439 440 441 442
  }

  inline void rx_format(Opcode opcode, int f1, int f2, int f3, int f4) {
    DCHECK(is_uint8(opcode));
    DCHECK(is_uint12(f4));
    emit4bytes(getfield<uint32_t, 4, 0, 8>(opcode) |
               getfield<uint32_t, 4, 8, 12>(f1) |
               getfield<uint32_t, 4, 12, 16>(f2) |
               getfield<uint32_t, 4, 16, 20>(f3) |
               getfield<uint32_t, 4, 20, 32>(f4));
  }
  S390_RX_A_OPCODE_LIST(DECLARE_S390_RX_INSTRUCTIONS)

  void bc(Condition cond, const MemOperand& opnd) {
    bc(cond, opnd.getIndexRegister(),
443
       opnd.getBaseRegister(), Operand(opnd.getDisplacement()));
444
  }
445 446
  void bc(Condition cond, Register x2, Register b2, const Operand& d2) {
    rx_format(BC, cond, x2.code(), b2.code(), d2.immediate());
447 448 449
  }
#undef DECLARE_S390_RX_INSTRUCTIONS

450 451 452 453 454 455 456 457 458
#define DECLARE_S390_RXY_INSTRUCTIONS(name, op_name, op_value)            \
  template <class R1, class R2>                                           \
  inline void name(R1 r1, R2 r2, Register b2, const Operand& d2) {        \
    rxy_format(op_name, r1.code(), r2.code(), b2.code(), d2.immediate()); \
  }                                                                       \
  template <class R1>                                                     \
  inline void name(R1 r1, const MemOperand& opnd) {                       \
    name(r1, opnd.getIndexRegister(), opnd.getBaseRegister(),             \
         Operand(opnd.getDisplacement()));                                \
459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475
  }

  inline void rxy_format(Opcode opcode, int f1, int f2, int f3, int f4) {
    DCHECK(is_uint16(opcode));
    DCHECK(is_int20(f4));
    emit6bytes(getfield<uint64_t, 6, 0, 8>(opcode >> 8) |
               getfield<uint64_t, 6, 8, 12>(f1) |
               getfield<uint64_t, 6, 12, 16>(f2) |
               getfield<uint64_t, 6, 16, 20>(f3) |
               getfield<uint64_t, 6, 20, 32>(f4 & 0x0fff) |
               getfield<uint64_t, 6, 32, 40>(f4 >> 12) |
               getfield<uint64_t, 6, 40, 48>(opcode & 0x00ff));
  }
  S390_RXY_A_OPCODE_LIST(DECLARE_S390_RXY_INSTRUCTIONS)

  void pfd(Condition cond, const MemOperand& opnd) {
    pfd(cond, opnd.getIndexRegister(),
476
        opnd.getBaseRegister(), Operand(opnd.getDisplacement()));
477
  }
478 479
  void pfd(Condition cond, Register x2, Register b2, const Operand& d2) {
    rxy_format(PFD, cond, x2.code(), b2.code(), d2.immediate());
480 481 482
  }
#undef DECLARE_S390_RXY_INSTRUCTIONS

483 484

inline void rsy_format(Opcode op, int f1, int f2, int f3, int f4) {
485 486 487 488 489 490 491 492 493 494 495 496 497
  DCHECK(is_int20(f4));
  DCHECK(is_uint16(op));
  uint64_t code = (getfield<uint64_t, 6, 0, 8>(op >> 8) |
                   getfield<uint64_t, 6, 8, 12>(f1) |
                   getfield<uint64_t, 6, 12, 16>(f2) |
                   getfield<uint64_t, 6, 16, 20>(f3) |
                   getfield<uint64_t, 6, 20, 32>(f4 & 0x0fff) |
                   getfield<uint64_t, 6, 32, 40>(f4 >> 12) |
                   getfield<uint64_t, 6, 40, 48>(op & 0xff));
  emit6bytes(code);
}

#define DECLARE_S390_RSY_A_INSTRUCTIONS(name, op_name, op_value)           \
498 499 500
  void name(Register r1, Register r3, Register b2,                         \
            const Operand& d2 = Operand::Zero()) {                         \
    rsy_format(op_name, r1.code(), r3.code(), b2.code(), d2.immediate());  \
501 502
  }                                                                        \
  void name(Register r1, Register r3, Operand d2) {                        \
503
    name(r1, r3, r0, d2);                                                  \
504 505
  }                                                                        \
  void name(Register r1, Register r3, const MemOperand& opnd) {            \
506
    name(r1, r3, opnd.getBaseRegister(), Operand(opnd.getDisplacement())); \
507
  }
508
  S390_RSY_A_OPCODE_LIST(DECLARE_S390_RSY_A_INSTRUCTIONS)
509 510 511
#undef DECLARE_S390_RSY_A_INSTRUCTIONS

#define DECLARE_S390_RSY_B_INSTRUCTIONS(name, op_name, op_value)            \
512 513
  void name(Register r1, Condition m3, Register b2, const Operand& d2) {    \
    rsy_format(op_name, r1.code(), m3, b2.code(), d2.immediate());          \
514 515
  }                                                                         \
  void name(Register r1, Condition m3, const MemOperand& opnd) {            \
516
    name(r1, m3, opnd.getBaseRegister(), Operand(opnd.getDisplacement()));  \
517
  }
518
  S390_RSY_B_OPCODE_LIST(DECLARE_S390_RSY_B_INSTRUCTIONS)
519 520
#undef DECLARE_S390_RSY_B_INSTRUCTIONS

521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537

inline void rs_format(Opcode op, int f1, int f2, int f3, const int f4) {
  uint32_t code = getfield<uint32_t, 4, 0, 8>(op) |
                  getfield<uint32_t, 4, 8, 12>(f1) |
                  getfield<uint32_t, 4, 12, 16>(f2) |
                  getfield<uint32_t, 4, 16, 20>(f3) |
                  getfield<uint32_t, 4, 20, 32>(f4);
  emit4bytes(code);
}

#define DECLARE_S390_RS_A_INSTRUCTIONS(name, op_name, op_value)             \
  void name(Register r1, Register r3, Register b2, const Operand& d2) {     \
    rs_format(op_name, r1.code(), r3.code(), b2.code(), d2.immediate());    \
  }                                                                         \
  void name(Register r1, Register r3, const MemOperand& opnd) {             \
    name(r1, r3, opnd.getBaseRegister(), Operand(opnd.getDisplacement()));  \
  }
538
  S390_RS_A_OPCODE_LIST(DECLARE_S390_RS_A_INSTRUCTIONS)
539 540 541 542 543 544 545 546 547
#undef DECLARE_S390_RS_A_INSTRUCTIONS

#define DECLARE_S390_RS_B_INSTRUCTIONS(name, op_name, op_value)             \
  void name(Register r1, Condition m3, Register b2, const Operand& d2) {    \
    rs_format(op_name, r1.code(), m3, b2.code(), d2.immediate());           \
  }                                                                         \
  void name(Register r1, Condition m3, const MemOperand& opnd) {            \
    name(r1, m3, opnd.getBaseRegister(), Operand(opnd.getDisplacement()));  \
  }
548
  S390_RS_B_OPCODE_LIST(DECLARE_S390_RS_B_INSTRUCTIONS)
549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593
#undef DECLARE_S390_RS_B_INSTRUCTIONS

#define DECLARE_S390_RS_SHIFT_FORMAT(name, opcode)                          \
  void name(Register r1, Register r2, const Operand& opnd =                 \
            Operand::Zero()) {                                              \
    DCHECK(r2 != r0);                                                       \
    rs_format(opcode, r1.code(), r0.code(), r2.code(), opnd.immediate());   \
  }                                                                         \
  void name(Register r1, const Operand& opnd) {                             \
    rs_format(opcode, r1.code(), r0.code(), r0.code(), opnd.immediate());   \
  }
  DECLARE_S390_RS_SHIFT_FORMAT(sll, SLL)
  DECLARE_S390_RS_SHIFT_FORMAT(srl, SRL)
  DECLARE_S390_RS_SHIFT_FORMAT(sla, SLA)
  DECLARE_S390_RS_SHIFT_FORMAT(sra, SRA)
  DECLARE_S390_RS_SHIFT_FORMAT(sldl, SLDL)
  DECLARE_S390_RS_SHIFT_FORMAT(srda, SRDA)
  DECLARE_S390_RS_SHIFT_FORMAT(srdl, SRDL)
#undef DECLARE_S390_RS_SHIFT_FORMAT


inline void rxe_format(Opcode op, int f1, int f2, int f3, int f4, int f5 = 0) {
  DCHECK(is_uint12(f4));
  DCHECK(is_uint16(op));
  uint64_t code = (getfield<uint64_t, 6, 0, 8>(op >> 8) |
                   getfield<uint64_t, 6, 8, 12>(f1) |
                   getfield<uint64_t, 6, 12, 16>(f2) |
                   getfield<uint64_t, 6, 16, 20>(f3) |
                   getfield<uint64_t, 6, 20, 32>(f4 & 0x0fff) |
                   getfield<uint64_t, 6, 32, 36>(f5) |
                   getfield<uint64_t, 6, 40, 48>(op & 0xff));
  emit6bytes(code);
}

#define DECLARE_S390_RXE_INSTRUCTIONS(name, op_name, op_value)             \
  void name(Register r1, Register x2, Register b2, const Operand& d2,      \
            Condition m3 = static_cast<Condition>(0)) {                    \
    rxe_format(op_name, r1.code(), x2.code(), b2.code(), d2.immediate(),   \
               m3);                                                        \
  }                                                                        \
  template<class _R1Type>                                                  \
  void name(_R1Type r1, const MemOperand& opnd) {                          \
    name(Register::from_code(r1.code()), opnd.rx(), opnd.rb(),             \
         Operand(opnd.offset()));                                          \
  }
594
  S390_RXE_OPCODE_LIST(DECLARE_S390_RXE_INSTRUCTIONS)
595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612
#undef DECLARE_S390_RXE_INSTRUCTIONS


inline void ri_format(Opcode opcode, int f1, int f2) {
  uint32_t op1 = opcode >> 4;
  uint32_t op2 = opcode & 0xf;
  emit4bytes(getfield<uint32_t, 4, 0, 8>(op1) |
             getfield<uint32_t, 4, 8, 12>(f1) |
             getfield<uint32_t, 4, 12, 16>(op2) |
             getfield<uint32_t, 4, 16, 32>(f2));
}

#define DECLARE_S390_RI_A_INSTRUCTIONS(name, op_name, op_value)            \
  void name(Register r, const Operand& i2) {                               \
    DCHECK(is_uint12(op_name));                                            \
    DCHECK(is_uint16(i2.immediate()) || is_int16(i2.immediate()));         \
    ri_format(op_name, r.code(), i2.immediate());                          \
  }
613
  S390_RI_A_OPCODE_LIST(DECLARE_S390_RI_A_INSTRUCTIONS)
614 615 616 617 618 619 620 621 622 623
#undef DECLARE_S390_RI_A_INSTRUCTIONS

#define DECLARE_S390_RI_B_INSTRUCTIONS(name, op_name, op_value)            \
  void name(Register r1, const Operand& imm) {                             \
    /* 2nd argument encodes # of halfwords, so divide by 2. */             \
    int16_t numHalfwords = static_cast<int16_t>(imm.immediate()) / 2;      \
    Operand halfwordOp = Operand(numHalfwords);                            \
    halfwordOp.setBits(16);                                                \
    ri_format(op_name, r1.code(), halfwordOp.immediate());                 \
  }
624
  S390_RI_B_OPCODE_LIST(DECLARE_S390_RI_B_INSTRUCTIONS)
625 626 627 628 629 630 631 632 633 634
#undef DECLARE_S390_RI_B_INSTRUCTIONS

#define DECLARE_S390_RI_C_INSTRUCTIONS(name, op_name, op_value)            \
  void name(Condition m, const Operand& i2) {                              \
    DCHECK(is_uint12(op_name));                                            \
    DCHECK(is_uint4(m));                                                   \
    DCHECK(op_name == BRC ?                                                \
           is_int16(i2.immediate()) : is_uint16(i2.immediate()));          \
    ri_format(op_name, m, i2.immediate());                                 \
  }
635
  S390_RI_C_OPCODE_LIST(DECLARE_S390_RI_C_INSTRUCTIONS)
636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654
#undef DECLARE_S390_RI_C_INSTRUCTIONS


inline void rrf_format(Opcode op, int f1, int f2, int f3, int f4) {
  uint32_t code = getfield<uint32_t, 4, 0, 16>(op) |
                  getfield<uint32_t, 4, 16, 20>(f1) |
                  getfield<uint32_t, 4, 20, 24>(f2) |
                  getfield<uint32_t, 4, 24, 28>(f3) |
                  getfield<uint32_t, 4, 28, 32>(f4);
  emit4bytes(code);
}

#define DECLARE_S390_RRF_A_INSTRUCTIONS(name, op_name, op_value)           \
  void name(Register r1, Condition m4, Register r2, Register r3) {         \
    rrf_format(op_name, r3.code(), m4, r1.code(), r2.code());              \
  }                                                                        \
  void name(Register r1, Register r2, Register r3) {                       \
    name(r1, Condition(0), r2, r3);                                        \
  }
655
  S390_RRF_A_OPCODE_LIST(DECLARE_S390_RRF_A_INSTRUCTIONS)
656 657 658 659 660 661 662 663 664 665
#undef DECLARE_S390_RRF_A_INSTRUCTIONS


#define DECLARE_S390_RRF_B_INSTRUCTIONS(name, op_name, op_value)           \
  void name(Register r1, Condition m4, Register r2, Register r3) {         \
    rrf_format(op_name, r3.code(), m4, r1.code(), r2.code());              \
  }                                                                        \
  void name(Register r1, Register r2, Register r3) {                       \
    name(r1, Condition(0), r2, r3);                                        \
  }
666
  S390_RRF_B_OPCODE_LIST(DECLARE_S390_RRF_B_INSTRUCTIONS)
667 668 669 670 671 672 673 674 675 676 677 678
#undef DECLARE_S390_RRF_B_INSTRUCTIONS


#define DECLARE_S390_RRF_C_INSTRUCTIONS(name, op_name, op_value)           \
  template <class R1, class R2>                                            \
  void name(Condition m3, Condition m4, R1 r1, R2 r2) {                    \
    rrf_format(op_name, m3, m4, r1.code(), r2.code());                     \
  }                                                                        \
  template <class R1, class R2>                                            \
  void name(Condition m3, R1 r1, R2 r2) {                                  \
    name(m3, Condition(0), r1, r2);                                        \
  }
679
  S390_RRF_C_OPCODE_LIST(DECLARE_S390_RRF_C_INSTRUCTIONS)
680 681 682 683 684 685 686 687 688 689 690 691
#undef DECLARE_S390_RRF_C_INSTRUCTIONS


#define DECLARE_S390_RRF_D_INSTRUCTIONS(name, op_name, op_value)           \
  template <class R1, class R2>                                            \
  void name(Condition m3, Condition m4, R1 r1, R2 r2) {                    \
    rrf_format(op_name, m3, m4, r1.code(), r2.code());                     \
  }                                                                        \
  template <class R1, class R2>                                            \
  void name(Condition m3, R1 r1, R2 r2) {                                  \
    name(m3, Condition(0), r1, r2);                                        \
  }
692
  S390_RRF_D_OPCODE_LIST(DECLARE_S390_RRF_D_INSTRUCTIONS)
693 694 695 696 697 698 699 700 701 702 703 704
#undef DECLARE_S390_RRF_D_INSTRUCTIONS


#define DECLARE_S390_RRF_E_INSTRUCTIONS(name, op_name, op_value)           \
  template <class M3, class M4, class R1, class R2>                        \
  void name(M3 m3, M4 m4, R1 r1, R2 r2) {                                  \
    rrf_format(op_name, m3, m4, r1.code(), r2.code());                     \
  }                                                                        \
  template <class M3, class R1, class R2>                                  \
  void name(M3 m3, R1 r1, R2 r2) {                                         \
    name(m3, Condition(0), r1, r2);                                        \
  }
705
  S390_RRF_E_OPCODE_LIST(DECLARE_S390_RRF_E_INSTRUCTIONS)
706 707 708 709 710 711 712 713 714 715 716 717 718 719
#undef DECLARE_S390_RRF_E_INSTRUCTIONS

enum FIDBRA_FLAGS {
  FIDBRA_CURRENT_ROUNDING_MODE = 0,
  FIDBRA_ROUND_TO_NEAREST_AWAY_FROM_0 = 1,
  // ...
  FIDBRA_ROUND_TOWARD_0 = 5,
  FIDBRA_ROUND_TOWARD_POS_INF = 6,
  FIDBRA_ROUND_TOWARD_NEG_INF = 7
};


inline void rsi_format(Opcode op, int f1, int f2, int f3) {
  DCHECK(is_uint8(op));
720
  DCHECK(is_uint16(f3) || is_int16(f3));
721 722 723 724 725 726 727 728 729 730 731
  uint32_t code = getfield<uint32_t, 4, 0, 8>(op) |
                  getfield<uint32_t, 4, 8, 12>(f1) |
                  getfield<uint32_t, 4, 12, 16>(f2) |
                  getfield<uint32_t, 4, 16, 32>(f3);
  emit4bytes(code);
}

#define DECLARE_S390_RSI_INSTRUCTIONS(name, op_name, op_value)           \
  void name(Register r1, Register r3, const Operand& i2) {               \
    rsi_format(op_name, r1.code(), r3.code(), i2.immediate());           \
  }
732
  S390_RSI_OPCODE_LIST(DECLARE_S390_RSI_INSTRUCTIONS)
733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753
#undef DECLARE_S390_RSI_INSTRUCTIONS


inline void rsl_format(Opcode op, uint16_t f1, int f2, int f3, int f4,
                       int f5) {
  DCHECK(is_uint16(op));
  uint64_t code = getfield<uint64_t, 6, 0, 8>(op >> 8) |
                  getfield<uint64_t, 6, 8, 16>(f1) |
                  getfield<uint64_t, 6, 16, 20>(f2) |
                  getfield<uint64_t, 6, 20, 32>(f3) |
                  getfield<uint64_t, 6, 32, 36>(f4) |
                  getfield<uint64_t, 6, 36, 40>(f5) |
                  getfield<uint64_t, 6, 40, 48>(op & 0x00FF);
  emit6bytes(code);
}

#define DECLARE_S390_RSL_A_INSTRUCTIONS(name, op_name, op_value)         \
  void name(const Operand& l1, Register b1, const Operand& d1) {         \
    uint16_t L = static_cast<uint16_t>(l1.immediate() << 8);             \
    rsl_format(op_name, L, b1.code(), d1.immediate(), 0, 0);             \
  }
754
  S390_RSL_A_OPCODE_LIST(DECLARE_S390_RSL_A_INSTRUCTIONS)
755 756 757 758 759 760 761 762
#undef DECLARE_S390_RSL_A_INSTRUCTIONS

#define DECLARE_S390_RSL_B_INSTRUCTIONS(name, op_name, op_value)         \
  void name(const Operand& l2, Register b2, const Operand& d2,           \
            Register r1, Condition m3) {                                 \
    uint16_t L = static_cast<uint16_t>(l2.immediate());                  \
    rsl_format(op_name, L, b2.code(), d2.immediate(), r1.code(), m3);    \
  }
763
  S390_RSL_B_OPCODE_LIST(DECLARE_S390_RSL_B_INSTRUCTIONS)
764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787
#undef DECLARE_S390_RSL_B_INSTRUCTIONS


inline void s_format(Opcode op, int f1, int f2) {
  DCHECK_NE(op & 0xff00, 0);
  DCHECK(is_uint12(f2));
  uint32_t code = getfield<uint32_t, 4, 0, 16>(op) |
                  getfield<uint32_t, 4, 16, 20>(f1) |
                  getfield<uint32_t, 4, 20, 32>(f2);
  emit4bytes(code);
}

#define DECLARE_S390_S_INSTRUCTIONS(name, op_name, op_value)             \
  void name(Register b1, const Operand& d2) {                            \
    Opcode op = op_name;                                                 \
    if ((op & 0xFF00) == 0) {                                            \
      op = (Opcode)(op << 8);                                            \
    }                                                                    \
    s_format(op, b1.code(), d2.immediate());                             \
  }                                                                      \
  void name(const MemOperand& opnd) {                                    \
    Operand d2 = Operand(opnd.getDisplacement());                        \
    name(opnd.getBaseRegister(), d2);                                    \
  }
788
  S390_S_OPCODE_LIST(DECLARE_S390_S_INSTRUCTIONS)
789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806
#undef DECLARE_S390_S_INSTRUCTIONS


inline void si_format(Opcode op, int f1, int f2, int f3) {
  uint32_t code = getfield<uint32_t, 4, 0, 8>(op) |
                  getfield<uint32_t, 4, 8, 16>(f1) |
                  getfield<uint32_t, 4, 16, 20>(f2) |
                  getfield<uint32_t, 4, 20, 32>(f3);
  emit4bytes(code);
}

#define DECLARE_S390_SI_INSTRUCTIONS(name, op_name, op_value)            \
  void name(const Operand& i2, Register b1, const Operand& d1) {         \
    si_format(op_name, i2.immediate(), b1.code(), d1.immediate());       \
  }                                                                      \
  void name(const MemOperand& opnd, const Operand& i2) {                 \
    name(i2, opnd.getBaseRegister(), Operand(opnd.getDisplacement()));   \
  }
807
  S390_SI_OPCODE_LIST(DECLARE_S390_SI_INSTRUCTIONS)
808 809 810 811 812 813
#undef DECLARE_S390_SI_INSTRUCTIONS


inline void siy_format(Opcode op, int f1, int f2, int f3) {
  DCHECK(is_uint20(f3) || is_int20(f3));
  DCHECK(is_uint16(op));
814
  DCHECK(is_uint8(f1) || is_int8(f1));
815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830
  uint64_t code = getfield<uint64_t, 6, 0, 8>(op >> 8) |
                  getfield<uint64_t, 6, 8, 16>(f1) |
                  getfield<uint64_t, 6, 16, 20>(f2) |
                  getfield<uint64_t, 6, 20, 32>(f3) |
                  getfield<uint64_t, 6, 32, 40>(f3 >> 12) |
                  getfield<uint64_t, 6, 40, 48>(op & 0x00FF);
  emit6bytes(code);
}

#define DECLARE_S390_SIY_INSTRUCTIONS(name, op_name, op_value)           \
  void name(const Operand& i2, Register b1, const Operand& d1) {         \
    siy_format(op_name, i2.immediate(), b1.code(), d1.immediate());      \
  }                                                                      \
  void name(const MemOperand& opnd, const Operand& i2) {                 \
    name(i2, opnd.getBaseRegister(), Operand(opnd.getDisplacement()));   \
  }
831
  S390_SIY_OPCODE_LIST(DECLARE_S390_SIY_INSTRUCTIONS)
832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858
#undef DECLARE_S390_SIY_INSTRUCTIONS


inline void rrs_format(Opcode op, int f1, int f2, int f3, int f4, int f5) {
  DCHECK(is_uint12(f4));
  DCHECK(is_uint16(op));
  uint64_t code = getfield<uint64_t, 6, 0, 8>(op >> 8) |
                  getfield<uint64_t, 6, 8, 12>(f1) |
                  getfield<uint64_t, 6, 12, 16>(f2) |
                  getfield<uint64_t, 6, 16, 20>(f3) |
                  getfield<uint64_t, 6, 20, 32>(f4) |
                  getfield<uint64_t, 6, 32, 36>(f5) |
                  getfield<uint64_t, 6, 40, 48>(op & 0x00FF);
  emit6bytes(code);
}

#define DECLARE_S390_RRS_INSTRUCTIONS(name, op_name, op_value)           \
  void name(Register r1, Register r2, Register b4, const Operand& d4,    \
            Condition m3) {                                              \
    rrs_format(op_name, r1.code(), r2.code(), b4.code(), d4.immediate(), \
               m3);                                                      \
  }                                                                      \
  void name(Register r1, Register r2, Condition m3,                      \
            const MemOperand& opnd) {                                    \
    name(r1, r2, opnd.getBaseRegister(),                                 \
         Operand(opnd.getDisplacement()), m3);                           \
  }
859
  S390_RRS_OPCODE_LIST(DECLARE_S390_RRS_INSTRUCTIONS)
860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887
#undef DECLARE_S390_RRS_INSTRUCTIONS


inline void ris_format(Opcode op, int f1, int f2, int f3, int f4, int f5) {
  DCHECK(is_uint12(f3));
  DCHECK(is_uint16(op));
  DCHECK(is_uint8(f5));
  uint64_t code = getfield<uint64_t, 6, 0, 8>(op >> 8) |
                  getfield<uint64_t, 6, 8, 12>(f1) |
                  getfield<uint64_t, 6, 12, 16>(f2) |
                  getfield<uint64_t, 6, 16, 20>(f3) |
                  getfield<uint64_t, 6, 20, 32>(f4) |
                  getfield<uint64_t, 6, 32, 40>(f5) |
                  getfield<uint64_t, 6, 40, 48>(op & 0x00FF);
  emit6bytes(code);
}

#define DECLARE_S390_RIS_INSTRUCTIONS(name, op_name, op_value)           \
  void name(Register r1, Condition m3, Register b4, const Operand& d4,   \
                       const Operand& i2) {                              \
    ris_format(op_name, r1.code(), m3, b4.code(), d4.immediate(),        \
               i2.immediate());                                          \
  }                                                                      \
  void name(Register r1, const Operand& i2, Condition m3,                \
                       const MemOperand& opnd) {                         \
    name(r1, m3, opnd.getBaseRegister(),                                 \
         Operand(opnd.getDisplacement()), i2);                           \
  }
888
  S390_RIS_OPCODE_LIST(DECLARE_S390_RIS_INSTRUCTIONS)
889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909
#undef DECLARE_S390_RIS_INSTRUCTIONS


inline void sil_format(Opcode op, int f1, int f2, int f3) {
  DCHECK(is_uint12(f2));
  DCHECK(is_uint16(op));
  DCHECK(is_uint16(f3));
  uint64_t code = getfield<uint64_t, 6, 0, 16>(op) |
                  getfield<uint64_t, 6, 16, 20>(f1) |
                  getfield<uint64_t, 6, 20, 32>(f2) |
                  getfield<uint64_t, 6, 32, 48>(f3);
  emit6bytes(code);
}

#define DECLARE_S390_SIL_INSTRUCTIONS(name, op_name, op_value)           \
  void name(Register b1, const Operand& d1, const Operand& i2) {         \
    sil_format(op_name, b1.code(), d1.immediate(), i2.immediate());      \
  }                                                                      \
  void name(const MemOperand& opnd, const Operand& i2) {                 \
    name(opnd.getBaseRegister(), Operand(opnd.getDisplacement()), i2);   \
  }
910
  S390_SIL_OPCODE_LIST(DECLARE_S390_SIL_INSTRUCTIONS)
911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933
#undef DECLARE_S390_SIL_INSTRUCTIONS


inline void rie_d_format(Opcode opcode, int f1, int f2, int f3, int f4) {
  uint32_t op1 = opcode >> 8;
  uint32_t op2 = opcode & 0xff;
  uint64_t code = getfield<uint64_t, 6, 0, 8>(op1) |
                  getfield<uint64_t, 6, 8, 12>(f1) |
                  getfield<uint64_t, 6, 12, 16>(f2) |
                  getfield<uint64_t, 6, 16, 32>(f3) |
                  getfield<uint64_t, 6, 32, 40>(f4) |
                  getfield<uint64_t, 6, 40, 48>(op2);
  emit6bytes(code);
}

#define DECLARE_S390_RIE_D_INSTRUCTIONS(name, op_name, op_value)         \
  void name(Register r1, Register r3, const Operand& i2) {               \
    rie_d_format(op_name, r1.code(), r3.code(), i2.immediate(), 0);      \
  }
  S390_RIE_D_OPCODE_LIST(DECLARE_S390_RIE_D_INSTRUCTIONS)
#undef DECLARE_S390_RIE_D_INSTRUCTIONS


934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952
inline void rie_e_format(Opcode opcode, int f1, int f2, int f3) {
  uint32_t op1 = opcode >> 8;
  uint32_t op2 = opcode & 0xff;
  uint64_t code = getfield<uint64_t, 6, 0, 8>(op1) |
                  getfield<uint64_t, 6, 8, 12>(f1) |
                  getfield<uint64_t, 6, 12, 16>(f2) |
                  getfield<uint64_t, 6, 16, 32>(f3) |
                  getfield<uint64_t, 6, 40, 48>(op2);
  emit6bytes(code);
}

#define DECLARE_S390_RIE_E_INSTRUCTIONS(name, op_name, op_value)         \
  void name(Register r1, Register r3, const Operand& i2) {               \
    rie_e_format(op_name, r1.code(), r3.code(), i2.immediate());         \
  }
  S390_RIE_E_OPCODE_LIST(DECLARE_S390_RIE_E_INSTRUCTIONS)
#undef DECLARE_S390_RIE_E_INSTRUCTIONS


953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010
inline void rie_f_format(Opcode opcode, int f1, int f2, int f3, int f4,
                         int f5) {
  uint32_t op1 = opcode >> 8;
  uint32_t op2 = opcode & 0xff;
  uint64_t code = getfield<uint64_t, 6, 0, 8>(op1) |
                  getfield<uint64_t, 6, 8, 12>(f1) |
                  getfield<uint64_t, 6, 12, 16>(f2) |
                  getfield<uint64_t, 6, 16, 24>(f3) |
                  getfield<uint64_t, 6, 24, 32>(f4) |
                  getfield<uint64_t, 6, 32, 40>(f5) |
                  getfield<uint64_t, 6, 40, 48>(op2);
  emit6bytes(code);
}

#define DECLARE_S390_RIE_F_INSTRUCTIONS(name, op_name, op_value)         \
  void name(Register dst, Register src, const Operand& startBit,         \
            const Operand& endBit, const Operand& shiftAmt) {            \
    DCHECK(is_uint8(startBit.immediate()));                              \
    DCHECK(is_uint8(endBit.immediate()));                                \
    DCHECK(is_uint8(shiftAmt.immediate()));                              \
    rie_f_format(op_name, dst.code(), src.code(), startBit.immediate(),  \
                 endBit.immediate(), shiftAmt.immediate());              \
  }
  S390_RIE_F_OPCODE_LIST(DECLARE_S390_RIE_F_INSTRUCTIONS)
#undef DECLARE_S390_RIE_F_INSTRUCTIONS


inline void ss_a_format(Opcode op, int f1, int f2, int f3, int f4, int f5) {
  DCHECK(is_uint12(f5));
  DCHECK(is_uint12(f3));
  DCHECK(is_uint8(f1));
  DCHECK(is_uint8(op));
  uint64_t code = getfield<uint64_t, 6, 0, 8>(op) |
                  getfield<uint64_t, 6, 8, 16>(f1) |
                  getfield<uint64_t, 6, 16, 20>(f2) |
                  getfield<uint64_t, 6, 20, 32>(f3) |
                  getfield<uint64_t, 6, 32, 36>(f4) |
                  getfield<uint64_t, 6, 36, 48>(f5);
  emit6bytes(code);
}

#define DECLARE_S390_SS_A_INSTRUCTIONS(name, op_name, op_value)          \
  void name(Register b1, const Operand& d1, Register b2,                 \
            const Operand& d2, const Operand& length) {                  \
    ss_a_format(op_name, length.immediate(), b1.code(), d1.immediate(),  \
                b2.code(), d2.immediate());                              \
  }                                                                      \
  void name(const MemOperand& opnd1, const MemOperand& opnd2,            \
            const Operand& length) {                                     \
    ss_a_format(op_name, length.immediate(),                             \
                opnd1.getBaseRegister().code(),                          \
                opnd1.getDisplacement(), opnd2.getBaseRegister().code(), \
                opnd2.getDisplacement());                                \
  }
  S390_SS_A_OPCODE_LIST(DECLARE_S390_SS_A_INSTRUCTIONS)
#undef DECLARE_S390_SS_A_INSTRUCTIONS


1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057
  // Helper for unconditional branch to Label with update to save register
  void b(Register r, Label* l) {
    int32_t halfwords = branch_offset(l) / 2;
    brasl(r, Operand(halfwords));
  }

  // Conditional Branch Instruction - Generates either BRC / BRCL
  void branchOnCond(Condition c, int branch_offset, bool is_bound = false);

  // Helpers for conditional branch to Label
  void b(Condition cond, Label* l, Label::Distance dist = Label::kFar) {
    branchOnCond(cond, branch_offset(l),
                 l->is_bound() || (dist == Label::kNear));
  }

  void bc_short(Condition cond, Label* l, Label::Distance dist = Label::kFar) {
    b(cond, l, Label::kNear);
  }
  // Helpers for conditional branch to Label
  void beq(Label* l, Label::Distance dist = Label::kFar) { b(eq, l, dist); }
  void bne(Label* l, Label::Distance dist = Label::kFar) { b(ne, l, dist); }
  void blt(Label* l, Label::Distance dist = Label::kFar) { b(lt, l, dist); }
  void ble(Label* l, Label::Distance dist = Label::kFar) { b(le, l, dist); }
  void bgt(Label* l, Label::Distance dist = Label::kFar) { b(gt, l, dist); }
  void bge(Label* l, Label::Distance dist = Label::kFar) { b(ge, l, dist); }
  void b(Label* l, Label::Distance dist = Label::kFar) { b(al, l, dist); }
  void jmp(Label* l, Label::Distance dist = Label::kFar) { b(al, l, dist); }
  void bunordered(Label* l, Label::Distance dist = Label::kFar) {
    b(unordered, l, dist);
  }
  void bordered(Label* l, Label::Distance dist = Label::kFar) {
    b(ordered, l, dist);
  }

  // Helpers for conditional indirect branch off register
  void b(Condition cond, Register r) { bcr(cond, r); }
  void beq(Register r) { b(eq, r); }
  void bne(Register r) { b(ne, r); }
  void blt(Register r) { b(lt, r); }
  void ble(Register r) { b(le, r); }
  void bgt(Register r) { b(gt, r); }
  void bge(Register r) { b(ge, r); }
  void b(Register r) { b(al, r); }
  void jmp(Register r) { b(al, r); }
  void bunordered(Register r) { b(unordered, r); }
  void bordered(Register r) { b(ordered, r); }

1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070
  // wrappers around asm instr
  void brxh(Register dst, Register inc, Label* L) {
    int offset_halfwords = branch_offset(L) / 2;
    CHECK(is_int16(offset_halfwords));
    brxh(dst, inc, Operand(offset_halfwords));
  }

  void brxhg(Register dst, Register inc, Label* L) {
    int offset_halfwords = branch_offset(L) / 2;
    CHECK(is_int16(offset_halfwords));
    brxhg(dst, inc, Operand(offset_halfwords));
  }

1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110
  template <class R1, class R2>
  void ledbr(R1 r1, R2 r2) {
    ledbra(Condition(0), Condition(0), r1, r2);
  }

  template <class R1, class R2>
  void cdfbr(R1 r1, R2 r2) {
    cdfbra(Condition(0), Condition(0), r1, r2);
  }

  template <class R1, class R2>
  void cdgbr(R1 r1, R2 r2) {
    cdgbra(Condition(0), Condition(0), r1, r2);
  }

  template <class R1, class R2>
  void cegbr(R1 r1, R2 r2) {
    cegbra(Condition(0), Condition(0), r1, r2);
  }

  template <class R1, class R2>
  void cgebr(Condition m3, R1 r1, R2 r2) {
    cgebra(m3, Condition(0), r1, r2);
  }

  template <class R1, class R2>
  void cgdbr(Condition m3, R1 r1, R2 r2) {
    cgdbra(m3, Condition(0), r1, r2);
  }

  template <class R1, class R2>
  void cfdbr(Condition m3, R1 r1, R2 r2) {
    cfdbra(m3, Condition(0), r1, r2);
  }

  template <class R1, class R2>
  void cfebr(Condition m3, R1 r1, R2 r2) {
    cfebra(m3, Condition(0), r1, r2);
  }

1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125
  // ---------------------------------------------------------------------------
  // Code generation

  // Insert the smallest number of nop instructions
  // possible to align the pc offset to a multiple
  // of m. m must be a power of 2 (>= 4).
  void Align(int m);
  // Insert the smallest number of zero bytes possible to align the pc offset
  // to a mulitple of m. m must be a power of 2 (>= 2).
  void DataAlign(int m);
  // Aligns code to something that's optimal for a jump target for the platform.
  void CodeTargetAlign();

  void breakpoint(bool do_print) {
    if (do_print) {
1126
      PrintF("DebugBreak is inserted to %p\n", static_cast<void*>(pc_));
1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140
    }
#if V8_HOST_ARCH_64_BIT
    int64_t value = reinterpret_cast<uint64_t>(&v8::base::OS::DebugBreak);
    int32_t hi_32 = static_cast<int64_t>(value) >> 32;
    int32_t lo_32 = static_cast<int32_t>(value);

    iihf(r1, Operand(hi_32));
    iilf(r1, Operand(lo_32));
#else
    iilf(r1, Operand(reinterpret_cast<uint32_t>(&v8::base::OS::DebugBreak)));
#endif
    basr(r14, r1);
  }

1141
  void call(Handle<Code> target, RelocInfo::Mode rmode);
1142 1143 1144
  void jump(Handle<Code> target, RelocInfo::Mode rmode, Condition cond);

// S390 instruction generation
1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156
#define DECLARE_VRR_A_INSTRUCTIONS(name, opcode_name, opcode_value)           \
  void name(DoubleRegister v1, DoubleRegister v2, Condition m5, Condition m4, \
            Condition m3) {                                                   \
    uint64_t code = (static_cast<uint64_t>(opcode_value & 0xFF00)) * B32 |    \
                    (static_cast<uint64_t>(v1.code())) * B36 |                \
                    (static_cast<uint64_t>(v2.code())) * B32 |                \
                    (static_cast<uint64_t>(m5 & 0xF)) * B20 |                 \
                    (static_cast<uint64_t>(m4 & 0xF)) * B16 |                 \
                    (static_cast<uint64_t>(m3 & 0xF)) * B12 |                 \
                    (static_cast<uint64_t>(opcode_value & 0x00FF));           \
    emit6bytes(code);                                                         \
  }
jyan's avatar
jyan committed
1157
  S390_VRR_A_OPCODE_LIST(DECLARE_VRR_A_INSTRUCTIONS)
1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172
#undef DECLARE_VRR_A_INSTRUCTIONS

#define DECLARE_VRR_C_INSTRUCTIONS(name, opcode_name, opcode_value)        \
  void name(DoubleRegister v1, DoubleRegister v2, DoubleRegister v3,       \
            Condition m6, Condition m5, Condition m4) {                    \
    uint64_t code = (static_cast<uint64_t>(opcode_value & 0xFF00)) * B32 | \
                    (static_cast<uint64_t>(v1.code())) * B36 |             \
                    (static_cast<uint64_t>(v2.code())) * B32 |             \
                    (static_cast<uint64_t>(v3.code())) * B28 |             \
                    (static_cast<uint64_t>(m6 & 0xF)) * B20 |              \
                    (static_cast<uint64_t>(m5 & 0xF)) * B16 |              \
                    (static_cast<uint64_t>(m4 & 0xF)) * B12 |              \
                    (static_cast<uint64_t>(opcode_value & 0x00FF));        \
    emit6bytes(code);                                                      \
  }
jyan's avatar
jyan committed
1173
  S390_VRR_C_OPCODE_LIST(DECLARE_VRR_C_INSTRUCTIONS)
1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193
#undef DECLARE_VRR_C_INSTRUCTIONS

  // Single Element format
  void vfa(DoubleRegister v1, DoubleRegister v2, DoubleRegister v3) {
    vfa(v1, v2, v3, static_cast<Condition>(0), static_cast<Condition>(8),
        static_cast<Condition>(3));
  }
  void vfs(DoubleRegister v1, DoubleRegister v2, DoubleRegister v3) {
    vfs(v1, v2, v3, static_cast<Condition>(0), static_cast<Condition>(8),
        static_cast<Condition>(3));
  }
  void vfm(DoubleRegister v1, DoubleRegister v2, DoubleRegister v3) {
    vfm(v1, v2, v3, static_cast<Condition>(0), static_cast<Condition>(8),
        static_cast<Condition>(3));
  }
  void vfd(DoubleRegister v1, DoubleRegister v2, DoubleRegister v3) {
    vfd(v1, v2, v3, static_cast<Condition>(0), static_cast<Condition>(8),
        static_cast<Condition>(3));
  }

1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219
  // Load Address Instructions
  void larl(Register r, Label* l);

  // Exception-generating instructions and debugging support
  void stop(const char* msg, Condition cond = al,
            int32_t code = kDefaultStopCode, CRegister cr = cr7);

  void bkpt(uint32_t imm16);  // v5 and above

  // Different nop operations are used by the code generator to detect certain
  // states of the generated code.
  enum NopMarkerTypes {
    NON_MARKING_NOP = 0,
    GROUP_ENDING_NOP,
    DEBUG_BREAK_NOP,
    // IC markers.
    PROPERTY_ACCESS_INLINED,
    PROPERTY_ACCESS_INLINED_CONTEXT,
    PROPERTY_ACCESS_INLINED_CONTEXT_DONT_DELETE,
    // Helper values.
    LAST_CODE_MARKER,
    FIRST_IC_MARKER = PROPERTY_ACCESS_INLINED
  };

  void nop(int type = 0);  // 0 is the default non-marking type.

1220 1221
  void dumy(int r1, int x2, int b2, int d2);

1222 1223 1224 1225 1226 1227 1228
  // Check the code size generated from label to here.
  int SizeOfCodeGeneratedSince(Label* label) {
    return pc_offset() - label->pos();
  }

  // Record a deoptimization reason that can be used by a log or cpu profiler.
  // Use --trace-deopt to enable.
1229 1230
  void RecordDeoptReason(DeoptimizeReason reason, SourcePosition position,
                         int id);
1231 1232 1233 1234 1235 1236 1237 1238 1239 1240

  // Writes a single byte or word of data in the code stream.  Used
  // for inline tables, e.g., jump-tables.
  void db(uint8_t data);
  void dd(uint32_t data);
  void dq(uint64_t data);
  void dp(uintptr_t data);

  // Read/patch instructions
  SixByteInstr instr_at(int pos) {
1241
    return Instruction::InstructionBits(buffer_start_ + pos);
1242 1243 1244
  }
  template <typename T>
  void instr_at_put(int pos, T instr) {
1245
    Instruction::SetInstructionBits<T>(buffer_start_ + pos, instr);
1246 1247 1248 1249
  }

  // Decodes instruction at pos, and returns its length
  int32_t instr_length_at(int pos) {
1250
    return Instruction::InstructionLength(buffer_start_ + pos);
1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280
  }

  static SixByteInstr instr_at(byte* pc) {
    return Instruction::InstructionBits(pc);
  }

  static Condition GetCondition(Instr instr);

  static bool IsBranch(Instr instr);
#if V8_TARGET_ARCH_S390X
  static bool Is64BitLoadIntoIP(SixByteInstr instr1, SixByteInstr instr2);
#else
  static bool Is32BitLoadIntoIP(SixByteInstr instr);
#endif

  static bool IsCmpRegister(Instr instr);
  static bool IsCmpImmediate(Instr instr);
  static bool IsNop(SixByteInstr instr, int type = NON_MARKING_NOP);

  // The code currently calls CheckBuffer() too often. This has the side
  // effect of randomly growing the buffer in the middle of multi-instruction
  // sequences.
  //
  // This function allows outside callers to check and grow the buffer
  void EnsureSpaceFor(int space_needed);

  void EmitRelocations();
  void emit_label_addr(Label* label);

 public:
1281
  byte* buffer_pos() const { return buffer_start_; }
1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296

 protected:
  int buffer_space() const { return reloc_info_writer.pos() - pc_; }

  // Decode instruction(s) at pos and return backchain to previous
  // label reference or kEndOfChain.
  int target_at(int pos);

  // Patch instruction(s) at pos to target target_pos (e.g. branch)
  void target_at_put(int pos, int target_pos, bool* is_branch = nullptr);

  // Record reloc info for current pc_
  void RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data = 0);

 private:
1297 1298 1299
  // Avoid overflows for displacements etc.
  static const int kMaximalBufferSize = 512 * MB;

1300 1301 1302 1303 1304
  // Code generation
  // The relocation writer's position is at least kGap bytes below the end of
  // the generated instructions. This is so that multi-instruction sequences do
  // not have to check for overflow. The same is true for writes of large
  // relocation info entries.
1305
  static constexpr int kGap = 32;
1306 1307 1308

  // Relocation info generation
  // Each relocation is encoded as a variable size value
1309
  static constexpr int kMaxRelocSize = RelocInfoWriter::kMaxSize;
1310 1311 1312 1313 1314 1315 1316
  RelocInfoWriter reloc_info_writer;
  std::vector<DeferredRelocInfo> relocations_;

  // The bound position, before this we cannot do instruction elimination.
  int last_bound_pos_;

  // Code emission
1317 1318 1319 1320 1321
  void CheckBuffer() {
    if (buffer_space() <= kGap) {
      GrowBuffer();
    }
  }
1322 1323 1324 1325
  void GrowBuffer(int needed = 0);
  inline void TrackBranch();
  inline void UntrackBranch();

1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377
  // Helper to emit the binary encoding of a 2 byte instruction
  void emit2bytes(uint16_t x) {
    CheckBuffer();
#if V8_TARGET_LITTLE_ENDIAN
    // We need to emit instructions in big endian format as disassembler /
    // simulator require the first byte of the instruction in order to decode
    // the instruction length.  Swap the bytes.
    x = ((x & 0x00FF) << 8) | ((x & 0xFF00) >> 8);
#endif
    *reinterpret_cast<uint16_t*>(pc_) = x;
    pc_ += 2;
  }

  // Helper to emit the binary encoding of a 4 byte instruction
  void emit4bytes(uint32_t x) {
    CheckBuffer();
#if V8_TARGET_LITTLE_ENDIAN
    // We need to emit instructions in big endian format as disassembler /
    // simulator require the first byte of the instruction in order to decode
    // the instruction length.  Swap the bytes.
    x = ((x & 0x000000FF) << 24) | ((x & 0x0000FF00) << 8) |
        ((x & 0x00FF0000) >> 8) | ((x & 0xFF000000) >> 24);
#endif
    *reinterpret_cast<uint32_t*>(pc_) = x;
    pc_ += 4;
  }

  // Helper to emit the binary encoding of a 6 byte instruction
  void emit6bytes(uint64_t x) {
    CheckBuffer();
#if V8_TARGET_LITTLE_ENDIAN
    // We need to emit instructions in big endian format as disassembler /
    // simulator require the first byte of the instruction in order to decode
    // the instruction length.  Swap the bytes.
    x = (static_cast<uint64_t>(x & 0xFF) << 40) |
        (static_cast<uint64_t>((x >> 8) & 0xFF) << 32) |
        (static_cast<uint64_t>((x >> 16) & 0xFF) << 24) |
        (static_cast<uint64_t>((x >> 24) & 0xFF) << 16) |
        (static_cast<uint64_t>((x >> 32) & 0xFF) << 8) |
        (static_cast<uint64_t>((x >> 40) & 0xFF));
    x |= (*reinterpret_cast<uint64_t*>(pc_) >> 48) << 48;
#else
    // We need to pad two bytes of zeros in order to get the 6-bytes
    // stored from low address.
    x = x << 16;
    x |= *reinterpret_cast<uint64_t*>(pc_) & 0xFFFF;
#endif
    // It is safe to store 8-bytes, as CheckBuffer() guarantees we have kGap
    // space left over.
    *reinterpret_cast<uint64_t*>(pc_) = x;
    pc_ += 6;
  }
1378 1379 1380 1381 1382 1383 1384

  // Labels
  void print(Label* L);
  int max_reach_from(int pos);
  void bind_to(Label* L, int pos);
  void next(Label* L);

1385 1386
  void AllocateAndInstallRequestedHeapObjects(Isolate* isolate);

1387 1388
  int WriteCodeComments();

1389 1390
  friend class RegExpMacroAssemblerS390;
  friend class RelocInfo;
1391
  friend class EnsureSpace;
1392 1393
};

1394
class EnsureSpace {
1395 1396 1397 1398 1399 1400 1401 1402
 public:
  explicit EnsureSpace(Assembler* assembler) { assembler->CheckBuffer(); }
};

}  // namespace internal
}  // namespace v8

#endif  // V8_S390_ASSEMBLER_S390_H_