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